s3:winbindd: list users/groups of our own domain as AD DC
[samba.git] / source3 / winbindd / winbindd_util.c
1 /*
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon for ntdom nss module
5
6    Copyright (C) Tim Potter 2000-2001
7    Copyright (C) 2001 by Martin Pool <mbp@samba.org>
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "winbindd.h"
25 #include "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                 bool ok;
726
727                 domain = add_trusted_domain(get_global_sam_name(), lp_dnsdomain(),
728                                             &cache_methods, get_global_sam_sid());
729                 if (domain == NULL) {
730                         DEBUG(0, ("Failed to add our own, local AD domain to winbindd's internal list\n"));
731                         return false;
732                 }
733
734                 /*
735                  * We need to call this to find out if we are an RODC
736                  */
737                 ok = get_trust_pw_hash(domain->name,
738                                        current_nt_hash.hash,
739                                        &account_name,
740                                        &sec_chan_type);
741                 if (!ok) {
742                         DEBUG(0, ("Failed to fetch our own, local AD domain join password for winbindd's internal use\n"));
743                         return false;
744                 }
745                 if (sec_chan_type == SEC_CHAN_RODC) {
746                         domain->rodc = true;
747                 }
748
749         } else {
750                 (void)add_trusted_domain(get_global_sam_name(), NULL,
751                                          &cache_methods, get_global_sam_sid());
752         }
753         /* Add ourselves as the first entry. */
754
755         if ( role == ROLE_DOMAIN_MEMBER ) {
756                 struct winbindd_domain *domain;
757                 struct dom_sid our_sid;
758
759                 if (!secrets_fetch_domain_sid(lp_workgroup(), &our_sid)) {
760                         DEBUG(0, ("Could not fetch our SID - did we join?\n"));
761                         return False;
762                 }
763
764                 domain = add_trusted_domain( lp_workgroup(), lp_realm(),
765                                              &cache_methods, &our_sid);
766                 if (domain) {
767                         /* Even in the parent winbindd we'll need to
768                            talk to the DC, so try and see if we can
769                            contact it. Theoretically this isn't neccessary
770                            as the init_dc_connection() in init_child_recv()
771                            will do this, but we can start detecting the DC
772                            early here. */
773                         set_domain_online_request(domain);
774                 }
775         }
776
777         status = imessaging_register(winbind_imessaging_context(), NULL,
778                                      MSG_WINBIND_NEW_TRUSTED_DOMAIN,
779                                      wb_imsg_new_trusted_domain);
780         if (!NT_STATUS_IS_OK(status)) {
781                 DEBUG(0, ("imessaging_register(MSG_WINBIND_NEW_TRUSTED_DOMAIN) - %s\n",
782                           nt_errstr(status)));
783                 return false;
784         }
785
786         return True;
787 }
788
789 /**
790  * Given a domain name, return the struct winbindd domain info for it
791  *
792  * @note Do *not* pass lp_workgroup() to this function.  domain_list
793  *       may modify it's value, and free that pointer.  Instead, our local
794  *       domain may be found by calling find_our_domain().
795  *       directly.
796  *
797  *
798  * @return The domain structure for the named domain, if it is working.
799  */
800
801 struct winbindd_domain *find_domain_from_name_noinit(const char *domain_name)
802 {
803         struct winbindd_domain *domain;
804
805         /* Search through list */
806
807         for (domain = domain_list(); domain != NULL; domain = domain->next) {
808                 if (strequal(domain_name, domain->name) ||
809                     (domain->alt_name != NULL &&
810                      strequal(domain_name, domain->alt_name))) {
811                         return domain;
812                 }
813         }
814
815         /* Not found */
816
817         return NULL;
818 }
819
820 struct winbindd_domain *find_domain_from_name(const char *domain_name)
821 {
822         struct winbindd_domain *domain;
823
824         domain = find_domain_from_name_noinit(domain_name);
825
826         if (domain == NULL)
827                 return NULL;
828
829         if (!domain->initialized)
830                 init_dc_connection(domain, false);
831
832         return domain;
833 }
834
835 /* Given a domain sid, return the struct winbindd domain info for it */
836
837 struct winbindd_domain *find_domain_from_sid_noinit(const struct dom_sid *sid)
838 {
839         struct winbindd_domain *domain;
840
841         /* Search through list */
842
843         for (domain = domain_list(); domain != NULL; domain = domain->next) {
844                 if (dom_sid_compare_domain(sid, &domain->sid) == 0)
845                         return domain;
846         }
847
848         /* Not found */
849
850         return NULL;
851 }
852
853 /* Given a domain sid, return the struct winbindd domain info for it */
854
855 struct winbindd_domain *find_domain_from_sid(const struct dom_sid *sid)
856 {
857         struct winbindd_domain *domain;
858
859         domain = find_domain_from_sid_noinit(sid);
860
861         if (domain == NULL)
862                 return NULL;
863
864         if (!domain->initialized)
865                 init_dc_connection(domain, false);
866
867         return domain;
868 }
869
870 struct winbindd_domain *find_our_domain(void)
871 {
872         struct winbindd_domain *domain;
873
874         /* Search through list */
875
876         for (domain = domain_list(); domain != NULL; domain = domain->next) {
877                 if (domain->primary)
878                         return domain;
879         }
880
881         smb_panic("Could not find our domain");
882         return NULL;
883 }
884
885 struct winbindd_domain *find_root_domain(void)
886 {
887         struct winbindd_domain *ours = find_our_domain();
888
889         if (ours->forest_name == NULL) {
890                 return NULL;
891         }
892
893         return find_domain_from_name( ours->forest_name );
894 }
895
896 struct winbindd_domain *find_builtin_domain(void)
897 {
898         struct winbindd_domain *domain;
899
900         domain = find_domain_from_sid(&global_sid_Builtin);
901         if (domain == NULL) {
902                 smb_panic("Could not find BUILTIN domain");
903         }
904
905         return domain;
906 }
907
908 /* Find the appropriate domain to lookup a name or SID */
909
910 struct winbindd_domain *find_lookup_domain_from_sid(const struct dom_sid *sid)
911 {
912         /* SIDs in the S-1-22-{1,2} domain should be handled by our passdb */
913
914         if ( sid_check_is_in_unix_groups(sid) ||
915              sid_check_is_unix_groups(sid) ||
916              sid_check_is_in_unix_users(sid) ||
917              sid_check_is_unix_users(sid) )
918         {
919                 return find_domain_from_sid(get_global_sam_sid());
920         }
921
922         /* A DC can't ask the local smbd for remote SIDs, here winbindd is the
923          * one to contact the external DC's. On member servers the internal
924          * domains are different: These are part of the local SAM. */
925
926         DEBUG(10, ("find_lookup_domain_from_sid(%s)\n", sid_string_dbg(sid)));
927
928         if (IS_DC || is_internal_domain(sid) || is_in_internal_domain(sid)) {
929                 DEBUG(10, ("calling find_domain_from_sid\n"));
930                 return find_domain_from_sid(sid);
931         }
932
933         /* On a member server a query for SID or name can always go to our
934          * primary DC. */
935
936         DEBUG(10, ("calling find_our_domain\n"));
937         return find_our_domain();
938 }
939
940 struct winbindd_domain *find_lookup_domain_from_name(const char *domain_name)
941 {
942         if ( strequal(domain_name, unix_users_domain_name() ) ||
943              strequal(domain_name, unix_groups_domain_name() ) )
944         {
945                 /*
946                  * The "Unix User" and "Unix Group" domain our handled by
947                  * passdb
948                  */
949                 return find_domain_from_name_noinit( get_global_sam_name() );
950         }
951
952         if (IS_DC || strequal(domain_name, "BUILTIN") ||
953             strequal(domain_name, get_global_sam_name()))
954                 return find_domain_from_name_noinit(domain_name);
955
956
957         return find_our_domain();
958 }
959
960 /* Is this a domain which we may assume no DOMAIN\ prefix? */
961
962 static bool assume_domain(const char *domain)
963 {
964         /* never assume the domain on a standalone server */
965
966         if ( lp_server_role() == ROLE_STANDALONE )
967                 return False;
968
969         /* domain member servers may possibly assume for the domain name */
970
971         if ( lp_server_role() == ROLE_DOMAIN_MEMBER ) {
972                 if ( !strequal(lp_workgroup(), domain) )
973                         return False;
974
975                 if ( lp_winbind_use_default_domain() || lp_winbind_trusted_domains_only() )
976                         return True;
977         }
978
979         /* only left with a domain controller */
980
981         if ( strequal(get_global_sam_name(), domain) )  {
982                 return True;
983         }
984
985         return False;
986 }
987
988 /* Parse a string of the form DOMAIN\user into a domain and a user */
989
990 bool parse_domain_user(const char *domuser, fstring domain, fstring user)
991 {
992         char *p = strchr(domuser,*lp_winbind_separator());
993
994         if ( !p ) {
995                 fstrcpy(user, domuser);
996
997                 if ( assume_domain(lp_workgroup())) {
998                         fstrcpy(domain, lp_workgroup());
999                 } else if ((p = strchr(domuser, '@')) != NULL) {
1000                         fstrcpy(domain, p + 1);
1001                         user[PTR_DIFF(p, domuser)] = 0;
1002                 } else {
1003                         return False;
1004                 }
1005         } else {
1006                 fstrcpy(user, p+1);
1007                 fstrcpy(domain, domuser);
1008                 domain[PTR_DIFF(p, domuser)] = 0;
1009         }
1010
1011         return strupper_m(domain);
1012 }
1013
1014 bool parse_domain_user_talloc(TALLOC_CTX *mem_ctx, const char *domuser,
1015                               char **domain, char **user)
1016 {
1017         fstring fstr_domain, fstr_user;
1018         if (!parse_domain_user(domuser, fstr_domain, fstr_user)) {
1019                 return False;
1020         }
1021         *domain = talloc_strdup(mem_ctx, fstr_domain);
1022         *user = talloc_strdup(mem_ctx, fstr_user);
1023         return ((*domain != NULL) && (*user != NULL));
1024 }
1025
1026 /* Ensure an incoming username from NSS is fully qualified. Replace the
1027    incoming fstring with DOMAIN <separator> user. Returns the same
1028    values as parse_domain_user() but also replaces the incoming username.
1029    Used to ensure all names are fully qualified within winbindd.
1030    Used by the NSS protocols of auth, chauthtok, logoff and ccache_ntlm_auth.
1031    The protocol definitions of auth_crap, chng_pswd_auth_crap
1032    really should be changed to use this instead of doing things
1033    by hand. JRA. */
1034
1035 bool canonicalize_username(fstring username_inout, fstring domain, fstring user)
1036 {
1037         if (!parse_domain_user(username_inout, domain, user)) {
1038                 return False;
1039         }
1040         slprintf(username_inout, sizeof(fstring) - 1, "%s%c%s",
1041                  domain, *lp_winbind_separator(),
1042                  user);
1043         return True;
1044 }
1045
1046 /*
1047     Fill DOMAIN\\USERNAME entry accounting 'winbind use default domain' and
1048     'winbind separator' options.
1049     This means:
1050         - omit DOMAIN when 'winbind use default domain = true' and DOMAIN is
1051         lp_workgroup()
1052
1053     If we are a PDC or BDC, and this is for our domain, do likewise.
1054
1055     Also, if omit DOMAIN if 'winbind trusted domains only = true', as the
1056     username is then unqualified in unix
1057
1058     On an AD DC we always fill DOMAIN\\USERNAME.
1059
1060     We always canonicalize as UPPERCASE DOMAIN, lowercase username.
1061 */
1062 void fill_domain_username(fstring name, const char *domain, const char *user, bool can_assume)
1063 {
1064         fstring tmp_user;
1065
1066         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1067                 can_assume = false;
1068         }
1069
1070         fstrcpy(tmp_user, user);
1071         (void)strlower_m(tmp_user);
1072
1073         if (can_assume && assume_domain(domain)) {
1074                 strlcpy(name, tmp_user, sizeof(fstring));
1075         } else {
1076                 slprintf(name, sizeof(fstring) - 1, "%s%c%s",
1077                          domain, *lp_winbind_separator(),
1078                          tmp_user);
1079         }
1080 }
1081
1082 /**
1083  * talloc version of fill_domain_username()
1084  * return NULL on talloc failure.
1085  */
1086 char *fill_domain_username_talloc(TALLOC_CTX *mem_ctx,
1087                                   const char *domain,
1088                                   const char *user,
1089                                   bool can_assume)
1090 {
1091         char *tmp_user, *name;
1092
1093         if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
1094                 can_assume = false;
1095         }
1096
1097         tmp_user = talloc_strdup(mem_ctx, user);
1098         if (!strlower_m(tmp_user)) {
1099                 TALLOC_FREE(tmp_user);
1100                 return NULL;
1101         }
1102
1103         if (can_assume && assume_domain(domain)) {
1104                 name = tmp_user;
1105         } else {
1106                 name = talloc_asprintf(mem_ctx, "%s%c%s",
1107                                        domain,
1108                                        *lp_winbind_separator(),
1109                                        tmp_user);
1110                 TALLOC_FREE(tmp_user);
1111         }
1112
1113         return name;
1114 }
1115
1116 /*
1117  * Client list accessor functions
1118  */
1119
1120 static struct winbindd_cli_state *_client_list;
1121 static int _num_clients;
1122
1123 /* Return list of all connected clients */
1124
1125 struct winbindd_cli_state *winbindd_client_list(void)
1126 {
1127         return _client_list;
1128 }
1129
1130 /* Add a connection to the list */
1131
1132 void winbindd_add_client(struct winbindd_cli_state *cli)
1133 {
1134         DLIST_ADD(_client_list, cli);
1135         _num_clients++;
1136 }
1137
1138 /* Remove a client from the list */
1139
1140 void winbindd_remove_client(struct winbindd_cli_state *cli)
1141 {
1142         DLIST_REMOVE(_client_list, cli);
1143         _num_clients--;
1144 }
1145
1146 /* Return number of open clients */
1147
1148 int winbindd_num_clients(void)
1149 {
1150         return _num_clients;
1151 }
1152
1153 NTSTATUS lookup_usergroups_cached(struct winbindd_domain *domain,
1154                                   TALLOC_CTX *mem_ctx,
1155                                   const struct dom_sid *user_sid,
1156                                   uint32_t *p_num_groups, struct dom_sid **user_sids)
1157 {
1158         struct netr_SamInfo3 *info3 = NULL;
1159         NTSTATUS status = NT_STATUS_NO_MEMORY;
1160         uint32_t num_groups = 0;
1161
1162         DEBUG(3,(": lookup_usergroups_cached\n"));
1163
1164         *user_sids = NULL;
1165         *p_num_groups = 0;
1166
1167         info3 = netsamlogon_cache_get(mem_ctx, user_sid);
1168
1169         if (info3 == NULL) {
1170                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
1171         }
1172
1173         if (info3->base.groups.count == 0) {
1174                 TALLOC_FREE(info3);
1175                 return NT_STATUS_UNSUCCESSFUL;
1176         }
1177
1178         /*
1179          * Before bug #7843 the "Domain Local" groups were added with a
1180          * lookupuseraliases call, but this isn't done anymore for our domain
1181          * so we need to resolve resource groups here.
1182          *
1183          * When to use Resource Groups:
1184          * http://technet.microsoft.com/en-us/library/cc753670%28v=WS.10%29.aspx
1185          */
1186         status = sid_array_from_info3(mem_ctx, info3,
1187                                       user_sids,
1188                                       &num_groups,
1189                                       false);
1190
1191         if (!NT_STATUS_IS_OK(status)) {
1192                 TALLOC_FREE(info3);
1193                 return status;
1194         }
1195
1196         TALLOC_FREE(info3);
1197         *p_num_groups = num_groups;
1198         status = (user_sids != NULL) ? NT_STATUS_OK : NT_STATUS_NO_MEMORY;
1199
1200         DEBUG(3,(": lookup_usergroups_cached succeeded\n"));
1201
1202         return status;
1203 }
1204
1205 /*********************************************************************
1206  We use this to remove spaces from user and group names
1207 ********************************************************************/
1208
1209 NTSTATUS normalize_name_map(TALLOC_CTX *mem_ctx,
1210                              struct winbindd_domain *domain,
1211                              const char *name,
1212                              char **normalized)
1213 {
1214         NTSTATUS nt_status;
1215
1216         if (!name || !normalized) {
1217                 return NT_STATUS_INVALID_PARAMETER;
1218         }
1219
1220         if (!lp_winbind_normalize_names()) {
1221                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1222         }
1223
1224         /* Alias support and whitespace replacement are mutually
1225            exclusive */
1226
1227         nt_status = resolve_username_to_alias(mem_ctx, domain,
1228                                               name, normalized );
1229         if (NT_STATUS_IS_OK(nt_status)) {
1230                 /* special return code to let the caller know we
1231                    mapped to an alias */
1232                 return NT_STATUS_FILE_RENAMED;
1233         }
1234
1235         /* check for an unreachable domain */
1236
1237         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1238                 DEBUG(5,("normalize_name_map: Setting domain %s offline\n",
1239                          domain->name));
1240                 set_domain_offline(domain);
1241                 return nt_status;
1242         }
1243
1244         /* deal with whitespace */
1245
1246         *normalized = talloc_strdup(mem_ctx, name);
1247         if (!(*normalized)) {
1248                 return NT_STATUS_NO_MEMORY;
1249         }
1250
1251         all_string_sub( *normalized, " ", "_", 0 );
1252
1253         return NT_STATUS_OK;
1254 }
1255
1256 /*********************************************************************
1257  We use this to do the inverse of normalize_name_map()
1258 ********************************************************************/
1259
1260 NTSTATUS normalize_name_unmap(TALLOC_CTX *mem_ctx,
1261                               char *name,
1262                               char **normalized)
1263 {
1264         NTSTATUS nt_status;
1265         struct winbindd_domain *domain = find_our_domain();
1266
1267         if (!name || !normalized) {
1268                 return NT_STATUS_INVALID_PARAMETER;
1269         }
1270
1271         if (!lp_winbind_normalize_names()) {
1272                 return NT_STATUS_PROCEDURE_NOT_FOUND;
1273         }
1274
1275         /* Alias support and whitespace replacement are mutally
1276            exclusive */
1277
1278         /* When mapping from an alias to a username, we don't know the
1279            domain.  But we only need a domain structure to cache
1280            a successful lookup , so just our own domain structure for
1281            the seqnum. */
1282
1283         nt_status = resolve_alias_to_username(mem_ctx, domain,
1284                                               name, normalized);
1285         if (NT_STATUS_IS_OK(nt_status)) {
1286                 /* Special return code to let the caller know we mapped
1287                    from an alias */
1288                 return NT_STATUS_FILE_RENAMED;
1289         }
1290
1291         /* check for an unreachable domain */
1292
1293         if (NT_STATUS_EQUAL(nt_status, NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND)) {
1294                 DEBUG(5,("normalize_name_unmap: Setting domain %s offline\n",
1295                          domain->name));
1296                 set_domain_offline(domain);
1297                 return nt_status;
1298         }
1299
1300         /* deal with whitespace */
1301
1302         *normalized = talloc_strdup(mem_ctx, name);
1303         if (!(*normalized)) {
1304                 return NT_STATUS_NO_MEMORY;
1305         }
1306
1307         all_string_sub(*normalized, "_", " ", 0);
1308
1309         return NT_STATUS_OK;
1310 }
1311
1312 /*********************************************************************
1313  ********************************************************************/
1314
1315 bool winbindd_can_contact_domain(struct winbindd_domain *domain)
1316 {
1317         struct winbindd_tdc_domain *tdc = NULL;
1318         TALLOC_CTX *frame = talloc_stackframe();
1319         bool ret = false;
1320
1321         /* We can contact the domain if it is our primary domain */
1322
1323         if (domain->primary) {
1324                 ret = true;
1325                 goto done;
1326         }
1327
1328         /* Trust the TDC cache and not the winbindd_domain flags */
1329
1330         if ((tdc = wcache_tdc_fetch_domain(frame, domain->name)) == NULL) {
1331                 DEBUG(10,("winbindd_can_contact_domain: %s not found in cache\n",
1332                           domain->name));
1333                 ret = false;
1334                 goto done;
1335         }
1336
1337         /* Can always contact a domain that is in out forest */
1338
1339         if (tdc->trust_flags & NETR_TRUST_FLAG_IN_FOREST) {
1340                 ret = true;
1341                 goto done;
1342         }
1343
1344         /*
1345          * On a _member_ server, we cannot contact the domain if it
1346          * is running AD and we have no inbound trust.
1347          */
1348
1349         if (!IS_DC &&
1350              domain->active_directory &&
1351             ((tdc->trust_flags & NETR_TRUST_FLAG_INBOUND) != NETR_TRUST_FLAG_INBOUND))
1352         {
1353                 DEBUG(10, ("winbindd_can_contact_domain: %s is an AD domain "
1354                            "and we have no inbound trust.\n", domain->name));
1355                 goto done;
1356         }
1357
1358         /* Assume everything else is ok (probably not true but what
1359            can you do?) */
1360
1361         ret = true;
1362
1363 done:
1364         talloc_destroy(frame);
1365
1366         return ret;
1367 }
1368
1369 /*********************************************************************
1370  ********************************************************************/
1371
1372 bool winbindd_internal_child(struct winbindd_child *child)
1373 {
1374         if ((child == idmap_child()) || (child == locator_child())) {
1375                 return True;
1376         }
1377
1378         return False;
1379 }
1380
1381 #ifdef HAVE_KRB5_LOCATE_PLUGIN_H
1382
1383 /*********************************************************************
1384  ********************************************************************/
1385
1386 static void winbindd_set_locator_kdc_env(const struct winbindd_domain *domain)
1387 {
1388         char *var = NULL;
1389         char addr[INET6_ADDRSTRLEN];
1390         const char *kdc = NULL;
1391         int lvl = 11;
1392
1393         if (!domain || !domain->alt_name || !*domain->alt_name) {
1394                 return;
1395         }
1396
1397         if (domain->initialized && !domain->active_directory) {
1398                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s not AD\n",
1399                         domain->alt_name));
1400                 return;
1401         }
1402
1403         print_sockaddr(addr, sizeof(addr), &domain->dcaddr);
1404         kdc = addr;
1405         if (!*kdc) {
1406                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC IP\n",
1407                         domain->alt_name));
1408                 kdc = domain->dcname;
1409         }
1410
1411         if (!kdc || !*kdc) {
1412                 DEBUG(lvl,("winbindd_set_locator_kdc_env: %s no DC at all\n",
1413                         domain->alt_name));
1414                 return;
1415         }
1416
1417         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1418                                 domain->alt_name) == -1) {
1419                 return;
1420         }
1421
1422         DEBUG(lvl,("winbindd_set_locator_kdc_env: setting var: %s to: %s\n",
1423                 var, kdc));
1424
1425         setenv(var, kdc, 1);
1426         free(var);
1427 }
1428
1429 /*********************************************************************
1430  ********************************************************************/
1431
1432 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1433 {
1434         struct winbindd_domain *our_dom = find_our_domain();
1435
1436         winbindd_set_locator_kdc_env(domain);
1437
1438         if (domain != our_dom) {
1439                 winbindd_set_locator_kdc_env(our_dom);
1440         }
1441 }
1442
1443 /*********************************************************************
1444  ********************************************************************/
1445
1446 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1447 {
1448         char *var = NULL;
1449
1450         if (!domain || !domain->alt_name || !*domain->alt_name) {
1451                 return;
1452         }
1453
1454         if (asprintf_strupper_m(&var, "%s_%s", WINBINDD_LOCATOR_KDC_ADDRESS,
1455                                 domain->alt_name) == -1) {
1456                 return;
1457         }
1458
1459         unsetenv(var);
1460         free(var);
1461 }
1462 #else
1463
1464 void winbindd_set_locator_kdc_envs(const struct winbindd_domain *domain)
1465 {
1466         return;
1467 }
1468
1469 void winbindd_unset_locator_kdc_env(const struct winbindd_domain *domain)
1470 {
1471         return;
1472 }
1473
1474 #endif /* HAVE_KRB5_LOCATE_PLUGIN_H */
1475
1476 void set_auth_errors(struct winbindd_response *resp, NTSTATUS result)
1477 {
1478         resp->data.auth.nt_status = NT_STATUS_V(result);
1479         fstrcpy(resp->data.auth.nt_status_string, nt_errstr(result));
1480
1481         /* we might have given a more useful error above */
1482         if (*resp->data.auth.error_string == '\0')
1483                 fstrcpy(resp->data.auth.error_string,
1484                         get_friendly_nt_error_msg(result));
1485         resp->data.auth.pam_error = nt_status_to_pam(result);
1486 }
1487
1488 bool is_domain_offline(const struct winbindd_domain *domain)
1489 {
1490         if (!lp_winbind_offline_logon()) {
1491                 return false;
1492         }
1493         if (get_global_winbindd_state_offline()) {
1494                 return true;
1495         }
1496         return !domain->online;
1497 }
1498
1499 bool is_domain_online(const struct winbindd_domain *domain)
1500 {
1501         return !is_domain_offline(domain);
1502 }
1503
1504 /**
1505  * Parse an char array into a list of sids.
1506  *
1507  * The input sidstr should consist of 0-terminated strings
1508  * representing sids, separated by newline characters '\n'.
1509  * The list is terminated by an empty string, i.e.
1510  * character '\0' directly following a character '\n'
1511  * (or '\0' right at the start of sidstr).
1512  */
1513 bool parse_sidlist(TALLOC_CTX *mem_ctx, const char *sidstr,
1514                    struct dom_sid **sids, uint32_t *num_sids)
1515 {
1516         const char *p;
1517
1518         p = sidstr;
1519         if (p == NULL)
1520                 return False;
1521
1522         while (p[0] != '\0') {
1523                 struct dom_sid sid;
1524                 const char *q = NULL;
1525
1526                 if (!dom_sid_parse_endp(p, &sid, &q)) {
1527                         DEBUG(1, ("Could not parse sid %s\n", p));
1528                         return false;
1529                 }
1530                 if ((q == NULL) || (q[0] != '\n')) {
1531                         DEBUG(1, ("Got invalid sidstr: %s\n", p));
1532                         return false;
1533                 }
1534                 if (!NT_STATUS_IS_OK(add_sid_to_array(mem_ctx, &sid, sids,
1535                                                       num_sids)))
1536                 {
1537                         return False;
1538                 }
1539                 p = q+1;
1540         }
1541         return True;
1542 }