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