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