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