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