Convert the winbind parent->child communication to wb_reqtrans
[amitay/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
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
28
29 extern struct winbindd_methods cache_methods;
30 extern struct winbindd_methods builtin_passdb_methods;
31 extern struct winbindd_methods sam_passdb_methods;
32
33
34 /**
35  * @file winbindd_util.c
36  *
37  * Winbind daemon for NT domain authentication nss module.
38  **/
39
40
41 /* The list of trusted domains.  Note that the list can be deleted and
42    recreated using the init_domain_list() function so pointers to
43    individual winbindd_domain structures cannot be made.  Keep a copy of
44    the domain name instead. */
45
46 static struct winbindd_domain *_domain_list = NULL;
47
48 /**
49    When was the last scan of trusted domains done?
50
51    0 == not ever
52 */
53
54 static time_t last_trustdom_scan;
55
56 struct winbindd_domain *domain_list(void)
57 {
58         /* Initialise list */
59
60         if ((!_domain_list) && (!init_domain_list())) {
61                 smb_panic("Init_domain_list failed");
62         }
63
64         return _domain_list;
65 }
66
67 /* Free all entries in the trusted domain list */
68
69 void free_domain_list(void)
70 {
71         struct winbindd_domain *domain = _domain_list;
72
73         while(domain) {
74                 struct winbindd_domain *next = domain->next;
75
76                 DLIST_REMOVE(_domain_list, domain);
77                 SAFE_FREE(domain);
78                 domain = next;
79         }
80 }
81
82 static bool is_internal_domain(const DOM_SID *sid)
83 {
84         if (sid == NULL)
85                 return False;
86
87         if ( IS_DC )
88                 return sid_check_is_builtin(sid);
89
90         return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
91 }
92
93 static bool is_in_internal_domain(const DOM_SID *sid)
94 {
95         if (sid == NULL)
96                 return False;
97
98         if ( IS_DC )
99                 return sid_check_is_in_builtin(sid);
100
101         return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
102 }
103
104
105 /* Add a trusted domain to our list of domains */
106 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
107                                                   struct winbindd_methods *methods,
108                                                   const DOM_SID *sid)
109 {
110         struct winbindd_domain *domain;
111         const char *alternative_name = NULL;
112         char *idmap_config_option;
113         const char *param;
114         const char **ignored_domains, **dom;
115
116         ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
117         for (dom=ignored_domains; dom && *dom; dom++) {
118                 if (gen_fnmatch(*dom, domain_name) == 0) {
119                         DEBUG(2,("Ignoring domain '%s'\n", domain_name));
120                         return NULL;
121                 }
122         }
123
124         /* ignore alt_name if we are not in an AD domain */
125
126         if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
127                 alternative_name = alt_name;
128         }
129
130         /* We can't call domain_list() as this function is called from
131            init_domain_list() and we'll get stuck in a loop. */
132         for (domain = _domain_list; domain; domain = domain->next) {
133                 if (strequal(domain_name, domain->name) ||
134                     strequal(domain_name, domain->alt_name))
135                 {
136                         break;
137                 }
138
139                 if (alternative_name && *alternative_name)
140                 {
141                         if (strequal(alternative_name, domain->name) ||
142                             strequal(alternative_name, domain->alt_name))
143                         {
144                                 break;
145                         }
146                 }
147
148                 if (sid)
149                 {
150                         if (is_null_sid(sid)) {
151                                 continue;
152                         }
153
154                         if (sid_equal(sid, &domain->sid)) {
155                                 break;
156                         }
157                 }
158         }
159
160         /* See if we found a match.  Check if we need to update the
161            SID. */
162
163         if ( domain && sid) {
164                 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
165                         sid_copy( &domain->sid, sid );
166
167                 return domain;
168         }
169
170         /* Create new domain entry */
171
172         if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
173                 return NULL;
174
175         /* Fill in fields */
176
177         ZERO_STRUCTP(domain);
178
179         fstrcpy(domain->name, domain_name);
180         if (alternative_name) {
181                 fstrcpy(domain->alt_name, alternative_name);
182         }
183
184         domain->methods = methods;
185         domain->backend = NULL;
186         domain->internal = is_internal_domain(sid);
187         domain->sequence_number = DOM_SEQUENCE_NONE;
188         domain->last_seq_check = 0;
189         domain->initialized = False;
190         domain->online = is_internal_domain(sid);
191         domain->check_online_timeout = 0;
192         domain->dc_probe_pid = (pid_t)-1;
193         if (sid) {
194                 sid_copy(&domain->sid, sid);
195         }
196
197         /* Link to domain list */
198         DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
199
200         wcache_tdc_add_domain( domain );
201
202         idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
203                                               domain->name);
204         if (idmap_config_option == NULL) {
205                 DEBUG(0, ("talloc failed, not looking for idmap config\n"));
206                 goto done;
207         }
208
209         param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);
210
211         DEBUG(10, ("%s : range = %s\n", idmap_config_option,
212                    param ? param : "not defined"));
213
214         if (param != NULL) {
215                 unsigned low_id, high_id;
216                 if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
217                         DEBUG(1, ("invalid range syntax in %s: %s\n",
218                                   idmap_config_option, param));
219                         goto done;
220                 }
221                 if (low_id > high_id) {
222                         DEBUG(1, ("invalid range in %s: %s\n",
223                                   idmap_config_option, param));
224                         goto done;
225                 }
226                 domain->have_idmap_config = true;
227                 domain->id_range_low = low_id;
228                 domain->id_range_high = high_id;
229         }
230
231 done:
232
233         DEBUG(2,("Added domain %s %s %s\n",
234                  domain->name, domain->alt_name,
235                  &domain->sid?sid_string_dbg(&domain->sid):""));
236
237         return domain;
238 }
239
240 /********************************************************************
241   rescan our domains looking for new trusted domains
242 ********************************************************************/
243
244 struct trustdom_state {
245         TALLOC_CTX *mem_ctx;
246         bool primary;
247         bool forest_root;
248         struct winbindd_response *response;
249 };
250
251 static void trustdom_recv(void *private_data, bool success);
252 static void rescan_forest_root_trusts( void );
253 static void rescan_forest_trusts( void );
254
255 static void add_trusted_domains( struct winbindd_domain *domain )
256 {
257         TALLOC_CTX *mem_ctx;
258         struct winbindd_request *request;
259         struct winbindd_response *response;
260         uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
261
262         struct trustdom_state *state;
263
264         mem_ctx = talloc_init("add_trusted_domains");
265         if (mem_ctx == NULL) {
266                 DEBUG(0, ("talloc_init failed\n"));
267                 return;
268         }
269
270         request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
271         response = TALLOC_P(mem_ctx, struct winbindd_response);
272         state = TALLOC_P(mem_ctx, struct trustdom_state);
273
274         if ((request == NULL) || (response == NULL) || (state == NULL)) {
275                 DEBUG(0, ("talloc failed\n"));
276                 talloc_destroy(mem_ctx);
277                 return;
278         }
279
280         state->mem_ctx = mem_ctx;
281         state->response = response;
282
283         /* Flags used to know how to continue the forest trust search */
284
285         state->primary = domain->primary;
286         state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
287
288         request->length = sizeof(*request);
289         request->cmd = WINBINDD_LIST_TRUSTDOM;
290
291         async_domain_request(mem_ctx, domain, request, response,
292                              trustdom_recv, state);
293 }
294
295 static void trustdom_recv(void *private_data, bool success)
296 {
297         struct trustdom_state *state =
298                 talloc_get_type_abort(private_data, struct trustdom_state);
299         struct winbindd_response *response = state->response;
300         char *p;
301
302         if ((!success) || (response->result != WINBINDD_OK)) {
303                 DEBUG(1, ("Could not receive trustdoms\n"));
304                 talloc_destroy(state->mem_ctx);
305                 return;
306         }
307
308         p = (char *)response->extra_data.data;
309
310         while ((p != NULL) && (*p != '\0')) {
311                 char *q, *sidstr, *alt_name;
312                 DOM_SID sid;
313                 struct winbindd_domain *domain;
314                 char *alternate_name = NULL;
315
316                 alt_name = strchr(p, '\\');
317                 if (alt_name == NULL) {
318                         DEBUG(0, ("Got invalid trustdom response\n"));
319                         break;
320                 }
321
322                 *alt_name = '\0';
323                 alt_name += 1;
324
325                 sidstr = strchr(alt_name, '\\');
326                 if (sidstr == NULL) {
327                         DEBUG(0, ("Got invalid trustdom response\n"));
328                         break;
329                 }
330
331                 *sidstr = '\0';
332                 sidstr += 1;
333
334                 q = strchr(sidstr, '\n');
335                 if (q != NULL)
336                         *q = '\0';
337
338                 if (!string_to_sid(&sid, sidstr)) {
339                         /* Allow NULL sid for sibling domains */
340                         if ( strcmp(sidstr,"S-0-0") == 0) {
341                                 sid_copy( &sid, &global_sid_NULL);
342                         } else {
343                                 DEBUG(0, ("Got invalid trustdom response\n"));
344                                 break;
345                         }
346                 }
347
348                 /* use the real alt_name if we have one, else pass in NULL */
349
350                 if ( !strequal( alt_name, "(null)" ) )
351                         alternate_name = alt_name;
352
353                 /* If we have an existing domain structure, calling
354                    add_trusted_domain() will update the SID if
355                    necessary.  This is important because we need the
356                    SID for sibling domains */
357
358                 if ( find_domain_from_name_noinit(p) != NULL ) {
359                         domain = add_trusted_domain(p, alternate_name,
360                                                     &cache_methods,
361                                                     &sid);
362                 } else {
363                         domain = add_trusted_domain(p, alternate_name,
364                                                     &cache_methods,
365                                                     &sid);
366                         if (domain) {
367                                 setup_domain_child(domain,
368                                                    &domain->child);
369                         }
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->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 ( !state->forest_root )
389                         rescan_forest_root_trusts();
390                 else
391                         rescan_forest_trusts();
392
393         } else if ( state->forest_root ) {
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_destroy(state->mem_ctx);
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 == NETR_TRUST_TYPE_UPLEVEL) &&
503                      (attribs == NETR_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( void )
539 {
540         time_t now = time(NULL);
541
542         /* Check that we allow trusted domains at all */
543         if (!lp_allow_trusted_domains())
544                 return;
545
546         /* see if the time has come... */
547
548         if ((now >= last_trustdom_scan) &&
549             ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
550                 return;
551
552         /* I use to clear the cache here and start over but that
553            caused problems in child processes that needed the
554            trust dom list early on.  Removing it means we
555            could have some trusted domains listed that have been
556            removed from our primary domain's DC until a full
557            restart.  This should be ok since I think this is what
558            Windows does as well. */
559
560         /* this will only add new domains we didn't already know about
561            in the domain_list()*/
562
563         add_trusted_domains( find_our_domain() );
564
565         last_trustdom_scan = now;
566
567         return;
568 }
569
570 struct init_child_state {
571         TALLOC_CTX *mem_ctx;
572         struct winbindd_domain *domain;
573         struct winbindd_request *request;
574         struct winbindd_response *response;
575         void (*continuation)(void *private_data, bool success);
576         void *private_data;
577 };
578
579 static void init_child_recv(void *private_data, bool success);
580 static void init_child_getdc_recv(void *private_data, bool success);
581
582 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
583                                            void (*continuation)(void *private_data,
584                                                                 bool success),
585                                            void *private_data)
586 {
587         TALLOC_CTX *mem_ctx;
588         struct winbindd_request *request;
589         struct winbindd_response *response;
590         struct init_child_state *state;
591         struct winbindd_domain *request_domain;
592
593         mem_ctx = talloc_init("init_child_connection");
594         if (mem_ctx == NULL) {
595                 DEBUG(0, ("talloc_init failed\n"));
596                 return WINBINDD_ERROR;
597         }
598
599         request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
600         response = TALLOC_P(mem_ctx, struct winbindd_response);
601         state = TALLOC_P(mem_ctx, struct init_child_state);
602
603         if ((request == NULL) || (response == NULL) || (state == NULL)) {
604                 DEBUG(0, ("talloc failed\n"));
605                 TALLOC_FREE(mem_ctx);
606                 continuation(private_data, False);
607                 return WINBINDD_ERROR;
608         }
609
610         request->length = sizeof(*request);
611
612         state->mem_ctx = mem_ctx;
613         state->domain = domain;
614         state->request = request;
615         state->response = response;
616         state->continuation = continuation;
617         state->private_data = private_data;
618
619         if (IS_DC || domain->primary || domain->internal ) {
620                 /* The primary domain has to find the DC name itself */
621                 request->cmd = WINBINDD_INIT_CONNECTION;
622                 fstrcpy(request->domain_name, domain->name);
623                 request->data.init_conn.is_primary = domain->primary ? true : false;
624                 fstrcpy(request->data.init_conn.dcname, "");
625                 async_request(mem_ctx, &domain->child, request, response,
626                               init_child_recv, state);
627                 return WINBINDD_PENDING;
628         }
629
630         /* This is *not* the primary domain, let's ask our DC about a DC
631          * name */
632
633         request->cmd = WINBINDD_GETDCNAME;
634         fstrcpy(request->domain_name, domain->name);
635
636         request_domain = find_our_domain();
637         async_domain_request(mem_ctx, request_domain, request, response,
638                              init_child_getdc_recv, state);
639         return WINBINDD_PENDING;
640 }
641
642 static void init_child_getdc_recv(void *private_data, bool success)
643 {
644         struct init_child_state *state =
645                 talloc_get_type_abort(private_data, struct init_child_state);
646         const char *dcname = "";
647
648         DEBUG(10, ("Received getdcname response\n"));
649
650         if (success && (state->response->result == WINBINDD_OK)) {
651                 dcname = state->response->data.dc_name;
652         }
653
654         state->request->cmd = WINBINDD_INIT_CONNECTION;
655         fstrcpy(state->request->domain_name, state->domain->name);
656         state->request->data.init_conn.is_primary = False;
657         fstrcpy(state->request->data.init_conn.dcname, dcname);
658
659         async_request(state->mem_ctx, &state->domain->child,
660                       state->request, state->response,
661                       init_child_recv, state);
662 }
663
664 static void init_child_recv(void *private_data, bool success)
665 {
666         struct init_child_state *state =
667                 talloc_get_type_abort(private_data, struct init_child_state);
668
669         DEBUG(5, ("Received child initialization response for domain %s\n",
670                   state->domain->name));
671
672         if ((!success) || (state->response->result != WINBINDD_OK)) {
673                 DEBUG(3, ("Could not init child\n"));
674                 state->continuation(state->private_data, False);
675                 talloc_destroy(state->mem_ctx);
676                 return;
677         }
678
679         fstrcpy(state->domain->name,
680                 state->response->data.domain_info.name);
681         fstrcpy(state->domain->alt_name,
682                 state->response->data.domain_info.alt_name);
683         if (!string_to_sid(&state->domain->sid,
684                       state->response->data.domain_info.sid)) {
685                 DEBUG(1,("init_child_recv: Could not convert sid %s "
686                         "from string\n",
687                         state->response->data.domain_info.sid));
688                 state->continuation(state->private_data, False);
689                 talloc_destroy(state->mem_ctx);
690                 return;
691         }
692
693         state->domain->native_mode =
694                 state->response->data.domain_info.native_mode;
695         state->domain->active_directory =
696                 state->response->data.domain_info.active_directory;
697
698         init_dc_connection(state->domain);
699
700         if (state->continuation != NULL)
701                 state->continuation(state->private_data, True);
702         talloc_destroy(state->mem_ctx);
703 }
704
705 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
706                                                    struct winbindd_cli_state *state)
707 {
708         /* Ensure null termination */
709         state->request->domain_name
710                 [sizeof(state->request->domain_name)-1]='\0';
711         state->request->data.init_conn.dcname
712                 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
713
714         if (strlen(state->request->data.init_conn.dcname) > 0) {
715                 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
716         }
717
718         init_dc_connection(domain);
719
720         if (!domain->initialized) {
721                 /* If we return error here we can't do any cached authentication,
722                    but we may be in disconnected mode and can't initialize correctly.
723                    Do what the previous code did and just return without initialization,
724                    once we go online we'll re-initialize.
725                 */
726                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
727                         "online = %d\n", domain->name, (int)domain->online ));
728         }
729
730         fstrcpy(state->response.data.domain_info.name, domain->name);
731         fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
732         sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
733
734         state->response.data.domain_info.native_mode
735                 = domain->native_mode;
736         state->response.data.domain_info.active_directory
737                 = domain->active_directory;
738         state->response.data.domain_info.primary
739                 = domain->primary;
740
741         return WINBINDD_OK;
742 }
743
744 /* Look up global info for the winbind daemon */
745 bool init_domain_list(void)
746 {
747         struct winbindd_domain *domain;
748         int role = lp_server_role();
749
750         /* Free existing list */
751         free_domain_list();
752
753         /* BUILTIN domain */
754
755         domain = add_trusted_domain("BUILTIN", NULL, &builtin_passdb_methods,
756                                     &global_sid_Builtin);
757         if (domain) {
758                 setup_domain_child(domain,
759                                    &domain->child);
760         }
761
762         /* Local SAM */
763
764         domain = add_trusted_domain(get_global_sam_name(), NULL,
765                                     &sam_passdb_methods, get_global_sam_sid());
766         if (domain) {
767                 if ( role != ROLE_DOMAIN_MEMBER ) {
768                         domain->primary = True;
769                 }
770                 setup_domain_child(domain,
771                                    &domain->child);
772         }
773
774         /* Add ourselves as the first entry. */
775
776         if ( role == ROLE_DOMAIN_MEMBER ) {
777                 DOM_SID our_sid;
778
779                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
780                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
781                         return False;
782                 }
783
784                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
785                                              &cache_methods, &our_sid);
786                 if (domain) {
787                         domain->primary = True;
788                         setup_domain_child(domain,
789                                            &domain->child);
790
791                         /* Even in the parent winbindd we'll need to
792                            talk to the DC, so try and see if we can
793                            contact it. Theoretically this isn't neccessary
794                            as the init_dc_connection() in init_child_recv()
795                            will do this, but we can start detecting the DC
796                            early here. */
797                         set_domain_online_request(domain);
798                 }
799         }
800
801         return True;
802 }
803
804 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
805 {
806         struct winbindd_domain *domain;
807         DOM_SID dom_sid;
808         uint32 rid;
809
810         /* Check if we even care */
811
812         if (!lp_allow_trusted_domains())
813                 return;
814
815         domain = find_domain_from_name_noinit( name );
816         if ( domain )
817                 return;
818
819         sid_copy( &dom_sid, user_sid );
820         if ( !sid_split_rid( &dom_sid, &rid ) )
821                 return;
822
823         /* add the newly discovered trusted domain */
824
825         domain = add_trusted_domain( name, NULL, &cache_methods,
826                                      &dom_sid);
827
828         if ( !domain )
829                 return;
830
831         /* assume this is a trust from a one-way transitive
832            forest trust */
833
834         domain->active_directory = True;
835         domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
836         domain->domain_type  = NETR_TRUST_TYPE_UPLEVEL;
837         domain->internal = False;
838         domain->online = True;
839
840         setup_domain_child(domain,
841                            &domain->child);
842
843         wcache_tdc_add_domain( domain );
844
845         return;
846 }
847
848 /**
849  * Given a domain name, return the struct winbindd domain info for it
850  *
851  * @note Do *not* pass lp_workgroup() to this function.  domain_list
852  *       may modify it's value, and free that pointer.  Instead, our local
853  *       domain may be found by calling find_our_domain().
854  *       directly.
855  *
856  *
857  * @return The domain structure for the named domain, if it is working.
858  */
859
860 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
861 {
862         struct winbindd_domain *domain;
863
864         /* Search through list */
865
866         for (domain = domain_list(); domain != NULL; domain = domain->next) {
867                 if (strequal(domain_name, domain->name) ||
868                     (domain->alt_name[0] &&
869                      strequal(domain_name, domain->alt_name))) {
870                         return domain;
871                 }
872         }
873
874         /* Not found */
875
876         return NULL;
877 }
878
879 struct winbindd_domain *find_domain_from_name(const char *domain_name)
880 {
881         struct winbindd_domain *domain;
882
883         domain = find_domain_from_name_noinit(domain_name);
884
885         if (domain == NULL)
886                 return NULL;
887
888         if (!domain->initialized)
889                 init_dc_connection(domain);
890
891         return domain;
892 }
893
894 /* Given a domain sid, return the struct winbindd domain info for it */
895
896 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
897 {
898         struct winbindd_domain *domain;
899
900         /* Search through list */
901
902         for (domain = domain_list(); domain != NULL; domain = domain->next) {
903                 if (sid_compare_domain(sid, &domain->sid) == 0)
904                         return domain;
905         }
906
907         /* Not found */
908
909         return NULL;
910 }
911
912 /* Given a domain sid, return the struct winbindd domain info for it */
913
914 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
915 {
916         struct winbindd_domain *domain;
917
918         domain = find_domain_from_sid_noinit(sid);
919
920         if (domain == NULL)
921                 return NULL;
922
923         if (!domain->initialized)
924                 init_dc_connection(domain);
925
926         return domain;
927 }
928
929 struct winbindd_domain *find_our_domain(void)
930 {
931         struct winbindd_domain *domain;
932
933         /* Search through list */
934
935         for (domain = domain_list(); domain != NULL; domain = domain->next) {
936                 if (domain->primary)
937                         return domain;
938         }
939
940         smb_panic("Could not find our domain");
941         return NULL;
942 }
943
944 struct winbindd_domain *find_root_domain(void)
945 {
946         struct winbindd_domain *ours = find_our_domain();
947
948         if ( !ours )
949                 return NULL;
950
951         if ( strlen(ours->forest_name) == 0 )
952                 return NULL;
953
954         return find_domain_from_name( ours->forest_name );
955 }
956
957 struct winbindd_domain *find_builtin_domain(void)
958 {
959         DOM_SID sid;
960         struct winbindd_domain *domain;
961
962         string_to_sid(&sid, "S-1-5-32");
963         domain = find_domain_from_sid(&sid);
964
965         if (domain == NULL) {
966                 smb_panic("Could not find BUILTIN domain");
967         }
968
969         return domain;
970 }
971
972 /* Find the appropriate domain to lookup a name or SID */
973
974 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
975 {
976         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
977
978         if ( sid_check_is_in_unix_groups(sid) ||
979              sid_check_is_unix_groups(sid) ||
980              sid_check_is_in_unix_users(sid) ||
981              sid_check_is_unix_users(sid) )
982         {
983                 return find_domain_from_sid(get_global_sam_sid());
984         }
985
986         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
987          * one to contact the external DC's. On member servers the internal
988          * domains are different: These are part of the local SAM. */
989
990         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
991
992         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
993                 DEBUG(10, ("calling find_domain_from_sid\n"));
994                 return find_domain_from_sid(sid);
995         }
996
997         /* On a member server a query for SID or name can always go to our
998          * primary DC. */
999
1000         DEBUG(10, ("calling find_our_domain\n"));
1001         return find_our_domain();
1002 }
1003
1004 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1005 {
1006         if ( strequal(domain_name, unix_users_domain_name() ) ||
1007              strequal(domain_name, unix_groups_domain_name() ) )
1008         {
1009                 return find_domain_from_name_noinit( get_global_sam_name() );
1010         }
1011
1012         if (IS_DC || strequal(domain_name, "BUILTIN") ||
1013             strequal(domain_name, get_global_sam_name()))
1014                 return find_domain_from_name_noinit(domain_name);
1015
1016         /* The "Unix User" and "Unix Group" domain our handled by passdb */
1017
1018         return find_our_domain();
1019 }
1020
1021 /* Lookup a sid in a domain from a name */
1022
1023 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
1024                                  enum winbindd_cmd orig_cmd,
1025                                  struct winbindd_domain *domain,
1026                                  const char *domain_name,
1027                                  const char *name, DOM_SID *sid,
1028                                  enum lsa_SidType *type)
1029 {
1030         NTSTATUS result;
1031
1032         /* Lookup name */
1033         result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
1034                                               domain_name, name, sid, type);
1035
1036         /* Return sid and type if lookup successful */
1037         if (!NT_STATUS_IS_OK(result)) {
1038                 *type = SID_NAME_UNKNOWN;
1039         }
1040
1041         return NT_STATUS_IS_OK(result);
1042 }
1043
1044 /**
1045  * @brief Lookup a name in a domain from a sid.
1046  *
1047  * @param sid Security ID you want to look up.
1048  * @param name On success, set to the name corresponding to @p sid.
1049  * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
1050  * @param type On success, contains the type of name: alias, group or
1051  * user.
1052  * @retval True if the name exists, in which case @p name and @p type
1053  * are set, otherwise False.
1054  **/
1055 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
1056                                  struct winbindd_domain *domain,
1057                                  DOM_SID *sid,
1058                                  char **dom_name,
1059                                  char **name,
1060                                  enum lsa_SidType *type)
1061 {
1062         NTSTATUS result;
1063
1064         *dom_name = NULL;
1065         *name = NULL;
1066
1067         /* Lookup name */
1068
1069         result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1070
1071         /* Return name and type if successful */
1072
1073         if (NT_STATUS_IS_OK(result)) {
1074                 return True;
1075         }
1076
1077         *type = SID_NAME_UNKNOWN;
1078
1079         return False;
1080 }
1081
1082 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1083
1084 void free_getent_state(struct getent_state *state)
1085 {
1086         struct getent_state *temp;
1087
1088         /* Iterate over state list */
1089
1090         temp = state;
1091
1092         while(temp != NULL) {
1093                 struct getent_state *next = temp->next;
1094
1095                 /* Free sam entries then list entry */
1096
1097                 SAFE_FREE(state->sam_entries);
1098                 DLIST_REMOVE(state, state);
1099
1100                 SAFE_FREE(temp);
1101                 temp = next;
1102         }
1103 }
1104
1105 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1106
1107 static bool assume_domain(const char *domain)
1108 {
1109         /* never assume the domain on a standalone server */
1110
1111         if ( lp_server_role() == ROLE_STANDALONE )
1112                 return False;
1113
1114         /* domain member servers may possibly assume for the domain name */
1115
1116         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1117                 if ( !strequal(lp_workgroup(), domain) )
1118                         return False;
1119
1120                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1121                         return True;
1122         }
1123
1124         /* only left with a domain controller */
1125
1126         if ( strequal(get_global_sam_name(), domain) )  {
1127                 return True;
1128         }
1129
1130         return False;
1131 }
1132
1133 /* Parse a string of the form DOMAIN\user into a domain and a user */
1134
1135 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1136 {
1137         char *p = strchr(domuser,*lp_winbind_separator());
1138
1139         if ( !p ) {
1140                 fstrcpy(user, domuser);
1141
1142                 if ( assume_domain(lp_workgroup())) {
1143                         fstrcpy(domain, lp_workgroup());
1144                 } else if ((p = strchr(domuser, '@')) != NULL) {
1145                         fstrcpy(domain, "");
1146                 } else {
1147                         return False;
1148                 }
1149         } else {
1150                 fstrcpy(user, p+1);
1151                 fstrcpy(domain, domuser);
1152                 domain[PTR_DIFF(p, domuser)] = 0;
1153         }
1154
1155         strupper_m(domain);
1156
1157         return True;
1158 }
1159
1160 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1161                               char **domain, char **user)
1162 {
1163         fstring fstr_domain, fstr_user;
1164         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1165                 return False;
1166         }
1167         *domain = talloc_strdup(mem_ctx, fstr_domain);
1168         *user = talloc_strdup(mem_ctx, fstr_user);
1169         return ((*domain != NULL) && (*user != NULL));
1170 }
1171
1172 /* add a domain user name to a buffer */
1173 void parse_add_domuser(void *buf, char *domuser, int *len)
1174 {
1175         fstring domain;
1176         char *p, *user;
1177
1178         user = domuser;
1179         p = strchr(domuser, *lp_winbind_separator());
1180
1181         if (p) {
1182
1183                 fstrcpy(domain, domuser);
1184                 domain[PTR_DIFF(p, domuser)] = 0;
1185                 p++;
1186
1187                 if (assume_domain(domain)) {
1188
1189                         user = p;
1190                         *len -= (PTR_DIFF(p, domuser));
1191                 }
1192         }
1193
1194         safe_strcpy((char *)buf, user, *len);
1195 }
1196
1197 /* Ensure an incoming username from NSS is fully qualified. Replace the
1198    incoming fstring with DOMAIN <separator> user. Returns the same
1199    values as parse_domain_user() but also replaces the incoming username.
1200    Used to ensure all names are fully qualified within winbindd.
1201    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1202    The protocol definitions of auth_crap, chng_pswd_auth_crap
1203    really should be changed to use this instead of doing things
1204    by hand. JRA. */
1205
1206 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1207 {
1208         if (!parse_domain_user(username_inout, domain, user)) {
1209                 return False;
1210         }
1211         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1212                  domain, *lp_winbind_separator(),
1213                  user);
1214         return True;
1215 }
1216
1217 /*
1218     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1219     'winbind separator' options.
1220     This means:
1221         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1222         lp_workgroup()
1223
1224     If we are a PDC or BDC, and this is for our domain, do likewise.
1225
1226     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1227     username is then unqualified in unix
1228
1229     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1230 */
1231 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1232 {
1233         fstring tmp_user;
1234
1235         fstrcpy(tmp_user, user);
1236         strlower_m(tmp_user);
1237
1238         if (can_assume && assume_domain(domain)) {
1239                 strlcpy(name, tmp_user, sizeof(fstring));
1240         } else {
1241                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1242                          domain, *lp_winbind_separator(),
1243                          tmp_user);
1244         }
1245 }
1246
1247 /**
1248  * talloc version of fill_domain_username()
1249  * return NULL on talloc failure.
1250  */
1251 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1252                                   const char *domain,
1253                                   const char *user,
1254                                   bool can_assume)
1255 {
1256         char *tmp_user, *name;
1257
1258         tmp_user = talloc_strdup(mem_ctx, user);
1259         strlower_m(tmp_user);
1260
1261         if (can_assume && assume_domain(domain)) {
1262                 name = tmp_user;
1263         } else {
1264                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1265                                        domain,
1266                                        *lp_winbind_separator(),
1267                                        tmp_user);
1268                 TALLOC_FREE(tmp_user);
1269         }
1270
1271         return name;
1272 }
1273
1274 /*
1275  * Winbindd socket accessor functions
1276  */
1277
1278 const char *get_winbind_pipe_dir(void)
1279 {
1280         return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1281 }
1282
1283 char *get_winbind_priv_pipe_dir(void)
1284 {
1285         return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1286 }
1287
1288 /* Open the winbindd socket */
1289
1290 static int _winbindd_socket = -1;
1291 static int _winbindd_priv_socket = -1;
1292
1293 int open_winbindd_socket(void)
1294 {
1295         if (_winbindd_socket == -1) {
1296                 _winbindd_socket = create_pipe_sock(
1297                         get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1298                 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1299                            _winbindd_socket));
1300         }
1301
1302         return _winbindd_socket;
1303 }
1304
1305 int open_winbindd_priv_socket(void)
1306 {
1307         if (_winbindd_priv_socket == -1) {
1308                 _winbindd_priv_socket = create_pipe_sock(
1309                         get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1310                 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1311                            _winbindd_priv_socket));
1312         }
1313
1314         return _winbindd_priv_socket;
1315 }
1316
1317 /*
1318  * Client list accessor functions
1319  */
1320
1321 static struct winbindd_cli_state *_client_list;
1322 static int _num_clients;
1323
1324 /* Return list of all connected clients */
1325
1326 struct winbindd_cli_state *winbindd_client_list(void)
1327 {
1328         return _client_list;
1329 }
1330
1331 /* Add a connection to the list */
1332
1333 void winbindd_add_client(struct winbindd_cli_state *cli)
1334 {
1335         DLIST_ADD(_client_list, cli);
1336         _num_clients++;
1337 }
1338
1339 /* Remove a client from the list */
1340
1341 void winbindd_remove_client(struct winbindd_cli_state *cli)
1342 {
1343         DLIST_REMOVE(_client_list, cli);
1344         _num_clients--;
1345 }
1346
1347 /* Close all open clients */
1348
1349 void winbindd_kill_all_clients(void)
1350 {
1351         struct winbindd_cli_state *cl = winbindd_client_list();
1352
1353         DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1354
1355         while (cl) {
1356                 struct winbindd_cli_state *next;
1357
1358                 next = cl->next;
1359                 winbindd_remove_client(cl);
1360                 cl = next;
1361         }
1362 }
1363
1364 /* Return number of open clients */
1365
1366 int winbindd_num_clients(void)
1367 {
1368         return _num_clients;
1369 }
1370
1371 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1372                                   TALLOC_CTX *mem_ctx,
1373                                   const DOM_SID *user_sid,
1374                                   uint32 *p_num_groups, DOM_SID **user_sids)
1375 {
1376         struct netr_SamInfo3 *info3 = NULL;
1377         NTSTATUS status = NT_STATUS_NO_MEMORY;
1378         size_t num_groups = 0;
1379
1380         DEBUG(3,(": lookup_usergroups_cached\n"));
1381
1382         *user_sids = NULL;
1383         *p_num_groups = 0;
1384
1385         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1386
1387         if (info3 == NULL) {
1388                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1389         }
1390
1391         if (info3->base.groups.count == 0) {
1392                 TALLOC_FREE(info3);
1393                 return NT_STATUS_UNSUCCESSFUL;
1394         }
1395
1396         /* Skip Domain local groups outside our domain.
1397            We'll get these from the getsidaliases() RPC call. */
1398         status = sid_array_from_info3(mem_ctx, info3,
1399                                       user_sids,
1400                                       &num_groups,
1401                                       false, true);
1402
1403         if (!NT_STATUS_IS_OK(status)) {
1404                 TALLOC_FREE(info3);
1405                 return status;
1406         }
1407
1408         TALLOC_FREE(info3);
1409         *p_num_groups = num_groups;
1410         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1411
1412         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1413
1414         return status;
1415 }
1416
1417 /*********************************************************************
1418  We use this to remove spaces from user and group names
1419 ********************************************************************/
1420
1421 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1422                              struct winbindd_domain *domain,
1423                              char *name,
1424                              char **normalized)
1425 {
1426         NTSTATUS nt_status;
1427
1428         if (!name || !normalized) {
1429                 return NT_STATUS_INVALID_PARAMETER;
1430         }
1431
1432         if (!lp_winbind_normalize_names()) {
1433                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1434         }
1435
1436         /* Alias support and whitespace replacement are mutually
1437            exclusive */
1438
1439         nt_status = resolve_username_to_alias(mem_ctx, domain,
1440                                               name, normalized );
1441         if (NT_STATUS_IS_OK(nt_status)) {
1442                 /* special return code to let the caller know we
1443                    mapped to an alias */
1444                 return NT_STATUS_FILE_RENAMED;
1445         }
1446
1447         /* check for an unreachable domain */
1448
1449         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1450                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1451                          domain->name));
1452                 set_domain_offline(domain);
1453                 return nt_status;
1454         }
1455
1456         /* deal with whitespace */
1457
1458         *normalized = talloc_strdup(mem_ctx, name);
1459         if (!(*normalized)) {
1460                 return NT_STATUS_NO_MEMORY;
1461         }
1462
1463         all_string_sub( *normalized, " ", "_", 0 );
1464
1465         return NT_STATUS_OK;
1466 }
1467
1468 /*********************************************************************
1469  We use this to do the inverse of normalize_name_map()
1470 ********************************************************************/
1471
1472 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1473                               char *name,
1474                               char **normalized)
1475 {
1476         NTSTATUS nt_status;
1477         struct winbindd_domain *domain = find_our_domain();
1478
1479         if (!name || !normalized) {
1480                 return NT_STATUS_INVALID_PARAMETER;
1481         }
1482
1483         if (!lp_winbind_normalize_names()) {
1484                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1485         }
1486
1487         /* Alias support and whitespace replacement are mutally
1488            exclusive */
1489
1490         /* When mapping from an alias to a username, we don't know the
1491            domain.  But we only need a domain structure to cache
1492            a successful lookup , so just our own domain structure for
1493            the seqnum. */
1494
1495         nt_status = resolve_alias_to_username(mem_ctx, domain,
1496                                               name, normalized);
1497         if (NT_STATUS_IS_OK(nt_status)) {
1498                 /* Special return code to let the caller know we mapped
1499                    from an alias */
1500                 return NT_STATUS_FILE_RENAMED;
1501         }
1502
1503         /* check for an unreachable domain */
1504
1505         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1506                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1507                          domain->name));
1508                 set_domain_offline(domain);
1509                 return nt_status;
1510         }
1511
1512         /* deal with whitespace */
1513
1514         *normalized = talloc_strdup(mem_ctx, name);
1515         if (!(*normalized)) {
1516                 return NT_STATUS_NO_MEMORY;
1517         }
1518
1519         all_string_sub(*normalized, "_", " ", 0);
1520
1521         return NT_STATUS_OK;
1522 }
1523
1524 /*********************************************************************
1525  ********************************************************************/
1526
1527 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1528 {
1529         struct winbindd_tdc_domain *tdc = NULL;
1530         TALLOC_CTX *frame = talloc_stackframe();
1531         bool ret = false;
1532
1533         /* We can contact the domain if it is our primary domain */
1534
1535         if (domain->primary) {
1536                 return true;
1537         }
1538
1539         /* Trust the TDC cache and not the winbindd_domain flags */
1540
1541         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1542                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1543                           domain->name));
1544                 return false;
1545         }
1546
1547         /* Can always contact a domain that is in out forest */
1548
1549         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1550                 ret = true;
1551                 goto done;
1552         }
1553
1554         /*
1555          * On a _member_ server, we cannot contact the domain if it
1556          * is running AD and we have no inbound trust.
1557          */
1558
1559         if (!IS_DC &&
1560              domain->active_directory &&
1561             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1562         {
1563                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1564                            "and we have no inbound trust.\n", domain->name));
1565                 goto done;
1566         }
1567
1568         /* Assume everything else is ok (probably not true but what
1569            can you do?) */
1570
1571         ret = true;
1572
1573 done:
1574         talloc_destroy(frame);
1575
1576         return ret;
1577 }
1578
1579 /*********************************************************************
1580  ********************************************************************/
1581
1582 bool winbindd_internal_child(struct winbindd_child *child)
1583 {
1584         if ((child == idmap_child()) || (child == locator_child())) {
1585                 return True;
1586         }
1587
1588         return False;
1589 }
1590
1591 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1592
1593 /*********************************************************************
1594  ********************************************************************/
1595
1596 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1597 {
1598         char *var = NULL;
1599         char addr[INET6_ADDRSTRLEN];
1600         const char *kdc = NULL;
1601         int lvl = 11;
1602
1603         if (!domain || !domain->alt_name || !*domain->alt_name) {
1604                 return;
1605         }
1606
1607         if (domain->initialized && !domain->active_directory) {
1608                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1609                         domain->alt_name));
1610                 return;
1611         }
1612
1613         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1614         kdc = addr;
1615         if (!*kdc) {
1616                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1617                         domain->alt_name));
1618                 kdc = domain->dcname;
1619         }
1620
1621         if (!kdc || !*kdc) {
1622                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1623                         domain->alt_name));
1624                 return;
1625         }
1626
1627         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1628                                 domain->alt_name) == -1) {
1629                 return;
1630         }
1631
1632         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1633                 var, kdc));
1634
1635         setenv(var, kdc, 1);
1636         free(var);
1637 }
1638
1639 /*********************************************************************
1640  ********************************************************************/
1641
1642 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1643 {
1644         struct winbindd_domain *our_dom = find_our_domain();
1645
1646         winbindd_set_locator_kdc_env(domain);
1647
1648         if (domain != our_dom) {
1649                 winbindd_set_locator_kdc_env(our_dom);
1650         }
1651 }
1652
1653 /*********************************************************************
1654  ********************************************************************/
1655
1656 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1657 {
1658         char *var = NULL;
1659
1660         if (!domain || !domain->alt_name || !*domain->alt_name) {
1661                 return;
1662         }
1663
1664         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1665                                 domain->alt_name) == -1) {
1666                 return;
1667         }
1668
1669         unsetenv(var);
1670         free(var);
1671 }
1672 #else
1673
1674 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1675 {
1676         return;
1677 }
1678
1679 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1680 {
1681         return;
1682 }
1683
1684 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1685
1686 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1687 {
1688         resp->data.auth.nt_status = NT_STATUS_V(result);
1689         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1690
1691         /* we might have given a more useful error above */
1692         if (*resp->data.auth.error_string == '\0')
1693                 fstrcpy(resp->data.auth.error_string,
1694                         get_friendly_nt_error_msg(result));
1695         resp->data.auth.pam_error = nt_status_to_pam(result);
1696 }