1*2b4a7802SBaban Kenkre /* 2*2b4a7802SBaban Kenkre * CDDL HEADER START 3*2b4a7802SBaban Kenkre * 4*2b4a7802SBaban Kenkre * The contents of this file are subject to the terms of the 5*2b4a7802SBaban Kenkre * Common Development and Distribution License (the "License"). 6*2b4a7802SBaban Kenkre * You may not use this file except in compliance with the License. 7*2b4a7802SBaban Kenkre * 8*2b4a7802SBaban Kenkre * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*2b4a7802SBaban Kenkre * or http://www.opensolaris.org/os/licensing. 10*2b4a7802SBaban Kenkre * See the License for the specific language governing permissions 11*2b4a7802SBaban Kenkre * and limitations under the License. 12*2b4a7802SBaban Kenkre * 13*2b4a7802SBaban Kenkre * When distributing Covered Code, include this CDDL HEADER in each 14*2b4a7802SBaban Kenkre * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*2b4a7802SBaban Kenkre * If applicable, add the following below this CDDL HEADER, with the 16*2b4a7802SBaban Kenkre * fields enclosed by brackets "[]" replaced with your own identifying 17*2b4a7802SBaban Kenkre * information: Portions Copyright [yyyy] [name of copyright owner] 18*2b4a7802SBaban Kenkre * 19*2b4a7802SBaban Kenkre * CDDL HEADER END 20*2b4a7802SBaban Kenkre */ 21*2b4a7802SBaban Kenkre /* 22*2b4a7802SBaban Kenkre * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*2b4a7802SBaban Kenkre * Use is subject to license terms. 24*2b4a7802SBaban Kenkre */ 25*2b4a7802SBaban Kenkre 26*2b4a7802SBaban Kenkre #include <alloca.h> 27*2b4a7802SBaban Kenkre #include <string.h> 28*2b4a7802SBaban Kenkre #include <strings.h> 29*2b4a7802SBaban Kenkre #include <lber.h> 30*2b4a7802SBaban Kenkre #include <sasl/sasl.h> 31*2b4a7802SBaban Kenkre #include <string.h> 32*2b4a7802SBaban Kenkre #include <ctype.h> 33*2b4a7802SBaban Kenkre #include <synch.h> 34*2b4a7802SBaban Kenkre #include <atomic.h> 35*2b4a7802SBaban Kenkre #include <errno.h> 36*2b4a7802SBaban Kenkre #include <assert.h> 37*2b4a7802SBaban Kenkre #include <limits.h> 38*2b4a7802SBaban Kenkre #include <sys/u8_textprep.h> 39*2b4a7802SBaban Kenkre #include <sys/varargs.h> 40*2b4a7802SBaban Kenkre #include "libadutils.h" 41*2b4a7802SBaban Kenkre #include "adutils_impl.h" 42*2b4a7802SBaban Kenkre 43*2b4a7802SBaban Kenkre /* List of DSs, needed by the idle connection reaper thread */ 44*2b4a7802SBaban Kenkre static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER; 45*2b4a7802SBaban Kenkre static adutils_host_t *host_head = NULL; 46*2b4a7802SBaban Kenkre 47*2b4a7802SBaban Kenkre /* 48*2b4a7802SBaban Kenkre * List of query state structs -- needed so we can "route" LDAP results 49*2b4a7802SBaban Kenkre * to the right context if multiple threads should be using the same 50*2b4a7802SBaban Kenkre * connection concurrently 51*2b4a7802SBaban Kenkre */ 52*2b4a7802SBaban Kenkre static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER; 53*2b4a7802SBaban Kenkre static adutils_query_state_t *qstatehead = NULL; 54*2b4a7802SBaban Kenkre 55*2b4a7802SBaban Kenkre static char *adutils_sid_ber2str(BerValue *bvalues); 56*2b4a7802SBaban Kenkre static void adutils_lookup_batch_unlock(adutils_query_state_t **state); 57*2b4a7802SBaban Kenkre static void delete_ds(adutils_ad_t *ad, const char *host, int port); 58*2b4a7802SBaban Kenkre 59*2b4a7802SBaban Kenkre typedef struct binary_attrs { 60*2b4a7802SBaban Kenkre const char *name; 61*2b4a7802SBaban Kenkre char *(*ber2str)(BerValue *bvalues); 62*2b4a7802SBaban Kenkre } binary_attrs_t; 63*2b4a7802SBaban Kenkre 64*2b4a7802SBaban Kenkre static binary_attrs_t binattrs[] = { 65*2b4a7802SBaban Kenkre {"objectSID", adutils_sid_ber2str}, 66*2b4a7802SBaban Kenkre {NULL, NULL} 67*2b4a7802SBaban Kenkre }; 68*2b4a7802SBaban Kenkre 69*2b4a7802SBaban Kenkre void 70*2b4a7802SBaban Kenkre adutils_set_log(int pri, bool_t syslog, bool_t degraded) 71*2b4a7802SBaban Kenkre { 72*2b4a7802SBaban Kenkre idmap_log_stderr(pri); 73*2b4a7802SBaban Kenkre idmap_log_syslog(syslog); 74*2b4a7802SBaban Kenkre idmap_log_degraded(degraded); 75*2b4a7802SBaban Kenkre } 76*2b4a7802SBaban Kenkre 77*2b4a7802SBaban Kenkre /* 78*2b4a7802SBaban Kenkre * Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com" 79*2b4a7802SBaban Kenkre */ 80*2b4a7802SBaban Kenkre static 81*2b4a7802SBaban Kenkre char * 82*2b4a7802SBaban Kenkre adutils_dns2dn(const char *dns) 83*2b4a7802SBaban Kenkre { 84*2b4a7802SBaban Kenkre int nameparts; 85*2b4a7802SBaban Kenkre return (ldap_dns_to_dn((char *)dns, &nameparts)); 86*2b4a7802SBaban Kenkre } 87*2b4a7802SBaban Kenkre 88*2b4a7802SBaban Kenkre /* 89*2b4a7802SBaban Kenkre * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other 90*2b4a7802SBaban Kenkre * attributes (CN, etc...). 91*2b4a7802SBaban Kenkre */ 92*2b4a7802SBaban Kenkre char * 93*2b4a7802SBaban Kenkre adutils_dn2dns(const char *dn) 94*2b4a7802SBaban Kenkre { 95*2b4a7802SBaban Kenkre char **rdns = NULL; 96*2b4a7802SBaban Kenkre char **attrs = NULL; 97*2b4a7802SBaban Kenkre char **labels = NULL; 98*2b4a7802SBaban Kenkre char *dns = NULL; 99*2b4a7802SBaban Kenkre char **rdn, **attr, **label; 100*2b4a7802SBaban Kenkre int maxlabels = 5; 101*2b4a7802SBaban Kenkre int nlabels = 0; 102*2b4a7802SBaban Kenkre int dnslen; 103*2b4a7802SBaban Kenkre 104*2b4a7802SBaban Kenkre /* 105*2b4a7802SBaban Kenkre * There is no reverse of ldap_dns_to_dn() in our libldap, so we 106*2b4a7802SBaban Kenkre * have to do the hard work here for now. 107*2b4a7802SBaban Kenkre */ 108*2b4a7802SBaban Kenkre 109*2b4a7802SBaban Kenkre /* 110*2b4a7802SBaban Kenkre * This code is much too liberal: it looks for "dc" attributes 111*2b4a7802SBaban Kenkre * in all RDNs of the DN. In theory this could cause problems 112*2b4a7802SBaban Kenkre * if people were to use "dc" in nodes other than the root of 113*2b4a7802SBaban Kenkre * the tree, but in practice noone, least of all Active 114*2b4a7802SBaban Kenkre * Directory, does that. 115*2b4a7802SBaban Kenkre * 116*2b4a7802SBaban Kenkre * On the other hand, this code is much too conservative: it 117*2b4a7802SBaban Kenkre * does not make assumptions about ldap_explode_dn(), and _that_ 118*2b4a7802SBaban Kenkre * is the true for looking at every attr of every RDN. 119*2b4a7802SBaban Kenkre * 120*2b4a7802SBaban Kenkre * Since we only ever look at dc and those must be DNS labels, 121*2b4a7802SBaban Kenkre * at least until we get around to supporting IDN here we 122*2b4a7802SBaban Kenkre * shouldn't see escaped labels from AD nor from libldap, though 123*2b4a7802SBaban Kenkre * the spec (RFC2253) does allow libldap to escape things that 124*2b4a7802SBaban Kenkre * don't need escaping -- if that should ever happen then 125*2b4a7802SBaban Kenkre * libldap will need a spanking, and we can take care of that. 126*2b4a7802SBaban Kenkre */ 127*2b4a7802SBaban Kenkre 128*2b4a7802SBaban Kenkre /* Explode a DN into RDNs */ 129*2b4a7802SBaban Kenkre if ((rdns = ldap_explode_dn(dn, 0)) == NULL) 130*2b4a7802SBaban Kenkre return (NULL); 131*2b4a7802SBaban Kenkre 132*2b4a7802SBaban Kenkre labels = calloc(maxlabels + 1, sizeof (char *)); 133*2b4a7802SBaban Kenkre label = labels; 134*2b4a7802SBaban Kenkre 135*2b4a7802SBaban Kenkre for (rdn = rdns; *rdn != NULL; rdn++) { 136*2b4a7802SBaban Kenkre if (attrs != NULL) 137*2b4a7802SBaban Kenkre ldap_value_free(attrs); 138*2b4a7802SBaban Kenkre 139*2b4a7802SBaban Kenkre /* Explode each RDN, look for DC attr, save val as DNS label */ 140*2b4a7802SBaban Kenkre if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) 141*2b4a7802SBaban Kenkre goto done; 142*2b4a7802SBaban Kenkre 143*2b4a7802SBaban Kenkre for (attr = attrs; *attr != NULL; attr++) { 144*2b4a7802SBaban Kenkre if (strncasecmp(*attr, "dc=", 3) != 0) 145*2b4a7802SBaban Kenkre continue; 146*2b4a7802SBaban Kenkre 147*2b4a7802SBaban Kenkre /* Found a DNS label */ 148*2b4a7802SBaban Kenkre labels[nlabels++] = strdup((*attr) + 3); 149*2b4a7802SBaban Kenkre 150*2b4a7802SBaban Kenkre if (nlabels == maxlabels) { 151*2b4a7802SBaban Kenkre char **tmp; 152*2b4a7802SBaban Kenkre tmp = realloc(labels, 153*2b4a7802SBaban Kenkre sizeof (char *) * (maxlabels + 1)); 154*2b4a7802SBaban Kenkre 155*2b4a7802SBaban Kenkre if (tmp == NULL) 156*2b4a7802SBaban Kenkre goto done; 157*2b4a7802SBaban Kenkre 158*2b4a7802SBaban Kenkre labels = tmp; 159*2b4a7802SBaban Kenkre labels[nlabels] = NULL; 160*2b4a7802SBaban Kenkre } 161*2b4a7802SBaban Kenkre 162*2b4a7802SBaban Kenkre /* There should be just one DC= attr per-RDN */ 163*2b4a7802SBaban Kenkre break; 164*2b4a7802SBaban Kenkre } 165*2b4a7802SBaban Kenkre } 166*2b4a7802SBaban Kenkre 167*2b4a7802SBaban Kenkre /* 168*2b4a7802SBaban Kenkre * Got all the labels, now join with '.' 169*2b4a7802SBaban Kenkre * 170*2b4a7802SBaban Kenkre * We need room for nlabels - 1 periods ('.'), one nul 171*2b4a7802SBaban Kenkre * terminator, and the strlen() of each label. 172*2b4a7802SBaban Kenkre */ 173*2b4a7802SBaban Kenkre dnslen = nlabels; 174*2b4a7802SBaban Kenkre for (label = labels; *label != NULL; label++) 175*2b4a7802SBaban Kenkre dnslen += strlen(*label); 176*2b4a7802SBaban Kenkre 177*2b4a7802SBaban Kenkre if ((dns = malloc(dnslen)) == NULL) 178*2b4a7802SBaban Kenkre goto done; 179*2b4a7802SBaban Kenkre 180*2b4a7802SBaban Kenkre *dns = '\0'; 181*2b4a7802SBaban Kenkre 182*2b4a7802SBaban Kenkre for (label = labels; *label != NULL; label++) { 183*2b4a7802SBaban Kenkre (void) strlcat(dns, *label, dnslen); 184*2b4a7802SBaban Kenkre /* 185*2b4a7802SBaban Kenkre * NOTE: the last '.' won't be appended -- there's no room 186*2b4a7802SBaban Kenkre * for it! 187*2b4a7802SBaban Kenkre */ 188*2b4a7802SBaban Kenkre (void) strlcat(dns, ".", dnslen); 189*2b4a7802SBaban Kenkre } 190*2b4a7802SBaban Kenkre 191*2b4a7802SBaban Kenkre done: 192*2b4a7802SBaban Kenkre if (labels != NULL) { 193*2b4a7802SBaban Kenkre for (label = labels; *label != NULL; label++) 194*2b4a7802SBaban Kenkre free(*label); 195*2b4a7802SBaban Kenkre free(labels); 196*2b4a7802SBaban Kenkre } 197*2b4a7802SBaban Kenkre if (attrs != NULL) 198*2b4a7802SBaban Kenkre ldap_value_free(attrs); 199*2b4a7802SBaban Kenkre if (rdns != NULL) 200*2b4a7802SBaban Kenkre ldap_value_free(rdns); 201*2b4a7802SBaban Kenkre 202*2b4a7802SBaban Kenkre return (dns); 203*2b4a7802SBaban Kenkre } 204*2b4a7802SBaban Kenkre 205*2b4a7802SBaban Kenkre /* 206*2b4a7802SBaban Kenkre * Convert a binary SID in a BerValue to a adutils_sid_t 207*2b4a7802SBaban Kenkre */ 208*2b4a7802SBaban Kenkre static 209*2b4a7802SBaban Kenkre int 210*2b4a7802SBaban Kenkre getsid(BerValue *bval, adutils_sid_t *sidp) 211*2b4a7802SBaban Kenkre { 212*2b4a7802SBaban Kenkre int i, j; 213*2b4a7802SBaban Kenkre uchar_t *v; 214*2b4a7802SBaban Kenkre uint32_t a; 215*2b4a7802SBaban Kenkre 216*2b4a7802SBaban Kenkre /* 217*2b4a7802SBaban Kenkre * The binary format of a SID is as follows: 218*2b4a7802SBaban Kenkre * 219*2b4a7802SBaban Kenkre * byte #0: version, always 0x01 220*2b4a7802SBaban Kenkre * byte #1: RID count, always <= 0x0f 221*2b4a7802SBaban Kenkre * bytes #2-#7: SID authority, big-endian 48-bit unsigned int 222*2b4a7802SBaban Kenkre * 223*2b4a7802SBaban Kenkre * followed by RID count RIDs, each a little-endian, unsigned 224*2b4a7802SBaban Kenkre * 32-bit int. 225*2b4a7802SBaban Kenkre */ 226*2b4a7802SBaban Kenkre /* 227*2b4a7802SBaban Kenkre * Sanity checks: must have at least one RID, version must be 228*2b4a7802SBaban Kenkre * 0x01, and the length must be 8 + rid count * 4 229*2b4a7802SBaban Kenkre */ 230*2b4a7802SBaban Kenkre if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 && 231*2b4a7802SBaban Kenkre bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) { 232*2b4a7802SBaban Kenkre v = (uchar_t *)bval->bv_val; 233*2b4a7802SBaban Kenkre sidp->version = v[0]; 234*2b4a7802SBaban Kenkre sidp->sub_authority_count = v[1]; 235*2b4a7802SBaban Kenkre sidp->authority = 236*2b4a7802SBaban Kenkre /* big endian -- so start from the left */ 237*2b4a7802SBaban Kenkre ((u_longlong_t)v[2] << 40) | 238*2b4a7802SBaban Kenkre ((u_longlong_t)v[3] << 32) | 239*2b4a7802SBaban Kenkre ((u_longlong_t)v[4] << 24) | 240*2b4a7802SBaban Kenkre ((u_longlong_t)v[5] << 16) | 241*2b4a7802SBaban Kenkre ((u_longlong_t)v[6] << 8) | 242*2b4a7802SBaban Kenkre (u_longlong_t)v[7]; 243*2b4a7802SBaban Kenkre for (i = 0; i < sidp->sub_authority_count; i++) { 244*2b4a7802SBaban Kenkre j = 8 + (i * 4); 245*2b4a7802SBaban Kenkre /* little endian -- so start from the right */ 246*2b4a7802SBaban Kenkre a = (v[j + 3] << 24) | (v[j + 2] << 16) | 247*2b4a7802SBaban Kenkre (v[j + 1] << 8) | (v[j]); 248*2b4a7802SBaban Kenkre sidp->sub_authorities[i] = a; 249*2b4a7802SBaban Kenkre } 250*2b4a7802SBaban Kenkre return (0); 251*2b4a7802SBaban Kenkre } 252*2b4a7802SBaban Kenkre return (-1); 253*2b4a7802SBaban Kenkre } 254*2b4a7802SBaban Kenkre 255*2b4a7802SBaban Kenkre /* 256*2b4a7802SBaban Kenkre * Convert a adutils_sid_t to S-1-... 257*2b4a7802SBaban Kenkre */ 258*2b4a7802SBaban Kenkre static 259*2b4a7802SBaban Kenkre char * 260*2b4a7802SBaban Kenkre sid2txt(adutils_sid_t *sidp) 261*2b4a7802SBaban Kenkre { 262*2b4a7802SBaban Kenkre int rlen, i, len; 263*2b4a7802SBaban Kenkre char *str, *cp; 264*2b4a7802SBaban Kenkre 265*2b4a7802SBaban Kenkre if (sidp->version != 1) 266*2b4a7802SBaban Kenkre return (NULL); 267*2b4a7802SBaban Kenkre 268*2b4a7802SBaban Kenkre len = sizeof ("S-1-") - 1; 269*2b4a7802SBaban Kenkre 270*2b4a7802SBaban Kenkre /* 271*2b4a7802SBaban Kenkre * We could optimize like so, but, why? 272*2b4a7802SBaban Kenkre * if (sidp->authority < 10) 273*2b4a7802SBaban Kenkre * len += 2; 274*2b4a7802SBaban Kenkre * else if (sidp->authority < 100) 275*2b4a7802SBaban Kenkre * len += 3; 276*2b4a7802SBaban Kenkre * else 277*2b4a7802SBaban Kenkre * len += snprintf(NULL, 0"%llu", sidp->authority); 278*2b4a7802SBaban Kenkre */ 279*2b4a7802SBaban Kenkre len += snprintf(NULL, 0, "%llu", sidp->authority); 280*2b4a7802SBaban Kenkre 281*2b4a7802SBaban Kenkre /* Max length of a uint32_t printed out in ASCII is 10 bytes */ 282*2b4a7802SBaban Kenkre len += 1 + (sidp->sub_authority_count + 1) * 10; 283*2b4a7802SBaban Kenkre 284*2b4a7802SBaban Kenkre if ((cp = str = malloc(len)) == NULL) 285*2b4a7802SBaban Kenkre return (NULL); 286*2b4a7802SBaban Kenkre 287*2b4a7802SBaban Kenkre rlen = snprintf(str, len, "S-1-%llu", sidp->authority); 288*2b4a7802SBaban Kenkre 289*2b4a7802SBaban Kenkre cp += rlen; 290*2b4a7802SBaban Kenkre len -= rlen; 291*2b4a7802SBaban Kenkre 292*2b4a7802SBaban Kenkre for (i = 0; i < sidp->sub_authority_count; i++) { 293*2b4a7802SBaban Kenkre assert(len > 0); 294*2b4a7802SBaban Kenkre rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]); 295*2b4a7802SBaban Kenkre cp += rlen; 296*2b4a7802SBaban Kenkre len -= rlen; 297*2b4a7802SBaban Kenkre assert(len >= 0); 298*2b4a7802SBaban Kenkre } 299*2b4a7802SBaban Kenkre 300*2b4a7802SBaban Kenkre return (str); 301*2b4a7802SBaban Kenkre } 302*2b4a7802SBaban Kenkre 303*2b4a7802SBaban Kenkre /* 304*2b4a7802SBaban Kenkre * Convert a adutils_sid_t to on-the-wire encoding 305*2b4a7802SBaban Kenkre */ 306*2b4a7802SBaban Kenkre static 307*2b4a7802SBaban Kenkre int 308*2b4a7802SBaban Kenkre sid2binsid(adutils_sid_t *sid, uchar_t *binsid, int binsidlen) 309*2b4a7802SBaban Kenkre { 310*2b4a7802SBaban Kenkre uchar_t *p; 311*2b4a7802SBaban Kenkre int i; 312*2b4a7802SBaban Kenkre uint64_t a; 313*2b4a7802SBaban Kenkre uint32_t r; 314*2b4a7802SBaban Kenkre 315*2b4a7802SBaban Kenkre if (sid->version != 1 || 316*2b4a7802SBaban Kenkre binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4)) 317*2b4a7802SBaban Kenkre return (-1); 318*2b4a7802SBaban Kenkre 319*2b4a7802SBaban Kenkre p = binsid; 320*2b4a7802SBaban Kenkre *p++ = 0x01; /* version */ 321*2b4a7802SBaban Kenkre /* sub authority count */ 322*2b4a7802SBaban Kenkre *p++ = sid->sub_authority_count; 323*2b4a7802SBaban Kenkre /* Authority */ 324*2b4a7802SBaban Kenkre a = sid->authority; 325*2b4a7802SBaban Kenkre /* big-endian -- start from left */ 326*2b4a7802SBaban Kenkre *p++ = (a >> 40) & 0xFF; 327*2b4a7802SBaban Kenkre *p++ = (a >> 32) & 0xFF; 328*2b4a7802SBaban Kenkre *p++ = (a >> 24) & 0xFF; 329*2b4a7802SBaban Kenkre *p++ = (a >> 16) & 0xFF; 330*2b4a7802SBaban Kenkre *p++ = (a >> 8) & 0xFF; 331*2b4a7802SBaban Kenkre *p++ = a & 0xFF; 332*2b4a7802SBaban Kenkre 333*2b4a7802SBaban Kenkre /* sub-authorities */ 334*2b4a7802SBaban Kenkre for (i = 0; i < sid->sub_authority_count; i++) { 335*2b4a7802SBaban Kenkre r = sid->sub_authorities[i]; 336*2b4a7802SBaban Kenkre /* little-endian -- start from right */ 337*2b4a7802SBaban Kenkre *p++ = (r & 0x000000FF); 338*2b4a7802SBaban Kenkre *p++ = (r & 0x0000FF00) >> 8; 339*2b4a7802SBaban Kenkre *p++ = (r & 0x00FF0000) >> 16; 340*2b4a7802SBaban Kenkre *p++ = (r & 0xFF000000) >> 24; 341*2b4a7802SBaban Kenkre } 342*2b4a7802SBaban Kenkre 343*2b4a7802SBaban Kenkre return (0); 344*2b4a7802SBaban Kenkre } 345*2b4a7802SBaban Kenkre 346*2b4a7802SBaban Kenkre /* 347*2b4a7802SBaban Kenkre * Convert a stringified SID (S-1-...) into a hex-encoded version of the 348*2b4a7802SBaban Kenkre * on-the-wire encoding, but with each pair of hex digits pre-pended 349*2b4a7802SBaban Kenkre * with a '\', so we can pass this to libldap. 350*2b4a7802SBaban Kenkre */ 351*2b4a7802SBaban Kenkre int 352*2b4a7802SBaban Kenkre adutils_txtsid2hexbinsid(const char *txt, const uint32_t *rid, 353*2b4a7802SBaban Kenkre char *hexbinsid, int hexbinsidlen) 354*2b4a7802SBaban Kenkre { 355*2b4a7802SBaban Kenkre adutils_sid_t sid = { 0 }; 356*2b4a7802SBaban Kenkre int i, j; 357*2b4a7802SBaban Kenkre const char *cp; 358*2b4a7802SBaban Kenkre char *ecp; 359*2b4a7802SBaban Kenkre u_longlong_t a; 360*2b4a7802SBaban Kenkre unsigned long r; 361*2b4a7802SBaban Kenkre uchar_t *binsid, b, hb; 362*2b4a7802SBaban Kenkre 363*2b4a7802SBaban Kenkre /* Only version 1 SIDs please */ 364*2b4a7802SBaban Kenkre if (strncmp(txt, "S-1-", strlen("S-1-")) != 0) 365*2b4a7802SBaban Kenkre return (-1); 366*2b4a7802SBaban Kenkre 367*2b4a7802SBaban Kenkre if (strlen(txt) < (strlen("S-1-") + 1)) 368*2b4a7802SBaban Kenkre return (-1); 369*2b4a7802SBaban Kenkre 370*2b4a7802SBaban Kenkre /* count '-'s */ 371*2b4a7802SBaban Kenkre for (j = 0, cp = strchr(txt, '-'); 372*2b4a7802SBaban Kenkre cp != NULL && *cp != '\0'; 373*2b4a7802SBaban Kenkre j++, cp = strchr(cp + 1, '-')) { 374*2b4a7802SBaban Kenkre /* can't end on a '-' */ 375*2b4a7802SBaban Kenkre if (*(cp + 1) == '\0') 376*2b4a7802SBaban Kenkre return (-1); 377*2b4a7802SBaban Kenkre } 378*2b4a7802SBaban Kenkre 379*2b4a7802SBaban Kenkre /* Adjust count for version and authority */ 380*2b4a7802SBaban Kenkre j -= 2; 381*2b4a7802SBaban Kenkre 382*2b4a7802SBaban Kenkre /* we know the version number and RID count */ 383*2b4a7802SBaban Kenkre sid.version = 1; 384*2b4a7802SBaban Kenkre sid.sub_authority_count = (rid != NULL) ? j + 1 : j; 385*2b4a7802SBaban Kenkre 386*2b4a7802SBaban Kenkre /* must have at least one RID, but not too many */ 387*2b4a7802SBaban Kenkre if (sid.sub_authority_count < 1 || 388*2b4a7802SBaban Kenkre sid.sub_authority_count > ADUTILS_SID_MAX_SUB_AUTHORITIES) 389*2b4a7802SBaban Kenkre return (-1); 390*2b4a7802SBaban Kenkre 391*2b4a7802SBaban Kenkre /* check that we only have digits and '-' */ 392*2b4a7802SBaban Kenkre if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1)) 393*2b4a7802SBaban Kenkre return (-1); 394*2b4a7802SBaban Kenkre 395*2b4a7802SBaban Kenkre cp = txt + strlen("S-1-"); 396*2b4a7802SBaban Kenkre 397*2b4a7802SBaban Kenkre /* 64-bit safe parsing of unsigned 48-bit authority value */ 398*2b4a7802SBaban Kenkre errno = 0; 399*2b4a7802SBaban Kenkre a = strtoull(cp, &ecp, 10); 400*2b4a7802SBaban Kenkre 401*2b4a7802SBaban Kenkre /* errors parsing the authority or too many bits */ 402*2b4a7802SBaban Kenkre if (cp == ecp || (a == 0 && errno == EINVAL) || 403*2b4a7802SBaban Kenkre (a == ULLONG_MAX && errno == ERANGE) || 404*2b4a7802SBaban Kenkre (a & 0x0000ffffffffffffULL) != a) 405*2b4a7802SBaban Kenkre return (-1); 406*2b4a7802SBaban Kenkre 407*2b4a7802SBaban Kenkre cp = ecp; 408*2b4a7802SBaban Kenkre 409*2b4a7802SBaban Kenkre sid.authority = (uint64_t)a; 410*2b4a7802SBaban Kenkre 411*2b4a7802SBaban Kenkre for (i = 0; i < j; i++) { 412*2b4a7802SBaban Kenkre if (*cp++ != '-') 413*2b4a7802SBaban Kenkre return (-1); 414*2b4a7802SBaban Kenkre /* 64-bit safe parsing of unsigned 32-bit RID */ 415*2b4a7802SBaban Kenkre errno = 0; 416*2b4a7802SBaban Kenkre r = strtoul(cp, &ecp, 10); 417*2b4a7802SBaban Kenkre /* errors parsing the RID or too many bits */ 418*2b4a7802SBaban Kenkre if (cp == ecp || (r == 0 && errno == EINVAL) || 419*2b4a7802SBaban Kenkre (r == ULONG_MAX && errno == ERANGE) || 420*2b4a7802SBaban Kenkre (r & 0xffffffffUL) != r) 421*2b4a7802SBaban Kenkre return (-1); 422*2b4a7802SBaban Kenkre sid.sub_authorities[i] = (uint32_t)r; 423*2b4a7802SBaban Kenkre cp = ecp; 424*2b4a7802SBaban Kenkre } 425*2b4a7802SBaban Kenkre 426*2b4a7802SBaban Kenkre /* check that all of the string SID has been consumed */ 427*2b4a7802SBaban Kenkre if (*cp != '\0') 428*2b4a7802SBaban Kenkre return (-1); 429*2b4a7802SBaban Kenkre 430*2b4a7802SBaban Kenkre if (rid != NULL) 431*2b4a7802SBaban Kenkre sid.sub_authorities[j] = *rid; 432*2b4a7802SBaban Kenkre 433*2b4a7802SBaban Kenkre j = 1 + 1 + 6 + sid.sub_authority_count * 4; 434*2b4a7802SBaban Kenkre 435*2b4a7802SBaban Kenkre if (hexbinsidlen < (j * 3)) 436*2b4a7802SBaban Kenkre return (-2); 437*2b4a7802SBaban Kenkre 438*2b4a7802SBaban Kenkre /* binary encode the SID */ 439*2b4a7802SBaban Kenkre binsid = (uchar_t *)alloca(j); 440*2b4a7802SBaban Kenkre (void) sid2binsid(&sid, binsid, j); 441*2b4a7802SBaban Kenkre 442*2b4a7802SBaban Kenkre /* hex encode, with a backslash before each byte */ 443*2b4a7802SBaban Kenkre for (ecp = hexbinsid, i = 0; i < j; i++) { 444*2b4a7802SBaban Kenkre b = binsid[i]; 445*2b4a7802SBaban Kenkre *ecp++ = '\\'; 446*2b4a7802SBaban Kenkre hb = (b >> 4) & 0xF; 447*2b4a7802SBaban Kenkre *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 448*2b4a7802SBaban Kenkre hb = b & 0xF; 449*2b4a7802SBaban Kenkre *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 450*2b4a7802SBaban Kenkre } 451*2b4a7802SBaban Kenkre *ecp = '\0'; 452*2b4a7802SBaban Kenkre 453*2b4a7802SBaban Kenkre return (0); 454*2b4a7802SBaban Kenkre } 455*2b4a7802SBaban Kenkre 456*2b4a7802SBaban Kenkre static 457*2b4a7802SBaban Kenkre char * 458*2b4a7802SBaban Kenkre convert_bval2sid(BerValue *bval, uint32_t *rid) 459*2b4a7802SBaban Kenkre { 460*2b4a7802SBaban Kenkre adutils_sid_t sid; 461*2b4a7802SBaban Kenkre 462*2b4a7802SBaban Kenkre if (getsid(bval, &sid) < 0) 463*2b4a7802SBaban Kenkre return (NULL); 464*2b4a7802SBaban Kenkre 465*2b4a7802SBaban Kenkre /* 466*2b4a7802SBaban Kenkre * If desired and if the SID is what should be a domain/computer 467*2b4a7802SBaban Kenkre * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then 468*2b4a7802SBaban Kenkre * save the last RID and truncate the SID 469*2b4a7802SBaban Kenkre */ 470*2b4a7802SBaban Kenkre if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5) 471*2b4a7802SBaban Kenkre *rid = sid.sub_authorities[--sid.sub_authority_count]; 472*2b4a7802SBaban Kenkre return (sid2txt(&sid)); 473*2b4a7802SBaban Kenkre } 474*2b4a7802SBaban Kenkre 475*2b4a7802SBaban Kenkre 476*2b4a7802SBaban Kenkre /* 477*2b4a7802SBaban Kenkre * Return a NUL-terminated stringified SID from the value of an 478*2b4a7802SBaban Kenkre * objectSid attribute and put the last RID in *rid. 479*2b4a7802SBaban Kenkre */ 480*2b4a7802SBaban Kenkre char * 481*2b4a7802SBaban Kenkre adutils_bv_objsid2sidstr(BerValue *bval, uint32_t *rid) 482*2b4a7802SBaban Kenkre { 483*2b4a7802SBaban Kenkre char *sid; 484*2b4a7802SBaban Kenkre 485*2b4a7802SBaban Kenkre if (bval == NULL) 486*2b4a7802SBaban Kenkre return (NULL); 487*2b4a7802SBaban Kenkre /* objectSid is single valued */ 488*2b4a7802SBaban Kenkre if ((sid = convert_bval2sid(bval, rid)) == NULL) 489*2b4a7802SBaban Kenkre return (NULL); 490*2b4a7802SBaban Kenkre return (sid); 491*2b4a7802SBaban Kenkre } 492*2b4a7802SBaban Kenkre 493*2b4a7802SBaban Kenkre static 494*2b4a7802SBaban Kenkre char * 495*2b4a7802SBaban Kenkre adutils_sid_ber2str(BerValue *bval) 496*2b4a7802SBaban Kenkre { 497*2b4a7802SBaban Kenkre return (adutils_bv_objsid2sidstr(bval, NULL)); 498*2b4a7802SBaban Kenkre } 499*2b4a7802SBaban Kenkre 500*2b4a7802SBaban Kenkre 501*2b4a7802SBaban Kenkre /* Return a NUL-terminated string from the Ber value */ 502*2b4a7802SBaban Kenkre char * 503*2b4a7802SBaban Kenkre adutils_bv_name2str(BerValue *bval) 504*2b4a7802SBaban Kenkre { 505*2b4a7802SBaban Kenkre char *s; 506*2b4a7802SBaban Kenkre 507*2b4a7802SBaban Kenkre if (bval == NULL || bval->bv_val == NULL) 508*2b4a7802SBaban Kenkre return (NULL); 509*2b4a7802SBaban Kenkre if ((s = malloc(bval->bv_len + 1)) == NULL) 510*2b4a7802SBaban Kenkre return (NULL); 511*2b4a7802SBaban Kenkre (void) snprintf(s, bval->bv_len + 1, "%.*s", bval->bv_len, 512*2b4a7802SBaban Kenkre bval->bv_val); 513*2b4a7802SBaban Kenkre return (s); 514*2b4a7802SBaban Kenkre } 515*2b4a7802SBaban Kenkre 516*2b4a7802SBaban Kenkre /*ARGSUSED*/ 517*2b4a7802SBaban Kenkre static 518*2b4a7802SBaban Kenkre int 519*2b4a7802SBaban Kenkre saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) 520*2b4a7802SBaban Kenkre { 521*2b4a7802SBaban Kenkre sasl_interact_t *interact; 522*2b4a7802SBaban Kenkre 523*2b4a7802SBaban Kenkre if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE) 524*2b4a7802SBaban Kenkre return (LDAP_PARAM_ERROR); 525*2b4a7802SBaban Kenkre 526*2b4a7802SBaban Kenkre /* There should be no extra arguemnts for SASL/GSSAPI authentication */ 527*2b4a7802SBaban Kenkre for (interact = prompts; interact->id != SASL_CB_LIST_END; 528*2b4a7802SBaban Kenkre interact++) { 529*2b4a7802SBaban Kenkre interact->result = NULL; 530*2b4a7802SBaban Kenkre interact->len = 0; 531*2b4a7802SBaban Kenkre } 532*2b4a7802SBaban Kenkre return (LDAP_SUCCESS); 533*2b4a7802SBaban Kenkre } 534*2b4a7802SBaban Kenkre 535*2b4a7802SBaban Kenkre 536*2b4a7802SBaban Kenkre #define ADCONN_TIME 300 537*2b4a7802SBaban Kenkre 538*2b4a7802SBaban Kenkre /* 539*2b4a7802SBaban Kenkre * Idle connection reaping side of connection management 540*2b4a7802SBaban Kenkre */ 541*2b4a7802SBaban Kenkre void 542*2b4a7802SBaban Kenkre adutils_reap_idle_connections() 543*2b4a7802SBaban Kenkre { 544*2b4a7802SBaban Kenkre adutils_host_t *adh; 545*2b4a7802SBaban Kenkre time_t now; 546*2b4a7802SBaban Kenkre 547*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 548*2b4a7802SBaban Kenkre now = time(NULL); 549*2b4a7802SBaban Kenkre for (adh = host_head; adh != NULL; adh = adh->next) { 550*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 551*2b4a7802SBaban Kenkre if (adh->ref == 0 && adh->idletime != 0 && 552*2b4a7802SBaban Kenkre adh->idletime + ADCONN_TIME < now) { 553*2b4a7802SBaban Kenkre if (adh->ld) { 554*2b4a7802SBaban Kenkre (void) ldap_unbind(adh->ld); 555*2b4a7802SBaban Kenkre adh->ld = NULL; 556*2b4a7802SBaban Kenkre adh->idletime = 0; 557*2b4a7802SBaban Kenkre adh->ref = 0; 558*2b4a7802SBaban Kenkre } 559*2b4a7802SBaban Kenkre } 560*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 561*2b4a7802SBaban Kenkre } 562*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 563*2b4a7802SBaban Kenkre } 564*2b4a7802SBaban Kenkre 565*2b4a7802SBaban Kenkre 566*2b4a7802SBaban Kenkre adutils_rc 567*2b4a7802SBaban Kenkre adutils_ad_alloc(adutils_ad_t **new_ad, const char *default_domain, 568*2b4a7802SBaban Kenkre adutils_ad_partition_t part) 569*2b4a7802SBaban Kenkre { 570*2b4a7802SBaban Kenkre adutils_ad_t *ad; 571*2b4a7802SBaban Kenkre 572*2b4a7802SBaban Kenkre *new_ad = NULL; 573*2b4a7802SBaban Kenkre 574*2b4a7802SBaban Kenkre if ((default_domain == NULL || *default_domain == '\0') && 575*2b4a7802SBaban Kenkre part != ADUTILS_AD_GLOBAL_CATALOG) 576*2b4a7802SBaban Kenkre return (ADUTILS_ERR_DOMAIN); 577*2b4a7802SBaban Kenkre if ((ad = calloc(1, sizeof (*ad))) == NULL) 578*2b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 579*2b4a7802SBaban Kenkre ad->ref = 1; 580*2b4a7802SBaban Kenkre ad->partition = part; 581*2b4a7802SBaban Kenkre if (default_domain == NULL) 582*2b4a7802SBaban Kenkre default_domain = ""; 583*2b4a7802SBaban Kenkre if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL) 584*2b4a7802SBaban Kenkre goto err; 585*2b4a7802SBaban Kenkre if (pthread_mutex_init(&ad->lock, NULL) != 0) 586*2b4a7802SBaban Kenkre goto err; 587*2b4a7802SBaban Kenkre *new_ad = ad; 588*2b4a7802SBaban Kenkre return (ADUTILS_SUCCESS); 589*2b4a7802SBaban Kenkre 590*2b4a7802SBaban Kenkre err: 591*2b4a7802SBaban Kenkre if (ad->dflt_w2k_dom != NULL) 592*2b4a7802SBaban Kenkre free(ad->dflt_w2k_dom); 593*2b4a7802SBaban Kenkre free(ad); 594*2b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 595*2b4a7802SBaban Kenkre } 596*2b4a7802SBaban Kenkre 597*2b4a7802SBaban Kenkre void 598*2b4a7802SBaban Kenkre adutils_ad_free(adutils_ad_t **ad) 599*2b4a7802SBaban Kenkre { 600*2b4a7802SBaban Kenkre adutils_host_t *p; 601*2b4a7802SBaban Kenkre adutils_host_t *prev; 602*2b4a7802SBaban Kenkre 603*2b4a7802SBaban Kenkre if (ad == NULL || *ad == NULL) 604*2b4a7802SBaban Kenkre return; 605*2b4a7802SBaban Kenkre 606*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&(*ad)->lock); 607*2b4a7802SBaban Kenkre 608*2b4a7802SBaban Kenkre if (atomic_dec_32_nv(&(*ad)->ref) > 0) { 609*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&(*ad)->lock); 610*2b4a7802SBaban Kenkre *ad = NULL; 611*2b4a7802SBaban Kenkre return; 612*2b4a7802SBaban Kenkre } 613*2b4a7802SBaban Kenkre 614*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 615*2b4a7802SBaban Kenkre prev = NULL; 616*2b4a7802SBaban Kenkre p = host_head; 617*2b4a7802SBaban Kenkre while (p != NULL) { 618*2b4a7802SBaban Kenkre if (p->owner != (*ad)) { 619*2b4a7802SBaban Kenkre prev = p; 620*2b4a7802SBaban Kenkre p = p->next; 621*2b4a7802SBaban Kenkre continue; 622*2b4a7802SBaban Kenkre } else { 623*2b4a7802SBaban Kenkre delete_ds((*ad), p->host, p->port); 624*2b4a7802SBaban Kenkre if (prev == NULL) 625*2b4a7802SBaban Kenkre p = host_head; 626*2b4a7802SBaban Kenkre else 627*2b4a7802SBaban Kenkre p = prev->next; 628*2b4a7802SBaban Kenkre } 629*2b4a7802SBaban Kenkre } 630*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 631*2b4a7802SBaban Kenkre 632*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&(*ad)->lock); 633*2b4a7802SBaban Kenkre (void) pthread_mutex_destroy(&(*ad)->lock); 634*2b4a7802SBaban Kenkre 635*2b4a7802SBaban Kenkre free((*ad)->dflt_w2k_dom); 636*2b4a7802SBaban Kenkre free(*ad); 637*2b4a7802SBaban Kenkre 638*2b4a7802SBaban Kenkre *ad = NULL; 639*2b4a7802SBaban Kenkre } 640*2b4a7802SBaban Kenkre 641*2b4a7802SBaban Kenkre static 642*2b4a7802SBaban Kenkre int 643*2b4a7802SBaban Kenkre open_conn(adutils_host_t *adh, int timeoutsecs) 644*2b4a7802SBaban Kenkre { 645*2b4a7802SBaban Kenkre int zero = 0; 646*2b4a7802SBaban Kenkre int ldversion, rc; 647*2b4a7802SBaban Kenkre int timeoutms = timeoutsecs * 1000; 648*2b4a7802SBaban Kenkre 649*2b4a7802SBaban Kenkre if (adh == NULL) 650*2b4a7802SBaban Kenkre return (0); 651*2b4a7802SBaban Kenkre 652*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 653*2b4a7802SBaban Kenkre 654*2b4a7802SBaban Kenkre if (!adh->dead && adh->ld != NULL) 655*2b4a7802SBaban Kenkre /* done! */ 656*2b4a7802SBaban Kenkre goto out; 657*2b4a7802SBaban Kenkre 658*2b4a7802SBaban Kenkre if (adh->ld != NULL) { 659*2b4a7802SBaban Kenkre (void) ldap_unbind(adh->ld); 660*2b4a7802SBaban Kenkre adh->ld = NULL; 661*2b4a7802SBaban Kenkre } 662*2b4a7802SBaban Kenkre adh->num_requests = 0; 663*2b4a7802SBaban Kenkre 664*2b4a7802SBaban Kenkre atomic_inc_64(&adh->generation); 665*2b4a7802SBaban Kenkre 666*2b4a7802SBaban Kenkre /* Open and bind an LDAP connection */ 667*2b4a7802SBaban Kenkre adh->ld = ldap_init(adh->host, adh->port); 668*2b4a7802SBaban Kenkre if (adh->ld == NULL) { 669*2b4a7802SBaban Kenkre idmapdlog(LOG_INFO, "ldap_init() to server " 670*2b4a7802SBaban Kenkre "%s port %d failed. (%s)", adh->host, 671*2b4a7802SBaban Kenkre adh->port, strerror(errno)); 672*2b4a7802SBaban Kenkre goto out; 673*2b4a7802SBaban Kenkre } 674*2b4a7802SBaban Kenkre ldversion = LDAP_VERSION3; 675*2b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion); 676*2b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 677*2b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero); 678*2b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero); 679*2b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms); 680*2b4a7802SBaban Kenkre (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 681*2b4a7802SBaban Kenkre rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */, 682*2b4a7802SBaban Kenkre adh->saslmech, NULL, NULL, adh->saslflags, &saslcallback, 683*2b4a7802SBaban Kenkre NULL); 684*2b4a7802SBaban Kenkre 685*2b4a7802SBaban Kenkre if (rc != LDAP_SUCCESS) { 686*2b4a7802SBaban Kenkre (void) ldap_unbind(adh->ld); 687*2b4a7802SBaban Kenkre adh->ld = NULL; 688*2b4a7802SBaban Kenkre idmapdlog(LOG_INFO, "ldap_sasl_interactive_bind_s() to server " 689*2b4a7802SBaban Kenkre "%s port %d failed. (%s)", adh->host, adh->port, 690*2b4a7802SBaban Kenkre ldap_err2string(rc)); 691*2b4a7802SBaban Kenkre } 692*2b4a7802SBaban Kenkre 693*2b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, "Using global catalog server %s:%d", 694*2b4a7802SBaban Kenkre adh->host, adh->port); 695*2b4a7802SBaban Kenkre 696*2b4a7802SBaban Kenkre out: 697*2b4a7802SBaban Kenkre if (adh->ld != NULL) { 698*2b4a7802SBaban Kenkre atomic_inc_32(&adh->ref); 699*2b4a7802SBaban Kenkre adh->idletime = time(NULL); 700*2b4a7802SBaban Kenkre adh->dead = 0; 701*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 702*2b4a7802SBaban Kenkre return (1); 703*2b4a7802SBaban Kenkre } 704*2b4a7802SBaban Kenkre 705*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 706*2b4a7802SBaban Kenkre return (0); 707*2b4a7802SBaban Kenkre } 708*2b4a7802SBaban Kenkre 709*2b4a7802SBaban Kenkre 710*2b4a7802SBaban Kenkre /* 711*2b4a7802SBaban Kenkre * Connection management: find an open connection or open one 712*2b4a7802SBaban Kenkre */ 713*2b4a7802SBaban Kenkre static 714*2b4a7802SBaban Kenkre adutils_host_t * 715*2b4a7802SBaban Kenkre get_conn(adutils_ad_t *ad) 716*2b4a7802SBaban Kenkre { 717*2b4a7802SBaban Kenkre adutils_host_t *adh = NULL; 718*2b4a7802SBaban Kenkre int tries; 719*2b4a7802SBaban Kenkre int dscount = 0; 720*2b4a7802SBaban Kenkre int timeoutsecs = ADUTILS_LDAP_OPEN_TIMEOUT; 721*2b4a7802SBaban Kenkre 722*2b4a7802SBaban Kenkre retry: 723*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 724*2b4a7802SBaban Kenkre 725*2b4a7802SBaban Kenkre if (host_head == NULL) { 726*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 727*2b4a7802SBaban Kenkre goto out; 728*2b4a7802SBaban Kenkre } 729*2b4a7802SBaban Kenkre 730*2b4a7802SBaban Kenkre if (dscount == 0) { 731*2b4a7802SBaban Kenkre /* 732*2b4a7802SBaban Kenkre * First try: count the number of DSes. 733*2b4a7802SBaban Kenkre * 734*2b4a7802SBaban Kenkre * Integer overflow is not an issue -- we can't have so many 735*2b4a7802SBaban Kenkre * DSes because they won't fit even DNS over TCP, and SMF 736*2b4a7802SBaban Kenkre * shouldn't let you set so many. 737*2b4a7802SBaban Kenkre */ 738*2b4a7802SBaban Kenkre for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) { 739*2b4a7802SBaban Kenkre if (adh->owner == ad) 740*2b4a7802SBaban Kenkre dscount++; 741*2b4a7802SBaban Kenkre } 742*2b4a7802SBaban Kenkre 743*2b4a7802SBaban Kenkre if (dscount == 0) { 744*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 745*2b4a7802SBaban Kenkre goto out; 746*2b4a7802SBaban Kenkre } 747*2b4a7802SBaban Kenkre 748*2b4a7802SBaban Kenkre tries = dscount * 3; /* three tries per-ds */ 749*2b4a7802SBaban Kenkre 750*2b4a7802SBaban Kenkre /* 751*2b4a7802SBaban Kenkre * Begin round-robin at the next DS in the list after the last 752*2b4a7802SBaban Kenkre * one that we had a connection to, else start with the first 753*2b4a7802SBaban Kenkre * DS in the list. 754*2b4a7802SBaban Kenkre */ 755*2b4a7802SBaban Kenkre adh = ad->last_adh; 756*2b4a7802SBaban Kenkre } 757*2b4a7802SBaban Kenkre 758*2b4a7802SBaban Kenkre /* 759*2b4a7802SBaban Kenkre * Round-robin -- pick the next one on the list; if the list 760*2b4a7802SBaban Kenkre * changes on us, no big deal, we'll just potentially go 761*2b4a7802SBaban Kenkre * around the wrong number of times. 762*2b4a7802SBaban Kenkre */ 763*2b4a7802SBaban Kenkre for (;;) { 764*2b4a7802SBaban Kenkre if (adh != NULL && adh->ld != NULL && !adh->dead) 765*2b4a7802SBaban Kenkre break; 766*2b4a7802SBaban Kenkre if (adh == NULL || (adh = adh->next) == NULL) 767*2b4a7802SBaban Kenkre adh = host_head; 768*2b4a7802SBaban Kenkre if (adh->owner == ad) 769*2b4a7802SBaban Kenkre break; 770*2b4a7802SBaban Kenkre } 771*2b4a7802SBaban Kenkre 772*2b4a7802SBaban Kenkre ad->last_adh = adh; 773*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 774*2b4a7802SBaban Kenkre 775*2b4a7802SBaban Kenkre /* Found suitable DS, open it if not already opened */ 776*2b4a7802SBaban Kenkre if (open_conn(adh, timeoutsecs)) 777*2b4a7802SBaban Kenkre return (adh); 778*2b4a7802SBaban Kenkre 779*2b4a7802SBaban Kenkre tries--; 780*2b4a7802SBaban Kenkre if ((tries % dscount) == 0) 781*2b4a7802SBaban Kenkre timeoutsecs *= 2; 782*2b4a7802SBaban Kenkre if (tries > 0) 783*2b4a7802SBaban Kenkre goto retry; 784*2b4a7802SBaban Kenkre 785*2b4a7802SBaban Kenkre out: 786*2b4a7802SBaban Kenkre idmapdlog(LOG_NOTICE, "Couldn't open an LDAP connection to any global " 787*2b4a7802SBaban Kenkre "catalog server!"); 788*2b4a7802SBaban Kenkre return (NULL); 789*2b4a7802SBaban Kenkre } 790*2b4a7802SBaban Kenkre 791*2b4a7802SBaban Kenkre static 792*2b4a7802SBaban Kenkre void 793*2b4a7802SBaban Kenkre release_conn(adutils_host_t *adh) 794*2b4a7802SBaban Kenkre { 795*2b4a7802SBaban Kenkre int delete = 0; 796*2b4a7802SBaban Kenkre 797*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 798*2b4a7802SBaban Kenkre if (atomic_dec_32_nv(&adh->ref) == 0) { 799*2b4a7802SBaban Kenkre if (adh->owner == NULL) 800*2b4a7802SBaban Kenkre delete = 1; 801*2b4a7802SBaban Kenkre adh->idletime = time(NULL); 802*2b4a7802SBaban Kenkre } 803*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 804*2b4a7802SBaban Kenkre 805*2b4a7802SBaban Kenkre /* Free this host if its owner no longer exists. */ 806*2b4a7802SBaban Kenkre if (delete) { 807*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 808*2b4a7802SBaban Kenkre delete_ds(NULL, adh->host, adh->port); 809*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 810*2b4a7802SBaban Kenkre } 811*2b4a7802SBaban Kenkre } 812*2b4a7802SBaban Kenkre 813*2b4a7802SBaban Kenkre /* 814*2b4a7802SBaban Kenkre * Create a adutils_host_t, populate it and add it to the list of hosts. 815*2b4a7802SBaban Kenkre */ 816*2b4a7802SBaban Kenkre adutils_rc 817*2b4a7802SBaban Kenkre adutils_add_ds(adutils_ad_t *ad, const char *host, int port) 818*2b4a7802SBaban Kenkre { 819*2b4a7802SBaban Kenkre adutils_host_t *p; 820*2b4a7802SBaban Kenkre adutils_host_t *new = NULL; 821*2b4a7802SBaban Kenkre int ret; 822*2b4a7802SBaban Kenkre adutils_rc rc; 823*2b4a7802SBaban Kenkre 824*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adhostlock); 825*2b4a7802SBaban Kenkre for (p = host_head; p != NULL; p = p->next) { 826*2b4a7802SBaban Kenkre if (p->owner != ad) 827*2b4a7802SBaban Kenkre continue; 828*2b4a7802SBaban Kenkre 829*2b4a7802SBaban Kenkre if (strcmp(host, p->host) == 0 && p->port == port) { 830*2b4a7802SBaban Kenkre /* already added */ 831*2b4a7802SBaban Kenkre rc = ADUTILS_SUCCESS; 832*2b4a7802SBaban Kenkre goto err; 833*2b4a7802SBaban Kenkre } 834*2b4a7802SBaban Kenkre } 835*2b4a7802SBaban Kenkre 836*2b4a7802SBaban Kenkre rc = ADUTILS_ERR_MEMORY; 837*2b4a7802SBaban Kenkre 838*2b4a7802SBaban Kenkre /* add new entry */ 839*2b4a7802SBaban Kenkre new = (adutils_host_t *)calloc(1, sizeof (*new)); 840*2b4a7802SBaban Kenkre if (new == NULL) 841*2b4a7802SBaban Kenkre goto err; 842*2b4a7802SBaban Kenkre new->owner = ad; 843*2b4a7802SBaban Kenkre new->port = port; 844*2b4a7802SBaban Kenkre new->dead = 0; 845*2b4a7802SBaban Kenkre new->max_requests = 80; 846*2b4a7802SBaban Kenkre new->num_requests = 0; 847*2b4a7802SBaban Kenkre if ((new->host = strdup(host)) == NULL) 848*2b4a7802SBaban Kenkre goto err; 849*2b4a7802SBaban Kenkre new->saslflags = LDAP_SASL_INTERACTIVE; 850*2b4a7802SBaban Kenkre new->saslmech = "GSSAPI"; 851*2b4a7802SBaban Kenkre 852*2b4a7802SBaban Kenkre if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) { 853*2b4a7802SBaban Kenkre free(new->host); 854*2b4a7802SBaban Kenkre new->host = NULL; 855*2b4a7802SBaban Kenkre errno = ret; 856*2b4a7802SBaban Kenkre rc = ADUTILS_ERR_INTERNAL; 857*2b4a7802SBaban Kenkre goto err; 858*2b4a7802SBaban Kenkre } 859*2b4a7802SBaban Kenkre 860*2b4a7802SBaban Kenkre /* link in */ 861*2b4a7802SBaban Kenkre rc = ADUTILS_SUCCESS; 862*2b4a7802SBaban Kenkre new->next = host_head; 863*2b4a7802SBaban Kenkre host_head = new; 864*2b4a7802SBaban Kenkre 865*2b4a7802SBaban Kenkre err: 866*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adhostlock); 867*2b4a7802SBaban Kenkre 868*2b4a7802SBaban Kenkre if (rc != 0 && new != NULL) { 869*2b4a7802SBaban Kenkre if (new->host != NULL) { 870*2b4a7802SBaban Kenkre (void) pthread_mutex_destroy(&new->lock); 871*2b4a7802SBaban Kenkre free(new->host); 872*2b4a7802SBaban Kenkre } 873*2b4a7802SBaban Kenkre free(new); 874*2b4a7802SBaban Kenkre } 875*2b4a7802SBaban Kenkre 876*2b4a7802SBaban Kenkre return (rc); 877*2b4a7802SBaban Kenkre } 878*2b4a7802SBaban Kenkre 879*2b4a7802SBaban Kenkre /* 880*2b4a7802SBaban Kenkre * Free a DS configuration. 881*2b4a7802SBaban Kenkre * Caller must lock the adhostlock mutex 882*2b4a7802SBaban Kenkre */ 883*2b4a7802SBaban Kenkre static 884*2b4a7802SBaban Kenkre void 885*2b4a7802SBaban Kenkre delete_ds(adutils_ad_t *ad, const char *host, int port) 886*2b4a7802SBaban Kenkre { 887*2b4a7802SBaban Kenkre adutils_host_t **p, *q; 888*2b4a7802SBaban Kenkre 889*2b4a7802SBaban Kenkre for (p = &host_head; *p != NULL; p = &((*p)->next)) { 890*2b4a7802SBaban Kenkre if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 || 891*2b4a7802SBaban Kenkre (*p)->port != port) 892*2b4a7802SBaban Kenkre continue; 893*2b4a7802SBaban Kenkre /* found */ 894*2b4a7802SBaban Kenkre 895*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&((*p)->lock)); 896*2b4a7802SBaban Kenkre if ((*p)->ref > 0) { 897*2b4a7802SBaban Kenkre /* 898*2b4a7802SBaban Kenkre * Still in use. Set its owner to NULL so 899*2b4a7802SBaban Kenkre * that it can be freed when its ref count 900*2b4a7802SBaban Kenkre * becomes 0. 901*2b4a7802SBaban Kenkre */ 902*2b4a7802SBaban Kenkre (*p)->owner = NULL; 903*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&((*p)->lock)); 904*2b4a7802SBaban Kenkre break; 905*2b4a7802SBaban Kenkre } 906*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&((*p)->lock)); 907*2b4a7802SBaban Kenkre 908*2b4a7802SBaban Kenkre q = *p; 909*2b4a7802SBaban Kenkre *p = (*p)->next; 910*2b4a7802SBaban Kenkre 911*2b4a7802SBaban Kenkre (void) pthread_mutex_destroy(&q->lock); 912*2b4a7802SBaban Kenkre 913*2b4a7802SBaban Kenkre if (q->ld) 914*2b4a7802SBaban Kenkre (void) ldap_unbind(q->ld); 915*2b4a7802SBaban Kenkre if (q->host) 916*2b4a7802SBaban Kenkre free(q->host); 917*2b4a7802SBaban Kenkre free(q); 918*2b4a7802SBaban Kenkre break; 919*2b4a7802SBaban Kenkre } 920*2b4a7802SBaban Kenkre 921*2b4a7802SBaban Kenkre } 922*2b4a7802SBaban Kenkre 923*2b4a7802SBaban Kenkre adutils_rc 924*2b4a7802SBaban Kenkre adutils_lookup_batch_start(adutils_ad_t *ad, int nqueries, 925*2b4a7802SBaban Kenkre adutils_ldap_res_search_cb ldap_res_search_cb, 926*2b4a7802SBaban Kenkre void *ldap_res_search_argp, 927*2b4a7802SBaban Kenkre adutils_query_state_t **state) 928*2b4a7802SBaban Kenkre { 929*2b4a7802SBaban Kenkre adutils_query_state_t *new_state; 930*2b4a7802SBaban Kenkre adutils_host_t *adh = NULL; 931*2b4a7802SBaban Kenkre 932*2b4a7802SBaban Kenkre if (ad == NULL) 933*2b4a7802SBaban Kenkre return (ADUTILS_ERR_INTERNAL); 934*2b4a7802SBaban Kenkre 935*2b4a7802SBaban Kenkre *state = NULL; 936*2b4a7802SBaban Kenkre adh = get_conn(ad); 937*2b4a7802SBaban Kenkre if (adh == NULL) 938*2b4a7802SBaban Kenkre return (ADUTILS_ERR_RETRIABLE_NET_ERR); 939*2b4a7802SBaban Kenkre 940*2b4a7802SBaban Kenkre new_state = calloc(1, sizeof (adutils_query_state_t) + 941*2b4a7802SBaban Kenkre (nqueries - 1) * sizeof (adutils_q_t)); 942*2b4a7802SBaban Kenkre if (new_state == NULL) 943*2b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 944*2b4a7802SBaban Kenkre 945*2b4a7802SBaban Kenkre /* 946*2b4a7802SBaban Kenkre * Save default domain from the ad object so that we don't 947*2b4a7802SBaban Kenkre * have to access the 'ad' object later. 948*2b4a7802SBaban Kenkre */ 949*2b4a7802SBaban Kenkre new_state->default_domain = strdup(adh->owner->dflt_w2k_dom); 950*2b4a7802SBaban Kenkre if (new_state->default_domain == NULL) { 951*2b4a7802SBaban Kenkre free(new_state); 952*2b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 953*2b4a7802SBaban Kenkre } 954*2b4a7802SBaban Kenkre 955*2b4a7802SBaban Kenkre if (ad->partition == ADUTILS_AD_DATA) 956*2b4a7802SBaban Kenkre new_state->basedn = adutils_dns2dn(new_state->default_domain); 957*2b4a7802SBaban Kenkre else 958*2b4a7802SBaban Kenkre new_state->basedn = strdup(""); 959*2b4a7802SBaban Kenkre if (new_state->basedn == NULL) { 960*2b4a7802SBaban Kenkre free(new_state->default_domain); 961*2b4a7802SBaban Kenkre free(new_state); 962*2b4a7802SBaban Kenkre return (ADUTILS_ERR_MEMORY); 963*2b4a7802SBaban Kenkre } 964*2b4a7802SBaban Kenkre 965*2b4a7802SBaban Kenkre new_state->ref_cnt = 1; 966*2b4a7802SBaban Kenkre new_state->qadh = adh; 967*2b4a7802SBaban Kenkre new_state->qcount = nqueries; 968*2b4a7802SBaban Kenkre new_state->qadh_gen = adh->generation; 969*2b4a7802SBaban Kenkre new_state->qlastsent = 0; 970*2b4a7802SBaban Kenkre new_state->ldap_res_search_cb = ldap_res_search_cb; 971*2b4a7802SBaban Kenkre new_state->ldap_res_search_argp = ldap_res_search_argp; 972*2b4a7802SBaban Kenkre (void) pthread_cond_init(&new_state->cv, NULL); 973*2b4a7802SBaban Kenkre 974*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 975*2b4a7802SBaban Kenkre new_state->next = qstatehead; 976*2b4a7802SBaban Kenkre qstatehead = new_state; 977*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 978*2b4a7802SBaban Kenkre *state = new_state; 979*2b4a7802SBaban Kenkre 980*2b4a7802SBaban Kenkre return (ADUTILS_SUCCESS); 981*2b4a7802SBaban Kenkre } 982*2b4a7802SBaban Kenkre 983*2b4a7802SBaban Kenkre /* 984*2b4a7802SBaban Kenkre * Find the adutils_query_state_t to which a given LDAP result msgid on a 985*2b4a7802SBaban Kenkre * given connection belongs. This routine increaments the reference count 986*2b4a7802SBaban Kenkre * so that the object can not be freed. adutils_lookup_batch_unlock() 987*2b4a7802SBaban Kenkre * must be called to decreament the reference count. 988*2b4a7802SBaban Kenkre */ 989*2b4a7802SBaban Kenkre static 990*2b4a7802SBaban Kenkre int 991*2b4a7802SBaban Kenkre msgid2query(adutils_host_t *adh, int msgid, 992*2b4a7802SBaban Kenkre adutils_query_state_t **state, int *qid) 993*2b4a7802SBaban Kenkre { 994*2b4a7802SBaban Kenkre adutils_query_state_t *p; 995*2b4a7802SBaban Kenkre int i; 996*2b4a7802SBaban Kenkre int ret; 997*2b4a7802SBaban Kenkre 998*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 999*2b4a7802SBaban Kenkre for (p = qstatehead; p != NULL; p = p->next) { 1000*2b4a7802SBaban Kenkre if (p->qadh != adh || adh->generation != p->qadh_gen) 1001*2b4a7802SBaban Kenkre continue; 1002*2b4a7802SBaban Kenkre for (i = 0; i < p->qcount; i++) { 1003*2b4a7802SBaban Kenkre if ((p->queries[i]).msgid == msgid) { 1004*2b4a7802SBaban Kenkre if (!p->qdead) { 1005*2b4a7802SBaban Kenkre p->ref_cnt++; 1006*2b4a7802SBaban Kenkre *state = p; 1007*2b4a7802SBaban Kenkre *qid = i; 1008*2b4a7802SBaban Kenkre ret = 1; 1009*2b4a7802SBaban Kenkre } else 1010*2b4a7802SBaban Kenkre ret = 0; 1011*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 1012*2b4a7802SBaban Kenkre return (ret); 1013*2b4a7802SBaban Kenkre } 1014*2b4a7802SBaban Kenkre } 1015*2b4a7802SBaban Kenkre } 1016*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 1017*2b4a7802SBaban Kenkre return (0); 1018*2b4a7802SBaban Kenkre } 1019*2b4a7802SBaban Kenkre 1020*2b4a7802SBaban Kenkre static 1021*2b4a7802SBaban Kenkre int 1022*2b4a7802SBaban Kenkre check_for_binary_attrs(const char *attr) 1023*2b4a7802SBaban Kenkre { 1024*2b4a7802SBaban Kenkre int i; 1025*2b4a7802SBaban Kenkre for (i = 0; binattrs[i].name != NULL; i++) { 1026*2b4a7802SBaban Kenkre if (strcasecmp(binattrs[i].name, attr) == 0) 1027*2b4a7802SBaban Kenkre return (i); 1028*2b4a7802SBaban Kenkre } 1029*2b4a7802SBaban Kenkre return (-1); 1030*2b4a7802SBaban Kenkre } 1031*2b4a7802SBaban Kenkre 1032*2b4a7802SBaban Kenkre static 1033*2b4a7802SBaban Kenkre void 1034*2b4a7802SBaban Kenkre free_entry(adutils_entry_t *entry) 1035*2b4a7802SBaban Kenkre { 1036*2b4a7802SBaban Kenkre int i, j; 1037*2b4a7802SBaban Kenkre adutils_attr_t *ap; 1038*2b4a7802SBaban Kenkre 1039*2b4a7802SBaban Kenkre if (entry == NULL) 1040*2b4a7802SBaban Kenkre return; 1041*2b4a7802SBaban Kenkre if (entry->attr_nvpairs == NULL) { 1042*2b4a7802SBaban Kenkre free(entry); 1043*2b4a7802SBaban Kenkre return; 1044*2b4a7802SBaban Kenkre } 1045*2b4a7802SBaban Kenkre for (i = 0; i < entry->num_nvpairs; i++) { 1046*2b4a7802SBaban Kenkre ap = &entry->attr_nvpairs[i]; 1047*2b4a7802SBaban Kenkre if (ap->attr_name == NULL) { 1048*2b4a7802SBaban Kenkre ldap_value_free(ap->attr_values); 1049*2b4a7802SBaban Kenkre continue; 1050*2b4a7802SBaban Kenkre } 1051*2b4a7802SBaban Kenkre if (check_for_binary_attrs(ap->attr_name) >= 0) { 1052*2b4a7802SBaban Kenkre free(ap->attr_name); 1053*2b4a7802SBaban Kenkre if (ap->attr_values == NULL) 1054*2b4a7802SBaban Kenkre continue; 1055*2b4a7802SBaban Kenkre for (j = 0; j < ap->num_values; j++) 1056*2b4a7802SBaban Kenkre free(ap->attr_values[j]); 1057*2b4a7802SBaban Kenkre free(ap->attr_values); 1058*2b4a7802SBaban Kenkre } else if (strcasecmp(ap->attr_name, "dn") == 0) { 1059*2b4a7802SBaban Kenkre free(ap->attr_name); 1060*2b4a7802SBaban Kenkre ldap_memfree(ap->attr_values[0]); 1061*2b4a7802SBaban Kenkre free(ap->attr_values); 1062*2b4a7802SBaban Kenkre } else { 1063*2b4a7802SBaban Kenkre free(ap->attr_name); 1064*2b4a7802SBaban Kenkre ldap_value_free(ap->attr_values); 1065*2b4a7802SBaban Kenkre } 1066*2b4a7802SBaban Kenkre } 1067*2b4a7802SBaban Kenkre free(entry->attr_nvpairs); 1068*2b4a7802SBaban Kenkre free(entry); 1069*2b4a7802SBaban Kenkre } 1070*2b4a7802SBaban Kenkre 1071*2b4a7802SBaban Kenkre void 1072*2b4a7802SBaban Kenkre adutils_freeresult(adutils_result_t **result) 1073*2b4a7802SBaban Kenkre { 1074*2b4a7802SBaban Kenkre adutils_entry_t *e, *next; 1075*2b4a7802SBaban Kenkre 1076*2b4a7802SBaban Kenkre if (result == NULL || *result == NULL) 1077*2b4a7802SBaban Kenkre return; 1078*2b4a7802SBaban Kenkre if ((*result)->entries == NULL) { 1079*2b4a7802SBaban Kenkre free(*result); 1080*2b4a7802SBaban Kenkre *result = NULL; 1081*2b4a7802SBaban Kenkre return; 1082*2b4a7802SBaban Kenkre } 1083*2b4a7802SBaban Kenkre for (e = (*result)->entries; e != NULL; e = next) { 1084*2b4a7802SBaban Kenkre next = e->next; 1085*2b4a7802SBaban Kenkre free_entry(e); 1086*2b4a7802SBaban Kenkre } 1087*2b4a7802SBaban Kenkre free(*result); 1088*2b4a7802SBaban Kenkre *result = NULL; 1089*2b4a7802SBaban Kenkre } 1090*2b4a7802SBaban Kenkre 1091*2b4a7802SBaban Kenkre const adutils_entry_t * 1092*2b4a7802SBaban Kenkre adutils_getfirstentry(adutils_result_t *result) 1093*2b4a7802SBaban Kenkre { 1094*2b4a7802SBaban Kenkre if (result != NULL) 1095*2b4a7802SBaban Kenkre return (result->entries); 1096*2b4a7802SBaban Kenkre return (NULL); 1097*2b4a7802SBaban Kenkre } 1098*2b4a7802SBaban Kenkre 1099*2b4a7802SBaban Kenkre 1100*2b4a7802SBaban Kenkre char ** 1101*2b4a7802SBaban Kenkre adutils_getattr(const adutils_entry_t *entry, const char *attrname) 1102*2b4a7802SBaban Kenkre { 1103*2b4a7802SBaban Kenkre int i; 1104*2b4a7802SBaban Kenkre adutils_attr_t *ap; 1105*2b4a7802SBaban Kenkre 1106*2b4a7802SBaban Kenkre if (entry == NULL || entry->attr_nvpairs == NULL) 1107*2b4a7802SBaban Kenkre return (NULL); 1108*2b4a7802SBaban Kenkre for (i = 0; i < entry->num_nvpairs; i++) { 1109*2b4a7802SBaban Kenkre ap = &entry->attr_nvpairs[i]; 1110*2b4a7802SBaban Kenkre if (ap->attr_name != NULL && 1111*2b4a7802SBaban Kenkre strcasecmp(ap->attr_name, attrname) == 0) 1112*2b4a7802SBaban Kenkre return (ap->attr_values); 1113*2b4a7802SBaban Kenkre } 1114*2b4a7802SBaban Kenkre return (NULL); 1115*2b4a7802SBaban Kenkre } 1116*2b4a7802SBaban Kenkre 1117*2b4a7802SBaban Kenkre 1118*2b4a7802SBaban Kenkre /* 1119*2b4a7802SBaban Kenkre * Queue LDAP result for the given query. 1120*2b4a7802SBaban Kenkre * 1121*2b4a7802SBaban Kenkre * Return values: 1122*2b4a7802SBaban Kenkre * 0 success 1123*2b4a7802SBaban Kenkre * -1 ignore result 1124*2b4a7802SBaban Kenkre * -2 error 1125*2b4a7802SBaban Kenkre */ 1126*2b4a7802SBaban Kenkre static 1127*2b4a7802SBaban Kenkre int 1128*2b4a7802SBaban Kenkre make_entry(adutils_q_t *q, adutils_host_t *adh, LDAPMessage *search_res, 1129*2b4a7802SBaban Kenkre adutils_entry_t **entry) 1130*2b4a7802SBaban Kenkre { 1131*2b4a7802SBaban Kenkre BerElement *ber = NULL; 1132*2b4a7802SBaban Kenkre BerValue **bvalues = NULL; 1133*2b4a7802SBaban Kenkre char **strvalues; 1134*2b4a7802SBaban Kenkre char *attr = NULL, *dn = NULL, *domain = NULL; 1135*2b4a7802SBaban Kenkre adutils_entry_t *ep; 1136*2b4a7802SBaban Kenkre adutils_attr_t *ap; 1137*2b4a7802SBaban Kenkre int i, j, b, err = 0, ret = -2; 1138*2b4a7802SBaban Kenkre 1139*2b4a7802SBaban Kenkre *entry = NULL; 1140*2b4a7802SBaban Kenkre 1141*2b4a7802SBaban Kenkre /* Check that this is the domain that we were looking for */ 1142*2b4a7802SBaban Kenkre if ((dn = ldap_get_dn(adh->ld, search_res)) == NULL) 1143*2b4a7802SBaban Kenkre return (-2); 1144*2b4a7802SBaban Kenkre if ((domain = adutils_dn2dns(dn)) == NULL) { 1145*2b4a7802SBaban Kenkre ldap_memfree(dn); 1146*2b4a7802SBaban Kenkre return (-2); 1147*2b4a7802SBaban Kenkre } 1148*2b4a7802SBaban Kenkre if (q->edomain != NULL) { 1149*2b4a7802SBaban Kenkre if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER, 1150*2b4a7802SBaban Kenkre U8_UNICODE_LATEST, &err) != 0 || err != 0) { 1151*2b4a7802SBaban Kenkre ldap_memfree(dn); 1152*2b4a7802SBaban Kenkre free(domain); 1153*2b4a7802SBaban Kenkre return (-1); 1154*2b4a7802SBaban Kenkre } 1155*2b4a7802SBaban Kenkre } 1156*2b4a7802SBaban Kenkre free(domain); 1157*2b4a7802SBaban Kenkre 1158*2b4a7802SBaban Kenkre /* Allocate memory for the entry */ 1159*2b4a7802SBaban Kenkre if ((ep = calloc(1, sizeof (*ep))) == NULL) 1160*2b4a7802SBaban Kenkre goto out; 1161*2b4a7802SBaban Kenkre 1162*2b4a7802SBaban Kenkre /* For 'dn' */ 1163*2b4a7802SBaban Kenkre ep->num_nvpairs = 1; 1164*2b4a7802SBaban Kenkre 1165*2b4a7802SBaban Kenkre /* Count the number of name-value pairs for this entry */ 1166*2b4a7802SBaban Kenkre for (attr = ldap_first_attribute(adh->ld, search_res, &ber); 1167*2b4a7802SBaban Kenkre attr != NULL; 1168*2b4a7802SBaban Kenkre attr = ldap_next_attribute(adh->ld, search_res, ber)) { 1169*2b4a7802SBaban Kenkre ep->num_nvpairs++; 1170*2b4a7802SBaban Kenkre ldap_memfree(attr); 1171*2b4a7802SBaban Kenkre } 1172*2b4a7802SBaban Kenkre ber_free(ber, 0); 1173*2b4a7802SBaban Kenkre ber = NULL; 1174*2b4a7802SBaban Kenkre 1175*2b4a7802SBaban Kenkre /* Allocate array for the attribute name-value pairs */ 1176*2b4a7802SBaban Kenkre ep->attr_nvpairs = calloc(ep->num_nvpairs, sizeof (*ep->attr_nvpairs)); 1177*2b4a7802SBaban Kenkre if (ep->attr_nvpairs == NULL) { 1178*2b4a7802SBaban Kenkre ep->num_nvpairs = 0; 1179*2b4a7802SBaban Kenkre goto out; 1180*2b4a7802SBaban Kenkre } 1181*2b4a7802SBaban Kenkre 1182*2b4a7802SBaban Kenkre /* For dn */ 1183*2b4a7802SBaban Kenkre ap = &ep->attr_nvpairs[0]; 1184*2b4a7802SBaban Kenkre if ((ap->attr_name = strdup("dn")) == NULL) 1185*2b4a7802SBaban Kenkre goto out; 1186*2b4a7802SBaban Kenkre ap->num_values = 1; 1187*2b4a7802SBaban Kenkre ap->attr_values = calloc(ap->num_values, sizeof (*ap->attr_values)); 1188*2b4a7802SBaban Kenkre if (ap->attr_values == NULL) { 1189*2b4a7802SBaban Kenkre ap->num_values = 0; 1190*2b4a7802SBaban Kenkre goto out; 1191*2b4a7802SBaban Kenkre } 1192*2b4a7802SBaban Kenkre ap->attr_values[0] = dn; 1193*2b4a7802SBaban Kenkre dn = NULL; 1194*2b4a7802SBaban Kenkre 1195*2b4a7802SBaban Kenkre for (attr = ldap_first_attribute(adh->ld, search_res, &ber), i = 1; 1196*2b4a7802SBaban Kenkre attr != NULL; 1197*2b4a7802SBaban Kenkre ldap_memfree(attr), i++, 1198*2b4a7802SBaban Kenkre attr = ldap_next_attribute(adh->ld, search_res, ber)) { 1199*2b4a7802SBaban Kenkre ap = &ep->attr_nvpairs[i]; 1200*2b4a7802SBaban Kenkre if ((ap->attr_name = strdup(attr)) == NULL) 1201*2b4a7802SBaban Kenkre goto out; 1202*2b4a7802SBaban Kenkre 1203*2b4a7802SBaban Kenkre if ((b = check_for_binary_attrs(attr)) >= 0) { 1204*2b4a7802SBaban Kenkre bvalues = 1205*2b4a7802SBaban Kenkre ldap_get_values_len(adh->ld, search_res, attr); 1206*2b4a7802SBaban Kenkre if (bvalues == NULL) 1207*2b4a7802SBaban Kenkre continue; 1208*2b4a7802SBaban Kenkre ap->num_values = ldap_count_values_len(bvalues); 1209*2b4a7802SBaban Kenkre if (ap->num_values == 0) { 1210*2b4a7802SBaban Kenkre ldap_value_free_len(bvalues); 1211*2b4a7802SBaban Kenkre bvalues = NULL; 1212*2b4a7802SBaban Kenkre continue; 1213*2b4a7802SBaban Kenkre } 1214*2b4a7802SBaban Kenkre ap->attr_values = calloc(ap->num_values, 1215*2b4a7802SBaban Kenkre sizeof (*ap->attr_values)); 1216*2b4a7802SBaban Kenkre if (ap->attr_values == NULL) { 1217*2b4a7802SBaban Kenkre ap->num_values = 0; 1218*2b4a7802SBaban Kenkre goto out; 1219*2b4a7802SBaban Kenkre } 1220*2b4a7802SBaban Kenkre for (j = 0; j < ap->num_values; j++) { 1221*2b4a7802SBaban Kenkre ap->attr_values[j] = 1222*2b4a7802SBaban Kenkre binattrs[b].ber2str(bvalues[j]); 1223*2b4a7802SBaban Kenkre if (ap->attr_values[j] == NULL) 1224*2b4a7802SBaban Kenkre goto out; 1225*2b4a7802SBaban Kenkre } 1226*2b4a7802SBaban Kenkre ldap_value_free_len(bvalues); 1227*2b4a7802SBaban Kenkre bvalues = NULL; 1228*2b4a7802SBaban Kenkre continue; 1229*2b4a7802SBaban Kenkre } 1230*2b4a7802SBaban Kenkre 1231*2b4a7802SBaban Kenkre strvalues = ldap_get_values(adh->ld, search_res, attr); 1232*2b4a7802SBaban Kenkre if (strvalues == NULL) 1233*2b4a7802SBaban Kenkre continue; 1234*2b4a7802SBaban Kenkre ap->num_values = ldap_count_values(strvalues); 1235*2b4a7802SBaban Kenkre if (ap->num_values == 0) { 1236*2b4a7802SBaban Kenkre ldap_value_free(strvalues); 1237*2b4a7802SBaban Kenkre continue; 1238*2b4a7802SBaban Kenkre } 1239*2b4a7802SBaban Kenkre ap->attr_values = strvalues; 1240*2b4a7802SBaban Kenkre } 1241*2b4a7802SBaban Kenkre 1242*2b4a7802SBaban Kenkre ret = 0; 1243*2b4a7802SBaban Kenkre out: 1244*2b4a7802SBaban Kenkre ldap_memfree(attr); 1245*2b4a7802SBaban Kenkre ldap_memfree(dn); 1246*2b4a7802SBaban Kenkre ber_free(ber, 0); 1247*2b4a7802SBaban Kenkre ldap_value_free_len(bvalues); 1248*2b4a7802SBaban Kenkre if (ret < 0) 1249*2b4a7802SBaban Kenkre free_entry(ep); 1250*2b4a7802SBaban Kenkre else 1251*2b4a7802SBaban Kenkre *entry = ep; 1252*2b4a7802SBaban Kenkre return (ret); 1253*2b4a7802SBaban Kenkre } 1254*2b4a7802SBaban Kenkre 1255*2b4a7802SBaban Kenkre /* 1256*2b4a7802SBaban Kenkre * Put the search result onto the given adutils_q_t. 1257*2b4a7802SBaban Kenkre * Returns: 0 success 1258*2b4a7802SBaban Kenkre * < 0 error 1259*2b4a7802SBaban Kenkre */ 1260*2b4a7802SBaban Kenkre static 1261*2b4a7802SBaban Kenkre int 1262*2b4a7802SBaban Kenkre add_entry(adutils_host_t *adh, adutils_q_t *q, LDAPMessage *search_res) 1263*2b4a7802SBaban Kenkre { 1264*2b4a7802SBaban Kenkre int ret = -1; 1265*2b4a7802SBaban Kenkre adutils_entry_t *entry = NULL; 1266*2b4a7802SBaban Kenkre adutils_result_t *res; 1267*2b4a7802SBaban Kenkre 1268*2b4a7802SBaban Kenkre ret = make_entry(q, adh, search_res, &entry); 1269*2b4a7802SBaban Kenkre if (ret < -1) { 1270*2b4a7802SBaban Kenkre *q->rc = ADUTILS_ERR_MEMORY; 1271*2b4a7802SBaban Kenkre goto out; 1272*2b4a7802SBaban Kenkre } else if (ret == -1) { 1273*2b4a7802SBaban Kenkre /* ignore result */ 1274*2b4a7802SBaban Kenkre goto out; 1275*2b4a7802SBaban Kenkre } 1276*2b4a7802SBaban Kenkre if (*q->result == NULL) { 1277*2b4a7802SBaban Kenkre res = calloc(1, sizeof (*res)); 1278*2b4a7802SBaban Kenkre if (res == NULL) { 1279*2b4a7802SBaban Kenkre *q->rc = ADUTILS_ERR_MEMORY; 1280*2b4a7802SBaban Kenkre goto out; 1281*2b4a7802SBaban Kenkre } 1282*2b4a7802SBaban Kenkre res->num_entries = 1; 1283*2b4a7802SBaban Kenkre res->entries = entry; 1284*2b4a7802SBaban Kenkre *q->result = res; 1285*2b4a7802SBaban Kenkre } else { 1286*2b4a7802SBaban Kenkre res = *q->result; 1287*2b4a7802SBaban Kenkre entry->next = res->entries; 1288*2b4a7802SBaban Kenkre res->entries = entry; 1289*2b4a7802SBaban Kenkre res->num_entries++; 1290*2b4a7802SBaban Kenkre } 1291*2b4a7802SBaban Kenkre *q->rc = ADUTILS_SUCCESS; 1292*2b4a7802SBaban Kenkre entry = NULL; 1293*2b4a7802SBaban Kenkre ret = 0; 1294*2b4a7802SBaban Kenkre 1295*2b4a7802SBaban Kenkre out: 1296*2b4a7802SBaban Kenkre free_entry(entry); 1297*2b4a7802SBaban Kenkre return (ret); 1298*2b4a7802SBaban Kenkre } 1299*2b4a7802SBaban Kenkre 1300*2b4a7802SBaban Kenkre /* 1301*2b4a7802SBaban Kenkre * Try to get a result; if there is one, find the corresponding 1302*2b4a7802SBaban Kenkre * adutils_q_t and process the result. 1303*2b4a7802SBaban Kenkre * 1304*2b4a7802SBaban Kenkre * Returns: 0 success 1305*2b4a7802SBaban Kenkre * -1 error 1306*2b4a7802SBaban Kenkre */ 1307*2b4a7802SBaban Kenkre static 1308*2b4a7802SBaban Kenkre int 1309*2b4a7802SBaban Kenkre get_adobject_batch(adutils_host_t *adh, struct timeval *timeout) 1310*2b4a7802SBaban Kenkre { 1311*2b4a7802SBaban Kenkre adutils_query_state_t *query_state; 1312*2b4a7802SBaban Kenkre LDAPMessage *res = NULL; 1313*2b4a7802SBaban Kenkre int rc, ret, msgid, qid; 1314*2b4a7802SBaban Kenkre adutils_q_t *que; 1315*2b4a7802SBaban Kenkre int num; 1316*2b4a7802SBaban Kenkre 1317*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&adh->lock); 1318*2b4a7802SBaban Kenkre if (adh->dead || adh->num_requests == 0) { 1319*2b4a7802SBaban Kenkre ret = (adh->dead) ? -1 : -2; 1320*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1321*2b4a7802SBaban Kenkre return (ret); 1322*2b4a7802SBaban Kenkre } 1323*2b4a7802SBaban Kenkre 1324*2b4a7802SBaban Kenkre /* Get one result */ 1325*2b4a7802SBaban Kenkre rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, timeout, &res); 1326*2b4a7802SBaban Kenkre if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) || 1327*2b4a7802SBaban Kenkre rc < 0) 1328*2b4a7802SBaban Kenkre adh->dead = 1; 1329*2b4a7802SBaban Kenkre 1330*2b4a7802SBaban Kenkre if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0) 1331*2b4a7802SBaban Kenkre adh->num_requests--; 1332*2b4a7802SBaban Kenkre if (adh->dead) { 1333*2b4a7802SBaban Kenkre num = adh->num_requests; 1334*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1335*2b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, 1336*2b4a7802SBaban Kenkre "AD ldap_result error - %d queued requests", num); 1337*2b4a7802SBaban Kenkre return (-1); 1338*2b4a7802SBaban Kenkre } 1339*2b4a7802SBaban Kenkre 1340*2b4a7802SBaban Kenkre switch (rc) { 1341*2b4a7802SBaban Kenkre case LDAP_RES_SEARCH_RESULT: 1342*2b4a7802SBaban Kenkre msgid = ldap_msgid(res); 1343*2b4a7802SBaban Kenkre if (msgid2query(adh, msgid, &query_state, &qid)) { 1344*2b4a7802SBaban Kenkre if (query_state->ldap_res_search_cb != NULL) { 1345*2b4a7802SBaban Kenkre /* 1346*2b4a7802SBaban Kenkre * We use the caller-provided callback 1347*2b4a7802SBaban Kenkre * to process the result. 1348*2b4a7802SBaban Kenkre */ 1349*2b4a7802SBaban Kenkre query_state->ldap_res_search_cb( 1350*2b4a7802SBaban Kenkre adh->ld, &res, rc, qid, 1351*2b4a7802SBaban Kenkre query_state->ldap_res_search_argp); 1352*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1353*2b4a7802SBaban Kenkre } else { 1354*2b4a7802SBaban Kenkre /* 1355*2b4a7802SBaban Kenkre * No callback. We fallback to our 1356*2b4a7802SBaban Kenkre * default behaviour. All the entries 1357*2b4a7802SBaban Kenkre * gotten from this search have been 1358*2b4a7802SBaban Kenkre * added to the result list during 1359*2b4a7802SBaban Kenkre * LDAP_RES_SEARCH_ENTRY (see below). 1360*2b4a7802SBaban Kenkre * Here we set the return status to 1361*2b4a7802SBaban Kenkre * notfound if the result is still empty. 1362*2b4a7802SBaban Kenkre */ 1363*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1364*2b4a7802SBaban Kenkre que = &(query_state->queries[qid]); 1365*2b4a7802SBaban Kenkre if (*que->result == NULL) 1366*2b4a7802SBaban Kenkre *que->rc = ADUTILS_ERR_NOTFOUND; 1367*2b4a7802SBaban Kenkre } 1368*2b4a7802SBaban Kenkre atomic_dec_32(&query_state->qinflight); 1369*2b4a7802SBaban Kenkre adutils_lookup_batch_unlock(&query_state); 1370*2b4a7802SBaban Kenkre } else { 1371*2b4a7802SBaban Kenkre num = adh->num_requests; 1372*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1373*2b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, 1374*2b4a7802SBaban Kenkre "AD cannot find message ID (%d) " 1375*2b4a7802SBaban Kenkre "- %d queued requests", 1376*2b4a7802SBaban Kenkre msgid, num); 1377*2b4a7802SBaban Kenkre } 1378*2b4a7802SBaban Kenkre (void) ldap_msgfree(res); 1379*2b4a7802SBaban Kenkre ret = 0; 1380*2b4a7802SBaban Kenkre break; 1381*2b4a7802SBaban Kenkre 1382*2b4a7802SBaban Kenkre case LDAP_RES_SEARCH_ENTRY: 1383*2b4a7802SBaban Kenkre msgid = ldap_msgid(res); 1384*2b4a7802SBaban Kenkre if (msgid2query(adh, msgid, &query_state, &qid)) { 1385*2b4a7802SBaban Kenkre if (query_state->ldap_res_search_cb != NULL) { 1386*2b4a7802SBaban Kenkre /* 1387*2b4a7802SBaban Kenkre * We use the caller-provided callback 1388*2b4a7802SBaban Kenkre * to process the entry. 1389*2b4a7802SBaban Kenkre */ 1390*2b4a7802SBaban Kenkre query_state->ldap_res_search_cb( 1391*2b4a7802SBaban Kenkre adh->ld, &res, rc, qid, 1392*2b4a7802SBaban Kenkre query_state->ldap_res_search_argp); 1393*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1394*2b4a7802SBaban Kenkre } else { 1395*2b4a7802SBaban Kenkre /* 1396*2b4a7802SBaban Kenkre * No callback. We fallback to our 1397*2b4a7802SBaban Kenkre * default behaviour. This entry 1398*2b4a7802SBaban Kenkre * will be added to the result list. 1399*2b4a7802SBaban Kenkre */ 1400*2b4a7802SBaban Kenkre que = &(query_state->queries[qid]); 1401*2b4a7802SBaban Kenkre rc = add_entry(adh, que, res); 1402*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1403*2b4a7802SBaban Kenkre if (rc < 0) { 1404*2b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, 1405*2b4a7802SBaban Kenkre "Failed to queue entry by " 1406*2b4a7802SBaban Kenkre "message ID (%d) " 1407*2b4a7802SBaban Kenkre "- %d queued requests", 1408*2b4a7802SBaban Kenkre msgid, num); 1409*2b4a7802SBaban Kenkre } 1410*2b4a7802SBaban Kenkre } 1411*2b4a7802SBaban Kenkre adutils_lookup_batch_unlock(&query_state); 1412*2b4a7802SBaban Kenkre } else { 1413*2b4a7802SBaban Kenkre num = adh->num_requests; 1414*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1415*2b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, 1416*2b4a7802SBaban Kenkre "AD cannot find message ID (%d) " 1417*2b4a7802SBaban Kenkre "- %d queued requests", 1418*2b4a7802SBaban Kenkre msgid, num); 1419*2b4a7802SBaban Kenkre } 1420*2b4a7802SBaban Kenkre (void) ldap_msgfree(res); 1421*2b4a7802SBaban Kenkre ret = 0; 1422*2b4a7802SBaban Kenkre break; 1423*2b4a7802SBaban Kenkre 1424*2b4a7802SBaban Kenkre case LDAP_RES_SEARCH_REFERENCE: 1425*2b4a7802SBaban Kenkre /* 1426*2b4a7802SBaban Kenkre * We have no need for these at the moment. Eventually, 1427*2b4a7802SBaban Kenkre * when we query things that we can't expect to find in 1428*2b4a7802SBaban Kenkre * the Global Catalog then we'll need to learn to follow 1429*2b4a7802SBaban Kenkre * references. 1430*2b4a7802SBaban Kenkre */ 1431*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1432*2b4a7802SBaban Kenkre (void) ldap_msgfree(res); 1433*2b4a7802SBaban Kenkre ret = 0; 1434*2b4a7802SBaban Kenkre break; 1435*2b4a7802SBaban Kenkre 1436*2b4a7802SBaban Kenkre default: 1437*2b4a7802SBaban Kenkre /* timeout or error; treat the same */ 1438*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&adh->lock); 1439*2b4a7802SBaban Kenkre ret = -1; 1440*2b4a7802SBaban Kenkre break; 1441*2b4a7802SBaban Kenkre } 1442*2b4a7802SBaban Kenkre 1443*2b4a7802SBaban Kenkre return (ret); 1444*2b4a7802SBaban Kenkre } 1445*2b4a7802SBaban Kenkre 1446*2b4a7802SBaban Kenkre /* 1447*2b4a7802SBaban Kenkre * This routine decreament the reference count of the 1448*2b4a7802SBaban Kenkre * adutils_query_state_t 1449*2b4a7802SBaban Kenkre */ 1450*2b4a7802SBaban Kenkre static void 1451*2b4a7802SBaban Kenkre adutils_lookup_batch_unlock(adutils_query_state_t **state) 1452*2b4a7802SBaban Kenkre { 1453*2b4a7802SBaban Kenkre /* 1454*2b4a7802SBaban Kenkre * Decrement reference count with qstatelock locked 1455*2b4a7802SBaban Kenkre */ 1456*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 1457*2b4a7802SBaban Kenkre (*state)->ref_cnt--; 1458*2b4a7802SBaban Kenkre /* 1459*2b4a7802SBaban Kenkre * If there are no references wakup the allocating thread 1460*2b4a7802SBaban Kenkre */ 1461*2b4a7802SBaban Kenkre if ((*state)->ref_cnt <= 1) 1462*2b4a7802SBaban Kenkre (void) pthread_cond_signal(&(*state)->cv); 1463*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 1464*2b4a7802SBaban Kenkre *state = NULL; 1465*2b4a7802SBaban Kenkre } 1466*2b4a7802SBaban Kenkre 1467*2b4a7802SBaban Kenkre /* 1468*2b4a7802SBaban Kenkre * This routine frees the adutils_query_state_t structure 1469*2b4a7802SBaban Kenkre * If the reference count is greater than 1 it waits 1470*2b4a7802SBaban Kenkre * for the other threads to finish using it. 1471*2b4a7802SBaban Kenkre */ 1472*2b4a7802SBaban Kenkre void 1473*2b4a7802SBaban Kenkre adutils_lookup_batch_release(adutils_query_state_t **state) 1474*2b4a7802SBaban Kenkre { 1475*2b4a7802SBaban Kenkre adutils_query_state_t **p; 1476*2b4a7802SBaban Kenkre int i; 1477*2b4a7802SBaban Kenkre 1478*2b4a7802SBaban Kenkre if (state == NULL || *state == NULL) 1479*2b4a7802SBaban Kenkre return; 1480*2b4a7802SBaban Kenkre 1481*2b4a7802SBaban Kenkre /* 1482*2b4a7802SBaban Kenkre * Set state to dead to stop further operations. 1483*2b4a7802SBaban Kenkre * Wait for reference count with qstatelock locked 1484*2b4a7802SBaban Kenkre * to get to one. 1485*2b4a7802SBaban Kenkre */ 1486*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 1487*2b4a7802SBaban Kenkre (*state)->qdead = 1; 1488*2b4a7802SBaban Kenkre while ((*state)->ref_cnt > 1) { 1489*2b4a7802SBaban Kenkre (void) pthread_cond_wait(&(*state)->cv, &qstatelock); 1490*2b4a7802SBaban Kenkre } 1491*2b4a7802SBaban Kenkre 1492*2b4a7802SBaban Kenkre /* Remove this state struct from the list of state structs */ 1493*2b4a7802SBaban Kenkre for (p = &qstatehead; *p != NULL; p = &(*p)->next) { 1494*2b4a7802SBaban Kenkre if (*p == (*state)) { 1495*2b4a7802SBaban Kenkre *p = (*state)->next; 1496*2b4a7802SBaban Kenkre break; 1497*2b4a7802SBaban Kenkre } 1498*2b4a7802SBaban Kenkre } 1499*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 1500*2b4a7802SBaban Kenkre (void) pthread_cond_destroy(&(*state)->cv); 1501*2b4a7802SBaban Kenkre release_conn((*state)->qadh); 1502*2b4a7802SBaban Kenkre 1503*2b4a7802SBaban Kenkre /* Clear results for queries that failed */ 1504*2b4a7802SBaban Kenkre for (i = 0; i < (*state)->qcount; i++) { 1505*2b4a7802SBaban Kenkre if (*(*state)->queries[i].rc != ADUTILS_SUCCESS) { 1506*2b4a7802SBaban Kenkre adutils_freeresult((*state)->queries[i].result); 1507*2b4a7802SBaban Kenkre } 1508*2b4a7802SBaban Kenkre } 1509*2b4a7802SBaban Kenkre free((*state)->default_domain); 1510*2b4a7802SBaban Kenkre free((*state)->basedn); 1511*2b4a7802SBaban Kenkre free(*state); 1512*2b4a7802SBaban Kenkre *state = NULL; 1513*2b4a7802SBaban Kenkre } 1514*2b4a7802SBaban Kenkre 1515*2b4a7802SBaban Kenkre 1516*2b4a7802SBaban Kenkre /* 1517*2b4a7802SBaban Kenkre * This routine waits for other threads using the 1518*2b4a7802SBaban Kenkre * adutils_query_state_t structure to finish. 1519*2b4a7802SBaban Kenkre * If the reference count is greater than 1 it waits 1520*2b4a7802SBaban Kenkre * for the other threads to finish using it. 1521*2b4a7802SBaban Kenkre */ 1522*2b4a7802SBaban Kenkre static 1523*2b4a7802SBaban Kenkre void 1524*2b4a7802SBaban Kenkre adutils_lookup_batch_wait(adutils_query_state_t *state) 1525*2b4a7802SBaban Kenkre { 1526*2b4a7802SBaban Kenkre /* 1527*2b4a7802SBaban Kenkre * Set state to dead to stop further operation. 1528*2b4a7802SBaban Kenkre * stating. 1529*2b4a7802SBaban Kenkre * Wait for reference count to get to one 1530*2b4a7802SBaban Kenkre * with qstatelock locked. 1531*2b4a7802SBaban Kenkre */ 1532*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&qstatelock); 1533*2b4a7802SBaban Kenkre state->qdead = 1; 1534*2b4a7802SBaban Kenkre while (state->ref_cnt > 1) { 1535*2b4a7802SBaban Kenkre (void) pthread_cond_wait(&state->cv, &qstatelock); 1536*2b4a7802SBaban Kenkre } 1537*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&qstatelock); 1538*2b4a7802SBaban Kenkre } 1539*2b4a7802SBaban Kenkre 1540*2b4a7802SBaban Kenkre /* 1541*2b4a7802SBaban Kenkre * Process active queries in the AD lookup batch and then finalize the 1542*2b4a7802SBaban Kenkre * result. 1543*2b4a7802SBaban Kenkre */ 1544*2b4a7802SBaban Kenkre adutils_rc 1545*2b4a7802SBaban Kenkre adutils_lookup_batch_end(adutils_query_state_t **state) 1546*2b4a7802SBaban Kenkre { 1547*2b4a7802SBaban Kenkre int rc = LDAP_SUCCESS; 1548*2b4a7802SBaban Kenkre adutils_rc ad_rc = ADUTILS_SUCCESS; 1549*2b4a7802SBaban Kenkre struct timeval tv; 1550*2b4a7802SBaban Kenkre 1551*2b4a7802SBaban Kenkre tv.tv_sec = ADUTILS_SEARCH_TIMEOUT; 1552*2b4a7802SBaban Kenkre tv.tv_usec = 0; 1553*2b4a7802SBaban Kenkre 1554*2b4a7802SBaban Kenkre /* Process results until done or until timeout, if given */ 1555*2b4a7802SBaban Kenkre while ((*state)->qinflight > 0) { 1556*2b4a7802SBaban Kenkre if ((rc = get_adobject_batch((*state)->qadh, 1557*2b4a7802SBaban Kenkre &tv)) != 0) 1558*2b4a7802SBaban Kenkre break; 1559*2b4a7802SBaban Kenkre } 1560*2b4a7802SBaban Kenkre (*state)->qdead = 1; 1561*2b4a7802SBaban Kenkre /* Wait for other threads processing search result to finish */ 1562*2b4a7802SBaban Kenkre adutils_lookup_batch_wait(*state); 1563*2b4a7802SBaban Kenkre if (rc == -1 || (*state)->qinflight != 0) 1564*2b4a7802SBaban Kenkre ad_rc = ADUTILS_ERR_RETRIABLE_NET_ERR; 1565*2b4a7802SBaban Kenkre adutils_lookup_batch_release(state); 1566*2b4a7802SBaban Kenkre return (ad_rc); 1567*2b4a7802SBaban Kenkre } 1568*2b4a7802SBaban Kenkre 1569*2b4a7802SBaban Kenkre const char * 1570*2b4a7802SBaban Kenkre adutils_lookup_batch_getdefdomain(adutils_query_state_t *state) 1571*2b4a7802SBaban Kenkre { 1572*2b4a7802SBaban Kenkre return (state->default_domain); 1573*2b4a7802SBaban Kenkre } 1574*2b4a7802SBaban Kenkre 1575*2b4a7802SBaban Kenkre /* 1576*2b4a7802SBaban Kenkre * Send one prepared search, queue up msgid, process what results are 1577*2b4a7802SBaban Kenkre * available 1578*2b4a7802SBaban Kenkre */ 1579*2b4a7802SBaban Kenkre adutils_rc 1580*2b4a7802SBaban Kenkre adutils_lookup_batch_add(adutils_query_state_t *state, 1581*2b4a7802SBaban Kenkre const char *filter, const char **attrs, const char *edomain, 1582*2b4a7802SBaban Kenkre adutils_result_t **result, adutils_rc *rc) 1583*2b4a7802SBaban Kenkre { 1584*2b4a7802SBaban Kenkre adutils_rc retcode = ADUTILS_SUCCESS; 1585*2b4a7802SBaban Kenkre int lrc, qid; 1586*2b4a7802SBaban Kenkre int num; 1587*2b4a7802SBaban Kenkre int dead; 1588*2b4a7802SBaban Kenkre struct timeval tv; 1589*2b4a7802SBaban Kenkre adutils_q_t *q; 1590*2b4a7802SBaban Kenkre 1591*2b4a7802SBaban Kenkre qid = atomic_inc_32_nv(&state->qlastsent) - 1; 1592*2b4a7802SBaban Kenkre q = &(state->queries[qid]); 1593*2b4a7802SBaban Kenkre 1594*2b4a7802SBaban Kenkre /* 1595*2b4a7802SBaban Kenkre * Remember the expected domain so we can check the results 1596*2b4a7802SBaban Kenkre * against it 1597*2b4a7802SBaban Kenkre */ 1598*2b4a7802SBaban Kenkre q->edomain = edomain; 1599*2b4a7802SBaban Kenkre 1600*2b4a7802SBaban Kenkre /* Remember where to put the results */ 1601*2b4a7802SBaban Kenkre q->result = result; 1602*2b4a7802SBaban Kenkre q->rc = rc; 1603*2b4a7802SBaban Kenkre 1604*2b4a7802SBaban Kenkre /* 1605*2b4a7802SBaban Kenkre * Provide sane defaults for the results in case we never hear 1606*2b4a7802SBaban Kenkre * back from the DS before closing the connection. 1607*2b4a7802SBaban Kenkre */ 1608*2b4a7802SBaban Kenkre *rc = ADUTILS_ERR_RETRIABLE_NET_ERR; 1609*2b4a7802SBaban Kenkre if (result != NULL) 1610*2b4a7802SBaban Kenkre *result = NULL; 1611*2b4a7802SBaban Kenkre 1612*2b4a7802SBaban Kenkre /* Check the number of queued requests first */ 1613*2b4a7802SBaban Kenkre tv.tv_sec = ADUTILS_SEARCH_TIMEOUT; 1614*2b4a7802SBaban Kenkre tv.tv_usec = 0; 1615*2b4a7802SBaban Kenkre while (!state->qadh->dead && 1616*2b4a7802SBaban Kenkre state->qadh->num_requests > state->qadh->max_requests) { 1617*2b4a7802SBaban Kenkre if (get_adobject_batch(state->qadh, &tv) != 0) 1618*2b4a7802SBaban Kenkre break; 1619*2b4a7802SBaban Kenkre } 1620*2b4a7802SBaban Kenkre 1621*2b4a7802SBaban Kenkre /* Send this lookup, don't wait for a result here */ 1622*2b4a7802SBaban Kenkre lrc = LDAP_SUCCESS; 1623*2b4a7802SBaban Kenkre (void) pthread_mutex_lock(&state->qadh->lock); 1624*2b4a7802SBaban Kenkre 1625*2b4a7802SBaban Kenkre if (!state->qadh->dead) { 1626*2b4a7802SBaban Kenkre state->qadh->idletime = time(NULL); 1627*2b4a7802SBaban Kenkre lrc = ldap_search_ext(state->qadh->ld, state->basedn, 1628*2b4a7802SBaban Kenkre LDAP_SCOPE_SUBTREE, filter, (char **)attrs, 1629*2b4a7802SBaban Kenkre 0, NULL, NULL, NULL, -1, &q->msgid); 1630*2b4a7802SBaban Kenkre 1631*2b4a7802SBaban Kenkre if (lrc == LDAP_SUCCESS) { 1632*2b4a7802SBaban Kenkre state->qadh->num_requests++; 1633*2b4a7802SBaban Kenkre } else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE || 1634*2b4a7802SBaban Kenkre lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN || 1635*2b4a7802SBaban Kenkre lrc == LDAP_UNWILLING_TO_PERFORM) { 1636*2b4a7802SBaban Kenkre retcode = ADUTILS_ERR_RETRIABLE_NET_ERR; 1637*2b4a7802SBaban Kenkre state->qadh->dead = 1; 1638*2b4a7802SBaban Kenkre } else { 1639*2b4a7802SBaban Kenkre retcode = ADUTILS_ERR_OTHER; 1640*2b4a7802SBaban Kenkre state->qadh->dead = 1; 1641*2b4a7802SBaban Kenkre } 1642*2b4a7802SBaban Kenkre } 1643*2b4a7802SBaban Kenkre dead = state->qadh->dead; 1644*2b4a7802SBaban Kenkre num = state->qadh->num_requests; 1645*2b4a7802SBaban Kenkre (void) pthread_mutex_unlock(&state->qadh->lock); 1646*2b4a7802SBaban Kenkre 1647*2b4a7802SBaban Kenkre if (dead) { 1648*2b4a7802SBaban Kenkre if (lrc != LDAP_SUCCESS) 1649*2b4a7802SBaban Kenkre idmapdlog(LOG_DEBUG, 1650*2b4a7802SBaban Kenkre "AD ldap_search_ext error (%s) " 1651*2b4a7802SBaban Kenkre "- %d queued requests", 1652*2b4a7802SBaban Kenkre ldap_err2string(lrc), num); 1653*2b4a7802SBaban Kenkre return (retcode); 1654*2b4a7802SBaban Kenkre } 1655*2b4a7802SBaban Kenkre 1656*2b4a7802SBaban Kenkre atomic_inc_32(&state->qinflight); 1657*2b4a7802SBaban Kenkre 1658*2b4a7802SBaban Kenkre /* 1659*2b4a7802SBaban Kenkre * Reap as many requests as we can _without_ waiting to prevent 1660*2b4a7802SBaban Kenkre * any possible TCP socket buffer starvation deadlocks. 1661*2b4a7802SBaban Kenkre */ 1662*2b4a7802SBaban Kenkre (void) memset(&tv, 0, sizeof (tv)); 1663*2b4a7802SBaban Kenkre while (get_adobject_batch(state->qadh, &tv) == 0) 1664*2b4a7802SBaban Kenkre ; 1665*2b4a7802SBaban Kenkre 1666*2b4a7802SBaban Kenkre return (ADUTILS_SUCCESS); 1667*2b4a7802SBaban Kenkre } 1668*2b4a7802SBaban Kenkre 1669*2b4a7802SBaban Kenkre /* 1670*2b4a7802SBaban Kenkre * Single AD lookup request implemented on top of the batch API. 1671*2b4a7802SBaban Kenkre */ 1672*2b4a7802SBaban Kenkre adutils_rc 1673*2b4a7802SBaban Kenkre adutils_lookup(adutils_ad_t *ad, const char *filter, const char **attrs, 1674*2b4a7802SBaban Kenkre const char *domain, adutils_result_t **result) 1675*2b4a7802SBaban Kenkre { 1676*2b4a7802SBaban Kenkre adutils_rc rc, brc; 1677*2b4a7802SBaban Kenkre adutils_query_state_t *qs; 1678*2b4a7802SBaban Kenkre 1679*2b4a7802SBaban Kenkre rc = adutils_lookup_batch_start(ad, 1, NULL, NULL, &qs); 1680*2b4a7802SBaban Kenkre if (rc != ADUTILS_SUCCESS) 1681*2b4a7802SBaban Kenkre return (rc); 1682*2b4a7802SBaban Kenkre 1683*2b4a7802SBaban Kenkre rc = adutils_lookup_batch_add(qs, filter, attrs, domain, result, &brc); 1684*2b4a7802SBaban Kenkre if (rc != ADUTILS_SUCCESS) { 1685*2b4a7802SBaban Kenkre adutils_lookup_batch_release(&qs); 1686*2b4a7802SBaban Kenkre return (rc); 1687*2b4a7802SBaban Kenkre } 1688*2b4a7802SBaban Kenkre 1689*2b4a7802SBaban Kenkre rc = adutils_lookup_batch_end(&qs); 1690*2b4a7802SBaban Kenkre if (rc != ADUTILS_SUCCESS) 1691*2b4a7802SBaban Kenkre return (rc); 1692*2b4a7802SBaban Kenkre return (brc); 1693*2b4a7802SBaban Kenkre } 1694