xref: /titanic_50/usr/src/lib/libnisdb/ldap_op.c (revision a87701e9837f8a9ee9e4c4d3186295c0e29f743f)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
554caa916SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India  * Common Development and Distribution License (the "License").
654caa916SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*a87701e9SGary Mills  * Copyright 2015 Gary Mills
2354caa916SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <synch.h>
287c478bd9Sstevel@tonic-gate #include <strings.h>
297c478bd9Sstevel@tonic-gate #include <sys/time.h>
307c478bd9Sstevel@tonic-gate #include <ctype.h>
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #include "ldap_op.h"
337c478bd9Sstevel@tonic-gate #include "ldap_util.h"
347c478bd9Sstevel@tonic-gate #include "ldap_structs.h"
357c478bd9Sstevel@tonic-gate #include "ldap_ruleval.h"
367c478bd9Sstevel@tonic-gate #include "ldap_attr.h"
377c478bd9Sstevel@tonic-gate #include "ldap_print.h"
387c478bd9Sstevel@tonic-gate #include "ldap_glob.h"
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include "nis_parse_ldap_conf.h"
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #ifndef LDAPS_PORT
437c478bd9Sstevel@tonic-gate #define	LDAPS_PORT	636
447c478bd9Sstevel@tonic-gate #endif
457c478bd9Sstevel@tonic-gate 
46a506a34cSth160488 static int setupConList(char *serverList, char *who,
47a506a34cSth160488 			char *cred, auth_method_t method);
48a506a34cSth160488 
49a506a34cSth160488 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Build one of our internal LDAP search structures, containing copies of
527c478bd9Sstevel@tonic-gate  * the supplied input. return NULL in case of error.
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * If 'filter' is NULL, build an AND-filter using the filter components.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate __nis_ldap_search_t *
buildLdapSearch(char * base,int scope,int numFilterComps,char ** filterComp,char * filter,char ** attrs,int attrsonly,int isDN)577c478bd9Sstevel@tonic-gate buildLdapSearch(char *base, int scope, int numFilterComps, char **filterComp,
587c478bd9Sstevel@tonic-gate 		char *filter, char **attrs, int attrsonly, int isDN) {
597c478bd9Sstevel@tonic-gate 	__nis_ldap_search_t	*ls;
607c478bd9Sstevel@tonic-gate 	char			**a;
617c478bd9Sstevel@tonic-gate 	int			i, na, err = 0;
627c478bd9Sstevel@tonic-gate 	char			*myself = "buildLdapSearch";
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate 	ls = am(myself, sizeof (*ls));
657c478bd9Sstevel@tonic-gate 	if (ls == 0)
667c478bd9Sstevel@tonic-gate 		return (0);
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	ls->base = sdup(myself, T, base);
697c478bd9Sstevel@tonic-gate 	if (ls->base == 0 && base != 0)
707c478bd9Sstevel@tonic-gate 		err++;
717c478bd9Sstevel@tonic-gate 	ls->scope = scope;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	if (filterComp != 0 && numFilterComps > 0) {
747c478bd9Sstevel@tonic-gate 		ls->filterComp = am(myself, numFilterComps *
757c478bd9Sstevel@tonic-gate 					sizeof (ls->filterComp[0]));
767c478bd9Sstevel@tonic-gate 		if (ls->filterComp == 0) {
777c478bd9Sstevel@tonic-gate 			err++;
787c478bd9Sstevel@tonic-gate 			numFilterComps = 0;
797c478bd9Sstevel@tonic-gate 		}
807c478bd9Sstevel@tonic-gate 		for (i = 0; i < numFilterComps; i++) {
817c478bd9Sstevel@tonic-gate 			ls->filterComp[i] = sdup(myself, T, filterComp[i]);
827c478bd9Sstevel@tonic-gate 			if (ls->filterComp[i] == 0 && filterComp[i] != 0)
837c478bd9Sstevel@tonic-gate 				err++;
847c478bd9Sstevel@tonic-gate 		}
857c478bd9Sstevel@tonic-gate 		ls->numFilterComps = numFilterComps;
867c478bd9Sstevel@tonic-gate 		if (filter == 0) {
877c478bd9Sstevel@tonic-gate 			ls->filter = concatenateFilterComps(ls->numFilterComps,
887c478bd9Sstevel@tonic-gate 					ls->filterComp);
897c478bd9Sstevel@tonic-gate 			if (ls->filter == 0)
907c478bd9Sstevel@tonic-gate 				err++;
917c478bd9Sstevel@tonic-gate 		}
927c478bd9Sstevel@tonic-gate 	} else {
937c478bd9Sstevel@tonic-gate 		ls->filterComp = 0;
947c478bd9Sstevel@tonic-gate 		ls->numFilterComps = 0;
957c478bd9Sstevel@tonic-gate 		ls->filter = sdup(myself, T, filter);
967c478bd9Sstevel@tonic-gate 		if (ls->filter == 0 && filter != 0)
977c478bd9Sstevel@tonic-gate 			err++;
987c478bd9Sstevel@tonic-gate 	}
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	if (attrs != 0) {
1017c478bd9Sstevel@tonic-gate 		for (na = 0, a = attrs; *a != 0; a++, na++);
1027c478bd9Sstevel@tonic-gate 		ls->attrs = am(myself, (na + 1) * sizeof (ls->attrs[0]));
1037c478bd9Sstevel@tonic-gate 		if (ls->attrs != 0) {
1047c478bd9Sstevel@tonic-gate 			for (i = 0; i < na; i++) {
1057c478bd9Sstevel@tonic-gate 				ls->attrs[i] = sdup(myself, T, attrs[i]);
1067c478bd9Sstevel@tonic-gate 				if (ls->attrs[i] == 0 && attrs[i] != 0)
1077c478bd9Sstevel@tonic-gate 					err++;
1087c478bd9Sstevel@tonic-gate 			}
1097c478bd9Sstevel@tonic-gate 			ls->attrs[na] = 0;
1107c478bd9Sstevel@tonic-gate 			ls->numAttrs = na;
1117c478bd9Sstevel@tonic-gate 		} else {
1127c478bd9Sstevel@tonic-gate 			err++;
1137c478bd9Sstevel@tonic-gate 		}
1147c478bd9Sstevel@tonic-gate 	} else {
1157c478bd9Sstevel@tonic-gate 		ls->attrs = 0;
1167c478bd9Sstevel@tonic-gate 		ls->numAttrs = 0;
1177c478bd9Sstevel@tonic-gate 	}
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	ls->attrsonly = attrsonly;
1207c478bd9Sstevel@tonic-gate 	ls->isDN = isDN;
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	if (err > 0) {
1237c478bd9Sstevel@tonic-gate 		freeLdapSearch(ls);
1247c478bd9Sstevel@tonic-gate 		ls = 0;
1257c478bd9Sstevel@tonic-gate 	}
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	return (ls);
1287c478bd9Sstevel@tonic-gate }
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate void
freeLdapSearch(__nis_ldap_search_t * ls)1317c478bd9Sstevel@tonic-gate freeLdapSearch(__nis_ldap_search_t *ls) {
1327c478bd9Sstevel@tonic-gate 	int	i;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if (ls == 0)
1357c478bd9Sstevel@tonic-gate 		return;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	sfree(ls->base);
1387c478bd9Sstevel@tonic-gate 	if (ls->filterComp != 0) {
1397c478bd9Sstevel@tonic-gate 		for (i = 0; i < ls->numFilterComps; i++) {
1407c478bd9Sstevel@tonic-gate 			sfree(ls->filterComp[i]);
1417c478bd9Sstevel@tonic-gate 		}
1427c478bd9Sstevel@tonic-gate 		sfree(ls->filterComp);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 	sfree(ls->filter);
1457c478bd9Sstevel@tonic-gate 	if (ls->attrs != 0) {
1467c478bd9Sstevel@tonic-gate 		for (i = 0; i < ls->numAttrs; i++) {
1477c478bd9Sstevel@tonic-gate 			sfree(ls->attrs[i]);
1487c478bd9Sstevel@tonic-gate 		}
1497c478bd9Sstevel@tonic-gate 		sfree(ls->attrs);
1507c478bd9Sstevel@tonic-gate 	}
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	free(ls);
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate /*
1567c478bd9Sstevel@tonic-gate  * Given a table mapping, and a rule/value pointer,
1577c478bd9Sstevel@tonic-gate  * return an LDAP search structure with values suitable for use
1587c478bd9Sstevel@tonic-gate  * by ldap_search() or (if dn != 0) ldap_modify(). The rule/value
1597c478bd9Sstevel@tonic-gate  * may be modified.
1607c478bd9Sstevel@tonic-gate  *
1617c478bd9Sstevel@tonic-gate  * If dn != 0 and *dn == 0, the function attemps to return a pointer
1627c478bd9Sstevel@tonic-gate  * to the DN. This may necessitate an ldapSearch, if the rule set doesn't
1637c478bd9Sstevel@tonic-gate  * produce a DN directly.
1647c478bd9Sstevel@tonic-gate  *
1657c478bd9Sstevel@tonic-gate  * if dn == 0, and the rule set produces a DN as well as other attribute/
1667c478bd9Sstevel@tonic-gate  * value pairs, the function returns an LDAP search structure with the
1677c478bd9Sstevel@tonic-gate  * DN only.
1687c478bd9Sstevel@tonic-gate  *
1697c478bd9Sstevel@tonic-gate  * If 'fromLDAP' is set, the caller wants base/scope/filter from
1707c478bd9Sstevel@tonic-gate  * t->objectDN->read; otherwise, from t->objectDN->write.
1717c478bd9Sstevel@tonic-gate  *
1727c478bd9Sstevel@tonic-gate  * If 'rv' is NULL, the caller wants an enumeration of the container.
1737c478bd9Sstevel@tonic-gate  *
1747c478bd9Sstevel@tonic-gate  * Note that this function only creates a search structure for 't' itself;
1757c478bd9Sstevel@tonic-gate  * if there are alternative mappings for the table, those must be handled
1767c478bd9Sstevel@tonic-gate  * by our caller.
1777c478bd9Sstevel@tonic-gate  */
1787c478bd9Sstevel@tonic-gate __nis_ldap_search_t *
createLdapRequest(__nis_table_mapping_t * t,__nis_rule_value_t * rv,char ** dn,int fromLDAP,int * res,__nis_object_dn_t * obj_dn)1797c478bd9Sstevel@tonic-gate createLdapRequest(__nis_table_mapping_t *t,
1807c478bd9Sstevel@tonic-gate 		__nis_rule_value_t *rv, char **dn, int fromLDAP,
1817c478bd9Sstevel@tonic-gate 		int *res, __nis_object_dn_t *obj_dn) {
1827c478bd9Sstevel@tonic-gate 	int			i, j;
1837c478bd9Sstevel@tonic-gate 	__nis_ldap_search_t	*ls = 0;
1847c478bd9Sstevel@tonic-gate 	char			**locDN;
1857c478bd9Sstevel@tonic-gate 	int			numLocDN, stat = 0, count = 0;
1867c478bd9Sstevel@tonic-gate 	char			*myself = "createLdapRequest";
1877c478bd9Sstevel@tonic-gate 	__nis_object_dn_t 	*objectDN = NULL;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	if (t == 0)
1907c478bd9Sstevel@tonic-gate 		return (0);
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	if (obj_dn == NULL)
1937c478bd9Sstevel@tonic-gate 		objectDN = t->objectDN;
1947c478bd9Sstevel@tonic-gate 	else
1957c478bd9Sstevel@tonic-gate 		objectDN = obj_dn;
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	if (rv == 0) {
1987c478bd9Sstevel@tonic-gate 		char	*base;
1997c478bd9Sstevel@tonic-gate 		char	*filter;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 		if (fromLDAP) {
2027c478bd9Sstevel@tonic-gate 			base = objectDN->read.base;
2037c478bd9Sstevel@tonic-gate 			filter = makeFilter(objectDN->read.attrs);
2047c478bd9Sstevel@tonic-gate 		} else {
2057c478bd9Sstevel@tonic-gate 			base = objectDN->write.base;
2067c478bd9Sstevel@tonic-gate 			filter = makeFilter(objectDN->write.attrs);
2077c478bd9Sstevel@tonic-gate 		}
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 		/* Create request to enumerate container */
2107c478bd9Sstevel@tonic-gate 		ls = buildLdapSearch(base, objectDN->read.scope, 0, 0, filter,
2117c478bd9Sstevel@tonic-gate 					0, 0, 0);
2127c478bd9Sstevel@tonic-gate 		sfree(filter);
2137c478bd9Sstevel@tonic-gate 		return (ls);
2147c478bd9Sstevel@tonic-gate 	}
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	for (i = 0; i < t->numRulesToLDAP; i++) {
2177c478bd9Sstevel@tonic-gate 		rv = addLdapRuleValue(t, t->ruleToLDAP[i],
2187c478bd9Sstevel@tonic-gate 				mit_ldap, mit_nisplus, rv, !fromLDAP, &stat);
2197c478bd9Sstevel@tonic-gate 		if (rv == 0)
2207c478bd9Sstevel@tonic-gate 			return (0);
2217c478bd9Sstevel@tonic-gate 		if (stat == NP_LDAP_RULES_NO_VALUE)
2227c478bd9Sstevel@tonic-gate 			count++;
2237c478bd9Sstevel@tonic-gate 		stat = 0;
2247c478bd9Sstevel@tonic-gate 	}
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate 	/*
2277c478bd9Sstevel@tonic-gate 	 * If none of the rules produced a value despite
2287c478bd9Sstevel@tonic-gate 	 * having enough NIS+ columns, return error.
2297c478bd9Sstevel@tonic-gate 	 */
2307c478bd9Sstevel@tonic-gate 	if (rv->numAttrs == 0 && count > 0) {
2317c478bd9Sstevel@tonic-gate 		*res = NP_LDAP_RULES_NO_VALUE;
2327c478bd9Sstevel@tonic-gate 		return (0);
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	/*
2367c478bd9Sstevel@tonic-gate 	 * 'rv' now contains everything we know about the attributes and
2377c478bd9Sstevel@tonic-gate 	 * values. Build an LDAP search structure from it.
2387c478bd9Sstevel@tonic-gate 	 */
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	/* Look for a single-valued DN */
2417c478bd9Sstevel@tonic-gate 	locDN = findDNs(myself, rv, 1,
2427c478bd9Sstevel@tonic-gate 			fromLDAP ? objectDN->read.base :
2437c478bd9Sstevel@tonic-gate 					objectDN->write.base,
2447c478bd9Sstevel@tonic-gate 			&numLocDN);
2457c478bd9Sstevel@tonic-gate 	if (locDN != 0 && numLocDN == 1) {
2467c478bd9Sstevel@tonic-gate 		if (dn != 0 && *dn == 0) {
2477c478bd9Sstevel@tonic-gate 			*dn = locDN[0];
2487c478bd9Sstevel@tonic-gate 			sfree(locDN);
2497c478bd9Sstevel@tonic-gate 		} else {
2507c478bd9Sstevel@tonic-gate 			char	*filter;
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 			if (fromLDAP)
2537c478bd9Sstevel@tonic-gate 				filter = makeFilter(objectDN->read.attrs);
2547c478bd9Sstevel@tonic-gate 			else
2557c478bd9Sstevel@tonic-gate 				filter = makeFilter(objectDN->write.attrs);
2567c478bd9Sstevel@tonic-gate 			ls = buildLdapSearch(locDN[0], LDAP_SCOPE_BASE, 0, 0,
2577c478bd9Sstevel@tonic-gate 						filter, 0, 0, 1);
2587c478bd9Sstevel@tonic-gate 			sfree(filter);
2597c478bd9Sstevel@tonic-gate 			freeDNs(locDN, numLocDN);
2607c478bd9Sstevel@tonic-gate 		}
2617c478bd9Sstevel@tonic-gate 	} else {
2627c478bd9Sstevel@tonic-gate 		freeDNs(locDN, numLocDN);
2637c478bd9Sstevel@tonic-gate 	}
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	if (ls != 0) {
2667c478bd9Sstevel@tonic-gate 		ls->useCon = 1;
2677c478bd9Sstevel@tonic-gate 		return (ls);
2687c478bd9Sstevel@tonic-gate 	}
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	/*
2717c478bd9Sstevel@tonic-gate 	 * No DN, or caller wanted a search structure with the non-DN
2727c478bd9Sstevel@tonic-gate 	 * attributes.
2737c478bd9Sstevel@tonic-gate 	 */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	/* Initialize search structure */
2767c478bd9Sstevel@tonic-gate 	{
2777c478bd9Sstevel@tonic-gate 		char	*filter = (fromLDAP) ?
2787c478bd9Sstevel@tonic-gate 				makeFilter(objectDN->read.attrs) :
2797c478bd9Sstevel@tonic-gate 				makeFilter(objectDN->write.attrs);
2807c478bd9Sstevel@tonic-gate 		char	**ofc;
2817c478bd9Sstevel@tonic-gate 		int	nofc = 0;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 		ofc = makeFilterComp(filter, &nofc);
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate 		if (filter != 0 && ofc == 0) {
2867c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
2877c478bd9Sstevel@tonic-gate 			"%s: Unable to break filter into components: \"%s\"",
2887c478bd9Sstevel@tonic-gate 				myself, NIL(filter));
2897c478bd9Sstevel@tonic-gate 			sfree(filter);
2907c478bd9Sstevel@tonic-gate 			return (0);
2917c478bd9Sstevel@tonic-gate 		}
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 		if (fromLDAP)
2947c478bd9Sstevel@tonic-gate 			ls = buildLdapSearch(objectDN->read.base,
2957c478bd9Sstevel@tonic-gate 				objectDN->read.scope,
2967c478bd9Sstevel@tonic-gate 				nofc, ofc, 0, 0, 0, 0);
2977c478bd9Sstevel@tonic-gate 		else
2987c478bd9Sstevel@tonic-gate 			ls = buildLdapSearch(objectDN->write.base,
2997c478bd9Sstevel@tonic-gate 				objectDN->write.scope,
3007c478bd9Sstevel@tonic-gate 				nofc, ofc, 0, 0, 0, 0);
3017c478bd9Sstevel@tonic-gate 		sfree(filter);
3027c478bd9Sstevel@tonic-gate 		freeFilterComp(ofc, nofc);
3037c478bd9Sstevel@tonic-gate 		if (ls == 0)
3047c478bd9Sstevel@tonic-gate 			return (0);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/* Build and add the filter components */
3087c478bd9Sstevel@tonic-gate 	for (i = 0; i < rv->numAttrs; i++) {
3097c478bd9Sstevel@tonic-gate 		/* Skip DN */
3107c478bd9Sstevel@tonic-gate 		if (strcasecmp("dn", rv->attrName[i]) == 0)
3117c478bd9Sstevel@tonic-gate 			continue;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 		/* Skip vt_ber values */
3147c478bd9Sstevel@tonic-gate 		if (rv->attrVal[i].type == vt_ber)
3157c478bd9Sstevel@tonic-gate 			continue;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 		for (j = 0; j < rv->attrVal[i].numVals; j++) {
3187c478bd9Sstevel@tonic-gate 			__nis_buffer_t	b = {0, 0};
3197c478bd9Sstevel@tonic-gate 			char		**tmpComp;
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 			bp2buf(myself, &b, "%s=%s",
3227c478bd9Sstevel@tonic-gate 				rv->attrName[i], rv->attrVal[i].val[j].value);
3237c478bd9Sstevel@tonic-gate 			tmpComp = addFilterComp(b.buf, ls->filterComp,
3247c478bd9Sstevel@tonic-gate 						&ls->numFilterComps);
3257c478bd9Sstevel@tonic-gate 			if (tmpComp == 0) {
3267c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
3277c478bd9Sstevel@tonic-gate 				"%s: Unable to add filter component \"%s\"",
3287c478bd9Sstevel@tonic-gate 					myself, NIL(b.buf));
3297c478bd9Sstevel@tonic-gate 				sfree(b.buf);
3307c478bd9Sstevel@tonic-gate 				freeLdapSearch(ls);
3317c478bd9Sstevel@tonic-gate 				return (0);
3327c478bd9Sstevel@tonic-gate 			}
3337c478bd9Sstevel@tonic-gate 			ls->filterComp = tmpComp;
3347c478bd9Sstevel@tonic-gate 			sfree(b.buf);
3357c478bd9Sstevel@tonic-gate 		}
3367c478bd9Sstevel@tonic-gate 	}
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate 	if (ls->numFilterComps > 0) {
3397c478bd9Sstevel@tonic-gate 		sfree(ls->filter);
3407c478bd9Sstevel@tonic-gate 		ls->filter = concatenateFilterComps(ls->numFilterComps,
3417c478bd9Sstevel@tonic-gate 							ls->filterComp);
3427c478bd9Sstevel@tonic-gate 		if (ls->filter == 0) {
3437c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
3447c478bd9Sstevel@tonic-gate 			"%s: Unable to concatenate filter components",
3457c478bd9Sstevel@tonic-gate 				myself);
3467c478bd9Sstevel@tonic-gate 			freeLdapSearch(ls);
3477c478bd9Sstevel@tonic-gate 			return (0);
3487c478bd9Sstevel@tonic-gate 		}
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate 	if (dn != 0 && *dn == 0) {
3527c478bd9Sstevel@tonic-gate 		/*
3537c478bd9Sstevel@tonic-gate 		 * The caller wants a DN, but we didn't get one from the
3547c478bd9Sstevel@tonic-gate 		 * the rule set. We have an 'ls', so use it to ldapSearch()
3557c478bd9Sstevel@tonic-gate 		 * for an entry from which we can extract the DN.
3567c478bd9Sstevel@tonic-gate 		 */
3577c478bd9Sstevel@tonic-gate 		__nis_rule_value_t	*rvtmp;
3587c478bd9Sstevel@tonic-gate 		char			**locDN;
3597c478bd9Sstevel@tonic-gate 		int			nv = 0, numLocDN;
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 		rvtmp = ldapSearch(ls, &nv, 0, 0);
3627c478bd9Sstevel@tonic-gate 		locDN = findDNs(myself, rvtmp, nv, 0, &numLocDN);
3637c478bd9Sstevel@tonic-gate 		if (locDN != 0 && numLocDN == 1) {
3647c478bd9Sstevel@tonic-gate 			*dn = locDN[0];
3657c478bd9Sstevel@tonic-gate 			sfree(locDN);
3667c478bd9Sstevel@tonic-gate 		} else {
3677c478bd9Sstevel@tonic-gate 			freeDNs(locDN, numLocDN);
3687c478bd9Sstevel@tonic-gate 		}
3697c478bd9Sstevel@tonic-gate 		freeRuleValue(rvtmp, nv);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	ls->useCon = 1;
3737c478bd9Sstevel@tonic-gate 	return (ls);
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate int	ldapConnAttemptRetryTimeout = 60;	/* seconds */
3777c478bd9Sstevel@tonic-gate 
3787c478bd9Sstevel@tonic-gate typedef struct {
3797c478bd9Sstevel@tonic-gate 	LDAP		*ld;
3807c478bd9Sstevel@tonic-gate 	mutex_t		mutex;		/* Mutex for update of structure */
3817c478bd9Sstevel@tonic-gate 	pthread_t	owner;		/* Thread holding mutex */
3827c478bd9Sstevel@tonic-gate 	mutex_t		rcMutex;	/* Mutex for refCount */
3837c478bd9Sstevel@tonic-gate 	int		refCount;	/* Reference count */
3847c478bd9Sstevel@tonic-gate 	int		isBound;	/* Is connection open and usable ? */
3857c478bd9Sstevel@tonic-gate 	time_t		retryTime;	/* When should open be retried */
3867c478bd9Sstevel@tonic-gate 	int		status;		/* Status of last operation */
3877c478bd9Sstevel@tonic-gate 	int		doDis;		/* To be disconnected if refCount==0 */
3887c478bd9Sstevel@tonic-gate 	int		doDel;		/* To be deleted if refCount zero */
3897c478bd9Sstevel@tonic-gate 	int		onList;		/* True if on the 'ldapCon' list */
3907c478bd9Sstevel@tonic-gate 	char		*sp;		/* server string */
3917c478bd9Sstevel@tonic-gate 	char		*who;
3927c478bd9Sstevel@tonic-gate 	char		*cred;
3937c478bd9Sstevel@tonic-gate 	auth_method_t	method;
3947c478bd9Sstevel@tonic-gate 	int		port;
3957c478bd9Sstevel@tonic-gate 	struct timeval	bindTimeout;
3967c478bd9Sstevel@tonic-gate 	struct timeval	searchTimeout;
3977c478bd9Sstevel@tonic-gate 	struct timeval	modifyTimeout;
3987c478bd9Sstevel@tonic-gate 	struct timeval	addTimeout;
3997c478bd9Sstevel@tonic-gate 	struct timeval	deleteTimeout;
4007c478bd9Sstevel@tonic-gate 	int		simplePage;	/* Can do simple-page */
4017c478bd9Sstevel@tonic-gate 	int		vlv;		/* Can do VLV */
4027c478bd9Sstevel@tonic-gate 	uint_t		batchFrom;	/* # entries read in one operation */
4037c478bd9Sstevel@tonic-gate 	void		*next;
4047c478bd9Sstevel@tonic-gate } __nis_ldap_conn_t;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate /*
4077c478bd9Sstevel@tonic-gate  * List of connections, 'ldapCon', protected by an RW lock.
4087c478bd9Sstevel@tonic-gate  *
4097c478bd9Sstevel@tonic-gate  * The following locking scheme is used:
4107c478bd9Sstevel@tonic-gate  *
4117c478bd9Sstevel@tonic-gate  * (1)	Find a connection structure to use to talk to LDAP
4127c478bd9Sstevel@tonic-gate  *		Rlock list
4137c478bd9Sstevel@tonic-gate  *			Locate structure
4147c478bd9Sstevel@tonic-gate  *			Acquire 'mutex'
4157c478bd9Sstevel@tonic-gate  *				Acquire 'rcMutex'
4167c478bd9Sstevel@tonic-gate  *					update refCount
4177c478bd9Sstevel@tonic-gate  *				Release 'rcMutex'
4187c478bd9Sstevel@tonic-gate  *			release 'mutex'
4197c478bd9Sstevel@tonic-gate  *		Unlock list
4207c478bd9Sstevel@tonic-gate  *		Use structure
4217c478bd9Sstevel@tonic-gate  *		Release structure when done
4227c478bd9Sstevel@tonic-gate  * (2)	Insert/delete structure(s) on/from list
4237c478bd9Sstevel@tonic-gate  *		Wlock list
4247c478bd9Sstevel@tonic-gate  *			Insert/delete structure; if deleting, must
4257c478bd9Sstevel@tonic-gate  *			acquire 'mutex', and 'rcMutex' (in that order),
4267c478bd9Sstevel@tonic-gate  *			and 'refCount' must be zero.
4277c478bd9Sstevel@tonic-gate  *		Unlock list
4287c478bd9Sstevel@tonic-gate  * (3)	Modify structure
4297c478bd9Sstevel@tonic-gate  *		Find structure
4307c478bd9Sstevel@tonic-gate  *		Acquire 'mutex'
4317c478bd9Sstevel@tonic-gate  *			Modify (except refCount)
4327c478bd9Sstevel@tonic-gate  *		Release 'mutex'
4337c478bd9Sstevel@tonic-gate  *		Release structure
4347c478bd9Sstevel@tonic-gate  */
4357c478bd9Sstevel@tonic-gate 
4367c478bd9Sstevel@tonic-gate __nis_ldap_conn_t		*ldapCon = 0;
4377c478bd9Sstevel@tonic-gate __nis_ldap_conn_t		*ldapReferralCon = 0;
4387c478bd9Sstevel@tonic-gate static rwlock_t			ldapConLock = DEFAULTRWLOCK;
4397c478bd9Sstevel@tonic-gate static rwlock_t			referralConLock = DEFAULTRWLOCK;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate void
exclusiveLC(__nis_ldap_conn_t * lc)4427c478bd9Sstevel@tonic-gate exclusiveLC(__nis_ldap_conn_t *lc) {
4437c478bd9Sstevel@tonic-gate 	pthread_t	me = pthread_self();
4447c478bd9Sstevel@tonic-gate 	int		stat;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 	if (lc == 0)
4477c478bd9Sstevel@tonic-gate 		return;
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 	stat = mutex_trylock(&lc->mutex);
4507c478bd9Sstevel@tonic-gate 	if (stat == EBUSY && lc->owner != me)
4517c478bd9Sstevel@tonic-gate 		mutex_lock(&lc->mutex);
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	lc->owner = me;
4547c478bd9Sstevel@tonic-gate }
4557c478bd9Sstevel@tonic-gate 
4567c478bd9Sstevel@tonic-gate /* Return 1 if mutex held by this thread, 0 otherwise */
4577c478bd9Sstevel@tonic-gate int
assertExclusive(__nis_ldap_conn_t * lc)4587c478bd9Sstevel@tonic-gate assertExclusive(__nis_ldap_conn_t *lc) {
4597c478bd9Sstevel@tonic-gate 	pthread_t	me;
4607c478bd9Sstevel@tonic-gate 	int		stat;
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate 	if (lc == 0)
4637c478bd9Sstevel@tonic-gate 		return (0);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	stat = mutex_trylock(&lc->mutex);
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	if (stat == 0) {
4687c478bd9Sstevel@tonic-gate 		mutex_unlock(&lc->mutex);
4697c478bd9Sstevel@tonic-gate 		return (0);
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	me = pthread_self();
4737c478bd9Sstevel@tonic-gate 	if (stat != EBUSY || lc->owner != me)
4747c478bd9Sstevel@tonic-gate 		return (0);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	return (1);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate void
releaseLC(__nis_ldap_conn_t * lc)4807c478bd9Sstevel@tonic-gate releaseLC(__nis_ldap_conn_t *lc) {
4817c478bd9Sstevel@tonic-gate 	pthread_t	me = pthread_self();
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 	if (lc == 0 || lc->owner != me)
4847c478bd9Sstevel@tonic-gate 		return;
4857c478bd9Sstevel@tonic-gate 
4867c478bd9Sstevel@tonic-gate 	lc->owner = 0;
4877c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lc->mutex);
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate void
incrementRC(__nis_ldap_conn_t * lc)4917c478bd9Sstevel@tonic-gate incrementRC(__nis_ldap_conn_t *lc) {
4927c478bd9Sstevel@tonic-gate 	if (lc == 0)
4937c478bd9Sstevel@tonic-gate 		return;
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&lc->rcMutex);
4967c478bd9Sstevel@tonic-gate 	lc->refCount++;
4977c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lc->rcMutex);
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate void
decrementRC(__nis_ldap_conn_t * lc)5017c478bd9Sstevel@tonic-gate decrementRC(__nis_ldap_conn_t *lc) {
5027c478bd9Sstevel@tonic-gate 	if (lc == 0)
5037c478bd9Sstevel@tonic-gate 		return;
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&lc->rcMutex);
5067c478bd9Sstevel@tonic-gate 	if (lc->refCount > 0)
5077c478bd9Sstevel@tonic-gate 		lc->refCount--;
5087c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lc->rcMutex);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate /* Accept a server/port indication, and call ldap_init() */
5127c478bd9Sstevel@tonic-gate static LDAP *
ldapInit(char * srv,int port,bool_t use_ssl)5137c478bd9Sstevel@tonic-gate ldapInit(char *srv, int port, bool_t use_ssl) {
5147c478bd9Sstevel@tonic-gate 	LDAP			*ld;
5157c478bd9Sstevel@tonic-gate 	int			ldapVersion = LDAP_VERSION3;
5167c478bd9Sstevel@tonic-gate 	int			derefOption = LDAP_DEREF_ALWAYS;
5177c478bd9Sstevel@tonic-gate 	int			timelimit = proxyInfo.search_time_limit;
5187c478bd9Sstevel@tonic-gate 	int			sizelimit = proxyInfo.search_size_limit;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 	if (srv == 0)
5217c478bd9Sstevel@tonic-gate 		return (0);
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	if (use_ssl) {
5247c478bd9Sstevel@tonic-gate 		ld = ldapssl_init(srv, port, 1);
5257c478bd9Sstevel@tonic-gate 	} else {
5267c478bd9Sstevel@tonic-gate 		ld = ldap_init(srv, port);
5277c478bd9Sstevel@tonic-gate 	}
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	if (ld != 0) {
5307c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
5317c478bd9Sstevel@tonic-gate 					&ldapVersion);
5327c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption);
5337c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
5347c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit);
5357c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
5367c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_REBIND_ARG, 0);
5377c478bd9Sstevel@tonic-gate 	}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	return (ld);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate  * Bind the specified LDAP structure per the supplied authentication.
5447c478bd9Sstevel@tonic-gate  * Note: tested with none, simple, and digest_md5. May or may not
5457c478bd9Sstevel@tonic-gate  * work with other authentication methods, mostly depending on whether
5467c478bd9Sstevel@tonic-gate  * or not 'who' and 'cred' contain sufficient information.
5477c478bd9Sstevel@tonic-gate  */
5487c478bd9Sstevel@tonic-gate static int
ldapBind(LDAP ** ldP,char * who,char * cred,auth_method_t method,struct timeval timeout)5497c478bd9Sstevel@tonic-gate ldapBind(LDAP **ldP, char *who, char *cred, auth_method_t method,
5507c478bd9Sstevel@tonic-gate 		struct timeval timeout) {
5517c478bd9Sstevel@tonic-gate 	int		ret;
5527c478bd9Sstevel@tonic-gate 	LDAP		*ld;
5537c478bd9Sstevel@tonic-gate 	char		*myself = "ldapBind";
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	if (ldP == 0 || (ld = *ldP) == 0)
5567c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	if (method == none) {
5597c478bd9Sstevel@tonic-gate 		/* No ldap_bind() required (or even possible) */
5607c478bd9Sstevel@tonic-gate 		ret = LDAP_SUCCESS;
5617c478bd9Sstevel@tonic-gate 	} else if (method == simple) {
5627c478bd9Sstevel@tonic-gate 		struct timeval	tv;
5637c478bd9Sstevel@tonic-gate 		LDAPMessage	*msg = 0;
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate 		tv = timeout;
5667c478bd9Sstevel@tonic-gate 		ret = ldap_bind(ld, who, cred, LDAP_AUTH_SIMPLE);
5677c478bd9Sstevel@tonic-gate 		if (ret != -1) {
5687c478bd9Sstevel@tonic-gate 			ret = ldap_result(ld, ret, 0, &tv, &msg);
5697c478bd9Sstevel@tonic-gate 			if (ret == 0) {
5707c478bd9Sstevel@tonic-gate 				ret = LDAP_TIMEOUT;
5717c478bd9Sstevel@tonic-gate 			} else if (ret == -1) {
5727c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(ld,
5737c478bd9Sstevel@tonic-gate 							LDAP_OPT_ERROR_NUMBER,
5747c478bd9Sstevel@tonic-gate 							&ret);
5757c478bd9Sstevel@tonic-gate 			} else {
5767c478bd9Sstevel@tonic-gate 				ret = ldap_result2error(ld, msg, 0);
5777c478bd9Sstevel@tonic-gate 			}
5787c478bd9Sstevel@tonic-gate 			if (msg != 0)
5797c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(msg);
5807c478bd9Sstevel@tonic-gate 		} else {
5817c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
5827c478bd9Sstevel@tonic-gate 						&ret);
5837c478bd9Sstevel@tonic-gate 		}
5847c478bd9Sstevel@tonic-gate 	} else if (method == cram_md5) {
5857c478bd9Sstevel@tonic-gate 		/* Note: there is only a synchronous call for cram-md5 */
5867c478bd9Sstevel@tonic-gate 		struct berval ber_cred;
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 		ber_cred.bv_len = strlen(cred);
5897c478bd9Sstevel@tonic-gate 		ber_cred.bv_val = cred;
5907c478bd9Sstevel@tonic-gate 		ret = ldap_sasl_cram_md5_bind_s(ld, who, &ber_cred, NULL, NULL);
5917c478bd9Sstevel@tonic-gate 	} else if (method == digest_md5) {
5927c478bd9Sstevel@tonic-gate 		/* Note: there is only a synchronous call for digest-md5 */
5937c478bd9Sstevel@tonic-gate 		struct berval ber_cred;
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 		ber_cred.bv_len = strlen(cred);
5967c478bd9Sstevel@tonic-gate 		ber_cred.bv_val = cred;
5977c478bd9Sstevel@tonic-gate 		ret = ldap_x_sasl_digest_md5_bind_s(ld, who, &ber_cred, NULL,
5987c478bd9Sstevel@tonic-gate 			NULL);
5997c478bd9Sstevel@tonic-gate 	} else {
6007c478bd9Sstevel@tonic-gate 		ret = LDAP_AUTH_METHOD_NOT_SUPPORTED;
6017c478bd9Sstevel@tonic-gate 	}
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 	if (ret != LDAP_SUCCESS) {
6047c478bd9Sstevel@tonic-gate 		(void) ldap_unbind_s(ld);
6057c478bd9Sstevel@tonic-gate 		*ldP = 0;
6067c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_WARNING,
6077c478bd9Sstevel@tonic-gate 			"%s: Unable to bind as: %s: %s",
6087c478bd9Sstevel@tonic-gate 			myself, who, ldap_err2string(ret));
6097c478bd9Sstevel@tonic-gate 	}
6107c478bd9Sstevel@tonic-gate 
6117c478bd9Sstevel@tonic-gate 	return (ret);
6127c478bd9Sstevel@tonic-gate }
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate /*
6157c478bd9Sstevel@tonic-gate  * Free 'lc' and all related memory. Caller must hold the exclusive lock.
6167c478bd9Sstevel@tonic-gate  * Return LDAP_UNAVAILABLE upon success, in which case the caller mustn't
6177c478bd9Sstevel@tonic-gate  * try to use the structure pointer in any way.
6187c478bd9Sstevel@tonic-gate  */
6197c478bd9Sstevel@tonic-gate static int
freeCon(__nis_ldap_conn_t * lc)6207c478bd9Sstevel@tonic-gate freeCon(__nis_ldap_conn_t *lc) {
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate 	if (!assertExclusive(lc))
6237c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	incrementRC(lc);
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	/* Must be unused, unbound, and not on the 'ldapCon' list */
6287c478bd9Sstevel@tonic-gate 	if (lc->onList || lc->refCount != 1 || lc->isBound) {
6297c478bd9Sstevel@tonic-gate 		lc->doDel++;
6307c478bd9Sstevel@tonic-gate 		decrementRC(lc);
6317c478bd9Sstevel@tonic-gate 		return (LDAP_BUSY);
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	sfree(lc->sp);
6357c478bd9Sstevel@tonic-gate 	sfree(lc->who);
6367c478bd9Sstevel@tonic-gate 	sfree(lc->cred);
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	/* Delete structure with both mutex:es held */
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	free(lc);
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	return (LDAP_UNAVAILABLE);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate /*
6467c478bd9Sstevel@tonic-gate  * Disconnect the specified LDAP connection. Caller must have acquired 'mutex'.
6477c478bd9Sstevel@tonic-gate  *
6487c478bd9Sstevel@tonic-gate  * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch
6497c478bd9Sstevel@tonic-gate  * the structure in any way.
6507c478bd9Sstevel@tonic-gate  */
6517c478bd9Sstevel@tonic-gate static int
disconnectCon(__nis_ldap_conn_t * lc)6527c478bd9Sstevel@tonic-gate disconnectCon(__nis_ldap_conn_t *lc) {
6537c478bd9Sstevel@tonic-gate 	int	stat;
6547c478bd9Sstevel@tonic-gate 	char	*myself = "disconnectCon";
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	if (lc == 0)
6577c478bd9Sstevel@tonic-gate 		return (LDAP_SUCCESS);
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	if (!assertExclusive(lc))
6607c478bd9Sstevel@tonic-gate 		return (LDAP_UNAVAILABLE);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	if (lc->doDis) {
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 		/* Increment refCount to protect against interference */
6657c478bd9Sstevel@tonic-gate 		incrementRC(lc);
6667c478bd9Sstevel@tonic-gate 		/* refCount must be one (i.e., just us) */
6677c478bd9Sstevel@tonic-gate 		if (lc->refCount != 1) {
6687c478bd9Sstevel@tonic-gate 			/*
6697c478bd9Sstevel@tonic-gate 			 * In use; already marked for disconnect,
6707c478bd9Sstevel@tonic-gate 			 * so do nothing.
6717c478bd9Sstevel@tonic-gate 			 */
6727c478bd9Sstevel@tonic-gate 			decrementRC(lc);
6737c478bd9Sstevel@tonic-gate 			return (LDAP_BUSY);
6747c478bd9Sstevel@tonic-gate 		}
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 		stat = ldap_unbind_s(lc->ld);
6777c478bd9Sstevel@tonic-gate 		if (stat == LDAP_SUCCESS) {
6787c478bd9Sstevel@tonic-gate 			lc->ld = 0;
6797c478bd9Sstevel@tonic-gate 			lc->isBound = 0;
6807c478bd9Sstevel@tonic-gate 			lc->doDis = 0;
6817c478bd9Sstevel@tonic-gate 			/* Reset simple page and vlv indication */
6827c478bd9Sstevel@tonic-gate 			lc->simplePage = 0;
6837c478bd9Sstevel@tonic-gate 			lc->vlv = 0;
6847c478bd9Sstevel@tonic-gate 		} else if (verbose) {
6857c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
6867c478bd9Sstevel@tonic-gate 				"%s: ldap_unbind_s() => %d (%s)",
6877c478bd9Sstevel@tonic-gate 				myself, stat, ldap_err2string(stat));
6887c478bd9Sstevel@tonic-gate 		}
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate 		decrementRC(lc);
6917c478bd9Sstevel@tonic-gate 	}
6927c478bd9Sstevel@tonic-gate 
6937c478bd9Sstevel@tonic-gate 	if (lc->doDel) {
6947c478bd9Sstevel@tonic-gate 		if (LDAP_UNAVAILABLE == freeCon(lc))
6957c478bd9Sstevel@tonic-gate 			stat = LDAP_UNAVAILABLE;
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	return (stat);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate  * controlSupported will determine for a given connection whether a set
7037c478bd9Sstevel@tonic-gate  * of controls is supported or not. The input parameters:
7047c478bd9Sstevel@tonic-gate  *	lc	The connection
7057c478bd9Sstevel@tonic-gate  *	ctrl	A an array of OID strings, the terminal string should be NULL
7067c478bd9Sstevel@tonic-gate  * The returned values if LDAP_SUCCESS is returned:
7077c478bd9Sstevel@tonic-gate  *	supported	A caller supplied array which will be set to TRUE or
7087c478bd9Sstevel@tonic-gate  *			FALSE depending on whether the corresponding control
7097c478bd9Sstevel@tonic-gate  *			is reported as supported.
7107c478bd9Sstevel@tonic-gate  * Returns LDAP_SUCCESS if the supportedControl attribute is read.
7117c478bd9Sstevel@tonic-gate  */
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate static int
controlSupported(__nis_ldap_conn_t * lc,char ** ctrl,bool_t * supported)7147c478bd9Sstevel@tonic-gate controlSupported(__nis_ldap_conn_t *lc, char **ctrl, bool_t *supported) {
7157c478bd9Sstevel@tonic-gate 	LDAPMessage	*res, *e;
7167c478bd9Sstevel@tonic-gate 	char		*attr[2], *a, **val;
7177c478bd9Sstevel@tonic-gate 	int		stat, i;
7187c478bd9Sstevel@tonic-gate 	BerElement	*ber = 0;
7197c478bd9Sstevel@tonic-gate 	char		*myself = "controlSupported";
7207c478bd9Sstevel@tonic-gate 
7217c478bd9Sstevel@tonic-gate 	attr[0] = "supportedControl";
7227c478bd9Sstevel@tonic-gate 	attr[1] = 0;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	stat = ldap_search_st(lc->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
7257c478bd9Sstevel@tonic-gate 				attr, 0, &lc->searchTimeout, &res);
7267c478bd9Sstevel@tonic-gate 	if (stat != LDAP_SUCCESS) {
7277c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_WARNING,
7287c478bd9Sstevel@tonic-gate 	"%s: Unable to retrieve supported control information for %s: %s",
7297c478bd9Sstevel@tonic-gate 			myself, NIL(lc->sp), ldap_err2string(stat));
7307c478bd9Sstevel@tonic-gate 		return (stat);
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	e = ldap_first_entry(lc->ld, res);
7347c478bd9Sstevel@tonic-gate 	if (e != 0) {
7357c478bd9Sstevel@tonic-gate 		a = ldap_first_attribute(lc->ld, e, &ber);
7367c478bd9Sstevel@tonic-gate 		if (a != 0) {
7377c478bd9Sstevel@tonic-gate 			val = ldap_get_values(lc->ld, e, a);
7387c478bd9Sstevel@tonic-gate 			if (val == 0) {
7397c478bd9Sstevel@tonic-gate 				ldap_memfree(a);
7407c478bd9Sstevel@tonic-gate 				if (ber != 0)
7417c478bd9Sstevel@tonic-gate 					ber_free(ber, 0);
7427c478bd9Sstevel@tonic-gate 			}
7437c478bd9Sstevel@tonic-gate 		}
7447c478bd9Sstevel@tonic-gate 	}
7457c478bd9Sstevel@tonic-gate 	if (e == 0 || a == 0 || val == 0) {
7467c478bd9Sstevel@tonic-gate 		ldap_msgfree(res);
7477c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
7487c478bd9Sstevel@tonic-gate 			"%s: Unable to get root DSE for %s",
7497c478bd9Sstevel@tonic-gate 			myself, NIL(lc->sp));
7507c478bd9Sstevel@tonic-gate 		return (LDAP_OPERATIONS_ERROR);
7517c478bd9Sstevel@tonic-gate 	}
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	while (*ctrl != NULL) {
7547c478bd9Sstevel@tonic-gate 		*supported = FALSE;
7557c478bd9Sstevel@tonic-gate 		for (i = 0; val[i] != 0; i++) {
7567c478bd9Sstevel@tonic-gate 			if (strstr(val[i], *ctrl) != 0) {
7577c478bd9Sstevel@tonic-gate 				*supported = TRUE;
7587c478bd9Sstevel@tonic-gate 				break;
7597c478bd9Sstevel@tonic-gate 			}
7607c478bd9Sstevel@tonic-gate 		}
7617c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
7627c478bd9Sstevel@tonic-gate 			"%s: %s: %s: %s",
7637c478bd9Sstevel@tonic-gate 			myself, NIL(lc->sp), NIL(*ctrl),
7647c478bd9Sstevel@tonic-gate 			*supported ? "enabled" : "disabled");
7657c478bd9Sstevel@tonic-gate 		ctrl++;
7667c478bd9Sstevel@tonic-gate 		supported++;
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	ldap_value_free(val);
7707c478bd9Sstevel@tonic-gate 	ldap_memfree(a);
7717c478bd9Sstevel@tonic-gate 	if (ber != 0)
7727c478bd9Sstevel@tonic-gate 		ber_free(ber, 0);
7737c478bd9Sstevel@tonic-gate 	ldap_msgfree(res);
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	return (stat);
7767c478bd9Sstevel@tonic-gate }
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate /*
7797c478bd9Sstevel@tonic-gate  * Connect the LDAP connection 'lc'. Caller must have acquired the 'mutex',
7807c478bd9Sstevel@tonic-gate  * and the refCount must be zero.
7817c478bd9Sstevel@tonic-gate  *
7827c478bd9Sstevel@tonic-gate  * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch
7837c478bd9Sstevel@tonic-gate  * the structure in any way.
7847c478bd9Sstevel@tonic-gate  */
7857c478bd9Sstevel@tonic-gate static int
connectCon(__nis_ldap_conn_t * lc,int check_ctrl)7867c478bd9Sstevel@tonic-gate connectCon(__nis_ldap_conn_t *lc, int check_ctrl) {
7877c478bd9Sstevel@tonic-gate 	struct timeval	tp;
7887c478bd9Sstevel@tonic-gate 	int		stat;
7897c478bd9Sstevel@tonic-gate 	bool_t		supported[2] = {FALSE, FALSE};
7907c478bd9Sstevel@tonic-gate 	char		*ctrl[3] = {LDAP_CONTROL_SIMPLE_PAGE,
7917c478bd9Sstevel@tonic-gate 					LDAP_CONTROL_VLVREQUEST,
7927c478bd9Sstevel@tonic-gate 					NULL};
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	if (lc == 0)
7957c478bd9Sstevel@tonic-gate 		return (LDAP_SUCCESS);
7967c478bd9Sstevel@tonic-gate 
7977c478bd9Sstevel@tonic-gate 	if (!assertExclusive(lc))
7987c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	incrementRC(lc);
8017c478bd9Sstevel@tonic-gate 	if (lc->refCount != 1) {
8027c478bd9Sstevel@tonic-gate 		/*
8037c478bd9Sstevel@tonic-gate 		 * Don't want to step on structure when it's used by someone
8047c478bd9Sstevel@tonic-gate 		 * else.
8057c478bd9Sstevel@tonic-gate 		 */
8067c478bd9Sstevel@tonic-gate 		decrementRC(lc);
8077c478bd9Sstevel@tonic-gate 		return (LDAP_BUSY);
8087c478bd9Sstevel@tonic-gate 	}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&tp, 0);
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate 	if (lc->ld != 0) {
8137c478bd9Sstevel@tonic-gate 		/* Try to disconnect */
8147c478bd9Sstevel@tonic-gate 		lc->doDis++;
8157c478bd9Sstevel@tonic-gate 		decrementRC(lc);
8167c478bd9Sstevel@tonic-gate 		/* disconnctCon() will do the delete if required */
8177c478bd9Sstevel@tonic-gate 		stat = disconnectCon(lc);
8187c478bd9Sstevel@tonic-gate 		if (stat != LDAP_SUCCESS)
8197c478bd9Sstevel@tonic-gate 			return (stat);
8207c478bd9Sstevel@tonic-gate 		incrementRC(lc);
8217c478bd9Sstevel@tonic-gate 		if (lc->refCount != 1 || lc->ld != 0) {
8227c478bd9Sstevel@tonic-gate 			decrementRC(lc);
8237c478bd9Sstevel@tonic-gate 			return (lc->ld != 0) ? LDAP_SUCCESS :
8247c478bd9Sstevel@tonic-gate 						LDAP_BUSY;
8257c478bd9Sstevel@tonic-gate 		}
8267c478bd9Sstevel@tonic-gate 	} else if (tp.tv_sec < lc->retryTime) {
8277c478bd9Sstevel@tonic-gate 		/* Too early to retry connect */
8287c478bd9Sstevel@tonic-gate 		decrementRC(lc);
8297c478bd9Sstevel@tonic-gate 		return (LDAP_SERVER_DOWN);
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	/* Set new retry time in case we fail below */
8337c478bd9Sstevel@tonic-gate 	lc->retryTime = tp.tv_sec + ldapConnAttemptRetryTimeout;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	lc->ld = ldapInit(lc->sp, lc->port, proxyInfo.tls_method != no_tls);
8367c478bd9Sstevel@tonic-gate 	if (lc->ld == 0) {
8377c478bd9Sstevel@tonic-gate 		decrementRC(lc);
8387c478bd9Sstevel@tonic-gate 		return (LDAP_LOCAL_ERROR);
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	stat = lc->status = ldapBind(&lc->ld, lc->who, lc->cred, lc->method,
8427c478bd9Sstevel@tonic-gate 		lc->bindTimeout);
8437c478bd9Sstevel@tonic-gate 	if (lc->status == LDAP_SUCCESS) {
8447c478bd9Sstevel@tonic-gate 		lc->isBound = 1;
8457c478bd9Sstevel@tonic-gate 		lc->retryTime = 0;
8467c478bd9Sstevel@tonic-gate 		if (check_ctrl) {
8477c478bd9Sstevel@tonic-gate 			(void) controlSupported(lc, ctrl, supported);
8487c478bd9Sstevel@tonic-gate 			lc->simplePage = supported[0];
8497c478bd9Sstevel@tonic-gate 			lc->vlv = supported[1];
8507c478bd9Sstevel@tonic-gate 			lc->batchFrom = 50000;
8517c478bd9Sstevel@tonic-gate 		}
8527c478bd9Sstevel@tonic-gate 	}
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	decrementRC(lc);
8557c478bd9Sstevel@tonic-gate 
8567c478bd9Sstevel@tonic-gate 	return (stat);
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate /*
8607c478bd9Sstevel@tonic-gate  * Find and return a connection believed to be OK.
8617c478bd9Sstevel@tonic-gate  */
8627c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t *
findCon(int * stat)8637c478bd9Sstevel@tonic-gate findCon(int *stat) {
8647c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc;
8657c478bd9Sstevel@tonic-gate 	int			ldapStat;
8667c478bd9Sstevel@tonic-gate 	char			*myself = "findCon";
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	if (stat == 0)
8697c478bd9Sstevel@tonic-gate 		stat = &ldapStat;
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&ldapConLock);
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	if (ldapCon == 0) {
8747c478bd9Sstevel@tonic-gate 		/* Probably first call; try to set up the connection list */
8757c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ldapConLock);
8767c478bd9Sstevel@tonic-gate 		if ((*stat = setupConList(proxyInfo.default_servers,
8777c478bd9Sstevel@tonic-gate 					proxyInfo.proxy_dn,
8787c478bd9Sstevel@tonic-gate 					proxyInfo.proxy_passwd,
8797c478bd9Sstevel@tonic-gate 					proxyInfo.auth_method)) !=
8807c478bd9Sstevel@tonic-gate 					LDAP_SUCCESS)
8817c478bd9Sstevel@tonic-gate 			return (0);
8827c478bd9Sstevel@tonic-gate 		(void) rw_rdlock(&ldapConLock);
8837c478bd9Sstevel@tonic-gate 	}
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	for (lc = ldapCon; lc != 0; lc = lc->next) {
8867c478bd9Sstevel@tonic-gate 		exclusiveLC(lc);
8877c478bd9Sstevel@tonic-gate 		if (!lc->isBound) {
8887c478bd9Sstevel@tonic-gate 			*stat = connectCon(lc, 1);
8897c478bd9Sstevel@tonic-gate 			if (*stat != LDAP_SUCCESS) {
8907c478bd9Sstevel@tonic-gate 				if (*stat != LDAP_UNAVAILABLE) {
8917c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
8927c478bd9Sstevel@tonic-gate 		"%s: Cannot open connection to LDAP server (%s): %s",
8937c478bd9Sstevel@tonic-gate 						myself, NIL(lc->sp),
8947c478bd9Sstevel@tonic-gate 						ldap_err2string(*stat));
8957c478bd9Sstevel@tonic-gate 					releaseLC(lc);
8967c478bd9Sstevel@tonic-gate 				}
8977c478bd9Sstevel@tonic-gate 				continue;
8987c478bd9Sstevel@tonic-gate 			}
8997c478bd9Sstevel@tonic-gate 		} else if (lc->doDis || lc->doDel) {
9007c478bd9Sstevel@tonic-gate 			*stat = disconnectCon(lc);
9017c478bd9Sstevel@tonic-gate 			if (*stat != LDAP_UNAVAILABLE)
9027c478bd9Sstevel@tonic-gate 				releaseLC(lc);
9037c478bd9Sstevel@tonic-gate 			continue;
9047c478bd9Sstevel@tonic-gate 		}
9057c478bd9Sstevel@tonic-gate 		incrementRC(lc);
9067c478bd9Sstevel@tonic-gate 		releaseLC(lc);
9077c478bd9Sstevel@tonic-gate 		break;
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&ldapConLock);
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	return (lc);
9137c478bd9Sstevel@tonic-gate }
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate /* Release connection; decrements ref count for the connection */
9167c478bd9Sstevel@tonic-gate static void
releaseCon(__nis_ldap_conn_t * lc,int status)9177c478bd9Sstevel@tonic-gate releaseCon(__nis_ldap_conn_t *lc, int status) {
9187c478bd9Sstevel@tonic-gate 	int	stat;
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	if (lc == 0)
9217c478bd9Sstevel@tonic-gate 		return;
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 	exclusiveLC(lc);
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	lc->status = status;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	decrementRC(lc);
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	if (lc->doDis)
9307c478bd9Sstevel@tonic-gate 		stat = disconnectCon(lc);
9317c478bd9Sstevel@tonic-gate 	else
9327c478bd9Sstevel@tonic-gate 		stat = LDAP_SUCCESS;
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	if (stat != LDAP_UNAVAILABLE)
9357c478bd9Sstevel@tonic-gate 		releaseLC(lc);
9367c478bd9Sstevel@tonic-gate }
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t *
createCon(char * sp,char * who,char * cred,auth_method_t method,int port)9397c478bd9Sstevel@tonic-gate createCon(char *sp, char *who, char *cred, auth_method_t method, int port) {
9407c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc;
9417c478bd9Sstevel@tonic-gate 	char			*myself = "createCon";
9427c478bd9Sstevel@tonic-gate 	char			*r;
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	if (sp == 0)
9457c478bd9Sstevel@tonic-gate 		return (0);
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	lc = am(myself, sizeof (*lc));
9487c478bd9Sstevel@tonic-gate 	if (lc == 0)
9497c478bd9Sstevel@tonic-gate 		return (0);
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 	(void) mutex_init(&lc->mutex, 0, 0);
9527c478bd9Sstevel@tonic-gate 	(void) mutex_init(&lc->rcMutex, 0, 0);
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	/* If we need to delete 'lc', freeCon() wants the mutex held */
9557c478bd9Sstevel@tonic-gate 	exclusiveLC(lc);
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	lc->sp = sdup(myself, T, sp);
9587c478bd9Sstevel@tonic-gate 	if (lc->sp == 0) {
9597c478bd9Sstevel@tonic-gate 		(void) freeCon(lc);
9607c478bd9Sstevel@tonic-gate 		return (0);
9617c478bd9Sstevel@tonic-gate 	}
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	if ((r = strchr(lc->sp, ']')) != 0) {
9647c478bd9Sstevel@tonic-gate 		/*
9657c478bd9Sstevel@tonic-gate 		 * IPv6 address. Does libldap want this with the
9667c478bd9Sstevel@tonic-gate 		 * '[' and ']' left in place ? Assume so for now.
9677c478bd9Sstevel@tonic-gate 		 */
9687c478bd9Sstevel@tonic-gate 		r = strchr(r, ':');
9697c478bd9Sstevel@tonic-gate 	} else {
9707c478bd9Sstevel@tonic-gate 		r = strchr(lc->sp, ':');
9717c478bd9Sstevel@tonic-gate 	}
9727c478bd9Sstevel@tonic-gate 
9737c478bd9Sstevel@tonic-gate 	if (r != NULL) {
9747c478bd9Sstevel@tonic-gate 		*r++ = '\0';
9757c478bd9Sstevel@tonic-gate 		port = atoi(r);
9767c478bd9Sstevel@tonic-gate 	} else if (port == 0)
9777c478bd9Sstevel@tonic-gate 		port = proxyInfo.tls_method == ssl_tls ? LDAPS_PORT : LDAP_PORT;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	if (who != 0) {
9807c478bd9Sstevel@tonic-gate 		lc->who = sdup(myself, T, who);
9817c478bd9Sstevel@tonic-gate 		if (lc->who == 0) {
9827c478bd9Sstevel@tonic-gate 			(void) freeCon(lc);
9837c478bd9Sstevel@tonic-gate 			return (0);
9847c478bd9Sstevel@tonic-gate 		}
9857c478bd9Sstevel@tonic-gate 	}
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	if (cred != 0) {
9887c478bd9Sstevel@tonic-gate 		lc->cred = sdup(myself, T, cred);
9897c478bd9Sstevel@tonic-gate 		if (lc->cred == 0) {
9907c478bd9Sstevel@tonic-gate 			(void) freeCon(lc);
9917c478bd9Sstevel@tonic-gate 			return (0);
9927c478bd9Sstevel@tonic-gate 		}
9937c478bd9Sstevel@tonic-gate 	}
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	lc->method = method;
9967c478bd9Sstevel@tonic-gate 	lc->port = port;
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	lc->bindTimeout = proxyInfo.bind_timeout;
9997c478bd9Sstevel@tonic-gate 	lc->searchTimeout = proxyInfo.search_timeout;
10007c478bd9Sstevel@tonic-gate 	lc->modifyTimeout = proxyInfo.modify_timeout;
10017c478bd9Sstevel@tonic-gate 	lc->addTimeout = proxyInfo.add_timeout;
10027c478bd9Sstevel@tonic-gate 	lc->deleteTimeout = proxyInfo.delete_timeout;
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	/* All other fields OK at zero */
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	releaseLC(lc);
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 	return (lc);
10097c478bd9Sstevel@tonic-gate }
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate static int
setupConList(char * serverList,char * who,char * cred,auth_method_t method)10127c478bd9Sstevel@tonic-gate setupConList(char *serverList, char *who, char *cred, auth_method_t method) {
10137c478bd9Sstevel@tonic-gate 	char			*sls, *sl, *s, *e;
10147c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc, *tmp;
10157c478bd9Sstevel@tonic-gate 	char			*myself = "setupConList";
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 	if (serverList == 0)
10187c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 	(void) rw_wrlock(&ldapConLock);
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	if (ldapCon != 0) {
10237c478bd9Sstevel@tonic-gate 		/* Assume we've already been called and done the set-up */
10247c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ldapConLock);
10257c478bd9Sstevel@tonic-gate 		return (LDAP_SUCCESS);
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	/* Work on a copy of 'serverList' */
10297c478bd9Sstevel@tonic-gate 	sl = sls = sdup(myself, T, serverList);
10307c478bd9Sstevel@tonic-gate 	if (sl == 0) {
10317c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ldapConLock);
10327c478bd9Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	/* Remove leading white space */
1036*a87701e9SGary Mills 	for (; *sl == ' ' || *sl == '\t'; sl++);
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 	/* Create connection for each server on the list */
10397c478bd9Sstevel@tonic-gate 	for (s = sl; *s != '\0'; s = e+1) {
10407c478bd9Sstevel@tonic-gate 		int	l;
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 		/* Find end of server/port token */
10437c478bd9Sstevel@tonic-gate 		for (e = s; *e != ' ' && *e != '\t' && *e != '\0'; e++);
10447c478bd9Sstevel@tonic-gate 		if (*e != '\0')
10457c478bd9Sstevel@tonic-gate 			*e = '\0';
10467c478bd9Sstevel@tonic-gate 		else
10477c478bd9Sstevel@tonic-gate 			e--;
10487c478bd9Sstevel@tonic-gate 		l = slen(s);
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 		if (l > 0) {
10517c478bd9Sstevel@tonic-gate 			lc = createCon(s, who, cred, method, 0);
10527c478bd9Sstevel@tonic-gate 			if (lc == 0) {
10537c478bd9Sstevel@tonic-gate 				free(sls);
10547c478bd9Sstevel@tonic-gate 				(void) rw_unlock(&ldapConLock);
10557c478bd9Sstevel@tonic-gate 				return (LDAP_NO_MEMORY);
10567c478bd9Sstevel@tonic-gate 			}
10577c478bd9Sstevel@tonic-gate 			lc->onList = 1;
10587c478bd9Sstevel@tonic-gate 			if (ldapCon == 0) {
10597c478bd9Sstevel@tonic-gate 				ldapCon = lc;
10607c478bd9Sstevel@tonic-gate 			} else {
10617c478bd9Sstevel@tonic-gate 				/* Insert at end of list */
10627c478bd9Sstevel@tonic-gate 				for (tmp = ldapCon; tmp->next != 0;
10637c478bd9Sstevel@tonic-gate 					tmp = tmp->next);
10647c478bd9Sstevel@tonic-gate 				tmp->next = lc;
10657c478bd9Sstevel@tonic-gate 			}
10667c478bd9Sstevel@tonic-gate 		}
10677c478bd9Sstevel@tonic-gate 	}
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 	free(sls);
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&ldapConLock);
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	return (LDAP_SUCCESS);
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate static bool_t
is_same_connection(__nis_ldap_conn_t * lc,LDAPURLDesc * ludpp)10777c478bd9Sstevel@tonic-gate is_same_connection(__nis_ldap_conn_t *lc, LDAPURLDesc *ludpp)
10787c478bd9Sstevel@tonic-gate {
10797c478bd9Sstevel@tonic-gate 	return (strcasecmp(ludpp->lud_host, lc->sp) == 0 &&
10807c478bd9Sstevel@tonic-gate 	    ludpp->lud_port == lc->port);
10817c478bd9Sstevel@tonic-gate }
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t *
find_connection_from_list(__nis_ldap_conn_t * list,LDAPURLDesc * ludpp,int * stat)10847c478bd9Sstevel@tonic-gate find_connection_from_list(__nis_ldap_conn_t *list,
10857c478bd9Sstevel@tonic-gate 			LDAPURLDesc *ludpp, int *stat)
10867c478bd9Sstevel@tonic-gate {
10877c478bd9Sstevel@tonic-gate 	int			ldapStat;
10887c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc	= NULL;
10897c478bd9Sstevel@tonic-gate 	if (stat == 0)
10907c478bd9Sstevel@tonic-gate 		stat = &ldapStat;
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 	*stat = LDAP_SUCCESS;
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	for (lc = list; lc != 0; lc = lc->next) {
10957c478bd9Sstevel@tonic-gate 		exclusiveLC(lc);
10967c478bd9Sstevel@tonic-gate 		if (is_same_connection(lc, ludpp)) {
10977c478bd9Sstevel@tonic-gate 			if (!lc->isBound) {
10987c478bd9Sstevel@tonic-gate 				*stat = connectCon(lc, 1);
10997c478bd9Sstevel@tonic-gate 				if (*stat != LDAP_SUCCESS) {
11007c478bd9Sstevel@tonic-gate 					releaseLC(lc);
11017c478bd9Sstevel@tonic-gate 					continue;
11027c478bd9Sstevel@tonic-gate 				}
11037c478bd9Sstevel@tonic-gate 			} else if (lc->doDis || lc->doDel) {
11047c478bd9Sstevel@tonic-gate 				(void) disconnectCon(lc);
11057c478bd9Sstevel@tonic-gate 				releaseLC(lc);
11067c478bd9Sstevel@tonic-gate 				continue;
11077c478bd9Sstevel@tonic-gate 			}
11087c478bd9Sstevel@tonic-gate 			incrementRC(lc);
11097c478bd9Sstevel@tonic-gate 			releaseLC(lc);
11107c478bd9Sstevel@tonic-gate 			break;
11117c478bd9Sstevel@tonic-gate 		}
11127c478bd9Sstevel@tonic-gate 		releaseLC(lc);
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 	return (lc);
11157c478bd9Sstevel@tonic-gate }
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t *
findReferralCon(char ** referralsp,int * stat)11187c478bd9Sstevel@tonic-gate findReferralCon(char **referralsp, int *stat)
11197c478bd9Sstevel@tonic-gate {
11207c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc	= NULL;
11217c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*tmp;
11227c478bd9Sstevel@tonic-gate 	int			ldapStat;
11237c478bd9Sstevel@tonic-gate 	int			i;
11247c478bd9Sstevel@tonic-gate 	LDAPURLDesc		*ludpp	= NULL;
11257c478bd9Sstevel@tonic-gate 	char			*myself = "findReferralCon";
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 	if (stat == 0)
11287c478bd9Sstevel@tonic-gate 		stat = &ldapStat;
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	*stat = LDAP_SUCCESS;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 	/*
11337c478bd9Sstevel@tonic-gate 	 * We have the referral lock - to prevent multiple
11347c478bd9Sstevel@tonic-gate 	 * threads from creating a referred connection simultaneously
11357c478bd9Sstevel@tonic-gate 	 *
11367c478bd9Sstevel@tonic-gate 	 * Note that this code assumes that the ldapCon list is a
11377c478bd9Sstevel@tonic-gate 	 * static list - that it has previously been created
11387c478bd9Sstevel@tonic-gate 	 * (otherwise we wouldn't have gotten a referral) and that
11397c478bd9Sstevel@tonic-gate 	 * it will neither grow or shrink - elements may have new
11407c478bd9Sstevel@tonic-gate 	 * connections or unbound. If this assumption is no longer valid,
11417c478bd9Sstevel@tonic-gate 	 * the locking needs to be reworked.
11427c478bd9Sstevel@tonic-gate 	 */
11437c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&referralConLock);
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate 	for (i = 0; referralsp[i] != NULL; i++) {
11467c478bd9Sstevel@tonic-gate 		if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS)
11477c478bd9Sstevel@tonic-gate 			continue;
11487c478bd9Sstevel@tonic-gate 		/* Ignore referrals if not at the appropriate tls level */
11497c478bd9Sstevel@tonic-gate #ifdef LDAP_URL_OPT_SECURE
11507c478bd9Sstevel@tonic-gate 		if (ludpp->lud_options & LDAP_URL_OPT_SECURE) {
11517c478bd9Sstevel@tonic-gate 			if (proxyInfo.tls_method != ssl_tls) {
11527c478bd9Sstevel@tonic-gate 				ldap_free_urldesc(ludpp);
11537c478bd9Sstevel@tonic-gate 				continue;
11547c478bd9Sstevel@tonic-gate 			}
11557c478bd9Sstevel@tonic-gate 		} else {
11567c478bd9Sstevel@tonic-gate 			if (proxyInfo.tls_method != no_tls) {
11577c478bd9Sstevel@tonic-gate 				ldap_free_urldesc(ludpp);
11587c478bd9Sstevel@tonic-gate 				continue;
11597c478bd9Sstevel@tonic-gate 			}
11607c478bd9Sstevel@tonic-gate 		}
11617c478bd9Sstevel@tonic-gate #endif
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 		/* Determine if we already have a connection to the server */
11647c478bd9Sstevel@tonic-gate 		lc = find_connection_from_list(ldapReferralCon, ludpp, stat);
11657c478bd9Sstevel@tonic-gate 		if (lc == NULL)
11667c478bd9Sstevel@tonic-gate 			lc = find_connection_from_list(ldapCon, ludpp, stat);
11677c478bd9Sstevel@tonic-gate 		ldap_free_urldesc(ludpp);
11687c478bd9Sstevel@tonic-gate 		if (lc != NULL) {
11697c478bd9Sstevel@tonic-gate 			(void) rw_unlock(&referralConLock);
11707c478bd9Sstevel@tonic-gate 			return (lc);
11717c478bd9Sstevel@tonic-gate 		}
11727c478bd9Sstevel@tonic-gate 	}
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	for (i = 0; referralsp[i] != NULL; i++) {
11757c478bd9Sstevel@tonic-gate 		if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS)
11767c478bd9Sstevel@tonic-gate 			continue;
11777c478bd9Sstevel@tonic-gate 		/* Ignore referrals if not at the appropriate tls level */
11787c478bd9Sstevel@tonic-gate #ifdef LDAP_URL_OPT_SECURE
11797c478bd9Sstevel@tonic-gate 		if (ludpp->lud_options & LDAP_URL_OPT_SECURE) {
11807c478bd9Sstevel@tonic-gate 			if (proxyInfo.tls_method != ssl_tls) {
11817c478bd9Sstevel@tonic-gate 				ldap_free_urldesc(ludpp);
11827c478bd9Sstevel@tonic-gate 				continue;
11837c478bd9Sstevel@tonic-gate 			}
11847c478bd9Sstevel@tonic-gate 		} else {
11857c478bd9Sstevel@tonic-gate 			if (proxyInfo.tls_method != no_tls) {
11867c478bd9Sstevel@tonic-gate 				ldap_free_urldesc(ludpp);
11877c478bd9Sstevel@tonic-gate 				continue;
11887c478bd9Sstevel@tonic-gate 			}
11897c478bd9Sstevel@tonic-gate 		}
11907c478bd9Sstevel@tonic-gate #endif
11917c478bd9Sstevel@tonic-gate 		lc = createCon(ludpp->lud_host, proxyInfo.proxy_dn,
11927c478bd9Sstevel@tonic-gate 		    proxyInfo.proxy_passwd,
11937c478bd9Sstevel@tonic-gate 		    proxyInfo.auth_method,
11947c478bd9Sstevel@tonic-gate 		    ludpp->lud_port);
11957c478bd9Sstevel@tonic-gate 		if (lc == 0) {
11967c478bd9Sstevel@tonic-gate 			ldap_free_urldesc(ludpp);
11977c478bd9Sstevel@tonic-gate 			(void) rw_unlock(&referralConLock);
11987c478bd9Sstevel@tonic-gate 			*stat = LDAP_NO_MEMORY;
11997c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
12007c478bd9Sstevel@tonic-gate 			    "%s: Could not connect to host: %s",
12017c478bd9Sstevel@tonic-gate 			    myself, NIL(ludpp->lud_host));
12027c478bd9Sstevel@tonic-gate 			return (NULL);
12037c478bd9Sstevel@tonic-gate 		}
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate 		lc->onList = 1;
12067c478bd9Sstevel@tonic-gate 		if (ldapReferralCon == 0) {
12077c478bd9Sstevel@tonic-gate 			ldapReferralCon = lc;
12087c478bd9Sstevel@tonic-gate 		} else {
12097c478bd9Sstevel@tonic-gate 			/* Insert at end of list */
12107c478bd9Sstevel@tonic-gate 			for (tmp = ldapReferralCon; tmp->next != 0;
12117c478bd9Sstevel@tonic-gate 			    tmp = tmp->next) {}
12127c478bd9Sstevel@tonic-gate 			tmp->next = lc;
12137c478bd9Sstevel@tonic-gate 		}
12147c478bd9Sstevel@tonic-gate 		lc = find_connection_from_list(ldapReferralCon, ludpp, stat);
12157c478bd9Sstevel@tonic-gate 		ldap_free_urldesc(ludpp);
12167c478bd9Sstevel@tonic-gate 		if (lc != NULL)
12177c478bd9Sstevel@tonic-gate 			break;
12187c478bd9Sstevel@tonic-gate 	}
12197c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&referralConLock);
12207c478bd9Sstevel@tonic-gate 	if (lc == NULL) {
12217c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
12227c478bd9Sstevel@tonic-gate 		    "%s: Could not find a connection to %s, ...",
12237c478bd9Sstevel@tonic-gate 		    myself, NIL(referralsp[0]));
12247c478bd9Sstevel@tonic-gate 	}
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	return (lc);
12277c478bd9Sstevel@tonic-gate }
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate /*
12307c478bd9Sstevel@tonic-gate  * Find and return a connection believed to be OK and ensure children
12317c478bd9Sstevel@tonic-gate  * will never use parent's connection.
12327c478bd9Sstevel@tonic-gate  */
12337c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t *
findYPCon(__nis_ldap_search_t * ls,int * stat)12347c478bd9Sstevel@tonic-gate findYPCon(__nis_ldap_search_t *ls, int *stat) {
12357c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc, *newlc;
12367c478bd9Sstevel@tonic-gate 	int			ldapStat, newstat;
12377c478bd9Sstevel@tonic-gate 	char			*myself = "findYPCon";
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate 	if (stat == 0)
12407c478bd9Sstevel@tonic-gate 		stat = &ldapStat;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&ldapConLock);
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	if (ldapCon == 0) {
12457c478bd9Sstevel@tonic-gate 		/* Probably first call; try to set up the connection list */
12467c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ldapConLock);
12477c478bd9Sstevel@tonic-gate 		if ((*stat = setupConList(proxyInfo.default_servers,
12487c478bd9Sstevel@tonic-gate 					proxyInfo.proxy_dn,
12497c478bd9Sstevel@tonic-gate 					proxyInfo.proxy_passwd,
12507c478bd9Sstevel@tonic-gate 					proxyInfo.auth_method)) !=
12517c478bd9Sstevel@tonic-gate 					LDAP_SUCCESS)
12527c478bd9Sstevel@tonic-gate 			return (0);
12537c478bd9Sstevel@tonic-gate 		(void) rw_rdlock(&ldapConLock);
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	for (lc = ldapCon; lc != 0; lc = lc->next) {
12577c478bd9Sstevel@tonic-gate 		exclusiveLC(lc);
12587c478bd9Sstevel@tonic-gate 
12597c478bd9Sstevel@tonic-gate 		if (lc->isBound && (lc->doDis || lc->doDel)) {
12607c478bd9Sstevel@tonic-gate 			*stat = disconnectCon(lc);
12617c478bd9Sstevel@tonic-gate 			if (*stat != LDAP_UNAVAILABLE)
12627c478bd9Sstevel@tonic-gate 				releaseLC(lc);
12637c478bd9Sstevel@tonic-gate 			continue;
12647c478bd9Sstevel@tonic-gate 		}
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 		/*
12677c478bd9Sstevel@tonic-gate 		 * Use a new connection for all cases except when
12687c478bd9Sstevel@tonic-gate 		 * requested by the main thread in the parent ypserv
12697c478bd9Sstevel@tonic-gate 		 * process.
12707c478bd9Sstevel@tonic-gate 		 */
12717c478bd9Sstevel@tonic-gate 		if (ls->useCon == 0) {
12727c478bd9Sstevel@tonic-gate 			newlc = createCon(lc->sp, lc->who, lc->cred,
12737c478bd9Sstevel@tonic-gate 						lc->method, lc->port);
12747c478bd9Sstevel@tonic-gate 			if (!newlc) {
12757c478bd9Sstevel@tonic-gate 				releaseLC(lc);
12767c478bd9Sstevel@tonic-gate 				continue;
12777c478bd9Sstevel@tonic-gate 			}
12787c478bd9Sstevel@tonic-gate 			if (lc->ld != 0) {
12797c478bd9Sstevel@tonic-gate 				newlc->simplePage = lc->simplePage;
12807c478bd9Sstevel@tonic-gate 				newlc->vlv = lc->vlv;
12817c478bd9Sstevel@tonic-gate 				newlc->batchFrom = lc->batchFrom;
12827c478bd9Sstevel@tonic-gate 			}
12837c478bd9Sstevel@tonic-gate 			releaseLC(lc);
12847c478bd9Sstevel@tonic-gate 			exclusiveLC(newlc);
12857c478bd9Sstevel@tonic-gate 			newstat = connectCon(newlc, 0);
12867c478bd9Sstevel@tonic-gate 			if (newstat != LDAP_SUCCESS) {
12877c478bd9Sstevel@tonic-gate 				if (newstat != LDAP_UNAVAILABLE) {
12887c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
12897c478bd9Sstevel@tonic-gate 			"%s: Cannot open connection to LDAP server (%s): %s",
12907c478bd9Sstevel@tonic-gate 						myself, NIL(newlc->sp),
12917c478bd9Sstevel@tonic-gate 						ldap_err2string(*stat));
12927c478bd9Sstevel@tonic-gate 				}
12937c478bd9Sstevel@tonic-gate 				(void) freeCon(newlc);
12947c478bd9Sstevel@tonic-gate 				newlc = 0;
12957c478bd9Sstevel@tonic-gate 				continue;
12967c478bd9Sstevel@tonic-gate 			}
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 			/*
12997c478bd9Sstevel@tonic-gate 			 * No need to put newlc on the ldapCon list as this
13007c478bd9Sstevel@tonic-gate 			 * connection will be freed after use.
13017c478bd9Sstevel@tonic-gate 			 */
13027c478bd9Sstevel@tonic-gate 			newlc->onList = 0;
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate 			lc = newlc;
13057c478bd9Sstevel@tonic-gate 		} else  if (!lc->isBound) {
13067c478bd9Sstevel@tonic-gate 			*stat = connectCon(lc, 1);
13077c478bd9Sstevel@tonic-gate 			if (*stat != LDAP_SUCCESS) {
13087c478bd9Sstevel@tonic-gate 				if (*stat != LDAP_UNAVAILABLE) {
13097c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
13107c478bd9Sstevel@tonic-gate 		"%s: Cannot open connection to LDAP server (%s): %s",
13117c478bd9Sstevel@tonic-gate 						myself, NIL(lc->sp),
13127c478bd9Sstevel@tonic-gate 						ldap_err2string(*stat));
13137c478bd9Sstevel@tonic-gate 					releaseLC(lc);
13147c478bd9Sstevel@tonic-gate 				}
13157c478bd9Sstevel@tonic-gate 				continue;
13167c478bd9Sstevel@tonic-gate 			}
13177c478bd9Sstevel@tonic-gate 		}
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate 		incrementRC(lc);
13207c478bd9Sstevel@tonic-gate 		releaseLC(lc);
13217c478bd9Sstevel@tonic-gate 		break;
13227c478bd9Sstevel@tonic-gate 	}
13237c478bd9Sstevel@tonic-gate 
13247c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&ldapConLock);
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 	return (lc);
13277c478bd9Sstevel@tonic-gate }
13287c478bd9Sstevel@tonic-gate 
13297c478bd9Sstevel@tonic-gate #define	SORTKEYLIST	"cn uid"
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate /*
13327c478bd9Sstevel@tonic-gate  * Perform an LDAP search operation per 'ls', adding the result(s) to
13337c478bd9Sstevel@tonic-gate  * a copy of the 'rvIn' structure; the copy becomes the return value.
13347c478bd9Sstevel@tonic-gate  * The caller must deallocate both 'rvIn' and the result, if any.
13357c478bd9Sstevel@tonic-gate  *
13367c478bd9Sstevel@tonic-gate  * On entry, '*numValues' contains a hint regarding the expected
13377c478bd9Sstevel@tonic-gate  * number of entries. Zero is the same as one, and negative values
13387c478bd9Sstevel@tonic-gate  * imply no information. This is used to decide whether or not to
13397c478bd9Sstevel@tonic-gate  * try an indexed search.
13407c478bd9Sstevel@tonic-gate  *
13417c478bd9Sstevel@tonic-gate  * On successful (non-NULL) return, '*numValues' contains the number
13427c478bd9Sstevel@tonic-gate  * of __nis_rule_value_t elements in the returned array, and '*stat'
13437c478bd9Sstevel@tonic-gate  * the LDAP operations status.
13447c478bd9Sstevel@tonic-gate  */
13457c478bd9Sstevel@tonic-gate __nis_rule_value_t *
ldapSearch(__nis_ldap_search_t * ls,int * numValues,__nis_rule_value_t * rvIn,int * ldapStat)13467c478bd9Sstevel@tonic-gate ldapSearch(__nis_ldap_search_t *ls, int *numValues, __nis_rule_value_t *rvIn,
13477c478bd9Sstevel@tonic-gate 		int *ldapStat) {
13487c478bd9Sstevel@tonic-gate 	__nis_rule_value_t	*rv = 0;
13497c478bd9Sstevel@tonic-gate 	int			stat, numEntries, numVals, tnv, done, lprEc;
13507c478bd9Sstevel@tonic-gate 	LDAPMessage		*msg = 0, *m;
13517c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc;
13527c478bd9Sstevel@tonic-gate 	struct timeval		tv, start, now;
13537c478bd9Sstevel@tonic-gate 	LDAPsortkey		**sortKeyList = 0;
13547c478bd9Sstevel@tonic-gate 	LDAPControl		*ctrls[3], *sortCtrl = 0, *vlvCtrl = 0;
13557c478bd9Sstevel@tonic-gate 	LDAPControl		**retCtrls = 0;
13567c478bd9Sstevel@tonic-gate 	LDAPVirtualList		vList;
13577c478bd9Sstevel@tonic-gate 	struct berval		*spCookie = 0;
13587c478bd9Sstevel@tonic-gate 	int			doVLV = 0;
13597c478bd9Sstevel@tonic-gate 	int			doSP = 0;
13607c478bd9Sstevel@tonic-gate 	long			index;
13617c478bd9Sstevel@tonic-gate 	char			*myself = "ldapSearch";
13627c478bd9Sstevel@tonic-gate 	bool_t			follow_referral =
13637c478bd9Sstevel@tonic-gate 					proxyInfo.follow_referral == follow;
13647c478bd9Sstevel@tonic-gate 	int			doIndex = 1;
13657c478bd9Sstevel@tonic-gate 	char			**referralsp = NULL;
13667c478bd9Sstevel@tonic-gate 
136754caa916SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 	ctrls[0] = ctrls[1] = ctrls[2] = 0;
136854caa916SSreedhar Chalamalasetti - Sun Microsystems - Bangalore India 
13697c478bd9Sstevel@tonic-gate 	if (ldapStat == 0)
13707c478bd9Sstevel@tonic-gate 		ldapStat = &stat;
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	if (ls == 0) {
13737c478bd9Sstevel@tonic-gate 		*ldapStat = LDAP_PARAM_ERROR;
13747c478bd9Sstevel@tonic-gate 		return (0);
13757c478bd9Sstevel@tonic-gate 	}
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	if (yp2ldap) {
13787c478bd9Sstevel@tonic-gate 		/* make sure the parent's connection is not used by child */
13797c478bd9Sstevel@tonic-gate 		if ((lc = findYPCon(ls, ldapStat)) == 0) {
13807c478bd9Sstevel@tonic-gate 			*ldapStat = LDAP_SERVER_DOWN;
13817c478bd9Sstevel@tonic-gate 			return (0);
13827c478bd9Sstevel@tonic-gate 		}
13837c478bd9Sstevel@tonic-gate 	} else {
13847c478bd9Sstevel@tonic-gate 		if ((lc = findCon(ldapStat)) == 0) {
13857c478bd9Sstevel@tonic-gate 			*ldapStat = LDAP_SERVER_DOWN;
13867c478bd9Sstevel@tonic-gate 			return (0);
13877c478bd9Sstevel@tonic-gate 		}
13887c478bd9Sstevel@tonic-gate 	}
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 	if (numValues != 0 && (*numValues == 0 || *numValues == 1))
13917c478bd9Sstevel@tonic-gate 		doIndex = 0;
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate retry_new_conn:
13947c478bd9Sstevel@tonic-gate 	/* Prefer VLV over simple page, and SP over nothing */
13957c478bd9Sstevel@tonic-gate 	if (doIndex && lc->vlv) {
13967c478bd9Sstevel@tonic-gate 		stat = ldap_create_sort_keylist(&sortKeyList, SORTKEYLIST);
13977c478bd9Sstevel@tonic-gate 		if (stat != LDAP_SUCCESS) {
13987c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
13997c478bd9Sstevel@tonic-gate 				"%s: Error creating sort keylist: %s",
14007c478bd9Sstevel@tonic-gate 				myself, ldap_err2string(stat));
14017c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
14027c478bd9Sstevel@tonic-gate 			*ldapStat = stat;
14037c478bd9Sstevel@tonic-gate 			rv = 0;
14047c478bd9Sstevel@tonic-gate 			goto retry_noVLV;
14057c478bd9Sstevel@tonic-gate 		}
14067c478bd9Sstevel@tonic-gate 		stat = ldap_create_sort_control(lc->ld, sortKeyList, 1,
14077c478bd9Sstevel@tonic-gate 						&sortCtrl);
14087c478bd9Sstevel@tonic-gate 		if (stat == LDAP_SUCCESS) {
14097c478bd9Sstevel@tonic-gate 			vList.ldvlist_before_count = 0;
14107c478bd9Sstevel@tonic-gate 			vList.ldvlist_after_count = lc->batchFrom - 1;
14117c478bd9Sstevel@tonic-gate 			vList.ldvlist_attrvalue = 0;
14127c478bd9Sstevel@tonic-gate 			vList.ldvlist_extradata = 0;
14137c478bd9Sstevel@tonic-gate 			index = 1;
14147c478bd9Sstevel@tonic-gate 			doVLV = 1;
14157c478bd9Sstevel@tonic-gate 		} else {
14167c478bd9Sstevel@tonic-gate 			ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
14177c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
14187c478bd9Sstevel@tonic-gate 				"%s: Error creating VLV sort control: %s",
14197c478bd9Sstevel@tonic-gate 				myself, ldap_err2string(stat));
14207c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
14217c478bd9Sstevel@tonic-gate 			*ldapStat = stat;
14227c478bd9Sstevel@tonic-gate 			rv = 0;
14237c478bd9Sstevel@tonic-gate 		}
14247c478bd9Sstevel@tonic-gate 	}
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate retry_noVLV:
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	if (doIndex && !doVLV && lc->simplePage) {
14297c478bd9Sstevel@tonic-gate 		spCookie = am(myself, sizeof (*spCookie));
14307c478bd9Sstevel@tonic-gate 		if (spCookie != 0 &&
14317c478bd9Sstevel@tonic-gate 				(spCookie->bv_val = sdup(myself, T, "")) != 0) {
14327c478bd9Sstevel@tonic-gate 			spCookie->bv_len = 0;
14337c478bd9Sstevel@tonic-gate 			doSP = 1;
14347c478bd9Sstevel@tonic-gate 		} else {
14357c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
14367c478bd9Sstevel@tonic-gate 	"%s: No memory for simple page cookie; using un-paged LDAP search",
14377c478bd9Sstevel@tonic-gate 				myself);
14387c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
14397c478bd9Sstevel@tonic-gate 			*ldapStat = stat;
14407c478bd9Sstevel@tonic-gate 			rv = 0;
14417c478bd9Sstevel@tonic-gate 			goto cleanup;
14427c478bd9Sstevel@tonic-gate 		}
14437c478bd9Sstevel@tonic-gate 	}
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	if (!doVLV && !doSP)
14467c478bd9Sstevel@tonic-gate 		ctrls[0] = ctrls[1] = 0;
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	numVals = 0;
14497c478bd9Sstevel@tonic-gate 	done = 0;
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 	if (ls->timeout.tv_sec || ls->timeout.tv_usec) {
14527c478bd9Sstevel@tonic-gate 		tv = ls->timeout;
14537c478bd9Sstevel@tonic-gate 	} else {
14547c478bd9Sstevel@tonic-gate 		tv = lc->searchTimeout;
14557c478bd9Sstevel@tonic-gate 	}
14567c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&start, 0);
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 	do {
14597c478bd9Sstevel@tonic-gate 		/* don't do vlv or simple page for base level searches */
14607c478bd9Sstevel@tonic-gate 		if (doVLV && ls->base != LDAP_SCOPE_BASE) {
14617c478bd9Sstevel@tonic-gate 			vList.ldvlist_index = index;
14627c478bd9Sstevel@tonic-gate 			vList.ldvlist_size = 0;
14637c478bd9Sstevel@tonic-gate 			if (vlvCtrl != 0)
14647c478bd9Sstevel@tonic-gate 				ldap_control_free(vlvCtrl);
14657c478bd9Sstevel@tonic-gate 			stat = ldap_create_virtuallist_control(lc->ld,
14667c478bd9Sstevel@tonic-gate 					&vList, &vlvCtrl);
14677c478bd9Sstevel@tonic-gate 			if (stat != LDAP_SUCCESS) {
14687c478bd9Sstevel@tonic-gate 				ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
14697c478bd9Sstevel@tonic-gate 						&stat);
14707c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
14717c478bd9Sstevel@tonic-gate 				"%s: Error creating VLV at index %ld: %s",
14727c478bd9Sstevel@tonic-gate 					myself, index, ldap_err2string(stat));
14737c478bd9Sstevel@tonic-gate 				*ldapStat = stat;
14747c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, numVals);
14757c478bd9Sstevel@tonic-gate 				rv = 0;
14767c478bd9Sstevel@tonic-gate 				goto cleanup;
14777c478bd9Sstevel@tonic-gate 			}
14787c478bd9Sstevel@tonic-gate 			ctrls[0] = sortCtrl;
14797c478bd9Sstevel@tonic-gate 			ctrls[1] = vlvCtrl;
14807c478bd9Sstevel@tonic-gate 			ctrls[2] = 0;
14817c478bd9Sstevel@tonic-gate 			stat = ldap_search_ext_s(lc->ld, ls->base,
14827c478bd9Sstevel@tonic-gate 					ls->scope, ls->filter, ls->attrs,
14837c478bd9Sstevel@tonic-gate 					ls->attrsonly, ctrls, 0, &tv,
14847c478bd9Sstevel@tonic-gate 					proxyInfo.search_size_limit, &msg);
14857c478bd9Sstevel@tonic-gate 		/* don't do vlv or simple page for base level searches */
14867c478bd9Sstevel@tonic-gate 		} else if (doSP && ls->base != LDAP_SCOPE_BASE) {
14877c478bd9Sstevel@tonic-gate 			if (ctrls[0] != 0)
14887c478bd9Sstevel@tonic-gate 				ldap_control_free(ctrls[0]);
14897c478bd9Sstevel@tonic-gate 			stat = ldap_create_page_control(lc->ld,
14907c478bd9Sstevel@tonic-gate 					lc->batchFrom, spCookie, 0, &ctrls[0]);
14917c478bd9Sstevel@tonic-gate 			if (stat != LDAP_SUCCESS) {
14927c478bd9Sstevel@tonic-gate 				ber_bvfree(spCookie);
14937c478bd9Sstevel@tonic-gate 				spCookie = 0;
14947c478bd9Sstevel@tonic-gate 				ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
14957c478bd9Sstevel@tonic-gate 						&stat);
14967c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
14977c478bd9Sstevel@tonic-gate 					"%s: Simple page error: %s",
14987c478bd9Sstevel@tonic-gate 					myself, ldap_err2string(stat));
14997c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, numVals);
15007c478bd9Sstevel@tonic-gate 				*ldapStat = stat;
15017c478bd9Sstevel@tonic-gate 				rv = 0;
15027c478bd9Sstevel@tonic-gate 				goto cleanup;
15037c478bd9Sstevel@tonic-gate 			}
15047c478bd9Sstevel@tonic-gate 			ctrls[1] = 0;
15057c478bd9Sstevel@tonic-gate 			stat = ldap_search_ext_s(lc->ld, ls->base,
15067c478bd9Sstevel@tonic-gate 					ls->scope, ls->filter, ls->attrs,
15077c478bd9Sstevel@tonic-gate 					ls->attrsonly, ctrls, 0, &tv,
15087c478bd9Sstevel@tonic-gate 					proxyInfo.search_size_limit, &msg);
15097c478bd9Sstevel@tonic-gate 		} else {
15107c478bd9Sstevel@tonic-gate 			stat = ldap_search_st(lc->ld, ls->base, ls->scope,
15117c478bd9Sstevel@tonic-gate 					ls->filter, ls->attrs, ls->attrsonly,
15127c478bd9Sstevel@tonic-gate 					&tv, &msg);
15137c478bd9Sstevel@tonic-gate 		}
15147c478bd9Sstevel@tonic-gate 		if (stat == LDAP_SUCCESS)
15157c478bd9Sstevel@tonic-gate 			ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 		if (stat == LDAP_SERVER_DOWN) {
15187c478bd9Sstevel@tonic-gate 			lc->doDis++;
15197c478bd9Sstevel@tonic-gate 			releaseCon(lc, stat);
15207c478bd9Sstevel@tonic-gate 			lc = (yp2ldap)?findYPCon(ls, ldapStat):
15217c478bd9Sstevel@tonic-gate 				findCon(ldapStat);
15227c478bd9Sstevel@tonic-gate 			if (lc == 0) {
15237c478bd9Sstevel@tonic-gate 				*ldapStat = LDAP_SERVER_DOWN;
15247c478bd9Sstevel@tonic-gate 				rv =  0;
15257c478bd9Sstevel@tonic-gate 				goto cleanup;
15267c478bd9Sstevel@tonic-gate 			}
15277c478bd9Sstevel@tonic-gate 			goto retry_new_conn;
15287c478bd9Sstevel@tonic-gate 		}
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 		if (stat == LDAP_REFERRAL && follow_referral) {
15317c478bd9Sstevel@tonic-gate 			(void) ldap_parse_result(lc->ld, msg, NULL, NULL, NULL,
15327c478bd9Sstevel@tonic-gate 				&referralsp, NULL, 0);
15337c478bd9Sstevel@tonic-gate 			if (referralsp != NULL) {
15347c478bd9Sstevel@tonic-gate 				/* We support at most one level of referrals */
15357c478bd9Sstevel@tonic-gate 				follow_referral = FALSE;
15367c478bd9Sstevel@tonic-gate 				releaseCon(lc, stat);
15377c478bd9Sstevel@tonic-gate 				lc = findReferralCon(referralsp, &stat);
15387c478bd9Sstevel@tonic-gate 				ldap_value_free(referralsp);
15397c478bd9Sstevel@tonic-gate 				if (lc == NULL) {
15407c478bd9Sstevel@tonic-gate 					freeRuleValue(rv, numVals);
15417c478bd9Sstevel@tonic-gate 					rv = 0;
15427c478bd9Sstevel@tonic-gate 					*ldapStat = stat;
15437c478bd9Sstevel@tonic-gate 					goto cleanup;
15447c478bd9Sstevel@tonic-gate 				}
15457c478bd9Sstevel@tonic-gate 				stat = LDAP_SUCCESS;
15467c478bd9Sstevel@tonic-gate 				goto retry_new_conn;
15477c478bd9Sstevel@tonic-gate 			}
15487c478bd9Sstevel@tonic-gate 		}
15497c478bd9Sstevel@tonic-gate 		*ldapStat = stat;
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 		if (*ldapStat == LDAP_NO_SUCH_OBJECT) {
15527c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
15537c478bd9Sstevel@tonic-gate 			rv = 0;
15547c478bd9Sstevel@tonic-gate 			goto cleanup;
15557c478bd9Sstevel@tonic-gate 		} else if (doVLV && *ldapStat == LDAP_INSUFFICIENT_ACCESS) {
15567c478bd9Sstevel@tonic-gate 			/*
15577c478bd9Sstevel@tonic-gate 			 * The LDAP server (at least Netscape 4.x) can return
15587c478bd9Sstevel@tonic-gate 			 * LDAP_INSUFFICIENT_ACCESS when VLV is supported,
15597c478bd9Sstevel@tonic-gate 			 * but not for the bind DN specified. So, just in
15607c478bd9Sstevel@tonic-gate 			 * case, we clean up, and try again without VLV.
15617c478bd9Sstevel@tonic-gate 			 */
15627c478bd9Sstevel@tonic-gate 			doVLV = 0;
15637c478bd9Sstevel@tonic-gate 			if (msg != 0) {
15647c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(msg);
15657c478bd9Sstevel@tonic-gate 				msg = 0;
15667c478bd9Sstevel@tonic-gate 			}
15677c478bd9Sstevel@tonic-gate 			if (ctrls[0] != 0) {
15687c478bd9Sstevel@tonic-gate 				ldap_control_free(ctrls[0]);
15697c478bd9Sstevel@tonic-gate 				ctrls[0] = 0;
15707c478bd9Sstevel@tonic-gate 			}
15717c478bd9Sstevel@tonic-gate 			if (ctrls[1] != 0) {
15727c478bd9Sstevel@tonic-gate 				ldap_control_free(ctrls[1]);
15737c478bd9Sstevel@tonic-gate 				ctrls[1] = 0;
15747c478bd9Sstevel@tonic-gate 			}
15757c478bd9Sstevel@tonic-gate 			logmsg(MSG_VLV_INSUFF_ACC, LOG_WARNING,
15767c478bd9Sstevel@tonic-gate 	"%s: VLV insufficient access from server %s; retrying without VLV",
15777c478bd9Sstevel@tonic-gate 				myself, NIL(lc->sp));
15787c478bd9Sstevel@tonic-gate 			goto retry_noVLV;
15797c478bd9Sstevel@tonic-gate 		} else if (*ldapStat != LDAP_SUCCESS) {
15807c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
15817c478bd9Sstevel@tonic-gate 				"ldap_search(0x%x,\n\t\"%s\",\n\t %d,",
15827c478bd9Sstevel@tonic-gate 				lc->ld, NIL(ls->base), ls->scope);
15837c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
15847c478bd9Sstevel@tonic-gate 				"\t\"%s\",\n\t0x%x,\n\t%d) => %d (%s)",
15857c478bd9Sstevel@tonic-gate 				NIL(ls->filter), ls->attrs, ls->attrsonly,
15867c478bd9Sstevel@tonic-gate 				*ldapStat, ldap_err2string(stat));
15877c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
15887c478bd9Sstevel@tonic-gate 			rv = 0;
15897c478bd9Sstevel@tonic-gate 			goto cleanup;
15907c478bd9Sstevel@tonic-gate 		}
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 		numEntries = ldap_count_entries(lc->ld, msg);
15937c478bd9Sstevel@tonic-gate 		if (numEntries == 0 && *ldapStat == LDAP_SUCCESS) {
15947c478bd9Sstevel@tonic-gate 			/*
15957c478bd9Sstevel@tonic-gate 			 * This is a bit weird, but the server (or, at least,
15967c478bd9Sstevel@tonic-gate 			 * ldap_search_ext()) can sometimes return
15977c478bd9Sstevel@tonic-gate 			 * LDAP_SUCCESS and no entries when it didn't
15987c478bd9Sstevel@tonic-gate 			 * find what we were looking for. Seems it ought to
15997c478bd9Sstevel@tonic-gate 			 * return LDAP_NO_SUCH_OBJECT or some such.
16007c478bd9Sstevel@tonic-gate 			 */
16017c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
16027c478bd9Sstevel@tonic-gate 			rv = 0;
16037c478bd9Sstevel@tonic-gate 			*ldapStat = LDAP_NO_SUCH_OBJECT;
16047c478bd9Sstevel@tonic-gate 			goto cleanup;
16057c478bd9Sstevel@tonic-gate 		}
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate 		tnv = numVals + numEntries;
16087c478bd9Sstevel@tonic-gate 		if ((rv = growRuleValue(numVals, tnv, rv, rvIn)) == 0) {
16097c478bd9Sstevel@tonic-gate 			*ldapStat = LDAP_NO_MEMORY;
16107c478bd9Sstevel@tonic-gate 			goto cleanup;
16117c478bd9Sstevel@tonic-gate 		}
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 		for (m = ldap_first_entry(lc->ld, msg); m != 0;
16147c478bd9Sstevel@tonic-gate 				m = ldap_next_entry(lc->ld, m), numVals++) {
16157c478bd9Sstevel@tonic-gate 			char		*nm;
16167c478bd9Sstevel@tonic-gate 			BerElement	*ber = 0;
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 			if (numVals > tnv) {
16197c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_INFO,
16207c478bd9Sstevel@tonic-gate 				"%s: Inconsistent LDAP entry count > %d",
16217c478bd9Sstevel@tonic-gate 					myself, numEntries);
16227c478bd9Sstevel@tonic-gate 				break;
16237c478bd9Sstevel@tonic-gate 			}
16247c478bd9Sstevel@tonic-gate 
16257c478bd9Sstevel@tonic-gate 			nm = ldap_get_dn(lc->ld, m);
16267c478bd9Sstevel@tonic-gate 			if (nm == 0 || addSAttr2RuleValue("dn", nm,
16277c478bd9Sstevel@tonic-gate 					&rv[numVals])) {
16287c478bd9Sstevel@tonic-gate 				sfree(nm);
16297c478bd9Sstevel@tonic-gate 				*ldapStat = LDAP_NO_MEMORY;
16307c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, tnv);
16317c478bd9Sstevel@tonic-gate 				rv = 0;
16327c478bd9Sstevel@tonic-gate 				goto cleanup;
16337c478bd9Sstevel@tonic-gate 			}
16347c478bd9Sstevel@tonic-gate 			sfree(nm);
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 			for (nm = ldap_first_attribute(lc->ld, m, &ber);
16377c478bd9Sstevel@tonic-gate 					nm != 0;
16387c478bd9Sstevel@tonic-gate 				nm = ldap_next_attribute(lc->ld, m, ber)) {
16397c478bd9Sstevel@tonic-gate 				struct berval	**val;
16407c478bd9Sstevel@tonic-gate 				int		i, nv;
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 				val = ldap_get_values_len(lc->ld, m, nm);
16437c478bd9Sstevel@tonic-gate 				nv = (val == 0) ? 0 :
16447c478bd9Sstevel@tonic-gate 						ldap_count_values_len(val);
16457c478bd9Sstevel@tonic-gate 				for (i = 0; i < nv; i++) {
16467c478bd9Sstevel@tonic-gate 					/*
16477c478bd9Sstevel@tonic-gate 					 * Since we don't know if the value is
16487c478bd9Sstevel@tonic-gate 					 * BER-encoded or not, we mark it as a
16497c478bd9Sstevel@tonic-gate 					 * string. All is well as long as we
16507c478bd9Sstevel@tonic-gate 					 * don't insist on 'vt_ber' when
16517c478bd9Sstevel@tonic-gate 					 * interpreting.
16527c478bd9Sstevel@tonic-gate 					 */
16537c478bd9Sstevel@tonic-gate 					if (addAttr2RuleValue(vt_string, nm,
16547c478bd9Sstevel@tonic-gate 							val[i]->bv_val,
16557c478bd9Sstevel@tonic-gate 							val[i]->bv_len,
16567c478bd9Sstevel@tonic-gate 							&rv[numVals])) {
16577c478bd9Sstevel@tonic-gate 						if (ber != 0)
16587c478bd9Sstevel@tonic-gate 							ber_free(ber, 0);
16597c478bd9Sstevel@tonic-gate 						ldap_value_free_len(val);
16607c478bd9Sstevel@tonic-gate 						*ldapStat = LDAP_NO_MEMORY;
16617c478bd9Sstevel@tonic-gate 						freeRuleValue(rv, tnv);
16627c478bd9Sstevel@tonic-gate 						rv = 0;
16637c478bd9Sstevel@tonic-gate 						goto cleanup;
16647c478bd9Sstevel@tonic-gate 					}
16657c478bd9Sstevel@tonic-gate 				}
16667c478bd9Sstevel@tonic-gate 				ldap_memfree(nm);
16677c478bd9Sstevel@tonic-gate 				if (val != 0)
16687c478bd9Sstevel@tonic-gate 					ldap_value_free_len(val);
16697c478bd9Sstevel@tonic-gate 			}
16707c478bd9Sstevel@tonic-gate 			if (ber != 0)
16717c478bd9Sstevel@tonic-gate 				ber_free(ber, 0);
16727c478bd9Sstevel@tonic-gate 		}
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 		if (numVals != tnv) {
16757c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
16767c478bd9Sstevel@tonic-gate 		"%s: Inconsistent LDAP entry count, found = %d, expected %d",
16777c478bd9Sstevel@tonic-gate 				myself, numVals, tnv);
16787c478bd9Sstevel@tonic-gate 		}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 		if (doVLV) {
16817c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0,
16827c478bd9Sstevel@tonic-gate 						&retCtrls, 0);
16837c478bd9Sstevel@tonic-gate 			if (stat != LDAP_SUCCESS) {
16847c478bd9Sstevel@tonic-gate 				ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
16857c478bd9Sstevel@tonic-gate 						&stat);
16867c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
16877c478bd9Sstevel@tonic-gate 					"%s: VLV parse result error: %s",
16887c478bd9Sstevel@tonic-gate 					myself, ldap_err2string(stat));
16897c478bd9Sstevel@tonic-gate 				*ldapStat = stat;
16907c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, tnv);
16917c478bd9Sstevel@tonic-gate 				rv = 0;
16927c478bd9Sstevel@tonic-gate 				goto cleanup;
16937c478bd9Sstevel@tonic-gate 			}
16947c478bd9Sstevel@tonic-gate 			if (retCtrls != 0) {
16957c478bd9Sstevel@tonic-gate 				unsigned long	targetPosP = 0;
16967c478bd9Sstevel@tonic-gate 				unsigned long	listSize = 0;
16977c478bd9Sstevel@tonic-gate 
16987c478bd9Sstevel@tonic-gate 				stat = ldap_parse_virtuallist_control(lc->ld,
16997c478bd9Sstevel@tonic-gate 					retCtrls, &targetPosP, &listSize,
17007c478bd9Sstevel@tonic-gate 					&lprEc);
17017c478bd9Sstevel@tonic-gate 				if (stat == LDAP_SUCCESS) {
17027c478bd9Sstevel@tonic-gate 					index = targetPosP + lc->batchFrom;
17037c478bd9Sstevel@tonic-gate 					if (index >= listSize)
17047c478bd9Sstevel@tonic-gate 						done = 1;
17057c478bd9Sstevel@tonic-gate 				}
17067c478bd9Sstevel@tonic-gate 				ldap_controls_free(retCtrls);
17077c478bd9Sstevel@tonic-gate 				retCtrls = 0;
17087c478bd9Sstevel@tonic-gate 			} else {
17097c478bd9Sstevel@tonic-gate 				done = 1;
17107c478bd9Sstevel@tonic-gate 			}
17117c478bd9Sstevel@tonic-gate 		} else if (doSP) {
17127c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0,
17137c478bd9Sstevel@tonic-gate 						&retCtrls, 0);
17147c478bd9Sstevel@tonic-gate 			if (stat != LDAP_SUCCESS) {
17157c478bd9Sstevel@tonic-gate 				ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
17167c478bd9Sstevel@tonic-gate 						&stat);
17177c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
17187c478bd9Sstevel@tonic-gate 				"%s: Simple page parse result error: %s",
17197c478bd9Sstevel@tonic-gate 					myself, ldap_err2string(stat));
17207c478bd9Sstevel@tonic-gate 				*ldapStat = stat;
17217c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, tnv);
17227c478bd9Sstevel@tonic-gate 				rv = 0;
17237c478bd9Sstevel@tonic-gate 				goto cleanup;
17247c478bd9Sstevel@tonic-gate 			}
17257c478bd9Sstevel@tonic-gate 			if (retCtrls != 0) {
17267c478bd9Sstevel@tonic-gate 				unsigned int	count;
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 				if (spCookie != 0) {
17297c478bd9Sstevel@tonic-gate 					ber_bvfree(spCookie);
17307c478bd9Sstevel@tonic-gate 					spCookie = 0;
17317c478bd9Sstevel@tonic-gate 				}
17327c478bd9Sstevel@tonic-gate 				stat = ldap_parse_page_control(lc->ld,
17337c478bd9Sstevel@tonic-gate 						retCtrls, &count, &spCookie);
17347c478bd9Sstevel@tonic-gate 				if (stat == LDAP_SUCCESS) {
17357c478bd9Sstevel@tonic-gate 					if (spCookie == 0 ||
17367c478bd9Sstevel@tonic-gate 						spCookie->bv_val == 0 ||
17377c478bd9Sstevel@tonic-gate 						spCookie->bv_len == 0)
17387c478bd9Sstevel@tonic-gate 						done = 1;
17397c478bd9Sstevel@tonic-gate 				}
17407c478bd9Sstevel@tonic-gate 				ldap_controls_free(retCtrls);
17417c478bd9Sstevel@tonic-gate 				retCtrls = 0;
17427c478bd9Sstevel@tonic-gate 			} else {
17437c478bd9Sstevel@tonic-gate 				done = 1;
17447c478bd9Sstevel@tonic-gate 			}
17457c478bd9Sstevel@tonic-gate 		} else {
17467c478bd9Sstevel@tonic-gate 			done = 1;
17477c478bd9Sstevel@tonic-gate 		}
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 		(void) ldap_msgfree(msg);
17507c478bd9Sstevel@tonic-gate 		msg = 0;
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate 		/*
17537c478bd9Sstevel@tonic-gate 		 * If we're using VLV or SP, the timeout should apply
17547c478bd9Sstevel@tonic-gate 		 * to all calls as an aggregate, so we need to reduce
17557c478bd9Sstevel@tonic-gate 		 * 'tv' with the time spent on this chunk of data.
17567c478bd9Sstevel@tonic-gate 		 */
17577c478bd9Sstevel@tonic-gate 		if (!done) {
17587c478bd9Sstevel@tonic-gate 			struct timeval	tmp;
17597c478bd9Sstevel@tonic-gate 
17607c478bd9Sstevel@tonic-gate 			(void) gettimeofday(&now, 0);
17617c478bd9Sstevel@tonic-gate 			tmp = now;
17627c478bd9Sstevel@tonic-gate 			now.tv_sec -= start.tv_sec;
17637c478bd9Sstevel@tonic-gate 			now.tv_usec -= start.tv_usec;
17647c478bd9Sstevel@tonic-gate 			if (now.tv_usec < 0) {
17657c478bd9Sstevel@tonic-gate 				now.tv_usec += 1000000;
17667c478bd9Sstevel@tonic-gate 				now.tv_sec -= 1;
17677c478bd9Sstevel@tonic-gate 			}
17687c478bd9Sstevel@tonic-gate 			tv.tv_sec -= now.tv_sec;
17697c478bd9Sstevel@tonic-gate 			tv.tv_usec -= now.tv_usec;
17707c478bd9Sstevel@tonic-gate 			if (tv.tv_usec < 0) {
17717c478bd9Sstevel@tonic-gate 				tv.tv_usec += 1000000;
17727c478bd9Sstevel@tonic-gate 				tv.tv_sec -= 1;
17737c478bd9Sstevel@tonic-gate 			}
17747c478bd9Sstevel@tonic-gate 			if (tv.tv_sec < 0) {
17757c478bd9Sstevel@tonic-gate 				*ldapStat = LDAP_TIMEOUT;
17767c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, tnv);
17777c478bd9Sstevel@tonic-gate 				rv = 0;
17787c478bd9Sstevel@tonic-gate 				goto cleanup;
17797c478bd9Sstevel@tonic-gate 			}
17807c478bd9Sstevel@tonic-gate 			start = tmp;
17817c478bd9Sstevel@tonic-gate 		}
17827c478bd9Sstevel@tonic-gate 
17837c478bd9Sstevel@tonic-gate 	} while (!done);
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 	if (numValues != 0)
17867c478bd9Sstevel@tonic-gate 		*numValues = numVals;
17877c478bd9Sstevel@tonic-gate 
17887c478bd9Sstevel@tonic-gate cleanup:
17897c478bd9Sstevel@tonic-gate 	if (NULL != lc) {
17907c478bd9Sstevel@tonic-gate 		if (yp2ldap && ls->useCon == 0) {
17917c478bd9Sstevel@tonic-gate 			/* Disconnect and free the connection */
17927c478bd9Sstevel@tonic-gate 			lc->doDis++;
17937c478bd9Sstevel@tonic-gate 			lc->doDel++;
17947c478bd9Sstevel@tonic-gate 			releaseCon(lc, stat);
17957c478bd9Sstevel@tonic-gate 			releaseLC(lc);
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 		} else {
17987c478bd9Sstevel@tonic-gate 			releaseCon(lc, stat);
17997c478bd9Sstevel@tonic-gate 		}
18007c478bd9Sstevel@tonic-gate 	}
18017c478bd9Sstevel@tonic-gate 	if (msg != 0)
18027c478bd9Sstevel@tonic-gate 		(void) ldap_msgfree(msg);
18037c478bd9Sstevel@tonic-gate 	if (ctrls[0] != 0)
18047c478bd9Sstevel@tonic-gate 		ldap_control_free(ctrls[0]);
18057c478bd9Sstevel@tonic-gate 	if (ctrls[1] != 0)
18067c478bd9Sstevel@tonic-gate 		ldap_control_free(ctrls[1]);
18077c478bd9Sstevel@tonic-gate 	if (spCookie != 0)
18087c478bd9Sstevel@tonic-gate 		ber_bvfree(spCookie);
18097c478bd9Sstevel@tonic-gate 	if (sortKeyList != 0)
18107c478bd9Sstevel@tonic-gate 		ldap_free_sort_keylist(sortKeyList);
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 	return (rv);
18137c478bd9Sstevel@tonic-gate }
18147c478bd9Sstevel@tonic-gate 
18157c478bd9Sstevel@tonic-gate static void
freeLdapModEntry(LDAPMod * m)18167c478bd9Sstevel@tonic-gate freeLdapModEntry(LDAPMod *m) {
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate 	if (m == 0)
18197c478bd9Sstevel@tonic-gate 		return;
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate 	sfree(m->mod_type);
18227c478bd9Sstevel@tonic-gate 	if ((m->mod_op & LDAP_MOD_BVALUES) == 0) {
18237c478bd9Sstevel@tonic-gate 		char	**v = m->mod_values;
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate 		if (v != 0) {
18267c478bd9Sstevel@tonic-gate 			while (*v != 0) {
18277c478bd9Sstevel@tonic-gate 				sfree(*v);
18287c478bd9Sstevel@tonic-gate 				v++;
18297c478bd9Sstevel@tonic-gate 			}
18307c478bd9Sstevel@tonic-gate 			free(m->mod_values);
18317c478bd9Sstevel@tonic-gate 		}
18327c478bd9Sstevel@tonic-gate 	} else {
18337c478bd9Sstevel@tonic-gate 		struct berval	**b = m->mod_bvalues;
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 		if (b != 0) {
18367c478bd9Sstevel@tonic-gate 			while (*b != 0) {
18377c478bd9Sstevel@tonic-gate 				sfree((*b)->bv_val);
18387c478bd9Sstevel@tonic-gate 				free(*b);
18397c478bd9Sstevel@tonic-gate 				b++;
18407c478bd9Sstevel@tonic-gate 			}
18417c478bd9Sstevel@tonic-gate 			free(m->mod_bvalues);
18427c478bd9Sstevel@tonic-gate 		}
18437c478bd9Sstevel@tonic-gate 	}
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 	free(m);
18467c478bd9Sstevel@tonic-gate }
18477c478bd9Sstevel@tonic-gate 
18487c478bd9Sstevel@tonic-gate static void
freeLdapMod(LDAPMod ** mods)18497c478bd9Sstevel@tonic-gate freeLdapMod(LDAPMod **mods) {
18507c478bd9Sstevel@tonic-gate 	LDAPMod		*m, **org = mods;
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 	if (mods == 0)
18537c478bd9Sstevel@tonic-gate 		return;
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate 	while ((m = *mods) != 0) {
18567c478bd9Sstevel@tonic-gate 		freeLdapModEntry(m);
18577c478bd9Sstevel@tonic-gate 		mods++;
18587c478bd9Sstevel@tonic-gate 	}
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	free(org);
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate /*
18647c478bd9Sstevel@tonic-gate  * Convert a rule-value structure to the corresponding LDAPMod.
18657c478bd9Sstevel@tonic-gate  * If 'add' is set, attributes/values are added; object classes
18667c478bd9Sstevel@tonic-gate  * are also added. If 'add' is cleared, attributes/values are modified,
18677c478bd9Sstevel@tonic-gate  * and 'oc' controls whether or not object classes are added.
18687c478bd9Sstevel@tonic-gate  */
18697c478bd9Sstevel@tonic-gate LDAPMod **
search2LdapMod(__nis_rule_value_t * rv,int add,int oc)18707c478bd9Sstevel@tonic-gate search2LdapMod(__nis_rule_value_t *rv, int add, int oc) {
18717c478bd9Sstevel@tonic-gate 	LDAPMod		**mods;
18727c478bd9Sstevel@tonic-gate 	int		i, j, nm;
18737c478bd9Sstevel@tonic-gate 	char		*myself = "search2LdapMod";
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	if (rv == 0 || rv->numAttrs <= 0)
18767c478bd9Sstevel@tonic-gate 		return (0);
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate 	mods = am(myself, (rv->numAttrs + 1) * sizeof (mods[0]));
18797c478bd9Sstevel@tonic-gate 	if (mods == 0)
18807c478bd9Sstevel@tonic-gate 		return (0);
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate 	for (i = 0, nm = 0; i < rv->numAttrs; i++) {
18837c478bd9Sstevel@tonic-gate 		int	isOc;
18847c478bd9Sstevel@tonic-gate 		/*
18857c478bd9Sstevel@tonic-gate 		 * If we're creating an LDAPMod array for an add operation,
18867c478bd9Sstevel@tonic-gate 		 * just skip attributes that should be deleted.
18877c478bd9Sstevel@tonic-gate 		 */
18887c478bd9Sstevel@tonic-gate 		if (add && rv->attrVal[i].numVals < 0)
18897c478bd9Sstevel@tonic-gate 			continue;
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate 		/*
18927c478bd9Sstevel@tonic-gate 		 * Skip DN; it's specified separately to ldap_modify()
18937c478bd9Sstevel@tonic-gate 		 * and ldap_add(), and mustn't appear among the
18947c478bd9Sstevel@tonic-gate 		 * attributes to be modified/added.
18957c478bd9Sstevel@tonic-gate 		 */
18967c478bd9Sstevel@tonic-gate 		if (strcasecmp("dn", rv->attrName[i]) == 0)
18977c478bd9Sstevel@tonic-gate 			continue;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 		/*
19007c478bd9Sstevel@tonic-gate 		 * If modifying, and 'oc' is off, skip object class
19017c478bd9Sstevel@tonic-gate 		 * attributes.
19027c478bd9Sstevel@tonic-gate 		 */
19037c478bd9Sstevel@tonic-gate 		isOc = (strcasecmp("objectclass", rv->attrName[i]) == 0);
19047c478bd9Sstevel@tonic-gate 		if (!add && !oc && isOc)
19057c478bd9Sstevel@tonic-gate 			continue;
19067c478bd9Sstevel@tonic-gate 
19077c478bd9Sstevel@tonic-gate 		mods[nm] = am(myself, sizeof (*mods[nm]));
19087c478bd9Sstevel@tonic-gate 		if (mods[nm] == 0) {
19097c478bd9Sstevel@tonic-gate 			freeLdapMod(mods);
19107c478bd9Sstevel@tonic-gate 			return (0);
19117c478bd9Sstevel@tonic-gate 		}
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate 		/* 'mod_type' is the attribute name */
19147c478bd9Sstevel@tonic-gate 		mods[nm]->mod_type = sdup(myself, T, rv->attrName[i]);
19157c478bd9Sstevel@tonic-gate 		if (mods[nm]->mod_type == 0) {
19167c478bd9Sstevel@tonic-gate 			freeLdapMod(mods);
19177c478bd9Sstevel@tonic-gate 			return (0);
19187c478bd9Sstevel@tonic-gate 		}
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 		/*
19217c478bd9Sstevel@tonic-gate 		 * numVals < 0 means attribute and all values should
19227c478bd9Sstevel@tonic-gate 		 * be deleted.
19237c478bd9Sstevel@tonic-gate 		 */
19247c478bd9Sstevel@tonic-gate 		if (rv->attrVal[i].numVals < 0) {
19257c478bd9Sstevel@tonic-gate 			mods[nm]->mod_op = LDAP_MOD_DELETE;
19267c478bd9Sstevel@tonic-gate 			mods[nm]->mod_values = 0;
19277c478bd9Sstevel@tonic-gate 			nm++;
19287c478bd9Sstevel@tonic-gate 			continue;
19297c478bd9Sstevel@tonic-gate 		}
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 		/* objectClass attributes always added */
19327c478bd9Sstevel@tonic-gate 		mods[nm]->mod_op = (add) ? 0 : ((isOc) ? 0 : LDAP_MOD_REPLACE);
19337c478bd9Sstevel@tonic-gate 
19347c478bd9Sstevel@tonic-gate 		if (rv->attrVal[i].type == vt_string) {
19357c478bd9Sstevel@tonic-gate 			/*
19367c478bd9Sstevel@tonic-gate 			 * mods[]->mod_values is a NULL-terminated array
19377c478bd9Sstevel@tonic-gate 			 * of (char *)'s.
19387c478bd9Sstevel@tonic-gate 			 */
19397c478bd9Sstevel@tonic-gate 			mods[nm]->mod_values = am(myself,
19407c478bd9Sstevel@tonic-gate 					(rv->attrVal[i].numVals + 1) *
19417c478bd9Sstevel@tonic-gate 					sizeof (mods[nm]->mod_values[0]));
19427c478bd9Sstevel@tonic-gate 			if (mods[nm]->mod_values == 0) {
19437c478bd9Sstevel@tonic-gate 				freeLdapMod(mods);
19447c478bd9Sstevel@tonic-gate 				return (0);
19457c478bd9Sstevel@tonic-gate 			}
19467c478bd9Sstevel@tonic-gate 			for (j = 0; j < rv->attrVal[i].numVals; j++) {
19477c478bd9Sstevel@tonic-gate 				/*
19487c478bd9Sstevel@tonic-gate 				 * Just in case the string isn't NUL
19497c478bd9Sstevel@tonic-gate 				 * terminated, add one byte to the
19507c478bd9Sstevel@tonic-gate 				 * allocated length; am() will initialize
19517c478bd9Sstevel@tonic-gate 				 * the buffer to zero.
19527c478bd9Sstevel@tonic-gate 				 */
19537c478bd9Sstevel@tonic-gate 				mods[nm]->mod_values[j] = am(myself,
19547c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].length + 1);
19557c478bd9Sstevel@tonic-gate 				if (mods[nm]->mod_values[j] == 0) {
19567c478bd9Sstevel@tonic-gate 					freeLdapMod(mods);
19577c478bd9Sstevel@tonic-gate 					return (0);
19587c478bd9Sstevel@tonic-gate 				}
19597c478bd9Sstevel@tonic-gate 				memcpy(mods[nm]->mod_values[j],
19607c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].value,
19617c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].length);
19627c478bd9Sstevel@tonic-gate 			}
19637c478bd9Sstevel@tonic-gate 		} else {
19647c478bd9Sstevel@tonic-gate 			mods[nm]->mod_op |= LDAP_MOD_BVALUES;
19657c478bd9Sstevel@tonic-gate 			mods[nm]->mod_bvalues = am(myself,
19667c478bd9Sstevel@tonic-gate 					(rv->attrVal[i].numVals+1) *
19677c478bd9Sstevel@tonic-gate 					sizeof (mods[nm]->mod_bvalues[0]));
19687c478bd9Sstevel@tonic-gate 			if (mods[nm]->mod_bvalues == 0) {
19697c478bd9Sstevel@tonic-gate 				freeLdapMod(mods);
19707c478bd9Sstevel@tonic-gate 				return (0);
19717c478bd9Sstevel@tonic-gate 			}
19727c478bd9Sstevel@tonic-gate 			for (j = 0; j < rv->attrVal[i].numVals; j++) {
19737c478bd9Sstevel@tonic-gate 				mods[nm]->mod_bvalues[j] = am(myself,
19747c478bd9Sstevel@tonic-gate 					sizeof (*mods[nm]->mod_bvalues[j]));
19757c478bd9Sstevel@tonic-gate 				if (mods[nm]->mod_bvalues[j] == 0) {
19767c478bd9Sstevel@tonic-gate 					freeLdapMod(mods);
19777c478bd9Sstevel@tonic-gate 					return (0);
19787c478bd9Sstevel@tonic-gate 				}
19797c478bd9Sstevel@tonic-gate 				mods[nm]->mod_bvalues[j]->bv_val = am(myself,
19807c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].length);
19817c478bd9Sstevel@tonic-gate 				if (mods[nm]->mod_bvalues[j]->bv_val == 0) {
19827c478bd9Sstevel@tonic-gate 					freeLdapMod(mods);
19837c478bd9Sstevel@tonic-gate 					return (0);
19847c478bd9Sstevel@tonic-gate 				}
19857c478bd9Sstevel@tonic-gate 				mods[nm]->mod_bvalues[j]->bv_len =
19867c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].length;
19877c478bd9Sstevel@tonic-gate 				memcpy(mods[nm]->mod_bvalues[j]->bv_val,
19887c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].value,
19897c478bd9Sstevel@tonic-gate 					mods[nm]->mod_bvalues[j]->bv_len);
19907c478bd9Sstevel@tonic-gate 			}
19917c478bd9Sstevel@tonic-gate 		}
19927c478bd9Sstevel@tonic-gate 		nm++;
19937c478bd9Sstevel@tonic-gate 	}
19947c478bd9Sstevel@tonic-gate 
19957c478bd9Sstevel@tonic-gate 	return (mods);
19967c478bd9Sstevel@tonic-gate }
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate /*
19997c478bd9Sstevel@tonic-gate  * Remove 'value' from 'val'. If value==0, remove the entire
20007c478bd9Sstevel@tonic-gate  * __nis_single_value_t array from 'val'.
20017c478bd9Sstevel@tonic-gate  */
20027c478bd9Sstevel@tonic-gate static void
removeSingleValue(__nis_value_t * val,void * value,int length)20037c478bd9Sstevel@tonic-gate removeSingleValue(__nis_value_t *val, void *value, int length) {
20047c478bd9Sstevel@tonic-gate 	int	i;
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	if (val == 0)
20077c478bd9Sstevel@tonic-gate 		return;
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate 	if (value == 0) {
20107c478bd9Sstevel@tonic-gate 		for (i = 0; i < val->numVals; i++) {
20117c478bd9Sstevel@tonic-gate 			sfree(val->val[i].value);
20127c478bd9Sstevel@tonic-gate 		}
20137c478bd9Sstevel@tonic-gate 		sfree(val->val);
20147c478bd9Sstevel@tonic-gate 		val->val = 0;
20157c478bd9Sstevel@tonic-gate 		val->numVals = 0;
20167c478bd9Sstevel@tonic-gate 		return;
20177c478bd9Sstevel@tonic-gate 	}
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 	for (i = 0; i < val->numVals; i++) {
20207c478bd9Sstevel@tonic-gate 		if (val->val[i].value == 0 || (val->val[i].length != length))
20217c478bd9Sstevel@tonic-gate 			continue;
20227c478bd9Sstevel@tonic-gate 		if (memcmp(val->val[i].value, value, length) != 0)
20237c478bd9Sstevel@tonic-gate 			continue;
20247c478bd9Sstevel@tonic-gate 		sfree(val->val[i].value);
20257c478bd9Sstevel@tonic-gate 		if (i != (val->numVals - 1)) {
20267c478bd9Sstevel@tonic-gate 			(void) memmove(&val->val[i], &val->val[i+1],
20277c478bd9Sstevel@tonic-gate 				(val->numVals - 1 - i) * sizeof (val->val[0]));
20287c478bd9Sstevel@tonic-gate 		}
20297c478bd9Sstevel@tonic-gate 		val->numVals -= 1;
20307c478bd9Sstevel@tonic-gate 		break;
20317c478bd9Sstevel@tonic-gate 	}
20327c478bd9Sstevel@tonic-gate }
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate /*
20357c478bd9Sstevel@tonic-gate  * Helper function for LdapModify
20367c478bd9Sstevel@tonic-gate  * When a modify operation fails with an object class violation,
20377c478bd9Sstevel@tonic-gate  * the most probable reason is that the attributes we're modifying are new,
20387c478bd9Sstevel@tonic-gate  * and the needed object class are not present. So, try the modify again,
20397c478bd9Sstevel@tonic-gate  * but add the object classes this time.
20407c478bd9Sstevel@tonic-gate  */
20417c478bd9Sstevel@tonic-gate 
20427c478bd9Sstevel@tonic-gate static int
ldapModifyObjectClass(__nis_ldap_conn_t ** lc,char * dn,__nis_rule_value_t * rvIn,char * objClassAttrs)20437c478bd9Sstevel@tonic-gate ldapModifyObjectClass(__nis_ldap_conn_t **lc, char *dn,
20447c478bd9Sstevel@tonic-gate 		__nis_rule_value_t *rvIn, char *objClassAttrs)
20457c478bd9Sstevel@tonic-gate {
20467c478bd9Sstevel@tonic-gate 	LDAPMod			**mods = 0;
20477c478bd9Sstevel@tonic-gate 	int			msgid;
20487c478bd9Sstevel@tonic-gate 	int			lderr;
20497c478bd9Sstevel@tonic-gate 	struct timeval		tv;
20507c478bd9Sstevel@tonic-gate 	int			stat;
20517c478bd9Sstevel@tonic-gate 	LDAPMessage		*msg = 0;
20527c478bd9Sstevel@tonic-gate 	char			**referralsp = NULL;
20537c478bd9Sstevel@tonic-gate 	__nis_rule_value_t	*rv, *rvldap;
20547c478bd9Sstevel@tonic-gate 	__nis_ldap_search_t	*ls;
20557c478bd9Sstevel@tonic-gate 	int			i, ocrv, ocrvldap, nv;
20567c478bd9Sstevel@tonic-gate 	char			*oc[2] = { "objectClass", 0};
20577c478bd9Sstevel@tonic-gate 	char			*myself = "ldapModifyObjectClass";
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	rv = initRuleValue(1, rvIn);
20607c478bd9Sstevel@tonic-gate 	if (rv == 0)
20617c478bd9Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 	delAttrFromRuleValue(rv, "objectClass");
20647c478bd9Sstevel@tonic-gate 	rv = addObjectClasses(rv, objClassAttrs);
20657c478bd9Sstevel@tonic-gate 	if (rv == 0) {
20667c478bd9Sstevel@tonic-gate 		stat = LDAP_OPERATIONS_ERROR;
20677c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_WARNING,
20687c478bd9Sstevel@tonic-gate 		    "%s: addObjectClasses failed for %s",
20697c478bd9Sstevel@tonic-gate 		    myself, NIL(dn));
20707c478bd9Sstevel@tonic-gate 		goto cleanup;
20717c478bd9Sstevel@tonic-gate 	}
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 	/*
20747c478bd9Sstevel@tonic-gate 	 * Before adding the object classes whole-sale, try retrieving
20757c478bd9Sstevel@tonic-gate 	 * the entry specified by the 'dn'. If it exists, we filter out
20767c478bd9Sstevel@tonic-gate 	 * those object classes that already are present in LDAP from our
20777c478bd9Sstevel@tonic-gate 	 * update.
20787c478bd9Sstevel@tonic-gate 	 */
20797c478bd9Sstevel@tonic-gate 	ls = buildLdapSearch(dn, LDAP_SCOPE_BASE, 0, 0, "objectClass=*",
20807c478bd9Sstevel@tonic-gate 	    oc, 0, 1);
20817c478bd9Sstevel@tonic-gate 	if (ls == 0) {
20827c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
20837c478bd9Sstevel@tonic-gate 		    "%s: Unable to build DN search for \"%s\"",
20847c478bd9Sstevel@tonic-gate 		    myself, NIL(dn));
20857c478bd9Sstevel@tonic-gate 		/* Fall through to try just adding the object classes */
20867c478bd9Sstevel@tonic-gate 		goto addObjectClasses;
20877c478bd9Sstevel@tonic-gate 	}
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 	nv = 0;
20907c478bd9Sstevel@tonic-gate 	rvldap = ldapSearch(ls, &nv, 0, &lderr);
20917c478bd9Sstevel@tonic-gate 	freeLdapSearch(ls);
20927c478bd9Sstevel@tonic-gate 	if (rvldap == 0) {
20937c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
20947c478bd9Sstevel@tonic-gate 		    "%s: No data for DN search (\"%s\"); LDAP status %d",
20957c478bd9Sstevel@tonic-gate 		    myself, NIL(dn), lderr);
20967c478bd9Sstevel@tonic-gate 		/* Fall through to try just adding the object classes */
20977c478bd9Sstevel@tonic-gate 		goto addObjectClasses;
20987c478bd9Sstevel@tonic-gate 	}
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 	/*
21017c478bd9Sstevel@tonic-gate 	 * Find the indices of the 'objectClass' attribute
21027c478bd9Sstevel@tonic-gate 	 * in 'rvldap' and 'rv'.
21037c478bd9Sstevel@tonic-gate 	 */
21047c478bd9Sstevel@tonic-gate 	for (i = 0, ocrvldap = -1; i < rvldap->numAttrs; i++) {
21057c478bd9Sstevel@tonic-gate 		if (rvldap->attrName[i] != 0 &&
21067c478bd9Sstevel@tonic-gate 		    strcasecmp("objectClass", rvldap->attrName[i]) == 0) {
21077c478bd9Sstevel@tonic-gate 			ocrvldap = i;
21087c478bd9Sstevel@tonic-gate 			break;
21097c478bd9Sstevel@tonic-gate 		}
21107c478bd9Sstevel@tonic-gate 	}
21117c478bd9Sstevel@tonic-gate 	for (i = 0, ocrv = -1; i < rv->numAttrs; i++) {
21127c478bd9Sstevel@tonic-gate 		if (rv->attrName[i] != 0 &&
21137c478bd9Sstevel@tonic-gate 		    strcasecmp("objectClass", rv->attrName[i]) == 0) {
21147c478bd9Sstevel@tonic-gate 			ocrv = i;
21157c478bd9Sstevel@tonic-gate 			break;
21167c478bd9Sstevel@tonic-gate 		}
21177c478bd9Sstevel@tonic-gate 	}
21187c478bd9Sstevel@tonic-gate 
21197c478bd9Sstevel@tonic-gate 	/*
21207c478bd9Sstevel@tonic-gate 	 * Remove those object classes that already exist
21217c478bd9Sstevel@tonic-gate 	 * in LDAP (i.e., in 'rvldap') from 'rv'.
21227c478bd9Sstevel@tonic-gate 	 */
21237c478bd9Sstevel@tonic-gate 	if (ocrv >= 0 && ocrvldap >= 0) {
21247c478bd9Sstevel@tonic-gate 		for (i = 0; i < rvldap->attrVal[ocrvldap].numVals; i++) {
21257c478bd9Sstevel@tonic-gate 			removeSingleValue(&rv->attrVal[ocrv],
21267c478bd9Sstevel@tonic-gate 			    rvldap->attrVal[ocrvldap].val[i].value,
21277c478bd9Sstevel@tonic-gate 			    rvldap->attrVal[ocrvldap].val[i].length);
21287c478bd9Sstevel@tonic-gate 		}
21297c478bd9Sstevel@tonic-gate 		/*
21307c478bd9Sstevel@tonic-gate 		 * If no 'objectClass' values left in 'rv', delete
21317c478bd9Sstevel@tonic-gate 		 * 'objectClass' from 'rv'.
21327c478bd9Sstevel@tonic-gate 		 */
21337c478bd9Sstevel@tonic-gate 		if (rv->attrVal[ocrv].numVals == 0)
21347c478bd9Sstevel@tonic-gate 			delAttrFromRuleValue(rv, "objectClass");
21357c478bd9Sstevel@tonic-gate 	}
21367c478bd9Sstevel@tonic-gate 
21377c478bd9Sstevel@tonic-gate 	/*
21387c478bd9Sstevel@tonic-gate 	 * 'rv' now contains the update we want to make, with just the
21397c478bd9Sstevel@tonic-gate 	 * object class(es) that need to be added. Fall through to the
21407c478bd9Sstevel@tonic-gate 	 * actual LDAP modify operation.
21417c478bd9Sstevel@tonic-gate 	 */
21427c478bd9Sstevel@tonic-gate 	freeRuleValue(rvldap, 1);
21437c478bd9Sstevel@tonic-gate 
21447c478bd9Sstevel@tonic-gate addObjectClasses:
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	mods = search2LdapMod(rv, 0, 1);
21477c478bd9Sstevel@tonic-gate 	if (mods == 0) {
21487c478bd9Sstevel@tonic-gate 		stat = LDAP_OPERATIONS_ERROR;
21497c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_WARNING,
21507c478bd9Sstevel@tonic-gate 	"%s: Unable to create LDAP modify changes with object classes for %s",
21517c478bd9Sstevel@tonic-gate 		    myself, NIL(dn));
21527c478bd9Sstevel@tonic-gate 		goto cleanup;
21537c478bd9Sstevel@tonic-gate 	}
21547c478bd9Sstevel@tonic-gate 	msgid = ldap_modify((*lc)->ld, dn, mods);
21557c478bd9Sstevel@tonic-gate 	if (msgid != -1) {
21567c478bd9Sstevel@tonic-gate 		tv = (*lc)->modifyTimeout;
21577c478bd9Sstevel@tonic-gate 		stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg);
21587c478bd9Sstevel@tonic-gate 		if (stat == 0) {
21597c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
21607c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
21617c478bd9Sstevel@tonic-gate 			(void) ldap_get_option((*lc)->ld,
21627c478bd9Sstevel@tonic-gate 			    LDAP_OPT_ERROR_NUMBER, &stat);
21637c478bd9Sstevel@tonic-gate 		} else {
21647c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result((*lc)->ld, msg, &lderr, NULL,
21657c478bd9Sstevel@tonic-gate 			    NULL, &referralsp, NULL, 0);
21667c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
21677c478bd9Sstevel@tonic-gate 				stat = lderr;
21687c478bd9Sstevel@tonic-gate 			stat = ldap_result2error((*lc)->ld, msg, 0);
21697c478bd9Sstevel@tonic-gate 		}
21707c478bd9Sstevel@tonic-gate 	} else {
21717c478bd9Sstevel@tonic-gate 		(void) ldap_get_option((*lc)->ld, LDAP_OPT_ERROR_NUMBER,
21727c478bd9Sstevel@tonic-gate 		    &stat);
21737c478bd9Sstevel@tonic-gate 	}
21747c478bd9Sstevel@tonic-gate 	if (proxyInfo.follow_referral == follow &&
21757c478bd9Sstevel@tonic-gate 	    stat == LDAP_REFERRAL && referralsp != NULL) {
21767c478bd9Sstevel@tonic-gate 		releaseCon(*lc, stat);
21777c478bd9Sstevel@tonic-gate 		if (msg != NULL)
21787c478bd9Sstevel@tonic-gate 			(void) ldap_msgfree(msg);
21797c478bd9Sstevel@tonic-gate 		msg = NULL;
21807c478bd9Sstevel@tonic-gate 		*lc = findReferralCon(referralsp, &stat);
21817c478bd9Sstevel@tonic-gate 		ldap_value_free(referralsp);
21827c478bd9Sstevel@tonic-gate 		referralsp = NULL;
21837c478bd9Sstevel@tonic-gate 		if (*lc == NULL)
21847c478bd9Sstevel@tonic-gate 			goto cleanup;
21857c478bd9Sstevel@tonic-gate 		msgid = ldap_modify((*lc)->ld, dn, mods);
21867c478bd9Sstevel@tonic-gate 		if (msgid == -1) {
21877c478bd9Sstevel@tonic-gate 			(void) ldap_get_option((*lc)->ld,
21887c478bd9Sstevel@tonic-gate 			    LDAP_OPT_ERROR_NUMBER, &stat);
21897c478bd9Sstevel@tonic-gate 			goto cleanup;
21907c478bd9Sstevel@tonic-gate 		}
21917c478bd9Sstevel@tonic-gate 		stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg);
21927c478bd9Sstevel@tonic-gate 		if (stat == 0) {
21937c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
21947c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
21957c478bd9Sstevel@tonic-gate 			(void) ldap_get_option((*lc)->ld,
21967c478bd9Sstevel@tonic-gate 			    LDAP_OPT_ERROR_NUMBER, &stat);
21977c478bd9Sstevel@tonic-gate 		} else {
21987c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result((*lc)->ld, msg, &lderr,
21997c478bd9Sstevel@tonic-gate 			    NULL, NULL, NULL, NULL, 0);
22007c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
22017c478bd9Sstevel@tonic-gate 				stat = lderr;
22027c478bd9Sstevel@tonic-gate 		}
22037c478bd9Sstevel@tonic-gate 	}
22047c478bd9Sstevel@tonic-gate cleanup:
22057c478bd9Sstevel@tonic-gate 	if (mods != 0)
22067c478bd9Sstevel@tonic-gate 		freeLdapMod(mods);
22077c478bd9Sstevel@tonic-gate 	freeRuleValue(rv, 1);
22087c478bd9Sstevel@tonic-gate 	return (stat);
22097c478bd9Sstevel@tonic-gate }
22107c478bd9Sstevel@tonic-gate 
22117c478bd9Sstevel@tonic-gate /*
22127c478bd9Sstevel@tonic-gate  * Modify the specified 'dn' per the attribute names/values in 'rv'.
22137c478bd9Sstevel@tonic-gate  * If 'rv' is NULL, we attempt to delete the entire entry.
22147c478bd9Sstevel@tonic-gate  *
22157c478bd9Sstevel@tonic-gate  * The 'objClassAttrs' parameter is needed if the entry must be added
22167c478bd9Sstevel@tonic-gate  * (i.e., created), or a modify fails with an object class violation.
22177c478bd9Sstevel@tonic-gate  *
22187c478bd9Sstevel@tonic-gate  * If 'addFirst' is set, we try an add before a modify; modify before
22197c478bd9Sstevel@tonic-gate  * add otherwise (ignored if we're deleting).
22207c478bd9Sstevel@tonic-gate  */
22217c478bd9Sstevel@tonic-gate int
ldapModify(char * dn,__nis_rule_value_t * rv,char * objClassAttrs,int addFirst)22227c478bd9Sstevel@tonic-gate ldapModify(char *dn, __nis_rule_value_t *rv, char *objClassAttrs,
22237c478bd9Sstevel@tonic-gate 		int addFirst) {
22247c478bd9Sstevel@tonic-gate 	int			stat, add = 0;
22257c478bd9Sstevel@tonic-gate 	LDAPMod			**mods = 0;
22267c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc;
22277c478bd9Sstevel@tonic-gate 	struct timeval		tv;
22287c478bd9Sstevel@tonic-gate 	LDAPMessage		*msg = 0;
22297c478bd9Sstevel@tonic-gate 	int			msgid;
22307c478bd9Sstevel@tonic-gate 	int			lderr;
22317c478bd9Sstevel@tonic-gate 	char			**referralsp = NULL;
22327c478bd9Sstevel@tonic-gate 	bool_t			delete = FALSE;
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 	if (dn == 0)
22357c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 	if ((lc = findCon(&stat)) == 0)
22387c478bd9Sstevel@tonic-gate 		return (stat);
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 	if (rv == 0) {
22417c478bd9Sstevel@tonic-gate 		delete = TRUE;
22427c478bd9Sstevel@tonic-gate 		/* Simple case: if rv == 0, try to delete the entire entry */
22437c478bd9Sstevel@tonic-gate 		msgid = ldap_delete(lc->ld, dn);
22447c478bd9Sstevel@tonic-gate 		if (msgid == -1) {
22457c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
22467c478bd9Sstevel@tonic-gate 						&stat);
22477c478bd9Sstevel@tonic-gate 			goto cleanup;
22487c478bd9Sstevel@tonic-gate 		}
22497c478bd9Sstevel@tonic-gate 		tv = lc->deleteTimeout;
22507c478bd9Sstevel@tonic-gate 		stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 		if (stat == 0) {
22537c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
22547c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
22557c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
22567c478bd9Sstevel@tonic-gate 						&stat);
22577c478bd9Sstevel@tonic-gate 		} else {
22587c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
22597c478bd9Sstevel@tonic-gate 				NULL, &referralsp, NULL, 0);
22607c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
22617c478bd9Sstevel@tonic-gate 				stat = lderr;
22627c478bd9Sstevel@tonic-gate 		}
22637c478bd9Sstevel@tonic-gate 		if (proxyInfo.follow_referral == follow &&
22647c478bd9Sstevel@tonic-gate 				stat == LDAP_REFERRAL && referralsp != NULL) {
22657c478bd9Sstevel@tonic-gate 			releaseCon(lc, stat);
22667c478bd9Sstevel@tonic-gate 			if (msg != NULL)
22677c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(msg);
22687c478bd9Sstevel@tonic-gate 			msg = NULL;
22697c478bd9Sstevel@tonic-gate 			lc = findReferralCon(referralsp, &stat);
22707c478bd9Sstevel@tonic-gate 			ldap_value_free(referralsp);
22717c478bd9Sstevel@tonic-gate 			if (lc == NULL)
22727c478bd9Sstevel@tonic-gate 				goto cleanup;
22737c478bd9Sstevel@tonic-gate 			msgid = ldap_delete(lc->ld, dn);
22747c478bd9Sstevel@tonic-gate 			if (msgid == -1) {
22757c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(lc->ld,
22767c478bd9Sstevel@tonic-gate 					LDAP_OPT_ERROR_NUMBER, &stat);
22777c478bd9Sstevel@tonic-gate 				goto cleanup;
22787c478bd9Sstevel@tonic-gate 			}
22797c478bd9Sstevel@tonic-gate 			stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
22807c478bd9Sstevel@tonic-gate 			if (stat == 0) {
22817c478bd9Sstevel@tonic-gate 				stat = LDAP_TIMEOUT;
22827c478bd9Sstevel@tonic-gate 			} else if (stat == -1) {
22837c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(lc->ld,
22847c478bd9Sstevel@tonic-gate 					LDAP_OPT_ERROR_NUMBER, &stat);
22857c478bd9Sstevel@tonic-gate 			} else {
22867c478bd9Sstevel@tonic-gate 				stat = ldap_parse_result(lc->ld, msg, &lderr,
22877c478bd9Sstevel@tonic-gate 					NULL, NULL, NULL, NULL, 0);
22887c478bd9Sstevel@tonic-gate 				if (stat == LDAP_SUCCESS)
22897c478bd9Sstevel@tonic-gate 					stat = lderr;
22907c478bd9Sstevel@tonic-gate 			}
22917c478bd9Sstevel@tonic-gate 		}
22927c478bd9Sstevel@tonic-gate 		/* No such object means someone else has done our job */
22937c478bd9Sstevel@tonic-gate 		if (stat == LDAP_NO_SUCH_OBJECT)
22947c478bd9Sstevel@tonic-gate 			stat = LDAP_SUCCESS;
22957c478bd9Sstevel@tonic-gate 	} else {
22967c478bd9Sstevel@tonic-gate 		if (addFirst) {
22977c478bd9Sstevel@tonic-gate 			stat = ldapAdd(dn, rv, objClassAttrs, lc);
22987c478bd9Sstevel@tonic-gate 			lc = NULL;
22997c478bd9Sstevel@tonic-gate 			if (stat != LDAP_ALREADY_EXISTS)
23007c478bd9Sstevel@tonic-gate 				goto cleanup;
23017c478bd9Sstevel@tonic-gate 			if ((lc = findCon(&stat)) == 0)
23027c478bd9Sstevel@tonic-gate 				return (stat);
23037c478bd9Sstevel@tonic-gate 		}
23047c478bd9Sstevel@tonic-gate 
23057c478bd9Sstevel@tonic-gate 		/*
23067c478bd9Sstevel@tonic-gate 		 * First try the modify without specifying object classes
23077c478bd9Sstevel@tonic-gate 		 * (i.e., assume they're already present).
23087c478bd9Sstevel@tonic-gate 		 */
23097c478bd9Sstevel@tonic-gate 		mods = search2LdapMod(rv, 0, 0);
23107c478bd9Sstevel@tonic-gate 		if (mods == 0) {
23117c478bd9Sstevel@tonic-gate 			stat = LDAP_PARAM_ERROR;
23127c478bd9Sstevel@tonic-gate 			goto cleanup;
23137c478bd9Sstevel@tonic-gate 		}
23147c478bd9Sstevel@tonic-gate 
23157c478bd9Sstevel@tonic-gate 		msgid = ldap_modify(lc->ld, dn, mods);
23167c478bd9Sstevel@tonic-gate 		if (msgid == -1) {
23177c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
23187c478bd9Sstevel@tonic-gate 						&stat);
23197c478bd9Sstevel@tonic-gate 			goto cleanup;
23207c478bd9Sstevel@tonic-gate 		}
23217c478bd9Sstevel@tonic-gate 		tv = lc->modifyTimeout;
23227c478bd9Sstevel@tonic-gate 		stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
23237c478bd9Sstevel@tonic-gate 		if (stat == 0) {
23247c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
23257c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
23267c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
23277c478bd9Sstevel@tonic-gate 						&stat);
23287c478bd9Sstevel@tonic-gate 		} else {
23297c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
23307c478bd9Sstevel@tonic-gate 				NULL, &referralsp, NULL, 0);
23317c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
23327c478bd9Sstevel@tonic-gate 				stat = lderr;
23337c478bd9Sstevel@tonic-gate 		}
23347c478bd9Sstevel@tonic-gate 		if (proxyInfo.follow_referral == follow &&
23357c478bd9Sstevel@tonic-gate 				stat == LDAP_REFERRAL && referralsp != NULL) {
23367c478bd9Sstevel@tonic-gate 			releaseCon(lc, stat);
23377c478bd9Sstevel@tonic-gate 			if (msg != NULL)
23387c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(msg);
23397c478bd9Sstevel@tonic-gate 			msg = NULL;
23407c478bd9Sstevel@tonic-gate 			lc = findReferralCon(referralsp, &stat);
23417c478bd9Sstevel@tonic-gate 			ldap_value_free(referralsp);
23427c478bd9Sstevel@tonic-gate 			referralsp = NULL;
23437c478bd9Sstevel@tonic-gate 			if (lc == NULL)
23447c478bd9Sstevel@tonic-gate 				goto cleanup;
23457c478bd9Sstevel@tonic-gate 			msgid = ldap_modify(lc->ld, dn, mods);
23467c478bd9Sstevel@tonic-gate 			if (msgid == -1) {
23477c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(lc->ld,
23487c478bd9Sstevel@tonic-gate 					LDAP_OPT_ERROR_NUMBER, &stat);
23497c478bd9Sstevel@tonic-gate 				goto cleanup;
23507c478bd9Sstevel@tonic-gate 			}
23517c478bd9Sstevel@tonic-gate 			stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
23527c478bd9Sstevel@tonic-gate 			if (stat == 0) {
23537c478bd9Sstevel@tonic-gate 				stat = LDAP_TIMEOUT;
23547c478bd9Sstevel@tonic-gate 			} else if (stat == -1) {
23557c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(lc->ld,
23567c478bd9Sstevel@tonic-gate 					LDAP_OPT_ERROR_NUMBER, &stat);
23577c478bd9Sstevel@tonic-gate 			} else {
23587c478bd9Sstevel@tonic-gate 				stat = ldap_parse_result(lc->ld, msg, &lderr,
23597c478bd9Sstevel@tonic-gate 					NULL, NULL, NULL, NULL, 0);
23607c478bd9Sstevel@tonic-gate 				if (stat == LDAP_SUCCESS)
23617c478bd9Sstevel@tonic-gate 					stat = lderr;
23627c478bd9Sstevel@tonic-gate 			}
23637c478bd9Sstevel@tonic-gate 		}
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate 		/*
23667c478bd9Sstevel@tonic-gate 		 * If the modify failed with an object class violation,
23677c478bd9Sstevel@tonic-gate 		 * the most probable reason is that at least on of the
23687c478bd9Sstevel@tonic-gate 		 * attributes we're modifying didn't exist before, and
23697c478bd9Sstevel@tonic-gate 		 * neither did its object class. So, try the modify again,
23707c478bd9Sstevel@tonic-gate 		 * but add the object classes this time.
23717c478bd9Sstevel@tonic-gate 		 */
23727c478bd9Sstevel@tonic-gate 		if (stat == LDAP_OBJECT_CLASS_VIOLATION &&
23737c478bd9Sstevel@tonic-gate 				objClassAttrs != 0) {
23747c478bd9Sstevel@tonic-gate 			freeLdapMod(mods);
23757c478bd9Sstevel@tonic-gate 			mods = 0;
23767c478bd9Sstevel@tonic-gate 			stat = ldapModifyObjectClass(&lc, dn, rv,
23777c478bd9Sstevel@tonic-gate 				objClassAttrs);
23787c478bd9Sstevel@tonic-gate 		}
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 		if (stat == LDAP_NO_SUCH_ATTRIBUTE) {
23817c478bd9Sstevel@tonic-gate 			/*
23827c478bd9Sstevel@tonic-gate 			 * If there was at least one attribute delete, then
23837c478bd9Sstevel@tonic-gate 			 * the cause of this error could be that said attribute
23847c478bd9Sstevel@tonic-gate 			 * didn't exist in LDAP. So, do things the slow way,
23857c478bd9Sstevel@tonic-gate 			 * and try to delete one attribute at a time.
23867c478bd9Sstevel@tonic-gate 			 */
23877c478bd9Sstevel@tonic-gate 			int			d, numDelete, st;
23887c478bd9Sstevel@tonic-gate 			__nis_rule_value_t	*rvt;
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate 			for (d = 0, numDelete = 0; d < rv->numAttrs; d++) {
23917c478bd9Sstevel@tonic-gate 				if (rv->attrVal[d].numVals < 0)
23927c478bd9Sstevel@tonic-gate 					numDelete++;
23937c478bd9Sstevel@tonic-gate 			}
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate 			/* If there's just one, we've already tried */
23967c478bd9Sstevel@tonic-gate 			if (numDelete <= 1)
23977c478bd9Sstevel@tonic-gate 				goto cleanup;
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 			/* Make a copy of the rule value */
24007c478bd9Sstevel@tonic-gate 			rvt = initRuleValue(1, rv);
24017c478bd9Sstevel@tonic-gate 			if (rvt == 0)
24027c478bd9Sstevel@tonic-gate 				goto cleanup;
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 			/*
24057c478bd9Sstevel@tonic-gate 			 * Remove all delete attributes from the tmp
24067c478bd9Sstevel@tonic-gate 			 * rule value.
24077c478bd9Sstevel@tonic-gate 			 */
24087c478bd9Sstevel@tonic-gate 			for (d = 0; d < rv->numAttrs; d++) {
24097c478bd9Sstevel@tonic-gate 				if (rv->attrVal[d].numVals < 0) {
24107c478bd9Sstevel@tonic-gate 					delAttrFromRuleValue(rvt,
24117c478bd9Sstevel@tonic-gate 						rv->attrName[d]);
24127c478bd9Sstevel@tonic-gate 				}
24137c478bd9Sstevel@tonic-gate 			}
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate 			/*
24167c478bd9Sstevel@tonic-gate 			 * Now put the attributes back in one by one, and
24177c478bd9Sstevel@tonic-gate 			 * invoke ourselves.
24187c478bd9Sstevel@tonic-gate 			 */
24197c478bd9Sstevel@tonic-gate 			for (d = 0; d < rv->numAttrs; d++) {
24207c478bd9Sstevel@tonic-gate 				if (rv->attrVal[d].numVals >= 0)
24217c478bd9Sstevel@tonic-gate 					continue;
24227c478bd9Sstevel@tonic-gate 				st = addAttr2RuleValue(rv->attrVal[d].type,
24237c478bd9Sstevel@tonic-gate 					rv->attrName[d], 0, 0, rvt);
24247c478bd9Sstevel@tonic-gate 				if (st != 0) {
24257c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOMEM, LOG_ERR,
24267c478bd9Sstevel@tonic-gate 					"%s: Error deleting \"%s\" for \"%s\"",
24277c478bd9Sstevel@tonic-gate 						NIL(rv->attrName[d]), NIL(dn));
24287c478bd9Sstevel@tonic-gate 					stat = LDAP_NO_MEMORY;
24297c478bd9Sstevel@tonic-gate 					freeRuleValue(rvt, 1);
24307c478bd9Sstevel@tonic-gate 					goto cleanup;
24317c478bd9Sstevel@tonic-gate 				}
24327c478bd9Sstevel@tonic-gate 				stat = ldapModify(dn, rvt, objClassAttrs, 0);
24337c478bd9Sstevel@tonic-gate 				if (stat != LDAP_SUCCESS &&
24347c478bd9Sstevel@tonic-gate 					stat != LDAP_NO_SUCH_ATTRIBUTE) {
24357c478bd9Sstevel@tonic-gate 					freeRuleValue(rvt, 1);
24367c478bd9Sstevel@tonic-gate 					goto cleanup;
24377c478bd9Sstevel@tonic-gate 				}
24387c478bd9Sstevel@tonic-gate 				delAttrFromRuleValue(rvt, rv->attrName[d]);
24397c478bd9Sstevel@tonic-gate 			}
24407c478bd9Sstevel@tonic-gate 
24417c478bd9Sstevel@tonic-gate 			/*
24427c478bd9Sstevel@tonic-gate 			 * If we got here, then all attributes that should
24437c478bd9Sstevel@tonic-gate 			 * be deleted either have been, or didn't exist. For
24447c478bd9Sstevel@tonic-gate 			 * our purposes, the latter is as good as the former.
24457c478bd9Sstevel@tonic-gate 			 */
24467c478bd9Sstevel@tonic-gate 			stat = LDAP_SUCCESS;
24477c478bd9Sstevel@tonic-gate 			freeRuleValue(rvt, 1);
24487c478bd9Sstevel@tonic-gate 		}
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 		if (stat == LDAP_NO_SUCH_OBJECT && !addFirst) {
24517c478bd9Sstevel@tonic-gate 			/*
24527c478bd9Sstevel@tonic-gate 			 * Entry doesn't exist, so try an ldap_add(). If the
24537c478bd9Sstevel@tonic-gate 			 * ldap_add() also fails, that could be because someone
24547c478bd9Sstevel@tonic-gate 			 * else added it between our modify and add operations.
24557c478bd9Sstevel@tonic-gate 			 * If so, we consider that foreign add to be
24567c478bd9Sstevel@tonic-gate 			 * authoritative (meaning we don't retry our modify).
24577c478bd9Sstevel@tonic-gate 			 *
24587c478bd9Sstevel@tonic-gate 			 * Also, if all modify operations specified by 'mods'
24597c478bd9Sstevel@tonic-gate 			 * are deletes, LDAP_NO_SUCH_OBJECT is a kind of
24607c478bd9Sstevel@tonic-gate 			 * success; we certainly don't want to create the
24617c478bd9Sstevel@tonic-gate 			 * entry.
24627c478bd9Sstevel@tonic-gate 			 */
24637c478bd9Sstevel@tonic-gate 			int	allDelete;
24647c478bd9Sstevel@tonic-gate 			LDAPMod	**m;
24657c478bd9Sstevel@tonic-gate 
24667c478bd9Sstevel@tonic-gate 			for (m = mods, allDelete = 1; *m != 0 && allDelete;
24677c478bd9Sstevel@tonic-gate 					m++) {
24687c478bd9Sstevel@tonic-gate 				if (((*m)->mod_op & LDAP_MOD_DELETE) == 0)
24697c478bd9Sstevel@tonic-gate 					allDelete = 0;
24707c478bd9Sstevel@tonic-gate 			}
24717c478bd9Sstevel@tonic-gate 
24727c478bd9Sstevel@tonic-gate 			add = 1;
24737c478bd9Sstevel@tonic-gate 
24747c478bd9Sstevel@tonic-gate 			if (allDelete) {
24757c478bd9Sstevel@tonic-gate 				stat = LDAP_SUCCESS;
24767c478bd9Sstevel@tonic-gate 			} else if (objClassAttrs == 0) {
24777c478bd9Sstevel@tonic-gate 				/* Now we need it, so this is fatal */
24787c478bd9Sstevel@tonic-gate 				stat = LDAP_PARAM_ERROR;
24797c478bd9Sstevel@tonic-gate 			} else {
24807c478bd9Sstevel@tonic-gate 				stat = ldapAdd(dn, rv, objClassAttrs, lc);
24817c478bd9Sstevel@tonic-gate 				lc = NULL;
24827c478bd9Sstevel@tonic-gate 			}
24837c478bd9Sstevel@tonic-gate 		}
24847c478bd9Sstevel@tonic-gate 	}
24857c478bd9Sstevel@tonic-gate 
24867c478bd9Sstevel@tonic-gate cleanup:
24877c478bd9Sstevel@tonic-gate 	if (stat != LDAP_SUCCESS) {
24887c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
24897c478bd9Sstevel@tonic-gate 			"%s(0x%x (%s), \"%s\") => %d (%s)\n",
24907c478bd9Sstevel@tonic-gate 			!delete ? (add ? "ldap_add" : "ldap_modify") :
24917c478bd9Sstevel@tonic-gate 				"ldap_delete",
24927c478bd9Sstevel@tonic-gate 			lc != NULL ? lc->ld : 0,
24937c478bd9Sstevel@tonic-gate 			lc != NULL ? NIL(lc->sp) : "nil",
24947c478bd9Sstevel@tonic-gate 			dn, stat, ldap_err2string(stat));
24957c478bd9Sstevel@tonic-gate 	}
24967c478bd9Sstevel@tonic-gate 
24977c478bd9Sstevel@tonic-gate 	releaseCon(lc, stat);
24987c478bd9Sstevel@tonic-gate 	freeLdapMod(mods);
24997c478bd9Sstevel@tonic-gate 	if (msg != 0)
25007c478bd9Sstevel@tonic-gate 		(void) ldap_msgfree(msg);
25017c478bd9Sstevel@tonic-gate 
25027c478bd9Sstevel@tonic-gate 	return (stat);
25037c478bd9Sstevel@tonic-gate }
25047c478bd9Sstevel@tonic-gate 
25057c478bd9Sstevel@tonic-gate /*
25067c478bd9Sstevel@tonic-gate  * Create the entry specified by 'dn' to have the values per 'rv'.
25077c478bd9Sstevel@tonic-gate  * The 'objClassAttrs' are the extra object classes we need when
25087c478bd9Sstevel@tonic-gate  * creating an entry.
25097c478bd9Sstevel@tonic-gate  *
25107c478bd9Sstevel@tonic-gate  * If 'lc' is non-NULL, we use that connection; otherwise, we find
25117c478bd9Sstevel@tonic-gate  * our own. CAUTION: This connection will be released on return. Regardless
25127c478bd9Sstevel@tonic-gate  * of return value, this connection should not subsequently used by the
25137c478bd9Sstevel@tonic-gate  * caller.
25147c478bd9Sstevel@tonic-gate  *
25157c478bd9Sstevel@tonic-gate  * Returns an LDAP status.
25167c478bd9Sstevel@tonic-gate  */
25177c478bd9Sstevel@tonic-gate int
ldapAdd(char * dn,__nis_rule_value_t * rv,char * objClassAttrs,void * lcv)25187c478bd9Sstevel@tonic-gate ldapAdd(char *dn, __nis_rule_value_t *rv, char *objClassAttrs, void *lcv) {
25197c478bd9Sstevel@tonic-gate 	int			stat;
25207c478bd9Sstevel@tonic-gate 	LDAPMod			**mods = 0;
25217c478bd9Sstevel@tonic-gate 	struct timeval		tv;
25227c478bd9Sstevel@tonic-gate 	LDAPMessage		*msg = 0;
25237c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc = lcv;
25247c478bd9Sstevel@tonic-gate 	int			msgid;
25257c478bd9Sstevel@tonic-gate 	int			lderr;
25267c478bd9Sstevel@tonic-gate 	char			**referralsp = NULL;
25277c478bd9Sstevel@tonic-gate 
25287c478bd9Sstevel@tonic-gate 	if (dn == 0 || rv == 0 || objClassAttrs == 0) {
25297c478bd9Sstevel@tonic-gate 		releaseCon(lc, LDAP_SUCCESS);
25307c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
25317c478bd9Sstevel@tonic-gate 	}
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 	if (lc == 0) {
25347c478bd9Sstevel@tonic-gate 		if ((lc = findCon(&stat)) == 0)
25357c478bd9Sstevel@tonic-gate 			return (stat);
25367c478bd9Sstevel@tonic-gate 	}
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 	rv = addObjectClasses(rv, objClassAttrs);
25397c478bd9Sstevel@tonic-gate 	if (rv == 0) {
25407c478bd9Sstevel@tonic-gate 		stat = LDAP_OPERATIONS_ERROR;
25417c478bd9Sstevel@tonic-gate 		goto cleanup;
25427c478bd9Sstevel@tonic-gate 	}
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	mods = search2LdapMod(rv, 1, 0);
25457c478bd9Sstevel@tonic-gate 	if (mods == 0) {
25467c478bd9Sstevel@tonic-gate 		stat = LDAP_OPERATIONS_ERROR;
25477c478bd9Sstevel@tonic-gate 		goto cleanup;
25487c478bd9Sstevel@tonic-gate 	}
25497c478bd9Sstevel@tonic-gate 
25507c478bd9Sstevel@tonic-gate 	msgid = ldap_add(lc->ld, dn, mods);
25517c478bd9Sstevel@tonic-gate 	if (msgid == -1) {
25527c478bd9Sstevel@tonic-gate 		(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
25537c478bd9Sstevel@tonic-gate 		goto cleanup;
25547c478bd9Sstevel@tonic-gate 	}
25557c478bd9Sstevel@tonic-gate 	tv = lc->addTimeout;
25567c478bd9Sstevel@tonic-gate 	stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
25577c478bd9Sstevel@tonic-gate 	if (stat == 0) {
25587c478bd9Sstevel@tonic-gate 		stat = LDAP_TIMEOUT;
25597c478bd9Sstevel@tonic-gate 	} else if (stat == -1) {
25607c478bd9Sstevel@tonic-gate 		(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
25617c478bd9Sstevel@tonic-gate 	} else {
25627c478bd9Sstevel@tonic-gate 		stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, NULL,
25637c478bd9Sstevel@tonic-gate 			&referralsp, NULL, 0);
25647c478bd9Sstevel@tonic-gate 		if (stat == LDAP_SUCCESS)
25657c478bd9Sstevel@tonic-gate 			stat = lderr;
25667c478bd9Sstevel@tonic-gate 	}
25677c478bd9Sstevel@tonic-gate 	if (proxyInfo.follow_referral == follow && stat == LDAP_REFERRAL &&
25687c478bd9Sstevel@tonic-gate 			referralsp != NULL) {
25697c478bd9Sstevel@tonic-gate 		releaseCon(lc, stat);
25707c478bd9Sstevel@tonic-gate 		if (msg != NULL)
25717c478bd9Sstevel@tonic-gate 			(void) ldap_msgfree(msg);
25727c478bd9Sstevel@tonic-gate 		msg = NULL;
25737c478bd9Sstevel@tonic-gate 		lc = findReferralCon(referralsp, &stat);
25747c478bd9Sstevel@tonic-gate 		ldap_value_free(referralsp);
25757c478bd9Sstevel@tonic-gate 		if (lc == NULL)
25767c478bd9Sstevel@tonic-gate 			goto cleanup;
25777c478bd9Sstevel@tonic-gate 		msgid = ldap_add(lc->ld, dn, mods);
25787c478bd9Sstevel@tonic-gate 		if (msgid == -1) {
25797c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld,
25807c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
25817c478bd9Sstevel@tonic-gate 			goto cleanup;
25827c478bd9Sstevel@tonic-gate 		}
25837c478bd9Sstevel@tonic-gate 		stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
25847c478bd9Sstevel@tonic-gate 		if (stat == 0) {
25857c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
25867c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
25877c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
25887c478bd9Sstevel@tonic-gate 						&stat);
25897c478bd9Sstevel@tonic-gate 		} else {
25907c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
25917c478bd9Sstevel@tonic-gate 				NULL, NULL, NULL, 0);
25927c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
25937c478bd9Sstevel@tonic-gate 				stat = lderr;
25947c478bd9Sstevel@tonic-gate 		}
25957c478bd9Sstevel@tonic-gate 	}
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate cleanup:
25987c478bd9Sstevel@tonic-gate 	if (stat != LDAP_SUCCESS) {
25997c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
26007c478bd9Sstevel@tonic-gate 			"ldap_add(0x%x (%s), \"%s\") => %d (%s)\n",
26017c478bd9Sstevel@tonic-gate 			lc != NULL ? lc->ld : 0,
26027c478bd9Sstevel@tonic-gate 			lc != NULL ? NIL(lc->sp) : "nil",
26037c478bd9Sstevel@tonic-gate 			dn, stat, ldap_err2string(stat));
26047c478bd9Sstevel@tonic-gate 	}
26057c478bd9Sstevel@tonic-gate 
26067c478bd9Sstevel@tonic-gate 	releaseCon(lc, stat);
26077c478bd9Sstevel@tonic-gate 	freeLdapMod(mods);
26087c478bd9Sstevel@tonic-gate 	if (msg != 0)
26097c478bd9Sstevel@tonic-gate 		(void) ldap_msgfree(msg);
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate 	return (stat);
26127c478bd9Sstevel@tonic-gate }
26137c478bd9Sstevel@tonic-gate 
26147c478bd9Sstevel@tonic-gate /*
26157c478bd9Sstevel@tonic-gate  * Change the entry at 'oldDn' to have the new DN (not RDN) 'dn'.
26167c478bd9Sstevel@tonic-gate  * Returns an LDAP error status.
26177c478bd9Sstevel@tonic-gate  */
26187c478bd9Sstevel@tonic-gate int
ldapChangeDN(char * oldDn,char * dn)26197c478bd9Sstevel@tonic-gate ldapChangeDN(char *oldDn, char *dn) {
26207c478bd9Sstevel@tonic-gate 	int			stat;
26217c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc;
26227c478bd9Sstevel@tonic-gate 	int			i, j, lo, ln;
26237c478bd9Sstevel@tonic-gate 	char			*rdn;
26247c478bd9Sstevel@tonic-gate 	int			msgid;
26257c478bd9Sstevel@tonic-gate 	int			lderr;
26267c478bd9Sstevel@tonic-gate 	struct timeval		tv;
26277c478bd9Sstevel@tonic-gate 	LDAPMessage		*msg = 0;
26287c478bd9Sstevel@tonic-gate 	char			**referralsp = NULL;
26297c478bd9Sstevel@tonic-gate 	char			*myself = "ldapChangeDN";
26307c478bd9Sstevel@tonic-gate 
26317c478bd9Sstevel@tonic-gate 	if ((lo = slen(oldDn)) <= 0 || (ln = slen(dn)) <= 0)
26327c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
26337c478bd9Sstevel@tonic-gate 
26347c478bd9Sstevel@tonic-gate 	if (strcasecmp(oldDn, dn) == 0)
26357c478bd9Sstevel@tonic-gate 		return (LDAP_SUCCESS);
26367c478bd9Sstevel@tonic-gate 
26377c478bd9Sstevel@tonic-gate 	if ((lc = findCon(&stat)) == 0)
26387c478bd9Sstevel@tonic-gate 		return (stat);
26397c478bd9Sstevel@tonic-gate 
26407c478bd9Sstevel@tonic-gate 	rdn = sdup(myself, T, dn);
26417c478bd9Sstevel@tonic-gate 	if (rdn == 0) {
26427c478bd9Sstevel@tonic-gate 		releaseCon(lc, LDAP_SUCCESS);
26437c478bd9Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
26447c478bd9Sstevel@tonic-gate 	}
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate 	/* Compare old and new DN from the end */
26477c478bd9Sstevel@tonic-gate 	for (i = lo-1, j = ln-1; i >= 0 && j >= 0; i--, j--) {
26487c478bd9Sstevel@tonic-gate 		if (tolower(oldDn[i]) != tolower(rdn[j])) {
26497c478bd9Sstevel@tonic-gate 			/*
26507c478bd9Sstevel@tonic-gate 			 * Terminate 'rdn' after this character in order
26517c478bd9Sstevel@tonic-gate 			 * to snip off the portion of the new DN that is
26527c478bd9Sstevel@tonic-gate 			 * the same as the old DN. What remains in 'rdn'
26537c478bd9Sstevel@tonic-gate 			 * is the relative DN.
26547c478bd9Sstevel@tonic-gate 			 */
26557c478bd9Sstevel@tonic-gate 			rdn[j+1] = '\0';
26567c478bd9Sstevel@tonic-gate 			break;
26577c478bd9Sstevel@tonic-gate 		}
26587c478bd9Sstevel@tonic-gate 	}
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	stat = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL, &msgid);
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate 	if (msgid != -1) {
26637c478bd9Sstevel@tonic-gate 		tv = lc->modifyTimeout;
26647c478bd9Sstevel@tonic-gate 		stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
26657c478bd9Sstevel@tonic-gate 		if (stat == 0) {
26667c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
26677c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
26687c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld,
26697c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
26707c478bd9Sstevel@tonic-gate 		} else {
26717c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
26727c478bd9Sstevel@tonic-gate 				NULL, &referralsp, NULL, 0);
26737c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
26747c478bd9Sstevel@tonic-gate 				stat = lderr;
26757c478bd9Sstevel@tonic-gate 			stat = ldap_result2error(lc->ld, msg, 0);
26767c478bd9Sstevel@tonic-gate 		}
26777c478bd9Sstevel@tonic-gate 	} else {
26787c478bd9Sstevel@tonic-gate 		(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
26797c478bd9Sstevel@tonic-gate 			&stat);
26807c478bd9Sstevel@tonic-gate 	}
26817c478bd9Sstevel@tonic-gate 	if (proxyInfo.follow_referral == follow &&
26827c478bd9Sstevel@tonic-gate 			stat == LDAP_REFERRAL && referralsp != NULL) {
26837c478bd9Sstevel@tonic-gate 		releaseCon(lc, stat);
26847c478bd9Sstevel@tonic-gate 		if (msg != NULL)
26857c478bd9Sstevel@tonic-gate 			(void) ldap_msgfree(msg);
26867c478bd9Sstevel@tonic-gate 		msg = NULL;
26877c478bd9Sstevel@tonic-gate 		lc = findReferralCon(referralsp, &stat);
26887c478bd9Sstevel@tonic-gate 		ldap_value_free(referralsp);
26897c478bd9Sstevel@tonic-gate 		referralsp = NULL;
26907c478bd9Sstevel@tonic-gate 		if (lc == NULL)
26917c478bd9Sstevel@tonic-gate 			goto cleanup;
26927c478bd9Sstevel@tonic-gate 		msgid = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL,
26937c478bd9Sstevel@tonic-gate 			&msgid);
26947c478bd9Sstevel@tonic-gate 		if (msgid == -1) {
26957c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld,
26967c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
26977c478bd9Sstevel@tonic-gate 			goto cleanup;
26987c478bd9Sstevel@tonic-gate 		}
26997c478bd9Sstevel@tonic-gate 		stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
27007c478bd9Sstevel@tonic-gate 		if (stat == 0) {
27017c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
27027c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
27037c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld,
27047c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
27057c478bd9Sstevel@tonic-gate 		} else {
27067c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lderr,
27077c478bd9Sstevel@tonic-gate 				NULL, NULL, NULL, NULL, 0);
27087c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
27097c478bd9Sstevel@tonic-gate 				stat = lderr;
27107c478bd9Sstevel@tonic-gate 		}
27117c478bd9Sstevel@tonic-gate 	}
27127c478bd9Sstevel@tonic-gate 
27137c478bd9Sstevel@tonic-gate cleanup:
27147c478bd9Sstevel@tonic-gate 	if (msg != NULL)
27157c478bd9Sstevel@tonic-gate 		(void) ldap_msgfree(msg);
27167c478bd9Sstevel@tonic-gate 
27177c478bd9Sstevel@tonic-gate #if	1
27187c478bd9Sstevel@tonic-gate 	fprintf(stderr, "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s\n",
27197c478bd9Sstevel@tonic-gate 		myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn),
27207c478bd9Sstevel@tonic-gate 		ldap_err2string(stat));
27217c478bd9Sstevel@tonic-gate 	logmsg(MSG_NOTIMECHECK, LOG_WARNING,
27227c478bd9Sstevel@tonic-gate 		"%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s",
27237c478bd9Sstevel@tonic-gate 		myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn),
27247c478bd9Sstevel@tonic-gate 		ldap_err2string(stat));
27257c478bd9Sstevel@tonic-gate #endif
27267c478bd9Sstevel@tonic-gate 
27277c478bd9Sstevel@tonic-gate 	if (stat == LDAP_NO_SUCH_OBJECT) {
27287c478bd9Sstevel@tonic-gate 		/*
27297c478bd9Sstevel@tonic-gate 		 * Fine from our point of view, since all we want to do
27307c478bd9Sstevel@tonic-gate 		 * is to make sure that an update to the new DN doesn't
27317c478bd9Sstevel@tonic-gate 		 * leave the old entry around.
27327c478bd9Sstevel@tonic-gate 		 */
27337c478bd9Sstevel@tonic-gate 		stat = LDAP_SUCCESS;
27347c478bd9Sstevel@tonic-gate 	}
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate 	releaseCon(lc, stat);
27377c478bd9Sstevel@tonic-gate 	sfree(rdn);
27387c478bd9Sstevel@tonic-gate 
27397c478bd9Sstevel@tonic-gate 	return (stat);
27407c478bd9Sstevel@tonic-gate }
2741