winbindd: Remove now unused domain->methods
[amitay/samba.git] / source3 / winbindd / winbindd_util.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon for ntdom nss module
5
6    Copyright (C) Tim Potter 2000-2001
7    Copyright (C) 2001 by Martin Pool <mbp@samba.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25 #include "secrets.h"
26 #include "../libcli/security/security.h"
27 #include "../libcli/auth/pam_errors.h"
28 #include "passdb/machine_sid.h"
29 #include "passdb.h"
30 #include "source4/lib/messaging/messaging.h"
31 #include "librpc/gen_ndr/ndr_lsa.h"
32 #include "auth/credentials/credentials.h"
33
34 #undef DBGC_CLASS
35 #define DBGC_CLASS DBGC_WINBIND
36
37 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->backend = NULL;
242         domain->internal = is_internal_domain(sid);
243         domain->sequence_number = DOM_SEQUENCE_NONE;
244         domain->last_seq_check = 0;
245         domain->initialized = false;
246         domain->online = is_internal_domain(sid);
247         domain->check_online_timeout = 0;
248         domain->dc_probe_pid = (pid_t)-1;
249         if (sid != NULL) {
250                 sid_copy(&domain->sid, sid);
251         }
252         domain->domain_flags = tdc->trust_flags;
253         domain->domain_type = tdc->trust_type;
254         domain->domain_trust_attribs = tdc->trust_attribs;
255
256         /* Is this our primary domain ? */
257         if (strequal(domain_name, get_global_sam_name()) &&
258                         (role != ROLE_DOMAIN_MEMBER)) {
259                 domain->primary = true;
260         } else if (strequal(domain_name, lp_workgroup()) &&
261                         (role == ROLE_DOMAIN_MEMBER)) {
262                 domain->primary = true;
263         }
264
265         if (domain->primary) {
266                 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
267                         domain->active_directory = true;
268                 }
269                 if (lp_security() == SEC_ADS) {
270                         domain->active_directory = true;
271                 }
272         } else if (!domain->internal) {
273                 if (domain->domain_type == LSA_TRUST_TYPE_UPLEVEL) {
274                         domain->active_directory = true;
275                 }
276         }
277
278         /* Link to domain list */
279         DLIST_ADD_END(_domain_list, domain);
280
281         wcache_tdc_add_domain( domain );
282
283         setup_domain_child(domain);
284
285         DEBUG(2,
286               ("Added domain %s %s %s\n", domain->name, domain->alt_name,
287                !is_null_sid(&domain->sid) ? sid_string_dbg(&domain->sid) : ""));
288
289         return domain;
290 }
291
292 bool domain_is_forest_root(const struct winbindd_domain *domain)
293 {
294         const uint32_t fr_flags =
295                 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
296
297         return ((domain->domain_flags & fr_flags) == fr_flags);
298 }
299
300 /********************************************************************
301   rescan our domains looking for new trusted domains
302 ********************************************************************/
303
304 struct trustdom_state {
305         struct winbindd_domain *domain;
306         struct winbindd_request request;
307 };
308
309 static void trustdom_list_done(struct tevent_req *req);
310 static void rescan_forest_root_trusts( void );
311 static void rescan_forest_trusts( void );
312
313 static void add_trusted_domains( struct winbindd_domain *domain )
314 {
315         struct trustdom_state *state;
316         struct tevent_req *req;
317
318         state = talloc_zero(NULL, struct trustdom_state);
319         if (state == NULL) {
320                 DEBUG(0, ("talloc failed\n"));
321                 return;
322         }
323         state->domain = domain;
324
325         state->request.length = sizeof(state->request);
326         state->request.cmd = WINBINDD_LIST_TRUSTDOM;
327
328         req = wb_domain_request_send(state, winbind_event_context(),
329                                      domain, &state->request);
330         if (req == NULL) {
331                 DEBUG(1, ("wb_domain_request_send failed\n"));
332                 TALLOC_FREE(state);
333                 return;
334         }
335         tevent_req_set_callback(req, trustdom_list_done, state);
336 }
337
338 static void trustdom_list_done(struct tevent_req *req)
339 {
340         struct trustdom_state *state = tevent_req_callback_data(
341                 req, struct trustdom_state);
342         struct winbindd_response *response;
343         int res, err;
344         char *p;
345         struct winbindd_tdc_domain trust_params = {0};
346         ptrdiff_t extra_len;
347
348         res = wb_domain_request_recv(req, state, &response, &err);
349         if ((res == -1) || (response->result != WINBINDD_OK)) {
350                 DBG_WARNING("Could not receive trusts for domain %s\n",
351                             state->domain->name);
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                 p = strchr(domuser, '@');
1106
1107                 if ( assume_domain(lp_workgroup()) && p == NULL) {
1108                         fstrcpy(domain, lp_workgroup());
1109                 } else if (p != 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 }