winbindd: only use NetBIOS name when searching domain list in add_trusted_domain_from...
[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 "lib/util_unixsids.h"
26 #include "secrets.h"
27 #include "../libcli/security/security.h"
28 #include "../libcli/auth/pam_errors.h"
29 #include "passdb/machine_sid.h"
30 #include "passdb.h"
31 #include "source4/lib/messaging/messaging.h"
32 #include "librpc/gen_ndr/ndr_lsa.h"
33 #include "auth/credentials/credentials.h"
34 #include "libsmb/samlogon_cache.h"
35
36 #undef DBGC_CLASS
37 #define DBGC_CLASS DBGC_WINBIND
38
39 static struct winbindd_domain *
40 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc);
41
42 /**
43  * @file winbindd_util.c
44  *
45  * Winbind daemon for NT domain authentication nss module.
46  **/
47
48
49 /* The list of trusted domains.  Note that the list can be deleted and
50    recreated using the init_domain_list() function so pointers to
51    individual winbindd_domain structures cannot be made.  Keep a copy of
52    the domain name instead. */
53
54 static struct winbindd_domain *_domain_list = NULL;
55
56 struct winbindd_domain *domain_list(void)
57 {
58         /* Initialise list */
59
60         if ((!_domain_list) && (!init_domain_list())) {
61                 smb_panic("Init_domain_list failed");
62         }
63
64         return _domain_list;
65 }
66
67 /* Free all entries in the trusted domain list */
68
69 static void free_domain_list(void)
70 {
71         struct winbindd_domain *domain = _domain_list;
72
73         while(domain) {
74                 struct winbindd_domain *next = domain->next;
75
76                 DLIST_REMOVE(_domain_list, domain);
77                 TALLOC_FREE(domain);
78                 domain = next;
79         }
80 }
81
82 /**
83  * Iterator for winbindd's domain list.
84  * To be used (e.g.) in tevent based loops.
85  */
86 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
87 {
88         if (domain == NULL) {
89                 domain = domain_list();
90         } else {
91                 domain = domain->next;
92         }
93
94         if ((domain != NULL) &&
95             (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
96             sid_check_is_our_sam(&domain->sid))
97         {
98                 domain = domain->next;
99         }
100
101         return domain;
102 }
103
104 static bool is_internal_domain(const struct dom_sid *sid)
105 {
106         if (sid == NULL)
107                 return False;
108
109         return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
110 }
111
112 static bool is_in_internal_domain(const struct dom_sid *sid)
113 {
114         if (sid == NULL)
115                 return False;
116
117         return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
118 }
119
120
121 /* Add a trusted domain to our list of domains.
122    If the domain already exists in the list,
123    return it and don't re-initialize.  */
124
125 static struct winbindd_domain *
126 add_trusted_domain(const char *domain_name, const char *alt_name,
127                    const struct dom_sid *sid)
128 {
129         struct winbindd_tdc_domain tdc;
130
131         ZERO_STRUCT(tdc);
132
133         tdc.domain_name = domain_name;
134         tdc.dns_name = alt_name;
135         if (sid) {
136                 sid_copy(&tdc.sid, sid);
137         }
138
139         return add_trusted_domain_from_tdc(&tdc);
140 }
141
142 /* Add a trusted domain out of a trusted domain cache
143    entry
144 */
145 static struct winbindd_domain *
146 add_trusted_domain_from_tdc(const struct winbindd_tdc_domain *tdc)
147 {
148         struct winbindd_domain *domain;
149         const char *alternative_name = NULL;
150         const char **ignored_domains, **dom;
151         int role = lp_server_role();
152         const char *domain_name = tdc->domain_name;
153         const struct dom_sid *sid = &tdc->sid;
154
155         if (is_null_sid(sid)) {
156                 DBG_ERR("Got null SID for domain [%s]\n", domain_name);
157                 return NULL;
158         }
159
160         ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
161         for (dom=ignored_domains; dom && *dom; dom++) {
162                 if (gen_fnmatch(*dom, domain_name) == 0) {
163                         DEBUG(2,("Ignoring domain '%s'\n", domain_name));
164                         return NULL;
165                 }
166         }
167
168         /* use alt_name if available to allow DNS lookups */
169
170         if (tdc->dns_name && *tdc->dns_name) {
171                 alternative_name = tdc->dns_name;
172         }
173
174         /* We can't call domain_list() as this function is called from
175            init_domain_list() and we'll get stuck in a loop. */
176         for (domain = _domain_list; domain; domain = domain->next) {
177                 if (strequal(domain_name, domain->name)) {
178                         break;
179                 }
180         }
181
182         if (domain != NULL) {
183                 struct winbindd_domain *check_domain = NULL;
184
185                 for (check_domain = _domain_list;
186                      check_domain != NULL;
187                      check_domain = check_domain->next)
188                 {
189                         if (check_domain == domain) {
190                                 continue;
191                         }
192
193                         if (dom_sid_equal(&check_domain->sid, sid)) {
194                                 break;
195                         }
196                 }
197
198                 if (check_domain != NULL) {
199                         DBG_ERR("SID [%s] already used by domain [%s], "
200                                 "expected [%s]\n",
201                                 sid_string_dbg(sid), check_domain->name,
202                                 domain->name);
203                         return NULL;
204                 }
205         }
206
207         if ((domain != NULL) && (alternative_name != NULL)) {
208                 struct winbindd_domain *check_domain = NULL;
209
210                 for (check_domain = _domain_list;
211                      check_domain != NULL;
212                      check_domain = check_domain->next)
213                 {
214                         if (check_domain == domain) {
215                                 continue;
216                         }
217
218                         if (strequal(check_domain->alt_name, alternative_name)) {
219                                 break;
220                         }
221                 }
222
223                 if (check_domain != NULL) {
224                         DBG_ERR("DNS name [%s] used by domain [%s], "
225                                 "expected [%s]\n",
226                                 alternative_name, check_domain->name,
227                                 domain->name);
228                         return NULL;
229                 }
230         }
231
232         if (domain != NULL) {
233                 return domain;
234         }
235
236         /* Create new domain entry */
237         domain = talloc_zero(NULL, struct winbindd_domain);
238         if (domain == NULL) {
239                 return NULL;
240         }
241
242         domain->children = talloc_zero_array(domain,
243                                              struct winbindd_child,
244                                              lp_winbind_max_domain_connections());
245         if (domain->children == NULL) {
246                 TALLOC_FREE(domain);
247                 return NULL;
248         }
249
250         domain->name = talloc_strdup(domain, domain_name);
251         if (domain->name == NULL) {
252                 TALLOC_FREE(domain);
253                 return NULL;
254         }
255
256         if (alternative_name) {
257                 domain->alt_name = talloc_strdup(domain, alternative_name);
258                 if (domain->alt_name == NULL) {
259                         TALLOC_FREE(domain);
260                         return NULL;
261                 }
262         }
263
264         domain->backend = NULL;
265         domain->internal = is_internal_domain(sid);
266         domain->sequence_number = DOM_SEQUENCE_NONE;
267         domain->last_seq_check = 0;
268         domain->initialized = false;
269         domain->online = is_internal_domain(sid);
270         domain->check_online_timeout = 0;
271         domain->dc_probe_pid = (pid_t)-1;
272         domain->domain_flags = tdc->trust_flags;
273         domain->domain_type = tdc->trust_type;
274         domain->domain_trust_attribs = tdc->trust_attribs;
275         sid_copy(&domain->sid, sid);
276
277         /* Is this our primary domain ? */
278         if (role == ROLE_DOMAIN_MEMBER) {
279                 domain->primary = strequal(domain_name, lp_workgroup());
280         } else {
281                 domain->primary = strequal(domain_name, get_global_sam_name());
282         }
283
284         if (domain->primary) {
285                 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
286                         domain->active_directory = true;
287                 }
288                 if (lp_security() == SEC_ADS) {
289                         domain->active_directory = true;
290                 }
291         } else if (!domain->internal) {
292                 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
293                         domain->active_directory = true;
294                 }
295         }
296
297         /* Link to domain list */
298         DLIST_ADD_END(_domain_list, domain);
299
300         wcache_tdc_add_domain( domain );
301
302         setup_domain_child(domain);
303
304         DEBUG(2,
305               ("Added domain %s %s %s\n", domain->name, domain->alt_name,
306                !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
307
308         return domain;
309 }
310
311 bool domain_is_forest_root(const struct winbindd_domain *domain)
312 {
313         const uint32_t fr_flags =
314                 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
315
316         return ((domain->domain_flags & fr_flags) == fr_flags);
317 }
318
319 /********************************************************************
320   rescan our domains looking for new trusted domains
321 ********************************************************************/
322
323 struct trustdom_state {
324         struct winbindd_domain *domain;
325         struct winbindd_request request;
326 };
327
328 static void trustdom_list_done(struct tevent_req *req);
329 static void rescan_forest_root_trusts( void );
330 static void rescan_forest_trusts( void );
331
332 static void add_trusted_domains( struct winbindd_domain *domain )
333 {
334         struct trustdom_state *state;
335         struct tevent_req *req;
336
337         state = talloc_zero(NULL, struct trustdom_state);
338         if (state == NULL) {
339                 DEBUG(0, ("talloc failed\n"));
340                 return;
341         }
342         state->domain = domain;
343
344         state->request.length = sizeof(state->request);
345         state->request.cmd = WINBINDD_LIST_TRUSTDOM;
346
347         req = wb_domain_request_send(state, server_event_context(),
348                                      domain, &state->request);
349         if (req == NULL) {
350                 DEBUG(1, ("wb_domain_request_send failed\n"));
351                 TALLOC_FREE(state);
352                 return;
353         }
354         tevent_req_set_callback(req, trustdom_list_done, state);
355 }
356
357 static void trustdom_list_done(struct tevent_req *req)
358 {
359         struct trustdom_state *state = tevent_req_callback_data(
360                 req, struct trustdom_state);
361         struct winbindd_response *response;
362         int res, err;
363         char *p;
364         struct winbindd_tdc_domain trust_params = {0};
365         ptrdiff_t extra_len;
366         bool within_forest = false;
367
368         /*
369          * Only when we enumerate our primary domain
370          * or our forest root domain, we should keep
371          * the NETR_TRUST_FLAG_IN_FOREST flag, in
372          * all other cases we need to clear it as the domain
373          * is not part of our forest.
374          */
375         if (state->domain->primary) {
376                 within_forest = true;
377         } else if (domain_is_forest_root(state->domain)) {
378                 within_forest = true;
379         }
380
381         res = wb_domain_request_recv(req, state, &response, &err);
382         if ((res == -1) || (response->result != WINBINDD_OK)) {
383                 DBG_WARNING("Could not receive trusts for domain %s\n",
384                             state->domain->name);
385                 TALLOC_FREE(state);
386                 return;
387         }
388
389         if (response->length < sizeof(struct winbindd_response)) {
390                 DBG_ERR("ill-formed trustdom response - short length\n");
391                 TALLOC_FREE(state);
392                 return;
393         }
394
395         extra_len = response->length - sizeof(struct winbindd_response);
396
397         p = (char *)response->extra_data.data;
398
399         while ((p - (char *)response->extra_data.data) < extra_len) {
400                 char *q, *sidstr, *alt_name;
401
402                 DBG_DEBUG("parsing response line '%s'\n", p);
403
404                 ZERO_STRUCT(trust_params);
405                 trust_params.domain_name = p;
406
407                 alt_name = strchr(p, '\\');
408                 if (alt_name == NULL) {
409                         DBG_ERR("Got invalid trustdom response\n");
410                         break;
411                 }
412
413                 *alt_name = '\0';
414                 alt_name += 1;
415
416                 sidstr = strchr(alt_name, '\\');
417                 if (sidstr == NULL) {
418                         DBG_ERR("Got invalid trustdom response\n");
419                         break;
420                 }
421
422                 *sidstr = '\0';
423                 sidstr += 1;
424
425                 /* use the real alt_name if we have one, else pass in NULL */
426                 if (!strequal(alt_name, "(null)")) {
427                         trust_params.dns_name = alt_name;
428                 }
429
430                 q = strtok(sidstr, "\\");
431                 if (q == NULL) {
432                         DBG_ERR("Got invalid trustdom response\n");
433                         break;
434                 }
435
436                 if (!string_to_sid(&trust_params.sid, sidstr)) {
437                         DEBUG(0, ("Got invalid trustdom response\n"));
438                         break;
439                 }
440
441                 q = strtok(NULL, "\\");
442                 if (q == NULL) {
443                         DBG_ERR("Got invalid trustdom response\n");
444                         break;
445                 }
446
447                 trust_params.trust_flags = (uint32_t)strtoul(q, NULL, 10);
448
449                 q = strtok(NULL, "\\");
450                 if (q == NULL) {
451                         DBG_ERR("Got invalid trustdom response\n");
452                         break;
453                 }
454
455                 trust_params.trust_type = (uint32_t)strtoul(q, NULL, 10);
456
457                 q = strtok(NULL, "\n");
458                 if (q == NULL) {
459                         DBG_ERR("Got invalid trustdom response\n");
460                         break;
461                 }
462
463                 trust_params.trust_attribs = (uint32_t)strtoul(q, NULL, 10);
464
465                 if (!within_forest) {
466                         trust_params.trust_flags &= ~NETR_TRUST_FLAG_IN_FOREST;
467                 }
468
469                 if (!state->domain->primary) {
470                         trust_params.trust_flags &= ~NETR_TRUST_FLAG_PRIMARY;
471                 }
472
473                 /*
474                  * We always call add_trusted_domain() cause on an existing
475                  * domain structure, it will update the SID if necessary.
476                  * This is important because we need the SID for sibling
477                  * domains.
478                  */
479                 (void)add_trusted_domain_from_tdc(&trust_params);
480
481                 p = q + strlen(q) + 1;
482         }
483
484         /*
485            Cases to consider when scanning trusts:
486            (a) we are calling from a child domain (primary && !forest_root)
487            (b) we are calling from the root of the forest (primary && forest_root)
488            (c) we are calling from a trusted forest domain (!primary
489                && !forest_root)
490         */
491
492         if (state->domain->primary) {
493                 /* If this is our primary domain and we are not in the
494                    forest root, we have to scan the root trusts first */
495
496                 if (!domain_is_forest_root(state->domain))
497                         rescan_forest_root_trusts();
498                 else
499                         rescan_forest_trusts();
500
501         } else if (domain_is_forest_root(state->domain)) {
502                 /* Once we have done root forest trust search, we can
503                    go on to search the trusted forests */
504
505                 rescan_forest_trusts();
506         }
507
508         TALLOC_FREE(state);
509
510         return;
511 }
512
513 /********************************************************************
514  Scan the trusts of our forest root
515 ********************************************************************/
516
517 static void rescan_forest_root_trusts( void )
518 {
519         struct winbindd_tdc_domain *dom_list = NULL;
520         size_t num_trusts = 0;
521         int i;
522
523         /* The only transitive trusts supported by Windows 2003 AD are
524            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
525            first two are handled in forest and listed by
526            DsEnumerateDomainTrusts().  Forest trusts are not so we
527            have to do that ourselves. */
528
529         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
530                 return;
531
532         for ( i=0; i<num_trusts; i++ ) {
533                 struct winbindd_domain *d = NULL;
534
535                 /* Find the forest root.  Don't necessarily trust
536                    the domain_list() as our primary domain may not
537                    have been initialized. */
538
539                 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
540                         continue;
541                 }
542
543                 /* Here's the forest root */
544
545                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
546
547                 if ( !d ) {
548                         d = add_trusted_domain_from_tdc(&dom_list[i]);
549                 }
550
551                 if (d == NULL) {
552                         continue;
553                 }
554
555                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
556                           "for domain tree root %s (%s)\n",
557                           d->name, d->alt_name ));
558
559                 d->domain_flags = dom_list[i].trust_flags;
560                 d->domain_type  = dom_list[i].trust_type;
561                 d->domain_trust_attribs = dom_list[i].trust_attribs;
562
563                 add_trusted_domains( d );
564
565                 break;
566         }
567
568         TALLOC_FREE( dom_list );
569
570         return;
571 }
572
573 /********************************************************************
574  scan the transitive forest trusts (not our own)
575 ********************************************************************/
576
577
578 static void rescan_forest_trusts( void )
579 {
580         struct winbindd_domain *d = NULL;
581         struct winbindd_tdc_domain *dom_list = NULL;
582         size_t num_trusts = 0;
583         int i;
584
585         /* The only transitive trusts supported by Windows 2003 AD are
586            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
587            first two are handled in forest and listed by
588            DsEnumerateDomainTrusts().  Forest trusts are not so we
589            have to do that ourselves. */
590
591         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
592                 return;
593
594         for ( i=0; i<num_trusts; i++ ) {
595                 uint32_t flags   = dom_list[i].trust_flags;
596                 uint32_t type    = dom_list[i].trust_type;
597                 uint32_t attribs = dom_list[i].trust_attribs;
598
599                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
600
601                 /* ignore our primary and internal domains */
602
603                 if ( d && (d->internal || d->primary ) )
604                         continue;
605
606                 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
607                      (type == LSA_TRUST_TYPE_UPLEVEL) &&
608                      (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
609                 {
610                         /* add the trusted domain if we don't know
611                            about it */
612
613                         if ( !d ) {
614                                 d = add_trusted_domain_from_tdc(&dom_list[i]);
615                         }
616
617                         if (d == NULL) {
618                                 continue;
619                         }
620
621                         DEBUG(10,("Following trust path for domain %s (%s)\n",
622                                   d->name, d->alt_name ));
623                         add_trusted_domains( d );
624                 }
625         }
626
627         TALLOC_FREE( dom_list );
628
629         return;
630 }
631
632 /*********************************************************************
633  The process of updating the trusted domain list is a three step
634  async process:
635  (a) ask our domain
636  (b) ask the root domain in our forest
637  (c) ask the a DC in any Win2003 trusted forests
638 *********************************************************************/
639
640 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
641                             struct timeval now, void *private_data)
642 {
643         TALLOC_FREE(te);
644
645         /* I use to clear the cache here and start over but that
646            caused problems in child processes that needed the
647            trust dom list early on.  Removing it means we
648            could have some trusted domains listed that have been
649            removed from our primary domain's DC until a full
650            restart.  This should be ok since I think this is what
651            Windows does as well. */
652
653         /* this will only add new domains we didn't already know about
654            in the domain_list()*/
655
656         add_trusted_domains( find_our_domain() );
657
658         te = tevent_add_timer(
659                 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
660                 rescan_trusted_domains, NULL);
661         /*
662          * If te == NULL, there's not much we can do here. Don't fail, the
663          * only thing we miss is new trusted domains.
664          */
665
666         return;
667 }
668
669 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
670                                                    struct winbindd_cli_state *state)
671 {
672         /* Ensure null termination */
673         state->request->domain_name
674                 [sizeof(state->request->domain_name)-1]='\0';
675         state->request->data.init_conn.dcname
676                 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
677
678         if (strlen(state->request->data.init_conn.dcname) > 0) {
679                 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
680         }
681
682         init_dc_connection(domain, false);
683
684         if (!domain->initialized) {
685                 /* If we return error here we can't do any cached authentication,
686                    but we may be in disconnected mode and can't initialize correctly.
687                    Do what the previous code did and just return without initialization,
688                    once we go online we'll re-initialize.
689                 */
690                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
691                         "online = %d\n", domain->name, (int)domain->online ));
692         }
693
694         fstrcpy(state->response->data.domain_info.name, domain->name);
695         fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
696         sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
697
698         state->response->data.domain_info.native_mode
699                 = domain->native_mode;
700         state->response->data.domain_info.active_directory
701                 = domain->active_directory;
702         state->response->data.domain_info.primary
703                 = domain->primary;
704
705         return WINBINDD_OK;
706 }
707
708 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
709                                        void *private_data,
710                                        uint32_t msg_type,
711                                        struct server_id server_id,
712                                        DATA_BLOB *data)
713 {
714         TALLOC_CTX *frame = talloc_stackframe();
715         struct lsa_TrustDomainInfoInfoEx info;
716         enum ndr_err_code ndr_err;
717         struct winbindd_domain *d = NULL;
718
719         DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
720
721         if (data == NULL) {
722                 TALLOC_FREE(frame);
723                 return;
724         }
725
726         ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
727                         (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
728         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
729                 TALLOC_FREE(frame);
730                 return;
731         }
732
733         d = find_domain_from_name_noinit(info.netbios_name.string);
734         if (d != NULL) {
735                 TALLOC_FREE(frame);
736                 return;
737         }
738
739         d = add_trusted_domain(info.netbios_name.string,
740                                info.domain_name.string,
741                                info.sid);
742         if (d == NULL) {
743                 TALLOC_FREE(frame);
744                 return;
745         }
746
747         if (d->internal) {
748                 TALLOC_FREE(frame);
749                 return;
750         }
751
752         if (d->primary) {
753                 TALLOC_FREE(frame);
754                 return;
755         }
756
757         if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
758                 d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
759         }
760         if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
761                 d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
762         }
763         if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
764                 d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
765         }
766         d->domain_type = info.trust_type;
767         d->domain_trust_attribs = info.trust_attributes;
768
769         TALLOC_FREE(frame);
770 }
771
772 /*
773  * We did not get the secret when we queried secrets.tdb, so read it
774  * from secrets.tdb and re-sync the databases
775  */
776 static bool migrate_secrets_tdb_to_ldb(struct winbindd_domain *domain)
777 {
778         bool ok;
779         struct cli_credentials *creds;
780         NTSTATUS can_migrate = pdb_get_trust_credentials(domain->name,
781                                                          NULL, domain, &creds);
782         if (!NT_STATUS_IS_OK(can_migrate)) {
783                 DEBUG(0, ("Failed to fetch our own, local AD domain join "
784                         "password for winbindd's internal use, both from "
785                         "secrets.tdb and secrets.ldb: %s\n",
786                         nt_errstr(can_migrate)));
787                 return false;
788         }
789
790         /*
791          * NOTE: It is very unlikely we end up here if there is an
792          * oldpass, because a new password is created at
793          * classicupgrade, so this is not a concern.
794          */
795         ok = secrets_store_machine_pw_sync(cli_credentials_get_password(creds),
796                    NULL /* oldpass */,
797                    cli_credentials_get_domain(creds),
798                    cli_credentials_get_realm(creds),
799                    cli_credentials_get_salt_principal(creds),
800                    0, /* Supported enc types, unused */
801                    &domain->sid,
802                    cli_credentials_get_password_last_changed_time(creds),
803                    cli_credentials_get_secure_channel_type(creds),
804                    false /* do_delete: Do not delete */);
805         TALLOC_FREE(creds);
806         if (ok == false) {
807                 DEBUG(0, ("Failed to write our our own, "
808                           "local AD domain join password for "
809                           "winbindd's internal use into secrets.tdb\n"));
810                 return false;
811         }
812         return true;
813 }
814
815 /* Look up global info for the winbind daemon */
816 bool init_domain_list(void)
817 {
818         int role = lp_server_role();
819         struct pdb_domain_info *pdb_domain_info = NULL;
820         NTSTATUS status;
821
822         /* Free existing list */
823         free_domain_list();
824
825         /* BUILTIN domain */
826
827         (void)add_trusted_domain("BUILTIN", NULL, &global_sid_Builtin);
828
829         /* Local SAM */
830
831         /*
832          * In case the passdb backend is passdb_dsdb the domain SID comes from
833          * dsdb, not from secrets.tdb. As we use the domain SID in various
834          * places, we must ensure the domain SID is migrated from dsdb to
835          * secrets.tdb before get_global_sam_sid() is called the first time.
836          *
837          * The migration is done as part of the passdb_dsdb initialisation,
838          * calling pdb_get_domain_info() triggers it.
839          */
840         pdb_domain_info = pdb_get_domain_info(talloc_tos());
841
842         if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
843                 struct winbindd_domain *domain;
844                 enum netr_SchannelType sec_chan_type;
845                 const char *account_name;
846                 struct samr_Password current_nt_hash;
847                 bool ok;
848
849                 if (pdb_domain_info == NULL) {
850                         DEBUG(0, ("Failed to fetch our own, local AD "
851                                 "domain info from sam.ldb\n"));
852                         return false;
853                 }
854                 domain = add_trusted_domain(pdb_domain_info->name,
855                                         pdb_domain_info->dns_domain,
856                                         &pdb_domain_info->sid);
857                 TALLOC_FREE(pdb_domain_info);
858                 if (domain == NULL) {
859                         DEBUG(0, ("Failed to add our own, local AD "
860                                 "domain to winbindd's internal list\n"));
861                         return false;
862                 }
863
864                 /*
865                  * We need to call this to find out if we are an RODC
866                  */
867                 ok = get_trust_pw_hash(domain->name,
868                                        current_nt_hash.hash,
869                                        &account_name,
870                                        &sec_chan_type);
871                 if (!ok) {
872                         /*
873                          * If get_trust_pw_hash() fails, then try and
874                          * fetch the password from the more recent of
875                          * secrets.{ldb,tdb} using the
876                          * pdb_get_trust_credentials()
877                          */
878                         ok = migrate_secrets_tdb_to_ldb(domain);
879
880                         if (!ok) {
881                                 DEBUG(0, ("Failed to migrate our own, "
882                                           "local AD domain join password for "
883                                           "winbindd's internal use into "
884                                           "secrets.tdb\n"));
885                                 return false;
886                         }
887                         ok = get_trust_pw_hash(domain->name,
888                                                current_nt_hash.hash,
889                                                &account_name,
890                                                &sec_chan_type);
891                         if (!ok) {
892                                 DEBUG(0, ("Failed to find our our own, just "
893                                           "written local AD domain join "
894                                           "password for winbindd's internal "
895                                           "use in secrets.tdb\n"));
896                                 return false;
897                         }
898                 }
899                 if (sec_chan_type == SEC_CHAN_RODC) {
900                         domain->rodc = true;
901                 }
902
903         } else {
904                 (void)add_trusted_domain(get_global_sam_name(), NULL,
905                                          get_global_sam_sid());
906         }
907         /* Add ourselves as the first entry. */
908
909         if ( role == ROLE_DOMAIN_MEMBER ) {
910                 struct winbindd_domain *domain;
911                 struct dom_sid our_sid;
912
913                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
914                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
915                         return False;
916                 }
917
918                 domain = add_trusted_domain(lp_workgroup(), lp_realm(),
919                                             &our_sid);
920                 if (domain) {
921                         /* Even in the parent winbindd we'll need to
922                            talk to the DC, so try and see if we can
923                            contact it. Theoretically this isn't neccessary
924                            as the init_dc_connection() in init_child_recv()
925                            will do this, but we can start detecting the DC
926                            early here. */
927                         set_domain_online_request(domain);
928                 }
929         }
930
931         status = imessaging_register(winbind_imessaging_context(), NULL,
932                                      MSG_WINBIND_NEW_TRUSTED_DOMAIN,
933                                      wb_imsg_new_trusted_domain);
934         if (!NT_STATUS_IS_OK(status)) {
935                 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
936                           nt_errstr(status)));
937                 return false;
938         }
939
940         return True;
941 }
942
943 /**
944  * Given a domain name, return the struct winbindd domain info for it
945  *
946  * @note Do *not* pass lp_workgroup() to this function.  domain_list
947  *       may modify it's value, and free that pointer.  Instead, our local
948  *       domain may be found by calling find_our_domain().
949  *       directly.
950  *
951  *
952  * @return The domain structure for the named domain, if it is working.
953  */
954
955 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
956 {
957         struct winbindd_domain *domain;
958
959         /* Search through list */
960
961         for (domain = domain_list(); domain != NULL; domain = domain->next) {
962                 if (strequal(domain_name, domain->name)) {
963                         return domain;
964                 }
965                 if (domain->alt_name == NULL) {
966                         continue;
967                 }
968                 if (strequal(domain_name, domain->alt_name)) {
969                         return domain;
970                 }
971         }
972
973         /* Not found */
974
975         return NULL;
976 }
977
978 struct winbindd_domain *find_domain_from_name(const char *domain_name)
979 {
980         struct winbindd_domain *domain;
981
982         domain = find_domain_from_name_noinit(domain_name);
983
984         if (domain == NULL)
985                 return NULL;
986
987         if (!domain->initialized)
988                 init_dc_connection(domain, false);
989
990         return domain;
991 }
992
993 /* Given a domain sid, return the struct winbindd domain info for it */
994
995 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
996 {
997         struct winbindd_domain *domain;
998
999         /* Search through list */
1000
1001         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1002                 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1003                         return domain;
1004         }
1005
1006         /* Not found */
1007
1008         return NULL;
1009 }
1010
1011 /* Given a domain sid, return the struct winbindd domain info for it */
1012
1013 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1014 {
1015         struct winbindd_domain *domain;
1016
1017         domain = find_domain_from_sid_noinit(sid);
1018
1019         if (domain == NULL)
1020                 return NULL;
1021
1022         if (!domain->initialized)
1023                 init_dc_connection(domain, false);
1024
1025         return domain;
1026 }
1027
1028 struct winbindd_domain *find_our_domain(void)
1029 {
1030         struct winbindd_domain *domain;
1031
1032         /* Search through list */
1033
1034         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1035                 if (domain->primary)
1036                         return domain;
1037         }
1038
1039         smb_panic("Could not find our domain");
1040         return NULL;
1041 }
1042
1043 /* Find the appropriate domain to lookup a name or SID */
1044
1045 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1046 {
1047         DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1048
1049         /*
1050          * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1051          * by our passdb.
1052          */
1053
1054         if ( sid_check_is_in_unix_groups(sid) ||
1055              sid_check_is_unix_groups(sid) ||
1056              sid_check_is_in_unix_users(sid) ||
1057              sid_check_is_unix_users(sid) ||
1058              sid_check_is_wellknown_domain(sid, NULL) ||
1059              sid_check_is_in_wellknown_domain(sid) )
1060         {
1061                 return find_domain_from_sid(get_global_sam_sid());
1062         }
1063
1064         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1065          * one to contact the external DC's. On member servers the internal
1066          * domains are different: These are part of the local SAM. */
1067
1068         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1069                 DEBUG(10, ("calling find_domain_from_sid\n"));
1070                 return find_domain_from_sid(sid);
1071         }
1072
1073         /* On a member server a query for SID or name can always go to our
1074          * primary DC. */
1075
1076         DEBUG(10, ("calling find_our_domain\n"));
1077         return find_our_domain();
1078 }
1079
1080 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1081 {
1082         if ( strequal(domain_name, unix_users_domain_name() ) ||
1083              strequal(domain_name, unix_groups_domain_name() ) )
1084         {
1085                 /*
1086                  * The "Unix User" and "Unix Group" domain our handled by
1087                  * passdb
1088                  */
1089                 return find_domain_from_name_noinit( get_global_sam_name() );
1090         }
1091
1092         if (IS_DC || strequal(domain_name, "BUILTIN") ||
1093             strequal(domain_name, get_global_sam_name()))
1094                 return find_domain_from_name_noinit(domain_name);
1095
1096
1097         return find_our_domain();
1098 }
1099
1100 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1101
1102 static bool assume_domain(const char *domain)
1103 {
1104         /* never assume the domain on a standalone server */
1105
1106         if ( lp_server_role() == ROLE_STANDALONE )
1107                 return False;
1108
1109         /* domain member servers may possibly assume for the domain name */
1110
1111         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1112                 if ( !strequal(lp_workgroup(), domain) )
1113                         return False;
1114
1115                 if ( lp_winbind_use_default_domain() )
1116                         return True;
1117         }
1118
1119         /* only left with a domain controller */
1120
1121         if ( strequal(get_global_sam_name(), domain) )  {
1122                 return True;
1123         }
1124
1125         return False;
1126 }
1127
1128 /* Parse a string of the form DOMAIN\user into a domain and a user */
1129
1130 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1131 {
1132         char *p = strchr(domuser,*lp_winbind_separator());
1133
1134         if ( !p ) {
1135                 fstrcpy(user, domuser);
1136                 p = strchr(domuser, '@');
1137
1138                 if ( assume_domain(lp_workgroup()) && p == NULL) {
1139                         fstrcpy(domain, lp_workgroup());
1140                 } else if (p != NULL) {
1141                         fstrcpy(domain, p + 1);
1142                         user[PTR_DIFF(p, domuser)] = 0;
1143                 } else {
1144                         return False;
1145                 }
1146         } else {
1147                 fstrcpy(user, p+1);
1148                 fstrcpy(domain, domuser);
1149                 domain[PTR_DIFF(p, domuser)] = 0;
1150         }
1151
1152         return strupper_m(domain);
1153 }
1154
1155 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1156                               char **domain, char **user)
1157 {
1158         fstring fstr_domain, fstr_user;
1159         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1160                 return False;
1161         }
1162         *domain = talloc_strdup(mem_ctx, fstr_domain);
1163         *user = talloc_strdup(mem_ctx, fstr_user);
1164         return ((*domain != NULL) && (*user != NULL));
1165 }
1166
1167 /* Ensure an incoming username from NSS is fully qualified. Replace the
1168    incoming fstring with DOMAIN <separator> user. Returns the same
1169    values as parse_domain_user() but also replaces the incoming username.
1170    Used to ensure all names are fully qualified within winbindd.
1171    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1172    The protocol definitions of auth_crap, chng_pswd_auth_crap
1173    really should be changed to use this instead of doing things
1174    by hand. JRA. */
1175
1176 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1177 {
1178         if (!parse_domain_user(username_inout, domain, user)) {
1179                 return False;
1180         }
1181         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1182                  domain, *lp_winbind_separator(),
1183                  user);
1184         return True;
1185 }
1186
1187 /*
1188     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1189     'winbind separator' options.
1190     This means:
1191         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1192         lp_workgroup()
1193
1194     If we are a PDC or BDC, and this is for our domain, do likewise.
1195
1196     On an AD DC we always fill DOMAIN\\USERNAME.
1197
1198     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1199 */
1200 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1201 {
1202         fstring tmp_user;
1203
1204         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1205                 can_assume = false;
1206         }
1207
1208         fstrcpy(tmp_user, user);
1209         (void)strlower_m(tmp_user);
1210
1211         if (can_assume && assume_domain(domain)) {
1212                 strlcpy(name, tmp_user, sizeof(fstring));
1213         } else {
1214                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1215                          domain, *lp_winbind_separator(),
1216                          tmp_user);
1217         }
1218 }
1219
1220 /**
1221  * talloc version of fill_domain_username()
1222  * return NULL on talloc failure.
1223  */
1224 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1225                                   const char *domain,
1226                                   const char *user,
1227                                   bool can_assume)
1228 {
1229         char *tmp_user, *name;
1230
1231         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1232                 can_assume = false;
1233         }
1234
1235         tmp_user = talloc_strdup(mem_ctx, user);
1236         if (!strlower_m(tmp_user)) {
1237                 TALLOC_FREE(tmp_user);
1238                 return NULL;
1239         }
1240
1241         if (can_assume && assume_domain(domain)) {
1242                 name = tmp_user;
1243         } else {
1244                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1245                                        domain,
1246                                        *lp_winbind_separator(),
1247                                        tmp_user);
1248                 TALLOC_FREE(tmp_user);
1249         }
1250
1251         return name;
1252 }
1253
1254 /*
1255  * Client list accessor functions
1256  */
1257
1258 static struct winbindd_cli_state *_client_list;
1259 static int _num_clients;
1260
1261 /* Return list of all connected clients */
1262
1263 struct winbindd_cli_state *winbindd_client_list(void)
1264 {
1265         return _client_list;
1266 }
1267
1268 /* Return list-tail of all connected clients */
1269
1270 struct winbindd_cli_state *winbindd_client_list_tail(void)
1271 {
1272         return DLIST_TAIL(_client_list);
1273 }
1274
1275 /* Return previous (read:newer) client in list */
1276
1277 struct winbindd_cli_state *
1278 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1279 {
1280         return DLIST_PREV(cli);
1281 }
1282
1283 /* Add a connection to the list */
1284
1285 void winbindd_add_client(struct winbindd_cli_state *cli)
1286 {
1287         cli->last_access = time(NULL);
1288         DLIST_ADD(_client_list, cli);
1289         _num_clients++;
1290 }
1291
1292 /* Remove a client from the list */
1293
1294 void winbindd_remove_client(struct winbindd_cli_state *cli)
1295 {
1296         DLIST_REMOVE(_client_list, cli);
1297         _num_clients--;
1298 }
1299
1300 /* Move a client to head or list */
1301
1302 void winbindd_promote_client(struct winbindd_cli_state *cli)
1303 {
1304         cli->last_access = time(NULL);
1305         DLIST_PROMOTE(_client_list, cli);
1306 }
1307
1308 /* Return number of open clients */
1309
1310 int winbindd_num_clients(void)
1311 {
1312         return _num_clients;
1313 }
1314
1315 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1316                                   const struct dom_sid *user_sid,
1317                                   uint32_t *p_num_groups, struct dom_sid **user_sids)
1318 {
1319         struct netr_SamInfo3 *info3 = NULL;
1320         NTSTATUS status = NT_STATUS_NO_MEMORY;
1321         uint32_t num_groups = 0;
1322
1323         DEBUG(3,(": lookup_usergroups_cached\n"));
1324
1325         *user_sids = NULL;
1326         *p_num_groups = 0;
1327
1328         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1329
1330         if (info3 == NULL) {
1331                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1332         }
1333
1334         /*
1335          * Before bug #7843 the "Domain Local" groups were added with a
1336          * lookupuseraliases call, but this isn't done anymore for our domain
1337          * so we need to resolve resource groups here.
1338          *
1339          * When to use Resource Groups:
1340          * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1341          */
1342         status = sid_array_from_info3(mem_ctx, info3,
1343                                       user_sids,
1344                                       &num_groups,
1345                                       false);
1346
1347         if (!NT_STATUS_IS_OK(status)) {
1348                 TALLOC_FREE(info3);
1349                 return status;
1350         }
1351
1352         TALLOC_FREE(info3);
1353         *p_num_groups = num_groups;
1354         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1355
1356         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1357
1358         return status;
1359 }
1360
1361 /*********************************************************************
1362  We use this to remove spaces from user and group names
1363 ********************************************************************/
1364
1365 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1366                              const char *domain_name,
1367                              const char *name,
1368                              char **normalized)
1369 {
1370         struct winbindd_domain *domain = NULL;
1371         NTSTATUS nt_status;
1372
1373         if (!name || !normalized) {
1374                 return NT_STATUS_INVALID_PARAMETER;
1375         }
1376
1377         if (!lp_winbind_normalize_names()) {
1378                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1379         }
1380
1381         domain = find_domain_from_name_noinit(domain_name);
1382         if (domain == NULL) {
1383                 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1384                 return NT_STATUS_NO_SUCH_DOMAIN;
1385         }
1386
1387         /* Alias support and whitespace replacement are mutually
1388            exclusive */
1389
1390         nt_status = resolve_username_to_alias(mem_ctx, domain,
1391                                               name, normalized );
1392         if (NT_STATUS_IS_OK(nt_status)) {
1393                 /* special return code to let the caller know we
1394                    mapped to an alias */
1395                 return NT_STATUS_FILE_RENAMED;
1396         }
1397
1398         /* check for an unreachable domain */
1399
1400         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1401                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1402                          domain->name));
1403                 set_domain_offline(domain);
1404                 return nt_status;
1405         }
1406
1407         /* deal with whitespace */
1408
1409         *normalized = talloc_strdup(mem_ctx, name);
1410         if (!(*normalized)) {
1411                 return NT_STATUS_NO_MEMORY;
1412         }
1413
1414         all_string_sub( *normalized, " ", "_", 0 );
1415
1416         return NT_STATUS_OK;
1417 }
1418
1419 /*********************************************************************
1420  We use this to do the inverse of normalize_name_map()
1421 ********************************************************************/
1422
1423 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1424                               char *name,
1425                               char **normalized)
1426 {
1427         NTSTATUS nt_status;
1428         struct winbindd_domain *domain = find_our_domain();
1429
1430         if (!name || !normalized) {
1431                 return NT_STATUS_INVALID_PARAMETER;
1432         }
1433
1434         if (!lp_winbind_normalize_names()) {
1435                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1436         }
1437
1438         /* Alias support and whitespace replacement are mutally
1439            exclusive */
1440
1441         /* When mapping from an alias to a username, we don't know the
1442            domain.  But we only need a domain structure to cache
1443            a successful lookup , so just our own domain structure for
1444            the seqnum. */
1445
1446         nt_status = resolve_alias_to_username(mem_ctx, domain,
1447                                               name, normalized);
1448         if (NT_STATUS_IS_OK(nt_status)) {
1449                 /* Special return code to let the caller know we mapped
1450                    from an alias */
1451                 return NT_STATUS_FILE_RENAMED;
1452         }
1453
1454         /* check for an unreachable domain */
1455
1456         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1457                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1458                          domain->name));
1459                 set_domain_offline(domain);
1460                 return nt_status;
1461         }
1462
1463         /* deal with whitespace */
1464
1465         *normalized = talloc_strdup(mem_ctx, name);
1466         if (!(*normalized)) {
1467                 return NT_STATUS_NO_MEMORY;
1468         }
1469
1470         all_string_sub(*normalized, "_", " ", 0);
1471
1472         return NT_STATUS_OK;
1473 }
1474
1475 /*********************************************************************
1476  ********************************************************************/
1477
1478 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1479 {
1480         struct winbindd_tdc_domain *tdc = NULL;
1481         TALLOC_CTX *frame = talloc_stackframe();
1482         bool ret = false;
1483
1484         /* We can contact the domain if it is our primary domain */
1485
1486         if (domain->primary) {
1487                 ret = true;
1488                 goto done;
1489         }
1490
1491         /* Trust the TDC cache and not the winbindd_domain flags */
1492
1493         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1494                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1495                           domain->name));
1496                 ret = false;
1497                 goto done;
1498         }
1499
1500         /* Can always contact a domain that is in out forest */
1501
1502         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1503                 ret = true;
1504                 goto done;
1505         }
1506
1507         /*
1508          * On a _member_ server, we cannot contact the domain if it
1509          * is running AD and we have no inbound trust.
1510          */
1511
1512         if (!IS_DC &&
1513              domain->active_directory &&
1514             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1515         {
1516                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1517                            "and we have no inbound trust.\n", domain->name));
1518                 goto done;
1519         }
1520
1521         /* Assume everything else is ok (probably not true but what
1522            can you do?) */
1523
1524         ret = true;
1525
1526 done:
1527         talloc_destroy(frame);
1528
1529         return ret;
1530 }
1531
1532 /*********************************************************************
1533  ********************************************************************/
1534
1535 bool winbindd_internal_child(struct winbindd_child *child)
1536 {
1537         if ((child == idmap_child()) || (child == locator_child())) {
1538                 return True;
1539         }
1540
1541         return False;
1542 }
1543
1544 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1545
1546 /*********************************************************************
1547  ********************************************************************/
1548
1549 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1550 {
1551         char *var = NULL;
1552         char addr[INET6_ADDRSTRLEN];
1553         const char *kdc = NULL;
1554         int lvl = 11;
1555
1556         if (!domain || !domain->alt_name || !*domain->alt_name) {
1557                 return;
1558         }
1559
1560         if (domain->initialized && !domain->active_directory) {
1561                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1562                         domain->alt_name));
1563                 return;
1564         }
1565
1566         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1567         kdc = addr;
1568         if (!*kdc) {
1569                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1570                         domain->alt_name));
1571                 kdc = domain->dcname;
1572         }
1573
1574         if (!kdc || !*kdc) {
1575                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1576                         domain->alt_name));
1577                 return;
1578         }
1579
1580         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1581                                 domain->alt_name) == -1) {
1582                 return;
1583         }
1584
1585         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1586                 var, kdc));
1587
1588         setenv(var, kdc, 1);
1589         free(var);
1590 }
1591
1592 /*********************************************************************
1593  ********************************************************************/
1594
1595 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1596 {
1597         struct winbindd_domain *our_dom = find_our_domain();
1598
1599         winbindd_set_locator_kdc_env(domain);
1600
1601         if (domain != our_dom) {
1602                 winbindd_set_locator_kdc_env(our_dom);
1603         }
1604 }
1605
1606 /*********************************************************************
1607  ********************************************************************/
1608
1609 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1610 {
1611         char *var = NULL;
1612
1613         if (!domain || !domain->alt_name || !*domain->alt_name) {
1614                 return;
1615         }
1616
1617         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1618                                 domain->alt_name) == -1) {
1619                 return;
1620         }
1621
1622         unsetenv(var);
1623         free(var);
1624 }
1625 #else
1626
1627 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1628 {
1629         return;
1630 }
1631
1632 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1633 {
1634         return;
1635 }
1636
1637 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1638
1639 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1640 {
1641         resp->data.auth.nt_status = NT_STATUS_V(result);
1642         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1643
1644         /* we might have given a more useful error above */
1645         if (*resp->data.auth.error_string == '\0')
1646                 fstrcpy(resp->data.auth.error_string,
1647                         get_friendly_nt_error_msg(result));
1648         resp->data.auth.pam_error = nt_status_to_pam(result);
1649 }
1650
1651 bool is_domain_offline(const struct winbindd_domain *domain)
1652 {
1653         if (get_global_winbindd_state_offline()) {
1654                 return true;
1655         }
1656         return !domain->online;
1657 }
1658
1659 bool is_domain_online(const struct winbindd_domain *domain)
1660 {
1661         return !is_domain_offline(domain);
1662 }
1663
1664 /**
1665  * Parse an char array into a list of sids.
1666  *
1667  * The input sidstr should consist of 0-terminated strings
1668  * representing sids, separated by newline characters '\n'.
1669  * The list is terminated by an empty string, i.e.
1670  * character '\0' directly following a character '\n'
1671  * (or '\0' right at the start of sidstr).
1672  */
1673 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1674                    struct dom_sid **sids, uint32_t *num_sids)
1675 {
1676         const char *p;
1677
1678         p = sidstr;
1679         if (p == NULL)
1680                 return False;
1681
1682         while (p[0] != '\0') {
1683                 struct dom_sid sid;
1684                 const char *q = NULL;
1685
1686                 if (!dom_sid_parse_endp(p, &sid, &q)) {
1687                         DEBUG(1, ("Could not parse sid %s\n", p));
1688                         return false;
1689                 }
1690                 if (q[0] != '\n') {
1691                         DEBUG(1, ("Got invalid sidstr: %s\n", p));
1692                         return false;
1693                 }
1694                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1695                                                       num_sids)))
1696                 {
1697                         return False;
1698                 }
1699                 p = q+1;
1700         }
1701         return True;
1702 }
1703
1704 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1705                    struct unixid **pxids, uint32_t *pnum_xids)
1706 {
1707         const char *p;
1708         struct unixid *xids = NULL;
1709         uint32_t num_xids = 0;
1710
1711         p = xidstr;
1712         if (p == NULL) {
1713                 return false;
1714         }
1715
1716         while (p[0] != '\0') {
1717                 struct unixid *tmp;
1718                 struct unixid xid;
1719                 unsigned long long id;
1720                 char *endp;
1721
1722                 switch (p[0]) {
1723                 case 'U':
1724                         xid = (struct unixid) { .type = ID_TYPE_UID };
1725                         break;
1726                 case 'G':
1727                         xid = (struct unixid) { .type = ID_TYPE_GID };
1728                         break;
1729                 default:
1730                         return false;
1731                 }
1732
1733                 p += 1;
1734
1735                 id = strtoull(p, &endp, 10);
1736                 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1737                         goto fail;
1738                 }
1739                 if (*endp != '\n') {
1740                         goto fail;
1741                 }
1742                 p = endp+1;
1743
1744                 xid.id = id;
1745                 if ((unsigned long long)xid.id != id) {
1746                         goto fail;
1747                 }
1748
1749                 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1750                 if (tmp == NULL) {
1751                         return 0;
1752                 }
1753                 xids = tmp;
1754
1755                 xids[num_xids] = xid;
1756                 num_xids += 1;
1757         }
1758
1759         *pxids = xids;
1760         *pnum_xids = num_xids;
1761         return true;
1762
1763 fail:
1764         TALLOC_FREE(xids);
1765         return false;
1766 }