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