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