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