xref: /illumos-gate/usr/src/lib/libsldap/common/ns_reads.c (revision bdfc6d18da790deeec2e0eb09c625902defe2498)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <sys/types.h>
31 #include <stdlib.h>
32 #include <libintl.h>
33 #include <ctype.h>
34 #include <syslog.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <unistd.h>
38 #include <string.h>
39 #include <strings.h>
40 
41 #include "ns_sldap.h"
42 #include "ns_internal.h"
43 #include "ns_cache_door.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
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
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 *
114 _cvtRDN(const char *service, const char *rdn) {
115 	char	**attrs, **mapped_attrs, **mapp, *type, *value, *attr;
116 	char	*new_rdn = NULL;
117 	int	nAttr = 0, i, attr_mapped, len = 0;
118 
119 	/* Break down "type=value\0" pairs. Assume RDN is normalized */
120 	if ((attrs = ldap_explode_rdn(rdn, 0)) == NULL)
121 		return (NULL);
122 
123 	for (nAttr = 0; attrs[nAttr] != NULL; nAttr++);
124 
125 	if ((mapped_attrs = (char **)calloc(nAttr, sizeof (char *))) == NULL) {
126 		ldap_value_free(attrs);
127 		return (NULL);
128 	}
129 
130 	attr_mapped = 0;
131 	for (i = 0; i < nAttr; i++) {
132 		/* Parse type=value pair */
133 		if ((type = strtok_r(attrs[i], "=", &value)) == NULL ||
134 					value == NULL)
135 			goto cleanup;
136 		/* Reverse map: e.g. cn-sm -> cn */
137 		mapp = __ns_ldap_getOrigAttribute(service, type);
138 		if (mapp != NULL && mapp[0] != NULL) {
139 			/* The attribute mapping is found */
140 			type = mapp[0];
141 			attr_mapped = 1;
142 
143 			/* "type=value\0" */
144 			len = strlen(type) + strlen(value) + 2;
145 
146 			/* Reconstruct type=value pair. A string is allocated */
147 			if ((attr = (char *)calloc(1, len)) == NULL) {
148 				__s_api_free2dArray(mapp);
149 				goto cleanup;
150 			}
151 			(void) snprintf(attr, len, "%s=%s",
152 						type, value);
153 			mapped_attrs[i] = attr;
154 		} else {
155 			/*
156 			 * No attribute mapping. attrs[i] is going to be copied
157 			 * later. Restore "type\0value\0" back to
158 			 * "type=value\0".
159 			 */
160 			type[strlen(type)] = '=';
161 		}
162 		__s_api_free2dArray(mapp);
163 	}
164 	if (attr_mapped == 0)
165 		/* No attribute mapping. Don't bother to reconstruct RDN */
166 		goto cleanup;
167 
168 	len = 0;
169 	/* Reconstruct RDN from type=value pairs */
170 	for (i = 0; i < nAttr; i++) {
171 		if (mapped_attrs[i])
172 			len += strlen(mapped_attrs[i]);
173 		else
174 			len += strlen(attrs[i]);
175 		/* Add 1 for "+" */
176 		len++;
177 	}
178 	if ((new_rdn = (char *)calloc(1, ++len)) == NULL)
179 		goto cleanup;
180 	for (i = 0; i < nAttr; i++) {
181 		if (i > 0)
182 			/* Add seperator */
183 			(void) strlcat(new_rdn, "+", len);
184 
185 		if (mapped_attrs[i])
186 			(void) strlcat(new_rdn, mapped_attrs[i], len);
187 		else
188 			(void) strlcat(new_rdn, attrs[i], len);
189 
190 	}
191 cleanup:
192 	ldap_value_free(attrs);
193 	if (mapped_attrs) {
194 		if (attr_mapped) {
195 			for (i = 0; i < nAttr; i++) {
196 				if (mapped_attrs[i])
197 					free(mapped_attrs[i]);
198 			}
199 		}
200 		free(mapped_attrs);
201 	}
202 
203 	return (new_rdn);
204 }
205 /*
206  * Convert attribute type in a DN that has an attribute mapping to the
207  * original mappped type.
208  * e.g
209  * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
210  *
211  * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com
212  * is converted to
213  * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
214  *
215  * Input - service: e.g. hosts, passwd etc.
216  *         dn: the value of a distinguished name
217  * Return - NULL: error
218  *          non-NULL: A converted DN and the memory is allocated
219  */
220 static char *
221 _cvtDN(const char *service, const char *dn) {
222 	char	**mapped_rdns;
223 	char	**rdns, *new_rdn, *new_dn = NULL;
224 	int	nRdn = 0, i, len = 0, rdn_mapped;
225 
226 	if (service == NULL || dn == NULL)
227 		return (NULL);
228 
229 	if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
230 		return (NULL);
231 
232 	for (nRdn = 0; rdns[nRdn] != NULL; nRdn++);
233 
234 	if ((mapped_rdns = (char **)calloc(nRdn, sizeof (char *))) == NULL) {
235 		ldap_value_free(rdns);
236 		return (NULL);
237 	}
238 
239 	rdn_mapped = 0;
240 	/* Break down RDNs in a DN */
241 	for (i = 0; i < nRdn; i++) {
242 		if ((new_rdn = _cvtRDN(service, rdns[i])) != NULL) {
243 			mapped_rdns[i] = new_rdn;
244 			rdn_mapped = 1;
245 		}
246 	}
247 	if (rdn_mapped == 0) {
248 		/*
249 		 * No RDN contains any attribute mapping.
250 		 * Don't bother to reconstruct DN from RDN. Copy DN directly.
251 		 */
252 		new_dn = strdup(dn);
253 		goto cleanup;
254 	}
255 	/*
256 	 * Reconstruct dn from RDNs.
257 	 * Calculate the length first.
258 	 */
259 	for (i = 0; i < nRdn; i++) {
260 		if (mapped_rdns[i])
261 			len += strlen(mapped_rdns[i]);
262 		else
263 			len += strlen(rdns[i]);
264 
265 		/* add 1 for ',' */
266 		len ++;
267 	}
268 	if ((new_dn = (char *)calloc(1, ++len)) == NULL)
269 		goto cleanup;
270 	for (i = 0; i < nRdn; i++) {
271 		if (i > 0)
272 			/* Add seperator */
273 			(void) strlcat(new_dn, ",", len);
274 
275 		if (mapped_rdns[i])
276 			(void) strlcat(new_dn, mapped_rdns[i], len);
277 		else
278 			(void) strlcat(new_dn, rdns[i], len);
279 
280 	}
281 
282 cleanup:
283 	ldap_value_free(rdns);
284 	if (mapped_rdns) {
285 		if (rdn_mapped) {
286 			for (i = 0; i < nRdn; i++) {
287 				if (mapped_rdns[i])
288 					free(mapped_rdns[i]);
289 			}
290 		}
291 		free(mapped_rdns);
292 	}
293 
294 	return (new_dn);
295 }
296 /*
297  * Convert a single ldap entry from a LDAPMessage
298  * into an ns_ldap_entry structure.
299  * Schema map the entry if specified in flags
300  */
301 
302 static int
303 __s_api_cvtEntry(LDAP	*ld,
304 	const char	*service,
305 	LDAPMessage	*e,
306 	int		flags,
307 	ns_ldap_entry_t	**ret,
308 	ns_ldap_error_t	**error)
309 {
310 
311 	ns_ldap_entry_t	*ep = NULL;
312 	ns_ldap_attr_t	**ap = NULL;
313 	BerElement	*ber;
314 	char		*attr = NULL;
315 	char		**vals = NULL;
316 	char		**mapping;
317 	char		*dn;
318 	int		nAttrs = 0;
319 	int		i, j, k = 0;
320 	char		**gecos_mapping = NULL;
321 	int		gecos_val_index[3] = { -1, -1, -1};
322 	char		errstr[MAXERROR];
323 	int		schema_mapping_existed = FALSE;
324 	int		gecos_mapping_existed = FALSE;
325 	int		gecos_attr_matched;
326 	int		auto_service = FALSE;
327 	int		rc = NS_LDAP_SUCCESS;
328 
329 	if (e == NULL || ret == NULL || error == NULL)
330 		return (NS_LDAP_INVALID_PARAM);
331 
332 	*error = NULL;
333 
334 	ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
335 	if (ep == NULL)
336 		return (NS_LDAP_MEMORY);
337 
338 	if (service != NULL &&
339 		(strncasecmp(service, "auto_", 5) == 0 ||
340 		strcasecmp(service, "automount") == 0))
341 		auto_service = TRUE;
342 	/*
343 	 * see if schema mapping existed for the given service
344 	 */
345 	mapping = __ns_ldap_getOrigAttribute(service,
346 			NS_HASH_SCHEMA_MAPPING_EXISTED);
347 	if (mapping) {
348 		schema_mapping_existed = TRUE;
349 		__s_api_free2dArray(mapping);
350 		mapping = NULL;
351 	} else if (auto_service) {
352 		/*
353 		 * If service == auto_* and no
354 		 * schema mapping found
355 		 * then try automount
356 		 * There is certain case that schema mapping exist
357 		 * but __ns_ldap_getOrigAttribute(service,
358 		 *	NS_HASH_SCHEMA_MAPPING_EXISTED);
359 		 * returns NULL.
360 		 * e.g.
361 		 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
362 		 * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
363 		 * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
364 		 *
365 		 * Make a check for schema_mapping_existed here
366 		 * so later on __s_api_convert_automountmapname won't be called
367 		 * unnecessarily. It is also used for attribute mapping
368 		 * and objectclass mapping.
369 		 */
370 		mapping = __ns_ldap_getOrigAttribute("automount",
371 			NS_HASH_SCHEMA_MAPPING_EXISTED);
372 		if (mapping) {
373 			schema_mapping_existed = TRUE;
374 			__s_api_free2dArray(mapping);
375 			mapping = NULL;
376 		}
377 	}
378 
379 	nAttrs = 1;  /* start with 1 for the DN attr */
380 	for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL;
381 		attr = ldap_next_attribute(ld, e, ber)) {
382 		nAttrs++;
383 		ldap_memfree(attr);
384 		attr = NULL;
385 	}
386 	ber_free(ber, 0);
387 	ber = NULL;
388 
389 	ep->attr_count = nAttrs;
390 
391 	/*
392 	 * add 1 for "gecos" 1 to N attribute mapping,
393 	 * just in case it is needed.
394 	 * ep->attr_count will be updated later if that is true.
395 	 */
396 	ap = (ns_ldap_attr_t **)calloc(ep->attr_count + 1,
397 					sizeof (ns_ldap_attr_t *));
398 	if (ap == NULL) {
399 		__ns_ldap_freeEntry(ep);
400 		ep = NULL;
401 		return (NS_LDAP_MEMORY);
402 	}
403 	ep->attr_pair = ap;
404 
405 	/* DN attribute */
406 	dn = ldap_get_dn(ld, e);
407 	ap[0] = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
408 	if (ap[0] == NULL) {
409 		ldap_memfree(dn);
410 		dn = NULL;
411 		__ns_ldap_freeEntry(ep);
412 		ep = NULL;
413 		return (NS_LDAP_MEMORY);
414 	}
415 
416 	if ((ap[0]->attrname = strdup("dn")) == NULL) {
417 		ldap_memfree(dn);
418 		dn = NULL;
419 		__ns_ldap_freeEntry(ep);
420 		ep = NULL;
421 		return (NS_LDAP_INVALID_PARAM);
422 	}
423 	ap[0]->value_count = 1;
424 	if ((ap[0]->attrvalue = (char **)
425 		calloc(2, sizeof (char *))) == NULL) {
426 		ldap_memfree(dn);
427 		dn = NULL;
428 		__ns_ldap_freeEntry(ep);
429 		ep = NULL;
430 		return (NS_LDAP_MEMORY);
431 	}
432 
433 	if (schema_mapping_existed)
434 		ap[0]->attrvalue[0] = _cvtDN(service, dn);
435 	else
436 		ap[0]->attrvalue[0] = strdup(dn);
437 
438 	if (ap[0]->attrvalue[0] == NULL) {
439 		ldap_memfree(dn);
440 		dn = NULL;
441 		__ns_ldap_freeEntry(ep);
442 		ep = NULL;
443 		return (NS_LDAP_MEMORY);
444 	}
445 	ldap_memfree(dn);
446 	dn = NULL;
447 
448 	if ((flags & NS_LDAP_NOMAP) == 0 && auto_service &&
449 		schema_mapping_existed) {
450 		rc = __s_api_convert_automountmapname(service,
451 				&ap[0]->attrvalue[0],
452 				error);
453 		if (rc != NS_LDAP_SUCCESS) {
454 			__ns_ldap_freeEntry(ep);
455 			ep = NULL;
456 			return (rc);
457 		}
458 	}
459 
460 	/* other attributes */
461 	for (attr = ldap_first_attribute(ld, e, &ber), j = 1;
462 		attr != NULL && j != nAttrs;
463 		attr = ldap_next_attribute(ld, e, ber), j++) {
464 	    /* allocate new attr name */
465 
466 	    if ((ap[j] = (ns_ldap_attr_t *)
467 		calloc(1, sizeof (ns_ldap_attr_t))) == NULL) {
468 		    ber_free(ber, 0);
469 		    ber = NULL;
470 		    __ns_ldap_freeEntry(ep);
471 		    ep = NULL;
472 		    if (gecos_mapping)
473 			__s_api_free2dArray(gecos_mapping);
474 		    gecos_mapping = NULL;
475 		    return (NS_LDAP_MEMORY);
476 	    }
477 
478 	    if ((flags & NS_LDAP_NOMAP) || schema_mapping_existed == FALSE)
479 		mapping = NULL;
480 	    else
481 		mapping = __ns_ldap_getOrigAttribute(service, attr);
482 
483 	    if (mapping == NULL && auto_service &&
484 		schema_mapping_existed &&
485 		(flags & NS_LDAP_NOMAP) == 0)
486 		/*
487 		 * if service == auto_* and no
488 		 * schema mapping found
489 		 * and schema_mapping_existed is TRUE
490 		 * and NS_LDAP_NOMAP is not set
491 		 * then try automount
492 		 * e.g.
493 		 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
494 		 */
495 		mapping = __ns_ldap_getOrigAttribute("automount", attr);
496 
497 	    if (mapping == NULL) {
498 		if ((ap[j]->attrname = strdup(attr)) == NULL) {
499 		    ber_free(ber, 0);
500 		    ber = NULL;
501 		    __ns_ldap_freeEntry(ep);
502 		    ep = NULL;
503 		    if (gecos_mapping)
504 			__s_api_free2dArray(gecos_mapping);
505 		    gecos_mapping = NULL;
506 		    return (NS_LDAP_MEMORY);
507 		}
508 	    } else {
509 		/*
510 		 * for "gecos" 1 to N mapping,
511 		 * do not remove the mapped attribute,
512 		 * just create a new gecos attribute
513 		 * and append it to the end of the attribute list
514 		 */
515 		if (strcasecmp(mapping[0], "gecos") == 0) {
516 			ap[j]->attrname = strdup(attr);
517 			gecos_mapping_existed = TRUE;
518 		} else
519 			ap[j]->attrname = strdup(mapping[0]);
520 
521 		if (ap[j]->attrname == NULL) {
522 		    ber_free(ber, 0);
523 		    ber = NULL;
524 		    __ns_ldap_freeEntry(ep);
525 		    ep = NULL;
526 		    if (gecos_mapping)
527 			__s_api_free2dArray(gecos_mapping);
528 		    gecos_mapping = NULL;
529 		    return (NS_LDAP_MEMORY);
530 		}
531 		/*
532 		 * 1 to N attribute mapping processing
533 		 * is only done for "gecos"
534 		 */
535 
536 		if (strcasecmp(mapping[0], "gecos") == 0) {
537 			/*
538 			 * get attribute mapping for "gecos",
539 			 * need to know the number and order of the
540 			 * mapped attributes
541 			 */
542 			if (gecos_mapping == NULL) {
543 				gecos_mapping =
544 					__ns_ldap_getMappedAttributes(service,
545 						mapping[0]);
546 				if (gecos_mapping == NULL ||
547 					gecos_mapping[0] == NULL) {
548 					/*
549 					 * this should never happens,
550 					 * syslog the error
551 					 */
552 					(void) sprintf(errstr,
553 						gettext(
554 						"Attribute mapping "
555 						"inconsistency "
556 						"found for attributes "
557 						"'%s' and '%s'."),
558 						mapping[0], attr);
559 					syslog(LOG_ERR, "libsldap: %s", errstr);
560 
561 					ber_free(ber, 0);
562 					ber = NULL;
563 					__ns_ldap_freeEntry(ep);
564 					ep = NULL;
565 					__s_api_free2dArray(mapping);
566 					mapping = NULL;
567 					if (gecos_mapping)
568 						__s_api_free2dArray(
569 							gecos_mapping);
570 					gecos_mapping = NULL;
571 					return (NS_LDAP_INTERNAL);
572 				}
573 			}
574 
575 			/*
576 			 * is this attribute the 1st, 2nd, or
577 			 * 3rd attr in the mapping list?
578 			 */
579 			gecos_attr_matched = FALSE;
580 			for (i = 0; i < 3 && gecos_mapping[i]; i++) {
581 				if (gecos_mapping[i] &&
582 					strcasecmp(gecos_mapping[i],
583 						attr) == 0) {
584 					gecos_val_index[i] = j;
585 					gecos_attr_matched = TRUE;
586 					break;
587 				}
588 			}
589 			if (gecos_attr_matched == FALSE) {
590 				/*
591 				 * Not match found.
592 				 * This should never happens,
593 				 * syslog the error
594 				 */
595 				(void) sprintf(errstr,
596 					gettext(
597 					"Attribute mapping "
598 					"inconsistency "
599 					"found for attributes "
600 					"'%s' and '%s'."),
601 					mapping[0], attr);
602 				syslog(LOG_ERR, "libsldap: %s", errstr);
603 
604 				ber_free(ber, 0);
605 				ber = NULL;
606 				__ns_ldap_freeEntry(ep);
607 				ep = NULL;
608 				__s_api_free2dArray(mapping);
609 				mapping = NULL;
610 				__s_api_free2dArray(gecos_mapping);
611 				gecos_mapping = NULL;
612 				return (NS_LDAP_INTERNAL);
613 			}
614 		}
615 		__s_api_free2dArray(mapping);
616 		mapping = NULL;
617 	    }
618 
619 	    if ((vals = ldap_get_values(ld, e, attr)) != NULL) {
620 
621 		if ((ap[j]->value_count = ldap_count_values(vals)) == 0) {
622 		    ldap_value_free(vals);
623 		    vals = NULL;
624 		    continue;
625 		} else {
626 		    ap[j]->attrvalue = (char **)
627 			calloc(ap[j]->value_count+1, 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(gecos_mapping);
635 			    gecos_mapping = NULL;
636 			    return (NS_LDAP_MEMORY);
637 		    }
638 		}
639 
640 		/* map object classes if necessary */
641 		if ((flags & NS_LDAP_NOMAP) == 0 &&
642 		    schema_mapping_existed && ap[j]->attrname &&
643 		    strcasecmp(ap[j]->attrname, "objectclass") == 0) {
644 		    for (k = 0; k < ap[j]->value_count; k++) {
645 			mapping =
646 			    __ns_ldap_getOrigObjectClass(service, vals[k]);
647 
648 			if (mapping == NULL && auto_service)
649 				/*
650 				 * if service == auto_* and no
651 				 * schema mapping found
652 				 * then try automount
653 				 */
654 				mapping =
655 				    __ns_ldap_getOrigObjectClass(
656 					"automount", vals[k]);
657 
658 			if (mapping == NULL) {
659 			    ap[j]->attrvalue[k] = strdup(vals[k]);
660 			} else {
661 			    ap[j]->attrvalue[k] = strdup(mapping[0]);
662 			    __s_api_free2dArray(mapping);
663 			    mapping = NULL;
664 			}
665 			if (ap[j]->attrvalue[k] == NULL) {
666 				ber_free(ber, 0);
667 				ber = NULL;
668 				__ns_ldap_freeEntry(ep);
669 				ep = NULL;
670 				if (gecos_mapping)
671 					__s_api_free2dArray(gecos_mapping);
672 				gecos_mapping = NULL;
673 				return (NS_LDAP_MEMORY);
674 			}
675 		    }
676 		} else {
677 		    for (k = 0; k < ap[j]->value_count; k++) {
678 			if ((ap[j]->attrvalue[k] = strdup(vals[k])) == NULL) {
679 				ber_free(ber, 0);
680 				ber = NULL;
681 				__ns_ldap_freeEntry(ep);
682 				ep = NULL;
683 				if (gecos_mapping)
684 					__s_api_free2dArray(gecos_mapping);
685 				gecos_mapping = NULL;
686 				return (NS_LDAP_MEMORY);
687 			}
688 		    }
689 		}
690 
691 		ap[j]->attrvalue[k] = NULL;
692 		ldap_value_free(vals);
693 		vals = NULL;
694 	    }
695 
696 	    ldap_memfree(attr);
697 	    attr = NULL;
698 	}
699 
700 	ber_free(ber, 0);
701 	ber = NULL;
702 
703 	if (gecos_mapping) {
704 		__s_api_free2dArray(gecos_mapping);
705 		gecos_mapping = NULL;
706 	}
707 
708 	/* special processing for gecos 1 to up to 3 attribute mapping */
709 	if (schema_mapping_existed && gecos_mapping_existed) {
710 
711 		int	f = -1;
712 
713 		for (i = 0; i < 3; i++) {
714 			k = gecos_val_index[i];
715 
716 			/*
717 			 * f is the index of the first returned
718 			 * attribute which "gecos" attribute mapped to
719 			 */
720 			if (k != -1 && f == -1)
721 				f = k;
722 
723 			if (k != -1 && ap[k]->value_count > 0 &&
724 				ap[k]->attrvalue[0] &&
725 				strlen(ap[k]->attrvalue[0]) > 0) {
726 
727 				if (k == f) {
728 					/*
729 					 * Create and fill in the last reserved
730 					 * ap with the data from the "gecos"
731 					 * mapping attributes
732 					 */
733 					ap[nAttrs] = (ns_ldap_attr_t *)
734 						calloc(1,
735 						sizeof (ns_ldap_attr_t));
736 					if (ap[nAttrs] == NULL) {
737 						__ns_ldap_freeEntry(ep);
738 						ep = NULL;
739 						return (NS_LDAP_MEMORY);
740 					}
741 					ap[nAttrs]->attrvalue = (char **)calloc(
742 						2, sizeof (char *));
743 					if (ap[nAttrs]->attrvalue == NULL) {
744 						__ns_ldap_freeEntry(ep);
745 						ep = NULL;
746 						return (NS_LDAP_MEMORY);
747 					}
748 					/* add 1 more for a possible "," */
749 					ap[nAttrs]->attrvalue[0] =
750 						(char *)calloc(
751 						strlen(ap[f]->attrvalue[0]) +
752 						2, 1);
753 					if (ap[nAttrs]->attrvalue[0] == NULL) {
754 						__ns_ldap_freeEntry(ep);
755 						ep = NULL;
756 						return (NS_LDAP_MEMORY);
757 					}
758 					(void) strcpy(ap[nAttrs]->attrvalue[0],
759 						ap[f]->attrvalue[0]);
760 
761 					ap[nAttrs]->attrname = strdup("gecos");
762 					if (ap[nAttrs]->attrname == NULL) {
763 						__ns_ldap_freeEntry(ep);
764 						ep = NULL;
765 						return (NS_LDAP_MEMORY);
766 					}
767 
768 					ap[nAttrs]->value_count = 1;
769 					ep->attr_count = nAttrs + 1;
770 
771 				} else {
772 					(void) strcat(ap[nAttrs]->attrvalue[0],
773 						",");
774 					ap[nAttrs]->attrvalue[0] =
775 						(char *)realloc(
776 						ap[nAttrs]->attrvalue[0],
777 						strlen(ap[nAttrs]->
778 						attrvalue[0]) + 2);
779 					if (ap[nAttrs]->attrvalue[0] == NULL) {
780 						__ns_ldap_freeEntry(ep);
781 						ep = NULL;
782 						return (NS_LDAP_MEMORY);
783 					}
784 					(void) strcat(ap[nAttrs]->attrvalue[0],
785 						ap[k]->attrvalue[0]);
786 				}
787 			}
788 		}
789 	}
790 
791 	*ret = ep;
792 	return (NS_LDAP_SUCCESS);
793 }
794 
795 static int
796 __s_api_getEntry(ns_ldap_cookie_t *cookie)
797 {
798 	ns_ldap_entry_t	*curEntry = NULL;
799 	int		ret;
800 
801 #ifdef DEBUG
802 	(void) fprintf(stderr, "__s_api_getEntry START\n");
803 #endif
804 
805 	if (cookie->resultMsg == NULL) {
806 		return (NS_LDAP_INVALID_PARAM);
807 	}
808 	ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service,
809 				cookie->resultMsg, cookie->i_flags,
810 				&curEntry, &cookie->errorp);
811 	if (ret != NS_LDAP_SUCCESS) {
812 		return (ret);
813 	}
814 
815 	if (cookie->result == NULL) {
816 		cookie->result = (ns_ldap_result_t *)
817 			calloc(1, sizeof (ns_ldap_result_t));
818 		if (cookie->result == NULL) {
819 			__ns_ldap_freeEntry(curEntry);
820 			curEntry = NULL;
821 			return (NS_LDAP_MEMORY);
822 		}
823 		cookie->result->entry = curEntry;
824 		cookie->nextEntry = curEntry;
825 	} else {
826 		cookie->nextEntry->next = curEntry;
827 		cookie->nextEntry = curEntry;
828 	}
829 	cookie->result->entries_count++;
830 
831 	return (NS_LDAP_SUCCESS);
832 }
833 
834 static int
835 __s_api_get_cachemgr_data(const char *type,
836 		const char *from, char **to)
837 {
838 	union {
839 		ldap_data_t	s_d;
840 		char		s_b[DOORBUFFERSIZE];
841 	} space;
842 	ldap_data_t	*sptr;
843 	int		ndata;
844 	int		adata;
845 	int		rc;
846 
847 #ifdef DEBUG
848 	(void) fprintf(stderr, "__s_api_get_cachemgr_data START\n");
849 #endif
850 
851 	if (from == NULL || from[0] == '\0' || to == NULL)
852 		return (-1);
853 
854 	*to = NULL;
855 	(void) memset(space.s_b, 0, DOORBUFFERSIZE);
856 
857 	space.s_d.ldap_call.ldap_callnumber = GETCACHE;
858 	(void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
859 		DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
860 		"%s%s%s",
861 		type,
862 		DOORLINESEP,
863 		from);
864 	ndata = sizeof (space);
865 	adata = sizeof (ldap_call_t) +
866 		strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
867 	sptr = &space.s_d;
868 
869 	rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
870 	if (rc != SUCCESS)
871 		return (-1);
872 	else
873 		*to = strdup(sptr->ldap_ret.ldap_u.buff);
874 	return (NS_LDAP_SUCCESS);
875 }
876 
877 static int
878 __s_api_set_cachemgr_data(const char *type,
879 		const char *from, const char *to)
880 {
881 	union {
882 		ldap_data_t	s_d;
883 		char		s_b[DOORBUFFERSIZE];
884 	} space;
885 	ldap_data_t	*sptr;
886 	int		ndata;
887 	int		adata;
888 	int		rc;
889 
890 #ifdef DEBUG
891 	(void) fprintf(stderr, "__s_api_set_cachemgr_data START\n");
892 #endif
893 
894 	if ((from == NULL) || (from[0] == '\0') ||
895 		(to == NULL) || (to[0] == '\0'))
896 		return (-1);
897 
898 	(void) memset(space.s_b, 0, DOORBUFFERSIZE);
899 
900 	space.s_d.ldap_call.ldap_callnumber = SETCACHE;
901 	(void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
902 		DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
903 		"%s%s%s%s%s",
904 		type,
905 		DOORLINESEP,
906 		from,
907 		DOORLINESEP,
908 		to);
909 
910 	ndata = sizeof (space);
911 	adata = sizeof (ldap_call_t) +
912 		strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
913 	sptr = &space.s_d;
914 
915 	rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
916 	if (rc != SUCCESS)
917 		return (-1);
918 
919 	return (NS_LDAP_SUCCESS);
920 }
921 
922 
923 static char *
924 __s_api_remove_rdn_space(char *rdn)
925 {
926 	char	*tf, *tl, *vf, *vl, *eqsign;
927 
928 	/* if no space(s) to remove, return */
929 	if (strchr(rdn, SPACETOK) == NULL)
930 		return (rdn);
931 
932 	/* if no '=' separator, return */
933 	eqsign = strchr(rdn, '=');
934 	if (eqsign == NULL)
935 		return (rdn);
936 
937 	tf = rdn;
938 	tl = eqsign - 1;
939 	vf = eqsign + 1;
940 	vl = rdn + strlen(rdn) - 1;
941 
942 	/* now two strings, type and value */
943 	*eqsign = '\0';
944 
945 	/* remove type's leading spaces */
946 	while (tf < tl && *tf == SPACETOK)
947 		tf++;
948 	/* remove type's trailing spaces */
949 	while (tf < tl && *tl == SPACETOK)
950 		tl--;
951 	/* add '=' separator back */
952 	*(++tl) = '=';
953 	/* remove value's leading spaces */
954 	while (vf < vl && *vf == SPACETOK)
955 		vf++;
956 	/* remove value's trailing spaces */
957 	while (vf < vl && *vl == SPACETOK)
958 		*vl-- = '\0';
959 
960 	/* move value up if necessary */
961 	if (vf != tl + 1)
962 		(void) strcpy(tl + 1, vf);
963 
964 	return (tf);
965 }
966 
967 static
968 ns_ldap_cookie_t *
969 init_search_state_machine()
970 {
971 	ns_ldap_cookie_t	*cookie;
972 	ns_config_t		*cfg;
973 
974 	cookie = (ns_ldap_cookie_t *)calloc(1, sizeof (ns_ldap_cookie_t));
975 	if (cookie == NULL)
976 		return (NULL);
977 	cookie->state = INIT;
978 	/* assign other state variables */
979 	cfg = __s_api_loadrefresh_config();
980 	cookie->connectionId = -1;
981 	if (cfg == NULL ||
982 		cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_ptype == NS_UNKNOWN) {
983 		cookie->search_timeout.tv_sec = NS_DEFAULT_SEARCH_TIMEOUT;
984 	} else {
985 		cookie->search_timeout.tv_sec =
986 			cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_i;
987 	}
988 	if (cfg != NULL)
989 		__s_api_release_config(cfg);
990 	cookie->search_timeout.tv_usec = 0;
991 
992 	return (cookie);
993 }
994 
995 static void
996 delete_search_cookie(ns_ldap_cookie_t *cookie)
997 {
998 	if (cookie == NULL)
999 		return;
1000 	if (cookie->connectionId > -1)
1001 		DropConnection(cookie->connectionId, cookie->i_flags);
1002 	if (cookie->filter)
1003 		free(cookie->filter);
1004 	if (cookie->i_filter)
1005 		free(cookie->i_filter);
1006 	if (cookie->service)
1007 		free(cookie->service);
1008 	if (cookie->sdlist)
1009 		(void) __ns_ldap_freeSearchDescriptors(&(cookie->sdlist));
1010 	if (cookie->result)
1011 		(void) __ns_ldap_freeResult(&cookie->result);
1012 	if (cookie->attribute)
1013 		__s_api_free2dArray(cookie->attribute);
1014 	if (cookie->errorp)
1015 		(void) __ns_ldap_freeError(&cookie->errorp);
1016 	if (cookie->reflist)
1017 		__s_api_deleteRefInfo(cookie->reflist);
1018 	if (cookie->basedn)
1019 		free(cookie->basedn);
1020 	if (cookie->ctrlCookie)
1021 		ber_bvfree(cookie->ctrlCookie);
1022 	_freeControlList(&cookie->p_serverctrls);
1023 	free(cookie);
1024 }
1025 
1026 static int
1027 get_mapped_filter(ns_ldap_cookie_t *cookie, char **new_filter)
1028 {
1029 
1030 	typedef	struct	filter_mapping_info {
1031 		char	oc_or_attr;
1032 		char	*name_start;
1033 		char	*name_end;
1034 		char	*veq_pos;
1035 		char	*from_name;
1036 		char	*to_name;
1037 		char	**mapping;
1038 	} filter_mapping_info_t;
1039 
1040 	char			*c, *last_copied;
1041 	char			*filter_c, *filter_c_next;
1042 	char			*key, *tail, *head;
1043 	char			errstr[MAXERROR];
1044 	int			num_eq = 0, num_veq = 0;
1045 	int			in_quote = FALSE;
1046 	int			i, j, oc_len, len;
1047 	int			at_least_one = FALSE;
1048 	filter_mapping_info_t	**info, *info1;
1049 	char			**mapping;
1050 	char			*service, *filter, *err;
1051 	int			auto_service = FALSE;
1052 
1053 	if (cookie == NULL || new_filter == NULL)
1054 		return (NS_LDAP_INVALID_PARAM);
1055 
1056 	*new_filter = NULL;
1057 	service = cookie->service;
1058 	filter = cookie->filter;
1059 
1060 	/*
1061 	 * count the number of '=' char
1062 	 */
1063 	for (c = filter; *c; c++) {
1064 		if (*c == TOKENSEPARATOR)
1065 			num_eq++;
1066 	}
1067 
1068 	if (service != NULL && strncasecmp(service, "auto_", 5) == 0)
1069 		auto_service = TRUE;
1070 
1071 	/*
1072 	 * See if schema mapping existed for the given service.
1073 	 * If not, just return success.
1074 	 */
1075 	mapping = __ns_ldap_getOrigAttribute(service,
1076 			NS_HASH_SCHEMA_MAPPING_EXISTED);
1077 
1078 	if (mapping == NULL && auto_service)
1079 		/*
1080 		 * if service == auto_* and no
1081 		 * schema mapping found
1082 		 * then try automount
1083 		 */
1084 		mapping = __ns_ldap_getOrigAttribute(
1085 			"automount", NS_HASH_SCHEMA_MAPPING_EXISTED);
1086 
1087 	if (mapping)
1088 		__s_api_free2dArray(mapping);
1089 	else
1090 		return (NS_LDAP_SUCCESS);
1091 
1092 	/*
1093 	 * no '=' sign, just say OK and return nothing
1094 	 */
1095 	if (num_eq == 0)
1096 		return (NS_LDAP_SUCCESS);
1097 
1098 	/*
1099 	 * Make a copy of the filter string
1100 	 * for saving the name of the objectclasses or
1101 	 * attributes that need to be passed to the
1102 	 * objectclass or attribute mapping functions.
1103 	 * pointer "info->from_name" points to the locations
1104 	 * within this string.
1105 	 *
1106 	 * The input filter string, filter, will be used
1107 	 * to indicate where these names start and end.
1108 	 * pointers "info->name_start" and "info->name_end"
1109 	 * point to locations within the input filter string,
1110 	 * and are used at the end of this function to
1111 	 * merge the original filter data with the
1112 	 * mapped objectclass or attribute names.
1113 	 */
1114 	filter_c = strdup(filter);
1115 	if (filter_c == NULL)
1116 		return (NS_LDAP_MEMORY);
1117 	filter_c_next = filter_c;
1118 
1119 	/*
1120 	 * get memory for info arrays
1121 	 */
1122 	info = (filter_mapping_info_t **)calloc(num_eq + 1,
1123 			sizeof (filter_mapping_info_t *));
1124 
1125 	if (info == NULL) {
1126 		free(filter_c);
1127 		return (NS_LDAP_MEMORY);
1128 	}
1129 
1130 	/*
1131 	 * find valid '=' for further processing,
1132 	 * ignore the "escaped =" (.i.e. "\="), or
1133 	 * "=" in quoted string
1134 	 */
1135 	for (c = filter_c; *c; c++) {
1136 
1137 		switch (*c) {
1138 		case TOKENSEPARATOR:
1139 			if (!in_quote) {
1140 				info1 = (filter_mapping_info_t *)calloc(1,
1141 					sizeof (filter_mapping_info_t));
1142 				if (!info1) {
1143 					free(filter_c);
1144 					for (i = 0; i < num_veq; i++)
1145 						free(info[i]);
1146 					free(info);
1147 					return (NS_LDAP_MEMORY);
1148 				}
1149 				info[num_veq] = info1;
1150 
1151 				/*
1152 				 * remember the location of this "="
1153 				 */
1154 				info[num_veq++]->veq_pos = c;
1155 			}
1156 			break;
1157 		case QUOTETOK:
1158 			/*
1159 			 * switch on/off the in_quote mode
1160 			 */
1161 			in_quote = (in_quote == FALSE);
1162 			break;
1163 		case '\\':
1164 			/*
1165 			 * ignore escape characters
1166 			 * don't skip if next char is '\0'
1167 			 */
1168 			if (!in_quote)
1169 				if (*(++c) == '\0')
1170 					c--;
1171 			break;
1172 		}
1173 
1174 	}
1175 
1176 	/*
1177 	 * for each valid "=" found, get the name to
1178 	 * be mapped
1179 	 */
1180 	oc_len = strlen("objectclass");
1181 	for (i = 0; i < num_veq; i++) {
1182 
1183 		/*
1184 		 * look at the left side of "=" to see
1185 		 * if assertion is "objectclass=<ocname>"
1186 		 * or "<attribute name>=<attribute value>"
1187 		 *
1188 		 * first skip spaces before "=".
1189 		 * Note that filter_c_next may not point to the
1190 		 * start of the filter string. For i > 0,
1191 		 * it points to the end of the last name processed + 2
1192 		 */
1193 		for (tail = info[i]->veq_pos; (tail > filter_c_next) &&
1194 			(*(tail - 1) == SPACETOK); tail--);
1195 
1196 		/*
1197 		 * mark the end of the left side string (the key)
1198 		 */
1199 		*tail = '\0';
1200 		info[i]->name_end = tail - filter_c - 1 + filter;
1201 
1202 		/*
1203 		 * find the start of the key
1204 		 */
1205 		key = filter_c_next;
1206 		for (c = tail; filter_c_next <= c; c--) {
1207 			/* OPARATOK is '(' */
1208 			if (*c == OPARATOK ||
1209 				*c == SPACETOK) {
1210 				key = c + 1;
1211 				break;
1212 			}
1213 		}
1214 		info[i]->name_start = key - filter_c + filter;
1215 
1216 		if ((key + oc_len) <= tail) {
1217 			if (strncasecmp(key, "objectclass",
1218 				oc_len) == 0) {
1219 				/*
1220 				 * assertion is "objectclass=ocname",
1221 				 * ocname is the one needs to be mapped
1222 				 *
1223 				 * skip spaces after "=" to find start
1224 				 * of the ocname
1225 				 */
1226 				head = info[i]->veq_pos;
1227 				for (head = info[i]->veq_pos + 1;
1228 					*head && *head == SPACETOK; head++);
1229 
1230 				/* ignore empty ocname */
1231 				if (!(*head))
1232 					continue;
1233 
1234 				info[i]->name_start = head - filter_c +
1235 					filter;
1236 
1237 				/*
1238 				 * now find the end of the ocname
1239 				 */
1240 				for (c = head; ; c++) {
1241 					/* CPARATOK is ')' */
1242 					if (*c == CPARATOK ||
1243 						*c == '\0' ||
1244 						*c == SPACETOK) {
1245 						*c = '\0';
1246 						info[i]->name_end =
1247 							c - filter_c - 1 +
1248 							filter;
1249 						filter_c_next = c + 1;
1250 						info[i]->oc_or_attr = 'o';
1251 						info[i]->from_name = head;
1252 						break;
1253 					}
1254 				}
1255 			}
1256 		}
1257 
1258 		/*
1259 		 * assertion is not "objectclass=ocname",
1260 		 * assume assertion is "<key> = <value>",
1261 		 * <key> is the one needs to be mapped
1262 		 */
1263 		if (info[i]->from_name == NULL && strlen(key) > 0) {
1264 			info[i]->oc_or_attr = 'a';
1265 			info[i]->from_name = key;
1266 		}
1267 	}
1268 
1269 	/* perform schema mapping */
1270 	for (i = 0; i < num_veq; i++) {
1271 		if (info[i]->from_name == NULL)
1272 			continue;
1273 
1274 		if (info[i]->oc_or_attr == 'a')
1275 			info[i]->mapping =
1276 			__ns_ldap_getMappedAttributes(service,
1277 				info[i]->from_name);
1278 		else
1279 			info[i]->mapping =
1280 			__ns_ldap_getMappedObjectClass(service,
1281 				info[i]->from_name);
1282 
1283 		if (info[i]->mapping == NULL && auto_service)  {
1284 			/*
1285 			 * If no mapped attribute/objectclass is found
1286 			 * and service == auto*
1287 			 * try to find automount's
1288 			 * mapped attribute/objectclass
1289 			 */
1290 			if (info[i]->oc_or_attr == 'a')
1291 				info[i]->mapping =
1292 				__ns_ldap_getMappedAttributes("automount",
1293 					info[i]->from_name);
1294 			else
1295 				info[i]->mapping =
1296 				__ns_ldap_getMappedObjectClass("automount",
1297 					info[i]->from_name);
1298 		}
1299 
1300 		if (info[i]->mapping == NULL ||
1301 			info[i]->mapping[0] == NULL) {
1302 			info[i]->to_name = NULL;
1303 		} else if (info[i]->mapping[1] == NULL) {
1304 			info[i]->to_name = info[i]->mapping[0];
1305 			at_least_one = TRUE;
1306 		} else {
1307 			__s_api_free2dArray(info[i]->mapping);
1308 			/*
1309 			 * multiple mapping
1310 			 * not allowed
1311 			 */
1312 			(void) sprintf(errstr,
1313 				gettext(
1314 				"Multiple attribute or objectclass "
1315 				"mapping for '%s' in filter "
1316 				"'%s' not allowed."),
1317 				info[i]->from_name, filter);
1318 			err = strdup(errstr);
1319 			if (err)
1320 				MKERROR(LOG_WARNING, cookie->errorp,
1321 				NS_CONFIG_SYNTAX,
1322 				err, NULL);
1323 
1324 			free(filter_c);
1325 			for (j = 0; j < num_veq; j++) {
1326 				if (info[j]->mapping)
1327 					__s_api_free2dArray(
1328 						info[j]->mapping);
1329 				free(info[j]);
1330 			}
1331 			free(info);
1332 			return (NS_LDAP_CONFIG);
1333 		}
1334 	}
1335 
1336 
1337 	if (at_least_one) {
1338 
1339 		len = strlen(filter);
1340 		last_copied = filter - 1;
1341 
1342 		for (i = 0; i < num_veq; i++) {
1343 			if (info[i]->to_name)
1344 				len += strlen(info[i]->to_name);
1345 		}
1346 
1347 		*new_filter = (char *)calloc(1, len);
1348 		if (*new_filter == NULL) {
1349 			free(filter_c);
1350 			for (j = 0; j < num_veq; j++) {
1351 				if (info[j]->mapping)
1352 					__s_api_free2dArray(
1353 						info[j]->mapping);
1354 				free(info[j]);
1355 			}
1356 			free(info);
1357 			return (NS_LDAP_MEMORY);
1358 		}
1359 
1360 		for (i = 0; i < num_veq; i++) {
1361 			if (info[i]->to_name != NULL &&
1362 				info[i]->to_name != NULL) {
1363 
1364 			/*
1365 			 * copy the original filter data
1366 			 * between the last name and current
1367 			 * name
1368 			 */
1369 			if ((last_copied + 1) != info[i]->name_start)
1370 				(void) strncat(*new_filter, last_copied + 1,
1371 					info[i]->name_start -
1372 					last_copied - 1);
1373 
1374 				/* the data is copied */
1375 				last_copied = info[i]->name_end;
1376 
1377 				/*
1378 				 * replace the name with
1379 				 * the mapped name
1380 				 */
1381 				(void) strcat(*new_filter, info[i]->to_name);
1382 			}
1383 
1384 			/* copy the filter data after the last name */
1385 			if (i == (num_veq -1) &&
1386 				info[i]->name_end <
1387 					(filter + strlen(filter)))
1388 				(void) strncat(*new_filter, last_copied + 1,
1389 					filter + strlen(filter) -
1390 					last_copied - 1);
1391 		}
1392 
1393 	}
1394 
1395 	/* free memory */
1396 	free(filter_c);
1397 	for (j = 0; j < num_veq; j++) {
1398 		if (info[j]->mapping)
1399 			__s_api_free2dArray(info[j]->mapping);
1400 		free(info[j]);
1401 	}
1402 	free(info);
1403 
1404 	return (NS_LDAP_SUCCESS);
1405 }
1406 
1407 static int
1408 setup_next_search(ns_ldap_cookie_t *cookie)
1409 {
1410 	ns_ldap_search_desc_t	*dptr;
1411 	int			scope;
1412 	char			*filter, *str;
1413 	int			baselen;
1414 	int			rc;
1415 	void			**param;
1416 
1417 	dptr = *cookie->sdpos;
1418 	scope = cookie->i_flags & (NS_LDAP_SCOPE_BASE |
1419 			NS_LDAP_SCOPE_ONELEVEL |
1420 			NS_LDAP_SCOPE_SUBTREE);
1421 	if (scope)
1422 		cookie->scope = scope;
1423 	else
1424 		cookie->scope = dptr->scope;
1425 	switch (cookie->scope) {
1426 	case NS_LDAP_SCOPE_BASE:
1427 		cookie->scope = LDAP_SCOPE_BASE;
1428 		break;
1429 	case NS_LDAP_SCOPE_ONELEVEL:
1430 		cookie->scope = LDAP_SCOPE_ONELEVEL;
1431 		break;
1432 	case NS_LDAP_SCOPE_SUBTREE:
1433 		cookie->scope = LDAP_SCOPE_SUBTREE;
1434 		break;
1435 	}
1436 
1437 	filter = NULL;
1438 	if (cookie->use_filtercb && cookie->init_filter_cb &&
1439 		dptr->filter && strlen(dptr->filter) > 0) {
1440 		(*cookie->init_filter_cb)(dptr, &filter,
1441 			cookie->userdata);
1442 	}
1443 	if (filter == NULL) {
1444 		if (cookie->i_filter == NULL) {
1445 			cookie->err_rc = NS_LDAP_INVALID_PARAM;
1446 			return (-1);
1447 		} else {
1448 			cookie->filter = strdup(cookie->i_filter);
1449 			if (cookie->filter == NULL) {
1450 				cookie->err_rc = NS_LDAP_MEMORY;
1451 				return (-1);
1452 			}
1453 		}
1454 	} else {
1455 		cookie->filter = strdup(filter);
1456 		free(filter);
1457 		if (cookie->filter == NULL) {
1458 			cookie->err_rc = NS_LDAP_MEMORY;
1459 			return (-1);
1460 		}
1461 	}
1462 
1463 	/*
1464 	 * perform attribute/objectclass mapping on filter
1465 	 */
1466 	filter = NULL;
1467 
1468 	if (cookie->service) {
1469 		rc = get_mapped_filter(cookie, &filter);
1470 		if (rc != NS_LDAP_SUCCESS) {
1471 			cookie->err_rc = rc;
1472 			return (-1);
1473 		} else {
1474 			/*
1475 			 * get_mapped_filter returns
1476 			 * NULL filter pointer, if
1477 			 * no mapping was done
1478 			 */
1479 			if (filter) {
1480 				free(cookie->filter);
1481 				cookie->filter = filter;
1482 			}
1483 		}
1484 	}
1485 
1486 	/*
1487 	 * validate filter to make sure it's legal
1488 	 * [remove redundant ()'s]
1489 	 */
1490 	rc = validate_filter(cookie);
1491 	if (rc != NS_LDAP_SUCCESS) {
1492 		cookie->err_rc = rc;
1493 		return (-1);
1494 	}
1495 
1496 	baselen = strlen(dptr->basedn);
1497 	if (baselen > 0 && dptr->basedn[baselen-1] == COMMATOK) {
1498 		rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
1499 				(void ***)&param, &cookie->errorp);
1500 		if (rc != NS_LDAP_SUCCESS) {
1501 			cookie->err_rc = rc;
1502 			return (-1);
1503 		}
1504 		str = ((char **)param)[0];
1505 		baselen += strlen(str)+1;
1506 		cookie->basedn = (char *)malloc(baselen);
1507 		if (cookie->basedn == NULL) {
1508 			cookie->err_rc = NS_LDAP_MEMORY;
1509 			return (-1);
1510 		}
1511 		(void) strcpy(cookie->basedn, dptr->basedn);
1512 		(void) strcat(cookie->basedn, str);
1513 		(void) __ns_ldap_freeParam(&param);
1514 	} else {
1515 		cookie->basedn = strdup(dptr->basedn);
1516 	}
1517 	return (0);
1518 }
1519 
1520 static int
1521 setup_referral_search(ns_ldap_cookie_t *cookie)
1522 {
1523 	ns_referral_info_t	*ref;
1524 
1525 	ref = cookie->refpos;
1526 	cookie->scope = ref->refScope;
1527 	if (cookie->filter) {
1528 		free(cookie->filter);
1529 	}
1530 	cookie->filter = strdup(ref->refFilter);
1531 	if (cookie->basedn) {
1532 		free(cookie->basedn);
1533 	}
1534 	cookie->basedn = strdup(ref->refDN);
1535 	if (cookie->filter == NULL || cookie->basedn == NULL) {
1536 		cookie->err_rc = NS_LDAP_MEMORY;
1537 		return (-1);
1538 	}
1539 	return (0);
1540 }
1541 
1542 static int
1543 get_current_session(ns_ldap_cookie_t *cookie)
1544 {
1545 	ConnectionID	connectionId = -1;
1546 	Connection	*conp = NULL;
1547 	int		rc;
1548 	int		fail_if_new_pwd_reqd = 1;
1549 
1550 	rc = __s_api_getConnection(NULL, cookie->i_flags,
1551 		cookie->i_auth, &connectionId, &conp,
1552 		&cookie->errorp, fail_if_new_pwd_reqd);
1553 
1554 	/*
1555 	 * If password control attached in *cookie->errorp,
1556 	 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1557 	 * free the error structure (we do not need
1558 	 * the sec_to_expired info).
1559 	 * Reset rc to NS_LDAP_SUCCESS.
1560 	 */
1561 	if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1562 		(void) __ns_ldap_freeError(
1563 			&cookie->errorp);
1564 		cookie->errorp = NULL;
1565 		rc = NS_LDAP_SUCCESS;
1566 	}
1567 
1568 	if (rc != NS_LDAP_SUCCESS) {
1569 		cookie->err_rc = rc;
1570 		return (-1);
1571 	}
1572 	cookie->conn = conp;
1573 	cookie->connectionId = connectionId;
1574 
1575 	return (0);
1576 }
1577 
1578 static int
1579 get_next_session(ns_ldap_cookie_t *cookie)
1580 {
1581 	ConnectionID	connectionId = -1;
1582 	Connection	*conp = NULL;
1583 	int		rc;
1584 	int		fail_if_new_pwd_reqd = 1;
1585 
1586 	if (cookie->connectionId > -1)
1587 		DropConnection(cookie->connectionId, cookie->i_flags);
1588 
1589 	rc = __s_api_getConnection(NULL, cookie->i_flags,
1590 		cookie->i_auth, &connectionId, &conp,
1591 		&cookie->errorp, fail_if_new_pwd_reqd);
1592 
1593 	/*
1594 	 * If password control attached in *cookie->errorp,
1595 	 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1596 	 * free the error structure (we do not need
1597 	 * the sec_to_expired info).
1598 	 * Reset rc to NS_LDAP_SUCCESS.
1599 	 */
1600 	if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1601 		(void) __ns_ldap_freeError(
1602 			&cookie->errorp);
1603 		cookie->errorp = NULL;
1604 		rc = NS_LDAP_SUCCESS;
1605 	}
1606 
1607 	if (rc != NS_LDAP_SUCCESS) {
1608 		cookie->err_rc = rc;
1609 		return (-1);
1610 	}
1611 	cookie->conn = conp;
1612 	cookie->connectionId = connectionId;
1613 	return (0);
1614 }
1615 
1616 static int
1617 get_referral_session(ns_ldap_cookie_t *cookie)
1618 {
1619 	ConnectionID	connectionId = -1;
1620 	Connection	*conp = NULL;
1621 	int		rc;
1622 	int		fail_if_new_pwd_reqd = 1;
1623 
1624 	if (cookie->connectionId > -1)
1625 		DropConnection(cookie->connectionId, cookie->i_flags);
1626 
1627 	rc = __s_api_getConnection(cookie->refpos->refHost, 0,
1628 			cookie->i_auth, &connectionId, &conp,
1629 			&cookie->errorp, fail_if_new_pwd_reqd);
1630 
1631 	/*
1632 	 * If password control attached in *cookie->errorp,
1633 	 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
1634 	 * free the error structure (we do not need
1635 	 * the sec_to_expired info).
1636 	 * Reset rc to NS_LDAP_SUCCESS.
1637 	 */
1638 	if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
1639 		(void) __ns_ldap_freeError(
1640 			&cookie->errorp);
1641 		cookie->errorp = NULL;
1642 		rc = NS_LDAP_SUCCESS;
1643 	}
1644 
1645 	if (rc != NS_LDAP_SUCCESS) {
1646 		cookie->err_rc = rc;
1647 		return (-1);
1648 	}
1649 	cookie->conn = conp;
1650 	cookie->connectionId = connectionId;
1651 	return (0);
1652 }
1653 
1654 static int
1655 paging_supported(ns_ldap_cookie_t *cookie)
1656 {
1657 	int		rc;
1658 
1659 	cookie->listType = 0;
1660 	rc = __s_api_isCtrlSupported(cookie->conn,
1661 			LDAP_CONTROL_VLVREQUEST);
1662 	if (rc == NS_LDAP_SUCCESS) {
1663 		cookie->listType = VLVCTRLFLAG;
1664 		return (1);
1665 	}
1666 	rc = __s_api_isCtrlSupported(cookie->conn,
1667 			LDAP_CONTROL_SIMPLE_PAGE);
1668 	if (rc == NS_LDAP_SUCCESS) {
1669 		cookie->listType = SIMPLEPAGECTRLFLAG;
1670 		return (1);
1671 	}
1672 	return (0);
1673 }
1674 
1675 static int
1676 setup_vlv_params(ns_ldap_cookie_t *cookie)
1677 {
1678 	LDAPControl	**ctrls;
1679 	LDAPsortkey	**sortkeylist;
1680 	LDAPControl	*sortctrl = NULL;
1681 	LDAPControl	*vlvctrl = NULL;
1682 	LDAPVirtualList	vlist;
1683 	int		rc;
1684 
1685 	_freeControlList(&cookie->p_serverctrls);
1686 
1687 	rc = ldap_create_sort_keylist(&sortkeylist, SORTKEYLIST);
1688 	if (rc != LDAP_SUCCESS) {
1689 		(void) ldap_get_option(cookie->conn->ld,
1690 			LDAP_OPT_ERROR_NUMBER, &rc);
1691 		return (rc);
1692 	}
1693 	rc = ldap_create_sort_control(cookie->conn->ld,
1694 			sortkeylist, 1, &sortctrl);
1695 	ldap_free_sort_keylist(sortkeylist);
1696 	if (rc != LDAP_SUCCESS) {
1697 		(void) ldap_get_option(cookie->conn->ld,
1698 				LDAP_OPT_ERROR_NUMBER, &rc);
1699 		return (rc);
1700 	}
1701 
1702 	vlist.ldvlist_index = cookie->index;
1703 	vlist.ldvlist_size = 0;
1704 
1705 	vlist.ldvlist_before_count = 0;
1706 	vlist.ldvlist_after_count = LISTPAGESIZE-1;
1707 	vlist.ldvlist_attrvalue = NULL;
1708 	vlist.ldvlist_extradata = NULL;
1709 
1710 	rc = ldap_create_virtuallist_control(cookie->conn->ld,
1711 			&vlist, &vlvctrl);
1712 	if (rc != LDAP_SUCCESS) {
1713 		ldap_control_free(sortctrl);
1714 		(void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1715 									&rc);
1716 		return (rc);
1717 	}
1718 
1719 	ctrls = (LDAPControl **)calloc(3, sizeof (LDAPControl *));
1720 	if (ctrls == NULL) {
1721 		ldap_control_free(sortctrl);
1722 		ldap_control_free(vlvctrl);
1723 		return (LDAP_NO_MEMORY);
1724 	}
1725 
1726 	ctrls[0] = sortctrl;
1727 	ctrls[1] = vlvctrl;
1728 
1729 	cookie->p_serverctrls = ctrls;
1730 	return (LDAP_SUCCESS);
1731 }
1732 
1733 static int
1734 setup_simplepg_params(ns_ldap_cookie_t *cookie)
1735 {
1736 	LDAPControl	**ctrls;
1737 	LDAPControl	*pgctrl = NULL;
1738 	int		rc;
1739 
1740 	_freeControlList(&cookie->p_serverctrls);
1741 
1742 	rc = ldap_create_page_control(cookie->conn->ld, LISTPAGESIZE,
1743 		cookie->ctrlCookie, (char)0, &pgctrl);
1744 	if (rc != LDAP_SUCCESS) {
1745 		(void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1746 									&rc);
1747 		return (rc);
1748 	}
1749 
1750 	ctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
1751 	if (ctrls == NULL) {
1752 		ldap_control_free(pgctrl);
1753 		return (LDAP_NO_MEMORY);
1754 	}
1755 	ctrls[0] = pgctrl;
1756 	cookie->p_serverctrls = ctrls;
1757 	return (LDAP_SUCCESS);
1758 }
1759 
1760 static void
1761 proc_result_referrals(ns_ldap_cookie_t *cookie)
1762 {
1763 	int 		errCode, i, rc;
1764 	char 		**referrals = NULL;
1765 
1766 	/*
1767 	 * Only follow one level of referrals, i.e.
1768 	 * if already in referral mode, do nothing
1769 	 */
1770 	if (cookie->refpos == NULL) {
1771 		cookie->new_state = END_RESULT;
1772 		rc = ldap_parse_result(cookie->conn->ld,
1773 			cookie->resultMsg,
1774 			&errCode, NULL,
1775 			NULL, &referrals,
1776 			NULL, 0);
1777 		if (rc != NS_LDAP_SUCCESS) {
1778 			(void) ldap_get_option(cookie->conn->ld,
1779 					LDAP_OPT_ERROR_NUMBER,
1780 					&cookie->err_rc);
1781 			cookie->new_state = LDAP_ERROR;
1782 			return;
1783 		}
1784 		if (errCode == LDAP_REFERRAL) {
1785 			for (i = 0; referrals[i] != NULL;
1786 				i++) {
1787 				/* add to referral list */
1788 				rc = __s_api_addRefInfo(
1789 					&cookie->reflist,
1790 					referrals[i],
1791 					cookie->basedn,
1792 					&cookie->scope,
1793 					cookie->filter,
1794 					cookie->conn->ld);
1795 				if (rc != NS_LDAP_SUCCESS) {
1796 					cookie->new_state =
1797 						ERROR;
1798 					break;
1799 				}
1800 			}
1801 			ldap_value_free(referrals);
1802 		}
1803 	}
1804 }
1805 
1806 static void
1807 proc_search_references(ns_ldap_cookie_t *cookie)
1808 {
1809 	char 		**refurls = NULL;
1810 	int 		i, rc;
1811 
1812 	/*
1813 	 * Only follow one level of referrals, i.e.
1814 	 * if already in referral mode, do nothing
1815 	 */
1816 	if (cookie->refpos == NULL) {
1817 		refurls = ldap_get_reference_urls(
1818 				cookie->conn->ld,
1819 				cookie->resultMsg);
1820 		if (refurls == NULL) {
1821 			(void) ldap_get_option(cookie->conn->ld,
1822 					LDAP_OPT_ERROR_NUMBER,
1823 					&cookie->err_rc);
1824 			cookie->new_state = LDAP_ERROR;
1825 			return;
1826 		}
1827 		for (i = 0; refurls[i] != NULL; i++) {
1828 			/* add to referral list */
1829 			rc = __s_api_addRefInfo(
1830 				&cookie->reflist,
1831 				refurls[i],
1832 				cookie->basedn,
1833 				&cookie->scope,
1834 				cookie->filter,
1835 				cookie->conn->ld);
1836 			if (rc != NS_LDAP_SUCCESS) {
1837 				cookie->new_state =
1838 					ERROR;
1839 				break;
1840 			}
1841 		}
1842 		/* free allocated storage */
1843 		for (i = 0; refurls[i] != NULL; i++)
1844 			free(refurls[i]);
1845 	}
1846 }
1847 
1848 static ns_state_t
1849 multi_result(ns_ldap_cookie_t *cookie)
1850 {
1851 	char		errstr[MAXERROR];
1852 	char		*err;
1853 	ns_ldap_error_t **errorp = NULL;
1854 	LDAPControl	**retCtrls = NULL;
1855 	int		i, rc;
1856 	int		errCode;
1857 	int		finished = 0;
1858 	unsigned long	target_posp = 0;
1859 	unsigned long	list_size = 0;
1860 	unsigned int	count = 0;
1861 	char 		**referrals = NULL;
1862 
1863 	if (cookie->listType == VLVCTRLFLAG) {
1864 		rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
1865 			&errCode, NULL, NULL, &referrals, &retCtrls, 0);
1866 		if (rc != LDAP_SUCCESS) {
1867 			(void) ldap_get_option(cookie->conn->ld,
1868 					LDAP_OPT_ERROR_NUMBER,
1869 					&cookie->err_rc);
1870 			(void) sprintf(errstr,
1871 				gettext("LDAP ERROR (%d): %s.\n"),
1872 				cookie->err_rc,
1873 				gettext(ldap_err2string(cookie->err_rc)));
1874 			err = strdup(errstr);
1875 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
1876 				NULL);
1877 			cookie->err_rc = NS_LDAP_INTERNAL;
1878 			cookie->errorp = *errorp;
1879 			return (LDAP_ERROR);
1880 		}
1881 		if (errCode == LDAP_REFERRAL) {
1882 			for (i = 0; referrals[i] != NULL;
1883 				i++) {
1884 				/* add to referral list */
1885 				rc = __s_api_addRefInfo(
1886 					&cookie->reflist,
1887 					referrals[i],
1888 					cookie->basedn,
1889 					&cookie->scope,
1890 					cookie->filter,
1891 					cookie->conn->ld);
1892 				if (rc != NS_LDAP_SUCCESS) {
1893 						ldap_value_free(
1894 						referrals);
1895 					if (retCtrls)
1896 						ldap_controls_free(
1897 						retCtrls);
1898 					return (ERROR);
1899 				}
1900 			}
1901 			ldap_value_free(referrals);
1902 			if (retCtrls)
1903 				ldap_controls_free(retCtrls);
1904 			return (END_RESULT);
1905 		}
1906 		if (retCtrls) {
1907 			rc = ldap_parse_virtuallist_control(
1908 					cookie->conn->ld, retCtrls,
1909 					&target_posp, &list_size, &errCode);
1910 			if (rc == LDAP_SUCCESS) {
1911 				cookie->index = target_posp + LISTPAGESIZE;
1912 				if (cookie->index >= list_size) {
1913 					finished = 1;
1914 				}
1915 			}
1916 			ldap_controls_free(retCtrls);
1917 			retCtrls = NULL;
1918 		}
1919 		else
1920 			finished = 1;
1921 	} else if (cookie->listType == SIMPLEPAGECTRLFLAG) {
1922 		rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
1923 			&errCode, NULL, NULL, &referrals, &retCtrls, 0);
1924 		if (rc != LDAP_SUCCESS) {
1925 			(void) ldap_get_option(cookie->conn->ld,
1926 					LDAP_OPT_ERROR_NUMBER,
1927 					&cookie->err_rc);
1928 			(void) sprintf(errstr,
1929 				gettext("LDAP ERROR (%d): %s.\n"),
1930 				cookie->err_rc,
1931 				gettext(ldap_err2string(cookie->err_rc)));
1932 			err = strdup(errstr);
1933 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
1934 				NULL);
1935 			cookie->err_rc = NS_LDAP_INTERNAL;
1936 			cookie->errorp = *errorp;
1937 			return (LDAP_ERROR);
1938 		}
1939 		if (errCode == LDAP_REFERRAL) {
1940 			for (i = 0; referrals[i] != NULL;
1941 				i++) {
1942 				/* add to referral list */
1943 				rc = __s_api_addRefInfo(
1944 					&cookie->reflist,
1945 					referrals[i],
1946 					cookie->basedn,
1947 					&cookie->scope,
1948 					cookie->filter,
1949 					cookie->conn->ld);
1950 				if (rc != NS_LDAP_SUCCESS) {
1951 						ldap_value_free(
1952 						referrals);
1953 					if (retCtrls)
1954 						ldap_controls_free(
1955 						retCtrls);
1956 					return (ERROR);
1957 				}
1958 			}
1959 			ldap_value_free(referrals);
1960 			if (retCtrls)
1961 				ldap_controls_free(retCtrls);
1962 			return (END_RESULT);
1963 		}
1964 		if (retCtrls) {
1965 			if (cookie->ctrlCookie)
1966 				ber_bvfree(cookie->ctrlCookie);
1967 			cookie->ctrlCookie = NULL;
1968 			rc = ldap_parse_page_control(
1969 					cookie->conn->ld, retCtrls,
1970 					&count, &cookie->ctrlCookie);
1971 			if (rc == LDAP_SUCCESS) {
1972 				if ((cookie->ctrlCookie == NULL) ||
1973 					(cookie->ctrlCookie->bv_val == NULL) ||
1974 					(*cookie->ctrlCookie->bv_val == NULL))
1975 					finished = 1;
1976 			}
1977 			ldap_controls_free(retCtrls);
1978 			retCtrls = NULL;
1979 		}
1980 		else
1981 			finished = 1;
1982 	}
1983 	if (!finished && cookie->listType == VLVCTRLFLAG)
1984 		return (NEXT_VLV);
1985 	if (!finished && cookie->listType == SIMPLEPAGECTRLFLAG)
1986 		return (NEXT_PAGE);
1987 	if (finished)
1988 		return (END_RESULT);
1989 	return (ERROR);
1990 }
1991 
1992 /*
1993  * This state machine performs one or more LDAP searches to a given
1994  * directory server using service search descriptors and schema
1995  * mapping as appropriate.  The approximate pseudocode for
1996  * this routine is the following:
1997  *    Given the current configuration [set/reset connection etc.]
1998  *    and the current service search descriptor list
1999  *        or default search filter parameters
2000  *    foreach (service search filter) {
2001  *        initialize the filter [via filter_init if appropriate]
2002  *		  get a valid session/connection (preferably the current one)
2003  *					Recover if the connection is lost
2004  *        perform the search
2005  *        foreach (result entry) {
2006  *            process result [via callback if appropriate]
2007  *                save result for caller if accepted.
2008  *                exit and return all collected if allResults found;
2009  *        }
2010  *    }
2011  *    return collected results and exit
2012  */
2013 
2014 static
2015 ns_state_t
2016 search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
2017 {
2018 	char		errstr[MAXERROR];
2019 	char		*err;
2020 	int		rc;
2021 	ns_ldap_entry_t	*nextEntry;
2022 	ns_ldap_error_t *error = NULL;
2023 	ns_ldap_error_t **errorp;
2024 
2025 	errorp = &error;
2026 	cookie->err_rc = 0;
2027 	cookie->state = state;
2028 
2029 	for (;;) {
2030 		switch (cookie->state) {
2031 		case EXIT:
2032 			/* state engine/connection cleaned up in delete */
2033 			if (cookie->attribute) {
2034 				__s_api_free2dArray(cookie->attribute);
2035 				cookie->attribute = NULL;
2036 			}
2037 			if (cookie->reflist) {
2038 				__s_api_deleteRefInfo(cookie->reflist);
2039 				cookie->reflist = NULL;
2040 			}
2041 			return (EXIT);
2042 		case INIT:
2043 			cookie->sdpos = NULL;
2044 			cookie->new_state = NEXT_SEARCH_DESCRIPTOR;
2045 			if (cookie->attribute) {
2046 				__s_api_free2dArray(cookie->attribute);
2047 				cookie->attribute = NULL;
2048 			}
2049 			if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
2050 				cookie->i_attr) {
2051 				cookie->attribute =
2052 					__ns_ldap_mapAttributeList(
2053 						cookie->service,
2054 						cookie->i_attr);
2055 			}
2056 			break;
2057 		case NEXT_SEARCH_DESCRIPTOR:
2058 			/* get next search descriptor */
2059 			if (cookie->sdpos == NULL) {
2060 				cookie->sdpos = cookie->sdlist;
2061 				cookie->new_state = GET_SESSION;
2062 			} else {
2063 				cookie->sdpos++;
2064 				cookie->new_state = NEXT_SEARCH;
2065 			}
2066 			if (*cookie->sdpos == NULL)
2067 				cookie->new_state = EXIT;
2068 			break;
2069 		case GET_SESSION:
2070 			if (get_current_session(cookie) < 0)
2071 				cookie->new_state = NEXT_SESSION;
2072 			else
2073 				cookie->new_state = NEXT_SEARCH;
2074 			break;
2075 		case NEXT_SESSION:
2076 			if (get_next_session(cookie) < 0)
2077 				cookie->new_state = RESTART_SESSION;
2078 			else
2079 				cookie->new_state = NEXT_SEARCH;
2080 			break;
2081 		case RESTART_SESSION:
2082 			if (cookie->i_flags & NS_LDAP_HARD) {
2083 				cookie->new_state = NEXT_SESSION;
2084 				break;
2085 			}
2086 			(void) sprintf(errstr,
2087 				gettext("Session error no available conn.\n"),
2088 				state);
2089 			err = strdup(errstr);
2090 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2091 				NULL);
2092 			cookie->err_rc = NS_LDAP_INTERNAL;
2093 			cookie->errorp = *errorp;
2094 			cookie->new_state = EXIT;
2095 			break;
2096 		case NEXT_SEARCH:
2097 			/* setup referrals search if necessary */
2098 			if (cookie->refpos) {
2099 				if (setup_referral_search(cookie) < 0) {
2100 					cookie->new_state = EXIT;
2101 					break;
2102 				}
2103 			} else if (setup_next_search(cookie) < 0) {
2104 				cookie->new_state = EXIT;
2105 				break;
2106 			}
2107 			/* only do VLV/PAGE on scopes onelevel/subtree */
2108 			if (paging_supported(cookie)) {
2109 				if (cookie->use_paging &&
2110 				    (cookie->scope != LDAP_SCOPE_BASE)) {
2111 					cookie->index = 1;
2112 					if (cookie->listType == VLVCTRLFLAG)
2113 						cookie->new_state = NEXT_VLV;
2114 					else
2115 						cookie->new_state = NEXT_PAGE;
2116 					break;
2117 				}
2118 			}
2119 			cookie->new_state = ONE_SEARCH;
2120 			break;
2121 		case NEXT_VLV:
2122 			rc = setup_vlv_params(cookie);
2123 			if (rc != LDAP_SUCCESS) {
2124 				cookie->err_rc = rc;
2125 				cookie->new_state = LDAP_ERROR;
2126 				break;
2127 			}
2128 			cookie->next_state = MULTI_RESULT;
2129 			cookie->new_state = DO_SEARCH;
2130 			break;
2131 		case NEXT_PAGE:
2132 			rc = setup_simplepg_params(cookie);
2133 			if (rc != LDAP_SUCCESS) {
2134 				cookie->err_rc = rc;
2135 				cookie->new_state = LDAP_ERROR;
2136 				break;
2137 			}
2138 			cookie->next_state = MULTI_RESULT;
2139 			cookie->new_state = DO_SEARCH;
2140 			break;
2141 		case ONE_SEARCH:
2142 			cookie->next_state = NEXT_RESULT;
2143 			cookie->new_state = DO_SEARCH;
2144 			break;
2145 		case DO_SEARCH:
2146 			rc = ldap_search_ext(cookie->conn->ld,
2147 				cookie->basedn,
2148 				cookie->scope,
2149 				cookie->filter,
2150 				cookie->attribute,
2151 				0,
2152 				cookie->p_serverctrls,
2153 				NULL,
2154 				&cookie->search_timeout, 0,
2155 				&cookie->msgId);
2156 			if (rc != LDAP_SUCCESS) {
2157 				if (rc == LDAP_BUSY ||
2158 				    rc == LDAP_UNAVAILABLE ||
2159 				    rc == LDAP_UNWILLING_TO_PERFORM ||
2160 				    rc == LDAP_CONNECT_ERROR ||
2161 				    rc == LDAP_SERVER_DOWN) {
2162 
2163 					cookie->new_state = NEXT_SESSION;
2164 
2165 					/*
2166 					 * If not able to reach the
2167 					 * server, inform the ldap
2168 					 * cache manager that the
2169 					 * server should be removed
2170 					 * from it's server list.
2171 					 * Thus, the manager will not
2172 					 * return this server on the next
2173 					 * get-server request and will
2174 					 * also reduce the server list
2175 					 * refresh TTL, so that it will
2176 					 * find out sooner when the server
2177 					 * is up again.
2178 					 */
2179 					if (rc == LDAP_CONNECT_ERROR ||
2180 						rc == LDAP_SERVER_DOWN) {
2181 						__s_api_removeServer(
2182 						    cookie->conn->serverAddr);
2183 						if (cookie->connectionId > -1) {
2184 						    DropConnection(
2185 							cookie->connectionId,
2186 							NS_LDAP_NEW_CONN);
2187 						    cookie->connectionId = -1;
2188 						}
2189 					}
2190 					break;
2191 				}
2192 				cookie->err_rc = rc;
2193 				cookie->new_state = LDAP_ERROR;
2194 				break;
2195 			}
2196 			cookie->new_state = cookie->next_state;
2197 			break;
2198 		case NEXT_RESULT:
2199 			rc = ldap_result(cookie->conn->ld, cookie->msgId,
2200 				LDAP_MSG_ONE,
2201 				(struct timeval *)&cookie->search_timeout,
2202 				&cookie->resultMsg);
2203 			if (rc == LDAP_RES_SEARCH_RESULT) {
2204 				cookie->new_state = END_RESULT;
2205 				/* check and process referrals info */
2206 				if (cookie->followRef)
2207 					proc_result_referrals(
2208 						cookie);
2209 				(void) ldap_msgfree(cookie->resultMsg);
2210 				cookie->resultMsg = NULL;
2211 				break;
2212 			}
2213 			/* handle referrals if necessary */
2214 			if (rc == LDAP_RES_SEARCH_REFERENCE) {
2215 				if (cookie->followRef)
2216 					proc_search_references(cookie);
2217 				(void) ldap_msgfree(cookie->resultMsg);
2218 				cookie->resultMsg = NULL;
2219 				break;
2220 			}
2221 			if (rc != LDAP_RES_SEARCH_ENTRY) {
2222 				switch (rc) {
2223 				case 0:
2224 					rc = LDAP_TIMEOUT;
2225 					break;
2226 				case -1:
2227 					rc = ldap_get_lderrno(cookie->conn->ld,
2228 						    NULL, NULL);
2229 					break;
2230 				default:
2231 					rc = ldap_result2error(cookie->conn->ld,
2232 						cookie->resultMsg, 1);
2233 					break;
2234 				}
2235 				(void) ldap_msgfree(cookie->resultMsg);
2236 				cookie->resultMsg = NULL;
2237 				if (rc == LDAP_BUSY ||
2238 				    rc == LDAP_UNAVAILABLE ||
2239 				    rc == LDAP_UNWILLING_TO_PERFORM ||
2240 				    rc == LDAP_SERVER_DOWN) {
2241 					cookie->new_state = NEXT_SESSION;
2242 					break;
2243 				}
2244 				cookie->err_rc = rc;
2245 				cookie->new_state = LDAP_ERROR;
2246 				break;
2247 			}
2248 			/* else LDAP_RES_SEARCH_ENTRY */
2249 			rc = __s_api_getEntry(cookie);
2250 			(void) ldap_msgfree(cookie->resultMsg);
2251 			cookie->resultMsg = NULL;
2252 			if (rc != NS_LDAP_SUCCESS) {
2253 				cookie->new_state = LDAP_ERROR;
2254 				break;
2255 			}
2256 			cookie->new_state = PROCESS_RESULT;
2257 			cookie->next_state = NEXT_RESULT;
2258 			break;
2259 		case MULTI_RESULT:
2260 			rc = ldap_result(cookie->conn->ld, cookie->msgId,
2261 				LDAP_MSG_ONE,
2262 				(struct timeval *)&cookie->search_timeout,
2263 				&cookie->resultMsg);
2264 			if (rc == LDAP_RES_SEARCH_RESULT) {
2265 				rc = ldap_result2error(cookie->conn->ld,
2266 					cookie->resultMsg, 0);
2267 				if (rc != LDAP_SUCCESS) {
2268 					cookie->err_rc = rc;
2269 					cookie->new_state = LDAP_ERROR;
2270 					(void) ldap_msgfree(cookie->resultMsg);
2271 					break;
2272 				}
2273 				cookie->new_state = multi_result(cookie);
2274 				(void) ldap_msgfree(cookie->resultMsg);
2275 				cookie->resultMsg = NULL;
2276 				break;
2277 			}
2278 			/* handle referrals if necessary */
2279 			if (rc == LDAP_RES_SEARCH_REFERENCE &&
2280 				cookie->followRef) {
2281 				proc_search_references(cookie);
2282 				(void) ldap_msgfree(cookie->resultMsg);
2283 				cookie->resultMsg = NULL;
2284 				break;
2285 			}
2286 			if (rc != LDAP_RES_SEARCH_ENTRY) {
2287 				switch (rc) {
2288 				case 0:
2289 					rc = LDAP_TIMEOUT;
2290 					break;
2291 				case -1:
2292 					rc = ldap_get_lderrno(cookie->conn->ld,
2293 						    NULL, NULL);
2294 					break;
2295 				default:
2296 					rc = ldap_result2error(cookie->conn->ld,
2297 						cookie->resultMsg, 1);
2298 					break;
2299 				}
2300 				(void) ldap_msgfree(cookie->resultMsg);
2301 				cookie->resultMsg = NULL;
2302 				if (rc == LDAP_BUSY ||
2303 				    rc == LDAP_UNAVAILABLE ||
2304 				    rc == LDAP_UNWILLING_TO_PERFORM ||
2305 				    rc == LDAP_SERVER_DOWN) {
2306 					cookie->new_state = NEXT_SESSION;
2307 					break;
2308 				}
2309 				cookie->err_rc = rc;
2310 				cookie->new_state = LDAP_ERROR;
2311 				break;
2312 			}
2313 			/* else LDAP_RES_SEARCH_ENTRY */
2314 			rc = __s_api_getEntry(cookie);
2315 			(void) ldap_msgfree(cookie->resultMsg);
2316 			cookie->resultMsg = NULL;
2317 			if (rc != NS_LDAP_SUCCESS) {
2318 				cookie->new_state = LDAP_ERROR;
2319 				break;
2320 			}
2321 			cookie->new_state = PROCESS_RESULT;
2322 			cookie->next_state = MULTI_RESULT;
2323 			break;
2324 		case PROCESS_RESULT:
2325 			/* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
2326 			if (cookie->use_usercb && cookie->callback) {
2327 				rc = 0;
2328 				for (nextEntry = cookie->result->entry;
2329 					nextEntry != NULL;
2330 					nextEntry = nextEntry->next) {
2331 					rc = (*cookie->callback)(nextEntry,
2332 						cookie->userdata);
2333 
2334 					if (rc == NS_LDAP_CB_DONE) {
2335 					/* cb doesn't want any more data */
2336 						rc = NS_LDAP_PARTIAL;
2337 						cookie->err_rc = rc;
2338 						break;
2339 					} else if (rc != NS_LDAP_CB_NEXT) {
2340 					/* invalid return code */
2341 						rc = NS_LDAP_OP_FAILED;
2342 						cookie->err_rc = rc;
2343 						break;
2344 					}
2345 				}
2346 				(void) __ns_ldap_freeResult(&cookie->result);
2347 				cookie->result = NULL;
2348 			}
2349 			if (rc != 0) {
2350 				cookie->new_state = EXIT;
2351 				break;
2352 			}
2353 			/* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
2354 			cookie->new_state = cookie->next_state;
2355 			break;
2356 		case END_PROCESS_RESULT:
2357 			cookie->new_state = cookie->next_state;
2358 			break;
2359 		case END_RESULT:
2360 			/*
2361 			 * XXX DO WE NEED THIS CASE?
2362 			 * if (search is complete) {
2363 			 * 	cookie->new_state = EXIT;
2364 			 * } else
2365 			 */
2366 				/*
2367 				 * entering referral mode if necessary
2368 				 */
2369 				if (cookie->followRef && cookie->reflist)
2370 					cookie->new_state =
2371 						NEXT_REFERRAL;
2372 				else
2373 					cookie->new_state =
2374 						NEXT_SEARCH_DESCRIPTOR;
2375 			break;
2376 		case NEXT_REFERRAL:
2377 			/* get next referral info */
2378 			if (cookie->refpos == NULL)
2379 				cookie->refpos =
2380 					cookie->reflist;
2381 			else
2382 				cookie->refpos =
2383 					cookie->refpos->next;
2384 			/* check see if done with all referrals */
2385 			if (cookie->refpos != NULL)
2386 				cookie->new_state =
2387 					GET_REFERRAL_SESSION;
2388 			else {
2389 				__s_api_deleteRefInfo(cookie->reflist);
2390 				cookie->reflist = NULL;
2391 				cookie->new_state =
2392 					NEXT_SEARCH_DESCRIPTOR;
2393 			}
2394 			break;
2395 		case GET_REFERRAL_SESSION:
2396 			if (get_referral_session(cookie) < 0)
2397 				cookie->new_state = EXIT;
2398 			else {
2399 				cookie->new_state = NEXT_SEARCH;
2400 			}
2401 			break;
2402 		case LDAP_ERROR:
2403 			(void) sprintf(errstr,
2404 				gettext("LDAP ERROR (%d): %s."),
2405 				cookie->err_rc,
2406 				ldap_err2string(cookie->err_rc));
2407 			err = strdup(errstr);
2408 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2409 			NULL);
2410 			cookie->err_rc = NS_LDAP_INTERNAL;
2411 			cookie->errorp = *errorp;
2412 			return (ERROR);
2413 		default:
2414 		case ERROR:
2415 			(void) sprintf(errstr,
2416 				gettext("Internal State machine exit (%d).\n"),
2417 				cookie->state);
2418 			err = strdup(errstr);
2419 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2420 			NULL);
2421 			cookie->err_rc = NS_LDAP_INTERNAL;
2422 			cookie->errorp = *errorp;
2423 			return (ERROR);
2424 		}
2425 
2426 		if (cycle == ONE_STEP) {
2427 			return (cookie->new_state);
2428 		}
2429 		cookie->state = cookie->new_state;
2430 	}
2431 	/*NOTREACHED*/
2432 #if 0
2433 	(void) sprintf(errstr,
2434 		gettext("Unexpected State machine error.\n"));
2435 	err = strdup(errstr);
2436 	MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NULL);
2437 	cookie->err_rc = NS_LDAP_INTERNAL;
2438 	cookie->errorp = *errorp;
2439 	return (ERROR);
2440 #endif
2441 }
2442 
2443 
2444 
2445 /*
2446  * __ns_ldap_list performs one or more LDAP searches to a given
2447  * directory server using service search descriptors and schema
2448  * mapping as appropriate.
2449  */
2450 
2451 int
2452 __ns_ldap_list(
2453 	const char *service,
2454 	const char *filter,
2455 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2456 	char **realfilter, const void *userdata),
2457 	const char * const *attribute,
2458 	const ns_cred_t *auth,
2459 	const int flags,
2460 	ns_ldap_result_t **rResult, /* return result entries */
2461 	ns_ldap_error_t **errorp,
2462 	int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
2463 	const void *userdata)
2464 {
2465 	ns_ldap_cookie_t	*cookie;
2466 	ns_ldap_search_desc_t	**sdlist = NULL;
2467 	ns_ldap_search_desc_t	*dptr;
2468 	ns_ldap_error_t		*error = NULL;
2469 	char			**dns = NULL;
2470 	int			scope;
2471 	int			rc;
2472 
2473 	*errorp = NULL;
2474 
2475 	/* Initialize State machine cookie */
2476 	cookie = init_search_state_machine();
2477 	if (cookie == NULL) {
2478 		return (NS_LDAP_MEMORY);
2479 	}
2480 
2481 	/* see if need to follow referrals */
2482 	rc = __s_api_toFollowReferrals(flags,
2483 		&cookie->followRef, errorp);
2484 	if (rc != NS_LDAP_SUCCESS) {
2485 		delete_search_cookie(cookie);
2486 		return (rc);
2487 	}
2488 
2489 	/* get the service descriptor - or create a default one */
2490 	rc = __s_api_get_SSD_from_SSDtoUse_service(service,
2491 		&sdlist, errorp);
2492 	if (rc != NS_LDAP_SUCCESS) {
2493 		delete_search_cookie(cookie);
2494 		*errorp = error;
2495 		return (rc);
2496 	}
2497 
2498 	if (sdlist == NULL) {
2499 		/* Create default service Desc */
2500 		sdlist = (ns_ldap_search_desc_t **)calloc(2,
2501 					sizeof (ns_ldap_search_desc_t *));
2502 		if (sdlist == NULL) {
2503 			delete_search_cookie(cookie);
2504 			cookie = NULL;
2505 			return (NS_LDAP_MEMORY);
2506 		}
2507 		dptr = (ns_ldap_search_desc_t *)
2508 				calloc(1, sizeof (ns_ldap_search_desc_t));
2509 		if (dptr == NULL) {
2510 			free(sdlist);
2511 			delete_search_cookie(cookie);
2512 			cookie = NULL;
2513 			return (NS_LDAP_MEMORY);
2514 		}
2515 		sdlist[0] = dptr;
2516 
2517 		/* default base */
2518 		rc = __s_api_getDNs(&dns, service, &cookie->errorp);
2519 		if (rc != NS_LDAP_SUCCESS) {
2520 			if (dns) {
2521 				__s_api_free2dArray(dns);
2522 				dns = NULL;
2523 			}
2524 			*errorp = cookie->errorp;
2525 			cookie->errorp = NULL;
2526 			delete_search_cookie(cookie);
2527 			cookie = NULL;
2528 			return (rc);
2529 		}
2530 		dptr->basedn = strdup(dns[0]);
2531 		__s_api_free2dArray(dns);
2532 		dns = NULL;
2533 
2534 		/* default scope */
2535 		scope = 0;
2536 		rc = __s_api_getSearchScope(&scope, &cookie->errorp);
2537 		dptr->scope = scope;
2538 	}
2539 
2540 	cookie->sdlist = sdlist;
2541 
2542 	/*
2543 	 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
2544 	 */
2545 	if (flags & NS_LDAP_PAGE_CTRL)
2546 		cookie->use_paging = TRUE;
2547 	else
2548 		cookie->use_paging = FALSE;
2549 
2550 	/* Set up other arguments */
2551 	cookie->userdata = userdata;
2552 	if (init_filter_cb != NULL) {
2553 		cookie->init_filter_cb = init_filter_cb;
2554 		cookie->use_filtercb = 1;
2555 	}
2556 	if (callback != NULL) {
2557 		cookie->callback = callback;
2558 		cookie->use_usercb = 1;
2559 	}
2560 	if (service) {
2561 		cookie->service = strdup(service);
2562 		if (cookie->service == NULL) {
2563 			delete_search_cookie(cookie);
2564 			cookie = NULL;
2565 			return (NS_LDAP_MEMORY);
2566 		}
2567 	}
2568 
2569 	cookie->i_filter = strdup(filter);
2570 	cookie->i_attr = attribute;
2571 	cookie->i_auth = auth;
2572 	cookie->i_flags = flags;
2573 
2574 	/* Process search */
2575 	rc = search_state_machine(cookie, INIT, 0);
2576 
2577 	/* Copy results back to user */
2578 	rc = cookie->err_rc;
2579 	if (rc != NS_LDAP_SUCCESS)
2580 		*errorp = cookie->errorp;
2581 	*rResult = cookie->result;
2582 
2583 	cookie->errorp = NULL;
2584 	cookie->result = NULL;
2585 	delete_search_cookie(cookie);
2586 	cookie = NULL;
2587 
2588 	if (*rResult == NULL)
2589 		rc = NS_LDAP_NOTFOUND;
2590 	return (rc);
2591 }
2592 
2593 /*
2594  * __s_api_find_domainname performs one or more LDAP searches to
2595  * find the value of the nisdomain attribute associated with
2596  * the input DN
2597  */
2598 
2599 static int
2600 __s_api_find_domainname(
2601 	const char *dn,
2602 	char **domainname,
2603 	const ns_cred_t *cred,
2604 	ns_ldap_error_t **errorp)
2605 {
2606 
2607 	ns_ldap_cookie_t	*cookie;
2608 	ns_ldap_search_desc_t	**sdlist;
2609 	ns_ldap_search_desc_t	*dptr;
2610 	int			rc;
2611 	char			**value;
2612 	int			flags = 0;
2613 
2614 	*domainname = NULL;
2615 	*errorp = NULL;
2616 
2617 	/* Initialize State machine cookie */
2618 	cookie = init_search_state_machine();
2619 	if (cookie == NULL) {
2620 		return (NS_LDAP_MEMORY);
2621 	}
2622 
2623 	/* see if need to follow referrals */
2624 	rc = __s_api_toFollowReferrals(flags,
2625 		&cookie->followRef, errorp);
2626 	if (rc != NS_LDAP_SUCCESS) {
2627 		delete_search_cookie(cookie);
2628 		return (rc);
2629 	}
2630 
2631 	/* Create default service Desc */
2632 	sdlist = (ns_ldap_search_desc_t **)calloc(2,
2633 				sizeof (ns_ldap_search_desc_t *));
2634 	if (sdlist == NULL) {
2635 		delete_search_cookie(cookie);
2636 		cookie = NULL;
2637 		return (NS_LDAP_MEMORY);
2638 	}
2639 	dptr = (ns_ldap_search_desc_t *)
2640 			calloc(1, sizeof (ns_ldap_search_desc_t));
2641 	if (dptr == NULL) {
2642 		free(sdlist);
2643 		delete_search_cookie(cookie);
2644 		cookie = NULL;
2645 		return (NS_LDAP_MEMORY);
2646 	}
2647 	sdlist[0] = dptr;
2648 
2649 	/* search base is dn */
2650 	dptr->basedn = strdup(dn);
2651 
2652 	/* search scope is base */
2653 	dptr->scope = NS_LDAP_SCOPE_BASE;
2654 
2655 	/* search filter is "nisdomain=*" */
2656 	dptr->filter = strdup(_NIS_FILTER);
2657 
2658 	cookie->sdlist = sdlist;
2659 	cookie->i_filter = strdup(dptr->filter);
2660 	cookie->i_attr = nis_domain_attrs;
2661 	cookie->i_auth = cred;
2662 	cookie->i_flags = 0;
2663 
2664 	/* Process search */
2665 	rc = search_state_machine(cookie, INIT, 0);
2666 
2667 	/* Copy domain name if found */
2668 	rc = cookie->err_rc;
2669 	if (rc != NS_LDAP_SUCCESS)
2670 		*errorp = cookie->errorp;
2671 	if (cookie->result == NULL)
2672 		rc = NS_LDAP_NOTFOUND;
2673 	if (rc == NS_LDAP_SUCCESS) {
2674 		value = __ns_ldap_getAttr(cookie->result->entry,
2675 			_NIS_DOMAIN);
2676 		if (value[0])
2677 			*domainname = strdup(value[0]);
2678 		else
2679 			rc = NS_LDAP_NOTFOUND;
2680 	}
2681 	if (cookie->result != NULL)
2682 		(void) __ns_ldap_freeResult(&cookie->result);
2683 	cookie->errorp = NULL;
2684 	delete_search_cookie(cookie);
2685 	cookie = NULL;
2686 	return (rc);
2687 }
2688 
2689 int
2690 __ns_ldap_firstEntry(
2691 	const char *service,
2692 	const char *filter,
2693 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2694 	char **realfilter, const void *userdata),
2695 	const char * const *attribute,
2696 	const ns_cred_t *auth,
2697 	const int flags,
2698 	void **vcookie,
2699 	ns_ldap_result_t **result,
2700 	ns_ldap_error_t ** errorp,
2701 	const void *userdata)
2702 {
2703 	ns_ldap_cookie_t	*cookie = NULL;
2704 	ns_ldap_error_t		*error = NULL;
2705 	ns_state_t		state;
2706 	ns_ldap_search_desc_t	**sdlist;
2707 	ns_ldap_search_desc_t	*dptr;
2708 	char			**dns = NULL;
2709 	int			scope;
2710 	int			rc;
2711 
2712 	*errorp = NULL;
2713 	*result = NULL;
2714 
2715 	/* get the service descriptor - or create a default one */
2716 	rc = __s_api_get_SSD_from_SSDtoUse_service(service,
2717 			&sdlist, errorp);
2718 	if (rc != NS_LDAP_SUCCESS) {
2719 		*errorp = error;
2720 		return (rc);
2721 	}
2722 	if (sdlist == NULL) {
2723 		/* Create default service Desc */
2724 		sdlist = (ns_ldap_search_desc_t **)calloc(2,
2725 					sizeof (ns_ldap_search_desc_t *));
2726 		if (sdlist == NULL) {
2727 			return (NS_LDAP_MEMORY);
2728 		}
2729 		dptr = (ns_ldap_search_desc_t *)
2730 				calloc(1, sizeof (ns_ldap_search_desc_t));
2731 		if (dptr == NULL) {
2732 			free(sdlist);
2733 			return (NS_LDAP_MEMORY);
2734 		}
2735 		sdlist[0] = dptr;
2736 
2737 		/* default base */
2738 		rc = __s_api_getDNs(&dns, service, &error);
2739 		if (rc != NS_LDAP_SUCCESS) {
2740 			if (dns) {
2741 				__s_api_free2dArray(dns);
2742 				dns = NULL;
2743 			}
2744 			if (sdlist) {
2745 				(void) __ns_ldap_freeSearchDescriptors(
2746 					&sdlist);
2747 
2748 				sdlist = NULL;
2749 			}
2750 			*errorp = error;
2751 			return (rc);
2752 		}
2753 		dptr->basedn = strdup(dns[0]);
2754 		__s_api_free2dArray(dns);
2755 		dns = NULL;
2756 
2757 		/* default scope */
2758 		scope = 0;
2759 		cookie = init_search_state_machine();
2760 		if (cookie == NULL) {
2761 			if (sdlist) {
2762 				(void) __ns_ldap_freeSearchDescriptors(&sdlist);
2763 				sdlist = NULL;
2764 			}
2765 			return (NS_LDAP_MEMORY);
2766 		}
2767 		rc = __s_api_getSearchScope(&scope, &cookie->errorp);
2768 		dptr->scope = scope;
2769 	}
2770 
2771 	/* Initialize State machine cookie */
2772 	if (cookie == NULL)
2773 		cookie = init_search_state_machine();
2774 	if (cookie == NULL) {
2775 		if (sdlist) {
2776 			(void) __ns_ldap_freeSearchDescriptors(&sdlist);
2777 			sdlist = NULL;
2778 		}
2779 		return (NS_LDAP_MEMORY);
2780 	}
2781 
2782 	cookie->sdlist = sdlist;
2783 
2784 	/* see if need to follow referrals */
2785 	rc = __s_api_toFollowReferrals(flags,
2786 		&cookie->followRef, errorp);
2787 	if (rc != NS_LDAP_SUCCESS) {
2788 		delete_search_cookie(cookie);
2789 		return (rc);
2790 	}
2791 
2792 	/*
2793 	 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
2794 	 */
2795 	if (flags & NS_LDAP_NO_PAGE_CTRL)
2796 		cookie->use_paging = FALSE;
2797 	else
2798 		cookie->use_paging = TRUE;
2799 
2800 	/* Set up other arguments */
2801 	cookie->userdata = userdata;
2802 	if (init_filter_cb != NULL) {
2803 		cookie->init_filter_cb = init_filter_cb;
2804 		cookie->use_filtercb = 1;
2805 	}
2806 	cookie->use_usercb = 0;
2807 	if (service) {
2808 		cookie->service = strdup(service);
2809 		if (cookie->service == NULL) {
2810 			delete_search_cookie(cookie);
2811 			return (NS_LDAP_MEMORY);
2812 		}
2813 	}
2814 
2815 	cookie->i_filter = strdup(filter);
2816 	cookie->i_attr = attribute;
2817 	cookie->i_auth = auth;
2818 	cookie->i_flags = flags;
2819 
2820 	state = INIT;
2821 	for (;;) {
2822 		state = search_state_machine(cookie, state, ONE_STEP);
2823 		switch (state) {
2824 		case PROCESS_RESULT:
2825 			*result = cookie->result;
2826 			cookie->result = NULL;
2827 			*vcookie = (void *)cookie;
2828 			return (NS_LDAP_SUCCESS);
2829 		case ERROR:
2830 		case LDAP_ERROR:
2831 			rc = cookie->err_rc;
2832 			*errorp = cookie->errorp;
2833 			cookie->errorp = NULL;
2834 			delete_search_cookie(cookie);
2835 			return (rc);
2836 		case EXIT:
2837 			rc = cookie->err_rc;
2838 			if (rc != NS_LDAP_SUCCESS) {
2839 				*errorp = cookie->errorp;
2840 				cookie->errorp = NULL;
2841 			} else {
2842 				rc = NS_LDAP_NOTFOUND;
2843 			}
2844 
2845 			delete_search_cookie(cookie);
2846 			return (rc);
2847 
2848 		default:
2849 			break;
2850 		}
2851 	}
2852 }
2853 
2854 /*ARGSUSED2*/
2855 int
2856 __ns_ldap_nextEntry(
2857 	void *vcookie,
2858 	ns_ldap_result_t **result,
2859 	ns_ldap_error_t ** errorp)
2860 {
2861 	ns_ldap_cookie_t	*cookie;
2862 	ns_state_t		state;
2863 	int			rc;
2864 
2865 	cookie = (ns_ldap_cookie_t *)vcookie;
2866 	cookie->result = NULL;
2867 	*result = NULL;
2868 
2869 	state = END_PROCESS_RESULT;
2870 	for (;;) {
2871 		state = search_state_machine(cookie, state, ONE_STEP);
2872 		switch (state) {
2873 		case PROCESS_RESULT:
2874 			*result = cookie->result;
2875 			cookie->result = NULL;
2876 			return (NS_LDAP_SUCCESS);
2877 		case ERROR:
2878 		case LDAP_ERROR:
2879 			rc = cookie->err_rc;
2880 			*errorp = cookie->errorp;
2881 			cookie->errorp = NULL;
2882 			return (rc);
2883 		case EXIT:
2884 			return (NS_LDAP_SUCCESS);
2885 		}
2886 	}
2887 }
2888 
2889 int
2890 __ns_ldap_endEntry(
2891 	void **vcookie,
2892 	ns_ldap_error_t ** errorp)
2893 {
2894 	ns_ldap_cookie_t	*cookie;
2895 	int			rc;
2896 
2897 	if (*vcookie == NULL)
2898 		return (NS_LDAP_INVALID_PARAM);
2899 
2900 	cookie = (ns_ldap_cookie_t *)(*vcookie);
2901 	cookie->result = NULL;
2902 
2903 	/* Complete search */
2904 	rc = search_state_machine(cookie, EXIT, 0);
2905 
2906 	/* Copy results back to user */
2907 	rc = cookie->err_rc;
2908 	if (rc != NS_LDAP_SUCCESS)
2909 		*errorp = cookie->errorp;
2910 
2911 	cookie->errorp = NULL;
2912 	delete_search_cookie(cookie);
2913 	cookie = NULL;
2914 	*vcookie = NULL;
2915 
2916 	return (rc);
2917 }
2918 
2919 
2920 int
2921 __ns_ldap_freeResult(ns_ldap_result_t **result)
2922 {
2923 
2924 	ns_ldap_entry_t	*curEntry = NULL;
2925 	ns_ldap_entry_t	*delEntry = NULL;
2926 	int		i;
2927 	ns_ldap_result_t	*res = *result;
2928 
2929 #ifdef DEBUG
2930 	(void) fprintf(stderr, "__ns_ldap_freeResult START\n");
2931 #endif
2932 	if (res == NULL)
2933 		return (NS_LDAP_INVALID_PARAM);
2934 
2935 	if (res->entry != NULL)
2936 		curEntry = res->entry;
2937 
2938 	for (i = 0; i < res->entries_count; i++) {
2939 		if (curEntry != NULL) {
2940 			delEntry = curEntry;
2941 			curEntry = curEntry->next;
2942 			__ns_ldap_freeEntry(delEntry);
2943 		}
2944 	}
2945 
2946 	free(res);
2947 	*result = NULL;
2948 	return (NS_LDAP_SUCCESS);
2949 }
2950 
2951 /*ARGSUSED*/
2952 int
2953 __ns_ldap_auth(const ns_cred_t *auth,
2954 		    const int flags,
2955 		    ns_ldap_error_t **errorp,
2956 		    LDAPControl **serverctrls,
2957 		    LDAPControl **clientctrls)
2958 {
2959 
2960 	ConnectionID	connectionId = -1;
2961 	Connection	*conp;
2962 	int		rc = 0;
2963 	int		do_not_fail_if_new_pwd_reqd = 0;
2964 
2965 
2966 #ifdef DEBUG
2967 	(void) fprintf(stderr, "__ns_ldap_auth START\n");
2968 #endif
2969 
2970 	*errorp = NULL;
2971 	if (!auth)
2972 		return (NS_LDAP_INVALID_PARAM);
2973 
2974 	rc = __s_api_getConnection(NULL, flags,
2975 			auth, &connectionId, &conp, errorp,
2976 			do_not_fail_if_new_pwd_reqd);
2977 	if (rc == NS_LDAP_OP_FAILED && *errorp)
2978 		(void) __ns_ldap_freeError(errorp);
2979 
2980 	if (connectionId > -1)
2981 		DropConnection(connectionId, flags);
2982 	return (rc);
2983 }
2984 
2985 char **
2986 __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname)
2987 {
2988 	int	i;
2989 
2990 	if (entry == NULL)
2991 		return (NULL);
2992 	for (i = 0; i < entry->attr_count; i++) {
2993 		if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL)
2994 			return (entry->attr_pair[i]->attrvalue);
2995 	}
2996 	return (NULL);
2997 }
2998 
2999 
3000 /*ARGSUSED*/
3001 int
3002 __ns_ldap_uid2dn(const char *uid,
3003 		char **userDN,
3004 		const ns_cred_t *cred,	/* cred is ignored */
3005 		ns_ldap_error_t **errorp)
3006 {
3007 	ns_ldap_result_t	*result = NULL;
3008 	char		*filter, *userdata;
3009 	char		errstr[MAXERROR];
3010 	char		**value;
3011 	int		rc = 0;
3012 	int		i = 0;
3013 	size_t		len;
3014 
3015 	*errorp = NULL;
3016 	*userDN = NULL;
3017 	if ((uid == NULL) || (uid[0] == '\0'))
3018 		return (NS_LDAP_INVALID_PARAM);
3019 
3020 	while (uid[i] != '\0') {
3021 		if (uid[i] == '=') {
3022 			*userDN = strdup(uid);
3023 			return (NS_LDAP_SUCCESS);
3024 		}
3025 		i++;
3026 	}
3027 	i = 0;
3028 	while ((uid[i] != '\0') && (isdigit(uid[i])))
3029 		i++;
3030 	if (uid[i] == '\0') {
3031 		len = strlen(UIDNUMFILTER) + strlen(uid) + 1;
3032 		filter = (char *)malloc(len);
3033 		if (filter == NULL) {
3034 			*userDN = NULL;
3035 			return (NS_LDAP_MEMORY);
3036 		}
3037 		(void) snprintf(filter, len, UIDNUMFILTER, uid);
3038 
3039 		len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1;
3040 		userdata = (char *)malloc(len);
3041 		if (userdata == NULL) {
3042 			*userDN = NULL;
3043 			return (NS_LDAP_MEMORY);
3044 		}
3045 		(void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid);
3046 	} else {
3047 		len = strlen(UIDFILTER) + strlen(uid) + 1;
3048 		filter = (char *)malloc(len);
3049 		if (filter == NULL) {
3050 			*userDN = NULL;
3051 			return (NS_LDAP_MEMORY);
3052 		}
3053 		(void) snprintf(filter, len, UIDFILTER, uid);
3054 
3055 		len = strlen(UIDFILTER_SSD) + strlen(uid) + 1;
3056 		userdata = (char *)malloc(len);
3057 		if (userdata == NULL) {
3058 			*userDN = NULL;
3059 			return (NS_LDAP_MEMORY);
3060 		}
3061 		(void) snprintf(userdata, len, UIDFILTER_SSD, uid);
3062 	}
3063 
3064 	rc = __ns_ldap_list("passwd", filter,
3065 				__s_api_merge_SSD_filter,
3066 				NULL, cred, 0,
3067 				&result, errorp, NULL,
3068 				userdata);
3069 	free(filter);
3070 	filter = NULL;
3071 	free(userdata);
3072 	userdata = NULL;
3073 	if (rc != NS_LDAP_SUCCESS) {
3074 		if (result) {
3075 			(void) __ns_ldap_freeResult(&result);
3076 			result = NULL;
3077 		}
3078 		return (rc);
3079 	}
3080 	if (result->entries_count > 1) {
3081 		(void) __ns_ldap_freeResult(&result);
3082 		result = NULL;
3083 		*userDN = NULL;
3084 		(void) sprintf(errstr,
3085 			gettext("Too many entries are returned for %s"), uid);
3086 		MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
3087 			NULL);
3088 		return (NS_LDAP_INTERNAL);
3089 	}
3090 
3091 	value = __ns_ldap_getAttr(result->entry, "dn");
3092 	*userDN = strdup(value[0]);
3093 	(void) __ns_ldap_freeResult(&result);
3094 	result = NULL;
3095 	return (NS_LDAP_SUCCESS);
3096 }
3097 
3098 
3099 /*ARGSUSED*/
3100 int
3101 __ns_ldap_host2dn(const char *host,
3102 		const char *domain,
3103 		char **hostDN,
3104 		const ns_cred_t *cred,	/* cred is ignored */
3105 		ns_ldap_error_t **errorp)
3106 {
3107 	ns_ldap_result_t	*result = NULL;
3108 	char		*filter, *userdata;
3109 	char		errstr[MAXERROR];
3110 	char		**value;
3111 	int		rc;
3112 	size_t		len;
3113 
3114 /*
3115  * XXX
3116  * the domain parameter needs to be used in case domain is not local, if
3117  * this routine is to support multi domain setups, it needs lots of work...
3118  */
3119 	*errorp = NULL;
3120 	*hostDN = NULL;
3121 	if ((host == NULL) || (host[0] == '\0'))
3122 		return (NS_LDAP_INVALID_PARAM);
3123 
3124 	len = strlen(HOSTFILTER) + strlen(host) + 1;
3125 	filter = (char *)malloc(len);
3126 	if (filter == NULL) {
3127 		return (NS_LDAP_MEMORY);
3128 	}
3129 	(void) snprintf(filter,	len, HOSTFILTER, host);
3130 
3131 	len = strlen(HOSTFILTER_SSD) + strlen(host) + 1;
3132 	userdata = (char *)malloc(len);
3133 	if (userdata == NULL) {
3134 		return (NS_LDAP_MEMORY);
3135 	}
3136 	(void) snprintf(userdata, len, HOSTFILTER_SSD, host);
3137 
3138 	rc = __ns_ldap_list("hosts", filter,
3139 				__s_api_merge_SSD_filter,
3140 				NULL, cred, 0, &result,
3141 				errorp, NULL,
3142 				userdata);
3143 	free(filter);
3144 	filter = NULL;
3145 	free(userdata);
3146 	userdata = NULL;
3147 	if (rc != NS_LDAP_SUCCESS) {
3148 		if (result) {
3149 			(void) __ns_ldap_freeResult(&result);
3150 			result = NULL;
3151 		}
3152 		return (rc);
3153 	}
3154 
3155 	if (result->entries_count > 1) {
3156 		(void) __ns_ldap_freeResult(&result);
3157 		result = NULL;
3158 		*hostDN = NULL;
3159 		(void) sprintf(errstr,
3160 			gettext("Too many entries are returned for %s"), host);
3161 		MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
3162 			NULL);
3163 		return (NS_LDAP_INTERNAL);
3164 	}
3165 
3166 	value = __ns_ldap_getAttr(result->entry, "dn");
3167 	*hostDN = strdup(value[0]);
3168 	(void) __ns_ldap_freeResult(&result);
3169 	result = NULL;
3170 	return (NS_LDAP_SUCCESS);
3171 }
3172 
3173 /*ARGSUSED*/
3174 int
3175 __ns_ldap_dn2domain(const char *dn,
3176 			char **domain,
3177 			const ns_cred_t *cred,
3178 			ns_ldap_error_t **errorp)
3179 {
3180 	int		rc, pnum, i, j, len = 0;
3181 	char		*newdn, **rdns = NULL;
3182 	char		**dns, *dn1;
3183 
3184 	*errorp = NULL;
3185 
3186 	if (domain == NULL)
3187 		return (NS_LDAP_INVALID_PARAM);
3188 	else
3189 		*domain = NULL;
3190 
3191 	if ((dn == NULL) || (dn[0] == '\0'))
3192 		return (NS_LDAP_INVALID_PARAM);
3193 
3194 	/*
3195 	 * break dn into rdns
3196 	 */
3197 	dn1 = strdup(dn);
3198 	if (dn1 == NULL)
3199 		return (NS_LDAP_MEMORY);
3200 	rdns = ldap_explode_dn(dn1, 0);
3201 	free(dn1);
3202 	if (rdns == NULL || *rdns == NULL)
3203 		return (NS_LDAP_INVALID_PARAM);
3204 
3205 	for (i = 0; rdns[i]; i++)
3206 		len += strlen(rdns[i]) + 1;
3207 	pnum = i;
3208 
3209 	newdn = (char *)malloc(len + 1);
3210 	dns = (char **)calloc(pnum, sizeof (char *));
3211 	if (newdn == NULL || dns == NULL) {
3212 		if (newdn)
3213 			free(newdn);
3214 		ldap_value_free(rdns);
3215 		return (NS_LDAP_MEMORY);
3216 	}
3217 
3218 	/* construct a semi-normalized dn, newdn */
3219 	*newdn = '\0';
3220 	for (i = 0; rdns[i]; i++) {
3221 		dns[i] = newdn + strlen(newdn);
3222 		(void) strcat(newdn,
3223 			__s_api_remove_rdn_space(rdns[i]));
3224 		(void) strcat(newdn, ",");
3225 	}
3226 	/* remove the last ',' */
3227 	newdn[strlen(newdn) - 1] = '\0';
3228 	ldap_value_free(rdns);
3229 
3230 	/*
3231 	 * loop and find the domain name associated with newdn,
3232 	 * removing rdn one by one from left to right
3233 	 */
3234 	for (i = 0; i < pnum; i++) {
3235 
3236 		if (*errorp)
3237 			(void) __ns_ldap_freeError(errorp);
3238 
3239 		/*
3240 		 *  try cache manager first
3241 		 */
3242 		rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN,
3243 				dns[i], domain);
3244 		if (rc != NS_LDAP_SUCCESS) {
3245 			/*
3246 			 *  try ldap server second
3247 			 */
3248 			rc = __s_api_find_domainname(dns[i], domain,
3249 				cred, errorp);
3250 		} else {
3251 			/*
3252 			 * skip the last one,
3253 			 * since it is already cached by ldap_cachemgr
3254 			 */
3255 			i--;
3256 		}
3257 		if (rc == NS_LDAP_SUCCESS) {
3258 			/*
3259 			 * ask cache manager to save the
3260 			 * dn to domain mapping(s)
3261 			 */
3262 			for (j = 0; j <= i; j++) {
3263 				(void) __s_api_set_cachemgr_data(
3264 					NS_CACHE_DN2DOMAIN,
3265 					dns[j],
3266 					*domain);
3267 			}
3268 			break;
3269 		}
3270 	}
3271 
3272 	free(dns);
3273 	free(newdn);
3274 	if (rc != NS_LDAP_SUCCESS)
3275 		rc = NS_LDAP_NOTFOUND;
3276 	return (rc);
3277 }
3278 
3279 /*ARGSUSED*/
3280 int
3281 __ns_ldap_getServiceAuthMethods(const char *service,
3282 		ns_auth_t ***auth,
3283 		ns_ldap_error_t **errorp)
3284 {
3285 	char		errstr[MAXERROR];
3286 	int		rc, i, done = 0;
3287 	int		slen;
3288 	void		**param;
3289 	char		**sam, *srv, *send;
3290 	ns_auth_t	**authpp = NULL, *ap;
3291 	int		cnt, max;
3292 	ns_config_t	*cfg;
3293 	ns_ldap_error_t	*error = NULL;
3294 
3295 	if (errorp == NULL)
3296 		return (NS_LDAP_INVALID_PARAM);
3297 	*errorp = NULL;
3298 
3299 	if ((service == NULL) || (service[0] == '\0') ||
3300 		(auth == NULL))
3301 		return (NS_LDAP_INVALID_PARAM);
3302 
3303 	*auth = NULL;
3304 	rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, &param, &error);
3305 	if (rc != NS_LDAP_SUCCESS || param == NULL) {
3306 		*errorp = error;
3307 		return (rc);
3308 	}
3309 	sam = (char **)param;
3310 
3311 	cfg = __s_api_get_default_config();
3312 	cnt = 0;
3313 
3314 	slen = strlen(service);
3315 
3316 	for (; *sam; sam++) {
3317 		srv = *sam;
3318 		if (strncasecmp(service, srv, slen) != 0)
3319 			continue;
3320 		srv += slen;
3321 		if (*srv != COLONTOK)
3322 			continue;
3323 		send = srv;
3324 		srv++;
3325 		for (max = 1; (send = strchr(++send, SEMITOK)) != NULL;
3326 			max++) {}
3327 		authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *));
3328 		if (authpp == NULL) {
3329 			(void) __ns_ldap_freeParam(&param);
3330 			__s_api_release_config(cfg);
3331 			return (NS_LDAP_MEMORY);
3332 		}
3333 		while (!done) {
3334 			send = strchr(srv, SEMITOK);
3335 			if (send != NULL) {
3336 				*send = '\0';
3337 				send++;
3338 			}
3339 			i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P);
3340 			if (i == -1) {
3341 				(void) __ns_ldap_freeParam(&param);
3342 				(void) sprintf(errstr,
3343 		gettext("Unsupported serviceAuthenticationMethod: %s.\n"), srv);
3344 				MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
3345 					strdup(errstr), NULL);
3346 				__s_api_release_config(cfg);
3347 				return (NS_LDAP_CONFIG);
3348 			}
3349 			ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i);
3350 			if (ap == NULL) {
3351 				(void) __ns_ldap_freeParam(&param);
3352 				__s_api_release_config(cfg);
3353 				return (NS_LDAP_MEMORY);
3354 			}
3355 			authpp[cnt++] = ap;
3356 			if (send == NULL)
3357 				done = TRUE;
3358 			else
3359 				srv = send;
3360 		}
3361 	}
3362 
3363 	*auth = authpp;
3364 	(void) __ns_ldap_freeParam(&param);
3365 	__s_api_release_config(cfg);
3366 	return (NS_LDAP_SUCCESS);
3367 }
3368 
3369 /*
3370  * This routine is called when certain scenario occurs
3371  * e.g.
3372  * service == auto_home
3373  * SSD = automount: ou = mytest,
3374  * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
3375  * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
3376  * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
3377  *
3378  * The automountMapName is prepended implicitely but is mapped
3379  * to AAA. So dn could appers as
3380  * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
3381  * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
3382  * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
3383  * in the directory.
3384  * This function is called to covert the mapped attr back to
3385  * orig attr when the entries are searched and returned
3386  */
3387 
3388 int
3389 __s_api_convert_automountmapname(const char *service, char **dn,
3390 		ns_ldap_error_t **errp) {
3391 
3392 	char	**mapping = NULL;
3393 	char	*mapped_attr = NULL;
3394 	char	*automountmapname = "automountMapName";
3395 	char	*buffer = NULL;
3396 	int	rc = NS_LDAP_SUCCESS;
3397 	char	errstr[MAXERROR];
3398 
3399 	/*
3400 	 * dn is an input/out parameter, check it first
3401 	 */
3402 
3403 	if (service == NULL || dn == NULL || *dn == NULL)
3404 		return (NS_LDAP_INVALID_PARAM);
3405 
3406 	/*
3407 	 * Check to see if there is a mapped attribute for auto_xxx
3408 	 */
3409 
3410 	mapping = __ns_ldap_getMappedAttributes(service, automountmapname);
3411 
3412 	/*
3413 	 * if no mapped attribute for auto_xxx, try automount
3414 	 */
3415 
3416 	if (mapping == NULL)
3417 		mapping = __ns_ldap_getMappedAttributes(
3418 			"automount", automountmapname);
3419 
3420 	/*
3421 	 * if no mapped attribute is found, return SUCCESS (no op)
3422 	 */
3423 
3424 	if (mapping == NULL)
3425 		return (NS_LDAP_SUCCESS);
3426 
3427 	/*
3428 	 * if the mapped attribute is found and attr is not empty,
3429 	 * copy it
3430 	 */
3431 
3432 	if (mapping[0] != NULL) {
3433 		mapped_attr = strdup(mapping[0]);
3434 		__s_api_free2dArray(mapping);
3435 		if (mapped_attr == NULL) {
3436 			return (NS_LDAP_MEMORY);
3437 		}
3438 	} else {
3439 		__s_api_free2dArray(mapping);
3440 
3441 		(void) snprintf(errstr, (2 * MAXERROR),
3442 			gettext(
3443 			"Attribute nisMapName is mapped to an "
3444 			"empty string.\n"));
3445 
3446 		MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX,
3447 			strdup(errstr), NULL);
3448 
3449 		return (NS_LDAP_CONFIG);
3450 	}
3451 
3452 	/*
3453 	 * Locate the mapped attribute in the dn
3454 	 * and replace it if it exists
3455 	 */
3456 
3457 	rc = __s_api_replace_mapped_attr_in_dn(
3458 		(const char *) automountmapname, (const char *) mapped_attr,
3459 		(const char *) *dn, &buffer);
3460 
3461 	/* clean up */
3462 
3463 	free(mapped_attr);
3464 
3465 	/*
3466 	 * If mapped attr is found(buffer != NULL)
3467 	 *	a new dn is returned
3468 	 * If no mapped attribute is in dn,
3469 	 *	return NS_LDAP_SUCCESS (no op)
3470 	 * If no memory,
3471 	 *	return NS_LDAP_MEMORY (no op)
3472 	 */
3473 
3474 	if (buffer != NULL) {
3475 		free(*dn);
3476 		*dn = buffer;
3477 	}
3478 
3479 	return (rc);
3480 }
3481 
3482 /*
3483  * If the mapped attr is found in the dn,
3484  * 	return NS_LDAP_SUCCESS and a new_dn.
3485  * If no mapped attr is found,
3486  * 	return NS_LDAP_SUCCESS and *new_dn == NULL
3487  * If there is not enough memory,
3488  * 	return NS_LDAP_MEMORY and *new_dn == NULL
3489  */
3490 
3491 int
3492 __s_api_replace_mapped_attr_in_dn(
3493 	const char *orig_attr, const char *mapped_attr,
3494 	const char *dn, char **new_dn) {
3495 
3496 	char	**dnArray = NULL;
3497 	char	*cur = NULL, *start = NULL;
3498 	int	i = 0, found = 0;
3499 	int	len = 0, orig_len = 0, mapped_len = 0;
3500 	int	dn_len = 0, tmp_len = 0;
3501 
3502 	*new_dn = NULL;
3503 
3504 	/*
3505 	 * seperate dn into individual componets
3506 	 * e.g.
3507 	 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
3508 	 */
3509 	dnArray = ldap_explode_dn(dn, 0);
3510 
3511 	/*
3512 	 * This will find "mapped attr=value" in dn.
3513 	 * It won't find match if mapped attr appears
3514 	 * in the value.
3515 	 */
3516 	for (i = 0; dnArray[i] != NULL; i++) {
3517 		/*
3518 		 * This function is called when reading from
3519 		 * the directory so assume each component has "=".
3520 		 * Any ill formatted dn should be rejected
3521 		 * before adding to the directory
3522 		 */
3523 		cur = strchr(dnArray[i], '=');
3524 		*cur = '\0';
3525 		if (strcasecmp(mapped_attr, dnArray[i]) == 0)
3526 			found = 1;
3527 		*cur = '=';
3528 		if (found) break;
3529 	}
3530 
3531 	if (!found) {
3532 		__s_api_free2dArray(dnArray);
3533 		*new_dn = NULL;
3534 		return (NS_LDAP_SUCCESS);
3535 	}
3536 	/*
3537 	 * The new length is *dn length + (difference between
3538 	 * orig attr and mapped attr) + 1 ;
3539 	 * e.g.
3540 	 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
3541 	 * ==>
3542 	 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
3543 	 */
3544 	mapped_len = strlen(mapped_attr);
3545 	orig_len = strlen(orig_attr);
3546 	dn_len = strlen(dn);
3547 	len = dn_len + orig_len - mapped_len + 1;
3548 	*new_dn = (char *)calloc(1, len);
3549 	if (*new_dn == NULL) {
3550 		__s_api_free2dArray(dnArray);
3551 		return (NS_LDAP_MEMORY);
3552 	}
3553 
3554 	/*
3555 	 * Locate the mapped attr in the dn.
3556 	 * Use dnArray[i] instead of mapped_attr
3557 	 * because mapped_attr could appear in
3558 	 * the value
3559 	 */
3560 
3561 	cur = strstr(dn, dnArray[i]);
3562 	__s_api_free2dArray(dnArray);
3563 	/* copy the portion before mapped attr in dn  */
3564 	start = *new_dn;
3565 	tmp_len = cur - dn;
3566 	(void) memcpy((void *) start, (const void*) dn, tmp_len);
3567 
3568 	/*
3569 	 * Copy the orig_attr. e.g. automountMapName
3570 	 * This replaces mapped attr with orig attr
3571 	 */
3572 	start = start + (cur - dn); /* move cursor in buffer */
3573 	(void) memcpy((void *) start, (const void*) orig_attr, orig_len);
3574 
3575 	/*
3576 	 * Copy the portion after mapped attr in dn
3577 	 */
3578 	cur = cur + mapped_len; /* move cursor in  dn  */
3579 	start = start + orig_len; /* move cursor in buffer */
3580 	(void) strcpy(start, cur);
3581 
3582 	return (NS_LDAP_SUCCESS);
3583 }
3584 
3585 /*
3586  * Validate Filter functions
3587  */
3588 
3589 /* ***** Start of modified libldap.so.5 filter parser ***** */
3590 
3591 /* filter parsing routine forward references */
3592 static int adj_filter_list(char *str);
3593 static int adj_simple_filter(char *str);
3594 static int unescape_filterval(char *val);
3595 static int hexchar2int(char c);
3596 static int adj_substring_filter(char *val);
3597 
3598 
3599 /*
3600  * assumes string manipulation is in-line
3601  * and all strings are sufficient in size
3602  * return value is the position after 'c'
3603  */
3604 
3605 static char *
3606 resync_str(char *str, char *next, char c)
3607 {
3608 	char	*ret;
3609 
3610 	ret = str + strlen(str);
3611 	*next = c;
3612 	if (ret == next)
3613 		return (ret);
3614 	(void) strcat(str, next);
3615 	return (ret);
3616 }
3617 
3618 static char *
3619 find_right_paren(char *s)
3620 {
3621 	int	balance, escape;
3622 
3623 	balance = 1;
3624 	escape = 0;
3625 	while (*s && balance) {
3626 		if (escape == 0) {
3627 			if (*s == '(')
3628 				balance++;
3629 			else if (*s == ')')
3630 				balance--;
3631 		}
3632 		if (*s == '\\' && ! escape)
3633 			escape = 1;
3634 		else
3635 			escape = 0;
3636 		if (balance)
3637 			s++;
3638 	}
3639 
3640 	return (*s ? s : NULL);
3641 }
3642 
3643 static char *
3644 adj_complex_filter(char	*str)
3645 {
3646 	char	*next;
3647 
3648 	/*
3649 	 * We have (x(filter)...) with str sitting on
3650 	 * the x.  We have to find the paren matching
3651 	 * the one before the x and put the intervening
3652 	 * filters by calling adj_filter_list().
3653 	 */
3654 
3655 	str++;
3656 	if ((next = find_right_paren(str)) == NULL)
3657 		return (NULL);
3658 
3659 	*next = '\0';
3660 	if (adj_filter_list(str) == -1)
3661 		return (NULL);
3662 	next = resync_str(str, next, ')');
3663 	next++;
3664 
3665 	return (next);
3666 }
3667 
3668 static int
3669 adj_filter(char *str)
3670 {
3671 	char	*next;
3672 	int	parens, balance, escape;
3673 	char	*np, *cp,  *dp;
3674 
3675 	parens = 0;
3676 	while (*str) {
3677 		switch (*str) {
3678 		case '(':
3679 			str++;
3680 			parens++;
3681 			switch (*str) {
3682 			case '&':
3683 				if ((str = adj_complex_filter(str)) == NULL)
3684 					return (-1);
3685 
3686 				parens--;
3687 				break;
3688 
3689 			case '|':
3690 				if ((str = adj_complex_filter(str)) == NULL)
3691 					return (-1);
3692 
3693 				parens--;
3694 				break;
3695 
3696 			case '!':
3697 				if ((str = adj_complex_filter(str)) == NULL)
3698 					return (-1);
3699 
3700 				parens--;
3701 				break;
3702 
3703 			case '(':
3704 				/* illegal ((case - generated by conversion */
3705 
3706 				/* find missing close) */
3707 				np = find_right_paren(str+1);
3708 
3709 				/* error if not found */
3710 				if (np == NULL)
3711 					return (-1);
3712 
3713 				/* remove redundant (and) */
3714 				for (dp = str, cp = str+1; cp < np; ) {
3715 					*dp++ = *cp++;
3716 				}
3717 				cp++;
3718 				while (*cp)
3719 					*dp++ = *cp++;
3720 				*dp = '\0';
3721 
3722 				/* re-start test at original ( */
3723 				parens--;
3724 				str--;
3725 				break;
3726 
3727 			default:
3728 				balance = 1;
3729 				escape = 0;
3730 				next = str;
3731 				while (*next && balance) {
3732 					if (escape == 0) {
3733 						if (*next == '(')
3734 							balance++;
3735 						else if (*next == ')')
3736 							balance--;
3737 					}
3738 					if (*next == '\\' && ! escape)
3739 						escape = 1;
3740 					else
3741 						escape = 0;
3742 					if (balance)
3743 						next++;
3744 				}
3745 				if (balance != 0)
3746 					return (-1);
3747 
3748 				*next = '\0';
3749 				if (adj_simple_filter(str) == -1) {
3750 					return (-1);
3751 				}
3752 				next = resync_str(str, next, ')');
3753 				next++;
3754 				str = next;
3755 				parens--;
3756 				break;
3757 			}
3758 			break;
3759 
3760 		case ')':
3761 			str++;
3762 			parens--;
3763 			break;
3764 
3765 		case ' ':
3766 			str++;
3767 			break;
3768 
3769 		default:	/* assume it's a simple type=value filter */
3770 			next = strchr(str, '\0');
3771 			if (adj_simple_filter(str) == -1) {
3772 				return (-1);
3773 			}
3774 			str = next;
3775 			break;
3776 		}
3777 	}
3778 
3779 	return (parens ? -1 : 0);
3780 }
3781 
3782 
3783 /*
3784  * Put a list of filters like this "(filter1)(filter2)..."
3785  */
3786 
3787 static int
3788 adj_filter_list(char *str)
3789 {
3790 	char	*next;
3791 	char	save;
3792 
3793 	while (*str) {
3794 		while (*str && isspace(*str))
3795 			str++;
3796 		if (*str == '\0')
3797 			break;
3798 
3799 		if ((next = find_right_paren(str + 1)) == NULL)
3800 			return (-1);
3801 		save = *++next;
3802 
3803 		/* now we have "(filter)" with str pointing to it */
3804 		*next = '\0';
3805 		if (adj_filter(str) == -1)
3806 			return (-1);
3807 		next = resync_str(str, next, save);
3808 
3809 		str = next;
3810 	}
3811 
3812 	return (0);
3813 }
3814 
3815 
3816 /*
3817  * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
3818  * of a filter expression, 0 otherwise.  A valid string may contain only
3819  * letters, numbers, hyphens, semi-colons, colons and periods. examples:
3820  *	cn
3821  *	cn;lang-fr
3822  *	1.2.3.4;binary;dynamic
3823  *	mail;dynamic
3824  *	cn:dn:1.2.3.4
3825  *
3826  * For compatibility with older servers, we also allow underscores in
3827  * attribute types, even through they are not allowed by the LDAPv3 RFCs.
3828  */
3829 static int
3830 is_valid_attr(char *a)
3831 {
3832 	for (; *a; a++) {
3833 		if (!isascii(*a)) {
3834 			return (0);
3835 		} else if (!isalnum(*a)) {
3836 			switch (*a) {
3837 			case '-':
3838 			case '.':
3839 			case ';':
3840 			case ':':
3841 			case '_':
3842 				break; /* valid */
3843 			default:
3844 				return (0);
3845 			}
3846 		}
3847 	}
3848 	return (1);
3849 }
3850 
3851 static char *
3852 find_star(char *s)
3853 {
3854 	for (; *s; ++s) {
3855 		switch (*s) {
3856 		case '*':
3857 			return (s);
3858 		case '\\':
3859 			++s;
3860 			if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0)
3861 				++s;
3862 		default:
3863 			break;
3864 		}
3865 	}
3866 	return (NULL);
3867 }
3868 
3869 static int
3870 adj_simple_filter(char *str)
3871 {
3872 	char		*s, *s2, *s3, filterop;
3873 	char		*value;
3874 	int		ftype = 0;
3875 	int		rc;
3876 
3877 	rc = -1;	/* pessimistic */
3878 
3879 	if ((str = strdup(str)) == NULL) {
3880 		return (rc);
3881 	}
3882 
3883 	if ((s = strchr(str, '=')) == NULL) {
3884 		goto free_and_return;
3885 	}
3886 	value = s + 1;
3887 	*s-- = '\0';
3888 	filterop = *s;
3889 	if (filterop == '<' || filterop == '>' || filterop == '~' ||
3890 	    filterop == ':') {
3891 		*s = '\0';
3892 	}
3893 
3894 	if (! is_valid_attr(str)) {
3895 		goto free_and_return;
3896 	}
3897 
3898 	switch (filterop) {
3899 	case '<': /* LDAP_FILTER_LE */
3900 	case '>': /* LDAP_FILTER_GE */
3901 	case '~': /* LDAP_FILTER_APPROX */
3902 		break;
3903 	case ':':	/* extended filter - v3 only */
3904 		/*
3905 		 * extended filter looks like this:
3906 		 *
3907 		 *	[type][':dn'][':'oid]':='value
3908 		 *
3909 		 * where one of type or :oid is required.
3910 		 *
3911 		 */
3912 		s2 = s3 = NULL;
3913 		if ((s2 = strrchr(str, ':')) == NULL) {
3914 			goto free_and_return;
3915 		}
3916 		if (strcasecmp(s2, ":dn") == 0) {
3917 			*s2 = '\0';
3918 		} else {
3919 			*s2 = '\0';
3920 			if ((s3 = strrchr(str, ':')) != NULL) {
3921 				if (strcasecmp(s3, ":dn") != 0) {
3922 					goto free_and_return;
3923 				}
3924 				*s3 = '\0';
3925 			}
3926 		}
3927 		if (unescape_filterval(value) < 0) {
3928 			goto free_and_return;
3929 		}
3930 		rc = 0;
3931 		goto free_and_return;
3932 		/* break; */
3933 	default:
3934 		if (find_star(value) == NULL) {
3935 			ftype = 0; /* LDAP_FILTER_EQUALITY */
3936 		} else if (strcmp(value, "*") == 0) {
3937 			ftype = 1; /* LDAP_FILTER_PRESENT */
3938 		} else {
3939 			rc = adj_substring_filter(value);
3940 			goto free_and_return;
3941 		}
3942 		break;
3943 	}
3944 
3945 	if (ftype != 0) {	/* == LDAP_FILTER_PRESENT */
3946 		rc = 0;
3947 	} else if (unescape_filterval(value) >= 0) {
3948 		rc = 0;
3949 	}
3950 	if (rc != -1) {
3951 		rc = 0;
3952 	}
3953 
3954 free_and_return:
3955 	free(str);
3956 	return (rc);
3957 }
3958 
3959 
3960 /*
3961  * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
3962  * sequences within the null-terminated string 'val'.
3963  *
3964  * If 'val' contains invalid escape sequences we return -1.
3965  * Otherwise return 1
3966  */
3967 static int
3968 unescape_filterval(char *val)
3969 {
3970 	int	escape, firstdigit;
3971 	char	*s;
3972 
3973 	firstdigit = 0;
3974 	escape = 0;
3975 	for (s = val; *s; s++) {
3976 		if (escape) {
3977 			/*
3978 			 * first try LDAPv3 escape (hexadecimal) sequence
3979 			 */
3980 			if (hexchar2int(*s) < 0) {
3981 				if (firstdigit) {
3982 					/*
3983 					 * LDAPv2 (RFC1960) escape sequence
3984 					 */
3985 					escape = 0;
3986 				} else {
3987 					return (-1);
3988 				}
3989 			}
3990 			if (firstdigit) {
3991 			    firstdigit = 0;
3992 			} else {
3993 			    escape = 0;
3994 			}
3995 
3996 		} else if (*s != '\\') {
3997 			escape = 0;
3998 
3999 		} else {
4000 			escape = 1;
4001 			firstdigit = 1;
4002 		}
4003 	}
4004 
4005 	return (1);
4006 }
4007 
4008 
4009 /*
4010  * convert character 'c' that represents a hexadecimal digit to an integer.
4011  * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
4012  * otherwise the converted value is returned.
4013  */
4014 static int
4015 hexchar2int(char c)
4016 {
4017 	if (c >= '0' && c <= '9') {
4018 		return (c - '0');
4019 	}
4020 	if (c >= 'A' && c <= 'F') {
4021 		return (c - 'A' + 10);
4022 	}
4023 	if (c >= 'a' && c <= 'f') {
4024 		return (c - 'a' + 10);
4025 	}
4026 	return (-1);
4027 }
4028 
4029 static int
4030 adj_substring_filter(char *val)
4031 {
4032 	char		*nextstar;
4033 
4034 	for (; val != NULL; val = nextstar) {
4035 		if ((nextstar = find_star(val)) != NULL) {
4036 			*nextstar++ = '\0';
4037 		}
4038 
4039 		if (*val != '\0') {
4040 			if (unescape_filterval(val) < 0) {
4041 				return (-1);
4042 			}
4043 		}
4044 	}
4045 
4046 	return (0);
4047 }
4048 
4049 /* ***** End of modified libldap.so.5 filter parser ***** */
4050 
4051 
4052 /*
4053  * Walk filter, remove redundant parentheses in-line
4054  * verify that the filter is reasonable
4055  */
4056 static int
4057 validate_filter(ns_ldap_cookie_t *cookie)
4058 {
4059 	char			*filter = cookie->filter;
4060 	int			rc;
4061 
4062 	/* Parse filter looking for illegal values */
4063 
4064 	rc = adj_filter(filter);
4065 	if (rc != 0) {
4066 		return (NS_LDAP_OP_FAILED);
4067 	}
4068 
4069 	/* end of filter checking */
4070 
4071 	return (NS_LDAP_SUCCESS);
4072 }
4073