2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * CDDL HEADER START
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * The contents of this file are subject to the terms of the
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Common Development and Distribution License (the "License").
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * You may not use this file except in compliance with the License.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * See the License for the specific language governing permissions
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * and limitations under the License.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * When distributing Covered Code, include this CDDL HEADER in each
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * If applicable, add the following below this CDDL HEADER, with the
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * fields enclosed by brackets "[]" replaced with your own identifying
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * information: Portions Copyright [yyyy] [name of copyright owner]
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * CDDL HEADER END
148c5f43199ca0b43fc8e3b643aab11cd66ea327Alan Wright * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre/* List of DSs, needed by the idle connection reaper thread */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkrestatic pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * List of query state structs -- needed so we can "route" LDAP results
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * to the right context if multiple threads should be using the same
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * connection concurrently
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkrestatic pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkrestatic adutils_query_state_t *qstatehead = NULL;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkrestatic char *adutils_sid_ber2str(BerValue *bvalues);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkrestatic void adutils_lookup_batch_unlock(adutils_query_state_t **state);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkrestatic void delete_ds(adutils_ad_t *ad, const char *host, int port);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com"
7a8a68f5e3efbaec1a375c2d50bd20b566631755Julian Pullen return (ldap_dns_to_dn((char *)dns, &num_parts));
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * attributes (CN, etc...).
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Convert a binary SID in a BerValue to a adutils_sid_t
7a8a68f5e3efbaec1a375c2d50bd20b566631755Julian Pullenadutils_getsid(BerValue *bval, adutils_sid_t *sidp)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * The binary format of a SID is as follows:
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * byte #0: version, always 0x01
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * byte #1: RID count, always <= 0x0f
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * bytes #2-#7: SID authority, big-endian 48-bit unsigned int
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * followed by RID count RIDs, each a little-endian, unsigned
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * 32-bit int.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Sanity checks: must have at least one RID, version must be
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * 0x01, and the length must be 8 + rid count * 4
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 &&
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* big endian -- so start from the left */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (i = 0; i < sidp->sub_authority_count; i++) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* little endian -- so start from the right */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Convert a adutils_sid_t to S-1-...
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * We could optimize like so, but, why?
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * if (sidp->authority < 10)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * else if (sidp->authority < 100)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * len += snprintf(NULL, 0"%llu", sidp->authority);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre len += snprintf(NULL, 0, "%llu", sidp->authority);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Max length of a uint32_t printed out in ASCII is 10 bytes */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre len += 1 + (sidp->sub_authority_count + 1) * 10;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre rlen = snprintf(str, len, "S-1-%llu", sidp->authority);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (i = 0; i < sidp->sub_authority_count; i++) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Convert a adutils_sid_t to on-the-wire encoding
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkresid2binsid(adutils_sid_t *sid, uchar_t *binsid, int binsidlen)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4))
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* sub authority count */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Authority */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* big-endian -- start from left */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre *p++ = a & 0xFF;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* sub-authorities */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (i = 0; i < sid->sub_authority_count; i++) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* little-endian -- start from right */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre *p++ = (r & 0x000000FF);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Convert a stringified SID (S-1-...) into a hex-encoded version of the
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * on-the-wire encoding, but with each pair of hex digits pre-pended
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * with a '\', so we can pass this to libldap.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_txtsid2hexbinsid(const char *txt, const uint32_t *rid,
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre unsigned long r;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Only version 1 SIDs please */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* count '-'s */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* can't end on a '-' */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Adjust count for version and authority */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* we know the version number and RID count */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre sid.sub_authority_count = (rid != NULL) ? j + 1 : j;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* must have at least one RID, but not too many */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre sid.sub_authority_count > ADUTILS_SID_MAX_SUB_AUTHORITIES)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* check that we only have digits and '-' */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1))
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* 64-bit safe parsing of unsigned 48-bit authority value */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* errors parsing the authority or too many bits */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (cp == ecp || (a == 0 && errno == EINVAL) ||
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (a & 0x0000ffffffffffffULL) != a)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (i = 0; i < j; i++) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* 64-bit safe parsing of unsigned 32-bit RID */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* errors parsing the RID or too many bits */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (cp == ecp || (r == 0 && errno == EINVAL) ||
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (r & 0xffffffffUL) != r)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* check that all of the string SID has been consumed */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-2);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* binary encode the SID */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* hex encode, with a backslash before each byte */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A');
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * If desired and if the SID is what should be a domain/computer
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * save the last RID and truncate the SID
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre *rid = sid.sub_authorities[--sid.sub_authority_count];
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Return a NUL-terminated stringified SID from the value of an
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * objectSid attribute and put the last RID in *rid.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_bv_objsid2sidstr(BerValue *bval, uint32_t *rid)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* objectSid is single valued */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if ((sid = convert_bval2sid(bval, rid)) == NULL)
e3f2c991a8548408db0a2787bd8b43d5124821d3Keyur Desai * Extract an int from the Ber value
e3f2c991a8548408db0a2787bd8b43d5124821d3Keyur Desai * Return B_TRUE if a valid integer was found, B_FALSE if not.
e3f2c991a8548408db0a2787bd8b43d5124821d3Keyur Desaiadutils_bv_uint(BerValue *bval, unsigned int *result)
e3f2c991a8548408db0a2787bd8b43d5124821d3Keyur Desai /* Junk after the number? */
e3f2c991a8548408db0a2787bd8b43d5124821d3Keyur Desai if (*p != '\0')
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre/* Return a NUL-terminated string from the Ber value */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) snprintf(s, bval->bv_len + 1, "%.*s", bval->bv_len,
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkresaslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* There should be no extra arguemnts for SASL/GSSAPI authentication */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (interact = prompts; interact->id != SASL_CB_LIST_END;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Idle connection reaping side of connection management
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (adh = host_head; adh != NULL; adh = adh->next) {
e3f2c991a8548408db0a2787bd8b43d5124821d3Keyur Desaiadutils_ad_alloc(adutils_ad_t **new_ad, const char *domain_name,
e3f2c991a8548408db0a2787bd8b43d5124821d3Keyur Desai /* domain_name is required iff we are talking directly to a DC */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre while (p != NULL) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Open and bind an LDAP connection */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON);
bd42852645f5ef79a1729096abd7405b72e159f7Julian Pullen /* Error has already been logged */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */,
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback,
7a8a68f5e3efbaec1a375c2d50bd20b566631755Julian Pullen logger(LOG_INFO, "ldap_sasl_interactive_bind_s() to server "
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "%s port %d failed. (%s)", adh->host, adh->port,
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Connection management: find an open connection or open one
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * First try: count the number of DSes.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Integer overflow is not an issue -- we can't have so many
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * DSes because they won't fit even DNS over TCP, and SMF
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * shouldn't let you set so many.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Begin round-robin at the next DS in the list after the last
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * one that we had a connection to, else start with the first
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * DS in the list.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Round-robin -- pick the next one on the list; if the list
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * changes on us, no big deal, we'll just potentially go
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * around the wrong number of times.
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen if (adh != NULL && adh->owner == ad && adh->ld != NULL &&
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Found suitable DS, open it if not already opened */
7a8a68f5e3efbaec1a375c2d50bd20b566631755Julian Pullen logger(LOG_NOTICE, "Couldn't open an LDAP connection to any global "
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "catalog server!");
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Free this host if its owner no longer exists. */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Create a adutils_host_t, populate it and add it to the list of hosts.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_add_ds(adutils_ad_t *ad, const char *host, int port)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (strcmp(host, p->host) == 0 && p->port == port) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* already added */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* add new entry */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre new = (adutils_host_t *)calloc(1, sizeof (*new));
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* link in */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Free a DS configuration.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Caller must lock the adhostlock mutex
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkredelete_ds(adutils_ad_t *ad, const char *host, int port)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (p = &host_head; *p != NULL; p = &((*p)->next)) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 ||
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if ((*p)->ref > 0) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Still in use. Set its owner to NULL so
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * that it can be freed when its ref count
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * becomes 0.
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * Add known domain name and domain SID to AD configuration.
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullenadutils_add_domain(adutils_ad_t *ad, const char *domain, const char *sid)
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen sizeof (struct known_domain) * ad->num_known_domains);
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen (void) strlcpy(ad->known_domains[num].name, domain,
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen (void) strlcpy(ad->known_domains[num].sid, sid,
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * Check that this AD supports this domain.
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * If there are no known domains assume that the
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * domain is supported by this AD.
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * Returns 1 if this domain is supported by this AD
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * else returns 0;
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullenadutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain)
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown if (domain_eq(domain, ad->known_domains[i].name))
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen return ((i == 0) ? 1 : 0);
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * Check that this AD supports the SID prefix.
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * The SID prefix should match the domain SID.
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * If there are no known domains assume that the
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * SID prefix is supported by this AD.
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * Returns 1 if this sid prefix is supported by this AD
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen * else returns 0;
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullenadutils_lookup_check_sid_prefix(adutils_query_state_t *qs, const char *sid)
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen if (strcmp(sid, ad->known_domains[i].sid) == 0)
4d61c878ad5fbf36c5338bef5994cc5fe88a589aJulian Pullen return ((i == 0) ? 1 : 0);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_lookup_batch_start(adutils_ad_t *ad, int nqueries,
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre new_state = calloc(1, sizeof (adutils_query_state_t) +
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre new_state->ldap_res_search_cb = ldap_res_search_cb;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre new_state->ldap_res_search_argp = ldap_res_search_argp;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) pthread_cond_init(&new_state->cv, NULL);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Find the adutils_query_state_t to which a given LDAP result msgid on a
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * given connection belongs. This routine increaments the reference count
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * so that the object can not be freed. adutils_lookup_batch_unlock()
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * must be called to decreament the reference count.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (p->qadh != adh || adh->generation != p->qadh_gen)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (i = 0; i < p->qcount; i++) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (check_for_binary_attrs(ap->attr_name) >= 0) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre } else if (strcasecmp(ap->attr_name, "dn") == 0) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (e = (*result)->entries; e != NULL; e = next) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_getattr(const adutils_entry_t *entry, const char *attrname)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (entry == NULL || entry->attr_nvpairs == NULL)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Queue LDAP result for the given query.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Return values:
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * -1 ignore result
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkremake_entry(adutils_q_t *q, adutils_host_t *adh, LDAPMessage *search_res,
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Check that this is the domain that we were looking for */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if ((dn = ldap_get_dn(adh->ld, search_res)) == NULL)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-2);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-2);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Allocate memory for the entry */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* For 'dn' */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Count the number of name-value pairs for this entry */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (attr = ldap_first_attribute(adh->ld, search_res, &ber);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre attr = ldap_next_attribute(adh->ld, search_res, ber)) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Allocate array for the attribute name-value pairs */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre ep->attr_nvpairs = calloc(ep->num_nvpairs, sizeof (*ep->attr_nvpairs));
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* For dn */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre ap->attr_values = calloc(ap->num_values, sizeof (*ap->attr_values));
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (attr = ldap_first_attribute(adh->ld, search_res, &ber), i = 1;
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre attr = ldap_next_attribute(adh->ld, search_res, ber)) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre ldap_get_values_len(adh->ld, search_res, attr);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre ap->num_values = ldap_count_values_len(bvalues);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre strvalues = ldap_get_values(adh->ld, search_res, attr);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Put the search result onto the given adutils_q_t.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Returns: 0 success
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadd_entry(adutils_host_t *adh, adutils_q_t *q, LDAPMessage *search_res)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* ignore result */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Try to get a result; if there is one, find the corresponding
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * adutils_q_t and process the result.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Returns: 0 success
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreget_adobject_batch(adutils_host_t *adh, struct timeval *timeout)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Get one result */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, timeout, &res);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) ||
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "AD ldap_result error - %d queued requests", num);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre return (-1);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (msgid2query(adh, msgid, &query_state, &qid)) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * We use the caller-provided callback
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * to process the result.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * No callback. We fallback to our
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * default behaviour. All the entries
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * gotten from this search have been
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * added to the result list during
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * LDAP_RES_SEARCH_ENTRY (see below).
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Here we set the return status to
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * notfound if the result is still empty.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "AD cannot find message ID (%d) "
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "- %d queued requests",
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (msgid2query(adh, msgid, &query_state, &qid)) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * We use the caller-provided callback
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * to process the entry.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * No callback. We fallback to our
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * default behaviour. This entry
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * will be added to the result list.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "Failed to queue entry by "
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "message ID (%d) "
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "- %d queued requests",
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "AD cannot find message ID (%d) "
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "- %d queued requests",
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * We have no need for these at the moment. Eventually,
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * when we query things that we can't expect to find in
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * the Global Catalog then we'll need to learn to follow
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * references.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* timeout or error; treat the same */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * This routine decreament the reference count of the
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * adutils_query_state_t
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_lookup_batch_unlock(adutils_query_state_t **state)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Decrement reference count with qstatelock locked
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * If there are no references wakup the allocating thread
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * This routine frees the adutils_query_state_t structure
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * If the reference count is greater than 1 it waits
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * for the other threads to finish using it.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_lookup_batch_release(adutils_query_state_t **state)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Set state to dead to stop further operations.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Wait for reference count with qstatelock locked
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * to get to one.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) pthread_cond_wait(&(*state)->cv, &qstatelock);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Remove this state struct from the list of state structs */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre for (p = &qstatehead; *p != NULL; p = &(*p)->next) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (*p == (*state)) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Clear results for queries that failed */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre if (*(*state)->queries[i].rc != ADUTILS_SUCCESS) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre adutils_freeresult((*state)->queries[i].result);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * This routine waits for other threads using the
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * adutils_query_state_t structure to finish.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * If the reference count is greater than 1 it waits
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * for the other threads to finish using it.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_lookup_batch_wait(adutils_query_state_t *state)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Set state to dead to stop further operation.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Wait for reference count to get to one
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * with qstatelock locked.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) pthread_cond_wait(&state->cv, &qstatelock);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Process active queries in the AD lookup batch and then finalize the
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_lookup_batch_end(adutils_query_state_t **state)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Process results until done or until timeout, if given */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Wait for other threads processing search result to finish */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Send one prepared search, queue up msgid, process what results are
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_lookup_batch_add(adutils_query_state_t *state,
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown const char *filter, const char * const *attrs, const char *edomain,
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Remember the expected domain so we can check the results
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * against it
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Remember where to put the results */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Provide sane defaults for the results in case we never hear
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * back from the DS before closing the connection.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Check the number of queued requests first */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre state->qadh->num_requests > state->qadh->max_requests) {
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre /* Send this lookup, don't wait for a result here */
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre } else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE ||
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN ||
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre (void) pthread_mutex_unlock(&state->qadh->lock);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "AD ldap_search_ext error (%s) "
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre "- %d queued requests",
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Reap as many requests as we can _without_ waiting to prevent
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * any possible TCP socket buffer starvation deadlocks.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre while (get_adobject_batch(state->qadh, &tv) == 0)
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre * Single AD lookup request implemented on top of the batch API.
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkreadutils_lookup(adutils_ad_t *ad, const char *filter, const char **attrs,
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre rc = adutils_lookup_batch_start(ad, 1, NULL, NULL, &qs);
2b4a78020b9c38d1b95e2f3fefa6d6e4be382d1fBaban Kenkre rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc);
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown return (u8_strcmp(a, b, 0, U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err)
1fcced4c370617db71610fecffd5451a5894ca5eJordan Brown == 0 && err == 0);