xref: /illumos-gate/usr/src/lib/libsldap/common/ns_reads.c (revision f5c3c7a74383e65508998376630a111f8872d807)
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 && ((flags & NS_LDAP_NOT_CVT_DN) == 0))
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, ret;
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 						ret = __s_api_removeServer(
2182 						    cookie->conn->serverAddr);
2183 						if (ret == NOSERVER &&
2184 						    cookie->conn_auth_type
2185 							== NS_LDAP_AUTH_NONE) {
2186 							/*
2187 							 * Couldn't remove
2188 							 * server from server
2189 							 * list.
2190 							 * Exit to avoid
2191 							 * potential infinite
2192 							 * loop.
2193 							 */
2194 							cookie->err_rc = rc;
2195 							cookie->new_state =
2196 							    LDAP_ERROR;
2197 						}
2198 						if (cookie->connectionId > -1) {
2199 						    DropConnection(
2200 							cookie->connectionId,
2201 							NS_LDAP_NEW_CONN);
2202 						    cookie->connectionId = -1;
2203 						}
2204 					}
2205 					break;
2206 				}
2207 				cookie->err_rc = rc;
2208 				cookie->new_state = LDAP_ERROR;
2209 				break;
2210 			}
2211 			cookie->new_state = cookie->next_state;
2212 			break;
2213 		case NEXT_RESULT:
2214 			rc = ldap_result(cookie->conn->ld, cookie->msgId,
2215 				LDAP_MSG_ONE,
2216 				(struct timeval *)&cookie->search_timeout,
2217 				&cookie->resultMsg);
2218 			if (rc == LDAP_RES_SEARCH_RESULT) {
2219 				cookie->new_state = END_RESULT;
2220 				/* check and process referrals info */
2221 				if (cookie->followRef)
2222 					proc_result_referrals(
2223 						cookie);
2224 				(void) ldap_msgfree(cookie->resultMsg);
2225 				cookie->resultMsg = NULL;
2226 				break;
2227 			}
2228 			/* handle referrals if necessary */
2229 			if (rc == LDAP_RES_SEARCH_REFERENCE) {
2230 				if (cookie->followRef)
2231 					proc_search_references(cookie);
2232 				(void) ldap_msgfree(cookie->resultMsg);
2233 				cookie->resultMsg = NULL;
2234 				break;
2235 			}
2236 			if (rc != LDAP_RES_SEARCH_ENTRY) {
2237 				switch (rc) {
2238 				case 0:
2239 					rc = LDAP_TIMEOUT;
2240 					break;
2241 				case -1:
2242 					rc = ldap_get_lderrno(cookie->conn->ld,
2243 						    NULL, NULL);
2244 					break;
2245 				default:
2246 					rc = ldap_result2error(cookie->conn->ld,
2247 						cookie->resultMsg, 1);
2248 					break;
2249 				}
2250 				(void) ldap_msgfree(cookie->resultMsg);
2251 				cookie->resultMsg = NULL;
2252 				if (rc == LDAP_BUSY ||
2253 				    rc == LDAP_UNAVAILABLE ||
2254 				    rc == LDAP_UNWILLING_TO_PERFORM ||
2255 				    rc == LDAP_SERVER_DOWN) {
2256 					cookie->new_state = NEXT_SESSION;
2257 					break;
2258 				}
2259 				cookie->err_rc = rc;
2260 				cookie->new_state = LDAP_ERROR;
2261 				break;
2262 			}
2263 			/* else LDAP_RES_SEARCH_ENTRY */
2264 			rc = __s_api_getEntry(cookie);
2265 			(void) ldap_msgfree(cookie->resultMsg);
2266 			cookie->resultMsg = NULL;
2267 			if (rc != NS_LDAP_SUCCESS) {
2268 				cookie->new_state = LDAP_ERROR;
2269 				break;
2270 			}
2271 			cookie->new_state = PROCESS_RESULT;
2272 			cookie->next_state = NEXT_RESULT;
2273 			break;
2274 		case MULTI_RESULT:
2275 			rc = ldap_result(cookie->conn->ld, cookie->msgId,
2276 				LDAP_MSG_ONE,
2277 				(struct timeval *)&cookie->search_timeout,
2278 				&cookie->resultMsg);
2279 			if (rc == LDAP_RES_SEARCH_RESULT) {
2280 				rc = ldap_result2error(cookie->conn->ld,
2281 					cookie->resultMsg, 0);
2282 				if (rc != LDAP_SUCCESS) {
2283 					cookie->err_rc = rc;
2284 					cookie->new_state = LDAP_ERROR;
2285 					(void) ldap_msgfree(cookie->resultMsg);
2286 					break;
2287 				}
2288 				cookie->new_state = multi_result(cookie);
2289 				(void) ldap_msgfree(cookie->resultMsg);
2290 				cookie->resultMsg = NULL;
2291 				break;
2292 			}
2293 			/* handle referrals if necessary */
2294 			if (rc == LDAP_RES_SEARCH_REFERENCE &&
2295 				cookie->followRef) {
2296 				proc_search_references(cookie);
2297 				(void) ldap_msgfree(cookie->resultMsg);
2298 				cookie->resultMsg = NULL;
2299 				break;
2300 			}
2301 			if (rc != LDAP_RES_SEARCH_ENTRY) {
2302 				switch (rc) {
2303 				case 0:
2304 					rc = LDAP_TIMEOUT;
2305 					break;
2306 				case -1:
2307 					rc = ldap_get_lderrno(cookie->conn->ld,
2308 						    NULL, NULL);
2309 					break;
2310 				default:
2311 					rc = ldap_result2error(cookie->conn->ld,
2312 						cookie->resultMsg, 1);
2313 					break;
2314 				}
2315 				(void) ldap_msgfree(cookie->resultMsg);
2316 				cookie->resultMsg = NULL;
2317 				if (rc == LDAP_BUSY ||
2318 				    rc == LDAP_UNAVAILABLE ||
2319 				    rc == LDAP_UNWILLING_TO_PERFORM ||
2320 				    rc == LDAP_SERVER_DOWN) {
2321 					cookie->new_state = NEXT_SESSION;
2322 					break;
2323 				}
2324 				cookie->err_rc = rc;
2325 				cookie->new_state = LDAP_ERROR;
2326 				break;
2327 			}
2328 			/* else LDAP_RES_SEARCH_ENTRY */
2329 			rc = __s_api_getEntry(cookie);
2330 			(void) ldap_msgfree(cookie->resultMsg);
2331 			cookie->resultMsg = NULL;
2332 			if (rc != NS_LDAP_SUCCESS) {
2333 				cookie->new_state = LDAP_ERROR;
2334 				break;
2335 			}
2336 			cookie->new_state = PROCESS_RESULT;
2337 			cookie->next_state = MULTI_RESULT;
2338 			break;
2339 		case PROCESS_RESULT:
2340 			/* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
2341 			if (cookie->use_usercb && cookie->callback) {
2342 				rc = 0;
2343 				for (nextEntry = cookie->result->entry;
2344 					nextEntry != NULL;
2345 					nextEntry = nextEntry->next) {
2346 					rc = (*cookie->callback)(nextEntry,
2347 						cookie->userdata);
2348 
2349 					if (rc == NS_LDAP_CB_DONE) {
2350 					/* cb doesn't want any more data */
2351 						rc = NS_LDAP_PARTIAL;
2352 						cookie->err_rc = rc;
2353 						break;
2354 					} else if (rc != NS_LDAP_CB_NEXT) {
2355 					/* invalid return code */
2356 						rc = NS_LDAP_OP_FAILED;
2357 						cookie->err_rc = rc;
2358 						break;
2359 					}
2360 				}
2361 				(void) __ns_ldap_freeResult(&cookie->result);
2362 				cookie->result = NULL;
2363 			}
2364 			if (rc != 0) {
2365 				cookie->new_state = EXIT;
2366 				break;
2367 			}
2368 			/* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
2369 			cookie->new_state = cookie->next_state;
2370 			break;
2371 		case END_PROCESS_RESULT:
2372 			cookie->new_state = cookie->next_state;
2373 			break;
2374 		case END_RESULT:
2375 			/*
2376 			 * XXX DO WE NEED THIS CASE?
2377 			 * if (search is complete) {
2378 			 * 	cookie->new_state = EXIT;
2379 			 * } else
2380 			 */
2381 				/*
2382 				 * entering referral mode if necessary
2383 				 */
2384 				if (cookie->followRef && cookie->reflist)
2385 					cookie->new_state =
2386 						NEXT_REFERRAL;
2387 				else
2388 					cookie->new_state =
2389 						NEXT_SEARCH_DESCRIPTOR;
2390 			break;
2391 		case NEXT_REFERRAL:
2392 			/* get next referral info */
2393 			if (cookie->refpos == NULL)
2394 				cookie->refpos =
2395 					cookie->reflist;
2396 			else
2397 				cookie->refpos =
2398 					cookie->refpos->next;
2399 			/* check see if done with all referrals */
2400 			if (cookie->refpos != NULL)
2401 				cookie->new_state =
2402 					GET_REFERRAL_SESSION;
2403 			else {
2404 				__s_api_deleteRefInfo(cookie->reflist);
2405 				cookie->reflist = NULL;
2406 				cookie->new_state =
2407 					NEXT_SEARCH_DESCRIPTOR;
2408 			}
2409 			break;
2410 		case GET_REFERRAL_SESSION:
2411 			if (get_referral_session(cookie) < 0)
2412 				cookie->new_state = EXIT;
2413 			else {
2414 				cookie->new_state = NEXT_SEARCH;
2415 			}
2416 			break;
2417 		case LDAP_ERROR:
2418 			(void) sprintf(errstr,
2419 				gettext("LDAP ERROR (%d): %s."),
2420 				cookie->err_rc,
2421 				ldap_err2string(cookie->err_rc));
2422 			err = strdup(errstr);
2423 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2424 			NULL);
2425 			cookie->err_rc = NS_LDAP_INTERNAL;
2426 			cookie->errorp = *errorp;
2427 			return (ERROR);
2428 		default:
2429 		case ERROR:
2430 			(void) sprintf(errstr,
2431 				gettext("Internal State machine exit (%d).\n"),
2432 				cookie->state);
2433 			err = strdup(errstr);
2434 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2435 			NULL);
2436 			cookie->err_rc = NS_LDAP_INTERNAL;
2437 			cookie->errorp = *errorp;
2438 			return (ERROR);
2439 		}
2440 
2441 		if (cycle == ONE_STEP) {
2442 			return (cookie->new_state);
2443 		}
2444 		cookie->state = cookie->new_state;
2445 	}
2446 	/*NOTREACHED*/
2447 #if 0
2448 	(void) sprintf(errstr,
2449 		gettext("Unexpected State machine error.\n"));
2450 	err = strdup(errstr);
2451 	MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NULL);
2452 	cookie->err_rc = NS_LDAP_INTERNAL;
2453 	cookie->errorp = *errorp;
2454 	return (ERROR);
2455 #endif
2456 }
2457 
2458 
2459 
2460 /*
2461  * __ns_ldap_list performs one or more LDAP searches to a given
2462  * directory server using service search descriptors and schema
2463  * mapping as appropriate.
2464  */
2465 
2466 int
2467 __ns_ldap_list(
2468 	const char *service,
2469 	const char *filter,
2470 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2471 	char **realfilter, const void *userdata),
2472 	const char * const *attribute,
2473 	const ns_cred_t *auth,
2474 	const int flags,
2475 	ns_ldap_result_t **rResult, /* return result entries */
2476 	ns_ldap_error_t **errorp,
2477 	int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
2478 	const void *userdata)
2479 {
2480 	ns_ldap_cookie_t	*cookie;
2481 	ns_ldap_search_desc_t	**sdlist = NULL;
2482 	ns_ldap_search_desc_t	*dptr;
2483 	ns_ldap_error_t		*error = NULL;
2484 	char			**dns = NULL;
2485 	int			scope;
2486 	int			rc;
2487 
2488 	*errorp = NULL;
2489 
2490 	/* Initialize State machine cookie */
2491 	cookie = init_search_state_machine();
2492 	if (cookie == NULL) {
2493 		return (NS_LDAP_MEMORY);
2494 	}
2495 
2496 	/* see if need to follow referrals */
2497 	rc = __s_api_toFollowReferrals(flags,
2498 		&cookie->followRef, errorp);
2499 	if (rc != NS_LDAP_SUCCESS) {
2500 		delete_search_cookie(cookie);
2501 		return (rc);
2502 	}
2503 
2504 	/* get the service descriptor - or create a default one */
2505 	rc = __s_api_get_SSD_from_SSDtoUse_service(service,
2506 		&sdlist, errorp);
2507 	if (rc != NS_LDAP_SUCCESS) {
2508 		delete_search_cookie(cookie);
2509 		*errorp = error;
2510 		return (rc);
2511 	}
2512 
2513 	if (sdlist == NULL) {
2514 		/* Create default service Desc */
2515 		sdlist = (ns_ldap_search_desc_t **)calloc(2,
2516 					sizeof (ns_ldap_search_desc_t *));
2517 		if (sdlist == NULL) {
2518 			delete_search_cookie(cookie);
2519 			cookie = NULL;
2520 			return (NS_LDAP_MEMORY);
2521 		}
2522 		dptr = (ns_ldap_search_desc_t *)
2523 				calloc(1, sizeof (ns_ldap_search_desc_t));
2524 		if (dptr == NULL) {
2525 			free(sdlist);
2526 			delete_search_cookie(cookie);
2527 			cookie = NULL;
2528 			return (NS_LDAP_MEMORY);
2529 		}
2530 		sdlist[0] = dptr;
2531 
2532 		/* default base */
2533 		rc = __s_api_getDNs(&dns, service, &cookie->errorp);
2534 		if (rc != NS_LDAP_SUCCESS) {
2535 			if (dns) {
2536 				__s_api_free2dArray(dns);
2537 				dns = NULL;
2538 			}
2539 			*errorp = cookie->errorp;
2540 			cookie->errorp = NULL;
2541 			delete_search_cookie(cookie);
2542 			cookie = NULL;
2543 			return (rc);
2544 		}
2545 		dptr->basedn = strdup(dns[0]);
2546 		__s_api_free2dArray(dns);
2547 		dns = NULL;
2548 
2549 		/* default scope */
2550 		scope = 0;
2551 		rc = __s_api_getSearchScope(&scope, &cookie->errorp);
2552 		dptr->scope = scope;
2553 	}
2554 
2555 	cookie->sdlist = sdlist;
2556 
2557 	/*
2558 	 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
2559 	 */
2560 	if (flags & NS_LDAP_PAGE_CTRL)
2561 		cookie->use_paging = TRUE;
2562 	else
2563 		cookie->use_paging = FALSE;
2564 
2565 	/* Set up other arguments */
2566 	cookie->userdata = userdata;
2567 	if (init_filter_cb != NULL) {
2568 		cookie->init_filter_cb = init_filter_cb;
2569 		cookie->use_filtercb = 1;
2570 	}
2571 	if (callback != NULL) {
2572 		cookie->callback = callback;
2573 		cookie->use_usercb = 1;
2574 	}
2575 	if (service) {
2576 		cookie->service = strdup(service);
2577 		if (cookie->service == NULL) {
2578 			delete_search_cookie(cookie);
2579 			cookie = NULL;
2580 			return (NS_LDAP_MEMORY);
2581 		}
2582 	}
2583 
2584 	cookie->i_filter = strdup(filter);
2585 	cookie->i_attr = attribute;
2586 	cookie->i_auth = auth;
2587 	cookie->i_flags = flags;
2588 
2589 	/* Process search */
2590 	rc = search_state_machine(cookie, INIT, 0);
2591 
2592 	/* Copy results back to user */
2593 	rc = cookie->err_rc;
2594 	if (rc != NS_LDAP_SUCCESS)
2595 		*errorp = cookie->errorp;
2596 	*rResult = cookie->result;
2597 
2598 	cookie->errorp = NULL;
2599 	cookie->result = NULL;
2600 	delete_search_cookie(cookie);
2601 	cookie = NULL;
2602 
2603 	if (*rResult == NULL)
2604 		rc = NS_LDAP_NOTFOUND;
2605 	return (rc);
2606 }
2607 
2608 /*
2609  * __s_api_find_domainname performs one or more LDAP searches to
2610  * find the value of the nisdomain attribute associated with
2611  * the input DN
2612  */
2613 
2614 static int
2615 __s_api_find_domainname(
2616 	const char *dn,
2617 	char **domainname,
2618 	const ns_cred_t *cred,
2619 	ns_ldap_error_t **errorp)
2620 {
2621 
2622 	ns_ldap_cookie_t	*cookie;
2623 	ns_ldap_search_desc_t	**sdlist;
2624 	ns_ldap_search_desc_t	*dptr;
2625 	int			rc;
2626 	char			**value;
2627 	int			flags = 0;
2628 
2629 	*domainname = NULL;
2630 	*errorp = NULL;
2631 
2632 	/* Initialize State machine cookie */
2633 	cookie = init_search_state_machine();
2634 	if (cookie == NULL) {
2635 		return (NS_LDAP_MEMORY);
2636 	}
2637 
2638 	/* see if need to follow referrals */
2639 	rc = __s_api_toFollowReferrals(flags,
2640 		&cookie->followRef, errorp);
2641 	if (rc != NS_LDAP_SUCCESS) {
2642 		delete_search_cookie(cookie);
2643 		return (rc);
2644 	}
2645 
2646 	/* Create default service Desc */
2647 	sdlist = (ns_ldap_search_desc_t **)calloc(2,
2648 				sizeof (ns_ldap_search_desc_t *));
2649 	if (sdlist == NULL) {
2650 		delete_search_cookie(cookie);
2651 		cookie = NULL;
2652 		return (NS_LDAP_MEMORY);
2653 	}
2654 	dptr = (ns_ldap_search_desc_t *)
2655 			calloc(1, sizeof (ns_ldap_search_desc_t));
2656 	if (dptr == NULL) {
2657 		free(sdlist);
2658 		delete_search_cookie(cookie);
2659 		cookie = NULL;
2660 		return (NS_LDAP_MEMORY);
2661 	}
2662 	sdlist[0] = dptr;
2663 
2664 	/* search base is dn */
2665 	dptr->basedn = strdup(dn);
2666 
2667 	/* search scope is base */
2668 	dptr->scope = NS_LDAP_SCOPE_BASE;
2669 
2670 	/* search filter is "nisdomain=*" */
2671 	dptr->filter = strdup(_NIS_FILTER);
2672 
2673 	cookie->sdlist = sdlist;
2674 	cookie->i_filter = strdup(dptr->filter);
2675 	cookie->i_attr = nis_domain_attrs;
2676 	cookie->i_auth = cred;
2677 	cookie->i_flags = 0;
2678 
2679 	/* Process search */
2680 	rc = search_state_machine(cookie, INIT, 0);
2681 
2682 	/* Copy domain name if found */
2683 	rc = cookie->err_rc;
2684 	if (rc != NS_LDAP_SUCCESS)
2685 		*errorp = cookie->errorp;
2686 	if (cookie->result == NULL)
2687 		rc = NS_LDAP_NOTFOUND;
2688 	if (rc == NS_LDAP_SUCCESS) {
2689 		value = __ns_ldap_getAttr(cookie->result->entry,
2690 			_NIS_DOMAIN);
2691 		if (value[0])
2692 			*domainname = strdup(value[0]);
2693 		else
2694 			rc = NS_LDAP_NOTFOUND;
2695 	}
2696 	if (cookie->result != NULL)
2697 		(void) __ns_ldap_freeResult(&cookie->result);
2698 	cookie->errorp = NULL;
2699 	delete_search_cookie(cookie);
2700 	cookie = NULL;
2701 	return (rc);
2702 }
2703 
2704 int
2705 __ns_ldap_firstEntry(
2706 	const char *service,
2707 	const char *filter,
2708 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
2709 	char **realfilter, const void *userdata),
2710 	const char * const *attribute,
2711 	const ns_cred_t *auth,
2712 	const int flags,
2713 	void **vcookie,
2714 	ns_ldap_result_t **result,
2715 	ns_ldap_error_t ** errorp,
2716 	const void *userdata)
2717 {
2718 	ns_ldap_cookie_t	*cookie = NULL;
2719 	ns_ldap_error_t		*error = NULL;
2720 	ns_state_t		state;
2721 	ns_ldap_search_desc_t	**sdlist;
2722 	ns_ldap_search_desc_t	*dptr;
2723 	char			**dns = NULL;
2724 	int			scope;
2725 	int			rc;
2726 
2727 	*errorp = NULL;
2728 	*result = NULL;
2729 
2730 	/* get the service descriptor - or create a default one */
2731 	rc = __s_api_get_SSD_from_SSDtoUse_service(service,
2732 			&sdlist, errorp);
2733 	if (rc != NS_LDAP_SUCCESS) {
2734 		*errorp = error;
2735 		return (rc);
2736 	}
2737 	if (sdlist == NULL) {
2738 		/* Create default service Desc */
2739 		sdlist = (ns_ldap_search_desc_t **)calloc(2,
2740 					sizeof (ns_ldap_search_desc_t *));
2741 		if (sdlist == NULL) {
2742 			return (NS_LDAP_MEMORY);
2743 		}
2744 		dptr = (ns_ldap_search_desc_t *)
2745 				calloc(1, sizeof (ns_ldap_search_desc_t));
2746 		if (dptr == NULL) {
2747 			free(sdlist);
2748 			return (NS_LDAP_MEMORY);
2749 		}
2750 		sdlist[0] = dptr;
2751 
2752 		/* default base */
2753 		rc = __s_api_getDNs(&dns, service, &error);
2754 		if (rc != NS_LDAP_SUCCESS) {
2755 			if (dns) {
2756 				__s_api_free2dArray(dns);
2757 				dns = NULL;
2758 			}
2759 			if (sdlist) {
2760 				(void) __ns_ldap_freeSearchDescriptors(
2761 					&sdlist);
2762 
2763 				sdlist = NULL;
2764 			}
2765 			*errorp = error;
2766 			return (rc);
2767 		}
2768 		dptr->basedn = strdup(dns[0]);
2769 		__s_api_free2dArray(dns);
2770 		dns = NULL;
2771 
2772 		/* default scope */
2773 		scope = 0;
2774 		cookie = init_search_state_machine();
2775 		if (cookie == NULL) {
2776 			if (sdlist) {
2777 				(void) __ns_ldap_freeSearchDescriptors(&sdlist);
2778 				sdlist = NULL;
2779 			}
2780 			return (NS_LDAP_MEMORY);
2781 		}
2782 		rc = __s_api_getSearchScope(&scope, &cookie->errorp);
2783 		dptr->scope = scope;
2784 	}
2785 
2786 	/* Initialize State machine cookie */
2787 	if (cookie == NULL)
2788 		cookie = init_search_state_machine();
2789 	if (cookie == NULL) {
2790 		if (sdlist) {
2791 			(void) __ns_ldap_freeSearchDescriptors(&sdlist);
2792 			sdlist = NULL;
2793 		}
2794 		return (NS_LDAP_MEMORY);
2795 	}
2796 
2797 	cookie->sdlist = sdlist;
2798 
2799 	/* see if need to follow referrals */
2800 	rc = __s_api_toFollowReferrals(flags,
2801 		&cookie->followRef, errorp);
2802 	if (rc != NS_LDAP_SUCCESS) {
2803 		delete_search_cookie(cookie);
2804 		return (rc);
2805 	}
2806 
2807 	/*
2808 	 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
2809 	 */
2810 	if (flags & NS_LDAP_NO_PAGE_CTRL)
2811 		cookie->use_paging = FALSE;
2812 	else
2813 		cookie->use_paging = TRUE;
2814 
2815 	/* Set up other arguments */
2816 	cookie->userdata = userdata;
2817 	if (init_filter_cb != NULL) {
2818 		cookie->init_filter_cb = init_filter_cb;
2819 		cookie->use_filtercb = 1;
2820 	}
2821 	cookie->use_usercb = 0;
2822 	if (service) {
2823 		cookie->service = strdup(service);
2824 		if (cookie->service == NULL) {
2825 			delete_search_cookie(cookie);
2826 			return (NS_LDAP_MEMORY);
2827 		}
2828 	}
2829 
2830 	cookie->i_filter = strdup(filter);
2831 	cookie->i_attr = attribute;
2832 	cookie->i_auth = auth;
2833 	cookie->i_flags = flags;
2834 
2835 	state = INIT;
2836 	for (;;) {
2837 		state = search_state_machine(cookie, state, ONE_STEP);
2838 		switch (state) {
2839 		case PROCESS_RESULT:
2840 			*result = cookie->result;
2841 			cookie->result = NULL;
2842 			*vcookie = (void *)cookie;
2843 			return (NS_LDAP_SUCCESS);
2844 		case ERROR:
2845 		case LDAP_ERROR:
2846 			rc = cookie->err_rc;
2847 			*errorp = cookie->errorp;
2848 			cookie->errorp = NULL;
2849 			delete_search_cookie(cookie);
2850 			return (rc);
2851 		case EXIT:
2852 			rc = cookie->err_rc;
2853 			if (rc != NS_LDAP_SUCCESS) {
2854 				*errorp = cookie->errorp;
2855 				cookie->errorp = NULL;
2856 			} else {
2857 				rc = NS_LDAP_NOTFOUND;
2858 			}
2859 
2860 			delete_search_cookie(cookie);
2861 			return (rc);
2862 
2863 		default:
2864 			break;
2865 		}
2866 	}
2867 }
2868 
2869 /*ARGSUSED2*/
2870 int
2871 __ns_ldap_nextEntry(
2872 	void *vcookie,
2873 	ns_ldap_result_t **result,
2874 	ns_ldap_error_t ** errorp)
2875 {
2876 	ns_ldap_cookie_t	*cookie;
2877 	ns_state_t		state;
2878 	int			rc;
2879 
2880 	cookie = (ns_ldap_cookie_t *)vcookie;
2881 	cookie->result = NULL;
2882 	*result = NULL;
2883 
2884 	state = END_PROCESS_RESULT;
2885 	for (;;) {
2886 		state = search_state_machine(cookie, state, ONE_STEP);
2887 		switch (state) {
2888 		case PROCESS_RESULT:
2889 			*result = cookie->result;
2890 			cookie->result = NULL;
2891 			return (NS_LDAP_SUCCESS);
2892 		case ERROR:
2893 		case LDAP_ERROR:
2894 			rc = cookie->err_rc;
2895 			*errorp = cookie->errorp;
2896 			cookie->errorp = NULL;
2897 			return (rc);
2898 		case EXIT:
2899 			return (NS_LDAP_SUCCESS);
2900 		}
2901 	}
2902 }
2903 
2904 int
2905 __ns_ldap_endEntry(
2906 	void **vcookie,
2907 	ns_ldap_error_t ** errorp)
2908 {
2909 	ns_ldap_cookie_t	*cookie;
2910 	int			rc;
2911 
2912 	if (*vcookie == NULL)
2913 		return (NS_LDAP_INVALID_PARAM);
2914 
2915 	cookie = (ns_ldap_cookie_t *)(*vcookie);
2916 	cookie->result = NULL;
2917 
2918 	/* Complete search */
2919 	rc = search_state_machine(cookie, EXIT, 0);
2920 
2921 	/* Copy results back to user */
2922 	rc = cookie->err_rc;
2923 	if (rc != NS_LDAP_SUCCESS)
2924 		*errorp = cookie->errorp;
2925 
2926 	cookie->errorp = NULL;
2927 	delete_search_cookie(cookie);
2928 	cookie = NULL;
2929 	*vcookie = NULL;
2930 
2931 	return (rc);
2932 }
2933 
2934 
2935 int
2936 __ns_ldap_freeResult(ns_ldap_result_t **result)
2937 {
2938 
2939 	ns_ldap_entry_t	*curEntry = NULL;
2940 	ns_ldap_entry_t	*delEntry = NULL;
2941 	int		i;
2942 	ns_ldap_result_t	*res = *result;
2943 
2944 #ifdef DEBUG
2945 	(void) fprintf(stderr, "__ns_ldap_freeResult START\n");
2946 #endif
2947 	if (res == NULL)
2948 		return (NS_LDAP_INVALID_PARAM);
2949 
2950 	if (res->entry != NULL)
2951 		curEntry = res->entry;
2952 
2953 	for (i = 0; i < res->entries_count; i++) {
2954 		if (curEntry != NULL) {
2955 			delEntry = curEntry;
2956 			curEntry = curEntry->next;
2957 			__ns_ldap_freeEntry(delEntry);
2958 		}
2959 	}
2960 
2961 	free(res);
2962 	*result = NULL;
2963 	return (NS_LDAP_SUCCESS);
2964 }
2965 
2966 /*ARGSUSED*/
2967 int
2968 __ns_ldap_auth(const ns_cred_t *auth,
2969 		    const int flags,
2970 		    ns_ldap_error_t **errorp,
2971 		    LDAPControl **serverctrls,
2972 		    LDAPControl **clientctrls)
2973 {
2974 
2975 	ConnectionID	connectionId = -1;
2976 	Connection	*conp;
2977 	int		rc = 0;
2978 	int		do_not_fail_if_new_pwd_reqd = 0;
2979 
2980 
2981 #ifdef DEBUG
2982 	(void) fprintf(stderr, "__ns_ldap_auth START\n");
2983 #endif
2984 
2985 	*errorp = NULL;
2986 	if (!auth)
2987 		return (NS_LDAP_INVALID_PARAM);
2988 
2989 	rc = __s_api_getConnection(NULL, flags,
2990 			auth, &connectionId, &conp, errorp,
2991 			do_not_fail_if_new_pwd_reqd);
2992 	if (rc == NS_LDAP_OP_FAILED && *errorp)
2993 		(void) __ns_ldap_freeError(errorp);
2994 
2995 	if (connectionId > -1)
2996 		DropConnection(connectionId, flags);
2997 	return (rc);
2998 }
2999 
3000 char **
3001 __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname)
3002 {
3003 	int	i;
3004 
3005 	if (entry == NULL)
3006 		return (NULL);
3007 	for (i = 0; i < entry->attr_count; i++) {
3008 		if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL)
3009 			return (entry->attr_pair[i]->attrvalue);
3010 	}
3011 	return (NULL);
3012 }
3013 
3014 
3015 /*ARGSUSED*/
3016 int
3017 __ns_ldap_uid2dn(const char *uid,
3018 		char **userDN,
3019 		const ns_cred_t *cred,	/* cred is ignored */
3020 		ns_ldap_error_t **errorp)
3021 {
3022 	ns_ldap_result_t	*result = NULL;
3023 	char		*filter, *userdata;
3024 	char		errstr[MAXERROR];
3025 	char		**value;
3026 	int		rc = 0;
3027 	int		i = 0;
3028 	size_t		len;
3029 
3030 	*errorp = NULL;
3031 	*userDN = NULL;
3032 	if ((uid == NULL) || (uid[0] == '\0'))
3033 		return (NS_LDAP_INVALID_PARAM);
3034 
3035 	while (uid[i] != '\0') {
3036 		if (uid[i] == '=') {
3037 			*userDN = strdup(uid);
3038 			return (NS_LDAP_SUCCESS);
3039 		}
3040 		i++;
3041 	}
3042 	i = 0;
3043 	while ((uid[i] != '\0') && (isdigit(uid[i])))
3044 		i++;
3045 	if (uid[i] == '\0') {
3046 		len = strlen(UIDNUMFILTER) + strlen(uid) + 1;
3047 		filter = (char *)malloc(len);
3048 		if (filter == NULL) {
3049 			*userDN = NULL;
3050 			return (NS_LDAP_MEMORY);
3051 		}
3052 		(void) snprintf(filter, len, UIDNUMFILTER, uid);
3053 
3054 		len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1;
3055 		userdata = (char *)malloc(len);
3056 		if (userdata == NULL) {
3057 			*userDN = NULL;
3058 			return (NS_LDAP_MEMORY);
3059 		}
3060 		(void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid);
3061 	} else {
3062 		len = strlen(UIDFILTER) + strlen(uid) + 1;
3063 		filter = (char *)malloc(len);
3064 		if (filter == NULL) {
3065 			*userDN = NULL;
3066 			return (NS_LDAP_MEMORY);
3067 		}
3068 		(void) snprintf(filter, len, UIDFILTER, uid);
3069 
3070 		len = strlen(UIDFILTER_SSD) + strlen(uid) + 1;
3071 		userdata = (char *)malloc(len);
3072 		if (userdata == NULL) {
3073 			*userDN = NULL;
3074 			return (NS_LDAP_MEMORY);
3075 		}
3076 		(void) snprintf(userdata, len, UIDFILTER_SSD, uid);
3077 	}
3078 
3079 	/*
3080 	 * we want to retrieve the DN as it appears in LDAP
3081 	 * hence the use of NS_LDAP_NOT_CVT_DN in flags
3082 	 */
3083 	rc = __ns_ldap_list("passwd", filter,
3084 				__s_api_merge_SSD_filter,
3085 				NULL, cred, NS_LDAP_NOT_CVT_DN,
3086 				&result, errorp, NULL,
3087 				userdata);
3088 	free(filter);
3089 	filter = NULL;
3090 	free(userdata);
3091 	userdata = NULL;
3092 	if (rc != NS_LDAP_SUCCESS) {
3093 		if (result) {
3094 			(void) __ns_ldap_freeResult(&result);
3095 			result = NULL;
3096 		}
3097 		return (rc);
3098 	}
3099 	if (result->entries_count > 1) {
3100 		(void) __ns_ldap_freeResult(&result);
3101 		result = NULL;
3102 		*userDN = NULL;
3103 		(void) sprintf(errstr,
3104 			gettext("Too many entries are returned for %s"), uid);
3105 		MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
3106 			NULL);
3107 		return (NS_LDAP_INTERNAL);
3108 	}
3109 
3110 	value = __ns_ldap_getAttr(result->entry, "dn");
3111 	*userDN = strdup(value[0]);
3112 	(void) __ns_ldap_freeResult(&result);
3113 	result = NULL;
3114 	return (NS_LDAP_SUCCESS);
3115 }
3116 
3117 
3118 /*ARGSUSED*/
3119 int
3120 __ns_ldap_host2dn(const char *host,
3121 		const char *domain,
3122 		char **hostDN,
3123 		const ns_cred_t *cred,	/* cred is ignored */
3124 		ns_ldap_error_t **errorp)
3125 {
3126 	ns_ldap_result_t	*result = NULL;
3127 	char		*filter, *userdata;
3128 	char		errstr[MAXERROR];
3129 	char		**value;
3130 	int		rc;
3131 	size_t		len;
3132 
3133 /*
3134  * XXX
3135  * the domain parameter needs to be used in case domain is not local, if
3136  * this routine is to support multi domain setups, it needs lots of work...
3137  */
3138 	*errorp = NULL;
3139 	*hostDN = NULL;
3140 	if ((host == NULL) || (host[0] == '\0'))
3141 		return (NS_LDAP_INVALID_PARAM);
3142 
3143 	len = strlen(HOSTFILTER) + strlen(host) + 1;
3144 	filter = (char *)malloc(len);
3145 	if (filter == NULL) {
3146 		return (NS_LDAP_MEMORY);
3147 	}
3148 	(void) snprintf(filter,	len, HOSTFILTER, host);
3149 
3150 	len = strlen(HOSTFILTER_SSD) + strlen(host) + 1;
3151 	userdata = (char *)malloc(len);
3152 	if (userdata == NULL) {
3153 		return (NS_LDAP_MEMORY);
3154 	}
3155 	(void) snprintf(userdata, len, HOSTFILTER_SSD, host);
3156 
3157 	/*
3158 	 * we want to retrieve the DN as it appears in LDAP
3159 	 * hence the use of NS_LDAP_NOT_CVT_DN in flags
3160 	 */
3161 	rc = __ns_ldap_list("hosts", filter,
3162 				__s_api_merge_SSD_filter,
3163 				NULL, cred, NS_LDAP_NOT_CVT_DN, &result,
3164 				errorp, NULL,
3165 				userdata);
3166 	free(filter);
3167 	filter = NULL;
3168 	free(userdata);
3169 	userdata = NULL;
3170 	if (rc != NS_LDAP_SUCCESS) {
3171 		if (result) {
3172 			(void) __ns_ldap_freeResult(&result);
3173 			result = NULL;
3174 		}
3175 		return (rc);
3176 	}
3177 
3178 	if (result->entries_count > 1) {
3179 		(void) __ns_ldap_freeResult(&result);
3180 		result = NULL;
3181 		*hostDN = NULL;
3182 		(void) sprintf(errstr,
3183 			gettext("Too many entries are returned for %s"), host);
3184 		MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
3185 			NULL);
3186 		return (NS_LDAP_INTERNAL);
3187 	}
3188 
3189 	value = __ns_ldap_getAttr(result->entry, "dn");
3190 	*hostDN = strdup(value[0]);
3191 	(void) __ns_ldap_freeResult(&result);
3192 	result = NULL;
3193 	return (NS_LDAP_SUCCESS);
3194 }
3195 
3196 /*ARGSUSED*/
3197 int
3198 __ns_ldap_dn2domain(const char *dn,
3199 			char **domain,
3200 			const ns_cred_t *cred,
3201 			ns_ldap_error_t **errorp)
3202 {
3203 	int		rc, pnum, i, j, len = 0;
3204 	char		*newdn, **rdns = NULL;
3205 	char		**dns, *dn1;
3206 
3207 	*errorp = NULL;
3208 
3209 	if (domain == NULL)
3210 		return (NS_LDAP_INVALID_PARAM);
3211 	else
3212 		*domain = NULL;
3213 
3214 	if ((dn == NULL) || (dn[0] == '\0'))
3215 		return (NS_LDAP_INVALID_PARAM);
3216 
3217 	/*
3218 	 * break dn into rdns
3219 	 */
3220 	dn1 = strdup(dn);
3221 	if (dn1 == NULL)
3222 		return (NS_LDAP_MEMORY);
3223 	rdns = ldap_explode_dn(dn1, 0);
3224 	free(dn1);
3225 	if (rdns == NULL || *rdns == NULL)
3226 		return (NS_LDAP_INVALID_PARAM);
3227 
3228 	for (i = 0; rdns[i]; i++)
3229 		len += strlen(rdns[i]) + 1;
3230 	pnum = i;
3231 
3232 	newdn = (char *)malloc(len + 1);
3233 	dns = (char **)calloc(pnum, sizeof (char *));
3234 	if (newdn == NULL || dns == NULL) {
3235 		if (newdn)
3236 			free(newdn);
3237 		ldap_value_free(rdns);
3238 		return (NS_LDAP_MEMORY);
3239 	}
3240 
3241 	/* construct a semi-normalized dn, newdn */
3242 	*newdn = '\0';
3243 	for (i = 0; rdns[i]; i++) {
3244 		dns[i] = newdn + strlen(newdn);
3245 		(void) strcat(newdn,
3246 			__s_api_remove_rdn_space(rdns[i]));
3247 		(void) strcat(newdn, ",");
3248 	}
3249 	/* remove the last ',' */
3250 	newdn[strlen(newdn) - 1] = '\0';
3251 	ldap_value_free(rdns);
3252 
3253 	/*
3254 	 * loop and find the domain name associated with newdn,
3255 	 * removing rdn one by one from left to right
3256 	 */
3257 	for (i = 0; i < pnum; i++) {
3258 
3259 		if (*errorp)
3260 			(void) __ns_ldap_freeError(errorp);
3261 
3262 		/*
3263 		 *  try cache manager first
3264 		 */
3265 		rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN,
3266 				dns[i], domain);
3267 		if (rc != NS_LDAP_SUCCESS) {
3268 			/*
3269 			 *  try ldap server second
3270 			 */
3271 			rc = __s_api_find_domainname(dns[i], domain,
3272 				cred, errorp);
3273 		} else {
3274 			/*
3275 			 * skip the last one,
3276 			 * since it is already cached by ldap_cachemgr
3277 			 */
3278 			i--;
3279 		}
3280 		if (rc == NS_LDAP_SUCCESS) {
3281 			/*
3282 			 * ask cache manager to save the
3283 			 * dn to domain mapping(s)
3284 			 */
3285 			for (j = 0; j <= i; j++) {
3286 				(void) __s_api_set_cachemgr_data(
3287 					NS_CACHE_DN2DOMAIN,
3288 					dns[j],
3289 					*domain);
3290 			}
3291 			break;
3292 		}
3293 	}
3294 
3295 	free(dns);
3296 	free(newdn);
3297 	if (rc != NS_LDAP_SUCCESS)
3298 		rc = NS_LDAP_NOTFOUND;
3299 	return (rc);
3300 }
3301 
3302 /*ARGSUSED*/
3303 int
3304 __ns_ldap_getServiceAuthMethods(const char *service,
3305 		ns_auth_t ***auth,
3306 		ns_ldap_error_t **errorp)
3307 {
3308 	char		errstr[MAXERROR];
3309 	int		rc, i, done = 0;
3310 	int		slen;
3311 	void		**param;
3312 	char		**sam, *srv, *send;
3313 	ns_auth_t	**authpp = NULL, *ap;
3314 	int		cnt, max;
3315 	ns_config_t	*cfg;
3316 	ns_ldap_error_t	*error = NULL;
3317 
3318 	if (errorp == NULL)
3319 		return (NS_LDAP_INVALID_PARAM);
3320 	*errorp = NULL;
3321 
3322 	if ((service == NULL) || (service[0] == '\0') ||
3323 		(auth == NULL))
3324 		return (NS_LDAP_INVALID_PARAM);
3325 
3326 	*auth = NULL;
3327 	rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, &param, &error);
3328 	if (rc != NS_LDAP_SUCCESS || param == NULL) {
3329 		*errorp = error;
3330 		return (rc);
3331 	}
3332 	sam = (char **)param;
3333 
3334 	cfg = __s_api_get_default_config();
3335 	cnt = 0;
3336 
3337 	slen = strlen(service);
3338 
3339 	for (; *sam; sam++) {
3340 		srv = *sam;
3341 		if (strncasecmp(service, srv, slen) != 0)
3342 			continue;
3343 		srv += slen;
3344 		if (*srv != COLONTOK)
3345 			continue;
3346 		send = srv;
3347 		srv++;
3348 		for (max = 1; (send = strchr(++send, SEMITOK)) != NULL;
3349 			max++) {}
3350 		authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *));
3351 		if (authpp == NULL) {
3352 			(void) __ns_ldap_freeParam(&param);
3353 			__s_api_release_config(cfg);
3354 			return (NS_LDAP_MEMORY);
3355 		}
3356 		while (!done) {
3357 			send = strchr(srv, SEMITOK);
3358 			if (send != NULL) {
3359 				*send = '\0';
3360 				send++;
3361 			}
3362 			i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P);
3363 			if (i == -1) {
3364 				(void) __ns_ldap_freeParam(&param);
3365 				(void) sprintf(errstr,
3366 		gettext("Unsupported serviceAuthenticationMethod: %s.\n"), srv);
3367 				MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
3368 					strdup(errstr), NULL);
3369 				__s_api_release_config(cfg);
3370 				return (NS_LDAP_CONFIG);
3371 			}
3372 			ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i);
3373 			if (ap == NULL) {
3374 				(void) __ns_ldap_freeParam(&param);
3375 				__s_api_release_config(cfg);
3376 				return (NS_LDAP_MEMORY);
3377 			}
3378 			authpp[cnt++] = ap;
3379 			if (send == NULL)
3380 				done = TRUE;
3381 			else
3382 				srv = send;
3383 		}
3384 	}
3385 
3386 	*auth = authpp;
3387 	(void) __ns_ldap_freeParam(&param);
3388 	__s_api_release_config(cfg);
3389 	return (NS_LDAP_SUCCESS);
3390 }
3391 
3392 /*
3393  * This routine is called when certain scenario occurs
3394  * e.g.
3395  * service == auto_home
3396  * SSD = automount: ou = mytest,
3397  * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
3398  * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
3399  * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
3400  *
3401  * The automountMapName is prepended implicitely but is mapped
3402  * to AAA. So dn could appers as
3403  * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
3404  * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
3405  * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
3406  * in the directory.
3407  * This function is called to covert the mapped attr back to
3408  * orig attr when the entries are searched and returned
3409  */
3410 
3411 int
3412 __s_api_convert_automountmapname(const char *service, char **dn,
3413 		ns_ldap_error_t **errp) {
3414 
3415 	char	**mapping = NULL;
3416 	char	*mapped_attr = NULL;
3417 	char	*automountmapname = "automountMapName";
3418 	char	*buffer = NULL;
3419 	int	rc = NS_LDAP_SUCCESS;
3420 	char	errstr[MAXERROR];
3421 
3422 	/*
3423 	 * dn is an input/out parameter, check it first
3424 	 */
3425 
3426 	if (service == NULL || dn == NULL || *dn == NULL)
3427 		return (NS_LDAP_INVALID_PARAM);
3428 
3429 	/*
3430 	 * Check to see if there is a mapped attribute for auto_xxx
3431 	 */
3432 
3433 	mapping = __ns_ldap_getMappedAttributes(service, automountmapname);
3434 
3435 	/*
3436 	 * if no mapped attribute for auto_xxx, try automount
3437 	 */
3438 
3439 	if (mapping == NULL)
3440 		mapping = __ns_ldap_getMappedAttributes(
3441 			"automount", automountmapname);
3442 
3443 	/*
3444 	 * if no mapped attribute is found, return SUCCESS (no op)
3445 	 */
3446 
3447 	if (mapping == NULL)
3448 		return (NS_LDAP_SUCCESS);
3449 
3450 	/*
3451 	 * if the mapped attribute is found and attr is not empty,
3452 	 * copy it
3453 	 */
3454 
3455 	if (mapping[0] != NULL) {
3456 		mapped_attr = strdup(mapping[0]);
3457 		__s_api_free2dArray(mapping);
3458 		if (mapped_attr == NULL) {
3459 			return (NS_LDAP_MEMORY);
3460 		}
3461 	} else {
3462 		__s_api_free2dArray(mapping);
3463 
3464 		(void) snprintf(errstr, (2 * MAXERROR),
3465 			gettext(
3466 			"Attribute nisMapName is mapped to an "
3467 			"empty string.\n"));
3468 
3469 		MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX,
3470 			strdup(errstr), NULL);
3471 
3472 		return (NS_LDAP_CONFIG);
3473 	}
3474 
3475 	/*
3476 	 * Locate the mapped attribute in the dn
3477 	 * and replace it if it exists
3478 	 */
3479 
3480 	rc = __s_api_replace_mapped_attr_in_dn(
3481 		(const char *) automountmapname, (const char *) mapped_attr,
3482 		(const char *) *dn, &buffer);
3483 
3484 	/* clean up */
3485 
3486 	free(mapped_attr);
3487 
3488 	/*
3489 	 * If mapped attr is found(buffer != NULL)
3490 	 *	a new dn is returned
3491 	 * If no mapped attribute is in dn,
3492 	 *	return NS_LDAP_SUCCESS (no op)
3493 	 * If no memory,
3494 	 *	return NS_LDAP_MEMORY (no op)
3495 	 */
3496 
3497 	if (buffer != NULL) {
3498 		free(*dn);
3499 		*dn = buffer;
3500 	}
3501 
3502 	return (rc);
3503 }
3504 
3505 /*
3506  * If the mapped attr is found in the dn,
3507  * 	return NS_LDAP_SUCCESS and a new_dn.
3508  * If no mapped attr is found,
3509  * 	return NS_LDAP_SUCCESS and *new_dn == NULL
3510  * If there is not enough memory,
3511  * 	return NS_LDAP_MEMORY and *new_dn == NULL
3512  */
3513 
3514 int
3515 __s_api_replace_mapped_attr_in_dn(
3516 	const char *orig_attr, const char *mapped_attr,
3517 	const char *dn, char **new_dn) {
3518 
3519 	char	**dnArray = NULL;
3520 	char	*cur = NULL, *start = NULL;
3521 	int	i = 0, found = 0;
3522 	int	len = 0, orig_len = 0, mapped_len = 0;
3523 	int	dn_len = 0, tmp_len = 0;
3524 
3525 	*new_dn = NULL;
3526 
3527 	/*
3528 	 * seperate dn into individual componets
3529 	 * e.g.
3530 	 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
3531 	 */
3532 	dnArray = ldap_explode_dn(dn, 0);
3533 
3534 	/*
3535 	 * This will find "mapped attr=value" in dn.
3536 	 * It won't find match if mapped attr appears
3537 	 * in the value.
3538 	 */
3539 	for (i = 0; dnArray[i] != NULL; i++) {
3540 		/*
3541 		 * This function is called when reading from
3542 		 * the directory so assume each component has "=".
3543 		 * Any ill formatted dn should be rejected
3544 		 * before adding to the directory
3545 		 */
3546 		cur = strchr(dnArray[i], '=');
3547 		*cur = '\0';
3548 		if (strcasecmp(mapped_attr, dnArray[i]) == 0)
3549 			found = 1;
3550 		*cur = '=';
3551 		if (found) break;
3552 	}
3553 
3554 	if (!found) {
3555 		__s_api_free2dArray(dnArray);
3556 		*new_dn = NULL;
3557 		return (NS_LDAP_SUCCESS);
3558 	}
3559 	/*
3560 	 * The new length is *dn length + (difference between
3561 	 * orig attr and mapped attr) + 1 ;
3562 	 * e.g.
3563 	 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
3564 	 * ==>
3565 	 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
3566 	 */
3567 	mapped_len = strlen(mapped_attr);
3568 	orig_len = strlen(orig_attr);
3569 	dn_len = strlen(dn);
3570 	len = dn_len + orig_len - mapped_len + 1;
3571 	*new_dn = (char *)calloc(1, len);
3572 	if (*new_dn == NULL) {
3573 		__s_api_free2dArray(dnArray);
3574 		return (NS_LDAP_MEMORY);
3575 	}
3576 
3577 	/*
3578 	 * Locate the mapped attr in the dn.
3579 	 * Use dnArray[i] instead of mapped_attr
3580 	 * because mapped_attr could appear in
3581 	 * the value
3582 	 */
3583 
3584 	cur = strstr(dn, dnArray[i]);
3585 	__s_api_free2dArray(dnArray);
3586 	/* copy the portion before mapped attr in dn  */
3587 	start = *new_dn;
3588 	tmp_len = cur - dn;
3589 	(void) memcpy((void *) start, (const void*) dn, tmp_len);
3590 
3591 	/*
3592 	 * Copy the orig_attr. e.g. automountMapName
3593 	 * This replaces mapped attr with orig attr
3594 	 */
3595 	start = start + (cur - dn); /* move cursor in buffer */
3596 	(void) memcpy((void *) start, (const void*) orig_attr, orig_len);
3597 
3598 	/*
3599 	 * Copy the portion after mapped attr in dn
3600 	 */
3601 	cur = cur + mapped_len; /* move cursor in  dn  */
3602 	start = start + orig_len; /* move cursor in buffer */
3603 	(void) strcpy(start, cur);
3604 
3605 	return (NS_LDAP_SUCCESS);
3606 }
3607 
3608 /*
3609  * Validate Filter functions
3610  */
3611 
3612 /* ***** Start of modified libldap.so.5 filter parser ***** */
3613 
3614 /* filter parsing routine forward references */
3615 static int adj_filter_list(char *str);
3616 static int adj_simple_filter(char *str);
3617 static int unescape_filterval(char *val);
3618 static int hexchar2int(char c);
3619 static int adj_substring_filter(char *val);
3620 
3621 
3622 /*
3623  * assumes string manipulation is in-line
3624  * and all strings are sufficient in size
3625  * return value is the position after 'c'
3626  */
3627 
3628 static char *
3629 resync_str(char *str, char *next, char c)
3630 {
3631 	char	*ret;
3632 
3633 	ret = str + strlen(str);
3634 	*next = c;
3635 	if (ret == next)
3636 		return (ret);
3637 	(void) strcat(str, next);
3638 	return (ret);
3639 }
3640 
3641 static char *
3642 find_right_paren(char *s)
3643 {
3644 	int	balance, escape;
3645 
3646 	balance = 1;
3647 	escape = 0;
3648 	while (*s && balance) {
3649 		if (escape == 0) {
3650 			if (*s == '(')
3651 				balance++;
3652 			else if (*s == ')')
3653 				balance--;
3654 		}
3655 		if (*s == '\\' && ! escape)
3656 			escape = 1;
3657 		else
3658 			escape = 0;
3659 		if (balance)
3660 			s++;
3661 	}
3662 
3663 	return (*s ? s : NULL);
3664 }
3665 
3666 static char *
3667 adj_complex_filter(char	*str)
3668 {
3669 	char	*next;
3670 
3671 	/*
3672 	 * We have (x(filter)...) with str sitting on
3673 	 * the x.  We have to find the paren matching
3674 	 * the one before the x and put the intervening
3675 	 * filters by calling adj_filter_list().
3676 	 */
3677 
3678 	str++;
3679 	if ((next = find_right_paren(str)) == NULL)
3680 		return (NULL);
3681 
3682 	*next = '\0';
3683 	if (adj_filter_list(str) == -1)
3684 		return (NULL);
3685 	next = resync_str(str, next, ')');
3686 	next++;
3687 
3688 	return (next);
3689 }
3690 
3691 static int
3692 adj_filter(char *str)
3693 {
3694 	char	*next;
3695 	int	parens, balance, escape;
3696 	char	*np, *cp,  *dp;
3697 
3698 	parens = 0;
3699 	while (*str) {
3700 		switch (*str) {
3701 		case '(':
3702 			str++;
3703 			parens++;
3704 			switch (*str) {
3705 			case '&':
3706 				if ((str = adj_complex_filter(str)) == NULL)
3707 					return (-1);
3708 
3709 				parens--;
3710 				break;
3711 
3712 			case '|':
3713 				if ((str = adj_complex_filter(str)) == NULL)
3714 					return (-1);
3715 
3716 				parens--;
3717 				break;
3718 
3719 			case '!':
3720 				if ((str = adj_complex_filter(str)) == NULL)
3721 					return (-1);
3722 
3723 				parens--;
3724 				break;
3725 
3726 			case '(':
3727 				/* illegal ((case - generated by conversion */
3728 
3729 				/* find missing close) */
3730 				np = find_right_paren(str+1);
3731 
3732 				/* error if not found */
3733 				if (np == NULL)
3734 					return (-1);
3735 
3736 				/* remove redundant (and) */
3737 				for (dp = str, cp = str+1; cp < np; ) {
3738 					*dp++ = *cp++;
3739 				}
3740 				cp++;
3741 				while (*cp)
3742 					*dp++ = *cp++;
3743 				*dp = '\0';
3744 
3745 				/* re-start test at original ( */
3746 				parens--;
3747 				str--;
3748 				break;
3749 
3750 			default:
3751 				balance = 1;
3752 				escape = 0;
3753 				next = str;
3754 				while (*next && balance) {
3755 					if (escape == 0) {
3756 						if (*next == '(')
3757 							balance++;
3758 						else if (*next == ')')
3759 							balance--;
3760 					}
3761 					if (*next == '\\' && ! escape)
3762 						escape = 1;
3763 					else
3764 						escape = 0;
3765 					if (balance)
3766 						next++;
3767 				}
3768 				if (balance != 0)
3769 					return (-1);
3770 
3771 				*next = '\0';
3772 				if (adj_simple_filter(str) == -1) {
3773 					return (-1);
3774 				}
3775 				next = resync_str(str, next, ')');
3776 				next++;
3777 				str = next;
3778 				parens--;
3779 				break;
3780 			}
3781 			break;
3782 
3783 		case ')':
3784 			str++;
3785 			parens--;
3786 			break;
3787 
3788 		case ' ':
3789 			str++;
3790 			break;
3791 
3792 		default:	/* assume it's a simple type=value filter */
3793 			next = strchr(str, '\0');
3794 			if (adj_simple_filter(str) == -1) {
3795 				return (-1);
3796 			}
3797 			str = next;
3798 			break;
3799 		}
3800 	}
3801 
3802 	return (parens ? -1 : 0);
3803 }
3804 
3805 
3806 /*
3807  * Put a list of filters like this "(filter1)(filter2)..."
3808  */
3809 
3810 static int
3811 adj_filter_list(char *str)
3812 {
3813 	char	*next;
3814 	char	save;
3815 
3816 	while (*str) {
3817 		while (*str && isspace(*str))
3818 			str++;
3819 		if (*str == '\0')
3820 			break;
3821 
3822 		if ((next = find_right_paren(str + 1)) == NULL)
3823 			return (-1);
3824 		save = *++next;
3825 
3826 		/* now we have "(filter)" with str pointing to it */
3827 		*next = '\0';
3828 		if (adj_filter(str) == -1)
3829 			return (-1);
3830 		next = resync_str(str, next, save);
3831 
3832 		str = next;
3833 	}
3834 
3835 	return (0);
3836 }
3837 
3838 
3839 /*
3840  * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
3841  * of a filter expression, 0 otherwise.  A valid string may contain only
3842  * letters, numbers, hyphens, semi-colons, colons and periods. examples:
3843  *	cn
3844  *	cn;lang-fr
3845  *	1.2.3.4;binary;dynamic
3846  *	mail;dynamic
3847  *	cn:dn:1.2.3.4
3848  *
3849  * For compatibility with older servers, we also allow underscores in
3850  * attribute types, even through they are not allowed by the LDAPv3 RFCs.
3851  */
3852 static int
3853 is_valid_attr(char *a)
3854 {
3855 	for (; *a; a++) {
3856 		if (!isascii(*a)) {
3857 			return (0);
3858 		} else if (!isalnum(*a)) {
3859 			switch (*a) {
3860 			case '-':
3861 			case '.':
3862 			case ';':
3863 			case ':':
3864 			case '_':
3865 				break; /* valid */
3866 			default:
3867 				return (0);
3868 			}
3869 		}
3870 	}
3871 	return (1);
3872 }
3873 
3874 static char *
3875 find_star(char *s)
3876 {
3877 	for (; *s; ++s) {
3878 		switch (*s) {
3879 		case '*':
3880 			return (s);
3881 		case '\\':
3882 			++s;
3883 			if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0)
3884 				++s;
3885 		default:
3886 			break;
3887 		}
3888 	}
3889 	return (NULL);
3890 }
3891 
3892 static int
3893 adj_simple_filter(char *str)
3894 {
3895 	char		*s, *s2, *s3, filterop;
3896 	char		*value;
3897 	int		ftype = 0;
3898 	int		rc;
3899 
3900 	rc = -1;	/* pessimistic */
3901 
3902 	if ((str = strdup(str)) == NULL) {
3903 		return (rc);
3904 	}
3905 
3906 	if ((s = strchr(str, '=')) == NULL) {
3907 		goto free_and_return;
3908 	}
3909 	value = s + 1;
3910 	*s-- = '\0';
3911 	filterop = *s;
3912 	if (filterop == '<' || filterop == '>' || filterop == '~' ||
3913 	    filterop == ':') {
3914 		*s = '\0';
3915 	}
3916 
3917 	if (! is_valid_attr(str)) {
3918 		goto free_and_return;
3919 	}
3920 
3921 	switch (filterop) {
3922 	case '<': /* LDAP_FILTER_LE */
3923 	case '>': /* LDAP_FILTER_GE */
3924 	case '~': /* LDAP_FILTER_APPROX */
3925 		break;
3926 	case ':':	/* extended filter - v3 only */
3927 		/*
3928 		 * extended filter looks like this:
3929 		 *
3930 		 *	[type][':dn'][':'oid]':='value
3931 		 *
3932 		 * where one of type or :oid is required.
3933 		 *
3934 		 */
3935 		s2 = s3 = NULL;
3936 		if ((s2 = strrchr(str, ':')) == NULL) {
3937 			goto free_and_return;
3938 		}
3939 		if (strcasecmp(s2, ":dn") == 0) {
3940 			*s2 = '\0';
3941 		} else {
3942 			*s2 = '\0';
3943 			if ((s3 = strrchr(str, ':')) != NULL) {
3944 				if (strcasecmp(s3, ":dn") != 0) {
3945 					goto free_and_return;
3946 				}
3947 				*s3 = '\0';
3948 			}
3949 		}
3950 		if (unescape_filterval(value) < 0) {
3951 			goto free_and_return;
3952 		}
3953 		rc = 0;
3954 		goto free_and_return;
3955 		/* break; */
3956 	default:
3957 		if (find_star(value) == NULL) {
3958 			ftype = 0; /* LDAP_FILTER_EQUALITY */
3959 		} else if (strcmp(value, "*") == 0) {
3960 			ftype = 1; /* LDAP_FILTER_PRESENT */
3961 		} else {
3962 			rc = adj_substring_filter(value);
3963 			goto free_and_return;
3964 		}
3965 		break;
3966 	}
3967 
3968 	if (ftype != 0) {	/* == LDAP_FILTER_PRESENT */
3969 		rc = 0;
3970 	} else if (unescape_filterval(value) >= 0) {
3971 		rc = 0;
3972 	}
3973 	if (rc != -1) {
3974 		rc = 0;
3975 	}
3976 
3977 free_and_return:
3978 	free(str);
3979 	return (rc);
3980 }
3981 
3982 
3983 /*
3984  * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
3985  * sequences within the null-terminated string 'val'.
3986  *
3987  * If 'val' contains invalid escape sequences we return -1.
3988  * Otherwise return 1
3989  */
3990 static int
3991 unescape_filterval(char *val)
3992 {
3993 	int	escape, firstdigit;
3994 	char	*s;
3995 
3996 	firstdigit = 0;
3997 	escape = 0;
3998 	for (s = val; *s; s++) {
3999 		if (escape) {
4000 			/*
4001 			 * first try LDAPv3 escape (hexadecimal) sequence
4002 			 */
4003 			if (hexchar2int(*s) < 0) {
4004 				if (firstdigit) {
4005 					/*
4006 					 * LDAPv2 (RFC1960) escape sequence
4007 					 */
4008 					escape = 0;
4009 				} else {
4010 					return (-1);
4011 				}
4012 			}
4013 			if (firstdigit) {
4014 			    firstdigit = 0;
4015 			} else {
4016 			    escape = 0;
4017 			}
4018 
4019 		} else if (*s != '\\') {
4020 			escape = 0;
4021 
4022 		} else {
4023 			escape = 1;
4024 			firstdigit = 1;
4025 		}
4026 	}
4027 
4028 	return (1);
4029 }
4030 
4031 
4032 /*
4033  * convert character 'c' that represents a hexadecimal digit to an integer.
4034  * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
4035  * otherwise the converted value is returned.
4036  */
4037 static int
4038 hexchar2int(char c)
4039 {
4040 	if (c >= '0' && c <= '9') {
4041 		return (c - '0');
4042 	}
4043 	if (c >= 'A' && c <= 'F') {
4044 		return (c - 'A' + 10);
4045 	}
4046 	if (c >= 'a' && c <= 'f') {
4047 		return (c - 'a' + 10);
4048 	}
4049 	return (-1);
4050 }
4051 
4052 static int
4053 adj_substring_filter(char *val)
4054 {
4055 	char		*nextstar;
4056 
4057 	for (; val != NULL; val = nextstar) {
4058 		if ((nextstar = find_star(val)) != NULL) {
4059 			*nextstar++ = '\0';
4060 		}
4061 
4062 		if (*val != '\0') {
4063 			if (unescape_filterval(val) < 0) {
4064 				return (-1);
4065 			}
4066 		}
4067 	}
4068 
4069 	return (0);
4070 }
4071 
4072 /* ***** End of modified libldap.so.5 filter parser ***** */
4073 
4074 
4075 /*
4076  * Walk filter, remove redundant parentheses in-line
4077  * verify that the filter is reasonable
4078  */
4079 static int
4080 validate_filter(ns_ldap_cookie_t *cookie)
4081 {
4082 	char			*filter = cookie->filter;
4083 	int			rc;
4084 
4085 	/* Parse filter looking for illegal values */
4086 
4087 	rc = adj_filter(filter);
4088 	if (rc != 0) {
4089 		return (NS_LDAP_OP_FAILED);
4090 	}
4091 
4092 	/* end of filter checking */
4093 
4094 	return (NS_LDAP_SUCCESS);
4095 }
4096