1*8040SBaban.Kenkre@Sun.COM /*
2*8040SBaban.Kenkre@Sun.COM  * CDDL HEADER START
3*8040SBaban.Kenkre@Sun.COM  *
4*8040SBaban.Kenkre@Sun.COM  * The contents of this file are subject to the terms of the
5*8040SBaban.Kenkre@Sun.COM  * Common Development and Distribution License (the "License").
6*8040SBaban.Kenkre@Sun.COM  * You may not use this file except in compliance with the License.
7*8040SBaban.Kenkre@Sun.COM  *
8*8040SBaban.Kenkre@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*8040SBaban.Kenkre@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*8040SBaban.Kenkre@Sun.COM  * See the License for the specific language governing permissions
11*8040SBaban.Kenkre@Sun.COM  * and limitations under the License.
12*8040SBaban.Kenkre@Sun.COM  *
13*8040SBaban.Kenkre@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*8040SBaban.Kenkre@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*8040SBaban.Kenkre@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*8040SBaban.Kenkre@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*8040SBaban.Kenkre@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*8040SBaban.Kenkre@Sun.COM  *
19*8040SBaban.Kenkre@Sun.COM  * CDDL HEADER END
20*8040SBaban.Kenkre@Sun.COM  */
21*8040SBaban.Kenkre@Sun.COM /*
22*8040SBaban.Kenkre@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*8040SBaban.Kenkre@Sun.COM  * Use is subject to license terms.
24*8040SBaban.Kenkre@Sun.COM  */
25*8040SBaban.Kenkre@Sun.COM 
26*8040SBaban.Kenkre@Sun.COM #include <alloca.h>
27*8040SBaban.Kenkre@Sun.COM #include <string.h>
28*8040SBaban.Kenkre@Sun.COM #include <strings.h>
29*8040SBaban.Kenkre@Sun.COM #include <lber.h>
30*8040SBaban.Kenkre@Sun.COM #include <sasl/sasl.h>
31*8040SBaban.Kenkre@Sun.COM #include <string.h>
32*8040SBaban.Kenkre@Sun.COM #include <ctype.h>
33*8040SBaban.Kenkre@Sun.COM #include <synch.h>
34*8040SBaban.Kenkre@Sun.COM #include <atomic.h>
35*8040SBaban.Kenkre@Sun.COM #include <errno.h>
36*8040SBaban.Kenkre@Sun.COM #include <assert.h>
37*8040SBaban.Kenkre@Sun.COM #include <limits.h>
38*8040SBaban.Kenkre@Sun.COM #include <sys/u8_textprep.h>
39*8040SBaban.Kenkre@Sun.COM #include <sys/varargs.h>
40*8040SBaban.Kenkre@Sun.COM #include "libadutils.h"
41*8040SBaban.Kenkre@Sun.COM #include "adutils_impl.h"
42*8040SBaban.Kenkre@Sun.COM 
43*8040SBaban.Kenkre@Sun.COM /* List of DSs, needed by the idle connection reaper thread */
44*8040SBaban.Kenkre@Sun.COM static pthread_mutex_t	adhostlock = PTHREAD_MUTEX_INITIALIZER;
45*8040SBaban.Kenkre@Sun.COM static adutils_host_t	*host_head = NULL;
46*8040SBaban.Kenkre@Sun.COM 
47*8040SBaban.Kenkre@Sun.COM /*
48*8040SBaban.Kenkre@Sun.COM  * List of query state structs -- needed so we can "route" LDAP results
49*8040SBaban.Kenkre@Sun.COM  * to the right context if multiple threads should be using the same
50*8040SBaban.Kenkre@Sun.COM  * connection concurrently
51*8040SBaban.Kenkre@Sun.COM  */
52*8040SBaban.Kenkre@Sun.COM static pthread_mutex_t		qstatelock = PTHREAD_MUTEX_INITIALIZER;
53*8040SBaban.Kenkre@Sun.COM static adutils_query_state_t	*qstatehead = NULL;
54*8040SBaban.Kenkre@Sun.COM 
55*8040SBaban.Kenkre@Sun.COM static char *adutils_sid_ber2str(BerValue *bvalues);
56*8040SBaban.Kenkre@Sun.COM static void adutils_lookup_batch_unlock(adutils_query_state_t **state);
57*8040SBaban.Kenkre@Sun.COM static void delete_ds(adutils_ad_t *ad, const char *host, int port);
58*8040SBaban.Kenkre@Sun.COM 
59*8040SBaban.Kenkre@Sun.COM typedef struct binary_attrs {
60*8040SBaban.Kenkre@Sun.COM 	const char	*name;
61*8040SBaban.Kenkre@Sun.COM 	char		*(*ber2str)(BerValue *bvalues);
62*8040SBaban.Kenkre@Sun.COM } binary_attrs_t;
63*8040SBaban.Kenkre@Sun.COM 
64*8040SBaban.Kenkre@Sun.COM static binary_attrs_t binattrs[] = {
65*8040SBaban.Kenkre@Sun.COM 	{"objectSID", adutils_sid_ber2str},
66*8040SBaban.Kenkre@Sun.COM 	{NULL, NULL}
67*8040SBaban.Kenkre@Sun.COM };
68*8040SBaban.Kenkre@Sun.COM 
69*8040SBaban.Kenkre@Sun.COM void
70*8040SBaban.Kenkre@Sun.COM adutils_set_log(int pri, bool_t syslog, bool_t degraded)
71*8040SBaban.Kenkre@Sun.COM {
72*8040SBaban.Kenkre@Sun.COM 	idmap_log_stderr(pri);
73*8040SBaban.Kenkre@Sun.COM 	idmap_log_syslog(syslog);
74*8040SBaban.Kenkre@Sun.COM 	idmap_log_degraded(degraded);
75*8040SBaban.Kenkre@Sun.COM }
76*8040SBaban.Kenkre@Sun.COM 
77*8040SBaban.Kenkre@Sun.COM /*
78*8040SBaban.Kenkre@Sun.COM  * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com"
79*8040SBaban.Kenkre@Sun.COM  */
80*8040SBaban.Kenkre@Sun.COM static
81*8040SBaban.Kenkre@Sun.COM char *
82*8040SBaban.Kenkre@Sun.COM adutils_dns2dn(const char *dns)
83*8040SBaban.Kenkre@Sun.COM {
84*8040SBaban.Kenkre@Sun.COM 	int	nameparts;
85*8040SBaban.Kenkre@Sun.COM 	return (ldap_dns_to_dn((char *)dns, &nameparts));
86*8040SBaban.Kenkre@Sun.COM }
87*8040SBaban.Kenkre@Sun.COM 
88*8040SBaban.Kenkre@Sun.COM /*
89*8040SBaban.Kenkre@Sun.COM  * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other
90*8040SBaban.Kenkre@Sun.COM  * attributes (CN, etc...).
91*8040SBaban.Kenkre@Sun.COM  */
92*8040SBaban.Kenkre@Sun.COM char *
93*8040SBaban.Kenkre@Sun.COM adutils_dn2dns(const char *dn)
94*8040SBaban.Kenkre@Sun.COM {
95*8040SBaban.Kenkre@Sun.COM 	char **rdns = NULL;
96*8040SBaban.Kenkre@Sun.COM 	char **attrs = NULL;
97*8040SBaban.Kenkre@Sun.COM 	char **labels = NULL;
98*8040SBaban.Kenkre@Sun.COM 	char *dns = NULL;
99*8040SBaban.Kenkre@Sun.COM 	char **rdn, **attr, **label;
100*8040SBaban.Kenkre@Sun.COM 	int maxlabels = 5;
101*8040SBaban.Kenkre@Sun.COM 	int nlabels = 0;
102*8040SBaban.Kenkre@Sun.COM 	int dnslen;
103*8040SBaban.Kenkre@Sun.COM 
104*8040SBaban.Kenkre@Sun.COM 	/*
105*8040SBaban.Kenkre@Sun.COM 	 * There is no reverse of ldap_dns_to_dn() in our libldap, so we
106*8040SBaban.Kenkre@Sun.COM 	 * have to do the hard work here for now.
107*8040SBaban.Kenkre@Sun.COM 	 */
108*8040SBaban.Kenkre@Sun.COM 
109*8040SBaban.Kenkre@Sun.COM 	/*
110*8040SBaban.Kenkre@Sun.COM 	 * This code is much too liberal: it looks for "dc" attributes
111*8040SBaban.Kenkre@Sun.COM 	 * in all RDNs of the DN.  In theory this could cause problems
112*8040SBaban.Kenkre@Sun.COM 	 * if people were to use "dc" in nodes other than the root of
113*8040SBaban.Kenkre@Sun.COM 	 * the tree, but in practice noone, least of all Active
114*8040SBaban.Kenkre@Sun.COM 	 * Directory, does that.
115*8040SBaban.Kenkre@Sun.COM 	 *
116*8040SBaban.Kenkre@Sun.COM 	 * On the other hand, this code is much too conservative: it
117*8040SBaban.Kenkre@Sun.COM 	 * does not make assumptions about ldap_explode_dn(), and _that_
118*8040SBaban.Kenkre@Sun.COM 	 * is the true for looking at every attr of every RDN.
119*8040SBaban.Kenkre@Sun.COM 	 *
120*8040SBaban.Kenkre@Sun.COM 	 * Since we only ever look at dc and those must be DNS labels,
121*8040SBaban.Kenkre@Sun.COM 	 * at least until we get around to supporting IDN here we
122*8040SBaban.Kenkre@Sun.COM 	 * shouldn't see escaped labels from AD nor from libldap, though
123*8040SBaban.Kenkre@Sun.COM 	 * the spec (RFC2253) does allow libldap to escape things that
124*8040SBaban.Kenkre@Sun.COM 	 * don't need escaping -- if that should ever happen then
125*8040SBaban.Kenkre@Sun.COM 	 * libldap will need a spanking, and we can take care of that.
126*8040SBaban.Kenkre@Sun.COM 	 */
127*8040SBaban.Kenkre@Sun.COM 
128*8040SBaban.Kenkre@Sun.COM 	/* Explode a DN into RDNs */
129*8040SBaban.Kenkre@Sun.COM 	if ((rdns = ldap_explode_dn(dn, 0)) == NULL)
130*8040SBaban.Kenkre@Sun.COM 		return (NULL);
131*8040SBaban.Kenkre@Sun.COM 
132*8040SBaban.Kenkre@Sun.COM 	labels = calloc(maxlabels + 1, sizeof (char *));
133*8040SBaban.Kenkre@Sun.COM 	label = labels;
134*8040SBaban.Kenkre@Sun.COM 
135*8040SBaban.Kenkre@Sun.COM 	for (rdn = rdns; *rdn != NULL; rdn++) {
136*8040SBaban.Kenkre@Sun.COM 		if (attrs != NULL)
137*8040SBaban.Kenkre@Sun.COM 			ldap_value_free(attrs);
138*8040SBaban.Kenkre@Sun.COM 
139*8040SBaban.Kenkre@Sun.COM 		/* Explode each RDN, look for DC attr, save val as DNS label */
140*8040SBaban.Kenkre@Sun.COM 		if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL)
141*8040SBaban.Kenkre@Sun.COM 			goto done;
142*8040SBaban.Kenkre@Sun.COM 
143*8040SBaban.Kenkre@Sun.COM 		for (attr = attrs; *attr != NULL; attr++) {
144*8040SBaban.Kenkre@Sun.COM 			if (strncasecmp(*attr, "dc=", 3) != 0)
145*8040SBaban.Kenkre@Sun.COM 				continue;
146*8040SBaban.Kenkre@Sun.COM 
147*8040SBaban.Kenkre@Sun.COM 			/* Found a DNS label */
148*8040SBaban.Kenkre@Sun.COM 			labels[nlabels++] = strdup((*attr) + 3);
149*8040SBaban.Kenkre@Sun.COM 
150*8040SBaban.Kenkre@Sun.COM 			if (nlabels == maxlabels) {
151*8040SBaban.Kenkre@Sun.COM 				char **tmp;
152*8040SBaban.Kenkre@Sun.COM 				tmp = realloc(labels,
153*8040SBaban.Kenkre@Sun.COM 				    sizeof (char *) * (maxlabels + 1));
154*8040SBaban.Kenkre@Sun.COM 
155*8040SBaban.Kenkre@Sun.COM 				if (tmp == NULL)
156*8040SBaban.Kenkre@Sun.COM 					goto done;
157*8040SBaban.Kenkre@Sun.COM 
158*8040SBaban.Kenkre@Sun.COM 				labels = tmp;
159*8040SBaban.Kenkre@Sun.COM 				labels[nlabels] = NULL;
160*8040SBaban.Kenkre@Sun.COM 			}
161*8040SBaban.Kenkre@Sun.COM 
162*8040SBaban.Kenkre@Sun.COM 			/* There should be just one DC= attr per-RDN */
163*8040SBaban.Kenkre@Sun.COM 			break;
164*8040SBaban.Kenkre@Sun.COM 		}
165*8040SBaban.Kenkre@Sun.COM 	}
166*8040SBaban.Kenkre@Sun.COM 
167*8040SBaban.Kenkre@Sun.COM 	/*
168*8040SBaban.Kenkre@Sun.COM 	 * Got all the labels, now join with '.'
169*8040SBaban.Kenkre@Sun.COM 	 *
170*8040SBaban.Kenkre@Sun.COM 	 * We need room for nlabels - 1 periods ('.'), one nul
171*8040SBaban.Kenkre@Sun.COM 	 * terminator, and the strlen() of each label.
172*8040SBaban.Kenkre@Sun.COM 	 */
173*8040SBaban.Kenkre@Sun.COM 	dnslen = nlabels;
174*8040SBaban.Kenkre@Sun.COM 	for (label = labels; *label != NULL; label++)
175*8040SBaban.Kenkre@Sun.COM 		dnslen += strlen(*label);
176*8040SBaban.Kenkre@Sun.COM 
177*8040SBaban.Kenkre@Sun.COM 	if ((dns = malloc(dnslen)) == NULL)
178*8040SBaban.Kenkre@Sun.COM 		goto done;
179*8040SBaban.Kenkre@Sun.COM 
180*8040SBaban.Kenkre@Sun.COM 	*dns = '\0';
181*8040SBaban.Kenkre@Sun.COM 
182*8040SBaban.Kenkre@Sun.COM 	for (label = labels; *label != NULL; label++) {
183*8040SBaban.Kenkre@Sun.COM 		(void) strlcat(dns, *label, dnslen);
184*8040SBaban.Kenkre@Sun.COM 		/*
185*8040SBaban.Kenkre@Sun.COM 		 * NOTE: the last '.' won't be appended -- there's no room
186*8040SBaban.Kenkre@Sun.COM 		 * for it!
187*8040SBaban.Kenkre@Sun.COM 		 */
188*8040SBaban.Kenkre@Sun.COM 		(void) strlcat(dns, ".", dnslen);
189*8040SBaban.Kenkre@Sun.COM 	}
190*8040SBaban.Kenkre@Sun.COM 
191*8040SBaban.Kenkre@Sun.COM done:
192*8040SBaban.Kenkre@Sun.COM 	if (labels != NULL) {
193*8040SBaban.Kenkre@Sun.COM 		for (label = labels; *label != NULL; label++)
194*8040SBaban.Kenkre@Sun.COM 			free(*label);
195*8040SBaban.Kenkre@Sun.COM 		free(labels);
196*8040SBaban.Kenkre@Sun.COM 	}
197*8040SBaban.Kenkre@Sun.COM 	if (attrs != NULL)
198*8040SBaban.Kenkre@Sun.COM 		ldap_value_free(attrs);
199*8040SBaban.Kenkre@Sun.COM 	if (rdns != NULL)
200*8040SBaban.Kenkre@Sun.COM 		ldap_value_free(rdns);
201*8040SBaban.Kenkre@Sun.COM 
202*8040SBaban.Kenkre@Sun.COM 	return (dns);
203*8040SBaban.Kenkre@Sun.COM }
204*8040SBaban.Kenkre@Sun.COM 
205*8040SBaban.Kenkre@Sun.COM /*
206*8040SBaban.Kenkre@Sun.COM  * Convert a binary SID in a BerValue to a adutils_sid_t
207*8040SBaban.Kenkre@Sun.COM  */
208*8040SBaban.Kenkre@Sun.COM static
209*8040SBaban.Kenkre@Sun.COM int
210*8040SBaban.Kenkre@Sun.COM getsid(BerValue *bval, adutils_sid_t *sidp)
211*8040SBaban.Kenkre@Sun.COM {
212*8040SBaban.Kenkre@Sun.COM 	int		i, j;
213*8040SBaban.Kenkre@Sun.COM 	uchar_t		*v;
214*8040SBaban.Kenkre@Sun.COM 	uint32_t	a;
215*8040SBaban.Kenkre@Sun.COM 
216*8040SBaban.Kenkre@Sun.COM 	/*
217*8040SBaban.Kenkre@Sun.COM 	 * The binary format of a SID is as follows:
218*8040SBaban.Kenkre@Sun.COM 	 *
219*8040SBaban.Kenkre@Sun.COM 	 * byte #0: version, always 0x01
220*8040SBaban.Kenkre@Sun.COM 	 * byte #1: RID count, always <= 0x0f
221*8040SBaban.Kenkre@Sun.COM 	 * bytes #2-#7: SID authority, big-endian 48-bit unsigned int
222*8040SBaban.Kenkre@Sun.COM 	 *
223*8040SBaban.Kenkre@Sun.COM 	 * followed by RID count RIDs, each a little-endian, unsigned
224*8040SBaban.Kenkre@Sun.COM 	 * 32-bit int.
225*8040SBaban.Kenkre@Sun.COM 	 */
226*8040SBaban.Kenkre@Sun.COM 	/*
227*8040SBaban.Kenkre@Sun.COM 	 * Sanity checks: must have at least one RID, version must be
228*8040SBaban.Kenkre@Sun.COM 	 * 0x01, and the length must be 8 + rid count * 4
229*8040SBaban.Kenkre@Sun.COM 	 */
230*8040SBaban.Kenkre@Sun.COM 	if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 &&
231*8040SBaban.Kenkre@Sun.COM 	    bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) {
232*8040SBaban.Kenkre@Sun.COM 		v = (uchar_t *)bval->bv_val;
233*8040SBaban.Kenkre@Sun.COM 		sidp->version = v[0];
234*8040SBaban.Kenkre@Sun.COM 		sidp->sub_authority_count = v[1];
235*8040SBaban.Kenkre@Sun.COM 		sidp->authority =
236*8040SBaban.Kenkre@Sun.COM 		    /* big endian -- so start from the left */
237*8040SBaban.Kenkre@Sun.COM 		    ((u_longlong_t)v[2] << 40) |
238*8040SBaban.Kenkre@Sun.COM 		    ((u_longlong_t)v[3] << 32) |
239*8040SBaban.Kenkre@Sun.COM 		    ((u_longlong_t)v[4] << 24) |
240*8040SBaban.Kenkre@Sun.COM 		    ((u_longlong_t)v[5] << 16) |
241*8040SBaban.Kenkre@Sun.COM 		    ((u_longlong_t)v[6] << 8) |
242*8040SBaban.Kenkre@Sun.COM 		    (u_longlong_t)v[7];
243*8040SBaban.Kenkre@Sun.COM 		for (i = 0; i < sidp->sub_authority_count; i++) {
244*8040SBaban.Kenkre@Sun.COM 			j = 8 + (i * 4);
245*8040SBaban.Kenkre@Sun.COM 			/* little endian -- so start from the right */
246*8040SBaban.Kenkre@Sun.COM 			a = (v[j + 3] << 24) | (v[j + 2] << 16) |
247*8040SBaban.Kenkre@Sun.COM 			    (v[j + 1] << 8) | (v[j]);
248*8040SBaban.Kenkre@Sun.COM 			sidp->sub_authorities[i] = a;
249*8040SBaban.Kenkre@Sun.COM 		}
250*8040SBaban.Kenkre@Sun.COM 		return (0);
251*8040SBaban.Kenkre@Sun.COM 	}
252*8040SBaban.Kenkre@Sun.COM 	return (-1);
253*8040SBaban.Kenkre@Sun.COM }
254*8040SBaban.Kenkre@Sun.COM 
255*8040SBaban.Kenkre@Sun.COM /*
256*8040SBaban.Kenkre@Sun.COM  * Convert a adutils_sid_t to S-1-...
257*8040SBaban.Kenkre@Sun.COM  */
258*8040SBaban.Kenkre@Sun.COM static
259*8040SBaban.Kenkre@Sun.COM char *
260*8040SBaban.Kenkre@Sun.COM sid2txt(adutils_sid_t *sidp)
261*8040SBaban.Kenkre@Sun.COM {
262*8040SBaban.Kenkre@Sun.COM 	int	rlen, i, len;
263*8040SBaban.Kenkre@Sun.COM 	char	*str, *cp;
264*8040SBaban.Kenkre@Sun.COM 
265*8040SBaban.Kenkre@Sun.COM 	if (sidp->version != 1)
266*8040SBaban.Kenkre@Sun.COM 		return (NULL);
267*8040SBaban.Kenkre@Sun.COM 
268*8040SBaban.Kenkre@Sun.COM 	len = sizeof ("S-1-") - 1;
269*8040SBaban.Kenkre@Sun.COM 
270*8040SBaban.Kenkre@Sun.COM 	/*
271*8040SBaban.Kenkre@Sun.COM 	 * We could optimize like so, but, why?
272*8040SBaban.Kenkre@Sun.COM 	 *	if (sidp->authority < 10)
273*8040SBaban.Kenkre@Sun.COM 	 *		len += 2;
274*8040SBaban.Kenkre@Sun.COM 	 *	else if (sidp->authority < 100)
275*8040SBaban.Kenkre@Sun.COM 	 *		len += 3;
276*8040SBaban.Kenkre@Sun.COM 	 *	else
277*8040SBaban.Kenkre@Sun.COM 	 *		len += snprintf(NULL, 0"%llu", sidp->authority);
278*8040SBaban.Kenkre@Sun.COM 	 */
279*8040SBaban.Kenkre@Sun.COM 	len += snprintf(NULL, 0, "%llu", sidp->authority);
280*8040SBaban.Kenkre@Sun.COM 
281*8040SBaban.Kenkre@Sun.COM 	/* Max length of a uint32_t printed out in ASCII is 10 bytes */
282*8040SBaban.Kenkre@Sun.COM 	len += 1 + (sidp->sub_authority_count + 1) * 10;
283*8040SBaban.Kenkre@Sun.COM 
284*8040SBaban.Kenkre@Sun.COM 	if ((cp = str = malloc(len)) == NULL)
285*8040SBaban.Kenkre@Sun.COM 		return (NULL);
286*8040SBaban.Kenkre@Sun.COM 
287*8040SBaban.Kenkre@Sun.COM 	rlen = snprintf(str, len, "S-1-%llu", sidp->authority);
288*8040SBaban.Kenkre@Sun.COM 
289*8040SBaban.Kenkre@Sun.COM 	cp += rlen;
290*8040SBaban.Kenkre@Sun.COM 	len -= rlen;
291*8040SBaban.Kenkre@Sun.COM 
292*8040SBaban.Kenkre@Sun.COM 	for (i = 0; i < sidp->sub_authority_count; i++) {
293*8040SBaban.Kenkre@Sun.COM 		assert(len > 0);
294*8040SBaban.Kenkre@Sun.COM 		rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]);
295*8040SBaban.Kenkre@Sun.COM 		cp += rlen;
296*8040SBaban.Kenkre@Sun.COM 		len -= rlen;
297*8040SBaban.Kenkre@Sun.COM 		assert(len >= 0);
298*8040SBaban.Kenkre@Sun.COM 	}
299*8040SBaban.Kenkre@Sun.COM 
300*8040SBaban.Kenkre@Sun.COM 	return (str);
301*8040SBaban.Kenkre@Sun.COM }
302*8040SBaban.Kenkre@Sun.COM 
303*8040SBaban.Kenkre@Sun.COM /*
304*8040SBaban.Kenkre@Sun.COM  * Convert a adutils_sid_t to on-the-wire encoding
305*8040SBaban.Kenkre@Sun.COM  */
306*8040SBaban.Kenkre@Sun.COM static
307*8040SBaban.Kenkre@Sun.COM int
308*8040SBaban.Kenkre@Sun.COM sid2binsid(adutils_sid_t *sid, uchar_t *binsid, int binsidlen)
309*8040SBaban.Kenkre@Sun.COM {
310*8040SBaban.Kenkre@Sun.COM 	uchar_t		*p;
311*8040SBaban.Kenkre@Sun.COM 	int		i;
312*8040SBaban.Kenkre@Sun.COM 	uint64_t	a;
313*8040SBaban.Kenkre@Sun.COM 	uint32_t	r;
314*8040SBaban.Kenkre@Sun.COM 
315*8040SBaban.Kenkre@Sun.COM 	if (sid->version != 1 ||
316*8040SBaban.Kenkre@Sun.COM 	    binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4))
317*8040SBaban.Kenkre@Sun.COM 		return (-1);
318*8040SBaban.Kenkre@Sun.COM 
319*8040SBaban.Kenkre@Sun.COM 	p = binsid;
320*8040SBaban.Kenkre@Sun.COM 	*p++ = 0x01;		/* version */
321*8040SBaban.Kenkre@Sun.COM 	/* sub authority count */
322*8040SBaban.Kenkre@Sun.COM 	*p++ = sid->sub_authority_count;
323*8040SBaban.Kenkre@Sun.COM 	/* Authority */
324*8040SBaban.Kenkre@Sun.COM 	a = sid->authority;
325*8040SBaban.Kenkre@Sun.COM 	/* big-endian -- start from left */
326*8040SBaban.Kenkre@Sun.COM 	*p++ = (a >> 40) & 0xFF;
327*8040SBaban.Kenkre@Sun.COM 	*p++ = (a >> 32) & 0xFF;
328*8040SBaban.Kenkre@Sun.COM 	*p++ = (a >> 24) & 0xFF;
329*8040SBaban.Kenkre@Sun.COM 	*p++ = (a >> 16) & 0xFF;
330*8040SBaban.Kenkre@Sun.COM 	*p++ = (a >> 8) & 0xFF;
331*8040SBaban.Kenkre@Sun.COM 	*p++ = a & 0xFF;
332*8040SBaban.Kenkre@Sun.COM 
333*8040SBaban.Kenkre@Sun.COM 	/* sub-authorities */
334*8040SBaban.Kenkre@Sun.COM 	for (i = 0; i < sid->sub_authority_count; i++) {
335*8040SBaban.Kenkre@Sun.COM 		r = sid->sub_authorities[i];
336*8040SBaban.Kenkre@Sun.COM 		/* little-endian -- start from right */
337*8040SBaban.Kenkre@Sun.COM 		*p++ = (r & 0x000000FF);
338*8040SBaban.Kenkre@Sun.COM 		*p++ = (r & 0x0000FF00) >> 8;
339*8040SBaban.Kenkre@Sun.COM 		*p++ = (r & 0x00FF0000) >> 16;
340*8040SBaban.Kenkre@Sun.COM 		*p++ = (r & 0xFF000000) >> 24;
341*8040SBaban.Kenkre@Sun.COM 	}
342*8040SBaban.Kenkre@Sun.COM 
343*8040SBaban.Kenkre@Sun.COM 	return (0);
344*8040SBaban.Kenkre@Sun.COM }
345*8040SBaban.Kenkre@Sun.COM 
346*8040SBaban.Kenkre@Sun.COM /*
347*8040SBaban.Kenkre@Sun.COM  * Convert a stringified SID (S-1-...) into a hex-encoded version of the
348*8040SBaban.Kenkre@Sun.COM  * on-the-wire encoding, but with each pair of hex digits pre-pended
349*8040SBaban.Kenkre@Sun.COM  * with a '\', so we can pass this to libldap.
350*8040SBaban.Kenkre@Sun.COM  */
351*8040SBaban.Kenkre@Sun.COM int
352*8040SBaban.Kenkre@Sun.COM adutils_txtsid2hexbinsid(const char *txt, const uint32_t *rid,
353*8040SBaban.Kenkre@Sun.COM 	char *hexbinsid, int hexbinsidlen)
354*8040SBaban.Kenkre@Sun.COM {
355*8040SBaban.Kenkre@Sun.COM 	adutils_sid_t	sid = { 0 };
356*8040SBaban.Kenkre@Sun.COM 	int		i, j;
357*8040SBaban.Kenkre@Sun.COM 	const char	*cp;
358*8040SBaban.Kenkre@Sun.COM 	char		*ecp;
359*8040SBaban.Kenkre@Sun.COM 	u_longlong_t	a;
360*8040SBaban.Kenkre@Sun.COM 	unsigned long	r;
361*8040SBaban.Kenkre@Sun.COM 	uchar_t		*binsid, b, hb;
362*8040SBaban.Kenkre@Sun.COM 
363*8040SBaban.Kenkre@Sun.COM 	/* Only version 1 SIDs please */
364*8040SBaban.Kenkre@Sun.COM 	if (strncmp(txt, "S-1-", strlen("S-1-")) != 0)
365*8040SBaban.Kenkre@Sun.COM 		return (-1);
366*8040SBaban.Kenkre@Sun.COM 
367*8040SBaban.Kenkre@Sun.COM 	if (strlen(txt) < (strlen("S-1-") + 1))
368*8040SBaban.Kenkre@Sun.COM 		return (-1);
369*8040SBaban.Kenkre@Sun.COM 
370*8040SBaban.Kenkre@Sun.COM 	/* count '-'s */
371*8040SBaban.Kenkre@Sun.COM 	for (j = 0, cp = strchr(txt, '-');
372*8040SBaban.Kenkre@Sun.COM 	    cp != NULL && *cp != '\0';
373*8040SBaban.Kenkre@Sun.COM 	    j++, cp = strchr(cp + 1, '-')) {
374*8040SBaban.Kenkre@Sun.COM 		/* can't end on a '-' */
375*8040SBaban.Kenkre@Sun.COM 		if (*(cp + 1) == '\0')
376*8040SBaban.Kenkre@Sun.COM 			return (-1);
377*8040SBaban.Kenkre@Sun.COM 	}
378*8040SBaban.Kenkre@Sun.COM 
379*8040SBaban.Kenkre@Sun.COM 	/* Adjust count for version and authority */
380*8040SBaban.Kenkre@Sun.COM 	j -= 2;
381*8040SBaban.Kenkre@Sun.COM 
382*8040SBaban.Kenkre@Sun.COM 	/* we know the version number and RID count */
383*8040SBaban.Kenkre@Sun.COM 	sid.version = 1;
384*8040SBaban.Kenkre@Sun.COM 	sid.sub_authority_count = (rid != NULL) ? j + 1 : j;
385*8040SBaban.Kenkre@Sun.COM 
386*8040SBaban.Kenkre@Sun.COM 	/* must have at least one RID, but not too many */
387*8040SBaban.Kenkre@Sun.COM 	if (sid.sub_authority_count < 1 ||
388*8040SBaban.Kenkre@Sun.COM 	    sid.sub_authority_count > ADUTILS_SID_MAX_SUB_AUTHORITIES)
389*8040SBaban.Kenkre@Sun.COM 		return (-1);
390*8040SBaban.Kenkre@Sun.COM 
391*8040SBaban.Kenkre@Sun.COM 	/* check that we only have digits and '-' */
392*8040SBaban.Kenkre@Sun.COM 	if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1))
393*8040SBaban.Kenkre@Sun.COM 		return (-1);
394*8040SBaban.Kenkre@Sun.COM 
395*8040SBaban.Kenkre@Sun.COM 	cp = txt + strlen("S-1-");
396*8040SBaban.Kenkre@Sun.COM 
397*8040SBaban.Kenkre@Sun.COM 	/* 64-bit safe parsing of unsigned 48-bit authority value */
398*8040SBaban.Kenkre@Sun.COM 	errno = 0;
399*8040SBaban.Kenkre@Sun.COM 	a = strtoull(cp, &ecp, 10);
400*8040SBaban.Kenkre@Sun.COM 
401*8040SBaban.Kenkre@Sun.COM 	/* errors parsing the authority or too many bits */
402*8040SBaban.Kenkre@Sun.COM 	if (cp == ecp || (a == 0 && errno == EINVAL) ||
403*8040SBaban.Kenkre@Sun.COM 	    (a == ULLONG_MAX && errno == ERANGE) ||
404*8040SBaban.Kenkre@Sun.COM 	    (a & 0x0000ffffffffffffULL) != a)
405*8040SBaban.Kenkre@Sun.COM 		return (-1);
406*8040SBaban.Kenkre@Sun.COM 
407*8040SBaban.Kenkre@Sun.COM 	cp = ecp;
408*8040SBaban.Kenkre@Sun.COM 
409*8040SBaban.Kenkre@Sun.COM 	sid.authority = (uint64_t)a;
410*8040SBaban.Kenkre@Sun.COM 
411*8040SBaban.Kenkre@Sun.COM 	for (i = 0; i < j; i++) {
412*8040SBaban.Kenkre@Sun.COM 		if (*cp++ != '-')
413*8040SBaban.Kenkre@Sun.COM 			return (-1);
414*8040SBaban.Kenkre@Sun.COM 		/* 64-bit safe parsing of unsigned 32-bit RID */
415*8040SBaban.Kenkre@Sun.COM 		errno = 0;
416*8040SBaban.Kenkre@Sun.COM 		r = strtoul(cp, &ecp, 10);
417*8040SBaban.Kenkre@Sun.COM 		/* errors parsing the RID or too many bits */
418*8040SBaban.Kenkre@Sun.COM 		if (cp == ecp || (r == 0 && errno == EINVAL) ||
419*8040SBaban.Kenkre@Sun.COM 		    (r == ULONG_MAX && errno == ERANGE) ||
420*8040SBaban.Kenkre@Sun.COM 		    (r & 0xffffffffUL) != r)
421*8040SBaban.Kenkre@Sun.COM 			return (-1);
422*8040SBaban.Kenkre@Sun.COM 		sid.sub_authorities[i] = (uint32_t)r;
423*8040SBaban.Kenkre@Sun.COM 		cp = ecp;
424*8040SBaban.Kenkre@Sun.COM 	}
425*8040SBaban.Kenkre@Sun.COM 
426*8040SBaban.Kenkre@Sun.COM 	/* check that all of the string SID has been consumed */
427*8040SBaban.Kenkre@Sun.COM 	if (*cp != '\0')
428*8040SBaban.Kenkre@Sun.COM 		return (-1);
429*8040SBaban.Kenkre@Sun.COM 
430*8040SBaban.Kenkre@Sun.COM 	if (rid != NULL)
431*8040SBaban.Kenkre@Sun.COM 		sid.sub_authorities[j] = *rid;
432*8040SBaban.Kenkre@Sun.COM 
433*8040SBaban.Kenkre@Sun.COM 	j = 1 + 1 + 6 + sid.sub_authority_count * 4;
434*8040SBaban.Kenkre@Sun.COM 
435*8040SBaban.Kenkre@Sun.COM 	if (hexbinsidlen < (j * 3))
436*8040SBaban.Kenkre@Sun.COM 		return (-2);
437*8040SBaban.Kenkre@Sun.COM 
438*8040SBaban.Kenkre@Sun.COM 	/* binary encode the SID */
439*8040SBaban.Kenkre@Sun.COM 	binsid = (uchar_t *)alloca(j);
440*8040SBaban.Kenkre@Sun.COM 	(void) sid2binsid(&sid, binsid, j);
441*8040SBaban.Kenkre@Sun.COM 
442*8040SBaban.Kenkre@Sun.COM 	/* hex encode, with a backslash before each byte */
443*8040SBaban.Kenkre@Sun.COM 	for (ecp = hexbinsid, i = 0; i < j; i++) {
444*8040SBaban.Kenkre@Sun.COM 		b = binsid[i];
445*8040SBaban.Kenkre@Sun.COM 		*ecp++ = '\\';
446*8040SBaban.Kenkre@Sun.COM 		hb = (b >> 4) & 0xF;
447*8040SBaban.Kenkre@Sun.COM 		*ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
448*8040SBaban.Kenkre@Sun.COM 		hb = b & 0xF;
449*8040SBaban.Kenkre@Sun.COM 		*ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
450*8040SBaban.Kenkre@Sun.COM 	}
451*8040SBaban.Kenkre@Sun.COM 	*ecp = '\0';
452*8040SBaban.Kenkre@Sun.COM 
453*8040SBaban.Kenkre@Sun.COM 	return (0);
454*8040SBaban.Kenkre@Sun.COM }
455*8040SBaban.Kenkre@Sun.COM 
456*8040SBaban.Kenkre@Sun.COM static
457*8040SBaban.Kenkre@Sun.COM char *
458*8040SBaban.Kenkre@Sun.COM convert_bval2sid(BerValue *bval, uint32_t *rid)
459*8040SBaban.Kenkre@Sun.COM {
460*8040SBaban.Kenkre@Sun.COM 	adutils_sid_t	sid;
461*8040SBaban.Kenkre@Sun.COM 
462*8040SBaban.Kenkre@Sun.COM 	if (getsid(bval, &sid) < 0)
463*8040SBaban.Kenkre@Sun.COM 		return (NULL);
464*8040SBaban.Kenkre@Sun.COM 
465*8040SBaban.Kenkre@Sun.COM 	/*
466*8040SBaban.Kenkre@Sun.COM 	 * If desired and if the SID is what should be a domain/computer
467*8040SBaban.Kenkre@Sun.COM 	 * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then
468*8040SBaban.Kenkre@Sun.COM 	 * save the last RID and truncate the SID
469*8040SBaban.Kenkre@Sun.COM 	 */
470*8040SBaban.Kenkre@Sun.COM 	if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5)
471*8040SBaban.Kenkre@Sun.COM 		*rid = sid.sub_authorities[--sid.sub_authority_count];
472*8040SBaban.Kenkre@Sun.COM 	return (sid2txt(&sid));
473*8040SBaban.Kenkre@Sun.COM }
474*8040SBaban.Kenkre@Sun.COM 
475*8040SBaban.Kenkre@Sun.COM 
476*8040SBaban.Kenkre@Sun.COM /*
477*8040SBaban.Kenkre@Sun.COM  * Return a NUL-terminated stringified SID from the value of an
478*8040SBaban.Kenkre@Sun.COM  * objectSid attribute and put the last RID in *rid.
479*8040SBaban.Kenkre@Sun.COM  */
480*8040SBaban.Kenkre@Sun.COM char *
481*8040SBaban.Kenkre@Sun.COM adutils_bv_objsid2sidstr(BerValue *bval, uint32_t *rid)
482*8040SBaban.Kenkre@Sun.COM {
483*8040SBaban.Kenkre@Sun.COM 	char *sid;
484*8040SBaban.Kenkre@Sun.COM 
485*8040SBaban.Kenkre@Sun.COM 	if (bval == NULL)
486*8040SBaban.Kenkre@Sun.COM 		return (NULL);
487*8040SBaban.Kenkre@Sun.COM 	/* objectSid is single valued */
488*8040SBaban.Kenkre@Sun.COM 	if ((sid = convert_bval2sid(bval, rid)) == NULL)
489*8040SBaban.Kenkre@Sun.COM 		return (NULL);
490*8040SBaban.Kenkre@Sun.COM 	return (sid);
491*8040SBaban.Kenkre@Sun.COM }
492*8040SBaban.Kenkre@Sun.COM 
493*8040SBaban.Kenkre@Sun.COM static
494*8040SBaban.Kenkre@Sun.COM char *
495*8040SBaban.Kenkre@Sun.COM adutils_sid_ber2str(BerValue *bval)
496*8040SBaban.Kenkre@Sun.COM {
497*8040SBaban.Kenkre@Sun.COM 	return (adutils_bv_objsid2sidstr(bval, NULL));
498*8040SBaban.Kenkre@Sun.COM }
499*8040SBaban.Kenkre@Sun.COM 
500*8040SBaban.Kenkre@Sun.COM 
501*8040SBaban.Kenkre@Sun.COM /* Return a NUL-terminated string from the Ber value */
502*8040SBaban.Kenkre@Sun.COM char *
503*8040SBaban.Kenkre@Sun.COM adutils_bv_name2str(BerValue *bval)
504*8040SBaban.Kenkre@Sun.COM {
505*8040SBaban.Kenkre@Sun.COM 	char *s;
506*8040SBaban.Kenkre@Sun.COM 
507*8040SBaban.Kenkre@Sun.COM 	if (bval == NULL || bval->bv_val == NULL)
508*8040SBaban.Kenkre@Sun.COM 		return (NULL);
509*8040SBaban.Kenkre@Sun.COM 	if ((s = malloc(bval->bv_len + 1)) == NULL)
510*8040SBaban.Kenkre@Sun.COM 		return (NULL);
511*8040SBaban.Kenkre@Sun.COM 	(void) snprintf(s, bval->bv_len + 1, "%.*s", bval->bv_len,
512*8040SBaban.Kenkre@Sun.COM 	    bval->bv_val);
513*8040SBaban.Kenkre@Sun.COM 	return (s);
514*8040SBaban.Kenkre@Sun.COM }
515*8040SBaban.Kenkre@Sun.COM 
516*8040SBaban.Kenkre@Sun.COM /*ARGSUSED*/
517*8040SBaban.Kenkre@Sun.COM static
518*8040SBaban.Kenkre@Sun.COM int
519*8040SBaban.Kenkre@Sun.COM saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts)
520*8040SBaban.Kenkre@Sun.COM {
521*8040SBaban.Kenkre@Sun.COM 	sasl_interact_t	*interact;
522*8040SBaban.Kenkre@Sun.COM 
523*8040SBaban.Kenkre@Sun.COM 	if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
524*8040SBaban.Kenkre@Sun.COM 		return (LDAP_PARAM_ERROR);
525*8040SBaban.Kenkre@Sun.COM 
526*8040SBaban.Kenkre@Sun.COM 	/* There should be no extra arguemnts for SASL/GSSAPI authentication */
527*8040SBaban.Kenkre@Sun.COM 	for (interact = prompts; interact->id != SASL_CB_LIST_END;
528*8040SBaban.Kenkre@Sun.COM 	    interact++) {
529*8040SBaban.Kenkre@Sun.COM 		interact->result = NULL;
530*8040SBaban.Kenkre@Sun.COM 		interact->len = 0;
531*8040SBaban.Kenkre@Sun.COM 	}
532*8040SBaban.Kenkre@Sun.COM 	return (LDAP_SUCCESS);
533*8040SBaban.Kenkre@Sun.COM }
534*8040SBaban.Kenkre@Sun.COM 
535*8040SBaban.Kenkre@Sun.COM 
536*8040SBaban.Kenkre@Sun.COM #define	ADCONN_TIME	300
537*8040SBaban.Kenkre@Sun.COM 
538*8040SBaban.Kenkre@Sun.COM /*
539*8040SBaban.Kenkre@Sun.COM  * Idle connection reaping side of connection management
540*8040SBaban.Kenkre@Sun.COM  */
541*8040SBaban.Kenkre@Sun.COM void
542*8040SBaban.Kenkre@Sun.COM adutils_reap_idle_connections()
543*8040SBaban.Kenkre@Sun.COM {
544*8040SBaban.Kenkre@Sun.COM 	adutils_host_t	*adh;
545*8040SBaban.Kenkre@Sun.COM 	time_t		now;
546*8040SBaban.Kenkre@Sun.COM 
547*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&adhostlock);
548*8040SBaban.Kenkre@Sun.COM 	now = time(NULL);
549*8040SBaban.Kenkre@Sun.COM 	for (adh = host_head; adh != NULL; adh = adh->next) {
550*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_lock(&adh->lock);
551*8040SBaban.Kenkre@Sun.COM 		if (adh->ref == 0 && adh->idletime != 0 &&
552*8040SBaban.Kenkre@Sun.COM 		    adh->idletime + ADCONN_TIME < now) {
553*8040SBaban.Kenkre@Sun.COM 			if (adh->ld) {
554*8040SBaban.Kenkre@Sun.COM 				(void) ldap_unbind(adh->ld);
555*8040SBaban.Kenkre@Sun.COM 				adh->ld = NULL;
556*8040SBaban.Kenkre@Sun.COM 				adh->idletime = 0;
557*8040SBaban.Kenkre@Sun.COM 				adh->ref = 0;
558*8040SBaban.Kenkre@Sun.COM 			}
559*8040SBaban.Kenkre@Sun.COM 		}
560*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&adh->lock);
561*8040SBaban.Kenkre@Sun.COM 	}
562*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&adhostlock);
563*8040SBaban.Kenkre@Sun.COM }
564*8040SBaban.Kenkre@Sun.COM 
565*8040SBaban.Kenkre@Sun.COM 
566*8040SBaban.Kenkre@Sun.COM adutils_rc
567*8040SBaban.Kenkre@Sun.COM adutils_ad_alloc(adutils_ad_t **new_ad, const char *default_domain,
568*8040SBaban.Kenkre@Sun.COM 	adutils_ad_partition_t part)
569*8040SBaban.Kenkre@Sun.COM {
570*8040SBaban.Kenkre@Sun.COM 	adutils_ad_t *ad;
571*8040SBaban.Kenkre@Sun.COM 
572*8040SBaban.Kenkre@Sun.COM 	*new_ad = NULL;
573*8040SBaban.Kenkre@Sun.COM 
574*8040SBaban.Kenkre@Sun.COM 	if ((default_domain == NULL || *default_domain == '\0') &&
575*8040SBaban.Kenkre@Sun.COM 	    part != ADUTILS_AD_GLOBAL_CATALOG)
576*8040SBaban.Kenkre@Sun.COM 		return (ADUTILS_ERR_DOMAIN);
577*8040SBaban.Kenkre@Sun.COM 	if ((ad = calloc(1, sizeof (*ad))) == NULL)
578*8040SBaban.Kenkre@Sun.COM 		return (ADUTILS_ERR_MEMORY);
579*8040SBaban.Kenkre@Sun.COM 	ad->ref = 1;
580*8040SBaban.Kenkre@Sun.COM 	ad->partition = part;
581*8040SBaban.Kenkre@Sun.COM 	if (default_domain == NULL)
582*8040SBaban.Kenkre@Sun.COM 		default_domain = "";
583*8040SBaban.Kenkre@Sun.COM 	if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL)
584*8040SBaban.Kenkre@Sun.COM 		goto err;
585*8040SBaban.Kenkre@Sun.COM 	if (pthread_mutex_init(&ad->lock, NULL) != 0)
586*8040SBaban.Kenkre@Sun.COM 		goto err;
587*8040SBaban.Kenkre@Sun.COM 	*new_ad = ad;
588*8040SBaban.Kenkre@Sun.COM 	return (ADUTILS_SUCCESS);
589*8040SBaban.Kenkre@Sun.COM 
590*8040SBaban.Kenkre@Sun.COM err:
591*8040SBaban.Kenkre@Sun.COM 	if (ad->dflt_w2k_dom != NULL)
592*8040SBaban.Kenkre@Sun.COM 		free(ad->dflt_w2k_dom);
593*8040SBaban.Kenkre@Sun.COM 	free(ad);
594*8040SBaban.Kenkre@Sun.COM 	return (ADUTILS_ERR_MEMORY);
595*8040SBaban.Kenkre@Sun.COM }
596*8040SBaban.Kenkre@Sun.COM 
597*8040SBaban.Kenkre@Sun.COM void
598*8040SBaban.Kenkre@Sun.COM adutils_ad_free(adutils_ad_t **ad)
599*8040SBaban.Kenkre@Sun.COM {
600*8040SBaban.Kenkre@Sun.COM 	adutils_host_t *p;
601*8040SBaban.Kenkre@Sun.COM 	adutils_host_t *prev;
602*8040SBaban.Kenkre@Sun.COM 
603*8040SBaban.Kenkre@Sun.COM 	if (ad == NULL || *ad == NULL)
604*8040SBaban.Kenkre@Sun.COM 		return;
605*8040SBaban.Kenkre@Sun.COM 
606*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&(*ad)->lock);
607*8040SBaban.Kenkre@Sun.COM 
608*8040SBaban.Kenkre@Sun.COM 	if (atomic_dec_32_nv(&(*ad)->ref) > 0) {
609*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&(*ad)->lock);
610*8040SBaban.Kenkre@Sun.COM 		*ad = NULL;
611*8040SBaban.Kenkre@Sun.COM 		return;
612*8040SBaban.Kenkre@Sun.COM 	}
613*8040SBaban.Kenkre@Sun.COM 
614*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&adhostlock);
615*8040SBaban.Kenkre@Sun.COM 	prev = NULL;
616*8040SBaban.Kenkre@Sun.COM 	p = host_head;
617*8040SBaban.Kenkre@Sun.COM 	while (p != NULL) {
618*8040SBaban.Kenkre@Sun.COM 		if (p->owner != (*ad)) {
619*8040SBaban.Kenkre@Sun.COM 			prev = p;
620*8040SBaban.Kenkre@Sun.COM 			p = p->next;
621*8040SBaban.Kenkre@Sun.COM 			continue;
622*8040SBaban.Kenkre@Sun.COM 		} else {
623*8040SBaban.Kenkre@Sun.COM 			delete_ds((*ad), p->host, p->port);
624*8040SBaban.Kenkre@Sun.COM 			if (prev == NULL)
625*8040SBaban.Kenkre@Sun.COM 				p = host_head;
626*8040SBaban.Kenkre@Sun.COM 			else
627*8040SBaban.Kenkre@Sun.COM 				p = prev->next;
628*8040SBaban.Kenkre@Sun.COM 		}
629*8040SBaban.Kenkre@Sun.COM 	}
630*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&adhostlock);
631*8040SBaban.Kenkre@Sun.COM 
632*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&(*ad)->lock);
633*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_destroy(&(*ad)->lock);
634*8040SBaban.Kenkre@Sun.COM 
635*8040SBaban.Kenkre@Sun.COM 	free((*ad)->dflt_w2k_dom);
636*8040SBaban.Kenkre@Sun.COM 	free(*ad);
637*8040SBaban.Kenkre@Sun.COM 
638*8040SBaban.Kenkre@Sun.COM 	*ad = NULL;
639*8040SBaban.Kenkre@Sun.COM }
640*8040SBaban.Kenkre@Sun.COM 
641*8040SBaban.Kenkre@Sun.COM static
642*8040SBaban.Kenkre@Sun.COM int
643*8040SBaban.Kenkre@Sun.COM open_conn(adutils_host_t *adh, int timeoutsecs)
644*8040SBaban.Kenkre@Sun.COM {
645*8040SBaban.Kenkre@Sun.COM 	int zero = 0;
646*8040SBaban.Kenkre@Sun.COM 	int ldversion, rc;
647*8040SBaban.Kenkre@Sun.COM 	int timeoutms = timeoutsecs * 1000;
648*8040SBaban.Kenkre@Sun.COM 
649*8040SBaban.Kenkre@Sun.COM 	if (adh == NULL)
650*8040SBaban.Kenkre@Sun.COM 		return (0);
651*8040SBaban.Kenkre@Sun.COM 
652*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&adh->lock);
653*8040SBaban.Kenkre@Sun.COM 
654*8040SBaban.Kenkre@Sun.COM 	if (!adh->dead && adh->ld != NULL)
655*8040SBaban.Kenkre@Sun.COM 		/* done! */
656*8040SBaban.Kenkre@Sun.COM 		goto out;
657*8040SBaban.Kenkre@Sun.COM 
658*8040SBaban.Kenkre@Sun.COM 	if (adh->ld != NULL) {
659*8040SBaban.Kenkre@Sun.COM 		(void) ldap_unbind(adh->ld);
660*8040SBaban.Kenkre@Sun.COM 		adh->ld = NULL;
661*8040SBaban.Kenkre@Sun.COM 	}
662*8040SBaban.Kenkre@Sun.COM 	adh->num_requests = 0;
663*8040SBaban.Kenkre@Sun.COM 
664*8040SBaban.Kenkre@Sun.COM 	atomic_inc_64(&adh->generation);
665*8040SBaban.Kenkre@Sun.COM 
666*8040SBaban.Kenkre@Sun.COM 	/* Open and bind an LDAP connection */
667*8040SBaban.Kenkre@Sun.COM 	adh->ld = ldap_init(adh->host, adh->port);
668*8040SBaban.Kenkre@Sun.COM 	if (adh->ld == NULL) {
669*8040SBaban.Kenkre@Sun.COM 		idmapdlog(LOG_INFO, "ldap_init() to server "
670*8040SBaban.Kenkre@Sun.COM 		    "%s port %d failed. (%s)", adh->host,
671*8040SBaban.Kenkre@Sun.COM 		    adh->port, strerror(errno));
672*8040SBaban.Kenkre@Sun.COM 		goto out;
673*8040SBaban.Kenkre@Sun.COM 	}
674*8040SBaban.Kenkre@Sun.COM 	ldversion = LDAP_VERSION3;
675*8040SBaban.Kenkre@Sun.COM 	(void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion);
676*8040SBaban.Kenkre@Sun.COM 	(void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
677*8040SBaban.Kenkre@Sun.COM 	(void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero);
678*8040SBaban.Kenkre@Sun.COM 	(void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero);
679*8040SBaban.Kenkre@Sun.COM 	(void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms);
680*8040SBaban.Kenkre@Sun.COM 	(void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
681*8040SBaban.Kenkre@Sun.COM 	rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */,
682*8040SBaban.Kenkre@Sun.COM 	    adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback,
683*8040SBaban.Kenkre@Sun.COM 	    NULL);
684*8040SBaban.Kenkre@Sun.COM 
685*8040SBaban.Kenkre@Sun.COM 	if (rc != LDAP_SUCCESS) {
686*8040SBaban.Kenkre@Sun.COM 		(void) ldap_unbind(adh->ld);
687*8040SBaban.Kenkre@Sun.COM 		adh->ld = NULL;
688*8040SBaban.Kenkre@Sun.COM 		idmapdlog(LOG_INFO, "ldap_sasl_interactive_bind_s() to server "
689*8040SBaban.Kenkre@Sun.COM 		    "%s port %d failed. (%s)", adh->host, adh->port,
690*8040SBaban.Kenkre@Sun.COM 		    ldap_err2string(rc));
691*8040SBaban.Kenkre@Sun.COM 	}
692*8040SBaban.Kenkre@Sun.COM 
693*8040SBaban.Kenkre@Sun.COM 	idmapdlog(LOG_DEBUG, "Using global catalog server %s:%d",
694*8040SBaban.Kenkre@Sun.COM 	    adh->host, adh->port);
695*8040SBaban.Kenkre@Sun.COM 
696*8040SBaban.Kenkre@Sun.COM out:
697*8040SBaban.Kenkre@Sun.COM 	if (adh->ld != NULL) {
698*8040SBaban.Kenkre@Sun.COM 		atomic_inc_32(&adh->ref);
699*8040SBaban.Kenkre@Sun.COM 		adh->idletime = time(NULL);
700*8040SBaban.Kenkre@Sun.COM 		adh->dead = 0;
701*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&adh->lock);
702*8040SBaban.Kenkre@Sun.COM 		return (1);
703*8040SBaban.Kenkre@Sun.COM 	}
704*8040SBaban.Kenkre@Sun.COM 
705*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&adh->lock);
706*8040SBaban.Kenkre@Sun.COM 	return (0);
707*8040SBaban.Kenkre@Sun.COM }
708*8040SBaban.Kenkre@Sun.COM 
709*8040SBaban.Kenkre@Sun.COM 
710*8040SBaban.Kenkre@Sun.COM /*
711*8040SBaban.Kenkre@Sun.COM  * Connection management: find an open connection or open one
712*8040SBaban.Kenkre@Sun.COM  */
713*8040SBaban.Kenkre@Sun.COM static
714*8040SBaban.Kenkre@Sun.COM adutils_host_t *
715*8040SBaban.Kenkre@Sun.COM get_conn(adutils_ad_t *ad)
716*8040SBaban.Kenkre@Sun.COM {
717*8040SBaban.Kenkre@Sun.COM 	adutils_host_t	*adh = NULL;
718*8040SBaban.Kenkre@Sun.COM 	int		tries;
719*8040SBaban.Kenkre@Sun.COM 	int		dscount = 0;
720*8040SBaban.Kenkre@Sun.COM 	int		timeoutsecs = ADUTILS_LDAP_OPEN_TIMEOUT;
721*8040SBaban.Kenkre@Sun.COM 
722*8040SBaban.Kenkre@Sun.COM retry:
723*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&adhostlock);
724*8040SBaban.Kenkre@Sun.COM 
725*8040SBaban.Kenkre@Sun.COM 	if (host_head == NULL) {
726*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&adhostlock);
727*8040SBaban.Kenkre@Sun.COM 		goto out;
728*8040SBaban.Kenkre@Sun.COM 	}
729*8040SBaban.Kenkre@Sun.COM 
730*8040SBaban.Kenkre@Sun.COM 	if (dscount == 0) {
731*8040SBaban.Kenkre@Sun.COM 		/*
732*8040SBaban.Kenkre@Sun.COM 		 * First try: count the number of DSes.
733*8040SBaban.Kenkre@Sun.COM 		 *
734*8040SBaban.Kenkre@Sun.COM 		 * Integer overflow is not an issue -- we can't have so many
735*8040SBaban.Kenkre@Sun.COM 		 * DSes because they won't fit even DNS over TCP, and SMF
736*8040SBaban.Kenkre@Sun.COM 		 * shouldn't let you set so many.
737*8040SBaban.Kenkre@Sun.COM 		 */
738*8040SBaban.Kenkre@Sun.COM 		for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) {
739*8040SBaban.Kenkre@Sun.COM 			if (adh->owner == ad)
740*8040SBaban.Kenkre@Sun.COM 				dscount++;
741*8040SBaban.Kenkre@Sun.COM 		}
742*8040SBaban.Kenkre@Sun.COM 
743*8040SBaban.Kenkre@Sun.COM 		if (dscount == 0) {
744*8040SBaban.Kenkre@Sun.COM 			(void) pthread_mutex_unlock(&adhostlock);
745*8040SBaban.Kenkre@Sun.COM 			goto out;
746*8040SBaban.Kenkre@Sun.COM 		}
747*8040SBaban.Kenkre@Sun.COM 
748*8040SBaban.Kenkre@Sun.COM 		tries = dscount * 3;	/* three tries per-ds */
749*8040SBaban.Kenkre@Sun.COM 
750*8040SBaban.Kenkre@Sun.COM 		/*
751*8040SBaban.Kenkre@Sun.COM 		 * Begin round-robin at the next DS in the list after the last
752*8040SBaban.Kenkre@Sun.COM 		 * one that we had a connection to, else start with the first
753*8040SBaban.Kenkre@Sun.COM 		 * DS in the list.
754*8040SBaban.Kenkre@Sun.COM 		 */
755*8040SBaban.Kenkre@Sun.COM 		adh = ad->last_adh;
756*8040SBaban.Kenkre@Sun.COM 	}
757*8040SBaban.Kenkre@Sun.COM 
758*8040SBaban.Kenkre@Sun.COM 	/*
759*8040SBaban.Kenkre@Sun.COM 	 * Round-robin -- pick the next one on the list; if the list
760*8040SBaban.Kenkre@Sun.COM 	 * changes on us, no big deal, we'll just potentially go
761*8040SBaban.Kenkre@Sun.COM 	 * around the wrong number of times.
762*8040SBaban.Kenkre@Sun.COM 	 */
763*8040SBaban.Kenkre@Sun.COM 	for (;;) {
764*8040SBaban.Kenkre@Sun.COM 		if (adh != NULL && adh->ld != NULL && !adh->dead)
765*8040SBaban.Kenkre@Sun.COM 			break;
766*8040SBaban.Kenkre@Sun.COM 		if (adh == NULL || (adh = adh->next) == NULL)
767*8040SBaban.Kenkre@Sun.COM 			adh = host_head;
768*8040SBaban.Kenkre@Sun.COM 		if (adh->owner == ad)
769*8040SBaban.Kenkre@Sun.COM 			break;
770*8040SBaban.Kenkre@Sun.COM 	}
771*8040SBaban.Kenkre@Sun.COM 
772*8040SBaban.Kenkre@Sun.COM 	ad->last_adh = adh;
773*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&adhostlock);
774*8040SBaban.Kenkre@Sun.COM 
775*8040SBaban.Kenkre@Sun.COM 	/* Found suitable DS, open it if not already opened */
776*8040SBaban.Kenkre@Sun.COM 	if (open_conn(adh, timeoutsecs))
777*8040SBaban.Kenkre@Sun.COM 		return (adh);
778*8040SBaban.Kenkre@Sun.COM 
779*8040SBaban.Kenkre@Sun.COM 	tries--;
780*8040SBaban.Kenkre@Sun.COM 	if ((tries % dscount) == 0)
781*8040SBaban.Kenkre@Sun.COM 		timeoutsecs *= 2;
782*8040SBaban.Kenkre@Sun.COM 	if (tries > 0)
783*8040SBaban.Kenkre@Sun.COM 		goto retry;
784*8040SBaban.Kenkre@Sun.COM 
785*8040SBaban.Kenkre@Sun.COM out:
786*8040SBaban.Kenkre@Sun.COM 	idmapdlog(LOG_NOTICE, "Couldn't open an LDAP connection to any global "
787*8040SBaban.Kenkre@Sun.COM 	    "catalog server!");
788*8040SBaban.Kenkre@Sun.COM 	return (NULL);
789*8040SBaban.Kenkre@Sun.COM }
790*8040SBaban.Kenkre@Sun.COM 
791*8040SBaban.Kenkre@Sun.COM static
792*8040SBaban.Kenkre@Sun.COM void
793*8040SBaban.Kenkre@Sun.COM release_conn(adutils_host_t *adh)
794*8040SBaban.Kenkre@Sun.COM {
795*8040SBaban.Kenkre@Sun.COM 	int delete = 0;
796*8040SBaban.Kenkre@Sun.COM 
797*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&adh->lock);
798*8040SBaban.Kenkre@Sun.COM 	if (atomic_dec_32_nv(&adh->ref) == 0) {
799*8040SBaban.Kenkre@Sun.COM 		if (adh->owner == NULL)
800*8040SBaban.Kenkre@Sun.COM 			delete = 1;
801*8040SBaban.Kenkre@Sun.COM 		adh->idletime = time(NULL);
802*8040SBaban.Kenkre@Sun.COM 	}
803*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&adh->lock);
804*8040SBaban.Kenkre@Sun.COM 
805*8040SBaban.Kenkre@Sun.COM 	/* Free this host if its owner no longer exists. */
806*8040SBaban.Kenkre@Sun.COM 	if (delete) {
807*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_lock(&adhostlock);
808*8040SBaban.Kenkre@Sun.COM 		delete_ds(NULL, adh->host, adh->port);
809*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&adhostlock);
810*8040SBaban.Kenkre@Sun.COM 	}
811*8040SBaban.Kenkre@Sun.COM }
812*8040SBaban.Kenkre@Sun.COM 
813*8040SBaban.Kenkre@Sun.COM /*
814*8040SBaban.Kenkre@Sun.COM  * Create a adutils_host_t, populate it and add it to the list of hosts.
815*8040SBaban.Kenkre@Sun.COM  */
816*8040SBaban.Kenkre@Sun.COM adutils_rc
817*8040SBaban.Kenkre@Sun.COM adutils_add_ds(adutils_ad_t *ad, const char *host, int port)
818*8040SBaban.Kenkre@Sun.COM {
819*8040SBaban.Kenkre@Sun.COM 	adutils_host_t	*p;
820*8040SBaban.Kenkre@Sun.COM 	adutils_host_t	*new = NULL;
821*8040SBaban.Kenkre@Sun.COM 	int		ret;
822*8040SBaban.Kenkre@Sun.COM 	adutils_rc	rc;
823*8040SBaban.Kenkre@Sun.COM 
824*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&adhostlock);
825*8040SBaban.Kenkre@Sun.COM 	for (p = host_head; p != NULL; p = p->next) {
826*8040SBaban.Kenkre@Sun.COM 		if (p->owner != ad)
827*8040SBaban.Kenkre@Sun.COM 			continue;
828*8040SBaban.Kenkre@Sun.COM 
829*8040SBaban.Kenkre@Sun.COM 		if (strcmp(host, p->host) == 0 && p->port == port) {
830*8040SBaban.Kenkre@Sun.COM 			/* already added */
831*8040SBaban.Kenkre@Sun.COM 			rc = ADUTILS_SUCCESS;
832*8040SBaban.Kenkre@Sun.COM 			goto err;
833*8040SBaban.Kenkre@Sun.COM 		}
834*8040SBaban.Kenkre@Sun.COM 	}
835*8040SBaban.Kenkre@Sun.COM 
836*8040SBaban.Kenkre@Sun.COM 	rc = ADUTILS_ERR_MEMORY;
837*8040SBaban.Kenkre@Sun.COM 
838*8040SBaban.Kenkre@Sun.COM 	/* add new entry */
839*8040SBaban.Kenkre@Sun.COM 	new = (adutils_host_t *)calloc(1, sizeof (*new));
840*8040SBaban.Kenkre@Sun.COM 	if (new == NULL)
841*8040SBaban.Kenkre@Sun.COM 		goto err;
842*8040SBaban.Kenkre@Sun.COM 	new->owner = ad;
843*8040SBaban.Kenkre@Sun.COM 	new->port = port;
844*8040SBaban.Kenkre@Sun.COM 	new->dead = 0;
845*8040SBaban.Kenkre@Sun.COM 	new->max_requests = 80;
846*8040SBaban.Kenkre@Sun.COM 	new->num_requests = 0;
847*8040SBaban.Kenkre@Sun.COM 	if ((new->host = strdup(host)) == NULL)
848*8040SBaban.Kenkre@Sun.COM 		goto err;
849*8040SBaban.Kenkre@Sun.COM 	new->saslflags = LDAP_SASL_INTERACTIVE;
850*8040SBaban.Kenkre@Sun.COM 	new->saslmech = "GSSAPI";
851*8040SBaban.Kenkre@Sun.COM 
852*8040SBaban.Kenkre@Sun.COM 	if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) {
853*8040SBaban.Kenkre@Sun.COM 		free(new->host);
854*8040SBaban.Kenkre@Sun.COM 		new->host = NULL;
855*8040SBaban.Kenkre@Sun.COM 		errno = ret;
856*8040SBaban.Kenkre@Sun.COM 		rc = ADUTILS_ERR_INTERNAL;
857*8040SBaban.Kenkre@Sun.COM 		goto err;
858*8040SBaban.Kenkre@Sun.COM 	}
859*8040SBaban.Kenkre@Sun.COM 
860*8040SBaban.Kenkre@Sun.COM 	/* link in */
861*8040SBaban.Kenkre@Sun.COM 	rc = ADUTILS_SUCCESS;
862*8040SBaban.Kenkre@Sun.COM 	new->next = host_head;
863*8040SBaban.Kenkre@Sun.COM 	host_head = new;
864*8040SBaban.Kenkre@Sun.COM 
865*8040SBaban.Kenkre@Sun.COM err:
866*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&adhostlock);
867*8040SBaban.Kenkre@Sun.COM 
868*8040SBaban.Kenkre@Sun.COM 	if (rc != 0 && new != NULL) {
869*8040SBaban.Kenkre@Sun.COM 		if (new->host != NULL) {
870*8040SBaban.Kenkre@Sun.COM 			(void) pthread_mutex_destroy(&new->lock);
871*8040SBaban.Kenkre@Sun.COM 			free(new->host);
872*8040SBaban.Kenkre@Sun.COM 		}
873*8040SBaban.Kenkre@Sun.COM 		free(new);
874*8040SBaban.Kenkre@Sun.COM 	}
875*8040SBaban.Kenkre@Sun.COM 
876*8040SBaban.Kenkre@Sun.COM 	return (rc);
877*8040SBaban.Kenkre@Sun.COM }
878*8040SBaban.Kenkre@Sun.COM 
879*8040SBaban.Kenkre@Sun.COM /*
880*8040SBaban.Kenkre@Sun.COM  * Free a DS configuration.
881*8040SBaban.Kenkre@Sun.COM  * Caller must lock the adhostlock mutex
882*8040SBaban.Kenkre@Sun.COM  */
883*8040SBaban.Kenkre@Sun.COM static
884*8040SBaban.Kenkre@Sun.COM void
885*8040SBaban.Kenkre@Sun.COM delete_ds(adutils_ad_t *ad, const char *host, int port)
886*8040SBaban.Kenkre@Sun.COM {
887*8040SBaban.Kenkre@Sun.COM 	adutils_host_t	**p, *q;
888*8040SBaban.Kenkre@Sun.COM 
889*8040SBaban.Kenkre@Sun.COM 	for (p = &host_head; *p != NULL; p = &((*p)->next)) {
890*8040SBaban.Kenkre@Sun.COM 		if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 ||
891*8040SBaban.Kenkre@Sun.COM 		    (*p)->port != port)
892*8040SBaban.Kenkre@Sun.COM 			continue;
893*8040SBaban.Kenkre@Sun.COM 		/* found */
894*8040SBaban.Kenkre@Sun.COM 
895*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_lock(&((*p)->lock));
896*8040SBaban.Kenkre@Sun.COM 		if ((*p)->ref > 0) {
897*8040SBaban.Kenkre@Sun.COM 			/*
898*8040SBaban.Kenkre@Sun.COM 			 * Still in use. Set its owner to NULL so
899*8040SBaban.Kenkre@Sun.COM 			 * that it can be freed when its ref count
900*8040SBaban.Kenkre@Sun.COM 			 * becomes 0.
901*8040SBaban.Kenkre@Sun.COM 			 */
902*8040SBaban.Kenkre@Sun.COM 			(*p)->owner = NULL;
903*8040SBaban.Kenkre@Sun.COM 			(void) pthread_mutex_unlock(&((*p)->lock));
904*8040SBaban.Kenkre@Sun.COM 			break;
905*8040SBaban.Kenkre@Sun.COM 		}
906*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&((*p)->lock));
907*8040SBaban.Kenkre@Sun.COM 
908*8040SBaban.Kenkre@Sun.COM 		q = *p;
909*8040SBaban.Kenkre@Sun.COM 		*p = (*p)->next;
910*8040SBaban.Kenkre@Sun.COM 
911*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_destroy(&q->lock);
912*8040SBaban.Kenkre@Sun.COM 
913*8040SBaban.Kenkre@Sun.COM 		if (q->ld)
914*8040SBaban.Kenkre@Sun.COM 			(void) ldap_unbind(q->ld);
915*8040SBaban.Kenkre@Sun.COM 		if (q->host)
916*8040SBaban.Kenkre@Sun.COM 			free(q->host);
917*8040SBaban.Kenkre@Sun.COM 		free(q);
918*8040SBaban.Kenkre@Sun.COM 		break;
919*8040SBaban.Kenkre@Sun.COM 	}
920*8040SBaban.Kenkre@Sun.COM 
921*8040SBaban.Kenkre@Sun.COM }
922*8040SBaban.Kenkre@Sun.COM 
923*8040SBaban.Kenkre@Sun.COM adutils_rc
924*8040SBaban.Kenkre@Sun.COM adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries,
925*8040SBaban.Kenkre@Sun.COM 	adutils_ldap_res_search_cb ldap_res_search_cb,
926*8040SBaban.Kenkre@Sun.COM 	void *ldap_res_search_argp,
927*8040SBaban.Kenkre@Sun.COM 	adutils_query_state_t **state)
928*8040SBaban.Kenkre@Sun.COM {
929*8040SBaban.Kenkre@Sun.COM 	adutils_query_state_t	*new_state;
930*8040SBaban.Kenkre@Sun.COM 	adutils_host_t		*adh = NULL;
931*8040SBaban.Kenkre@Sun.COM 
932*8040SBaban.Kenkre@Sun.COM 	if (ad == NULL)
933*8040SBaban.Kenkre@Sun.COM 		return (ADUTILS_ERR_INTERNAL);
934*8040SBaban.Kenkre@Sun.COM 
935*8040SBaban.Kenkre@Sun.COM 	*state = NULL;
936*8040SBaban.Kenkre@Sun.COM 	adh = get_conn(ad);
937*8040SBaban.Kenkre@Sun.COM 	if (adh == NULL)
938*8040SBaban.Kenkre@Sun.COM 		return (ADUTILS_ERR_RETRIABLE_NET_ERR);
939*8040SBaban.Kenkre@Sun.COM 
940*8040SBaban.Kenkre@Sun.COM 	new_state = calloc(1, sizeof (adutils_query_state_t) +
941*8040SBaban.Kenkre@Sun.COM 	    (nqueries - 1) * sizeof (adutils_q_t));
942*8040SBaban.Kenkre@Sun.COM 	if (new_state == NULL)
943*8040SBaban.Kenkre@Sun.COM 		return (ADUTILS_ERR_MEMORY);
944*8040SBaban.Kenkre@Sun.COM 
945*8040SBaban.Kenkre@Sun.COM 	/*
946*8040SBaban.Kenkre@Sun.COM 	 * Save default domain from the ad object so that we don't
947*8040SBaban.Kenkre@Sun.COM 	 * have to access the 'ad' object later.
948*8040SBaban.Kenkre@Sun.COM 	 */
949*8040SBaban.Kenkre@Sun.COM 	new_state->default_domain = strdup(adh->owner->dflt_w2k_dom);
950*8040SBaban.Kenkre@Sun.COM 	if (new_state->default_domain == NULL) {
951*8040SBaban.Kenkre@Sun.COM 		free(new_state);
952*8040SBaban.Kenkre@Sun.COM 		return (ADUTILS_ERR_MEMORY);
953*8040SBaban.Kenkre@Sun.COM 	}
954*8040SBaban.Kenkre@Sun.COM 
955*8040SBaban.Kenkre@Sun.COM 	if (ad->partition == ADUTILS_AD_DATA)
956*8040SBaban.Kenkre@Sun.COM 		new_state->basedn = adutils_dns2dn(new_state->default_domain);
957*8040SBaban.Kenkre@Sun.COM 	else
958*8040SBaban.Kenkre@Sun.COM 		new_state->basedn = strdup("");
959*8040SBaban.Kenkre@Sun.COM 	if (new_state->basedn == NULL) {
960*8040SBaban.Kenkre@Sun.COM 		free(new_state->default_domain);
961*8040SBaban.Kenkre@Sun.COM 		free(new_state);
962*8040SBaban.Kenkre@Sun.COM 		return (ADUTILS_ERR_MEMORY);
963*8040SBaban.Kenkre@Sun.COM 	}
964*8040SBaban.Kenkre@Sun.COM 
965*8040SBaban.Kenkre@Sun.COM 	new_state->ref_cnt = 1;
966*8040SBaban.Kenkre@Sun.COM 	new_state->qadh = adh;
967*8040SBaban.Kenkre@Sun.COM 	new_state->qcount = nqueries;
968*8040SBaban.Kenkre@Sun.COM 	new_state->qadh_gen = adh->generation;
969*8040SBaban.Kenkre@Sun.COM 	new_state->qlastsent = 0;
970*8040SBaban.Kenkre@Sun.COM 	new_state->ldap_res_search_cb = ldap_res_search_cb;
971*8040SBaban.Kenkre@Sun.COM 	new_state->ldap_res_search_argp = ldap_res_search_argp;
972*8040SBaban.Kenkre@Sun.COM 	(void) pthread_cond_init(&new_state->cv, NULL);
973*8040SBaban.Kenkre@Sun.COM 
974*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&qstatelock);
975*8040SBaban.Kenkre@Sun.COM 	new_state->next = qstatehead;
976*8040SBaban.Kenkre@Sun.COM 	qstatehead = new_state;
977*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&qstatelock);
978*8040SBaban.Kenkre@Sun.COM 	*state = new_state;
979*8040SBaban.Kenkre@Sun.COM 
980*8040SBaban.Kenkre@Sun.COM 	return (ADUTILS_SUCCESS);
981*8040SBaban.Kenkre@Sun.COM }
982*8040SBaban.Kenkre@Sun.COM 
983*8040SBaban.Kenkre@Sun.COM /*
984*8040SBaban.Kenkre@Sun.COM  * Find the adutils_query_state_t to which a given LDAP result msgid on a
985*8040SBaban.Kenkre@Sun.COM  * given connection belongs. This routine increaments the reference count
986*8040SBaban.Kenkre@Sun.COM  * so that the object can not be freed. adutils_lookup_batch_unlock()
987*8040SBaban.Kenkre@Sun.COM  * must be called to decreament the reference count.
988*8040SBaban.Kenkre@Sun.COM  */
989*8040SBaban.Kenkre@Sun.COM static
990*8040SBaban.Kenkre@Sun.COM int
991*8040SBaban.Kenkre@Sun.COM msgid2query(adutils_host_t *adh, int msgid,
992*8040SBaban.Kenkre@Sun.COM 	adutils_query_state_t **state, int *qid)
993*8040SBaban.Kenkre@Sun.COM {
994*8040SBaban.Kenkre@Sun.COM 	adutils_query_state_t	*p;
995*8040SBaban.Kenkre@Sun.COM 	int			i;
996*8040SBaban.Kenkre@Sun.COM 	int			ret;
997*8040SBaban.Kenkre@Sun.COM 
998*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&qstatelock);
999*8040SBaban.Kenkre@Sun.COM 	for (p = qstatehead; p != NULL; p = p->next) {
1000*8040SBaban.Kenkre@Sun.COM 		if (p->qadh != adh || adh->generation != p->qadh_gen)
1001*8040SBaban.Kenkre@Sun.COM 			continue;
1002*8040SBaban.Kenkre@Sun.COM 		for (i = 0; i < p->qcount; i++) {
1003*8040SBaban.Kenkre@Sun.COM 			if ((p->queries[i]).msgid == msgid) {
1004*8040SBaban.Kenkre@Sun.COM 				if (!p->qdead) {
1005*8040SBaban.Kenkre@Sun.COM 					p->ref_cnt++;
1006*8040SBaban.Kenkre@Sun.COM 					*state = p;
1007*8040SBaban.Kenkre@Sun.COM 					*qid = i;
1008*8040SBaban.Kenkre@Sun.COM 					ret = 1;
1009*8040SBaban.Kenkre@Sun.COM 				} else
1010*8040SBaban.Kenkre@Sun.COM 					ret = 0;
1011*8040SBaban.Kenkre@Sun.COM 				(void) pthread_mutex_unlock(&qstatelock);
1012*8040SBaban.Kenkre@Sun.COM 				return (ret);
1013*8040SBaban.Kenkre@Sun.COM 			}
1014*8040SBaban.Kenkre@Sun.COM 		}
1015*8040SBaban.Kenkre@Sun.COM 	}
1016*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&qstatelock);
1017*8040SBaban.Kenkre@Sun.COM 	return (0);
1018*8040SBaban.Kenkre@Sun.COM }
1019*8040SBaban.Kenkre@Sun.COM 
1020*8040SBaban.Kenkre@Sun.COM static
1021*8040SBaban.Kenkre@Sun.COM int
1022*8040SBaban.Kenkre@Sun.COM check_for_binary_attrs(const char *attr)
1023*8040SBaban.Kenkre@Sun.COM {
1024*8040SBaban.Kenkre@Sun.COM 	int i;
1025*8040SBaban.Kenkre@Sun.COM 	for (i = 0; binattrs[i].name != NULL; i++) {
1026*8040SBaban.Kenkre@Sun.COM 		if (strcasecmp(binattrs[i].name, attr) == 0)
1027*8040SBaban.Kenkre@Sun.COM 			return (i);
1028*8040SBaban.Kenkre@Sun.COM 	}
1029*8040SBaban.Kenkre@Sun.COM 	return (-1);
1030*8040SBaban.Kenkre@Sun.COM }
1031*8040SBaban.Kenkre@Sun.COM 
1032*8040SBaban.Kenkre@Sun.COM static
1033*8040SBaban.Kenkre@Sun.COM void
1034*8040SBaban.Kenkre@Sun.COM free_entry(adutils_entry_t *entry)
1035*8040SBaban.Kenkre@Sun.COM {
1036*8040SBaban.Kenkre@Sun.COM 	int		i, j;
1037*8040SBaban.Kenkre@Sun.COM 	adutils_attr_t	*ap;
1038*8040SBaban.Kenkre@Sun.COM 
1039*8040SBaban.Kenkre@Sun.COM 	if (entry == NULL)
1040*8040SBaban.Kenkre@Sun.COM 		return;
1041*8040SBaban.Kenkre@Sun.COM 	if (entry->attr_nvpairs == NULL) {
1042*8040SBaban.Kenkre@Sun.COM 		free(entry);
1043*8040SBaban.Kenkre@Sun.COM 		return;
1044*8040SBaban.Kenkre@Sun.COM 	}
1045*8040SBaban.Kenkre@Sun.COM 	for (i = 0; i < entry->num_nvpairs; i++) {
1046*8040SBaban.Kenkre@Sun.COM 		ap = &entry->attr_nvpairs[i];
1047*8040SBaban.Kenkre@Sun.COM 		if (ap->attr_name == NULL) {
1048*8040SBaban.Kenkre@Sun.COM 			ldap_value_free(ap->attr_values);
1049*8040SBaban.Kenkre@Sun.COM 			continue;
1050*8040SBaban.Kenkre@Sun.COM 		}
1051*8040SBaban.Kenkre@Sun.COM 		if (check_for_binary_attrs(ap->attr_name) >= 0) {
1052*8040SBaban.Kenkre@Sun.COM 			free(ap->attr_name);
1053*8040SBaban.Kenkre@Sun.COM 			if (ap->attr_values == NULL)
1054*8040SBaban.Kenkre@Sun.COM 				continue;
1055*8040SBaban.Kenkre@Sun.COM 			for (j = 0; j < ap->num_values; j++)
1056*8040SBaban.Kenkre@Sun.COM 				free(ap->attr_values[j]);
1057*8040SBaban.Kenkre@Sun.COM 			free(ap->attr_values);
1058*8040SBaban.Kenkre@Sun.COM 		} else if (strcasecmp(ap->attr_name, "dn") == 0) {
1059*8040SBaban.Kenkre@Sun.COM 			free(ap->attr_name);
1060*8040SBaban.Kenkre@Sun.COM 			ldap_memfree(ap->attr_values[0]);
1061*8040SBaban.Kenkre@Sun.COM 			free(ap->attr_values);
1062*8040SBaban.Kenkre@Sun.COM 		} else {
1063*8040SBaban.Kenkre@Sun.COM 			free(ap->attr_name);
1064*8040SBaban.Kenkre@Sun.COM 			ldap_value_free(ap->attr_values);
1065*8040SBaban.Kenkre@Sun.COM 		}
1066*8040SBaban.Kenkre@Sun.COM 	}
1067*8040SBaban.Kenkre@Sun.COM 	free(entry->attr_nvpairs);
1068*8040SBaban.Kenkre@Sun.COM 	free(entry);
1069*8040SBaban.Kenkre@Sun.COM }
1070*8040SBaban.Kenkre@Sun.COM 
1071*8040SBaban.Kenkre@Sun.COM void
1072*8040SBaban.Kenkre@Sun.COM adutils_freeresult(adutils_result_t **result)
1073*8040SBaban.Kenkre@Sun.COM {
1074*8040SBaban.Kenkre@Sun.COM 	adutils_entry_t	*e, *next;
1075*8040SBaban.Kenkre@Sun.COM 
1076*8040SBaban.Kenkre@Sun.COM 	if (result == NULL || *result == NULL)
1077*8040SBaban.Kenkre@Sun.COM 		return;
1078*8040SBaban.Kenkre@Sun.COM 	if ((*result)->entries == NULL) {
1079*8040SBaban.Kenkre@Sun.COM 		free(*result);
1080*8040SBaban.Kenkre@Sun.COM 		*result = NULL;
1081*8040SBaban.Kenkre@Sun.COM 		return;
1082*8040SBaban.Kenkre@Sun.COM 	}
1083*8040SBaban.Kenkre@Sun.COM 	for (e = (*result)->entries; e != NULL; e = next) {
1084*8040SBaban.Kenkre@Sun.COM 		next = e->next;
1085*8040SBaban.Kenkre@Sun.COM 		free_entry(e);
1086*8040SBaban.Kenkre@Sun.COM 	}
1087*8040SBaban.Kenkre@Sun.COM 	free(*result);
1088*8040SBaban.Kenkre@Sun.COM 	*result = NULL;
1089*8040SBaban.Kenkre@Sun.COM }
1090*8040SBaban.Kenkre@Sun.COM 
1091*8040SBaban.Kenkre@Sun.COM const adutils_entry_t *
1092*8040SBaban.Kenkre@Sun.COM adutils_getfirstentry(adutils_result_t *result)
1093*8040SBaban.Kenkre@Sun.COM {
1094*8040SBaban.Kenkre@Sun.COM 	if (result != NULL)
1095*8040SBaban.Kenkre@Sun.COM 		return (result->entries);
1096*8040SBaban.Kenkre@Sun.COM 	return (NULL);
1097*8040SBaban.Kenkre@Sun.COM }
1098*8040SBaban.Kenkre@Sun.COM 
1099*8040SBaban.Kenkre@Sun.COM 
1100*8040SBaban.Kenkre@Sun.COM char **
1101*8040SBaban.Kenkre@Sun.COM adutils_getattr(const adutils_entry_t *entry, const char *attrname)
1102*8040SBaban.Kenkre@Sun.COM {
1103*8040SBaban.Kenkre@Sun.COM 	int		i;
1104*8040SBaban.Kenkre@Sun.COM 	adutils_attr_t	*ap;
1105*8040SBaban.Kenkre@Sun.COM 
1106*8040SBaban.Kenkre@Sun.COM 	if (entry == NULL || entry->attr_nvpairs == NULL)
1107*8040SBaban.Kenkre@Sun.COM 		return (NULL);
1108*8040SBaban.Kenkre@Sun.COM 	for (i = 0; i < entry->num_nvpairs; i++) {
1109*8040SBaban.Kenkre@Sun.COM 		ap = &entry->attr_nvpairs[i];
1110*8040SBaban.Kenkre@Sun.COM 		if (ap->attr_name != NULL &&
1111*8040SBaban.Kenkre@Sun.COM 		    strcasecmp(ap->attr_name, attrname) == 0)
1112*8040SBaban.Kenkre@Sun.COM 			return (ap->attr_values);
1113*8040SBaban.Kenkre@Sun.COM 	}
1114*8040SBaban.Kenkre@Sun.COM 	return (NULL);
1115*8040SBaban.Kenkre@Sun.COM }
1116*8040SBaban.Kenkre@Sun.COM 
1117*8040SBaban.Kenkre@Sun.COM 
1118*8040SBaban.Kenkre@Sun.COM /*
1119*8040SBaban.Kenkre@Sun.COM  * Queue LDAP result for the given query.
1120*8040SBaban.Kenkre@Sun.COM  *
1121*8040SBaban.Kenkre@Sun.COM  * Return values:
1122*8040SBaban.Kenkre@Sun.COM  *  0 success
1123*8040SBaban.Kenkre@Sun.COM  * -1 ignore result
1124*8040SBaban.Kenkre@Sun.COM  * -2 error
1125*8040SBaban.Kenkre@Sun.COM  */
1126*8040SBaban.Kenkre@Sun.COM static
1127*8040SBaban.Kenkre@Sun.COM int
1128*8040SBaban.Kenkre@Sun.COM make_entry(adutils_q_t *q, adutils_host_t *adh, LDAPMessage *search_res,
1129*8040SBaban.Kenkre@Sun.COM 	adutils_entry_t **entry)
1130*8040SBaban.Kenkre@Sun.COM {
1131*8040SBaban.Kenkre@Sun.COM 	BerElement	*ber = NULL;
1132*8040SBaban.Kenkre@Sun.COM 	BerValue	**bvalues = NULL;
1133*8040SBaban.Kenkre@Sun.COM 	char		**strvalues;
1134*8040SBaban.Kenkre@Sun.COM 	char		*attr = NULL, *dn = NULL, *domain = NULL;
1135*8040SBaban.Kenkre@Sun.COM 	adutils_entry_t	*ep;
1136*8040SBaban.Kenkre@Sun.COM 	adutils_attr_t	*ap;
1137*8040SBaban.Kenkre@Sun.COM 	int		i, j, b, err = 0, ret = -2;
1138*8040SBaban.Kenkre@Sun.COM 
1139*8040SBaban.Kenkre@Sun.COM 	*entry = NULL;
1140*8040SBaban.Kenkre@Sun.COM 
1141*8040SBaban.Kenkre@Sun.COM 	/* Check that this is the domain that we were looking for */
1142*8040SBaban.Kenkre@Sun.COM 	if ((dn = ldap_get_dn(adh->ld, search_res)) == NULL)
1143*8040SBaban.Kenkre@Sun.COM 		return (-2);
1144*8040SBaban.Kenkre@Sun.COM 	if ((domain = adutils_dn2dns(dn)) == NULL) {
1145*8040SBaban.Kenkre@Sun.COM 		ldap_memfree(dn);
1146*8040SBaban.Kenkre@Sun.COM 		return (-2);
1147*8040SBaban.Kenkre@Sun.COM 	}
1148*8040SBaban.Kenkre@Sun.COM 	if (q->edomain != NULL) {
1149*8040SBaban.Kenkre@Sun.COM 		if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER,
1150*8040SBaban.Kenkre@Sun.COM 		    U8_UNICODE_LATEST, &err) != 0 || err != 0) {
1151*8040SBaban.Kenkre@Sun.COM 			ldap_memfree(dn);
1152*8040SBaban.Kenkre@Sun.COM 			free(domain);
1153*8040SBaban.Kenkre@Sun.COM 			return (-1);
1154*8040SBaban.Kenkre@Sun.COM 		}
1155*8040SBaban.Kenkre@Sun.COM 	}
1156*8040SBaban.Kenkre@Sun.COM 	free(domain);
1157*8040SBaban.Kenkre@Sun.COM 
1158*8040SBaban.Kenkre@Sun.COM 	/* Allocate memory for the entry */
1159*8040SBaban.Kenkre@Sun.COM 	if ((ep = calloc(1, sizeof (*ep))) == NULL)
1160*8040SBaban.Kenkre@Sun.COM 		goto out;
1161*8040SBaban.Kenkre@Sun.COM 
1162*8040SBaban.Kenkre@Sun.COM 	/* For 'dn' */
1163*8040SBaban.Kenkre@Sun.COM 	ep->num_nvpairs = 1;
1164*8040SBaban.Kenkre@Sun.COM 
1165*8040SBaban.Kenkre@Sun.COM 	/* Count the number of name-value pairs for this entry */
1166*8040SBaban.Kenkre@Sun.COM 	for (attr = ldap_first_attribute(adh->ld, search_res, &ber);
1167*8040SBaban.Kenkre@Sun.COM 	    attr != NULL;
1168*8040SBaban.Kenkre@Sun.COM 	    attr = ldap_next_attribute(adh->ld, search_res, ber)) {
1169*8040SBaban.Kenkre@Sun.COM 		ep->num_nvpairs++;
1170*8040SBaban.Kenkre@Sun.COM 		ldap_memfree(attr);
1171*8040SBaban.Kenkre@Sun.COM 	}
1172*8040SBaban.Kenkre@Sun.COM 	ber_free(ber, 0);
1173*8040SBaban.Kenkre@Sun.COM 	ber = NULL;
1174*8040SBaban.Kenkre@Sun.COM 
1175*8040SBaban.Kenkre@Sun.COM 	/* Allocate array for the attribute name-value pairs */
1176*8040SBaban.Kenkre@Sun.COM 	ep->attr_nvpairs = calloc(ep->num_nvpairs, sizeof (*ep->attr_nvpairs));
1177*8040SBaban.Kenkre@Sun.COM 	if (ep->attr_nvpairs == NULL) {
1178*8040SBaban.Kenkre@Sun.COM 		ep->num_nvpairs = 0;
1179*8040SBaban.Kenkre@Sun.COM 		goto out;
1180*8040SBaban.Kenkre@Sun.COM 	}
1181*8040SBaban.Kenkre@Sun.COM 
1182*8040SBaban.Kenkre@Sun.COM 	/* For dn */
1183*8040SBaban.Kenkre@Sun.COM 	ap = &ep->attr_nvpairs[0];
1184*8040SBaban.Kenkre@Sun.COM 	if ((ap->attr_name = strdup("dn")) == NULL)
1185*8040SBaban.Kenkre@Sun.COM 		goto out;
1186*8040SBaban.Kenkre@Sun.COM 	ap->num_values = 1;
1187*8040SBaban.Kenkre@Sun.COM 	ap->attr_values = calloc(ap->num_values, sizeof (*ap->attr_values));
1188*8040SBaban.Kenkre@Sun.COM 	if (ap->attr_values == NULL) {
1189*8040SBaban.Kenkre@Sun.COM 		ap->num_values = 0;
1190*8040SBaban.Kenkre@Sun.COM 		goto out;
1191*8040SBaban.Kenkre@Sun.COM 	}
1192*8040SBaban.Kenkre@Sun.COM 	ap->attr_values[0] = dn;
1193*8040SBaban.Kenkre@Sun.COM 	dn = NULL;
1194*8040SBaban.Kenkre@Sun.COM 
1195*8040SBaban.Kenkre@Sun.COM 	for (attr = ldap_first_attribute(adh->ld, search_res, &ber), i = 1;
1196*8040SBaban.Kenkre@Sun.COM 	    attr != NULL;
1197*8040SBaban.Kenkre@Sun.COM 	    ldap_memfree(attr), i++,
1198*8040SBaban.Kenkre@Sun.COM 	    attr = ldap_next_attribute(adh->ld, search_res, ber)) {
1199*8040SBaban.Kenkre@Sun.COM 		ap = &ep->attr_nvpairs[i];
1200*8040SBaban.Kenkre@Sun.COM 		if ((ap->attr_name = strdup(attr)) == NULL)
1201*8040SBaban.Kenkre@Sun.COM 			goto out;
1202*8040SBaban.Kenkre@Sun.COM 
1203*8040SBaban.Kenkre@Sun.COM 		if ((b = check_for_binary_attrs(attr)) >= 0) {
1204*8040SBaban.Kenkre@Sun.COM 			bvalues =
1205*8040SBaban.Kenkre@Sun.COM 			    ldap_get_values_len(adh->ld, search_res, attr);
1206*8040SBaban.Kenkre@Sun.COM 			if (bvalues == NULL)
1207*8040SBaban.Kenkre@Sun.COM 				continue;
1208*8040SBaban.Kenkre@Sun.COM 			ap->num_values = ldap_count_values_len(bvalues);
1209*8040SBaban.Kenkre@Sun.COM 			if (ap->num_values == 0) {
1210*8040SBaban.Kenkre@Sun.COM 				ldap_value_free_len(bvalues);
1211*8040SBaban.Kenkre@Sun.COM 				bvalues = NULL;
1212*8040SBaban.Kenkre@Sun.COM 				continue;
1213*8040SBaban.Kenkre@Sun.COM 			}
1214*8040SBaban.Kenkre@Sun.COM 			ap->attr_values = calloc(ap->num_values,
1215*8040SBaban.Kenkre@Sun.COM 			    sizeof (*ap->attr_values));
1216*8040SBaban.Kenkre@Sun.COM 			if (ap->attr_values == NULL) {
1217*8040SBaban.Kenkre@Sun.COM 				ap->num_values = 0;
1218*8040SBaban.Kenkre@Sun.COM 				goto out;
1219*8040SBaban.Kenkre@Sun.COM 			}
1220*8040SBaban.Kenkre@Sun.COM 			for (j = 0; j < ap->num_values; j++) {
1221*8040SBaban.Kenkre@Sun.COM 				ap->attr_values[j] =
1222*8040SBaban.Kenkre@Sun.COM 				    binattrs[b].ber2str(bvalues[j]);
1223*8040SBaban.Kenkre@Sun.COM 				if (ap->attr_values[j] == NULL)
1224*8040SBaban.Kenkre@Sun.COM 					goto out;
1225*8040SBaban.Kenkre@Sun.COM 			}
1226*8040SBaban.Kenkre@Sun.COM 			ldap_value_free_len(bvalues);
1227*8040SBaban.Kenkre@Sun.COM 			bvalues = NULL;
1228*8040SBaban.Kenkre@Sun.COM 			continue;
1229*8040SBaban.Kenkre@Sun.COM 		}
1230*8040SBaban.Kenkre@Sun.COM 
1231*8040SBaban.Kenkre@Sun.COM 		strvalues = ldap_get_values(adh->ld, search_res, attr);
1232*8040SBaban.Kenkre@Sun.COM 		if (strvalues == NULL)
1233*8040SBaban.Kenkre@Sun.COM 			continue;
1234*8040SBaban.Kenkre@Sun.COM 		ap->num_values = ldap_count_values(strvalues);
1235*8040SBaban.Kenkre@Sun.COM 		if (ap->num_values == 0) {
1236*8040SBaban.Kenkre@Sun.COM 			ldap_value_free(strvalues);
1237*8040SBaban.Kenkre@Sun.COM 			continue;
1238*8040SBaban.Kenkre@Sun.COM 		}
1239*8040SBaban.Kenkre@Sun.COM 		ap->attr_values = strvalues;
1240*8040SBaban.Kenkre@Sun.COM 	}
1241*8040SBaban.Kenkre@Sun.COM 
1242*8040SBaban.Kenkre@Sun.COM 	ret = 0;
1243*8040SBaban.Kenkre@Sun.COM out:
1244*8040SBaban.Kenkre@Sun.COM 	ldap_memfree(attr);
1245*8040SBaban.Kenkre@Sun.COM 	ldap_memfree(dn);
1246*8040SBaban.Kenkre@Sun.COM 	ber_free(ber, 0);
1247*8040SBaban.Kenkre@Sun.COM 	ldap_value_free_len(bvalues);
1248*8040SBaban.Kenkre@Sun.COM 	if (ret < 0)
1249*8040SBaban.Kenkre@Sun.COM 		free_entry(ep);
1250*8040SBaban.Kenkre@Sun.COM 	else
1251*8040SBaban.Kenkre@Sun.COM 		*entry = ep;
1252*8040SBaban.Kenkre@Sun.COM 	return (ret);
1253*8040SBaban.Kenkre@Sun.COM }
1254*8040SBaban.Kenkre@Sun.COM 
1255*8040SBaban.Kenkre@Sun.COM /*
1256*8040SBaban.Kenkre@Sun.COM  * Put the search result onto the given adutils_q_t.
1257*8040SBaban.Kenkre@Sun.COM  * Returns:	  0 success
1258*8040SBaban.Kenkre@Sun.COM  *		< 0 error
1259*8040SBaban.Kenkre@Sun.COM  */
1260*8040SBaban.Kenkre@Sun.COM static
1261*8040SBaban.Kenkre@Sun.COM int
1262*8040SBaban.Kenkre@Sun.COM add_entry(adutils_host_t *adh, adutils_q_t *q, LDAPMessage *search_res)
1263*8040SBaban.Kenkre@Sun.COM {
1264*8040SBaban.Kenkre@Sun.COM 	int			ret = -1;
1265*8040SBaban.Kenkre@Sun.COM 	adutils_entry_t		*entry = NULL;
1266*8040SBaban.Kenkre@Sun.COM 	adutils_result_t	*res;
1267*8040SBaban.Kenkre@Sun.COM 
1268*8040SBaban.Kenkre@Sun.COM 	ret = make_entry(q, adh, search_res, &entry);
1269*8040SBaban.Kenkre@Sun.COM 	if (ret < -1) {
1270*8040SBaban.Kenkre@Sun.COM 		*q->rc = ADUTILS_ERR_MEMORY;
1271*8040SBaban.Kenkre@Sun.COM 		goto out;
1272*8040SBaban.Kenkre@Sun.COM 	} else if (ret == -1) {
1273*8040SBaban.Kenkre@Sun.COM 		/* ignore result */
1274*8040SBaban.Kenkre@Sun.COM 		goto out;
1275*8040SBaban.Kenkre@Sun.COM 	}
1276*8040SBaban.Kenkre@Sun.COM 	if (*q->result == NULL) {
1277*8040SBaban.Kenkre@Sun.COM 		res = calloc(1, sizeof (*res));
1278*8040SBaban.Kenkre@Sun.COM 		if (res == NULL) {
1279*8040SBaban.Kenkre@Sun.COM 			*q->rc = ADUTILS_ERR_MEMORY;
1280*8040SBaban.Kenkre@Sun.COM 			goto out;
1281*8040SBaban.Kenkre@Sun.COM 		}
1282*8040SBaban.Kenkre@Sun.COM 		res->num_entries = 1;
1283*8040SBaban.Kenkre@Sun.COM 		res->entries = entry;
1284*8040SBaban.Kenkre@Sun.COM 		*q->result = res;
1285*8040SBaban.Kenkre@Sun.COM 	} else {
1286*8040SBaban.Kenkre@Sun.COM 		res = *q->result;
1287*8040SBaban.Kenkre@Sun.COM 		entry->next = res->entries;
1288*8040SBaban.Kenkre@Sun.COM 		res->entries = entry;
1289*8040SBaban.Kenkre@Sun.COM 		res->num_entries++;
1290*8040SBaban.Kenkre@Sun.COM 	}
1291*8040SBaban.Kenkre@Sun.COM 	*q->rc = ADUTILS_SUCCESS;
1292*8040SBaban.Kenkre@Sun.COM 	entry = NULL;
1293*8040SBaban.Kenkre@Sun.COM 	ret = 0;
1294*8040SBaban.Kenkre@Sun.COM 
1295*8040SBaban.Kenkre@Sun.COM out:
1296*8040SBaban.Kenkre@Sun.COM 	free_entry(entry);
1297*8040SBaban.Kenkre@Sun.COM 	return (ret);
1298*8040SBaban.Kenkre@Sun.COM }
1299*8040SBaban.Kenkre@Sun.COM 
1300*8040SBaban.Kenkre@Sun.COM /*
1301*8040SBaban.Kenkre@Sun.COM  * Try to get a result; if there is one, find the corresponding
1302*8040SBaban.Kenkre@Sun.COM  * adutils_q_t and process the result.
1303*8040SBaban.Kenkre@Sun.COM  *
1304*8040SBaban.Kenkre@Sun.COM  * Returns:	0 success
1305*8040SBaban.Kenkre@Sun.COM  *		-1 error
1306*8040SBaban.Kenkre@Sun.COM  */
1307*8040SBaban.Kenkre@Sun.COM static
1308*8040SBaban.Kenkre@Sun.COM int
1309*8040SBaban.Kenkre@Sun.COM get_adobject_batch(adutils_host_t *adh, struct timeval *timeout)
1310*8040SBaban.Kenkre@Sun.COM {
1311*8040SBaban.Kenkre@Sun.COM 	adutils_query_state_t	*query_state;
1312*8040SBaban.Kenkre@Sun.COM 	LDAPMessage		*res = NULL;
1313*8040SBaban.Kenkre@Sun.COM 	int			rc, ret, msgid, qid;
1314*8040SBaban.Kenkre@Sun.COM 	adutils_q_t		*que;
1315*8040SBaban.Kenkre@Sun.COM 	int			num;
1316*8040SBaban.Kenkre@Sun.COM 
1317*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&adh->lock);
1318*8040SBaban.Kenkre@Sun.COM 	if (adh->dead || adh->num_requests == 0) {
1319*8040SBaban.Kenkre@Sun.COM 		ret = (adh->dead) ? -1 : -2;
1320*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&adh->lock);
1321*8040SBaban.Kenkre@Sun.COM 		return (ret);
1322*8040SBaban.Kenkre@Sun.COM 	}
1323*8040SBaban.Kenkre@Sun.COM 
1324*8040SBaban.Kenkre@Sun.COM 	/* Get one result */
1325*8040SBaban.Kenkre@Sun.COM 	rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, timeout, &res);
1326*8040SBaban.Kenkre@Sun.COM 	if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) ||
1327*8040SBaban.Kenkre@Sun.COM 	    rc < 0)
1328*8040SBaban.Kenkre@Sun.COM 		adh->dead = 1;
1329*8040SBaban.Kenkre@Sun.COM 
1330*8040SBaban.Kenkre@Sun.COM 	if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0)
1331*8040SBaban.Kenkre@Sun.COM 		adh->num_requests--;
1332*8040SBaban.Kenkre@Sun.COM 	if (adh->dead) {
1333*8040SBaban.Kenkre@Sun.COM 		num = adh->num_requests;
1334*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&adh->lock);
1335*8040SBaban.Kenkre@Sun.COM 		idmapdlog(LOG_DEBUG,
1336*8040SBaban.Kenkre@Sun.COM 		    "AD ldap_result error - %d queued requests", num);
1337*8040SBaban.Kenkre@Sun.COM 		return (-1);
1338*8040SBaban.Kenkre@Sun.COM 	}
1339*8040SBaban.Kenkre@Sun.COM 
1340*8040SBaban.Kenkre@Sun.COM 	switch (rc) {
1341*8040SBaban.Kenkre@Sun.COM 	case LDAP_RES_SEARCH_RESULT:
1342*8040SBaban.Kenkre@Sun.COM 		msgid = ldap_msgid(res);
1343*8040SBaban.Kenkre@Sun.COM 		if (msgid2query(adh, msgid, &query_state, &qid)) {
1344*8040SBaban.Kenkre@Sun.COM 			if (query_state->ldap_res_search_cb != NULL) {
1345*8040SBaban.Kenkre@Sun.COM 				/*
1346*8040SBaban.Kenkre@Sun.COM 				 * We use the caller-provided callback
1347*8040SBaban.Kenkre@Sun.COM 				 * to process the result.
1348*8040SBaban.Kenkre@Sun.COM 				 */
1349*8040SBaban.Kenkre@Sun.COM 				query_state->ldap_res_search_cb(
1350*8040SBaban.Kenkre@Sun.COM 				    adh->ld, &res, rc, qid,
1351*8040SBaban.Kenkre@Sun.COM 				    query_state->ldap_res_search_argp);
1352*8040SBaban.Kenkre@Sun.COM 				(void) pthread_mutex_unlock(&adh->lock);
1353*8040SBaban.Kenkre@Sun.COM 			} else {
1354*8040SBaban.Kenkre@Sun.COM 				/*
1355*8040SBaban.Kenkre@Sun.COM 				 * No callback. We fallback to our
1356*8040SBaban.Kenkre@Sun.COM 				 * default behaviour. All the entries
1357*8040SBaban.Kenkre@Sun.COM 				 * gotten from this search have been
1358*8040SBaban.Kenkre@Sun.COM 				 * added to the result list during
1359*8040SBaban.Kenkre@Sun.COM 				 * LDAP_RES_SEARCH_ENTRY (see below).
1360*8040SBaban.Kenkre@Sun.COM 				 * Here we set the return status to
1361*8040SBaban.Kenkre@Sun.COM 				 * notfound if the result is still empty.
1362*8040SBaban.Kenkre@Sun.COM 				 */
1363*8040SBaban.Kenkre@Sun.COM 				(void) pthread_mutex_unlock(&adh->lock);
1364*8040SBaban.Kenkre@Sun.COM 				que = &(query_state->queries[qid]);
1365*8040SBaban.Kenkre@Sun.COM 				if (*que->result == NULL)
1366*8040SBaban.Kenkre@Sun.COM 					*que->rc = ADUTILS_ERR_NOTFOUND;
1367*8040SBaban.Kenkre@Sun.COM 			}
1368*8040SBaban.Kenkre@Sun.COM 			atomic_dec_32(&query_state->qinflight);
1369*8040SBaban.Kenkre@Sun.COM 			adutils_lookup_batch_unlock(&query_state);
1370*8040SBaban.Kenkre@Sun.COM 		} else {
1371*8040SBaban.Kenkre@Sun.COM 			num = adh->num_requests;
1372*8040SBaban.Kenkre@Sun.COM 			(void) pthread_mutex_unlock(&adh->lock);
1373*8040SBaban.Kenkre@Sun.COM 			idmapdlog(LOG_DEBUG,
1374*8040SBaban.Kenkre@Sun.COM 			    "AD cannot find message ID (%d) "
1375*8040SBaban.Kenkre@Sun.COM 			    "- %d queued requests",
1376*8040SBaban.Kenkre@Sun.COM 			    msgid, num);
1377*8040SBaban.Kenkre@Sun.COM 		}
1378*8040SBaban.Kenkre@Sun.COM 		(void) ldap_msgfree(res);
1379*8040SBaban.Kenkre@Sun.COM 		ret = 0;
1380*8040SBaban.Kenkre@Sun.COM 		break;
1381*8040SBaban.Kenkre@Sun.COM 
1382*8040SBaban.Kenkre@Sun.COM 	case LDAP_RES_SEARCH_ENTRY:
1383*8040SBaban.Kenkre@Sun.COM 		msgid = ldap_msgid(res);
1384*8040SBaban.Kenkre@Sun.COM 		if (msgid2query(adh, msgid, &query_state, &qid)) {
1385*8040SBaban.Kenkre@Sun.COM 			if (query_state->ldap_res_search_cb != NULL) {
1386*8040SBaban.Kenkre@Sun.COM 				/*
1387*8040SBaban.Kenkre@Sun.COM 				 * We use the caller-provided callback
1388*8040SBaban.Kenkre@Sun.COM 				 * to process the entry.
1389*8040SBaban.Kenkre@Sun.COM 				 */
1390*8040SBaban.Kenkre@Sun.COM 				query_state->ldap_res_search_cb(
1391*8040SBaban.Kenkre@Sun.COM 				    adh->ld, &res, rc, qid,
1392*8040SBaban.Kenkre@Sun.COM 				    query_state->ldap_res_search_argp);
1393*8040SBaban.Kenkre@Sun.COM 				(void) pthread_mutex_unlock(&adh->lock);
1394*8040SBaban.Kenkre@Sun.COM 			} else {
1395*8040SBaban.Kenkre@Sun.COM 				/*
1396*8040SBaban.Kenkre@Sun.COM 				 * No callback. We fallback to our
1397*8040SBaban.Kenkre@Sun.COM 				 * default behaviour. This entry
1398*8040SBaban.Kenkre@Sun.COM 				 * will be added to the result list.
1399*8040SBaban.Kenkre@Sun.COM 				 */
1400*8040SBaban.Kenkre@Sun.COM 				que = &(query_state->queries[qid]);
1401*8040SBaban.Kenkre@Sun.COM 				rc = add_entry(adh, que, res);
1402*8040SBaban.Kenkre@Sun.COM 				(void) pthread_mutex_unlock(&adh->lock);
1403*8040SBaban.Kenkre@Sun.COM 				if (rc < 0) {
1404*8040SBaban.Kenkre@Sun.COM 					idmapdlog(LOG_DEBUG,
1405*8040SBaban.Kenkre@Sun.COM 					    "Failed to queue entry by "
1406*8040SBaban.Kenkre@Sun.COM 					    "message ID (%d) "
1407*8040SBaban.Kenkre@Sun.COM 					    "- %d queued requests",
1408*8040SBaban.Kenkre@Sun.COM 					    msgid, num);
1409*8040SBaban.Kenkre@Sun.COM 				}
1410*8040SBaban.Kenkre@Sun.COM 			}
1411*8040SBaban.Kenkre@Sun.COM 			adutils_lookup_batch_unlock(&query_state);
1412*8040SBaban.Kenkre@Sun.COM 		} else {
1413*8040SBaban.Kenkre@Sun.COM 			num = adh->num_requests;
1414*8040SBaban.Kenkre@Sun.COM 			(void) pthread_mutex_unlock(&adh->lock);
1415*8040SBaban.Kenkre@Sun.COM 			idmapdlog(LOG_DEBUG,
1416*8040SBaban.Kenkre@Sun.COM 			    "AD cannot find message ID (%d) "
1417*8040SBaban.Kenkre@Sun.COM 			    "- %d queued requests",
1418*8040SBaban.Kenkre@Sun.COM 			    msgid, num);
1419*8040SBaban.Kenkre@Sun.COM 		}
1420*8040SBaban.Kenkre@Sun.COM 		(void) ldap_msgfree(res);
1421*8040SBaban.Kenkre@Sun.COM 		ret = 0;
1422*8040SBaban.Kenkre@Sun.COM 		break;
1423*8040SBaban.Kenkre@Sun.COM 
1424*8040SBaban.Kenkre@Sun.COM 	case LDAP_RES_SEARCH_REFERENCE:
1425*8040SBaban.Kenkre@Sun.COM 		/*
1426*8040SBaban.Kenkre@Sun.COM 		 * We have no need for these at the moment.  Eventually,
1427*8040SBaban.Kenkre@Sun.COM 		 * when we query things that we can't expect to find in
1428*8040SBaban.Kenkre@Sun.COM 		 * the Global Catalog then we'll need to learn to follow
1429*8040SBaban.Kenkre@Sun.COM 		 * references.
1430*8040SBaban.Kenkre@Sun.COM 		 */
1431*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&adh->lock);
1432*8040SBaban.Kenkre@Sun.COM 		(void) ldap_msgfree(res);
1433*8040SBaban.Kenkre@Sun.COM 		ret = 0;
1434*8040SBaban.Kenkre@Sun.COM 		break;
1435*8040SBaban.Kenkre@Sun.COM 
1436*8040SBaban.Kenkre@Sun.COM 	default:
1437*8040SBaban.Kenkre@Sun.COM 		/* timeout or error; treat the same */
1438*8040SBaban.Kenkre@Sun.COM 		(void) pthread_mutex_unlock(&adh->lock);
1439*8040SBaban.Kenkre@Sun.COM 		ret = -1;
1440*8040SBaban.Kenkre@Sun.COM 		break;
1441*8040SBaban.Kenkre@Sun.COM 	}
1442*8040SBaban.Kenkre@Sun.COM 
1443*8040SBaban.Kenkre@Sun.COM 	return (ret);
1444*8040SBaban.Kenkre@Sun.COM }
1445*8040SBaban.Kenkre@Sun.COM 
1446*8040SBaban.Kenkre@Sun.COM /*
1447*8040SBaban.Kenkre@Sun.COM  * This routine decreament the reference count of the
1448*8040SBaban.Kenkre@Sun.COM  * adutils_query_state_t
1449*8040SBaban.Kenkre@Sun.COM  */
1450*8040SBaban.Kenkre@Sun.COM static void
1451*8040SBaban.Kenkre@Sun.COM adutils_lookup_batch_unlock(adutils_query_state_t **state)
1452*8040SBaban.Kenkre@Sun.COM {
1453*8040SBaban.Kenkre@Sun.COM 	/*
1454*8040SBaban.Kenkre@Sun.COM 	 * Decrement reference count with qstatelock locked
1455*8040SBaban.Kenkre@Sun.COM 	 */
1456*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&qstatelock);
1457*8040SBaban.Kenkre@Sun.COM 	(*state)->ref_cnt--;
1458*8040SBaban.Kenkre@Sun.COM 	/*
1459*8040SBaban.Kenkre@Sun.COM 	 * If there are no references wakup the allocating thread
1460*8040SBaban.Kenkre@Sun.COM 	 */
1461*8040SBaban.Kenkre@Sun.COM 	if ((*state)->ref_cnt <= 1)
1462*8040SBaban.Kenkre@Sun.COM 		(void) pthread_cond_signal(&(*state)->cv);
1463*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&qstatelock);
1464*8040SBaban.Kenkre@Sun.COM 	*state = NULL;
1465*8040SBaban.Kenkre@Sun.COM }
1466*8040SBaban.Kenkre@Sun.COM 
1467*8040SBaban.Kenkre@Sun.COM /*
1468*8040SBaban.Kenkre@Sun.COM  * This routine frees the adutils_query_state_t structure
1469*8040SBaban.Kenkre@Sun.COM  * If the reference count is greater than 1 it waits
1470*8040SBaban.Kenkre@Sun.COM  * for the other threads to finish using it.
1471*8040SBaban.Kenkre@Sun.COM  */
1472*8040SBaban.Kenkre@Sun.COM void
1473*8040SBaban.Kenkre@Sun.COM adutils_lookup_batch_release(adutils_query_state_t **state)
1474*8040SBaban.Kenkre@Sun.COM {
1475*8040SBaban.Kenkre@Sun.COM 	adutils_query_state_t **p;
1476*8040SBaban.Kenkre@Sun.COM 	int			i;
1477*8040SBaban.Kenkre@Sun.COM 
1478*8040SBaban.Kenkre@Sun.COM 	if (state == NULL || *state == NULL)
1479*8040SBaban.Kenkre@Sun.COM 		return;
1480*8040SBaban.Kenkre@Sun.COM 
1481*8040SBaban.Kenkre@Sun.COM 	/*
1482*8040SBaban.Kenkre@Sun.COM 	 * Set state to dead to stop further operations.
1483*8040SBaban.Kenkre@Sun.COM 	 * Wait for reference count with qstatelock locked
1484*8040SBaban.Kenkre@Sun.COM 	 * to get to one.
1485*8040SBaban.Kenkre@Sun.COM 	 */
1486*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&qstatelock);
1487*8040SBaban.Kenkre@Sun.COM 	(*state)->qdead = 1;
1488*8040SBaban.Kenkre@Sun.COM 	while ((*state)->ref_cnt > 1) {
1489*8040SBaban.Kenkre@Sun.COM 		(void) pthread_cond_wait(&(*state)->cv, &qstatelock);
1490*8040SBaban.Kenkre@Sun.COM 	}
1491*8040SBaban.Kenkre@Sun.COM 
1492*8040SBaban.Kenkre@Sun.COM 	/* Remove this state struct from the list of state structs */
1493*8040SBaban.Kenkre@Sun.COM 	for (p = &qstatehead; *p != NULL; p = &(*p)->next) {
1494*8040SBaban.Kenkre@Sun.COM 		if (*p == (*state)) {
1495*8040SBaban.Kenkre@Sun.COM 			*p = (*state)->next;
1496*8040SBaban.Kenkre@Sun.COM 			break;
1497*8040SBaban.Kenkre@Sun.COM 		}
1498*8040SBaban.Kenkre@Sun.COM 	}
1499*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&qstatelock);
1500*8040SBaban.Kenkre@Sun.COM 	(void) pthread_cond_destroy(&(*state)->cv);
1501*8040SBaban.Kenkre@Sun.COM 	release_conn((*state)->qadh);
1502*8040SBaban.Kenkre@Sun.COM 
1503*8040SBaban.Kenkre@Sun.COM 	/* Clear results for queries that failed */
1504*8040SBaban.Kenkre@Sun.COM 	for (i = 0; i < (*state)->qcount; i++) {
1505*8040SBaban.Kenkre@Sun.COM 		if (*(*state)->queries[i].rc != ADUTILS_SUCCESS) {
1506*8040SBaban.Kenkre@Sun.COM 			adutils_freeresult((*state)->queries[i].result);
1507*8040SBaban.Kenkre@Sun.COM 		}
1508*8040SBaban.Kenkre@Sun.COM 	}
1509*8040SBaban.Kenkre@Sun.COM 	free((*state)->default_domain);
1510*8040SBaban.Kenkre@Sun.COM 	free((*state)->basedn);
1511*8040SBaban.Kenkre@Sun.COM 	free(*state);
1512*8040SBaban.Kenkre@Sun.COM 	*state = NULL;
1513*8040SBaban.Kenkre@Sun.COM }
1514*8040SBaban.Kenkre@Sun.COM 
1515*8040SBaban.Kenkre@Sun.COM 
1516*8040SBaban.Kenkre@Sun.COM /*
1517*8040SBaban.Kenkre@Sun.COM  * This routine waits for other threads using the
1518*8040SBaban.Kenkre@Sun.COM  * adutils_query_state_t structure to finish.
1519*8040SBaban.Kenkre@Sun.COM  * If the reference count is greater than 1 it waits
1520*8040SBaban.Kenkre@Sun.COM  * for the other threads to finish using it.
1521*8040SBaban.Kenkre@Sun.COM  */
1522*8040SBaban.Kenkre@Sun.COM static
1523*8040SBaban.Kenkre@Sun.COM void
1524*8040SBaban.Kenkre@Sun.COM adutils_lookup_batch_wait(adutils_query_state_t *state)
1525*8040SBaban.Kenkre@Sun.COM {
1526*8040SBaban.Kenkre@Sun.COM 	/*
1527*8040SBaban.Kenkre@Sun.COM 	 * Set state to dead to stop further operation.
1528*8040SBaban.Kenkre@Sun.COM 	 * stating.
1529*8040SBaban.Kenkre@Sun.COM 	 * Wait for reference count to get to one
1530*8040SBaban.Kenkre@Sun.COM 	 * with qstatelock locked.
1531*8040SBaban.Kenkre@Sun.COM 	 */
1532*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&qstatelock);
1533*8040SBaban.Kenkre@Sun.COM 	state->qdead = 1;
1534*8040SBaban.Kenkre@Sun.COM 	while (state->ref_cnt > 1) {
1535*8040SBaban.Kenkre@Sun.COM 		(void) pthread_cond_wait(&state->cv, &qstatelock);
1536*8040SBaban.Kenkre@Sun.COM 	}
1537*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&qstatelock);
1538*8040SBaban.Kenkre@Sun.COM }
1539*8040SBaban.Kenkre@Sun.COM 
1540*8040SBaban.Kenkre@Sun.COM /*
1541*8040SBaban.Kenkre@Sun.COM  * Process active queries in the AD lookup batch and then finalize the
1542*8040SBaban.Kenkre@Sun.COM  * result.
1543*8040SBaban.Kenkre@Sun.COM  */
1544*8040SBaban.Kenkre@Sun.COM adutils_rc
1545*8040SBaban.Kenkre@Sun.COM adutils_lookup_batch_end(adutils_query_state_t **state)
1546*8040SBaban.Kenkre@Sun.COM {
1547*8040SBaban.Kenkre@Sun.COM 	int		    rc = LDAP_SUCCESS;
1548*8040SBaban.Kenkre@Sun.COM 	adutils_rc	    ad_rc = ADUTILS_SUCCESS;
1549*8040SBaban.Kenkre@Sun.COM 	struct timeval	    tv;
1550*8040SBaban.Kenkre@Sun.COM 
1551*8040SBaban.Kenkre@Sun.COM 	tv.tv_sec = ADUTILS_SEARCH_TIMEOUT;
1552*8040SBaban.Kenkre@Sun.COM 	tv.tv_usec = 0;
1553*8040SBaban.Kenkre@Sun.COM 
1554*8040SBaban.Kenkre@Sun.COM 	/* Process results until done or until timeout, if given */
1555*8040SBaban.Kenkre@Sun.COM 	while ((*state)->qinflight > 0) {
1556*8040SBaban.Kenkre@Sun.COM 		if ((rc = get_adobject_batch((*state)->qadh,
1557*8040SBaban.Kenkre@Sun.COM 		    &tv)) != 0)
1558*8040SBaban.Kenkre@Sun.COM 			break;
1559*8040SBaban.Kenkre@Sun.COM 	}
1560*8040SBaban.Kenkre@Sun.COM 	(*state)->qdead = 1;
1561*8040SBaban.Kenkre@Sun.COM 	/* Wait for other threads processing search result to finish */
1562*8040SBaban.Kenkre@Sun.COM 	adutils_lookup_batch_wait(*state);
1563*8040SBaban.Kenkre@Sun.COM 	if (rc == -1 || (*state)->qinflight != 0)
1564*8040SBaban.Kenkre@Sun.COM 		ad_rc = ADUTILS_ERR_RETRIABLE_NET_ERR;
1565*8040SBaban.Kenkre@Sun.COM 	adutils_lookup_batch_release(state);
1566*8040SBaban.Kenkre@Sun.COM 	return (ad_rc);
1567*8040SBaban.Kenkre@Sun.COM }
1568*8040SBaban.Kenkre@Sun.COM 
1569*8040SBaban.Kenkre@Sun.COM const char *
1570*8040SBaban.Kenkre@Sun.COM adutils_lookup_batch_getdefdomain(adutils_query_state_t *state)
1571*8040SBaban.Kenkre@Sun.COM {
1572*8040SBaban.Kenkre@Sun.COM 	return (state->default_domain);
1573*8040SBaban.Kenkre@Sun.COM }
1574*8040SBaban.Kenkre@Sun.COM 
1575*8040SBaban.Kenkre@Sun.COM /*
1576*8040SBaban.Kenkre@Sun.COM  * Send one prepared search, queue up msgid, process what results are
1577*8040SBaban.Kenkre@Sun.COM  * available
1578*8040SBaban.Kenkre@Sun.COM  */
1579*8040SBaban.Kenkre@Sun.COM adutils_rc
1580*8040SBaban.Kenkre@Sun.COM adutils_lookup_batch_add(adutils_query_state_t *state,
1581*8040SBaban.Kenkre@Sun.COM 	const char *filter, const char **attrs, const char *edomain,
1582*8040SBaban.Kenkre@Sun.COM 	adutils_result_t **result, adutils_rc *rc)
1583*8040SBaban.Kenkre@Sun.COM {
1584*8040SBaban.Kenkre@Sun.COM 	adutils_rc	retcode = ADUTILS_SUCCESS;
1585*8040SBaban.Kenkre@Sun.COM 	int		lrc, qid;
1586*8040SBaban.Kenkre@Sun.COM 	int		num;
1587*8040SBaban.Kenkre@Sun.COM 	int		dead;
1588*8040SBaban.Kenkre@Sun.COM 	struct timeval	tv;
1589*8040SBaban.Kenkre@Sun.COM 	adutils_q_t	*q;
1590*8040SBaban.Kenkre@Sun.COM 
1591*8040SBaban.Kenkre@Sun.COM 	qid = atomic_inc_32_nv(&state->qlastsent) - 1;
1592*8040SBaban.Kenkre@Sun.COM 	q = &(state->queries[qid]);
1593*8040SBaban.Kenkre@Sun.COM 
1594*8040SBaban.Kenkre@Sun.COM 	/*
1595*8040SBaban.Kenkre@Sun.COM 	 * Remember the expected domain so we can check the results
1596*8040SBaban.Kenkre@Sun.COM 	 * against it
1597*8040SBaban.Kenkre@Sun.COM 	 */
1598*8040SBaban.Kenkre@Sun.COM 	q->edomain = edomain;
1599*8040SBaban.Kenkre@Sun.COM 
1600*8040SBaban.Kenkre@Sun.COM 	/* Remember where to put the results */
1601*8040SBaban.Kenkre@Sun.COM 	q->result = result;
1602*8040SBaban.Kenkre@Sun.COM 	q->rc = rc;
1603*8040SBaban.Kenkre@Sun.COM 
1604*8040SBaban.Kenkre@Sun.COM 	/*
1605*8040SBaban.Kenkre@Sun.COM 	 * Provide sane defaults for the results in case we never hear
1606*8040SBaban.Kenkre@Sun.COM 	 * back from the DS before closing the connection.
1607*8040SBaban.Kenkre@Sun.COM 	 */
1608*8040SBaban.Kenkre@Sun.COM 	*rc = ADUTILS_ERR_RETRIABLE_NET_ERR;
1609*8040SBaban.Kenkre@Sun.COM 	if (result != NULL)
1610*8040SBaban.Kenkre@Sun.COM 		*result = NULL;
1611*8040SBaban.Kenkre@Sun.COM 
1612*8040SBaban.Kenkre@Sun.COM 	/* Check the number of queued requests first */
1613*8040SBaban.Kenkre@Sun.COM 	tv.tv_sec = ADUTILS_SEARCH_TIMEOUT;
1614*8040SBaban.Kenkre@Sun.COM 	tv.tv_usec = 0;
1615*8040SBaban.Kenkre@Sun.COM 	while (!state->qadh->dead &&
1616*8040SBaban.Kenkre@Sun.COM 	    state->qadh->num_requests > state->qadh->max_requests) {
1617*8040SBaban.Kenkre@Sun.COM 		if (get_adobject_batch(state->qadh, &tv) != 0)
1618*8040SBaban.Kenkre@Sun.COM 			break;
1619*8040SBaban.Kenkre@Sun.COM 	}
1620*8040SBaban.Kenkre@Sun.COM 
1621*8040SBaban.Kenkre@Sun.COM 	/* Send this lookup, don't wait for a result here */
1622*8040SBaban.Kenkre@Sun.COM 	lrc = LDAP_SUCCESS;
1623*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_lock(&state->qadh->lock);
1624*8040SBaban.Kenkre@Sun.COM 
1625*8040SBaban.Kenkre@Sun.COM 	if (!state->qadh->dead) {
1626*8040SBaban.Kenkre@Sun.COM 		state->qadh->idletime = time(NULL);
1627*8040SBaban.Kenkre@Sun.COM 		lrc = ldap_search_ext(state->qadh->ld, state->basedn,
1628*8040SBaban.Kenkre@Sun.COM 		    LDAP_SCOPE_SUBTREE, filter, (char **)attrs,
1629*8040SBaban.Kenkre@Sun.COM 		    0, NULL, NULL, NULL, -1, &q->msgid);
1630*8040SBaban.Kenkre@Sun.COM 
1631*8040SBaban.Kenkre@Sun.COM 		if (lrc == LDAP_SUCCESS) {
1632*8040SBaban.Kenkre@Sun.COM 			state->qadh->num_requests++;
1633*8040SBaban.Kenkre@Sun.COM 		} else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE ||
1634*8040SBaban.Kenkre@Sun.COM 		    lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN ||
1635*8040SBaban.Kenkre@Sun.COM 		    lrc == LDAP_UNWILLING_TO_PERFORM) {
1636*8040SBaban.Kenkre@Sun.COM 			retcode = ADUTILS_ERR_RETRIABLE_NET_ERR;
1637*8040SBaban.Kenkre@Sun.COM 			state->qadh->dead = 1;
1638*8040SBaban.Kenkre@Sun.COM 		} else {
1639*8040SBaban.Kenkre@Sun.COM 			retcode = ADUTILS_ERR_OTHER;
1640*8040SBaban.Kenkre@Sun.COM 			state->qadh->dead = 1;
1641*8040SBaban.Kenkre@Sun.COM 		}
1642*8040SBaban.Kenkre@Sun.COM 	}
1643*8040SBaban.Kenkre@Sun.COM 	dead = state->qadh->dead;
1644*8040SBaban.Kenkre@Sun.COM 	num = state->qadh->num_requests;
1645*8040SBaban.Kenkre@Sun.COM 	(void) pthread_mutex_unlock(&state->qadh->lock);
1646*8040SBaban.Kenkre@Sun.COM 
1647*8040SBaban.Kenkre@Sun.COM 	if (dead) {
1648*8040SBaban.Kenkre@Sun.COM 		if (lrc != LDAP_SUCCESS)
1649*8040SBaban.Kenkre@Sun.COM 			idmapdlog(LOG_DEBUG,
1650*8040SBaban.Kenkre@Sun.COM 			    "AD ldap_search_ext error (%s) "
1651*8040SBaban.Kenkre@Sun.COM 			    "- %d queued requests",
1652*8040SBaban.Kenkre@Sun.COM 			    ldap_err2string(lrc), num);
1653*8040SBaban.Kenkre@Sun.COM 		return (retcode);
1654*8040SBaban.Kenkre@Sun.COM 	}
1655*8040SBaban.Kenkre@Sun.COM 
1656*8040SBaban.Kenkre@Sun.COM 	atomic_inc_32(&state->qinflight);
1657*8040SBaban.Kenkre@Sun.COM 
1658*8040SBaban.Kenkre@Sun.COM 	/*
1659*8040SBaban.Kenkre@Sun.COM 	 * Reap as many requests as we can _without_ waiting to prevent
1660*8040SBaban.Kenkre@Sun.COM 	 * any possible TCP socket buffer starvation deadlocks.
1661*8040SBaban.Kenkre@Sun.COM 	 */
1662*8040SBaban.Kenkre@Sun.COM 	(void) memset(&tv, 0, sizeof (tv));
1663*8040SBaban.Kenkre@Sun.COM 	while (get_adobject_batch(state->qadh, &tv) == 0)
1664*8040SBaban.Kenkre@Sun.COM 		;
1665*8040SBaban.Kenkre@Sun.COM 
1666*8040SBaban.Kenkre@Sun.COM 	return (ADUTILS_SUCCESS);
1667*8040SBaban.Kenkre@Sun.COM }
1668*8040SBaban.Kenkre@Sun.COM 
1669*8040SBaban.Kenkre@Sun.COM /*
1670*8040SBaban.Kenkre@Sun.COM  * Single AD lookup request implemented on top of the batch API.
1671*8040SBaban.Kenkre@Sun.COM  */
1672*8040SBaban.Kenkre@Sun.COM adutils_rc
1673*8040SBaban.Kenkre@Sun.COM adutils_lookup(adutils_ad_t *ad, const char *filter, const char **attrs,
1674*8040SBaban.Kenkre@Sun.COM 		const char *domain, adutils_result_t **result)
1675*8040SBaban.Kenkre@Sun.COM {
1676*8040SBaban.Kenkre@Sun.COM 	adutils_rc		rc, brc;
1677*8040SBaban.Kenkre@Sun.COM 	adutils_query_state_t	*qs;
1678*8040SBaban.Kenkre@Sun.COM 
1679*8040SBaban.Kenkre@Sun.COM 	rc = adutils_lookup_batch_start(ad, 1, NULL, NULL, &qs);
1680*8040SBaban.Kenkre@Sun.COM 	if (rc != ADUTILS_SUCCESS)
1681*8040SBaban.Kenkre@Sun.COM 		return (rc);
1682*8040SBaban.Kenkre@Sun.COM 
1683*8040SBaban.Kenkre@Sun.COM 	rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc);
1684*8040SBaban.Kenkre@Sun.COM 	if (rc != ADUTILS_SUCCESS) {
1685*8040SBaban.Kenkre@Sun.COM 		adutils_lookup_batch_release(&qs);
1686*8040SBaban.Kenkre@Sun.COM 		return (rc);
1687*8040SBaban.Kenkre@Sun.COM 	}
1688*8040SBaban.Kenkre@Sun.COM 
1689*8040SBaban.Kenkre@Sun.COM 	rc = adutils_lookup_batch_end(&qs);
1690*8040SBaban.Kenkre@Sun.COM 	if (rc != ADUTILS_SUCCESS)
1691*8040SBaban.Kenkre@Sun.COM 		return (rc);
1692*8040SBaban.Kenkre@Sun.COM 	return (brc);
1693*8040SBaban.Kenkre@Sun.COM }
1694