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