14520Snw141292 /* 24520Snw141292 * CDDL HEADER START 34520Snw141292 * 44520Snw141292 * The contents of this file are subject to the terms of the 54520Snw141292 * Common Development and Distribution License (the "License"). 64520Snw141292 * You may not use this file except in compliance with the License. 74520Snw141292 * 84520Snw141292 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94520Snw141292 * or http://www.opensolaris.org/os/licensing. 104520Snw141292 * See the License for the specific language governing permissions 114520Snw141292 * and limitations under the License. 124520Snw141292 * 134520Snw141292 * When distributing Covered Code, include this CDDL HEADER in each 144520Snw141292 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154520Snw141292 * If applicable, add the following below this CDDL HEADER, with the 164520Snw141292 * fields enclosed by brackets "[]" replaced with your own identifying 174520Snw141292 * information: Portions Copyright [yyyy] [name of copyright owner] 184520Snw141292 * 194520Snw141292 * CDDL HEADER END 204520Snw141292 */ 214520Snw141292 224520Snw141292 /* 234520Snw141292 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 244520Snw141292 * Use is subject to license terms. 254520Snw141292 */ 264520Snw141292 274520Snw141292 #pragma ident "%Z%%M% %I% %E% SMI" 284520Snw141292 294520Snw141292 /* 304520Snw141292 * Processes name2sid & sid2name batched lookups for a given user or 314520Snw141292 * computer from an AD Directory server using GSSAPI authentication 324520Snw141292 */ 334520Snw141292 344520Snw141292 #include <stdio.h> 354520Snw141292 #include <stdlib.h> 364520Snw141292 #include <alloca.h> 374520Snw141292 #include <string.h> 384520Snw141292 #include <strings.h> 394520Snw141292 #include <lber.h> 404520Snw141292 #include <ldap.h> 414520Snw141292 #include <sasl/sasl.h> 424520Snw141292 #include <string.h> 434520Snw141292 #include <ctype.h> 444520Snw141292 #include <pthread.h> 454520Snw141292 #include <synch.h> 464520Snw141292 #include <atomic.h> 474520Snw141292 #include <errno.h> 484520Snw141292 #include <assert.h> 494520Snw141292 #include <limits.h> 504520Snw141292 #include "idmapd.h" 514520Snw141292 524520Snw141292 /* 534520Snw141292 * Internal data structures for this code 544520Snw141292 */ 554520Snw141292 564520Snw141292 /* Attribute names and filter format strings */ 574520Snw141292 #define OBJECTSID "objectSid" 584520Snw141292 #define OBJECTSIDFILTER "(objectSid=%s)" 594520Snw141292 #define SAMACCOUNTNAME "sAMAccountName" 604520Snw141292 #define SANFILTER "(sAMAccountName=%.*s)" 614520Snw141292 #define OBJECTCLASS "objectClass" 624520Snw141292 634520Snw141292 /* 644520Snw141292 * This should really be in some <sys/sid.h> file or so; we have a 654520Snw141292 * private version of sid_t, and so must other components of ON until we 664520Snw141292 * rationalize this. 674520Snw141292 */ 684520Snw141292 typedef struct sid { 694520Snw141292 uchar_t version; 704520Snw141292 uchar_t sub_authority_count; 714520Snw141292 uint64_t authority; /* really, 48-bits */ 724520Snw141292 rid_t sub_authorities[SID_MAX_SUB_AUTHORITIES]; 734520Snw141292 } sid_t; 744520Snw141292 754520Snw141292 /* A single DS */ 764520Snw141292 typedef struct ad_host { 774520Snw141292 struct ad_host *next; 784520Snw141292 ad_t *owner; /* ad_t to which this belongs */ 794520Snw141292 pthread_mutex_t lock; 804520Snw141292 LDAP *ld; /* LDAP connection */ 814520Snw141292 uint32_t ref; /* ref count */ 824520Snw141292 time_t idletime; /* time since last activity */ 834520Snw141292 int dead; /* error on LDAP connection */ 844520Snw141292 /* 854520Snw141292 * Used to distinguish between different instances of LDAP 864520Snw141292 * connections to this same DS. We need this so we never mix up 874520Snw141292 * results for a given msgID from one connection with those of 884520Snw141292 * another earlier connection where two batch state structures 894520Snw141292 * share this ad_host object but used different LDAP connections 904520Snw141292 * to send their LDAP searches. 914520Snw141292 */ 924520Snw141292 uint64_t generation; 934520Snw141292 944520Snw141292 /* LDAP DS info */ 954520Snw141292 char *host; 964520Snw141292 int port; 974520Snw141292 984520Snw141292 /* hardwired to SASL GSSAPI only for now */ 994520Snw141292 char *saslmech; 1004520Snw141292 unsigned saslflags; 1014520Snw141292 } ad_host_t; 1024520Snw141292 1034520Snw141292 /* A set of DSs for a given AD partition; ad_t typedef comes from adutil.h */ 1044520Snw141292 struct ad { 1054520Snw141292 char *dflt_w2k_dom; /* used to qualify bare names */ 1064520Snw141292 char *basedn; /* derived from dflt domain */ 1074520Snw141292 pthread_mutex_t lock; 1084520Snw141292 uint32_t ref; 1094520Snw141292 idmap_ad_partition_t partition; /* Data or global catalog? */ 1104520Snw141292 }; 1114520Snw141292 1124520Snw141292 /* 1134520Snw141292 * A place to put the results of a batched (async) query 1144520Snw141292 * 1154520Snw141292 * There is one of these for every query added to a batch object 1164520Snw141292 * (idmap_query_state, see below). 1174520Snw141292 */ 1184520Snw141292 typedef struct idmap_q { 1194520Snw141292 char **result; /* name or stringified SID */ 1204520Snw141292 char **domain; /* name of domain of object */ 1214520Snw141292 rid_t *rid; /* for n2s, if not NULL */ 1224520Snw141292 int *sid_type; /* if not NULL */ 1234520Snw141292 idmap_retcode *rc; 1244520Snw141292 int msgid; /* LDAP message ID */ 1254520Snw141292 /* 1264520Snw141292 * Bitfield containing state needed to know when we're done 1274520Snw141292 * processing search results related to this query's LDAP 1284520Snw141292 * searches. Mostly self-explanatory. 1294520Snw141292 */ 1304520Snw141292 uint16_t n2s : 1; /* name->SID or SID->name? */ 1314520Snw141292 uint16_t got_reply : 1; 1324520Snw141292 uint16_t got_results : 1; 1334520Snw141292 uint16_t got_objectSid : 1; 1344520Snw141292 uint16_t got_objectClass : 1; 1354520Snw141292 uint16_t got_samAcctName : 1; 1364520Snw141292 } idmap_q_t; 1374520Snw141292 1384520Snw141292 /* Batch context structure; typedef is in header file */ 1394520Snw141292 struct idmap_query_state { 1404520Snw141292 idmap_query_state_t *next; 1414520Snw141292 int qcount; /* how many queries */ 142*4884Sjp151216 int ref_cnt; /* reference count */ 143*4884Sjp151216 pthread_cond_t cv; /* Condition wait variable */ 1444520Snw141292 uint32_t qlastsent; 1454520Snw141292 uint32_t qinflight; /* how many queries in flight */ 1464520Snw141292 uint16_t qdead; /* oops, lost LDAP connection */ 1474520Snw141292 ad_host_t *qadh; /* LDAP connection */ 1484520Snw141292 uint64_t qadh_gen; /* same as qadh->generation */ 1494520Snw141292 idmap_q_t queries[1]; /* array of query results */ 1504520Snw141292 }; 1514520Snw141292 1524520Snw141292 /* 1534520Snw141292 * List of query state structs -- needed so we can "route" LDAP results 1544520Snw141292 * to the right context if multiple threads should be using the same 1554520Snw141292 * connection concurrently 1564520Snw141292 */ 1574520Snw141292 static idmap_query_state_t *qstatehead = NULL; 1584520Snw141292 static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER; 1594520Snw141292 1604520Snw141292 /* 1614520Snw141292 * List of DSs, needed by the idle connection reaper thread 1624520Snw141292 */ 1634520Snw141292 static ad_host_t *host_head = NULL; 1644644Sbaban static pthread_t reaperid = 0; 1654520Snw141292 static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER; 1664520Snw141292 167*4884Sjp151216 168*4884Sjp151216 static void 169*4884Sjp151216 idmap_lookup_unlock_batch(idmap_query_state_t **state); 170*4884Sjp151216 171*4884Sjp151216 172*4884Sjp151216 1734520Snw141292 /*ARGSUSED*/ 1744520Snw141292 static int 1754520Snw141292 idmap_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) { 1764520Snw141292 sasl_interact_t *interact; 1774520Snw141292 1784520Snw141292 if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE) 1794520Snw141292 return (LDAP_PARAM_ERROR); 1804520Snw141292 1814520Snw141292 /* There should be no extra arguemnts for SASL/GSSAPI authentication */ 1824520Snw141292 for (interact = prompts; interact->id != SASL_CB_LIST_END; 1834520Snw141292 interact++) { 1844520Snw141292 interact->result = NULL; 1854520Snw141292 interact->len = 0; 1864520Snw141292 } 1874520Snw141292 return (LDAP_SUCCESS); 1884520Snw141292 } 1894520Snw141292 1904520Snw141292 /* Turn "foo.bar.com" into "dc=foo,dc=bar,dc=com" */ 1914520Snw141292 static 1924520Snw141292 char * 1934520Snw141292 dns2dn(const char *dns) 1944520Snw141292 { 1954520Snw141292 int nameparts; 1964520Snw141292 1974520Snw141292 /* Sigh, ldap_dns_to_dn()'s first arg should be a const char * */ 1984520Snw141292 return (ldap_dns_to_dn((char *)dns, &nameparts)); 1994520Snw141292 } 2004520Snw141292 2014520Snw141292 /* 2024520Snw141292 * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other 2034520Snw141292 * attributes (CN, etc...) 2044520Snw141292 */ 2054520Snw141292 static 2064520Snw141292 char * 2074520Snw141292 dn2dns(const char *dn) 2084520Snw141292 { 2094520Snw141292 char **rdns = NULL; 2104520Snw141292 char **attrs = NULL; 2114520Snw141292 char **labels = NULL; 2124520Snw141292 char *dns = NULL; 2134520Snw141292 char **rdn, **attr, **label; 2144520Snw141292 int maxlabels = 5; 2154520Snw141292 int nlabels = 0; 2164520Snw141292 int dnslen; 2174520Snw141292 2184520Snw141292 /* 2194520Snw141292 * There is no reverse of ldap_dns_to_dn() in our libldap, so we 2204520Snw141292 * have to do the hard work here for now. 2214520Snw141292 */ 2224520Snw141292 2234520Snw141292 /* 2244520Snw141292 * This code is much too liberal: it looks for "dc" attributes 2254520Snw141292 * in all RDNs of the DN. In theory this could cause problems 2264520Snw141292 * if people were to use "dc" in nodes other than the root of 2274520Snw141292 * the tree, but in practice noone, least of all Active 2284520Snw141292 * Directory, does that. 2294520Snw141292 * 2304520Snw141292 * On the other hand, this code is much too conservative: it 2314520Snw141292 * does not make assumptions about ldap_explode_dn(), and _that_ 2324520Snw141292 * is the true for looking at every attr of every RDN. 2334520Snw141292 * 2344520Snw141292 * Since we only ever look at dc and those must be DNS labels, 2354520Snw141292 * at least until we get around to supporting IDN here we 2364520Snw141292 * shouldn't see escaped labels from AD nor from libldap, though 2374520Snw141292 * the spec (RFC2253) does allow libldap to escape things that 2384520Snw141292 * don't need escaping -- if that should ever happen then 2394520Snw141292 * libldap will need a spanking, and we can take care of that. 2404520Snw141292 */ 2414520Snw141292 2424520Snw141292 /* Explode a DN into RDNs */ 2434520Snw141292 if ((rdns = ldap_explode_dn(dn, 0)) == NULL) 2444520Snw141292 return (NULL); 2454520Snw141292 2464520Snw141292 labels = calloc(maxlabels + 1, sizeof (char *)); 2474520Snw141292 label = labels; 2484520Snw141292 2494520Snw141292 for (rdn = rdns; *rdn != NULL; rdn++) { 2504520Snw141292 if (attrs != NULL) 2514520Snw141292 ldap_value_free(attrs); 2524520Snw141292 2534520Snw141292 /* Explode each RDN, look for DC attr, save val as DNS label */ 2544520Snw141292 if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) 2554520Snw141292 goto done; 2564520Snw141292 2574520Snw141292 for (attr = attrs; *attr != NULL; attr++) { 2584520Snw141292 if (strncasecmp(*attr, "dc=", 3) != 0) 2594520Snw141292 continue; 2604520Snw141292 2614520Snw141292 /* Found a DNS label */ 2624520Snw141292 labels[nlabels++] = strdup((*attr) + 3); 2634520Snw141292 2644520Snw141292 if (nlabels == maxlabels) { 2654520Snw141292 char **tmp; 2664520Snw141292 tmp = realloc(labels, 2674520Snw141292 sizeof (char *) * (maxlabels + 1)); 2684520Snw141292 2694520Snw141292 if (tmp == NULL) 2704520Snw141292 goto done; 2714520Snw141292 2724520Snw141292 labels = tmp; 2734520Snw141292 labels[nlabels] = NULL; 2744520Snw141292 } 2754520Snw141292 2764520Snw141292 /* There should be just one DC= attr per-RDN */ 2774520Snw141292 break; 2784520Snw141292 } 2794520Snw141292 } 2804520Snw141292 2814520Snw141292 /* 2824520Snw141292 * Got all the labels, now join with '.' 2834520Snw141292 * 2844520Snw141292 * We need room for nlabels - 1 periods ('.'), one nul 2854520Snw141292 * terminator, and the strlen() of each label. 2864520Snw141292 */ 2874520Snw141292 dnslen = nlabels; 2884520Snw141292 for (label = labels; *label != NULL; label++) 2894520Snw141292 dnslen += strlen(*label); 2904520Snw141292 2914520Snw141292 if ((dns = malloc(dnslen)) == NULL) 2924520Snw141292 goto done; 2934520Snw141292 2944520Snw141292 *dns = '\0'; 2954520Snw141292 2964520Snw141292 for (label = labels; *label != NULL; label++) { 2974520Snw141292 (void) strlcat(dns, *label, dnslen); 2984520Snw141292 /* 2994520Snw141292 * NOTE: the last '.' won't be appended -- there's no room 3004520Snw141292 * for it! 3014520Snw141292 */ 3024520Snw141292 (void) strlcat(dns, ".", dnslen); 3034520Snw141292 } 3044520Snw141292 3054520Snw141292 done: 3064520Snw141292 if (labels != NULL) { 3074520Snw141292 for (label = labels; *label != NULL; label++) 3084520Snw141292 free(*label); 3094520Snw141292 free(labels); 3104520Snw141292 } 3114520Snw141292 if (attrs != NULL) 3124520Snw141292 ldap_value_free(attrs); 3134520Snw141292 if (rdns != NULL) 3144520Snw141292 ldap_value_free(rdns); 3154520Snw141292 3164520Snw141292 return (dns); 3174520Snw141292 } 3184520Snw141292 3194520Snw141292 /* 3204520Snw141292 * Keep connection management simple for now, extend or replace later 3214520Snw141292 * with updated libsldap code. 3224520Snw141292 */ 3234520Snw141292 #define ADREAPERSLEEP 60 3244520Snw141292 #define ADCONN_TIME 300 3254520Snw141292 3264520Snw141292 /* 3274520Snw141292 * Idle connection reaping side of connection management 3284520Snw141292 * 3294520Snw141292 * Every minute wake up and look for connections that have been idle for 3304520Snw141292 * five minutes or more and close them. 3314520Snw141292 */ 3324520Snw141292 /*ARGSUSED*/ 3334520Snw141292 static 3344520Snw141292 void 3354520Snw141292 adreaper(void *arg) 3364520Snw141292 { 3374520Snw141292 ad_host_t *adh; 3384520Snw141292 time_t now; 3394520Snw141292 timespec_t ts; 3404520Snw141292 3414520Snw141292 ts.tv_sec = ADREAPERSLEEP; 3424520Snw141292 ts.tv_nsec = 0; 3434520Snw141292 3444520Snw141292 for (;;) { 3454520Snw141292 /* 3464520Snw141292 * nanosleep(3RT) is thead-safe (no SIGALRM) and more 3474520Snw141292 * portable than usleep(3C) 3484520Snw141292 */ 3494520Snw141292 (void) nanosleep(&ts, NULL); 3504520Snw141292 (void) pthread_mutex_lock(&adhostlock); 3514520Snw141292 now = time(NULL); 3524520Snw141292 for (adh = host_head; adh != NULL; adh = adh->next) { 3534520Snw141292 (void) pthread_mutex_lock(&adh->lock); 3544520Snw141292 if (adh->ref == 0 && adh->idletime != 0 && 3554520Snw141292 adh->idletime + ADCONN_TIME < now) { 3564520Snw141292 if (adh->ld) { 3574520Snw141292 (void) ldap_unbind(adh->ld); 3584520Snw141292 adh->ld = NULL; 3594520Snw141292 adh->idletime = 0; 3604520Snw141292 adh->ref = 0; 3614520Snw141292 } 3624520Snw141292 } 3634520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 3644520Snw141292 } 3654520Snw141292 (void) pthread_mutex_unlock(&adhostlock); 3664520Snw141292 } 3674520Snw141292 } 3684520Snw141292 3694520Snw141292 int 3704520Snw141292 idmap_ad_alloc(ad_t **new_ad, const char *default_domain, 3714520Snw141292 idmap_ad_partition_t part) 3724520Snw141292 { 3734520Snw141292 ad_t *ad; 3744520Snw141292 3754520Snw141292 *new_ad = NULL; 3764520Snw141292 3774520Snw141292 if ((default_domain == NULL || *default_domain == '\0') && 3784520Snw141292 part != IDMAP_AD_GLOBAL_CATALOG) 3794520Snw141292 return (-1); 3804520Snw141292 3814520Snw141292 if ((ad = calloc(1, sizeof (ad_t))) == NULL) 3824520Snw141292 return (-1); 3834520Snw141292 3844520Snw141292 ad->ref = 1; 3854520Snw141292 ad->partition = part; 3864520Snw141292 3874520Snw141292 /* 3884520Snw141292 * If default_domain is NULL, deal, deferring errors until 3894520Snw141292 * idmap_lookup_batch_start() -- this makes it easier on the 3904520Snw141292 * caller, who can simply observe lookups failing as opposed to 3914520Snw141292 * having to conditionalize calls to lookups according to 3924520Snw141292 * whether it has a non-NULL ad_t *. 3934520Snw141292 */ 3944520Snw141292 if (default_domain == NULL) 3954520Snw141292 default_domain = ""; 3964520Snw141292 3974520Snw141292 if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL) 3984520Snw141292 goto err; 3994520Snw141292 4004520Snw141292 /* If default_domain is empty, deal; see above */ 4014520Snw141292 if (*default_domain == '\0') { 4024520Snw141292 if ((ad->basedn = strdup("")) == NULL) 4034520Snw141292 goto err; 4044520Snw141292 } else if ((ad->basedn = dns2dn(default_domain)) == NULL) { 4054520Snw141292 goto err; 4064520Snw141292 } 4074520Snw141292 4084520Snw141292 if (pthread_mutex_init(&ad->lock, NULL) != 0) 4094520Snw141292 goto err; 4104520Snw141292 4114520Snw141292 *new_ad = ad; 4124520Snw141292 4134520Snw141292 return (0); 4144520Snw141292 err: 4154520Snw141292 if (ad->dflt_w2k_dom != NULL) 4164520Snw141292 free(ad->dflt_w2k_dom); 4174520Snw141292 if (ad->basedn != NULL) 4184520Snw141292 free(ad->basedn); 4194520Snw141292 free(ad); 4204520Snw141292 return (-1); 4214520Snw141292 } 4224520Snw141292 4234520Snw141292 4244520Snw141292 void 4254520Snw141292 idmap_ad_free(ad_t **ad) 4264520Snw141292 { 4274520Snw141292 ad_host_t *p; 4284520Snw141292 4294520Snw141292 if (ad == NULL || *ad == NULL) 4304520Snw141292 return; 4314520Snw141292 4324520Snw141292 (void) pthread_mutex_lock(&(*ad)->lock); 4334520Snw141292 4344520Snw141292 if (atomic_dec_32_nv(&(*ad)->ref) > 0) { 4354520Snw141292 (void) pthread_mutex_unlock(&(*ad)->lock); 4364520Snw141292 *ad = NULL; 4374520Snw141292 return; 4384520Snw141292 } 4394520Snw141292 4404520Snw141292 for (p = host_head; p != NULL; p = p->next) { 4414520Snw141292 if (p->owner != (*ad)) 4424520Snw141292 continue; 4434520Snw141292 idmap_delete_ds((*ad), p->host, p->port); 4444520Snw141292 } 4454520Snw141292 4464520Snw141292 free((*ad)->basedn); 4474520Snw141292 4484520Snw141292 (void) pthread_mutex_unlock(&(*ad)->lock); 4494520Snw141292 (void) pthread_mutex_destroy(&(*ad)->lock); 4504520Snw141292 4514520Snw141292 free(*ad); 4524520Snw141292 4534520Snw141292 *ad = NULL; 4544520Snw141292 } 4554520Snw141292 4564520Snw141292 static 4574520Snw141292 int 4584520Snw141292 idmap_open_conn(ad_host_t *adh) 4594520Snw141292 { 4604520Snw141292 int rc, ldversion; 4614520Snw141292 4624520Snw141292 if (adh->dead && adh->ld != NULL) { 4634520Snw141292 (void) ldap_unbind(adh->ld); 4644520Snw141292 adh->ld = NULL; 4654520Snw141292 adh->dead = 0; 4664520Snw141292 } 4674520Snw141292 4684520Snw141292 if (adh->ld == NULL) { 4694520Snw141292 int zero = 0; 4704520Snw141292 int timeoutms = 30 * 1000; 4714520Snw141292 4724520Snw141292 atomic_inc_64(&adh->generation); 4734520Snw141292 adh->ld = ldap_init(adh->host, adh->port); 4744520Snw141292 if (adh->ld == NULL) 4754520Snw141292 return (-1); 4764520Snw141292 4774520Snw141292 ldversion = LDAP_VERSION3; 4784520Snw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, 4794520Snw141292 &ldversion); 4804520Snw141292 4814520Snw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, 4824520Snw141292 LDAP_OPT_OFF); 4834520Snw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero); 4844520Snw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero); 4854520Snw141292 /* setup TCP/IP connect timeout */ 4864520Snw141292 (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, 4874520Snw141292 &timeoutms); 4884520Snw141292 (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 4894520Snw141292 rc = ldap_sasl_interactive_bind_s(adh->ld, 4904520Snw141292 "" /* binddn */, adh->saslmech, NULL, NULL, adh->saslflags, 4914520Snw141292 &idmap_saslcallback, NULL /* defaults */); 4924520Snw141292 4934520Snw141292 if (rc != LDAP_SUCCESS) { 4944695Sbaban idmapdlog(LOG_ERR, "ldap_sasl_interactive_bind_s() " 4954695Sbaban "to server %s:%d failed. (%s)", 4964695Sbaban adh->host, adh->port, ldap_err2string(rc)); 4974520Snw141292 return (rc); 4984520Snw141292 } 4994520Snw141292 } 5004520Snw141292 5014520Snw141292 adh->idletime = time(NULL); 5024520Snw141292 5034520Snw141292 return (LDAP_SUCCESS); 5044520Snw141292 } 5054520Snw141292 5064520Snw141292 5074520Snw141292 /* 5084520Snw141292 * Connection management: find an open connection or open one 5094520Snw141292 */ 5104520Snw141292 static 5114520Snw141292 ad_host_t * 5124520Snw141292 idmap_get_conn(const ad_t *ad) 5134520Snw141292 { 5144520Snw141292 ad_host_t *adh = NULL; 5154520Snw141292 int rc; 5164520Snw141292 5174520Snw141292 (void) pthread_mutex_lock(&adhostlock); 5184520Snw141292 5194520Snw141292 /* 5204520Snw141292 * Search for any ad_host_t, preferably one with an open 5214520Snw141292 * connection 5224520Snw141292 */ 5234520Snw141292 for (adh = host_head; adh != NULL; adh = adh->next) { 5244520Snw141292 if (adh->owner == ad) { 5254520Snw141292 break; 5264520Snw141292 } 5274520Snw141292 } 5284520Snw141292 5294520Snw141292 if (adh != NULL) 5304520Snw141292 atomic_inc_32(&adh->ref); 5314520Snw141292 5324520Snw141292 (void) pthread_mutex_unlock(&adhostlock); 5334520Snw141292 5344520Snw141292 if (adh == NULL) 5354520Snw141292 return (NULL); 5364520Snw141292 5374520Snw141292 /* found connection, open it if not opened */ 5384520Snw141292 (void) pthread_mutex_lock(&adh->lock); 5394520Snw141292 rc = idmap_open_conn(adh); 5404520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 5414520Snw141292 if (rc != LDAP_SUCCESS) 5424520Snw141292 return (NULL); 5434520Snw141292 5444520Snw141292 return (adh); 5454520Snw141292 } 5464520Snw141292 5474520Snw141292 static 5484520Snw141292 void 5494520Snw141292 idmap_release_conn(ad_host_t *adh) 5504520Snw141292 { 5514520Snw141292 (void) pthread_mutex_lock(&adh->lock); 5524520Snw141292 if (atomic_dec_32_nv(&adh->ref) == 0) 5534520Snw141292 adh->idletime = time(NULL); 5544520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 5554520Snw141292 } 5564520Snw141292 5574520Snw141292 /* 5584520Snw141292 * Take ad_host_config_t information, create a ad_host_t, 5594520Snw141292 * populate it and add it to the list of hosts. 5604520Snw141292 */ 5614520Snw141292 5624520Snw141292 int 5634520Snw141292 idmap_add_ds(ad_t *ad, const char *host, int port) 5644520Snw141292 { 5654520Snw141292 ad_host_t *p; 5664520Snw141292 ad_host_t *new = NULL; 5674520Snw141292 int ret = -1; 5684520Snw141292 5694520Snw141292 if (port == 0) 5704520Snw141292 port = (int)ad->partition; 5714520Snw141292 5724520Snw141292 (void) pthread_mutex_lock(&adhostlock); 5734520Snw141292 for (p = host_head; p != NULL; p = p->next) { 5744520Snw141292 if (p->owner != ad) 5754520Snw141292 continue; 5764520Snw141292 5774520Snw141292 if (strcmp(host, p->host) == 0 && p->port == port) { 5784520Snw141292 /* already added */ 5794520Snw141292 ret = -2; 5804520Snw141292 goto err; 5814520Snw141292 } 5824520Snw141292 } 5834520Snw141292 5844520Snw141292 /* add new entry */ 5854520Snw141292 new = (ad_host_t *)calloc(1, sizeof (ad_host_t)); 5864520Snw141292 if (new == NULL) 5874520Snw141292 goto err; 5884520Snw141292 new->owner = ad; 5894520Snw141292 new->port = port; 5904520Snw141292 new->dead = 0; 5914520Snw141292 if ((new->host = strdup(host)) == NULL) 5924520Snw141292 goto err; 5934520Snw141292 5944520Snw141292 /* default to SASL GSSAPI only for now */ 5954520Snw141292 new->saslflags = LDAP_SASL_INTERACTIVE; 5964520Snw141292 new->saslmech = "GSSAPI"; 5974520Snw141292 5984520Snw141292 if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) { 5994520Snw141292 free(new->host); 6004520Snw141292 new->host = NULL; 6014520Snw141292 errno = ret; 6024520Snw141292 ret = -1; 6034520Snw141292 goto err; 6044520Snw141292 } 6054520Snw141292 6064520Snw141292 /* link in */ 6074520Snw141292 new->next = host_head; 6084520Snw141292 host_head = new; 6094520Snw141292 6104520Snw141292 /* Start reaper if it doesn't exist */ 6114520Snw141292 if (reaperid == 0) 6124520Snw141292 (void) pthread_create(&reaperid, NULL, 6134520Snw141292 (void *(*)(void *))adreaper, (void *)NULL); 6144520Snw141292 6154520Snw141292 err: 6164520Snw141292 (void) pthread_mutex_unlock(&adhostlock); 6174520Snw141292 6184520Snw141292 if (ret != 0 && new != NULL) { 6194520Snw141292 if (new->host != NULL) { 6204520Snw141292 (void) pthread_mutex_destroy(&new->lock); 6214520Snw141292 free(new->host); 6224520Snw141292 } 6234520Snw141292 free(new); 6244520Snw141292 } 6254520Snw141292 6264520Snw141292 return (ret); 6274520Snw141292 } 6284520Snw141292 6294520Snw141292 /* 6304520Snw141292 * free a DS configuration 6314520Snw141292 */ 6324520Snw141292 void 6334520Snw141292 idmap_delete_ds(ad_t *ad, const char *host, int port) 6344520Snw141292 { 6354520Snw141292 ad_host_t **p, *q; 6364520Snw141292 6374520Snw141292 (void) pthread_mutex_lock(&adhostlock); 6384520Snw141292 for (p = &host_head; *p != NULL; p = &((*p)->next)) { 6394520Snw141292 if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 || 6404520Snw141292 (*p)->port != port) 6414520Snw141292 continue; 6424520Snw141292 /* found */ 6434520Snw141292 if (atomic_dec_32_nv(&((*p)->ref)) > 0) 6444520Snw141292 break; /* still in use */ 6454520Snw141292 6464520Snw141292 q = *p; 6474520Snw141292 *p = (*p)->next; 6484520Snw141292 6494520Snw141292 (void) pthread_mutex_destroy(&q->lock); 6504520Snw141292 6514520Snw141292 if (q->ld) 6524520Snw141292 (void) ldap_unbind(q->ld); 6534520Snw141292 if (q->host) 6544520Snw141292 free(q->host); 6554520Snw141292 free(q); 6564520Snw141292 break; 6574520Snw141292 } 6584520Snw141292 (void) pthread_mutex_unlock(&adhostlock); 6594520Snw141292 } 6604520Snw141292 6614520Snw141292 /* 6624520Snw141292 * Convert a binary SID in a BerValue to a sid_t 6634520Snw141292 */ 6644520Snw141292 static 6654520Snw141292 int 6664520Snw141292 idmap_getsid(BerValue *bval, sid_t *sidp) 6674520Snw141292 { 6684520Snw141292 int i, j; 6694520Snw141292 uchar_t *v; 6704520Snw141292 uint32_t a; 6714520Snw141292 6724520Snw141292 /* 6734520Snw141292 * The binary format of a SID is as follows: 6744520Snw141292 * 6754520Snw141292 * byte #0: version, always 0x01 6764520Snw141292 * byte #1: RID count, always <= 0x0f 6774520Snw141292 * bytes #2-#7: SID authority, big-endian 48-bit unsigned int 6784520Snw141292 * 6794520Snw141292 * followed by RID count RIDs, each a little-endian, unsigned 6804520Snw141292 * 32-bit int. 6814520Snw141292 */ 6824520Snw141292 /* 6834520Snw141292 * Sanity checks: must have at least one RID, version must be 6844520Snw141292 * 0x01, and the length must be 8 + rid count * 4 6854520Snw141292 */ 6864520Snw141292 if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 && 6874520Snw141292 bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) { 6884520Snw141292 v = (uchar_t *)bval->bv_val; 6894520Snw141292 sidp->version = v[0]; 6904520Snw141292 sidp->sub_authority_count = v[1]; 6914520Snw141292 sidp->authority = 6924520Snw141292 /* big endian -- so start from the left */ 6934520Snw141292 ((u_longlong_t)v[2] << 40) | 6944520Snw141292 ((u_longlong_t)v[3] << 32) | 6954520Snw141292 ((u_longlong_t)v[4] << 24) | 6964520Snw141292 ((u_longlong_t)v[5] << 16) | 6974520Snw141292 ((u_longlong_t)v[6] << 8) | 6984520Snw141292 (u_longlong_t)v[7]; 6994520Snw141292 for (i = 0; i < sidp->sub_authority_count; i++) { 7004520Snw141292 j = 8 + (i * 4); 7014520Snw141292 /* little endian -- so start from the right */ 7024520Snw141292 a = (v[j + 3] << 24) | (v[j + 2] << 16) | 7034520Snw141292 (v[j + 1] << 8) | (v[j]); 7044520Snw141292 sidp->sub_authorities[i] = a; 7054520Snw141292 } 7064520Snw141292 return (0); 7074520Snw141292 } 7084520Snw141292 return (-1); 7094520Snw141292 } 7104520Snw141292 7114520Snw141292 /* 7124520Snw141292 * Convert a sid_t to S-1-... 7134520Snw141292 */ 7144520Snw141292 static 7154520Snw141292 char * 7164520Snw141292 idmap_sid2txt(sid_t *sidp) 7174520Snw141292 { 7184520Snw141292 int rlen, i, len; 7194520Snw141292 char *str, *cp; 7204520Snw141292 7214520Snw141292 if (sidp->version != 1) 7224520Snw141292 return (NULL); 7234520Snw141292 7244520Snw141292 len = sizeof ("S-1-") - 1; 7254520Snw141292 7264520Snw141292 /* 7274520Snw141292 * We could optimize like so, but, why? 7284520Snw141292 * if (sidp->authority < 10) 7294520Snw141292 * len += 2; 7304520Snw141292 * else if (sidp->authority < 100) 7314520Snw141292 * len += 3; 7324520Snw141292 * else 7334520Snw141292 * len += snprintf(NULL, 0"%llu", sidp->authority); 7344520Snw141292 */ 7354520Snw141292 len += snprintf(NULL, 0, "%llu", sidp->authority); 7364520Snw141292 7374520Snw141292 /* Max length of a uint32_t printed out in ASCII is 10 bytes */ 7384520Snw141292 len += 1 + (sidp->sub_authority_count + 1) * 10; 7394520Snw141292 7404520Snw141292 if ((cp = str = malloc(len)) == NULL) 7414520Snw141292 return (NULL); 7424520Snw141292 7434520Snw141292 rlen = snprintf(str, len, "S-1-%llu", sidp->authority); 7444520Snw141292 7454520Snw141292 cp += rlen; 7464520Snw141292 len -= rlen; 7474520Snw141292 7484520Snw141292 for (i = 0; i < sidp->sub_authority_count; i++) { 7494520Snw141292 assert(len > 0); 7504520Snw141292 rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]); 7514520Snw141292 cp += rlen; 7524520Snw141292 len -= rlen; 7534520Snw141292 assert(len >= 0); 7544520Snw141292 } 7554520Snw141292 7564520Snw141292 return (str); 7574520Snw141292 } 7584520Snw141292 7594520Snw141292 /* 7604520Snw141292 * Convert a sid_t to on-the-wire encoding 7614520Snw141292 */ 7624520Snw141292 static 7634520Snw141292 int 7644520Snw141292 idmap_sid2binsid(sid_t *sid, uchar_t *binsid, int binsidlen) 7654520Snw141292 { 7664520Snw141292 uchar_t *p; 7674520Snw141292 int i; 7684520Snw141292 uint64_t a; 7694520Snw141292 uint32_t r; 7704520Snw141292 7714520Snw141292 if (sid->version != 1 || 7724520Snw141292 binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4)) 7734520Snw141292 return (-1); 7744520Snw141292 7754520Snw141292 p = binsid; 7764520Snw141292 *p++ = 0x01; /* version */ 7774520Snw141292 /* sub authority count */ 7784520Snw141292 *p++ = sid->sub_authority_count; 7794520Snw141292 /* Authority */ 7804520Snw141292 a = sid->authority; 7814520Snw141292 /* big-endian -- start from left */ 7824520Snw141292 *p++ = (a >> 40) & 0xFF; 7834520Snw141292 *p++ = (a >> 32) & 0xFF; 7844520Snw141292 *p++ = (a >> 24) & 0xFF; 7854520Snw141292 *p++ = (a >> 16) & 0xFF; 7864520Snw141292 *p++ = (a >> 8) & 0xFF; 7874520Snw141292 *p++ = a & 0xFF; 7884520Snw141292 7894520Snw141292 /* sub-authorities */ 7904520Snw141292 for (i = 0; i < sid->sub_authority_count; i++) { 7914520Snw141292 r = sid->sub_authorities[i]; 7924520Snw141292 /* little-endian -- start from right */ 7934520Snw141292 *p++ = (r & 0x000000FF); 7944520Snw141292 *p++ = (r & 0x0000FF00) >> 8; 7954520Snw141292 *p++ = (r & 0x00FF0000) >> 16; 7964520Snw141292 *p++ = (r & 0xFF000000) >> 24; 7974520Snw141292 } 7984520Snw141292 7994520Snw141292 return (0); 8004520Snw141292 } 8014520Snw141292 8024520Snw141292 /* 8034520Snw141292 * Convert a stringified SID (S-1-...) into a hex-encoded version of the 8044520Snw141292 * on-the-wire encoding, but with each pair of hex digits pre-pended 8054520Snw141292 * with a '\', so we can pass this to libldap. 8064520Snw141292 */ 8074520Snw141292 static 8084520Snw141292 int 8094520Snw141292 idmap_txtsid2hexbinsid(const char *txt, const rid_t *rid, 8104520Snw141292 char *hexbinsid, int hexbinsidlen) 8114520Snw141292 { 8124520Snw141292 sid_t sid = { 0 }; 8134520Snw141292 int i, j; 8144520Snw141292 const char *cp; 8154520Snw141292 char *ecp; 8164520Snw141292 u_longlong_t a; 8174520Snw141292 unsigned long r; 8184520Snw141292 uchar_t *binsid, b, hb; 8194520Snw141292 8204520Snw141292 /* Only version 1 SIDs please */ 8214520Snw141292 if (strncmp(txt, "S-1-", strlen("S-1-")) != 0) 8224520Snw141292 return (-1); 8234520Snw141292 8244520Snw141292 if (strlen(txt) < (strlen("S-1-") + 1)) 8254520Snw141292 return (-1); 8264520Snw141292 8274520Snw141292 /* count '-'s */ 8284520Snw141292 for (j = 0, cp = strchr(txt, '-'); 8294520Snw141292 cp != NULL && *cp != '\0'; 8304520Snw141292 j++, cp = strchr(cp + 1, '-')) { 8314520Snw141292 /* can't end on a '-' */ 8324520Snw141292 if (*(cp + 1) == '\0') 8334520Snw141292 return (-1); 8344520Snw141292 } 8354520Snw141292 8364864Sbaban /* Adjust count for version and authority */ 8374864Sbaban j -= 2; 8384864Sbaban 8394864Sbaban /* we know the version number and RID count */ 8404864Sbaban sid.version = 1; 8414864Sbaban sid.sub_authority_count = (rid != NULL) ? j + 1 : j; 8424864Sbaban 8434520Snw141292 /* must have at least one RID, but not too many */ 8444864Sbaban if (sid.sub_authority_count < 1 || 8454864Sbaban sid.sub_authority_count > SID_MAX_SUB_AUTHORITIES) 8464520Snw141292 return (-1); 8474520Snw141292 8484520Snw141292 /* check that we only have digits and '-' */ 8494520Snw141292 if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1)) 8504520Snw141292 return (-1); 8514520Snw141292 8524520Snw141292 cp = txt + strlen("S-1-"); 8534520Snw141292 8544520Snw141292 /* 64-bit safe parsing of unsigned 48-bit authority value */ 8554520Snw141292 errno = 0; 8564520Snw141292 a = strtoull(cp, &ecp, 10); 8574520Snw141292 8584520Snw141292 /* errors parsing the authority or too many bits */ 8594520Snw141292 if (cp == ecp || (a == 0 && errno == EINVAL) || 8604520Snw141292 (a == ULLONG_MAX && errno == ERANGE) || 8614520Snw141292 (a & 0x0000ffffffffffffULL) != a) 8624520Snw141292 return (-1); 8634520Snw141292 8644520Snw141292 cp = ecp; 8654520Snw141292 8664520Snw141292 sid.authority = (uint64_t)a; 8674520Snw141292 8684864Sbaban for (i = 0; i < j; i++) { 8694520Snw141292 if (*cp++ != '-') 8704520Snw141292 return (-1); 8714520Snw141292 /* 64-bit safe parsing of unsigned 32-bit RID */ 8724520Snw141292 errno = 0; 8734520Snw141292 r = strtoul(cp, &ecp, 10); 8744520Snw141292 /* errors parsing the RID or too many bits */ 8754520Snw141292 if (cp == ecp || (r == 0 && errno == EINVAL) || 8764520Snw141292 (r == ULONG_MAX && errno == ERANGE) || 8774520Snw141292 (r & 0xffffffffUL) != r) 8784520Snw141292 return (-1); 8794520Snw141292 sid.sub_authorities[i] = (uint32_t)r; 8804520Snw141292 cp = ecp; 8814520Snw141292 } 8824520Snw141292 8834520Snw141292 /* check that all of the string SID has been consumed */ 8844520Snw141292 if (*cp != '\0') 8854520Snw141292 return (-1); 8864520Snw141292 8874864Sbaban if (rid != NULL) 8884864Sbaban sid.sub_authorities[j] = *rid; 8894520Snw141292 8904520Snw141292 j = 1 + 1 + 6 + sid.sub_authority_count * 4; 8914520Snw141292 8924520Snw141292 if (hexbinsidlen < (j * 3)) 8934520Snw141292 return (-2); 8944520Snw141292 8954520Snw141292 /* binary encode the SID */ 8964520Snw141292 binsid = (uchar_t *)alloca(j); 8974520Snw141292 (void) idmap_sid2binsid(&sid, binsid, j); 8984520Snw141292 8994520Snw141292 /* hex encode, with a backslash before each byte */ 9004520Snw141292 for (ecp = hexbinsid, i = 0; i < j; i++) { 9014520Snw141292 b = binsid[i]; 9024520Snw141292 *ecp++ = '\\'; 9034520Snw141292 hb = (b >> 4) & 0xF; 9044520Snw141292 *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 9054520Snw141292 hb = b & 0xF; 9064520Snw141292 *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 9074520Snw141292 } 9084520Snw141292 *ecp = '\0'; 9094520Snw141292 9104520Snw141292 return (0); 9114520Snw141292 } 9124520Snw141292 9134520Snw141292 static 9144520Snw141292 char * 9154520Snw141292 convert_bval2sid(BerValue *bval, rid_t *rid) 9164520Snw141292 { 9174520Snw141292 sid_t sid; 9184520Snw141292 9194520Snw141292 if (idmap_getsid(bval, &sid) < 0) 9204520Snw141292 return (NULL); 9214520Snw141292 9224520Snw141292 /* 9234520Snw141292 * If desired and if the SID is what should be a domain/computer 9244520Snw141292 * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then 9254520Snw141292 * save the last RID and truncate the SID 9264520Snw141292 */ 9274520Snw141292 if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5) 9284520Snw141292 *rid = sid.sub_authorities[--sid.sub_authority_count]; 9294520Snw141292 return (idmap_sid2txt(&sid)); 9304520Snw141292 } 9314520Snw141292 9324520Snw141292 9334520Snw141292 idmap_retcode 9344520Snw141292 idmap_lookup_batch_start(ad_t *ad, int nqueries, idmap_query_state_t **state) 9354520Snw141292 { 9364520Snw141292 idmap_query_state_t *new_state; 9374520Snw141292 ad_host_t *adh = NULL; 9384520Snw141292 9394520Snw141292 *state = NULL; 9404520Snw141292 9414520Snw141292 if (*ad->dflt_w2k_dom == '\0') 9424520Snw141292 return (-1); 9434520Snw141292 9444520Snw141292 adh = idmap_get_conn(ad); 9454520Snw141292 if (adh == NULL) 9464520Snw141292 return (IDMAP_ERR_OTHER); 9474520Snw141292 9484520Snw141292 new_state = calloc(1, sizeof (idmap_query_state_t) + 9494520Snw141292 (nqueries - 1) * sizeof (idmap_q_t)); 9504520Snw141292 9514520Snw141292 if (new_state == NULL) 9524520Snw141292 return (IDMAP_ERR_MEMORY); 9534520Snw141292 954*4884Sjp151216 new_state->ref_cnt = 1; 9554520Snw141292 new_state->qadh = adh; 9564520Snw141292 new_state->qcount = nqueries; 9574520Snw141292 new_state->qadh_gen = adh->generation; 9584520Snw141292 /* should be -1, but the atomic routines want unsigned */ 9594520Snw141292 new_state->qlastsent = 0; 960*4884Sjp151216 (void) pthread_cond_init(&new_state->cv, NULL); 9614520Snw141292 9624520Snw141292 (void) pthread_mutex_lock(&qstatelock); 9634520Snw141292 new_state->next = qstatehead; 9644520Snw141292 qstatehead = new_state; 9654520Snw141292 (void) pthread_mutex_unlock(&qstatelock); 9664520Snw141292 9674520Snw141292 *state = new_state; 9684520Snw141292 9694520Snw141292 return (IDMAP_SUCCESS); 9704520Snw141292 } 9714520Snw141292 9724520Snw141292 /* 9734520Snw141292 * Find the idmap_query_state_t to which a given LDAP result msgid on a 974*4884Sjp151216 * given connection belongs. This routine increaments the reference count 975*4884Sjp151216 * so that the object can not be freed. idmap_lookup_unlock_batch() 976*4884Sjp151216 * must be called to decreament the reference count. 9774520Snw141292 */ 9784520Snw141292 static 9794520Snw141292 int 9804520Snw141292 idmap_msgid2query(ad_host_t *adh, int msgid, 9814520Snw141292 idmap_query_state_t **state, int *qid) 9824520Snw141292 { 9834520Snw141292 idmap_query_state_t *p; 9844520Snw141292 int i; 9854520Snw141292 9864520Snw141292 (void) pthread_mutex_lock(&qstatelock); 9874520Snw141292 for (p = qstatehead; p != NULL; p = p->next) { 9884520Snw141292 if (p->qadh != adh || adh->generation != p->qadh_gen) 9894520Snw141292 continue; 9904520Snw141292 for (i = 0; i < p->qcount; i++) { 9914520Snw141292 if ((p->queries[i]).msgid == msgid) { 992*4884Sjp151216 p->ref_cnt++; 9934520Snw141292 *state = p; 9944520Snw141292 *qid = i; 9954520Snw141292 (void) pthread_mutex_unlock(&qstatelock); 9964520Snw141292 return (1); 9974520Snw141292 } 9984520Snw141292 } 9994520Snw141292 } 10004520Snw141292 (void) pthread_mutex_unlock(&qstatelock); 10014520Snw141292 return (0); 10024520Snw141292 } 10034520Snw141292 10044520Snw141292 /* 10054520Snw141292 * Handle an objectSid attr from a result 10064520Snw141292 */ 10074520Snw141292 static 10084520Snw141292 void 10094520Snw141292 idmap_bv_objsid2sidstr(BerValue **bvalues, idmap_q_t *q) 10104520Snw141292 { 10114520Snw141292 if (bvalues == NULL) 10124520Snw141292 return; 10134520Snw141292 /* objectSid is single valued */ 10144520Snw141292 *(q->result) = convert_bval2sid(bvalues[0], q->rid); 10154520Snw141292 q->got_objectSid = 1; 10164520Snw141292 } 10174520Snw141292 10184520Snw141292 /* 10194520Snw141292 * Handle a sAMAccountName attr from a result 10204520Snw141292 */ 10214520Snw141292 static 10224520Snw141292 void 10234520Snw141292 idmap_bv_samaccountname2name(BerValue **bvalues, idmap_q_t *q, const char *dn) 10244520Snw141292 { 10254520Snw141292 char *result, *domain; 10264520Snw141292 int len; 10274520Snw141292 10284520Snw141292 if (bvalues == NULL) 10294520Snw141292 return; 10304520Snw141292 10314520Snw141292 if ((domain = dn2dns(dn)) == NULL) 10324520Snw141292 return; 10334520Snw141292 10344520Snw141292 if (bvalues == NULL || bvalues[0] == NULL || 10354520Snw141292 bvalues[0]->bv_val == NULL) 10364520Snw141292 return; 10374520Snw141292 10384520Snw141292 len = bvalues[0]->bv_len + 1; 10394520Snw141292 10404520Snw141292 if (q->domain != NULL) 10414520Snw141292 *(q->domain) = domain; 10424520Snw141292 else 10434520Snw141292 len += strlen(domain) + 1; 10444520Snw141292 10454520Snw141292 if ((result = malloc(len)) == NULL) { 10464520Snw141292 if (q->domain != NULL) 10474520Snw141292 *(q->domain) = NULL; 10484520Snw141292 free(domain); 10494520Snw141292 return; 10504520Snw141292 } 10514520Snw141292 10524520Snw141292 (void) memcpy(result, bvalues[0]->bv_val, (size_t)bvalues[0]->bv_len); 10534520Snw141292 result[bvalues[0]->bv_len] = '\0'; 10544520Snw141292 10554520Snw141292 if (q->domain == NULL) { 10564520Snw141292 (void) strlcat(result, "@", len); 10574520Snw141292 (void) strlcat(result, domain, len); 10584520Snw141292 free(domain); 10594520Snw141292 } 10604520Snw141292 10614520Snw141292 *(q->result) = result; 10624520Snw141292 q->got_samAcctName = 1; 10634520Snw141292 } 10644520Snw141292 10654520Snw141292 10664520Snw141292 #define BVAL_CASEEQ(bv, str) \ 10674520Snw141292 (((*(bv))->bv_len == (sizeof (str) - 1)) && \ 10684520Snw141292 strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0) 10694520Snw141292 10704520Snw141292 /* 10714520Snw141292 * Handle an objectClass attr from a result 10724520Snw141292 */ 10734520Snw141292 static 10744520Snw141292 void 10754520Snw141292 idmap_bv_objclass2sidtype(BerValue **bvalues, idmap_q_t *q) 10764520Snw141292 { 10774520Snw141292 BerValue **cbval; 10784520Snw141292 10794520Snw141292 if (bvalues == NULL) 10804520Snw141292 return; 10814520Snw141292 10824520Snw141292 for (cbval = bvalues; *cbval != NULL; cbval++) { 10834520Snw141292 /* don't clobber sid_type */ 10844520Snw141292 if (*(q->sid_type) == _IDMAP_T_COMPUTER || 10854520Snw141292 *(q->sid_type) == _IDMAP_T_GROUP || 10864520Snw141292 *(q->sid_type) == _IDMAP_T_USER) 10874520Snw141292 continue; 10884520Snw141292 10894520Snw141292 if (BVAL_CASEEQ(cbval, "Computer")) { 10904520Snw141292 *(q->sid_type) = _IDMAP_T_COMPUTER; 10914520Snw141292 return; 10924520Snw141292 } else if (BVAL_CASEEQ(cbval, "Group")) { 10934520Snw141292 *(q->sid_type) = _IDMAP_T_GROUP; 10944520Snw141292 } else if (BVAL_CASEEQ(cbval, "USER")) { 10954520Snw141292 *(q->sid_type) = _IDMAP_T_USER; 10964520Snw141292 } else 10974520Snw141292 *(q->sid_type) = _IDMAP_T_OTHER; 10984520Snw141292 q->got_objectClass = 1; 10994520Snw141292 } 11004520Snw141292 } 11014520Snw141292 11024520Snw141292 /* 11034520Snw141292 * Handle a given search result entry 11044520Snw141292 */ 11054520Snw141292 static 11064520Snw141292 void 11074520Snw141292 idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res) 11084520Snw141292 { 11094520Snw141292 char *dn, *attr; 11104520Snw141292 BerElement *ber = NULL; 11114520Snw141292 BerValue **bvalues; 11124520Snw141292 ad_host_t *adh; 11134520Snw141292 idmap_q_t *q; 11144520Snw141292 idmap_retcode orc; 11154520Snw141292 11164520Snw141292 adh = state->qadh; 11174520Snw141292 11184520Snw141292 (void) pthread_mutex_lock(&adh->lock); 11194520Snw141292 11204520Snw141292 if (adh->dead || (dn = ldap_get_dn(adh->ld, res)) == NULL) { 11214520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 11224520Snw141292 return; 11234520Snw141292 } 11244520Snw141292 11254520Snw141292 q = &(state->queries[qid]); 11264520Snw141292 11274520Snw141292 for (attr = ldap_first_attribute(adh->ld, res, &ber); attr != NULL; 11284520Snw141292 attr = ldap_next_attribute(adh->ld, res, ber)) { 11294520Snw141292 orc = *q->rc; 11304520Snw141292 bvalues = NULL; /* for memory management below */ 11314520Snw141292 11324520Snw141292 /* 11334520Snw141292 * If this is an attribute we are looking for and 11344520Snw141292 * haven't seen it yet, parse it 11354520Snw141292 */ 11364520Snw141292 if (orc != IDMAP_SUCCESS && q->n2s && !q->got_objectSid && 11374520Snw141292 strcasecmp(attr, OBJECTSID) == 0) { 11384520Snw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 11394520Snw141292 idmap_bv_objsid2sidstr(bvalues, q); 11404520Snw141292 } else if (orc != IDMAP_SUCCESS && !q->n2s && 11414520Snw141292 !q->got_samAcctName && 11424520Snw141292 strcasecmp(attr, SAMACCOUNTNAME) == 0) { 11434520Snw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 11444520Snw141292 idmap_bv_samaccountname2name(bvalues, q, dn); 11454520Snw141292 } else if (orc != IDMAP_SUCCESS && !q->got_objectClass && 11464520Snw141292 strcasecmp(attr, OBJECTCLASS) == 0) { 11474520Snw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 11484520Snw141292 idmap_bv_objclass2sidtype(bvalues, q); 11494520Snw141292 } 11504520Snw141292 11514520Snw141292 if (bvalues != NULL) 11524520Snw141292 ldap_value_free_len(bvalues); 11534520Snw141292 ldap_memfree(attr); 11544520Snw141292 11554520Snw141292 if (q->n2s) 11564520Snw141292 *q->rc = (q->got_objectSid && 11574520Snw141292 q->got_objectClass) ? 11584520Snw141292 IDMAP_SUCCESS : IDMAP_ERR_NORESULT; 11594520Snw141292 else 11604520Snw141292 *q->rc = (q->got_samAcctName && 11614520Snw141292 q->got_objectClass) ? 11624520Snw141292 IDMAP_SUCCESS : IDMAP_ERR_NORESULT; 11634520Snw141292 11644520Snw141292 if (*q->rc == IDMAP_SUCCESS && *q->result == NULL) 11654520Snw141292 *q->rc = IDMAP_ERR_NORESULT; 11664520Snw141292 } 11674520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 11684520Snw141292 11694520Snw141292 /* 11704520Snw141292 * If there should be multiple partial results for different 11714520Snw141292 * entities (there should not be, but, if it should happen) then 11724520Snw141292 * it's possible that they could get mixed up here and we could 11734520Snw141292 * get bogus results. We just mark the query's results as 11744520Snw141292 * toxic (IDMAP_ERR_INTERNAL). 11754520Snw141292 * 11764520Snw141292 * Between this and ignoring results when we've already filled 11774520Snw141292 * out a query's results we should be OK. The first full reply 11784520Snw141292 * wins. In practice we should never get multiple results. 11794520Snw141292 */ 11804520Snw141292 if (orc == IDMAP_ERR_INTERNAL) 11814520Snw141292 *q->rc = IDMAP_ERR_INTERNAL; 11824520Snw141292 else if (*q->rc != IDMAP_SUCCESS) 11834520Snw141292 *q->rc = IDMAP_ERR_INTERNAL; 11844520Snw141292 11854520Snw141292 if (ber != NULL) 11864520Snw141292 ber_free(ber, 0); 11874520Snw141292 11884520Snw141292 ldap_memfree(dn); 11894520Snw141292 } 11904520Snw141292 11914520Snw141292 /* 11924520Snw141292 * Try to get a result; if there is one, find the corresponding 11934520Snw141292 * idmap_q_t and process the result. 11944520Snw141292 */ 11954520Snw141292 static 11964520Snw141292 int 11974520Snw141292 idmap_get_adobject_batch(ad_host_t *adh, struct timeval *timeout) 11984520Snw141292 { 11994520Snw141292 idmap_query_state_t *query_state; 12004520Snw141292 LDAPMessage *res = NULL; 12014520Snw141292 int rc, ret, msgid, qid; 12024520Snw141292 12034520Snw141292 (void) pthread_mutex_lock(&adh->lock); 12044520Snw141292 if (adh->dead) { 12054520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 12064520Snw141292 return (-1); 12074520Snw141292 } 12084520Snw141292 12094520Snw141292 /* Get one result */ 12104520Snw141292 rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, 12114520Snw141292 timeout, &res); 12124520Snw141292 if (rc == LDAP_UNAVAILABLE || rc == LDAP_UNWILLING_TO_PERFORM || 12134520Snw141292 rc == LDAP_CONNECT_ERROR || rc == LDAP_SERVER_DOWN || 12144520Snw141292 rc == LDAP_BUSY) 12154520Snw141292 adh->dead = 1; 12164520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 12174520Snw141292 12184520Snw141292 if (adh->dead) 12194520Snw141292 return (-1); 12204520Snw141292 12214520Snw141292 switch (rc) { 12224520Snw141292 case LDAP_RES_SEARCH_RESULT: 12234520Snw141292 /* We have all the LDAP replies for some search... */ 12244520Snw141292 msgid = ldap_msgid(res); 12254520Snw141292 if (idmap_msgid2query(adh, msgid, 12264520Snw141292 &query_state, &qid)) { 12274520Snw141292 /* ...so we can decrement qinflight */ 12284520Snw141292 atomic_dec_32(&query_state->qinflight); 12294520Snw141292 /* we saw at least one reply */ 12304520Snw141292 query_state->queries[qid].got_reply = 1; 1231*4884Sjp151216 idmap_lookup_unlock_batch(&query_state); 12324520Snw141292 } 12334520Snw141292 (void) ldap_msgfree(res); 12344520Snw141292 ret = 0; 12354520Snw141292 break; 12364520Snw141292 case LDAP_RES_SEARCH_REFERENCE: 12374520Snw141292 /* 12384520Snw141292 * We have no need for these at the moment. Eventually, 12394520Snw141292 * when we query things that we can't expect to find in 12404520Snw141292 * the Global Catalog then we'll need to learn to follow 12414520Snw141292 * references. 12424520Snw141292 */ 12434520Snw141292 (void) ldap_msgfree(res); 12444520Snw141292 ret = 0; 12454520Snw141292 break; 12464520Snw141292 case LDAP_RES_SEARCH_ENTRY: 12474520Snw141292 /* Got a result */ 12484520Snw141292 msgid = ldap_msgid(res); 12494520Snw141292 if (idmap_msgid2query(adh, msgid, 12504520Snw141292 &query_state, &qid)) { 12514520Snw141292 idmap_extract_object(query_state, qid, res); 12524520Snw141292 /* we saw at least one result */ 12534520Snw141292 query_state->queries[qid].got_reply = 1; 12544520Snw141292 query_state->queries[qid].got_results = 1; 1255*4884Sjp151216 idmap_lookup_unlock_batch(&query_state); 12564520Snw141292 } 12574520Snw141292 (void) ldap_msgfree(res); 12584520Snw141292 ret = 0; 12594520Snw141292 break; 12604520Snw141292 default: 12614520Snw141292 /* timeout or error; treat the same */ 12624520Snw141292 ret = -1; 12634520Snw141292 break; 12644520Snw141292 } 12654520Snw141292 12664520Snw141292 return (ret); 12674520Snw141292 } 12684520Snw141292 1269*4884Sjp151216 /* 1270*4884Sjp151216 * This routine decreament the reference count of the 1271*4884Sjp151216 * idmap_query_state_t 1272*4884Sjp151216 */ 1273*4884Sjp151216 static void 1274*4884Sjp151216 idmap_lookup_unlock_batch(idmap_query_state_t **state) 1275*4884Sjp151216 { 1276*4884Sjp151216 /* 1277*4884Sjp151216 * Decrement reference count with qstatelock locked 1278*4884Sjp151216 */ 1279*4884Sjp151216 (void) pthread_mutex_lock(&qstatelock); 1280*4884Sjp151216 (*state)->ref_cnt--; 1281*4884Sjp151216 /* 1282*4884Sjp151216 * If there are no references wakup the allocating thread 1283*4884Sjp151216 */ 1284*4884Sjp151216 if ((*state)->ref_cnt == 0) 1285*4884Sjp151216 (void) pthread_cond_signal(&(*state)->cv); 1286*4884Sjp151216 (void) pthread_mutex_unlock(&qstatelock); 1287*4884Sjp151216 *state = NULL; 1288*4884Sjp151216 } 1289*4884Sjp151216 1290*4884Sjp151216 /* 1291*4884Sjp151216 * This routine frees the idmap_query_state_t structure 1292*4884Sjp151216 * If the reference count is greater than 1 it waits 1293*4884Sjp151216 * for the other threads to finish using it. 1294*4884Sjp151216 */ 12954520Snw141292 void 1296*4884Sjp151216 idmap_lookup_release_batch(idmap_query_state_t **state) 12974520Snw141292 { 12984520Snw141292 idmap_query_state_t **p; 12994520Snw141292 1300*4884Sjp151216 /* 1301*4884Sjp151216 * Decrement reference count with qstatelock locked 1302*4884Sjp151216 * and wait for reference count to get to zero 1303*4884Sjp151216 */ 1304*4884Sjp151216 (void) pthread_mutex_lock(&qstatelock); 1305*4884Sjp151216 (*state)->ref_cnt--; 1306*4884Sjp151216 while ((*state)->ref_cnt > 0) { 1307*4884Sjp151216 (void) pthread_cond_wait(&(*state)->cv, &qstatelock); 1308*4884Sjp151216 } 13094520Snw141292 13104520Snw141292 /* Remove this state struct from the list of state structs */ 13114520Snw141292 for (p = &qstatehead; *p != NULL; p = &(*p)->next) { 13124520Snw141292 if (*p == (*state)) { 13134520Snw141292 *p = (*state)->next; 13144520Snw141292 break; 13154520Snw141292 } 13164520Snw141292 } 13174520Snw141292 (void) pthread_mutex_unlock(&qstatelock); 13184520Snw141292 1319*4884Sjp151216 (void) pthread_cond_destroy(&(*state)->cv); 1320*4884Sjp151216 1321*4884Sjp151216 idmap_release_conn((*state)->qadh); 1322*4884Sjp151216 13234520Snw141292 free(*state); 13244520Snw141292 *state = NULL; 13254520Snw141292 } 13264520Snw141292 13274520Snw141292 idmap_retcode 13284520Snw141292 idmap_lookup_batch_end(idmap_query_state_t **state, 13294520Snw141292 struct timeval *timeout) 13304520Snw141292 { 13314520Snw141292 idmap_q_t *q; 13324520Snw141292 int i; 13334520Snw141292 int rc = LDAP_SUCCESS; 13344520Snw141292 idmap_retcode retcode = IDMAP_SUCCESS; 13354520Snw141292 13364520Snw141292 (*state)->qdead = 1; 13374520Snw141292 13384520Snw141292 /* Process results until done or until timeout, if given */ 13394520Snw141292 while ((*state)->qinflight > 0) { 13404520Snw141292 if ((rc = idmap_get_adobject_batch((*state)->qadh, 13414520Snw141292 timeout)) != 0) 13424520Snw141292 break; 13434520Snw141292 } 13444520Snw141292 13454520Snw141292 if (rc == LDAP_UNAVAILABLE || rc == LDAP_UNWILLING_TO_PERFORM || 13464520Snw141292 rc == LDAP_CONNECT_ERROR || rc == LDAP_SERVER_DOWN || 13474520Snw141292 rc == LDAP_BUSY) { 13484520Snw141292 retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 13494520Snw141292 (*state)->qadh->dead = 1; 13504520Snw141292 } 13514520Snw141292 13524520Snw141292 for (i = 0; i < (*state)->qcount; i++) { 13534520Snw141292 q = &((*state)->queries[i]); 13544520Snw141292 if (q->got_reply && !q->got_results) { 13554520Snw141292 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 13564520Snw141292 *q->rc = IDMAP_ERR_RETRIABLE_NET_ERR; 13574520Snw141292 else 13584520Snw141292 *q->rc = IDMAP_ERR_NOTFOUND; 13594520Snw141292 } 13604520Snw141292 } 13614520Snw141292 1362*4884Sjp151216 idmap_lookup_release_batch(state); 13634520Snw141292 13644520Snw141292 return (retcode); 13654520Snw141292 } 13664520Snw141292 13674520Snw141292 /* 13684520Snw141292 * Send one prepared search, queue up msgid, process what results are 13694520Snw141292 * available 13704520Snw141292 */ 13714520Snw141292 static 13724520Snw141292 idmap_retcode 13734520Snw141292 idmap_batch_add1(idmap_query_state_t *state, int n2s, 13744520Snw141292 const char *filter, const char *basedn, 13754520Snw141292 char **result, char **dname, rid_t *rid, int *sid_type, 13764520Snw141292 idmap_retcode *rc) 13774520Snw141292 { 13784520Snw141292 idmap_retcode retcode = IDMAP_SUCCESS; 13794520Snw141292 int lrc, qid; 13804520Snw141292 struct timeval tv; 13814520Snw141292 idmap_q_t *q; 13824520Snw141292 13834520Snw141292 if (state->qdead) { 13844520Snw141292 *rc = IDMAP_ERR_NORESULT; 13854520Snw141292 return (IDMAP_ERR_RETRIABLE_NET_ERR); 13864520Snw141292 } 13874520Snw141292 13884520Snw141292 qid = atomic_inc_32_nv(&state->qlastsent) - 1; 13894520Snw141292 13904520Snw141292 q = &(state->queries[qid]); 13914520Snw141292 13924520Snw141292 /* Remember where to put the results */ 13934520Snw141292 q->result = result; 13944520Snw141292 q->domain = dname; 13954520Snw141292 q->rid = rid; 13964520Snw141292 q->sid_type = sid_type; 13974520Snw141292 q->rc = rc; 13984520Snw141292 q->n2s = n2s ? 1 : 0; 13994520Snw141292 q->got_objectSid = 0; 14004520Snw141292 q->got_objectClass = 0; 14014520Snw141292 q->got_samAcctName = 0; 14024520Snw141292 14034520Snw141292 /* 14044520Snw141292 * Provide sane defaults for the results in case we never hear 14054520Snw141292 * back from the DS before closing the connection. 14064520Snw141292 */ 14074520Snw141292 *rc = IDMAP_ERR_RETRIABLE_NET_ERR; 14084520Snw141292 *sid_type = _IDMAP_T_OTHER; 14094520Snw141292 *result = NULL; 14104520Snw141292 if (dname != NULL) 14114520Snw141292 *dname = NULL; 14124520Snw141292 if (rid != NULL) 14134520Snw141292 *rid = 0; 14144520Snw141292 14154520Snw141292 /* Send this lookup, don't wait for a result here */ 14164520Snw141292 (void) pthread_mutex_lock(&state->qadh->lock); 14174520Snw141292 14184520Snw141292 if (!state->qadh->dead) { 14194520Snw141292 state->qadh->idletime = time(NULL); 14204520Snw141292 lrc = ldap_search_ext(state->qadh->ld, basedn, 14214520Snw141292 LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, 14224520Snw141292 NULL, -1, &q->msgid); 14234520Snw141292 if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE || 14244520Snw141292 lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN || 14254520Snw141292 lrc == LDAP_UNWILLING_TO_PERFORM) { 14264520Snw141292 retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 14274520Snw141292 state->qadh->dead = 1; 14284520Snw141292 } else if (lrc != LDAP_SUCCESS) { 14294520Snw141292 retcode = IDMAP_ERR_OTHER; 14304520Snw141292 state->qadh->dead = 1; 14314520Snw141292 } 14324520Snw141292 } 14334520Snw141292 (void) pthread_mutex_unlock(&state->qadh->lock); 14344520Snw141292 14354520Snw141292 if (state->qadh->dead) 14364520Snw141292 return (retcode); 14374520Snw141292 14384520Snw141292 atomic_inc_32(&state->qinflight); 14394520Snw141292 14404520Snw141292 /* 14414520Snw141292 * Reap as many requests as we can _without_ waiting 14424520Snw141292 * 14434520Snw141292 * We do this to prevent any possible TCP socket buffer 14444520Snw141292 * starvation deadlocks. 14454520Snw141292 */ 14464520Snw141292 (void) memset(&tv, 0, sizeof (tv)); 14474520Snw141292 while (idmap_get_adobject_batch(state->qadh, &tv) == 0) 14484520Snw141292 ; 14494520Snw141292 14504520Snw141292 return (IDMAP_SUCCESS); 14514520Snw141292 } 14524520Snw141292 14534520Snw141292 idmap_retcode 14544520Snw141292 idmap_name2sid_batch_add1(idmap_query_state_t *state, 14554520Snw141292 const char *name, const char *dname, 14564520Snw141292 char **sid, rid_t *rid, int *sid_type, idmap_retcode *rc) 14574520Snw141292 { 14584520Snw141292 idmap_retcode retcode; 14594520Snw141292 int flen, samAcctNameLen; 14604520Snw141292 char *filter = NULL; 14614520Snw141292 char *basedn = NULL; 14624520Snw141292 char *cp; 14634520Snw141292 14644520Snw141292 /* 14654520Snw141292 * Strategy: search [the global catalog] for user/group by 14664520Snw141292 * sAMAccountName = user/groupname with base DN derived from the 14674520Snw141292 * domain name. The objectSid and objectClass of the result are 14684520Snw141292 * all we need to figure out the SID of the user/group and 14694520Snw141292 * whether it is a user or a group. 14704520Snw141292 */ 14714520Snw141292 14724520Snw141292 /* 14734520Snw141292 * Handle optional domain parameter and default domain 14744520Snw141292 * semantics. The get a basedn from the domainname. 14754520Snw141292 */ 14764520Snw141292 if (dname == NULL || *dname != '\0') { 14774520Snw141292 /* domain name not given separately */ 14784520Snw141292 if ((cp = strchr(name, '@')) == NULL) { 14794520Snw141292 /* nor is the name qualified */ 14804520Snw141292 dname = state->qadh->owner->dflt_w2k_dom; 14814520Snw141292 basedn = state->qadh->owner->basedn; 14824520Snw141292 samAcctNameLen = strlen(name); 14834520Snw141292 } else { 14844520Snw141292 /* the name is qualified */ 14854520Snw141292 /* LINTED */ 14864520Snw141292 samAcctNameLen = cp - name; 14874520Snw141292 dname = cp + 1; 14884520Snw141292 } 14894520Snw141292 } 14904520Snw141292 14914520Snw141292 if (basedn == NULL) 14924520Snw141292 basedn = dns2dn(dname); 14934520Snw141292 14944520Snw141292 /* Assemble filter */ 14954520Snw141292 flen = snprintf(NULL, 0, SANFILTER, samAcctNameLen, name) + 1; 14964520Snw141292 if ((filter = (char *)malloc(flen)) == NULL) { 14974520Snw141292 if (basedn != state->qadh->owner->basedn) 14984520Snw141292 free(basedn); 14994520Snw141292 return (IDMAP_ERR_MEMORY); 15004520Snw141292 } 15014520Snw141292 (void) snprintf(filter, flen, SANFILTER, samAcctNameLen, name); 15024520Snw141292 15034520Snw141292 retcode = idmap_batch_add1(state, 1, filter, basedn, 15044520Snw141292 sid, NULL, rid, sid_type, rc); 15054520Snw141292 15064520Snw141292 if (basedn != state->qadh->owner->basedn) 15074520Snw141292 free(basedn); 15084520Snw141292 free(filter); 15094520Snw141292 15104520Snw141292 return (retcode); 15114520Snw141292 } 15124520Snw141292 15134520Snw141292 idmap_retcode 15144520Snw141292 idmap_sid2name_batch_add1(idmap_query_state_t *state, 15154520Snw141292 const char *sid, const rid_t *rid, 15164520Snw141292 char **name, char **dname, int *sid_type, idmap_retcode *rc) 15174520Snw141292 { 15184520Snw141292 idmap_retcode retcode; 15194520Snw141292 int flen, ret; 15204520Snw141292 char *filter = NULL; 15214520Snw141292 char cbinsid[MAXHEXBINSID + 1]; 15224520Snw141292 15234520Snw141292 /* 15244520Snw141292 * Strategy: search [the global catalog] for user/group by 15254520Snw141292 * objectSid = SID with empty base DN. The DN, sAMAccountName 15264520Snw141292 * and objectClass of the result are all we need to figure out 15274520Snw141292 * the name of the SID and whether it is a user, a group or a 15284520Snw141292 * computer. 15294520Snw141292 */ 15304520Snw141292 15314520Snw141292 ret = idmap_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid)); 15324520Snw141292 if (ret != 0) 15334520Snw141292 return (IDMAP_ERR_SID); 15344520Snw141292 15354520Snw141292 /* Assemble filter */ 15364520Snw141292 flen = snprintf(NULL, 0, OBJECTSIDFILTER, cbinsid) + 1; 15374520Snw141292 if ((filter = (char *)malloc(flen)) == NULL) 15384520Snw141292 return (IDMAP_ERR_MEMORY); 15394520Snw141292 (void) snprintf(filter, flen, OBJECTSIDFILTER, cbinsid); 15404520Snw141292 15414520Snw141292 retcode = idmap_batch_add1(state, 0, filter, NULL, name, dname, 15424520Snw141292 NULL, sid_type, rc); 15434520Snw141292 15444520Snw141292 free(filter); 15454520Snw141292 15464520Snw141292 return (retcode); 15474520Snw141292 } 1548