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