winbindd: simplify if condition in find_domain_from_name_noinit()
[amitay/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                         return domain;
941                 }
942                 if (domain->alt_name == NULL) {
943                         continue;
944                 }
945                 if (strequal(domain_name, domain->alt_name)) {
946                         return domain;
947                 }
948         }
949
950         /* Not found */
951
952         return NULL;
953 }
954
955 struct winbindd_domain *find_domain_from_name(const char *domain_name)
956 {
957         struct winbindd_domain *domain;
958
959         domain = find_domain_from_name_noinit(domain_name);
960
961         if (domain == NULL)
962                 return NULL;
963
964         if (!domain->initialized)
965                 init_dc_connection(domain, false);
966
967         return domain;
968 }
969
970 /* Given a domain sid, return the struct winbindd domain info for it */
971
972 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
973 {
974         struct winbindd_domain *domain;
975
976         /* Search through list */
977
978         for (domain = domain_list(); domain != NULL; domain = domain->next) {
979                 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
980                         return domain;
981         }
982
983         /* Not found */
984
985         return NULL;
986 }
987
988 /* Given a domain sid, return the struct winbindd domain info for it */
989
990 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
991 {
992         struct winbindd_domain *domain;
993
994         domain = find_domain_from_sid_noinit(sid);
995
996         if (domain == NULL)
997                 return NULL;
998
999         if (!domain->initialized)
1000                 init_dc_connection(domain, false);
1001
1002         return domain;
1003 }
1004
1005 struct winbindd_domain *find_our_domain(void)
1006 {
1007         struct winbindd_domain *domain;
1008
1009         /* Search through list */
1010
1011         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1012                 if (domain->primary)
1013                         return domain;
1014         }
1015
1016         smb_panic("Could not find our domain");
1017         return NULL;
1018 }
1019
1020 /* Find the appropriate domain to lookup a name or SID */
1021
1022 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1023 {
1024         DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1025
1026         /*
1027          * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1028          * by our passdb.
1029          */
1030
1031         if ( sid_check_is_in_unix_groups(sid) ||
1032              sid_check_is_unix_groups(sid) ||
1033              sid_check_is_in_unix_users(sid) ||
1034              sid_check_is_unix_users(sid) ||
1035              sid_check_is_wellknown_domain(sid, NULL) ||
1036              sid_check_is_in_wellknown_domain(sid) )
1037         {
1038                 return find_domain_from_sid(get_global_sam_sid());
1039         }
1040
1041         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
1042          * one to contact the external DC's. On member servers the internal
1043          * domains are different: These are part of the local SAM. */
1044
1045         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
1046                 DEBUG(10, ("calling find_domain_from_sid\n"));
1047                 return find_domain_from_sid(sid);
1048         }
1049
1050         /* On a member server a query for SID or name can always go to our
1051          * primary DC. */
1052
1053         DEBUG(10, ("calling find_our_domain\n"));
1054         return find_our_domain();
1055 }
1056
1057 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1058 {
1059         if ( strequal(domain_name, unix_users_domain_name() ) ||
1060              strequal(domain_name, unix_groups_domain_name() ) )
1061         {
1062                 /*
1063                  * The "Unix User" and "Unix Group" domain our handled by
1064                  * passdb
1065                  */
1066                 return find_domain_from_name_noinit( get_global_sam_name() );
1067         }
1068
1069         if (IS_DC || strequal(domain_name, "BUILTIN") ||
1070             strequal(domain_name, get_global_sam_name()))
1071                 return find_domain_from_name_noinit(domain_name);
1072
1073
1074         return find_our_domain();
1075 }
1076
1077 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1078
1079 static bool assume_domain(const char *domain)
1080 {
1081         /* never assume the domain on a standalone server */
1082
1083         if ( lp_server_role() == ROLE_STANDALONE )
1084                 return False;
1085
1086         /* domain member servers may possibly assume for the domain name */
1087
1088         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1089                 if ( !strequal(lp_workgroup(), domain) )
1090                         return False;
1091
1092                 if ( lp_winbind_use_default_domain() )
1093                         return True;
1094         }
1095
1096         /* only left with a domain controller */
1097
1098         if ( strequal(get_global_sam_name(), domain) )  {
1099                 return True;
1100         }
1101
1102         return False;
1103 }
1104
1105 /* Parse a string of the form DOMAIN\user into a domain and a user */
1106
1107 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1108 {
1109         char *p = strchr(domuser,*lp_winbind_separator());
1110
1111         if ( !p ) {
1112                 fstrcpy(user, domuser);
1113                 p = strchr(domuser, '@');
1114
1115                 if ( assume_domain(lp_workgroup()) && p == NULL) {
1116                         fstrcpy(domain, lp_workgroup());
1117                 } else if (p != NULL) {
1118                         fstrcpy(domain, p + 1);
1119                         user[PTR_DIFF(p, domuser)] = 0;
1120                 } else {
1121                         return False;
1122                 }
1123         } else {
1124                 fstrcpy(user, p+1);
1125                 fstrcpy(domain, domuser);
1126                 domain[PTR_DIFF(p, domuser)] = 0;
1127         }
1128
1129         return strupper_m(domain);
1130 }
1131
1132 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1133                               char **domain, char **user)
1134 {
1135         fstring fstr_domain, fstr_user;
1136         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1137                 return False;
1138         }
1139         *domain = talloc_strdup(mem_ctx, fstr_domain);
1140         *user = talloc_strdup(mem_ctx, fstr_user);
1141         return ((*domain != NULL) && (*user != NULL));
1142 }
1143
1144 /* Ensure an incoming username from NSS is fully qualified. Replace the
1145    incoming fstring with DOMAIN <separator> user. Returns the same
1146    values as parse_domain_user() but also replaces the incoming username.
1147    Used to ensure all names are fully qualified within winbindd.
1148    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1149    The protocol definitions of auth_crap, chng_pswd_auth_crap
1150    really should be changed to use this instead of doing things
1151    by hand. JRA. */
1152
1153 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1154 {
1155         if (!parse_domain_user(username_inout, domain, user)) {
1156                 return False;
1157         }
1158         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1159                  domain, *lp_winbind_separator(),
1160                  user);
1161         return True;
1162 }
1163
1164 /*
1165     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1166     'winbind separator' options.
1167     This means:
1168         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1169         lp_workgroup()
1170
1171     If we are a PDC or BDC, and this is for our domain, do likewise.
1172
1173     On an AD DC we always fill DOMAIN\\USERNAME.
1174
1175     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1176 */
1177 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1178 {
1179         fstring tmp_user;
1180
1181         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1182                 can_assume = false;
1183         }
1184
1185         fstrcpy(tmp_user, user);
1186         (void)strlower_m(tmp_user);
1187
1188         if (can_assume && assume_domain(domain)) {
1189                 strlcpy(name, tmp_user, sizeof(fstring));
1190         } else {
1191                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1192                          domain, *lp_winbind_separator(),
1193                          tmp_user);
1194         }
1195 }
1196
1197 /**
1198  * talloc version of fill_domain_username()
1199  * return NULL on talloc failure.
1200  */
1201 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1202                                   const char *domain,
1203                                   const char *user,
1204                                   bool can_assume)
1205 {
1206         char *tmp_user, *name;
1207
1208         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1209                 can_assume = false;
1210         }
1211
1212         tmp_user = talloc_strdup(mem_ctx, user);
1213         if (!strlower_m(tmp_user)) {
1214                 TALLOC_FREE(tmp_user);
1215                 return NULL;
1216         }
1217
1218         if (can_assume && assume_domain(domain)) {
1219                 name = tmp_user;
1220         } else {
1221                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1222                                        domain,
1223                                        *lp_winbind_separator(),
1224                                        tmp_user);
1225                 TALLOC_FREE(tmp_user);
1226         }
1227
1228         return name;
1229 }
1230
1231 /*
1232  * Client list accessor functions
1233  */
1234
1235 static struct winbindd_cli_state *_client_list;
1236 static int _num_clients;
1237
1238 /* Return list of all connected clients */
1239
1240 struct winbindd_cli_state *winbindd_client_list(void)
1241 {
1242         return _client_list;
1243 }
1244
1245 /* Return list-tail of all connected clients */
1246
1247 struct winbindd_cli_state *winbindd_client_list_tail(void)
1248 {
1249         return DLIST_TAIL(_client_list);
1250 }
1251
1252 /* Return previous (read:newer) client in list */
1253
1254 struct winbindd_cli_state *
1255 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1256 {
1257         return DLIST_PREV(cli);
1258 }
1259
1260 /* Add a connection to the list */
1261
1262 void winbindd_add_client(struct winbindd_cli_state *cli)
1263 {
1264         cli->last_access = time(NULL);
1265         DLIST_ADD(_client_list, cli);
1266         _num_clients++;
1267 }
1268
1269 /* Remove a client from the list */
1270
1271 void winbindd_remove_client(struct winbindd_cli_state *cli)
1272 {
1273         DLIST_REMOVE(_client_list, cli);
1274         _num_clients--;
1275 }
1276
1277 /* Move a client to head or list */
1278
1279 void winbindd_promote_client(struct winbindd_cli_state *cli)
1280 {
1281         cli->last_access = time(NULL);
1282         DLIST_PROMOTE(_client_list, cli);
1283 }
1284
1285 /* Return number of open clients */
1286
1287 int winbindd_num_clients(void)
1288 {
1289         return _num_clients;
1290 }
1291
1292 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1293                                   const struct dom_sid *user_sid,
1294                                   uint32_t *p_num_groups, struct dom_sid **user_sids)
1295 {
1296         struct netr_SamInfo3 *info3 = NULL;
1297         NTSTATUS status = NT_STATUS_NO_MEMORY;
1298         uint32_t num_groups = 0;
1299
1300         DEBUG(3,(": lookup_usergroups_cached\n"));
1301
1302         *user_sids = NULL;
1303         *p_num_groups = 0;
1304
1305         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1306
1307         if (info3 == NULL) {
1308                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1309         }
1310
1311         /*
1312          * Before bug #7843 the "Domain Local" groups were added with a
1313          * lookupuseraliases call, but this isn't done anymore for our domain
1314          * so we need to resolve resource groups here.
1315          *
1316          * When to use Resource Groups:
1317          * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1318          */
1319         status = sid_array_from_info3(mem_ctx, info3,
1320                                       user_sids,
1321                                       &num_groups,
1322                                       false);
1323
1324         if (!NT_STATUS_IS_OK(status)) {
1325                 TALLOC_FREE(info3);
1326                 return status;
1327         }
1328
1329         TALLOC_FREE(info3);
1330         *p_num_groups = num_groups;
1331         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1332
1333         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1334
1335         return status;
1336 }
1337
1338 /*********************************************************************
1339  We use this to remove spaces from user and group names
1340 ********************************************************************/
1341
1342 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1343                              const char *domain_name,
1344                              const char *name,
1345                              char **normalized)
1346 {
1347         struct winbindd_domain *domain = NULL;
1348         NTSTATUS nt_status;
1349
1350         if (!name || !normalized) {
1351                 return NT_STATUS_INVALID_PARAMETER;
1352         }
1353
1354         if (!lp_winbind_normalize_names()) {
1355                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1356         }
1357
1358         domain = find_domain_from_name_noinit(domain_name);
1359         if (domain == NULL) {
1360                 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1361                 return NT_STATUS_NO_SUCH_DOMAIN;
1362         }
1363
1364         /* Alias support and whitespace replacement are mutually
1365            exclusive */
1366
1367         nt_status = resolve_username_to_alias(mem_ctx, domain,
1368                                               name, normalized );
1369         if (NT_STATUS_IS_OK(nt_status)) {
1370                 /* special return code to let the caller know we
1371                    mapped to an alias */
1372                 return NT_STATUS_FILE_RENAMED;
1373         }
1374
1375         /* check for an unreachable domain */
1376
1377         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1378                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1379                          domain->name));
1380                 set_domain_offline(domain);
1381                 return nt_status;
1382         }
1383
1384         /* deal with whitespace */
1385
1386         *normalized = talloc_strdup(mem_ctx, name);
1387         if (!(*normalized)) {
1388                 return NT_STATUS_NO_MEMORY;
1389         }
1390
1391         all_string_sub( *normalized, " ", "_", 0 );
1392
1393         return NT_STATUS_OK;
1394 }
1395
1396 /*********************************************************************
1397  We use this to do the inverse of normalize_name_map()
1398 ********************************************************************/
1399
1400 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1401                               char *name,
1402                               char **normalized)
1403 {
1404         NTSTATUS nt_status;
1405         struct winbindd_domain *domain = find_our_domain();
1406
1407         if (!name || !normalized) {
1408                 return NT_STATUS_INVALID_PARAMETER;
1409         }
1410
1411         if (!lp_winbind_normalize_names()) {
1412                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1413         }
1414
1415         /* Alias support and whitespace replacement are mutally
1416            exclusive */
1417
1418         /* When mapping from an alias to a username, we don't know the
1419            domain.  But we only need a domain structure to cache
1420            a successful lookup , so just our own domain structure for
1421            the seqnum. */
1422
1423         nt_status = resolve_alias_to_username(mem_ctx, domain,
1424                                               name, normalized);
1425         if (NT_STATUS_IS_OK(nt_status)) {
1426                 /* Special return code to let the caller know we mapped
1427                    from an alias */
1428                 return NT_STATUS_FILE_RENAMED;
1429         }
1430
1431         /* check for an unreachable domain */
1432
1433         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1434                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1435                          domain->name));
1436                 set_domain_offline(domain);
1437                 return nt_status;
1438         }
1439
1440         /* deal with whitespace */
1441
1442         *normalized = talloc_strdup(mem_ctx, name);
1443         if (!(*normalized)) {
1444                 return NT_STATUS_NO_MEMORY;
1445         }
1446
1447         all_string_sub(*normalized, "_", " ", 0);
1448
1449         return NT_STATUS_OK;
1450 }
1451
1452 /*********************************************************************
1453  ********************************************************************/
1454
1455 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1456 {
1457         struct winbindd_tdc_domain *tdc = NULL;
1458         TALLOC_CTX *frame = talloc_stackframe();
1459         bool ret = false;
1460
1461         /* We can contact the domain if it is our primary domain */
1462
1463         if (domain->primary) {
1464                 ret = true;
1465                 goto done;
1466         }
1467
1468         /* Trust the TDC cache and not the winbindd_domain flags */
1469
1470         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1471                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1472                           domain->name));
1473                 ret = false;
1474                 goto done;
1475         }
1476
1477         /* Can always contact a domain that is in out forest */
1478
1479         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1480                 ret = true;
1481                 goto done;
1482         }
1483
1484         /*
1485          * On a _member_ server, we cannot contact the domain if it
1486          * is running AD and we have no inbound trust.
1487          */
1488
1489         if (!IS_DC &&
1490              domain->active_directory &&
1491             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1492         {
1493                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1494                            "and we have no inbound trust.\n", domain->name));
1495                 goto done;
1496         }
1497
1498         /* Assume everything else is ok (probably not true but what
1499            can you do?) */
1500
1501         ret = true;
1502
1503 done:
1504         talloc_destroy(frame);
1505
1506         return ret;
1507 }
1508
1509 /*********************************************************************
1510  ********************************************************************/
1511
1512 bool winbindd_internal_child(struct winbindd_child *child)
1513 {
1514         if ((child == idmap_child()) || (child == locator_child())) {
1515                 return True;
1516         }
1517
1518         return False;
1519 }
1520
1521 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1522
1523 /*********************************************************************
1524  ********************************************************************/
1525
1526 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1527 {
1528         char *var = NULL;
1529         char addr[INET6_ADDRSTRLEN];
1530         const char *kdc = NULL;
1531         int lvl = 11;
1532
1533         if (!domain || !domain->alt_name || !*domain->alt_name) {
1534                 return;
1535         }
1536
1537         if (domain->initialized && !domain->active_directory) {
1538                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1539                         domain->alt_name));
1540                 return;
1541         }
1542
1543         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1544         kdc = addr;
1545         if (!*kdc) {
1546                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1547                         domain->alt_name));
1548                 kdc = domain->dcname;
1549         }
1550
1551         if (!kdc || !*kdc) {
1552                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1553                         domain->alt_name));
1554                 return;
1555         }
1556
1557         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1558                                 domain->alt_name) == -1) {
1559                 return;
1560         }
1561
1562         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1563                 var, kdc));
1564
1565         setenv(var, kdc, 1);
1566         free(var);
1567 }
1568
1569 /*********************************************************************
1570  ********************************************************************/
1571
1572 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1573 {
1574         struct winbindd_domain *our_dom = find_our_domain();
1575
1576         winbindd_set_locator_kdc_env(domain);
1577
1578         if (domain != our_dom) {
1579                 winbindd_set_locator_kdc_env(our_dom);
1580         }
1581 }
1582
1583 /*********************************************************************
1584  ********************************************************************/
1585
1586 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1587 {
1588         char *var = NULL;
1589
1590         if (!domain || !domain->alt_name || !*domain->alt_name) {
1591                 return;
1592         }
1593
1594         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1595                                 domain->alt_name) == -1) {
1596                 return;
1597         }
1598
1599         unsetenv(var);
1600         free(var);
1601 }
1602 #else
1603
1604 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1605 {
1606         return;
1607 }
1608
1609 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1610 {
1611         return;
1612 }
1613
1614 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1615
1616 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1617 {
1618         resp->data.auth.nt_status = NT_STATUS_V(result);
1619         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1620
1621         /* we might have given a more useful error above */
1622         if (*resp->data.auth.error_string == '\0')
1623                 fstrcpy(resp->data.auth.error_string,
1624                         get_friendly_nt_error_msg(result));
1625         resp->data.auth.pam_error = nt_status_to_pam(result);
1626 }
1627
1628 bool is_domain_offline(const struct winbindd_domain *domain)
1629 {
1630         if (get_global_winbindd_state_offline()) {
1631                 return true;
1632         }
1633         return !domain->online;
1634 }
1635
1636 bool is_domain_online(const struct winbindd_domain *domain)
1637 {
1638         return !is_domain_offline(domain);
1639 }
1640
1641 /**
1642  * Parse an char array into a list of sids.
1643  *
1644  * The input sidstr should consist of 0-terminated strings
1645  * representing sids, separated by newline characters '\n'.
1646  * The list is terminated by an empty string, i.e.
1647  * character '\0' directly following a character '\n'
1648  * (or '\0' right at the start of sidstr).
1649  */
1650 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1651                    struct dom_sid **sids, uint32_t *num_sids)
1652 {
1653         const char *p;
1654
1655         p = sidstr;
1656         if (p == NULL)
1657                 return False;
1658
1659         while (p[0] != '\0') {
1660                 struct dom_sid sid;
1661                 const char *q = NULL;
1662
1663                 if (!dom_sid_parse_endp(p, &sid, &q)) {
1664                         DEBUG(1, ("Could not parse sid %s\n", p));
1665                         return false;
1666                 }
1667                 if (q[0] != '\n') {
1668                         DEBUG(1, ("Got invalid sidstr: %s\n", p));
1669                         return false;
1670                 }
1671                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1672                                                       num_sids)))
1673                 {
1674                         return False;
1675                 }
1676                 p = q+1;
1677         }
1678         return True;
1679 }
1680
1681 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
1682                    struct unixid **pxids, uint32_t *pnum_xids)
1683 {
1684         const char *p;
1685         struct unixid *xids = NULL;
1686         uint32_t num_xids = 0;
1687
1688         p = xidstr;
1689         if (p == NULL) {
1690                 return false;
1691         }
1692
1693         while (p[0] != '\0') {
1694                 struct unixid *tmp;
1695                 struct unixid xid;
1696                 unsigned long long id;
1697                 char *endp;
1698
1699                 switch (p[0]) {
1700                 case 'U':
1701                         xid = (struct unixid) { .type = ID_TYPE_UID };
1702                         break;
1703                 case 'G':
1704                         xid = (struct unixid) { .type = ID_TYPE_GID };
1705                         break;
1706                 default:
1707                         return false;
1708                 }
1709
1710                 p += 1;
1711
1712                 id = strtoull(p, &endp, 10);
1713                 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
1714                         goto fail;
1715                 }
1716                 if (*endp != '\n') {
1717                         goto fail;
1718                 }
1719                 p = endp+1;
1720
1721                 xid.id = id;
1722                 if ((unsigned long long)xid.id != id) {
1723                         goto fail;
1724                 }
1725
1726                 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
1727                 if (tmp == NULL) {
1728                         return 0;
1729                 }
1730                 xids = tmp;
1731
1732                 xids[num_xids] = xid;
1733                 num_xids += 1;
1734         }
1735
1736         *pxids = xids;
1737         *pnum_xids = num_xids;
1738         return true;
1739
1740 fail:
1741         TALLOC_FREE(xids);
1742         return false;
1743 }