12b4a7802SBaban Kenkre /*
22b4a7802SBaban Kenkre  * CDDL HEADER START
32b4a7802SBaban Kenkre  *
42b4a7802SBaban Kenkre  * The contents of this file are subject to the terms of the
52b4a7802SBaban Kenkre  * Common Development and Distribution License (the "License").
62b4a7802SBaban Kenkre  * You may not use this file except in compliance with the License.
72b4a7802SBaban Kenkre  *
82b4a7802SBaban Kenkre  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92b4a7802SBaban Kenkre  * or http://www.opensolaris.org/os/licensing.
102b4a7802SBaban Kenkre  * See the License for the specific language governing permissions
112b4a7802SBaban Kenkre  * and limitations under the License.
122b4a7802SBaban Kenkre  *
132b4a7802SBaban Kenkre  * When distributing Covered Code, include this CDDL HEADER in each
142b4a7802SBaban Kenkre  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152b4a7802SBaban Kenkre  * If applicable, add the following below this CDDL HEADER, with the
162b4a7802SBaban Kenkre  * fields enclosed by brackets "[]" replaced with your own identifying
172b4a7802SBaban Kenkre  * information: Portions Copyright [yyyy] [name of copyright owner]
182b4a7802SBaban Kenkre  *
192b4a7802SBaban Kenkre  * CDDL HEADER END
202b4a7802SBaban Kenkre  */
212b4a7802SBaban Kenkre /*
22148c5f43SAlan Wright  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23*67fccfffSMatt Barden  * Copyright 2023 RackTop Systems, Inc.
242b4a7802SBaban Kenkre  */
252b4a7802SBaban Kenkre 
262b4a7802SBaban Kenkre #include <alloca.h>
272b4a7802SBaban Kenkre #include <string.h>
282b4a7802SBaban Kenkre #include <strings.h>
292b4a7802SBaban Kenkre #include <lber.h>
302b4a7802SBaban Kenkre #include <sasl/sasl.h>
312b4a7802SBaban Kenkre #include <string.h>
322b4a7802SBaban Kenkre #include <ctype.h>
332b4a7802SBaban Kenkre #include <synch.h>
342b4a7802SBaban Kenkre #include <atomic.h>
352b4a7802SBaban Kenkre #include <errno.h>
362b4a7802SBaban Kenkre #include <assert.h>
372b4a7802SBaban Kenkre #include <limits.h>
387a8a68f5SJulian Pullen #include <syslog.h>
392b4a7802SBaban Kenkre #include <sys/u8_textprep.h>
402b4a7802SBaban Kenkre #include <sys/varargs.h>
412b4a7802SBaban Kenkre #include "libadutils.h"
422b4a7802SBaban Kenkre #include "adutils_impl.h"
432b4a7802SBaban Kenkre 
442b4a7802SBaban Kenkre /* List of DSs, needed by the idle connection reaper thread */
452b4a7802SBaban Kenkre static pthread_mutex_t	adhostlock = PTHREAD_MUTEX_INITIALIZER;
462b4a7802SBaban Kenkre static adutils_host_t	*host_head = NULL;
472b4a7802SBaban Kenkre 
482b4a7802SBaban Kenkre /*
492b4a7802SBaban Kenkre  * List of query state structs -- needed so we can "route" LDAP results
502b4a7802SBaban Kenkre  * to the right context if multiple threads should be using the same
512b4a7802SBaban Kenkre  * connection concurrently
522b4a7802SBaban Kenkre  */
532b4a7802SBaban Kenkre static pthread_mutex_t		qstatelock = PTHREAD_MUTEX_INITIALIZER;
542b4a7802SBaban Kenkre static adutils_query_state_t	*qstatehead = NULL;
552b4a7802SBaban Kenkre 
562b4a7802SBaban Kenkre static char *adutils_sid_ber2str(BerValue *bvalues);
572b4a7802SBaban Kenkre static void adutils_lookup_batch_unlock(adutils_query_state_t **state);
582b4a7802SBaban Kenkre static void delete_ds(adutils_ad_t *ad, const char *host, int port);
592b4a7802SBaban Kenkre 
60148c5f43SAlan Wright int ad_debug[AD_DEBUG_MAX+1] = {0};
61148c5f43SAlan Wright 
622b4a7802SBaban Kenkre typedef struct binary_attrs {
632b4a7802SBaban Kenkre 	const char	*name;
642b4a7802SBaban Kenkre 	char		*(*ber2str)(BerValue *bvalues);
652b4a7802SBaban Kenkre } binary_attrs_t;
662b4a7802SBaban Kenkre 
672b4a7802SBaban Kenkre static binary_attrs_t binattrs[] = {
682b4a7802SBaban Kenkre 	{"objectSID", adutils_sid_ber2str},
692b4a7802SBaban Kenkre 	{NULL, NULL}
702b4a7802SBaban Kenkre };
712b4a7802SBaban Kenkre 
724d61c878SJulian Pullen 
737a8a68f5SJulian Pullen adutils_logger logger = syslog;
747a8a68f5SJulian Pullen 
757a8a68f5SJulian Pullen 
762b4a7802SBaban Kenkre void
adutils_set_logger(adutils_logger funct)777a8a68f5SJulian Pullen adutils_set_logger(adutils_logger funct)
782b4a7802SBaban Kenkre {
797a8a68f5SJulian Pullen 	logger = funct;
802b4a7802SBaban Kenkre }
812b4a7802SBaban Kenkre 
824d61c878SJulian Pullen 
832b4a7802SBaban Kenkre /*
842b4a7802SBaban Kenkre  * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com"
852b4a7802SBaban Kenkre  */
862b4a7802SBaban Kenkre static
872b4a7802SBaban Kenkre char *
adutils_dns2dn(const char * dns)882b4a7802SBaban Kenkre adutils_dns2dn(const char *dns)
892b4a7802SBaban Kenkre {
907a8a68f5SJulian Pullen 	int num_parts;
917a8a68f5SJulian Pullen 
927a8a68f5SJulian Pullen 	return (ldap_dns_to_dn((char *)dns, &num_parts));
932b4a7802SBaban Kenkre }
942b4a7802SBaban Kenkre 
954d61c878SJulian Pullen 
962b4a7802SBaban Kenkre /*
972b4a7802SBaban Kenkre  * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other
982b4a7802SBaban Kenkre  * attributes (CN, etc...).
992b4a7802SBaban Kenkre  */
1002b4a7802SBaban Kenkre char *
adutils_dn2dns(const char * dn)1012b4a7802SBaban Kenkre adutils_dn2dns(const char *dn)
1022b4a7802SBaban Kenkre {
1037a8a68f5SJulian Pullen 	return (DN_to_DNS(dn));
1042b4a7802SBaban Kenkre }
1052b4a7802SBaban Kenkre 
1067a8a68f5SJulian Pullen 
1072b4a7802SBaban Kenkre /*
1082b4a7802SBaban Kenkre  * Convert a binary SID in a BerValue to a adutils_sid_t
1092b4a7802SBaban Kenkre  */
1102b4a7802SBaban Kenkre int
adutils_getsid(BerValue * bval,adutils_sid_t * sidp)1117a8a68f5SJulian Pullen adutils_getsid(BerValue *bval, adutils_sid_t *sidp)
1122b4a7802SBaban Kenkre {
1132b4a7802SBaban Kenkre 	int		i, j;
1142b4a7802SBaban Kenkre 	uchar_t		*v;
1152b4a7802SBaban Kenkre 	uint32_t	a;
1162b4a7802SBaban Kenkre 
1172b4a7802SBaban Kenkre 	/*
1182b4a7802SBaban Kenkre 	 * The binary format of a SID is as follows:
1192b4a7802SBaban Kenkre 	 *
1202b4a7802SBaban Kenkre 	 * byte #0: version, always 0x01
1212b4a7802SBaban Kenkre 	 * byte #1: RID count, always <= 0x0f
1222b4a7802SBaban Kenkre 	 * bytes #2-#7: SID authority, big-endian 48-bit unsigned int
1232b4a7802SBaban Kenkre 	 *
1242b4a7802SBaban Kenkre 	 * followed by RID count RIDs, each a little-endian, unsigned
1252b4a7802SBaban Kenkre 	 * 32-bit int.
1262b4a7802SBaban Kenkre 	 */
1272b4a7802SBaban Kenkre 	/*
1282b4a7802SBaban Kenkre 	 * Sanity checks: must have at least one RID, version must be
1292b4a7802SBaban Kenkre 	 * 0x01, and the length must be 8 + rid count * 4
1302b4a7802SBaban Kenkre 	 */
1312b4a7802SBaban Kenkre 	if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 &&
1322b4a7802SBaban Kenkre 	    bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) {
1332b4a7802SBaban Kenkre 		v = (uchar_t *)bval->bv_val;
1342b4a7802SBaban Kenkre 		sidp->version = v[0];
1352b4a7802SBaban Kenkre 		sidp->sub_authority_count = v[1];
1362b4a7802SBaban Kenkre 		sidp->authority =
1372b4a7802SBaban Kenkre 		    /* big endian -- so start from the left */
1382b4a7802SBaban Kenkre 		    ((u_longlong_t)v[2] << 40) |
1392b4a7802SBaban Kenkre 		    ((u_longlong_t)v[3] << 32) |
1402b4a7802SBaban Kenkre 		    ((u_longlong_t)v[4] << 24) |
1412b4a7802SBaban Kenkre 		    ((u_longlong_t)v[5] << 16) |
1422b4a7802SBaban Kenkre 		    ((u_longlong_t)v[6] << 8) |
1432b4a7802SBaban Kenkre 		    (u_longlong_t)v[7];
1442b4a7802SBaban Kenkre 		for (i = 0; i < sidp->sub_authority_count; i++) {
1452b4a7802SBaban Kenkre 			j = 8 + (i * 4);
1462b4a7802SBaban Kenkre 			/* little endian -- so start from the right */
1472b4a7802SBaban Kenkre 			a = (v[j + 3] << 24) | (v[j + 2] << 16) |
1482b4a7802SBaban Kenkre 			    (v[j + 1] << 8) | (v[j]);
1492b4a7802SBaban Kenkre 			sidp->sub_authorities[i] = a;
1502b4a7802SBaban Kenkre 		}
1512b4a7802SBaban Kenkre 		return (0);
1522b4a7802SBaban Kenkre 	}
1532b4a7802SBaban Kenkre 	return (-1);
1542b4a7802SBaban Kenkre }
1552b4a7802SBaban Kenkre 
1562b4a7802SBaban Kenkre /*
1572b4a7802SBaban Kenkre  * Convert a adutils_sid_t to S-1-...
1582b4a7802SBaban Kenkre  */
1592b4a7802SBaban Kenkre char *
adutils_sid2txt(adutils_sid_t * sidp)1607a8a68f5SJulian Pullen adutils_sid2txt(adutils_sid_t *sidp)
1612b4a7802SBaban Kenkre {
1622b4a7802SBaban Kenkre 	int	rlen, i, len;
1632b4a7802SBaban Kenkre 	char	*str, *cp;
1642b4a7802SBaban Kenkre 
1652b4a7802SBaban Kenkre 	if (sidp->version != 1)
1662b4a7802SBaban Kenkre 		return (NULL);
1672b4a7802SBaban Kenkre 
1682b4a7802SBaban Kenkre 	len = sizeof ("S-1-") - 1;
1692b4a7802SBaban Kenkre 
1702b4a7802SBaban Kenkre 	/*
1712b4a7802SBaban Kenkre 	 * We could optimize like so, but, why?
1722b4a7802SBaban Kenkre 	 *	if (sidp->authority < 10)
1732b4a7802SBaban Kenkre 	 *		len += 2;
1742b4a7802SBaban Kenkre 	 *	else if (sidp->authority < 100)
1752b4a7802SBaban Kenkre 	 *		len += 3;
1762b4a7802SBaban Kenkre 	 *	else
1772b4a7802SBaban Kenkre 	 *		len += snprintf(NULL, 0"%llu", sidp->authority);
1782b4a7802SBaban Kenkre 	 */
1792b4a7802SBaban Kenkre 	len += snprintf(NULL, 0, "%llu", sidp->authority);
1802b4a7802SBaban Kenkre 
1812b4a7802SBaban Kenkre 	/* Max length of a uint32_t printed out in ASCII is 10 bytes */
1822b4a7802SBaban Kenkre 	len += 1 + (sidp->sub_authority_count + 1) * 10;
1832b4a7802SBaban Kenkre 
1842b4a7802SBaban Kenkre 	if ((cp = str = malloc(len)) == NULL)
1852b4a7802SBaban Kenkre 		return (NULL);
1862b4a7802SBaban Kenkre 
1872b4a7802SBaban Kenkre 	rlen = snprintf(str, len, "S-1-%llu", sidp->authority);
1882b4a7802SBaban Kenkre 
1892b4a7802SBaban Kenkre 	cp += rlen;
1902b4a7802SBaban Kenkre 	len -= rlen;
1912b4a7802SBaban Kenkre 
1922b4a7802SBaban Kenkre 	for (i = 0; i < sidp->sub_authority_count; i++) {
1932b4a7802SBaban Kenkre 		assert(len > 0);
1942b4a7802SBaban Kenkre 		rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]);
1952b4a7802SBaban Kenkre 		cp += rlen;
1962b4a7802SBaban Kenkre 		len -= rlen;
1972b4a7802SBaban Kenkre 		assert(len >= 0);
1982b4a7802SBaban Kenkre 	}
1992b4a7802SBaban Kenkre 
2002b4a7802SBaban Kenkre 	return (str);
2012b4a7802SBaban Kenkre }
2022b4a7802SBaban Kenkre 
2032b4a7802SBaban Kenkre /*
2042b4a7802SBaban Kenkre  * Convert a adutils_sid_t to on-the-wire encoding
2052b4a7802SBaban Kenkre  */
2062b4a7802SBaban Kenkre static
2072b4a7802SBaban Kenkre int
sid2binsid(adutils_sid_t * sid,uchar_t * binsid,int binsidlen)2082b4a7802SBaban Kenkre sid2binsid(adutils_sid_t *sid, uchar_t *binsid, int binsidlen)
2092b4a7802SBaban Kenkre {
2102b4a7802SBaban Kenkre 	uchar_t		*p;
2112b4a7802SBaban Kenkre 	int		i;
2122b4a7802SBaban Kenkre 	uint64_t	a;
2132b4a7802SBaban Kenkre 	uint32_t	r;
2142b4a7802SBaban Kenkre 
2152b4a7802SBaban Kenkre 	if (sid->version != 1 ||
2162b4a7802SBaban Kenkre 	    binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4))
2172b4a7802SBaban Kenkre 		return (-1);
2182b4a7802SBaban Kenkre 
2192b4a7802SBaban Kenkre 	p = binsid;
2202b4a7802SBaban Kenkre 	*p++ = 0x01;		/* version */
2212b4a7802SBaban Kenkre 	/* sub authority count */
2222b4a7802SBaban Kenkre 	*p++ = sid->sub_authority_count;
2232b4a7802SBaban Kenkre 	/* Authority */
2242b4a7802SBaban Kenkre 	a = sid->authority;
2252b4a7802SBaban Kenkre 	/* big-endian -- start from left */
2262b4a7802SBaban Kenkre 	*p++ = (a >> 40) & 0xFF;
2272b4a7802SBaban Kenkre 	*p++ = (a >> 32) & 0xFF;
2282b4a7802SBaban Kenkre 	*p++ = (a >> 24) & 0xFF;
2292b4a7802SBaban Kenkre 	*p++ = (a >> 16) & 0xFF;
2302b4a7802SBaban Kenkre 	*p++ = (a >> 8) & 0xFF;
2312b4a7802SBaban Kenkre 	*p++ = a & 0xFF;
2322b4a7802SBaban Kenkre 
2332b4a7802SBaban Kenkre 	/* sub-authorities */
2342b4a7802SBaban Kenkre 	for (i = 0; i < sid->sub_authority_count; i++) {
2352b4a7802SBaban Kenkre 		r = sid->sub_authorities[i];
2362b4a7802SBaban Kenkre 		/* little-endian -- start from right */
2372b4a7802SBaban Kenkre 		*p++ = (r & 0x000000FF);
2382b4a7802SBaban Kenkre 		*p++ = (r & 0x0000FF00) >> 8;
2392b4a7802SBaban Kenkre 		*p++ = (r & 0x00FF0000) >> 16;
2402b4a7802SBaban Kenkre 		*p++ = (r & 0xFF000000) >> 24;
2412b4a7802SBaban Kenkre 	}
2422b4a7802SBaban Kenkre 
2432b4a7802SBaban Kenkre 	return (0);
2442b4a7802SBaban Kenkre }
2452b4a7802SBaban Kenkre 
2462b4a7802SBaban Kenkre /*
2472b4a7802SBaban Kenkre  * Convert a stringified SID (S-1-...) into a hex-encoded version of the
2482b4a7802SBaban Kenkre  * on-the-wire encoding, but with each pair of hex digits pre-pended
2492b4a7802SBaban Kenkre  * with a '\', so we can pass this to libldap.
2502b4a7802SBaban Kenkre  */
2512b4a7802SBaban Kenkre int
adutils_txtsid2hexbinsid(const char * txt,const uint32_t * rid,char * hexbinsid,int hexbinsidlen)2522b4a7802SBaban Kenkre adutils_txtsid2hexbinsid(const char *txt, const uint32_t *rid,
253*67fccfffSMatt Barden     char *hexbinsid, int hexbinsidlen)
2542b4a7802SBaban Kenkre {
2552b4a7802SBaban Kenkre 	adutils_sid_t	sid = { 0 };
2562b4a7802SBaban Kenkre 	int		i, j;
2572b4a7802SBaban Kenkre 	const char	*cp;
2582b4a7802SBaban Kenkre 	char		*ecp;
2592b4a7802SBaban Kenkre 	u_longlong_t	a;
2602b4a7802SBaban Kenkre 	unsigned long	r;
2612b4a7802SBaban Kenkre 	uchar_t		*binsid, b, hb;
2622b4a7802SBaban Kenkre 
2632b4a7802SBaban Kenkre 	/* Only version 1 SIDs please */
2642b4a7802SBaban Kenkre 	if (strncmp(txt, "S-1-", strlen("S-1-")) != 0)
2652b4a7802SBaban Kenkre 		return (-1);
2662b4a7802SBaban Kenkre 
2672b4a7802SBaban Kenkre 	if (strlen(txt) < (strlen("S-1-") + 1))
2682b4a7802SBaban Kenkre 		return (-1);
2692b4a7802SBaban Kenkre 
2702b4a7802SBaban Kenkre 	/* count '-'s */
2712b4a7802SBaban Kenkre 	for (j = 0, cp = strchr(txt, '-');
2722b4a7802SBaban Kenkre 	    cp != NULL && *cp != '\0';
2732b4a7802SBaban Kenkre 	    j++, cp = strchr(cp + 1, '-')) {
2742b4a7802SBaban Kenkre 		/* can't end on a '-' */
2752b4a7802SBaban Kenkre 		if (*(cp + 1) == '\0')
2762b4a7802SBaban Kenkre 			return (-1);
2772b4a7802SBaban Kenkre 	}
2782b4a7802SBaban Kenkre 
2792b4a7802SBaban Kenkre 	/* Adjust count for version and authority */
2802b4a7802SBaban Kenkre 	j -= 2;
2812b4a7802SBaban Kenkre 
2822b4a7802SBaban Kenkre 	/* we know the version number and RID count */
2832b4a7802SBaban Kenkre 	sid.version = 1;
2842b4a7802SBaban Kenkre 	sid.sub_authority_count = (rid != NULL) ? j + 1 : j;
2852b4a7802SBaban Kenkre 
2862b4a7802SBaban Kenkre 	/* must have at least one RID, but not too many */
2872b4a7802SBaban Kenkre 	if (sid.sub_authority_count < 1 ||
2882b4a7802SBaban Kenkre 	    sid.sub_authority_count > ADUTILS_SID_MAX_SUB_AUTHORITIES)
2892b4a7802SBaban Kenkre 		return (-1);
2902b4a7802SBaban Kenkre 
2912b4a7802SBaban Kenkre 	/* check that we only have digits and '-' */
2922b4a7802SBaban Kenkre 	if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1))
2932b4a7802SBaban Kenkre 		return (-1);
2942b4a7802SBaban Kenkre 
2952b4a7802SBaban Kenkre 	cp = txt + strlen("S-1-");
2962b4a7802SBaban Kenkre 
2972b4a7802SBaban Kenkre 	/* 64-bit safe parsing of unsigned 48-bit authority value */
2982b4a7802SBaban Kenkre 	errno = 0;
2992b4a7802SBaban Kenkre 	a = strtoull(cp, &ecp, 10);
3002b4a7802SBaban Kenkre 
3012b4a7802SBaban Kenkre 	/* errors parsing the authority or too many bits */
3022b4a7802SBaban Kenkre 	if (cp == ecp || (a == 0 && errno == EINVAL) ||
3032b4a7802SBaban Kenkre 	    (a == ULLONG_MAX && errno == ERANGE) ||
3042b4a7802SBaban Kenkre 	    (a & 0x0000ffffffffffffULL) != a)
3052b4a7802SBaban Kenkre 		return (-1);
3062b4a7802SBaban Kenkre 
3072b4a7802SBaban Kenkre 	cp = ecp;
3082b4a7802SBaban Kenkre 
3092b4a7802SBaban Kenkre 	sid.authority = (uint64_t)a;
3102b4a7802SBaban Kenkre 
3112b4a7802SBaban Kenkre 	for (i = 0; i < j; i++) {
3122b4a7802SBaban Kenkre 		if (*cp++ != '-')
3132b4a7802SBaban Kenkre 			return (-1);
3142b4a7802SBaban Kenkre 		/* 64-bit safe parsing of unsigned 32-bit RID */
3152b4a7802SBaban Kenkre 		errno = 0;
3162b4a7802SBaban Kenkre 		r = strtoul(cp, &ecp, 10);
3172b4a7802SBaban Kenkre 		/* errors parsing the RID or too many bits */
3182b4a7802SBaban Kenkre 		if (cp == ecp || (r == 0 && errno == EINVAL) ||
3192b4a7802SBaban Kenkre 		    (r == ULONG_MAX && errno == ERANGE) ||
3202b4a7802SBaban Kenkre 		    (r & 0xffffffffUL) != r)
3212b4a7802SBaban Kenkre 			return (-1);
3222b4a7802SBaban Kenkre 		sid.sub_authorities[i] = (uint32_t)r;
3232b4a7802SBaban Kenkre 		cp = ecp;
3242b4a7802SBaban Kenkre 	}
3252b4a7802SBaban Kenkre 
3262b4a7802SBaban Kenkre 	/* check that all of the string SID has been consumed */
3272b4a7802SBaban Kenkre 	if (*cp != '\0')
3282b4a7802SBaban Kenkre 		return (-1);
3292b4a7802SBaban Kenkre 
3302b4a7802SBaban Kenkre 	if (rid != NULL)
3312b4a7802SBaban Kenkre 		sid.sub_authorities[j] = *rid;
3322b4a7802SBaban Kenkre 
3332b4a7802SBaban Kenkre 	j = 1 + 1 + 6 + sid.sub_authority_count * 4;
3342b4a7802SBaban Kenkre 
3352b4a7802SBaban Kenkre 	if (hexbinsidlen < (j * 3))
3362b4a7802SBaban Kenkre 		return (-2);
3372b4a7802SBaban Kenkre 
3382b4a7802SBaban Kenkre 	/* binary encode the SID */
3392b4a7802SBaban Kenkre 	binsid = (uchar_t *)alloca(j);
3402b4a7802SBaban Kenkre 	(void) sid2binsid(&sid, binsid, j);
3412b4a7802SBaban Kenkre 
3422b4a7802SBaban Kenkre 	/* hex encode, with a backslash before each byte */
3432b4a7802SBaban Kenkre 	for (ecp = hexbinsid, i = 0; i < j; i++) {
3442b4a7802SBaban Kenkre 		b = binsid[i];
3452b4a7802SBaban Kenkre 		*ecp++ = '\\';
3462b4a7802SBaban Kenkre 		hb = (b >> 4) & 0xF;
3472b4a7802SBaban Kenkre 		*ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
3482b4a7802SBaban Kenkre 		hb = b & 0xF;
3492b4a7802SBaban Kenkre 		*ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
3502b4a7802SBaban Kenkre 	}
3512b4a7802SBaban Kenkre 	*ecp = '\0';
3522b4a7802SBaban Kenkre 
3532b4a7802SBaban Kenkre 	return (0);
3542b4a7802SBaban Kenkre }
3552b4a7802SBaban Kenkre 
3562b4a7802SBaban Kenkre static
3572b4a7802SBaban Kenkre char *
convert_bval2sid(BerValue * bval,uint32_t * rid)3582b4a7802SBaban Kenkre convert_bval2sid(BerValue *bval, uint32_t *rid)
3592b4a7802SBaban Kenkre {
3602b4a7802SBaban Kenkre 	adutils_sid_t	sid;
3612b4a7802SBaban Kenkre 
3627a8a68f5SJulian Pullen 	if (adutils_getsid(bval, &sid) < 0)
3632b4a7802SBaban Kenkre 		return (NULL);
3642b4a7802SBaban Kenkre 
3652b4a7802SBaban Kenkre 	/*
3662b4a7802SBaban Kenkre 	 * If desired and if the SID is what should be a domain/computer
3672b4a7802SBaban Kenkre 	 * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then
3682b4a7802SBaban Kenkre 	 * save the last RID and truncate the SID
3692b4a7802SBaban Kenkre 	 */
3702b4a7802SBaban Kenkre 	if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5)
3712b4a7802SBaban Kenkre 		*rid = sid.sub_authorities[--sid.sub_authority_count];
3727a8a68f5SJulian Pullen 	return (adutils_sid2txt(&sid));
3732b4a7802SBaban Kenkre }
3742b4a7802SBaban Kenkre 
3752b4a7802SBaban Kenkre 
3762b4a7802SBaban Kenkre /*
3772b4a7802SBaban Kenkre  * Return a NUL-terminated stringified SID from the value of an
3782b4a7802SBaban Kenkre  * objectSid attribute and put the last RID in *rid.
3792b4a7802SBaban Kenkre  */
3802b4a7802SBaban Kenkre char *
adutils_bv_objsid2sidstr(BerValue * bval,uint32_t * rid)3812b4a7802SBaban Kenkre adutils_bv_objsid2sidstr(BerValue *bval, uint32_t *rid)
3822b4a7802SBaban Kenkre {
3832b4a7802SBaban Kenkre 	char *sid;
3842b4a7802SBaban Kenkre 
3852b4a7802SBaban Kenkre 	if (bval == NULL)
3862b4a7802SBaban Kenkre 		return (NULL);
3872b4a7802SBaban Kenkre 	/* objectSid is single valued */
3882b4a7802SBaban Kenkre 	if ((sid = convert_bval2sid(bval, rid)) == NULL)
3892b4a7802SBaban Kenkre 		return (NULL);
3902b4a7802SBaban Kenkre 	return (sid);
3912b4a7802SBaban Kenkre }
3922b4a7802SBaban Kenkre 
3932b4a7802SBaban Kenkre static
3942b4a7802SBaban Kenkre char *
adutils_sid_ber2str(BerValue * bval)3952b4a7802SBaban Kenkre adutils_sid_ber2str(BerValue *bval)
3962b4a7802SBaban Kenkre {
3972b4a7802SBaban Kenkre 	return (adutils_bv_objsid2sidstr(bval, NULL));
3982b4a7802SBaban Kenkre }
3992b4a7802SBaban Kenkre 
4002b4a7802SBaban Kenkre 
401e3f2c991SKeyur Desai /*
402e3f2c991SKeyur Desai  * Extract an int from the Ber value
403e3f2c991SKeyur Desai  * Return B_TRUE if a valid integer was found, B_FALSE if not.
404e3f2c991SKeyur Desai  */
405e3f2c991SKeyur Desai boolean_t
adutils_bv_uint(BerValue * bval,unsigned int * result)406e3f2c991SKeyur Desai adutils_bv_uint(BerValue *bval, unsigned int *result)
407e3f2c991SKeyur Desai {
408e3f2c991SKeyur Desai 	char buf[40];	/* big enough for any int */
409e3f2c991SKeyur Desai 	unsigned int tmp;
410e3f2c991SKeyur Desai 	char *p;
411e3f2c991SKeyur Desai 
412e3f2c991SKeyur Desai 	*result = 0;	/* for error cases */
413e3f2c991SKeyur Desai 
414e3f2c991SKeyur Desai 	if (bval == NULL || bval->bv_val == NULL)
415e3f2c991SKeyur Desai 		return (B_FALSE);
416e3f2c991SKeyur Desai 	if (bval->bv_len >= sizeof (buf))
417e3f2c991SKeyur Desai 		return (B_FALSE);
418e3f2c991SKeyur Desai 
419e3f2c991SKeyur Desai 	(void) memcpy(buf, bval->bv_val, bval->bv_len);
420e3f2c991SKeyur Desai 	buf[bval->bv_len] = '\0';
421e3f2c991SKeyur Desai 
422e3f2c991SKeyur Desai 	tmp = strtoul(buf, &p, 10);
423e3f2c991SKeyur Desai 
424e3f2c991SKeyur Desai 	/* Junk after the number? */
425e3f2c991SKeyur Desai 	if (*p != '\0')
426e3f2c991SKeyur Desai 		return (B_FALSE);
427e3f2c991SKeyur Desai 
428e3f2c991SKeyur Desai 	*result = tmp;
429e3f2c991SKeyur Desai 
430e3f2c991SKeyur Desai 	return (B_TRUE);
431e3f2c991SKeyur Desai }
432e3f2c991SKeyur Desai 
4332b4a7802SBaban Kenkre /* Return a NUL-terminated string from the Ber value */
4342b4a7802SBaban Kenkre char *
adutils_bv_str(BerValue * bval)435e3f2c991SKeyur Desai adutils_bv_str(BerValue *bval)
4362b4a7802SBaban Kenkre {
4372b4a7802SBaban Kenkre 	char *s;
4382b4a7802SBaban Kenkre 
4392b4a7802SBaban Kenkre 	if (bval == NULL || bval->bv_val == NULL)
4402b4a7802SBaban Kenkre 		return (NULL);
4412b4a7802SBaban Kenkre 	if ((s = malloc(bval->bv_len + 1)) == NULL)
4422b4a7802SBaban Kenkre 		return (NULL);
4432b4a7802SBaban Kenkre 	(void) snprintf(s, bval->bv_len + 1, "%.*s", bval->bv_len,
4442b4a7802SBaban Kenkre 	    bval->bv_val);
4452b4a7802SBaban Kenkre 	return (s);
4462b4a7802SBaban Kenkre }
4472b4a7802SBaban Kenkre 
4482b4a7802SBaban Kenkre /*ARGSUSED*/
4492b4a7802SBaban Kenkre int
saslcallback(LDAP * ld,unsigned flags,void * defaults,void * prompts)4502b4a7802SBaban Kenkre saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts)
4512b4a7802SBaban Kenkre {
4522b4a7802SBaban Kenkre 	sasl_interact_t	*interact;
4532b4a7802SBaban Kenkre 
4542b4a7802SBaban Kenkre 	if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
4552b4a7802SBaban Kenkre 		return (LDAP_PARAM_ERROR);
4562b4a7802SBaban Kenkre 
4572b4a7802SBaban Kenkre 	/* There should be no extra arguemnts for SASL/GSSAPI authentication */
4582b4a7802SBaban Kenkre 	for (interact = prompts; interact->id != SASL_CB_LIST_END;
4592b4a7802SBaban Kenkre 	    interact++) {
4602b4a7802SBaban Kenkre 		interact->result = NULL;
4612b4a7802SBaban Kenkre 		interact->len = 0;
4622b4a7802SBaban Kenkre 	}
4632b4a7802SBaban Kenkre 	return (LDAP_SUCCESS);
4642b4a7802SBaban Kenkre }
4652b4a7802SBaban Kenkre 
4662b4a7802SBaban Kenkre 
4672b4a7802SBaban Kenkre #define	ADCONN_TIME	300
4682b4a7802SBaban Kenkre 
4692b4a7802SBaban Kenkre /*
4702b4a7802SBaban Kenkre  * Idle connection reaping side of connection management
4712b4a7802SBaban Kenkre  */
4722b4a7802SBaban Kenkre void
adutils_reap_idle_connections()4732b4a7802SBaban Kenkre adutils_reap_idle_connections()
4742b4a7802SBaban Kenkre {
4752b4a7802SBaban Kenkre 	adutils_host_t	*adh;
4762b4a7802SBaban Kenkre 	time_t		now;
4772b4a7802SBaban Kenkre 
4782b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&adhostlock);
4792b4a7802SBaban Kenkre 	now = time(NULL);
4802b4a7802SBaban Kenkre 	for (adh = host_head; adh != NULL; adh = adh->next) {
4812b4a7802SBaban Kenkre 		(void) pthread_mutex_lock(&adh->lock);
4822b4a7802SBaban Kenkre 		if (adh->ref == 0 && adh->idletime != 0 &&
4832b4a7802SBaban Kenkre 		    adh->idletime + ADCONN_TIME < now) {
4842b4a7802SBaban Kenkre 			if (adh->ld) {
4852b4a7802SBaban Kenkre 				(void) ldap_unbind(adh->ld);
4862b4a7802SBaban Kenkre 				adh->ld = NULL;
4872b4a7802SBaban Kenkre 				adh->idletime = 0;
4882b4a7802SBaban Kenkre 				adh->ref = 0;
4892b4a7802SBaban Kenkre 			}
4902b4a7802SBaban Kenkre 		}
4912b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&adh->lock);
4922b4a7802SBaban Kenkre 	}
4932b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&adhostlock);
4942b4a7802SBaban Kenkre }
4952b4a7802SBaban Kenkre 
4962b4a7802SBaban Kenkre 
4972b4a7802SBaban Kenkre adutils_rc
adutils_ad_alloc(adutils_ad_t ** new_ad,const char * domain_name,adutils_ad_partition_t part)498e3f2c991SKeyur Desai adutils_ad_alloc(adutils_ad_t **new_ad, const char *domain_name,
499*67fccfffSMatt Barden     adutils_ad_partition_t part)
5002b4a7802SBaban Kenkre {
5012b4a7802SBaban Kenkre 	adutils_ad_t *ad;
5022b4a7802SBaban Kenkre 
5032b4a7802SBaban Kenkre 	*new_ad = NULL;
5042b4a7802SBaban Kenkre 
5052b4a7802SBaban Kenkre 	if ((ad = calloc(1, sizeof (*ad))) == NULL)
5062b4a7802SBaban Kenkre 		return (ADUTILS_ERR_MEMORY);
5072b4a7802SBaban Kenkre 	ad->ref = 1;
5082b4a7802SBaban Kenkre 	ad->partition = part;
509e3f2c991SKeyur Desai 
510e3f2c991SKeyur Desai 	/* domain_name is required iff we are talking directly to a DC */
511e3f2c991SKeyur Desai 	if (part == ADUTILS_AD_DATA) {
512e3f2c991SKeyur Desai 		assert(domain_name != NULL);
513e3f2c991SKeyur Desai 		assert(*domain_name != '\0');
514e3f2c991SKeyur Desai 
515e3f2c991SKeyur Desai 		ad->basedn = adutils_dns2dn(domain_name);
516e3f2c991SKeyur Desai 	} else {
517e3f2c991SKeyur Desai 		assert(domain_name == NULL);
518e3f2c991SKeyur Desai 		ad->basedn = strdup("");
519e3f2c991SKeyur Desai 	}
520e3f2c991SKeyur Desai 	if (ad->basedn == NULL)
5212b4a7802SBaban Kenkre 		goto err;
522e3f2c991SKeyur Desai 
5232b4a7802SBaban Kenkre 	if (pthread_mutex_init(&ad->lock, NULL) != 0)
5242b4a7802SBaban Kenkre 		goto err;
5252b4a7802SBaban Kenkre 	*new_ad = ad;
5262b4a7802SBaban Kenkre 	return (ADUTILS_SUCCESS);
5272b4a7802SBaban Kenkre 
5282b4a7802SBaban Kenkre err:
529e3f2c991SKeyur Desai 	free(ad->basedn);
5302b4a7802SBaban Kenkre 	free(ad);
5312b4a7802SBaban Kenkre 	return (ADUTILS_ERR_MEMORY);
5322b4a7802SBaban Kenkre }
5332b4a7802SBaban Kenkre 
5342b4a7802SBaban Kenkre void
adutils_ad_free(adutils_ad_t ** ad)5352b4a7802SBaban Kenkre adutils_ad_free(adutils_ad_t **ad)
5362b4a7802SBaban Kenkre {
5372b4a7802SBaban Kenkre 	adutils_host_t *p;
5382b4a7802SBaban Kenkre 	adutils_host_t *prev;
5392b4a7802SBaban Kenkre 
5402b4a7802SBaban Kenkre 	if (ad == NULL || *ad == NULL)
5412b4a7802SBaban Kenkre 		return;
5422b4a7802SBaban Kenkre 
5432b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&(*ad)->lock);
5442b4a7802SBaban Kenkre 
5452b4a7802SBaban Kenkre 	if (atomic_dec_32_nv(&(*ad)->ref) > 0) {
5462b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&(*ad)->lock);
5472b4a7802SBaban Kenkre 		*ad = NULL;
5482b4a7802SBaban Kenkre 		return;
5492b4a7802SBaban Kenkre 	}
5502b4a7802SBaban Kenkre 
5512b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&adhostlock);
5522b4a7802SBaban Kenkre 	prev = NULL;
5532b4a7802SBaban Kenkre 	p = host_head;
5542b4a7802SBaban Kenkre 	while (p != NULL) {
5552b4a7802SBaban Kenkre 		if (p->owner != (*ad)) {
5562b4a7802SBaban Kenkre 			prev = p;
5572b4a7802SBaban Kenkre 			p = p->next;
5582b4a7802SBaban Kenkre 			continue;
5592b4a7802SBaban Kenkre 		} else {
5602b4a7802SBaban Kenkre 			delete_ds((*ad), p->host, p->port);
5612b4a7802SBaban Kenkre 			if (prev == NULL)
5622b4a7802SBaban Kenkre 				p = host_head;
5632b4a7802SBaban Kenkre 			else
5642b4a7802SBaban Kenkre 				p = prev->next;
5652b4a7802SBaban Kenkre 		}
5662b4a7802SBaban Kenkre 	}
5672b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&adhostlock);
5682b4a7802SBaban Kenkre 
5692b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&(*ad)->lock);
5702b4a7802SBaban Kenkre 	(void) pthread_mutex_destroy(&(*ad)->lock);
5712b4a7802SBaban Kenkre 
5724d61c878SJulian Pullen 	if ((*ad)->known_domains)
5734d61c878SJulian Pullen 		free((*ad)->known_domains);
574e3f2c991SKeyur Desai 	free((*ad)->basedn);
5752b4a7802SBaban Kenkre 	free(*ad);
5762b4a7802SBaban Kenkre 
5772b4a7802SBaban Kenkre 	*ad = NULL;
5782b4a7802SBaban Kenkre }
5792b4a7802SBaban Kenkre 
5802b4a7802SBaban Kenkre static
5812b4a7802SBaban Kenkre int
open_conn(adutils_host_t * adh,int timeoutsecs)5822b4a7802SBaban Kenkre open_conn(adutils_host_t *adh, int timeoutsecs)
5832b4a7802SBaban Kenkre {
5842b4a7802SBaban Kenkre 	int zero = 0;
5852b4a7802SBaban Kenkre 	int ldversion, rc;
5862b4a7802SBaban Kenkre 	int timeoutms = timeoutsecs * 1000;
5872b4a7802SBaban Kenkre 
5882b4a7802SBaban Kenkre 	if (adh == NULL)
5892b4a7802SBaban Kenkre 		return (0);
5902b4a7802SBaban Kenkre 
5912b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&adh->lock);
5922b4a7802SBaban Kenkre 
5932b4a7802SBaban Kenkre 	if (!adh->dead && adh->ld != NULL)
5942b4a7802SBaban Kenkre 		/* done! */
5952b4a7802SBaban Kenkre 		goto out;
5962b4a7802SBaban Kenkre 
5972b4a7802SBaban Kenkre 	if (adh->ld != NULL) {
5982b4a7802SBaban Kenkre 		(void) ldap_unbind(adh->ld);
5992b4a7802SBaban Kenkre 		adh->ld = NULL;
6002b4a7802SBaban Kenkre 	}
6012b4a7802SBaban Kenkre 	adh->num_requests = 0;
6022b4a7802SBaban Kenkre 
6032b4a7802SBaban Kenkre 	atomic_inc_64(&adh->generation);
6042b4a7802SBaban Kenkre 
6052b4a7802SBaban Kenkre 	/* Open and bind an LDAP connection */
6062b4a7802SBaban Kenkre 	adh->ld = ldap_init(adh->host, adh->port);
6072b4a7802SBaban Kenkre 	if (adh->ld == NULL) {
6087a8a68f5SJulian Pullen 		logger(LOG_INFO, "ldap_init() to server "
6092b4a7802SBaban Kenkre 		    "%s port %d failed. (%s)", adh->host,
6102b4a7802SBaban Kenkre 		    adh->port, strerror(errno));
6112b4a7802SBaban Kenkre 		goto out;
6122b4a7802SBaban Kenkre 	}
6132b4a7802SBaban Kenkre 	ldversion = LDAP_VERSION3;
6142b4a7802SBaban Kenkre 	(void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion);
6152b4a7802SBaban Kenkre 	(void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
6162b4a7802SBaban Kenkre 	(void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero);
6172b4a7802SBaban Kenkre 	(void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero);
6182b4a7802SBaban Kenkre 	(void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms);
6192b4a7802SBaban Kenkre 	(void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
620bd428526SJulian Pullen 
621bd428526SJulian Pullen 	rc = adutils_set_thread_functions(adh->ld);
622bd428526SJulian Pullen 	if (rc != LDAP_SUCCESS) {
623bd428526SJulian Pullen 		/* Error has already been logged */
624bd428526SJulian Pullen 		(void) ldap_unbind(adh->ld);
625bd428526SJulian Pullen 		adh->ld = NULL;
626bd428526SJulian Pullen 		goto out;
627bd428526SJulian Pullen 	}
628bd428526SJulian Pullen 
6292b4a7802SBaban Kenkre 	rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */,
6302b4a7802SBaban Kenkre 	    adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback,
6312b4a7802SBaban Kenkre 	    NULL);
6322b4a7802SBaban Kenkre 
6332b4a7802SBaban Kenkre 	if (rc != LDAP_SUCCESS) {
6347a8a68f5SJulian Pullen 		logger(LOG_INFO, "ldap_sasl_interactive_bind_s() to server "
6352b4a7802SBaban Kenkre 		    "%s port %d failed. (%s)", adh->host, adh->port,
6362b4a7802SBaban Kenkre 		    ldap_err2string(rc));
637*67fccfffSMatt Barden 		ldap_perror(adh->ld, adh->host);
638*67fccfffSMatt Barden 		(void) ldap_unbind(adh->ld);
639*67fccfffSMatt Barden 		adh->ld = NULL;
640e3f2c991SKeyur Desai 		goto out;
6412b4a7802SBaban Kenkre 	}
6422b4a7802SBaban Kenkre 
643e3f2c991SKeyur Desai 	logger(LOG_DEBUG, "Using server %s:%d",
6442b4a7802SBaban Kenkre 	    adh->host, adh->port);
6452b4a7802SBaban Kenkre 
6462b4a7802SBaban Kenkre out:
6472b4a7802SBaban Kenkre 	if (adh->ld != NULL) {
6482b4a7802SBaban Kenkre 		atomic_inc_32(&adh->ref);
6492b4a7802SBaban Kenkre 		adh->idletime = time(NULL);
6502b4a7802SBaban Kenkre 		adh->dead = 0;
6512b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&adh->lock);
6522b4a7802SBaban Kenkre 		return (1);
6532b4a7802SBaban Kenkre 	}
6542b4a7802SBaban Kenkre 
6552b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&adh->lock);
6562b4a7802SBaban Kenkre 	return (0);
6572b4a7802SBaban Kenkre }
6582b4a7802SBaban Kenkre 
6592b4a7802SBaban Kenkre 
6602b4a7802SBaban Kenkre /*
6612b4a7802SBaban Kenkre  * Connection management: find an open connection or open one
6622b4a7802SBaban Kenkre  */
6632b4a7802SBaban Kenkre static
6642b4a7802SBaban Kenkre adutils_host_t *
get_conn(adutils_ad_t * ad)6652b4a7802SBaban Kenkre get_conn(adutils_ad_t *ad)
6662b4a7802SBaban Kenkre {
6672b4a7802SBaban Kenkre 	adutils_host_t	*adh = NULL;
6682b4a7802SBaban Kenkre 	int		tries;
6692b4a7802SBaban Kenkre 	int		dscount = 0;
6702b4a7802SBaban Kenkre 	int		timeoutsecs = ADUTILS_LDAP_OPEN_TIMEOUT;
6712b4a7802SBaban Kenkre 
6722b4a7802SBaban Kenkre retry:
6732b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&adhostlock);
6742b4a7802SBaban Kenkre 
6752b4a7802SBaban Kenkre 	if (host_head == NULL) {
6762b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&adhostlock);
6772b4a7802SBaban Kenkre 		goto out;
6782b4a7802SBaban Kenkre 	}
6792b4a7802SBaban Kenkre 
6802b4a7802SBaban Kenkre 	if (dscount == 0) {
6812b4a7802SBaban Kenkre 		/*
6822b4a7802SBaban Kenkre 		 * First try: count the number of DSes.
6832b4a7802SBaban Kenkre 		 *
6842b4a7802SBaban Kenkre 		 * Integer overflow is not an issue -- we can't have so many
6852b4a7802SBaban Kenkre 		 * DSes because they won't fit even DNS over TCP, and SMF
6862b4a7802SBaban Kenkre 		 * shouldn't let you set so many.
6872b4a7802SBaban Kenkre 		 */
6882b4a7802SBaban Kenkre 		for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) {
6892b4a7802SBaban Kenkre 			if (adh->owner == ad)
6902b4a7802SBaban Kenkre 				dscount++;
6912b4a7802SBaban Kenkre 		}
6922b4a7802SBaban Kenkre 
6932b4a7802SBaban Kenkre 		if (dscount == 0) {
6942b4a7802SBaban Kenkre 			(void) pthread_mutex_unlock(&adhostlock);
6952b4a7802SBaban Kenkre 			goto out;
6962b4a7802SBaban Kenkre 		}
6972b4a7802SBaban Kenkre 
6982b4a7802SBaban Kenkre 		tries = dscount * 3;	/* three tries per-ds */
6992b4a7802SBaban Kenkre 
7002b4a7802SBaban Kenkre 		/*
7012b4a7802SBaban Kenkre 		 * Begin round-robin at the next DS in the list after the last
7022b4a7802SBaban Kenkre 		 * one that we had a connection to, else start with the first
7032b4a7802SBaban Kenkre 		 * DS in the list.
7042b4a7802SBaban Kenkre 		 */
7052b4a7802SBaban Kenkre 		adh = ad->last_adh;
7062b4a7802SBaban Kenkre 	}
7072b4a7802SBaban Kenkre 
7082b4a7802SBaban Kenkre 	/*
7092b4a7802SBaban Kenkre 	 * Round-robin -- pick the next one on the list; if the list
7102b4a7802SBaban Kenkre 	 * changes on us, no big deal, we'll just potentially go
7112b4a7802SBaban Kenkre 	 * around the wrong number of times.
7122b4a7802SBaban Kenkre 	 */
7132b4a7802SBaban Kenkre 	for (;;) {
7144d61c878SJulian Pullen 		if (adh != NULL && adh->owner == ad && adh->ld != NULL &&
7154d61c878SJulian Pullen 		    !adh->dead)
7162b4a7802SBaban Kenkre 			break;
7172b4a7802SBaban Kenkre 		if (adh == NULL || (adh = adh->next) == NULL)
7182b4a7802SBaban Kenkre 			adh = host_head;
7192b4a7802SBaban Kenkre 		if (adh->owner == ad)
7202b4a7802SBaban Kenkre 			break;
7212b4a7802SBaban Kenkre 	}
7222b4a7802SBaban Kenkre 
7232b4a7802SBaban Kenkre 	ad->last_adh = adh;
7242b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&adhostlock);
7252b4a7802SBaban Kenkre 
7262b4a7802SBaban Kenkre 	/* Found suitable DS, open it if not already opened */
7272b4a7802SBaban Kenkre 	if (open_conn(adh, timeoutsecs))
7282b4a7802SBaban Kenkre 		return (adh);
7292b4a7802SBaban Kenkre 
7302b4a7802SBaban Kenkre 	tries--;
7312b4a7802SBaban Kenkre 	if ((tries % dscount) == 0)
7322b4a7802SBaban Kenkre 		timeoutsecs *= 2;
7332b4a7802SBaban Kenkre 	if (tries > 0)
7342b4a7802SBaban Kenkre 		goto retry;
7352b4a7802SBaban Kenkre 
7362b4a7802SBaban Kenkre out:
7377a8a68f5SJulian Pullen 	logger(LOG_NOTICE, "Couldn't open an LDAP connection to any global "
7382b4a7802SBaban Kenkre 	    "catalog server!");
7392b4a7802SBaban Kenkre 	return (NULL);
7402b4a7802SBaban Kenkre }
7412b4a7802SBaban Kenkre 
7422b4a7802SBaban Kenkre static
7432b4a7802SBaban Kenkre void
release_conn(adutils_host_t * adh)7442b4a7802SBaban Kenkre release_conn(adutils_host_t *adh)
7452b4a7802SBaban Kenkre {
7462b4a7802SBaban Kenkre 	int delete = 0;
7472b4a7802SBaban Kenkre 
7482b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&adh->lock);
7492b4a7802SBaban Kenkre 	if (atomic_dec_32_nv(&adh->ref) == 0) {
7502b4a7802SBaban Kenkre 		if (adh->owner == NULL)
7512b4a7802SBaban Kenkre 			delete = 1;
7522b4a7802SBaban Kenkre 		adh->idletime = time(NULL);
7532b4a7802SBaban Kenkre 	}
7542b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&adh->lock);
7552b4a7802SBaban Kenkre 
7562b4a7802SBaban Kenkre 	/* Free this host if its owner no longer exists. */
7572b4a7802SBaban Kenkre 	if (delete) {
7582b4a7802SBaban Kenkre 		(void) pthread_mutex_lock(&adhostlock);
7592b4a7802SBaban Kenkre 		delete_ds(NULL, adh->host, adh->port);
7602b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&adhostlock);
7612b4a7802SBaban Kenkre 	}
7622b4a7802SBaban Kenkre }
7632b4a7802SBaban Kenkre 
7642b4a7802SBaban Kenkre /*
7652b4a7802SBaban Kenkre  * Create a adutils_host_t, populate it and add it to the list of hosts.
7662b4a7802SBaban Kenkre  */
7672b4a7802SBaban Kenkre adutils_rc
adutils_add_ds(adutils_ad_t * ad,const char * host,int port)7682b4a7802SBaban Kenkre adutils_add_ds(adutils_ad_t *ad, const char *host, int port)
7692b4a7802SBaban Kenkre {
7702b4a7802SBaban Kenkre 	adutils_host_t	*p;
7712b4a7802SBaban Kenkre 	adutils_host_t	*new = NULL;
7722b4a7802SBaban Kenkre 	int		ret;
7732b4a7802SBaban Kenkre 	adutils_rc	rc;
7742b4a7802SBaban Kenkre 
7752b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&adhostlock);
7762b4a7802SBaban Kenkre 	for (p = host_head; p != NULL; p = p->next) {
7772b4a7802SBaban Kenkre 		if (p->owner != ad)
7782b4a7802SBaban Kenkre 			continue;
7792b4a7802SBaban Kenkre 
7802b4a7802SBaban Kenkre 		if (strcmp(host, p->host) == 0 && p->port == port) {
7812b4a7802SBaban Kenkre 			/* already added */
7822b4a7802SBaban Kenkre 			rc = ADUTILS_SUCCESS;
7832b4a7802SBaban Kenkre 			goto err;
7842b4a7802SBaban Kenkre 		}
7852b4a7802SBaban Kenkre 	}
7862b4a7802SBaban Kenkre 
7872b4a7802SBaban Kenkre 	rc = ADUTILS_ERR_MEMORY;
7882b4a7802SBaban Kenkre 
7892b4a7802SBaban Kenkre 	/* add new entry */
7902b4a7802SBaban Kenkre 	new = (adutils_host_t *)calloc(1, sizeof (*new));
7912b4a7802SBaban Kenkre 	if (new == NULL)
7922b4a7802SBaban Kenkre 		goto err;
7932b4a7802SBaban Kenkre 	new->owner = ad;
7942b4a7802SBaban Kenkre 	new->port = port;
7952b4a7802SBaban Kenkre 	new->dead = 0;
7962b4a7802SBaban Kenkre 	new->max_requests = 80;
7972b4a7802SBaban Kenkre 	new->num_requests = 0;
7982b4a7802SBaban Kenkre 	if ((new->host = strdup(host)) == NULL)
7992b4a7802SBaban Kenkre 		goto err;
8002b4a7802SBaban Kenkre 	new->saslflags = LDAP_SASL_INTERACTIVE;
8012b4a7802SBaban Kenkre 	new->saslmech = "GSSAPI";
8022b4a7802SBaban Kenkre 
8032b4a7802SBaban Kenkre 	if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) {
8042b4a7802SBaban Kenkre 		free(new->host);
8052b4a7802SBaban Kenkre 		new->host = NULL;
8062b4a7802SBaban Kenkre 		errno = ret;
8072b4a7802SBaban Kenkre 		rc = ADUTILS_ERR_INTERNAL;
8082b4a7802SBaban Kenkre 		goto err;
8092b4a7802SBaban Kenkre 	}
8102b4a7802SBaban Kenkre 
8112b4a7802SBaban Kenkre 	/* link in */
8122b4a7802SBaban Kenkre 	rc = ADUTILS_SUCCESS;
8132b4a7802SBaban Kenkre 	new->next = host_head;
8142b4a7802SBaban Kenkre 	host_head = new;
8152b4a7802SBaban Kenkre 
8162b4a7802SBaban Kenkre err:
8172b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&adhostlock);
8182b4a7802SBaban Kenkre 
8192b4a7802SBaban Kenkre 	if (rc != 0 && new != NULL) {
8202b4a7802SBaban Kenkre 		if (new->host != NULL) {
8212b4a7802SBaban Kenkre 			(void) pthread_mutex_destroy(&new->lock);
8222b4a7802SBaban Kenkre 			free(new->host);
8232b4a7802SBaban Kenkre 		}
8242b4a7802SBaban Kenkre 		free(new);
8252b4a7802SBaban Kenkre 	}
8262b4a7802SBaban Kenkre 
8272b4a7802SBaban Kenkre 	return (rc);
8282b4a7802SBaban Kenkre }
8292b4a7802SBaban Kenkre 
8302b4a7802SBaban Kenkre /*
8312b4a7802SBaban Kenkre  * Free a DS configuration.
8322b4a7802SBaban Kenkre  * Caller must lock the adhostlock mutex
8332b4a7802SBaban Kenkre  */
8342b4a7802SBaban Kenkre static
8352b4a7802SBaban Kenkre void
delete_ds(adutils_ad_t * ad,const char * host,int port)8362b4a7802SBaban Kenkre delete_ds(adutils_ad_t *ad, const char *host, int port)
8372b4a7802SBaban Kenkre {
8382b4a7802SBaban Kenkre 	adutils_host_t	**p, *q;
8392b4a7802SBaban Kenkre 
8402b4a7802SBaban Kenkre 	for (p = &host_head; *p != NULL; p = &((*p)->next)) {
8412b4a7802SBaban Kenkre 		if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 ||
8422b4a7802SBaban Kenkre 		    (*p)->port != port)
8432b4a7802SBaban Kenkre 			continue;
8442b4a7802SBaban Kenkre 		/* found */
8452b4a7802SBaban Kenkre 
8462b4a7802SBaban Kenkre 		(void) pthread_mutex_lock(&((*p)->lock));
8472b4a7802SBaban Kenkre 		if ((*p)->ref > 0) {
8482b4a7802SBaban Kenkre 			/*
8492b4a7802SBaban Kenkre 			 * Still in use. Set its owner to NULL so
8502b4a7802SBaban Kenkre 			 * that it can be freed when its ref count
8512b4a7802SBaban Kenkre 			 * becomes 0.
8522b4a7802SBaban Kenkre 			 */
8532b4a7802SBaban Kenkre 			(*p)->owner = NULL;
8542b4a7802SBaban Kenkre 			(void) pthread_mutex_unlock(&((*p)->lock));
8552b4a7802SBaban Kenkre 			break;
8562b4a7802SBaban Kenkre 		}
8572b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&((*p)->lock));
8582b4a7802SBaban Kenkre 
8592b4a7802SBaban Kenkre 		q = *p;
8602b4a7802SBaban Kenkre 		*p = (*p)->next;
8612b4a7802SBaban Kenkre 
8622b4a7802SBaban Kenkre 		(void) pthread_mutex_destroy(&q->lock);
8632b4a7802SBaban Kenkre 
8642b4a7802SBaban Kenkre 		if (q->ld)
8652b4a7802SBaban Kenkre 			(void) ldap_unbind(q->ld);
8662b4a7802SBaban Kenkre 		if (q->host)
8672b4a7802SBaban Kenkre 			free(q->host);
8682b4a7802SBaban Kenkre 		free(q);
8692b4a7802SBaban Kenkre 		break;
8702b4a7802SBaban Kenkre 	}
8712b4a7802SBaban Kenkre 
8722b4a7802SBaban Kenkre }
8734d61c878SJulian Pullen /*
8744d61c878SJulian Pullen  * Add known domain name and domain SID to AD configuration.
8754d61c878SJulian Pullen  */
8764d61c878SJulian Pullen 
8774d61c878SJulian Pullen adutils_rc
adutils_add_domain(adutils_ad_t * ad,const char * domain,const char * sid)8784d61c878SJulian Pullen adutils_add_domain(adutils_ad_t *ad, const char *domain, const char *sid)
8794d61c878SJulian Pullen {
8804d61c878SJulian Pullen 	struct known_domain *new;
8814d61c878SJulian Pullen 	int num = ad->num_known_domains;
8824d61c878SJulian Pullen 
8834d61c878SJulian Pullen 	ad->num_known_domains++;
8844d61c878SJulian Pullen 	new = realloc(ad->known_domains,
8854d61c878SJulian Pullen 	    sizeof (struct known_domain) * ad->num_known_domains);
8864d61c878SJulian Pullen 	if (new != NULL) {
8874d61c878SJulian Pullen 		ad->known_domains = new;
8884d61c878SJulian Pullen 		(void) strlcpy(ad->known_domains[num].name, domain,
8894d61c878SJulian Pullen 		    sizeof (ad->known_domains[num].name));
8904d61c878SJulian Pullen 		(void) strlcpy(ad->known_domains[num].sid, sid,
8914d61c878SJulian Pullen 		    sizeof (ad->known_domains[num].sid));
8924d61c878SJulian Pullen 		return (ADUTILS_SUCCESS);
8934d61c878SJulian Pullen 	} else {
8944d61c878SJulian Pullen 		if (ad->known_domains != NULL) {
8954d61c878SJulian Pullen 			free(ad->known_domains);
8964d61c878SJulian Pullen 			ad->known_domains = NULL;
8974d61c878SJulian Pullen 		}
8984d61c878SJulian Pullen 		ad->num_known_domains = 0;
8994d61c878SJulian Pullen 		return (ADUTILS_ERR_MEMORY);
9004d61c878SJulian Pullen 	}
9014d61c878SJulian Pullen }
9024d61c878SJulian Pullen 
9034d61c878SJulian Pullen 
9044d61c878SJulian Pullen /*
9054d61c878SJulian Pullen  * Check that this AD supports this domain.
9064d61c878SJulian Pullen  * If there are no known domains assume that the
9074d61c878SJulian Pullen  * domain is supported by this AD.
9084d61c878SJulian Pullen  *
9094d61c878SJulian Pullen  * Returns 1 if this domain is supported by this AD
9104d61c878SJulian Pullen  * else returns 0;
9114d61c878SJulian Pullen  */
9124d61c878SJulian Pullen 
9134d61c878SJulian Pullen int
adutils_lookup_check_domain(adutils_query_state_t * qs,const char * domain)9144d61c878SJulian Pullen adutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain)
9154d61c878SJulian Pullen {
9164d61c878SJulian Pullen 	adutils_ad_t *ad = qs->qadh->owner;
9171fcced4cSJordan Brown 	int i;
9184d61c878SJulian Pullen 
9194d61c878SJulian Pullen 	for (i = 0; i < ad->num_known_domains; i++) {
9201fcced4cSJordan Brown 		if (domain_eq(domain, ad->known_domains[i].name))
9214d61c878SJulian Pullen 			return (1);
9224d61c878SJulian Pullen 	}
9234d61c878SJulian Pullen 
9244d61c878SJulian Pullen 	return ((i == 0) ? 1 : 0);
9254d61c878SJulian Pullen }
9264d61c878SJulian Pullen 
9274d61c878SJulian Pullen 
9284d61c878SJulian Pullen /*
9294d61c878SJulian Pullen  * Check that this AD supports the SID prefix.
9304d61c878SJulian Pullen  * The SID prefix should match the domain SID.
9314d61c878SJulian Pullen  * If there are no known domains assume that the
9324d61c878SJulian Pullen  * SID prefix is supported by this AD.
9334d61c878SJulian Pullen  *
9344d61c878SJulian Pullen  * Returns 1 if this sid prefix is supported by this AD
9354d61c878SJulian Pullen  * else returns 0;
9364d61c878SJulian Pullen  */
9374d61c878SJulian Pullen 
9384d61c878SJulian Pullen int
adutils_lookup_check_sid_prefix(adutils_query_state_t * qs,const char * sid)9394d61c878SJulian Pullen adutils_lookup_check_sid_prefix(adutils_query_state_t *qs, const char *sid)
9404d61c878SJulian Pullen {
9414d61c878SJulian Pullen 	adutils_ad_t *ad = qs->qadh->owner;
9424d61c878SJulian Pullen 	int i;
9434d61c878SJulian Pullen 
9444d61c878SJulian Pullen 
9454d61c878SJulian Pullen 	for (i = 0; i < ad->num_known_domains; i++) {
9464d61c878SJulian Pullen 		if (strcmp(sid, ad->known_domains[i].sid) == 0)
9474d61c878SJulian Pullen 			return (1);
9484d61c878SJulian Pullen 	}
9494d61c878SJulian Pullen 
9504d61c878SJulian Pullen 	return ((i == 0) ? 1 : 0);
9514d61c878SJulian Pullen }
9524d61c878SJulian Pullen 
9532b4a7802SBaban Kenkre 
9542b4a7802SBaban Kenkre adutils_rc
adutils_lookup_batch_start(adutils_ad_t * ad,int nqueries,adutils_ldap_res_search_cb ldap_res_search_cb,void * ldap_res_search_argp,adutils_query_state_t ** state)9552b4a7802SBaban Kenkre adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries,
956*67fccfffSMatt Barden     adutils_ldap_res_search_cb ldap_res_search_cb,
957*67fccfffSMatt Barden     void *ldap_res_search_argp,
958*67fccfffSMatt Barden     adutils_query_state_t **state)
9592b4a7802SBaban Kenkre {
9602b4a7802SBaban Kenkre 	adutils_query_state_t	*new_state;
9612b4a7802SBaban Kenkre 	adutils_host_t		*adh = NULL;
9622b4a7802SBaban Kenkre 
9632b4a7802SBaban Kenkre 	if (ad == NULL)
9642b4a7802SBaban Kenkre 		return (ADUTILS_ERR_INTERNAL);
9652b4a7802SBaban Kenkre 
9662b4a7802SBaban Kenkre 	*state = NULL;
9672b4a7802SBaban Kenkre 	adh = get_conn(ad);
9682b4a7802SBaban Kenkre 	if (adh == NULL)
9692b4a7802SBaban Kenkre 		return (ADUTILS_ERR_RETRIABLE_NET_ERR);
9702b4a7802SBaban Kenkre 
9712b4a7802SBaban Kenkre 	new_state = calloc(1, sizeof (adutils_query_state_t) +
9722b4a7802SBaban Kenkre 	    (nqueries - 1) * sizeof (adutils_q_t));
9732b4a7802SBaban Kenkre 	if (new_state == NULL)
9742b4a7802SBaban Kenkre 		return (ADUTILS_ERR_MEMORY);
9752b4a7802SBaban Kenkre 
9762b4a7802SBaban Kenkre 	new_state->ref_cnt = 1;
9772b4a7802SBaban Kenkre 	new_state->qadh = adh;
9784d61c878SJulian Pullen 	new_state->qsize = nqueries;
9792b4a7802SBaban Kenkre 	new_state->qadh_gen = adh->generation;
9804d61c878SJulian Pullen 	new_state->qcount = 0;
9812b4a7802SBaban Kenkre 	new_state->ldap_res_search_cb = ldap_res_search_cb;
9822b4a7802SBaban Kenkre 	new_state->ldap_res_search_argp = ldap_res_search_argp;
9832b4a7802SBaban Kenkre 	(void) pthread_cond_init(&new_state->cv, NULL);
9842b4a7802SBaban Kenkre 
9852b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&qstatelock);
9862b4a7802SBaban Kenkre 	new_state->next = qstatehead;
9872b4a7802SBaban Kenkre 	qstatehead = new_state;
9882b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&qstatelock);
9892b4a7802SBaban Kenkre 	*state = new_state;
9902b4a7802SBaban Kenkre 
9912b4a7802SBaban Kenkre 	return (ADUTILS_SUCCESS);
9922b4a7802SBaban Kenkre }
9932b4a7802SBaban Kenkre 
9942b4a7802SBaban Kenkre /*
9952b4a7802SBaban Kenkre  * Find the adutils_query_state_t to which a given LDAP result msgid on a
9962b4a7802SBaban Kenkre  * given connection belongs. This routine increaments the reference count
9972b4a7802SBaban Kenkre  * so that the object can not be freed. adutils_lookup_batch_unlock()
9982b4a7802SBaban Kenkre  * must be called to decreament the reference count.
9992b4a7802SBaban Kenkre  */
10002b4a7802SBaban Kenkre static
10012b4a7802SBaban Kenkre int
msgid2query(adutils_host_t * adh,int msgid,adutils_query_state_t ** state,int * qid)10022b4a7802SBaban Kenkre msgid2query(adutils_host_t *adh, int msgid,
1003*67fccfffSMatt Barden     adutils_query_state_t **state, int *qid)
10042b4a7802SBaban Kenkre {
10052b4a7802SBaban Kenkre 	adutils_query_state_t	*p;
10062b4a7802SBaban Kenkre 	int			i;
10072b4a7802SBaban Kenkre 	int			ret;
10082b4a7802SBaban Kenkre 
10092b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&qstatelock);
10102b4a7802SBaban Kenkre 	for (p = qstatehead; p != NULL; p = p->next) {
10112b4a7802SBaban Kenkre 		if (p->qadh != adh || adh->generation != p->qadh_gen)
10122b4a7802SBaban Kenkre 			continue;
10132b4a7802SBaban Kenkre 		for (i = 0; i < p->qcount; i++) {
10142b4a7802SBaban Kenkre 			if ((p->queries[i]).msgid == msgid) {
10152b4a7802SBaban Kenkre 				if (!p->qdead) {
10162b4a7802SBaban Kenkre 					p->ref_cnt++;
10172b4a7802SBaban Kenkre 					*state = p;
10182b4a7802SBaban Kenkre 					*qid = i;
10192b4a7802SBaban Kenkre 					ret = 1;
10202b4a7802SBaban Kenkre 				} else
10212b4a7802SBaban Kenkre 					ret = 0;
10222b4a7802SBaban Kenkre 				(void) pthread_mutex_unlock(&qstatelock);
10232b4a7802SBaban Kenkre 				return (ret);
10242b4a7802SBaban Kenkre 			}
10252b4a7802SBaban Kenkre 		}
10262b4a7802SBaban Kenkre 	}
10272b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&qstatelock);
10282b4a7802SBaban Kenkre 	return (0);
10292b4a7802SBaban Kenkre }
10302b4a7802SBaban Kenkre 
10312b4a7802SBaban Kenkre static
10322b4a7802SBaban Kenkre int
check_for_binary_attrs(const char * attr)10332b4a7802SBaban Kenkre check_for_binary_attrs(const char *attr)
10342b4a7802SBaban Kenkre {
10352b4a7802SBaban Kenkre 	int i;
10362b4a7802SBaban Kenkre 	for (i = 0; binattrs[i].name != NULL; i++) {
10372b4a7802SBaban Kenkre 		if (strcasecmp(binattrs[i].name, attr) == 0)
10382b4a7802SBaban Kenkre 			return (i);
10392b4a7802SBaban Kenkre 	}
10402b4a7802SBaban Kenkre 	return (-1);
10412b4a7802SBaban Kenkre }
10422b4a7802SBaban Kenkre 
10432b4a7802SBaban Kenkre static
10442b4a7802SBaban Kenkre void
free_entry(adutils_entry_t * entry)10452b4a7802SBaban Kenkre free_entry(adutils_entry_t *entry)
10462b4a7802SBaban Kenkre {
10472b4a7802SBaban Kenkre 	int		i, j;
10482b4a7802SBaban Kenkre 	adutils_attr_t	*ap;
10492b4a7802SBaban Kenkre 
10502b4a7802SBaban Kenkre 	if (entry == NULL)
10512b4a7802SBaban Kenkre 		return;
10522b4a7802SBaban Kenkre 	if (entry->attr_nvpairs == NULL) {
10532b4a7802SBaban Kenkre 		free(entry);
10542b4a7802SBaban Kenkre 		return;
10552b4a7802SBaban Kenkre 	}
10562b4a7802SBaban Kenkre 	for (i = 0; i < entry->num_nvpairs; i++) {
10572b4a7802SBaban Kenkre 		ap = &entry->attr_nvpairs[i];
10582b4a7802SBaban Kenkre 		if (ap->attr_name == NULL) {
10592b4a7802SBaban Kenkre 			ldap_value_free(ap->attr_values);
10602b4a7802SBaban Kenkre 			continue;
10612b4a7802SBaban Kenkre 		}
10622b4a7802SBaban Kenkre 		if (check_for_binary_attrs(ap->attr_name) >= 0) {
10632b4a7802SBaban Kenkre 			free(ap->attr_name);
10642b4a7802SBaban Kenkre 			if (ap->attr_values == NULL)
10652b4a7802SBaban Kenkre 				continue;
10662b4a7802SBaban Kenkre 			for (j = 0; j < ap->num_values; j++)
10672b4a7802SBaban Kenkre 				free(ap->attr_values[j]);
10682b4a7802SBaban Kenkre 			free(ap->attr_values);
10692b4a7802SBaban Kenkre 		} else if (strcasecmp(ap->attr_name, "dn") == 0) {
10702b4a7802SBaban Kenkre 			free(ap->attr_name);
10712b4a7802SBaban Kenkre 			ldap_memfree(ap->attr_values[0]);
10722b4a7802SBaban Kenkre 			free(ap->attr_values);
10732b4a7802SBaban Kenkre 		} else {
10742b4a7802SBaban Kenkre 			free(ap->attr_name);
10752b4a7802SBaban Kenkre 			ldap_value_free(ap->attr_values);
10762b4a7802SBaban Kenkre 		}
10772b4a7802SBaban Kenkre 	}
10782b4a7802SBaban Kenkre 	free(entry->attr_nvpairs);
10792b4a7802SBaban Kenkre 	free(entry);
10802b4a7802SBaban Kenkre }
10812b4a7802SBaban Kenkre 
10822b4a7802SBaban Kenkre void
adutils_freeresult(adutils_result_t ** result)10832b4a7802SBaban Kenkre adutils_freeresult(adutils_result_t **result)
10842b4a7802SBaban Kenkre {
10852b4a7802SBaban Kenkre 	adutils_entry_t	*e, *next;
10862b4a7802SBaban Kenkre 
10872b4a7802SBaban Kenkre 	if (result == NULL || *result == NULL)
10882b4a7802SBaban Kenkre 		return;
10892b4a7802SBaban Kenkre 	if ((*result)->entries == NULL) {
10902b4a7802SBaban Kenkre 		free(*result);
10912b4a7802SBaban Kenkre 		*result = NULL;
10922b4a7802SBaban Kenkre 		return;
10932b4a7802SBaban Kenkre 	}
10942b4a7802SBaban Kenkre 	for (e = (*result)->entries; e != NULL; e = next) {
10952b4a7802SBaban Kenkre 		next = e->next;
10962b4a7802SBaban Kenkre 		free_entry(e);
10972b4a7802SBaban Kenkre 	}
10982b4a7802SBaban Kenkre 	free(*result);
10992b4a7802SBaban Kenkre 	*result = NULL;
11002b4a7802SBaban Kenkre }
11012b4a7802SBaban Kenkre 
11022b4a7802SBaban Kenkre const adutils_entry_t *
adutils_getfirstentry(adutils_result_t * result)11032b4a7802SBaban Kenkre adutils_getfirstentry(adutils_result_t *result)
11042b4a7802SBaban Kenkre {
11052b4a7802SBaban Kenkre 	if (result != NULL)
11062b4a7802SBaban Kenkre 		return (result->entries);
11072b4a7802SBaban Kenkre 	return (NULL);
11082b4a7802SBaban Kenkre }
11092b4a7802SBaban Kenkre 
11102b4a7802SBaban Kenkre 
11112b4a7802SBaban Kenkre char **
adutils_getattr(const adutils_entry_t * entry,const char * attrname)11122b4a7802SBaban Kenkre adutils_getattr(const adutils_entry_t *entry, const char *attrname)
11132b4a7802SBaban Kenkre {
11142b4a7802SBaban Kenkre 	int		i;
11152b4a7802SBaban Kenkre 	adutils_attr_t	*ap;
11162b4a7802SBaban Kenkre 
11172b4a7802SBaban Kenkre 	if (entry == NULL || entry->attr_nvpairs == NULL)
11182b4a7802SBaban Kenkre 		return (NULL);
11192b4a7802SBaban Kenkre 	for (i = 0; i < entry->num_nvpairs; i++) {
11202b4a7802SBaban Kenkre 		ap = &entry->attr_nvpairs[i];
11212b4a7802SBaban Kenkre 		if (ap->attr_name != NULL &&
11222b4a7802SBaban Kenkre 		    strcasecmp(ap->attr_name, attrname) == 0)
11232b4a7802SBaban Kenkre 			return (ap->attr_values);
11242b4a7802SBaban Kenkre 	}
11252b4a7802SBaban Kenkre 	return (NULL);
11262b4a7802SBaban Kenkre }
11272b4a7802SBaban Kenkre 
11282b4a7802SBaban Kenkre 
11292b4a7802SBaban Kenkre /*
11302b4a7802SBaban Kenkre  * Queue LDAP result for the given query.
11312b4a7802SBaban Kenkre  *
11322b4a7802SBaban Kenkre  * Return values:
11332b4a7802SBaban Kenkre  *  0 success
11342b4a7802SBaban Kenkre  * -1 ignore result
11352b4a7802SBaban Kenkre  * -2 error
11362b4a7802SBaban Kenkre  */
11372b4a7802SBaban Kenkre static
11382b4a7802SBaban Kenkre int
make_entry(adutils_q_t * q,adutils_host_t * adh,LDAPMessage * search_res,adutils_entry_t ** entry)11392b4a7802SBaban Kenkre make_entry(adutils_q_t *q, adutils_host_t *adh, LDAPMessage *search_res,
1140*67fccfffSMatt Barden     adutils_entry_t **entry)
11412b4a7802SBaban Kenkre {
11422b4a7802SBaban Kenkre 	BerElement	*ber = NULL;
11432b4a7802SBaban Kenkre 	BerValue	**bvalues = NULL;
11442b4a7802SBaban Kenkre 	char		**strvalues;
11452b4a7802SBaban Kenkre 	char		*attr = NULL, *dn = NULL, *domain = NULL;
11462b4a7802SBaban Kenkre 	adutils_entry_t	*ep;
11472b4a7802SBaban Kenkre 	adutils_attr_t	*ap;
11481fcced4cSJordan Brown 	int		i, j, b, ret = -2;
11492b4a7802SBaban Kenkre 
11502b4a7802SBaban Kenkre 	*entry = NULL;
11512b4a7802SBaban Kenkre 
11522b4a7802SBaban Kenkre 	/* Check that this is the domain that we were looking for */
11532b4a7802SBaban Kenkre 	if ((dn = ldap_get_dn(adh->ld, search_res)) == NULL)
11542b4a7802SBaban Kenkre 		return (-2);
11552b4a7802SBaban Kenkre 	if ((domain = adutils_dn2dns(dn)) == NULL) {
11562b4a7802SBaban Kenkre 		ldap_memfree(dn);
11572b4a7802SBaban Kenkre 		return (-2);
11582b4a7802SBaban Kenkre 	}
11592b4a7802SBaban Kenkre 	if (q->edomain != NULL) {
11601fcced4cSJordan Brown 		if (!domain_eq(q->edomain, domain)) {
11612b4a7802SBaban Kenkre 			ldap_memfree(dn);
11622b4a7802SBaban Kenkre 			free(domain);
11632b4a7802SBaban Kenkre 			return (-1);
11642b4a7802SBaban Kenkre 		}
11652b4a7802SBaban Kenkre 	}
11662b4a7802SBaban Kenkre 	free(domain);
11672b4a7802SBaban Kenkre 
11682b4a7802SBaban Kenkre 	/* Allocate memory for the entry */
11692b4a7802SBaban Kenkre 	if ((ep = calloc(1, sizeof (*ep))) == NULL)
11702b4a7802SBaban Kenkre 		goto out;
11712b4a7802SBaban Kenkre 
11722b4a7802SBaban Kenkre 	/* For 'dn' */
11732b4a7802SBaban Kenkre 	ep->num_nvpairs = 1;
11742b4a7802SBaban Kenkre 
11752b4a7802SBaban Kenkre 	/* Count the number of name-value pairs for this entry */
11762b4a7802SBaban Kenkre 	for (attr = ldap_first_attribute(adh->ld, search_res, &ber);
11772b4a7802SBaban Kenkre 	    attr != NULL;
11782b4a7802SBaban Kenkre 	    attr = ldap_next_attribute(adh->ld, search_res, ber)) {
11792b4a7802SBaban Kenkre 		ep->num_nvpairs++;
11802b4a7802SBaban Kenkre 		ldap_memfree(attr);
11812b4a7802SBaban Kenkre 	}
11822b4a7802SBaban Kenkre 	ber_free(ber, 0);
11832b4a7802SBaban Kenkre 	ber = NULL;
11842b4a7802SBaban Kenkre 
11852b4a7802SBaban Kenkre 	/* Allocate array for the attribute name-value pairs */
11862b4a7802SBaban Kenkre 	ep->attr_nvpairs = calloc(ep->num_nvpairs, sizeof (*ep->attr_nvpairs));
11872b4a7802SBaban Kenkre 	if (ep->attr_nvpairs == NULL) {
11882b4a7802SBaban Kenkre 		ep->num_nvpairs = 0;
11892b4a7802SBaban Kenkre 		goto out;
11902b4a7802SBaban Kenkre 	}
11912b4a7802SBaban Kenkre 
11922b4a7802SBaban Kenkre 	/* For dn */
11932b4a7802SBaban Kenkre 	ap = &ep->attr_nvpairs[0];
11942b4a7802SBaban Kenkre 	if ((ap->attr_name = strdup("dn")) == NULL)
11952b4a7802SBaban Kenkre 		goto out;
11962b4a7802SBaban Kenkre 	ap->num_values = 1;
11972b4a7802SBaban Kenkre 	ap->attr_values = calloc(ap->num_values, sizeof (*ap->attr_values));
11982b4a7802SBaban Kenkre 	if (ap->attr_values == NULL) {
11992b4a7802SBaban Kenkre 		ap->num_values = 0;
12002b4a7802SBaban Kenkre 		goto out;
12012b4a7802SBaban Kenkre 	}
12022b4a7802SBaban Kenkre 	ap->attr_values[0] = dn;
12032b4a7802SBaban Kenkre 	dn = NULL;
12042b4a7802SBaban Kenkre 
12052b4a7802SBaban Kenkre 	for (attr = ldap_first_attribute(adh->ld, search_res, &ber), i = 1;
12062b4a7802SBaban Kenkre 	    attr != NULL;
12072b4a7802SBaban Kenkre 	    ldap_memfree(attr), i++,
12082b4a7802SBaban Kenkre 	    attr = ldap_next_attribute(adh->ld, search_res, ber)) {
12092b4a7802SBaban Kenkre 		ap = &ep->attr_nvpairs[i];
12102b4a7802SBaban Kenkre 		if ((ap->attr_name = strdup(attr)) == NULL)
12112b4a7802SBaban Kenkre 			goto out;
12122b4a7802SBaban Kenkre 
12132b4a7802SBaban Kenkre 		if ((b = check_for_binary_attrs(attr)) >= 0) {
12142b4a7802SBaban Kenkre 			bvalues =
12152b4a7802SBaban Kenkre 			    ldap_get_values_len(adh->ld, search_res, attr);
12162b4a7802SBaban Kenkre 			if (bvalues == NULL)
12172b4a7802SBaban Kenkre 				continue;
12182b4a7802SBaban Kenkre 			ap->num_values = ldap_count_values_len(bvalues);
12192b4a7802SBaban Kenkre 			if (ap->num_values == 0) {
12202b4a7802SBaban Kenkre 				ldap_value_free_len(bvalues);
12212b4a7802SBaban Kenkre 				bvalues = NULL;
12222b4a7802SBaban Kenkre 				continue;
12232b4a7802SBaban Kenkre 			}
12242b4a7802SBaban Kenkre 			ap->attr_values = calloc(ap->num_values,
12252b4a7802SBaban Kenkre 			    sizeof (*ap->attr_values));
12262b4a7802SBaban Kenkre 			if (ap->attr_values == NULL) {
12272b4a7802SBaban Kenkre 				ap->num_values = 0;
12282b4a7802SBaban Kenkre 				goto out;
12292b4a7802SBaban Kenkre 			}
12302b4a7802SBaban Kenkre 			for (j = 0; j < ap->num_values; j++) {
12312b4a7802SBaban Kenkre 				ap->attr_values[j] =
12322b4a7802SBaban Kenkre 				    binattrs[b].ber2str(bvalues[j]);
12332b4a7802SBaban Kenkre 				if (ap->attr_values[j] == NULL)
12342b4a7802SBaban Kenkre 					goto out;
12352b4a7802SBaban Kenkre 			}
12362b4a7802SBaban Kenkre 			ldap_value_free_len(bvalues);
12372b4a7802SBaban Kenkre 			bvalues = NULL;
12382b4a7802SBaban Kenkre 			continue;
12392b4a7802SBaban Kenkre 		}
12402b4a7802SBaban Kenkre 
12412b4a7802SBaban Kenkre 		strvalues = ldap_get_values(adh->ld, search_res, attr);
12422b4a7802SBaban Kenkre 		if (strvalues == NULL)
12432b4a7802SBaban Kenkre 			continue;
12442b4a7802SBaban Kenkre 		ap->num_values = ldap_count_values(strvalues);
12452b4a7802SBaban Kenkre 		if (ap->num_values == 0) {
12462b4a7802SBaban Kenkre 			ldap_value_free(strvalues);
12472b4a7802SBaban Kenkre 			continue;
12482b4a7802SBaban Kenkre 		}
12492b4a7802SBaban Kenkre 		ap->attr_values = strvalues;
12502b4a7802SBaban Kenkre 	}
12512b4a7802SBaban Kenkre 
12522b4a7802SBaban Kenkre 	ret = 0;
12532b4a7802SBaban Kenkre out:
12542b4a7802SBaban Kenkre 	ldap_memfree(attr);
12552b4a7802SBaban Kenkre 	ldap_memfree(dn);
12562b4a7802SBaban Kenkre 	ber_free(ber, 0);
12572b4a7802SBaban Kenkre 	ldap_value_free_len(bvalues);
12582b4a7802SBaban Kenkre 	if (ret < 0)
12592b4a7802SBaban Kenkre 		free_entry(ep);
12602b4a7802SBaban Kenkre 	else
12612b4a7802SBaban Kenkre 		*entry = ep;
12622b4a7802SBaban Kenkre 	return (ret);
12632b4a7802SBaban Kenkre }
12642b4a7802SBaban Kenkre 
12652b4a7802SBaban Kenkre /*
12662b4a7802SBaban Kenkre  * Put the search result onto the given adutils_q_t.
12672b4a7802SBaban Kenkre  * Returns:	  0 success
12682b4a7802SBaban Kenkre  *		< 0 error
12692b4a7802SBaban Kenkre  */
12702b4a7802SBaban Kenkre static
12712b4a7802SBaban Kenkre int
add_entry(adutils_host_t * adh,adutils_q_t * q,LDAPMessage * search_res)12722b4a7802SBaban Kenkre add_entry(adutils_host_t *adh, adutils_q_t *q, LDAPMessage *search_res)
12732b4a7802SBaban Kenkre {
12742b4a7802SBaban Kenkre 	int			ret = -1;
12752b4a7802SBaban Kenkre 	adutils_entry_t		*entry = NULL;
12762b4a7802SBaban Kenkre 	adutils_result_t	*res;
12772b4a7802SBaban Kenkre 
12782b4a7802SBaban Kenkre 	ret = make_entry(q, adh, search_res, &entry);
12792b4a7802SBaban Kenkre 	if (ret < -1) {
12802b4a7802SBaban Kenkre 		*q->rc = ADUTILS_ERR_MEMORY;
12812b4a7802SBaban Kenkre 		goto out;
12822b4a7802SBaban Kenkre 	} else if (ret == -1) {
12832b4a7802SBaban Kenkre 		/* ignore result */
12842b4a7802SBaban Kenkre 		goto out;
12852b4a7802SBaban Kenkre 	}
12862b4a7802SBaban Kenkre 	if (*q->result == NULL) {
12872b4a7802SBaban Kenkre 		res = calloc(1, sizeof (*res));
12882b4a7802SBaban Kenkre 		if (res == NULL) {
12892b4a7802SBaban Kenkre 			*q->rc = ADUTILS_ERR_MEMORY;
12902b4a7802SBaban Kenkre 			goto out;
12912b4a7802SBaban Kenkre 		}
12922b4a7802SBaban Kenkre 		res->num_entries = 1;
12932b4a7802SBaban Kenkre 		res->entries = entry;
12942b4a7802SBaban Kenkre 		*q->result = res;
12952b4a7802SBaban Kenkre 	} else {
12962b4a7802SBaban Kenkre 		res = *q->result;
12972b4a7802SBaban Kenkre 		entry->next = res->entries;
12982b4a7802SBaban Kenkre 		res->entries = entry;
12992b4a7802SBaban Kenkre 		res->num_entries++;
13002b4a7802SBaban Kenkre 	}
13012b4a7802SBaban Kenkre 	*q->rc = ADUTILS_SUCCESS;
13022b4a7802SBaban Kenkre 	entry = NULL;
13032b4a7802SBaban Kenkre 	ret = 0;
13042b4a7802SBaban Kenkre 
13052b4a7802SBaban Kenkre out:
13062b4a7802SBaban Kenkre 	free_entry(entry);
13072b4a7802SBaban Kenkre 	return (ret);
13082b4a7802SBaban Kenkre }
13092b4a7802SBaban Kenkre 
13102b4a7802SBaban Kenkre /*
13112b4a7802SBaban Kenkre  * Try to get a result; if there is one, find the corresponding
13122b4a7802SBaban Kenkre  * adutils_q_t and process the result.
13132b4a7802SBaban Kenkre  *
13142b4a7802SBaban Kenkre  * Returns:	0 success
13152b4a7802SBaban Kenkre  *		-1 error
13162b4a7802SBaban Kenkre  */
13172b4a7802SBaban Kenkre static
13182b4a7802SBaban Kenkre int
get_adobject_batch(adutils_host_t * adh,struct timeval * timeout)13192b4a7802SBaban Kenkre get_adobject_batch(adutils_host_t *adh, struct timeval *timeout)
13202b4a7802SBaban Kenkre {
13212b4a7802SBaban Kenkre 	adutils_query_state_t	*query_state;
13222b4a7802SBaban Kenkre 	LDAPMessage		*res = NULL;
13232b4a7802SBaban Kenkre 	int			rc, ret, msgid, qid;
13242b4a7802SBaban Kenkre 	adutils_q_t		*que;
13252b4a7802SBaban Kenkre 	int			num;
13262b4a7802SBaban Kenkre 
13272b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&adh->lock);
13282b4a7802SBaban Kenkre 	if (adh->dead || adh->num_requests == 0) {
13292b4a7802SBaban Kenkre 		ret = (adh->dead) ? -1 : -2;
13302b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&adh->lock);
13312b4a7802SBaban Kenkre 		return (ret);
13322b4a7802SBaban Kenkre 	}
13332b4a7802SBaban Kenkre 
13342b4a7802SBaban Kenkre 	/* Get one result */
13352b4a7802SBaban Kenkre 	rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, timeout, &res);
13362b4a7802SBaban Kenkre 	if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) ||
13372b4a7802SBaban Kenkre 	    rc < 0)
13382b4a7802SBaban Kenkre 		adh->dead = 1;
13392b4a7802SBaban Kenkre 
13402b4a7802SBaban Kenkre 	if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0)
13412b4a7802SBaban Kenkre 		adh->num_requests--;
13422b4a7802SBaban Kenkre 	if (adh->dead) {
13432b4a7802SBaban Kenkre 		num = adh->num_requests;
13442b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&adh->lock);
13457a8a68f5SJulian Pullen 		logger(LOG_DEBUG,
13462b4a7802SBaban Kenkre 		    "AD ldap_result error - %d queued requests", num);
13472b4a7802SBaban Kenkre 		return (-1);
13482b4a7802SBaban Kenkre 	}
13492b4a7802SBaban Kenkre 
13502b4a7802SBaban Kenkre 	switch (rc) {
13512b4a7802SBaban Kenkre 	case LDAP_RES_SEARCH_RESULT:
13522b4a7802SBaban Kenkre 		msgid = ldap_msgid(res);
13532b4a7802SBaban Kenkre 		if (msgid2query(adh, msgid, &query_state, &qid)) {
13542b4a7802SBaban Kenkre 			if (query_state->ldap_res_search_cb != NULL) {
13552b4a7802SBaban Kenkre 				/*
13562b4a7802SBaban Kenkre 				 * We use the caller-provided callback
13572b4a7802SBaban Kenkre 				 * to process the result.
13582b4a7802SBaban Kenkre 				 */
13592b4a7802SBaban Kenkre 				query_state->ldap_res_search_cb(
13602b4a7802SBaban Kenkre 				    adh->ld, &res, rc, qid,
13612b4a7802SBaban Kenkre 				    query_state->ldap_res_search_argp);
13622b4a7802SBaban Kenkre 				(void) pthread_mutex_unlock(&adh->lock);
13632b4a7802SBaban Kenkre 			} else {
13642b4a7802SBaban Kenkre 				/*
13652b4a7802SBaban Kenkre 				 * No callback. We fallback to our
13662b4a7802SBaban Kenkre 				 * default behaviour. All the entries
13672b4a7802SBaban Kenkre 				 * gotten from this search have been
13682b4a7802SBaban Kenkre 				 * added to the result list during
13692b4a7802SBaban Kenkre 				 * LDAP_RES_SEARCH_ENTRY (see below).
13702b4a7802SBaban Kenkre 				 * Here we set the return status to
13712b4a7802SBaban Kenkre 				 * notfound if the result is still empty.
13722b4a7802SBaban Kenkre 				 */
13732b4a7802SBaban Kenkre 				(void) pthread_mutex_unlock(&adh->lock);
13742b4a7802SBaban Kenkre 				que = &(query_state->queries[qid]);
13752b4a7802SBaban Kenkre 				if (*que->result == NULL)
13762b4a7802SBaban Kenkre 					*que->rc = ADUTILS_ERR_NOTFOUND;
13772b4a7802SBaban Kenkre 			}
13782b4a7802SBaban Kenkre 			atomic_dec_32(&query_state->qinflight);
13792b4a7802SBaban Kenkre 			adutils_lookup_batch_unlock(&query_state);
13802b4a7802SBaban Kenkre 		} else {
13812b4a7802SBaban Kenkre 			num = adh->num_requests;
13822b4a7802SBaban Kenkre 			(void) pthread_mutex_unlock(&adh->lock);
13837a8a68f5SJulian Pullen 			logger(LOG_DEBUG,
13842b4a7802SBaban Kenkre 			    "AD cannot find message ID (%d) "
13852b4a7802SBaban Kenkre 			    "- %d queued requests",
13862b4a7802SBaban Kenkre 			    msgid, num);
13872b4a7802SBaban Kenkre 		}
13882b4a7802SBaban Kenkre 		(void) ldap_msgfree(res);
13892b4a7802SBaban Kenkre 		ret = 0;
13902b4a7802SBaban Kenkre 		break;
13912b4a7802SBaban Kenkre 
13922b4a7802SBaban Kenkre 	case LDAP_RES_SEARCH_ENTRY:
13932b4a7802SBaban Kenkre 		msgid = ldap_msgid(res);
13942b4a7802SBaban Kenkre 		if (msgid2query(adh, msgid, &query_state, &qid)) {
13952b4a7802SBaban Kenkre 			if (query_state->ldap_res_search_cb != NULL) {
13962b4a7802SBaban Kenkre 				/*
13972b4a7802SBaban Kenkre 				 * We use the caller-provided callback
13982b4a7802SBaban Kenkre 				 * to process the entry.
13992b4a7802SBaban Kenkre 				 */
14002b4a7802SBaban Kenkre 				query_state->ldap_res_search_cb(
14012b4a7802SBaban Kenkre 				    adh->ld, &res, rc, qid,
14022b4a7802SBaban Kenkre 				    query_state->ldap_res_search_argp);
14032b4a7802SBaban Kenkre 				(void) pthread_mutex_unlock(&adh->lock);
14042b4a7802SBaban Kenkre 			} else {
14052b4a7802SBaban Kenkre 				/*
14062b4a7802SBaban Kenkre 				 * No callback. We fallback to our
14072b4a7802SBaban Kenkre 				 * default behaviour. This entry
14082b4a7802SBaban Kenkre 				 * will be added to the result list.
14092b4a7802SBaban Kenkre 				 */
14102b4a7802SBaban Kenkre 				que = &(query_state->queries[qid]);
14112b4a7802SBaban Kenkre 				rc = add_entry(adh, que, res);
14122b4a7802SBaban Kenkre 				(void) pthread_mutex_unlock(&adh->lock);
14132b4a7802SBaban Kenkre 				if (rc < 0) {
14147a8a68f5SJulian Pullen 					logger(LOG_DEBUG,
14152b4a7802SBaban Kenkre 					    "Failed to queue entry by "
14162b4a7802SBaban Kenkre 					    "message ID (%d) "
14172b4a7802SBaban Kenkre 					    "- %d queued requests",
14182b4a7802SBaban Kenkre 					    msgid, num);
14192b4a7802SBaban Kenkre 				}
14202b4a7802SBaban Kenkre 			}
14212b4a7802SBaban Kenkre 			adutils_lookup_batch_unlock(&query_state);
14222b4a7802SBaban Kenkre 		} else {
14232b4a7802SBaban Kenkre 			num = adh->num_requests;
14242b4a7802SBaban Kenkre 			(void) pthread_mutex_unlock(&adh->lock);
14257a8a68f5SJulian Pullen 			logger(LOG_DEBUG,
14262b4a7802SBaban Kenkre 			    "AD cannot find message ID (%d) "
14272b4a7802SBaban Kenkre 			    "- %d queued requests",
14282b4a7802SBaban Kenkre 			    msgid, num);
14292b4a7802SBaban Kenkre 		}
14302b4a7802SBaban Kenkre 		(void) ldap_msgfree(res);
14312b4a7802SBaban Kenkre 		ret = 0;
14322b4a7802SBaban Kenkre 		break;
14332b4a7802SBaban Kenkre 
14342b4a7802SBaban Kenkre 	case LDAP_RES_SEARCH_REFERENCE:
14352b4a7802SBaban Kenkre 		/*
14362b4a7802SBaban Kenkre 		 * We have no need for these at the moment.  Eventually,
14372b4a7802SBaban Kenkre 		 * when we query things that we can't expect to find in
14382b4a7802SBaban Kenkre 		 * the Global Catalog then we'll need to learn to follow
14392b4a7802SBaban Kenkre 		 * references.
14402b4a7802SBaban Kenkre 		 */
14412b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&adh->lock);
14422b4a7802SBaban Kenkre 		(void) ldap_msgfree(res);
14432b4a7802SBaban Kenkre 		ret = 0;
14442b4a7802SBaban Kenkre 		break;
14452b4a7802SBaban Kenkre 
14462b4a7802SBaban Kenkre 	default:
14472b4a7802SBaban Kenkre 		/* timeout or error; treat the same */
14482b4a7802SBaban Kenkre 		(void) pthread_mutex_unlock(&adh->lock);
14492b4a7802SBaban Kenkre 		ret = -1;
14502b4a7802SBaban Kenkre 		break;
14512b4a7802SBaban Kenkre 	}
14522b4a7802SBaban Kenkre 
14532b4a7802SBaban Kenkre 	return (ret);
14542b4a7802SBaban Kenkre }
14552b4a7802SBaban Kenkre 
14562b4a7802SBaban Kenkre /*
14572b4a7802SBaban Kenkre  * This routine decreament the reference count of the
14582b4a7802SBaban Kenkre  * adutils_query_state_t
14592b4a7802SBaban Kenkre  */
14602b4a7802SBaban Kenkre static void
adutils_lookup_batch_unlock(adutils_query_state_t ** state)14612b4a7802SBaban Kenkre adutils_lookup_batch_unlock(adutils_query_state_t **state)
14622b4a7802SBaban Kenkre {
14632b4a7802SBaban Kenkre 	/*
14642b4a7802SBaban Kenkre 	 * Decrement reference count with qstatelock locked
14652b4a7802SBaban Kenkre 	 */
14662b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&qstatelock);
14672b4a7802SBaban Kenkre 	(*state)->ref_cnt--;
14682b4a7802SBaban Kenkre 	/*
14692b4a7802SBaban Kenkre 	 * If there are no references wakup the allocating thread
14702b4a7802SBaban Kenkre 	 */
14712b4a7802SBaban Kenkre 	if ((*state)->ref_cnt <= 1)
14722b4a7802SBaban Kenkre 		(void) pthread_cond_signal(&(*state)->cv);
14732b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&qstatelock);
14742b4a7802SBaban Kenkre 	*state = NULL;
14752b4a7802SBaban Kenkre }
14762b4a7802SBaban Kenkre 
14772b4a7802SBaban Kenkre /*
14782b4a7802SBaban Kenkre  * This routine frees the adutils_query_state_t structure
14792b4a7802SBaban Kenkre  * If the reference count is greater than 1 it waits
14802b4a7802SBaban Kenkre  * for the other threads to finish using it.
14812b4a7802SBaban Kenkre  */
14822b4a7802SBaban Kenkre void
adutils_lookup_batch_release(adutils_query_state_t ** state)14832b4a7802SBaban Kenkre adutils_lookup_batch_release(adutils_query_state_t **state)
14842b4a7802SBaban Kenkre {
14852b4a7802SBaban Kenkre 	adutils_query_state_t **p;
14862b4a7802SBaban Kenkre 	int			i;
14872b4a7802SBaban Kenkre 
14882b4a7802SBaban Kenkre 	if (state == NULL || *state == NULL)
14892b4a7802SBaban Kenkre 		return;
14902b4a7802SBaban Kenkre 
14912b4a7802SBaban Kenkre 	/*
14922b4a7802SBaban Kenkre 	 * Set state to dead to stop further operations.
14932b4a7802SBaban Kenkre 	 * Wait for reference count with qstatelock locked
14942b4a7802SBaban Kenkre 	 * to get to one.
14952b4a7802SBaban Kenkre 	 */
14962b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&qstatelock);
14972b4a7802SBaban Kenkre 	(*state)->qdead = 1;
14982b4a7802SBaban Kenkre 	while ((*state)->ref_cnt > 1) {
14992b4a7802SBaban Kenkre 		(void) pthread_cond_wait(&(*state)->cv, &qstatelock);
15002b4a7802SBaban Kenkre 	}
15012b4a7802SBaban Kenkre 
15022b4a7802SBaban Kenkre 	/* Remove this state struct from the list of state structs */
15032b4a7802SBaban Kenkre 	for (p = &qstatehead; *p != NULL; p = &(*p)->next) {
15042b4a7802SBaban Kenkre 		if (*p == (*state)) {
15052b4a7802SBaban Kenkre 			*p = (*state)->next;
15062b4a7802SBaban Kenkre 			break;
15072b4a7802SBaban Kenkre 		}
15082b4a7802SBaban Kenkre 	}
15092b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&qstatelock);
15102b4a7802SBaban Kenkre 	(void) pthread_cond_destroy(&(*state)->cv);
15112b4a7802SBaban Kenkre 	release_conn((*state)->qadh);
15122b4a7802SBaban Kenkre 
15132b4a7802SBaban Kenkre 	/* Clear results for queries that failed */
15142b4a7802SBaban Kenkre 	for (i = 0; i < (*state)->qcount; i++) {
15152b4a7802SBaban Kenkre 		if (*(*state)->queries[i].rc != ADUTILS_SUCCESS) {
15162b4a7802SBaban Kenkre 			adutils_freeresult((*state)->queries[i].result);
15172b4a7802SBaban Kenkre 		}
15182b4a7802SBaban Kenkre 	}
15192b4a7802SBaban Kenkre 	free(*state);
15202b4a7802SBaban Kenkre 	*state = NULL;
15212b4a7802SBaban Kenkre }
15222b4a7802SBaban Kenkre 
15232b4a7802SBaban Kenkre 
15242b4a7802SBaban Kenkre /*
15252b4a7802SBaban Kenkre  * This routine waits for other threads using the
15262b4a7802SBaban Kenkre  * adutils_query_state_t structure to finish.
15272b4a7802SBaban Kenkre  * If the reference count is greater than 1 it waits
15282b4a7802SBaban Kenkre  * for the other threads to finish using it.
15292b4a7802SBaban Kenkre  */
15302b4a7802SBaban Kenkre static
15312b4a7802SBaban Kenkre void
adutils_lookup_batch_wait(adutils_query_state_t * state)15322b4a7802SBaban Kenkre adutils_lookup_batch_wait(adutils_query_state_t *state)
15332b4a7802SBaban Kenkre {
15342b4a7802SBaban Kenkre 	/*
15352b4a7802SBaban Kenkre 	 * Set state to dead to stop further operation.
15362b4a7802SBaban Kenkre 	 * stating.
15372b4a7802SBaban Kenkre 	 * Wait for reference count to get to one
15382b4a7802SBaban Kenkre 	 * with qstatelock locked.
15392b4a7802SBaban Kenkre 	 */
15402b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&qstatelock);
15412b4a7802SBaban Kenkre 	state->qdead = 1;
15422b4a7802SBaban Kenkre 	while (state->ref_cnt > 1) {
15432b4a7802SBaban Kenkre 		(void) pthread_cond_wait(&state->cv, &qstatelock);
15442b4a7802SBaban Kenkre 	}
15452b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&qstatelock);
15462b4a7802SBaban Kenkre }
15472b4a7802SBaban Kenkre 
15482b4a7802SBaban Kenkre /*
15492b4a7802SBaban Kenkre  * Process active queries in the AD lookup batch and then finalize the
15502b4a7802SBaban Kenkre  * result.
15512b4a7802SBaban Kenkre  */
15522b4a7802SBaban Kenkre adutils_rc
adutils_lookup_batch_end(adutils_query_state_t ** state)15532b4a7802SBaban Kenkre adutils_lookup_batch_end(adutils_query_state_t **state)
15542b4a7802SBaban Kenkre {
15552b4a7802SBaban Kenkre 	int		    rc = LDAP_SUCCESS;
15562b4a7802SBaban Kenkre 	adutils_rc	    ad_rc = ADUTILS_SUCCESS;
15572b4a7802SBaban Kenkre 	struct timeval	    tv;
15582b4a7802SBaban Kenkre 
15592b4a7802SBaban Kenkre 	tv.tv_sec = ADUTILS_SEARCH_TIMEOUT;
15602b4a7802SBaban Kenkre 	tv.tv_usec = 0;
15612b4a7802SBaban Kenkre 
15622b4a7802SBaban Kenkre 	/* Process results until done or until timeout, if given */
15632b4a7802SBaban Kenkre 	while ((*state)->qinflight > 0) {
15642b4a7802SBaban Kenkre 		if ((rc = get_adobject_batch((*state)->qadh,
15652b4a7802SBaban Kenkre 		    &tv)) != 0)
15662b4a7802SBaban Kenkre 			break;
15672b4a7802SBaban Kenkre 	}
15682b4a7802SBaban Kenkre 	(*state)->qdead = 1;
15692b4a7802SBaban Kenkre 	/* Wait for other threads processing search result to finish */
15702b4a7802SBaban Kenkre 	adutils_lookup_batch_wait(*state);
15712b4a7802SBaban Kenkre 	if (rc == -1 || (*state)->qinflight != 0)
15722b4a7802SBaban Kenkre 		ad_rc = ADUTILS_ERR_RETRIABLE_NET_ERR;
15732b4a7802SBaban Kenkre 	adutils_lookup_batch_release(state);
15742b4a7802SBaban Kenkre 	return (ad_rc);
15752b4a7802SBaban Kenkre }
15762b4a7802SBaban Kenkre 
15772b4a7802SBaban Kenkre /*
15782b4a7802SBaban Kenkre  * Send one prepared search, queue up msgid, process what results are
15792b4a7802SBaban Kenkre  * available
15802b4a7802SBaban Kenkre  */
15812b4a7802SBaban Kenkre adutils_rc
adutils_lookup_batch_add(adutils_query_state_t * state,const char * filter,const char * const * attrs,const char * edomain,adutils_result_t ** result,adutils_rc * rc)15822b4a7802SBaban Kenkre adutils_lookup_batch_add(adutils_query_state_t *state,
1583*67fccfffSMatt Barden     const char *filter, const char * const *attrs, const char *edomain,
1584*67fccfffSMatt Barden     adutils_result_t **result, adutils_rc *rc)
15852b4a7802SBaban Kenkre {
15862b4a7802SBaban Kenkre 	adutils_rc	retcode = ADUTILS_SUCCESS;
15872b4a7802SBaban Kenkre 	int		lrc, qid;
15882b4a7802SBaban Kenkre 	int		num;
15892b4a7802SBaban Kenkre 	int		dead;
15902b4a7802SBaban Kenkre 	struct timeval	tv;
15912b4a7802SBaban Kenkre 	adutils_q_t	*q;
15922b4a7802SBaban Kenkre 
15934d61c878SJulian Pullen 	qid = atomic_inc_32_nv(&state->qcount) - 1;
15942b4a7802SBaban Kenkre 	q = &(state->queries[qid]);
15952b4a7802SBaban Kenkre 
15964d61c878SJulian Pullen 	assert(qid < state->qsize);
15974d61c878SJulian Pullen 
15982b4a7802SBaban Kenkre 	/*
15992b4a7802SBaban Kenkre 	 * Remember the expected domain so we can check the results
16002b4a7802SBaban Kenkre 	 * against it
16012b4a7802SBaban Kenkre 	 */
16022b4a7802SBaban Kenkre 	q->edomain = edomain;
16032b4a7802SBaban Kenkre 
16042b4a7802SBaban Kenkre 	/* Remember where to put the results */
16052b4a7802SBaban Kenkre 	q->result = result;
16062b4a7802SBaban Kenkre 	q->rc = rc;
16072b4a7802SBaban Kenkre 
16082b4a7802SBaban Kenkre 	/*
16092b4a7802SBaban Kenkre 	 * Provide sane defaults for the results in case we never hear
16102b4a7802SBaban Kenkre 	 * back from the DS before closing the connection.
16112b4a7802SBaban Kenkre 	 */
16122b4a7802SBaban Kenkre 	*rc = ADUTILS_ERR_RETRIABLE_NET_ERR;
16132b4a7802SBaban Kenkre 	if (result != NULL)
16142b4a7802SBaban Kenkre 		*result = NULL;
16152b4a7802SBaban Kenkre 
16162b4a7802SBaban Kenkre 	/* Check the number of queued requests first */
16172b4a7802SBaban Kenkre 	tv.tv_sec = ADUTILS_SEARCH_TIMEOUT;
16182b4a7802SBaban Kenkre 	tv.tv_usec = 0;
16192b4a7802SBaban Kenkre 	while (!state->qadh->dead &&
16202b4a7802SBaban Kenkre 	    state->qadh->num_requests > state->qadh->max_requests) {
16212b4a7802SBaban Kenkre 		if (get_adobject_batch(state->qadh, &tv) != 0)
16222b4a7802SBaban Kenkre 			break;
16232b4a7802SBaban Kenkre 	}
16242b4a7802SBaban Kenkre 
16252b4a7802SBaban Kenkre 	/* Send this lookup, don't wait for a result here */
16262b4a7802SBaban Kenkre 	lrc = LDAP_SUCCESS;
16272b4a7802SBaban Kenkre 	(void) pthread_mutex_lock(&state->qadh->lock);
16282b4a7802SBaban Kenkre 
16292b4a7802SBaban Kenkre 	if (!state->qadh->dead) {
16302b4a7802SBaban Kenkre 		state->qadh->idletime = time(NULL);
1631e3f2c991SKeyur Desai 
1632e3f2c991SKeyur Desai 		lrc = ldap_search_ext(state->qadh->ld,
1633e3f2c991SKeyur Desai 		    state->qadh->owner->basedn,
16342b4a7802SBaban Kenkre 		    LDAP_SCOPE_SUBTREE, filter, (char **)attrs,
16352b4a7802SBaban Kenkre 		    0, NULL, NULL, NULL, -1, &q->msgid);
16362b4a7802SBaban Kenkre 
16372b4a7802SBaban Kenkre 		if (lrc == LDAP_SUCCESS) {
16382b4a7802SBaban Kenkre 			state->qadh->num_requests++;
16392b4a7802SBaban Kenkre 		} else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE ||
16402b4a7802SBaban Kenkre 		    lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN ||
16412b4a7802SBaban Kenkre 		    lrc == LDAP_UNWILLING_TO_PERFORM) {
16422b4a7802SBaban Kenkre 			retcode = ADUTILS_ERR_RETRIABLE_NET_ERR;
16432b4a7802SBaban Kenkre 			state->qadh->dead = 1;
16442b4a7802SBaban Kenkre 		} else {
16452b4a7802SBaban Kenkre 			retcode = ADUTILS_ERR_OTHER;
16462b4a7802SBaban Kenkre 			state->qadh->dead = 1;
16472b4a7802SBaban Kenkre 		}
16482b4a7802SBaban Kenkre 	}
16492b4a7802SBaban Kenkre 	dead = state->qadh->dead;
16502b4a7802SBaban Kenkre 	num = state->qadh->num_requests;
16512b4a7802SBaban Kenkre 	(void) pthread_mutex_unlock(&state->qadh->lock);
16522b4a7802SBaban Kenkre 
16532b4a7802SBaban Kenkre 	if (dead) {
16542b4a7802SBaban Kenkre 		if (lrc != LDAP_SUCCESS)
16557a8a68f5SJulian Pullen 			logger(LOG_DEBUG,
16562b4a7802SBaban Kenkre 			    "AD ldap_search_ext error (%s) "
16572b4a7802SBaban Kenkre 			    "- %d queued requests",
16582b4a7802SBaban Kenkre 			    ldap_err2string(lrc), num);
16592b4a7802SBaban Kenkre 		return (retcode);
16602b4a7802SBaban Kenkre 	}
16612b4a7802SBaban Kenkre 
16622b4a7802SBaban Kenkre 	atomic_inc_32(&state->qinflight);
16632b4a7802SBaban Kenkre 
16642b4a7802SBaban Kenkre 	/*
16652b4a7802SBaban Kenkre 	 * Reap as many requests as we can _without_ waiting to prevent
16662b4a7802SBaban Kenkre 	 * any possible TCP socket buffer starvation deadlocks.
16672b4a7802SBaban Kenkre 	 */
16682b4a7802SBaban Kenkre 	(void) memset(&tv, 0, sizeof (tv));
16692b4a7802SBaban Kenkre 	while (get_adobject_batch(state->qadh, &tv) == 0)
16702b4a7802SBaban Kenkre 		;
16712b4a7802SBaban Kenkre 
16722b4a7802SBaban Kenkre 	return (ADUTILS_SUCCESS);
16732b4a7802SBaban Kenkre }
16742b4a7802SBaban Kenkre 
16752b4a7802SBaban Kenkre /*
16762b4a7802SBaban Kenkre  * Single AD lookup request implemented on top of the batch API.
16772b4a7802SBaban Kenkre  */
16782b4a7802SBaban Kenkre adutils_rc
adutils_lookup(adutils_ad_t * ad,const char * filter,const char ** attrs,const char * domain,adutils_result_t ** result)16792b4a7802SBaban Kenkre adutils_lookup(adutils_ad_t *ad, const char *filter, const char **attrs,
1680*67fccfffSMatt Barden     const char *domain, adutils_result_t **result)
16812b4a7802SBaban Kenkre {
16822b4a7802SBaban Kenkre 	adutils_rc		rc, brc;
16832b4a7802SBaban Kenkre 	adutils_query_state_t	*qs;
16842b4a7802SBaban Kenkre 
16852b4a7802SBaban Kenkre 	rc = adutils_lookup_batch_start(ad, 1, NULL, NULL, &qs);
16862b4a7802SBaban Kenkre 	if (rc != ADUTILS_SUCCESS)
16872b4a7802SBaban Kenkre 		return (rc);
16882b4a7802SBaban Kenkre 
16892b4a7802SBaban Kenkre 	rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc);
16902b4a7802SBaban Kenkre 	if (rc != ADUTILS_SUCCESS) {
16912b4a7802SBaban Kenkre 		adutils_lookup_batch_release(&qs);
16922b4a7802SBaban Kenkre 		return (rc);
16932b4a7802SBaban Kenkre 	}
16942b4a7802SBaban Kenkre 
16952b4a7802SBaban Kenkre 	rc = adutils_lookup_batch_end(&qs);
16962b4a7802SBaban Kenkre 	if (rc != ADUTILS_SUCCESS)
16972b4a7802SBaban Kenkre 		return (rc);
16982b4a7802SBaban Kenkre 	return (brc);
16992b4a7802SBaban Kenkre }
17001fcced4cSJordan Brown 
17011fcced4cSJordan Brown boolean_t
domain_eq(const char * a,const char * b)17021fcced4cSJordan Brown domain_eq(const char *a, const char *b)
17031fcced4cSJordan Brown {
17041fcced4cSJordan Brown 	int err;
17051fcced4cSJordan Brown 
17061fcced4cSJordan Brown 	return (u8_strcmp(a, b, 0, U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err)
17071fcced4cSJordan Brown 	    == 0 && err == 0);
17081fcced4cSJordan Brown }
1709148c5f43SAlan Wright 
1710148c5f43SAlan Wright void
adutils_set_debug(enum ad_debug item,int value)1711148c5f43SAlan Wright adutils_set_debug(enum ad_debug item, int value)
1712148c5f43SAlan Wright {
1713148c5f43SAlan Wright 	if (item >= 0 && item <= AD_DEBUG_MAX)
1714148c5f43SAlan Wright 		ad_debug[item] = value;
1715148c5f43SAlan Wright }
1716