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