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