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