1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2020 Joyent, Inc.
25 */
26
27 #include <stdio.h>
28 #include <sys/types.h>
29 #include <stdlib.h>
30 #include <libintl.h>
31 #include <ctype.h>
32 #include <syslog.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <priv.h>
39
40 #include "ns_sldap.h"
41 #include "ns_internal.h"
42 #include "ns_cache_door.h"
43 #include "ns_connmgmt.h"
44
45 #define _NIS_FILTER "nisdomain=*"
46 #define _NIS_DOMAIN "nisdomain"
47 static const char *nis_domain_attrs[] = {
48 _NIS_DOMAIN,
49 (char *)NULL
50 };
51
52 static int validate_filter(ns_ldap_cookie_t *cookie);
53
54 void
__ns_ldap_freeEntry(ns_ldap_entry_t * ep)55 __ns_ldap_freeEntry(ns_ldap_entry_t *ep)
56 {
57 int j, k = 0;
58
59 if (ep == NULL)
60 return;
61
62 if (ep->attr_pair == NULL) {
63 free(ep);
64 return;
65 }
66 for (j = 0; j < ep->attr_count; j++) {
67 if (ep->attr_pair[j] == NULL)
68 continue;
69 if (ep->attr_pair[j]->attrname)
70 free(ep->attr_pair[j]->attrname);
71 if (ep->attr_pair[j]->attrvalue) {
72 for (k = 0; (k < ep->attr_pair[j]->value_count) &&
73 (ep->attr_pair[j]->attrvalue[k]); k++) {
74 free(ep->attr_pair[j]->attrvalue[k]);
75 }
76 free(ep->attr_pair[j]->attrvalue);
77 }
78 free(ep->attr_pair[j]);
79 }
80 free(ep->attr_pair);
81 free(ep);
82 }
83
84 static void
_freeControlList(LDAPControl *** ctrls)85 _freeControlList(LDAPControl ***ctrls)
86 {
87 LDAPControl **ctrl;
88
89 if (ctrls == NULL || *ctrls == NULL)
90 return;
91
92 for (ctrl = *ctrls; *ctrl != NULL; ctrl++)
93 ldap_control_free(*ctrl);
94 free(*ctrls);
95 *ctrls = NULL;
96 }
97 /*
98 * Convert attribute type in a RDN that has an attribute mapping to the
99 * original mappped type.
100 * e.g.
101 * cn<->cn-st and iphostnumber<->iphostnumber-st
102 * cn-st=aaa+iphostnumber-st=10.10.01.01
103 * is mapped to
104 * cn=aaa+iphostnumber=10.10.01.01
105 *
106 * Input - service: e.g. hosts, passwd etc.
107 * rdn: RDN
108 * Return: NULL - No attribute mapping in the RDN
109 * Non-NULL - The attribute type(s) in the RDN are mapped and
110 * the memory is allocated for the new rdn.
111 *
112 */
113 static char *
_cvtRDN(const char * service,const char * rdn)114 _cvtRDN(const char *service, const char *rdn)
115 {
116 char **attrs, **mapped_attrs, **mapp, *type, *value, *attr;
117 char *new_rdn = NULL;
118 int nAttr = 0, i, attr_mapped, len = 0;
119
120 /* Break down "type=value\0" pairs. Assume RDN is normalized */
121 if ((attrs = ldap_explode_rdn(rdn, 0)) == NULL)
122 return (NULL);
123
124 for (nAttr = 0; attrs[nAttr] != NULL; nAttr++)
125 ;
126
127 if ((mapped_attrs = (char **)calloc(nAttr, sizeof (char *))) == NULL) {
128 ldap_value_free(attrs);
129 return (NULL);
130 }
131
132 attr_mapped = 0;
133 for (i = 0; i < nAttr; i++) {
134 /* Parse type=value pair */
135 if ((type = strtok_r(attrs[i], "=", &value)) == NULL ||
136 value == NULL)
137 goto cleanup;
138 /* Reverse map: e.g. cn-sm -> cn */
139 mapp = __ns_ldap_getOrigAttribute(service, type);
140 if (mapp != NULL && mapp[0] != NULL) {
141 /* The attribute mapping is found */
142 type = mapp[0];
143 attr_mapped = 1;
144
145 /* "type=value\0" */
146 len = strlen(type) + strlen(value) + 2;
147
148 /* Reconstruct type=value pair. A string is allocated */
149 if ((attr = (char *)calloc(1, len)) == NULL) {
150 __s_api_free2dArray(mapp);
151 goto cleanup;
152 }
153 (void) snprintf(attr, len, "%s=%s", type, value);
154 mapped_attrs[i] = attr;
155 } else {
156 /*
157 * No attribute mapping. attrs[i] is going to be copied
158 * later. Restore "type\0value\0" back to
159 * "type=value\0".
160 */
161 type[strlen(type)] = '=';
162 }
163 __s_api_free2dArray(mapp);
164 }
165 if (attr_mapped == 0)
166 /* No attribute mapping. Don't bother to reconstruct RDN */
167 goto cleanup;
168
169 len = 0;
170 /* Reconstruct RDN from type=value pairs */
171 for (i = 0; i < nAttr; i++) {
172 if (mapped_attrs[i])
173 len += strlen(mapped_attrs[i]);
174 else
175 len += strlen(attrs[i]);
176 /* Add 1 for "+" */
177 len++;
178 }
179 if ((new_rdn = (char *)calloc(1, ++len)) == NULL)
180 goto cleanup;
181 for (i = 0; i < nAttr; i++) {
182 if (i > 0)
183 /* Add seperator */
184 (void) strlcat(new_rdn, "+", len);
185
186 if (mapped_attrs[i])
187 (void) strlcat(new_rdn, mapped_attrs[i], len);
188 else
189 (void) strlcat(new_rdn, attrs[i], len);
190
191 }
192 cleanup:
193 ldap_value_free(attrs);
194 if (mapped_attrs) {
195 if (attr_mapped) {
196 for (i = 0; i < nAttr; i++) {
197 if (mapped_attrs[i])
198 free(mapped_attrs[i]);
199 }
200 }
201 free(mapped_attrs);
202 }
203
204 return (new_rdn);
205 }
206 /*
207 * Convert attribute type in a DN that has an attribute mapping to the
208 * original mappped type.
209 * e.g
210 * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
211 *
212 * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com
213 * is converted to
214 * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
215 *
216 * Input - service: e.g. hosts, passwd etc.
217 * dn: the value of a distinguished name
218 * Return - NULL: error
219 * non-NULL: A converted DN and the memory is allocated
220 */
221 static char *
_cvtDN(const char * service,const char * dn)222 _cvtDN(const char *service, const char *dn)
223 {
224 char **mapped_rdns;
225 char **rdns, *new_rdn, *new_dn = NULL;
226 int nRdn = 0, i, len = 0, rdn_mapped;
227
228 if (service == NULL || dn == NULL)
229 return (NULL);
230
231 if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
232 return (NULL);
233
234 for (nRdn = 0; rdns[nRdn] != NULL; nRdn++)
235 ;
236
237 if ((mapped_rdns = (char **)calloc(nRdn, sizeof (char *))) == NULL) {
238 ldap_value_free(rdns);
239 return (NULL);
240 }
241
242 rdn_mapped = 0;
243 /* Break down RDNs in a DN */
244 for (i = 0; i < nRdn; i++) {
245 if ((new_rdn = _cvtRDN(service, rdns[i])) != NULL) {
246 mapped_rdns[i] = new_rdn;
247 rdn_mapped = 1;
248 }
249 }
250 if (rdn_mapped == 0) {
251 /*
252 * No RDN contains any attribute mapping.
253 * Don't bother to reconstruct DN from RDN. Copy DN directly.
254 */
255 new_dn = strdup(dn);
256 goto cleanup;
257 }
258 /*
259 * Reconstruct dn from RDNs.
260 * Calculate the length first.
261 */
262 for (i = 0; i < nRdn; i++) {
263 if (mapped_rdns[i])
264 len += strlen(mapped_rdns[i]);
265 else
266 len += strlen(rdns[i]);
267
268 /* add 1 for ',' */
269 len ++;
270 }
271 if ((new_dn = (char *)calloc(1, ++len)) == NULL)
272 goto cleanup;
273 for (i = 0; i < nRdn; i++) {
274 if (i > 0)
275 /* Add seperator */
276 (void) strlcat(new_dn, ",", len);
277
278 if (mapped_rdns[i])
279 (void) strlcat(new_dn, mapped_rdns[i], len);
280 else
281 (void) strlcat(new_dn, rdns[i], len);
282
283 }
284
285 cleanup:
286 ldap_value_free(rdns);
287 if (mapped_rdns) {
288 if (rdn_mapped) {
289 for (i = 0; i < nRdn; i++) {
290 if (mapped_rdns[i])
291 free(mapped_rdns[i]);
292 }
293 }
294 free(mapped_rdns);
295 }
296
297 return (new_dn);
298 }
299 /*
300 * Convert a single ldap entry from a LDAPMessage
301 * into an ns_ldap_entry structure.
302 * Schema map the entry if specified in flags
303 */
304
305 static int
__s_api_cvtEntry(LDAP * ld,const char * service,LDAPMessage * e,int flags,ns_ldap_entry_t ** ret,ns_ldap_error_t ** error)306 __s_api_cvtEntry(LDAP *ld, const char *service, LDAPMessage *e, int flags,
307 ns_ldap_entry_t **ret, ns_ldap_error_t **error)
308 {
309
310 ns_ldap_entry_t *ep = NULL;
311 ns_ldap_attr_t **ap = NULL;
312 BerElement *ber;
313 char *attr = NULL;
314 char **vals = NULL;
315 char **mapping;
316 char *dn;
317 int nAttrs = 0;
318 int i, j, k = 0;
319 char **gecos_mapping = NULL;
320 int gecos_val_index[3] = { -1, -1, -1};
321 char errstr[MAXERROR];
322 int schema_mapping_existed = FALSE;
323 int gecos_mapping_existed = FALSE;
324 int gecos_attr_matched;
325 int auto_service = FALSE;
326 int rc = NS_LDAP_SUCCESS;
327
328 if (e == NULL || ret == NULL || error == NULL)
329 return (NS_LDAP_INVALID_PARAM);
330
331 *error = NULL;
332
333 ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
334 if (ep == NULL)
335 return (NS_LDAP_MEMORY);
336
337 if (service != NULL &&
338 (strncasecmp(service, "auto_", 5) == 0 ||
339 strcasecmp(service, "automount") == 0))
340 auto_service = TRUE;
341 /*
342 * see if schema mapping existed for the given service
343 */
344 mapping = __ns_ldap_getOrigAttribute(service,
345 NS_HASH_SCHEMA_MAPPING_EXISTED);
346 if (mapping) {
347 schema_mapping_existed = TRUE;
348 __s_api_free2dArray(mapping);
349 mapping = NULL;
350 } else if (auto_service) {
351 /*
352 * If service == auto_* and no
353 * schema mapping found
354 * then try automount
355 * There is certain case that schema mapping exist
356 * but __ns_ldap_getOrigAttribute(service,
357 * NS_HASH_SCHEMA_MAPPING_EXISTED);
358 * returns NULL.
359 * e.g.
360 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
361 * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
362 * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
363 *
364 * Make a check for schema_mapping_existed here
365 * so later on __s_api_convert_automountmapname won't be called
366 * unnecessarily. It is also used for attribute mapping
367 * and objectclass mapping.
368 */
369 mapping = __ns_ldap_getOrigAttribute("automount",
370 NS_HASH_SCHEMA_MAPPING_EXISTED);
371 if (mapping) {
372 schema_mapping_existed = TRUE;
373 __s_api_free2dArray(mapping);
374 mapping = NULL;
375 }
376 }
377
378 nAttrs = 1; /* start with 1 for the DN attr */
379 for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL;
380 attr = ldap_next_attribute(ld, e, ber)) {
381 nAttrs++;
382 ldap_memfree(attr);
383 attr = NULL;
384 }
385 ber_free(ber, 0);
386 ber = NULL;
387
388 ep->attr_count = nAttrs;
389
390 /*
391 * add 1 for "gecos" 1 to N attribute mapping,
392 * just in case it is needed.
393 * ep->attr_count will be updated later if that is true.
394 */
395 ap = (ns_ldap_attr_t **)calloc(ep->attr_count + 1,
396 sizeof (ns_ldap_attr_t *));
397 if (ap == NULL) {
398 __ns_ldap_freeEntry(ep);
399 ep = NULL;
400 return (NS_LDAP_MEMORY);
401 }
402 ep->attr_pair = ap;
403
404 /* DN attribute */
405 dn = ldap_get_dn(ld, e);
406 ap[0] = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
407 if (ap[0] == NULL) {
408 ldap_memfree(dn);
409 dn = NULL;
410 __ns_ldap_freeEntry(ep);
411 ep = NULL;
412 return (NS_LDAP_MEMORY);
413 }
414
415 if ((ap[0]->attrname = strdup("dn")) == NULL) {
416 ldap_memfree(dn);
417 dn = NULL;
418 __ns_ldap_freeEntry(ep);
419 ep = NULL;
420 return (NS_LDAP_INVALID_PARAM);
421 }
422 ap[0]->value_count = 1;
423 if ((ap[0]->attrvalue = (char **)
424 calloc(2, sizeof (char *))) == NULL) {
425 ldap_memfree(dn);
426 dn = NULL;
427 __ns_ldap_freeEntry(ep);
428 ep = NULL;
429 return (NS_LDAP_MEMORY);
430 }
431
432 if (schema_mapping_existed && ((flags & NS_LDAP_NOT_CVT_DN) == 0))
433 ap[0]->attrvalue[0] = _cvtDN(service, dn);
434 else
435 ap[0]->attrvalue[0] = strdup(dn);
436
437 if (ap[0]->attrvalue[0] == NULL) {
438 ldap_memfree(dn);
439 dn = NULL;
440 __ns_ldap_freeEntry(ep);
441 ep = NULL;
442 return (NS_LDAP_MEMORY);
443 }
444 ldap_memfree(dn);
445 dn = NULL;
446
447 if ((flags & NS_LDAP_NOMAP) == 0 && auto_service &&
448 schema_mapping_existed) {
449 rc = __s_api_convert_automountmapname(service,
450 &ap[0]->attrvalue[0],
451 error);
452 if (rc != NS_LDAP_SUCCESS) {
453 __ns_ldap_freeEntry(ep);
454 ep = NULL;
455 return (rc);
456 }
457 }
458
459 /* other attributes */
460 for (attr = ldap_first_attribute(ld, e, &ber), j = 1;
461 attr != NULL && j != nAttrs;
462 attr = ldap_next_attribute(ld, e, ber), j++) {
463 /* allocate new attr name */
464
465 if ((ap[j] = (ns_ldap_attr_t *)
466 calloc(1, sizeof (ns_ldap_attr_t))) == NULL) {
467 ber_free(ber, 0);
468 ber = NULL;
469 __ns_ldap_freeEntry(ep);
470 ep = NULL;
471 if (gecos_mapping)
472 __s_api_free2dArray(gecos_mapping);
473 gecos_mapping = NULL;
474 return (NS_LDAP_MEMORY);
475 }
476
477 if ((flags & NS_LDAP_NOMAP) || schema_mapping_existed == FALSE)
478 mapping = NULL;
479 else
480 mapping = __ns_ldap_getOrigAttribute(service, attr);
481
482 if (mapping == NULL && auto_service &&
483 schema_mapping_existed && (flags & NS_LDAP_NOMAP) == 0)
484 /*
485 * if service == auto_* and no schema mapping found
486 * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP
487 * is not set then try automount e.g.
488 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
489 */
490 mapping = __ns_ldap_getOrigAttribute("automount",
491 attr);
492
493 if (mapping == NULL) {
494 if ((ap[j]->attrname = strdup(attr)) == NULL) {
495 ber_free(ber, 0);
496 ber = NULL;
497 __ns_ldap_freeEntry(ep);
498 ep = NULL;
499 if (gecos_mapping)
500 __s_api_free2dArray(gecos_mapping);
501 gecos_mapping = NULL;
502 return (NS_LDAP_MEMORY);
503 }
504 } else {
505 /*
506 * for "gecos" 1 to N mapping,
507 * do not remove the mapped attribute,
508 * just create a new gecos attribute
509 * and append it to the end of the attribute list
510 */
511 if (strcasecmp(mapping[0], "gecos") == 0) {
512 ap[j]->attrname = strdup(attr);
513 gecos_mapping_existed = TRUE;
514 } else {
515 ap[j]->attrname = strdup(mapping[0]);
516 }
517
518 if (ap[j]->attrname == NULL) {
519 ber_free(ber, 0);
520 ber = NULL;
521 __ns_ldap_freeEntry(ep);
522 ep = NULL;
523 if (gecos_mapping)
524 __s_api_free2dArray(gecos_mapping);
525 gecos_mapping = NULL;
526 return (NS_LDAP_MEMORY);
527 }
528 /*
529 * 1 to N attribute mapping processing
530 * is only done for "gecos"
531 */
532
533 if (strcasecmp(mapping[0], "gecos") == 0) {
534 /*
535 * get attribute mapping for "gecos",
536 * need to know the number and order of the
537 * mapped attributes
538 */
539 if (gecos_mapping == NULL) {
540 gecos_mapping =
541 __ns_ldap_getMappedAttributes(
542 service, mapping[0]);
543 if (gecos_mapping == NULL ||
544 gecos_mapping[0] == NULL) {
545 /*
546 * this should never happens,
547 * syslog the error
548 */
549 (void) sprintf(errstr,
550 gettext(
551 "Attribute mapping "
552 "inconsistency "
553 "found for attributes "
554 "'%s' and '%s'."),
555 mapping[0], attr);
556 syslog(LOG_ERR, "libsldap: %s",
557 errstr);
558
559 ber_free(ber, 0);
560 ber = NULL;
561 __ns_ldap_freeEntry(ep);
562 ep = NULL;
563 __s_api_free2dArray(mapping);
564 mapping = NULL;
565 if (gecos_mapping)
566 __s_api_free2dArray(
567 gecos_mapping);
568 gecos_mapping = NULL;
569 return (NS_LDAP_INTERNAL);
570 }
571 }
572
573 /*
574 * is this attribute the 1st, 2nd, or
575 * 3rd attr in the mapping list?
576 */
577 gecos_attr_matched = FALSE;
578 for (i = 0; i < 3 && gecos_mapping[i]; i++) {
579 if (gecos_mapping[i] &&
580 strcasecmp(gecos_mapping[i],
581 attr) == 0) {
582 gecos_val_index[i] = j;
583 gecos_attr_matched = TRUE;
584 break;
585 }
586 }
587 if (gecos_attr_matched == FALSE) {
588 /*
589 * Not match found.
590 * This should never happens,
591 * syslog the error
592 */
593 (void) sprintf(errstr,
594 gettext(
595 "Attribute mapping "
596 "inconsistency "
597 "found for attributes "
598 "'%s' and '%s'."),
599 mapping[0], attr);
600 syslog(LOG_ERR, "libsldap: %s", errstr);
601
602 ber_free(ber, 0);
603 ber = NULL;
604 __ns_ldap_freeEntry(ep);
605 ep = NULL;
606 __s_api_free2dArray(mapping);
607 mapping = NULL;
608 __s_api_free2dArray(gecos_mapping);
609 gecos_mapping = NULL;
610 return (NS_LDAP_INTERNAL);
611 }
612 }
613 __s_api_free2dArray(mapping);
614 mapping = NULL;
615 }
616
617 if ((vals = ldap_get_values(ld, e, attr)) != NULL) {
618
619 if ((ap[j]->value_count =
620 ldap_count_values(vals)) == 0) {
621 ldap_value_free(vals);
622 vals = NULL;
623 continue;
624 } else {
625 ap[j]->attrvalue = (char **)
626 calloc(ap[j]->value_count+1,
627 sizeof (char *));
628 if (ap[j]->attrvalue == NULL) {
629 ber_free(ber, 0);
630 ber = NULL;
631 __ns_ldap_freeEntry(ep);
632 ep = NULL;
633 if (gecos_mapping)
634 __s_api_free2dArray(
635 gecos_mapping);
636 gecos_mapping = NULL;
637 return (NS_LDAP_MEMORY);
638 }
639 }
640
641 /* map object classes if necessary */
642 if ((flags & NS_LDAP_NOMAP) == 0 &&
643 schema_mapping_existed && ap[j]->attrname &&
644 strcasecmp(ap[j]->attrname, "objectclass") == 0) {
645 for (k = 0; k < ap[j]->value_count; k++) {
646 mapping =
647 __ns_ldap_getOrigObjectClass(
648 service, vals[k]);
649
650 if (mapping == NULL && auto_service)
651 /*
652 * if service == auto_* and no
653 * schema mapping found
654 * then try automount
655 */
656 mapping =
657 __ns_ldap_getOrigObjectClass(
658 "automount", vals[k]);
659
660 if (mapping == NULL) {
661 ap[j]->attrvalue[k] =
662 strdup(vals[k]);
663 } else {
664 ap[j]->attrvalue[k] =
665 strdup(mapping[0]);
666 __s_api_free2dArray(mapping);
667 mapping = NULL;
668 }
669 if (ap[j]->attrvalue[k] == NULL) {
670 ber_free(ber, 0);
671 ber = NULL;
672 __ns_ldap_freeEntry(ep);
673 ep = NULL;
674 if (gecos_mapping)
675 __s_api_free2dArray(
676 gecos_mapping);
677 gecos_mapping = NULL;
678 return (NS_LDAP_MEMORY);
679 }
680 }
681 } else {
682 for (k = 0; k < ap[j]->value_count; k++) {
683 if ((ap[j]->attrvalue[k] =
684 strdup(vals[k])) == NULL) {
685 ber_free(ber, 0);
686 ber = NULL;
687 __ns_ldap_freeEntry(ep);
688 ep = NULL;
689 if (gecos_mapping)
690 __s_api_free2dArray(
691 gecos_mapping);
692 gecos_mapping = NULL;
693 return (NS_LDAP_MEMORY);
694 }
695 }
696 }
697
698 ap[j]->attrvalue[k] = NULL;
699 ldap_value_free(vals);
700 vals = NULL;
701 }
702
703 ldap_memfree(attr);
704 attr = NULL;
705 }
706
707 ber_free(ber, 0);
708 ber = NULL;
709
710 if (gecos_mapping) {
711 __s_api_free2dArray(gecos_mapping);
712 gecos_mapping = NULL;
713 }
714
715 /* special processing for gecos 1 to up to 3 attribute mapping */
716 if (schema_mapping_existed && gecos_mapping_existed) {
717
718 int f = -1;
719
720 for (i = 0; i < 3; i++) {
721 k = gecos_val_index[i];
722
723 /*
724 * f is the index of the first returned
725 * attribute which "gecos" attribute mapped to
726 */
727 if (k != -1 && f == -1)
728 f = k;
729
730 if (k != -1 && ap[k]->value_count > 0 &&
731 ap[k]->attrvalue[0] &&
732 strlen(ap[k]->attrvalue[0]) > 0) {
733
734 if (k == f) {
735 /*
736 * Create and fill in the last reserved
737 * ap with the data from the "gecos"
738 * mapping attributes
739 */
740 ap[nAttrs] = (ns_ldap_attr_t *)
741 calloc(1,
742 sizeof (ns_ldap_attr_t));
743 if (ap[nAttrs] == NULL) {
744 __ns_ldap_freeEntry(ep);
745 ep = NULL;
746 return (NS_LDAP_MEMORY);
747 }
748 ap[nAttrs]->attrvalue = (char **)calloc(
749 2, sizeof (char *));
750 if (ap[nAttrs]->attrvalue == NULL) {
751 __ns_ldap_freeEntry(ep);
752 ep = NULL;
753 return (NS_LDAP_MEMORY);
754 }
755 /* add 1 more for a possible "," */
756 ap[nAttrs]->attrvalue[0] =
757 (char *)calloc(
758 strlen(ap[f]->attrvalue[0]) +
759 2, 1);
760 if (ap[nAttrs]->attrvalue[0] == NULL) {
761 __ns_ldap_freeEntry(ep);
762 ep = NULL;
763 return (NS_LDAP_MEMORY);
764 }
765 (void) strcpy(ap[nAttrs]->attrvalue[0],
766 ap[f]->attrvalue[0]);
767
768 ap[nAttrs]->attrname = strdup("gecos");
769 if (ap[nAttrs]->attrname == NULL) {
770 __ns_ldap_freeEntry(ep);
771 ep = NULL;
772 return (NS_LDAP_MEMORY);
773 }
774
775 ap[nAttrs]->value_count = 1;
776 ep->attr_count = nAttrs + 1;
777
778 } else {
779 char *tmp = NULL;
780
781 /*
782 * realloc to add "," and
783 * ap[k]->attrvalue[0]
784 */
785 tmp = (char *)realloc(
786 ap[nAttrs]->attrvalue[0],
787 strlen(ap[nAttrs]->
788 attrvalue[0]) +
789 strlen(ap[k]->
790 attrvalue[0]) + 2);
791 if (tmp == NULL) {
792 __ns_ldap_freeEntry(ep);
793 ep = NULL;
794 return (NS_LDAP_MEMORY);
795 }
796 ap[nAttrs]->attrvalue[0] = tmp;
797 (void) strcat(ap[nAttrs]->attrvalue[0],
798 ",");
799 (void) strcat(ap[nAttrs]->attrvalue[0],
800 ap[k]->attrvalue[0]);
801 }
802 }
803 }
804 }
805
806 *ret = ep;
807 return (NS_LDAP_SUCCESS);
808 }
809
810 static int
__s_api_getEntry(ns_ldap_cookie_t * cookie)811 __s_api_getEntry(ns_ldap_cookie_t *cookie)
812 {
813 ns_ldap_entry_t *curEntry = NULL;
814 int ret;
815
816 #ifdef DEBUG
817 (void) fprintf(stderr, "__s_api_getEntry START\n");
818 #endif
819
820 if (cookie->resultMsg == NULL) {
821 return (NS_LDAP_INVALID_PARAM);
822 }
823 ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service,
824 cookie->resultMsg, cookie->i_flags,
825 &curEntry, &cookie->errorp);
826 if (ret != NS_LDAP_SUCCESS) {
827 return (ret);
828 }
829
830 if (cookie->result == NULL) {
831 cookie->result = (ns_ldap_result_t *)
832 calloc(1, sizeof (ns_ldap_result_t));
833 if (cookie->result == NULL) {
834 __ns_ldap_freeEntry(curEntry);
835 curEntry = NULL;
836 return (NS_LDAP_MEMORY);
837 }
838 cookie->result->entry = curEntry;
839 cookie->nextEntry = curEntry;
840 } else {
841 cookie->nextEntry->next = curEntry;
842 cookie->nextEntry = curEntry;
843 }
844 cookie->result->entries_count++;
845
846 return (NS_LDAP_SUCCESS);
847 }
848
849 static int
__s_api_get_cachemgr_data(const char * type,const char * from,char ** to)850 __s_api_get_cachemgr_data(const char *type, const char *from, char **to)
851 {
852 union {
853 ldap_data_t s_d;
854 char s_b[DOORBUFFERSIZE];
855 } space;
856 ldap_data_t *sptr;
857 int ndata;
858 int adata;
859 int rc;
860
861 #ifdef DEBUG
862 (void) fprintf(stderr, "__s_api_get_cachemgr_data START\n");
863 #endif
864 /*
865 * We are not going to perform DN to domain mapping
866 * in the Standalone mode
867 */
868 if (__s_api_isStandalone()) {
869 return (-1);
870 }
871
872 if (from == NULL || from[0] == '\0' || to == NULL)
873 return (-1);
874
875 *to = NULL;
876 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
877
878 space.s_d.ldap_call.ldap_callnumber = GETCACHE;
879 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
880 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
881 "%s%s%s",
882 type,
883 DOORLINESEP,
884 from);
885 ndata = sizeof (space);
886 adata = sizeof (ldap_call_t) +
887 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
888 sptr = &space.s_d;
889
890 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
891 if (rc != NS_CACHE_SUCCESS)
892 return (-1);
893 else
894 *to = strdup(sptr->ldap_ret.ldap_u.buff);
895 return (NS_LDAP_SUCCESS);
896 }
897
898 static int
__s_api_set_cachemgr_data(const char * type,const char * from,const char * to)899 __s_api_set_cachemgr_data(const char *type, const char *from, const char *to)
900 {
901 union {
902 ldap_data_t s_d;
903 char s_b[DOORBUFFERSIZE];
904 } space;
905 ldap_data_t *sptr;
906 int ndata;
907 int adata;
908 int rc;
909
910 #ifdef DEBUG
911 (void) fprintf(stderr, "__s_api_set_cachemgr_data START\n");
912 #endif
913 /*
914 * We are not going to perform DN to domain mapping
915 * in the Standalone mode
916 */
917 if (__s_api_isStandalone()) {
918 return (-1);
919 }
920
921 if ((from == NULL) || (from[0] == '\0') ||
922 (to == NULL) || (to[0] == '\0'))
923 return (-1);
924
925 (void) memset(space.s_b, 0, DOORBUFFERSIZE);
926
927 space.s_d.ldap_call.ldap_callnumber = SETCACHE;
928 (void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
929 DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
930 "%s%s%s%s%s",
931 type,
932 DOORLINESEP,
933 from,
934 DOORLINESEP,
935 to);
936
937 ndata = sizeof (space);
938 adata = sizeof (ldap_call_t) +
939 strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
940 sptr = &space.s_d;
941
942 rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
943 if (rc != NS_CACHE_SUCCESS)
944 return (-1);
945
946 return (NS_LDAP_SUCCESS);
947 }
948
949
950 static char *
__s_api_remove_rdn_space(char * rdn)951 __s_api_remove_rdn_space(char *rdn)
952 {
953 char *tf, *tl, *vf, *vl, *eqsign;
954
955 /* if no space(s) to remove, return */
956 if (strchr(rdn, SPACETOK) == NULL)
957 return (rdn);
958
959 /* if no '=' separator, return */
960 eqsign = strchr(rdn, '=');
961 if (eqsign == NULL)
962 return (rdn);
963
964 tf = rdn;
965 tl = eqsign - 1;
966 vf = eqsign + 1;
967 vl = rdn + strlen(rdn) - 1;
968
969 /* now two strings, type and value */
970 *eqsign = '\0';
971
972 /* remove type's leading spaces */
973 while (tf < tl && *tf == SPACETOK)
974 tf++;
975 /* remove type's trailing spaces */
976 while (tf < tl && *tl == SPACETOK)
977 tl--;
978 /* add '=' separator back */
979 *(++tl) = '=';
980 /* remove value's leading spaces */
981 while (vf < vl && *vf == SPACETOK)
982 vf++;
983 /* remove value's trailing spaces */
984 while (vf < vl && *vl == SPACETOK)
985 *vl-- = '\0';
986
987 /* move value up if necessary */
988 if (vf != tl + 1)
989 (void) strcpy(tl + 1, vf);
990
991 return (tf);
992 }
993
994 static
995 ns_ldap_cookie_t *
init_search_state_machine()996 init_search_state_machine()
997 {
998 ns_ldap_cookie_t *cookie;
999 ns_config_t *cfg;
1000
1001 cookie = (ns_ldap_cookie_t *)calloc(1, sizeof (ns_ldap_cookie_t));
1002 if (cookie == NULL)
1003 return (NULL);
1004 cookie->state = INIT;
1005 /* assign other state variables */
1006 cfg = __s_api_loadrefresh_config();
1007 cookie->connectionId = -1;
1008 if (cfg == NULL ||
1009 cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_ptype == NS_UNKNOWN) {
1010 cookie->search_timeout.tv_sec = NS_DEFAULT_SEARCH_TIMEOUT;
1011 } else {
1012 cookie->search_timeout.tv_sec =
1013 cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_i;
1014 }
1015 if (cfg != NULL)
1016 __s_api_release_config(cfg);
1017 cookie->search_timeout.tv_usec = 0;
1018
1019 return (cookie);
1020 }
1021
1022 static void
delete_search_cookie(ns_ldap_cookie_t * cookie)1023 delete_search_cookie(ns_ldap_cookie_t *cookie)
1024 {
1025 if (cookie == NULL)
1026 return;
1027 if (cookie->connectionId > -1)
1028 DropConnection(cookie->connectionId, cookie->i_flags);
1029 if (cookie->filter)
1030 free(cookie->filter);
1031 if (cookie->i_filter)
1032 free(cookie->i_filter);
1033 if (cookie->service)
1034 free(cookie->service);
1035 if (cookie->sdlist)
1036 (void) __ns_ldap_freeSearchDescriptors(&(cookie->sdlist));
1037 if (cookie->result)
1038 (void) __ns_ldap_freeResult(&cookie->result);
1039 if (cookie->attribute)
1040 __s_api_free2dArray(cookie->attribute);
1041 if (cookie->errorp)
1042 (void) __ns_ldap_freeError(&cookie->errorp);
1043 if (cookie->reflist)
1044 __s_api_deleteRefInfo(cookie->reflist);
1045 if (cookie->basedn)
1046 free(cookie->basedn);
1047 if (cookie->ctrlCookie)
1048 ber_bvfree(cookie->ctrlCookie);
1049 _freeControlList(&cookie->p_serverctrls);
1050 if (cookie->resultctrl)
1051 ldap_controls_free(cookie->resultctrl);
1052 free(cookie);
1053 }
1054
1055 static int
get_mapped_filter(ns_ldap_cookie_t * cookie,char ** new_filter)1056 get_mapped_filter(ns_ldap_cookie_t *cookie, char **new_filter)
1057 {
1058
1059 typedef struct filter_mapping_info {
1060 char oc_or_attr;
1061 char *name_start;
1062 char *name_end;
1063 char *veq_pos;
1064 char *from_name;
1065 char *to_name;
1066 char **mapping;
1067 } filter_mapping_info_t;
1068
1069 char *c, *last_copied;
1070 char *filter_c, *filter_c_next;
1071 char *key, *tail, *head;
1072 char errstr[MAXERROR];
1073 int num_eq = 0, num_veq = 0;
1074 boolean_t in_quote = B_FALSE;
1075 boolean_t is_value = B_FALSE;
1076 int i, j, oc_len, len;
1077 boolean_t at_least_one = B_FALSE;
1078 filter_mapping_info_t **info, *info1;
1079 char **mapping;
1080 char *service, *filter, *err;
1081 boolean_t auto_service = B_FALSE;
1082
1083 if (cookie == NULL || new_filter == NULL)
1084 return (NS_LDAP_INVALID_PARAM);
1085
1086 *new_filter = NULL;
1087 service = cookie->service;
1088 filter = cookie->filter;
1089
1090 /*
1091 * count the number of '=' char
1092 */
1093 for (c = filter; *c; c++) {
1094 if (*c == TOKENSEPARATOR)
1095 num_eq++;
1096 }
1097
1098 if (service != NULL && strncasecmp(service, "auto_", 5) == 0)
1099 auto_service = TRUE;
1100
1101 /*
1102 * See if schema mapping existed for the given service.
1103 * If not, just return success.
1104 */
1105 mapping = __ns_ldap_getOrigAttribute(service,
1106 NS_HASH_SCHEMA_MAPPING_EXISTED);
1107
1108 if (mapping == NULL && auto_service)
1109 /*
1110 * if service == auto_* and no
1111 * schema mapping found
1112 * then try automount
1113 */
1114 mapping = __ns_ldap_getOrigAttribute(
1115 "automount", NS_HASH_SCHEMA_MAPPING_EXISTED);
1116
1117 if (mapping)
1118 __s_api_free2dArray(mapping);
1119 else
1120 return (NS_LDAP_SUCCESS);
1121
1122 /*
1123 * no '=' sign, just say OK and return nothing
1124 */
1125 if (num_eq == 0)
1126 return (NS_LDAP_SUCCESS);
1127
1128 /*
1129 * Make a copy of the filter string
1130 * for saving the name of the objectclasses or
1131 * attributes that need to be passed to the
1132 * objectclass or attribute mapping functions.
1133 * pointer "info->from_name" points to the locations
1134 * within this string.
1135 *
1136 * The input filter string, filter, will be used
1137 * to indicate where these names start and end.
1138 * pointers "info->name_start" and "info->name_end"
1139 * point to locations within the input filter string,
1140 * and are used at the end of this function to
1141 * merge the original filter data with the
1142 * mapped objectclass or attribute names.
1143 */
1144 filter_c = strdup(filter);
1145 if (filter_c == NULL)
1146 return (NS_LDAP_MEMORY);
1147 filter_c_next = filter_c;
1148
1149 /*
1150 * get memory for info arrays
1151 */
1152 info = (filter_mapping_info_t **)calloc(num_eq + 1,
1153 sizeof (filter_mapping_info_t *));
1154
1155 if (info == NULL) {
1156 free(filter_c);
1157 return (NS_LDAP_MEMORY);
1158 }
1159
1160 /*
1161 * find valid '=' for further processing,
1162 * ignore the "escaped =" (.i.e. "\="), or
1163 * "=" in quoted string
1164 */
1165 for (c = filter_c; *c; c++) {
1166
1167 switch (*c) {
1168 case TOKENSEPARATOR:
1169 if (!in_quote && !is_value) {
1170 info1 = (filter_mapping_info_t *)calloc(1,
1171 sizeof (filter_mapping_info_t));
1172 if (info1 == NULL) {
1173 free(filter_c);
1174 for (i = 0; i < num_veq; i++)
1175 free(info[i]);
1176 free(info);
1177 return (NS_LDAP_MEMORY);
1178 }
1179 info[num_veq] = info1;
1180
1181 /*
1182 * remember the location of this "="
1183 */
1184 info[num_veq++]->veq_pos = c;
1185
1186 /*
1187 * skip until the end of the attribute value
1188 */
1189 is_value = B_TRUE;
1190 }
1191 break;
1192 case CPARATOK:
1193 /*
1194 * mark the end of the attribute value
1195 */
1196 if (!in_quote)
1197 is_value = B_FALSE;
1198 break;
1199 case QUOTETOK:
1200 /*
1201 * switch on/off the in_quote mode
1202 */
1203 in_quote = (in_quote == B_FALSE);
1204 break;
1205 case '\\':
1206 /*
1207 * ignore escape characters
1208 * don't skip if next char is '\0'
1209 */
1210 if (!in_quote)
1211 if (*(++c) == '\0')
1212 c--;
1213 break;
1214 }
1215
1216 }
1217
1218 /*
1219 * for each valid "=" found, get the name to
1220 * be mapped
1221 */
1222 oc_len = strlen("objectclass");
1223 for (i = 0; i < num_veq; i++) {
1224
1225 /*
1226 * look at the left side of "=" to see
1227 * if assertion is "objectclass=<ocname>"
1228 * or "<attribute name>=<attribute value>"
1229 *
1230 * first skip spaces before "=".
1231 * Note that filter_c_next may not point to the
1232 * start of the filter string. For i > 0,
1233 * it points to the end of the last name processed + 2
1234 */
1235 for (tail = info[i]->veq_pos; (tail > filter_c_next) &&
1236 (*(tail - 1) == SPACETOK); tail--)
1237 ;
1238
1239 /*
1240 * mark the end of the left side string (the key)
1241 */
1242 *tail = '\0';
1243 info[i]->name_end = tail - filter_c - 1 + filter;
1244
1245 /*
1246 * find the start of the key
1247 */
1248 key = filter_c_next;
1249 for (c = tail; filter_c_next <= c; c--) {
1250 /* OPARATOK is '(' */
1251 if (*c == OPARATOK ||
1252 *c == SPACETOK) {
1253 key = c + 1;
1254 break;
1255 }
1256 }
1257 info[i]->name_start = key - filter_c + filter;
1258
1259 if ((key + oc_len) <= tail) {
1260 if (strncasecmp(key, "objectclass",
1261 oc_len) == 0) {
1262 /*
1263 * assertion is "objectclass=ocname",
1264 * ocname is the one needs to be mapped
1265 *
1266 * skip spaces after "=" to find start
1267 * of the ocname
1268 */
1269 head = info[i]->veq_pos;
1270 for (head = info[i]->veq_pos + 1;
1271 *head && *head == SPACETOK; head++)
1272 ;
1273
1274 /* ignore empty ocname */
1275 if (!(*head))
1276 continue;
1277
1278 info[i]->name_start = head - filter_c +
1279 filter;
1280
1281 /*
1282 * now find the end of the ocname
1283 */
1284 for (c = head; ; c++) {
1285 /* CPARATOK is ')' */
1286 if (*c == CPARATOK ||
1287 *c == '\0' ||
1288 *c == SPACETOK) {
1289 *c = '\0';
1290 info[i]->name_end =
1291 c - filter_c - 1 +
1292 filter;
1293 filter_c_next = c + 1;
1294 info[i]->oc_or_attr = 'o';
1295 info[i]->from_name = head;
1296 break;
1297 }
1298 }
1299 }
1300 }
1301
1302 /*
1303 * assertion is not "objectclass=ocname",
1304 * assume assertion is "<key> = <value>",
1305 * <key> is the one needs to be mapped
1306 */
1307 if (info[i]->from_name == NULL && strlen(key) > 0) {
1308 info[i]->oc_or_attr = 'a';
1309 info[i]->from_name = key;
1310 }
1311 }
1312
1313 /* perform schema mapping */
1314 for (i = 0; i < num_veq; i++) {
1315 if (info[i]->from_name == NULL)
1316 continue;
1317
1318 if (info[i]->oc_or_attr == 'a')
1319 info[i]->mapping =
1320 __ns_ldap_getMappedAttributes(service,
1321 info[i]->from_name);
1322 else
1323 info[i]->mapping =
1324 __ns_ldap_getMappedObjectClass(service,
1325 info[i]->from_name);
1326
1327 if (info[i]->mapping == NULL && auto_service) {
1328 /*
1329 * If no mapped attribute/objectclass is found
1330 * and service == auto*
1331 * try to find automount's
1332 * mapped attribute/objectclass
1333 */
1334 if (info[i]->oc_or_attr == 'a')
1335 info[i]->mapping =
1336 __ns_ldap_getMappedAttributes("automount",
1337 info[i]->from_name);
1338 else
1339 info[i]->mapping =
1340 __ns_ldap_getMappedObjectClass("automount",
1341 info[i]->from_name);
1342 }
1343
1344 if (info[i]->mapping == NULL ||
1345 info[i]->mapping[0] == NULL) {
1346 info[i]->to_name = NULL;
1347 } else if (info[i]->mapping[1] == NULL) {
1348 info[i]->to_name = info[i]->mapping[0];
1349 at_least_one = TRUE;
1350 } else {
1351 __s_api_free2dArray(info[i]->mapping);
1352 /*
1353 * multiple mapping
1354 * not allowed
1355 */
1356 (void) sprintf(errstr,
1357 gettext(
1358 "Multiple attribute or objectclass "
1359 "mapping for '%s' in filter "
1360 "'%s' not allowed."),
1361 info[i]->from_name, filter);
1362 err = strdup(errstr);
1363 if (err) {
1364 MKERROR(LOG_WARNING, cookie->errorp,
1365 NS_CONFIG_SYNTAX,
1366 err, NS_LDAP_MEMORY);
1367 }
1368
1369 free(filter_c);
1370 for (j = 0; j < num_veq; j++) {
1371 if (info[j]->mapping)
1372 __s_api_free2dArray(
1373 info[j]->mapping);
1374 free(info[j]);
1375 }
1376 free(info);
1377 return (NS_LDAP_CONFIG);
1378 }
1379 }
1380
1381
1382 if (at_least_one) {
1383
1384 len = strlen(filter);
1385 last_copied = filter - 1;
1386
1387 for (i = 0; i < num_veq; i++) {
1388 if (info[i]->to_name)
1389 len += strlen(info[i]->to_name);
1390 }
1391
1392 *new_filter = (char *)calloc(1, len);
1393 if (*new_filter == NULL) {
1394 free(filter_c);
1395 for (j = 0; j < num_veq; j++) {
1396 if (info[j]->mapping)
1397 __s_api_free2dArray(
1398 info[j]->mapping);
1399 free(info[j]);
1400 }
1401 free(info);
1402 return (NS_LDAP_MEMORY);
1403 }
1404
1405 for (i = 0; i < num_veq; i++) {
1406 if (info[i]->to_name != NULL &&
1407 info[i]->to_name != NULL) {
1408
1409 /*
1410 * copy the original filter data
1411 * between the last name and current
1412 * name
1413 */
1414 if ((last_copied + 1) != info[i]->name_start)
1415 (void) strncat(*new_filter,
1416 last_copied + 1,
1417 info[i]->name_start -
1418 last_copied - 1);
1419
1420 /* the data is copied */
1421 last_copied = info[i]->name_end;
1422
1423 /*
1424 * replace the name with
1425 * the mapped name
1426 */
1427 (void) strcat(*new_filter, info[i]->to_name);
1428 }
1429
1430 /* copy the filter data after the last name */
1431 if (i == (num_veq -1) &&
1432 info[i]->name_end <
1433 (filter + strlen(filter)))
1434 (void) strncat(*new_filter, last_copied + 1,
1435 filter + strlen(filter) -
1436 last_copied - 1);
1437 }
1438
1439 }
1440
1441 /* free memory */
1442 free(filter_c);
1443 for (j = 0; j < num_veq; j++) {
1444 if (info[j]->mapping)
1445 __s_api_free2dArray(info[j]->mapping);
1446 free(info[j]);
1447 }
1448 free(info);
1449
1450 return (NS_LDAP_SUCCESS);
1451 }
1452
1453 static int
setup_next_search(ns_ldap_cookie_t * cookie)1454 setup_next_search(ns_ldap_cookie_t *cookie)
1455 {
1456 ns_ldap_search_desc_t *dptr;
1457 int scope;
1458 char *filter, *str;
1459 int baselen;
1460 int rc;
1461 void **param;
1462
1463 dptr = *cookie->sdpos;
1464 scope = cookie->i_flags & (NS_LDAP_SCOPE_BASE |
1465 NS_LDAP_SCOPE_ONELEVEL |
1466 NS_LDAP_SCOPE_SUBTREE);
1467 if (scope)
1468 cookie->scope = scope;
1469 else
1470 cookie->scope = dptr->scope;
1471 switch (cookie->scope) {
1472 case NS_LDAP_SCOPE_BASE:
1473 cookie->scope = LDAP_SCOPE_BASE;
1474 break;
1475 case NS_LDAP_SCOPE_ONELEVEL:
1476 cookie->scope = LDAP_SCOPE_ONELEVEL;
1477 break;
1478 case NS_LDAP_SCOPE_SUBTREE:
1479 cookie->scope = LDAP_SCOPE_SUBTREE;
1480 break;
1481 }
1482
1483 filter = NULL;
1484 if (cookie->use_filtercb && cookie->init_filter_cb &&
1485 dptr->filter && strlen(dptr->filter) > 0) {
1486 (*cookie->init_filter_cb)(dptr, &filter,
1487 cookie->userdata);
1488 }
1489 if (filter == NULL) {
1490 if (cookie->i_filter == NULL) {
1491 cookie->err_rc = NS_LDAP_INVALID_PARAM;
1492 return (-1);
1493 } else {
1494 if (cookie->filter)
1495 free(cookie->filter);
1496 cookie->filter = strdup(cookie->i_filter);
1497 if (cookie->filter == NULL) {
1498 cookie->err_rc = NS_LDAP_MEMORY;
1499 return (-1);
1500 }
1501 }
1502 } else {
1503 if (cookie->filter)
1504 free(cookie->filter);
1505 cookie->filter = strdup(filter);
1506 free(filter);
1507 if (cookie->filter == NULL) {
1508 cookie->err_rc = NS_LDAP_MEMORY;
1509 return (-1);
1510 }
1511 }
1512
1513 /*
1514 * perform attribute/objectclass mapping on filter
1515 */
1516 filter = NULL;
1517
1518 if (cookie->service) {
1519 rc = get_mapped_filter(cookie, &filter);
1520 if (rc != NS_LDAP_SUCCESS) {
1521 cookie->err_rc = rc;
1522 return (-1);
1523 } else {
1524 /*
1525 * get_mapped_filter returns
1526 * NULL filter pointer, if
1527 * no mapping was done
1528 */
1529 if (filter) {
1530 free(cookie->filter);
1531 cookie->filter = filter;
1532 }
1533 }
1534 }
1535
1536 /*
1537 * validate filter to make sure it's legal
1538 * [remove redundant ()'s]
1539 */
1540 rc = validate_filter(cookie);
1541 if (rc != NS_LDAP_SUCCESS) {
1542 cookie->err_rc = rc;
1543 return (-1);
1544 }
1545
1546 baselen = strlen(dptr->basedn);
1547 if (baselen > 0 && dptr->basedn[baselen-1] == COMMATOK) {
1548 rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
1549 (void ***)¶m, &cookie->errorp);
1550 if (rc != NS_LDAP_SUCCESS) {
1551 cookie->err_rc = rc;
1552 return (-1);
1553 }
1554 str = ((char **)param)[0];
1555 baselen += strlen(str)+1;
1556 if (cookie->basedn)
1557 free(cookie->basedn);
1558 cookie->basedn = (char *)malloc(baselen);
1559 if (cookie->basedn == NULL) {
1560 cookie->err_rc = NS_LDAP_MEMORY;
1561 return (-1);
1562 }
1563 (void) strcpy(cookie->basedn, dptr->basedn);
1564 (void) strcat(cookie->basedn, str);
1565 (void) __ns_ldap_freeParam(¶m);
1566 } else {
1567 if (cookie->basedn)
1568 free(cookie->basedn);
1569 cookie->basedn = strdup(dptr->basedn);
1570 }
1571 return (0);
1572 }
1573
1574 static int
setup_referral_search(ns_ldap_cookie_t * cookie)1575 setup_referral_search(ns_ldap_cookie_t *cookie)
1576 {
1577 ns_referral_info_t *ref;
1578
1579 ref = cookie->refpos;
1580 cookie->scope = ref->refScope;
1581 if (cookie->filter) {
1582 free(cookie->filter);
1583 }
1584 cookie->filter = strdup(ref->refFilter);
1585 if (cookie->basedn) {
1586 free(cookie->basedn);
1587 }
1588 cookie->basedn = strdup(ref->refDN);
1589 if (cookie->filter == NULL || cookie->basedn == NULL) {
1590 cookie->err_rc = NS_LDAP_MEMORY;
1591 return (-1);
1592 }
1593 return (0);
1594 }
1595
1596 static int
get_current_session(ns_ldap_cookie_t * cookie)1597 get_current_session(ns_ldap_cookie_t *cookie)
1598 {
1599 ConnectionID connectionId = -1;
1600 Connection *conp = NULL;
1601 int rc;
1602 int fail_if_new_pwd_reqd = 1;
1603
1604 rc = __s_api_getConnection(NULL, cookie->i_flags,
1605 cookie->i_auth, &connectionId, &conp,
1606 &cookie->errorp, fail_if_new_pwd_reqd,
1607 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1608
1609 /*
1610 * If password control attached in *cookie->errorp,
1611 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1612 * free the error structure (we do not need
1613 * the sec_to_expired info).
1614 * Reset rc to NS_LDAP_SUCCESS.
1615 */
1616 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1617 (void) __ns_ldap_freeError(
1618 &cookie->errorp);
1619 cookie->errorp = NULL;
1620 rc = NS_LDAP_SUCCESS;
1621 }
1622
1623 if (rc != NS_LDAP_SUCCESS) {
1624 cookie->err_rc = rc;
1625 return (-1);
1626 }
1627 cookie->conn = conp;
1628 cookie->connectionId = connectionId;
1629
1630 return (0);
1631 }
1632
1633 static int
get_next_session(ns_ldap_cookie_t * cookie)1634 get_next_session(ns_ldap_cookie_t *cookie)
1635 {
1636 ConnectionID connectionId = -1;
1637 Connection *conp = NULL;
1638 int rc;
1639 int fail_if_new_pwd_reqd = 1;
1640
1641 if (cookie->connectionId > -1) {
1642 DropConnection(cookie->connectionId, cookie->i_flags);
1643 cookie->connectionId = -1;
1644 }
1645
1646 /* If using a MT connection, return it. */
1647 if (cookie->conn_user != NULL &&
1648 cookie->conn_user->conn_mt != NULL)
1649 __s_api_conn_mt_return(cookie->conn_user);
1650
1651 rc = __s_api_getConnection(NULL, cookie->i_flags,
1652 cookie->i_auth, &connectionId, &conp,
1653 &cookie->errorp, fail_if_new_pwd_reqd,
1654 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1655
1656 /*
1657 * If password control attached in *cookie->errorp,
1658 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1659 * free the error structure (we do not need
1660 * the sec_to_expired info).
1661 * Reset rc to NS_LDAP_SUCCESS.
1662 */
1663 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1664 (void) __ns_ldap_freeError(
1665 &cookie->errorp);
1666 cookie->errorp = NULL;
1667 rc = NS_LDAP_SUCCESS;
1668 }
1669
1670 if (rc != NS_LDAP_SUCCESS) {
1671 cookie->err_rc = rc;
1672 return (-1);
1673 }
1674 cookie->conn = conp;
1675 cookie->connectionId = connectionId;
1676 return (0);
1677 }
1678
1679 static int
get_referral_session(ns_ldap_cookie_t * cookie)1680 get_referral_session(ns_ldap_cookie_t *cookie)
1681 {
1682 ConnectionID connectionId = -1;
1683 Connection *conp = NULL;
1684 int rc;
1685 int fail_if_new_pwd_reqd = 1;
1686
1687 if (cookie->connectionId > -1) {
1688 DropConnection(cookie->connectionId, cookie->i_flags);
1689 cookie->connectionId = -1;
1690 }
1691
1692 /* set it up to use a connection opened for referral */
1693 if (cookie->conn_user != NULL) {
1694 /* If using a MT connection, return it. */
1695 if (cookie->conn_user->conn_mt != NULL)
1696 __s_api_conn_mt_return(cookie->conn_user);
1697 cookie->conn_user->referral = B_TRUE;
1698 }
1699
1700 rc = __s_api_getConnection(cookie->refpos->refHost, 0,
1701 cookie->i_auth, &connectionId, &conp,
1702 &cookie->errorp, fail_if_new_pwd_reqd,
1703 cookie->nopasswd_acct_mgmt, cookie->conn_user);
1704
1705 /*
1706 * If password control attached in *cookie->errorp,
1707 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1708 * free the error structure (we do not need
1709 * the sec_to_expired info).
1710 * Reset rc to NS_LDAP_SUCCESS.
1711 */
1712 if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1713 (void) __ns_ldap_freeError(
1714 &cookie->errorp);
1715 cookie->errorp = NULL;
1716 rc = NS_LDAP_SUCCESS;
1717 }
1718
1719 if (rc != NS_LDAP_SUCCESS) {
1720 cookie->err_rc = rc;
1721 return (-1);
1722 }
1723 cookie->conn = conp;
1724 cookie->connectionId = connectionId;
1725 return (0);
1726 }
1727
1728 static int
paging_supported(ns_ldap_cookie_t * cookie)1729 paging_supported(ns_ldap_cookie_t *cookie)
1730 {
1731 int rc;
1732
1733 cookie->listType = 0;
1734 rc = __s_api_isCtrlSupported(cookie->conn,
1735 LDAP_CONTROL_VLVREQUEST);
1736 if (rc == NS_LDAP_SUCCESS) {
1737 cookie->listType = VLVCTRLFLAG;
1738 return (1);
1739 }
1740 rc = __s_api_isCtrlSupported(cookie->conn,
1741 LDAP_CONTROL_SIMPLE_PAGE);
1742 if (rc == NS_LDAP_SUCCESS) {
1743 cookie->listType = SIMPLEPAGECTRLFLAG;
1744 return (1);
1745 }
1746 return (0);
1747 }
1748
1749 typedef struct servicesorttype {
1750 char *service;
1751 ns_srvsidesort_t type;
1752 } servicesorttype_t;
1753
1754 static servicesorttype_t *sort_type = NULL;
1755 static int sort_type_size = 0;
1756 static int sort_type_hwm = 0;
1757 static mutex_t sort_type_mutex = DEFAULTMUTEX;
1758
1759
1760 static ns_srvsidesort_t
get_srvsidesort_type(char * service)1761 get_srvsidesort_type(char *service)
1762 {
1763 int i;
1764 ns_srvsidesort_t type = SSS_UNKNOWN;
1765
1766 if (service == NULL)
1767 return (type);
1768
1769 (void) mutex_lock(&sort_type_mutex);
1770 if (sort_type != NULL) {
1771 for (i = 0; i < sort_type_hwm; i++) {
1772 if (strcmp(sort_type[i].service, service) == 0) {
1773 type = sort_type[i].type;
1774 break;
1775 }
1776 }
1777 }
1778 (void) mutex_unlock(&sort_type_mutex);
1779 return (type);
1780 }
1781
1782 static void
update_srvsidesort_type(char * service,ns_srvsidesort_t type)1783 update_srvsidesort_type(char *service, ns_srvsidesort_t type)
1784 {
1785 int i, size;
1786 servicesorttype_t *tmp;
1787
1788 if (service == NULL)
1789 return;
1790
1791 (void) mutex_lock(&sort_type_mutex);
1792
1793 for (i = 0; i < sort_type_hwm; i++) {
1794 if (strcmp(sort_type[i].service, service) == 0) {
1795 sort_type[i].type = type;
1796 (void) mutex_unlock(&sort_type_mutex);
1797 return;
1798 }
1799 }
1800 if (sort_type == NULL) {
1801 size = 10;
1802 tmp = malloc(size * sizeof (servicesorttype_t));
1803 if (tmp == NULL) {
1804 (void) mutex_unlock(&sort_type_mutex);
1805 return;
1806 }
1807 sort_type = tmp;
1808 sort_type_size = size;
1809 } else if (sort_type_hwm >= sort_type_size) {
1810 size = sort_type_size + 10;
1811 tmp = realloc(sort_type, size * sizeof (servicesorttype_t));
1812 if (tmp == NULL) {
1813 (void) mutex_unlock(&sort_type_mutex);
1814 return;
1815 }
1816 sort_type = tmp;
1817 sort_type_size = size;
1818 }
1819 sort_type[sort_type_hwm].service = strdup(service);
1820 if (sort_type[sort_type_hwm].service == NULL) {
1821 (void) mutex_unlock(&sort_type_mutex);
1822 return;
1823 }
1824 sort_type[sort_type_hwm].type = type;
1825 sort_type_hwm++;
1826
1827 (void) mutex_unlock(&sort_type_mutex);
1828 }
1829
1830 static int
setup_vlv_params(ns_ldap_cookie_t * cookie)1831 setup_vlv_params(ns_ldap_cookie_t *cookie)
1832 {
1833 LDAPControl **ctrls;
1834 LDAPsortkey **sortkeylist;
1835 LDAPControl *sortctrl = NULL;
1836 LDAPControl *vlvctrl = NULL;
1837 LDAPVirtualList vlist;
1838 char *sortattr;
1839 int rc;
1840 int free_sort = FALSE;
1841
1842 _freeControlList(&cookie->p_serverctrls);
1843
1844 if (cookie->sortTypeTry == SSS_UNKNOWN)
1845 cookie->sortTypeTry = get_srvsidesort_type(cookie->service);
1846 if (cookie->sortTypeTry == SSS_UNKNOWN)
1847 cookie->sortTypeTry = SSS_SINGLE_ATTR;
1848
1849 if (cookie->sortTypeTry == SSS_SINGLE_ATTR) {
1850 if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
1851 cookie->i_sortattr) {
1852 sortattr = __ns_ldap_mapAttribute(cookie->service,
1853 cookie->i_sortattr);
1854 free_sort = TRUE;
1855 } else if (cookie->i_sortattr) {
1856 sortattr = (char *)cookie->i_sortattr;
1857 } else {
1858 sortattr = "cn";
1859 }
1860 } else {
1861 sortattr = "cn uid";
1862 }
1863
1864 rc = ldap_create_sort_keylist(&sortkeylist, sortattr);
1865 if (free_sort)
1866 free(sortattr);
1867 if (rc != LDAP_SUCCESS) {
1868 (void) ldap_get_option(cookie->conn->ld,
1869 LDAP_OPT_ERROR_NUMBER, &rc);
1870 return (rc);
1871 }
1872 rc = ldap_create_sort_control(cookie->conn->ld,
1873 sortkeylist, 1, &sortctrl);
1874 ldap_free_sort_keylist(sortkeylist);
1875 if (rc != LDAP_SUCCESS) {
1876 (void) ldap_get_option(cookie->conn->ld,
1877 LDAP_OPT_ERROR_NUMBER, &rc);
1878 return (rc);
1879 }
1880
1881 vlist.ldvlist_index = cookie->index;
1882 vlist.ldvlist_size = 0;
1883
1884 vlist.ldvlist_before_count = 0;
1885 vlist.ldvlist_after_count = LISTPAGESIZE-1;
1886 vlist.ldvlist_attrvalue = NULL;
1887 vlist.ldvlist_extradata = NULL;
1888
1889 rc = ldap_create_virtuallist_control(cookie->conn->ld,
1890 &vlist, &vlvctrl);
1891 if (rc != LDAP_SUCCESS) {
1892 ldap_control_free(sortctrl);
1893 (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1894 &rc);
1895 return (rc);
1896 }
1897
1898 ctrls = (LDAPControl **)calloc(3, sizeof (LDAPControl *));
1899 if (ctrls == NULL) {
1900 ldap_control_free(sortctrl);
1901 ldap_control_free(vlvctrl);
1902 return (LDAP_NO_MEMORY);
1903 }
1904
1905 ctrls[0] = sortctrl;
1906 ctrls[1] = vlvctrl;
1907
1908 cookie->p_serverctrls = ctrls;
1909 return (LDAP_SUCCESS);
1910 }
1911
1912 static int
setup_simplepg_params(ns_ldap_cookie_t * cookie)1913 setup_simplepg_params(ns_ldap_cookie_t *cookie)
1914 {
1915 LDAPControl **ctrls;
1916 LDAPControl *pgctrl = NULL;
1917 int rc;
1918
1919 _freeControlList(&cookie->p_serverctrls);
1920
1921 rc = ldap_create_page_control(cookie->conn->ld, LISTPAGESIZE,
1922 cookie->ctrlCookie, (char)0, &pgctrl);
1923 if (rc != LDAP_SUCCESS) {
1924 (void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1925 &rc);
1926 return (rc);
1927 }
1928
1929 ctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
1930 if (ctrls == NULL) {
1931 ldap_control_free(pgctrl);
1932 return (LDAP_NO_MEMORY);
1933 }
1934 ctrls[0] = pgctrl;
1935 cookie->p_serverctrls = ctrls;
1936 return (LDAP_SUCCESS);
1937 }
1938
1939 static void
proc_result_referrals(ns_ldap_cookie_t * cookie)1940 proc_result_referrals(ns_ldap_cookie_t *cookie)
1941 {
1942 int errCode, i, rc;
1943 char **referrals = NULL;
1944
1945 /*
1946 * Only follow one level of referrals, i.e.
1947 * if already in referral mode, do nothing
1948 */
1949 if (cookie->refpos == NULL) {
1950 cookie->new_state = END_RESULT;
1951 rc = ldap_parse_result(cookie->conn->ld,
1952 cookie->resultMsg,
1953 &errCode, NULL,
1954 NULL, &referrals,
1955 NULL, 0);
1956 if (rc != NS_LDAP_SUCCESS) {
1957 (void) ldap_get_option(cookie->conn->ld,
1958 LDAP_OPT_ERROR_NUMBER,
1959 &cookie->err_rc);
1960 cookie->new_state = LDAP_ERROR;
1961 return;
1962 }
1963 if (errCode == LDAP_REFERRAL) {
1964 for (i = 0; referrals[i] != NULL;
1965 i++) {
1966 /* add to referral list */
1967 rc = __s_api_addRefInfo(
1968 &cookie->reflist,
1969 referrals[i],
1970 cookie->basedn,
1971 &cookie->scope,
1972 cookie->filter,
1973 cookie->conn->ld);
1974 if (rc != NS_LDAP_SUCCESS) {
1975 cookie->new_state =
1976 ERROR;
1977 break;
1978 }
1979 }
1980 ldap_value_free(referrals);
1981 }
1982 }
1983 }
1984
1985 static void
proc_search_references(ns_ldap_cookie_t * cookie)1986 proc_search_references(ns_ldap_cookie_t *cookie)
1987 {
1988 char **refurls = NULL;
1989 int i, rc;
1990
1991 /*
1992 * Only follow one level of referrals, i.e.
1993 * if already in referral mode, do nothing
1994 */
1995 if (cookie->refpos == NULL) {
1996 refurls = ldap_get_reference_urls(
1997 cookie->conn->ld,
1998 cookie->resultMsg);
1999 if (refurls == NULL) {
2000 (void) ldap_get_option(cookie->conn->ld,
2001 LDAP_OPT_ERROR_NUMBER,
2002 &cookie->err_rc);
2003 cookie->new_state = LDAP_ERROR;
2004 return;
2005 }
2006 for (i = 0; refurls[i] != NULL; i++) {
2007 /* add to referral list */
2008 rc = __s_api_addRefInfo(
2009 &cookie->reflist,
2010 refurls[i],
2011 cookie->basedn,
2012 &cookie->scope,
2013 cookie->filter,
2014 cookie->conn->ld);
2015 if (rc != NS_LDAP_SUCCESS) {
2016 cookie->new_state =
2017 ERROR;
2018 break;
2019 }
2020 }
2021 /* free allocated storage */
2022 for (i = 0; refurls[i] != NULL; i++)
2023 free(refurls[i]);
2024 }
2025 }
2026
2027 static ns_state_t
multi_result(ns_ldap_cookie_t * cookie)2028 multi_result(ns_ldap_cookie_t *cookie)
2029 {
2030 char errstr[MAXERROR];
2031 char *err;
2032 ns_ldap_error_t **errorp = NULL;
2033 LDAPControl **retCtrls = NULL;
2034 int i, rc;
2035 int errCode;
2036 boolean_t finished = B_FALSE;
2037 unsigned long target_posp = 0;
2038 unsigned long list_size = 0;
2039 unsigned int count = 0;
2040 char **referrals = NULL;
2041
2042 if (cookie->listType == VLVCTRLFLAG) {
2043 rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2044 &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2045 if (rc != LDAP_SUCCESS) {
2046 (void) ldap_get_option(cookie->conn->ld,
2047 LDAP_OPT_ERROR_NUMBER,
2048 &cookie->err_rc);
2049 (void) sprintf(errstr,
2050 gettext("LDAP ERROR (%d): %s.\n"),
2051 cookie->err_rc,
2052 gettext(ldap_err2string(cookie->err_rc)));
2053 err = strdup(errstr);
2054 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2055 LDAP_ERROR);
2056 cookie->err_rc = NS_LDAP_INTERNAL;
2057 cookie->errorp = *errorp;
2058 return (LDAP_ERROR);
2059 }
2060 if (errCode == LDAP_REFERRAL) {
2061 for (i = 0; referrals[i] != NULL;
2062 i++) {
2063 /* add to referral list */
2064 rc = __s_api_addRefInfo(
2065 &cookie->reflist,
2066 referrals[i],
2067 cookie->basedn,
2068 &cookie->scope,
2069 cookie->filter,
2070 cookie->conn->ld);
2071 if (rc != NS_LDAP_SUCCESS) {
2072 ldap_value_free(
2073 referrals);
2074 if (retCtrls)
2075 ldap_controls_free(
2076 retCtrls);
2077 return (ERROR);
2078 }
2079 }
2080 ldap_value_free(referrals);
2081 if (retCtrls)
2082 ldap_controls_free(retCtrls);
2083 return (END_RESULT);
2084 }
2085 if (retCtrls) {
2086 rc = ldap_parse_virtuallist_control(
2087 cookie->conn->ld, retCtrls,
2088 &target_posp, &list_size, &errCode);
2089 if (rc == LDAP_SUCCESS) {
2090 /*
2091 * AD does not return valid target_posp
2092 * and list_size
2093 */
2094 if (target_posp != 0 && list_size != 0) {
2095 cookie->index =
2096 target_posp + LISTPAGESIZE;
2097 if (cookie->index > list_size)
2098 finished = B_TRUE;
2099 } else {
2100 if (cookie->entryCount < LISTPAGESIZE)
2101 finished = B_TRUE;
2102 else
2103 cookie->index +=
2104 cookie->entryCount;
2105 }
2106 }
2107 ldap_controls_free(retCtrls);
2108 retCtrls = NULL;
2109 } else {
2110 finished = B_TRUE;
2111 }
2112 } else if (cookie->listType == SIMPLEPAGECTRLFLAG) {
2113 rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2114 &errCode, NULL, NULL, &referrals, &retCtrls, 0);
2115 if (rc != LDAP_SUCCESS) {
2116 (void) ldap_get_option(cookie->conn->ld,
2117 LDAP_OPT_ERROR_NUMBER,
2118 &cookie->err_rc);
2119 (void) sprintf(errstr,
2120 gettext("LDAP ERROR (%d): %s.\n"),
2121 cookie->err_rc,
2122 gettext(ldap_err2string(cookie->err_rc)));
2123 err = strdup(errstr);
2124 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2125 LDAP_ERROR);
2126 cookie->err_rc = NS_LDAP_INTERNAL;
2127 cookie->errorp = *errorp;
2128 return (LDAP_ERROR);
2129 }
2130 if (errCode == LDAP_REFERRAL) {
2131 for (i = 0; referrals[i] != NULL;
2132 i++) {
2133 /* add to referral list */
2134 rc = __s_api_addRefInfo(
2135 &cookie->reflist,
2136 referrals[i],
2137 cookie->basedn,
2138 &cookie->scope,
2139 cookie->filter,
2140 cookie->conn->ld);
2141 if (rc != NS_LDAP_SUCCESS) {
2142 ldap_value_free(
2143 referrals);
2144 if (retCtrls)
2145 ldap_controls_free(
2146 retCtrls);
2147 return (ERROR);
2148 }
2149 }
2150 ldap_value_free(referrals);
2151 if (retCtrls)
2152 ldap_controls_free(retCtrls);
2153 return (END_RESULT);
2154 }
2155 if (retCtrls) {
2156 if (cookie->ctrlCookie)
2157 ber_bvfree(cookie->ctrlCookie);
2158 cookie->ctrlCookie = NULL;
2159 rc = ldap_parse_page_control(
2160 cookie->conn->ld, retCtrls,
2161 &count, &cookie->ctrlCookie);
2162 if (rc == LDAP_SUCCESS) {
2163 if ((cookie->ctrlCookie == NULL) ||
2164 (cookie->ctrlCookie->bv_val == NULL) ||
2165 (cookie->ctrlCookie->bv_len == 0))
2166 finished = B_TRUE;
2167 }
2168 ldap_controls_free(retCtrls);
2169 retCtrls = NULL;
2170 } else {
2171 finished = B_TRUE;
2172 }
2173 }
2174 if (!finished && cookie->listType == VLVCTRLFLAG)
2175 return (NEXT_VLV);
2176 if (!finished && cookie->listType == SIMPLEPAGECTRLFLAG)
2177 return (NEXT_PAGE);
2178 if (finished)
2179 return (END_RESULT);
2180 return (ERROR);
2181 }
2182
2183 /*
2184 * clear_results(ns_ldap_cookie_t):
2185 *
2186 * Attempt to obtain remnants of ldap responses and free them. If remnants are
2187 * not obtained within a certain time period tell the server we wish to abandon
2188 * the request.
2189 *
2190 * Note that we do not initially tell the server to abandon the request as that
2191 * can be an expensive operation for the server, while it is cheap for us to
2192 * just flush the input.
2193 *
2194 * If something was to remain in libldap queue as a result of some error then
2195 * it would be freed later during drop connection call or when no other
2196 * requests share the connection.
2197 */
2198 static void
clear_results(ns_ldap_cookie_t * cookie)2199 clear_results(ns_ldap_cookie_t *cookie)
2200 {
2201 int rc;
2202 if (cookie->conn != NULL && cookie->conn->ld != NULL &&
2203 (cookie->connectionId != -1 ||
2204 (cookie->conn_user != NULL &&
2205 cookie->conn_user->conn_mt != NULL)) &&
2206 cookie->msgId != 0) {
2207 /*
2208 * We need to cleanup the rest of response (if there is such)
2209 * and LDAP abandon is too heavy for LDAP servers, so we will
2210 * wait for the rest of response till timeout and "process" it.
2211 */
2212 rc = ldap_result(cookie->conn->ld, cookie->msgId, LDAP_MSG_ALL,
2213 (struct timeval *)&cookie->search_timeout,
2214 &cookie->resultMsg);
2215 if (rc != -1 && rc != 0 && cookie->resultMsg != NULL) {
2216 (void) ldap_msgfree(cookie->resultMsg);
2217 cookie->resultMsg = NULL;
2218 }
2219
2220 /*
2221 * If there was timeout then we will send ABANDON request to
2222 * LDAP server to decrease load.
2223 */
2224 if (rc == 0)
2225 (void) ldap_abandon_ext(cookie->conn->ld, cookie->msgId,
2226 NULL, NULL);
2227 /* Disassociate cookie with msgId */
2228 cookie->msgId = 0;
2229 }
2230 }
2231
2232 /*
2233 * This state machine performs one or more LDAP searches to a given
2234 * directory server using service search descriptors and schema
2235 * mapping as appropriate. The approximate pseudocode for
2236 * this routine is the following:
2237 * Given the current configuration [set/reset connection etc.]
2238 * and the current service search descriptor list
2239 * or default search filter parameters
2240 * foreach (service search filter) {
2241 * initialize the filter [via filter_init if appropriate]
2242 * get a valid session/connection (preferably the current one)
2243 * Recover if the connection is lost
2244 * perform the search
2245 * foreach (result entry) {
2246 * process result [via callback if appropriate]
2247 * save result for caller if accepted.
2248 * exit and return all collected if allResults found;
2249 * }
2250 * }
2251 * return collected results and exit
2252 */
2253
2254 static
2255 ns_state_t
search_state_machine(ns_ldap_cookie_t * cookie,ns_state_t state,int cycle)2256 search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
2257 {
2258 char errstr[MAXERROR];
2259 char *err;
2260 int rc, ret;
2261 int rc_save;
2262 ns_ldap_entry_t *nextEntry;
2263 ns_ldap_error_t *error = NULL;
2264 ns_ldap_error_t **errorp;
2265 struct timeval tv;
2266
2267 errorp = &error;
2268 cookie->state = state;
2269 errstr[0] = '\0';
2270
2271 for (;;) {
2272 switch (cookie->state) {
2273 case CLEAR_RESULTS:
2274 clear_results(cookie);
2275 cookie->new_state = EXIT;
2276 break;
2277 case GET_ACCT_MGMT_INFO:
2278 /*
2279 * Set the flag to get ldap account management controls.
2280 */
2281 cookie->nopasswd_acct_mgmt = 1;
2282 cookie->new_state = INIT;
2283 break;
2284 case EXIT:
2285 /* state engine/connection cleaned up in delete */
2286 if (cookie->attribute) {
2287 __s_api_free2dArray(cookie->attribute);
2288 cookie->attribute = NULL;
2289 }
2290 if (cookie->reflist) {
2291 __s_api_deleteRefInfo(cookie->reflist);
2292 cookie->reflist = NULL;
2293 }
2294 return (EXIT);
2295 case INIT:
2296 cookie->sdpos = NULL;
2297 cookie->new_state = NEXT_SEARCH_DESCRIPTOR;
2298 if (cookie->attribute) {
2299 __s_api_free2dArray(cookie->attribute);
2300 cookie->attribute = NULL;
2301 }
2302 if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
2303 cookie->i_attr) {
2304 cookie->attribute =
2305 __ns_ldap_mapAttributeList(
2306 cookie->service,
2307 cookie->i_attr);
2308 }
2309 break;
2310 case REINIT:
2311 /* Check if we've reached MAX retries. */
2312 cookie->retries++;
2313 if (cookie->retries > NS_LIST_TRY_MAX - 1) {
2314 cookie->new_state = LDAP_ERROR;
2315 break;
2316 }
2317
2318 /*
2319 * Even if we still have retries left, check
2320 * if retry is possible.
2321 */
2322 if (cookie->conn_user != NULL) {
2323 int retry;
2324 ns_conn_mgmt_t *cmg;
2325 cmg = cookie->conn_user->conn_mgmt;
2326 retry = cookie->conn_user->retry;
2327 if (cmg != NULL && cmg->cfg_reloaded == 1)
2328 retry = 1;
2329 if (retry == 0) {
2330 cookie->new_state = LDAP_ERROR;
2331 break;
2332 }
2333 }
2334 /*
2335 * Free results if any, reset to the first
2336 * search descriptor and start a new session.
2337 */
2338 if (cookie->resultMsg != NULL) {
2339 (void) ldap_msgfree(cookie->resultMsg);
2340 cookie->resultMsg = NULL;
2341 }
2342 (void) __ns_ldap_freeError(&cookie->errorp);
2343 (void) __ns_ldap_freeResult(&cookie->result);
2344 cookie->sdpos = cookie->sdlist;
2345 cookie->err_from_result = 0;
2346 cookie->err_rc = 0;
2347 cookie->new_state = NEXT_SESSION;
2348 break;
2349 case NEXT_SEARCH_DESCRIPTOR:
2350 /* get next search descriptor */
2351 if (cookie->sdpos == NULL) {
2352 cookie->sdpos = cookie->sdlist;
2353 cookie->new_state = GET_SESSION;
2354 } else {
2355 cookie->sdpos++;
2356 cookie->new_state = NEXT_SEARCH;
2357 }
2358 if (*cookie->sdpos == NULL)
2359 cookie->new_state = EXIT;
2360 break;
2361 case GET_SESSION:
2362 if (get_current_session(cookie) < 0)
2363 cookie->new_state = NEXT_SESSION;
2364 else
2365 cookie->new_state = NEXT_SEARCH;
2366 break;
2367 case NEXT_SESSION:
2368 if (get_next_session(cookie) < 0)
2369 cookie->new_state = RESTART_SESSION;
2370 else
2371 cookie->new_state = NEXT_SEARCH;
2372 break;
2373 case RESTART_SESSION:
2374 if (cookie->i_flags & NS_LDAP_HARD) {
2375 cookie->new_state = NEXT_SESSION;
2376 break;
2377 }
2378 (void) sprintf(errstr,
2379 gettext("Session error no available conn.\n"),
2380 state);
2381 err = strdup(errstr);
2382 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2383 LDAP_ERROR);
2384 cookie->err_rc = NS_LDAP_INTERNAL;
2385 cookie->errorp = *errorp;
2386 cookie->new_state = EXIT;
2387 break;
2388 case NEXT_SEARCH:
2389 /* setup referrals search if necessary */
2390 if (cookie->refpos) {
2391 if (setup_referral_search(cookie) < 0) {
2392 cookie->new_state = EXIT;
2393 break;
2394 }
2395 } else if (setup_next_search(cookie) < 0) {
2396 cookie->new_state = EXIT;
2397 break;
2398 }
2399 /* only do VLV/PAGE on scopes onelevel/subtree */
2400 if (paging_supported(cookie)) {
2401 if (cookie->use_paging &&
2402 (cookie->scope != LDAP_SCOPE_BASE)) {
2403 cookie->index = 1;
2404 if (cookie->listType == VLVCTRLFLAG)
2405 cookie->new_state = NEXT_VLV;
2406 else
2407 cookie->new_state = NEXT_PAGE;
2408 break;
2409 }
2410 }
2411 cookie->new_state = ONE_SEARCH;
2412 break;
2413 case NEXT_VLV:
2414 rc = setup_vlv_params(cookie);
2415 if (rc != LDAP_SUCCESS) {
2416 cookie->err_rc = rc;
2417 cookie->new_state = LDAP_ERROR;
2418 break;
2419 }
2420 cookie->next_state = MULTI_RESULT;
2421 cookie->new_state = DO_SEARCH;
2422 break;
2423 case NEXT_PAGE:
2424 rc = setup_simplepg_params(cookie);
2425 if (rc != LDAP_SUCCESS) {
2426 cookie->err_rc = rc;
2427 cookie->new_state = LDAP_ERROR;
2428 break;
2429 }
2430 cookie->next_state = MULTI_RESULT;
2431 cookie->new_state = DO_SEARCH;
2432 break;
2433 case ONE_SEARCH:
2434 cookie->next_state = NEXT_RESULT;
2435 cookie->new_state = DO_SEARCH;
2436 break;
2437 case DO_SEARCH:
2438 cookie->entryCount = 0;
2439 rc = ldap_search_ext(cookie->conn->ld,
2440 cookie->basedn,
2441 cookie->scope,
2442 cookie->filter,
2443 cookie->attribute,
2444 0,
2445 cookie->p_serverctrls,
2446 NULL,
2447 &cookie->search_timeout, 0,
2448 &cookie->msgId);
2449 if (rc != LDAP_SUCCESS) {
2450 if (rc == LDAP_BUSY ||
2451 rc == LDAP_UNAVAILABLE ||
2452 rc == LDAP_UNWILLING_TO_PERFORM ||
2453 rc == LDAP_CONNECT_ERROR ||
2454 rc == LDAP_SERVER_DOWN) {
2455
2456 if (cookie->reinit_on_retriable_err) {
2457 cookie->err_rc = rc;
2458 cookie->new_state = REINIT;
2459 } else {
2460 cookie->new_state =
2461 NEXT_SESSION;
2462 }
2463
2464 /*
2465 * If not able to reach the
2466 * server, inform the ldap
2467 * cache manager that the
2468 * server should be removed
2469 * from it's server list.
2470 * Thus, the manager will not
2471 * return this server on the next
2472 * get-server request and will
2473 * also reduce the server list
2474 * refresh TTL, so that it will
2475 * find out sooner when the server
2476 * is up again.
2477 */
2478 if ((rc == LDAP_CONNECT_ERROR ||
2479 rc == LDAP_SERVER_DOWN) &&
2480 (cookie->conn_user == NULL ||
2481 cookie->conn_user->conn_mt ==
2482 NULL)) {
2483 ret = __s_api_removeServer(
2484 cookie->conn->serverAddr);
2485 if (ret == NS_CACHE_NOSERVER &&
2486 cookie->conn_auth_type
2487 == NS_LDAP_AUTH_NONE) {
2488 /*
2489 * Couldn't remove
2490 * server from server
2491 * list.
2492 * Exit to avoid
2493 * potential infinite
2494 * loop.
2495 */
2496 cookie->err_rc = rc;
2497 cookie->new_state =
2498 LDAP_ERROR;
2499 }
2500 if (cookie->connectionId > -1) {
2501 /*
2502 * NS_LDAP_NEW_CONN
2503 * indicates that the
2504 * connection should
2505 * be deleted, not
2506 * kept alive
2507 */
2508 DropConnection(
2509 cookie->
2510 connectionId,
2511 NS_LDAP_NEW_CONN);
2512 cookie->connectionId =
2513 -1;
2514 }
2515 } else if ((rc == LDAP_CONNECT_ERROR ||
2516 rc == LDAP_SERVER_DOWN) &&
2517 cookie->conn_user != NULL) {
2518 if (cookie->
2519 reinit_on_retriable_err) {
2520 /*
2521 * MT connection not
2522 * usable, close it
2523 * before REINIT.
2524 * rc has already
2525 * been saved in
2526 * cookie->err_rc above.
2527 */
2528 __s_api_conn_mt_close(
2529 cookie->conn_user,
2530 rc,
2531 &cookie->errorp);
2532 } else {
2533 /*
2534 * MT connection not
2535 * usable, close it in
2536 * the LDAP_ERROR state.
2537 * A retry will be done
2538 * next if allowed.
2539 */
2540 cookie->err_rc = rc;
2541 cookie->new_state =
2542 LDAP_ERROR;
2543 }
2544 }
2545 break;
2546 }
2547 cookie->err_rc = rc;
2548 cookie->new_state = LDAP_ERROR;
2549 break;
2550 }
2551 cookie->new_state = cookie->next_state;
2552 break;
2553 case NEXT_RESULT:
2554 /*
2555 * Caller (e.g. __ns_ldap_list_batch_add)
2556 * does not want to block on ldap_result().
2557 * Therefore we execute ldap_result() with
2558 * a zeroed timeval.
2559 */
2560 if (cookie->no_wait == B_TRUE)
2561 (void) memset(&tv, 0, sizeof (tv));
2562 else
2563 tv = cookie->search_timeout;
2564 rc = ldap_result(cookie->conn->ld, cookie->msgId,
2565 LDAP_MSG_ONE,
2566 &tv,
2567 &cookie->resultMsg);
2568 if (rc == LDAP_RES_SEARCH_RESULT) {
2569 cookie->new_state = END_RESULT;
2570 /* check and process referrals info */
2571 if (cookie->followRef)
2572 proc_result_referrals(
2573 cookie);
2574 (void) ldap_msgfree(cookie->resultMsg);
2575 cookie->resultMsg = NULL;
2576 break;
2577 }
2578 /* handle referrals if necessary */
2579 if (rc == LDAP_RES_SEARCH_REFERENCE) {
2580 if (cookie->followRef)
2581 proc_search_references(cookie);
2582 (void) ldap_msgfree(cookie->resultMsg);
2583 cookie->resultMsg = NULL;
2584 break;
2585 }
2586 if (rc != LDAP_RES_SEARCH_ENTRY) {
2587 switch (rc) {
2588 case 0:
2589 if (cookie->no_wait == B_TRUE) {
2590 (void) ldap_msgfree(
2591 cookie->resultMsg);
2592 cookie->resultMsg = NULL;
2593 return (cookie->new_state);
2594 }
2595 rc = LDAP_TIMEOUT;
2596 break;
2597 case -1:
2598 rc = ldap_get_lderrno(cookie->conn->ld,
2599 NULL, NULL);
2600 break;
2601 default:
2602 rc = ldap_result2error(cookie->conn->ld,
2603 cookie->resultMsg, 1);
2604 break;
2605 }
2606 if ((rc == LDAP_TIMEOUT ||
2607 rc == LDAP_SERVER_DOWN) &&
2608 (cookie->conn_user == NULL ||
2609 cookie->conn_user->conn_mt == NULL)) {
2610 if (rc == LDAP_TIMEOUT)
2611 (void) __s_api_removeServer(
2612 cookie->conn->serverAddr);
2613 if (cookie->connectionId > -1) {
2614 DropConnection(
2615 cookie->connectionId,
2616 NS_LDAP_NEW_CONN);
2617 cookie->connectionId = -1;
2618 }
2619 cookie->err_from_result = 1;
2620 }
2621 (void) ldap_msgfree(cookie->resultMsg);
2622 cookie->resultMsg = NULL;
2623 if (rc == LDAP_BUSY ||
2624 rc == LDAP_UNAVAILABLE ||
2625 rc == LDAP_UNWILLING_TO_PERFORM) {
2626 if (cookie->reinit_on_retriable_err) {
2627 cookie->err_rc = rc;
2628 cookie->err_from_result = 1;
2629 cookie->new_state = REINIT;
2630 } else {
2631 cookie->new_state =
2632 NEXT_SESSION;
2633 }
2634 break;
2635 }
2636 if ((rc == LDAP_CONNECT_ERROR ||
2637 rc == LDAP_SERVER_DOWN) &&
2638 cookie->reinit_on_retriable_err) {
2639 ns_ldap_error_t *errorp = NULL;
2640 cookie->err_rc = rc;
2641 cookie->err_from_result = 1;
2642 cookie->new_state = REINIT;
2643 if (cookie->conn_user != NULL)
2644 __s_api_conn_mt_close(
2645 cookie->conn_user,
2646 rc, &errorp);
2647 if (errorp != NULL) {
2648 (void) __ns_ldap_freeError(
2649 &cookie->errorp);
2650 cookie->errorp = errorp;
2651 }
2652 break;
2653 }
2654 cookie->err_rc = rc;
2655 cookie->new_state = LDAP_ERROR;
2656 break;
2657 }
2658 /* else LDAP_RES_SEARCH_ENTRY */
2659 /* get account management response control */
2660 if (cookie->nopasswd_acct_mgmt == 1) {
2661 rc = ldap_get_entry_controls(cookie->conn->ld,
2662 cookie->resultMsg,
2663 &(cookie->resultctrl));
2664 if (rc != LDAP_SUCCESS) {
2665 cookie->new_state = LDAP_ERROR;
2666 cookie->err_rc = rc;
2667 break;
2668 }
2669 }
2670 rc = __s_api_getEntry(cookie);
2671 (void) ldap_msgfree(cookie->resultMsg);
2672 cookie->resultMsg = NULL;
2673 if (rc != NS_LDAP_SUCCESS) {
2674 cookie->new_state = LDAP_ERROR;
2675 break;
2676 }
2677 cookie->new_state = PROCESS_RESULT;
2678 cookie->next_state = NEXT_RESULT;
2679 break;
2680 case MULTI_RESULT:
2681 if (cookie->no_wait == B_TRUE)
2682 (void) memset(&tv, 0, sizeof (tv));
2683 else
2684 tv = cookie->search_timeout;
2685 rc = ldap_result(cookie->conn->ld, cookie->msgId,
2686 LDAP_MSG_ONE,
2687 &tv,
2688 &cookie->resultMsg);
2689 if (rc == LDAP_RES_SEARCH_RESULT) {
2690 rc = ldap_result2error(cookie->conn->ld,
2691 cookie->resultMsg, 0);
2692 if (rc == LDAP_ADMINLIMIT_EXCEEDED &&
2693 cookie->listType == VLVCTRLFLAG &&
2694 cookie->sortTypeTry == SSS_SINGLE_ATTR) {
2695 /* Try old "cn uid" server side sort */
2696 cookie->sortTypeTry = SSS_CN_UID_ATTRS;
2697 cookie->new_state = NEXT_VLV;
2698 (void) ldap_msgfree(cookie->resultMsg);
2699 cookie->resultMsg = NULL;
2700 break;
2701 }
2702 if (rc != LDAP_SUCCESS) {
2703 cookie->err_rc = rc;
2704 cookie->new_state = LDAP_ERROR;
2705 (void) ldap_msgfree(cookie->resultMsg);
2706 cookie->resultMsg = NULL;
2707 break;
2708 }
2709 cookie->new_state = multi_result(cookie);
2710 (void) ldap_msgfree(cookie->resultMsg);
2711 cookie->resultMsg = NULL;
2712 break;
2713 }
2714 /* handle referrals if necessary */
2715 if (rc == LDAP_RES_SEARCH_REFERENCE &&
2716 cookie->followRef) {
2717 proc_search_references(cookie);
2718 (void) ldap_msgfree(cookie->resultMsg);
2719 cookie->resultMsg = NULL;
2720 break;
2721 }
2722 if (rc != LDAP_RES_SEARCH_ENTRY) {
2723 switch (rc) {
2724 case 0:
2725 if (cookie->no_wait == B_TRUE) {
2726 (void) ldap_msgfree(
2727 cookie->resultMsg);
2728 cookie->resultMsg = NULL;
2729 return (cookie->new_state);
2730 }
2731 rc = LDAP_TIMEOUT;
2732 break;
2733 case -1:
2734 rc = ldap_get_lderrno(cookie->conn->ld,
2735 NULL, NULL);
2736 break;
2737 default:
2738 rc = ldap_result2error(cookie->conn->ld,
2739 cookie->resultMsg, 1);
2740 break;
2741 }
2742 if ((rc == LDAP_TIMEOUT ||
2743 rc == LDAP_SERVER_DOWN) &&
2744 (cookie->conn_user == NULL ||
2745 cookie->conn_user->conn_mt == NULL)) {
2746 if (rc == LDAP_TIMEOUT)
2747 (void) __s_api_removeServer(
2748 cookie->conn->serverAddr);
2749 if (cookie->connectionId > -1) {
2750 DropConnection(
2751 cookie->connectionId,
2752 NS_LDAP_NEW_CONN);
2753 cookie->connectionId = -1;
2754 }
2755 cookie->err_from_result = 1;
2756 }
2757 (void) ldap_msgfree(cookie->resultMsg);
2758 cookie->resultMsg = NULL;
2759 if (rc == LDAP_BUSY ||
2760 rc == LDAP_UNAVAILABLE ||
2761 rc == LDAP_UNWILLING_TO_PERFORM) {
2762 if (cookie->reinit_on_retriable_err) {
2763 cookie->err_rc = rc;
2764 cookie->err_from_result = 1;
2765 cookie->new_state = REINIT;
2766 } else {
2767 cookie->new_state =
2768 NEXT_SESSION;
2769 }
2770 break;
2771 }
2772
2773 if ((rc == LDAP_CONNECT_ERROR ||
2774 rc == LDAP_SERVER_DOWN) &&
2775 cookie->reinit_on_retriable_err) {
2776 ns_ldap_error_t *errorp = NULL;
2777 cookie->err_rc = rc;
2778 cookie->err_from_result = 1;
2779 cookie->new_state = REINIT;
2780 if (cookie->conn_user != NULL)
2781 __s_api_conn_mt_close(
2782 cookie->conn_user,
2783 rc, &errorp);
2784 if (errorp != NULL) {
2785 (void) __ns_ldap_freeError(
2786 &cookie->errorp);
2787 cookie->errorp = errorp;
2788 }
2789 break;
2790 }
2791 cookie->err_rc = rc;
2792 cookie->new_state = LDAP_ERROR;
2793 break;
2794 }
2795 /* else LDAP_RES_SEARCH_ENTRY */
2796 cookie->entryCount++;
2797 rc = __s_api_getEntry(cookie);
2798 (void) ldap_msgfree(cookie->resultMsg);
2799 cookie->resultMsg = NULL;
2800 if (rc != NS_LDAP_SUCCESS) {
2801 cookie->new_state = LDAP_ERROR;
2802 break;
2803 }
2804 /*
2805 * If VLV search was successfull save the server
2806 * side sort type tried.
2807 */
2808 if (cookie->listType == VLVCTRLFLAG)
2809 update_srvsidesort_type(cookie->service,
2810 cookie->sortTypeTry);
2811
2812 cookie->new_state = PROCESS_RESULT;
2813 cookie->next_state = MULTI_RESULT;
2814 break;
2815 case PROCESS_RESULT:
2816 /* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
2817 if (cookie->use_usercb && cookie->callback) {
2818 rc = 0;
2819 for (nextEntry = cookie->result->entry;
2820 nextEntry != NULL;
2821 nextEntry = nextEntry->next) {
2822 rc = (*cookie->callback)(nextEntry,
2823 cookie->userdata);
2824
2825 if (rc == NS_LDAP_CB_DONE) {
2826 /* cb doesn't want any more data */
2827 rc = NS_LDAP_PARTIAL;
2828 cookie->err_rc = rc;
2829 break;
2830 } else if (rc != NS_LDAP_CB_NEXT) {
2831 /* invalid return code */
2832 rc = NS_LDAP_OP_FAILED;
2833 cookie->err_rc = rc;
2834 break;
2835 }
2836 }
2837 (void) __ns_ldap_freeResult(&cookie->result);
2838 cookie->result = NULL;
2839 }
2840 if (rc != 0) {
2841 cookie->new_state = EXIT;
2842 break;
2843 }
2844 /* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
2845 cookie->new_state = cookie->next_state;
2846 break;
2847 case END_PROCESS_RESULT:
2848 cookie->new_state = cookie->next_state;
2849 break;
2850 case END_RESULT:
2851 /*
2852 * XXX DO WE NEED THIS CASE?
2853 * if (search is complete) {
2854 * cookie->new_state = EXIT;
2855 * } else
2856 */
2857 /*
2858 * entering referral mode if necessary
2859 */
2860 if (cookie->followRef && cookie->reflist)
2861 cookie->new_state =
2862 NEXT_REFERRAL;
2863 else
2864 cookie->new_state =
2865 NEXT_SEARCH_DESCRIPTOR;
2866 break;
2867 case NEXT_REFERRAL:
2868 /* get next referral info */
2869 if (cookie->refpos == NULL)
2870 cookie->refpos =
2871 cookie->reflist;
2872 else
2873 cookie->refpos =
2874 cookie->refpos->next;
2875 /* check see if done with all referrals */
2876 if (cookie->refpos != NULL) {
2877 cookie->new_state =
2878 GET_REFERRAL_SESSION;
2879 } else {
2880 __s_api_deleteRefInfo(cookie->reflist);
2881 cookie->reflist = NULL;
2882 cookie->new_state =
2883 NEXT_SEARCH_DESCRIPTOR;
2884 if (cookie->conn_user != NULL)
2885 cookie->conn_user->referral = B_FALSE;
2886 }
2887 break;
2888 case GET_REFERRAL_SESSION:
2889 if (get_referral_session(cookie) < 0) {
2890 cookie->new_state = EXIT;
2891 } else {
2892 cookie->new_state = NEXT_SEARCH;
2893 }
2894 break;
2895 case LDAP_ERROR:
2896 rc_save = cookie->err_rc;
2897 if (cookie->err_from_result) {
2898 if (cookie->err_rc == LDAP_SERVER_DOWN) {
2899 (void) sprintf(errstr,
2900 gettext("LDAP ERROR (%d): "
2901 "Error occurred during"
2902 " receiving results. "
2903 "Connection to server lost."),
2904 cookie->err_rc);
2905 } else if (cookie->err_rc == LDAP_TIMEOUT) {
2906 (void) sprintf(errstr,
2907 gettext("LDAP ERROR (%d): "
2908 "Error occurred during"
2909 " receiving results. %s"
2910 "."), cookie->err_rc,
2911 ldap_err2string(
2912 cookie->err_rc));
2913 }
2914 } else {
2915 (void) sprintf(errstr,
2916 gettext("LDAP ERROR (%d): %s."),
2917 cookie->err_rc,
2918 ldap_err2string(cookie->err_rc));
2919 }
2920 err = strdup(errstr);
2921 if (cookie->err_from_result) {
2922 if (cookie->err_rc == LDAP_SERVER_DOWN) {
2923 MKERROR(LOG_INFO, *errorp,
2924 cookie->err_rc, err,
2925 LDAP_ERROR);
2926 } else {
2927 MKERROR(LOG_WARNING, *errorp,
2928 cookie->err_rc, err,
2929 LDAP_ERROR);
2930 }
2931 } else {
2932 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2933 err, LDAP_ERROR);
2934 }
2935 cookie->err_rc = NS_LDAP_INTERNAL;
2936 cookie->errorp = *errorp;
2937 if (cookie->conn_user != NULL) {
2938 if (rc_save == LDAP_SERVER_DOWN ||
2939 rc_save == LDAP_CONNECT_ERROR) {
2940 /*
2941 * MT connection is not usable,
2942 * close it.
2943 */
2944 __s_api_conn_mt_close(cookie->conn_user,
2945 rc_save, &cookie->errorp);
2946 return (ERROR);
2947 }
2948 }
2949 return (ERROR);
2950 default:
2951 case ERROR:
2952 (void) sprintf(errstr,
2953 gettext("Internal State machine exit (%d).\n"),
2954 cookie->state);
2955 err = strdup(errstr);
2956 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2957 LDAP_ERROR);
2958 cookie->err_rc = NS_LDAP_INTERNAL;
2959 cookie->errorp = *errorp;
2960 return (ERROR);
2961 }
2962
2963 if (cookie->conn_user != NULL &&
2964 cookie->conn_user->bad_mt_conn == B_TRUE) {
2965 __s_api_conn_mt_close(cookie->conn_user, 0, NULL);
2966 cookie->err_rc = cookie->conn_user->ns_rc;
2967 cookie->errorp = cookie->conn_user->ns_error;
2968 cookie->conn_user->ns_error = NULL;
2969 return (ERROR);
2970 }
2971
2972 if (cycle == ONE_STEP) {
2973 return (cookie->new_state);
2974 }
2975 cookie->state = cookie->new_state;
2976 }
2977 /*NOTREACHED*/
2978 #if 0
2979 (void) sprintf(errstr,
2980 gettext("Unexpected State machine error.\n"));
2981 err = strdup(errstr);
2982 MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NS_LDAP_MEMORY);
2983 cookie->err_rc = NS_LDAP_INTERNAL;
2984 cookie->errorp = *errorp;
2985 return (ERROR);
2986 #endif
2987 }
2988
2989 /*
2990 * For a lookup of shadow data, if shadow update is enabled,
2991 * check the calling process' privilege to ensure it's
2992 * allowed to perform such operation.
2993 */
2994 static int
check_shadow(ns_ldap_cookie_t * cookie,const char * service)2995 check_shadow(ns_ldap_cookie_t *cookie, const char *service)
2996 {
2997 char errstr[MAXERROR];
2998 char *err;
2999 boolean_t priv;
3000 /* caller */
3001 priv_set_t *ps;
3002 /* zone */
3003 priv_set_t *zs;
3004
3005 /*
3006 * If service is "shadow", we may need
3007 * to use privilege credentials.
3008 */
3009 if ((strcmp(service, "shadow") == 0) &&
3010 __ns_ldap_is_shadow_update_enabled()) {
3011 /*
3012 * Since we release admin credentials after
3013 * connection is closed and we do not cache
3014 * them, we allow any root or all zone
3015 * privilege process to read shadow data.
3016 */
3017 priv = (geteuid() == 0);
3018 if (!priv) {
3019 /* caller */
3020 ps = priv_allocset();
3021
3022 (void) getppriv(PRIV_EFFECTIVE, ps);
3023 zs = priv_str_to_set("zone", ",", NULL);
3024 priv = priv_isequalset(ps, zs);
3025 priv_freeset(ps);
3026 priv_freeset(zs);
3027 }
3028 if (!priv) {
3029 (void) sprintf(errstr,
3030 gettext("Permission denied"));
3031 err = strdup(errstr);
3032 if (err == NULL)
3033 return (NS_LDAP_MEMORY);
3034 MKERROR(LOG_INFO, cookie->errorp, NS_LDAP_INTERNAL, err,
3035 NS_LDAP_MEMORY);
3036 return (NS_LDAP_INTERNAL);
3037 }
3038 cookie->i_flags |= NS_LDAP_READ_SHADOW;
3039 /*
3040 * We do not want to reuse connection (hence
3041 * keep it open) with admin credentials.
3042 * If NS_LDAP_KEEP_CONN is set, reject the
3043 * request.
3044 */
3045 if (cookie->i_flags & NS_LDAP_KEEP_CONN)
3046 return (NS_LDAP_INVALID_PARAM);
3047 cookie->i_flags |= NS_LDAP_NEW_CONN;
3048 }
3049
3050 return (NS_LDAP_SUCCESS);
3051 }
3052
3053 /*
3054 * internal function for __ns_ldap_list
3055 */
3056 static int
ldap_list(ns_ldap_list_batch_t * batch,const char * service,const char * filter,const char * sortattr,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int * rcp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata,ns_conn_user_t * conn_user)3057 ldap_list(
3058 ns_ldap_list_batch_t *batch,
3059 const char *service,
3060 const char *filter,
3061 const char *sortattr,
3062 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3063 char **realfilter, const void *userdata),
3064 const char * const *attribute,
3065 const ns_cred_t *auth,
3066 const int flags,
3067 ns_ldap_result_t **rResult, /* return result entries */
3068 ns_ldap_error_t **errorp,
3069 int *rcp,
3070 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3071 const void *userdata, ns_conn_user_t *conn_user)
3072 {
3073 ns_ldap_cookie_t *cookie;
3074 ns_ldap_search_desc_t **sdlist = NULL;
3075 ns_ldap_search_desc_t *dptr;
3076 ns_ldap_error_t *error = NULL;
3077 char **dns = NULL;
3078 int scope;
3079 int rc;
3080 int from_result;
3081
3082 *errorp = NULL;
3083 *rResult = NULL;
3084 *rcp = NS_LDAP_SUCCESS;
3085
3086 /*
3087 * Sanity check - NS_LDAP_READ_SHADOW is for our
3088 * own internal use.
3089 */
3090 if (flags & NS_LDAP_READ_SHADOW)
3091 return (NS_LDAP_INVALID_PARAM);
3092
3093 /* Initialize State machine cookie */
3094 cookie = init_search_state_machine();
3095 if (cookie == NULL) {
3096 *rcp = NS_LDAP_MEMORY;
3097 return (NS_LDAP_MEMORY);
3098 }
3099 cookie->conn_user = conn_user;
3100
3101 /* see if need to follow referrals */
3102 rc = __s_api_toFollowReferrals(flags,
3103 &cookie->followRef, errorp);
3104 if (rc != NS_LDAP_SUCCESS) {
3105 delete_search_cookie(cookie);
3106 *rcp = rc;
3107 return (rc);
3108 }
3109
3110 /* get the service descriptor - or create a default one */
3111 rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3112 &sdlist, &error);
3113 if (rc != NS_LDAP_SUCCESS) {
3114 delete_search_cookie(cookie);
3115 *errorp = error;
3116 *rcp = rc;
3117 return (rc);
3118 }
3119
3120 if (sdlist == NULL) {
3121 /* Create default service Desc */
3122 sdlist = (ns_ldap_search_desc_t **)calloc(2,
3123 sizeof (ns_ldap_search_desc_t *));
3124 if (sdlist == NULL) {
3125 delete_search_cookie(cookie);
3126 cookie = NULL;
3127 *rcp = NS_LDAP_MEMORY;
3128 return (NS_LDAP_MEMORY);
3129 }
3130 dptr = (ns_ldap_search_desc_t *)
3131 calloc(1, sizeof (ns_ldap_search_desc_t));
3132 if (dptr == NULL) {
3133 free(sdlist);
3134 delete_search_cookie(cookie);
3135 cookie = NULL;
3136 *rcp = NS_LDAP_MEMORY;
3137 return (NS_LDAP_MEMORY);
3138 }
3139 sdlist[0] = dptr;
3140
3141 /* default base */
3142 rc = __s_api_getDNs(&dns, service, &cookie->errorp);
3143 if (rc != NS_LDAP_SUCCESS) {
3144 if (dns) {
3145 __s_api_free2dArray(dns);
3146 dns = NULL;
3147 }
3148 *errorp = cookie->errorp;
3149 cookie->errorp = NULL;
3150 delete_search_cookie(cookie);
3151 cookie = NULL;
3152 *rcp = rc;
3153 return (rc);
3154 }
3155 dptr->basedn = strdup(dns[0]);
3156 __s_api_free2dArray(dns);
3157 dns = NULL;
3158
3159 /* default scope */
3160 scope = 0;
3161 rc = __s_api_getSearchScope(&scope, &cookie->errorp);
3162 dptr->scope = scope;
3163 }
3164
3165 cookie->sdlist = sdlist;
3166
3167 /*
3168 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
3169 */
3170 if (flags & NS_LDAP_PAGE_CTRL)
3171 cookie->use_paging = TRUE;
3172 else
3173 cookie->use_paging = FALSE;
3174
3175 /* Set up other arguments */
3176 cookie->userdata = userdata;
3177 if (init_filter_cb != NULL) {
3178 cookie->init_filter_cb = init_filter_cb;
3179 cookie->use_filtercb = 1;
3180 }
3181 if (callback != NULL) {
3182 cookie->callback = callback;
3183 cookie->use_usercb = 1;
3184 }
3185
3186 /* check_shadow() may add extra value to cookie->i_flags */
3187 cookie->i_flags = flags;
3188 if (service) {
3189 cookie->service = strdup(service);
3190 if (cookie->service == NULL) {
3191 delete_search_cookie(cookie);
3192 cookie = NULL;
3193 *rcp = NS_LDAP_MEMORY;
3194 return (NS_LDAP_MEMORY);
3195 }
3196
3197 /*
3198 * If given, use the credential given by the caller, and
3199 * skip the credential check required for shadow update.
3200 */
3201 if (auth == NULL) {
3202 rc = check_shadow(cookie, service);
3203 if (rc != NS_LDAP_SUCCESS) {
3204 *errorp = cookie->errorp;
3205 cookie->errorp = NULL;
3206 delete_search_cookie(cookie);
3207 cookie = NULL;
3208 *rcp = rc;
3209 return (rc);
3210 }
3211 }
3212 }
3213
3214 cookie->i_filter = strdup(filter);
3215 cookie->i_attr = attribute;
3216 cookie->i_auth = auth;
3217 cookie->i_sortattr = sortattr;
3218
3219 if (batch != NULL) {
3220 cookie->batch = batch;
3221 cookie->reinit_on_retriable_err = B_TRUE;
3222 cookie->no_wait = B_TRUE;
3223 (void) search_state_machine(cookie, INIT, 0);
3224 cookie->no_wait = B_FALSE;
3225 rc = cookie->err_rc;
3226
3227 if (rc == NS_LDAP_SUCCESS) {
3228 /*
3229 * Here rc == NS_LDAP_SUCCESS means that the state
3230 * machine init'ed successfully. The actual status
3231 * of the search will be determined by
3232 * __ns_ldap_list_batch_end(). Add the cookie to our
3233 * batch.
3234 */
3235 cookie->caller_result = rResult;
3236 cookie->caller_errorp = errorp;
3237 cookie->caller_rc = rcp;
3238 cookie->next_cookie_in_batch = batch->cookie_list;
3239 batch->cookie_list = cookie;
3240 batch->nactive++;
3241 return (rc);
3242 }
3243 /*
3244 * If state machine init failed then copy error to the caller
3245 * and delete the cookie.
3246 */
3247 } else {
3248 (void) search_state_machine(cookie, INIT, 0);
3249 }
3250
3251 /* Copy results back to user */
3252 rc = cookie->err_rc;
3253 if (rc != NS_LDAP_SUCCESS) {
3254 if (conn_user != NULL && conn_user->ns_error != NULL) {
3255 *errorp = conn_user->ns_error;
3256 conn_user->ns_error = NULL;
3257 } else {
3258 *errorp = cookie->errorp;
3259 }
3260 }
3261 *rResult = cookie->result;
3262 from_result = cookie->err_from_result;
3263
3264 cookie->errorp = NULL;
3265 cookie->result = NULL;
3266 delete_search_cookie(cookie);
3267 cookie = NULL;
3268
3269 if (from_result == 0 && *rResult == NULL)
3270 rc = NS_LDAP_NOTFOUND;
3271 *rcp = rc;
3272 return (rc);
3273 }
3274
3275
3276 /*
3277 * __ns_ldap_list performs one or more LDAP searches to a given
3278 * directory server using service search descriptors and schema
3279 * mapping as appropriate. The operation may be retried a
3280 * couple of times in error situations.
3281 */
3282 int
__ns_ldap_list(const char * service,const char * filter,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata)3283 __ns_ldap_list(
3284 const char *service,
3285 const char *filter,
3286 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3287 char **realfilter, const void *userdata),
3288 const char * const *attribute,
3289 const ns_cred_t *auth,
3290 const int flags,
3291 ns_ldap_result_t **rResult, /* return result entries */
3292 ns_ldap_error_t **errorp,
3293 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3294 const void *userdata)
3295 {
3296 int mod_flags;
3297 /*
3298 * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
3299 * support this. If you want to use this option call the API
3300 * __ns_ldap_list_sort() with has the sort attribute.
3301 */
3302 mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3303
3304 return (__ns_ldap_list_sort(service, filter, NULL, init_filter_cb,
3305 attribute, auth, mod_flags, rResult, errorp,
3306 callback, userdata));
3307 }
3308
3309 /*
3310 * __ns_ldap_list_sort performs one or more LDAP searches to a given
3311 * directory server using service search descriptors and schema
3312 * mapping as appropriate. The operation may be retried a
3313 * couple of times in error situations.
3314 */
3315 int
__ns_ldap_list_sort(const char * service,const char * filter,const char * sortattr,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata)3316 __ns_ldap_list_sort(
3317 const char *service,
3318 const char *filter,
3319 const char *sortattr,
3320 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3321 char **realfilter, const void *userdata),
3322 const char * const *attribute,
3323 const ns_cred_t *auth,
3324 const int flags,
3325 ns_ldap_result_t **rResult, /* return result entries */
3326 ns_ldap_error_t **errorp,
3327 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3328 const void *userdata)
3329 {
3330 ns_conn_user_t *cu = NULL;
3331 int try_cnt = 0;
3332 int rc = NS_LDAP_SUCCESS, trc;
3333
3334 for (;;) {
3335 if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3336 &try_cnt, &rc, errorp) == 0)
3337 break;
3338 rc = ldap_list(NULL, service, filter, sortattr, init_filter_cb,
3339 attribute, auth, flags, rResult, errorp, &trc, callback,
3340 userdata, cu);
3341 }
3342
3343 return (rc);
3344 }
3345
3346 /*
3347 * Create and initialize batch for native LDAP lookups
3348 */
3349 int
__ns_ldap_list_batch_start(ns_ldap_list_batch_t ** batch)3350 __ns_ldap_list_batch_start(ns_ldap_list_batch_t **batch)
3351 {
3352 *batch = calloc(1, sizeof (ns_ldap_list_batch_t));
3353 if (*batch == NULL)
3354 return (NS_LDAP_MEMORY);
3355 return (NS_LDAP_SUCCESS);
3356 }
3357
3358
3359 /*
3360 * Add a LDAP search request to the batch.
3361 */
3362 int
__ns_ldap_list_batch_add(ns_ldap_list_batch_t * batch,const char * service,const char * filter,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int * rcp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata)3363 __ns_ldap_list_batch_add(
3364 ns_ldap_list_batch_t *batch,
3365 const char *service,
3366 const char *filter,
3367 int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3368 char **realfilter, const void *userdata),
3369 const char * const *attribute,
3370 const ns_cred_t *auth,
3371 const int flags,
3372 ns_ldap_result_t **rResult, /* return result entries */
3373 ns_ldap_error_t **errorp,
3374 int *rcp,
3375 int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3376 const void *userdata)
3377 {
3378 ns_conn_user_t *cu;
3379 int rc;
3380 int mod_flags;
3381
3382 cu = __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, 0);
3383 if (cu == NULL) {
3384 if (rcp != NULL)
3385 *rcp = NS_LDAP_MEMORY;
3386 return (NS_LDAP_MEMORY);
3387 }
3388
3389 /*
3390 * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not
3391 * support this.
3392 */
3393 mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3394
3395 rc = ldap_list(batch, service, filter, NULL, init_filter_cb, attribute,
3396 auth, mod_flags, rResult, errorp, rcp, callback, userdata, cu);
3397
3398 /*
3399 * Free the conn_user if the cookie was not batched. If the cookie
3400 * was batched then __ns_ldap_list_batch_end or release will free the
3401 * conn_user. The batch API instructs the search_state_machine
3402 * to reinit and retry (max 3 times) on retriable LDAP errors.
3403 */
3404 if (rc != NS_LDAP_SUCCESS && cu != NULL) {
3405 if (cu->conn_mt != NULL)
3406 __s_api_conn_mt_return(cu);
3407 __s_api_conn_user_free(cu);
3408 }
3409 return (rc);
3410 }
3411
3412
3413 /*
3414 * Free batch.
3415 */
3416 void
__ns_ldap_list_batch_release(ns_ldap_list_batch_t * batch)3417 __ns_ldap_list_batch_release(ns_ldap_list_batch_t *batch)
3418 {
3419 ns_ldap_cookie_t *c, *next;
3420
3421 for (c = batch->cookie_list; c != NULL; c = next) {
3422 next = c->next_cookie_in_batch;
3423 if (c->