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