Fix bug #5533. Winbindd fails to cope correctly with a workgroup name containing...
[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 builtin_passdb_methods;
31 extern struct winbindd_methods sam_passdb_methods;
32
33
34 /**
35  * @file winbindd_util.c
36  *
37  * Winbind daemon for NT domain authentication nss module.
38  **/
39
40
41 /* The list of trusted domains.  Note that the list can be deleted and
42    recreated using the init_domain_list() function so pointers to
43    individual winbindd_domain structures cannot be made.  Keep a copy of
44    the domain name instead. */
45
46 static struct winbindd_domain *_domain_list = NULL;
47
48 /**
49    When was the last scan of trusted domains done?
50    
51    0 == not ever
52 */
53
54 static time_t last_trustdom_scan;
55
56 struct winbindd_domain *domain_list(void)
57 {
58         /* Initialise list */
59
60         if ((!_domain_list) && (!init_domain_list())) {
61                 smb_panic("Init_domain_list failed");
62         }
63
64         return _domain_list;
65 }
66
67 /* Free all entries in the trusted domain list */
68
69 void free_domain_list(void)
70 {
71         struct winbindd_domain *domain = _domain_list;
72
73         while(domain) {
74                 struct winbindd_domain *next = domain->next;
75                 
76                 DLIST_REMOVE(_domain_list, domain);
77                 SAFE_FREE(domain);
78                 domain = next;
79         }
80 }
81
82 static bool is_internal_domain(const DOM_SID *sid)
83 {
84         if (sid == NULL)
85                 return False;
86
87         if ( IS_DC )
88                 return sid_check_is_builtin(sid);
89
90         return (sid_check_is_domain(sid) || sid_check_is_builtin(sid));
91 }
92
93 static bool is_in_internal_domain(const DOM_SID *sid)
94 {
95         if (sid == NULL)
96                 return False;
97
98         if ( IS_DC )
99                 return sid_check_is_in_builtin(sid);
100
101         return (sid_check_is_in_our_domain(sid) || sid_check_is_in_builtin(sid));
102 }
103
104
105 /* Add a trusted domain to our list of domains */
106 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
107                                                   struct winbindd_methods *methods,
108                                                   const DOM_SID *sid)
109 {
110         struct winbindd_domain *domain;
111         const char *alternative_name = NULL;
112         
113         /* ignore alt_name if we are not in an AD domain */
114         
115         if ( (lp_security() == SEC_ADS) && alt_name && *alt_name) {
116                 alternative_name = alt_name;
117         }
118         
119         /* We can't call domain_list() as this function is called from
120            init_domain_list() and we'll get stuck in a loop. */
121         for (domain = _domain_list; domain; domain = domain->next) {
122                 if (strequal(domain_name, domain->name) ||
123                     strequal(domain_name, domain->alt_name)) 
124                 {
125                         break;                  
126                 }
127
128                 if (alternative_name && *alternative_name) 
129                 {
130                         if (strequal(alternative_name, domain->name) ||
131                             strequal(alternative_name, domain->alt_name)) 
132                         {
133                                 break;                          
134                         }
135                 }
136
137                 if (sid) 
138                 {
139                         if (is_null_sid(sid)) {
140                                 continue;                               
141                         }
142                                 
143                         if (sid_equal(sid, &domain->sid)) {
144                                 break;                          
145                         }
146                 }
147         }
148         
149         /* See if we found a match.  Check if we need to update the
150            SID. */
151
152         if ( domain && sid) {
153                 if ( sid_equal( &domain->sid, &global_sid_NULL ) )
154                         sid_copy( &domain->sid, sid );
155
156                 return domain;          
157         }       
158         
159         /* Create new domain entry */
160
161         if ((domain = SMB_MALLOC_P(struct winbindd_domain)) == NULL)
162                 return NULL;
163
164         /* Fill in fields */
165         
166         ZERO_STRUCTP(domain);
167
168         fstrcpy(domain->name, domain_name);
169         if (alternative_name) {
170                 fstrcpy(domain->alt_name, alternative_name);
171         }
172
173         domain->methods = methods;
174         domain->backend = NULL;
175         domain->internal = is_internal_domain(sid);
176         domain->sequence_number = DOM_SEQUENCE_NONE;
177         domain->last_seq_check = 0;
178         domain->initialized = False;
179         domain->online = is_internal_domain(sid);
180         domain->check_online_timeout = 0;
181         if (sid) {
182                 sid_copy(&domain->sid, sid);
183         }
184         
185         /* Link to domain list */
186         DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
187         
188         wcache_tdc_add_domain( domain );
189         
190         DEBUG(2,("Added domain %s %s %s\n", 
191                  domain->name, domain->alt_name,
192                  &domain->sid?sid_string_dbg(&domain->sid):""));
193         
194         return domain;
195 }
196
197 /********************************************************************
198   rescan our domains looking for new trusted domains
199 ********************************************************************/
200
201 struct trustdom_state {
202         TALLOC_CTX *mem_ctx;
203         bool primary;   
204         bool forest_root;       
205         struct winbindd_response *response;
206 };
207
208 static void trustdom_recv(void *private_data, bool success);
209 static void rescan_forest_root_trusts( void );
210 static void rescan_forest_trusts( void );
211
212 static void add_trusted_domains( struct winbindd_domain *domain )
213 {
214         TALLOC_CTX *mem_ctx;
215         struct winbindd_request *request;
216         struct winbindd_response *response;
217         uint32 fr_flags = (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
218
219         struct trustdom_state *state;
220
221         mem_ctx = talloc_init("add_trusted_domains");
222         if (mem_ctx == NULL) {
223                 DEBUG(0, ("talloc_init failed\n"));
224                 return;
225         }
226
227         request = TALLOC_ZERO_P(mem_ctx, struct winbindd_request);
228         response = TALLOC_P(mem_ctx, struct winbindd_response);
229         state = TALLOC_P(mem_ctx, struct trustdom_state);
230
231         if ((request == NULL) || (response == NULL) || (state == NULL)) {
232                 DEBUG(0, ("talloc failed\n"));
233                 talloc_destroy(mem_ctx);
234                 return;
235         }
236
237         state->mem_ctx = mem_ctx;
238         state->response = response;
239
240         /* Flags used to know how to continue the forest trust search */
241
242         state->primary = domain->primary;
243         state->forest_root = ((domain->domain_flags & fr_flags) == fr_flags );
244
245         request->length = sizeof(*request);
246         request->cmd = WINBINDD_LIST_TRUSTDOM;
247
248         async_domain_request(mem_ctx, domain, request, response,
249                              trustdom_recv, state);
250 }
251
252 static void trustdom_recv(void *private_data, bool success)
253 {
254         struct trustdom_state *state =
255                 talloc_get_type_abort(private_data, struct trustdom_state);
256         struct winbindd_response *response = state->response;
257         char *p;
258
259         if ((!success) || (response->result != WINBINDD_OK)) {
260                 DEBUG(1, ("Could not receive trustdoms\n"));
261                 talloc_destroy(state->mem_ctx);
262                 return;
263         }
264
265         p = (char *)response->extra_data.data;
266
267         while ((p != NULL) && (*p != '\0')) {
268                 char *q, *sidstr, *alt_name;
269                 DOM_SID sid;
270                 struct winbindd_domain *domain;
271                 char *alternate_name = NULL;
272
273                 alt_name = strchr(p, '\\');
274                 if (alt_name == NULL) {
275                         DEBUG(0, ("Got invalid trustdom response\n"));
276                         break;
277                 }
278
279                 *alt_name = '\0';
280                 alt_name += 1;
281
282                 sidstr = strchr(alt_name, '\\');
283                 if (sidstr == NULL) {
284                         DEBUG(0, ("Got invalid trustdom response\n"));
285                         break;
286                 }
287
288                 *sidstr = '\0';
289                 sidstr += 1;
290
291                 q = strchr(sidstr, '\n');
292                 if (q != NULL)
293                         *q = '\0';
294
295                 if (!string_to_sid(&sid, sidstr)) {
296                         /* Allow NULL sid for sibling domains */
297                         if ( strcmp(sidstr,"S-0-0") == 0) {
298                                 sid_copy( &sid, &global_sid_NULL);                              
299                         } else {                                
300                                 DEBUG(0, ("Got invalid trustdom response\n"));
301                                 break;
302                         }                       
303                 }
304
305                 /* use the real alt_name if we have one, else pass in NULL */
306
307                 if ( !strequal( alt_name, "(null)" ) )
308                         alternate_name = alt_name;
309
310                 /* If we have an existing domain structure, calling
311                    add_trusted_domain() will update the SID if
312                    necessary.  This is important because we need the
313                    SID for sibling domains */
314
315                 if ( find_domain_from_name_noinit(p) != NULL ) {
316                         domain = add_trusted_domain(p, alternate_name,
317                                                     &cache_methods,
318                                                     &sid);
319                 } else {
320                         domain = add_trusted_domain(p, alternate_name,
321                                                     &cache_methods,
322                                                     &sid);
323                         if (domain) {
324                                 setup_domain_child(domain,
325                                                    &domain->child);
326                         }
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 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 the 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 & NETR_TRUST_FLAG_TREEROOT) ) {
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 trusts (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 & NETR_TRUST_FLAG_INBOUND) &&
457                      (type == NETR_TRUST_TYPE_UPLEVEL) &&
458                      (attribs == NETR_TRUST_ATTRIBUTE_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         /* I use to clear the cache here and start over but that
500            caused problems in child processes that needed the
501            trust dom list early on.  Removing it means we
502            could have some trusted domains listed that have been
503            removed from our primary domain's DC until a full
504            restart.  This should be ok since I think this is what
505            Windows does as well. */
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->primary ? true : false;
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         sid_to_fstring(state->response.data.domain_info.sid, &domain->sid);
672         
673         state->response.data.domain_info.native_mode
674                 = domain->native_mode;
675         state->response.data.domain_info.active_directory
676                 = domain->active_directory;
677         state->response.data.domain_info.primary
678                 = domain->primary;
679
680         return WINBINDD_OK;
681 }
682
683 /* Look up global info for the winbind daemon */
684 bool init_domain_list(void)
685 {
686         struct winbindd_domain *domain;
687         int role = lp_server_role();
688
689         /* Free existing list */
690         free_domain_list();
691
692         /* BUILTIN domain */
693
694         domain = add_trusted_domain("BUILTIN", NULL, &builtin_passdb_methods,
695                                     &global_sid_Builtin);
696         if (domain) {
697                 setup_domain_child(domain,
698                                    &domain->child);
699         }
700
701         /* Local SAM */
702
703         domain = add_trusted_domain(get_global_sam_name(), NULL,
704                                     &sam_passdb_methods, get_global_sam_sid());
705         if (domain) {
706                 if ( role != ROLE_DOMAIN_MEMBER ) {
707                         domain->primary = True;
708                 }
709                 setup_domain_child(domain,
710                                    &domain->child);
711         }
712
713         /* Add ourselves as the first entry. */
714
715         if ( role == ROLE_DOMAIN_MEMBER ) {
716                 DOM_SID our_sid;
717
718                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
719                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
720                         return False;
721                 }
722         
723                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
724                                              &cache_methods, &our_sid);
725                 if (domain) {
726                         domain->primary = True;
727                         setup_domain_child(domain,
728                                            &domain->child);
729
730                         /* Even in the parent winbindd we'll need to
731                            talk to the DC, so try and see if we can
732                            contact it. Theoretically this isn't neccessary
733                            as the init_dc_connection() in init_child_recv()
734                            will do this, but we can start detecting the DC
735                            early here. */
736                         set_domain_online_request(domain);
737                 }
738         }
739
740         return True;
741 }
742
743 void check_domain_trusted( const char *name, const DOM_SID *user_sid )
744 {
745         struct winbindd_domain *domain; 
746         DOM_SID dom_sid;
747         uint32 rid;
748         
749         domain = find_domain_from_name_noinit( name );
750         if ( domain )
751                 return; 
752         
753         sid_copy( &dom_sid, user_sid );         
754         if ( !sid_split_rid( &dom_sid, &rid ) )
755                 return;
756         
757         /* add the newly discovered trusted domain */
758
759         domain = add_trusted_domain( name, NULL, &cache_methods, 
760                                      &dom_sid);
761
762         if ( !domain )
763                 return;
764
765         /* assume this is a trust from a one-way transitive 
766            forest trust */
767
768         domain->active_directory = True;
769         domain->domain_flags = NETR_TRUST_FLAG_OUTBOUND;
770         domain->domain_type  = NETR_TRUST_TYPE_UPLEVEL;
771         domain->internal = False;
772         domain->online = True;  
773
774         setup_domain_child(domain,
775                            &domain->child);
776
777         wcache_tdc_add_domain( domain );
778
779         return; 
780 }
781
782 /** 
783  * Given a domain name, return the struct winbindd domain info for it 
784  *
785  * @note Do *not* pass lp_workgroup() to this function.  domain_list
786  *       may modify it's value, and free that pointer.  Instead, our local
787  *       domain may be found by calling find_our_domain().
788  *       directly.
789  *
790  *
791  * @return The domain structure for the named domain, if it is working.
792  */
793
794 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
795 {
796         struct winbindd_domain *domain;
797
798         /* Search through list */
799
800         for (domain = domain_list(); domain != NULL; domain = domain->next) {
801                 if (strequal(domain_name, domain->name) ||
802                     (domain->alt_name[0] &&
803                      strequal(domain_name, domain->alt_name))) {
804                         return domain;
805                 }
806         }
807
808         /* Not found */
809
810         return NULL;
811 }
812
813 struct winbindd_domain *find_domain_from_name(const char *domain_name)
814 {
815         struct winbindd_domain *domain;
816
817         domain = find_domain_from_name_noinit(domain_name);
818
819         if (domain == NULL)
820                 return NULL;
821
822         if (!domain->initialized)
823                 init_dc_connection(domain);
824
825         return domain;
826 }
827
828 /* Given a domain sid, return the struct winbindd domain info for it */
829
830 struct winbindd_domain *find_domain_from_sid_noinit(const DOM_SID *sid)
831 {
832         struct winbindd_domain *domain;
833
834         /* Search through list */
835
836         for (domain = domain_list(); domain != NULL; domain = domain->next) {
837                 if (sid_compare_domain(sid, &domain->sid) == 0)
838                         return domain;
839         }
840
841         /* Not found */
842
843         return NULL;
844 }
845
846 /* Given a domain sid, return the struct winbindd domain info for it */
847
848 struct winbindd_domain *find_domain_from_sid(const DOM_SID *sid)
849 {
850         struct winbindd_domain *domain;
851
852         domain = find_domain_from_sid_noinit(sid);
853
854         if (domain == NULL)
855                 return NULL;
856
857         if (!domain->initialized)
858                 init_dc_connection(domain);
859
860         return domain;
861 }
862
863 struct winbindd_domain *find_our_domain(void)
864 {
865         struct winbindd_domain *domain;
866
867         /* Search through list */
868
869         for (domain = domain_list(); domain != NULL; domain = domain->next) {
870                 if (domain->primary)
871                         return domain;
872         }
873
874         smb_panic("Could not find our domain");
875         return NULL;
876 }
877
878 struct winbindd_domain *find_root_domain(void)
879 {
880         struct winbindd_domain *ours = find_our_domain();       
881         
882         if ( !ours )
883                 return NULL;
884         
885         if ( strlen(ours->forest_name) == 0 )
886                 return NULL;
887         
888         return find_domain_from_name( ours->forest_name );
889 }
890
891 struct winbindd_domain *find_builtin_domain(void)
892 {
893         DOM_SID sid;
894         struct winbindd_domain *domain;
895
896         string_to_sid(&sid, "S-1-5-32");
897         domain = find_domain_from_sid(&sid);
898
899         if (domain == NULL) {
900                 smb_panic("Could not find BUILTIN domain");
901         }
902
903         return domain;
904 }
905
906 /* Find the appropriate domain to lookup a name or SID */
907
908 struct winbindd_domain *find_lookup_domain_from_sid(const DOM_SID *sid)
909 {
910         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
911
912         if ( sid_check_is_in_unix_groups(sid) || 
913              sid_check_is_unix_groups(sid) ||
914              sid_check_is_in_unix_users(sid) ||
915              sid_check_is_unix_users(sid) )
916         {
917                 return find_domain_from_sid(get_global_sam_sid());
918         }
919
920         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
921          * one to contact the external DC's. On member servers the internal
922          * domains are different: These are part of the local SAM. */
923
924         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
925
926         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
927                 DEBUG(10, ("calling find_domain_from_sid\n"));
928                 return find_domain_from_sid(sid);
929         }       
930
931         /* On a member server a query for SID or name can always go to our
932          * primary DC. */
933
934         DEBUG(10, ("calling find_our_domain\n"));
935         return find_our_domain();
936 }
937
938 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
939 {
940         if ( strequal(domain_name, unix_users_domain_name() ) ||
941              strequal(domain_name, unix_groups_domain_name() ) )
942         {
943                 return find_domain_from_name_noinit( get_global_sam_name() );
944         }
945
946         if (IS_DC || strequal(domain_name, "BUILTIN") ||
947             strequal(domain_name, get_global_sam_name()))
948                 return find_domain_from_name_noinit(domain_name);
949
950         /* The "Unix User" and "Unix Group" domain our handled by passdb */
951
952         return find_our_domain();
953 }
954
955 /* Lookup a sid in a domain from a name */
956
957 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
958                                  enum winbindd_cmd orig_cmd,
959                                  struct winbindd_domain *domain, 
960                                  const char *domain_name,
961                                  const char *name, DOM_SID *sid, 
962                                  enum lsa_SidType *type)
963 {
964         NTSTATUS result;
965
966         /* Lookup name */
967         result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
968                                               domain_name, name, sid, type);
969
970         /* Return sid and type if lookup successful */
971         if (!NT_STATUS_IS_OK(result)) {
972                 *type = SID_NAME_UNKNOWN;
973         }
974
975         return NT_STATUS_IS_OK(result);
976 }
977
978 /**
979  * @brief Lookup a name in a domain from a sid.
980  *
981  * @param sid Security ID you want to look up.
982  * @param name On success, set to the name corresponding to @p sid.
983  * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
984  * @param type On success, contains the type of name: alias, group or
985  * user.
986  * @retval True if the name exists, in which case @p name and @p type
987  * are set, otherwise False.
988  **/
989 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
990                                  struct winbindd_domain *domain,
991                                  DOM_SID *sid,
992                                  char **dom_name,
993                                  char **name,
994                                  enum lsa_SidType *type)
995 {
996         NTSTATUS result;
997
998         *dom_name = NULL;
999         *name = NULL;
1000
1001         /* Lookup name */
1002
1003         result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1004
1005         /* Return name and type if successful */
1006         
1007         if (NT_STATUS_IS_OK(result)) {
1008                 return True;
1009         }
1010
1011         *type = SID_NAME_UNKNOWN;
1012         
1013         return False;
1014 }
1015
1016 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1017
1018 void free_getent_state(struct getent_state *state)
1019 {
1020         struct getent_state *temp;
1021
1022         /* Iterate over state list */
1023
1024         temp = state;
1025
1026         while(temp != NULL) {
1027                 struct getent_state *next;
1028
1029                 /* Free sam entries then list entry */
1030
1031                 SAFE_FREE(state->sam_entries);
1032                 DLIST_REMOVE(state, state);
1033                 next = temp->next;
1034
1035                 SAFE_FREE(temp);
1036                 temp = next;
1037         }
1038 }
1039
1040 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1041
1042 static bool assume_domain(const char *domain)
1043 {
1044         /* never assume the domain on a standalone server */
1045
1046         if ( lp_server_role() == ROLE_STANDALONE )
1047                 return False;
1048
1049         /* domain member servers may possibly assume for the domain name */
1050
1051         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1052                 if ( !strequal(lp_workgroup(), domain) )
1053                         return False;
1054
1055                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1056                         return True;
1057         } 
1058
1059         /* only left with a domain controller */
1060
1061         if ( strequal(get_global_sam_name(), domain) )  {
1062                 return True;
1063         }
1064         
1065         return False;
1066 }
1067
1068 /* Parse a string of the form DOMAIN\user into a domain and a user */
1069
1070 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1071 {
1072         char *p = strchr(domuser,*lp_winbind_separator());
1073
1074         if ( !p ) {
1075                 fstrcpy(user, domuser);
1076
1077                 if ( assume_domain(lp_workgroup())) {
1078                         fstrcpy(domain, lp_workgroup());
1079                 } else if ((p = strchr(domuser, '@')) != NULL) {
1080                         fstrcpy(domain, "");                    
1081                 } else {
1082                         return False;
1083                 }
1084         } else {
1085                 fstrcpy(user, p+1);
1086                 fstrcpy(domain, domuser);
1087                 domain[PTR_DIFF(p, domuser)] = 0;
1088         }
1089         
1090         strupper_m(domain);
1091         
1092         return True;
1093 }
1094
1095 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1096                               char **domain, char **user)
1097 {
1098         fstring fstr_domain, fstr_user;
1099         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1100                 return False;
1101         }
1102         *domain = talloc_strdup(mem_ctx, fstr_domain);
1103         *user = talloc_strdup(mem_ctx, fstr_user);
1104         return ((*domain != NULL) && (*user != NULL));
1105 }
1106
1107 /* Ensure an incoming username from NSS is fully qualified. Replace the
1108    incoming fstring with DOMAIN <separator> user. Returns the same
1109    values as parse_domain_user() but also replaces the incoming username.
1110    Used to ensure all names are fully qualified within winbindd.
1111    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1112    The protocol definitions of auth_crap, chng_pswd_auth_crap
1113    really should be changed to use this instead of doing things
1114    by hand. JRA. */
1115
1116 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1117 {
1118         if (!parse_domain_user(username_inout, domain, user)) {
1119                 return False;
1120         }
1121         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1122                  domain, *lp_winbind_separator(),
1123                  user);
1124         return True;
1125 }
1126
1127 /*
1128     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1129     'winbind separator' options.
1130     This means:
1131         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1132         lp_workgroup()
1133
1134     If we are a PDC or BDC, and this is for our domain, do likewise.
1135
1136     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the 
1137     username is then unqualified in unix
1138
1139     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1140 */
1141 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1142 {
1143         fstring tmp_user;
1144
1145         fstrcpy(tmp_user, user);
1146         strlower_m(tmp_user);
1147
1148         if (can_assume && assume_domain(domain)) {
1149                 strlcpy(name, tmp_user, sizeof(fstring));
1150         } else {
1151                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1152                          domain, *lp_winbind_separator(),
1153                          tmp_user);
1154         }
1155 }
1156
1157 /*
1158  * Winbindd socket accessor functions
1159  */
1160
1161 const char *get_winbind_pipe_dir(void) 
1162 {
1163         return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1164 }
1165
1166 char *get_winbind_priv_pipe_dir(void) 
1167 {
1168         return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1169 }
1170
1171 /* Open the winbindd socket */
1172
1173 static int _winbindd_socket = -1;
1174 static int _winbindd_priv_socket = -1;
1175
1176 int open_winbindd_socket(void)
1177 {
1178         if (_winbindd_socket == -1) {
1179                 _winbindd_socket = create_pipe_sock(
1180                         get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1181                 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1182                            _winbindd_socket));
1183         }
1184
1185         return _winbindd_socket;
1186 }
1187
1188 int open_winbindd_priv_socket(void)
1189 {
1190         if (_winbindd_priv_socket == -1) {
1191                 _winbindd_priv_socket = create_pipe_sock(
1192                         get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1193                 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1194                            _winbindd_priv_socket));
1195         }
1196
1197         return _winbindd_priv_socket;
1198 }
1199
1200 /* Close the winbindd socket */
1201
1202 void close_winbindd_socket(void)
1203 {
1204         if (_winbindd_socket != -1) {
1205                 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1206                            _winbindd_socket));
1207                 close(_winbindd_socket);
1208                 _winbindd_socket = -1;
1209         }
1210         if (_winbindd_priv_socket != -1) {
1211                 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1212                            _winbindd_priv_socket));
1213                 close(_winbindd_priv_socket);
1214                 _winbindd_priv_socket = -1;
1215         }
1216 }
1217
1218 /*
1219  * Client list accessor functions
1220  */
1221
1222 static struct winbindd_cli_state *_client_list;
1223 static int _num_clients;
1224
1225 /* Return list of all connected clients */
1226
1227 struct winbindd_cli_state *winbindd_client_list(void)
1228 {
1229         return _client_list;
1230 }
1231
1232 /* Add a connection to the list */
1233
1234 void winbindd_add_client(struct winbindd_cli_state *cli)
1235 {
1236         DLIST_ADD(_client_list, cli);
1237         _num_clients++;
1238 }
1239
1240 /* Remove a client from the list */
1241
1242 void winbindd_remove_client(struct winbindd_cli_state *cli)
1243 {
1244         DLIST_REMOVE(_client_list, cli);
1245         _num_clients--;
1246 }
1247
1248 /* Close all open clients */
1249
1250 void winbindd_kill_all_clients(void)
1251 {
1252         struct winbindd_cli_state *cl = winbindd_client_list();
1253
1254         DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1255
1256         while (cl) {
1257                 struct winbindd_cli_state *next;
1258                 
1259                 next = cl->next;
1260                 winbindd_remove_client(cl);
1261                 cl = next;
1262         }
1263 }
1264
1265 /* Return number of open clients */
1266
1267 int winbindd_num_clients(void)
1268 {
1269         return _num_clients;
1270 }
1271
1272 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1273                                   TALLOC_CTX *mem_ctx,
1274                                   const DOM_SID *user_sid,
1275                                   uint32 *p_num_groups, DOM_SID **user_sids)
1276 {
1277         struct netr_SamInfo3 *info3 = NULL;
1278         NTSTATUS status = NT_STATUS_NO_MEMORY;
1279         size_t num_groups = 0;
1280
1281         DEBUG(3,(": lookup_usergroups_cached\n"));
1282
1283         *user_sids = NULL;
1284         *p_num_groups = 0;
1285
1286         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1287
1288         if (info3 == NULL) {
1289                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1290         }
1291
1292         if (info3->base.groups.count == 0) {
1293                 TALLOC_FREE(info3);
1294                 return NT_STATUS_UNSUCCESSFUL;
1295         }
1296
1297         /* Skip Domain local groups outside our domain.
1298            We'll get these from the getsidaliases() RPC call. */
1299         status = sid_array_from_info3(mem_ctx, info3,
1300                                       user_sids,
1301                                       &num_groups,
1302                                       true, true);
1303
1304         if (!NT_STATUS_IS_OK(status)) {
1305                 TALLOC_FREE(info3);
1306                 return status;
1307         }
1308
1309         TALLOC_FREE(info3);
1310         *p_num_groups = num_groups;
1311         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1312         
1313         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1314
1315         return status;
1316 }
1317
1318 /*********************************************************************
1319  We use this to remove spaces from user and group names
1320 ********************************************************************/
1321
1322 void ws_name_replace( char *name, char replace )
1323 {
1324         char replace_char[2] = { 0x0, 0x0 };
1325     
1326         if ( !lp_winbind_normalize_names() || (replace == '\0') ) 
1327                 return;
1328
1329         replace_char[0] = replace;      
1330         all_string_sub( name, " ", replace_char, 0 );
1331
1332         return; 
1333 }
1334
1335 /*********************************************************************
1336  We use this to do the inverse of ws_name_replace()
1337 ********************************************************************/
1338
1339 void ws_name_return( char *name, char replace )
1340 {
1341         char replace_char[2] = { 0x0, 0x0 };
1342     
1343         if ( !lp_winbind_normalize_names() || (replace == '\0') ) 
1344                 return;
1345         
1346         replace_char[0] = replace;      
1347         all_string_sub( name, replace_char, " ", 0 );
1348
1349         return; 
1350 }
1351
1352 /*********************************************************************
1353  ********************************************************************/
1354
1355 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1356 {
1357         struct winbindd_tdc_domain *tdc = NULL;
1358         TALLOC_CTX *frame = talloc_stackframe();
1359         bool ret = false;
1360
1361         /* We can contact the domain if it is our primary domain */
1362
1363         if (domain->primary) {
1364                 return true;
1365         }
1366
1367         /* Trust the TDC cache and not the winbindd_domain flags */
1368
1369         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1370                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1371                           domain->name));
1372                 return false;
1373         }
1374
1375         /* Can always contact a domain that is in out forest */
1376
1377         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1378                 ret = true;
1379                 goto done;
1380         }
1381         
1382         /*
1383          * On a _member_ server, we cannot contact the domain if it
1384          * is running AD and we have no inbound trust.
1385          */
1386
1387         if (!IS_DC && 
1388              domain->active_directory &&
1389             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1390         {
1391                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1392                            "and we have no inbound trust.\n", domain->name));
1393                 goto done;
1394         }
1395
1396         /* Assume everything else is ok (probably not true but what
1397            can you do?) */
1398
1399         ret = true;     
1400
1401 done:   
1402         talloc_destroy(frame);
1403         
1404         return ret;     
1405 }
1406
1407 /*********************************************************************
1408  ********************************************************************/
1409
1410 bool winbindd_internal_child(struct winbindd_child *child)
1411 {
1412         if ((child == idmap_child()) || (child == locator_child())) {
1413                 return True;
1414         }
1415
1416         return False;
1417 }
1418
1419 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1420
1421 /*********************************************************************
1422  ********************************************************************/
1423
1424 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1425 {
1426         char *var = NULL;
1427         char addr[INET6_ADDRSTRLEN];
1428         const char *kdc = NULL;
1429         int lvl = 11;
1430
1431         if (!domain || !domain->alt_name || !*domain->alt_name) {
1432                 return;
1433         }
1434
1435         if (domain->initialized && !domain->active_directory) {
1436                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1437                         domain->alt_name));
1438                 return;
1439         }
1440
1441         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1442         kdc = addr;
1443         if (!*kdc) {
1444                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1445                         domain->alt_name));
1446                 kdc = domain->dcname;
1447         }
1448
1449         if (!kdc || !*kdc) {
1450                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1451                         domain->alt_name));
1452                 return;
1453         }
1454
1455         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1456                                 domain->alt_name) == -1) {
1457                 return;
1458         }
1459
1460         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1461                 var, kdc));
1462
1463         setenv(var, kdc, 1);
1464         free(var);
1465 }
1466
1467 /*********************************************************************
1468  ********************************************************************/
1469
1470 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1471 {
1472         struct winbindd_domain *our_dom = find_our_domain();
1473
1474         winbindd_set_locator_kdc_env(domain);
1475
1476         if (domain != our_dom) {
1477                 winbindd_set_locator_kdc_env(our_dom);
1478         }
1479 }
1480
1481 /*********************************************************************
1482  ********************************************************************/
1483
1484 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1485 {
1486         char *var = NULL;
1487
1488         if (!domain || !domain->alt_name || !*domain->alt_name) {
1489                 return;
1490         }
1491
1492         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1493                                 domain->alt_name) == -1) {
1494                 return;
1495         }
1496
1497         unsetenv(var);
1498         free(var);
1499 }
1500 #else
1501
1502 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1503 {
1504         return;
1505 }
1506
1507 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1508 {
1509         return;
1510 }
1511
1512 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */