xref: /onnv-gate/usr/src/lib/libsldap/common/ns_reads.c (revision 12758:996c46be076f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52031Svt115884  * Common Development and Distribution License (the "License").
62031Svt115884  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*12758SJulian.Pullen@Sun.COM  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate  */
240Sstevel@tonic-gate 
250Sstevel@tonic-gate #include <stdio.h>
260Sstevel@tonic-gate #include <sys/types.h>
270Sstevel@tonic-gate #include <stdlib.h>
280Sstevel@tonic-gate #include <libintl.h>
290Sstevel@tonic-gate #include <ctype.h>
300Sstevel@tonic-gate #include <syslog.h>
310Sstevel@tonic-gate #include <sys/stat.h>
320Sstevel@tonic-gate #include <fcntl.h>
330Sstevel@tonic-gate #include <unistd.h>
340Sstevel@tonic-gate #include <string.h>
350Sstevel@tonic-gate #include <strings.h>
369576SJulian.Pullen@Sun.COM #include <priv.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include "ns_sldap.h"
390Sstevel@tonic-gate #include "ns_internal.h"
400Sstevel@tonic-gate #include "ns_cache_door.h"
416842Sth160488 #include "ns_connmgmt.h"
420Sstevel@tonic-gate 
430Sstevel@tonic-gate #define	_NIS_FILTER	"nisdomain=*"
440Sstevel@tonic-gate #define	_NIS_DOMAIN	"nisdomain"
450Sstevel@tonic-gate static const char *nis_domain_attrs[] = {
460Sstevel@tonic-gate 	_NIS_DOMAIN,
470Sstevel@tonic-gate 	(char *)NULL
480Sstevel@tonic-gate };
490Sstevel@tonic-gate 
500Sstevel@tonic-gate static int validate_filter(ns_ldap_cookie_t *cookie);
510Sstevel@tonic-gate 
520Sstevel@tonic-gate void
__ns_ldap_freeEntry(ns_ldap_entry_t * ep)530Sstevel@tonic-gate __ns_ldap_freeEntry(ns_ldap_entry_t *ep)
540Sstevel@tonic-gate {
550Sstevel@tonic-gate 	int		j, k = 0;
560Sstevel@tonic-gate 
570Sstevel@tonic-gate 	if (ep == NULL)
580Sstevel@tonic-gate 		return;
590Sstevel@tonic-gate 
600Sstevel@tonic-gate 	if (ep->attr_pair == NULL) {
610Sstevel@tonic-gate 		free(ep);
620Sstevel@tonic-gate 		return;
630Sstevel@tonic-gate 	}
640Sstevel@tonic-gate 	for (j = 0; j < ep->attr_count; j++) {
650Sstevel@tonic-gate 		if (ep->attr_pair[j] == NULL)
660Sstevel@tonic-gate 			continue;
670Sstevel@tonic-gate 		if (ep->attr_pair[j]->attrname)
680Sstevel@tonic-gate 			free(ep->attr_pair[j]->attrname);
690Sstevel@tonic-gate 		if (ep->attr_pair[j]->attrvalue) {
700Sstevel@tonic-gate 			for (k = 0; (k < ep->attr_pair[j]->value_count) &&
714765Smj162486 			    (ep->attr_pair[j]->attrvalue[k]); k++) {
720Sstevel@tonic-gate 				free(ep->attr_pair[j]->attrvalue[k]);
730Sstevel@tonic-gate 			}
740Sstevel@tonic-gate 			free(ep->attr_pair[j]->attrvalue);
750Sstevel@tonic-gate 		}
760Sstevel@tonic-gate 		free(ep->attr_pair[j]);
770Sstevel@tonic-gate 	}
780Sstevel@tonic-gate 	free(ep->attr_pair);
790Sstevel@tonic-gate 	free(ep);
800Sstevel@tonic-gate }
810Sstevel@tonic-gate 
820Sstevel@tonic-gate static void
_freeControlList(LDAPControl *** ctrls)830Sstevel@tonic-gate _freeControlList(LDAPControl ***ctrls)
840Sstevel@tonic-gate {
850Sstevel@tonic-gate 	LDAPControl	**ctrl;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	if (ctrls == NULL || *ctrls == NULL)
880Sstevel@tonic-gate 		return;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	for (ctrl = *ctrls; *ctrl != NULL; ctrl++)
910Sstevel@tonic-gate 		ldap_control_free(*ctrl);
920Sstevel@tonic-gate 	free(*ctrls);
930Sstevel@tonic-gate 	*ctrls = NULL;
940Sstevel@tonic-gate }
950Sstevel@tonic-gate /*
960Sstevel@tonic-gate  * Convert attribute type in a RDN that has an attribute mapping to the
970Sstevel@tonic-gate  * original mappped type.
980Sstevel@tonic-gate  * e.g.
990Sstevel@tonic-gate  * cn<->cn-st and iphostnumber<->iphostnumber-st
1000Sstevel@tonic-gate  * cn-st=aaa+iphostnumber-st=10.10.01.01
1010Sstevel@tonic-gate  * is mapped to
1020Sstevel@tonic-gate  * cn=aaa+iphostnumber=10.10.01.01
1030Sstevel@tonic-gate  *
1040Sstevel@tonic-gate  * Input - service: e.g. hosts, passwd etc.
1050Sstevel@tonic-gate  *         rdn: RDN
1060Sstevel@tonic-gate  * Return: NULL - No attribute mapping in the RDN
1070Sstevel@tonic-gate  *         Non-NULL - The attribute type(s) in the RDN are mapped and
1080Sstevel@tonic-gate  *                    the memory is allocated for the new rdn.
1090Sstevel@tonic-gate  *
1100Sstevel@tonic-gate  */
1110Sstevel@tonic-gate static char *
_cvtRDN(const char * service,const char * rdn)1120Sstevel@tonic-gate _cvtRDN(const char *service, const char *rdn) {
1130Sstevel@tonic-gate 	char	**attrs, **mapped_attrs, **mapp, *type, *value, *attr;
1140Sstevel@tonic-gate 	char	*new_rdn = NULL;
1150Sstevel@tonic-gate 	int	nAttr = 0, i, attr_mapped, len = 0;
1160Sstevel@tonic-gate 
1170Sstevel@tonic-gate 	/* Break down "type=value\0" pairs. Assume RDN is normalized */
1180Sstevel@tonic-gate 	if ((attrs = ldap_explode_rdn(rdn, 0)) == NULL)
1190Sstevel@tonic-gate 		return (NULL);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	for (nAttr = 0; attrs[nAttr] != NULL; nAttr++);
1220Sstevel@tonic-gate 
1230Sstevel@tonic-gate 	if ((mapped_attrs = (char **)calloc(nAttr, sizeof (char *))) == NULL) {
1240Sstevel@tonic-gate 		ldap_value_free(attrs);
1250Sstevel@tonic-gate 		return (NULL);
1260Sstevel@tonic-gate 	}
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate 	attr_mapped = 0;
1290Sstevel@tonic-gate 	for (i = 0; i < nAttr; i++) {
1300Sstevel@tonic-gate 		/* Parse type=value pair */
1310Sstevel@tonic-gate 		if ((type = strtok_r(attrs[i], "=", &value)) == NULL ||
1320Sstevel@tonic-gate 					value == NULL)
1330Sstevel@tonic-gate 			goto cleanup;
1340Sstevel@tonic-gate 		/* Reverse map: e.g. cn-sm -> cn */
1350Sstevel@tonic-gate 		mapp = __ns_ldap_getOrigAttribute(service, type);
1360Sstevel@tonic-gate 		if (mapp != NULL && mapp[0] != NULL) {
1370Sstevel@tonic-gate 			/* The attribute mapping is found */
1380Sstevel@tonic-gate 			type = mapp[0];
1390Sstevel@tonic-gate 			attr_mapped = 1;
1400Sstevel@tonic-gate 
1410Sstevel@tonic-gate 			/* "type=value\0" */
1420Sstevel@tonic-gate 			len = strlen(type) + strlen(value) + 2;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 			/* Reconstruct type=value pair. A string is allocated */
1450Sstevel@tonic-gate 			if ((attr = (char *)calloc(1, len)) == NULL) {
1460Sstevel@tonic-gate 				__s_api_free2dArray(mapp);
1470Sstevel@tonic-gate 				goto cleanup;
1480Sstevel@tonic-gate 			}
1490Sstevel@tonic-gate 			(void) snprintf(attr, len, "%s=%s",
1500Sstevel@tonic-gate 						type, value);
1510Sstevel@tonic-gate 			mapped_attrs[i] = attr;
1520Sstevel@tonic-gate 		} else {
1530Sstevel@tonic-gate 			/*
1540Sstevel@tonic-gate 			 * No attribute mapping. attrs[i] is going to be copied
1550Sstevel@tonic-gate 			 * later. Restore "type\0value\0" back to
1560Sstevel@tonic-gate 			 * "type=value\0".
1570Sstevel@tonic-gate 			 */
1580Sstevel@tonic-gate 			type[strlen(type)] = '=';
1590Sstevel@tonic-gate 		}
1600Sstevel@tonic-gate 		__s_api_free2dArray(mapp);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 	if (attr_mapped == 0)
1630Sstevel@tonic-gate 		/* No attribute mapping. Don't bother to reconstruct RDN */
1640Sstevel@tonic-gate 		goto cleanup;
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	len = 0;
1670Sstevel@tonic-gate 	/* Reconstruct RDN from type=value pairs */
1680Sstevel@tonic-gate 	for (i = 0; i < nAttr; i++) {
1690Sstevel@tonic-gate 		if (mapped_attrs[i])
1700Sstevel@tonic-gate 			len += strlen(mapped_attrs[i]);
1710Sstevel@tonic-gate 		else
1720Sstevel@tonic-gate 			len += strlen(attrs[i]);
1730Sstevel@tonic-gate 		/* Add 1 for "+" */
1740Sstevel@tonic-gate 		len++;
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate 	if ((new_rdn = (char *)calloc(1, ++len)) == NULL)
1770Sstevel@tonic-gate 		goto cleanup;
1780Sstevel@tonic-gate 	for (i = 0; i < nAttr; i++) {
1790Sstevel@tonic-gate 		if (i > 0)
1800Sstevel@tonic-gate 			/* Add seperator */
1810Sstevel@tonic-gate 			(void) strlcat(new_rdn, "+", len);
1820Sstevel@tonic-gate 
1830Sstevel@tonic-gate 		if (mapped_attrs[i])
1840Sstevel@tonic-gate 			(void) strlcat(new_rdn, mapped_attrs[i], len);
1850Sstevel@tonic-gate 		else
1860Sstevel@tonic-gate 			(void) strlcat(new_rdn, attrs[i], len);
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	}
1890Sstevel@tonic-gate cleanup:
1900Sstevel@tonic-gate 	ldap_value_free(attrs);
1910Sstevel@tonic-gate 	if (mapped_attrs) {
1920Sstevel@tonic-gate 		if (attr_mapped) {
1930Sstevel@tonic-gate 			for (i = 0; i < nAttr; i++) {
1940Sstevel@tonic-gate 				if (mapped_attrs[i])
1950Sstevel@tonic-gate 					free(mapped_attrs[i]);
1960Sstevel@tonic-gate 			}
1970Sstevel@tonic-gate 		}
1980Sstevel@tonic-gate 		free(mapped_attrs);
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	return (new_rdn);
2020Sstevel@tonic-gate }
2030Sstevel@tonic-gate /*
2040Sstevel@tonic-gate  * Convert attribute type in a DN that has an attribute mapping to the
2050Sstevel@tonic-gate  * original mappped type.
2060Sstevel@tonic-gate  * e.g
2070Sstevel@tonic-gate  * The mappings are cn<->cn-sm, iphostnumber<->iphostnumber-sm
2080Sstevel@tonic-gate  *
2090Sstevel@tonic-gate  * dn: cn-sm=aaa+iphostnumber-sm=9.9.9.9,dc=central,dc=sun,dc=com
2100Sstevel@tonic-gate  * is converted to
2110Sstevel@tonic-gate  * dn: cn=aaa+iphostnumber=9.9.9.9,dc=central,dc=sun,dc=com
2120Sstevel@tonic-gate  *
2130Sstevel@tonic-gate  * Input - service: e.g. hosts, passwd etc.
2140Sstevel@tonic-gate  *         dn: the value of a distinguished name
2150Sstevel@tonic-gate  * Return - NULL: error
2160Sstevel@tonic-gate  *          non-NULL: A converted DN and the memory is allocated
2170Sstevel@tonic-gate  */
2180Sstevel@tonic-gate static char *
_cvtDN(const char * service,const char * dn)2190Sstevel@tonic-gate _cvtDN(const char *service, const char *dn) {
2200Sstevel@tonic-gate 	char	**mapped_rdns;
2210Sstevel@tonic-gate 	char	**rdns, *new_rdn, *new_dn = NULL;
2220Sstevel@tonic-gate 	int	nRdn = 0, i, len = 0, rdn_mapped;
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate 	if (service == NULL || dn == NULL)
2250Sstevel@tonic-gate 		return (NULL);
2260Sstevel@tonic-gate 
2270Sstevel@tonic-gate 	if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
2280Sstevel@tonic-gate 		return (NULL);
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	for (nRdn = 0; rdns[nRdn] != NULL; nRdn++);
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 	if ((mapped_rdns = (char **)calloc(nRdn, sizeof (char *))) == NULL) {
2330Sstevel@tonic-gate 		ldap_value_free(rdns);
2340Sstevel@tonic-gate 		return (NULL);
2350Sstevel@tonic-gate 	}
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 	rdn_mapped = 0;
2380Sstevel@tonic-gate 	/* Break down RDNs in a DN */
2390Sstevel@tonic-gate 	for (i = 0; i < nRdn; i++) {
2400Sstevel@tonic-gate 		if ((new_rdn = _cvtRDN(service, rdns[i])) != NULL) {
2410Sstevel@tonic-gate 			mapped_rdns[i] = new_rdn;
2420Sstevel@tonic-gate 			rdn_mapped = 1;
2430Sstevel@tonic-gate 		}
2440Sstevel@tonic-gate 	}
2450Sstevel@tonic-gate 	if (rdn_mapped == 0) {
2460Sstevel@tonic-gate 		/*
2470Sstevel@tonic-gate 		 * No RDN contains any attribute mapping.
2480Sstevel@tonic-gate 		 * Don't bother to reconstruct DN from RDN. Copy DN directly.
2490Sstevel@tonic-gate 		 */
2500Sstevel@tonic-gate 		new_dn = strdup(dn);
2510Sstevel@tonic-gate 		goto cleanup;
2520Sstevel@tonic-gate 	}
2530Sstevel@tonic-gate 	/*
2540Sstevel@tonic-gate 	 * Reconstruct dn from RDNs.
2550Sstevel@tonic-gate 	 * Calculate the length first.
2560Sstevel@tonic-gate 	 */
2570Sstevel@tonic-gate 	for (i = 0; i < nRdn; i++) {
2580Sstevel@tonic-gate 		if (mapped_rdns[i])
2590Sstevel@tonic-gate 			len += strlen(mapped_rdns[i]);
2600Sstevel@tonic-gate 		else
2610Sstevel@tonic-gate 			len += strlen(rdns[i]);
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 		/* add 1 for ',' */
2640Sstevel@tonic-gate 		len ++;
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 	if ((new_dn = (char *)calloc(1, ++len)) == NULL)
2670Sstevel@tonic-gate 		goto cleanup;
2680Sstevel@tonic-gate 	for (i = 0; i < nRdn; i++) {
2690Sstevel@tonic-gate 		if (i > 0)
2700Sstevel@tonic-gate 			/* Add seperator */
2710Sstevel@tonic-gate 			(void) strlcat(new_dn, ",", len);
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 		if (mapped_rdns[i])
2740Sstevel@tonic-gate 			(void) strlcat(new_dn, mapped_rdns[i], len);
2750Sstevel@tonic-gate 		else
2760Sstevel@tonic-gate 			(void) strlcat(new_dn, rdns[i], len);
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate cleanup:
2810Sstevel@tonic-gate 	ldap_value_free(rdns);
2820Sstevel@tonic-gate 	if (mapped_rdns) {
2830Sstevel@tonic-gate 		if (rdn_mapped) {
2840Sstevel@tonic-gate 			for (i = 0; i < nRdn; i++) {
2850Sstevel@tonic-gate 				if (mapped_rdns[i])
2860Sstevel@tonic-gate 					free(mapped_rdns[i]);
2870Sstevel@tonic-gate 			}
2880Sstevel@tonic-gate 		}
2890Sstevel@tonic-gate 		free(mapped_rdns);
2900Sstevel@tonic-gate 	}
2910Sstevel@tonic-gate 
2920Sstevel@tonic-gate 	return (new_dn);
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate /*
2950Sstevel@tonic-gate  * Convert a single ldap entry from a LDAPMessage
2960Sstevel@tonic-gate  * into an ns_ldap_entry structure.
2970Sstevel@tonic-gate  * Schema map the entry if specified in flags
2980Sstevel@tonic-gate  */
2990Sstevel@tonic-gate 
3000Sstevel@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)3010Sstevel@tonic-gate __s_api_cvtEntry(LDAP	*ld,
3020Sstevel@tonic-gate 	const char	*service,
3030Sstevel@tonic-gate 	LDAPMessage	*e,
3040Sstevel@tonic-gate 	int		flags,
3050Sstevel@tonic-gate 	ns_ldap_entry_t	**ret,
3060Sstevel@tonic-gate 	ns_ldap_error_t	**error)
3070Sstevel@tonic-gate {
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	ns_ldap_entry_t	*ep = NULL;
3100Sstevel@tonic-gate 	ns_ldap_attr_t	**ap = NULL;
3110Sstevel@tonic-gate 	BerElement	*ber;
3120Sstevel@tonic-gate 	char		*attr = NULL;
3130Sstevel@tonic-gate 	char		**vals = NULL;
3140Sstevel@tonic-gate 	char		**mapping;
3150Sstevel@tonic-gate 	char		*dn;
3160Sstevel@tonic-gate 	int		nAttrs = 0;
3170Sstevel@tonic-gate 	int		i, j, k = 0;
3180Sstevel@tonic-gate 	char		**gecos_mapping = NULL;
3190Sstevel@tonic-gate 	int		gecos_val_index[3] = { -1, -1, -1};
3200Sstevel@tonic-gate 	char		errstr[MAXERROR];
3210Sstevel@tonic-gate 	int		schema_mapping_existed = FALSE;
3220Sstevel@tonic-gate 	int		gecos_mapping_existed = FALSE;
3230Sstevel@tonic-gate 	int		gecos_attr_matched;
3240Sstevel@tonic-gate 	int		auto_service = FALSE;
3250Sstevel@tonic-gate 	int		rc = NS_LDAP_SUCCESS;
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	if (e == NULL || ret == NULL || error == NULL)
3280Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	*error = NULL;
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	ep = (ns_ldap_entry_t *)calloc(1, sizeof (ns_ldap_entry_t));
3330Sstevel@tonic-gate 	if (ep == NULL)
3340Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	if (service != NULL &&
3374765Smj162486 	    (strncasecmp(service, "auto_", 5) == 0 ||
3384765Smj162486 	    strcasecmp(service, "automount") == 0))
3390Sstevel@tonic-gate 		auto_service = TRUE;
3400Sstevel@tonic-gate 	/*
3410Sstevel@tonic-gate 	 * see if schema mapping existed for the given service
3420Sstevel@tonic-gate 	 */
3430Sstevel@tonic-gate 	mapping = __ns_ldap_getOrigAttribute(service,
3444765Smj162486 	    NS_HASH_SCHEMA_MAPPING_EXISTED);
3450Sstevel@tonic-gate 	if (mapping) {
3460Sstevel@tonic-gate 		schema_mapping_existed = TRUE;
3470Sstevel@tonic-gate 		__s_api_free2dArray(mapping);
3480Sstevel@tonic-gate 		mapping = NULL;
3490Sstevel@tonic-gate 	} else if (auto_service) {
3500Sstevel@tonic-gate 		/*
3510Sstevel@tonic-gate 		 * If service == auto_* and no
3520Sstevel@tonic-gate 		 * schema mapping found
3530Sstevel@tonic-gate 		 * then try automount
3540Sstevel@tonic-gate 		 * There is certain case that schema mapping exist
3550Sstevel@tonic-gate 		 * but __ns_ldap_getOrigAttribute(service,
3560Sstevel@tonic-gate 		 *	NS_HASH_SCHEMA_MAPPING_EXISTED);
3570Sstevel@tonic-gate 		 * returns NULL.
3580Sstevel@tonic-gate 		 * e.g.
3590Sstevel@tonic-gate 		 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
3600Sstevel@tonic-gate 		 * NS_LDAP_OBJECTCLASSMAP = automount:automountMap=MynisMap
3610Sstevel@tonic-gate 		 * NS_LDAP_OBJECTCLASSMAP = automount:automount=MynisObject
3620Sstevel@tonic-gate 		 *
3630Sstevel@tonic-gate 		 * Make a check for schema_mapping_existed here
3640Sstevel@tonic-gate 		 * so later on __s_api_convert_automountmapname won't be called
3650Sstevel@tonic-gate 		 * unnecessarily. It is also used for attribute mapping
3660Sstevel@tonic-gate 		 * and objectclass mapping.
3670Sstevel@tonic-gate 		 */
3680Sstevel@tonic-gate 		mapping = __ns_ldap_getOrigAttribute("automount",
3694765Smj162486 		    NS_HASH_SCHEMA_MAPPING_EXISTED);
3700Sstevel@tonic-gate 		if (mapping) {
3710Sstevel@tonic-gate 			schema_mapping_existed = TRUE;
3720Sstevel@tonic-gate 			__s_api_free2dArray(mapping);
3730Sstevel@tonic-gate 			mapping = NULL;
3740Sstevel@tonic-gate 		}
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate 	nAttrs = 1;  /* start with 1 for the DN attr */
3780Sstevel@tonic-gate 	for (attr = ldap_first_attribute(ld, e, &ber); attr != NULL;
3794765Smj162486 	    attr = ldap_next_attribute(ld, e, ber)) {
3800Sstevel@tonic-gate 		nAttrs++;
3810Sstevel@tonic-gate 		ldap_memfree(attr);
3820Sstevel@tonic-gate 		attr = NULL;
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate 	ber_free(ber, 0);
3850Sstevel@tonic-gate 	ber = NULL;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	ep->attr_count = nAttrs;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	/*
3900Sstevel@tonic-gate 	 * add 1 for "gecos" 1 to N attribute mapping,
3910Sstevel@tonic-gate 	 * just in case it is needed.
3920Sstevel@tonic-gate 	 * ep->attr_count will be updated later if that is true.
3930Sstevel@tonic-gate 	 */
3940Sstevel@tonic-gate 	ap = (ns_ldap_attr_t **)calloc(ep->attr_count + 1,
3954765Smj162486 	    sizeof (ns_ldap_attr_t *));
3960Sstevel@tonic-gate 	if (ap == NULL) {
3970Sstevel@tonic-gate 		__ns_ldap_freeEntry(ep);
3980Sstevel@tonic-gate 		ep = NULL;
3990Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
4000Sstevel@tonic-gate 	}
4010Sstevel@tonic-gate 	ep->attr_pair = ap;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	/* DN attribute */
4040Sstevel@tonic-gate 	dn = ldap_get_dn(ld, e);
4050Sstevel@tonic-gate 	ap[0] = (ns_ldap_attr_t *)calloc(1, sizeof (ns_ldap_attr_t));
4060Sstevel@tonic-gate 	if (ap[0] == NULL) {
4070Sstevel@tonic-gate 		ldap_memfree(dn);
4080Sstevel@tonic-gate 		dn = NULL;
4090Sstevel@tonic-gate 		__ns_ldap_freeEntry(ep);
4100Sstevel@tonic-gate 		ep = NULL;
4110Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	if ((ap[0]->attrname = strdup("dn")) == NULL) {
4150Sstevel@tonic-gate 		ldap_memfree(dn);
4160Sstevel@tonic-gate 		dn = NULL;
4170Sstevel@tonic-gate 		__ns_ldap_freeEntry(ep);
4180Sstevel@tonic-gate 		ep = NULL;
4190Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
4200Sstevel@tonic-gate 	}
4210Sstevel@tonic-gate 	ap[0]->value_count = 1;
4220Sstevel@tonic-gate 	if ((ap[0]->attrvalue = (char **)
4234765Smj162486 	    calloc(2, sizeof (char *))) == NULL) {
4240Sstevel@tonic-gate 		ldap_memfree(dn);
4250Sstevel@tonic-gate 		dn = NULL;
4260Sstevel@tonic-gate 		__ns_ldap_freeEntry(ep);
4270Sstevel@tonic-gate 		ep = NULL;
4280Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
4290Sstevel@tonic-gate 	}
4300Sstevel@tonic-gate 
431699Ssdussud 	if (schema_mapping_existed && ((flags & NS_LDAP_NOT_CVT_DN) == 0))
4320Sstevel@tonic-gate 		ap[0]->attrvalue[0] = _cvtDN(service, dn);
4330Sstevel@tonic-gate 	else
4340Sstevel@tonic-gate 		ap[0]->attrvalue[0] = strdup(dn);
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 	if (ap[0]->attrvalue[0] == NULL) {
4370Sstevel@tonic-gate 		ldap_memfree(dn);
4380Sstevel@tonic-gate 		dn = NULL;
4390Sstevel@tonic-gate 		__ns_ldap_freeEntry(ep);
4400Sstevel@tonic-gate 		ep = NULL;
4410Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
4420Sstevel@tonic-gate 	}
4430Sstevel@tonic-gate 	ldap_memfree(dn);
4440Sstevel@tonic-gate 	dn = NULL;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	if ((flags & NS_LDAP_NOMAP) == 0 && auto_service &&
4474765Smj162486 	    schema_mapping_existed) {
4480Sstevel@tonic-gate 		rc = __s_api_convert_automountmapname(service,
4494765Smj162486 		    &ap[0]->attrvalue[0],
4504765Smj162486 		    error);
4510Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
4520Sstevel@tonic-gate 			__ns_ldap_freeEntry(ep);
4530Sstevel@tonic-gate 			ep = NULL;
4540Sstevel@tonic-gate 			return (rc);
4550Sstevel@tonic-gate 		}
4560Sstevel@tonic-gate 	}
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/* other attributes */
4590Sstevel@tonic-gate 	for (attr = ldap_first_attribute(ld, e, &ber), j = 1;
4604765Smj162486 	    attr != NULL && j != nAttrs;
4614765Smj162486 	    attr = ldap_next_attribute(ld, e, ber), j++) {
4624765Smj162486 		/* allocate new attr name */
4634765Smj162486 
4644765Smj162486 		if ((ap[j] = (ns_ldap_attr_t *)
4654765Smj162486 		    calloc(1, sizeof (ns_ldap_attr_t))) == NULL) {
4664765Smj162486 			ber_free(ber, 0);
4674765Smj162486 			ber = NULL;
4684765Smj162486 			__ns_ldap_freeEntry(ep);
4694765Smj162486 			ep = NULL;
4704765Smj162486 			if (gecos_mapping)
4714765Smj162486 				__s_api_free2dArray(gecos_mapping);
4724765Smj162486 			gecos_mapping = NULL;
4734765Smj162486 			return (NS_LDAP_MEMORY);
4740Sstevel@tonic-gate 		}
4754765Smj162486 
4764765Smj162486 		if ((flags & NS_LDAP_NOMAP) || schema_mapping_existed == FALSE)
4774765Smj162486 			mapping = NULL;
4784765Smj162486 		else
4794765Smj162486 			mapping = __ns_ldap_getOrigAttribute(service, attr);
4804765Smj162486 
4814765Smj162486 		if (mapping == NULL && auto_service &&
4824765Smj162486 		    schema_mapping_existed && (flags & NS_LDAP_NOMAP) == 0)
4830Sstevel@tonic-gate 			/*
4844765Smj162486 			 * if service == auto_* and no schema mapping found
4854765Smj162486 			 * and schema_mapping_existed is TRUE and NS_LDAP_NOMAP
4864765Smj162486 			 * is not set then try automount e.g.
4874765Smj162486 			 * NS_LDAP_ATTRIBUTEMAP = automount:automountMapName=AAA
4880Sstevel@tonic-gate 			 */
4894765Smj162486 			mapping = __ns_ldap_getOrigAttribute("automount",
4904765Smj162486 			    attr);
4914765Smj162486 
4924765Smj162486 		if (mapping == NULL) {
4934765Smj162486 			if ((ap[j]->attrname = strdup(attr)) == NULL) {
4940Sstevel@tonic-gate 				ber_free(ber, 0);
4950Sstevel@tonic-gate 				ber = NULL;
4960Sstevel@tonic-gate 				__ns_ldap_freeEntry(ep);
4970Sstevel@tonic-gate 				ep = NULL;
4984765Smj162486 				if (gecos_mapping)
4994765Smj162486 					__s_api_free2dArray(gecos_mapping);
5000Sstevel@tonic-gate 				gecos_mapping = NULL;
5014765Smj162486 				return (NS_LDAP_MEMORY);
5020Sstevel@tonic-gate 			}
5030Sstevel@tonic-gate 		} else {
5044765Smj162486 			/*
5054765Smj162486 			 * for "gecos" 1 to N mapping,
5064765Smj162486 			 * do not remove the mapped attribute,
5074765Smj162486 			 * just create a new gecos attribute
5084765Smj162486 			 * and append it to the end of the attribute list
5094765Smj162486 			 */
5104765Smj162486 			if (strcasecmp(mapping[0], "gecos") == 0) {
5114765Smj162486 				ap[j]->attrname = strdup(attr);
5124765Smj162486 				gecos_mapping_existed = TRUE;
5134765Smj162486 			} else
5144765Smj162486 				ap[j]->attrname = strdup(mapping[0]);
5154765Smj162486 
5164765Smj162486 			if (ap[j]->attrname == NULL) {
5170Sstevel@tonic-gate 				ber_free(ber, 0);
5180Sstevel@tonic-gate 				ber = NULL;
5190Sstevel@tonic-gate 				__ns_ldap_freeEntry(ep);
5200Sstevel@tonic-gate 				ep = NULL;
5210Sstevel@tonic-gate 				if (gecos_mapping)
5220Sstevel@tonic-gate 					__s_api_free2dArray(gecos_mapping);
5230Sstevel@tonic-gate 				gecos_mapping = NULL;
5240Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
5250Sstevel@tonic-gate 			}
5264765Smj162486 			/*
5274765Smj162486 			 * 1 to N attribute mapping processing
5284765Smj162486 			 * is only done for "gecos"
5294765Smj162486 			 */
5304765Smj162486 
5314765Smj162486 			if (strcasecmp(mapping[0], "gecos") == 0) {
5324765Smj162486 				/*
5334765Smj162486 				 * get attribute mapping for "gecos",
5344765Smj162486 				 * need to know the number and order of the
5354765Smj162486 				 * mapped attributes
5364765Smj162486 				 */
5374765Smj162486 				if (gecos_mapping == NULL) {
5384765Smj162486 					gecos_mapping =
5394765Smj162486 					    __ns_ldap_getMappedAttributes(
5404765Smj162486 					    service, mapping[0]);
5414765Smj162486 					if (gecos_mapping == NULL ||
5424765Smj162486 					    gecos_mapping[0] == NULL) {
5434765Smj162486 						/*
5444765Smj162486 						 * this should never happens,
5454765Smj162486 						 * syslog the error
5464765Smj162486 						 */
5474765Smj162486 						(void) sprintf(errstr,
5484765Smj162486 						    gettext(
5494765Smj162486 						    "Attribute mapping "
5504765Smj162486 						    "inconsistency "
5514765Smj162486 						    "found for attributes "
5524765Smj162486 						    "'%s' and '%s'."),
5534765Smj162486 						    mapping[0], attr);
5544765Smj162486 						syslog(LOG_ERR, "libsldap: %s",
5554765Smj162486 						    errstr);
5564765Smj162486 
5574765Smj162486 						ber_free(ber, 0);
5584765Smj162486 						ber = NULL;
5594765Smj162486 						__ns_ldap_freeEntry(ep);
5604765Smj162486 						ep = NULL;
5614765Smj162486 						__s_api_free2dArray(mapping);
5624765Smj162486 						mapping = NULL;
5634765Smj162486 						if (gecos_mapping)
5644765Smj162486 							__s_api_free2dArray(
5654765Smj162486 							    gecos_mapping);
5664765Smj162486 						gecos_mapping = NULL;
5674765Smj162486 						return (NS_LDAP_INTERNAL);
5684765Smj162486 					}
5694765Smj162486 				}
5704765Smj162486 
5714765Smj162486 				/*
5724765Smj162486 				 * is this attribute the 1st, 2nd, or
5734765Smj162486 				 * 3rd attr in the mapping list?
5744765Smj162486 				 */
5754765Smj162486 				gecos_attr_matched = FALSE;
5764765Smj162486 				for (i = 0; i < 3 && gecos_mapping[i]; i++) {
5774765Smj162486 					if (gecos_mapping[i] &&
5784765Smj162486 					    strcasecmp(gecos_mapping[i],
5794765Smj162486 					    attr) == 0) {
5804765Smj162486 						gecos_val_index[i] = j;
5814765Smj162486 						gecos_attr_matched = TRUE;
5824765Smj162486 						break;
5834765Smj162486 					}
5844765Smj162486 				}
5854765Smj162486 				if (gecos_attr_matched == FALSE) {
5864765Smj162486 					/*
5874765Smj162486 					 * Not match found.
5884765Smj162486 					 * This should never happens,
5894765Smj162486 					 * syslog the error
5904765Smj162486 					 */
5914765Smj162486 					(void) sprintf(errstr,
5924765Smj162486 					    gettext(
5934765Smj162486 					    "Attribute mapping "
5944765Smj162486 					    "inconsistency "
5954765Smj162486 					    "found for attributes "
5964765Smj162486 					    "'%s' and '%s'."),
5974765Smj162486 					    mapping[0], attr);
5984765Smj162486 					syslog(LOG_ERR, "libsldap: %s", errstr);
5994765Smj162486 
6004765Smj162486 					ber_free(ber, 0);
6014765Smj162486 					ber = NULL;
6024765Smj162486 					__ns_ldap_freeEntry(ep);
6034765Smj162486 					ep = NULL;
6044765Smj162486 					__s_api_free2dArray(mapping);
6054765Smj162486 					mapping = NULL;
6060Sstevel@tonic-gate 					__s_api_free2dArray(gecos_mapping);
6074765Smj162486 					gecos_mapping = NULL;
6084765Smj162486 					return (NS_LDAP_INTERNAL);
6094765Smj162486 				}
6100Sstevel@tonic-gate 			}
6114765Smj162486 			__s_api_free2dArray(mapping);
6124765Smj162486 			mapping = NULL;
6130Sstevel@tonic-gate 		}
6140Sstevel@tonic-gate 
6154765Smj162486 		if ((vals = ldap_get_values(ld, e, attr)) != NULL) {
6164765Smj162486 
6174765Smj162486 			if ((ap[j]->value_count =
6184765Smj162486 			    ldap_count_values(vals)) == 0) {
6194765Smj162486 				ldap_value_free(vals);
6204765Smj162486 				vals = NULL;
6214765Smj162486 				continue;
6224765Smj162486 			} else {
6234765Smj162486 				ap[j]->attrvalue = (char **)
6244765Smj162486 				    calloc(ap[j]->value_count+1,
6254765Smj162486 				    sizeof (char *));
6264765Smj162486 				if (ap[j]->attrvalue == NULL) {
6274765Smj162486 					ber_free(ber, 0);
6284765Smj162486 					ber = NULL;
6294765Smj162486 					__ns_ldap_freeEntry(ep);
6304765Smj162486 					ep = NULL;
6314765Smj162486 					if (gecos_mapping)
6324765Smj162486 						__s_api_free2dArray(
6334765Smj162486 						    gecos_mapping);
6344765Smj162486 					gecos_mapping = NULL;
6354765Smj162486 					return (NS_LDAP_MEMORY);
6364765Smj162486 				}
6374765Smj162486 			}
6384765Smj162486 
6394765Smj162486 			/* map object classes if necessary */
6404765Smj162486 			if ((flags & NS_LDAP_NOMAP) == 0 &&
6414765Smj162486 			    schema_mapping_existed && ap[j]->attrname &&
6424765Smj162486 			    strcasecmp(ap[j]->attrname, "objectclass") == 0) {
6434765Smj162486 				for (k = 0; k < ap[j]->value_count; k++) {
6444765Smj162486 					mapping =
6454765Smj162486 					    __ns_ldap_getOrigObjectClass(
6464765Smj162486 					    service, vals[k]);
6474765Smj162486 
6484765Smj162486 					if (mapping == NULL && auto_service)
6494765Smj162486 						/*
6504765Smj162486 						 * if service == auto_* and no
6514765Smj162486 						 * schema mapping found
6524765Smj162486 						 * then try automount
6534765Smj162486 						 */
6544790Ssdussud 					mapping =
6554790Ssdussud 					    __ns_ldap_getOrigObjectClass(
6564790Ssdussud 					    "automount", vals[k]);
6574765Smj162486 
6584765Smj162486 					if (mapping == NULL) {
6594765Smj162486 						ap[j]->attrvalue[k] =
6604765Smj162486 						    strdup(vals[k]);
6614765Smj162486 					} else {
6624765Smj162486 						ap[j]->attrvalue[k] =
6634765Smj162486 						    strdup(mapping[0]);
6644765Smj162486 						__s_api_free2dArray(mapping);
6654765Smj162486 						mapping = NULL;
6664765Smj162486 					}
6674765Smj162486 					if (ap[j]->attrvalue[k] == NULL) {
6684765Smj162486 						ber_free(ber, 0);
6694765Smj162486 						ber = NULL;
6704765Smj162486 						__ns_ldap_freeEntry(ep);
6714765Smj162486 						ep = NULL;
6724765Smj162486 						if (gecos_mapping)
6734765Smj162486 							__s_api_free2dArray(
6744765Smj162486 							    gecos_mapping);
6754765Smj162486 						gecos_mapping = NULL;
6764765Smj162486 						return (NS_LDAP_MEMORY);
6774765Smj162486 					}
6784765Smj162486 				}
6794765Smj162486 			} else {
6804765Smj162486 				for (k = 0; k < ap[j]->value_count; k++) {
6814765Smj162486 					if ((ap[j]->attrvalue[k] =
6824765Smj162486 					    strdup(vals[k])) == NULL) {
6834765Smj162486 						ber_free(ber, 0);
6844765Smj162486 						ber = NULL;
6854765Smj162486 						__ns_ldap_freeEntry(ep);
6864765Smj162486 						ep = NULL;
6874765Smj162486 						if (gecos_mapping)
6884765Smj162486 							__s_api_free2dArray(
6894765Smj162486 							    gecos_mapping);
6904765Smj162486 						gecos_mapping = NULL;
6914765Smj162486 						return (NS_LDAP_MEMORY);
6924765Smj162486 					}
6934765Smj162486 				}
6944765Smj162486 			}
6954765Smj162486 
6964765Smj162486 			ap[j]->attrvalue[k] = NULL;
6974765Smj162486 			ldap_value_free(vals);
6984765Smj162486 			vals = NULL;
6994765Smj162486 		}
7004765Smj162486 
7014765Smj162486 		ldap_memfree(attr);
7024765Smj162486 		attr = NULL;
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	ber_free(ber, 0);
7060Sstevel@tonic-gate 	ber = NULL;
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	if (gecos_mapping) {
7090Sstevel@tonic-gate 		__s_api_free2dArray(gecos_mapping);
7100Sstevel@tonic-gate 		gecos_mapping = NULL;
7110Sstevel@tonic-gate 	}
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	/* special processing for gecos 1 to up to 3 attribute mapping */
7140Sstevel@tonic-gate 	if (schema_mapping_existed && gecos_mapping_existed) {
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 		int	f = -1;
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 		for (i = 0; i < 3; i++) {
7190Sstevel@tonic-gate 			k = gecos_val_index[i];
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 			/*
7220Sstevel@tonic-gate 			 * f is the index of the first returned
7230Sstevel@tonic-gate 			 * attribute which "gecos" attribute mapped to
7240Sstevel@tonic-gate 			 */
7250Sstevel@tonic-gate 			if (k != -1 && f == -1)
7260Sstevel@tonic-gate 				f = k;
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 			if (k != -1 && ap[k]->value_count > 0 &&
7294765Smj162486 			    ap[k]->attrvalue[0] &&
7304765Smj162486 			    strlen(ap[k]->attrvalue[0]) > 0) {
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 				if (k == f) {
7330Sstevel@tonic-gate 					/*
7340Sstevel@tonic-gate 					 * Create and fill in the last reserved
7350Sstevel@tonic-gate 					 * ap with the data from the "gecos"
7360Sstevel@tonic-gate 					 * mapping attributes
7370Sstevel@tonic-gate 					 */
7380Sstevel@tonic-gate 					ap[nAttrs] = (ns_ldap_attr_t *)
7394765Smj162486 					    calloc(1,
7404765Smj162486 					    sizeof (ns_ldap_attr_t));
7410Sstevel@tonic-gate 					if (ap[nAttrs] == NULL) {
7420Sstevel@tonic-gate 						__ns_ldap_freeEntry(ep);
7430Sstevel@tonic-gate 						ep = NULL;
7440Sstevel@tonic-gate 						return (NS_LDAP_MEMORY);
7450Sstevel@tonic-gate 					}
7460Sstevel@tonic-gate 					ap[nAttrs]->attrvalue = (char **)calloc(
7474765Smj162486 					    2, sizeof (char *));
7480Sstevel@tonic-gate 					if (ap[nAttrs]->attrvalue == NULL) {
7490Sstevel@tonic-gate 						__ns_ldap_freeEntry(ep);
7500Sstevel@tonic-gate 						ep = NULL;
7510Sstevel@tonic-gate 						return (NS_LDAP_MEMORY);
7520Sstevel@tonic-gate 					}
7530Sstevel@tonic-gate 					/* add 1 more for a possible "," */
7540Sstevel@tonic-gate 					ap[nAttrs]->attrvalue[0] =
7554765Smj162486 					    (char *)calloc(
7564765Smj162486 					    strlen(ap[f]->attrvalue[0]) +
7574765Smj162486 					    2, 1);
7580Sstevel@tonic-gate 					if (ap[nAttrs]->attrvalue[0] == NULL) {
7590Sstevel@tonic-gate 						__ns_ldap_freeEntry(ep);
7600Sstevel@tonic-gate 						ep = NULL;
7610Sstevel@tonic-gate 						return (NS_LDAP_MEMORY);
7620Sstevel@tonic-gate 					}
7630Sstevel@tonic-gate 					(void) strcpy(ap[nAttrs]->attrvalue[0],
7644765Smj162486 					    ap[f]->attrvalue[0]);
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate 					ap[nAttrs]->attrname = strdup("gecos");
7670Sstevel@tonic-gate 					if (ap[nAttrs]->attrname == NULL) {
7680Sstevel@tonic-gate 						__ns_ldap_freeEntry(ep);
7690Sstevel@tonic-gate 						ep = NULL;
7700Sstevel@tonic-gate 						return (NS_LDAP_MEMORY);
7710Sstevel@tonic-gate 					}
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 					ap[nAttrs]->value_count = 1;
7740Sstevel@tonic-gate 					ep->attr_count = nAttrs + 1;
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 				} else {
7774288Ssdussud 					char	*tmp = NULL;
7784288Ssdussud 
7794288Ssdussud 					/*
7804288Ssdussud 					 * realloc to add "," and
7814288Ssdussud 					 * ap[k]->attrvalue[0]
7824288Ssdussud 					 */
7834288Ssdussud 					tmp = (char *)realloc(
7844765Smj162486 					    ap[nAttrs]->attrvalue[0],
7854765Smj162486 					    strlen(ap[nAttrs]->
7864765Smj162486 					    attrvalue[0]) +
7874765Smj162486 					    strlen(ap[k]->
7884765Smj162486 					    attrvalue[0]) + 2);
7894288Ssdussud 					if (tmp == NULL) {
7900Sstevel@tonic-gate 						__ns_ldap_freeEntry(ep);
7910Sstevel@tonic-gate 						ep = NULL;
7920Sstevel@tonic-gate 						return (NS_LDAP_MEMORY);
7930Sstevel@tonic-gate 					}
7944288Ssdussud 					ap[nAttrs]->attrvalue[0] = tmp;
7954288Ssdussud 					(void) strcat(ap[nAttrs]->attrvalue[0],
7964765Smj162486 					    ",");
7970Sstevel@tonic-gate 					(void) strcat(ap[nAttrs]->attrvalue[0],
7984765Smj162486 					    ap[k]->attrvalue[0]);
7990Sstevel@tonic-gate 				}
8000Sstevel@tonic-gate 			}
8010Sstevel@tonic-gate 		}
8020Sstevel@tonic-gate 	}
8030Sstevel@tonic-gate 
8040Sstevel@tonic-gate 	*ret = ep;
8050Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
8060Sstevel@tonic-gate }
8070Sstevel@tonic-gate 
8080Sstevel@tonic-gate static int
__s_api_getEntry(ns_ldap_cookie_t * cookie)8090Sstevel@tonic-gate __s_api_getEntry(ns_ldap_cookie_t *cookie)
8100Sstevel@tonic-gate {
8110Sstevel@tonic-gate 	ns_ldap_entry_t	*curEntry = NULL;
8120Sstevel@tonic-gate 	int		ret;
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate #ifdef DEBUG
8150Sstevel@tonic-gate 	(void) fprintf(stderr, "__s_api_getEntry START\n");
8160Sstevel@tonic-gate #endif
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	if (cookie->resultMsg == NULL) {
8190Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
8200Sstevel@tonic-gate 	}
8210Sstevel@tonic-gate 	ret = __s_api_cvtEntry(cookie->conn->ld, cookie->service,
8224765Smj162486 	    cookie->resultMsg, cookie->i_flags,
8234765Smj162486 	    &curEntry, &cookie->errorp);
8240Sstevel@tonic-gate 	if (ret != NS_LDAP_SUCCESS) {
8250Sstevel@tonic-gate 		return (ret);
8260Sstevel@tonic-gate 	}
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	if (cookie->result == NULL) {
8290Sstevel@tonic-gate 		cookie->result = (ns_ldap_result_t *)
8304765Smj162486 		    calloc(1, sizeof (ns_ldap_result_t));
8310Sstevel@tonic-gate 		if (cookie->result == NULL) {
8320Sstevel@tonic-gate 			__ns_ldap_freeEntry(curEntry);
8330Sstevel@tonic-gate 			curEntry = NULL;
8340Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
8350Sstevel@tonic-gate 		}
8360Sstevel@tonic-gate 		cookie->result->entry = curEntry;
8370Sstevel@tonic-gate 		cookie->nextEntry = curEntry;
8380Sstevel@tonic-gate 	} else {
8390Sstevel@tonic-gate 		cookie->nextEntry->next = curEntry;
8400Sstevel@tonic-gate 		cookie->nextEntry = curEntry;
8410Sstevel@tonic-gate 	}
8420Sstevel@tonic-gate 	cookie->result->entries_count++;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
8450Sstevel@tonic-gate }
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate static int
__s_api_get_cachemgr_data(const char * type,const char * from,char ** to)8480Sstevel@tonic-gate __s_api_get_cachemgr_data(const char *type,
8490Sstevel@tonic-gate 		const char *from, char **to)
8500Sstevel@tonic-gate {
8510Sstevel@tonic-gate 	union {
8520Sstevel@tonic-gate 		ldap_data_t	s_d;
8530Sstevel@tonic-gate 		char		s_b[DOORBUFFERSIZE];
8540Sstevel@tonic-gate 	} space;
8550Sstevel@tonic-gate 	ldap_data_t	*sptr;
8560Sstevel@tonic-gate 	int		ndata;
8570Sstevel@tonic-gate 	int		adata;
8580Sstevel@tonic-gate 	int		rc;
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate #ifdef DEBUG
8610Sstevel@tonic-gate 	(void) fprintf(stderr, "__s_api_get_cachemgr_data START\n");
8620Sstevel@tonic-gate #endif
8636842Sth160488 	/*
8646842Sth160488 	 * We are not going to perform DN to domain mapping
8656842Sth160488 	 * in the Standalone mode
8666842Sth160488 	 */
8676842Sth160488 	if (__s_api_isStandalone()) {
8686842Sth160488 		return (-1);
8696842Sth160488 	}
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	if (from == NULL || from[0] == '\0' || to == NULL)
8720Sstevel@tonic-gate 		return (-1);
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 	*to = NULL;
8750Sstevel@tonic-gate 	(void) memset(space.s_b, 0, DOORBUFFERSIZE);
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	space.s_d.ldap_call.ldap_callnumber = GETCACHE;
8780Sstevel@tonic-gate 	(void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
8794765Smj162486 	    DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
8804765Smj162486 	    "%s%s%s",
8814765Smj162486 	    type,
8824765Smj162486 	    DOORLINESEP,
8834765Smj162486 	    from);
8840Sstevel@tonic-gate 	ndata = sizeof (space);
8850Sstevel@tonic-gate 	adata = sizeof (ldap_call_t) +
8864765Smj162486 	    strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
8870Sstevel@tonic-gate 	sptr = &space.s_d;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
8906842Sth160488 	if (rc != NS_CACHE_SUCCESS)
8910Sstevel@tonic-gate 		return (-1);
8920Sstevel@tonic-gate 	else
8930Sstevel@tonic-gate 		*to = strdup(sptr->ldap_ret.ldap_u.buff);
8940Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
8950Sstevel@tonic-gate }
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate static int
__s_api_set_cachemgr_data(const char * type,const char * from,const char * to)8980Sstevel@tonic-gate __s_api_set_cachemgr_data(const char *type,
8990Sstevel@tonic-gate 		const char *from, const char *to)
9000Sstevel@tonic-gate {
9010Sstevel@tonic-gate 	union {
9020Sstevel@tonic-gate 		ldap_data_t	s_d;
9030Sstevel@tonic-gate 		char		s_b[DOORBUFFERSIZE];
9040Sstevel@tonic-gate 	} space;
9050Sstevel@tonic-gate 	ldap_data_t	*sptr;
9060Sstevel@tonic-gate 	int		ndata;
9070Sstevel@tonic-gate 	int		adata;
9080Sstevel@tonic-gate 	int		rc;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate #ifdef DEBUG
9110Sstevel@tonic-gate 	(void) fprintf(stderr, "__s_api_set_cachemgr_data START\n");
9120Sstevel@tonic-gate #endif
9136842Sth160488 	/*
9146842Sth160488 	 * We are not going to perform DN to domain mapping
9156842Sth160488 	 * in the Standalone mode
9166842Sth160488 	 */
9176842Sth160488 	if (__s_api_isStandalone()) {
9186842Sth160488 		return (-1);
9196842Sth160488 	}
9200Sstevel@tonic-gate 
9210Sstevel@tonic-gate 	if ((from == NULL) || (from[0] == '\0') ||
9224765Smj162486 	    (to == NULL) || (to[0] == '\0'))
9230Sstevel@tonic-gate 		return (-1);
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	(void) memset(space.s_b, 0, DOORBUFFERSIZE);
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate 	space.s_d.ldap_call.ldap_callnumber = SETCACHE;
9280Sstevel@tonic-gate 	(void) snprintf(space.s_d.ldap_call.ldap_u.domainname,
9294765Smj162486 	    DOORBUFFERSIZE - sizeof (space.s_d.ldap_call.ldap_callnumber),
9304765Smj162486 	    "%s%s%s%s%s",
9314765Smj162486 	    type,
9324765Smj162486 	    DOORLINESEP,
9334765Smj162486 	    from,
9344765Smj162486 	    DOORLINESEP,
9354765Smj162486 	    to);
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	ndata = sizeof (space);
9380Sstevel@tonic-gate 	adata = sizeof (ldap_call_t) +
9394765Smj162486 	    strlen(space.s_d.ldap_call.ldap_u.domainname) + 1;
9400Sstevel@tonic-gate 	sptr = &space.s_d;
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate 	rc = __ns_ldap_trydoorcall(&sptr, &ndata, &adata);
9436842Sth160488 	if (rc != NS_CACHE_SUCCESS)
9440Sstevel@tonic-gate 		return (-1);
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 
9500Sstevel@tonic-gate static char *
__s_api_remove_rdn_space(char * rdn)9510Sstevel@tonic-gate __s_api_remove_rdn_space(char *rdn)
9520Sstevel@tonic-gate {
9530Sstevel@tonic-gate 	char	*tf, *tl, *vf, *vl, *eqsign;
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	/* if no space(s) to remove, return */
9560Sstevel@tonic-gate 	if (strchr(rdn, SPACETOK) == NULL)
9570Sstevel@tonic-gate 		return (rdn);
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 	/* if no '=' separator, return */
9600Sstevel@tonic-gate 	eqsign = strchr(rdn, '=');
9610Sstevel@tonic-gate 	if (eqsign == NULL)
9620Sstevel@tonic-gate 		return (rdn);
9630Sstevel@tonic-gate 
9640Sstevel@tonic-gate 	tf = rdn;
9650Sstevel@tonic-gate 	tl = eqsign - 1;
9660Sstevel@tonic-gate 	vf = eqsign + 1;
9670Sstevel@tonic-gate 	vl = rdn + strlen(rdn) - 1;
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	/* now two strings, type and value */
9700Sstevel@tonic-gate 	*eqsign = '\0';
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	/* remove type's leading spaces */
9730Sstevel@tonic-gate 	while (tf < tl && *tf == SPACETOK)
9740Sstevel@tonic-gate 		tf++;
9750Sstevel@tonic-gate 	/* remove type's trailing spaces */
9760Sstevel@tonic-gate 	while (tf < tl && *tl == SPACETOK)
9770Sstevel@tonic-gate 		tl--;
9780Sstevel@tonic-gate 	/* add '=' separator back */
9790Sstevel@tonic-gate 	*(++tl) = '=';
9800Sstevel@tonic-gate 	/* remove value's leading spaces */
9810Sstevel@tonic-gate 	while (vf < vl && *vf == SPACETOK)
9820Sstevel@tonic-gate 		vf++;
9830Sstevel@tonic-gate 	/* remove value's trailing spaces */
9840Sstevel@tonic-gate 	while (vf < vl && *vl == SPACETOK)
9850Sstevel@tonic-gate 		*vl-- = '\0';
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	/* move value up if necessary */
9880Sstevel@tonic-gate 	if (vf != tl + 1)
9890Sstevel@tonic-gate 		(void) strcpy(tl + 1, vf);
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	return (tf);
9920Sstevel@tonic-gate }
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate static
9950Sstevel@tonic-gate ns_ldap_cookie_t *
init_search_state_machine()9960Sstevel@tonic-gate init_search_state_machine()
9970Sstevel@tonic-gate {
9980Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie;
9990Sstevel@tonic-gate 	ns_config_t		*cfg;
10000Sstevel@tonic-gate 
10010Sstevel@tonic-gate 	cookie = (ns_ldap_cookie_t *)calloc(1, sizeof (ns_ldap_cookie_t));
10020Sstevel@tonic-gate 	if (cookie == NULL)
10030Sstevel@tonic-gate 		return (NULL);
10040Sstevel@tonic-gate 	cookie->state = INIT;
10050Sstevel@tonic-gate 	/* assign other state variables */
10060Sstevel@tonic-gate 	cfg = __s_api_loadrefresh_config();
10070Sstevel@tonic-gate 	cookie->connectionId = -1;
10080Sstevel@tonic-gate 	if (cfg == NULL ||
10094765Smj162486 	    cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_ptype == NS_UNKNOWN) {
10100Sstevel@tonic-gate 		cookie->search_timeout.tv_sec = NS_DEFAULT_SEARCH_TIMEOUT;
10110Sstevel@tonic-gate 	} else {
10120Sstevel@tonic-gate 		cookie->search_timeout.tv_sec =
10134765Smj162486 		    cfg->paramList[NS_LDAP_SEARCH_TIME_P].ns_i;
10140Sstevel@tonic-gate 	}
10150Sstevel@tonic-gate 	if (cfg != NULL)
10160Sstevel@tonic-gate 		__s_api_release_config(cfg);
10170Sstevel@tonic-gate 	cookie->search_timeout.tv_usec = 0;
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	return (cookie);
10200Sstevel@tonic-gate }
10210Sstevel@tonic-gate 
10220Sstevel@tonic-gate static void
delete_search_cookie(ns_ldap_cookie_t * cookie)10230Sstevel@tonic-gate delete_search_cookie(ns_ldap_cookie_t *cookie)
10240Sstevel@tonic-gate {
10250Sstevel@tonic-gate 	if (cookie == NULL)
10260Sstevel@tonic-gate 		return;
10270Sstevel@tonic-gate 	if (cookie->connectionId > -1)
10280Sstevel@tonic-gate 		DropConnection(cookie->connectionId, cookie->i_flags);
10290Sstevel@tonic-gate 	if (cookie->filter)
10300Sstevel@tonic-gate 		free(cookie->filter);
10310Sstevel@tonic-gate 	if (cookie->i_filter)
10320Sstevel@tonic-gate 		free(cookie->i_filter);
10330Sstevel@tonic-gate 	if (cookie->service)
10340Sstevel@tonic-gate 		free(cookie->service);
10350Sstevel@tonic-gate 	if (cookie->sdlist)
10360Sstevel@tonic-gate 		(void) __ns_ldap_freeSearchDescriptors(&(cookie->sdlist));
10370Sstevel@tonic-gate 	if (cookie->result)
10380Sstevel@tonic-gate 		(void) __ns_ldap_freeResult(&cookie->result);
10390Sstevel@tonic-gate 	if (cookie->attribute)
10400Sstevel@tonic-gate 		__s_api_free2dArray(cookie->attribute);
10410Sstevel@tonic-gate 	if (cookie->errorp)
10420Sstevel@tonic-gate 		(void) __ns_ldap_freeError(&cookie->errorp);
10430Sstevel@tonic-gate 	if (cookie->reflist)
10440Sstevel@tonic-gate 		__s_api_deleteRefInfo(cookie->reflist);
10450Sstevel@tonic-gate 	if (cookie->basedn)
10460Sstevel@tonic-gate 		free(cookie->basedn);
10470Sstevel@tonic-gate 	if (cookie->ctrlCookie)
10480Sstevel@tonic-gate 		ber_bvfree(cookie->ctrlCookie);
10490Sstevel@tonic-gate 	_freeControlList(&cookie->p_serverctrls);
10501179Svv149972 	if (cookie->resultctrl)
10511179Svv149972 		ldap_controls_free(cookie->resultctrl);
10520Sstevel@tonic-gate 	free(cookie);
10530Sstevel@tonic-gate }
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate static int
get_mapped_filter(ns_ldap_cookie_t * cookie,char ** new_filter)10560Sstevel@tonic-gate get_mapped_filter(ns_ldap_cookie_t *cookie, char **new_filter)
10570Sstevel@tonic-gate {
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	typedef	struct	filter_mapping_info {
10600Sstevel@tonic-gate 		char	oc_or_attr;
10610Sstevel@tonic-gate 		char	*name_start;
10620Sstevel@tonic-gate 		char	*name_end;
10630Sstevel@tonic-gate 		char	*veq_pos;
10640Sstevel@tonic-gate 		char	*from_name;
10650Sstevel@tonic-gate 		char	*to_name;
10660Sstevel@tonic-gate 		char	**mapping;
10670Sstevel@tonic-gate 	} filter_mapping_info_t;
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	char			*c, *last_copied;
10700Sstevel@tonic-gate 	char			*filter_c, *filter_c_next;
10710Sstevel@tonic-gate 	char			*key, *tail, *head;
10720Sstevel@tonic-gate 	char			errstr[MAXERROR];
10730Sstevel@tonic-gate 	int			num_eq = 0, num_veq = 0;
10740Sstevel@tonic-gate 	int			in_quote = FALSE;
10752031Svt115884 	int			is_value = FALSE;
10760Sstevel@tonic-gate 	int			i, j, oc_len, len;
10770Sstevel@tonic-gate 	int			at_least_one = FALSE;
10780Sstevel@tonic-gate 	filter_mapping_info_t	**info, *info1;
10790Sstevel@tonic-gate 	char			**mapping;
10800Sstevel@tonic-gate 	char			*service, *filter, *err;
10810Sstevel@tonic-gate 	int			auto_service = FALSE;
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate 	if (cookie == NULL || new_filter == NULL)
10840Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
10850Sstevel@tonic-gate 
10860Sstevel@tonic-gate 	*new_filter = NULL;
10870Sstevel@tonic-gate 	service = cookie->service;
10880Sstevel@tonic-gate 	filter = cookie->filter;
10890Sstevel@tonic-gate 
10900Sstevel@tonic-gate 	/*
10910Sstevel@tonic-gate 	 * count the number of '=' char
10920Sstevel@tonic-gate 	 */
10930Sstevel@tonic-gate 	for (c = filter; *c; c++) {
10940Sstevel@tonic-gate 		if (*c == TOKENSEPARATOR)
10950Sstevel@tonic-gate 			num_eq++;
10960Sstevel@tonic-gate 	}
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	if (service != NULL && strncasecmp(service, "auto_", 5) == 0)
10990Sstevel@tonic-gate 		auto_service = TRUE;
11000Sstevel@tonic-gate 
11010Sstevel@tonic-gate 	/*
11020Sstevel@tonic-gate 	 * See if schema mapping existed for the given service.
11030Sstevel@tonic-gate 	 * If not, just return success.
11040Sstevel@tonic-gate 	 */
11050Sstevel@tonic-gate 	mapping = __ns_ldap_getOrigAttribute(service,
11064765Smj162486 	    NS_HASH_SCHEMA_MAPPING_EXISTED);
11070Sstevel@tonic-gate 
11080Sstevel@tonic-gate 	if (mapping == NULL && auto_service)
11090Sstevel@tonic-gate 		/*
11100Sstevel@tonic-gate 		 * if service == auto_* and no
11110Sstevel@tonic-gate 		 * schema mapping found
11120Sstevel@tonic-gate 		 * then try automount
11130Sstevel@tonic-gate 		 */
11140Sstevel@tonic-gate 		mapping = __ns_ldap_getOrigAttribute(
11154765Smj162486 		    "automount", NS_HASH_SCHEMA_MAPPING_EXISTED);
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	if (mapping)
11180Sstevel@tonic-gate 		__s_api_free2dArray(mapping);
11190Sstevel@tonic-gate 	else
11200Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	/*
11230Sstevel@tonic-gate 	 * no '=' sign, just say OK and return nothing
11240Sstevel@tonic-gate 	 */
11250Sstevel@tonic-gate 	if (num_eq == 0)
11260Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
11270Sstevel@tonic-gate 
11280Sstevel@tonic-gate 	/*
11290Sstevel@tonic-gate 	 * Make a copy of the filter string
11300Sstevel@tonic-gate 	 * for saving the name of the objectclasses or
11310Sstevel@tonic-gate 	 * attributes that need to be passed to the
11320Sstevel@tonic-gate 	 * objectclass or attribute mapping functions.
11330Sstevel@tonic-gate 	 * pointer "info->from_name" points to the locations
11340Sstevel@tonic-gate 	 * within this string.
11350Sstevel@tonic-gate 	 *
11360Sstevel@tonic-gate 	 * The input filter string, filter, will be used
11370Sstevel@tonic-gate 	 * to indicate where these names start and end.
11380Sstevel@tonic-gate 	 * pointers "info->name_start" and "info->name_end"
11390Sstevel@tonic-gate 	 * point to locations within the input filter string,
11400Sstevel@tonic-gate 	 * and are used at the end of this function to
11410Sstevel@tonic-gate 	 * merge the original filter data with the
11420Sstevel@tonic-gate 	 * mapped objectclass or attribute names.
11430Sstevel@tonic-gate 	 */
11440Sstevel@tonic-gate 	filter_c = strdup(filter);
11450Sstevel@tonic-gate 	if (filter_c == NULL)
11460Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
11470Sstevel@tonic-gate 	filter_c_next = filter_c;
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	/*
11500Sstevel@tonic-gate 	 * get memory for info arrays
11510Sstevel@tonic-gate 	 */
11520Sstevel@tonic-gate 	info = (filter_mapping_info_t **)calloc(num_eq + 1,
11534765Smj162486 	    sizeof (filter_mapping_info_t *));
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate 	if (info == NULL) {
11560Sstevel@tonic-gate 		free(filter_c);
11570Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
11580Sstevel@tonic-gate 	}
11590Sstevel@tonic-gate 
11600Sstevel@tonic-gate 	/*
11610Sstevel@tonic-gate 	 * find valid '=' for further processing,
11620Sstevel@tonic-gate 	 * ignore the "escaped =" (.i.e. "\="), or
11630Sstevel@tonic-gate 	 * "=" in quoted string
11640Sstevel@tonic-gate 	 */
11650Sstevel@tonic-gate 	for (c = filter_c; *c; c++) {
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 		switch (*c) {
11680Sstevel@tonic-gate 		case TOKENSEPARATOR:
11692031Svt115884 			if (!in_quote && !is_value) {
11700Sstevel@tonic-gate 				info1 = (filter_mapping_info_t *)calloc(1,
11714765Smj162486 				    sizeof (filter_mapping_info_t));
11720Sstevel@tonic-gate 				if (!info1) {
11730Sstevel@tonic-gate 					free(filter_c);
11740Sstevel@tonic-gate 					for (i = 0; i < num_veq; i++)
11750Sstevel@tonic-gate 						free(info[i]);
11760Sstevel@tonic-gate 					free(info);
11770Sstevel@tonic-gate 					return (NS_LDAP_MEMORY);
11780Sstevel@tonic-gate 				}
11790Sstevel@tonic-gate 				info[num_veq] = info1;
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 				/*
11820Sstevel@tonic-gate 				 * remember the location of this "="
11830Sstevel@tonic-gate 				 */
11840Sstevel@tonic-gate 				info[num_veq++]->veq_pos = c;
11852031Svt115884 
11862031Svt115884 				/*
11872031Svt115884 				 * skip until the end of the attribute value
11882031Svt115884 				 */
11892031Svt115884 				is_value = TRUE;
11900Sstevel@tonic-gate 			}
11910Sstevel@tonic-gate 			break;
11922031Svt115884 		case CPARATOK:
11932031Svt115884 			/*
11942031Svt115884 			 * mark the end of the attribute value
11952031Svt115884 			 */
11962031Svt115884 			if (!in_quote)
11972031Svt115884 				is_value = FALSE;
11982031Svt115884 			break;
11990Sstevel@tonic-gate 		case QUOTETOK:
12000Sstevel@tonic-gate 			/*
12010Sstevel@tonic-gate 			 * switch on/off the in_quote mode
12020Sstevel@tonic-gate 			 */
12030Sstevel@tonic-gate 			in_quote = (in_quote == FALSE);
12040Sstevel@tonic-gate 			break;
12050Sstevel@tonic-gate 		case '\\':
12060Sstevel@tonic-gate 			/*
12070Sstevel@tonic-gate 			 * ignore escape characters
12080Sstevel@tonic-gate 			 * don't skip if next char is '\0'
12090Sstevel@tonic-gate 			 */
12100Sstevel@tonic-gate 			if (!in_quote)
12110Sstevel@tonic-gate 				if (*(++c) == '\0')
12120Sstevel@tonic-gate 					c--;
12130Sstevel@tonic-gate 			break;
12140Sstevel@tonic-gate 		}
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	}
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	/*
12190Sstevel@tonic-gate 	 * for each valid "=" found, get the name to
12200Sstevel@tonic-gate 	 * be mapped
12210Sstevel@tonic-gate 	 */
12220Sstevel@tonic-gate 	oc_len = strlen("objectclass");
12230Sstevel@tonic-gate 	for (i = 0; i < num_veq; i++) {
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 		/*
12260Sstevel@tonic-gate 		 * look at the left side of "=" to see
12270Sstevel@tonic-gate 		 * if assertion is "objectclass=<ocname>"
12280Sstevel@tonic-gate 		 * or "<attribute name>=<attribute value>"
12290Sstevel@tonic-gate 		 *
12300Sstevel@tonic-gate 		 * first skip spaces before "=".
12310Sstevel@tonic-gate 		 * Note that filter_c_next may not point to the
12320Sstevel@tonic-gate 		 * start of the filter string. For i > 0,
12330Sstevel@tonic-gate 		 * it points to the end of the last name processed + 2
12340Sstevel@tonic-gate 		 */
12350Sstevel@tonic-gate 		for (tail = info[i]->veq_pos; (tail > filter_c_next) &&
12364765Smj162486 		    (*(tail - 1) == SPACETOK); tail--)
12374765Smj162486 			;
12380Sstevel@tonic-gate 
12390Sstevel@tonic-gate 		/*
12400Sstevel@tonic-gate 		 * mark the end of the left side string (the key)
12410Sstevel@tonic-gate 		 */
12420Sstevel@tonic-gate 		*tail = '\0';
12430Sstevel@tonic-gate 		info[i]->name_end = tail - filter_c - 1 + filter;
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 		/*
12460Sstevel@tonic-gate 		 * find the start of the key
12470Sstevel@tonic-gate 		 */
12480Sstevel@tonic-gate 		key = filter_c_next;
12490Sstevel@tonic-gate 		for (c = tail; filter_c_next <= c; c--) {
12500Sstevel@tonic-gate 			/* OPARATOK is '(' */
12510Sstevel@tonic-gate 			if (*c == OPARATOK ||
12524765Smj162486 			    *c == SPACETOK) {
12530Sstevel@tonic-gate 				key = c + 1;
12540Sstevel@tonic-gate 				break;
12550Sstevel@tonic-gate 			}
12560Sstevel@tonic-gate 		}
12570Sstevel@tonic-gate 		info[i]->name_start = key - filter_c + filter;
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 		if ((key + oc_len) <= tail) {
12600Sstevel@tonic-gate 			if (strncasecmp(key, "objectclass",
12614765Smj162486 			    oc_len) == 0) {
12620Sstevel@tonic-gate 				/*
12630Sstevel@tonic-gate 				 * assertion is "objectclass=ocname",
12640Sstevel@tonic-gate 				 * ocname is the one needs to be mapped
12650Sstevel@tonic-gate 				 *
12660Sstevel@tonic-gate 				 * skip spaces after "=" to find start
12670Sstevel@tonic-gate 				 * of the ocname
12680Sstevel@tonic-gate 				 */
12690Sstevel@tonic-gate 				head = info[i]->veq_pos;
12700Sstevel@tonic-gate 				for (head = info[i]->veq_pos + 1;
12714765Smj162486 				    *head && *head == SPACETOK; head++)
12724765Smj162486 					;
12730Sstevel@tonic-gate 
12740Sstevel@tonic-gate 				/* ignore empty ocname */
12750Sstevel@tonic-gate 				if (!(*head))
12760Sstevel@tonic-gate 					continue;
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 				info[i]->name_start = head - filter_c +
12794765Smj162486 				    filter;
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate 				/*
12820Sstevel@tonic-gate 				 * now find the end of the ocname
12830Sstevel@tonic-gate 				 */
12840Sstevel@tonic-gate 				for (c = head; ; c++) {
12850Sstevel@tonic-gate 					/* CPARATOK is ')' */
12860Sstevel@tonic-gate 					if (*c == CPARATOK ||
12874765Smj162486 					    *c == '\0' ||
12884765Smj162486 					    *c == SPACETOK) {
12890Sstevel@tonic-gate 						*c = '\0';
12900Sstevel@tonic-gate 						info[i]->name_end =
12914765Smj162486 						    c - filter_c - 1 +
12924765Smj162486 						    filter;
12930Sstevel@tonic-gate 						filter_c_next = c + 1;
12940Sstevel@tonic-gate 						info[i]->oc_or_attr = 'o';
12950Sstevel@tonic-gate 						info[i]->from_name = head;
12960Sstevel@tonic-gate 						break;
12970Sstevel@tonic-gate 					}
12980Sstevel@tonic-gate 				}
12990Sstevel@tonic-gate 			}
13000Sstevel@tonic-gate 		}
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 		/*
13030Sstevel@tonic-gate 		 * assertion is not "objectclass=ocname",
13040Sstevel@tonic-gate 		 * assume assertion is "<key> = <value>",
13050Sstevel@tonic-gate 		 * <key> is the one needs to be mapped
13060Sstevel@tonic-gate 		 */
13070Sstevel@tonic-gate 		if (info[i]->from_name == NULL && strlen(key) > 0) {
13080Sstevel@tonic-gate 			info[i]->oc_or_attr = 'a';
13090Sstevel@tonic-gate 			info[i]->from_name = key;
13100Sstevel@tonic-gate 		}
13110Sstevel@tonic-gate 	}
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 	/* perform schema mapping */
13140Sstevel@tonic-gate 	for (i = 0; i < num_veq; i++) {
13150Sstevel@tonic-gate 		if (info[i]->from_name == NULL)
13160Sstevel@tonic-gate 			continue;
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 		if (info[i]->oc_or_attr == 'a')
13190Sstevel@tonic-gate 			info[i]->mapping =
13204765Smj162486 			    __ns_ldap_getMappedAttributes(service,
13214765Smj162486 			    info[i]->from_name);
13220Sstevel@tonic-gate 		else
13230Sstevel@tonic-gate 			info[i]->mapping =
13244765Smj162486 			    __ns_ldap_getMappedObjectClass(service,
13254765Smj162486 			    info[i]->from_name);
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 		if (info[i]->mapping == NULL && auto_service)  {
13280Sstevel@tonic-gate 			/*
13290Sstevel@tonic-gate 			 * If no mapped attribute/objectclass is found
13300Sstevel@tonic-gate 			 * and service == auto*
13310Sstevel@tonic-gate 			 * try to find automount's
13320Sstevel@tonic-gate 			 * mapped attribute/objectclass
13330Sstevel@tonic-gate 			 */
13340Sstevel@tonic-gate 			if (info[i]->oc_or_attr == 'a')
13350Sstevel@tonic-gate 				info[i]->mapping =
13364765Smj162486 				    __ns_ldap_getMappedAttributes("automount",
13374765Smj162486 				    info[i]->from_name);
13380Sstevel@tonic-gate 			else
13390Sstevel@tonic-gate 				info[i]->mapping =
13404765Smj162486 				    __ns_ldap_getMappedObjectClass("automount",
13414765Smj162486 				    info[i]->from_name);
13420Sstevel@tonic-gate 		}
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 		if (info[i]->mapping == NULL ||
13454765Smj162486 		    info[i]->mapping[0] == NULL) {
13460Sstevel@tonic-gate 			info[i]->to_name = NULL;
13470Sstevel@tonic-gate 		} else if (info[i]->mapping[1] == NULL) {
13480Sstevel@tonic-gate 			info[i]->to_name = info[i]->mapping[0];
13490Sstevel@tonic-gate 			at_least_one = TRUE;
13500Sstevel@tonic-gate 		} else {
13510Sstevel@tonic-gate 			__s_api_free2dArray(info[i]->mapping);
13520Sstevel@tonic-gate 			/*
13530Sstevel@tonic-gate 			 * multiple mapping
13540Sstevel@tonic-gate 			 * not allowed
13550Sstevel@tonic-gate 			 */
13560Sstevel@tonic-gate 			(void) sprintf(errstr,
13574765Smj162486 			    gettext(
13584765Smj162486 			    "Multiple attribute or objectclass "
13594765Smj162486 			    "mapping for '%s' in filter "
13604765Smj162486 			    "'%s' not allowed."),
13614765Smj162486 			    info[i]->from_name, filter);
13620Sstevel@tonic-gate 			err = strdup(errstr);
13630Sstevel@tonic-gate 			if (err)
13640Sstevel@tonic-gate 				MKERROR(LOG_WARNING, cookie->errorp,
13654765Smj162486 				    NS_CONFIG_SYNTAX,
13664765Smj162486 				    err, NULL);
13670Sstevel@tonic-gate 
13680Sstevel@tonic-gate 			free(filter_c);
13690Sstevel@tonic-gate 			for (j = 0; j < num_veq; j++) {
13700Sstevel@tonic-gate 				if (info[j]->mapping)
13710Sstevel@tonic-gate 					__s_api_free2dArray(
13724765Smj162486 					    info[j]->mapping);
13730Sstevel@tonic-gate 				free(info[j]);
13740Sstevel@tonic-gate 			}
13750Sstevel@tonic-gate 			free(info);
13760Sstevel@tonic-gate 			return (NS_LDAP_CONFIG);
13770Sstevel@tonic-gate 		}
13780Sstevel@tonic-gate 	}
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 
13810Sstevel@tonic-gate 	if (at_least_one) {
13820Sstevel@tonic-gate 
13830Sstevel@tonic-gate 		len = strlen(filter);
13840Sstevel@tonic-gate 		last_copied = filter - 1;
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 		for (i = 0; i < num_veq; i++) {
13870Sstevel@tonic-gate 			if (info[i]->to_name)
13880Sstevel@tonic-gate 				len += strlen(info[i]->to_name);
13890Sstevel@tonic-gate 		}
13900Sstevel@tonic-gate 
13910Sstevel@tonic-gate 		*new_filter = (char *)calloc(1, len);
13920Sstevel@tonic-gate 		if (*new_filter == NULL) {
13930Sstevel@tonic-gate 			free(filter_c);
13940Sstevel@tonic-gate 			for (j = 0; j < num_veq; j++) {
13950Sstevel@tonic-gate 				if (info[j]->mapping)
13960Sstevel@tonic-gate 					__s_api_free2dArray(
13974765Smj162486 					    info[j]->mapping);
13980Sstevel@tonic-gate 				free(info[j]);
13990Sstevel@tonic-gate 			}
14000Sstevel@tonic-gate 			free(info);
14010Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
14020Sstevel@tonic-gate 		}
14030Sstevel@tonic-gate 
14040Sstevel@tonic-gate 		for (i = 0; i < num_veq; i++) {
14050Sstevel@tonic-gate 			if (info[i]->to_name != NULL &&
14064765Smj162486 			    info[i]->to_name != NULL) {
14074765Smj162486 
14084765Smj162486 				/*
14094765Smj162486 				 * copy the original filter data
14104765Smj162486 				 * between the last name and current
14114765Smj162486 				 * name
14124765Smj162486 				 */
14134765Smj162486 				if ((last_copied + 1) != info[i]->name_start)
14144765Smj162486 					(void) strncat(*new_filter,
14154765Smj162486 					    last_copied + 1,
14164765Smj162486 					    info[i]->name_start -
14174765Smj162486 					    last_copied - 1);
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 				/* the data is copied */
14200Sstevel@tonic-gate 				last_copied = info[i]->name_end;
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 				/*
14230Sstevel@tonic-gate 				 * replace the name with
14240Sstevel@tonic-gate 				 * the mapped name
14250Sstevel@tonic-gate 				 */
14260Sstevel@tonic-gate 				(void) strcat(*new_filter, info[i]->to_name);
14270Sstevel@tonic-gate 			}
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 			/* copy the filter data after the last name */
14300Sstevel@tonic-gate 			if (i == (num_veq -1) &&
14314765Smj162486 			    info[i]->name_end <
14324765Smj162486 			    (filter + strlen(filter)))
14330Sstevel@tonic-gate 				(void) strncat(*new_filter, last_copied + 1,
14344765Smj162486 				    filter + strlen(filter) -
14354765Smj162486 				    last_copied - 1);
14360Sstevel@tonic-gate 		}
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	}
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 	/* free memory */
14410Sstevel@tonic-gate 	free(filter_c);
14420Sstevel@tonic-gate 	for (j = 0; j < num_veq; j++) {
14430Sstevel@tonic-gate 		if (info[j]->mapping)
14440Sstevel@tonic-gate 			__s_api_free2dArray(info[j]->mapping);
14450Sstevel@tonic-gate 		free(info[j]);
14460Sstevel@tonic-gate 	}
14470Sstevel@tonic-gate 	free(info);
14480Sstevel@tonic-gate 
14490Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
14500Sstevel@tonic-gate }
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate static int
setup_next_search(ns_ldap_cookie_t * cookie)14530Sstevel@tonic-gate setup_next_search(ns_ldap_cookie_t *cookie)
14540Sstevel@tonic-gate {
14550Sstevel@tonic-gate 	ns_ldap_search_desc_t	*dptr;
14560Sstevel@tonic-gate 	int			scope;
14570Sstevel@tonic-gate 	char			*filter, *str;
14580Sstevel@tonic-gate 	int			baselen;
14590Sstevel@tonic-gate 	int			rc;
14600Sstevel@tonic-gate 	void			**param;
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate 	dptr = *cookie->sdpos;
14630Sstevel@tonic-gate 	scope = cookie->i_flags & (NS_LDAP_SCOPE_BASE |
14644765Smj162486 	    NS_LDAP_SCOPE_ONELEVEL |
14654765Smj162486 	    NS_LDAP_SCOPE_SUBTREE);
14660Sstevel@tonic-gate 	if (scope)
14670Sstevel@tonic-gate 		cookie->scope = scope;
14680Sstevel@tonic-gate 	else
14690Sstevel@tonic-gate 		cookie->scope = dptr->scope;
14700Sstevel@tonic-gate 	switch (cookie->scope) {
14710Sstevel@tonic-gate 	case NS_LDAP_SCOPE_BASE:
14720Sstevel@tonic-gate 		cookie->scope = LDAP_SCOPE_BASE;
14730Sstevel@tonic-gate 		break;
14740Sstevel@tonic-gate 	case NS_LDAP_SCOPE_ONELEVEL:
14750Sstevel@tonic-gate 		cookie->scope = LDAP_SCOPE_ONELEVEL;
14760Sstevel@tonic-gate 		break;
14770Sstevel@tonic-gate 	case NS_LDAP_SCOPE_SUBTREE:
14780Sstevel@tonic-gate 		cookie->scope = LDAP_SCOPE_SUBTREE;
14790Sstevel@tonic-gate 		break;
14800Sstevel@tonic-gate 	}
14810Sstevel@tonic-gate 
14820Sstevel@tonic-gate 	filter = NULL;
14830Sstevel@tonic-gate 	if (cookie->use_filtercb && cookie->init_filter_cb &&
14844765Smj162486 	    dptr->filter && strlen(dptr->filter) > 0) {
14850Sstevel@tonic-gate 		(*cookie->init_filter_cb)(dptr, &filter,
14864765Smj162486 		    cookie->userdata);
14870Sstevel@tonic-gate 	}
14880Sstevel@tonic-gate 	if (filter == NULL) {
14890Sstevel@tonic-gate 		if (cookie->i_filter == NULL) {
14900Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INVALID_PARAM;
14910Sstevel@tonic-gate 			return (-1);
14920Sstevel@tonic-gate 		} else {
14933762Srm88369 			if (cookie->filter)
14943762Srm88369 				free(cookie->filter);
14950Sstevel@tonic-gate 			cookie->filter = strdup(cookie->i_filter);
14960Sstevel@tonic-gate 			if (cookie->filter == NULL) {
14970Sstevel@tonic-gate 				cookie->err_rc = NS_LDAP_MEMORY;
14980Sstevel@tonic-gate 				return (-1);
14990Sstevel@tonic-gate 			}
15000Sstevel@tonic-gate 		}
15010Sstevel@tonic-gate 	} else {
15023762Srm88369 		if (cookie->filter)
15033762Srm88369 			free(cookie->filter);
15040Sstevel@tonic-gate 		cookie->filter = strdup(filter);
15050Sstevel@tonic-gate 		free(filter);
15060Sstevel@tonic-gate 		if (cookie->filter == NULL) {
15070Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_MEMORY;
15080Sstevel@tonic-gate 			return (-1);
15090Sstevel@tonic-gate 		}
15100Sstevel@tonic-gate 	}
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	/*
15130Sstevel@tonic-gate 	 * perform attribute/objectclass mapping on filter
15140Sstevel@tonic-gate 	 */
15150Sstevel@tonic-gate 	filter = NULL;
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	if (cookie->service) {
15180Sstevel@tonic-gate 		rc = get_mapped_filter(cookie, &filter);
15190Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
15200Sstevel@tonic-gate 			cookie->err_rc = rc;
15210Sstevel@tonic-gate 			return (-1);
15220Sstevel@tonic-gate 		} else {
15230Sstevel@tonic-gate 			/*
15240Sstevel@tonic-gate 			 * get_mapped_filter returns
15250Sstevel@tonic-gate 			 * NULL filter pointer, if
15260Sstevel@tonic-gate 			 * no mapping was done
15270Sstevel@tonic-gate 			 */
15280Sstevel@tonic-gate 			if (filter) {
15290Sstevel@tonic-gate 				free(cookie->filter);
15300Sstevel@tonic-gate 				cookie->filter = filter;
15310Sstevel@tonic-gate 			}
15320Sstevel@tonic-gate 		}
15330Sstevel@tonic-gate 	}
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 	/*
15360Sstevel@tonic-gate 	 * validate filter to make sure it's legal
15370Sstevel@tonic-gate 	 * [remove redundant ()'s]
15380Sstevel@tonic-gate 	 */
15390Sstevel@tonic-gate 	rc = validate_filter(cookie);
15400Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
15410Sstevel@tonic-gate 		cookie->err_rc = rc;
15420Sstevel@tonic-gate 		return (-1);
15430Sstevel@tonic-gate 	}
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	baselen = strlen(dptr->basedn);
15460Sstevel@tonic-gate 	if (baselen > 0 && dptr->basedn[baselen-1] == COMMATOK) {
15470Sstevel@tonic-gate 		rc = __ns_ldap_getParam(NS_LDAP_SEARCH_BASEDN_P,
15484765Smj162486 		    (void ***)&param, &cookie->errorp);
15490Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
15500Sstevel@tonic-gate 			cookie->err_rc = rc;
15510Sstevel@tonic-gate 			return (-1);
15520Sstevel@tonic-gate 		}
15530Sstevel@tonic-gate 		str = ((char **)param)[0];
15540Sstevel@tonic-gate 		baselen += strlen(str)+1;
15553762Srm88369 		if (cookie->basedn)
15563762Srm88369 			free(cookie->basedn);
15570Sstevel@tonic-gate 		cookie->basedn = (char *)malloc(baselen);
15580Sstevel@tonic-gate 		if (cookie->basedn == NULL) {
15590Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_MEMORY;
15600Sstevel@tonic-gate 			return (-1);
15610Sstevel@tonic-gate 		}
15620Sstevel@tonic-gate 		(void) strcpy(cookie->basedn, dptr->basedn);
15630Sstevel@tonic-gate 		(void) strcat(cookie->basedn, str);
15640Sstevel@tonic-gate 		(void) __ns_ldap_freeParam(&param);
15650Sstevel@tonic-gate 	} else {
15663762Srm88369 		if (cookie->basedn)
15673762Srm88369 			free(cookie->basedn);
15680Sstevel@tonic-gate 		cookie->basedn = strdup(dptr->basedn);
15690Sstevel@tonic-gate 	}
15700Sstevel@tonic-gate 	return (0);
15710Sstevel@tonic-gate }
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate static int
setup_referral_search(ns_ldap_cookie_t * cookie)15740Sstevel@tonic-gate setup_referral_search(ns_ldap_cookie_t *cookie)
15750Sstevel@tonic-gate {
15760Sstevel@tonic-gate 	ns_referral_info_t	*ref;
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	ref = cookie->refpos;
15790Sstevel@tonic-gate 	cookie->scope = ref->refScope;
15800Sstevel@tonic-gate 	if (cookie->filter) {
15810Sstevel@tonic-gate 		free(cookie->filter);
15820Sstevel@tonic-gate 	}
15830Sstevel@tonic-gate 	cookie->filter = strdup(ref->refFilter);
15840Sstevel@tonic-gate 	if (cookie->basedn) {
15850Sstevel@tonic-gate 		free(cookie->basedn);
15860Sstevel@tonic-gate 	}
15870Sstevel@tonic-gate 	cookie->basedn = strdup(ref->refDN);
15880Sstevel@tonic-gate 	if (cookie->filter == NULL || cookie->basedn == NULL) {
15890Sstevel@tonic-gate 		cookie->err_rc = NS_LDAP_MEMORY;
15900Sstevel@tonic-gate 		return (-1);
15910Sstevel@tonic-gate 	}
15920Sstevel@tonic-gate 	return (0);
15930Sstevel@tonic-gate }
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate static int
get_current_session(ns_ldap_cookie_t * cookie)15960Sstevel@tonic-gate get_current_session(ns_ldap_cookie_t *cookie)
15970Sstevel@tonic-gate {
15980Sstevel@tonic-gate 	ConnectionID	connectionId = -1;
15990Sstevel@tonic-gate 	Connection	*conp = NULL;
16000Sstevel@tonic-gate 	int		rc;
16010Sstevel@tonic-gate 	int		fail_if_new_pwd_reqd = 1;
16020Sstevel@tonic-gate 
16030Sstevel@tonic-gate 	rc = __s_api_getConnection(NULL, cookie->i_flags,
16044765Smj162486 	    cookie->i_auth, &connectionId, &conp,
16054765Smj162486 	    &cookie->errorp, fail_if_new_pwd_reqd,
16066842Sth160488 	    cookie->nopasswd_acct_mgmt, cookie->conn_user);
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 	/*
16090Sstevel@tonic-gate 	 * If password control attached in *cookie->errorp,
16100Sstevel@tonic-gate 	 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
16110Sstevel@tonic-gate 	 * free the error structure (we do not need
16120Sstevel@tonic-gate 	 * the sec_to_expired info).
16130Sstevel@tonic-gate 	 * Reset rc to NS_LDAP_SUCCESS.
16140Sstevel@tonic-gate 	 */
16150Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
16160Sstevel@tonic-gate 		(void) __ns_ldap_freeError(
16174765Smj162486 		    &cookie->errorp);
16180Sstevel@tonic-gate 		cookie->errorp = NULL;
16190Sstevel@tonic-gate 		rc = NS_LDAP_SUCCESS;
16200Sstevel@tonic-gate 	}
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
16230Sstevel@tonic-gate 		cookie->err_rc = rc;
16240Sstevel@tonic-gate 		return (-1);
16250Sstevel@tonic-gate 	}
16260Sstevel@tonic-gate 	cookie->conn = conp;
16270Sstevel@tonic-gate 	cookie->connectionId = connectionId;
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate 	return (0);
16300Sstevel@tonic-gate }
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate static int
get_next_session(ns_ldap_cookie_t * cookie)16330Sstevel@tonic-gate get_next_session(ns_ldap_cookie_t *cookie)
16340Sstevel@tonic-gate {
16350Sstevel@tonic-gate 	ConnectionID	connectionId = -1;
16360Sstevel@tonic-gate 	Connection	*conp = NULL;
16370Sstevel@tonic-gate 	int		rc;
16380Sstevel@tonic-gate 	int		fail_if_new_pwd_reqd = 1;
16390Sstevel@tonic-gate 
16404953Smichen 	if (cookie->connectionId > -1) {
16410Sstevel@tonic-gate 		DropConnection(cookie->connectionId, cookie->i_flags);
16424953Smichen 		cookie->connectionId = -1;
16434953Smichen 	}
16440Sstevel@tonic-gate 
16456842Sth160488 	/* If using a MT connection, return it. */
16466842Sth160488 	if (cookie->conn_user != NULL &&
16476842Sth160488 	    cookie->conn_user->conn_mt != NULL)
16486842Sth160488 		__s_api_conn_mt_return(cookie->conn_user);
16496842Sth160488 
16500Sstevel@tonic-gate 	rc = __s_api_getConnection(NULL, cookie->i_flags,
16514765Smj162486 	    cookie->i_auth, &connectionId, &conp,
16524765Smj162486 	    &cookie->errorp, fail_if_new_pwd_reqd,
16536842Sth160488 	    cookie->nopasswd_acct_mgmt, cookie->conn_user);
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate 	/*
16560Sstevel@tonic-gate 	 * If password control attached in *cookie->errorp,
16570Sstevel@tonic-gate 	 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
16580Sstevel@tonic-gate 	 * free the error structure (we do not need
16590Sstevel@tonic-gate 	 * the sec_to_expired info).
16600Sstevel@tonic-gate 	 * Reset rc to NS_LDAP_SUCCESS.
16610Sstevel@tonic-gate 	 */
16620Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
16630Sstevel@tonic-gate 		(void) __ns_ldap_freeError(
16644765Smj162486 		    &cookie->errorp);
16650Sstevel@tonic-gate 		cookie->errorp = NULL;
16660Sstevel@tonic-gate 		rc = NS_LDAP_SUCCESS;
16670Sstevel@tonic-gate 	}
16680Sstevel@tonic-gate 
16690Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
16700Sstevel@tonic-gate 		cookie->err_rc = rc;
16710Sstevel@tonic-gate 		return (-1);
16720Sstevel@tonic-gate 	}
16730Sstevel@tonic-gate 	cookie->conn = conp;
16740Sstevel@tonic-gate 	cookie->connectionId = connectionId;
16750Sstevel@tonic-gate 	return (0);
16760Sstevel@tonic-gate }
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate static int
get_referral_session(ns_ldap_cookie_t * cookie)16790Sstevel@tonic-gate get_referral_session(ns_ldap_cookie_t *cookie)
16800Sstevel@tonic-gate {
16810Sstevel@tonic-gate 	ConnectionID	connectionId = -1;
16820Sstevel@tonic-gate 	Connection	*conp = NULL;
16830Sstevel@tonic-gate 	int		rc;
16840Sstevel@tonic-gate 	int		fail_if_new_pwd_reqd = 1;
16850Sstevel@tonic-gate 
16864953Smichen 	if (cookie->connectionId > -1) {
16870Sstevel@tonic-gate 		DropConnection(cookie->connectionId, cookie->i_flags);
16884953Smichen 		cookie->connectionId = -1;
16894953Smichen 	}
16900Sstevel@tonic-gate 
16916842Sth160488 	/* set it up to use a connection opened for referral */
16926842Sth160488 	if (cookie->conn_user != NULL) {
16936842Sth160488 		/* If using a MT connection, return it. */
16946842Sth160488 		if (cookie->conn_user->conn_mt != NULL)
16956842Sth160488 			__s_api_conn_mt_return(cookie->conn_user);
16966842Sth160488 		cookie->conn_user->referral = B_TRUE;
16976842Sth160488 	}
16986842Sth160488 
16990Sstevel@tonic-gate 	rc = __s_api_getConnection(cookie->refpos->refHost, 0,
17004765Smj162486 	    cookie->i_auth, &connectionId, &conp,
17014765Smj162486 	    &cookie->errorp, fail_if_new_pwd_reqd,
17026842Sth160488 	    cookie->nopasswd_acct_mgmt, cookie->conn_user);
17030Sstevel@tonic-gate 
17040Sstevel@tonic-gate 	/*
17050Sstevel@tonic-gate 	 * If password control attached in *cookie->errorp,
17060Sstevel@tonic-gate 	 * e.g. rc == NS_LDAP_SUCCESS_WITH_INFO,
17070Sstevel@tonic-gate 	 * free the error structure (we do not need
17080Sstevel@tonic-gate 	 * the sec_to_expired info).
17090Sstevel@tonic-gate 	 * Reset rc to NS_LDAP_SUCCESS.
17100Sstevel@tonic-gate 	 */
17110Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS_WITH_INFO) {
17120Sstevel@tonic-gate 		(void) __ns_ldap_freeError(
17134765Smj162486 		    &cookie->errorp);
17140Sstevel@tonic-gate 		cookie->errorp = NULL;
17150Sstevel@tonic-gate 		rc = NS_LDAP_SUCCESS;
17160Sstevel@tonic-gate 	}
17170Sstevel@tonic-gate 
17180Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
17190Sstevel@tonic-gate 		cookie->err_rc = rc;
17200Sstevel@tonic-gate 		return (-1);
17210Sstevel@tonic-gate 	}
17220Sstevel@tonic-gate 	cookie->conn = conp;
17230Sstevel@tonic-gate 	cookie->connectionId = connectionId;
17240Sstevel@tonic-gate 	return (0);
17250Sstevel@tonic-gate }
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate static int
paging_supported(ns_ldap_cookie_t * cookie)17280Sstevel@tonic-gate paging_supported(ns_ldap_cookie_t *cookie)
17290Sstevel@tonic-gate {
17300Sstevel@tonic-gate 	int		rc;
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 	cookie->listType = 0;
17330Sstevel@tonic-gate 	rc = __s_api_isCtrlSupported(cookie->conn,
17344765Smj162486 	    LDAP_CONTROL_VLVREQUEST);
17350Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS) {
17360Sstevel@tonic-gate 		cookie->listType = VLVCTRLFLAG;
17370Sstevel@tonic-gate 		return (1);
17380Sstevel@tonic-gate 	}
17390Sstevel@tonic-gate 	rc = __s_api_isCtrlSupported(cookie->conn,
17404765Smj162486 	    LDAP_CONTROL_SIMPLE_PAGE);
17410Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS) {
17420Sstevel@tonic-gate 		cookie->listType = SIMPLEPAGECTRLFLAG;
17430Sstevel@tonic-gate 		return (1);
17440Sstevel@tonic-gate 	}
17450Sstevel@tonic-gate 	return (0);
17460Sstevel@tonic-gate }
17470Sstevel@tonic-gate 
1748*12758SJulian.Pullen@Sun.COM typedef struct servicesorttype {
1749*12758SJulian.Pullen@Sun.COM 	char *service;
1750*12758SJulian.Pullen@Sun.COM 	ns_srvsidesort_t type;
1751*12758SJulian.Pullen@Sun.COM } servicesorttype_t;
1752*12758SJulian.Pullen@Sun.COM 
1753*12758SJulian.Pullen@Sun.COM static servicesorttype_t *sort_type = NULL;
1754*12758SJulian.Pullen@Sun.COM static int sort_type_size = 0;
1755*12758SJulian.Pullen@Sun.COM static int sort_type_hwm = 0;
1756*12758SJulian.Pullen@Sun.COM static mutex_t sort_type_mutex = DEFAULTMUTEX;
1757*12758SJulian.Pullen@Sun.COM 
1758*12758SJulian.Pullen@Sun.COM 
1759*12758SJulian.Pullen@Sun.COM static ns_srvsidesort_t
get_srvsidesort_type(char * service)1760*12758SJulian.Pullen@Sun.COM get_srvsidesort_type(char *service)
1761*12758SJulian.Pullen@Sun.COM {
1762*12758SJulian.Pullen@Sun.COM 	int i;
1763*12758SJulian.Pullen@Sun.COM 	ns_srvsidesort_t type = SSS_UNKNOWN;
1764*12758SJulian.Pullen@Sun.COM 
1765*12758SJulian.Pullen@Sun.COM 	if (service == NULL)
1766*12758SJulian.Pullen@Sun.COM 		return (type);
1767*12758SJulian.Pullen@Sun.COM 
1768*12758SJulian.Pullen@Sun.COM 	(void) mutex_lock(&sort_type_mutex);
1769*12758SJulian.Pullen@Sun.COM 	if (sort_type != NULL) {
1770*12758SJulian.Pullen@Sun.COM 		for (i = 0; i < sort_type_hwm; i++) {
1771*12758SJulian.Pullen@Sun.COM 			if (strcmp(sort_type[i].service, service) == 0) {
1772*12758SJulian.Pullen@Sun.COM 				type = sort_type[i].type;
1773*12758SJulian.Pullen@Sun.COM 				break;
1774*12758SJulian.Pullen@Sun.COM 			}
1775*12758SJulian.Pullen@Sun.COM 		}
1776*12758SJulian.Pullen@Sun.COM 	}
1777*12758SJulian.Pullen@Sun.COM 	(void) mutex_unlock(&sort_type_mutex);
1778*12758SJulian.Pullen@Sun.COM 	return (type);
1779*12758SJulian.Pullen@Sun.COM }
1780*12758SJulian.Pullen@Sun.COM 
1781*12758SJulian.Pullen@Sun.COM static void
update_srvsidesort_type(char * service,ns_srvsidesort_t type)1782*12758SJulian.Pullen@Sun.COM update_srvsidesort_type(char *service, ns_srvsidesort_t type)
1783*12758SJulian.Pullen@Sun.COM {
1784*12758SJulian.Pullen@Sun.COM 	int i, size;
1785*12758SJulian.Pullen@Sun.COM 	servicesorttype_t *tmp;
1786*12758SJulian.Pullen@Sun.COM 
1787*12758SJulian.Pullen@Sun.COM 	if (service == NULL)
1788*12758SJulian.Pullen@Sun.COM 		return;
1789*12758SJulian.Pullen@Sun.COM 
1790*12758SJulian.Pullen@Sun.COM 	(void) mutex_lock(&sort_type_mutex);
1791*12758SJulian.Pullen@Sun.COM 
1792*12758SJulian.Pullen@Sun.COM 	for (i = 0; i < sort_type_hwm; i++) {
1793*12758SJulian.Pullen@Sun.COM 		if (strcmp(sort_type[i].service, service) == 0) {
1794*12758SJulian.Pullen@Sun.COM 			sort_type[i].type = type;
1795*12758SJulian.Pullen@Sun.COM 			(void) mutex_unlock(&sort_type_mutex);
1796*12758SJulian.Pullen@Sun.COM 			return;
1797*12758SJulian.Pullen@Sun.COM 		}
1798*12758SJulian.Pullen@Sun.COM 	}
1799*12758SJulian.Pullen@Sun.COM 	if (sort_type == NULL) {
1800*12758SJulian.Pullen@Sun.COM 		size = 10;
1801*12758SJulian.Pullen@Sun.COM 		tmp = malloc(size * sizeof (servicesorttype_t));
1802*12758SJulian.Pullen@Sun.COM 		if (tmp == NULL) {
1803*12758SJulian.Pullen@Sun.COM 			(void) mutex_unlock(&sort_type_mutex);
1804*12758SJulian.Pullen@Sun.COM 			return;
1805*12758SJulian.Pullen@Sun.COM 		}
1806*12758SJulian.Pullen@Sun.COM 		sort_type = tmp;
1807*12758SJulian.Pullen@Sun.COM 		sort_type_size = size;
1808*12758SJulian.Pullen@Sun.COM 	} else if (sort_type_hwm >= sort_type_size) {
1809*12758SJulian.Pullen@Sun.COM 		size = sort_type_size + 10;
1810*12758SJulian.Pullen@Sun.COM 		tmp = realloc(sort_type, size * sizeof (servicesorttype_t));
1811*12758SJulian.Pullen@Sun.COM 		if (tmp == NULL) {
1812*12758SJulian.Pullen@Sun.COM 			(void) mutex_unlock(&sort_type_mutex);
1813*12758SJulian.Pullen@Sun.COM 			return;
1814*12758SJulian.Pullen@Sun.COM 		}
1815*12758SJulian.Pullen@Sun.COM 		sort_type = tmp;
1816*12758SJulian.Pullen@Sun.COM 		sort_type_size = size;
1817*12758SJulian.Pullen@Sun.COM 	}
1818*12758SJulian.Pullen@Sun.COM 	sort_type[sort_type_hwm].service = strdup(service);
1819*12758SJulian.Pullen@Sun.COM 	if (sort_type[sort_type_hwm].service == NULL) {
1820*12758SJulian.Pullen@Sun.COM 		(void) mutex_unlock(&sort_type_mutex);
1821*12758SJulian.Pullen@Sun.COM 		return;
1822*12758SJulian.Pullen@Sun.COM 	}
1823*12758SJulian.Pullen@Sun.COM 	sort_type[sort_type_hwm].type = type;
1824*12758SJulian.Pullen@Sun.COM 	sort_type_hwm++;
1825*12758SJulian.Pullen@Sun.COM 
1826*12758SJulian.Pullen@Sun.COM 	(void) mutex_unlock(&sort_type_mutex);
1827*12758SJulian.Pullen@Sun.COM }
1828*12758SJulian.Pullen@Sun.COM 
18290Sstevel@tonic-gate static int
setup_vlv_params(ns_ldap_cookie_t * cookie)18300Sstevel@tonic-gate setup_vlv_params(ns_ldap_cookie_t *cookie)
18310Sstevel@tonic-gate {
18320Sstevel@tonic-gate 	LDAPControl	**ctrls;
18330Sstevel@tonic-gate 	LDAPsortkey	**sortkeylist;
18340Sstevel@tonic-gate 	LDAPControl	*sortctrl = NULL;
18350Sstevel@tonic-gate 	LDAPControl	*vlvctrl = NULL;
18360Sstevel@tonic-gate 	LDAPVirtualList	vlist;
1837*12758SJulian.Pullen@Sun.COM 	char		*sortattr;
18380Sstevel@tonic-gate 	int		rc;
1839*12758SJulian.Pullen@Sun.COM 	int		free_sort = FALSE;
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 	_freeControlList(&cookie->p_serverctrls);
18420Sstevel@tonic-gate 
1843*12758SJulian.Pullen@Sun.COM 	if (cookie->sortTypeTry == SSS_UNKNOWN)
1844*12758SJulian.Pullen@Sun.COM 		cookie->sortTypeTry = get_srvsidesort_type(cookie->service);
1845*12758SJulian.Pullen@Sun.COM 	if (cookie->sortTypeTry == SSS_UNKNOWN)
1846*12758SJulian.Pullen@Sun.COM 		cookie->sortTypeTry = SSS_SINGLE_ATTR;
1847*12758SJulian.Pullen@Sun.COM 
1848*12758SJulian.Pullen@Sun.COM 	if (cookie->sortTypeTry == SSS_SINGLE_ATTR) {
1849*12758SJulian.Pullen@Sun.COM 		if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
1850*12758SJulian.Pullen@Sun.COM 		    cookie->i_sortattr) {
1851*12758SJulian.Pullen@Sun.COM 			sortattr =  __ns_ldap_mapAttribute(cookie->service,
1852*12758SJulian.Pullen@Sun.COM 			    cookie->i_sortattr);
1853*12758SJulian.Pullen@Sun.COM 			free_sort = TRUE;
1854*12758SJulian.Pullen@Sun.COM 		} else if (cookie->i_sortattr) {
1855*12758SJulian.Pullen@Sun.COM 			sortattr = (char *)cookie->i_sortattr;
1856*12758SJulian.Pullen@Sun.COM 		} else {
1857*12758SJulian.Pullen@Sun.COM 			sortattr = "cn";
1858*12758SJulian.Pullen@Sun.COM 		}
1859*12758SJulian.Pullen@Sun.COM 	} else {
1860*12758SJulian.Pullen@Sun.COM 		sortattr = "cn uid";
1861*12758SJulian.Pullen@Sun.COM 	}
1862*12758SJulian.Pullen@Sun.COM 
1863*12758SJulian.Pullen@Sun.COM 	rc = ldap_create_sort_keylist(&sortkeylist, sortattr);
1864*12758SJulian.Pullen@Sun.COM 	if (free_sort)
1865*12758SJulian.Pullen@Sun.COM 		free(sortattr);
18660Sstevel@tonic-gate 	if (rc != LDAP_SUCCESS) {
18670Sstevel@tonic-gate 		(void) ldap_get_option(cookie->conn->ld,
18684765Smj162486 		    LDAP_OPT_ERROR_NUMBER, &rc);
18690Sstevel@tonic-gate 		return (rc);
18700Sstevel@tonic-gate 	}
18710Sstevel@tonic-gate 	rc = ldap_create_sort_control(cookie->conn->ld,
18724765Smj162486 	    sortkeylist, 1, &sortctrl);
18730Sstevel@tonic-gate 	ldap_free_sort_keylist(sortkeylist);
18740Sstevel@tonic-gate 	if (rc != LDAP_SUCCESS) {
18750Sstevel@tonic-gate 		(void) ldap_get_option(cookie->conn->ld,
18764765Smj162486 		    LDAP_OPT_ERROR_NUMBER, &rc);
18770Sstevel@tonic-gate 		return (rc);
18780Sstevel@tonic-gate 	}
18790Sstevel@tonic-gate 
18800Sstevel@tonic-gate 	vlist.ldvlist_index = cookie->index;
18810Sstevel@tonic-gate 	vlist.ldvlist_size = 0;
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 	vlist.ldvlist_before_count = 0;
18840Sstevel@tonic-gate 	vlist.ldvlist_after_count = LISTPAGESIZE-1;
18850Sstevel@tonic-gate 	vlist.ldvlist_attrvalue = NULL;
18860Sstevel@tonic-gate 	vlist.ldvlist_extradata = NULL;
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate 	rc = ldap_create_virtuallist_control(cookie->conn->ld,
18894765Smj162486 	    &vlist, &vlvctrl);
18900Sstevel@tonic-gate 	if (rc != LDAP_SUCCESS) {
18910Sstevel@tonic-gate 		ldap_control_free(sortctrl);
18920Sstevel@tonic-gate 		(void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
18934765Smj162486 		    &rc);
18940Sstevel@tonic-gate 		return (rc);
18950Sstevel@tonic-gate 	}
18960Sstevel@tonic-gate 
18970Sstevel@tonic-gate 	ctrls = (LDAPControl **)calloc(3, sizeof (LDAPControl *));
18980Sstevel@tonic-gate 	if (ctrls == NULL) {
18990Sstevel@tonic-gate 		ldap_control_free(sortctrl);
19000Sstevel@tonic-gate 		ldap_control_free(vlvctrl);
19010Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
19020Sstevel@tonic-gate 	}
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 	ctrls[0] = sortctrl;
19050Sstevel@tonic-gate 	ctrls[1] = vlvctrl;
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 	cookie->p_serverctrls = ctrls;
19080Sstevel@tonic-gate 	return (LDAP_SUCCESS);
19090Sstevel@tonic-gate }
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate static int
setup_simplepg_params(ns_ldap_cookie_t * cookie)19120Sstevel@tonic-gate setup_simplepg_params(ns_ldap_cookie_t *cookie)
19130Sstevel@tonic-gate {
19140Sstevel@tonic-gate 	LDAPControl	**ctrls;
19150Sstevel@tonic-gate 	LDAPControl	*pgctrl = NULL;
19160Sstevel@tonic-gate 	int		rc;
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate 	_freeControlList(&cookie->p_serverctrls);
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	rc = ldap_create_page_control(cookie->conn->ld, LISTPAGESIZE,
19214765Smj162486 	    cookie->ctrlCookie, (char)0, &pgctrl);
19220Sstevel@tonic-gate 	if (rc != LDAP_SUCCESS) {
19230Sstevel@tonic-gate 		(void) ldap_get_option(cookie->conn->ld, LDAP_OPT_ERROR_NUMBER,
19244765Smj162486 		    &rc);
19250Sstevel@tonic-gate 		return (rc);
19260Sstevel@tonic-gate 	}
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 	ctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
19290Sstevel@tonic-gate 	if (ctrls == NULL) {
19300Sstevel@tonic-gate 		ldap_control_free(pgctrl);
19310Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
19320Sstevel@tonic-gate 	}
19330Sstevel@tonic-gate 	ctrls[0] = pgctrl;
19340Sstevel@tonic-gate 	cookie->p_serverctrls = ctrls;
19350Sstevel@tonic-gate 	return (LDAP_SUCCESS);
19360Sstevel@tonic-gate }
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate static void
proc_result_referrals(ns_ldap_cookie_t * cookie)19390Sstevel@tonic-gate proc_result_referrals(ns_ldap_cookie_t *cookie)
19400Sstevel@tonic-gate {
19410Sstevel@tonic-gate 	int 		errCode, i, rc;
19420Sstevel@tonic-gate 	char 		**referrals = NULL;
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate 	/*
19450Sstevel@tonic-gate 	 * Only follow one level of referrals, i.e.
19460Sstevel@tonic-gate 	 * if already in referral mode, do nothing
19470Sstevel@tonic-gate 	 */
19480Sstevel@tonic-gate 	if (cookie->refpos == NULL) {
19490Sstevel@tonic-gate 		cookie->new_state = END_RESULT;
19500Sstevel@tonic-gate 		rc = ldap_parse_result(cookie->conn->ld,
19514765Smj162486 		    cookie->resultMsg,
19524765Smj162486 		    &errCode, NULL,
19534765Smj162486 		    NULL, &referrals,
19544765Smj162486 		    NULL, 0);
19550Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
19560Sstevel@tonic-gate 			(void) ldap_get_option(cookie->conn->ld,
19574765Smj162486 			    LDAP_OPT_ERROR_NUMBER,
19584765Smj162486 			    &cookie->err_rc);
19590Sstevel@tonic-gate 			cookie->new_state = LDAP_ERROR;
19600Sstevel@tonic-gate 			return;
19610Sstevel@tonic-gate 		}
19620Sstevel@tonic-gate 		if (errCode == LDAP_REFERRAL) {
19630Sstevel@tonic-gate 			for (i = 0; referrals[i] != NULL;
19644765Smj162486 			    i++) {
19650Sstevel@tonic-gate 				/* add to referral list */
19660Sstevel@tonic-gate 				rc = __s_api_addRefInfo(
19674765Smj162486 				    &cookie->reflist,
19684765Smj162486 				    referrals[i],
19694765Smj162486 				    cookie->basedn,
19704765Smj162486 				    &cookie->scope,
19714765Smj162486 				    cookie->filter,
19724765Smj162486 				    cookie->conn->ld);
19730Sstevel@tonic-gate 				if (rc != NS_LDAP_SUCCESS) {
19740Sstevel@tonic-gate 					cookie->new_state =
19754765Smj162486 					    ERROR;
19760Sstevel@tonic-gate 					break;
19770Sstevel@tonic-gate 				}
19780Sstevel@tonic-gate 			}
19790Sstevel@tonic-gate 			ldap_value_free(referrals);
19800Sstevel@tonic-gate 		}
19810Sstevel@tonic-gate 	}
19820Sstevel@tonic-gate }
19830Sstevel@tonic-gate 
19840Sstevel@tonic-gate static void
proc_search_references(ns_ldap_cookie_t * cookie)19850Sstevel@tonic-gate proc_search_references(ns_ldap_cookie_t *cookie)
19860Sstevel@tonic-gate {
19870Sstevel@tonic-gate 	char 		**refurls = NULL;
19880Sstevel@tonic-gate 	int 		i, rc;
19890Sstevel@tonic-gate 
19900Sstevel@tonic-gate 	/*
19910Sstevel@tonic-gate 	 * Only follow one level of referrals, i.e.
19920Sstevel@tonic-gate 	 * if already in referral mode, do nothing
19930Sstevel@tonic-gate 	 */
19940Sstevel@tonic-gate 	if (cookie->refpos == NULL) {
19950Sstevel@tonic-gate 		refurls = ldap_get_reference_urls(
19964765Smj162486 		    cookie->conn->ld,
19974765Smj162486 		    cookie->resultMsg);
19980Sstevel@tonic-gate 		if (refurls == NULL) {
19990Sstevel@tonic-gate 			(void) ldap_get_option(cookie->conn->ld,
20004765Smj162486 			    LDAP_OPT_ERROR_NUMBER,
20014765Smj162486 			    &cookie->err_rc);
20020Sstevel@tonic-gate 			cookie->new_state = LDAP_ERROR;
20030Sstevel@tonic-gate 			return;
20040Sstevel@tonic-gate 		}
20050Sstevel@tonic-gate 		for (i = 0; refurls[i] != NULL; i++) {
20060Sstevel@tonic-gate 			/* add to referral list */
20070Sstevel@tonic-gate 			rc = __s_api_addRefInfo(
20084765Smj162486 			    &cookie->reflist,
20094765Smj162486 			    refurls[i],
20104765Smj162486 			    cookie->basedn,
20114765Smj162486 			    &cookie->scope,
20124765Smj162486 			    cookie->filter,
20134765Smj162486 			    cookie->conn->ld);
20140Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
20150Sstevel@tonic-gate 				cookie->new_state =
20164765Smj162486 				    ERROR;
20170Sstevel@tonic-gate 				break;
20180Sstevel@tonic-gate 			}
20190Sstevel@tonic-gate 		}
20200Sstevel@tonic-gate 		/* free allocated storage */
20210Sstevel@tonic-gate 		for (i = 0; refurls[i] != NULL; i++)
20220Sstevel@tonic-gate 			free(refurls[i]);
20230Sstevel@tonic-gate 	}
20240Sstevel@tonic-gate }
20250Sstevel@tonic-gate 
20260Sstevel@tonic-gate static ns_state_t
multi_result(ns_ldap_cookie_t * cookie)20270Sstevel@tonic-gate multi_result(ns_ldap_cookie_t *cookie)
20280Sstevel@tonic-gate {
20290Sstevel@tonic-gate 	char		errstr[MAXERROR];
20300Sstevel@tonic-gate 	char		*err;
20310Sstevel@tonic-gate 	ns_ldap_error_t **errorp = NULL;
20320Sstevel@tonic-gate 	LDAPControl	**retCtrls = NULL;
20330Sstevel@tonic-gate 	int		i, rc;
20340Sstevel@tonic-gate 	int		errCode;
20350Sstevel@tonic-gate 	int		finished = 0;
20360Sstevel@tonic-gate 	unsigned long	target_posp = 0;
20370Sstevel@tonic-gate 	unsigned long	list_size = 0;
20380Sstevel@tonic-gate 	unsigned int	count = 0;
20390Sstevel@tonic-gate 	char 		**referrals = NULL;
20400Sstevel@tonic-gate 
20410Sstevel@tonic-gate 	if (cookie->listType == VLVCTRLFLAG) {
20420Sstevel@tonic-gate 		rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
20434765Smj162486 		    &errCode, NULL, NULL, &referrals, &retCtrls, 0);
20440Sstevel@tonic-gate 		if (rc != LDAP_SUCCESS) {
20450Sstevel@tonic-gate 			(void) ldap_get_option(cookie->conn->ld,
20464765Smj162486 			    LDAP_OPT_ERROR_NUMBER,
20474765Smj162486 			    &cookie->err_rc);
20480Sstevel@tonic-gate 			(void) sprintf(errstr,
20494765Smj162486 			    gettext("LDAP ERROR (%d): %s.\n"),
20504765Smj162486 			    cookie->err_rc,
20514765Smj162486 			    gettext(ldap_err2string(cookie->err_rc)));
20520Sstevel@tonic-gate 			err = strdup(errstr);
20530Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
20544765Smj162486 			    NULL);
20550Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INTERNAL;
20560Sstevel@tonic-gate 			cookie->errorp = *errorp;
20570Sstevel@tonic-gate 			return (LDAP_ERROR);
20580Sstevel@tonic-gate 		}
20590Sstevel@tonic-gate 		if (errCode == LDAP_REFERRAL) {
20600Sstevel@tonic-gate 			for (i = 0; referrals[i] != NULL;
20614765Smj162486 			    i++) {
20620Sstevel@tonic-gate 				/* add to referral list */
20630Sstevel@tonic-gate 				rc = __s_api_addRefInfo(
20644765Smj162486 				    &cookie->reflist,
20654765Smj162486 				    referrals[i],
20664765Smj162486 				    cookie->basedn,
20674765Smj162486 				    &cookie->scope,
20684765Smj162486 				    cookie->filter,
20694765Smj162486 				    cookie->conn->ld);
20700Sstevel@tonic-gate 				if (rc != NS_LDAP_SUCCESS) {
20714765Smj162486 					ldap_value_free(
20724765Smj162486 					    referrals);
20730Sstevel@tonic-gate 					if (retCtrls)
20740Sstevel@tonic-gate 						ldap_controls_free(
20754765Smj162486 						    retCtrls);
20760Sstevel@tonic-gate 					return (ERROR);
20770Sstevel@tonic-gate 				}
20780Sstevel@tonic-gate 			}
20790Sstevel@tonic-gate 			ldap_value_free(referrals);
20800Sstevel@tonic-gate 			if (retCtrls)
20810Sstevel@tonic-gate 				ldap_controls_free(retCtrls);
20820Sstevel@tonic-gate 			return (END_RESULT);
20830Sstevel@tonic-gate 		}
20840Sstevel@tonic-gate 		if (retCtrls) {
20850Sstevel@tonic-gate 			rc = ldap_parse_virtuallist_control(
20864765Smj162486 			    cookie->conn->ld, retCtrls,
20874765Smj162486 			    &target_posp, &list_size, &errCode);
20880Sstevel@tonic-gate 			if (rc == LDAP_SUCCESS) {
2089*12758SJulian.Pullen@Sun.COM 				/*
2090*12758SJulian.Pullen@Sun.COM 				 * AD does not return valid target_posp
2091*12758SJulian.Pullen@Sun.COM 				 * and list_size
2092*12758SJulian.Pullen@Sun.COM 				 */
2093*12758SJulian.Pullen@Sun.COM 				if (target_posp != 0 && list_size != 0) {
2094*12758SJulian.Pullen@Sun.COM 					cookie->index =
2095*12758SJulian.Pullen@Sun.COM 					    target_posp + LISTPAGESIZE;
2096*12758SJulian.Pullen@Sun.COM 					if (cookie->index > list_size)
2097*12758SJulian.Pullen@Sun.COM 						finished = 1;
2098*12758SJulian.Pullen@Sun.COM 				} else {
2099*12758SJulian.Pullen@Sun.COM 					if (cookie->entryCount < LISTPAGESIZE)
2100*12758SJulian.Pullen@Sun.COM 						finished = 1;
2101*12758SJulian.Pullen@Sun.COM 					else
2102*12758SJulian.Pullen@Sun.COM 						cookie->index +=
2103*12758SJulian.Pullen@Sun.COM 						    cookie->entryCount;
21040Sstevel@tonic-gate 				}
21050Sstevel@tonic-gate 			}
21060Sstevel@tonic-gate 			ldap_controls_free(retCtrls);
21070Sstevel@tonic-gate 			retCtrls = NULL;
21080Sstevel@tonic-gate 		}
21090Sstevel@tonic-gate 		else
21100Sstevel@tonic-gate 			finished = 1;
21110Sstevel@tonic-gate 	} else if (cookie->listType == SIMPLEPAGECTRLFLAG) {
21120Sstevel@tonic-gate 		rc = ldap_parse_result(cookie->conn->ld, cookie->resultMsg,
21134765Smj162486 		    &errCode, NULL, NULL, &referrals, &retCtrls, 0);
21140Sstevel@tonic-gate 		if (rc != LDAP_SUCCESS) {
21150Sstevel@tonic-gate 			(void) ldap_get_option(cookie->conn->ld,
21164765Smj162486 			    LDAP_OPT_ERROR_NUMBER,
21174765Smj162486 			    &cookie->err_rc);
21180Sstevel@tonic-gate 			(void) sprintf(errstr,
21194765Smj162486 			    gettext("LDAP ERROR (%d): %s.\n"),
21204765Smj162486 			    cookie->err_rc,
21214765Smj162486 			    gettext(ldap_err2string(cookie->err_rc)));
21220Sstevel@tonic-gate 			err = strdup(errstr);
21230Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
21244765Smj162486 			    NULL);
21250Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INTERNAL;
21260Sstevel@tonic-gate 			cookie->errorp = *errorp;
21270Sstevel@tonic-gate 			return (LDAP_ERROR);
21280Sstevel@tonic-gate 		}
21290Sstevel@tonic-gate 		if (errCode == LDAP_REFERRAL) {
21300Sstevel@tonic-gate 			for (i = 0; referrals[i] != NULL;
21314765Smj162486 			    i++) {
21320Sstevel@tonic-gate 				/* add to referral list */
21330Sstevel@tonic-gate 				rc = __s_api_addRefInfo(
21344765Smj162486 				    &cookie->reflist,
21354765Smj162486 				    referrals[i],
21364765Smj162486 				    cookie->basedn,
21374765Smj162486 				    &cookie->scope,
21384765Smj162486 				    cookie->filter,
21394765Smj162486 				    cookie->conn->ld);
21400Sstevel@tonic-gate 				if (rc != NS_LDAP_SUCCESS) {
21414765Smj162486 					ldap_value_free(
21424765Smj162486 					    referrals);
21430Sstevel@tonic-gate 					if (retCtrls)
21440Sstevel@tonic-gate 						ldap_controls_free(
21454765Smj162486 						    retCtrls);
21460Sstevel@tonic-gate 					return (ERROR);
21470Sstevel@tonic-gate 				}
21480Sstevel@tonic-gate 			}
21490Sstevel@tonic-gate 			ldap_value_free(referrals);
21500Sstevel@tonic-gate 			if (retCtrls)
21510Sstevel@tonic-gate 				ldap_controls_free(retCtrls);
21520Sstevel@tonic-gate 			return (END_RESULT);
21530Sstevel@tonic-gate 		}
21540Sstevel@tonic-gate 		if (retCtrls) {
21550Sstevel@tonic-gate 			if (cookie->ctrlCookie)
21560Sstevel@tonic-gate 				ber_bvfree(cookie->ctrlCookie);
21570Sstevel@tonic-gate 			cookie->ctrlCookie = NULL;
21580Sstevel@tonic-gate 			rc = ldap_parse_page_control(
21594765Smj162486 			    cookie->conn->ld, retCtrls,
21604765Smj162486 			    &count, &cookie->ctrlCookie);
21610Sstevel@tonic-gate 			if (rc == LDAP_SUCCESS) {
21620Sstevel@tonic-gate 				if ((cookie->ctrlCookie == NULL) ||
21634765Smj162486 				    (cookie->ctrlCookie->bv_val == NULL) ||
21644765Smj162486 				    (cookie->ctrlCookie->bv_len == 0))
21650Sstevel@tonic-gate 					finished = 1;
21660Sstevel@tonic-gate 			}
21670Sstevel@tonic-gate 			ldap_controls_free(retCtrls);
21680Sstevel@tonic-gate 			retCtrls = NULL;
21690Sstevel@tonic-gate 		}
21700Sstevel@tonic-gate 		else
21710Sstevel@tonic-gate 			finished = 1;
21720Sstevel@tonic-gate 	}
21730Sstevel@tonic-gate 	if (!finished && cookie->listType == VLVCTRLFLAG)
21740Sstevel@tonic-gate 		return (NEXT_VLV);
21750Sstevel@tonic-gate 	if (!finished && cookie->listType == SIMPLEPAGECTRLFLAG)
21760Sstevel@tonic-gate 		return (NEXT_PAGE);
21770Sstevel@tonic-gate 	if (finished)
21780Sstevel@tonic-gate 		return (END_RESULT);
21790Sstevel@tonic-gate 	return (ERROR);
21800Sstevel@tonic-gate }
21810Sstevel@tonic-gate 
21820Sstevel@tonic-gate /*
21836722Smj162486  * clear_results(ns_ldap_cookie_t):
21846722Smj162486  *
21856722Smj162486  * Attempt to obtain remnants of ldap responses and free them.  If remnants are
21866722Smj162486  * not obtained within a certain time period tell the server we wish to abandon
21876722Smj162486  * the request.
21886722Smj162486  *
21896722Smj162486  * Note that we do not initially tell the server to abandon the request as that
21906722Smj162486  * can be an expensive operation for the server, while it is cheap for us to
21916722Smj162486  * just flush the input.
21926722Smj162486  *
21936722Smj162486  * If something was to remain in libldap queue as a result of some error then
21946722Smj162486  * it would be freed later during drop connection call or when no other
21956722Smj162486  * requests share the connection.
21966722Smj162486  */
21976722Smj162486 static void
clear_results(ns_ldap_cookie_t * cookie)21986722Smj162486 clear_results(ns_ldap_cookie_t *cookie)
21996722Smj162486 {
22006722Smj162486 	int rc;
22016722Smj162486 	if (cookie->conn != NULL && cookie->conn->ld != NULL &&
22026842Sth160488 	    (cookie->connectionId != -1 ||
22036842Sth160488 	    (cookie->conn_user != NULL &&
22046842Sth160488 	    cookie->conn_user->conn_mt != NULL)) &&
22056842Sth160488 	    cookie->msgId != 0) {
22066722Smj162486 		/*
22076722Smj162486 		 * We need to cleanup the rest of response (if there is such)
22086722Smj162486 		 * and LDAP abandon is too heavy for LDAP servers, so we will
22096722Smj162486 		 * wait for the rest of response till timeout and "process" it.
22106722Smj162486 		 */
22116722Smj162486 		rc = ldap_result(cookie->conn->ld, cookie->msgId, LDAP_MSG_ALL,
22126722Smj162486 		    (struct timeval *)&cookie->search_timeout,
22136722Smj162486 		    &cookie->resultMsg);
2214*12758SJulian.Pullen@Sun.COM 		if (rc != -1 && rc != 0 && cookie->resultMsg != NULL) {
22156722Smj162486 			(void) ldap_msgfree(cookie->resultMsg);
2216*12758SJulian.Pullen@Sun.COM 			cookie->resultMsg = NULL;
2217*12758SJulian.Pullen@Sun.COM 		}
2218*12758SJulian.Pullen@Sun.COM 
22196722Smj162486 		/*
22206722Smj162486 		 * If there was timeout then we will send  ABANDON request to
22216722Smj162486 		 * LDAP server to decrease load.
22226722Smj162486 		 */
22236722Smj162486 		if (rc == 0)
22246722Smj162486 			(void) ldap_abandon_ext(cookie->conn->ld, cookie->msgId,
22256722Smj162486 			    NULL, NULL);
22266722Smj162486 		/* Disassociate cookie with msgId */
22276722Smj162486 		cookie->msgId = 0;
22286722Smj162486 	}
22296722Smj162486 }
22306722Smj162486 
22316722Smj162486 /*
22320Sstevel@tonic-gate  * This state machine performs one or more LDAP searches to a given
22330Sstevel@tonic-gate  * directory server using service search descriptors and schema
22340Sstevel@tonic-gate  * mapping as appropriate.  The approximate pseudocode for
22350Sstevel@tonic-gate  * this routine is the following:
22360Sstevel@tonic-gate  *    Given the current configuration [set/reset connection etc.]
22370Sstevel@tonic-gate  *    and the current service search descriptor list
22380Sstevel@tonic-gate  *        or default search filter parameters
22390Sstevel@tonic-gate  *    foreach (service search filter) {
22400Sstevel@tonic-gate  *        initialize the filter [via filter_init if appropriate]
22410Sstevel@tonic-gate  *		  get a valid session/connection (preferably the current one)
22420Sstevel@tonic-gate  *					Recover if the connection is lost
22430Sstevel@tonic-gate  *        perform the search
22440Sstevel@tonic-gate  *        foreach (result entry) {
22450Sstevel@tonic-gate  *            process result [via callback if appropriate]
22460Sstevel@tonic-gate  *                save result for caller if accepted.
22470Sstevel@tonic-gate  *                exit and return all collected if allResults found;
22480Sstevel@tonic-gate  *        }
22490Sstevel@tonic-gate  *    }
22500Sstevel@tonic-gate  *    return collected results and exit
22510Sstevel@tonic-gate  */
22520Sstevel@tonic-gate 
22530Sstevel@tonic-gate static
22540Sstevel@tonic-gate ns_state_t
search_state_machine(ns_ldap_cookie_t * cookie,ns_state_t state,int cycle)22550Sstevel@tonic-gate search_state_machine(ns_ldap_cookie_t *cookie, ns_state_t state, int cycle)
22560Sstevel@tonic-gate {
22570Sstevel@tonic-gate 	char		errstr[MAXERROR];
22580Sstevel@tonic-gate 	char		*err;
2259493Ssdussud 	int		rc, ret;
22606842Sth160488 	int		rc_save;
22610Sstevel@tonic-gate 	ns_ldap_entry_t	*nextEntry;
22620Sstevel@tonic-gate 	ns_ldap_error_t *error = NULL;
22630Sstevel@tonic-gate 	ns_ldap_error_t **errorp;
22646616Sdm199847 	struct timeval	tv;
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate 	errorp = &error;
22670Sstevel@tonic-gate 	cookie->state = state;
22683387Schinlong 	errstr[0] = '\0';
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 	for (;;) {
22710Sstevel@tonic-gate 		switch (cookie->state) {
22724765Smj162486 		case CLEAR_RESULTS:
22736722Smj162486 			clear_results(cookie);
22744765Smj162486 			cookie->new_state = EXIT;
22754765Smj162486 			break;
22761179Svv149972 		case GET_ACCT_MGMT_INFO:
22771179Svv149972 			/*
22781179Svv149972 			 * Set the flag to get ldap account management controls.
22791179Svv149972 			 */
22801179Svv149972 			cookie->nopasswd_acct_mgmt = 1;
22811179Svv149972 			cookie->new_state = INIT;
22821179Svv149972 			break;
22830Sstevel@tonic-gate 		case EXIT:
22840Sstevel@tonic-gate 			/* state engine/connection cleaned up in delete */
22850Sstevel@tonic-gate 			if (cookie->attribute) {
22860Sstevel@tonic-gate 				__s_api_free2dArray(cookie->attribute);
22870Sstevel@tonic-gate 				cookie->attribute = NULL;
22880Sstevel@tonic-gate 			}
22890Sstevel@tonic-gate 			if (cookie->reflist) {
22900Sstevel@tonic-gate 				__s_api_deleteRefInfo(cookie->reflist);
22910Sstevel@tonic-gate 				cookie->reflist = NULL;
22920Sstevel@tonic-gate 			}
22930Sstevel@tonic-gate 			return (EXIT);
22940Sstevel@tonic-gate 		case INIT:
22950Sstevel@tonic-gate 			cookie->sdpos = NULL;
22960Sstevel@tonic-gate 			cookie->new_state = NEXT_SEARCH_DESCRIPTOR;
22970Sstevel@tonic-gate 			if (cookie->attribute) {
22980Sstevel@tonic-gate 				__s_api_free2dArray(cookie->attribute);
22990Sstevel@tonic-gate 				cookie->attribute = NULL;
23000Sstevel@tonic-gate 			}
23010Sstevel@tonic-gate 			if ((cookie->i_flags & NS_LDAP_NOMAP) == 0 &&
23024765Smj162486 			    cookie->i_attr) {
23030Sstevel@tonic-gate 				cookie->attribute =
23044765Smj162486 				    __ns_ldap_mapAttributeList(
23054765Smj162486 				    cookie->service,
23064765Smj162486 				    cookie->i_attr);
23070Sstevel@tonic-gate 			}
23080Sstevel@tonic-gate 			break;
23096842Sth160488 		case REINIT:
23106842Sth160488 			/* Check if we've reached MAX retries. */
23116842Sth160488 			cookie->retries++;
23126842Sth160488 			if (cookie->retries > NS_LIST_TRY_MAX - 1) {
23136842Sth160488 				cookie->new_state = LDAP_ERROR;
23146842Sth160488 				break;
23156842Sth160488 			}
23166842Sth160488 
23176842Sth160488 			/*
23186842Sth160488 			 * Even if we still have retries left, check
23196842Sth160488 			 * if retry is possible.
23206842Sth160488 			 */
23216842Sth160488 			if (cookie->conn_user != NULL) {
23226842Sth160488 				int		retry;
23236842Sth160488 				ns_conn_mgmt_t	*cmg;
23246842Sth160488 				cmg = cookie->conn_user->conn_mgmt;
23256842Sth160488 				retry = cookie->conn_user->retry;
23266842Sth160488 				if (cmg != NULL && cmg->cfg_reloaded == 1)
23276842Sth160488 					retry = 1;
23286842Sth160488 				if (retry == 0) {
23296842Sth160488 					cookie->new_state = LDAP_ERROR;
23306842Sth160488 					break;
23316842Sth160488 				}
23326842Sth160488 			}
23336842Sth160488 			/*
23346842Sth160488 			 * Free results if any, reset to the first
23356842Sth160488 			 * search descriptor and start a new session.
23366842Sth160488 			 */
23376842Sth160488 			if (cookie->resultMsg != NULL) {
23386842Sth160488 				(void) ldap_msgfree(cookie->resultMsg);
23396842Sth160488 				cookie->resultMsg = NULL;
23406842Sth160488 			}
23416842Sth160488 			(void) __ns_ldap_freeError(&cookie->errorp);
23426842Sth160488 			(void) __ns_ldap_freeResult(&cookie->result);
23436842Sth160488 			cookie->sdpos = cookie->sdlist;
23446842Sth160488 			cookie->err_from_result = 0;
23456842Sth160488 			cookie->err_rc = 0;
23466842Sth160488 			cookie->new_state = NEXT_SESSION;
23476842Sth160488 			break;
23480Sstevel@tonic-gate 		case NEXT_SEARCH_DESCRIPTOR:
23490Sstevel@tonic-gate 			/* get next search descriptor */
23500Sstevel@tonic-gate 			if (cookie->sdpos == NULL) {
23510Sstevel@tonic-gate 				cookie->sdpos = cookie->sdlist;
23520Sstevel@tonic-gate 				cookie->new_state = GET_SESSION;
23530Sstevel@tonic-gate 			} else {
23540Sstevel@tonic-gate 				cookie->sdpos++;
23550Sstevel@tonic-gate 				cookie->new_state = NEXT_SEARCH;
23560Sstevel@tonic-gate 			}
23570Sstevel@tonic-gate 			if (*cookie->sdpos == NULL)
23580Sstevel@tonic-gate 				cookie->new_state = EXIT;
23590Sstevel@tonic-gate 			break;
23600Sstevel@tonic-gate 		case GET_SESSION:
23610Sstevel@tonic-gate 			if (get_current_session(cookie) < 0)
23620Sstevel@tonic-gate 				cookie->new_state = NEXT_SESSION;
23630Sstevel@tonic-gate 			else
23640Sstevel@tonic-gate 				cookie->new_state = NEXT_SEARCH;
23650Sstevel@tonic-gate 			break;
23660Sstevel@tonic-gate 		case NEXT_SESSION:
23670Sstevel@tonic-gate 			if (get_next_session(cookie) < 0)
23680Sstevel@tonic-gate 				cookie->new_state = RESTART_SESSION;
23690Sstevel@tonic-gate 			else
23700Sstevel@tonic-gate 				cookie->new_state = NEXT_SEARCH;
23710Sstevel@tonic-gate 			break;
23720Sstevel@tonic-gate 		case RESTART_SESSION:
23730Sstevel@tonic-gate 			if (cookie->i_flags & NS_LDAP_HARD) {
23740Sstevel@tonic-gate 				cookie->new_state = NEXT_SESSION;
23750Sstevel@tonic-gate 				break;
23760Sstevel@tonic-gate 			}
23770Sstevel@tonic-gate 			(void) sprintf(errstr,
23784765Smj162486 			    gettext("Session error no available conn.\n"),
23794765Smj162486 			    state);
23800Sstevel@tonic-gate 			err = strdup(errstr);
23810Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
23824765Smj162486 			    NULL);
23830Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INTERNAL;
23840Sstevel@tonic-gate 			cookie->errorp = *errorp;
23850Sstevel@tonic-gate 			cookie->new_state = EXIT;
23860Sstevel@tonic-gate 			break;
23870Sstevel@tonic-gate 		case NEXT_SEARCH:
23880Sstevel@tonic-gate 			/* setup referrals search if necessary */
23890Sstevel@tonic-gate 			if (cookie->refpos) {
23900Sstevel@tonic-gate 				if (setup_referral_search(cookie) < 0) {
23910Sstevel@tonic-gate 					cookie->new_state = EXIT;
23920Sstevel@tonic-gate 					break;
23930Sstevel@tonic-gate 				}
23940Sstevel@tonic-gate 			} else if (setup_next_search(cookie) < 0) {
23950Sstevel@tonic-gate 				cookie->new_state = EXIT;
23960Sstevel@tonic-gate 				break;
23970Sstevel@tonic-gate 			}
23980Sstevel@tonic-gate 			/* only do VLV/PAGE on scopes onelevel/subtree */
23990Sstevel@tonic-gate 			if (paging_supported(cookie)) {
24000Sstevel@tonic-gate 				if (cookie->use_paging &&
24010Sstevel@tonic-gate 				    (cookie->scope != LDAP_SCOPE_BASE)) {
24020Sstevel@tonic-gate 					cookie->index = 1;
24030Sstevel@tonic-gate 					if (cookie->listType == VLVCTRLFLAG)
24040Sstevel@tonic-gate 						cookie->new_state = NEXT_VLV;
24050Sstevel@tonic-gate 					else
24060Sstevel@tonic-gate 						cookie->new_state = NEXT_PAGE;
24070Sstevel@tonic-gate 					break;
24080Sstevel@tonic-gate 				}
24090Sstevel@tonic-gate 			}
24100Sstevel@tonic-gate 			cookie->new_state = ONE_SEARCH;
24110Sstevel@tonic-gate 			break;
24120Sstevel@tonic-gate 		case NEXT_VLV:
24130Sstevel@tonic-gate 			rc = setup_vlv_params(cookie);
24140Sstevel@tonic-gate 			if (rc != LDAP_SUCCESS) {
24150Sstevel@tonic-gate 				cookie->err_rc = rc;
24160Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
24170Sstevel@tonic-gate 				break;
24180Sstevel@tonic-gate 			}
24190Sstevel@tonic-gate 			cookie->next_state = MULTI_RESULT;
24200Sstevel@tonic-gate 			cookie->new_state = DO_SEARCH;
24210Sstevel@tonic-gate 			break;
24220Sstevel@tonic-gate 		case NEXT_PAGE:
24230Sstevel@tonic-gate 			rc = setup_simplepg_params(cookie);
24240Sstevel@tonic-gate 			if (rc != LDAP_SUCCESS) {
24250Sstevel@tonic-gate 				cookie->err_rc = rc;
24260Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
24270Sstevel@tonic-gate 				break;
24280Sstevel@tonic-gate 			}
24290Sstevel@tonic-gate 			cookie->next_state = MULTI_RESULT;
24300Sstevel@tonic-gate 			cookie->new_state = DO_SEARCH;
24310Sstevel@tonic-gate 			break;
24320Sstevel@tonic-gate 		case ONE_SEARCH:
24330Sstevel@tonic-gate 			cookie->next_state = NEXT_RESULT;
24340Sstevel@tonic-gate 			cookie->new_state = DO_SEARCH;
24350Sstevel@tonic-gate 			break;
24360Sstevel@tonic-gate 		case DO_SEARCH:
2437*12758SJulian.Pullen@Sun.COM 			cookie->entryCount = 0;
24380Sstevel@tonic-gate 			rc = ldap_search_ext(cookie->conn->ld,
24394765Smj162486 			    cookie->basedn,
24404765Smj162486 			    cookie->scope,
24414765Smj162486 			    cookie->filter,
24424765Smj162486 			    cookie->attribute,
24434765Smj162486 			    0,
24444765Smj162486 			    cookie->p_serverctrls,
24454765Smj162486 			    NULL,
24464765Smj162486 			    &cookie->search_timeout, 0,
24474765Smj162486 			    &cookie->msgId);
24480Sstevel@tonic-gate 			if (rc != LDAP_SUCCESS) {
24490Sstevel@tonic-gate 				if (rc == LDAP_BUSY ||
24500Sstevel@tonic-gate 				    rc == LDAP_UNAVAILABLE ||
24510Sstevel@tonic-gate 				    rc == LDAP_UNWILLING_TO_PERFORM ||
24520Sstevel@tonic-gate 				    rc == LDAP_CONNECT_ERROR ||
24530Sstevel@tonic-gate 				    rc == LDAP_SERVER_DOWN) {
24540Sstevel@tonic-gate 
24556842Sth160488 					if (cookie->reinit_on_retriable_err) {
24566842Sth160488 						cookie->err_rc = rc;
24576842Sth160488 						cookie->new_state = REINIT;
24586842Sth160488 					} else
24596842Sth160488 						cookie->new_state =
24606842Sth160488 						    NEXT_SESSION;
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 					/*
24630Sstevel@tonic-gate 					 * If not able to reach the
24640Sstevel@tonic-gate 					 * server, inform the ldap
24650Sstevel@tonic-gate 					 * cache manager that the
24660Sstevel@tonic-gate 					 * server should be removed
24670Sstevel@tonic-gate 					 * from it's server list.
24680Sstevel@tonic-gate 					 * Thus, the manager will not
24690Sstevel@tonic-gate 					 * return this server on the next
24700Sstevel@tonic-gate 					 * get-server request and will
24710Sstevel@tonic-gate 					 * also reduce the server list
24720Sstevel@tonic-gate 					 * refresh TTL, so that it will
24730Sstevel@tonic-gate 					 * find out sooner when the server
24740Sstevel@tonic-gate 					 * is up again.
24750Sstevel@tonic-gate 					 */
24766842Sth160488 					if ((rc == LDAP_CONNECT_ERROR ||
24776842Sth160488 					    rc == LDAP_SERVER_DOWN) &&
24786842Sth160488 					    (cookie->conn_user == NULL ||
24796842Sth160488 					    cookie->conn_user->conn_mt ==
24806842Sth160488 					    NULL)) {
2481493Ssdussud 						ret = __s_api_removeServer(
24820Sstevel@tonic-gate 						    cookie->conn->serverAddr);
24836842Sth160488 						if (ret == NS_CACHE_NOSERVER &&
2484493Ssdussud 						    cookie->conn_auth_type
24854765Smj162486 						    == NS_LDAP_AUTH_NONE) {
2486493Ssdussud 							/*
2487493Ssdussud 							 * Couldn't remove
2488493Ssdussud 							 * server from server
2489493Ssdussud 							 * list.
2490493Ssdussud 							 * Exit to avoid
2491493Ssdussud 							 * potential infinite
2492493Ssdussud 							 * loop.
2493493Ssdussud 							 */
2494493Ssdussud 							cookie->err_rc = rc;
2495493Ssdussud 							cookie->new_state =
2496493Ssdussud 							    LDAP_ERROR;
2497493Ssdussud 						}
24980Sstevel@tonic-gate 						if (cookie->connectionId > -1) {
24992830Sdjl 							/*
25002830Sdjl 							 * NS_LDAP_NEW_CONN
25012830Sdjl 							 * indicates that the
25022830Sdjl 							 * connection should
25032830Sdjl 							 * be deleted, not
25042830Sdjl 							 * kept alive
25052830Sdjl 							 */
25062830Sdjl 							DropConnection(
25074765Smj162486 							    cookie->
25084765Smj162486 							    connectionId,
25094765Smj162486 							    NS_LDAP_NEW_CONN);
25102830Sdjl 							cookie->connectionId =
25114765Smj162486 							    -1;
25120Sstevel@tonic-gate 						}
25136842Sth160488 					} else if ((rc == LDAP_CONNECT_ERROR ||
25146842Sth160488 					    rc == LDAP_SERVER_DOWN) &&
25159944SSreedhar.Chalamalasetti@Sun.COM 					    cookie->conn_user != NULL) {
25169944SSreedhar.Chalamalasetti@Sun.COM 						if (cookie->
25179944SSreedhar.Chalamalasetti@Sun.COM 						    reinit_on_retriable_err) {
25189944SSreedhar.Chalamalasetti@Sun.COM 							/*
25199944SSreedhar.Chalamalasetti@Sun.COM 							 * MT connection not
25209944SSreedhar.Chalamalasetti@Sun.COM 							 * usable, close it
25219944SSreedhar.Chalamalasetti@Sun.COM 							 * before REINIT.
25229944SSreedhar.Chalamalasetti@Sun.COM 							 * rc has already
25239944SSreedhar.Chalamalasetti@Sun.COM 							 * been saved in
25249944SSreedhar.Chalamalasetti@Sun.COM 							 * cookie->err_rc above.
25259944SSreedhar.Chalamalasetti@Sun.COM 							 */
25269944SSreedhar.Chalamalasetti@Sun.COM 							__s_api_conn_mt_close(
25279944SSreedhar.Chalamalasetti@Sun.COM 							    cookie->conn_user,
25289944SSreedhar.Chalamalasetti@Sun.COM 							    rc,
25299944SSreedhar.Chalamalasetti@Sun.COM 							    &cookie->errorp);
25309944SSreedhar.Chalamalasetti@Sun.COM 						} else {
25319944SSreedhar.Chalamalasetti@Sun.COM 							/*
25329944SSreedhar.Chalamalasetti@Sun.COM 							 * MT connection not
25339944SSreedhar.Chalamalasetti@Sun.COM 							 * usable, close it in
25349944SSreedhar.Chalamalasetti@Sun.COM 							 * the LDAP_ERROR state.
25359944SSreedhar.Chalamalasetti@Sun.COM 							 * A retry will be done
25369944SSreedhar.Chalamalasetti@Sun.COM 							 * next if allowed.
25379944SSreedhar.Chalamalasetti@Sun.COM 							 */
25389944SSreedhar.Chalamalasetti@Sun.COM 							cookie->err_rc = rc;
25399944SSreedhar.Chalamalasetti@Sun.COM 							cookie->new_state =
25409944SSreedhar.Chalamalasetti@Sun.COM 							    LDAP_ERROR;
25419944SSreedhar.Chalamalasetti@Sun.COM 						}
25420Sstevel@tonic-gate 					}
25430Sstevel@tonic-gate 					break;
25440Sstevel@tonic-gate 				}
25450Sstevel@tonic-gate 				cookie->err_rc = rc;
25460Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
25470Sstevel@tonic-gate 				break;
25480Sstevel@tonic-gate 			}
25490Sstevel@tonic-gate 			cookie->new_state = cookie->next_state;
25500Sstevel@tonic-gate 			break;
25510Sstevel@tonic-gate 		case NEXT_RESULT:
25526616Sdm199847 			/*
25536616Sdm199847 			 * Caller (e.g. __ns_ldap_list_batch_add)
25546616Sdm199847 			 * does not want to block on ldap_result().
25556616Sdm199847 			 * Therefore we execute ldap_result() with
25566616Sdm199847 			 * a zeroed timeval.
25576616Sdm199847 			 */
25586616Sdm199847 			if (cookie->no_wait == B_TRUE)
25596616Sdm199847 				(void) memset(&tv, 0, sizeof (tv));
25606616Sdm199847 			else
25616616Sdm199847 				tv = cookie->search_timeout;
25620Sstevel@tonic-gate 			rc = ldap_result(cookie->conn->ld, cookie->msgId,
25634765Smj162486 			    LDAP_MSG_ONE,
25646616Sdm199847 			    &tv,
25654765Smj162486 			    &cookie->resultMsg);
25660Sstevel@tonic-gate 			if (rc == LDAP_RES_SEARCH_RESULT) {
25670Sstevel@tonic-gate 				cookie->new_state = END_RESULT;
25680Sstevel@tonic-gate 				/* check and process referrals info */
25690Sstevel@tonic-gate 				if (cookie->followRef)
25700Sstevel@tonic-gate 					proc_result_referrals(
25714765Smj162486 					    cookie);
25720Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
25730Sstevel@tonic-gate 				cookie->resultMsg = NULL;
25740Sstevel@tonic-gate 				break;
25750Sstevel@tonic-gate 			}
25760Sstevel@tonic-gate 			/* handle referrals if necessary */
25770Sstevel@tonic-gate 			if (rc == LDAP_RES_SEARCH_REFERENCE) {
25780Sstevel@tonic-gate 				if (cookie->followRef)
25790Sstevel@tonic-gate 					proc_search_references(cookie);
25800Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
25810Sstevel@tonic-gate 				cookie->resultMsg = NULL;
25820Sstevel@tonic-gate 				break;
25830Sstevel@tonic-gate 			}
25840Sstevel@tonic-gate 			if (rc != LDAP_RES_SEARCH_ENTRY) {
25850Sstevel@tonic-gate 				switch (rc) {
25860Sstevel@tonic-gate 				case 0:
25876616Sdm199847 					if (cookie->no_wait == B_TRUE) {
25886616Sdm199847 						(void) ldap_msgfree(
25896616Sdm199847 						    cookie->resultMsg);
25906616Sdm199847 						cookie->resultMsg = NULL;
25916616Sdm199847 						return (cookie->new_state);
25926616Sdm199847 					}
25930Sstevel@tonic-gate 					rc = LDAP_TIMEOUT;
25940Sstevel@tonic-gate 					break;
25950Sstevel@tonic-gate 				case -1:
25960Sstevel@tonic-gate 					rc = ldap_get_lderrno(cookie->conn->ld,
25974765Smj162486 					    NULL, NULL);
25980Sstevel@tonic-gate 					break;
25990Sstevel@tonic-gate 				default:
26000Sstevel@tonic-gate 					rc = ldap_result2error(cookie->conn->ld,
26014765Smj162486 					    cookie->resultMsg, 1);
26020Sstevel@tonic-gate 					break;
26030Sstevel@tonic-gate 				}
26046842Sth160488 				if ((rc == LDAP_TIMEOUT ||
26056842Sth160488 				    rc == LDAP_SERVER_DOWN) &&
26066842Sth160488 				    (cookie->conn_user == NULL ||
26076842Sth160488 				    cookie->conn_user->conn_mt == NULL)) {
26083387Schinlong 					if (rc == LDAP_TIMEOUT)
26093387Schinlong 						(void) __s_api_removeServer(
26103387Schinlong 						    cookie->conn->serverAddr);
26113387Schinlong 					if (cookie->connectionId > -1) {
26124765Smj162486 						DropConnection(
26134765Smj162486 						    cookie->connectionId,
26144765Smj162486 						    NS_LDAP_NEW_CONN);
26153387Schinlong 						cookie->connectionId = -1;
26163387Schinlong 					}
26173387Schinlong 					cookie->err_from_result = 1;
26183387Schinlong 				}
26190Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
26200Sstevel@tonic-gate 				cookie->resultMsg = NULL;
26210Sstevel@tonic-gate 				if (rc == LDAP_BUSY ||
26220Sstevel@tonic-gate 				    rc == LDAP_UNAVAILABLE ||
26233387Schinlong 				    rc == LDAP_UNWILLING_TO_PERFORM) {
26246842Sth160488 					if (cookie->reinit_on_retriable_err) {
26256842Sth160488 						cookie->err_rc = rc;
26266842Sth160488 						cookie->err_from_result = 1;
26276842Sth160488 						cookie->new_state = REINIT;
26286842Sth160488 					} else
26296842Sth160488 						cookie->new_state =
26306842Sth160488 						    NEXT_SESSION;
26316842Sth160488 					break;
26326842Sth160488 				}
26336842Sth160488 				if ((rc == LDAP_CONNECT_ERROR ||
26346842Sth160488 				    rc == LDAP_SERVER_DOWN) &&
26356842Sth160488 				    cookie->reinit_on_retriable_err) {
26366842Sth160488 					ns_ldap_error_t *errorp = NULL;
26376842Sth160488 					cookie->err_rc = rc;
26386842Sth160488 					cookie->err_from_result = 1;
26396842Sth160488 					cookie->new_state = REINIT;
26406842Sth160488 					if (cookie->conn_user != NULL)
26416842Sth160488 						__s_api_conn_mt_close(
26426842Sth160488 						    cookie->conn_user,
26436842Sth160488 						    rc, &errorp);
26446842Sth160488 					if (errorp != NULL) {
26456842Sth160488 						(void) __ns_ldap_freeError(
26466842Sth160488 						    &cookie->errorp);
26476842Sth160488 						cookie->errorp = errorp;
26486842Sth160488 					}
26490Sstevel@tonic-gate 					break;
26500Sstevel@tonic-gate 				}
26510Sstevel@tonic-gate 				cookie->err_rc = rc;
26520Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
26530Sstevel@tonic-gate 				break;
26540Sstevel@tonic-gate 			}
26550Sstevel@tonic-gate 			/* else LDAP_RES_SEARCH_ENTRY */
26561179Svv149972 			/* get account management response control */
26571179Svv149972 			if (cookie->nopasswd_acct_mgmt == 1) {
26581179Svv149972 				rc = ldap_get_entry_controls(cookie->conn->ld,
26594765Smj162486 				    cookie->resultMsg,
26604765Smj162486 				    &(cookie->resultctrl));
26611179Svv149972 				if (rc != LDAP_SUCCESS) {
26621179Svv149972 					cookie->new_state = LDAP_ERROR;
26631179Svv149972 					cookie->err_rc = rc;
26641179Svv149972 					break;
26651179Svv149972 				}
26661179Svv149972 			}
26670Sstevel@tonic-gate 			rc = __s_api_getEntry(cookie);
26680Sstevel@tonic-gate 			(void) ldap_msgfree(cookie->resultMsg);
26690Sstevel@tonic-gate 			cookie->resultMsg = NULL;
26700Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
26710Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
26720Sstevel@tonic-gate 				break;
26730Sstevel@tonic-gate 			}
26740Sstevel@tonic-gate 			cookie->new_state = PROCESS_RESULT;
26750Sstevel@tonic-gate 			cookie->next_state = NEXT_RESULT;
26760Sstevel@tonic-gate 			break;
26770Sstevel@tonic-gate 		case MULTI_RESULT:
26786616Sdm199847 			if (cookie->no_wait == B_TRUE)
26796616Sdm199847 				(void) memset(&tv, 0, sizeof (tv));
26806616Sdm199847 			else
26816616Sdm199847 				tv = cookie->search_timeout;
26820Sstevel@tonic-gate 			rc = ldap_result(cookie->conn->ld, cookie->msgId,
26834765Smj162486 			    LDAP_MSG_ONE,
26846616Sdm199847 			    &tv,
26854765Smj162486 			    &cookie->resultMsg);
26860Sstevel@tonic-gate 			if (rc == LDAP_RES_SEARCH_RESULT) {
26870Sstevel@tonic-gate 				rc = ldap_result2error(cookie->conn->ld,
26884765Smj162486 				    cookie->resultMsg, 0);
2689*12758SJulian.Pullen@Sun.COM 				if (rc == LDAP_ADMINLIMIT_EXCEEDED &&
2690*12758SJulian.Pullen@Sun.COM 				    cookie->listType == VLVCTRLFLAG &&
2691*12758SJulian.Pullen@Sun.COM 				    cookie->sortTypeTry == SSS_SINGLE_ATTR) {
2692*12758SJulian.Pullen@Sun.COM 					/* Try old "cn uid" server side sort */
2693*12758SJulian.Pullen@Sun.COM 					cookie->sortTypeTry = SSS_CN_UID_ATTRS;
2694*12758SJulian.Pullen@Sun.COM 					cookie->new_state = NEXT_VLV;
2695*12758SJulian.Pullen@Sun.COM 					(void) ldap_msgfree(cookie->resultMsg);
2696*12758SJulian.Pullen@Sun.COM 					cookie->resultMsg = NULL;
2697*12758SJulian.Pullen@Sun.COM 					break;
2698*12758SJulian.Pullen@Sun.COM 				}
26990Sstevel@tonic-gate 				if (rc != LDAP_SUCCESS) {
27000Sstevel@tonic-gate 					cookie->err_rc = rc;
27010Sstevel@tonic-gate 					cookie->new_state = LDAP_ERROR;
27020Sstevel@tonic-gate 					(void) ldap_msgfree(cookie->resultMsg);
2703*12758SJulian.Pullen@Sun.COM 					cookie->resultMsg = NULL;
27040Sstevel@tonic-gate 					break;
27050Sstevel@tonic-gate 				}
27060Sstevel@tonic-gate 				cookie->new_state = multi_result(cookie);
27070Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
27080Sstevel@tonic-gate 				cookie->resultMsg = NULL;
27090Sstevel@tonic-gate 				break;
27100Sstevel@tonic-gate 			}
27110Sstevel@tonic-gate 			/* handle referrals if necessary */
27120Sstevel@tonic-gate 			if (rc == LDAP_RES_SEARCH_REFERENCE &&
27134765Smj162486 			    cookie->followRef) {
27140Sstevel@tonic-gate 				proc_search_references(cookie);
27150Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
27160Sstevel@tonic-gate 				cookie->resultMsg = NULL;
27170Sstevel@tonic-gate 				break;
27180Sstevel@tonic-gate 			}
27190Sstevel@tonic-gate 			if (rc != LDAP_RES_SEARCH_ENTRY) {
27200Sstevel@tonic-gate 				switch (rc) {
27210Sstevel@tonic-gate 				case 0:
27226616Sdm199847 					if (cookie->no_wait == B_TRUE) {
27236616Sdm199847 						(void) ldap_msgfree(
27246616Sdm199847 						    cookie->resultMsg);
27256616Sdm199847 						cookie->resultMsg = NULL;
27266616Sdm199847 						return (cookie->new_state);
27276616Sdm199847 					}
27280Sstevel@tonic-gate 					rc = LDAP_TIMEOUT;
27290Sstevel@tonic-gate 					break;
27300Sstevel@tonic-gate 				case -1:
27310Sstevel@tonic-gate 					rc = ldap_get_lderrno(cookie->conn->ld,
27324765Smj162486 					    NULL, NULL);
27330Sstevel@tonic-gate 					break;
27340Sstevel@tonic-gate 				default:
27350Sstevel@tonic-gate 					rc = ldap_result2error(cookie->conn->ld,
27364765Smj162486 					    cookie->resultMsg, 1);
27370Sstevel@tonic-gate 					break;
27380Sstevel@tonic-gate 				}
27396842Sth160488 				if ((rc == LDAP_TIMEOUT ||
27406842Sth160488 				    rc == LDAP_SERVER_DOWN) &&
27416842Sth160488 				    (cookie->conn_user == NULL ||
27426842Sth160488 				    cookie->conn_user->conn_mt == NULL)) {
27433387Schinlong 					if (rc == LDAP_TIMEOUT)
27443387Schinlong 						(void) __s_api_removeServer(
27453387Schinlong 						    cookie->conn->serverAddr);
27463387Schinlong 					if (cookie->connectionId > -1) {
27474765Smj162486 						DropConnection(
27484765Smj162486 						    cookie->connectionId,
27494765Smj162486 						    NS_LDAP_NEW_CONN);
27503387Schinlong 						cookie->connectionId = -1;
27513387Schinlong 					}
27523387Schinlong 					cookie->err_from_result = 1;
27533387Schinlong 				}
27540Sstevel@tonic-gate 				(void) ldap_msgfree(cookie->resultMsg);
27550Sstevel@tonic-gate 				cookie->resultMsg = NULL;
27560Sstevel@tonic-gate 				if (rc == LDAP_BUSY ||
27570Sstevel@tonic-gate 				    rc == LDAP_UNAVAILABLE ||
27583387Schinlong 				    rc == LDAP_UNWILLING_TO_PERFORM) {
27596842Sth160488 					if (cookie->reinit_on_retriable_err) {
27606842Sth160488 						cookie->err_rc = rc;
27616842Sth160488 						cookie->err_from_result = 1;
27626842Sth160488 						cookie->new_state = REINIT;
27636842Sth160488 					} else
27646842Sth160488 						cookie->new_state =
27656842Sth160488 						    NEXT_SESSION;
27666842Sth160488 					break;
27676842Sth160488 				}
2768*12758SJulian.Pullen@Sun.COM 
27696842Sth160488 				if ((rc == LDAP_CONNECT_ERROR ||
27706842Sth160488 				    rc == LDAP_SERVER_DOWN) &&
27716842Sth160488 				    cookie->reinit_on_retriable_err) {
27726842Sth160488 					ns_ldap_error_t *errorp = NULL;
27736842Sth160488 					cookie->err_rc = rc;
27746842Sth160488 					cookie->err_from_result = 1;
27756842Sth160488 					cookie->new_state = REINIT;
27766842Sth160488 					if (cookie->conn_user != NULL)
27776842Sth160488 						__s_api_conn_mt_close(
27786842Sth160488 						    cookie->conn_user,
27796842Sth160488 						    rc, &errorp);
27806842Sth160488 					if (errorp != NULL) {
27816842Sth160488 						(void) __ns_ldap_freeError(
27826842Sth160488 						    &cookie->errorp);
27836842Sth160488 						cookie->errorp = errorp;
27846842Sth160488 					}
27850Sstevel@tonic-gate 					break;
27860Sstevel@tonic-gate 				}
27870Sstevel@tonic-gate 				cookie->err_rc = rc;
27880Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
27890Sstevel@tonic-gate 				break;
27900Sstevel@tonic-gate 			}
27910Sstevel@tonic-gate 			/* else LDAP_RES_SEARCH_ENTRY */
2792*12758SJulian.Pullen@Sun.COM 			cookie->entryCount++;
27930Sstevel@tonic-gate 			rc = __s_api_getEntry(cookie);
27940Sstevel@tonic-gate 			(void) ldap_msgfree(cookie->resultMsg);
27950Sstevel@tonic-gate 			cookie->resultMsg = NULL;
27960Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
27970Sstevel@tonic-gate 				cookie->new_state = LDAP_ERROR;
27980Sstevel@tonic-gate 				break;
27990Sstevel@tonic-gate 			}
2800*12758SJulian.Pullen@Sun.COM 			/*
2801*12758SJulian.Pullen@Sun.COM 			 * If VLV search was successfull save the server
2802*12758SJulian.Pullen@Sun.COM 			 * side sort type tried.
2803*12758SJulian.Pullen@Sun.COM 			 */
2804*12758SJulian.Pullen@Sun.COM 			if (cookie->listType == VLVCTRLFLAG)
2805*12758SJulian.Pullen@Sun.COM 				update_srvsidesort_type(cookie->service,
2806*12758SJulian.Pullen@Sun.COM 				    cookie->sortTypeTry);
2807*12758SJulian.Pullen@Sun.COM 
28080Sstevel@tonic-gate 			cookie->new_state = PROCESS_RESULT;
28090Sstevel@tonic-gate 			cookie->next_state = MULTI_RESULT;
28100Sstevel@tonic-gate 			break;
28110Sstevel@tonic-gate 		case PROCESS_RESULT:
28120Sstevel@tonic-gate 			/* NOTE THIS STATE MAY BE PROCESSED BY CALLER */
28130Sstevel@tonic-gate 			if (cookie->use_usercb && cookie->callback) {
28140Sstevel@tonic-gate 				rc = 0;
28150Sstevel@tonic-gate 				for (nextEntry = cookie->result->entry;
28164765Smj162486 				    nextEntry != NULL;
28174765Smj162486 				    nextEntry = nextEntry->next) {
28180Sstevel@tonic-gate 					rc = (*cookie->callback)(nextEntry,
28194765Smj162486 					    cookie->userdata);
28200Sstevel@tonic-gate 
28210Sstevel@tonic-gate 					if (rc == NS_LDAP_CB_DONE) {
28220Sstevel@tonic-gate 					/* cb doesn't want any more data */
28230Sstevel@tonic-gate 						rc = NS_LDAP_PARTIAL;
28240Sstevel@tonic-gate 						cookie->err_rc = rc;
28250Sstevel@tonic-gate 						break;
28260Sstevel@tonic-gate 					} else if (rc != NS_LDAP_CB_NEXT) {
28270Sstevel@tonic-gate 					/* invalid return code */
28280Sstevel@tonic-gate 						rc = NS_LDAP_OP_FAILED;
28290Sstevel@tonic-gate 						cookie->err_rc = rc;
28300Sstevel@tonic-gate 						break;
28310Sstevel@tonic-gate 					}
28320Sstevel@tonic-gate 				}
28330Sstevel@tonic-gate 				(void) __ns_ldap_freeResult(&cookie->result);
28340Sstevel@tonic-gate 				cookie->result = NULL;
28350Sstevel@tonic-gate 			}
28360Sstevel@tonic-gate 			if (rc != 0) {
28370Sstevel@tonic-gate 				cookie->new_state = EXIT;
28380Sstevel@tonic-gate 				break;
28390Sstevel@tonic-gate 			}
28400Sstevel@tonic-gate 			/* NOTE PREVIOUS STATE SPECIFIES NEXT STATE */
28410Sstevel@tonic-gate 			cookie->new_state = cookie->next_state;
28420Sstevel@tonic-gate 			break;
28430Sstevel@tonic-gate 		case END_PROCESS_RESULT:
28440Sstevel@tonic-gate 			cookie->new_state = cookie->next_state;
28450Sstevel@tonic-gate 			break;
28460Sstevel@tonic-gate 		case END_RESULT:
28470Sstevel@tonic-gate 			/*
28480Sstevel@tonic-gate 			 * XXX DO WE NEED THIS CASE?
28490Sstevel@tonic-gate 			 * if (search is complete) {
28500Sstevel@tonic-gate 			 * 	cookie->new_state = EXIT;
28510Sstevel@tonic-gate 			 * } else
28520Sstevel@tonic-gate 			 */
28530Sstevel@tonic-gate 				/*
28540Sstevel@tonic-gate 				 * entering referral mode if necessary
28550Sstevel@tonic-gate 				 */
28560Sstevel@tonic-gate 				if (cookie->followRef && cookie->reflist)
28570Sstevel@tonic-gate 					cookie->new_state =
28584765Smj162486 					    NEXT_REFERRAL;
28590Sstevel@tonic-gate 				else
28600Sstevel@tonic-gate 					cookie->new_state =
28614765Smj162486 					    NEXT_SEARCH_DESCRIPTOR;
28620Sstevel@tonic-gate 			break;
28630Sstevel@tonic-gate 		case NEXT_REFERRAL:
28640Sstevel@tonic-gate 			/* get next referral info */
28650Sstevel@tonic-gate 			if (cookie->refpos == NULL)
28660Sstevel@tonic-gate 				cookie->refpos =
28674765Smj162486 				    cookie->reflist;
28680Sstevel@tonic-gate 			else
28690Sstevel@tonic-gate 				cookie->refpos =
28704765Smj162486 				    cookie->refpos->next;
28710Sstevel@tonic-gate 			/* check see if done with all referrals */
28720Sstevel@tonic-gate 			if (cookie->refpos != NULL)
28730Sstevel@tonic-gate 				cookie->new_state =
28744765Smj162486 				    GET_REFERRAL_SESSION;
28750Sstevel@tonic-gate 			else {
28760Sstevel@tonic-gate 				__s_api_deleteRefInfo(cookie->reflist);
28770Sstevel@tonic-gate 				cookie->reflist = NULL;
28780Sstevel@tonic-gate 				cookie->new_state =
28794765Smj162486 				    NEXT_SEARCH_DESCRIPTOR;
28806842Sth160488 				if (cookie->conn_user != NULL)
28816842Sth160488 					cookie->conn_user->referral = B_FALSE;
28820Sstevel@tonic-gate 			}
28830Sstevel@tonic-gate 			break;
28840Sstevel@tonic-gate 		case GET_REFERRAL_SESSION:
28850Sstevel@tonic-gate 			if (get_referral_session(cookie) < 0)
28860Sstevel@tonic-gate 				cookie->new_state = EXIT;
28870Sstevel@tonic-gate 			else {
28880Sstevel@tonic-gate 				cookie->new_state = NEXT_SEARCH;
28890Sstevel@tonic-gate 			}
28900Sstevel@tonic-gate 			break;
28910Sstevel@tonic-gate 		case LDAP_ERROR:
28926842Sth160488 			rc_save = cookie->err_rc;
28933387Schinlong 			if (cookie->err_from_result) {
28943387Schinlong 				if (cookie->err_rc == LDAP_SERVER_DOWN) {
28953387Schinlong 					(void) sprintf(errstr,
28964765Smj162486 					    gettext("LDAP ERROR (%d): "
28974765Smj162486 					    "Error occurred during"
28984765Smj162486 					    " receiving results. "
28995671Smj162486 					    "Connection to server lost."),
29004765Smj162486 					    cookie->err_rc);
29013387Schinlong 				} else if (cookie->err_rc == LDAP_TIMEOUT) {
29023387Schinlong 					(void) sprintf(errstr,
29034765Smj162486 					    gettext("LDAP ERROR (%d): "
29044765Smj162486 					    "Error occurred during"
29054765Smj162486 					    " receiving results. %s"
29064765Smj162486 					    "."), cookie->err_rc,
29074765Smj162486 					    ldap_err2string(
29084765Smj162486 					    cookie->err_rc));
29093387Schinlong 				}
29103387Schinlong 			} else
29113387Schinlong 				(void) sprintf(errstr,
29124765Smj162486 				    gettext("LDAP ERROR (%d): %s."),
29134765Smj162486 				    cookie->err_rc,
29144765Smj162486 				    ldap_err2string(cookie->err_rc));
29150Sstevel@tonic-gate 			err = strdup(errstr);
29163387Schinlong 			if (cookie->err_from_result) {
29175671Smj162486 				if (cookie->err_rc == LDAP_SERVER_DOWN) {
29185671Smj162486 					MKERROR(LOG_INFO, *errorp,
29195671Smj162486 					    cookie->err_rc, err, NULL);
29205671Smj162486 				} else {
29215671Smj162486 					MKERROR(LOG_WARNING, *errorp,
29225671Smj162486 					    cookie->err_rc, err, NULL);
29235671Smj162486 				}
29243387Schinlong 			} else {
29253387Schinlong 				MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL,
29264765Smj162486 				    err, NULL);
29273387Schinlong 			}
29280Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INTERNAL;
29290Sstevel@tonic-gate 			cookie->errorp = *errorp;
29306842Sth160488 			if (cookie->conn_user != NULL)  {
29316842Sth160488 				if (rc_save == LDAP_SERVER_DOWN ||
29326842Sth160488 				    rc_save == LDAP_CONNECT_ERROR) {
29336842Sth160488 					/*
29346842Sth160488 					 * MT connection is not usable,
29356842Sth160488 					 * close it.
29366842Sth160488 					 */
29376842Sth160488 					__s_api_conn_mt_close(cookie->conn_user,
29386842Sth160488 					    rc_save, &cookie->errorp);
29396842Sth160488 					return (ERROR);
29406842Sth160488 				}
29416842Sth160488 			}
29420Sstevel@tonic-gate 			return (ERROR);
29430Sstevel@tonic-gate 		default:
29440Sstevel@tonic-gate 		case ERROR:
29450Sstevel@tonic-gate 			(void) sprintf(errstr,
29464765Smj162486 			    gettext("Internal State machine exit (%d).\n"),
29474765Smj162486 			    cookie->state);
29480Sstevel@tonic-gate 			err = strdup(errstr);
29490Sstevel@tonic-gate 			MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err,
29504765Smj162486 			    NULL);
29510Sstevel@tonic-gate 			cookie->err_rc = NS_LDAP_INTERNAL;
29520Sstevel@tonic-gate 			cookie->errorp = *errorp;
29530Sstevel@tonic-gate 			return (ERROR);
29540Sstevel@tonic-gate 		}
29550Sstevel@tonic-gate 
29566842Sth160488 		if (cookie->conn_user != NULL &&
29576842Sth160488 		    cookie->conn_user->bad_mt_conn ==  B_TRUE) {
29586842Sth160488 			__s_api_conn_mt_close(cookie->conn_user, 0, NULL);
29596842Sth160488 			cookie->err_rc = cookie->conn_user->ns_rc;
29606842Sth160488 			cookie->errorp = cookie->conn_user->ns_error;
29616842Sth160488 			cookie->conn_user->ns_error = NULL;
29626842Sth160488 			return (ERROR);
29636842Sth160488 		}
29646842Sth160488 
29650Sstevel@tonic-gate 		if (cycle == ONE_STEP) {
29660Sstevel@tonic-gate 			return (cookie->new_state);
29670Sstevel@tonic-gate 		}
29680Sstevel@tonic-gate 		cookie->state = cookie->new_state;
29690Sstevel@tonic-gate 	}
29700Sstevel@tonic-gate 	/*NOTREACHED*/
29710Sstevel@tonic-gate #if 0
29720Sstevel@tonic-gate 	(void) sprintf(errstr,
29734765Smj162486 	    gettext("Unexpected State machine error.\n"));
29740Sstevel@tonic-gate 	err = strdup(errstr);
29750Sstevel@tonic-gate 	MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, err, NULL);
29760Sstevel@tonic-gate 	cookie->err_rc = NS_LDAP_INTERNAL;
29770Sstevel@tonic-gate 	cookie->errorp = *errorp;
29780Sstevel@tonic-gate 	return (ERROR);
29790Sstevel@tonic-gate #endif
29800Sstevel@tonic-gate }
29810Sstevel@tonic-gate 
29820Sstevel@tonic-gate /*
29839576SJulian.Pullen@Sun.COM  * For a lookup of shadow data, if shadow update is enabled,
29849576SJulian.Pullen@Sun.COM  * check the calling process' privilege to ensure it's
29859576SJulian.Pullen@Sun.COM  * allowed to perform such operation.
29869576SJulian.Pullen@Sun.COM  */
29879576SJulian.Pullen@Sun.COM static int
check_shadow(ns_ldap_cookie_t * cookie,const char * service)29889576SJulian.Pullen@Sun.COM check_shadow(ns_ldap_cookie_t *cookie, const char *service)
29899576SJulian.Pullen@Sun.COM {
29909576SJulian.Pullen@Sun.COM 	char errstr[MAXERROR];
29919576SJulian.Pullen@Sun.COM 	char *err;
29929576SJulian.Pullen@Sun.COM 	boolean_t priv;
29939576SJulian.Pullen@Sun.COM 	/* caller */
29949576SJulian.Pullen@Sun.COM 	priv_set_t *ps;
29959576SJulian.Pullen@Sun.COM 	/* zone */
29969576SJulian.Pullen@Sun.COM 	priv_set_t *zs;
29979576SJulian.Pullen@Sun.COM 
29989576SJulian.Pullen@Sun.COM 	/*
29999576SJulian.Pullen@Sun.COM 	 * If service is "shadow", we may need
30009576SJulian.Pullen@Sun.COM 	 * to use privilege credentials.
30019576SJulian.Pullen@Sun.COM 	 */
30029576SJulian.Pullen@Sun.COM 	if ((strcmp(service, "shadow") == 0) &&
30039576SJulian.Pullen@Sun.COM 	    __ns_ldap_is_shadow_update_enabled()) {
30049576SJulian.Pullen@Sun.COM 		/*
30059576SJulian.Pullen@Sun.COM 		 * Since we release admin credentials after
30069576SJulian.Pullen@Sun.COM 		 * connection is closed and we do not cache
30079576SJulian.Pullen@Sun.COM 		 * them, we allow any root or all zone
30089576SJulian.Pullen@Sun.COM 		 * privilege process to read shadow data.
30099576SJulian.Pullen@Sun.COM 		 */
30109576SJulian.Pullen@Sun.COM 		priv = (geteuid() == 0);
30119576SJulian.Pullen@Sun.COM 		if (!priv) {
30129576SJulian.Pullen@Sun.COM 			/* caller */
30139576SJulian.Pullen@Sun.COM 			ps = priv_allocset();
30149576SJulian.Pullen@Sun.COM 
30159576SJulian.Pullen@Sun.COM 			(void) getppriv(PRIV_EFFECTIVE, ps);
30169576SJulian.Pullen@Sun.COM 			zs = priv_str_to_set("zone", ",", NULL);
30179576SJulian.Pullen@Sun.COM 			priv = priv_isequalset(ps, zs);
30189576SJulian.Pullen@Sun.COM 			priv_freeset(ps);
30199576SJulian.Pullen@Sun.COM 			priv_freeset(zs);
30209576SJulian.Pullen@Sun.COM 		}
30219576SJulian.Pullen@Sun.COM 		if (!priv) {
30229576SJulian.Pullen@Sun.COM 			(void) sprintf(errstr,
30239576SJulian.Pullen@Sun.COM 			    gettext("Permission denied"));
30249576SJulian.Pullen@Sun.COM 			err = strdup(errstr);
30259576SJulian.Pullen@Sun.COM 			if (err == NULL)
30269576SJulian.Pullen@Sun.COM 				return (NS_LDAP_MEMORY);
30279576SJulian.Pullen@Sun.COM 			MKERROR(LOG_INFO, cookie->errorp, NS_LDAP_INTERNAL, err,
30289576SJulian.Pullen@Sun.COM 			    NULL);
30299576SJulian.Pullen@Sun.COM 			return (NS_LDAP_INTERNAL);
30309576SJulian.Pullen@Sun.COM 		}
30319576SJulian.Pullen@Sun.COM 		cookie->i_flags |= NS_LDAP_READ_SHADOW;
30329576SJulian.Pullen@Sun.COM 		/*
30339576SJulian.Pullen@Sun.COM 		 * We do not want to reuse connection (hence
30349576SJulian.Pullen@Sun.COM 		 * keep it open) with admin credentials.
30359576SJulian.Pullen@Sun.COM 		 * If NS_LDAP_KEEP_CONN is set, reject the
30369576SJulian.Pullen@Sun.COM 		 * request.
30379576SJulian.Pullen@Sun.COM 		 */
30389576SJulian.Pullen@Sun.COM 		if (cookie->i_flags & NS_LDAP_KEEP_CONN)
30399576SJulian.Pullen@Sun.COM 			return (NS_LDAP_INVALID_PARAM);
30409576SJulian.Pullen@Sun.COM 		cookie->i_flags |= NS_LDAP_NEW_CONN;
30419576SJulian.Pullen@Sun.COM 	}
30429576SJulian.Pullen@Sun.COM 
30439576SJulian.Pullen@Sun.COM 	return (NS_LDAP_SUCCESS);
30449576SJulian.Pullen@Sun.COM }
30459576SJulian.Pullen@Sun.COM 
30469576SJulian.Pullen@Sun.COM /*
30476616Sdm199847  * internal function for __ns_ldap_list
30480Sstevel@tonic-gate  */
30496616Sdm199847 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)30506616Sdm199847 ldap_list(
30516616Sdm199847 	ns_ldap_list_batch_t *batch,
30520Sstevel@tonic-gate 	const char *service,
30530Sstevel@tonic-gate 	const char *filter,
3054*12758SJulian.Pullen@Sun.COM 	const char *sortattr,
30550Sstevel@tonic-gate 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
30560Sstevel@tonic-gate 	char **realfilter, const void *userdata),
30570Sstevel@tonic-gate 	const char * const *attribute,
30580Sstevel@tonic-gate 	const ns_cred_t *auth,
30590Sstevel@tonic-gate 	const int flags,
30600Sstevel@tonic-gate 	ns_ldap_result_t **rResult, /* return result entries */
30610Sstevel@tonic-gate 	ns_ldap_error_t **errorp,
30626616Sdm199847 	int *rcp,
30630Sstevel@tonic-gate 	int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
30646842Sth160488 	const void *userdata, ns_conn_user_t *conn_user)
30650Sstevel@tonic-gate {
30660Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie;
30670Sstevel@tonic-gate 	ns_ldap_search_desc_t	**sdlist = NULL;
30680Sstevel@tonic-gate 	ns_ldap_search_desc_t	*dptr;
30690Sstevel@tonic-gate 	ns_ldap_error_t		*error = NULL;
30700Sstevel@tonic-gate 	char			**dns = NULL;
30710Sstevel@tonic-gate 	int			scope;
30720Sstevel@tonic-gate 	int			rc;
30733387Schinlong 	int			from_result;
30740Sstevel@tonic-gate 
30750Sstevel@tonic-gate 	*errorp = NULL;
30766616Sdm199847 	*rResult = NULL;
30776616Sdm199847 	*rcp = NS_LDAP_SUCCESS;
30780Sstevel@tonic-gate 
30799576SJulian.Pullen@Sun.COM 	/*
30809576SJulian.Pullen@Sun.COM 	 * Sanity check - NS_LDAP_READ_SHADOW is for our
30819576SJulian.Pullen@Sun.COM 	 * own internal use.
30829576SJulian.Pullen@Sun.COM 	 */
30839576SJulian.Pullen@Sun.COM 	if (flags & NS_LDAP_READ_SHADOW)
30849576SJulian.Pullen@Sun.COM 		return (NS_LDAP_INVALID_PARAM);
30859576SJulian.Pullen@Sun.COM 
30860Sstevel@tonic-gate 	/* Initialize State machine cookie */
30870Sstevel@tonic-gate 	cookie = init_search_state_machine();
30880Sstevel@tonic-gate 	if (cookie == NULL) {
30896616Sdm199847 		*rcp = NS_LDAP_MEMORY;
30900Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
30910Sstevel@tonic-gate 	}
30926842Sth160488 	cookie->conn_user = conn_user;
30930Sstevel@tonic-gate 
30940Sstevel@tonic-gate 	/* see if need to follow referrals */
30950Sstevel@tonic-gate 	rc = __s_api_toFollowReferrals(flags,
30964765Smj162486 	    &cookie->followRef, errorp);
30970Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
30980Sstevel@tonic-gate 		delete_search_cookie(cookie);
30996616Sdm199847 		*rcp = rc;
31000Sstevel@tonic-gate 		return (rc);
31010Sstevel@tonic-gate 	}
31020Sstevel@tonic-gate 
31030Sstevel@tonic-gate 	/* get the service descriptor - or create a default one */
31040Sstevel@tonic-gate 	rc = __s_api_get_SSD_from_SSDtoUse_service(service,
310512022SMichen.Chang@Sun.COM 	    &sdlist, &error);
31060Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
31070Sstevel@tonic-gate 		delete_search_cookie(cookie);
31080Sstevel@tonic-gate 		*errorp = error;
31096616Sdm199847 		*rcp = rc;
31100Sstevel@tonic-gate 		return (rc);
31110Sstevel@tonic-gate 	}
31120Sstevel@tonic-gate 
31130Sstevel@tonic-gate 	if (sdlist == NULL) {
31140Sstevel@tonic-gate 		/* Create default service Desc */
31150Sstevel@tonic-gate 		sdlist = (ns_ldap_search_desc_t **)calloc(2,
31164765Smj162486 		    sizeof (ns_ldap_search_desc_t *));
31170Sstevel@tonic-gate 		if (sdlist == NULL) {
31180Sstevel@tonic-gate 			delete_search_cookie(cookie);
31190Sstevel@tonic-gate 			cookie = NULL;
31206616Sdm199847 			*rcp = NS_LDAP_MEMORY;
31210Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
31220Sstevel@tonic-gate 		}
31230Sstevel@tonic-gate 		dptr = (ns_ldap_search_desc_t *)
31244765Smj162486 		    calloc(1, sizeof (ns_ldap_search_desc_t));
31250Sstevel@tonic-gate 		if (dptr == NULL) {
31260Sstevel@tonic-gate 			free(sdlist);
31270Sstevel@tonic-gate 			delete_search_cookie(cookie);
31280Sstevel@tonic-gate 			cookie = NULL;
31296616Sdm199847 			*rcp = NS_LDAP_MEMORY;
31300Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
31310Sstevel@tonic-gate 		}
31320Sstevel@tonic-gate 		sdlist[0] = dptr;
31330Sstevel@tonic-gate 
31340Sstevel@tonic-gate 		/* default base */
31350Sstevel@tonic-gate 		rc = __s_api_getDNs(&dns, service, &cookie->errorp);
31360Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
31370Sstevel@tonic-gate 			if (dns) {
31380Sstevel@tonic-gate 				__s_api_free2dArray(dns);
31390Sstevel@tonic-gate 				dns = NULL;
31400Sstevel@tonic-gate 			}
31410Sstevel@tonic-gate 			*errorp = cookie->errorp;
31420Sstevel@tonic-gate 			cookie->errorp = NULL;
31430Sstevel@tonic-gate 			delete_search_cookie(cookie);
31440Sstevel@tonic-gate 			cookie = NULL;
31456616Sdm199847 			*rcp = rc;
31460Sstevel@tonic-gate 			return (rc);
31470Sstevel@tonic-gate 		}
31480Sstevel@tonic-gate 		dptr->basedn = strdup(dns[0]);
31490Sstevel@tonic-gate 		__s_api_free2dArray(dns);
31500Sstevel@tonic-gate 		dns = NULL;
31510Sstevel@tonic-gate 
31520Sstevel@tonic-gate 		/* default scope */
31530Sstevel@tonic-gate 		scope = 0;
31540Sstevel@tonic-gate 		rc = __s_api_getSearchScope(&scope, &cookie->errorp);
31550Sstevel@tonic-gate 		dptr->scope = scope;
31560Sstevel@tonic-gate 	}
31570Sstevel@tonic-gate 
31580Sstevel@tonic-gate 	cookie->sdlist = sdlist;
31590Sstevel@tonic-gate 
31600Sstevel@tonic-gate 	/*
31610Sstevel@tonic-gate 	 * use VLV/PAGE control only if NS_LDAP_PAGE_CTRL is set
31620Sstevel@tonic-gate 	 */
31630Sstevel@tonic-gate 	if (flags & NS_LDAP_PAGE_CTRL)
31640Sstevel@tonic-gate 		cookie->use_paging = TRUE;
31650Sstevel@tonic-gate 	else
31660Sstevel@tonic-gate 		cookie->use_paging = FALSE;
31670Sstevel@tonic-gate 
31680Sstevel@tonic-gate 	/* Set up other arguments */
31690Sstevel@tonic-gate 	cookie->userdata = userdata;
31700Sstevel@tonic-gate 	if (init_filter_cb != NULL) {
31710Sstevel@tonic-gate 		cookie->init_filter_cb = init_filter_cb;
31720Sstevel@tonic-gate 		cookie->use_filtercb = 1;
31730Sstevel@tonic-gate 	}
31740Sstevel@tonic-gate 	if (callback != NULL) {
31750Sstevel@tonic-gate 		cookie->callback = callback;
31760Sstevel@tonic-gate 		cookie->use_usercb = 1;
31770Sstevel@tonic-gate 	}
31789576SJulian.Pullen@Sun.COM 
31799576SJulian.Pullen@Sun.COM 	/* check_shadow() may add extra value to cookie->i_flags */
31809576SJulian.Pullen@Sun.COM 	cookie->i_flags = flags;
31810Sstevel@tonic-gate 	if (service) {
31820Sstevel@tonic-gate 		cookie->service = strdup(service);
31830Sstevel@tonic-gate 		if (cookie->service == NULL) {
31840Sstevel@tonic-gate 			delete_search_cookie(cookie);
31850Sstevel@tonic-gate 			cookie = NULL;
31866616Sdm199847 			*rcp = NS_LDAP_MEMORY;
31870Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
31880Sstevel@tonic-gate 		}
31899576SJulian.Pullen@Sun.COM 
31909576SJulian.Pullen@Sun.COM 		/*
31919576SJulian.Pullen@Sun.COM 		 * If given, use the credential given by the caller, and
31929576SJulian.Pullen@Sun.COM 		 * skip the credential check required for shadow update.
31939576SJulian.Pullen@Sun.COM 		 */
31949576SJulian.Pullen@Sun.COM 		if (auth == NULL) {
31959576SJulian.Pullen@Sun.COM 			rc = check_shadow(cookie, service);
31969576SJulian.Pullen@Sun.COM 			if (rc != NS_LDAP_SUCCESS) {
31979576SJulian.Pullen@Sun.COM 				*errorp = cookie->errorp;
31989576SJulian.Pullen@Sun.COM 				cookie->errorp = NULL;
31999576SJulian.Pullen@Sun.COM 				delete_search_cookie(cookie);
32009576SJulian.Pullen@Sun.COM 				cookie = NULL;
32019576SJulian.Pullen@Sun.COM 				*rcp = rc;
32029576SJulian.Pullen@Sun.COM 				return (rc);
32039576SJulian.Pullen@Sun.COM 			}
32049576SJulian.Pullen@Sun.COM 		}
32050Sstevel@tonic-gate 	}
32060Sstevel@tonic-gate 
32070Sstevel@tonic-gate 	cookie->i_filter = strdup(filter);
32080Sstevel@tonic-gate 	cookie->i_attr = attribute;
32090Sstevel@tonic-gate 	cookie->i_auth = auth;
3210*12758SJulian.Pullen@Sun.COM 	cookie->i_sortattr = sortattr;
32110Sstevel@tonic-gate 
32126616Sdm199847 	if (batch != NULL) {
32136616Sdm199847 		cookie->batch = batch;
32146842Sth160488 		cookie->reinit_on_retriable_err = B_TRUE;
32156616Sdm199847 		cookie->no_wait = B_TRUE;
32166616Sdm199847 		(void) search_state_machine(cookie, INIT, 0);
32176616Sdm199847 		cookie->no_wait = B_FALSE;
32186616Sdm199847 		rc = cookie->err_rc;
32196616Sdm199847 
32206616Sdm199847 		if (rc == NS_LDAP_SUCCESS) {
32216616Sdm199847 			/*
32226616Sdm199847 			 * Here rc == NS_LDAP_SUCCESS means that the state
32236616Sdm199847 			 * machine init'ed successfully. The actual status
32246616Sdm199847 			 * of the search will be determined by
32256616Sdm199847 			 * __ns_ldap_list_batch_end(). Add the cookie to our
32266616Sdm199847 			 * batch.
32276616Sdm199847 			 */
32286616Sdm199847 			cookie->caller_result = rResult;
32296616Sdm199847 			cookie->caller_errorp = errorp;
32306616Sdm199847 			cookie->caller_rc = rcp;
32316616Sdm199847 			cookie->next_cookie_in_batch = batch->cookie_list;
32326616Sdm199847 			batch->cookie_list = cookie;
32336616Sdm199847 			batch->nactive++;
32346616Sdm199847 			return (rc);
32356616Sdm199847 		}
32366616Sdm199847 		/*
32376616Sdm199847 		 * If state machine init failed then copy error to the caller
32386616Sdm199847 		 * and delete the cookie.
32396616Sdm199847 		 */
32406616Sdm199847 	} else {
32416616Sdm199847 		(void) search_state_machine(cookie, INIT, 0);
32426616Sdm199847 	}
32430Sstevel@tonic-gate 
32440Sstevel@tonic-gate 	/* Copy results back to user */
32450Sstevel@tonic-gate 	rc = cookie->err_rc;
32466842Sth160488 	if (rc != NS_LDAP_SUCCESS) {
32476842Sth160488 		if (conn_user != NULL && conn_user->ns_error != NULL) {
32486842Sth160488 			*errorp = conn_user->ns_error;
32496842Sth160488 			conn_user->ns_error = NULL;
32506842Sth160488 		} else
32516842Sth160488 			*errorp = cookie->errorp;
32526842Sth160488 	}
32530Sstevel@tonic-gate 	*rResult = cookie->result;
32543387Schinlong 	from_result = cookie->err_from_result;
32550Sstevel@tonic-gate 
32560Sstevel@tonic-gate 	cookie->errorp = NULL;
32570Sstevel@tonic-gate 	cookie->result = NULL;
32580Sstevel@tonic-gate 	delete_search_cookie(cookie);
32590Sstevel@tonic-gate 	cookie = NULL;
32600Sstevel@tonic-gate 
32613387Schinlong 	if (from_result == 0 && *rResult == NULL)
32620Sstevel@tonic-gate 		rc = NS_LDAP_NOTFOUND;
32636616Sdm199847 	*rcp = rc;
32640Sstevel@tonic-gate 	return (rc);
32650Sstevel@tonic-gate }
32660Sstevel@tonic-gate 
32676616Sdm199847 
32686616Sdm199847 /*
32696616Sdm199847  * __ns_ldap_list performs one or more LDAP searches to a given
32706616Sdm199847  * directory server using service search descriptors and schema
32716842Sth160488  * mapping as appropriate. The operation may be retried a
32726842Sth160488  * couple of times in error situations.
32736616Sdm199847  */
32746616Sdm199847 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)32756616Sdm199847 __ns_ldap_list(
32766616Sdm199847 	const char *service,
32776616Sdm199847 	const char *filter,
32786616Sdm199847 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
32796616Sdm199847 	char **realfilter, const void *userdata),
32806616Sdm199847 	const char * const *attribute,
32816616Sdm199847 	const ns_cred_t *auth,
32826616Sdm199847 	const int flags,
32836616Sdm199847 	ns_ldap_result_t **rResult, /* return result entries */
32846616Sdm199847 	ns_ldap_error_t **errorp,
32856616Sdm199847 	int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
32866616Sdm199847 	const void *userdata)
32876616Sdm199847 {
3288*12758SJulian.Pullen@Sun.COM 	int mod_flags;
3289*12758SJulian.Pullen@Sun.COM 	/*
3290*12758SJulian.Pullen@Sun.COM 	 * Strip the NS_LDAP_PAGE_CTRL option as this interface does not
3291*12758SJulian.Pullen@Sun.COM 	 * support this. If you want to use this option call the API
3292*12758SJulian.Pullen@Sun.COM 	 * __ns_ldap_list_sort() with has the sort attribute.
3293*12758SJulian.Pullen@Sun.COM 	 */
3294*12758SJulian.Pullen@Sun.COM 	mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3295*12758SJulian.Pullen@Sun.COM 
3296*12758SJulian.Pullen@Sun.COM 	return (__ns_ldap_list_sort(service, filter, NULL, init_filter_cb,
3297*12758SJulian.Pullen@Sun.COM 	    attribute, auth, mod_flags, rResult, errorp,
3298*12758SJulian.Pullen@Sun.COM 	    callback, userdata));
3299*12758SJulian.Pullen@Sun.COM }
3300*12758SJulian.Pullen@Sun.COM 
3301*12758SJulian.Pullen@Sun.COM /*
3302*12758SJulian.Pullen@Sun.COM  * __ns_ldap_list_sort performs one or more LDAP searches to a given
3303*12758SJulian.Pullen@Sun.COM  * directory server using service search descriptors and schema
3304*12758SJulian.Pullen@Sun.COM  * mapping as appropriate. The operation may be retried a
3305*12758SJulian.Pullen@Sun.COM  * couple of times in error situations.
3306*12758SJulian.Pullen@Sun.COM  */
3307*12758SJulian.Pullen@Sun.COM 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)3308*12758SJulian.Pullen@Sun.COM __ns_ldap_list_sort(
3309*12758SJulian.Pullen@Sun.COM 	const char *service,
3310*12758SJulian.Pullen@Sun.COM 	const char *filter,
3311*12758SJulian.Pullen@Sun.COM 	const char *sortattr,
3312*12758SJulian.Pullen@Sun.COM 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
3313*12758SJulian.Pullen@Sun.COM 	char **realfilter, const void *userdata),
3314*12758SJulian.Pullen@Sun.COM 	const char * const *attribute,
3315*12758SJulian.Pullen@Sun.COM 	const ns_cred_t *auth,
3316*12758SJulian.Pullen@Sun.COM 	const int flags,
3317*12758SJulian.Pullen@Sun.COM 	ns_ldap_result_t **rResult, /* return result entries */
3318*12758SJulian.Pullen@Sun.COM 	ns_ldap_error_t **errorp,
3319*12758SJulian.Pullen@Sun.COM 	int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
3320*12758SJulian.Pullen@Sun.COM 	const void *userdata)
3321*12758SJulian.Pullen@Sun.COM {
33226842Sth160488 	ns_conn_user_t	*cu = NULL;
33236842Sth160488 	int		try_cnt = 0;
33246842Sth160488 	int		rc = NS_LDAP_SUCCESS, trc;
33256842Sth160488 
33266842Sth160488 	for (;;) {
33276842Sth160488 		if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
33286842Sth160488 		    &try_cnt, &rc, errorp) == 0)
33296842Sth160488 			break;
3330*12758SJulian.Pullen@Sun.COM 		rc = ldap_list(NULL, service, filter, sortattr, init_filter_cb,
3331*12758SJulian.Pullen@Sun.COM 		    attribute, auth, flags, rResult, errorp, &trc, callback,
3332*12758SJulian.Pullen@Sun.COM 		    userdata, cu);
33336842Sth160488 	}
33346842Sth160488 
33356842Sth160488 	return (rc);
33366616Sdm199847 }
33376616Sdm199847 
33386616Sdm199847 /*
33396616Sdm199847  * Create and initialize batch for native LDAP lookups
33406616Sdm199847  */
33416616Sdm199847 int
__ns_ldap_list_batch_start(ns_ldap_list_batch_t ** batch)33426616Sdm199847 __ns_ldap_list_batch_start(ns_ldap_list_batch_t **batch)
33436616Sdm199847 {
33446616Sdm199847 	*batch = calloc(1, sizeof (ns_ldap_list_batch_t));
33456616Sdm199847 	if (*batch == NULL)
33466616Sdm199847 		return (NS_LDAP_MEMORY);
33476616Sdm199847 	return (NS_LDAP_SUCCESS);
33486616Sdm199847 }
33496616Sdm199847 
33506616Sdm199847 
33516616Sdm199847 /*
33526616Sdm199847  * Add a LDAP search request to the batch.
33536616Sdm199847  */
33546616Sdm199847 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)33556616Sdm199847 __ns_ldap_list_batch_add(
33566616Sdm199847 	ns_ldap_list_batch_t *batch,
33576616Sdm199847 	const char *service,
33586616Sdm199847 	const char *filter,
33596616Sdm199847 	int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
33606616Sdm199847 	char **realfilter, const void *userdata),
33616616Sdm199847 	const char * const *attribute,
33626616Sdm199847 	const ns_cred_t *auth,
33636616Sdm199847 	const int flags,
33646616Sdm199847 	ns_ldap_result_t **rResult, /* return result entries */
33656616Sdm199847 	ns_ldap_error_t **errorp,
33666616Sdm199847 	int *rcp,
33676616Sdm199847 	int (*callback)(const ns_ldap_entry_t *entry, const void *userdata),
33686616Sdm199847 	const void *userdata)
33696616Sdm199847 {
33706842Sth160488 	ns_conn_user_t	*cu;
33716842Sth160488 	int		rc;
3372*12758SJulian.Pullen@Sun.COM 	int		mod_flags;
33736842Sth160488 
33746842Sth160488 	cu =  __s_api_conn_user_init(NS_CONN_USER_SEARCH, NULL, 0);
33756842Sth160488 	if (cu == NULL) {
33766842Sth160488 		if (rcp != NULL)
33776842Sth160488 			*rcp = NS_LDAP_MEMORY;
33786842Sth160488 		return (NS_LDAP_MEMORY);
33796842Sth160488 	}
33806842Sth160488 
3381*12758SJulian.Pullen@Sun.COM 	/*
3382*12758SJulian.Pullen@Sun.COM 	 * Strip the NS_LDAP_PAGE_CTRL option as the batch interface does not
3383*12758SJulian.Pullen@Sun.COM 	 * support this.
3384*12758SJulian.Pullen@Sun.COM 	 */
3385*12758SJulian.Pullen@Sun.COM 	mod_flags = flags & (~NS_LDAP_PAGE_CTRL);
3386*12758SJulian.Pullen@Sun.COM 
3387*12758SJulian.Pullen@Sun.COM 	rc = ldap_list(batch, service, filter, NULL, init_filter_cb, attribute,
3388*12758SJulian.Pullen@Sun.COM 	    auth, mod_flags, rResult, errorp, rcp, callback, userdata, cu);
33896842Sth160488 
33906842Sth160488 	/*
33916842Sth160488 	 * Free the conn_user if the cookie was not batched. If the cookie
33926842Sth160488 	 * was batched then __ns_ldap_list_batch_end or release will free the
33936842Sth160488 	 * conn_user. The batch API instructs the search_state_machine
33946842Sth160488 	 * to reinit and retry (max 3 times) on retriable LDAP errors.
33956842Sth160488 	 */
33966842Sth160488 	if (rc != NS_LDAP_SUCCESS && cu != NULL) {
33976842Sth160488 		if (cu->conn_mt != NULL)
33986842Sth160488 			__s_api_conn_mt_return(cu);
33996842Sth160488 		__s_api_conn_user_free(cu);
34006842Sth160488 	}
34016842Sth160488 	return (rc);
34026616Sdm199847 }
34036616Sdm199847 
34046616Sdm199847 
34056616Sdm199847 /*
34066616Sdm199847  * Free batch.
34076616Sdm199847  */
34086616Sdm199847 void
__ns_ldap_list_batch_release(ns_ldap_list_batch_t * batch)34096616Sdm199847 __ns_ldap_list_batch_release(ns_ldap_list_batch_t *batch)
34106616Sdm199847 {
34116616Sdm199847 	ns_ldap_cookie_t	*c, *next;
34126616Sdm199847 
34136616Sdm199847 	for (c = batch->cookie_list; c != NULL; c = next) {
34146616Sdm199847 		next = c->next_cookie_in_batch;
34156842Sth160488 		if (c->conn_user != NULL) {
34166842Sth160488 			if (c->conn_user->conn_mt != NULL)
34176842Sth160488 				__s_api_conn_mt_return(c->conn_user);
34186842Sth160488 			__s_api_conn_user_free(c->conn_user);
34196842Sth160488 			c->conn_user = NULL;
34206842Sth160488 		}
34216616Sdm199847 		delete_search_cookie(c);
34226616Sdm199847 	}
34236616Sdm199847 	free(batch);
34246616Sdm199847 }
34256616Sdm199847 
34266842Sth160488 #define	LD_USING_STATE(st) \
34276842Sth160488 	((st == DO_SEARCH) || (st == MULTI_RESULT) || (st == NEXT_RESULT))
34286616Sdm199847 
34296616Sdm199847 /*
34306616Sdm199847  * Process batch. Everytime this function is called it selects an
34316616Sdm199847  * active cookie from the batch and single steps through the
34326616Sdm199847  * search_state_machine for the selected cookie. If lookup associated
34336616Sdm199847  * with the cookie is complete (success or error) then the cookie is
34346616Sdm199847  * removed from the batch and its memory freed.
34356616Sdm199847  *
34366616Sdm199847  * Returns 1 (if batch still has active cookies)
34376616Sdm199847  *         0 (if batch has no more active cookies)
34386616Sdm199847  *        -1 (on errors, *rcp will contain the error code)
34396616Sdm199847  *
34406616Sdm199847  * The caller should call this function in a loop as long as it returns 1
34416616Sdm199847  * to process all the requests added to the batch. The results (and errors)
34426616Sdm199847  * will be available in the locations provided by the caller at the time of
34436616Sdm199847  * __ns_ldap_list_batch_add().
34446616Sdm199847  */
34456616Sdm199847 static
34466616Sdm199847 int
__ns_ldap_list_batch_process(ns_ldap_list_batch_t * batch,int * rcp)34476616Sdm199847 __ns_ldap_list_batch_process(ns_ldap_list_batch_t *batch, int *rcp)
34486616Sdm199847 {
34496616Sdm199847 	ns_ldap_cookie_t	*c, *ptr, **prev;
34506616Sdm199847 	ns_state_t		state;
34516842Sth160488 	ns_ldap_error_t		*errorp = NULL;
34526616Sdm199847 	int			rc;
34536616Sdm199847 
34546616Sdm199847 	/* Check if are already done */
34556616Sdm199847 	if (batch->nactive == 0)
34566616Sdm199847 		return (0);
34576616Sdm199847 
34586616Sdm199847 	/* Get the next cookie from the batch */
34596616Sdm199847 	c = (batch->next_cookie == NULL) ?
34606616Sdm199847 	    batch->cookie_list : batch->next_cookie;
34616616Sdm199847 
34626616Sdm199847 	batch->next_cookie = c->next_cookie_in_batch;
34636616Sdm199847 
34646842Sth160488 	/*
34656842Sth160488 	 * Checks the status of the cookie's connection if it needs
34666842Sth160488 	 * to use that connection for ldap_search_ext or ldap_result.
34676842Sth160488 	 * If the connection is no longer good but worth retrying
34686842Sth160488 	 * then reinit the search_state_machine for this cookie
34696842Sth160488 	 * starting from the first search descriptor. REINIT will
34706842Sth160488 	 * clear any leftover results if max retries have not been
34716842Sth160488 	 * reached and redo the search (which may also involve
34726842Sth160488 	 * following referrals again).
34736842Sth160488 	 *
34746842Sth160488 	 * Note that each cookie in the batch will make this
34756842Sth160488 	 * determination when it reaches one of the LD_USING_STATES.
34766842Sth160488 	 */
34776842Sth160488 	if (LD_USING_STATE(c->new_state) && c->conn_user != NULL) {
34786842Sth160488 		rc = __s_api_setup_getnext(c->conn_user, &c->err_rc, &errorp);
34796842Sth160488 		if (rc == LDAP_BUSY || rc == LDAP_UNAVAILABLE ||
34806842Sth160488 		    rc == LDAP_UNWILLING_TO_PERFORM) {
34816842Sth160488 			if (errorp != NULL) {
34826842Sth160488 				(void) __ns_ldap_freeError(&c->errorp);
34836842Sth160488 				c->errorp = errorp;
34846842Sth160488 			}
34856842Sth160488 			c->new_state = REINIT;
34866842Sth160488 		} else if (rc == LDAP_CONNECT_ERROR ||
34876842Sth160488 		    rc == LDAP_SERVER_DOWN) {
34886842Sth160488 			if (errorp != NULL) {
34896842Sth160488 				(void) __ns_ldap_freeError(&c->errorp);
34906842Sth160488 				c->errorp = errorp;
34916842Sth160488 			}
34926842Sth160488 			c->new_state = REINIT;
34936842Sth160488 			/*
34946842Sth160488 			 * MT connection is not usable,
34956842Sth160488 			 * close it before REINIT.
34966842Sth160488 			 */
34976842Sth160488 			__s_api_conn_mt_close(
34986842Sth160488 			    c->conn_user, rc, NULL);
34996842Sth160488 		} else if (rc != NS_LDAP_SUCCESS) {
35006616Sdm199847 			if (rcp != NULL)
35016616Sdm199847 				*rcp = rc;
35026842Sth160488 			*c->caller_result = NULL;
35036842Sth160488 			*c->caller_errorp = errorp;
35046842Sth160488 			*c->caller_rc = rc;
35056616Sdm199847 			return (-1);
35066616Sdm199847 		}
35076616Sdm199847 	}
35086616Sdm199847 
35096616Sdm199847 	for (;;) {
35106616Sdm199847 		/* Single step through the search_state_machine */
35116616Sdm199847 		state = search_state_machine(c, c->new_state, ONE_STEP);
35126616Sdm199847 		switch (state) {
35136616Sdm199847 		case LDAP_ERROR:
35146616Sdm199847 			(void) search_state_machine(c, state, ONE_STEP);
35156616Sdm199847 			(void) search_state_machine(c, CLEAR_RESULTS, ONE_STEP);
35166616Sdm199847 			/* FALLTHROUGH */
35176616Sdm199847 		case ERROR:
35186616Sdm199847 		case EXIT:
35196616Sdm199847 			*c->caller_result = c->result;
35206616Sdm199847 			*c->caller_errorp = c->errorp;
35216616Sdm199847 			*c->caller_rc =
35226616Sdm199847 			    (c->result == NULL && c->err_from_result == 0)
35236616Sdm199847 			    ? NS_LDAP_NOTFOUND : c->err_rc;
35246616Sdm199847 			c->result = NULL;
35256616Sdm199847 			c->errorp = NULL;
35266616Sdm199847 			/* Remove the cookie from the batch */
35276616Sdm199847 			ptr = batch->cookie_list;
35286616Sdm199847 			prev = &batch->cookie_list;
35296616Sdm199847 			while (ptr != NULL) {
35306616Sdm199847 				if (ptr == c) {
35316616Sdm199847 					*prev = ptr->next_cookie_in_batch;
35326616Sdm199847 					break;
35336616Sdm199847 				}
35346616Sdm199847 				prev = &ptr->next_cookie_in_batch;
35356616Sdm199847 				ptr = ptr->next_cookie_in_batch;
35366616Sdm199847 			}
35376616Sdm199847 			/* Delete cookie and decrement active cookie count */
35386842Sth160488 			if (c->conn_user != NULL) {
35396842Sth160488 				if (c->conn_user->conn_mt != NULL)
35406842Sth160488 					__s_api_conn_mt_return(c->conn_user);
35416842Sth160488 				__s_api_conn_user_free(c->conn_user);
35426842Sth160488 				c->conn_user = NULL;
35436842Sth160488 			}
35446616Sdm199847 			delete_search_cookie(c);
35456616Sdm199847 			batch->nactive--;
35466616Sdm199847 			break;
35476616Sdm199847 		case NEXT_RESULT:
35486616Sdm199847 		case MULTI_RESULT:
35496616Sdm199847 			/*
35506616Sdm199847 			 * This means that search_state_machine needs to do
35516616Sdm199847 			 * another ldap_result() for the cookie in question.
35526616Sdm199847 			 * We only do at most one ldap_result() per call in
35536616Sdm199847 			 * this function and therefore we return. This allows
35546616Sdm199847 			 * the caller to process results from other cookies
35556616Sdm199847 			 * in the batch without getting tied up on just one
35566616Sdm199847 			 * cookie.
35576616Sdm199847 			 */
35586616Sdm199847 			break;
35596616Sdm199847 		default:
35606616Sdm199847 			/*
35616616Sdm199847 			 * This includes states that follow NEXT_RESULT or
35626616Sdm199847 			 * MULTI_RESULT such as PROCESS_RESULT and
35636616Sdm199847 			 * END_PROCESS_RESULT. We continue processing
35646616Sdm199847 			 * this cookie till we reach either the error, exit
35656616Sdm199847 			 * or the result states.
35666616Sdm199847 			 */
35676616Sdm199847 			continue;
35686616Sdm199847 		}
35696616Sdm199847 		break;
35706616Sdm199847 	}
35716616Sdm199847 
35726616Sdm199847 	/* Return 0 if no more cookies left otherwise 1 */
35736616Sdm199847 	return ((batch->nactive > 0) ? 1 : 0);
35746616Sdm199847 }
35756616Sdm199847 
35766616Sdm199847 
35776616Sdm199847 /*
35786616Sdm199847  * Process all the active cookies in the batch and when none
35796616Sdm199847  * remains finalize the batch.
35806616Sdm199847  */
35816616Sdm199847 int
__ns_ldap_list_batch_end(ns_ldap_list_batch_t * batch)35826616Sdm199847 __ns_ldap_list_batch_end(ns_ldap_list_batch_t *batch)
35836616Sdm199847 {
35846616Sdm199847 	int rc = NS_LDAP_SUCCESS;
35856616Sdm199847 	while (__ns_ldap_list_batch_process(batch, &rc) > 0)
35866616Sdm199847 		;
35876616Sdm199847 	__ns_ldap_list_batch_release(batch);
35886616Sdm199847 	return (rc);
35896616Sdm199847 }
35906616Sdm199847 
35910Sstevel@tonic-gate /*
35926842Sth160488  * find_domainname performs one or more LDAP searches to
35930Sstevel@tonic-gate  * find the value of the nisdomain attribute associated with
35946842Sth160488  * the input DN (with no retry).
35950Sstevel@tonic-gate  */
35960Sstevel@tonic-gate 
35970Sstevel@tonic-gate 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)35986842Sth160488 find_domainname(const char *dn, char **domainname, const ns_cred_t *cred,
35996842Sth160488     ns_ldap_error_t **errorp, ns_conn_user_t *conn_user)
36000Sstevel@tonic-gate {
36010Sstevel@tonic-gate 
36020Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie;
36030Sstevel@tonic-gate 	ns_ldap_search_desc_t	**sdlist;
36040Sstevel@tonic-gate 	ns_ldap_search_desc_t	*dptr;
36050Sstevel@tonic-gate 	int			rc;
36060Sstevel@tonic-gate 	char			**value;
36070Sstevel@tonic-gate 	int			flags = 0;
36080Sstevel@tonic-gate 
36090Sstevel@tonic-gate 	*domainname = NULL;
36100Sstevel@tonic-gate 	*errorp = NULL;
36110Sstevel@tonic-gate 
36120Sstevel@tonic-gate 	/* Initialize State machine cookie */
36130Sstevel@tonic-gate 	cookie = init_search_state_machine();
36140Sstevel@tonic-gate 	if (cookie == NULL) {
36150Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
36160Sstevel@tonic-gate 	}
36176842Sth160488 	cookie->conn_user = conn_user;
36180Sstevel@tonic-gate 
36190Sstevel@tonic-gate 	/* see if need to follow referrals */
36200Sstevel@tonic-gate 	rc = __s_api_toFollowReferrals(flags,
36214765Smj162486 	    &cookie->followRef, errorp);
36220Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
36230Sstevel@tonic-gate 		delete_search_cookie(cookie);
36240Sstevel@tonic-gate 		return (rc);
36250Sstevel@tonic-gate 	}
36260Sstevel@tonic-gate 
36270Sstevel@tonic-gate 	/* Create default service Desc */
36280Sstevel@tonic-gate 	sdlist = (ns_ldap_search_desc_t **)calloc(2,
36294765Smj162486 	    sizeof (ns_ldap_search_desc_t *));
36300Sstevel@tonic-gate 	if (sdlist == NULL) {
36310Sstevel@tonic-gate 		delete_search_cookie(cookie);
36320Sstevel@tonic-gate 		cookie = NULL;
36330Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
36340Sstevel@tonic-gate 	}
36350Sstevel@tonic-gate 	dptr = (ns_ldap_search_desc_t *)
36364765Smj162486 	    calloc(1, sizeof (ns_ldap_search_desc_t));
36370Sstevel@tonic-gate 	if (dptr == NULL) {
36380Sstevel@tonic-gate 		free(sdlist);
36390Sstevel@tonic-gate 		delete_search_cookie(cookie);
36400Sstevel@tonic-gate 		cookie = NULL;
36410Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
36420Sstevel@tonic-gate 	}
36430Sstevel@tonic-gate 	sdlist[0] = dptr;
36440Sstevel@tonic-gate 
36450Sstevel@tonic-gate 	/* search base is dn */
36460Sstevel@tonic-gate 	dptr->basedn = strdup(dn);
36470Sstevel@tonic-gate 
36480Sstevel@tonic-gate 	/* search scope is base */
36490Sstevel@tonic-gate 	dptr->scope = NS_LDAP_SCOPE_BASE;
36500Sstevel@tonic-gate 
36510Sstevel@tonic-gate 	/* search filter is "nisdomain=*" */
36520Sstevel@tonic-gate 	dptr->filter = strdup(_NIS_FILTER);
36530Sstevel@tonic-gate 
36540Sstevel@tonic-gate 	cookie->sdlist = sdlist;
36550Sstevel@tonic-gate 	cookie->i_filter = strdup(dptr->filter);
36560Sstevel@tonic-gate 	cookie->i_attr = nis_domain_attrs;
36570Sstevel@tonic-gate 	cookie->i_auth = cred;
36580Sstevel@tonic-gate 	cookie->i_flags = 0;
36590Sstevel@tonic-gate 
36600Sstevel@tonic-gate 	/* Process search */
36610Sstevel@tonic-gate 	rc = search_state_machine(cookie, INIT, 0);
36620Sstevel@tonic-gate 
36630Sstevel@tonic-gate 	/* Copy domain name if found */
36640Sstevel@tonic-gate 	rc = cookie->err_rc;
36656842Sth160488 	if (rc != NS_LDAP_SUCCESS) {
36666842Sth160488 		if (conn_user != NULL && conn_user->ns_error != NULL) {
36676842Sth160488 			*errorp = conn_user->ns_error;
36686842Sth160488 			conn_user->ns_error = NULL;
36696842Sth160488 		} else
36706842Sth160488 			*errorp = cookie->errorp;
36716842Sth160488 	}
36720Sstevel@tonic-gate 	if (cookie->result == NULL)
36730Sstevel@tonic-gate 		rc = NS_LDAP_NOTFOUND;
36740Sstevel@tonic-gate 	if (rc == NS_LDAP_SUCCESS) {
36750Sstevel@tonic-gate 		value = __ns_ldap_getAttr(cookie->result->entry,
36764765Smj162486 		    _NIS_DOMAIN);
36770Sstevel@tonic-gate 		if (value[0])
36780Sstevel@tonic-gate 			*domainname = strdup(value[0]);
36790Sstevel@tonic-gate 		else
36800Sstevel@tonic-gate 			rc = NS_LDAP_NOTFOUND;
36810Sstevel@tonic-gate 	}
36820Sstevel@tonic-gate 	if (cookie->result != NULL)
36830Sstevel@tonic-gate 		(void) __ns_ldap_freeResult(&cookie->result);
36840Sstevel@tonic-gate 	cookie->errorp = NULL;
36850Sstevel@tonic-gate 	delete_search_cookie(cookie);
36860Sstevel@tonic-gate 	cookie = NULL;
36870Sstevel@tonic-gate 	return (rc);
36880Sstevel@tonic-gate }
36890Sstevel@tonic-gate 
36906842Sth160488 /*
36916842Sth160488  * __s_api_find_domainname performs one or more LDAP searches to
36926842Sth160488  * find the value of the nisdomain attribute associated with
36936842Sth160488  * the input DN (with retry).
36946842Sth160488  */
36956842Sth160488 
36966842Sth160488 static int
__s_api_find_domainname(const char * dn,char ** domainname,const ns_cred_t * cred,ns_ldap_error_t ** errorp)36976842Sth160488 __s_api_find_domainname(const char *dn, char **domainname,
36986842Sth160488     const ns_cred_t *cred, ns_ldap_error_t **errorp)
36996842Sth160488 {
37006842Sth160488 	ns_conn_user_t	*cu = NULL;
37016842Sth160488 	int		try_cnt = 0;
37026842Sth160488 	int		rc = NS_LDAP_SUCCESS;
37036842Sth160488 
37046842Sth160488 	for (;;) {
37056842Sth160488 		if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
37066842Sth160488 		    &try_cnt, &rc, errorp) == 0)
37076842Sth160488 			break;
37086842Sth160488 		rc = find_domainname(dn, domainname, cred, errorp, cu);
37096842Sth160488 	}
37106842Sth160488 
37116842Sth160488 	return (rc);
37126842Sth160488 }
37136842Sth160488 
37146842Sth160488 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)37156842Sth160488 firstEntry(
37166842Sth160488     const char *service,
37176842Sth160488     const char *filter,
3718*12758SJulian.Pullen@Sun.COM     const char *sortattr,
37196842Sth160488     int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
37206842Sth160488     char **realfilter, const void *userdata),
37216842Sth160488     const char * const *attribute,
37226842Sth160488     const ns_cred_t *auth,
37236842Sth160488     const int flags,
37246842Sth160488     void **vcookie,
37256842Sth160488     ns_ldap_result_t **result,
37266842Sth160488     ns_ldap_error_t ** errorp,
37276842Sth160488     const void *userdata,
37286842Sth160488     ns_conn_user_t *conn_user)
37290Sstevel@tonic-gate {
37300Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie = NULL;
37310Sstevel@tonic-gate 	ns_ldap_error_t		*error = NULL;
37320Sstevel@tonic-gate 	ns_state_t		state;
37330Sstevel@tonic-gate 	ns_ldap_search_desc_t	**sdlist;
37340Sstevel@tonic-gate 	ns_ldap_search_desc_t	*dptr;
37350Sstevel@tonic-gate 	char			**dns = NULL;
37360Sstevel@tonic-gate 	int			scope;
37370Sstevel@tonic-gate 	int			rc;
37380Sstevel@tonic-gate 
37390Sstevel@tonic-gate 	*errorp = NULL;
37400Sstevel@tonic-gate 	*result = NULL;
37410Sstevel@tonic-gate 
37429576SJulian.Pullen@Sun.COM 	/*
37439576SJulian.Pullen@Sun.COM 	 * Sanity check - NS_LDAP_READ_SHADOW is for our
37449576SJulian.Pullen@Sun.COM 	 * own internal use.
37459576SJulian.Pullen@Sun.COM 	 */
37469576SJulian.Pullen@Sun.COM 	if (flags & NS_LDAP_READ_SHADOW)
37479576SJulian.Pullen@Sun.COM 		return (NS_LDAP_INVALID_PARAM);
37489576SJulian.Pullen@Sun.COM 
37490Sstevel@tonic-gate 	/* get the service descriptor - or create a default one */
37500Sstevel@tonic-gate 	rc = __s_api_get_SSD_from_SSDtoUse_service(service,
375112022SMichen.Chang@Sun.COM 	    &sdlist, &error);
37520Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
37530Sstevel@tonic-gate 		*errorp = error;
37540Sstevel@tonic-gate 		return (rc);
37550Sstevel@tonic-gate 	}
37560Sstevel@tonic-gate 	if (sdlist == NULL) {
37570Sstevel@tonic-gate 		/* Create default service Desc */
37580Sstevel@tonic-gate 		sdlist = (ns_ldap_search_desc_t **)calloc(2,
37594765Smj162486 		    sizeof (ns_ldap_search_desc_t *));
37600Sstevel@tonic-gate 		if (sdlist == NULL) {
37610Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
37620Sstevel@tonic-gate 		}
37630Sstevel@tonic-gate 		dptr = (ns_ldap_search_desc_t *)
37644765Smj162486 		    calloc(1, sizeof (ns_ldap_search_desc_t));
37650Sstevel@tonic-gate 		if (dptr == NULL) {
37660Sstevel@tonic-gate 			free(sdlist);
37670Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
37680Sstevel@tonic-gate 		}
37690Sstevel@tonic-gate 		sdlist[0] = dptr;
37700Sstevel@tonic-gate 
37710Sstevel@tonic-gate 		/* default base */
37720Sstevel@tonic-gate 		rc = __s_api_getDNs(&dns, service, &error);
37730Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
37740Sstevel@tonic-gate 			if (dns) {
37750Sstevel@tonic-gate 				__s_api_free2dArray(dns);
37760Sstevel@tonic-gate 				dns = NULL;
37770Sstevel@tonic-gate 			}
37780Sstevel@tonic-gate 			if (sdlist) {
37790Sstevel@tonic-gate 				(void) __ns_ldap_freeSearchDescriptors(
37804765Smj162486 				    &sdlist);
37810Sstevel@tonic-gate 
37820Sstevel@tonic-gate 				sdlist = NULL;
37830Sstevel@tonic-gate 			}
37840Sstevel@tonic-gate 			*errorp = error;
37850Sstevel@tonic-gate 			return (rc);
37860Sstevel@tonic-gate 		}
37870Sstevel@tonic-gate 		dptr->basedn = strdup(dns[0]);
37880Sstevel@tonic-gate 		__s_api_free2dArray(dns);
37890Sstevel@tonic-gate 		dns = NULL;
37900Sstevel@tonic-gate 
37910Sstevel@tonic-gate 		/* default scope */
37920Sstevel@tonic-gate 		scope = 0;
37930Sstevel@tonic-gate 		cookie = init_search_state_machine();
37940Sstevel@tonic-gate 		if (cookie == NULL) {
37950Sstevel@tonic-gate 			if (sdlist) {
37960Sstevel@tonic-gate 				(void) __ns_ldap_freeSearchDescriptors(&sdlist);
37970Sstevel@tonic-gate 				sdlist = NULL;
37980Sstevel@tonic-gate 			}
37990Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
38000Sstevel@tonic-gate 		}
38010Sstevel@tonic-gate 		rc = __s_api_getSearchScope(&scope, &cookie->errorp);
38020Sstevel@tonic-gate 		dptr->scope = scope;
38030Sstevel@tonic-gate 	}
38040Sstevel@tonic-gate 
38050Sstevel@tonic-gate 	/* Initialize State machine cookie */
38060Sstevel@tonic-gate 	if (cookie == NULL)
38070Sstevel@tonic-gate 		cookie = init_search_state_machine();
38080Sstevel@tonic-gate 	if (cookie == NULL) {
38090Sstevel@tonic-gate 		if (sdlist) {
38100Sstevel@tonic-gate 			(void) __ns_ldap_freeSearchDescriptors(&sdlist);
38110Sstevel@tonic-gate 			sdlist = NULL;
38120Sstevel@tonic-gate 		}
38130Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
38140Sstevel@tonic-gate 	}
38150Sstevel@tonic-gate 
38166842Sth160488 	/* identify self as a getent user */
38176842Sth160488 	cookie->conn_user = conn_user;
38186842Sth160488 
38190Sstevel@tonic-gate 	cookie->sdlist = sdlist;
38200Sstevel@tonic-gate 
38210Sstevel@tonic-gate 	/* see if need to follow referrals */
38220Sstevel@tonic-gate 	rc = __s_api_toFollowReferrals(flags,
38234765Smj162486 	    &cookie->followRef, errorp);
38240Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
38250Sstevel@tonic-gate 		delete_search_cookie(cookie);
38260Sstevel@tonic-gate 		return (rc);
38270Sstevel@tonic-gate 	}
38280Sstevel@tonic-gate 
38290Sstevel@tonic-gate 	/*
38300Sstevel@tonic-gate 	 * use VLV/PAGE control only if NS_LDAP_NO_PAGE_CTRL is not set
38310Sstevel@tonic-gate 	 */
38320Sstevel@tonic-gate 	if (flags & NS_LDAP_NO_PAGE_CTRL)
38330Sstevel@tonic-gate 		cookie->use_paging = FALSE;
38340Sstevel@tonic-gate 	else
38350Sstevel@tonic-gate 		cookie->use_paging = TRUE;
38360Sstevel@tonic-gate 
38370Sstevel@tonic-gate 	/* Set up other arguments */
38380Sstevel@tonic-gate 	cookie->userdata = userdata;
38390Sstevel@tonic-gate 	if (init_filter_cb != NULL) {
38400Sstevel@tonic-gate 		cookie->init_filter_cb = init_filter_cb;
38410Sstevel@tonic-gate 		cookie->use_filtercb = 1;
38420Sstevel@tonic-gate 	}
38430Sstevel@tonic-gate 	cookie->use_usercb = 0;
38449576SJulian.Pullen@Sun.COM 	/* check_shadow() may add extra value to cookie->i_flags */
38459576SJulian.Pullen@Sun.COM 	cookie->i_flags = flags;
38460Sstevel@tonic-gate 	if (service) {
38470Sstevel@tonic-gate 		cookie->service = strdup(service);
38480Sstevel@tonic-gate 		if (cookie->service == NULL) {
38490Sstevel@tonic-gate 			delete_search_cookie(cookie);
38500Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
38510Sstevel@tonic-gate 		}
38529576SJulian.Pullen@Sun.COM 
38539576SJulian.Pullen@Sun.COM 		/*
38549576SJulian.Pullen@Sun.COM 		 * If given, use the credential given by the caller, and
38559576SJulian.Pullen@Sun.COM 		 * skip the credential check required for shadow update.
38569576SJulian.Pullen@Sun.COM 		 */
38579576SJulian.Pullen@Sun.COM 		if (auth == NULL) {
38589576SJulian.Pullen@Sun.COM 			rc = check_shadow(cookie, service);
38599576SJulian.Pullen@Sun.COM 			if (rc != NS_LDAP_SUCCESS) {
38609576SJulian.Pullen@Sun.COM 				*errorp = cookie->errorp;
38619576SJulian.Pullen@Sun.COM 				cookie->errorp = NULL;
38629576SJulian.Pullen@Sun.COM 				delete_search_cookie(cookie);
38639576SJulian.Pullen@Sun.COM 				cookie = NULL;
38649576SJulian.Pullen@Sun.COM 				return (rc);
38659576SJulian.Pullen@Sun.COM 			}
38669576SJulian.Pullen@Sun.COM 		}
38670Sstevel@tonic-gate 	}
38680Sstevel@tonic-gate 
38690Sstevel@tonic-gate 	cookie->i_filter = strdup(filter);
38700Sstevel@tonic-gate 	cookie->i_attr = attribute;
3871*12758SJulian.Pullen@Sun.COM 	cookie->i_sortattr = sortattr;
38720Sstevel@tonic-gate 	cookie->i_auth = auth;
38730Sstevel@tonic-gate 
38740Sstevel@tonic-gate 	state = INIT;
38750Sstevel@tonic-gate 	for (;;) {
38760Sstevel@tonic-gate 		state = search_state_machine(cookie, state, ONE_STEP);
38770Sstevel@tonic-gate 		switch (state) {
38780Sstevel@tonic-gate 		case PROCESS_RESULT:
38790Sstevel@tonic-gate 			*result = cookie->result;
38800Sstevel@tonic-gate 			cookie->result = NULL;
38810Sstevel@tonic-gate 			*vcookie = (void *)cookie;
38820Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
38834953Smichen 		case LDAP_ERROR:
38844953Smichen 			state = search_state_machine(cookie, state, ONE_STEP);
38854953Smichen 			state = search_state_machine(cookie, CLEAR_RESULTS,
38864953Smichen 			    ONE_STEP);
38874953Smichen 			/* FALLTHROUGH */
38880Sstevel@tonic-gate 		case ERROR:
38890Sstevel@tonic-gate 			rc = cookie->err_rc;
38906842Sth160488 			if (conn_user != NULL && conn_user->ns_error != NULL) {
38916842Sth160488 				*errorp = conn_user->ns_error;
38926842Sth160488 				conn_user->ns_error = NULL;
38936842Sth160488 			} else {
38946842Sth160488 				*errorp = cookie->errorp;
38956842Sth160488 				cookie->errorp = NULL;
38966842Sth160488 			}
38970Sstevel@tonic-gate 			delete_search_cookie(cookie);
38980Sstevel@tonic-gate 			return (rc);
38990Sstevel@tonic-gate 		case EXIT:
39000Sstevel@tonic-gate 			rc = cookie->err_rc;
39010Sstevel@tonic-gate 			if (rc != NS_LDAP_SUCCESS) {
39020Sstevel@tonic-gate 				*errorp = cookie->errorp;
39030Sstevel@tonic-gate 				cookie->errorp = NULL;
39040Sstevel@tonic-gate 			} else {
39050Sstevel@tonic-gate 				rc = NS_LDAP_NOTFOUND;
39060Sstevel@tonic-gate 			}
39070Sstevel@tonic-gate 
39080Sstevel@tonic-gate 			delete_search_cookie(cookie);
39090Sstevel@tonic-gate 			return (rc);
39100Sstevel@tonic-gate 
39110Sstevel@tonic-gate 		default:
39120Sstevel@tonic-gate 			break;
39130Sstevel@tonic-gate 		}
39140Sstevel@tonic-gate 	}
39150Sstevel@tonic-gate }
39160Sstevel@tonic-gate 
39176842Sth160488 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)39186842Sth160488 __ns_ldap_firstEntry(
39196842Sth160488     const char *service,
39206842Sth160488     const char *filter,
3921*12758SJulian.Pullen@Sun.COM     const char *vlv_sort,
39226842Sth160488     int (*init_filter_cb)(const ns_ldap_search_desc_t *desc,
39236842Sth160488     char **realfilter, const void *userdata),
39246842Sth160488     const char * const *attribute,
39256842Sth160488     const ns_cred_t *auth,
39266842Sth160488     const int flags,
39276842Sth160488     void **vcookie,
39286842Sth160488     ns_ldap_result_t **result,
39296842Sth160488     ns_ldap_error_t ** errorp,
39306842Sth160488     const void *userdata)
39316842Sth160488 {
39326842Sth160488 	ns_conn_user_t	*cu = NULL;
39336842Sth160488 	int		try_cnt = 0;
39346842Sth160488 	int		rc = NS_LDAP_SUCCESS;
39356842Sth160488 
39366842Sth160488 	for (;;) {
39376842Sth160488 		if (__s_api_setup_retry_search(&cu, NS_CONN_USER_GETENT,
39386842Sth160488 		    &try_cnt, &rc, errorp) == 0)
39396842Sth160488 			break;
3940*12758SJulian.Pullen@Sun.COM 		rc = firstEntry(service, filter, vlv_sort, init_filter_cb,
3941*12758SJulian.Pullen@Sun.COM 		    attribute, auth, flags, vcookie, result, errorp, userdata,
3942*12758SJulian.Pullen@Sun.COM 		    cu);
39436842Sth160488 	}
39446842Sth160488 	return (rc);
39456842Sth160488 }
39466842Sth160488 
39470Sstevel@tonic-gate /*ARGSUSED2*/
39480Sstevel@tonic-gate int
__ns_ldap_nextEntry(void * vcookie,ns_ldap_result_t ** result,ns_ldap_error_t ** errorp)39496842Sth160488 __ns_ldap_nextEntry(void *vcookie, ns_ldap_result_t **result,
39506842Sth160488     ns_ldap_error_t ** errorp)
39510Sstevel@tonic-gate {
39520Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie;
39530Sstevel@tonic-gate 	ns_state_t		state;
39540Sstevel@tonic-gate 	int			rc;
39550Sstevel@tonic-gate 
39560Sstevel@tonic-gate 	cookie = (ns_ldap_cookie_t *)vcookie;
39570Sstevel@tonic-gate 	cookie->result = NULL;
39580Sstevel@tonic-gate 	*result = NULL;
39590Sstevel@tonic-gate 
39606842Sth160488 	if (cookie->conn_user != NULL) {
39616842Sth160488 		rc = __s_api_setup_getnext(cookie->conn_user,
39626842Sth160488 		    &cookie->err_rc, errorp);
39636842Sth160488 		if (rc != NS_LDAP_SUCCESS)
39646842Sth160488 			return (rc);
39656842Sth160488 	}
39666842Sth160488 
39670Sstevel@tonic-gate 	state = END_PROCESS_RESULT;
39680Sstevel@tonic-gate 	for (;;) {
39690Sstevel@tonic-gate 		state = search_state_machine(cookie, state, ONE_STEP);
39700Sstevel@tonic-gate 		switch (state) {
39710Sstevel@tonic-gate 		case PROCESS_RESULT:
39720Sstevel@tonic-gate 			*result = cookie->result;
39730Sstevel@tonic-gate 			cookie->result = NULL;
39740Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
39754953Smichen 		case LDAP_ERROR:
39764953Smichen 			state = search_state_machine(cookie, state, ONE_STEP);
39774953Smichen 			state = search_state_machine(cookie, CLEAR_RESULTS,
39784953Smichen 			    ONE_STEP);
39794953Smichen 			/* FALLTHROUGH */
39800Sstevel@tonic-gate 		case ERROR:
39810Sstevel@tonic-gate 			rc = cookie->err_rc;
39820Sstevel@tonic-gate 			*errorp = cookie->errorp;
39830Sstevel@tonic-gate 			cookie->errorp = NULL;
39840Sstevel@tonic-gate 			return (rc);
39850Sstevel@tonic-gate 		case EXIT:
39860Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
39870Sstevel@tonic-gate 		}
39880Sstevel@tonic-gate 	}
39890Sstevel@tonic-gate }
39900Sstevel@tonic-gate 
39910Sstevel@tonic-gate int
__ns_ldap_endEntry(void ** vcookie,ns_ldap_error_t ** errorp)39920Sstevel@tonic-gate __ns_ldap_endEntry(
39930Sstevel@tonic-gate 	void **vcookie,
39940Sstevel@tonic-gate 	ns_ldap_error_t ** errorp)
39950Sstevel@tonic-gate {
39960Sstevel@tonic-gate 	ns_ldap_cookie_t	*cookie;
39970Sstevel@tonic-gate 	int			rc;
39980Sstevel@tonic-gate 
39990Sstevel@tonic-gate 	if (*vcookie == NULL)
40000Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
40010Sstevel@tonic-gate 
40020Sstevel@tonic-gate 	cookie = (ns_ldap_cookie_t *)(*vcookie);
40030Sstevel@tonic-gate 	cookie->result = NULL;
40040Sstevel@tonic-gate 
40050Sstevel@tonic-gate 	/* Complete search */
40064765Smj162486 	rc = search_state_machine(cookie, CLEAR_RESULTS, 0);
40070Sstevel@tonic-gate 
40080Sstevel@tonic-gate 	/* Copy results back to user */
40090Sstevel@tonic-gate 	rc = cookie->err_rc;
40100Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS)
40110Sstevel@tonic-gate 		*errorp = cookie->errorp;
40120Sstevel@tonic-gate 
40130Sstevel@tonic-gate 	cookie->errorp = NULL;
40146842Sth160488 	if (cookie->conn_user != NULL) {
40156842Sth160488 		if (cookie->conn_user->conn_mt != NULL)
40166842Sth160488 			__s_api_conn_mt_return(cookie->conn_user);
40176842Sth160488 		__s_api_conn_user_free(cookie->conn_user);
40186842Sth160488 	}
40190Sstevel@tonic-gate 	delete_search_cookie(cookie);
40200Sstevel@tonic-gate 	cookie = NULL;
40210Sstevel@tonic-gate 	*vcookie = NULL;
40220Sstevel@tonic-gate 
40230Sstevel@tonic-gate 	return (rc);
40240Sstevel@tonic-gate }
40250Sstevel@tonic-gate 
40260Sstevel@tonic-gate 
40270Sstevel@tonic-gate int
__ns_ldap_freeResult(ns_ldap_result_t ** result)40280Sstevel@tonic-gate __ns_ldap_freeResult(ns_ldap_result_t **result)
40290Sstevel@tonic-gate {
40300Sstevel@tonic-gate 
40310Sstevel@tonic-gate 	ns_ldap_entry_t	*curEntry = NULL;
40320Sstevel@tonic-gate 	ns_ldap_entry_t	*delEntry = NULL;
40330Sstevel@tonic-gate 	int		i;
40340Sstevel@tonic-gate 	ns_ldap_result_t	*res = *result;
40350Sstevel@tonic-gate 
40360Sstevel@tonic-gate #ifdef DEBUG
40370Sstevel@tonic-gate 	(void) fprintf(stderr, "__ns_ldap_freeResult START\n");
40380Sstevel@tonic-gate #endif
40390Sstevel@tonic-gate 	if (res == NULL)
40400Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
40410Sstevel@tonic-gate 
40420Sstevel@tonic-gate 	if (res->entry != NULL)
40430Sstevel@tonic-gate 		curEntry = res->entry;
40440Sstevel@tonic-gate 
40450Sstevel@tonic-gate 	for (i = 0; i < res->entries_count; i++) {
40460Sstevel@tonic-gate 		if (curEntry != NULL) {
40470Sstevel@tonic-gate 			delEntry = curEntry;
40480Sstevel@tonic-gate 			curEntry = curEntry->next;
40490Sstevel@tonic-gate 			__ns_ldap_freeEntry(delEntry);
40500Sstevel@tonic-gate 		}
40510Sstevel@tonic-gate 	}
40520Sstevel@tonic-gate 
40530Sstevel@tonic-gate 	free(res);
40540Sstevel@tonic-gate 	*result = NULL;
40550Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
40560Sstevel@tonic-gate }
40570Sstevel@tonic-gate 
40580Sstevel@tonic-gate /*ARGSUSED*/
40590Sstevel@tonic-gate int
__ns_ldap_auth(const ns_cred_t * auth,const int flags,ns_ldap_error_t ** errorp,LDAPControl ** serverctrls,LDAPControl ** clientctrls)40600Sstevel@tonic-gate __ns_ldap_auth(const ns_cred_t *auth,
40610Sstevel@tonic-gate 		    const int flags,
40620Sstevel@tonic-gate 		    ns_ldap_error_t **errorp,
40630Sstevel@tonic-gate 		    LDAPControl **serverctrls,
40640Sstevel@tonic-gate 		    LDAPControl **clientctrls)
40650Sstevel@tonic-gate {
40660Sstevel@tonic-gate 
40670Sstevel@tonic-gate 	ConnectionID	connectionId = -1;
40680Sstevel@tonic-gate 	Connection	*conp;
40690Sstevel@tonic-gate 	int		rc = 0;
40700Sstevel@tonic-gate 	int		do_not_fail_if_new_pwd_reqd = 0;
40711179Svv149972 	int		nopasswd_acct_mgmt = 0;
40726842Sth160488 	ns_conn_user_t	*conn_user;
40730Sstevel@tonic-gate 
40740Sstevel@tonic-gate 
40750Sstevel@tonic-gate #ifdef DEBUG
40760Sstevel@tonic-gate 	(void) fprintf(stderr, "__ns_ldap_auth START\n");
40770Sstevel@tonic-gate #endif
40780Sstevel@tonic-gate 
40790Sstevel@tonic-gate 	*errorp = NULL;
40800Sstevel@tonic-gate 	if (!auth)
40810Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
40820Sstevel@tonic-gate 
40836842Sth160488 	conn_user = __s_api_conn_user_init(NS_CONN_USER_AUTH,
40846842Sth160488 	    NULL, B_FALSE);
40856842Sth160488 
40862830Sdjl 	rc = __s_api_getConnection(NULL, flags | NS_LDAP_NEW_CONN,
40874765Smj162486 	    auth, &connectionId, &conp, errorp,
40886842Sth160488 	    do_not_fail_if_new_pwd_reqd, nopasswd_acct_mgmt,
40896842Sth160488 	    conn_user);
40906842Sth160488 
40916842Sth160488 	if (conn_user != NULL)
40926842Sth160488 		__s_api_conn_user_free(conn_user);
40936842Sth160488 
40940Sstevel@tonic-gate 	if (rc == NS_LDAP_OP_FAILED && *errorp)
40950Sstevel@tonic-gate 		(void) __ns_ldap_freeError(errorp);
40960Sstevel@tonic-gate 
40970Sstevel@tonic-gate 	if (connectionId > -1)
40980Sstevel@tonic-gate 		DropConnection(connectionId, flags);
40990Sstevel@tonic-gate 	return (rc);
41000Sstevel@tonic-gate }
41010Sstevel@tonic-gate 
41020Sstevel@tonic-gate char **
__ns_ldap_getAttr(const ns_ldap_entry_t * entry,const char * attrname)41030Sstevel@tonic-gate __ns_ldap_getAttr(const ns_ldap_entry_t *entry, const char *attrname)
41040Sstevel@tonic-gate {
41050Sstevel@tonic-gate 	int	i;
41060Sstevel@tonic-gate 
41070Sstevel@tonic-gate 	if (entry == NULL)
41080Sstevel@tonic-gate 		return (NULL);
41090Sstevel@tonic-gate 	for (i = 0; i < entry->attr_count; i++) {
41100Sstevel@tonic-gate 		if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL)
41110Sstevel@tonic-gate 			return (entry->attr_pair[i]->attrvalue);
41120Sstevel@tonic-gate 	}
41130Sstevel@tonic-gate 	return (NULL);
41140Sstevel@tonic-gate }
41150Sstevel@tonic-gate 
41162830Sdjl ns_ldap_attr_t *
__ns_ldap_getAttrStruct(const ns_ldap_entry_t * entry,const char * attrname)41172830Sdjl __ns_ldap_getAttrStruct(const ns_ldap_entry_t *entry, const char *attrname)
41182830Sdjl {
41192830Sdjl 	int	i;
41202830Sdjl 
41212830Sdjl 	if (entry == NULL)
41222830Sdjl 		return (NULL);
41232830Sdjl 	for (i = 0; i < entry->attr_count; i++) {
41242830Sdjl 		if (strcasecmp(entry->attr_pair[i]->attrname, attrname) == NULL)
41252830Sdjl 			return (entry->attr_pair[i]);
41262830Sdjl 	}
41272830Sdjl 	return (NULL);
41282830Sdjl }
41292830Sdjl 
41300Sstevel@tonic-gate 
41310Sstevel@tonic-gate /*ARGSUSED*/
41320Sstevel@tonic-gate int
__ns_ldap_uid2dn(const char * uid,char ** userDN,const ns_cred_t * cred,ns_ldap_error_t ** errorp)41330Sstevel@tonic-gate __ns_ldap_uid2dn(const char *uid,
41340Sstevel@tonic-gate 		char **userDN,
41350Sstevel@tonic-gate 		const ns_cred_t *cred,	/* cred is ignored */
41360Sstevel@tonic-gate 		ns_ldap_error_t **errorp)
41370Sstevel@tonic-gate {
41380Sstevel@tonic-gate 	ns_ldap_result_t	*result = NULL;
41390Sstevel@tonic-gate 	char		*filter, *userdata;
41400Sstevel@tonic-gate 	char		errstr[MAXERROR];
41410Sstevel@tonic-gate 	char		**value;
41420Sstevel@tonic-gate 	int		rc = 0;
41430Sstevel@tonic-gate 	int		i = 0;
41440Sstevel@tonic-gate 	size_t		len;
41450Sstevel@tonic-gate 
41460Sstevel@tonic-gate 	*errorp = NULL;
41470Sstevel@tonic-gate 	*userDN = NULL;
41480Sstevel@tonic-gate 	if ((uid == NULL) || (uid[0] == '\0'))
41490Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
41500Sstevel@tonic-gate 
41510Sstevel@tonic-gate 	while (uid[i] != '\0') {
41520Sstevel@tonic-gate 		if (uid[i] == '=') {
41530Sstevel@tonic-gate 			*userDN = strdup(uid);
41540Sstevel@tonic-gate 			return (NS_LDAP_SUCCESS);
41550Sstevel@tonic-gate 		}
41560Sstevel@tonic-gate 		i++;
41570Sstevel@tonic-gate 	}
41580Sstevel@tonic-gate 	i = 0;
41590Sstevel@tonic-gate 	while ((uid[i] != '\0') && (isdigit(uid[i])))
41600Sstevel@tonic-gate 		i++;
41610Sstevel@tonic-gate 	if (uid[i] == '\0') {
41620Sstevel@tonic-gate 		len = strlen(UIDNUMFILTER) + strlen(uid) + 1;
41630Sstevel@tonic-gate 		filter = (char *)malloc(len);
41640Sstevel@tonic-gate 		if (filter == NULL) {
41650Sstevel@tonic-gate 			*userDN = NULL;
41660Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
41670Sstevel@tonic-gate 		}
41680Sstevel@tonic-gate 		(void) snprintf(filter, len, UIDNUMFILTER, uid);
41690Sstevel@tonic-gate 
41700Sstevel@tonic-gate 		len = strlen(UIDNUMFILTER_SSD) + strlen(uid) + 1;
41710Sstevel@tonic-gate 		userdata = (char *)malloc(len);
41720Sstevel@tonic-gate 		if (userdata == NULL) {
41730Sstevel@tonic-gate 			*userDN = NULL;
41740Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
41750Sstevel@tonic-gate 		}
41760Sstevel@tonic-gate 		(void) snprintf(userdata, len, UIDNUMFILTER_SSD, uid);
41770Sstevel@tonic-gate 	} else {
41780Sstevel@tonic-gate 		len = strlen(UIDFILTER) + strlen(uid) + 1;
41790Sstevel@tonic-gate 		filter = (char *)malloc(len);
41800Sstevel@tonic-gate 		if (filter == NULL) {
41810Sstevel@tonic-gate 			*userDN = NULL;
41820Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
41830Sstevel@tonic-gate 		}
41840Sstevel@tonic-gate 		(void) snprintf(filter, len, UIDFILTER, uid);
41850Sstevel@tonic-gate 
41860Sstevel@tonic-gate 		len = strlen(UIDFILTER_SSD) + strlen(uid) + 1;
41870Sstevel@tonic-gate 		userdata = (char *)malloc(len);
41880Sstevel@tonic-gate 		if (userdata == NULL) {
41890Sstevel@tonic-gate 			*userDN = NULL;
41900Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
41910Sstevel@tonic-gate 		}
41920Sstevel@tonic-gate 		(void) snprintf(userdata, len, UIDFILTER_SSD, uid);
41930Sstevel@tonic-gate 	}
41940Sstevel@tonic-gate 
4195699Ssdussud 	/*
4196699Ssdussud 	 * we want to retrieve the DN as it appears in LDAP
4197699Ssdussud 	 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4198699Ssdussud 	 */
41990Sstevel@tonic-gate 	rc = __ns_ldap_list("passwd", filter,
42004765Smj162486 	    __s_api_merge_SSD_filter,
42014765Smj162486 	    NULL, cred, NS_LDAP_NOT_CVT_DN,
42024765Smj162486 	    &result, errorp, NULL,
42034765Smj162486 	    userdata);
42040Sstevel@tonic-gate 	free(filter);
42050Sstevel@tonic-gate 	filter = NULL;
42060Sstevel@tonic-gate 	free(userdata);
42070Sstevel@tonic-gate 	userdata = NULL;
42080Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
42090Sstevel@tonic-gate 		if (result) {
42100Sstevel@tonic-gate 			(void) __ns_ldap_freeResult(&result);
42110Sstevel@tonic-gate 			result = NULL;
42120Sstevel@tonic-gate 		}
42130Sstevel@tonic-gate 		return (rc);
42140Sstevel@tonic-gate 	}
42150Sstevel@tonic-gate 	if (result->entries_count > 1) {
42160Sstevel@tonic-gate 		(void) __ns_ldap_freeResult(&result);
42170Sstevel@tonic-gate 		result = NULL;
42180Sstevel@tonic-gate 		*userDN = NULL;
42190Sstevel@tonic-gate 		(void) sprintf(errstr,
42204765Smj162486 		    gettext("Too many entries are returned for %s"), uid);
42210Sstevel@tonic-gate 		MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
42224765Smj162486 		    NULL);
42230Sstevel@tonic-gate 		return (NS_LDAP_INTERNAL);
42240Sstevel@tonic-gate 	}
42250Sstevel@tonic-gate 
42260Sstevel@tonic-gate 	value = __ns_ldap_getAttr(result->entry, "dn");
42270Sstevel@tonic-gate 	*userDN = strdup(value[0]);
42280Sstevel@tonic-gate 	(void) __ns_ldap_freeResult(&result);
42290Sstevel@tonic-gate 	result = NULL;
42300Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
42310Sstevel@tonic-gate }
42320Sstevel@tonic-gate 
42330Sstevel@tonic-gate 
42340Sstevel@tonic-gate /*ARGSUSED*/
42350Sstevel@tonic-gate int
__ns_ldap_host2dn(const char * host,const char * domain,char ** hostDN,const ns_cred_t * cred,ns_ldap_error_t ** errorp)42360Sstevel@tonic-gate __ns_ldap_host2dn(const char *host,
42370Sstevel@tonic-gate 		const char *domain,
42380Sstevel@tonic-gate 		char **hostDN,
42390Sstevel@tonic-gate 		const ns_cred_t *cred,	/* cred is ignored */
42400Sstevel@tonic-gate 		ns_ldap_error_t **errorp)
42410Sstevel@tonic-gate {
42420Sstevel@tonic-gate 	ns_ldap_result_t	*result = NULL;
42430Sstevel@tonic-gate 	char		*filter, *userdata;
42440Sstevel@tonic-gate 	char		errstr[MAXERROR];
42450Sstevel@tonic-gate 	char		**value;
42460Sstevel@tonic-gate 	int		rc;
42470Sstevel@tonic-gate 	size_t		len;
42480Sstevel@tonic-gate 
42490Sstevel@tonic-gate /*
42500Sstevel@tonic-gate  * XXX
42510Sstevel@tonic-gate  * the domain parameter needs to be used in case domain is not local, if
42520Sstevel@tonic-gate  * this routine is to support multi domain setups, it needs lots of work...
42530Sstevel@tonic-gate  */
42540Sstevel@tonic-gate 	*errorp = NULL;
42550Sstevel@tonic-gate 	*hostDN = NULL;
42560Sstevel@tonic-gate 	if ((host == NULL) || (host[0] == '\0'))
42570Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
42580Sstevel@tonic-gate 
42590Sstevel@tonic-gate 	len = strlen(HOSTFILTER) + strlen(host) + 1;
42600Sstevel@tonic-gate 	filter = (char *)malloc(len);
42610Sstevel@tonic-gate 	if (filter == NULL) {
42620Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
42630Sstevel@tonic-gate 	}
42640Sstevel@tonic-gate 	(void) snprintf(filter,	len, HOSTFILTER, host);
42650Sstevel@tonic-gate 
42660Sstevel@tonic-gate 	len = strlen(HOSTFILTER_SSD) + strlen(host) + 1;
42670Sstevel@tonic-gate 	userdata = (char *)malloc(len);
42680Sstevel@tonic-gate 	if (userdata == NULL) {
42690Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
42700Sstevel@tonic-gate 	}
42710Sstevel@tonic-gate 	(void) snprintf(userdata, len, HOSTFILTER_SSD, host);
42720Sstevel@tonic-gate 
4273699Ssdussud 	/*
4274699Ssdussud 	 * we want to retrieve the DN as it appears in LDAP
4275699Ssdussud 	 * hence the use of NS_LDAP_NOT_CVT_DN in flags
4276699Ssdussud 	 */
42770Sstevel@tonic-gate 	rc = __ns_ldap_list("hosts", filter,
42784765Smj162486 	    __s_api_merge_SSD_filter,
42794765Smj162486 	    NULL, cred, NS_LDAP_NOT_CVT_DN, &result,
42804765Smj162486 	    errorp, NULL,
42814765Smj162486 	    userdata);
42820Sstevel@tonic-gate 	free(filter);
42830Sstevel@tonic-gate 	filter = NULL;
42840Sstevel@tonic-gate 	free(userdata);
42850Sstevel@tonic-gate 	userdata = NULL;
42860Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS) {
42870Sstevel@tonic-gate 		if (result) {
42880Sstevel@tonic-gate 			(void) __ns_ldap_freeResult(&result);
42890Sstevel@tonic-gate 			result = NULL;
42900Sstevel@tonic-gate 		}
42910Sstevel@tonic-gate 		return (rc);
42920Sstevel@tonic-gate 	}
42930Sstevel@tonic-gate 
42940Sstevel@tonic-gate 	if (result->entries_count > 1) {
42950Sstevel@tonic-gate 		(void) __ns_ldap_freeResult(&result);
42960Sstevel@tonic-gate 		result = NULL;
42970Sstevel@tonic-gate 		*hostDN = NULL;
42980Sstevel@tonic-gate 		(void) sprintf(errstr,
42994765Smj162486 		    gettext("Too many entries are returned for %s"), host);
43000Sstevel@tonic-gate 		MKERROR(LOG_WARNING, *errorp, NS_LDAP_INTERNAL, strdup(errstr),
43014765Smj162486 		    NULL);
43020Sstevel@tonic-gate 		return (NS_LDAP_INTERNAL);
43030Sstevel@tonic-gate 	}
43040Sstevel@tonic-gate 
43050Sstevel@tonic-gate 	value = __ns_ldap_getAttr(result->entry, "dn");
43060Sstevel@tonic-gate 	*hostDN = strdup(value[0]);
43070Sstevel@tonic-gate 	(void) __ns_ldap_freeResult(&result);
43080Sstevel@tonic-gate 	result = NULL;
43090Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
43100Sstevel@tonic-gate }
43110Sstevel@tonic-gate 
43120Sstevel@tonic-gate /*ARGSUSED*/
43130Sstevel@tonic-gate int
__ns_ldap_dn2domain(const char * dn,char ** domain,const ns_cred_t * cred,ns_ldap_error_t ** errorp)43140Sstevel@tonic-gate __ns_ldap_dn2domain(const char *dn,
43150Sstevel@tonic-gate 			char **domain,
43160Sstevel@tonic-gate 			const ns_cred_t *cred,
43170Sstevel@tonic-gate 			ns_ldap_error_t **errorp)
43180Sstevel@tonic-gate {
43190Sstevel@tonic-gate 	int		rc, pnum, i, j, len = 0;
43200Sstevel@tonic-gate 	char		*newdn, **rdns = NULL;
43210Sstevel@tonic-gate 	char		**dns, *dn1;
43220Sstevel@tonic-gate 
43230Sstevel@tonic-gate 	*errorp = NULL;
43240Sstevel@tonic-gate 
43250Sstevel@tonic-gate 	if (domain == NULL)
43260Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
43270Sstevel@tonic-gate 	else
43280Sstevel@tonic-gate 		*domain = NULL;
43290Sstevel@tonic-gate 
43300Sstevel@tonic-gate 	if ((dn == NULL) || (dn[0] == '\0'))
43310Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
43320Sstevel@tonic-gate 
43330Sstevel@tonic-gate 	/*
43340Sstevel@tonic-gate 	 * break dn into rdns
43350Sstevel@tonic-gate 	 */
43360Sstevel@tonic-gate 	dn1 = strdup(dn);
43370Sstevel@tonic-gate 	if (dn1 == NULL)
43380Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
43390Sstevel@tonic-gate 	rdns = ldap_explode_dn(dn1, 0);
43400Sstevel@tonic-gate 	free(dn1);
43410Sstevel@tonic-gate 	if (rdns == NULL || *rdns == NULL)
43420Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
43430Sstevel@tonic-gate 
43440Sstevel@tonic-gate 	for (i = 0; rdns[i]; i++)
43450Sstevel@tonic-gate 		len += strlen(rdns[i]) + 1;
43460Sstevel@tonic-gate 	pnum = i;
43470Sstevel@tonic-gate 
43480Sstevel@tonic-gate 	newdn = (char *)malloc(len + 1);
43490Sstevel@tonic-gate 	dns = (char **)calloc(pnum, sizeof (char *));
43500Sstevel@tonic-gate 	if (newdn == NULL || dns == NULL) {
43510Sstevel@tonic-gate 		if (newdn)
43520Sstevel@tonic-gate 			free(newdn);
43530Sstevel@tonic-gate 		ldap_value_free(rdns);
43540Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
43550Sstevel@tonic-gate 	}
43560Sstevel@tonic-gate 
43570Sstevel@tonic-gate 	/* construct a semi-normalized dn, newdn */
43580Sstevel@tonic-gate 	*newdn = '\0';
43590Sstevel@tonic-gate 	for (i = 0; rdns[i]; i++) {
43600Sstevel@tonic-gate 		dns[i] = newdn + strlen(newdn);
43610Sstevel@tonic-gate 		(void) strcat(newdn,
43624765Smj162486 		    __s_api_remove_rdn_space(rdns[i]));
43630Sstevel@tonic-gate 		(void) strcat(newdn, ",");
43640Sstevel@tonic-gate 	}
43650Sstevel@tonic-gate 	/* remove the last ',' */
43660Sstevel@tonic-gate 	newdn[strlen(newdn) - 1] = '\0';
43670Sstevel@tonic-gate 	ldap_value_free(rdns);
43680Sstevel@tonic-gate 
43690Sstevel@tonic-gate 	/*
43700Sstevel@tonic-gate 	 * loop and find the domain name associated with newdn,
43710Sstevel@tonic-gate 	 * removing rdn one by one from left to right
43720Sstevel@tonic-gate 	 */
43730Sstevel@tonic-gate 	for (i = 0; i < pnum; i++) {
43740Sstevel@tonic-gate 
43750Sstevel@tonic-gate 		if (*errorp)
43760Sstevel@tonic-gate 			(void) __ns_ldap_freeError(errorp);
43770Sstevel@tonic-gate 
43780Sstevel@tonic-gate 		/*
43790Sstevel@tonic-gate 		 *  try cache manager first
43800Sstevel@tonic-gate 		 */
43810Sstevel@tonic-gate 		rc = __s_api_get_cachemgr_data(NS_CACHE_DN2DOMAIN,
43824765Smj162486 		    dns[i], domain);
43830Sstevel@tonic-gate 		if (rc != NS_LDAP_SUCCESS) {
43840Sstevel@tonic-gate 			/*
43850Sstevel@tonic-gate 			 *  try ldap server second
43860Sstevel@tonic-gate 			 */
43870Sstevel@tonic-gate 			rc = __s_api_find_domainname(dns[i], domain,
43884765Smj162486 			    cred, errorp);
43890Sstevel@tonic-gate 		} else {
43900Sstevel@tonic-gate 			/*
43910Sstevel@tonic-gate 			 * skip the last one,
43920Sstevel@tonic-gate 			 * since it is already cached by ldap_cachemgr
43930Sstevel@tonic-gate 			 */
43940Sstevel@tonic-gate 			i--;
43950Sstevel@tonic-gate 		}
43960Sstevel@tonic-gate 		if (rc == NS_LDAP_SUCCESS) {
43975399Schinlong 			if (__s_api_nscd_proc()) {
43985399Schinlong 				/*
43995399Schinlong 				 * If it's nscd, ask cache manager to save the
44005399Schinlong 				 * dn to domain mapping(s)
44015399Schinlong 				 */
44025399Schinlong 				for (j = 0; j <= i; j++) {
44035399Schinlong 					(void) __s_api_set_cachemgr_data(
44045399Schinlong 					    NS_CACHE_DN2DOMAIN,
44055399Schinlong 					    dns[j],
44065399Schinlong 					    *domain);
44075399Schinlong 				}
44080Sstevel@tonic-gate 			}
44090Sstevel@tonic-gate 			break;
44100Sstevel@tonic-gate 		}
44110Sstevel@tonic-gate 	}
44120Sstevel@tonic-gate 
44130Sstevel@tonic-gate 	free(dns);
44140Sstevel@tonic-gate 	free(newdn);
44150Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS)
44160Sstevel@tonic-gate 		rc = NS_LDAP_NOTFOUND;
44170Sstevel@tonic-gate 	return (rc);
44180Sstevel@tonic-gate }
44190Sstevel@tonic-gate 
44200Sstevel@tonic-gate /*ARGSUSED*/
44210Sstevel@tonic-gate int
__ns_ldap_getServiceAuthMethods(const char * service,ns_auth_t *** auth,ns_ldap_error_t ** errorp)44220Sstevel@tonic-gate __ns_ldap_getServiceAuthMethods(const char *service,
44230Sstevel@tonic-gate 		ns_auth_t ***auth,
44240Sstevel@tonic-gate 		ns_ldap_error_t **errorp)
44250Sstevel@tonic-gate {
44260Sstevel@tonic-gate 	char		errstr[MAXERROR];
44270Sstevel@tonic-gate 	int		rc, i, done = 0;
44280Sstevel@tonic-gate 	int		slen;
44290Sstevel@tonic-gate 	void		**param;
44300Sstevel@tonic-gate 	char		**sam, *srv, *send;
44310Sstevel@tonic-gate 	ns_auth_t	**authpp = NULL, *ap;
44320Sstevel@tonic-gate 	int		cnt, max;
44330Sstevel@tonic-gate 	ns_config_t	*cfg;
44340Sstevel@tonic-gate 	ns_ldap_error_t	*error = NULL;
44350Sstevel@tonic-gate 
44360Sstevel@tonic-gate 	if (errorp == NULL)
44370Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
44380Sstevel@tonic-gate 	*errorp = NULL;
44390Sstevel@tonic-gate 
44400Sstevel@tonic-gate 	if ((service == NULL) || (service[0] == '\0') ||
44414765Smj162486 	    (auth == NULL))
44420Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
44430Sstevel@tonic-gate 
44440Sstevel@tonic-gate 	*auth = NULL;
44450Sstevel@tonic-gate 	rc = __ns_ldap_getParam(NS_LDAP_SERVICE_AUTH_METHOD_P, &param, &error);
44460Sstevel@tonic-gate 	if (rc != NS_LDAP_SUCCESS || param == NULL) {
44470Sstevel@tonic-gate 		*errorp = error;
44480Sstevel@tonic-gate 		return (rc);
44490Sstevel@tonic-gate 	}
44500Sstevel@tonic-gate 	sam = (char **)param;
44510Sstevel@tonic-gate 
44520Sstevel@tonic-gate 	cfg = __s_api_get_default_config();
44530Sstevel@tonic-gate 	cnt = 0;
44540Sstevel@tonic-gate 
44550Sstevel@tonic-gate 	slen = strlen(service);
44560Sstevel@tonic-gate 
44570Sstevel@tonic-gate 	for (; *sam; sam++) {
44580Sstevel@tonic-gate 		srv = *sam;
44590Sstevel@tonic-gate 		if (strncasecmp(service, srv, slen) != 0)
44600Sstevel@tonic-gate 			continue;
44610Sstevel@tonic-gate 		srv += slen;
44620Sstevel@tonic-gate 		if (*srv != COLONTOK)
44630Sstevel@tonic-gate 			continue;
44640Sstevel@tonic-gate 		send = srv;
44650Sstevel@tonic-gate 		srv++;
44660Sstevel@tonic-gate 		for (max = 1; (send = strchr(++send, SEMITOK)) != NULL;
44674765Smj162486 		    max++) {}
44680Sstevel@tonic-gate 		authpp = (ns_auth_t **)calloc(++max, sizeof (ns_auth_t *));
44690Sstevel@tonic-gate 		if (authpp == NULL) {
44700Sstevel@tonic-gate 			(void) __ns_ldap_freeParam(&param);
44710Sstevel@tonic-gate 			__s_api_release_config(cfg);
44720Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
44730Sstevel@tonic-gate 		}
44740Sstevel@tonic-gate 		while (!done) {
44750Sstevel@tonic-gate 			send = strchr(srv, SEMITOK);
44760Sstevel@tonic-gate 			if (send != NULL) {
44770Sstevel@tonic-gate 				*send = '\0';
44780Sstevel@tonic-gate 				send++;
44790Sstevel@tonic-gate 			}
44800Sstevel@tonic-gate 			i = __s_get_enum_value(cfg, srv, NS_LDAP_AUTH_P);
44810Sstevel@tonic-gate 			if (i == -1) {
44820Sstevel@tonic-gate 				(void) __ns_ldap_freeParam(&param);
44830Sstevel@tonic-gate 				(void) sprintf(errstr,
44844765Smj162486 				gettext("Unsupported "
44854765Smj162486 				    "serviceAuthenticationMethod: %s.\n"), srv);
44860Sstevel@tonic-gate 				MKERROR(LOG_WARNING, *errorp, NS_CONFIG_SYNTAX,
44874765Smj162486 				    strdup(errstr), NULL);
44880Sstevel@tonic-gate 				__s_api_release_config(cfg);
44890Sstevel@tonic-gate 				return (NS_LDAP_CONFIG);
44900Sstevel@tonic-gate 			}
44910Sstevel@tonic-gate 			ap = __s_api_AuthEnumtoStruct((EnumAuthType_t)i);
44920Sstevel@tonic-gate 			if (ap == NULL) {
44930Sstevel@tonic-gate 				(void) __ns_ldap_freeParam(&param);
44940Sstevel@tonic-gate 				__s_api_release_config(cfg);
44950Sstevel@tonic-gate 				return (NS_LDAP_MEMORY);
44960Sstevel@tonic-gate 			}
44970Sstevel@tonic-gate 			authpp[cnt++] = ap;
44980Sstevel@tonic-gate 			if (send == NULL)
44990Sstevel@tonic-gate 				done = TRUE;
45000Sstevel@tonic-gate 			else
45010Sstevel@tonic-gate 				srv = send;
45020Sstevel@tonic-gate 		}
45030Sstevel@tonic-gate 	}
45040Sstevel@tonic-gate 
45050Sstevel@tonic-gate 	*auth = authpp;
45060Sstevel@tonic-gate 	(void) __ns_ldap_freeParam(&param);
45070Sstevel@tonic-gate 	__s_api_release_config(cfg);
45080Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
45090Sstevel@tonic-gate }
45100Sstevel@tonic-gate 
45110Sstevel@tonic-gate /*
45120Sstevel@tonic-gate  * This routine is called when certain scenario occurs
45130Sstevel@tonic-gate  * e.g.
45140Sstevel@tonic-gate  * service == auto_home
45150Sstevel@tonic-gate  * SSD = automount: ou = mytest,
45160Sstevel@tonic-gate  * NS_LDAP_MAPATTRIBUTE= auto_home: automountMapName=AAA
45170Sstevel@tonic-gate  * NS_LDAP_OBJECTCLASSMAP= auto_home:automountMap=MynisMap
45180Sstevel@tonic-gate  * NS_LDAP_OBJECTCLASSMAP= auto_home:automount=MynisObject
45190Sstevel@tonic-gate  *
45200Sstevel@tonic-gate  * The automountMapName is prepended implicitely but is mapped
45210Sstevel@tonic-gate  * to AAA. So dn could appers as
45220Sstevel@tonic-gate  * dn: AAA=auto_home,ou=bar,dc=foo,dc=com
45230Sstevel@tonic-gate  * dn: automountKey=user_01,AAA=auto_home,ou=bar,dc=foo,dc=com
45240Sstevel@tonic-gate  * dn: automountKey=user_02,AAA=auto_home,ou=bar,dc=foo,dc=com
45250Sstevel@tonic-gate  * in the directory.
45260Sstevel@tonic-gate  * This function is called to covert the mapped attr back to
45270Sstevel@tonic-gate  * orig attr when the entries are searched and returned
45280Sstevel@tonic-gate  */
45290Sstevel@tonic-gate 
45300Sstevel@tonic-gate int
__s_api_convert_automountmapname(const char * service,char ** dn,ns_ldap_error_t ** errp)45310Sstevel@tonic-gate __s_api_convert_automountmapname(const char *service, char **dn,
45320Sstevel@tonic-gate 		ns_ldap_error_t **errp) {
45330Sstevel@tonic-gate 
45340Sstevel@tonic-gate 	char	**mapping = NULL;
45350Sstevel@tonic-gate 	char	*mapped_attr = NULL;
45360Sstevel@tonic-gate 	char	*automountmapname = "automountMapName";
45370Sstevel@tonic-gate 	char	*buffer = NULL;
45380Sstevel@tonic-gate 	int	rc = NS_LDAP_SUCCESS;
45390Sstevel@tonic-gate 	char	errstr[MAXERROR];
45400Sstevel@tonic-gate 
45410Sstevel@tonic-gate 	/*
45420Sstevel@tonic-gate 	 * dn is an input/out parameter, check it first
45430Sstevel@tonic-gate 	 */
45440Sstevel@tonic-gate 
45450Sstevel@tonic-gate 	if (service == NULL || dn == NULL || *dn == NULL)
45460Sstevel@tonic-gate 		return (NS_LDAP_INVALID_PARAM);
45470Sstevel@tonic-gate 
45480Sstevel@tonic-gate 	/*
45490Sstevel@tonic-gate 	 * Check to see if there is a mapped attribute for auto_xxx
45500Sstevel@tonic-gate 	 */
45510Sstevel@tonic-gate 
45520Sstevel@tonic-gate 	mapping = __ns_ldap_getMappedAttributes(service, automountmapname);
45530Sstevel@tonic-gate 
45540Sstevel@tonic-gate 	/*
45550Sstevel@tonic-gate 	 * if no mapped attribute for auto_xxx, try automount
45560Sstevel@tonic-gate 	 */
45570Sstevel@tonic-gate 
45580Sstevel@tonic-gate 	if (mapping == NULL)
45590Sstevel@tonic-gate 		mapping = __ns_ldap_getMappedAttributes(
45600Sstevel@tonic-gate 			"automount", automountmapname);
45610Sstevel@tonic-gate 
45620Sstevel@tonic-gate 	/*
45630Sstevel@tonic-gate 	 * if no mapped attribute is found, return SUCCESS (no op)
45640Sstevel@tonic-gate 	 */
45650Sstevel@tonic-gate 
45660Sstevel@tonic-gate 	if (mapping == NULL)
45670Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
45680Sstevel@tonic-gate 
45690Sstevel@tonic-gate 	/*
45700Sstevel@tonic-gate 	 * if the mapped attribute is found and attr is not empty,
45710Sstevel@tonic-gate 	 * copy it
45720Sstevel@tonic-gate 	 */
45730Sstevel@tonic-gate 
45740Sstevel@tonic-gate 	if (mapping[0] != NULL) {
45750Sstevel@tonic-gate 		mapped_attr = strdup(mapping[0]);
45760Sstevel@tonic-gate 		__s_api_free2dArray(mapping);
45770Sstevel@tonic-gate 		if (mapped_attr == NULL) {
45780Sstevel@tonic-gate 			return (NS_LDAP_MEMORY);
45790Sstevel@tonic-gate 		}
45800Sstevel@tonic-gate 	} else {
45810Sstevel@tonic-gate 		__s_api_free2dArray(mapping);
45820Sstevel@tonic-gate 
45830Sstevel@tonic-gate 		(void) snprintf(errstr, (2 * MAXERROR),
45840Sstevel@tonic-gate 			gettext(
45850Sstevel@tonic-gate 			"Attribute nisMapName is mapped to an "
45860Sstevel@tonic-gate 			"empty string.\n"));
45870Sstevel@tonic-gate 
45880Sstevel@tonic-gate 		MKERROR(LOG_ERR, *errp, NS_CONFIG_SYNTAX,
45890Sstevel@tonic-gate 			strdup(errstr), NULL);
45900Sstevel@tonic-gate 
45910Sstevel@tonic-gate 		return (NS_LDAP_CONFIG);
45920Sstevel@tonic-gate 	}
45930Sstevel@tonic-gate 
45940Sstevel@tonic-gate 	/*
45950Sstevel@tonic-gate 	 * Locate the mapped attribute in the dn
45960Sstevel@tonic-gate 	 * and replace it if it exists
45970Sstevel@tonic-gate 	 */
45980Sstevel@tonic-gate 
45990Sstevel@tonic-gate 	rc = __s_api_replace_mapped_attr_in_dn(
46000Sstevel@tonic-gate 		(const char *) automountmapname, (const char *) mapped_attr,
46010Sstevel@tonic-gate 		(const char *) *dn, &buffer);
46020Sstevel@tonic-gate 
46030Sstevel@tonic-gate 	/* clean up */
46040Sstevel@tonic-gate 
46050Sstevel@tonic-gate 	free(mapped_attr);
46060Sstevel@tonic-gate 
46070Sstevel@tonic-gate 	/*
46080Sstevel@tonic-gate 	 * If mapped attr is found(buffer != NULL)
46090Sstevel@tonic-gate 	 *	a new dn is returned
46100Sstevel@tonic-gate 	 * If no mapped attribute is in dn,
46110Sstevel@tonic-gate 	 *	return NS_LDAP_SUCCESS (no op)
46120Sstevel@tonic-gate 	 * If no memory,
46130Sstevel@tonic-gate 	 *	return NS_LDAP_MEMORY (no op)
46140Sstevel@tonic-gate 	 */
46150Sstevel@tonic-gate 
46160Sstevel@tonic-gate 	if (buffer != NULL) {
46170Sstevel@tonic-gate 		free(*dn);
46180Sstevel@tonic-gate 		*dn = buffer;
46190Sstevel@tonic-gate 	}
46200Sstevel@tonic-gate 
46210Sstevel@tonic-gate 	return (rc);
46220Sstevel@tonic-gate }
46230Sstevel@tonic-gate 
46240Sstevel@tonic-gate /*
46250Sstevel@tonic-gate  * If the mapped attr is found in the dn,
46260Sstevel@tonic-gate  * 	return NS_LDAP_SUCCESS and a new_dn.
46270Sstevel@tonic-gate  * If no mapped attr is found,
46280Sstevel@tonic-gate  * 	return NS_LDAP_SUCCESS and *new_dn == NULL
46290Sstevel@tonic-gate  * If there is not enough memory,
46300Sstevel@tonic-gate  * 	return NS_LDAP_MEMORY and *new_dn == NULL
46310Sstevel@tonic-gate  */
46320Sstevel@tonic-gate 
46330Sstevel@tonic-gate int
__s_api_replace_mapped_attr_in_dn(const char * orig_attr,const char * mapped_attr,const char * dn,char ** new_dn)46340Sstevel@tonic-gate __s_api_replace_mapped_attr_in_dn(
46350Sstevel@tonic-gate 	const char *orig_attr, const char *mapped_attr,
46360Sstevel@tonic-gate 	const char *dn, char **new_dn) {
46370Sstevel@tonic-gate 
46380Sstevel@tonic-gate 	char	**dnArray = NULL;
46390Sstevel@tonic-gate 	char	*cur = NULL, *start = NULL;
46400Sstevel@tonic-gate 	int	i = 0, found = 0;
46410Sstevel@tonic-gate 	int	len = 0, orig_len = 0, mapped_len = 0;
46420Sstevel@tonic-gate 	int	dn_len = 0, tmp_len = 0;
46430Sstevel@tonic-gate 
46440Sstevel@tonic-gate 	*new_dn = NULL;
46450Sstevel@tonic-gate 
46460Sstevel@tonic-gate 	/*
46470Sstevel@tonic-gate 	 * seperate dn into individual componets
46480Sstevel@tonic-gate 	 * e.g.
46490Sstevel@tonic-gate 	 * "automountKey=user_01" , "automountMapName_test=auto_home", ...
46500Sstevel@tonic-gate 	 */
46510Sstevel@tonic-gate 	dnArray = ldap_explode_dn(dn, 0);
46520Sstevel@tonic-gate 
46530Sstevel@tonic-gate 	/*
46540Sstevel@tonic-gate 	 * This will find "mapped attr=value" in dn.
46550Sstevel@tonic-gate 	 * It won't find match if mapped attr appears
46560Sstevel@tonic-gate 	 * in the value.
46570Sstevel@tonic-gate 	 */
46580Sstevel@tonic-gate 	for (i = 0; dnArray[i] != NULL; i++) {
46590Sstevel@tonic-gate 		/*
46600Sstevel@tonic-gate 		 * This function is called when reading from
46610Sstevel@tonic-gate 		 * the directory so assume each component has "=".
46620Sstevel@tonic-gate 		 * Any ill formatted dn should be rejected
46630Sstevel@tonic-gate 		 * before adding to the directory
46640Sstevel@tonic-gate 		 */
46650Sstevel@tonic-gate 		cur = strchr(dnArray[i], '=');
46660Sstevel@tonic-gate 		*cur = '\0';
46670Sstevel@tonic-gate 		if (strcasecmp(mapped_attr, dnArray[i]) == 0)
46680Sstevel@tonic-gate 			found = 1;
46690Sstevel@tonic-gate 		*cur = '=';
46700Sstevel@tonic-gate 		if (found) break;
46710Sstevel@tonic-gate 	}
46720Sstevel@tonic-gate 
46730Sstevel@tonic-gate 	if (!found) {
46740Sstevel@tonic-gate 		__s_api_free2dArray(dnArray);
46750Sstevel@tonic-gate 		*new_dn = NULL;
46760Sstevel@tonic-gate 		return (NS_LDAP_SUCCESS);
46770Sstevel@tonic-gate 	}
46780Sstevel@tonic-gate 	/*
46790Sstevel@tonic-gate 	 * The new length is *dn length + (difference between
46800Sstevel@tonic-gate 	 * orig attr and mapped attr) + 1 ;
46810Sstevel@tonic-gate 	 * e.g.
46820Sstevel@tonic-gate 	 * automountKey=aa,automountMapName_test=auto_home,dc=foo,dc=com
46830Sstevel@tonic-gate 	 * ==>
46840Sstevel@tonic-gate 	 * automountKey=aa,automountMapName=auto_home,dc=foo,dc=com
46850Sstevel@tonic-gate 	 */
46860Sstevel@tonic-gate 	mapped_len = strlen(mapped_attr);
46870Sstevel@tonic-gate 	orig_len = strlen(orig_attr);
46880Sstevel@tonic-gate 	dn_len = strlen(dn);
46890Sstevel@tonic-gate 	len = dn_len + orig_len - mapped_len + 1;
46900Sstevel@tonic-gate 	*new_dn = (char *)calloc(1, len);
46910Sstevel@tonic-gate 	if (*new_dn == NULL) {
46920Sstevel@tonic-gate 		__s_api_free2dArray(dnArray);
46930Sstevel@tonic-gate 		return (NS_LDAP_MEMORY);
46940Sstevel@tonic-gate 	}
46950Sstevel@tonic-gate 
46960Sstevel@tonic-gate 	/*
46970Sstevel@tonic-gate 	 * Locate the mapped attr in the dn.
46980Sstevel@tonic-gate 	 * Use dnArray[i] instead of mapped_attr
46990Sstevel@tonic-gate 	 * because mapped_attr could appear in
47000Sstevel@tonic-gate 	 * the value
47010Sstevel@tonic-gate 	 */
47020Sstevel@tonic-gate 
47030Sstevel@tonic-gate 	cur = strstr(dn, dnArray[i]);
47040Sstevel@tonic-gate 	__s_api_free2dArray(dnArray);
47050Sstevel@tonic-gate 	/* copy the portion before mapped attr in dn  */
47060Sstevel@tonic-gate 	start = *new_dn;
47070Sstevel@tonic-gate 	tmp_len = cur - dn;
47080Sstevel@tonic-gate 	(void) memcpy((void *) start, (const void*) dn, tmp_len);
47090Sstevel@tonic-gate 
47100Sstevel@tonic-gate 	/*
47110Sstevel@tonic-gate 	 * Copy the orig_attr. e.g. automountMapName
47120Sstevel@tonic-gate 	 * This replaces mapped attr with orig attr
47130Sstevel@tonic-gate 	 */
47140Sstevel@tonic-gate 	start = start + (cur - dn); /* move cursor in buffer */
47150Sstevel@tonic-gate 	(void) memcpy((void *) start, (const void*) orig_attr, orig_len);
47160Sstevel@tonic-gate 
47170Sstevel@tonic-gate 	/*
47180Sstevel@tonic-gate 	 * Copy the portion after mapped attr in dn
47190Sstevel@tonic-gate 	 */
47200Sstevel@tonic-gate 	cur = cur + mapped_len; /* move cursor in  dn  */
47210Sstevel@tonic-gate 	start = start + orig_len; /* move cursor in buffer */
47220Sstevel@tonic-gate 	(void) strcpy(start, cur);
47230Sstevel@tonic-gate 
47240Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
47250Sstevel@tonic-gate }
47260Sstevel@tonic-gate 
47270Sstevel@tonic-gate /*
47280Sstevel@tonic-gate  * Validate Filter functions
47290Sstevel@tonic-gate  */
47300Sstevel@tonic-gate 
47310Sstevel@tonic-gate /* ***** Start of modified libldap.so.5 filter parser ***** */
47320Sstevel@tonic-gate 
47330Sstevel@tonic-gate /* filter parsing routine forward references */
47340Sstevel@tonic-gate static int adj_filter_list(char *str);
47350Sstevel@tonic-gate static int adj_simple_filter(char *str);
47360Sstevel@tonic-gate static int unescape_filterval(char *val);
47370Sstevel@tonic-gate static int hexchar2int(char c);
47380Sstevel@tonic-gate static int adj_substring_filter(char *val);
47390Sstevel@tonic-gate 
47400Sstevel@tonic-gate 
47410Sstevel@tonic-gate /*
47420Sstevel@tonic-gate  * assumes string manipulation is in-line
47430Sstevel@tonic-gate  * and all strings are sufficient in size
47440Sstevel@tonic-gate  * return value is the position after 'c'
47450Sstevel@tonic-gate  */
47460Sstevel@tonic-gate 
47470Sstevel@tonic-gate static char *
resync_str(char * str,char * next,char c)47480Sstevel@tonic-gate resync_str(char *str, char *next, char c)
47490Sstevel@tonic-gate {
47500Sstevel@tonic-gate 	char	*ret;
47510Sstevel@tonic-gate 
47520Sstevel@tonic-gate 	ret = str + strlen(str);
47530Sstevel@tonic-gate 	*next = c;
47540Sstevel@tonic-gate 	if (ret == next)
47550Sstevel@tonic-gate 		return (ret);
47560Sstevel@tonic-gate 	(void) strcat(str, next);
47570Sstevel@tonic-gate 	return (ret);
47580Sstevel@tonic-gate }
47590Sstevel@tonic-gate 
47600Sstevel@tonic-gate static char *
find_right_paren(char * s)47610Sstevel@tonic-gate find_right_paren(char *s)
47620Sstevel@tonic-gate {
47630Sstevel@tonic-gate 	int	balance, escape;
47640Sstevel@tonic-gate 
47650Sstevel@tonic-gate 	balance = 1;
47660Sstevel@tonic-gate 	escape = 0;
47670Sstevel@tonic-gate 	while (*s && balance) {
47680Sstevel@tonic-gate 		if (escape == 0) {
47690Sstevel@tonic-gate 			if (*s == '(')
47700Sstevel@tonic-gate 				balance++;
47710Sstevel@tonic-gate 			else if (*s == ')')
47720Sstevel@tonic-gate 				balance--;
47730Sstevel@tonic-gate 		}
47740Sstevel@tonic-gate 		if (*s == '\\' && ! escape)
47750Sstevel@tonic-gate 			escape = 1;
47760Sstevel@tonic-gate 		else
47770Sstevel@tonic-gate 			escape = 0;
47780Sstevel@tonic-gate 		if (balance)
47790Sstevel@tonic-gate 			s++;
47800Sstevel@tonic-gate 	}
47810Sstevel@tonic-gate 
47820Sstevel@tonic-gate 	return (*s ? s : NULL);
47830Sstevel@tonic-gate }
47840Sstevel@tonic-gate 
47850Sstevel@tonic-gate static char *
adj_complex_filter(char * str)47860Sstevel@tonic-gate adj_complex_filter(char	*str)
47870Sstevel@tonic-gate {
47880Sstevel@tonic-gate 	char	*next;
47890Sstevel@tonic-gate 
47900Sstevel@tonic-gate 	/*
47910Sstevel@tonic-gate 	 * We have (x(filter)...) with str sitting on
47920Sstevel@tonic-gate 	 * the x.  We have to find the paren matching
47930Sstevel@tonic-gate 	 * the one before the x and put the intervening
47940Sstevel@tonic-gate 	 * filters by calling adj_filter_list().
47950Sstevel@tonic-gate 	 */
47960Sstevel@tonic-gate 
47970Sstevel@tonic-gate 	str++;
47980Sstevel@tonic-gate 	if ((next = find_right_paren(str)) == NULL)
47990Sstevel@tonic-gate 		return (NULL);
48000Sstevel@tonic-gate 
48010Sstevel@tonic-gate 	*next = '\0';
48020Sstevel@tonic-gate 	if (adj_filter_list(str) == -1)
48030Sstevel@tonic-gate 		return (NULL);
48040Sstevel@tonic-gate 	next = resync_str(str, next, ')');
48050Sstevel@tonic-gate 	next++;
48060Sstevel@tonic-gate 
48070Sstevel@tonic-gate 	return (next);
48080Sstevel@tonic-gate }
48090Sstevel@tonic-gate 
48100Sstevel@tonic-gate static int
adj_filter(char * str)48110Sstevel@tonic-gate adj_filter(char *str)
48120Sstevel@tonic-gate {
48130Sstevel@tonic-gate 	char	*next;
48140Sstevel@tonic-gate 	int	parens, balance, escape;
48150Sstevel@tonic-gate 	char	*np, *cp,  *dp;
48160Sstevel@tonic-gate 
48170Sstevel@tonic-gate 	parens = 0;
48180Sstevel@tonic-gate 	while (*str) {
48190Sstevel@tonic-gate 		switch (*str) {
48200Sstevel@tonic-gate 		case '(':
48210Sstevel@tonic-gate 			str++;
48220Sstevel@tonic-gate 			parens++;
48230Sstevel@tonic-gate 			switch (*str) {
48240Sstevel@tonic-gate 			case '&':
48250Sstevel@tonic-gate 				if ((str = adj_complex_filter(str)) == NULL)
48260Sstevel@tonic-gate 					return (-1);
48270Sstevel@tonic-gate 
48280Sstevel@tonic-gate 				parens--;
48290Sstevel@tonic-gate 				break;
48300Sstevel@tonic-gate 
48310Sstevel@tonic-gate 			case '|':
48320Sstevel@tonic-gate 				if ((str = adj_complex_filter(str)) == NULL)
48330Sstevel@tonic-gate 					return (-1);
48340Sstevel@tonic-gate 
48350Sstevel@tonic-gate 				parens--;
48360Sstevel@tonic-gate 				break;
48370Sstevel@tonic-gate 
48380Sstevel@tonic-gate 			case '!':
48390Sstevel@tonic-gate 				if ((str = adj_complex_filter(str)) == NULL)
48400Sstevel@tonic-gate 					return (-1);
48410Sstevel@tonic-gate 
48420Sstevel@tonic-gate 				parens--;
48430Sstevel@tonic-gate 				break;
48440Sstevel@tonic-gate 
48450Sstevel@tonic-gate 			case '(':
48460Sstevel@tonic-gate 				/* illegal ((case - generated by conversion */
48470Sstevel@tonic-gate 
48480Sstevel@tonic-gate 				/* find missing close) */
48490Sstevel@tonic-gate 				np = find_right_paren(str+1);
48500Sstevel@tonic-gate 
48510Sstevel@tonic-gate 				/* error if not found */
48520Sstevel@tonic-gate 				if (np == NULL)
48530Sstevel@tonic-gate 					return (-1);
48540Sstevel@tonic-gate 
48550Sstevel@tonic-gate 				/* remove redundant (and) */
48560Sstevel@tonic-gate 				for (dp = str, cp = str+1; cp < np; ) {
48570Sstevel@tonic-gate 					*dp++ = *cp++;
48580Sstevel@tonic-gate 				}
48590Sstevel@tonic-gate 				cp++;
48600Sstevel@tonic-gate 				while (*cp)
48610Sstevel@tonic-gate 					*dp++ = *cp++;
48620Sstevel@tonic-gate 				*dp = '\0';
48630Sstevel@tonic-gate 
48640Sstevel@tonic-gate 				/* re-start test at original ( */
48650Sstevel@tonic-gate 				parens--;
48660Sstevel@tonic-gate 				str--;
48670Sstevel@tonic-gate 				break;
48680Sstevel@tonic-gate 
48690Sstevel@tonic-gate 			default:
48700Sstevel@tonic-gate 				balance = 1;
48710Sstevel@tonic-gate 				escape = 0;
48720Sstevel@tonic-gate 				next = str;
48730Sstevel@tonic-gate 				while (*next && balance) {
48740Sstevel@tonic-gate 					if (escape == 0) {
48750Sstevel@tonic-gate 						if (*next == '(')
48760Sstevel@tonic-gate 							balance++;
48770Sstevel@tonic-gate 						else if (*next == ')')
48780Sstevel@tonic-gate 							balance--;
48790Sstevel@tonic-gate 					}
48800Sstevel@tonic-gate 					if (*next == '\\' && ! escape)
48810Sstevel@tonic-gate 						escape = 1;
48820Sstevel@tonic-gate 					else
48830Sstevel@tonic-gate 						escape = 0;
48840Sstevel@tonic-gate 					if (balance)
48850Sstevel@tonic-gate 						next++;
48860Sstevel@tonic-gate 				}
48870Sstevel@tonic-gate 				if (balance != 0)
48880Sstevel@tonic-gate 					return (-1);
48890Sstevel@tonic-gate 
48900Sstevel@tonic-gate 				*next = '\0';
48910Sstevel@tonic-gate 				if (adj_simple_filter(str) == -1) {
48920Sstevel@tonic-gate 					return (-1);
48930Sstevel@tonic-gate 				}
48940Sstevel@tonic-gate 				next = resync_str(str, next, ')');
48950Sstevel@tonic-gate 				next++;
48960Sstevel@tonic-gate 				str = next;
48970Sstevel@tonic-gate 				parens--;
48980Sstevel@tonic-gate 				break;
48990Sstevel@tonic-gate 			}
49000Sstevel@tonic-gate 			break;
49010Sstevel@tonic-gate 
49020Sstevel@tonic-gate 		case ')':
49030Sstevel@tonic-gate 			str++;
49040Sstevel@tonic-gate 			parens--;
49050Sstevel@tonic-gate 			break;
49060Sstevel@tonic-gate 
49070Sstevel@tonic-gate 		case ' ':
49080Sstevel@tonic-gate 			str++;
49090Sstevel@tonic-gate 			break;
49100Sstevel@tonic-gate 
49110Sstevel@tonic-gate 		default:	/* assume it's a simple type=value filter */
49120Sstevel@tonic-gate 			next = strchr(str, '\0');
49130Sstevel@tonic-gate 			if (adj_simple_filter(str) == -1) {
49140Sstevel@tonic-gate 				return (-1);
49150Sstevel@tonic-gate 			}
49160Sstevel@tonic-gate 			str = next;
49170Sstevel@tonic-gate 			break;
49180Sstevel@tonic-gate 		}
49190Sstevel@tonic-gate 	}
49200Sstevel@tonic-gate 
49210Sstevel@tonic-gate 	return (parens ? -1 : 0);
49220Sstevel@tonic-gate }
49230Sstevel@tonic-gate 
49240Sstevel@tonic-gate 
49250Sstevel@tonic-gate /*
49260Sstevel@tonic-gate  * Put a list of filters like this "(filter1)(filter2)..."
49270Sstevel@tonic-gate  */
49280Sstevel@tonic-gate 
49290Sstevel@tonic-gate static int
adj_filter_list(char * str)49300Sstevel@tonic-gate adj_filter_list(char *str)
49310Sstevel@tonic-gate {
49320Sstevel@tonic-gate 	char	*next;
49330Sstevel@tonic-gate 	char	save;
49340Sstevel@tonic-gate 
49350Sstevel@tonic-gate 	while (*str) {
49360Sstevel@tonic-gate 		while (*str && isspace(*str))
49370Sstevel@tonic-gate 			str++;
49380Sstevel@tonic-gate 		if (*str == '\0')
49390Sstevel@tonic-gate 			break;
49400Sstevel@tonic-gate 
49410Sstevel@tonic-gate 		if ((next = find_right_paren(str + 1)) == NULL)
49420Sstevel@tonic-gate 			return (-1);
49430Sstevel@tonic-gate 		save = *++next;
49440Sstevel@tonic-gate 
49450Sstevel@tonic-gate 		/* now we have "(filter)" with str pointing to it */
49460Sstevel@tonic-gate 		*next = '\0';
49470Sstevel@tonic-gate 		if (adj_filter(str) == -1)
49480Sstevel@tonic-gate 			return (-1);
49490Sstevel@tonic-gate 		next = resync_str(str, next, save);
49500Sstevel@tonic-gate 
49510Sstevel@tonic-gate 		str = next;
49520Sstevel@tonic-gate 	}
49530Sstevel@tonic-gate 
49540Sstevel@tonic-gate 	return (0);
49550Sstevel@tonic-gate }
49560Sstevel@tonic-gate 
49570Sstevel@tonic-gate 
49580Sstevel@tonic-gate /*
49590Sstevel@tonic-gate  * is_valid_attr - returns 1 if a is a syntactically valid left-hand side
49600Sstevel@tonic-gate  * of a filter expression, 0 otherwise.  A valid string may contain only
49610Sstevel@tonic-gate  * letters, numbers, hyphens, semi-colons, colons and periods. examples:
49620Sstevel@tonic-gate  *	cn
49630Sstevel@tonic-gate  *	cn;lang-fr
49640Sstevel@tonic-gate  *	1.2.3.4;binary;dynamic
49650Sstevel@tonic-gate  *	mail;dynamic
49660Sstevel@tonic-gate  *	cn:dn:1.2.3.4
49670Sstevel@tonic-gate  *
49680Sstevel@tonic-gate  * For compatibility with older servers, we also allow underscores in
49690Sstevel@tonic-gate  * attribute types, even through they are not allowed by the LDAPv3 RFCs.
49700Sstevel@tonic-gate  */
49710Sstevel@tonic-gate static int
is_valid_attr(char * a)49720Sstevel@tonic-gate is_valid_attr(char *a)
49730Sstevel@tonic-gate {
49740Sstevel@tonic-gate 	for (; *a; a++) {
49750Sstevel@tonic-gate 		if (!isascii(*a)) {
49760Sstevel@tonic-gate 			return (0);
49770Sstevel@tonic-gate 		} else if (!isalnum(*a)) {
49780Sstevel@tonic-gate 			switch (*a) {
49790Sstevel@tonic-gate 			case '-':
49800Sstevel@tonic-gate 			case '.':
49810Sstevel@tonic-gate 			case ';':
49820Sstevel@tonic-gate 			case ':':
49830Sstevel@tonic-gate 			case '_':
49840Sstevel@tonic-gate 				break; /* valid */
49850Sstevel@tonic-gate 			default:
49860Sstevel@tonic-gate 				return (0);
49870Sstevel@tonic-gate 			}
49880Sstevel@tonic-gate 		}
49890Sstevel@tonic-gate 	}
49900Sstevel@tonic-gate 	return (1);
49910Sstevel@tonic-gate }
49920Sstevel@tonic-gate 
49930Sstevel@tonic-gate static char *
find_star(char * s)49940Sstevel@tonic-gate find_star(char *s)
49950Sstevel@tonic-gate {
49960Sstevel@tonic-gate 	for (; *s; ++s) {
49970Sstevel@tonic-gate 		switch (*s) {
49980Sstevel@tonic-gate 		case '*':
49990Sstevel@tonic-gate 			return (s);
50000Sstevel@tonic-gate 		case '\\':
50010Sstevel@tonic-gate 			++s;
50020Sstevel@tonic-gate 			if (hexchar2int(s[0]) >= 0 && hexchar2int(s[1]) >= 0)
50030Sstevel@tonic-gate 				++s;
50040Sstevel@tonic-gate 		default:
50050Sstevel@tonic-gate 			break;
50060Sstevel@tonic-gate 		}
50070Sstevel@tonic-gate 	}
50080Sstevel@tonic-gate 	return (NULL);
50090Sstevel@tonic-gate }
50100Sstevel@tonic-gate 
50110Sstevel@tonic-gate static int
adj_simple_filter(char * str)50120Sstevel@tonic-gate adj_simple_filter(char *str)
50130Sstevel@tonic-gate {
50140Sstevel@tonic-gate 	char		*s, *s2, *s3, filterop;
50150Sstevel@tonic-gate 	char		*value;
50160Sstevel@tonic-gate 	int		ftype = 0;
50170Sstevel@tonic-gate 	int		rc;
50180Sstevel@tonic-gate 
50190Sstevel@tonic-gate 	rc = -1;	/* pessimistic */
50200Sstevel@tonic-gate 
50210Sstevel@tonic-gate 	if ((str = strdup(str)) == NULL) {
50220Sstevel@tonic-gate 		return (rc);
50230Sstevel@tonic-gate 	}
50240Sstevel@tonic-gate 
50250Sstevel@tonic-gate 	if ((s = strchr(str, '=')) == NULL) {
50260Sstevel@tonic-gate 		goto free_and_return;
50270Sstevel@tonic-gate 	}
50280Sstevel@tonic-gate 	value = s + 1;
50290Sstevel@tonic-gate 	*s-- = '\0';
50300Sstevel@tonic-gate 	filterop = *s;
50310Sstevel@tonic-gate 	if (filterop == '<' || filterop == '>' || filterop == '~' ||
50320Sstevel@tonic-gate 	    filterop == ':') {
50330Sstevel@tonic-gate 		*s = '\0';
50340Sstevel@tonic-gate 	}
50350Sstevel@tonic-gate 
50360Sstevel@tonic-gate 	if (! is_valid_attr(str)) {
50370Sstevel@tonic-gate 		goto free_and_return;
50380Sstevel@tonic-gate 	}
50390Sstevel@tonic-gate 
50400Sstevel@tonic-gate 	switch (filterop) {
50410Sstevel@tonic-gate 	case '<': /* LDAP_FILTER_LE */
50420Sstevel@tonic-gate 	case '>': /* LDAP_FILTER_GE */
50430Sstevel@tonic-gate 	case '~': /* LDAP_FILTER_APPROX */
50440Sstevel@tonic-gate 		break;
50450Sstevel@tonic-gate 	case ':':	/* extended filter - v3 only */
50460Sstevel@tonic-gate 		/*
50470Sstevel@tonic-gate 		 * extended filter looks like this:
50480Sstevel@tonic-gate 		 *
50490Sstevel@tonic-gate 		 *	[type][':dn'][':'oid]':='value
50500Sstevel@tonic-gate 		 *
50510Sstevel@tonic-gate 		 * where one of type or :oid is required.
50520Sstevel@tonic-gate 		 *
50530Sstevel@tonic-gate 		 */
50540Sstevel@tonic-gate 		s2 = s3 = NULL;
50550Sstevel@tonic-gate 		if ((s2 = strrchr(str, ':')) == NULL) {
50560Sstevel@tonic-gate 			goto free_and_return;
50570Sstevel@tonic-gate 		}
50580Sstevel@tonic-gate 		if (strcasecmp(s2, ":dn") == 0) {
50590Sstevel@tonic-gate 			*s2 = '\0';
50600Sstevel@tonic-gate 		} else {
50610Sstevel@tonic-gate 			*s2 = '\0';
50620Sstevel@tonic-gate 			if ((s3 = strrchr(str, ':')) != NULL) {
50630Sstevel@tonic-gate 				if (strcasecmp(s3, ":dn") != 0) {
50640Sstevel@tonic-gate 					goto free_and_return;
50650Sstevel@tonic-gate 				}
50660Sstevel@tonic-gate 				*s3 = '\0';
50670Sstevel@tonic-gate 			}
50680Sstevel@tonic-gate 		}
50690Sstevel@tonic-gate 		if (unescape_filterval(value) < 0) {
50700Sstevel@tonic-gate 			goto free_and_return;
50710Sstevel@tonic-gate 		}
50720Sstevel@tonic-gate 		rc = 0;
50730Sstevel@tonic-gate 		goto free_and_return;
50740Sstevel@tonic-gate 		/* break; */
50750Sstevel@tonic-gate 	default:
50760Sstevel@tonic-gate 		if (find_star(value) == NULL) {
50770Sstevel@tonic-gate 			ftype = 0; /* LDAP_FILTER_EQUALITY */
50780Sstevel@tonic-gate 		} else if (strcmp(value, "*") == 0) {
50790Sstevel@tonic-gate 			ftype = 1; /* LDAP_FILTER_PRESENT */
50800Sstevel@tonic-gate 		} else {
50810Sstevel@tonic-gate 			rc = adj_substring_filter(value);
50820Sstevel@tonic-gate 			goto free_and_return;
50830Sstevel@tonic-gate 		}
50840Sstevel@tonic-gate 		break;
50850Sstevel@tonic-gate 	}
50860Sstevel@tonic-gate 
50870Sstevel@tonic-gate 	if (ftype != 0) {	/* == LDAP_FILTER_PRESENT */
50880Sstevel@tonic-gate 		rc = 0;
50890Sstevel@tonic-gate 	} else if (unescape_filterval(value) >= 0) {
50900Sstevel@tonic-gate 		rc = 0;
50910Sstevel@tonic-gate 	}
50920Sstevel@tonic-gate 	if (rc != -1) {
50930Sstevel@tonic-gate 		rc = 0;
50940Sstevel@tonic-gate 	}
50950Sstevel@tonic-gate 
50960Sstevel@tonic-gate free_and_return:
50970Sstevel@tonic-gate 	free(str);
50980Sstevel@tonic-gate 	return (rc);
50990Sstevel@tonic-gate }
51000Sstevel@tonic-gate 
51010Sstevel@tonic-gate 
51020Sstevel@tonic-gate /*
51030Sstevel@tonic-gate  * Check in place both LDAPv2 (RFC-1960) and LDAPv3 (hexadecimal) escape
51040Sstevel@tonic-gate  * sequences within the null-terminated string 'val'.
51050Sstevel@tonic-gate  *
51060Sstevel@tonic-gate  * If 'val' contains invalid escape sequences we return -1.
51070Sstevel@tonic-gate  * Otherwise return 1
51080Sstevel@tonic-gate  */
51090Sstevel@tonic-gate static int
unescape_filterval(char * val)51100Sstevel@tonic-gate unescape_filterval(char *val)
51110Sstevel@tonic-gate {
51120Sstevel@tonic-gate 	int	escape, firstdigit;
51130Sstevel@tonic-gate 	char	*s;
51140Sstevel@tonic-gate 
51150Sstevel@tonic-gate 	firstdigit = 0;
51160Sstevel@tonic-gate 	escape = 0;
51170Sstevel@tonic-gate 	for (s = val; *s; s++) {
51180Sstevel@tonic-gate 		if (escape) {
51190Sstevel@tonic-gate 			/*
51200Sstevel@tonic-gate 			 * first try LDAPv3 escape (hexadecimal) sequence
51210Sstevel@tonic-gate 			 */
51220Sstevel@tonic-gate 			if (hexchar2int(*s) < 0) {
51230Sstevel@tonic-gate 				if (firstdigit) {
51240Sstevel@tonic-gate 					/*
51250Sstevel@tonic-gate 					 * LDAPv2 (RFC1960) escape sequence
51260Sstevel@tonic-gate 					 */
51270Sstevel@tonic-gate 					escape = 0;
51280Sstevel@tonic-gate 				} else {
51290Sstevel@tonic-gate 					return (-1);
51300Sstevel@tonic-gate 				}
51310Sstevel@tonic-gate 			}
51320Sstevel@tonic-gate 			if (firstdigit) {
51334765Smj162486 				firstdigit = 0;
51340Sstevel@tonic-gate 			} else {
51354765Smj162486 				escape = 0;
51360Sstevel@tonic-gate 			}
51370Sstevel@tonic-gate 
51380Sstevel@tonic-gate 		} else if (*s != '\\') {
51390Sstevel@tonic-gate 			escape = 0;
51400Sstevel@tonic-gate 
51410Sstevel@tonic-gate 		} else {
51420Sstevel@tonic-gate 			escape = 1;
51430Sstevel@tonic-gate 			firstdigit = 1;
51440Sstevel@tonic-gate 		}
51450Sstevel@tonic-gate 	}
51460Sstevel@tonic-gate 
51470Sstevel@tonic-gate 	return (1);
51480Sstevel@tonic-gate }
51490Sstevel@tonic-gate 
51500Sstevel@tonic-gate 
51510Sstevel@tonic-gate /*
51520Sstevel@tonic-gate  * convert character 'c' that represents a hexadecimal digit to an integer.
51530Sstevel@tonic-gate  * if 'c' is not a hexidecimal digit [0-9A-Fa-f], -1 is returned.
51540Sstevel@tonic-gate  * otherwise the converted value is returned.
51550Sstevel@tonic-gate  */
51560Sstevel@tonic-gate static int
hexchar2int(char c)51570Sstevel@tonic-gate hexchar2int(char c)
51580Sstevel@tonic-gate {
51590Sstevel@tonic-gate 	if (c >= '0' && c <= '9') {
51600Sstevel@tonic-gate 		return (c - '0');
51610Sstevel@tonic-gate 	}
51620Sstevel@tonic-gate 	if (c >= 'A' && c <= 'F') {
51630Sstevel@tonic-gate 		return (c - 'A' + 10);
51640Sstevel@tonic-gate 	}
51650Sstevel@tonic-gate 	if (c >= 'a' && c <= 'f') {
51660Sstevel@tonic-gate 		return (c - 'a' + 10);
51670Sstevel@tonic-gate 	}
51680Sstevel@tonic-gate 	return (-1);
51690Sstevel@tonic-gate }
51700Sstevel@tonic-gate 
51710Sstevel@tonic-gate static int
adj_substring_filter(char * val)51720Sstevel@tonic-gate adj_substring_filter(char *val)
51730Sstevel@tonic-gate {
51740Sstevel@tonic-gate 	char		*nextstar;
51750Sstevel@tonic-gate 
51760Sstevel@tonic-gate 	for (; val != NULL; val = nextstar) {
51770Sstevel@tonic-gate 		if ((nextstar = find_star(val)) != NULL) {
51780Sstevel@tonic-gate 			*nextstar++ = '\0';
51790Sstevel@tonic-gate 		}
51800Sstevel@tonic-gate 
51810Sstevel@tonic-gate 		if (*val != '\0') {
51820Sstevel@tonic-gate 			if (unescape_filterval(val) < 0) {
51830Sstevel@tonic-gate 				return (-1);
51840Sstevel@tonic-gate 			}
51850Sstevel@tonic-gate 		}
51860Sstevel@tonic-gate 	}
51870Sstevel@tonic-gate 
51880Sstevel@tonic-gate 	return (0);
51890Sstevel@tonic-gate }
51900Sstevel@tonic-gate 
51910Sstevel@tonic-gate /* ***** End of modified libldap.so.5 filter parser ***** */
51920Sstevel@tonic-gate 
51930Sstevel@tonic-gate 
51940Sstevel@tonic-gate /*
51950Sstevel@tonic-gate  * Walk filter, remove redundant parentheses in-line
51960Sstevel@tonic-gate  * verify that the filter is reasonable
51970Sstevel@tonic-gate  */
51980Sstevel@tonic-gate static int
validate_filter(ns_ldap_cookie_t * cookie)51990Sstevel@tonic-gate validate_filter(ns_ldap_cookie_t *cookie)
52000Sstevel@tonic-gate {
52010Sstevel@tonic-gate 	char			*filter = cookie->filter;
52020Sstevel@tonic-gate 	int			rc;
52030Sstevel@tonic-gate 
52040Sstevel@tonic-gate 	/* Parse filter looking for illegal values */
52050Sstevel@tonic-gate 
52060Sstevel@tonic-gate 	rc = adj_filter(filter);
52070Sstevel@tonic-gate 	if (rc != 0) {
52080Sstevel@tonic-gate 		return (NS_LDAP_OP_FAILED);
52090Sstevel@tonic-gate 	}
52100Sstevel@tonic-gate 
52110Sstevel@tonic-gate 	/* end of filter checking */
52120Sstevel@tonic-gate 
52130Sstevel@tonic-gate 	return (NS_LDAP_SUCCESS);
52140Sstevel@tonic-gate }
52151179Svv149972 
52161179Svv149972 /*
52171179Svv149972  * Set the account management request control that needs to be sent to server.
52181179Svv149972  * This control is required to get the account management information of
52191179Svv149972  * a user to do local account checking.
52201179Svv149972  */
52211179Svv149972 static int
setup_acctmgmt_params(ns_ldap_cookie_t * cookie)52221179Svv149972 setup_acctmgmt_params(ns_ldap_cookie_t *cookie)
52231179Svv149972 {
52241179Svv149972 	LDAPControl	*req = NULL, **requestctrls;
52251179Svv149972 
52261179Svv149972 	req = (LDAPControl *)malloc(sizeof (LDAPControl));
52271179Svv149972 
52281179Svv149972 	if (req == NULL)
52291179Svv149972 		return (NS_LDAP_MEMORY);
52301179Svv149972 
52311179Svv149972 	/* fill in the fields of this new control */
52321179Svv149972 	req->ldctl_iscritical = 1;
52331179Svv149972 	req->ldctl_oid = strdup(NS_LDAP_ACCOUNT_USABLE_CONTROL);
52341179Svv149972 	if (req->ldctl_oid == NULL) {
52351179Svv149972 		free(req);
52361179Svv149972 		return (NS_LDAP_MEMORY);
52371179Svv149972 	}
52381179Svv149972 	req->ldctl_value.bv_len = 0;
52391179Svv149972 	req->ldctl_value.bv_val = NULL;
52401179Svv149972 
52411179Svv149972 	requestctrls = (LDAPControl **)calloc(2, sizeof (LDAPControl *));
52421179Svv149972 	if (requestctrls == NULL) {
52431179Svv149972 		ldap_control_free(req);
52441179Svv149972 		return (NS_LDAP_MEMORY);
52451179Svv149972 	}
52461179Svv149972 
52471179Svv149972 	requestctrls[0] = req;
52481179Svv149972 
52491179Svv149972 	cookie->p_serverctrls = requestctrls;
52501179Svv149972 
52511179Svv149972 	return (NS_LDAP_SUCCESS);
52521179Svv149972 }
52531179Svv149972 
52541179Svv149972 /*
52554790Ssdussud  * int get_new_acct_more_info(BerElement *ber,
52564790Ssdussud  *     AcctUsableResponse_t *acctResp)
52574790Ssdussud  *
52584790Ssdussud  * Decode the more_info data from an Account Management control response,
52594790Ssdussud  * when the account is not usable and when code style is from recent LDAP
52604790Ssdussud  * servers (see below comments for parse_acct_cont_resp_msg() to get more
52614790Ssdussud  * details on coding styles and ASN1 description).
52624790Ssdussud  *
52634790Ssdussud  * Expected BER encoding: {tbtbtbtiti}
52644790Ssdussud  *      +t: tag is 0
52651179Svv149972  *	+b: TRUE if inactive due to account inactivation
52664790Ssdussud  *      +t: tag is 1
52671179Svv149972  * 	+b: TRUE if password has been reset
52684790Ssdussud  *      +t: tag is 2
52691179Svv149972  * 	+b: TRUE if password is expired
52704790Ssdussud  *	+t: tag is 3
52714790Ssdussud  *	+i: contains num of remaining grace, 0 means no grace
52724790Ssdussud  *	+t: tag is 4
52734790Ssdussud  *	+i: contains num of seconds before auto-unlock. -1 means acct is locked
52744790Ssdussud  *		forever (i.e. until reset)
52754790Ssdussud  *
52764790Ssdussud  * Asumptions:
52774790Ssdussud  * - ber is not null
52784790Ssdussud  * - acctResp is not null and is initialized with default values for the
52794790Ssdussud  *   fields in its AcctUsableResp.more_info structure
52804790Ssdussud  * - the ber stream is received in the correct order, per the ASN1 description.
52814790Ssdussud  *   We do not check this order and make the asumption that it is correct.
52824790Ssdussud  *   Note that the ber stream may not (and will not in most cases) contain
52834790Ssdussud  *   all fields.
52844790Ssdussud  */
52854790Ssdussud static int
get_new_acct_more_info(BerElement * ber,AcctUsableResponse_t * acctResp)52864790Ssdussud get_new_acct_more_info(BerElement *ber, AcctUsableResponse_t *acctResp)
52874790Ssdussud {
52884790Ssdussud 	int		rc = NS_LDAP_SUCCESS;
52894790Ssdussud 	char		errstr[MAXERROR];
52904790Ssdussud 	ber_tag_t	rTag = LBER_DEFAULT;
52914790Ssdussud 	ber_len_t	rLen = 0;
52924790Ssdussud 	ber_int_t	rValue;
52934790Ssdussud 	char		*last;
52944790Ssdussud 	int		berRC = 0;
52954790Ssdussud 
52964790Ssdussud 	/*
52974790Ssdussud 	 * Look at what more_info BER element is/are left to be decoded.
52984790Ssdussud 	 * look at each of them 1 by 1, without checking on their order
52994790Ssdussud 	 * and possible multi values.
53004790Ssdussud 	 */
53014790Ssdussud 	for (rTag = ber_first_element(ber, &rLen, &last);
53024790Ssdussud 	    rTag != LBER_END_OF_SEQORSET;
53034790Ssdussud 	    rTag = ber_next_element(ber, &rLen, last)) {
53044790Ssdussud 
53054790Ssdussud 		berRC = 0;
53064790Ssdussud 		switch (rTag) {
53074790Ssdussud 		case 0 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
53084790Ssdussud 			/* inactive */
53094790Ssdussud 			berRC = ber_scanf(ber, "b", &rValue);
53104790Ssdussud 			if (berRC != LBER_ERROR) {
53114790Ssdussud 				(acctResp->AcctUsableResp).more_info.
53124790Ssdussud 				    inactive = (rValue != 0) ? 1 : 0;
53134790Ssdussud 			}
53144790Ssdussud 			break;
53154790Ssdussud 
53164790Ssdussud 		case 1 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
53174790Ssdussud 			/* reset */
53184790Ssdussud 			berRC = ber_scanf(ber, "b", &rValue);
53194790Ssdussud 			if (berRC != LBER_ERROR) {
53204790Ssdussud 				(acctResp->AcctUsableResp).more_info.reset
53214790Ssdussud 				    = (rValue != 0) ? 1 : 0;
53224790Ssdussud 			}
53234790Ssdussud 			break;
53244790Ssdussud 
53254790Ssdussud 		case 2 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
53264790Ssdussud 			/* expired */
53274790Ssdussud 			berRC = ber_scanf(ber, "b", &rValue);
53284790Ssdussud 			if (berRC != LBER_ERROR) {
53294790Ssdussud 				(acctResp->AcctUsableResp).more_info.expired
53304790Ssdussud 				    = (rValue != 0) ? 1 : 0;
53314790Ssdussud 			}
53324790Ssdussud 			break;
53334790Ssdussud 
53344790Ssdussud 		case 3 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
53354790Ssdussud 			/* remaining grace */
53364790Ssdussud 			berRC = ber_scanf(ber, "i", &rValue);
53374790Ssdussud 			if (berRC != LBER_ERROR) {
53384790Ssdussud 				(acctResp->AcctUsableResp).more_info.rem_grace
53394790Ssdussud 				    = rValue;
53404790Ssdussud 			}
53414790Ssdussud 			break;
53424790Ssdussud 
53434790Ssdussud 		case 4 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE:
53444790Ssdussud 			/* seconds before unlock */
53454790Ssdussud 			berRC = ber_scanf(ber, "i", &rValue);
53464790Ssdussud 			if (berRC != LBER_ERROR) {
53474790Ssdussud 				(acctResp->AcctUsableResp).more_info.
53484790Ssdussud 				    sec_b4_unlock = rValue;
53494790Ssdussud 			}
53504790Ssdussud 			break;
53514790Ssdussud 
53524790Ssdussud 		default :
53534790Ssdussud 			(void) sprintf(errstr,
53544790Ssdussud 			    gettext("invalid reason tag 0x%x"), rTag);
53554790Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
53564790Ssdussud 			rc = NS_LDAP_INTERNAL;
53574790Ssdussud 			break;
53584790Ssdussud 		}
53594790Ssdussud 		if (berRC == LBER_ERROR) {
53604790Ssdussud 			(void) sprintf(errstr,
53614790Ssdussud 			    gettext("error 0x%x decoding value for "
53624790Ssdussud 			    "tag 0x%x"), berRC, rTag);
53634790Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
53644790Ssdussud 			rc = NS_LDAP_INTERNAL;
53654790Ssdussud 		}
53664790Ssdussud 		if (rc != NS_LDAP_SUCCESS) {
53674790Ssdussud 			/* exit the for loop */
53684790Ssdussud 			break;
53694790Ssdussud 		}
53704790Ssdussud 	}
53714790Ssdussud 
53724790Ssdussud 	return (rc);
53734790Ssdussud }
53744790Ssdussud 
53754790Ssdussud /*
53764790Ssdussud  * int get_old_acct_opt_more_info(BerElement *ber,
53774790Ssdussud  *     AcctUsableResponse_t *acctResp)
53784790Ssdussud  *
53794790Ssdussud  * Decode the optional more_info data from an Account Management control
53804790Ssdussud  * response, when the account is not usable and when code style is from LDAP
53814790Ssdussud  * server 5.2p4 (see below comments for parse_acct_cont_resp_msg() to get more
53824790Ssdussud  * details on coding styles and ASN1 description).
53834790Ssdussud  *
53844790Ssdussud  * Expected BER encoding: titi}
53851179Svv149972  *	+t: tag is 2
53861179Svv149972  *	+i: contains num of remaining grace, 0 means no grace
53871179Svv149972  *	+t: tag is 3
53881179Svv149972  *	+i: contains num of seconds before auto-unlock. -1 means acct is locked
53891179Svv149972  *		forever (i.e. until reset)
53904790Ssdussud  *
53914790Ssdussud  * Asumptions:
53924790Ssdussud  * - ber is a valid BER element
53934790Ssdussud  * - acctResp is initialized for the fields in its AcctUsableResp.more_info
53944790Ssdussud  *   structure
53951179Svv149972  */
53961179Svv149972 static int
get_old_acct_opt_more_info(ber_tag_t tag,BerElement * ber,AcctUsableResponse_t * acctResp)53974790Ssdussud get_old_acct_opt_more_info(ber_tag_t tag, BerElement *ber,
53984790Ssdussud     AcctUsableResponse_t *acctResp)
53994790Ssdussud {
54004790Ssdussud 	int		rc = NS_LDAP_SUCCESS;
54014790Ssdussud 	char		errstr[MAXERROR];
54024790Ssdussud 	ber_len_t	len;
54034790Ssdussud 	int		rem_grace, sec_b4_unlock;
54044790Ssdussud 
54054790Ssdussud 	switch (tag) {
54064790Ssdussud 	case 2:
54074790Ssdussud 		/* decode and maybe 3 is following */
54084790Ssdussud 		if ((tag = ber_scanf(ber, "i", &rem_grace)) == LBER_ERROR) {
54094790Ssdussud 			(void) sprintf(errstr, gettext("Can not get "
54104790Ssdussud 			    "rem_grace"));
54114790Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
54124790Ssdussud 			rc = NS_LDAP_INTERNAL;
54134790Ssdussud 			break;
54144790Ssdussud 		}
54154790Ssdussud 		(acctResp->AcctUsableResp).more_info.rem_grace = rem_grace;
54164790Ssdussud 
54174790Ssdussud 		if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
54184790Ssdussud 			/* this is a success case, break to exit */
54194790Ssdussud 			(void) sprintf(errstr, gettext("No more "
54204790Ssdussud 			    "optional data"));
54214790Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
54224790Ssdussud 			break;
54234790Ssdussud 		}
54244790Ssdussud 
54254790Ssdussud 		if (tag == 3) {
54264790Ssdussud 			if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
54274790Ssdussud 				(void) sprintf(errstr,
54284790Ssdussud 				    gettext("Can not get sec_b4_unlock "
54294790Ssdussud 				    "- 1st case"));
54304790Ssdussud 				syslog(LOG_DEBUG, "libsldap: %s", errstr);
54314790Ssdussud 				rc = NS_LDAP_INTERNAL;
54324790Ssdussud 				break;
54334790Ssdussud 			}
54344790Ssdussud 			(acctResp->AcctUsableResp).more_info.sec_b4_unlock =
54354790Ssdussud 			    sec_b4_unlock;
54364790Ssdussud 		} else { /* unknown tag */
54374790Ssdussud 			(void) sprintf(errstr, gettext("Unknown tag "
54384790Ssdussud 			    "- 1st case"));
54394790Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
54404790Ssdussud 			rc = NS_LDAP_INTERNAL;
54414790Ssdussud 			break;
54424790Ssdussud 		}
54434790Ssdussud 		break;
54444790Ssdussud 
54454790Ssdussud 	case 3:
54464790Ssdussud 		if (ber_scanf(ber, "i", &sec_b4_unlock) == LBER_ERROR) {
54474790Ssdussud 			(void) sprintf(errstr, gettext("Can not get "
54484790Ssdussud 			    "sec_b4_unlock - 2nd case"));
54494790Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
54504790Ssdussud 			rc = NS_LDAP_INTERNAL;
54514790Ssdussud 			break;
54524790Ssdussud 		}
54534790Ssdussud 		(acctResp->AcctUsableResp).more_info.sec_b4_unlock =
54544790Ssdussud 		    sec_b4_unlock;
54554790Ssdussud 		break;
54564790Ssdussud 
54574790Ssdussud 	default: /* unknown tag */
54584790Ssdussud 		(void) sprintf(errstr, gettext("Unknown tag - 2nd case"));
54594790Ssdussud 		syslog(LOG_DEBUG, "libsldap: %s", errstr);
54604790Ssdussud 		rc = NS_LDAP_INTERNAL;
54614790Ssdussud 		break;
54624790Ssdussud 	}
54634790Ssdussud 
54644790Ssdussud 	return (rc);
54654790Ssdussud }
54664790Ssdussud 
54674790Ssdussud /*
54684790Ssdussud  * **** This function needs to be moved to libldap library ****
54694790Ssdussud  * parse_acct_cont_resp_msg() parses the message received by server according to
54704790Ssdussud  * following format (ASN1 notation):
54714790Ssdussud  *
54724790Ssdussud  *	ACCOUNT_USABLE_RESPONSE::= CHOICE {
54734790Ssdussud  *		is_available		[0] INTEGER,
54744790Ssdussud  *				** seconds before expiration **
54754790Ssdussud  *		is_not_available	[1] more_info
54764790Ssdussud  *	}
54774790Ssdussud  *	more_info::= SEQUENCE {
54784790Ssdussud  *		inactive		[0] BOOLEAN DEFAULT FALSE,
54794790Ssdussud  *		reset			[1] BOOLEAN DEFAULT FALSE,
54804790Ssdussud  *		expired			[2] BOOLEAN DEFAULT FALSE,
54814790Ssdussud  *		remaining_grace		[3] INTEGER OPTIONAL,
54824790Ssdussud  *		seconds_before_unlock	[4] INTEGER OPTIONAL
54834790Ssdussud  *	}
54844790Ssdussud  */
54854790Ssdussud /*
54864790Ssdussud  * #define used to make the difference between coding style as done
54874790Ssdussud  * by LDAP server 5.2p4 and newer LDAP servers. There are 4 values:
54884790Ssdussud  * - DS52p4_USABLE: 5.2p4 coding style, account is usable
54894790Ssdussud  * - DS52p4_NOT_USABLE: 5.2p4 coding style, account is not usable
54904790Ssdussud  * - NEW_USABLE: newer LDAP servers coding style, account is usable
54914790Ssdussud  * - NEW_NOT_USABLE: newer LDAP servers coding style, account is not usable
54924790Ssdussud  *
54934790Ssdussud  * An account would be considered not usable if for instance:
54944790Ssdussud  * - it's been made inactive in the LDAP server
54954790Ssdussud  * - or its password was reset in the LDAP server database
54964790Ssdussud  * - or its password expired
54974790Ssdussud  * - or the account has been locked, possibly forever
54984790Ssdussud  */
54994790Ssdussud #define	DS52p4_USABLE		0x00
55004790Ssdussud #define	DS52p4_NOT_USABLE	0x01
55014790Ssdussud #define	NEW_USABLE		0x00 | LBER_CLASS_CONTEXT | LBER_PRIMITIVE
55024790Ssdussud #define	NEW_NOT_USABLE		0x01 | LBER_CLASS_CONTEXT | LBER_CONSTRUCTED
55034790Ssdussud static int
parse_acct_cont_resp_msg(LDAPControl ** ectrls,AcctUsableResponse_t * acctResp)55041179Svv149972 parse_acct_cont_resp_msg(LDAPControl **ectrls, AcctUsableResponse_t *acctResp)
55051179Svv149972 {
55064790Ssdussud 	int		rc = NS_LDAP_SUCCESS;
55071179Svv149972 	BerElement	*ber;
55084790Ssdussud 	ber_tag_t 	tag;
55091179Svv149972 	ber_len_t	len;
55104790Ssdussud 	int		i;
55114790Ssdussud 	char		errstr[MAXERROR];
55124790Ssdussud 	/* used for any coding style when account is usable */
55134790Ssdussud 	int		seconds_before_expiry;
55144790Ssdussud 	/* used for 5.2p4 coding style when account is not usable */
55154790Ssdussud 	int		inactive, reset, expired;
55164790Ssdussud 
55174790Ssdussud 	if (ectrls == NULL) {
55184790Ssdussud 		(void) sprintf(errstr, gettext("Invalid ectrls parameter"));
55194790Ssdussud 		syslog(LOG_DEBUG, "libsldap: %s", errstr);
55201179Svv149972 		return (NS_LDAP_INVALID_PARAM);
55214790Ssdussud 	}
55221179Svv149972 
55231179Svv149972 	for (i = 0; ectrls[i] != NULL; i++) {
55241179Svv149972 		if (strcmp(ectrls[i]->ldctl_oid, NS_LDAP_ACCOUNT_USABLE_CONTROL)
55254790Ssdussud 		    == 0) {
55264790Ssdussud 			break;
55274790Ssdussud 		}
55281179Svv149972 	}
55294790Ssdussud 
55304790Ssdussud 	if (ectrls[i] == NULL) {
55314790Ssdussud 		/* Ldap control is not found */
55324790Ssdussud 		(void) sprintf(errstr, gettext("Account Usable Control "
55334790Ssdussud 		    "not found"));
55344790Ssdussud 		syslog(LOG_DEBUG, "libsldap: %s", errstr);
55354790Ssdussud 		return (NS_LDAP_NOTFOUND);
55364790Ssdussud 	}
55374790Ssdussud 
55384790Ssdussud 	/* Allocate a BER element from the control value and parse it. */
55391179Svv149972 	if ((ber = ber_init(&ectrls[i]->ldctl_value)) == NULL)
55401179Svv149972 		return (NS_LDAP_MEMORY);
55411179Svv149972 
55421179Svv149972 	if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
55431179Svv149972 		/* Ldap decoding error */
55444790Ssdussud 		(void) sprintf(errstr, gettext("Error decoding 1st tag"));
55454790Ssdussud 		syslog(LOG_DEBUG, "libsldap: %s", errstr);
55461179Svv149972 		ber_free(ber, 1);
55471179Svv149972 		return (NS_LDAP_INTERNAL);
55481179Svv149972 	}
55491179Svv149972 
55501179Svv149972 	switch (tag) {
55514790Ssdussud 	case DS52p4_USABLE:
55524790Ssdussud 	case NEW_USABLE:
55534790Ssdussud 		acctResp->choice = 0;
55544790Ssdussud 		if (ber_scanf(ber, "i", &seconds_before_expiry)
55554790Ssdussud 		    == LBER_ERROR) {
55564790Ssdussud 			/* Ldap decoding error */
55574790Ssdussud 			(void) sprintf(errstr, gettext("Can not get "
55584790Ssdussud 			    "seconds_before_expiry"));
55594790Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
55604790Ssdussud 			rc = NS_LDAP_INTERNAL;
55614790Ssdussud 			break;
55624790Ssdussud 		}
55634790Ssdussud 		/* ber_scanf() succeeded */
55644790Ssdussud 		(acctResp->AcctUsableResp).seconds_before_expiry =
55654790Ssdussud 		    seconds_before_expiry;
55664790Ssdussud 		break;
55674790Ssdussud 
55684790Ssdussud 	case DS52p4_NOT_USABLE:
55694790Ssdussud 		acctResp->choice = 1;
55704790Ssdussud 		if (ber_scanf(ber, "{bbb", &inactive, &reset, &expired)
55714790Ssdussud 		    == LBER_ERROR) {
55724790Ssdussud 			/* Ldap decoding error */
55734790Ssdussud 			(void) sprintf(errstr, gettext("Can not get "
55744790Ssdussud 			    "inactive/reset/expired"));
55754790Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
55764790Ssdussud 			rc = NS_LDAP_INTERNAL;
55774790Ssdussud 			break;
55784790Ssdussud 		}
55794790Ssdussud 		/* ber_scanf() succeeded */
55804790Ssdussud 		(acctResp->AcctUsableResp).more_info.inactive =
55814790Ssdussud 		    ((inactive == 0) ? 0 : 1);
55824790Ssdussud 		(acctResp->AcctUsableResp).more_info.reset =
55834790Ssdussud 		    ((reset == 0) ? 0 : 1);
55844790Ssdussud 		(acctResp->AcctUsableResp).more_info.expired =
55854790Ssdussud 		    ((expired == 0) ? 0 : 1);
55864790Ssdussud 		(acctResp->AcctUsableResp).more_info.rem_grace = 0;
55874790Ssdussud 		(acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
55884790Ssdussud 
55894790Ssdussud 		if ((tag = ber_peek_tag(ber, &len)) == LBER_ERROR) {
55904790Ssdussud 			/* this is a success case, break to exit */
55914790Ssdussud 			(void) sprintf(errstr, gettext("No optional data"));
55924790Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
55931179Svv149972 			break;
55944790Ssdussud 		}
55954790Ssdussud 
55964790Ssdussud 		/*
55974790Ssdussud 		 * Look at what optional more_info BER element is/are
55984790Ssdussud 		 * left to be decoded.
55994790Ssdussud 		 */
56004790Ssdussud 		rc = get_old_acct_opt_more_info(tag, ber, acctResp);
56014790Ssdussud 		break;
56024790Ssdussud 
56034790Ssdussud 	case NEW_NOT_USABLE:
56044790Ssdussud 		acctResp->choice = 1;
56054790Ssdussud 		/*
56064790Ssdussud 		 * Recent LDAP servers won't code more_info data for default
56074790Ssdussud 		 * values (see above comments on ASN1 description for what
56084790Ssdussud 		 * fields have default values & what fields are optional).
56094790Ssdussud 		 */
56104790Ssdussud 		(acctResp->AcctUsableResp).more_info.inactive = 0;
56114790Ssdussud 		(acctResp->AcctUsableResp).more_info.reset = 0;
56124790Ssdussud 		(acctResp->AcctUsableResp).more_info.expired = 0;
56134790Ssdussud 		(acctResp->AcctUsableResp).more_info.rem_grace = 0;
56144790Ssdussud 		(acctResp->AcctUsableResp).more_info.sec_b4_unlock = 0;
56154790Ssdussud 
56164790Ssdussud 		if (len == 0) {
56174790Ssdussud 			/*
56184790Ssdussud 			 * Nothing else to decode; this is valid and we
56194790Ssdussud 			 * use default values set above.
56204790Ssdussud 			 */
56214790Ssdussud 			(void) sprintf(errstr, gettext("more_info is "
56224790Ssdussud 			    "empty, using default values"));
56234790Ssdussud 			syslog(LOG_DEBUG, "libsldap: %s", errstr);
56241179Svv149972 			break;
56254790Ssdussud 		}
56264790Ssdussud 
56274790Ssdussud 		/*
56284790Ssdussud 		 * Look at what more_info BER element is/are left to
56294790Ssdussud 		 * be decoded.
56304790Ssdussud 		 */
56314790Ssdussud 		rc = get_new_acct_more_info(ber, acctResp);
56324790Ssdussud 		break;
56334790Ssdussud 
56344790Ssdussud 	default:
56354790Ssdussud 		(void) sprintf(errstr, gettext("unknwon coding style "
56364790Ssdussud 		    "(tag: 0x%x)"), tag);
56374790Ssdussud 		syslog(LOG_DEBUG, "libsldap: %s", errstr);
56384790Ssdussud 		rc = NS_LDAP_INTERNAL;
56394790Ssdussud 		break;
56401179Svv149972 	}
56411179Svv149972 
56421179Svv149972 	ber_free(ber, 1);
56434790Ssdussud 	return (rc);
56441179Svv149972 }
56451179Svv149972 
56461179Svv149972 /*
56476842Sth160488  * internal function for __ns_ldap_getAcctMgmt()
56481179Svv149972  */
56496842Sth160488 static int
getAcctMgmt(const char * user,AcctUsableResponse_t * acctResp,ns_conn_user_t * conn_user)56506842Sth160488 getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp,
56516842Sth160488 	ns_conn_user_t *conn_user)
56521179Svv149972 {
56531179Svv149972 	int		scope, rc;
56541179Svv149972 	char		ldapfilter[1024];
56551179Svv149972 	ns_ldap_cookie_t	*cookie;
56561179Svv149972 	ns_ldap_search_desc_t	**sdlist = NULL;
56571179Svv149972 	ns_ldap_search_desc_t	*dptr;
56581179Svv149972 	ns_ldap_error_t		*error = NULL;
56591179Svv149972 	char			**dns = NULL;
56601179Svv149972 	char		service[] = "shadow";
56611179Svv149972 
56621179Svv149972 	if (user == NULL || acctResp == NULL)
56631179Svv149972 		return (NS_LDAP_INVALID_PARAM);
56641179Svv149972 
56651179Svv149972 	/* Initialize State machine cookie */
56661179Svv149972 	cookie = init_search_state_machine();
56671179Svv149972 	if (cookie == NULL)
56681179Svv149972 		return (NS_LDAP_MEMORY);
56696842Sth160488 	cookie->conn_user = conn_user;
56701179Svv149972 
56711179Svv149972 	/* see if need to follow referrals */
56721179Svv149972 	rc = __s_api_toFollowReferrals(0,
56734765Smj162486 	    &cookie->followRef, &error);
56741179Svv149972 	if (rc != NS_LDAP_SUCCESS) {
56751179Svv149972 		(void) __ns_ldap_freeError(&error);
56761179Svv149972 		goto out;
56771179Svv149972 	}
56781179Svv149972 
56791179Svv149972 	/* get the service descriptor - or create a default one */
56801179Svv149972 	rc = __s_api_get_SSD_from_SSDtoUse_service(service,
56814765Smj162486 	    &sdlist, &error);
56821179Svv149972 	if (rc != NS_LDAP_SUCCESS) {
56831179Svv149972 		(void) __ns_ldap_freeError(&error);
56841179Svv149972 		goto out;
56851179Svv149972 	}
56861179Svv149972 
56871179Svv149972 	if (sdlist == NULL) {
56881179Svv149972 		/* Create default service Desc */
56891179Svv149972 		sdlist = (ns_ldap_search_desc_t **)calloc(2,
56904765Smj162486 		    sizeof (ns_ldap_search_desc_t *));
56911179Svv149972 		if (sdlist == NULL) {
56921179Svv149972 			rc = NS_LDAP_MEMORY;
56931179Svv149972 			goto out;
56941179Svv149972 		}
56951179Svv149972 		dptr = (ns_ldap_search_desc_t *)
56964765Smj162486 		    calloc(1, sizeof (ns_ldap_search_desc_t));
56971179Svv149972 		if (dptr == NULL) {
56981179Svv149972 			free(sdlist);
56991179Svv149972 			rc = NS_LDAP_MEMORY;
57001179Svv149972 			goto out;
57011179Svv149972 		}
57021179Svv149972 		sdlist[0] = dptr;
57031179Svv149972 
57041179Svv149972 		/* default base */
57051179Svv149972 		rc = __s_api_getDNs(&dns, service, &cookie->errorp);
57061179Svv149972 		if (rc != NS_LDAP_SUCCESS) {
57071179Svv149972 			if (dns) {
57081179Svv149972 				__s_api_free2dArray(dns);
57091179Svv149972 				dns = NULL;
57101179Svv149972 			}
57111179Svv149972 			(void) __ns_ldap_freeError(&(cookie->errorp));
57121179Svv149972 			cookie->errorp = NULL;
57131179Svv149972 			goto out;
57141179Svv149972 		}
57151179Svv149972 		dptr->basedn = strdup(dns[0]);
57161179Svv149972 		if (dptr->basedn == NULL) {
57171179Svv149972 			free(sdlist);
57181179Svv149972 			free(dptr);
57191179Svv149972 			if (dns) {
57201179Svv149972 				__s_api_free2dArray(dns);
57211179Svv149972 				dns = NULL;
57221179Svv149972 			}
57231179Svv149972 			rc = NS_LDAP_MEMORY;
57241179Svv149972 			goto out;
57251179Svv149972 		}
57261179Svv149972 		__s_api_free2dArray(dns);
57271179Svv149972 		dns = NULL;
57281179Svv149972 
57291179Svv149972 		/* default scope */
57301179Svv149972 		scope = 0;
57311179Svv149972 		rc = __s_api_getSearchScope(&scope, &cookie->errorp);
57321179Svv149972 		dptr->scope = scope;
57331179Svv149972 	}
57341179Svv149972 
57351179Svv149972 	cookie->sdlist = sdlist;
57361179Svv149972 
57371179Svv149972 	cookie->service = strdup(service);
57381179Svv149972 	if (cookie->service == NULL) {
57391179Svv149972 		rc = NS_LDAP_MEMORY;
57401179Svv149972 		goto out;
57411179Svv149972 	}
57421179Svv149972 
57431179Svv149972 	/* search for entries for this particular uid */
57441179Svv149972 	(void) snprintf(ldapfilter, sizeof (ldapfilter), "(uid=%s)", user);
57451179Svv149972 	cookie->i_filter = strdup(ldapfilter);
57461179Svv149972 	if (cookie->i_filter == NULL) {
57471179Svv149972 		rc = NS_LDAP_MEMORY;
57481179Svv149972 		goto out;
57491179Svv149972 	}
57501179Svv149972 
57511179Svv149972 	/* create the control request */
57521179Svv149972 	if ((rc = setup_acctmgmt_params(cookie)) != NS_LDAP_SUCCESS)
57531179Svv149972 		goto out;
57541179Svv149972 
57551179Svv149972 	/* Process search */
57561179Svv149972 	rc = search_state_machine(cookie, GET_ACCT_MGMT_INFO, 0);
57571179Svv149972 
57581179Svv149972 	/* Copy results back to user */
57591179Svv149972 	rc = cookie->err_rc;
57601179Svv149972 	if (rc != NS_LDAP_SUCCESS)
57611179Svv149972 			(void) __ns_ldap_freeError(&(cookie->errorp));
57621179Svv149972 
57631179Svv149972 	if (cookie->result == NULL)
57641179Svv149972 			goto out;
57651179Svv149972 
57661179Svv149972 	if ((rc = parse_acct_cont_resp_msg(cookie->resultctrl, acctResp))
57674765Smj162486 	    != NS_LDAP_SUCCESS)
57681179Svv149972 		goto out;
57691179Svv149972 
57701179Svv149972 	rc = NS_LDAP_SUCCESS;
57711179Svv149972 
57721179Svv149972 out:
57731179Svv149972 	delete_search_cookie(cookie);
57741179Svv149972 
57751179Svv149972 	return (rc);
57761179Svv149972 }
57776842Sth160488 
57786842Sth160488 /*
57796842Sth160488  * __ns_ldap_getAcctMgmt() is called from pam account management stack
57806842Sth160488  * for retrieving accounting information of users with no user password -
57816842Sth160488  * eg. rlogin, rsh, etc. This function uses the account management control
57826842Sth160488  * request to do a search on the server for the user in question. The
57836842Sth160488  * response control returned from the server is got from the cookie.
57846842Sth160488  * Input params: username of whose account mgmt information is to be got
57856842Sth160488  *		 pointer to hold the parsed account management information
57866842Sth160488  * Return values: NS_LDAP_SUCCESS on success or appropriate error
57876842Sth160488  *		code on failure
57886842Sth160488  */
57896842Sth160488 int
__ns_ldap_getAcctMgmt(const char * user,AcctUsableResponse_t * acctResp)57906842Sth160488 __ns_ldap_getAcctMgmt(const char *user, AcctUsableResponse_t *acctResp)
57916842Sth160488 {
57926842Sth160488 	ns_conn_user_t	*cu = NULL;
57936842Sth160488 	int		try_cnt = 0;
57946842Sth160488 	int		rc = NS_LDAP_SUCCESS;
57956842Sth160488 	ns_ldap_error_t	*error = NULL;
57966842Sth160488 
57976842Sth160488 	for (;;) {
57986842Sth160488 		if (__s_api_setup_retry_search(&cu, NS_CONN_USER_SEARCH,
57996842Sth160488 		    &try_cnt, &rc, &error) == 0)
58006842Sth160488 			break;
58016842Sth160488 		rc = getAcctMgmt(user, acctResp, cu);
58026842Sth160488 	}
58036842Sth160488 	return (rc);
58046842Sth160488 }
5805