xref: /titanic_53/usr/src/lib/libnisdb/ldap_op.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <synch.h>
30*7c478bd9Sstevel@tonic-gate #include <strings.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
32*7c478bd9Sstevel@tonic-gate #include <ctype.h>
33*7c478bd9Sstevel@tonic-gate 
34*7c478bd9Sstevel@tonic-gate #include "ldap_op.h"
35*7c478bd9Sstevel@tonic-gate #include "ldap_util.h"
36*7c478bd9Sstevel@tonic-gate #include "ldap_structs.h"
37*7c478bd9Sstevel@tonic-gate #include "ldap_ruleval.h"
38*7c478bd9Sstevel@tonic-gate #include "ldap_attr.h"
39*7c478bd9Sstevel@tonic-gate #include "ldap_print.h"
40*7c478bd9Sstevel@tonic-gate #include "ldap_glob.h"
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate #include "nis_parse_ldap_conf.h"
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate #ifndef LDAPS_PORT
45*7c478bd9Sstevel@tonic-gate #define	LDAPS_PORT	636
46*7c478bd9Sstevel@tonic-gate #endif
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate /*
49*7c478bd9Sstevel@tonic-gate  * Build one of our internal LDAP search structures, containing copies of
50*7c478bd9Sstevel@tonic-gate  * the supplied input. return NULL in case of error.
51*7c478bd9Sstevel@tonic-gate  *
52*7c478bd9Sstevel@tonic-gate  * If 'filter' is NULL, build an AND-filter using the filter components.
53*7c478bd9Sstevel@tonic-gate  */
54*7c478bd9Sstevel@tonic-gate __nis_ldap_search_t *
55*7c478bd9Sstevel@tonic-gate buildLdapSearch(char *base, int scope, int numFilterComps, char **filterComp,
56*7c478bd9Sstevel@tonic-gate 		char *filter, char **attrs, int attrsonly, int isDN) {
57*7c478bd9Sstevel@tonic-gate 	__nis_ldap_search_t	*ls;
58*7c478bd9Sstevel@tonic-gate 	char			**a;
59*7c478bd9Sstevel@tonic-gate 	int			i, na, err = 0;
60*7c478bd9Sstevel@tonic-gate 	char			*myself = "buildLdapSearch";
61*7c478bd9Sstevel@tonic-gate 
62*7c478bd9Sstevel@tonic-gate 	ls = am(myself, sizeof (*ls));
63*7c478bd9Sstevel@tonic-gate 	if (ls == 0)
64*7c478bd9Sstevel@tonic-gate 		return (0);
65*7c478bd9Sstevel@tonic-gate 
66*7c478bd9Sstevel@tonic-gate 	ls->base = sdup(myself, T, base);
67*7c478bd9Sstevel@tonic-gate 	if (ls->base == 0 && base != 0)
68*7c478bd9Sstevel@tonic-gate 		err++;
69*7c478bd9Sstevel@tonic-gate 	ls->scope = scope;
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate 	if (filterComp != 0 && numFilterComps > 0) {
72*7c478bd9Sstevel@tonic-gate 		ls->filterComp = am(myself, numFilterComps *
73*7c478bd9Sstevel@tonic-gate 					sizeof (ls->filterComp[0]));
74*7c478bd9Sstevel@tonic-gate 		if (ls->filterComp == 0) {
75*7c478bd9Sstevel@tonic-gate 			err++;
76*7c478bd9Sstevel@tonic-gate 			numFilterComps = 0;
77*7c478bd9Sstevel@tonic-gate 		}
78*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < numFilterComps; i++) {
79*7c478bd9Sstevel@tonic-gate 			ls->filterComp[i] = sdup(myself, T, filterComp[i]);
80*7c478bd9Sstevel@tonic-gate 			if (ls->filterComp[i] == 0 && filterComp[i] != 0)
81*7c478bd9Sstevel@tonic-gate 				err++;
82*7c478bd9Sstevel@tonic-gate 		}
83*7c478bd9Sstevel@tonic-gate 		ls->numFilterComps = numFilterComps;
84*7c478bd9Sstevel@tonic-gate 		if (filter == 0) {
85*7c478bd9Sstevel@tonic-gate 			ls->filter = concatenateFilterComps(ls->numFilterComps,
86*7c478bd9Sstevel@tonic-gate 					ls->filterComp);
87*7c478bd9Sstevel@tonic-gate 			if (ls->filter == 0)
88*7c478bd9Sstevel@tonic-gate 				err++;
89*7c478bd9Sstevel@tonic-gate 		}
90*7c478bd9Sstevel@tonic-gate 	} else {
91*7c478bd9Sstevel@tonic-gate 		ls->filterComp = 0;
92*7c478bd9Sstevel@tonic-gate 		ls->numFilterComps = 0;
93*7c478bd9Sstevel@tonic-gate 		ls->filter = sdup(myself, T, filter);
94*7c478bd9Sstevel@tonic-gate 		if (ls->filter == 0 && filter != 0)
95*7c478bd9Sstevel@tonic-gate 			err++;
96*7c478bd9Sstevel@tonic-gate 	}
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate 	if (attrs != 0) {
99*7c478bd9Sstevel@tonic-gate 		for (na = 0, a = attrs; *a != 0; a++, na++);
100*7c478bd9Sstevel@tonic-gate 		ls->attrs = am(myself, (na + 1) * sizeof (ls->attrs[0]));
101*7c478bd9Sstevel@tonic-gate 		if (ls->attrs != 0) {
102*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < na; i++) {
103*7c478bd9Sstevel@tonic-gate 				ls->attrs[i] = sdup(myself, T, attrs[i]);
104*7c478bd9Sstevel@tonic-gate 				if (ls->attrs[i] == 0 && attrs[i] != 0)
105*7c478bd9Sstevel@tonic-gate 					err++;
106*7c478bd9Sstevel@tonic-gate 			}
107*7c478bd9Sstevel@tonic-gate 			ls->attrs[na] = 0;
108*7c478bd9Sstevel@tonic-gate 			ls->numAttrs = na;
109*7c478bd9Sstevel@tonic-gate 		} else {
110*7c478bd9Sstevel@tonic-gate 			err++;
111*7c478bd9Sstevel@tonic-gate 		}
112*7c478bd9Sstevel@tonic-gate 	} else {
113*7c478bd9Sstevel@tonic-gate 		ls->attrs = 0;
114*7c478bd9Sstevel@tonic-gate 		ls->numAttrs = 0;
115*7c478bd9Sstevel@tonic-gate 	}
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	ls->attrsonly = attrsonly;
118*7c478bd9Sstevel@tonic-gate 	ls->isDN = isDN;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	if (err > 0) {
121*7c478bd9Sstevel@tonic-gate 		freeLdapSearch(ls);
122*7c478bd9Sstevel@tonic-gate 		ls = 0;
123*7c478bd9Sstevel@tonic-gate 	}
124*7c478bd9Sstevel@tonic-gate 
125*7c478bd9Sstevel@tonic-gate 	return (ls);
126*7c478bd9Sstevel@tonic-gate }
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate void
129*7c478bd9Sstevel@tonic-gate freeLdapSearch(__nis_ldap_search_t *ls) {
130*7c478bd9Sstevel@tonic-gate 	int	i;
131*7c478bd9Sstevel@tonic-gate 
132*7c478bd9Sstevel@tonic-gate 	if (ls == 0)
133*7c478bd9Sstevel@tonic-gate 		return;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	sfree(ls->base);
136*7c478bd9Sstevel@tonic-gate 	if (ls->filterComp != 0) {
137*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ls->numFilterComps; i++) {
138*7c478bd9Sstevel@tonic-gate 			sfree(ls->filterComp[i]);
139*7c478bd9Sstevel@tonic-gate 		}
140*7c478bd9Sstevel@tonic-gate 		sfree(ls->filterComp);
141*7c478bd9Sstevel@tonic-gate 	}
142*7c478bd9Sstevel@tonic-gate 	sfree(ls->filter);
143*7c478bd9Sstevel@tonic-gate 	if (ls->attrs != 0) {
144*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < ls->numAttrs; i++) {
145*7c478bd9Sstevel@tonic-gate 			sfree(ls->attrs[i]);
146*7c478bd9Sstevel@tonic-gate 		}
147*7c478bd9Sstevel@tonic-gate 		sfree(ls->attrs);
148*7c478bd9Sstevel@tonic-gate 	}
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 	free(ls);
151*7c478bd9Sstevel@tonic-gate }
152*7c478bd9Sstevel@tonic-gate 
153*7c478bd9Sstevel@tonic-gate /*
154*7c478bd9Sstevel@tonic-gate  * Given a table mapping, and a rule/value pointer,
155*7c478bd9Sstevel@tonic-gate  * return an LDAP search structure with values suitable for use
156*7c478bd9Sstevel@tonic-gate  * by ldap_search() or (if dn != 0) ldap_modify(). The rule/value
157*7c478bd9Sstevel@tonic-gate  * may be modified.
158*7c478bd9Sstevel@tonic-gate  *
159*7c478bd9Sstevel@tonic-gate  * If dn != 0 and *dn == 0, the function attemps to return a pointer
160*7c478bd9Sstevel@tonic-gate  * to the DN. This may necessitate an ldapSearch, if the rule set doesn't
161*7c478bd9Sstevel@tonic-gate  * produce a DN directly.
162*7c478bd9Sstevel@tonic-gate  *
163*7c478bd9Sstevel@tonic-gate  * if dn == 0, and the rule set produces a DN as well as other attribute/
164*7c478bd9Sstevel@tonic-gate  * value pairs, the function returns an LDAP search structure with the
165*7c478bd9Sstevel@tonic-gate  * DN only.
166*7c478bd9Sstevel@tonic-gate  *
167*7c478bd9Sstevel@tonic-gate  * If 'fromLDAP' is set, the caller wants base/scope/filter from
168*7c478bd9Sstevel@tonic-gate  * t->objectDN->read; otherwise, from t->objectDN->write.
169*7c478bd9Sstevel@tonic-gate  *
170*7c478bd9Sstevel@tonic-gate  * If 'rv' is NULL, the caller wants an enumeration of the container.
171*7c478bd9Sstevel@tonic-gate  *
172*7c478bd9Sstevel@tonic-gate  * Note that this function only creates a search structure for 't' itself;
173*7c478bd9Sstevel@tonic-gate  * if there are alternative mappings for the table, those must be handled
174*7c478bd9Sstevel@tonic-gate  * by our caller.
175*7c478bd9Sstevel@tonic-gate  */
176*7c478bd9Sstevel@tonic-gate __nis_ldap_search_t *
177*7c478bd9Sstevel@tonic-gate createLdapRequest(__nis_table_mapping_t *t,
178*7c478bd9Sstevel@tonic-gate 		__nis_rule_value_t *rv, char **dn, int fromLDAP,
179*7c478bd9Sstevel@tonic-gate 		int *res, __nis_object_dn_t *obj_dn) {
180*7c478bd9Sstevel@tonic-gate 	int			i, j;
181*7c478bd9Sstevel@tonic-gate 	__nis_ldap_search_t	*ls = 0;
182*7c478bd9Sstevel@tonic-gate 	char			**locDN;
183*7c478bd9Sstevel@tonic-gate 	int			numLocDN, stat = 0, count = 0;
184*7c478bd9Sstevel@tonic-gate 	char			*myself = "createLdapRequest";
185*7c478bd9Sstevel@tonic-gate 	__nis_object_dn_t 	*objectDN = NULL;
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	if (t == 0)
188*7c478bd9Sstevel@tonic-gate 		return (0);
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	if (obj_dn == NULL)
191*7c478bd9Sstevel@tonic-gate 		objectDN = t->objectDN;
192*7c478bd9Sstevel@tonic-gate 	else
193*7c478bd9Sstevel@tonic-gate 		objectDN = obj_dn;
194*7c478bd9Sstevel@tonic-gate 
195*7c478bd9Sstevel@tonic-gate 	if (rv == 0) {
196*7c478bd9Sstevel@tonic-gate 		char	*base;
197*7c478bd9Sstevel@tonic-gate 		char	*filter;
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 		if (fromLDAP) {
200*7c478bd9Sstevel@tonic-gate 			base = objectDN->read.base;
201*7c478bd9Sstevel@tonic-gate 			filter = makeFilter(objectDN->read.attrs);
202*7c478bd9Sstevel@tonic-gate 		} else {
203*7c478bd9Sstevel@tonic-gate 			base = objectDN->write.base;
204*7c478bd9Sstevel@tonic-gate 			filter = makeFilter(objectDN->write.attrs);
205*7c478bd9Sstevel@tonic-gate 		}
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate 		/* Create request to enumerate container */
208*7c478bd9Sstevel@tonic-gate 		ls = buildLdapSearch(base, objectDN->read.scope, 0, 0, filter,
209*7c478bd9Sstevel@tonic-gate 					0, 0, 0);
210*7c478bd9Sstevel@tonic-gate 		sfree(filter);
211*7c478bd9Sstevel@tonic-gate 		return (ls);
212*7c478bd9Sstevel@tonic-gate 	}
213*7c478bd9Sstevel@tonic-gate 
214*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < t->numRulesToLDAP; i++) {
215*7c478bd9Sstevel@tonic-gate 		rv = addLdapRuleValue(t, t->ruleToLDAP[i],
216*7c478bd9Sstevel@tonic-gate 				mit_ldap, mit_nisplus, rv, !fromLDAP, &stat);
217*7c478bd9Sstevel@tonic-gate 		if (rv == 0)
218*7c478bd9Sstevel@tonic-gate 			return (0);
219*7c478bd9Sstevel@tonic-gate 		if (stat == NP_LDAP_RULES_NO_VALUE)
220*7c478bd9Sstevel@tonic-gate 			count++;
221*7c478bd9Sstevel@tonic-gate 		stat = 0;
222*7c478bd9Sstevel@tonic-gate 	}
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	/*
225*7c478bd9Sstevel@tonic-gate 	 * If none of the rules produced a value despite
226*7c478bd9Sstevel@tonic-gate 	 * having enough NIS+ columns, return error.
227*7c478bd9Sstevel@tonic-gate 	 */
228*7c478bd9Sstevel@tonic-gate 	if (rv->numAttrs == 0 && count > 0) {
229*7c478bd9Sstevel@tonic-gate 		*res = NP_LDAP_RULES_NO_VALUE;
230*7c478bd9Sstevel@tonic-gate 		return (0);
231*7c478bd9Sstevel@tonic-gate 	}
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	/*
234*7c478bd9Sstevel@tonic-gate 	 * 'rv' now contains everything we know about the attributes and
235*7c478bd9Sstevel@tonic-gate 	 * values. Build an LDAP search structure from it.
236*7c478bd9Sstevel@tonic-gate 	 */
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate 	/* Look for a single-valued DN */
239*7c478bd9Sstevel@tonic-gate 	locDN = findDNs(myself, rv, 1,
240*7c478bd9Sstevel@tonic-gate 			fromLDAP ? objectDN->read.base :
241*7c478bd9Sstevel@tonic-gate 					objectDN->write.base,
242*7c478bd9Sstevel@tonic-gate 			&numLocDN);
243*7c478bd9Sstevel@tonic-gate 	if (locDN != 0 && numLocDN == 1) {
244*7c478bd9Sstevel@tonic-gate 		if (dn != 0 && *dn == 0) {
245*7c478bd9Sstevel@tonic-gate 			*dn = locDN[0];
246*7c478bd9Sstevel@tonic-gate 			sfree(locDN);
247*7c478bd9Sstevel@tonic-gate 		} else {
248*7c478bd9Sstevel@tonic-gate 			char	*filter;
249*7c478bd9Sstevel@tonic-gate 
250*7c478bd9Sstevel@tonic-gate 			if (fromLDAP)
251*7c478bd9Sstevel@tonic-gate 				filter = makeFilter(objectDN->read.attrs);
252*7c478bd9Sstevel@tonic-gate 			else
253*7c478bd9Sstevel@tonic-gate 				filter = makeFilter(objectDN->write.attrs);
254*7c478bd9Sstevel@tonic-gate 			ls = buildLdapSearch(locDN[0], LDAP_SCOPE_BASE, 0, 0,
255*7c478bd9Sstevel@tonic-gate 						filter, 0, 0, 1);
256*7c478bd9Sstevel@tonic-gate 			sfree(filter);
257*7c478bd9Sstevel@tonic-gate 			freeDNs(locDN, numLocDN);
258*7c478bd9Sstevel@tonic-gate 		}
259*7c478bd9Sstevel@tonic-gate 	} else {
260*7c478bd9Sstevel@tonic-gate 		freeDNs(locDN, numLocDN);
261*7c478bd9Sstevel@tonic-gate 	}
262*7c478bd9Sstevel@tonic-gate 
263*7c478bd9Sstevel@tonic-gate 	if (ls != 0) {
264*7c478bd9Sstevel@tonic-gate 		ls->useCon = 1;
265*7c478bd9Sstevel@tonic-gate 		return (ls);
266*7c478bd9Sstevel@tonic-gate 	}
267*7c478bd9Sstevel@tonic-gate 
268*7c478bd9Sstevel@tonic-gate 	/*
269*7c478bd9Sstevel@tonic-gate 	 * No DN, or caller wanted a search structure with the non-DN
270*7c478bd9Sstevel@tonic-gate 	 * attributes.
271*7c478bd9Sstevel@tonic-gate 	 */
272*7c478bd9Sstevel@tonic-gate 
273*7c478bd9Sstevel@tonic-gate 	/* Initialize search structure */
274*7c478bd9Sstevel@tonic-gate 	{
275*7c478bd9Sstevel@tonic-gate 		char	*filter = (fromLDAP) ?
276*7c478bd9Sstevel@tonic-gate 				makeFilter(objectDN->read.attrs) :
277*7c478bd9Sstevel@tonic-gate 				makeFilter(objectDN->write.attrs);
278*7c478bd9Sstevel@tonic-gate 		char	**ofc;
279*7c478bd9Sstevel@tonic-gate 		int	nofc = 0;
280*7c478bd9Sstevel@tonic-gate 
281*7c478bd9Sstevel@tonic-gate 		ofc = makeFilterComp(filter, &nofc);
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 		if (filter != 0 && ofc == 0) {
284*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
285*7c478bd9Sstevel@tonic-gate 			"%s: Unable to break filter into components: \"%s\"",
286*7c478bd9Sstevel@tonic-gate 				myself, NIL(filter));
287*7c478bd9Sstevel@tonic-gate 			sfree(filter);
288*7c478bd9Sstevel@tonic-gate 			return (0);
289*7c478bd9Sstevel@tonic-gate 		}
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 		if (fromLDAP)
292*7c478bd9Sstevel@tonic-gate 			ls = buildLdapSearch(objectDN->read.base,
293*7c478bd9Sstevel@tonic-gate 				objectDN->read.scope,
294*7c478bd9Sstevel@tonic-gate 				nofc, ofc, 0, 0, 0, 0);
295*7c478bd9Sstevel@tonic-gate 		else
296*7c478bd9Sstevel@tonic-gate 			ls = buildLdapSearch(objectDN->write.base,
297*7c478bd9Sstevel@tonic-gate 				objectDN->write.scope,
298*7c478bd9Sstevel@tonic-gate 				nofc, ofc, 0, 0, 0, 0);
299*7c478bd9Sstevel@tonic-gate 		sfree(filter);
300*7c478bd9Sstevel@tonic-gate 		freeFilterComp(ofc, nofc);
301*7c478bd9Sstevel@tonic-gate 		if (ls == 0)
302*7c478bd9Sstevel@tonic-gate 			return (0);
303*7c478bd9Sstevel@tonic-gate 	}
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	/* Build and add the filter components */
306*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < rv->numAttrs; i++) {
307*7c478bd9Sstevel@tonic-gate 		/* Skip DN */
308*7c478bd9Sstevel@tonic-gate 		if (strcasecmp("dn", rv->attrName[i]) == 0)
309*7c478bd9Sstevel@tonic-gate 			continue;
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 		/* Skip vt_ber values */
312*7c478bd9Sstevel@tonic-gate 		if (rv->attrVal[i].type == vt_ber)
313*7c478bd9Sstevel@tonic-gate 			continue;
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 		for (j = 0; j < rv->attrVal[i].numVals; j++) {
316*7c478bd9Sstevel@tonic-gate 			__nis_buffer_t	b = {0, 0};
317*7c478bd9Sstevel@tonic-gate 			char		**tmpComp;
318*7c478bd9Sstevel@tonic-gate 
319*7c478bd9Sstevel@tonic-gate 			bp2buf(myself, &b, "%s=%s",
320*7c478bd9Sstevel@tonic-gate 				rv->attrName[i], rv->attrVal[i].val[j].value);
321*7c478bd9Sstevel@tonic-gate 			tmpComp = addFilterComp(b.buf, ls->filterComp,
322*7c478bd9Sstevel@tonic-gate 						&ls->numFilterComps);
323*7c478bd9Sstevel@tonic-gate 			if (tmpComp == 0) {
324*7c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
325*7c478bd9Sstevel@tonic-gate 				"%s: Unable to add filter component \"%s\"",
326*7c478bd9Sstevel@tonic-gate 					myself, NIL(b.buf));
327*7c478bd9Sstevel@tonic-gate 				sfree(b.buf);
328*7c478bd9Sstevel@tonic-gate 				freeLdapSearch(ls);
329*7c478bd9Sstevel@tonic-gate 				return (0);
330*7c478bd9Sstevel@tonic-gate 			}
331*7c478bd9Sstevel@tonic-gate 			ls->filterComp = tmpComp;
332*7c478bd9Sstevel@tonic-gate 			sfree(b.buf);
333*7c478bd9Sstevel@tonic-gate 		}
334*7c478bd9Sstevel@tonic-gate 	}
335*7c478bd9Sstevel@tonic-gate 
336*7c478bd9Sstevel@tonic-gate 	if (ls->numFilterComps > 0) {
337*7c478bd9Sstevel@tonic-gate 		sfree(ls->filter);
338*7c478bd9Sstevel@tonic-gate 		ls->filter = concatenateFilterComps(ls->numFilterComps,
339*7c478bd9Sstevel@tonic-gate 							ls->filterComp);
340*7c478bd9Sstevel@tonic-gate 		if (ls->filter == 0) {
341*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
342*7c478bd9Sstevel@tonic-gate 			"%s: Unable to concatenate filter components",
343*7c478bd9Sstevel@tonic-gate 				myself);
344*7c478bd9Sstevel@tonic-gate 			freeLdapSearch(ls);
345*7c478bd9Sstevel@tonic-gate 			return (0);
346*7c478bd9Sstevel@tonic-gate 		}
347*7c478bd9Sstevel@tonic-gate 	}
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	if (dn != 0 && *dn == 0) {
350*7c478bd9Sstevel@tonic-gate 		/*
351*7c478bd9Sstevel@tonic-gate 		 * The caller wants a DN, but we didn't get one from the
352*7c478bd9Sstevel@tonic-gate 		 * the rule set. We have an 'ls', so use it to ldapSearch()
353*7c478bd9Sstevel@tonic-gate 		 * for an entry from which we can extract the DN.
354*7c478bd9Sstevel@tonic-gate 		 */
355*7c478bd9Sstevel@tonic-gate 		__nis_rule_value_t	*rvtmp;
356*7c478bd9Sstevel@tonic-gate 		char			**locDN;
357*7c478bd9Sstevel@tonic-gate 		int			nv = 0, numLocDN;
358*7c478bd9Sstevel@tonic-gate 
359*7c478bd9Sstevel@tonic-gate 		rvtmp = ldapSearch(ls, &nv, 0, 0);
360*7c478bd9Sstevel@tonic-gate 		locDN = findDNs(myself, rvtmp, nv, 0, &numLocDN);
361*7c478bd9Sstevel@tonic-gate 		if (locDN != 0 && numLocDN == 1) {
362*7c478bd9Sstevel@tonic-gate 			*dn = locDN[0];
363*7c478bd9Sstevel@tonic-gate 			sfree(locDN);
364*7c478bd9Sstevel@tonic-gate 		} else {
365*7c478bd9Sstevel@tonic-gate 			freeDNs(locDN, numLocDN);
366*7c478bd9Sstevel@tonic-gate 		}
367*7c478bd9Sstevel@tonic-gate 		freeRuleValue(rvtmp, nv);
368*7c478bd9Sstevel@tonic-gate 	}
369*7c478bd9Sstevel@tonic-gate 
370*7c478bd9Sstevel@tonic-gate 	ls->useCon = 1;
371*7c478bd9Sstevel@tonic-gate 	return (ls);
372*7c478bd9Sstevel@tonic-gate }
373*7c478bd9Sstevel@tonic-gate 
374*7c478bd9Sstevel@tonic-gate int	ldapConnAttemptRetryTimeout = 60;	/* seconds */
375*7c478bd9Sstevel@tonic-gate 
376*7c478bd9Sstevel@tonic-gate typedef struct {
377*7c478bd9Sstevel@tonic-gate 	LDAP		*ld;
378*7c478bd9Sstevel@tonic-gate 	mutex_t		mutex;		/* Mutex for update of structure */
379*7c478bd9Sstevel@tonic-gate 	pthread_t	owner;		/* Thread holding mutex */
380*7c478bd9Sstevel@tonic-gate 	mutex_t		rcMutex;	/* Mutex for refCount */
381*7c478bd9Sstevel@tonic-gate 	int		refCount;	/* Reference count */
382*7c478bd9Sstevel@tonic-gate 	int		isBound;	/* Is connection open and usable ? */
383*7c478bd9Sstevel@tonic-gate 	time_t		retryTime;	/* When should open be retried */
384*7c478bd9Sstevel@tonic-gate 	int		status;		/* Status of last operation */
385*7c478bd9Sstevel@tonic-gate 	int		doDis;		/* To be disconnected if refCount==0 */
386*7c478bd9Sstevel@tonic-gate 	int		doDel;		/* To be deleted if refCount zero */
387*7c478bd9Sstevel@tonic-gate 	int		onList;		/* True if on the 'ldapCon' list */
388*7c478bd9Sstevel@tonic-gate 	char		*sp;		/* server string */
389*7c478bd9Sstevel@tonic-gate 	char		*who;
390*7c478bd9Sstevel@tonic-gate 	char		*cred;
391*7c478bd9Sstevel@tonic-gate 	auth_method_t	method;
392*7c478bd9Sstevel@tonic-gate 	int		port;
393*7c478bd9Sstevel@tonic-gate 	struct timeval	bindTimeout;
394*7c478bd9Sstevel@tonic-gate 	struct timeval	searchTimeout;
395*7c478bd9Sstevel@tonic-gate 	struct timeval	modifyTimeout;
396*7c478bd9Sstevel@tonic-gate 	struct timeval	addTimeout;
397*7c478bd9Sstevel@tonic-gate 	struct timeval	deleteTimeout;
398*7c478bd9Sstevel@tonic-gate 	int		simplePage;	/* Can do simple-page */
399*7c478bd9Sstevel@tonic-gate 	int		vlv;		/* Can do VLV */
400*7c478bd9Sstevel@tonic-gate 	uint_t		batchFrom;	/* # entries read in one operation */
401*7c478bd9Sstevel@tonic-gate 	void		*next;
402*7c478bd9Sstevel@tonic-gate } __nis_ldap_conn_t;
403*7c478bd9Sstevel@tonic-gate 
404*7c478bd9Sstevel@tonic-gate /*
405*7c478bd9Sstevel@tonic-gate  * List of connections, 'ldapCon', protected by an RW lock.
406*7c478bd9Sstevel@tonic-gate  *
407*7c478bd9Sstevel@tonic-gate  * The following locking scheme is used:
408*7c478bd9Sstevel@tonic-gate  *
409*7c478bd9Sstevel@tonic-gate  * (1)	Find a connection structure to use to talk to LDAP
410*7c478bd9Sstevel@tonic-gate  *		Rlock list
411*7c478bd9Sstevel@tonic-gate  *			Locate structure
412*7c478bd9Sstevel@tonic-gate  *			Acquire 'mutex'
413*7c478bd9Sstevel@tonic-gate  *				Acquire 'rcMutex'
414*7c478bd9Sstevel@tonic-gate  *					update refCount
415*7c478bd9Sstevel@tonic-gate  *				Release 'rcMutex'
416*7c478bd9Sstevel@tonic-gate  *			release 'mutex'
417*7c478bd9Sstevel@tonic-gate  *		Unlock list
418*7c478bd9Sstevel@tonic-gate  *		Use structure
419*7c478bd9Sstevel@tonic-gate  *		Release structure when done
420*7c478bd9Sstevel@tonic-gate  * (2)	Insert/delete structure(s) on/from list
421*7c478bd9Sstevel@tonic-gate  *		Wlock list
422*7c478bd9Sstevel@tonic-gate  *			Insert/delete structure; if deleting, must
423*7c478bd9Sstevel@tonic-gate  *			acquire 'mutex', and 'rcMutex' (in that order),
424*7c478bd9Sstevel@tonic-gate  *			and 'refCount' must be zero.
425*7c478bd9Sstevel@tonic-gate  *		Unlock list
426*7c478bd9Sstevel@tonic-gate  * (3)	Modify structure
427*7c478bd9Sstevel@tonic-gate  *		Find structure
428*7c478bd9Sstevel@tonic-gate  *		Acquire 'mutex'
429*7c478bd9Sstevel@tonic-gate  *			Modify (except refCount)
430*7c478bd9Sstevel@tonic-gate  *		Release 'mutex'
431*7c478bd9Sstevel@tonic-gate  *		Release structure
432*7c478bd9Sstevel@tonic-gate  */
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate __nis_ldap_conn_t		*ldapCon = 0;
435*7c478bd9Sstevel@tonic-gate __nis_ldap_conn_t		*ldapReferralCon = 0;
436*7c478bd9Sstevel@tonic-gate static rwlock_t			ldapConLock = DEFAULTRWLOCK;
437*7c478bd9Sstevel@tonic-gate static rwlock_t			referralConLock = DEFAULTRWLOCK;
438*7c478bd9Sstevel@tonic-gate 
439*7c478bd9Sstevel@tonic-gate void
440*7c478bd9Sstevel@tonic-gate exclusiveLC(__nis_ldap_conn_t *lc) {
441*7c478bd9Sstevel@tonic-gate 	pthread_t	me = pthread_self();
442*7c478bd9Sstevel@tonic-gate 	int		stat;
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	if (lc == 0)
445*7c478bd9Sstevel@tonic-gate 		return;
446*7c478bd9Sstevel@tonic-gate 
447*7c478bd9Sstevel@tonic-gate 	stat = mutex_trylock(&lc->mutex);
448*7c478bd9Sstevel@tonic-gate 	if (stat == EBUSY && lc->owner != me)
449*7c478bd9Sstevel@tonic-gate 		mutex_lock(&lc->mutex);
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate 	lc->owner = me;
452*7c478bd9Sstevel@tonic-gate }
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate /* Return 1 if mutex held by this thread, 0 otherwise */
455*7c478bd9Sstevel@tonic-gate int
456*7c478bd9Sstevel@tonic-gate assertExclusive(__nis_ldap_conn_t *lc) {
457*7c478bd9Sstevel@tonic-gate 	pthread_t	me;
458*7c478bd9Sstevel@tonic-gate 	int		stat;
459*7c478bd9Sstevel@tonic-gate 
460*7c478bd9Sstevel@tonic-gate 	if (lc == 0)
461*7c478bd9Sstevel@tonic-gate 		return (0);
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	stat = mutex_trylock(&lc->mutex);
464*7c478bd9Sstevel@tonic-gate 
465*7c478bd9Sstevel@tonic-gate 	if (stat == 0) {
466*7c478bd9Sstevel@tonic-gate 		mutex_unlock(&lc->mutex);
467*7c478bd9Sstevel@tonic-gate 		return (0);
468*7c478bd9Sstevel@tonic-gate 	}
469*7c478bd9Sstevel@tonic-gate 
470*7c478bd9Sstevel@tonic-gate 	me = pthread_self();
471*7c478bd9Sstevel@tonic-gate 	if (stat != EBUSY || lc->owner != me)
472*7c478bd9Sstevel@tonic-gate 		return (0);
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	return (1);
475*7c478bd9Sstevel@tonic-gate }
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate void
478*7c478bd9Sstevel@tonic-gate releaseLC(__nis_ldap_conn_t *lc) {
479*7c478bd9Sstevel@tonic-gate 	pthread_t	me = pthread_self();
480*7c478bd9Sstevel@tonic-gate 
481*7c478bd9Sstevel@tonic-gate 	if (lc == 0 || lc->owner != me)
482*7c478bd9Sstevel@tonic-gate 		return;
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 	lc->owner = 0;
485*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lc->mutex);
486*7c478bd9Sstevel@tonic-gate }
487*7c478bd9Sstevel@tonic-gate 
488*7c478bd9Sstevel@tonic-gate void
489*7c478bd9Sstevel@tonic-gate incrementRC(__nis_ldap_conn_t *lc) {
490*7c478bd9Sstevel@tonic-gate 	if (lc == 0)
491*7c478bd9Sstevel@tonic-gate 		return;
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&lc->rcMutex);
494*7c478bd9Sstevel@tonic-gate 	lc->refCount++;
495*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lc->rcMutex);
496*7c478bd9Sstevel@tonic-gate }
497*7c478bd9Sstevel@tonic-gate 
498*7c478bd9Sstevel@tonic-gate void
499*7c478bd9Sstevel@tonic-gate decrementRC(__nis_ldap_conn_t *lc) {
500*7c478bd9Sstevel@tonic-gate 	if (lc == 0)
501*7c478bd9Sstevel@tonic-gate 		return;
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&lc->rcMutex);
504*7c478bd9Sstevel@tonic-gate 	if (lc->refCount > 0)
505*7c478bd9Sstevel@tonic-gate 		lc->refCount--;
506*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&lc->rcMutex);
507*7c478bd9Sstevel@tonic-gate }
508*7c478bd9Sstevel@tonic-gate 
509*7c478bd9Sstevel@tonic-gate /* Accept a server/port indication, and call ldap_init() */
510*7c478bd9Sstevel@tonic-gate static LDAP *
511*7c478bd9Sstevel@tonic-gate ldapInit(char *srv, int port, bool_t use_ssl) {
512*7c478bd9Sstevel@tonic-gate 	LDAP			*ld;
513*7c478bd9Sstevel@tonic-gate 	int			ldapVersion = LDAP_VERSION3;
514*7c478bd9Sstevel@tonic-gate 	int			derefOption = LDAP_DEREF_ALWAYS;
515*7c478bd9Sstevel@tonic-gate 	int			timelimit = proxyInfo.search_time_limit;
516*7c478bd9Sstevel@tonic-gate 	int			sizelimit = proxyInfo.search_size_limit;
517*7c478bd9Sstevel@tonic-gate 	char			*myself = "ldapInit";
518*7c478bd9Sstevel@tonic-gate 
519*7c478bd9Sstevel@tonic-gate 	if (srv == 0)
520*7c478bd9Sstevel@tonic-gate 		return (0);
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	if (use_ssl) {
523*7c478bd9Sstevel@tonic-gate 		ld = ldapssl_init(srv, port, 1);
524*7c478bd9Sstevel@tonic-gate 	} else {
525*7c478bd9Sstevel@tonic-gate 		ld = ldap_init(srv, port);
526*7c478bd9Sstevel@tonic-gate 	}
527*7c478bd9Sstevel@tonic-gate 
528*7c478bd9Sstevel@tonic-gate 	if (ld != 0) {
529*7c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION,
530*7c478bd9Sstevel@tonic-gate 					&ldapVersion);
531*7c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_DEREF, &derefOption);
532*7c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
533*7c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_TIMELIMIT, &timelimit);
534*7c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
535*7c478bd9Sstevel@tonic-gate 		(void) ldap_set_option(ld, LDAP_OPT_REBIND_ARG, 0);
536*7c478bd9Sstevel@tonic-gate 	}
537*7c478bd9Sstevel@tonic-gate 
538*7c478bd9Sstevel@tonic-gate 	return (ld);
539*7c478bd9Sstevel@tonic-gate }
540*7c478bd9Sstevel@tonic-gate 
541*7c478bd9Sstevel@tonic-gate /*
542*7c478bd9Sstevel@tonic-gate  * Bind the specified LDAP structure per the supplied authentication.
543*7c478bd9Sstevel@tonic-gate  * Note: tested with none, simple, and digest_md5. May or may not
544*7c478bd9Sstevel@tonic-gate  * work with other authentication methods, mostly depending on whether
545*7c478bd9Sstevel@tonic-gate  * or not 'who' and 'cred' contain sufficient information.
546*7c478bd9Sstevel@tonic-gate  */
547*7c478bd9Sstevel@tonic-gate static int
548*7c478bd9Sstevel@tonic-gate ldapBind(LDAP **ldP, char *who, char *cred, auth_method_t method,
549*7c478bd9Sstevel@tonic-gate 		struct timeval timeout) {
550*7c478bd9Sstevel@tonic-gate 	int		ret;
551*7c478bd9Sstevel@tonic-gate 	LDAP		*ld;
552*7c478bd9Sstevel@tonic-gate 	char		*myself = "ldapBind";
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 	if (ldP == 0 || (ld = *ldP) == 0)
555*7c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate 	if (method == none) {
558*7c478bd9Sstevel@tonic-gate 		/* No ldap_bind() required (or even possible) */
559*7c478bd9Sstevel@tonic-gate 		ret = LDAP_SUCCESS;
560*7c478bd9Sstevel@tonic-gate 	} else if (method == simple) {
561*7c478bd9Sstevel@tonic-gate 		struct timeval	tv;
562*7c478bd9Sstevel@tonic-gate 		LDAPMessage	*msg = 0;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 		tv = timeout;
565*7c478bd9Sstevel@tonic-gate 		ret = ldap_bind(ld, who, cred, LDAP_AUTH_SIMPLE);
566*7c478bd9Sstevel@tonic-gate 		if (ret != -1) {
567*7c478bd9Sstevel@tonic-gate 			ret = ldap_result(ld, ret, 0, &tv, &msg);
568*7c478bd9Sstevel@tonic-gate 			if (ret == 0) {
569*7c478bd9Sstevel@tonic-gate 				ret = LDAP_TIMEOUT;
570*7c478bd9Sstevel@tonic-gate 			} else if (ret == -1) {
571*7c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(ld,
572*7c478bd9Sstevel@tonic-gate 							LDAP_OPT_ERROR_NUMBER,
573*7c478bd9Sstevel@tonic-gate 							&ret);
574*7c478bd9Sstevel@tonic-gate 			} else {
575*7c478bd9Sstevel@tonic-gate 				ret = ldap_result2error(ld, msg, 0);
576*7c478bd9Sstevel@tonic-gate 			}
577*7c478bd9Sstevel@tonic-gate 			if (msg != 0)
578*7c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(msg);
579*7c478bd9Sstevel@tonic-gate 		} else {
580*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER,
581*7c478bd9Sstevel@tonic-gate 						&ret);
582*7c478bd9Sstevel@tonic-gate 		}
583*7c478bd9Sstevel@tonic-gate 	} else if (method == cram_md5) {
584*7c478bd9Sstevel@tonic-gate 		/* Note: there is only a synchronous call for cram-md5 */
585*7c478bd9Sstevel@tonic-gate 		struct berval ber_cred;
586*7c478bd9Sstevel@tonic-gate 
587*7c478bd9Sstevel@tonic-gate 		ber_cred.bv_len = strlen(cred);
588*7c478bd9Sstevel@tonic-gate 		ber_cred.bv_val = cred;
589*7c478bd9Sstevel@tonic-gate 		ret = ldap_sasl_cram_md5_bind_s(ld, who, &ber_cred, NULL, NULL);
590*7c478bd9Sstevel@tonic-gate 	} else if (method == digest_md5) {
591*7c478bd9Sstevel@tonic-gate 		/* Note: there is only a synchronous call for digest-md5 */
592*7c478bd9Sstevel@tonic-gate 		struct berval ber_cred;
593*7c478bd9Sstevel@tonic-gate 
594*7c478bd9Sstevel@tonic-gate 		ber_cred.bv_len = strlen(cred);
595*7c478bd9Sstevel@tonic-gate 		ber_cred.bv_val = cred;
596*7c478bd9Sstevel@tonic-gate 		ret = ldap_x_sasl_digest_md5_bind_s(ld, who, &ber_cred, NULL,
597*7c478bd9Sstevel@tonic-gate 			NULL);
598*7c478bd9Sstevel@tonic-gate 	} else {
599*7c478bd9Sstevel@tonic-gate 		ret = LDAP_AUTH_METHOD_NOT_SUPPORTED;
600*7c478bd9Sstevel@tonic-gate 	}
601*7c478bd9Sstevel@tonic-gate 
602*7c478bd9Sstevel@tonic-gate 	if (ret != LDAP_SUCCESS) {
603*7c478bd9Sstevel@tonic-gate 		(void) ldap_unbind_s(ld);
604*7c478bd9Sstevel@tonic-gate 		*ldP = 0;
605*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_WARNING,
606*7c478bd9Sstevel@tonic-gate 			"%s: Unable to bind as: %s: %s",
607*7c478bd9Sstevel@tonic-gate 			myself, who, ldap_err2string(ret));
608*7c478bd9Sstevel@tonic-gate 	}
609*7c478bd9Sstevel@tonic-gate 
610*7c478bd9Sstevel@tonic-gate 	return (ret);
611*7c478bd9Sstevel@tonic-gate }
612*7c478bd9Sstevel@tonic-gate 
613*7c478bd9Sstevel@tonic-gate /*
614*7c478bd9Sstevel@tonic-gate  * Free 'lc' and all related memory. Caller must hold the exclusive lock.
615*7c478bd9Sstevel@tonic-gate  * Return LDAP_UNAVAILABLE upon success, in which case the caller mustn't
616*7c478bd9Sstevel@tonic-gate  * try to use the structure pointer in any way.
617*7c478bd9Sstevel@tonic-gate  */
618*7c478bd9Sstevel@tonic-gate static int
619*7c478bd9Sstevel@tonic-gate freeCon(__nis_ldap_conn_t *lc) {
620*7c478bd9Sstevel@tonic-gate 	char			*myself = "freeCon";
621*7c478bd9Sstevel@tonic-gate 
622*7c478bd9Sstevel@tonic-gate 	if (!assertExclusive(lc))
623*7c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	incrementRC(lc);
626*7c478bd9Sstevel@tonic-gate 
627*7c478bd9Sstevel@tonic-gate 	/* Must be unused, unbound, and not on the 'ldapCon' list */
628*7c478bd9Sstevel@tonic-gate 	if (lc->onList || lc->refCount != 1 || lc->isBound) {
629*7c478bd9Sstevel@tonic-gate 		lc->doDel++;
630*7c478bd9Sstevel@tonic-gate 		decrementRC(lc);
631*7c478bd9Sstevel@tonic-gate 		return (LDAP_BUSY);
632*7c478bd9Sstevel@tonic-gate 	}
633*7c478bd9Sstevel@tonic-gate 
634*7c478bd9Sstevel@tonic-gate 	sfree(lc->sp);
635*7c478bd9Sstevel@tonic-gate 	sfree(lc->who);
636*7c478bd9Sstevel@tonic-gate 	sfree(lc->cred);
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 	/* Delete structure with both mutex:es held */
639*7c478bd9Sstevel@tonic-gate 
640*7c478bd9Sstevel@tonic-gate 	free(lc);
641*7c478bd9Sstevel@tonic-gate 
642*7c478bd9Sstevel@tonic-gate 	return (LDAP_UNAVAILABLE);
643*7c478bd9Sstevel@tonic-gate }
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate /*
646*7c478bd9Sstevel@tonic-gate  * Disconnect the specified LDAP connection. Caller must have acquired 'mutex'.
647*7c478bd9Sstevel@tonic-gate  *
648*7c478bd9Sstevel@tonic-gate  * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch
649*7c478bd9Sstevel@tonic-gate  * the structure in any way.
650*7c478bd9Sstevel@tonic-gate  */
651*7c478bd9Sstevel@tonic-gate static int
652*7c478bd9Sstevel@tonic-gate disconnectCon(__nis_ldap_conn_t *lc) {
653*7c478bd9Sstevel@tonic-gate 	int	stat;
654*7c478bd9Sstevel@tonic-gate 	char	*myself = "disconnectCon";
655*7c478bd9Sstevel@tonic-gate 
656*7c478bd9Sstevel@tonic-gate 	if (lc == 0)
657*7c478bd9Sstevel@tonic-gate 		return (LDAP_SUCCESS);
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 	if (!assertExclusive(lc))
660*7c478bd9Sstevel@tonic-gate 		return (LDAP_UNAVAILABLE);
661*7c478bd9Sstevel@tonic-gate 
662*7c478bd9Sstevel@tonic-gate 	if (lc->doDis) {
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 		/* Increment refCount to protect against interference */
665*7c478bd9Sstevel@tonic-gate 		incrementRC(lc);
666*7c478bd9Sstevel@tonic-gate 		/* refCount must be one (i.e., just us) */
667*7c478bd9Sstevel@tonic-gate 		if (lc->refCount != 1) {
668*7c478bd9Sstevel@tonic-gate 			/*
669*7c478bd9Sstevel@tonic-gate 			 * In use; already marked for disconnect,
670*7c478bd9Sstevel@tonic-gate 			 * so do nothing.
671*7c478bd9Sstevel@tonic-gate 			 */
672*7c478bd9Sstevel@tonic-gate 			decrementRC(lc);
673*7c478bd9Sstevel@tonic-gate 			return (LDAP_BUSY);
674*7c478bd9Sstevel@tonic-gate 		}
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate 		stat = ldap_unbind_s(lc->ld);
677*7c478bd9Sstevel@tonic-gate 		if (stat == LDAP_SUCCESS) {
678*7c478bd9Sstevel@tonic-gate 			lc->ld = 0;
679*7c478bd9Sstevel@tonic-gate 			lc->isBound = 0;
680*7c478bd9Sstevel@tonic-gate 			lc->doDis = 0;
681*7c478bd9Sstevel@tonic-gate 			/* Reset simple page and vlv indication */
682*7c478bd9Sstevel@tonic-gate 			lc->simplePage = 0;
683*7c478bd9Sstevel@tonic-gate 			lc->vlv = 0;
684*7c478bd9Sstevel@tonic-gate 		} else if (verbose) {
685*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_ERR,
686*7c478bd9Sstevel@tonic-gate 				"%s: ldap_unbind_s() => %d (%s)",
687*7c478bd9Sstevel@tonic-gate 				myself, stat, ldap_err2string(stat));
688*7c478bd9Sstevel@tonic-gate 		}
689*7c478bd9Sstevel@tonic-gate 
690*7c478bd9Sstevel@tonic-gate 		decrementRC(lc);
691*7c478bd9Sstevel@tonic-gate 	}
692*7c478bd9Sstevel@tonic-gate 
693*7c478bd9Sstevel@tonic-gate 	if (lc->doDel) {
694*7c478bd9Sstevel@tonic-gate 		if (LDAP_UNAVAILABLE == freeCon(lc))
695*7c478bd9Sstevel@tonic-gate 			stat = LDAP_UNAVAILABLE;
696*7c478bd9Sstevel@tonic-gate 	}
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	return (stat);
699*7c478bd9Sstevel@tonic-gate }
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate /*
702*7c478bd9Sstevel@tonic-gate  * controlSupported will determine for a given connection whether a set
703*7c478bd9Sstevel@tonic-gate  * of controls is supported or not. The input parameters:
704*7c478bd9Sstevel@tonic-gate  *	lc	The connection
705*7c478bd9Sstevel@tonic-gate  *	ctrl	A an array of OID strings, the terminal string should be NULL
706*7c478bd9Sstevel@tonic-gate  * The returned values if LDAP_SUCCESS is returned:
707*7c478bd9Sstevel@tonic-gate  *	supported	A caller supplied array which will be set to TRUE or
708*7c478bd9Sstevel@tonic-gate  *			FALSE depending on whether the corresponding control
709*7c478bd9Sstevel@tonic-gate  *			is reported as supported.
710*7c478bd9Sstevel@tonic-gate  * Returns LDAP_SUCCESS if the supportedControl attribute is read.
711*7c478bd9Sstevel@tonic-gate  */
712*7c478bd9Sstevel@tonic-gate 
713*7c478bd9Sstevel@tonic-gate static int
714*7c478bd9Sstevel@tonic-gate controlSupported(__nis_ldap_conn_t *lc, char **ctrl, bool_t *supported) {
715*7c478bd9Sstevel@tonic-gate 	LDAPMessage	*res, *e;
716*7c478bd9Sstevel@tonic-gate 	char		*attr[2], *a, **val;
717*7c478bd9Sstevel@tonic-gate 	int		stat, i;
718*7c478bd9Sstevel@tonic-gate 	BerElement	*ber = 0;
719*7c478bd9Sstevel@tonic-gate 	char		*myself = "controlSupported";
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 	attr[0] = "supportedControl";
722*7c478bd9Sstevel@tonic-gate 	attr[1] = 0;
723*7c478bd9Sstevel@tonic-gate 
724*7c478bd9Sstevel@tonic-gate 	stat = ldap_search_st(lc->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
725*7c478bd9Sstevel@tonic-gate 				attr, 0, &lc->searchTimeout, &res);
726*7c478bd9Sstevel@tonic-gate 	if (stat != LDAP_SUCCESS) {
727*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_WARNING,
728*7c478bd9Sstevel@tonic-gate 	"%s: Unable to retrieve supported control information for %s: %s",
729*7c478bd9Sstevel@tonic-gate 			myself, NIL(lc->sp), ldap_err2string(stat));
730*7c478bd9Sstevel@tonic-gate 		return (stat);
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	e = ldap_first_entry(lc->ld, res);
734*7c478bd9Sstevel@tonic-gate 	if (e != 0) {
735*7c478bd9Sstevel@tonic-gate 		a = ldap_first_attribute(lc->ld, e, &ber);
736*7c478bd9Sstevel@tonic-gate 		if (a != 0) {
737*7c478bd9Sstevel@tonic-gate 			val = ldap_get_values(lc->ld, e, a);
738*7c478bd9Sstevel@tonic-gate 			if (val == 0) {
739*7c478bd9Sstevel@tonic-gate 				ldap_memfree(a);
740*7c478bd9Sstevel@tonic-gate 				if (ber != 0)
741*7c478bd9Sstevel@tonic-gate 					ber_free(ber, 0);
742*7c478bd9Sstevel@tonic-gate 			}
743*7c478bd9Sstevel@tonic-gate 		}
744*7c478bd9Sstevel@tonic-gate 	}
745*7c478bd9Sstevel@tonic-gate 	if (e == 0 || a == 0 || val == 0) {
746*7c478bd9Sstevel@tonic-gate 		ldap_msgfree(res);
747*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
748*7c478bd9Sstevel@tonic-gate 			"%s: Unable to get root DSE for %s",
749*7c478bd9Sstevel@tonic-gate 			myself, NIL(lc->sp));
750*7c478bd9Sstevel@tonic-gate 		return (LDAP_OPERATIONS_ERROR);
751*7c478bd9Sstevel@tonic-gate 	}
752*7c478bd9Sstevel@tonic-gate 
753*7c478bd9Sstevel@tonic-gate 	while (*ctrl != NULL) {
754*7c478bd9Sstevel@tonic-gate 		*supported = FALSE;
755*7c478bd9Sstevel@tonic-gate 		for (i = 0; val[i] != 0; i++) {
756*7c478bd9Sstevel@tonic-gate 			if (strstr(val[i], *ctrl) != 0) {
757*7c478bd9Sstevel@tonic-gate 				*supported = TRUE;
758*7c478bd9Sstevel@tonic-gate 				break;
759*7c478bd9Sstevel@tonic-gate 			}
760*7c478bd9Sstevel@tonic-gate 		}
761*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
762*7c478bd9Sstevel@tonic-gate 			"%s: %s: %s: %s",
763*7c478bd9Sstevel@tonic-gate 			myself, NIL(lc->sp), NIL(*ctrl),
764*7c478bd9Sstevel@tonic-gate 			*supported ? "enabled" : "disabled");
765*7c478bd9Sstevel@tonic-gate 		ctrl++;
766*7c478bd9Sstevel@tonic-gate 		supported++;
767*7c478bd9Sstevel@tonic-gate 	}
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	ldap_value_free(val);
770*7c478bd9Sstevel@tonic-gate 	ldap_memfree(a);
771*7c478bd9Sstevel@tonic-gate 	if (ber != 0)
772*7c478bd9Sstevel@tonic-gate 		ber_free(ber, 0);
773*7c478bd9Sstevel@tonic-gate 	ldap_msgfree(res);
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate 	return (stat);
776*7c478bd9Sstevel@tonic-gate }
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate /*
779*7c478bd9Sstevel@tonic-gate  * Connect the LDAP connection 'lc'. Caller must have acquired the 'mutex',
780*7c478bd9Sstevel@tonic-gate  * and the refCount must be zero.
781*7c478bd9Sstevel@tonic-gate  *
782*7c478bd9Sstevel@tonic-gate  * On return, if the status is LDAP_UNAVAILABLE, the caller must not touch
783*7c478bd9Sstevel@tonic-gate  * the structure in any way.
784*7c478bd9Sstevel@tonic-gate  */
785*7c478bd9Sstevel@tonic-gate static int
786*7c478bd9Sstevel@tonic-gate connectCon(__nis_ldap_conn_t *lc, int check_ctrl) {
787*7c478bd9Sstevel@tonic-gate 	struct timeval	tp;
788*7c478bd9Sstevel@tonic-gate 	int		stat;
789*7c478bd9Sstevel@tonic-gate 	bool_t		supported[2] = {FALSE, FALSE};
790*7c478bd9Sstevel@tonic-gate 	char		*ctrl[3] = {LDAP_CONTROL_SIMPLE_PAGE,
791*7c478bd9Sstevel@tonic-gate 					LDAP_CONTROL_VLVREQUEST,
792*7c478bd9Sstevel@tonic-gate 					NULL};
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 	if (lc == 0)
795*7c478bd9Sstevel@tonic-gate 		return (LDAP_SUCCESS);
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 	if (!assertExclusive(lc))
798*7c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	incrementRC(lc);
801*7c478bd9Sstevel@tonic-gate 	if (lc->refCount != 1) {
802*7c478bd9Sstevel@tonic-gate 		/*
803*7c478bd9Sstevel@tonic-gate 		 * Don't want to step on structure when it's used by someone
804*7c478bd9Sstevel@tonic-gate 		 * else.
805*7c478bd9Sstevel@tonic-gate 		 */
806*7c478bd9Sstevel@tonic-gate 		decrementRC(lc);
807*7c478bd9Sstevel@tonic-gate 		return (LDAP_BUSY);
808*7c478bd9Sstevel@tonic-gate 	}
809*7c478bd9Sstevel@tonic-gate 
810*7c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&tp, 0);
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 	if (lc->ld != 0) {
813*7c478bd9Sstevel@tonic-gate 		/* Try to disconnect */
814*7c478bd9Sstevel@tonic-gate 		lc->doDis++;
815*7c478bd9Sstevel@tonic-gate 		decrementRC(lc);
816*7c478bd9Sstevel@tonic-gate 		/* disconnctCon() will do the delete if required */
817*7c478bd9Sstevel@tonic-gate 		stat = disconnectCon(lc);
818*7c478bd9Sstevel@tonic-gate 		if (stat != LDAP_SUCCESS)
819*7c478bd9Sstevel@tonic-gate 			return (stat);
820*7c478bd9Sstevel@tonic-gate 		incrementRC(lc);
821*7c478bd9Sstevel@tonic-gate 		if (lc->refCount != 1 || lc->ld != 0) {
822*7c478bd9Sstevel@tonic-gate 			decrementRC(lc);
823*7c478bd9Sstevel@tonic-gate 			return (lc->ld != 0) ? LDAP_SUCCESS :
824*7c478bd9Sstevel@tonic-gate 						LDAP_BUSY;
825*7c478bd9Sstevel@tonic-gate 		}
826*7c478bd9Sstevel@tonic-gate 	} else if (tp.tv_sec < lc->retryTime) {
827*7c478bd9Sstevel@tonic-gate 		/* Too early to retry connect */
828*7c478bd9Sstevel@tonic-gate 		decrementRC(lc);
829*7c478bd9Sstevel@tonic-gate 		return (LDAP_SERVER_DOWN);
830*7c478bd9Sstevel@tonic-gate 	}
831*7c478bd9Sstevel@tonic-gate 
832*7c478bd9Sstevel@tonic-gate 	/* Set new retry time in case we fail below */
833*7c478bd9Sstevel@tonic-gate 	lc->retryTime = tp.tv_sec + ldapConnAttemptRetryTimeout;
834*7c478bd9Sstevel@tonic-gate 
835*7c478bd9Sstevel@tonic-gate 	lc->ld = ldapInit(lc->sp, lc->port, proxyInfo.tls_method != no_tls);
836*7c478bd9Sstevel@tonic-gate 	if (lc->ld == 0) {
837*7c478bd9Sstevel@tonic-gate 		decrementRC(lc);
838*7c478bd9Sstevel@tonic-gate 		return (LDAP_LOCAL_ERROR);
839*7c478bd9Sstevel@tonic-gate 	}
840*7c478bd9Sstevel@tonic-gate 
841*7c478bd9Sstevel@tonic-gate 	stat = lc->status = ldapBind(&lc->ld, lc->who, lc->cred, lc->method,
842*7c478bd9Sstevel@tonic-gate 		lc->bindTimeout);
843*7c478bd9Sstevel@tonic-gate 	if (lc->status == LDAP_SUCCESS) {
844*7c478bd9Sstevel@tonic-gate 		lc->isBound = 1;
845*7c478bd9Sstevel@tonic-gate 		lc->retryTime = 0;
846*7c478bd9Sstevel@tonic-gate 		if (check_ctrl) {
847*7c478bd9Sstevel@tonic-gate 			(void) controlSupported(lc, ctrl, supported);
848*7c478bd9Sstevel@tonic-gate 			lc->simplePage = supported[0];
849*7c478bd9Sstevel@tonic-gate 			lc->vlv = supported[1];
850*7c478bd9Sstevel@tonic-gate 			lc->batchFrom = 50000;
851*7c478bd9Sstevel@tonic-gate 		}
852*7c478bd9Sstevel@tonic-gate 	}
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	decrementRC(lc);
855*7c478bd9Sstevel@tonic-gate 
856*7c478bd9Sstevel@tonic-gate 	return (stat);
857*7c478bd9Sstevel@tonic-gate }
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate /*
860*7c478bd9Sstevel@tonic-gate  * Find and return a connection believed to be OK.
861*7c478bd9Sstevel@tonic-gate  */
862*7c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t *
863*7c478bd9Sstevel@tonic-gate findCon(int *stat) {
864*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc;
865*7c478bd9Sstevel@tonic-gate 	int			ldapStat;
866*7c478bd9Sstevel@tonic-gate 	char			*myself = "findCon";
867*7c478bd9Sstevel@tonic-gate 
868*7c478bd9Sstevel@tonic-gate 	if (stat == 0)
869*7c478bd9Sstevel@tonic-gate 		stat = &ldapStat;
870*7c478bd9Sstevel@tonic-gate 
871*7c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&ldapConLock);
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	if (ldapCon == 0) {
874*7c478bd9Sstevel@tonic-gate 		/* Probably first call; try to set up the connection list */
875*7c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ldapConLock);
876*7c478bd9Sstevel@tonic-gate 		if ((*stat = setupConList(proxyInfo.default_servers,
877*7c478bd9Sstevel@tonic-gate 					proxyInfo.proxy_dn,
878*7c478bd9Sstevel@tonic-gate 					proxyInfo.proxy_passwd,
879*7c478bd9Sstevel@tonic-gate 					proxyInfo.auth_method)) !=
880*7c478bd9Sstevel@tonic-gate 					LDAP_SUCCESS)
881*7c478bd9Sstevel@tonic-gate 			return (0);
882*7c478bd9Sstevel@tonic-gate 		(void) rw_rdlock(&ldapConLock);
883*7c478bd9Sstevel@tonic-gate 	}
884*7c478bd9Sstevel@tonic-gate 
885*7c478bd9Sstevel@tonic-gate 	for (lc = ldapCon; lc != 0; lc = lc->next) {
886*7c478bd9Sstevel@tonic-gate 		exclusiveLC(lc);
887*7c478bd9Sstevel@tonic-gate 		if (!lc->isBound) {
888*7c478bd9Sstevel@tonic-gate 			*stat = connectCon(lc, 1);
889*7c478bd9Sstevel@tonic-gate 			if (*stat != LDAP_SUCCESS) {
890*7c478bd9Sstevel@tonic-gate 				if (*stat != LDAP_UNAVAILABLE) {
891*7c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
892*7c478bd9Sstevel@tonic-gate 		"%s: Cannot open connection to LDAP server (%s): %s",
893*7c478bd9Sstevel@tonic-gate 						myself, NIL(lc->sp),
894*7c478bd9Sstevel@tonic-gate 						ldap_err2string(*stat));
895*7c478bd9Sstevel@tonic-gate 					releaseLC(lc);
896*7c478bd9Sstevel@tonic-gate 				}
897*7c478bd9Sstevel@tonic-gate 				continue;
898*7c478bd9Sstevel@tonic-gate 			}
899*7c478bd9Sstevel@tonic-gate 		} else if (lc->doDis || lc->doDel) {
900*7c478bd9Sstevel@tonic-gate 			*stat = disconnectCon(lc);
901*7c478bd9Sstevel@tonic-gate 			if (*stat != LDAP_UNAVAILABLE)
902*7c478bd9Sstevel@tonic-gate 				releaseLC(lc);
903*7c478bd9Sstevel@tonic-gate 			continue;
904*7c478bd9Sstevel@tonic-gate 		}
905*7c478bd9Sstevel@tonic-gate 		incrementRC(lc);
906*7c478bd9Sstevel@tonic-gate 		releaseLC(lc);
907*7c478bd9Sstevel@tonic-gate 		break;
908*7c478bd9Sstevel@tonic-gate 	}
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&ldapConLock);
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	return (lc);
913*7c478bd9Sstevel@tonic-gate }
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate /* Release connection; decrements ref count for the connection */
916*7c478bd9Sstevel@tonic-gate static void
917*7c478bd9Sstevel@tonic-gate releaseCon(__nis_ldap_conn_t *lc, int status) {
918*7c478bd9Sstevel@tonic-gate 	int	stat;
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 	if (lc == 0)
921*7c478bd9Sstevel@tonic-gate 		return;
922*7c478bd9Sstevel@tonic-gate 
923*7c478bd9Sstevel@tonic-gate 	exclusiveLC(lc);
924*7c478bd9Sstevel@tonic-gate 
925*7c478bd9Sstevel@tonic-gate 	lc->status = status;
926*7c478bd9Sstevel@tonic-gate 
927*7c478bd9Sstevel@tonic-gate 	decrementRC(lc);
928*7c478bd9Sstevel@tonic-gate 
929*7c478bd9Sstevel@tonic-gate 	if (lc->doDis)
930*7c478bd9Sstevel@tonic-gate 		stat = disconnectCon(lc);
931*7c478bd9Sstevel@tonic-gate 	else
932*7c478bd9Sstevel@tonic-gate 		stat = LDAP_SUCCESS;
933*7c478bd9Sstevel@tonic-gate 
934*7c478bd9Sstevel@tonic-gate 	if (stat != LDAP_UNAVAILABLE)
935*7c478bd9Sstevel@tonic-gate 		releaseLC(lc);
936*7c478bd9Sstevel@tonic-gate }
937*7c478bd9Sstevel@tonic-gate 
938*7c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t *
939*7c478bd9Sstevel@tonic-gate createCon(char *sp, char *who, char *cred, auth_method_t method, int port) {
940*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc;
941*7c478bd9Sstevel@tonic-gate 	char			*myself = "createCon";
942*7c478bd9Sstevel@tonic-gate 	char			*r;
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate 	if (sp == 0)
945*7c478bd9Sstevel@tonic-gate 		return (0);
946*7c478bd9Sstevel@tonic-gate 
947*7c478bd9Sstevel@tonic-gate 	lc = am(myself, sizeof (*lc));
948*7c478bd9Sstevel@tonic-gate 	if (lc == 0)
949*7c478bd9Sstevel@tonic-gate 		return (0);
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&lc->mutex, 0, 0);
952*7c478bd9Sstevel@tonic-gate 	(void) mutex_init(&lc->rcMutex, 0, 0);
953*7c478bd9Sstevel@tonic-gate 
954*7c478bd9Sstevel@tonic-gate 	/* If we need to delete 'lc', freeCon() wants the mutex held */
955*7c478bd9Sstevel@tonic-gate 	exclusiveLC(lc);
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	lc->sp = sdup(myself, T, sp);
958*7c478bd9Sstevel@tonic-gate 	if (lc->sp == 0) {
959*7c478bd9Sstevel@tonic-gate 		(void) freeCon(lc);
960*7c478bd9Sstevel@tonic-gate 		return (0);
961*7c478bd9Sstevel@tonic-gate 	}
962*7c478bd9Sstevel@tonic-gate 
963*7c478bd9Sstevel@tonic-gate 	if ((r = strchr(lc->sp, ']')) != 0) {
964*7c478bd9Sstevel@tonic-gate 		/*
965*7c478bd9Sstevel@tonic-gate 		 * IPv6 address. Does libldap want this with the
966*7c478bd9Sstevel@tonic-gate 		 * '[' and ']' left in place ? Assume so for now.
967*7c478bd9Sstevel@tonic-gate 		 */
968*7c478bd9Sstevel@tonic-gate 		r = strchr(r, ':');
969*7c478bd9Sstevel@tonic-gate 	} else {
970*7c478bd9Sstevel@tonic-gate 		r = strchr(lc->sp, ':');
971*7c478bd9Sstevel@tonic-gate 	}
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	if (r != NULL) {
974*7c478bd9Sstevel@tonic-gate 		*r++ = '\0';
975*7c478bd9Sstevel@tonic-gate 		port = atoi(r);
976*7c478bd9Sstevel@tonic-gate 	} else if (port == 0)
977*7c478bd9Sstevel@tonic-gate 		port = proxyInfo.tls_method == ssl_tls ? LDAPS_PORT : LDAP_PORT;
978*7c478bd9Sstevel@tonic-gate 
979*7c478bd9Sstevel@tonic-gate 	if (who != 0) {
980*7c478bd9Sstevel@tonic-gate 		lc->who = sdup(myself, T, who);
981*7c478bd9Sstevel@tonic-gate 		if (lc->who == 0) {
982*7c478bd9Sstevel@tonic-gate 			(void) freeCon(lc);
983*7c478bd9Sstevel@tonic-gate 			return (0);
984*7c478bd9Sstevel@tonic-gate 		}
985*7c478bd9Sstevel@tonic-gate 	}
986*7c478bd9Sstevel@tonic-gate 
987*7c478bd9Sstevel@tonic-gate 	if (cred != 0) {
988*7c478bd9Sstevel@tonic-gate 		lc->cred = sdup(myself, T, cred);
989*7c478bd9Sstevel@tonic-gate 		if (lc->cred == 0) {
990*7c478bd9Sstevel@tonic-gate 			(void) freeCon(lc);
991*7c478bd9Sstevel@tonic-gate 			return (0);
992*7c478bd9Sstevel@tonic-gate 		}
993*7c478bd9Sstevel@tonic-gate 	}
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 	lc->method = method;
996*7c478bd9Sstevel@tonic-gate 	lc->port = port;
997*7c478bd9Sstevel@tonic-gate 
998*7c478bd9Sstevel@tonic-gate 	lc->bindTimeout = proxyInfo.bind_timeout;
999*7c478bd9Sstevel@tonic-gate 	lc->searchTimeout = proxyInfo.search_timeout;
1000*7c478bd9Sstevel@tonic-gate 	lc->modifyTimeout = proxyInfo.modify_timeout;
1001*7c478bd9Sstevel@tonic-gate 	lc->addTimeout = proxyInfo.add_timeout;
1002*7c478bd9Sstevel@tonic-gate 	lc->deleteTimeout = proxyInfo.delete_timeout;
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 	/* All other fields OK at zero */
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate 	releaseLC(lc);
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 	return (lc);
1009*7c478bd9Sstevel@tonic-gate }
1010*7c478bd9Sstevel@tonic-gate 
1011*7c478bd9Sstevel@tonic-gate static int
1012*7c478bd9Sstevel@tonic-gate setupConList(char *serverList, char *who, char *cred, auth_method_t method) {
1013*7c478bd9Sstevel@tonic-gate 	char			*sls, *sl, *s, *e;
1014*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc, *tmp;
1015*7c478bd9Sstevel@tonic-gate 	char			*myself = "setupConList";
1016*7c478bd9Sstevel@tonic-gate 
1017*7c478bd9Sstevel@tonic-gate 	if (serverList == 0)
1018*7c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
1019*7c478bd9Sstevel@tonic-gate 
1020*7c478bd9Sstevel@tonic-gate 	(void) rw_wrlock(&ldapConLock);
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 	if (ldapCon != 0) {
1023*7c478bd9Sstevel@tonic-gate 		/* Assume we've already been called and done the set-up */
1024*7c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ldapConLock);
1025*7c478bd9Sstevel@tonic-gate 		return (LDAP_SUCCESS);
1026*7c478bd9Sstevel@tonic-gate 	}
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate 	/* Work on a copy of 'serverList' */
1029*7c478bd9Sstevel@tonic-gate 	sl = sls = sdup(myself, T, serverList);
1030*7c478bd9Sstevel@tonic-gate 	if (sl == 0) {
1031*7c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ldapConLock);
1032*7c478bd9Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
1033*7c478bd9Sstevel@tonic-gate 	}
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	/* Remove leading white space */
1036*7c478bd9Sstevel@tonic-gate 	for (0; *sl == ' ' || *sl == '\t'; sl++);
1037*7c478bd9Sstevel@tonic-gate 
1038*7c478bd9Sstevel@tonic-gate 	/* Create connection for each server on the list */
1039*7c478bd9Sstevel@tonic-gate 	for (s = sl; *s != '\0'; s = e+1) {
1040*7c478bd9Sstevel@tonic-gate 		int	l;
1041*7c478bd9Sstevel@tonic-gate 
1042*7c478bd9Sstevel@tonic-gate 		/* Find end of server/port token */
1043*7c478bd9Sstevel@tonic-gate 		for (e = s; *e != ' ' && *e != '\t' && *e != '\0'; e++);
1044*7c478bd9Sstevel@tonic-gate 		if (*e != '\0')
1045*7c478bd9Sstevel@tonic-gate 			*e = '\0';
1046*7c478bd9Sstevel@tonic-gate 		else
1047*7c478bd9Sstevel@tonic-gate 			e--;
1048*7c478bd9Sstevel@tonic-gate 		l = slen(s);
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 		if (l > 0) {
1051*7c478bd9Sstevel@tonic-gate 			lc = createCon(s, who, cred, method, 0);
1052*7c478bd9Sstevel@tonic-gate 			if (lc == 0) {
1053*7c478bd9Sstevel@tonic-gate 				free(sls);
1054*7c478bd9Sstevel@tonic-gate 				(void) rw_unlock(&ldapConLock);
1055*7c478bd9Sstevel@tonic-gate 				return (LDAP_NO_MEMORY);
1056*7c478bd9Sstevel@tonic-gate 			}
1057*7c478bd9Sstevel@tonic-gate 			lc->onList = 1;
1058*7c478bd9Sstevel@tonic-gate 			if (ldapCon == 0) {
1059*7c478bd9Sstevel@tonic-gate 				ldapCon = lc;
1060*7c478bd9Sstevel@tonic-gate 			} else {
1061*7c478bd9Sstevel@tonic-gate 				/* Insert at end of list */
1062*7c478bd9Sstevel@tonic-gate 				for (tmp = ldapCon; tmp->next != 0;
1063*7c478bd9Sstevel@tonic-gate 					tmp = tmp->next);
1064*7c478bd9Sstevel@tonic-gate 				tmp->next = lc;
1065*7c478bd9Sstevel@tonic-gate 			}
1066*7c478bd9Sstevel@tonic-gate 		}
1067*7c478bd9Sstevel@tonic-gate 	}
1068*7c478bd9Sstevel@tonic-gate 
1069*7c478bd9Sstevel@tonic-gate 	free(sls);
1070*7c478bd9Sstevel@tonic-gate 
1071*7c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&ldapConLock);
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	return (LDAP_SUCCESS);
1074*7c478bd9Sstevel@tonic-gate }
1075*7c478bd9Sstevel@tonic-gate 
1076*7c478bd9Sstevel@tonic-gate static bool_t
1077*7c478bd9Sstevel@tonic-gate is_same_connection(__nis_ldap_conn_t *lc, LDAPURLDesc *ludpp)
1078*7c478bd9Sstevel@tonic-gate {
1079*7c478bd9Sstevel@tonic-gate 	return (strcasecmp(ludpp->lud_host, lc->sp) == 0 &&
1080*7c478bd9Sstevel@tonic-gate 		ludpp->lud_port == lc->port);
1081*7c478bd9Sstevel@tonic-gate }
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t *
1084*7c478bd9Sstevel@tonic-gate find_connection_from_list(__nis_ldap_conn_t *list,
1085*7c478bd9Sstevel@tonic-gate 			LDAPURLDesc *ludpp, int *stat)
1086*7c478bd9Sstevel@tonic-gate {
1087*7c478bd9Sstevel@tonic-gate 	int			ldapStat;
1088*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc	= NULL;
1089*7c478bd9Sstevel@tonic-gate 	if (stat == 0)
1090*7c478bd9Sstevel@tonic-gate 		stat = &ldapStat;
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	*stat = LDAP_SUCCESS;
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	for (lc = list; lc != 0; lc = lc->next) {
1095*7c478bd9Sstevel@tonic-gate 		exclusiveLC(lc);
1096*7c478bd9Sstevel@tonic-gate 		if (is_same_connection(lc, ludpp)) {
1097*7c478bd9Sstevel@tonic-gate 			if (!lc->isBound) {
1098*7c478bd9Sstevel@tonic-gate 				*stat = connectCon(lc, 1);
1099*7c478bd9Sstevel@tonic-gate 				if (*stat != LDAP_SUCCESS) {
1100*7c478bd9Sstevel@tonic-gate 					releaseLC(lc);
1101*7c478bd9Sstevel@tonic-gate 					continue;
1102*7c478bd9Sstevel@tonic-gate 				}
1103*7c478bd9Sstevel@tonic-gate 			} else if (lc->doDis || lc->doDel) {
1104*7c478bd9Sstevel@tonic-gate 				(void) disconnectCon(lc);
1105*7c478bd9Sstevel@tonic-gate 				releaseLC(lc);
1106*7c478bd9Sstevel@tonic-gate 				continue;
1107*7c478bd9Sstevel@tonic-gate 			}
1108*7c478bd9Sstevel@tonic-gate 			incrementRC(lc);
1109*7c478bd9Sstevel@tonic-gate 			releaseLC(lc);
1110*7c478bd9Sstevel@tonic-gate 			break;
1111*7c478bd9Sstevel@tonic-gate 		}
1112*7c478bd9Sstevel@tonic-gate 		releaseLC(lc);
1113*7c478bd9Sstevel@tonic-gate 	}
1114*7c478bd9Sstevel@tonic-gate 	return (lc);
1115*7c478bd9Sstevel@tonic-gate }
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t *
1118*7c478bd9Sstevel@tonic-gate findReferralCon(char **referralsp, int *stat)
1119*7c478bd9Sstevel@tonic-gate {
1120*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc	= NULL;
1121*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*tmp;
1122*7c478bd9Sstevel@tonic-gate 	int			ldapStat;
1123*7c478bd9Sstevel@tonic-gate 	int			i;
1124*7c478bd9Sstevel@tonic-gate 	LDAPURLDesc		*ludpp	= NULL;
1125*7c478bd9Sstevel@tonic-gate 	char			*myself = "findReferralCon";
1126*7c478bd9Sstevel@tonic-gate 
1127*7c478bd9Sstevel@tonic-gate 	if (stat == 0)
1128*7c478bd9Sstevel@tonic-gate 		stat = &ldapStat;
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 	*stat = LDAP_SUCCESS;
1131*7c478bd9Sstevel@tonic-gate 
1132*7c478bd9Sstevel@tonic-gate 	/*
1133*7c478bd9Sstevel@tonic-gate 	 * We have the referral lock - to prevent multiple
1134*7c478bd9Sstevel@tonic-gate 	 * threads from creating a referred connection simultaneously
1135*7c478bd9Sstevel@tonic-gate 	 *
1136*7c478bd9Sstevel@tonic-gate 	 * Note that this code assumes that the ldapCon list is a
1137*7c478bd9Sstevel@tonic-gate 	 * static list - that it has previously been created
1138*7c478bd9Sstevel@tonic-gate 	 * (otherwise we wouldn't have gotten a referral) and that
1139*7c478bd9Sstevel@tonic-gate 	 * it will neither grow or shrink - elements may have new
1140*7c478bd9Sstevel@tonic-gate 	 * connections or unbound. If this assumption is no longer valid,
1141*7c478bd9Sstevel@tonic-gate 	 * the locking needs to be reworked.
1142*7c478bd9Sstevel@tonic-gate 	 */
1143*7c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&referralConLock);
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate 	for (i = 0; referralsp[i] != NULL; i++) {
1146*7c478bd9Sstevel@tonic-gate 		if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS)
1147*7c478bd9Sstevel@tonic-gate 			continue;
1148*7c478bd9Sstevel@tonic-gate 		/* Ignore referrals if not at the appropriate tls level */
1149*7c478bd9Sstevel@tonic-gate #ifdef LDAP_URL_OPT_SECURE
1150*7c478bd9Sstevel@tonic-gate 		if (ludpp->lud_options & LDAP_URL_OPT_SECURE) {
1151*7c478bd9Sstevel@tonic-gate 			if (proxyInfo.tls_method != ssl_tls) {
1152*7c478bd9Sstevel@tonic-gate 				ldap_free_urldesc(ludpp);
1153*7c478bd9Sstevel@tonic-gate 				continue;
1154*7c478bd9Sstevel@tonic-gate 			}
1155*7c478bd9Sstevel@tonic-gate 		} else {
1156*7c478bd9Sstevel@tonic-gate 			if (proxyInfo.tls_method != no_tls) {
1157*7c478bd9Sstevel@tonic-gate 				ldap_free_urldesc(ludpp);
1158*7c478bd9Sstevel@tonic-gate 				continue;
1159*7c478bd9Sstevel@tonic-gate 			}
1160*7c478bd9Sstevel@tonic-gate 		}
1161*7c478bd9Sstevel@tonic-gate #endif
1162*7c478bd9Sstevel@tonic-gate 
1163*7c478bd9Sstevel@tonic-gate 		/* Determine if we already have a connection to the server */
1164*7c478bd9Sstevel@tonic-gate 		lc = find_connection_from_list(ldapReferralCon, ludpp, stat);
1165*7c478bd9Sstevel@tonic-gate 		if (lc == NULL)
1166*7c478bd9Sstevel@tonic-gate 			lc = find_connection_from_list(ldapCon, ludpp, stat);
1167*7c478bd9Sstevel@tonic-gate 		ldap_free_urldesc(ludpp);
1168*7c478bd9Sstevel@tonic-gate 		if (lc != NULL) {
1169*7c478bd9Sstevel@tonic-gate 			(void) rw_unlock(&referralConLock);
1170*7c478bd9Sstevel@tonic-gate 			return (lc);
1171*7c478bd9Sstevel@tonic-gate 		}
1172*7c478bd9Sstevel@tonic-gate 	}
1173*7c478bd9Sstevel@tonic-gate 
1174*7c478bd9Sstevel@tonic-gate 	for (i = 0; referralsp[i] != NULL; i++) {
1175*7c478bd9Sstevel@tonic-gate 		if (ldap_url_parse(referralsp[i], &ludpp) != LDAP_SUCCESS)
1176*7c478bd9Sstevel@tonic-gate 			continue;
1177*7c478bd9Sstevel@tonic-gate 		/* Ignore referrals if not at the appropriate tls level */
1178*7c478bd9Sstevel@tonic-gate #ifdef LDAP_URL_OPT_SECURE
1179*7c478bd9Sstevel@tonic-gate 		if (ludpp->lud_options & LDAP_URL_OPT_SECURE) {
1180*7c478bd9Sstevel@tonic-gate 			if (proxyInfo.tls_method != ssl_tls) {
1181*7c478bd9Sstevel@tonic-gate 				ldap_free_urldesc(ludpp);
1182*7c478bd9Sstevel@tonic-gate 				continue;
1183*7c478bd9Sstevel@tonic-gate 			}
1184*7c478bd9Sstevel@tonic-gate 		} else {
1185*7c478bd9Sstevel@tonic-gate 			if (proxyInfo.tls_method != no_tls) {
1186*7c478bd9Sstevel@tonic-gate 				ldap_free_urldesc(ludpp);
1187*7c478bd9Sstevel@tonic-gate 				continue;
1188*7c478bd9Sstevel@tonic-gate 			}
1189*7c478bd9Sstevel@tonic-gate 		}
1190*7c478bd9Sstevel@tonic-gate #endif
1191*7c478bd9Sstevel@tonic-gate 		lc = createCon(ludpp->lud_host, proxyInfo.proxy_dn,
1192*7c478bd9Sstevel@tonic-gate 					proxyInfo.proxy_passwd,
1193*7c478bd9Sstevel@tonic-gate 					proxyInfo.auth_method,
1194*7c478bd9Sstevel@tonic-gate 					ludpp->lud_port);
1195*7c478bd9Sstevel@tonic-gate 		if (lc == 0) {
1196*7c478bd9Sstevel@tonic-gate 			ldap_free_urldesc(ludpp);
1197*7c478bd9Sstevel@tonic-gate 			(void) rw_unlock(&referralConLock);
1198*7c478bd9Sstevel@tonic-gate 			*stat = LDAP_NO_MEMORY;
1199*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
1200*7c478bd9Sstevel@tonic-gate 				"%s: Could not connect to host: %s",
1201*7c478bd9Sstevel@tonic-gate 				myself, NIL(ludpp->lud_host));
1202*7c478bd9Sstevel@tonic-gate 			return (NULL);
1203*7c478bd9Sstevel@tonic-gate 		}
1204*7c478bd9Sstevel@tonic-gate 
1205*7c478bd9Sstevel@tonic-gate 		lc->onList = 1;
1206*7c478bd9Sstevel@tonic-gate 		if (ldapReferralCon == 0) {
1207*7c478bd9Sstevel@tonic-gate 			ldapReferralCon = lc;
1208*7c478bd9Sstevel@tonic-gate 		} else {
1209*7c478bd9Sstevel@tonic-gate 			/* Insert at end of list */
1210*7c478bd9Sstevel@tonic-gate 			for (tmp = ldapReferralCon; tmp->next != 0;
1211*7c478bd9Sstevel@tonic-gate 				tmp = tmp->next) {}
1212*7c478bd9Sstevel@tonic-gate 			tmp->next = lc;
1213*7c478bd9Sstevel@tonic-gate 		}
1214*7c478bd9Sstevel@tonic-gate 		lc = find_connection_from_list(ldapReferralCon, ludpp, stat);
1215*7c478bd9Sstevel@tonic-gate 		ldap_free_urldesc(ludpp);
1216*7c478bd9Sstevel@tonic-gate 		if (lc != NULL)
1217*7c478bd9Sstevel@tonic-gate 			break;
1218*7c478bd9Sstevel@tonic-gate 	}
1219*7c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&referralConLock);
1220*7c478bd9Sstevel@tonic-gate 	if (lc == NULL) {
1221*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
1222*7c478bd9Sstevel@tonic-gate 			"%s: Could not find a connection to %s, ...",
1223*7c478bd9Sstevel@tonic-gate 			myself, NIL(referralsp[0]));
1224*7c478bd9Sstevel@tonic-gate 	}
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	return (lc);
1227*7c478bd9Sstevel@tonic-gate }
1228*7c478bd9Sstevel@tonic-gate 
1229*7c478bd9Sstevel@tonic-gate /*
1230*7c478bd9Sstevel@tonic-gate  * Find and return a connection believed to be OK and ensure children
1231*7c478bd9Sstevel@tonic-gate  * will never use parent's connection.
1232*7c478bd9Sstevel@tonic-gate  */
1233*7c478bd9Sstevel@tonic-gate static __nis_ldap_conn_t *
1234*7c478bd9Sstevel@tonic-gate findYPCon(__nis_ldap_search_t *ls, int *stat) {
1235*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc, *newlc;
1236*7c478bd9Sstevel@tonic-gate 	int			ldapStat, newstat;
1237*7c478bd9Sstevel@tonic-gate 	char			*myself = "findYPCon";
1238*7c478bd9Sstevel@tonic-gate 
1239*7c478bd9Sstevel@tonic-gate 	if (stat == 0)
1240*7c478bd9Sstevel@tonic-gate 		stat = &ldapStat;
1241*7c478bd9Sstevel@tonic-gate 
1242*7c478bd9Sstevel@tonic-gate 	(void) rw_rdlock(&ldapConLock);
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	if (ldapCon == 0) {
1245*7c478bd9Sstevel@tonic-gate 		/* Probably first call; try to set up the connection list */
1246*7c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ldapConLock);
1247*7c478bd9Sstevel@tonic-gate 		if ((*stat = setupConList(proxyInfo.default_servers,
1248*7c478bd9Sstevel@tonic-gate 					proxyInfo.proxy_dn,
1249*7c478bd9Sstevel@tonic-gate 					proxyInfo.proxy_passwd,
1250*7c478bd9Sstevel@tonic-gate 					proxyInfo.auth_method)) !=
1251*7c478bd9Sstevel@tonic-gate 					LDAP_SUCCESS)
1252*7c478bd9Sstevel@tonic-gate 			return (0);
1253*7c478bd9Sstevel@tonic-gate 		(void) rw_rdlock(&ldapConLock);
1254*7c478bd9Sstevel@tonic-gate 	}
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 	for (lc = ldapCon; lc != 0; lc = lc->next) {
1257*7c478bd9Sstevel@tonic-gate 		exclusiveLC(lc);
1258*7c478bd9Sstevel@tonic-gate 
1259*7c478bd9Sstevel@tonic-gate 		if (lc->isBound && (lc->doDis || lc->doDel)) {
1260*7c478bd9Sstevel@tonic-gate 			*stat = disconnectCon(lc);
1261*7c478bd9Sstevel@tonic-gate 			if (*stat != LDAP_UNAVAILABLE)
1262*7c478bd9Sstevel@tonic-gate 				releaseLC(lc);
1263*7c478bd9Sstevel@tonic-gate 			continue;
1264*7c478bd9Sstevel@tonic-gate 		}
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 		/*
1267*7c478bd9Sstevel@tonic-gate 		 * Use a new connection for all cases except when
1268*7c478bd9Sstevel@tonic-gate 		 * requested by the main thread in the parent ypserv
1269*7c478bd9Sstevel@tonic-gate 		 * process.
1270*7c478bd9Sstevel@tonic-gate 		 */
1271*7c478bd9Sstevel@tonic-gate 		if (ls->useCon == 0) {
1272*7c478bd9Sstevel@tonic-gate 			newlc = createCon(lc->sp, lc->who, lc->cred,
1273*7c478bd9Sstevel@tonic-gate 						lc->method, lc->port);
1274*7c478bd9Sstevel@tonic-gate 			if (!newlc) {
1275*7c478bd9Sstevel@tonic-gate 				releaseLC(lc);
1276*7c478bd9Sstevel@tonic-gate 				continue;
1277*7c478bd9Sstevel@tonic-gate 			}
1278*7c478bd9Sstevel@tonic-gate 			if (lc->ld != 0) {
1279*7c478bd9Sstevel@tonic-gate 				newlc->simplePage = lc->simplePage;
1280*7c478bd9Sstevel@tonic-gate 				newlc->vlv = lc->vlv;
1281*7c478bd9Sstevel@tonic-gate 				newlc->batchFrom = lc->batchFrom;
1282*7c478bd9Sstevel@tonic-gate 			}
1283*7c478bd9Sstevel@tonic-gate 			releaseLC(lc);
1284*7c478bd9Sstevel@tonic-gate 			exclusiveLC(newlc);
1285*7c478bd9Sstevel@tonic-gate 			newstat = connectCon(newlc, 0);
1286*7c478bd9Sstevel@tonic-gate 			if (newstat != LDAP_SUCCESS) {
1287*7c478bd9Sstevel@tonic-gate 				if (newstat != LDAP_UNAVAILABLE) {
1288*7c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1289*7c478bd9Sstevel@tonic-gate 			"%s: Cannot open connection to LDAP server (%s): %s",
1290*7c478bd9Sstevel@tonic-gate 						myself, NIL(newlc->sp),
1291*7c478bd9Sstevel@tonic-gate 						ldap_err2string(*stat));
1292*7c478bd9Sstevel@tonic-gate 				}
1293*7c478bd9Sstevel@tonic-gate 				(void) freeCon(newlc);
1294*7c478bd9Sstevel@tonic-gate 				newlc = 0;
1295*7c478bd9Sstevel@tonic-gate 				continue;
1296*7c478bd9Sstevel@tonic-gate 			}
1297*7c478bd9Sstevel@tonic-gate 
1298*7c478bd9Sstevel@tonic-gate 			/*
1299*7c478bd9Sstevel@tonic-gate 			 * No need to put newlc on the ldapCon list as this
1300*7c478bd9Sstevel@tonic-gate 			 * connection will be freed after use.
1301*7c478bd9Sstevel@tonic-gate 			 */
1302*7c478bd9Sstevel@tonic-gate 			newlc->onList = 0;
1303*7c478bd9Sstevel@tonic-gate 
1304*7c478bd9Sstevel@tonic-gate 			lc = newlc;
1305*7c478bd9Sstevel@tonic-gate 		} else  if (!lc->isBound) {
1306*7c478bd9Sstevel@tonic-gate 			*stat = connectCon(lc, 1);
1307*7c478bd9Sstevel@tonic-gate 			if (*stat != LDAP_SUCCESS) {
1308*7c478bd9Sstevel@tonic-gate 				if (*stat != LDAP_UNAVAILABLE) {
1309*7c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1310*7c478bd9Sstevel@tonic-gate 		"%s: Cannot open connection to LDAP server (%s): %s",
1311*7c478bd9Sstevel@tonic-gate 						myself, NIL(lc->sp),
1312*7c478bd9Sstevel@tonic-gate 						ldap_err2string(*stat));
1313*7c478bd9Sstevel@tonic-gate 					releaseLC(lc);
1314*7c478bd9Sstevel@tonic-gate 				}
1315*7c478bd9Sstevel@tonic-gate 				continue;
1316*7c478bd9Sstevel@tonic-gate 			}
1317*7c478bd9Sstevel@tonic-gate 		}
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 		incrementRC(lc);
1320*7c478bd9Sstevel@tonic-gate 		releaseLC(lc);
1321*7c478bd9Sstevel@tonic-gate 		break;
1322*7c478bd9Sstevel@tonic-gate 	}
1323*7c478bd9Sstevel@tonic-gate 
1324*7c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&ldapConLock);
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 	return (lc);
1327*7c478bd9Sstevel@tonic-gate }
1328*7c478bd9Sstevel@tonic-gate 
1329*7c478bd9Sstevel@tonic-gate #define	SORTKEYLIST	"cn uid"
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate /*
1332*7c478bd9Sstevel@tonic-gate  * Perform an LDAP search operation per 'ls', adding the result(s) to
1333*7c478bd9Sstevel@tonic-gate  * a copy of the 'rvIn' structure; the copy becomes the return value.
1334*7c478bd9Sstevel@tonic-gate  * The caller must deallocate both 'rvIn' and the result, if any.
1335*7c478bd9Sstevel@tonic-gate  *
1336*7c478bd9Sstevel@tonic-gate  * On entry, '*numValues' contains a hint regarding the expected
1337*7c478bd9Sstevel@tonic-gate  * number of entries. Zero is the same as one, and negative values
1338*7c478bd9Sstevel@tonic-gate  * imply no information. This is used to decide whether or not to
1339*7c478bd9Sstevel@tonic-gate  * try an indexed search.
1340*7c478bd9Sstevel@tonic-gate  *
1341*7c478bd9Sstevel@tonic-gate  * On successful (non-NULL) return, '*numValues' contains the number
1342*7c478bd9Sstevel@tonic-gate  * of __nis_rule_value_t elements in the returned array, and '*stat'
1343*7c478bd9Sstevel@tonic-gate  * the LDAP operations status.
1344*7c478bd9Sstevel@tonic-gate  */
1345*7c478bd9Sstevel@tonic-gate __nis_rule_value_t *
1346*7c478bd9Sstevel@tonic-gate ldapSearch(__nis_ldap_search_t *ls, int *numValues, __nis_rule_value_t *rvIn,
1347*7c478bd9Sstevel@tonic-gate 		int *ldapStat) {
1348*7c478bd9Sstevel@tonic-gate 	__nis_rule_value_t	*rv = 0;
1349*7c478bd9Sstevel@tonic-gate 	int			stat, numEntries, numVals, tnv, done, lprEc;
1350*7c478bd9Sstevel@tonic-gate 	LDAPMessage		*msg = 0, *m;
1351*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc;
1352*7c478bd9Sstevel@tonic-gate 	struct timeval		tv, start, now;
1353*7c478bd9Sstevel@tonic-gate 	LDAPsortkey		**sortKeyList = 0;
1354*7c478bd9Sstevel@tonic-gate 	LDAPControl		*ctrls[3], *sortCtrl = 0, *vlvCtrl = 0;
1355*7c478bd9Sstevel@tonic-gate 	LDAPControl		**retCtrls = 0;
1356*7c478bd9Sstevel@tonic-gate 	LDAPVirtualList		vList;
1357*7c478bd9Sstevel@tonic-gate 	struct berval		*spCookie = 0;
1358*7c478bd9Sstevel@tonic-gate 	int			doVLV = 0;
1359*7c478bd9Sstevel@tonic-gate 	int			doSP = 0;
1360*7c478bd9Sstevel@tonic-gate 	long			index;
1361*7c478bd9Sstevel@tonic-gate 	char			*myself = "ldapSearch";
1362*7c478bd9Sstevel@tonic-gate 	bool_t			follow_referral =
1363*7c478bd9Sstevel@tonic-gate 					proxyInfo.follow_referral == follow;
1364*7c478bd9Sstevel@tonic-gate 	int			doIndex = 1;
1365*7c478bd9Sstevel@tonic-gate 	char			**referralsp = NULL;
1366*7c478bd9Sstevel@tonic-gate 
1367*7c478bd9Sstevel@tonic-gate 	if (ldapStat == 0)
1368*7c478bd9Sstevel@tonic-gate 		ldapStat = &stat;
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 	if (ls == 0) {
1371*7c478bd9Sstevel@tonic-gate 		*ldapStat = LDAP_PARAM_ERROR;
1372*7c478bd9Sstevel@tonic-gate 		return (0);
1373*7c478bd9Sstevel@tonic-gate 	}
1374*7c478bd9Sstevel@tonic-gate 
1375*7c478bd9Sstevel@tonic-gate 	if (yp2ldap) {
1376*7c478bd9Sstevel@tonic-gate 		/* make sure the parent's connection is not used by child */
1377*7c478bd9Sstevel@tonic-gate 		if ((lc = findYPCon(ls, ldapStat)) == 0) {
1378*7c478bd9Sstevel@tonic-gate 			*ldapStat = LDAP_SERVER_DOWN;
1379*7c478bd9Sstevel@tonic-gate 			return (0);
1380*7c478bd9Sstevel@tonic-gate 		}
1381*7c478bd9Sstevel@tonic-gate 	} else {
1382*7c478bd9Sstevel@tonic-gate 		if ((lc = findCon(ldapStat)) == 0) {
1383*7c478bd9Sstevel@tonic-gate 			*ldapStat = LDAP_SERVER_DOWN;
1384*7c478bd9Sstevel@tonic-gate 			return (0);
1385*7c478bd9Sstevel@tonic-gate 		}
1386*7c478bd9Sstevel@tonic-gate 	}
1387*7c478bd9Sstevel@tonic-gate 
1388*7c478bd9Sstevel@tonic-gate 	if (numValues != 0 && (*numValues == 0 || *numValues == 1))
1389*7c478bd9Sstevel@tonic-gate 		doIndex = 0;
1390*7c478bd9Sstevel@tonic-gate 
1391*7c478bd9Sstevel@tonic-gate retry_new_conn:
1392*7c478bd9Sstevel@tonic-gate 	/* Prefer VLV over simple page, and SP over nothing */
1393*7c478bd9Sstevel@tonic-gate 	if (doIndex && lc->vlv) {
1394*7c478bd9Sstevel@tonic-gate 		stat = ldap_create_sort_keylist(&sortKeyList, SORTKEYLIST);
1395*7c478bd9Sstevel@tonic-gate 		if (stat != LDAP_SUCCESS) {
1396*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
1397*7c478bd9Sstevel@tonic-gate 				"%s: Error creating sort keylist: %s",
1398*7c478bd9Sstevel@tonic-gate 				myself, ldap_err2string(stat));
1399*7c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
1400*7c478bd9Sstevel@tonic-gate 			*ldapStat = stat;
1401*7c478bd9Sstevel@tonic-gate 			rv = 0;
1402*7c478bd9Sstevel@tonic-gate 			goto retry_noVLV;
1403*7c478bd9Sstevel@tonic-gate 		}
1404*7c478bd9Sstevel@tonic-gate 		stat = ldap_create_sort_control(lc->ld, sortKeyList, 1,
1405*7c478bd9Sstevel@tonic-gate 						&sortCtrl);
1406*7c478bd9Sstevel@tonic-gate 		if (stat == LDAP_SUCCESS) {
1407*7c478bd9Sstevel@tonic-gate 			vList.ldvlist_before_count = 0;
1408*7c478bd9Sstevel@tonic-gate 			vList.ldvlist_after_count = lc->batchFrom - 1;
1409*7c478bd9Sstevel@tonic-gate 			vList.ldvlist_attrvalue = 0;
1410*7c478bd9Sstevel@tonic-gate 			vList.ldvlist_extradata = 0;
1411*7c478bd9Sstevel@tonic-gate 			index = 1;
1412*7c478bd9Sstevel@tonic-gate 			doVLV = 1;
1413*7c478bd9Sstevel@tonic-gate 		} else {
1414*7c478bd9Sstevel@tonic-gate 			ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
1415*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
1416*7c478bd9Sstevel@tonic-gate 				"%s: Error creating VLV sort control: %s",
1417*7c478bd9Sstevel@tonic-gate 				myself, ldap_err2string(stat));
1418*7c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
1419*7c478bd9Sstevel@tonic-gate 			*ldapStat = stat;
1420*7c478bd9Sstevel@tonic-gate 			rv = 0;
1421*7c478bd9Sstevel@tonic-gate 		}
1422*7c478bd9Sstevel@tonic-gate 	}
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate retry_noVLV:
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate 	if (doIndex && !doVLV && lc->simplePage) {
1427*7c478bd9Sstevel@tonic-gate 		spCookie = am(myself, sizeof (*spCookie));
1428*7c478bd9Sstevel@tonic-gate 		if (spCookie != 0 &&
1429*7c478bd9Sstevel@tonic-gate 				(spCookie->bv_val = sdup(myself, T, "")) != 0) {
1430*7c478bd9Sstevel@tonic-gate 			spCookie->bv_len = 0;
1431*7c478bd9Sstevel@tonic-gate 			doSP = 1;
1432*7c478bd9Sstevel@tonic-gate 		} else {
1433*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_INFO,
1434*7c478bd9Sstevel@tonic-gate 	"%s: No memory for simple page cookie; using un-paged LDAP search",
1435*7c478bd9Sstevel@tonic-gate 				myself);
1436*7c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
1437*7c478bd9Sstevel@tonic-gate 			*ldapStat = stat;
1438*7c478bd9Sstevel@tonic-gate 			rv = 0;
1439*7c478bd9Sstevel@tonic-gate 			goto cleanup;
1440*7c478bd9Sstevel@tonic-gate 		}
1441*7c478bd9Sstevel@tonic-gate 	}
1442*7c478bd9Sstevel@tonic-gate 
1443*7c478bd9Sstevel@tonic-gate 	if (!doVLV && !doSP)
1444*7c478bd9Sstevel@tonic-gate 		ctrls[0] = ctrls[1] = 0;
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate 	numVals = 0;
1447*7c478bd9Sstevel@tonic-gate 	done = 0;
1448*7c478bd9Sstevel@tonic-gate 
1449*7c478bd9Sstevel@tonic-gate 	if (ls->timeout.tv_sec || ls->timeout.tv_usec) {
1450*7c478bd9Sstevel@tonic-gate 		tv = ls->timeout;
1451*7c478bd9Sstevel@tonic-gate 	} else {
1452*7c478bd9Sstevel@tonic-gate 		tv = lc->searchTimeout;
1453*7c478bd9Sstevel@tonic-gate 	}
1454*7c478bd9Sstevel@tonic-gate 	(void) gettimeofday(&start, 0);
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate 	do {
1457*7c478bd9Sstevel@tonic-gate 		/* don't do vlv or simple page for base level searches */
1458*7c478bd9Sstevel@tonic-gate 		if (doVLV && ls->base != LDAP_SCOPE_BASE) {
1459*7c478bd9Sstevel@tonic-gate 			vList.ldvlist_index = index;
1460*7c478bd9Sstevel@tonic-gate 			vList.ldvlist_size = 0;
1461*7c478bd9Sstevel@tonic-gate 			if (vlvCtrl != 0)
1462*7c478bd9Sstevel@tonic-gate 				ldap_control_free(vlvCtrl);
1463*7c478bd9Sstevel@tonic-gate 			stat = ldap_create_virtuallist_control(lc->ld,
1464*7c478bd9Sstevel@tonic-gate 					&vList, &vlvCtrl);
1465*7c478bd9Sstevel@tonic-gate 			if (stat != LDAP_SUCCESS) {
1466*7c478bd9Sstevel@tonic-gate 				ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
1467*7c478bd9Sstevel@tonic-gate 						&stat);
1468*7c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
1469*7c478bd9Sstevel@tonic-gate 				"%s: Error creating VLV at index %ld: %s",
1470*7c478bd9Sstevel@tonic-gate 					myself, index, ldap_err2string(stat));
1471*7c478bd9Sstevel@tonic-gate 				*ldapStat = stat;
1472*7c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, numVals);
1473*7c478bd9Sstevel@tonic-gate 				rv = 0;
1474*7c478bd9Sstevel@tonic-gate 				goto cleanup;
1475*7c478bd9Sstevel@tonic-gate 			}
1476*7c478bd9Sstevel@tonic-gate 			ctrls[0] = sortCtrl;
1477*7c478bd9Sstevel@tonic-gate 			ctrls[1] = vlvCtrl;
1478*7c478bd9Sstevel@tonic-gate 			ctrls[2] = 0;
1479*7c478bd9Sstevel@tonic-gate 			stat = ldap_search_ext_s(lc->ld, ls->base,
1480*7c478bd9Sstevel@tonic-gate 					ls->scope, ls->filter, ls->attrs,
1481*7c478bd9Sstevel@tonic-gate 					ls->attrsonly, ctrls, 0, &tv,
1482*7c478bd9Sstevel@tonic-gate 					proxyInfo.search_size_limit, &msg);
1483*7c478bd9Sstevel@tonic-gate 		/* don't do vlv or simple page for base level searches */
1484*7c478bd9Sstevel@tonic-gate 		} else if (doSP && ls->base != LDAP_SCOPE_BASE) {
1485*7c478bd9Sstevel@tonic-gate 			if (ctrls[0] != 0)
1486*7c478bd9Sstevel@tonic-gate 				ldap_control_free(ctrls[0]);
1487*7c478bd9Sstevel@tonic-gate 			stat = ldap_create_page_control(lc->ld,
1488*7c478bd9Sstevel@tonic-gate 					lc->batchFrom, spCookie, 0, &ctrls[0]);
1489*7c478bd9Sstevel@tonic-gate 			if (stat != LDAP_SUCCESS) {
1490*7c478bd9Sstevel@tonic-gate 				ber_bvfree(spCookie);
1491*7c478bd9Sstevel@tonic-gate 				spCookie = 0;
1492*7c478bd9Sstevel@tonic-gate 				ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
1493*7c478bd9Sstevel@tonic-gate 						&stat);
1494*7c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
1495*7c478bd9Sstevel@tonic-gate 					"%s: Simple page error: %s",
1496*7c478bd9Sstevel@tonic-gate 					myself, ldap_err2string(stat));
1497*7c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, numVals);
1498*7c478bd9Sstevel@tonic-gate 				*ldapStat = stat;
1499*7c478bd9Sstevel@tonic-gate 				rv = 0;
1500*7c478bd9Sstevel@tonic-gate 				goto cleanup;
1501*7c478bd9Sstevel@tonic-gate 			}
1502*7c478bd9Sstevel@tonic-gate 			ctrls[1] = 0;
1503*7c478bd9Sstevel@tonic-gate 			stat = ldap_search_ext_s(lc->ld, ls->base,
1504*7c478bd9Sstevel@tonic-gate 					ls->scope, ls->filter, ls->attrs,
1505*7c478bd9Sstevel@tonic-gate 					ls->attrsonly, ctrls, 0, &tv,
1506*7c478bd9Sstevel@tonic-gate 					proxyInfo.search_size_limit, &msg);
1507*7c478bd9Sstevel@tonic-gate 		} else {
1508*7c478bd9Sstevel@tonic-gate 			stat = ldap_search_st(lc->ld, ls->base, ls->scope,
1509*7c478bd9Sstevel@tonic-gate 					ls->filter, ls->attrs, ls->attrsonly,
1510*7c478bd9Sstevel@tonic-gate 					&tv, &msg);
1511*7c478bd9Sstevel@tonic-gate 		}
1512*7c478bd9Sstevel@tonic-gate 		if (stat == LDAP_SUCCESS)
1513*7c478bd9Sstevel@tonic-gate 			ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
1514*7c478bd9Sstevel@tonic-gate 
1515*7c478bd9Sstevel@tonic-gate 		if (stat == LDAP_SERVER_DOWN) {
1516*7c478bd9Sstevel@tonic-gate 			lc->doDis++;
1517*7c478bd9Sstevel@tonic-gate 			releaseCon(lc, stat);
1518*7c478bd9Sstevel@tonic-gate 			lc = (yp2ldap)?findYPCon(ls, ldapStat):
1519*7c478bd9Sstevel@tonic-gate 				findCon(ldapStat);
1520*7c478bd9Sstevel@tonic-gate 			if (lc == 0) {
1521*7c478bd9Sstevel@tonic-gate 				*ldapStat = LDAP_SERVER_DOWN;
1522*7c478bd9Sstevel@tonic-gate 				rv =  0;
1523*7c478bd9Sstevel@tonic-gate 				goto cleanup;
1524*7c478bd9Sstevel@tonic-gate 			}
1525*7c478bd9Sstevel@tonic-gate 			goto retry_new_conn;
1526*7c478bd9Sstevel@tonic-gate 		}
1527*7c478bd9Sstevel@tonic-gate 
1528*7c478bd9Sstevel@tonic-gate 		if (stat == LDAP_REFERRAL && follow_referral) {
1529*7c478bd9Sstevel@tonic-gate 			(void) ldap_parse_result(lc->ld, msg, NULL, NULL, NULL,
1530*7c478bd9Sstevel@tonic-gate 				&referralsp, NULL, 0);
1531*7c478bd9Sstevel@tonic-gate 			if (referralsp != NULL) {
1532*7c478bd9Sstevel@tonic-gate 				/* We support at most one level of referrals */
1533*7c478bd9Sstevel@tonic-gate 				follow_referral = FALSE;
1534*7c478bd9Sstevel@tonic-gate 				releaseCon(lc, stat);
1535*7c478bd9Sstevel@tonic-gate 				lc = findReferralCon(referralsp, &stat);
1536*7c478bd9Sstevel@tonic-gate 				ldap_value_free(referralsp);
1537*7c478bd9Sstevel@tonic-gate 				if (lc == NULL) {
1538*7c478bd9Sstevel@tonic-gate 					freeRuleValue(rv, numVals);
1539*7c478bd9Sstevel@tonic-gate 					rv = 0;
1540*7c478bd9Sstevel@tonic-gate 					*ldapStat = stat;
1541*7c478bd9Sstevel@tonic-gate 					goto cleanup;
1542*7c478bd9Sstevel@tonic-gate 				}
1543*7c478bd9Sstevel@tonic-gate 				stat = LDAP_SUCCESS;
1544*7c478bd9Sstevel@tonic-gate 				goto retry_new_conn;
1545*7c478bd9Sstevel@tonic-gate 			}
1546*7c478bd9Sstevel@tonic-gate 		}
1547*7c478bd9Sstevel@tonic-gate 		*ldapStat = stat;
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate 		if (*ldapStat == LDAP_NO_SUCH_OBJECT) {
1550*7c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
1551*7c478bd9Sstevel@tonic-gate 			rv = 0;
1552*7c478bd9Sstevel@tonic-gate 			goto cleanup;
1553*7c478bd9Sstevel@tonic-gate 		} else if (doVLV && *ldapStat == LDAP_INSUFFICIENT_ACCESS) {
1554*7c478bd9Sstevel@tonic-gate 			/*
1555*7c478bd9Sstevel@tonic-gate 			 * The LDAP server (at least Netscape 4.x) can return
1556*7c478bd9Sstevel@tonic-gate 			 * LDAP_INSUFFICIENT_ACCESS when VLV is supported,
1557*7c478bd9Sstevel@tonic-gate 			 * but not for the bind DN specified. So, just in
1558*7c478bd9Sstevel@tonic-gate 			 * case, we clean up, and try again without VLV.
1559*7c478bd9Sstevel@tonic-gate 			 */
1560*7c478bd9Sstevel@tonic-gate 			doVLV = 0;
1561*7c478bd9Sstevel@tonic-gate 			if (msg != 0) {
1562*7c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(msg);
1563*7c478bd9Sstevel@tonic-gate 				msg = 0;
1564*7c478bd9Sstevel@tonic-gate 			}
1565*7c478bd9Sstevel@tonic-gate 			if (ctrls[0] != 0) {
1566*7c478bd9Sstevel@tonic-gate 				ldap_control_free(ctrls[0]);
1567*7c478bd9Sstevel@tonic-gate 				ctrls[0] = 0;
1568*7c478bd9Sstevel@tonic-gate 			}
1569*7c478bd9Sstevel@tonic-gate 			if (ctrls[1] != 0) {
1570*7c478bd9Sstevel@tonic-gate 				ldap_control_free(ctrls[1]);
1571*7c478bd9Sstevel@tonic-gate 				ctrls[1] = 0;
1572*7c478bd9Sstevel@tonic-gate 			}
1573*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_VLV_INSUFF_ACC, LOG_WARNING,
1574*7c478bd9Sstevel@tonic-gate 	"%s: VLV insufficient access from server %s; retrying without VLV",
1575*7c478bd9Sstevel@tonic-gate 				myself, NIL(lc->sp));
1576*7c478bd9Sstevel@tonic-gate 			goto retry_noVLV;
1577*7c478bd9Sstevel@tonic-gate 		} else if (*ldapStat != LDAP_SUCCESS) {
1578*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1579*7c478bd9Sstevel@tonic-gate 				"ldap_search(0x%x,\n\t\"%s\",\n\t %d,",
1580*7c478bd9Sstevel@tonic-gate 				lc->ld, NIL(ls->base), ls->scope);
1581*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1582*7c478bd9Sstevel@tonic-gate 				"\t\"%s\",\n\t0x%x,\n\t%d) => %d (%s)",
1583*7c478bd9Sstevel@tonic-gate 				NIL(ls->filter), ls->attrs, ls->attrsonly,
1584*7c478bd9Sstevel@tonic-gate 				*ldapStat, ldap_err2string(stat));
1585*7c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
1586*7c478bd9Sstevel@tonic-gate 			rv = 0;
1587*7c478bd9Sstevel@tonic-gate 			goto cleanup;
1588*7c478bd9Sstevel@tonic-gate 		}
1589*7c478bd9Sstevel@tonic-gate 
1590*7c478bd9Sstevel@tonic-gate 		numEntries = ldap_count_entries(lc->ld, msg);
1591*7c478bd9Sstevel@tonic-gate 		if (numEntries == 0 && *ldapStat == LDAP_SUCCESS) {
1592*7c478bd9Sstevel@tonic-gate 			/*
1593*7c478bd9Sstevel@tonic-gate 			 * This is a bit weird, but the server (or, at least,
1594*7c478bd9Sstevel@tonic-gate 			 * ldap_search_ext()) can sometimes return
1595*7c478bd9Sstevel@tonic-gate 			 * LDAP_SUCCESS and no entries when it didn't
1596*7c478bd9Sstevel@tonic-gate 			 * find what we were looking for. Seems it ought to
1597*7c478bd9Sstevel@tonic-gate 			 * return LDAP_NO_SUCH_OBJECT or some such.
1598*7c478bd9Sstevel@tonic-gate 			 */
1599*7c478bd9Sstevel@tonic-gate 			freeRuleValue(rv, numVals);
1600*7c478bd9Sstevel@tonic-gate 			rv = 0;
1601*7c478bd9Sstevel@tonic-gate 			*ldapStat = LDAP_NO_SUCH_OBJECT;
1602*7c478bd9Sstevel@tonic-gate 			goto cleanup;
1603*7c478bd9Sstevel@tonic-gate 		}
1604*7c478bd9Sstevel@tonic-gate 
1605*7c478bd9Sstevel@tonic-gate 		tnv = numVals + numEntries;
1606*7c478bd9Sstevel@tonic-gate 		if ((rv = growRuleValue(numVals, tnv, rv, rvIn)) == 0) {
1607*7c478bd9Sstevel@tonic-gate 			*ldapStat = LDAP_NO_MEMORY;
1608*7c478bd9Sstevel@tonic-gate 			goto cleanup;
1609*7c478bd9Sstevel@tonic-gate 		}
1610*7c478bd9Sstevel@tonic-gate 
1611*7c478bd9Sstevel@tonic-gate 		for (m = ldap_first_entry(lc->ld, msg); m != 0;
1612*7c478bd9Sstevel@tonic-gate 				m = ldap_next_entry(lc->ld, m), numVals++) {
1613*7c478bd9Sstevel@tonic-gate 			char		*nm;
1614*7c478bd9Sstevel@tonic-gate 			BerElement	*ber = 0;
1615*7c478bd9Sstevel@tonic-gate 
1616*7c478bd9Sstevel@tonic-gate 			if (numVals > tnv) {
1617*7c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_INFO,
1618*7c478bd9Sstevel@tonic-gate 				"%s: Inconsistent LDAP entry count > %d",
1619*7c478bd9Sstevel@tonic-gate 					myself, numEntries);
1620*7c478bd9Sstevel@tonic-gate 				break;
1621*7c478bd9Sstevel@tonic-gate 			}
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate 			nm = ldap_get_dn(lc->ld, m);
1624*7c478bd9Sstevel@tonic-gate 			if (nm == 0 || addSAttr2RuleValue("dn", nm,
1625*7c478bd9Sstevel@tonic-gate 					&rv[numVals])) {
1626*7c478bd9Sstevel@tonic-gate 				sfree(nm);
1627*7c478bd9Sstevel@tonic-gate 				*ldapStat = LDAP_NO_MEMORY;
1628*7c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, tnv);
1629*7c478bd9Sstevel@tonic-gate 				rv = 0;
1630*7c478bd9Sstevel@tonic-gate 				goto cleanup;
1631*7c478bd9Sstevel@tonic-gate 			}
1632*7c478bd9Sstevel@tonic-gate 			sfree(nm);
1633*7c478bd9Sstevel@tonic-gate 
1634*7c478bd9Sstevel@tonic-gate 			for (nm = ldap_first_attribute(lc->ld, m, &ber);
1635*7c478bd9Sstevel@tonic-gate 					nm != 0;
1636*7c478bd9Sstevel@tonic-gate 				nm = ldap_next_attribute(lc->ld, m, ber)) {
1637*7c478bd9Sstevel@tonic-gate 				struct berval	**val;
1638*7c478bd9Sstevel@tonic-gate 				int		i, nv;
1639*7c478bd9Sstevel@tonic-gate 
1640*7c478bd9Sstevel@tonic-gate 				val = ldap_get_values_len(lc->ld, m, nm);
1641*7c478bd9Sstevel@tonic-gate 				nv = (val == 0) ? 0 :
1642*7c478bd9Sstevel@tonic-gate 						ldap_count_values_len(val);
1643*7c478bd9Sstevel@tonic-gate 				for (i = 0; i < nv; i++) {
1644*7c478bd9Sstevel@tonic-gate 					/*
1645*7c478bd9Sstevel@tonic-gate 					 * Since we don't know if the value is
1646*7c478bd9Sstevel@tonic-gate 					 * BER-encoded or not, we mark it as a
1647*7c478bd9Sstevel@tonic-gate 					 * string. All is well as long as we
1648*7c478bd9Sstevel@tonic-gate 					 * don't insist on 'vt_ber' when
1649*7c478bd9Sstevel@tonic-gate 					 * interpreting.
1650*7c478bd9Sstevel@tonic-gate 					 */
1651*7c478bd9Sstevel@tonic-gate 					if (addAttr2RuleValue(vt_string, nm,
1652*7c478bd9Sstevel@tonic-gate 							val[i]->bv_val,
1653*7c478bd9Sstevel@tonic-gate 							val[i]->bv_len,
1654*7c478bd9Sstevel@tonic-gate 							&rv[numVals])) {
1655*7c478bd9Sstevel@tonic-gate 						if (ber != 0)
1656*7c478bd9Sstevel@tonic-gate 							ber_free(ber, 0);
1657*7c478bd9Sstevel@tonic-gate 						ldap_value_free_len(val);
1658*7c478bd9Sstevel@tonic-gate 						*ldapStat = LDAP_NO_MEMORY;
1659*7c478bd9Sstevel@tonic-gate 						freeRuleValue(rv, tnv);
1660*7c478bd9Sstevel@tonic-gate 						rv = 0;
1661*7c478bd9Sstevel@tonic-gate 						goto cleanup;
1662*7c478bd9Sstevel@tonic-gate 					}
1663*7c478bd9Sstevel@tonic-gate 				}
1664*7c478bd9Sstevel@tonic-gate 				/*
1665*7c478bd9Sstevel@tonic-gate 				 * XXX the ldap_first_attribute(3LDAP) man
1666*7c478bd9Sstevel@tonic-gate 				 * page says that the ldap_first_attribute/
1667*7c478bd9Sstevel@tonic-gate 				 * ldap_next_attribute should be treated as
1668*7c478bd9Sstevel@tonic-gate 				 * static, but the libldap.so.4 code mallocs
1669*7c478bd9Sstevel@tonic-gate 				 * (and it's not TSD). So, in order to avoid
1670*7c478bd9Sstevel@tonic-gate 				 * a leak, we free the return value.
1671*7c478bd9Sstevel@tonic-gate 				 */
1672*7c478bd9Sstevel@tonic-gate 				ldap_memfree(nm);
1673*7c478bd9Sstevel@tonic-gate 				if (val != 0)
1674*7c478bd9Sstevel@tonic-gate 					ldap_value_free_len(val);
1675*7c478bd9Sstevel@tonic-gate 			}
1676*7c478bd9Sstevel@tonic-gate 			/*
1677*7c478bd9Sstevel@tonic-gate 			 * XXX ldap_next_attribute(3LDAP) says that the 'ber'
1678*7c478bd9Sstevel@tonic-gate 			 * pointer is freed when it returns NULL, but that's
1679*7c478bd9Sstevel@tonic-gate 			 * not implemented in the libldap.so.4 code, so we
1680*7c478bd9Sstevel@tonic-gate 			 * free it here in order to avoid a memory leak.
1681*7c478bd9Sstevel@tonic-gate 			 */
1682*7c478bd9Sstevel@tonic-gate 			if (ber != 0)
1683*7c478bd9Sstevel@tonic-gate 				ber_free(ber, 0);
1684*7c478bd9Sstevel@tonic-gate 		}
1685*7c478bd9Sstevel@tonic-gate 
1686*7c478bd9Sstevel@tonic-gate 		if (numVals != tnv) {
1687*7c478bd9Sstevel@tonic-gate 			logmsg(MSG_NOTIMECHECK, LOG_WARNING,
1688*7c478bd9Sstevel@tonic-gate 		"%s: Inconsistent LDAP entry count, found = %d, expected %d",
1689*7c478bd9Sstevel@tonic-gate 				myself, numVals, tnv);
1690*7c478bd9Sstevel@tonic-gate 		}
1691*7c478bd9Sstevel@tonic-gate 
1692*7c478bd9Sstevel@tonic-gate 		if (doVLV) {
1693*7c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0,
1694*7c478bd9Sstevel@tonic-gate 						&retCtrls, 0);
1695*7c478bd9Sstevel@tonic-gate 			if (stat != LDAP_SUCCESS) {
1696*7c478bd9Sstevel@tonic-gate 				ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
1697*7c478bd9Sstevel@tonic-gate 						&stat);
1698*7c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
1699*7c478bd9Sstevel@tonic-gate 					"%s: VLV parse result error: %s",
1700*7c478bd9Sstevel@tonic-gate 					myself, ldap_err2string(stat));
1701*7c478bd9Sstevel@tonic-gate 				*ldapStat = stat;
1702*7c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, tnv);
1703*7c478bd9Sstevel@tonic-gate 				rv = 0;
1704*7c478bd9Sstevel@tonic-gate 				goto cleanup;
1705*7c478bd9Sstevel@tonic-gate 			}
1706*7c478bd9Sstevel@tonic-gate 			if (retCtrls != 0) {
1707*7c478bd9Sstevel@tonic-gate 				unsigned long	targetPosP = 0;
1708*7c478bd9Sstevel@tonic-gate 				unsigned long	listSize = 0;
1709*7c478bd9Sstevel@tonic-gate 
1710*7c478bd9Sstevel@tonic-gate 				stat = ldap_parse_virtuallist_control(lc->ld,
1711*7c478bd9Sstevel@tonic-gate 					retCtrls, &targetPosP, &listSize,
1712*7c478bd9Sstevel@tonic-gate 					&lprEc);
1713*7c478bd9Sstevel@tonic-gate 				if (stat == LDAP_SUCCESS) {
1714*7c478bd9Sstevel@tonic-gate 					index = targetPosP + lc->batchFrom;
1715*7c478bd9Sstevel@tonic-gate 					if (index >= listSize)
1716*7c478bd9Sstevel@tonic-gate 						done = 1;
1717*7c478bd9Sstevel@tonic-gate 				}
1718*7c478bd9Sstevel@tonic-gate 				ldap_controls_free(retCtrls);
1719*7c478bd9Sstevel@tonic-gate 				retCtrls = 0;
1720*7c478bd9Sstevel@tonic-gate 			} else {
1721*7c478bd9Sstevel@tonic-gate 				done = 1;
1722*7c478bd9Sstevel@tonic-gate 			}
1723*7c478bd9Sstevel@tonic-gate 		} else if (doSP) {
1724*7c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lprEc, 0, 0, 0,
1725*7c478bd9Sstevel@tonic-gate 						&retCtrls, 0);
1726*7c478bd9Sstevel@tonic-gate 			if (stat != LDAP_SUCCESS) {
1727*7c478bd9Sstevel@tonic-gate 				ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
1728*7c478bd9Sstevel@tonic-gate 						&stat);
1729*7c478bd9Sstevel@tonic-gate 				logmsg(MSG_NOTIMECHECK, LOG_ERR,
1730*7c478bd9Sstevel@tonic-gate 				"%s: Simple page parse result error: %s",
1731*7c478bd9Sstevel@tonic-gate 					myself, ldap_err2string(stat));
1732*7c478bd9Sstevel@tonic-gate 				*ldapStat = stat;
1733*7c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, tnv);
1734*7c478bd9Sstevel@tonic-gate 				rv = 0;
1735*7c478bd9Sstevel@tonic-gate 				goto cleanup;
1736*7c478bd9Sstevel@tonic-gate 			}
1737*7c478bd9Sstevel@tonic-gate 			if (retCtrls != 0) {
1738*7c478bd9Sstevel@tonic-gate 				unsigned int	count;
1739*7c478bd9Sstevel@tonic-gate 
1740*7c478bd9Sstevel@tonic-gate 				if (spCookie != 0) {
1741*7c478bd9Sstevel@tonic-gate 					ber_bvfree(spCookie);
1742*7c478bd9Sstevel@tonic-gate 					spCookie = 0;
1743*7c478bd9Sstevel@tonic-gate 				}
1744*7c478bd9Sstevel@tonic-gate 				stat = ldap_parse_page_control(lc->ld,
1745*7c478bd9Sstevel@tonic-gate 						retCtrls, &count, &spCookie);
1746*7c478bd9Sstevel@tonic-gate 				if (stat == LDAP_SUCCESS) {
1747*7c478bd9Sstevel@tonic-gate 					if (spCookie == 0 ||
1748*7c478bd9Sstevel@tonic-gate 						spCookie->bv_val == 0 ||
1749*7c478bd9Sstevel@tonic-gate 						spCookie->bv_len == 0)
1750*7c478bd9Sstevel@tonic-gate 						done = 1;
1751*7c478bd9Sstevel@tonic-gate 				}
1752*7c478bd9Sstevel@tonic-gate 				ldap_controls_free(retCtrls);
1753*7c478bd9Sstevel@tonic-gate 				retCtrls = 0;
1754*7c478bd9Sstevel@tonic-gate 			} else {
1755*7c478bd9Sstevel@tonic-gate 				done = 1;
1756*7c478bd9Sstevel@tonic-gate 			}
1757*7c478bd9Sstevel@tonic-gate 		} else {
1758*7c478bd9Sstevel@tonic-gate 			done = 1;
1759*7c478bd9Sstevel@tonic-gate 		}
1760*7c478bd9Sstevel@tonic-gate 
1761*7c478bd9Sstevel@tonic-gate 		(void) ldap_msgfree(msg);
1762*7c478bd9Sstevel@tonic-gate 		msg = 0;
1763*7c478bd9Sstevel@tonic-gate 
1764*7c478bd9Sstevel@tonic-gate 		/*
1765*7c478bd9Sstevel@tonic-gate 		 * If we're using VLV or SP, the timeout should apply
1766*7c478bd9Sstevel@tonic-gate 		 * to all calls as an aggregate, so we need to reduce
1767*7c478bd9Sstevel@tonic-gate 		 * 'tv' with the time spent on this chunk of data.
1768*7c478bd9Sstevel@tonic-gate 		 */
1769*7c478bd9Sstevel@tonic-gate 		if (!done) {
1770*7c478bd9Sstevel@tonic-gate 			struct timeval	tmp;
1771*7c478bd9Sstevel@tonic-gate 
1772*7c478bd9Sstevel@tonic-gate 			(void) gettimeofday(&now, 0);
1773*7c478bd9Sstevel@tonic-gate 			tmp = now;
1774*7c478bd9Sstevel@tonic-gate 			now.tv_sec -= start.tv_sec;
1775*7c478bd9Sstevel@tonic-gate 			now.tv_usec -= start.tv_usec;
1776*7c478bd9Sstevel@tonic-gate 			if (now.tv_usec < 0) {
1777*7c478bd9Sstevel@tonic-gate 				now.tv_usec += 1000000;
1778*7c478bd9Sstevel@tonic-gate 				now.tv_sec -= 1;
1779*7c478bd9Sstevel@tonic-gate 			}
1780*7c478bd9Sstevel@tonic-gate 			tv.tv_sec -= now.tv_sec;
1781*7c478bd9Sstevel@tonic-gate 			tv.tv_usec -= now.tv_usec;
1782*7c478bd9Sstevel@tonic-gate 			if (tv.tv_usec < 0) {
1783*7c478bd9Sstevel@tonic-gate 				tv.tv_usec += 1000000;
1784*7c478bd9Sstevel@tonic-gate 				tv.tv_sec -= 1;
1785*7c478bd9Sstevel@tonic-gate 			}
1786*7c478bd9Sstevel@tonic-gate 			if (tv.tv_sec < 0) {
1787*7c478bd9Sstevel@tonic-gate 				*ldapStat = LDAP_TIMEOUT;
1788*7c478bd9Sstevel@tonic-gate 				freeRuleValue(rv, tnv);
1789*7c478bd9Sstevel@tonic-gate 				rv = 0;
1790*7c478bd9Sstevel@tonic-gate 				goto cleanup;
1791*7c478bd9Sstevel@tonic-gate 			}
1792*7c478bd9Sstevel@tonic-gate 			start = tmp;
1793*7c478bd9Sstevel@tonic-gate 		}
1794*7c478bd9Sstevel@tonic-gate 
1795*7c478bd9Sstevel@tonic-gate 	} while (!done);
1796*7c478bd9Sstevel@tonic-gate 
1797*7c478bd9Sstevel@tonic-gate 	if (numValues != 0)
1798*7c478bd9Sstevel@tonic-gate 		*numValues = numVals;
1799*7c478bd9Sstevel@tonic-gate 
1800*7c478bd9Sstevel@tonic-gate cleanup:
1801*7c478bd9Sstevel@tonic-gate 	if (NULL != lc) {
1802*7c478bd9Sstevel@tonic-gate 		if (yp2ldap && ls->useCon == 0) {
1803*7c478bd9Sstevel@tonic-gate 			/* Disconnect and free the connection */
1804*7c478bd9Sstevel@tonic-gate 			lc->doDis++;
1805*7c478bd9Sstevel@tonic-gate 			lc->doDel++;
1806*7c478bd9Sstevel@tonic-gate 			releaseCon(lc, stat);
1807*7c478bd9Sstevel@tonic-gate 			releaseLC(lc);
1808*7c478bd9Sstevel@tonic-gate 
1809*7c478bd9Sstevel@tonic-gate 		} else {
1810*7c478bd9Sstevel@tonic-gate 			releaseCon(lc, stat);
1811*7c478bd9Sstevel@tonic-gate 		}
1812*7c478bd9Sstevel@tonic-gate 	}
1813*7c478bd9Sstevel@tonic-gate 	if (msg != 0)
1814*7c478bd9Sstevel@tonic-gate 		(void) ldap_msgfree(msg);
1815*7c478bd9Sstevel@tonic-gate 	if (ctrls[0] != 0)
1816*7c478bd9Sstevel@tonic-gate 		ldap_control_free(ctrls[0]);
1817*7c478bd9Sstevel@tonic-gate 	if (ctrls[1] != 0)
1818*7c478bd9Sstevel@tonic-gate 		ldap_control_free(ctrls[1]);
1819*7c478bd9Sstevel@tonic-gate 	if (spCookie != 0)
1820*7c478bd9Sstevel@tonic-gate 		ber_bvfree(spCookie);
1821*7c478bd9Sstevel@tonic-gate 	if (sortKeyList != 0)
1822*7c478bd9Sstevel@tonic-gate 		ldap_free_sort_keylist(sortKeyList);
1823*7c478bd9Sstevel@tonic-gate 
1824*7c478bd9Sstevel@tonic-gate 	return (rv);
1825*7c478bd9Sstevel@tonic-gate }
1826*7c478bd9Sstevel@tonic-gate 
1827*7c478bd9Sstevel@tonic-gate static void
1828*7c478bd9Sstevel@tonic-gate freeLdapModEntry(LDAPMod *m) {
1829*7c478bd9Sstevel@tonic-gate 
1830*7c478bd9Sstevel@tonic-gate 	if (m == 0)
1831*7c478bd9Sstevel@tonic-gate 		return;
1832*7c478bd9Sstevel@tonic-gate 
1833*7c478bd9Sstevel@tonic-gate 	sfree(m->mod_type);
1834*7c478bd9Sstevel@tonic-gate 	if ((m->mod_op & LDAP_MOD_BVALUES) == 0) {
1835*7c478bd9Sstevel@tonic-gate 		char	**v = m->mod_values;
1836*7c478bd9Sstevel@tonic-gate 
1837*7c478bd9Sstevel@tonic-gate 		if (v != 0) {
1838*7c478bd9Sstevel@tonic-gate 			while (*v != 0) {
1839*7c478bd9Sstevel@tonic-gate 				sfree(*v);
1840*7c478bd9Sstevel@tonic-gate 				v++;
1841*7c478bd9Sstevel@tonic-gate 			}
1842*7c478bd9Sstevel@tonic-gate 			free(m->mod_values);
1843*7c478bd9Sstevel@tonic-gate 		}
1844*7c478bd9Sstevel@tonic-gate 	} else {
1845*7c478bd9Sstevel@tonic-gate 		struct berval	**b = m->mod_bvalues;
1846*7c478bd9Sstevel@tonic-gate 
1847*7c478bd9Sstevel@tonic-gate 		if (b != 0) {
1848*7c478bd9Sstevel@tonic-gate 			while (*b != 0) {
1849*7c478bd9Sstevel@tonic-gate 				sfree((*b)->bv_val);
1850*7c478bd9Sstevel@tonic-gate 				free(*b);
1851*7c478bd9Sstevel@tonic-gate 				b++;
1852*7c478bd9Sstevel@tonic-gate 			}
1853*7c478bd9Sstevel@tonic-gate 			free(m->mod_bvalues);
1854*7c478bd9Sstevel@tonic-gate 		}
1855*7c478bd9Sstevel@tonic-gate 	}
1856*7c478bd9Sstevel@tonic-gate 
1857*7c478bd9Sstevel@tonic-gate 	free(m);
1858*7c478bd9Sstevel@tonic-gate }
1859*7c478bd9Sstevel@tonic-gate 
1860*7c478bd9Sstevel@tonic-gate static void
1861*7c478bd9Sstevel@tonic-gate freeLdapMod(LDAPMod **mods) {
1862*7c478bd9Sstevel@tonic-gate 	LDAPMod		*m, **org = mods;
1863*7c478bd9Sstevel@tonic-gate 
1864*7c478bd9Sstevel@tonic-gate 	if (mods == 0)
1865*7c478bd9Sstevel@tonic-gate 		return;
1866*7c478bd9Sstevel@tonic-gate 
1867*7c478bd9Sstevel@tonic-gate 	while ((m = *mods) != 0) {
1868*7c478bd9Sstevel@tonic-gate 		freeLdapModEntry(m);
1869*7c478bd9Sstevel@tonic-gate 		mods++;
1870*7c478bd9Sstevel@tonic-gate 	}
1871*7c478bd9Sstevel@tonic-gate 
1872*7c478bd9Sstevel@tonic-gate 	free(org);
1873*7c478bd9Sstevel@tonic-gate }
1874*7c478bd9Sstevel@tonic-gate 
1875*7c478bd9Sstevel@tonic-gate /*
1876*7c478bd9Sstevel@tonic-gate  * Convert a rule-value structure to the corresponding LDAPMod.
1877*7c478bd9Sstevel@tonic-gate  * If 'add' is set, attributes/values are added; object classes
1878*7c478bd9Sstevel@tonic-gate  * are also added. If 'add' is cleared, attributes/values are modified,
1879*7c478bd9Sstevel@tonic-gate  * and 'oc' controls whether or not object classes are added.
1880*7c478bd9Sstevel@tonic-gate  */
1881*7c478bd9Sstevel@tonic-gate LDAPMod **
1882*7c478bd9Sstevel@tonic-gate search2LdapMod(__nis_rule_value_t *rv, int add, int oc) {
1883*7c478bd9Sstevel@tonic-gate 	LDAPMod		**mods;
1884*7c478bd9Sstevel@tonic-gate 	int		i, j, nm;
1885*7c478bd9Sstevel@tonic-gate 	char		*myself = "search2LdapMod";
1886*7c478bd9Sstevel@tonic-gate 
1887*7c478bd9Sstevel@tonic-gate 	if (rv == 0 || rv->numAttrs <= 0)
1888*7c478bd9Sstevel@tonic-gate 		return (0);
1889*7c478bd9Sstevel@tonic-gate 
1890*7c478bd9Sstevel@tonic-gate 	mods = am(myself, (rv->numAttrs + 1) * sizeof (mods[0]));
1891*7c478bd9Sstevel@tonic-gate 	if (mods == 0)
1892*7c478bd9Sstevel@tonic-gate 		return (0);
1893*7c478bd9Sstevel@tonic-gate 
1894*7c478bd9Sstevel@tonic-gate 	for (i = 0, nm = 0; i < rv->numAttrs; i++) {
1895*7c478bd9Sstevel@tonic-gate 		int	isOc;
1896*7c478bd9Sstevel@tonic-gate 		/*
1897*7c478bd9Sstevel@tonic-gate 		 * If we're creating an LDAPMod array for an add operation,
1898*7c478bd9Sstevel@tonic-gate 		 * just skip attributes that should be deleted.
1899*7c478bd9Sstevel@tonic-gate 		 */
1900*7c478bd9Sstevel@tonic-gate 		if (add && rv->attrVal[i].numVals < 0)
1901*7c478bd9Sstevel@tonic-gate 			continue;
1902*7c478bd9Sstevel@tonic-gate 
1903*7c478bd9Sstevel@tonic-gate 		/*
1904*7c478bd9Sstevel@tonic-gate 		 * Skip DN; it's specified separately to ldap_modify()
1905*7c478bd9Sstevel@tonic-gate 		 * and ldap_add(), and mustn't appear among the
1906*7c478bd9Sstevel@tonic-gate 		 * attributes to be modified/added.
1907*7c478bd9Sstevel@tonic-gate 		 */
1908*7c478bd9Sstevel@tonic-gate 		if (strcasecmp("dn", rv->attrName[i]) == 0)
1909*7c478bd9Sstevel@tonic-gate 			continue;
1910*7c478bd9Sstevel@tonic-gate 
1911*7c478bd9Sstevel@tonic-gate 		/*
1912*7c478bd9Sstevel@tonic-gate 		 * If modifying, and 'oc' is off, skip object class
1913*7c478bd9Sstevel@tonic-gate 		 * attributes.
1914*7c478bd9Sstevel@tonic-gate 		 */
1915*7c478bd9Sstevel@tonic-gate 		isOc = (strcasecmp("objectclass", rv->attrName[i]) == 0);
1916*7c478bd9Sstevel@tonic-gate 		if (!add && !oc && isOc)
1917*7c478bd9Sstevel@tonic-gate 			continue;
1918*7c478bd9Sstevel@tonic-gate 
1919*7c478bd9Sstevel@tonic-gate 		mods[nm] = am(myself, sizeof (*mods[nm]));
1920*7c478bd9Sstevel@tonic-gate 		if (mods[nm] == 0) {
1921*7c478bd9Sstevel@tonic-gate 			freeLdapMod(mods);
1922*7c478bd9Sstevel@tonic-gate 			return (0);
1923*7c478bd9Sstevel@tonic-gate 		}
1924*7c478bd9Sstevel@tonic-gate 
1925*7c478bd9Sstevel@tonic-gate 		/* 'mod_type' is the attribute name */
1926*7c478bd9Sstevel@tonic-gate 		mods[nm]->mod_type = sdup(myself, T, rv->attrName[i]);
1927*7c478bd9Sstevel@tonic-gate 		if (mods[nm]->mod_type == 0) {
1928*7c478bd9Sstevel@tonic-gate 			freeLdapMod(mods);
1929*7c478bd9Sstevel@tonic-gate 			return (0);
1930*7c478bd9Sstevel@tonic-gate 		}
1931*7c478bd9Sstevel@tonic-gate 
1932*7c478bd9Sstevel@tonic-gate 		/*
1933*7c478bd9Sstevel@tonic-gate 		 * numVals < 0 means attribute and all values should
1934*7c478bd9Sstevel@tonic-gate 		 * be deleted.
1935*7c478bd9Sstevel@tonic-gate 		 */
1936*7c478bd9Sstevel@tonic-gate 		if (rv->attrVal[i].numVals < 0) {
1937*7c478bd9Sstevel@tonic-gate 			mods[nm]->mod_op = LDAP_MOD_DELETE;
1938*7c478bd9Sstevel@tonic-gate 			mods[nm]->mod_values = 0;
1939*7c478bd9Sstevel@tonic-gate 			nm++;
1940*7c478bd9Sstevel@tonic-gate 			continue;
1941*7c478bd9Sstevel@tonic-gate 		}
1942*7c478bd9Sstevel@tonic-gate 
1943*7c478bd9Sstevel@tonic-gate 		/* objectClass attributes always added */
1944*7c478bd9Sstevel@tonic-gate 		mods[nm]->mod_op = (add) ? 0 : ((isOc) ? 0 : LDAP_MOD_REPLACE);
1945*7c478bd9Sstevel@tonic-gate 
1946*7c478bd9Sstevel@tonic-gate 		if (rv->attrVal[i].type == vt_string) {
1947*7c478bd9Sstevel@tonic-gate 			/*
1948*7c478bd9Sstevel@tonic-gate 			 * mods[]->mod_values is a NULL-terminated array
1949*7c478bd9Sstevel@tonic-gate 			 * of (char *)'s.
1950*7c478bd9Sstevel@tonic-gate 			 */
1951*7c478bd9Sstevel@tonic-gate 			mods[nm]->mod_values = am(myself,
1952*7c478bd9Sstevel@tonic-gate 					(rv->attrVal[i].numVals + 1) *
1953*7c478bd9Sstevel@tonic-gate 					sizeof (mods[nm]->mod_values[0]));
1954*7c478bd9Sstevel@tonic-gate 			if (mods[nm]->mod_values == 0) {
1955*7c478bd9Sstevel@tonic-gate 				freeLdapMod(mods);
1956*7c478bd9Sstevel@tonic-gate 				return (0);
1957*7c478bd9Sstevel@tonic-gate 			}
1958*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < rv->attrVal[i].numVals; j++) {
1959*7c478bd9Sstevel@tonic-gate 				/*
1960*7c478bd9Sstevel@tonic-gate 				 * Just in case the string isn't NUL
1961*7c478bd9Sstevel@tonic-gate 				 * terminated, add one byte to the
1962*7c478bd9Sstevel@tonic-gate 				 * allocated length; am() will initialize
1963*7c478bd9Sstevel@tonic-gate 				 * the buffer to zero.
1964*7c478bd9Sstevel@tonic-gate 				 */
1965*7c478bd9Sstevel@tonic-gate 				mods[nm]->mod_values[j] = am(myself,
1966*7c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].length + 1);
1967*7c478bd9Sstevel@tonic-gate 				if (mods[nm]->mod_values[j] == 0) {
1968*7c478bd9Sstevel@tonic-gate 					freeLdapMod(mods);
1969*7c478bd9Sstevel@tonic-gate 					return (0);
1970*7c478bd9Sstevel@tonic-gate 				}
1971*7c478bd9Sstevel@tonic-gate 				memcpy(mods[nm]->mod_values[j],
1972*7c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].value,
1973*7c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].length);
1974*7c478bd9Sstevel@tonic-gate 			}
1975*7c478bd9Sstevel@tonic-gate 		} else {
1976*7c478bd9Sstevel@tonic-gate 			mods[nm]->mod_op |= LDAP_MOD_BVALUES;
1977*7c478bd9Sstevel@tonic-gate 			mods[nm]->mod_bvalues = am(myself,
1978*7c478bd9Sstevel@tonic-gate 					(rv->attrVal[i].numVals+1) *
1979*7c478bd9Sstevel@tonic-gate 					sizeof (mods[nm]->mod_bvalues[0]));
1980*7c478bd9Sstevel@tonic-gate 			if (mods[nm]->mod_bvalues == 0) {
1981*7c478bd9Sstevel@tonic-gate 				freeLdapMod(mods);
1982*7c478bd9Sstevel@tonic-gate 				return (0);
1983*7c478bd9Sstevel@tonic-gate 			}
1984*7c478bd9Sstevel@tonic-gate 			for (j = 0; j < rv->attrVal[i].numVals; j++) {
1985*7c478bd9Sstevel@tonic-gate 				mods[nm]->mod_bvalues[j] = am(myself,
1986*7c478bd9Sstevel@tonic-gate 					sizeof (*mods[nm]->mod_bvalues[j]));
1987*7c478bd9Sstevel@tonic-gate 				if (mods[nm]->mod_bvalues[j] == 0) {
1988*7c478bd9Sstevel@tonic-gate 					freeLdapMod(mods);
1989*7c478bd9Sstevel@tonic-gate 					return (0);
1990*7c478bd9Sstevel@tonic-gate 				}
1991*7c478bd9Sstevel@tonic-gate 				mods[nm]->mod_bvalues[j]->bv_val = am(myself,
1992*7c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].length);
1993*7c478bd9Sstevel@tonic-gate 				if (mods[nm]->mod_bvalues[j]->bv_val == 0) {
1994*7c478bd9Sstevel@tonic-gate 					freeLdapMod(mods);
1995*7c478bd9Sstevel@tonic-gate 					return (0);
1996*7c478bd9Sstevel@tonic-gate 				}
1997*7c478bd9Sstevel@tonic-gate 				mods[nm]->mod_bvalues[j]->bv_len =
1998*7c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].length;
1999*7c478bd9Sstevel@tonic-gate 				memcpy(mods[nm]->mod_bvalues[j]->bv_val,
2000*7c478bd9Sstevel@tonic-gate 					rv->attrVal[i].val[j].value,
2001*7c478bd9Sstevel@tonic-gate 					mods[nm]->mod_bvalues[j]->bv_len);
2002*7c478bd9Sstevel@tonic-gate 			}
2003*7c478bd9Sstevel@tonic-gate 		}
2004*7c478bd9Sstevel@tonic-gate 		nm++;
2005*7c478bd9Sstevel@tonic-gate 	}
2006*7c478bd9Sstevel@tonic-gate 
2007*7c478bd9Sstevel@tonic-gate 	return (mods);
2008*7c478bd9Sstevel@tonic-gate }
2009*7c478bd9Sstevel@tonic-gate 
2010*7c478bd9Sstevel@tonic-gate /*
2011*7c478bd9Sstevel@tonic-gate  * Remove 'value' from 'val'. If value==0, remove the entire
2012*7c478bd9Sstevel@tonic-gate  * __nis_single_value_t array from 'val'.
2013*7c478bd9Sstevel@tonic-gate  */
2014*7c478bd9Sstevel@tonic-gate static void
2015*7c478bd9Sstevel@tonic-gate removeSingleValue(__nis_value_t *val, void *value, int length) {
2016*7c478bd9Sstevel@tonic-gate 	int	i;
2017*7c478bd9Sstevel@tonic-gate 
2018*7c478bd9Sstevel@tonic-gate 	if (val == 0)
2019*7c478bd9Sstevel@tonic-gate 		return;
2020*7c478bd9Sstevel@tonic-gate 
2021*7c478bd9Sstevel@tonic-gate 	if (value == 0) {
2022*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < val->numVals; i++) {
2023*7c478bd9Sstevel@tonic-gate 			sfree(val->val[i].value);
2024*7c478bd9Sstevel@tonic-gate 		}
2025*7c478bd9Sstevel@tonic-gate 		sfree(val->val);
2026*7c478bd9Sstevel@tonic-gate 		val->val = 0;
2027*7c478bd9Sstevel@tonic-gate 		val->numVals = 0;
2028*7c478bd9Sstevel@tonic-gate 		return;
2029*7c478bd9Sstevel@tonic-gate 	}
2030*7c478bd9Sstevel@tonic-gate 
2031*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < val->numVals; i++) {
2032*7c478bd9Sstevel@tonic-gate 		if (val->val[i].value == 0 || (val->val[i].length != length))
2033*7c478bd9Sstevel@tonic-gate 			continue;
2034*7c478bd9Sstevel@tonic-gate 		if (memcmp(val->val[i].value, value, length) != 0)
2035*7c478bd9Sstevel@tonic-gate 			continue;
2036*7c478bd9Sstevel@tonic-gate 		sfree(val->val[i].value);
2037*7c478bd9Sstevel@tonic-gate 		if (i != (val->numVals - 1)) {
2038*7c478bd9Sstevel@tonic-gate 			(void) memmove(&val->val[i], &val->val[i+1],
2039*7c478bd9Sstevel@tonic-gate 				(val->numVals - 1 - i) * sizeof (val->val[0]));
2040*7c478bd9Sstevel@tonic-gate 		}
2041*7c478bd9Sstevel@tonic-gate 		val->numVals -= 1;
2042*7c478bd9Sstevel@tonic-gate 		break;
2043*7c478bd9Sstevel@tonic-gate 	}
2044*7c478bd9Sstevel@tonic-gate }
2045*7c478bd9Sstevel@tonic-gate 
2046*7c478bd9Sstevel@tonic-gate /*
2047*7c478bd9Sstevel@tonic-gate  * Helper function for LdapModify
2048*7c478bd9Sstevel@tonic-gate  * When a modify operation fails with an object class violation,
2049*7c478bd9Sstevel@tonic-gate  * the most probable reason is that the attributes we're modifying are new,
2050*7c478bd9Sstevel@tonic-gate  * and the needed object class are not present. So, try the modify again,
2051*7c478bd9Sstevel@tonic-gate  * but add the object classes this time.
2052*7c478bd9Sstevel@tonic-gate  */
2053*7c478bd9Sstevel@tonic-gate 
2054*7c478bd9Sstevel@tonic-gate static int
2055*7c478bd9Sstevel@tonic-gate ldapModifyObjectClass(__nis_ldap_conn_t **lc, char *dn,
2056*7c478bd9Sstevel@tonic-gate 		__nis_rule_value_t *rvIn, char *objClassAttrs)
2057*7c478bd9Sstevel@tonic-gate {
2058*7c478bd9Sstevel@tonic-gate 	LDAPMod			**mods = 0;
2059*7c478bd9Sstevel@tonic-gate 	int			msgid;
2060*7c478bd9Sstevel@tonic-gate 	int			lderr;
2061*7c478bd9Sstevel@tonic-gate 	struct timeval		tv;
2062*7c478bd9Sstevel@tonic-gate 	int			stat;
2063*7c478bd9Sstevel@tonic-gate 	LDAPMessage		*msg = 0;
2064*7c478bd9Sstevel@tonic-gate 	char			**referralsp = NULL;
2065*7c478bd9Sstevel@tonic-gate 	__nis_rule_value_t	*rv, *rvldap;
2066*7c478bd9Sstevel@tonic-gate 	__nis_ldap_search_t	*ls;
2067*7c478bd9Sstevel@tonic-gate 	int			i, ocrv, ocrvldap, nv;
2068*7c478bd9Sstevel@tonic-gate 	char			*oc[2] = { "objectClass", 0};
2069*7c478bd9Sstevel@tonic-gate 	char			*myself = "ldapModifyObjectClass";
2070*7c478bd9Sstevel@tonic-gate 
2071*7c478bd9Sstevel@tonic-gate 	rv = initRuleValue(1, rvIn);
2072*7c478bd9Sstevel@tonic-gate 	if (rv == 0)
2073*7c478bd9Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
2074*7c478bd9Sstevel@tonic-gate 
2075*7c478bd9Sstevel@tonic-gate 	delAttrFromRuleValue(rv, "objectClass");
2076*7c478bd9Sstevel@tonic-gate 	rv = addObjectClasses(rv, objClassAttrs);
2077*7c478bd9Sstevel@tonic-gate 	if (rv == 0) {
2078*7c478bd9Sstevel@tonic-gate 		stat = LDAP_OPERATIONS_ERROR;
2079*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_WARNING,
2080*7c478bd9Sstevel@tonic-gate 			"%s: addObjectClasses failed for %s",
2081*7c478bd9Sstevel@tonic-gate 			myself, NIL(dn));
2082*7c478bd9Sstevel@tonic-gate 		goto cleanup;
2083*7c478bd9Sstevel@tonic-gate 	}
2084*7c478bd9Sstevel@tonic-gate 
2085*7c478bd9Sstevel@tonic-gate 	/*
2086*7c478bd9Sstevel@tonic-gate 	 * Before adding the object classes whole-sale, try retrieving
2087*7c478bd9Sstevel@tonic-gate 	 * the entry specified by the 'dn'. If it exists, we filter out
2088*7c478bd9Sstevel@tonic-gate 	 * those object classes that already are present in LDAP from our
2089*7c478bd9Sstevel@tonic-gate 	 * update.
2090*7c478bd9Sstevel@tonic-gate 	 */
2091*7c478bd9Sstevel@tonic-gate 	ls = buildLdapSearch(dn, LDAP_SCOPE_BASE, 0, 0, "objectClass=*",
2092*7c478bd9Sstevel@tonic-gate 				oc, 0, 1);
2093*7c478bd9Sstevel@tonic-gate 	if (ls == 0) {
2094*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
2095*7c478bd9Sstevel@tonic-gate 			"%s: Unable to build DN search for \"%s\"",
2096*7c478bd9Sstevel@tonic-gate 			myself, NIL(dn));
2097*7c478bd9Sstevel@tonic-gate 		/* Fall through to try just adding the object classes */
2098*7c478bd9Sstevel@tonic-gate 		goto addObjectClasses;
2099*7c478bd9Sstevel@tonic-gate 	}
2100*7c478bd9Sstevel@tonic-gate 
2101*7c478bd9Sstevel@tonic-gate 	nv = 0;
2102*7c478bd9Sstevel@tonic-gate 	rvldap = ldapSearch(ls, &nv, 0, &lderr);
2103*7c478bd9Sstevel@tonic-gate 	freeLdapSearch(ls);
2104*7c478bd9Sstevel@tonic-gate 	if (rvldap == 0) {
2105*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
2106*7c478bd9Sstevel@tonic-gate 			"%s: No data for DN search (\"%s\"); LDAP status %d",
2107*7c478bd9Sstevel@tonic-gate 			myself, NIL(dn), lderr);
2108*7c478bd9Sstevel@tonic-gate 		/* Fall through to try just adding the object classes */
2109*7c478bd9Sstevel@tonic-gate 		goto addObjectClasses;
2110*7c478bd9Sstevel@tonic-gate 	}
2111*7c478bd9Sstevel@tonic-gate 
2112*7c478bd9Sstevel@tonic-gate 	/*
2113*7c478bd9Sstevel@tonic-gate 	 * Find the indices of the 'objectClass' attribute
2114*7c478bd9Sstevel@tonic-gate 	 * in 'rvldap' and 'rv'.
2115*7c478bd9Sstevel@tonic-gate 	 */
2116*7c478bd9Sstevel@tonic-gate 	for (i = 0, ocrvldap = -1; i < rvldap->numAttrs; i++) {
2117*7c478bd9Sstevel@tonic-gate 		if (rvldap->attrName[i] != 0 &&
2118*7c478bd9Sstevel@tonic-gate 			strcasecmp("objectClass", rvldap->attrName[i]) == 0) {
2119*7c478bd9Sstevel@tonic-gate 			ocrvldap = i;
2120*7c478bd9Sstevel@tonic-gate 			break;
2121*7c478bd9Sstevel@tonic-gate 		}
2122*7c478bd9Sstevel@tonic-gate 	}
2123*7c478bd9Sstevel@tonic-gate 	for (i = 0, ocrv = -1; i < rv->numAttrs; i++) {
2124*7c478bd9Sstevel@tonic-gate 		if (rv->attrName[i] != 0 &&
2125*7c478bd9Sstevel@tonic-gate 			strcasecmp("objectClass", rv->attrName[i]) == 0) {
2126*7c478bd9Sstevel@tonic-gate 			ocrv = i;
2127*7c478bd9Sstevel@tonic-gate 			break;
2128*7c478bd9Sstevel@tonic-gate 		}
2129*7c478bd9Sstevel@tonic-gate 	}
2130*7c478bd9Sstevel@tonic-gate 
2131*7c478bd9Sstevel@tonic-gate 	/*
2132*7c478bd9Sstevel@tonic-gate 	 * Remove those object classes that already exist
2133*7c478bd9Sstevel@tonic-gate 	 * in LDAP (i.e., in 'rvldap') from 'rv'.
2134*7c478bd9Sstevel@tonic-gate 	 */
2135*7c478bd9Sstevel@tonic-gate 	if (ocrv >= 0 && ocrvldap >= 0) {
2136*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < rvldap->attrVal[ocrvldap].numVals; i++) {
2137*7c478bd9Sstevel@tonic-gate 			removeSingleValue(&rv->attrVal[ocrv],
2138*7c478bd9Sstevel@tonic-gate 				rvldap->attrVal[ocrvldap].val[i].value,
2139*7c478bd9Sstevel@tonic-gate 				rvldap->attrVal[ocrvldap].val[i].length);
2140*7c478bd9Sstevel@tonic-gate 		}
2141*7c478bd9Sstevel@tonic-gate 		/*
2142*7c478bd9Sstevel@tonic-gate 		 * If no 'objectClass' values left in 'rv', delete
2143*7c478bd9Sstevel@tonic-gate 		 * 'objectClass' from 'rv'.
2144*7c478bd9Sstevel@tonic-gate 		 */
2145*7c478bd9Sstevel@tonic-gate 		if (rv->attrVal[ocrv].numVals == 0)
2146*7c478bd9Sstevel@tonic-gate 			delAttrFromRuleValue(rv, "objectClass");
2147*7c478bd9Sstevel@tonic-gate 	}
2148*7c478bd9Sstevel@tonic-gate 
2149*7c478bd9Sstevel@tonic-gate 	/*
2150*7c478bd9Sstevel@tonic-gate 	 * 'rv' now contains the update we want to make, with just the
2151*7c478bd9Sstevel@tonic-gate 	 * object class(es) that need to be added. Fall through to the
2152*7c478bd9Sstevel@tonic-gate 	 * actual LDAP modify operation.
2153*7c478bd9Sstevel@tonic-gate 	 */
2154*7c478bd9Sstevel@tonic-gate 	freeRuleValue(rvldap, 1);
2155*7c478bd9Sstevel@tonic-gate 
2156*7c478bd9Sstevel@tonic-gate addObjectClasses:
2157*7c478bd9Sstevel@tonic-gate 
2158*7c478bd9Sstevel@tonic-gate 	mods = search2LdapMod(rv, 0, 1);
2159*7c478bd9Sstevel@tonic-gate 	if (mods == 0) {
2160*7c478bd9Sstevel@tonic-gate 		stat = LDAP_OPERATIONS_ERROR;
2161*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_WARNING,
2162*7c478bd9Sstevel@tonic-gate 	"%s: Unable to create LDAP modify changes with object classes for %s",
2163*7c478bd9Sstevel@tonic-gate 			myself, NIL(dn));
2164*7c478bd9Sstevel@tonic-gate 		goto cleanup;
2165*7c478bd9Sstevel@tonic-gate 	}
2166*7c478bd9Sstevel@tonic-gate 	msgid = ldap_modify((*lc)->ld, dn, mods);
2167*7c478bd9Sstevel@tonic-gate 	if (msgid != -1) {
2168*7c478bd9Sstevel@tonic-gate 		tv = (*lc)->modifyTimeout;
2169*7c478bd9Sstevel@tonic-gate 		stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg);
2170*7c478bd9Sstevel@tonic-gate 		if (stat == 0) {
2171*7c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
2172*7c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
2173*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option((*lc)->ld,
2174*7c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
2175*7c478bd9Sstevel@tonic-gate 		} else {
2176*7c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result((*lc)->ld, msg, &lderr, NULL,
2177*7c478bd9Sstevel@tonic-gate 				NULL, &referralsp, NULL, 0);
2178*7c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
2179*7c478bd9Sstevel@tonic-gate 				stat = lderr;
2180*7c478bd9Sstevel@tonic-gate 			stat = ldap_result2error((*lc)->ld, msg, 0);
2181*7c478bd9Sstevel@tonic-gate 		}
2182*7c478bd9Sstevel@tonic-gate 	} else {
2183*7c478bd9Sstevel@tonic-gate 		(void) ldap_get_option((*lc)->ld, LDAP_OPT_ERROR_NUMBER,
2184*7c478bd9Sstevel@tonic-gate 			&stat);
2185*7c478bd9Sstevel@tonic-gate 	}
2186*7c478bd9Sstevel@tonic-gate 	if (proxyInfo.follow_referral == follow &&
2187*7c478bd9Sstevel@tonic-gate 			stat == LDAP_REFERRAL && referralsp != NULL) {
2188*7c478bd9Sstevel@tonic-gate 		releaseCon(*lc, stat);
2189*7c478bd9Sstevel@tonic-gate 		if (msg != NULL)
2190*7c478bd9Sstevel@tonic-gate 			(void) ldap_msgfree(msg);
2191*7c478bd9Sstevel@tonic-gate 		msg = NULL;
2192*7c478bd9Sstevel@tonic-gate 		*lc = findReferralCon(referralsp, &stat);
2193*7c478bd9Sstevel@tonic-gate 		ldap_value_free(referralsp);
2194*7c478bd9Sstevel@tonic-gate 		referralsp = NULL;
2195*7c478bd9Sstevel@tonic-gate 		if (*lc == NULL)
2196*7c478bd9Sstevel@tonic-gate 			goto cleanup;
2197*7c478bd9Sstevel@tonic-gate 		msgid = ldap_modify((*lc)->ld, dn, mods);
2198*7c478bd9Sstevel@tonic-gate 		if (msgid == -1) {
2199*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option((*lc)->ld,
2200*7c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
2201*7c478bd9Sstevel@tonic-gate 			goto cleanup;
2202*7c478bd9Sstevel@tonic-gate 		}
2203*7c478bd9Sstevel@tonic-gate 		stat = ldap_result((*lc)->ld, msgid, 0, &tv, &msg);
2204*7c478bd9Sstevel@tonic-gate 		if (stat == 0) {
2205*7c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
2206*7c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
2207*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option((*lc)->ld,
2208*7c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
2209*7c478bd9Sstevel@tonic-gate 		} else {
2210*7c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result((*lc)->ld, msg, &lderr,
2211*7c478bd9Sstevel@tonic-gate 				NULL, NULL, NULL, NULL, 0);
2212*7c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
2213*7c478bd9Sstevel@tonic-gate 				stat = lderr;
2214*7c478bd9Sstevel@tonic-gate 		}
2215*7c478bd9Sstevel@tonic-gate 	}
2216*7c478bd9Sstevel@tonic-gate cleanup:
2217*7c478bd9Sstevel@tonic-gate 	if (mods != 0)
2218*7c478bd9Sstevel@tonic-gate 		freeLdapMod(mods);
2219*7c478bd9Sstevel@tonic-gate 	freeRuleValue(rv, 1);
2220*7c478bd9Sstevel@tonic-gate 	return (stat);
2221*7c478bd9Sstevel@tonic-gate }
2222*7c478bd9Sstevel@tonic-gate 
2223*7c478bd9Sstevel@tonic-gate /*
2224*7c478bd9Sstevel@tonic-gate  * Modify the specified 'dn' per the attribute names/values in 'rv'.
2225*7c478bd9Sstevel@tonic-gate  * If 'rv' is NULL, we attempt to delete the entire entry.
2226*7c478bd9Sstevel@tonic-gate  *
2227*7c478bd9Sstevel@tonic-gate  * The 'objClassAttrs' parameter is needed if the entry must be added
2228*7c478bd9Sstevel@tonic-gate  * (i.e., created), or a modify fails with an object class violation.
2229*7c478bd9Sstevel@tonic-gate  *
2230*7c478bd9Sstevel@tonic-gate  * If 'addFirst' is set, we try an add before a modify; modify before
2231*7c478bd9Sstevel@tonic-gate  * add otherwise (ignored if we're deleting).
2232*7c478bd9Sstevel@tonic-gate  */
2233*7c478bd9Sstevel@tonic-gate int
2234*7c478bd9Sstevel@tonic-gate ldapModify(char *dn, __nis_rule_value_t *rv, char *objClassAttrs,
2235*7c478bd9Sstevel@tonic-gate 		int addFirst) {
2236*7c478bd9Sstevel@tonic-gate 	int			stat, add = 0;
2237*7c478bd9Sstevel@tonic-gate 	LDAPMod			**mods = 0;
2238*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc;
2239*7c478bd9Sstevel@tonic-gate 	struct timeval		tv;
2240*7c478bd9Sstevel@tonic-gate 	LDAPMessage		*msg = 0;
2241*7c478bd9Sstevel@tonic-gate 	char			*myself = "ldapModify";
2242*7c478bd9Sstevel@tonic-gate 	int			msgid;
2243*7c478bd9Sstevel@tonic-gate 	int			lderr;
2244*7c478bd9Sstevel@tonic-gate 	char			**referralsp = NULL;
2245*7c478bd9Sstevel@tonic-gate 	bool_t			delete = FALSE;
2246*7c478bd9Sstevel@tonic-gate 
2247*7c478bd9Sstevel@tonic-gate 	if (dn == 0)
2248*7c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
2249*7c478bd9Sstevel@tonic-gate 
2250*7c478bd9Sstevel@tonic-gate 	if ((lc = findCon(&stat)) == 0)
2251*7c478bd9Sstevel@tonic-gate 		return (stat);
2252*7c478bd9Sstevel@tonic-gate 
2253*7c478bd9Sstevel@tonic-gate 	if (rv == 0) {
2254*7c478bd9Sstevel@tonic-gate 		delete = TRUE;
2255*7c478bd9Sstevel@tonic-gate 		/* Simple case: if rv == 0, try to delete the entire entry */
2256*7c478bd9Sstevel@tonic-gate 		msgid = ldap_delete(lc->ld, dn);
2257*7c478bd9Sstevel@tonic-gate 		if (msgid == -1) {
2258*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2259*7c478bd9Sstevel@tonic-gate 						&stat);
2260*7c478bd9Sstevel@tonic-gate 			goto cleanup;
2261*7c478bd9Sstevel@tonic-gate 		}
2262*7c478bd9Sstevel@tonic-gate 		tv = lc->deleteTimeout;
2263*7c478bd9Sstevel@tonic-gate 		stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2264*7c478bd9Sstevel@tonic-gate 
2265*7c478bd9Sstevel@tonic-gate 		if (stat == 0) {
2266*7c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
2267*7c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
2268*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2269*7c478bd9Sstevel@tonic-gate 						&stat);
2270*7c478bd9Sstevel@tonic-gate 		} else {
2271*7c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
2272*7c478bd9Sstevel@tonic-gate 				NULL, &referralsp, NULL, 0);
2273*7c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
2274*7c478bd9Sstevel@tonic-gate 				stat = lderr;
2275*7c478bd9Sstevel@tonic-gate 		}
2276*7c478bd9Sstevel@tonic-gate 		if (proxyInfo.follow_referral == follow &&
2277*7c478bd9Sstevel@tonic-gate 				stat == LDAP_REFERRAL && referralsp != NULL) {
2278*7c478bd9Sstevel@tonic-gate 			releaseCon(lc, stat);
2279*7c478bd9Sstevel@tonic-gate 			if (msg != NULL)
2280*7c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(msg);
2281*7c478bd9Sstevel@tonic-gate 			msg = NULL;
2282*7c478bd9Sstevel@tonic-gate 			lc = findReferralCon(referralsp, &stat);
2283*7c478bd9Sstevel@tonic-gate 			ldap_value_free(referralsp);
2284*7c478bd9Sstevel@tonic-gate 			if (lc == NULL)
2285*7c478bd9Sstevel@tonic-gate 				goto cleanup;
2286*7c478bd9Sstevel@tonic-gate 			msgid = ldap_delete(lc->ld, dn);
2287*7c478bd9Sstevel@tonic-gate 			if (msgid == -1) {
2288*7c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(lc->ld,
2289*7c478bd9Sstevel@tonic-gate 					LDAP_OPT_ERROR_NUMBER, &stat);
2290*7c478bd9Sstevel@tonic-gate 				goto cleanup;
2291*7c478bd9Sstevel@tonic-gate 			}
2292*7c478bd9Sstevel@tonic-gate 			stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2293*7c478bd9Sstevel@tonic-gate 			if (stat == 0) {
2294*7c478bd9Sstevel@tonic-gate 				stat = LDAP_TIMEOUT;
2295*7c478bd9Sstevel@tonic-gate 			} else if (stat == -1) {
2296*7c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(lc->ld,
2297*7c478bd9Sstevel@tonic-gate 					LDAP_OPT_ERROR_NUMBER, &stat);
2298*7c478bd9Sstevel@tonic-gate 			} else {
2299*7c478bd9Sstevel@tonic-gate 				stat = ldap_parse_result(lc->ld, msg, &lderr,
2300*7c478bd9Sstevel@tonic-gate 					NULL, NULL, NULL, NULL, 0);
2301*7c478bd9Sstevel@tonic-gate 				if (stat == LDAP_SUCCESS)
2302*7c478bd9Sstevel@tonic-gate 					stat = lderr;
2303*7c478bd9Sstevel@tonic-gate 			}
2304*7c478bd9Sstevel@tonic-gate 		}
2305*7c478bd9Sstevel@tonic-gate 		/* No such object means someone else has done our job */
2306*7c478bd9Sstevel@tonic-gate 		if (stat == LDAP_NO_SUCH_OBJECT)
2307*7c478bd9Sstevel@tonic-gate 			stat = LDAP_SUCCESS;
2308*7c478bd9Sstevel@tonic-gate 	} else {
2309*7c478bd9Sstevel@tonic-gate 		if (addFirst) {
2310*7c478bd9Sstevel@tonic-gate 			stat = ldapAdd(dn, rv, objClassAttrs, lc);
2311*7c478bd9Sstevel@tonic-gate 			lc = NULL;
2312*7c478bd9Sstevel@tonic-gate 			if (stat != LDAP_ALREADY_EXISTS)
2313*7c478bd9Sstevel@tonic-gate 				goto cleanup;
2314*7c478bd9Sstevel@tonic-gate 			if ((lc = findCon(&stat)) == 0)
2315*7c478bd9Sstevel@tonic-gate 				return (stat);
2316*7c478bd9Sstevel@tonic-gate 		}
2317*7c478bd9Sstevel@tonic-gate 
2318*7c478bd9Sstevel@tonic-gate 		/*
2319*7c478bd9Sstevel@tonic-gate 		 * First try the modify without specifying object classes
2320*7c478bd9Sstevel@tonic-gate 		 * (i.e., assume they're already present).
2321*7c478bd9Sstevel@tonic-gate 		 */
2322*7c478bd9Sstevel@tonic-gate 		mods = search2LdapMod(rv, 0, 0);
2323*7c478bd9Sstevel@tonic-gate 		if (mods == 0) {
2324*7c478bd9Sstevel@tonic-gate 			stat = LDAP_PARAM_ERROR;
2325*7c478bd9Sstevel@tonic-gate 			goto cleanup;
2326*7c478bd9Sstevel@tonic-gate 		}
2327*7c478bd9Sstevel@tonic-gate 
2328*7c478bd9Sstevel@tonic-gate 		msgid = ldap_modify(lc->ld, dn, mods);
2329*7c478bd9Sstevel@tonic-gate 		if (msgid == -1) {
2330*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2331*7c478bd9Sstevel@tonic-gate 						&stat);
2332*7c478bd9Sstevel@tonic-gate 			goto cleanup;
2333*7c478bd9Sstevel@tonic-gate 		}
2334*7c478bd9Sstevel@tonic-gate 		tv = lc->modifyTimeout;
2335*7c478bd9Sstevel@tonic-gate 		stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2336*7c478bd9Sstevel@tonic-gate 		if (stat == 0) {
2337*7c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
2338*7c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
2339*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2340*7c478bd9Sstevel@tonic-gate 						&stat);
2341*7c478bd9Sstevel@tonic-gate 		} else {
2342*7c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
2343*7c478bd9Sstevel@tonic-gate 				NULL, &referralsp, NULL, 0);
2344*7c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
2345*7c478bd9Sstevel@tonic-gate 				stat = lderr;
2346*7c478bd9Sstevel@tonic-gate 		}
2347*7c478bd9Sstevel@tonic-gate 		if (proxyInfo.follow_referral == follow &&
2348*7c478bd9Sstevel@tonic-gate 				stat == LDAP_REFERRAL && referralsp != NULL) {
2349*7c478bd9Sstevel@tonic-gate 			releaseCon(lc, stat);
2350*7c478bd9Sstevel@tonic-gate 			if (msg != NULL)
2351*7c478bd9Sstevel@tonic-gate 				(void) ldap_msgfree(msg);
2352*7c478bd9Sstevel@tonic-gate 			msg = NULL;
2353*7c478bd9Sstevel@tonic-gate 			lc = findReferralCon(referralsp, &stat);
2354*7c478bd9Sstevel@tonic-gate 			ldap_value_free(referralsp);
2355*7c478bd9Sstevel@tonic-gate 			referralsp = NULL;
2356*7c478bd9Sstevel@tonic-gate 			if (lc == NULL)
2357*7c478bd9Sstevel@tonic-gate 				goto cleanup;
2358*7c478bd9Sstevel@tonic-gate 			msgid = ldap_modify(lc->ld, dn, mods);
2359*7c478bd9Sstevel@tonic-gate 			if (msgid == -1) {
2360*7c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(lc->ld,
2361*7c478bd9Sstevel@tonic-gate 					LDAP_OPT_ERROR_NUMBER, &stat);
2362*7c478bd9Sstevel@tonic-gate 				goto cleanup;
2363*7c478bd9Sstevel@tonic-gate 			}
2364*7c478bd9Sstevel@tonic-gate 			stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2365*7c478bd9Sstevel@tonic-gate 			if (stat == 0) {
2366*7c478bd9Sstevel@tonic-gate 				stat = LDAP_TIMEOUT;
2367*7c478bd9Sstevel@tonic-gate 			} else if (stat == -1) {
2368*7c478bd9Sstevel@tonic-gate 				(void) ldap_get_option(lc->ld,
2369*7c478bd9Sstevel@tonic-gate 					LDAP_OPT_ERROR_NUMBER, &stat);
2370*7c478bd9Sstevel@tonic-gate 			} else {
2371*7c478bd9Sstevel@tonic-gate 				stat = ldap_parse_result(lc->ld, msg, &lderr,
2372*7c478bd9Sstevel@tonic-gate 					NULL, NULL, NULL, NULL, 0);
2373*7c478bd9Sstevel@tonic-gate 				if (stat == LDAP_SUCCESS)
2374*7c478bd9Sstevel@tonic-gate 					stat = lderr;
2375*7c478bd9Sstevel@tonic-gate 			}
2376*7c478bd9Sstevel@tonic-gate 		}
2377*7c478bd9Sstevel@tonic-gate 
2378*7c478bd9Sstevel@tonic-gate 		/*
2379*7c478bd9Sstevel@tonic-gate 		 * If the modify failed with an object class violation,
2380*7c478bd9Sstevel@tonic-gate 		 * the most probable reason is that at least on of the
2381*7c478bd9Sstevel@tonic-gate 		 * attributes we're modifying didn't exist before, and
2382*7c478bd9Sstevel@tonic-gate 		 * neither did its object class. So, try the modify again,
2383*7c478bd9Sstevel@tonic-gate 		 * but add the object classes this time.
2384*7c478bd9Sstevel@tonic-gate 		 */
2385*7c478bd9Sstevel@tonic-gate 		if (stat == LDAP_OBJECT_CLASS_VIOLATION &&
2386*7c478bd9Sstevel@tonic-gate 				objClassAttrs != 0) {
2387*7c478bd9Sstevel@tonic-gate 			freeLdapMod(mods);
2388*7c478bd9Sstevel@tonic-gate 			mods = 0;
2389*7c478bd9Sstevel@tonic-gate 			stat = ldapModifyObjectClass(&lc, dn, rv,
2390*7c478bd9Sstevel@tonic-gate 				objClassAttrs);
2391*7c478bd9Sstevel@tonic-gate 		}
2392*7c478bd9Sstevel@tonic-gate 
2393*7c478bd9Sstevel@tonic-gate 		if (stat == LDAP_NO_SUCH_ATTRIBUTE) {
2394*7c478bd9Sstevel@tonic-gate 			/*
2395*7c478bd9Sstevel@tonic-gate 			 * If there was at least one attribute delete, then
2396*7c478bd9Sstevel@tonic-gate 			 * the cause of this error could be that said attribute
2397*7c478bd9Sstevel@tonic-gate 			 * didn't exist in LDAP. So, do things the slow way,
2398*7c478bd9Sstevel@tonic-gate 			 * and try to delete one attribute at a time.
2399*7c478bd9Sstevel@tonic-gate 			 */
2400*7c478bd9Sstevel@tonic-gate 			int			d, numDelete, st;
2401*7c478bd9Sstevel@tonic-gate 			__nis_rule_value_t	*rvt;
2402*7c478bd9Sstevel@tonic-gate 
2403*7c478bd9Sstevel@tonic-gate 			for (d = 0, numDelete = 0; d < rv->numAttrs; d++) {
2404*7c478bd9Sstevel@tonic-gate 				if (rv->attrVal[d].numVals < 0)
2405*7c478bd9Sstevel@tonic-gate 					numDelete++;
2406*7c478bd9Sstevel@tonic-gate 			}
2407*7c478bd9Sstevel@tonic-gate 
2408*7c478bd9Sstevel@tonic-gate 			/* If there's just one, we've already tried */
2409*7c478bd9Sstevel@tonic-gate 			if (numDelete <= 1)
2410*7c478bd9Sstevel@tonic-gate 				goto cleanup;
2411*7c478bd9Sstevel@tonic-gate 
2412*7c478bd9Sstevel@tonic-gate 			/* Make a copy of the rule value */
2413*7c478bd9Sstevel@tonic-gate 			rvt = initRuleValue(1, rv);
2414*7c478bd9Sstevel@tonic-gate 			if (rvt == 0)
2415*7c478bd9Sstevel@tonic-gate 				goto cleanup;
2416*7c478bd9Sstevel@tonic-gate 
2417*7c478bd9Sstevel@tonic-gate 			/*
2418*7c478bd9Sstevel@tonic-gate 			 * Remove all delete attributes from the tmp
2419*7c478bd9Sstevel@tonic-gate 			 * rule value.
2420*7c478bd9Sstevel@tonic-gate 			 */
2421*7c478bd9Sstevel@tonic-gate 			for (d = 0; d < rv->numAttrs; d++) {
2422*7c478bd9Sstevel@tonic-gate 				if (rv->attrVal[d].numVals < 0) {
2423*7c478bd9Sstevel@tonic-gate 					delAttrFromRuleValue(rvt,
2424*7c478bd9Sstevel@tonic-gate 						rv->attrName[d]);
2425*7c478bd9Sstevel@tonic-gate 				}
2426*7c478bd9Sstevel@tonic-gate 			}
2427*7c478bd9Sstevel@tonic-gate 
2428*7c478bd9Sstevel@tonic-gate 			/*
2429*7c478bd9Sstevel@tonic-gate 			 * Now put the attributes back in one by one, and
2430*7c478bd9Sstevel@tonic-gate 			 * invoke ourselves.
2431*7c478bd9Sstevel@tonic-gate 			 */
2432*7c478bd9Sstevel@tonic-gate 			for (d = 0; d < rv->numAttrs; d++) {
2433*7c478bd9Sstevel@tonic-gate 				if (rv->attrVal[d].numVals >= 0)
2434*7c478bd9Sstevel@tonic-gate 					continue;
2435*7c478bd9Sstevel@tonic-gate 				st = addAttr2RuleValue(rv->attrVal[d].type,
2436*7c478bd9Sstevel@tonic-gate 					rv->attrName[d], 0, 0, rvt);
2437*7c478bd9Sstevel@tonic-gate 				if (st != 0) {
2438*7c478bd9Sstevel@tonic-gate 					logmsg(MSG_NOMEM, LOG_ERR,
2439*7c478bd9Sstevel@tonic-gate 					"%s: Error deleting \"%s\" for \"%s\"",
2440*7c478bd9Sstevel@tonic-gate 						NIL(rv->attrName[d]), NIL(dn));
2441*7c478bd9Sstevel@tonic-gate 					stat = LDAP_NO_MEMORY;
2442*7c478bd9Sstevel@tonic-gate 					freeRuleValue(rvt, 1);
2443*7c478bd9Sstevel@tonic-gate 					goto cleanup;
2444*7c478bd9Sstevel@tonic-gate 				}
2445*7c478bd9Sstevel@tonic-gate 				stat = ldapModify(dn, rvt, objClassAttrs, 0);
2446*7c478bd9Sstevel@tonic-gate 				if (stat != LDAP_SUCCESS &&
2447*7c478bd9Sstevel@tonic-gate 					stat != LDAP_NO_SUCH_ATTRIBUTE) {
2448*7c478bd9Sstevel@tonic-gate 					freeRuleValue(rvt, 1);
2449*7c478bd9Sstevel@tonic-gate 					goto cleanup;
2450*7c478bd9Sstevel@tonic-gate 				}
2451*7c478bd9Sstevel@tonic-gate 				delAttrFromRuleValue(rvt, rv->attrName[d]);
2452*7c478bd9Sstevel@tonic-gate 			}
2453*7c478bd9Sstevel@tonic-gate 
2454*7c478bd9Sstevel@tonic-gate 			/*
2455*7c478bd9Sstevel@tonic-gate 			 * If we got here, then all attributes that should
2456*7c478bd9Sstevel@tonic-gate 			 * be deleted either have been, or didn't exist. For
2457*7c478bd9Sstevel@tonic-gate 			 * our purposes, the latter is as good as the former.
2458*7c478bd9Sstevel@tonic-gate 			 */
2459*7c478bd9Sstevel@tonic-gate 			stat = LDAP_SUCCESS;
2460*7c478bd9Sstevel@tonic-gate 			freeRuleValue(rvt, 1);
2461*7c478bd9Sstevel@tonic-gate 		}
2462*7c478bd9Sstevel@tonic-gate 
2463*7c478bd9Sstevel@tonic-gate 		if (stat == LDAP_NO_SUCH_OBJECT && !addFirst) {
2464*7c478bd9Sstevel@tonic-gate 			/*
2465*7c478bd9Sstevel@tonic-gate 			 * Entry doesn't exist, so try an ldap_add(). If the
2466*7c478bd9Sstevel@tonic-gate 			 * ldap_add() also fails, that could be because someone
2467*7c478bd9Sstevel@tonic-gate 			 * else added it between our modify and add operations.
2468*7c478bd9Sstevel@tonic-gate 			 * If so, we consider that foreign add to be
2469*7c478bd9Sstevel@tonic-gate 			 * authoritative (meaning we don't retry our modify).
2470*7c478bd9Sstevel@tonic-gate 			 *
2471*7c478bd9Sstevel@tonic-gate 			 * Also, if all modify operations specified by 'mods'
2472*7c478bd9Sstevel@tonic-gate 			 * are deletes, LDAP_NO_SUCH_OBJECT is a kind of
2473*7c478bd9Sstevel@tonic-gate 			 * success; we certainly don't want to create the
2474*7c478bd9Sstevel@tonic-gate 			 * entry.
2475*7c478bd9Sstevel@tonic-gate 			 */
2476*7c478bd9Sstevel@tonic-gate 			int	allDelete;
2477*7c478bd9Sstevel@tonic-gate 			LDAPMod	**m;
2478*7c478bd9Sstevel@tonic-gate 
2479*7c478bd9Sstevel@tonic-gate 			for (m = mods, allDelete = 1; *m != 0 && allDelete;
2480*7c478bd9Sstevel@tonic-gate 					m++) {
2481*7c478bd9Sstevel@tonic-gate 				if (((*m)->mod_op & LDAP_MOD_DELETE) == 0)
2482*7c478bd9Sstevel@tonic-gate 					allDelete = 0;
2483*7c478bd9Sstevel@tonic-gate 			}
2484*7c478bd9Sstevel@tonic-gate 
2485*7c478bd9Sstevel@tonic-gate 			add = 1;
2486*7c478bd9Sstevel@tonic-gate 
2487*7c478bd9Sstevel@tonic-gate 			if (allDelete) {
2488*7c478bd9Sstevel@tonic-gate 				stat = LDAP_SUCCESS;
2489*7c478bd9Sstevel@tonic-gate 			} else if (objClassAttrs == 0) {
2490*7c478bd9Sstevel@tonic-gate 				/* Now we need it, so this is fatal */
2491*7c478bd9Sstevel@tonic-gate 				stat = LDAP_PARAM_ERROR;
2492*7c478bd9Sstevel@tonic-gate 			} else {
2493*7c478bd9Sstevel@tonic-gate 				stat = ldapAdd(dn, rv, objClassAttrs, lc);
2494*7c478bd9Sstevel@tonic-gate 				lc = NULL;
2495*7c478bd9Sstevel@tonic-gate 			}
2496*7c478bd9Sstevel@tonic-gate 		}
2497*7c478bd9Sstevel@tonic-gate 	}
2498*7c478bd9Sstevel@tonic-gate 
2499*7c478bd9Sstevel@tonic-gate cleanup:
2500*7c478bd9Sstevel@tonic-gate 	if (stat != LDAP_SUCCESS) {
2501*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
2502*7c478bd9Sstevel@tonic-gate 			"%s(0x%x (%s), \"%s\") => %d (%s)\n",
2503*7c478bd9Sstevel@tonic-gate 			!delete ? (add ? "ldap_add" : "ldap_modify") :
2504*7c478bd9Sstevel@tonic-gate 				"ldap_delete",
2505*7c478bd9Sstevel@tonic-gate 			lc != NULL ? lc->ld : 0,
2506*7c478bd9Sstevel@tonic-gate 			lc != NULL ? NIL(lc->sp) : "nil",
2507*7c478bd9Sstevel@tonic-gate 			dn, stat, ldap_err2string(stat));
2508*7c478bd9Sstevel@tonic-gate 	}
2509*7c478bd9Sstevel@tonic-gate 
2510*7c478bd9Sstevel@tonic-gate 	releaseCon(lc, stat);
2511*7c478bd9Sstevel@tonic-gate 	freeLdapMod(mods);
2512*7c478bd9Sstevel@tonic-gate 	if (msg != 0)
2513*7c478bd9Sstevel@tonic-gate 		(void) ldap_msgfree(msg);
2514*7c478bd9Sstevel@tonic-gate 
2515*7c478bd9Sstevel@tonic-gate 	return (stat);
2516*7c478bd9Sstevel@tonic-gate }
2517*7c478bd9Sstevel@tonic-gate 
2518*7c478bd9Sstevel@tonic-gate /*
2519*7c478bd9Sstevel@tonic-gate  * Create the entry specified by 'dn' to have the values per 'rv'.
2520*7c478bd9Sstevel@tonic-gate  * The 'objClassAttrs' are the extra object classes we need when
2521*7c478bd9Sstevel@tonic-gate  * creating an entry.
2522*7c478bd9Sstevel@tonic-gate  *
2523*7c478bd9Sstevel@tonic-gate  * If 'lc' is non-NULL, we use that connection; otherwise, we find
2524*7c478bd9Sstevel@tonic-gate  * our own. CAUTION: This connection will be released on return. Regardless
2525*7c478bd9Sstevel@tonic-gate  * of return value, this connection should not subsequently used by the
2526*7c478bd9Sstevel@tonic-gate  * caller.
2527*7c478bd9Sstevel@tonic-gate  *
2528*7c478bd9Sstevel@tonic-gate  * Returns an LDAP status.
2529*7c478bd9Sstevel@tonic-gate  */
2530*7c478bd9Sstevel@tonic-gate int
2531*7c478bd9Sstevel@tonic-gate ldapAdd(char *dn, __nis_rule_value_t *rv, char *objClassAttrs, void *lcv) {
2532*7c478bd9Sstevel@tonic-gate 	int			stat;
2533*7c478bd9Sstevel@tonic-gate 	LDAPMod			**mods = 0;
2534*7c478bd9Sstevel@tonic-gate 	struct timeval		tv;
2535*7c478bd9Sstevel@tonic-gate 	LDAPMessage		*msg = 0;
2536*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc = lcv;
2537*7c478bd9Sstevel@tonic-gate 	int			msgid;
2538*7c478bd9Sstevel@tonic-gate 	int			lderr;
2539*7c478bd9Sstevel@tonic-gate 	char			**referralsp = NULL;
2540*7c478bd9Sstevel@tonic-gate 
2541*7c478bd9Sstevel@tonic-gate 	if (dn == 0 || rv == 0 || objClassAttrs == 0) {
2542*7c478bd9Sstevel@tonic-gate 		releaseCon(lc, LDAP_SUCCESS);
2543*7c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
2544*7c478bd9Sstevel@tonic-gate 	}
2545*7c478bd9Sstevel@tonic-gate 
2546*7c478bd9Sstevel@tonic-gate 	if (lc == 0) {
2547*7c478bd9Sstevel@tonic-gate 		if ((lc = findCon(&stat)) == 0)
2548*7c478bd9Sstevel@tonic-gate 			return (stat);
2549*7c478bd9Sstevel@tonic-gate 	}
2550*7c478bd9Sstevel@tonic-gate 
2551*7c478bd9Sstevel@tonic-gate 	rv = addObjectClasses(rv, objClassAttrs);
2552*7c478bd9Sstevel@tonic-gate 	if (rv == 0) {
2553*7c478bd9Sstevel@tonic-gate 		stat = LDAP_OPERATIONS_ERROR;
2554*7c478bd9Sstevel@tonic-gate 		goto cleanup;
2555*7c478bd9Sstevel@tonic-gate 	}
2556*7c478bd9Sstevel@tonic-gate 
2557*7c478bd9Sstevel@tonic-gate 	mods = search2LdapMod(rv, 1, 0);
2558*7c478bd9Sstevel@tonic-gate 	if (mods == 0) {
2559*7c478bd9Sstevel@tonic-gate 		stat = LDAP_OPERATIONS_ERROR;
2560*7c478bd9Sstevel@tonic-gate 		goto cleanup;
2561*7c478bd9Sstevel@tonic-gate 	}
2562*7c478bd9Sstevel@tonic-gate 
2563*7c478bd9Sstevel@tonic-gate 	msgid = ldap_add(lc->ld, dn, mods);
2564*7c478bd9Sstevel@tonic-gate 	if (msgid == -1) {
2565*7c478bd9Sstevel@tonic-gate 		(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
2566*7c478bd9Sstevel@tonic-gate 		goto cleanup;
2567*7c478bd9Sstevel@tonic-gate 	}
2568*7c478bd9Sstevel@tonic-gate 	tv = lc->addTimeout;
2569*7c478bd9Sstevel@tonic-gate 	stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2570*7c478bd9Sstevel@tonic-gate 	if (stat == 0) {
2571*7c478bd9Sstevel@tonic-gate 		stat = LDAP_TIMEOUT;
2572*7c478bd9Sstevel@tonic-gate 	} else if (stat == -1) {
2573*7c478bd9Sstevel@tonic-gate 		(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER, &stat);
2574*7c478bd9Sstevel@tonic-gate 	} else {
2575*7c478bd9Sstevel@tonic-gate 		stat = ldap_parse_result(lc->ld, msg, &lderr, NULL, NULL,
2576*7c478bd9Sstevel@tonic-gate 			&referralsp, NULL, 0);
2577*7c478bd9Sstevel@tonic-gate 		if (stat == LDAP_SUCCESS)
2578*7c478bd9Sstevel@tonic-gate 			stat = lderr;
2579*7c478bd9Sstevel@tonic-gate 	}
2580*7c478bd9Sstevel@tonic-gate 	if (proxyInfo.follow_referral == follow && stat == LDAP_REFERRAL &&
2581*7c478bd9Sstevel@tonic-gate 			referralsp != NULL) {
2582*7c478bd9Sstevel@tonic-gate 		releaseCon(lc, stat);
2583*7c478bd9Sstevel@tonic-gate 		if (msg != NULL)
2584*7c478bd9Sstevel@tonic-gate 			(void) ldap_msgfree(msg);
2585*7c478bd9Sstevel@tonic-gate 		msg = NULL;
2586*7c478bd9Sstevel@tonic-gate 		lc = findReferralCon(referralsp, &stat);
2587*7c478bd9Sstevel@tonic-gate 		ldap_value_free(referralsp);
2588*7c478bd9Sstevel@tonic-gate 		if (lc == NULL)
2589*7c478bd9Sstevel@tonic-gate 			goto cleanup;
2590*7c478bd9Sstevel@tonic-gate 		msgid = ldap_add(lc->ld, dn, mods);
2591*7c478bd9Sstevel@tonic-gate 		if (msgid == -1) {
2592*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld,
2593*7c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
2594*7c478bd9Sstevel@tonic-gate 			goto cleanup;
2595*7c478bd9Sstevel@tonic-gate 		}
2596*7c478bd9Sstevel@tonic-gate 		stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2597*7c478bd9Sstevel@tonic-gate 		if (stat == 0) {
2598*7c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
2599*7c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
2600*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2601*7c478bd9Sstevel@tonic-gate 						&stat);
2602*7c478bd9Sstevel@tonic-gate 		} else {
2603*7c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
2604*7c478bd9Sstevel@tonic-gate 				NULL, NULL, NULL, 0);
2605*7c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
2606*7c478bd9Sstevel@tonic-gate 				stat = lderr;
2607*7c478bd9Sstevel@tonic-gate 		}
2608*7c478bd9Sstevel@tonic-gate 	}
2609*7c478bd9Sstevel@tonic-gate 
2610*7c478bd9Sstevel@tonic-gate cleanup:
2611*7c478bd9Sstevel@tonic-gate 	if (stat != LDAP_SUCCESS) {
2612*7c478bd9Sstevel@tonic-gate 		logmsg(MSG_NOTIMECHECK, LOG_INFO,
2613*7c478bd9Sstevel@tonic-gate 			"ldap_add(0x%x (%s), \"%s\") => %d (%s)\n",
2614*7c478bd9Sstevel@tonic-gate 			lc != NULL ? lc->ld : 0,
2615*7c478bd9Sstevel@tonic-gate 			lc != NULL ? NIL(lc->sp) : "nil",
2616*7c478bd9Sstevel@tonic-gate 			dn, stat, ldap_err2string(stat));
2617*7c478bd9Sstevel@tonic-gate 	}
2618*7c478bd9Sstevel@tonic-gate 
2619*7c478bd9Sstevel@tonic-gate 	releaseCon(lc, stat);
2620*7c478bd9Sstevel@tonic-gate 	freeLdapMod(mods);
2621*7c478bd9Sstevel@tonic-gate 	if (msg != 0)
2622*7c478bd9Sstevel@tonic-gate 		(void) ldap_msgfree(msg);
2623*7c478bd9Sstevel@tonic-gate 
2624*7c478bd9Sstevel@tonic-gate 	return (stat);
2625*7c478bd9Sstevel@tonic-gate }
2626*7c478bd9Sstevel@tonic-gate 
2627*7c478bd9Sstevel@tonic-gate /*
2628*7c478bd9Sstevel@tonic-gate  * Change the entry at 'oldDn' to have the new DN (not RDN) 'dn'.
2629*7c478bd9Sstevel@tonic-gate  * Returns an LDAP error status.
2630*7c478bd9Sstevel@tonic-gate  */
2631*7c478bd9Sstevel@tonic-gate int
2632*7c478bd9Sstevel@tonic-gate ldapChangeDN(char *oldDn, char *dn) {
2633*7c478bd9Sstevel@tonic-gate 	int			stat;
2634*7c478bd9Sstevel@tonic-gate 	__nis_ldap_conn_t	*lc;
2635*7c478bd9Sstevel@tonic-gate 	int			i, j, lo, ln;
2636*7c478bd9Sstevel@tonic-gate 	char			*rdn;
2637*7c478bd9Sstevel@tonic-gate 	int			msgid;
2638*7c478bd9Sstevel@tonic-gate 	int			lderr;
2639*7c478bd9Sstevel@tonic-gate 	struct timeval		tv;
2640*7c478bd9Sstevel@tonic-gate 	LDAPMessage		*msg = 0;
2641*7c478bd9Sstevel@tonic-gate 	char			**referralsp = NULL;
2642*7c478bd9Sstevel@tonic-gate 	char			*myself = "ldapChangeDN";
2643*7c478bd9Sstevel@tonic-gate 
2644*7c478bd9Sstevel@tonic-gate 	if ((lo = slen(oldDn)) <= 0 || (ln = slen(dn)) <= 0)
2645*7c478bd9Sstevel@tonic-gate 		return (LDAP_PARAM_ERROR);
2646*7c478bd9Sstevel@tonic-gate 
2647*7c478bd9Sstevel@tonic-gate 	if (strcasecmp(oldDn, dn) == 0)
2648*7c478bd9Sstevel@tonic-gate 		return (LDAP_SUCCESS);
2649*7c478bd9Sstevel@tonic-gate 
2650*7c478bd9Sstevel@tonic-gate 	if ((lc = findCon(&stat)) == 0)
2651*7c478bd9Sstevel@tonic-gate 		return (stat);
2652*7c478bd9Sstevel@tonic-gate 
2653*7c478bd9Sstevel@tonic-gate 	rdn = sdup(myself, T, dn);
2654*7c478bd9Sstevel@tonic-gate 	if (rdn == 0) {
2655*7c478bd9Sstevel@tonic-gate 		releaseCon(lc, LDAP_SUCCESS);
2656*7c478bd9Sstevel@tonic-gate 		return (LDAP_NO_MEMORY);
2657*7c478bd9Sstevel@tonic-gate 	}
2658*7c478bd9Sstevel@tonic-gate 
2659*7c478bd9Sstevel@tonic-gate 	/* Compare old and new DN from the end */
2660*7c478bd9Sstevel@tonic-gate 	for (i = lo-1, j = ln-1; i >= 0 && j >= 0; i--, j--) {
2661*7c478bd9Sstevel@tonic-gate 		if (tolower(oldDn[i]) != tolower(rdn[j])) {
2662*7c478bd9Sstevel@tonic-gate 			/*
2663*7c478bd9Sstevel@tonic-gate 			 * Terminate 'rdn' after this character in order
2664*7c478bd9Sstevel@tonic-gate 			 * to snip off the portion of the new DN that is
2665*7c478bd9Sstevel@tonic-gate 			 * the same as the old DN. What remains in 'rdn'
2666*7c478bd9Sstevel@tonic-gate 			 * is the relative DN.
2667*7c478bd9Sstevel@tonic-gate 			 */
2668*7c478bd9Sstevel@tonic-gate 			rdn[j+1] = '\0';
2669*7c478bd9Sstevel@tonic-gate 			break;
2670*7c478bd9Sstevel@tonic-gate 		}
2671*7c478bd9Sstevel@tonic-gate 	}
2672*7c478bd9Sstevel@tonic-gate 
2673*7c478bd9Sstevel@tonic-gate 	stat = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL, &msgid);
2674*7c478bd9Sstevel@tonic-gate 
2675*7c478bd9Sstevel@tonic-gate 	if (msgid != -1) {
2676*7c478bd9Sstevel@tonic-gate 		tv = lc->modifyTimeout;
2677*7c478bd9Sstevel@tonic-gate 		stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2678*7c478bd9Sstevel@tonic-gate 		if (stat == 0) {
2679*7c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
2680*7c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
2681*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld,
2682*7c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
2683*7c478bd9Sstevel@tonic-gate 		} else {
2684*7c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lderr, NULL,
2685*7c478bd9Sstevel@tonic-gate 				NULL, &referralsp, NULL, 0);
2686*7c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
2687*7c478bd9Sstevel@tonic-gate 				stat = lderr;
2688*7c478bd9Sstevel@tonic-gate 			stat = ldap_result2error(lc->ld, msg, 0);
2689*7c478bd9Sstevel@tonic-gate 		}
2690*7c478bd9Sstevel@tonic-gate 	} else {
2691*7c478bd9Sstevel@tonic-gate 		(void) ldap_get_option(lc->ld, LDAP_OPT_ERROR_NUMBER,
2692*7c478bd9Sstevel@tonic-gate 			&stat);
2693*7c478bd9Sstevel@tonic-gate 	}
2694*7c478bd9Sstevel@tonic-gate 	if (proxyInfo.follow_referral == follow &&
2695*7c478bd9Sstevel@tonic-gate 			stat == LDAP_REFERRAL && referralsp != NULL) {
2696*7c478bd9Sstevel@tonic-gate 		releaseCon(lc, stat);
2697*7c478bd9Sstevel@tonic-gate 		if (msg != NULL)
2698*7c478bd9Sstevel@tonic-gate 			(void) ldap_msgfree(msg);
2699*7c478bd9Sstevel@tonic-gate 		msg = NULL;
2700*7c478bd9Sstevel@tonic-gate 		lc = findReferralCon(referralsp, &stat);
2701*7c478bd9Sstevel@tonic-gate 		ldap_value_free(referralsp);
2702*7c478bd9Sstevel@tonic-gate 		referralsp = NULL;
2703*7c478bd9Sstevel@tonic-gate 		if (lc == NULL)
2704*7c478bd9Sstevel@tonic-gate 			goto cleanup;
2705*7c478bd9Sstevel@tonic-gate 		msgid = ldap_rename(lc->ld, oldDn, rdn, NULL, 1, NULL, NULL,
2706*7c478bd9Sstevel@tonic-gate 			&msgid);
2707*7c478bd9Sstevel@tonic-gate 		if (msgid == -1) {
2708*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld,
2709*7c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
2710*7c478bd9Sstevel@tonic-gate 			goto cleanup;
2711*7c478bd9Sstevel@tonic-gate 		}
2712*7c478bd9Sstevel@tonic-gate 		stat = ldap_result(lc->ld, msgid, 0, &tv, &msg);
2713*7c478bd9Sstevel@tonic-gate 		if (stat == 0) {
2714*7c478bd9Sstevel@tonic-gate 			stat = LDAP_TIMEOUT;
2715*7c478bd9Sstevel@tonic-gate 		} else if (stat == -1) {
2716*7c478bd9Sstevel@tonic-gate 			(void) ldap_get_option(lc->ld,
2717*7c478bd9Sstevel@tonic-gate 				LDAP_OPT_ERROR_NUMBER, &stat);
2718*7c478bd9Sstevel@tonic-gate 		} else {
2719*7c478bd9Sstevel@tonic-gate 			stat = ldap_parse_result(lc->ld, msg, &lderr,
2720*7c478bd9Sstevel@tonic-gate 				NULL, NULL, NULL, NULL, 0);
2721*7c478bd9Sstevel@tonic-gate 			if (stat == LDAP_SUCCESS)
2722*7c478bd9Sstevel@tonic-gate 				stat = lderr;
2723*7c478bd9Sstevel@tonic-gate 		}
2724*7c478bd9Sstevel@tonic-gate 	}
2725*7c478bd9Sstevel@tonic-gate 
2726*7c478bd9Sstevel@tonic-gate cleanup:
2727*7c478bd9Sstevel@tonic-gate 	if (msg != NULL)
2728*7c478bd9Sstevel@tonic-gate 		(void) ldap_msgfree(msg);
2729*7c478bd9Sstevel@tonic-gate 
2730*7c478bd9Sstevel@tonic-gate #if	1
2731*7c478bd9Sstevel@tonic-gate 	fprintf(stderr, "%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s\n",
2732*7c478bd9Sstevel@tonic-gate 		myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn),
2733*7c478bd9Sstevel@tonic-gate 		ldap_err2string(stat));
2734*7c478bd9Sstevel@tonic-gate 	logmsg(MSG_NOTIMECHECK, LOG_WARNING,
2735*7c478bd9Sstevel@tonic-gate 		"%s: ldap_modrdn_s(0x%x, %s, %s, 1) => %s",
2736*7c478bd9Sstevel@tonic-gate 		myself, lc == NULL ? 0: lc->ld, NIL(oldDn), NIL(rdn),
2737*7c478bd9Sstevel@tonic-gate 		ldap_err2string(stat));
2738*7c478bd9Sstevel@tonic-gate #endif
2739*7c478bd9Sstevel@tonic-gate 
2740*7c478bd9Sstevel@tonic-gate 	if (stat == LDAP_NO_SUCH_OBJECT) {
2741*7c478bd9Sstevel@tonic-gate 		/*
2742*7c478bd9Sstevel@tonic-gate 		 * Fine from our point of view, since all we want to do
2743*7c478bd9Sstevel@tonic-gate 		 * is to make sure that an update to the new DN doesn't
2744*7c478bd9Sstevel@tonic-gate 		 * leave the old entry around.
2745*7c478bd9Sstevel@tonic-gate 		 */
2746*7c478bd9Sstevel@tonic-gate 		stat = LDAP_SUCCESS;
2747*7c478bd9Sstevel@tonic-gate 	}
2748*7c478bd9Sstevel@tonic-gate 
2749*7c478bd9Sstevel@tonic-gate 	releaseCon(lc, stat);
2750*7c478bd9Sstevel@tonic-gate 	sfree(rdn);
2751*7c478bd9Sstevel@tonic-gate 
2752*7c478bd9Sstevel@tonic-gate 	return (stat);
2753*7c478bd9Sstevel@tonic-gate }
2754