r23784: use the GPLv3 boilerplate as recommended by the FSF and the license text
[abartlet/samba.git/.git] / source3 / nsswitch / 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 ) {
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(_domain_list, 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                         setup_domain_child(domain, &domain->child, NULL);
327                 }
328                 p=q;
329                 if (p != NULL)
330                         p += 1;
331         }
332
333         SAFE_FREE(response->extra_data.data);
334
335         /* 
336            Cases to consider when scanning trusts:
337            (a) we are calling from a child domain (primary && !forest_root)
338            (b) we are calling from the root of the forest (primary && forest_root)
339            (c) we are calling from a trusted forest domain (!primary
340                && !forest_root)
341         */
342
343         if ( state->primary ) {
344                 /* If this is our primary domain and we are not the in the
345                    forest root, we have to scan the root trusts first */
346
347                 if ( !state->forest_root )
348                         rescan_forest_root_trusts();
349                 else
350                         rescan_forest_trusts();
351
352         } else if ( state->forest_root ) {
353                 /* Once we have done root forest trust search, we can
354                    go on to search thing trusted forests */
355
356                 rescan_forest_trusts();
357         }
358         
359         talloc_destroy(state->mem_ctx);
360         
361         return;
362 }
363
364 /********************************************************************
365  Scan the trusts of our forest root
366 ********************************************************************/
367
368 static void rescan_forest_root_trusts( void )
369 {
370         struct winbindd_tdc_domain *dom_list = NULL;
371         size_t num_trusts = 0;
372         int i;  
373
374         /* The only transitive trusts supported by Windows 2003 AD are
375            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
376            first two are handled in forest and listed by
377            DsEnumerateDomainTrusts().  Forest trusts are not so we
378            have to do that ourselves. */
379
380         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
381                 return;
382
383         for ( i=0; i<num_trusts; i++ ) {
384                 struct winbindd_domain *d = NULL;
385
386                 /* Find the forest root.  Don't necessarily trust 
387                    the domain_list() as our primary domain may not 
388                    have been initialized. */
389
390                 if ( !(dom_list[i].trust_flags & DS_DOMAIN_TREE_ROOT) ) {
391                         continue;                       
392                 }
393         
394                 /* Here's the forest root */
395
396                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
397
398                 if ( !d ) {
399                         d = add_trusted_domain( dom_list[i].domain_name,
400                                                 dom_list[i].dns_name,
401                                                 &cache_methods,
402                                                 &dom_list[i].sid );
403                 }
404
405                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
406                           "for domain tree root %s (%s)\n",
407                           d->name, d->alt_name ));
408
409                 d->domain_flags = dom_list[i].trust_flags;
410                 d->domain_type  = dom_list[i].trust_type;               
411                 d->domain_trust_attribs = dom_list[i].trust_attribs;            
412                 
413                 add_trusted_domains( d );
414
415                 break;          
416         }
417
418         TALLOC_FREE( dom_list );
419
420         return;
421 }
422
423 /********************************************************************
424  scan the transitive forest trists (not our own)
425 ********************************************************************/
426
427
428 static void rescan_forest_trusts( void )
429 {
430         struct winbindd_domain *d = NULL;
431         struct winbindd_tdc_domain *dom_list = NULL;
432         size_t num_trusts = 0;
433         int i;  
434
435         /* The only transitive trusts supported by Windows 2003 AD are
436            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
437            first two are handled in forest and listed by
438            DsEnumerateDomainTrusts().  Forest trusts are not so we
439            have to do that ourselves. */
440
441         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
442                 return;
443
444         for ( i=0; i<num_trusts; i++ ) {
445                 uint32 flags   = dom_list[i].trust_flags;
446                 uint32 type    = dom_list[i].trust_type;
447                 uint32 attribs = dom_list[i].trust_attribs;
448                 
449                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
450
451                 /* ignore our primary and internal domains */
452
453                 if ( d && (d->internal || d->primary ) )
454                         continue;               
455                 
456                 if ( (flags & DS_DOMAIN_DIRECT_INBOUND) &&
457                      (type == DS_DOMAIN_TRUST_TYPE_UPLEVEL) &&
458                      (attribs == DS_DOMAIN_TRUST_ATTRIB_FOREST_TRANSITIVE) )
459                 {
460                         /* add the trusted domain if we don't know
461                            about it */
462
463                         if ( !d ) {
464                                 d = add_trusted_domain( dom_list[i].domain_name,
465                                                         dom_list[i].dns_name,
466                                                         &cache_methods,
467                                                         &dom_list[i].sid );
468                         }
469                         
470                         DEBUG(10,("Following trust path for domain %s (%s)\n",
471                                   d->name, d->alt_name ));
472                         add_trusted_domains( d );
473                 }
474         }
475
476         TALLOC_FREE( dom_list );
477
478         return; 
479 }
480
481 /*********************************************************************
482  The process of updating the trusted domain list is a three step
483  async process:
484  (a) ask our domain
485  (b) ask the root domain in our forest
486  (c) ask the a DC in any Win2003 trusted forests
487 *********************************************************************/
488
489 void rescan_trusted_domains( void )
490 {
491         time_t now = time(NULL);
492         
493         /* see if the time has come... */
494         
495         if ((now >= last_trustdom_scan) &&
496             ((now-last_trustdom_scan) < WINBINDD_RESCAN_FREQ) )
497                 return;
498                 
499         /* clear the TRUSTDOM cache first */
500
501         wcache_tdc_clear();
502
503         /* this will only add new domains we didn't already know about
504            in the domain_list()*/
505         
506         add_trusted_domains( find_our_domain() );
507
508         last_trustdom_scan = now;
509         
510         return; 
511 }
512
513 struct init_child_state {
514         TALLOC_CTX *mem_ctx;
515         struct winbindd_domain *domain;
516         struct winbindd_request *request;
517         struct winbindd_response *response;
518         void (*continuation)(void *private_data, BOOL success);
519         void *private_data;
520 };
521
522 static void init_child_recv(void *private_data, BOOL success);
523 static void init_child_getdc_recv(void *private_data, BOOL success);
524
525 enum winbindd_result init_child_connection(struct winbindd_domain *domain,
526                                            void (*continuation)(void *private_data,
527                                                                 BOOL success),
528                                            void *private_data)
529 {
530         TALLOC_CTX *mem_ctx;
531         struct winbindd_request *request;
532         struct winbindd_response *response;
533         struct init_child_state *state;
534         struct winbindd_domain *request_domain;
535
536         mem_ctx = talloc_init("init_child_connection");
537         if (mem_ctx == NULL) {
538                 DEBUG(0, ("talloc_init failed\n"));
539                 return WINBINDD_ERROR;
540         }
541
542         request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
543         response = TALLOC_P(mem_ctx, struct winbindd_response);
544         state = TALLOC_P(mem_ctx, struct init_child_state);
545
546         if ((request == NULL) || (response == NULL) || (state == NULL)) {
547                 DEBUG(0, ("talloc failed\n"));
548                 TALLOC_FREE(mem_ctx);
549                 continuation(private_data, False);
550                 return WINBINDD_ERROR;
551         }
552
553         request->length = sizeof(*request);
554
555         state->mem_ctx = mem_ctx;
556         state->domain = domain;
557         state->request = request;
558         state->response = response;
559         state->continuation = continuation;
560         state->private_data = private_data;
561
562         if (IS_DC || domain->primary || domain->internal ) {
563                 /* The primary domain has to find the DC name itself */
564                 request->cmd = WINBINDD_INIT_CONNECTION;
565                 fstrcpy(request->domain_name, domain->name);
566                 request->data.init_conn.is_primary = domain->internal ? False : True;
567                 fstrcpy(request->data.init_conn.dcname, "");
568                 async_request(mem_ctx, &domain->child, request, response,
569                               init_child_recv, state);
570                 return WINBINDD_PENDING;
571         }
572
573         /* This is *not* the primary domain, let's ask our DC about a DC
574          * name */
575
576         request->cmd = WINBINDD_GETDCNAME;
577         fstrcpy(request->domain_name, domain->name);
578
579         request_domain = find_our_domain();
580         async_domain_request(mem_ctx, request_domain, request, response,
581                              init_child_getdc_recv, state);
582         return WINBINDD_PENDING;
583 }
584
585 static void init_child_getdc_recv(void *private_data, BOOL success)
586 {
587         struct init_child_state *state =
588                 talloc_get_type_abort(private_data, struct init_child_state);
589         const char *dcname = "";
590
591         DEBUG(10, ("Received getdcname response\n"));
592
593         if (success && (state->response->result == WINBINDD_OK)) {
594                 dcname = state->response->data.dc_name;
595         }
596
597         state->request->cmd = WINBINDD_INIT_CONNECTION;
598         fstrcpy(state->request->domain_name, state->domain->name);
599         state->request->data.init_conn.is_primary = False;
600         fstrcpy(state->request->data.init_conn.dcname, dcname);
601
602         async_request(state->mem_ctx, &state->domain->child,
603                       state->request, state->response,
604                       init_child_recv, state);
605 }
606
607 static void init_child_recv(void *private_data, BOOL success)
608 {
609         struct init_child_state *state =
610                 talloc_get_type_abort(private_data, struct init_child_state);
611
612         DEBUG(5, ("Received child initialization response for domain %s\n",
613                   state->domain->name));
614
615         if ((!success) || (state->response->result != WINBINDD_OK)) {
616                 DEBUG(3, ("Could not init child\n"));
617                 state->continuation(state->private_data, False);
618                 talloc_destroy(state->mem_ctx);
619                 return;
620         }
621
622         fstrcpy(state->domain->name,
623                 state->response->data.domain_info.name);
624         fstrcpy(state->domain->alt_name,
625                 state->response->data.domain_info.alt_name);
626         string_to_sid(&state->domain->sid,
627                       state->response->data.domain_info.sid);
628         state->domain->native_mode =
629                 state->response->data.domain_info.native_mode;
630         state->domain->active_directory =
631                 state->response->data.domain_info.active_directory;
632         state->domain->sequence_number =
633                 state->response->data.domain_info.sequence_number;
634
635         init_dc_connection(state->domain);
636
637         if (state->continuation != NULL)
638                 state->continuation(state->private_data, True);
639         talloc_destroy(state->mem_ctx);
640 }
641
642 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
643                                                    struct winbindd_cli_state *state)
644 {
645         /* Ensure null termination */
646         state->request.domain_name
647                 [sizeof(state->request.domain_name)-1]='\0';
648         state->request.data.init_conn.dcname
649                 [sizeof(state->request.data.init_conn.dcname)-1]='\0';
650
651         if (strlen(state->request.data.init_conn.dcname) > 0) {
652                 fstrcpy(domain->dcname, state->request.data.init_conn.dcname);
653         }
654
655         init_dc_connection(domain);
656
657         if (!domain->initialized) {
658                 /* If we return error here we can't do any cached authentication,
659                    but we may be in disconnected mode and can't initialize correctly.
660                    Do what the previous code did and just return without initialization,
661                    once we go online we'll re-initialize.
662                 */
663                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
664                         "online = %d\n", domain->name, (int)domain->online ));
665         }
666
667         fstrcpy(state->response.data.domain_info.name, domain->name);
668         fstrcpy(state->response.data.domain_info.alt_name, domain->alt_name);
669         fstrcpy(state->response.data.domain_info.sid,
670                 sid_string_static(&domain->sid));
671         
672         state->response.data.domain_info.native_mode
673                 = domain->native_mode;
674         state->response.data.domain_info.active_directory
675                 = domain->active_directory;
676         state->response.data.domain_info.primary
677                 = domain->primary;
678         state->response.data.domain_info.sequence_number =
679                 domain->sequence_number;
680
681         return WINBINDD_OK;
682 }
683
684 /* Look up global info for the winbind daemon */
685 BOOL init_domain_list(void)
686 {
687         struct winbindd_domain *domain;
688         int role = lp_server_role();
689
690         /* Free existing list */
691         free_domain_list();
692
693         /* Add ourselves as the first entry. */
694
695         if ( role == ROLE_DOMAIN_MEMBER ) {
696                 DOM_SID our_sid;
697
698                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
699                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
700                         return False;
701                 }
702         
703                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
704                                              &cache_methods, &our_sid);
705                 domain->primary = True;
706                 setup_domain_child(domain, &domain->child, NULL);
707                 
708                 /* Even in the parent winbindd we'll need to
709                    talk to the DC, so try and see if we can
710                    contact it. Theoretically this isn't neccessary
711                    as the init_dc_connection() in init_child_recv()
712                    will do this, but we can start detecting the DC
713                    early here. */
714                 set_domain_online_request(domain);
715         }
716
717         /* Local SAM */
718
719         domain = add_trusted_domain(get_global_sam_name(), NULL,
720                                     &passdb_methods, get_global_sam_sid());
721         if ( role != ROLE_DOMAIN_MEMBER ) {
722                 domain->primary = True;
723         }
724         setup_domain_child(domain, &domain->child, NULL);
725
726         /* BUILTIN domain */
727
728         domain = add_trusted_domain("BUILTIN", NULL, &passdb_methods,
729                                     &global_sid_Builtin);
730         setup_domain_child(domain, &domain->child, NULL);
731
732         return True;
733 }
734
735 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
736 {
737         struct winbindd_domain *domain; 
738         DOM_SID dom_sid;
739         uint32 rid;
740         
741         domain = find_domain_from_name_noinit( name );
742         if ( domain )
743                 return; 
744         
745         sid_copy( &dom_sid, user_sid );         
746         if ( !sid_split_rid( &dom_sid, &rid ) )
747                 return;
748         
749         /* add the newly discovered trusted domain */
750
751         domain = add_trusted_domain( name, NULL, &cache_methods, 
752                                      &dom_sid);
753
754         if ( !domain )
755                 return;
756
757         /* assume this is a trust from a one-way transitive 
758            forest trust */
759
760         domain->active_directory = True;
761         domain->domain_flags = DS_DOMAIN_DIRECT_OUTBOUND;
762         domain->domain_type  = DS_DOMAIN_TRUST_TYPE_UPLEVEL;
763         domain->internal = False;
764         domain->online = True;  
765
766         setup_domain_child(domain, &domain->child, NULL);
767
768         wcache_tdc_add_domain( domain );
769
770         return; 
771 }
772
773 /** 
774  * Given a domain name, return the struct winbindd domain info for it 
775  *
776  * @note Do *not* pass lp_workgroup() to this function.  domain_list
777  *       may modify it's value, and free that pointer.  Instead, our local
778  *       domain may be found by calling find_our_domain().
779  *       directly.
780  *
781  *
782  * @return The domain structure for the named domain, if it is working.
783  */
784
785 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
786 {
787         struct winbindd_domain *domain;
788
789         /* Search through list */
790
791         for (domain = domain_list(); domain != NULL; domain = domain->next) {
792                 if (strequal(domain_name, domain->name) ||
793                     (domain->alt_name[0] &&
794                      strequal(domain_name, domain->alt_name))) {
795                         return domain;
796                 }
797         }
798
799         /* Not found */
800
801         return NULL;
802 }
803
804 struct winbindd_domain *find_domain_from_name(const char *domain_name)
805 {
806         struct winbindd_domain *domain;
807
808         domain = find_domain_from_name_noinit(domain_name);
809
810         if (domain == NULL)
811                 return NULL;
812
813         if (!domain->initialized)
814                 init_dc_connection(domain);
815
816         return domain;
817 }
818
819 /* Given a domain sid, return the struct winbindd domain info for it */
820
821 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
822 {
823         struct winbindd_domain *domain;
824
825         /* Search through list */
826
827         for (domain = domain_list(); domain != NULL; domain = domain->next) {
828                 if (sid_compare_domain(sid, &domain->sid) == 0)
829                         return domain;
830         }
831
832         /* Not found */
833
834         return NULL;
835 }
836
837 /* Given a domain sid, return the struct winbindd domain info for it */
838
839 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
840 {
841         struct winbindd_domain *domain;
842
843         domain = find_domain_from_sid_noinit(sid);
844
845         if (domain == NULL)
846                 return NULL;
847
848         if (!domain->initialized)
849                 init_dc_connection(domain);
850
851         return domain;
852 }
853
854 struct winbindd_domain *find_our_domain(void)
855 {
856         struct winbindd_domain *domain;
857
858         /* Search through list */
859
860         for (domain = domain_list(); domain != NULL; domain = domain->next) {
861                 if (domain->primary)
862                         return domain;
863         }
864
865         smb_panic("Could not find our domain");
866         return NULL;
867 }
868
869 struct winbindd_domain *find_root_domain(void)
870 {
871         struct winbindd_domain *ours = find_our_domain();       
872         
873         if ( !ours )
874                 return NULL;
875         
876         if ( strlen(ours->forest_name) == 0 )
877                 return NULL;
878         
879         return find_domain_from_name( ours->forest_name );
880 }
881
882 struct winbindd_domain *find_builtin_domain(void)
883 {
884         DOM_SID sid;
885         struct winbindd_domain *domain;
886
887         string_to_sid(&sid, "S-1-5-32");
888         domain = find_domain_from_sid(&sid);
889
890         if (domain == NULL) {
891                 smb_panic("Could not find BUILTIN domain");
892         }
893
894         return domain;
895 }
896
897 /* Find the appropriate domain to lookup a name or SID */
898
899 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
900 {
901         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
902
903         if ( sid_check_is_in_unix_groups(sid) || 
904              sid_check_is_unix_groups(sid) ||
905              sid_check_is_in_unix_users(sid) ||
906              sid_check_is_unix_users(sid) )
907         {
908                 return find_domain_from_sid(get_global_sam_sid());
909         }
910
911         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
912          * one to contact the external DC's. On member servers the internal
913          * domains are different: These are part of the local SAM. */
914
915         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n",
916                    sid_string_static(sid)));
917
918         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
919                 DEBUG(10, ("calling find_domain_from_sid\n"));
920                 return find_domain_from_sid(sid);
921         }       
922
923         /* On a member server a query for SID or name can always go to our
924          * primary DC. */
925
926         DEBUG(10, ("calling find_our_domain\n"));
927         return find_our_domain();
928 }
929
930 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
931 {
932         if ( strequal(domain_name, unix_users_domain_name() ) ||
933              strequal(domain_name, unix_groups_domain_name() ) )
934         {
935                 return find_domain_from_name_noinit( get_global_sam_name() );
936         }
937
938         if (IS_DC || strequal(domain_name, "BUILTIN") ||
939             strequal(domain_name, get_global_sam_name()))
940                 return find_domain_from_name_noinit(domain_name);
941
942         /* The "Unix User" and "Unix Group" domain our handled by passdb */
943
944         return find_our_domain();
945 }
946
947 /* Lookup a sid in a domain from a name */
948
949 BOOL winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
950                                  enum winbindd_cmd orig_cmd,
951                                  struct winbindd_domain *domain, 
952                                  const char *domain_name,
953                                  const char *name, DOM_SID *sid, 
954                                  enum lsa_SidType *type)
955 {
956         NTSTATUS result;
957
958         /* Lookup name */
959         result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
960                                               domain_name, name, sid, type);
961
962         /* Return sid and type if lookup successful */
963         if (!NT_STATUS_IS_OK(result)) {
964                 *type = SID_NAME_UNKNOWN;
965         }
966
967         return NT_STATUS_IS_OK(result);
968 }
969
970 /**
971  * @brief Lookup a name in a domain from a sid.
972  *
973  * @param sid Security ID you want to look up.
974  * @param name On success, set to the name corresponding to @p sid.
975  * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
976  * @param type On success, contains the type of name: alias, group or
977  * user.
978  * @retval True if the name exists, in which case @p name and @p type
979  * are set, otherwise False.
980  **/
981 BOOL winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
982                                  struct winbindd_domain *domain,
983                                  DOM_SID *sid,
984                                  char **dom_name,
985                                  char **name,
986                                  enum lsa_SidType *type)
987 {
988         NTSTATUS result;
989
990         *dom_name = NULL;
991         *name = NULL;
992
993         /* Lookup name */
994
995         result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
996
997         /* Return name and type if successful */
998         
999         if (NT_STATUS_IS_OK(result)) {
1000                 return True;
1001         }
1002
1003         *type = SID_NAME_UNKNOWN;
1004         
1005         return False;
1006 }
1007
1008 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1009
1010 void free_getent_state(struct getent_state *state)
1011 {
1012         struct getent_state *temp;
1013
1014         /* Iterate over state list */
1015
1016         temp = state;
1017
1018         while(temp != NULL) {
1019                 struct getent_state *next;
1020
1021                 /* Free sam entries then list entry */
1022
1023                 SAFE_FREE(state->sam_entries);
1024                 DLIST_REMOVE(state, state);
1025                 next = temp->next;
1026
1027                 SAFE_FREE(temp);
1028                 temp = next;
1029         }
1030 }
1031
1032 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1033
1034 static BOOL assume_domain(const char *domain)
1035 {
1036         /* never assume the domain on a standalone server */
1037
1038         if ( lp_server_role() == ROLE_STANDALONE )
1039                 return False;
1040
1041         /* domain member servers may possibly assume for the domain name */
1042
1043         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1044                 if ( !strequal(lp_workgroup(), domain) )
1045                         return False;
1046
1047                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1048                         return True;
1049         } 
1050
1051         /* only left with a domain controller */
1052
1053         if ( strequal(get_global_sam_name(), domain) )  {
1054                 return True;
1055         }
1056         
1057         return False;
1058 }
1059
1060 /* Parse a string of the form DOMAIN\user into a domain and a user */
1061
1062 BOOL parse_domain_user(const char *domuser, fstring domain, fstring user)
1063 {
1064         char *p = strchr(domuser,*lp_winbind_separator());
1065
1066         if ( !p ) {
1067                 fstrcpy(user, domuser);
1068
1069                 if ( assume_domain(lp_workgroup())) {
1070                         fstrcpy(domain, lp_workgroup());
1071                 } else {
1072                         return False;
1073                 }
1074         } else {
1075                 fstrcpy(user, p+1);
1076                 fstrcpy(domain, domuser);
1077                 domain[PTR_DIFF(p, domuser)] = 0;
1078         }
1079         
1080         strupper_m(domain);
1081         
1082         return True;
1083 }
1084
1085 BOOL parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1086                               char **domain, char **user)
1087 {
1088         fstring fstr_domain, fstr_user;
1089         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1090                 return False;
1091         }
1092         *domain = talloc_strdup(mem_ctx, fstr_domain);
1093         *user = talloc_strdup(mem_ctx, fstr_user);
1094         return ((*domain != NULL) && (*user != NULL));
1095 }
1096
1097 /* Ensure an incoming username from NSS is fully qualified. Replace the
1098    incoming fstring with DOMAIN <separator> user. Returns the same
1099    values as parse_domain_user() but also replaces the incoming username.
1100    Used to ensure all names are fully qualified within winbindd.
1101    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1102    The protocol definitions of auth_crap, chng_pswd_auth_crap
1103    really should be changed to use this instead of doing things
1104    by hand. JRA. */
1105
1106 BOOL canonicalize_username(fstring username_inout, fstring domain, fstring user)
1107 {
1108         if (!parse_domain_user(username_inout, domain, user)) {
1109                 return False;
1110         }
1111         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1112                  domain, *lp_winbind_separator(),
1113                  user);
1114         return True;
1115 }
1116
1117 /*
1118     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1119     'winbind separator' options.
1120     This means:
1121         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1122         lp_workgroup()
1123
1124     If we are a PDC or BDC, and this is for our domain, do likewise.
1125
1126     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the 
1127     username is then unqualified in unix
1128
1129     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1130 */
1131 void fill_domain_username(fstring name, const char *domain, const char *user, BOOL can_assume)
1132 {
1133         fstring tmp_user;
1134
1135         fstrcpy(tmp_user, user);
1136         strlower_m(tmp_user);
1137
1138         if (can_assume && assume_domain(domain)) {
1139                 strlcpy(name, tmp_user, sizeof(fstring));
1140         } else {
1141                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1142                          domain, *lp_winbind_separator(),
1143                          tmp_user);
1144         }
1145 }
1146
1147 /*
1148  * Winbindd socket accessor functions
1149  */
1150
1151 char *get_winbind_priv_pipe_dir(void) 
1152 {
1153         return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1154 }
1155
1156 /*
1157  * Client list accessor functions
1158  */
1159
1160 static struct winbindd_cli_state *_client_list;
1161 static int _num_clients;
1162
1163 /* Return list of all connected clients */
1164
1165 struct winbindd_cli_state *winbindd_client_list(void)
1166 {
1167         return _client_list;
1168 }
1169
1170 /* Add a connection to the list */
1171
1172 void winbindd_add_client(struct winbindd_cli_state *cli)
1173 {
1174         DLIST_ADD(_client_list, cli);
1175         _num_clients++;
1176 }
1177
1178 /* Remove a client from the list */
1179
1180 void winbindd_remove_client(struct winbindd_cli_state *cli)
1181 {
1182         DLIST_REMOVE(_client_list, cli);
1183         _num_clients--;
1184 }
1185
1186 /* Close all open clients */
1187
1188 void winbindd_kill_all_clients(void)
1189 {
1190         struct winbindd_cli_state *cl = winbindd_client_list();
1191
1192         DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1193
1194         while (cl) {
1195                 struct winbindd_cli_state *next;
1196                 
1197                 next = cl->next;
1198                 winbindd_remove_client(cl);
1199                 cl = next;
1200         }
1201 }
1202
1203 /* Return number of open clients */
1204
1205 int winbindd_num_clients(void)
1206 {
1207         return _num_clients;
1208 }
1209
1210 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1211                                   TALLOC_CTX *mem_ctx,
1212                                   const DOM_SID *user_sid,
1213                                   uint32 *p_num_groups, DOM_SID **user_sids)
1214 {
1215         NET_USER_INFO_3 *info3 = NULL;
1216         NTSTATUS status = NT_STATUS_NO_MEMORY;
1217         int i;
1218         size_t num_groups = 0;
1219         DOM_SID group_sid, primary_group;
1220         
1221         DEBUG(3,(": lookup_usergroups_cached\n"));
1222         
1223         *user_sids = NULL;
1224         num_groups = 0;
1225         *p_num_groups = 0;
1226
1227         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1228
1229         if (info3 == NULL) {
1230                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1231         }
1232
1233         if (info3->num_groups == 0) {
1234                 TALLOC_FREE(info3);
1235                 return NT_STATUS_UNSUCCESSFUL;
1236         }
1237         
1238         /* always add the primary group to the sid array */
1239         sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1240         
1241         if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1242                 TALLOC_FREE(info3);
1243                 return NT_STATUS_NO_MEMORY;
1244         }
1245
1246         for (i=0; i<info3->num_groups; i++) {
1247                 sid_copy(&group_sid, &info3->dom_sid.sid);
1248                 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1249
1250                 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1251                                  &num_groups)) {
1252                         TALLOC_FREE(info3);
1253                         return NT_STATUS_NO_MEMORY;
1254                 }
1255         }
1256
1257         TALLOC_FREE(info3);
1258         *p_num_groups = num_groups;
1259         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1260         
1261         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1262
1263         return status;
1264 }
1265
1266 /*********************************************************************
1267  We use this to remove spaces from user and group names
1268 ********************************************************************/
1269
1270 void ws_name_replace( char *name, char replace )
1271 {
1272         char replace_char[2] = { 0x0, 0x0 };
1273     
1274         if ( !lp_winbind_normalize_names() || (replace == '\0') ) 
1275                 return;
1276
1277         replace_char[0] = replace;      
1278         all_string_sub( name, " ", replace_char, 0 );
1279
1280         return; 
1281 }
1282
1283 /*********************************************************************
1284  We use this to do the inverse of ws_name_replace()
1285 ********************************************************************/
1286
1287 void ws_name_return( char *name, char replace )
1288 {
1289         char replace_char[2] = { 0x0, 0x0 };
1290     
1291         if ( !lp_winbind_normalize_names() || (replace == '\0') ) 
1292                 return;
1293         
1294         replace_char[0] = replace;      
1295         all_string_sub( name, replace_char, " ", 0 );
1296
1297         return; 
1298 }
1299
1300 /*********************************************************************
1301  ********************************************************************/
1302
1303 BOOL winbindd_can_contact_domain( struct winbindd_domain *domain )
1304 {
1305         /* We can contact the domain if it is our primary domain */
1306
1307         if ( domain->primary )
1308                 return True;
1309
1310         /* Can always contact a domain that is in out forest */
1311
1312         if ( domain->domain_flags & DS_DOMAIN_IN_FOREST )
1313                 return True;    
1314
1315         /* We cannot contact the domain if it is running AD and
1316            we have no inbound trust */
1317
1318         if ( domain->active_directory && 
1319              ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) ) 
1320         {
1321                 return False;
1322         }
1323         
1324         /* Assume everything else is ok (probably not true but what
1325            can you do?) */
1326         
1327         return True;    
1328 }