12b4a780Baban Kenkre/*
22b4a780Baban Kenkre * CDDL HEADER START
32b4a780Baban Kenkre *
42b4a780Baban Kenkre * The contents of this file are subject to the terms of the
52b4a780Baban Kenkre * Common Development and Distribution License (the "License").
62b4a780Baban Kenkre * You may not use this file except in compliance with the License.
72b4a780Baban Kenkre *
82b4a780Baban Kenkre * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92b4a780Baban Kenkre * or http://www.opensolaris.org/os/licensing.
102b4a780Baban Kenkre * See the License for the specific language governing permissions
112b4a780Baban Kenkre * and limitations under the License.
122b4a780Baban Kenkre *
132b4a780Baban Kenkre * When distributing Covered Code, include this CDDL HEADER in each
142b4a780Baban Kenkre * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152b4a780Baban Kenkre * If applicable, add the following below this CDDL HEADER, with the
162b4a780Baban Kenkre * fields enclosed by brackets "[]" replaced with your own identifying
172b4a780Baban Kenkre * information: Portions Copyright [yyyy] [name of copyright owner]
182b4a780Baban Kenkre *
192b4a780Baban Kenkre * CDDL HEADER END
202b4a780Baban Kenkre */
212b4a780Baban Kenkre/*
22148c5f4Alan Wright * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
232b4a780Baban Kenkre */
242b4a780Baban Kenkre
252b4a780Baban Kenkre#include <alloca.h>
262b4a780Baban Kenkre#include <string.h>
272b4a780Baban Kenkre#include <strings.h>
282b4a780Baban Kenkre#include <lber.h>
292b4a780Baban Kenkre#include <sasl/sasl.h>
302b4a780Baban Kenkre#include <string.h>
312b4a780Baban Kenkre#include <ctype.h>
322b4a780Baban Kenkre#include <synch.h>
332b4a780Baban Kenkre#include <atomic.h>
342b4a780Baban Kenkre#include <errno.h>
352b4a780Baban Kenkre#include <assert.h>
362b4a780Baban Kenkre#include <limits.h>
377a8a68fJulian Pullen#include <syslog.h>
382b4a780Baban Kenkre#include <sys/u8_textprep.h>
392b4a780Baban Kenkre#include <sys/varargs.h>
402b4a780Baban Kenkre#include "libadutils.h"
412b4a780Baban Kenkre#include "adutils_impl.h"
422b4a780Baban Kenkre
432b4a780Baban Kenkre/* List of DSs, needed by the idle connection reaper thread */
442b4a780Baban Kenkrestatic pthread_mutex_t	adhostlock = PTHREAD_MUTEX_INITIALIZER;
452b4a780Baban Kenkrestatic adutils_host_t	*host_head = NULL;
462b4a780Baban Kenkre
472b4a780Baban Kenkre/*
482b4a780Baban Kenkre * List of query state structs -- needed so we can "route" LDAP results
492b4a780Baban Kenkre * to the right context if multiple threads should be using the same
502b4a780Baban Kenkre * connection concurrently
512b4a780Baban Kenkre */
522b4a780Baban Kenkrestatic pthread_mutex_t		qstatelock = PTHREAD_MUTEX_INITIALIZER;
532b4a780Baban Kenkrestatic adutils_query_state_t	*qstatehead = NULL;
542b4a780Baban Kenkre
552b4a780Baban Kenkrestatic char *adutils_sid_ber2str(BerValue *bvalues);
562b4a780Baban Kenkrestatic void adutils_lookup_batch_unlock(adutils_query_state_t **state);
572b4a780Baban Kenkrestatic void delete_ds(adutils_ad_t *ad, const char *host, int port);
582b4a780Baban Kenkre
59148c5f4Alan Wrightint ad_debug[AD_DEBUG_MAX+1] = {0};
60148c5f4Alan Wright
612b4a780Baban Kenkretypedef struct binary_attrs {
622b4a780Baban Kenkre	const char	*name;
632b4a780Baban Kenkre	char		*(*ber2str)(BerValue *bvalues);
642b4a780Baban Kenkre} binary_attrs_t;
652b4a780Baban Kenkre
662b4a780Baban Kenkrestatic binary_attrs_t binattrs[] = {
672b4a780Baban Kenkre	{"objectSID", adutils_sid_ber2str},
682b4a780Baban Kenkre	{NULL, NULL}
692b4a780Baban Kenkre};
702b4a780Baban Kenkre
714d61c87Julian Pullen
727a8a68fJulian Pullenadutils_logger logger = syslog;
737a8a68fJulian Pullen
747a8a68fJulian Pullen
752b4a780Baban Kenkrevoid
767a8a68fJulian Pullenadutils_set_logger(adutils_logger funct)
772b4a780Baban Kenkre{
787a8a68fJulian Pullen	logger = funct;
792b4a780Baban Kenkre}
802b4a780Baban Kenkre
814d61c87Julian Pullen
822b4a780Baban Kenkre/*
832b4a780Baban Kenkre * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com"
842b4a780Baban Kenkre */
852b4a780Baban Kenkrestatic
862b4a780Baban Kenkrechar *
872b4a780Baban Kenkreadutils_dns2dn(const char *dns)
882b4a780Baban Kenkre{
897a8a68fJulian Pullen	int num_parts;
907a8a68fJulian Pullen
917a8a68fJulian Pullen	return (ldap_dns_to_dn((char *)dns, &num_parts));
922b4a780Baban Kenkre}
932b4a780Baban Kenkre
944d61c87Julian Pullen
952b4a780Baban Kenkre/*
962b4a780Baban Kenkre * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other
972b4a780Baban Kenkre * attributes (CN, etc...).
982b4a780Baban Kenkre */
992b4a780Baban Kenkrechar *
1002b4a780Baban Kenkreadutils_dn2dns(const char *dn)
1012b4a780Baban Kenkre{
1027a8a68fJulian Pullen	return (DN_to_DNS(dn));
1032b4a780Baban Kenkre}
1042b4a780Baban Kenkre
1057a8a68fJulian Pullen
1062b4a780Baban Kenkre/*
1072b4a780Baban Kenkre * Convert a binary SID in a BerValue to a adutils_sid_t
1082b4a780Baban Kenkre */
1092b4a780Baban Kenkreint
1107a8a68fJulian Pullenadutils_getsid(BerValue *bval, adutils_sid_t *sidp)
1112b4a780Baban Kenkre{
1122b4a780Baban Kenkre	int		i, j;
1132b4a780Baban Kenkre	uchar_t		*v;
1142b4a780Baban Kenkre	uint32_t	a;
1152b4a780Baban Kenkre
1162b4a780Baban Kenkre	/*
1172b4a780Baban Kenkre	 * The binary format of a SID is as follows:
1182b4a780Baban Kenkre	 *
1192b4a780Baban Kenkre	 * byte #0: version, always 0x01
1202b4a780Baban Kenkre	 * byte #1: RID count, always <= 0x0f
1212b4a780Baban Kenkre	 * bytes #2-#7: SID authority, big-endian 48-bit unsigned int
1222b4a780Baban Kenkre	 *
1232b4a780Baban Kenkre	 * followed by RID count RIDs, each a little-endian, unsigned
1242b4a780Baban Kenkre	 * 32-bit int.
1252b4a780Baban Kenkre	 */
1262b4a780Baban Kenkre	/*
1272b4a780Baban Kenkre	 * Sanity checks: must have at least one RID, version must be
1282b4a780Baban Kenkre	 * 0x01, and the length must be 8 + rid count * 4
1292b4a780Baban Kenkre	 */
1302b4a780Baban Kenkre	if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 &&
1312b4a780Baban Kenkre	    bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) {
1322b4a780Baban Kenkre		v = (uchar_t *)bval->bv_val;
1332b4a780Baban Kenkre		sidp->version = v[0];
1342b4a780Baban Kenkre		sidp->sub_authority_count = v[1];
1352b4a780Baban Kenkre		sidp->authority =
1362b4a780Baban Kenkre		    /* big endian -- so start from the left */
1372b4a780Baban Kenkre		    ((u_longlong_t)v[2] << 40) |
1382b4a780Baban Kenkre		    ((u_longlong_t)v[3] << 32) |
1392b4a780Baban Kenkre		    ((u_longlong_t)v[4] << 24) |
1402b4a780Baban Kenkre		    ((u_longlong_t)v[5] << 16) |
1412b4a780Baban Kenkre		    ((u_longlong_t)v[6] << 8) |
1422b4a780Baban Kenkre		    (u_longlong_t)v[7];
1432b4a780Baban Kenkre		for (i = 0; i < sidp->sub_authority_count; i++) {
1442b4a780Baban Kenkre			j = 8 + (i * 4);
1452b4a780Baban Kenkre			/* little endian -- so start from the right */
1462b4a780Baban Kenkre			a = (v[j + 3] << 24) | (v[j + 2] << 16) |
1472b4a780Baban Kenkre			    (v[j + 1] << 8) | (v[j]);
1482b4a780Baban Kenkre			sidp->sub_authorities[i] = a;
1492b4a780Baban Kenkre		}
1502b4a780Baban Kenkre		return (0);
1512b4a780Baban Kenkre	}
1522b4a780Baban Kenkre	return (-1);
1532b4a780Baban Kenkre}
1542b4a780Baban Kenkre
1552b4a780Baban Kenkre/*
1562b4a780Baban Kenkre * Convert a adutils_sid_t to S-1-...
1572b4a780Baban Kenkre */
1582b4a780Baban Kenkrechar *
1597a8a68fJulian Pullenadutils_sid2txt(adutils_sid_t *sidp)
1602b4a780Baban Kenkre{
1612b4a780Baban Kenkre	int	rlen, i, len;
1622b4a780Baban Kenkre	char	*str, *cp;
1632b4a780Baban Kenkre
1642b4a780Baban Kenkre	if (sidp->version != 1)
1652b4a780Baban Kenkre		return (NULL);
1662b4a780Baban Kenkre
1672b4a780Baban Kenkre	len = sizeof ("S-1-") - 1;
1682b4a780Baban Kenkre
1692b4a780Baban Kenkre	/*
1702b4a780Baban Kenkre	 * We could optimize like so, but, why?
1712b4a780Baban Kenkre	 *	if (sidp->authority < 10)
1722b4a780Baban Kenkre	 *		len += 2;
1732b4a780Baban Kenkre	 *	else if (sidp->authority < 100)
1742b4a780Baban Kenkre	 *		len += 3;
1752b4a780Baban Kenkre	 *	else
1762b4a780Baban Kenkre	 *		len += snprintf(NULL, 0"%llu", sidp->authority);
1772b4a780Baban Kenkre	 */
1782b4a780Baban Kenkre	len += snprintf(NULL, 0, "%llu", sidp->authority);
1792b4a780Baban Kenkre
1802b4a780Baban Kenkre	/* Max length of a uint32_t printed out in ASCII is 10 bytes */
1812b4a780Baban Kenkre	len += 1 + (sidp->sub_authority_count + 1) * 10;
1822b4a780Baban Kenkre
1832b4a780Baban Kenkre	if ((cp = str = malloc(len)) == NULL)
1842b4a780Baban Kenkre		return (NULL);
1852b4a780Baban Kenkre
1862b4a780Baban Kenkre	rlen = snprintf(str, len, "S-1-%llu", sidp->authority);
1872b4a780Baban Kenkre
1882b4a780Baban Kenkre	cp += rlen;
1892b4a780Baban Kenkre	len -= rlen;
1902b4a780Baban Kenkre
1912b4a780Baban Kenkre	for (i = 0; i < sidp->sub_authority_count; i++) {
1922b4a780Baban Kenkre		assert(len > 0);
1932b4a780Baban Kenkre		rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]);
1942b4a780Baban Kenkre		cp += rlen;
1952b4a780Baban Kenkre		len -= rlen;
1962b4a780Baban Kenkre		assert(len >= 0);
1972b4a780Baban Kenkre	}
1982b4a780Baban Kenkre
1992b4a780Baban Kenkre	return (str);
2002b4a780Baban Kenkre}
2012b4a780Baban Kenkre
2022b4a780Baban Kenkre/*
2032b4a780Baban Kenkre * Convert a adutils_sid_t to on-the-wire encoding
2042b4a780Baban Kenkre */
2052b4a780Baban Kenkrestatic
2062b4a780Baban Kenkreint
2072b4a780Baban Kenkresid2binsid(adutils_sid_t *sid, uchar_t *binsid, int binsidlen)
2082b4a780Baban Kenkre{
2092b4a780Baban Kenkre	uchar_t		*p;
2102b4a780Baban Kenkre	int		i;
2112b4a780Baban Kenkre	uint64_t	a;
2122b4a780Baban Kenkre	uint32_t	r;
2132b4a780Baban Kenkre
2142b4a780Baban Kenkre	if (sid->version != 1 ||
2152b4a780Baban Kenkre	    binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4))
2162b4a780Baban Kenkre		return (-1);
2172b4a780Baban Kenkre
2182b4a780Baban Kenkre	p = binsid;
2192b4a780Baban Kenkre	*p++ = 0x01;		/* version */
2202b4a780Baban Kenkre	/* sub authority count */
2212b4a780Baban Kenkre	*p++ = sid->sub_authority_count;
2222b4a780Baban Kenkre	/* Authority */
2232b4a780Baban Kenkre	a = sid->authority;
2242b4a780Baban Kenkre	/* big-endian -- start from left */
2252b4a780Baban Kenkre	*p++ = (a >> 40) & 0xFF;
2262b4a780Baban Kenkre	*p++ = (a >> 32) & 0xFF;
2272b4a780Baban Kenkre	*p++ = (a >> 24) & 0xFF;
2282b4a780Baban Kenkre	*p++ = (a >> 16) & 0xFF;
2292b4a780Baban Kenkre	*p++ = (a >> 8) & 0xFF;
2302b4a780Baban Kenkre	*p++ = a & 0xFF;
2312b4a780Baban Kenkre
2322b4a780Baban Kenkre	/* sub-authorities */
2332b4a780Baban Kenkre	for (i = 0; i < sid->sub_authority_count; i++) {
2342b4a780Baban Kenkre		r = sid->sub_authorities[i];
2352b4a780Baban Kenkre		/* little-endian -- start from right */
2362b4a780Baban Kenkre		*p++ = (r & 0x000000FF);
2372b4a780Baban Kenkre		*p++ = (r & 0x0000FF00) >> 8;
2382b4a780Baban Kenkre		*p++ = (r & 0x00FF0000) >> 16;
2392b4a780Baban Kenkre		*p++ = (r & 0xFF000000) >> 24;
2402b4a780Baban Kenkre	}
2412b4a780Baban Kenkre
2422b4a780Baban Kenkre	return (0);
2432b4a780Baban Kenkre}
2442b4a780Baban Kenkre
2452b4a780Baban Kenkre/*
2462b4a780Baban Kenkre * Convert a stringified SID (S-1-...) into a hex-encoded version of the
2472b4a780Baban Kenkre * on-the-wire encoding, but with each pair of hex digits pre-pended
2482b4a780Baban Kenkre * with a '\', so we can pass this to libldap.
2492b4a780Baban Kenkre */
2502b4a780Baban Kenkreint
2512b4a780Baban Kenkreadutils_txtsid2hexbinsid(const char *txt, const uint32_t *rid,
2522b4a780Baban Kenkre	char *hexbinsid, int hexbinsidlen)
2532b4a780Baban Kenkre{
2542b4a780Baban Kenkre	adutils_sid_t	sid = { 0 };
2552b4a780Baban Kenkre	int		i, j;
2562b4a780Baban Kenkre	const char	*cp;
2572b4a780Baban Kenkre	char		*ecp;
2582b4a780Baban Kenkre	u_longlong_t	a;
2592b4a780Baban Kenkre	unsigned long	r;
2602b4a780Baban Kenkre	uchar_t		*binsid, b, hb;
2612b4a780Baban Kenkre
2622b4a780Baban Kenkre	/* Only version 1 SIDs please */
2632b4a780Baban Kenkre	if (strncmp(txt, "S-1-", strlen("S-1-")) != 0)
2642b4a780Baban Kenkre		return (-1);
2652b4a780Baban Kenkre
2662b4a780Baban Kenkre	if (strlen(txt) < (strlen("S-1-") + 1))
2672b4a780Baban Kenkre		return (-1);
2682b4a780Baban Kenkre
2692b4a780Baban Kenkre	/* count '-'s */
2702b4a780Baban Kenkre	for (j = 0, cp = strchr(txt, '-');
2712b4a780Baban Kenkre	    cp != NULL && *cp != '\0';
2722b4a780Baban Kenkre	    j++, cp = strchr(cp + 1, '-')) {
2732b4a780Baban Kenkre		/* can't end on a '-' */
2742b4a780Baban Kenkre		if (*(cp + 1) == '\0')
2752b4a780Baban Kenkre			return (-1);
2762b4a780Baban Kenkre	}
2772b4a780Baban Kenkre
2782b4a780Baban Kenkre	/* Adjust count for version and authority */
2792b4a780Baban Kenkre	j -= 2;
2802b4a780Baban Kenkre
2812b4a780Baban Kenkre	/* we know the version number and RID count */
2822b4a780Baban Kenkre	sid.version = 1;
2832b4a780Baban Kenkre	sid.sub_authority_count = (rid != NULL) ? j + 1 : j;
2842b4a780Baban Kenkre
2852b4a780Baban Kenkre	/* must have at least one RID, but not too many */
2862b4a780Baban Kenkre	if (sid.sub_authority_count < 1 ||
2872b4a780Baban Kenkre	    sid.sub_authority_count > ADUTILS_SID_MAX_SUB_AUTHORITIES)
2882b4a780Baban Kenkre		return (-1);
2892b4a780Baban Kenkre
2902b4a780Baban Kenkre	/* check that we only have digits and '-' */
2912b4a780Baban Kenkre	if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1))
2922b4a780Baban Kenkre		return (-1);
2932b4a780Baban Kenkre
2942b4a780Baban Kenkre	cp = txt + strlen("S-1-");
2952b4a780Baban Kenkre
2962b4a780Baban Kenkre	/* 64-bit safe parsing of unsigned 48-bit authority value */
2972b4a780Baban Kenkre	errno = 0;
2982b4a780Baban Kenkre	a = strtoull(cp, &ecp, 10);
2992b4a780Baban Kenkre
3002b4a780Baban Kenkre	/* errors parsing the authority or too many bits */
3012b4a780Baban Kenkre	if (cp == ecp || (a == 0 && errno == EINVAL) ||
3022b4a780Baban Kenkre	    (a == ULLONG_MAX && errno == ERANGE) ||
3032b4a780Baban Kenkre	    (a & 0x0000ffffffffffffULL) != a)
3042b4a780Baban Kenkre		return (-1);
3052b4a780Baban Kenkre
3062b4a780Baban Kenkre	cp = ecp;
3072b4a780Baban Kenkre
3082b4a780Baban Kenkre	sid.authority = (uint64_t)a;
3092b4a780Baban Kenkre
3102b4a780Baban Kenkre	for (i = 0; i < j; i++) {
3112b4a780Baban Kenkre		if (*cp++ != '-')
3122b4a780Baban Kenkre			return (-1);
3132b4a780Baban Kenkre		/* 64-bit safe parsing of unsigned 32-bit RID */
3142b4a780Baban Kenkre		errno = 0;
3152b4a780Baban Kenkre		r = strtoul(cp, &ecp, 10);
3162b4a780Baban Kenkre		/* errors parsing the RID or too many bits */
3172b4a780Baban Kenkre		if (cp == ecp || (r == 0 && errno == EINVAL) ||
3182b4a780Baban Kenkre		    (r == ULONG_MAX && errno == ERANGE) ||
3192b4a780Baban Kenkre		    (r & 0xffffffffUL) != r)
3202b4a780Baban Kenkre			return (-1);
3212b4a780Baban Kenkre		sid.sub_authorities[i] = (uint32_t)r;
3222b4a780Baban Kenkre		cp = ecp;
3232b4a780Baban Kenkre	}
3242b4a780Baban Kenkre
3252b4a780Baban Kenkre	/* check that all of the string SID has been consumed */
3262b4a780Baban Kenkre	if (*cp != '\0')
3272b4a780Baban Kenkre		return (-1);
3282b4a780Baban Kenkre
3292b4a780Baban Kenkre	if (rid != NULL)
3302b4a780Baban Kenkre		sid.sub_authorities[j] = *rid;
3312b4a780Baban Kenkre
3322b4a780Baban Kenkre	j = 1 + 1 + 6 + sid.sub_authority_count * 4;
3332b4a780Baban Kenkre
3342b4a780Baban Kenkre	if (hexbinsidlen < (j * 3))
3352b4a780Baban Kenkre		return (-2);
3362b4a780Baban Kenkre
3372b4a780Baban Kenkre	/* binary encode the SID */
3382b4a780Baban Kenkre	binsid = (uchar_t *)alloca(j);
3392b4a780Baban Kenkre	(void) sid2binsid(&sid, binsid, j);
3402b4a780Baban Kenkre
3412b4a780Baban Kenkre	/* hex encode, with a backslash before each byte */
3422b4a780Baban Kenkre	for (ecp = hexbinsid, i = 0; i < j; i++) {
3432b4a780Baban Kenkre		b = binsid[i];
3442b4a780Baban Kenkre		*ecp++ = '\\';
3452b4a780Baban Kenkre		hb = (b >> 4) & 0xF;
3462b4a780Baban Kenkre		*ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
3472b4a780Baban Kenkre		hb = b & 0xF;
3482b4a780Baban Kenkre		*ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
3492b4a780Baban Kenkre	}
3502b4a780Baban Kenkre	*ecp = '\0';
3512b4a780Baban Kenkre
3522b4a780Baban Kenkre	return (0);
3532b4a780Baban Kenkre}
3542b4a780Baban Kenkre
3552b4a780Baban Kenkrestatic
3562b4a780Baban Kenkrechar *
3572b4a780Baban Kenkreconvert_bval2sid(BerValue *bval, uint32_t *rid)
3582b4a780Baban Kenkre{
3592b4a780Baban Kenkre	adutils_sid_t	sid;
3602b4a780Baban Kenkre
3617a8a68fJulian Pullen	if (adutils_getsid(bval, &sid) < 0)
3622b4a780Baban Kenkre		return (NULL);
3632b4a780Baban Kenkre
3642b4a780Baban Kenkre	/*
3652b4a780Baban Kenkre	 * If desired and if the SID is what should be a domain/computer
3662b4a780Baban Kenkre	 * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then
3672b4a780Baban Kenkre	 * save the last RID and truncate the SID
3682b4a780Baban Kenkre	 */
3692b4a780Baban Kenkre	if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5)
3702b4a780Baban Kenkre		*rid = sid.sub_authorities[--sid.sub_authority_count];
3717a8a68fJulian Pullen	return (adutils_sid2txt(&sid));
3722b4a780Baban Kenkre}
3732b4a780Baban Kenkre
3742b4a780Baban Kenkre
3752b4a780Baban Kenkre/*
3762b4a780Baban Kenkre * Return a NUL-terminated stringified SID from the value of an
3772b4a780Baban Kenkre * objectSid attribute and put the last RID in *rid.
3782b4a780Baban Kenkre */
3792b4a780Baban Kenkrechar *
3802b4a780Baban Kenkreadutils_bv_objsid2sidstr(BerValue *bval, uint32_t *rid)
3812b4a780Baban Kenkre{
3822b4a780Baban Kenkre	char *sid;
3832b4a780Baban Kenkre
3842b4a780Baban Kenkre	if (bval == NULL)
3852b4a780Baban Kenkre		return (NULL);
3862b4a780Baban Kenkre	/* objectSid is single valued */
3872b4a780Baban Kenkre	if ((sid = convert_bval2sid(bval, rid)) == NULL)
3882b4a780Baban Kenkre		return (NULL);
3892b4a780Baban Kenkre	return (sid);
3902b4a780Baban Kenkre}
3912b4a780Baban Kenkre
3922b4a780Baban Kenkrestatic
3932b4a780Baban Kenkrechar *
3942b4a780Baban Kenkreadutils_sid_ber2str(BerValue *bval)
3952b4a780Baban Kenkre{
3962b4a780Baban Kenkre	return (adutils_bv_objsid2sidstr(bval, NULL));
3972b4a780Baban Kenkre}
3982b4a780Baban Kenkre
3992b4a780Baban Kenkre
400e3f2c99Keyur Desai/*
401e3f2c99Keyur Desai * Extract an int from the Ber value
402e3f2c99Keyur Desai * Return B_TRUE if a valid integer was found, B_FALSE if not.
403e3f2c99Keyur Desai */
404e3f2c99Keyur Desaiboolean_t
405e3f2c99Keyur Desaiadutils_bv_uint(BerValue *bval, unsigned int *result)
406e3f2c99Keyur Desai{
407e3f2c99Keyur Desai	char buf[40];	/* big enough for any int */
408e3f2c99Keyur Desai	unsigned int tmp;
409e3f2c99Keyur Desai	char *p;
410e3f2c99Keyur Desai
411e3f2c99Keyur Desai	*result = 0;	/* for error cases */
412e3f2c99Keyur Desai
413e3f2c99Keyur Desai	if (bval == NULL || bval->bv_val == NULL)
414e3f2c99Keyur Desai		return (B_FALSE);
415e3f2c99Keyur Desai	if (bval->bv_len >= sizeof (buf))
416e3f2c99Keyur Desai		return (B_FALSE);
417e3f2c99Keyur Desai
418e3f2c99Keyur Desai	(void) memcpy(buf, bval->bv_val, bval->bv_len);
419e3f2c99Keyur Desai	buf[bval->bv_len] = '\0';
420e3f2c99Keyur Desai
421e3f2c99Keyur Desai	tmp = strtoul(buf, &p, 10);
422e3f2c99Keyur Desai
423e3f2c99Keyur Desai	/* Junk after the number? */
424e3f2c99Keyur Desai	if (*p != '\0')
425e3f2c99Keyur Desai		return (B_FALSE);
426e3f2c99Keyur Desai
427e3f2c99Keyur Desai	*result = tmp;
428e3f2c99Keyur Desai
429e3f2c99Keyur Desai	return (B_TRUE);
430e3f2c99Keyur Desai}
431e3f2c99Keyur Desai
4322b4a780Baban Kenkre/* Return a NUL-terminated string from the Ber value */
4332b4a780Baban Kenkrechar *
434e3f2c99Keyur Desaiadutils_bv_str(BerValue *bval)
4352b4a780Baban Kenkre{
4362b4a780Baban Kenkre	char *s;
4372b4a780Baban Kenkre
4382b4a780Baban Kenkre	if (bval == NULL || bval->bv_val == NULL)
4392b4a780Baban Kenkre		return (NULL);
4402b4a780Baban Kenkre	if ((s = malloc(bval->bv_len + 1)) == NULL)
4412b4a780Baban Kenkre		return (NULL);
4422b4a780Baban Kenkre	(void) snprintf(s, bval->bv_len + 1, "%.*s", bval->bv_len,
4432b4a780Baban Kenkre	    bval->bv_val);
4442b4a780Baban Kenkre	return (s);
4452b4a780Baban Kenkre}
4462b4a780Baban Kenkre
4472b4a780Baban Kenkre/*ARGSUSED*/
4482b4a780Baban Kenkreint
4492b4a780Baban Kenkresaslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts)
4502b4a780Baban Kenkre{
4512b4a780Baban Kenkre	sasl_interact_t	*interact;
4522b4a780Baban Kenkre
4532b4a780Baban Kenkre	if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
4542b4a780Baban Kenkre		return (LDAP_PARAM_ERROR);
4552b4a780Baban Kenkre
4562b4a780Baban Kenkre	/* There should be no extra arguemnts for SASL/GSSAPI authentication */
4572b4a780Baban Kenkre	for (interact = prompts; interact->id != SASL_CB_LIST_END;
4582b4a780Baban Kenkre	    interact++) {
4592b4a780Baban Kenkre		interact->result = NULL;
4602b4a780Baban Kenkre		interact->len = 0;
4612b4a780Baban Kenkre	}
4622b4a780Baban Kenkre	return (LDAP_SUCCESS);
4632b4a780Baban Kenkre}
4642b4a780Baban Kenkre
4652b4a780Baban Kenkre
4662b4a780Baban Kenkre#define	ADCONN_TIME	300
4672b4a780Baban Kenkre
4682b4a780Baban Kenkre/*
4692b4a780Baban Kenkre * Idle connection reaping side of connection management
4702b4a780Baban Kenkre */
4712b4a780Baban Kenkrevoid
4722b4a780Baban Kenkreadutils_reap_idle_connections()
4732b4a780Baban Kenkre{
4742b4a780Baban Kenkre	adutils_host_t	*adh;
4752b4a780Baban Kenkre	time_t		now;
4762b4a780Baban Kenkre
4772b4a780Baban Kenkre	(void) pthread_mutex_lock(&adhostlock);
4782b4a780Baban Kenkre	now = time(NULL);
4792b4a780Baban Kenkre	for (adh = host_head; adh != NULL; adh = adh->next) {
4802b4a780Baban Kenkre		(void) pthread_mutex_lock(&adh->lock);
4812b4a780Baban Kenkre		if (adh->ref == 0 && adh->idletime != 0 &&
4822b4a780Baban Kenkre		    adh->idletime + ADCONN_TIME < now) {
4832b4a780Baban Kenkre			if (adh->ld) {
4842b4a780Baban Kenkre				(void) ldap_unbind(adh->ld);
4852b4a780Baban Kenkre				adh->ld = NULL;
4862b4a780Baban Kenkre				adh->idletime = 0;
4872b4a780Baban Kenkre				adh->ref = 0;
4882b4a780Baban Kenkre			}
4892b4a780Baban Kenkre		}
4902b4a780Baban Kenkre		(void) pthread_mutex_unlock(&adh->lock);
4912b4a780Baban Kenkre	}
4922b4a780Baban Kenkre	(void) pthread_mutex_unlock(&adhostlock);
4932b4a780Baban Kenkre}
4942b4a780Baban Kenkre
4952b4a780Baban Kenkre
4962b4a780Baban Kenkreadutils_rc
497e3f2c99Keyur Desaiadutils_ad_alloc(adutils_ad_t **new_ad, const char *domain_name,
4982b4a780Baban Kenkre	adutils_ad_partition_t part)
4992b4a780Baban Kenkre{
5002b4a780Baban Kenkre	adutils_ad_t *ad;
5012b4a780Baban Kenkre
5022b4a780Baban Kenkre	*new_ad = NULL;
5032b4a780Baban Kenkre
5042b4a780Baban Kenkre	if ((ad = calloc(1, sizeof (*ad))) == NULL)
5052b4a780Baban Kenkre		return (ADUTILS_ERR_MEMORY);
5062b4a780Baban Kenkre	ad->ref = 1;
5072b4a780Baban Kenkre	ad->partition = part;
508e3f2c99Keyur Desai
509e3f2c99Keyur Desai	/* domain_name is required iff we are talking directly to a DC */
510e3f2c99Keyur Desai	if (part == ADUTILS_AD_DATA) {
511e3f2c99Keyur Desai		assert(domain_name != NULL);
512e3f2c99Keyur Desai		assert(*domain_name != '\0');
513e3f2c99Keyur Desai
514e3f2c99Keyur Desai		ad->basedn = adutils_dns2dn(domain_name);
515e3f2c99Keyur Desai	} else {
516e3f2c99Keyur Desai		assert(domain_name == NULL);
517e3f2c99Keyur Desai		ad->basedn = strdup("");
518e3f2c99Keyur Desai	}
519e3f2c99Keyur Desai	if (ad->basedn == NULL)
5202b4a780Baban Kenkre		goto err;
521e3f2c99Keyur Desai
5222b4a780Baban Kenkre	if (pthread_mutex_init(&ad->lock, NULL) != 0)
5232b4a780Baban Kenkre		goto err;
5242b4a780Baban Kenkre	*new_ad = ad;
5252b4a780Baban Kenkre	return (ADUTILS_SUCCESS);
5262b4a780Baban Kenkre
5272b4a780Baban Kenkreerr:
528e3f2c99Keyur Desai	free(ad->basedn);
5292b4a780Baban Kenkre	free(ad);
5302b4a780Baban Kenkre	return (ADUTILS_ERR_MEMORY);
5312b4a780Baban Kenkre}
5322b4a780Baban Kenkre
5332b4a780Baban Kenkrevoid
5342b4a780Baban Kenkreadutils_ad_free(adutils_ad_t **ad)
5352b4a780Baban Kenkre{
5362b4a780Baban Kenkre	adutils_host_t *p;
5372b4a780Baban Kenkre	adutils_host_t *prev;
5382b4a780Baban Kenkre
5392b4a780Baban Kenkre	if (ad == NULL || *ad == NULL)
5402b4a780Baban Kenkre		return;
5412b4a780Baban Kenkre
5422b4a780Baban Kenkre	(void) pthread_mutex_lock(&(*ad)->lock);
5432b4a780Baban Kenkre
5442b4a780Baban Kenkre	if (atomic_dec_32_nv(&(*ad)->ref) > 0) {
5452b4a780Baban Kenkre		(void) pthread_mutex_unlock(&(*ad)->lock);
5462b4a780Baban Kenkre		*ad = NULL;
5472b4a780Baban Kenkre		return;
5482b4a780Baban Kenkre	}
5492b4a780Baban Kenkre
5502b4a780Baban Kenkre	(void) pthread_mutex_lock(&adhostlock);
5512b4a780Baban Kenkre	prev = NULL;
5522b4a780Baban Kenkre	p = host_head;
5532b4a780Baban Kenkre	while (p != NULL) {
5542b4a780Baban Kenkre		if (p->owner != (*ad)) {
5552b4a780Baban Kenkre			prev = p;
5562b4a780Baban Kenkre			p = p->next;
5572b4a780Baban Kenkre			continue;
5582b4a780Baban Kenkre		} else {
5592b4a780Baban Kenkre			delete_ds((*ad), p->host, p->port);
5602b4a780Baban Kenkre			if (prev == NULL)
5612b4a780Baban Kenkre				p = host_head;
5622b4a780Baban Kenkre			else
5632b4a780Baban Kenkre				p = prev->next;
5642b4a780Baban Kenkre		}
5652b4a780Baban Kenkre	}
5662b4a780Baban Kenkre	(void) pthread_mutex_unlock(&adhostlock);
5672b4a780Baban Kenkre
5682b4a780Baban Kenkre	(void) pthread_mutex_unlock(&(*ad)->lock);
5692b4a780Baban Kenkre	(void) pthread_mutex_destroy(&(*ad)->lock);
5702b4a780Baban Kenkre
5714d61c87Julian Pullen	if ((*ad)->known_domains)
5724d61c87Julian Pullen		free((*ad)->known_domains);
573e3f2c99Keyur Desai	free((*ad)->basedn);
5742b4a780Baban Kenkre	free(*ad);
5752b4a780Baban Kenkre
5762b4a780Baban Kenkre	*ad = NULL;
5772b4a780Baban Kenkre}
5782b4a780Baban Kenkre
5792b4a780Baban Kenkrestatic
5802b4a780Baban Kenkreint
5812b4a780Baban Kenkreopen_conn(adutils_host_t *adh, int timeoutsecs)
5822b4a780Baban Kenkre{
5832b4a780Baban Kenkre	int zero = 0;
5842b4a780Baban Kenkre	int ldversion, rc;
5852b4a780Baban Kenkre	int timeoutms = timeoutsecs * 1000;
5862b4a780Baban Kenkre
5872b4a780Baban Kenkre	if (adh == NULL)
5882b4a780Baban Kenkre		return (0);
5892b4a780Baban Kenkre
5902b4a780Baban Kenkre	(void) pthread_mutex_lock(&adh->lock);
5912b4a780Baban Kenkre
5922b4a780Baban Kenkre	if (!adh->dead && adh->ld != NULL)
5932b4a780Baban Kenkre		/* done! */
5942b4a780Baban Kenkre		goto out;
5952b4a780Baban Kenkre
5962b4a780Baban Kenkre	if (adh->ld != NULL) {
5972b4a780Baban Kenkre		(void) ldap_unbind(adh->ld);
5982b4a780Baban Kenkre		adh->ld = NULL;
5992b4a780Baban Kenkre	}
6002b4a780Baban Kenkre	adh->num_requests = 0;
6012b4a780Baban Kenkre
6022b4a780Baban Kenkre	atomic_inc_64(&adh->generation);
6032b4a780Baban Kenkre
6042b4a780Baban Kenkre	/* Open and bind an LDAP connection */
6052b4a780Baban Kenkre	adh->ld = ldap_init(adh->host, adh->port);
6062b4a780Baban Kenkre	if (adh->ld == NULL) {
6077a8a68fJulian Pullen		logger(LOG_INFO, "ldap_init() to server "
6082b4a780Baban Kenkre		    "%s port %d failed. (%s)", adh->host,
6092b4a780Baban Kenkre		    adh->port, strerror(errno));
6102b4a780Baban Kenkre		goto out;
6112b4a780Baban Kenkre	}
6122b4a780Baban Kenkre	ldversion = LDAP_VERSION3;
6132b4a780Baban Kenkre	(void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion);
6142b4a780Baban Kenkre	(void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
6152b4a780Baban Kenkre	(void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero);
6162b4a780Baban Kenkre	(void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero);
6172b4a780Baban Kenkre	(void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms);
6182b4a780Baban Kenkre	(void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
619bd42852Julian Pullen
620bd42852Julian Pullen	rc = adutils_set_thread_functions(adh->ld);
621bd42852Julian Pullen	if (rc != LDAP_SUCCESS) {
622bd42852Julian Pullen		/* Error has already been logged */
623bd42852Julian Pullen		(void) ldap_unbind(adh->ld);
624bd42852Julian Pullen		adh->ld = NULL;
625bd42852Julian Pullen		goto out;
626bd42852Julian Pullen	}
627bd42852Julian Pullen
6282b4a780Baban Kenkre	rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */,
6292b4a780Baban Kenkre	    adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback,
6302b4a780Baban Kenkre	    NULL);
6312b4a780Baban Kenkre
6322b4a780Baban Kenkre	if (rc != LDAP_SUCCESS) {
6332b4a780Baban Kenkre		(void) ldap_unbind(adh->ld);
6342b4a780Baban Kenkre		adh->ld = NULL;
6357a8a68fJulian Pullen		logger(LOG_INFO, "ldap_sasl_interactive_bind_s() to server "
6362b4a780Baban Kenkre		    "%s port %d failed. (%s)", adh->host, adh->port,
6372b4a780Baban Kenkre		    ldap_err2string(rc));
638e3f2c99Keyur Desai		goto out;
6392b4a780Baban Kenkre	}
6402b4a780Baban Kenkre
641e3f2c99Keyur Desai	logger(LOG_DEBUG, "Using server %s:%d",
6422b4a780Baban Kenkre	    adh->host, adh->port);
6432b4a780Baban Kenkre
6442b4a780Baban Kenkreout:
6452b4a780Baban Kenkre	if (adh->ld != NULL) {
6462b4a780Baban Kenkre		atomic_inc_32(&adh->ref);
6472b4a780Baban Kenkre		adh->idletime = time(NULL);
6482b4a780Baban Kenkre		adh->dead = 0;
6492b4a780Baban Kenkre		(void) pthread_mutex_unlock(&adh->lock);
6502b4a780Baban Kenkre		return (1);
6512b4a780Baban Kenkre	}
6522b4a780Baban Kenkre
6532b4a780Baban Kenkre	(void) pthread_mutex_unlock(&adh->lock);
6542b4a780Baban Kenkre	return (0);
6552b4a780Baban Kenkre}
6562b4a780Baban Kenkre
6572b4a780Baban Kenkre
6582b4a780Baban Kenkre/*
6592b4a780Baban Kenkre * Connection management: find an open connection or open one
6602b4a780Baban Kenkre */
6612b4a780Baban Kenkrestatic
6622b4a780Baban Kenkreadutils_host_t *
6632b4a780Baban Kenkreget_conn(adutils_ad_t *ad)
6642b4a780Baban Kenkre{
6652b4a780Baban Kenkre	adutils_host_t	*adh = NULL;
6662b4a780Baban Kenkre	int		tries;
6672b4a780Baban Kenkre	int		dscount = 0;
6682b4a780Baban Kenkre	int		timeoutsecs = ADUTILS_LDAP_OPEN_TIMEOUT;
6692b4a780Baban Kenkre
6702b4a780Baban Kenkreretry:
6712b4a780Baban Kenkre	(void) pthread_mutex_lock(&adhostlock);
6722b4a780Baban Kenkre
6732b4a780Baban Kenkre	if (host_head == NULL) {
6742b4a780Baban Kenkre		(void) pthread_mutex_unlock(&adhostlock);
6752b4a780Baban Kenkre		goto out;
6762b4a780Baban Kenkre	}
6772b4a780Baban Kenkre
6782b4a780Baban Kenkre	if (dscount == 0) {
6792b4a780Baban Kenkre		/*
6802b4a780Baban Kenkre		 * First try: count the number of DSes.
6812b4a780Baban Kenkre		 *
6822b4a780Baban Kenkre		 * Integer overflow is not an issue -- we can't have so many
6832b4a780Baban Kenkre		 * DSes because they won't fit even DNS over TCP, and SMF
6842b4a780Baban Kenkre		 * shouldn't let you set so many.
6852b4a780Baban Kenkre		 */
6862b4a780Baban Kenkre		for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) {
6872b4a780Baban Kenkre			if (adh->owner == ad)
6882b4a780Baban Kenkre				dscount++;
6892b4a780Baban Kenkre		}
6902b4a780Baban Kenkre
6912b4a780Baban Kenkre		if (dscount == 0) {
6922b4a780Baban Kenkre			(void) pthread_mutex_unlock(&adhostlock);
6932b4a780Baban Kenkre			goto out;
6942b4a780Baban Kenkre		}
6952b4a780Baban Kenkre
6962b4a780Baban Kenkre		tries = dscount * 3;	/* three tries per-ds */
6972b4a780Baban Kenkre
6982b4a780Baban Kenkre		/*
6992b4a780Baban Kenkre		 * Begin round-robin at the next DS in the list after the last
7002b4a780Baban Kenkre		 * one that we had a connection to, else start with the first
7012b4a780Baban Kenkre		 * DS in the list.
7022b4a780Baban Kenkre		 */
7032b4a780Baban Kenkre		adh = ad->last_adh;
7042b4a780Baban Kenkre	}
7052b4a780Baban Kenkre
7062b4a780Baban Kenkre	/*
7072b4a780Baban Kenkre	 * Round-robin -- pick the next one on the list; if the list
7082b4a780Baban Kenkre	 * changes on us, no big deal, we'll just potentially go
7092b4a780Baban Kenkre	 * around the wrong number of times.
7102b4a780Baban Kenkre	 */
7112b4a780Baban Kenkre	for (;;) {
7124d61c87Julian Pullen		if (adh != NULL && adh->owner == ad && adh->ld != NULL &&
7134d61c87Julian Pullen		    !adh->dead)
7142b4a780Baban Kenkre			break;
7152b4a780Baban Kenkre		if (adh == NULL || (adh = adh->next) == NULL)
7162b4a780Baban Kenkre			adh = host_head;
7172b4a780Baban Kenkre		if (adh->owner == ad)
7182b4a780Baban Kenkre			break;
7192b4a780Baban Kenkre	}
7202b4a780Baban Kenkre
7212b4a780Baban Kenkre	ad->last_adh = adh;
7222b4a780Baban Kenkre	(void) pthread_mutex_unlock(&adhostlock);
7232b4a780Baban Kenkre
7242b4a780Baban Kenkre	/* Found suitable DS, open it if not already opened */
7252b4a780Baban Kenkre	if (open_conn(adh, timeoutsecs))
7262b4a780Baban Kenkre		return (adh);
7272b4a780Baban Kenkre
7282b4a780Baban Kenkre	tries--;
7292b4a780Baban Kenkre	if ((tries % dscount) == 0)
7302b4a780Baban Kenkre		timeoutsecs *= 2;
7312b4a780Baban Kenkre	if (tries > 0)
7322b4a780Baban Kenkre		goto retry;
7332b4a780Baban Kenkre
7342b4a780Baban Kenkreout:
7357a8a68fJulian Pullen	logger(LOG_NOTICE, "Couldn't open an LDAP connection to any global "
7362b4a780Baban Kenkre	    "catalog server!");
7372b4a780Baban Kenkre	return (NULL);
7382b4a780Baban Kenkre}
7392b4a780Baban Kenkre
7402b4a780Baban Kenkrestatic
7412b4a780Baban Kenkrevoid
7422b4a780Baban Kenkrerelease_conn(adutils_host_t *adh)
7432b4a780Baban Kenkre{
7442b4a780Baban Kenkre	int delete = 0;
7452b4a780Baban Kenkre
7462b4a780Baban Kenkre	(void) pthread_mutex_lock(&adh->lock);
7472b4a780Baban Kenkre	if (atomic_dec_32_nv(&adh->ref) == 0) {
7482b4a780Baban Kenkre		if (adh->owner == NULL)
7492b4a780Baban Kenkre			delete = 1;
7502b4a780Baban Kenkre		adh->idletime = time(NULL);
7512b4a780Baban Kenkre	}
7522b4a780Baban Kenkre	(void) pthread_mutex_unlock(&adh->lock);
7532b4a780Baban Kenkre
7542b4a780Baban Kenkre	/* Free this host if its owner no longer exists. */
7552b4a780Baban Kenkre	if (delete) {
7562b4a780Baban Kenkre		(void) pthread_mutex_lock(&adhostlock);
7572b4a780Baban Kenkre		delete_ds(NULL, adh->host, adh->port);
7582b4a780Baban Kenkre		(void) pthread_mutex_unlock(&adhostlock);
7592b4a780Baban Kenkre	}
7602b4a780Baban Kenkre}
7612b4a780Baban Kenkre
7622b4a780Baban Kenkre/*
7632b4a780Baban Kenkre * Create a adutils_host_t, populate it and add it to the list of hosts.
7642b4a780Baban Kenkre */
7652b4a780Baban Kenkreadutils_rc
7662b4a780Baban Kenkreadutils_add_ds(adutils_ad_t *ad, const char *host, int port)
7672b4a780Baban Kenkre{
7682b4a780Baban Kenkre	adutils_host_t	*p;
7692b4a780Baban Kenkre	adutils_host_t	*new = NULL;
7702b4a780Baban Kenkre	int		ret;
7712b4a780Baban Kenkre	adutils_rc	rc;
7722b4a780Baban Kenkre
7732b4a780Baban Kenkre	(void) pthread_mutex_lock(&adhostlock);
7742b4a780Baban Kenkre	for (p = host_head; p != NULL; p = p->next) {
7752b4a780Baban Kenkre		if (p->owner != ad)
7762b4a780Baban Kenkre			continue;
7772b4a780Baban Kenkre
7782b4a780Baban Kenkre		if (strcmp(host, p->host) == 0 && p->port == port) {
7792b4a780Baban Kenkre			/* already added */
7802b4a780Baban Kenkre			rc = ADUTILS_SUCCESS;
7812b4a780Baban Kenkre			goto err;
7822b4a780Baban Kenkre		}
7832b4a780Baban Kenkre	}
7842b4a780Baban Kenkre
7852b4a780Baban Kenkre	rc = ADUTILS_ERR_MEMORY;
7862b4a780Baban Kenkre
7872b4a780Baban Kenkre	/* add new entry */
7882b4a780Baban Kenkre	new = (adutils_host_t *)calloc(1, sizeof (*new));
7892b4a780Baban Kenkre	if (new == NULL)
7902b4a780Baban Kenkre		goto err;
7912b4a780Baban Kenkre	new->owner = ad;
7922b4a780Baban Kenkre	new->port = port;
7932b4a780Baban Kenkre	new->dead = 0;
7942b4a780Baban Kenkre	new->max_requests = 80;
7952b4a780Baban Kenkre	new->num_requests = 0;
7962b4a780Baban Kenkre	if ((new->host = strdup(host)) == NULL)
7972b4a780Baban Kenkre		goto err;
7982b4a780Baban Kenkre	new->saslflags = LDAP_SASL_INTERACTIVE;
7992b4a780Baban Kenkre	new->saslmech = "GSSAPI";
8002b4a780Baban Kenkre
8012b4a780Baban Kenkre	if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) {
8022b4a780Baban Kenkre		free(new->host);
8032b4a780Baban Kenkre		new->host = NULL;
8042b4a780Baban Kenkre		errno = ret;
8052b4a780Baban Kenkre		rc = ADUTILS_ERR_INTERNAL;
8062b4a780Baban Kenkre		goto err;
8072b4a780Baban Kenkre	}
8082b4a780Baban Kenkre
8092b4a780Baban Kenkre	/* link in */
8102b4a780Baban Kenkre	rc = ADUTILS_SUCCESS;
8112b4a780Baban Kenkre	new->next = host_head;
8122b4a780Baban Kenkre	host_head = new;
8132b4a780Baban Kenkre
8142b4a780Baban Kenkreerr:
8152b4a780Baban Kenkre	(void) pthread_mutex_unlock(&adhostlock);
8162b4a780Baban Kenkre
8172b4a780Baban Kenkre	if (rc != 0 && new != NULL) {
8182b4a780Baban Kenkre		if (new->host != NULL) {
8192b4a780Baban Kenkre			(void) pthread_mutex_destroy(&new->lock);
8202b4a780Baban Kenkre			free(new->host);
8212b4a780Baban Kenkre		}
8222b4a780Baban Kenkre		free(new);
8232b4a780Baban Kenkre	}
8242b4a780Baban Kenkre
8252b4a780Baban Kenkre	return (rc);
8262b4a780Baban Kenkre}
8272b4a780Baban Kenkre
8282b4a780Baban Kenkre/*
8292b4a780Baban Kenkre * Free a DS configuration.
8302b4a780Baban Kenkre * Caller must lock the adhostlock mutex
8312b4a780Baban Kenkre */
8322b4a780Baban Kenkrestatic
8332b4a780Baban Kenkrevoid
8342b4a780Baban Kenkredelete_ds(adutils_ad_t *ad, const char *host, int port)
8352b4a780Baban Kenkre{
8362b4a780Baban Kenkre	adutils_host_t	**p, *q;
8372b4a780Baban Kenkre
8382b4a780Baban Kenkre	for (p = &host_head; *p != NULL; p = &((*p)->next)) {
8392b4a780Baban Kenkre		if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 ||
8402b4a780Baban Kenkre		    (*p)->port != port)
8412b4a780Baban Kenkre			continue;
8422b4a780Baban Kenkre		/* found */
8432b4a780Baban Kenkre
8442b4a780Baban Kenkre		(void) pthread_mutex_lock(&((*p)->lock));
8452b4a780Baban Kenkre		if ((*p)->ref > 0) {
8462b4a780Baban Kenkre			/*
8472b4a780Baban Kenkre			 * Still in use. Set its owner to NULL so
8482b4a780Baban Kenkre			 * that it can be freed when its ref count
8492b4a780Baban Kenkre			 * becomes 0.
8502b4a780Baban Kenkre			 */
8512b4a780Baban Kenkre			(*p)->owner = NULL;
8522b4a780Baban Kenkre			(void) pthread_mutex_unlock(&((*p)->lock));
8532b4a780Baban Kenkre			break;
8542b4a780Baban Kenkre		}
8552b4a780Baban Kenkre		(void) pthread_mutex_unlock(&((*p)->lock));
8562b4a780Baban Kenkre
8572b4a780Baban Kenkre		q = *p;
8582b4a780Baban Kenkre		*p = (*p)->next;
8592b4a780Baban Kenkre
8602b4a780Baban Kenkre		(void) pthread_mutex_destroy(&q->lock);
8612b4a780Baban Kenkre
8622b4a780Baban Kenkre		if (q->ld)
8632b4a780Baban Kenkre			(void) ldap_unbind(q->ld);
8642b4a780Baban Kenkre		if (q->host)
8652b4a780Baban Kenkre			free(q->host);
8662b4a780Baban Kenkre		free(q);
8672b4a780Baban Kenkre		break;
8682b4a780Baban Kenkre	}
8692b4a780Baban Kenkre
8702b4a780Baban Kenkre}
8714d61c87Julian Pullen/*
8724d61c87Julian Pullen * Add known domain name and domain SID to AD configuration.
8734d61c87Julian Pullen */
8744d61c87Julian Pullen
8754d61c87Julian Pullenadutils_rc
8764d61c87Julian Pullenadutils_add_domain(adutils_ad_t *ad, const char *domain, const char *sid)
8774d61c87Julian Pullen{
8784d61c87Julian Pullen	struct known_domain *new;
8794d61c87Julian Pullen	int num = ad->num_known_domains;
8804d61c87Julian Pullen
8814d61c87Julian Pullen	ad->num_known_domains++;
8824d61c87Julian Pullen	new = realloc(ad->known_domains,
8834d61c87Julian Pullen	    sizeof (struct known_domain) * ad->num_known_domains);
8844d61c87Julian Pullen	if (new != NULL) {
8854d61c87Julian Pullen		ad->known_domains = new;
8864d61c87Julian Pullen		(void) strlcpy(ad->known_domains[num].name, domain,
8874d61c87Julian Pullen		    sizeof (ad->known_domains[num].name));
8884d61c87Julian Pullen		(void) strlcpy(ad->known_domains[num].sid, sid,
8894d61c87Julian Pullen		    sizeof (ad->known_domains[num].sid));
8904d61c87Julian Pullen		return (ADUTILS_SUCCESS);
8914d61c87Julian Pullen	} else {
8924d61c87Julian Pullen		if (ad->known_domains != NULL) {
8934d61c87Julian Pullen			free(ad->known_domains);
8944d61c87Julian Pullen			ad->known_domains = NULL;
8954d61c87Julian Pullen		}
8964d61c87Julian Pullen		ad->num_known_domains = 0;
8974d61c87Julian Pullen		return (ADUTILS_ERR_MEMORY);
8984d61c87Julian Pullen	}
8994d61c87Julian Pullen}
9004d61c87Julian Pullen
9014d61c87Julian Pullen
9024d61c87Julian Pullen/*
9034d61c87Julian Pullen * Check that this AD supports this domain.
9044d61c87Julian Pullen * If there are no known domains assume that the
9054d61c87Julian Pullen * domain is supported by this AD.
9064d61c87Julian Pullen *
9074d61c87Julian Pullen * Returns 1 if this domain is supported by this AD
9084d61c87Julian Pullen * else returns 0;
9094d61c87Julian Pullen */
9104d61c87Julian Pullen
9114d61c87Julian Pullenint
9124d61c87Julian Pullenadutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain)
9134d61c87Julian Pullen{
9144d61c87Julian Pullen	adutils_ad_t *ad = qs->qadh->owner;
9151fcced4Jordan Brown	int i;
9164d61c87Julian Pullen
9174d61c87Julian Pullen	for (i = 0; i < ad->num_known_domains; i++) {
9181fcced4Jordan Brown		if (domain_eq(domain, ad->known_domains[i].name))
9194d61c87Julian Pullen			return (1);
9204d61c87Julian Pullen	}
9214d61c87Julian Pullen
9224d61c87Julian Pullen	return ((i == 0) ? 1 : 0);
9234d61c87Julian Pullen}
9244d61c87Julian Pullen
9254d61c87Julian Pullen
9264d61c87Julian Pullen/*
9274d61c87Julian Pullen * Check that this AD supports the SID prefix.
9284d61c87Julian Pullen * The SID prefix should match the domain SID.
9294d61c87Julian Pullen * If there are no known domains assume that the
9304d61c87Julian Pullen * SID prefix is supported by this AD.
9314d61c87Julian Pullen *
9324d61c87Julian Pullen * Returns 1 if this sid prefix is supported by this AD
9334d61c87Julian Pullen * else returns 0;
9344d61c87Julian Pullen */
9354d61c87Julian Pullen
9364d61c87Julian Pullenint
9374d61c87Julian Pullenadutils_lookup_check_sid_prefix(adutils_query_state_t *qs, const char *sid)
9384d61c87Julian Pullen{
9394d61c87Julian Pullen	adutils_ad_t *ad = qs->qadh->owner;
9404d61c87Julian Pullen	int i;
9414d61c87Julian Pullen
9424d61c87Julian Pullen
9434d61c87Julian Pullen	for (i = 0; i < ad->num_known_domains; i++) {
9444d61c87Julian Pullen		if (strcmp(sid, ad->known_domains[i].sid) == 0)
9454d61c87Julian Pullen			return (1);
9464d61c87Julian Pullen	}
9474d61c87Julian Pullen
9484d61c87Julian Pullen	return ((i == 0) ? 1 : 0);
9494d61c87Julian Pullen}
9504d61c87Julian Pullen
9512b4a780Baban Kenkre
9522b4a780Baban Kenkreadutils_rc
9532b4a780Baban Kenkreadutils_lookup_batch_start(adutils_ad_t *ad, int nqueries,
9542b4a780Baban Kenkre	adutils_ldap_res_search_cb ldap_res_search_cb,
9552b4a780Baban Kenkre	void *ldap_res_search_argp,
9562b4a780Baban Kenkre	adutils_query_state_t **state)
9572b4a780Baban Kenkre{
9582b4a780Baban Kenkre	adutils_query_state_t	*new_state;
9592b4a780Baban Kenkre	adutils_host_t		*adh = NULL;
9602b4a780Baban Kenkre
9612b4a780Baban Kenkre	if (ad == NULL)
9622b4a780Baban Kenkre		return (ADUTILS_ERR_INTERNAL);
9632b4a780Baban Kenkre
9642b4a780Baban Kenkre	*state = NULL;
9652b4a780Baban Kenkre	adh = get_conn(ad);
9662b4a780Baban Kenkre	if (adh == NULL)
9672b4a780Baban Kenkre		return (ADUTILS_ERR_RETRIABLE_NET_ERR);
9682b4a780Baban Kenkre
9692b4a780Baban Kenkre	new_state = calloc(1, sizeof (adutils_query_state_t) +
9702b4a780Baban Kenkre	    (nqueries - 1) * sizeof (adutils_q_t));
9712b4a780Baban Kenkre	if (new_state == NULL)
9722b4a780Baban Kenkre		return (ADUTILS_ERR_MEMORY);
9732b4a780Baban Kenkre
9742b4a780Baban Kenkre	new_state->ref_cnt = 1;
9752b4a780Baban Kenkre	new_state->qadh = adh;
9764d61c87Julian Pullen	new_state->qsize = nqueries;
9772b4a780Baban Kenkre	new_state->qadh_gen = adh->generation;
9784d61c87Julian Pullen	new_state->qcount = 0;
9792b4a780Baban Kenkre	new_state->ldap_res_search_cb = ldap_res_search_cb;
9802b4a780Baban Kenkre	new_state->ldap_res_search_argp = ldap_res_search_argp;
9812b4a780Baban Kenkre	(void) pthread_cond_init(&new_state->cv, NULL);
9822b4a780Baban Kenkre
9832b4a780Baban Kenkre	(void) pthread_mutex_lock(&qstatelock);
9842b4a780Baban Kenkre	new_state->next = qstatehead;
9852b4a780Baban Kenkre	qstatehead = new_state;
9862b4a780Baban Kenkre	(void) pthread_mutex_unlock(&qstatelock);
9872b4a780Baban Kenkre	*state = new_state;
9882b4a780Baban Kenkre
9892b4a780Baban Kenkre	return (ADUTILS_SUCCESS);
9902b4a780Baban Kenkre}
9912b4a780Baban Kenkre
9922b4a780Baban Kenkre/*
9932b4a780Baban Kenkre * Find the adutils_query_state_t to which a given LDAP result msgid on a
9942b4a780Baban Kenkre * given connection belongs. This routine increaments the reference count
9952b4a780Baban Kenkre * so that the object can not be freed. adutils_lookup_batch_unlock()
9962b4a780Baban Kenkre * must be called to decreament the reference count.
9972b4a780Baban Kenkre */
9982b4a780Baban Kenkrestatic
9992b4a780Baban Kenkreint
10002b4a780Baban Kenkremsgid2query(adutils_host_t *adh, int msgid,
10012b4a780Baban Kenkre	adutils_query_state_t **state, int *qid)
10022b4a780Baban Kenkre{
10032b4a780Baban Kenkre	adutils_query_state_t	*p;
10042b4a780Baban Kenkre	int			i;
10052b4a780Baban Kenkre	int			ret;
10062b4a780Baban Kenkre
10072b4a780Baban Kenkre	(void) pthread_mutex_lock(&qstatelock);
10082b4a780Baban Kenkre	for (p = qstatehead; p != NULL; p = p->next) {
10092b4a780Baban Kenkre		if (p->qadh != adh || adh->generation != p->qadh_gen)
10102b4a780Baban Kenkre			continue;
10112b4a780Baban Kenkre		for (i = 0; i < p->qcount; i++) {
10122b4a780Baban Kenkre			if ((p->queries[i]).msgid == msgid) {
10132b4a780Baban Kenkre				if (!p->qdead) {
10142b4a780Baban Kenkre					p->ref_cnt++;
10152b4a780Baban Kenkre					*state = p;
10162b4a780Baban Kenkre					*qid = i;
10172b4a780Baban Kenkre					ret = 1;
10182b4a780Baban Kenkre				} else
10192b4a780Baban Kenkre					ret = 0;
10202b4a780Baban Kenkre				(void) pthread_mutex_unlock(&qstatelock);
10212b4a780Baban Kenkre				return (ret);
10222b4a780Baban Kenkre			}
10232b4a780Baban Kenkre		}
10242b4a780Baban Kenkre	}
10252b4a780Baban Kenkre	(void) pthread_mutex_unlock(&qstatelock);
10262b4a780Baban Kenkre	return (0);
10272b4a780Baban Kenkre}
10282b4a780Baban Kenkre
10292b4a780Baban Kenkrestatic
10302b4a780Baban Kenkreint
10312b4a780Baban Kenkrecheck_for_binary_attrs(const char *attr)
10322b4a780Baban Kenkre{
10332b4a780Baban Kenkre	int i;
10342b4a780Baban Kenkre	for (i = 0; binattrs[i].name != NULL; i++) {
10352b4a780Baban Kenkre		if (strcasecmp(binattrs[i].name, attr) == 0)
10362b4a780Baban Kenkre			return (i);
10372b4a780Baban Kenkre	}
10382b4a780Baban Kenkre	return (-1);
10392b4a780Baban Kenkre}
10402b4a780Baban Kenkre
10412b4a780Baban Kenkrestatic
10422b4a780Baban Kenkrevoid
10432b4a780Baban Kenkrefree_entry(adutils_entry_t *entry)
10442b4a780Baban Kenkre{
10452b4a780Baban Kenkre	int		i, j;
10462b4a780Baban Kenkre	adutils_attr_t	*ap;
10472b4a780Baban Kenkre
10482b4a780Baban Kenkre	if (entry == NULL)
10492b4a780Baban Kenkre		return;
10502b4a780Baban Kenkre	if (entry->attr_nvpairs == NULL) {
1051