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