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