winbindd: Use pdb_get_domain_info() to get exactly the local domain info when we...
[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 "secrets.h"
26 #include "../libcli/security/security.h"
27 #include "../libcli/auth/pam_errors.h"
28 #include "passdb/machine_sid.h"
29 #include "passdb.h"
30 #include "source4/lib/messaging/messaging.h"
31 #include "librpc/gen_ndr/ndr_lsa.h"
32
33 #undef DBGC_CLASS
34 #define DBGC_CLASS DBGC_WINBIND
35
36 extern struct winbindd_methods cache_methods;
37
38 /**
39  * @file winbindd_util.c
40  *
41  * Winbind daemon for NT domain authentication nss module.
42  **/
43
44
45 /* The list of trusted domains.  Note that the list can be deleted and
46    recreated using the init_domain_list() function so pointers to
47    individual winbindd_domain structures cannot be made.  Keep a copy of
48    the domain name instead. */
49
50 static struct winbindd_domain *_domain_list = NULL;
51
52 struct winbindd_domain *domain_list(void)
53 {
54         /* Initialise list */
55
56         if ((!_domain_list) && (!init_domain_list())) {
57                 smb_panic("Init_domain_list failed");
58         }
59
60         return _domain_list;
61 }
62
63 /* Free all entries in the trusted domain list */
64
65 static void free_domain_list(void)
66 {
67         struct winbindd_domain *domain = _domain_list;
68
69         while(domain) {
70                 struct winbindd_domain *next = domain->next;
71
72                 DLIST_REMOVE(_domain_list, domain);
73                 TALLOC_FREE(domain);
74                 domain = next;
75         }
76 }
77
78 /**
79  * Iterator for winbindd's domain list.
80  * To be used (e.g.) in tevent based loops.
81  */
82 struct winbindd_domain *wb_next_domain(struct winbindd_domain *domain)
83 {
84         if (domain == NULL) {
85                 domain = domain_list();
86         } else {
87                 domain = domain->next;
88         }
89
90         if ((domain != NULL) &&
91             (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) &&
92             sid_check_is_our_sam(&domain->sid))
93         {
94                 domain = domain->next;
95         }
96
97         return domain;
98 }
99
100 static bool is_internal_domain(const struct dom_sid *sid)
101 {
102         if (sid == NULL)
103                 return False;
104
105         return (sid_check_is_our_sam(sid) || sid_check_is_builtin(sid));
106 }
107
108 static bool is_in_internal_domain(const struct dom_sid *sid)
109 {
110         if (sid == NULL)
111                 return False;
112
113         return (sid_check_is_in_our_sam(sid) || sid_check_is_in_builtin(sid));
114 }
115
116
117 /* Add a trusted domain to our list of domains.
118    If the domain already exists in the list,
119    return it and don't re-initialize.  */
120
121 static struct winbindd_domain *add_trusted_domain(const char *domain_name, const char *alt_name,
122                                                   struct winbindd_methods *methods,
123                                                   const struct dom_sid *sid)
124 {
125         struct winbindd_domain *domain;
126         const char *alternative_name = NULL;
127         char *idmap_config_option;
128         const char *param;
129         const char **ignored_domains, **dom;
130         int role = lp_server_role();
131
132         ignored_domains = lp_parm_string_list(-1, "winbind", "ignore domains", NULL);
133         for (dom=ignored_domains; dom && *dom; dom++) {
134                 if (gen_fnmatch(*dom, domain_name) == 0) {
135                         DEBUG(2,("Ignoring domain '%s'\n", domain_name));
136                         return NULL;
137                 }
138         }
139
140         /* use alt_name if available to allow DNS lookups */
141
142         if (alt_name && *alt_name) {
143                 alternative_name = alt_name;
144         }
145
146         /* We can't call domain_list() as this function is called from
147            init_domain_list() and we'll get stuck in a loop. */
148         for (domain = _domain_list; domain; domain = domain->next) {
149                 if (strequal(domain_name, domain->name) ||
150                     strequal(domain_name, domain->alt_name))
151                 {
152                         break;
153                 }
154
155                 if (alternative_name && *alternative_name)
156                 {
157                         if (strequal(alternative_name, domain->name) ||
158                             strequal(alternative_name, domain->alt_name))
159                         {
160                                 break;
161                         }
162                 }
163
164                 if (sid)
165                 {
166                         if (is_null_sid(sid)) {
167                                 continue;
168                         }
169
170                         if (dom_sid_equal(sid, &domain->sid)) {
171                                 break;
172                         }
173                 }
174         }
175
176         if (domain != NULL) {
177                 /*
178                  * We found a match on domain->name or
179                  * domain->alt_name. Possibly update the SID
180                  * if the stored SID was the NULL SID
181                  * and return the matching entry.
182                  */
183                 if ((sid != NULL)
184                     && dom_sid_equal(&domain->sid, &global_sid_NULL)) {
185                         sid_copy( &domain->sid, sid );
186                 }
187                 return domain;
188         }
189
190         /* Create new domain entry */
191         domain = talloc_zero(NULL, struct winbindd_domain);
192         if (domain == NULL) {
193                 return NULL;
194         }
195
196         domain->children = talloc_zero_array(domain,
197                                              struct winbindd_child,
198                                              lp_winbind_max_domain_connections());
199         if (domain->children == NULL) {
200                 TALLOC_FREE(domain);
201                 return NULL;
202         }
203
204         domain->name = talloc_strdup(domain, domain_name);
205         if (domain->name == NULL) {
206                 TALLOC_FREE(domain);
207                 return NULL;
208         }
209
210         if (alternative_name) {
211                 domain->alt_name = talloc_strdup(domain, alternative_name);
212                 if (domain->alt_name == NULL) {
213                         TALLOC_FREE(domain);
214                         return NULL;
215                 }
216         }
217
218         domain->methods = methods;
219         domain->backend = NULL;
220         domain->internal = is_internal_domain(sid);
221         domain->sequence_number = DOM_SEQUENCE_NONE;
222         domain->last_seq_check = 0;
223         domain->initialized = False;
224         domain->online = is_internal_domain(sid);
225         domain->check_online_timeout = 0;
226         domain->dc_probe_pid = (pid_t)-1;
227         if (sid) {
228                 sid_copy(&domain->sid, sid);
229         }
230
231         /* Is this our primary domain ? */
232         if (strequal(domain_name, get_global_sam_name()) &&
233                         (role != ROLE_DOMAIN_MEMBER)) {
234                 domain->primary = true;
235         } else if (strequal(domain_name, lp_workgroup()) &&
236                         (role == ROLE_DOMAIN_MEMBER)) {
237                 domain->primary = true;
238         }
239
240         if (domain->primary) {
241                 if (role == ROLE_ACTIVE_DIRECTORY_DC) {
242                         domain->active_directory = true;
243                 }
244                 if (lp_security() == SEC_ADS) {
245                         domain->active_directory = true;
246                 }
247         }
248
249         /* Link to domain list */
250         DLIST_ADD_END(_domain_list, domain, struct winbindd_domain *);
251
252         wcache_tdc_add_domain( domain );
253
254         idmap_config_option = talloc_asprintf(talloc_tos(), "idmap config %s",
255                                               domain->name);
256         if (idmap_config_option == NULL) {
257                 DEBUG(0, ("talloc failed, not looking for idmap config\n"));
258                 goto done;
259         }
260
261         param = lp_parm_const_string(-1, idmap_config_option, "range", NULL);
262
263         DEBUG(10, ("%s : range = %s\n", idmap_config_option,
264                    param ? param : "not defined"));
265
266         if (param != NULL) {
267                 unsigned low_id, high_id;
268                 if (sscanf(param, "%u - %u", &low_id, &high_id) != 2) {
269                         DEBUG(1, ("invalid range syntax in %s: %s\n",
270                                   idmap_config_option, param));
271                         goto done;
272                 }
273                 if (low_id > high_id) {
274                         DEBUG(1, ("invalid range in %s: %s\n",
275                                   idmap_config_option, param));
276                         goto done;
277                 }
278                 domain->have_idmap_config = true;
279                 domain->id_range_low = low_id;
280                 domain->id_range_high = high_id;
281         }
282
283 done:
284
285         setup_domain_child(domain);
286
287         DEBUG(2,("Added domain %s %s %s\n",
288                  domain->name, domain->alt_name,
289                  &domain->sid?sid_string_dbg(&domain->sid):""));
290
291         return domain;
292 }
293
294 bool domain_is_forest_root(const struct winbindd_domain *domain)
295 {
296         const uint32_t fr_flags =
297                 (NETR_TRUST_FLAG_TREEROOT|NETR_TRUST_FLAG_IN_FOREST);
298
299         return ((domain->domain_flags & fr_flags) == fr_flags);
300 }
301
302 /********************************************************************
303   rescan our domains looking for new trusted domains
304 ********************************************************************/
305
306 struct trustdom_state {
307         struct winbindd_domain *domain;
308         struct winbindd_request request;
309 };
310
311 static void trustdom_list_done(struct tevent_req *req);
312 static void rescan_forest_root_trusts( void );
313 static void rescan_forest_trusts( void );
314
315 static void add_trusted_domains( struct winbindd_domain *domain )
316 {
317         struct trustdom_state *state;
318         struct tevent_req *req;
319
320         state = talloc_zero(NULL, struct trustdom_state);
321         if (state == NULL) {
322                 DEBUG(0, ("talloc failed\n"));
323                 return;
324         }
325         state->domain = domain;
326
327         state->request.length = sizeof(state->request);
328         state->request.cmd = WINBINDD_LIST_TRUSTDOM;
329
330         req = wb_domain_request_send(state, winbind_event_context(),
331                                      domain, &state->request);
332         if (req == NULL) {
333                 DEBUG(1, ("wb_domain_request_send failed\n"));
334                 TALLOC_FREE(state);
335                 return;
336         }
337         tevent_req_set_callback(req, trustdom_list_done, state);
338 }
339
340 static void trustdom_list_done(struct tevent_req *req)
341 {
342         struct trustdom_state *state = tevent_req_callback_data(
343                 req, struct trustdom_state);
344         struct winbindd_response *response;
345         int res, err;
346         char *p;
347
348         res = wb_domain_request_recv(req, state, &response, &err);
349         if ((res == -1) || (response->result != WINBINDD_OK)) {
350                 DEBUG(1, ("Could not receive trustdoms\n"));
351                 TALLOC_FREE(state);
352                 return;
353         }
354
355         p = (char *)response->extra_data.data;
356
357         while ((p != NULL) && (*p != '\0')) {
358                 char *q, *sidstr, *alt_name;
359                 struct dom_sid sid;
360                 char *alternate_name = NULL;
361
362                 alt_name = strchr(p, '\\');
363                 if (alt_name == NULL) {
364                         DEBUG(0, ("Got invalid trustdom response\n"));
365                         break;
366                 }
367
368                 *alt_name = '\0';
369                 alt_name += 1;
370
371                 sidstr = strchr(alt_name, '\\');
372                 if (sidstr == NULL) {
373                         DEBUG(0, ("Got invalid trustdom response\n"));
374                         break;
375                 }
376
377                 *sidstr = '\0';
378                 sidstr += 1;
379
380                 q = strchr(sidstr, '\n');
381                 if (q != NULL)
382                         *q = '\0';
383
384                 if (!string_to_sid(&sid, sidstr)) {
385                         DEBUG(0, ("Got invalid trustdom response\n"));
386                         break;
387                 }
388
389                 /* use the real alt_name if we have one, else pass in NULL */
390
391                 if ( !strequal( alt_name, "(null)" ) )
392                         alternate_name = alt_name;
393
394                 /*
395                  * We always call add_trusted_domain() cause on an existing
396                  * domain structure, it will update the SID if necessary.
397                  * This is important because we need the SID for sibling
398                  * domains.
399                  */
400                 (void)add_trusted_domain(p, alternate_name,
401                                             &cache_methods,
402                                             &sid);
403
404                 p=q;
405                 if (p != NULL)
406                         p += 1;
407         }
408
409         /*
410            Cases to consider when scanning trusts:
411            (a) we are calling from a child domain (primary && !forest_root)
412            (b) we are calling from the root of the forest (primary && forest_root)
413            (c) we are calling from a trusted forest domain (!primary
414                && !forest_root)
415         */
416
417         if (state->domain->primary) {
418                 /* If this is our primary domain and we are not in the
419                    forest root, we have to scan the root trusts first */
420
421                 if (!domain_is_forest_root(state->domain))
422                         rescan_forest_root_trusts();
423                 else
424                         rescan_forest_trusts();
425
426         } else if (domain_is_forest_root(state->domain)) {
427                 /* Once we have done root forest trust search, we can
428                    go on to search the trusted forests */
429
430                 rescan_forest_trusts();
431         }
432
433         TALLOC_FREE(state);
434
435         return;
436 }
437
438 /********************************************************************
439  Scan the trusts of our forest root
440 ********************************************************************/
441
442 static void rescan_forest_root_trusts( void )
443 {
444         struct winbindd_tdc_domain *dom_list = NULL;
445         size_t num_trusts = 0;
446         int i;
447
448         /* The only transitive trusts supported by Windows 2003 AD are
449            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
450            first two are handled in forest and listed by
451            DsEnumerateDomainTrusts().  Forest trusts are not so we
452            have to do that ourselves. */
453
454         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
455                 return;
456
457         for ( i=0; i<num_trusts; i++ ) {
458                 struct winbindd_domain *d = NULL;
459
460                 /* Find the forest root.  Don't necessarily trust
461                    the domain_list() as our primary domain may not
462                    have been initialized. */
463
464                 if ( !(dom_list[i].trust_flags & NETR_TRUST_FLAG_TREEROOT) ) {
465                         continue;
466                 }
467
468                 /* Here's the forest root */
469
470                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
471
472                 if ( !d ) {
473                         d = add_trusted_domain( dom_list[i].domain_name,
474                                                 dom_list[i].dns_name,
475                                                 &cache_methods,
476                                                 &dom_list[i].sid );
477                 }
478
479                 if (d == NULL) {
480                         continue;
481                 }
482
483                 DEBUG(10,("rescan_forest_root_trusts: Following trust path "
484                           "for domain tree root %s (%s)\n",
485                           d->name, d->alt_name ));
486
487                 d->domain_flags = dom_list[i].trust_flags;
488                 d->domain_type  = dom_list[i].trust_type;
489                 d->domain_trust_attribs = dom_list[i].trust_attribs;
490
491                 add_trusted_domains( d );
492
493                 break;
494         }
495
496         TALLOC_FREE( dom_list );
497
498         return;
499 }
500
501 /********************************************************************
502  scan the transitive forest trusts (not our own)
503 ********************************************************************/
504
505
506 static void rescan_forest_trusts( void )
507 {
508         struct winbindd_domain *d = NULL;
509         struct winbindd_tdc_domain *dom_list = NULL;
510         size_t num_trusts = 0;
511         int i;
512
513         /* The only transitive trusts supported by Windows 2003 AD are
514            (a) Parent-Child, (b) Tree-Root, and (c) Forest.   The
515            first two are handled in forest and listed by
516            DsEnumerateDomainTrusts().  Forest trusts are not so we
517            have to do that ourselves. */
518
519         if ( !wcache_tdc_fetch_list( &dom_list, &num_trusts ) )
520                 return;
521
522         for ( i=0; i<num_trusts; i++ ) {
523                 uint32_t flags   = dom_list[i].trust_flags;
524                 uint32_t type    = dom_list[i].trust_type;
525                 uint32_t attribs = dom_list[i].trust_attribs;
526
527                 d = find_domain_from_name_noinit( dom_list[i].domain_name );
528
529                 /* ignore our primary and internal domains */
530
531                 if ( d && (d->internal || d->primary ) )
532                         continue;
533
534                 if ( (flags & NETR_TRUST_FLAG_INBOUND) &&
535                      (type == LSA_TRUST_TYPE_UPLEVEL) &&
536                      (attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) )
537                 {
538                         /* add the trusted domain if we don't know
539                            about it */
540
541                         if ( !d ) {
542                                 d = add_trusted_domain( dom_list[i].domain_name,
543                                                         dom_list[i].dns_name,
544                                                         &cache_methods,
545                                                         &dom_list[i].sid );
546                         }
547
548                         if (d == NULL) {
549                                 continue;
550                         }
551
552                         DEBUG(10,("Following trust path for domain %s (%s)\n",
553                                   d->name, d->alt_name ));
554                         add_trusted_domains( d );
555                 }
556         }
557
558         TALLOC_FREE( dom_list );
559
560         return;
561 }
562
563 /*********************************************************************
564  The process of updating the trusted domain list is a three step
565  async process:
566  (a) ask our domain
567  (b) ask the root domain in our forest
568  (c) ask the a DC in any Win2003 trusted forests
569 *********************************************************************/
570
571 void rescan_trusted_domains(struct tevent_context *ev, struct tevent_timer *te,
572                             struct timeval now, void *private_data)
573 {
574         TALLOC_FREE(te);
575
576         /* I use to clear the cache here and start over but that
577            caused problems in child processes that needed the
578            trust dom list early on.  Removing it means we
579            could have some trusted domains listed that have been
580            removed from our primary domain's DC until a full
581            restart.  This should be ok since I think this is what
582            Windows does as well. */
583
584         /* this will only add new domains we didn't already know about
585            in the domain_list()*/
586
587         add_trusted_domains( find_our_domain() );
588
589         te = tevent_add_timer(
590                 ev, NULL, timeval_current_ofs(WINBINDD_RESCAN_FREQ, 0),
591                 rescan_trusted_domains, NULL);
592         /*
593          * If te == NULL, there's not much we can do here. Don't fail, the
594          * only thing we miss is new trusted domains.
595          */
596
597         return;
598 }
599
600 enum winbindd_result winbindd_dual_init_connection(struct winbindd_domain *domain,
601                                                    struct winbindd_cli_state *state)
602 {
603         /* Ensure null termination */
604         state->request->domain_name
605                 [sizeof(state->request->domain_name)-1]='\0';
606         state->request->data.init_conn.dcname
607                 [sizeof(state->request->data.init_conn.dcname)-1]='\0';
608
609         if (strlen(state->request->data.init_conn.dcname) > 0) {
610                 fstrcpy(domain->dcname, state->request->data.init_conn.dcname);
611         }
612
613         init_dc_connection(domain, false);
614
615         if (!domain->initialized) {
616                 /* If we return error here we can't do any cached authentication,
617                    but we may be in disconnected mode and can't initialize correctly.
618                    Do what the previous code did and just return without initialization,
619                    once we go online we'll re-initialize.
620                 */
621                 DEBUG(5, ("winbindd_dual_init_connection: %s returning without initialization "
622                         "online = %d\n", domain->name, (int)domain->online ));
623         }
624
625         fstrcpy(state->response->data.domain_info.name, domain->name);
626         fstrcpy(state->response->data.domain_info.alt_name, domain->alt_name);
627         sid_to_fstring(state->response->data.domain_info.sid, &domain->sid);
628
629         state->response->data.domain_info.native_mode
630                 = domain->native_mode;
631         state->response->data.domain_info.active_directory
632                 = domain->active_directory;
633         state->response->data.domain_info.primary
634                 = domain->primary;
635
636         return WINBINDD_OK;
637 }
638
639 static void wb_imsg_new_trusted_domain(struct imessaging_context *msg,
640                                        void *private_data,
641                                        uint32_t msg_type,
642                                        struct server_id server_id,
643                                        DATA_BLOB *data)
644 {
645         TALLOC_CTX *frame = talloc_stackframe();
646         struct lsa_TrustDomainInfoInfoEx info;
647         enum ndr_err_code ndr_err;
648         struct winbindd_domain *d = NULL;
649
650         DEBUG(5, ("wb_imsg_new_trusted_domain\n"));
651
652         if (data == NULL) {
653                 TALLOC_FREE(frame);
654                 return;
655         }
656
657         ndr_err = ndr_pull_struct_blob_all(data, frame, &info,
658                         (ndr_pull_flags_fn_t)ndr_pull_lsa_TrustDomainInfoInfoEx);
659         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
660                 TALLOC_FREE(frame);
661                 return;
662         }
663
664         d = find_domain_from_name_noinit(info.netbios_name.string);
665         if (d != NULL) {
666                 TALLOC_FREE(frame);
667                 return;
668         }
669
670         d = add_trusted_domain(info.netbios_name.string,
671                                info.domain_name.string,
672                                &cache_methods,
673                                info.sid);
674         if (d == NULL) {
675                 TALLOC_FREE(frame);
676                 return;
677         }
678
679         if (d->internal) {
680                 TALLOC_FREE(frame);
681                 return;
682         }
683
684         if (d->primary) {
685                 TALLOC_FREE(frame);
686                 return;
687         }
688
689         if (info.trust_direction & LSA_TRUST_DIRECTION_INBOUND) {
690                 d->domain_flags |= NETR_TRUST_FLAG_INBOUND;
691         }
692         if (info.trust_direction & LSA_TRUST_DIRECTION_OUTBOUND) {
693                 d->domain_flags |= NETR_TRUST_FLAG_OUTBOUND;
694         }
695         if (info.trust_attributes & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
696                 d->domain_flags |= NETR_TRUST_FLAG_IN_FOREST;
697         }
698         d->domain_type = info.trust_type;
699         d->domain_trust_attribs = info.trust_attributes;
700
701         TALLOC_FREE(frame);
702 }
703
704 /* Look up global info for the winbind daemon */
705 bool init_domain_list(void)
706 {
707         int role = lp_server_role();
708         NTSTATUS status;
709
710         /* Free existing list */
711         free_domain_list();
712
713         /* BUILTIN domain */
714
715         (void)add_trusted_domain("BUILTIN", NULL, &cache_methods,
716                                     &global_sid_Builtin);
717
718         /* Local SAM */
719
720         if ( role == ROLE_ACTIVE_DIRECTORY_DC ) {
721                 struct winbindd_domain *domain;
722                 enum netr_SchannelType sec_chan_type;
723                 const char *account_name;
724                 struct samr_Password current_nt_hash;
725                 struct pdb_domain_info *pdb_domain_info;
726                 bool ok;
727
728                 pdb_domain_info = pdb_get_domain_info(talloc_tos());
729                 if (pdb_domain_info == NULL) {
730                         DEBUG(0, ("Failed to fetch our own, local AD "
731                                 "domain info from sam.ldb\n"));
732                         return false;
733                 }
734                 domain = add_trusted_domain(pdb_domain_info->name,
735                                         pdb_domain_info->dns_domain,
736                                         &cache_methods,
737                                         &pdb_domain_info->sid);
738                 TALLOC_FREE(pdb_domain_info);
739                 if (domain == NULL) {
740                         DEBUG(0, ("Failed to add our own, local AD "
741                                 "domain to winbindd's internal list\n"));
742                         return false;
743                 }
744
745                 /*
746                  * We need to call this to find out if we are an RODC
747                  */
748                 ok = get_trust_pw_hash(domain->name,
749                                        current_nt_hash.hash,
750                                        &account_name,
751                                        &sec_chan_type);
752                 if (!ok) {
753                         DEBUG(0, ("Failed to fetch our own, local AD domain join password for winbindd's internal use\n"));
754                         return false;
755                 }
756                 if (sec_chan_type == SEC_CHAN_RODC) {
757                         domain->rodc = true;
758                 }
759
760         } else {
761                 (void)add_trusted_domain(get_global_sam_name(), NULL,
762                                          &cache_methods, get_global_sam_sid());
763         }
764         /* Add ourselves as the first entry. */
765
766         if ( role == ROLE_DOMAIN_MEMBER ) {
767                 struct winbindd_domain *domain;
768                 struct dom_sid our_sid;
769
770                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
771                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
772                         return False;
773                 }
774
775                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
776                                              &cache_methods, &our_sid);
777                 if (domain) {
778                         /* Even in the parent winbindd we'll need to
779                            talk to the DC, so try and see if we can
780                            contact it. Theoretically this isn't neccessary
781                            as the init_dc_connection() in init_child_recv()
782                            will do this, but we can start detecting the DC
783                            early here. */
784                         set_domain_online_request(domain);
785                 }
786         }
787
788         status = imessaging_register(winbind_imessaging_context(), NULL,
789                                      MSG_WINBIND_NEW_TRUSTED_DOMAIN,
790                                      wb_imsg_new_trusted_domain);
791         if (!NT_STATUS_IS_OK(status)) {
792                 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
793                           nt_errstr(status)));
794                 return false;
795         }
796
797         return True;
798 }
799
800 /**
801  * Given a domain name, return the struct winbindd domain info for it
802  *
803  * @note Do *not* pass lp_workgroup() to this function.  domain_list
804  *       may modify it's value, and free that pointer.  Instead, our local
805  *       domain may be found by calling find_our_domain().
806  *       directly.
807  *
808  *
809  * @return The domain structure for the named domain, if it is working.
810  */
811
812 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
813 {
814         struct winbindd_domain *domain;
815
816         /* Search through list */
817
818         for (domain = domain_list(); domain != NULL; domain = domain->next) {
819                 if (strequal(domain_name, domain->name) ||
820                     (domain->alt_name != NULL &&
821                      strequal(domain_name, domain->alt_name))) {
822                         return domain;
823                 }
824         }
825
826         /* Not found */
827
828         return NULL;
829 }
830
831 struct winbindd_domain *find_domain_from_name(const char *domain_name)
832 {
833         struct winbindd_domain *domain;
834
835         domain = find_domain_from_name_noinit(domain_name);
836
837         if (domain == NULL)
838                 return NULL;
839
840         if (!domain->initialized)
841                 init_dc_connection(domain, false);
842
843         return domain;
844 }
845
846 /* Given a domain sid, return the struct winbindd domain info for it */
847
848 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
849 {
850         struct winbindd_domain *domain;
851
852         /* Search through list */
853
854         for (domain = domain_list(); domain != NULL; domain = domain->next) {
855                 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
856                         return domain;
857         }
858
859         /* Not found */
860
861         return NULL;
862 }
863
864 /* Given a domain sid, return the struct winbindd domain info for it */
865
866 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
867 {
868         struct winbindd_domain *domain;
869
870         domain = find_domain_from_sid_noinit(sid);
871
872         if (domain == NULL)
873                 return NULL;
874
875         if (!domain->initialized)
876                 init_dc_connection(domain, false);
877
878         return domain;
879 }
880
881 struct winbindd_domain *find_our_domain(void)
882 {
883         struct winbindd_domain *domain;
884
885         /* Search through list */
886
887         for (domain = domain_list(); domain != NULL; domain = domain->next) {
888                 if (domain->primary)
889                         return domain;
890         }
891
892         smb_panic("Could not find our domain");
893         return NULL;
894 }
895
896 struct winbindd_domain *find_root_domain(void)
897 {
898         struct winbindd_domain *ours = find_our_domain();
899
900         if (ours->forest_name == NULL) {
901                 return NULL;
902         }
903
904         return find_domain_from_name( ours->forest_name );
905 }
906
907 struct winbindd_domain *find_builtin_domain(void)
908 {
909         struct winbindd_domain *domain;
910
911         domain = find_domain_from_sid(&global_sid_Builtin);
912         if (domain == NULL) {
913                 smb_panic("Could not find BUILTIN domain");
914         }
915
916         return domain;
917 }
918
919 /* Find the appropriate domain to lookup a name or SID */
920
921 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
922 {
923         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
924
925         if ( sid_check_is_in_unix_groups(sid) ||
926              sid_check_is_unix_groups(sid) ||
927              sid_check_is_in_unix_users(sid) ||
928              sid_check_is_unix_users(sid) )
929         {
930                 return find_domain_from_sid(get_global_sam_sid());
931         }
932
933         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
934          * one to contact the external DC's. On member servers the internal
935          * domains are different: These are part of the local SAM. */
936
937         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
938
939         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
940                 DEBUG(10, ("calling find_domain_from_sid\n"));
941                 return find_domain_from_sid(sid);
942         }
943
944         /* On a member server a query for SID or name can always go to our
945          * primary DC. */
946
947         DEBUG(10, ("calling find_our_domain\n"));
948         return find_our_domain();
949 }
950
951 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
952 {
953         if ( strequal(domain_name, unix_users_domain_name() ) ||
954              strequal(domain_name, unix_groups_domain_name() ) )
955         {
956                 /*
957                  * The "Unix User" and "Unix Group" domain our handled by
958                  * passdb
959                  */
960                 return find_domain_from_name_noinit( get_global_sam_name() );
961         }
962
963         if (IS_DC || strequal(domain_name, "BUILTIN") ||
964             strequal(domain_name, get_global_sam_name()))
965                 return find_domain_from_name_noinit(domain_name);
966
967
968         return find_our_domain();
969 }
970
971 /* Is this a domain which we may assume no DOMAIN\ prefix? */
972
973 static bool assume_domain(const char *domain)
974 {
975         /* never assume the domain on a standalone server */
976
977         if ( lp_server_role() == ROLE_STANDALONE )
978                 return False;
979
980         /* domain member servers may possibly assume for the domain name */
981
982         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
983                 if ( !strequal(lp_workgroup(), domain) )
984                         return False;
985
986                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
987                         return True;
988         }
989
990         /* only left with a domain controller */
991
992         if ( strequal(get_global_sam_name(), domain) )  {
993                 return True;
994         }
995
996         return False;
997 }
998
999 /* Parse a string of the form DOMAIN\user into a domain and a user */
1000
1001 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
1002 {
1003         char *p = strchr(domuser,*lp_winbind_separator());
1004
1005         if ( !p ) {
1006                 fstrcpy(user, domuser);
1007
1008                 if ( assume_domain(lp_workgroup())) {
1009                         fstrcpy(domain, lp_workgroup());
1010                 } else if ((p = strchr(domuser, '@')) != NULL) {
1011                         fstrcpy(domain, p + 1);
1012                         user[PTR_DIFF(p, domuser)] = 0;
1013                 } else {
1014                         return False;
1015                 }
1016         } else {
1017                 fstrcpy(user, p+1);
1018                 fstrcpy(domain, domuser);
1019                 domain[PTR_DIFF(p, domuser)] = 0;
1020         }
1021
1022         return strupper_m(domain);
1023 }
1024
1025 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1026                               char **domain, char **user)
1027 {
1028         fstring fstr_domain, fstr_user;
1029         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1030                 return False;
1031         }
1032         *domain = talloc_strdup(mem_ctx, fstr_domain);
1033         *user = talloc_strdup(mem_ctx, fstr_user);
1034         return ((*domain != NULL) && (*user != NULL));
1035 }
1036
1037 /* Ensure an incoming username from NSS is fully qualified. Replace the
1038    incoming fstring with DOMAIN <separator> user. Returns the same
1039    values as parse_domain_user() but also replaces the incoming username.
1040    Used to ensure all names are fully qualified within winbindd.
1041    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1042    The protocol definitions of auth_crap, chng_pswd_auth_crap
1043    really should be changed to use this instead of doing things
1044    by hand. JRA. */
1045
1046 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1047 {
1048         if (!parse_domain_user(username_inout, domain, user)) {
1049                 return False;
1050         }
1051         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1052                  domain, *lp_winbind_separator(),
1053                  user);
1054         return True;
1055 }
1056
1057 /*
1058     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1059     'winbind separator' options.
1060     This means:
1061         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1062         lp_workgroup()
1063
1064     If we are a PDC or BDC, and this is for our domain, do likewise.
1065
1066     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1067     username is then unqualified in unix
1068
1069     On an AD DC we always fill DOMAIN\\USERNAME.
1070
1071     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1072 */
1073 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1074 {
1075         fstring tmp_user;
1076
1077         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1078                 can_assume = false;
1079         }
1080
1081         fstrcpy(tmp_user, user);
1082         (void)strlower_m(tmp_user);
1083
1084         if (can_assume && assume_domain(domain)) {
1085                 strlcpy(name, tmp_user, sizeof(fstring));
1086         } else {
1087                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1088                          domain, *lp_winbind_separator(),
1089                          tmp_user);
1090         }
1091 }
1092
1093 /**
1094  * talloc version of fill_domain_username()
1095  * return NULL on talloc failure.
1096  */
1097 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1098                                   const char *domain,
1099                                   const char *user,
1100                                   bool can_assume)
1101 {
1102         char *tmp_user, *name;
1103
1104         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1105                 can_assume = false;
1106         }
1107
1108         tmp_user = talloc_strdup(mem_ctx, user);
1109         if (!strlower_m(tmp_user)) {
1110                 TALLOC_FREE(tmp_user);
1111                 return NULL;
1112         }
1113
1114         if (can_assume && assume_domain(domain)) {
1115                 name = tmp_user;
1116         } else {
1117                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1118                                        domain,
1119                                        *lp_winbind_separator(),
1120                                        tmp_user);
1121                 TALLOC_FREE(tmp_user);
1122         }
1123
1124         return name;
1125 }
1126
1127 /*
1128  * Client list accessor functions
1129  */
1130
1131 static struct winbindd_cli_state *_client_list;
1132 static int _num_clients;
1133
1134 /* Return list of all connected clients */
1135
1136 struct winbindd_cli_state *winbindd_client_list(void)
1137 {
1138         return _client_list;
1139 }
1140
1141 /* Add a connection to the list */
1142
1143 void winbindd_add_client(struct winbindd_cli_state *cli)
1144 {
1145         DLIST_ADD(_client_list, cli);
1146         _num_clients++;
1147 }
1148
1149 /* Remove a client from the list */
1150
1151 void winbindd_remove_client(struct winbindd_cli_state *cli)
1152 {
1153         DLIST_REMOVE(_client_list, cli);
1154         _num_clients--;
1155 }
1156
1157 /* Return number of open clients */
1158
1159 int winbindd_num_clients(void)
1160 {
1161         return _num_clients;
1162 }
1163
1164 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1165                                   TALLOC_CTX *mem_ctx,
1166                                   const struct dom_sid *user_sid,
1167                                   uint32_t *p_num_groups, struct dom_sid **user_sids)
1168 {
1169         struct netr_SamInfo3 *info3 = NULL;
1170         NTSTATUS status = NT_STATUS_NO_MEMORY;
1171         uint32_t num_groups = 0;
1172
1173         DEBUG(3,(": lookup_usergroups_cached\n"));
1174
1175         *user_sids = NULL;
1176         *p_num_groups = 0;
1177
1178         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1179
1180         if (info3 == NULL) {
1181                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1182         }
1183
1184         if (info3->base.groups.count == 0) {
1185                 TALLOC_FREE(info3);
1186                 return NT_STATUS_UNSUCCESSFUL;
1187         }
1188
1189         /*
1190          * Before bug #7843 the "Domain Local" groups were added with a
1191          * lookupuseraliases call, but this isn't done anymore for our domain
1192          * so we need to resolve resource groups here.
1193          *
1194          * When to use Resource Groups:
1195          * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1196          */
1197         status = sid_array_from_info3(mem_ctx, info3,
1198                                       user_sids,
1199                                       &num_groups,
1200                                       false);
1201
1202         if (!NT_STATUS_IS_OK(status)) {
1203                 TALLOC_FREE(info3);
1204                 return status;
1205         }
1206
1207         TALLOC_FREE(info3);
1208         *p_num_groups = num_groups;
1209         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1210
1211         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1212
1213         return status;
1214 }
1215
1216 /*********************************************************************
1217  We use this to remove spaces from user and group names
1218 ********************************************************************/
1219
1220 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1221                              struct winbindd_domain *domain,
1222                              const char *name,
1223                              char **normalized)
1224 {
1225         NTSTATUS nt_status;
1226
1227         if (!name || !normalized) {
1228                 return NT_STATUS_INVALID_PARAMETER;
1229         }
1230
1231         if (!lp_winbind_normalize_names()) {
1232                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1233         }
1234
1235         /* Alias support and whitespace replacement are mutually
1236            exclusive */
1237
1238         nt_status = resolve_username_to_alias(mem_ctx, domain,
1239                                               name, normalized );
1240         if (NT_STATUS_IS_OK(nt_status)) {
1241                 /* special return code to let the caller know we
1242                    mapped to an alias */
1243                 return NT_STATUS_FILE_RENAMED;
1244         }
1245
1246         /* check for an unreachable domain */
1247
1248         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1249                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1250                          domain->name));
1251                 set_domain_offline(domain);
1252                 return nt_status;
1253         }
1254
1255         /* deal with whitespace */
1256
1257         *normalized = talloc_strdup(mem_ctx, name);
1258         if (!(*normalized)) {
1259                 return NT_STATUS_NO_MEMORY;
1260         }
1261
1262         all_string_sub( *normalized, " ", "_", 0 );
1263
1264         return NT_STATUS_OK;
1265 }
1266
1267 /*********************************************************************
1268  We use this to do the inverse of normalize_name_map()
1269 ********************************************************************/
1270
1271 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1272                               char *name,
1273                               char **normalized)
1274 {
1275         NTSTATUS nt_status;
1276         struct winbindd_domain *domain = find_our_domain();
1277
1278         if (!name || !normalized) {
1279                 return NT_STATUS_INVALID_PARAMETER;
1280         }
1281
1282         if (!lp_winbind_normalize_names()) {
1283                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1284         }
1285
1286         /* Alias support and whitespace replacement are mutally
1287            exclusive */
1288
1289         /* When mapping from an alias to a username, we don't know the
1290            domain.  But we only need a domain structure to cache
1291            a successful lookup , so just our own domain structure for
1292            the seqnum. */
1293
1294         nt_status = resolve_alias_to_username(mem_ctx, domain,
1295                                               name, normalized);
1296         if (NT_STATUS_IS_OK(nt_status)) {
1297                 /* Special return code to let the caller know we mapped
1298                    from an alias */
1299                 return NT_STATUS_FILE_RENAMED;
1300         }
1301
1302         /* check for an unreachable domain */
1303
1304         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1305                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1306                          domain->name));
1307                 set_domain_offline(domain);
1308                 return nt_status;
1309         }
1310
1311         /* deal with whitespace */
1312
1313         *normalized = talloc_strdup(mem_ctx, name);
1314         if (!(*normalized)) {
1315                 return NT_STATUS_NO_MEMORY;
1316         }
1317
1318         all_string_sub(*normalized, "_", " ", 0);
1319
1320         return NT_STATUS_OK;
1321 }
1322
1323 /*********************************************************************
1324  ********************************************************************/
1325
1326 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1327 {
1328         struct winbindd_tdc_domain *tdc = NULL;
1329         TALLOC_CTX *frame = talloc_stackframe();
1330         bool ret = false;
1331
1332         /* We can contact the domain if it is our primary domain */
1333
1334         if (domain->primary) {
1335                 ret = true;
1336                 goto done;
1337         }
1338
1339         /* Trust the TDC cache and not the winbindd_domain flags */
1340
1341         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1342                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1343                           domain->name));
1344                 ret = false;
1345                 goto done;
1346         }
1347
1348         /* Can always contact a domain that is in out forest */
1349
1350         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1351                 ret = true;
1352                 goto done;
1353         }
1354
1355         /*
1356          * On a _member_ server, we cannot contact the domain if it
1357          * is running AD and we have no inbound trust.
1358          */
1359
1360         if (!IS_DC &&
1361              domain->active_directory &&
1362             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1363         {
1364                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1365                            "and we have no inbound trust.\n", domain->name));
1366                 goto done;
1367         }
1368
1369         /* Assume everything else is ok (probably not true but what
1370            can you do?) */
1371
1372         ret = true;
1373
1374 done:
1375         talloc_destroy(frame);
1376
1377         return ret;
1378 }
1379
1380 /*********************************************************************
1381  ********************************************************************/
1382
1383 bool winbindd_internal_child(struct winbindd_child *child)
1384 {
1385         if ((child == idmap_child()) || (child == locator_child())) {
1386                 return True;
1387         }
1388
1389         return False;
1390 }
1391
1392 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1393
1394 /*********************************************************************
1395  ********************************************************************/
1396
1397 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1398 {
1399         char *var = NULL;
1400         char addr[INET6_ADDRSTRLEN];
1401         const char *kdc = NULL;
1402         int lvl = 11;
1403
1404         if (!domain || !domain->alt_name || !*domain->alt_name) {
1405                 return;
1406         }
1407
1408         if (domain->initialized && !domain->active_directory) {
1409                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1410                         domain->alt_name));
1411                 return;
1412         }
1413
1414         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1415         kdc = addr;
1416         if (!*kdc) {
1417                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1418                         domain->alt_name));
1419                 kdc = domain->dcname;
1420         }
1421
1422         if (!kdc || !*kdc) {
1423                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1424                         domain->alt_name));
1425                 return;
1426         }
1427
1428         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1429                                 domain->alt_name) == -1) {
1430                 return;
1431         }
1432
1433         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1434                 var, kdc));
1435
1436         setenv(var, kdc, 1);
1437         free(var);
1438 }
1439
1440 /*********************************************************************
1441  ********************************************************************/
1442
1443 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1444 {
1445         struct winbindd_domain *our_dom = find_our_domain();
1446
1447         winbindd_set_locator_kdc_env(domain);
1448
1449         if (domain != our_dom) {
1450                 winbindd_set_locator_kdc_env(our_dom);
1451         }
1452 }
1453
1454 /*********************************************************************
1455  ********************************************************************/
1456
1457 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1458 {
1459         char *var = NULL;
1460
1461         if (!domain || !domain->alt_name || !*domain->alt_name) {
1462                 return;
1463         }
1464
1465         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1466                                 domain->alt_name) == -1) {
1467                 return;
1468         }
1469
1470         unsetenv(var);
1471         free(var);
1472 }
1473 #else
1474
1475 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1476 {
1477         return;
1478 }
1479
1480 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1481 {
1482         return;
1483 }
1484
1485 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1486
1487 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1488 {
1489         resp->data.auth.nt_status = NT_STATUS_V(result);
1490         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1491
1492         /* we might have given a more useful error above */
1493         if (*resp->data.auth.error_string == '\0')
1494                 fstrcpy(resp->data.auth.error_string,
1495                         get_friendly_nt_error_msg(result));
1496         resp->data.auth.pam_error = nt_status_to_pam(result);
1497 }
1498
1499 bool is_domain_offline(const struct winbindd_domain *domain)
1500 {
1501         if (!lp_winbind_offline_logon()) {
1502                 return false;
1503         }
1504         if (get_global_winbindd_state_offline()) {
1505                 return true;
1506         }
1507         return !domain->online;
1508 }
1509
1510 bool is_domain_online(const struct winbindd_domain *domain)
1511 {
1512         return !is_domain_offline(domain);
1513 }
1514
1515 /**
1516  * Parse an char array into a list of sids.
1517  *
1518  * The input sidstr should consist of 0-terminated strings
1519  * representing sids, separated by newline characters '\n'.
1520  * The list is terminated by an empty string, i.e.
1521  * character '\0' directly following a character '\n'
1522  * (or '\0' right at the start of sidstr).
1523  */
1524 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1525                    struct dom_sid **sids, uint32_t *num_sids)
1526 {
1527         const char *p;
1528
1529         p = sidstr;
1530         if (p == NULL)
1531                 return False;
1532
1533         while (p[0] != '\0') {
1534                 struct dom_sid sid;
1535                 const char *q = NULL;
1536
1537                 if (!dom_sid_parse_endp(p, &sid, &q)) {
1538                         DEBUG(1, ("Could not parse sid %s\n", p));
1539                         return false;
1540                 }
1541                 if ((q == NULL) || (q[0] != '\n')) {
1542                         DEBUG(1, ("Got invalid sidstr: %s\n", p));
1543                         return false;
1544                 }
1545                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1546                                                       num_sids)))
1547                 {
1548                         return False;
1549                 }
1550                 p = q+1;
1551         }
1552         return True;
1553 }