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 /* 22*7a8a68f5SJulian Pullen * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 232b4a7802SBaban Kenkre * Use is subject to license terms. 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> 38*7a8a68f5SJulian 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 602b4a7802SBaban Kenkre typedef struct binary_attrs { 612b4a7802SBaban Kenkre const char *name; 622b4a7802SBaban Kenkre char *(*ber2str)(BerValue *bvalues); 632b4a7802SBaban Kenkre } binary_attrs_t; 642b4a7802SBaban Kenkre 652b4a7802SBaban Kenkre static binary_attrs_t binattrs[] = { 662b4a7802SBaban Kenkre {"objectSID", adutils_sid_ber2str}, 672b4a7802SBaban Kenkre {NULL, NULL} 682b4a7802SBaban Kenkre }; 692b4a7802SBaban Kenkre 704d61c878SJulian Pullen 71*7a8a68f5SJulian Pullen adutils_logger logger = syslog; 72*7a8a68f5SJulian Pullen 73*7a8a68f5SJulian Pullen 742b4a7802SBaban Kenkre void 75*7a8a68f5SJulian Pullen adutils_set_logger(adutils_logger funct) 762b4a7802SBaban Kenkre { 77*7a8a68f5SJulian Pullen logger = funct; 782b4a7802SBaban Kenkre } 792b4a7802SBaban Kenkre 804d61c878SJulian Pullen 812b4a7802SBaban Kenkre /* 822b4a7802SBaban Kenkre * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com" 832b4a7802SBaban Kenkre */ 842b4a7802SBaban Kenkre static 852b4a7802SBaban Kenkre char * 862b4a7802SBaban Kenkre adutils_dns2dn(const char *dns) 872b4a7802SBaban Kenkre { 88*7a8a68f5SJulian Pullen int num_parts; 89*7a8a68f5SJulian Pullen 90*7a8a68f5SJulian Pullen return (ldap_dns_to_dn((char *)dns, &num_parts)); 912b4a7802SBaban Kenkre } 922b4a7802SBaban Kenkre 934d61c878SJulian Pullen 942b4a7802SBaban Kenkre /* 952b4a7802SBaban Kenkre * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other 962b4a7802SBaban Kenkre * attributes (CN, etc...). 972b4a7802SBaban Kenkre */ 982b4a7802SBaban Kenkre char * 992b4a7802SBaban Kenkre adutils_dn2dns(const char *dn) 1002b4a7802SBaban Kenkre { 101*7a8a68f5SJulian Pullen return (DN_to_DNS(dn)); 1022b4a7802SBaban Kenkre } 1032b4a7802SBaban Kenkre 1042b4a7802SBaban Kenkre 1052b4a7802SBaban Kenkre /* 1062b4a7802SBaban Kenkre * Convert a binary SID in a BerValue to a adutils_sid_t 1072b4a7802SBaban Kenkre */ 1082b4a7802SBaban Kenkre int 109*7a8a68f5SJulian Pullen adutils_getsid(BerValue *bval, adutils_sid_t *sidp) 1102b4a7802SBaban Kenkre { 1112b4a7802SBaban Kenkre int i, j; 1122b4a7802SBaban Kenkre uchar_t *v; 1132b4a7802SBaban Kenkre uint32_t a; 1142b4a7802SBaban Kenkre 1152b4a7802SBaban Kenkre /* 1162b4a7802SBaban Kenkre * The binary format of a SID is as follows: 1172b4a7802SBaban Kenkre * 1182b4a7802SBaban Kenkre * byte #0: version, always 0x01 1192b4a7802SBaban Kenkre * byte #1: RID count, always <= 0x0f 1202b4a7802SBaban Kenkre * bytes #2-#7: SID authority, big-endian 48-bit unsigned int 1212b4a7802SBaban Kenkre * 1222b4a7802SBaban Kenkre * followed by RID count RIDs, each a little-endian, unsigned 1232b4a7802SBaban Kenkre * 32-bit int. 1242b4a7802SBaban Kenkre */ 1252b4a7802SBaban Kenkre /* 1262b4a7802SBaban Kenkre * Sanity checks: must have at least one RID, version must be 1272b4a7802SBaban Kenkre * 0x01, and the length must be 8 + rid count * 4 1282b4a7802SBaban Kenkre */ 1292b4a7802SBaban Kenkre if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 && 1302b4a7802SBaban Kenkre bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) { 1312b4a7802SBaban Kenkre v = (uchar_t *)bval->bv_val; 1322b4a7802SBaban Kenkre sidp->version = v[0]; 1332b4a7802SBaban Kenkre sidp->sub_authority_count = v[1]; 1342b4a7802SBaban Kenkre sidp->authority = 1352b4a7802SBaban Kenkre /* big endian -- so start from the left */ 1362b4a7802SBaban Kenkre ((u_longlong_t)v[2] << 40) | 1372b4a7802SBaban Kenkre ((u_longlong_t)v[3] << 32) | 1382b4a7802SBaban Kenkre ((u_longlong_t)v[4] << 24) | 1392b4a7802SBaban Kenkre ((u_longlong_t)v[5] << 16) | 1402b4a7802SBaban Kenkre ((u_longlong_t)v[6] << 8) | 1412b4a7802SBaban Kenkre (u_longlong_t)v[7]; 1422b4a7802SBaban Kenkre for (i = 0; i < sidp->sub_authority_count; i++) { 1432b4a7802SBaban Kenkre j = 8 + (i * 4); 1442b4a7802SBaban Kenkre /* little endian -- so start from the right */ 1452b4a7802SBaban Kenkre a = (v[j + 3] << 24) | (v[j + 2] << 16) | 1462b4a7802SBaban Kenkre (v[j + 1] << 8) | (v[j]); 1472b4a7802SBaban Kenkre sidp->sub_authorities[i] = a; 1482b4a7802SBaban Kenkre } 1492b4a7802SBaban Kenkre return (0); 1502b4a7802SBaban Kenkre } 1512b4a7802SBaban Kenkre return (-1); 1522b4a7802SBaban Kenkre } 1532b4a7802SBaban Kenkre 1542b4a7802SBaban Kenkre /* 1552b4a7802SBaban Kenkre * Convert a adutils_sid_t to S-1-... 1562b4a7802SBaban Kenkre */ 1572b4a7802SBaban Kenkre char * 158*7a8a68f5SJulian Pullen adutils_sid2txt(adutils_sid_t *sidp) 1592b4a7802SBaban Kenkre { 1602b4a7802SBaban Kenkre int rlen, i, len; 1612b4a7802SBaban Kenkre char *str, *cp; 1622b4a7802SBaban Kenkre 1632b4a7802SBaban Kenkre if (sidp->version != 1) 1642b4a7802SBaban Kenkre return (NULL); 1652b4a7802SBaban Kenkre 1662b4a7802SBaban Kenkre len = sizeof ("S-1-") - 1; 1672b4a7802SBaban Kenkre 1682b4a7802SBaban Kenkre /* 1692b4a7802SBaban Kenkre * We could optimize like so, but, why? 1702b4a7802SBaban Kenkre * if (sidp->authority < 10) 1712b4a7802SBaban Kenkre * len += 2; 1722b4a7802SBaban Kenkre * else if (sidp->authority < 100) 1732b4a7802SBaban Kenkre * len += 3; 1742b4a7802SBaban Kenkre * else 1752b4a7802SBaban Kenkre * len += snprintf(NULL, 0"%llu", sidp->authority); 1762b4a7802SBaban Kenkre */ 1772b4a7802SBaban Kenkre len += snprintf(NULL, 0, "%llu", sidp->authority); 1782b4a7802SBaban Kenkre 1792b4a7802SBaban Kenkre /* Max length of a uint32_t printed out in ASCII is 10 bytes */ 1802b4a7802SBaban Kenkre len += 1 + (sidp->sub_authority_count + 1) * 10; 1812b4a7802SBaban Kenkre 1822b4a7802SBaban Kenkre if ((cp = str = malloc(len)) == NULL) 1832b4a7802SBaban Kenkre return (NULL); 1842b4a7802SBaban Kenkre 1852b4a7802SBaban Kenkre rlen = snprintf(str, len, "S-1-%llu", sidp->authority); 1862b4a7802SBaban Kenkre 1872b4a7802SBaban Kenkre cp += rlen; 1882b4a7802SBaban Kenkre len -= rlen; 1892b4a7802SBaban Kenkre 1902b4a7802SBaban Kenkre for (i = 0; i < sidp->sub_authority_count; i++) { 1912b4a7802SBaban Kenkre assert(len > 0); 1922b4a7802SBaban Kenkre rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]); 1932b4a7802SBaban Kenkre cp += rlen; 1942b4a7802SBaban Kenkre len -= rlen; 1952b4a7802SBaban Kenkre assert(len >= 0); 1962b4a7802SBaban Kenkre } 1972b4a7802SBaban Kenkre 1982b4a7802SBaban Kenkre return (str); 1992b4a7802SBaban Kenkre } 2002b4a7802SBaban Kenkre 2012b4a7802SBaban Kenkre /* 2022b4a7802SBaban Kenkre * Convert a adutils_sid_t to on-the-wire encoding 2032b4a7802SBaban Kenkre */ 2042b4a7802SBaban Kenkre static 2052b4a7802SBaban Kenkre int 2062b4a7802SBaban Kenkre sid2binsid(adutils_sid_t *sid, uchar_t *binsid, int binsidlen) 2072b4a7802SBaban Kenkre { 2082b4a7802SBaban Kenkre uchar_t *p; 2092b4a7802SBaban Kenkre int i; 2102b4a7802SBaban Kenkre uint64_t a; 2112b4a7802SBaban Kenkre uint32_t r; 2122b4a7802SBaban Kenkre 2132b4a7802SBaban Kenkre if (sid->version != 1 || 2142b4a7802SBaban Kenkre binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4)) 2152b4a7802SBaban Kenkre return (-1); 2162b4a7802SBaban Kenkre 2172b4a7802SBaban Kenkre p = binsid; 2182b4a7802SBaban Kenkre *p++ = 0x01; /* version */ 2192b4a7802SBaban Kenkre /* sub authority count */ 2202b4a7802SBaban Kenkre *p++ = sid->sub_authority_count; 2212b4a7802SBaban Kenkre /* Authority */ 2222b4a7802SBaban Kenkre a = sid->authority; 2232b4a7802SBaban Kenkre /* big-endian -- start from left */ 2242b4a7802SBaban Kenkre *p++ = (a >> 40) & 0xFF; 2252b4a7802SBaban Kenkre *p++ = (a >> 32) & 0xFF; 2262b4a7802SBaban Kenkre *p++ = (a >> 24) & 0xFF; 2272b4a7802SBaban Kenkre *p++ = (a >> 16) & 0xFF; 2282b4a7802SBaban Kenkre *p++ = (a >> 8) & 0xFF; 2292b4a7802SBaban Kenkre *p++ = a & 0xFF; 2302b4a7802SBaban Kenkre 2312b4a7802SBaban Kenkre /* sub-authorities */ 2322b4a7802SBaban Kenkre for (i = 0; i < sid->sub_authority_count; i++) { 2332b4a7802SBaban Kenkre r = sid->sub_authorities[i]; 2342b4a7802SBaban Kenkre /* little-endian -- start from right */ 2352b4a7802SBaban Kenkre *p++ = (r & 0x000000FF); 2362b4a7802SBaban Kenkre *p++ = (r & 0x0000FF00) >> 8; 2372b4a7802SBaban Kenkre *p++ = (r & 0x00FF0000) >> 16; 2382b4a7802SBaban Kenkre *p++ = (r & 0xFF000000) >> 24; 2392b4a7802SBaban Kenkre } 2402b4a7802SBaban Kenkre 2412b4a7802SBaban Kenkre return (0); 2422b4a7802SBaban Kenkre } 2432b4a7802SBaban Kenkre 2442b4a7802SBaban Kenkre /* 2452b4a7802SBaban Kenkre * Convert a stringified SID (S-1-...) into a hex-encoded version of the 2462b4a7802SBaban Kenkre * on-the-wire encoding, but with each pair of hex digits pre-pended 2472b4a7802SBaban Kenkre * with a '\', so we can pass this to libldap. 2482b4a7802SBaban Kenkre */ 2492b4a7802SBaban Kenkre int 2502b4a7802SBaban Kenkre adutils_txtsid2hexbinsid(const char *txt, const uint32_t *rid, 2512b4a7802SBaban Kenkre char *hexbinsid, int hexbinsidlen) 2522b4a7802SBaban Kenkre { 2532b4a7802SBaban Kenkre adutils_sid_t sid = { 0 }; 2542b4a7802SBaban Kenkre int i, j; 2552b4a7802SBaban Kenkre const char *cp; 2562b4a7802SBaban Kenkre char *ecp; 2572b4a7802SBaban Kenkre u_longlong_t a; 2582b4a7802SBaban Kenkre unsigned long r; 2592b4a7802SBaban Kenkre uchar_t *binsid, b, hb; 2602b4a7802SBaban Kenkre 2612b4a7802SBaban Kenkre /* Only version 1 SIDs please */ 2622b4a7802SBaban Kenkre if (strncmp(txt, "S-1-", strlen("S-1-")) != 0) 2632b4a7802SBaban Kenkre return (-1); 2642b4a7802SBaban Kenkre 2652b4a7802SBaban Kenkre if (strlen(txt) < (strlen("S-1-") + 1)) 2662b4a7802SBaban Kenkre return (-1); 2672b4a7802SBaban Kenkre 2682b4a7802SBaban Kenkre /* count '-'s */ 2692b4a7802SBaban Kenkre for (j = 0, cp = strchr(txt, '-'); 2702b4a7802SBaban Kenkre cp != NULL && *cp != '\0'; 2712b4a7802SBaban Kenkre j++, cp = strchr(cp + 1, '-')) { 2722b4a7802SBaban Kenkre /* can't end on a '-' */ 2732b4a7802SBaban Kenkre if (*(cp + 1) == '\0') 2742b4a7802SBaban Kenkre return (-1); 2752b4a7802SBaban Kenkre } 2762b4a7802SBaban Kenkre 2772b4a7802SBaban Kenkre /* Adjust count for version and authority */ 2782b4a7802SBaban Kenkre j -= 2; 2792b4a7802SBaban Kenkre 2802b4a7802SBaban Kenkre /* we know the version number and RID count */ 2812b4a7802SBaban Kenkre sid.version = 1; 2822b4a7802SBaban Kenkre sid.sub_authority_count = (rid != NULL) ? j + 1 : j; 2832b4a7802SBaban Kenkre 2842b4a7802SBaban Kenkre /* must have at least one RID, but not too many */ 2852b4a7802SBaban Kenkre if (sid.sub_authority_count < 1 || 2862b4a7802SBaban Kenkre sid.sub_authority_count > ADUTILS_SID_MAX_SUB_AUTHORITIES) 2872b4a7802SBaban Kenkre return (-1); 2882b4a7802SBaban Kenkre 2892b4a7802SBaban Kenkre /* check that we only have digits and '-' */ 2902b4a7802SBaban Kenkre if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1)) 2912b4a7802SBaban Kenkre return (-1); 2922b4a7802SBaban Kenkre 2932b4a7802SBaban Kenkre cp = txt + strlen("S-1-"); 2942b4a7802SBaban Kenkre 2952b4a7802SBaban Kenkre /* 64-bit safe parsing of unsigned 48-bit authority value */ 2962b4a7802SBaban Kenkre errno = 0; 2972b4a7802SBaban Kenkre a = strtoull(cp, &ecp, 10); 2982b4a7802SBaban Kenkre 2992b4a7802SBaban Kenkre /* errors parsing the authority or too many bits */ 3002b4a7802SBaban Kenkre if (cp == ecp || (a == 0 && errno == EINVAL) || 3012b4a7802SBaban Kenkre (a == ULLONG_MAX && errno == ERANGE) || 3022b4a7802SBaban Kenkre (a & 0x0000ffffffffffffULL) != a) 3032b4a7802SBaban Kenkre return (-1); 3042b4a7802SBaban Kenkre 3052b4a7802SBaban Kenkre cp = ecp; 3062b4a7802SBaban Kenkre 3072b4a7802SBaban Kenkre sid.authority = (uint64_t)a; 3082b4a7802SBaban Kenkre 3092b4a7802SBaban Kenkre for (i = 0; i < j; i++) { 3102b4a7802SBaban Kenkre if (*cp++ != '-') 3112b4a7802SBaban Kenkre return (-1); 3122b4a7802SBaban Kenkre /* 64-bit safe parsing of unsigned 32-bit RID */ 3132b4a7802SBaban Kenkre errno = 0; 3142b4a7802SBaban Kenkre r = strtoul(cp, &ecp, 10); 3152b4a7802SBaban Kenkre /* errors parsing the RID or too many bits */ 3162b4a7802SBaban Kenkre if (cp == ecp || (r == 0 && errno == EINVAL) || 3172b4a7802SBaban Kenkre (r == ULONG_MAX && errno == ERANGE) || 3182b4a7802SBaban Kenkre (r & 0xffffffffUL) != r) 3192b4a7802SBaban Kenkre return (-1); 3202b4a7802SBaban Kenkre sid.sub_authorities[i] = (uint32_t)r; 3212b4a7802SBaban Kenkre cp = ecp; 3222b4a7802SBaban Kenkre } 3232b4a7802SBaban Kenkre 3242b4a7802SBaban Kenkre /* check that all of the string SID has been consumed */ 3252b4a7802SBaban Kenkre if (*cp != '\0') 3262b4a7802SBaban Kenkre return (-1); 3272b4a7802SBaban Kenkre 3282b4a7802SBaban Kenkre if (rid != NULL) 3292b4a7802SBaban Kenkre sid.sub_authorities[j] = *rid; 3302b4a7802SBaban Kenkre 3312b4a7802SBaban Kenkre j = 1 + 1 + 6 + sid.sub_authority_count * 4; 3322b4a7802SBaban Kenkre 3332b4a7802SBaban Kenkre if (hexbinsidlen < (j * 3)) 3342b4a7802SBaban Kenkre return (-2); 3352b4a7802SBaban Kenkre 3362b4a7802SBaban Kenkre /* binary encode the SID */ 3372b4a7802SBaban Kenkre binsid = (uchar_t *)alloca(j); 3382b4a7802SBaban Kenkre (void) sid2binsid(&sid, binsid, j); 3392b4a7802SBaban Kenkre 3402b4a7802SBaban Kenkre /* hex encode, with a backslash before each byte */ 3412b4a7802SBaban Kenkre for (ecp = hexbinsid, i = 0; i < j; i++) { 3422b4a7802SBaban Kenkre b = binsid[i]; 3432b4a7802SBaban Kenkre *ecp++ = '\\'; 3442b4a7802SBaban Kenkre hb = (b >> 4) & 0xF; 3452b4a7802SBaban Kenkre *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 3462b4a7802SBaban Kenkre hb = b & 0xF; 3472b4a7802SBaban Kenkre *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 3482b4a7802SBaban Kenkre } 3492b4a7802SBaban Kenkre *ecp = '\0'; 3502b4a7802SBaban Kenkre 3512b4a7802SBaban Kenkre return (0); 3522b4a7802SBaban Kenkre } 3532b4a7802SBaban Kenkre 3542b4a7802SBaban Kenkre static 3552b4a7802SBaban Kenkre char * 3562b4a7802SBaban Kenkre convert_bval2sid(BerValue *bval, uint32_t *rid) 3572b4a7802SBaban Kenkre { 3582b4a7802SBaban Kenkre adutils_sid_t sid; 3592b4a7802SBaban Kenkre 360*7a8a68f5SJulian Pullen if (adutils_getsid(bval, &sid) < 0) 3612b4a7802SBaban Kenkre return (NULL); 3622b4a7802SBaban Kenkre 3632b4a7802SBaban Kenkre /* 3642b4a7802SBaban Kenkre * If desired and if the SID is what should be a domain/computer 3652b4a7802SBaban Kenkre * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then 3662b4a7802SBaban Kenkre * save the last RID and truncate the SID 3672b4a7802SBaban Kenkre */ 3682b4a7802SBaban Kenkre if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5) 3692b4a7802SBaban Kenkre *rid = sid.sub_authorities[--sid.sub_authority_count]; 370*7a8a68f5SJulian Pullen return (adutils_sid2txt(&sid)); 3712b4a7802SBaban Kenkre } 3722b4a7802SBaban Kenkre 3732b4a7802SBaban Kenkre 3742b4a7802SBaban Kenkre /* 3752b4a7802SBaban Kenkre * Return a NUL-terminated stringified SID from the value of an 3762b4a7802SBaban Kenkre * objectSid attribute and put the last RID in *rid. 3772b4a7802SBaban Kenkre */ 3782b4a7802SBaban Kenkre char * 3792b4a7802SBaban Kenkre adutils_bv_objsid2sidstr(BerValue *bval, uint32_t *rid) 3802b4a7802SBaban Kenkre { 3812b4a7802SBaban Kenkre char *sid; 3822b4a7802SBaban Kenkre 3832b4a7802SBaban Kenkre if (bval == NULL) 3842b4a7802SBaban Kenkre return (NULL); 3852b4a7802SBaban Kenkre /* objectSid is single valued */ 3862b4a7802SBaban Kenkre if ((sid = convert_bval2sid(bval, rid)) == NULL) 3872b4a7802SBaban Kenkre return (NULL); 3882b4a7802SBaban Kenkre return (sid); 3892b4a7802SBaban Kenkre } 3902b4a7802SBaban Kenkre 3912b4a7802SBaban Kenkre static 3922b4a7802SBaban Kenkre char * 3932b4a7802SBaban Kenkre adutils_sid_ber2str(BerValue *bval) 3942b4a7802SBaban Kenkre { 3952b4a7802SBaban Kenkre return (adutils_bv_objsid2sidstr(bval, NULL)); 3962b4a7802SBaban Kenkre } 3972b4a7802SBaban Kenkre 3982b4a7802SBaban Kenkre 3992b4a7802SBaban Kenkre /* Return a NUL-terminated string from the Ber value */ 4002b4a7802SBaban Kenkre char * 4012b4a7802SBaban Kenkre adutils_bv_name2str(BerValue *bval) 4022b4a7802SBaban Kenkre { 4032b4a7802SBaban Kenkre char *s; 4042b4a7802SBaban Kenkre 4052b4a7802SBaban Kenkre if (bval == NULL || bval->bv_val == NULL) 4062b4a7802SBaban Kenkre return (NULL); 4072b4a7802SBaban Kenkre if ((s = malloc(bval->bv_len + 1)) == NULL) 4082b4a7802SBaban Kenkre return (NULL); 4092b4a7802SBaban Kenkre (void) snprintf(s, bval->bv_len + 1, "%.*s", bval->bv_len, 4102b4a7802SBaban Kenkre bval->bv_val); 4112b4a7802SBaban Kenkre return (s); 4122b4a7802SBaban Kenkre } 4132b4a7802SBaban Kenkre 4142b4a7802SBaban Kenkre /*ARGSUSED*/ 4152b4a7802SBaban Kenkre int 4162b4a7802SBaban Kenkre saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) 4172b4a7802SBaban Kenkre { 4182b4a7802SBaban Kenkre sasl_interact_t *interact; 4192b4a7802SBaban Kenkre 4202b4a7802SBaban Kenkre if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE) 4212b4a7802SBaban Kenkre return (LDAP_PARAM_ERROR); 4222b4a7802SBaban Kenkre 4232b4a7802SBaban Kenkre /* There should be no extra arguemnts for SASL/GSSAPI authentication */ 4242b4a7802SBaban Kenkre for (interact = prompts; interact->id != SASL_CB_LIST_END; 4252b4a7802SBaban Kenkre interact++) { 4262b4a7802SBaban Kenkre interact->result = NULL; 4272b4a7802SBaban Kenkre interact->len = 0; 4282b4a7802SBaban Kenkre } 4292b4a7802SBaban Kenkre return (LDAP_SUCCESS); 4302b4a7802SBaban Kenkre } 4312b4a7802SBaban Kenkre 4322b4a7802SBaban Kenkre 4332b4a7802SBaban Kenkre #define ADCONN_TIME 300 4342b4a7802SBaban Kenkre 4352b4a7802SBaban Kenkre /* 4362b4a7802SBaban Kenkre * Idle connection reaping side of connection management 4372b4a7802SBaban Kenkre */ 4382b4a7802SBaban Kenkre void 4392b4a7802SBaban Kenkre adutils_reap_idle_connections() 4402b4a7802SBaban Kenkre { 4412b4a7802SBaban Kenkre adutils_host_t *adh; 4422b4a7802SBaban Kenkre time_t now; 4432b4a7802SBaban Kenkre 4442b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 4452b4a7802SBaban Kenkre now = time(NULL); 4462b4a7802SBaban Kenkre for (adh = host_head; adh != NULL; adh = adh->next) { 4472b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 4482b4a7802SBaban Kenkre if (adh->ref == 0 && adh->idletime != 0 && 4492b4a7802SBaban Kenkre adh->idletime + ADCONN_TIME < now) { 4502b4a7802SBaban Kenkre if (adh->ld) { 4512b4a7802SBaban Kenkre (void) ldap_unbind(adh->ld); 4522b4a7802SBaban Kenkre adh->ld = NULL; 4532b4a7802SBaban Kenkre adh->idletime = 0; 4542b4a7802SBaban Kenkre adh->ref = 0; 4552b4a7802SBaban Kenkre } 4562b4a7802SBaban Kenkre } 4572b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 4582b4a7802SBaban Kenkre } 4592b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 4602b4a7802SBaban Kenkre } 4612b4a7802SBaban Kenkre 4622b4a7802SBaban Kenkre 4632b4a7802SBaban Kenkre adutils_rc 4642b4a7802SBaban Kenkre adutils_ad_alloc(adutils_ad_t **new_ad, const char *default_domain, 4652b4a7802SBaban Kenkre adutils_ad_partition_t part) 4662b4a7802SBaban Kenkre { 4672b4a7802SBaban Kenkre adutils_ad_t *ad; 4682b4a7802SBaban Kenkre 4692b4a7802SBaban Kenkre *new_ad = NULL; 4702b4a7802SBaban Kenkre 4712b4a7802SBaban Kenkre if ((default_domain == NULL || *default_domain == '\0') && 4722b4a7802SBaban Kenkre part != ADUTILS_AD_GLOBAL_CATALOG) 4732b4a7802SBaban Kenkre return (ADUTILS_ERR_DOMAIN); 4742b4a7802SBaban Kenkre if ((ad = calloc(1, sizeof (*ad))) == NULL) 4752b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 4762b4a7802SBaban Kenkre ad->ref = 1; 4772b4a7802SBaban Kenkre ad->partition = part; 4782b4a7802SBaban Kenkre if (default_domain == NULL) 4792b4a7802SBaban Kenkre default_domain = ""; 4802b4a7802SBaban Kenkre if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL) 4812b4a7802SBaban Kenkre goto err; 4822b4a7802SBaban Kenkre if (pthread_mutex_init(&ad->lock, NULL) != 0) 4832b4a7802SBaban Kenkre goto err; 4842b4a7802SBaban Kenkre *new_ad = ad; 4852b4a7802SBaban Kenkre return (ADUTILS_SUCCESS); 4862b4a7802SBaban Kenkre 4872b4a7802SBaban Kenkre err: 4882b4a7802SBaban Kenkre if (ad->dflt_w2k_dom != NULL) 4892b4a7802SBaban Kenkre free(ad->dflt_w2k_dom); 4902b4a7802SBaban Kenkre free(ad); 4912b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 4922b4a7802SBaban Kenkre } 4932b4a7802SBaban Kenkre 4942b4a7802SBaban Kenkre void 4952b4a7802SBaban Kenkre adutils_ad_free(adutils_ad_t **ad) 4962b4a7802SBaban Kenkre { 4972b4a7802SBaban Kenkre adutils_host_t *p; 4982b4a7802SBaban Kenkre adutils_host_t *prev; 4992b4a7802SBaban Kenkre 5002b4a7802SBaban Kenkre if (ad == NULL || *ad == NULL) 5012b4a7802SBaban Kenkre return; 5022b4a7802SBaban Kenkre 5032b4a7802SBaban Kenkre (void) pthread_mutex_lock(&(*ad)->lock); 5042b4a7802SBaban Kenkre 5052b4a7802SBaban Kenkre if (atomic_dec_32_nv(&(*ad)->ref) > 0) { 5062b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&(*ad)->lock); 5072b4a7802SBaban Kenkre *ad = NULL; 5082b4a7802SBaban Kenkre return; 5092b4a7802SBaban Kenkre } 5102b4a7802SBaban Kenkre 5112b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 5122b4a7802SBaban Kenkre prev = NULL; 5132b4a7802SBaban Kenkre p = host_head; 5142b4a7802SBaban Kenkre while (p != NULL) { 5152b4a7802SBaban Kenkre if (p->owner != (*ad)) { 5162b4a7802SBaban Kenkre prev = p; 5172b4a7802SBaban Kenkre p = p->next; 5182b4a7802SBaban Kenkre continue; 5192b4a7802SBaban Kenkre } else { 5202b4a7802SBaban Kenkre delete_ds((*ad), p->host, p->port); 5212b4a7802SBaban Kenkre if (prev == NULL) 5222b4a7802SBaban Kenkre p = host_head; 5232b4a7802SBaban Kenkre else 5242b4a7802SBaban Kenkre p = prev->next; 5252b4a7802SBaban Kenkre } 5262b4a7802SBaban Kenkre } 5272b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 5282b4a7802SBaban Kenkre 5292b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&(*ad)->lock); 5302b4a7802SBaban Kenkre (void) pthread_mutex_destroy(&(*ad)->lock); 5312b4a7802SBaban Kenkre 5324d61c878SJulian Pullen if ((*ad)->known_domains) 5334d61c878SJulian Pullen free((*ad)->known_domains); 5342b4a7802SBaban Kenkre free((*ad)->dflt_w2k_dom); 5352b4a7802SBaban Kenkre free(*ad); 5362b4a7802SBaban Kenkre 5372b4a7802SBaban Kenkre *ad = NULL; 5382b4a7802SBaban Kenkre } 5392b4a7802SBaban Kenkre 5402b4a7802SBaban Kenkre static 5412b4a7802SBaban Kenkre int 5422b4a7802SBaban Kenkre open_conn(adutils_host_t *adh, int timeoutsecs) 5432b4a7802SBaban Kenkre { 5442b4a7802SBaban Kenkre int zero = 0; 5452b4a7802SBaban Kenkre int ldversion, rc; 5462b4a7802SBaban Kenkre int timeoutms = timeoutsecs * 1000; 5472b4a7802SBaban Kenkre 5482b4a7802SBaban Kenkre if (adh == NULL) 5492b4a7802SBaban Kenkre return (0); 5502b4a7802SBaban Kenkre 5512b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 5522b4a7802SBaban Kenkre 5532b4a7802SBaban Kenkre if (!adh->dead && adh->ld != NULL) 5542b4a7802SBaban Kenkre /* done! */ 5552b4a7802SBaban Kenkre goto out; 5562b4a7802SBaban Kenkre 5572b4a7802SBaban Kenkre if (adh->ld != NULL) { 5582b4a7802SBaban Kenkre (void) ldap_unbind(adh->ld); 5592b4a7802SBaban Kenkre adh->ld = NULL; 5602b4a7802SBaban Kenkre } 5612b4a7802SBaban Kenkre adh->num_requests = 0; 5622b4a7802SBaban Kenkre 5632b4a7802SBaban Kenkre atomic_inc_64(&adh->generation); 5642b4a7802SBaban Kenkre 5652b4a7802SBaban Kenkre /* Open and bind an LDAP connection */ 5662b4a7802SBaban Kenkre adh->ld = ldap_init(adh->host, adh->port); 5672b4a7802SBaban Kenkre if (adh->ld == NULL) { 568*7a8a68f5SJulian Pullen logger(LOG_INFO, "ldap_init() to server " 5692b4a7802SBaban Kenkre "%s port %d failed. (%s)", adh->host, 5702b4a7802SBaban Kenkre adh->port, strerror(errno)); 5712b4a7802SBaban Kenkre goto out; 5722b4a7802SBaban Kenkre } 5732b4a7802SBaban Kenkre ldversion = LDAP_VERSION3; 5742b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion); 5752b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 5762b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero); 5772b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero); 5782b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms); 5792b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 5802b4a7802SBaban Kenkre rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */, 5812b4a7802SBaban Kenkre adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback, 5822b4a7802SBaban Kenkre NULL); 5832b4a7802SBaban Kenkre 5842b4a7802SBaban Kenkre if (rc != LDAP_SUCCESS) { 5852b4a7802SBaban Kenkre (void) ldap_unbind(adh->ld); 5862b4a7802SBaban Kenkre adh->ld = NULL; 587*7a8a68f5SJulian Pullen logger(LOG_INFO, "ldap_sasl_interactive_bind_s() to server " 5882b4a7802SBaban Kenkre "%s port %d failed. (%s)", adh->host, adh->port, 5892b4a7802SBaban Kenkre ldap_err2string(rc)); 5902b4a7802SBaban Kenkre } 5912b4a7802SBaban Kenkre 592*7a8a68f5SJulian Pullen logger(LOG_DEBUG, "Using global catalog server %s:%d", 5932b4a7802SBaban Kenkre adh->host, adh->port); 5942b4a7802SBaban Kenkre 5952b4a7802SBaban Kenkre out: 5962b4a7802SBaban Kenkre if (adh->ld != NULL) { 5972b4a7802SBaban Kenkre atomic_inc_32(&adh->ref); 5982b4a7802SBaban Kenkre adh->idletime = time(NULL); 5992b4a7802SBaban Kenkre adh->dead = 0; 6002b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 6012b4a7802SBaban Kenkre return (1); 6022b4a7802SBaban Kenkre } 6032b4a7802SBaban Kenkre 6042b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 6052b4a7802SBaban Kenkre return (0); 6062b4a7802SBaban Kenkre } 6072b4a7802SBaban Kenkre 6082b4a7802SBaban Kenkre 6092b4a7802SBaban Kenkre /* 6102b4a7802SBaban Kenkre * Connection management: find an open connection or open one 6112b4a7802SBaban Kenkre */ 6122b4a7802SBaban Kenkre static 6132b4a7802SBaban Kenkre adutils_host_t * 6142b4a7802SBaban Kenkre get_conn(adutils_ad_t *ad) 6152b4a7802SBaban Kenkre { 6162b4a7802SBaban Kenkre adutils_host_t *adh = NULL; 6172b4a7802SBaban Kenkre int tries; 6182b4a7802SBaban Kenkre int dscount = 0; 6192b4a7802SBaban Kenkre int timeoutsecs = ADUTILS_LDAP_OPEN_TIMEOUT; 6202b4a7802SBaban Kenkre 6212b4a7802SBaban Kenkre retry: 6222b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 6232b4a7802SBaban Kenkre 6242b4a7802SBaban Kenkre if (host_head == NULL) { 6252b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 6262b4a7802SBaban Kenkre goto out; 6272b4a7802SBaban Kenkre } 6282b4a7802SBaban Kenkre 6292b4a7802SBaban Kenkre if (dscount == 0) { 6302b4a7802SBaban Kenkre /* 6312b4a7802SBaban Kenkre * First try: count the number of DSes. 6322b4a7802SBaban Kenkre * 6332b4a7802SBaban Kenkre * Integer overflow is not an issue -- we can't have so many 6342b4a7802SBaban Kenkre * DSes because they won't fit even DNS over TCP, and SMF 6352b4a7802SBaban Kenkre * shouldn't let you set so many. 6362b4a7802SBaban Kenkre */ 6372b4a7802SBaban Kenkre for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) { 6382b4a7802SBaban Kenkre if (adh->owner == ad) 6392b4a7802SBaban Kenkre dscount++; 6402b4a7802SBaban Kenkre } 6412b4a7802SBaban Kenkre 6422b4a7802SBaban Kenkre if (dscount == 0) { 6432b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 6442b4a7802SBaban Kenkre goto out; 6452b4a7802SBaban Kenkre } 6462b4a7802SBaban Kenkre 6472b4a7802SBaban Kenkre tries = dscount * 3; /* three tries per-ds */ 6482b4a7802SBaban Kenkre 6492b4a7802SBaban Kenkre /* 6502b4a7802SBaban Kenkre * Begin round-robin at the next DS in the list after the last 6512b4a7802SBaban Kenkre * one that we had a connection to, else start with the first 6522b4a7802SBaban Kenkre * DS in the list. 6532b4a7802SBaban Kenkre */ 6542b4a7802SBaban Kenkre adh = ad->last_adh; 6552b4a7802SBaban Kenkre } 6562b4a7802SBaban Kenkre 6572b4a7802SBaban Kenkre /* 6582b4a7802SBaban Kenkre * Round-robin -- pick the next one on the list; if the list 6592b4a7802SBaban Kenkre * changes on us, no big deal, we'll just potentially go 6602b4a7802SBaban Kenkre * around the wrong number of times. 6612b4a7802SBaban Kenkre */ 6622b4a7802SBaban Kenkre for (;;) { 6634d61c878SJulian Pullen if (adh != NULL && adh->owner == ad && adh->ld != NULL && 6644d61c878SJulian Pullen !adh->dead) 6652b4a7802SBaban Kenkre break; 6662b4a7802SBaban Kenkre if (adh == NULL || (adh = adh->next) == NULL) 6672b4a7802SBaban Kenkre adh = host_head; 6682b4a7802SBaban Kenkre if (adh->owner == ad) 6692b4a7802SBaban Kenkre break; 6702b4a7802SBaban Kenkre } 6712b4a7802SBaban Kenkre 6722b4a7802SBaban Kenkre ad->last_adh = adh; 6732b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 6742b4a7802SBaban Kenkre 6752b4a7802SBaban Kenkre /* Found suitable DS, open it if not already opened */ 6762b4a7802SBaban Kenkre if (open_conn(adh, timeoutsecs)) 6772b4a7802SBaban Kenkre return (adh); 6782b4a7802SBaban Kenkre 6792b4a7802SBaban Kenkre tries--; 6802b4a7802SBaban Kenkre if ((tries % dscount) == 0) 6812b4a7802SBaban Kenkre timeoutsecs *= 2; 6822b4a7802SBaban Kenkre if (tries > 0) 6832b4a7802SBaban Kenkre goto retry; 6842b4a7802SBaban Kenkre 6852b4a7802SBaban Kenkre out: 686*7a8a68f5SJulian Pullen logger(LOG_NOTICE, "Couldn't open an LDAP connection to any global " 6872b4a7802SBaban Kenkre "catalog server!"); 6882b4a7802SBaban Kenkre return (NULL); 6892b4a7802SBaban Kenkre } 6902b4a7802SBaban Kenkre 6912b4a7802SBaban Kenkre static 6922b4a7802SBaban Kenkre void 6932b4a7802SBaban Kenkre release_conn(adutils_host_t *adh) 6942b4a7802SBaban Kenkre { 6952b4a7802SBaban Kenkre int delete = 0; 6962b4a7802SBaban Kenkre 6972b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 6982b4a7802SBaban Kenkre if (atomic_dec_32_nv(&adh->ref) == 0) { 6992b4a7802SBaban Kenkre if (adh->owner == NULL) 7002b4a7802SBaban Kenkre delete = 1; 7012b4a7802SBaban Kenkre adh->idletime = time(NULL); 7022b4a7802SBaban Kenkre } 7032b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 7042b4a7802SBaban Kenkre 7052b4a7802SBaban Kenkre /* Free this host if its owner no longer exists. */ 7062b4a7802SBaban Kenkre if (delete) { 7072b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 7082b4a7802SBaban Kenkre delete_ds(NULL, adh->host, adh->port); 7092b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 7102b4a7802SBaban Kenkre } 7112b4a7802SBaban Kenkre } 7122b4a7802SBaban Kenkre 7132b4a7802SBaban Kenkre /* 7142b4a7802SBaban Kenkre * Create a adutils_host_t, populate it and add it to the list of hosts. 7152b4a7802SBaban Kenkre */ 7162b4a7802SBaban Kenkre adutils_rc 7172b4a7802SBaban Kenkre adutils_add_ds(adutils_ad_t *ad, const char *host, int port) 7182b4a7802SBaban Kenkre { 7192b4a7802SBaban Kenkre adutils_host_t *p; 7202b4a7802SBaban Kenkre adutils_host_t *new = NULL; 7212b4a7802SBaban Kenkre int ret; 7222b4a7802SBaban Kenkre adutils_rc rc; 7232b4a7802SBaban Kenkre 7242b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 7252b4a7802SBaban Kenkre for (p = host_head; p != NULL; p = p->next) { 7262b4a7802SBaban Kenkre if (p->owner != ad) 7272b4a7802SBaban Kenkre continue; 7282b4a7802SBaban Kenkre 7292b4a7802SBaban Kenkre if (strcmp(host, p->host) == 0 && p->port == port) { 7302b4a7802SBaban Kenkre /* already added */ 7312b4a7802SBaban Kenkre rc = ADUTILS_SUCCESS; 7322b4a7802SBaban Kenkre goto err; 7332b4a7802SBaban Kenkre } 7342b4a7802SBaban Kenkre } 7352b4a7802SBaban Kenkre 7362b4a7802SBaban Kenkre rc = ADUTILS_ERR_MEMORY; 7372b4a7802SBaban Kenkre 7382b4a7802SBaban Kenkre /* add new entry */ 7392b4a7802SBaban Kenkre new = (adutils_host_t *)calloc(1, sizeof (*new)); 7402b4a7802SBaban Kenkre if (new == NULL) 7412b4a7802SBaban Kenkre goto err; 7422b4a7802SBaban Kenkre new->owner = ad; 7432b4a7802SBaban Kenkre new->port = port; 7442b4a7802SBaban Kenkre new->dead = 0; 7452b4a7802SBaban Kenkre new->max_requests = 80; 7462b4a7802SBaban Kenkre new->num_requests = 0; 7472b4a7802SBaban Kenkre if ((new->host = strdup(host)) == NULL) 7482b4a7802SBaban Kenkre goto err; 7492b4a7802SBaban Kenkre new->saslflags = LDAP_SASL_INTERACTIVE; 7502b4a7802SBaban Kenkre new->saslmech = "GSSAPI"; 7512b4a7802SBaban Kenkre 7522b4a7802SBaban Kenkre if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) { 7532b4a7802SBaban Kenkre free(new->host); 7542b4a7802SBaban Kenkre new->host = NULL; 7552b4a7802SBaban Kenkre errno = ret; 7562b4a7802SBaban Kenkre rc = ADUTILS_ERR_INTERNAL; 7572b4a7802SBaban Kenkre goto err; 7582b4a7802SBaban Kenkre } 7592b4a7802SBaban Kenkre 7602b4a7802SBaban Kenkre /* link in */ 7612b4a7802SBaban Kenkre rc = ADUTILS_SUCCESS; 7622b4a7802SBaban Kenkre new->next = host_head; 7632b4a7802SBaban Kenkre host_head = new; 7642b4a7802SBaban Kenkre 7652b4a7802SBaban Kenkre err: 7662b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 7672b4a7802SBaban Kenkre 7682b4a7802SBaban Kenkre if (rc != 0 && new != NULL) { 7692b4a7802SBaban Kenkre if (new->host != NULL) { 7702b4a7802SBaban Kenkre (void) pthread_mutex_destroy(&new->lock); 7712b4a7802SBaban Kenkre free(new->host); 7722b4a7802SBaban Kenkre } 7732b4a7802SBaban Kenkre free(new); 7742b4a7802SBaban Kenkre } 7752b4a7802SBaban Kenkre 7762b4a7802SBaban Kenkre return (rc); 7772b4a7802SBaban Kenkre } 7782b4a7802SBaban Kenkre 7792b4a7802SBaban Kenkre /* 7802b4a7802SBaban Kenkre * Free a DS configuration. 7812b4a7802SBaban Kenkre * Caller must lock the adhostlock mutex 7822b4a7802SBaban Kenkre */ 7832b4a7802SBaban Kenkre static 7842b4a7802SBaban Kenkre void 7852b4a7802SBaban Kenkre delete_ds(adutils_ad_t *ad, const char *host, int port) 7862b4a7802SBaban Kenkre { 7872b4a7802SBaban Kenkre adutils_host_t **p, *q; 7882b4a7802SBaban Kenkre 7892b4a7802SBaban Kenkre for (p = &host_head; *p != NULL; p = &((*p)->next)) { 7902b4a7802SBaban Kenkre if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 || 7912b4a7802SBaban Kenkre (*p)->port != port) 7922b4a7802SBaban Kenkre continue; 7932b4a7802SBaban Kenkre /* found */ 7942b4a7802SBaban Kenkre 7952b4a7802SBaban Kenkre (void) pthread_mutex_lock(&((*p)->lock)); 7962b4a7802SBaban Kenkre if ((*p)->ref > 0) { 7972b4a7802SBaban Kenkre /* 7982b4a7802SBaban Kenkre * Still in use. Set its owner to NULL so 7992b4a7802SBaban Kenkre * that it can be freed when its ref count 8002b4a7802SBaban Kenkre * becomes 0. 8012b4a7802SBaban Kenkre */ 8022b4a7802SBaban Kenkre (*p)->owner = NULL; 8032b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&((*p)->lock)); 8042b4a7802SBaban Kenkre break; 8052b4a7802SBaban Kenkre } 8062b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&((*p)->lock)); 8072b4a7802SBaban Kenkre 8082b4a7802SBaban Kenkre q = *p; 8092b4a7802SBaban Kenkre *p = (*p)->next; 8102b4a7802SBaban Kenkre 8112b4a7802SBaban Kenkre (void) pthread_mutex_destroy(&q->lock); 8122b4a7802SBaban Kenkre 8132b4a7802SBaban Kenkre if (q->ld) 8142b4a7802SBaban Kenkre (void) ldap_unbind(q->ld); 8152b4a7802SBaban Kenkre if (q->host) 8162b4a7802SBaban Kenkre free(q->host); 8172b4a7802SBaban Kenkre free(q); 8182b4a7802SBaban Kenkre break; 8192b4a7802SBaban Kenkre } 8202b4a7802SBaban Kenkre 8212b4a7802SBaban Kenkre } 8224d61c878SJulian Pullen /* 8234d61c878SJulian Pullen * Add known domain name and domain SID to AD configuration. 8244d61c878SJulian Pullen */ 8254d61c878SJulian Pullen 8264d61c878SJulian Pullen adutils_rc 8274d61c878SJulian Pullen adutils_add_domain(adutils_ad_t *ad, const char *domain, const char *sid) 8284d61c878SJulian Pullen { 8294d61c878SJulian Pullen struct known_domain *new; 8304d61c878SJulian Pullen int num = ad->num_known_domains; 8314d61c878SJulian Pullen 8324d61c878SJulian Pullen ad->num_known_domains++; 8334d61c878SJulian Pullen new = realloc(ad->known_domains, 8344d61c878SJulian Pullen sizeof (struct known_domain) * ad->num_known_domains); 8354d61c878SJulian Pullen if (new != NULL) { 8364d61c878SJulian Pullen ad->known_domains = new; 8374d61c878SJulian Pullen (void) strlcpy(ad->known_domains[num].name, domain, 8384d61c878SJulian Pullen sizeof (ad->known_domains[num].name)); 8394d61c878SJulian Pullen (void) strlcpy(ad->known_domains[num].sid, sid, 8404d61c878SJulian Pullen sizeof (ad->known_domains[num].sid)); 8414d61c878SJulian Pullen return (ADUTILS_SUCCESS); 8424d61c878SJulian Pullen } else { 8434d61c878SJulian Pullen if (ad->known_domains != NULL) { 8444d61c878SJulian Pullen free(ad->known_domains); 8454d61c878SJulian Pullen ad->known_domains = NULL; 8464d61c878SJulian Pullen } 8474d61c878SJulian Pullen ad->num_known_domains = 0; 8484d61c878SJulian Pullen return (ADUTILS_ERR_MEMORY); 8494d61c878SJulian Pullen } 8504d61c878SJulian Pullen } 8514d61c878SJulian Pullen 8524d61c878SJulian Pullen 8534d61c878SJulian Pullen /* 8544d61c878SJulian Pullen * Check that this AD supports this domain. 8554d61c878SJulian Pullen * If there are no known domains assume that the 8564d61c878SJulian Pullen * domain is supported by this AD. 8574d61c878SJulian Pullen * 8584d61c878SJulian Pullen * Returns 1 if this domain is supported by this AD 8594d61c878SJulian Pullen * else returns 0; 8604d61c878SJulian Pullen */ 8614d61c878SJulian Pullen 8624d61c878SJulian Pullen int 8634d61c878SJulian Pullen adutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain) 8644d61c878SJulian Pullen { 8654d61c878SJulian Pullen adutils_ad_t *ad = qs->qadh->owner; 8664d61c878SJulian Pullen int i, err; 8674d61c878SJulian Pullen 8684d61c878SJulian Pullen for (i = 0; i < ad->num_known_domains; i++) { 8694d61c878SJulian Pullen if (u8_strcmp(domain, ad->known_domains[i].name, 0, 8704d61c878SJulian Pullen U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && 8714d61c878SJulian Pullen err == 0) 8724d61c878SJulian Pullen return (1); 8734d61c878SJulian Pullen } 8744d61c878SJulian Pullen 8754d61c878SJulian Pullen return ((i == 0) ? 1 : 0); 8764d61c878SJulian Pullen } 8774d61c878SJulian Pullen 8784d61c878SJulian Pullen 8794d61c878SJulian Pullen /* 8804d61c878SJulian Pullen * Check that this AD supports the SID prefix. 8814d61c878SJulian Pullen * The SID prefix should match the domain SID. 8824d61c878SJulian Pullen * If there are no known domains assume that the 8834d61c878SJulian Pullen * SID prefix is supported by this AD. 8844d61c878SJulian Pullen * 8854d61c878SJulian Pullen * Returns 1 if this sid prefix is supported by this AD 8864d61c878SJulian Pullen * else returns 0; 8874d61c878SJulian Pullen */ 8884d61c878SJulian Pullen 8894d61c878SJulian Pullen int 8904d61c878SJulian Pullen adutils_lookup_check_sid_prefix(adutils_query_state_t *qs, const char *sid) 8914d61c878SJulian Pullen { 8924d61c878SJulian Pullen adutils_ad_t *ad = qs->qadh->owner; 8934d61c878SJulian Pullen int i; 8944d61c878SJulian Pullen 8954d61c878SJulian Pullen 8964d61c878SJulian Pullen for (i = 0; i < ad->num_known_domains; i++) { 8974d61c878SJulian Pullen if (strcmp(sid, ad->known_domains[i].sid) == 0) 8984d61c878SJulian Pullen return (1); 8994d61c878SJulian Pullen } 9004d61c878SJulian Pullen 9014d61c878SJulian Pullen return ((i == 0) ? 1 : 0); 9024d61c878SJulian Pullen } 9034d61c878SJulian Pullen 9042b4a7802SBaban Kenkre 9052b4a7802SBaban Kenkre adutils_rc 9062b4a7802SBaban Kenkre adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries, 9072b4a7802SBaban Kenkre adutils_ldap_res_search_cb ldap_res_search_cb, 9082b4a7802SBaban Kenkre void *ldap_res_search_argp, 9092b4a7802SBaban Kenkre adutils_query_state_t **state) 9102b4a7802SBaban Kenkre { 9112b4a7802SBaban Kenkre adutils_query_state_t *new_state; 9122b4a7802SBaban Kenkre adutils_host_t *adh = NULL; 9132b4a7802SBaban Kenkre 9142b4a7802SBaban Kenkre if (ad == NULL) 9152b4a7802SBaban Kenkre return (ADUTILS_ERR_INTERNAL); 9162b4a7802SBaban Kenkre 9172b4a7802SBaban Kenkre *state = NULL; 9182b4a7802SBaban Kenkre adh = get_conn(ad); 9192b4a7802SBaban Kenkre if (adh == NULL) 9202b4a7802SBaban Kenkre return (ADUTILS_ERR_RETRIABLE_NET_ERR); 9212b4a7802SBaban Kenkre 9222b4a7802SBaban Kenkre new_state = calloc(1, sizeof (adutils_query_state_t) + 9232b4a7802SBaban Kenkre (nqueries - 1) * sizeof (adutils_q_t)); 9242b4a7802SBaban Kenkre if (new_state == NULL) 9252b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 9262b4a7802SBaban Kenkre 9272b4a7802SBaban Kenkre /* 9282b4a7802SBaban Kenkre * Save default domain from the ad object so that we don't 9292b4a7802SBaban Kenkre * have to access the 'ad' object later. 9302b4a7802SBaban Kenkre */ 9312b4a7802SBaban Kenkre new_state->default_domain = strdup(adh->owner->dflt_w2k_dom); 9322b4a7802SBaban Kenkre if (new_state->default_domain == NULL) { 9332b4a7802SBaban Kenkre free(new_state); 9342b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 9352b4a7802SBaban Kenkre } 9362b4a7802SBaban Kenkre 9372b4a7802SBaban Kenkre if (ad->partition == ADUTILS_AD_DATA) 9382b4a7802SBaban Kenkre new_state->basedn = adutils_dns2dn(new_state->default_domain); 9392b4a7802SBaban Kenkre else 9402b4a7802SBaban Kenkre new_state->basedn = strdup(""); 9412b4a7802SBaban Kenkre if (new_state->basedn == NULL) { 9422b4a7802SBaban Kenkre free(new_state->default_domain); 9432b4a7802SBaban Kenkre free(new_state); 9442b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 9452b4a7802SBaban Kenkre } 9462b4a7802SBaban Kenkre 9472b4a7802SBaban Kenkre new_state->ref_cnt = 1; 9482b4a7802SBaban Kenkre new_state->qadh = adh; 9494d61c878SJulian Pullen new_state->qsize = nqueries; 9502b4a7802SBaban Kenkre new_state->qadh_gen = adh->generation; 9514d61c878SJulian Pullen new_state->qcount = 0; 9522b4a7802SBaban Kenkre new_state->ldap_res_search_cb = ldap_res_search_cb; 9532b4a7802SBaban Kenkre new_state->ldap_res_search_argp = ldap_res_search_argp; 9542b4a7802SBaban Kenkre (void) pthread_cond_init(&new_state->cv, NULL); 9552b4a7802SBaban Kenkre 9562b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 9572b4a7802SBaban Kenkre new_state->next = qstatehead; 9582b4a7802SBaban Kenkre qstatehead = new_state; 9592b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 9602b4a7802SBaban Kenkre *state = new_state; 9612b4a7802SBaban Kenkre 9622b4a7802SBaban Kenkre return (ADUTILS_SUCCESS); 9632b4a7802SBaban Kenkre } 9642b4a7802SBaban Kenkre 9652b4a7802SBaban Kenkre /* 9662b4a7802SBaban Kenkre * Find the adutils_query_state_t to which a given LDAP result msgid on a 9672b4a7802SBaban Kenkre * given connection belongs. This routine increaments the reference count 9682b4a7802SBaban Kenkre * so that the object can not be freed. adutils_lookup_batch_unlock() 9692b4a7802SBaban Kenkre * must be called to decreament the reference count. 9702b4a7802SBaban Kenkre */ 9712b4a7802SBaban Kenkre static 9722b4a7802SBaban Kenkre int 9732b4a7802SBaban Kenkre msgid2query(adutils_host_t *adh, int msgid, 9742b4a7802SBaban Kenkre adutils_query_state_t **state, int *qid) 9752b4a7802SBaban Kenkre { 9762b4a7802SBaban Kenkre adutils_query_state_t *p; 9772b4a7802SBaban Kenkre int i; 9782b4a7802SBaban Kenkre int ret; 9792b4a7802SBaban Kenkre 9802b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 9812b4a7802SBaban Kenkre for (p = qstatehead; p != NULL; p = p->next) { 9822b4a7802SBaban Kenkre if (p->qadh != adh || adh->generation != p->qadh_gen) 9832b4a7802SBaban Kenkre continue; 9842b4a7802SBaban Kenkre for (i = 0; i < p->qcount; i++) { 9852b4a7802SBaban Kenkre if ((p->queries[i]).msgid == msgid) { 9862b4a7802SBaban Kenkre if (!p->qdead) { 9872b4a7802SBaban Kenkre p->ref_cnt++; 9882b4a7802SBaban Kenkre *state = p; 9892b4a7802SBaban Kenkre *qid = i; 9902b4a7802SBaban Kenkre ret = 1; 9912b4a7802SBaban Kenkre } else 9922b4a7802SBaban Kenkre ret = 0; 9932b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 9942b4a7802SBaban Kenkre return (ret); 9952b4a7802SBaban Kenkre } 9962b4a7802SBaban Kenkre } 9972b4a7802SBaban Kenkre } 9982b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 9992b4a7802SBaban Kenkre return (0); 10002b4a7802SBaban Kenkre } 10012b4a7802SBaban Kenkre 10022b4a7802SBaban Kenkre static 10032b4a7802SBaban Kenkre int 10042b4a7802SBaban Kenkre check_for_binary_attrs(const char *attr) 10052b4a7802SBaban Kenkre { 10062b4a7802SBaban Kenkre int i; 10072b4a7802SBaban Kenkre for (i = 0; binattrs[i].name != NULL; i++) { 10082b4a7802SBaban Kenkre if (strcasecmp(binattrs[i].name, attr) == 0) 10092b4a7802SBaban Kenkre return (i); 10102b4a7802SBaban Kenkre } 10112b4a7802SBaban Kenkre return (-1); 10122b4a7802SBaban Kenkre } 10132b4a7802SBaban Kenkre 10142b4a7802SBaban Kenkre static 10152b4a7802SBaban Kenkre void 10162b4a7802SBaban Kenkre free_entry(adutils_entry_t *entry) 10172b4a7802SBaban Kenkre { 10182b4a7802SBaban Kenkre int i, j; 10192b4a7802SBaban Kenkre adutils_attr_t *ap; 10202b4a7802SBaban Kenkre 10212b4a7802SBaban Kenkre if (entry == NULL) 10222b4a7802SBaban Kenkre return; 10232b4a7802SBaban Kenkre if (entry->attr_nvpairs == NULL) { 10242b4a7802SBaban Kenkre free(entry); 10252b4a7802SBaban Kenkre return; 10262b4a7802SBaban Kenkre } 10272b4a7802SBaban Kenkre for (i = 0; i < entry->num_nvpairs; i++) { 10282b4a7802SBaban Kenkre ap = &entry->attr_nvpairs[i]; 10292b4a7802SBaban Kenkre if (ap->attr_name == NULL) { 10302b4a7802SBaban Kenkre ldap_value_free(ap->attr_values); 10312b4a7802SBaban Kenkre continue; 10322b4a7802SBaban Kenkre } 10332b4a7802SBaban Kenkre if (check_for_binary_attrs(ap->attr_name) >= 0) { 10342b4a7802SBaban Kenkre free(ap->attr_name); 10352b4a7802SBaban Kenkre if (ap->attr_values == NULL) 10362b4a7802SBaban Kenkre continue; 10372b4a7802SBaban Kenkre for (j = 0; j < ap->num_values; j++) 10382b4a7802SBaban Kenkre free(ap->attr_values[j]); 10392b4a7802SBaban Kenkre free(ap->attr_values); 10402b4a7802SBaban Kenkre } else if (strcasecmp(ap->attr_name, "dn") == 0) { 10412b4a7802SBaban Kenkre free(ap->attr_name); 10422b4a7802SBaban Kenkre ldap_memfree(ap->attr_values[0]); 10432b4a7802SBaban Kenkre free(ap->attr_values); 10442b4a7802SBaban Kenkre } else { 10452b4a7802SBaban Kenkre free(ap->attr_name); 10462b4a7802SBaban Kenkre ldap_value_free(ap->attr_values); 10472b4a7802SBaban Kenkre } 10482b4a7802SBaban Kenkre } 10492b4a7802SBaban Kenkre free(entry->attr_nvpairs); 10502b4a7802SBaban Kenkre free(entry); 10512b4a7802SBaban Kenkre } 10522b4a7802SBaban Kenkre 10532b4a7802SBaban Kenkre void 10542b4a7802SBaban Kenkre adutils_freeresult(adutils_result_t **result) 10552b4a7802SBaban Kenkre { 10562b4a7802SBaban Kenkre adutils_entry_t *e, *next; 10572b4a7802SBaban Kenkre 10582b4a7802SBaban Kenkre if (result == NULL || *result == NULL) 10592b4a7802SBaban Kenkre return; 10602b4a7802SBaban Kenkre if ((*result)->entries == NULL) { 10612b4a7802SBaban Kenkre free(*result); 10622b4a7802SBaban Kenkre *result = NULL; 10632b4a7802SBaban Kenkre return; 10642b4a7802SBaban Kenkre } 10652b4a7802SBaban Kenkre for (e = (*result)->entries; e != NULL; e = next) { 10662b4a7802SBaban Kenkre next = e->next; 10672b4a7802SBaban Kenkre free_entry(e); 10682b4a7802SBaban Kenkre } 10692b4a7802SBaban Kenkre free(*result); 10702b4a7802SBaban Kenkre *result = NULL; 10712b4a7802SBaban Kenkre } 10722b4a7802SBaban Kenkre 10732b4a7802SBaban Kenkre const adutils_entry_t * 10742b4a7802SBaban Kenkre adutils_getfirstentry(adutils_result_t *result) 10752b4a7802SBaban Kenkre { 10762b4a7802SBaban Kenkre if (result != NULL) 10772b4a7802SBaban Kenkre return (result->entries); 10782b4a7802SBaban Kenkre return (NULL); 10792b4a7802SBaban Kenkre } 10802b4a7802SBaban Kenkre 10812b4a7802SBaban Kenkre 10822b4a7802SBaban Kenkre char ** 10832b4a7802SBaban Kenkre adutils_getattr(const adutils_entry_t *entry, const char *attrname) 10842b4a7802SBaban Kenkre { 10852b4a7802SBaban Kenkre int i; 10862b4a7802SBaban Kenkre adutils_attr_t *ap; 10872b4a7802SBaban Kenkre 10882b4a7802SBaban Kenkre if (entry == NULL || entry->attr_nvpairs == NULL) 10892b4a7802SBaban Kenkre return (NULL); 10902b4a7802SBaban Kenkre for (i = 0; i < entry->num_nvpairs; i++) { 10912b4a7802SBaban Kenkre ap = &entry->attr_nvpairs[i]; 10922b4a7802SBaban Kenkre if (ap->attr_name != NULL && 10932b4a7802SBaban Kenkre strcasecmp(ap->attr_name, attrname) == 0) 10942b4a7802SBaban Kenkre return (ap->attr_values); 10952b4a7802SBaban Kenkre } 10962b4a7802SBaban Kenkre return (NULL); 10972b4a7802SBaban Kenkre } 10982b4a7802SBaban Kenkre 10992b4a7802SBaban Kenkre 11002b4a7802SBaban Kenkre /* 11012b4a7802SBaban Kenkre * Queue LDAP result for the given query. 11022b4a7802SBaban Kenkre * 11032b4a7802SBaban Kenkre * Return values: 11042b4a7802SBaban Kenkre * 0 success 11052b4a7802SBaban Kenkre * -1 ignore result 11062b4a7802SBaban Kenkre * -2 error 11072b4a7802SBaban Kenkre */ 11082b4a7802SBaban Kenkre static 11092b4a7802SBaban Kenkre int 11102b4a7802SBaban Kenkre make_entry(adutils_q_t *q, adutils_host_t *adh, LDAPMessage *search_res, 11112b4a7802SBaban Kenkre adutils_entry_t **entry) 11122b4a7802SBaban Kenkre { 11132b4a7802SBaban Kenkre BerElement *ber = NULL; 11142b4a7802SBaban Kenkre BerValue **bvalues = NULL; 11152b4a7802SBaban Kenkre char **strvalues; 11162b4a7802SBaban Kenkre char *attr = NULL, *dn = NULL, *domain = NULL; 11172b4a7802SBaban Kenkre adutils_entry_t *ep; 11182b4a7802SBaban Kenkre adutils_attr_t *ap; 11192b4a7802SBaban Kenkre int i, j, b, err = 0, ret = -2; 11202b4a7802SBaban Kenkre 11212b4a7802SBaban Kenkre *entry = NULL; 11222b4a7802SBaban Kenkre 11232b4a7802SBaban Kenkre /* Check that this is the domain that we were looking for */ 11242b4a7802SBaban Kenkre if ((dn = ldap_get_dn(adh->ld, search_res)) == NULL) 11252b4a7802SBaban Kenkre return (-2); 11262b4a7802SBaban Kenkre if ((domain = adutils_dn2dns(dn)) == NULL) { 11272b4a7802SBaban Kenkre ldap_memfree(dn); 11282b4a7802SBaban Kenkre return (-2); 11292b4a7802SBaban Kenkre } 11302b4a7802SBaban Kenkre if (q->edomain != NULL) { 11312b4a7802SBaban Kenkre if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER, 11322b4a7802SBaban Kenkre U8_UNICODE_LATEST, &err) != 0 || err != 0) { 11332b4a7802SBaban Kenkre ldap_memfree(dn); 11342b4a7802SBaban Kenkre free(domain); 11352b4a7802SBaban Kenkre return (-1); 11362b4a7802SBaban Kenkre } 11372b4a7802SBaban Kenkre } 11382b4a7802SBaban Kenkre free(domain); 11392b4a7802SBaban Kenkre 11402b4a7802SBaban Kenkre /* Allocate memory for the entry */ 11412b4a7802SBaban Kenkre if ((ep = calloc(1, sizeof (*ep))) == NULL) 11422b4a7802SBaban Kenkre goto out; 11432b4a7802SBaban Kenkre 11442b4a7802SBaban Kenkre /* For 'dn' */ 11452b4a7802SBaban Kenkre ep->num_nvpairs = 1; 11462b4a7802SBaban Kenkre 11472b4a7802SBaban Kenkre /* Count the number of name-value pairs for this entry */ 11482b4a7802SBaban Kenkre for (attr = ldap_first_attribute(adh->ld, search_res, &ber); 11492b4a7802SBaban Kenkre attr != NULL; 11502b4a7802SBaban Kenkre attr = ldap_next_attribute(adh->ld, search_res, ber)) { 11512b4a7802SBaban Kenkre ep->num_nvpairs++; 11522b4a7802SBaban Kenkre ldap_memfree(attr); 11532b4a7802SBaban Kenkre } 11542b4a7802SBaban Kenkre ber_free(ber, 0); 11552b4a7802SBaban Kenkre ber = NULL; 11562b4a7802SBaban Kenkre 11572b4a7802SBaban Kenkre /* Allocate array for the attribute name-value pairs */ 11582b4a7802SBaban Kenkre ep->attr_nvpairs = calloc(ep->num_nvpairs, sizeof (*ep->attr_nvpairs)); 11592b4a7802SBaban Kenkre if (ep->attr_nvpairs == NULL) { 11602b4a7802SBaban Kenkre ep->num_nvpairs = 0; 11612b4a7802SBaban Kenkre goto out; 11622b4a7802SBaban Kenkre } 11632b4a7802SBaban Kenkre 11642b4a7802SBaban Kenkre /* For dn */ 11652b4a7802SBaban Kenkre ap = &ep->attr_nvpairs[0]; 11662b4a7802SBaban Kenkre if ((ap->attr_name = strdup("dn")) == NULL) 11672b4a7802SBaban Kenkre goto out; 11682b4a7802SBaban Kenkre ap->num_values = 1; 11692b4a7802SBaban Kenkre ap->attr_values = calloc(ap->num_values, sizeof (*ap->attr_values)); 11702b4a7802SBaban Kenkre if (ap->attr_values == NULL) { 11712b4a7802SBaban Kenkre ap->num_values = 0; 11722b4a7802SBaban Kenkre goto out; 11732b4a7802SBaban Kenkre } 11742b4a7802SBaban Kenkre ap->attr_values[0] = dn; 11752b4a7802SBaban Kenkre dn = NULL; 11762b4a7802SBaban Kenkre 11772b4a7802SBaban Kenkre for (attr = ldap_first_attribute(adh->ld, search_res, &ber), i = 1; 11782b4a7802SBaban Kenkre attr != NULL; 11792b4a7802SBaban Kenkre ldap_memfree(attr), i++, 11802b4a7802SBaban Kenkre attr = ldap_next_attribute(adh->ld, search_res, ber)) { 11812b4a7802SBaban Kenkre ap = &ep->attr_nvpairs[i]; 11822b4a7802SBaban Kenkre if ((ap->attr_name = strdup(attr)) == NULL) 11832b4a7802SBaban Kenkre goto out; 11842b4a7802SBaban Kenkre 11852b4a7802SBaban Kenkre if ((b = check_for_binary_attrs(attr)) >= 0) { 11862b4a7802SBaban Kenkre bvalues = 11872b4a7802SBaban Kenkre ldap_get_values_len(adh->ld, search_res, attr); 11882b4a7802SBaban Kenkre if (bvalues == NULL) 11892b4a7802SBaban Kenkre continue; 11902b4a7802SBaban Kenkre ap->num_values = ldap_count_values_len(bvalues); 11912b4a7802SBaban Kenkre if (ap->num_values == 0) { 11922b4a7802SBaban Kenkre ldap_value_free_len(bvalues); 11932b4a7802SBaban Kenkre bvalues = NULL; 11942b4a7802SBaban Kenkre continue; 11952b4a7802SBaban Kenkre } 11962b4a7802SBaban Kenkre ap->attr_values = calloc(ap->num_values, 11972b4a7802SBaban Kenkre 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 for (j = 0; j < ap->num_values; j++) { 12032b4a7802SBaban Kenkre ap->attr_values[j] = 12042b4a7802SBaban Kenkre binattrs[b].ber2str(bvalues[j]); 12052b4a7802SBaban Kenkre if (ap->attr_values[j] == NULL) 12062b4a7802SBaban Kenkre goto out; 12072b4a7802SBaban Kenkre } 12082b4a7802SBaban Kenkre ldap_value_free_len(bvalues); 12092b4a7802SBaban Kenkre bvalues = NULL; 12102b4a7802SBaban Kenkre continue; 12112b4a7802SBaban Kenkre } 12122b4a7802SBaban Kenkre 12132b4a7802SBaban Kenkre strvalues = ldap_get_values(adh->ld, search_res, attr); 12142b4a7802SBaban Kenkre if (strvalues == NULL) 12152b4a7802SBaban Kenkre continue; 12162b4a7802SBaban Kenkre ap->num_values = ldap_count_values(strvalues); 12172b4a7802SBaban Kenkre if (ap->num_values == 0) { 12182b4a7802SBaban Kenkre ldap_value_free(strvalues); 12192b4a7802SBaban Kenkre continue; 12202b4a7802SBaban Kenkre } 12212b4a7802SBaban Kenkre ap->attr_values = strvalues; 12222b4a7802SBaban Kenkre } 12232b4a7802SBaban Kenkre 12242b4a7802SBaban Kenkre ret = 0; 12252b4a7802SBaban Kenkre out: 12262b4a7802SBaban Kenkre ldap_memfree(attr); 12272b4a7802SBaban Kenkre ldap_memfree(dn); 12282b4a7802SBaban Kenkre ber_free(ber, 0); 12292b4a7802SBaban Kenkre ldap_value_free_len(bvalues); 12302b4a7802SBaban Kenkre if (ret < 0) 12312b4a7802SBaban Kenkre free_entry(ep); 12322b4a7802SBaban Kenkre else 12332b4a7802SBaban Kenkre *entry = ep; 12342b4a7802SBaban Kenkre return (ret); 12352b4a7802SBaban Kenkre } 12362b4a7802SBaban Kenkre 12372b4a7802SBaban Kenkre /* 12382b4a7802SBaban Kenkre * Put the search result onto the given adutils_q_t. 12392b4a7802SBaban Kenkre * Returns: 0 success 12402b4a7802SBaban Kenkre * < 0 error 12412b4a7802SBaban Kenkre */ 12422b4a7802SBaban Kenkre static 12432b4a7802SBaban Kenkre int 12442b4a7802SBaban Kenkre add_entry(adutils_host_t *adh, adutils_q_t *q, LDAPMessage *search_res) 12452b4a7802SBaban Kenkre { 12462b4a7802SBaban Kenkre int ret = -1; 12472b4a7802SBaban Kenkre adutils_entry_t *entry = NULL; 12482b4a7802SBaban Kenkre adutils_result_t *res; 12492b4a7802SBaban Kenkre 12502b4a7802SBaban Kenkre ret = make_entry(q, adh, search_res, &entry); 12512b4a7802SBaban Kenkre if (ret < -1) { 12522b4a7802SBaban Kenkre *q->rc = ADUTILS_ERR_MEMORY; 12532b4a7802SBaban Kenkre goto out; 12542b4a7802SBaban Kenkre } else if (ret == -1) { 12552b4a7802SBaban Kenkre /* ignore result */ 12562b4a7802SBaban Kenkre goto out; 12572b4a7802SBaban Kenkre } 12582b4a7802SBaban Kenkre if (*q->result == NULL) { 12592b4a7802SBaban Kenkre res = calloc(1, sizeof (*res)); 12602b4a7802SBaban Kenkre if (res == NULL) { 12612b4a7802SBaban Kenkre *q->rc = ADUTILS_ERR_MEMORY; 12622b4a7802SBaban Kenkre goto out; 12632b4a7802SBaban Kenkre } 12642b4a7802SBaban Kenkre res->num_entries = 1; 12652b4a7802SBaban Kenkre res->entries = entry; 12662b4a7802SBaban Kenkre *q->result = res; 12672b4a7802SBaban Kenkre } else { 12682b4a7802SBaban Kenkre res = *q->result; 12692b4a7802SBaban Kenkre entry->next = res->entries; 12702b4a7802SBaban Kenkre res->entries = entry; 12712b4a7802SBaban Kenkre res->num_entries++; 12722b4a7802SBaban Kenkre } 12732b4a7802SBaban Kenkre *q->rc = ADUTILS_SUCCESS; 12742b4a7802SBaban Kenkre entry = NULL; 12752b4a7802SBaban Kenkre ret = 0; 12762b4a7802SBaban Kenkre 12772b4a7802SBaban Kenkre out: 12782b4a7802SBaban Kenkre free_entry(entry); 12792b4a7802SBaban Kenkre return (ret); 12802b4a7802SBaban Kenkre } 12812b4a7802SBaban Kenkre 12822b4a7802SBaban Kenkre /* 12832b4a7802SBaban Kenkre * Try to get a result; if there is one, find the corresponding 12842b4a7802SBaban Kenkre * adutils_q_t and process the result. 12852b4a7802SBaban Kenkre * 12862b4a7802SBaban Kenkre * Returns: 0 success 12872b4a7802SBaban Kenkre * -1 error 12882b4a7802SBaban Kenkre */ 12892b4a7802SBaban Kenkre static 12902b4a7802SBaban Kenkre int 12912b4a7802SBaban Kenkre get_adobject_batch(adutils_host_t *adh, struct timeval *timeout) 12922b4a7802SBaban Kenkre { 12932b4a7802SBaban Kenkre adutils_query_state_t *query_state; 12942b4a7802SBaban Kenkre LDAPMessage *res = NULL; 12952b4a7802SBaban Kenkre int rc, ret, msgid, qid; 12962b4a7802SBaban Kenkre adutils_q_t *que; 12972b4a7802SBaban Kenkre int num; 12982b4a7802SBaban Kenkre 12992b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 13002b4a7802SBaban Kenkre if (adh->dead || adh->num_requests == 0) { 13012b4a7802SBaban Kenkre ret = (adh->dead) ? -1 : -2; 13022b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 13032b4a7802SBaban Kenkre return (ret); 13042b4a7802SBaban Kenkre } 13052b4a7802SBaban Kenkre 13062b4a7802SBaban Kenkre /* Get one result */ 13072b4a7802SBaban Kenkre rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, timeout, &res); 13082b4a7802SBaban Kenkre if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) || 13092b4a7802SBaban Kenkre rc < 0) 13102b4a7802SBaban Kenkre adh->dead = 1; 13112b4a7802SBaban Kenkre 13122b4a7802SBaban Kenkre if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0) 13132b4a7802SBaban Kenkre adh->num_requests--; 13142b4a7802SBaban Kenkre if (adh->dead) { 13152b4a7802SBaban Kenkre num = adh->num_requests; 13162b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1317*7a8a68f5SJulian Pullen logger(LOG_DEBUG, 13182b4a7802SBaban Kenkre "AD ldap_result error - %d queued requests", num); 13192b4a7802SBaban Kenkre return (-1); 13202b4a7802SBaban Kenkre } 13212b4a7802SBaban Kenkre 13222b4a7802SBaban Kenkre switch (rc) { 13232b4a7802SBaban Kenkre case LDAP_RES_SEARCH_RESULT: 13242b4a7802SBaban Kenkre msgid = ldap_msgid(res); 13252b4a7802SBaban Kenkre if (msgid2query(adh, msgid, &query_state, &qid)) { 13262b4a7802SBaban Kenkre if (query_state->ldap_res_search_cb != NULL) { 13272b4a7802SBaban Kenkre /* 13282b4a7802SBaban Kenkre * We use the caller-provided callback 13292b4a7802SBaban Kenkre * to process the result. 13302b4a7802SBaban Kenkre */ 13312b4a7802SBaban Kenkre query_state->ldap_res_search_cb( 13322b4a7802SBaban Kenkre adh->ld, &res, rc, qid, 13332b4a7802SBaban Kenkre query_state->ldap_res_search_argp); 13342b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 13352b4a7802SBaban Kenkre } else { 13362b4a7802SBaban Kenkre /* 13372b4a7802SBaban Kenkre * No callback. We fallback to our 13382b4a7802SBaban Kenkre * default behaviour. All the entries 13392b4a7802SBaban Kenkre * gotten from this search have been 13402b4a7802SBaban Kenkre * added to the result list during 13412b4a7802SBaban Kenkre * LDAP_RES_SEARCH_ENTRY (see below). 13422b4a7802SBaban Kenkre * Here we set the return status to 13432b4a7802SBaban Kenkre * notfound if the result is still empty. 13442b4a7802SBaban Kenkre */ 13452b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 13462b4a7802SBaban Kenkre que = &(query_state->queries[qid]); 13472b4a7802SBaban Kenkre if (*que->result == NULL) 13482b4a7802SBaban Kenkre *que->rc = ADUTILS_ERR_NOTFOUND; 13492b4a7802SBaban Kenkre } 13502b4a7802SBaban Kenkre atomic_dec_32(&query_state->qinflight); 13512b4a7802SBaban Kenkre adutils_lookup_batch_unlock(&query_state); 13522b4a7802SBaban Kenkre } else { 13532b4a7802SBaban Kenkre num = adh->num_requests; 13542b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1355*7a8a68f5SJulian Pullen logger(LOG_DEBUG, 13562b4a7802SBaban Kenkre "AD cannot find message ID (%d) " 13572b4a7802SBaban Kenkre "- %d queued requests", 13582b4a7802SBaban Kenkre msgid, num); 13592b4a7802SBaban Kenkre } 13602b4a7802SBaban Kenkre (void) ldap_msgfree(res); 13612b4a7802SBaban Kenkre ret = 0; 13622b4a7802SBaban Kenkre break; 13632b4a7802SBaban Kenkre 13642b4a7802SBaban Kenkre case LDAP_RES_SEARCH_ENTRY: 13652b4a7802SBaban Kenkre msgid = ldap_msgid(res); 13662b4a7802SBaban Kenkre if (msgid2query(adh, msgid, &query_state, &qid)) { 13672b4a7802SBaban Kenkre if (query_state->ldap_res_search_cb != NULL) { 13682b4a7802SBaban Kenkre /* 13692b4a7802SBaban Kenkre * We use the caller-provided callback 13702b4a7802SBaban Kenkre * to process the entry. 13712b4a7802SBaban Kenkre */ 13722b4a7802SBaban Kenkre query_state->ldap_res_search_cb( 13732b4a7802SBaban Kenkre adh->ld, &res, rc, qid, 13742b4a7802SBaban Kenkre query_state->ldap_res_search_argp); 13752b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 13762b4a7802SBaban Kenkre } else { 13772b4a7802SBaban Kenkre /* 13782b4a7802SBaban Kenkre * No callback. We fallback to our 13792b4a7802SBaban Kenkre * default behaviour. This entry 13802b4a7802SBaban Kenkre * will be added to the result list. 13812b4a7802SBaban Kenkre */ 13822b4a7802SBaban Kenkre que = &(query_state->queries[qid]); 13832b4a7802SBaban Kenkre rc = add_entry(adh, que, res); 13842b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 13852b4a7802SBaban Kenkre if (rc < 0) { 1386*7a8a68f5SJulian Pullen logger(LOG_DEBUG, 13872b4a7802SBaban Kenkre "Failed to queue entry by " 13882b4a7802SBaban Kenkre "message ID (%d) " 13892b4a7802SBaban Kenkre "- %d queued requests", 13902b4a7802SBaban Kenkre msgid, num); 13912b4a7802SBaban Kenkre } 13922b4a7802SBaban Kenkre } 13932b4a7802SBaban Kenkre adutils_lookup_batch_unlock(&query_state); 13942b4a7802SBaban Kenkre } else { 13952b4a7802SBaban Kenkre num = adh->num_requests; 13962b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1397*7a8a68f5SJulian Pullen logger(LOG_DEBUG, 13982b4a7802SBaban Kenkre "AD cannot find message ID (%d) " 13992b4a7802SBaban Kenkre "- %d queued requests", 14002b4a7802SBaban Kenkre msgid, num); 14012b4a7802SBaban Kenkre } 14022b4a7802SBaban Kenkre (void) ldap_msgfree(res); 14032b4a7802SBaban Kenkre ret = 0; 14042b4a7802SBaban Kenkre break; 14052b4a7802SBaban Kenkre 14062b4a7802SBaban Kenkre case LDAP_RES_SEARCH_REFERENCE: 14072b4a7802SBaban Kenkre /* 14082b4a7802SBaban Kenkre * We have no need for these at the moment. Eventually, 14092b4a7802SBaban Kenkre * when we query things that we can't expect to find in 14102b4a7802SBaban Kenkre * the Global Catalog then we'll need to learn to follow 14112b4a7802SBaban Kenkre * references. 14122b4a7802SBaban Kenkre */ 14132b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 14142b4a7802SBaban Kenkre (void) ldap_msgfree(res); 14152b4a7802SBaban Kenkre ret = 0; 14162b4a7802SBaban Kenkre break; 14172b4a7802SBaban Kenkre 14182b4a7802SBaban Kenkre default: 14192b4a7802SBaban Kenkre /* timeout or error; treat the same */ 14202b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 14212b4a7802SBaban Kenkre ret = -1; 14222b4a7802SBaban Kenkre break; 14232b4a7802SBaban Kenkre } 14242b4a7802SBaban Kenkre 14252b4a7802SBaban Kenkre return (ret); 14262b4a7802SBaban Kenkre } 14272b4a7802SBaban Kenkre 14282b4a7802SBaban Kenkre /* 14292b4a7802SBaban Kenkre * This routine decreament the reference count of the 14302b4a7802SBaban Kenkre * adutils_query_state_t 14312b4a7802SBaban Kenkre */ 14322b4a7802SBaban Kenkre static void 14332b4a7802SBaban Kenkre adutils_lookup_batch_unlock(adutils_query_state_t **state) 14342b4a7802SBaban Kenkre { 14352b4a7802SBaban Kenkre /* 14362b4a7802SBaban Kenkre * Decrement reference count with qstatelock locked 14372b4a7802SBaban Kenkre */ 14382b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 14392b4a7802SBaban Kenkre (*state)->ref_cnt--; 14402b4a7802SBaban Kenkre /* 14412b4a7802SBaban Kenkre * If there are no references wakup the allocating thread 14422b4a7802SBaban Kenkre */ 14432b4a7802SBaban Kenkre if ((*state)->ref_cnt <= 1) 14442b4a7802SBaban Kenkre (void) pthread_cond_signal(&(*state)->cv); 14452b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 14462b4a7802SBaban Kenkre *state = NULL; 14472b4a7802SBaban Kenkre } 14482b4a7802SBaban Kenkre 14492b4a7802SBaban Kenkre /* 14502b4a7802SBaban Kenkre * This routine frees the adutils_query_state_t structure 14512b4a7802SBaban Kenkre * If the reference count is greater than 1 it waits 14522b4a7802SBaban Kenkre * for the other threads to finish using it. 14532b4a7802SBaban Kenkre */ 14542b4a7802SBaban Kenkre void 14552b4a7802SBaban Kenkre adutils_lookup_batch_release(adutils_query_state_t **state) 14562b4a7802SBaban Kenkre { 14572b4a7802SBaban Kenkre adutils_query_state_t **p; 14582b4a7802SBaban Kenkre int i; 14592b4a7802SBaban Kenkre 14602b4a7802SBaban Kenkre if (state == NULL || *state == NULL) 14612b4a7802SBaban Kenkre return; 14622b4a7802SBaban Kenkre 14632b4a7802SBaban Kenkre /* 14642b4a7802SBaban Kenkre * Set state to dead to stop further operations. 14652b4a7802SBaban Kenkre * Wait for reference count with qstatelock locked 14662b4a7802SBaban Kenkre * to get to one. 14672b4a7802SBaban Kenkre */ 14682b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 14692b4a7802SBaban Kenkre (*state)->qdead = 1; 14702b4a7802SBaban Kenkre while ((*state)->ref_cnt > 1) { 14712b4a7802SBaban Kenkre (void) pthread_cond_wait(&(*state)->cv, &qstatelock); 14722b4a7802SBaban Kenkre } 14732b4a7802SBaban Kenkre 14742b4a7802SBaban Kenkre /* Remove this state struct from the list of state structs */ 14752b4a7802SBaban Kenkre for (p = &qstatehead; *p != NULL; p = &(*p)->next) { 14762b4a7802SBaban Kenkre if (*p == (*state)) { 14772b4a7802SBaban Kenkre *p = (*state)->next; 14782b4a7802SBaban Kenkre break; 14792b4a7802SBaban Kenkre } 14802b4a7802SBaban Kenkre } 14812b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 14822b4a7802SBaban Kenkre (void) pthread_cond_destroy(&(*state)->cv); 14832b4a7802SBaban Kenkre release_conn((*state)->qadh); 14842b4a7802SBaban Kenkre 14852b4a7802SBaban Kenkre /* Clear results for queries that failed */ 14862b4a7802SBaban Kenkre for (i = 0; i < (*state)->qcount; i++) { 14872b4a7802SBaban Kenkre if (*(*state)->queries[i].rc != ADUTILS_SUCCESS) { 14882b4a7802SBaban Kenkre adutils_freeresult((*state)->queries[i].result); 14892b4a7802SBaban Kenkre } 14902b4a7802SBaban Kenkre } 14912b4a7802SBaban Kenkre free((*state)->default_domain); 14922b4a7802SBaban Kenkre free((*state)->basedn); 14932b4a7802SBaban Kenkre free(*state); 14942b4a7802SBaban Kenkre *state = NULL; 14952b4a7802SBaban Kenkre } 14962b4a7802SBaban Kenkre 14972b4a7802SBaban Kenkre 14982b4a7802SBaban Kenkre /* 14992b4a7802SBaban Kenkre * This routine waits for other threads using the 15002b4a7802SBaban Kenkre * adutils_query_state_t structure to finish. 15012b4a7802SBaban Kenkre * If the reference count is greater than 1 it waits 15022b4a7802SBaban Kenkre * for the other threads to finish using it. 15032b4a7802SBaban Kenkre */ 15042b4a7802SBaban Kenkre static 15052b4a7802SBaban Kenkre void 15062b4a7802SBaban Kenkre adutils_lookup_batch_wait(adutils_query_state_t *state) 15072b4a7802SBaban Kenkre { 15082b4a7802SBaban Kenkre /* 15092b4a7802SBaban Kenkre * Set state to dead to stop further operation. 15102b4a7802SBaban Kenkre * stating. 15112b4a7802SBaban Kenkre * Wait for reference count to get to one 15122b4a7802SBaban Kenkre * with qstatelock locked. 15132b4a7802SBaban Kenkre */ 15142b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 15152b4a7802SBaban Kenkre state->qdead = 1; 15162b4a7802SBaban Kenkre while (state->ref_cnt > 1) { 15172b4a7802SBaban Kenkre (void) pthread_cond_wait(&state->cv, &qstatelock); 15182b4a7802SBaban Kenkre } 15192b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 15202b4a7802SBaban Kenkre } 15212b4a7802SBaban Kenkre 15222b4a7802SBaban Kenkre /* 15232b4a7802SBaban Kenkre * Process active queries in the AD lookup batch and then finalize the 15242b4a7802SBaban Kenkre * result. 15252b4a7802SBaban Kenkre */ 15262b4a7802SBaban Kenkre adutils_rc 15272b4a7802SBaban Kenkre adutils_lookup_batch_end(adutils_query_state_t **state) 15282b4a7802SBaban Kenkre { 15292b4a7802SBaban Kenkre int rc = LDAP_SUCCESS; 15302b4a7802SBaban Kenkre adutils_rc ad_rc = ADUTILS_SUCCESS; 15312b4a7802SBaban Kenkre struct timeval tv; 15322b4a7802SBaban Kenkre 15332b4a7802SBaban Kenkre tv.tv_sec = ADUTILS_SEARCH_TIMEOUT; 15342b4a7802SBaban Kenkre tv.tv_usec = 0; 15352b4a7802SBaban Kenkre 15362b4a7802SBaban Kenkre /* Process results until done or until timeout, if given */ 15372b4a7802SBaban Kenkre while ((*state)->qinflight > 0) { 15382b4a7802SBaban Kenkre if ((rc = get_adobject_batch((*state)->qadh, 15392b4a7802SBaban Kenkre &tv)) != 0) 15402b4a7802SBaban Kenkre break; 15412b4a7802SBaban Kenkre } 15422b4a7802SBaban Kenkre (*state)->qdead = 1; 15432b4a7802SBaban Kenkre /* Wait for other threads processing search result to finish */ 15442b4a7802SBaban Kenkre adutils_lookup_batch_wait(*state); 15452b4a7802SBaban Kenkre if (rc == -1 || (*state)->qinflight != 0) 15462b4a7802SBaban Kenkre ad_rc = ADUTILS_ERR_RETRIABLE_NET_ERR; 15472b4a7802SBaban Kenkre adutils_lookup_batch_release(state); 15482b4a7802SBaban Kenkre return (ad_rc); 15492b4a7802SBaban Kenkre } 15502b4a7802SBaban Kenkre 15512b4a7802SBaban Kenkre const char * 15522b4a7802SBaban Kenkre adutils_lookup_batch_getdefdomain(adutils_query_state_t *state) 15532b4a7802SBaban Kenkre { 15542b4a7802SBaban Kenkre return (state->default_domain); 15552b4a7802SBaban Kenkre } 15562b4a7802SBaban Kenkre 15572b4a7802SBaban Kenkre /* 15582b4a7802SBaban Kenkre * Send one prepared search, queue up msgid, process what results are 15592b4a7802SBaban Kenkre * available 15602b4a7802SBaban Kenkre */ 15612b4a7802SBaban Kenkre adutils_rc 15622b4a7802SBaban Kenkre adutils_lookup_batch_add(adutils_query_state_t *state, 15632b4a7802SBaban Kenkre const char *filter, const char **attrs, const char *edomain, 15642b4a7802SBaban Kenkre adutils_result_t **result, adutils_rc *rc) 15652b4a7802SBaban Kenkre { 15662b4a7802SBaban Kenkre adutils_rc retcode = ADUTILS_SUCCESS; 15672b4a7802SBaban Kenkre int lrc, qid; 15682b4a7802SBaban Kenkre int num; 15692b4a7802SBaban Kenkre int dead; 15702b4a7802SBaban Kenkre struct timeval tv; 15712b4a7802SBaban Kenkre adutils_q_t *q; 15722b4a7802SBaban Kenkre 15734d61c878SJulian Pullen qid = atomic_inc_32_nv(&state->qcount) - 1; 15742b4a7802SBaban Kenkre q = &(state->queries[qid]); 15752b4a7802SBaban Kenkre 15764d61c878SJulian Pullen assert(qid < state->qsize); 15774d61c878SJulian Pullen 15782b4a7802SBaban Kenkre /* 15792b4a7802SBaban Kenkre * Remember the expected domain so we can check the results 15802b4a7802SBaban Kenkre * against it 15812b4a7802SBaban Kenkre */ 15822b4a7802SBaban Kenkre q->edomain = edomain; 15832b4a7802SBaban Kenkre 15842b4a7802SBaban Kenkre /* Remember where to put the results */ 15852b4a7802SBaban Kenkre q->result = result; 15862b4a7802SBaban Kenkre q->rc = rc; 15872b4a7802SBaban Kenkre 15882b4a7802SBaban Kenkre /* 15892b4a7802SBaban Kenkre * Provide sane defaults for the results in case we never hear 15902b4a7802SBaban Kenkre * back from the DS before closing the connection. 15912b4a7802SBaban Kenkre */ 15922b4a7802SBaban Kenkre *rc = ADUTILS_ERR_RETRIABLE_NET_ERR; 15932b4a7802SBaban Kenkre if (result != NULL) 15942b4a7802SBaban Kenkre *result = NULL; 15952b4a7802SBaban Kenkre 15962b4a7802SBaban Kenkre /* Check the number of queued requests first */ 15972b4a7802SBaban Kenkre tv.tv_sec = ADUTILS_SEARCH_TIMEOUT; 15982b4a7802SBaban Kenkre tv.tv_usec = 0; 15992b4a7802SBaban Kenkre while (!state->qadh->dead && 16002b4a7802SBaban Kenkre state->qadh->num_requests > state->qadh->max_requests) { 16012b4a7802SBaban Kenkre if (get_adobject_batch(state->qadh, &tv) != 0) 16022b4a7802SBaban Kenkre break; 16032b4a7802SBaban Kenkre } 16042b4a7802SBaban Kenkre 16052b4a7802SBaban Kenkre /* Send this lookup, don't wait for a result here */ 16062b4a7802SBaban Kenkre lrc = LDAP_SUCCESS; 16072b4a7802SBaban Kenkre (void) pthread_mutex_lock(&state->qadh->lock); 16082b4a7802SBaban Kenkre 16092b4a7802SBaban Kenkre if (!state->qadh->dead) { 16102b4a7802SBaban Kenkre state->qadh->idletime = time(NULL); 16112b4a7802SBaban Kenkre lrc = ldap_search_ext(state->qadh->ld, state->basedn, 16122b4a7802SBaban Kenkre LDAP_SCOPE_SUBTREE, filter, (char **)attrs, 16132b4a7802SBaban Kenkre 0, NULL, NULL, NULL, -1, &q->msgid); 16142b4a7802SBaban Kenkre 16152b4a7802SBaban Kenkre if (lrc == LDAP_SUCCESS) { 16162b4a7802SBaban Kenkre state->qadh->num_requests++; 16172b4a7802SBaban Kenkre } else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE || 16182b4a7802SBaban Kenkre lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN || 16192b4a7802SBaban Kenkre lrc == LDAP_UNWILLING_TO_PERFORM) { 16202b4a7802SBaban Kenkre retcode = ADUTILS_ERR_RETRIABLE_NET_ERR; 16212b4a7802SBaban Kenkre state->qadh->dead = 1; 16222b4a7802SBaban Kenkre } else { 16232b4a7802SBaban Kenkre retcode = ADUTILS_ERR_OTHER; 16242b4a7802SBaban Kenkre state->qadh->dead = 1; 16252b4a7802SBaban Kenkre } 16262b4a7802SBaban Kenkre } 16272b4a7802SBaban Kenkre dead = state->qadh->dead; 16282b4a7802SBaban Kenkre num = state->qadh->num_requests; 16292b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&state->qadh->lock); 16302b4a7802SBaban Kenkre 16312b4a7802SBaban Kenkre if (dead) { 16322b4a7802SBaban Kenkre if (lrc != LDAP_SUCCESS) 1633*7a8a68f5SJulian Pullen logger(LOG_DEBUG, 16342b4a7802SBaban Kenkre "AD ldap_search_ext error (%s) " 16352b4a7802SBaban Kenkre "- %d queued requests", 16362b4a7802SBaban Kenkre ldap_err2string(lrc), num); 16372b4a7802SBaban Kenkre return (retcode); 16382b4a7802SBaban Kenkre } 16392b4a7802SBaban Kenkre 16402b4a7802SBaban Kenkre atomic_inc_32(&state->qinflight); 16412b4a7802SBaban Kenkre 16422b4a7802SBaban Kenkre /* 16432b4a7802SBaban Kenkre * Reap as many requests as we can _without_ waiting to prevent 16442b4a7802SBaban Kenkre * any possible TCP socket buffer starvation deadlocks. 16452b4a7802SBaban Kenkre */ 16462b4a7802SBaban Kenkre (void) memset(&tv, 0, sizeof (tv)); 16472b4a7802SBaban Kenkre while (get_adobject_batch(state->qadh, &tv) == 0) 16482b4a7802SBaban Kenkre ; 16492b4a7802SBaban Kenkre 16502b4a7802SBaban Kenkre return (ADUTILS_SUCCESS); 16512b4a7802SBaban Kenkre } 16522b4a7802SBaban Kenkre 16532b4a7802SBaban Kenkre /* 16542b4a7802SBaban Kenkre * Single AD lookup request implemented on top of the batch API. 16552b4a7802SBaban Kenkre */ 16562b4a7802SBaban Kenkre adutils_rc 16572b4a7802SBaban Kenkre adutils_lookup(adutils_ad_t *ad, const char *filter, const char **attrs, 16582b4a7802SBaban Kenkre const char *domain, adutils_result_t **result) 16592b4a7802SBaban Kenkre { 16602b4a7802SBaban Kenkre adutils_rc rc, brc; 16612b4a7802SBaban Kenkre adutils_query_state_t *qs; 16622b4a7802SBaban Kenkre 16632b4a7802SBaban Kenkre rc = adutils_lookup_batch_start(ad, 1, NULL, NULL, &qs); 16642b4a7802SBaban Kenkre if (rc != ADUTILS_SUCCESS) 16652b4a7802SBaban Kenkre return (rc); 16662b4a7802SBaban Kenkre 16672b4a7802SBaban Kenkre rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc); 16682b4a7802SBaban Kenkre if (rc != ADUTILS_SUCCESS) { 16692b4a7802SBaban Kenkre adutils_lookup_batch_release(&qs); 16702b4a7802SBaban Kenkre return (rc); 16712b4a7802SBaban Kenkre } 16722b4a7802SBaban Kenkre 16732b4a7802SBaban Kenkre rc = adutils_lookup_batch_end(&qs); 16742b4a7802SBaban Kenkre if (rc != ADUTILS_SUCCESS) 16752b4a7802SBaban Kenkre return (rc); 16762b4a7802SBaban Kenkre return (brc); 16772b4a7802SBaban Kenkre } 1678