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