1c5c4113dSnw141292 /* 2c5c4113dSnw141292 * CDDL HEADER START 3c5c4113dSnw141292 * 4c5c4113dSnw141292 * The contents of this file are subject to the terms of the 5c5c4113dSnw141292 * Common Development and Distribution License (the "License"). 6c5c4113dSnw141292 * You may not use this file except in compliance with the License. 7c5c4113dSnw141292 * 8c5c4113dSnw141292 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9c5c4113dSnw141292 * or http://www.opensolaris.org/os/licensing. 10c5c4113dSnw141292 * See the License for the specific language governing permissions 11c5c4113dSnw141292 * and limitations under the License. 12c5c4113dSnw141292 * 13c5c4113dSnw141292 * When distributing Covered Code, include this CDDL HEADER in each 14c5c4113dSnw141292 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15c5c4113dSnw141292 * If applicable, add the following below this CDDL HEADER, with the 16c5c4113dSnw141292 * fields enclosed by brackets "[]" replaced with your own identifying 17c5c4113dSnw141292 * information: Portions Copyright [yyyy] [name of copyright owner] 18c5c4113dSnw141292 * 19c5c4113dSnw141292 * CDDL HEADER END 20c5c4113dSnw141292 */ 21c5c4113dSnw141292 22c5c4113dSnw141292 /* 23c5c4113dSnw141292 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 24c5c4113dSnw141292 * Use is subject to license terms. 25c5c4113dSnw141292 */ 26c5c4113dSnw141292 27c5c4113dSnw141292 #pragma ident "%Z%%M% %I% %E% SMI" 28c5c4113dSnw141292 29c5c4113dSnw141292 /* 30c5c4113dSnw141292 * Processes name2sid & sid2name batched lookups for a given user or 31c5c4113dSnw141292 * computer from an AD Directory server using GSSAPI authentication 32c5c4113dSnw141292 */ 33c5c4113dSnw141292 34c5c4113dSnw141292 #include <stdio.h> 35c5c4113dSnw141292 #include <stdlib.h> 36c5c4113dSnw141292 #include <alloca.h> 37c5c4113dSnw141292 #include <string.h> 38c5c4113dSnw141292 #include <strings.h> 39c5c4113dSnw141292 #include <lber.h> 40c5c4113dSnw141292 #include <ldap.h> 41c5c4113dSnw141292 #include <sasl/sasl.h> 42c5c4113dSnw141292 #include <string.h> 43c5c4113dSnw141292 #include <ctype.h> 44c5c4113dSnw141292 #include <pthread.h> 45c5c4113dSnw141292 #include <synch.h> 46c5c4113dSnw141292 #include <atomic.h> 47c5c4113dSnw141292 #include <errno.h> 48c5c4113dSnw141292 #include <assert.h> 49c5c4113dSnw141292 #include <limits.h> 50cd37da74Snw141292 #include <sys/u8_textprep.h> 51c5c4113dSnw141292 #include "idmapd.h" 52c5c4113dSnw141292 53c5c4113dSnw141292 /* 54c5c4113dSnw141292 * Internal data structures for this code 55c5c4113dSnw141292 */ 56c5c4113dSnw141292 57c5c4113dSnw141292 /* Attribute names and filter format strings */ 58e3c2d6aaSnw141292 #define SAN "sAMAccountName" 59e3c2d6aaSnw141292 #define OBJSID "objectSid" 60e3c2d6aaSnw141292 #define OBJCLASS "objectClass" 61c5c4113dSnw141292 #define SANFILTER "(sAMAccountName=%.*s)" 62e3c2d6aaSnw141292 #define OBJSIDFILTER "(objectSid=%s)" 63c5c4113dSnw141292 64c5c4113dSnw141292 /* 65c5c4113dSnw141292 * This should really be in some <sys/sid.h> file or so; we have a 66c5c4113dSnw141292 * private version of sid_t, and so must other components of ON until we 67c5c4113dSnw141292 * rationalize this. 68c5c4113dSnw141292 */ 69c5c4113dSnw141292 typedef struct sid { 70c5c4113dSnw141292 uchar_t version; 71c5c4113dSnw141292 uchar_t sub_authority_count; 72c5c4113dSnw141292 uint64_t authority; /* really, 48-bits */ 73c5c4113dSnw141292 rid_t sub_authorities[SID_MAX_SUB_AUTHORITIES]; 74c5c4113dSnw141292 } sid_t; 75c5c4113dSnw141292 76c5c4113dSnw141292 /* A single DS */ 77c5c4113dSnw141292 typedef struct ad_host { 78c5c4113dSnw141292 struct ad_host *next; 79c5c4113dSnw141292 ad_t *owner; /* ad_t to which this belongs */ 80c5c4113dSnw141292 pthread_mutex_t lock; 81c5c4113dSnw141292 LDAP *ld; /* LDAP connection */ 82c5c4113dSnw141292 uint32_t ref; /* ref count */ 83c5c4113dSnw141292 time_t idletime; /* time since last activity */ 84c5c4113dSnw141292 int dead; /* error on LDAP connection */ 85c5c4113dSnw141292 /* 86c5c4113dSnw141292 * Used to distinguish between different instances of LDAP 87c5c4113dSnw141292 * connections to this same DS. We need this so we never mix up 88c5c4113dSnw141292 * results for a given msgID from one connection with those of 89c5c4113dSnw141292 * another earlier connection where two batch state structures 90c5c4113dSnw141292 * share this ad_host object but used different LDAP connections 91c5c4113dSnw141292 * to send their LDAP searches. 92c5c4113dSnw141292 */ 93c5c4113dSnw141292 uint64_t generation; 94c5c4113dSnw141292 95c5c4113dSnw141292 /* LDAP DS info */ 96c5c4113dSnw141292 char *host; 97c5c4113dSnw141292 int port; 98c5c4113dSnw141292 99c5c4113dSnw141292 /* hardwired to SASL GSSAPI only for now */ 100c5c4113dSnw141292 char *saslmech; 101c5c4113dSnw141292 unsigned saslflags; 102c5c4113dSnw141292 } ad_host_t; 103c5c4113dSnw141292 104c5c4113dSnw141292 /* A set of DSs for a given AD partition; ad_t typedef comes from adutil.h */ 105c5c4113dSnw141292 struct ad { 106c5c4113dSnw141292 char *dflt_w2k_dom; /* used to qualify bare names */ 107c5c4113dSnw141292 pthread_mutex_t lock; 108c5c4113dSnw141292 uint32_t ref; 109c8e26105Sjp151216 ad_host_t *last_adh; 110c5c4113dSnw141292 idmap_ad_partition_t partition; /* Data or global catalog? */ 111c5c4113dSnw141292 }; 112c5c4113dSnw141292 113c5c4113dSnw141292 /* 114c5c4113dSnw141292 * A place to put the results of a batched (async) query 115c5c4113dSnw141292 * 116c5c4113dSnw141292 * There is one of these for every query added to a batch object 117c5c4113dSnw141292 * (idmap_query_state, see below). 118c5c4113dSnw141292 */ 119c5c4113dSnw141292 typedef struct idmap_q { 120e3c2d6aaSnw141292 /* 121e3c2d6aaSnw141292 * data used for validating search result entries for name->SID 122*e8c27ec8Sbaban * lookups 123e3c2d6aaSnw141292 */ 124cd37da74Snw141292 char *ecanonname; /* expected canon name */ 125cd37da74Snw141292 char *edomain; /* expected domain name */ 126*e8c27ec8Sbaban int eunixtype; /* expected unix type */ 127e3c2d6aaSnw141292 /* results */ 128cd37da74Snw141292 char **canonname; /* actual canon name */ 129c5c4113dSnw141292 char **domain; /* name of domain of object */ 130*e8c27ec8Sbaban char **sid; /* stringified SID */ 131*e8c27ec8Sbaban rid_t *rid; /* RID */ 132*e8c27ec8Sbaban int *sid_type; /* user or group SID? */ 133*e8c27ec8Sbaban char **unixname; /* unixname for name mapping */ 134c5c4113dSnw141292 idmap_retcode *rc; 135e3c2d6aaSnw141292 136e3c2d6aaSnw141292 /* lookup state */ 137c5c4113dSnw141292 int msgid; /* LDAP message ID */ 138c5c4113dSnw141292 } idmap_q_t; 139c5c4113dSnw141292 140c5c4113dSnw141292 /* Batch context structure; typedef is in header file */ 141c5c4113dSnw141292 struct idmap_query_state { 142c5c4113dSnw141292 idmap_query_state_t *next; 143c5c4113dSnw141292 int qcount; /* how many queries */ 14484decf41Sjp151216 int ref_cnt; /* reference count */ 14584decf41Sjp151216 pthread_cond_t cv; /* Condition wait variable */ 146c5c4113dSnw141292 uint32_t qlastsent; 147c5c4113dSnw141292 uint32_t qinflight; /* how many queries in flight */ 148c5c4113dSnw141292 uint16_t qdead; /* oops, lost LDAP connection */ 149c5c4113dSnw141292 ad_host_t *qadh; /* LDAP connection */ 150c5c4113dSnw141292 uint64_t qadh_gen; /* same as qadh->generation */ 151*e8c27ec8Sbaban const char *ad_unixuser_attr; 152*e8c27ec8Sbaban const char *ad_unixgroup_attr; 153c5c4113dSnw141292 idmap_q_t queries[1]; /* array of query results */ 154c5c4113dSnw141292 }; 155c5c4113dSnw141292 156c5c4113dSnw141292 /* 157c5c4113dSnw141292 * List of query state structs -- needed so we can "route" LDAP results 158c5c4113dSnw141292 * to the right context if multiple threads should be using the same 159c5c4113dSnw141292 * connection concurrently 160c5c4113dSnw141292 */ 161c5c4113dSnw141292 static idmap_query_state_t *qstatehead = NULL; 162c5c4113dSnw141292 static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER; 163c5c4113dSnw141292 164c5c4113dSnw141292 /* 165c5c4113dSnw141292 * List of DSs, needed by the idle connection reaper thread 166c5c4113dSnw141292 */ 167c5c4113dSnw141292 static ad_host_t *host_head = NULL; 168651c0131Sbaban static pthread_t reaperid = 0; 169c5c4113dSnw141292 static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER; 170c5c4113dSnw141292 17184decf41Sjp151216 17284decf41Sjp151216 static void 17384decf41Sjp151216 idmap_lookup_unlock_batch(idmap_query_state_t **state); 17484decf41Sjp151216 175c8e26105Sjp151216 static void 176c8e26105Sjp151216 delete_ds(ad_t *ad, const char *host, int port); 17784decf41Sjp151216 178c5c4113dSnw141292 /*ARGSUSED*/ 179c5c4113dSnw141292 static int 180c5c4113dSnw141292 idmap_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) { 181c5c4113dSnw141292 sasl_interact_t *interact; 182c5c4113dSnw141292 183c5c4113dSnw141292 if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE) 184c5c4113dSnw141292 return (LDAP_PARAM_ERROR); 185c5c4113dSnw141292 186c5c4113dSnw141292 /* There should be no extra arguemnts for SASL/GSSAPI authentication */ 187c5c4113dSnw141292 for (interact = prompts; interact->id != SASL_CB_LIST_END; 188c5c4113dSnw141292 interact++) { 189c5c4113dSnw141292 interact->result = NULL; 190c5c4113dSnw141292 interact->len = 0; 191c5c4113dSnw141292 } 192c5c4113dSnw141292 return (LDAP_SUCCESS); 193c5c4113dSnw141292 } 194c5c4113dSnw141292 195c5c4113dSnw141292 196c5c4113dSnw141292 /* 197c5c4113dSnw141292 * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other 198e3c2d6aaSnw141292 * attributes (CN, etc...). We don't need the reverse, for now. 199c5c4113dSnw141292 */ 200c5c4113dSnw141292 static 201c5c4113dSnw141292 char * 202c5c4113dSnw141292 dn2dns(const char *dn) 203c5c4113dSnw141292 { 204c5c4113dSnw141292 char **rdns = NULL; 205c5c4113dSnw141292 char **attrs = NULL; 206c5c4113dSnw141292 char **labels = NULL; 207c5c4113dSnw141292 char *dns = NULL; 208c5c4113dSnw141292 char **rdn, **attr, **label; 209c5c4113dSnw141292 int maxlabels = 5; 210c5c4113dSnw141292 int nlabels = 0; 211c5c4113dSnw141292 int dnslen; 212c5c4113dSnw141292 213c5c4113dSnw141292 /* 214c5c4113dSnw141292 * There is no reverse of ldap_dns_to_dn() in our libldap, so we 215c5c4113dSnw141292 * have to do the hard work here for now. 216c5c4113dSnw141292 */ 217c5c4113dSnw141292 218c5c4113dSnw141292 /* 219c5c4113dSnw141292 * This code is much too liberal: it looks for "dc" attributes 220c5c4113dSnw141292 * in all RDNs of the DN. In theory this could cause problems 221c5c4113dSnw141292 * if people were to use "dc" in nodes other than the root of 222c5c4113dSnw141292 * the tree, but in practice noone, least of all Active 223c5c4113dSnw141292 * Directory, does that. 224c5c4113dSnw141292 * 225c5c4113dSnw141292 * On the other hand, this code is much too conservative: it 226c5c4113dSnw141292 * does not make assumptions about ldap_explode_dn(), and _that_ 227c5c4113dSnw141292 * is the true for looking at every attr of every RDN. 228c5c4113dSnw141292 * 229c5c4113dSnw141292 * Since we only ever look at dc and those must be DNS labels, 230c5c4113dSnw141292 * at least until we get around to supporting IDN here we 231c5c4113dSnw141292 * shouldn't see escaped labels from AD nor from libldap, though 232c5c4113dSnw141292 * the spec (RFC2253) does allow libldap to escape things that 233c5c4113dSnw141292 * don't need escaping -- if that should ever happen then 234c5c4113dSnw141292 * libldap will need a spanking, and we can take care of that. 235c5c4113dSnw141292 */ 236c5c4113dSnw141292 237c5c4113dSnw141292 /* Explode a DN into RDNs */ 238c5c4113dSnw141292 if ((rdns = ldap_explode_dn(dn, 0)) == NULL) 239c5c4113dSnw141292 return (NULL); 240c5c4113dSnw141292 241c5c4113dSnw141292 labels = calloc(maxlabels + 1, sizeof (char *)); 242c5c4113dSnw141292 label = labels; 243c5c4113dSnw141292 244c5c4113dSnw141292 for (rdn = rdns; *rdn != NULL; rdn++) { 245c5c4113dSnw141292 if (attrs != NULL) 246c5c4113dSnw141292 ldap_value_free(attrs); 247c5c4113dSnw141292 248c5c4113dSnw141292 /* Explode each RDN, look for DC attr, save val as DNS label */ 249c5c4113dSnw141292 if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) 250c5c4113dSnw141292 goto done; 251c5c4113dSnw141292 252c5c4113dSnw141292 for (attr = attrs; *attr != NULL; attr++) { 253c5c4113dSnw141292 if (strncasecmp(*attr, "dc=", 3) != 0) 254c5c4113dSnw141292 continue; 255c5c4113dSnw141292 256c5c4113dSnw141292 /* Found a DNS label */ 257c5c4113dSnw141292 labels[nlabels++] = strdup((*attr) + 3); 258c5c4113dSnw141292 259c5c4113dSnw141292 if (nlabels == maxlabels) { 260c5c4113dSnw141292 char **tmp; 261c5c4113dSnw141292 tmp = realloc(labels, 262c5c4113dSnw141292 sizeof (char *) * (maxlabels + 1)); 263c5c4113dSnw141292 264c5c4113dSnw141292 if (tmp == NULL) 265c5c4113dSnw141292 goto done; 266c5c4113dSnw141292 267c5c4113dSnw141292 labels = tmp; 268c5c4113dSnw141292 labels[nlabels] = NULL; 269c5c4113dSnw141292 } 270c5c4113dSnw141292 271c5c4113dSnw141292 /* There should be just one DC= attr per-RDN */ 272c5c4113dSnw141292 break; 273c5c4113dSnw141292 } 274c5c4113dSnw141292 } 275c5c4113dSnw141292 276c5c4113dSnw141292 /* 277c5c4113dSnw141292 * Got all the labels, now join with '.' 278c5c4113dSnw141292 * 279c5c4113dSnw141292 * We need room for nlabels - 1 periods ('.'), one nul 280c5c4113dSnw141292 * terminator, and the strlen() of each label. 281c5c4113dSnw141292 */ 282c5c4113dSnw141292 dnslen = nlabels; 283c5c4113dSnw141292 for (label = labels; *label != NULL; label++) 284c5c4113dSnw141292 dnslen += strlen(*label); 285c5c4113dSnw141292 286c5c4113dSnw141292 if ((dns = malloc(dnslen)) == NULL) 287c5c4113dSnw141292 goto done; 288c5c4113dSnw141292 289c5c4113dSnw141292 *dns = '\0'; 290c5c4113dSnw141292 291c5c4113dSnw141292 for (label = labels; *label != NULL; label++) { 292c5c4113dSnw141292 (void) strlcat(dns, *label, dnslen); 293c5c4113dSnw141292 /* 294c5c4113dSnw141292 * NOTE: the last '.' won't be appended -- there's no room 295c5c4113dSnw141292 * for it! 296c5c4113dSnw141292 */ 297c5c4113dSnw141292 (void) strlcat(dns, ".", dnslen); 298c5c4113dSnw141292 } 299c5c4113dSnw141292 300c5c4113dSnw141292 done: 301c5c4113dSnw141292 if (labels != NULL) { 302c5c4113dSnw141292 for (label = labels; *label != NULL; label++) 303c5c4113dSnw141292 free(*label); 304c5c4113dSnw141292 free(labels); 305c5c4113dSnw141292 } 306c5c4113dSnw141292 if (attrs != NULL) 307c5c4113dSnw141292 ldap_value_free(attrs); 308c5c4113dSnw141292 if (rdns != NULL) 309c5c4113dSnw141292 ldap_value_free(rdns); 310c5c4113dSnw141292 311c5c4113dSnw141292 return (dns); 312c5c4113dSnw141292 } 313c5c4113dSnw141292 314c5c4113dSnw141292 /* 315c5c4113dSnw141292 * Keep connection management simple for now, extend or replace later 316c5c4113dSnw141292 * with updated libsldap code. 317c5c4113dSnw141292 */ 318c5c4113dSnw141292 #define ADREAPERSLEEP 60 319c5c4113dSnw141292 #define ADCONN_TIME 300 320c5c4113dSnw141292 321c5c4113dSnw141292 /* 322c5c4113dSnw141292 * Idle connection reaping side of connection management 323c5c4113dSnw141292 * 324c5c4113dSnw141292 * Every minute wake up and look for connections that have been idle for 325c5c4113dSnw141292 * five minutes or more and close them. 326c5c4113dSnw141292 */ 327c5c4113dSnw141292 /*ARGSUSED*/ 328c5c4113dSnw141292 static 329c5c4113dSnw141292 void 330c5c4113dSnw141292 adreaper(void *arg) 331c5c4113dSnw141292 { 332c5c4113dSnw141292 ad_host_t *adh; 333c5c4113dSnw141292 time_t now; 334c5c4113dSnw141292 timespec_t ts; 335c5c4113dSnw141292 336c5c4113dSnw141292 ts.tv_sec = ADREAPERSLEEP; 337c5c4113dSnw141292 ts.tv_nsec = 0; 338c5c4113dSnw141292 339c5c4113dSnw141292 for (;;) { 340c5c4113dSnw141292 /* 341c5c4113dSnw141292 * nanosleep(3RT) is thead-safe (no SIGALRM) and more 342c5c4113dSnw141292 * portable than usleep(3C) 343c5c4113dSnw141292 */ 344c5c4113dSnw141292 (void) nanosleep(&ts, NULL); 345c5c4113dSnw141292 (void) pthread_mutex_lock(&adhostlock); 346c5c4113dSnw141292 now = time(NULL); 347c5c4113dSnw141292 for (adh = host_head; adh != NULL; adh = adh->next) { 348c5c4113dSnw141292 (void) pthread_mutex_lock(&adh->lock); 349c5c4113dSnw141292 if (adh->ref == 0 && adh->idletime != 0 && 350c5c4113dSnw141292 adh->idletime + ADCONN_TIME < now) { 351c5c4113dSnw141292 if (adh->ld) { 352c5c4113dSnw141292 (void) ldap_unbind(adh->ld); 353c5c4113dSnw141292 adh->ld = NULL; 354c5c4113dSnw141292 adh->idletime = 0; 355c5c4113dSnw141292 adh->ref = 0; 356c5c4113dSnw141292 } 357c5c4113dSnw141292 } 358c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 359c5c4113dSnw141292 } 360c5c4113dSnw141292 (void) pthread_mutex_unlock(&adhostlock); 361c5c4113dSnw141292 } 362c5c4113dSnw141292 } 363c5c4113dSnw141292 364c5c4113dSnw141292 int 365c5c4113dSnw141292 idmap_ad_alloc(ad_t **new_ad, const char *default_domain, 366c5c4113dSnw141292 idmap_ad_partition_t part) 367c5c4113dSnw141292 { 368c5c4113dSnw141292 ad_t *ad; 369c5c4113dSnw141292 370c5c4113dSnw141292 *new_ad = NULL; 371c5c4113dSnw141292 372c5c4113dSnw141292 if ((default_domain == NULL || *default_domain == '\0') && 373c5c4113dSnw141292 part != IDMAP_AD_GLOBAL_CATALOG) 374c5c4113dSnw141292 return (-1); 375c5c4113dSnw141292 376c5c4113dSnw141292 if ((ad = calloc(1, sizeof (ad_t))) == NULL) 377c5c4113dSnw141292 return (-1); 378c5c4113dSnw141292 379c5c4113dSnw141292 ad->ref = 1; 380c5c4113dSnw141292 ad->partition = part; 381c5c4113dSnw141292 382c5c4113dSnw141292 /* 383c5c4113dSnw141292 * If default_domain is NULL, deal, deferring errors until 384c5c4113dSnw141292 * idmap_lookup_batch_start() -- this makes it easier on the 385c5c4113dSnw141292 * caller, who can simply observe lookups failing as opposed to 386c5c4113dSnw141292 * having to conditionalize calls to lookups according to 387c5c4113dSnw141292 * whether it has a non-NULL ad_t *. 388c5c4113dSnw141292 */ 389c5c4113dSnw141292 if (default_domain == NULL) 390c5c4113dSnw141292 default_domain = ""; 391c5c4113dSnw141292 392c5c4113dSnw141292 if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL) 393c5c4113dSnw141292 goto err; 394c5c4113dSnw141292 395c5c4113dSnw141292 if (pthread_mutex_init(&ad->lock, NULL) != 0) 396c5c4113dSnw141292 goto err; 397c5c4113dSnw141292 398c5c4113dSnw141292 *new_ad = ad; 399c5c4113dSnw141292 400c5c4113dSnw141292 return (0); 401c5c4113dSnw141292 err: 402c5c4113dSnw141292 if (ad->dflt_w2k_dom != NULL) 403c5c4113dSnw141292 free(ad->dflt_w2k_dom); 404c5c4113dSnw141292 free(ad); 405c5c4113dSnw141292 return (-1); 406c5c4113dSnw141292 } 407c5c4113dSnw141292 408c5c4113dSnw141292 409c5c4113dSnw141292 void 410c5c4113dSnw141292 idmap_ad_free(ad_t **ad) 411c5c4113dSnw141292 { 412c5c4113dSnw141292 ad_host_t *p; 413c8e26105Sjp151216 ad_host_t *prev; 414c5c4113dSnw141292 415c5c4113dSnw141292 if (ad == NULL || *ad == NULL) 416c5c4113dSnw141292 return; 417c5c4113dSnw141292 418c5c4113dSnw141292 (void) pthread_mutex_lock(&(*ad)->lock); 419c5c4113dSnw141292 420c5c4113dSnw141292 if (atomic_dec_32_nv(&(*ad)->ref) > 0) { 421c5c4113dSnw141292 (void) pthread_mutex_unlock(&(*ad)->lock); 422c5c4113dSnw141292 *ad = NULL; 423c5c4113dSnw141292 return; 424c5c4113dSnw141292 } 425c5c4113dSnw141292 426c8e26105Sjp151216 (void) pthread_mutex_lock(&adhostlock); 427c8e26105Sjp151216 prev = NULL; 428c8e26105Sjp151216 p = host_head; 429c8e26105Sjp151216 while (p != NULL) { 430c8e26105Sjp151216 if (p->owner != (*ad)) { 431c8e26105Sjp151216 prev = p; 432c8e26105Sjp151216 p = p->next; 433c5c4113dSnw141292 continue; 434c8e26105Sjp151216 } else { 435c8e26105Sjp151216 delete_ds((*ad), p->host, p->port); 436c8e26105Sjp151216 if (prev == NULL) 437c8e26105Sjp151216 p = host_head; 438c8e26105Sjp151216 else 439c8e26105Sjp151216 p = prev->next; 440c5c4113dSnw141292 } 441c8e26105Sjp151216 } 442c8e26105Sjp151216 (void) pthread_mutex_unlock(&adhostlock); 443c5c4113dSnw141292 444c5c4113dSnw141292 (void) pthread_mutex_unlock(&(*ad)->lock); 445c5c4113dSnw141292 (void) pthread_mutex_destroy(&(*ad)->lock); 446c5c4113dSnw141292 447e3c2d6aaSnw141292 free((*ad)->dflt_w2k_dom); 448c5c4113dSnw141292 free(*ad); 449c5c4113dSnw141292 450c5c4113dSnw141292 *ad = NULL; 451c5c4113dSnw141292 } 452c5c4113dSnw141292 453c8e26105Sjp151216 454c5c4113dSnw141292 static 455c5c4113dSnw141292 int 456c5c4113dSnw141292 idmap_open_conn(ad_host_t *adh) 457c5c4113dSnw141292 { 458c5c4113dSnw141292 int zero = 0; 459c5c4113dSnw141292 int timeoutms = 30 * 1000; 460c8e26105Sjp151216 int ldversion, rc; 461c8e26105Sjp151216 462c8e26105Sjp151216 if (adh == NULL) 463c8e26105Sjp151216 return (0); 464c8e26105Sjp151216 465c8e26105Sjp151216 (void) pthread_mutex_lock(&adh->lock); 466c8e26105Sjp151216 467c8e26105Sjp151216 if (!adh->dead && adh->ld != NULL) 468c8e26105Sjp151216 /* done! */ 469c8e26105Sjp151216 goto out; 470c8e26105Sjp151216 471c8e26105Sjp151216 if (adh->ld != NULL) { 472c8e26105Sjp151216 (void) ldap_unbind(adh->ld); 473c8e26105Sjp151216 adh->ld = NULL; 474c8e26105Sjp151216 } 475c5c4113dSnw141292 476c5c4113dSnw141292 atomic_inc_64(&adh->generation); 477c8e26105Sjp151216 478c8e26105Sjp151216 /* Open and bind an LDAP connection */ 479c5c4113dSnw141292 adh->ld = ldap_init(adh->host, adh->port); 480c8e26105Sjp151216 if (adh->ld == NULL) { 481c8e26105Sjp151216 idmapdlog(LOG_INFO, "ldap_init() to server " 482c8e26105Sjp151216 "%s port %d failed. (%s)", adh->host, 483c8e26105Sjp151216 adh->port, strerror(errno)); 484c8e26105Sjp151216 goto out; 485c8e26105Sjp151216 } 486c5c4113dSnw141292 ldversion = LDAP_VERSION3; 487c8e26105Sjp151216 (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion); 488c8e26105Sjp151216 (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 489c5c4113dSnw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero); 490c5c4113dSnw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero); 491c8e26105Sjp151216 (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms); 492c5c4113dSnw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 493c8e26105Sjp151216 rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */, 494c8e26105Sjp151216 adh->saslmech, NULL, NULL, adh->saslflags, &idmap_saslcallback, 495c8e26105Sjp151216 NULL); 496c5c4113dSnw141292 497c5c4113dSnw141292 if (rc != LDAP_SUCCESS) { 498c8e26105Sjp151216 (void) ldap_unbind(adh->ld); 499c8e26105Sjp151216 adh->ld = NULL; 500c8e26105Sjp151216 idmapdlog(LOG_INFO, "ldap_sasl_interactive_bind_s() to server " 501c8e26105Sjp151216 "%s port %d failed. (%s)", adh->host, adh->port, 502c8e26105Sjp151216 ldap_err2string(rc)); 503c5c4113dSnw141292 } 504c5c4113dSnw141292 505c8e26105Sjp151216 idmapdlog(LOG_DEBUG, "Using global catalog server %s:%d", 506c8e26105Sjp151216 adh->host, adh->port); 507c8e26105Sjp151216 508c8e26105Sjp151216 out: 509c8e26105Sjp151216 if (adh->ld != NULL) { 510c8e26105Sjp151216 atomic_inc_32(&adh->ref); 511c5c4113dSnw141292 adh->idletime = time(NULL); 512c8e26105Sjp151216 adh->dead = 0; 513c8e26105Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 514c8e26105Sjp151216 return (1); 515c8e26105Sjp151216 } 516c5c4113dSnw141292 517c8e26105Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 518c8e26105Sjp151216 return (0); 519c5c4113dSnw141292 } 520c5c4113dSnw141292 521c5c4113dSnw141292 522c5c4113dSnw141292 /* 523c5c4113dSnw141292 * Connection management: find an open connection or open one 524c5c4113dSnw141292 */ 525c5c4113dSnw141292 static 526c5c4113dSnw141292 ad_host_t * 527c8e26105Sjp151216 idmap_get_conn(ad_t *ad) 528c5c4113dSnw141292 { 529c5c4113dSnw141292 ad_host_t *adh = NULL; 530c8e26105Sjp151216 ad_host_t *first_adh, *next_adh; 531c8e26105Sjp151216 int seen_last; 532c8e26105Sjp151216 int tries = -1; 533c5c4113dSnw141292 534c8e26105Sjp151216 retry: 535c5c4113dSnw141292 (void) pthread_mutex_lock(&adhostlock); 536c5c4113dSnw141292 537c8e26105Sjp151216 if (host_head == NULL) 538c8e26105Sjp151216 goto out; 539c8e26105Sjp151216 540c8e26105Sjp151216 /* Try as many DSs as we have, once each; count them once */ 541c8e26105Sjp151216 if (tries < 0) { 542c8e26105Sjp151216 for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) 543c8e26105Sjp151216 tries++; 544c8e26105Sjp151216 } 545c8e26105Sjp151216 546c5c4113dSnw141292 /* 547c8e26105Sjp151216 * Find a suitable ad_host_t (one associated with this ad_t, 548c8e26105Sjp151216 * preferably one that's already connected and not dead), 549c8e26105Sjp151216 * possibly round-robining through the ad_host_t list. 550c8e26105Sjp151216 * 551c8e26105Sjp151216 * If we can't find a non-dead ad_host_t and we've had one 552c8e26105Sjp151216 * before (ad->last_adh != NULL) then pick the next one or, if 553c8e26105Sjp151216 * there is no next one, the first one (i.e., round-robin). 554c8e26105Sjp151216 * 555c8e26105Sjp151216 * If we've never had one then (ad->last_adh == NULL) then pick 556c8e26105Sjp151216 * the first one. 557c8e26105Sjp151216 * 558c8e26105Sjp151216 * If we ever want to be more clever, such as preferring DSes 559c8e26105Sjp151216 * with better average response times, adjusting for weights 560c8e26105Sjp151216 * from SRV RRs, and so on, then this is the place to do it. 561c5c4113dSnw141292 */ 562c8e26105Sjp151216 563c8e26105Sjp151216 for (adh = host_head, first_adh = NULL, next_adh = NULL, seen_last = 0; 564c8e26105Sjp151216 adh != NULL; adh = adh->next) { 565c8e26105Sjp151216 if (adh->owner != ad) 566c8e26105Sjp151216 continue; 567c8e26105Sjp151216 if (first_adh == NULL) 568c8e26105Sjp151216 first_adh = adh; 569c8e26105Sjp151216 if (adh == ad->last_adh) 570c8e26105Sjp151216 seen_last++; 571c8e26105Sjp151216 else if (seen_last) 572c8e26105Sjp151216 next_adh = adh; 573c8e26105Sjp151216 574c8e26105Sjp151216 /* First time or current adh is live -> done */ 575c8e26105Sjp151216 if (ad->last_adh == NULL || (!adh->dead && adh->ld != NULL)) 576c5c4113dSnw141292 break; 577c5c4113dSnw141292 } 578c8e26105Sjp151216 579c8e26105Sjp151216 /* Round-robin */ 580c8e26105Sjp151216 if (adh == NULL) 581c8e26105Sjp151216 adh = (next_adh != NULL) ? next_adh : first_adh; 582c5c4113dSnw141292 583c5c4113dSnw141292 if (adh != NULL) 584c8e26105Sjp151216 ad->last_adh = adh; 585c5c4113dSnw141292 586c8e26105Sjp151216 out: 587c5c4113dSnw141292 (void) pthread_mutex_unlock(&adhostlock); 588c5c4113dSnw141292 589c8e26105Sjp151216 /* Found suitable DS, open it if not already opened */ 590c8e26105Sjp151216 if (idmap_open_conn(adh)) 591c5c4113dSnw141292 return (adh); 592c8e26105Sjp151216 593c8e26105Sjp151216 if (tries-- > 0) 594c8e26105Sjp151216 goto retry; 595c8e26105Sjp151216 596c8e26105Sjp151216 idmapdlog(LOG_ERR, "Couldn't open an LDAP connection to any global " 597c8e26105Sjp151216 "catalog server!"); 598c8e26105Sjp151216 599c8e26105Sjp151216 return (NULL); 600c5c4113dSnw141292 } 601c5c4113dSnw141292 602c5c4113dSnw141292 static 603c5c4113dSnw141292 void 604c5c4113dSnw141292 idmap_release_conn(ad_host_t *adh) 605c5c4113dSnw141292 { 606c5c4113dSnw141292 (void) pthread_mutex_lock(&adh->lock); 607c5c4113dSnw141292 if (atomic_dec_32_nv(&adh->ref) == 0) 608c5c4113dSnw141292 adh->idletime = time(NULL); 609c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 610c5c4113dSnw141292 } 611c5c4113dSnw141292 612c5c4113dSnw141292 /* 613c5c4113dSnw141292 * Take ad_host_config_t information, create a ad_host_t, 614c5c4113dSnw141292 * populate it and add it to the list of hosts. 615c5c4113dSnw141292 */ 616c5c4113dSnw141292 617c5c4113dSnw141292 int 618c5c4113dSnw141292 idmap_add_ds(ad_t *ad, const char *host, int port) 619c5c4113dSnw141292 { 620c5c4113dSnw141292 ad_host_t *p; 621c5c4113dSnw141292 ad_host_t *new = NULL; 622c5c4113dSnw141292 int ret = -1; 623c5c4113dSnw141292 624c5c4113dSnw141292 if (port == 0) 625c5c4113dSnw141292 port = (int)ad->partition; 626c5c4113dSnw141292 627c5c4113dSnw141292 (void) pthread_mutex_lock(&adhostlock); 628c5c4113dSnw141292 for (p = host_head; p != NULL; p = p->next) { 629c5c4113dSnw141292 if (p->owner != ad) 630c5c4113dSnw141292 continue; 631c5c4113dSnw141292 632c5c4113dSnw141292 if (strcmp(host, p->host) == 0 && p->port == port) { 633c5c4113dSnw141292 /* already added */ 634c8e26105Sjp151216 ret = 0; 635c5c4113dSnw141292 goto err; 636c5c4113dSnw141292 } 637c5c4113dSnw141292 } 638c5c4113dSnw141292 639c5c4113dSnw141292 /* add new entry */ 640c5c4113dSnw141292 new = (ad_host_t *)calloc(1, sizeof (ad_host_t)); 641c5c4113dSnw141292 if (new == NULL) 642c5c4113dSnw141292 goto err; 643c5c4113dSnw141292 new->owner = ad; 644c5c4113dSnw141292 new->port = port; 645c5c4113dSnw141292 new->dead = 0; 646c5c4113dSnw141292 if ((new->host = strdup(host)) == NULL) 647c5c4113dSnw141292 goto err; 648c5c4113dSnw141292 649c5c4113dSnw141292 /* default to SASL GSSAPI only for now */ 650c5c4113dSnw141292 new->saslflags = LDAP_SASL_INTERACTIVE; 651c5c4113dSnw141292 new->saslmech = "GSSAPI"; 652c5c4113dSnw141292 653c5c4113dSnw141292 if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) { 654c5c4113dSnw141292 free(new->host); 655c5c4113dSnw141292 new->host = NULL; 656c5c4113dSnw141292 errno = ret; 657c5c4113dSnw141292 ret = -1; 658c5c4113dSnw141292 goto err; 659c5c4113dSnw141292 } 660c5c4113dSnw141292 661c5c4113dSnw141292 /* link in */ 662c5c4113dSnw141292 new->next = host_head; 663c5c4113dSnw141292 host_head = new; 664c5c4113dSnw141292 665c5c4113dSnw141292 /* Start reaper if it doesn't exist */ 666c5c4113dSnw141292 if (reaperid == 0) 667c5c4113dSnw141292 (void) pthread_create(&reaperid, NULL, 668c5c4113dSnw141292 (void *(*)(void *))adreaper, (void *)NULL); 669c5c4113dSnw141292 670c5c4113dSnw141292 err: 671c5c4113dSnw141292 (void) pthread_mutex_unlock(&adhostlock); 672c5c4113dSnw141292 673c5c4113dSnw141292 if (ret != 0 && new != NULL) { 674c5c4113dSnw141292 if (new->host != NULL) { 675c5c4113dSnw141292 (void) pthread_mutex_destroy(&new->lock); 676c5c4113dSnw141292 free(new->host); 677c5c4113dSnw141292 } 678c5c4113dSnw141292 free(new); 679c5c4113dSnw141292 } 680c5c4113dSnw141292 681c5c4113dSnw141292 return (ret); 682c5c4113dSnw141292 } 683c5c4113dSnw141292 684c5c4113dSnw141292 /* 685c8e26105Sjp151216 * Free a DS configuration. 686c8e26105Sjp151216 * Caller must lock the adhostlock mutex 687c5c4113dSnw141292 */ 688c8e26105Sjp151216 static void 689c8e26105Sjp151216 delete_ds(ad_t *ad, const char *host, int port) 690c5c4113dSnw141292 { 691c5c4113dSnw141292 ad_host_t **p, *q; 692c5c4113dSnw141292 693c5c4113dSnw141292 for (p = &host_head; *p != NULL; p = &((*p)->next)) { 694c5c4113dSnw141292 if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 || 695c5c4113dSnw141292 (*p)->port != port) 696c5c4113dSnw141292 continue; 697c5c4113dSnw141292 /* found */ 698c8e26105Sjp151216 if ((*p)->ref > 0) 699c5c4113dSnw141292 break; /* still in use */ 700c5c4113dSnw141292 701c5c4113dSnw141292 q = *p; 702c5c4113dSnw141292 *p = (*p)->next; 703c5c4113dSnw141292 704c5c4113dSnw141292 (void) pthread_mutex_destroy(&q->lock); 705c5c4113dSnw141292 706c5c4113dSnw141292 if (q->ld) 707c5c4113dSnw141292 (void) ldap_unbind(q->ld); 708c5c4113dSnw141292 if (q->host) 709c5c4113dSnw141292 free(q->host); 710c5c4113dSnw141292 free(q); 711c5c4113dSnw141292 break; 712c5c4113dSnw141292 } 713c8e26105Sjp151216 714c5c4113dSnw141292 } 715c5c4113dSnw141292 716c8e26105Sjp151216 717c5c4113dSnw141292 /* 718c5c4113dSnw141292 * Convert a binary SID in a BerValue to a sid_t 719c5c4113dSnw141292 */ 720c5c4113dSnw141292 static 721c5c4113dSnw141292 int 722c5c4113dSnw141292 idmap_getsid(BerValue *bval, sid_t *sidp) 723c5c4113dSnw141292 { 724c5c4113dSnw141292 int i, j; 725c5c4113dSnw141292 uchar_t *v; 726c5c4113dSnw141292 uint32_t a; 727c5c4113dSnw141292 728c5c4113dSnw141292 /* 729c5c4113dSnw141292 * The binary format of a SID is as follows: 730c5c4113dSnw141292 * 731c5c4113dSnw141292 * byte #0: version, always 0x01 732c5c4113dSnw141292 * byte #1: RID count, always <= 0x0f 733c5c4113dSnw141292 * bytes #2-#7: SID authority, big-endian 48-bit unsigned int 734c5c4113dSnw141292 * 735c5c4113dSnw141292 * followed by RID count RIDs, each a little-endian, unsigned 736c5c4113dSnw141292 * 32-bit int. 737c5c4113dSnw141292 */ 738c5c4113dSnw141292 /* 739c5c4113dSnw141292 * Sanity checks: must have at least one RID, version must be 740c5c4113dSnw141292 * 0x01, and the length must be 8 + rid count * 4 741c5c4113dSnw141292 */ 742c5c4113dSnw141292 if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 && 743c5c4113dSnw141292 bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) { 744c5c4113dSnw141292 v = (uchar_t *)bval->bv_val; 745c5c4113dSnw141292 sidp->version = v[0]; 746c5c4113dSnw141292 sidp->sub_authority_count = v[1]; 747c5c4113dSnw141292 sidp->authority = 748c5c4113dSnw141292 /* big endian -- so start from the left */ 749c5c4113dSnw141292 ((u_longlong_t)v[2] << 40) | 750c5c4113dSnw141292 ((u_longlong_t)v[3] << 32) | 751c5c4113dSnw141292 ((u_longlong_t)v[4] << 24) | 752c5c4113dSnw141292 ((u_longlong_t)v[5] << 16) | 753c5c4113dSnw141292 ((u_longlong_t)v[6] << 8) | 754c5c4113dSnw141292 (u_longlong_t)v[7]; 755c5c4113dSnw141292 for (i = 0; i < sidp->sub_authority_count; i++) { 756c5c4113dSnw141292 j = 8 + (i * 4); 757c5c4113dSnw141292 /* little endian -- so start from the right */ 758c5c4113dSnw141292 a = (v[j + 3] << 24) | (v[j + 2] << 16) | 759c5c4113dSnw141292 (v[j + 1] << 8) | (v[j]); 760c5c4113dSnw141292 sidp->sub_authorities[i] = a; 761c5c4113dSnw141292 } 762c5c4113dSnw141292 return (0); 763c5c4113dSnw141292 } 764c5c4113dSnw141292 return (-1); 765c5c4113dSnw141292 } 766c5c4113dSnw141292 767c5c4113dSnw141292 /* 768c5c4113dSnw141292 * Convert a sid_t to S-1-... 769c5c4113dSnw141292 */ 770c5c4113dSnw141292 static 771c5c4113dSnw141292 char * 772c5c4113dSnw141292 idmap_sid2txt(sid_t *sidp) 773c5c4113dSnw141292 { 774c5c4113dSnw141292 int rlen, i, len; 775c5c4113dSnw141292 char *str, *cp; 776c5c4113dSnw141292 777c5c4113dSnw141292 if (sidp->version != 1) 778c5c4113dSnw141292 return (NULL); 779c5c4113dSnw141292 780c5c4113dSnw141292 len = sizeof ("S-1-") - 1; 781c5c4113dSnw141292 782c5c4113dSnw141292 /* 783c5c4113dSnw141292 * We could optimize like so, but, why? 784c5c4113dSnw141292 * if (sidp->authority < 10) 785c5c4113dSnw141292 * len += 2; 786c5c4113dSnw141292 * else if (sidp->authority < 100) 787c5c4113dSnw141292 * len += 3; 788c5c4113dSnw141292 * else 789c5c4113dSnw141292 * len += snprintf(NULL, 0"%llu", sidp->authority); 790c5c4113dSnw141292 */ 791c5c4113dSnw141292 len += snprintf(NULL, 0, "%llu", sidp->authority); 792c5c4113dSnw141292 793c5c4113dSnw141292 /* Max length of a uint32_t printed out in ASCII is 10 bytes */ 794c5c4113dSnw141292 len += 1 + (sidp->sub_authority_count + 1) * 10; 795c5c4113dSnw141292 796c5c4113dSnw141292 if ((cp = str = malloc(len)) == NULL) 797c5c4113dSnw141292 return (NULL); 798c5c4113dSnw141292 799c5c4113dSnw141292 rlen = snprintf(str, len, "S-1-%llu", sidp->authority); 800c5c4113dSnw141292 801c5c4113dSnw141292 cp += rlen; 802c5c4113dSnw141292 len -= rlen; 803c5c4113dSnw141292 804c5c4113dSnw141292 for (i = 0; i < sidp->sub_authority_count; i++) { 805c5c4113dSnw141292 assert(len > 0); 806c5c4113dSnw141292 rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]); 807c5c4113dSnw141292 cp += rlen; 808c5c4113dSnw141292 len -= rlen; 809c5c4113dSnw141292 assert(len >= 0); 810c5c4113dSnw141292 } 811c5c4113dSnw141292 812c5c4113dSnw141292 return (str); 813c5c4113dSnw141292 } 814c5c4113dSnw141292 815c5c4113dSnw141292 /* 816c5c4113dSnw141292 * Convert a sid_t to on-the-wire encoding 817c5c4113dSnw141292 */ 818c5c4113dSnw141292 static 819c5c4113dSnw141292 int 820c5c4113dSnw141292 idmap_sid2binsid(sid_t *sid, uchar_t *binsid, int binsidlen) 821c5c4113dSnw141292 { 822c5c4113dSnw141292 uchar_t *p; 823c5c4113dSnw141292 int i; 824c5c4113dSnw141292 uint64_t a; 825c5c4113dSnw141292 uint32_t r; 826c5c4113dSnw141292 827c5c4113dSnw141292 if (sid->version != 1 || 828c5c4113dSnw141292 binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4)) 829c5c4113dSnw141292 return (-1); 830c5c4113dSnw141292 831c5c4113dSnw141292 p = binsid; 832c5c4113dSnw141292 *p++ = 0x01; /* version */ 833c5c4113dSnw141292 /* sub authority count */ 834c5c4113dSnw141292 *p++ = sid->sub_authority_count; 835c5c4113dSnw141292 /* Authority */ 836c5c4113dSnw141292 a = sid->authority; 837c5c4113dSnw141292 /* big-endian -- start from left */ 838c5c4113dSnw141292 *p++ = (a >> 40) & 0xFF; 839c5c4113dSnw141292 *p++ = (a >> 32) & 0xFF; 840c5c4113dSnw141292 *p++ = (a >> 24) & 0xFF; 841c5c4113dSnw141292 *p++ = (a >> 16) & 0xFF; 842c5c4113dSnw141292 *p++ = (a >> 8) & 0xFF; 843c5c4113dSnw141292 *p++ = a & 0xFF; 844c5c4113dSnw141292 845c5c4113dSnw141292 /* sub-authorities */ 846c5c4113dSnw141292 for (i = 0; i < sid->sub_authority_count; i++) { 847c5c4113dSnw141292 r = sid->sub_authorities[i]; 848c5c4113dSnw141292 /* little-endian -- start from right */ 849c5c4113dSnw141292 *p++ = (r & 0x000000FF); 850c5c4113dSnw141292 *p++ = (r & 0x0000FF00) >> 8; 851c5c4113dSnw141292 *p++ = (r & 0x00FF0000) >> 16; 852c5c4113dSnw141292 *p++ = (r & 0xFF000000) >> 24; 853c5c4113dSnw141292 } 854c5c4113dSnw141292 855c5c4113dSnw141292 return (0); 856c5c4113dSnw141292 } 857c5c4113dSnw141292 858c5c4113dSnw141292 /* 859c5c4113dSnw141292 * Convert a stringified SID (S-1-...) into a hex-encoded version of the 860c5c4113dSnw141292 * on-the-wire encoding, but with each pair of hex digits pre-pended 861c5c4113dSnw141292 * with a '\', so we can pass this to libldap. 862c5c4113dSnw141292 */ 863c5c4113dSnw141292 static 864c5c4113dSnw141292 int 865c5c4113dSnw141292 idmap_txtsid2hexbinsid(const char *txt, const rid_t *rid, 866c5c4113dSnw141292 char *hexbinsid, int hexbinsidlen) 867c5c4113dSnw141292 { 868c5c4113dSnw141292 sid_t sid = { 0 }; 869c5c4113dSnw141292 int i, j; 870c5c4113dSnw141292 const char *cp; 871c5c4113dSnw141292 char *ecp; 872c5c4113dSnw141292 u_longlong_t a; 873c5c4113dSnw141292 unsigned long r; 874c5c4113dSnw141292 uchar_t *binsid, b, hb; 875c5c4113dSnw141292 876c5c4113dSnw141292 /* Only version 1 SIDs please */ 877c5c4113dSnw141292 if (strncmp(txt, "S-1-", strlen("S-1-")) != 0) 878c5c4113dSnw141292 return (-1); 879c5c4113dSnw141292 880c5c4113dSnw141292 if (strlen(txt) < (strlen("S-1-") + 1)) 881c5c4113dSnw141292 return (-1); 882c5c4113dSnw141292 883c5c4113dSnw141292 /* count '-'s */ 884c5c4113dSnw141292 for (j = 0, cp = strchr(txt, '-'); 885c5c4113dSnw141292 cp != NULL && *cp != '\0'; 886c5c4113dSnw141292 j++, cp = strchr(cp + 1, '-')) { 887c5c4113dSnw141292 /* can't end on a '-' */ 888c5c4113dSnw141292 if (*(cp + 1) == '\0') 889c5c4113dSnw141292 return (-1); 890c5c4113dSnw141292 } 891c5c4113dSnw141292 89262c60062Sbaban /* Adjust count for version and authority */ 89362c60062Sbaban j -= 2; 89462c60062Sbaban 89562c60062Sbaban /* we know the version number and RID count */ 89662c60062Sbaban sid.version = 1; 89762c60062Sbaban sid.sub_authority_count = (rid != NULL) ? j + 1 : j; 89862c60062Sbaban 899c5c4113dSnw141292 /* must have at least one RID, but not too many */ 90062c60062Sbaban if (sid.sub_authority_count < 1 || 90162c60062Sbaban sid.sub_authority_count > SID_MAX_SUB_AUTHORITIES) 902c5c4113dSnw141292 return (-1); 903c5c4113dSnw141292 904c5c4113dSnw141292 /* check that we only have digits and '-' */ 905c5c4113dSnw141292 if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1)) 906c5c4113dSnw141292 return (-1); 907c5c4113dSnw141292 908c5c4113dSnw141292 cp = txt + strlen("S-1-"); 909c5c4113dSnw141292 910c5c4113dSnw141292 /* 64-bit safe parsing of unsigned 48-bit authority value */ 911c5c4113dSnw141292 errno = 0; 912c5c4113dSnw141292 a = strtoull(cp, &ecp, 10); 913c5c4113dSnw141292 914c5c4113dSnw141292 /* errors parsing the authority or too many bits */ 915c5c4113dSnw141292 if (cp == ecp || (a == 0 && errno == EINVAL) || 916c5c4113dSnw141292 (a == ULLONG_MAX && errno == ERANGE) || 917c5c4113dSnw141292 (a & 0x0000ffffffffffffULL) != a) 918c5c4113dSnw141292 return (-1); 919c5c4113dSnw141292 920c5c4113dSnw141292 cp = ecp; 921c5c4113dSnw141292 922c5c4113dSnw141292 sid.authority = (uint64_t)a; 923c5c4113dSnw141292 92462c60062Sbaban for (i = 0; i < j; i++) { 925c5c4113dSnw141292 if (*cp++ != '-') 926c5c4113dSnw141292 return (-1); 927c5c4113dSnw141292 /* 64-bit safe parsing of unsigned 32-bit RID */ 928c5c4113dSnw141292 errno = 0; 929c5c4113dSnw141292 r = strtoul(cp, &ecp, 10); 930c5c4113dSnw141292 /* errors parsing the RID or too many bits */ 931c5c4113dSnw141292 if (cp == ecp || (r == 0 && errno == EINVAL) || 932c5c4113dSnw141292 (r == ULONG_MAX && errno == ERANGE) || 933c5c4113dSnw141292 (r & 0xffffffffUL) != r) 934c5c4113dSnw141292 return (-1); 935c5c4113dSnw141292 sid.sub_authorities[i] = (uint32_t)r; 936c5c4113dSnw141292 cp = ecp; 937c5c4113dSnw141292 } 938c5c4113dSnw141292 939c5c4113dSnw141292 /* check that all of the string SID has been consumed */ 940c5c4113dSnw141292 if (*cp != '\0') 941c5c4113dSnw141292 return (-1); 942c5c4113dSnw141292 94362c60062Sbaban if (rid != NULL) 94462c60062Sbaban sid.sub_authorities[j] = *rid; 945c5c4113dSnw141292 946c5c4113dSnw141292 j = 1 + 1 + 6 + sid.sub_authority_count * 4; 947c5c4113dSnw141292 948c5c4113dSnw141292 if (hexbinsidlen < (j * 3)) 949c5c4113dSnw141292 return (-2); 950c5c4113dSnw141292 951c5c4113dSnw141292 /* binary encode the SID */ 952c5c4113dSnw141292 binsid = (uchar_t *)alloca(j); 953c5c4113dSnw141292 (void) idmap_sid2binsid(&sid, binsid, j); 954c5c4113dSnw141292 955c5c4113dSnw141292 /* hex encode, with a backslash before each byte */ 956c5c4113dSnw141292 for (ecp = hexbinsid, i = 0; i < j; i++) { 957c5c4113dSnw141292 b = binsid[i]; 958c5c4113dSnw141292 *ecp++ = '\\'; 959c5c4113dSnw141292 hb = (b >> 4) & 0xF; 960c5c4113dSnw141292 *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 961c5c4113dSnw141292 hb = b & 0xF; 962c5c4113dSnw141292 *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 963c5c4113dSnw141292 } 964c5c4113dSnw141292 *ecp = '\0'; 965c5c4113dSnw141292 966c5c4113dSnw141292 return (0); 967c5c4113dSnw141292 } 968c5c4113dSnw141292 969c5c4113dSnw141292 static 970c5c4113dSnw141292 char * 971c5c4113dSnw141292 convert_bval2sid(BerValue *bval, rid_t *rid) 972c5c4113dSnw141292 { 973c5c4113dSnw141292 sid_t sid; 974c5c4113dSnw141292 975c5c4113dSnw141292 if (idmap_getsid(bval, &sid) < 0) 976c5c4113dSnw141292 return (NULL); 977c5c4113dSnw141292 978c5c4113dSnw141292 /* 979c5c4113dSnw141292 * If desired and if the SID is what should be a domain/computer 980c5c4113dSnw141292 * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then 981c5c4113dSnw141292 * save the last RID and truncate the SID 982c5c4113dSnw141292 */ 983c5c4113dSnw141292 if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5) 984c5c4113dSnw141292 *rid = sid.sub_authorities[--sid.sub_authority_count]; 985c5c4113dSnw141292 return (idmap_sid2txt(&sid)); 986c5c4113dSnw141292 } 987c5c4113dSnw141292 988c5c4113dSnw141292 989c5c4113dSnw141292 idmap_retcode 990c5c4113dSnw141292 idmap_lookup_batch_start(ad_t *ad, int nqueries, idmap_query_state_t **state) 991c5c4113dSnw141292 { 992c5c4113dSnw141292 idmap_query_state_t *new_state; 993c5c4113dSnw141292 ad_host_t *adh = NULL; 994c5c4113dSnw141292 995c5c4113dSnw141292 *state = NULL; 996c5c4113dSnw141292 997cd37da74Snw141292 /* Note: ad->dflt_w2k_dom cannot be NULL - see idmap_ad_alloc() */ 998cd37da74Snw141292 if (ad == NULL || *ad->dflt_w2k_dom == '\0') 999*e8c27ec8Sbaban return (IDMAP_ERR_INTERNAL); 1000c5c4113dSnw141292 1001c5c4113dSnw141292 adh = idmap_get_conn(ad); 1002c5c4113dSnw141292 if (adh == NULL) 1003c5c4113dSnw141292 return (IDMAP_ERR_OTHER); 1004c5c4113dSnw141292 1005c5c4113dSnw141292 new_state = calloc(1, sizeof (idmap_query_state_t) + 1006c5c4113dSnw141292 (nqueries - 1) * sizeof (idmap_q_t)); 1007c5c4113dSnw141292 1008c5c4113dSnw141292 if (new_state == NULL) 1009c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 1010c5c4113dSnw141292 101184decf41Sjp151216 new_state->ref_cnt = 1; 1012c5c4113dSnw141292 new_state->qadh = adh; 1013c5c4113dSnw141292 new_state->qcount = nqueries; 1014c5c4113dSnw141292 new_state->qadh_gen = adh->generation; 1015c5c4113dSnw141292 /* should be -1, but the atomic routines want unsigned */ 1016c5c4113dSnw141292 new_state->qlastsent = 0; 101784decf41Sjp151216 (void) pthread_cond_init(&new_state->cv, NULL); 1018c5c4113dSnw141292 1019c5c4113dSnw141292 (void) pthread_mutex_lock(&qstatelock); 1020c5c4113dSnw141292 new_state->next = qstatehead; 1021c5c4113dSnw141292 qstatehead = new_state; 1022c5c4113dSnw141292 (void) pthread_mutex_unlock(&qstatelock); 1023c5c4113dSnw141292 1024c5c4113dSnw141292 *state = new_state; 1025c5c4113dSnw141292 1026c5c4113dSnw141292 return (IDMAP_SUCCESS); 1027c5c4113dSnw141292 } 1028c5c4113dSnw141292 1029c5c4113dSnw141292 /* 1030*e8c27ec8Sbaban * Set unixuser_attr and unixgroup_attr for AD-based name mapping 1031*e8c27ec8Sbaban */ 1032*e8c27ec8Sbaban void 1033*e8c27ec8Sbaban idmap_lookup_batch_set_unixattr(idmap_query_state_t *state, 1034*e8c27ec8Sbaban const char *unixuser_attr, const char *unixgroup_attr) { 1035*e8c27ec8Sbaban state->ad_unixuser_attr = unixuser_attr; 1036*e8c27ec8Sbaban state->ad_unixgroup_attr = unixgroup_attr; 1037*e8c27ec8Sbaban } 1038*e8c27ec8Sbaban 1039*e8c27ec8Sbaban /* 1040c5c4113dSnw141292 * Find the idmap_query_state_t to which a given LDAP result msgid on a 104184decf41Sjp151216 * given connection belongs. This routine increaments the reference count 104284decf41Sjp151216 * so that the object can not be freed. idmap_lookup_unlock_batch() 104384decf41Sjp151216 * must be called to decreament the reference count. 1044c5c4113dSnw141292 */ 1045c5c4113dSnw141292 static 1046c5c4113dSnw141292 int 1047c5c4113dSnw141292 idmap_msgid2query(ad_host_t *adh, int msgid, 1048c5c4113dSnw141292 idmap_query_state_t **state, int *qid) 1049c5c4113dSnw141292 { 1050c5c4113dSnw141292 idmap_query_state_t *p; 1051c5c4113dSnw141292 int i; 1052c5c4113dSnw141292 1053c5c4113dSnw141292 (void) pthread_mutex_lock(&qstatelock); 1054c5c4113dSnw141292 for (p = qstatehead; p != NULL; p = p->next) { 1055c5c4113dSnw141292 if (p->qadh != adh || adh->generation != p->qadh_gen) 1056c5c4113dSnw141292 continue; 1057c5c4113dSnw141292 for (i = 0; i < p->qcount; i++) { 1058c5c4113dSnw141292 if ((p->queries[i]).msgid == msgid) { 105984decf41Sjp151216 p->ref_cnt++; 1060c5c4113dSnw141292 *state = p; 1061c5c4113dSnw141292 *qid = i; 1062c5c4113dSnw141292 (void) pthread_mutex_unlock(&qstatelock); 1063c5c4113dSnw141292 return (1); 1064c5c4113dSnw141292 } 1065c5c4113dSnw141292 } 1066c5c4113dSnw141292 } 1067c5c4113dSnw141292 (void) pthread_mutex_unlock(&qstatelock); 1068c5c4113dSnw141292 return (0); 1069c5c4113dSnw141292 } 1070c5c4113dSnw141292 1071c5c4113dSnw141292 /* 1072cd37da74Snw141292 * Take parsed attribute values from a search result entry and check if 1073cd37da74Snw141292 * it is the result that was desired and, if so, set the result fields 1074cd37da74Snw141292 * of the given idmap_q_t. 1075cd37da74Snw141292 * 1076*e8c27ec8Sbaban * Frees the unused char * values. 1077c5c4113dSnw141292 */ 1078c5c4113dSnw141292 static 1079cd37da74Snw141292 void 1080cd37da74Snw141292 idmap_setqresults(idmap_q_t *q, char *san, char *dn, char *sid, 1081*e8c27ec8Sbaban rid_t rid, int sid_type, char *unixname) 1082c5c4113dSnw141292 { 1083cd37da74Snw141292 char *domain; 1084*e8c27ec8Sbaban int err1, err2; 1085cd37da74Snw141292 1086cd37da74Snw141292 assert(dn != NULL); 1087cd37da74Snw141292 1088cd37da74Snw141292 if ((domain = dn2dns(dn)) == NULL) 1089cd37da74Snw141292 goto out; 1090cd37da74Snw141292 1091*e8c27ec8Sbaban if (q->ecanonname != NULL && san != NULL) { 1092*e8c27ec8Sbaban /* Check that this is the canonname that we were looking for */ 1093cd37da74Snw141292 if (u8_strcmp(q->ecanonname, san, 0, 1094cd37da74Snw141292 U8_STRCMP_CI_LOWER, /* no normalization, for now */ 1095*e8c27ec8Sbaban U8_UNICODE_LATEST, &err1) != 0 || err1 != 0) 1096*e8c27ec8Sbaban goto out; 1097*e8c27ec8Sbaban } 1098*e8c27ec8Sbaban 1099*e8c27ec8Sbaban if (q->edomain != NULL) { 1100*e8c27ec8Sbaban /* Check that this is the domain that we were looking for */ 1101*e8c27ec8Sbaban if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER, 1102cd37da74Snw141292 U8_UNICODE_LATEST, &err2) != 0 || err2 != 0) 1103cd37da74Snw141292 goto out; 1104*e8c27ec8Sbaban } 1105cd37da74Snw141292 1106*e8c27ec8Sbaban /* Set results */ 1107*e8c27ec8Sbaban if (q->sid) { 1108*e8c27ec8Sbaban *q->sid = sid; 1109cd37da74Snw141292 sid = NULL; 1110*e8c27ec8Sbaban } 1111*e8c27ec8Sbaban if (q->rid) 1112*e8c27ec8Sbaban *q->rid = rid; 1113*e8c27ec8Sbaban if (q->sid_type) 1114cd37da74Snw141292 *q->sid_type = sid_type; 1115*e8c27ec8Sbaban if (q->unixname) { 1116*e8c27ec8Sbaban *q->unixname = unixname; 1117*e8c27ec8Sbaban unixname = NULL; 1118*e8c27ec8Sbaban } 1119cd37da74Snw141292 if (q->domain != NULL) { 1120cd37da74Snw141292 *q->domain = domain; 1121cd37da74Snw141292 domain = NULL; 1122*e8c27ec8Sbaban } 1123*e8c27ec8Sbaban if (q->canonname != NULL) { 1124*e8c27ec8Sbaban *q->canonname = san; 1125cd37da74Snw141292 san = NULL; 1126cd37da74Snw141292 } 1127cd37da74Snw141292 1128*e8c27ec8Sbaban /* Always have q->rc; idmap_extract_object() asserts this */ 1129cd37da74Snw141292 *q->rc = IDMAP_SUCCESS; 1130cd37da74Snw141292 1131cd37da74Snw141292 out: 1132cd37da74Snw141292 /* Free unused attribute values */ 1133cd37da74Snw141292 free(san); 1134cd37da74Snw141292 free(sid); 1135cd37da74Snw141292 free(domain); 1136*e8c27ec8Sbaban free(unixname); 1137c5c4113dSnw141292 } 1138c5c4113dSnw141292 1139c5c4113dSnw141292 /* 1140cd37da74Snw141292 * The following three functions extract objectSid, sAMAccountName and 1141cd37da74Snw141292 * objectClass attribute values and, in the case of objectSid and 1142cd37da74Snw141292 * objectClass, parse them. 1143cd37da74Snw141292 * 1144cd37da74Snw141292 * idmap_setqresults() takes care of dealing with the result entry's DN. 1145cd37da74Snw141292 */ 1146cd37da74Snw141292 1147cd37da74Snw141292 /* 1148cd37da74Snw141292 * Return a NUL-terminated stringified SID from the value of an 1149cd37da74Snw141292 * objectSid attribute and put the last RID in *rid. 1150c5c4113dSnw141292 */ 1151c5c4113dSnw141292 static 1152cd37da74Snw141292 char * 1153cd37da74Snw141292 idmap_bv_objsid2sidstr(BerValue **bvalues, rid_t *rid) 1154c5c4113dSnw141292 { 1155cd37da74Snw141292 char *sid; 1156cd37da74Snw141292 1157cd37da74Snw141292 if (bvalues == NULL) 1158cd37da74Snw141292 return (NULL); 1159cd37da74Snw141292 /* objectSid is single valued */ 1160cd37da74Snw141292 if ((sid = convert_bval2sid(bvalues[0], rid)) == NULL) 1161cd37da74Snw141292 return (NULL); 1162cd37da74Snw141292 return (sid); 1163cd37da74Snw141292 } 1164cd37da74Snw141292 1165cd37da74Snw141292 /* 1166cd37da74Snw141292 * Return a NUL-terminated string from the value of a sAMAccountName 1167*e8c27ec8Sbaban * or unixname attribute. 1168cd37da74Snw141292 */ 1169cd37da74Snw141292 static 1170cd37da74Snw141292 char * 1171*e8c27ec8Sbaban idmap_bv_name2str(BerValue **bvalues) 1172cd37da74Snw141292 { 1173cd37da74Snw141292 char *s; 1174c5c4113dSnw141292 1175c5c4113dSnw141292 if (bvalues == NULL || bvalues[0] == NULL || 1176c5c4113dSnw141292 bvalues[0]->bv_val == NULL) 1177cd37da74Snw141292 return (NULL); 1178e3c2d6aaSnw141292 1179cd37da74Snw141292 if ((s = malloc(bvalues[0]->bv_len + 1)) == NULL) 1180cd37da74Snw141292 return (NULL); 1181e3c2d6aaSnw141292 1182cd37da74Snw141292 (void) snprintf(s, bvalues[0]->bv_len + 1, "%.*s", bvalues[0]->bv_len, 1183cd37da74Snw141292 bvalues[0]->bv_val); 1184e3c2d6aaSnw141292 1185cd37da74Snw141292 return (s); 1186c5c4113dSnw141292 } 1187c5c4113dSnw141292 1188c5c4113dSnw141292 1189c5c4113dSnw141292 #define BVAL_CASEEQ(bv, str) \ 1190c5c4113dSnw141292 (((*(bv))->bv_len == (sizeof (str) - 1)) && \ 1191c5c4113dSnw141292 strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0) 1192c5c4113dSnw141292 1193c5c4113dSnw141292 /* 1194cd37da74Snw141292 * Extract the class of the result entry. Returns 1 on success, 0 on 1195cd37da74Snw141292 * failure. 1196c5c4113dSnw141292 */ 1197c5c4113dSnw141292 static 1198e3c2d6aaSnw141292 int 1199cd37da74Snw141292 idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type) 1200c5c4113dSnw141292 { 1201c5c4113dSnw141292 BerValue **cbval; 1202c5c4113dSnw141292 1203cd37da74Snw141292 *sid_type = _IDMAP_T_OTHER; 1204c5c4113dSnw141292 if (bvalues == NULL) 1205e3c2d6aaSnw141292 return (0); 1206c5c4113dSnw141292 1207cd37da74Snw141292 /* 1208cd37da74Snw141292 * We iterate over all the values because computer is a 1209cd37da74Snw141292 * sub-class of user. 1210cd37da74Snw141292 */ 1211c5c4113dSnw141292 for (cbval = bvalues; *cbval != NULL; cbval++) { 1212c5c4113dSnw141292 if (BVAL_CASEEQ(cbval, "Computer")) { 1213cd37da74Snw141292 *sid_type = _IDMAP_T_COMPUTER; 1214cd37da74Snw141292 break; 1215c5c4113dSnw141292 } else if (BVAL_CASEEQ(cbval, "Group")) { 1216cd37da74Snw141292 *sid_type = _IDMAP_T_GROUP; 1217cd37da74Snw141292 break; 1218c5c4113dSnw141292 } else if (BVAL_CASEEQ(cbval, "USER")) { 1219cd37da74Snw141292 *sid_type = _IDMAP_T_USER; 1220cd37da74Snw141292 /* Continue looping -- this may be a computer yet */ 1221cd37da74Snw141292 } 1222cd37da74Snw141292 /* 1223cd37da74Snw141292 * "else if (*sid_type = _IDMAP_T_USER)" then this is a 1224cd37da74Snw141292 * new sub-class of user -- what to do with it?? 1225cd37da74Snw141292 */ 1226c5c4113dSnw141292 } 1227e3c2d6aaSnw141292 1228e3c2d6aaSnw141292 return (1); 1229c5c4113dSnw141292 } 1230c5c4113dSnw141292 1231c5c4113dSnw141292 /* 1232c5c4113dSnw141292 * Handle a given search result entry 1233c5c4113dSnw141292 */ 1234c5c4113dSnw141292 static 1235c5c4113dSnw141292 void 1236c5c4113dSnw141292 idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res) 1237c5c4113dSnw141292 { 1238c5c4113dSnw141292 BerElement *ber = NULL; 1239c5c4113dSnw141292 BerValue **bvalues; 1240c5c4113dSnw141292 ad_host_t *adh; 1241c5c4113dSnw141292 idmap_q_t *q; 1242cd37da74Snw141292 char *attr; 1243*e8c27ec8Sbaban const char *unixuser_attr = NULL; 1244*e8c27ec8Sbaban const char *unixgroup_attr = NULL; 1245*e8c27ec8Sbaban char *unixuser = NULL; 1246*e8c27ec8Sbaban char *unixgroup = NULL; 1247cd37da74Snw141292 char *dn = NULL; 1248cd37da74Snw141292 char *san = NULL; 1249cd37da74Snw141292 char *sid = NULL; 1250cd37da74Snw141292 rid_t rid = 0; 1251*e8c27ec8Sbaban int sid_type = _IDMAP_T_UNDEF; 1252e3c2d6aaSnw141292 int has_class, has_san, has_sid; 1253*e8c27ec8Sbaban int has_unixuser, has_unixgroup; 1254c5c4113dSnw141292 1255c5c4113dSnw141292 adh = state->qadh; 1256c5c4113dSnw141292 1257c5c4113dSnw141292 (void) pthread_mutex_lock(&adh->lock); 1258c5c4113dSnw141292 1259e3c2d6aaSnw141292 q = &(state->queries[qid]); 1260e3c2d6aaSnw141292 1261*e8c27ec8Sbaban assert(q->rc != NULL); 1262*e8c27ec8Sbaban 1263e3c2d6aaSnw141292 if (*q->rc == IDMAP_SUCCESS || adh->dead || 1264e3c2d6aaSnw141292 (dn = ldap_get_dn(adh->ld, res)) == NULL) { 1265c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 1266c5c4113dSnw141292 return; 1267c5c4113dSnw141292 } 1268c5c4113dSnw141292 1269e3c2d6aaSnw141292 assert(q->domain == NULL || *q->domain == NULL); 1270c5c4113dSnw141292 1271*e8c27ec8Sbaban /* 1272*e8c27ec8Sbaban * If the caller has requested unixname then determine the 1273*e8c27ec8Sbaban * AD attribute name that will have the unixname. 1274*e8c27ec8Sbaban */ 1275*e8c27ec8Sbaban if (q->unixname != NULL) { 1276*e8c27ec8Sbaban if (q->eunixtype == _IDMAP_T_USER) 1277*e8c27ec8Sbaban unixuser_attr = state->ad_unixuser_attr; 1278*e8c27ec8Sbaban else if (q->eunixtype == _IDMAP_T_GROUP) 1279*e8c27ec8Sbaban unixgroup_attr = state->ad_unixgroup_attr; 1280*e8c27ec8Sbaban else if (q->eunixtype == _IDMAP_T_UNDEF) { 1281*e8c27ec8Sbaban /* 1282*e8c27ec8Sbaban * This is the case where we don't know 1283*e8c27ec8Sbaban * before hand whether we need unixuser 1284*e8c27ec8Sbaban * or unixgroup. This will be determined 1285*e8c27ec8Sbaban * by the "sid_type" (i.e whether the given 1286*e8c27ec8Sbaban * winname is user or group). If sid_type 1287*e8c27ec8Sbaban * turns out to be user we will return 1288*e8c27ec8Sbaban * unixuser (if found) and if it is a group 1289*e8c27ec8Sbaban * we will return unixgroup (if found). We 1290*e8c27ec8Sbaban * lookup for both ad_unixuser_attr and 1291*e8c27ec8Sbaban * ad_unixgroup_attr and discard one of them 1292*e8c27ec8Sbaban * after we know the "sidtype". This 1293*e8c27ec8Sbaban * supports the following type of lookups. 1294*e8c27ec8Sbaban * 1295*e8c27ec8Sbaban * Example: 1296*e8c27ec8Sbaban * $idmap show -c winname:foo 1297*e8c27ec8Sbaban * In the above example, idmap will 1298*e8c27ec8Sbaban * return uid if winname is winuser 1299*e8c27ec8Sbaban * and gid if winname is wingroup. 1300*e8c27ec8Sbaban */ 1301*e8c27ec8Sbaban unixuser_attr = state->ad_unixuser_attr; 1302*e8c27ec8Sbaban unixgroup_attr = state->ad_unixgroup_attr; 1303*e8c27ec8Sbaban } 1304*e8c27ec8Sbaban } 1305*e8c27ec8Sbaban 1306*e8c27ec8Sbaban has_class = has_san = has_sid = has_unixuser = has_unixgroup = 0; 1307c5c4113dSnw141292 for (attr = ldap_first_attribute(adh->ld, res, &ber); attr != NULL; 1308c5c4113dSnw141292 attr = ldap_next_attribute(adh->ld, res, ber)) { 1309c5c4113dSnw141292 bvalues = NULL; /* for memory management below */ 1310c5c4113dSnw141292 1311c5c4113dSnw141292 /* 1312c5c4113dSnw141292 * If this is an attribute we are looking for and 1313c5c4113dSnw141292 * haven't seen it yet, parse it 1314c5c4113dSnw141292 */ 1315*e8c27ec8Sbaban if (q->sid != NULL && !has_sid && 1316e3c2d6aaSnw141292 strcasecmp(attr, OBJSID) == 0) { 1317c5c4113dSnw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 1318cd37da74Snw141292 sid = idmap_bv_objsid2sidstr(bvalues, &rid); 1319cd37da74Snw141292 has_sid = (sid != NULL); 1320e3c2d6aaSnw141292 } else if (!has_san && strcasecmp(attr, SAN) == 0) { 1321c5c4113dSnw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 1322*e8c27ec8Sbaban san = idmap_bv_name2str(bvalues); 1323cd37da74Snw141292 has_san = (san != NULL); 1324e3c2d6aaSnw141292 } else if (!has_class && strcasecmp(attr, OBJCLASS) == 0) { 1325c5c4113dSnw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 1326cd37da74Snw141292 has_class = idmap_bv_objclass2sidtype(bvalues, 1327cd37da74Snw141292 &sid_type); 1328*e8c27ec8Sbaban if (has_class && q->unixname != NULL && 1329*e8c27ec8Sbaban q->eunixtype == _IDMAP_T_UNDEF) { 1330*e8c27ec8Sbaban /* 1331*e8c27ec8Sbaban * This is the case where we didn't 1332*e8c27ec8Sbaban * know whether we wanted unixuser or 1333*e8c27ec8Sbaban * unixgroup as described above. 1334*e8c27ec8Sbaban * Now since we know the "sid_type" 1335*e8c27ec8Sbaban * we discard the unwanted value 1336*e8c27ec8Sbaban * if it was retrieved before we 1337*e8c27ec8Sbaban * got here. 1338*e8c27ec8Sbaban */ 1339*e8c27ec8Sbaban if (sid_type == _IDMAP_T_USER) { 1340*e8c27ec8Sbaban free(unixgroup); 1341*e8c27ec8Sbaban unixgroup_attr = unixgroup = NULL; 1342*e8c27ec8Sbaban } else if (sid_type == _IDMAP_T_GROUP) { 1343*e8c27ec8Sbaban free(unixuser); 1344*e8c27ec8Sbaban unixuser_attr = unixuser = NULL; 1345*e8c27ec8Sbaban } else { 1346*e8c27ec8Sbaban free(unixuser); 1347*e8c27ec8Sbaban free(unixgroup); 1348*e8c27ec8Sbaban unixuser_attr = unixuser = NULL; 1349*e8c27ec8Sbaban unixgroup_attr = unixgroup = NULL; 1350*e8c27ec8Sbaban } 1351*e8c27ec8Sbaban } 1352*e8c27ec8Sbaban } else if (!has_unixuser && unixuser_attr != NULL && 1353*e8c27ec8Sbaban strcasecmp(attr, unixuser_attr) == 0) { 1354*e8c27ec8Sbaban bvalues = ldap_get_values_len(adh->ld, res, attr); 1355*e8c27ec8Sbaban unixuser = idmap_bv_name2str(bvalues); 1356*e8c27ec8Sbaban has_unixuser = (unixuser != NULL); 1357*e8c27ec8Sbaban } else if (!has_unixgroup && unixgroup_attr != NULL && 1358*e8c27ec8Sbaban strcasecmp(attr, unixgroup_attr) == 0) { 1359*e8c27ec8Sbaban bvalues = ldap_get_values_len(adh->ld, res, attr); 1360*e8c27ec8Sbaban unixgroup = idmap_bv_name2str(bvalues); 1361*e8c27ec8Sbaban has_unixgroup = (unixgroup != NULL); 1362c5c4113dSnw141292 } 1363c5c4113dSnw141292 1364c5c4113dSnw141292 if (bvalues != NULL) 1365c5c4113dSnw141292 ldap_value_free_len(bvalues); 1366c5c4113dSnw141292 ldap_memfree(attr); 1367c5c4113dSnw141292 1368cd37da74Snw141292 if (has_class && has_san && 1369*e8c27ec8Sbaban (q->sid == NULL || has_sid) && 1370*e8c27ec8Sbaban (unixuser_attr == NULL || has_unixuser) && 1371*e8c27ec8Sbaban (unixgroup_attr == NULL || has_unixgroup)) { 1372*e8c27ec8Sbaban /* Got what we need */ 1373e3c2d6aaSnw141292 break; 1374c5c4113dSnw141292 } 1375e3c2d6aaSnw141292 } 1376e3c2d6aaSnw141292 1377*e8c27ec8Sbaban if (!has_class) { 1378*e8c27ec8Sbaban /* 1379*e8c27ec8Sbaban * Didn't find objectclass. Something's wrong with our 1380*e8c27ec8Sbaban * AD data. 1381*e8c27ec8Sbaban */ 1382*e8c27ec8Sbaban free(san); 1383*e8c27ec8Sbaban free(sid); 1384*e8c27ec8Sbaban free(unixuser); 1385*e8c27ec8Sbaban free(unixgroup); 1386*e8c27ec8Sbaban } else { 1387*e8c27ec8Sbaban /* 1388*e8c27ec8Sbaban * Either we got what we needed and came out of the loop 1389*e8c27ec8Sbaban * early OR we completed the loop in which case we didn't 1390*e8c27ec8Sbaban * find some attributes that we were looking for. In either 1391*e8c27ec8Sbaban * case set the result with what we got. 1392*e8c27ec8Sbaban */ 1393*e8c27ec8Sbaban idmap_setqresults(q, san, dn, sid, rid, sid_type, 1394*e8c27ec8Sbaban (unixuser != NULL) ? unixuser : unixgroup); 1395*e8c27ec8Sbaban } 1396*e8c27ec8Sbaban 1397e3c2d6aaSnw141292 (void) pthread_mutex_unlock(&adh->lock); 1398c5c4113dSnw141292 1399c5c4113dSnw141292 if (ber != NULL) 1400c5c4113dSnw141292 ber_free(ber, 0); 1401c5c4113dSnw141292 1402c5c4113dSnw141292 ldap_memfree(dn); 1403c5c4113dSnw141292 } 1404c5c4113dSnw141292 1405c5c4113dSnw141292 /* 1406c5c4113dSnw141292 * Try to get a result; if there is one, find the corresponding 1407c5c4113dSnw141292 * idmap_q_t and process the result. 1408c5c4113dSnw141292 */ 1409c5c4113dSnw141292 static 1410c5c4113dSnw141292 int 1411c5c4113dSnw141292 idmap_get_adobject_batch(ad_host_t *adh, struct timeval *timeout) 1412c5c4113dSnw141292 { 1413c5c4113dSnw141292 idmap_query_state_t *query_state; 1414c5c4113dSnw141292 LDAPMessage *res = NULL; 1415c5c4113dSnw141292 int rc, ret, msgid, qid; 1416c5c4113dSnw141292 1417c5c4113dSnw141292 (void) pthread_mutex_lock(&adh->lock); 1418c5c4113dSnw141292 if (adh->dead) { 1419c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 1420c5c4113dSnw141292 return (-1); 1421c5c4113dSnw141292 } 1422c5c4113dSnw141292 1423c5c4113dSnw141292 /* Get one result */ 1424c5c4113dSnw141292 rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, 1425c5c4113dSnw141292 timeout, &res); 1426c5c4113dSnw141292 if (rc == LDAP_UNAVAILABLE || rc == LDAP_UNWILLING_TO_PERFORM || 1427c5c4113dSnw141292 rc == LDAP_CONNECT_ERROR || rc == LDAP_SERVER_DOWN || 1428c5c4113dSnw141292 rc == LDAP_BUSY) 1429c5c4113dSnw141292 adh->dead = 1; 1430c5c4113dSnw141292 (void) pthread_mutex_unlock(&adh->lock); 1431c5c4113dSnw141292 1432c5c4113dSnw141292 if (adh->dead) 1433c5c4113dSnw141292 return (-1); 1434c5c4113dSnw141292 1435c5c4113dSnw141292 switch (rc) { 1436c5c4113dSnw141292 case LDAP_RES_SEARCH_RESULT: 1437c5c4113dSnw141292 /* We have all the LDAP replies for some search... */ 1438c5c4113dSnw141292 msgid = ldap_msgid(res); 1439c5c4113dSnw141292 if (idmap_msgid2query(adh, msgid, 1440c5c4113dSnw141292 &query_state, &qid)) { 1441c5c4113dSnw141292 /* ...so we can decrement qinflight */ 1442c5c4113dSnw141292 atomic_dec_32(&query_state->qinflight); 1443e3c2d6aaSnw141292 /* We've seen all the result entries we'll see */ 1444e3c2d6aaSnw141292 if (*query_state->queries[qid].rc != IDMAP_SUCCESS) 1445e3c2d6aaSnw141292 *query_state->queries[qid].rc = 1446e3c2d6aaSnw141292 IDMAP_ERR_NOTFOUND; 144784decf41Sjp151216 idmap_lookup_unlock_batch(&query_state); 1448c5c4113dSnw141292 } 1449c5c4113dSnw141292 (void) ldap_msgfree(res); 1450c5c4113dSnw141292 ret = 0; 1451c5c4113dSnw141292 break; 1452c5c4113dSnw141292 case LDAP_RES_SEARCH_REFERENCE: 1453c5c4113dSnw141292 /* 1454c5c4113dSnw141292 * We have no need for these at the moment. Eventually, 1455c5c4113dSnw141292 * when we query things that we can't expect to find in 1456c5c4113dSnw141292 * the Global Catalog then we'll need to learn to follow 1457c5c4113dSnw141292 * references. 1458c5c4113dSnw141292 */ 1459c5c4113dSnw141292 (void) ldap_msgfree(res); 1460c5c4113dSnw141292 ret = 0; 1461c5c4113dSnw141292 break; 1462c5c4113dSnw141292 case LDAP_RES_SEARCH_ENTRY: 1463c5c4113dSnw141292 /* Got a result */ 1464c5c4113dSnw141292 msgid = ldap_msgid(res); 1465c5c4113dSnw141292 if (idmap_msgid2query(adh, msgid, 1466c5c4113dSnw141292 &query_state, &qid)) { 1467c5c4113dSnw141292 idmap_extract_object(query_state, qid, res); 1468c5c4113dSnw141292 /* we saw at least one result */ 146984decf41Sjp151216 idmap_lookup_unlock_batch(&query_state); 1470c5c4113dSnw141292 } 1471c5c4113dSnw141292 (void) ldap_msgfree(res); 1472c5c4113dSnw141292 ret = 0; 1473c5c4113dSnw141292 break; 1474c5c4113dSnw141292 default: 1475c5c4113dSnw141292 /* timeout or error; treat the same */ 1476c5c4113dSnw141292 ret = -1; 1477c5c4113dSnw141292 break; 1478c5c4113dSnw141292 } 1479c5c4113dSnw141292 1480c5c4113dSnw141292 return (ret); 1481c5c4113dSnw141292 } 1482c5c4113dSnw141292 148384decf41Sjp151216 /* 148484decf41Sjp151216 * This routine decreament the reference count of the 148584decf41Sjp151216 * idmap_query_state_t 148684decf41Sjp151216 */ 148784decf41Sjp151216 static void 148884decf41Sjp151216 idmap_lookup_unlock_batch(idmap_query_state_t **state) 148984decf41Sjp151216 { 149084decf41Sjp151216 /* 149184decf41Sjp151216 * Decrement reference count with qstatelock locked 149284decf41Sjp151216 */ 149384decf41Sjp151216 (void) pthread_mutex_lock(&qstatelock); 149484decf41Sjp151216 (*state)->ref_cnt--; 149584decf41Sjp151216 /* 149684decf41Sjp151216 * If there are no references wakup the allocating thread 149784decf41Sjp151216 */ 149884decf41Sjp151216 if ((*state)->ref_cnt == 0) 149984decf41Sjp151216 (void) pthread_cond_signal(&(*state)->cv); 150084decf41Sjp151216 (void) pthread_mutex_unlock(&qstatelock); 150184decf41Sjp151216 *state = NULL; 150284decf41Sjp151216 } 150384decf41Sjp151216 1504e3c2d6aaSnw141292 static 1505e3c2d6aaSnw141292 void 1506e3c2d6aaSnw141292 idmap_cleanup_batch(idmap_query_state_t *batch) 1507e3c2d6aaSnw141292 { 1508e3c2d6aaSnw141292 int i; 1509e3c2d6aaSnw141292 1510e3c2d6aaSnw141292 for (i = 0; i < batch->qcount; i++) { 1511cd37da74Snw141292 if (batch->queries[i].ecanonname != NULL) 1512cd37da74Snw141292 free(batch->queries[i].ecanonname); 1513cd37da74Snw141292 batch->queries[i].ecanonname = NULL; 1514cd37da74Snw141292 if (batch->queries[i].edomain != NULL) 1515cd37da74Snw141292 free(batch->queries[i].edomain); 1516cd37da74Snw141292 batch->queries[i].edomain = NULL; 1517e3c2d6aaSnw141292 } 1518e3c2d6aaSnw141292 } 1519e3c2d6aaSnw141292 152084decf41Sjp151216 /* 152184decf41Sjp151216 * This routine frees the idmap_query_state_t structure 152284decf41Sjp151216 * If the reference count is greater than 1 it waits 152384decf41Sjp151216 * for the other threads to finish using it. 152484decf41Sjp151216 */ 1525c5c4113dSnw141292 void 152684decf41Sjp151216 idmap_lookup_release_batch(idmap_query_state_t **state) 1527c5c4113dSnw141292 { 1528c5c4113dSnw141292 idmap_query_state_t **p; 1529c5c4113dSnw141292 153084decf41Sjp151216 /* 153184decf41Sjp151216 * Decrement reference count with qstatelock locked 153284decf41Sjp151216 * and wait for reference count to get to zero 153384decf41Sjp151216 */ 153484decf41Sjp151216 (void) pthread_mutex_lock(&qstatelock); 153584decf41Sjp151216 (*state)->ref_cnt--; 153684decf41Sjp151216 while ((*state)->ref_cnt > 0) { 153784decf41Sjp151216 (void) pthread_cond_wait(&(*state)->cv, &qstatelock); 153884decf41Sjp151216 } 1539c5c4113dSnw141292 1540c5c4113dSnw141292 /* Remove this state struct from the list of state structs */ 1541c5c4113dSnw141292 for (p = &qstatehead; *p != NULL; p = &(*p)->next) { 1542c5c4113dSnw141292 if (*p == (*state)) { 1543c5c4113dSnw141292 *p = (*state)->next; 1544c5c4113dSnw141292 break; 1545c5c4113dSnw141292 } 1546c5c4113dSnw141292 } 1547e3c2d6aaSnw141292 1548e3c2d6aaSnw141292 idmap_cleanup_batch(*state); 1549e3c2d6aaSnw141292 1550c5c4113dSnw141292 (void) pthread_mutex_unlock(&qstatelock); 1551c5c4113dSnw141292 155284decf41Sjp151216 (void) pthread_cond_destroy(&(*state)->cv); 155384decf41Sjp151216 155484decf41Sjp151216 idmap_release_conn((*state)->qadh); 155584decf41Sjp151216 1556c5c4113dSnw141292 free(*state); 1557c5c4113dSnw141292 *state = NULL; 1558c5c4113dSnw141292 } 1559c5c4113dSnw141292 1560c5c4113dSnw141292 idmap_retcode 1561c5c4113dSnw141292 idmap_lookup_batch_end(idmap_query_state_t **state, 1562c5c4113dSnw141292 struct timeval *timeout) 1563c5c4113dSnw141292 { 1564c5c4113dSnw141292 int rc = LDAP_SUCCESS; 1565c5c4113dSnw141292 idmap_retcode retcode = IDMAP_SUCCESS; 1566c5c4113dSnw141292 1567c5c4113dSnw141292 (*state)->qdead = 1; 1568c5c4113dSnw141292 1569c5c4113dSnw141292 /* Process results until done or until timeout, if given */ 1570c5c4113dSnw141292 while ((*state)->qinflight > 0) { 1571c5c4113dSnw141292 if ((rc = idmap_get_adobject_batch((*state)->qadh, 1572c5c4113dSnw141292 timeout)) != 0) 1573c5c4113dSnw141292 break; 1574c5c4113dSnw141292 } 1575c5c4113dSnw141292 1576c5c4113dSnw141292 if (rc == LDAP_UNAVAILABLE || rc == LDAP_UNWILLING_TO_PERFORM || 1577c5c4113dSnw141292 rc == LDAP_CONNECT_ERROR || rc == LDAP_SERVER_DOWN || 1578c5c4113dSnw141292 rc == LDAP_BUSY) { 1579c5c4113dSnw141292 retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 1580c5c4113dSnw141292 (*state)->qadh->dead = 1; 1581c5c4113dSnw141292 } 1582c5c4113dSnw141292 158384decf41Sjp151216 idmap_lookup_release_batch(state); 1584c5c4113dSnw141292 1585c5c4113dSnw141292 return (retcode); 1586c5c4113dSnw141292 } 1587c5c4113dSnw141292 1588c5c4113dSnw141292 /* 1589c5c4113dSnw141292 * Send one prepared search, queue up msgid, process what results are 1590c5c4113dSnw141292 * available 1591c5c4113dSnw141292 */ 1592c5c4113dSnw141292 static 1593c5c4113dSnw141292 idmap_retcode 1594e3c2d6aaSnw141292 idmap_batch_add1(idmap_query_state_t *state, 1595*e8c27ec8Sbaban const char *filter, char *ecanonname, char *edomain, int eunixtype, 1596*e8c27ec8Sbaban char **canonname, char **dname, char **sid, rid_t *rid, 1597*e8c27ec8Sbaban int *sid_type, char **unixname, idmap_retcode *rc) 1598c5c4113dSnw141292 { 1599c5c4113dSnw141292 idmap_retcode retcode = IDMAP_SUCCESS; 1600*e8c27ec8Sbaban int lrc, qid, i; 1601c5c4113dSnw141292 struct timeval tv; 1602c5c4113dSnw141292 idmap_q_t *q; 1603cd37da74Snw141292 static char *attrs[] = { 1604cd37da74Snw141292 SAN, 1605cd37da74Snw141292 OBJSID, 1606cd37da74Snw141292 OBJCLASS, 1607*e8c27ec8Sbaban NULL, /* placeholder for unixname attr */ 1608*e8c27ec8Sbaban NULL, /* placeholder for unixname attr */ 1609cd37da74Snw141292 NULL 1610cd37da74Snw141292 }; 1611c5c4113dSnw141292 1612c5c4113dSnw141292 qid = atomic_inc_32_nv(&state->qlastsent) - 1; 1613c5c4113dSnw141292 1614c5c4113dSnw141292 q = &(state->queries[qid]); 1615c5c4113dSnw141292 1616cd37da74Snw141292 /* 1617cd37da74Snw141292 * Remember the expected canonname so we can check the results 1618cd37da74Snw141292 * agains it 1619cd37da74Snw141292 */ 1620cd37da74Snw141292 q->ecanonname = ecanonname; 1621cd37da74Snw141292 q->edomain = edomain; 1622*e8c27ec8Sbaban q->eunixtype = eunixtype; 1623e3c2d6aaSnw141292 1624c5c4113dSnw141292 /* Remember where to put the results */ 1625cd37da74Snw141292 q->canonname = canonname; 1626*e8c27ec8Sbaban q->sid = sid; 1627c5c4113dSnw141292 q->domain = dname; 1628c5c4113dSnw141292 q->rid = rid; 1629c5c4113dSnw141292 q->sid_type = sid_type; 1630c5c4113dSnw141292 q->rc = rc; 1631*e8c27ec8Sbaban q->unixname = unixname; 1632*e8c27ec8Sbaban 1633*e8c27ec8Sbaban /* Add unixuser/unixgroup attribute names to the attrs list */ 1634*e8c27ec8Sbaban if (unixname != NULL) { 1635*e8c27ec8Sbaban i = 3; 1636*e8c27ec8Sbaban if (eunixtype != _IDMAP_T_GROUP && 1637*e8c27ec8Sbaban state->ad_unixuser_attr != NULL) 1638*e8c27ec8Sbaban attrs[i++] = (char *)state->ad_unixuser_attr; 1639*e8c27ec8Sbaban if (eunixtype != _IDMAP_T_USER && 1640*e8c27ec8Sbaban state->ad_unixgroup_attr != NULL) 1641*e8c27ec8Sbaban attrs[i] = (char *)state->ad_unixgroup_attr; 1642*e8c27ec8Sbaban } 1643c5c4113dSnw141292 1644c5c4113dSnw141292 /* 1645c5c4113dSnw141292 * Provide sane defaults for the results in case we never hear 1646c5c4113dSnw141292 * back from the DS before closing the connection. 1647e3c2d6aaSnw141292 * 1648e3c2d6aaSnw141292 * In particular we default the result to indicate a retriable 1649e3c2d6aaSnw141292 * error. The first complete matching result entry will cause 1650e3c2d6aaSnw141292 * this to be set to IDMAP_SUCCESS, and the end of the results 1651e3c2d6aaSnw141292 * for this search will cause this to indicate "not found" if no 1652e3c2d6aaSnw141292 * result entries arrived or no complete ones matched the lookup 1653e3c2d6aaSnw141292 * we were doing. 1654c5c4113dSnw141292 */ 1655c5c4113dSnw141292 *rc = IDMAP_ERR_RETRIABLE_NET_ERR; 1656*e8c27ec8Sbaban if (sid_type != NULL) 1657c5c4113dSnw141292 *sid_type = _IDMAP_T_OTHER; 1658*e8c27ec8Sbaban if (sid != NULL) 1659*e8c27ec8Sbaban *sid = NULL; 1660cd37da74Snw141292 if (canonname != NULL) 1661cd37da74Snw141292 *canonname = NULL; 1662c5c4113dSnw141292 if (dname != NULL) 1663c5c4113dSnw141292 *dname = NULL; 1664c5c4113dSnw141292 if (rid != NULL) 1665c5c4113dSnw141292 *rid = 0; 1666c5c4113dSnw141292 1667c5c4113dSnw141292 /* Send this lookup, don't wait for a result here */ 1668c5c4113dSnw141292 (void) pthread_mutex_lock(&state->qadh->lock); 1669c5c4113dSnw141292 1670c5c4113dSnw141292 if (!state->qadh->dead) { 1671c5c4113dSnw141292 state->qadh->idletime = time(NULL); 1672e3c2d6aaSnw141292 lrc = ldap_search_ext(state->qadh->ld, "", 1673cd37da74Snw141292 LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL, 1674c5c4113dSnw141292 NULL, -1, &q->msgid); 1675c5c4113dSnw141292 if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE || 1676c5c4113dSnw141292 lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN || 1677c5c4113dSnw141292 lrc == LDAP_UNWILLING_TO_PERFORM) { 1678c5c4113dSnw141292 retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 1679c5c4113dSnw141292 state->qadh->dead = 1; 1680c5c4113dSnw141292 } else if (lrc != LDAP_SUCCESS) { 1681c5c4113dSnw141292 retcode = IDMAP_ERR_OTHER; 1682c5c4113dSnw141292 state->qadh->dead = 1; 1683c5c4113dSnw141292 } 1684c5c4113dSnw141292 } 1685c5c4113dSnw141292 (void) pthread_mutex_unlock(&state->qadh->lock); 1686c5c4113dSnw141292 1687c5c4113dSnw141292 if (state->qadh->dead) 1688c5c4113dSnw141292 return (retcode); 1689c5c4113dSnw141292 1690c5c4113dSnw141292 atomic_inc_32(&state->qinflight); 1691c5c4113dSnw141292 1692c5c4113dSnw141292 /* 1693c5c4113dSnw141292 * Reap as many requests as we can _without_ waiting 1694c5c4113dSnw141292 * 1695c5c4113dSnw141292 * We do this to prevent any possible TCP socket buffer 1696c5c4113dSnw141292 * starvation deadlocks. 1697c5c4113dSnw141292 */ 1698c5c4113dSnw141292 (void) memset(&tv, 0, sizeof (tv)); 1699c5c4113dSnw141292 while (idmap_get_adobject_batch(state->qadh, &tv) == 0) 1700c5c4113dSnw141292 ; 1701c5c4113dSnw141292 1702c5c4113dSnw141292 return (IDMAP_SUCCESS); 1703c5c4113dSnw141292 } 1704c5c4113dSnw141292 1705c5c4113dSnw141292 idmap_retcode 1706c5c4113dSnw141292 idmap_name2sid_batch_add1(idmap_query_state_t *state, 1707*e8c27ec8Sbaban const char *name, const char *dname, int eunixtype, 1708cd37da74Snw141292 char **canonname, char **sid, rid_t *rid, int *sid_type, 1709*e8c27ec8Sbaban char **unixname, idmap_retcode *rc) 1710c5c4113dSnw141292 { 1711c5c4113dSnw141292 idmap_retcode retcode; 1712e3c2d6aaSnw141292 int len, samAcctNameLen; 1713c5c4113dSnw141292 char *filter = NULL; 1714cd37da74Snw141292 char *ecanonname, *edomain; /* expected canonname */ 1715c5c4113dSnw141292 1716c5c4113dSnw141292 /* 1717e3c2d6aaSnw141292 * Strategy: search the global catalog for user/group by 1718e3c2d6aaSnw141292 * sAMAccountName = user/groupname with "" as the base DN and by 1719e3c2d6aaSnw141292 * userPrincipalName = user/groupname@domain. The result 1720e3c2d6aaSnw141292 * entries will be checked to conform to the name and domain 1721e3c2d6aaSnw141292 * name given here. The DN, sAMAccountName, userPrincipalName, 1722e3c2d6aaSnw141292 * objectSid and objectClass of the result entries are all we 1723e3c2d6aaSnw141292 * need to figure out which entries match the lookup, the SID of 1724e3c2d6aaSnw141292 * the user/group and whether it is a user or a group. 1725c5c4113dSnw141292 */ 1726c5c4113dSnw141292 1727c5c4113dSnw141292 /* 1728e3c2d6aaSnw141292 * We need the name and the domain name separately and as 1729e3c2d6aaSnw141292 * name@domain. We also allow the domain to be provided 1730e3c2d6aaSnw141292 * separately. 1731c5c4113dSnw141292 */ 1732d3a612caSnw141292 samAcctNameLen = strlen(name); 1733e3c2d6aaSnw141292 1734cd37da74Snw141292 if ((ecanonname = strdup(name)) == NULL) 1735e3c2d6aaSnw141292 return (IDMAP_ERR_MEMORY); 1736cd37da74Snw141292 1737cd37da74Snw141292 if (dname == NULL || *dname == '\0') { 1738cd37da74Snw141292 if ((dname = strchr(name, '@')) != NULL) { 1739cd37da74Snw141292 /* 'name' is qualified with a domain name */ 1740cd37da74Snw141292 if ((edomain = strdup(dname + 1)) == NULL) { 1741cd37da74Snw141292 free(ecanonname); 1742cd37da74Snw141292 return (IDMAP_ERR_MEMORY); 1743cd37da74Snw141292 } 1744cd37da74Snw141292 *strchr(ecanonname, '@') = '\0'; 1745c5c4113dSnw141292 } else { 1746e3c2d6aaSnw141292 /* 'name' not qualified and dname not given */ 1747cd37da74Snw141292 if (state->qadh->owner->dflt_w2k_dom == NULL || 1748cd37da74Snw141292 *state->qadh->owner->dflt_w2k_dom == '\0') { 1749cd37da74Snw141292 free(ecanonname); 1750e3c2d6aaSnw141292 return (IDMAP_ERR_DOMAIN); 1751e3c2d6aaSnw141292 } 1752cd37da74Snw141292 edomain = strdup(state->qadh->owner->dflt_w2k_dom); 1753cd37da74Snw141292 if (edomain == NULL) { 1754cd37da74Snw141292 free(ecanonname); 1755e3c2d6aaSnw141292 return (IDMAP_ERR_MEMORY); 1756cd37da74Snw141292 } 1757cd37da74Snw141292 } 1758cd37da74Snw141292 } else { 1759cd37da74Snw141292 if ((edomain = strdup(dname)) == NULL) { 1760cd37da74Snw141292 free(ecanonname); 1761cd37da74Snw141292 return (IDMAP_ERR_MEMORY); 1762cd37da74Snw141292 } 1763e3c2d6aaSnw141292 } 1764c5c4113dSnw141292 1765c5c4113dSnw141292 /* Assemble filter */ 1766e3c2d6aaSnw141292 len = snprintf(NULL, 0, SANFILTER, samAcctNameLen, name) + 1; 1767e3c2d6aaSnw141292 if ((filter = (char *)malloc(len)) == NULL) { 1768cd37da74Snw141292 free(ecanonname); 1769c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 1770c5c4113dSnw141292 } 1771e3c2d6aaSnw141292 (void) snprintf(filter, len, SANFILTER, samAcctNameLen, name); 1772c5c4113dSnw141292 1773cd37da74Snw141292 retcode = idmap_batch_add1(state, filter, ecanonname, edomain, 1774*e8c27ec8Sbaban eunixtype, canonname, NULL, sid, rid, sid_type, unixname, rc); 1775c5c4113dSnw141292 1776c5c4113dSnw141292 free(filter); 1777c5c4113dSnw141292 1778c5c4113dSnw141292 return (retcode); 1779c5c4113dSnw141292 } 1780c5c4113dSnw141292 1781c5c4113dSnw141292 idmap_retcode 1782c5c4113dSnw141292 idmap_sid2name_batch_add1(idmap_query_state_t *state, 1783*e8c27ec8Sbaban const char *sid, const rid_t *rid, int eunixtype, 1784*e8c27ec8Sbaban char **name, char **dname, int *sid_type, char **unixname, 1785*e8c27ec8Sbaban idmap_retcode *rc) 1786c5c4113dSnw141292 { 1787c5c4113dSnw141292 idmap_retcode retcode; 1788c5c4113dSnw141292 int flen, ret; 1789c5c4113dSnw141292 char *filter = NULL; 1790c5c4113dSnw141292 char cbinsid[MAXHEXBINSID + 1]; 1791c5c4113dSnw141292 1792c5c4113dSnw141292 /* 1793c5c4113dSnw141292 * Strategy: search [the global catalog] for user/group by 1794c5c4113dSnw141292 * objectSid = SID with empty base DN. The DN, sAMAccountName 1795c5c4113dSnw141292 * and objectClass of the result are all we need to figure out 1796c5c4113dSnw141292 * the name of the SID and whether it is a user, a group or a 1797c5c4113dSnw141292 * computer. 1798c5c4113dSnw141292 */ 1799c5c4113dSnw141292 1800c5c4113dSnw141292 ret = idmap_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid)); 1801c5c4113dSnw141292 if (ret != 0) 1802c5c4113dSnw141292 return (IDMAP_ERR_SID); 1803c5c4113dSnw141292 1804c5c4113dSnw141292 /* Assemble filter */ 1805e3c2d6aaSnw141292 flen = snprintf(NULL, 0, OBJSIDFILTER, cbinsid) + 1; 1806c5c4113dSnw141292 if ((filter = (char *)malloc(flen)) == NULL) 1807c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 1808e3c2d6aaSnw141292 (void) snprintf(filter, flen, OBJSIDFILTER, cbinsid); 1809c5c4113dSnw141292 1810*e8c27ec8Sbaban retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype, 1811*e8c27ec8Sbaban name, dname, NULL, NULL, sid_type, unixname, rc); 1812*e8c27ec8Sbaban 1813*e8c27ec8Sbaban free(filter); 1814*e8c27ec8Sbaban 1815*e8c27ec8Sbaban return (retcode); 1816*e8c27ec8Sbaban } 1817*e8c27ec8Sbaban 1818*e8c27ec8Sbaban idmap_retcode 1819*e8c27ec8Sbaban idmap_unixname2sid_batch_add1(idmap_query_state_t *state, 1820*e8c27ec8Sbaban const char *unixname, int is_user, int is_wuser, 1821*e8c27ec8Sbaban char **sid, rid_t *rid, char **name, char **dname, int *sid_type, 1822*e8c27ec8Sbaban idmap_retcode *rc) 1823*e8c27ec8Sbaban { 1824*e8c27ec8Sbaban idmap_retcode retcode; 1825*e8c27ec8Sbaban int len, ulen; 1826*e8c27ec8Sbaban char *filter = NULL; 1827*e8c27ec8Sbaban const char *attrname = NULL; 1828*e8c27ec8Sbaban 1829*e8c27ec8Sbaban /* Get unixuser or unixgroup AD attribute name */ 1830*e8c27ec8Sbaban attrname = (is_user) ? 1831*e8c27ec8Sbaban state->ad_unixuser_attr : state->ad_unixgroup_attr; 1832*e8c27ec8Sbaban if (attrname == NULL) 1833*e8c27ec8Sbaban return (IDMAP_ERR_NOTFOUND); 1834*e8c27ec8Sbaban 1835*e8c27ec8Sbaban /* Assemble filter */ 1836*e8c27ec8Sbaban ulen = strlen(unixname); 1837*e8c27ec8Sbaban len = snprintf(NULL, 0, "(&(objectclass=%s)(%s=%.*s))", 1838*e8c27ec8Sbaban is_wuser ? "user" : "group", attrname, ulen, unixname) + 1; 1839*e8c27ec8Sbaban if ((filter = (char *)malloc(len)) == NULL) 1840*e8c27ec8Sbaban return (IDMAP_ERR_MEMORY); 1841*e8c27ec8Sbaban (void) snprintf(filter, len, "(&(objectclass=%s)(%s=%.*s))", 1842*e8c27ec8Sbaban is_wuser ? "user" : "group", attrname, ulen, unixname); 1843*e8c27ec8Sbaban 1844*e8c27ec8Sbaban retcode = idmap_batch_add1(state, filter, NULL, NULL, 1845*e8c27ec8Sbaban _IDMAP_T_UNDEF, name, dname, sid, rid, sid_type, NULL, rc); 1846c5c4113dSnw141292 1847c5c4113dSnw141292 free(filter); 1848c5c4113dSnw141292 1849c5c4113dSnw141292 return (retcode); 1850c5c4113dSnw141292 } 1851