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