18040SBaban.Kenkre@Sun.COM /* 28040SBaban.Kenkre@Sun.COM * CDDL HEADER START 38040SBaban.Kenkre@Sun.COM * 48040SBaban.Kenkre@Sun.COM * The contents of this file are subject to the terms of the 58040SBaban.Kenkre@Sun.COM * Common Development and Distribution License (the "License"). 68040SBaban.Kenkre@Sun.COM * You may not use this file except in compliance with the License. 78040SBaban.Kenkre@Sun.COM * 88040SBaban.Kenkre@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 98040SBaban.Kenkre@Sun.COM * or http://www.opensolaris.org/os/licensing. 108040SBaban.Kenkre@Sun.COM * See the License for the specific language governing permissions 118040SBaban.Kenkre@Sun.COM * and limitations under the License. 128040SBaban.Kenkre@Sun.COM * 138040SBaban.Kenkre@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 148040SBaban.Kenkre@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 158040SBaban.Kenkre@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 168040SBaban.Kenkre@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 178040SBaban.Kenkre@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 188040SBaban.Kenkre@Sun.COM * 198040SBaban.Kenkre@Sun.COM * CDDL HEADER END 208040SBaban.Kenkre@Sun.COM */ 218040SBaban.Kenkre@Sun.COM /* 228040SBaban.Kenkre@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 238040SBaban.Kenkre@Sun.COM * Use is subject to license terms. 248040SBaban.Kenkre@Sun.COM */ 258040SBaban.Kenkre@Sun.COM 268040SBaban.Kenkre@Sun.COM #include <alloca.h> 278040SBaban.Kenkre@Sun.COM #include <string.h> 288040SBaban.Kenkre@Sun.COM #include <strings.h> 298040SBaban.Kenkre@Sun.COM #include <lber.h> 308040SBaban.Kenkre@Sun.COM #include <sasl/sasl.h> 318040SBaban.Kenkre@Sun.COM #include <string.h> 328040SBaban.Kenkre@Sun.COM #include <ctype.h> 338040SBaban.Kenkre@Sun.COM #include <synch.h> 348040SBaban.Kenkre@Sun.COM #include <atomic.h> 358040SBaban.Kenkre@Sun.COM #include <errno.h> 368040SBaban.Kenkre@Sun.COM #include <assert.h> 378040SBaban.Kenkre@Sun.COM #include <limits.h> 388040SBaban.Kenkre@Sun.COM #include <sys/u8_textprep.h> 398040SBaban.Kenkre@Sun.COM #include <sys/varargs.h> 408040SBaban.Kenkre@Sun.COM #include "libadutils.h" 418040SBaban.Kenkre@Sun.COM #include "adutils_impl.h" 428040SBaban.Kenkre@Sun.COM 438040SBaban.Kenkre@Sun.COM /* List of DSs, needed by the idle connection reaper thread */ 448040SBaban.Kenkre@Sun.COM static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER; 458040SBaban.Kenkre@Sun.COM static adutils_host_t *host_head = NULL; 468040SBaban.Kenkre@Sun.COM 478040SBaban.Kenkre@Sun.COM /* 488040SBaban.Kenkre@Sun.COM * List of query state structs -- needed so we can "route" LDAP results 498040SBaban.Kenkre@Sun.COM * to the right context if multiple threads should be using the same 508040SBaban.Kenkre@Sun.COM * connection concurrently 518040SBaban.Kenkre@Sun.COM */ 528040SBaban.Kenkre@Sun.COM static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER; 538040SBaban.Kenkre@Sun.COM static adutils_query_state_t *qstatehead = NULL; 548040SBaban.Kenkre@Sun.COM 558040SBaban.Kenkre@Sun.COM static char *adutils_sid_ber2str(BerValue *bvalues); 568040SBaban.Kenkre@Sun.COM static void adutils_lookup_batch_unlock(adutils_query_state_t **state); 578040SBaban.Kenkre@Sun.COM static void delete_ds(adutils_ad_t *ad, const char *host, int port); 588040SBaban.Kenkre@Sun.COM 598040SBaban.Kenkre@Sun.COM typedef struct binary_attrs { 608040SBaban.Kenkre@Sun.COM const char *name; 618040SBaban.Kenkre@Sun.COM char *(*ber2str)(BerValue *bvalues); 628040SBaban.Kenkre@Sun.COM } binary_attrs_t; 638040SBaban.Kenkre@Sun.COM 648040SBaban.Kenkre@Sun.COM static binary_attrs_t binattrs[] = { 658040SBaban.Kenkre@Sun.COM {"objectSID", adutils_sid_ber2str}, 668040SBaban.Kenkre@Sun.COM {NULL, NULL} 678040SBaban.Kenkre@Sun.COM }; 688040SBaban.Kenkre@Sun.COM 69*8361SJulian.Pullen@Sun.COM 708040SBaban.Kenkre@Sun.COM void 718040SBaban.Kenkre@Sun.COM adutils_set_log(int pri, bool_t syslog, bool_t degraded) 728040SBaban.Kenkre@Sun.COM { 738040SBaban.Kenkre@Sun.COM idmap_log_stderr(pri); 748040SBaban.Kenkre@Sun.COM idmap_log_syslog(syslog); 758040SBaban.Kenkre@Sun.COM idmap_log_degraded(degraded); 768040SBaban.Kenkre@Sun.COM } 778040SBaban.Kenkre@Sun.COM 78*8361SJulian.Pullen@Sun.COM 798040SBaban.Kenkre@Sun.COM /* 808040SBaban.Kenkre@Sun.COM * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com" 818040SBaban.Kenkre@Sun.COM */ 828040SBaban.Kenkre@Sun.COM static 838040SBaban.Kenkre@Sun.COM char * 848040SBaban.Kenkre@Sun.COM adutils_dns2dn(const char *dns) 858040SBaban.Kenkre@Sun.COM { 868040SBaban.Kenkre@Sun.COM int nameparts; 878040SBaban.Kenkre@Sun.COM return (ldap_dns_to_dn((char *)dns, &nameparts)); 888040SBaban.Kenkre@Sun.COM } 898040SBaban.Kenkre@Sun.COM 90*8361SJulian.Pullen@Sun.COM 918040SBaban.Kenkre@Sun.COM /* 928040SBaban.Kenkre@Sun.COM * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other 938040SBaban.Kenkre@Sun.COM * attributes (CN, etc...). 948040SBaban.Kenkre@Sun.COM */ 958040SBaban.Kenkre@Sun.COM char * 968040SBaban.Kenkre@Sun.COM adutils_dn2dns(const char *dn) 978040SBaban.Kenkre@Sun.COM { 988040SBaban.Kenkre@Sun.COM char **rdns = NULL; 998040SBaban.Kenkre@Sun.COM char **attrs = NULL; 1008040SBaban.Kenkre@Sun.COM char **labels = NULL; 1018040SBaban.Kenkre@Sun.COM char *dns = NULL; 1028040SBaban.Kenkre@Sun.COM char **rdn, **attr, **label; 1038040SBaban.Kenkre@Sun.COM int maxlabels = 5; 1048040SBaban.Kenkre@Sun.COM int nlabels = 0; 1058040SBaban.Kenkre@Sun.COM int dnslen; 1068040SBaban.Kenkre@Sun.COM 1078040SBaban.Kenkre@Sun.COM /* 1088040SBaban.Kenkre@Sun.COM * There is no reverse of ldap_dns_to_dn() in our libldap, so we 1098040SBaban.Kenkre@Sun.COM * have to do the hard work here for now. 1108040SBaban.Kenkre@Sun.COM */ 1118040SBaban.Kenkre@Sun.COM 1128040SBaban.Kenkre@Sun.COM /* 1138040SBaban.Kenkre@Sun.COM * This code is much too liberal: it looks for "dc" attributes 1148040SBaban.Kenkre@Sun.COM * in all RDNs of the DN. In theory this could cause problems 1158040SBaban.Kenkre@Sun.COM * if people were to use "dc" in nodes other than the root of 1168040SBaban.Kenkre@Sun.COM * the tree, but in practice noone, least of all Active 1178040SBaban.Kenkre@Sun.COM * Directory, does that. 1188040SBaban.Kenkre@Sun.COM * 1198040SBaban.Kenkre@Sun.COM * On the other hand, this code is much too conservative: it 1208040SBaban.Kenkre@Sun.COM * does not make assumptions about ldap_explode_dn(), and _that_ 1218040SBaban.Kenkre@Sun.COM * is the true for looking at every attr of every RDN. 1228040SBaban.Kenkre@Sun.COM * 1238040SBaban.Kenkre@Sun.COM * Since we only ever look at dc and those must be DNS labels, 1248040SBaban.Kenkre@Sun.COM * at least until we get around to supporting IDN here we 1258040SBaban.Kenkre@Sun.COM * shouldn't see escaped labels from AD nor from libldap, though 1268040SBaban.Kenkre@Sun.COM * the spec (RFC2253) does allow libldap to escape things that 1278040SBaban.Kenkre@Sun.COM * don't need escaping -- if that should ever happen then 1288040SBaban.Kenkre@Sun.COM * libldap will need a spanking, and we can take care of that. 1298040SBaban.Kenkre@Sun.COM */ 1308040SBaban.Kenkre@Sun.COM 1318040SBaban.Kenkre@Sun.COM /* Explode a DN into RDNs */ 1328040SBaban.Kenkre@Sun.COM if ((rdns = ldap_explode_dn(dn, 0)) == NULL) 1338040SBaban.Kenkre@Sun.COM return (NULL); 1348040SBaban.Kenkre@Sun.COM 1358040SBaban.Kenkre@Sun.COM labels = calloc(maxlabels + 1, sizeof (char *)); 1368040SBaban.Kenkre@Sun.COM label = labels; 1378040SBaban.Kenkre@Sun.COM 1388040SBaban.Kenkre@Sun.COM for (rdn = rdns; *rdn != NULL; rdn++) { 1398040SBaban.Kenkre@Sun.COM if (attrs != NULL) 1408040SBaban.Kenkre@Sun.COM ldap_value_free(attrs); 1418040SBaban.Kenkre@Sun.COM 1428040SBaban.Kenkre@Sun.COM /* Explode each RDN, look for DC attr, save val as DNS label */ 1438040SBaban.Kenkre@Sun.COM if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) 1448040SBaban.Kenkre@Sun.COM goto done; 1458040SBaban.Kenkre@Sun.COM 1468040SBaban.Kenkre@Sun.COM for (attr = attrs; *attr != NULL; attr++) { 1478040SBaban.Kenkre@Sun.COM if (strncasecmp(*attr, "dc=", 3) != 0) 1488040SBaban.Kenkre@Sun.COM continue; 1498040SBaban.Kenkre@Sun.COM 1508040SBaban.Kenkre@Sun.COM /* Found a DNS label */ 1518040SBaban.Kenkre@Sun.COM labels[nlabels++] = strdup((*attr) + 3); 1528040SBaban.Kenkre@Sun.COM 1538040SBaban.Kenkre@Sun.COM if (nlabels == maxlabels) { 1548040SBaban.Kenkre@Sun.COM char **tmp; 1558040SBaban.Kenkre@Sun.COM tmp = realloc(labels, 1568040SBaban.Kenkre@Sun.COM sizeof (char *) * (maxlabels + 1)); 1578040SBaban.Kenkre@Sun.COM 1588040SBaban.Kenkre@Sun.COM if (tmp == NULL) 1598040SBaban.Kenkre@Sun.COM goto done; 1608040SBaban.Kenkre@Sun.COM 1618040SBaban.Kenkre@Sun.COM labels = tmp; 1628040SBaban.Kenkre@Sun.COM labels[nlabels] = NULL; 1638040SBaban.Kenkre@Sun.COM } 1648040SBaban.Kenkre@Sun.COM 1658040SBaban.Kenkre@Sun.COM /* There should be just one DC= attr per-RDN */ 1668040SBaban.Kenkre@Sun.COM break; 1678040SBaban.Kenkre@Sun.COM } 1688040SBaban.Kenkre@Sun.COM } 1698040SBaban.Kenkre@Sun.COM 1708040SBaban.Kenkre@Sun.COM /* 1718040SBaban.Kenkre@Sun.COM * Got all the labels, now join with '.' 1728040SBaban.Kenkre@Sun.COM * 1738040SBaban.Kenkre@Sun.COM * We need room for nlabels - 1 periods ('.'), one nul 1748040SBaban.Kenkre@Sun.COM * terminator, and the strlen() of each label. 1758040SBaban.Kenkre@Sun.COM */ 1768040SBaban.Kenkre@Sun.COM dnslen = nlabels; 1778040SBaban.Kenkre@Sun.COM for (label = labels; *label != NULL; label++) 1788040SBaban.Kenkre@Sun.COM dnslen += strlen(*label); 1798040SBaban.Kenkre@Sun.COM 1808040SBaban.Kenkre@Sun.COM if ((dns = malloc(dnslen)) == NULL) 1818040SBaban.Kenkre@Sun.COM goto done; 1828040SBaban.Kenkre@Sun.COM 1838040SBaban.Kenkre@Sun.COM *dns = '\0'; 1848040SBaban.Kenkre@Sun.COM 1858040SBaban.Kenkre@Sun.COM for (label = labels; *label != NULL; label++) { 1868040SBaban.Kenkre@Sun.COM (void) strlcat(dns, *label, dnslen); 1878040SBaban.Kenkre@Sun.COM /* 1888040SBaban.Kenkre@Sun.COM * NOTE: the last '.' won't be appended -- there's no room 1898040SBaban.Kenkre@Sun.COM * for it! 1908040SBaban.Kenkre@Sun.COM */ 1918040SBaban.Kenkre@Sun.COM (void) strlcat(dns, ".", dnslen); 1928040SBaban.Kenkre@Sun.COM } 1938040SBaban.Kenkre@Sun.COM 1948040SBaban.Kenkre@Sun.COM done: 1958040SBaban.Kenkre@Sun.COM if (labels != NULL) { 1968040SBaban.Kenkre@Sun.COM for (label = labels; *label != NULL; label++) 1978040SBaban.Kenkre@Sun.COM free(*label); 1988040SBaban.Kenkre@Sun.COM free(labels); 1998040SBaban.Kenkre@Sun.COM } 2008040SBaban.Kenkre@Sun.COM if (attrs != NULL) 2018040SBaban.Kenkre@Sun.COM ldap_value_free(attrs); 2028040SBaban.Kenkre@Sun.COM if (rdns != NULL) 2038040SBaban.Kenkre@Sun.COM ldap_value_free(rdns); 2048040SBaban.Kenkre@Sun.COM 2058040SBaban.Kenkre@Sun.COM return (dns); 2068040SBaban.Kenkre@Sun.COM } 2078040SBaban.Kenkre@Sun.COM 2088040SBaban.Kenkre@Sun.COM /* 2098040SBaban.Kenkre@Sun.COM * Convert a binary SID in a BerValue to a adutils_sid_t 2108040SBaban.Kenkre@Sun.COM */ 2118040SBaban.Kenkre@Sun.COM static 2128040SBaban.Kenkre@Sun.COM int 2138040SBaban.Kenkre@Sun.COM getsid(BerValue *bval, adutils_sid_t *sidp) 2148040SBaban.Kenkre@Sun.COM { 2158040SBaban.Kenkre@Sun.COM int i, j; 2168040SBaban.Kenkre@Sun.COM uchar_t *v; 2178040SBaban.Kenkre@Sun.COM uint32_t a; 2188040SBaban.Kenkre@Sun.COM 2198040SBaban.Kenkre@Sun.COM /* 2208040SBaban.Kenkre@Sun.COM * The binary format of a SID is as follows: 2218040SBaban.Kenkre@Sun.COM * 2228040SBaban.Kenkre@Sun.COM * byte #0: version, always 0x01 2238040SBaban.Kenkre@Sun.COM * byte #1: RID count, always <= 0x0f 2248040SBaban.Kenkre@Sun.COM * bytes #2-#7: SID authority, big-endian 48-bit unsigned int 2258040SBaban.Kenkre@Sun.COM * 2268040SBaban.Kenkre@Sun.COM * followed by RID count RIDs, each a little-endian, unsigned 2278040SBaban.Kenkre@Sun.COM * 32-bit int. 2288040SBaban.Kenkre@Sun.COM */ 2298040SBaban.Kenkre@Sun.COM /* 2308040SBaban.Kenkre@Sun.COM * Sanity checks: must have at least one RID, version must be 2318040SBaban.Kenkre@Sun.COM * 0x01, and the length must be 8 + rid count * 4 2328040SBaban.Kenkre@Sun.COM */ 2338040SBaban.Kenkre@Sun.COM if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 && 2348040SBaban.Kenkre@Sun.COM bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) { 2358040SBaban.Kenkre@Sun.COM v = (uchar_t *)bval->bv_val; 2368040SBaban.Kenkre@Sun.COM sidp->version = v[0]; 2378040SBaban.Kenkre@Sun.COM sidp->sub_authority_count = v[1]; 2388040SBaban.Kenkre@Sun.COM sidp->authority = 2398040SBaban.Kenkre@Sun.COM /* big endian -- so start from the left */ 2408040SBaban.Kenkre@Sun.COM ((u_longlong_t)v[2] << 40) | 2418040SBaban.Kenkre@Sun.COM ((u_longlong_t)v[3] << 32) | 2428040SBaban.Kenkre@Sun.COM ((u_longlong_t)v[4] << 24) | 2438040SBaban.Kenkre@Sun.COM ((u_longlong_t)v[5] << 16) | 2448040SBaban.Kenkre@Sun.COM ((u_longlong_t)v[6] << 8) | 2458040SBaban.Kenkre@Sun.COM (u_longlong_t)v[7]; 2468040SBaban.Kenkre@Sun.COM for (i = 0; i < sidp->sub_authority_count; i++) { 2478040SBaban.Kenkre@Sun.COM j = 8 + (i * 4); 2488040SBaban.Kenkre@Sun.COM /* little endian -- so start from the right */ 2498040SBaban.Kenkre@Sun.COM a = (v[j + 3] << 24) | (v[j + 2] << 16) | 2508040SBaban.Kenkre@Sun.COM (v[j + 1] << 8) | (v[j]); 2518040SBaban.Kenkre@Sun.COM sidp->sub_authorities[i] = a; 2528040SBaban.Kenkre@Sun.COM } 2538040SBaban.Kenkre@Sun.COM return (0); 2548040SBaban.Kenkre@Sun.COM } 2558040SBaban.Kenkre@Sun.COM return (-1); 2568040SBaban.Kenkre@Sun.COM } 2578040SBaban.Kenkre@Sun.COM 2588040SBaban.Kenkre@Sun.COM /* 2598040SBaban.Kenkre@Sun.COM * Convert a adutils_sid_t to S-1-... 2608040SBaban.Kenkre@Sun.COM */ 2618040SBaban.Kenkre@Sun.COM static 2628040SBaban.Kenkre@Sun.COM char * 2638040SBaban.Kenkre@Sun.COM sid2txt(adutils_sid_t *sidp) 2648040SBaban.Kenkre@Sun.COM { 2658040SBaban.Kenkre@Sun.COM int rlen, i, len; 2668040SBaban.Kenkre@Sun.COM char *str, *cp; 2678040SBaban.Kenkre@Sun.COM 2688040SBaban.Kenkre@Sun.COM if (sidp->version != 1) 2698040SBaban.Kenkre@Sun.COM return (NULL); 2708040SBaban.Kenkre@Sun.COM 2718040SBaban.Kenkre@Sun.COM len = sizeof ("S-1-") - 1; 2728040SBaban.Kenkre@Sun.COM 2738040SBaban.Kenkre@Sun.COM /* 2748040SBaban.Kenkre@Sun.COM * We could optimize like so, but, why? 2758040SBaban.Kenkre@Sun.COM * if (sidp->authority < 10) 2768040SBaban.Kenkre@Sun.COM * len += 2; 2778040SBaban.Kenkre@Sun.COM * else if (sidp->authority < 100) 2788040SBaban.Kenkre@Sun.COM * len += 3; 2798040SBaban.Kenkre@Sun.COM * else 2808040SBaban.Kenkre@Sun.COM * len += snprintf(NULL, 0"%llu", sidp->authority); 2818040SBaban.Kenkre@Sun.COM */ 2828040SBaban.Kenkre@Sun.COM len += snprintf(NULL, 0, "%llu", sidp->authority); 2838040SBaban.Kenkre@Sun.COM 2848040SBaban.Kenkre@Sun.COM /* Max length of a uint32_t printed out in ASCII is 10 bytes */ 2858040SBaban.Kenkre@Sun.COM len += 1 + (sidp->sub_authority_count + 1) * 10; 2868040SBaban.Kenkre@Sun.COM 2878040SBaban.Kenkre@Sun.COM if ((cp = str = malloc(len)) == NULL) 2888040SBaban.Kenkre@Sun.COM return (NULL); 2898040SBaban.Kenkre@Sun.COM 2908040SBaban.Kenkre@Sun.COM rlen = snprintf(str, len, "S-1-%llu", sidp->authority); 2918040SBaban.Kenkre@Sun.COM 2928040SBaban.Kenkre@Sun.COM cp += rlen; 2938040SBaban.Kenkre@Sun.COM len -= rlen; 2948040SBaban.Kenkre@Sun.COM 2958040SBaban.Kenkre@Sun.COM for (i = 0; i < sidp->sub_authority_count; i++) { 2968040SBaban.Kenkre@Sun.COM assert(len > 0); 2978040SBaban.Kenkre@Sun.COM rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]); 2988040SBaban.Kenkre@Sun.COM cp += rlen; 2998040SBaban.Kenkre@Sun.COM len -= rlen; 3008040SBaban.Kenkre@Sun.COM assert(len >= 0); 3018040SBaban.Kenkre@Sun.COM } 3028040SBaban.Kenkre@Sun.COM 3038040SBaban.Kenkre@Sun.COM return (str); 3048040SBaban.Kenkre@Sun.COM } 3058040SBaban.Kenkre@Sun.COM 3068040SBaban.Kenkre@Sun.COM /* 3078040SBaban.Kenkre@Sun.COM * Convert a adutils_sid_t to on-the-wire encoding 3088040SBaban.Kenkre@Sun.COM */ 3098040SBaban.Kenkre@Sun.COM static 3108040SBaban.Kenkre@Sun.COM int 3118040SBaban.Kenkre@Sun.COM sid2binsid(adutils_sid_t *sid, uchar_t *binsid, int binsidlen) 3128040SBaban.Kenkre@Sun.COM { 3138040SBaban.Kenkre@Sun.COM uchar_t *p; 3148040SBaban.Kenkre@Sun.COM int i; 3158040SBaban.Kenkre@Sun.COM uint64_t a; 3168040SBaban.Kenkre@Sun.COM uint32_t r; 3178040SBaban.Kenkre@Sun.COM 3188040SBaban.Kenkre@Sun.COM if (sid->version != 1 || 3198040SBaban.Kenkre@Sun.COM binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4)) 3208040SBaban.Kenkre@Sun.COM return (-1); 3218040SBaban.Kenkre@Sun.COM 3228040SBaban.Kenkre@Sun.COM p = binsid; 3238040SBaban.Kenkre@Sun.COM *p++ = 0x01; /* version */ 3248040SBaban.Kenkre@Sun.COM /* sub authority count */ 3258040SBaban.Kenkre@Sun.COM *p++ = sid->sub_authority_count; 3268040SBaban.Kenkre@Sun.COM /* Authority */ 3278040SBaban.Kenkre@Sun.COM a = sid->authority; 3288040SBaban.Kenkre@Sun.COM /* big-endian -- start from left */ 3298040SBaban.Kenkre@Sun.COM *p++ = (a >> 40) & 0xFF; 3308040SBaban.Kenkre@Sun.COM *p++ = (a >> 32) & 0xFF; 3318040SBaban.Kenkre@Sun.COM *p++ = (a >> 24) & 0xFF; 3328040SBaban.Kenkre@Sun.COM *p++ = (a >> 16) & 0xFF; 3338040SBaban.Kenkre@Sun.COM *p++ = (a >> 8) & 0xFF; 3348040SBaban.Kenkre@Sun.COM *p++ = a & 0xFF; 3358040SBaban.Kenkre@Sun.COM 3368040SBaban.Kenkre@Sun.COM /* sub-authorities */ 3378040SBaban.Kenkre@Sun.COM for (i = 0; i < sid->sub_authority_count; i++) { 3388040SBaban.Kenkre@Sun.COM r = sid->sub_authorities[i]; 3398040SBaban.Kenkre@Sun.COM /* little-endian -- start from right */ 3408040SBaban.Kenkre@Sun.COM *p++ = (r & 0x000000FF); 3418040SBaban.Kenkre@Sun.COM *p++ = (r & 0x0000FF00) >> 8; 3428040SBaban.Kenkre@Sun.COM *p++ = (r & 0x00FF0000) >> 16; 3438040SBaban.Kenkre@Sun.COM *p++ = (r & 0xFF000000) >> 24; 3448040SBaban.Kenkre@Sun.COM } 3458040SBaban.Kenkre@Sun.COM 3468040SBaban.Kenkre@Sun.COM return (0); 3478040SBaban.Kenkre@Sun.COM } 3488040SBaban.Kenkre@Sun.COM 3498040SBaban.Kenkre@Sun.COM /* 3508040SBaban.Kenkre@Sun.COM * Convert a stringified SID (S-1-...) into a hex-encoded version of the 3518040SBaban.Kenkre@Sun.COM * on-the-wire encoding, but with each pair of hex digits pre-pended 3528040SBaban.Kenkre@Sun.COM * with a '\', so we can pass this to libldap. 3538040SBaban.Kenkre@Sun.COM */ 3548040SBaban.Kenkre@Sun.COM int 3558040SBaban.Kenkre@Sun.COM adutils_txtsid2hexbinsid(const char *txt, const uint32_t *rid, 3568040SBaban.Kenkre@Sun.COM char *hexbinsid, int hexbinsidlen) 3578040SBaban.Kenkre@Sun.COM { 3588040SBaban.Kenkre@Sun.COM adutils_sid_t sid = { 0 }; 3598040SBaban.Kenkre@Sun.COM int i, j; 3608040SBaban.Kenkre@Sun.COM const char *cp; 3618040SBaban.Kenkre@Sun.COM char *ecp; 3628040SBaban.Kenkre@Sun.COM u_longlong_t a; 3638040SBaban.Kenkre@Sun.COM unsigned long r; 3648040SBaban.Kenkre@Sun.COM uchar_t *binsid, b, hb; 3658040SBaban.Kenkre@Sun.COM 3668040SBaban.Kenkre@Sun.COM /* Only version 1 SIDs please */ 3678040SBaban.Kenkre@Sun.COM if (strncmp(txt, "S-1-", strlen("S-1-")) != 0) 3688040SBaban.Kenkre@Sun.COM return (-1); 3698040SBaban.Kenkre@Sun.COM 3708040SBaban.Kenkre@Sun.COM if (strlen(txt) < (strlen("S-1-") + 1)) 3718040SBaban.Kenkre@Sun.COM return (-1); 3728040SBaban.Kenkre@Sun.COM 3738040SBaban.Kenkre@Sun.COM /* count '-'s */ 3748040SBaban.Kenkre@Sun.COM for (j = 0, cp = strchr(txt, '-'); 3758040SBaban.Kenkre@Sun.COM cp != NULL && *cp != '\0'; 3768040SBaban.Kenkre@Sun.COM j++, cp = strchr(cp + 1, '-')) { 3778040SBaban.Kenkre@Sun.COM /* can't end on a '-' */ 3788040SBaban.Kenkre@Sun.COM if (*(cp + 1) == '\0') 3798040SBaban.Kenkre@Sun.COM return (-1); 3808040SBaban.Kenkre@Sun.COM } 3818040SBaban.Kenkre@Sun.COM 3828040SBaban.Kenkre@Sun.COM /* Adjust count for version and authority */ 3838040SBaban.Kenkre@Sun.COM j -= 2; 3848040SBaban.Kenkre@Sun.COM 3858040SBaban.Kenkre@Sun.COM /* we know the version number and RID count */ 3868040SBaban.Kenkre@Sun.COM sid.version = 1; 3878040SBaban.Kenkre@Sun.COM sid.sub_authority_count = (rid != NULL) ? j + 1 : j; 3888040SBaban.Kenkre@Sun.COM 3898040SBaban.Kenkre@Sun.COM /* must have at least one RID, but not too many */ 3908040SBaban.Kenkre@Sun.COM if (sid.sub_authority_count < 1 || 3918040SBaban.Kenkre@Sun.COM sid.sub_authority_count > ADUTILS_SID_MAX_SUB_AUTHORITIES) 3928040SBaban.Kenkre@Sun.COM return (-1); 3938040SBaban.Kenkre@Sun.COM 3948040SBaban.Kenkre@Sun.COM /* check that we only have digits and '-' */ 3958040SBaban.Kenkre@Sun.COM if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1)) 3968040SBaban.Kenkre@Sun.COM return (-1); 3978040SBaban.Kenkre@Sun.COM 3988040SBaban.Kenkre@Sun.COM cp = txt + strlen("S-1-"); 3998040SBaban.Kenkre@Sun.COM 4008040SBaban.Kenkre@Sun.COM /* 64-bit safe parsing of unsigned 48-bit authority value */ 4018040SBaban.Kenkre@Sun.COM errno = 0; 4028040SBaban.Kenkre@Sun.COM a = strtoull(cp, &ecp, 10); 4038040SBaban.Kenkre@Sun.COM 4048040SBaban.Kenkre@Sun.COM /* errors parsing the authority or too many bits */ 4058040SBaban.Kenkre@Sun.COM if (cp == ecp || (a == 0 && errno == EINVAL) || 4068040SBaban.Kenkre@Sun.COM (a == ULLONG_MAX && errno == ERANGE) || 4078040SBaban.Kenkre@Sun.COM (a & 0x0000ffffffffffffULL) != a) 4088040SBaban.Kenkre@Sun.COM return (-1); 4098040SBaban.Kenkre@Sun.COM 4108040SBaban.Kenkre@Sun.COM cp = ecp; 4118040SBaban.Kenkre@Sun.COM 4128040SBaban.Kenkre@Sun.COM sid.authority = (uint64_t)a; 4138040SBaban.Kenkre@Sun.COM 4148040SBaban.Kenkre@Sun.COM for (i = 0; i < j; i++) { 4158040SBaban.Kenkre@Sun.COM if (*cp++ != '-') 4168040SBaban.Kenkre@Sun.COM return (-1); 4178040SBaban.Kenkre@Sun.COM /* 64-bit safe parsing of unsigned 32-bit RID */ 4188040SBaban.Kenkre@Sun.COM errno = 0; 4198040SBaban.Kenkre@Sun.COM r = strtoul(cp, &ecp, 10); 4208040SBaban.Kenkre@Sun.COM /* errors parsing the RID or too many bits */ 4218040SBaban.Kenkre@Sun.COM if (cp == ecp || (r == 0 && errno == EINVAL) || 4228040SBaban.Kenkre@Sun.COM (r == ULONG_MAX && errno == ERANGE) || 4238040SBaban.Kenkre@Sun.COM (r & 0xffffffffUL) != r) 4248040SBaban.Kenkre@Sun.COM return (-1); 4258040SBaban.Kenkre@Sun.COM sid.sub_authorities[i] = (uint32_t)r; 4268040SBaban.Kenkre@Sun.COM cp = ecp; 4278040SBaban.Kenkre@Sun.COM } 4288040SBaban.Kenkre@Sun.COM 4298040SBaban.Kenkre@Sun.COM /* check that all of the string SID has been consumed */ 4308040SBaban.Kenkre@Sun.COM if (*cp != '\0') 4318040SBaban.Kenkre@Sun.COM return (-1); 4328040SBaban.Kenkre@Sun.COM 4338040SBaban.Kenkre@Sun.COM if (rid != NULL) 4348040SBaban.Kenkre@Sun.COM sid.sub_authorities[j] = *rid; 4358040SBaban.Kenkre@Sun.COM 4368040SBaban.Kenkre@Sun.COM j = 1 + 1 + 6 + sid.sub_authority_count * 4; 4378040SBaban.Kenkre@Sun.COM 4388040SBaban.Kenkre@Sun.COM if (hexbinsidlen < (j * 3)) 4398040SBaban.Kenkre@Sun.COM return (-2); 4408040SBaban.Kenkre@Sun.COM 4418040SBaban.Kenkre@Sun.COM /* binary encode the SID */ 4428040SBaban.Kenkre@Sun.COM binsid = (uchar_t *)alloca(j); 4438040SBaban.Kenkre@Sun.COM (void) sid2binsid(&sid, binsid, j); 4448040SBaban.Kenkre@Sun.COM 4458040SBaban.Kenkre@Sun.COM /* hex encode, with a backslash before each byte */ 4468040SBaban.Kenkre@Sun.COM for (ecp = hexbinsid, i = 0; i < j; i++) { 4478040SBaban.Kenkre@Sun.COM b = binsid[i]; 4488040SBaban.Kenkre@Sun.COM *ecp++ = '\\'; 4498040SBaban.Kenkre@Sun.COM hb = (b >> 4) & 0xF; 4508040SBaban.Kenkre@Sun.COM *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 4518040SBaban.Kenkre@Sun.COM hb = b & 0xF; 4528040SBaban.Kenkre@Sun.COM *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 4538040SBaban.Kenkre@Sun.COM } 4548040SBaban.Kenkre@Sun.COM *ecp = '\0'; 4558040SBaban.Kenkre@Sun.COM 4568040SBaban.Kenkre@Sun.COM return (0); 4578040SBaban.Kenkre@Sun.COM } 4588040SBaban.Kenkre@Sun.COM 4598040SBaban.Kenkre@Sun.COM static 4608040SBaban.Kenkre@Sun.COM char * 4618040SBaban.Kenkre@Sun.COM convert_bval2sid(BerValue *bval, uint32_t *rid) 4628040SBaban.Kenkre@Sun.COM { 4638040SBaban.Kenkre@Sun.COM adutils_sid_t sid; 4648040SBaban.Kenkre@Sun.COM 4658040SBaban.Kenkre@Sun.COM if (getsid(bval, &sid) < 0) 4668040SBaban.Kenkre@Sun.COM return (NULL); 4678040SBaban.Kenkre@Sun.COM 4688040SBaban.Kenkre@Sun.COM /* 4698040SBaban.Kenkre@Sun.COM * If desired and if the SID is what should be a domain/computer 4708040SBaban.Kenkre@Sun.COM * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then 4718040SBaban.Kenkre@Sun.COM * save the last RID and truncate the SID 4728040SBaban.Kenkre@Sun.COM */ 4738040SBaban.Kenkre@Sun.COM if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5) 4748040SBaban.Kenkre@Sun.COM *rid = sid.sub_authorities[--sid.sub_authority_count]; 4758040SBaban.Kenkre@Sun.COM return (sid2txt(&sid)); 4768040SBaban.Kenkre@Sun.COM } 4778040SBaban.Kenkre@Sun.COM 4788040SBaban.Kenkre@Sun.COM 4798040SBaban.Kenkre@Sun.COM /* 4808040SBaban.Kenkre@Sun.COM * Return a NUL-terminated stringified SID from the value of an 4818040SBaban.Kenkre@Sun.COM * objectSid attribute and put the last RID in *rid. 4828040SBaban.Kenkre@Sun.COM */ 4838040SBaban.Kenkre@Sun.COM char * 4848040SBaban.Kenkre@Sun.COM adutils_bv_objsid2sidstr(BerValue *bval, uint32_t *rid) 4858040SBaban.Kenkre@Sun.COM { 4868040SBaban.Kenkre@Sun.COM char *sid; 4878040SBaban.Kenkre@Sun.COM 4888040SBaban.Kenkre@Sun.COM if (bval == NULL) 4898040SBaban.Kenkre@Sun.COM return (NULL); 4908040SBaban.Kenkre@Sun.COM /* objectSid is single valued */ 4918040SBaban.Kenkre@Sun.COM if ((sid = convert_bval2sid(bval, rid)) == NULL) 4928040SBaban.Kenkre@Sun.COM return (NULL); 4938040SBaban.Kenkre@Sun.COM return (sid); 4948040SBaban.Kenkre@Sun.COM } 4958040SBaban.Kenkre@Sun.COM 4968040SBaban.Kenkre@Sun.COM static 4978040SBaban.Kenkre@Sun.COM char * 4988040SBaban.Kenkre@Sun.COM adutils_sid_ber2str(BerValue *bval) 4998040SBaban.Kenkre@Sun.COM { 5008040SBaban.Kenkre@Sun.COM return (adutils_bv_objsid2sidstr(bval, NULL)); 5018040SBaban.Kenkre@Sun.COM } 5028040SBaban.Kenkre@Sun.COM 5038040SBaban.Kenkre@Sun.COM 5048040SBaban.Kenkre@Sun.COM /* Return a NUL-terminated string from the Ber value */ 5058040SBaban.Kenkre@Sun.COM char * 5068040SBaban.Kenkre@Sun.COM adutils_bv_name2str(BerValue *bval) 5078040SBaban.Kenkre@Sun.COM { 5088040SBaban.Kenkre@Sun.COM char *s; 5098040SBaban.Kenkre@Sun.COM 5108040SBaban.Kenkre@Sun.COM if (bval == NULL || bval->bv_val == NULL) 5118040SBaban.Kenkre@Sun.COM return (NULL); 5128040SBaban.Kenkre@Sun.COM if ((s = malloc(bval->bv_len + 1)) == NULL) 5138040SBaban.Kenkre@Sun.COM return (NULL); 5148040SBaban.Kenkre@Sun.COM (void) snprintf(s, bval->bv_len + 1, "%.*s", bval->bv_len, 5158040SBaban.Kenkre@Sun.COM bval->bv_val); 5168040SBaban.Kenkre@Sun.COM return (s); 5178040SBaban.Kenkre@Sun.COM } 5188040SBaban.Kenkre@Sun.COM 5198040SBaban.Kenkre@Sun.COM /*ARGSUSED*/ 5208040SBaban.Kenkre@Sun.COM static 5218040SBaban.Kenkre@Sun.COM int 5228040SBaban.Kenkre@Sun.COM saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) 5238040SBaban.Kenkre@Sun.COM { 5248040SBaban.Kenkre@Sun.COM sasl_interact_t *interact; 5258040SBaban.Kenkre@Sun.COM 5268040SBaban.Kenkre@Sun.COM if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE) 5278040SBaban.Kenkre@Sun.COM return (LDAP_PARAM_ERROR); 5288040SBaban.Kenkre@Sun.COM 5298040SBaban.Kenkre@Sun.COM /* There should be no extra arguemnts for SASL/GSSAPI authentication */ 5308040SBaban.Kenkre@Sun.COM for (interact = prompts; interact->id != SASL_CB_LIST_END; 5318040SBaban.Kenkre@Sun.COM interact++) { 5328040SBaban.Kenkre@Sun.COM interact->result = NULL; 5338040SBaban.Kenkre@Sun.COM interact->len = 0; 5348040SBaban.Kenkre@Sun.COM } 5358040SBaban.Kenkre@Sun.COM return (LDAP_SUCCESS); 5368040SBaban.Kenkre@Sun.COM } 5378040SBaban.Kenkre@Sun.COM 5388040SBaban.Kenkre@Sun.COM 5398040SBaban.Kenkre@Sun.COM #define ADCONN_TIME 300 5408040SBaban.Kenkre@Sun.COM 5418040SBaban.Kenkre@Sun.COM /* 5428040SBaban.Kenkre@Sun.COM * Idle connection reaping side of connection management 5438040SBaban.Kenkre@Sun.COM */ 5448040SBaban.Kenkre@Sun.COM void 5458040SBaban.Kenkre@Sun.COM adutils_reap_idle_connections() 5468040SBaban.Kenkre@Sun.COM { 5478040SBaban.Kenkre@Sun.COM adutils_host_t *adh; 5488040SBaban.Kenkre@Sun.COM time_t now; 5498040SBaban.Kenkre@Sun.COM 5508040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&adhostlock); 5518040SBaban.Kenkre@Sun.COM now = time(NULL); 5528040SBaban.Kenkre@Sun.COM for (adh = host_head; adh != NULL; adh = adh->next) { 5538040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&adh->lock); 5548040SBaban.Kenkre@Sun.COM if (adh->ref == 0 && adh->idletime != 0 && 5558040SBaban.Kenkre@Sun.COM adh->idletime + ADCONN_TIME < now) { 5568040SBaban.Kenkre@Sun.COM if (adh->ld) { 5578040SBaban.Kenkre@Sun.COM (void) ldap_unbind(adh->ld); 5588040SBaban.Kenkre@Sun.COM adh->ld = NULL; 5598040SBaban.Kenkre@Sun.COM adh->idletime = 0; 5608040SBaban.Kenkre@Sun.COM adh->ref = 0; 5618040SBaban.Kenkre@Sun.COM } 5628040SBaban.Kenkre@Sun.COM } 5638040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 5648040SBaban.Kenkre@Sun.COM } 5658040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adhostlock); 5668040SBaban.Kenkre@Sun.COM } 5678040SBaban.Kenkre@Sun.COM 5688040SBaban.Kenkre@Sun.COM 5698040SBaban.Kenkre@Sun.COM adutils_rc 5708040SBaban.Kenkre@Sun.COM adutils_ad_alloc(adutils_ad_t **new_ad, const char *default_domain, 5718040SBaban.Kenkre@Sun.COM adutils_ad_partition_t part) 5728040SBaban.Kenkre@Sun.COM { 5738040SBaban.Kenkre@Sun.COM adutils_ad_t *ad; 5748040SBaban.Kenkre@Sun.COM 5758040SBaban.Kenkre@Sun.COM *new_ad = NULL; 5768040SBaban.Kenkre@Sun.COM 5778040SBaban.Kenkre@Sun.COM if ((default_domain == NULL || *default_domain == '\0') && 5788040SBaban.Kenkre@Sun.COM part != ADUTILS_AD_GLOBAL_CATALOG) 5798040SBaban.Kenkre@Sun.COM return (ADUTILS_ERR_DOMAIN); 5808040SBaban.Kenkre@Sun.COM if ((ad = calloc(1, sizeof (*ad))) == NULL) 5818040SBaban.Kenkre@Sun.COM return (ADUTILS_ERR_MEMORY); 5828040SBaban.Kenkre@Sun.COM ad->ref = 1; 5838040SBaban.Kenkre@Sun.COM ad->partition = part; 5848040SBaban.Kenkre@Sun.COM if (default_domain == NULL) 5858040SBaban.Kenkre@Sun.COM default_domain = ""; 5868040SBaban.Kenkre@Sun.COM if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL) 5878040SBaban.Kenkre@Sun.COM goto err; 5888040SBaban.Kenkre@Sun.COM if (pthread_mutex_init(&ad->lock, NULL) != 0) 5898040SBaban.Kenkre@Sun.COM goto err; 5908040SBaban.Kenkre@Sun.COM *new_ad = ad; 5918040SBaban.Kenkre@Sun.COM return (ADUTILS_SUCCESS); 5928040SBaban.Kenkre@Sun.COM 5938040SBaban.Kenkre@Sun.COM err: 5948040SBaban.Kenkre@Sun.COM if (ad->dflt_w2k_dom != NULL) 5958040SBaban.Kenkre@Sun.COM free(ad->dflt_w2k_dom); 5968040SBaban.Kenkre@Sun.COM free(ad); 5978040SBaban.Kenkre@Sun.COM return (ADUTILS_ERR_MEMORY); 5988040SBaban.Kenkre@Sun.COM } 5998040SBaban.Kenkre@Sun.COM 6008040SBaban.Kenkre@Sun.COM void 6018040SBaban.Kenkre@Sun.COM adutils_ad_free(adutils_ad_t **ad) 6028040SBaban.Kenkre@Sun.COM { 6038040SBaban.Kenkre@Sun.COM adutils_host_t *p; 6048040SBaban.Kenkre@Sun.COM adutils_host_t *prev; 6058040SBaban.Kenkre@Sun.COM 6068040SBaban.Kenkre@Sun.COM if (ad == NULL || *ad == NULL) 6078040SBaban.Kenkre@Sun.COM return; 6088040SBaban.Kenkre@Sun.COM 6098040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&(*ad)->lock); 6108040SBaban.Kenkre@Sun.COM 6118040SBaban.Kenkre@Sun.COM if (atomic_dec_32_nv(&(*ad)->ref) > 0) { 6128040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&(*ad)->lock); 6138040SBaban.Kenkre@Sun.COM *ad = NULL; 6148040SBaban.Kenkre@Sun.COM return; 6158040SBaban.Kenkre@Sun.COM } 6168040SBaban.Kenkre@Sun.COM 6178040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&adhostlock); 6188040SBaban.Kenkre@Sun.COM prev = NULL; 6198040SBaban.Kenkre@Sun.COM p = host_head; 6208040SBaban.Kenkre@Sun.COM while (p != NULL) { 6218040SBaban.Kenkre@Sun.COM if (p->owner != (*ad)) { 6228040SBaban.Kenkre@Sun.COM prev = p; 6238040SBaban.Kenkre@Sun.COM p = p->next; 6248040SBaban.Kenkre@Sun.COM continue; 6258040SBaban.Kenkre@Sun.COM } else { 6268040SBaban.Kenkre@Sun.COM delete_ds((*ad), p->host, p->port); 6278040SBaban.Kenkre@Sun.COM if (prev == NULL) 6288040SBaban.Kenkre@Sun.COM p = host_head; 6298040SBaban.Kenkre@Sun.COM else 6308040SBaban.Kenkre@Sun.COM p = prev->next; 6318040SBaban.Kenkre@Sun.COM } 6328040SBaban.Kenkre@Sun.COM } 6338040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adhostlock); 6348040SBaban.Kenkre@Sun.COM 6358040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&(*ad)->lock); 6368040SBaban.Kenkre@Sun.COM (void) pthread_mutex_destroy(&(*ad)->lock); 6378040SBaban.Kenkre@Sun.COM 638*8361SJulian.Pullen@Sun.COM if ((*ad)->known_domains) 639*8361SJulian.Pullen@Sun.COM free((*ad)->known_domains); 6408040SBaban.Kenkre@Sun.COM free((*ad)->dflt_w2k_dom); 6418040SBaban.Kenkre@Sun.COM free(*ad); 6428040SBaban.Kenkre@Sun.COM 6438040SBaban.Kenkre@Sun.COM *ad = NULL; 6448040SBaban.Kenkre@Sun.COM } 6458040SBaban.Kenkre@Sun.COM 6468040SBaban.Kenkre@Sun.COM static 6478040SBaban.Kenkre@Sun.COM int 6488040SBaban.Kenkre@Sun.COM open_conn(adutils_host_t *adh, int timeoutsecs) 6498040SBaban.Kenkre@Sun.COM { 6508040SBaban.Kenkre@Sun.COM int zero = 0; 6518040SBaban.Kenkre@Sun.COM int ldversion, rc; 6528040SBaban.Kenkre@Sun.COM int timeoutms = timeoutsecs * 1000; 6538040SBaban.Kenkre@Sun.COM 6548040SBaban.Kenkre@Sun.COM if (adh == NULL) 6558040SBaban.Kenkre@Sun.COM return (0); 6568040SBaban.Kenkre@Sun.COM 6578040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&adh->lock); 6588040SBaban.Kenkre@Sun.COM 6598040SBaban.Kenkre@Sun.COM if (!adh->dead && adh->ld != NULL) 6608040SBaban.Kenkre@Sun.COM /* done! */ 6618040SBaban.Kenkre@Sun.COM goto out; 6628040SBaban.Kenkre@Sun.COM 6638040SBaban.Kenkre@Sun.COM if (adh->ld != NULL) { 6648040SBaban.Kenkre@Sun.COM (void) ldap_unbind(adh->ld); 6658040SBaban.Kenkre@Sun.COM adh->ld = NULL; 6668040SBaban.Kenkre@Sun.COM } 6678040SBaban.Kenkre@Sun.COM adh->num_requests = 0; 6688040SBaban.Kenkre@Sun.COM 6698040SBaban.Kenkre@Sun.COM atomic_inc_64(&adh->generation); 6708040SBaban.Kenkre@Sun.COM 6718040SBaban.Kenkre@Sun.COM /* Open and bind an LDAP connection */ 6728040SBaban.Kenkre@Sun.COM adh->ld = ldap_init(adh->host, adh->port); 6738040SBaban.Kenkre@Sun.COM if (adh->ld == NULL) { 6748040SBaban.Kenkre@Sun.COM idmapdlog(LOG_INFO, "ldap_init() to server " 6758040SBaban.Kenkre@Sun.COM "%s port %d failed. (%s)", adh->host, 6768040SBaban.Kenkre@Sun.COM adh->port, strerror(errno)); 6778040SBaban.Kenkre@Sun.COM goto out; 6788040SBaban.Kenkre@Sun.COM } 6798040SBaban.Kenkre@Sun.COM ldversion = LDAP_VERSION3; 6808040SBaban.Kenkre@Sun.COM (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion); 6818040SBaban.Kenkre@Sun.COM (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 6828040SBaban.Kenkre@Sun.COM (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero); 6838040SBaban.Kenkre@Sun.COM (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero); 6848040SBaban.Kenkre@Sun.COM (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms); 6858040SBaban.Kenkre@Sun.COM (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 6868040SBaban.Kenkre@Sun.COM rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */, 6878040SBaban.Kenkre@Sun.COM adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback, 6888040SBaban.Kenkre@Sun.COM NULL); 6898040SBaban.Kenkre@Sun.COM 6908040SBaban.Kenkre@Sun.COM if (rc != LDAP_SUCCESS) { 6918040SBaban.Kenkre@Sun.COM (void) ldap_unbind(adh->ld); 6928040SBaban.Kenkre@Sun.COM adh->ld = NULL; 6938040SBaban.Kenkre@Sun.COM idmapdlog(LOG_INFO, "ldap_sasl_interactive_bind_s() to server " 6948040SBaban.Kenkre@Sun.COM "%s port %d failed. (%s)", adh->host, adh->port, 6958040SBaban.Kenkre@Sun.COM ldap_err2string(rc)); 6968040SBaban.Kenkre@Sun.COM } 6978040SBaban.Kenkre@Sun.COM 6988040SBaban.Kenkre@Sun.COM idmapdlog(LOG_DEBUG, "Using global catalog server %s:%d", 6998040SBaban.Kenkre@Sun.COM adh->host, adh->port); 7008040SBaban.Kenkre@Sun.COM 7018040SBaban.Kenkre@Sun.COM out: 7028040SBaban.Kenkre@Sun.COM if (adh->ld != NULL) { 7038040SBaban.Kenkre@Sun.COM atomic_inc_32(&adh->ref); 7048040SBaban.Kenkre@Sun.COM adh->idletime = time(NULL); 7058040SBaban.Kenkre@Sun.COM adh->dead = 0; 7068040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 7078040SBaban.Kenkre@Sun.COM return (1); 7088040SBaban.Kenkre@Sun.COM } 7098040SBaban.Kenkre@Sun.COM 7108040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 7118040SBaban.Kenkre@Sun.COM return (0); 7128040SBaban.Kenkre@Sun.COM } 7138040SBaban.Kenkre@Sun.COM 7148040SBaban.Kenkre@Sun.COM 7158040SBaban.Kenkre@Sun.COM /* 7168040SBaban.Kenkre@Sun.COM * Connection management: find an open connection or open one 7178040SBaban.Kenkre@Sun.COM */ 7188040SBaban.Kenkre@Sun.COM static 7198040SBaban.Kenkre@Sun.COM adutils_host_t * 7208040SBaban.Kenkre@Sun.COM get_conn(adutils_ad_t *ad) 7218040SBaban.Kenkre@Sun.COM { 7228040SBaban.Kenkre@Sun.COM adutils_host_t *adh = NULL; 7238040SBaban.Kenkre@Sun.COM int tries; 7248040SBaban.Kenkre@Sun.COM int dscount = 0; 7258040SBaban.Kenkre@Sun.COM int timeoutsecs = ADUTILS_LDAP_OPEN_TIMEOUT; 7268040SBaban.Kenkre@Sun.COM 7278040SBaban.Kenkre@Sun.COM retry: 7288040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&adhostlock); 7298040SBaban.Kenkre@Sun.COM 7308040SBaban.Kenkre@Sun.COM if (host_head == NULL) { 7318040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adhostlock); 7328040SBaban.Kenkre@Sun.COM goto out; 7338040SBaban.Kenkre@Sun.COM } 7348040SBaban.Kenkre@Sun.COM 7358040SBaban.Kenkre@Sun.COM if (dscount == 0) { 7368040SBaban.Kenkre@Sun.COM /* 7378040SBaban.Kenkre@Sun.COM * First try: count the number of DSes. 7388040SBaban.Kenkre@Sun.COM * 7398040SBaban.Kenkre@Sun.COM * Integer overflow is not an issue -- we can't have so many 7408040SBaban.Kenkre@Sun.COM * DSes because they won't fit even DNS over TCP, and SMF 7418040SBaban.Kenkre@Sun.COM * shouldn't let you set so many. 7428040SBaban.Kenkre@Sun.COM */ 7438040SBaban.Kenkre@Sun.COM for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) { 7448040SBaban.Kenkre@Sun.COM if (adh->owner == ad) 7458040SBaban.Kenkre@Sun.COM dscount++; 7468040SBaban.Kenkre@Sun.COM } 7478040SBaban.Kenkre@Sun.COM 7488040SBaban.Kenkre@Sun.COM if (dscount == 0) { 7498040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adhostlock); 7508040SBaban.Kenkre@Sun.COM goto out; 7518040SBaban.Kenkre@Sun.COM } 7528040SBaban.Kenkre@Sun.COM 7538040SBaban.Kenkre@Sun.COM tries = dscount * 3; /* three tries per-ds */ 7548040SBaban.Kenkre@Sun.COM 7558040SBaban.Kenkre@Sun.COM /* 7568040SBaban.Kenkre@Sun.COM * Begin round-robin at the next DS in the list after the last 7578040SBaban.Kenkre@Sun.COM * one that we had a connection to, else start with the first 7588040SBaban.Kenkre@Sun.COM * DS in the list. 7598040SBaban.Kenkre@Sun.COM */ 7608040SBaban.Kenkre@Sun.COM adh = ad->last_adh; 7618040SBaban.Kenkre@Sun.COM } 7628040SBaban.Kenkre@Sun.COM 7638040SBaban.Kenkre@Sun.COM /* 7648040SBaban.Kenkre@Sun.COM * Round-robin -- pick the next one on the list; if the list 7658040SBaban.Kenkre@Sun.COM * changes on us, no big deal, we'll just potentially go 7668040SBaban.Kenkre@Sun.COM * around the wrong number of times. 7678040SBaban.Kenkre@Sun.COM */ 7688040SBaban.Kenkre@Sun.COM for (;;) { 769*8361SJulian.Pullen@Sun.COM if (adh != NULL && adh->owner == ad && adh->ld != NULL && 770*8361SJulian.Pullen@Sun.COM !adh->dead) 7718040SBaban.Kenkre@Sun.COM break; 7728040SBaban.Kenkre@Sun.COM if (adh == NULL || (adh = adh->next) == NULL) 7738040SBaban.Kenkre@Sun.COM adh = host_head; 7748040SBaban.Kenkre@Sun.COM if (adh->owner == ad) 7758040SBaban.Kenkre@Sun.COM break; 7768040SBaban.Kenkre@Sun.COM } 7778040SBaban.Kenkre@Sun.COM 7788040SBaban.Kenkre@Sun.COM ad->last_adh = adh; 7798040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adhostlock); 7808040SBaban.Kenkre@Sun.COM 7818040SBaban.Kenkre@Sun.COM /* Found suitable DS, open it if not already opened */ 7828040SBaban.Kenkre@Sun.COM if (open_conn(adh, timeoutsecs)) 7838040SBaban.Kenkre@Sun.COM return (adh); 7848040SBaban.Kenkre@Sun.COM 7858040SBaban.Kenkre@Sun.COM tries--; 7868040SBaban.Kenkre@Sun.COM if ((tries % dscount) == 0) 7878040SBaban.Kenkre@Sun.COM timeoutsecs *= 2; 7888040SBaban.Kenkre@Sun.COM if (tries > 0) 7898040SBaban.Kenkre@Sun.COM goto retry; 7908040SBaban.Kenkre@Sun.COM 7918040SBaban.Kenkre@Sun.COM out: 7928040SBaban.Kenkre@Sun.COM idmapdlog(LOG_NOTICE, "Couldn't open an LDAP connection to any global " 7938040SBaban.Kenkre@Sun.COM "catalog server!"); 7948040SBaban.Kenkre@Sun.COM return (NULL); 7958040SBaban.Kenkre@Sun.COM } 7968040SBaban.Kenkre@Sun.COM 7978040SBaban.Kenkre@Sun.COM static 7988040SBaban.Kenkre@Sun.COM void 7998040SBaban.Kenkre@Sun.COM release_conn(adutils_host_t *adh) 8008040SBaban.Kenkre@Sun.COM { 8018040SBaban.Kenkre@Sun.COM int delete = 0; 8028040SBaban.Kenkre@Sun.COM 8038040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&adh->lock); 8048040SBaban.Kenkre@Sun.COM if (atomic_dec_32_nv(&adh->ref) == 0) { 8058040SBaban.Kenkre@Sun.COM if (adh->owner == NULL) 8068040SBaban.Kenkre@Sun.COM delete = 1; 8078040SBaban.Kenkre@Sun.COM adh->idletime = time(NULL); 8088040SBaban.Kenkre@Sun.COM } 8098040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 8108040SBaban.Kenkre@Sun.COM 8118040SBaban.Kenkre@Sun.COM /* Free this host if its owner no longer exists. */ 8128040SBaban.Kenkre@Sun.COM if (delete) { 8138040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&adhostlock); 8148040SBaban.Kenkre@Sun.COM delete_ds(NULL, adh->host, adh->port); 8158040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adhostlock); 8168040SBaban.Kenkre@Sun.COM } 8178040SBaban.Kenkre@Sun.COM } 8188040SBaban.Kenkre@Sun.COM 8198040SBaban.Kenkre@Sun.COM /* 8208040SBaban.Kenkre@Sun.COM * Create a adutils_host_t, populate it and add it to the list of hosts. 8218040SBaban.Kenkre@Sun.COM */ 8228040SBaban.Kenkre@Sun.COM adutils_rc 8238040SBaban.Kenkre@Sun.COM adutils_add_ds(adutils_ad_t *ad, const char *host, int port) 8248040SBaban.Kenkre@Sun.COM { 8258040SBaban.Kenkre@Sun.COM adutils_host_t *p; 8268040SBaban.Kenkre@Sun.COM adutils_host_t *new = NULL; 8278040SBaban.Kenkre@Sun.COM int ret; 8288040SBaban.Kenkre@Sun.COM adutils_rc rc; 8298040SBaban.Kenkre@Sun.COM 8308040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&adhostlock); 8318040SBaban.Kenkre@Sun.COM for (p = host_head; p != NULL; p = p->next) { 8328040SBaban.Kenkre@Sun.COM if (p->owner != ad) 8338040SBaban.Kenkre@Sun.COM continue; 8348040SBaban.Kenkre@Sun.COM 8358040SBaban.Kenkre@Sun.COM if (strcmp(host, p->host) == 0 && p->port == port) { 8368040SBaban.Kenkre@Sun.COM /* already added */ 8378040SBaban.Kenkre@Sun.COM rc = ADUTILS_SUCCESS; 8388040SBaban.Kenkre@Sun.COM goto err; 8398040SBaban.Kenkre@Sun.COM } 8408040SBaban.Kenkre@Sun.COM } 8418040SBaban.Kenkre@Sun.COM 8428040SBaban.Kenkre@Sun.COM rc = ADUTILS_ERR_MEMORY; 8438040SBaban.Kenkre@Sun.COM 8448040SBaban.Kenkre@Sun.COM /* add new entry */ 8458040SBaban.Kenkre@Sun.COM new = (adutils_host_t *)calloc(1, sizeof (*new)); 8468040SBaban.Kenkre@Sun.COM if (new == NULL) 8478040SBaban.Kenkre@Sun.COM goto err; 8488040SBaban.Kenkre@Sun.COM new->owner = ad; 8498040SBaban.Kenkre@Sun.COM new->port = port; 8508040SBaban.Kenkre@Sun.COM new->dead = 0; 8518040SBaban.Kenkre@Sun.COM new->max_requests = 80; 8528040SBaban.Kenkre@Sun.COM new->num_requests = 0; 8538040SBaban.Kenkre@Sun.COM if ((new->host = strdup(host)) == NULL) 8548040SBaban.Kenkre@Sun.COM goto err; 8558040SBaban.Kenkre@Sun.COM new->saslflags = LDAP_SASL_INTERACTIVE; 8568040SBaban.Kenkre@Sun.COM new->saslmech = "GSSAPI"; 8578040SBaban.Kenkre@Sun.COM 8588040SBaban.Kenkre@Sun.COM if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) { 8598040SBaban.Kenkre@Sun.COM free(new->host); 8608040SBaban.Kenkre@Sun.COM new->host = NULL; 8618040SBaban.Kenkre@Sun.COM errno = ret; 8628040SBaban.Kenkre@Sun.COM rc = ADUTILS_ERR_INTERNAL; 8638040SBaban.Kenkre@Sun.COM goto err; 8648040SBaban.Kenkre@Sun.COM } 8658040SBaban.Kenkre@Sun.COM 8668040SBaban.Kenkre@Sun.COM /* link in */ 8678040SBaban.Kenkre@Sun.COM rc = ADUTILS_SUCCESS; 8688040SBaban.Kenkre@Sun.COM new->next = host_head; 8698040SBaban.Kenkre@Sun.COM host_head = new; 8708040SBaban.Kenkre@Sun.COM 8718040SBaban.Kenkre@Sun.COM err: 8728040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adhostlock); 8738040SBaban.Kenkre@Sun.COM 8748040SBaban.Kenkre@Sun.COM if (rc != 0 && new != NULL) { 8758040SBaban.Kenkre@Sun.COM if (new->host != NULL) { 8768040SBaban.Kenkre@Sun.COM (void) pthread_mutex_destroy(&new->lock); 8778040SBaban.Kenkre@Sun.COM free(new->host); 8788040SBaban.Kenkre@Sun.COM } 8798040SBaban.Kenkre@Sun.COM free(new); 8808040SBaban.Kenkre@Sun.COM } 8818040SBaban.Kenkre@Sun.COM 8828040SBaban.Kenkre@Sun.COM return (rc); 8838040SBaban.Kenkre@Sun.COM } 8848040SBaban.Kenkre@Sun.COM 8858040SBaban.Kenkre@Sun.COM /* 8868040SBaban.Kenkre@Sun.COM * Free a DS configuration. 8878040SBaban.Kenkre@Sun.COM * Caller must lock the adhostlock mutex 8888040SBaban.Kenkre@Sun.COM */ 8898040SBaban.Kenkre@Sun.COM static 8908040SBaban.Kenkre@Sun.COM void 8918040SBaban.Kenkre@Sun.COM delete_ds(adutils_ad_t *ad, const char *host, int port) 8928040SBaban.Kenkre@Sun.COM { 8938040SBaban.Kenkre@Sun.COM adutils_host_t **p, *q; 8948040SBaban.Kenkre@Sun.COM 8958040SBaban.Kenkre@Sun.COM for (p = &host_head; *p != NULL; p = &((*p)->next)) { 8968040SBaban.Kenkre@Sun.COM if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 || 8978040SBaban.Kenkre@Sun.COM (*p)->port != port) 8988040SBaban.Kenkre@Sun.COM continue; 8998040SBaban.Kenkre@Sun.COM /* found */ 9008040SBaban.Kenkre@Sun.COM 9018040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&((*p)->lock)); 9028040SBaban.Kenkre@Sun.COM if ((*p)->ref > 0) { 9038040SBaban.Kenkre@Sun.COM /* 9048040SBaban.Kenkre@Sun.COM * Still in use. Set its owner to NULL so 9058040SBaban.Kenkre@Sun.COM * that it can be freed when its ref count 9068040SBaban.Kenkre@Sun.COM * becomes 0. 9078040SBaban.Kenkre@Sun.COM */ 9088040SBaban.Kenkre@Sun.COM (*p)->owner = NULL; 9098040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&((*p)->lock)); 9108040SBaban.Kenkre@Sun.COM break; 9118040SBaban.Kenkre@Sun.COM } 9128040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&((*p)->lock)); 9138040SBaban.Kenkre@Sun.COM 9148040SBaban.Kenkre@Sun.COM q = *p; 9158040SBaban.Kenkre@Sun.COM *p = (*p)->next; 9168040SBaban.Kenkre@Sun.COM 9178040SBaban.Kenkre@Sun.COM (void) pthread_mutex_destroy(&q->lock); 9188040SBaban.Kenkre@Sun.COM 9198040SBaban.Kenkre@Sun.COM if (q->ld) 9208040SBaban.Kenkre@Sun.COM (void) ldap_unbind(q->ld); 9218040SBaban.Kenkre@Sun.COM if (q->host) 9228040SBaban.Kenkre@Sun.COM free(q->host); 9238040SBaban.Kenkre@Sun.COM free(q); 9248040SBaban.Kenkre@Sun.COM break; 9258040SBaban.Kenkre@Sun.COM } 9268040SBaban.Kenkre@Sun.COM 9278040SBaban.Kenkre@Sun.COM } 928*8361SJulian.Pullen@Sun.COM /* 929*8361SJulian.Pullen@Sun.COM * Add known domain name and domain SID to AD configuration. 930*8361SJulian.Pullen@Sun.COM */ 931*8361SJulian.Pullen@Sun.COM 932*8361SJulian.Pullen@Sun.COM adutils_rc 933*8361SJulian.Pullen@Sun.COM adutils_add_domain(adutils_ad_t *ad, const char *domain, const char *sid) 934*8361SJulian.Pullen@Sun.COM { 935*8361SJulian.Pullen@Sun.COM struct known_domain *new; 936*8361SJulian.Pullen@Sun.COM int num = ad->num_known_domains; 937*8361SJulian.Pullen@Sun.COM 938*8361SJulian.Pullen@Sun.COM ad->num_known_domains++; 939*8361SJulian.Pullen@Sun.COM new = realloc(ad->known_domains, 940*8361SJulian.Pullen@Sun.COM sizeof (struct known_domain) * ad->num_known_domains); 941*8361SJulian.Pullen@Sun.COM if (new != NULL) { 942*8361SJulian.Pullen@Sun.COM ad->known_domains = new; 943*8361SJulian.Pullen@Sun.COM (void) strlcpy(ad->known_domains[num].name, domain, 944*8361SJulian.Pullen@Sun.COM sizeof (ad->known_domains[num].name)); 945*8361SJulian.Pullen@Sun.COM (void) strlcpy(ad->known_domains[num].sid, sid, 946*8361SJulian.Pullen@Sun.COM sizeof (ad->known_domains[num].sid)); 947*8361SJulian.Pullen@Sun.COM return (ADUTILS_SUCCESS); 948*8361SJulian.Pullen@Sun.COM } else { 949*8361SJulian.Pullen@Sun.COM if (ad->known_domains != NULL) { 950*8361SJulian.Pullen@Sun.COM free(ad->known_domains); 951*8361SJulian.Pullen@Sun.COM ad->known_domains = NULL; 952*8361SJulian.Pullen@Sun.COM } 953*8361SJulian.Pullen@Sun.COM ad->num_known_domains = 0; 954*8361SJulian.Pullen@Sun.COM return (ADUTILS_ERR_MEMORY); 955*8361SJulian.Pullen@Sun.COM } 956*8361SJulian.Pullen@Sun.COM } 957*8361SJulian.Pullen@Sun.COM 958*8361SJulian.Pullen@Sun.COM 959*8361SJulian.Pullen@Sun.COM /* 960*8361SJulian.Pullen@Sun.COM * Check that this AD supports this domain. 961*8361SJulian.Pullen@Sun.COM * If there are no known domains assume that the 962*8361SJulian.Pullen@Sun.COM * domain is supported by this AD. 963*8361SJulian.Pullen@Sun.COM * 964*8361SJulian.Pullen@Sun.COM * Returns 1 if this domain is supported by this AD 965*8361SJulian.Pullen@Sun.COM * else returns 0; 966*8361SJulian.Pullen@Sun.COM */ 967*8361SJulian.Pullen@Sun.COM 968*8361SJulian.Pullen@Sun.COM int 969*8361SJulian.Pullen@Sun.COM adutils_lookup_check_domain(adutils_query_state_t *qs, const char *domain) 970*8361SJulian.Pullen@Sun.COM { 971*8361SJulian.Pullen@Sun.COM adutils_ad_t *ad = qs->qadh->owner; 972*8361SJulian.Pullen@Sun.COM int i, err; 973*8361SJulian.Pullen@Sun.COM 974*8361SJulian.Pullen@Sun.COM for (i = 0; i < ad->num_known_domains; i++) { 975*8361SJulian.Pullen@Sun.COM if (u8_strcmp(domain, ad->known_domains[i].name, 0, 976*8361SJulian.Pullen@Sun.COM U8_STRCMP_CI_LOWER, U8_UNICODE_LATEST, &err) == 0 && 977*8361SJulian.Pullen@Sun.COM err == 0) 978*8361SJulian.Pullen@Sun.COM return (1); 979*8361SJulian.Pullen@Sun.COM } 980*8361SJulian.Pullen@Sun.COM 981*8361SJulian.Pullen@Sun.COM return ((i == 0) ? 1 : 0); 982*8361SJulian.Pullen@Sun.COM } 983*8361SJulian.Pullen@Sun.COM 984*8361SJulian.Pullen@Sun.COM 985*8361SJulian.Pullen@Sun.COM /* 986*8361SJulian.Pullen@Sun.COM * Check that this AD supports the SID prefix. 987*8361SJulian.Pullen@Sun.COM * The SID prefix should match the domain SID. 988*8361SJulian.Pullen@Sun.COM * If there are no known domains assume that the 989*8361SJulian.Pullen@Sun.COM * SID prefix is supported by this AD. 990*8361SJulian.Pullen@Sun.COM * 991*8361SJulian.Pullen@Sun.COM * Returns 1 if this sid prefix is supported by this AD 992*8361SJulian.Pullen@Sun.COM * else returns 0; 993*8361SJulian.Pullen@Sun.COM */ 994*8361SJulian.Pullen@Sun.COM 995*8361SJulian.Pullen@Sun.COM int 996*8361SJulian.Pullen@Sun.COM adutils_lookup_check_sid_prefix(adutils_query_state_t *qs, const char *sid) 997*8361SJulian.Pullen@Sun.COM { 998*8361SJulian.Pullen@Sun.COM adutils_ad_t *ad = qs->qadh->owner; 999*8361SJulian.Pullen@Sun.COM int i; 1000*8361SJulian.Pullen@Sun.COM 1001*8361SJulian.Pullen@Sun.COM 1002*8361SJulian.Pullen@Sun.COM for (i = 0; i < ad->num_known_domains; i++) { 1003*8361SJulian.Pullen@Sun.COM if (strcmp(sid, ad->known_domains[i].sid) == 0) 1004*8361SJulian.Pullen@Sun.COM return (1); 1005*8361SJulian.Pullen@Sun.COM } 1006*8361SJulian.Pullen@Sun.COM 1007*8361SJulian.Pullen@Sun.COM return ((i == 0) ? 1 : 0); 1008*8361SJulian.Pullen@Sun.COM } 1009*8361SJulian.Pullen@Sun.COM 10108040SBaban.Kenkre@Sun.COM 10118040SBaban.Kenkre@Sun.COM adutils_rc 10128040SBaban.Kenkre@Sun.COM adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries, 10138040SBaban.Kenkre@Sun.COM adutils_ldap_res_search_cb ldap_res_search_cb, 10148040SBaban.Kenkre@Sun.COM void *ldap_res_search_argp, 10158040SBaban.Kenkre@Sun.COM adutils_query_state_t **state) 10168040SBaban.Kenkre@Sun.COM { 10178040SBaban.Kenkre@Sun.COM adutils_query_state_t *new_state; 10188040SBaban.Kenkre@Sun.COM adutils_host_t *adh = NULL; 10198040SBaban.Kenkre@Sun.COM 10208040SBaban.Kenkre@Sun.COM if (ad == NULL) 10218040SBaban.Kenkre@Sun.COM return (ADUTILS_ERR_INTERNAL); 10228040SBaban.Kenkre@Sun.COM 10238040SBaban.Kenkre@Sun.COM *state = NULL; 10248040SBaban.Kenkre@Sun.COM adh = get_conn(ad); 10258040SBaban.Kenkre@Sun.COM if (adh == NULL) 10268040SBaban.Kenkre@Sun.COM return (ADUTILS_ERR_RETRIABLE_NET_ERR); 10278040SBaban.Kenkre@Sun.COM 10288040SBaban.Kenkre@Sun.COM new_state = calloc(1, sizeof (adutils_query_state_t) + 10298040SBaban.Kenkre@Sun.COM (nqueries - 1) * sizeof (adutils_q_t)); 10308040SBaban.Kenkre@Sun.COM if (new_state == NULL) 10318040SBaban.Kenkre@Sun.COM return (ADUTILS_ERR_MEMORY); 10328040SBaban.Kenkre@Sun.COM 10338040SBaban.Kenkre@Sun.COM /* 10348040SBaban.Kenkre@Sun.COM * Save default domain from the ad object so that we don't 10358040SBaban.Kenkre@Sun.COM * have to access the 'ad' object later. 10368040SBaban.Kenkre@Sun.COM */ 10378040SBaban.Kenkre@Sun.COM new_state->default_domain = strdup(adh->owner->dflt_w2k_dom); 10388040SBaban.Kenkre@Sun.COM if (new_state->default_domain == NULL) { 10398040SBaban.Kenkre@Sun.COM free(new_state); 10408040SBaban.Kenkre@Sun.COM return (ADUTILS_ERR_MEMORY); 10418040SBaban.Kenkre@Sun.COM } 10428040SBaban.Kenkre@Sun.COM 10438040SBaban.Kenkre@Sun.COM if (ad->partition == ADUTILS_AD_DATA) 10448040SBaban.Kenkre@Sun.COM new_state->basedn = adutils_dns2dn(new_state->default_domain); 10458040SBaban.Kenkre@Sun.COM else 10468040SBaban.Kenkre@Sun.COM new_state->basedn = strdup(""); 10478040SBaban.Kenkre@Sun.COM if (new_state->basedn == NULL) { 10488040SBaban.Kenkre@Sun.COM free(new_state->default_domain); 10498040SBaban.Kenkre@Sun.COM free(new_state); 10508040SBaban.Kenkre@Sun.COM return (ADUTILS_ERR_MEMORY); 10518040SBaban.Kenkre@Sun.COM } 10528040SBaban.Kenkre@Sun.COM 10538040SBaban.Kenkre@Sun.COM new_state->ref_cnt = 1; 10548040SBaban.Kenkre@Sun.COM new_state->qadh = adh; 1055*8361SJulian.Pullen@Sun.COM new_state->qsize = nqueries; 10568040SBaban.Kenkre@Sun.COM new_state->qadh_gen = adh->generation; 1057*8361SJulian.Pullen@Sun.COM new_state->qcount = 0; 10588040SBaban.Kenkre@Sun.COM new_state->ldap_res_search_cb = ldap_res_search_cb; 10598040SBaban.Kenkre@Sun.COM new_state->ldap_res_search_argp = ldap_res_search_argp; 10608040SBaban.Kenkre@Sun.COM (void) pthread_cond_init(&new_state->cv, NULL); 10618040SBaban.Kenkre@Sun.COM 10628040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&qstatelock); 10638040SBaban.Kenkre@Sun.COM new_state->next = qstatehead; 10648040SBaban.Kenkre@Sun.COM qstatehead = new_state; 10658040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&qstatelock); 10668040SBaban.Kenkre@Sun.COM *state = new_state; 10678040SBaban.Kenkre@Sun.COM 10688040SBaban.Kenkre@Sun.COM return (ADUTILS_SUCCESS); 10698040SBaban.Kenkre@Sun.COM } 10708040SBaban.Kenkre@Sun.COM 10718040SBaban.Kenkre@Sun.COM /* 10728040SBaban.Kenkre@Sun.COM * Find the adutils_query_state_t to which a given LDAP result msgid on a 10738040SBaban.Kenkre@Sun.COM * given connection belongs. This routine increaments the reference count 10748040SBaban.Kenkre@Sun.COM * so that the object can not be freed. adutils_lookup_batch_unlock() 10758040SBaban.Kenkre@Sun.COM * must be called to decreament the reference count. 10768040SBaban.Kenkre@Sun.COM */ 10778040SBaban.Kenkre@Sun.COM static 10788040SBaban.Kenkre@Sun.COM int 10798040SBaban.Kenkre@Sun.COM msgid2query(adutils_host_t *adh, int msgid, 10808040SBaban.Kenkre@Sun.COM adutils_query_state_t **state, int *qid) 10818040SBaban.Kenkre@Sun.COM { 10828040SBaban.Kenkre@Sun.COM adutils_query_state_t *p; 10838040SBaban.Kenkre@Sun.COM int i; 10848040SBaban.Kenkre@Sun.COM int ret; 10858040SBaban.Kenkre@Sun.COM 10868040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&qstatelock); 10878040SBaban.Kenkre@Sun.COM for (p = qstatehead; p != NULL; p = p->next) { 10888040SBaban.Kenkre@Sun.COM if (p->qadh != adh || adh->generation != p->qadh_gen) 10898040SBaban.Kenkre@Sun.COM continue; 10908040SBaban.Kenkre@Sun.COM for (i = 0; i < p->qcount; i++) { 10918040SBaban.Kenkre@Sun.COM if ((p->queries[i]).msgid == msgid) { 10928040SBaban.Kenkre@Sun.COM if (!p->qdead) { 10938040SBaban.Kenkre@Sun.COM p->ref_cnt++; 10948040SBaban.Kenkre@Sun.COM *state = p; 10958040SBaban.Kenkre@Sun.COM *qid = i; 10968040SBaban.Kenkre@Sun.COM ret = 1; 10978040SBaban.Kenkre@Sun.COM } else 10988040SBaban.Kenkre@Sun.COM ret = 0; 10998040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&qstatelock); 11008040SBaban.Kenkre@Sun.COM return (ret); 11018040SBaban.Kenkre@Sun.COM } 11028040SBaban.Kenkre@Sun.COM } 11038040SBaban.Kenkre@Sun.COM } 11048040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&qstatelock); 11058040SBaban.Kenkre@Sun.COM return (0); 11068040SBaban.Kenkre@Sun.COM } 11078040SBaban.Kenkre@Sun.COM 11088040SBaban.Kenkre@Sun.COM static 11098040SBaban.Kenkre@Sun.COM int 11108040SBaban.Kenkre@Sun.COM check_for_binary_attrs(const char *attr) 11118040SBaban.Kenkre@Sun.COM { 11128040SBaban.Kenkre@Sun.COM int i; 11138040SBaban.Kenkre@Sun.COM for (i = 0; binattrs[i].name != NULL; i++) { 11148040SBaban.Kenkre@Sun.COM if (strcasecmp(binattrs[i].name, attr) == 0) 11158040SBaban.Kenkre@Sun.COM return (i); 11168040SBaban.Kenkre@Sun.COM } 11178040SBaban.Kenkre@Sun.COM return (-1); 11188040SBaban.Kenkre@Sun.COM } 11198040SBaban.Kenkre@Sun.COM 11208040SBaban.Kenkre@Sun.COM static 11218040SBaban.Kenkre@Sun.COM void 11228040SBaban.Kenkre@Sun.COM free_entry(adutils_entry_t *entry) 11238040SBaban.Kenkre@Sun.COM { 11248040SBaban.Kenkre@Sun.COM int i, j; 11258040SBaban.Kenkre@Sun.COM adutils_attr_t *ap; 11268040SBaban.Kenkre@Sun.COM 11278040SBaban.Kenkre@Sun.COM if (entry == NULL) 11288040SBaban.Kenkre@Sun.COM return; 11298040SBaban.Kenkre@Sun.COM if (entry->attr_nvpairs == NULL) { 11308040SBaban.Kenkre@Sun.COM free(entry); 11318040SBaban.Kenkre@Sun.COM return; 11328040SBaban.Kenkre@Sun.COM } 11338040SBaban.Kenkre@Sun.COM for (i = 0; i < entry->num_nvpairs; i++) { 11348040SBaban.Kenkre@Sun.COM ap = &entry->attr_nvpairs[i]; 11358040SBaban.Kenkre@Sun.COM if (ap->attr_name == NULL) { 11368040SBaban.Kenkre@Sun.COM ldap_value_free(ap->attr_values); 11378040SBaban.Kenkre@Sun.COM continue; 11388040SBaban.Kenkre@Sun.COM } 11398040SBaban.Kenkre@Sun.COM if (check_for_binary_attrs(ap->attr_name) >= 0) { 11408040SBaban.Kenkre@Sun.COM free(ap->attr_name); 11418040SBaban.Kenkre@Sun.COM if (ap->attr_values == NULL) 11428040SBaban.Kenkre@Sun.COM continue; 11438040SBaban.Kenkre@Sun.COM for (j = 0; j < ap->num_values; j++) 11448040SBaban.Kenkre@Sun.COM free(ap->attr_values[j]); 11458040SBaban.Kenkre@Sun.COM free(ap->attr_values); 11468040SBaban.Kenkre@Sun.COM } else if (strcasecmp(ap->attr_name, "dn") == 0) { 11478040SBaban.Kenkre@Sun.COM free(ap->attr_name); 11488040SBaban.Kenkre@Sun.COM ldap_memfree(ap->attr_values[0]); 11498040SBaban.Kenkre@Sun.COM free(ap->attr_values); 11508040SBaban.Kenkre@Sun.COM } else { 11518040SBaban.Kenkre@Sun.COM free(ap->attr_name); 11528040SBaban.Kenkre@Sun.COM ldap_value_free(ap->attr_values); 11538040SBaban.Kenkre@Sun.COM } 11548040SBaban.Kenkre@Sun.COM } 11558040SBaban.Kenkre@Sun.COM free(entry->attr_nvpairs); 11568040SBaban.Kenkre@Sun.COM free(entry); 11578040SBaban.Kenkre@Sun.COM } 11588040SBaban.Kenkre@Sun.COM 11598040SBaban.Kenkre@Sun.COM void 11608040SBaban.Kenkre@Sun.COM adutils_freeresult(adutils_result_t **result) 11618040SBaban.Kenkre@Sun.COM { 11628040SBaban.Kenkre@Sun.COM adutils_entry_t *e, *next; 11638040SBaban.Kenkre@Sun.COM 11648040SBaban.Kenkre@Sun.COM if (result == NULL || *result == NULL) 11658040SBaban.Kenkre@Sun.COM return; 11668040SBaban.Kenkre@Sun.COM if ((*result)->entries == NULL) { 11678040SBaban.Kenkre@Sun.COM free(*result); 11688040SBaban.Kenkre@Sun.COM *result = NULL; 11698040SBaban.Kenkre@Sun.COM return; 11708040SBaban.Kenkre@Sun.COM } 11718040SBaban.Kenkre@Sun.COM for (e = (*result)->entries; e != NULL; e = next) { 11728040SBaban.Kenkre@Sun.COM next = e->next; 11738040SBaban.Kenkre@Sun.COM free_entry(e); 11748040SBaban.Kenkre@Sun.COM } 11758040SBaban.Kenkre@Sun.COM free(*result); 11768040SBaban.Kenkre@Sun.COM *result = NULL; 11778040SBaban.Kenkre@Sun.COM } 11788040SBaban.Kenkre@Sun.COM 11798040SBaban.Kenkre@Sun.COM const adutils_entry_t * 11808040SBaban.Kenkre@Sun.COM adutils_getfirstentry(adutils_result_t *result) 11818040SBaban.Kenkre@Sun.COM { 11828040SBaban.Kenkre@Sun.COM if (result != NULL) 11838040SBaban.Kenkre@Sun.COM return (result->entries); 11848040SBaban.Kenkre@Sun.COM return (NULL); 11858040SBaban.Kenkre@Sun.COM } 11868040SBaban.Kenkre@Sun.COM 11878040SBaban.Kenkre@Sun.COM 11888040SBaban.Kenkre@Sun.COM char ** 11898040SBaban.Kenkre@Sun.COM adutils_getattr(const adutils_entry_t *entry, const char *attrname) 11908040SBaban.Kenkre@Sun.COM { 11918040SBaban.Kenkre@Sun.COM int i; 11928040SBaban.Kenkre@Sun.COM adutils_attr_t *ap; 11938040SBaban.Kenkre@Sun.COM 11948040SBaban.Kenkre@Sun.COM if (entry == NULL || entry->attr_nvpairs == NULL) 11958040SBaban.Kenkre@Sun.COM return (NULL); 11968040SBaban.Kenkre@Sun.COM for (i = 0; i < entry->num_nvpairs; i++) { 11978040SBaban.Kenkre@Sun.COM ap = &entry->attr_nvpairs[i]; 11988040SBaban.Kenkre@Sun.COM if (ap->attr_name != NULL && 11998040SBaban.Kenkre@Sun.COM strcasecmp(ap->attr_name, attrname) == 0) 12008040SBaban.Kenkre@Sun.COM return (ap->attr_values); 12018040SBaban.Kenkre@Sun.COM } 12028040SBaban.Kenkre@Sun.COM return (NULL); 12038040SBaban.Kenkre@Sun.COM } 12048040SBaban.Kenkre@Sun.COM 12058040SBaban.Kenkre@Sun.COM 12068040SBaban.Kenkre@Sun.COM /* 12078040SBaban.Kenkre@Sun.COM * Queue LDAP result for the given query. 12088040SBaban.Kenkre@Sun.COM * 12098040SBaban.Kenkre@Sun.COM * Return values: 12108040SBaban.Kenkre@Sun.COM * 0 success 12118040SBaban.Kenkre@Sun.COM * -1 ignore result 12128040SBaban.Kenkre@Sun.COM * -2 error 12138040SBaban.Kenkre@Sun.COM */ 12148040SBaban.Kenkre@Sun.COM static 12158040SBaban.Kenkre@Sun.COM int 12168040SBaban.Kenkre@Sun.COM make_entry(adutils_q_t *q, adutils_host_t *adh, LDAPMessage *search_res, 12178040SBaban.Kenkre@Sun.COM adutils_entry_t **entry) 12188040SBaban.Kenkre@Sun.COM { 12198040SBaban.Kenkre@Sun.COM BerElement *ber = NULL; 12208040SBaban.Kenkre@Sun.COM BerValue **bvalues = NULL; 12218040SBaban.Kenkre@Sun.COM char **strvalues; 12228040SBaban.Kenkre@Sun.COM char *attr = NULL, *dn = NULL, *domain = NULL; 12238040SBaban.Kenkre@Sun.COM adutils_entry_t *ep; 12248040SBaban.Kenkre@Sun.COM adutils_attr_t *ap; 12258040SBaban.Kenkre@Sun.COM int i, j, b, err = 0, ret = -2; 12268040SBaban.Kenkre@Sun.COM 12278040SBaban.Kenkre@Sun.COM *entry = NULL; 12288040SBaban.Kenkre@Sun.COM 12298040SBaban.Kenkre@Sun.COM /* Check that this is the domain that we were looking for */ 12308040SBaban.Kenkre@Sun.COM if ((dn = ldap_get_dn(adh->ld, search_res)) == NULL) 12318040SBaban.Kenkre@Sun.COM return (-2); 12328040SBaban.Kenkre@Sun.COM if ((domain = adutils_dn2dns(dn)) == NULL) { 12338040SBaban.Kenkre@Sun.COM ldap_memfree(dn); 12348040SBaban.Kenkre@Sun.COM return (-2); 12358040SBaban.Kenkre@Sun.COM } 12368040SBaban.Kenkre@Sun.COM if (q->edomain != NULL) { 12378040SBaban.Kenkre@Sun.COM if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER, 12388040SBaban.Kenkre@Sun.COM U8_UNICODE_LATEST, &err) != 0 || err != 0) { 12398040SBaban.Kenkre@Sun.COM ldap_memfree(dn); 12408040SBaban.Kenkre@Sun.COM free(domain); 12418040SBaban.Kenkre@Sun.COM return (-1); 12428040SBaban.Kenkre@Sun.COM } 12438040SBaban.Kenkre@Sun.COM } 12448040SBaban.Kenkre@Sun.COM free(domain); 12458040SBaban.Kenkre@Sun.COM 12468040SBaban.Kenkre@Sun.COM /* Allocate memory for the entry */ 12478040SBaban.Kenkre@Sun.COM if ((ep = calloc(1, sizeof (*ep))) == NULL) 12488040SBaban.Kenkre@Sun.COM goto out; 12498040SBaban.Kenkre@Sun.COM 12508040SBaban.Kenkre@Sun.COM /* For 'dn' */ 12518040SBaban.Kenkre@Sun.COM ep->num_nvpairs = 1; 12528040SBaban.Kenkre@Sun.COM 12538040SBaban.Kenkre@Sun.COM /* Count the number of name-value pairs for this entry */ 12548040SBaban.Kenkre@Sun.COM for (attr = ldap_first_attribute(adh->ld, search_res, &ber); 12558040SBaban.Kenkre@Sun.COM attr != NULL; 12568040SBaban.Kenkre@Sun.COM attr = ldap_next_attribute(adh->ld, search_res, ber)) { 12578040SBaban.Kenkre@Sun.COM ep->num_nvpairs++; 12588040SBaban.Kenkre@Sun.COM ldap_memfree(attr); 12598040SBaban.Kenkre@Sun.COM } 12608040SBaban.Kenkre@Sun.COM ber_free(ber, 0); 12618040SBaban.Kenkre@Sun.COM ber = NULL; 12628040SBaban.Kenkre@Sun.COM 12638040SBaban.Kenkre@Sun.COM /* Allocate array for the attribute name-value pairs */ 12648040SBaban.Kenkre@Sun.COM ep->attr_nvpairs = calloc(ep->num_nvpairs, sizeof (*ep->attr_nvpairs)); 12658040SBaban.Kenkre@Sun.COM if (ep->attr_nvpairs == NULL) { 12668040SBaban.Kenkre@Sun.COM ep->num_nvpairs = 0; 12678040SBaban.Kenkre@Sun.COM goto out; 12688040SBaban.Kenkre@Sun.COM } 12698040SBaban.Kenkre@Sun.COM 12708040SBaban.Kenkre@Sun.COM /* For dn */ 12718040SBaban.Kenkre@Sun.COM ap = &ep->attr_nvpairs[0]; 12728040SBaban.Kenkre@Sun.COM if ((ap->attr_name = strdup("dn")) == NULL) 12738040SBaban.Kenkre@Sun.COM goto out; 12748040SBaban.Kenkre@Sun.COM ap->num_values = 1; 12758040SBaban.Kenkre@Sun.COM ap->attr_values = calloc(ap->num_values, sizeof (*ap->attr_values)); 12768040SBaban.Kenkre@Sun.COM if (ap->attr_values == NULL) { 12778040SBaban.Kenkre@Sun.COM ap->num_values = 0; 12788040SBaban.Kenkre@Sun.COM goto out; 12798040SBaban.Kenkre@Sun.COM } 12808040SBaban.Kenkre@Sun.COM ap->attr_values[0] = dn; 12818040SBaban.Kenkre@Sun.COM dn = NULL; 12828040SBaban.Kenkre@Sun.COM 12838040SBaban.Kenkre@Sun.COM for (attr = ldap_first_attribute(adh->ld, search_res, &ber), i = 1; 12848040SBaban.Kenkre@Sun.COM attr != NULL; 12858040SBaban.Kenkre@Sun.COM ldap_memfree(attr), i++, 12868040SBaban.Kenkre@Sun.COM attr = ldap_next_attribute(adh->ld, search_res, ber)) { 12878040SBaban.Kenkre@Sun.COM ap = &ep->attr_nvpairs[i]; 12888040SBaban.Kenkre@Sun.COM if ((ap->attr_name = strdup(attr)) == NULL) 12898040SBaban.Kenkre@Sun.COM goto out; 12908040SBaban.Kenkre@Sun.COM 12918040SBaban.Kenkre@Sun.COM if ((b = check_for_binary_attrs(attr)) >= 0) { 12928040SBaban.Kenkre@Sun.COM bvalues = 12938040SBaban.Kenkre@Sun.COM ldap_get_values_len(adh->ld, search_res, attr); 12948040SBaban.Kenkre@Sun.COM if (bvalues == NULL) 12958040SBaban.Kenkre@Sun.COM continue; 12968040SBaban.Kenkre@Sun.COM ap->num_values = ldap_count_values_len(bvalues); 12978040SBaban.Kenkre@Sun.COM if (ap->num_values == 0) { 12988040SBaban.Kenkre@Sun.COM ldap_value_free_len(bvalues); 12998040SBaban.Kenkre@Sun.COM bvalues = NULL; 13008040SBaban.Kenkre@Sun.COM continue; 13018040SBaban.Kenkre@Sun.COM } 13028040SBaban.Kenkre@Sun.COM ap->attr_values = calloc(ap->num_values, 13038040SBaban.Kenkre@Sun.COM sizeof (*ap->attr_values)); 13048040SBaban.Kenkre@Sun.COM if (ap->attr_values == NULL) { 13058040SBaban.Kenkre@Sun.COM ap->num_values = 0; 13068040SBaban.Kenkre@Sun.COM goto out; 13078040SBaban.Kenkre@Sun.COM } 13088040SBaban.Kenkre@Sun.COM for (j = 0; j < ap->num_values; j++) { 13098040SBaban.Kenkre@Sun.COM ap->attr_values[j] = 13108040SBaban.Kenkre@Sun.COM binattrs[b].ber2str(bvalues[j]); 13118040SBaban.Kenkre@Sun.COM if (ap->attr_values[j] == NULL) 13128040SBaban.Kenkre@Sun.COM goto out; 13138040SBaban.Kenkre@Sun.COM } 13148040SBaban.Kenkre@Sun.COM ldap_value_free_len(bvalues); 13158040SBaban.Kenkre@Sun.COM bvalues = NULL; 13168040SBaban.Kenkre@Sun.COM continue; 13178040SBaban.Kenkre@Sun.COM } 13188040SBaban.Kenkre@Sun.COM 13198040SBaban.Kenkre@Sun.COM strvalues = ldap_get_values(adh->ld, search_res, attr); 13208040SBaban.Kenkre@Sun.COM if (strvalues == NULL) 13218040SBaban.Kenkre@Sun.COM continue; 13228040SBaban.Kenkre@Sun.COM ap->num_values = ldap_count_values(strvalues); 13238040SBaban.Kenkre@Sun.COM if (ap->num_values == 0) { 13248040SBaban.Kenkre@Sun.COM ldap_value_free(strvalues); 13258040SBaban.Kenkre@Sun.COM continue; 13268040SBaban.Kenkre@Sun.COM } 13278040SBaban.Kenkre@Sun.COM ap->attr_values = strvalues; 13288040SBaban.Kenkre@Sun.COM } 13298040SBaban.Kenkre@Sun.COM 13308040SBaban.Kenkre@Sun.COM ret = 0; 13318040SBaban.Kenkre@Sun.COM out: 13328040SBaban.Kenkre@Sun.COM ldap_memfree(attr); 13338040SBaban.Kenkre@Sun.COM ldap_memfree(dn); 13348040SBaban.Kenkre@Sun.COM ber_free(ber, 0); 13358040SBaban.Kenkre@Sun.COM ldap_value_free_len(bvalues); 13368040SBaban.Kenkre@Sun.COM if (ret < 0) 13378040SBaban.Kenkre@Sun.COM free_entry(ep); 13388040SBaban.Kenkre@Sun.COM else 13398040SBaban.Kenkre@Sun.COM *entry = ep; 13408040SBaban.Kenkre@Sun.COM return (ret); 13418040SBaban.Kenkre@Sun.COM } 13428040SBaban.Kenkre@Sun.COM 13438040SBaban.Kenkre@Sun.COM /* 13448040SBaban.Kenkre@Sun.COM * Put the search result onto the given adutils_q_t. 13458040SBaban.Kenkre@Sun.COM * Returns: 0 success 13468040SBaban.Kenkre@Sun.COM * < 0 error 13478040SBaban.Kenkre@Sun.COM */ 13488040SBaban.Kenkre@Sun.COM static 13498040SBaban.Kenkre@Sun.COM int 13508040SBaban.Kenkre@Sun.COM add_entry(adutils_host_t *adh, adutils_q_t *q, LDAPMessage *search_res) 13518040SBaban.Kenkre@Sun.COM { 13528040SBaban.Kenkre@Sun.COM int ret = -1; 13538040SBaban.Kenkre@Sun.COM adutils_entry_t *entry = NULL; 13548040SBaban.Kenkre@Sun.COM adutils_result_t *res; 13558040SBaban.Kenkre@Sun.COM 13568040SBaban.Kenkre@Sun.COM ret = make_entry(q, adh, search_res, &entry); 13578040SBaban.Kenkre@Sun.COM if (ret < -1) { 13588040SBaban.Kenkre@Sun.COM *q->rc = ADUTILS_ERR_MEMORY; 13598040SBaban.Kenkre@Sun.COM goto out; 13608040SBaban.Kenkre@Sun.COM } else if (ret == -1) { 13618040SBaban.Kenkre@Sun.COM /* ignore result */ 13628040SBaban.Kenkre@Sun.COM goto out; 13638040SBaban.Kenkre@Sun.COM } 13648040SBaban.Kenkre@Sun.COM if (*q->result == NULL) { 13658040SBaban.Kenkre@Sun.COM res = calloc(1, sizeof (*res)); 13668040SBaban.Kenkre@Sun.COM if (res == NULL) { 13678040SBaban.Kenkre@Sun.COM *q->rc = ADUTILS_ERR_MEMORY; 13688040SBaban.Kenkre@Sun.COM goto out; 13698040SBaban.Kenkre@Sun.COM } 13708040SBaban.Kenkre@Sun.COM res->num_entries = 1; 13718040SBaban.Kenkre@Sun.COM res->entries = entry; 13728040SBaban.Kenkre@Sun.COM *q->result = res; 13738040SBaban.Kenkre@Sun.COM } else { 13748040SBaban.Kenkre@Sun.COM res = *q->result; 13758040SBaban.Kenkre@Sun.COM entry->next = res->entries; 13768040SBaban.Kenkre@Sun.COM res->entries = entry; 13778040SBaban.Kenkre@Sun.COM res->num_entries++; 13788040SBaban.Kenkre@Sun.COM } 13798040SBaban.Kenkre@Sun.COM *q->rc = ADUTILS_SUCCESS; 13808040SBaban.Kenkre@Sun.COM entry = NULL; 13818040SBaban.Kenkre@Sun.COM ret = 0; 13828040SBaban.Kenkre@Sun.COM 13838040SBaban.Kenkre@Sun.COM out: 13848040SBaban.Kenkre@Sun.COM free_entry(entry); 13858040SBaban.Kenkre@Sun.COM return (ret); 13868040SBaban.Kenkre@Sun.COM } 13878040SBaban.Kenkre@Sun.COM 13888040SBaban.Kenkre@Sun.COM /* 13898040SBaban.Kenkre@Sun.COM * Try to get a result; if there is one, find the corresponding 13908040SBaban.Kenkre@Sun.COM * adutils_q_t and process the result. 13918040SBaban.Kenkre@Sun.COM * 13928040SBaban.Kenkre@Sun.COM * Returns: 0 success 13938040SBaban.Kenkre@Sun.COM * -1 error 13948040SBaban.Kenkre@Sun.COM */ 13958040SBaban.Kenkre@Sun.COM static 13968040SBaban.Kenkre@Sun.COM int 13978040SBaban.Kenkre@Sun.COM get_adobject_batch(adutils_host_t *adh, struct timeval *timeout) 13988040SBaban.Kenkre@Sun.COM { 13998040SBaban.Kenkre@Sun.COM adutils_query_state_t *query_state; 14008040SBaban.Kenkre@Sun.COM LDAPMessage *res = NULL; 14018040SBaban.Kenkre@Sun.COM int rc, ret, msgid, qid; 14028040SBaban.Kenkre@Sun.COM adutils_q_t *que; 14038040SBaban.Kenkre@Sun.COM int num; 14048040SBaban.Kenkre@Sun.COM 14058040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&adh->lock); 14068040SBaban.Kenkre@Sun.COM if (adh->dead || adh->num_requests == 0) { 14078040SBaban.Kenkre@Sun.COM ret = (adh->dead) ? -1 : -2; 14088040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 14098040SBaban.Kenkre@Sun.COM return (ret); 14108040SBaban.Kenkre@Sun.COM } 14118040SBaban.Kenkre@Sun.COM 14128040SBaban.Kenkre@Sun.COM /* Get one result */ 14138040SBaban.Kenkre@Sun.COM rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, timeout, &res); 14148040SBaban.Kenkre@Sun.COM if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) || 14158040SBaban.Kenkre@Sun.COM rc < 0) 14168040SBaban.Kenkre@Sun.COM adh->dead = 1; 14178040SBaban.Kenkre@Sun.COM 14188040SBaban.Kenkre@Sun.COM if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0) 14198040SBaban.Kenkre@Sun.COM adh->num_requests--; 14208040SBaban.Kenkre@Sun.COM if (adh->dead) { 14218040SBaban.Kenkre@Sun.COM num = adh->num_requests; 14228040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 14238040SBaban.Kenkre@Sun.COM idmapdlog(LOG_DEBUG, 14248040SBaban.Kenkre@Sun.COM "AD ldap_result error - %d queued requests", num); 14258040SBaban.Kenkre@Sun.COM return (-1); 14268040SBaban.Kenkre@Sun.COM } 14278040SBaban.Kenkre@Sun.COM 14288040SBaban.Kenkre@Sun.COM switch (rc) { 14298040SBaban.Kenkre@Sun.COM case LDAP_RES_SEARCH_RESULT: 14308040SBaban.Kenkre@Sun.COM msgid = ldap_msgid(res); 14318040SBaban.Kenkre@Sun.COM if (msgid2query(adh, msgid, &query_state, &qid)) { 14328040SBaban.Kenkre@Sun.COM if (query_state->ldap_res_search_cb != NULL) { 14338040SBaban.Kenkre@Sun.COM /* 14348040SBaban.Kenkre@Sun.COM * We use the caller-provided callback 14358040SBaban.Kenkre@Sun.COM * to process the result. 14368040SBaban.Kenkre@Sun.COM */ 14378040SBaban.Kenkre@Sun.COM query_state->ldap_res_search_cb( 14388040SBaban.Kenkre@Sun.COM adh->ld, &res, rc, qid, 14398040SBaban.Kenkre@Sun.COM query_state->ldap_res_search_argp); 14408040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 14418040SBaban.Kenkre@Sun.COM } else { 14428040SBaban.Kenkre@Sun.COM /* 14438040SBaban.Kenkre@Sun.COM * No callback. We fallback to our 14448040SBaban.Kenkre@Sun.COM * default behaviour. All the entries 14458040SBaban.Kenkre@Sun.COM * gotten from this search have been 14468040SBaban.Kenkre@Sun.COM * added to the result list during 14478040SBaban.Kenkre@Sun.COM * LDAP_RES_SEARCH_ENTRY (see below). 14488040SBaban.Kenkre@Sun.COM * Here we set the return status to 14498040SBaban.Kenkre@Sun.COM * notfound if the result is still empty. 14508040SBaban.Kenkre@Sun.COM */ 14518040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 14528040SBaban.Kenkre@Sun.COM que = &(query_state->queries[qid]); 14538040SBaban.Kenkre@Sun.COM if (*que->result == NULL) 14548040SBaban.Kenkre@Sun.COM *que->rc = ADUTILS_ERR_NOTFOUND; 14558040SBaban.Kenkre@Sun.COM } 14568040SBaban.Kenkre@Sun.COM atomic_dec_32(&query_state->qinflight); 14578040SBaban.Kenkre@Sun.COM adutils_lookup_batch_unlock(&query_state); 14588040SBaban.Kenkre@Sun.COM } else { 14598040SBaban.Kenkre@Sun.COM num = adh->num_requests; 14608040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 14618040SBaban.Kenkre@Sun.COM idmapdlog(LOG_DEBUG, 14628040SBaban.Kenkre@Sun.COM "AD cannot find message ID (%d) " 14638040SBaban.Kenkre@Sun.COM "- %d queued requests", 14648040SBaban.Kenkre@Sun.COM msgid, num); 14658040SBaban.Kenkre@Sun.COM } 14668040SBaban.Kenkre@Sun.COM (void) ldap_msgfree(res); 14678040SBaban.Kenkre@Sun.COM ret = 0; 14688040SBaban.Kenkre@Sun.COM break; 14698040SBaban.Kenkre@Sun.COM 14708040SBaban.Kenkre@Sun.COM case LDAP_RES_SEARCH_ENTRY: 14718040SBaban.Kenkre@Sun.COM msgid = ldap_msgid(res); 14728040SBaban.Kenkre@Sun.COM if (msgid2query(adh, msgid, &query_state, &qid)) { 14738040SBaban.Kenkre@Sun.COM if (query_state->ldap_res_search_cb != NULL) { 14748040SBaban.Kenkre@Sun.COM /* 14758040SBaban.Kenkre@Sun.COM * We use the caller-provided callback 14768040SBaban.Kenkre@Sun.COM * to process the entry. 14778040SBaban.Kenkre@Sun.COM */ 14788040SBaban.Kenkre@Sun.COM query_state->ldap_res_search_cb( 14798040SBaban.Kenkre@Sun.COM adh->ld, &res, rc, qid, 14808040SBaban.Kenkre@Sun.COM query_state->ldap_res_search_argp); 14818040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 14828040SBaban.Kenkre@Sun.COM } else { 14838040SBaban.Kenkre@Sun.COM /* 14848040SBaban.Kenkre@Sun.COM * No callback. We fallback to our 14858040SBaban.Kenkre@Sun.COM * default behaviour. This entry 14868040SBaban.Kenkre@Sun.COM * will be added to the result list. 14878040SBaban.Kenkre@Sun.COM */ 14888040SBaban.Kenkre@Sun.COM que = &(query_state->queries[qid]); 14898040SBaban.Kenkre@Sun.COM rc = add_entry(adh, que, res); 14908040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 14918040SBaban.Kenkre@Sun.COM if (rc < 0) { 14928040SBaban.Kenkre@Sun.COM idmapdlog(LOG_DEBUG, 14938040SBaban.Kenkre@Sun.COM "Failed to queue entry by " 14948040SBaban.Kenkre@Sun.COM "message ID (%d) " 14958040SBaban.Kenkre@Sun.COM "- %d queued requests", 14968040SBaban.Kenkre@Sun.COM msgid, num); 14978040SBaban.Kenkre@Sun.COM } 14988040SBaban.Kenkre@Sun.COM } 14998040SBaban.Kenkre@Sun.COM adutils_lookup_batch_unlock(&query_state); 15008040SBaban.Kenkre@Sun.COM } else { 15018040SBaban.Kenkre@Sun.COM num = adh->num_requests; 15028040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 15038040SBaban.Kenkre@Sun.COM idmapdlog(LOG_DEBUG, 15048040SBaban.Kenkre@Sun.COM "AD cannot find message ID (%d) " 15058040SBaban.Kenkre@Sun.COM "- %d queued requests", 15068040SBaban.Kenkre@Sun.COM msgid, num); 15078040SBaban.Kenkre@Sun.COM } 15088040SBaban.Kenkre@Sun.COM (void) ldap_msgfree(res); 15098040SBaban.Kenkre@Sun.COM ret = 0; 15108040SBaban.Kenkre@Sun.COM break; 15118040SBaban.Kenkre@Sun.COM 15128040SBaban.Kenkre@Sun.COM case LDAP_RES_SEARCH_REFERENCE: 15138040SBaban.Kenkre@Sun.COM /* 15148040SBaban.Kenkre@Sun.COM * We have no need for these at the moment. Eventually, 15158040SBaban.Kenkre@Sun.COM * when we query things that we can't expect to find in 15168040SBaban.Kenkre@Sun.COM * the Global Catalog then we'll need to learn to follow 15178040SBaban.Kenkre@Sun.COM * references. 15188040SBaban.Kenkre@Sun.COM */ 15198040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 15208040SBaban.Kenkre@Sun.COM (void) ldap_msgfree(res); 15218040SBaban.Kenkre@Sun.COM ret = 0; 15228040SBaban.Kenkre@Sun.COM break; 15238040SBaban.Kenkre@Sun.COM 15248040SBaban.Kenkre@Sun.COM default: 15258040SBaban.Kenkre@Sun.COM /* timeout or error; treat the same */ 15268040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&adh->lock); 15278040SBaban.Kenkre@Sun.COM ret = -1; 15288040SBaban.Kenkre@Sun.COM break; 15298040SBaban.Kenkre@Sun.COM } 15308040SBaban.Kenkre@Sun.COM 15318040SBaban.Kenkre@Sun.COM return (ret); 15328040SBaban.Kenkre@Sun.COM } 15338040SBaban.Kenkre@Sun.COM 15348040SBaban.Kenkre@Sun.COM /* 15358040SBaban.Kenkre@Sun.COM * This routine decreament the reference count of the 15368040SBaban.Kenkre@Sun.COM * adutils_query_state_t 15378040SBaban.Kenkre@Sun.COM */ 15388040SBaban.Kenkre@Sun.COM static void 15398040SBaban.Kenkre@Sun.COM adutils_lookup_batch_unlock(adutils_query_state_t **state) 15408040SBaban.Kenkre@Sun.COM { 15418040SBaban.Kenkre@Sun.COM /* 15428040SBaban.Kenkre@Sun.COM * Decrement reference count with qstatelock locked 15438040SBaban.Kenkre@Sun.COM */ 15448040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&qstatelock); 15458040SBaban.Kenkre@Sun.COM (*state)->ref_cnt--; 15468040SBaban.Kenkre@Sun.COM /* 15478040SBaban.Kenkre@Sun.COM * If there are no references wakup the allocating thread 15488040SBaban.Kenkre@Sun.COM */ 15498040SBaban.Kenkre@Sun.COM if ((*state)->ref_cnt <= 1) 15508040SBaban.Kenkre@Sun.COM (void) pthread_cond_signal(&(*state)->cv); 15518040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&qstatelock); 15528040SBaban.Kenkre@Sun.COM *state = NULL; 15538040SBaban.Kenkre@Sun.COM } 15548040SBaban.Kenkre@Sun.COM 15558040SBaban.Kenkre@Sun.COM /* 15568040SBaban.Kenkre@Sun.COM * This routine frees the adutils_query_state_t structure 15578040SBaban.Kenkre@Sun.COM * If the reference count is greater than 1 it waits 15588040SBaban.Kenkre@Sun.COM * for the other threads to finish using it. 15598040SBaban.Kenkre@Sun.COM */ 15608040SBaban.Kenkre@Sun.COM void 15618040SBaban.Kenkre@Sun.COM adutils_lookup_batch_release(adutils_query_state_t **state) 15628040SBaban.Kenkre@Sun.COM { 15638040SBaban.Kenkre@Sun.COM adutils_query_state_t **p; 15648040SBaban.Kenkre@Sun.COM int i; 15658040SBaban.Kenkre@Sun.COM 15668040SBaban.Kenkre@Sun.COM if (state == NULL || *state == NULL) 15678040SBaban.Kenkre@Sun.COM return; 15688040SBaban.Kenkre@Sun.COM 15698040SBaban.Kenkre@Sun.COM /* 15708040SBaban.Kenkre@Sun.COM * Set state to dead to stop further operations. 15718040SBaban.Kenkre@Sun.COM * Wait for reference count with qstatelock locked 15728040SBaban.Kenkre@Sun.COM * to get to one. 15738040SBaban.Kenkre@Sun.COM */ 15748040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&qstatelock); 15758040SBaban.Kenkre@Sun.COM (*state)->qdead = 1; 15768040SBaban.Kenkre@Sun.COM while ((*state)->ref_cnt > 1) { 15778040SBaban.Kenkre@Sun.COM (void) pthread_cond_wait(&(*state)->cv, &qstatelock); 15788040SBaban.Kenkre@Sun.COM } 15798040SBaban.Kenkre@Sun.COM 15808040SBaban.Kenkre@Sun.COM /* Remove this state struct from the list of state structs */ 15818040SBaban.Kenkre@Sun.COM for (p = &qstatehead; *p != NULL; p = &(*p)->next) { 15828040SBaban.Kenkre@Sun.COM if (*p == (*state)) { 15838040SBaban.Kenkre@Sun.COM *p = (*state)->next; 15848040SBaban.Kenkre@Sun.COM break; 15858040SBaban.Kenkre@Sun.COM } 15868040SBaban.Kenkre@Sun.COM } 15878040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&qstatelock); 15888040SBaban.Kenkre@Sun.COM (void) pthread_cond_destroy(&(*state)->cv); 15898040SBaban.Kenkre@Sun.COM release_conn((*state)->qadh); 15908040SBaban.Kenkre@Sun.COM 15918040SBaban.Kenkre@Sun.COM /* Clear results for queries that failed */ 15928040SBaban.Kenkre@Sun.COM for (i = 0; i < (*state)->qcount; i++) { 15938040SBaban.Kenkre@Sun.COM if (*(*state)->queries[i].rc != ADUTILS_SUCCESS) { 15948040SBaban.Kenkre@Sun.COM adutils_freeresult((*state)->queries[i].result); 15958040SBaban.Kenkre@Sun.COM } 15968040SBaban.Kenkre@Sun.COM } 15978040SBaban.Kenkre@Sun.COM free((*state)->default_domain); 15988040SBaban.Kenkre@Sun.COM free((*state)->basedn); 15998040SBaban.Kenkre@Sun.COM free(*state); 16008040SBaban.Kenkre@Sun.COM *state = NULL; 16018040SBaban.Kenkre@Sun.COM } 16028040SBaban.Kenkre@Sun.COM 16038040SBaban.Kenkre@Sun.COM 16048040SBaban.Kenkre@Sun.COM /* 16058040SBaban.Kenkre@Sun.COM * This routine waits for other threads using the 16068040SBaban.Kenkre@Sun.COM * adutils_query_state_t structure to finish. 16078040SBaban.Kenkre@Sun.COM * If the reference count is greater than 1 it waits 16088040SBaban.Kenkre@Sun.COM * for the other threads to finish using it. 16098040SBaban.Kenkre@Sun.COM */ 16108040SBaban.Kenkre@Sun.COM static 16118040SBaban.Kenkre@Sun.COM void 16128040SBaban.Kenkre@Sun.COM adutils_lookup_batch_wait(adutils_query_state_t *state) 16138040SBaban.Kenkre@Sun.COM { 16148040SBaban.Kenkre@Sun.COM /* 16158040SBaban.Kenkre@Sun.COM * Set state to dead to stop further operation. 16168040SBaban.Kenkre@Sun.COM * stating. 16178040SBaban.Kenkre@Sun.COM * Wait for reference count to get to one 16188040SBaban.Kenkre@Sun.COM * with qstatelock locked. 16198040SBaban.Kenkre@Sun.COM */ 16208040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&qstatelock); 16218040SBaban.Kenkre@Sun.COM state->qdead = 1; 16228040SBaban.Kenkre@Sun.COM while (state->ref_cnt > 1) { 16238040SBaban.Kenkre@Sun.COM (void) pthread_cond_wait(&state->cv, &qstatelock); 16248040SBaban.Kenkre@Sun.COM } 16258040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&qstatelock); 16268040SBaban.Kenkre@Sun.COM } 16278040SBaban.Kenkre@Sun.COM 16288040SBaban.Kenkre@Sun.COM /* 16298040SBaban.Kenkre@Sun.COM * Process active queries in the AD lookup batch and then finalize the 16308040SBaban.Kenkre@Sun.COM * result. 16318040SBaban.Kenkre@Sun.COM */ 16328040SBaban.Kenkre@Sun.COM adutils_rc 16338040SBaban.Kenkre@Sun.COM adutils_lookup_batch_end(adutils_query_state_t **state) 16348040SBaban.Kenkre@Sun.COM { 16358040SBaban.Kenkre@Sun.COM int rc = LDAP_SUCCESS; 16368040SBaban.Kenkre@Sun.COM adutils_rc ad_rc = ADUTILS_SUCCESS; 16378040SBaban.Kenkre@Sun.COM struct timeval tv; 16388040SBaban.Kenkre@Sun.COM 16398040SBaban.Kenkre@Sun.COM tv.tv_sec = ADUTILS_SEARCH_TIMEOUT; 16408040SBaban.Kenkre@Sun.COM tv.tv_usec = 0; 16418040SBaban.Kenkre@Sun.COM 16428040SBaban.Kenkre@Sun.COM /* Process results until done or until timeout, if given */ 16438040SBaban.Kenkre@Sun.COM while ((*state)->qinflight > 0) { 16448040SBaban.Kenkre@Sun.COM if ((rc = get_adobject_batch((*state)->qadh, 16458040SBaban.Kenkre@Sun.COM &tv)) != 0) 16468040SBaban.Kenkre@Sun.COM break; 16478040SBaban.Kenkre@Sun.COM } 16488040SBaban.Kenkre@Sun.COM (*state)->qdead = 1; 16498040SBaban.Kenkre@Sun.COM /* Wait for other threads processing search result to finish */ 16508040SBaban.Kenkre@Sun.COM adutils_lookup_batch_wait(*state); 16518040SBaban.Kenkre@Sun.COM if (rc == -1 || (*state)->qinflight != 0) 16528040SBaban.Kenkre@Sun.COM ad_rc = ADUTILS_ERR_RETRIABLE_NET_ERR; 16538040SBaban.Kenkre@Sun.COM adutils_lookup_batch_release(state); 16548040SBaban.Kenkre@Sun.COM return (ad_rc); 16558040SBaban.Kenkre@Sun.COM } 16568040SBaban.Kenkre@Sun.COM 16578040SBaban.Kenkre@Sun.COM const char * 16588040SBaban.Kenkre@Sun.COM adutils_lookup_batch_getdefdomain(adutils_query_state_t *state) 16598040SBaban.Kenkre@Sun.COM { 16608040SBaban.Kenkre@Sun.COM return (state->default_domain); 16618040SBaban.Kenkre@Sun.COM } 16628040SBaban.Kenkre@Sun.COM 16638040SBaban.Kenkre@Sun.COM /* 16648040SBaban.Kenkre@Sun.COM * Send one prepared search, queue up msgid, process what results are 16658040SBaban.Kenkre@Sun.COM * available 16668040SBaban.Kenkre@Sun.COM */ 16678040SBaban.Kenkre@Sun.COM adutils_rc 16688040SBaban.Kenkre@Sun.COM adutils_lookup_batch_add(adutils_query_state_t *state, 16698040SBaban.Kenkre@Sun.COM const char *filter, const char **attrs, const char *edomain, 16708040SBaban.Kenkre@Sun.COM adutils_result_t **result, adutils_rc *rc) 16718040SBaban.Kenkre@Sun.COM { 16728040SBaban.Kenkre@Sun.COM adutils_rc retcode = ADUTILS_SUCCESS; 16738040SBaban.Kenkre@Sun.COM int lrc, qid; 16748040SBaban.Kenkre@Sun.COM int num; 16758040SBaban.Kenkre@Sun.COM int dead; 16768040SBaban.Kenkre@Sun.COM struct timeval tv; 16778040SBaban.Kenkre@Sun.COM adutils_q_t *q; 16788040SBaban.Kenkre@Sun.COM 1679*8361SJulian.Pullen@Sun.COM qid = atomic_inc_32_nv(&state->qcount) - 1; 16808040SBaban.Kenkre@Sun.COM q = &(state->queries[qid]); 16818040SBaban.Kenkre@Sun.COM 1682*8361SJulian.Pullen@Sun.COM assert(qid < state->qsize); 1683*8361SJulian.Pullen@Sun.COM 16848040SBaban.Kenkre@Sun.COM /* 16858040SBaban.Kenkre@Sun.COM * Remember the expected domain so we can check the results 16868040SBaban.Kenkre@Sun.COM * against it 16878040SBaban.Kenkre@Sun.COM */ 16888040SBaban.Kenkre@Sun.COM q->edomain = edomain; 16898040SBaban.Kenkre@Sun.COM 16908040SBaban.Kenkre@Sun.COM /* Remember where to put the results */ 16918040SBaban.Kenkre@Sun.COM q->result = result; 16928040SBaban.Kenkre@Sun.COM q->rc = rc; 16938040SBaban.Kenkre@Sun.COM 16948040SBaban.Kenkre@Sun.COM /* 16958040SBaban.Kenkre@Sun.COM * Provide sane defaults for the results in case we never hear 16968040SBaban.Kenkre@Sun.COM * back from the DS before closing the connection. 16978040SBaban.Kenkre@Sun.COM */ 16988040SBaban.Kenkre@Sun.COM *rc = ADUTILS_ERR_RETRIABLE_NET_ERR; 16998040SBaban.Kenkre@Sun.COM if (result != NULL) 17008040SBaban.Kenkre@Sun.COM *result = NULL; 17018040SBaban.Kenkre@Sun.COM 17028040SBaban.Kenkre@Sun.COM /* Check the number of queued requests first */ 17038040SBaban.Kenkre@Sun.COM tv.tv_sec = ADUTILS_SEARCH_TIMEOUT; 17048040SBaban.Kenkre@Sun.COM tv.tv_usec = 0; 17058040SBaban.Kenkre@Sun.COM while (!state->qadh->dead && 17068040SBaban.Kenkre@Sun.COM state->qadh->num_requests > state->qadh->max_requests) { 17078040SBaban.Kenkre@Sun.COM if (get_adobject_batch(state->qadh, &tv) != 0) 17088040SBaban.Kenkre@Sun.COM break; 17098040SBaban.Kenkre@Sun.COM } 17108040SBaban.Kenkre@Sun.COM 17118040SBaban.Kenkre@Sun.COM /* Send this lookup, don't wait for a result here */ 17128040SBaban.Kenkre@Sun.COM lrc = LDAP_SUCCESS; 17138040SBaban.Kenkre@Sun.COM (void) pthread_mutex_lock(&state->qadh->lock); 17148040SBaban.Kenkre@Sun.COM 17158040SBaban.Kenkre@Sun.COM if (!state->qadh->dead) { 17168040SBaban.Kenkre@Sun.COM state->qadh->idletime = time(NULL); 17178040SBaban.Kenkre@Sun.COM lrc = ldap_search_ext(state->qadh->ld, state->basedn, 17188040SBaban.Kenkre@Sun.COM LDAP_SCOPE_SUBTREE, filter, (char **)attrs, 17198040SBaban.Kenkre@Sun.COM 0, NULL, NULL, NULL, -1, &q->msgid); 17208040SBaban.Kenkre@Sun.COM 17218040SBaban.Kenkre@Sun.COM if (lrc == LDAP_SUCCESS) { 17228040SBaban.Kenkre@Sun.COM state->qadh->num_requests++; 17238040SBaban.Kenkre@Sun.COM } else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE || 17248040SBaban.Kenkre@Sun.COM lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN || 17258040SBaban.Kenkre@Sun.COM lrc == LDAP_UNWILLING_TO_PERFORM) { 17268040SBaban.Kenkre@Sun.COM retcode = ADUTILS_ERR_RETRIABLE_NET_ERR; 17278040SBaban.Kenkre@Sun.COM state->qadh->dead = 1; 17288040SBaban.Kenkre@Sun.COM } else { 17298040SBaban.Kenkre@Sun.COM retcode = ADUTILS_ERR_OTHER; 17308040SBaban.Kenkre@Sun.COM state->qadh->dead = 1; 17318040SBaban.Kenkre@Sun.COM } 17328040SBaban.Kenkre@Sun.COM } 17338040SBaban.Kenkre@Sun.COM dead = state->qadh->dead; 17348040SBaban.Kenkre@Sun.COM num = state->qadh->num_requests; 17358040SBaban.Kenkre@Sun.COM (void) pthread_mutex_unlock(&state->qadh->lock); 17368040SBaban.Kenkre@Sun.COM 17378040SBaban.Kenkre@Sun.COM if (dead) { 17388040SBaban.Kenkre@Sun.COM if (lrc != LDAP_SUCCESS) 17398040SBaban.Kenkre@Sun.COM idmapdlog(LOG_DEBUG, 17408040SBaban.Kenkre@Sun.COM "AD ldap_search_ext error (%s) " 17418040SBaban.Kenkre@Sun.COM "- %d queued requests", 17428040SBaban.Kenkre@Sun.COM ldap_err2string(lrc), num); 17438040SBaban.Kenkre@Sun.COM return (retcode); 17448040SBaban.Kenkre@Sun.COM } 17458040SBaban.Kenkre@Sun.COM 17468040SBaban.Kenkre@Sun.COM atomic_inc_32(&state->qinflight); 17478040SBaban.Kenkre@Sun.COM 17488040SBaban.Kenkre@Sun.COM /* 17498040SBaban.Kenkre@Sun.COM * Reap as many requests as we can _without_ waiting to prevent 17508040SBaban.Kenkre@Sun.COM * any possible TCP socket buffer starvation deadlocks. 17518040SBaban.Kenkre@Sun.COM */ 17528040SBaban.Kenkre@Sun.COM (void) memset(&tv, 0, sizeof (tv)); 17538040SBaban.Kenkre@Sun.COM while (get_adobject_batch(state->qadh, &tv) == 0) 17548040SBaban.Kenkre@Sun.COM ; 17558040SBaban.Kenkre@Sun.COM 17568040SBaban.Kenkre@Sun.COM return (ADUTILS_SUCCESS); 17578040SBaban.Kenkre@Sun.COM } 17588040SBaban.Kenkre@Sun.COM 17598040SBaban.Kenkre@Sun.COM /* 17608040SBaban.Kenkre@Sun.COM * Single AD lookup request implemented on top of the batch API. 17618040SBaban.Kenkre@Sun.COM */ 17628040SBaban.Kenkre@Sun.COM adutils_rc 17638040SBaban.Kenkre@Sun.COM adutils_lookup(adutils_ad_t *ad, const char *filter, const char **attrs, 17648040SBaban.Kenkre@Sun.COM const char *domain, adutils_result_t **result) 17658040SBaban.Kenkre@Sun.COM { 17668040SBaban.Kenkre@Sun.COM adutils_rc rc, brc; 17678040SBaban.Kenkre@Sun.COM adutils_query_state_t *qs; 17688040SBaban.Kenkre@Sun.COM 17698040SBaban.Kenkre@Sun.COM rc = adutils_lookup_batch_start(ad, 1, NULL, NULL, &qs); 17708040SBaban.Kenkre@Sun.COM if (rc != ADUTILS_SUCCESS) 17718040SBaban.Kenkre@Sun.COM return (rc); 17728040SBaban.Kenkre@Sun.COM 17738040SBaban.Kenkre@Sun.COM rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc); 17748040SBaban.Kenkre@Sun.COM if (rc != ADUTILS_SUCCESS) { 17758040SBaban.Kenkre@Sun.COM adutils_lookup_batch_release(&qs); 17768040SBaban.Kenkre@Sun.COM return (rc); 17778040SBaban.Kenkre@Sun.COM } 17788040SBaban.Kenkre@Sun.COM 17798040SBaban.Kenkre@Sun.COM rc = adutils_lookup_batch_end(&qs); 17808040SBaban.Kenkre@Sun.COM if (rc != ADUTILS_SUCCESS) 17818040SBaban.Kenkre@Sun.COM return (rc); 17828040SBaban.Kenkre@Sun.COM return (brc); 17838040SBaban.Kenkre@Sun.COM } 1784