Fix some nonempty blank lines
[ira/wip.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         SAFE_FREE(response->extra_data.data);
377
378         /* 
379            Cases to consider when scanning trusts:
380            (a) we are calling from a child domain (primary && !forest_root)
381            (b) we are calling from the root of the forest (primary && forest_root)
382            (c) we are calling from a trusted forest domain (!primary
383                && !forest_root)
384         */
385
386         if ( state->primary ) {
387                 /* If this is our primary domain and we are not in the
388                    forest root, we have to scan the root trusts first */
389
390                 if ( !state->forest_root )
391                         rescan_forest_root_trusts();
392                 else
393                         rescan_forest_trusts();
394
395         } else if ( state->forest_root ) {
396                 /* Once we have done root forest trust search, we can
397                    go on to search the trusted forests */
398
399                 rescan_forest_trusts();
400         }
401
402         talloc_destroy(state->mem_ctx);
403
404         return;
405 }
406
407 /********************************************************************
408  Scan the trusts of our forest root
409 ********************************************************************/
410
411 static void rescan_forest_root_trusts( void )
412 {
413         struct winbindd_tdc_domain *dom_list = NULL;
414         size_t num_trusts = 0;
415         int i;  
416
417         /* The only transitive trusts supported by Windows 2003 AD are
418            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
419            first two are handled in forest and listed by
420            DsEnumerateDomainTrusts().  Forest trusts are not so we
421            have to do that ourselves. */
422
423         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
424                 return;
425
426         for ( i=0; i<num_trusts; i++ ) {
427                 struct winbindd_domain *d = NULL;
428
429                 /* Find the forest root.  Don't necessarily trust 
430                    the domain_list() as our primary domain may not 
431                    have been initialized. */
432
433                 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
434                         continue;
435                 }
436
437                 /* Here's the forest root */
438
439                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
440
441                 if ( !d ) {
442                         d = add_trusted_domain( dom_list[i].domain_name,
443                                                 dom_list[i].dns_name,
444                                                 &cache_methods,
445                                                 &dom_list[i].sid );
446                 }
447
448                 if (d == NULL) {
449                         continue;
450                 }
451
452                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
453                           "for domain tree root %s (%s)\n",
454                           d->name, d->alt_name ));
455
456                 d->domain_flags = dom_list[i].trust_flags;
457                 d->domain_type  = dom_list[i].trust_type;               
458                 d->domain_trust_attribs = dom_list[i].trust_attribs;            
459
460                 add_trusted_domains( d );
461
462                 break;          
463         }
464
465         TALLOC_FREE( dom_list );
466
467         return;
468 }
469
470 /********************************************************************
471  scan the transitive forest trusts (not our own)
472 ********************************************************************/
473
474
475 static void rescan_forest_trusts( void )
476 {
477         struct winbindd_domain *d = NULL;
478         struct winbindd_tdc_domain *dom_list = NULL;
479         size_t num_trusts = 0;
480         int i;  
481
482         /* The only transitive trusts supported by Windows 2003 AD are
483            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
484            first two are handled in forest and listed by
485            DsEnumerateDomainTrusts().  Forest trusts are not so we
486            have to do that ourselves. */
487
488         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
489                 return;
490
491         for ( i=0; i<num_trusts; i++ ) {
492                 uint32 flags   = dom_list[i].trust_flags;
493                 uint32 type    = dom_list[i].trust_type;
494                 uint32 attribs = dom_list[i].trust_attribs;
495
496                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
497
498                 /* ignore our primary and internal domains */
499
500                 if ( d && (d->internal || d->primary ) )
501                         continue;               
502
503                 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
504                      (type == NETR_TRUST_TYPE_UPLEVEL) &&
505                      (attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
506                 {
507                         /* add the trusted domain if we don't know
508                            about it */
509
510                         if ( !d ) {
511                                 d = add_trusted_domain( dom_list[i].domain_name,
512                                                         dom_list[i].dns_name,
513                                                         &cache_methods,
514                                                         &dom_list[i].sid );
515                         }
516
517                         if (d == NULL) {
518                                 continue;
519                         }
520
521                         DEBUG(10,("Following trust path for domain %s (%s)\n",
522                                   d->name, d->alt_name ));
523                         add_trusted_domains( d );
524                 }
525         }
526
527         TALLOC_FREE( dom_list );
528
529         return; 
530 }
531
532 /*********************************************************************
533  The process of updating the trusted domain list is a three step
534  async process:
535  (a) ask our domain
536  (b) ask the root domain in our forest
537  (c) ask the a DC in any Win2003 trusted forests
538 *********************************************************************/
539
540 void rescan_trusted_domains( void )
541 {
542         time_t now = time(NULL);
543
544         /* Check that we allow trusted domains at all */
545         if (!lp_allow_trusted_domains())
546                 return;
547
548         /* see if the time has come... */
549
550         if ((now >= last_trustdom_scan) &&
551             ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
552                 return;
553
554         /* I use to clear the cache here and start over but that
555            caused problems in child processes that needed the
556            trust dom list early on.  Removing it means we
557            could have some trusted domains listed that have been
558            removed from our primary domain's DC until a full
559            restart.  This should be ok since I think this is what
560            Windows does as well. */
561
562         /* this will only add new domains we didn't already know about
563            in the domain_list()*/
564
565         add_trusted_domains( find_our_domain() );
566
567         last_trustdom_scan = now;
568
569         return; 
570 }
571
572 struct init_child_state {
573         TALLOC_CTX *mem_ctx;
574         struct winbindd_domain *domain;
575         struct winbindd_request *request;
576         struct winbindd_response *response;
577         void (*continuation)(void *private_data, bool success);
578         void *private_data;
579 };
580
581 static void init_child_recv(void *private_data, bool success);
582 static void init_child_getdc_recv(void *private_data, bool success);
583
584 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
585                                            void (*continuation)(void *private_data,
586                                                                 bool success),
587                                            void *private_data)
588 {
589         TALLOC_CTX *mem_ctx;
590         struct winbindd_request *request;
591         struct winbindd_response *response;
592         struct init_child_state *state;
593         struct winbindd_domain *request_domain;
594
595         mem_ctx = talloc_init("init_child_connection");
596         if (mem_ctx == NULL) {
597                 DEBUG(0, ("talloc_init failed\n"));
598                 return WINBINDD_ERROR;
599         }
600
601         request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
602         response = TALLOC_P(mem_ctx, struct winbindd_response);
603         state = TALLOC_P(mem_ctx, struct init_child_state);
604
605         if ((request == NULL) || (response == NULL) || (state == NULL)) {
606                 DEBUG(0, ("talloc failed\n"));
607                 TALLOC_FREE(mem_ctx);
608                 continuation(private_data, False);
609                 return WINBINDD_ERROR;
610         }
611
612         request->length = sizeof(*request);
613
614         state->mem_ctx = mem_ctx;
615         state->domain = domain;
616         state->request = request;
617         state->response = response;
618         state->continuation = continuation;
619         state->private_data = private_data;
620
621         if (IS_DC || domain->primary || domain->internal ) {
622                 /* The primary domain has to find the DC name itself */
623                 request->cmd = WINBINDD_INIT_CONNECTION;
624                 fstrcpy(request->domain_name, domain->name);
625                 request->data.init_conn.is_primary = domain->primary ? true : false;
626                 fstrcpy(request->data.init_conn.dcname, "");
627                 async_request(mem_ctx, &domain->child, request, response,
628                               init_child_recv, state);
629                 return WINBINDD_PENDING;
630         }
631
632         /* This is *not* the primary domain, let's ask our DC about a DC
633          * name */
634
635         request->cmd = WINBINDD_GETDCNAME;
636         fstrcpy(request->domain_name, domain->name);
637
638         request_domain = find_our_domain();
639         async_domain_request(mem_ctx, request_domain, request, response,
640                              init_child_getdc_recv, state);
641         return WINBINDD_PENDING;
642 }
643
644 static void init_child_getdc_recv(void *private_data, bool success)
645 {
646         struct init_child_state *state =
647                 talloc_get_type_abort(private_data, struct init_child_state);
648         const char *dcname = "";
649
650         DEBUG(10, ("Received getdcname response\n"));
651
652         if (success && (state->response->result == WINBINDD_OK)) {
653                 dcname = state->response->data.dc_name;
654         }
655
656         state->request->cmd = WINBINDD_INIT_CONNECTION;
657         fstrcpy(state->request->domain_name, state->domain->name);
658         state->request->data.init_conn.is_primary = False;
659         fstrcpy(state->request->data.init_conn.dcname, dcname);
660
661         async_request(state->mem_ctx, &state->domain->child,
662                       state->request, state->response,
663                       init_child_recv, state);
664 }
665
666 static void init_child_recv(void *private_data, bool success)
667 {
668         struct init_child_state *state =
669                 talloc_get_type_abort(private_data, struct init_child_state);
670
671         DEBUG(5, ("Received child initialization response for domain %s\n",
672                   state->domain->name));
673
674         if ((!success) || (state->response->result != WINBINDD_OK)) {
675                 DEBUG(3, ("Could not init child\n"));
676                 state->continuation(state->private_data, False);
677                 talloc_destroy(state->mem_ctx);
678                 return;
679         }
680
681         fstrcpy(state->domain->name,
682                 state->response->data.domain_info.name);
683         fstrcpy(state->domain->alt_name,
684                 state->response->data.domain_info.alt_name);
685         if (!string_to_sid(&state->domain->sid,
686                       state->response->data.domain_info.sid)) {
687                 DEBUG(1,("init_child_recv: Could not convert sid %s "
688                         "from string\n",
689                         state->response->data.domain_info.sid));
690                 state->continuation(state->private_data, False);
691                 talloc_destroy(state->mem_ctx);
692                 return;
693         }
694
695         state->domain->native_mode =
696                 state->response->data.domain_info.native_mode;
697         state->domain->active_directory =
698                 state->response->data.domain_info.active_directory;
699
700         init_dc_connection(state->domain);
701
702         if (state->continuation != NULL)
703                 state->continuation(state->private_data, True);
704         talloc_destroy(state->mem_ctx);
705 }
706
707 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
708                                                    struct winbindd_cli_state *state)
709 {
710         /* Ensure null termination */
711         state->request.domain_name
712                 [sizeof(state->request.domain_name)-1]='\0';
713         state->request.data.init_conn.dcname
714                 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
715
716         if (strlen(state->request.data.init_conn.dcname) > 0) {
717                 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
718         }
719
720         init_dc_connection(domain);
721
722         if (!domain->initialized) {
723                 /* If we return error here we can't do any cached authentication,
724                    but we may be in disconnected mode and can't initialize correctly.
725                    Do what the previous code did and just return without initialization,
726                    once we go online we'll re-initialize.
727                 */
728                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
729                         "online = %d\n", domain->name, (int)domain->online ));
730         }
731
732         fstrcpy(state->response.data.domain_info.name, domain->name);
733         fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
734         sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
735
736         state->response.data.domain_info.native_mode
737                 = domain->native_mode;
738         state->response.data.domain_info.active_directory
739                 = domain->active_directory;
740         state->response.data.domain_info.primary
741                 = domain->primary;
742
743         return WINBINDD_OK;
744 }
745
746 /* Look up global info for the winbind daemon */
747 bool init_domain_list(void)
748 {
749         struct winbindd_domain *domain;
750         int role = lp_server_role();
751
752         /* Free existing list */
753         free_domain_list();
754
755         /* BUILTIN domain */
756
757         domain = add_trusted_domain("BUILTIN", NULL, &builtin_passdb_methods,
758                                     &global_sid_Builtin);
759         if (domain) {
760                 setup_domain_child(domain,
761                                    &domain->child);
762         }
763
764         /* Local SAM */
765
766         domain = add_trusted_domain(get_global_sam_name(), NULL,
767                                     &sam_passdb_methods, get_global_sam_sid());
768         if (domain) {
769                 if ( role != ROLE_DOMAIN_MEMBER ) {
770                         domain->primary = True;
771                 }
772                 setup_domain_child(domain,
773                                    &domain->child);
774         }
775
776         /* Add ourselves as the first entry. */
777
778         if ( role == ROLE_DOMAIN_MEMBER ) {
779                 DOM_SID our_sid;
780
781                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
782                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
783                         return False;
784                 }
785
786                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
787                                              &cache_methods, &our_sid);
788                 if (domain) {
789                         domain->primary = True;
790                         setup_domain_child(domain,
791                                            &domain->child);
792
793                         /* Even in the parent winbindd we'll need to
794                            talk to the DC, so try and see if we can
795                            contact it. Theoretically this isn't neccessary
796                            as the init_dc_connection() in init_child_recv()
797                            will do this, but we can start detecting the DC
798                            early here. */
799                         set_domain_online_request(domain);
800                 }
801         }
802
803         return True;
804 }
805
806 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
807 {
808         struct winbindd_domain *domain; 
809         DOM_SID dom_sid;
810         uint32 rid;
811
812         /* Check if we even care */
813
814         if (!lp_allow_trusted_domains())
815                 return;
816
817         domain = find_domain_from_name_noinit( name );
818         if ( domain )
819                 return; 
820
821         sid_copy( &dom_sid, user_sid );         
822         if ( !sid_split_rid( &dom_sid, &rid ) )
823                 return;
824
825         /* add the newly discovered trusted domain */
826
827         domain = add_trusted_domain( name, NULL, &cache_methods, 
828                                      &dom_sid);
829
830         if ( !domain )
831                 return;
832
833         /* assume this is a trust from a one-way transitive 
834            forest trust */
835
836         domain->active_directory = True;
837         domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
838         domain->domain_type  = NETR_TRUST_TYPE_UPLEVEL;
839         domain->internal = False;
840         domain->online = True;  
841
842         setup_domain_child(domain,
843                            &domain->child);
844
845         wcache_tdc_add_domain( domain );
846
847         return; 
848 }
849
850 /** 
851  * Given a domain name, return the struct winbindd domain info for it 
852  *
853  * @note Do *not* pass lp_workgroup() to this function.  domain_list
854  *       may modify it's value, and free that pointer.  Instead, our local
855  *       domain may be found by calling find_our_domain().
856  *       directly.
857  *
858  *
859  * @return The domain structure for the named domain, if it is working.
860  */
861
862 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
863 {
864         struct winbindd_domain *domain;
865
866         /* Search through list */
867
868         for (domain = domain_list(); domain != NULL; domain = domain->next) {
869                 if (strequal(domain_name, domain->name) ||
870                     (domain->alt_name[0] &&
871                      strequal(domain_name, domain->alt_name))) {
872                         return domain;
873                 }
874         }
875
876         /* Not found */
877
878         return NULL;
879 }
880
881 struct winbindd_domain *find_domain_from_name(const char *domain_name)
882 {
883         struct winbindd_domain *domain;
884
885         domain = find_domain_from_name_noinit(domain_name);
886
887         if (domain == NULL)
888                 return NULL;
889
890         if (!domain->initialized)
891                 init_dc_connection(domain);
892
893         return domain;
894 }
895
896 /* Given a domain sid, return the struct winbindd domain info for it */
897
898 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
899 {
900         struct winbindd_domain *domain;
901
902         /* Search through list */
903
904         for (domain = domain_list(); domain != NULL; domain = domain->next) {
905                 if (sid_compare_domain(sid, &domain->sid) == 0)
906                         return domain;
907         }
908
909         /* Not found */
910
911         return NULL;
912 }
913
914 /* Given a domain sid, return the struct winbindd domain info for it */
915
916 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
917 {
918         struct winbindd_domain *domain;
919
920         domain = find_domain_from_sid_noinit(sid);
921
922         if (domain == NULL)
923                 return NULL;
924
925         if (!domain->initialized)
926                 init_dc_connection(domain);
927
928         return domain;
929 }
930
931 struct winbindd_domain *find_our_domain(void)
932 {
933         struct winbindd_domain *domain;
934
935         /* Search through list */
936
937         for (domain = domain_list(); domain != NULL; domain = domain->next) {
938                 if (domain->primary)
939                         return domain;
940         }
941
942         smb_panic("Could not find our domain");
943         return NULL;
944 }
945
946 struct winbindd_domain *find_root_domain(void)
947 {
948         struct winbindd_domain *ours = find_our_domain();       
949
950         if ( !ours )
951                 return NULL;
952
953         if ( strlen(ours->forest_name) == 0 )
954                 return NULL;
955
956         return find_domain_from_name( ours->forest_name );
957 }
958
959 struct winbindd_domain *find_builtin_domain(void)
960 {
961         DOM_SID sid;
962         struct winbindd_domain *domain;
963
964         string_to_sid(&sid, "S-1-5-32");
965         domain = find_domain_from_sid(&sid);
966
967         if (domain == NULL) {
968                 smb_panic("Could not find BUILTIN domain");
969         }
970
971         return domain;
972 }
973
974 /* Find the appropriate domain to lookup a name or SID */
975
976 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
977 {
978         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
979
980         if ( sid_check_is_in_unix_groups(sid) || 
981              sid_check_is_unix_groups(sid) ||
982              sid_check_is_in_unix_users(sid) ||
983              sid_check_is_unix_users(sid) )
984         {
985                 return find_domain_from_sid(get_global_sam_sid());
986         }
987
988         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
989          * one to contact the external DC's. On member servers the internal
990          * domains are different: These are part of the local SAM. */
991
992         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
993
994         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
995                 DEBUG(10, ("calling find_domain_from_sid\n"));
996                 return find_domain_from_sid(sid);
997         }       
998
999         /* On a member server a query for SID or name can always go to our
1000          * primary DC. */
1001
1002         DEBUG(10, ("calling find_our_domain\n"));
1003         return find_our_domain();
1004 }
1005
1006 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1007 {
1008         if ( strequal(domain_name, unix_users_domain_name() ) ||
1009              strequal(domain_name, unix_groups_domain_name() ) )
1010         {
1011                 return find_domain_from_name_noinit( get_global_sam_name() );
1012         }
1013
1014         if (IS_DC || strequal(domain_name, "BUILTIN") ||
1015             strequal(domain_name, get_global_sam_name()))
1016                 return find_domain_from_name_noinit(domain_name);
1017
1018         /* The "Unix User" and "Unix Group" domain our handled by passdb */
1019
1020         return find_our_domain();
1021 }
1022
1023 /* Lookup a sid in a domain from a name */
1024
1025 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
1026                                  enum winbindd_cmd orig_cmd,
1027                                  struct winbindd_domain *domain, 
1028                                  const char *domain_name,
1029                                  const char *name, DOM_SID *sid, 
1030                                  enum lsa_SidType *type)
1031 {
1032         NTSTATUS result;
1033
1034         /* Lookup name */
1035         result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
1036                                               domain_name, name, sid, type);
1037
1038         /* Return sid and type if lookup successful */
1039         if (!NT_STATUS_IS_OK(result)) {
1040                 *type = SID_NAME_UNKNOWN;
1041         }
1042
1043         return NT_STATUS_IS_OK(result);
1044 }
1045
1046 /**
1047  * @brief Lookup a name in a domain from a sid.
1048  *
1049  * @param sid Security ID you want to look up.
1050  * @param name On success, set to the name corresponding to @p sid.
1051  * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
1052  * @param type On success, contains the type of name: alias, group or
1053  * user.
1054  * @retval True if the name exists, in which case @p name and @p type
1055  * are set, otherwise False.
1056  **/
1057 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
1058                                  struct winbindd_domain *domain,
1059                                  DOM_SID *sid,
1060                                  char **dom_name,
1061                                  char **name,
1062                                  enum lsa_SidType *type)
1063 {
1064         NTSTATUS result;
1065
1066         *dom_name = NULL;
1067         *name = NULL;
1068
1069         /* Lookup name */
1070
1071         result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1072
1073         /* Return name and type if successful */
1074
1075         if (NT_STATUS_IS_OK(result)) {
1076                 return True;
1077         }
1078
1079         *type = SID_NAME_UNKNOWN;
1080
1081         return False;
1082 }
1083
1084 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1085
1086 void free_getent_state(struct getent_state *state)
1087 {
1088         struct getent_state *temp;
1089
1090         /* Iterate over state list */
1091
1092         temp = state;
1093
1094         while(temp != NULL) {
1095                 struct getent_state *next = temp->next;
1096
1097                 /* Free sam entries then list entry */
1098
1099                 SAFE_FREE(state->sam_entries);
1100                 DLIST_REMOVE(state, state);
1101
1102                 SAFE_FREE(temp);
1103                 temp = next;
1104         }
1105 }
1106
1107 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1108
1109 static bool assume_domain(const char *domain)
1110 {
1111         /* never assume the domain on a standalone server */
1112
1113         if ( lp_server_role() == ROLE_STANDALONE )
1114                 return False;
1115
1116         /* domain member servers may possibly assume for the domain name */
1117
1118         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1119                 if ( !strequal(lp_workgroup(), domain) )
1120                         return False;
1121
1122                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1123                         return True;
1124         } 
1125
1126         /* only left with a domain controller */
1127
1128         if ( strequal(get_global_sam_name(), domain) )  {
1129                 return True;
1130         }
1131
1132         return False;
1133 }
1134
1135 /* Parse a string of the form DOMAIN\user into a domain and a user */
1136
1137 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1138 {
1139         char *p = strchr(domuser,*lp_winbind_separator());
1140
1141         if ( !p ) {
1142                 fstrcpy(user, domuser);
1143
1144                 if ( assume_domain(lp_workgroup())) {
1145                         fstrcpy(domain, lp_workgroup());
1146                 } else if ((p = strchr(domuser, '@')) != NULL) {
1147                         fstrcpy(domain, "");                    
1148                 } else {
1149                         return False;
1150                 }
1151         } else {
1152                 fstrcpy(user, p+1);
1153                 fstrcpy(domain, domuser);
1154                 domain[PTR_DIFF(p, domuser)] = 0;
1155         }
1156
1157         strupper_m(domain);
1158
1159         return True;
1160 }
1161
1162 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1163                               char **domain, char **user)
1164 {
1165         fstring fstr_domain, fstr_user;
1166         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1167                 return False;
1168         }
1169         *domain = talloc_strdup(mem_ctx, fstr_domain);
1170         *user = talloc_strdup(mem_ctx, fstr_user);
1171         return ((*domain != NULL) && (*user != NULL));
1172 }
1173
1174 /* add a domain user name to a buffer */
1175 void parse_add_domuser(void *buf, char *domuser, int *len)
1176 {
1177         fstring domain;
1178         char *p, *user;
1179
1180         user = domuser;
1181         p = strchr(domuser, *lp_winbind_separator());
1182
1183         if (p) {
1184
1185                 fstrcpy(domain, domuser);
1186                 domain[PTR_DIFF(p, domuser)] = 0;
1187                 p++;
1188
1189                 if (assume_domain(domain)) {
1190
1191                         user = p;
1192                         *len -= (PTR_DIFF(p, domuser));
1193                 }
1194         }
1195
1196         safe_strcpy((char *)buf, user, *len);
1197 }
1198
1199 /* Ensure an incoming username from NSS is fully qualified. Replace the
1200    incoming fstring with DOMAIN <separator> user. Returns the same
1201    values as parse_domain_user() but also replaces the incoming username.
1202    Used to ensure all names are fully qualified within winbindd.
1203    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1204    The protocol definitions of auth_crap, chng_pswd_auth_crap
1205    really should be changed to use this instead of doing things
1206    by hand. JRA. */
1207
1208 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1209 {
1210         if (!parse_domain_user(username_inout, domain, user)) {
1211                 return False;
1212         }
1213         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1214                  domain, *lp_winbind_separator(),
1215                  user);
1216         return True;
1217 }
1218
1219 /*
1220     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1221     'winbind separator' options.
1222     This means:
1223         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1224         lp_workgroup()
1225
1226     If we are a PDC or BDC, and this is for our domain, do likewise.
1227
1228     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the 
1229     username is then unqualified in unix
1230
1231     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1232 */
1233 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1234 {
1235         fstring tmp_user;
1236
1237         fstrcpy(tmp_user, user);
1238         strlower_m(tmp_user);
1239
1240         if (can_assume && assume_domain(domain)) {
1241                 strlcpy(name, tmp_user, sizeof(fstring));
1242         } else {
1243                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1244                          domain, *lp_winbind_separator(),
1245                          tmp_user);
1246         }
1247 }
1248
1249 /**
1250  * talloc version of fill_domain_username()
1251  * return NULL on talloc failure.
1252  */
1253 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1254                                   const char *domain,
1255                                   const char *user,
1256                                   bool can_assume)
1257 {
1258         char *tmp_user, *name;
1259
1260         tmp_user = talloc_strdup(mem_ctx, user);
1261         strlower_m(tmp_user);
1262
1263         if (can_assume && assume_domain(domain)) {
1264                 name = tmp_user;
1265         } else {
1266                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1267                                        domain,
1268                                        *lp_winbind_separator(),
1269                                        tmp_user);
1270                 TALLOC_FREE(tmp_user);
1271         }
1272
1273         return name;
1274 }
1275
1276 /*
1277  * Winbindd socket accessor functions
1278  */
1279
1280 const char *get_winbind_pipe_dir(void) 
1281 {
1282         return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1283 }
1284
1285 char *get_winbind_priv_pipe_dir(void) 
1286 {
1287         return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1288 }
1289
1290 /* Open the winbindd socket */
1291
1292 static int _winbindd_socket = -1;
1293 static int _winbindd_priv_socket = -1;
1294
1295 int open_winbindd_socket(void)
1296 {
1297         if (_winbindd_socket == -1) {
1298                 _winbindd_socket = create_pipe_sock(
1299                         get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1300                 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1301                            _winbindd_socket));
1302         }
1303
1304         return _winbindd_socket;
1305 }
1306
1307 int open_winbindd_priv_socket(void)
1308 {
1309         if (_winbindd_priv_socket == -1) {
1310                 _winbindd_priv_socket = create_pipe_sock(
1311                         get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1312                 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1313                            _winbindd_priv_socket));
1314         }
1315
1316         return _winbindd_priv_socket;
1317 }
1318
1319 /*
1320  * Client list accessor functions
1321  */
1322
1323 static struct winbindd_cli_state *_client_list;
1324 static int _num_clients;
1325
1326 /* Return list of all connected clients */
1327
1328 struct winbindd_cli_state *winbindd_client_list(void)
1329 {
1330         return _client_list;
1331 }
1332
1333 /* Add a connection to the list */
1334
1335 void winbindd_add_client(struct winbindd_cli_state *cli)
1336 {
1337         DLIST_ADD(_client_list, cli);
1338         _num_clients++;
1339 }
1340
1341 /* Remove a client from the list */
1342
1343 void winbindd_remove_client(struct winbindd_cli_state *cli)
1344 {
1345         DLIST_REMOVE(_client_list, cli);
1346         _num_clients--;
1347 }
1348
1349 /* Close all open clients */
1350
1351 void winbindd_kill_all_clients(void)
1352 {
1353         struct winbindd_cli_state *cl = winbindd_client_list();
1354
1355         DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1356
1357         while (cl) {
1358                 struct winbindd_cli_state *next;
1359
1360                 next = cl->next;
1361                 winbindd_remove_client(cl);
1362                 cl = next;
1363         }
1364 }
1365
1366 /* Return number of open clients */
1367
1368 int winbindd_num_clients(void)
1369 {
1370         return _num_clients;
1371 }
1372
1373 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1374                                   TALLOC_CTX *mem_ctx,
1375                                   const DOM_SID *user_sid,
1376                                   uint32 *p_num_groups, DOM_SID **user_sids)
1377 {
1378         struct netr_SamInfo3 *info3 = NULL;
1379         NTSTATUS status = NT_STATUS_NO_MEMORY;
1380         size_t num_groups = 0;
1381
1382         DEBUG(3,(": lookup_usergroups_cached\n"));
1383
1384         *user_sids = NULL;
1385         *p_num_groups = 0;
1386
1387         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1388
1389         if (info3 == NULL) {
1390                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1391         }
1392
1393         if (info3->base.groups.count == 0) {
1394                 TALLOC_FREE(info3);
1395                 return NT_STATUS_UNSUCCESSFUL;
1396         }
1397
1398         /* Skip Domain local groups outside our domain.
1399            We'll get these from the getsidaliases() RPC call. */
1400         status = sid_array_from_info3(mem_ctx, info3,
1401                                       user_sids,
1402                                       &num_groups,
1403                                       false, true);
1404
1405         if (!NT_STATUS_IS_OK(status)) {
1406                 TALLOC_FREE(info3);
1407                 return status;
1408         }
1409
1410         TALLOC_FREE(info3);
1411         *p_num_groups = num_groups;
1412         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1413
1414         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1415
1416         return status;
1417 }
1418
1419 /*********************************************************************
1420  We use this to remove spaces from user and group names
1421 ********************************************************************/
1422
1423 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1424                              struct winbindd_domain *domain,
1425                              char *name,
1426                              char **normalized)
1427 {
1428         NTSTATUS nt_status;
1429
1430         if (!name || !normalized) {
1431                 return NT_STATUS_INVALID_PARAMETER;
1432         }
1433
1434         if (!lp_winbind_normalize_names()) {
1435                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1436         }
1437
1438         /* Alias support and whitespace replacement are mutually
1439            exclusive */
1440
1441         nt_status = resolve_username_to_alias(mem_ctx, domain,
1442                                               name, normalized );
1443         if (NT_STATUS_IS_OK(nt_status)) {
1444                 /* special return code to let the caller know we
1445                    mapped to an alias */
1446                 return NT_STATUS_FILE_RENAMED;
1447         }
1448
1449         /* check for an unreachable domain */
1450
1451         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1452                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1453                          domain->name));
1454                 set_domain_offline(domain);
1455                 return nt_status;
1456         }
1457
1458         /* deal with whitespace */
1459
1460         *normalized = talloc_strdup(mem_ctx, name);
1461         if (!(*normalized)) {
1462                 return NT_STATUS_NO_MEMORY;
1463         }
1464
1465         all_string_sub( *normalized, " ", "_", 0 );
1466
1467         return NT_STATUS_OK;
1468 }
1469
1470 /*********************************************************************
1471  We use this to do the inverse of normalize_name_map()
1472 ********************************************************************/
1473
1474 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1475                               char *name,
1476                               char **normalized)
1477 {
1478         NTSTATUS nt_status;
1479         struct winbindd_domain *domain = find_our_domain();
1480
1481         if (!name || !normalized) {
1482                 return NT_STATUS_INVALID_PARAMETER;
1483         }
1484
1485         if (!lp_winbind_normalize_names()) {
1486                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1487         }
1488
1489         /* Alias support and whitespace replacement are mutally
1490            exclusive */
1491
1492         /* When mapping from an alias to a username, we don't know the
1493            domain.  But we only need a domain structure to cache
1494            a successful lookup , so just our own domain structure for
1495            the seqnum. */
1496
1497         nt_status = resolve_alias_to_username(mem_ctx, domain,
1498                                               name, normalized);
1499         if (NT_STATUS_IS_OK(nt_status)) {
1500                 /* Special return code to let the caller know we mapped
1501                    from an alias */
1502                 return NT_STATUS_FILE_RENAMED;
1503         }
1504
1505         /* check for an unreachable domain */
1506
1507         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1508                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1509                          domain->name));
1510                 set_domain_offline(domain);
1511                 return nt_status;
1512         }
1513
1514         /* deal with whitespace */
1515
1516         *normalized = talloc_strdup(mem_ctx, name);
1517         if (!(*normalized)) {
1518                 return NT_STATUS_NO_MEMORY;
1519         }
1520
1521         all_string_sub(*normalized, "_", " ", 0);
1522
1523         return NT_STATUS_OK;
1524 }
1525
1526 /*********************************************************************
1527  ********************************************************************/
1528
1529 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1530 {
1531         struct winbindd_tdc_domain *tdc = NULL;
1532         TALLOC_CTX *frame = talloc_stackframe();
1533         bool ret = false;
1534
1535         /* We can contact the domain if it is our primary domain */
1536
1537         if (domain->primary) {
1538                 return true;
1539         }
1540
1541         /* Trust the TDC cache and not the winbindd_domain flags */
1542
1543         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1544                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1545                           domain->name));
1546                 return false;
1547         }
1548
1549         /* Can always contact a domain that is in out forest */
1550
1551         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1552                 ret = true;
1553                 goto done;
1554         }
1555
1556         /*
1557          * On a _member_ server, we cannot contact the domain if it
1558          * is running AD and we have no inbound trust.
1559          */
1560
1561         if (!IS_DC && 
1562              domain->active_directory &&
1563             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1564         {
1565                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1566                            "and we have no inbound trust.\n", domain->name));
1567                 goto done;
1568         }
1569
1570         /* Assume everything else is ok (probably not true but what
1571            can you do?) */
1572
1573         ret = true;     
1574
1575 done:   
1576         talloc_destroy(frame);
1577
1578         return ret;     
1579 }
1580
1581 /*********************************************************************
1582  ********************************************************************/
1583
1584 bool winbindd_internal_child(struct winbindd_child *child)
1585 {
1586         if ((child == idmap_child()) || (child == locator_child())) {
1587                 return True;
1588         }
1589
1590         return False;
1591 }
1592
1593 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1594
1595 /*********************************************************************
1596  ********************************************************************/
1597
1598 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1599 {
1600         char *var = NULL;
1601         char addr[INET6_ADDRSTRLEN];
1602         const char *kdc = NULL;
1603         int lvl = 11;
1604
1605         if (!domain || !domain->alt_name || !*domain->alt_name) {
1606                 return;
1607         }
1608
1609         if (domain->initialized && !domain->active_directory) {
1610                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1611                         domain->alt_name));
1612                 return;
1613         }
1614
1615         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1616         kdc = addr;
1617         if (!*kdc) {
1618                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1619                         domain->alt_name));
1620                 kdc = domain->dcname;
1621         }
1622
1623         if (!kdc || !*kdc) {
1624                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1625                         domain->alt_name));
1626                 return;
1627         }
1628
1629         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1630                                 domain->alt_name) == -1) {
1631                 return;
1632         }
1633
1634         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1635                 var, kdc));
1636
1637         setenv(var, kdc, 1);
1638         free(var);
1639 }
1640
1641 /*********************************************************************
1642  ********************************************************************/
1643
1644 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1645 {
1646         struct winbindd_domain *our_dom = find_our_domain();
1647
1648         winbindd_set_locator_kdc_env(domain);
1649
1650         if (domain != our_dom) {
1651                 winbindd_set_locator_kdc_env(our_dom);
1652         }
1653 }
1654
1655 /*********************************************************************
1656  ********************************************************************/
1657
1658 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1659 {
1660         char *var = NULL;
1661
1662         if (!domain || !domain->alt_name || !*domain->alt_name) {
1663                 return;
1664         }
1665
1666         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1667                                 domain->alt_name) == -1) {
1668                 return;
1669         }
1670
1671         unsetenv(var);
1672         free(var);
1673 }
1674 #else
1675
1676 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1677 {
1678         return;
1679 }
1680
1681 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1682 {
1683         return;
1684 }
1685
1686 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1687
1688 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1689 {
1690         resp->data.auth.nt_status = NT_STATUS_V(result);
1691         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1692
1693         /* we might have given a more useful error above */
1694         if (*resp->data.auth.error_string == '\0')
1695                 fstrcpy(resp->data.auth.error_string,
1696                         get_friendly_nt_error_msg(result));
1697         resp->data.auth.pam_error = nt_status_to_pam(result);
1698 }