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