17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5f8f1c176Svt  * Common Development and Distribution License (the "License").
6f8f1c176Svt  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
229f2fd570SJulian Pullen  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23695ef821SGordon Ross  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
24d7ab8532SJason King  * Copyright 2020 Joyent, Inc.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <sys/types.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <libintl.h>
317c478bd9Sstevel@tonic-gate #include <ctype.h>
327c478bd9Sstevel@tonic-gate #include <syslog.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <fcntl.h>
357c478bd9Sstevel@tonic-gate #include <unistd.h>
367c478bd9Sstevel@tonic-gate #include <string.h>
377c478bd9Sstevel@tonic-gate #include <strings.h>
38b57459abSJulian Pullen #include <priv.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include "ns_sldap.h"
417c478bd9Sstevel@tonic-gate #include "ns_internal.h"
427c478bd9Sstevel@tonic-gate #include "ns_cache_door.h"
43e1dd0a2fSth #include "ns_connmgmt.h"
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate #define	_NIS_FILTER	"nisdomain=*"
467c478bd9Sstevel@tonic-gate #define	_NIS_DOMAIN	"nisdomain"
477c478bd9Sstevel@tonic-gate static const char *nis_domain_attrs[] = {
487c478bd9Sstevel@tonic-gate 	_NIS_DOMAIN,
497c478bd9Sstevel@tonic-gate 	(char *)NULL
507c478bd9Sstevel@tonic-gate };
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate static int validate_filter(ns_ldap_cookie_t *cookie);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate void
__ns_ldap_freeEntry(ns_ldap_entry_t * ep)557c478bd9Sstevel@tonic-gate __ns_ldap_freeEntry(ns_ldap_entry_t *ep)
567c478bd9Sstevel@tonic-gate {
577c478bd9Sstevel@tonic-gate 	int		j, k = 0;
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	if (ep == NULL)
607c478bd9Sstevel@tonic-gate 		return;
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate 	if (ep->attr_pair == NULL) {
637c478bd9Sstevel@tonic-gate 		free(ep);
647c478bd9Sstevel@tonic-gate 		return;
657c478bd9Sstevel@tonic-gate 	}
667c478bd9Sstevel@tonic-gate 	for (j = 0; j < ep->attr_count; j++) {
677c478bd9Sstevel@tonic-gate 		if (ep->attr_pair[j] == NULL)
687c478bd9Sstevel@tonic-gate 			continue;
697c478bd9Sstevel@tonic-gate 		if (ep->attr_pair[j]->attrname)
707c478bd9Sstevel@tonic-gate 			free(ep->attr_pair[j]->attrname);
717c478bd9Sstevel@tonic-gate 		if (ep->attr_pair[j]->attrvalue) {
727c478bd9Sstevel@tonic-gate 			for (k = 0; (k < ep->attr_pair[j]->value_count) &&
73699bceb8Smj 			    (ep->attr_pair[j]->attrvalue[k]); k++) {
747c478bd9Sstevel@tonic-gate 				free(ep->attr_pair[j]->attrvalue[k]);
757c478bd9Sstevel@tonic-gate 			}
767c478bd9Sstevel@tonic-gate 			free(ep->attr_pair[j]->attrvalue);
777c478bd9Sstevel@tonic-gate 		}
787c478bd9Sstevel@tonic-gate 		free(ep->attr_pair[j]);
797c478bd9Sstevel@tonic-gate 	}
807c478bd9Sstevel@tonic-gate 	free(ep->attr_pair);
817c478bd9Sstevel@tonic-gate 	free(ep);
827c478bd9Sstevel@tonic-gate }
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate static void
_freeControlList(LDAPControl *** ctrls)857c478bd9Sstevel@tonic-gate _freeControlList(LDAPControl ***ctrls)
867c478bd9Sstevel@tonic-gate {
877c478bd9Sstevel@tonic-gate 	LDAPControl	**ctrl;
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate 	if (ctrls == NULL || *ctrls == NULL)
907c478bd9Sstevel@tonic-gate 		return;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	for (ctrl = *ctrls; *ctrl != NULL; ctrl++)
937c478bd9Sstevel@tonic-gate 		ldap_control_free(*ctrl);
947c478bd9Sstevel@tonic-gate 	free(*ctrls);
957c478bd9Sstevel@tonic-gate 	*ctrls = NULL;
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * Convert attribute type in a RDN that has an attribute mapping to the
997c478bd9Sstevel@tonic-gate  * original mappped type.
1007c478bd9Sstevel@tonic-gate  * e.g.
1017c478bd9Sstevel@tonic-gate  * cn<->cn-st and iphostnumber<->iphostnumber-st
1027c478bd9Sstevel@tonic-gate  * cn-st=aaa+iphostnumber-st=10.10.01.01
1037c478bd9Sstevel@tonic-gate  * is mapped to
1047c478bd9Sstevel@tonic-gate  * cn=aaa+iphostnumber=10.10.01.01
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * Input - service: e.g. hosts, passwd etc.
1077c478bd9Sstevel@tonic-gate  *         rdn: RDN
1087c478bd9Sstevel@tonic-gate  * Return: NULL - No attribute mapping in the RDN
1097c478bd9Sstevel@tonic-gate  *         Non-NULL - The attribute type(s) in the RDN are mapped and
1107c478bd9Sstevel@tonic-gate  *                    the memory is allocated for the new rdn.
1117c478bd9Sstevel@tonic-gate  *
1127c478bd9Sstevel@tonic-gate  */
1137c478bd9Sstevel@tonic-gate static char *
_cvtRDN(const char * service,const char * rdn)1148f0bb794SToomas Soome _cvtRDN(const char *service, const char *rdn)
1158f0bb794SToomas Soome {
1167c478bd9Sstevel@tonic-gate 	char	**attrs, **mapped_attrs, **mapp, *type, *value, *attr;
1177c478bd9Sstevel@tonic-gate 	char	*new_rdn = NULL;
1187c478bd9Sstevel@tonic-gate 	int	nAttr = 0, i, attr_mapped, len = 0;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	/* Break down "type=value\0" pairs. Assume RDN is normalized */
1217c478bd9Sstevel@tonic-gate 	if ((attrs = ldap_explode_rdn(rdn, 0)) == NULL)
1227c478bd9Sstevel@tonic-gate 		return (NULL);
1237c478bd9Sstevel@tonic-gate 
1248f0bb794SToomas Soome 	for (nAttr = 0; attrs[nAttr] != NULL; nAttr++)
1258f0bb794SToomas Soome 		;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	if ((mapped_attrs = (char **)calloc(nAttr, sizeof (char *))) == NULL) {
1287c478bd9Sstevel@tonic-gate 		ldap_value_free(attrs);
1297c478bd9Sstevel@tonic-gate 		return (NULL);
1307c478bd9Sstevel@tonic-gate 	}
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate 	attr_mapped = 0;
1337c478bd9Sstevel@tonic-gate 	for (i = 0; i < nAttr; i++) {
1347c478bd9Sstevel@tonic-gate 		/* Parse type=value pair */
1357c478bd9Sstevel@tonic-gate 		if ((type = strtok_r(attrs[i], "=", &value)) == NULL ||
1368f0bb794SToomas Soome 		    value == NULL)
1377c478bd9Sstevel@tonic-gate 			goto cleanup;
1387c478bd9Sstevel@tonic-gate 		/* Reverse map: e.g. cn-sm -> cn */
1397c478bd9Sstevel@tonic-gate 		mapp = __ns_ldap_getOrigAttribute(service, type);
1407c478bd9Sstevel@tonic-gate 		if (mapp != NULL && mapp[0] != NULL) {
1417c478bd9Sstevel@tonic-gate 			/* The attribute mapping is found */
1427c478bd9Sstevel@tonic-gate 			type = mapp[0];
1437c478bd9Sstevel@tonic-gate 			attr_mapped = 1;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 			/* "type=value\0" */
1467c478bd9Sstevel@tonic-gate 			len = strlen(type) + strlen(value) + 2;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 			/* Reconstruct type=value pair. A string is allocated */
1497c478bd9Sstevel@tonic-gate 			if ((attr = (char *)calloc(1, len)) == NULL) {
1507c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(mapp);
1517c478bd9Sstevel@tonic-gate 				goto cleanup;
1527c478bd9Sstevel@tonic-gate 			}
1538f0bb794SToomas Soome 			(void) snprintf(attr, len, "%s=%s", type, value);
1547c478bd9Sstevel@tonic-gate 			mapped_attrs[i] = attr;
1557c478bd9Sstevel@tonic-gate 		} else {
1567c478bd9Sstevel@tonic-gate 			/*
1577c478bd9Sstevel@tonic-gate 			 * No attribute mapping. attrs[i] is going to be copied
1587c478bd9Sstevel@tonic-gate 			 * later. Restore "type\0value\0" back to
1597c478bd9Sstevel@tonic-gate 			 * "type=value\0".
1607c478bd9Sstevel@tonic-gate 			 */
1617c478bd9Sstevel@tonic-gate 			type[strlen(type)] = '=';
1627c478bd9Sstevel@tonic-gate 		}
1637c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(mapp);
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 	if (attr_mapped == 0)
1667c478bd9Sstevel@tonic-gate 		/* No attribute mapping. Don't bother to reconstruct RDN */
1677c478bd9Sstevel@tonic-gate 		goto cleanup;
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	len = 0;
1707c478bd9Sstevel@tonic-gate 	/* Reconstruct RDN from type=value pairs */
1717c478bd9Sstevel@tonic-gate 	for (i = 0; i < nAttr; i++) {
1727c478bd9Sstevel@tonic-gate 		if (mapped_attrs[i])
1737c478bd9Sstevel@tonic-gate 			len += strlen(mapped_attrs[i]);
1747c478bd9Sstevel@tonic-gate 		else
1757c478bd9Sstevel@tonic-gate 			len += strlen(attrs[i]);
1767c478bd9Sstevel@tonic-gate 		/* Add 1 for "+" */
1777c478bd9Sstevel@tonic-gate 		len++;
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 	if ((new_rdn = (char *)calloc(1, ++len)) == NULL)
1807c478bd9Sstevel@tonic-gate 		goto cleanup;
1817c478bd9Sstevel@tonic-gate 	for (i = 0; i < nAttr; i++) {
1827c478bd9Sstevel@tonic-gate 		if (i > 0)
1837c478bd9Sstevel@tonic-gate 			/* Add seperator */
1847c478bd9Sstevel@tonic-gate 			(void) strlcat(new_rdn, "+", len);
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 		if (mapped_attrs[i])
1877c478bd9Sstevel@tonic-gate 			(void) strlcat(new_rdn, mapped_attrs[i], len);
1887c478bd9Sstevel@tonic-gate 		else
1897c478bd9Sstevel@tonic-gate 			(void) strlcat(new_rdn, attrs[i], len);
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	}
1927c478bd9Sstevel@tonic-gate cleanup:
1937c478bd9Sstevel@tonic-gate 	ldap_value_free(attrs);
1947c478bd9Sstevel@tonic-gate 	if (mapped_attrs) {
1957c478bd9Sstevel@tonic-gate 		if (attr_mapped) {
1967c478bd9Sstevel@tonic-gate 			for (i = 0; i < nAttr; i++) {
1977c478bd9Sstevel@tonic-gate 				if (mapped_attrs[i])
1987c478bd9Sstevel@tonic-gate 					free(mapped_attrs[i]);
1997c478bd9Sstevel@tonic-gate 			}
2007c478bd9Sstevel@tonic-gate 		}
2017c478bd9Sstevel@tonic-gate 		free(mapped_attrs);
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	return (new_rdn);
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate /*
2077c478bd9Sstevel@tonic-gate  * Convert attribute type in a DN that has an attribute mapping to the
2087c478bd9Sstevel@tonic-gate  * original mappped type.
2097c478bd9Sstevel@tonic-gate  * e.g
2107c478bd9Sstevel@tonic-gate  * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
2117c478bd9Sstevel@tonic-gate  *
2127c478bd9Sstevel@tonic-gate  * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com
2137c478bd9Sstevel@tonic-gate  * is converted to
2147c478bd9Sstevel@tonic-gate  * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
2157c478bd9Sstevel@tonic-gate  *
2167c478bd9Sstevel@tonic-gate  * Input - service: e.g. hosts, passwd etc.
2177c478bd9Sstevel@tonic-gate  *         dn: the value of a distinguished name
2187c478bd9Sstevel@tonic-gate  * Return - NULL: error
2197c478bd9Sstevel@tonic-gate  *          non-NULL: A converted DN and the memory is allocated
2207c478bd9Sstevel@tonic-gate  */
2217c478bd9Sstevel@tonic-gate static char *
_cvtDN(const char * service,const char * dn)2228f0bb794SToomas Soome _cvtDN(const char *service, const char *dn)
2238f0bb794SToomas Soome {
2247c478bd9Sstevel@tonic-gate 	char	**mapped_rdns;
2257c478bd9Sstevel@tonic-gate 	char	**rdns, *new_rdn, *new_dn = NULL;
2267c478bd9Sstevel@tonic-gate 	int	nRdn = 0, i, len = 0, rdn_mapped;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	if (service == NULL || dn == NULL)
2297c478bd9Sstevel@tonic-gate 		return (NULL);
2307c478bd9Sstevel@tonic-gate 
2317c478bd9Sstevel@tonic-gate 	if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
2327c478bd9Sstevel@tonic-gate 		return (NULL);
2337c478bd9Sstevel@tonic-gate 
234695ef821SGordon Ross 	for (nRdn = 0; rdns[nRdn] != NULL; nRdn++)
235695ef821SGordon Ross 		;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	if ((mapped_rdns = (char **)calloc(nRdn, sizeof (char *))) == NULL) {
2387c478bd9Sstevel@tonic-gate 		ldap_value_free(rdns);
2397c478bd9Sstevel@tonic-gate 		return (NULL);
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate 	rdn_mapped = 0;
2437c478bd9Sstevel@tonic-gate 	/* Break down RDNs in a DN */
2447c478bd9Sstevel@tonic-gate 	for (i = 0; i < nRdn; i++) {
2457c478bd9Sstevel@tonic-gate 		if ((new_rdn = _cvtRDN(service, rdns[i])) != NULL) {
2467c478bd9Sstevel@tonic-gate 			mapped_rdns[i] = new_rdn;
2477c478bd9Sstevel@tonic-gate 			rdn_mapped = 1;
2487c478bd9Sstevel@tonic-gate 		}
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate 	if (rdn_mapped == 0) {
2517c478bd9Sstevel@tonic-gate 		/*
2527c478bd9Sstevel@tonic-gate 		 * No RDN contains any attribute mapping.
2537c478bd9Sstevel@tonic-gate 		 * Don't bother to reconstruct DN from RDN. Copy DN directly.
2547c478bd9Sstevel@tonic-gate 		 */
2557c478bd9Sstevel@tonic-gate 		new_dn = strdup(dn);
2567c478bd9Sstevel@tonic-gate 		goto cleanup;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 	/*
2597c478bd9Sstevel@tonic-gate 	 * Reconstruct dn from RDNs.
2607c478bd9Sstevel@tonic-gate 	 * Calculate the length first.
2617c478bd9Sstevel@tonic-gate 	 */
2627c478bd9Sstevel@tonic-gate 	for (i = 0; i < nRdn; i++) {
2637c478bd9Sstevel@tonic-gate 		if (mapped_rdns[i])
2647c478bd9Sstevel@tonic-gate 			len += strlen(mapped_rdns[i]);
2657c478bd9Sstevel@tonic-gate 		else
2667c478bd9Sstevel@tonic-gate 			len += strlen(rdns[i]);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate 		/* add 1 for ',' */
2697c478bd9Sstevel@tonic-gate 		len ++;
2707c478bd9Sstevel@tonic-gate 	}
2717c478bd9Sstevel@tonic-gate 	if ((new_dn = (char *)calloc(1, ++len)) == NULL)
2727c478bd9Sstevel@tonic-gate 		goto cleanup;
2737c478bd9Sstevel@tonic-gate 	for (i = 0; i < nRdn; i++) {
2747c478bd9Sstevel@tonic-gate 		if (i > 0)
2757c478bd9Sstevel@tonic-gate 			/* Add seperator */
2767c478bd9Sstevel@tonic-gate 			(void) strlcat(new_dn, ",", len);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 		if (mapped_rdns[i])
2797c478bd9Sstevel@tonic-gate 			(void) strlcat(new_dn, mapped_rdns[i], len);
2807c478bd9Sstevel@tonic-gate 		else
2817c478bd9Sstevel@tonic-gate 			(void) strlcat(new_dn, rdns[i], len);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate cleanup:
2867c478bd9Sstevel@tonic-gate 	ldap_value_free(rdns);
2877c478bd9Sstevel@tonic-gate 	if (mapped_rdns) {
2887c478bd9Sstevel@tonic-gate 		if (rdn_mapped) {
2897c478bd9Sstevel@tonic-gate 			for (i = 0; i < nRdn; i++) {
2907c478bd9Sstevel@tonic-gate 				if (mapped_rdns[i])
2917c478bd9Sstevel@tonic-gate 					free(mapped_rdns[i]);
2927c478bd9Sstevel@tonic-gate 			}
2937c478bd9Sstevel@tonic-gate 		}
2947c478bd9Sstevel@tonic-gate 		free(mapped_rdns);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	return (new_dn);
2987c478bd9Sstevel@tonic-gate }
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate  * Convert a single ldap entry from a LDAPMessage
3017c478bd9Sstevel@tonic-gate  * into an ns_ldap_entry structure.
3027c478bd9Sstevel@tonic-gate  * Schema map the entry if specified in flags
3037c478bd9Sstevel@tonic-gate  */
3047c478bd9Sstevel@tonic-gate 
3057c478bd9Sstevel@tonic-gate static int
__s_api_cvtEntry(LDAP * ld,const char * service,LDAPMessage * e,int flags,ns_ldap_entry_t ** ret,ns_ldap_error_t ** error)3068f0bb794SToomas Soome __s_api_cvtEntry(LDAP *ld, const char *service, LDAPMessage *e, int flags,
3078f0bb794SToomas Soome     ns_ldap_entry_t **ret, ns_ldap_error_t **error)
3087c478bd9Sstevel@tonic-gate {
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	ns_ldap_entry_t	*ep = NULL;
3117c478bd9Sstevel@tonic-gate 	ns_ldap_attr_t	**ap = NULL;
3127c478bd9Sstevel@tonic-gate 	BerElement	*ber;
3137c478bd9Sstevel@tonic-gate 	char		*attr = NULL;
3147c478bd9Sstevel@tonic-gate 	char		**vals = NULL;
3157c478bd9Sstevel@tonic-gate 	char		**mapping;
3167c478bd9Sstevel@tonic-gate 	char		*dn;
3177c478bd9Sstevel@tonic-gate 	int		nAttrs = 0;
3187c478bd9Sstevel@tonic-gate 	int		i, j, k = 0;
3197c478bd9Sstevel@tonic-gate 	char		**gecos_mapping = NULL;
3207c478bd9Sstevel@tonic-gate 	int		gecos_val_index[3] = { -1, -1, -1};
3217c478bd9Sstevel@tonic-gate 	char		errstr[MAXERROR];
3227c478bd9Sstevel@tonic-gate 	int		schema_mapping_existed = FALSE;
3237c478bd9Sstevel@tonic-gate 	int		gecos_mapping_existed = FALSE;
3247c478bd9Sstevel@tonic-gate 	int		gecos_attr_matched;
3257c478bd9Sstevel@tonic-gate 	int		auto_service = FALSE;
3267c478bd9Sstevel@tonic-gate 	int		rc = NS_LDAP_SUCCESS;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 	if (e == NULL || ret == NULL || error == NULL)
3297c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	*error = NULL;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
3347c478bd9Sstevel@tonic-gate 	if (ep == NULL)
3357c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	if (service != NULL &&
338699bceb8Smj 	    (strncasecmp(service, "auto_", 5) == 0 ||
339699bceb8Smj 	    strcasecmp(service, "automount") == 0))
3407c478bd9Sstevel@tonic-gate 		auto_service = TRUE;
3417c478bd9Sstevel@tonic-gate 	/*
3427c478bd9Sstevel@tonic-gate 	 * see if schema mapping existed for the given service
3437c478bd9Sstevel@tonic-gate 	 */
3447c478bd9Sstevel@tonic-gate 	mapping = __ns_ldap_getOrigAttribute(service,
345699bceb8Smj 	    NS_HASH_SCHEMA_MAPPING_EXISTED);
3467c478bd9Sstevel@tonic-gate 	if (mapping) {
3477c478bd9Sstevel@tonic-gate 		schema_mapping_existed = TRUE;
3487c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(mapping);
3497c478bd9Sstevel@tonic-gate 		mapping = NULL;
3507c478bd9Sstevel@tonic-gate 	} else if (auto_service) {
3517c478bd9Sstevel@tonic-gate 		/*
3527c478bd9Sstevel@tonic-gate 		 * If service == auto_* and no
3537c478bd9Sstevel@tonic-gate 		 * schema mapping found
3547c478bd9Sstevel@tonic-gate 		 * then try automount
3557c478bd9Sstevel@tonic-gate 		 * There is certain case that schema mapping exist
3567c478bd9Sstevel@tonic-gate 		 * but __ns_ldap_getOrigAttribute(service,
3577c478bd9Sstevel@tonic-gate 		 *	NS_HASH_SCHEMA_MAPPING_EXISTED);
3587c478bd9Sstevel@tonic-gate 		 * returns NULL.
3597c478bd9Sstevel@tonic-gate 		 * e.g.
3607c478bd9Sstevel@tonic-gate 		 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
3617c478bd9Sstevel@tonic-gate 		 * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
3627c478bd9Sstevel@tonic-gate 		 * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
3637c478bd9Sstevel@tonic-gate 		 *
3647c478bd9Sstevel@tonic-gate 		 * Make a check for schema_mapping_existed here
3657c478bd9Sstevel@tonic-gate 		 * so later on __s_api_convert_automountmapname won't be called
3667c478bd9Sstevel@tonic-gate 		 * unnecessarily. It is also used for attribute mapping
3677c478bd9Sstevel@tonic-gate 		 * and objectclass mapping.
3687c478bd9Sstevel@tonic-gate 		 */
3697c478bd9Sstevel@tonic-gate 		mapping = __ns_ldap_getOrigAttribute("automount",
370699bceb8Smj 		    NS_HASH_SCHEMA_MAPPING_EXISTED);
3717c478bd9Sstevel@tonic-gate 		if (mapping) {
3727c478bd9Sstevel@tonic-gate 			schema_mapping_existed = TRUE;
3737c478bd9Sstevel@tonic-gate 			__s_api_free2dArray(mapping);
3747c478bd9Sstevel@tonic-gate 			mapping = NULL;
3757c478bd9Sstevel@tonic-gate 		}
3767c478bd9Sstevel@tonic-gate 	}
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate 	nAttrs = 1;  /* start with 1 for the DN attr */
3797c478bd9Sstevel@tonic-gate 	for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL;
380699bceb8Smj 	    attr = ldap_next_attribute(ld, e, ber)) {
3817c478bd9Sstevel@tonic-gate 		nAttrs++;
3827c478bd9Sstevel@tonic-gate 		ldap_memfree(attr);
3837c478bd9Sstevel@tonic-gate 		attr = NULL;
3847c478bd9Sstevel@tonic-gate 	}
3857c478bd9Sstevel@tonic-gate 	ber_free(ber, 0);
3867c478bd9Sstevel@tonic-gate 	ber = NULL;
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	ep->attr_count = nAttrs;
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 	/*
3917c478bd9Sstevel@tonic-gate 	 * add 1 for "gecos" 1 to N attribute mapping,
3927c478bd9Sstevel@tonic-gate 	 * just in case it is needed.
3937c478bd9Sstevel@tonic-gate 	 * ep->attr_count will be updated later if that is true.
3947c478bd9Sstevel@tonic-gate 	 */
3957c478bd9Sstevel@tonic-gate 	ap = (ns_ldap_attr_t **)calloc(ep->attr_count + 1,
396699bceb8Smj 	    sizeof (ns_ldap_attr_t *));
3977c478bd9Sstevel@tonic-gate 	if (ap == NULL) {
3987c478bd9Sstevel@tonic-gate 		__ns_ldap_freeEntry(ep);
3997c478bd9Sstevel@tonic-gate 		ep = NULL;
4007c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
4017c478bd9Sstevel@tonic-gate 	}
4027c478bd9Sstevel@tonic-gate 	ep->attr_pair = ap;
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	/* DN attribute */
4057c478bd9Sstevel@tonic-gate 	dn = ldap_get_dn(ld, e);
4067c478bd9Sstevel@tonic-gate 	ap[0] = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
4077c478bd9Sstevel@tonic-gate 	if (ap[0] == NULL) {
4087c478bd9Sstevel@tonic-gate 		ldap_memfree(dn);
4097c478bd9Sstevel@tonic-gate 		dn = NULL;
4107c478bd9Sstevel@tonic-gate 		__ns_ldap_freeEntry(ep);
4117c478bd9Sstevel@tonic-gate 		ep = NULL;
4127c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
4137c478bd9Sstevel@tonic-gate 	}
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	if ((ap[0]->attrname = strdup("dn")) == NULL) {
4167c478bd9Sstevel@tonic-gate 		ldap_memfree(dn);
4177c478bd9Sstevel@tonic-gate 		dn = NULL;
4187c478bd9Sstevel@tonic-gate 		__ns_ldap_freeEntry(ep);
4197c478bd9Sstevel@tonic-gate 		ep = NULL;
4207c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate 	ap[0]->value_count = 1;
4237c478bd9Sstevel@tonic-gate 	if ((ap[0]->attrvalue = (char **)
424699bceb8Smj 	    calloc(2, sizeof (char *))) == NULL) {
4257c478bd9Sstevel@tonic-gate 		ldap_memfree(dn);
4267c478bd9Sstevel@tonic-gate 		dn = NULL;
4277c478bd9Sstevel@tonic-gate 		__ns_ldap_freeEntry(ep);
4287c478bd9Sstevel@tonic-gate 		ep = NULL;
4297c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
4307c478bd9Sstevel@tonic-gate 	}
4317c478bd9Sstevel@tonic-gate 
432f5c3c7a7Ssdussud 	if (schema_mapping_existed && ((flags & NS_LDAP_NOT_CVT_DN) == 0))
4337c478bd9Sstevel@tonic-gate 		ap[0]->attrvalue[0] = _cvtDN(service, dn);
4347c478bd9Sstevel@tonic-gate 	else
4357c478bd9Sstevel@tonic-gate 		ap[0]->attrvalue[0] = strdup(dn);
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	if (ap[0]->attrvalue[0] == NULL) {
4387c478bd9Sstevel@tonic-gate 		ldap_memfree(dn);
4397c478bd9Sstevel@tonic-gate 		dn = NULL;
4407c478bd9Sstevel@tonic-gate 		__ns_ldap_freeEntry(ep);
4417c478bd9Sstevel@tonic-gate 		ep = NULL;
4427c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 	ldap_memfree(dn);
4457c478bd9Sstevel@tonic-gate 	dn = NULL;
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	if ((flags & NS_LDAP_NOMAP) == 0 && auto_service &&
448699bceb8Smj 	    schema_mapping_existed) {
4497c478bd9Sstevel@tonic-gate 		rc = __s_api_convert_automountmapname(service,
450699bceb8Smj 		    &ap[0]->attrvalue[0],
451699bceb8Smj 		    error);
4527c478bd9Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
4537c478bd9Sstevel@tonic-gate 			__ns_ldap_freeEntry(ep);
4547c478bd9Sstevel@tonic-gate 			ep = NULL;
4557c478bd9Sstevel@tonic-gate 			return (rc);
4567c478bd9Sstevel@tonic-gate 		}
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	/* other attributes */
4607c478bd9Sstevel@tonic-gate 	for (attr = ldap_first_attribute(ld, e, &ber), j = 1;
461699bceb8Smj 	    attr != NULL && j != nAttrs;
462699bceb8Smj 	    attr = ldap_next_attribute(ld, e, ber), j++) {
463699bceb8Smj 		/* allocate new attr name */
464699bceb8Smj 
465699bceb8Smj 		if ((ap[j] = (ns_ldap_attr_t *)
466699bceb8Smj 		    calloc(1, sizeof (ns_ldap_attr_t))) == NULL) {
467699bceb8Smj 			ber_free(ber, 0);
468699bceb8Smj 			ber = NULL;
469699bceb8Smj 			__ns_ldap_freeEntry(ep);
470699bceb8Smj 			ep = NULL;
471699bceb8Smj 			if (gecos_mapping)
472699bceb8Smj 				__s_api_free2dArray(gecos_mapping);
473699bceb8Smj 			gecos_mapping = NULL;
474699bceb8Smj 			return (NS_LDAP_MEMORY);
4757c478bd9Sstevel@tonic-gate 		}
4767c478bd9Sstevel@tonic-gate 
477699bceb8Smj 		if ((flags & NS_LDAP_NOMAP) || schema_mapping_existed == FALSE)
478699bceb8Smj 			mapping = NULL;
479699bceb8Smj 		else
480699bceb8Smj 			mapping = __ns_ldap_getOrigAttribute(service, attr);
4817c478bd9Sstevel@tonic-gate 
482699bceb8Smj 		if (mapping == NULL && auto_service &&
483699bceb8Smj 		    schema_mapping_existed && (flags & NS_LDAP_NOMAP) == 0)
4847c478bd9Sstevel@tonic-gate 			/*
485699bceb8Smj 			 * if service == auto_* and no schema mapping found
486699bceb8Smj 			 * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP
487699bceb8Smj 			 * is not set then try automount e.g.
488699bceb8Smj 			 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
4897c478bd9Sstevel@tonic-gate 			 */
490699bceb8Smj 			mapping = __ns_ldap_getOrigAttribute("automount",
491699bceb8Smj 			    attr);
4927c478bd9Sstevel@tonic-gate 
493699bceb8Smj 		if (mapping == NULL) {
494699bceb8Smj 			if ((ap[j]->attrname = strdup(attr)) == NULL) {
4957c478bd9Sstevel@tonic-gate 				ber_free(ber, 0);
4967c478bd9Sstevel@tonic-gate 				ber = NULL;
4977c478bd9Sstevel@tonic-gate 				__ns_ldap_freeEntry(ep);
4987c478bd9Sstevel@tonic-gate 				ep = NULL;
4997c478bd9Sstevel@tonic-gate 				if (gecos_mapping)
5007c478bd9Sstevel@tonic-gate 					__s_api_free2dArray(gecos_mapping);
5017c478bd9Sstevel@tonic-gate 				gecos_mapping = NULL;
5027c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
5037c478bd9Sstevel@tonic-gate 			}
5047c478bd9Sstevel@tonic-gate 		} else {
505699bceb8Smj 			/*
506699bceb8Smj 			 * for "gecos" 1 to N mapping,
507699bceb8Smj 			 * do not remove the mapped attribute,
508699bceb8Smj 			 * just create a new gecos attribute
509699bceb8Smj 			 * and append it to the end of the attribute list
510699bceb8Smj 			 */
511699bceb8Smj 			if (strcasecmp(mapping[0], "gecos") == 0) {
512699bceb8Smj 				ap[j]->attrname = strdup(attr);
513699bceb8Smj 				gecos_mapping_existed = TRUE;
5148f0bb794SToomas Soome 			} else {
515699bceb8Smj 				ap[j]->attrname = strdup(mapping[0]);
5168f0bb794SToomas Soome 			}
517699bceb8Smj 
518699bceb8Smj 			if (ap[j]->attrname == NULL) {
5197c478bd9Sstevel@tonic-gate 				ber_free(ber, 0);
5207c478bd9Sstevel@tonic-gate 				ber = NULL;
5217c478bd9Sstevel@tonic-gate 				__ns_ldap_freeEntry(ep);
5227c478bd9Sstevel@tonic-gate 				ep = NULL;
5237c478bd9Sstevel@tonic-gate 				if (gecos_mapping)
5247c478bd9Sstevel@tonic-gate 					__s_api_free2dArray(gecos_mapping);
5257c478bd9Sstevel@tonic-gate 				gecos_mapping = NULL;
5267c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
5277c478bd9Sstevel@tonic-gate 			}
528699bceb8Smj 			/*
529699bceb8Smj 			 * 1 to N attribute mapping processing
530699bceb8Smj 			 * is only done for "gecos"
531699bceb8Smj 			 */
532699bceb8Smj 
533699bceb8Smj 			if (strcasecmp(mapping[0], "gecos") == 0) {
534699bceb8Smj 				/*
535699bceb8Smj 				 * get attribute mapping for "gecos",
536699bceb8Smj 				 * need to know the number and order of the
537699bceb8Smj 				 * mapped attributes
538699bceb8Smj 				 */
539699bceb8Smj 				if (gecos_mapping == NULL) {
540699bceb8Smj 					gecos_mapping =
541699bceb8Smj 					    __ns_ldap_getMappedAttributes(
542699bceb8Smj 					    service, mapping[0]);
543699bceb8Smj 					if (gecos_mapping == NULL ||
544699bceb8Smj 					    gecos_mapping[0] == NULL) {
545699bceb8Smj 						/*
546699bceb8Smj 						 * this should never happens,
547699bceb8Smj 						 * syslog the error
548699bceb8Smj 						 */
549699bceb8Smj 						(void) sprintf(errstr,
550699bceb8Smj 						    gettext(
551699bceb8Smj 						    "Attribute mapping "
552699bceb8Smj 						    "inconsistency "
553699bceb8Smj 						    "found for attributes "
554699bceb8Smj 						    "'%s' and '%s'."),
555699bceb8Smj 						    mapping[0], attr);
556699bceb8Smj 						syslog(LOG_ERR, "libsldap: %s",
557699bceb8Smj 						    errstr);
558699bceb8Smj 
559699bceb8Smj 						ber_free(ber, 0);
560699bceb8Smj 						ber = NULL;
561699bceb8Smj 						__ns_ldap_freeEntry(ep);
562699bceb8Smj 						ep = NULL;
563699bceb8Smj 						__s_api_free2dArray(mapping);
564699bceb8Smj 						mapping = NULL;
565699bceb8Smj 						if (gecos_mapping)
566699bceb8Smj 							__s_api_free2dArray(
567699bceb8Smj 							    gecos_mapping);
568699bceb8Smj 						gecos_mapping = NULL;
569699bceb8Smj 						return (NS_LDAP_INTERNAL);
570699bceb8Smj 					}
571699bceb8Smj 				}
572699bceb8Smj 
573699bceb8Smj 				/*
574699bceb8Smj 				 * is this attribute the 1st, 2nd, or
575699bceb8Smj 				 * 3rd attr in the mapping list?
576699bceb8Smj 				 */
577699bceb8Smj 				gecos_attr_matched = FALSE;
578699bceb8Smj 				for (i = 0; i < 3 && gecos_mapping[i]; i++) {
579699bceb8Smj 					if (gecos_mapping[i] &&
580699bceb8Smj 					    strcasecmp(gecos_mapping[i],
581699bceb8Smj 					    attr) == 0) {
582699bceb8Smj 						gecos_val_index[i] = j;
583699bceb8Smj 						gecos_attr_matched = TRUE;
584699bceb8Smj 						break;
585699bceb8Smj 					}
586699bceb8Smj 				}
587699bceb8Smj 				if (gecos_attr_matched == FALSE) {
588699bceb8Smj 					/*
589699bceb8Smj 					 * Not match found.
590699bceb8Smj 					 * This should never happens,
591699bceb8Smj 					 * syslog the error
592699bceb8Smj 					 */
593699bceb8Smj 					(void) sprintf(errstr,
594699bceb8Smj 					    gettext(
595699bceb8Smj 					    "Attribute mapping "
596699bceb8Smj 					    "inconsistency "
597699bceb8Smj 					    "found for attributes "
598699bceb8Smj 					    "'%s' and '%s'."),
599699bceb8Smj 					    mapping[0], attr);
600699bceb8Smj 					syslog(LOG_ERR, "libsldap: %s", errstr);
601699bceb8Smj 
602699bceb8Smj 					ber_free(ber, 0);
603699bceb8Smj 					ber = NULL;
604699bceb8Smj 					__ns_ldap_freeEntry(ep);
605699bceb8Smj 					ep = NULL;
606699bceb8Smj 					__s_api_free2dArray(mapping);
607699bceb8Smj 					mapping = NULL;
608699bceb8Smj 					__s_api_free2dArray(gecos_mapping);
609699bceb8Smj 					gecos_mapping = NULL;
610699bceb8Smj 					return (NS_LDAP_INTERNAL);
611699bceb8Smj 				}
612699bceb8Smj 			}
613699bceb8Smj 			__s_api_free2dArray(mapping);
614699bceb8Smj 			mapping = NULL;
6157c478bd9Sstevel@tonic-gate 		}
6167c478bd9Sstevel@tonic-gate 
617699bceb8Smj 		if ((vals = ldap_get_values(ld, e, attr)) != NULL) {
6187c478bd9Sstevel@tonic-gate 
619699bceb8Smj 			if ((ap[j]->value_count =
620699bceb8Smj 			    ldap_count_values(vals)) == 0) {
621699bceb8Smj 				ldap_value_free(vals);
622699bceb8Smj 				vals = NULL;
623699bceb8Smj 				continue;
624699bceb8Smj 			} else {
625699bceb8Smj 				ap[j]->attrvalue = (char **)
626699bceb8Smj 				    calloc(ap[j]->value_count+1,
627699bceb8Smj 				    sizeof (char *));
628699bceb8Smj 				if (ap[j]->attrvalue == NULL) {
629699bceb8Smj 					ber_free(ber, 0);
630699bceb8Smj 					ber = NULL;
631699bceb8Smj 					__ns_ldap_freeEntry(ep);
632699bceb8Smj 					ep = NULL;
633699bceb8Smj 					if (gecos_mapping)
634699bceb8Smj 						__s_api_free2dArray(
635699bceb8Smj 						    gecos_mapping);
636699bceb8Smj 					gecos_mapping = NULL;
637699bceb8Smj 					return (NS_LDAP_MEMORY);
638699bceb8Smj 				}
639699bceb8Smj 			}
640699bceb8Smj 
641699bceb8Smj 			/* map object classes if necessary */
642699bceb8Smj 			if ((flags & NS_LDAP_NOMAP) == 0 &&
643699bceb8Smj 			    schema_mapping_existed && ap[j]->attrname &&
644699bceb8Smj 			    strcasecmp(ap[j]->attrname, "objectclass") == 0) {
645699bceb8Smj 				for (k = 0; k < ap[j]->value_count; k++) {
646699bceb8Smj 					mapping =
647699bceb8Smj 					    __ns_ldap_getOrigObjectClass(
648699bceb8Smj 					    service, vals[k]);
649699bceb8Smj 
650699bceb8Smj 					if (mapping == NULL && auto_service)
651699bceb8Smj 						/*
652699bceb8Smj 						 * if service == auto_* and no
653699bceb8Smj 						 * schema mapping found
654699bceb8Smj 						 * then try automount
655699bceb8Smj 						 */
656f47dc443Ssdussud 					mapping =
657f47dc443Ssdussud 					    __ns_ldap_getOrigObjectClass(
658f47dc443Ssdussud 					    "automount", vals[k]);
659699bceb8Smj 
660699bceb8Smj 					if (mapping == NULL) {
661699bceb8Smj 						ap[j]->attrvalue[k] =
662699bceb8Smj 						    strdup(vals[k]);
663699bceb8Smj 					} else {
664699bceb8Smj 						ap[j]->attrvalue[k] =
665699bceb8Smj 						    strdup(mapping[0]);
666699bceb8Smj 						__s_api_free2dArray(mapping);
667699bceb8Smj 						mapping = NULL;
668699bceb8Smj 					}
669699bceb8Smj 					if (ap[j]->attrvalue[k] == NULL) {
670699bceb8Smj 						ber_free(ber, 0);
671699bceb8Smj 						ber = NULL;
672699bceb8Smj 						__ns_ldap_freeEntry(ep);
673699bceb8Smj 						ep = NULL;
674699bceb8Smj 						if (gecos_mapping)
675699bceb8Smj 							__s_api_free2dArray(
676699bceb8Smj 							    gecos_mapping);
677699bceb8Smj 						gecos_mapping = NULL;
678699bceb8Smj 						return (NS_LDAP_MEMORY);
679699bceb8Smj 					}
680699bceb8Smj 				}
681699bceb8Smj 			} else {
682699bceb8Smj 				for (k = 0; k < ap[j]->value_count; k++) {
683699bceb8Smj 					if ((ap[j]->attrvalue[k] =
684699bceb8Smj 					    strdup(vals[k])) == NULL) {
685699bceb8Smj 						ber_free(ber, 0);
686699bceb8Smj 						ber = NULL;
687699bceb8Smj 						__ns_ldap_freeEntry(ep);
688699bceb8Smj 						ep = NULL;
689699bceb8Smj 						if (gecos_mapping)
690699bceb8Smj 							__s_api_free2dArray(
691699bceb8Smj 							    gecos_mapping);
692699bceb8Smj 						gecos_mapping = NULL;
693699bceb8Smj 						return (NS_LDAP_MEMORY);
694699bceb8Smj 					}
695699bceb8Smj 				}
696699bceb8Smj 			}
697699bceb8Smj 
698699bceb8Smj 			ap[j]->attrvalue[k] = NULL;
699699bceb8Smj 			ldap_value_free(vals);
700699bceb8Smj 			vals = NULL;
701699bceb8Smj 		}
702699bceb8Smj 
703699bceb8Smj 		ldap_memfree(attr);
704699bceb8Smj 		attr = NULL;
7057c478bd9Sstevel@tonic-gate 	}
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	ber_free(ber, 0);
7087c478bd9Sstevel@tonic-gate 	ber = NULL;
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	if (gecos_mapping) {
7117c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(gecos_mapping);
7127c478bd9Sstevel@tonic-gate 		gecos_mapping = NULL;
7137c478bd9Sstevel@tonic-gate 	}
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 	/* special processing for gecos 1 to up to 3 attribute mapping */
7167c478bd9Sstevel@tonic-gate 	if (schema_mapping_existed && gecos_mapping_existed) {
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 		int	f = -1;
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 		for (i = 0; i < 3; i++) {
7217c478bd9Sstevel@tonic-gate 			k = gecos_val_index[i];
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 			/*
7247c478bd9Sstevel@tonic-gate 			 * f is the index of the first returned
7257c478bd9Sstevel@tonic-gate 			 * attribute which "gecos" attribute mapped to
7267c478bd9Sstevel@tonic-gate 			 */
7277c478bd9Sstevel@tonic-gate 			if (k != -1 && f == -1)
7287c478bd9Sstevel@tonic-gate 				f = k;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 			if (k != -1 && ap[k]->value_count > 0 &&
731699bceb8Smj 			    ap[k]->attrvalue[0] &&
732699bceb8Smj 			    strlen(ap[k]->attrvalue[0]) > 0) {
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 				if (k == f) {
7357c478bd9Sstevel@tonic-gate 					/*
7367c478bd9Sstevel@tonic-gate 					 * Create and fill in the last reserved
7377c478bd9Sstevel@tonic-gate 					 * ap with the data from the "gecos"
7387c478bd9Sstevel@tonic-gate 					 * mapping attributes
7397c478bd9Sstevel@tonic-gate 					 */
7407c478bd9Sstevel@tonic-gate 					ap[nAttrs] = (ns_ldap_attr_t *)
741699bceb8Smj 					    calloc(1,
742699bceb8Smj 					    sizeof (ns_ldap_attr_t));
7437c478bd9Sstevel@tonic-gate 					if (ap[nAttrs] == NULL) {
7447c478bd9Sstevel@tonic-gate 						__ns_ldap_freeEntry(ep);
7457c478bd9Sstevel@tonic-gate 						ep = NULL;
7467c478bd9Sstevel@tonic-gate 						return (NS_LDAP_MEMORY);
7477c478bd9Sstevel@tonic-gate 					}
7487c478bd9Sstevel@tonic-gate 					ap[nAttrs]->attrvalue = (char **)calloc(
749699bceb8Smj 					    2, sizeof (char *));
7507c478bd9Sstevel@tonic-gate 					if (ap[nAttrs]->attrvalue == NULL) {
7517c478bd9Sstevel@tonic-gate 						__ns_ldap_freeEntry(ep);
7527c478bd9Sstevel@tonic-gate 						ep = NULL;
7537c478bd9Sstevel@tonic-gate 						return (NS_LDAP_MEMORY);
7547c478bd9Sstevel@tonic-gate 					}
7557c478bd9Sstevel@tonic-gate 					/* add 1 more for a possible "," */
7567c478bd9Sstevel@tonic-gate 					ap[nAttrs]->attrvalue[0] =
757699bceb8Smj 					    (char *)calloc(
758699bceb8Smj 					    strlen(ap[f]->attrvalue[0]) +
759699bceb8Smj 					    2, 1);
7607c478bd9Sstevel@tonic-gate 					if (ap[nAttrs]->attrvalue[0] == NULL) {
7617c478bd9Sstevel@tonic-gate 						__ns_ldap_freeEntry(ep);
7627c478bd9Sstevel@tonic-gate 						ep = NULL;
7637c478bd9Sstevel@tonic-gate 						return (NS_LDAP_MEMORY);
7647c478bd9Sstevel@tonic-gate 					}
7657c478bd9Sstevel@tonic-gate 					(void) strcpy(ap[nAttrs]->attrvalue[0],
766699bceb8Smj 					    ap[f]->attrvalue[0]);
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 					ap[nAttrs]->attrname = strdup("gecos");
7697c478bd9Sstevel@tonic-gate 					if (ap[nAttrs]->attrname == NULL) {
7707c478bd9Sstevel@tonic-gate 						__ns_ldap_freeEntry(ep);
7717c478bd9Sstevel@tonic-gate 						ep = NULL;
7727c478bd9Sstevel@tonic-gate 						return (NS_LDAP_MEMORY);
7737c478bd9Sstevel@tonic-gate 					}
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 					ap[nAttrs]->value_count = 1;
7767c478bd9Sstevel@tonic-gate 					ep->attr_count = nAttrs + 1;
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 				} else {
7794142e9a2Ssdussud 					char	*tmp = NULL;
7804142e9a2Ssdussud 
7814142e9a2Ssdussud 					/*
7824142e9a2Ssdussud 					 * realloc to add "," and
7834142e9a2Ssdussud 					 * ap[k]->attrvalue[0]
7844142e9a2Ssdussud 					 */
7854142e9a2Ssdussud 					tmp = (char *)realloc(
786699bceb8Smj 					    ap[nAttrs]->attrvalue[0],
787699bceb8Smj 					    strlen(ap[nAttrs]->
788699bceb8Smj 					    attrvalue[0]) +
789699bceb8Smj 					    strlen(ap[k]->
790699bceb8Smj 					    attrvalue[0]) + 2);
7914142e9a2Ssdussud 					if (tmp == NULL) {
7927c478bd9Sstevel@tonic-gate 						__ns_ldap_freeEntry(ep);
7937c478bd9Sstevel@tonic-gate 						ep = NULL;
7947c478bd9Sstevel@tonic-gate 						return (NS_LDAP_MEMORY);
7957c478bd9Sstevel@tonic-gate 					}
7964142e9a2Ssdussud 					ap[nAttrs]->attrvalue[0] = tmp;
7974142e9a2Ssdussud 					(void) strcat(ap[nAttrs]->attrvalue[0],
798699bceb8Smj 					    ",");
7997c478bd9Sstevel@tonic-gate 					(void) strcat(ap[nAttrs]->attrvalue[0],
800699bceb8Smj 					    ap[k]->attrvalue[0]);
8017c478bd9Sstevel@tonic-gate 				}
8027c478bd9Sstevel@tonic-gate 			}
8037c478bd9Sstevel@tonic-gate 		}
8047c478bd9Sstevel@tonic-gate 	}
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	*ret = ep;
8077c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
8087c478bd9Sstevel@tonic-gate }
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate static int
__s_api_getEntry(ns_ldap_cookie_t * cookie)8117c478bd9Sstevel@tonic-gate __s_api_getEntry(ns_ldap_cookie_t *cookie)
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate 	ns_ldap_entry_t	*curEntry = NULL;
8147c478bd9Sstevel@tonic-gate 	int		ret;
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate #ifdef DEBUG
8177c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "__s_api_getEntry START\n");
8187c478bd9Sstevel@tonic-gate #endif
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate 	if (cookie->resultMsg == NULL) {
8217c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
8227c478bd9Sstevel@tonic-gate 	}
8237c478bd9Sstevel@tonic-gate 	ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service,
824699bceb8Smj 	    cookie->resultMsg, cookie->i_flags,
825699bceb8Smj 	    &curEntry, &cookie->errorp);
8267c478bd9Sstevel@tonic-gate 	if (ret != NS_LDAP_SUCCESS) {
8277c478bd9Sstevel@tonic-gate 		return (ret);
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	if (cookie->result == NULL) {
8317c478bd9Sstevel@tonic-gate 		cookie->result = (ns_ldap_result_t *)
832699bceb8Smj 		    calloc(1, sizeof (ns_ldap_result_t));
8337c478bd9Sstevel@tonic-gate 		if (cookie->result == NULL) {
8347c478bd9Sstevel@tonic-gate 			__ns_ldap_freeEntry(curEntry);
8357c478bd9Sstevel@tonic-gate 			curEntry = NULL;
8367c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
8377c478bd9Sstevel@tonic-gate 		}
8387c478bd9Sstevel@tonic-gate 		cookie->result->entry = curEntry;
8397c478bd9Sstevel@tonic-gate 		cookie->nextEntry = curEntry;
8407c478bd9Sstevel@tonic-gate 	} else {
8417c478bd9Sstevel@tonic-gate 		cookie->nextEntry->next = curEntry;
8427c478bd9Sstevel@tonic-gate 		cookie->nextEntry = curEntry;
8437c478bd9Sstevel@tonic-gate 	}
8447c478bd9Sstevel@tonic-gate 	cookie->result->entries_count++;
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate static int
__s_api_get_cachemgr_data(const char * type,const char * from,char ** to)8508f0bb794SToomas Soome __s_api_get_cachemgr_data(const char *type, const char *from, char **to)
8517c478bd9Sstevel@tonic-gate {
8527c478bd9Sstevel@tonic-gate 	union {
8537c478bd9Sstevel@tonic-gate 		ldap_data_t	s_d;
8547c478bd9Sstevel@tonic-gate 		char		s_b[DOORBUFFERSIZE];
8557c478bd9Sstevel@tonic-gate 	} space;
8567c478bd9Sstevel@tonic-gate 	ldap_data_t	*sptr;
8577c478bd9Sstevel@tonic-gate 	int		ndata;
8587c478bd9Sstevel@tonic-gate 	int		adata;
8597c478bd9Sstevel@tonic-gate 	int		rc;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate #ifdef DEBUG
8627c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "__s_api_get_cachemgr_data START\n");
8637c478bd9Sstevel@tonic-gate #endif
864e1dd0a2fSth 	/*
865e1dd0a2fSth 	 * We are not going to perform DN to domain mapping
866e1dd0a2fSth 	 * in the Standalone mode
867e1dd0a2fSth 	 */
868e1dd0a2fSth 	if (__s_api_isStandalone()) {
869e1dd0a2fSth 		return (-1);
870e1dd0a2fSth 	}
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	if (from == NULL || from[0] == '\0' || to == NULL)
8737c478bd9Sstevel@tonic-gate 		return (-1);
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	*to = NULL;
8767c478bd9Sstevel@tonic-gate 	(void) memset(space.s_b, 0, DOORBUFFERSIZE);
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 	space.s_d.ldap_call.ldap_callnumber = GETCACHE;
8797c478bd9Sstevel@tonic-gate 	(void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
880699bceb8Smj 	    DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
881699bceb8Smj 	    "%s%s%s",
882699bceb8Smj 	    type,
883699bceb8Smj 	    DOORLINESEP,
884699bceb8Smj 	    from);
8857c478bd9Sstevel@tonic-gate 	ndata = sizeof (space);
8867c478bd9Sstevel@tonic-gate 	adata = sizeof (ldap_call_t) +
887699bceb8Smj 	    strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
8887c478bd9Sstevel@tonic-gate 	sptr = &space.s_d;
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
891e1dd0a2fSth 	if (rc != NS_CACHE_SUCCESS)
8927c478bd9Sstevel@tonic-gate 		return (-1);
8937c478bd9Sstevel@tonic-gate 	else
8947c478bd9Sstevel@tonic-gate 		*to = strdup(sptr->ldap_ret.ldap_u.buff);
8957c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate static int
__s_api_set_cachemgr_data(const char * type,const char * from,const char * to)8998f0bb794SToomas Soome __s_api_set_cachemgr_data(const char *type, const char *from, const char *to)
9007c478bd9Sstevel@tonic-gate {
9017c478bd9Sstevel@tonic-gate 	union {
9027c478bd9Sstevel@tonic-gate 		ldap_data_t	s_d;
9037c478bd9Sstevel@tonic-gate 		char		s_b[DOORBUFFERSIZE];
9047c478bd9Sstevel@tonic-gate 	} space;
9057c478bd9Sstevel@tonic-gate 	ldap_data_t	*sptr;
9067c478bd9Sstevel@tonic-gate 	int		ndata;
9077c478bd9Sstevel@tonic-gate 	int		adata;
9087c478bd9Sstevel@tonic-gate 	int		rc;
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate #ifdef DEBUG
9117c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "__s_api_set_cachemgr_data START\n");
9127c478bd9Sstevel@tonic-gate #endif
913e1dd0a2fSth 	/*
914e1dd0a2fSth 	 * We are not going to perform DN to domain mapping
915e1dd0a2fSth 	 * in the Standalone mode
916e1dd0a2fSth 	 */
917e1dd0a2fSth 	if (__s_api_isStandalone()) {
918e1dd0a2fSth 		return (-1);
919e1dd0a2fSth 	}
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 	if ((from == NULL) || (from[0] == '\0') ||
922699bceb8Smj 	    (to == NULL) || (to[0] == '\0'))
9237c478bd9Sstevel@tonic-gate 		return (-1);
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	(void) memset(space.s_b, 0, DOORBUFFERSIZE);
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	space.s_d.ldap_call.ldap_callnumber = SETCACHE;
9287c478bd9Sstevel@tonic-gate 	(void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
929699bceb8Smj 	    DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
930699bceb8Smj 	    "%s%s%s%s%s",
931699bceb8Smj 	    type,
932699bceb8Smj 	    DOORLINESEP,
933699bceb8Smj 	    from,
934699bceb8Smj 	    DOORLINESEP,
935699bceb8Smj 	    to);
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	ndata = sizeof (space);
9387c478bd9Sstevel@tonic-gate 	adata = sizeof (ldap_call_t) +
939699bceb8Smj 	    strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
9407c478bd9Sstevel@tonic-gate 	sptr = &space.s_d;
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
943e1dd0a2fSth 	if (rc != NS_CACHE_SUCCESS)
9447c478bd9Sstevel@tonic-gate 		return (-1);
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate static char *
__s_api_remove_rdn_space(char * rdn)9517c478bd9Sstevel@tonic-gate __s_api_remove_rdn_space(char *rdn)
9527c478bd9Sstevel@tonic-gate {
9537c478bd9Sstevel@tonic-gate 	char	*tf, *tl, *vf, *vl, *eqsign;
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	/* if no space(s) to remove, return */
9567c478bd9Sstevel@tonic-gate 	if (strchr(rdn, SPACETOK) == NULL)
9577c478bd9Sstevel@tonic-gate 		return (rdn);
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	/* if no '=' separator, return */
9607c478bd9Sstevel@tonic-gate 	eqsign = strchr(rdn, '=');
9617c478bd9Sstevel@tonic-gate 	if (eqsign == NULL)
9627c478bd9Sstevel@tonic-gate 		return (rdn);
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	tf = rdn;
9657c478bd9Sstevel@tonic-gate 	tl = eqsign - 1;
9667c478bd9Sstevel@tonic-gate 	vf = eqsign + 1;
9677c478bd9Sstevel@tonic-gate 	vl = rdn + strlen(rdn) - 1;
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	/* now two strings, type and value */
9707c478bd9Sstevel@tonic-gate 	*eqsign = '\0';
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 	/* remove type's leading spaces */
9737c478bd9Sstevel@tonic-gate 	while (tf < tl && *tf == SPACETOK)
9747c478bd9Sstevel@tonic-gate 		tf++;
9757c478bd9Sstevel@tonic-gate 	/* remove type's trailing spaces */
9767c478bd9Sstevel@tonic-gate 	while (tf < tl && *tl == SPACETOK)
9777c478bd9Sstevel@tonic-gate 		tl--;
9787c478bd9Sstevel@tonic-gate 	/* add '=' separator back */
9797c478bd9Sstevel@tonic-gate 	*(++tl) = '=';
9807c478bd9Sstevel@tonic-gate 	/* remove value's leading spaces */
9817c478bd9Sstevel@tonic-gate 	while (vf < vl && *vf == SPACETOK)
9827c478bd9Sstevel@tonic-gate 		vf++;
9837c478bd9Sstevel@tonic-gate 	/* remove value's trailing spaces */
9847c478bd9Sstevel@tonic-gate 	while (vf < vl && *vl == SPACETOK)
9857c478bd9Sstevel@tonic-gate 		*vl-- = '\0';
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	/* move value up if necessary */
9887c478bd9Sstevel@tonic-gate 	if (vf != tl + 1)
9897c478bd9Sstevel@tonic-gate 		(void) strcpy(tl + 1, vf);
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	return (tf);
9927c478bd9Sstevel@tonic-gate }
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate static
9957c478bd9Sstevel@tonic-gate ns_ldap_cookie_t *
init_search_state_machine()9967c478bd9Sstevel@tonic-gate init_search_state_machine()
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie;
9997c478bd9Sstevel@tonic-gate 	ns_config_t		*cfg;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	cookie = (ns_ldap_cookie_t *)calloc(1, sizeof (ns_ldap_cookie_t));
10027c478bd9Sstevel@tonic-gate 	if (cookie == NULL)
10037c478bd9Sstevel@tonic-gate 		return (NULL);
10047c478bd9Sstevel@tonic-gate 	cookie->state = INIT;
10057c478bd9Sstevel@tonic-gate 	/* assign other state variables */
10067c478bd9Sstevel@tonic-gate 	cfg = __s_api_loadrefresh_config();
10077c478bd9Sstevel@tonic-gate 	cookie->connectionId = -1;
10087c478bd9Sstevel@tonic-gate 	if (cfg == NULL ||
1009699bceb8Smj 	    cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_ptype == NS_UNKNOWN) {
10107c478bd9Sstevel@tonic-gate 		cookie->search_timeout.tv_sec = NS_DEFAULT_SEARCH_TIMEOUT;
10117c478bd9Sstevel@tonic-gate 	} else {
10127c478bd9Sstevel@tonic-gate 		cookie->search_timeout.tv_sec =
1013699bceb8Smj 		    cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_i;
10147c478bd9Sstevel@tonic-gate 	}
10157c478bd9Sstevel@tonic-gate 	if (cfg != NULL)
10167c478bd9Sstevel@tonic-gate 		__s_api_release_config(cfg);
10177c478bd9Sstevel@tonic-gate 	cookie->search_timeout.tv_usec = 0;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	return (cookie);
10207c478bd9Sstevel@tonic-gate }
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate static void
delete_search_cookie(ns_ldap_cookie_t * cookie)10237c478bd9Sstevel@tonic-gate delete_search_cookie(ns_ldap_cookie_t *cookie)
10247c478bd9Sstevel@tonic-gate {
10257c478bd9Sstevel@tonic-gate 	if (cookie == NULL)
10267c478bd9Sstevel@tonic-gate 		return;
10277c478bd9Sstevel@tonic-gate 	if (cookie->connectionId > -1)
10287c478bd9Sstevel@tonic-gate 		DropConnection(cookie->connectionId, cookie->i_flags);
10297c478bd9Sstevel@tonic-gate 	if (cookie->filter)
10307c478bd9Sstevel@tonic-gate 		free(cookie->filter);
10317c478bd9Sstevel@tonic-gate 	if (cookie->i_filter)
10327c478bd9Sstevel@tonic-gate 		free(cookie->i_filter);
10337c478bd9Sstevel@tonic-gate 	if (cookie->service)
10347c478bd9Sstevel@tonic-gate 		free(cookie->service);
10357c478bd9Sstevel@tonic-gate 	if (cookie->sdlist)
10367c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeSearchDescriptors(&(cookie->sdlist));
10377c478bd9Sstevel@tonic-gate 	if (cookie->result)
10387c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeResult(&cookie->result);
10397c478bd9Sstevel@tonic-gate 	if (cookie->attribute)
10407c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(cookie->attribute);
10417c478bd9Sstevel@tonic-gate 	if (cookie->errorp)
10427c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeError(&cookie->errorp);
10437c478bd9Sstevel@tonic-gate 	if (cookie->reflist)
10447c478bd9Sstevel@tonic-gate 		__s_api_deleteRefInfo(cookie->reflist);
10457c478bd9Sstevel@tonic-gate 	if (cookie->basedn)
10467c478bd9Sstevel@tonic-gate 		free(cookie->basedn);
10477c478bd9Sstevel@tonic-gate 	if (cookie->ctrlCookie)
10487c478bd9Sstevel@tonic-gate 		ber_bvfree(cookie->ctrlCookie);
10497c478bd9Sstevel@tonic-gate 	_freeControlList(&cookie->p_serverctrls);
105047789246Svv 	if (cookie->resultctrl)
105147789246Svv 		ldap_controls_free(cookie->resultctrl);
10527c478bd9Sstevel@tonic-gate 	free(cookie);
10537c478bd9Sstevel@tonic-gate }
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate static int
get_mapped_filter(ns_ldap_cookie_t * cookie,char ** new_filter)10567c478bd9Sstevel@tonic-gate get_mapped_filter(ns_ldap_cookie_t *cookie, char **new_filter)
10577c478bd9Sstevel@tonic-gate {
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	typedef	struct	filter_mapping_info {
10607c478bd9Sstevel@tonic-gate 		char	oc_or_attr;
10617c478bd9Sstevel@tonic-gate 		char	*name_start;
10627c478bd9Sstevel@tonic-gate 		char	*name_end;
10637c478bd9Sstevel@tonic-gate 		char	*veq_pos;
10647c478bd9Sstevel@tonic-gate 		char	*from_name;
10657c478bd9Sstevel@tonic-gate 		char	*to_name;
10667c478bd9Sstevel@tonic-gate 		char	**mapping;
10677c478bd9Sstevel@tonic-gate 	} filter_mapping_info_t;
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	char			*c, *last_copied;
10707c478bd9Sstevel@tonic-gate 	char			*filter_c, *filter_c_next;
10717c478bd9Sstevel@tonic-gate 	char			*key, *tail, *head;
10727c478bd9Sstevel@tonic-gate 	char			errstr[MAXERROR];
10737c478bd9Sstevel@tonic-gate 	int			num_eq = 0, num_veq = 0;
10748f0bb794SToomas Soome 	boolean_t		in_quote = B_FALSE;
10758f0bb794SToomas Soome 	boolean_t		is_value = B_FALSE;
10767c478bd9Sstevel@tonic-gate 	int			i, j, oc_len, len;
10778f0bb794SToomas Soome 	boolean_t		at_least_one = B_FALSE;
10787c478bd9Sstevel@tonic-gate 	filter_mapping_info_t	**info, *info1;
10797c478bd9Sstevel@tonic-gate 	char			**mapping;
10807c478bd9Sstevel@tonic-gate 	char			*service, *filter, *err;
10818f0bb794SToomas Soome 	boolean_t		auto_service = B_FALSE;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	if (cookie == NULL || new_filter == NULL)
10847c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	*new_filter = NULL;
10877c478bd9Sstevel@tonic-gate 	service = cookie->service;
10887c478bd9Sstevel@tonic-gate 	filter = cookie->filter;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	/*
10917c478bd9Sstevel@tonic-gate 	 * count the number of '=' char
10927c478bd9Sstevel@tonic-gate 	 */
10937c478bd9Sstevel@tonic-gate 	for (c = filter; *c; c++) {
10947c478bd9Sstevel@tonic-gate 		if (*c == TOKENSEPARATOR)
10957c478bd9Sstevel@tonic-gate 			num_eq++;
10967c478bd9Sstevel@tonic-gate 	}
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	if (service != NULL && strncasecmp(service, "auto_", 5) == 0)
10997c478bd9Sstevel@tonic-gate 		auto_service = TRUE;
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	/*
11027c478bd9Sstevel@tonic-gate 	 * See if schema mapping existed for the given service.
11037c478bd9Sstevel@tonic-gate 	 * If not, just return success.
11047c478bd9Sstevel@tonic-gate 	 */
11057c478bd9Sstevel@tonic-gate 	mapping = __ns_ldap_getOrigAttribute(service,
1106699bceb8Smj 	    NS_HASH_SCHEMA_MAPPING_EXISTED);
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 	if (mapping == NULL && auto_service)
11097c478bd9Sstevel@tonic-gate 		/*
11107c478bd9Sstevel@tonic-gate 		 * if service == auto_* and no
11117c478bd9Sstevel@tonic-gate 		 * schema mapping found
11127c478bd9Sstevel@tonic-gate 		 * then try automount
11137c478bd9Sstevel@tonic-gate 		 */
11147c478bd9Sstevel@tonic-gate 		mapping = __ns_ldap_getOrigAttribute(
1115699bceb8Smj 		    "automount", NS_HASH_SCHEMA_MAPPING_EXISTED);
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	if (mapping)
11187c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(mapping);
11197c478bd9Sstevel@tonic-gate 	else
11207c478bd9Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	/*
11237c478bd9Sstevel@tonic-gate 	 * no '=' sign, just say OK and return nothing
11247c478bd9Sstevel@tonic-gate 	 */
11257c478bd9Sstevel@tonic-gate 	if (num_eq == 0)
11267c478bd9Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	/*
11297c478bd9Sstevel@tonic-gate 	 * Make a copy of the filter string
11307c478bd9Sstevel@tonic-gate 	 * for saving the name of the objectclasses or
11317c478bd9Sstevel@tonic-gate 	 * attributes that need to be passed to the
11327c478bd9Sstevel@tonic-gate 	 * objectclass or attribute mapping functions.
11337c478bd9Sstevel@tonic-gate 	 * pointer "info->from_name" points to the locations
11347c478bd9Sstevel@tonic-gate 	 * within this string.
11357c478bd9Sstevel@tonic-gate 	 *
11367c478bd9Sstevel@tonic-gate 	 * The input filter string, filter, will be used
11377c478bd9Sstevel@tonic-gate 	 * to indicate where these names start and end.
11387c478bd9Sstevel@tonic-gate 	 * pointers "info->name_start" and "info->name_end"
11397c478bd9Sstevel@tonic-gate 	 * point to locations within the input filter string,
11407c478bd9Sstevel@tonic-gate 	 * and are used at the end of this function to
11417c478bd9Sstevel@tonic-gate 	 * merge the original filter data with the
11427c478bd9Sstevel@tonic-gate 	 * mapped objectclass or attribute names.
11437c478bd9Sstevel@tonic-gate 	 */
11447c478bd9Sstevel@tonic-gate 	filter_c = strdup(filter);
11457c478bd9Sstevel@tonic-gate 	if (filter_c == NULL)
11467c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
11477c478bd9Sstevel@tonic-gate 	filter_c_next = filter_c;
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate 	/*
11507c478bd9Sstevel@tonic-gate 	 * get memory for info arrays
11517c478bd9Sstevel@tonic-gate 	 */
11527c478bd9Sstevel@tonic-gate 	info = (filter_mapping_info_t **)calloc(num_eq + 1,
1153699bceb8Smj 	    sizeof (filter_mapping_info_t *));
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	if (info == NULL) {
11567c478bd9Sstevel@tonic-gate 		free(filter_c);
11577c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
11587c478bd9Sstevel@tonic-gate 	}
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 	/*
11617c478bd9Sstevel@tonic-gate 	 * find valid '=' for further processing,
11627c478bd9Sstevel@tonic-gate 	 * ignore the "escaped =" (.i.e. "\="), or
11637c478bd9Sstevel@tonic-gate 	 * "=" in quoted string
11647c478bd9Sstevel@tonic-gate 	 */
11657c478bd9Sstevel@tonic-gate 	for (c = filter_c; *c; c++) {
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate 		switch (*c) {
11687c478bd9Sstevel@tonic-gate 		case TOKENSEPARATOR:
1169f8f1c176Svt 			if (!in_quote && !is_value) {
11707c478bd9Sstevel@tonic-gate 				info1 = (filter_mapping_info_t *)calloc(1,
1171699bceb8Smj 				    sizeof (filter_mapping_info_t));
11728f0bb794SToomas Soome 				if (info1 == NULL) {
11737c478bd9Sstevel@tonic-gate 					free(filter_c);
11747c478bd9Sstevel@tonic-gate 					for (i = 0; i < num_veq; i++)
11757c478bd9Sstevel@tonic-gate 						free(info[i]);
11767c478bd9Sstevel@tonic-gate 					free(info);
11777c478bd9Sstevel@tonic-gate 					return (NS_LDAP_MEMORY);
11787c478bd9Sstevel@tonic-gate 				}
11797c478bd9Sstevel@tonic-gate 				info[num_veq] = info1;
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 				/*
11827c478bd9Sstevel@tonic-gate 				 * remember the location of this "="
11837c478bd9Sstevel@tonic-gate 				 */
11847c478bd9Sstevel@tonic-gate 				info[num_veq++]->veq_pos = c;
1185f8f1c176Svt 
1186f8f1c176Svt 				/*
1187f8f1c176Svt 				 * skip until the end of the attribute value
1188f8f1c176Svt 				 */
11898f0bb794SToomas Soome 				is_value = B_TRUE;
11907c478bd9Sstevel@tonic-gate 			}
11917c478bd9Sstevel@tonic-gate 			break;
1192f8f1c176Svt 		case CPARATOK:
1193f8f1c176Svt 			/*
1194f8f1c176Svt 			 * mark the end of the attribute value
1195f8f1c176Svt 			 */
1196f8f1c176Svt 			if (!in_quote)
11978f0bb794SToomas Soome 				is_value = B_FALSE;
1198f8f1c176Svt 			break;
11997c478bd9Sstevel@tonic-gate 		case QUOTETOK:
12007c478bd9Sstevel@tonic-gate 			/*
12017c478bd9Sstevel@tonic-gate 			 * switch on/off the in_quote mode
12027c478bd9Sstevel@tonic-gate 			 */
12038f0bb794SToomas Soome 			in_quote = (in_quote == B_FALSE);
12047c478bd9Sstevel@tonic-gate 			break;
12057c478bd9Sstevel@tonic-gate 		case '\\':
12067c478bd9Sstevel@tonic-gate 			/*
12077c478bd9Sstevel@tonic-gate 			 * ignore escape characters
12087c478bd9Sstevel@tonic-gate 			 * don't skip if next char is '\0'
12097c478bd9Sstevel@tonic-gate 			 */
12107c478bd9Sstevel@tonic-gate 			if (!in_quote)
12117c478bd9Sstevel@tonic-gate 				if (*(++c) == '\0')
12127c478bd9Sstevel@tonic-gate 					c--;
12137c478bd9Sstevel@tonic-gate 			break;
12147c478bd9Sstevel@tonic-gate 		}
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	}
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	/*
12197c478bd9Sstevel@tonic-gate 	 * for each valid "=" found, get the name to
12207c478bd9Sstevel@tonic-gate 	 * be mapped
12217c478bd9Sstevel@tonic-gate 	 */
12227c478bd9Sstevel@tonic-gate 	oc_len = strlen("objectclass");
12237c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_veq; i++) {
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 		/*
12267c478bd9Sstevel@tonic-gate 		 * look at the left side of "=" to see
12277c478bd9Sstevel@tonic-gate 		 * if assertion is "objectclass=<ocname>"
12287c478bd9Sstevel@tonic-gate 		 * or "<attribute name>=<attribute value>"
12297c478bd9Sstevel@tonic-gate 		 *
12307c478bd9Sstevel@tonic-gate 		 * first skip spaces before "=".
12317c478bd9Sstevel@tonic-gate 		 * Note that filter_c_next may not point to the
12327c478bd9Sstevel@tonic-gate 		 * start of the filter string. For i > 0,
12337c478bd9Sstevel@tonic-gate 		 * it points to the end of the last name processed + 2
12347c478bd9Sstevel@tonic-gate 		 */
12357c478bd9Sstevel@tonic-gate 		for (tail = info[i]->veq_pos; (tail > filter_c_next) &&
1236699bceb8Smj 		    (*(tail - 1) == SPACETOK); tail--)
1237699bceb8Smj 			;
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 		/*
12407c478bd9Sstevel@tonic-gate 		 * mark the end of the left side string (the key)
12417c478bd9Sstevel@tonic-gate 		 */
12427c478bd9Sstevel@tonic-gate 		*tail = '\0';
12437c478bd9Sstevel@tonic-gate 		info[i]->name_end = tail - filter_c - 1 + filter;
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 		/*
12467c478bd9Sstevel@tonic-gate 		 * find the start of the key
12477c478bd9Sstevel@tonic-gate 		 */
12487c478bd9Sstevel@tonic-gate 		key = filter_c_next;
12497c478bd9Sstevel@tonic-gate 		for (c = tail; filter_c_next <= c; c--) {
12507c478bd9Sstevel@tonic-gate 			/* OPARATOK is '(' */
12517c478bd9Sstevel@tonic-gate 			if (*c == OPARATOK ||
1252699bceb8Smj 			    *c == SPACETOK) {
12537c478bd9Sstevel@tonic-gate 				key = c + 1;
12547c478bd9Sstevel@tonic-gate 				break;
12557c478bd9Sstevel@tonic-gate 			}
12567c478bd9Sstevel@tonic-gate 		}
12577c478bd9Sstevel@tonic-gate 		info[i]->name_start = key - filter_c + filter;
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 		if ((key + oc_len) <= tail) {
12607c478bd9Sstevel@tonic-gate 			if (strncasecmp(key, "objectclass",
1261699bceb8Smj 			    oc_len) == 0) {
12627c478bd9Sstevel@tonic-gate 				/*
12637c478bd9Sstevel@tonic-gate 				 * assertion is "objectclass=ocname",
12647c478bd9Sstevel@tonic-gate 				 * ocname is the one needs to be mapped
12657c478bd9Sstevel@tonic-gate 				 *
12667c478bd9Sstevel@tonic-gate 				 * skip spaces after "=" to find start
12677c478bd9Sstevel@tonic-gate 				 * of the ocname
12687c478bd9Sstevel@tonic-gate 				 */
12697c478bd9Sstevel@tonic-gate 				head = info[i]->veq_pos;
12707c478bd9Sstevel@tonic-gate 				for (head = info[i]->veq_pos + 1;
1271699bceb8Smj 				    *head && *head == SPACETOK; head++)
1272699bceb8Smj 					;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 				/* ignore empty ocname */
12757c478bd9Sstevel@tonic-gate 				if (!(*head))
12767c478bd9Sstevel@tonic-gate 					continue;
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 				info[i]->name_start = head - filter_c +
1279699bceb8Smj 				    filter;
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 				/*
12827c478bd9Sstevel@tonic-gate 				 * now find the end of the ocname
12837c478bd9Sstevel@tonic-gate 				 */
12847c478bd9Sstevel@tonic-gate 				for (c = head; ; c++) {
12857c478bd9Sstevel@tonic-gate 					/* CPARATOK is ')' */
12867c478bd9Sstevel@tonic-gate 					if (*c == CPARATOK ||
1287699bceb8Smj 					    *c == '\0' ||
1288699bceb8Smj 					    *c == SPACETOK) {
12897c478bd9Sstevel@tonic-gate 						*c = '\0';
12907c478bd9Sstevel@tonic-gate 						info[i]->name_end =
1291699bceb8Smj 						    c - filter_c - 1 +
1292699bceb8Smj 						    filter;
12937c478bd9Sstevel@tonic-gate 						filter_c_next = c + 1;
12947c478bd9Sstevel@tonic-gate 						info[i]->oc_or_attr = 'o';
12957c478bd9Sstevel@tonic-gate 						info[i]->from_name = head;
12967c478bd9Sstevel@tonic-gate 						break;
12977c478bd9Sstevel@tonic-gate 					}
12987c478bd9Sstevel@tonic-gate 				}
12997c478bd9Sstevel@tonic-gate 			}
13007c478bd9Sstevel@tonic-gate 		}
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 		/*
13037c478bd9Sstevel@tonic-gate 		 * assertion is not "objectclass=ocname",
13047c478bd9Sstevel@tonic-gate 		 * assume assertion is "<key> = <value>",
13057c478bd9Sstevel@tonic-gate 		 * <key> is the one needs to be mapped
13067c478bd9Sstevel@tonic-gate 		 */
13077c478bd9Sstevel@tonic-gate 		if (info[i]->from_name == NULL && strlen(key) > 0) {
13087c478bd9Sstevel@tonic-gate 			info[i]->oc_or_attr = 'a';
13097c478bd9Sstevel@tonic-gate 			info[i]->from_name = key;
13107c478bd9Sstevel@tonic-gate 		}
13117c478bd9Sstevel@tonic-gate 	}
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	/* perform schema mapping */
13147c478bd9Sstevel@tonic-gate 	for (i = 0; i < num_veq; i++) {
13157c478bd9Sstevel@tonic-gate 		if (info[i]->from_name == NULL)
13167c478bd9Sstevel@tonic-gate 			continue;
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 		if (info[i]->oc_or_attr == 'a')
13197c478bd9Sstevel@tonic-gate 			info[i]->mapping =
1320699bceb8Smj 			    __ns_ldap_getMappedAttributes(service,
1321699bceb8Smj 			    info[i]->from_name);
13227c478bd9Sstevel@tonic-gate 		else
13237c478bd9Sstevel@tonic-gate 			info[i]->mapping =
1324699bceb8Smj 			    __ns_ldap_getMappedObjectClass(service,
1325699bceb8Smj 			    info[i]->from_name);
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 		if (info[i]->mapping == NULL && auto_service)  {
13287c478bd9Sstevel@tonic-gate 			/*
13297c478bd9Sstevel@tonic-gate 			 * If no mapped attribute/objectclass is found
13307c478bd9Sstevel@tonic-gate 			 * and service == auto*
13317c478bd9Sstevel@tonic-gate 			 * try to find automount's
13327c478bd9Sstevel@tonic-gate 			 * mapped attribute/objectclass
13337c478bd9Sstevel@tonic-gate 			 */
13347c478bd9Sstevel@tonic-gate 			if (info[i]->oc_or_attr == 'a')
13357c478bd9Sstevel@tonic-gate 				info[i]->mapping =
1336699bceb8Smj 				    __ns_ldap_getMappedAttributes("automount",
1337699bceb8Smj 				    info[i]->from_name);
13387c478bd9Sstevel@tonic-gate 			else
13397c478bd9Sstevel@tonic-gate 				info[i]->mapping =
1340699bceb8Smj 				    __ns_ldap_getMappedObjectClass("automount",
1341699bceb8Smj 				    info[i]->from_name);
13427c478bd9Sstevel@tonic-gate 		}
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 		if (info[i]->mapping == NULL ||
1345699bceb8Smj 		    info[i]->mapping[0] == NULL) {
13467c478bd9Sstevel@tonic-gate 			info[i]->to_name = NULL;
13477c478bd9Sstevel@tonic-gate 		} else if (info[i]->mapping[1] == NULL) {
13487c478bd9Sstevel@tonic-gate 			info[i]->to_name = info[i]->mapping[0];
13497c478bd9Sstevel@tonic-gate 			at_least_one = TRUE;
13507c478bd9Sstevel@tonic-gate 		} else {
13517c478bd9Sstevel@tonic-gate 			__s_api_free2dArray(info[i]->mapping);
13527c478bd9Sstevel@tonic-gate 			/*
13537c478bd9Sstevel@tonic-gate 			 * multiple mapping
13547c478bd9Sstevel@tonic-gate 			 * not allowed
13557c478bd9Sstevel@tonic-gate 			 */
13567c478bd9Sstevel@tonic-gate 			(void) sprintf(errstr,
1357699bceb8Smj 			    gettext(
1358699bceb8Smj 			    "Multiple attribute or objectclass "
1359699bceb8Smj 			    "mapping for '%s' in filter "
1360699bceb8Smj 			    "'%s' not allowed."),
1361699bceb8Smj 			    info[i]->from_name, filter);
13627c478bd9Sstevel@tonic-gate 			err = strdup(errstr);
1363a949e73dSToomas Soome 			if (err) {
13647c478bd9Sstevel@tonic-gate 				MKERROR(LOG_WARNING, cookie->errorp,
1365699bceb8Smj 				    NS_CONFIG_SYNTAX,
136651b02b29SToomas Soome 				    err, NS_LDAP_MEMORY);
1367a949e73dSToomas Soome 			}
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 			free(filter_c);
13707c478bd9Sstevel@tonic-gate 			for (j = 0; j < num_veq; j++) {
13717c478bd9Sstevel@tonic-gate 				if (info[j]->mapping)
13727c478bd9Sstevel@tonic-gate 					__s_api_free2dArray(
1373699bceb8Smj 					    info[j]->mapping);
13747c478bd9Sstevel@tonic-gate 				free(info[j]);
13757c478bd9Sstevel@tonic-gate 			}
13767c478bd9Sstevel@tonic-gate 			free(info);
13777c478bd9Sstevel@tonic-gate 			return (NS_LDAP_CONFIG);
13787c478bd9Sstevel@tonic-gate 		}
13797c478bd9Sstevel@tonic-gate 	}
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 	if (at_least_one) {
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 		len = strlen(filter);
13857c478bd9Sstevel@tonic-gate 		last_copied = filter - 1;
13867c478bd9Sstevel@tonic-gate 
13877c478bd9Sstevel@tonic-gate 		for (i = 0; i < num_veq; i++) {
13887c478bd9Sstevel@tonic-gate 			if (info[i]->to_name)
13897c478bd9Sstevel@tonic-gate 				len += strlen(info[i]->to_name);
13907c478bd9Sstevel@tonic-gate 		}
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 		*new_filter = (char *)calloc(1, len);
13937c478bd9Sstevel@tonic-gate 		if (*new_filter == NULL) {
13947c478bd9Sstevel@tonic-gate 			free(filter_c);
13957c478bd9Sstevel@tonic-gate 			for (j = 0; j < num_veq; j++) {
13967c478bd9Sstevel@tonic-gate 				if (info[j]->mapping)
13977c478bd9Sstevel@tonic-gate 					__s_api_free2dArray(
1398699bceb8Smj 					    info[j]->mapping);
13997c478bd9Sstevel@tonic-gate 				free(info[j]);
14007c478bd9Sstevel@tonic-gate 			}
14017c478bd9Sstevel@tonic-gate 			free(info);
14027c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
14037c478bd9Sstevel@tonic-gate 		}
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		for (i = 0; i < num_veq; i++) {
14067c478bd9Sstevel@tonic-gate 			if (info[i]->to_name != NULL &&
1407699bceb8Smj 			    info[i]->to_name != NULL) {
14087c478bd9Sstevel@tonic-gate 
1409699bceb8Smj 				/*
1410699bceb8Smj 				 * copy the original filter data
1411699bceb8Smj 				 * between the last name and current
1412699bceb8Smj 				 * name
1413699bceb8Smj 				 */
1414699bceb8Smj 				if ((last_copied + 1) != info[i]->name_start)
1415699bceb8Smj 					(void) strncat(*new_filter,
1416699bceb8Smj 					    last_copied + 1,
1417699bceb8Smj 					    info[i]->name_start -
1418699bceb8Smj 					    last_copied - 1);
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 				/* the data is copied */
14217c478bd9Sstevel@tonic-gate 				last_copied = info[i]->name_end;
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 				/*
14247c478bd9Sstevel@tonic-gate 				 * replace the name with
14257c478bd9Sstevel@tonic-gate 				 * the mapped name
14267c478bd9Sstevel@tonic-gate 				 */
14277c478bd9Sstevel@tonic-gate 				(void) strcat(*new_filter, info[i]->to_name);
14287c478bd9Sstevel@tonic-gate 			}
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 			/* copy the filter data after the last name */
14317c478bd9Sstevel@tonic-gate 			if (i == (num_veq -1) &&
1432699bceb8Smj 			    info[i]->name_end <
1433699bceb8Smj 			    (filter + strlen(filter)))
14347c478bd9Sstevel@tonic-gate 				(void) strncat(*new_filter, last_copied + 1,
1435699bceb8Smj 				    filter + strlen(filter) -
1436699bceb8Smj 				    last_copied - 1);
14377c478bd9Sstevel@tonic-gate 		}
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	}
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	/* free memory */
14427c478bd9Sstevel@tonic-gate 	free(filter_c);
14437c478bd9Sstevel@tonic-gate 	for (j = 0; j < num_veq; j++) {
14447c478bd9Sstevel@tonic-gate 		if (info[j]->mapping)
14457c478bd9Sstevel@tonic-gate 			__s_api_free2dArray(info[j]->mapping);
14467c478bd9Sstevel@tonic-gate 		free(info[j]);
14477c478bd9Sstevel@tonic-gate 	}
14487c478bd9Sstevel@tonic-gate 	free(info);
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
14517c478bd9Sstevel@tonic-gate }
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate static int
setup_next_search(ns_ldap_cookie_t * cookie)14547c478bd9Sstevel@tonic-gate setup_next_search(ns_ldap_cookie_t *cookie)
14557c478bd9Sstevel@tonic-gate {
14567c478bd9Sstevel@tonic-gate 	ns_ldap_search_desc_t	*dptr;
14577c478bd9Sstevel@tonic-gate 	int			scope;
14587c478bd9Sstevel@tonic-gate 	char			*filter, *str;
14597c478bd9Sstevel@tonic-gate 	int			baselen;
14607c478bd9Sstevel@tonic-gate 	int			rc;
14617c478bd9Sstevel@tonic-gate 	void			**param;
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	dptr = *cookie->sdpos;
14647c478bd9Sstevel@tonic-gate 	scope = cookie->i_flags & (NS_LDAP_SCOPE_BASE |
1465699bceb8Smj 	    NS_LDAP_SCOPE_ONELEVEL |
1466699bceb8Smj 	    NS_LDAP_SCOPE_SUBTREE);
14677c478bd9Sstevel@tonic-gate 	if (scope)
14687c478bd9Sstevel@tonic-gate 		cookie->scope = scope;
14697c478bd9Sstevel@tonic-gate 	else
14707c478bd9Sstevel@tonic-gate 		cookie->scope = dptr->scope;
14717c478bd9Sstevel@tonic-gate 	switch (cookie->scope) {
14727c478bd9Sstevel@tonic-gate 	case NS_LDAP_SCOPE_BASE:
14737c478bd9Sstevel@tonic-gate 		cookie->scope = LDAP_SCOPE_BASE;
14747c478bd9Sstevel@tonic-gate 		break;
14757c478bd9Sstevel@tonic-gate 	case NS_LDAP_SCOPE_ONELEVEL:
14767c478bd9Sstevel@tonic-gate 		cookie->scope = LDAP_SCOPE_ONELEVEL;
14777c478bd9Sstevel@tonic-gate 		break;
14787c478bd9Sstevel@tonic-gate 	case NS_LDAP_SCOPE_SUBTREE:
14797c478bd9Sstevel@tonic-gate 		cookie->scope = LDAP_SCOPE_SUBTREE;
14807c478bd9Sstevel@tonic-gate 		break;
14817c478bd9Sstevel@tonic-gate 	}
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	filter = NULL;
14847c478bd9Sstevel@tonic-gate 	if (cookie->use_filtercb && cookie->init_filter_cb &&
1485699bceb8Smj 	    dptr->filter && strlen(dptr->filter) > 0) {
14867c478bd9Sstevel@tonic-gate 		(*cookie->init_filter_cb)(dptr, &filter,
1487699bceb8Smj 		    cookie->userdata);
14887c478bd9Sstevel@tonic-gate 	}
14897c478bd9Sstevel@tonic-gate 	if (filter == NULL) {
14907c478bd9Sstevel@tonic-gate 		if (cookie->i_filter == NULL) {
14917c478bd9Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INVALID_PARAM;
14927c478bd9Sstevel@tonic-gate 			return (-1);
14937c478bd9Sstevel@tonic-gate 		} else {
149436cd58d3Srm 			if (cookie->filter)
149536cd58d3Srm 				free(cookie->filter);
14967c478bd9Sstevel@tonic-gate 			cookie->filter = strdup(cookie->i_filter);
14977c478bd9Sstevel@tonic-gate 			if (cookie->filter == NULL) {
14987c478bd9Sstevel@tonic-gate 				cookie->err_rc = NS_LDAP_MEMORY;
14997c478bd9Sstevel@tonic-gate 				return (-1);
15007c478bd9Sstevel@tonic-gate 			}
15017c478bd9Sstevel@tonic-gate 		}
15027c478bd9Sstevel@tonic-gate 	} else {
150336cd58d3Srm 		if (cookie->filter)
150436cd58d3Srm 			free(cookie->filter);
15057c478bd9Sstevel@tonic-gate 		cookie->filter = strdup(filter);
15067c478bd9Sstevel@tonic-gate 		free(filter);
15077c478bd9Sstevel@tonic-gate 		if (cookie->filter == NULL) {
15087c478bd9Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_MEMORY;
15097c478bd9Sstevel@tonic-gate 			return (-1);
15107c478bd9Sstevel@tonic-gate 		}
15117c478bd9Sstevel@tonic-gate 	}
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 	/*
15147c478bd9Sstevel@tonic-gate 	 * perform attribute/objectclass mapping on filter
15157c478bd9Sstevel@tonic-gate 	 */
15167c478bd9Sstevel@tonic-gate 	filter = NULL;
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	if (cookie->service) {
15197c478bd9Sstevel@tonic-gate 		rc = get_mapped_filter(cookie, &filter);
15207c478bd9Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
15217c478bd9Sstevel@tonic-gate 			cookie->err_rc = rc;
15227c478bd9Sstevel@tonic-gate 			return (-1);
15237c478bd9Sstevel@tonic-gate 		} else {
15247c478bd9Sstevel@tonic-gate 			/*
15257c478bd9Sstevel@tonic-gate 			 * get_mapped_filter returns
15267c478bd9Sstevel@tonic-gate 			 * NULL filter pointer, if
15277c478bd9Sstevel@tonic-gate 			 * no mapping was done
15287c478bd9Sstevel@tonic-gate 			 */
15297c478bd9Sstevel@tonic-gate 			if (filter) {
15307c478bd9Sstevel@tonic-gate 				free(cookie->filter);
15317c478bd9Sstevel@tonic-gate 				cookie->filter = filter;
15327c478bd9Sstevel@tonic-gate 			}
15337c478bd9Sstevel@tonic-gate 		}
15347c478bd9Sstevel@tonic-gate 	}
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 	/*
15377c478bd9Sstevel@tonic-gate 	 * validate filter to make sure it's legal
15387c478bd9Sstevel@tonic-gate 	 * [remove redundant ()'s]
15397c478bd9Sstevel@tonic-gate 	 */
15407c478bd9Sstevel@tonic-gate 	rc = validate_filter(cookie);
15417c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
15427c478bd9Sstevel@tonic-gate 		cookie->err_rc = rc;
15437c478bd9Sstevel@tonic-gate 		return (-1);
15447c478bd9Sstevel@tonic-gate 	}
15457c478bd9Sstevel@tonic-gate 
15467c478bd9Sstevel@tonic-gate 	baselen = strlen(dptr->basedn);
15477c478bd9Sstevel@tonic-gate 	if (baselen > 0 && dptr->basedn[baselen-1] == COMMATOK) {
15487c478bd9Sstevel@tonic-gate 		rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
1549699bceb8Smj 		    (void ***)&param, &cookie->errorp);
15507c478bd9Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
15517c478bd9Sstevel@tonic-gate 			cookie->err_rc = rc;
15527c478bd9Sstevel@tonic-gate 			return (-1);
15537c478bd9Sstevel@tonic-gate 		}
15547c478bd9Sstevel@tonic-gate 		str = ((char **)param)[0];
15557c478bd9Sstevel@tonic-gate 		baselen += strlen(str)+1;
155636cd58d3Srm 		if (cookie->basedn)
155736cd58d3Srm 			free(cookie->basedn);
15587c478bd9Sstevel@tonic-gate 		cookie->basedn = (char *)malloc(baselen);
15597c478bd9Sstevel@tonic-gate 		if (cookie->basedn == NULL) {
15607c478bd9Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_MEMORY;
15617c478bd9Sstevel@tonic-gate 			return (-1);
15627c478bd9Sstevel@tonic-gate 		}
15637c478bd9Sstevel@tonic-gate 		(void) strcpy(cookie->basedn, dptr->basedn);
15647c478bd9Sstevel@tonic-gate 		(void) strcat(cookie->basedn, str);
15657c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeParam(&param);
15667c478bd9Sstevel@tonic-gate 	} else {
156736cd58d3Srm 		if (cookie->basedn)
156836cd58d3Srm 			free(cookie->basedn);
15697c478bd9Sstevel@tonic-gate 		cookie->basedn = strdup(dptr->basedn);
15707c478bd9Sstevel@tonic-gate 	}
15717c478bd9Sstevel@tonic-gate 	return (0);
15727c478bd9Sstevel@tonic-gate }
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate static int
setup_referral_search(ns_ldap_cookie_t * cookie)15757c478bd9Sstevel@tonic-gate setup_referral_search(ns_ldap_cookie_t *cookie)
15767c478bd9Sstevel@tonic-gate {
15777c478bd9Sstevel@tonic-gate 	ns_referral_info_t	*ref;
15787c478bd9Sstevel@tonic-gate 
15797c478bd9Sstevel@tonic-gate 	ref = cookie->refpos;
15807c478bd9Sstevel@tonic-gate 	cookie->scope = ref->refScope;
15817c478bd9Sstevel@tonic-gate 	if (cookie->filter) {
15827c478bd9Sstevel@tonic-gate 		free(cookie->filter);
15837c478bd9Sstevel@tonic-gate 	}
15847c478bd9Sstevel@tonic-gate 	cookie->filter = strdup(ref->refFilter);
15857c478bd9Sstevel@tonic-gate 	if (cookie->basedn) {
15867c478bd9Sstevel@tonic-gate 		free(cookie->basedn);
15877c478bd9Sstevel@tonic-gate 	}
15887c478bd9Sstevel@tonic-gate 	cookie->basedn = strdup(ref->refDN);
15897c478bd9Sstevel@tonic-gate 	if (cookie->filter == NULL || cookie->basedn == NULL) {
15907c478bd9Sstevel@tonic-gate 		cookie->err_rc = NS_LDAP_MEMORY;
15917c478bd9Sstevel@tonic-gate 		return (-1);
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 	return (0);
15947c478bd9Sstevel@tonic-gate }
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate static int
get_current_session(ns_ldap_cookie_t * cookie)15977c478bd9Sstevel@tonic-gate get_current_session(ns_ldap_cookie_t *cookie)
15987c478bd9Sstevel@tonic-gate {
15997c478bd9Sstevel@tonic-gate 	ConnectionID	connectionId = -1;
16007c478bd9Sstevel@tonic-gate 	Connection	*conp = NULL;
16017c478bd9Sstevel@tonic-gate 	int		rc;
16027c478bd9Sstevel@tonic-gate 	int		fail_if_new_pwd_reqd = 1;
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	rc = __s_api_getConnection(NULL, cookie->i_flags,
1605699bceb8Smj 	    cookie->i_auth, &connectionId, &conp,
1606699bceb8Smj 	    &cookie->errorp, fail_if_new_pwd_reqd,
1607e1dd0a2fSth 	    cookie->nopasswd_acct_mgmt, cookie->conn_user);
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate 	/*
16107c478bd9Sstevel@tonic-gate 	 * If password control attached in *cookie->errorp,
16117c478bd9Sstevel@tonic-gate 	 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
16127c478bd9Sstevel@tonic-gate 	 * free the error structure (we do not need
16137c478bd9Sstevel@tonic-gate 	 * the sec_to_expired info).
16147c478bd9Sstevel@tonic-gate 	 * Reset rc to NS_LDAP_SUCCESS.
16157c478bd9Sstevel@tonic-gate 	 */
16167c478bd9Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
16177c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeError(
1618699bceb8Smj 		    &cookie->errorp);
16197c478bd9Sstevel@tonic-gate 		cookie->errorp = NULL;
16207c478bd9Sstevel@tonic-gate 		rc = NS_LDAP_SUCCESS;
16217c478bd9Sstevel@tonic-gate 	}
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
16247c478bd9Sstevel@tonic-gate 		cookie->err_rc = rc;
16257c478bd9Sstevel@tonic-gate 		return (-1);
16267c478bd9Sstevel@tonic-gate 	}
16277c478bd9Sstevel@tonic-gate 	cookie->conn = conp;
16287c478bd9Sstevel@tonic-gate 	cookie->connectionId = connectionId;
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	return (0);
16317c478bd9Sstevel@tonic-gate }
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate static int
get_next_session(ns_ldap_cookie_t * cookie)16347c478bd9Sstevel@tonic-gate get_next_session(ns_ldap_cookie_t *cookie)
16357c478bd9Sstevel@tonic-gate {
16367c478bd9Sstevel@tonic-gate 	ConnectionID	connectionId = -1;
16377c478bd9Sstevel@tonic-gate 	Connection	*conp = NULL;
16387c478bd9Sstevel@tonic-gate 	int		rc;
16397c478bd9Sstevel@tonic-gate 	int		fail_if_new_pwd_reqd = 1;
16407c478bd9Sstevel@tonic-gate 
16413d047983Smichen 	if (cookie->connectionId > -1) {
16427c478bd9Sstevel@tonic-gate 		DropConnection(cookie->connectionId, cookie->i_flags);
16433d047983Smichen 		cookie->connectionId = -1;
16443d047983Smichen 	}
16457c478bd9Sstevel@tonic-gate 
1646e1dd0a2fSth 	/* If using a MT connection, return it. */
1647e1dd0a2fSth 	if (cookie->conn_user != NULL &&
1648e1dd0a2fSth 	    cookie->conn_user->conn_mt != NULL)
1649e1dd0a2fSth 		__s_api_conn_mt_return(cookie->conn_user);
1650e1dd0a2fSth 
16517c478bd9Sstevel@tonic-gate 	rc = __s_api_getConnection(NULL, cookie->i_flags,
1652699bceb8Smj 	    cookie->i_auth, &connectionId, &conp,
1653699bceb8Smj 	    &cookie->errorp, fail_if_new_pwd_reqd,
1654e1dd0a2fSth 	    cookie->nopasswd_acct_mgmt, cookie->conn_user);
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	/*
16577c478bd9Sstevel@tonic-gate 	 * If password control attached in *cookie->errorp,
16587c478bd9Sstevel@tonic-gate 	 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
16597c478bd9Sstevel@tonic-gate 	 * free the error structure (we do not need
16607c478bd9Sstevel@tonic-gate 	 * the sec_to_expired info).
16617c478bd9Sstevel@tonic-gate 	 * Reset rc to NS_LDAP_SUCCESS.
16627c478bd9Sstevel@tonic-gate 	 */
16637c478bd9Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
16647c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeError(
1665699bceb8Smj 		    &cookie->errorp);
16667c478bd9Sstevel@tonic-gate 		cookie->errorp = NULL;
16677c478bd9Sstevel@tonic-gate 		rc = NS_LDAP_SUCCESS;
16687c478bd9Sstevel@tonic-gate 	}
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
16717c478bd9Sstevel@tonic-gate 		cookie->err_rc = rc;
16727c478bd9Sstevel@tonic-gate 		return (-1);
16737c478bd9Sstevel@tonic-gate 	}
16747c478bd9Sstevel@tonic-gate 	cookie->conn = conp;
16757c478bd9Sstevel@tonic-gate 	cookie->connectionId = connectionId;
16767c478bd9Sstevel@tonic-gate 	return (0);
16777c478bd9Sstevel@tonic-gate }
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate static int
get_referral_session(ns_ldap_cookie_t * cookie)16807c478bd9Sstevel@tonic-gate get_referral_session(ns_ldap_cookie_t *cookie)
16817c478bd9Sstevel@tonic-gate {
16827c478bd9Sstevel@tonic-gate 	ConnectionID	connectionId = -1;
16837c478bd9Sstevel@tonic-gate 	Connection	*conp = NULL;
16847c478bd9Sstevel@tonic-gate 	int		rc;
16857c478bd9Sstevel@tonic-gate 	int		fail_if_new_pwd_reqd = 1;
16867c478bd9Sstevel@tonic-gate 
16873d047983Smichen 	if (cookie->connectionId > -1) {
16887c478bd9Sstevel@tonic-gate 		DropConnection(cookie->connectionId, cookie->i_flags);
16893d047983Smichen 		cookie->connectionId = -1;
16903d047983Smichen 	}
16917c478bd9Sstevel@tonic-gate 
1692e1dd0a2fSth 	/* set it up to use a connection opened for referral */
1693e1dd0a2fSth 	if (cookie->conn_user != NULL) {
1694e1dd0a2fSth 		/* If using a MT connection, return it. */
1695e1dd0a2fSth 		if (cookie->conn_user->conn_mt != NULL)
1696e1dd0a2fSth 			__s_api_conn_mt_return(cookie->conn_user);
1697e1dd0a2fSth 		cookie->conn_user->referral = B_TRUE;
1698e1dd0a2fSth 	}
1699e1dd0a2fSth 
17007c478bd9Sstevel@tonic-gate 	rc = __s_api_getConnection(cookie->refpos->refHost, 0,
1701699bceb8Smj 	    cookie->i_auth, &connectionId, &conp,
1702699bceb8Smj 	    &cookie->errorp, fail_if_new_pwd_reqd,
1703e1dd0a2fSth 	    cookie->nopasswd_acct_mgmt, cookie->conn_user);
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	/*
17067c478bd9Sstevel@tonic-gate 	 * If password control attached in *cookie->errorp,
17077c478bd9Sstevel@tonic-gate 	 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
17087c478bd9Sstevel@tonic-gate 	 * free the error structure (we do not need
17097c478bd9Sstevel@tonic-gate 	 * the sec_to_expired info).
17107c478bd9Sstevel@tonic-gate 	 * Reset rc to NS_LDAP_SUCCESS.
17117c478bd9Sstevel@tonic-gate 	 */
17127c478bd9Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
17137c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeError(
1714699bceb8Smj 		    &cookie->errorp);
17157c478bd9Sstevel@tonic-gate 		cookie->errorp = NULL;
17167c478bd9Sstevel@tonic-gate 		rc = NS_LDAP_SUCCESS;
17177c478bd9Sstevel@tonic-gate 	}
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
17207c478bd9Sstevel@tonic-gate 		cookie->err_rc = rc;
17217c478bd9Sstevel@tonic-gate 		return (-1);
17227c478bd9Sstevel@tonic-gate 	}
17237c478bd9Sstevel@tonic-gate 	cookie->conn = conp;
17247c478bd9Sstevel@tonic-gate 	cookie->connectionId = connectionId;
17257c478bd9Sstevel@tonic-gate 	return (0);
17267c478bd9Sstevel@tonic-gate }
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate static int
paging_supported(ns_ldap_cookie_t * cookie)17297c478bd9Sstevel@tonic-gate paging_supported(ns_ldap_cookie_t *cookie)
17307c478bd9Sstevel@tonic-gate {
17317c478bd9Sstevel@tonic-gate 	int		rc;
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate 	cookie->listType = 0;
17347c478bd9Sstevel@tonic-gate 	rc = __s_api_isCtrlSupported(cookie->conn,
1735699bceb8Smj 	    LDAP_CONTROL_VLVREQUEST);
17367c478bd9Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS) {
17377c478bd9Sstevel@tonic-gate 		cookie->listType = VLVCTRLFLAG;
17387c478bd9Sstevel@tonic-gate 		return (1);
17397c478bd9Sstevel@tonic-gate 	}
17407c478bd9Sstevel@tonic-gate 	rc = __s_api_isCtrlSupported(cookie->conn,
1741699bceb8Smj 	    LDAP_CONTROL_SIMPLE_PAGE);
17427c478bd9Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS) {
17437c478bd9Sstevel@tonic-gate 		cookie->listType = SIMPLEPAGECTRLFLAG;
17447c478bd9Sstevel@tonic-gate 		return (1);
17457c478bd9Sstevel@tonic-gate 	}
17467c478bd9Sstevel@tonic-gate 	return (0);
17477c478bd9Sstevel@tonic-gate }
17487c478bd9Sstevel@tonic-gate 
17499f2fd570SJulian Pullen typedef struct servicesorttype {
17509f2fd570SJulian Pullen 	char *service;
17519f2fd570SJulian Pullen 	ns_srvsidesort_t type;
17529f2fd570SJulian Pullen } servicesorttype_t;
17539f2fd570SJulian Pullen 
17549f2fd570SJulian Pullen static servicesorttype_t *sort_type = NULL;
17559f2fd570SJulian Pullen static int sort_type_size = 0;
17569f2fd570SJulian Pullen static int sort_type_hwm = 0;
17579f2fd570SJulian Pullen static mutex_t sort_type_mutex = DEFAULTMUTEX;
17589f2fd570SJulian Pullen 
17599f2fd570SJulian Pullen 
17609f2fd570SJulian Pullen static ns_srvsidesort_t
get_srvsidesort_type(char * service)17619f2fd570SJulian Pullen get_srvsidesort_type(char *service)
17629f2fd570SJulian Pullen {
17639f2fd570SJulian Pullen 	int i;
17649f2fd570SJulian Pullen 	ns_srvsidesort_t type = SSS_UNKNOWN;
17659f2fd570SJulian Pullen 
17669f2fd570SJulian Pullen 	if (service == NULL)
17679f2fd570SJulian Pullen 		return (type);
17689f2fd570SJulian Pullen 
17699f2fd570SJulian Pullen 	(void) mutex_lock(&sort_type_mutex);
17709f2fd570SJulian Pullen 	if (sort_type != NULL) {
17719f2fd570SJulian Pullen 		for (i = 0; i < sort_type_hwm; i++) {
17729f2fd570SJulian Pullen 			if (strcmp(sort_type[i].service, service) == 0) {
17739f2fd570SJulian Pullen 				type = sort_type[i].type;
17749f2fd570SJulian Pullen 				break;
17759f2fd570SJulian Pullen 			}
17769f2fd570SJulian Pullen 		}
17779f2fd570SJulian Pullen 	}
17789f2fd570SJulian Pullen 	(void) mutex_unlock(&sort_type_mutex);
17799f2fd570SJulian Pullen 	return (type);
17809f2fd570SJulian Pullen }
17819f2fd570SJulian Pullen 
17829f2fd570SJulian Pullen static void
update_srvsidesort_type(char * service,ns_srvsidesort_t type)17839f2fd570SJulian Pullen update_srvsidesort_type(char *service, ns_srvsidesort_t type)
17849f2fd570SJulian Pullen {
17859f2fd570SJulian Pullen 	int i, size;
17869f2fd570SJulian Pullen 	servicesorttype_t *tmp;
17879f2fd570SJulian Pullen 
17889f2fd570SJulian Pullen 	if (service == NULL)
17899f2fd570SJulian Pullen 		return;
17909f2fd570SJulian Pullen 
17919f2fd570SJulian Pullen 	(void) mutex_lock(&sort_type_mutex);
17929f2fd570SJulian Pullen 
17939f2fd570SJulian Pullen 	for (i = 0; i < sort_type_hwm; i++) {
17949f2fd570SJulian Pullen 		if (strcmp(sort_type[i].service, service) == 0) {
17959f2fd570SJulian Pullen 			sort_type[i].type = type;
17969f2fd570SJulian Pullen 			(void) mutex_unlock(&sort_type_mutex);
17979f2fd570SJulian Pullen 			return;
17989f2fd570SJulian Pullen 		}
17999f2fd570SJulian Pullen 	}
18009f2fd570SJulian Pullen 	if (sort_type == NULL) {
18019f2fd570SJulian Pullen 		size = 10;
18029f2fd570SJulian Pullen 		tmp = malloc(size * sizeof (servicesorttype_t));
18039f2fd570SJulian Pullen 		if (tmp == NULL) {
18049f2fd570SJulian Pullen 			(void) mutex_unlock(&sort_type_mutex);
18059f2fd570SJulian Pullen 			return;
18069f2fd570SJulian Pullen 		}
18079f2fd570SJulian Pullen 		sort_type = tmp;
18089f2fd570SJulian Pullen 		sort_type_size = size;
18099f2fd570SJulian Pullen 	} else if (sort_type_hwm >= sort_type_size) {
18109f2fd570SJulian Pullen 		size = sort_type_size + 10;
18119f2fd570SJulian Pullen 		tmp = realloc(sort_type, size * sizeof (servicesorttype_t));
18129f2fd570SJulian Pullen 		if (tmp == NULL) {
18139f2fd570SJulian Pullen 			(void) mutex_unlock(&sort_type_mutex);
18149f2fd570SJulian Pullen 			return;
18159f2fd570SJulian Pullen 		}
18169f2fd570SJulian Pullen 		sort_type = tmp;
18179f2fd570SJulian Pullen 		sort_type_size = size;
18189f2fd570SJulian Pullen 	}
18199f2fd570SJulian Pullen 	sort_type[sort_type_hwm].service = strdup(service);
18209f2fd570SJulian Pullen 	if (sort_type[sort_type_hwm].service == NULL) {
18219f2fd570SJulian Pullen 		(void) mutex_unlock(&sort_type_mutex);
18229f2fd570SJulian Pullen 		return;
18239f2fd570SJulian Pullen 	}
18249f2fd570SJulian Pullen 	sort_type[sort_type_hwm].type = type;
18259f2fd570SJulian Pullen 	sort_type_hwm++;
18269f2fd570SJulian Pullen 
18279f2fd570SJulian Pullen 	(void) mutex_unlock(&sort_type_mutex);
18289f2fd570SJulian Pullen }
18299f2fd570SJulian Pullen 
18307c478bd9Sstevel@tonic-gate static int
setup_vlv_params(ns_ldap_cookie_t * cookie)18317c478bd9Sstevel@tonic-gate setup_vlv_params(ns_ldap_cookie_t *cookie)
18327c478bd9Sstevel@tonic-gate {
18337c478bd9Sstevel@tonic-gate 	LDAPControl	**ctrls;
18347c478bd9Sstevel@tonic-gate 	LDAPsortkey	**sortkeylist;
18357c478bd9Sstevel@tonic-gate 	LDAPControl	*sortctrl = NULL;
18367c478bd9Sstevel@tonic-gate 	LDAPControl	*vlvctrl = NULL;
18377c478bd9Sstevel@tonic-gate 	LDAPVirtualList	vlist;
18389f2fd570SJulian Pullen 	char		*sortattr;
18397c478bd9Sstevel@tonic-gate 	int		rc;
18409f2fd570SJulian Pullen 	int		free_sort = FALSE;
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	_freeControlList(&cookie->p_serverctrls);
18437c478bd9Sstevel@tonic-gate 
18449f2fd570SJulian Pullen 	if (cookie->sortTypeTry == SSS_UNKNOWN)
18459f2fd570SJulian Pullen 		cookie->sortTypeTry = get_srvsidesort_type(cookie->service);
18469f2fd570SJulian Pullen 	if (cookie->sortTypeTry == SSS_UNKNOWN)
18479f2fd570SJulian Pullen 		cookie->sortTypeTry = SSS_SINGLE_ATTR;
18489f2fd570SJulian Pullen 
18499f2fd570SJulian Pullen 	if (cookie->sortTypeTry == SSS_SINGLE_ATTR) {
18509f2fd570SJulian Pullen 		if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
18519f2fd570SJulian Pullen 		    cookie->i_sortattr) {
18529f2fd570SJulian Pullen 			sortattr =  __ns_ldap_mapAttribute(cookie->service,
18539f2fd570SJulian Pullen 			    cookie->i_sortattr);
18549f2fd570SJulian Pullen 			free_sort = TRUE;
18559f2fd570SJulian Pullen 		} else if (cookie->i_sortattr) {
18569f2fd570SJulian Pullen 			sortattr = (char *)cookie->i_sortattr;
18579f2fd570SJulian Pullen 		} else {
18589f2fd570SJulian Pullen 			sortattr = "cn";
18599f2fd570SJulian Pullen 		}
18609f2fd570SJulian Pullen 	} else {
18619f2fd570SJulian Pullen 		sortattr = "cn uid";
18629f2fd570SJulian Pullen 	}
18639f2fd570SJulian Pullen 
18649f2fd570SJulian Pullen 	rc = ldap_create_sort_keylist(&sortkeylist, sortattr);
18659f2fd570SJulian Pullen 	if (free_sort)
18669f2fd570SJulian Pullen 		free(sortattr);
18677c478bd9Sstevel@tonic-gate 	if (rc != LDAP_SUCCESS) {
18687c478bd9Sstevel@tonic-gate 		(void) ldap_get_option(cookie->conn->ld,
1869699bceb8Smj 		    LDAP_OPT_ERROR_NUMBER, &rc);
18707c478bd9Sstevel@tonic-gate 		return (rc);
18717c478bd9Sstevel@tonic-gate 	}
18727c478bd9Sstevel@tonic-gate 	rc = ldap_create_sort_control(cookie->conn->ld,
1873699bceb8Smj 	    sortkeylist, 1, &sortctrl);
18747c478bd9Sstevel@tonic-gate 	ldap_free_sort_keylist(sortkeylist);
18757c478bd9Sstevel@tonic-gate 	if (rc != LDAP_SUCCESS) {
18767c478bd9Sstevel@tonic-gate 		(void) ldap_get_option(cookie->conn->ld,
1877699bceb8Smj 		    LDAP_OPT_ERROR_NUMBER, &rc);
18787c478bd9Sstevel@tonic-gate 		return (rc);
18797c478bd9Sstevel@tonic-gate 	}
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 	vlist.ldvlist_index = cookie->index;
18827c478bd9Sstevel@tonic-gate 	vlist.ldvlist_size = 0;
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	vlist.ldvlist_before_count = 0;
18857c478bd9Sstevel@tonic-gate 	vlist.ldvlist_after_count = LISTPAGESIZE-1;
18867c478bd9Sstevel@tonic-gate 	vlist.ldvlist_attrvalue = NULL;
18877c478bd9Sstevel@tonic-gate 	vlist.ldvlist_extradata = NULL;
18887c478bd9Sstevel@tonic-gate 
18897c478bd9Sstevel@tonic-gate 	rc = ldap_create_virtuallist_control(cookie->conn->ld,
1890699bceb8Smj 	    &vlist, &vlvctrl);
18917c478bd9Sstevel@tonic-gate 	if (rc != LDAP_SUCCESS) {
18927c478bd9Sstevel@tonic-gate 		ldap_control_free(sortctrl);
18937c478bd9Sstevel@tonic-gate 		(void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1894699bceb8Smj 		    &rc);
18957c478bd9Sstevel@tonic-gate 		return (rc);
18967c478bd9Sstevel@tonic-gate 	}
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	ctrls = (LDAPControl **)calloc(3, sizeof (LDAPControl *));
18997c478bd9Sstevel@tonic-gate 	if (ctrls == NULL) {
19007c478bd9Sstevel@tonic-gate 		ldap_control_free(sortctrl);
19017c478bd9Sstevel@tonic-gate 		ldap_control_free(vlvctrl);
19027c478bd9Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
19037c478bd9Sstevel@tonic-gate 	}
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	ctrls[0] = sortctrl;
19067c478bd9Sstevel@tonic-gate 	ctrls[1] = vlvctrl;
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	cookie->p_serverctrls = ctrls;
19097c478bd9Sstevel@tonic-gate 	return (LDAP_SUCCESS);
19107c478bd9Sstevel@tonic-gate }
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate static int
setup_simplepg_params(ns_ldap_cookie_t * cookie)19137c478bd9Sstevel@tonic-gate setup_simplepg_params(ns_ldap_cookie_t *cookie)
19147c478bd9Sstevel@tonic-gate {
19157c478bd9Sstevel@tonic-gate 	LDAPControl	**ctrls;
19167c478bd9Sstevel@tonic-gate 	LDAPControl	*pgctrl = NULL;
19177c478bd9Sstevel@tonic-gate 	int		rc;
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate 	_freeControlList(&cookie->p_serverctrls);
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 	rc = ldap_create_page_control(cookie->conn->ld, LISTPAGESIZE,
1922699bceb8Smj 	    cookie->ctrlCookie, (char)0, &pgctrl);
19237c478bd9Sstevel@tonic-gate 	if (rc != LDAP_SUCCESS) {
19247c478bd9Sstevel@tonic-gate 		(void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
1925699bceb8Smj 		    &rc);
19267c478bd9Sstevel@tonic-gate 		return (rc);
19277c478bd9Sstevel@tonic-gate 	}
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 	ctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
19307c478bd9Sstevel@tonic-gate 	if (ctrls == NULL) {
19317c478bd9Sstevel@tonic-gate 		ldap_control_free(pgctrl);
19327c478bd9Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
19337c478bd9Sstevel@tonic-gate 	}
19347c478bd9Sstevel@tonic-gate 	ctrls[0] = pgctrl;
19357c478bd9Sstevel@tonic-gate 	cookie->p_serverctrls = ctrls;
19367c478bd9Sstevel@tonic-gate 	return (LDAP_SUCCESS);
19377c478bd9Sstevel@tonic-gate }
19387c478bd9Sstevel@tonic-gate 
19397c478bd9Sstevel@tonic-gate static void
proc_result_referrals(ns_ldap_cookie_t * cookie)19407c478bd9Sstevel@tonic-gate proc_result_referrals(ns_ldap_cookie_t *cookie)
19417c478bd9Sstevel@tonic-gate {
19428f0bb794SToomas Soome 	int		errCode, i, rc;
19438f0bb794SToomas Soome 	char		**referrals = NULL;
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate 	/*
19467c478bd9Sstevel@tonic-gate 	 * Only follow one level of referrals, i.e.
19477c478bd9Sstevel@tonic-gate 	 * if already in referral mode, do nothing
19487c478bd9Sstevel@tonic-gate 	 */
19497c478bd9Sstevel@tonic-gate 	if (cookie->refpos == NULL) {
19507c478bd9Sstevel@tonic-gate 		cookie->new_state = END_RESULT;
19517c478bd9Sstevel@tonic-gate 		rc = ldap_parse_result(cookie->conn->ld,
1952699bceb8Smj 		    cookie->resultMsg,
1953699bceb8Smj 		    &errCode, NULL,
1954699bceb8Smj 		    NULL, &referrals,
1955699bceb8Smj 		    NULL, 0);
19567c478bd9Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
19577c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(cookie->conn->ld,
1958699bceb8Smj 			    LDAP_OPT_ERROR_NUMBER,
1959699bceb8Smj 			    &cookie->err_rc);
19607c478bd9Sstevel@tonic-gate 			cookie->new_state = LDAP_ERROR;
19617c478bd9Sstevel@tonic-gate 			return;
19627c478bd9Sstevel@tonic-gate 		}
19637c478bd9Sstevel@tonic-gate 		if (errCode == LDAP_REFERRAL) {
19647c478bd9Sstevel@tonic-gate 			for (i = 0; referrals[i] != NULL;
1965699bceb8Smj 			    i++) {
19667c478bd9Sstevel@tonic-gate 				/* add to referral list */
19677c478bd9Sstevel@tonic-gate 				rc = __s_api_addRefInfo(
1968699bceb8Smj 				    &cookie->reflist,
1969699bceb8Smj 				    referrals[i],
1970699bceb8Smj 				    cookie->basedn,
1971699bceb8Smj 				    &cookie->scope,
1972699bceb8Smj 				    cookie->filter,
1973699bceb8Smj 				    cookie->conn->ld);
19747c478bd9Sstevel@tonic-gate 				if (rc != NS_LDAP_SUCCESS) {
19757c478bd9Sstevel@tonic-gate 					cookie->new_state =
1976699bceb8Smj 					    ERROR;
19777c478bd9Sstevel@tonic-gate 					break;
19787c478bd9Sstevel@tonic-gate 				}
19797c478bd9Sstevel@tonic-gate 			}
19807c478bd9Sstevel@tonic-gate 			ldap_value_free(referrals);
19817c478bd9Sstevel@tonic-gate 		}
19827c478bd9Sstevel@tonic-gate 	}
19837c478bd9Sstevel@tonic-gate }
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate static void
proc_search_references(ns_ldap_cookie_t * cookie)19867c478bd9Sstevel@tonic-gate proc_search_references(ns_ldap_cookie_t *cookie)
19877c478bd9Sstevel@tonic-gate {
19888f0bb794SToomas Soome 	char		**refurls = NULL;
19898f0bb794SToomas Soome 	int		i, rc;
19907c478bd9Sstevel@tonic-gate 
19917c478bd9Sstevel@tonic-gate 	/*
19927c478bd9Sstevel@tonic-gate 	 * Only follow one level of referrals, i.e.
19937c478bd9Sstevel@tonic-gate 	 * if already in referral mode, do nothing
19947c478bd9Sstevel@tonic-gate 	 */
19957c478bd9Sstevel@tonic-gate 	if (cookie->refpos == NULL) {
19967c478bd9Sstevel@tonic-gate 		refurls = ldap_get_reference_urls(
1997699bceb8Smj 		    cookie->conn->ld,
1998699bceb8Smj 		    cookie->resultMsg);
19997c478bd9Sstevel@tonic-gate 		if (refurls == NULL) {
20007c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(cookie->conn->ld,
2001699bceb8Smj 			    LDAP_OPT_ERROR_NUMBER,
2002699bceb8Smj 			    &cookie->err_rc);
20037c478bd9Sstevel@tonic-gate 			cookie->new_state = LDAP_ERROR;
20047c478bd9Sstevel@tonic-gate 			return;
20057c478bd9Sstevel@tonic-gate 		}
20067c478bd9Sstevel@tonic-gate 		for (i = 0; refurls[i] != NULL; i++) {
20077c478bd9Sstevel@tonic-gate 			/* add to referral list */
20087c478bd9Sstevel@tonic-gate 			rc = __s_api_addRefInfo(
2009699bceb8Smj 			    &cookie->reflist,
2010699bceb8Smj 			    refurls[i],
2011699bceb8Smj 			    cookie->basedn,
2012699bceb8Smj 			    &cookie->scope,
2013699bceb8Smj 			    cookie->filter,
2014699bceb8Smj 			    cookie->conn->ld);
20157c478bd9Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
20167c478bd9Sstevel@tonic-gate 				cookie->new_state =
2017699bceb8Smj 				    ERROR;
20187c478bd9Sstevel@tonic-gate 				break;
20197c478bd9Sstevel@tonic-gate 			}
20207c478bd9Sstevel@tonic-gate 		}
20217c478bd9Sstevel@tonic-gate 		/* free allocated storage */
20227c478bd9Sstevel@tonic-gate 		for (i = 0; refurls[i] != NULL; i++)
20237c478bd9Sstevel@tonic-gate 			free(refurls[i]);
20247c478bd9Sstevel@tonic-gate 	}
20257c478bd9Sstevel@tonic-gate }
20267c478bd9Sstevel@tonic-gate 
20277c478bd9Sstevel@tonic-gate static ns_state_t
multi_result(ns_ldap_cookie_t * cookie)20287c478bd9Sstevel@tonic-gate multi_result(ns_ldap_cookie_t *cookie)
20297c478bd9Sstevel@tonic-gate {
20307c478bd9Sstevel@tonic-gate 	char		errstr[MAXERROR];
20317c478bd9Sstevel@tonic-gate 	char		*err;
20327c478bd9Sstevel@tonic-gate 	ns_ldap_error_t **errorp = NULL;
20337c478bd9Sstevel@tonic-gate 	LDAPControl	**retCtrls = NULL;
20347c478bd9Sstevel@tonic-gate 	int		i, rc;
20357c478bd9Sstevel@tonic-gate 	int		errCode;
20368f0bb794SToomas Soome 	boolean_t	finished = B_FALSE;
20377c478bd9Sstevel@tonic-gate 	unsigned long	target_posp = 0;
20387c478bd9Sstevel@tonic-gate 	unsigned long	list_size = 0;
20397c478bd9Sstevel@tonic-gate 	unsigned int	count = 0;
20408f0bb794SToomas Soome 	char		**referrals = NULL;
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate 	if (cookie->listType == VLVCTRLFLAG) {
20437c478bd9Sstevel@tonic-gate 		rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2044699bceb8Smj 		    &errCode, NULL, NULL, &referrals, &retCtrls, 0);
20457c478bd9Sstevel@tonic-gate 		if (rc != LDAP_SUCCESS) {
20467c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(cookie->conn->ld,
2047699bceb8Smj 			    LDAP_OPT_ERROR_NUMBER,
2048699bceb8Smj 			    &cookie->err_rc);
20497c478bd9Sstevel@tonic-gate 			(void) sprintf(errstr,
2050699bceb8Smj 			    gettext("LDAP ERROR (%d): %s.\n"),
2051699bceb8Smj 			    cookie->err_rc,
2052699bceb8Smj 			    gettext(ldap_err2string(cookie->err_rc)));
20537c478bd9Sstevel@tonic-gate 			err = strdup(errstr);
20547c478bd9Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2055*81de4da4SToomas Soome 			    LDAP_ERROR);
20567c478bd9Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INTERNAL;
20577c478bd9Sstevel@tonic-gate 			cookie->errorp = *errorp;
20587c478bd9Sstevel@tonic-gate 			return (LDAP_ERROR);
20597c478bd9Sstevel@tonic-gate 		}
20607c478bd9Sstevel@tonic-gate 		if (errCode == LDAP_REFERRAL) {
20617c478bd9Sstevel@tonic-gate 			for (i = 0; referrals[i] != NULL;
2062699bceb8Smj 			    i++) {
20637c478bd9Sstevel@tonic-gate 				/* add to referral list */
20647c478bd9Sstevel@tonic-gate 				rc = __s_api_addRefInfo(
2065699bceb8Smj 				    &cookie->reflist,
2066699bceb8Smj 				    referrals[i],
2067699bceb8Smj 				    cookie->basedn,
2068699bceb8Smj 				    &cookie->scope,
2069699bceb8Smj 				    cookie->filter,
2070699bceb8Smj 				    cookie->conn->ld);
20717c478bd9Sstevel@tonic-gate 				if (rc != NS_LDAP_SUCCESS) {
2072699bceb8Smj 					ldap_value_free(
2073699bceb8Smj 					    referrals);
20747c478bd9Sstevel@tonic-gate 					if (retCtrls)
20757c478bd9Sstevel@tonic-gate 						ldap_controls_free(
2076699bceb8Smj 						    retCtrls);
20777c478bd9Sstevel@tonic-gate 					return (ERROR);
20787c478bd9Sstevel@tonic-gate 				}
20797c478bd9Sstevel@tonic-gate 			}
20807c478bd9Sstevel@tonic-gate 			ldap_value_free(referrals);
20817c478bd9Sstevel@tonic-gate 			if (retCtrls)
20827c478bd9Sstevel@tonic-gate 				ldap_controls_free(retCtrls);
20837c478bd9Sstevel@tonic-gate 			return (END_RESULT);
20847c478bd9Sstevel@tonic-gate 		}
20857c478bd9Sstevel@tonic-gate 		if (retCtrls) {
20867c478bd9Sstevel@tonic-gate 			rc = ldap_parse_virtuallist_control(
2087699bceb8Smj 			    cookie->conn->ld, retCtrls,
2088699bceb8Smj 			    &target_posp, &list_size, &errCode);
20897c478bd9Sstevel@tonic-gate 			if (rc == LDAP_SUCCESS) {
20909f2fd570SJulian Pullen 				/*
20919f2fd570SJulian Pullen 				 * AD does not return valid target_posp
20929f2fd570SJulian Pullen 				 * and list_size
20939f2fd570SJulian Pullen 				 */
20949f2fd570SJulian Pullen 				if (target_posp != 0 && list_size != 0) {
20959f2fd570SJulian Pullen 					cookie->index =
20969f2fd570SJulian Pullen 					    target_posp + LISTPAGESIZE;
20979f2fd570SJulian Pullen 					if (cookie->index > list_size)
20988f0bb794SToomas Soome 						finished = B_TRUE;
20999f2fd570SJulian Pullen 				} else {
21009f2fd570SJulian Pullen 					if (cookie->entryCount < LISTPAGESIZE)
21018f0bb794SToomas Soome 						finished = B_TRUE;
21029f2fd570SJulian Pullen 					else
21039f2fd570SJulian Pullen 						cookie->index +=
21049f2fd570SJulian Pullen 						    cookie->entryCount;
21057c478bd9Sstevel@tonic-gate 				}
21067c478bd9Sstevel@tonic-gate 			}
21077c478bd9Sstevel@tonic-gate 			ldap_controls_free(retCtrls);
21087c478bd9Sstevel@tonic-gate 			retCtrls = NULL;
21098f0bb794SToomas Soome 		} else {
21108f0bb794SToomas Soome 			finished = B_TRUE;
21117c478bd9Sstevel@tonic-gate 		}
21127c478bd9Sstevel@tonic-gate 	} else if (cookie->listType == SIMPLEPAGECTRLFLAG) {
21137c478bd9Sstevel@tonic-gate 		rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
2114699bceb8Smj 		    &errCode, NULL, NULL, &referrals, &retCtrls, 0);
21157c478bd9Sstevel@tonic-gate 		if (rc != LDAP_SUCCESS) {
21167c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(cookie->conn->ld,
2117699bceb8Smj 			    LDAP_OPT_ERROR_NUMBER,
2118699bceb8Smj 			    &cookie->err_rc);
21197c478bd9Sstevel@tonic-gate 			(void) sprintf(errstr,
2120699bceb8Smj 			    gettext("LDAP ERROR (%d): %s.\n"),
2121699bceb8Smj 			    cookie->err_rc,
2122699bceb8Smj 			    gettext(ldap_err2string(cookie->err_rc)));
21237c478bd9Sstevel@tonic-gate 			err = strdup(errstr);
21247c478bd9Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2125*81de4da4SToomas Soome 			    LDAP_ERROR);
21267c478bd9Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INTERNAL;
21277c478bd9Sstevel@tonic-gate 			cookie->errorp = *errorp;
21287c478bd9Sstevel@tonic-gate 			return (LDAP_ERROR);
21297c478bd9Sstevel@tonic-gate 		}
21307c478bd9Sstevel@tonic-gate 		if (errCode == LDAP_REFERRAL) {
21317c478bd9Sstevel@tonic-gate 			for (i = 0; referrals[i] != NULL;
2132699bceb8Smj 			    i++) {
21337c478bd9Sstevel@tonic-gate 				/* add to referral list */
21347c478bd9Sstevel@tonic-gate 				rc = __s_api_addRefInfo(
2135699bceb8Smj 				    &cookie->reflist,
2136699bceb8Smj 				    referrals[i],
2137699bceb8Smj 				    cookie->basedn,
2138699bceb8Smj 				    &cookie->scope,
2139699bceb8Smj 				    cookie->filter,
2140699bceb8Smj 				    cookie->conn->ld);
21417c478bd9Sstevel@tonic-gate 				if (rc != NS_LDAP_SUCCESS) {
2142699bceb8Smj 					ldap_value_free(
2143699bceb8Smj 					    referrals);
21447c478bd9Sstevel@tonic-gate 					if (retCtrls)
21457c478bd9Sstevel@tonic-gate 						ldap_controls_free(
2146699bceb8Smj 						    retCtrls);
21477c478bd9Sstevel@tonic-gate 					return (ERROR);
21487c478bd9Sstevel@tonic-gate 				}
21497c478bd9Sstevel@tonic-gate 			}
21507c478bd9Sstevel@tonic-gate 			ldap_value_free(referrals);
21517c478bd9Sstevel@tonic-gate 			if (retCtrls)
21527c478bd9Sstevel@tonic-gate 				ldap_controls_free(retCtrls);
21537c478bd9Sstevel@tonic-gate 			return (END_RESULT);
21547c478bd9Sstevel@tonic-gate 		}
21557c478bd9Sstevel@tonic-gate 		if (retCtrls) {
21567c478bd9Sstevel@tonic-gate 			if (cookie->ctrlCookie)
21577c478bd9Sstevel@tonic-gate 				ber_bvfree(cookie->ctrlCookie);
21587c478bd9Sstevel@tonic-gate 			cookie->ctrlCookie = NULL;
21597c478bd9Sstevel@tonic-gate 			rc = ldap_parse_page_control(
2160699bceb8Smj 			    cookie->conn->ld, retCtrls,
2161699bceb8Smj 			    &count, &cookie->ctrlCookie);
21627c478bd9Sstevel@tonic-gate 			if (rc == LDAP_SUCCESS) {
21637c478bd9Sstevel@tonic-gate 				if ((cookie->ctrlCookie == NULL) ||
2164699bceb8Smj 				    (cookie->ctrlCookie->bv_val == NULL) ||
2165699bceb8Smj 				    (cookie->ctrlCookie->bv_len == 0))
21668f0bb794SToomas Soome 					finished = B_TRUE;
21677c478bd9Sstevel@tonic-gate 			}
21687c478bd9Sstevel@tonic-gate 			ldap_controls_free(retCtrls);
21697c478bd9Sstevel@tonic-gate 			retCtrls = NULL;
21708f0bb794SToomas Soome 		} else {
21718f0bb794SToomas Soome 			finished = B_TRUE;
21727c478bd9Sstevel@tonic-gate 		}
21737c478bd9Sstevel@tonic-gate 	}
21747c478bd9Sstevel@tonic-gate 	if (!finished && cookie->listType == VLVCTRLFLAG)
21757c478bd9Sstevel@tonic-gate 		return (NEXT_VLV);
21767c478bd9Sstevel@tonic-gate 	if (!finished && cookie->listType == SIMPLEPAGECTRLFLAG)
21777c478bd9Sstevel@tonic-gate 		return (NEXT_PAGE);
21787c478bd9Sstevel@tonic-gate 	if (finished)
21797c478bd9Sstevel@tonic-gate 		return (END_RESULT);
21807c478bd9Sstevel@tonic-gate 	return (ERROR);
21817c478bd9Sstevel@tonic-gate }
21827c478bd9Sstevel@tonic-gate 
2183b5d0e4ebSmj /*
2184b5d0e4ebSmj  * clear_results(ns_ldap_cookie_t):
2185b5d0e4ebSmj  *
2186b5d0e4ebSmj  * Attempt to obtain remnants of ldap responses and free them.  If remnants are
2187b5d0e4ebSmj  * not obtained within a certain time period tell the server we wish to abandon
2188b5d0e4ebSmj  * the request.
2189b5d0e4ebSmj  *
2190b5d0e4ebSmj  * Note that we do not initially tell the server to abandon the request as that
2191b5d0e4ebSmj  * can be an expensive operation for the server, while it is cheap for us to
2192b5d0e4ebSmj  * just flush the input.
2193b5d0e4ebSmj  *
2194b5d0e4ebSmj  * If something was to remain in libldap queue as a result of some error then
2195b5d0e4ebSmj  * it would be freed later during drop connection call or when no other
2196b5d0e4ebSmj  * requests share the connection.
2197b5d0e4ebSmj  */
2198b5d0e4ebSmj static void
clear_results(ns_ldap_cookie_t * cookie)2199b5d0e4ebSmj clear_results(ns_ldap_cookie_t *cookie)
2200b5d0e4ebSmj {
2201b5d0e4ebSmj 	int rc;
2202b5d0e4ebSmj 	if (cookie->conn != NULL && cookie->conn->ld != NULL &&
2203e1dd0a2fSth 	    (cookie->connectionId != -1 ||
2204e1dd0a2fSth 	    (cookie->conn_user != NULL &&
2205e1dd0a2fSth 	    cookie->conn_user->conn_mt != NULL)) &&
2206e1dd0a2fSth 	    cookie->msgId != 0) {
2207b5d0e4ebSmj 		/*
2208b5d0e4ebSmj 		 * We need to cleanup the rest of response (if there is such)
2209b5d0e4ebSmj 		 * and LDAP abandon is too heavy for LDAP servers, so we will
2210b5d0e4ebSmj 		 * wait for the rest of response till timeout and "process" it.
2211b5d0e4ebSmj 		 */
2212b5d0e4ebSmj 		rc = ldap_result(cookie->conn->ld, cookie->msgId, LDAP_MSG_ALL,
2213b5d0e4ebSmj 		    (struct timeval *)&cookie->search_timeout,
2214b5d0e4ebSmj 		    &cookie->resultMsg);
22159f2fd570SJulian Pullen 		if (rc != -1 && rc != 0 && cookie->resultMsg != NULL) {
2216b5d0e4ebSmj 			(void) ldap_msgfree(cookie->resultMsg);
22179f2fd570SJulian Pullen 			cookie->resultMsg = NULL;
22189f2fd570SJulian Pullen 		}
22199f2fd570SJulian Pullen 
2220b5d0e4ebSmj 		/*
2221b5d0e4ebSmj 		 * If there was timeout then we will send  ABANDON request to
2222b5d0e4ebSmj 		 * LDAP server to decrease load.
2223b5d0e4ebSmj 		 */
2224b5d0e4ebSmj 		if (rc == 0)
2225b5d0e4ebSmj 			(void) ldap_abandon_ext(cookie->conn->ld, cookie->msgId,
2226b5d0e4ebSmj 			    NULL, NULL);
2227b5d0e4ebSmj 		/* Disassociate cookie with msgId */
2228b5d0e4ebSmj 		cookie->msgId = 0;
2229b5d0e4ebSmj 	}
2230b5d0e4ebSmj }
2231b5d0e4ebSmj 
22327c478bd9Sstevel@tonic-gate /*
22337c478bd9Sstevel@tonic-gate  * This state machine performs one or more LDAP searches to a given
22347c478bd9Sstevel@tonic-gate  * directory server using service search descriptors and schema
22357c478bd9Sstevel@tonic-gate  * mapping as appropriate.  The approximate pseudocode for
22367c478bd9Sstevel@tonic-gate  * this routine is the following:
22377c478bd9Sstevel@tonic-gate  *    Given the current configuration [set/reset connection etc.]
22387c478bd9Sstevel@tonic-gate  *    and the current service search descriptor list
22397c478bd9Sstevel@tonic-gate  *        or default search filter parameters
22407c478bd9Sstevel@tonic-gate  *    foreach (service search filter) {
22417c478bd9Sstevel@tonic-gate  *        initialize the filter [via filter_init if appropriate]
22427c478bd9Sstevel@tonic-gate  *		  get a valid session/connection (preferably the current one)
22437c478bd9Sstevel@tonic-gate  *					Recover if the connection is lost
22447c478bd9Sstevel@tonic-gate  *        perform the search
22457c478bd9Sstevel@tonic-gate  *        foreach (result entry) {
22467c478bd9Sstevel@tonic-gate  *            process result [via callback if appropriate]
22477c478bd9Sstevel@tonic-gate  *                save result for caller if accepted.
22487c478bd9Sstevel@tonic-gate  *                exit and return all collected if allResults found;
22497c478bd9Sstevel@tonic-gate  *        }
22507c478bd9Sstevel@tonic-gate  *    }
22517c478bd9Sstevel@tonic-gate  *    return collected results and exit
22527c478bd9Sstevel@tonic-gate  */
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate static
22557c478bd9Sstevel@tonic-gate ns_state_t
search_state_machine(ns_ldap_cookie_t * cookie,ns_state_t state,int cycle)22567c478bd9Sstevel@tonic-gate search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
22577c478bd9Sstevel@tonic-gate {
22587c478bd9Sstevel@tonic-gate 	char		errstr[MAXERROR];
22597c478bd9Sstevel@tonic-gate 	char		*err;
2260e8ac3ceaSsdussud 	int		rc, ret;
2261e1dd0a2fSth 	int		rc_save;
22627c478bd9Sstevel@tonic-gate 	ns_ldap_entry_t	*nextEntry;
22637c478bd9Sstevel@tonic-gate 	ns_ldap_error_t *error = NULL;
22647c478bd9Sstevel@tonic-gate 	ns_ldap_error_t **errorp;
2265479ac375Sdm 	struct timeval	tv;
22667c478bd9Sstevel@tonic-gate 
22677c478bd9Sstevel@tonic-gate 	errorp = &error;
22687c478bd9Sstevel@tonic-gate 	cookie->state = state;
22698277a58bSchinlong 	errstr[0] = '\0';
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 	for (;;) {
22727c478bd9Sstevel@tonic-gate 		switch (cookie->state) {
2273699bceb8Smj 		case CLEAR_RESULTS:
2274b5d0e4ebSmj 			clear_results(cookie);
2275699bceb8Smj 			cookie->new_state = EXIT;
2276699bceb8Smj 			break;
227747789246Svv 		case GET_ACCT_MGMT_INFO:
227847789246Svv 			/*
227947789246Svv 			 * Set the flag to get ldap account management controls.
228047789246Svv 			 */
228147789246Svv 			cookie->nopasswd_acct_mgmt = 1;
228247789246Svv 			cookie->new_state = INIT;
228347789246Svv 			break;
22847c478bd9Sstevel@tonic-gate 		case EXIT:
22857c478bd9Sstevel@tonic-gate 			/* state engine/connection cleaned up in delete */
22867c478bd9Sstevel@tonic-gate 			if (cookie->attribute) {
22877c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(cookie->attribute);
22887c478bd9Sstevel@tonic-gate 				cookie->attribute = NULL;
22897c478bd9Sstevel@tonic-gate 			}
22907c478bd9Sstevel@tonic-gate 			if (cookie->reflist) {
22917c478bd9Sstevel@tonic-gate 				__s_api_deleteRefInfo(cookie->reflist);
22927c478bd9Sstevel@tonic-gate 				cookie->reflist = NULL;
22937c478bd9Sstevel@tonic-gate 			}
22947c478bd9Sstevel@tonic-gate 			return (EXIT);
22957c478bd9Sstevel@tonic-gate 		case INIT:
22967c478bd9Sstevel@tonic-gate 			cookie->sdpos = NULL;
22977c478bd9Sstevel@tonic-gate 			cookie->new_state = NEXT_SEARCH_DESCRIPTOR;
22987c478bd9Sstevel@tonic-gate 			if (cookie->attribute) {
22997c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(cookie->attribute);
23007c478bd9Sstevel@tonic-gate 				cookie->attribute = NULL;
23017c478bd9Sstevel@tonic-gate 			}
23027c478bd9Sstevel@tonic-gate 			if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
2303699bceb8Smj 			    cookie->i_attr) {
23047c478bd9Sstevel@tonic-gate 				cookie->attribute =
2305699bceb8Smj 				    __ns_ldap_mapAttributeList(
2306699bceb8Smj 				    cookie->service,
2307699bceb8Smj 				    cookie->i_attr);
23087c478bd9Sstevel@tonic-gate 			}
23097c478bd9Sstevel@tonic-gate 			break;
2310e1dd0a2fSth 		case REINIT:
2311e1dd0a2fSth 			/* Check if we've reached MAX retries. */
2312e1dd0a2fSth 			cookie->retries++;
2313e1dd0a2fSth 			if (cookie->retries > NS_LIST_TRY_MAX - 1) {
2314e1dd0a2fSth 				cookie->new_state = LDAP_ERROR;
2315e1dd0a2fSth 				break;
2316e1dd0a2fSth 			}
2317e1dd0a2fSth 
2318e1dd0a2fSth 			/*
2319e1dd0a2fSth 			 * Even if we still have retries left, check
2320e1dd0a2fSth 			 * if retry is possible.
2321e1dd0a2fSth 			 */
2322e1dd0a2fSth 			if (cookie->conn_user != NULL) {
2323e1dd0a2fSth 				int		retry;
2324e1dd0a2fSth 				ns_conn_mgmt_t	*cmg;
2325e1dd0a2fSth 				cmg = cookie->conn_user->conn_mgmt;
2326e1dd0a2fSth 				retry = cookie->conn_user->retry;
2327e1dd0a2fSth 				if (cmg != NULL && cmg->cfg_reloaded == 1)
2328e1dd0a2fSth 					retry = 1;
2329e1dd0a2fSth 				if (retry == 0) {
2330e1dd0a2fSth 					cookie->new_state = LDAP_ERROR;
2331e1dd0a2fSth 					break;
2332e1dd0a2fSth 				}
2333e1dd0a2fSth 			}
2334e1dd0a2fSth 			/*
2335e1dd0a2fSth 			 * Free results if any, reset to the first
2336e1dd0a2fSth 			 * search descriptor and start a new session.
2337e1dd0a2fSth 			 */
2338e1dd0a2fSth 			if (cookie->resultMsg != NULL) {
2339e1dd0a2fSth 				(void) ldap_msgfree(cookie->resultMsg);
2340e1dd0a2fSth 				cookie->resultMsg = NULL;
2341e1dd0a2fSth 			}
2342e1dd0a2fSth 			(void) __ns_ldap_freeError(&cookie->errorp);
2343e1dd0a2fSth 			(void) __ns_ldap_freeResult(&cookie->result);
2344e1dd0a2fSth 			cookie->sdpos = cookie->sdlist;
2345e1dd0a2fSth 			cookie->err_from_result = 0;
2346e1dd0a2fSth 			cookie->err_rc = 0;
2347e1dd0a2fSth 			cookie->new_state = NEXT_SESSION;
2348e1dd0a2fSth 			break;
23497c478bd9Sstevel@tonic-gate 		case NEXT_SEARCH_DESCRIPTOR:
23507c478bd9Sstevel@tonic-gate 			/* get next search descriptor */
23517c478bd9Sstevel@tonic-gate 			if (cookie->sdpos == NULL) {
23527c478bd9Sstevel@tonic-gate 				cookie->sdpos = cookie->sdlist;
23537c478bd9Sstevel@tonic-gate 				cookie->new_state = GET_SESSION;
23547c478bd9Sstevel@tonic-gate 			} else {
23557c478bd9Sstevel@tonic-gate 				cookie->sdpos++;
23567c478bd9Sstevel@tonic-gate 				cookie->new_state = NEXT_SEARCH;
23577c478bd9Sstevel@tonic-gate 			}
23587c478bd9Sstevel@tonic-gate 			if (*cookie->sdpos == NULL)
23597c478bd9Sstevel@tonic-gate 				cookie->new_state = EXIT;
23607c478bd9Sstevel@tonic-gate 			break;
23617c478bd9Sstevel@tonic-gate 		case GET_SESSION:
23627c478bd9Sstevel@tonic-gate 			if (get_current_session(cookie) < 0)
23637c478bd9Sstevel@tonic-gate 				cookie->new_state = NEXT_SESSION;
23647c478bd9Sstevel@tonic-gate 			else
23657c478bd9Sstevel@tonic-gate 				cookie->new_state = NEXT_SEARCH;
23667c478bd9Sstevel@tonic-gate 			break;
23677c478bd9Sstevel@tonic-gate 		case NEXT_SESSION:
23687c478bd9Sstevel@tonic-gate 			if (get_next_session(cookie) < 0)
23697c478bd9Sstevel@tonic-gate 				cookie->new_state = RESTART_SESSION;
23707c478bd9Sstevel@tonic-gate 			else
23717c478bd9Sstevel@tonic-gate 				cookie->new_state = NEXT_SEARCH;
23727c478bd9Sstevel@tonic-gate 			break;
23737c478bd9Sstevel@tonic-gate 		case RESTART_SESSION:
23747c478bd9Sstevel@tonic-gate 			if (cookie->i_flags & NS_LDAP_HARD) {
23757c478bd9Sstevel@tonic-gate 				cookie->new_state = NEXT_SESSION;
23767c478bd9Sstevel@tonic-gate 				break;
23777c478bd9Sstevel@tonic-gate 			}
23787c478bd9Sstevel@tonic-gate 			(void) sprintf(errstr,
2379699bceb8Smj 			    gettext("Session error no available conn.\n"),
2380699bceb8Smj 			    state);
23817c478bd9Sstevel@tonic-gate 			err = strdup(errstr);
23827c478bd9Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2383*81de4da4SToomas Soome 			    LDAP_ERROR);
23847c478bd9Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INTERNAL;
23857c478bd9Sstevel@tonic-gate 			cookie->errorp = *errorp;
23867c478bd9Sstevel@tonic-gate 			cookie->new_state = EXIT;
23877c478bd9Sstevel@tonic-gate 			break;
23887c478bd9Sstevel@tonic-gate 		case NEXT_SEARCH:
23897c478bd9Sstevel@tonic-gate 			/* setup referrals search if necessary */
23907c478bd9Sstevel@tonic-gate 			if (cookie->refpos) {
23917c478bd9Sstevel@tonic-gate 				if (setup_referral_search(cookie) < 0) {
23927c478bd9Sstevel@tonic-gate 					cookie->new_state = EXIT;
23937c478bd9Sstevel@tonic-gate 					break;
23947c478bd9Sstevel@tonic-gate 				}
23957c478bd9Sstevel@tonic-gate 			} else if (setup_next_search(cookie) < 0) {
23967c478bd9Sstevel@tonic-gate 				cookie->new_state = EXIT;
23977c478bd9Sstevel@tonic-gate 				break;
23987c478bd9Sstevel@tonic-gate 			}
23997c478bd9Sstevel@tonic-gate 			/* only do VLV/PAGE on scopes onelevel/subtree */
24007c478bd9Sstevel@tonic-gate 			if (paging_supported(cookie)) {
24017c478bd9Sstevel@tonic-gate 				if (cookie->use_paging &&
24027c478bd9Sstevel@tonic-gate 				    (cookie->scope != LDAP_SCOPE_BASE)) {
24037c478bd9Sstevel@tonic-gate 					cookie->index = 1;
24047c478bd9Sstevel@tonic-gate 					if (cookie->listType == VLVCTRLFLAG)
24057c478bd9Sstevel@tonic-gate 						cookie->new_state = NEXT_VLV;
24067c478bd9Sstevel@tonic-gate 					else
24077c478bd9Sstevel@tonic-gate 						cookie->new_state = NEXT_PAGE;
24087c478bd9Sstevel@tonic-gate 					break;
24097c478bd9Sstevel@tonic-gate 				}
24107c478bd9Sstevel@tonic-gate 			}
24117c478bd9Sstevel@tonic-gate 			cookie->new_state = ONE_SEARCH;
24127c478bd9Sstevel@tonic-gate 			break;
24137c478bd9Sstevel@tonic-gate 		case NEXT_VLV:
24147c478bd9Sstevel@tonic-gate 			rc = setup_vlv_params(cookie);
24157c478bd9Sstevel@tonic-gate 			if (rc != LDAP_SUCCESS) {
24167c478bd9Sstevel@tonic-gate 				cookie->err_rc = rc;
24177c478bd9Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
24187c478bd9Sstevel@tonic-gate 				break;
24197c478bd9Sstevel@tonic-gate 			}
24207c478bd9Sstevel@tonic-gate 			cookie->next_state = MULTI_RESULT;
24217c478bd9Sstevel@tonic-gate 			cookie->new_state = DO_SEARCH;
24227c478bd9Sstevel@tonic-gate 			break;
24237c478bd9Sstevel@tonic-gate 		case NEXT_PAGE:
24247c478bd9Sstevel@tonic-gate 			rc = setup_simplepg_params(cookie);
24257c478bd9Sstevel@tonic-gate 			if (rc != LDAP_SUCCESS) {
24267c478bd9Sstevel@tonic-gate 				cookie->err_rc = rc;
24277c478bd9Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
24287c478bd9Sstevel@tonic-gate 				break;
24297c478bd9Sstevel@tonic-gate 			}
24307c478bd9Sstevel@tonic-gate 			cookie->next_state = MULTI_RESULT;
24317c478bd9Sstevel@tonic-gate 			cookie->new_state = DO_SEARCH;
24327c478bd9Sstevel@tonic-gate 			break;
24337c478bd9Sstevel@tonic-gate 		case ONE_SEARCH:
24347c478bd9Sstevel@tonic-gate 			cookie->next_state = NEXT_RESULT;
24357c478bd9Sstevel@tonic-gate 			cookie->new_state = DO_SEARCH;
24367c478bd9Sstevel@tonic-gate 			break;
24377c478bd9Sstevel@tonic-gate 		case DO_SEARCH:
24389f2fd570SJulian Pullen 			cookie->entryCount = 0;
24397c478bd9Sstevel@tonic-gate 			rc = ldap_search_ext(cookie->conn->ld,
2440699bceb8Smj 			    cookie->basedn,
2441699bceb8Smj 			    cookie->scope,
2442699bceb8Smj 			    cookie->filter,
2443699bceb8Smj 			    cookie->attribute,
2444699bceb8Smj 			    0,
2445699bceb8Smj 			    cookie->p_serverctrls,
2446699bceb8Smj 			    NULL,
2447699bceb8Smj 			    &cookie->search_timeout, 0,
2448699bceb8Smj 			    &cookie->msgId);
24497c478bd9Sstevel@tonic-gate 			if (rc != LDAP_SUCCESS) {
24507c478bd9Sstevel@tonic-gate 				if (rc == LDAP_BUSY ||
24517c478bd9Sstevel@tonic-gate 				    rc == LDAP_UNAVAILABLE ||
24527c478bd9Sstevel@tonic-gate 				    rc == LDAP_UNWILLING_TO_PERFORM ||
24537c478bd9Sstevel@tonic-gate 				    rc == LDAP_CONNECT_ERROR ||
24547c478bd9Sstevel@tonic-gate 				    rc == LDAP_SERVER_DOWN) {
24557c478bd9Sstevel@tonic-gate 
2456e1dd0a2fSth 					if (cookie->reinit_on_retriable_err) {
2457e1dd0a2fSth 						cookie->err_rc = rc;
2458e1dd0a2fSth 						cookie->new_state = REINIT;
24598f0bb794SToomas Soome 					} else {
2460e1dd0a2fSth 						cookie->new_state =
2461e1dd0a2fSth 						    NEXT_SESSION;
24628f0bb794SToomas Soome 					}
24637c478bd9Sstevel@tonic-gate 
24647c478bd9Sstevel@tonic-gate 					/*
24657c478bd9Sstevel@tonic-gate 					 * If not able to reach the
24667c478bd9Sstevel@tonic-gate 					 * server, inform the ldap
24677c478bd9Sstevel@tonic-gate 					 * cache manager that the
24687c478bd9Sstevel@tonic-gate 					 * server should be removed
24697c478bd9Sstevel@tonic-gate 					 * from it's server list.
24707c478bd9Sstevel@tonic-gate 					 * Thus, the manager will not
24717c478bd9Sstevel@tonic-gate 					 * return this server on the next
24727c478bd9Sstevel@tonic-gate 					 * get-server request and will
24737c478bd9Sstevel@tonic-gate 					 * also reduce the server list
24747c478bd9Sstevel@tonic-gate 					 * refresh TTL, so that it will
24757c478bd9Sstevel@tonic-gate 					 * find out sooner when the server
24767c478bd9Sstevel@tonic-gate 					 * is up again.
24777c478bd9Sstevel@tonic-gate 					 */
2478e1dd0a2fSth 					if ((rc == LDAP_CONNECT_ERROR ||
2479e1dd0a2fSth 					    rc == LDAP_SERVER_DOWN) &&
2480e1dd0a2fSth 					    (cookie->conn_user == NULL ||
2481e1dd0a2fSth 					    cookie->conn_user->conn_mt ==
2482e1dd0a2fSth 					    NULL)) {
2483e8ac3ceaSsdussud 						ret = __s_api_removeServer(
24847c478bd9Sstevel@tonic-gate 						    cookie->conn->serverAddr);
2485e1dd0a2fSth 						if (ret == NS_CACHE_NOSERVER &&
2486e8ac3ceaSsdussud 						    cookie->conn_auth_type
2487699bceb8Smj 						    == NS_LDAP_AUTH_NONE) {
2488e8ac3ceaSsdussud 							/*
2489e8ac3ceaSsdussud 							 * Couldn't remove
2490e8ac3ceaSsdussud 							 * server from server
2491e8ac3ceaSsdussud 							 * list.
2492e8ac3ceaSsdussud 							 * Exit to avoid
2493e8ac3ceaSsdussud 							 * potential infinite
2494e8ac3ceaSsdussud 							 * loop.
2495e8ac3ceaSsdussud 							 */
2496e8ac3ceaSsdussud 							cookie->err_rc = rc;
2497e8ac3ceaSsdussud 							cookie->new_state =
2498e8ac3ceaSsdussud 							    LDAP_ERROR;
2499e8ac3ceaSsdussud 						}
25007c478bd9Sstevel@tonic-gate 						if (cookie->connectionId > -1) {
2501cb5caa98Sdjl 							/*
2502cb5caa98Sdjl 							 * NS_LDAP_NEW_CONN
2503cb5caa98Sdjl 							 * indicates that the
2504cb5caa98Sdjl 							 * connection should
2505cb5caa98Sdjl 							 * be deleted, not
2506cb5caa98Sdjl 							 * kept alive
2507cb5caa98Sdjl 							 */
2508cb5caa98Sdjl 							DropConnection(
2509699bceb8Smj 							    cookie->
2510699bceb8Smj 							    connectionId,
2511699bceb8Smj 							    NS_LDAP_NEW_CONN);
2512cb5caa98Sdjl 							cookie->connectionId =
2513699bceb8Smj 							    -1;
25147c478bd9Sstevel@tonic-gate 						}
2515e1dd0a2fSth 					} else if ((rc == LDAP_CONNECT_ERROR ||
2516e1dd0a2fSth 					    rc == LDAP_SERVER_DOWN) &&
2517ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 					    cookie->conn_user != NULL) {
2518ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 						if (cookie->
2519ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 						    reinit_on_retriable_err) {
2520ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							/*
2521ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * MT connection not
2522ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * usable, close it
2523ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * before REINIT.
2524ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * rc has already
2525ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * been saved in
2526ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * cookie->err_rc above.
2527ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 */
2528ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							__s_api_conn_mt_close(
2529ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							    cookie->conn_user,
2530ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							    rc,
2531ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							    &cookie->errorp);
2532ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 						} else {
2533ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							/*
2534ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * MT connection not
2535ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * usable, close it in
2536ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * the LDAP_ERROR state.
2537ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * A retry will be done
2538ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 * next if allowed.
2539ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							 */
2540ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							cookie->err_rc = rc;
2541ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							cookie->new_state =
2542ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 							    LDAP_ERROR;
2543ead6eed0SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 						}
25447c478bd9Sstevel@tonic-gate 					}
25457c478bd9Sstevel@tonic-gate 					break;
25467c478bd9Sstevel@tonic-gate 				}
25477c478bd9Sstevel@tonic-gate 				cookie->err_rc = rc;
25487c478bd9Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
25497c478bd9Sstevel@tonic-gate 				break;
25507c478bd9Sstevel@tonic-gate 			}
25517c478bd9Sstevel@tonic-gate 			cookie->new_state = cookie->next_state;
25527c478bd9Sstevel@tonic-gate 			break;
25537c478bd9Sstevel@tonic-gate 		case NEXT_RESULT:
2554479ac375Sdm 			/*
2555479ac375Sdm 			 * Caller (e.g. __ns_ldap_list_batch_add)
2556479ac375Sdm 			 * does not want to block on ldap_result().
2557479ac375Sdm 			 * Therefore we execute ldap_result() with
2558479ac375Sdm 			 * a zeroed timeval.
2559479ac375Sdm 			 */
2560479ac375Sdm 			if (cookie->no_wait == B_TRUE)
2561479ac375Sdm 				(void) memset(&tv, 0, sizeof (tv));
2562479ac375Sdm 			else
2563479ac375Sdm 				tv = cookie->search_timeout;
25647c478bd9Sstevel@tonic-gate 			rc = ldap_result(cookie->conn->ld, cookie->msgId,
2565699bceb8Smj 			    LDAP_MSG_ONE,
2566479ac375Sdm 			    &tv,
2567699bceb8Smj 			    &cookie->resultMsg);
25687c478bd9Sstevel@tonic-gate 			if (rc == LDAP_RES_SEARCH_RESULT) {
25697c478bd9Sstevel@tonic-gate 				cookie->new_state = END_RESULT;
25707c478bd9Sstevel@tonic-gate 				/* check and process referrals info */
25717c478bd9Sstevel@tonic-gate 				if (cookie->followRef)
25727c478bd9Sstevel@tonic-gate 					proc_result_referrals(
2573699bceb8Smj 					    cookie);
25747c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
25757c478bd9Sstevel@tonic-gate 				cookie->resultMsg = NULL;
25767c478bd9Sstevel@tonic-gate 				break;
25777c478bd9Sstevel@tonic-gate 			}
25787c478bd9Sstevel@tonic-gate 			/* handle referrals if necessary */
25797c478bd9Sstevel@tonic-gate 			if (rc == LDAP_RES_SEARCH_REFERENCE) {
25807c478bd9Sstevel@tonic-gate 				if (cookie->followRef)
25817c478bd9Sstevel@tonic-gate 					proc_search_references(cookie);
25827c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
25837c478bd9Sstevel@tonic-gate 				cookie->resultMsg = NULL;
25847c478bd9Sstevel@tonic-gate 				break;
25857c478bd9Sstevel@tonic-gate 			}
25867c478bd9Sstevel@tonic-gate 			if (rc != LDAP_RES_SEARCH_ENTRY) {
25877c478bd9Sstevel@tonic-gate 				switch (rc) {
25887c478bd9Sstevel@tonic-gate 				case 0:
2589479ac375Sdm 					if (cookie->no_wait == B_TRUE) {
2590479ac375Sdm 						(void) ldap_msgfree(
2591479ac375Sdm 						    cookie->resultMsg);
2592479ac375Sdm 						cookie->resultMsg = NULL;
2593479ac375Sdm 						return (cookie->new_state);
2594479ac375Sdm 					}
25957c478bd9Sstevel@tonic-gate 					rc = LDAP_TIMEOUT;
25967c478bd9Sstevel@tonic-gate 					break;
25977c478bd9Sstevel@tonic-gate 				case -1:
25987c478bd9Sstevel@tonic-gate 					rc = ldap_get_lderrno(cookie->conn->ld,
2599699bceb8Smj 					    NULL, NULL);
26007c478bd9Sstevel@tonic-gate 					break;
26017c478bd9Sstevel@tonic-gate 				default:
26027c478bd9Sstevel@tonic-gate 					rc = ldap_result2error(cookie->conn->ld,
2603699bceb8Smj 					    cookie->resultMsg, 1);
26047c478bd9Sstevel@tonic-gate 					break;
26057c478bd9Sstevel@tonic-gate 				}
2606e1dd0a2fSth 				if ((rc == LDAP_TIMEOUT ||
2607e1dd0a2fSth 				    rc == LDAP_SERVER_DOWN) &&
2608e1dd0a2fSth 				    (cookie->conn_user == NULL ||
2609e1dd0a2fSth 				    cookie->conn_user->conn_mt == NULL)) {
26108277a58bSchinlong 					if (rc == LDAP_TIMEOUT)
26118277a58bSchinlong 						(void) __s_api_removeServer(
26128277a58bSchinlong 						    cookie->conn->serverAddr);
26138277a58bSchinlong 					if (cookie->connectionId > -1) {
2614699bceb8Smj 						DropConnection(
2615699bceb8Smj 						    cookie->connectionId,
2616699bceb8Smj 						    NS_LDAP_NEW_CONN);
26178277a58bSchinlong 						cookie->connectionId = -1;
26188277a58bSchinlong 					}
26198277a58bSchinlong 					cookie->err_from_result = 1;
26208277a58bSchinlong 				}
26217c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
26227c478bd9Sstevel@tonic-gate 				cookie->resultMsg = NULL;
26237c478bd9Sstevel@tonic-gate 				if (rc == LDAP_BUSY ||
26247c478bd9Sstevel@tonic-gate 				    rc == LDAP_UNAVAILABLE ||
26258277a58bSchinlong 				    rc == LDAP_UNWILLING_TO_PERFORM) {
2626e1dd0a2fSth 					if (cookie->reinit_on_retriable_err) {
2627e1dd0a2fSth 						cookie->err_rc = rc;
2628e1dd0a2fSth 						cookie->err_from_result = 1;
2629e1dd0a2fSth 						cookie->new_state = REINIT;
26308f0bb794SToomas Soome 					} else {
2631e1dd0a2fSth 						cookie->new_state =
2632e1dd0a2fSth 						    NEXT_SESSION;
26338f0bb794SToomas Soome 					}
2634e1dd0a2fSth 					break;
2635e1dd0a2fSth 				}
2636e1dd0a2fSth 				if ((rc == LDAP_CONNECT_ERROR ||
2637e1dd0a2fSth 				    rc == LDAP_SERVER_DOWN) &&
2638e1dd0a2fSth 				    cookie->reinit_on_retriable_err) {
2639e1dd0a2fSth 					ns_ldap_error_t *errorp = NULL;
2640e1dd0a2fSth 					cookie->err_rc = rc;
2641e1dd0a2fSth 					cookie->err_from_result = 1;
2642e1dd0a2fSth 					cookie->new_state = REINIT;
2643e1dd0a2fSth 					if (cookie->conn_user != NULL)
2644e1dd0a2fSth 						__s_api_conn_mt_close(
2645e1dd0a2fSth 						    cookie->conn_user,
2646e1dd0a2fSth 						    rc, &errorp);
2647e1dd0a2fSth 					if (errorp != NULL) {
2648e1dd0a2fSth 						(void) __ns_ldap_freeError(
2649e1dd0a2fSth 						    &cookie->errorp);
2650e1dd0a2fSth 						cookie->errorp = errorp;
2651e1dd0a2fSth 					}
26527c478bd9Sstevel@tonic-gate 					break;
26537c478bd9Sstevel@tonic-gate 				}
26547c478bd9Sstevel@tonic-gate 				cookie->err_rc = rc;
26557c478bd9Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
26567c478bd9Sstevel@tonic-gate 				break;
26577c478bd9Sstevel@tonic-gate 			}
26587c478bd9Sstevel@tonic-gate 			/* else LDAP_RES_SEARCH_ENTRY */
265947789246Svv 			/* get account management response control */
266047789246Svv 			if (cookie->nopasswd_acct_mgmt == 1) {
266147789246Svv 				rc = ldap_get_entry_controls(cookie->conn->ld,
2662699bceb8Smj 				    cookie->resultMsg,
2663699bceb8Smj 				    &(cookie->resultctrl));
266447789246Svv 				if (rc != LDAP_SUCCESS) {
266547789246Svv 					cookie->new_state = LDAP_ERROR;
266647789246Svv 					cookie->err_rc = rc;
266747789246Svv 					break;
266847789246Svv 				}
266947789246Svv 			}
26707c478bd9Sstevel@tonic-gate 			rc = __s_api_getEntry(cookie);
26717c478bd9Sstevel@tonic-gate 			(void) ldap_msgfree(cookie->resultMsg);
26727c478bd9Sstevel@tonic-gate 			cookie->resultMsg = NULL;
26737c478bd9Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
26747c478bd9Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
26757c478bd9Sstevel@tonic-gate 				break;
26767c478bd9Sstevel@tonic-gate 			}
26777c478bd9Sstevel@tonic-gate 			cookie->new_state = PROCESS_RESULT;
26787c478bd9Sstevel@tonic-gate 			cookie->next_state = NEXT_RESULT;
26797c478bd9Sstevel@tonic-gate 			break;
26807c478bd9Sstevel@tonic-gate 		case MULTI_RESULT:
2681479ac375Sdm 			if (cookie->no_wait == B_TRUE)
2682479ac375Sdm 				(void) memset(&tv, 0, sizeof (tv));
2683479ac375Sdm 			else
2684479ac375Sdm 				tv = cookie->search_timeout;
26857c478bd9Sstevel@tonic-gate 			rc = ldap_result(cookie->conn->ld, cookie->msgId,
2686699bceb8Smj 			    LDAP_MSG_ONE,
2687479ac375Sdm 			    &tv,
2688699bceb8Smj 			    &cookie->resultMsg);
26897c478bd9Sstevel@tonic-gate 			if (rc == LDAP_RES_SEARCH_RESULT) {
26907c478bd9Sstevel@tonic-gate 				rc = ldap_result2error(cookie->conn->ld,
2691699bceb8Smj 				    cookie->resultMsg, 0);
26929f2fd570SJulian Pullen 				if (rc == LDAP_ADMINLIMIT_EXCEEDED &&
26939f2fd570SJulian Pullen 				    cookie->listType == VLVCTRLFLAG &&
26949f2fd570SJulian Pullen 				    cookie->sortTypeTry == SSS_SINGLE_ATTR) {
26959f2fd570SJulian Pullen 					/* Try old "cn uid" server side sort */
26969f2fd570SJulian Pullen 					cookie->sortTypeTry = SSS_CN_UID_ATTRS;
26979f2fd570SJulian Pullen 					cookie->new_state = NEXT_VLV;
26989f2fd570SJulian Pullen 					(void) ldap_msgfree(cookie->resultMsg);
26999f2fd570SJulian Pullen 					cookie->resultMsg = NULL;
27009f2fd570SJulian Pullen 					break;
27019f2fd570SJulian Pullen 				}
27027c478bd9Sstevel@tonic-gate 				if (rc != LDAP_SUCCESS) {
27037c478bd9Sstevel@tonic-gate 					cookie->err_rc = rc;
27047c478bd9Sstevel@tonic-gate 					cookie->new_state = LDAP_ERROR;
27057c478bd9Sstevel@tonic-gate 					(void) ldap_msgfree(cookie->resultMsg);
27069f2fd570SJulian Pullen 					cookie->resultMsg = NULL;
27077c478bd9Sstevel@tonic-gate 					break;
27087c478bd9Sstevel@tonic-gate 				}
27097c478bd9Sstevel@tonic-gate 				cookie->new_state = multi_result(cookie);
27107c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
27117c478bd9Sstevel@tonic-gate 				cookie->resultMsg = NULL;
27127c478bd9Sstevel@tonic-gate 				break;
27137c478bd9Sstevel@tonic-gate 			}
27147c478bd9Sstevel@tonic-gate 			/* handle referrals if necessary */
27157c478bd9Sstevel@tonic-gate 			if (rc == LDAP_RES_SEARCH_REFERENCE &&
2716699bceb8Smj 			    cookie->followRef) {
27177c478bd9Sstevel@tonic-gate 				proc_search_references(cookie);
27187c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
27197c478bd9Sstevel@tonic-gate 				cookie->resultMsg = NULL;
27207c478bd9Sstevel@tonic-gate 				break;
27217c478bd9Sstevel@tonic-gate 			}
27227c478bd9Sstevel@tonic-gate 			if (rc != LDAP_RES_SEARCH_ENTRY) {
27237c478bd9Sstevel@tonic-gate 				switch (rc) {
27247c478bd9Sstevel@tonic-gate 				case 0:
2725479ac375Sdm 					if (cookie->no_wait == B_TRUE) {
2726479ac375Sdm 						(void) ldap_msgfree(
2727479ac375Sdm 						    cookie->resultMsg);
2728479ac375Sdm 						cookie->resultMsg = NULL;
2729479ac375Sdm 						return (cookie->new_state);
2730479ac375Sdm 					}
27317c478bd9Sstevel@tonic-gate 					rc = LDAP_TIMEOUT;
27327c478bd9Sstevel@tonic-gate 					break;
27337c478bd9Sstevel@tonic-gate 				case -1:
27347c478bd9Sstevel@tonic-gate 					rc = ldap_get_lderrno(cookie->conn->ld,
2735699bceb8Smj 					    NULL, NULL);
27367c478bd9Sstevel@tonic-gate 					break;
27377c478bd9Sstevel@tonic-gate 				default:
27387c478bd9Sstevel@tonic-gate 					rc = ldap_result2error(cookie->conn->ld,
2739699bceb8Smj 					    cookie->resultMsg, 1);
27407c478bd9Sstevel@tonic-gate 					break;
27417c478bd9Sstevel@tonic-gate 				}
2742e1dd0a2fSth 				if ((rc == LDAP_TIMEOUT ||
2743e1dd0a2fSth 				    rc == LDAP_SERVER_DOWN) &&
2744e1dd0a2fSth 				    (cookie->conn_user == NULL ||
2745e1dd0a2fSth 				    cookie->conn_user->conn_mt == NULL)) {
27468277a58bSchinlong 					if (rc == LDAP_TIMEOUT)
27478277a58bSchinlong 						(void) __s_api_removeServer(
27488277a58bSchinlong 						    cookie->conn->serverAddr);
27498277a58bSchinlong 					if (cookie->connectionId > -1) {
2750699bceb8Smj 						DropConnection(
2751699bceb8Smj 						    cookie->connectionId,
2752699bceb8Smj 						    NS_LDAP_NEW_CONN);
27538277a58bSchinlong 						cookie->connectionId = -1;
27548277a58bSchinlong 					}
27558277a58bSchinlong 					cookie->err_from_result = 1;
27568277a58bSchinlong 				}
27577c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
27587c478bd9Sstevel@tonic-gate 				cookie->resultMsg = NULL;
27597c478bd9Sstevel@tonic-gate 				if (rc == LDAP_BUSY ||
27607c478bd9Sstevel@tonic-gate 				    rc == LDAP_UNAVAILABLE ||
27618277a58bSchinlong 				    rc == LDAP_UNWILLING_TO_PERFORM) {
2762e1dd0a2fSth 					if (cookie->reinit_on_retriable_err) {
2763e1dd0a2fSth 						cookie->err_rc = rc;
2764e1dd0a2fSth 						cookie->err_from_result = 1;
2765e1dd0a2fSth 						cookie->new_state = REINIT;
27668f0bb794SToomas Soome 					} else {
2767e1dd0a2fSth 						cookie->new_state =
2768e1dd0a2fSth 						    NEXT_SESSION;
27698f0bb794SToomas Soome 					}
2770e1dd0a2fSth 					break;
2771e1dd0a2fSth 				}
27729f2fd570SJulian Pullen 
2773e1dd0a2fSth 				if ((rc == LDAP_CONNECT_ERROR ||
2774e1dd0a2fSth 				    rc == LDAP_SERVER_DOWN) &&
2775e1dd0a2fSth 				    cookie->reinit_on_retriable_err) {
2776e1dd0a2fSth 					ns_ldap_error_t *errorp = NULL;
2777e1dd0a2fSth 					cookie->err_rc = rc;
2778e1dd0a2fSth 					cookie->err_from_result = 1;
2779e1dd0a2fSth 					cookie->new_state = REINIT;
2780e1dd0a2fSth 					if (cookie->conn_user != NULL)
2781e1dd0a2fSth 						__s_api_conn_mt_close(
2782e1dd0a2fSth 						    cookie->conn_user,
2783e1dd0a2fSth 						    rc, &errorp);
2784e1dd0a2fSth 					if (errorp != NULL) {
2785e1dd0a2fSth 						(void) __ns_ldap_freeError(
2786e1dd0a2fSth 						    &cookie->errorp);
2787e1dd0a2fSth 						cookie->errorp = errorp;
2788e1dd0a2fSth 					}
27897c478bd9Sstevel@tonic-gate 					break;
27907c478bd9Sstevel@tonic-gate 				}
27917c478bd9Sstevel@tonic-gate 				cookie->err_rc = rc;
27927c478bd9Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
27937c478bd9Sstevel@tonic-gate 				break;
27947c478bd9Sstevel@tonic-gate 			}
27957c478bd9Sstevel@tonic-gate 			/* else LDAP_RES_SEARCH_ENTRY */
27969f2fd570SJulian Pullen 			cookie->entryCount++;
27977c478bd9Sstevel@tonic-gate 			rc = __s_api_getEntry(cookie);
27987c478bd9Sstevel@tonic-gate 			(void) ldap_msgfree(cookie->resultMsg);
27997c478bd9Sstevel@tonic-gate 			cookie->resultMsg = NULL;
28007c478bd9Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
28017c478bd9Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
28027c478bd9Sstevel@tonic-gate 				break;
28037c478bd9Sstevel@tonic-gate 			}
28049f2fd570SJulian Pullen 			/*
28059f2fd570SJulian Pullen 			 * If VLV search was successfull save the server
28069f2fd570SJulian Pullen 			 * side sort type tried.
28079f2fd570SJulian Pullen 			 */
28089f2fd570SJulian Pullen 			if (cookie->listType == VLVCTRLFLAG)
28099f2fd570SJulian Pullen 				update_srvsidesort_type(cookie->service,
28109f2fd570SJulian Pullen 				    cookie->sortTypeTry);
28119f2fd570SJulian Pullen 
28127c478bd9Sstevel@tonic-gate 			cookie->new_state = PROCESS_RESULT;
28137c478bd9Sstevel@tonic-gate 			cookie->next_state = MULTI_RESULT;
28147c478bd9Sstevel@tonic-gate 			break;
28157c478bd9Sstevel@tonic-gate 		case PROCESS_RESULT:
28167c478bd9Sstevel@tonic-gate 			/* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
28177c478bd9Sstevel@tonic-gate 			if (cookie->use_usercb && cookie->callback) {
28187c478bd9Sstevel@tonic-gate 				rc = 0;
28197c478bd9Sstevel@tonic-gate 				for (nextEntry = cookie->result->entry;
2820699bceb8Smj 				    nextEntry != NULL;
2821699bceb8Smj 				    nextEntry = nextEntry->next) {
28227c478bd9Sstevel@tonic-gate 					rc = (*cookie->callback)(nextEntry,
2823699bceb8Smj 					    cookie->userdata);
28247c478bd9Sstevel@tonic-gate 
28257c478bd9Sstevel@tonic-gate 					if (rc == NS_LDAP_CB_DONE) {
28267c478bd9Sstevel@tonic-gate 					/* cb doesn't want any more data */
28277c478bd9Sstevel@tonic-gate 						rc = NS_LDAP_PARTIAL;
28287c478bd9Sstevel@tonic-gate 						cookie->err_rc = rc;
28297c478bd9Sstevel@tonic-gate 						break;
28307c478bd9Sstevel@tonic-gate 					} else if (rc != NS_LDAP_CB_NEXT) {
28317c478bd9Sstevel@tonic-gate 					/* invalid return code */
28327c478bd9Sstevel@tonic-gate 						rc = NS_LDAP_OP_FAILED;
28337c478bd9Sstevel@tonic-gate 						cookie->err_rc = rc;
28347c478bd9Sstevel@tonic-gate 						break;
28357c478bd9Sstevel@tonic-gate 					}
28367c478bd9Sstevel@tonic-gate 				}
28377c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeResult(&cookie->result);
28387c478bd9Sstevel@tonic-gate 				cookie->result = NULL;
28397c478bd9Sstevel@tonic-gate 			}
28407c478bd9Sstevel@tonic-gate 			if (rc != 0) {
28417c478bd9Sstevel@tonic-gate 				cookie->new_state = EXIT;
28427c478bd9Sstevel@tonic-gate 				break;
28437c478bd9Sstevel@tonic-gate 			}
28447c478bd9Sstevel@tonic-gate 			/* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
28457c478bd9Sstevel@tonic-gate 			cookie->new_state = cookie->next_state;
28467c478bd9Sstevel@tonic-gate 			break;
28477c478bd9Sstevel@tonic-gate 		case END_PROCESS_RESULT:
28487c478bd9Sstevel@tonic-gate 			cookie->new_state = cookie->next_state;
28497c478bd9Sstevel@tonic-gate 			break;
28507c478bd9Sstevel@tonic-gate 		case END_RESULT:
28517c478bd9Sstevel@tonic-gate 			/*
28527c478bd9Sstevel@tonic-gate 			 * XXX DO WE NEED THIS CASE?
28537c478bd9Sstevel@tonic-gate 			 * if (search is complete) {
28548f0bb794SToomas Soome 			 *	cookie->new_state = EXIT;
28557c478bd9Sstevel@tonic-gate 			 * } else
28567c478bd9Sstevel@tonic-gate 			 */
28577c478bd9Sstevel@tonic-gate 				/*
28587c478bd9Sstevel@tonic-gate 				 * entering referral mode if necessary
28597c478bd9Sstevel@tonic-gate 				 */
28607c478bd9Sstevel@tonic-gate 				if (cookie->followRef && cookie->reflist)
28617c478bd9Sstevel@tonic-gate 					cookie->new_state =
2862699bceb8Smj 					    NEXT_REFERRAL;
28637c478bd9Sstevel@tonic-gate 				else
28647c478bd9Sstevel@tonic-gate 					cookie->new_state =
2865699bceb8Smj 					    NEXT_SEARCH_DESCRIPTOR;
28667c478bd9Sstevel@tonic-gate 			break;
28677c478bd9Sstevel@tonic-gate 		case NEXT_REFERRAL:
28687c478bd9Sstevel@tonic-gate 			/* get next referral info */
28697c478bd9Sstevel@tonic-gate 			if (cookie->refpos == NULL)
28707c478bd9Sstevel@tonic-gate 				cookie->refpos =
2871699bceb8Smj 				    cookie->reflist;
28727c478bd9Sstevel@tonic-gate 			else
28737c478bd9Sstevel@tonic-gate 				cookie->refpos =
2874699bceb8Smj 				    cookie->refpos->next;
28757c478bd9Sstevel@tonic-gate 			/* check see if done with all referrals */
28768f0bb794SToomas Soome 			if (cookie->refpos != NULL) {
28777c478bd9Sstevel@tonic-gate 				cookie->new_state =
2878699bceb8Smj 				    GET_REFERRAL_SESSION;
28798f0bb794SToomas Soome 			} else {
28807c478bd9Sstevel@tonic-gate 				__s_api_deleteRefInfo(cookie->reflist);
28817c478bd9Sstevel@tonic-gate 				cookie->reflist = NULL;
28827c478bd9Sstevel@tonic-gate 				cookie->new_state =
2883699bceb8Smj 				    NEXT_SEARCH_DESCRIPTOR;
2884e1dd0a2fSth 				if (cookie->conn_user != NULL)
2885e1dd0a2fSth 					cookie->conn_user->referral = B_FALSE;
28867c478bd9Sstevel@tonic-gate 			}
28877c478bd9Sstevel@tonic-gate 			break;
28887c478bd9Sstevel@tonic-gate 		case GET_REFERRAL_SESSION:
28898f0bb794SToomas Soome 			if (get_referral_session(cookie) < 0) {
28907c478bd9Sstevel@tonic-gate 				cookie->new_state = EXIT;
28918f0bb794SToomas Soome 			} else {
28927c478bd9Sstevel@tonic-gate 				cookie->new_state = NEXT_SEARCH;
28937c478bd9Sstevel@tonic-gate 			}
28947c478bd9Sstevel@tonic-gate 			break;
28957c478bd9Sstevel@tonic-gate 		case LDAP_ERROR:
2896e1dd0a2fSth 			rc_save = cookie->err_rc;
28978277a58bSchinlong 			if (cookie->err_from_result) {
28988277a58bSchinlong 				if (cookie->err_rc == LDAP_SERVER_DOWN) {
28998277a58bSchinlong 					(void) sprintf(errstr,
2900699bceb8Smj 					    gettext("LDAP ERROR (%d): "
2901699bceb8Smj 					    "Error occurred during"
2902699bceb8Smj 					    " receiving results. "
290310f9768dSmj 					    "Connection to server lost."),
2904699bceb8Smj 					    cookie->err_rc);
29058277a58bSchinlong 				} else if (cookie->err_rc == LDAP_TIMEOUT) {
29068277a58bSchinlong 					(void) sprintf(errstr,
2907699bceb8Smj 					    gettext("LDAP ERROR (%d): "
2908699bceb8Smj 					    "Error occurred during"
2909699bceb8Smj 					    " receiving results. %s"
2910699bceb8Smj 					    "."), cookie->err_rc,
2911699bceb8Smj 					    ldap_err2string(
2912699bceb8Smj 					    cookie->err_rc));
29138277a58bSchinlong 				}
29148f0bb794SToomas Soome 			} else {
29158277a58bSchinlong 				(void) sprintf(errstr,
2916699bceb8Smj 				    gettext("LDAP ERROR (%d): %s."),
2917699bceb8Smj 				    cookie->err_rc,
2918699bceb8Smj 				    ldap_err2string(cookie->err_rc));
29198f0bb794SToomas Soome 			}
29207c478bd9Sstevel@tonic-gate 			err = strdup(errstr);
29218277a58bSchinlong 			if (cookie->err_from_result) {
292210f9768dSmj 				if (cookie->err_rc == LDAP_SERVER_DOWN) {
292310f9768dSmj 					MKERROR(LOG_INFO, *errorp,
292451b02b29SToomas Soome 					    cookie->err_rc, err,
2925*81de4da4SToomas Soome 					    LDAP_ERROR);
292610f9768dSmj 				} else {
292710f9768dSmj 					MKERROR(LOG_WARNING, *errorp,
292851b02b29SToomas Soome 					    cookie->err_rc, err,
2929*81de4da4SToomas Soome 					    LDAP_ERROR);
293010f9768dSmj 				}
29318277a58bSchinlong 			} else {
29328277a58bSchinlong 				MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
2933*81de4da4SToomas Soome 				    err, LDAP_ERROR);
29348277a58bSchinlong 			}
29357c478bd9Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INTERNAL;
29367c478bd9Sstevel@tonic-gate 			cookie->errorp = *errorp;
2937e1dd0a2fSth 			if (cookie->conn_user != NULL)  {
2938e1dd0a2fSth 				if (rc_save == LDAP_SERVER_DOWN ||
2939e1dd0a2fSth 				    rc_save == LDAP_CONNECT_ERROR) {
2940e1dd0a2fSth 					/*
2941e1dd0a2fSth 					 * MT connection is not usable,
2942e1dd0a2fSth 					 * close it.
2943e1dd0a2fSth 					 */
2944e1dd0a2fSth 					__s_api_conn_mt_close(cookie->conn_user,
2945e1dd0a2fSth 					    rc_save, &cookie->errorp);
2946e1dd0a2fSth 					return (ERROR);
2947e1dd0a2fSth 				}
2948e1dd0a2fSth 			}
29497c478bd9Sstevel@tonic-gate 			return (ERROR);
29507c478bd9Sstevel@tonic-gate 		default:
29517c478bd9Sstevel@tonic-gate 		case ERROR:
29527c478bd9Sstevel@tonic-gate 			(void) sprintf(errstr,
2953699bceb8Smj 			    gettext("Internal State machine exit (%d).\n"),
2954699bceb8Smj 			    cookie->state);
29557c478bd9Sstevel@tonic-gate 			err = strdup(errstr);
29567c478bd9Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
2957*81de4da4SToomas Soome 			    LDAP_ERROR);
29587c478bd9Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INTERNAL;
29597c478bd9Sstevel@tonic-gate 			cookie->errorp = *errorp;
29607c478bd9Sstevel@tonic-gate 			return (ERROR);
29617c478bd9Sstevel@tonic-gate 		}
29627c478bd9Sstevel@tonic-gate 
2963e1dd0a2fSth 		if (cookie->conn_user != NULL &&
2964e1dd0a2fSth 		    cookie->conn_user->bad_mt_conn ==  B_TRUE) {
2965e1dd0a2fSth 			__s_api_conn_mt_close(cookie->conn_user, 0, NULL);
2966e1dd0a2fSth 			cookie->err_rc = cookie->conn_user->ns_rc;
2967e1dd0a2fSth 			cookie->errorp = cookie->conn_user->ns_error;
2968e1dd0a2fSth 			cookie->conn_user->ns_error = NULL;
2969e1dd0a2fSth 			return (ERROR);
2970e1dd0a2fSth 		}
2971e1dd0a2fSth 
29727c478bd9Sstevel@tonic-gate 		if (cycle == ONE_STEP) {
29737c478bd9Sstevel@tonic-gate 			return (cookie->new_state);
29747c478bd9Sstevel@tonic-gate 		}
29757c478bd9Sstevel@tonic-gate 		cookie->state = cookie->new_state;
29767c478bd9Sstevel@tonic-gate 	}
29777c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
29787c478bd9Sstevel@tonic-gate #if 0
29797c478bd9Sstevel@tonic-gate 	(void) sprintf(errstr,
2980699bceb8Smj 	    gettext("Unexpected State machine error.\n"));
29817c478bd9Sstevel@tonic-gate 	err = strdup(errstr);
298251b02b29SToomas Soome 	MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NS_LDAP_MEMORY);
29837c478bd9Sstevel@tonic-gate 	cookie->err_rc = NS_LDAP_INTERNAL;
29847c478bd9Sstevel@tonic-gate 	cookie->errorp = *errorp;
29857c478bd9Sstevel@tonic-gate 	return (ERROR);
29867c478bd9Sstevel@tonic-gate #endif
29877c478bd9Sstevel@tonic-gate }
29887c478bd9Sstevel@tonic-gate 
2989b57459abSJulian Pullen /*
2990b57459abSJulian Pullen  * For a lookup of shadow data, if shadow update is enabled,
2991b57459abSJulian Pullen  * check the calling process' privilege to ensure it's
2992b57459abSJulian Pullen  * allowed to perform such operation.
2993b57459abSJulian Pullen  */
2994b57459abSJulian Pullen static int
check_shadow(ns_ldap_cookie_t * cookie,const char * service)2995b57459abSJulian Pullen check_shadow(ns_ldap_cookie_t *cookie, const char *service)
2996b57459abSJulian Pullen {
2997b57459abSJulian Pullen 	char errstr[MAXERROR];
2998b57459abSJulian Pullen 	char *err;
2999b57459abSJulian Pullen 	boolean_t priv;
3000b57459abSJulian Pullen 	/* caller */
3001b57459abSJulian Pullen 	priv_set_t *ps;
3002b57459abSJulian Pullen 	/* zone */
3003b57459abSJulian Pullen 	priv_set_t *zs;
3004b57459abSJulian Pullen 
3005b57459abSJulian Pullen 	/*
3006b57459abSJulian Pullen 	 * If service is "shadow", we may need
3007b57459abSJulian Pullen 	 * to use privilege credentials.
3008b57459abSJulian Pullen 	 */
3009b57459abSJulian Pullen 	if ((strcmp(service, "shadow") == 0) &&
3010b57459abSJulian Pullen 	    __ns_ldap_is_shadow_update_enabled()) {
3011b57459abSJulian Pullen 		/*
3012b57459abSJulian Pullen 		 * Since we release admin credentials after
3013b57459abSJulian Pullen 		 * connection is closed and we do not cache
3014b57459abSJulian Pullen 		 * them, we allow any root or all zone
3015b57459abSJulian Pullen 		 * privilege process to read shadow data.
3016b57459abSJulian Pullen 		 */
3017b57459abSJulian Pullen 		priv = (geteuid() == 0);
3018b57459abSJulian Pullen 		if (!priv) {
3019b57459abSJulian Pullen 			/* caller */
3020b57459abSJulian Pullen 			ps = priv_allocset();
3021b57459abSJulian Pullen 
3022b57459abSJulian Pullen 			(void) getppriv(PRIV_EFFECTIVE, ps);
3023b57459abSJulian Pullen 			zs = priv_str_to_set("zone", ",", NULL);
3024b57459abSJulian Pullen 			priv = priv_isequalset(ps, zs);
3025b57459abSJulian Pullen 			priv_freeset(ps);
3026b57459abSJulian Pullen 			priv_freeset(zs);
3027b57459abSJulian Pullen 		}
3028b57459abSJulian Pullen 		if (!priv) {
3029b57459abSJulian Pullen 			(void) sprintf(errstr,
3030b57459abSJulian Pullen 			    gettext("Permission denied"));
3031b57459abSJulian Pullen 			err = strdup(errstr);
3032b57459abSJulian Pullen 			if (err == NULL)
3033b57459abSJulian Pullen 				return (NS_LDAP_MEMORY);
3034b57459abSJulian Pullen 			MKERROR(LOG_INFO, cookie->errorp, NS_LDAP_INTERNAL, err,
303551b02b29SToomas Soome 			    NS_LDAP_MEMORY);
3036b57459abSJulian Pullen 			return (NS_LDAP_INTERNAL);
3037b57459abSJulian Pullen 		}
3038b57459abSJulian Pullen 		cookie->i_flags |= NS_LDAP_READ_SHADOW;
3039b57459abSJulian Pullen 		/*
3040b57459abSJulian Pullen 		 * We do not want to reuse connection (hence
3041b57459abSJulian Pullen 		 * keep it open) with admin credentials.
3042b57459abSJulian Pullen 		 * If NS_LDAP_KEEP_CONN is set, reject the
3043b57459abSJulian Pullen 		 * request.
3044b57459abSJulian Pullen 		 */
3045b57459abSJulian Pullen 		if (cookie->i_flags & NS_LDAP_KEEP_CONN)
3046b57459abSJulian Pullen 			return (NS_LDAP_INVALID_PARAM);
3047b57459abSJulian Pullen 		cookie->i_flags |= NS_LDAP_NEW_CONN;
3048b57459abSJulian Pullen 	}
3049b57459abSJulian Pullen 
3050b57459abSJulian Pullen 	return (NS_LDAP_SUCCESS);
3051b57459abSJulian Pullen }
3052b57459abSJulian Pullen 
30537c478bd9Sstevel@tonic-gate /*
3054479ac375Sdm  * internal function for __ns_ldap_list
30557c478bd9Sstevel@tonic-gate  */
3056479ac375Sdm static int
ldap_list(ns_ldap_list_batch_t * batch,const char * service,const char * filter,const char * sortattr,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int * rcp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata,ns_conn_user_t * conn_user)3057479ac375Sdm ldap_list(
3058479ac375Sdm 	ns_ldap_list_batch_t *batch,
30597c478bd9Sstevel@tonic-gate 	const char *service,
30607c478bd9Sstevel@tonic-gate 	const char *filter,
30619f2fd570SJulian Pullen 	const char *sortattr,
30627c478bd9Sstevel@tonic-gate 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
30637c478bd9Sstevel@tonic-gate 	char **realfilter, const void *userdata),
30647c478bd9Sstevel@tonic-gate 	const char * const *attribute,
30657c478bd9Sstevel@tonic-gate 	const ns_cred_t *auth,
30667c478bd9Sstevel@tonic-gate 	const int flags,
30677c478bd9Sstevel@tonic-gate 	ns_ldap_result_t **rResult, /* return result entries */
30687c478bd9Sstevel@tonic-gate 	ns_ldap_error_t **errorp,
3069479ac375Sdm 	int *rcp,
30707c478bd9Sstevel@tonic-gate 	int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3071e1dd0a2fSth 	const void *userdata, ns_conn_user_t *conn_user)
30727c478bd9Sstevel@tonic-gate {
30737c478bd9Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie;
30747c478bd9Sstevel@tonic-gate 	ns_ldap_search_desc_t	**sdlist = NULL;
30757c478bd9Sstevel@tonic-gate 	ns_ldap_search_desc_t	*dptr;
30767c478bd9Sstevel@tonic-gate 	ns_ldap_error_t		*error = NULL;
30777c478bd9Sstevel@tonic-gate 	char			**dns = NULL;
30787c478bd9Sstevel@tonic-gate 	int			scope;
30797c478bd9Sstevel@tonic-gate 	int			rc;
30808277a58bSchinlong 	int			from_result;
30817c478bd9Sstevel@tonic-gate 
30827c478bd9Sstevel@tonic-gate 	*errorp = NULL;
3083479ac375Sdm 	*rResult = NULL;
3084479ac375Sdm 	*rcp = NS_LDAP_SUCCESS;
30857c478bd9Sstevel@tonic-gate 
3086b57459abSJulian Pullen 	/*
3087b57459abSJulian Pullen 	 * Sanity check - NS_LDAP_READ_SHADOW is for our
3088b57459abSJulian Pullen 	 * own internal use.
3089b57459abSJulian Pullen 	 */
3090b57459abSJulian Pullen 	if (flags & NS_LDAP_READ_SHADOW)
3091b57459abSJulian Pullen 		return (NS_LDAP_INVALID_PARAM);
3092b57459abSJulian Pullen 
30937c478bd9Sstevel@tonic-gate 	/* Initialize State machine cookie */
30947c478bd9Sstevel@tonic-gate 	cookie = init_search_state_machine();
30957c478bd9Sstevel@tonic-gate 	if (cookie == NULL) {
3096479ac375Sdm 		*rcp = NS_LDAP_MEMORY;
30977c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
30987c478bd9Sstevel@tonic-gate 	}
3099e1dd0a2fSth 	cookie->conn_user = conn_user;
31007c478bd9Sstevel@tonic-gate 
31017c478bd9Sstevel@tonic-gate 	/* see if need to follow referrals */
31027c478bd9Sstevel@tonic-gate 	rc = __s_api_toFollowReferrals(flags,
3103699bceb8Smj 	    &cookie->followRef, errorp);
31047c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
31057c478bd9Sstevel@tonic-gate 		delete_search_cookie(cookie);
3106479ac375Sdm 		*rcp = rc;
31077c478bd9Sstevel@tonic-gate 		return (rc);
31087c478bd9Sstevel@tonic-gate 	}
31097c478bd9Sstevel@tonic-gate 
31107c478bd9Sstevel@tonic-gate 	/* get the service descriptor - or create a default one */
31117c478bd9Sstevel@tonic-gate 	rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3112e84b06c3SMichen Chang 	    &sdlist, &error);
31137c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
31147c478bd9Sstevel@tonic-gate 		delete_search_cookie(cookie);
31157c478bd9Sstevel@tonic-gate 		*errorp = error;
3116479ac375Sdm 		*rcp = rc;
31177c478bd9Sstevel@tonic-gate 		return (rc);
31187c478bd9Sstevel@tonic-gate 	}
31197c478bd9Sstevel@tonic-gate 
31207c478bd9Sstevel@tonic-gate 	if (sdlist == NULL) {
31217c478bd9Sstevel@tonic-gate 		/* Create default service Desc */
31227c478bd9Sstevel@tonic-gate 		sdlist = (ns_ldap_search_desc_t **)calloc(2,
3123699bceb8Smj 		    sizeof (ns_ldap_search_desc_t *));
31247c478bd9Sstevel@tonic-gate 		if (sdlist == NULL) {
31257c478bd9Sstevel@tonic-gate 			delete_search_cookie(cookie);
31267c478bd9Sstevel@tonic-gate 			cookie = NULL;
3127479ac375Sdm 			*rcp = NS_LDAP_MEMORY;
31287c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
31297c478bd9Sstevel@tonic-gate 		}
31307c478bd9Sstevel@tonic-gate 		dptr = (ns_ldap_search_desc_t *)
3131699bceb8Smj 		    calloc(1, sizeof (ns_ldap_search_desc_t));
31327c478bd9Sstevel@tonic-gate 		if (dptr == NULL) {
31337c478bd9Sstevel@tonic-gate 			free(sdlist);
31347c478bd9Sstevel@tonic-gate 			delete_search_cookie(cookie);
31357c478bd9Sstevel@tonic-gate 			cookie = NULL;
3136479ac375Sdm 			*rcp = NS_LDAP_MEMORY;
31377c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
31387c478bd9Sstevel@tonic-gate 		}
31397c478bd9Sstevel@tonic-gate 		sdlist[0] = dptr;
31407c478bd9Sstevel@tonic-gate 
31417c478bd9Sstevel@tonic-gate 		/* default base */
31427c478bd9Sstevel@tonic-gate 		rc = __s_api_getDNs(&dns, service, &cookie->errorp);
31437c478bd9Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
31447c478bd9Sstevel@tonic-gate 			if (dns) {
31457c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(dns);
31467c478bd9Sstevel@tonic-gate 				dns = NULL;
31477c478bd9Sstevel@tonic-gate 			}
31487c478bd9Sstevel@tonic-gate 			*errorp = cookie->errorp;
31497c478bd9Sstevel@tonic-gate 			cookie->errorp = NULL;
31507c478bd9Sstevel@tonic-gate 			delete_search_cookie(cookie);
31517c478bd9Sstevel@tonic-gate 			cookie = NULL;
3152479ac375Sdm 			*rcp = rc;
31537c478bd9Sstevel@tonic-gate 			return (rc);
31547c478bd9Sstevel@tonic-gate 		}
31557c478bd9Sstevel@tonic-gate 		dptr->basedn = strdup(dns[0]);
31567c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(dns);
31577c478bd9Sstevel@tonic-gate 		dns = NULL;
31587c478bd9Sstevel@tonic-gate 
31597c478bd9Sstevel@tonic-gate 		/* default scope */
31607c478bd9Sstevel@tonic-gate 		scope = 0;
31617c478bd9Sstevel@tonic-gate 		rc = __s_api_getSearchScope(&scope, &cookie->errorp);
31627c478bd9Sstevel@tonic-gate 		dptr->scope = scope;
31637c478bd9Sstevel@tonic-gate 	}
31647c478bd9Sstevel@tonic-gate 
31657c478bd9Sstevel@tonic-gate 	cookie->sdlist = sdlist;
31667c478bd9Sstevel@tonic-gate 
31677c478bd9Sstevel@tonic-gate 	/*
31687c478bd9Sstevel@tonic-gate 	 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
31697c478bd9Sstevel@tonic-gate 	 */
31707c478bd9Sstevel@tonic-gate 	if (flags & NS_LDAP_PAGE_CTRL)
31717c478bd9Sstevel@tonic-gate 		cookie->use_paging = TRUE;
31727c478bd9Sstevel@tonic-gate 	else
31737c478bd9Sstevel@tonic-gate 		cookie->use_paging = FALSE;
31747c478bd9Sstevel@tonic-gate 
31757c478bd9Sstevel@tonic-gate 	/* Set up other arguments */
31767c478bd9Sstevel@tonic-gate 	cookie->userdata = userdata;
31777c478bd9Sstevel@tonic-gate 	if (init_filter_cb != NULL) {
31787c478bd9Sstevel@tonic-gate 		cookie->init_filter_cb = init_filter_cb;
31797c478bd9Sstevel@tonic-gate 		cookie->use_filtercb = 1;
31807c478bd9Sstevel@tonic-gate 	}
31817c478bd9Sstevel@tonic-gate 	if (callback != NULL) {
31827c478bd9Sstevel@tonic-gate 		cookie->callback = callback;
31837c478bd9Sstevel@tonic-gate 		cookie->use_usercb = 1;
31847c478bd9Sstevel@tonic-gate 	}
3185b57459abSJulian Pullen 
3186b57459abSJulian Pullen 	/* check_shadow() may add extra value to cookie->i_flags */
3187b57459abSJulian Pullen 	cookie->i_flags = flags;
31887c478bd9Sstevel@tonic-gate 	if (service) {
31897c478bd9Sstevel@tonic-gate 		cookie->service = strdup(service);
31907c478bd9Sstevel@tonic-gate 		if (cookie->service == NULL) {
31917c478bd9Sstevel@tonic-gate 			delete_search_cookie(cookie);
31927c478bd9Sstevel@tonic-gate 			cookie = NULL;
3193479ac375Sdm 			*rcp = NS_LDAP_MEMORY;
31947c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
31957c478bd9Sstevel@tonic-gate 		}
3196b57459abSJulian Pullen 
3197b57459abSJulian Pullen 		/*
3198b57459abSJulian Pullen 		 * If given, use the credential given by the caller, and
3199b57459abSJulian Pullen 		 * skip the credential check required for shadow update.
3200b57459abSJulian Pullen 		 */
3201b57459abSJulian Pullen 		if (auth == NULL) {
3202b57459abSJulian Pullen 			rc = check_shadow(cookie, service);
3203b57459abSJulian Pullen 			if (rc != NS_LDAP_SUCCESS) {
3204b57459abSJulian Pullen 				*errorp = cookie->errorp;
3205b57459abSJulian Pullen 				cookie->errorp = NULL;
3206b57459abSJulian Pullen 				delete_search_cookie(cookie);
3207b57459abSJulian Pullen 				cookie = NULL;
3208b57459abSJulian Pullen 				*rcp = rc;
3209b57459abSJulian Pullen 				return (rc);
3210b57459abSJulian Pullen 			}
3211b57459abSJulian Pullen 		}
32127c478bd9Sstevel@tonic-gate 	}
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate 	cookie->i_filter = strdup(filter);
32157c478bd9Sstevel@tonic-gate 	cookie->i_attr = attribute;
32167c478bd9Sstevel@tonic-gate 	cookie->i_auth = auth;
32179f2fd570SJulian Pullen 	cookie->i_sortattr = sortattr;
32187c478bd9Sstevel@tonic-gate 
3219479ac375Sdm 	if (batch != NULL) {
3220479ac375Sdm 		cookie->batch = batch;
3221e1dd0a2fSth 		cookie->reinit_on_retriable_err = B_TRUE;
3222479ac375Sdm 		cookie->no_wait = B_TRUE;
3223479ac375Sdm 		(void) search_state_machine(cookie, INIT, 0);
3224479ac375Sdm 		cookie->no_wait = B_FALSE;
3225479ac375Sdm 		rc = cookie->err_rc;
3226479ac375Sdm 
3227479ac375Sdm 		if (rc == NS_LDAP_SUCCESS) {
3228479ac375Sdm 			/*
3229479ac375Sdm 			 * Here rc == NS_LDAP_SUCCESS means that the state
3230479ac375Sdm 			 * machine init'ed successfully. The actual status
3231479ac375Sdm 			 * of the search will be determined by
3232479ac375Sdm 			 * __ns_ldap_list_batch_end(). Add the cookie to our
3233479ac375Sdm 			 * batch.
3234479ac375Sdm 			 */
3235479ac375Sdm 			cookie->caller_result = rResult;
3236479ac375Sdm 			cookie->caller_errorp = errorp;
3237479ac375Sdm 			cookie->caller_rc = rcp;
3238479ac375Sdm 			cookie->next_cookie_in_batch = batch->cookie_list;
3239479ac375Sdm 			batch->cookie_list = cookie;
3240479ac375Sdm 			batch->nactive++;
3241479ac375Sdm 			return (rc);
3242479ac375Sdm 		}
3243479ac375Sdm 		/*
3244479ac375Sdm 		 * If state machine init failed then copy error to the caller
3245479ac375Sdm 		 * and delete the cookie.
3246479ac375Sdm 		 */
3247479ac375Sdm 	} else {
3248479ac375Sdm 		(void) search_state_machine(cookie, INIT, 0);
3249479ac375Sdm 	}
32507c478bd9Sstevel@tonic-gate 
32517c478bd9Sstevel@tonic-gate 	/* Copy results back to user */
32527c478bd9Sstevel@tonic-gate 	rc = cookie->err_rc;
3253e1dd0a2fSth 	if (rc != NS_LDAP_SUCCESS) {
3254e1dd0a2fSth 		if (conn_user != NULL && conn_user->ns_error != NULL) {
3255e1dd0a2fSth 			*errorp = conn_user->ns_error;
3256e1dd0a2fSth 			conn_user->ns_error = NULL;
32578f0bb794SToomas Soome 		} else {
3258e1dd0a2fSth 			*errorp = cookie->errorp;
32598f0bb794SToomas Soome 		}
3260e1dd0a2fSth 	}
32617c478bd9Sstevel@tonic-gate 	*rResult = cookie->result;
32628277a58bSchinlong 	from_result = cookie->err_from_result;
32637c478bd9Sstevel@tonic-gate 
32647c478bd9Sstevel@tonic-gate 	cookie->errorp = NULL;
32657c478bd9Sstevel@tonic-gate 	cookie->result = NULL;
32667c478bd9Sstevel@tonic-gate 	delete_search_cookie(cookie);
32677c478bd9Sstevel@tonic-gate 	cookie = NULL;
32687c478bd9Sstevel@tonic-gate 
32698277a58bSchinlong 	if (from_result == 0 && *rResult == NULL)
32707c478bd9Sstevel@tonic-gate 		rc = NS_LDAP_NOTFOUND;
3271479ac375Sdm 	*rcp = rc;
32727c478bd9Sstevel@tonic-gate 	return (rc);
32737c478bd9Sstevel@tonic-gate }
32747c478bd9Sstevel@tonic-gate 
3275479ac375Sdm 
3276479ac375Sdm /*
3277479ac375Sdm  * __ns_ldap_list performs one or more LDAP searches to a given
3278479ac375Sdm  * directory server using service search descriptors and schema
3279e1dd0a2fSth  * mapping as appropriate. The operation may be retried a
3280e1dd0a2fSth  * couple of times in error situations.
3281479ac375Sdm  */
3282479ac375Sdm int
__ns_ldap_list(const char * service,const char * filter,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata)3283479ac375Sdm __ns_ldap_list(
3284479ac375Sdm 	const char *service,
3285479ac375Sdm 	const char *filter,
3286479ac375Sdm 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3287479ac375Sdm 	char **realfilter, const void *userdata),
3288479ac375Sdm 	const char * const *attribute,
3289479ac375Sdm 	const ns_cred_t *auth,
3290479ac375Sdm 	const int flags,
3291479ac375Sdm 	ns_ldap_result_t **rResult, /* return result entries */
3292479ac375Sdm 	ns_ldap_error_t **errorp,
3293479ac375Sdm 	int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3294479ac375Sdm 	const void *userdata)
32959f2fd570SJulian Pullen {
32969f2fd570SJulian Pullen 	int mod_flags;
32979f2fd570SJulian Pullen 	/*
32989f2fd570SJulian Pullen 	 * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
32999f2fd570SJulian Pullen 	 * support this. If you want to use this option call the API
33009f2fd570SJulian Pullen 	 * __ns_ldap_list_sort() with has the sort attribute.
33019f2fd570SJulian Pullen 	 */
33029f2fd570SJulian Pullen 	mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
33039f2fd570SJulian Pullen 
33049f2fd570SJulian Pullen 	return (__ns_ldap_list_sort(service, filter, NULL, init_filter_cb,
33059f2fd570SJulian Pullen 	    attribute, auth, mod_flags, rResult, errorp,
33069f2fd570SJulian Pullen 	    callback, userdata));
33079f2fd570SJulian Pullen }
33089f2fd570SJulian Pullen 
33099f2fd570SJulian Pullen /*
33109f2fd570SJulian Pullen  * __ns_ldap_list_sort performs one or more LDAP searches to a given
33119f2fd570SJulian Pullen  * directory server using service search descriptors and schema
33129f2fd570SJulian Pullen  * mapping as appropriate. The operation may be retried a
33139f2fd570SJulian Pullen  * couple of times in error situations.
33149f2fd570SJulian Pullen  */
33159f2fd570SJulian Pullen int
__ns_ldap_list_sort(const char * service,const char * filter,const char * sortattr,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata)33169f2fd570SJulian Pullen __ns_ldap_list_sort(
33179f2fd570SJulian Pullen 	const char *service,
33189f2fd570SJulian Pullen 	const char *filter,
33199f2fd570SJulian Pullen 	const char *sortattr,
33209f2fd570SJulian Pullen 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
33219f2fd570SJulian Pullen 	char **realfilter, const void *userdata),
33229f2fd570SJulian Pullen 	const char * const *attribute,
33239f2fd570SJulian Pullen 	const ns_cred_t *auth,
33249f2fd570SJulian Pullen 	const int flags,
33259f2fd570SJulian Pullen 	ns_ldap_result_t **rResult, /* return result entries */
33269f2fd570SJulian Pullen 	ns_ldap_error_t **errorp,
33279f2fd570SJulian Pullen 	int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
33289f2fd570SJulian Pullen 	const void *userdata)
3329479ac375Sdm {
3330e1dd0a2fSth 	ns_conn_user_t	*cu = NULL;
3331e1dd0a2fSth 	int		try_cnt = 0;
3332e1dd0a2fSth 	int		rc = NS_LDAP_SUCCESS, trc;
3333e1dd0a2fSth 
3334e1dd0a2fSth 	for (;;) {
3335e1dd0a2fSth 		if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3336e1dd0a2fSth 		    &try_cnt, &rc, errorp) == 0)
3337e1dd0a2fSth 			break;
33389f2fd570SJulian Pullen 		rc = ldap_list(NULL, service, filter, sortattr, init_filter_cb,
33399f2fd570SJulian Pullen 		    attribute, auth, flags, rResult, errorp, &trc, callback,
33409f2fd570SJulian Pullen 		    userdata, cu);
3341e1dd0a2fSth 	}
3342479ac375Sdm 
3343e1dd0a2fSth 	return (rc);
3344e1dd0a2fSth }
3345479ac375Sdm 
3346479ac375Sdm /*
3347479ac375Sdm  * Create and initialize batch for native LDAP lookups
3348479ac375Sdm  */
3349479ac375Sdm int
__ns_ldap_list_batch_start(ns_ldap_list_batch_t ** batch)3350479ac375Sdm __ns_ldap_list_batch_start(ns_ldap_list_batch_t **batch)
3351479ac375Sdm {
3352479ac375Sdm 	*batch = calloc(1, sizeof (ns_ldap_list_batch_t));
3353479ac375Sdm 	if (*batch == NULL)
3354479ac375Sdm 		return (NS_LDAP_MEMORY);
3355479ac375Sdm 	return (NS_LDAP_SUCCESS);
3356479ac375Sdm }
3357479ac375Sdm 
3358479ac375Sdm 
3359479ac375Sdm /*
3360479ac375Sdm  * Add a LDAP search request to the batch.
3361479ac375Sdm  */
3362479ac375Sdm int
__ns_ldap_list_batch_add(ns_ldap_list_batch_t * batch,const char * service,const char * filter,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,ns_ldap_result_t ** rResult,ns_ldap_error_t ** errorp,int * rcp,int (* callback)(const ns_ldap_entry_t * entry,const void * userdata),const void * userdata)3363479ac375Sdm __ns_ldap_list_batch_add(
3364479ac375Sdm 	ns_ldap_list_batch_t *batch,
3365479ac375Sdm 	const char *service,
3366479ac375Sdm 	const char *filter,
3367479ac375Sdm 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3368479ac375Sdm 	char **realfilter, const void *userdata),
3369479ac375Sdm 	const char * const *attribute,
3370479ac375Sdm 	const ns_cred_t *auth,
3371479ac375Sdm 	const int flags,
3372479ac375Sdm 	ns_ldap_result_t **rResult, /* return result entries */
3373479ac375Sdm 	ns_ldap_error_t **errorp,
3374479ac375Sdm 	int *rcp,
3375479ac375Sdm 	int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3376479ac375Sdm 	const void *userdata)
3377479ac375Sdm {
3378e1dd0a2fSth 	ns_conn_user_t	*cu;
3379e1dd0a2fSth 	int		rc;
33809f2fd570SJulian Pullen 	int		mod_flags;
3381e1dd0a2fSth 
3382e1dd0a2fSth 	cu =  __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, 0);
3383e1dd0a2fSth 	if (cu == NULL) {
3384e1dd0a2fSth 		if (rcp != NULL)
3385e1dd0a2fSth 			*rcp = NS_LDAP_MEMORY;
3386e1dd0a2fSth 		return (NS_LDAP_MEMORY);
3387e1dd0a2fSth 	}
3388e1dd0a2fSth 
33899f2fd570SJulian Pullen 	/*
33909f2fd570SJulian Pullen 	 * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not
33919f2fd570SJulian Pullen 	 * support this.
33929f2fd570SJulian Pullen 	 */
33939f2fd570SJulian Pullen 	mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
33949f2fd570SJulian Pullen 
33959f2fd570SJulian Pullen 	rc = ldap_list(batch, service, filter, NULL, init_filter_cb, attribute,
33969f2fd570SJulian Pullen 	    auth, mod_flags, rResult, errorp, rcp, callback, userdata, cu);
3397e1dd0a2fSth 
3398e1dd0a2fSth 	/*
3399e1dd0a2fSth 	 * Free the conn_user if the cookie was not batched. If the cookie
3400e1dd0a2fSth 	 * was batched then __ns_ldap_list_batch_end or release will free the
3401e1dd0a2fSth 	 * conn_user. The batch API instructs the search_state_machine
3402e1dd0a2fSth 	 * to reinit and retry (max 3 times) on retriable LDAP errors.
3403e1dd0a2fSth 	 */
3404e1dd0a2fSth 	if (rc != NS_LDAP_SUCCESS && cu != NULL) {
3405e1dd0a2fSth 		if (cu->conn_mt != NULL)
3406e1dd0a2fSth 			__s_api_conn_mt_return(cu);
3407e1dd0a2fSth 		__s_api_conn_user_free(cu);
3408e1dd0a2fSth 	}
3409e1dd0a2fSth 	return (rc);
3410479ac375Sdm }
3411479ac375Sdm 
3412479ac375Sdm 
3413479ac375Sdm /*
3414479ac375Sdm  * Free batch.
3415479ac375Sdm  */
3416479ac375Sdm void
__ns_ldap_list_batch_release(ns_ldap_list_batch_t * batch)3417479ac375Sdm __ns_ldap_list_batch_release(ns_ldap_list_batch_t *batch)
3418479ac375Sdm {
3419479ac375Sdm 	ns_ldap_cookie_t	*c, *next;
3420479ac375Sdm 
3421479ac375Sdm 	for (c = batch->cookie_list; c != NULL; c = next) {
3422479ac375Sdm 		next = c->next_cookie_in_batch;
3423e1dd0a2fSth 		if (c->conn_user != NULL) {
3424e1dd0a2fSth 			if (c->conn_user->conn_mt != NULL)
3425e1dd0a2fSth 				__s_api_conn_mt_return(c->conn_user);
3426e1dd0a2fSth 			__s_api_conn_user_free(c->conn_user);
3427e1dd0a2fSth 			c->conn_user = NULL;
3428e1dd0a2fSth 		}
3429479ac375Sdm 		delete_search_cookie(c);
3430479ac375Sdm 	}
3431479ac375Sdm 	free(batch);
3432479ac375Sdm }
3433479ac375Sdm 
3434e1dd0a2fSth #define	LD_USING_STATE(st) \
3435e1dd0a2fSth 	((st == DO_SEARCH) || (st == MULTI_RESULT) || (st == NEXT_RESULT))
3436479ac375Sdm 
3437479ac375Sdm /*
3438479ac375Sdm  * Process batch. Everytime this function is called it selects an
3439479ac375Sdm  * active cookie from the batch and single steps through the
3440479ac375Sdm  * search_state_machine for the selected cookie. If lookup associated
3441479ac375Sdm  * with the cookie is complete (success or error) then the cookie is
3442479ac375Sdm  * removed from the batch and its memory freed.
3443479ac375Sdm  *
3444479ac375Sdm  * Returns 1 (if batch still has active cookies)
3445479ac375Sdm  *         0 (if batch has no more active cookies)
3446479ac375Sdm  *        -1 (on errors, *rcp will contain the error code)
3447479ac375Sdm  *
3448479ac375Sdm  * The caller should call this function in a loop as long as it returns 1
3449479ac375Sdm  * to process all the requests added to the batch. The results (and errors)
3450479ac375Sdm  * will be available in the locations provided by the caller at the time of
3451479ac375Sdm  * __ns_ldap_list_batch_add().
3452479ac375Sdm  */
3453479ac375Sdm static
3454479ac375Sdm int
__ns_ldap_list_batch_process(ns_ldap_list_batch_t * batch,int * rcp)3455479ac375Sdm __ns_ldap_list_batch_process(ns_ldap_list_batch_t *batch, int *rcp)
3456479ac375Sdm {
3457479ac375Sdm 	ns_ldap_cookie_t	*c, *ptr, **prev;
3458479ac375Sdm 	ns_state_t		state;
3459e1dd0a2fSth 	ns_ldap_error_t		*errorp = NULL;
3460479ac375Sdm 	int			rc;
3461479ac375Sdm 
3462479ac375Sdm 	/* Check if are already done */
3463479ac375Sdm 	if (batch->nactive == 0)
3464479ac375Sdm 		return (0);
3465479ac375Sdm 
3466479ac375Sdm 	/* Get the next cookie from the batch */
3467479ac375Sdm 	c = (batch->next_cookie == NULL) ?
3468479ac375Sdm 	    batch->cookie_list : batch->next_cookie;
3469479ac375Sdm 
3470479ac375Sdm 	batch->next_cookie = c->next_cookie_in_batch;
3471479ac375Sdm 
3472e1dd0a2fSth 	/*
3473e1dd0a2fSth 	 * Checks the status of the cookie's connection if it needs
3474e1dd0a2fSth 	 * to use that connection for ldap_search_ext or ldap_result.
3475e1dd0a2fSth 	 * If the connection is no longer good but worth retrying
3476e1dd0a2fSth 	 * then reinit the search_state_machine for this cookie
3477e1dd0a2fSth 	 * starting from the first search descriptor. REINIT will
3478e1dd0a2fSth 	 * clear any leftover results if max retries have not been
3479e1dd0a2fSth 	 * reached and redo the search (which may also involve
3480e1dd0a2fSth 	 * following referrals again).
3481e1dd0a2fSth 	 *
3482e1dd0a2fSth 	 * Note that each cookie in the batch will make this
3483e1dd0a2fSth 	 * determination when it reaches one of the LD_USING_STATES.
3484e1dd0a2fSth 	 */
3485e1dd0a2fSth 	if (LD_USING_STATE(c->new_state) && c->conn_user != NULL) {
3486e1dd0a2fSth 		rc = __s_api_setup_getnext(c->conn_user, &c->err_rc, &errorp);
3487e1dd0a2fSth 		if (rc == LDAP_BUSY || rc == LDAP_UNAVAILABLE ||
3488e1dd0a2fSth 		    rc == LDAP_UNWILLING_TO_PERFORM) {
3489e1dd0a2fSth 			if (errorp != NULL) {
3490e1dd0a2fSth 				(void) __ns_ldap_freeError(&c->errorp);
3491e1dd0a2fSth 				c->errorp = errorp;
3492e1dd0a2fSth 			}
3493e1dd0a2fSth 			c->new_state = REINIT;
3494e1dd0a2fSth 		} else if (rc == LDAP_CONNECT_ERROR ||
3495e1dd0a2fSth 		    rc == LDAP_SERVER_DOWN) {
3496e1dd0a2fSth 			if (errorp != NULL) {
3497e1dd0a2fSth 				(void) __ns_ldap_freeError(&c->errorp);
3498e1dd0a2fSth 				c->errorp = errorp;
3499e1dd0a2fSth 			}
3500e1dd0a2fSth 			c->new_state = REINIT;
3501e1dd0a2fSth 			/*
3502e1dd0a2fSth 			 * MT connection is not usable,
3503e1dd0a2fSth 			 * close it before REINIT.
3504e1dd0a2fSth 			 */
3505e1dd0a2fSth 			__s_api_conn_mt_close(
3506e1dd0a2fSth 			    c->conn_user, rc, NULL);
3507e1dd0a2fSth 		} else if (rc != NS_LDAP_SUCCESS) {
3508479ac375Sdm 			if (rcp != NULL)
3509479ac375Sdm 				*rcp = rc;
3510e1dd0a2fSth 			*c->caller_result = NULL;
3511e1dd0a2fSth 			*c->caller_errorp = errorp;
3512e1dd0a2fSth 			*c->caller_rc = rc;
3513479ac375Sdm 			return (-1);
3514479ac375Sdm 		}
3515479ac375Sdm 	}
3516479ac375Sdm 
3517479ac375Sdm 	for (;;) {
3518479ac375Sdm 		/* Single step through the search_state_machine */
3519479ac375Sdm 		state = search_state_machine(c, c->new_state, ONE_STEP);
3520479ac375Sdm 		switch (state) {
3521479ac375Sdm 		case LDAP_ERROR:
3522479ac375Sdm 			(void) search_state_machine(c, state, ONE_STEP);
3523479ac375Sdm 			(void) search_state_machine(c, CLEAR_RESULTS, ONE_STEP);
3524479ac375Sdm 			/* FALLTHROUGH */
3525479ac375Sdm 		case ERROR:
3526479ac375Sdm 		case EXIT:
3527479ac375Sdm 			*c->caller_result = c->result;
3528479ac375Sdm 			*c->caller_errorp = c->errorp;
3529479ac375Sdm 			*c->caller_rc =
3530479ac375Sdm 			    (c->result == NULL && c->err_from_result == 0)
3531479ac375Sdm 			    ? NS_LDAP_NOTFOUND : c->err_rc;
3532479ac375Sdm 			c->result = NULL;
3533479ac375Sdm 			c->errorp = NULL;
3534479ac375Sdm 			/* Remove the cookie from the batch */
3535479ac375Sdm 			ptr = batch->cookie_list;
3536479ac375Sdm 			prev = &batch->cookie_list;
3537479ac375Sdm 			while (ptr != NULL) {
3538479ac375Sdm 				if (ptr == c) {
3539479ac375Sdm 					*prev = ptr->next_cookie_in_batch;
3540479ac375Sdm 					break;
3541479ac375Sdm 				}
3542479ac375Sdm 				prev = &ptr->next_cookie_in_batch;
3543479ac375Sdm 				ptr = ptr->next_cookie_in_batch;
3544479ac375Sdm 			}
3545479ac375Sdm 			/* Delete cookie and decrement active cookie count */
3546e1dd0a2fSth 			if (c->conn_user != NULL) {
3547e1dd0a2fSth 				if (c->conn_user->conn_mt != NULL)
3548e1dd0a2fSth 					__s_api_conn_mt_return(c->conn_user);
3549e1dd0a2fSth 				__s_api_conn_user_free(c->conn_user);
3550e1dd0a2fSth 				c->conn_user = NULL;
3551e1dd0a2fSth 			}
3552479ac375Sdm 			delete_search_cookie(c);
3553479ac375Sdm 			batch->nactive--;
3554479ac375Sdm 			break;
3555479ac375Sdm 		case NEXT_RESULT:
3556479ac375Sdm 		case MULTI_RESULT:
3557479ac375Sdm 			/*
3558479ac375Sdm 			 * This means that search_state_machine needs to do
3559479ac375Sdm 			 * another ldap_result() for the cookie in question.
3560479ac375Sdm 			 * We only do at most one ldap_result() per call in
3561479ac375Sdm 			 * this function and therefore we return. This allows
3562479ac375Sdm 			 * the caller to process results from other cookies
3563479ac375Sdm 			 * in the batch without getting tied up on just one
3564479ac375Sdm 			 * cookie.
3565479ac375Sdm 			 */
3566479ac375Sdm 			break;
3567479ac375Sdm 		default:
3568479ac375Sdm 			/*
3569479ac375Sdm 			 * This includes states that follow NEXT_RESULT or
3570479ac375Sdm 			 * MULTI_RESULT such as PROCESS_RESULT and
3571479ac375Sdm 			 * END_PROCESS_RESULT. We continue processing
3572479ac375Sdm 			 * this cookie till we reach either the error, exit
3573479ac375Sdm 			 * or the result states.
3574479ac375Sdm 			 */
3575479ac375Sdm 			continue;
3576479ac375Sdm 		}
3577479ac375Sdm 		break;
3578479ac375Sdm 	}
3579479ac375Sdm 
3580479ac375Sdm 	/* Return 0 if no more cookies left otherwise 1 */
3581479ac375Sdm 	return ((batch->nactive > 0) ? 1 : 0);
3582479ac375Sdm }
3583479ac375Sdm 
3584479ac375Sdm 
3585479ac375Sdm /*
3586479ac375Sdm  * Process all the active cookies in the batch and when none
3587479ac375Sdm  * remains finalize the batch.
3588479ac375Sdm  */
3589479ac375Sdm int
__ns_ldap_list_batch_end(ns_ldap_list_batch_t * batch)3590479ac375Sdm __ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch)
3591479ac375Sdm {
3592479ac375Sdm 	int rc = NS_LDAP_SUCCESS;
3593479ac375Sdm 	while (__ns_ldap_list_batch_process(batch, &rc) > 0)
3594479ac375Sdm 		;
3595479ac375Sdm 	__ns_ldap_list_batch_release(batch);
3596479ac375Sdm 	return (rc);
3597479ac375Sdm }
3598479ac375Sdm 
3599d7ab8532SJason King typedef struct lookup_data {
3600d7ab8532SJason King 	const char *lkd_dn;
3601d7ab8532SJason King 	const char *lkd_service;
3602d7ab8532SJason King 	const char *lkd_filter;
3603d7ab8532SJason King 	const ns_cred_t *lkd_cred;
3604d7ab8532SJason King 	ns_conn_user_t *lkd_user;
3605d7ab8532SJason King } lookup_data_t;
3606d7ab8532SJason King 
36077c478bd9Sstevel@tonic-gate /*
3608d7ab8532SJason King  * This creates a service search descriptor that can be used to
3609d7ab8532SJason King  * retrieve a specific DN by using the DN as the basedn with a search
3610d7ab8532SJason King  * scope of 'base'. We don't use any service SSDs in this instance since
3611d7ab8532SJason King  * they are intended to search specific locations/subtrees and filter the
3612d7ab8532SJason King  * results, while here we are wanting to retrieve a specific entry.
36137c478bd9Sstevel@tonic-gate  */
36147c478bd9Sstevel@tonic-gate static int
lookup_create_ssd(lookup_data_t * dn_data,ns_ldap_search_desc_t ** descpp)3615d7ab8532SJason King lookup_create_ssd(lookup_data_t *dn_data, ns_ldap_search_desc_t **descpp)
36167c478bd9Sstevel@tonic-gate {
3617d7ab8532SJason King 	ns_ldap_search_desc_t *dptr;
3618d7ab8532SJason King 
3619d7ab8532SJason King 	*descpp = NULL;
3620d7ab8532SJason King 
3621d7ab8532SJason King 	dptr = calloc(1, sizeof (ns_ldap_search_desc_t));
3622d7ab8532SJason King 	if (dptr == NULL)
3623d7ab8532SJason King 		return (NS_LDAP_MEMORY);
36247c478bd9Sstevel@tonic-gate 
3625d7ab8532SJason King 	dptr->basedn = strdup(dn_data->lkd_dn);
3626d7ab8532SJason King 	dptr->scope = NS_LDAP_SCOPE_BASE;
3627d7ab8532SJason King 	dptr->filter = strdup(dn_data->lkd_filter);
3628d7ab8532SJason King 
3629d7ab8532SJason King 	if (dptr->basedn == NULL || dptr->filter == NULL) {
3630d7ab8532SJason King 		__ns_ldap_freeASearchDesc(dptr);
3631d7ab8532SJason King 		return (NS_LDAP_MEMORY);
3632d7ab8532SJason King 	}
3633d7ab8532SJason King 
3634d7ab8532SJason King 	*descpp = dptr;
3635d7ab8532SJason King 	return (NS_LDAP_SUCCESS);
3636d7ab8532SJason King }
3637d7ab8532SJason King 
3638d7ab8532SJason King static int
lookup_dn(lookup_data_t * dn_data,const char ** attrs,ns_ldap_result_t ** resultp,ns_ldap_error_t ** errorp)3639d7ab8532SJason King lookup_dn(lookup_data_t *dn_data, const char **attrs,
3640d7ab8532SJason King     ns_ldap_result_t **resultp, ns_ldap_error_t **errorp)
3641d7ab8532SJason King {
36427c478bd9Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie;
3643d7ab8532SJason King 	int			rc = 0;
36447c478bd9Sstevel@tonic-gate 	int			flags = 0;
36457c478bd9Sstevel@tonic-gate 
36467c478bd9Sstevel@tonic-gate 	*errorp = NULL;
3647d7ab8532SJason King 	*resultp = NULL;
3648d7ab8532SJason King 
3649d7ab8532SJason King 	if (dn_data == NULL || dn_data->lkd_dn == NULL ||
3650d7ab8532SJason King 	    dn_data->lkd_dn[0] == '\0' || dn_data->lkd_filter == NULL)
3651d7ab8532SJason King 		return (NS_LDAP_INVALID_PARAM);
36527c478bd9Sstevel@tonic-gate 
36537c478bd9Sstevel@tonic-gate 	cookie = init_search_state_machine();
3654d7ab8532SJason King 	if (cookie == NULL)
36557c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
36567c478bd9Sstevel@tonic-gate 
3657d7ab8532SJason King 	rc = __s_api_toFollowReferrals(flags, &cookie->followRef, errorp);
3658d7ab8532SJason King 	if (rc != NS_LDAP_SUCCESS)
3659d7ab8532SJason King 		goto out;
36607c478bd9Sstevel@tonic-gate 
3661d7ab8532SJason King 	/* 1 for SSD, 1 for terminating NULL */
3662d7ab8532SJason King 	cookie->sdlist = calloc(2, sizeof (ns_ldap_search_desc_t *));
3663d7ab8532SJason King 	if (cookie->sdlist == NULL) {
3664d7ab8532SJason King 		rc = NS_LDAP_MEMORY;
3665d7ab8532SJason King 		goto out;
36667c478bd9Sstevel@tonic-gate 	}
36677c478bd9Sstevel@tonic-gate 
3668d7ab8532SJason King 	rc = lookup_create_ssd(dn_data, &cookie->sdlist[0]);
3669d7ab8532SJason King 	if (rc != NS_LDAP_SUCCESS)
3670d7ab8532SJason King 		goto out;
36717c478bd9Sstevel@tonic-gate 
3672d7ab8532SJason King 	if (dn_data->lkd_service != NULL) {
3673d7ab8532SJason King 		/*
3674d7ab8532SJason King 		 * If a service was specified, set that on the cookie so
3675d7ab8532SJason King 		 * that search_state_machine() will properly map
3676d7ab8532SJason King 		 * attributes and objectclasses.
3677d7ab8532SJason King 		 */
3678d7ab8532SJason King 		cookie->service = strdup(dn_data->lkd_service);
3679d7ab8532SJason King 		if (cookie->service == NULL) {
3680d7ab8532SJason King 			rc = NS_LDAP_MEMORY;
3681d7ab8532SJason King 			goto out;
3682d7ab8532SJason King 		}
3683d7ab8532SJason King 	}
36847c478bd9Sstevel@tonic-gate 
3685d7ab8532SJason King 	cookie->i_attr = attrs;
3686d7ab8532SJason King 	cookie->i_auth = dn_data->lkd_cred;
36877c478bd9Sstevel@tonic-gate 	cookie->i_flags = 0;
3688d7ab8532SJason King 	cookie->i_filter = strdup(dn_data->lkd_filter);
3689d7ab8532SJason King 	if (cookie->i_filter == NULL) {
3690d7ab8532SJason King 		rc = NS_LDAP_MEMORY;
3691d7ab8532SJason King 		goto out;
3692d7ab8532SJason King 	}
36937c478bd9Sstevel@tonic-gate 
3694d7ab8532SJason King 	/*
3695d7ab8532SJason King 	 * Actually perform the search. The return value is only used when
3696d7ab8532SJason King 	 * iterating through multiple results. Since we are searching with
3697d7ab8532SJason King 	 * a scope of base, we will always get at most one result entry,
3698d7ab8532SJason King 	 * we ignore the return value and look at err_rc to determine if
3699d7ab8532SJason King 	 * there were any errors.
3700d7ab8532SJason King 	 */
3701d7ab8532SJason King 	(void) search_state_machine(cookie, INIT, 0);
37027c478bd9Sstevel@tonic-gate 	rc = cookie->err_rc;
3703d7ab8532SJason King 
3704e1dd0a2fSth 	if (rc != NS_LDAP_SUCCESS) {
3705d7ab8532SJason King 		ns_conn_user_t *user = dn_data->lkd_user;
3706d7ab8532SJason King 
3707d7ab8532SJason King 		if (user != NULL && user->ns_error != NULL) {
3708d7ab8532SJason King 			*errorp = user->ns_error;
3709d7ab8532SJason King 			user->ns_error = NULL;
37108f0bb794SToomas Soome 		} else {
3711e1dd0a2fSth 			*errorp = cookie->errorp;
3712d7ab8532SJason King 			cookie->errorp = NULL;
37138f0bb794SToomas Soome 		}
3714d7ab8532SJason King 	} else if (cookie->result != NULL) {
3715d7ab8532SJason King 		*resultp = cookie->result;
3716d7ab8532SJason King 		cookie->result = NULL;
3717d7ab8532SJason King 	} else {
37187c478bd9Sstevel@tonic-gate 		rc = NS_LDAP_NOTFOUND;
37197c478bd9Sstevel@tonic-gate 	}
3720d7ab8532SJason King 
3721d7ab8532SJason King out:
37227c478bd9Sstevel@tonic-gate 	delete_search_cookie(cookie);
3723d7ab8532SJason King 	return (rc);
3724d7ab8532SJason King }
3725d7ab8532SJason King 
3726d7ab8532SJason King /*
3727d7ab8532SJason King  * find_domainname performs one or more LDAP searches to
3728d7ab8532SJason King  * find the value of the nisdomain attribute associated with
3729d7ab8532SJason King  * the input DN (with no retry).
3730d7ab8532SJason King  */
3731d7ab8532SJason King 
3732d7ab8532SJason King static int
find_domainname(const char * dn,char ** domainname,const ns_cred_t * cred,ns_ldap_error_t ** errorp,ns_conn_user_t * conn_user)3733d7ab8532SJason King find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
3734d7ab8532SJason King     ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
3735d7ab8532SJason King {
3736d7ab8532SJason King 	lookup_data_t		ldata;
3737d7ab8532SJason King 	ns_ldap_result_t	*result;
3738d7ab8532SJason King 	char			**value;
3739d7ab8532SJason King 	int			rc;
3740d7ab8532SJason King 
3741d7ab8532SJason King 	*domainname = NULL;
3742d7ab8532SJason King 	*errorp = NULL;
3743d7ab8532SJason King 
3744d7ab8532SJason King 	ldata.lkd_dn = dn;
3745d7ab8532SJason King 	ldata.lkd_service = NULL;
3746d7ab8532SJason King 	ldata.lkd_filter = _NIS_FILTER;
3747d7ab8532SJason King 	ldata.lkd_cred = cred;
3748d7ab8532SJason King 	ldata.lkd_user = conn_user;
3749d7ab8532SJason King 
3750d7ab8532SJason King 	rc = lookup_dn(&ldata, nis_domain_attrs, &result, errorp);
3751d7ab8532SJason King 	if (rc != NS_LDAP_SUCCESS)
3752d7ab8532SJason King 		return (rc);
3753d7ab8532SJason King 
3754d7ab8532SJason King 	value = __ns_ldap_getAttr(result->entry, _NIS_DOMAIN);
3755d7ab8532SJason King 
3756d7ab8532SJason King 	if (value != NULL && value[0] != NULL) {
3757d7ab8532SJason King 		*domainname = strdup(value[0]);
3758d7ab8532SJason King 		if (*domainname == NULL)
3759d7ab8532SJason King 			rc = NS_LDAP_MEMORY;
3760d7ab8532SJason King 	} else {
3761d7ab8532SJason King 		rc = NS_LDAP_NOTFOUND;
3762d7ab8532SJason King 	}
3763d7ab8532SJason King 
3764d7ab8532SJason King 	(void) __ns_ldap_freeResult(&result);
37657c478bd9Sstevel@tonic-gate 	return (rc);
37667c478bd9Sstevel@tonic-gate }
37677c478bd9Sstevel@tonic-gate 
3768e1dd0a2fSth /*
3769e1dd0a2fSth  * __s_api_find_domainname performs one or more LDAP searches to
3770e1dd0a2fSth  * find the value of the nisdomain attribute associated with
3771e1dd0a2fSth  * the input DN (with retry).
3772e1dd0a2fSth  */
3773e1dd0a2fSth 
3774e1dd0a2fSth static int
__s_api_find_domainname(const char * dn,char ** domainname,const ns_cred_t * cred,ns_ldap_error_t ** errorp)3775e1dd0a2fSth __s_api_find_domainname(const char *dn, char **domainname,
3776e1dd0a2fSth     const ns_cred_t *cred, ns_ldap_error_t **errorp)
3777e1dd0a2fSth {
3778e1dd0a2fSth 	ns_conn_user_t	*cu = NULL;
3779e1dd0a2fSth 	int		try_cnt = 0;
3780e1dd0a2fSth 	int		rc = NS_LDAP_SUCCESS;
3781e1dd0a2fSth 
3782e1dd0a2fSth 	for (;;) {
3783e1dd0a2fSth 		if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
3784e1dd0a2fSth 		    &try_cnt, &rc, errorp) == 0)
3785e1dd0a2fSth 			break;
3786e1dd0a2fSth 		rc = find_domainname(dn, domainname, cred, errorp, cu);
3787e1dd0a2fSth 	}
3788e1dd0a2fSth 
3789e1dd0a2fSth 	return (rc);
3790e1dd0a2fSth }
3791e1dd0a2fSth 
3792e1dd0a2fSth static int
firstEntry(const char * service,const char * filter,const char * sortattr,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,void ** vcookie,ns_ldap_result_t ** result,ns_ldap_error_t ** errorp,const void * userdata,ns_conn_user_t * conn_user)3793e1dd0a2fSth firstEntry(
3794e1dd0a2fSth     const char *service,
3795e1dd0a2fSth     const char *filter,
37969f2fd570SJulian Pullen     const char *sortattr,
3797e1dd0a2fSth     int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3798e1dd0a2fSth     char **realfilter, const void *userdata),
3799e1dd0a2fSth     const char * const *attribute,
3800e1dd0a2fSth     const ns_cred_t *auth,
3801e1dd0a2fSth     const int flags,
3802e1dd0a2fSth     void **vcookie,
3803e1dd0a2fSth     ns_ldap_result_t **result,
3804e1dd0a2fSth     ns_ldap_error_t ** errorp,
3805e1dd0a2fSth     const void *userdata,
3806e1dd0a2fSth     ns_conn_user_t *conn_user)
38077c478bd9Sstevel@tonic-gate {
38087c478bd9Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie = NULL;
38097c478bd9Sstevel@tonic-gate 	ns_ldap_error_t		*error = NULL;
38107c478bd9Sstevel@tonic-gate 	ns_state_t		state;
38117c478bd9Sstevel@tonic-gate 	ns_ldap_search_desc_t	**sdlist;
38127c478bd9Sstevel@tonic-gate 	ns_ldap_search_desc_t	*dptr;
38137c478bd9Sstevel@tonic-gate 	char			**dns = NULL;
38147c478bd9Sstevel@tonic-gate 	int			scope;
38157c478bd9Sstevel@tonic-gate 	int			rc;
38167c478bd9Sstevel@tonic-gate 
38177c478bd9Sstevel@tonic-gate 	*errorp = NULL;
38187c478bd9Sstevel@tonic-gate 	*result = NULL;
38197c478bd9Sstevel@tonic-gate 
3820b57459abSJulian Pullen 	/*
3821b57459abSJulian Pullen 	 * Sanity check - NS_LDAP_READ_SHADOW is for our
3822b57459abSJulian Pullen 	 * own internal use.
3823b57459abSJulian Pullen 	 */
3824b57459abSJulian Pullen 	if (flags & NS_LDAP_READ_SHADOW)
3825b57459abSJulian Pullen 		return (NS_LDAP_INVALID_PARAM);
3826b57459abSJulian Pullen 
38277c478bd9Sstevel@tonic-gate 	/* get the service descriptor - or create a default one */
38287c478bd9Sstevel@tonic-gate 	rc = __s_api_get_SSD_from_SSDtoUse_service(service,
3829e84b06c3SMichen Chang 	    &sdlist, &error);
38307c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
38317c478bd9Sstevel@tonic-gate 		*errorp = error;
38327c478bd9Sstevel@tonic-gate 		return (rc);
38337c478bd9Sstevel@tonic-gate 	}
38347c478bd9Sstevel@tonic-gate 	if (sdlist == NULL) {
38357c478bd9Sstevel@tonic-gate 		/* Create default service Desc */
38367c478bd9Sstevel@tonic-gate 		sdlist = (ns_ldap_search_desc_t **)calloc(2,
3837699bceb8Smj 		    sizeof (ns_ldap_search_desc_t *));
38387c478bd9Sstevel@tonic-gate 		if (sdlist == NULL) {
38397c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
38407c478bd9Sstevel@tonic-gate 		}
38417c478bd9Sstevel@tonic-gate 		dptr = (ns_ldap_search_desc_t *)
3842699bceb8Smj 		    calloc(1, sizeof (ns_ldap_search_desc_t));
38437c478bd9Sstevel@tonic-gate 		if (dptr == NULL) {
38447c478bd9Sstevel@tonic-gate 			free(sdlist);
38457c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
38467c478bd9Sstevel@tonic-gate 		}
38477c478bd9Sstevel@tonic-gate 		sdlist[0] = dptr;
38487c478bd9Sstevel@tonic-gate 
38497c478bd9Sstevel@tonic-gate 		/* default base */
38507c478bd9Sstevel@tonic-gate 		rc = __s_api_getDNs(&dns, service, &error);
38517c478bd9Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
38527c478bd9Sstevel@tonic-gate 			if (dns) {
38537c478bd9Sstevel@tonic-gate 				__s_api_free2dArray(dns);
38547c478bd9Sstevel@tonic-gate 				dns = NULL;
38557c478bd9Sstevel@tonic-gate 			}
38567c478bd9Sstevel@tonic-gate 			if (sdlist) {
38577c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeSearchDescriptors(
3858699bceb8Smj 				    &sdlist);
38597c478bd9Sstevel@tonic-gate 
38607c478bd9Sstevel@tonic-gate 				sdlist = NULL;
38617c478bd9Sstevel@tonic-gate 			}
38627c478bd9Sstevel@tonic-gate 			*errorp = error;
38637c478bd9Sstevel@tonic-gate 			return (rc);
38647c478bd9Sstevel@tonic-gate 		}
38657c478bd9Sstevel@tonic-gate 		dptr->basedn = strdup(dns[0]);
38667c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(dns);
38677c478bd9Sstevel@tonic-gate 		dns = NULL;
38687c478bd9Sstevel@tonic-gate 
38697c478bd9Sstevel@tonic-gate 		/* default scope */
38707c478bd9Sstevel@tonic-gate 		scope = 0;
38717c478bd9Sstevel@tonic-gate 		cookie = init_search_state_machine();
38727c478bd9Sstevel@tonic-gate 		if (cookie == NULL) {
38737c478bd9Sstevel@tonic-gate 			if (sdlist) {
38747c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeSearchDescriptors(&sdlist);
38757c478bd9Sstevel@tonic-gate 				sdlist = NULL;
38767c478bd9Sstevel@tonic-gate 			}
38777c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
38787c478bd9Sstevel@tonic-gate 		}
38797c478bd9Sstevel@tonic-gate 		rc = __s_api_getSearchScope(&scope, &cookie->errorp);
38807c478bd9Sstevel@tonic-gate 		dptr->scope = scope;
38817c478bd9Sstevel@tonic-gate 	}
38827c478bd9Sstevel@tonic-gate 
38837c478bd9Sstevel@tonic-gate 	/* Initialize State machine cookie */
38847c478bd9Sstevel@tonic-gate 	if (cookie == NULL)
38857c478bd9Sstevel@tonic-gate 		cookie = init_search_state_machine();
38867c478bd9Sstevel@tonic-gate 	if (cookie == NULL) {
38877c478bd9Sstevel@tonic-gate 		if (sdlist) {
38887c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeSearchDescriptors(&sdlist);
38897c478bd9Sstevel@tonic-gate 			sdlist = NULL;
38907c478bd9Sstevel@tonic-gate 		}
38917c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
38927c478bd9Sstevel@tonic-gate 	}
38937c478bd9Sstevel@tonic-gate 
3894e1dd0a2fSth 	/* identify self as a getent user */
3895e1dd0a2fSth 	cookie->conn_user = conn_user;
3896e1dd0a2fSth 
38977c478bd9Sstevel@tonic-gate 	cookie->sdlist = sdlist;
38987c478bd9Sstevel@tonic-gate 
38997c478bd9Sstevel@tonic-gate 	/* see if need to follow referrals */
39007c478bd9Sstevel@tonic-gate 	rc = __s_api_toFollowReferrals(flags,
3901699bceb8Smj 	    &cookie->followRef, errorp);
39027c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
39037c478bd9Sstevel@tonic-gate 		delete_search_cookie(cookie);
39047c478bd9Sstevel@tonic-gate 		return (rc);
39057c478bd9Sstevel@tonic-gate 	}
39067c478bd9Sstevel@tonic-gate 
39077c478bd9Sstevel@tonic-gate 	/*
39087c478bd9Sstevel@tonic-gate 	 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
39097c478bd9Sstevel@tonic-gate 	 */
39107c478bd9Sstevel@tonic-gate 	if (flags & NS_LDAP_NO_PAGE_CTRL)
39117c478bd9Sstevel@tonic-gate 		cookie->use_paging = FALSE;
39127c478bd9Sstevel@tonic-gate 	else
39137c478bd9Sstevel@tonic-gate 		cookie->use_paging = TRUE;
39147c478bd9Sstevel@tonic-gate 
39157c478bd9Sstevel@tonic-gate 	/* Set up other arguments */
39167c478bd9Sstevel@tonic-gate 	cookie->userdata = userdata;
39177c478bd9Sstevel@tonic-gate 	if (init_filter_cb != NULL) {
39187c478bd9Sstevel@tonic-gate 		cookie->init_filter_cb = init_filter_cb;
39197c478bd9Sstevel@tonic-gate 		cookie->use_filtercb = 1;
39207c478bd9Sstevel@tonic-gate 	}
39217c478bd9Sstevel@tonic-gate 	cookie->use_usercb = 0;
3922b57459abSJulian Pullen 	/* check_shadow() may add extra value to cookie->i_flags */
3923b57459abSJulian Pullen 	cookie->i_flags = flags;
39247c478bd9Sstevel@tonic-gate 	if (service) {
39257c478bd9Sstevel@tonic-gate 		cookie->service = strdup(service);
39267c478bd9Sstevel@tonic-gate 		if (cookie->service == NULL) {
39277c478bd9Sstevel@tonic-gate 			delete_search_cookie(cookie);
39287c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
39297c478bd9Sstevel@tonic-gate 		}
3930b57459abSJulian Pullen 
3931b57459abSJulian Pullen 		/*
3932b57459abSJulian Pullen 		 * If given, use the credential given by the caller, and
3933b57459abSJulian Pullen 		 * skip the credential check required for shadow update.
3934b57459abSJulian Pullen 		 */
3935b57459abSJulian Pullen 		if (auth == NULL) {
3936b57459abSJulian Pullen 			rc = check_shadow(cookie, service);
3937b57459abSJulian Pullen 			if (rc != NS_LDAP_SUCCESS) {
3938b57459abSJulian Pullen 				*errorp = cookie->errorp;
3939b57459abSJulian Pullen 				cookie->errorp = NULL;
3940b57459abSJulian Pullen 				delete_search_cookie(cookie);
3941b57459abSJulian Pullen 				cookie = NULL;
3942b57459abSJulian Pullen 				return (rc);
3943b57459abSJulian Pullen 			}
3944b57459abSJulian Pullen 		}
39457c478bd9Sstevel@tonic-gate 	}
39467c478bd9Sstevel@tonic-gate 
39477c478bd9Sstevel@tonic-gate 	cookie->i_filter = strdup(filter);
39487c478bd9Sstevel@tonic-gate 	cookie->i_attr = attribute;
39499f2fd570SJulian Pullen 	cookie->i_sortattr = sortattr;
39507c478bd9Sstevel@tonic-gate 	cookie->i_auth = auth;
39517c478bd9Sstevel@tonic-gate 
39527c478bd9Sstevel@tonic-gate 	state = INIT;
39537c478bd9Sstevel@tonic-gate 	for (;;) {
39547c478bd9Sstevel@tonic-gate 		state = search_state_machine(cookie, state, ONE_STEP);
39557c478bd9Sstevel@tonic-gate 		switch (state) {
39567c478bd9Sstevel@tonic-gate 		case PROCESS_RESULT:
39577c478bd9Sstevel@tonic-gate 			*result = cookie->result;
39587c478bd9Sstevel@tonic-gate 			cookie->result = NULL;
39597c478bd9Sstevel@tonic-gate 			*vcookie = (void *)cookie;
39607c478bd9Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
39617c478bd9Sstevel@tonic-gate 		case LDAP_ERROR:
39623d047983Smichen 			state = search_state_machine(cookie, state, ONE_STEP);
39633d047983Smichen 			state = search_state_machine(cookie, CLEAR_RESULTS,
39643d047983Smichen 			    ONE_STEP);
39653d047983Smichen 			/* FALLTHROUGH */
39663d047983Smichen 		case ERROR:
39677c478bd9Sstevel@tonic-gate 			rc = cookie->err_rc;
3968e1dd0a2fSth 			if (conn_user != NULL && conn_user->ns_error != NULL) {
3969e1dd0a2fSth 				*errorp = conn_user->ns_error;
3970e1dd0a2fSth 				conn_user->ns_error = NULL;
3971e1dd0a2fSth 			} else {
3972e1dd0a2fSth 				*errorp = cookie->errorp;
3973e1dd0a2fSth 				cookie->errorp = NULL;
3974e1dd0a2fSth 			}
39757c478bd9Sstevel@tonic-gate 			delete_search_cookie(cookie);
39767c478bd9Sstevel@tonic-gate 			return (rc);
39777c478bd9Sstevel@tonic-gate 		case EXIT:
39787c478bd9Sstevel@tonic-gate 			rc = cookie->err_rc;
39797c478bd9Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
39807c478bd9Sstevel@tonic-gate 				*errorp = cookie->errorp;
39817c478bd9Sstevel@tonic-gate 				cookie->errorp = NULL;
39827c478bd9Sstevel@tonic-gate 			} else {
39837c478bd9Sstevel@tonic-gate 				rc = NS_LDAP_NOTFOUND;
39847c478bd9Sstevel@tonic-gate 			}
39857c478bd9Sstevel@tonic-gate 
39867c478bd9Sstevel@tonic-gate 			delete_search_cookie(cookie);
39877c478bd9Sstevel@tonic-gate 			return (rc);
39887c478bd9Sstevel@tonic-gate 
39897c478bd9Sstevel@tonic-gate 		default:
39907c478bd9Sstevel@tonic-gate 			break;
39917c478bd9Sstevel@tonic-gate 		}
39927c478bd9Sstevel@tonic-gate 	}
39937c478bd9Sstevel@tonic-gate }
39947c478bd9Sstevel@tonic-gate 
3995e1dd0a2fSth int
__ns_ldap_firstEntry(const char * service,const char * filter,const char * vlv_sort,int (* init_filter_cb)(const ns_ldap_search_desc_t * desc,char ** realfilter,const void * userdata),const char * const * attribute,const ns_cred_t * auth,const int flags,void ** vcookie,ns_ldap_result_t ** result,ns_ldap_error_t ** errorp,const void * userdata)3996e1dd0a2fSth __ns_ldap_firstEntry(
3997e1dd0a2fSth     const char *service,
3998e1dd0a2fSth     const char *filter,
39999f2fd570SJulian Pullen     const char *vlv_sort,
4000e1dd0a2fSth     int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
4001e1dd0a2fSth     char **realfilter, const void *userdata),
4002e1dd0a2fSth     const char * const *attribute,
4003e1dd0a2fSth     const ns_cred_t *auth,
4004e1dd0a2fSth     const int flags,
4005e1dd0a2fSth     void **vcookie,
4006e1dd0a2fSth     ns_ldap_result_t **result,
4007e1dd0a2fSth     ns_ldap_error_t ** errorp,
4008e1dd0a2fSth     const void *userdata)
4009e1dd0a2fSth {
4010e1dd0a2fSth 	ns_conn_user_t	*cu = NULL;
4011e1dd0a2fSth 	int		try_cnt = 0;
4012e1dd0a2fSth 	int		rc = NS_LDAP_SUCCESS;
4013e1dd0a2fSth 
4014e1dd0a2fSth 	for (;;) {
4015e1dd0a2fSth 		if (__s_api_setup_retry_search(&cu, NS_CONN_USER_GETENT,
4016e1dd0a2fSth 		    &try_cnt, &rc, errorp) == 0)
4017e1dd0a2fSth 			break;
40189f2fd570SJulian Pullen 		rc = firstEntry(service, filter, vlv_sort, init_filter_cb,
40199f2fd570SJulian Pullen 		    attribute, auth, flags, vcookie, result, errorp, userdata,
40209f2fd570SJulian Pullen 		    cu);
4021e1dd0a2fSth 	}
4022e1dd0a2fSth 	return (rc);
4023e1dd0a2fSth }
4024e1dd0a2fSth 
40257c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
40267c478bd9Sstevel@tonic-gate int
__ns_ldap_nextEntry(void * vcookie,ns_ldap_result_t ** result,ns_ldap_error_t ** errorp)4027e1dd0a2fSth __ns_ldap_nextEntry(void *vcookie, ns_ldap_result_t **result,
4028e1dd0a2fSth     ns_ldap_error_t ** errorp)
40297c478bd9Sstevel@tonic-gate {
40307c478bd9Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie;
40317c478bd9Sstevel@tonic-gate 	ns_state_t		state;
40327c478bd9Sstevel@tonic-gate 	int			rc;
40337c478bd9Sstevel@tonic-gate 
40347c478bd9Sstevel@tonic-gate 	cookie = (ns_ldap_cookie_t *)vcookie;
40357c478bd9Sstevel@tonic-gate 	cookie->result = NULL;
40367c478bd9Sstevel@tonic-gate 	*result = NULL;
40377c478bd9Sstevel@tonic-gate 
4038e1dd0a2fSth 	if (cookie->conn_user != NULL) {
4039e1dd0a2fSth 		rc = __s_api_setup_getnext(cookie->conn_user,
4040e1dd0a2fSth 		    &cookie->err_rc, errorp);
4041e1dd0a2fSth 		if (rc != NS_LDAP_SUCCESS)
4042e1dd0a2fSth 			return (rc);
4043e1dd0a2fSth 	}
4044e1dd0a2fSth 
40457c478bd9Sstevel@tonic-gate 	state = END_PROCESS_RESULT;
40467c478bd9Sstevel@tonic-gate 	for (;;) {
40477c478bd9Sstevel@tonic-gate 		state = search_state_machine(cookie, state, ONE_STEP);
40487c478bd9Sstevel@tonic-gate 		switch (state) {
40497c478bd9Sstevel@tonic-gate 		case PROCESS_RESULT:
40507c478bd9Sstevel@tonic-gate 			*result = cookie->result;
40517c478bd9Sstevel@tonic-gate 			cookie->result = NULL;
40527c478bd9Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
40537c478bd9Sstevel@tonic-gate 		case LDAP_ERROR:
40543d047983Smichen 			state = search_state_machine(cookie, state, ONE_STEP);
40553d047983Smichen 			state = search_state_machine(cookie, CLEAR_RESULTS,
40563d047983Smichen 			    ONE_STEP);
40573d047983Smichen 			/* FALLTHROUGH */
40583d047983Smichen 		case ERROR:
40597c478bd9Sstevel@tonic-gate 			rc = cookie->err_rc;
40607c478bd9Sstevel@tonic-gate 			*errorp = cookie->errorp;
40617c478bd9Sstevel@tonic-gate 			cookie->errorp = NULL;
40627c478bd9Sstevel@tonic-gate 			return (rc);
40637c478bd9Sstevel@tonic-gate 		case EXIT:
40647c478bd9Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
40657c478bd9Sstevel@tonic-gate 		}
40667c478bd9Sstevel@tonic-gate 	}
40677c478bd9Sstevel@tonic-gate }
40687c478bd9Sstevel@tonic-gate 
40697c478bd9Sstevel@tonic-gate int
__ns_ldap_endEntry(void ** vcookie,ns_ldap_error_t ** errorp)40707c478bd9Sstevel@tonic-gate __ns_ldap_endEntry(
40717c478bd9Sstevel@tonic-gate 	void **vcookie,
40727c478bd9Sstevel@tonic-gate 	ns_ldap_error_t ** errorp)
40737c478bd9Sstevel@tonic-gate {
40747c478bd9Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie;
40757c478bd9Sstevel@tonic-gate 	int			rc;
40767c478bd9Sstevel@tonic-gate 
40777c478bd9Sstevel@tonic-gate 	if (*vcookie == NULL)
40787c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
40797c478bd9Sstevel@tonic-gate 
40807c478bd9Sstevel@tonic-gate 	cookie = (ns_ldap_cookie_t *)(*vcookie);
40817c478bd9Sstevel@tonic-gate 	cookie->result = NULL;
40827c478bd9Sstevel@tonic-gate 
40837c478bd9Sstevel@tonic-gate 	/* Complete search */
4084699bceb8Smj 	rc = search_state_machine(cookie, CLEAR_RESULTS, 0);
40857c478bd9Sstevel@tonic-gate 
40867c478bd9Sstevel@tonic-gate 	/* Copy results back to user */
40877c478bd9Sstevel@tonic-gate 	rc = cookie->err_rc;
40887c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS)
40897c478bd9Sstevel@tonic-gate 		*errorp = cookie->errorp;
40907c478bd9Sstevel@tonic-gate 
40917c478bd9Sstevel@tonic-gate 	cookie->errorp = NULL;
4092e1dd0a2fSth 	if (cookie->conn_user != NULL) {
4093e1dd0a2fSth 		if (cookie->conn_user->conn_mt != NULL)
4094e1dd0a2fSth 			__s_api_conn_mt_return(cookie->conn_user);
4095e1dd0a2fSth 		__s_api_conn_user_free(cookie->conn_user);
4096e1dd0a2fSth 	}
40977c478bd9Sstevel@tonic-gate 	delete_search_cookie(cookie);
40987c478bd9Sstevel@tonic-gate 	cookie = NULL;
40997c478bd9Sstevel@tonic-gate 	*vcookie = NULL;
41007c478bd9Sstevel@tonic-gate 
41017c478bd9Sstevel@tonic-gate 	return (rc);
41027c478bd9Sstevel@tonic-gate }
41037c478bd9Sstevel@tonic-gate 
41047c478bd9Sstevel@tonic-gate 
41057c478bd9Sstevel@tonic-gate int
__ns_ldap_freeResult(ns_ldap_result_t ** result)41067c478bd9Sstevel@tonic-gate __ns_ldap_freeResult(ns_ldap_result_t **result)
41077c478bd9Sstevel@tonic-gate {
41087c478bd9Sstevel@tonic-gate 
41097c478bd9Sstevel@tonic-gate 	ns_ldap_entry_t	*curEntry = NULL;
41107c478bd9Sstevel@tonic-gate 	ns_ldap_entry_t	*delEntry = NULL;
41117c478bd9Sstevel@tonic-gate 	int		i;
41127c478bd9Sstevel@tonic-gate 	ns_ldap_result_t	*res = *result;
41137c478bd9Sstevel@tonic-gate 
41147c478bd9Sstevel@tonic-gate #ifdef DEBUG
41157c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "__ns_ldap_freeResult START\n");
41167c478bd9Sstevel@tonic-gate #endif
41177c478bd9Sstevel@tonic-gate 	if (res == NULL)
41187c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
41197c478bd9Sstevel@tonic-gate 
41207c478bd9Sstevel@tonic-gate 	if (res->entry != NULL)
41217c478bd9Sstevel@tonic-gate 		curEntry = res->entry;
41227c478bd9Sstevel@tonic-gate 
41237c478bd9Sstevel@tonic-gate 	for (i = 0; i < res->entries_count; i++) {
41247c478bd9Sstevel@tonic-gate 		if (curEntry != NULL) {
41257c478bd9Sstevel@tonic-gate 			delEntry = curEntry;
41267c478bd9Sstevel@tonic-gate 			curEntry = curEntry->next;
41277c478bd9Sstevel@tonic-gate 			__ns_ldap_freeEntry(delEntry);
41287c478bd9Sstevel@tonic-gate 		}
41297c478bd9Sstevel@tonic-gate 	}
41307c478bd9Sstevel@tonic-gate 
41317c478bd9Sstevel@tonic-gate 	free(res);
41327c478bd9Sstevel@tonic-gate 	*result = NULL;
41337c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
41347c478bd9Sstevel@tonic-gate }
41357c478bd9Sstevel@tonic-gate 
41367c478bd9Sstevel@tonic-gate int
__ns_ldap_auth(const ns_cred_t * auth,const int flags,ns_ldap_error_t ** errorp,LDAPControl ** serverctrls __unused,LDAPControl ** clientctrls __unused)41378f0bb794SToomas Soome __ns_ldap_auth(const ns_cred_t *auth, const int flags, ns_ldap_error_t **errorp,
41388f0bb794SToomas Soome     LDAPControl **serverctrls __unused, LDAPControl **clientctrls __unused)
41397c478bd9Sstevel@tonic-gate {
41407c478bd9Sstevel@tonic-gate 
41417c478bd9Sstevel@tonic-gate 	ConnectionID	connectionId = -1;
41427c478bd9Sstevel@tonic-gate 	Connection	*conp;
41437c478bd9Sstevel@tonic-gate 	int		rc = 0;
41447c478bd9Sstevel@tonic-gate 	int		do_not_fail_if_new_pwd_reqd = 0;
414547789246Svv 	int		nopasswd_acct_mgmt = 0;
4146e1dd0a2fSth 	ns_conn_user_t	*conn_user;
41477c478bd9Sstevel@tonic-gate 
41487c478bd9Sstevel@tonic-gate 
41497c478bd9Sstevel@tonic-gate #ifdef DEBUG
41507c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "__ns_ldap_auth START\n");
41517c478bd9Sstevel@tonic-gate #endif
41527c478bd9Sstevel@tonic-gate 
41537c478bd9Sstevel@tonic-gate 	*errorp = NULL;
41548f0bb794SToomas Soome 	if (auth == NULL)
41557c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
41567c478bd9Sstevel@tonic-gate 
4157e1dd0a2fSth 	conn_user = __s_api_conn_user_init(NS_CONN_USER_AUTH,
4158e1dd0a2fSth 	    NULL, B_FALSE);
4159e1dd0a2fSth 
4160cb5caa98Sdjl 	rc = __s_api_getConnection(NULL, flags | NS_LDAP_NEW_CONN,
4161699bceb8Smj 	    auth, &connectionId, &conp, errorp,
4162e1dd0a2fSth 	    do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
4163e1dd0a2fSth 	    conn_user);
4164e1dd0a2fSth 
4165e1dd0a2fSth 	if (conn_user != NULL)
4166e1dd0a2fSth 		__s_api_conn_user_free(conn_user);
4167e1dd0a2fSth 
41687c478bd9Sstevel@tonic-gate 	if (rc == NS_LDAP_OP_FAILED && *errorp)
41697c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeError(errorp);
41707c478bd9Sstevel@tonic-gate 
41717c478bd9Sstevel@tonic-gate 	if (connectionId > -1)
41727c478bd9Sstevel@tonic-gate 		DropConnection(connectionId, flags);
41737c478bd9Sstevel@tonic-gate 	return (rc);
41747c478bd9Sstevel@tonic-gate }
41757c478bd9Sstevel@tonic-gate 
41767c478bd9Sstevel@tonic-gate char **
__ns_ldap_getAttr(const ns_ldap_entry_t * entry,const char * attrname)41777c478bd9Sstevel@tonic-gate __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname)
41787c478bd9Sstevel@tonic-gate {
41797c478bd9Sstevel@tonic-gate 	int	i;
41807c478bd9Sstevel@tonic-gate 
41817c478bd9Sstevel@tonic-gate 	if (entry == NULL)
41827c478bd9Sstevel@tonic-gate 		return (NULL);
41837c478bd9Sstevel@tonic-gate 	for (i = 0; i < entry->attr_count; i++) {
418451b02b29SToomas Soome 		if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == 0)
41857c478bd9Sstevel@tonic-gate 			return (entry->attr_pair[i]->attrvalue);
41867c478bd9Sstevel@tonic-gate 	}
41877c478bd9Sstevel@tonic-gate 	return (NULL);
41887c478bd9Sstevel@tonic-gate }
41897c478bd9Sstevel@tonic-gate 
4190cb5caa98Sdjl ns_ldap_attr_t *
__ns_ldap_getAttrStruct(const ns_ldap_entry_t * entry,const char * attrname)4191cb5caa98Sdjl __ns_ldap_getAttrStruct(const ns_ldap_entry_t *entry, const char *attrname)
4192cb5caa98Sdjl {
4193cb5caa98Sdjl 	int	i;
4194cb5caa98Sdjl 
4195cb5caa98Sdjl 	if (entry == NULL)
4196cb5caa98Sdjl 		return (NULL);
4197cb5caa98Sdjl 	for (i = 0; i < entry->attr_count; i++) {
419851b02b29SToomas Soome 		if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == 0)
4199cb5caa98Sdjl 			return (entry->attr_pair[i]);
4200cb5caa98Sdjl 	}
4201cb5caa98Sdjl 	return (NULL);
4202cb5caa98Sdjl }
4203cb5caa98Sdjl 
42047c478bd9Sstevel@tonic-gate 
42057c478bd9Sstevel@tonic-gate int
__ns_ldap_uid2dn(const char * uid,char ** userDN,const ns_cred_t * cred,ns_ldap_error_t ** errorp)42068f0bb794SToomas Soome __ns_ldap_uid2dn(const char *uid, char **userDN, const ns_cred_t *cred,
42078f0bb794SToomas Soome     ns_ldap_error_t **errorp)
42087c478bd9Sstevel@tonic-gate {
42097c478bd9Sstevel@tonic-gate 	ns_ldap_result_t	*result = NULL;
42107c478bd9Sstevel@tonic-gate 	char		*filter, *userdata;
42117c478bd9Sstevel@tonic-gate 	char		errstr[MAXERROR];
42127c478bd9Sstevel@tonic-gate 	char		**value;
42137c478bd9Sstevel@tonic-gate 	int		rc = 0;
42148f0bb794SToomas Soome 	int		i;
42157c478bd9Sstevel@tonic-gate 	size_t		len;
42167c478bd9Sstevel@tonic-gate 
42177c478bd9Sstevel@tonic-gate 	*errorp = NULL;
42187c478bd9Sstevel@tonic-gate 	*userDN = NULL;
42197c478bd9Sstevel@tonic-gate 	if ((uid == NULL) || (uid[0] == '\0'))
42207c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
42217c478bd9Sstevel@tonic-gate 
42228f0bb794SToomas Soome 	for (i = 0; uid[i] != '\0'; i++) {
42237c478bd9Sstevel@tonic-gate 		if (uid[i] == '=') {
42247c478bd9Sstevel@tonic-gate 			*userDN = strdup(uid);
42257c478bd9Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
42267c478bd9Sstevel@tonic-gate 		}
42277c478bd9Sstevel@tonic-gate 	}
42288f0bb794SToomas Soome 	for (i = 0; (uid[i] != '\0') && isdigit(uid[i]); i++)
42298f0bb794SToomas Soome 		;
42307c478bd9Sstevel@tonic-gate 	if (uid[i] == '\0') {
42317c478bd9Sstevel@tonic-gate 		len = strlen(UIDNUMFILTER) + strlen(uid) + 1;
42328f0bb794SToomas Soome 		filter = malloc(len);
42337c478bd9Sstevel@tonic-gate 		if (filter == NULL) {
42347c478bd9Sstevel@tonic-gate 			*userDN = NULL;
42357c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
42367c478bd9Sstevel@tonic-gate 		}
42377c478bd9Sstevel@tonic-gate 		(void) snprintf(filter, len, UIDNUMFILTER, uid);
42387c478bd9Sstevel@tonic-gate 
42397c478bd9Sstevel@tonic-gate 		len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1;
42408f0bb794SToomas Soome 		userdata = malloc(len);
42417c478bd9Sstevel@tonic-gate 		if (userdata == NULL) {
42427c478bd9Sstevel@tonic-gate 			*userDN = NULL;
42430ababfc6SToomas Soome 			free(filter);
42447c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
42457c478bd9Sstevel@tonic-gate 		}
42467c478bd9Sstevel@tonic-gate 		(void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid);
42477c478bd9Sstevel@tonic-gate 	} else {
42487c478bd9Sstevel@tonic-gate 		len = strlen(UIDFILTER) + strlen(uid) + 1;
42498f0bb794SToomas Soome 		filter = malloc(len);
42507c478bd9Sstevel@tonic-gate 		if (filter == NULL) {
42517c478bd9Sstevel@tonic-gate 			*userDN = NULL;
42527c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
42537c478bd9Sstevel@tonic-gate 		}
42547c478bd9Sstevel@tonic-gate 		(void) snprintf(filter, len, UIDFILTER, uid);
42557c478bd9Sstevel@tonic-gate 
42567c478bd9Sstevel@tonic-gate 		len = strlen(UIDFILTER_SSD) + strlen(uid) + 1;
42578f0bb794SToomas Soome 		userdata = malloc(len);
42587c478bd9Sstevel@tonic-gate 		if (userdata == NULL) {
42597c478bd9Sstevel@tonic-gate 			*userDN = NULL;
42600ababfc6SToomas Soome 			free(filter);
42617c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
42627c478bd9Sstevel@tonic-gate 		}
42637c478bd9Sstevel@tonic-gate 		(void) snprintf(userdata, len, UIDFILTER_SSD, uid);
42647c478bd9Sstevel@tonic-gate 	}
42657c478bd9Sstevel@tonic-gate 
4266f5c3c7a7Ssdussud 	/*
4267f5c3c7a7Ssdussud 	 * we want to retrieve the DN as it appears in LDAP
4268f5c3c7a7Ssdussud 	 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4269f5c3c7a7Ssdussud 	 */
42707c478bd9Sstevel@tonic-gate 	rc = __ns_ldap_list("passwd", filter,
4271699bceb8Smj 	    __s_api_merge_SSD_filter,
4272699bceb8Smj 	    NULL, cred, NS_LDAP_NOT_CVT_DN,
4273699bceb8Smj 	    &result, errorp, NULL,
4274699bceb8Smj 	    userdata);
42757c478bd9Sstevel@tonic-gate 	free(filter);
42767c478bd9Sstevel@tonic-gate 	filter = NULL;
42777c478bd9Sstevel@tonic-gate 	free(userdata);
42787c478bd9Sstevel@tonic-gate 	userdata = NULL;
42797c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
42807c478bd9Sstevel@tonic-gate 		if (result) {
42817c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeResult(&result);
42827c478bd9Sstevel@tonic-gate 			result = NULL;
42837c478bd9Sstevel@tonic-gate 		}
42847c478bd9Sstevel@tonic-gate 		return (rc);
42857c478bd9Sstevel@tonic-gate 	}
42867c478bd9Sstevel@tonic-gate 	if (result->entries_count > 1) {
42877c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeResult(&result);
42887c478bd9Sstevel@tonic-gate 		result = NULL;
42897c478bd9Sstevel@tonic-gate 		*userDN = NULL;
42907c478bd9Sstevel@tonic-gate 		(void) sprintf(errstr,
4291699bceb8Smj 		    gettext("Too many entries are returned for %s"), uid);
42927c478bd9Sstevel@tonic-gate 		MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
429351b02b29SToomas Soome 		    NS_LDAP_MEMORY);
42947c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INTERNAL);
42957c478bd9Sstevel@tonic-gate 	}
42967c478bd9Sstevel@tonic-gate 
42977c478bd9Sstevel@tonic-gate 	value = __ns_ldap_getAttr(result->entry, "dn");
42987c478bd9Sstevel@tonic-gate 	*userDN = strdup(value[0]);
42997c478bd9Sstevel@tonic-gate 	(void) __ns_ldap_freeResult(&result);
43007c478bd9Sstevel@tonic-gate 	result = NULL;
43017c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
43027c478bd9Sstevel@tonic-gate }
43037c478bd9Sstevel@tonic-gate 
4304695ef821SGordon Ross #define	_P_UID	"uid"
4305695ef821SGordon Ross static const char *dn2uid_attrs[] = {
4306695ef821SGordon Ross 	_P_CN,
4307695ef821SGordon Ross 	_P_UID,
4308695ef821SGordon Ross 	(char *)NULL
4309695ef821SGordon Ross };
4310695ef821SGordon Ross 
4311695ef821SGordon Ross int
__ns_ldap_dn2uid(const char * dn,char ** userIDp,const ns_cred_t * cred,ns_ldap_error_t ** errorp)4312d7ab8532SJason King __ns_ldap_dn2uid(const char *dn, char **userIDp, const ns_cred_t *cred,
43138f0bb794SToomas Soome     ns_ldap_error_t **errorp)
4314695ef821SGordon Ross {
4315d7ab8532SJason King 	lookup_data_t		ldata;
4316d7ab8532SJason King 	ns_ldap_result_t	*result;
4317d7ab8532SJason King 	char			**value;
4318d7ab8532SJason King 	int			rc;
4319695ef821SGordon Ross 
4320695ef821SGordon Ross 	*errorp = NULL;
4321d7ab8532SJason King 	*userIDp = NULL;
4322695ef821SGordon Ross 	if ((dn == NULL) || (dn[0] == '\0'))
4323695ef821SGordon Ross 		return (NS_LDAP_INVALID_PARAM);
4324695ef821SGordon Ross 
4325d7ab8532SJason King 	/*
4326d7ab8532SJason King 	 * Many LDAP servers do not support using the dn in a search
4327d7ab8532SJason King 	 * filter. As a result, we unfortunately cannot  use __ns_ldap_list()
4328d7ab8532SJason King 	 * to lookup the DN. Instead we perform a search with the baseDN
4329d7ab8532SJason King 	 * being the DN we are looking for with a scope of 'base' to
4330d7ab8532SJason King 	 * return the entry, as this should be supported by all LDAP servers.
4331d7ab8532SJason King 	 */
4332d7ab8532SJason King 	ldata.lkd_dn = dn;
4333695ef821SGordon Ross 
4334695ef821SGordon Ross 	/*
4335d7ab8532SJason King 	 * Since we are looking up a user account by its DN, use the attribute
4336d7ab8532SJason King 	 * and objectclass mappings (if present) for the passwd service.
4337695ef821SGordon Ross 	 */
4338d7ab8532SJason King 	ldata.lkd_service = "passwd";
4339d7ab8532SJason King 	ldata.lkd_filter = UIDDNFILTER;
4340d7ab8532SJason King 	ldata.lkd_cred = cred;
4341d7ab8532SJason King 	ldata.lkd_user = NULL;
4342695ef821SGordon Ross 
4343d7ab8532SJason King 	rc = lookup_dn(&ldata, dn2uid_attrs, &result, errorp);
4344d7ab8532SJason King 	if (rc != NS_LDAP_SUCCESS)
4345d7ab8532SJason King 		return (rc);
4346695ef821SGordon Ross 
4347695ef821SGordon Ross 	value = __ns_ldap_getAttr(result->entry, _P_UID);
4348d7ab8532SJason King 	if (value != NULL && value[0] != NULL) {
4349d7ab8532SJason King 		*userIDp = strdup(value[0]);
4350d7ab8532SJason King 		if (*userIDp == NULL)
4351d7ab8532SJason King 			rc = NS_LDAP_MEMORY;
4352d7ab8532SJason King 	} else {
4353695ef821SGordon Ross 		rc = NS_LDAP_NOTFOUND;
4354695ef821SGordon Ross 	}
4355695ef821SGordon Ross 
4356695ef821SGordon Ross 	(void) __ns_ldap_freeResult(&result);
4357695ef821SGordon Ross 	return (rc);
4358695ef821SGordon Ross }
43597c478bd9Sstevel@tonic-gate 
43607c478bd9Sstevel@tonic-gate int
__ns_ldap_host2dn(const char * host,const char * domain,char ** hostDN,const ns_cred_t * cred,ns_ldap_error_t ** errorp)43618f0bb794SToomas Soome __ns_ldap_host2dn(const char *host, const char *domain, char **hostDN,
43628f0bb794SToomas Soome     const ns_cred_t *cred, ns_ldap_error_t **errorp)
43637c478bd9Sstevel@tonic-gate {
43647c478bd9Sstevel@tonic-gate 	ns_ldap_result_t	*result = NULL;
43657c478bd9Sstevel@tonic-gate 	char		*filter, *userdata;
43667c478bd9Sstevel@tonic-gate 	char		errstr[MAXERROR];
43677c478bd9Sstevel@tonic-gate 	char		**value;
43687c478bd9Sstevel@tonic-gate 	int		rc;
43697c478bd9Sstevel@tonic-gate 	size_t		len;
43707c478bd9Sstevel@tonic-gate 
43718f0bb794SToomas Soome 	/*
43728f0bb794SToomas Soome 	 * XXX
43738f0bb794SToomas Soome 	 * the domain parameter needs to be used in case domain is not local,
43748f0bb794SToomas Soome 	 * if this routine is to support multi domain setups, it needs lots
43758f0bb794SToomas Soome 	 * of work...
43768f0bb794SToomas Soome 	 */
43777c478bd9Sstevel@tonic-gate 	*errorp = NULL;
43787c478bd9Sstevel@tonic-gate 	*hostDN = NULL;
43797c478bd9Sstevel@tonic-gate 	if ((host == NULL) || (host[0] == '\0'))
43807c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
43817c478bd9Sstevel@tonic-gate 
43827c478bd9Sstevel@tonic-gate 	len = strlen(HOSTFILTER) + strlen(host) + 1;
43838f0bb794SToomas Soome 	filter = malloc(len);
43847c478bd9Sstevel@tonic-gate 	if (filter == NULL) {
43857c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
43867c478bd9Sstevel@tonic-gate 	}
43877c478bd9Sstevel@tonic-gate 	(void) snprintf(filter,	len, HOSTFILTER, host);
43887c478bd9Sstevel@tonic-gate 
43897c478bd9Sstevel@tonic-gate 	len = strlen(HOSTFILTER_SSD) + strlen(host) + 1;
43908f0bb794SToomas Soome 	userdata = malloc(len);
43917c478bd9Sstevel@tonic-gate 	if (userdata == NULL) {
43920ababfc6SToomas Soome 		free(filter);
43937c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
43947c478bd9Sstevel@tonic-gate 	}
43957c478bd9Sstevel@tonic-gate 	(void) snprintf(userdata, len, HOSTFILTER_SSD, host);
43967c478bd9Sstevel@tonic-gate 
4397f5c3c7a7Ssdussud 	/*
4398f5c3c7a7Ssdussud 	 * we want to retrieve the DN as it appears in LDAP
4399f5c3c7a7Ssdussud 	 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4400f5c3c7a7Ssdussud 	 */
44017c478bd9Sstevel@tonic-gate 	rc = __ns_ldap_list("hosts", filter,
4402699bceb8Smj 	    __s_api_merge_SSD_filter,
4403699bceb8Smj 	    NULL, cred, NS_LDAP_NOT_CVT_DN, &result,
4404699bceb8Smj 	    errorp, NULL,
4405699bceb8Smj 	    userdata);
44067c478bd9Sstevel@tonic-gate 	free(filter);
44077c478bd9Sstevel@tonic-gate 	filter = NULL;
44087c478bd9Sstevel@tonic-gate 	free(userdata);
44097c478bd9Sstevel@tonic-gate 	userdata = NULL;
44107c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
44117c478bd9Sstevel@tonic-gate 		if (result) {
44127c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeResult(&result);
44137c478bd9Sstevel@tonic-gate 			result = NULL;
44147c478bd9Sstevel@tonic-gate 		}
44157c478bd9Sstevel@tonic-gate 		return (rc);
44167c478bd9Sstevel@tonic-gate 	}
44177c478bd9Sstevel@tonic-gate 
44187c478bd9Sstevel@tonic-gate 	if (result->entries_count > 1) {
44197c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeResult(&result);
44207c478bd9Sstevel@tonic-gate 		result = NULL;
44217c478bd9Sstevel@tonic-gate 		*hostDN = NULL;
44227c478bd9Sstevel@tonic-gate 		(void) sprintf(errstr,
4423699bceb8Smj 		    gettext("Too many entries are returned for %s"), host);
44247c478bd9Sstevel@tonic-gate 		MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
442551b02b29SToomas Soome 		    NS_LDAP_MEMORY);
44267c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INTERNAL);
44277c478bd9Sstevel@tonic-gate 	}
44287c478bd9Sstevel@tonic-gate 
44297c478bd9Sstevel@tonic-gate 	value = __ns_ldap_getAttr(result->entry, "dn");
44307c478bd9Sstevel@tonic-gate 	*hostDN = strdup(value[0]);
44317c478bd9Sstevel@tonic-gate 	(void) __ns_ldap_freeResult(&result);
44327c478bd9Sstevel@tonic-gate 	result = NULL;
44337c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
44347c478bd9Sstevel@tonic-gate }
44357c478bd9Sstevel@tonic-gate 
44367c478bd9Sstevel@tonic-gate int
__ns_ldap_dn2domain(const char * dn,char ** domain,const ns_cred_t * cred,ns_ldap_error_t ** errorp)44378f0bb794SToomas Soome __ns_ldap_dn2domain(const char *dn, char **domain, const ns_cred_t *cred,
44388f0bb794SToomas Soome     ns_ldap_error_t **errorp)
44397c478bd9Sstevel@tonic-gate {
44407c478bd9Sstevel@tonic-gate 	int		rc, pnum, i, j, len = 0;
44417c478bd9Sstevel@tonic-gate 	char		*newdn, **rdns = NULL;
44427c478bd9Sstevel@tonic-gate 	char		**dns, *dn1;
44437c478bd9Sstevel@tonic-gate 
44447c478bd9Sstevel@tonic-gate 	*errorp = NULL;
44457c478bd9Sstevel@tonic-gate 
44467c478bd9Sstevel@tonic-gate 	if (domain == NULL)
44477c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
44487c478bd9Sstevel@tonic-gate 	else
44497c478bd9Sstevel@tonic-gate 		*domain = NULL;
44507c478bd9Sstevel@tonic-gate 
44517c478bd9Sstevel@tonic-gate 	if ((dn == NULL) || (dn[0] == '\0'))
44527c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
44537c478bd9Sstevel@tonic-gate 
44547c478bd9Sstevel@tonic-gate 	/*
44557c478bd9Sstevel@tonic-gate 	 * break dn into rdns
44567c478bd9Sstevel@tonic-gate 	 */
44577c478bd9Sstevel@tonic-gate 	dn1 = strdup(dn);
44587c478bd9Sstevel@tonic-gate 	if (dn1 == NULL)
44597c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
44607c478bd9Sstevel@tonic-gate 	rdns = ldap_explode_dn(dn1, 0);
44617c478bd9Sstevel@tonic-gate 	free(dn1);
44627c478bd9Sstevel@tonic-gate 	if (rdns == NULL || *rdns == NULL)
44637c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
44647c478bd9Sstevel@tonic-gate 
44657c478bd9Sstevel@tonic-gate 	for (i = 0; rdns[i]; i++)
44667c478bd9Sstevel@tonic-gate 		len += strlen(rdns[i]) + 1;
44677c478bd9Sstevel@tonic-gate 	pnum = i;
44687c478bd9Sstevel@tonic-gate 
44697c478bd9Sstevel@tonic-gate 	newdn = (char *)malloc(len + 1);
44707c478bd9Sstevel@tonic-gate 	dns = (char **)calloc(pnum, sizeof (char *));
44717c478bd9Sstevel@tonic-gate 	if (newdn == NULL || dns == NULL) {
44727c478bd9Sstevel@tonic-gate 		if (newdn)
44737c478bd9Sstevel@tonic-gate 			free(newdn);
44747c478bd9Sstevel@tonic-gate 		ldap_value_free(rdns);
44757c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
44767c478bd9Sstevel@tonic-gate 	}
44777c478bd9Sstevel@tonic-gate 
44787c478bd9Sstevel@tonic-gate 	/* construct a semi-normalized dn, newdn */
44797c478bd9Sstevel@tonic-gate 	*newdn = '\0';
44807c478bd9Sstevel@tonic-gate 	for (i = 0; rdns[i]; i++) {
44817c478bd9Sstevel@tonic-gate 		dns[i] = newdn + strlen(newdn);
44827c478bd9Sstevel@tonic-gate 		(void) strcat(newdn,
4483699bceb8Smj 		    __s_api_remove_rdn_space(rdns[i]));
44847c478bd9Sstevel@tonic-gate 		(void) strcat(newdn, ",");
44857c478bd9Sstevel@tonic-gate 	}
44867c478bd9Sstevel@tonic-gate 	/* remove the last ',' */
44877c478bd9Sstevel@tonic-gate 	newdn[strlen(newdn) - 1] = '\0';
44887c478bd9Sstevel@tonic-gate 	ldap_value_free(rdns);
44897c478bd9Sstevel@tonic-gate 
44907c478bd9Sstevel@tonic-gate 	/*
44917c478bd9Sstevel@tonic-gate 	 * loop and find the domain name associated with newdn,
44927c478bd9Sstevel@tonic-gate 	 * removing rdn one by one from left to right
44937c478bd9Sstevel@tonic-gate 	 */
44947c478bd9Sstevel@tonic-gate 	for (i = 0; i < pnum; i++) {
44957c478bd9Sstevel@tonic-gate 
44967c478bd9Sstevel@tonic-gate 		if (*errorp)
44977c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeError(errorp);
44987c478bd9Sstevel@tonic-gate 
44997c478bd9Sstevel@tonic-gate 		/*
45007c478bd9Sstevel@tonic-gate 		 *  try cache manager first
45017c478bd9Sstevel@tonic-gate 		 */
45027c478bd9Sstevel@tonic-gate 		rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN,
4503699bceb8Smj 		    dns[i], domain);
45047c478bd9Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
45057c478bd9Sstevel@tonic-gate 			/*
45067c478bd9Sstevel@tonic-gate 			 *  try ldap server second
45077c478bd9Sstevel@tonic-gate 			 */
45087c478bd9Sstevel@tonic-gate 			rc = __s_api_find_domainname(dns[i], domain,
4509699bceb8Smj 			    cred, errorp);
45107c478bd9Sstevel@tonic-gate 		} else {
45117c478bd9Sstevel@tonic-gate 			/*
45127c478bd9Sstevel@tonic-gate 			 * skip the last one,
45137c478bd9Sstevel@tonic-gate 			 * since it is already cached by ldap_cachemgr
45147c478bd9Sstevel@tonic-gate 			 */
45157c478bd9Sstevel@tonic-gate 			i--;
45167c478bd9Sstevel@tonic-gate 		}
45177c478bd9Sstevel@tonic-gate 		if (rc == NS_LDAP_SUCCESS) {
45188142c2b2Schinlong 			if (__s_api_nscd_proc()) {
45198142c2b2Schinlong 				/*
45208142c2b2Schinlong 				 * If it's nscd, ask cache manager to save the
45218142c2b2Schinlong 				 * dn to domain mapping(s)
45228142c2b2Schinlong 				 */
45238142c2b2Schinlong 				for (j = 0; j <= i; j++) {
45248142c2b2Schinlong 					(void) __s_api_set_cachemgr_data(
45258142c2b2Schinlong 					    NS_CACHE_DN2DOMAIN,
45268142c2b2Schinlong 					    dns[j],
45278142c2b2Schinlong 					    *domain);
45288142c2b2Schinlong 				}
45297c478bd9Sstevel@tonic-gate 			}
45307c478bd9Sstevel@tonic-gate 			break;
45317c478bd9Sstevel@tonic-gate 		}
45327c478bd9Sstevel@tonic-gate 	}
45337c478bd9Sstevel@tonic-gate 
45347c478bd9Sstevel@tonic-gate 	free(dns);
45357c478bd9Sstevel@tonic-gate 	free(newdn);
45367c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS)
45377c478bd9Sstevel@tonic-gate 		rc = NS_LDAP_NOTFOUND;
45387c478bd9Sstevel@tonic-gate 	return (rc);
45397c478bd9Sstevel@tonic-gate }
45407c478bd9Sstevel@tonic-gate 
45417c478bd9Sstevel@tonic-gate int
__ns_ldap_getServiceAuthMethods(const char * service,ns_auth_t *** auth,ns_ldap_error_t ** errorp)45428f0bb794SToomas Soome __ns_ldap_getServiceAuthMethods(const char *service, ns_auth_t ***auth,
45438f0bb794SToomas Soome     ns_ldap_error_t **errorp)
45447c478bd9Sstevel@tonic-gate {
45457c478bd9Sstevel@tonic-gate 	char		errstr[MAXERROR];
45468f0bb794SToomas Soome 	int		rc, i;
45478f0bb794SToomas Soome 	boolean_t	done = B_FALSE;
45487c478bd9Sstevel@tonic-gate 	int		slen;
45497c478bd9Sstevel@tonic-gate 	void		**param;
45507c478bd9Sstevel@tonic-gate 	char		**sam, *srv, *send;
45517c478bd9Sstevel@tonic-gate 	ns_auth_t	**authpp = NULL, *ap;
45527c478bd9Sstevel@tonic-gate 	int		cnt, max;
45537c478bd9Sstevel@tonic-gate 	ns_config_t	*cfg;
45547c478bd9Sstevel@tonic-gate 	ns_ldap_error_t	*error = NULL;
45557c478bd9Sstevel@tonic-gate 
45567c478bd9Sstevel@tonic-gate 	if (errorp == NULL)
45577c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
45587c478bd9Sstevel@tonic-gate 	*errorp = NULL;
45597c478bd9Sstevel@tonic-gate 
45607c478bd9Sstevel@tonic-gate 	if ((service == NULL) || (service[0] == '\0') ||
4561699bceb8Smj 	    (auth == NULL))
45627c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
45637c478bd9Sstevel@tonic-gate 
45647c478bd9Sstevel@tonic-gate 	*auth = NULL;
45657c478bd9Sstevel@tonic-gate 	rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, &param, &error);
45667c478bd9Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS || param == NULL) {
45677c478bd9Sstevel@tonic-gate 		*errorp = error;
45687c478bd9Sstevel@tonic-gate 		return (rc);
45697c478bd9Sstevel@tonic-gate 	}
45707c478bd9Sstevel@tonic-gate 	sam = (char **)param;
45717c478bd9Sstevel@tonic-gate 
45727c478bd9Sstevel@tonic-gate 	cfg = __s_api_get_default_config();
45737c478bd9Sstevel@tonic-gate 	cnt = 0;
45747c478bd9Sstevel@tonic-gate 
45757c478bd9Sstevel@tonic-gate 	slen = strlen(service);
45767c478bd9Sstevel@tonic-gate 
45777c478bd9Sstevel@tonic-gate 	for (; *sam; sam++) {
45787c478bd9Sstevel@tonic-gate 		srv = *sam;
45797c478bd9Sstevel@tonic-gate 		if (strncasecmp(service, srv, slen) != 0)
45807c478bd9Sstevel@tonic-gate 			continue;
45817c478bd9Sstevel@tonic-gate 		srv += slen;
45827c478bd9Sstevel@tonic-gate 		if (*srv != COLONTOK)
45837c478bd9Sstevel@tonic-gate 			continue;
45847c478bd9Sstevel@tonic-gate 		send = srv;
45857c478bd9Sstevel@tonic-gate 		srv++;
45868f0bb794SToomas Soome 		for (max = 1; (send = strchr(++send, SEMITOK)) != NULL; max++)
45878f0bb794SToomas Soome 			;
45887c478bd9Sstevel@tonic-gate 		authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *));
45897c478bd9Sstevel@tonic-gate 		if (authpp == NULL) {
45907c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeParam(&param);
45917c478bd9Sstevel@tonic-gate 			__s_api_release_config(cfg);
45927c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
45937c478bd9Sstevel@tonic-gate 		}
45947c478bd9Sstevel@tonic-gate 		while (!done) {
45957c478bd9Sstevel@tonic-gate 			send = strchr(srv, SEMITOK);
45967c478bd9Sstevel@tonic-gate 			if (send != NULL) {
45977c478bd9Sstevel@tonic-gate 				*send = '\0';
45987c478bd9Sstevel@tonic-gate 				send++;
45997c478bd9Sstevel@tonic-gate 			}
46007c478bd9Sstevel@tonic-gate 			i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P);
46017c478bd9Sstevel@tonic-gate 			if (i == -1) {
46027c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeParam(&param);
46037c478bd9Sstevel@tonic-gate 				(void) sprintf(errstr,
4604699bceb8Smj 				gettext("Unsupported "
4605699bceb8Smj 				    "serviceAuthenticationMethod: %s.\n"), srv);
46067c478bd9Sstevel@tonic-gate 				MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
460751b02b29SToomas Soome 				    strdup(errstr), NS_LDAP_MEMORY);
46087c478bd9Sstevel@tonic-gate 				__s_api_release_config(cfg);
46097c478bd9Sstevel@tonic-gate 				return (NS_LDAP_CONFIG);
46107c478bd9Sstevel@tonic-gate 			}
46117c478bd9Sstevel@tonic-gate 			ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i);
46127c478bd9Sstevel@tonic-gate 			if (ap == NULL) {
46137c478bd9Sstevel@tonic-gate 				(void) __ns_ldap_freeParam(&param);
46147c478bd9Sstevel@tonic-gate 				__s_api_release_config(cfg);
46157c478bd9Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
46167c478bd9Sstevel@tonic-gate 			}
46177c478bd9Sstevel@tonic-gate 			authpp[cnt++] = ap;
46187c478bd9Sstevel@tonic-gate 			if (send == NULL)
46198f0bb794SToomas Soome 				done = B_TRUE;
46207c478bd9Sstevel@tonic-gate 			else
46217c478bd9Sstevel@tonic-gate 				srv = send;
46227c478bd9Sstevel@tonic-gate 		}
46237c478bd9Sstevel@tonic-gate 	}
46247c478bd9Sstevel@tonic-gate 
46257c478bd9Sstevel@tonic-gate 	*auth = authpp;
46267c478bd9Sstevel@tonic-gate 	(void) __ns_ldap_freeParam(&param);
46277c478bd9Sstevel@tonic-gate 	__s_api_release_config(cfg);
46287c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
46297c478bd9Sstevel@tonic-gate }
46307c478bd9Sstevel@tonic-gate 
46317c478bd9Sstevel@tonic-gate /*
46327c478bd9Sstevel@tonic-gate  * This routine is called when certain scenario occurs
46337c478bd9Sstevel@tonic-gate  * e.g.
46347c478bd9Sstevel@tonic-gate  * service == auto_home
46357c478bd9Sstevel@tonic-gate  * SSD = automount: ou = mytest,
46367c478bd9Sstevel@tonic-gate  * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
46377c478bd9Sstevel@tonic-gate  * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
46387c478bd9Sstevel@tonic-gate  * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
46397c478bd9Sstevel@tonic-gate  *
46407c478bd9Sstevel@tonic-gate  * The automountMapName is prepended implicitely but is mapped
46417c478bd9Sstevel@tonic-gate  * to AAA. So dn could appers as
46427c478bd9Sstevel@tonic-gate  * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
46437c478bd9Sstevel@tonic-gate  * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
46447c478bd9Sstevel@tonic-gate  * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
46457c478bd9Sstevel@tonic-gate  * in the directory.
46467c478bd9Sstevel@tonic-gate  * This function is called to covert the mapped attr back to
46477c478bd9Sstevel@tonic-gate  * orig attr when the entries are searched and returned
46487c478bd9Sstevel@tonic-gate  */
46497c478bd9Sstevel@tonic-gate 
46507c478bd9Sstevel@tonic-gate int
__s_api_convert_automountmapname(const char * service,char ** dn,ns_ldap_error_t ** errp)46517c478bd9Sstevel@tonic-gate __s_api_convert_automountmapname(const char *service, char **dn,
46528f0bb794SToomas Soome     ns_ldap_error_t **errp)
46538f0bb794SToomas Soome {
46547c478bd9Sstevel@tonic-gate 
46557c478bd9Sstevel@tonic-gate 	char	**mapping = NULL;
46567c478bd9Sstevel@tonic-gate 	char	*mapped_attr = NULL;
46577c478bd9Sstevel@tonic-gate 	char	*automountmapname = "automountMapName";
46587c478bd9Sstevel@tonic-gate 	char	*buffer = NULL;
46597c478bd9Sstevel@tonic-gate 	int	rc = NS_LDAP_SUCCESS;
46607c478bd9Sstevel@tonic-gate 	char	errstr[MAXERROR];
46617c478bd9Sstevel@tonic-gate 
46627c478bd9Sstevel@tonic-gate 	/*
46637c478bd9Sstevel@tonic-gate 	 * dn is an input/out parameter, check it first
46647c478bd9Sstevel@tonic-gate 	 */
46657c478bd9Sstevel@tonic-gate 
46667c478bd9Sstevel@tonic-gate 	if (service == NULL || dn == NULL || *dn == NULL)
46677c478bd9Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
46687c478bd9Sstevel@tonic-gate 
46697c478bd9Sstevel@tonic-gate 	/*
46707c478bd9Sstevel@tonic-gate 	 * Check to see if there is a mapped attribute for auto_xxx
46717c478bd9Sstevel@tonic-gate 	 */
46727c478bd9Sstevel@tonic-gate 
46737c478bd9Sstevel@tonic-gate 	mapping = __ns_ldap_getMappedAttributes(service, automountmapname);
46747c478bd9Sstevel@tonic-gate 
46757c478bd9Sstevel@tonic-gate 	/*
46767c478bd9Sstevel@tonic-gate 	 * if no mapped attribute for auto_xxx, try automount
46777c478bd9Sstevel@tonic-gate 	 */
46787c478bd9Sstevel@tonic-gate 
46798f0bb794SToomas Soome 	if (mapping == NULL) {
46807c478bd9Sstevel@tonic-gate 		mapping = __ns_ldap_getMappedAttributes(
46818f0bb794SToomas Soome 		    "automount", automountmapname);
46828f0bb794SToomas Soome 	}
46837c478bd9Sstevel@tonic-gate 
46847c478bd9Sstevel@tonic-gate 	/*
46857c478bd9Sstevel@tonic-gate 	 * if no mapped attribute is found, return SUCCESS (no op)
46867c478bd9Sstevel@tonic-gate 	 */
46877c478bd9Sstevel@tonic-gate 
46887c478bd9Sstevel@tonic-gate 	if (mapping == NULL)
46897c478bd9Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
46907c478bd9Sstevel@tonic-gate 
46917c478bd9Sstevel@tonic-gate 	/*
46927c478bd9Sstevel@tonic-gate 	 * if the mapped attribute is found and attr is not empty,
46937c478bd9Sstevel@tonic-gate 	 * copy it
46947c478bd9Sstevel@tonic-gate 	 */
46957c478bd9Sstevel@tonic-gate 
46967c478bd9Sstevel@tonic-gate 	if (mapping[0] != NULL) {
46977c478bd9Sstevel@tonic-gate 		mapped_attr = strdup(mapping[0]);
46987c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(mapping);
46997c478bd9Sstevel@tonic-gate 		if (mapped_attr == NULL) {
47007c478bd9Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
47017c478bd9Sstevel@tonic-gate 		}
47027c478bd9Sstevel@tonic-gate 	} else {
47037c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(mapping);
47047c478bd9Sstevel@tonic-gate 
47057c478bd9Sstevel@tonic-gate 		(void) snprintf(errstr, (2 * MAXERROR),
47068f0bb794SToomas Soome 		    gettext("Attribute nisMapName is mapped to an "
47078f0bb794SToomas Soome 		    "empty string.\n"));
47087c478bd9Sstevel@tonic-gate 
47097c478bd9Sstevel@tonic-gate 		MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX,
47108f0bb794SToomas Soome 		    strdup(errstr), NS_LDAP_MEMORY);
47117c478bd9Sstevel@tonic-gate 
47127c478bd9Sstevel@tonic-gate 		return (NS_LDAP_CONFIG);
47137c478bd9Sstevel@tonic-gate 	}
47147c478bd9Sstevel@tonic-gate 
47157c478bd9Sstevel@tonic-gate 	/*
47167c478bd9Sstevel@tonic-gate 	 * Locate the mapped attribute in the dn
47177c478bd9Sstevel@tonic-gate 	 * and replace it if it exists
47187c478bd9Sstevel@tonic-gate 	 */
47197c478bd9Sstevel@tonic-gate 
47207c478bd9Sstevel@tonic-gate 	rc = __s_api_replace_mapped_attr_in_dn(
47218f0bb794SToomas Soome 	    (const char *) automountmapname, (const char *) mapped_attr,
47228f0bb794SToomas Soome 	    (const char *) *dn, &buffer);
47237c478bd9Sstevel@tonic-gate 
47247c478bd9Sstevel@tonic-gate 	/* clean up */
47257c478bd9Sstevel@tonic-gate 
47267c478bd9Sstevel@tonic-gate 	free(mapped_attr);
47277c478bd9Sstevel@tonic-gate 
47287c478bd9Sstevel@tonic-gate 	/*
47297c478bd9Sstevel@tonic-gate 	 * If mapped attr is found(buffer != NULL)
47307c478bd9Sstevel@tonic-gate 	 *	a new dn is returned
47317c478bd9Sstevel@tonic-gate 	 * If no mapped attribute is in dn,
47327c478bd9Sstevel@tonic-gate 	 *	return NS_LDAP_SUCCESS (no op)
47337c478bd9Sstevel@tonic-gate 	 * If no memory,
47347c478bd9Sstevel@tonic-gate 	 *	return NS_LDAP_MEMORY (no op)
47357c478bd9Sstevel@tonic-gate 	 */
47367c478bd9Sstevel@tonic-gate 
47377c478bd9Sstevel@tonic-gate 	if (buffer != NULL) {
47387c478bd9Sstevel@tonic-gate 		free(*dn);
47397c478bd9Sstevel@tonic-gate 		*dn = buffer;
47407c478bd9Sstevel@tonic-gate 	}
47417c478bd9Sstevel@tonic-gate 
47427c478bd9Sstevel@tonic-gate 	return (rc);
47437c478bd9Sstevel@tonic-gate }
47447c478bd9Sstevel@tonic-gate 
47457c478bd9Sstevel@tonic-gate /*
47467c478bd9Sstevel@tonic-gate  * If the mapped attr is found in the dn,
47478f0bb794SToomas Soome  *	return NS_LDAP_SUCCESS and a new_dn.
47487c478bd9Sstevel@tonic-gate  * If no mapped attr is found,
47498f0bb794SToomas Soome  *	return NS_LDAP_SUCCESS and *new_dn == NULL
47507c478bd9Sstevel@tonic-gate  * If there is not enough memory,
47518f0bb794SToomas Soome  *	return NS_LDAP_MEMORY and *new_dn == NULL
47527c478bd9Sstevel@tonic-gate  */
47537c478bd9Sstevel@tonic-gate 
47547c478bd9Sstevel@tonic-gate int
__s_api_replace_mapped_attr_in_dn(const char * orig_attr,const char * mapped_attr,const char * dn,char ** new_dn)47558f0bb794SToomas Soome __s_api_replace_mapped_attr_in_dn(const char *orig_attr,
47568f0bb794SToomas Soome     const char *mapped_attr, const char *dn, char **new_dn)
47578f0bb794SToomas Soome {
47587c478bd9Sstevel@tonic-gate 
47597c478bd9Sstevel@tonic-gate 	char	**dnArray = NULL;
47607c478bd9Sstevel@tonic-gate 	char	*cur = NULL, *start = NULL;
47618f0bb794SToomas Soome 	int	i = 0;
47628f0bb794SToomas Soome 	boolean_t found = B_FALSE;
47637c478bd9Sstevel@tonic-gate 	int	len = 0, orig_len = 0, mapped_len = 0;
47647c478bd9Sstevel@tonic-gate 	int	dn_len = 0, tmp_len = 0;
47657c478bd9Sstevel@tonic-gate 
47667c478bd9Sstevel@tonic-gate 	*new_dn = NULL;
47677c478bd9Sstevel@tonic-gate 
47687c478bd9Sstevel@tonic-gate 	/*
47697c478bd9Sstevel@tonic-gate 	 * seperate dn into individual componets
47707c478bd9Sstevel@tonic-gate 	 * e.g.
47717c478bd9Sstevel@tonic-gate 	 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
47727c478bd9Sstevel@tonic-gate 	 */
47737c478bd9Sstevel@tonic-gate 	dnArray = ldap_explode_dn(dn, 0);
47747c478bd9Sstevel@tonic-gate 
47757c478bd9Sstevel@tonic-gate 	/*
47767c478bd9Sstevel@tonic-gate 	 * This will find "mapped attr=value" in dn.
47777c478bd9Sstevel@tonic-gate 	 * It won't find match if mapped attr appears
47787c478bd9Sstevel@tonic-gate 	 * in the value.
47797c478bd9Sstevel@tonic-gate 	 */
47807c478bd9Sstevel@tonic-gate 	for (i = 0; dnArray[i] != NULL; i++) {
47817c478bd9Sstevel@tonic-gate 		/*
47827c478bd9Sstevel@tonic-gate 		 * This function is called when reading from
47837c478bd9Sstevel@tonic-gate 		 * the directory so assume each component has "=".
47847c478bd9Sstevel@tonic-gate 		 * Any ill formatted dn should be rejected
47857c478bd9Sstevel@tonic-gate 		 * before adding to the directory
47867c478bd9Sstevel@tonic-gate 		 */
47877c478bd9Sstevel@tonic-gate 		cur = strchr(dnArray[i], '=');
47887c478bd9Sstevel@tonic-gate 		*cur = '\0';
47897c478bd9Sstevel@tonic-gate 		if (strcasecmp(mapped_attr, dnArray[i]) == 0)
47908f0bb794SToomas Soome 			found = B_TRUE;
47917c478bd9Sstevel@tonic-gate 		*cur = '=';
47928f0bb794SToomas Soome 		if (found)
47938f0bb794SToomas Soome 			break;
47947c478bd9Sstevel@tonic-gate 	}
47957c478bd9Sstevel@tonic-gate 
47967c478bd9Sstevel@tonic-gate 	if (!found) {
47977c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(dnArray);
47987c478bd9Sstevel@tonic-gate 		*new_dn = NULL;
47997c478bd9Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
48007c478bd9Sstevel@tonic-gate 	}
48017c478bd9Sstevel@tonic-gate 	/*
48027c478bd9Sstevel@tonic-gate 	 * The new length is *dn length + (difference between
48037c478bd9Sstevel@tonic-gate 	 * orig attr and mapped attr) + 1 ;
48047c478bd9Sstevel@tonic-gate 	 * e.g.
48057c478bd9Sstevel@tonic-gate 	 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
48067c478bd9Sstevel@tonic-gate 	 * ==>
48077c478bd9Sstevel@tonic-gate 	 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
48087c478bd9Sstevel@tonic-gate 	 */
48097c478bd9Sstevel@tonic-gate 	mapped_len = strlen(mapped_attr);
48107c478bd9Sstevel@tonic-gate 	orig_len = strlen(orig_attr);
48117c478bd9Sstevel@tonic-gate 	dn_len = strlen(dn);
48127c478bd9Sstevel@tonic-gate 	len = dn_len + orig_len - mapped_len + 1;
48137c478bd9Sstevel@tonic-gate 	*new_dn = (char *)calloc(1, len);
48147c478bd9Sstevel@tonic-gate 	if (*new_dn == NULL) {
48157c478bd9Sstevel@tonic-gate 		__s_api_free2dArray(dnArray);
48167c478bd9Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
48177c478bd9Sstevel@tonic-gate 	}
48187c478bd9Sstevel@tonic-gate 
48197c478bd9Sstevel@tonic-gate 	/*
48207c478bd9Sstevel@tonic-gate 	 * Locate the mapped attr in the dn.
48217c478bd9Sstevel@tonic-gate 	 * Use dnArray[i] instead of mapped_attr
48227c478bd9Sstevel@tonic-gate 	 * because mapped_attr could appear in
48237c478bd9Sstevel@tonic-gate 	 * the value
48247c478bd9Sstevel@tonic-gate 	 */
48257c478bd9Sstevel@tonic-gate 
48267c478bd9Sstevel@tonic-gate 	cur = strstr(dn, dnArray[i]);
48277c478bd9Sstevel@tonic-gate 	__s_api_free2dArray(dnArray);
48287c478bd9Sstevel@tonic-gate 	/* copy the portion before mapped attr in dn  */
48297c478bd9Sstevel@tonic-gate 	start = *new_dn;
48307c478bd9Sstevel@tonic-gate 	tmp_len = cur - dn;
48318f0bb794SToomas Soome 	(void) memcpy(start, dn, tmp_len);
48327c478bd9Sstevel@tonic-gate 
48337c478bd9Sstevel@tonic-gate 	/*
48347c478bd9Sstevel@tonic-gate 	 * Copy the orig_attr. e.g. automountMapName
48357c478bd9Sstevel@tonic-gate 	 * This replaces mapped attr with orig attr
48367c478bd9Sstevel@tonic-gate 	 */
48377c478bd9Sstevel@tonic-gate 	start = start + (cur - dn); /* move cursor in buffer */
48388f0bb794SToomas Soome 	(void) memcpy(start, orig_attr, orig_len);
48397c478bd9Sstevel@tonic-gate 
48407c478bd9Sstevel@tonic-gate 	/*
48417c478bd9Sstevel@tonic-gate 	 * Copy the portion after mapped attr in dn
48427c478bd9Sstevel@tonic-gate 	 */
48437c478bd9Sstevel@tonic-gate 	cur = cur + mapped_len; /* move cursor in  dn  */
48447c478bd9Sstevel@tonic-gate 	start = start + orig_len; /* move cursor in buffer */
48457c478bd9Sstevel@tonic-gate 	(void) strcpy(start, cur);
48467c478bd9Sstevel@tonic-gate 
48477c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
48487c478bd9Sstevel@tonic-gate }
48497c478bd9Sstevel@tonic-gate 
48507c478bd9Sstevel@tonic-gate /*
48517c478bd9Sstevel@tonic-gate  * Validate Filter functions
48527c478bd9Sstevel@tonic-gate  */
48537c478bd9Sstevel@tonic-gate 
48547c478bd9Sstevel@tonic-gate /* ***** Start of modified libldap.so.5 filter parser ***** */
48557c478bd9Sstevel@tonic-gate 
48567c478bd9Sstevel@tonic-gate /* filter parsing routine forward references */
48577c478bd9Sstevel@tonic-gate static int adj_filter_list(char *str);
48587c478bd9Sstevel@tonic-gate static int adj_simple_filter(char *str);
48597c478bd9Sstevel@tonic-gate static int unescape_filterval(char *val);
48607c478bd9Sstevel@tonic-gate static int hexchar2int(char c);
48617c478bd9Sstevel@tonic-gate static int adj_substring_filter(char *val);
48627c478bd9Sstevel@tonic-gate 
48637c478bd9Sstevel@tonic-gate 
48647c478bd9Sstevel@tonic-gate /*
48657c478bd9Sstevel@tonic-gate  * assumes string manipulation is in-line
48667c478bd9Sstevel@tonic-gate  * and all strings are sufficient in size
48677c478bd9Sstevel@tonic-gate  * return value is the position after 'c'
48687c478bd9Sstevel@tonic-gate  */
48697c478bd9Sstevel@tonic-gate 
48707c478bd9Sstevel@tonic-gate static char *
resync_str(char * str,char * next,char c)48717c478bd9Sstevel@tonic-gate resync_str(char *str, char *next, char c)
48727c478bd9Sstevel@tonic-gate {
48737c478bd9Sstevel@tonic-gate 	char	*ret;
48747c478bd9Sstevel@tonic-gate 
48757c478bd9Sstevel@tonic-gate 	ret = str + strlen(str);
48767c478bd9Sstevel@tonic-gate 	*next = c;
48777c478bd9Sstevel@tonic-gate 	if (ret == next)
48787c478bd9Sstevel@tonic-gate 		return (ret);
48797c478bd9Sstevel@tonic-gate 	(void) strcat(str, next);
48807c478bd9Sstevel@tonic-gate 	return (ret);
48817c478bd9Sstevel@tonic-gate }
48827c478bd9Sstevel@tonic-gate 
48837c478bd9Sstevel@tonic-gate static char *
find_right_paren(char * s)48847c478bd9Sstevel@tonic-gate find_right_paren(char *s)
48857c478bd9Sstevel@tonic-gate {
48868f0bb794SToomas Soome 	int balance;
48878f0bb794SToomas Soome 	boolean_t escape;
48887c478bd9Sstevel@tonic-gate 
48897c478bd9Sstevel@tonic-gate 	balance = 1;
48908f0bb794SToomas Soome 	escape = B_FALSE;
48917c478bd9Sstevel@tonic-gate 	while (*s && balance) {
48928f0bb794SToomas Soome 		if (escape == B_FALSE) {
48937c478bd9Sstevel@tonic-gate 			if (*s == '(')
48947c478bd9Sstevel@tonic-gate 				balance++;
48957c478bd9Sstevel@tonic-gate 			else if (*s == ')')
48967c478bd9Sstevel@tonic-gate 				balance--;
48977c478bd9Sstevel@tonic-gate 		}
48988f0bb794SToomas Soome 		if (*s == '\\' && !escape)
48998f0bb794SToomas Soome 			escape = B_TRUE;
49007c478bd9Sstevel@tonic-gate 		else
49018f0bb794SToomas Soome 			escape = B_FALSE;
49027c478bd9Sstevel@tonic-gate 		if (balance)
49037c478bd9Sstevel@tonic-gate 			s++;
49047c478bd9Sstevel@tonic-gate 	}
49057c478bd9Sstevel@tonic-gate 
49067c478bd9Sstevel@tonic-gate 	return (*s ? s : NULL);
49077c478bd9Sstevel@tonic-gate }
49087c478bd9Sstevel@tonic-gate 
49097c478bd9Sstevel@tonic-gate static char *
adj_complex_filter(char * str)49107c478bd9Sstevel@tonic-gate adj_complex_filter(char	*str)
49117c478bd9Sstevel@tonic-gate {
49127c478bd9Sstevel@tonic-gate 	char	*next;
49137c478bd9Sstevel@tonic-gate 
49147c478bd9Sstevel@tonic-gate 	/*
49157c478bd9Sstevel@tonic-gate 	 * We have (x(filter)...) with str sitting on
49167c478bd9Sstevel@tonic-gate 	 * the x.  We have to find the paren matching
49177c478bd9Sstevel@tonic-gate 	 * the one before the x and put the intervening
49187c478bd9Sstevel@tonic-gate 	 * filters by calling adj_filter_list().
49197c478bd9Sstevel@tonic-gate 	 */
49207c478bd9Sstevel@tonic-gate 
49217c478bd9Sstevel@tonic-gate 	str++;
49227c478bd9Sstevel@tonic-gate 	if ((next = find_right_paren(str)) == NULL)
49237c478bd9Sstevel@tonic-gate 		return (NULL);
49247c478bd9Sstevel@tonic-gate 
49257c478bd9Sstevel@tonic-gate 	*next = '\0';
49267c478bd9Sstevel@tonic-gate 	if (adj_filter_list(str) == -1)
49277c478bd9Sstevel@tonic-gate 		return (NULL);
49287c478bd9Sstevel@tonic-gate 	next = resync_str(str, next, ')');
49297c478bd9Sstevel@tonic-gate 	next++;
49307c478bd9Sstevel@tonic-gate 
49317c478bd9Sstevel@tonic-gate 	return (next);
49327c478bd9Sstevel@tonic-gate }
49337c478bd9Sstevel@tonic-gate 
49347c478bd9Sstevel@tonic-gate static int
adj_filter(char * str)49357c478bd9Sstevel@tonic-gate adj_filter(char *str)
49367c478bd9Sstevel@tonic-gate {
49378f0bb794SToomas Soome 	char *next;
49388f0bb794SToomas Soome 	int parens, balance;
49398f0bb794SToomas Soome 	boolean_t escape;
49408f0bb794SToomas Soome 	char *np, *cp,  *dp;
49417c478bd9Sstevel@tonic-gate 
49427c478bd9Sstevel@tonic-gate 	parens = 0;
49437c478bd9Sstevel@tonic-gate 	while (*str) {
49447c478bd9Sstevel@tonic-gate 		switch (*str) {
49457c478bd9Sstevel@tonic-gate 		case '(':
49467c478bd9Sstevel@tonic-gate 			str++;
49477c478bd9Sstevel@tonic-gate 			parens++;
49487c478bd9Sstevel@tonic-gate 			switch (*str) {
49497c478bd9Sstevel@tonic-gate 			case '&':
49507c478bd9Sstevel@tonic-gate 				if ((str = adj_complex_filter(str)) == NULL)
49517c478bd9Sstevel@tonic-gate 					return (-1);
49527c478bd9Sstevel@tonic-gate 
49537c478bd9Sstevel@tonic-gate 				parens--;
49547c478bd9Sstevel@tonic-gate 				break;
49557c478bd9Sstevel@tonic-gate 
49567c478bd9Sstevel@tonic-gate 			case '|':
49577c478bd9Sstevel@tonic-gate 				if ((str = adj_complex_filter(str)) == NULL)
49587c478bd9Sstevel@tonic-gate 					return (-1);
49597c478bd9Sstevel@tonic-gate 
49607c478bd9Sstevel@tonic-gate 				parens--;
49617c478bd9Sstevel@tonic-gate 				break;
49627c478bd9Sstevel@tonic-gate 
49637c478bd9Sstevel@tonic-gate 			case '!':
49647c478bd9Sstevel@tonic-gate 				if ((str = adj_complex_filter(str)) == NULL)
49657c478bd9Sstevel@tonic-gate 					return (-1);
49667c478bd9Sstevel@tonic-gate 
49677c478bd9Sstevel@tonic-gate 				parens--;
49687c478bd9Sstevel@tonic-gate 				break;
49697c478bd9Sstevel@tonic-gate 
49707c478bd9Sstevel@tonic-gate 			case '(':
49717c478bd9Sstevel@tonic-gate 				/* illegal ((case - generated by conversion */
49727c478bd9Sstevel@tonic-gate 
49737c478bd9Sstevel@tonic-gate 				/* find missing close) */
49747c478bd9Sstevel@tonic-gate 				np = find_right_paren(str+1);
49757c478bd9Sstevel@tonic-gate 
49767c478bd9Sstevel@tonic-gate 				/* error if not found */
49777c478bd9Sstevel@tonic-gate 				if (np == NULL)
49787c478bd9Sstevel@tonic-gate 					return (-1);
49797c478bd9Sstevel@tonic-gate 
49807c478bd9Sstevel@tonic-gate 				/* remove redundant (and) */
49817c478bd9Sstevel@tonic-gate 				for (dp = str, cp = str+1; cp < np; ) {
49827c478bd9Sstevel@tonic-gate 					*dp++ = *cp++;
49837c478bd9Sstevel@tonic-gate 				}
49847c478bd9Sstevel@tonic-gate 				cp++;
49857c478bd9Sstevel@tonic-gate 				while (*cp)
49867c478bd9Sstevel@tonic-gate 					*dp++ = *cp++;
49877c478bd9Sstevel@tonic-gate 				*dp = '\0';
49887c478bd9Sstevel@tonic-gate 
49897c478bd9Sstevel@tonic-gate 				/* re-start test at original ( */
49907c478bd9Sstevel@tonic-gate 				parens--;
49917c478bd9Sstevel@tonic-gate 				str--;
49927c478bd9Sstevel@tonic-gate 				break;
49937c478bd9Sstevel@tonic-gate 
49947c478bd9Sstevel@tonic-gate 			default:
49957c478bd9Sstevel@tonic-gate 				balance = 1;
49968f0bb794SToomas Soome 				escape = B_FALSE;
49977c478bd9Sstevel@tonic-gate 				next = str;
49987c478bd9Sstevel@tonic-gate 				while (*next && balance) {
49998f0bb794SToomas Soome 					if (escape == B_FALSE) {
50007c478bd9Sstevel@tonic-gate 						if (*next == '(')
50017c478bd9Sstevel@tonic-gate 							balance++;
50027c478bd9Sstevel@tonic-gate 						else if (*next == ')')
50037c478bd9Sstevel@tonic-gate 							balance--;
50047c478bd9Sstevel@tonic-gate 					}
50058f0bb794SToomas Soome 					if (*next == '\\' && !escape)
50068f0bb794SToomas Soome 						escape = B_TRUE;
50077c478bd9Sstevel@tonic-gate 					else
50088f0bb794SToomas Soome 						escape = B_FALSE;
50097c478bd9Sstevel@tonic-gate 					if (balance)
50107c478bd9Sstevel@tonic-gate 						next++;
50117c478bd9Sstevel@tonic-gate 				}
50127c478bd9Sstevel@tonic-gate 				if (balance != 0)
50137c478bd9Sstevel@tonic-gate 					return (-1);
50147c478bd9Sstevel@tonic-gate 
50157c478bd9Sstevel@tonic-gate 				*next = '\0';
50167c478bd9Sstevel@tonic-gate 				if (adj_simple_filter(str) == -1) {
50177c478bd9Sstevel@tonic-gate 					return (-1);
50187c478bd9Sstevel@tonic-gate 				}
50197c478bd9Sstevel@tonic-gate 				next = resync_str(str, next, ')');
50207c478bd9Sstevel@tonic-gate 				next++;
50217c478bd9Sstevel@tonic-gate 				str = next;
50227c478bd9Sstevel@tonic-gate 				parens--;
50237c478bd9Sstevel@tonic-gate 				break;
50247c478bd9Sstevel@tonic-gate 			}
50257c478bd9Sstevel@tonic-gate 			break;
50267c478bd9Sstevel@tonic-gate 
50277c478bd9Sstevel@tonic-gate 		case ')':
50287c478bd9Sstevel@tonic-gate 			str++;
50297c478bd9Sstevel@tonic-gate 			parens--;
50307c478bd9Sstevel@tonic-gate 			break;
50317c478bd9Sstevel@tonic-gate 
50327c478bd9Sstevel@tonic-gate 		case ' ':
50337c478bd9Sstevel@tonic-gate 			str++;
50347c478bd9Sstevel@tonic-gate 			break;
50357c478bd9Sstevel@tonic-gate 
50367c478bd9Sstevel@tonic-gate 		default:	/* assume it's a simple type=value filter */
50377c478bd9Sstevel@tonic-gate 			next = strchr(str, '\0');
50387c478bd9Sstevel@tonic-gate 			if (adj_simple_filter(str) == -1) {
50397c478bd9Sstevel@tonic-gate 				return (-1);
50407c478bd9Sstevel@tonic-gate 			}
50417c478bd9Sstevel@tonic-gate 			str = next;
50427c478bd9Sstevel@tonic-gate 			break;
50437c478bd9Sstevel@tonic-gate 		}
50447c478bd9Sstevel@tonic-gate 	}
50457c478bd9Sstevel@tonic-gate 
50467c478bd9Sstevel@tonic-gate 	return (parens ? -1 : 0);
50477c478bd9Sstevel@tonic-gate }
50487c478bd9Sstevel@tonic-gate 
50497c478bd9Sstevel@tonic-gate 
50507c478bd9Sstevel@tonic-gate /*
50517c478bd9Sstevel@tonic-gate  * Put a list of filters like this "(filter1)(filter2)..."
50527c478bd9Sstevel@tonic-gate  */
50537c478bd9Sstevel@tonic-gate 
50547c478bd9Sstevel@tonic-gate static int
adj_filter_list(char * str)50557c478bd9Sstevel@tonic-gate adj_filter_list(char *str)
50567c478bd9Sstevel@tonic-gate {
50577c478bd9Sstevel@tonic-gate 	char	*next;
50587c478bd9Sstevel@tonic-gate 	char	save;
50597c478bd9Sstevel@tonic-gate 
50607c478bd9Sstevel@tonic-gate 	while (*str) {
50617c478bd9Sstevel@tonic-gate 		while (*str && isspace(*str))
50627c478bd9Sstevel@tonic-gate 			str++;
50637c478bd9Sstevel@tonic-gate 		if (*str == '\0')
50647c478bd9Sstevel@tonic-gate 			break;
50657c478bd9Sstevel@tonic-gate 
50667c478bd9Sstevel@tonic-gate 		if ((next = find_right_paren(str + 1)) == NULL)
50677c478bd9Sstevel@tonic-gate 			return (-1);
50687c478bd9Sstevel@tonic-gate 		save = *++next;
50697c478bd9Sstevel@tonic-gate 
50707c478bd9Sstevel@tonic-gate 		/* now we have "(filter)" with str pointing to it */
50717c478bd9Sstevel@tonic-gate 		*next = '\0';
50727c478bd9Sstevel@tonic-gate 		if (adj_filter(str) == -1)
50737c478bd9Sstevel@tonic-gate 			return (-1);
50747c478bd9Sstevel@tonic-gate 		next = resync_str(str, next, save);
50757c478bd9Sstevel@tonic-gate 
50767c478bd9Sstevel@tonic-gate 		str = next;
50777c478bd9Sstevel@tonic-gate 	}
50787c478bd9Sstevel@tonic-gate 
50797c478bd9Sstevel@tonic-gate 	return (0);
50807c478bd9Sstevel@tonic-gate }
50817c478bd9Sstevel@tonic-gate 
50827c478bd9Sstevel@tonic-gate 
50837c478bd9Sstevel@tonic-gate /*
50847c478bd9Sstevel@tonic-gate  * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
50857c478bd9Sstevel@tonic-gate  * of a filter expression, 0 otherwise.  A valid string may contain only
50867c478bd9Sstevel@tonic-gate  * letters, numbers, hyphens, semi-colons, colons and periods. examples:
50877c478bd9Sstevel@tonic-gate  *	cn
50887c478bd9Sstevel@tonic-gate  *	cn;lang-fr
50897c478bd9Sstevel@tonic-gate  *	1.2.3.4;binary;dynamic
50907c478bd9Sstevel@tonic-gate  *	mail;dynamic
50917c478bd9Sstevel@tonic-gate  *	cn:dn:1.2.3.4
50927c478bd9Sstevel@tonic-gate  *
50937c478bd9Sstevel@tonic-gate  * For compatibility with older servers, we also allow underscores in
50947c478bd9Sstevel@tonic-gate  * attribute types, even through they are not allowed by the LDAPv3 RFCs.
50957c478bd9Sstevel@tonic-gate  */
50967c478bd9Sstevel@tonic-gate static int
is_valid_attr(char * a)50977c478bd9Sstevel@tonic-gate is_valid_attr(char *a)
50987c478bd9Sstevel@tonic-gate {
50997c478bd9Sstevel@tonic-gate 	for (; *a; a++) {
51007c478bd9Sstevel@tonic-gate 		if (!isascii(*a)) {
51017c478bd9Sstevel@tonic-gate 			return (0);
51027c478bd9Sstevel@tonic-gate 		} else if (!isalnum(*a)) {
51037c478bd9Sstevel@tonic-gate 			switch (*a) {
51047c478bd9Sstevel@tonic-gate 			case '-':
51057c478bd9Sstevel@tonic-gate 			case '.':
51067c478bd9Sstevel@tonic-gate 			case ';':
51077c478bd9Sstevel@tonic-gate 			case ':':
51087c478bd9Sstevel@tonic-gate 			case '_':
51097c478bd9Sstevel@tonic-gate 				break; /* valid */
51107c478bd9Sstevel@tonic-gate 			default:
51117c478bd9Sstevel@tonic-gate 				return (0);
51127c478bd9Sstevel@tonic-gate 			}
51137c478bd9Sstevel@tonic-gate 		}
51147c478bd9Sstevel@tonic-gate 	}
51157c478bd9Sstevel@tonic-gate 	return (1);
51167c478bd9Sstevel@tonic-gate }
51177c478bd9Sstevel@tonic-gate 
51187c478bd9Sstevel@tonic-gate static char *
find_star(char * s)51197c478bd9Sstevel@tonic-gate find_star(char *s)
51207c478bd9Sstevel@tonic-gate {
51217c478bd9Sstevel@tonic-gate 	for (; *s; ++s) {
51227c478bd9Sstevel@tonic-gate 		switch (*s) {
51237c478bd9Sstevel@tonic-gate 		case '*':
51247c478bd9Sstevel@tonic-gate 			return (s);
51257c478bd9Sstevel@tonic-gate 		case '\\':
51267c478bd9Sstevel@tonic-gate 			++s;
51277c478bd9Sstevel@tonic-gate 			if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0)
51287c478bd9Sstevel@tonic-gate 				++s;
51297c478bd9Sstevel@tonic-gate 		default:
51307c478bd9Sstevel@tonic-gate 			break;
51317c478bd9Sstevel@tonic-gate 		}
51327c478bd9Sstevel@tonic-gate 	}
51337c478bd9Sstevel@tonic-gate 	return (NULL);
51347c478bd9Sstevel@tonic-gate }
51357c478bd9Sstevel@tonic-gate 
51367c478bd9Sstevel@tonic-gate static int
adj_simple_filter(char * str)51377c478bd9Sstevel@tonic-gate adj_simple_filter(char *str)
51387c478bd9Sstevel@tonic-gate {
51397c478bd9Sstevel@tonic-gate 	char		*s, *s2, *s3, filterop;
51407c478bd9Sstevel@tonic-gate 	char		*value;
51417c478bd9Sstevel@tonic-gate 	int		ftype = 0;
51427c478bd9Sstevel@tonic-gate 	int		rc;
51437c478bd9Sstevel@tonic-gate 
51447c478bd9Sstevel@tonic-gate 	rc = -1;	/* pessimistic */
51457c478bd9Sstevel@tonic-gate 
51467c478bd9Sstevel@tonic-gate 	if ((str = strdup(str)) == NULL) {
51477c478bd9Sstevel@tonic-gate 		return (rc);
51487c478bd9Sstevel@tonic-gate 	}
51497c478bd9Sstevel@tonic-gate 
51507c478bd9Sstevel@tonic-gate 	if ((s = strchr(str, '=')) == NULL) {
51517c478bd9Sstevel@tonic-gate 		goto free_and_return;
51527c478bd9Sstevel@tonic-gate 	}
51537c478bd9Sstevel@tonic-gate 	value = s + 1;
51547c478bd9Sstevel@tonic-gate 	*s-- = '\0';
51557c478bd9Sstevel@tonic-gate 	filterop = *s;
51567c478bd9Sstevel@tonic-gate 	if (filterop == '<' || filterop == '>' || filterop == '~' ||
51577c478bd9Sstevel@tonic-gate 	    filterop == ':') {
51587c478bd9Sstevel@tonic-gate 		*s = '\0';
51597c478bd9Sstevel@tonic-gate 	}
51607c478bd9Sstevel@tonic-gate 
51618f0bb794SToomas Soome 	if (!is_valid_attr(str)) {
51627c478bd9Sstevel@tonic-gate 		goto free_and_return;
51637c478bd9Sstevel@tonic-gate 	}
51647c478bd9Sstevel@tonic-gate 
51657c478bd9Sstevel@tonic-gate 	switch (filterop) {
51667c478bd9Sstevel@tonic-gate 	case '<': /* LDAP_FILTER_LE */
51677c478bd9Sstevel@tonic-gate 	case '>': /* LDAP_FILTER_GE */
51687c478bd9Sstevel@tonic-gate 	case '~': /* LDAP_FILTER_APPROX */
51697c478bd9Sstevel@tonic-gate 		break;
51707c478bd9Sstevel@tonic-gate 	case ':':	/* extended filter - v3 only */
51717c478bd9Sstevel@tonic-gate 		/*
51727c478bd9Sstevel@tonic-gate 		 * extended filter looks like this:
51737c478bd9Sstevel@tonic-gate 		 *
51747c478bd9Sstevel@tonic-gate 		 *	[type][':dn'][':'oid]':='value
51757c478bd9Sstevel@tonic-gate 		 *
51767c478bd9Sstevel@tonic-gate 		 * where one of type or :oid is required.
51777c478bd9Sstevel@tonic-gate 		 *
51787c478bd9Sstevel@tonic-gate 		 */
51797c478bd9Sstevel@tonic-gate 		s2 = s3 = NULL;
51807c478bd9Sstevel@tonic-gate 		if ((s2 = strrchr(str, ':')) == NULL) {
51817c478bd9Sstevel@tonic-gate 			goto free_and_return;
51827c478bd9Sstevel@tonic-gate 		}
51837c478bd9Sstevel@tonic-gate 		if (strcasecmp(s2, ":dn") == 0) {
51847c478bd9Sstevel@tonic-gate 			*s2 = '\0';
51857c478bd9Sstevel@tonic-gate 		} else {
51867c478bd9Sstevel@tonic-gate 			*s2 = '\0';
51877c478bd9Sstevel@tonic-gate 			if ((s3 = strrchr(str, ':')) != NULL) {
51887c478bd9Sstevel@tonic-gate 				if (strcasecmp(s3, ":dn") != 0) {
51897c478bd9Sstevel@tonic-gate 					goto free_and_return;
51907c478bd9Sstevel@tonic-gate 				}
51917c478bd9Sstevel@tonic-gate 				*s3 = '\0';
51927c478bd9Sstevel@tonic-gate 			}
51937c478bd9Sstevel@tonic-gate 		}
51947c478bd9Sstevel@tonic-gate 		if (unescape_filterval(value) < 0) {
51957c478bd9Sstevel@tonic-gate 			goto free_and_return;
51967c478bd9Sstevel@tonic-gate 		}
51977c478bd9Sstevel@tonic-gate 		rc = 0;
51987c478bd9Sstevel@tonic-gate 		goto free_and_return;
51997c478bd9Sstevel@tonic-gate 		/* break; */
52007c478bd9Sstevel@tonic-gate 	default:
52017c478bd9Sstevel@tonic-gate 		if (find_star(value) == NULL) {
52027c478bd9Sstevel@tonic-gate 			ftype = 0; /* LDAP_FILTER_EQUALITY */
52037c478bd9Sstevel@tonic-gate 		} else if (strcmp(value, "*") == 0) {
52047c478bd9Sstevel@tonic-gate 			ftype = 1; /* LDAP_FILTER_PRESENT */
52057c478bd9Sstevel@tonic-gate 		} else {
52067c478bd9Sstevel@tonic-gate 			rc = adj_substring_filter(value);
52077c478bd9Sstevel@tonic-gate 			goto free_and_return;
52087c478bd9Sstevel@tonic-gate 		}
52097c478bd9Sstevel@tonic-gate 		break;
52107c478bd9Sstevel@tonic-gate 	}
52117c478bd9Sstevel@tonic-gate 
52127c478bd9Sstevel@tonic-gate 	if (ftype != 0) {	/* == LDAP_FILTER_PRESENT */
52137c478bd9Sstevel@tonic-gate 		rc = 0;
52147c478bd9Sstevel@tonic-gate 	} else if (unescape_filterval(value) >= 0) {
52157c478bd9Sstevel@tonic-gate 		rc = 0;
52167c478bd9Sstevel@tonic-gate 	}
52177c478bd9Sstevel@tonic-gate 	if (rc != -1) {
52187c478bd9Sstevel@tonic-gate 		rc = 0;
52197c478bd9Sstevel@tonic-gate 	}
52207c478bd9Sstevel@tonic-gate 
52217c478bd9Sstevel@tonic-gate free_and_return:
52227c478bd9Sstevel@tonic-gate 	free(str);
52237c478bd9Sstevel@tonic-gate 	return (rc);
52247c478bd9Sstevel@tonic-gate }
52257c478bd9Sstevel@tonic-gate 
52267c478bd9Sstevel@tonic-gate 
52277c478bd9Sstevel@tonic-gate /*
52287c478bd9Sstevel@tonic-gate  * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
52297c478bd9Sstevel@tonic-gate  * sequences within the null-terminated string 'val'.
52307c478bd9Sstevel@tonic-gate  *
52317c478bd9Sstevel@tonic-gate  * If 'val' contains invalid escape sequences we return -1.
52327c478bd9Sstevel@tonic-gate  * Otherwise return 1
52337c478bd9Sstevel@tonic-gate  */
52347c478bd9Sstevel@tonic-gate static int
unescape_filterval(char * val)52357c478bd9Sstevel@tonic-gate unescape_filterval(char *val)
52367c478bd9Sstevel@tonic-gate {
52378f0bb794SToomas Soome 	boolean_t escape, firstdigit;
52388f0bb794SToomas Soome 	char *s;
52397c478bd9Sstevel@tonic-gate 
52408f0bb794SToomas Soome 	firstdigit = B_FALSE;
52418f0bb794SToomas Soome 	escape = B_FALSE;
52427c478bd9Sstevel@tonic-gate 	for (s = val; *s; s++) {
52437c478bd9Sstevel@tonic-gate 		if (escape) {
52447c478bd9Sstevel@tonic-gate 			/*
52457c478bd9Sstevel@tonic-gate 			 * first try LDAPv3 escape (hexadecimal) sequence
52467c478bd9Sstevel@tonic-gate 			 */
52477c478bd9Sstevel@tonic-gate 			if (hexchar2int(*s) < 0) {
52487c478bd9Sstevel@tonic-gate 				if (firstdigit) {
52497c478bd9Sstevel@tonic-gate 					/*
52507c478bd9Sstevel@tonic-gate 					 * LDAPv2 (RFC1960) escape sequence
52517c478bd9Sstevel@tonic-gate 					 */
52528f0bb794SToomas Soome 					escape = B_FALSE;
52537c478bd9Sstevel@tonic-gate 				} else {
52547c478bd9Sstevel@tonic-gate 					return (-1);
52557c478bd9Sstevel@tonic-gate 				}
52567c478bd9Sstevel@tonic-gate 			}
52577c478bd9Sstevel@tonic-gate 			if (firstdigit) {
52588f0bb794SToomas Soome 				firstdigit = B_FALSE;
52597c478bd9Sstevel@tonic-gate 			} else {
52608f0bb794SToomas Soome 				escape = B_FALSE;
52617c478bd9Sstevel@tonic-gate 			}
52627c478bd9Sstevel@tonic-gate 
52637c478bd9Sstevel@tonic-gate 		} else if (*s != '\\') {
52648f0bb794SToomas Soome 			escape = B_FALSE;
52657c478bd9Sstevel@tonic-gate 
52667c478bd9Sstevel@tonic-gate 		} else {
52678f0bb794SToomas Soome 			escape = B_TRUE;
52688f0bb794SToomas Soome 			firstdigit = B_TRUE;
52697c478bd9Sstevel@tonic-gate 		}
52707c478bd9Sstevel@tonic-gate 	}
52717c478bd9Sstevel@tonic-gate 
52727c478bd9Sstevel@tonic-gate 	return (1);
52737c478bd9Sstevel@tonic-gate }
52747c478bd9Sstevel@tonic-gate 
52757c478bd9Sstevel@tonic-gate 
52767c478bd9Sstevel@tonic-gate /*
52777c478bd9Sstevel@tonic-gate  * convert character 'c' that represents a hexadecimal digit to an integer.
52787c478bd9Sstevel@tonic-gate  * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
52797c478bd9Sstevel@tonic-gate  * otherwise the converted value is returned.
52807c478bd9Sstevel@tonic-gate  */
52817c478bd9Sstevel@tonic-gate static int
hexchar2int(char c)52827c478bd9Sstevel@tonic-gate hexchar2int(char c)
52837c478bd9Sstevel@tonic-gate {
52847c478bd9Sstevel@tonic-gate 	if (c >= '0' && c <= '9') {
52857c478bd9Sstevel@tonic-gate 		return (c - '0');
52867c478bd9Sstevel@tonic-gate 	}
52877c478bd9Sstevel@tonic-gate 	if (c >= 'A' && c <= 'F') {
52887c478bd9Sstevel@tonic-gate 		return (c - 'A' + 10);
52897c478bd9Sstevel@tonic-gate 	}
52907c478bd9Sstevel@tonic-gate 	if (c >= 'a' && c <= 'f') {
52917c478bd9Sstevel@tonic-gate 		return (c - 'a' + 10);
52927c478bd9Sstevel@tonic-gate 	}
52937c478bd9Sstevel@tonic-gate 	return (-1);
52947c478bd9Sstevel@tonic-gate }
52957c478bd9Sstevel@tonic-gate 
52967c478bd9Sstevel@tonic-gate static int
adj_substring_filter(char * val)52977c478bd9Sstevel@tonic-gate adj_substring_filter(char *val)
52987c478bd9Sstevel@tonic-gate {
52997c478bd9Sstevel@tonic-gate 	char		*nextstar;
53007c478bd9Sstevel@tonic-gate 
53017c478bd9Sstevel@tonic-gate 	for (; val != NULL; val = nextstar) {
53027c478bd9Sstevel@tonic-gate 		if ((nextstar = find_star(val)) != NULL) {
53037c478bd9Sstevel@tonic-gate 			*nextstar++ = '\0';
53047c478bd9Sstevel@tonic-gate 		}
53057c478bd9Sstevel@tonic-gate 
53067c478bd9Sstevel@tonic-gate 		if (*val != '\0') {
53077c478bd9Sstevel@tonic-gate 			if (unescape_filterval(val) < 0) {
53087c478bd9Sstevel@tonic-gate 				return (-1);
53097c478bd9Sstevel@tonic-gate 			}
53107c478bd9Sstevel@tonic-gate 		}
53117c478bd9Sstevel@tonic-gate 	}
53127c478bd9Sstevel@tonic-gate 
53137c478bd9Sstevel@tonic-gate 	return (0);
53147c478bd9Sstevel@tonic-gate }
53157c478bd9Sstevel@tonic-gate 
53167c478bd9Sstevel@tonic-gate /* ***** End of modified libldap.so.5 filter parser ***** */
53177c478bd9Sstevel@tonic-gate 
53187c478bd9Sstevel@tonic-gate 
53197c478bd9Sstevel@tonic-gate /*
53207c478bd9Sstevel@tonic-gate  * Walk filter, remove redundant parentheses in-line
53217c478bd9Sstevel@tonic-gate  * verify that the filter is reasonable
53227c478bd9Sstevel@tonic-gate  */
53237c478bd9Sstevel@tonic-gate static int
validate_filter(ns_ldap_cookie_t * cookie)53247c478bd9Sstevel@tonic-gate validate_filter(ns_ldap_cookie_t *cookie)
53257c478bd9Sstevel@tonic-gate {
53267c478bd9Sstevel@tonic-gate 	char			*filter = cookie->filter;
53277c478bd9Sstevel@tonic-gate 	int			rc;
53287c478bd9Sstevel@tonic-gate 
53297c478bd9Sstevel@tonic-gate 	/* Parse filter looking for illegal values */
53307c478bd9Sstevel@tonic-gate 
53317c478bd9Sstevel@tonic-gate 	rc = adj_filter(filter);
53327c478bd9Sstevel@tonic-gate 	if (rc != 0) {
53337c478bd9Sstevel@tonic-gate 		return (NS_LDAP_OP_FAILED);
53347c478bd9Sstevel@tonic-gate 	}
53357c478bd9Sstevel@tonic-gate 
53367c478bd9Sstevel@tonic-gate 	/* end of filter checking */
53377c478bd9Sstevel@tonic-gate 
53387c478bd9Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
53397c478bd9Sstevel@tonic-gate }
534047789246Svv 
534147789246Svv /*
534247789246Svv  * Set the account management request control that needs to be sent to server.
534347789246Svv  * This control is required to get the account management information of
534447789246Svv  * a user to do local account checking.
534547789246Svv  */
534647789246Svv static int
setup_acctmgmt_params(ns_ldap_cookie_t * cookie)534747789246Svv setup_acctmgmt_params(ns_ldap_cookie_t *cookie)
534847789246Svv {
53490ababfc6SToomas Soome 	LDAPControl	*req, **requestctrls;
535047789246Svv 
53510ababfc6SToomas Soome 	req = calloc(1, sizeof (LDAPControl));
535247789246Svv 
535347789246Svv 	if (req == NULL)
535447789246Svv 		return (NS_LDAP_MEMORY);
535547789246Svv 
535647789246Svv 	/* fill in the fields of this new control */
535747789246Svv 	req->ldctl_iscritical = 1;
535847789246Svv 	req->ldctl_oid = strdup(NS_LDAP_ACCOUNT_USABLE_CONTROL);
535947789246Svv 	if (req->ldctl_oid == NULL) {
536047789246Svv 		free(req);
536147789246Svv 		return (NS_LDAP_MEMORY);
536247789246Svv 	}
536347789246Svv 
536447789246Svv 	requestctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
536547789246Svv 	if (requestctrls == NULL) {
536647789246Svv 		ldap_control_free(req);
536747789246Svv 		return (NS_LDAP_MEMORY);
536847789246Svv 	}
536947789246Svv 
537047789246Svv 	requestctrls[0] = req;
537147789246Svv 
537247789246Svv 	cookie->p_serverctrls = requestctrls;
537347789246Svv 
537447789246Svv 	return (NS_LDAP_SUCCESS);
537547789246Svv }
537647789246Svv 
537747789246Svv /*
5378f47dc443Ssdussud  * int get_new_acct_more_info(BerElement *ber,
5379f47dc443Ssdussud  *     AcctUsableResponse_t *acctResp)
5380f47dc443Ssdussud  *
5381f47dc443Ssdussud  * Decode the more_info data from an Account Management control response,
5382f47dc443Ssdussud  * when the account is not usable and when code style is from recent LDAP
5383f47dc443Ssdussud  * servers (see below comments for parse_acct_cont_resp_msg() to get more
5384f47dc443Ssdussud  * details on coding styles and ASN1 description).
5385f47dc443Ssdussud  *
5386f47dc443Ssdussud  * Expected BER encoding: {tbtbtbtiti}
5387f47dc443Ssdussud  *      +t: tag is 0
538847789246Svv  *	+b: TRUE if inactive due to account inactivation
5389f47dc443Ssdussud  *      +t: tag is 1
53908f0bb794SToomas Soome  *	+b: TRUE if password has been reset
5391f47dc443Ssdussud  *      +t: tag is 2
53928f0bb794SToomas Soome  *	+b: TRUE if password is expired
5393f47dc443Ssdussud  *	+t: tag is 3
5394f47dc443Ssdussud  *	+i: contains num of remaining grace, 0 means no grace
5395f47dc443Ssdussud  *	+t: tag is 4
5396f47dc443Ssdussud  *	+i: contains num of seconds before auto-unlock. -1 means acct is locked
5397f47dc443Ssdussud  *		forever (i.e. until reset)
5398f47dc443Ssdussud  *
5399f47dc443Ssdussud  * Asumptions:
5400f47dc443Ssdussud  * - ber is not null
5401f47dc443Ssdussud  * - acctResp is not null and is initialized with default values for the
5402f47dc443Ssdussud  *   fields in its AcctUsableResp.more_info structure
5403f47dc443Ssdussud  * - the ber stream is received in the correct order, per the ASN1 description.
5404f47dc443Ssdussud  *   We do not check this order and make the asumption that it is correct.
5405f47dc443Ssdussud  *   Note that the ber stream may not (and will not in most cases) contain
5406f47dc443Ssdussud  *   all fields.
5407f47dc443Ssdussud  */
5408f47dc443Ssdussud static int
get_new_acct_more_info(BerElement * ber,AcctUsableResponse_t * acctResp)5409f47dc443Ssdussud get_new_acct_more_info(BerElement *ber, AcctUsableResponse_t *acctResp)
5410f47dc443Ssdussud {
5411f47dc443Ssdussud 	int		rc = NS_LDAP_SUCCESS;
5412f47dc443Ssdussud 	char		errstr[MAXERROR];
5413f47dc443Ssdussud 	ber_tag_t	rTag = LBER_DEFAULT;
5414f47dc443Ssdussud 	ber_len_t	rLen = 0;
5415f47dc443Ssdussud 	ber_int_t	rValue;
5416f47dc443Ssdussud 	char		*last;
5417f47dc443Ssdussud 	int		berRC = 0;
5418f47dc443Ssdussud 
5419f47dc443Ssdussud 	/*
5420f47dc443Ssdussud 	 * Look at what more_info BER element is/are left to be decoded.
5421f47dc443Ssdussud 	 * look at each of them 1 by 1, without checking on their order
5422f47dc443Ssdussud 	 * and possible multi values.
5423f47dc443Ssdussud 	 */
5424f47dc443Ssdussud 	for (rTag = ber_first_element(ber, &rLen, &last);
5425f47dc443Ssdussud 	    rTag != LBER_END_OF_SEQORSET;
5426f47dc443Ssdussud 	    rTag = ber_next_element(ber, &rLen, last)) {
5427f47dc443Ssdussud 
5428f47dc443Ssdussud 		berRC = 0;
5429f47dc443Ssdussud 		switch (rTag) {
5430f47dc443Ssdussud 		case 0 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5431f47dc443Ssdussud 			/* inactive */
5432f47dc443Ssdussud 			berRC = ber_scanf(ber, "b", &rValue);
5433f47dc443Ssdussud 			if (berRC != LBER_ERROR) {
5434f47dc443Ssdussud 				(acctResp->AcctUsableResp).more_info.
5435f47dc443Ssdussud 				    inactive = (rValue != 0) ? 1 : 0;
5436f47dc443Ssdussud 			}
5437f47dc443Ssdussud 			break;
5438f47dc443Ssdussud 
5439f47dc443Ssdussud 		case 1 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5440f47dc443Ssdussud 			/* reset */
5441f47dc443Ssdussud 			berRC = ber_scanf(ber, "b", &rValue);
5442f47dc443Ssdussud 			if (berRC != LBER_ERROR) {
5443f47dc443Ssdussud 				(acctResp->AcctUsableResp).more_info.reset
5444f47dc443Ssdussud 				    = (rValue != 0) ? 1 : 0;
5445f47dc443Ssdussud 			}
5446f47dc443Ssdussud 			break;
5447f47dc443Ssdussud 
5448f47dc443Ssdussud 		case 2 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5449f47dc443Ssdussud 			/* expired */
5450f47dc443Ssdussud 			berRC = ber_scanf(ber, "b", &rValue);
5451f47dc443Ssdussud 			if (berRC != LBER_ERROR) {
5452f47dc443Ssdussud 				(acctResp->AcctUsableResp).more_info.expired
5453f47dc443Ssdussud 				    = (rValue != 0) ? 1 : 0;
5454f47dc443Ssdussud 			}
5455f47dc443Ssdussud 			break;
5456f47dc443Ssdussud 
5457f47dc443Ssdussud 		case 3 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5458f47dc443Ssdussud 			/* remaining grace */
5459f47dc443Ssdussud 			berRC = ber_scanf(ber, "i", &rValue);
5460f47dc443Ssdussud 			if (berRC != LBER_ERROR) {
5461f47dc443Ssdussud 				(acctResp->AcctUsableResp).more_info.rem_grace
5462f47dc443Ssdussud 				    = rValue;
5463f47dc443Ssdussud 			}
5464f47dc443Ssdussud 			break;
5465f47dc443Ssdussud 
5466f47dc443Ssdussud 		case 4 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
5467f47dc443Ssdussud 			/* seconds before unlock */
5468f47dc443Ssdussud 			berRC = ber_scanf(ber, "i", &rValue);
5469f47dc443Ssdussud 			if (berRC != LBER_ERROR) {
5470f47dc443Ssdussud 				(acctResp->AcctUsableResp).more_info.
5471f47dc443Ssdussud 				    sec_b4_unlock = rValue;
5472f47dc443Ssdussud 			}
5473f47dc443Ssdussud 			break;
5474f47dc443Ssdussud 
5475f47dc443Ssdussud 		default :
5476f47dc443Ssdussud 			(void) sprintf(errstr,
5477f47dc443Ssdussud 			    gettext("invalid reason tag 0x%x"), rTag);
5478f47dc443Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
5479f47dc443Ssdussud 			rc = NS_LDAP_INTERNAL;
5480f47dc443Ssdussud 			break;
5481f47dc443Ssdussud 		}
5482f47dc443Ssdussud 		if (berRC == LBER_ERROR) {
5483f47dc443Ssdussud 			(void) sprintf(errstr,
5484f47dc443Ssdussud 			    gettext("error 0x%x decoding value for "
5485f47dc443Ssdussud 			    "tag 0x%x"), berRC, rTag);
5486f47dc443Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
5487f47dc443Ssdussud 			rc = NS_LDAP_INTERNAL;
5488f47dc443Ssdussud 		}
5489f47dc443Ssdussud 		if (rc != NS_LDAP_SUCCESS) {
5490f47dc443Ssdussud 			/* exit the for loop */
5491f47dc443Ssdussud 			break;
5492f47dc443Ssdussud 		}
5493f47dc443Ssdussud 	}
5494f47dc443Ssdussud 
5495f47dc443Ssdussud 	return (rc);
5496f47dc443Ssdussud }
5497f47dc443Ssdussud 
5498f47dc443Ssdussud /*
5499f47dc443Ssdussud  * int get_old_acct_opt_more_info(BerElement *ber,
5500f47dc443Ssdussud  *     AcctUsableResponse_t *acctResp)
5501f47dc443Ssdussud  *
5502f47dc443Ssdussud  * Decode the optional more_info data from an Account Management control
5503f47dc443Ssdussud  * response, when the account is not usable and when code style is from LDAP
5504f47dc443Ssdussud  * server 5.2p4 (see below comments for parse_acct_cont_resp_msg() to get more
5505f47dc443Ssdussud  * details on coding styles and ASN1 description).
5506f47dc443Ssdussud  *
5507f47dc443Ssdussud  * Expected BER encoding: titi}
550847789246Svv  *	+t: tag is 2
550947789246Svv  *	+i: contains num of remaining grace, 0 means no grace
551047789246Svv  *	+t: tag is 3
551147789246Svv  *	+i: contains num of seconds before auto-unlock. -1 means acct is locked
551247789246Svv  *		forever (i.e. until reset)
5513f47dc443Ssdussud  *
5514f47dc443Ssdussud  * Asumptions:
5515f47dc443Ssdussud  * - ber is a valid BER element
5516f47dc443Ssdussud  * - acctResp is initialized for the fields in its AcctUsableResp.more_info
5517f47dc443Ssdussud  *   structure
5518f47dc443Ssdussud  */
5519f47dc443Ssdussud static int
get_old_acct_opt_more_info(ber_tag_t tag,BerElement * ber,AcctUsableResponse_t * acctResp)5520f47dc443Ssdussud get_old_acct_opt_more_info(ber_tag_t tag, BerElement *ber,
5521f47dc443Ssdussud     AcctUsableResponse_t *acctResp)
5522f47dc443Ssdussud {
5523f47dc443Ssdussud 	int		rc = NS_LDAP_SUCCESS;
5524f47dc443Ssdussud 	char		errstr[MAXERROR];
5525f47dc443Ssdussud 	ber_len_t	len;
5526f47dc443Ssdussud 	int		rem_grace, sec_b4_unlock;
5527f47dc443Ssdussud 
5528f47dc443Ssdussud 	switch (tag) {
5529f47dc443Ssdussud 	case 2:
5530f47dc443Ssdussud 		/* decode and maybe 3 is following */
5531f47dc443Ssdussud 		if ((tag = ber_scanf(ber, "i", &rem_grace)) == LBER_ERROR) {
5532f47dc443Ssdussud 			(void) sprintf(errstr, gettext("Can not get "
5533f47dc443Ssdussud 			    "rem_grace"));
5534f47dc443Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
5535f47dc443Ssdussud 			rc = NS_LDAP_INTERNAL;
5536f47dc443Ssdussud 			break;
5537f47dc443Ssdussud 		}
5538f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.rem_grace = rem_grace;
5539f47dc443Ssdussud 
5540f47dc443Ssdussud 		if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5541f47dc443Ssdussud 			/* this is a success case, break to exit */
5542f47dc443Ssdussud 			(void) sprintf(errstr, gettext("No more "
5543f47dc443Ssdussud 			    "optional data"));
5544f47dc443Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
5545f47dc443Ssdussud 			break;
5546f47dc443Ssdussud 		}
5547f47dc443Ssdussud 
5548f47dc443Ssdussud 		if (tag == 3) {
5549f47dc443Ssdussud 			if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
5550f47dc443Ssdussud 				(void) sprintf(errstr,
5551f47dc443Ssdussud 				    gettext("Can not get sec_b4_unlock "
5552f47dc443Ssdussud 				    "- 1st case"));
5553f47dc443Ssdussud 				syslog(LOG_DEBUG, "libsldap: %s", errstr);
5554f47dc443Ssdussud 				rc = NS_LDAP_INTERNAL;
5555f47dc443Ssdussud 				break;
5556f47dc443Ssdussud 			}
5557f47dc443Ssdussud 			(acctResp->AcctUsableResp).more_info.sec_b4_unlock =
5558f47dc443Ssdussud 			    sec_b4_unlock;
5559f47dc443Ssdussud 		} else { /* unknown tag */
5560f47dc443Ssdussud 			(void) sprintf(errstr, gettext("Unknown tag "
5561f47dc443Ssdussud 			    "- 1st case"));
5562f47dc443Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
5563f47dc443Ssdussud 			rc = NS_LDAP_INTERNAL;
5564f47dc443Ssdussud 			break;
5565f47dc443Ssdussud 		}
5566f47dc443Ssdussud 		break;
5567f47dc443Ssdussud 
5568f47dc443Ssdussud 	case 3:
5569f47dc443Ssdussud 		if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
5570f47dc443Ssdussud 			(void) sprintf(errstr, gettext("Can not get "
5571f47dc443Ssdussud 			    "sec_b4_unlock - 2nd case"));
5572f47dc443Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
5573f47dc443Ssdussud 			rc = NS_LDAP_INTERNAL;
5574f47dc443Ssdussud 			break;
5575f47dc443Ssdussud 		}
5576f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.sec_b4_unlock =
5577f47dc443Ssdussud 		    sec_b4_unlock;
5578f47dc443Ssdussud 		break;
5579f47dc443Ssdussud 
5580f47dc443Ssdussud 	default: /* unknown tag */
5581f47dc443Ssdussud 		(void) sprintf(errstr, gettext("Unknown tag - 2nd case"));
5582f47dc443Ssdussud 		syslog(LOG_DEBUG, "libsldap: %s", errstr);
5583f47dc443Ssdussud 		rc = NS_LDAP_INTERNAL;
5584f47dc443Ssdussud 		break;
5585f47dc443Ssdussud 	}
5586f47dc443Ssdussud 
5587f47dc443Ssdussud 	return (rc);
5588f47dc443Ssdussud }
5589f47dc443Ssdussud 
5590f47dc443Ssdussud /*
5591f47dc443Ssdussud  * **** This function needs to be moved to libldap library ****
5592f47dc443Ssdussud  * parse_acct_cont_resp_msg() parses the message received by server according to
5593f47dc443Ssdussud  * following format (ASN1 notation):
5594f47dc443Ssdussud  *
5595f47dc443Ssdussud  *	ACCOUNT_USABLE_RESPONSE::= CHOICE {
5596f47dc443Ssdussud  *		is_available		[0] INTEGER,
5597f47dc443Ssdussud  *				** seconds before expiration **
5598f47dc443Ssdussud  *		is_not_available	[1] more_info
5599f47dc443Ssdussud  *	}
5600f47dc443Ssdussud  *	more_info::= SEQUENCE {
5601f47dc443Ssdussud  *		inactive		[0] BOOLEAN DEFAULT FALSE,
5602f47dc443Ssdussud  *		reset			[1] BOOLEAN DEFAULT FALSE,
5603f47dc443Ssdussud  *		expired			[2] BOOLEAN DEFAULT FALSE,
5604f47dc443Ssdussud  *		remaining_grace		[3] INTEGER OPTIONAL,
5605f47dc443Ssdussud  *		seconds_before_unlock	[4] INTEGER OPTIONAL
5606f47dc443Ssdussud  *	}
560747789246Svv  */
5608f47dc443Ssdussud /*
5609f47dc443Ssdussud  * #define used to make the difference between coding style as done
5610f47dc443Ssdussud  * by LDAP server 5.2p4 and newer LDAP servers. There are 4 values:
5611f47dc443Ssdussud  * - DS52p4_USABLE: 5.2p4 coding style, account is usable
5612f47dc443Ssdussud  * - DS52p4_NOT_USABLE: 5.2p4 coding style, account is not usable
5613f47dc443Ssdussud  * - NEW_USABLE: newer LDAP servers coding style, account is usable
5614f47dc443Ssdussud  * - NEW_NOT_USABLE: newer LDAP servers coding style, account is not usable
5615f47dc443Ssdussud  *
5616f47dc443Ssdussud  * An account would be considered not usable if for instance:
5617f47dc443Ssdussud  * - it's been made inactive in the LDAP server
5618f47dc443Ssdussud  * - or its password was reset in the LDAP server database
5619f47dc443Ssdussud  * - or its password expired
5620f47dc443Ssdussud  * - or the account has been locked, possibly forever
5621f47dc443Ssdussud  */
5622f47dc443Ssdussud #define	DS52p4_USABLE		0x00
5623f47dc443Ssdussud #define	DS52p4_NOT_USABLE	0x01
5624f47dc443Ssdussud #define	NEW_USABLE		0x00 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE
5625f47dc443Ssdussud #define	NEW_NOT_USABLE		0x01 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED
562647789246Svv static int
parse_acct_cont_resp_msg(LDAPControl ** ectrls,AcctUsableResponse_t * acctResp)562747789246Svv parse_acct_cont_resp_msg(LDAPControl **ectrls, AcctUsableResponse_t *acctResp)
562847789246Svv {
5629f47dc443Ssdussud 	int		rc = NS_LDAP_SUCCESS;
563047789246Svv 	BerElement	*ber;
56318f0bb794SToomas Soome 	ber_tag_t	tag;
563247789246Svv 	ber_len_t	len;
5633f47dc443Ssdussud 	int		i;
5634f47dc443Ssdussud 	char		errstr[MAXERROR];
5635f47dc443Ssdussud 	/* used for any coding style when account is usable */
5636f47dc443Ssdussud 	int		seconds_before_expiry;
5637f47dc443Ssdussud 	/* used for 5.2p4 coding style when account is not usable */
5638f47dc443Ssdussud 	int		inactive, reset, expired;
5639f47dc443Ssdussud 
5640f47dc443Ssdussud 	if (ectrls == NULL) {
5641f47dc443Ssdussud 		(void) sprintf(errstr, gettext("Invalid ectrls parameter"));
5642f47dc443Ssdussud 		syslog(LOG_DEBUG, "libsldap: %s", errstr);
564347789246Svv 		return (NS_LDAP_INVALID_PARAM);
5644f47dc443Ssdussud 	}
564547789246Svv 
564647789246Svv 	for (i = 0; ectrls[i] != NULL; i++) {
564747789246Svv 		if (strcmp(ectrls[i]->ldctl_oid, NS_LDAP_ACCOUNT_USABLE_CONTROL)
5648f47dc443Ssdussud 		    == 0) {
5649f47dc443Ssdussud 			break;
5650f47dc443Ssdussud 		}
5651f47dc443Ssdussud 	}
5652f47dc443Ssdussud 
5653f47dc443Ssdussud 	if (ectrls[i] == NULL) {
5654f47dc443Ssdussud 		/* Ldap control is not found */
5655f47dc443Ssdussud 		(void) sprintf(errstr, gettext("Account Usable Control "
5656f47dc443Ssdussud 		    "not found"));
5657f47dc443Ssdussud 		syslog(LOG_DEBUG, "libsldap: %s", errstr);
5658f47dc443Ssdussud 		return (NS_LDAP_NOTFOUND);
565947789246Svv 	}
566047789246Svv 
5661f47dc443Ssdussud 	/* Allocate a BER element from the control value and parse it. */
566247789246Svv 	if ((ber = ber_init(&ectrls[i]->ldctl_value)) == NULL)
566347789246Svv 		return (NS_LDAP_MEMORY);
566447789246Svv 
566547789246Svv 	if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
566647789246Svv 		/* Ldap decoding error */
5667f47dc443Ssdussud 		(void) sprintf(errstr, gettext("Error decoding 1st tag"));
5668f47dc443Ssdussud 		syslog(LOG_DEBUG, "libsldap: %s", errstr);
566947789246Svv 		ber_free(ber, 1);
567047789246Svv 		return (NS_LDAP_INTERNAL);
567147789246Svv 	}
567247789246Svv 
567347789246Svv 	switch (tag) {
5674f47dc443Ssdussud 	case DS52p4_USABLE:
5675f47dc443Ssdussud 	case NEW_USABLE:
5676f47dc443Ssdussud 		acctResp->choice = 0;
5677f47dc443Ssdussud 		if (ber_scanf(ber, "i", &seconds_before_expiry)
5678f47dc443Ssdussud 		    == LBER_ERROR) {
5679f47dc443Ssdussud 			/* Ldap decoding error */
5680f47dc443Ssdussud 			(void) sprintf(errstr, gettext("Can not get "
5681f47dc443Ssdussud 			    "seconds_before_expiry"));
5682f47dc443Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
5683f47dc443Ssdussud 			rc = NS_LDAP_INTERNAL;
568447789246Svv 			break;
5685f47dc443Ssdussud 		}
5686f47dc443Ssdussud 		/* ber_scanf() succeeded */
5687f47dc443Ssdussud 		(acctResp->AcctUsableResp).seconds_before_expiry =
5688f47dc443Ssdussud 		    seconds_before_expiry;
5689f47dc443Ssdussud 		break;
569047789246Svv 
5691f47dc443Ssdussud 	case DS52p4_NOT_USABLE:
5692f47dc443Ssdussud 		acctResp->choice = 1;
5693f47dc443Ssdussud 		if (ber_scanf(ber, "{bbb", &inactive, &reset, &expired)
5694f47dc443Ssdussud 		    == LBER_ERROR) {
5695f47dc443Ssdussud 			/* Ldap decoding error */
5696f47dc443Ssdussud 			(void) sprintf(errstr, gettext("Can not get "
5697f47dc443Ssdussud 			    "inactive/reset/expired"));
5698f47dc443Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
5699f47dc443Ssdussud 			rc = NS_LDAP_INTERNAL;
5700f47dc443Ssdussud 			break;
5701f47dc443Ssdussud 		}
5702f47dc443Ssdussud 		/* ber_scanf() succeeded */
5703f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.inactive =
5704f47dc443Ssdussud 		    ((inactive == 0) ? 0 : 1);
5705f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.reset =
5706f47dc443Ssdussud 		    ((reset == 0) ? 0 : 1);
5707f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.expired =
5708f47dc443Ssdussud 		    ((expired == 0) ? 0 : 1);
5709f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.rem_grace = 0;
5710f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
5711f47dc443Ssdussud 
5712f47dc443Ssdussud 		if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
5713f47dc443Ssdussud 			/* this is a success case, break to exit */
5714f47dc443Ssdussud 			(void) sprintf(errstr, gettext("No optional data"));
5715f47dc443Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
5716f47dc443Ssdussud 			break;
5717f47dc443Ssdussud 		}
571847789246Svv 
5719f47dc443Ssdussud 		/*
5720f47dc443Ssdussud 		 * Look at what optional more_info BER element is/are
5721f47dc443Ssdussud 		 * left to be decoded.
5722f47dc443Ssdussud 		 */
5723f47dc443Ssdussud 		rc = get_old_acct_opt_more_info(tag, ber, acctResp);
5724f47dc443Ssdussud 		break;
5725f47dc443Ssdussud 
5726f47dc443Ssdussud 	case NEW_NOT_USABLE:
5727f47dc443Ssdussud 		acctResp->choice = 1;
5728f47dc443Ssdussud 		/*
5729f47dc443Ssdussud 		 * Recent LDAP servers won't code more_info data for default
5730f47dc443Ssdussud 		 * values (see above comments on ASN1 description for what
5731f47dc443Ssdussud 		 * fields have default values & what fields are optional).
5732f47dc443Ssdussud 		 */
5733f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.inactive = 0;
5734f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.reset = 0;
5735f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.expired = 0;
5736f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.rem_grace = 0;
5737f47dc443Ssdussud 		(acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
5738f47dc443Ssdussud 
5739f47dc443Ssdussud 		if (len == 0) {
5740f47dc443Ssdussud 			/*
5741f47dc443Ssdussud 			 * Nothing else to decode; this is valid and we
5742f47dc443Ssdussud 			 * use default values set above.
5743f47dc443Ssdussud 			 */
5744f47dc443Ssdussud 			(void) sprintf(errstr, gettext("more_info is "
5745f47dc443Ssdussud 			    "empty, using default values"));
5746f47dc443Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
574747789246Svv 			break;
5748f47dc443Ssdussud 		}
5749f47dc443Ssdussud 
5750f47dc443Ssdussud 		/*
5751f47dc443Ssdussud 		 * Look at what more_info BER element is/are left to
5752f47dc443Ssdussud 		 * be decoded.
5753f47dc443Ssdussud 		 */
5754f47dc443Ssdussud 		rc = get_new_acct_more_info(ber, acctResp);
5755f47dc443Ssdussud 		break;
5756f47dc443Ssdussud 
5757f47dc443Ssdussud 	default:
5758f47dc443Ssdussud 		(void) sprintf(errstr, gettext("unknwon coding style "
5759f47dc443Ssdussud 		    "(tag: 0x%x)"), tag);
5760f47dc443Ssdussud 		syslog(LOG_DEBUG, "libsldap: %s", errstr);
5761f47dc443Ssdussud 		rc = NS_LDAP_INTERNAL;
5762f47dc443Ssdussud 		break;
576347789246Svv 	}
576447789246Svv 
576547789246Svv 	ber_free(ber, 1);
5766f47dc443Ssdussud 	return (rc);
576747789246Svv }
576847789246Svv 
576947789246Svv /*
5770e1dd0a2fSth  * internal function for __ns_ldap_getAcctMgmt()
577147789246Svv  */
5772e1dd0a2fSth static int
getAcctMgmt(const char * user,AcctUsableResponse_t * acctResp,ns_conn_user_t * conn_user)5773e1dd0a2fSth getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp,
57748f0bb794SToomas Soome     ns_conn_user_t *conn_user)
577547789246Svv {
577647789246Svv 	int		scope, rc;
577747789246Svv 	ns_ldap_cookie_t	*cookie;
577847789246Svv 	ns_ldap_search_desc_t	**sdlist = NULL;
577947789246Svv 	ns_ldap_search_desc_t	*dptr;
578047789246Svv 	ns_ldap_error_t		*error = NULL;
578147789246Svv 	char			**dns = NULL;
578247789246Svv 	char		service[] = "shadow";
578347789246Svv 
578447789246Svv 	if (user == NULL || acctResp == NULL)
578547789246Svv 		return (NS_LDAP_INVALID_PARAM);
578647789246Svv 
578747789246Svv 	/* Initialize State machine cookie */
578847789246Svv 	cookie = init_search_state_machine();
578947789246Svv 	if (cookie == NULL)
579047789246Svv 		return (NS_LDAP_MEMORY);
5791e1dd0a2fSth 	cookie->conn_user = conn_user;
579247789246Svv 
579347789246Svv 	/* see if need to follow referrals */
579447789246Svv 	rc = __s_api_toFollowReferrals(0,
5795699bceb8Smj 	    &cookie->followRef, &error);
579647789246Svv 	if (rc != NS_LDAP_SUCCESS) {
579747789246Svv 		(void) __ns_ldap_freeError(&error);
579847789246Svv 		goto out;
579947789246Svv 	}
580047789246Svv 
580147789246Svv 	/* get the service descriptor - or create a default one */
580247789246Svv 	rc = __s_api_get_SSD_from_SSDtoUse_service(service,
5803699bceb8Smj 	    &sdlist, &error);
580447789246Svv 	if (rc != NS_LDAP_SUCCESS) {
580547789246Svv 		(void) __ns_ldap_freeError(&error);
580647789246Svv 		goto out;
580747789246Svv 	}
580847789246Svv 
580947789246Svv 	if (sdlist == NULL) {
581047789246Svv 		/* Create default service Desc */
581147789246Svv 		sdlist = (ns_ldap_search_desc_t **)calloc(2,
5812699bceb8Smj 		    sizeof (ns_ldap_search_desc_t *));
581347789246Svv 		if (sdlist == NULL) {
581447789246Svv 			rc = NS_LDAP_MEMORY;
581547789246Svv 			goto out;
581647789246Svv 		}
581747789246Svv 		dptr = (ns_ldap_search_desc_t *)
5818699bceb8Smj 		    calloc(1, sizeof (ns_ldap_search_desc_t));
581947789246Svv 		if (dptr == NULL) {
582047789246Svv 			free(sdlist);
582147789246Svv 			rc = NS_LDAP_MEMORY;
582247789246Svv 			goto out;
582347789246Svv 		}
582447789246Svv 		sdlist[0] = dptr;
582547789246Svv 
582647789246Svv 		/* default base */
582747789246Svv 		rc = __s_api_getDNs(&dns, service, &cookie->errorp);
582847789246Svv 		if (rc != NS_LDAP_SUCCESS) {
582947789246Svv 			if (dns) {
583047789246Svv 				__s_api_free2dArray(dns);
583147789246Svv 				dns = NULL;
583247789246Svv 			}
583347789246Svv 			(void) __ns_ldap_freeError(&(cookie->errorp));
583447789246Svv 			cookie->errorp = NULL;
583547789246Svv 			goto out;
583647789246Svv 		}
583747789246Svv 		dptr->basedn = strdup(dns[0]);
583847789246Svv 		if (dptr->basedn == NULL) {
583947789246Svv 			free(sdlist);
584047789246Svv 			free(dptr);
584147789246Svv 			if (dns) {
584247789246Svv 				__s_api_free2dArray(dns);
584347789246Svv 				dns = NULL;
584447789246Svv 			}
584547789246Svv 			rc = NS_LDAP_MEMORY;
584647789246Svv 			goto out;
584747789246Svv 		}
584847789246Svv 		__s_api_free2dArray(dns);
584947789246Svv 		dns = NULL;
585047789246Svv 
585147789246Svv 		/* default scope */
585247789246Svv 		scope = 0;
585347789246Svv 		rc = __s_api_getSearchScope(&scope, &cookie->errorp);
585447789246Svv 		dptr->scope = scope;
585547789246Svv 	}
585647789246Svv 
585747789246Svv 	cookie->sdlist = sdlist;
585847789246Svv 
585947789246Svv 	cookie->service = strdup(service);
586047789246Svv 	if (cookie->service == NULL) {
586147789246Svv 		rc = NS_LDAP_MEMORY;
586247789246Svv 		goto out;
586347789246Svv 	}
586447789246Svv 
586547789246Svv 	/* search for entries for this particular uid */
58660ababfc6SToomas Soome 	(void) asprintf(&cookie->i_filter, "(uid=%s)", user);
586747789246Svv 	if (cookie->i_filter == NULL) {
586847789246Svv 		rc = NS_LDAP_MEMORY;
586947789246Svv 		goto out;
587047789246Svv 	}
587147789246Svv 
587247789246Svv 	/* create the control request */
587347789246Svv 	if ((rc = setup_acctmgmt_params(cookie)) != NS_LDAP_SUCCESS)
587447789246Svv 		goto out;
587547789246Svv 
587647789246Svv 	/* Process search */
587747789246Svv 	rc = search_state_machine(cookie, GET_ACCT_MGMT_INFO, 0);
587847789246Svv 
587947789246Svv 	/* Copy results back to user */
588047789246Svv 	rc = cookie->err_rc;
588147789246Svv 	if (rc != NS_LDAP_SUCCESS)
588247789246Svv 			(void) __ns_ldap_freeError(&(cookie->errorp));
588347789246Svv 
588447789246Svv 	if (cookie->result == NULL)
588547789246Svv 			goto out;
588647789246Svv 
588747789246Svv 	if ((rc = parse_acct_cont_resp_msg(cookie->resultctrl, acctResp))
5888699bceb8Smj 	    != NS_LDAP_SUCCESS)
588947789246Svv 		goto out;
589047789246Svv 
589147789246Svv 	rc = NS_LDAP_SUCCESS;
589247789246Svv 
589347789246Svv out:
589447789246Svv 	delete_search_cookie(cookie);
589547789246Svv 
589647789246Svv 	return (rc);
589747789246Svv }
5898e1dd0a2fSth 
5899e1dd0a2fSth /*
5900e1dd0a2fSth  * __ns_ldap_getAcctMgmt() is called from pam account management stack
5901e1dd0a2fSth  * for retrieving accounting information of users with no user password -
5902e1dd0a2fSth  * eg. rlogin, rsh, etc. This function uses the account management control
5903e1dd0a2fSth  * request to do a search on the server for the user in question. The
5904e1dd0a2fSth  * response control returned from the server is got from the cookie.
5905e1dd0a2fSth  * Input params: username of whose account mgmt information is to be got
5906e1dd0a2fSth  *		 pointer to hold the parsed account management information
5907e1dd0a2fSth  * Return values: NS_LDAP_SUCCESS on success or appropriate error
5908e1dd0a2fSth  *		code on failure
5909e1dd0a2fSth  */
5910e1dd0a2fSth int
__ns_ldap_getAcctMgmt(const char * user,AcctUsableResponse_t * acctResp)5911e1dd0a2fSth __ns_ldap_getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp)
5912e1dd0a2fSth {
5913e1dd0a2fSth 	ns_conn_user_t	*cu = NULL;
5914e1dd0a2fSth 	int		try_cnt = 0;
5915e1dd0a2fSth 	int		rc = NS_LDAP_SUCCESS;
5916e1dd0a2fSth 	ns_ldap_error_t	*error = NULL;
5917e1dd0a2fSth 
5918e1dd0a2fSth 	for (;;) {
5919e1dd0a2fSth 		if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
5920e1dd0a2fSth 		    &try_cnt, &rc, &error) == 0)
5921e1dd0a2fSth 			break;
5922e1dd0a2fSth 		rc = getAcctMgmt(user, acctResp, cu);
5923e1dd0a2fSth 	}
5924e1dd0a2fSth 	return (rc);
5925e1dd0a2fSth }
5926