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