1*c5c4113dSnw141292 /* 2*c5c4113dSnw141292 * CDDL HEADER START 3*c5c4113dSnw141292 * 4*c5c4113dSnw141292 * The contents of this file are subject to the terms of the 5*c5c4113dSnw141292 * Common Development and Distribution License (the "License"). 6*c5c4113dSnw141292 * You may not use this file except in compliance with the License. 7*c5c4113dSnw141292 * 8*c5c4113dSnw141292 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*c5c4113dSnw141292 * or http://www.opensolaris.org/os/licensing. 10*c5c4113dSnw141292 * See the License for the specific language governing permissions 11*c5c4113dSnw141292 * and limitations under the License. 12*c5c4113dSnw141292 * 13*c5c4113dSnw141292 * When distributing Covered Code, include this CDDL HEADER in each 14*c5c4113dSnw141292 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*c5c4113dSnw141292 * If applicable, add the following below this CDDL HEADER, with the 16*c5c4113dSnw141292 * fields enclosed by brackets "[]" replaced with your own identifying 17*c5c4113dSnw141292 * information: Portions Copyright [yyyy] [name of copyright owner] 18*c5c4113dSnw141292 * 19*c5c4113dSnw141292 * CDDL HEADER END 20*c5c4113dSnw141292 */ 21*c5c4113dSnw141292 22*c5c4113dSnw141292 /* 23*c5c4113dSnw141292 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24*c5c4113dSnw141292 * Use is subject to license terms. 25*c5c4113dSnw141292 */ 26*c5c4113dSnw141292 27*c5c4113dSnw141292 #pragma ident "%Z%%M% %I% %E% SMI" 28*c5c4113dSnw141292 29*c5c4113dSnw141292 /* 30*c5c4113dSnw141292 * Processes name2sid & sid2name batched lookups for a given user or 31*c5c4113dSnw141292 * computer from an AD Directory server using GSSAPI authentication 32*c5c4113dSnw141292 */ 33*c5c4113dSnw141292 34*c5c4113dSnw141292 #include <stdio.h> 35*c5c4113dSnw141292 #include <stdlib.h> 36*c5c4113dSnw141292 #include <alloca.h> 37*c5c4113dSnw141292 #include <string.h> 38*c5c4113dSnw141292 #include <strings.h> 39*c5c4113dSnw141292 #include <lber.h> 40*c5c4113dSnw141292 #include <ldap.h> 41*c5c4113dSnw141292 #include <sasl/sasl.h> 42*c5c4113dSnw141292 #include <string.h> 43*c5c4113dSnw141292 #include <ctype.h> 44*c5c4113dSnw141292 #include <pthread.h> 45*c5c4113dSnw141292 #include <synch.h> 46*c5c4113dSnw141292 #include <atomic.h> 47*c5c4113dSnw141292 #include <errno.h> 48*c5c4113dSnw141292 #include <assert.h> 49*c5c4113dSnw141292 #include <limits.h> 50*c5c4113dSnw141292 #include "idmapd.h" 51*c5c4113dSnw141292 52*c5c4113dSnw141292 /* 53*c5c4113dSnw141292 * Internal data structures for this code 54*c5c4113dSnw141292 */ 55*c5c4113dSnw141292 56*c5c4113dSnw141292 /* Attribute names and filter format strings */ 57*c5c4113dSnw141292 #define OBJECTSID "objectSid" 58*c5c4113dSnw141292 #define OBJECTSIDFILTER "(objectSid=%s)" 59*c5c4113dSnw141292 #define SAMACCOUNTNAME "sAMAccountName" 60*c5c4113dSnw141292 #define SANFILTER "(sAMAccountName=%.*s)" 61*c5c4113dSnw141292 #define OBJECTCLASS "objectClass" 62*c5c4113dSnw141292 63*c5c4113dSnw141292 /* 64*c5c4113dSnw141292 * This should really be in some <sys/sid.h> file or so; we have a 65*c5c4113dSnw141292 * private version of sid_t, and so must other components of ON until we 66*c5c4113dSnw141292 * rationalize this. 67*c5c4113dSnw141292 */ 68*c5c4113dSnw141292 typedef struct sid { 69*c5c4113dSnw141292 uchar_t version; 70*c5c4113dSnw141292 uchar_t sub_authority_count; 71*c5c4113dSnw141292 uint64_t authority; /* really, 48-bits */ 72*c5c4113dSnw141292 rid_t sub_authorities[SID_MAX_SUB_AUTHORITIES]; 73*c5c4113dSnw141292 } sid_t; 74*c5c4113dSnw141292 75*c5c4113dSnw141292 /* A single DS */ 76*c5c4113dSnw141292 typedef struct ad_host { 77*c5c4113dSnw141292 struct ad_host *next; 78*c5c4113dSnw141292 ad_t *owner; /* ad_t to which this belongs */ 79*c5c4113dSnw141292 pthread_mutex_t lock; 80*c5c4113dSnw141292 LDAP *ld; /* LDAP connection */ 81*c5c4113dSnw141292 uint32_t ref; /* ref count */ 82*c5c4113dSnw141292 time_t idletime; /* time since last activity */ 83*c5c4113dSnw141292 int dead; /* error on LDAP connection */ 84*c5c4113dSnw141292 /* 85*c5c4113dSnw141292 * Used to distinguish between different instances of LDAP 86*c5c4113dSnw141292 * connections to this same DS. We need this so we never mix up 87*c5c4113dSnw141292 * results for a given msgID from one connection with those of 88*c5c4113dSnw141292 * another earlier connection where two batch state structures 89*c5c4113dSnw141292 * share this ad_host object but used different LDAP connections 90*c5c4113dSnw141292 * to send their LDAP searches. 91*c5c4113dSnw141292 */ 92*c5c4113dSnw141292 uint64_t generation; 93*c5c4113dSnw141292 94*c5c4113dSnw141292 /* LDAP DS info */ 95*c5c4113dSnw141292 char *host; 96*c5c4113dSnw141292 int port; 97*c5c4113dSnw141292 98*c5c4113dSnw141292 /* hardwired to SASL GSSAPI only for now */ 99*c5c4113dSnw141292 char *saslmech; 100*c5c4113dSnw141292 unsigned saslflags; 101*c5c4113dSnw141292 } ad_host_t; 102*c5c4113dSnw141292 103*c5c4113dSnw141292 /* A set of DSs for a given AD partition; ad_t typedef comes from adutil.h */ 104*c5c4113dSnw141292 struct ad { 105*c5c4113dSnw141292 char *dflt_w2k_dom; /* used to qualify bare names */ 106*c5c4113dSnw141292 char *basedn; /* derived from dflt domain */ 107*c5c4113dSnw141292 pthread_mutex_t lock; 108*c5c4113dSnw141292 uint32_t ref; 109*c5c4113dSnw141292 idmap_ad_partition_t partition; /* Data or global catalog? */ 110*c5c4113dSnw141292 }; 111*c5c4113dSnw141292 112*c5c4113dSnw141292 /* 113*c5c4113dSnw141292 * A place to put the results of a batched (async) query 114*c5c4113dSnw141292 * 115*c5c4113dSnw141292 * There is one of these for every query added to a batch object 116*c5c4113dSnw141292 * (idmap_query_state, see below). 117*c5c4113dSnw141292 */ 118*c5c4113dSnw141292 typedef struct idmap_q { 119*c5c4113dSnw141292 char **result; /* name or stringified SID */ 120*c5c4113dSnw141292 char **domain; /* name of domain of object */ 121*c5c4113dSnw141292 rid_t *rid; /* for n2s, if not NULL */ 122*c5c4113dSnw141292 int *sid_type; /* if not NULL */ 123*c5c4113dSnw141292 idmap_retcode *rc; 124*c5c4113dSnw141292 int msgid; /* LDAP message ID */ 125*c5c4113dSnw141292 /* 126*c5c4113dSnw141292 * Bitfield containing state needed to know when we're done 127*c5c4113dSnw141292 * processing search results related to this query's LDAP 128*c5c4113dSnw141292 * searches. Mostly self-explanatory. 129*c5c4113dSnw141292 */ 130*c5c4113dSnw141292 uint16_t n2s : 1; /* name->SID or SID->name? */ 131*c5c4113dSnw141292 uint16_t got_reply : 1; 132*c5c4113dSnw141292 uint16_t got_results : 1; 133*c5c4113dSnw141292 uint16_t got_objectSid : 1; 134*c5c4113dSnw141292 uint16_t got_objectClass : 1; 135*c5c4113dSnw141292 uint16_t got_samAcctName : 1; 136*c5c4113dSnw141292 } idmap_q_t; 137*c5c4113dSnw141292 138*c5c4113dSnw141292 /* Batch context structure; typedef is in header file */ 139*c5c4113dSnw141292 struct idmap_query_state { 140*c5c4113dSnw141292 idmap_query_state_t *next; 141*c5c4113dSnw141292 int qcount; /* how many queries */ 142*c5c4113dSnw141292 uint32_t qlastsent; 143*c5c4113dSnw141292 uint32_t qinflight; /* how many queries in flight */ 144*c5c4113dSnw141292 uint16_t qdead; /* oops, lost LDAP connection */ 145*c5c4113dSnw141292 ad_host_t *qadh; /* LDAP connection */ 146*c5c4113dSnw141292 uint64_t qadh_gen; /* same as qadh->generation */ 147*c5c4113dSnw141292 idmap_q_t queries[1]; /* array of query results */ 148*c5c4113dSnw141292 }; 149*c5c4113dSnw141292 150*c5c4113dSnw141292 /* 151*c5c4113dSnw141292 * List of query state structs -- needed so we can "route" LDAP results 152*c5c4113dSnw141292 * to the right context if multiple threads should be using the same 153*c5c4113dSnw141292 * connection concurrently 154*c5c4113dSnw141292 */ 155*c5c4113dSnw141292 static idmap_query_state_t *qstatehead = NULL; 156*c5c4113dSnw141292 static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER; 157*c5c4113dSnw141292 158*c5c4113dSnw141292 /* 159*c5c4113dSnw141292 * List of DSs, needed by the idle connection reaper thread 160*c5c4113dSnw141292 */ 161*c5c4113dSnw141292 static ad_host_t *host_head = NULL; 162*c5c4113dSnw141292 static pthread_t reaperid = (pthread_t)-1; 163*c5c4113dSnw141292 static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER; 164*c5c4113dSnw141292 165*c5c4113dSnw141292 /*ARGSUSED*/ 166*c5c4113dSnw141292 static int 167*c5c4113dSnw141292 idmap_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) { 168*c5c4113dSnw141292 sasl_interact_t *interact; 169*c5c4113dSnw141292 170*c5c4113dSnw141292 if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE) 171*c5c4113dSnw141292 return (LDAP_PARAM_ERROR); 172*c5c4113dSnw141292 173*c5c4113dSnw141292 /* There should be no extra arguemnts for SASL/GSSAPI authentication */ 174*c5c4113dSnw141292 for (interact = prompts; interact->id != SASL_CB_LIST_END; 175*c5c4113dSnw141292 interact++) { 176*c5c4113dSnw141292 interact->result = NULL; 177*c5c4113dSnw141292 interact->len = 0; 178*c5c4113dSnw141292 } 179*c5c4113dSnw141292 return (LDAP_SUCCESS); 180*c5c4113dSnw141292 } 181*c5c4113dSnw141292 182*c5c4113dSnw141292 /* Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com" */ 183*c5c4113dSnw141292 static 184*c5c4113dSnw141292 char * 185*c5c4113dSnw141292 dns2dn(const char *dns) 186*c5c4113dSnw141292 { 187*c5c4113dSnw141292 int nameparts; 188*c5c4113dSnw141292 189*c5c4113dSnw141292 /* Sigh, ldap_dns_to_dn()'s first arg should be a const char * */ 190*c5c4113dSnw141292 return (ldap_dns_to_dn((char *)dns, &nameparts)); 191*c5c4113dSnw141292 } 192*c5c4113dSnw141292 193*c5c4113dSnw141292 /* 194*c5c4113dSnw141292 * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other 195*c5c4113dSnw141292 * attributes (CN, etc...) 196*c5c4113dSnw141292 */ 197*c5c4113dSnw141292 static 198*c5c4113dSnw141292 char * 199*c5c4113dSnw141292 dn2dns(const char *dn) 200*c5c4113dSnw141292 { 201*c5c4113dSnw141292 char **rdns = NULL; 202*c5c4113dSnw141292 char **attrs = NULL; 203*c5c4113dSnw141292 char **labels = NULL; 204*c5c4113dSnw141292 char *dns = NULL; 205*c5c4113dSnw141292 char **rdn, **attr, **label; 206*c5c4113dSnw141292 int maxlabels = 5; 207*c5c4113dSnw141292 int nlabels = 0; 208*c5c4113dSnw141292 int dnslen; 209*c5c4113dSnw141292 210*c5c4113dSnw141292 /* 211*c5c4113dSnw141292 * There is no reverse of ldap_dns_to_dn() in our libldap, so we 212*c5c4113dSnw141292 * have to do the hard work here for now. 213*c5c4113dSnw141292 */ 214*c5c4113dSnw141292 215*c5c4113dSnw141292 /* 216*c5c4113dSnw141292 * This code is much too liberal: it looks for "dc" attributes 217*c5c4113dSnw141292 * in all RDNs of the DN. In theory this could cause problems 218*c5c4113dSnw141292 * if people were to use "dc" in nodes other than the root of 219*c5c4113dSnw141292 * the tree, but in practice noone, least of all Active 220*c5c4113dSnw141292 * Directory, does that. 221*c5c4113dSnw141292 * 222*c5c4113dSnw141292 * On the other hand, this code is much too conservative: it 223*c5c4113dSnw141292 * does not make assumptions about ldap_explode_dn(), and _that_ 224*c5c4113dSnw141292 * is the true for looking at every attr of every RDN. 225*c5c4113dSnw141292 * 226*c5c4113dSnw141292 * Since we only ever look at dc and those must be DNS labels, 227*c5c4113dSnw141292 * at least until we get around to supporting IDN here we 228*c5c4113dSnw141292 * shouldn't see escaped labels from AD nor from libldap, though 229*c5c4113dSnw141292 * the spec (RFC2253) does allow libldap to escape things that 230*c5c4113dSnw141292 * don't need escaping -- if that should ever happen then 231*c5c4113dSnw141292 * libldap will need a spanking, and we can take care of that. 232*c5c4113dSnw141292 */ 233*c5c4113dSnw141292 234*c5c4113dSnw141292 /* Explode a DN into RDNs */ 235*c5c4113dSnw141292 if ((rdns = ldap_explode_dn(dn, 0)) == NULL) 236*c5c4113dSnw141292 return (NULL); 237*c5c4113dSnw141292 238*c5c4113dSnw141292 labels = calloc(maxlabels + 1, sizeof (char *)); 239*c5c4113dSnw141292 label = labels; 240*c5c4113dSnw141292 241*c5c4113dSnw141292 for (rdn = rdns; *rdn != NULL; rdn++) { 242*c5c4113dSnw141292 if (attrs != NULL) 243*c5c4113dSnw141292 ldap_value_free(attrs); 244*c5c4113dSnw141292 245*c5c4113dSnw141292 /* Explode each RDN, look for DC attr, save val as DNS label */ 246*c5c4113dSnw141292 if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) 247*c5c4113dSnw141292 goto done; 248*c5c4113dSnw141292 249*c5c4113dSnw141292 for (attr = attrs; *attr != NULL; attr++) { 250*c5c4113dSnw141292 if (strncasecmp(*attr, "dc=", 3) != 0) 251*c5c4113dSnw141292 continue; 252*c5c4113dSnw141292 253*c5c4113dSnw141292 /* Found a DNS label */ 254*c5c4113dSnw141292 labels[nlabels++] = strdup((*attr) + 3); 255*c5c4113dSnw141292 256*c5c4113dSnw141292 if (nlabels == maxlabels) { 257*c5c4113dSnw141292 char **tmp; 258*c5c4113dSnw141292 tmp = realloc(labels, 259*c5c4113dSnw141292 sizeof (char *) * (maxlabels + 1)); 260*c5c4113dSnw141292 261*c5c4113dSnw141292 if (tmp == NULL) 262*c5c4113dSnw141292 goto done; 263*c5c4113dSnw141292 264*c5c4113dSnw141292 labels = tmp; 265*c5c4113dSnw141292 labels[nlabels] = NULL; 266*c5c4113dSnw141292 } 267*c5c4113dSnw141292 268*c5c4113dSnw141292 /* There should be just one DC= attr per-RDN */ 269*c5c4113dSnw141292 break; 270*c5c4113dSnw141292 } 271*c5c4113dSnw141292 } 272*c5c4113dSnw141292 273*c5c4113dSnw141292 /* 274*c5c4113dSnw141292 * Got all the labels, now join with '.' 275*c5c4113dSnw141292 * 276*c5c4113dSnw141292 * We need room for nlabels - 1 periods ('.'), one nul 277*c5c4113dSnw141292 * terminator, and the strlen() of each label. 278*c5c4113dSnw141292 */ 279*c5c4113dSnw141292 dnslen = nlabels; 280*c5c4113dSnw141292 for (label = labels; *label != NULL; label++) 281*c5c4113dSnw141292 dnslen += strlen(*label); 282*c5c4113dSnw141292 283*c5c4113dSnw141292 if ((dns = malloc(dnslen)) == NULL) 284*c5c4113dSnw141292 goto done; 285*c5c4113dSnw141292 286*c5c4113dSnw141292 *dns = '\0'; 287*c5c4113dSnw141292 288*c5c4113dSnw141292 for (label = labels; *label != NULL; label++) { 289*c5c4113dSnw141292 (void) strlcat(dns, *label, dnslen); 290*c5c4113dSnw141292 /* 291*c5c4113dSnw141292 * NOTE: the last '.' won't be appended -- there's no room 292*c5c4113dSnw141292 * for it! 293*c5c4113dSnw141292 */ 294*c5c4113dSnw141292 (void) strlcat(dns, ".", dnslen); 295*c5c4113dSnw141292 } 296*c5c4113dSnw141292 297*c5c4113dSnw141292 done: 298*c5c4113dSnw141292 if (labels != NULL) { 299*c5c4113dSnw141292 for (label = labels; *label != NULL; label++) 300*c5c4113dSnw141292 free(*label); 301*c5c4113dSnw141292 free(labels); 302*c5c4113dSnw141292 } 303*c5c4113dSnw141292 if (attrs != NULL) 304*c5c4113dSnw141292 ldap_value_free(attrs); 305*c5c4113dSnw141292 if (rdns != NULL) 306*c5c4113dSnw141292 ldap_value_free(rdns); 307*c5c4113dSnw141292 308*c5c4113dSnw141292 return (dns); 309*c5c4113dSnw141292 } 310*c5c4113dSnw141292 311*c5c4113dSnw141292 /* 312*c5c4113dSnw141292 * Keep connection management simple for now, extend or replace later 313*c5c4113dSnw141292 * with updated libsldap code. 314*c5c4113dSnw141292 */ 315*c5c4113dSnw141292 #define ADREAPERSLEEP 60 316*c5c4113dSnw141292 #define ADCONN_TIME 300 317*c5c4113dSnw141292 318*c5c4113dSnw141292 /* 319*c5c4113dSnw141292 * Idle connection reaping side of connection management 320*c5c4113dSnw141292 * 321*c5c4113dSnw141292 * Every minute wake up and look for connections that have been idle for 322*c5c4113dSnw141292 * five minutes or more and close them. 323*c5c4113dSnw141292 */ 324*c5c4113dSnw141292 /*ARGSUSED*/ 325*c5c4113dSnw141292 static 326*c5c4113dSnw141292 void 327*c5c4113dSnw141292 adreaper(void *arg) 328*c5c4113dSnw141292 { 329*c5c4113dSnw141292 ad_host_t *adh; 330*c5c4113dSnw141292 time_t now; 331*c5c4113dSnw141292 timespec_t ts; 332*c5c4113dSnw141292 333*c5c4113dSnw141292 ts.tv_sec = ADREAPERSLEEP; 334*c5c4113dSnw141292 ts.tv_nsec = 0; 335*c5c4113dSnw141292 336*c5c4113dSnw141292 for (;;) { 337*c5c4113dSnw141292 /* 338*c5c4113dSnw141292 * nanosleep(3RT) is thead-safe (no SIGALRM) and more 339*c5c4113dSnw141292 * portable than usleep(3C) 340*c5c4113dSnw141292 */ 341*c5c4113dSnw141292 (void) nanosleep(&ts, NULL); 342*c5c4113dSnw141292 (void) pthread_mutex_lock(&adhostlock); 343*c5c4113dSnw141292 now = time(NULL); 344*c5c4113dSnw141292 for (adh = host_head; adh != NULL; adh = adh->next) { 345*c5c4113dSnw141292 (void) pthread_mutex_lock(&adh->lock); 346*c5c4113dSnw141292 if (adh->ref == 0 && adh->idletime != 0 && 347*c5c4113dSnw141292 adh->idletime + ADCONN_TIME < now) { 348*c5c4113dSnw141292 if (adh->ld) { 349*c5c4113dSnw141292 (void) ldap_unbind(adh->ld); 350*c5c4113dSnw141292 adh->ld = NULL; 351*c5c4113dSnw141292 adh->idletime = 0; 352*c5c4113dSnw141292 adh->ref = 0; 353*c5c4113dSnw141292 } 354*c5c4113dSnw141292 } 355*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 356*c5c4113dSnw141292 } 357*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adhostlock); 358*c5c4113dSnw141292 } 359*c5c4113dSnw141292 } 360*c5c4113dSnw141292 361*c5c4113dSnw141292 int 362*c5c4113dSnw141292 idmap_ad_alloc(ad_t **new_ad, const char *default_domain, 363*c5c4113dSnw141292 idmap_ad_partition_t part) 364*c5c4113dSnw141292 { 365*c5c4113dSnw141292 ad_t *ad; 366*c5c4113dSnw141292 367*c5c4113dSnw141292 *new_ad = NULL; 368*c5c4113dSnw141292 369*c5c4113dSnw141292 if ((default_domain == NULL || *default_domain == '\0') && 370*c5c4113dSnw141292 part != IDMAP_AD_GLOBAL_CATALOG) 371*c5c4113dSnw141292 return (-1); 372*c5c4113dSnw141292 373*c5c4113dSnw141292 if ((ad = calloc(1, sizeof (ad_t))) == NULL) 374*c5c4113dSnw141292 return (-1); 375*c5c4113dSnw141292 376*c5c4113dSnw141292 ad->ref = 1; 377*c5c4113dSnw141292 ad->partition = part; 378*c5c4113dSnw141292 379*c5c4113dSnw141292 /* 380*c5c4113dSnw141292 * If default_domain is NULL, deal, deferring errors until 381*c5c4113dSnw141292 * idmap_lookup_batch_start() -- this makes it easier on the 382*c5c4113dSnw141292 * caller, who can simply observe lookups failing as opposed to 383*c5c4113dSnw141292 * having to conditionalize calls to lookups according to 384*c5c4113dSnw141292 * whether it has a non-NULL ad_t *. 385*c5c4113dSnw141292 */ 386*c5c4113dSnw141292 if (default_domain == NULL) 387*c5c4113dSnw141292 default_domain = ""; 388*c5c4113dSnw141292 389*c5c4113dSnw141292 if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL) 390*c5c4113dSnw141292 goto err; 391*c5c4113dSnw141292 392*c5c4113dSnw141292 /* If default_domain is empty, deal; see above */ 393*c5c4113dSnw141292 if (*default_domain == '\0') { 394*c5c4113dSnw141292 if ((ad->basedn = strdup("")) == NULL) 395*c5c4113dSnw141292 goto err; 396*c5c4113dSnw141292 } else if ((ad->basedn = dns2dn(default_domain)) == NULL) { 397*c5c4113dSnw141292 goto err; 398*c5c4113dSnw141292 } 399*c5c4113dSnw141292 400*c5c4113dSnw141292 if (pthread_mutex_init(&ad->lock, NULL) != 0) 401*c5c4113dSnw141292 goto err; 402*c5c4113dSnw141292 403*c5c4113dSnw141292 *new_ad = ad; 404*c5c4113dSnw141292 405*c5c4113dSnw141292 return (0); 406*c5c4113dSnw141292 err: 407*c5c4113dSnw141292 if (ad->dflt_w2k_dom != NULL) 408*c5c4113dSnw141292 free(ad->dflt_w2k_dom); 409*c5c4113dSnw141292 if (ad->basedn != NULL) 410*c5c4113dSnw141292 free(ad->basedn); 411*c5c4113dSnw141292 free(ad); 412*c5c4113dSnw141292 return (-1); 413*c5c4113dSnw141292 } 414*c5c4113dSnw141292 415*c5c4113dSnw141292 416*c5c4113dSnw141292 void 417*c5c4113dSnw141292 idmap_ad_free(ad_t **ad) 418*c5c4113dSnw141292 { 419*c5c4113dSnw141292 ad_host_t *p; 420*c5c4113dSnw141292 421*c5c4113dSnw141292 if (ad == NULL || *ad == NULL) 422*c5c4113dSnw141292 return; 423*c5c4113dSnw141292 424*c5c4113dSnw141292 (void) pthread_mutex_lock(&(*ad)->lock); 425*c5c4113dSnw141292 426*c5c4113dSnw141292 if (atomic_dec_32_nv(&(*ad)->ref) > 0) { 427*c5c4113dSnw141292 (void) pthread_mutex_unlock(&(*ad)->lock); 428*c5c4113dSnw141292 *ad = NULL; 429*c5c4113dSnw141292 return; 430*c5c4113dSnw141292 } 431*c5c4113dSnw141292 432*c5c4113dSnw141292 for (p = host_head; p != NULL; p = p->next) { 433*c5c4113dSnw141292 if (p->owner != (*ad)) 434*c5c4113dSnw141292 continue; 435*c5c4113dSnw141292 idmap_delete_ds((*ad), p->host, p->port); 436*c5c4113dSnw141292 } 437*c5c4113dSnw141292 438*c5c4113dSnw141292 free((*ad)->basedn); 439*c5c4113dSnw141292 440*c5c4113dSnw141292 (void) pthread_mutex_unlock(&(*ad)->lock); 441*c5c4113dSnw141292 (void) pthread_mutex_destroy(&(*ad)->lock); 442*c5c4113dSnw141292 443*c5c4113dSnw141292 free(*ad); 444*c5c4113dSnw141292 445*c5c4113dSnw141292 *ad = NULL; 446*c5c4113dSnw141292 } 447*c5c4113dSnw141292 448*c5c4113dSnw141292 static 449*c5c4113dSnw141292 int 450*c5c4113dSnw141292 idmap_open_conn(ad_host_t *adh) 451*c5c4113dSnw141292 { 452*c5c4113dSnw141292 int rc, ldversion; 453*c5c4113dSnw141292 454*c5c4113dSnw141292 if (adh->dead && adh->ld != NULL) { 455*c5c4113dSnw141292 (void) ldap_unbind(adh->ld); 456*c5c4113dSnw141292 adh->ld = NULL; 457*c5c4113dSnw141292 adh->dead = 0; 458*c5c4113dSnw141292 } 459*c5c4113dSnw141292 460*c5c4113dSnw141292 if (adh->ld == NULL) { 461*c5c4113dSnw141292 int zero = 0; 462*c5c4113dSnw141292 int timeoutms = 30 * 1000; 463*c5c4113dSnw141292 464*c5c4113dSnw141292 atomic_inc_64(&adh->generation); 465*c5c4113dSnw141292 adh->ld = ldap_init(adh->host, adh->port); 466*c5c4113dSnw141292 if (adh->ld == NULL) 467*c5c4113dSnw141292 return (-1); 468*c5c4113dSnw141292 469*c5c4113dSnw141292 ldversion = LDAP_VERSION3; 470*c5c4113dSnw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, 471*c5c4113dSnw141292 &ldversion); 472*c5c4113dSnw141292 473*c5c4113dSnw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, 474*c5c4113dSnw141292 LDAP_OPT_OFF); 475*c5c4113dSnw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero); 476*c5c4113dSnw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero); 477*c5c4113dSnw141292 /* setup TCP/IP connect timeout */ 478*c5c4113dSnw141292 (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, 479*c5c4113dSnw141292 &timeoutms); 480*c5c4113dSnw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 481*c5c4113dSnw141292 rc = ldap_sasl_interactive_bind_s(adh->ld, 482*c5c4113dSnw141292 "" /* binddn */, adh->saslmech, NULL, NULL, adh->saslflags, 483*c5c4113dSnw141292 &idmap_saslcallback, NULL /* defaults */); 484*c5c4113dSnw141292 485*c5c4113dSnw141292 if (rc != LDAP_SUCCESS) { 486*c5c4113dSnw141292 idmapdlog(LOG_ERR, "Could not authenticate to the " 487*c5c4113dSnw141292 "LDAP server. (Check that the host keys are " 488*c5c4113dSnw141292 "correct?)"); 489*c5c4113dSnw141292 return (rc); 490*c5c4113dSnw141292 } 491*c5c4113dSnw141292 } 492*c5c4113dSnw141292 493*c5c4113dSnw141292 adh->idletime = time(NULL); 494*c5c4113dSnw141292 495*c5c4113dSnw141292 return (LDAP_SUCCESS); 496*c5c4113dSnw141292 } 497*c5c4113dSnw141292 498*c5c4113dSnw141292 499*c5c4113dSnw141292 /* 500*c5c4113dSnw141292 * Connection management: find an open connection or open one 501*c5c4113dSnw141292 */ 502*c5c4113dSnw141292 static 503*c5c4113dSnw141292 ad_host_t * 504*c5c4113dSnw141292 idmap_get_conn(const ad_t *ad) 505*c5c4113dSnw141292 { 506*c5c4113dSnw141292 ad_host_t *adh = NULL; 507*c5c4113dSnw141292 int rc; 508*c5c4113dSnw141292 509*c5c4113dSnw141292 (void) pthread_mutex_lock(&adhostlock); 510*c5c4113dSnw141292 511*c5c4113dSnw141292 /* 512*c5c4113dSnw141292 * Search for any ad_host_t, preferably one with an open 513*c5c4113dSnw141292 * connection 514*c5c4113dSnw141292 */ 515*c5c4113dSnw141292 for (adh = host_head; adh != NULL; adh = adh->next) { 516*c5c4113dSnw141292 if (adh->owner == ad) { 517*c5c4113dSnw141292 break; 518*c5c4113dSnw141292 } 519*c5c4113dSnw141292 } 520*c5c4113dSnw141292 521*c5c4113dSnw141292 if (adh != NULL) 522*c5c4113dSnw141292 atomic_inc_32(&adh->ref); 523*c5c4113dSnw141292 524*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adhostlock); 525*c5c4113dSnw141292 526*c5c4113dSnw141292 if (adh == NULL) 527*c5c4113dSnw141292 return (NULL); 528*c5c4113dSnw141292 529*c5c4113dSnw141292 /* found connection, open it if not opened */ 530*c5c4113dSnw141292 (void) pthread_mutex_lock(&adh->lock); 531*c5c4113dSnw141292 rc = idmap_open_conn(adh); 532*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 533*c5c4113dSnw141292 if (rc != LDAP_SUCCESS) 534*c5c4113dSnw141292 return (NULL); 535*c5c4113dSnw141292 536*c5c4113dSnw141292 return (adh); 537*c5c4113dSnw141292 } 538*c5c4113dSnw141292 539*c5c4113dSnw141292 static 540*c5c4113dSnw141292 void 541*c5c4113dSnw141292 idmap_release_conn(ad_host_t *adh) 542*c5c4113dSnw141292 { 543*c5c4113dSnw141292 (void) pthread_mutex_lock(&adh->lock); 544*c5c4113dSnw141292 if (atomic_dec_32_nv(&adh->ref) == 0) 545*c5c4113dSnw141292 adh->idletime = time(NULL); 546*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 547*c5c4113dSnw141292 } 548*c5c4113dSnw141292 549*c5c4113dSnw141292 /* 550*c5c4113dSnw141292 * Take ad_host_config_t information, create a ad_host_t, 551*c5c4113dSnw141292 * populate it and add it to the list of hosts. 552*c5c4113dSnw141292 */ 553*c5c4113dSnw141292 554*c5c4113dSnw141292 int 555*c5c4113dSnw141292 idmap_add_ds(ad_t *ad, const char *host, int port) 556*c5c4113dSnw141292 { 557*c5c4113dSnw141292 ad_host_t *p; 558*c5c4113dSnw141292 ad_host_t *new = NULL; 559*c5c4113dSnw141292 int ret = -1; 560*c5c4113dSnw141292 561*c5c4113dSnw141292 if (port == 0) 562*c5c4113dSnw141292 port = (int)ad->partition; 563*c5c4113dSnw141292 564*c5c4113dSnw141292 (void) pthread_mutex_lock(&adhostlock); 565*c5c4113dSnw141292 for (p = host_head; p != NULL; p = p->next) { 566*c5c4113dSnw141292 if (p->owner != ad) 567*c5c4113dSnw141292 continue; 568*c5c4113dSnw141292 569*c5c4113dSnw141292 if (strcmp(host, p->host) == 0 && p->port == port) { 570*c5c4113dSnw141292 /* already added */ 571*c5c4113dSnw141292 ret = -2; 572*c5c4113dSnw141292 goto err; 573*c5c4113dSnw141292 } 574*c5c4113dSnw141292 } 575*c5c4113dSnw141292 576*c5c4113dSnw141292 /* add new entry */ 577*c5c4113dSnw141292 new = (ad_host_t *)calloc(1, sizeof (ad_host_t)); 578*c5c4113dSnw141292 if (new == NULL) 579*c5c4113dSnw141292 goto err; 580*c5c4113dSnw141292 new->owner = ad; 581*c5c4113dSnw141292 new->port = port; 582*c5c4113dSnw141292 new->dead = 0; 583*c5c4113dSnw141292 if ((new->host = strdup(host)) == NULL) 584*c5c4113dSnw141292 goto err; 585*c5c4113dSnw141292 586*c5c4113dSnw141292 /* default to SASL GSSAPI only for now */ 587*c5c4113dSnw141292 new->saslflags = LDAP_SASL_INTERACTIVE; 588*c5c4113dSnw141292 new->saslmech = "GSSAPI"; 589*c5c4113dSnw141292 590*c5c4113dSnw141292 if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) { 591*c5c4113dSnw141292 free(new->host); 592*c5c4113dSnw141292 new->host = NULL; 593*c5c4113dSnw141292 errno = ret; 594*c5c4113dSnw141292 ret = -1; 595*c5c4113dSnw141292 goto err; 596*c5c4113dSnw141292 } 597*c5c4113dSnw141292 598*c5c4113dSnw141292 /* link in */ 599*c5c4113dSnw141292 new->next = host_head; 600*c5c4113dSnw141292 host_head = new; 601*c5c4113dSnw141292 602*c5c4113dSnw141292 /* Start reaper if it doesn't exist */ 603*c5c4113dSnw141292 if (reaperid == 0) 604*c5c4113dSnw141292 (void) pthread_create(&reaperid, NULL, 605*c5c4113dSnw141292 (void *(*)(void *))adreaper, (void *)NULL); 606*c5c4113dSnw141292 607*c5c4113dSnw141292 err: 608*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adhostlock); 609*c5c4113dSnw141292 610*c5c4113dSnw141292 if (ret != 0 && new != NULL) { 611*c5c4113dSnw141292 if (new->host != NULL) { 612*c5c4113dSnw141292 (void) pthread_mutex_destroy(&new->lock); 613*c5c4113dSnw141292 free(new->host); 614*c5c4113dSnw141292 } 615*c5c4113dSnw141292 free(new); 616*c5c4113dSnw141292 } 617*c5c4113dSnw141292 618*c5c4113dSnw141292 return (ret); 619*c5c4113dSnw141292 } 620*c5c4113dSnw141292 621*c5c4113dSnw141292 /* 622*c5c4113dSnw141292 * free a DS configuration 623*c5c4113dSnw141292 */ 624*c5c4113dSnw141292 void 625*c5c4113dSnw141292 idmap_delete_ds(ad_t *ad, const char *host, int port) 626*c5c4113dSnw141292 { 627*c5c4113dSnw141292 ad_host_t **p, *q; 628*c5c4113dSnw141292 629*c5c4113dSnw141292 (void) pthread_mutex_lock(&adhostlock); 630*c5c4113dSnw141292 for (p = &host_head; *p != NULL; p = &((*p)->next)) { 631*c5c4113dSnw141292 if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 || 632*c5c4113dSnw141292 (*p)->port != port) 633*c5c4113dSnw141292 continue; 634*c5c4113dSnw141292 /* found */ 635*c5c4113dSnw141292 if (atomic_dec_32_nv(&((*p)->ref)) > 0) 636*c5c4113dSnw141292 break; /* still in use */ 637*c5c4113dSnw141292 638*c5c4113dSnw141292 q = *p; 639*c5c4113dSnw141292 *p = (*p)->next; 640*c5c4113dSnw141292 641*c5c4113dSnw141292 (void) pthread_mutex_destroy(&q->lock); 642*c5c4113dSnw141292 643*c5c4113dSnw141292 if (q->ld) 644*c5c4113dSnw141292 (void) ldap_unbind(q->ld); 645*c5c4113dSnw141292 if (q->host) 646*c5c4113dSnw141292 free(q->host); 647*c5c4113dSnw141292 free(q); 648*c5c4113dSnw141292 break; 649*c5c4113dSnw141292 } 650*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adhostlock); 651*c5c4113dSnw141292 } 652*c5c4113dSnw141292 653*c5c4113dSnw141292 /* 654*c5c4113dSnw141292 * Convert a binary SID in a BerValue to a sid_t 655*c5c4113dSnw141292 */ 656*c5c4113dSnw141292 static 657*c5c4113dSnw141292 int 658*c5c4113dSnw141292 idmap_getsid(BerValue *bval, sid_t *sidp) 659*c5c4113dSnw141292 { 660*c5c4113dSnw141292 int i, j; 661*c5c4113dSnw141292 uchar_t *v; 662*c5c4113dSnw141292 uint32_t a; 663*c5c4113dSnw141292 664*c5c4113dSnw141292 /* 665*c5c4113dSnw141292 * The binary format of a SID is as follows: 666*c5c4113dSnw141292 * 667*c5c4113dSnw141292 * byte #0: version, always 0x01 668*c5c4113dSnw141292 * byte #1: RID count, always <= 0x0f 669*c5c4113dSnw141292 * bytes #2-#7: SID authority, big-endian 48-bit unsigned int 670*c5c4113dSnw141292 * 671*c5c4113dSnw141292 * followed by RID count RIDs, each a little-endian, unsigned 672*c5c4113dSnw141292 * 32-bit int. 673*c5c4113dSnw141292 */ 674*c5c4113dSnw141292 /* 675*c5c4113dSnw141292 * Sanity checks: must have at least one RID, version must be 676*c5c4113dSnw141292 * 0x01, and the length must be 8 + rid count * 4 677*c5c4113dSnw141292 */ 678*c5c4113dSnw141292 if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 && 679*c5c4113dSnw141292 bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) { 680*c5c4113dSnw141292 v = (uchar_t *)bval->bv_val; 681*c5c4113dSnw141292 sidp->version = v[0]; 682*c5c4113dSnw141292 sidp->sub_authority_count = v[1]; 683*c5c4113dSnw141292 sidp->authority = 684*c5c4113dSnw141292 /* big endian -- so start from the left */ 685*c5c4113dSnw141292 ((u_longlong_t)v[2] << 40) | 686*c5c4113dSnw141292 ((u_longlong_t)v[3] << 32) | 687*c5c4113dSnw141292 ((u_longlong_t)v[4] << 24) | 688*c5c4113dSnw141292 ((u_longlong_t)v[5] << 16) | 689*c5c4113dSnw141292 ((u_longlong_t)v[6] << 8) | 690*c5c4113dSnw141292 (u_longlong_t)v[7]; 691*c5c4113dSnw141292 for (i = 0; i < sidp->sub_authority_count; i++) { 692*c5c4113dSnw141292 j = 8 + (i * 4); 693*c5c4113dSnw141292 /* little endian -- so start from the right */ 694*c5c4113dSnw141292 a = (v[j + 3] << 24) | (v[j + 2] << 16) | 695*c5c4113dSnw141292 (v[j + 1] << 8) | (v[j]); 696*c5c4113dSnw141292 sidp->sub_authorities[i] = a; 697*c5c4113dSnw141292 } 698*c5c4113dSnw141292 return (0); 699*c5c4113dSnw141292 } 700*c5c4113dSnw141292 return (-1); 701*c5c4113dSnw141292 } 702*c5c4113dSnw141292 703*c5c4113dSnw141292 /* 704*c5c4113dSnw141292 * Convert a sid_t to S-1-... 705*c5c4113dSnw141292 */ 706*c5c4113dSnw141292 static 707*c5c4113dSnw141292 char * 708*c5c4113dSnw141292 idmap_sid2txt(sid_t *sidp) 709*c5c4113dSnw141292 { 710*c5c4113dSnw141292 int rlen, i, len; 711*c5c4113dSnw141292 char *str, *cp; 712*c5c4113dSnw141292 713*c5c4113dSnw141292 if (sidp->version != 1) 714*c5c4113dSnw141292 return (NULL); 715*c5c4113dSnw141292 716*c5c4113dSnw141292 len = sizeof ("S-1-") - 1; 717*c5c4113dSnw141292 718*c5c4113dSnw141292 /* 719*c5c4113dSnw141292 * We could optimize like so, but, why? 720*c5c4113dSnw141292 * if (sidp->authority < 10) 721*c5c4113dSnw141292 * len += 2; 722*c5c4113dSnw141292 * else if (sidp->authority < 100) 723*c5c4113dSnw141292 * len += 3; 724*c5c4113dSnw141292 * else 725*c5c4113dSnw141292 * len += snprintf(NULL, 0"%llu", sidp->authority); 726*c5c4113dSnw141292 */ 727*c5c4113dSnw141292 len += snprintf(NULL, 0, "%llu", sidp->authority); 728*c5c4113dSnw141292 729*c5c4113dSnw141292 /* Max length of a uint32_t printed out in ASCII is 10 bytes */ 730*c5c4113dSnw141292 len += 1 + (sidp->sub_authority_count + 1) * 10; 731*c5c4113dSnw141292 732*c5c4113dSnw141292 if ((cp = str = malloc(len)) == NULL) 733*c5c4113dSnw141292 return (NULL); 734*c5c4113dSnw141292 735*c5c4113dSnw141292 rlen = snprintf(str, len, "S-1-%llu", sidp->authority); 736*c5c4113dSnw141292 737*c5c4113dSnw141292 cp += rlen; 738*c5c4113dSnw141292 len -= rlen; 739*c5c4113dSnw141292 740*c5c4113dSnw141292 for (i = 0; i < sidp->sub_authority_count; i++) { 741*c5c4113dSnw141292 assert(len > 0); 742*c5c4113dSnw141292 rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]); 743*c5c4113dSnw141292 cp += rlen; 744*c5c4113dSnw141292 len -= rlen; 745*c5c4113dSnw141292 assert(len >= 0); 746*c5c4113dSnw141292 } 747*c5c4113dSnw141292 748*c5c4113dSnw141292 return (str); 749*c5c4113dSnw141292 } 750*c5c4113dSnw141292 751*c5c4113dSnw141292 /* 752*c5c4113dSnw141292 * Convert a sid_t to on-the-wire encoding 753*c5c4113dSnw141292 */ 754*c5c4113dSnw141292 static 755*c5c4113dSnw141292 int 756*c5c4113dSnw141292 idmap_sid2binsid(sid_t *sid, uchar_t *binsid, int binsidlen) 757*c5c4113dSnw141292 { 758*c5c4113dSnw141292 uchar_t *p; 759*c5c4113dSnw141292 int i; 760*c5c4113dSnw141292 uint64_t a; 761*c5c4113dSnw141292 uint32_t r; 762*c5c4113dSnw141292 763*c5c4113dSnw141292 if (sid->version != 1 || 764*c5c4113dSnw141292 binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4)) 765*c5c4113dSnw141292 return (-1); 766*c5c4113dSnw141292 767*c5c4113dSnw141292 p = binsid; 768*c5c4113dSnw141292 *p++ = 0x01; /* version */ 769*c5c4113dSnw141292 /* sub authority count */ 770*c5c4113dSnw141292 *p++ = sid->sub_authority_count; 771*c5c4113dSnw141292 /* Authority */ 772*c5c4113dSnw141292 a = sid->authority; 773*c5c4113dSnw141292 /* big-endian -- start from left */ 774*c5c4113dSnw141292 *p++ = (a >> 40) & 0xFF; 775*c5c4113dSnw141292 *p++ = (a >> 32) & 0xFF; 776*c5c4113dSnw141292 *p++ = (a >> 24) & 0xFF; 777*c5c4113dSnw141292 *p++ = (a >> 16) & 0xFF; 778*c5c4113dSnw141292 *p++ = (a >> 8) & 0xFF; 779*c5c4113dSnw141292 *p++ = a & 0xFF; 780*c5c4113dSnw141292 781*c5c4113dSnw141292 /* sub-authorities */ 782*c5c4113dSnw141292 for (i = 0; i < sid->sub_authority_count; i++) { 783*c5c4113dSnw141292 r = sid->sub_authorities[i]; 784*c5c4113dSnw141292 /* little-endian -- start from right */ 785*c5c4113dSnw141292 *p++ = (r & 0x000000FF); 786*c5c4113dSnw141292 *p++ = (r & 0x0000FF00) >> 8; 787*c5c4113dSnw141292 *p++ = (r & 0x00FF0000) >> 16; 788*c5c4113dSnw141292 *p++ = (r & 0xFF000000) >> 24; 789*c5c4113dSnw141292 } 790*c5c4113dSnw141292 791*c5c4113dSnw141292 return (0); 792*c5c4113dSnw141292 } 793*c5c4113dSnw141292 794*c5c4113dSnw141292 /* 795*c5c4113dSnw141292 * Convert a stringified SID (S-1-...) into a hex-encoded version of the 796*c5c4113dSnw141292 * on-the-wire encoding, but with each pair of hex digits pre-pended 797*c5c4113dSnw141292 * with a '\', so we can pass this to libldap. 798*c5c4113dSnw141292 */ 799*c5c4113dSnw141292 static 800*c5c4113dSnw141292 int 801*c5c4113dSnw141292 idmap_txtsid2hexbinsid(const char *txt, const rid_t *rid, 802*c5c4113dSnw141292 char *hexbinsid, int hexbinsidlen) 803*c5c4113dSnw141292 { 804*c5c4113dSnw141292 sid_t sid = { 0 }; 805*c5c4113dSnw141292 int i, j; 806*c5c4113dSnw141292 const char *cp; 807*c5c4113dSnw141292 char *ecp; 808*c5c4113dSnw141292 u_longlong_t a; 809*c5c4113dSnw141292 unsigned long r; 810*c5c4113dSnw141292 uchar_t *binsid, b, hb; 811*c5c4113dSnw141292 812*c5c4113dSnw141292 /* Only version 1 SIDs please */ 813*c5c4113dSnw141292 if (strncmp(txt, "S-1-", strlen("S-1-")) != 0) 814*c5c4113dSnw141292 return (-1); 815*c5c4113dSnw141292 816*c5c4113dSnw141292 if (strlen(txt) < (strlen("S-1-") + 1)) 817*c5c4113dSnw141292 return (-1); 818*c5c4113dSnw141292 819*c5c4113dSnw141292 /* count '-'s */ 820*c5c4113dSnw141292 for (j = 0, cp = strchr(txt, '-'); 821*c5c4113dSnw141292 cp != NULL && *cp != '\0'; 822*c5c4113dSnw141292 j++, cp = strchr(cp + 1, '-')) { 823*c5c4113dSnw141292 /* can't end on a '-' */ 824*c5c4113dSnw141292 if (*(cp + 1) == '\0') 825*c5c4113dSnw141292 return (-1); 826*c5c4113dSnw141292 } 827*c5c4113dSnw141292 828*c5c4113dSnw141292 /* must have at least one RID, but not too many */ 829*c5c4113dSnw141292 if (j < 3 || (j - 1) > SID_MAX_SUB_AUTHORITIES || 830*c5c4113dSnw141292 (rid != NULL && j > SID_MAX_SUB_AUTHORITIES)) 831*c5c4113dSnw141292 return (-1); 832*c5c4113dSnw141292 833*c5c4113dSnw141292 /* check that we only have digits and '-' */ 834*c5c4113dSnw141292 if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1)) 835*c5c4113dSnw141292 return (-1); 836*c5c4113dSnw141292 837*c5c4113dSnw141292 /* we know the version number and RID count */ 838*c5c4113dSnw141292 sid.version = 1; 839*c5c4113dSnw141292 sid.sub_authority_count = j - 2; 840*c5c4113dSnw141292 841*c5c4113dSnw141292 cp = txt + strlen("S-1-"); 842*c5c4113dSnw141292 843*c5c4113dSnw141292 /* 64-bit safe parsing of unsigned 48-bit authority value */ 844*c5c4113dSnw141292 errno = 0; 845*c5c4113dSnw141292 a = strtoull(cp, &ecp, 10); 846*c5c4113dSnw141292 847*c5c4113dSnw141292 /* errors parsing the authority or too many bits */ 848*c5c4113dSnw141292 if (cp == ecp || (a == 0 && errno == EINVAL) || 849*c5c4113dSnw141292 (a == ULLONG_MAX && errno == ERANGE) || 850*c5c4113dSnw141292 (a & 0x0000ffffffffffffULL) != a) 851*c5c4113dSnw141292 return (-1); 852*c5c4113dSnw141292 853*c5c4113dSnw141292 cp = ecp; 854*c5c4113dSnw141292 855*c5c4113dSnw141292 sid.authority = (uint64_t)a; 856*c5c4113dSnw141292 857*c5c4113dSnw141292 for (i = 0; i < sid.sub_authority_count; i++) { 858*c5c4113dSnw141292 if (*cp++ != '-') 859*c5c4113dSnw141292 return (-1); 860*c5c4113dSnw141292 /* 64-bit safe parsing of unsigned 32-bit RID */ 861*c5c4113dSnw141292 errno = 0; 862*c5c4113dSnw141292 r = strtoul(cp, &ecp, 10); 863*c5c4113dSnw141292 /* errors parsing the RID or too many bits */ 864*c5c4113dSnw141292 if (cp == ecp || (r == 0 && errno == EINVAL) || 865*c5c4113dSnw141292 (r == ULONG_MAX && errno == ERANGE) || 866*c5c4113dSnw141292 (r & 0xffffffffUL) != r) 867*c5c4113dSnw141292 return (-1); 868*c5c4113dSnw141292 sid.sub_authorities[i] = (uint32_t)r; 869*c5c4113dSnw141292 cp = ecp; 870*c5c4113dSnw141292 } 871*c5c4113dSnw141292 872*c5c4113dSnw141292 /* check that all of the string SID has been consumed */ 873*c5c4113dSnw141292 if (*cp != '\0') 874*c5c4113dSnw141292 return (-1); 875*c5c4113dSnw141292 876*c5c4113dSnw141292 if (rid != NULL) { 877*c5c4113dSnw141292 sid.sub_authorities[sid.sub_authority_count++] = *rid; 878*c5c4113dSnw141292 } 879*c5c4113dSnw141292 880*c5c4113dSnw141292 j = 1 + 1 + 6 + sid.sub_authority_count * 4; 881*c5c4113dSnw141292 882*c5c4113dSnw141292 if (hexbinsidlen < (j * 3)) 883*c5c4113dSnw141292 return (-2); 884*c5c4113dSnw141292 885*c5c4113dSnw141292 /* binary encode the SID */ 886*c5c4113dSnw141292 binsid = (uchar_t *)alloca(j); 887*c5c4113dSnw141292 (void) idmap_sid2binsid(&sid, binsid, j); 888*c5c4113dSnw141292 889*c5c4113dSnw141292 /* hex encode, with a backslash before each byte */ 890*c5c4113dSnw141292 for (ecp = hexbinsid, i = 0; i < j; i++) { 891*c5c4113dSnw141292 b = binsid[i]; 892*c5c4113dSnw141292 *ecp++ = '\\'; 893*c5c4113dSnw141292 hb = (b >> 4) & 0xF; 894*c5c4113dSnw141292 *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 895*c5c4113dSnw141292 hb = b & 0xF; 896*c5c4113dSnw141292 *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 897*c5c4113dSnw141292 } 898*c5c4113dSnw141292 *ecp = '\0'; 899*c5c4113dSnw141292 900*c5c4113dSnw141292 return (0); 901*c5c4113dSnw141292 } 902*c5c4113dSnw141292 903*c5c4113dSnw141292 static 904*c5c4113dSnw141292 char * 905*c5c4113dSnw141292 convert_bval2sid(BerValue *bval, rid_t *rid) 906*c5c4113dSnw141292 { 907*c5c4113dSnw141292 sid_t sid; 908*c5c4113dSnw141292 909*c5c4113dSnw141292 if (idmap_getsid(bval, &sid) < 0) 910*c5c4113dSnw141292 return (NULL); 911*c5c4113dSnw141292 912*c5c4113dSnw141292 /* 913*c5c4113dSnw141292 * If desired and if the SID is what should be a domain/computer 914*c5c4113dSnw141292 * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then 915*c5c4113dSnw141292 * save the last RID and truncate the SID 916*c5c4113dSnw141292 */ 917*c5c4113dSnw141292 if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5) 918*c5c4113dSnw141292 *rid = sid.sub_authorities[--sid.sub_authority_count]; 919*c5c4113dSnw141292 return (idmap_sid2txt(&sid)); 920*c5c4113dSnw141292 } 921*c5c4113dSnw141292 922*c5c4113dSnw141292 923*c5c4113dSnw141292 idmap_retcode 924*c5c4113dSnw141292 idmap_lookup_batch_start(ad_t *ad, int nqueries, idmap_query_state_t **state) 925*c5c4113dSnw141292 { 926*c5c4113dSnw141292 idmap_query_state_t *new_state; 927*c5c4113dSnw141292 ad_host_t *adh = NULL; 928*c5c4113dSnw141292 929*c5c4113dSnw141292 *state = NULL; 930*c5c4113dSnw141292 931*c5c4113dSnw141292 if (*ad->dflt_w2k_dom == '\0') 932*c5c4113dSnw141292 return (-1); 933*c5c4113dSnw141292 934*c5c4113dSnw141292 adh = idmap_get_conn(ad); 935*c5c4113dSnw141292 if (adh == NULL) 936*c5c4113dSnw141292 return (IDMAP_ERR_OTHER); 937*c5c4113dSnw141292 938*c5c4113dSnw141292 new_state = calloc(1, sizeof (idmap_query_state_t) + 939*c5c4113dSnw141292 (nqueries - 1) * sizeof (idmap_q_t)); 940*c5c4113dSnw141292 941*c5c4113dSnw141292 if (new_state == NULL) 942*c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 943*c5c4113dSnw141292 944*c5c4113dSnw141292 new_state->qadh = adh; 945*c5c4113dSnw141292 new_state->qcount = nqueries; 946*c5c4113dSnw141292 new_state->qadh_gen = adh->generation; 947*c5c4113dSnw141292 /* should be -1, but the atomic routines want unsigned */ 948*c5c4113dSnw141292 new_state->qlastsent = 0; 949*c5c4113dSnw141292 950*c5c4113dSnw141292 (void) pthread_mutex_lock(&qstatelock); 951*c5c4113dSnw141292 new_state->next = qstatehead; 952*c5c4113dSnw141292 qstatehead = new_state; 953*c5c4113dSnw141292 (void) pthread_mutex_unlock(&qstatelock); 954*c5c4113dSnw141292 955*c5c4113dSnw141292 *state = new_state; 956*c5c4113dSnw141292 957*c5c4113dSnw141292 return (IDMAP_SUCCESS); 958*c5c4113dSnw141292 } 959*c5c4113dSnw141292 960*c5c4113dSnw141292 /* 961*c5c4113dSnw141292 * Find the idmap_query_state_t to which a given LDAP result msgid on a 962*c5c4113dSnw141292 * given connection belongs 963*c5c4113dSnw141292 */ 964*c5c4113dSnw141292 static 965*c5c4113dSnw141292 int 966*c5c4113dSnw141292 idmap_msgid2query(ad_host_t *adh, int msgid, 967*c5c4113dSnw141292 idmap_query_state_t **state, int *qid) 968*c5c4113dSnw141292 { 969*c5c4113dSnw141292 idmap_query_state_t *p; 970*c5c4113dSnw141292 int i; 971*c5c4113dSnw141292 972*c5c4113dSnw141292 (void) pthread_mutex_lock(&qstatelock); 973*c5c4113dSnw141292 for (p = qstatehead; p != NULL; p = p->next) { 974*c5c4113dSnw141292 if (p->qadh != adh || adh->generation != p->qadh_gen) 975*c5c4113dSnw141292 continue; 976*c5c4113dSnw141292 for (i = 0; i < p->qcount; i++) { 977*c5c4113dSnw141292 if ((p->queries[i]).msgid == msgid) { 978*c5c4113dSnw141292 *state = p; 979*c5c4113dSnw141292 *qid = i; 980*c5c4113dSnw141292 (void) pthread_mutex_unlock(&qstatelock); 981*c5c4113dSnw141292 return (1); 982*c5c4113dSnw141292 } 983*c5c4113dSnw141292 } 984*c5c4113dSnw141292 } 985*c5c4113dSnw141292 (void) pthread_mutex_unlock(&qstatelock); 986*c5c4113dSnw141292 return (0); 987*c5c4113dSnw141292 } 988*c5c4113dSnw141292 989*c5c4113dSnw141292 /* 990*c5c4113dSnw141292 * Handle an objectSid attr from a result 991*c5c4113dSnw141292 */ 992*c5c4113dSnw141292 static 993*c5c4113dSnw141292 void 994*c5c4113dSnw141292 idmap_bv_objsid2sidstr(BerValue **bvalues, idmap_q_t *q) 995*c5c4113dSnw141292 { 996*c5c4113dSnw141292 if (bvalues == NULL) 997*c5c4113dSnw141292 return; 998*c5c4113dSnw141292 /* objectSid is single valued */ 999*c5c4113dSnw141292 *(q->result) = convert_bval2sid(bvalues[0], q->rid); 1000*c5c4113dSnw141292 q->got_objectSid = 1; 1001*c5c4113dSnw141292 } 1002*c5c4113dSnw141292 1003*c5c4113dSnw141292 /* 1004*c5c4113dSnw141292 * Handle a sAMAccountName attr from a result 1005*c5c4113dSnw141292 */ 1006*c5c4113dSnw141292 static 1007*c5c4113dSnw141292 void 1008*c5c4113dSnw141292 idmap_bv_samaccountname2name(BerValue **bvalues, idmap_q_t *q, const char *dn) 1009*c5c4113dSnw141292 { 1010*c5c4113dSnw141292 char *result, *domain; 1011*c5c4113dSnw141292 int len; 1012*c5c4113dSnw141292 1013*c5c4113dSnw141292 if (bvalues == NULL) 1014*c5c4113dSnw141292 return; 1015*c5c4113dSnw141292 1016*c5c4113dSnw141292 if ((domain = dn2dns(dn)) == NULL) 1017*c5c4113dSnw141292 return; 1018*c5c4113dSnw141292 1019*c5c4113dSnw141292 if (bvalues == NULL || bvalues[0] == NULL || 1020*c5c4113dSnw141292 bvalues[0]->bv_val == NULL) 1021*c5c4113dSnw141292 return; 1022*c5c4113dSnw141292 1023*c5c4113dSnw141292 len = bvalues[0]->bv_len + 1; 1024*c5c4113dSnw141292 1025*c5c4113dSnw141292 if (q->domain != NULL) 1026*c5c4113dSnw141292 *(q->domain) = domain; 1027*c5c4113dSnw141292 else 1028*c5c4113dSnw141292 len += strlen(domain) + 1; 1029*c5c4113dSnw141292 1030*c5c4113dSnw141292 if ((result = malloc(len)) == NULL) { 1031*c5c4113dSnw141292 if (q->domain != NULL) 1032*c5c4113dSnw141292 *(q->domain) = NULL; 1033*c5c4113dSnw141292 free(domain); 1034*c5c4113dSnw141292 return; 1035*c5c4113dSnw141292 } 1036*c5c4113dSnw141292 1037*c5c4113dSnw141292 (void) memcpy(result, bvalues[0]->bv_val, (size_t)bvalues[0]->bv_len); 1038*c5c4113dSnw141292 result[bvalues[0]->bv_len] = '\0'; 1039*c5c4113dSnw141292 1040*c5c4113dSnw141292 if (q->domain == NULL) { 1041*c5c4113dSnw141292 (void) strlcat(result, "@", len); 1042*c5c4113dSnw141292 (void) strlcat(result, domain, len); 1043*c5c4113dSnw141292 free(domain); 1044*c5c4113dSnw141292 } 1045*c5c4113dSnw141292 1046*c5c4113dSnw141292 *(q->result) = result; 1047*c5c4113dSnw141292 q->got_samAcctName = 1; 1048*c5c4113dSnw141292 } 1049*c5c4113dSnw141292 1050*c5c4113dSnw141292 1051*c5c4113dSnw141292 #define BVAL_CASEEQ(bv, str) \ 1052*c5c4113dSnw141292 (((*(bv))->bv_len == (sizeof (str) - 1)) && \ 1053*c5c4113dSnw141292 strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0) 1054*c5c4113dSnw141292 1055*c5c4113dSnw141292 /* 1056*c5c4113dSnw141292 * Handle an objectClass attr from a result 1057*c5c4113dSnw141292 */ 1058*c5c4113dSnw141292 static 1059*c5c4113dSnw141292 void 1060*c5c4113dSnw141292 idmap_bv_objclass2sidtype(BerValue **bvalues, idmap_q_t *q) 1061*c5c4113dSnw141292 { 1062*c5c4113dSnw141292 BerValue **cbval; 1063*c5c4113dSnw141292 1064*c5c4113dSnw141292 if (bvalues == NULL) 1065*c5c4113dSnw141292 return; 1066*c5c4113dSnw141292 1067*c5c4113dSnw141292 for (cbval = bvalues; *cbval != NULL; cbval++) { 1068*c5c4113dSnw141292 /* don't clobber sid_type */ 1069*c5c4113dSnw141292 if (*(q->sid_type) == _IDMAP_T_COMPUTER || 1070*c5c4113dSnw141292 *(q->sid_type) == _IDMAP_T_GROUP || 1071*c5c4113dSnw141292 *(q->sid_type) == _IDMAP_T_USER) 1072*c5c4113dSnw141292 continue; 1073*c5c4113dSnw141292 1074*c5c4113dSnw141292 if (BVAL_CASEEQ(cbval, "Computer")) { 1075*c5c4113dSnw141292 *(q->sid_type) = _IDMAP_T_COMPUTER; 1076*c5c4113dSnw141292 return; 1077*c5c4113dSnw141292 } else if (BVAL_CASEEQ(cbval, "Group")) { 1078*c5c4113dSnw141292 *(q->sid_type) = _IDMAP_T_GROUP; 1079*c5c4113dSnw141292 } else if (BVAL_CASEEQ(cbval, "USER")) { 1080*c5c4113dSnw141292 *(q->sid_type) = _IDMAP_T_USER; 1081*c5c4113dSnw141292 } else 1082*c5c4113dSnw141292 *(q->sid_type) = _IDMAP_T_OTHER; 1083*c5c4113dSnw141292 q->got_objectClass = 1; 1084*c5c4113dSnw141292 } 1085*c5c4113dSnw141292 } 1086*c5c4113dSnw141292 1087*c5c4113dSnw141292 /* 1088*c5c4113dSnw141292 * Handle a given search result entry 1089*c5c4113dSnw141292 */ 1090*c5c4113dSnw141292 static 1091*c5c4113dSnw141292 void 1092*c5c4113dSnw141292 idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res) 1093*c5c4113dSnw141292 { 1094*c5c4113dSnw141292 char *dn, *attr; 1095*c5c4113dSnw141292 BerElement *ber = NULL; 1096*c5c4113dSnw141292 BerValue **bvalues; 1097*c5c4113dSnw141292 ad_host_t *adh; 1098*c5c4113dSnw141292 idmap_q_t *q; 1099*c5c4113dSnw141292 idmap_retcode orc; 1100*c5c4113dSnw141292 1101*c5c4113dSnw141292 adh = state->qadh; 1102*c5c4113dSnw141292 1103*c5c4113dSnw141292 (void) pthread_mutex_lock(&adh->lock); 1104*c5c4113dSnw141292 1105*c5c4113dSnw141292 if (adh->dead || (dn = ldap_get_dn(adh->ld, res)) == NULL) { 1106*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 1107*c5c4113dSnw141292 return; 1108*c5c4113dSnw141292 } 1109*c5c4113dSnw141292 1110*c5c4113dSnw141292 q = &(state->queries[qid]); 1111*c5c4113dSnw141292 1112*c5c4113dSnw141292 for (attr = ldap_first_attribute(adh->ld, res, &ber); attr != NULL; 1113*c5c4113dSnw141292 attr = ldap_next_attribute(adh->ld, res, ber)) { 1114*c5c4113dSnw141292 orc = *q->rc; 1115*c5c4113dSnw141292 bvalues = NULL; /* for memory management below */ 1116*c5c4113dSnw141292 1117*c5c4113dSnw141292 /* 1118*c5c4113dSnw141292 * If this is an attribute we are looking for and 1119*c5c4113dSnw141292 * haven't seen it yet, parse it 1120*c5c4113dSnw141292 */ 1121*c5c4113dSnw141292 if (orc != IDMAP_SUCCESS && q->n2s && !q->got_objectSid && 1122*c5c4113dSnw141292 strcasecmp(attr, OBJECTSID) == 0) { 1123*c5c4113dSnw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 1124*c5c4113dSnw141292 idmap_bv_objsid2sidstr(bvalues, q); 1125*c5c4113dSnw141292 } else if (orc != IDMAP_SUCCESS && !q->n2s && 1126*c5c4113dSnw141292 !q->got_samAcctName && 1127*c5c4113dSnw141292 strcasecmp(attr, SAMACCOUNTNAME) == 0) { 1128*c5c4113dSnw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 1129*c5c4113dSnw141292 idmap_bv_samaccountname2name(bvalues, q, dn); 1130*c5c4113dSnw141292 } else if (orc != IDMAP_SUCCESS && !q->got_objectClass && 1131*c5c4113dSnw141292 strcasecmp(attr, OBJECTCLASS) == 0) { 1132*c5c4113dSnw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 1133*c5c4113dSnw141292 idmap_bv_objclass2sidtype(bvalues, q); 1134*c5c4113dSnw141292 } 1135*c5c4113dSnw141292 1136*c5c4113dSnw141292 if (bvalues != NULL) 1137*c5c4113dSnw141292 ldap_value_free_len(bvalues); 1138*c5c4113dSnw141292 ldap_memfree(attr); 1139*c5c4113dSnw141292 1140*c5c4113dSnw141292 if (q->n2s) 1141*c5c4113dSnw141292 *q->rc = (q->got_objectSid && 1142*c5c4113dSnw141292 q->got_objectClass) ? 1143*c5c4113dSnw141292 IDMAP_SUCCESS : IDMAP_ERR_NORESULT; 1144*c5c4113dSnw141292 else 1145*c5c4113dSnw141292 *q->rc = (q->got_samAcctName && 1146*c5c4113dSnw141292 q->got_objectClass) ? 1147*c5c4113dSnw141292 IDMAP_SUCCESS : IDMAP_ERR_NORESULT; 1148*c5c4113dSnw141292 1149*c5c4113dSnw141292 if (*q->rc == IDMAP_SUCCESS && *q->result == NULL) 1150*c5c4113dSnw141292 *q->rc = IDMAP_ERR_NORESULT; 1151*c5c4113dSnw141292 } 1152*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 1153*c5c4113dSnw141292 1154*c5c4113dSnw141292 /* 1155*c5c4113dSnw141292 * If there should be multiple partial results for different 1156*c5c4113dSnw141292 * entities (there should not be, but, if it should happen) then 1157*c5c4113dSnw141292 * it's possible that they could get mixed up here and we could 1158*c5c4113dSnw141292 * get bogus results. We just mark the query's results as 1159*c5c4113dSnw141292 * toxic (IDMAP_ERR_INTERNAL). 1160*c5c4113dSnw141292 * 1161*c5c4113dSnw141292 * Between this and ignoring results when we've already filled 1162*c5c4113dSnw141292 * out a query's results we should be OK. The first full reply 1163*c5c4113dSnw141292 * wins. In practice we should never get multiple results. 1164*c5c4113dSnw141292 */ 1165*c5c4113dSnw141292 if (orc == IDMAP_ERR_INTERNAL) 1166*c5c4113dSnw141292 *q->rc = IDMAP_ERR_INTERNAL; 1167*c5c4113dSnw141292 else if (*q->rc != IDMAP_SUCCESS) 1168*c5c4113dSnw141292 *q->rc = IDMAP_ERR_INTERNAL; 1169*c5c4113dSnw141292 1170*c5c4113dSnw141292 if (ber != NULL) 1171*c5c4113dSnw141292 ber_free(ber, 0); 1172*c5c4113dSnw141292 1173*c5c4113dSnw141292 ldap_memfree(dn); 1174*c5c4113dSnw141292 } 1175*c5c4113dSnw141292 1176*c5c4113dSnw141292 /* 1177*c5c4113dSnw141292 * Try to get a result; if there is one, find the corresponding 1178*c5c4113dSnw141292 * idmap_q_t and process the result. 1179*c5c4113dSnw141292 */ 1180*c5c4113dSnw141292 static 1181*c5c4113dSnw141292 int 1182*c5c4113dSnw141292 idmap_get_adobject_batch(ad_host_t *adh, struct timeval *timeout) 1183*c5c4113dSnw141292 { 1184*c5c4113dSnw141292 idmap_query_state_t *query_state; 1185*c5c4113dSnw141292 LDAPMessage *res = NULL; 1186*c5c4113dSnw141292 int rc, ret, msgid, qid; 1187*c5c4113dSnw141292 1188*c5c4113dSnw141292 (void) pthread_mutex_lock(&adh->lock); 1189*c5c4113dSnw141292 if (adh->dead) { 1190*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 1191*c5c4113dSnw141292 return (-1); 1192*c5c4113dSnw141292 } 1193*c5c4113dSnw141292 1194*c5c4113dSnw141292 /* Get one result */ 1195*c5c4113dSnw141292 rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, 1196*c5c4113dSnw141292 timeout, &res); 1197*c5c4113dSnw141292 if (rc == LDAP_UNAVAILABLE || rc == LDAP_UNWILLING_TO_PERFORM || 1198*c5c4113dSnw141292 rc == LDAP_CONNECT_ERROR || rc == LDAP_SERVER_DOWN || 1199*c5c4113dSnw141292 rc == LDAP_BUSY) 1200*c5c4113dSnw141292 adh->dead = 1; 1201*c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 1202*c5c4113dSnw141292 1203*c5c4113dSnw141292 if (adh->dead) 1204*c5c4113dSnw141292 return (-1); 1205*c5c4113dSnw141292 1206*c5c4113dSnw141292 switch (rc) { 1207*c5c4113dSnw141292 case LDAP_RES_SEARCH_RESULT: 1208*c5c4113dSnw141292 /* We have all the LDAP replies for some search... */ 1209*c5c4113dSnw141292 msgid = ldap_msgid(res); 1210*c5c4113dSnw141292 if (idmap_msgid2query(adh, msgid, 1211*c5c4113dSnw141292 &query_state, &qid)) { 1212*c5c4113dSnw141292 /* ...so we can decrement qinflight */ 1213*c5c4113dSnw141292 atomic_dec_32(&query_state->qinflight); 1214*c5c4113dSnw141292 /* we saw at least one reply */ 1215*c5c4113dSnw141292 query_state->queries[qid].got_reply = 1; 1216*c5c4113dSnw141292 } 1217*c5c4113dSnw141292 (void) ldap_msgfree(res); 1218*c5c4113dSnw141292 ret = 0; 1219*c5c4113dSnw141292 break; 1220*c5c4113dSnw141292 case LDAP_RES_SEARCH_REFERENCE: 1221*c5c4113dSnw141292 /* 1222*c5c4113dSnw141292 * We have no need for these at the moment. Eventually, 1223*c5c4113dSnw141292 * when we query things that we can't expect to find in 1224*c5c4113dSnw141292 * the Global Catalog then we'll need to learn to follow 1225*c5c4113dSnw141292 * references. 1226*c5c4113dSnw141292 */ 1227*c5c4113dSnw141292 (void) ldap_msgfree(res); 1228*c5c4113dSnw141292 ret = 0; 1229*c5c4113dSnw141292 break; 1230*c5c4113dSnw141292 case LDAP_RES_SEARCH_ENTRY: 1231*c5c4113dSnw141292 /* Got a result */ 1232*c5c4113dSnw141292 msgid = ldap_msgid(res); 1233*c5c4113dSnw141292 if (idmap_msgid2query(adh, msgid, 1234*c5c4113dSnw141292 &query_state, &qid)) { 1235*c5c4113dSnw141292 idmap_extract_object(query_state, qid, res); 1236*c5c4113dSnw141292 /* we saw at least one result */ 1237*c5c4113dSnw141292 query_state->queries[qid].got_reply = 1; 1238*c5c4113dSnw141292 query_state->queries[qid].got_results = 1; 1239*c5c4113dSnw141292 } 1240*c5c4113dSnw141292 (void) ldap_msgfree(res); 1241*c5c4113dSnw141292 ret = 0; 1242*c5c4113dSnw141292 break; 1243*c5c4113dSnw141292 default: 1244*c5c4113dSnw141292 /* timeout or error; treat the same */ 1245*c5c4113dSnw141292 ret = -1; 1246*c5c4113dSnw141292 break; 1247*c5c4113dSnw141292 } 1248*c5c4113dSnw141292 1249*c5c4113dSnw141292 return (ret); 1250*c5c4113dSnw141292 } 1251*c5c4113dSnw141292 1252*c5c4113dSnw141292 void 1253*c5c4113dSnw141292 idmap_lookup_free_batch(idmap_query_state_t **state) 1254*c5c4113dSnw141292 { 1255*c5c4113dSnw141292 idmap_query_state_t **p; 1256*c5c4113dSnw141292 1257*c5c4113dSnw141292 idmap_release_conn((*state)->qadh); 1258*c5c4113dSnw141292 1259*c5c4113dSnw141292 /* Remove this state struct from the list of state structs */ 1260*c5c4113dSnw141292 (void) pthread_mutex_lock(&qstatelock); 1261*c5c4113dSnw141292 for (p = &qstatehead; *p != NULL; p = &(*p)->next) { 1262*c5c4113dSnw141292 if (*p == (*state)) { 1263*c5c4113dSnw141292 *p = (*state)->next; 1264*c5c4113dSnw141292 break; 1265*c5c4113dSnw141292 } 1266*c5c4113dSnw141292 } 1267*c5c4113dSnw141292 (void) pthread_mutex_unlock(&qstatelock); 1268*c5c4113dSnw141292 1269*c5c4113dSnw141292 free(*state); 1270*c5c4113dSnw141292 *state = NULL; 1271*c5c4113dSnw141292 } 1272*c5c4113dSnw141292 1273*c5c4113dSnw141292 idmap_retcode 1274*c5c4113dSnw141292 idmap_lookup_batch_end(idmap_query_state_t **state, 1275*c5c4113dSnw141292 struct timeval *timeout) 1276*c5c4113dSnw141292 { 1277*c5c4113dSnw141292 idmap_q_t *q; 1278*c5c4113dSnw141292 int i; 1279*c5c4113dSnw141292 int rc = LDAP_SUCCESS; 1280*c5c4113dSnw141292 idmap_retcode retcode = IDMAP_SUCCESS; 1281*c5c4113dSnw141292 1282*c5c4113dSnw141292 (*state)->qdead = 1; 1283*c5c4113dSnw141292 1284*c5c4113dSnw141292 /* Process results until done or until timeout, if given */ 1285*c5c4113dSnw141292 while ((*state)->qinflight > 0) { 1286*c5c4113dSnw141292 if ((rc = idmap_get_adobject_batch((*state)->qadh, 1287*c5c4113dSnw141292 timeout)) != 0) 1288*c5c4113dSnw141292 break; 1289*c5c4113dSnw141292 } 1290*c5c4113dSnw141292 1291*c5c4113dSnw141292 if (rc == LDAP_UNAVAILABLE || rc == LDAP_UNWILLING_TO_PERFORM || 1292*c5c4113dSnw141292 rc == LDAP_CONNECT_ERROR || rc == LDAP_SERVER_DOWN || 1293*c5c4113dSnw141292 rc == LDAP_BUSY) { 1294*c5c4113dSnw141292 retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 1295*c5c4113dSnw141292 (*state)->qadh->dead = 1; 1296*c5c4113dSnw141292 } 1297*c5c4113dSnw141292 1298*c5c4113dSnw141292 for (i = 0; i < (*state)->qcount; i++) { 1299*c5c4113dSnw141292 q = &((*state)->queries[i]); 1300*c5c4113dSnw141292 if (q->got_reply && !q->got_results) { 1301*c5c4113dSnw141292 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 1302*c5c4113dSnw141292 *q->rc = IDMAP_ERR_RETRIABLE_NET_ERR; 1303*c5c4113dSnw141292 else 1304*c5c4113dSnw141292 *q->rc = IDMAP_ERR_NOTFOUND; 1305*c5c4113dSnw141292 } 1306*c5c4113dSnw141292 } 1307*c5c4113dSnw141292 1308*c5c4113dSnw141292 idmap_lookup_free_batch(state); 1309*c5c4113dSnw141292 1310*c5c4113dSnw141292 return (retcode); 1311*c5c4113dSnw141292 } 1312*c5c4113dSnw141292 1313*c5c4113dSnw141292 /* 1314*c5c4113dSnw141292 * Send one prepared search, queue up msgid, process what results are 1315*c5c4113dSnw141292 * available 1316*c5c4113dSnw141292 */ 1317*c5c4113dSnw141292 static 1318*c5c4113dSnw141292 idmap_retcode 1319*c5c4113dSnw141292 idmap_batch_add1(idmap_query_state_t *state, int n2s, 1320*c5c4113dSnw141292 const char *filter, const char *basedn, 1321*c5c4113dSnw141292 char **result, char **dname, rid_t *rid, int *sid_type, 1322*c5c4113dSnw141292 idmap_retcode *rc) 1323*c5c4113dSnw141292 { 1324*c5c4113dSnw141292 idmap_retcode retcode = IDMAP_SUCCESS; 1325*c5c4113dSnw141292 int lrc, qid; 1326*c5c4113dSnw141292 struct timeval tv; 1327*c5c4113dSnw141292 idmap_q_t *q; 1328*c5c4113dSnw141292 1329*c5c4113dSnw141292 if (state->qdead) { 1330*c5c4113dSnw141292 *rc = IDMAP_ERR_NORESULT; 1331*c5c4113dSnw141292 return (IDMAP_ERR_RETRIABLE_NET_ERR); 1332*c5c4113dSnw141292 } 1333*c5c4113dSnw141292 1334*c5c4113dSnw141292 qid = atomic_inc_32_nv(&state->qlastsent) - 1; 1335*c5c4113dSnw141292 1336*c5c4113dSnw141292 q = &(state->queries[qid]); 1337*c5c4113dSnw141292 1338*c5c4113dSnw141292 /* Remember where to put the results */ 1339*c5c4113dSnw141292 q->result = result; 1340*c5c4113dSnw141292 q->domain = dname; 1341*c5c4113dSnw141292 q->rid = rid; 1342*c5c4113dSnw141292 q->sid_type = sid_type; 1343*c5c4113dSnw141292 q->rc = rc; 1344*c5c4113dSnw141292 q->n2s = n2s ? 1 : 0; 1345*c5c4113dSnw141292 q->got_objectSid = 0; 1346*c5c4113dSnw141292 q->got_objectClass = 0; 1347*c5c4113dSnw141292 q->got_samAcctName = 0; 1348*c5c4113dSnw141292 1349*c5c4113dSnw141292 /* 1350*c5c4113dSnw141292 * Provide sane defaults for the results in case we never hear 1351*c5c4113dSnw141292 * back from the DS before closing the connection. 1352*c5c4113dSnw141292 */ 1353*c5c4113dSnw141292 *rc = IDMAP_ERR_RETRIABLE_NET_ERR; 1354*c5c4113dSnw141292 *sid_type = _IDMAP_T_OTHER; 1355*c5c4113dSnw141292 *result = NULL; 1356*c5c4113dSnw141292 if (dname != NULL) 1357*c5c4113dSnw141292 *dname = NULL; 1358*c5c4113dSnw141292 if (rid != NULL) 1359*c5c4113dSnw141292 *rid = 0; 1360*c5c4113dSnw141292 1361*c5c4113dSnw141292 /* Send this lookup, don't wait for a result here */ 1362*c5c4113dSnw141292 (void) pthread_mutex_lock(&state->qadh->lock); 1363*c5c4113dSnw141292 1364*c5c4113dSnw141292 if (!state->qadh->dead) { 1365*c5c4113dSnw141292 state->qadh->idletime = time(NULL); 1366*c5c4113dSnw141292 lrc = ldap_search_ext(state->qadh->ld, basedn, 1367*c5c4113dSnw141292 LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, 1368*c5c4113dSnw141292 NULL, -1, &q->msgid); 1369*c5c4113dSnw141292 if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE || 1370*c5c4113dSnw141292 lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN || 1371*c5c4113dSnw141292 lrc == LDAP_UNWILLING_TO_PERFORM) { 1372*c5c4113dSnw141292 retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 1373*c5c4113dSnw141292 state->qadh->dead = 1; 1374*c5c4113dSnw141292 } else if (lrc != LDAP_SUCCESS) { 1375*c5c4113dSnw141292 retcode = IDMAP_ERR_OTHER; 1376*c5c4113dSnw141292 state->qadh->dead = 1; 1377*c5c4113dSnw141292 } 1378*c5c4113dSnw141292 } 1379*c5c4113dSnw141292 (void) pthread_mutex_unlock(&state->qadh->lock); 1380*c5c4113dSnw141292 1381*c5c4113dSnw141292 if (state->qadh->dead) 1382*c5c4113dSnw141292 return (retcode); 1383*c5c4113dSnw141292 1384*c5c4113dSnw141292 atomic_inc_32(&state->qinflight); 1385*c5c4113dSnw141292 1386*c5c4113dSnw141292 /* 1387*c5c4113dSnw141292 * Reap as many requests as we can _without_ waiting 1388*c5c4113dSnw141292 * 1389*c5c4113dSnw141292 * We do this to prevent any possible TCP socket buffer 1390*c5c4113dSnw141292 * starvation deadlocks. 1391*c5c4113dSnw141292 */ 1392*c5c4113dSnw141292 (void) memset(&tv, 0, sizeof (tv)); 1393*c5c4113dSnw141292 while (idmap_get_adobject_batch(state->qadh, &tv) == 0) 1394*c5c4113dSnw141292 ; 1395*c5c4113dSnw141292 1396*c5c4113dSnw141292 return (IDMAP_SUCCESS); 1397*c5c4113dSnw141292 } 1398*c5c4113dSnw141292 1399*c5c4113dSnw141292 idmap_retcode 1400*c5c4113dSnw141292 idmap_name2sid_batch_add1(idmap_query_state_t *state, 1401*c5c4113dSnw141292 const char *name, const char *dname, 1402*c5c4113dSnw141292 char **sid, rid_t *rid, int *sid_type, idmap_retcode *rc) 1403*c5c4113dSnw141292 { 1404*c5c4113dSnw141292 idmap_retcode retcode; 1405*c5c4113dSnw141292 int flen, samAcctNameLen; 1406*c5c4113dSnw141292 char *filter = NULL; 1407*c5c4113dSnw141292 char *basedn = NULL; 1408*c5c4113dSnw141292 char *cp; 1409*c5c4113dSnw141292 1410*c5c4113dSnw141292 /* 1411*c5c4113dSnw141292 * Strategy: search [the global catalog] for user/group by 1412*c5c4113dSnw141292 * sAMAccountName = user/groupname with base DN derived from the 1413*c5c4113dSnw141292 * domain name. The objectSid and objectClass of the result are 1414*c5c4113dSnw141292 * all we need to figure out the SID of the user/group and 1415*c5c4113dSnw141292 * whether it is a user or a group. 1416*c5c4113dSnw141292 */ 1417*c5c4113dSnw141292 1418*c5c4113dSnw141292 /* 1419*c5c4113dSnw141292 * Handle optional domain parameter and default domain 1420*c5c4113dSnw141292 * semantics. The get a basedn from the domainname. 1421*c5c4113dSnw141292 */ 1422*c5c4113dSnw141292 if (dname == NULL || *dname != '\0') { 1423*c5c4113dSnw141292 /* domain name not given separately */ 1424*c5c4113dSnw141292 if ((cp = strchr(name, '@')) == NULL) { 1425*c5c4113dSnw141292 /* nor is the name qualified */ 1426*c5c4113dSnw141292 dname = state->qadh->owner->dflt_w2k_dom; 1427*c5c4113dSnw141292 basedn = state->qadh->owner->basedn; 1428*c5c4113dSnw141292 samAcctNameLen = strlen(name); 1429*c5c4113dSnw141292 } else { 1430*c5c4113dSnw141292 /* the name is qualified */ 1431*c5c4113dSnw141292 /* LINTED */ 1432*c5c4113dSnw141292 samAcctNameLen = cp - name; 1433*c5c4113dSnw141292 dname = cp + 1; 1434*c5c4113dSnw141292 } 1435*c5c4113dSnw141292 } 1436*c5c4113dSnw141292 1437*c5c4113dSnw141292 if (basedn == NULL) 1438*c5c4113dSnw141292 basedn = dns2dn(dname); 1439*c5c4113dSnw141292 1440*c5c4113dSnw141292 /* Assemble filter */ 1441*c5c4113dSnw141292 flen = snprintf(NULL, 0, SANFILTER, samAcctNameLen, name) + 1; 1442*c5c4113dSnw141292 if ((filter = (char *)malloc(flen)) == NULL) { 1443*c5c4113dSnw141292 if (basedn != state->qadh->owner->basedn) 1444*c5c4113dSnw141292 free(basedn); 1445*c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 1446*c5c4113dSnw141292 } 1447*c5c4113dSnw141292 (void) snprintf(filter, flen, SANFILTER, samAcctNameLen, name); 1448*c5c4113dSnw141292 1449*c5c4113dSnw141292 retcode = idmap_batch_add1(state, 1, filter, basedn, 1450*c5c4113dSnw141292 sid, NULL, rid, sid_type, rc); 1451*c5c4113dSnw141292 1452*c5c4113dSnw141292 if (basedn != state->qadh->owner->basedn) 1453*c5c4113dSnw141292 free(basedn); 1454*c5c4113dSnw141292 free(filter); 1455*c5c4113dSnw141292 1456*c5c4113dSnw141292 return (retcode); 1457*c5c4113dSnw141292 } 1458*c5c4113dSnw141292 1459*c5c4113dSnw141292 idmap_retcode 1460*c5c4113dSnw141292 idmap_sid2name_batch_add1(idmap_query_state_t *state, 1461*c5c4113dSnw141292 const char *sid, const rid_t *rid, 1462*c5c4113dSnw141292 char **name, char **dname, int *sid_type, idmap_retcode *rc) 1463*c5c4113dSnw141292 { 1464*c5c4113dSnw141292 idmap_retcode retcode; 1465*c5c4113dSnw141292 int flen, ret; 1466*c5c4113dSnw141292 char *filter = NULL; 1467*c5c4113dSnw141292 char cbinsid[MAXHEXBINSID + 1]; 1468*c5c4113dSnw141292 1469*c5c4113dSnw141292 /* 1470*c5c4113dSnw141292 * Strategy: search [the global catalog] for user/group by 1471*c5c4113dSnw141292 * objectSid = SID with empty base DN. The DN, sAMAccountName 1472*c5c4113dSnw141292 * and objectClass of the result are all we need to figure out 1473*c5c4113dSnw141292 * the name of the SID and whether it is a user, a group or a 1474*c5c4113dSnw141292 * computer. 1475*c5c4113dSnw141292 */ 1476*c5c4113dSnw141292 1477*c5c4113dSnw141292 ret = idmap_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid)); 1478*c5c4113dSnw141292 if (ret != 0) 1479*c5c4113dSnw141292 return (IDMAP_ERR_SID); 1480*c5c4113dSnw141292 1481*c5c4113dSnw141292 /* Assemble filter */ 1482*c5c4113dSnw141292 flen = snprintf(NULL, 0, OBJECTSIDFILTER, cbinsid) + 1; 1483*c5c4113dSnw141292 if ((filter = (char *)malloc(flen)) == NULL) 1484*c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 1485*c5c4113dSnw141292 (void) snprintf(filter, flen, OBJECTSIDFILTER, cbinsid); 1486*c5c4113dSnw141292 1487*c5c4113dSnw141292 retcode = idmap_batch_add1(state, 0, filter, NULL, name, dname, 1488*c5c4113dSnw141292 NULL, sid_type, rc); 1489*c5c4113dSnw141292 1490*c5c4113dSnw141292 free(filter); 1491*c5c4113dSnw141292 1492*c5c4113dSnw141292 return (retcode); 1493*c5c4113dSnw141292 } 1494