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