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 /* 222b4a7802SBaban Kenkre * Copyright 2008 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> 382b4a7802SBaban Kenkre #include <sys/u8_textprep.h> 392b4a7802SBaban Kenkre #include <sys/varargs.h> 402b4a7802SBaban Kenkre #include "libadutils.h" 412b4a7802SBaban Kenkre #include "adutils_impl.h" 422b4a7802SBaban Kenkre 432b4a7802SBaban Kenkre /* List of DSs, needed by the idle connection reaper thread */ 442b4a7802SBaban Kenkre static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER; 452b4a7802SBaban Kenkre static adutils_host_t *host_head = NULL; 462b4a7802SBaban Kenkre 472b4a7802SBaban Kenkre /* 482b4a7802SBaban Kenkre * List of query state structs -- needed so we can "route" LDAP results 492b4a7802SBaban Kenkre * to the right context if multiple threads should be using the same 502b4a7802SBaban Kenkre * connection concurrently 512b4a7802SBaban Kenkre */ 522b4a7802SBaban Kenkre static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER; 532b4a7802SBaban Kenkre static adutils_query_state_t *qstatehead = NULL; 542b4a7802SBaban Kenkre 552b4a7802SBaban Kenkre static char *adutils_sid_ber2str(BerValue *bvalues); 562b4a7802SBaban Kenkre static void adutils_lookup_batch_unlock(adutils_query_state_t **state); 572b4a7802SBaban Kenkre static void delete_ds(adutils_ad_t *ad, const char *host, int port); 582b4a7802SBaban Kenkre 592b4a7802SBaban Kenkre typedef struct binary_attrs { 602b4a7802SBaban Kenkre const char *name; 612b4a7802SBaban Kenkre char *(*ber2str)(BerValue *bvalues); 622b4a7802SBaban Kenkre } binary_attrs_t; 632b4a7802SBaban Kenkre 642b4a7802SBaban Kenkre static binary_attrs_t binattrs[] = { 652b4a7802SBaban Kenkre {"objectSID", adutils_sid_ber2str}, 662b4a7802SBaban Kenkre {NULL, NULL} 672b4a7802SBaban Kenkre }; 682b4a7802SBaban Kenkre 69*4d61c878SJulian Pullen 702b4a7802SBaban Kenkre void 712b4a7802SBaban Kenkre adutils_set_log(int pri, bool_t syslog, bool_t degraded) 722b4a7802SBaban Kenkre { 732b4a7802SBaban Kenkre idmap_log_stderr(pri); 742b4a7802SBaban Kenkre idmap_log_syslog(syslog); 752b4a7802SBaban Kenkre idmap_log_degraded(degraded); 762b4a7802SBaban Kenkre } 772b4a7802SBaban Kenkre 78*4d61c878SJulian Pullen 792b4a7802SBaban Kenkre /* 802b4a7802SBaban Kenkre * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com" 812b4a7802SBaban Kenkre */ 822b4a7802SBaban Kenkre static 832b4a7802SBaban Kenkre char * 842b4a7802SBaban Kenkre adutils_dns2dn(const char *dns) 852b4a7802SBaban Kenkre { 862b4a7802SBaban Kenkre int nameparts; 872b4a7802SBaban Kenkre return (ldap_dns_to_dn((char *)dns, &nameparts)); 882b4a7802SBaban Kenkre } 892b4a7802SBaban Kenkre 90*4d61c878SJulian Pullen 912b4a7802SBaban Kenkre /* 922b4a7802SBaban Kenkre * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other 932b4a7802SBaban Kenkre * attributes (CN, etc...). 942b4a7802SBaban Kenkre */ 952b4a7802SBaban Kenkre char * 962b4a7802SBaban Kenkre adutils_dn2dns(const char *dn) 972b4a7802SBaban Kenkre { 982b4a7802SBaban Kenkre char **rdns = NULL; 992b4a7802SBaban Kenkre char **attrs = NULL; 1002b4a7802SBaban Kenkre char **labels = NULL; 1012b4a7802SBaban Kenkre char *dns = NULL; 1022b4a7802SBaban Kenkre char **rdn, **attr, **label; 1032b4a7802SBaban Kenkre int maxlabels = 5; 1042b4a7802SBaban Kenkre int nlabels = 0; 1052b4a7802SBaban Kenkre int dnslen; 1062b4a7802SBaban Kenkre 1072b4a7802SBaban Kenkre /* 1082b4a7802SBaban Kenkre * There is no reverse of ldap_dns_to_dn() in our libldap, so we 1092b4a7802SBaban Kenkre * have to do the hard work here for now. 1102b4a7802SBaban Kenkre */ 1112b4a7802SBaban Kenkre 1122b4a7802SBaban Kenkre /* 1132b4a7802SBaban Kenkre * This code is much too liberal: it looks for "dc" attributes 1142b4a7802SBaban Kenkre * in all RDNs of the DN. In theory this could cause problems 1152b4a7802SBaban Kenkre * if people were to use "dc" in nodes other than the root of 1162b4a7802SBaban Kenkre * the tree, but in practice noone, least of all Active 1172b4a7802SBaban Kenkre * Directory, does that. 1182b4a7802SBaban Kenkre * 1192b4a7802SBaban Kenkre * On the other hand, this code is much too conservative: it 1202b4a7802SBaban Kenkre * does not make assumptions about ldap_explode_dn(), and _that_ 1212b4a7802SBaban Kenkre * is the true for looking at every attr of every RDN. 1222b4a7802SBaban Kenkre * 1232b4a7802SBaban Kenkre * Since we only ever look at dc and those must be DNS labels, 1242b4a7802SBaban Kenkre * at least until we get around to supporting IDN here we 1252b4a7802SBaban Kenkre * shouldn't see escaped labels from AD nor from libldap, though 1262b4a7802SBaban Kenkre * the spec (RFC2253) does allow libldap to escape things that 1272b4a7802SBaban Kenkre * don't need escaping -- if that should ever happen then 1282b4a7802SBaban Kenkre * libldap will need a spanking, and we can take care of that. 1292b4a7802SBaban Kenkre */ 1302b4a7802SBaban Kenkre 1312b4a7802SBaban Kenkre /* Explode a DN into RDNs */ 1322b4a7802SBaban Kenkre if ((rdns = ldap_explode_dn(dn, 0)) == NULL) 1332b4a7802SBaban Kenkre return (NULL); 1342b4a7802SBaban Kenkre 1352b4a7802SBaban Kenkre labels = calloc(maxlabels + 1, sizeof (char *)); 1362b4a7802SBaban Kenkre label = labels; 1372b4a7802SBaban Kenkre 1382b4a7802SBaban Kenkre for (rdn = rdns; *rdn != NULL; rdn++) { 1392b4a7802SBaban Kenkre if (attrs != NULL) 1402b4a7802SBaban Kenkre ldap_value_free(attrs); 1412b4a7802SBaban Kenkre 1422b4a7802SBaban Kenkre /* Explode each RDN, look for DC attr, save val as DNS label */ 1432b4a7802SBaban Kenkre if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) 1442b4a7802SBaban Kenkre goto done; 1452b4a7802SBaban Kenkre 1462b4a7802SBaban Kenkre for (attr = attrs; *attr != NULL; attr++) { 1472b4a7802SBaban Kenkre if (strncasecmp(*attr, "dc=", 3) != 0) 1482b4a7802SBaban Kenkre continue; 1492b4a7802SBaban Kenkre 1502b4a7802SBaban Kenkre /* Found a DNS label */ 1512b4a7802SBaban Kenkre labels[nlabels++] = strdup((*attr) + 3); 1522b4a7802SBaban Kenkre 1532b4a7802SBaban Kenkre if (nlabels == maxlabels) { 1542b4a7802SBaban Kenkre char **tmp; 1552b4a7802SBaban Kenkre tmp = realloc(labels, 1562b4a7802SBaban Kenkre sizeof (char *) * (maxlabels + 1)); 1572b4a7802SBaban Kenkre 1582b4a7802SBaban Kenkre if (tmp == NULL) 1592b4a7802SBaban Kenkre goto done; 1602b4a7802SBaban Kenkre 1612b4a7802SBaban Kenkre labels = tmp; 1622b4a7802SBaban Kenkre labels[nlabels] = NULL; 1632b4a7802SBaban Kenkre } 1642b4a7802SBaban Kenkre 1652b4a7802SBaban Kenkre /* There should be just one DC= attr per-RDN */ 1662b4a7802SBaban Kenkre break; 1672b4a7802SBaban Kenkre } 1682b4a7802SBaban Kenkre } 1692b4a7802SBaban Kenkre 1702b4a7802SBaban Kenkre /* 1712b4a7802SBaban Kenkre * Got all the labels, now join with '.' 1722b4a7802SBaban Kenkre * 1732b4a7802SBaban Kenkre * We need room for nlabels - 1 periods ('.'), one nul 1742b4a7802SBaban Kenkre * terminator, and the strlen() of each label. 1752b4a7802SBaban Kenkre */ 1762b4a7802SBaban Kenkre dnslen = nlabels; 1772b4a7802SBaban Kenkre for (label = labels; *label != NULL; label++) 1782b4a7802SBaban Kenkre dnslen += strlen(*label); 1792b4a7802SBaban Kenkre 1802b4a7802SBaban Kenkre if ((dns = malloc(dnslen)) == NULL) 1812b4a7802SBaban Kenkre goto done; 1822b4a7802SBaban Kenkre 1832b4a7802SBaban Kenkre *dns = '\0'; 1842b4a7802SBaban Kenkre 1852b4a7802SBaban Kenkre for (label = labels; *label != NULL; label++) { 1862b4a7802SBaban Kenkre (void) strlcat(dns, *label, dnslen); 1872b4a7802SBaban Kenkre /* 1882b4a7802SBaban Kenkre * NOTE: the last '.' won't be appended -- there's no room 1892b4a7802SBaban Kenkre * for it! 1902b4a7802SBaban Kenkre */ 1912b4a7802SBaban Kenkre (void) strlcat(dns, ".", dnslen); 1922b4a7802SBaban Kenkre } 1932b4a7802SBaban Kenkre 1942b4a7802SBaban Kenkre done: 1952b4a7802SBaban Kenkre if (labels != NULL) { 1962b4a7802SBaban Kenkre for (label = labels; *label != NULL; label++) 1972b4a7802SBaban Kenkre free(*label); 1982b4a7802SBaban Kenkre free(labels); 1992b4a7802SBaban Kenkre } 2002b4a7802SBaban Kenkre if (attrs != NULL) 2012b4a7802SBaban Kenkre ldap_value_free(attrs); 2022b4a7802SBaban Kenkre if (rdns != NULL) 2032b4a7802SBaban Kenkre ldap_value_free(rdns); 2042b4a7802SBaban Kenkre 2052b4a7802SBaban Kenkre return (dns); 2062b4a7802SBaban Kenkre } 2072b4a7802SBaban Kenkre 2082b4a7802SBaban Kenkre /* 2092b4a7802SBaban Kenkre * Convert a binary SID in a BerValue to a adutils_sid_t 2102b4a7802SBaban Kenkre */ 2112b4a7802SBaban Kenkre static 2122b4a7802SBaban Kenkre int 2132b4a7802SBaban Kenkre getsid(BerValue *bval, adutils_sid_t *sidp) 2142b4a7802SBaban Kenkre { 2152b4a7802SBaban Kenkre int i, j; 2162b4a7802SBaban Kenkre uchar_t *v; 2172b4a7802SBaban Kenkre uint32_t a; 2182b4a7802SBaban Kenkre 2192b4a7802SBaban Kenkre /* 2202b4a7802SBaban Kenkre * The binary format of a SID is as follows: 2212b4a7802SBaban Kenkre * 2222b4a7802SBaban Kenkre * byte #0: version, always 0x01 2232b4a7802SBaban Kenkre * byte #1: RID count, always <= 0x0f 2242b4a7802SBaban Kenkre * bytes #2-#7: SID authority, big-endian 48-bit unsigned int 2252b4a7802SBaban Kenkre * 2262b4a7802SBaban Kenkre * followed by RID count RIDs, each a little-endian, unsigned 2272b4a7802SBaban Kenkre * 32-bit int. 2282b4a7802SBaban Kenkre */ 2292b4a7802SBaban Kenkre /* 2302b4a7802SBaban Kenkre * Sanity checks: must have at least one RID, version must be 2312b4a7802SBaban Kenkre * 0x01, and the length must be 8 + rid count * 4 2322b4a7802SBaban Kenkre */ 2332b4a7802SBaban Kenkre if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 && 2342b4a7802SBaban Kenkre bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) { 2352b4a7802SBaban Kenkre v = (uchar_t *)bval->bv_val; 2362b4a7802SBaban Kenkre sidp->version = v[0]; 2372b4a7802SBaban Kenkre sidp->sub_authority_count = v[1]; 2382b4a7802SBaban Kenkre sidp->authority = 2392b4a7802SBaban Kenkre /* big endian -- so start from the left */ 2402b4a7802SBaban Kenkre ((u_longlong_t)v[2] << 40) | 2412b4a7802SBaban Kenkre ((u_longlong_t)v[3] << 32) | 2422b4a7802SBaban Kenkre ((u_longlong_t)v[4] << 24) | 2432b4a7802SBaban Kenkre ((u_longlong_t)v[5] << 16) | 2442b4a7802SBaban Kenkre ((u_longlong_t)v[6] << 8) | 2452b4a7802SBaban Kenkre (u_longlong_t)v[7]; 2462b4a7802SBaban Kenkre for (i = 0; i < sidp->sub_authority_count; i++) { 2472b4a7802SBaban Kenkre j = 8 + (i * 4); 2482b4a7802SBaban Kenkre /* little endian -- so start from the right */ 2492b4a7802SBaban Kenkre a = (v[j + 3] << 24) | (v[j + 2] << 16) | 2502b4a7802SBaban Kenkre (v[j + 1] << 8) | (v[j]); 2512b4a7802SBaban Kenkre sidp->sub_authorities[i] = a; 2522b4a7802SBaban Kenkre } 2532b4a7802SBaban Kenkre return (0); 2542b4a7802SBaban Kenkre } 2552b4a7802SBaban Kenkre return (-1); 2562b4a7802SBaban Kenkre } 2572b4a7802SBaban Kenkre 2582b4a7802SBaban Kenkre /* 2592b4a7802SBaban Kenkre * Convert a adutils_sid_t to S-1-... 2602b4a7802SBaban Kenkre */ 2612b4a7802SBaban Kenkre static 2622b4a7802SBaban Kenkre char * 2632b4a7802SBaban Kenkre sid2txt(adutils_sid_t *sidp) 2642b4a7802SBaban Kenkre { 2652b4a7802SBaban Kenkre int rlen, i, len; 2662b4a7802SBaban Kenkre char *str, *cp; 2672b4a7802SBaban Kenkre 2682b4a7802SBaban Kenkre if (sidp->version != 1) 2692b4a7802SBaban Kenkre return (NULL); 2702b4a7802SBaban Kenkre 2712b4a7802SBaban Kenkre len = sizeof ("S-1-") - 1; 2722b4a7802SBaban Kenkre 2732b4a7802SBaban Kenkre /* 2742b4a7802SBaban Kenkre * We could optimize like so, but, why? 2752b4a7802SBaban Kenkre * if (sidp->authority < 10) 2762b4a7802SBaban Kenkre * len += 2; 2772b4a7802SBaban Kenkre * else if (sidp->authority < 100) 2782b4a7802SBaban Kenkre * len += 3; 2792b4a7802SBaban Kenkre * else 2802b4a7802SBaban Kenkre * len += snprintf(NULL, 0"%llu", sidp->authority); 2812b4a7802SBaban Kenkre */ 2822b4a7802SBaban Kenkre len += snprintf(NULL, 0, "%llu", sidp->authority); 2832b4a7802SBaban Kenkre 2842b4a7802SBaban Kenkre /* Max length of a uint32_t printed out in ASCII is 10 bytes */ 2852b4a7802SBaban Kenkre len += 1 + (sidp->sub_authority_count + 1) * 10; 2862b4a7802SBaban Kenkre 2872b4a7802SBaban Kenkre if ((cp = str = malloc(len)) == NULL) 2882b4a7802SBaban Kenkre return (NULL); 2892b4a7802SBaban Kenkre 2902b4a7802SBaban Kenkre rlen = snprintf(str, len, "S-1-%llu", sidp->authority); 2912b4a7802SBaban Kenkre 2922b4a7802SBaban Kenkre cp += rlen; 2932b4a7802SBaban Kenkre len -= rlen; 2942b4a7802SBaban Kenkre 2952b4a7802SBaban Kenkre for (i = 0; i < sidp->sub_authority_count; i++) { 2962b4a7802SBaban Kenkre assert(len > 0); 2972b4a7802SBaban Kenkre rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]); 2982b4a7802SBaban Kenkre cp += rlen; 2992b4a7802SBaban Kenkre len -= rlen; 3002b4a7802SBaban Kenkre assert(len >= 0); 3012b4a7802SBaban Kenkre } 3022b4a7802SBaban Kenkre 3032b4a7802SBaban Kenkre return (str); 3042b4a7802SBaban Kenkre } 3052b4a7802SBaban Kenkre 3062b4a7802SBaban Kenkre /* 3072b4a7802SBaban Kenkre * Convert a adutils_sid_t to on-the-wire encoding 3082b4a7802SBaban Kenkre */ 3092b4a7802SBaban Kenkre static 3102b4a7802SBaban Kenkre int 3112b4a7802SBaban Kenkre sid2binsid(adutils_sid_t *sid, uchar_t *binsid, int binsidlen) 3122b4a7802SBaban Kenkre { 3132b4a7802SBaban Kenkre uchar_t *p; 3142b4a7802SBaban Kenkre int i; 3152b4a7802SBaban Kenkre uint64_t a; 3162b4a7802SBaban Kenkre uint32_t r; 3172b4a7802SBaban Kenkre 3182b4a7802SBaban Kenkre if (sid->version != 1 || 3192b4a7802SBaban Kenkre binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4)) 3202b4a7802SBaban Kenkre return (-1); 3212b4a7802SBaban Kenkre 3222b4a7802SBaban Kenkre p = binsid; 3232b4a7802SBaban Kenkre *p++ = 0x01; /* version */ 3242b4a7802SBaban Kenkre /* sub authority count */ 3252b4a7802SBaban Kenkre *p++ = sid->sub_authority_count; 3262b4a7802SBaban Kenkre /* Authority */ 3272b4a7802SBaban Kenkre a = sid->authority; 3282b4a7802SBaban Kenkre /* big-endian -- start from left */ 3292b4a7802SBaban Kenkre *p++ = (a >> 40) & 0xFF; 3302b4a7802SBaban Kenkre *p++ = (a >> 32) & 0xFF; 3312b4a7802SBaban Kenkre *p++ = (a >> 24) & 0xFF; 3322b4a7802SBaban Kenkre *p++ = (a >> 16) & 0xFF; 3332b4a7802SBaban Kenkre *p++ = (a >> 8) & 0xFF; 3342b4a7802SBaban Kenkre *p++ = a & 0xFF; 3352b4a7802SBaban Kenkre 3362b4a7802SBaban Kenkre /* sub-authorities */ 3372b4a7802SBaban Kenkre for (i = 0; i < sid->sub_authority_count; i++) { 3382b4a7802SBaban Kenkre r = sid->sub_authorities[i]; 3392b4a7802SBaban Kenkre /* little-endian -- start from right */ 3402b4a7802SBaban Kenkre *p++ = (r & 0x000000FF); 3412b4a7802SBaban Kenkre *p++ = (r & 0x0000FF00) >> 8; 3422b4a7802SBaban Kenkre *p++ = (r & 0x00FF0000) >> 16; 3432b4a7802SBaban Kenkre *p++ = (r & 0xFF000000) >> 24; 3442b4a7802SBaban Kenkre } 3452b4a7802SBaban Kenkre 3462b4a7802SBaban Kenkre return (0); 3472b4a7802SBaban Kenkre } 3482b4a7802SBaban Kenkre 3492b4a7802SBaban Kenkre /* 3502b4a7802SBaban Kenkre * Convert a stringified SID (S-1-...) into a hex-encoded version of the 3512b4a7802SBaban Kenkre * on-the-wire encoding, but with each pair of hex digits pre-pended 3522b4a7802SBaban Kenkre * with a '\', so we can pass this to libldap. 3532b4a7802SBaban Kenkre */ 3542b4a7802SBaban Kenkre int 3552b4a7802SBaban Kenkre adutils_txtsid2hexbinsid(const char *txt, const uint32_t *rid, 3562b4a7802SBaban Kenkre char *hexbinsid, int hexbinsidlen) 3572b4a7802SBaban Kenkre { 3582b4a7802SBaban Kenkre adutils_sid_t sid = { 0 }; 3592b4a7802SBaban Kenkre int i, j; 3602b4a7802SBaban Kenkre const char *cp; 3612b4a7802SBaban Kenkre char *ecp; 3622b4a7802SBaban Kenkre u_longlong_t a; 3632b4a7802SBaban Kenkre unsigned long r; 3642b4a7802SBaban Kenkre uchar_t *binsid, b, hb; 3652b4a7802SBaban Kenkre 3662b4a7802SBaban Kenkre /* Only version 1 SIDs please */ 3672b4a7802SBaban Kenkre if (strncmp(txt, "S-1-", strlen("S-1-")) != 0) 3682b4a7802SBaban Kenkre return (-1); 3692b4a7802SBaban Kenkre 3702b4a7802SBaban Kenkre if (strlen(txt) < (strlen("S-1-") + 1)) 3712b4a7802SBaban Kenkre return (-1); 3722b4a7802SBaban Kenkre 3732b4a7802SBaban Kenkre /* count '-'s */ 3742b4a7802SBaban Kenkre for (j = 0, cp = strchr(txt, '-'); 3752b4a7802SBaban Kenkre cp != NULL && *cp != '\0'; 3762b4a7802SBaban Kenkre j++, cp = strchr(cp + 1, '-')) { 3772b4a7802SBaban Kenkre /* can't end on a '-' */ 3782b4a7802SBaban Kenkre if (*(cp + 1) == '\0') 3792b4a7802SBaban Kenkre return (-1); 3802b4a7802SBaban Kenkre } 3812b4a7802SBaban Kenkre 3822b4a7802SBaban Kenkre /* Adjust count for version and authority */ 3832b4a7802SBaban Kenkre j -= 2; 3842b4a7802SBaban Kenkre 3852b4a7802SBaban Kenkre /* we know the version number and RID count */ 3862b4a7802SBaban Kenkre sid.version = 1; 3872b4a7802SBaban Kenkre sid.sub_authority_count = (rid != NULL) ? j + 1 : j; 3882b4a7802SBaban Kenkre 3892b4a7802SBaban Kenkre /* must have at least one RID, but not too many */ 3902b4a7802SBaban Kenkre if (sid.sub_authority_count < 1 || 3912b4a7802SBaban Kenkre sid.sub_authority_count > ADUTILS_SID_MAX_SUB_AUTHORITIES) 3922b4a7802SBaban Kenkre return (-1); 3932b4a7802SBaban Kenkre 3942b4a7802SBaban Kenkre /* check that we only have digits and '-' */ 3952b4a7802SBaban Kenkre if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1)) 3962b4a7802SBaban Kenkre return (-1); 3972b4a7802SBaban Kenkre 3982b4a7802SBaban Kenkre cp = txt + strlen("S-1-"); 3992b4a7802SBaban Kenkre 4002b4a7802SBaban Kenkre /* 64-bit safe parsing of unsigned 48-bit authority value */ 4012b4a7802SBaban Kenkre errno = 0; 4022b4a7802SBaban Kenkre a = strtoull(cp, &ecp, 10); 4032b4a7802SBaban Kenkre 4042b4a7802SBaban Kenkre /* errors parsing the authority or too many bits */ 4052b4a7802SBaban Kenkre if (cp == ecp || (a == 0 && errno == EINVAL) || 4062b4a7802SBaban Kenkre (a == ULLONG_MAX && errno == ERANGE) || 4072b4a7802SBaban Kenkre (a & 0x0000ffffffffffffULL) != a) 4082b4a7802SBaban Kenkre return (-1); 4092b4a7802SBaban Kenkre 4102b4a7802SBaban Kenkre cp = ecp; 4112b4a7802SBaban Kenkre 4122b4a7802SBaban Kenkre sid.authority = (uint64_t)a; 4132b4a7802SBaban Kenkre 4142b4a7802SBaban Kenkre for (i = 0; i < j; i++) { 4152b4a7802SBaban Kenkre if (*cp++ != '-') 4162b4a7802SBaban Kenkre return (-1); 4172b4a7802SBaban Kenkre /* 64-bit safe parsing of unsigned 32-bit RID */ 4182b4a7802SBaban Kenkre errno = 0; 4192b4a7802SBaban Kenkre r = strtoul(cp, &ecp, 10); 4202b4a7802SBaban Kenkre /* errors parsing the RID or too many bits */ 4212b4a7802SBaban Kenkre if (cp == ecp || (r == 0 && errno == EINVAL) || 4222b4a7802SBaban Kenkre (r == ULONG_MAX && errno == ERANGE) || 4232b4a7802SBaban Kenkre (r & 0xffffffffUL) != r) 4242b4a7802SBaban Kenkre return (-1); 4252b4a7802SBaban Kenkre sid.sub_authorities[i] = (uint32_t)r; 4262b4a7802SBaban Kenkre cp = ecp; 4272b4a7802SBaban Kenkre } 4282b4a7802SBaban Kenkre 4292b4a7802SBaban Kenkre /* check that all of the string SID has been consumed */ 4302b4a7802SBaban Kenkre if (*cp != '\0') 4312b4a7802SBaban Kenkre return (-1); 4322b4a7802SBaban Kenkre 4332b4a7802SBaban Kenkre if (rid != NULL) 4342b4a7802SBaban Kenkre sid.sub_authorities[j] = *rid; 4352b4a7802SBaban Kenkre 4362b4a7802SBaban Kenkre j = 1 + 1 + 6 + sid.sub_authority_count * 4; 4372b4a7802SBaban Kenkre 4382b4a7802SBaban Kenkre if (hexbinsidlen < (j * 3)) 4392b4a7802SBaban Kenkre return (-2); 4402b4a7802SBaban Kenkre 4412b4a7802SBaban Kenkre /* binary encode the SID */ 4422b4a7802SBaban Kenkre binsid = (uchar_t *)alloca(j); 4432b4a7802SBaban Kenkre (void) sid2binsid(&sid, binsid, j); 4442b4a7802SBaban Kenkre 4452b4a7802SBaban Kenkre /* hex encode, with a backslash before each byte */ 4462b4a7802SBaban Kenkre for (ecp = hexbinsid, i = 0; i < j; i++) { 4472b4a7802SBaban Kenkre b = binsid[i]; 4482b4a7802SBaban Kenkre *ecp++ = '\\'; 4492b4a7802SBaban Kenkre hb = (b >> 4) & 0xF; 4502b4a7802SBaban Kenkre *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 4512b4a7802SBaban Kenkre hb = b & 0xF; 4522b4a7802SBaban Kenkre *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 4532b4a7802SBaban Kenkre } 4542b4a7802SBaban Kenkre *ecp = '\0'; 4552b4a7802SBaban Kenkre 4562b4a7802SBaban Kenkre return (0); 4572b4a7802SBaban Kenkre } 4582b4a7802SBaban Kenkre 4592b4a7802SBaban Kenkre static 4602b4a7802SBaban Kenkre char * 4612b4a7802SBaban Kenkre convert_bval2sid(BerValue *bval, uint32_t *rid) 4622b4a7802SBaban Kenkre { 4632b4a7802SBaban Kenkre adutils_sid_t sid; 4642b4a7802SBaban Kenkre 4652b4a7802SBaban Kenkre if (getsid(bval, &sid) < 0) 4662b4a7802SBaban Kenkre return (NULL); 4672b4a7802SBaban Kenkre 4682b4a7802SBaban Kenkre /* 4692b4a7802SBaban Kenkre * If desired and if the SID is what should be a domain/computer 4702b4a7802SBaban Kenkre * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then 4712b4a7802SBaban Kenkre * save the last RID and truncate the SID 4722b4a7802SBaban Kenkre */ 4732b4a7802SBaban Kenkre if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5) 4742b4a7802SBaban Kenkre *rid = sid.sub_authorities[--sid.sub_authority_count]; 4752b4a7802SBaban Kenkre return (sid2txt(&sid)); 4762b4a7802SBaban Kenkre } 4772b4a7802SBaban Kenkre 4782b4a7802SBaban Kenkre 4792b4a7802SBaban Kenkre /* 4802b4a7802SBaban Kenkre * Return a NUL-terminated stringified SID from the value of an 4812b4a7802SBaban Kenkre * objectSid attribute and put the last RID in *rid. 4822b4a7802SBaban Kenkre */ 4832b4a7802SBaban Kenkre char * 4842b4a7802SBaban Kenkre adutils_bv_objsid2sidstr(BerValue *bval, uint32_t *rid) 4852b4a7802SBaban Kenkre { 4862b4a7802SBaban Kenkre char *sid; 4872b4a7802SBaban Kenkre 4882b4a7802SBaban Kenkre if (bval == NULL) 4892b4a7802SBaban Kenkre return (NULL); 4902b4a7802SBaban Kenkre /* objectSid is single valued */ 4912b4a7802SBaban Kenkre if ((sid = convert_bval2sid(bval, rid)) == NULL) 4922b4a7802SBaban Kenkre return (NULL); 4932b4a7802SBaban Kenkre return (sid); 4942b4a7802SBaban Kenkre } 4952b4a7802SBaban Kenkre 4962b4a7802SBaban Kenkre static 4972b4a7802SBaban Kenkre char * 4982b4a7802SBaban Kenkre adutils_sid_ber2str(BerValue *bval) 4992b4a7802SBaban Kenkre { 5002b4a7802SBaban Kenkre return (adutils_bv_objsid2sidstr(bval, NULL)); 5012b4a7802SBaban Kenkre } 5022b4a7802SBaban Kenkre 5032b4a7802SBaban Kenkre 5042b4a7802SBaban Kenkre /* Return a NUL-terminated string from the Ber value */ 5052b4a7802SBaban Kenkre char * 5062b4a7802SBaban Kenkre adutils_bv_name2str(BerValue *bval) 5072b4a7802SBaban Kenkre { 5082b4a7802SBaban Kenkre char *s; 5092b4a7802SBaban Kenkre 5102b4a7802SBaban Kenkre if (bval == NULL || bval->bv_val == NULL) 5112b4a7802SBaban Kenkre return (NULL); 5122b4a7802SBaban Kenkre if ((s = malloc(bval->bv_len + 1)) == NULL) 5132b4a7802SBaban Kenkre return (NULL); 5142b4a7802SBaban Kenkre (void) snprintf(s, bval->bv_len + 1, "%.*s", bval->bv_len, 5152b4a7802SBaban Kenkre bval->bv_val); 5162b4a7802SBaban Kenkre return (s); 5172b4a7802SBaban Kenkre } 5182b4a7802SBaban Kenkre 5192b4a7802SBaban Kenkre /*ARGSUSED*/ 5202b4a7802SBaban Kenkre static 5212b4a7802SBaban Kenkre int 5222b4a7802SBaban Kenkre saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) 5232b4a7802SBaban Kenkre { 5242b4a7802SBaban Kenkre sasl_interact_t *interact; 5252b4a7802SBaban Kenkre 5262b4a7802SBaban Kenkre if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE) 5272b4a7802SBaban Kenkre return (LDAP_PARAM_ERROR); 5282b4a7802SBaban Kenkre 5292b4a7802SBaban Kenkre /* There should be no extra arguemnts for SASL/GSSAPI authentication */ 5302b4a7802SBaban Kenkre for (interact = prompts; interact->id != SASL_CB_LIST_END; 5312b4a7802SBaban Kenkre interact++) { 5322b4a7802SBaban Kenkre interact->result = NULL; 5332b4a7802SBaban Kenkre interact->len = 0; 5342b4a7802SBaban Kenkre } 5352b4a7802SBaban Kenkre return (LDAP_SUCCESS); 5362b4a7802SBaban Kenkre } 5372b4a7802SBaban Kenkre 5382b4a7802SBaban Kenkre 5392b4a7802SBaban Kenkre #define ADCONN_TIME 300 5402b4a7802SBaban Kenkre 5412b4a7802SBaban Kenkre /* 5422b4a7802SBaban Kenkre * Idle connection reaping side of connection management 5432b4a7802SBaban Kenkre */ 5442b4a7802SBaban Kenkre void 5452b4a7802SBaban Kenkre adutils_reap_idle_connections() 5462b4a7802SBaban Kenkre { 5472b4a7802SBaban Kenkre adutils_host_t *adh; 5482b4a7802SBaban Kenkre time_t now; 5492b4a7802SBaban Kenkre 5502b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 5512b4a7802SBaban Kenkre now = time(NULL); 5522b4a7802SBaban Kenkre for (adh = host_head; adh != NULL; adh = adh->next) { 5532b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 5542b4a7802SBaban Kenkre if (adh->ref == 0 && adh->idletime != 0 && 5552b4a7802SBaban Kenkre adh->idletime + ADCONN_TIME < now) { 5562b4a7802SBaban Kenkre if (adh->ld) { 5572b4a7802SBaban Kenkre (void) ldap_unbind(adh->ld); 5582b4a7802SBaban Kenkre adh->ld = NULL; 5592b4a7802SBaban Kenkre adh->idletime = 0; 5602b4a7802SBaban Kenkre adh->ref = 0; 5612b4a7802SBaban Kenkre } 5622b4a7802SBaban Kenkre } 5632b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 5642b4a7802SBaban Kenkre } 5652b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 5662b4a7802SBaban Kenkre } 5672b4a7802SBaban Kenkre 5682b4a7802SBaban Kenkre 5692b4a7802SBaban Kenkre adutils_rc 5702b4a7802SBaban Kenkre adutils_ad_alloc(adutils_ad_t **new_ad, const char *default_domain, 5712b4a7802SBaban Kenkre adutils_ad_partition_t part) 5722b4a7802SBaban Kenkre { 5732b4a7802SBaban Kenkre adutils_ad_t *ad; 5742b4a7802SBaban Kenkre 5752b4a7802SBaban Kenkre *new_ad = NULL; 5762b4a7802SBaban Kenkre 5772b4a7802SBaban Kenkre if ((default_domain == NULL || *default_domain == '\0') && 5782b4a7802SBaban Kenkre part != ADUTILS_AD_GLOBAL_CATALOG) 5792b4a7802SBaban Kenkre return (ADUTILS_ERR_DOMAIN); 5802b4a7802SBaban Kenkre if ((ad = calloc(1, sizeof (*ad))) == NULL) 5812b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 5822b4a7802SBaban Kenkre ad->ref = 1; 5832b4a7802SBaban Kenkre ad->partition = part; 5842b4a7802SBaban Kenkre if (default_domain == NULL) 5852b4a7802SBaban Kenkre default_domain = ""; 5862b4a7802SBaban Kenkre if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL) 5872b4a7802SBaban Kenkre goto err; 5882b4a7802SBaban Kenkre if (pthread_mutex_init(&ad->lock, NULL) != 0) 5892b4a7802SBaban Kenkre goto err; 5902b4a7802SBaban Kenkre *new_ad = ad; 5912b4a7802SBaban Kenkre return (ADUTILS_SUCCESS); 5922b4a7802SBaban Kenkre 5932b4a7802SBaban Kenkre err: 5942b4a7802SBaban Kenkre if (ad->dflt_w2k_dom != NULL) 5952b4a7802SBaban Kenkre free(ad->dflt_w2k_dom); 5962b4a7802SBaban Kenkre free(ad); 5972b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 5982b4a7802SBaban Kenkre } 5992b4a7802SBaban Kenkre 6002b4a7802SBaban Kenkre void 6012b4a7802SBaban Kenkre adutils_ad_free(adutils_ad_t **ad) 6022b4a7802SBaban Kenkre { 6032b4a7802SBaban Kenkre adutils_host_t *p; 6042b4a7802SBaban Kenkre adutils_host_t *prev; 6052b4a7802SBaban Kenkre 6062b4a7802SBaban Kenkre if (ad == NULL || *ad == NULL) 6072b4a7802SBaban Kenkre return; 6082b4a7802SBaban Kenkre 6092b4a7802SBaban Kenkre (void) pthread_mutex_lock(&(*ad)->lock); 6102b4a7802SBaban Kenkre 6112b4a7802SBaban Kenkre if (atomic_dec_32_nv(&(*ad)->ref) > 0) { 6122b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&(*ad)->lock); 6132b4a7802SBaban Kenkre *ad = NULL; 6142b4a7802SBaban Kenkre return; 6152b4a7802SBaban Kenkre } 6162b4a7802SBaban Kenkre 6172b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 6182b4a7802SBaban Kenkre prev = NULL; 6192b4a7802SBaban Kenkre p = host_head; 6202b4a7802SBaban Kenkre while (p != NULL) { 6212b4a7802SBaban Kenkre if (p->owner != (*ad)) { 6222b4a7802SBaban Kenkre prev = p; 6232b4a7802SBaban Kenkre p = p->next; 6242b4a7802SBaban Kenkre continue; 6252b4a7802SBaban Kenkre } else { 6262b4a7802SBaban Kenkre delete_ds((*ad), p->host, p->port); 6272b4a7802SBaban Kenkre if (prev == NULL) 6282b4a7802SBaban Kenkre p = host_head; 6292b4a7802SBaban Kenkre else 6302b4a7802SBaban Kenkre p = prev->next; 6312b4a7802SBaban Kenkre } 6322b4a7802SBaban Kenkre } 6332b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 6342b4a7802SBaban Kenkre 6352b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&(*ad)->lock); 6362b4a7802SBaban Kenkre (void) pthread_mutex_destroy(&(*ad)->lock); 6372b4a7802SBaban Kenkre 638*4d61c878SJulian Pullen if ((*ad)->known_domains) 639*4d61c878SJulian Pullen free((*ad)->known_domains); 6402b4a7802SBaban Kenkre free((*ad)->dflt_w2k_dom); 6412b4a7802SBaban Kenkre free(*ad); 6422b4a7802SBaban Kenkre 6432b4a7802SBaban Kenkre *ad = NULL; 6442b4a7802SBaban Kenkre } 6452b4a7802SBaban Kenkre 6462b4a7802SBaban Kenkre static 6472b4a7802SBaban Kenkre int 6482b4a7802SBaban Kenkre open_conn(adutils_host_t *adh, int timeoutsecs) 6492b4a7802SBaban Kenkre { 6502b4a7802SBaban Kenkre int zero = 0; 6512b4a7802SBaban Kenkre int ldversion, rc; 6522b4a7802SBaban Kenkre int timeoutms = timeoutsecs * 1000; 6532b4a7802SBaban Kenkre 6542b4a7802SBaban Kenkre if (adh == NULL) 6552b4a7802SBaban Kenkre return (0); 6562b4a7802SBaban Kenkre 6572b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 6582b4a7802SBaban Kenkre 6592b4a7802SBaban Kenkre if (!adh->dead && adh->ld != NULL) 6602b4a7802SBaban Kenkre /* done! */ 6612b4a7802SBaban Kenkre goto out; 6622b4a7802SBaban Kenkre 6632b4a7802SBaban Kenkre if (adh->ld != NULL) { 6642b4a7802SBaban Kenkre (void) ldap_unbind(adh->ld); 6652b4a7802SBaban Kenkre adh->ld = NULL; 6662b4a7802SBaban Kenkre } 6672b4a7802SBaban Kenkre adh->num_requests = 0; 6682b4a7802SBaban Kenkre 6692b4a7802SBaban Kenkre atomic_inc_64(&adh->generation); 6702b4a7802SBaban Kenkre 6712b4a7802SBaban Kenkre /* Open and bind an LDAP connection */ 6722b4a7802SBaban Kenkre adh->ld = ldap_init(adh->host, adh->port); 6732b4a7802SBaban Kenkre if (adh->ld == NULL) { 6742b4a7802SBaban Kenkre idmapdlog(LOG_INFO, "ldap_init() to server " 6752b4a7802SBaban Kenkre "%s port %d failed. (%s)", adh->host, 6762b4a7802SBaban Kenkre adh->port, strerror(errno)); 6772b4a7802SBaban Kenkre goto out; 6782b4a7802SBaban Kenkre } 6792b4a7802SBaban Kenkre ldversion = LDAP_VERSION3; 6802b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion); 6812b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 6822b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero); 6832b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero); 6842b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms); 6852b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 6862b4a7802SBaban Kenkre rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */, 6872b4a7802SBaban Kenkre adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback, 6882b4a7802SBaban Kenkre NULL); 6892b4a7802SBaban Kenkre 6902b4a7802SBaban Kenkre if (rc != LDAP_SUCCESS) { 6912b4a7802SBaban Kenkre (void) ldap_unbind(adh->ld); 6922b4a7802SBaban Kenkre adh->ld = NULL; 6932b4a7802SBaban Kenkre idmapdlog(LOG_INFO, "ldap_sasl_interactive_bind_s() to server " 6942b4a7802SBaban Kenkre "%s port %d failed. (%s)", adh->host, adh->port, 6952b4a7802SBaban Kenkre ldap_err2string(rc)); 6962b4a7802SBaban Kenkre } 6972b4a7802SBaban Kenkre 6982b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, "Using global catalog server %s:%d", 6992b4a7802SBaban Kenkre adh->host, adh->port); 7002b4a7802SBaban Kenkre 7012b4a7802SBaban Kenkre out: 7022b4a7802SBaban Kenkre if (adh->ld != NULL) { 7032b4a7802SBaban Kenkre atomic_inc_32(&adh->ref); 7042b4a7802SBaban Kenkre adh->idletime = time(NULL); 7052b4a7802SBaban Kenkre adh->dead = 0; 7062b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 7072b4a7802SBaban Kenkre return (1); 7082b4a7802SBaban Kenkre } 7092b4a7802SBaban Kenkre 7102b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 7112b4a7802SBaban Kenkre return (0); 7122b4a7802SBaban Kenkre } 7132b4a7802SBaban Kenkre 7142b4a7802SBaban Kenkre 7152b4a7802SBaban Kenkre /* 7162b4a7802SBaban Kenkre * Connection management: find an open connection or open one 7172b4a7802SBaban Kenkre */ 7182b4a7802SBaban Kenkre static 7192b4a7802SBaban Kenkre adutils_host_t * 7202b4a7802SBaban Kenkre get_conn(adutils_ad_t *ad) 7212b4a7802SBaban Kenkre { 7222b4a7802SBaban Kenkre adutils_host_t *adh = NULL; 7232b4a7802SBaban Kenkre int tries; 7242b4a7802SBaban Kenkre int dscount = 0; 7252b4a7802SBaban Kenkre int timeoutsecs = ADUTILS_LDAP_OPEN_TIMEOUT; 7262b4a7802SBaban Kenkre 7272b4a7802SBaban Kenkre retry: 7282b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 7292b4a7802SBaban Kenkre 7302b4a7802SBaban Kenkre if (host_head == NULL) { 7312b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 7322b4a7802SBaban Kenkre goto out; 7332b4a7802SBaban Kenkre } 7342b4a7802SBaban Kenkre 7352b4a7802SBaban Kenkre if (dscount == 0) { 7362b4a7802SBaban Kenkre /* 7372b4a7802SBaban Kenkre * First try: count the number of DSes. 7382b4a7802SBaban Kenkre * 7392b4a7802SBaban Kenkre * Integer overflow is not an issue -- we can't have so many 7402b4a7802SBaban Kenkre * DSes because they won't fit even DNS over TCP, and SMF 7412b4a7802SBaban Kenkre * shouldn't let you set so many. 7422b4a7802SBaban Kenkre */ 7432b4a7802SBaban Kenkre for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) { 7442b4a7802SBaban Kenkre if (adh->owner == ad) 7452b4a7802SBaban Kenkre dscount++; 7462b4a7802SBaban Kenkre } 7472b4a7802SBaban Kenkre 7482b4a7802SBaban Kenkre if (dscount == 0) { 7492b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 7502b4a7802SBaban Kenkre goto out; 7512b4a7802SBaban Kenkre } 7522b4a7802SBaban Kenkre 7532b4a7802SBaban Kenkre tries = dscount * 3; /* three tries per-ds */ 7542b4a7802SBaban Kenkre 7552b4a7802SBaban Kenkre /* 7562b4a7802SBaban Kenkre * Begin round-robin at the next DS in the list after the last 7572b4a7802SBaban Kenkre * one that we had a connection to, else start with the first 7582b4a7802SBaban Kenkre * DS in the list. 7592b4a7802SBaban Kenkre */ 7602b4a7802SBaban Kenkre adh = ad->last_adh; 7612b4a7802SBaban Kenkre } 7622b4a7802SBaban Kenkre 7632b4a7802SBaban Kenkre /* 7642b4a7802SBaban Kenkre * Round-robin -- pick the next one on the list; if the list 7652b4a7802SBaban Kenkre * changes on us, no big deal, we'll just potentially go 7662b4a7802SBaban Kenkre * around the wrong number of times. 7672b4a7802SBaban Kenkre */ 7682b4a7802SBaban Kenkre for (;;) { 769*4d61c878SJulian Pullen if (adh != NULL && adh->owner == ad && adh->ld != NULL && 770*4d61c878SJulian Pullen !adh->dead) 7712b4a7802SBaban Kenkre break; 7722b4a7802SBaban Kenkre if (adh == NULL || (adh = adh->next) == NULL) 7732b4a7802SBaban Kenkre adh = host_head; 7742b4a7802SBaban Kenkre if (adh->owner == ad) 7752b4a7802SBaban Kenkre break; 7762b4a7802SBaban Kenkre } 7772b4a7802SBaban Kenkre 7782b4a7802SBaban Kenkre ad->last_adh = adh; 7792b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 7802b4a7802SBaban Kenkre 7812b4a7802SBaban Kenkre /* Found suitable DS, open it if not already opened */ 7822b4a7802SBaban Kenkre if (open_conn(adh, timeoutsecs)) 7832b4a7802SBaban Kenkre return (adh); 7842b4a7802SBaban Kenkre 7852b4a7802SBaban Kenkre tries--; 7862b4a7802SBaban Kenkre if ((tries % dscount) == 0) 7872b4a7802SBaban Kenkre timeoutsecs *= 2; 7882b4a7802SBaban Kenkre if (tries > 0) 7892b4a7802SBaban Kenkre goto retry; 7902b4a7802SBaban Kenkre 7912b4a7802SBaban Kenkre out: 7922b4a7802SBaban Kenkre idmapdlog(LOG_NOTICE, "Couldn't open an LDAP connection to any global " 7932b4a7802SBaban Kenkre "catalog server!"); 7942b4a7802SBaban Kenkre return (NULL); 7952b4a7802SBaban Kenkre } 7962b4a7802SBaban Kenkre 7972b4a7802SBaban Kenkre static 7982b4a7802SBaban Kenkre void 7992b4a7802SBaban Kenkre release_conn(adutils_host_t *adh) 8002b4a7802SBaban Kenkre { 8012b4a7802SBaban Kenkre int delete = 0; 8022b4a7802SBaban Kenkre 8032b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 8042b4a7802SBaban Kenkre if (atomic_dec_32_nv(&adh->ref) == 0) { 8052b4a7802SBaban Kenkre if (adh->owner == NULL) 8062b4a7802SBaban Kenkre delete = 1; 8072b4a7802SBaban Kenkre adh->idletime = time(NULL); 8082b4a7802SBaban Kenkre } 8092b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 8102b4a7802SBaban Kenkre 8112b4a7802SBaban Kenkre /* Free this host if its owner no longer exists. */ 8122b4a7802SBaban Kenkre if (delete) { 8132b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 8142b4a7802SBaban Kenkre delete_ds(NULL, adh->host, adh->port); 8152b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 8162b4a7802SBaban Kenkre } 8172b4a7802SBaban Kenkre } 8182b4a7802SBaban Kenkre 8192b4a7802SBaban Kenkre /* 8202b4a7802SBaban Kenkre * Create a adutils_host_t, populate it and add it to the list of hosts. 8212b4a7802SBaban Kenkre */ 8222b4a7802SBaban Kenkre adutils_rc 8232b4a7802SBaban Kenkre adutils_add_ds(adutils_ad_t *ad, const char *host, int port) 8242b4a7802SBaban Kenkre { 8252b4a7802SBaban Kenkre adutils_host_t *p; 8262b4a7802SBaban Kenkre adutils_host_t *new = NULL; 8272b4a7802SBaban Kenkre int ret; 8282b4a7802SBaban Kenkre adutils_rc rc; 8292b4a7802SBaban Kenkre 8302b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 8312b4a7802SBaban Kenkre for (p = host_head; p != NULL; p = p->next) { 8322b4a7802SBaban Kenkre if (p->owner != ad) 8332b4a7802SBaban Kenkre continue; 8342b4a7802SBaban Kenkre 8352b4a7802SBaban Kenkre if (strcmp(host, p->host) == 0 && p->port == port) { 8362b4a7802SBaban Kenkre /* already added */ 8372b4a7802SBaban Kenkre rc = ADUTILS_SUCCESS; 8382b4a7802SBaban Kenkre goto err; 8392b4a7802SBaban Kenkre } 8402b4a7802SBaban Kenkre } 8412b4a7802SBaban Kenkre 8422b4a7802SBaban Kenkre rc = ADUTILS_ERR_MEMORY; 8432b4a7802SBaban Kenkre 8442b4a7802SBaban Kenkre /* add new entry */ 8452b4a7802SBaban Kenkre new = (adutils_host_t *)calloc(1, sizeof (*new)); 8462b4a7802SBaban Kenkre if (new == NULL) 8472b4a7802SBaban Kenkre goto err; 8482b4a7802SBaban Kenkre new->owner = ad; 8492b4a7802SBaban Kenkre new->port = port; 8502b4a7802SBaban Kenkre new->dead = 0; 8512b4a7802SBaban Kenkre new->max_requests = 80; 8522b4a7802SBaban Kenkre new->num_requests = 0; 8532b4a7802SBaban Kenkre if ((new->host = strdup(host)) == NULL) 8542b4a7802SBaban Kenkre goto err; 8552b4a7802SBaban Kenkre new->saslflags = LDAP_SASL_INTERACTIVE; 8562b4a7802SBaban Kenkre new->saslmech = "GSSAPI"; 8572b4a7802SBaban Kenkre 8582b4a7802SBaban Kenkre if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) { 8592b4a7802SBaban Kenkre free(new->host); 8602b4a7802SBaban Kenkre new->host = NULL; 8612b4a7802SBaban Kenkre errno = ret; 8622b4a7802SBaban Kenkre rc = ADUTILS_ERR_INTERNAL; 8632b4a7802SBaban Kenkre goto err; 8642b4a7802SBaban Kenkre } 8652b4a7802SBaban Kenkre 8662b4a7802SBaban Kenkre /* link in */ 8672b4a7802SBaban Kenkre rc = ADUTILS_SUCCESS; 8682b4a7802SBaban Kenkre new->next = host_head; 8692b4a7802SBaban Kenkre host_head = new; 8702b4a7802SBaban Kenkre 8712b4a7802SBaban Kenkre err: 8722b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 8732b4a7802SBaban Kenkre 8742b4a7802SBaban Kenkre if (rc != 0 && new != NULL) { 8752b4a7802SBaban Kenkre if (new->host != NULL) { 8762b4a7802SBaban Kenkre (void) pthread_mutex_destroy(&new->lock); 8772b4a7802SBaban Kenkre free(new->host); 8782b4a7802SBaban Kenkre } 8792b4a7802SBaban Kenkre free(new); 8802b4a7802SBaban Kenkre } 8812b4a7802SBaban Kenkre 8822b4a7802SBaban Kenkre return (rc); 8832b4a7802SBaban Kenkre } 8842b4a7802SBaban Kenkre 8852b4a7802SBaban Kenkre /* 8862b4a7802SBaban Kenkre * Free a DS configuration. 8872b4a7802SBaban Kenkre * Caller must lock the adhostlock mutex 8882b4a7802SBaban Kenkre */ 8892b4a7802SBaban Kenkre static 8902b4a7802SBaban Kenkre void 8912b4a7802SBaban Kenkre delete_ds(adutils_ad_t *ad, const char *host, int port) 8922b4a7802SBaban Kenkre { 8932b4a7802SBaban Kenkre adutils_host_t **p, *q; 8942b4a7802SBaban Kenkre 8952b4a7802SBaban Kenkre for (p = &host_head; *p != NULL; p = &((*p)->next)) { 8962b4a7802SBaban Kenkre if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 || 8972b4a7802SBaban Kenkre (*p)->port != port) 8982b4a7802SBaban Kenkre continue; 8992b4a7802SBaban Kenkre /* found */ 9002b4a7802SBaban Kenkre 9012b4a7802SBaban Kenkre (void) pthread_mutex_lock(&((*p)->lock)); 9022b4a7802SBaban Kenkre if ((*p)->ref > 0) { 9032b4a7802SBaban Kenkre /* 9042b4a7802SBaban Kenkre * Still in use. Set its owner to NULL so 9052b4a7802SBaban Kenkre * that it can be freed when its ref count 9062b4a7802SBaban Kenkre * becomes 0. 9072b4a7802SBaban Kenkre */ 9082b4a7802SBaban Kenkre (*p)->owner = NULL; 9092b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&((*p)->lock)); 9102b4a7802SBaban Kenkre break; 9112b4a7802SBaban Kenkre } 9122b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&((*p)->lock)); 9132b4a7802SBaban Kenkre 9142b4a7802SBaban Kenkre q = *p; 9152b4a7802SBaban Kenkre *p = (*p)->next; 9162b4a7802SBaban Kenkre 9172b4a7802SBaban Kenkre (void) pthread_mutex_destroy(&q->lock); 9182b4a7802SBaban Kenkre 9192b4a7802SBaban Kenkre if (q->ld) 9202b4a7802SBaban Kenkre (void) ldap_unbind(q->ld); 9212b4a7802SBaban Kenkre if (q->host) 9222b4a7802SBaban Kenkre free(q->host); 9232b4a7802SBaban Kenkre free(q); 9242b4a7802SBaban Kenkre break; 9252b4a7802SBaban Kenkre } 9262b4a7802SBaban Kenkre 9272b4a7802SBaban Kenkre } 928*4d61c878SJulian Pullen /* 929*4d61c878SJulian Pullen * Add known domain name and domain SID to AD configuration. 930*4d61c878SJulian Pullen */ 931*4d61c878SJulian Pullen 932*4d61c878SJulian Pullen adutils_rc 933*4d61c878SJulian Pullen adutils_add_domain(adutils_ad_t *ad, const char *domain, const char *sid) 934*4d61c878SJulian Pullen { 935*4d61c878SJulian Pullen struct known_domain *new; 936*4d61c878SJulian Pullen int num = ad->num_known_domains; 937*4d61c878SJulian Pullen 938*4d61c878SJulian Pullen ad->num_known_domains++; 939*4d61c878SJulian Pullen new = realloc(ad->known_domains, 940*4d61c878SJulian Pullen sizeof (struct known_domain) * ad->num_known_domains); 941*4d61c878SJulian Pullen if (new != NULL) { 942*4d61c878SJulian Pullen ad->known_domains = new; 943*4d61c878SJulian Pullen (void) strlcpy(ad->known_domains[num].name, domain, 944*4d61c878SJulian Pullen sizeof (ad->known_domains[num].name)); 945*4d61c878SJulian Pullen (void) strlcpy(ad->known_domains[num].sid, sid, 946*4d61c878SJulian Pullen sizeof (ad->known_domains[num].sid)); 947*4d61c878SJulian Pullen return (ADUTILS_SUCCESS); 948*4d61c878SJulian Pullen } else { 949*4d61c878SJulian Pullen if (ad->known_domains != NULL) { 950*4d61c878SJulian Pullen free(ad->known_domains); 951*4d61c878SJulian Pullen ad->known_domains = NULL; 952*4d61c878SJulian Pullen } 953*4d61c878SJulian Pullen ad->num_known_domains = 0; 954*4d61c878SJulian Pullen return (ADUTILS_ERR_MEMORY); 955*4d61c878SJulian Pullen } 956*4d61c878SJulian Pullen } 957*4d61c878SJulian Pullen 958*4d61c878SJulian Pullen 959*4d61c878SJulian Pullen /* 960*4d61c878SJulian Pullen * Check that this AD supports this domain. 961*4d61c878SJulian Pullen * If there are no known domains assume that the 962*4d61c878SJulian Pullen * domain is supported by this AD. 963*4d61c878SJulian Pullen * 964*4d61c878SJulian Pullen * Returns 1 if this domain is supported by this AD 965*4d61c878SJulian Pullen * else returns 0; 966*4d61c878SJulian Pullen */ 967*4d61c878SJulian Pullen 968*4d61c878SJulian Pullen int 969*4d61c878SJulian Pullen adutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain) 970*4d61c878SJulian Pullen { 971*4d61c878SJulian Pullen adutils_ad_t *ad = qs->qadh->owner; 972*4d61c878SJulian Pullen int i, err; 973*4d61c878SJulian Pullen 974*4d61c878SJulian Pullen for (i = 0; i < ad->num_known_domains; i++) { 975*4d61c878SJulian Pullen if (u8_strcmp(domain, ad->known_domains[i].name, 0, 976*4d61c878SJulian Pullen U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && 977*4d61c878SJulian Pullen err == 0) 978*4d61c878SJulian Pullen return (1); 979*4d61c878SJulian Pullen } 980*4d61c878SJulian Pullen 981*4d61c878SJulian Pullen return ((i == 0) ? 1 : 0); 982*4d61c878SJulian Pullen } 983*4d61c878SJulian Pullen 984*4d61c878SJulian Pullen 985*4d61c878SJulian Pullen /* 986*4d61c878SJulian Pullen * Check that this AD supports the SID prefix. 987*4d61c878SJulian Pullen * The SID prefix should match the domain SID. 988*4d61c878SJulian Pullen * If there are no known domains assume that the 989*4d61c878SJulian Pullen * SID prefix is supported by this AD. 990*4d61c878SJulian Pullen * 991*4d61c878SJulian Pullen * Returns 1 if this sid prefix is supported by this AD 992*4d61c878SJulian Pullen * else returns 0; 993*4d61c878SJulian Pullen */ 994*4d61c878SJulian Pullen 995*4d61c878SJulian Pullen int 996*4d61c878SJulian Pullen adutils_lookup_check_sid_prefix(adutils_query_state_t *qs, const char *sid) 997*4d61c878SJulian Pullen { 998*4d61c878SJulian Pullen adutils_ad_t *ad = qs->qadh->owner; 999*4d61c878SJulian Pullen int i; 1000*4d61c878SJulian Pullen 1001*4d61c878SJulian Pullen 1002*4d61c878SJulian Pullen for (i = 0; i < ad->num_known_domains; i++) { 1003*4d61c878SJulian Pullen if (strcmp(sid, ad->known_domains[i].sid) == 0) 1004*4d61c878SJulian Pullen return (1); 1005*4d61c878SJulian Pullen } 1006*4d61c878SJulian Pullen 1007*4d61c878SJulian Pullen return ((i == 0) ? 1 : 0); 1008*4d61c878SJulian Pullen } 1009*4d61c878SJulian Pullen 10102b4a7802SBaban Kenkre 10112b4a7802SBaban Kenkre adutils_rc 10122b4a7802SBaban Kenkre adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries, 10132b4a7802SBaban Kenkre adutils_ldap_res_search_cb ldap_res_search_cb, 10142b4a7802SBaban Kenkre void *ldap_res_search_argp, 10152b4a7802SBaban Kenkre adutils_query_state_t **state) 10162b4a7802SBaban Kenkre { 10172b4a7802SBaban Kenkre adutils_query_state_t *new_state; 10182b4a7802SBaban Kenkre adutils_host_t *adh = NULL; 10192b4a7802SBaban Kenkre 10202b4a7802SBaban Kenkre if (ad == NULL) 10212b4a7802SBaban Kenkre return (ADUTILS_ERR_INTERNAL); 10222b4a7802SBaban Kenkre 10232b4a7802SBaban Kenkre *state = NULL; 10242b4a7802SBaban Kenkre adh = get_conn(ad); 10252b4a7802SBaban Kenkre if (adh == NULL) 10262b4a7802SBaban Kenkre return (ADUTILS_ERR_RETRIABLE_NET_ERR); 10272b4a7802SBaban Kenkre 10282b4a7802SBaban Kenkre new_state = calloc(1, sizeof (adutils_query_state_t) + 10292b4a7802SBaban Kenkre (nqueries - 1) * sizeof (adutils_q_t)); 10302b4a7802SBaban Kenkre if (new_state == NULL) 10312b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 10322b4a7802SBaban Kenkre 10332b4a7802SBaban Kenkre /* 10342b4a7802SBaban Kenkre * Save default domain from the ad object so that we don't 10352b4a7802SBaban Kenkre * have to access the 'ad' object later. 10362b4a7802SBaban Kenkre */ 10372b4a7802SBaban Kenkre new_state->default_domain = strdup(adh->owner->dflt_w2k_dom); 10382b4a7802SBaban Kenkre if (new_state->default_domain == NULL) { 10392b4a7802SBaban Kenkre free(new_state); 10402b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 10412b4a7802SBaban Kenkre } 10422b4a7802SBaban Kenkre 10432b4a7802SBaban Kenkre if (ad->partition == ADUTILS_AD_DATA) 10442b4a7802SBaban Kenkre new_state->basedn = adutils_dns2dn(new_state->default_domain); 10452b4a7802SBaban Kenkre else 10462b4a7802SBaban Kenkre new_state->basedn = strdup(""); 10472b4a7802SBaban Kenkre if (new_state->basedn == NULL) { 10482b4a7802SBaban Kenkre free(new_state->default_domain); 10492b4a7802SBaban Kenkre free(new_state); 10502b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 10512b4a7802SBaban Kenkre } 10522b4a7802SBaban Kenkre 10532b4a7802SBaban Kenkre new_state->ref_cnt = 1; 10542b4a7802SBaban Kenkre new_state->qadh = adh; 1055*4d61c878SJulian Pullen new_state->qsize = nqueries; 10562b4a7802SBaban Kenkre new_state->qadh_gen = adh->generation; 1057*4d61c878SJulian Pullen new_state->qcount = 0; 10582b4a7802SBaban Kenkre new_state->ldap_res_search_cb = ldap_res_search_cb; 10592b4a7802SBaban Kenkre new_state->ldap_res_search_argp = ldap_res_search_argp; 10602b4a7802SBaban Kenkre (void) pthread_cond_init(&new_state->cv, NULL); 10612b4a7802SBaban Kenkre 10622b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 10632b4a7802SBaban Kenkre new_state->next = qstatehead; 10642b4a7802SBaban Kenkre qstatehead = new_state; 10652b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 10662b4a7802SBaban Kenkre *state = new_state; 10672b4a7802SBaban Kenkre 10682b4a7802SBaban Kenkre return (ADUTILS_SUCCESS); 10692b4a7802SBaban Kenkre } 10702b4a7802SBaban Kenkre 10712b4a7802SBaban Kenkre /* 10722b4a7802SBaban Kenkre * Find the adutils_query_state_t to which a given LDAP result msgid on a 10732b4a7802SBaban Kenkre * given connection belongs. This routine increaments the reference count 10742b4a7802SBaban Kenkre * so that the object can not be freed. adutils_lookup_batch_unlock() 10752b4a7802SBaban Kenkre * must be called to decreament the reference count. 10762b4a7802SBaban Kenkre */ 10772b4a7802SBaban Kenkre static 10782b4a7802SBaban Kenkre int 10792b4a7802SBaban Kenkre msgid2query(adutils_host_t *adh, int msgid, 10802b4a7802SBaban Kenkre adutils_query_state_t **state, int *qid) 10812b4a7802SBaban Kenkre { 10822b4a7802SBaban Kenkre adutils_query_state_t *p; 10832b4a7802SBaban Kenkre int i; 10842b4a7802SBaban Kenkre int ret; 10852b4a7802SBaban Kenkre 10862b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 10872b4a7802SBaban Kenkre for (p = qstatehead; p != NULL; p = p->next) { 10882b4a7802SBaban Kenkre if (p->qadh != adh || adh->generation != p->qadh_gen) 10892b4a7802SBaban Kenkre continue; 10902b4a7802SBaban Kenkre for (i = 0; i < p->qcount; i++) { 10912b4a7802SBaban Kenkre if ((p->queries[i]).msgid == msgid) { 10922b4a7802SBaban Kenkre if (!p->qdead) { 10932b4a7802SBaban Kenkre p->ref_cnt++; 10942b4a7802SBaban Kenkre *state = p; 10952b4a7802SBaban Kenkre *qid = i; 10962b4a7802SBaban Kenkre ret = 1; 10972b4a7802SBaban Kenkre } else 10982b4a7802SBaban Kenkre ret = 0; 10992b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 11002b4a7802SBaban Kenkre return (ret); 11012b4a7802SBaban Kenkre } 11022b4a7802SBaban Kenkre } 11032b4a7802SBaban Kenkre } 11042b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 11052b4a7802SBaban Kenkre return (0); 11062b4a7802SBaban Kenkre } 11072b4a7802SBaban Kenkre 11082b4a7802SBaban Kenkre static 11092b4a7802SBaban Kenkre int 11102b4a7802SBaban Kenkre check_for_binary_attrs(const char *attr) 11112b4a7802SBaban Kenkre { 11122b4a7802SBaban Kenkre int i; 11132b4a7802SBaban Kenkre for (i = 0; binattrs[i].name != NULL; i++) { 11142b4a7802SBaban Kenkre if (strcasecmp(binattrs[i].name, attr) == 0) 11152b4a7802SBaban Kenkre return (i); 11162b4a7802SBaban Kenkre } 11172b4a7802SBaban Kenkre return (-1); 11182b4a7802SBaban Kenkre } 11192b4a7802SBaban Kenkre 11202b4a7802SBaban Kenkre static 11212b4a7802SBaban Kenkre void 11222b4a7802SBaban Kenkre free_entry(adutils_entry_t *entry) 11232b4a7802SBaban Kenkre { 11242b4a7802SBaban Kenkre int i, j; 11252b4a7802SBaban Kenkre adutils_attr_t *ap; 11262b4a7802SBaban Kenkre 11272b4a7802SBaban Kenkre if (entry == NULL) 11282b4a7802SBaban Kenkre return; 11292b4a7802SBaban Kenkre if (entry->attr_nvpairs == NULL) { 11302b4a7802SBaban Kenkre free(entry); 11312b4a7802SBaban Kenkre return; 11322b4a7802SBaban Kenkre } 11332b4a7802SBaban Kenkre for (i = 0; i < entry->num_nvpairs; i++) { 11342b4a7802SBaban Kenkre ap = &entry->attr_nvpairs[i]; 11352b4a7802SBaban Kenkre if (ap->attr_name == NULL) { 11362b4a7802SBaban Kenkre ldap_value_free(ap->attr_values); 11372b4a7802SBaban Kenkre continue; 11382b4a7802SBaban Kenkre } 11392b4a7802SBaban Kenkre if (check_for_binary_attrs(ap->attr_name) >= 0) { 11402b4a7802SBaban Kenkre free(ap->attr_name); 11412b4a7802SBaban Kenkre if (ap->attr_values == NULL) 11422b4a7802SBaban Kenkre continue; 11432b4a7802SBaban Kenkre for (j = 0; j < ap->num_values; j++) 11442b4a7802SBaban Kenkre free(ap->attr_values[j]); 11452b4a7802SBaban Kenkre free(ap->attr_values); 11462b4a7802SBaban Kenkre } else if (strcasecmp(ap->attr_name, "dn") == 0) { 11472b4a7802SBaban Kenkre free(ap->attr_name); 11482b4a7802SBaban Kenkre ldap_memfree(ap->attr_values[0]); 11492b4a7802SBaban Kenkre free(ap->attr_values); 11502b4a7802SBaban Kenkre } else { 11512b4a7802SBaban Kenkre free(ap->attr_name); 11522b4a7802SBaban Kenkre ldap_value_free(ap->attr_values); 11532b4a7802SBaban Kenkre } 11542b4a7802SBaban Kenkre } 11552b4a7802SBaban Kenkre free(entry->attr_nvpairs); 11562b4a7802SBaban Kenkre free(entry); 11572b4a7802SBaban Kenkre } 11582b4a7802SBaban Kenkre 11592b4a7802SBaban Kenkre void 11602b4a7802SBaban Kenkre adutils_freeresult(adutils_result_t **result) 11612b4a7802SBaban Kenkre { 11622b4a7802SBaban Kenkre adutils_entry_t *e, *next; 11632b4a7802SBaban Kenkre 11642b4a7802SBaban Kenkre if (result == NULL || *result == NULL) 11652b4a7802SBaban Kenkre return; 11662b4a7802SBaban Kenkre if ((*result)->entries == NULL) { 11672b4a7802SBaban Kenkre free(*result); 11682b4a7802SBaban Kenkre *result = NULL; 11692b4a7802SBaban Kenkre return; 11702b4a7802SBaban Kenkre } 11712b4a7802SBaban Kenkre for (e = (*result)->entries; e != NULL; e = next) { 11722b4a7802SBaban Kenkre next = e->next; 11732b4a7802SBaban Kenkre free_entry(e); 11742b4a7802SBaban Kenkre } 11752b4a7802SBaban Kenkre free(*result); 11762b4a7802SBaban Kenkre *result = NULL; 11772b4a7802SBaban Kenkre } 11782b4a7802SBaban Kenkre 11792b4a7802SBaban Kenkre const adutils_entry_t * 11802b4a7802SBaban Kenkre adutils_getfirstentry(adutils_result_t *result) 11812b4a7802SBaban Kenkre { 11822b4a7802SBaban Kenkre if (result != NULL) 11832b4a7802SBaban Kenkre return (result->entries); 11842b4a7802SBaban Kenkre return (NULL); 11852b4a7802SBaban Kenkre } 11862b4a7802SBaban Kenkre 11872b4a7802SBaban Kenkre 11882b4a7802SBaban Kenkre char ** 11892b4a7802SBaban Kenkre adutils_getattr(const adutils_entry_t *entry, const char *attrname) 11902b4a7802SBaban Kenkre { 11912b4a7802SBaban Kenkre int i; 11922b4a7802SBaban Kenkre adutils_attr_t *ap; 11932b4a7802SBaban Kenkre 11942b4a7802SBaban Kenkre if (entry == NULL || entry->attr_nvpairs == NULL) 11952b4a7802SBaban Kenkre return (NULL); 11962b4a7802SBaban Kenkre for (i = 0; i < entry->num_nvpairs; i++) { 11972b4a7802SBaban Kenkre ap = &entry->attr_nvpairs[i]; 11982b4a7802SBaban Kenkre if (ap->attr_name != NULL && 11992b4a7802SBaban Kenkre strcasecmp(ap->attr_name, attrname) == 0) 12002b4a7802SBaban Kenkre return (ap->attr_values); 12012b4a7802SBaban Kenkre } 12022b4a7802SBaban Kenkre return (NULL); 12032b4a7802SBaban Kenkre } 12042b4a7802SBaban Kenkre 12052b4a7802SBaban Kenkre 12062b4a7802SBaban Kenkre /* 12072b4a7802SBaban Kenkre * Queue LDAP result for the given query. 12082b4a7802SBaban Kenkre * 12092b4a7802SBaban Kenkre * Return values: 12102b4a7802SBaban Kenkre * 0 success 12112b4a7802SBaban Kenkre * -1 ignore result 12122b4a7802SBaban Kenkre * -2 error 12132b4a7802SBaban Kenkre */ 12142b4a7802SBaban Kenkre static 12152b4a7802SBaban Kenkre int 12162b4a7802SBaban Kenkre make_entry(adutils_q_t *q, adutils_host_t *adh, LDAPMessage *search_res, 12172b4a7802SBaban Kenkre adutils_entry_t **entry) 12182b4a7802SBaban Kenkre { 12192b4a7802SBaban Kenkre BerElement *ber = NULL; 12202b4a7802SBaban Kenkre BerValue **bvalues = NULL; 12212b4a7802SBaban Kenkre char **strvalues; 12222b4a7802SBaban Kenkre char *attr = NULL, *dn = NULL, *domain = NULL; 12232b4a7802SBaban Kenkre adutils_entry_t *ep; 12242b4a7802SBaban Kenkre adutils_attr_t *ap; 12252b4a7802SBaban Kenkre int i, j, b, err = 0, ret = -2; 12262b4a7802SBaban Kenkre 12272b4a7802SBaban Kenkre *entry = NULL; 12282b4a7802SBaban Kenkre 12292b4a7802SBaban Kenkre /* Check that this is the domain that we were looking for */ 12302b4a7802SBaban Kenkre if ((dn = ldap_get_dn(adh->ld, search_res)) == NULL) 12312b4a7802SBaban Kenkre return (-2); 12322b4a7802SBaban Kenkre if ((domain = adutils_dn2dns(dn)) == NULL) { 12332b4a7802SBaban Kenkre ldap_memfree(dn); 12342b4a7802SBaban Kenkre return (-2); 12352b4a7802SBaban Kenkre } 12362b4a7802SBaban Kenkre if (q->edomain != NULL) { 12372b4a7802SBaban Kenkre if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER, 12382b4a7802SBaban Kenkre U8_UNICODE_LATEST, &err) != 0 || err != 0) { 12392b4a7802SBaban Kenkre ldap_memfree(dn); 12402b4a7802SBaban Kenkre free(domain); 12412b4a7802SBaban Kenkre return (-1); 12422b4a7802SBaban Kenkre } 12432b4a7802SBaban Kenkre } 12442b4a7802SBaban Kenkre free(domain); 12452b4a7802SBaban Kenkre 12462b4a7802SBaban Kenkre /* Allocate memory for the entry */ 12472b4a7802SBaban Kenkre if ((ep = calloc(1, sizeof (*ep))) == NULL) 12482b4a7802SBaban Kenkre goto out; 12492b4a7802SBaban Kenkre 12502b4a7802SBaban Kenkre /* For 'dn' */ 12512b4a7802SBaban Kenkre ep->num_nvpairs = 1; 12522b4a7802SBaban Kenkre 12532b4a7802SBaban Kenkre /* Count the number of name-value pairs for this entry */ 12542b4a7802SBaban Kenkre for (attr = ldap_first_attribute(adh->ld, search_res, &ber); 12552b4a7802SBaban Kenkre attr != NULL; 12562b4a7802SBaban Kenkre attr = ldap_next_attribute(adh->ld, search_res, ber)) { 12572b4a7802SBaban Kenkre ep->num_nvpairs++; 12582b4a7802SBaban Kenkre ldap_memfree(attr); 12592b4a7802SBaban Kenkre } 12602b4a7802SBaban Kenkre ber_free(ber, 0); 12612b4a7802SBaban Kenkre ber = NULL; 12622b4a7802SBaban Kenkre 12632b4a7802SBaban Kenkre /* Allocate array for the attribute name-value pairs */ 12642b4a7802SBaban Kenkre ep->attr_nvpairs = calloc(ep->num_nvpairs, sizeof (*ep->attr_nvpairs)); 12652b4a7802SBaban Kenkre if (ep->attr_nvpairs == NULL) { 12662b4a7802SBaban Kenkre ep->num_nvpairs = 0; 12672b4a7802SBaban Kenkre goto out; 12682b4a7802SBaban Kenkre } 12692b4a7802SBaban Kenkre 12702b4a7802SBaban Kenkre /* For dn */ 12712b4a7802SBaban Kenkre ap = &ep->attr_nvpairs[0]; 12722b4a7802SBaban Kenkre if ((ap->attr_name = strdup("dn")) == NULL) 12732b4a7802SBaban Kenkre goto out; 12742b4a7802SBaban Kenkre ap->num_values = 1; 12752b4a7802SBaban Kenkre ap->attr_values = calloc(ap->num_values, sizeof (*ap->attr_values)); 12762b4a7802SBaban Kenkre if (ap->attr_values == NULL) { 12772b4a7802SBaban Kenkre ap->num_values = 0; 12782b4a7802SBaban Kenkre goto out; 12792b4a7802SBaban Kenkre } 12802b4a7802SBaban Kenkre ap->attr_values[0] = dn; 12812b4a7802SBaban Kenkre dn = NULL; 12822b4a7802SBaban Kenkre 12832b4a7802SBaban Kenkre for (attr = ldap_first_attribute(adh->ld, search_res, &ber), i = 1; 12842b4a7802SBaban Kenkre attr != NULL; 12852b4a7802SBaban Kenkre ldap_memfree(attr), i++, 12862b4a7802SBaban Kenkre attr = ldap_next_attribute(adh->ld, search_res, ber)) { 12872b4a7802SBaban Kenkre ap = &ep->attr_nvpairs[i]; 12882b4a7802SBaban Kenkre if ((ap->attr_name = strdup(attr)) == NULL) 12892b4a7802SBaban Kenkre goto out; 12902b4a7802SBaban Kenkre 12912b4a7802SBaban Kenkre if ((b = check_for_binary_attrs(attr)) >= 0) { 12922b4a7802SBaban Kenkre bvalues = 12932b4a7802SBaban Kenkre ldap_get_values_len(adh->ld, search_res, attr); 12942b4a7802SBaban Kenkre if (bvalues == NULL) 12952b4a7802SBaban Kenkre continue; 12962b4a7802SBaban Kenkre ap->num_values = ldap_count_values_len(bvalues); 12972b4a7802SBaban Kenkre if (ap->num_values == 0) { 12982b4a7802SBaban Kenkre ldap_value_free_len(bvalues); 12992b4a7802SBaban Kenkre bvalues = NULL; 13002b4a7802SBaban Kenkre continue; 13012b4a7802SBaban Kenkre } 13022b4a7802SBaban Kenkre ap->attr_values = calloc(ap->num_values, 13032b4a7802SBaban Kenkre sizeof (*ap->attr_values)); 13042b4a7802SBaban Kenkre if (ap->attr_values == NULL) { 13052b4a7802SBaban Kenkre ap->num_values = 0; 13062b4a7802SBaban Kenkre goto out; 13072b4a7802SBaban Kenkre } 13082b4a7802SBaban Kenkre for (j = 0; j < ap->num_values; j++) { 13092b4a7802SBaban Kenkre ap->attr_values[j] = 13102b4a7802SBaban Kenkre binattrs[b].ber2str(bvalues[j]); 13112b4a7802SBaban Kenkre if (ap->attr_values[j] == NULL) 13122b4a7802SBaban Kenkre goto out; 13132b4a7802SBaban Kenkre } 13142b4a7802SBaban Kenkre ldap_value_free_len(bvalues); 13152b4a7802SBaban Kenkre bvalues = NULL; 13162b4a7802SBaban Kenkre continue; 13172b4a7802SBaban Kenkre } 13182b4a7802SBaban Kenkre 13192b4a7802SBaban Kenkre strvalues = ldap_get_values(adh->ld, search_res, attr); 13202b4a7802SBaban Kenkre if (strvalues == NULL) 13212b4a7802SBaban Kenkre continue; 13222b4a7802SBaban Kenkre ap->num_values = ldap_count_values(strvalues); 13232b4a7802SBaban Kenkre if (ap->num_values == 0) { 13242b4a7802SBaban Kenkre ldap_value_free(strvalues); 13252b4a7802SBaban Kenkre continue; 13262b4a7802SBaban Kenkre } 13272b4a7802SBaban Kenkre ap->attr_values = strvalues; 13282b4a7802SBaban Kenkre } 13292b4a7802SBaban Kenkre 13302b4a7802SBaban Kenkre ret = 0; 13312b4a7802SBaban Kenkre out: 13322b4a7802SBaban Kenkre ldap_memfree(attr); 13332b4a7802SBaban Kenkre ldap_memfree(dn); 13342b4a7802SBaban Kenkre ber_free(ber, 0); 13352b4a7802SBaban Kenkre ldap_value_free_len(bvalues); 13362b4a7802SBaban Kenkre if (ret < 0) 13372b4a7802SBaban Kenkre free_entry(ep); 13382b4a7802SBaban Kenkre else 13392b4a7802SBaban Kenkre *entry = ep; 13402b4a7802SBaban Kenkre return (ret); 13412b4a7802SBaban Kenkre } 13422b4a7802SBaban Kenkre 13432b4a7802SBaban Kenkre /* 13442b4a7802SBaban Kenkre * Put the search result onto the given adutils_q_t. 13452b4a7802SBaban Kenkre * Returns: 0 success 13462b4a7802SBaban Kenkre * < 0 error 13472b4a7802SBaban Kenkre */ 13482b4a7802SBaban Kenkre static 13492b4a7802SBaban Kenkre int 13502b4a7802SBaban Kenkre add_entry(adutils_host_t *adh, adutils_q_t *q, LDAPMessage *search_res) 13512b4a7802SBaban Kenkre { 13522b4a7802SBaban Kenkre int ret = -1; 13532b4a7802SBaban Kenkre adutils_entry_t *entry = NULL; 13542b4a7802SBaban Kenkre adutils_result_t *res; 13552b4a7802SBaban Kenkre 13562b4a7802SBaban Kenkre ret = make_entry(q, adh, search_res, &entry); 13572b4a7802SBaban Kenkre if (ret < -1) { 13582b4a7802SBaban Kenkre *q->rc = ADUTILS_ERR_MEMORY; 13592b4a7802SBaban Kenkre goto out; 13602b4a7802SBaban Kenkre } else if (ret == -1) { 13612b4a7802SBaban Kenkre /* ignore result */ 13622b4a7802SBaban Kenkre goto out; 13632b4a7802SBaban Kenkre } 13642b4a7802SBaban Kenkre if (*q->result == NULL) { 13652b4a7802SBaban Kenkre res = calloc(1, sizeof (*res)); 13662b4a7802SBaban Kenkre if (res == NULL) { 13672b4a7802SBaban Kenkre *q->rc = ADUTILS_ERR_MEMORY; 13682b4a7802SBaban Kenkre goto out; 13692b4a7802SBaban Kenkre } 13702b4a7802SBaban Kenkre res->num_entries = 1; 13712b4a7802SBaban Kenkre res->entries = entry; 13722b4a7802SBaban Kenkre *q->result = res; 13732b4a7802SBaban Kenkre } else { 13742b4a7802SBaban Kenkre res = *q->result; 13752b4a7802SBaban Kenkre entry->next = res->entries; 13762b4a7802SBaban Kenkre res->entries = entry; 13772b4a7802SBaban Kenkre res->num_entries++; 13782b4a7802SBaban Kenkre } 13792b4a7802SBaban Kenkre *q->rc = ADUTILS_SUCCESS; 13802b4a7802SBaban Kenkre entry = NULL; 13812b4a7802SBaban Kenkre ret = 0; 13822b4a7802SBaban Kenkre 13832b4a7802SBaban Kenkre out: 13842b4a7802SBaban Kenkre free_entry(entry); 13852b4a7802SBaban Kenkre return (ret); 13862b4a7802SBaban Kenkre } 13872b4a7802SBaban Kenkre 13882b4a7802SBaban Kenkre /* 13892b4a7802SBaban Kenkre * Try to get a result; if there is one, find the corresponding 13902b4a7802SBaban Kenkre * adutils_q_t and process the result. 13912b4a7802SBaban Kenkre * 13922b4a7802SBaban Kenkre * Returns: 0 success 13932b4a7802SBaban Kenkre * -1 error 13942b4a7802SBaban Kenkre */ 13952b4a7802SBaban Kenkre static 13962b4a7802SBaban Kenkre int 13972b4a7802SBaban Kenkre get_adobject_batch(adutils_host_t *adh, struct timeval *timeout) 13982b4a7802SBaban Kenkre { 13992b4a7802SBaban Kenkre adutils_query_state_t *query_state; 14002b4a7802SBaban Kenkre LDAPMessage *res = NULL; 14012b4a7802SBaban Kenkre int rc, ret, msgid, qid; 14022b4a7802SBaban Kenkre adutils_q_t *que; 14032b4a7802SBaban Kenkre int num; 14042b4a7802SBaban Kenkre 14052b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 14062b4a7802SBaban Kenkre if (adh->dead || adh->num_requests == 0) { 14072b4a7802SBaban Kenkre ret = (adh->dead) ? -1 : -2; 14082b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 14092b4a7802SBaban Kenkre return (ret); 14102b4a7802SBaban Kenkre } 14112b4a7802SBaban Kenkre 14122b4a7802SBaban Kenkre /* Get one result */ 14132b4a7802SBaban Kenkre rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, timeout, &res); 14142b4a7802SBaban Kenkre if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) || 14152b4a7802SBaban Kenkre rc < 0) 14162b4a7802SBaban Kenkre adh->dead = 1; 14172b4a7802SBaban Kenkre 14182b4a7802SBaban Kenkre if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0) 14192b4a7802SBaban Kenkre adh->num_requests--; 14202b4a7802SBaban Kenkre if (adh->dead) { 14212b4a7802SBaban Kenkre num = adh->num_requests; 14222b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 14232b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, 14242b4a7802SBaban Kenkre "AD ldap_result error - %d queued requests", num); 14252b4a7802SBaban Kenkre return (-1); 14262b4a7802SBaban Kenkre } 14272b4a7802SBaban Kenkre 14282b4a7802SBaban Kenkre switch (rc) { 14292b4a7802SBaban Kenkre case LDAP_RES_SEARCH_RESULT: 14302b4a7802SBaban Kenkre msgid = ldap_msgid(res); 14312b4a7802SBaban Kenkre if (msgid2query(adh, msgid, &query_state, &qid)) { 14322b4a7802SBaban Kenkre if (query_state->ldap_res_search_cb != NULL) { 14332b4a7802SBaban Kenkre /* 14342b4a7802SBaban Kenkre * We use the caller-provided callback 14352b4a7802SBaban Kenkre * to process the result. 14362b4a7802SBaban Kenkre */ 14372b4a7802SBaban Kenkre query_state->ldap_res_search_cb( 14382b4a7802SBaban Kenkre adh->ld, &res, rc, qid, 14392b4a7802SBaban Kenkre query_state->ldap_res_search_argp); 14402b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 14412b4a7802SBaban Kenkre } else { 14422b4a7802SBaban Kenkre /* 14432b4a7802SBaban Kenkre * No callback. We fallback to our 14442b4a7802SBaban Kenkre * default behaviour. All the entries 14452b4a7802SBaban Kenkre * gotten from this search have been 14462b4a7802SBaban Kenkre * added to the result list during 14472b4a7802SBaban Kenkre * LDAP_RES_SEARCH_ENTRY (see below). 14482b4a7802SBaban Kenkre * Here we set the return status to 14492b4a7802SBaban Kenkre * notfound if the result is still empty. 14502b4a7802SBaban Kenkre */ 14512b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 14522b4a7802SBaban Kenkre que = &(query_state->queries[qid]); 14532b4a7802SBaban Kenkre if (*que->result == NULL) 14542b4a7802SBaban Kenkre *que->rc = ADUTILS_ERR_NOTFOUND; 14552b4a7802SBaban Kenkre } 14562b4a7802SBaban Kenkre atomic_dec_32(&query_state->qinflight); 14572b4a7802SBaban Kenkre adutils_lookup_batch_unlock(&query_state); 14582b4a7802SBaban Kenkre } else { 14592b4a7802SBaban Kenkre num = adh->num_requests; 14602b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 14612b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, 14622b4a7802SBaban Kenkre "AD cannot find message ID (%d) " 14632b4a7802SBaban Kenkre "- %d queued requests", 14642b4a7802SBaban Kenkre msgid, num); 14652b4a7802SBaban Kenkre } 14662b4a7802SBaban Kenkre (void) ldap_msgfree(res); 14672b4a7802SBaban Kenkre ret = 0; 14682b4a7802SBaban Kenkre break; 14692b4a7802SBaban Kenkre 14702b4a7802SBaban Kenkre case LDAP_RES_SEARCH_ENTRY: 14712b4a7802SBaban Kenkre msgid = ldap_msgid(res); 14722b4a7802SBaban Kenkre if (msgid2query(adh, msgid, &query_state, &qid)) { 14732b4a7802SBaban Kenkre if (query_state->ldap_res_search_cb != NULL) { 14742b4a7802SBaban Kenkre /* 14752b4a7802SBaban Kenkre * We use the caller-provided callback 14762b4a7802SBaban Kenkre * to process the entry. 14772b4a7802SBaban Kenkre */ 14782b4a7802SBaban Kenkre query_state->ldap_res_search_cb( 14792b4a7802SBaban Kenkre adh->ld, &res, rc, qid, 14802b4a7802SBaban Kenkre query_state->ldap_res_search_argp); 14812b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 14822b4a7802SBaban Kenkre } else { 14832b4a7802SBaban Kenkre /* 14842b4a7802SBaban Kenkre * No callback. We fallback to our 14852b4a7802SBaban Kenkre * default behaviour. This entry 14862b4a7802SBaban Kenkre * will be added to the result list. 14872b4a7802SBaban Kenkre */ 14882b4a7802SBaban Kenkre que = &(query_state->queries[qid]); 14892b4a7802SBaban Kenkre rc = add_entry(adh, que, res); 14902b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 14912b4a7802SBaban Kenkre if (rc < 0) { 14922b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, 14932b4a7802SBaban Kenkre "Failed to queue entry by " 14942b4a7802SBaban Kenkre "message ID (%d) " 14952b4a7802SBaban Kenkre "- %d queued requests", 14962b4a7802SBaban Kenkre msgid, num); 14972b4a7802SBaban Kenkre } 14982b4a7802SBaban Kenkre } 14992b4a7802SBaban Kenkre adutils_lookup_batch_unlock(&query_state); 15002b4a7802SBaban Kenkre } else { 15012b4a7802SBaban Kenkre num = adh->num_requests; 15022b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 15032b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, 15042b4a7802SBaban Kenkre "AD cannot find message ID (%d) " 15052b4a7802SBaban Kenkre "- %d queued requests", 15062b4a7802SBaban Kenkre msgid, num); 15072b4a7802SBaban Kenkre } 15082b4a7802SBaban Kenkre (void) ldap_msgfree(res); 15092b4a7802SBaban Kenkre ret = 0; 15102b4a7802SBaban Kenkre break; 15112b4a7802SBaban Kenkre 15122b4a7802SBaban Kenkre case LDAP_RES_SEARCH_REFERENCE: 15132b4a7802SBaban Kenkre /* 15142b4a7802SBaban Kenkre * We have no need for these at the moment. Eventually, 15152b4a7802SBaban Kenkre * when we query things that we can't expect to find in 15162b4a7802SBaban Kenkre * the Global Catalog then we'll need to learn to follow 15172b4a7802SBaban Kenkre * references. 15182b4a7802SBaban Kenkre */ 15192b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 15202b4a7802SBaban Kenkre (void) ldap_msgfree(res); 15212b4a7802SBaban Kenkre ret = 0; 15222b4a7802SBaban Kenkre break; 15232b4a7802SBaban Kenkre 15242b4a7802SBaban Kenkre default: 15252b4a7802SBaban Kenkre /* timeout or error; treat the same */ 15262b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 15272b4a7802SBaban Kenkre ret = -1; 15282b4a7802SBaban Kenkre break; 15292b4a7802SBaban Kenkre } 15302b4a7802SBaban Kenkre 15312b4a7802SBaban Kenkre return (ret); 15322b4a7802SBaban Kenkre } 15332b4a7802SBaban Kenkre 15342b4a7802SBaban Kenkre /* 15352b4a7802SBaban Kenkre * This routine decreament the reference count of the 15362b4a7802SBaban Kenkre * adutils_query_state_t 15372b4a7802SBaban Kenkre */ 15382b4a7802SBaban Kenkre static void 15392b4a7802SBaban Kenkre adutils_lookup_batch_unlock(adutils_query_state_t **state) 15402b4a7802SBaban Kenkre { 15412b4a7802SBaban Kenkre /* 15422b4a7802SBaban Kenkre * Decrement reference count with qstatelock locked 15432b4a7802SBaban Kenkre */ 15442b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 15452b4a7802SBaban Kenkre (*state)->ref_cnt--; 15462b4a7802SBaban Kenkre /* 15472b4a7802SBaban Kenkre * If there are no references wakup the allocating thread 15482b4a7802SBaban Kenkre */ 15492b4a7802SBaban Kenkre if ((*state)->ref_cnt <= 1) 15502b4a7802SBaban Kenkre (void) pthread_cond_signal(&(*state)->cv); 15512b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 15522b4a7802SBaban Kenkre *state = NULL; 15532b4a7802SBaban Kenkre } 15542b4a7802SBaban Kenkre 15552b4a7802SBaban Kenkre /* 15562b4a7802SBaban Kenkre * This routine frees the adutils_query_state_t structure 15572b4a7802SBaban Kenkre * If the reference count is greater than 1 it waits 15582b4a7802SBaban Kenkre * for the other threads to finish using it. 15592b4a7802SBaban Kenkre */ 15602b4a7802SBaban Kenkre void 15612b4a7802SBaban Kenkre adutils_lookup_batch_release(adutils_query_state_t **state) 15622b4a7802SBaban Kenkre { 15632b4a7802SBaban Kenkre adutils_query_state_t **p; 15642b4a7802SBaban Kenkre int i; 15652b4a7802SBaban Kenkre 15662b4a7802SBaban Kenkre if (state == NULL || *state == NULL) 15672b4a7802SBaban Kenkre return; 15682b4a7802SBaban Kenkre 15692b4a7802SBaban Kenkre /* 15702b4a7802SBaban Kenkre * Set state to dead to stop further operations. 15712b4a7802SBaban Kenkre * Wait for reference count with qstatelock locked 15722b4a7802SBaban Kenkre * to get to one. 15732b4a7802SBaban Kenkre */ 15742b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 15752b4a7802SBaban Kenkre (*state)->qdead = 1; 15762b4a7802SBaban Kenkre while ((*state)->ref_cnt > 1) { 15772b4a7802SBaban Kenkre (void) pthread_cond_wait(&(*state)->cv, &qstatelock); 15782b4a7802SBaban Kenkre } 15792b4a7802SBaban Kenkre 15802b4a7802SBaban Kenkre /* Remove this state struct from the list of state structs */ 15812b4a7802SBaban Kenkre for (p = &qstatehead; *p != NULL; p = &(*p)->next) { 15822b4a7802SBaban Kenkre if (*p == (*state)) { 15832b4a7802SBaban Kenkre *p = (*state)->next; 15842b4a7802SBaban Kenkre break; 15852b4a7802SBaban Kenkre } 15862b4a7802SBaban Kenkre } 15872b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 15882b4a7802SBaban Kenkre (void) pthread_cond_destroy(&(*state)->cv); 15892b4a7802SBaban Kenkre release_conn((*state)->qadh); 15902b4a7802SBaban Kenkre 15912b4a7802SBaban Kenkre /* Clear results for queries that failed */ 15922b4a7802SBaban Kenkre for (i = 0; i < (*state)->qcount; i++) { 15932b4a7802SBaban Kenkre if (*(*state)->queries[i].rc != ADUTILS_SUCCESS) { 15942b4a7802SBaban Kenkre adutils_freeresult((*state)->queries[i].result); 15952b4a7802SBaban Kenkre } 15962b4a7802SBaban Kenkre } 15972b4a7802SBaban Kenkre free((*state)->default_domain); 15982b4a7802SBaban Kenkre free((*state)->basedn); 15992b4a7802SBaban Kenkre free(*state); 16002b4a7802SBaban Kenkre *state = NULL; 16012b4a7802SBaban Kenkre } 16022b4a7802SBaban Kenkre 16032b4a7802SBaban Kenkre 16042b4a7802SBaban Kenkre /* 16052b4a7802SBaban Kenkre * This routine waits for other threads using the 16062b4a7802SBaban Kenkre * adutils_query_state_t structure to finish. 16072b4a7802SBaban Kenkre * If the reference count is greater than 1 it waits 16082b4a7802SBaban Kenkre * for the other threads to finish using it. 16092b4a7802SBaban Kenkre */ 16102b4a7802SBaban Kenkre static 16112b4a7802SBaban Kenkre void 16122b4a7802SBaban Kenkre adutils_lookup_batch_wait(adutils_query_state_t *state) 16132b4a7802SBaban Kenkre { 16142b4a7802SBaban Kenkre /* 16152b4a7802SBaban Kenkre * Set state to dead to stop further operation. 16162b4a7802SBaban Kenkre * stating. 16172b4a7802SBaban Kenkre * Wait for reference count to get to one 16182b4a7802SBaban Kenkre * with qstatelock locked. 16192b4a7802SBaban Kenkre */ 16202b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 16212b4a7802SBaban Kenkre state->qdead = 1; 16222b4a7802SBaban Kenkre while (state->ref_cnt > 1) { 16232b4a7802SBaban Kenkre (void) pthread_cond_wait(&state->cv, &qstatelock); 16242b4a7802SBaban Kenkre } 16252b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 16262b4a7802SBaban Kenkre } 16272b4a7802SBaban Kenkre 16282b4a7802SBaban Kenkre /* 16292b4a7802SBaban Kenkre * Process active queries in the AD lookup batch and then finalize the 16302b4a7802SBaban Kenkre * result. 16312b4a7802SBaban Kenkre */ 16322b4a7802SBaban Kenkre adutils_rc 16332b4a7802SBaban Kenkre adutils_lookup_batch_end(adutils_query_state_t **state) 16342b4a7802SBaban Kenkre { 16352b4a7802SBaban Kenkre int rc = LDAP_SUCCESS; 16362b4a7802SBaban Kenkre adutils_rc ad_rc = ADUTILS_SUCCESS; 16372b4a7802SBaban Kenkre struct timeval tv; 16382b4a7802SBaban Kenkre 16392b4a7802SBaban Kenkre tv.tv_sec = ADUTILS_SEARCH_TIMEOUT; 16402b4a7802SBaban Kenkre tv.tv_usec = 0; 16412b4a7802SBaban Kenkre 16422b4a7802SBaban Kenkre /* Process results until done or until timeout, if given */ 16432b4a7802SBaban Kenkre while ((*state)->qinflight > 0) { 16442b4a7802SBaban Kenkre if ((rc = get_adobject_batch((*state)->qadh, 16452b4a7802SBaban Kenkre &tv)) != 0) 16462b4a7802SBaban Kenkre break; 16472b4a7802SBaban Kenkre } 16482b4a7802SBaban Kenkre (*state)->qdead = 1; 16492b4a7802SBaban Kenkre /* Wait for other threads processing search result to finish */ 16502b4a7802SBaban Kenkre adutils_lookup_batch_wait(*state); 16512b4a7802SBaban Kenkre if (rc == -1 || (*state)->qinflight != 0) 16522b4a7802SBaban Kenkre ad_rc = ADUTILS_ERR_RETRIABLE_NET_ERR; 16532b4a7802SBaban Kenkre adutils_lookup_batch_release(state); 16542b4a7802SBaban Kenkre return (ad_rc); 16552b4a7802SBaban Kenkre } 16562b4a7802SBaban Kenkre 16572b4a7802SBaban Kenkre const char * 16582b4a7802SBaban Kenkre adutils_lookup_batch_getdefdomain(adutils_query_state_t *state) 16592b4a7802SBaban Kenkre { 16602b4a7802SBaban Kenkre return (state->default_domain); 16612b4a7802SBaban Kenkre } 16622b4a7802SBaban Kenkre 16632b4a7802SBaban Kenkre /* 16642b4a7802SBaban Kenkre * Send one prepared search, queue up msgid, process what results are 16652b4a7802SBaban Kenkre * available 16662b4a7802SBaban Kenkre */ 16672b4a7802SBaban Kenkre adutils_rc 16682b4a7802SBaban Kenkre adutils_lookup_batch_add(adutils_query_state_t *state, 16692b4a7802SBaban Kenkre const char *filter, const char **attrs, const char *edomain, 16702b4a7802SBaban Kenkre adutils_result_t **result, adutils_rc *rc) 16712b4a7802SBaban Kenkre { 16722b4a7802SBaban Kenkre adutils_rc retcode = ADUTILS_SUCCESS; 16732b4a7802SBaban Kenkre int lrc, qid; 16742b4a7802SBaban Kenkre int num; 16752b4a7802SBaban Kenkre int dead; 16762b4a7802SBaban Kenkre struct timeval tv; 16772b4a7802SBaban Kenkre adutils_q_t *q; 16782b4a7802SBaban Kenkre 1679*4d61c878SJulian Pullen qid = atomic_inc_32_nv(&state->qcount) - 1; 16802b4a7802SBaban Kenkre q = &(state->queries[qid]); 16812b4a7802SBaban Kenkre 1682*4d61c878SJulian Pullen assert(qid < state->qsize); 1683*4d61c878SJulian Pullen 16842b4a7802SBaban Kenkre /* 16852b4a7802SBaban Kenkre * Remember the expected domain so we can check the results 16862b4a7802SBaban Kenkre * against it 16872b4a7802SBaban Kenkre */ 16882b4a7802SBaban Kenkre q->edomain = edomain; 16892b4a7802SBaban Kenkre 16902b4a7802SBaban Kenkre /* Remember where to put the results */ 16912b4a7802SBaban Kenkre q->result = result; 16922b4a7802SBaban Kenkre q->rc = rc; 16932b4a7802SBaban Kenkre 16942b4a7802SBaban Kenkre /* 16952b4a7802SBaban Kenkre * Provide sane defaults for the results in case we never hear 16962b4a7802SBaban Kenkre * back from the DS before closing the connection. 16972b4a7802SBaban Kenkre */ 16982b4a7802SBaban Kenkre *rc = ADUTILS_ERR_RETRIABLE_NET_ERR; 16992b4a7802SBaban Kenkre if (result != NULL) 17002b4a7802SBaban Kenkre *result = NULL; 17012b4a7802SBaban Kenkre 17022b4a7802SBaban Kenkre /* Check the number of queued requests first */ 17032b4a7802SBaban Kenkre tv.tv_sec = ADUTILS_SEARCH_TIMEOUT; 17042b4a7802SBaban Kenkre tv.tv_usec = 0; 17052b4a7802SBaban Kenkre while (!state->qadh->dead && 17062b4a7802SBaban Kenkre state->qadh->num_requests > state->qadh->max_requests) { 17072b4a7802SBaban Kenkre if (get_adobject_batch(state->qadh, &tv) != 0) 17082b4a7802SBaban Kenkre break; 17092b4a7802SBaban Kenkre } 17102b4a7802SBaban Kenkre 17112b4a7802SBaban Kenkre /* Send this lookup, don't wait for a result here */ 17122b4a7802SBaban Kenkre lrc = LDAP_SUCCESS; 17132b4a7802SBaban Kenkre (void) pthread_mutex_lock(&state->qadh->lock); 17142b4a7802SBaban Kenkre 17152b4a7802SBaban Kenkre if (!state->qadh->dead) { 17162b4a7802SBaban Kenkre state->qadh->idletime = time(NULL); 17172b4a7802SBaban Kenkre lrc = ldap_search_ext(state->qadh->ld, state->basedn, 17182b4a7802SBaban Kenkre LDAP_SCOPE_SUBTREE, filter, (char **)attrs, 17192b4a7802SBaban Kenkre 0, NULL, NULL, NULL, -1, &q->msgid); 17202b4a7802SBaban Kenkre 17212b4a7802SBaban Kenkre if (lrc == LDAP_SUCCESS) { 17222b4a7802SBaban Kenkre state->qadh->num_requests++; 17232b4a7802SBaban Kenkre } else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE || 17242b4a7802SBaban Kenkre lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN || 17252b4a7802SBaban Kenkre lrc == LDAP_UNWILLING_TO_PERFORM) { 17262b4a7802SBaban Kenkre retcode = ADUTILS_ERR_RETRIABLE_NET_ERR; 17272b4a7802SBaban Kenkre state->qadh->dead = 1; 17282b4a7802SBaban Kenkre } else { 17292b4a7802SBaban Kenkre retcode = ADUTILS_ERR_OTHER; 17302b4a7802SBaban Kenkre state->qadh->dead = 1; 17312b4a7802SBaban Kenkre } 17322b4a7802SBaban Kenkre } 17332b4a7802SBaban Kenkre dead = state->qadh->dead; 17342b4a7802SBaban Kenkre num = state->qadh->num_requests; 17352b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&state->qadh->lock); 17362b4a7802SBaban Kenkre 17372b4a7802SBaban Kenkre if (dead) { 17382b4a7802SBaban Kenkre if (lrc != LDAP_SUCCESS) 17392b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, 17402b4a7802SBaban Kenkre "AD ldap_search_ext error (%s) " 17412b4a7802SBaban Kenkre "- %d queued requests", 17422b4a7802SBaban Kenkre ldap_err2string(lrc), num); 17432b4a7802SBaban Kenkre return (retcode); 17442b4a7802SBaban Kenkre } 17452b4a7802SBaban Kenkre 17462b4a7802SBaban Kenkre atomic_inc_32(&state->qinflight); 17472b4a7802SBaban Kenkre 17482b4a7802SBaban Kenkre /* 17492b4a7802SBaban Kenkre * Reap as many requests as we can _without_ waiting to prevent 17502b4a7802SBaban Kenkre * any possible TCP socket buffer starvation deadlocks. 17512b4a7802SBaban Kenkre */ 17522b4a7802SBaban Kenkre (void) memset(&tv, 0, sizeof (tv)); 17532b4a7802SBaban Kenkre while (get_adobject_batch(state->qadh, &tv) == 0) 17542b4a7802SBaban Kenkre ; 17552b4a7802SBaban Kenkre 17562b4a7802SBaban Kenkre return (ADUTILS_SUCCESS); 17572b4a7802SBaban Kenkre } 17582b4a7802SBaban Kenkre 17592b4a7802SBaban Kenkre /* 17602b4a7802SBaban Kenkre * Single AD lookup request implemented on top of the batch API. 17612b4a7802SBaban Kenkre */ 17622b4a7802SBaban Kenkre adutils_rc 17632b4a7802SBaban Kenkre adutils_lookup(adutils_ad_t *ad, const char *filter, const char **attrs, 17642b4a7802SBaban Kenkre const char *domain, adutils_result_t **result) 17652b4a7802SBaban Kenkre { 17662b4a7802SBaban Kenkre adutils_rc rc, brc; 17672b4a7802SBaban Kenkre adutils_query_state_t *qs; 17682b4a7802SBaban Kenkre 17692b4a7802SBaban Kenkre rc = adutils_lookup_batch_start(ad, 1, NULL, NULL, &qs); 17702b4a7802SBaban Kenkre if (rc != ADUTILS_SUCCESS) 17712b4a7802SBaban Kenkre return (rc); 17722b4a7802SBaban Kenkre 17732b4a7802SBaban Kenkre rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc); 17742b4a7802SBaban Kenkre if (rc != ADUTILS_SUCCESS) { 17752b4a7802SBaban Kenkre adutils_lookup_batch_release(&qs); 17762b4a7802SBaban Kenkre return (rc); 17772b4a7802SBaban Kenkre } 17782b4a7802SBaban Kenkre 17792b4a7802SBaban Kenkre rc = adutils_lookup_batch_end(&qs); 17802b4a7802SBaban Kenkre if (rc != ADUTILS_SUCCESS) 17812b4a7802SBaban Kenkre return (rc); 17822b4a7802SBaban Kenkre return (brc); 17832b4a7802SBaban Kenkre } 1784