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