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