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