Replace sid_string_static by sid_string_dbg in DEBUGs
[nivanova/samba-autobuild/.git] / source3 / winbindd / winbindd_util.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon for ntdom nss module
5
6    Copyright (C) Tim Potter 2000-2001
7    Copyright (C) 2001 by Martin Pool <mbp@samba.org>
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
28
29 extern struct winbindd_methods cache_methods;
30 extern struct winbindd_methods passdb_methods;
31
32 /**
33  * @file winbindd_util.c
34  *
35  * Winbind daemon for NT domain authentication nss module.
36  **/
37
38
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_dbg(&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", sid_string_dbg(sid)));
926
927         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
928                 DEBUG(10, ("calling find_domain_from_sid\n"));
929                 return find_domain_from_sid(sid);
930         }       
931
932         /* On a member server a query for SID or name can always go to our
933          * primary DC. */
934
935         DEBUG(10, ("calling find_our_domain\n"));
936         return find_our_domain();
937 }
938
939 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
940 {
941         if ( strequal(domain_name, unix_users_domain_name() ) ||
942              strequal(domain_name, unix_groups_domain_name() ) )
943         {
944                 return find_domain_from_name_noinit( get_global_sam_name() );
945         }
946
947         if (IS_DC || strequal(domain_name, "BUILTIN") ||
948             strequal(domain_name, get_global_sam_name()))
949                 return find_domain_from_name_noinit(domain_name);
950
951         /* The "Unix User" and "Unix Group" domain our handled by passdb */
952
953         return find_our_domain();
954 }
955
956 /* Lookup a sid in a domain from a name */
957
958 bool winbindd_lookup_sid_by_name(TALLOC_CTX *mem_ctx,
959                                  enum winbindd_cmd orig_cmd,
960                                  struct winbindd_domain *domain, 
961                                  const char *domain_name,
962                                  const char *name, DOM_SID *sid, 
963                                  enum lsa_SidType *type)
964 {
965         NTSTATUS result;
966
967         /* Lookup name */
968         result = domain->methods->name_to_sid(domain, mem_ctx, orig_cmd,
969                                               domain_name, name, sid, type);
970
971         /* Return sid and type if lookup successful */
972         if (!NT_STATUS_IS_OK(result)) {
973                 *type = SID_NAME_UNKNOWN;
974         }
975
976         return NT_STATUS_IS_OK(result);
977 }
978
979 /**
980  * @brief Lookup a name in a domain from a sid.
981  *
982  * @param sid Security ID you want to look up.
983  * @param name On success, set to the name corresponding to @p sid.
984  * @param dom_name On success, set to the 'domain name' corresponding to @p sid.
985  * @param type On success, contains the type of name: alias, group or
986  * user.
987  * @retval True if the name exists, in which case @p name and @p type
988  * are set, otherwise False.
989  **/
990 bool winbindd_lookup_name_by_sid(TALLOC_CTX *mem_ctx,
991                                  struct winbindd_domain *domain,
992                                  DOM_SID *sid,
993                                  char **dom_name,
994                                  char **name,
995                                  enum lsa_SidType *type)
996 {
997         NTSTATUS result;
998
999         *dom_name = NULL;
1000         *name = NULL;
1001
1002         /* Lookup name */
1003
1004         result = domain->methods->sid_to_name(domain, mem_ctx, sid, dom_name, name, type);
1005
1006         /* Return name and type if successful */
1007         
1008         if (NT_STATUS_IS_OK(result)) {
1009                 return True;
1010         }
1011
1012         *type = SID_NAME_UNKNOWN;
1013         
1014         return False;
1015 }
1016
1017 /* Free state information held for {set,get,end}{pw,gr}ent() functions */
1018
1019 void free_getent_state(struct getent_state *state)
1020 {
1021         struct getent_state *temp;
1022
1023         /* Iterate over state list */
1024
1025         temp = state;
1026
1027         while(temp != NULL) {
1028                 struct getent_state *next;
1029
1030                 /* Free sam entries then list entry */
1031
1032                 SAFE_FREE(state->sam_entries);
1033                 DLIST_REMOVE(state, state);
1034                 next = temp->next;
1035
1036                 SAFE_FREE(temp);
1037                 temp = next;
1038         }
1039 }
1040
1041 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1042
1043 static bool assume_domain(const char *domain)
1044 {
1045         /* never assume the domain on a standalone server */
1046
1047         if ( lp_server_role() == ROLE_STANDALONE )
1048                 return False;
1049
1050         /* domain member servers may possibly assume for the domain name */
1051
1052         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1053                 if ( !strequal(lp_workgroup(), domain) )
1054                         return False;
1055
1056                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
1057                         return True;
1058         } 
1059
1060         /* only left with a domain controller */
1061
1062         if ( strequal(get_global_sam_name(), domain) )  {
1063                 return True;
1064         }
1065         
1066         return False;
1067 }
1068
1069 /* Parse a string of the form DOMAIN\user into a domain and a user */
1070
1071 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1072 {
1073         char *p = strchr(domuser,*lp_winbind_separator());
1074
1075         if ( !p ) {
1076                 fstrcpy(user, domuser);
1077
1078                 if ( assume_domain(lp_workgroup())) {
1079                         fstrcpy(domain, lp_workgroup());
1080                 } else if ((p = strchr(domuser, '@')) != NULL) {
1081                         fstrcpy(domain, "");                    
1082                 } else {
1083                         return False;
1084                 }
1085         } else {
1086                 fstrcpy(user, p+1);
1087                 fstrcpy(domain, domuser);
1088                 domain[PTR_DIFF(p, domuser)] = 0;
1089         }
1090         
1091         strupper_m(domain);
1092         
1093         return True;
1094 }
1095
1096 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1097                               char **domain, char **user)
1098 {
1099         fstring fstr_domain, fstr_user;
1100         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1101                 return False;
1102         }
1103         *domain = talloc_strdup(mem_ctx, fstr_domain);
1104         *user = talloc_strdup(mem_ctx, fstr_user);
1105         return ((*domain != NULL) && (*user != NULL));
1106 }
1107
1108 /* Ensure an incoming username from NSS is fully qualified. Replace the
1109    incoming fstring with DOMAIN <separator> user. Returns the same
1110    values as parse_domain_user() but also replaces the incoming username.
1111    Used to ensure all names are fully qualified within winbindd.
1112    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1113    The protocol definitions of auth_crap, chng_pswd_auth_crap
1114    really should be changed to use this instead of doing things
1115    by hand. JRA. */
1116
1117 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1118 {
1119         if (!parse_domain_user(username_inout, domain, user)) {
1120                 return False;
1121         }
1122         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1123                  domain, *lp_winbind_separator(),
1124                  user);
1125         return True;
1126 }
1127
1128 /*
1129     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1130     'winbind separator' options.
1131     This means:
1132         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1133         lp_workgroup()
1134
1135     If we are a PDC or BDC, and this is for our domain, do likewise.
1136
1137     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the 
1138     username is then unqualified in unix
1139
1140     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1141 */
1142 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1143 {
1144         fstring tmp_user;
1145
1146         fstrcpy(tmp_user, user);
1147         strlower_m(tmp_user);
1148
1149         if (can_assume && assume_domain(domain)) {
1150                 strlcpy(name, tmp_user, sizeof(fstring));
1151         } else {
1152                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1153                          domain, *lp_winbind_separator(),
1154                          tmp_user);
1155         }
1156 }
1157
1158 /*
1159  * Winbindd socket accessor functions
1160  */
1161
1162 const char *get_winbind_pipe_dir(void) 
1163 {
1164         return lp_parm_const_string(-1, "winbindd", "socket dir", WINBINDD_SOCKET_DIR);
1165 }
1166
1167 char *get_winbind_priv_pipe_dir(void) 
1168 {
1169         return lock_path(WINBINDD_PRIV_SOCKET_SUBDIR);
1170 }
1171
1172 /* Open the winbindd socket */
1173
1174 static int _winbindd_socket = -1;
1175 static int _winbindd_priv_socket = -1;
1176
1177 int open_winbindd_socket(void)
1178 {
1179         if (_winbindd_socket == -1) {
1180                 _winbindd_socket = create_pipe_sock(
1181                         get_winbind_pipe_dir(), WINBINDD_SOCKET_NAME, 0755);
1182                 DEBUG(10, ("open_winbindd_socket: opened socket fd %d\n",
1183                            _winbindd_socket));
1184         }
1185
1186         return _winbindd_socket;
1187 }
1188
1189 int open_winbindd_priv_socket(void)
1190 {
1191         if (_winbindd_priv_socket == -1) {
1192                 _winbindd_priv_socket = create_pipe_sock(
1193                         get_winbind_priv_pipe_dir(), WINBINDD_SOCKET_NAME, 0750);
1194                 DEBUG(10, ("open_winbindd_priv_socket: opened socket fd %d\n",
1195                            _winbindd_priv_socket));
1196         }
1197
1198         return _winbindd_priv_socket;
1199 }
1200
1201 /* Close the winbindd socket */
1202
1203 void close_winbindd_socket(void)
1204 {
1205         if (_winbindd_socket != -1) {
1206                 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1207                            _winbindd_socket));
1208                 close(_winbindd_socket);
1209                 _winbindd_socket = -1;
1210         }
1211         if (_winbindd_priv_socket != -1) {
1212                 DEBUG(10, ("close_winbindd_socket: closing socket fd %d\n",
1213                            _winbindd_priv_socket));
1214                 close(_winbindd_priv_socket);
1215                 _winbindd_priv_socket = -1;
1216         }
1217 }
1218
1219 /*
1220  * Client list accessor functions
1221  */
1222
1223 static struct winbindd_cli_state *_client_list;
1224 static int _num_clients;
1225
1226 /* Return list of all connected clients */
1227
1228 struct winbindd_cli_state *winbindd_client_list(void)
1229 {
1230         return _client_list;
1231 }
1232
1233 /* Add a connection to the list */
1234
1235 void winbindd_add_client(struct winbindd_cli_state *cli)
1236 {
1237         DLIST_ADD(_client_list, cli);
1238         _num_clients++;
1239 }
1240
1241 /* Remove a client from the list */
1242
1243 void winbindd_remove_client(struct winbindd_cli_state *cli)
1244 {
1245         DLIST_REMOVE(_client_list, cli);
1246         _num_clients--;
1247 }
1248
1249 /* Close all open clients */
1250
1251 void winbindd_kill_all_clients(void)
1252 {
1253         struct winbindd_cli_state *cl = winbindd_client_list();
1254
1255         DEBUG(10, ("winbindd_kill_all_clients: going postal\n"));
1256
1257         while (cl) {
1258                 struct winbindd_cli_state *next;
1259                 
1260                 next = cl->next;
1261                 winbindd_remove_client(cl);
1262                 cl = next;
1263         }
1264 }
1265
1266 /* Return number of open clients */
1267
1268 int winbindd_num_clients(void)
1269 {
1270         return _num_clients;
1271 }
1272
1273 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1274                                   TALLOC_CTX *mem_ctx,
1275                                   const DOM_SID *user_sid,
1276                                   uint32 *p_num_groups, DOM_SID **user_sids)
1277 {
1278         NET_USER_INFO_3 *info3 = NULL;
1279         NTSTATUS status = NT_STATUS_NO_MEMORY;
1280         int i;
1281         size_t num_groups = 0;
1282         DOM_SID group_sid, primary_group;
1283         
1284         DEBUG(3,(": lookup_usergroups_cached\n"));
1285         
1286         *user_sids = NULL;
1287         num_groups = 0;
1288         *p_num_groups = 0;
1289
1290         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1291
1292         if (info3 == NULL) {
1293                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1294         }
1295
1296         if (info3->num_groups == 0) {
1297                 TALLOC_FREE(info3);
1298                 return NT_STATUS_UNSUCCESSFUL;
1299         }
1300         
1301         /* always add the primary group to the sid array */
1302         sid_compose(&primary_group, &info3->dom_sid.sid, info3->user_rid);
1303         
1304         if (!add_sid_to_array(mem_ctx, &primary_group, user_sids, &num_groups)) {
1305                 TALLOC_FREE(info3);
1306                 return NT_STATUS_NO_MEMORY;
1307         }
1308
1309         for (i=0; i<info3->num_groups; i++) {
1310                 sid_copy(&group_sid, &info3->dom_sid.sid);
1311                 sid_append_rid(&group_sid, info3->gids[i].g_rid);
1312
1313                 if (!add_sid_to_array(mem_ctx, &group_sid, user_sids,
1314                                  &num_groups)) {
1315                         TALLOC_FREE(info3);
1316                         return NT_STATUS_NO_MEMORY;
1317                 }
1318         }
1319
1320         /* Add any Universal groups in the other_sids list */
1321
1322         for (i=0; i<info3->num_other_sids; i++) {
1323                 /* Skip Domain local groups outside our domain.
1324                    We'll get these from the getsidaliases() RPC call. */
1325                 if (info3->other_sids_attrib[i] & SE_GROUP_RESOURCE)
1326                         continue;
1327
1328                 if (!add_sid_to_array(mem_ctx, &info3->other_sids[i].sid,
1329                                       user_sids, &num_groups))
1330                 {
1331                         TALLOC_FREE(info3);
1332                         return NT_STATUS_NO_MEMORY;                     
1333                 }
1334         }
1335         
1336
1337         TALLOC_FREE(info3);
1338         *p_num_groups = num_groups;
1339         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1340         
1341         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1342
1343         return status;
1344 }
1345
1346 /*********************************************************************
1347  We use this to remove spaces from user and group names
1348 ********************************************************************/
1349
1350 void ws_name_replace( char *name, char replace )
1351 {
1352         char replace_char[2] = { 0x0, 0x0 };
1353     
1354         if ( !lp_winbind_normalize_names() || (replace == '\0') ) 
1355                 return;
1356
1357         replace_char[0] = replace;      
1358         all_string_sub( name, " ", replace_char, 0 );
1359
1360         return; 
1361 }
1362
1363 /*********************************************************************
1364  We use this to do the inverse of ws_name_replace()
1365 ********************************************************************/
1366
1367 void ws_name_return( char *name, char replace )
1368 {
1369         char replace_char[2] = { 0x0, 0x0 };
1370     
1371         if ( !lp_winbind_normalize_names() || (replace == '\0') ) 
1372                 return;
1373         
1374         replace_char[0] = replace;      
1375         all_string_sub( name, replace_char, " ", 0 );
1376
1377         return; 
1378 }
1379
1380 /*********************************************************************
1381  ********************************************************************/
1382
1383 bool winbindd_can_contact_domain( struct winbindd_domain *domain )
1384 {
1385         /* We can contact the domain if it is our primary domain */
1386
1387         if ( domain->primary )
1388                 return True;
1389
1390         /* Can always contact a domain that is in out forest */
1391
1392         if ( domain->domain_flags & DS_DOMAIN_IN_FOREST )
1393                 return True;    
1394
1395         /* We cannot contact the domain if it is running AD and
1396            we have no inbound trust */
1397
1398         if ( domain->active_directory && 
1399              ((domain->domain_flags&DS_DOMAIN_DIRECT_INBOUND) != DS_DOMAIN_DIRECT_INBOUND) ) 
1400         {
1401                 return False;
1402         }
1403         
1404         /* Assume everything else is ok (probably not true but what
1405            can you do?) */
1406         
1407         return True;    
1408 }
1409
1410 /*********************************************************************
1411  ********************************************************************/
1412
1413 bool winbindd_internal_child(struct winbindd_child *child)
1414 {
1415         if ((child == idmap_child()) || (child == locator_child())) {
1416                 return True;
1417         }
1418
1419         return False;
1420 }
1421
1422 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1423
1424 /*********************************************************************
1425  ********************************************************************/
1426
1427 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1428 {
1429         char *var = NULL;
1430         char addr[INET6_ADDRSTRLEN];
1431         const char *kdc = NULL;
1432         int lvl = 11;
1433
1434         if (!domain || !domain->alt_name || !*domain->alt_name) {
1435                 return;
1436         }
1437
1438         if (domain->initialized && !domain->active_directory) {
1439                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1440                         domain->alt_name));
1441                 return;
1442         }
1443
1444         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1445         kdc = addr;
1446         if (!*kdc) {
1447                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1448                         domain->alt_name));
1449                 kdc = domain->dcname;
1450         }
1451
1452         if (!kdc || !*kdc) {
1453                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1454                         domain->alt_name));
1455                 return;
1456         }
1457
1458         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1459                                 domain->alt_name) == -1) {
1460                 return;
1461         }
1462
1463         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1464                 var, kdc));
1465
1466         setenv(var, kdc, 1);
1467         free(var);
1468 }
1469
1470 /*********************************************************************
1471  ********************************************************************/
1472
1473 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1474 {
1475         struct winbindd_domain *our_dom = find_our_domain();
1476
1477         winbindd_set_locator_kdc_env(domain);
1478
1479         if (domain != our_dom) {
1480                 winbindd_set_locator_kdc_env(our_dom);
1481         }
1482 }
1483
1484 /*********************************************************************
1485  ********************************************************************/
1486
1487 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1488 {
1489         char *var = NULL;
1490
1491         if (!domain || !domain->alt_name || !*domain->alt_name) {
1492                 return;
1493         }
1494
1495         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1496                                 domain->alt_name) == -1) {
1497                 return;
1498         }
1499
1500         unsetenv(var);
1501         free(var);
1502 }
1503 #else
1504
1505 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1506 {
1507         return;
1508 }
1509
1510 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1511 {
1512         return;
1513 }
1514
1515 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */