idl: Merge NETR_TRUST and LSA_TRUST definitions into one set only in lsa.idl
[samba.git] / source3 / winbindd / winbindd_util.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon for ntdom nss module
5
6    Copyright (C) Tim Potter 2000-2001
7    Copyright (C) 2001 by Martin Pool <mbp@samba.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25 #include "secrets.h"
26 #include "../libcli/security/security.h"
27 #include "../libcli/auth/pam_errors.h"
28 #include "passdb/machine_sid.h"
29 #include "passdb.h"
30
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_WINBIND
33
34 extern struct winbindd_methods cache_methods;
35
36 /**
37  * @file winbindd_util.cq
38  *
39  * Winbind daemon for NT domain authentication nss module.
40  **/
41
42
43 /* The list of trusted domains.  Note that the list can be deleted and
44    recreated using the init_domain_list() function so pointers to
45    individual winbindd_domain structures cannot be made.  Keep a copy of
46    the domain name instead. */
47
48 static struct winbindd_domain *_domain_list = NULL;
49
50 struct winbindd_domain *domain_list(void)
51 {
52         /* Initialise list */
53
54         if ((!_domain_list) && (!init_domain_list())) {
55                 smb_panic("Init_domain_list failed");
56         }
57
58         return _domain_list;
59 }
60
61 /* Free all entries in the trusted domain list */
62
63 static void free_domain_list(void)
64 {
65         struct winbindd_domain *domain = _domain_list;
66
67         while(domain) {
68                 struct winbindd_domain *next = domain->next;
69
70                 DLIST_REMOVE(_domain_list, domain);
71                 TALLOC_FREE(domain);
72                 domain = next;
73         }
74 }
75
76 static bool is_internal_domain(const struct dom_sid *sid)
77 {
78         if (sid == NULL)
79                 return False;
80
81         return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
82 }
83
84 static bool is_in_internal_domain(const struct dom_sid *sid)
85 {
86         if (sid == NULL)
87                 return False;
88
89         return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
90 }
91
92
93 /* Add a trusted domain to our list of domains.
94    If the domain already exists in the list,
95    return it and don't re-initialize.  */
96
97 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
98                                                   struct winbindd_methods *methods,
99                                                   const struct dom_sid *sid)
100 {
101         struct winbindd_domain *domain;
102         const char *alternative_name = NULL;
103         char *idmap_config_option;
104         const char *param;
105         const char **ignored_domains, **dom;
106         int role = lp_server_role();
107
108         ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
109         for (dom=ignored_domains; dom && *dom; dom++) {
110                 if (gen_fnmatch(*dom, domain_name) == 0) {
111                         DEBUG(2,("Ignoring domain '%s'\n", domain_name));
112                         return NULL;
113                 }
114         }
115
116         /* use alt_name if available to allow DNS lookups */
117
118         if (alt_name && *alt_name) {
119                 alternative_name = alt_name;
120         }
121
122         /* We can't call domain_list() as this function is called from
123            init_domain_list() and we'll get stuck in a loop. */
124         for (domain = _domain_list; domain; domain = domain->next) {
125                 if (strequal(domain_name, domain->name) ||
126                     strequal(domain_name, domain->alt_name))
127                 {
128                         break;
129                 }
130
131                 if (alternative_name && *alternative_name)
132                 {
133                         if (strequal(alternative_name, domain->name) ||
134                             strequal(alternative_name, domain->alt_name))
135                         {
136                                 break;
137                         }
138                 }
139
140                 if (sid)
141                 {
142                         if (is_null_sid(sid)) {
143                                 continue;
144                         }
145
146                         if (dom_sid_equal(sid, &domain->sid)) {
147                                 break;
148                         }
149                 }
150         }
151
152         if (domain != NULL) {
153                 /*
154                  * We found a match on domain->name or
155                  * domain->alt_name. Possibly update the SID
156                  * if the stored SID was the NULL SID
157                  * and return the matching entry.
158                  */
159                 if ((sid != NULL)
160                     && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
161                         sid_copy( &domain->sid, sid );
162                 }
163                 return domain;
164         }
165
166         /* Create new domain entry */
167         domain = talloc_zero(NULL, struct winbindd_domain);
168         if (domain == NULL) {
169                 return NULL;
170         }
171
172         domain->children = talloc_zero_array(domain,
173                                              struct winbindd_child,
174                                              lp_winbind_max_domain_connections());
175         if (domain->children == NULL) {
176                 TALLOC_FREE(domain);
177                 return NULL;
178         }
179
180         domain->name = talloc_strdup(domain, domain_name);
181         if (domain->name == NULL) {
182                 TALLOC_FREE(domain);
183                 return NULL;
184         }
185
186         if (alternative_name) {
187                 domain->alt_name = talloc_strdup(domain, alternative_name);
188                 if (domain->alt_name == NULL) {
189                         TALLOC_FREE(domain);
190                         return NULL;
191                 }
192         }
193
194         domain->methods = methods;
195         domain->backend = NULL;
196         domain->internal = is_internal_domain(sid);
197         domain->sequence_number = DOM_SEQUENCE_NONE;
198         domain->last_seq_check = 0;
199         domain->initialized = False;
200         domain->online = is_internal_domain(sid);
201         domain->check_online_timeout = 0;
202         domain->dc_probe_pid = (pid_t)-1;
203         if (sid) {
204                 sid_copy(&domain->sid, sid);
205         }
206
207         /* Is this our primary domain ? */
208         if (strequal(domain_name, get_global_sam_name()) &&
209                         (role != ROLE_DOMAIN_MEMBER)) {
210                 domain->primary = true;
211         } else if (strequal(domain_name, lp_workgroup()) &&
212                         (role == ROLE_DOMAIN_MEMBER)) {
213                 domain->primary = true;
214         }
215
216         /* Link to domain list */
217         DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
218
219         wcache_tdc_add_domain( domain );
220
221         idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
222                                               domain->name);
223         if (idmap_config_option == NULL) {
224                 DEBUG(0, ("talloc failed, not looking for idmap config\n"));
225                 goto done;
226         }
227
228         param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);
229
230         DEBUG(10, ("%s : range = %s\n", idmap_config_option,
231                    param ? param : "not defined"));
232
233         if (param != NULL) {
234                 unsigned low_id, high_id;
235                 if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
236                         DEBUG(1, ("invalid range syntax in %s: %s\n",
237                                   idmap_config_option, param));
238                         goto done;
239                 }
240                 if (low_id > high_id) {
241                         DEBUG(1, ("invalid range in %s: %s\n",
242                                   idmap_config_option, param));
243                         goto done;
244                 }
245                 domain->have_idmap_config = true;
246                 domain->id_range_low = low_id;
247                 domain->id_range_high = high_id;
248         }
249
250 done:
251
252         setup_domain_child(domain);
253
254         DEBUG(2,("Added domain %s %s %s\n",
255                  domain->name, domain->alt_name,
256                  &domain->sid?sid_string_dbg(&domain->sid):""));
257
258         return domain;
259 }
260
261 bool domain_is_forest_root(const struct winbindd_domain *domain)
262 {
263         const uint32_t fr_flags =
264                 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
265
266         return ((domain->domain_flags & fr_flags) == fr_flags);
267 }
268
269 /********************************************************************
270   rescan our domains looking for new trusted domains
271 ********************************************************************/
272
273 struct trustdom_state {
274         struct winbindd_domain *domain;
275         struct winbindd_request request;
276 };
277
278 static void trustdom_list_done(struct tevent_req *req);
279 static void rescan_forest_root_trusts( void );
280 static void rescan_forest_trusts( void );
281
282 static void add_trusted_domains( struct winbindd_domain *domain )
283 {
284         struct trustdom_state *state;
285         struct tevent_req *req;
286
287         state = talloc_zero(NULL, struct trustdom_state);
288         if (state == NULL) {
289                 DEBUG(0, ("talloc failed\n"));
290                 return;
291         }
292         state->domain = domain;
293
294         state->request.length = sizeof(state->request);
295         state->request.cmd = WINBINDD_LIST_TRUSTDOM;
296
297         req = wb_domain_request_send(state, winbind_event_context(),
298                                      domain, &state->request);
299         if (req == NULL) {
300                 DEBUG(1, ("wb_domain_request_send failed\n"));
301                 TALLOC_FREE(state);
302                 return;
303         }
304         tevent_req_set_callback(req, trustdom_list_done, state);
305 }
306
307 static void trustdom_list_done(struct tevent_req *req)
308 {
309         struct trustdom_state *state = tevent_req_callback_data(
310                 req, struct trustdom_state);
311         struct winbindd_response *response;
312         int res, err;
313         char *p;
314
315         res = wb_domain_request_recv(req, state, &response, &err);
316         if ((res == -1) || (response->result != WINBINDD_OK)) {
317                 DEBUG(1, ("Could not receive trustdoms\n"));
318                 TALLOC_FREE(state);
319                 return;
320         }
321
322         p = (char *)response->extra_data.data;
323
324         while ((p != NULL) && (*p != '\0')) {
325                 char *q, *sidstr, *alt_name;
326                 struct dom_sid sid;
327                 char *alternate_name = NULL;
328
329                 alt_name = strchr(p, '\\');
330                 if (alt_name == NULL) {
331                         DEBUG(0, ("Got invalid trustdom response\n"));
332                         break;
333                 }
334
335                 *alt_name = '\0';
336                 alt_name += 1;
337
338                 sidstr = strchr(alt_name, '\\');
339                 if (sidstr == NULL) {
340                         DEBUG(0, ("Got invalid trustdom response\n"));
341                         break;
342                 }
343
344                 *sidstr = '\0';
345                 sidstr += 1;
346
347                 q = strchr(sidstr, '\n');
348                 if (q != NULL)
349                         *q = '\0';
350
351                 if (!string_to_sid(&sid, sidstr)) {
352                         DEBUG(0, ("Got invalid trustdom response\n"));
353                         break;
354                 }
355
356                 /* use the real alt_name if we have one, else pass in NULL */
357
358                 if ( !strequal( alt_name, "(null)" ) )
359                         alternate_name = alt_name;
360
361                 /*
362                  * We always call add_trusted_domain() cause on an existing
363                  * domain structure, it will update the SID if necessary.
364                  * This is important because we need the SID for sibling
365                  * domains.
366                  */
367                 (void)add_trusted_domain(p, alternate_name,
368                                             &cache_methods,
369                                             &sid);
370
371                 p=q;
372                 if (p != NULL)
373                         p += 1;
374         }
375
376         /*
377            Cases to consider when scanning trusts:
378            (a) we are calling from a child domain (primary && !forest_root)
379            (b) we are calling from the root of the forest (primary && forest_root)
380            (c) we are calling from a trusted forest domain (!primary
381                && !forest_root)
382         */
383
384         if (state->domain->primary) {
385                 /* If this is our primary domain and we are not in the
386                    forest root, we have to scan the root trusts first */
387
388                 if (!domain_is_forest_root(state->domain))
389                         rescan_forest_root_trusts();
390                 else
391                         rescan_forest_trusts();
392
393         } else if (domain_is_forest_root(state->domain)) {
394                 /* Once we have done root forest trust search, we can
395                    go on to search the trusted forests */
396
397                 rescan_forest_trusts();
398         }
399
400         TALLOC_FREE(state);
401
402         return;
403 }
404
405 /********************************************************************
406  Scan the trusts of our forest root
407 ********************************************************************/
408
409 static void rescan_forest_root_trusts( void )
410 {
411         struct winbindd_tdc_domain *dom_list = NULL;
412         size_t num_trusts = 0;
413         int i;
414
415         /* The only transitive trusts supported by Windows 2003 AD are
416            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
417            first two are handled in forest and listed by
418            DsEnumerateDomainTrusts().  Forest trusts are not so we
419            have to do that ourselves. */
420
421         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
422                 return;
423
424         for ( i=0; i<num_trusts; i++ ) {
425                 struct winbindd_domain *d = NULL;
426
427                 /* Find the forest root.  Don't necessarily trust
428                    the domain_list() as our primary domain may not
429                    have been initialized. */
430
431                 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
432                         continue;
433                 }
434
435                 /* Here's the forest root */
436
437                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
438
439                 if ( !d ) {
440                         d = add_trusted_domain( dom_list[i].domain_name,
441                                                 dom_list[i].dns_name,
442                                                 &cache_methods,
443                                                 &dom_list[i].sid );
444                 }
445
446                 if (d == NULL) {
447                         continue;
448                 }
449
450                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
451                           "for domain tree root %s (%s)\n",
452                           d->name, d->alt_name ));
453
454                 d->domain_flags = dom_list[i].trust_flags;
455                 d->domain_type  = dom_list[i].trust_type;
456                 d->domain_trust_attribs = dom_list[i].trust_attribs;
457
458                 add_trusted_domains( d );
459
460                 break;
461         }
462
463         TALLOC_FREE( dom_list );
464
465         return;
466 }
467
468 /********************************************************************
469  scan the transitive forest trusts (not our own)
470 ********************************************************************/
471
472
473 static void rescan_forest_trusts( void )
474 {
475         struct winbindd_domain *d = NULL;
476         struct winbindd_tdc_domain *dom_list = NULL;
477         size_t num_trusts = 0;
478         int i;
479
480         /* The only transitive trusts supported by Windows 2003 AD are
481            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
482            first two are handled in forest and listed by
483            DsEnumerateDomainTrusts().  Forest trusts are not so we
484            have to do that ourselves. */
485
486         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
487                 return;
488
489         for ( i=0; i<num_trusts; i++ ) {
490                 uint32 flags   = dom_list[i].trust_flags;
491                 uint32 type    = dom_list[i].trust_type;
492                 uint32 attribs = dom_list[i].trust_attribs;
493
494                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
495
496                 /* ignore our primary and internal domains */
497
498                 if ( d && (d->internal || d->primary ) )
499                         continue;
500
501                 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
502                      (type == LSA_TRUST_TYPE_UPLEVEL) &&
503                      (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
504                 {
505                         /* add the trusted domain if we don't know
506                            about it */
507
508                         if ( !d ) {
509                                 d = add_trusted_domain( dom_list[i].domain_name,
510                                                         dom_list[i].dns_name,
511                                                         &cache_methods,
512                                                         &dom_list[i].sid );
513                         }
514
515                         if (d == NULL) {
516                                 continue;
517                         }
518
519                         DEBUG(10,("Following trust path for domain %s (%s)\n",
520                                   d->name, d->alt_name ));
521                         add_trusted_domains( d );
522                 }
523         }
524
525         TALLOC_FREE( dom_list );
526
527         return;
528 }
529
530 /*********************************************************************
531  The process of updating the trusted domain list is a three step
532  async process:
533  (a) ask our domain
534  (b) ask the root domain in our forest
535  (c) ask the a DC in any Win2003 trusted forests
536 *********************************************************************/
537
538 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
539                             struct timeval now, void *private_data)
540 {
541         TALLOC_FREE(te);
542
543         /* I use to clear the cache here and start over but that
544            caused problems in child processes that needed the
545            trust dom list early on.  Removing it means we
546            could have some trusted domains listed that have been
547            removed from our primary domain's DC until a full
548            restart.  This should be ok since I think this is what
549            Windows does as well. */
550
551         /* this will only add new domains we didn't already know about
552            in the domain_list()*/
553
554         add_trusted_domains( find_our_domain() );
555
556         te = tevent_add_timer(
557                 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
558                 rescan_trusted_domains, NULL);
559         /*
560          * If te == NULL, there's not much we can do here. Don't fail, the
561          * only thing we miss is new trusted domains.
562          */
563
564         return;
565 }
566
567 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
568                                                    struct winbindd_cli_state *state)
569 {
570         /* Ensure null termination */
571         state->request->domain_name
572                 [sizeof(state->request->domain_name)-1]='\0';
573         state->request->data.init_conn.dcname
574                 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
575
576         if (strlen(state->request->data.init_conn.dcname) > 0) {
577                 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
578         }
579
580         init_dc_connection(domain, false);
581
582         if (!domain->initialized) {
583                 /* If we return error here we can't do any cached authentication,
584                    but we may be in disconnected mode and can't initialize correctly.
585                    Do what the previous code did and just return without initialization,
586                    once we go online we'll re-initialize.
587                 */
588                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
589                         "online = %d\n", domain->name, (int)domain->online ));
590         }
591
592         fstrcpy(state->response->data.domain_info.name, domain->name);
593         fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
594         sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
595
596         state->response->data.domain_info.native_mode
597                 = domain->native_mode;
598         state->response->data.domain_info.active_directory
599                 = domain->active_directory;
600         state->response->data.domain_info.primary
601                 = domain->primary;
602
603         return WINBINDD_OK;
604 }
605
606 /* Look up global info for the winbind daemon */
607 bool init_domain_list(void)
608 {
609         int role = lp_server_role();
610
611         /* Free existing list */
612         free_domain_list();
613
614         /* BUILTIN domain */
615
616         (void)add_trusted_domain("BUILTIN", NULL, &cache_methods,
617                                     &global_sid_Builtin);
618
619         /* Local SAM */
620
621         if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
622                 struct winbindd_domain *domain;
623                 enum netr_SchannelType sec_chan_type;
624                 const char *account_name;
625                 struct samr_Password current_nt_hash;
626                 bool ok;
627
628                 domain = add_trusted_domain(get_global_sam_name(), lp_dnsdomain(),
629                                             &cache_methods, get_global_sam_sid());
630                 if (domain == NULL) {
631                         DEBUG(0, ("Failed to add our own, local AD domain to winbindd's internal list\n"));
632                         return false;
633                 }
634
635                 /*
636                  * We need to call this to find out if we are an RODC
637                  */
638                 ok = get_trust_pw_hash(domain->name,
639                                        current_nt_hash.hash,
640                                        &account_name,
641                                        &sec_chan_type);
642                 if (!ok) {
643                         DEBUG(0, ("Failed to fetch our own, local AD domain join password for winbindd's internal use\n"));
644                         return false;
645                 }
646                 if (sec_chan_type == SEC_CHAN_RODC) {
647                         domain->rodc = true;
648                 }
649
650         } else {
651                 (void)add_trusted_domain(get_global_sam_name(), NULL,
652                                          &cache_methods, get_global_sam_sid());
653         }
654         /* Add ourselves as the first entry. */
655
656         if ( role == ROLE_DOMAIN_MEMBER ) {
657                 struct winbindd_domain *domain;
658                 struct dom_sid our_sid;
659
660                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
661                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
662                         return False;
663                 }
664
665                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
666                                              &cache_methods, &our_sid);
667                 if (domain) {
668                         /* Even in the parent winbindd we'll need to
669                            talk to the DC, so try and see if we can
670                            contact it. Theoretically this isn't neccessary
671                            as the init_dc_connection() in init_child_recv()
672                            will do this, but we can start detecting the DC
673                            early here. */
674                         set_domain_online_request(domain);
675                 }
676         }
677
678         return True;
679 }
680
681 /**
682  * Given a domain name, return the struct winbindd domain info for it
683  *
684  * @note Do *not* pass lp_workgroup() to this function.  domain_list
685  *       may modify it's value, and free that pointer.  Instead, our local
686  *       domain may be found by calling find_our_domain().
687  *       directly.
688  *
689  *
690  * @return The domain structure for the named domain, if it is working.
691  */
692
693 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
694 {
695         struct winbindd_domain *domain;
696
697         /* Search through list */
698
699         for (domain = domain_list(); domain != NULL; domain = domain->next) {
700                 if (strequal(domain_name, domain->name) ||
701                     (domain->alt_name != NULL &&
702                      strequal(domain_name, domain->alt_name))) {
703                         return domain;
704                 }
705         }
706
707         /* Not found */
708
709         return NULL;
710 }
711
712 struct winbindd_domain *find_domain_from_name(const char *domain_name)
713 {
714         struct winbindd_domain *domain;
715
716         domain = find_domain_from_name_noinit(domain_name);
717
718         if (domain == NULL)
719                 return NULL;
720
721         if (!domain->initialized)
722                 init_dc_connection(domain, false);
723
724         return domain;
725 }
726
727 /* Given a domain sid, return the struct winbindd domain info for it */
728
729 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
730 {
731         struct winbindd_domain *domain;
732
733         /* Search through list */
734
735         for (domain = domain_list(); domain != NULL; domain = domain->next) {
736                 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
737                         return domain;
738         }
739
740         /* Not found */
741
742         return NULL;
743 }
744
745 /* Given a domain sid, return the struct winbindd domain info for it */
746
747 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
748 {
749         struct winbindd_domain *domain;
750
751         domain = find_domain_from_sid_noinit(sid);
752
753         if (domain == NULL)
754                 return NULL;
755
756         if (!domain->initialized)
757                 init_dc_connection(domain, false);
758
759         return domain;
760 }
761
762 struct winbindd_domain *find_our_domain(void)
763 {
764         struct winbindd_domain *domain;
765
766         /* Search through list */
767
768         for (domain = domain_list(); domain != NULL; domain = domain->next) {
769                 if (domain->primary)
770                         return domain;
771         }
772
773         smb_panic("Could not find our domain");
774         return NULL;
775 }
776
777 struct winbindd_domain *find_root_domain(void)
778 {
779         struct winbindd_domain *ours = find_our_domain();
780
781         if (ours->forest_name == NULL) {
782                 return NULL;
783         }
784
785         return find_domain_from_name( ours->forest_name );
786 }
787
788 struct winbindd_domain *find_builtin_domain(void)
789 {
790         struct winbindd_domain *domain;
791
792         domain = find_domain_from_sid(&global_sid_Builtin);
793         if (domain == NULL) {
794                 smb_panic("Could not find BUILTIN domain");
795         }
796
797         return domain;
798 }
799
800 /* Find the appropriate domain to lookup a name or SID */
801
802 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
803 {
804         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
805
806         if ( sid_check_is_in_unix_groups(sid) ||
807              sid_check_is_unix_groups(sid) ||
808              sid_check_is_in_unix_users(sid) ||
809              sid_check_is_unix_users(sid) )
810         {
811                 return find_domain_from_sid(get_global_sam_sid());
812         }
813
814         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
815          * one to contact the external DC's. On member servers the internal
816          * domains are different: These are part of the local SAM. */
817
818         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
819
820         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
821                 DEBUG(10, ("calling find_domain_from_sid\n"));
822                 return find_domain_from_sid(sid);
823         }
824
825         /* On a member server a query for SID or name can always go to our
826          * primary DC. */
827
828         DEBUG(10, ("calling find_our_domain\n"));
829         return find_our_domain();
830 }
831
832 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
833 {
834         if ( strequal(domain_name, unix_users_domain_name() ) ||
835              strequal(domain_name, unix_groups_domain_name() ) )
836         {
837                 /*
838                  * The "Unix User" and "Unix Group" domain our handled by
839                  * passdb
840                  */
841                 return find_domain_from_name_noinit( get_global_sam_name() );
842         }
843
844         if (IS_DC || strequal(domain_name, "BUILTIN") ||
845             strequal(domain_name, get_global_sam_name()))
846                 return find_domain_from_name_noinit(domain_name);
847
848
849         return find_our_domain();
850 }
851
852 /* Is this a domain which we may assume no DOMAIN\ prefix? */
853
854 static bool assume_domain(const char *domain)
855 {
856         /* never assume the domain on a standalone server */
857
858         if ( lp_server_role() == ROLE_STANDALONE )
859                 return False;
860
861         /* domain member servers may possibly assume for the domain name */
862
863         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
864                 if ( !strequal(lp_workgroup(), domain) )
865                         return False;
866
867                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
868                         return True;
869         }
870
871         /* only left with a domain controller */
872
873         if ( strequal(get_global_sam_name(), domain) )  {
874                 return True;
875         }
876
877         return False;
878 }
879
880 /* Parse a string of the form DOMAIN\user into a domain and a user */
881
882 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
883 {
884         char *p = strchr(domuser,*lp_winbind_separator());
885
886         if ( !p ) {
887                 fstrcpy(user, domuser);
888
889                 if ( assume_domain(lp_workgroup())) {
890                         fstrcpy(domain, lp_workgroup());
891                 } else if ((p = strchr(domuser, '@')) != NULL) {
892                         fstrcpy(domain, p + 1);
893                         user[PTR_DIFF(p, domuser)] = 0;
894                 } else {
895                         return False;
896                 }
897         } else {
898                 fstrcpy(user, p+1);
899                 fstrcpy(domain, domuser);
900                 domain[PTR_DIFF(p, domuser)] = 0;
901         }
902
903         return strupper_m(domain);
904 }
905
906 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
907                               char **domain, char **user)
908 {
909         fstring fstr_domain, fstr_user;
910         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
911                 return False;
912         }
913         *domain = talloc_strdup(mem_ctx, fstr_domain);
914         *user = talloc_strdup(mem_ctx, fstr_user);
915         return ((*domain != NULL) && (*user != NULL));
916 }
917
918 /* Ensure an incoming username from NSS is fully qualified. Replace the
919    incoming fstring with DOMAIN <separator> user. Returns the same
920    values as parse_domain_user() but also replaces the incoming username.
921    Used to ensure all names are fully qualified within winbindd.
922    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
923    The protocol definitions of auth_crap, chng_pswd_auth_crap
924    really should be changed to use this instead of doing things
925    by hand. JRA. */
926
927 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
928 {
929         if (!parse_domain_user(username_inout, domain, user)) {
930                 return False;
931         }
932         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
933                  domain, *lp_winbind_separator(),
934                  user);
935         return True;
936 }
937
938 /*
939     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
940     'winbind separator' options.
941     This means:
942         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
943         lp_workgroup()
944
945     If we are a PDC or BDC, and this is for our domain, do likewise.
946
947     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
948     username is then unqualified in unix
949
950     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
951 */
952 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
953 {
954         fstring tmp_user;
955
956         fstrcpy(tmp_user, user);
957         (void)strlower_m(tmp_user);
958
959         if (can_assume && assume_domain(domain)) {
960                 strlcpy(name, tmp_user, sizeof(fstring));
961         } else {
962                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
963                          domain, *lp_winbind_separator(),
964                          tmp_user);
965         }
966 }
967
968 /**
969  * talloc version of fill_domain_username()
970  * return NULL on talloc failure.
971  */
972 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
973                                   const char *domain,
974                                   const char *user,
975                                   bool can_assume)
976 {
977         char *tmp_user, *name;
978
979         tmp_user = talloc_strdup(mem_ctx, user);
980         if (!strlower_m(tmp_user)) {
981                 TALLOC_FREE(tmp_user);
982                 return NULL;
983         }
984
985         if (can_assume && assume_domain(domain)) {
986                 name = tmp_user;
987         } else {
988                 name = talloc_asprintf(mem_ctx, "%s%c%s",
989                                        domain,
990                                        *lp_winbind_separator(),
991                                        tmp_user);
992                 TALLOC_FREE(tmp_user);
993         }
994
995         return name;
996 }
997
998 /*
999  * Client list accessor functions
1000  */
1001
1002 static struct winbindd_cli_state *_client_list;
1003 static int _num_clients;
1004
1005 /* Return list of all connected clients */
1006
1007 struct winbindd_cli_state *winbindd_client_list(void)
1008 {
1009         return _client_list;
1010 }
1011
1012 /* Add a connection to the list */
1013
1014 void winbindd_add_client(struct winbindd_cli_state *cli)
1015 {
1016         DLIST_ADD(_client_list, cli);
1017         _num_clients++;
1018 }
1019
1020 /* Remove a client from the list */
1021
1022 void winbindd_remove_client(struct winbindd_cli_state *cli)
1023 {
1024         DLIST_REMOVE(_client_list, cli);
1025         _num_clients--;
1026 }
1027
1028 /* Return number of open clients */
1029
1030 int winbindd_num_clients(void)
1031 {
1032         return _num_clients;
1033 }
1034
1035 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1036                                   TALLOC_CTX *mem_ctx,
1037                                   const struct dom_sid *user_sid,
1038                                   uint32_t *p_num_groups, struct dom_sid **user_sids)
1039 {
1040         struct netr_SamInfo3 *info3 = NULL;
1041         NTSTATUS status = NT_STATUS_NO_MEMORY;
1042         uint32_t num_groups = 0;
1043
1044         DEBUG(3,(": lookup_usergroups_cached\n"));
1045
1046         *user_sids = NULL;
1047         *p_num_groups = 0;
1048
1049         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1050
1051         if (info3 == NULL) {
1052                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1053         }
1054
1055         if (info3->base.groups.count == 0) {
1056                 TALLOC_FREE(info3);
1057                 return NT_STATUS_UNSUCCESSFUL;
1058         }
1059
1060         /*
1061          * Before bug #7843 the "Domain Local" groups were added with a
1062          * lookupuseraliases call, but this isn't done anymore for our domain
1063          * so we need to resolve resource groups here.
1064          *
1065          * When to use Resource Groups:
1066          * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1067          */
1068         status = sid_array_from_info3(mem_ctx, info3,
1069                                       user_sids,
1070                                       &num_groups,
1071                                       false);
1072
1073         if (!NT_STATUS_IS_OK(status)) {
1074                 TALLOC_FREE(info3);
1075                 return status;
1076         }
1077
1078         TALLOC_FREE(info3);
1079         *p_num_groups = num_groups;
1080         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1081
1082         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1083
1084         return status;
1085 }
1086
1087 /*********************************************************************
1088  We use this to remove spaces from user and group names
1089 ********************************************************************/
1090
1091 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1092                              struct winbindd_domain *domain,
1093                              const char *name,
1094                              char **normalized)
1095 {
1096         NTSTATUS nt_status;
1097
1098         if (!name || !normalized) {
1099                 return NT_STATUS_INVALID_PARAMETER;
1100         }
1101
1102         if (!lp_winbind_normalize_names()) {
1103                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1104         }
1105
1106         /* Alias support and whitespace replacement are mutually
1107            exclusive */
1108
1109         nt_status = resolve_username_to_alias(mem_ctx, domain,
1110                                               name, normalized );
1111         if (NT_STATUS_IS_OK(nt_status)) {
1112                 /* special return code to let the caller know we
1113                    mapped to an alias */
1114                 return NT_STATUS_FILE_RENAMED;
1115         }
1116
1117         /* check for an unreachable domain */
1118
1119         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1120                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1121                          domain->name));
1122                 set_domain_offline(domain);
1123                 return nt_status;
1124         }
1125
1126         /* deal with whitespace */
1127
1128         *normalized = talloc_strdup(mem_ctx, name);
1129         if (!(*normalized)) {
1130                 return NT_STATUS_NO_MEMORY;
1131         }
1132
1133         all_string_sub( *normalized, " ", "_", 0 );
1134
1135         return NT_STATUS_OK;
1136 }
1137
1138 /*********************************************************************
1139  We use this to do the inverse of normalize_name_map()
1140 ********************************************************************/
1141
1142 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1143                               char *name,
1144                               char **normalized)
1145 {
1146         NTSTATUS nt_status;
1147         struct winbindd_domain *domain = find_our_domain();
1148
1149         if (!name || !normalized) {
1150                 return NT_STATUS_INVALID_PARAMETER;
1151         }
1152
1153         if (!lp_winbind_normalize_names()) {
1154                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1155         }
1156
1157         /* Alias support and whitespace replacement are mutally
1158            exclusive */
1159
1160         /* When mapping from an alias to a username, we don't know the
1161            domain.  But we only need a domain structure to cache
1162            a successful lookup , so just our own domain structure for
1163            the seqnum. */
1164
1165         nt_status = resolve_alias_to_username(mem_ctx, domain,
1166                                               name, normalized);
1167         if (NT_STATUS_IS_OK(nt_status)) {
1168                 /* Special return code to let the caller know we mapped
1169                    from an alias */
1170                 return NT_STATUS_FILE_RENAMED;
1171         }
1172
1173         /* check for an unreachable domain */
1174
1175         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1176                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1177                          domain->name));
1178                 set_domain_offline(domain);
1179                 return nt_status;
1180         }
1181
1182         /* deal with whitespace */
1183
1184         *normalized = talloc_strdup(mem_ctx, name);
1185         if (!(*normalized)) {
1186                 return NT_STATUS_NO_MEMORY;
1187         }
1188
1189         all_string_sub(*normalized, "_", " ", 0);
1190
1191         return NT_STATUS_OK;
1192 }
1193
1194 /*********************************************************************
1195  ********************************************************************/
1196
1197 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1198 {
1199         struct winbindd_tdc_domain *tdc = NULL;
1200         TALLOC_CTX *frame = talloc_stackframe();
1201         bool ret = false;
1202
1203         /* We can contact the domain if it is our primary domain */
1204
1205         if (domain->primary) {
1206                 ret = true;
1207                 goto done;
1208         }
1209
1210         /* Trust the TDC cache and not the winbindd_domain flags */
1211
1212         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1213                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1214                           domain->name));
1215                 ret = false;
1216                 goto done;
1217         }
1218
1219         /* Can always contact a domain that is in out forest */
1220
1221         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1222                 ret = true;
1223                 goto done;
1224         }
1225
1226         /*
1227          * On a _member_ server, we cannot contact the domain if it
1228          * is running AD and we have no inbound trust.
1229          */
1230
1231         if (!IS_DC &&
1232              domain->active_directory &&
1233             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1234         {
1235                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1236                            "and we have no inbound trust.\n", domain->name));
1237                 goto done;
1238         }
1239
1240         /* Assume everything else is ok (probably not true but what
1241            can you do?) */
1242
1243         ret = true;
1244
1245 done:
1246         talloc_destroy(frame);
1247
1248         return ret;
1249 }
1250
1251 /*********************************************************************
1252  ********************************************************************/
1253
1254 bool winbindd_internal_child(struct winbindd_child *child)
1255 {
1256         if ((child == idmap_child()) || (child == locator_child())) {
1257                 return True;
1258         }
1259
1260         return False;
1261 }
1262
1263 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1264
1265 /*********************************************************************
1266  ********************************************************************/
1267
1268 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1269 {
1270         char *var = NULL;
1271         char addr[INET6_ADDRSTRLEN];
1272         const char *kdc = NULL;
1273         int lvl = 11;
1274
1275         if (!domain || !domain->alt_name || !*domain->alt_name) {
1276                 return;
1277         }
1278
1279         if (domain->initialized && !domain->active_directory) {
1280                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1281                         domain->alt_name));
1282                 return;
1283         }
1284
1285         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1286         kdc = addr;
1287         if (!*kdc) {
1288                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1289                         domain->alt_name));
1290                 kdc = domain->dcname;
1291         }
1292
1293         if (!kdc || !*kdc) {
1294                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1295                         domain->alt_name));
1296                 return;
1297         }
1298
1299         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1300                                 domain->alt_name) == -1) {
1301                 return;
1302         }
1303
1304         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1305                 var, kdc));
1306
1307         setenv(var, kdc, 1);
1308         free(var);
1309 }
1310
1311 /*********************************************************************
1312  ********************************************************************/
1313
1314 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1315 {
1316         struct winbindd_domain *our_dom = find_our_domain();
1317
1318         winbindd_set_locator_kdc_env(domain);
1319
1320         if (domain != our_dom) {
1321                 winbindd_set_locator_kdc_env(our_dom);
1322         }
1323 }
1324
1325 /*********************************************************************
1326  ********************************************************************/
1327
1328 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1329 {
1330         char *var = NULL;
1331
1332         if (!domain || !domain->alt_name || !*domain->alt_name) {
1333                 return;
1334         }
1335
1336         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1337                                 domain->alt_name) == -1) {
1338                 return;
1339         }
1340
1341         unsetenv(var);
1342         free(var);
1343 }
1344 #else
1345
1346 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1347 {
1348         return;
1349 }
1350
1351 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1352 {
1353         return;
1354 }
1355
1356 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1357
1358 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1359 {
1360         resp->data.auth.nt_status = NT_STATUS_V(result);
1361         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1362
1363         /* we might have given a more useful error above */
1364         if (*resp->data.auth.error_string == '\0')
1365                 fstrcpy(resp->data.auth.error_string,
1366                         get_friendly_nt_error_msg(result));
1367         resp->data.auth.pam_error = nt_status_to_pam(result);
1368 }
1369
1370 bool is_domain_offline(const struct winbindd_domain *domain)
1371 {
1372         if (!lp_winbind_offline_logon()) {
1373                 return false;
1374         }
1375         if (get_global_winbindd_state_offline()) {
1376                 return true;
1377         }
1378         return !domain->online;
1379 }
1380
1381 bool is_domain_online(const struct winbindd_domain *domain)
1382 {
1383         return !is_domain_offline(domain);
1384 }
1385
1386 /**
1387  * Parse an char array into a list of sids.
1388  *
1389  * The input sidstr should consist of 0-terminated strings
1390  * representing sids, separated by newline characters '\n'.
1391  * The list is terminated by an empty string, i.e.
1392  * character '\0' directly following a character '\n'
1393  * (or '\0' right at the start of sidstr).
1394  */
1395 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1396                    struct dom_sid **sids, uint32_t *num_sids)
1397 {
1398         const char *p;
1399
1400         p = sidstr;
1401         if (p == NULL)
1402                 return False;
1403
1404         while (p[0] != '\0') {
1405                 struct dom_sid sid;
1406                 const char *q = NULL;
1407
1408                 if (!dom_sid_parse_endp(p, &sid, &q)) {
1409                         DEBUG(1, ("Could not parse sid %s\n", p));
1410                         return false;
1411                 }
1412                 if ((q == NULL) || (q[0] != '\n')) {
1413                         DEBUG(1, ("Got invalid sidstr: %s\n", p));
1414                         return false;
1415                 }
1416                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1417                                                       num_sids)))
1418                 {
1419                         return False;
1420                 }
1421                 p = q+1;
1422         }
1423         return True;
1424 }