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