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