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