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