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