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