winbindd: move loading of trusted domains on a DC to a seperate function
[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 static bool add_trusted_domains_dc(void)
922 {
923         struct winbindd_domain *domain =  NULL;
924         struct pdb_trusted_domain **domains = NULL;
925         uint32_t num_domains = 0;
926         uint32_t i;
927         NTSTATUS status;
928
929         if (!(pdb_capabilities() & PDB_CAP_TRUSTED_DOMAINS_EX)) {
930                 struct trustdom_info **ti = NULL;
931
932                 status = pdb_enum_trusteddoms(talloc_tos(), &num_domains, &ti);
933                 if (!NT_STATUS_IS_OK(status)) {
934                         DBG_ERR("pdb_enum_trusteddoms() failed - %s\n",
935                                 nt_errstr(status));
936                         return false;
937                 }
938
939                 for (i = 0; i < num_domains; i++) {
940                         status = add_trusted_domain(ti[i]->name,
941                                                     NULL,
942                                                     &ti[i]->sid,
943                                                     LSA_TRUST_TYPE_DOWNLEVEL,
944                                                     NETR_TRUST_FLAG_OUTBOUND,
945                                                     0,
946                                                     SEC_CHAN_DOMAIN,
947                                                     NULL,
948                                                     &domain);
949                         if (!NT_STATUS_IS_OK(status)) {
950                                 DBG_NOTICE("add_trusted_domain returned %s\n",
951                                            nt_errstr(status));
952                                 return false;
953                         }
954
955                         /* Even in the parent winbindd we'll need to
956                            talk to the DC, so try and see if we can
957                            contact it. Theoretically this isn't neccessary
958                            as the init_dc_connection() in init_child_recv()
959                            will do this, but we can start detecting the DC
960                            early here. */
961                         set_domain_online_request(domain);
962                 }
963
964                 return true;
965         }
966
967         status = pdb_enum_trusted_domains(talloc_tos(), &num_domains, &domains);
968         if (!NT_STATUS_IS_OK(status)) {
969                 DBG_ERR("pdb_enum_trusted_domains() failed - %s\n",
970                         nt_errstr(status));
971                 return false;
972         }
973
974         for (i = 0; i < num_domains; i++) {
975                 enum netr_SchannelType sec_chan_type = SEC_CHAN_DOMAIN;
976                 uint32_t trust_flags = 0;
977
978                 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
979                         sec_chan_type = SEC_CHAN_DNS_DOMAIN;
980                 }
981
982                 if (!(domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND)) {
983                         sec_chan_type = SEC_CHAN_NULL;
984                 }
985
986                 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
987                         trust_flags |= NETR_TRUST_FLAG_INBOUND;
988                 }
989                 if (domains[i]->trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
990                         trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
991                 }
992                 if (domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
993                         trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
994                 }
995
996                 status = add_trusted_domain(domains[i]->netbios_name,
997                                             domains[i]->domain_name,
998                                             &domains[i]->security_identifier,
999                                             domains[i]->trust_type,
1000                                             trust_flags,
1001                                             domains[i]->trust_attributes,
1002                                             sec_chan_type,
1003                                             NULL,
1004                                             &domain);
1005                 if (!NT_STATUS_IS_OK(status)) {
1006                         DBG_NOTICE("add_trusted_domain returned %s\n",
1007                                    nt_errstr(status));
1008                         return false;
1009                 }
1010
1011                 if (domains[i]->trust_type == LSA_TRUST_TYPE_UPLEVEL) {
1012                         domain->active_directory = true;
1013                 }
1014                 domain->domain_type = domains[i]->trust_type;
1015                 domain->domain_trust_attribs = domains[i]->trust_attributes;
1016
1017                 if (sec_chan_type != SEC_CHAN_NULL) {
1018                         /* Even in the parent winbindd we'll need to
1019                            talk to the DC, so try and see if we can
1020                            contact it. Theoretically this isn't neccessary
1021                            as the init_dc_connection() in init_child_recv()
1022                            will do this, but we can start detecting the DC
1023                            early here. */
1024                         set_domain_online_request(domain);
1025                 }
1026         }
1027
1028         for (i = 0; i < num_domains; i++) {
1029                 struct ForestTrustInfo fti;
1030                 uint32_t fi;
1031                 enum ndr_err_code ndr_err;
1032                 struct winbindd_domain *routing_domain = NULL;
1033
1034                 if (domains[i]->trust_type != LSA_TRUST_TYPE_UPLEVEL) {
1035                         continue;
1036                 }
1037
1038                 if (!(domains[i]->trust_attributes & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)) {
1039                         continue;
1040                 }
1041
1042                 if (domains[i]->trust_forest_trust_info.length == 0) {
1043                         continue;
1044                 }
1045
1046                 routing_domain = find_domain_from_name_noinit(
1047                         domains[i]->netbios_name);
1048                 if (routing_domain == NULL) {
1049                         DBG_ERR("Can't find winbindd domain [%s]\n",
1050                                 domains[i]->netbios_name);
1051                         return false;
1052                 }
1053
1054                 ndr_err = ndr_pull_struct_blob_all(
1055                         &domains[i]->trust_forest_trust_info,
1056                         talloc_tos(), &fti,
1057                         (ndr_pull_flags_fn_t)ndr_pull_ForestTrustInfo);
1058                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1059                         DBG_ERR("ndr_pull_ForestTrustInfo(%s) - %s\n",
1060                                 domains[i]->netbios_name,
1061                                 ndr_map_error2string(ndr_err));
1062                         return false;
1063                 }
1064
1065                 for (fi = 0; fi < fti.count; fi++) {
1066                         struct ForestTrustInfoRecord *rec =
1067                                 &fti.records[fi].record;
1068                         struct ForestTrustDataDomainInfo *drec = NULL;
1069
1070                         if (rec->type != FOREST_TRUST_DOMAIN_INFO) {
1071                                 continue;
1072                         }
1073                         drec = &rec->data.info;
1074
1075                         if (rec->flags & LSA_NB_DISABLED_MASK) {
1076                                 continue;
1077                         }
1078
1079                         if (rec->flags & LSA_SID_DISABLED_MASK) {
1080                                 continue;
1081                         }
1082
1083                         /*
1084                          * TODO:
1085                          * also try to find a matching
1086                          * LSA_TLN_DISABLED_MASK ???
1087                          */
1088
1089                         domain = find_domain_from_name_noinit(drec->netbios_name.string);
1090                         if (domain != NULL) {
1091                                 continue;
1092                         }
1093
1094                         status = add_trusted_domain(drec->netbios_name.string,
1095                                                     drec->dns_name.string,
1096                                                     &drec->sid,
1097                                                     LSA_TRUST_TYPE_UPLEVEL,
1098                                                     NETR_TRUST_FLAG_OUTBOUND,
1099                                                     0,
1100                                                     SEC_CHAN_NULL,
1101                                                     routing_domain,
1102                                                     &domain);
1103                         if (!NT_STATUS_IS_OK(status)) {
1104                                 DBG_NOTICE("add_trusted_domain returned %s\n",
1105                                            nt_errstr(status));
1106                                 return false;
1107                         }
1108                         if (domain == NULL) {
1109                                 continue;
1110                         }
1111                 }
1112         }
1113
1114         return true;
1115 }
1116
1117
1118 /* Look up global info for the winbind daemon */
1119 bool init_domain_list(void)
1120 {
1121         int role = lp_server_role();
1122         struct pdb_domain_info *pdb_domain_info = NULL;
1123         struct winbindd_domain *domain =  NULL;
1124         NTSTATUS status;
1125         bool ok;
1126
1127         /* Free existing list */
1128         free_domain_list();
1129
1130         /* BUILTIN domain */
1131
1132         status = add_trusted_domain("BUILTIN",
1133                                     NULL,
1134                                     &global_sid_Builtin,
1135                                     LSA_TRUST_TYPE_DOWNLEVEL,
1136                                     0, /* trust_flags */
1137                                     0, /* trust_attribs */
1138                                     SEC_CHAN_LOCAL,
1139                                     NULL,
1140                                     &domain);
1141         if (!NT_STATUS_IS_OK(status)) {
1142                 DBG_ERR("add_trusted_domain BUILTIN returned %s\n",
1143                         nt_errstr(status));
1144                 return false;
1145         }
1146
1147         /* Local SAM */
1148
1149         /*
1150          * In case the passdb backend is passdb_dsdb the domain SID comes from
1151          * dsdb, not from secrets.tdb. As we use the domain SID in various
1152          * places, we must ensure the domain SID is migrated from dsdb to
1153          * secrets.tdb before get_global_sam_sid() is called the first time.
1154          *
1155          * The migration is done as part of the passdb_dsdb initialisation,
1156          * calling pdb_get_domain_info() triggers it.
1157          */
1158         pdb_domain_info = pdb_get_domain_info(talloc_tos());
1159
1160         if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
1161                 uint32_t trust_flags;
1162                 bool is_root;
1163                 enum netr_SchannelType sec_chan_type;
1164                 const char *account_name;
1165                 struct samr_Password current_nt_hash;
1166
1167                 if (pdb_domain_info == NULL) {
1168                         DEBUG(0, ("Failed to fetch our own, local AD "
1169                                 "domain info from sam.ldb\n"));
1170                         return false;
1171                 }
1172
1173                 trust_flags = NETR_TRUST_FLAG_PRIMARY;
1174                 trust_flags |= NETR_TRUST_FLAG_IN_FOREST;
1175                 trust_flags |= NETR_TRUST_FLAG_NATIVE;
1176                 trust_flags |= NETR_TRUST_FLAG_OUTBOUND;
1177
1178                 is_root = strequal(pdb_domain_info->dns_domain,
1179                                    pdb_domain_info->dns_forest);
1180                 if (is_root) {
1181                         trust_flags |= NETR_TRUST_FLAG_TREEROOT;
1182                 }
1183
1184                 status = add_trusted_domain(pdb_domain_info->name,
1185                                             pdb_domain_info->dns_domain,
1186                                             &pdb_domain_info->sid,
1187                                             LSA_TRUST_TYPE_UPLEVEL,
1188                                             trust_flags,
1189                                             LSA_TRUST_ATTRIBUTE_WITHIN_FOREST,
1190                                             SEC_CHAN_BDC,
1191                                             NULL,
1192                                             &domain);
1193                 TALLOC_FREE(pdb_domain_info);
1194                 if (!NT_STATUS_IS_OK(status)) {
1195                         DBG_ERR("Failed to add our own, local AD "
1196                                 "domain to winbindd's internal list\n");
1197                         return false;
1198                 }
1199
1200                 /*
1201                  * We need to call this to find out if we are an RODC
1202                  */
1203                 ok = get_trust_pw_hash(domain->name,
1204                                        current_nt_hash.hash,
1205                                        &account_name,
1206                                        &sec_chan_type);
1207                 if (!ok) {
1208                         /*
1209                          * If get_trust_pw_hash() fails, then try and
1210                          * fetch the password from the more recent of
1211                          * secrets.{ldb,tdb} using the
1212                          * pdb_get_trust_credentials()
1213                          */
1214                         ok = migrate_secrets_tdb_to_ldb(domain);
1215
1216                         if (!ok) {
1217                                 DEBUG(0, ("Failed to migrate our own, "
1218                                           "local AD domain join password for "
1219                                           "winbindd's internal use into "
1220                                           "secrets.tdb\n"));
1221                                 return false;
1222                         }
1223                         ok = get_trust_pw_hash(domain->name,
1224                                                current_nt_hash.hash,
1225                                                &account_name,
1226                                                &sec_chan_type);
1227                         if (!ok) {
1228                                 DEBUG(0, ("Failed to find our our own, just "
1229                                           "written local AD domain join "
1230                                           "password for winbindd's internal "
1231                                           "use in secrets.tdb\n"));
1232                                 return false;
1233                         }
1234                 }
1235
1236                 domain->secure_channel_type = sec_chan_type;
1237                 if (sec_chan_type == SEC_CHAN_RODC) {
1238                         domain->rodc = true;
1239                 }
1240
1241         } else {
1242                 uint32_t trust_flags;
1243                 enum netr_SchannelType secure_channel_type;
1244
1245                 trust_flags = NETR_TRUST_FLAG_OUTBOUND;
1246                 if (role != ROLE_DOMAIN_MEMBER) {
1247                         trust_flags |= NETR_TRUST_FLAG_PRIMARY;
1248                 }
1249
1250                 if (role > ROLE_DOMAIN_MEMBER) {
1251                         secure_channel_type = SEC_CHAN_BDC;
1252                 } else {
1253                         secure_channel_type = SEC_CHAN_LOCAL;
1254                 }
1255
1256                 status = add_trusted_domain(get_global_sam_name(),
1257                                             NULL,
1258                                             get_global_sam_sid(),
1259                                             LSA_TRUST_TYPE_DOWNLEVEL,
1260                                             trust_flags,
1261                                             0, /* trust_attribs */
1262                                             secure_channel_type,
1263                                             NULL,
1264                                             &domain);
1265                 if (!NT_STATUS_IS_OK(status)) {
1266                         DBG_ERR("Failed to add local SAM to "
1267                                 "domain to winbindd's internal list\n");
1268                         return false;
1269                 }
1270         }
1271
1272         if (IS_DC) {
1273                 ok = add_trusted_domains_dc();
1274                 if (!ok) {
1275                         DBG_ERR("init_domain_list_dc failed\n");
1276                         return false;
1277                 }
1278         }
1279
1280         if ( role == ROLE_DOMAIN_MEMBER ) {
1281                 struct dom_sid our_sid;
1282                 uint32_t trust_type;
1283
1284                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
1285                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
1286                         return False;
1287                 }
1288
1289                 if (lp_realm() != NULL) {
1290                         trust_type = LSA_TRUST_TYPE_UPLEVEL;
1291                 } else {
1292                         trust_type = LSA_TRUST_TYPE_DOWNLEVEL;
1293                 }
1294
1295                 status = add_trusted_domain(lp_workgroup(),
1296                                             lp_realm(),
1297                                             &our_sid,
1298                                             trust_type,
1299                                             NETR_TRUST_FLAG_PRIMARY|
1300                                             NETR_TRUST_FLAG_OUTBOUND,
1301                                             0, /* trust_attribs */
1302                                             SEC_CHAN_WKSTA,
1303                                             NULL,
1304                                             &domain);
1305                 if (!NT_STATUS_IS_OK(status)) {
1306                         DBG_ERR("Failed to add local SAM to "
1307                                 "domain to winbindd's internal list\n");
1308                         return false;
1309                 }
1310                 /* Even in the parent winbindd we'll need to
1311                    talk to the DC, so try and see if we can
1312                    contact it. Theoretically this isn't neccessary
1313                    as the init_dc_connection() in init_child_recv()
1314                    will do this, but we can start detecting the DC
1315                    early here. */
1316                 set_domain_online_request(domain);
1317
1318         }
1319
1320         status = imessaging_register(winbind_imessaging_context(), NULL,
1321                                      MSG_WINBIND_NEW_TRUSTED_DOMAIN,
1322                                      wb_imsg_new_trusted_domain);
1323         if (!NT_STATUS_IS_OK(status)) {
1324                 DBG_ERR("imessaging_register failed %s\n", nt_errstr(status));
1325                 return false;
1326         }
1327
1328         return True;
1329 }
1330
1331 /**
1332  * Given a domain name, return the struct winbindd domain info for it
1333  *
1334  * @note Do *not* pass lp_workgroup() to this function.  domain_list
1335  *       may modify it's value, and free that pointer.  Instead, our local
1336  *       domain may be found by calling find_our_domain().
1337  *       directly.
1338  *
1339  *
1340  * @return The domain structure for the named domain, if it is working.
1341  */
1342
1343 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
1344 {
1345         struct winbindd_domain *domain;
1346
1347         /* Search through list */
1348
1349         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1350                 if (strequal(domain_name, domain->name)) {
1351                         return domain;
1352                 }
1353                 if (domain->alt_name == NULL) {
1354                         continue;
1355                 }
1356                 if (strequal(domain_name, domain->alt_name)) {
1357                         return domain;
1358                 }
1359         }
1360
1361         /* Not found */
1362
1363         return NULL;
1364 }
1365
1366 /**
1367  * Given a domain name, return the struct winbindd domain if it's a direct
1368  * outgoing trust
1369  *
1370  * @return The domain structure for the named domain, if it is a direct outgoing trust
1371  */
1372 struct winbindd_domain *find_trust_from_name_noinit(const char *domain_name)
1373 {
1374         struct winbindd_domain *domain = NULL;
1375
1376         domain = find_domain_from_name_noinit(domain_name);
1377         if (domain == NULL) {
1378                 return NULL;
1379         }
1380
1381         if (domain->secure_channel_type != SEC_CHAN_NULL) {
1382                 return domain;
1383         }
1384
1385         return NULL;
1386 }
1387
1388 struct winbindd_domain *find_domain_from_name(const char *domain_name)
1389 {
1390         struct winbindd_domain *domain;
1391
1392         domain = find_domain_from_name_noinit(domain_name);
1393
1394         if (domain == NULL)
1395                 return NULL;
1396
1397         if (!domain->initialized)
1398                 init_dc_connection(domain, false);
1399
1400         return domain;
1401 }
1402
1403 /* Given a domain sid, return the struct winbindd domain info for it */
1404
1405 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
1406 {
1407         struct winbindd_domain *domain;
1408
1409         /* Search through list */
1410
1411         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1412                 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
1413                         return domain;
1414         }
1415
1416         /* Not found */
1417
1418         return NULL;
1419 }
1420
1421 /**
1422  * Given a domain sid, return the struct winbindd domain if it's a direct
1423  * outgoing trust
1424  *
1425  * @return The domain structure for the specified domain, if it is a direct outgoing trust
1426  */
1427 struct winbindd_domain *find_trust_from_sid_noinit(const struct dom_sid *sid)
1428 {
1429         struct winbindd_domain *domain = NULL;
1430
1431         domain = find_domain_from_sid_noinit(sid);
1432         if (domain == NULL) {
1433                 return NULL;
1434         }
1435
1436         if (domain->secure_channel_type != SEC_CHAN_NULL) {
1437                 return domain;
1438         }
1439
1440         return NULL;
1441 }
1442
1443 /* Given a domain sid, return the struct winbindd domain info for it */
1444
1445 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
1446 {
1447         struct winbindd_domain *domain;
1448
1449         domain = find_domain_from_sid_noinit(sid);
1450
1451         if (domain == NULL)
1452                 return NULL;
1453
1454         if (!domain->initialized)
1455                 init_dc_connection(domain, false);
1456
1457         return domain;
1458 }
1459
1460 struct winbindd_domain *find_our_domain(void)
1461 {
1462         struct winbindd_domain *domain;
1463
1464         /* Search through list */
1465
1466         for (domain = domain_list(); domain != NULL; domain = domain->next) {
1467                 if (domain->primary)
1468                         return domain;
1469         }
1470
1471         smb_panic("Could not find our domain");
1472         return NULL;
1473 }
1474
1475 struct winbindd_domain *find_default_route_domain(void)
1476 {
1477         if (!IS_DC) {
1478                 return find_our_domain();
1479         }
1480         DBG_ERR("Routing logic not yet implemented on a DC");
1481         return NULL;
1482 }
1483
1484 /* Find the appropriate domain to lookup a name or SID */
1485
1486 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
1487 {
1488         DBG_DEBUG("SID [%s]\n", sid_string_dbg(sid));
1489
1490         /*
1491          * SIDs in the S-1-22-{1,2} domain and well-known SIDs should be handled
1492          * by our passdb.
1493          */
1494
1495         if ( sid_check_is_in_unix_groups(sid) ||
1496              sid_check_is_unix_groups(sid) ||
1497              sid_check_is_in_unix_users(sid) ||
1498              sid_check_is_unix_users(sid) ||
1499              sid_check_is_wellknown_domain(sid, NULL) ||
1500              sid_check_is_in_wellknown_domain(sid) )
1501         {
1502                 return find_domain_from_sid(get_global_sam_sid());
1503         }
1504
1505         /*
1506          * On member servers the internal domains are different: These are part
1507          * of the local SAM.
1508          */
1509
1510         if (is_internal_domain(sid) || is_in_internal_domain(sid)) {
1511                 DEBUG(10, ("calling find_domain_from_sid\n"));
1512                 return find_domain_from_sid(sid);
1513         }
1514
1515         if (IS_DC) {
1516                 struct winbindd_domain *domain = NULL;
1517
1518                 domain = find_domain_from_sid_noinit(sid);
1519                 if (domain == NULL) {
1520                         return NULL;
1521                 }
1522
1523                 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1524                         return domain;
1525                 }
1526
1527                 return domain->routing_domain;
1528         }
1529
1530         /* On a member server a query for SID or name can always go to our
1531          * primary DC. */
1532
1533         DEBUG(10, ("calling find_our_domain\n"));
1534         return find_our_domain();
1535 }
1536
1537 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
1538 {
1539         if ( strequal(domain_name, unix_users_domain_name() ) ||
1540              strequal(domain_name, unix_groups_domain_name() ) )
1541         {
1542                 /*
1543                  * The "Unix User" and "Unix Group" domain our handled by
1544                  * passdb
1545                  */
1546                 return find_domain_from_name_noinit( get_global_sam_name() );
1547         }
1548
1549         if (strequal(domain_name, "BUILTIN") ||
1550             strequal(domain_name, get_global_sam_name()))
1551                 return find_domain_from_name_noinit(domain_name);
1552
1553         if (IS_DC) {
1554                 struct winbindd_domain *domain = NULL;
1555
1556                 domain = find_domain_from_name_noinit(domain_name);
1557                 if (domain == NULL) {
1558                         return NULL;
1559                 }
1560
1561                 if (domain->secure_channel_type != SEC_CHAN_NULL) {
1562                         return domain;
1563                 }
1564
1565                 return domain->routing_domain;
1566         }
1567
1568         return find_our_domain();
1569 }
1570
1571 /* Is this a domain which we may assume no DOMAIN\ prefix? */
1572
1573 static bool assume_domain(const char *domain)
1574 {
1575         /* never assume the domain on a standalone server */
1576
1577         if ( lp_server_role() == ROLE_STANDALONE )
1578                 return False;
1579
1580         /* domain member servers may possibly assume for the domain name */
1581
1582         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
1583                 if ( !strequal(lp_workgroup(), domain) )
1584                         return False;
1585
1586                 if ( lp_winbind_use_default_domain() )
1587                         return True;
1588         }
1589
1590         /* only left with a domain controller */
1591
1592         if ( strequal(get_global_sam_name(), domain) )  {
1593                 return True;
1594         }
1595
1596         return False;
1597 }
1598
1599 /* Parse a string of the form DOMAIN\user into a domain and a user */
1600
1601 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1602 {
1603         char *p = strchr(domuser,*lp_winbind_separator());
1604
1605         if ( !p ) {
1606                 fstrcpy(user, domuser);
1607                 p = strchr(domuser, '@');
1608
1609                 if ( assume_domain(lp_workgroup()) && p == NULL) {
1610                         fstrcpy(domain, lp_workgroup());
1611                 } else if (p != NULL) {
1612                         fstrcpy(domain, p + 1);
1613                         user[PTR_DIFF(p, domuser)] = 0;
1614                 } else {
1615                         return False;
1616                 }
1617         } else {
1618                 fstrcpy(user, p+1);
1619                 fstrcpy(domain, domuser);
1620                 domain[PTR_DIFF(p, domuser)] = 0;
1621         }
1622
1623         return strupper_m(domain);
1624 }
1625
1626 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1627                               char **domain, char **user)
1628 {
1629         fstring fstr_domain, fstr_user;
1630         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1631                 return False;
1632         }
1633         *domain = talloc_strdup(mem_ctx, fstr_domain);
1634         *user = talloc_strdup(mem_ctx, fstr_user);
1635         return ((*domain != NULL) && (*user != NULL));
1636 }
1637
1638 /* Ensure an incoming username from NSS is fully qualified. Replace the
1639    incoming fstring with DOMAIN <separator> user. Returns the same
1640    values as parse_domain_user() but also replaces the incoming username.
1641    Used to ensure all names are fully qualified within winbindd.
1642    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1643    The protocol definitions of auth_crap, chng_pswd_auth_crap
1644    really should be changed to use this instead of doing things
1645    by hand. JRA. */
1646
1647 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1648 {
1649         if (!parse_domain_user(username_inout, domain, user)) {
1650                 return False;
1651         }
1652         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1653                  domain, *lp_winbind_separator(),
1654                  user);
1655         return True;
1656 }
1657
1658 /*
1659     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1660     'winbind separator' options.
1661     This means:
1662         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1663         lp_workgroup()
1664
1665     If we are a PDC or BDC, and this is for our domain, do likewise.
1666
1667     On an AD DC we always fill DOMAIN\\USERNAME.
1668
1669     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1670 */
1671 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1672 {
1673         fstring tmp_user;
1674
1675         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1676                 can_assume = false;
1677         }
1678
1679         fstrcpy(tmp_user, user);
1680         (void)strlower_m(tmp_user);
1681
1682         if (can_assume && assume_domain(domain)) {
1683                 strlcpy(name, tmp_user, sizeof(fstring));
1684         } else {
1685                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1686                          domain, *lp_winbind_separator(),
1687                          tmp_user);
1688         }
1689 }
1690
1691 /**
1692  * talloc version of fill_domain_username()
1693  * return NULL on talloc failure.
1694  */
1695 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1696                                   const char *domain,
1697                                   const char *user,
1698                                   bool can_assume)
1699 {
1700         char *tmp_user, *name;
1701
1702         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1703                 can_assume = false;
1704         }
1705
1706         tmp_user = talloc_strdup(mem_ctx, user);
1707         if (!strlower_m(tmp_user)) {
1708                 TALLOC_FREE(tmp_user);
1709                 return NULL;
1710         }
1711
1712         if (can_assume && assume_domain(domain)) {
1713                 name = tmp_user;
1714         } else {
1715                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1716                                        domain,
1717                                        *lp_winbind_separator(),
1718                                        tmp_user);
1719                 TALLOC_FREE(tmp_user);
1720         }
1721
1722         return name;
1723 }
1724
1725 /*
1726  * Client list accessor functions
1727  */
1728
1729 static struct winbindd_cli_state *_client_list;
1730 static int _num_clients;
1731
1732 /* Return list of all connected clients */
1733
1734 struct winbindd_cli_state *winbindd_client_list(void)
1735 {
1736         return _client_list;
1737 }
1738
1739 /* Return list-tail of all connected clients */
1740
1741 struct winbindd_cli_state *winbindd_client_list_tail(void)
1742 {
1743         return DLIST_TAIL(_client_list);
1744 }
1745
1746 /* Return previous (read:newer) client in list */
1747
1748 struct winbindd_cli_state *
1749 winbindd_client_list_prev(struct winbindd_cli_state *cli)
1750 {
1751         return DLIST_PREV(cli);
1752 }
1753
1754 /* Add a connection to the list */
1755
1756 void winbindd_add_client(struct winbindd_cli_state *cli)
1757 {
1758         cli->last_access = time(NULL);
1759         DLIST_ADD(_client_list, cli);
1760         _num_clients++;
1761 }
1762
1763 /* Remove a client from the list */
1764
1765 void winbindd_remove_client(struct winbindd_cli_state *cli)
1766 {
1767         DLIST_REMOVE(_client_list, cli);
1768         _num_clients--;
1769 }
1770
1771 /* Move a client to head or list */
1772
1773 void winbindd_promote_client(struct winbindd_cli_state *cli)
1774 {
1775         cli->last_access = time(NULL);
1776         DLIST_PROMOTE(_client_list, cli);
1777 }
1778
1779 /* Return number of open clients */
1780
1781 int winbindd_num_clients(void)
1782 {
1783         return _num_clients;
1784 }
1785
1786 NTSTATUS lookup_usergroups_cached(TALLOC_CTX *mem_ctx,
1787                                   const struct dom_sid *user_sid,
1788                                   uint32_t *p_num_groups, struct dom_sid **user_sids)
1789 {
1790         struct netr_SamInfo3 *info3 = NULL;
1791         NTSTATUS status = NT_STATUS_NO_MEMORY;
1792         uint32_t num_groups = 0;
1793
1794         DEBUG(3,(": lookup_usergroups_cached\n"));
1795
1796         *user_sids = NULL;
1797         *p_num_groups = 0;
1798
1799         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1800
1801         if (info3 == NULL) {
1802                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1803         }
1804
1805         /*
1806          * Before bug #7843 the "Domain Local" groups were added with a
1807          * lookupuseraliases call, but this isn't done anymore for our domain
1808          * so we need to resolve resource groups here.
1809          *
1810          * When to use Resource Groups:
1811          * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1812          */
1813         status = sid_array_from_info3(mem_ctx, info3,
1814                                       user_sids,
1815                                       &num_groups,
1816                                       false);
1817
1818         if (!NT_STATUS_IS_OK(status)) {
1819                 TALLOC_FREE(info3);
1820                 return status;
1821         }
1822
1823         TALLOC_FREE(info3);
1824         *p_num_groups = num_groups;
1825         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1826
1827         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1828
1829         return status;
1830 }
1831
1832 /*********************************************************************
1833  We use this to remove spaces from user and group names
1834 ********************************************************************/
1835
1836 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1837                              const char *domain_name,
1838                              const char *name,
1839                              char **normalized)
1840 {
1841         struct winbindd_domain *domain = NULL;
1842         NTSTATUS nt_status;
1843
1844         if (!name || !normalized) {
1845                 return NT_STATUS_INVALID_PARAMETER;
1846         }
1847
1848         if (!lp_winbind_normalize_names()) {
1849                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1850         }
1851
1852         domain = find_domain_from_name_noinit(domain_name);
1853         if (domain == NULL) {
1854                 DBG_ERR("Failed to find domain '%s'\n", domain_name);
1855                 return NT_STATUS_NO_SUCH_DOMAIN;
1856         }
1857
1858         /* Alias support and whitespace replacement are mutually
1859            exclusive */
1860
1861         nt_status = resolve_username_to_alias(mem_ctx, domain,
1862                                               name, normalized );
1863         if (NT_STATUS_IS_OK(nt_status)) {
1864                 /* special return code to let the caller know we
1865                    mapped to an alias */
1866                 return NT_STATUS_FILE_RENAMED;
1867         }
1868
1869         /* check for an unreachable domain */
1870
1871         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1872                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1873                          domain->name));
1874                 set_domain_offline(domain);
1875                 return nt_status;
1876         }
1877
1878         /* deal with whitespace */
1879
1880         *normalized = talloc_strdup(mem_ctx, name);
1881         if (!(*normalized)) {
1882                 return NT_STATUS_NO_MEMORY;
1883         }
1884
1885         all_string_sub( *normalized, " ", "_", 0 );
1886
1887         return NT_STATUS_OK;
1888 }
1889
1890 /*********************************************************************
1891  We use this to do the inverse of normalize_name_map()
1892 ********************************************************************/
1893
1894 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1895                               char *name,
1896                               char **normalized)
1897 {
1898         NTSTATUS nt_status;
1899         struct winbindd_domain *domain = find_our_domain();
1900
1901         if (!name || !normalized) {
1902                 return NT_STATUS_INVALID_PARAMETER;
1903         }
1904
1905         if (!lp_winbind_normalize_names()) {
1906                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1907         }
1908
1909         /* Alias support and whitespace replacement are mutally
1910            exclusive */
1911
1912         /* When mapping from an alias to a username, we don't know the
1913            domain.  But we only need a domain structure to cache
1914            a successful lookup , so just our own domain structure for
1915            the seqnum. */
1916
1917         nt_status = resolve_alias_to_username(mem_ctx, domain,
1918                                               name, normalized);
1919         if (NT_STATUS_IS_OK(nt_status)) {
1920                 /* Special return code to let the caller know we mapped
1921                    from an alias */
1922                 return NT_STATUS_FILE_RENAMED;
1923         }
1924
1925         /* check for an unreachable domain */
1926
1927         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1928                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1929                          domain->name));
1930                 set_domain_offline(domain);
1931                 return nt_status;
1932         }
1933
1934         /* deal with whitespace */
1935
1936         *normalized = talloc_strdup(mem_ctx, name);
1937         if (!(*normalized)) {
1938                 return NT_STATUS_NO_MEMORY;
1939         }
1940
1941         all_string_sub(*normalized, "_", " ", 0);
1942
1943         return NT_STATUS_OK;
1944 }
1945
1946 /*********************************************************************
1947  ********************************************************************/
1948
1949 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1950 {
1951         struct winbindd_tdc_domain *tdc = NULL;
1952         TALLOC_CTX *frame = talloc_stackframe();
1953         bool ret = false;
1954
1955         /* We can contact the domain if it is our primary domain */
1956
1957         if (domain->primary) {
1958                 ret = true;
1959                 goto done;
1960         }
1961
1962         /* Trust the TDC cache and not the winbindd_domain flags */
1963
1964         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1965                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1966                           domain->name));
1967                 ret = false;
1968                 goto done;
1969         }
1970
1971         /* Can always contact a domain that is in out forest */
1972
1973         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1974                 ret = true;
1975                 goto done;
1976         }
1977
1978         /*
1979          * On a _member_ server, we cannot contact the domain if it
1980          * is running AD and we have no inbound trust.
1981          */
1982
1983         if (!IS_DC &&
1984              domain->active_directory &&
1985             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1986         {
1987                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1988                            "and we have no inbound trust.\n", domain->name));
1989                 goto done;
1990         }
1991
1992         /* Assume everything else is ok (probably not true but what
1993            can you do?) */
1994
1995         ret = true;
1996
1997 done:
1998         talloc_destroy(frame);
1999
2000         return ret;
2001 }
2002
2003 /*********************************************************************
2004  ********************************************************************/
2005
2006 bool winbindd_internal_child(struct winbindd_child *child)
2007 {
2008         if ((child == idmap_child()) || (child == locator_child())) {
2009                 return True;
2010         }
2011
2012         return False;
2013 }
2014
2015 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
2016
2017 /*********************************************************************
2018  ********************************************************************/
2019
2020 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
2021 {
2022         char *var = NULL;
2023         char addr[INET6_ADDRSTRLEN];
2024         const char *kdc = NULL;
2025         int lvl = 11;
2026
2027         if (!domain || !domain->alt_name || !*domain->alt_name) {
2028                 return;
2029         }
2030
2031         if (domain->initialized && !domain->active_directory) {
2032                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
2033                         domain->alt_name));
2034                 return;
2035         }
2036
2037         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
2038         kdc = addr;
2039         if (!*kdc) {
2040                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
2041                         domain->alt_name));
2042                 kdc = domain->dcname;
2043         }
2044
2045         if (!kdc || !*kdc) {
2046                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
2047                         domain->alt_name));
2048                 return;
2049         }
2050
2051         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2052                                 domain->alt_name) == -1) {
2053                 return;
2054         }
2055
2056         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
2057                 var, kdc));
2058
2059         setenv(var, kdc, 1);
2060         free(var);
2061 }
2062
2063 /*********************************************************************
2064  ********************************************************************/
2065
2066 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2067 {
2068         struct winbindd_domain *our_dom = find_our_domain();
2069
2070         winbindd_set_locator_kdc_env(domain);
2071
2072         if (domain != our_dom) {
2073                 winbindd_set_locator_kdc_env(our_dom);
2074         }
2075 }
2076
2077 /*********************************************************************
2078  ********************************************************************/
2079
2080 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2081 {
2082         char *var = NULL;
2083
2084         if (!domain || !domain->alt_name || !*domain->alt_name) {
2085                 return;
2086         }
2087
2088         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
2089                                 domain->alt_name) == -1) {
2090                 return;
2091         }
2092
2093         unsetenv(var);
2094         free(var);
2095 }
2096 #else
2097
2098 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
2099 {
2100         return;
2101 }
2102
2103 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
2104 {
2105         return;
2106 }
2107
2108 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
2109
2110 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
2111 {
2112         resp->data.auth.nt_status = NT_STATUS_V(result);
2113         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
2114
2115         /* we might have given a more useful error above */
2116         if (*resp->data.auth.error_string == '\0')
2117                 fstrcpy(resp->data.auth.error_string,
2118                         get_friendly_nt_error_msg(result));
2119         resp->data.auth.pam_error = nt_status_to_pam(result);
2120 }
2121
2122 bool is_domain_offline(const struct winbindd_domain *domain)
2123 {
2124         if (get_global_winbindd_state_offline()) {
2125                 return true;
2126         }
2127         return !domain->online;
2128 }
2129
2130 bool is_domain_online(const struct winbindd_domain *domain)
2131 {
2132         return !is_domain_offline(domain);
2133 }
2134
2135 /**
2136  * Parse an char array into a list of sids.
2137  *
2138  * The input sidstr should consist of 0-terminated strings
2139  * representing sids, separated by newline characters '\n'.
2140  * The list is terminated by an empty string, i.e.
2141  * character '\0' directly following a character '\n'
2142  * (or '\0' right at the start of sidstr).
2143  */
2144 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
2145                    struct dom_sid **sids, uint32_t *num_sids)
2146 {
2147         const char *p;
2148
2149         p = sidstr;
2150         if (p == NULL)
2151                 return False;
2152
2153         while (p[0] != '\0') {
2154                 struct dom_sid sid;
2155                 const char *q = NULL;
2156
2157                 if (!dom_sid_parse_endp(p, &sid, &q)) {
2158                         DEBUG(1, ("Could not parse sid %s\n", p));
2159                         return false;
2160                 }
2161                 if (q[0] != '\n') {
2162                         DEBUG(1, ("Got invalid sidstr: %s\n", p));
2163                         return false;
2164                 }
2165                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
2166                                                       num_sids)))
2167                 {
2168                         return False;
2169                 }
2170                 p = q+1;
2171         }
2172         return True;
2173 }
2174
2175 bool parse_xidlist(TALLOC_CTX *mem_ctx, const char *xidstr,
2176                    struct unixid **pxids, uint32_t *pnum_xids)
2177 {
2178         const char *p;
2179         struct unixid *xids = NULL;
2180         uint32_t num_xids = 0;
2181
2182         p = xidstr;
2183         if (p == NULL) {
2184                 return false;
2185         }
2186
2187         while (p[0] != '\0') {
2188                 struct unixid *tmp;
2189                 struct unixid xid;
2190                 unsigned long long id;
2191                 char *endp;
2192
2193                 switch (p[0]) {
2194                 case 'U':
2195                         xid = (struct unixid) { .type = ID_TYPE_UID };
2196                         break;
2197                 case 'G':
2198                         xid = (struct unixid) { .type = ID_TYPE_GID };
2199                         break;
2200                 default:
2201                         return false;
2202                 }
2203
2204                 p += 1;
2205
2206                 id = strtoull(p, &endp, 10);
2207                 if ((id == ULLONG_MAX) && (errno == ERANGE)) {
2208                         goto fail;
2209                 }
2210                 if (*endp != '\n') {
2211                         goto fail;
2212                 }
2213                 p = endp+1;
2214
2215                 xid.id = id;
2216                 if ((unsigned long long)xid.id != id) {
2217                         goto fail;
2218                 }
2219
2220                 tmp = talloc_realloc(mem_ctx, xids, struct unixid, num_xids+1);
2221                 if (tmp == NULL) {
2222                         return 0;
2223                 }
2224                 xids = tmp;
2225
2226                 xids[num_xids] = xid;
2227                 num_xids += 1;
2228         }
2229
2230         *pxids = xids;
2231         *pnum_xids = num_xids;
2232         return true;
2233
2234 fail:
2235         TALLOC_FREE(xids);
2236         return false;
2237 }