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