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