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