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