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 /* 235908Sjp151216 * Copyright 2008 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> 505696Snw141292 #include <sys/u8_textprep.h> 51*6616Sdm199847 #include "nldaputils.h" 524520Snw141292 #include "idmapd.h" 534520Snw141292 544520Snw141292 /* 554520Snw141292 * Internal data structures for this code 564520Snw141292 */ 574520Snw141292 584520Snw141292 /* Attribute names and filter format strings */ 595447Snw141292 #define SAN "sAMAccountName" 605447Snw141292 #define OBJSID "objectSid" 615447Snw141292 #define OBJCLASS "objectClass" 624520Snw141292 #define SANFILTER "(sAMAccountName=%.*s)" 635447Snw141292 #define OBJSIDFILTER "(objectSid=%s)" 644520Snw141292 654520Snw141292 /* 664520Snw141292 * This should really be in some <sys/sid.h> file or so; we have a 674520Snw141292 * private version of sid_t, and so must other components of ON until we 684520Snw141292 * rationalize this. 694520Snw141292 */ 704520Snw141292 typedef struct sid { 714520Snw141292 uchar_t version; 724520Snw141292 uchar_t sub_authority_count; 734520Snw141292 uint64_t authority; /* really, 48-bits */ 744520Snw141292 rid_t sub_authorities[SID_MAX_SUB_AUTHORITIES]; 754520Snw141292 } sid_t; 764520Snw141292 774520Snw141292 /* A single DS */ 784520Snw141292 typedef struct ad_host { 794520Snw141292 struct ad_host *next; 804520Snw141292 ad_t *owner; /* ad_t to which this belongs */ 814520Snw141292 pthread_mutex_t lock; 824520Snw141292 LDAP *ld; /* LDAP connection */ 834520Snw141292 uint32_t ref; /* ref count */ 844520Snw141292 time_t idletime; /* time since last activity */ 854520Snw141292 int dead; /* error on LDAP connection */ 864520Snw141292 /* 874520Snw141292 * Used to distinguish between different instances of LDAP 884520Snw141292 * connections to this same DS. We need this so we never mix up 894520Snw141292 * results for a given msgID from one connection with those of 904520Snw141292 * another earlier connection where two batch state structures 914520Snw141292 * share this ad_host object but used different LDAP connections 924520Snw141292 * to send their LDAP searches. 934520Snw141292 */ 944520Snw141292 uint64_t generation; 954520Snw141292 964520Snw141292 /* LDAP DS info */ 974520Snw141292 char *host; 984520Snw141292 int port; 994520Snw141292 1004520Snw141292 /* hardwired to SASL GSSAPI only for now */ 1014520Snw141292 char *saslmech; 1024520Snw141292 unsigned saslflags; 1036531Sjp151216 1046531Sjp151216 /* Number of outstanding search requests */ 1056531Sjp151216 uint32_t max_requests; 1066531Sjp151216 uint32_t num_requests; 1074520Snw141292 } ad_host_t; 1084520Snw141292 1094520Snw141292 /* A set of DSs for a given AD partition; ad_t typedef comes from adutil.h */ 1104520Snw141292 struct ad { 1114520Snw141292 char *dflt_w2k_dom; /* used to qualify bare names */ 1124520Snw141292 pthread_mutex_t lock; 1134520Snw141292 uint32_t ref; 1145317Sjp151216 ad_host_t *last_adh; 1154520Snw141292 idmap_ad_partition_t partition; /* Data or global catalog? */ 1164520Snw141292 }; 1174520Snw141292 1184520Snw141292 /* 1194520Snw141292 * A place to put the results of a batched (async) query 1204520Snw141292 * 1214520Snw141292 * There is one of these for every query added to a batch object 1224520Snw141292 * (idmap_query_state, see below). 1234520Snw141292 */ 1244520Snw141292 typedef struct idmap_q { 1255447Snw141292 /* 1265447Snw141292 * data used for validating search result entries for name->SID 1275731Sbaban * lookups 1285447Snw141292 */ 1295696Snw141292 char *ecanonname; /* expected canon name */ 1305696Snw141292 char *edomain; /* expected domain name */ 1315731Sbaban int eunixtype; /* expected unix type */ 1325447Snw141292 /* results */ 1335696Snw141292 char **canonname; /* actual canon name */ 1344520Snw141292 char **domain; /* name of domain of object */ 1355731Sbaban char **sid; /* stringified SID */ 1365731Sbaban rid_t *rid; /* RID */ 1375731Sbaban int *sid_type; /* user or group SID? */ 1385731Sbaban char **unixname; /* unixname for name mapping */ 1396386Sjp151216 char **dn; /* DN of entry */ 1406386Sjp151216 char **attr; /* Attr for name mapping */ 1416386Sjp151216 char **value; /* value for name mapping */ 1424520Snw141292 idmap_retcode *rc; 1435447Snw141292 1445447Snw141292 /* lookup state */ 1454520Snw141292 int msgid; /* LDAP message ID */ 1466531Sjp151216 /* 1476531Sjp151216 * The LDAP search entry result is placed here to be processed 1486531Sjp151216 * when the search done result is received. 1496531Sjp151216 */ 1506531Sjp151216 LDAPMessage *search_res; /* The LDAP search result */ 1514520Snw141292 } idmap_q_t; 1524520Snw141292 1534520Snw141292 /* Batch context structure; typedef is in header file */ 1544520Snw141292 struct idmap_query_state { 1554520Snw141292 idmap_query_state_t *next; 1564520Snw141292 int qcount; /* how many queries */ 1574884Sjp151216 int ref_cnt; /* reference count */ 1584884Sjp151216 pthread_cond_t cv; /* Condition wait variable */ 1594520Snw141292 uint32_t qlastsent; 1604520Snw141292 uint32_t qinflight; /* how many queries in flight */ 1614520Snw141292 uint16_t qdead; /* oops, lost LDAP connection */ 1624520Snw141292 ad_host_t *qadh; /* LDAP connection */ 1634520Snw141292 uint64_t qadh_gen; /* same as qadh->generation */ 1645731Sbaban const char *ad_unixuser_attr; 1655731Sbaban const char *ad_unixgroup_attr; 1664520Snw141292 idmap_q_t queries[1]; /* array of query results */ 1674520Snw141292 }; 1684520Snw141292 1694520Snw141292 /* 1704520Snw141292 * List of query state structs -- needed so we can "route" LDAP results 1714520Snw141292 * to the right context if multiple threads should be using the same 1724520Snw141292 * connection concurrently 1734520Snw141292 */ 1744520Snw141292 static idmap_query_state_t *qstatehead = NULL; 1754520Snw141292 static pthread_mutex_t qstatelock = PTHREAD_MUTEX_INITIALIZER; 1764520Snw141292 1774520Snw141292 /* 1784520Snw141292 * List of DSs, needed by the idle connection reaper thread 1794520Snw141292 */ 1804520Snw141292 static ad_host_t *host_head = NULL; 1814644Sbaban static pthread_t reaperid = 0; 1824520Snw141292 static pthread_mutex_t adhostlock = PTHREAD_MUTEX_INITIALIZER; 1834520Snw141292 1844884Sjp151216 1854884Sjp151216 static void 1864884Sjp151216 idmap_lookup_unlock_batch(idmap_query_state_t **state); 1874884Sjp151216 1885317Sjp151216 static void 1895317Sjp151216 delete_ds(ad_t *ad, const char *host, int port); 1904884Sjp151216 1914520Snw141292 /*ARGSUSED*/ 1924520Snw141292 static int 1935908Sjp151216 idmap_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts) 1945908Sjp151216 { 1954520Snw141292 sasl_interact_t *interact; 1964520Snw141292 1974520Snw141292 if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE) 1984520Snw141292 return (LDAP_PARAM_ERROR); 1994520Snw141292 2004520Snw141292 /* There should be no extra arguemnts for SASL/GSSAPI authentication */ 2014520Snw141292 for (interact = prompts; interact->id != SASL_CB_LIST_END; 2025908Sjp151216 interact++) { 2034520Snw141292 interact->result = NULL; 2044520Snw141292 interact->len = 0; 2054520Snw141292 } 2064520Snw141292 return (LDAP_SUCCESS); 2074520Snw141292 } 2084520Snw141292 2094520Snw141292 2104520Snw141292 /* 2114520Snw141292 * Turn "dc=foo,dc=bar,dc=com" into "foo.bar.com"; ignores any other 2125447Snw141292 * attributes (CN, etc...). We don't need the reverse, for now. 2134520Snw141292 */ 2144520Snw141292 static 2154520Snw141292 char * 2164520Snw141292 dn2dns(const char *dn) 2174520Snw141292 { 2184520Snw141292 char **rdns = NULL; 2194520Snw141292 char **attrs = NULL; 2204520Snw141292 char **labels = NULL; 2214520Snw141292 char *dns = NULL; 2224520Snw141292 char **rdn, **attr, **label; 2234520Snw141292 int maxlabels = 5; 2244520Snw141292 int nlabels = 0; 2254520Snw141292 int dnslen; 2264520Snw141292 2274520Snw141292 /* 2284520Snw141292 * There is no reverse of ldap_dns_to_dn() in our libldap, so we 2294520Snw141292 * have to do the hard work here for now. 2304520Snw141292 */ 2314520Snw141292 2324520Snw141292 /* 2334520Snw141292 * This code is much too liberal: it looks for "dc" attributes 2344520Snw141292 * in all RDNs of the DN. In theory this could cause problems 2354520Snw141292 * if people were to use "dc" in nodes other than the root of 2364520Snw141292 * the tree, but in practice noone, least of all Active 2374520Snw141292 * Directory, does that. 2384520Snw141292 * 2394520Snw141292 * On the other hand, this code is much too conservative: it 2404520Snw141292 * does not make assumptions about ldap_explode_dn(), and _that_ 2414520Snw141292 * is the true for looking at every attr of every RDN. 2424520Snw141292 * 2434520Snw141292 * Since we only ever look at dc and those must be DNS labels, 2444520Snw141292 * at least until we get around to supporting IDN here we 2454520Snw141292 * shouldn't see escaped labels from AD nor from libldap, though 2464520Snw141292 * the spec (RFC2253) does allow libldap to escape things that 2474520Snw141292 * don't need escaping -- if that should ever happen then 2484520Snw141292 * libldap will need a spanking, and we can take care of that. 2494520Snw141292 */ 2504520Snw141292 2514520Snw141292 /* Explode a DN into RDNs */ 2524520Snw141292 if ((rdns = ldap_explode_dn(dn, 0)) == NULL) 2534520Snw141292 return (NULL); 2544520Snw141292 2554520Snw141292 labels = calloc(maxlabels + 1, sizeof (char *)); 2564520Snw141292 label = labels; 2574520Snw141292 2584520Snw141292 for (rdn = rdns; *rdn != NULL; rdn++) { 2594520Snw141292 if (attrs != NULL) 2604520Snw141292 ldap_value_free(attrs); 2614520Snw141292 2624520Snw141292 /* Explode each RDN, look for DC attr, save val as DNS label */ 2634520Snw141292 if ((attrs = ldap_explode_rdn(rdn[0], 0)) == NULL) 2644520Snw141292 goto done; 2654520Snw141292 2664520Snw141292 for (attr = attrs; *attr != NULL; attr++) { 2674520Snw141292 if (strncasecmp(*attr, "dc=", 3) != 0) 2684520Snw141292 continue; 2694520Snw141292 2704520Snw141292 /* Found a DNS label */ 2714520Snw141292 labels[nlabels++] = strdup((*attr) + 3); 2724520Snw141292 2734520Snw141292 if (nlabels == maxlabels) { 2744520Snw141292 char **tmp; 2754520Snw141292 tmp = realloc(labels, 2764520Snw141292 sizeof (char *) * (maxlabels + 1)); 2774520Snw141292 2784520Snw141292 if (tmp == NULL) 2794520Snw141292 goto done; 2804520Snw141292 2814520Snw141292 labels = tmp; 2824520Snw141292 labels[nlabels] = NULL; 2834520Snw141292 } 2844520Snw141292 2854520Snw141292 /* There should be just one DC= attr per-RDN */ 2864520Snw141292 break; 2874520Snw141292 } 2884520Snw141292 } 2894520Snw141292 2904520Snw141292 /* 2914520Snw141292 * Got all the labels, now join with '.' 2924520Snw141292 * 2934520Snw141292 * We need room for nlabels - 1 periods ('.'), one nul 2944520Snw141292 * terminator, and the strlen() of each label. 2954520Snw141292 */ 2964520Snw141292 dnslen = nlabels; 2974520Snw141292 for (label = labels; *label != NULL; label++) 2984520Snw141292 dnslen += strlen(*label); 2994520Snw141292 3004520Snw141292 if ((dns = malloc(dnslen)) == NULL) 3014520Snw141292 goto done; 3024520Snw141292 3034520Snw141292 *dns = '\0'; 3044520Snw141292 3054520Snw141292 for (label = labels; *label != NULL; label++) { 3064520Snw141292 (void) strlcat(dns, *label, dnslen); 3074520Snw141292 /* 3084520Snw141292 * NOTE: the last '.' won't be appended -- there's no room 3094520Snw141292 * for it! 3104520Snw141292 */ 3114520Snw141292 (void) strlcat(dns, ".", dnslen); 3124520Snw141292 } 3134520Snw141292 3144520Snw141292 done: 3154520Snw141292 if (labels != NULL) { 3164520Snw141292 for (label = labels; *label != NULL; label++) 3174520Snw141292 free(*label); 3184520Snw141292 free(labels); 3194520Snw141292 } 3204520Snw141292 if (attrs != NULL) 3214520Snw141292 ldap_value_free(attrs); 3224520Snw141292 if (rdns != NULL) 3234520Snw141292 ldap_value_free(rdns); 3244520Snw141292 3254520Snw141292 return (dns); 3264520Snw141292 } 3274520Snw141292 3284520Snw141292 /* 3294520Snw141292 * Keep connection management simple for now, extend or replace later 3304520Snw141292 * with updated libsldap code. 3314520Snw141292 */ 3324520Snw141292 #define ADREAPERSLEEP 60 3334520Snw141292 #define ADCONN_TIME 300 3344520Snw141292 3354520Snw141292 /* 3364520Snw141292 * Idle connection reaping side of connection management 3374520Snw141292 * 3384520Snw141292 * Every minute wake up and look for connections that have been idle for 3394520Snw141292 * five minutes or more and close them. 3404520Snw141292 */ 3414520Snw141292 /*ARGSUSED*/ 3424520Snw141292 static 3434520Snw141292 void 3444520Snw141292 adreaper(void *arg) 3454520Snw141292 { 3464520Snw141292 ad_host_t *adh; 3474520Snw141292 time_t now; 3484520Snw141292 timespec_t ts; 3494520Snw141292 3504520Snw141292 ts.tv_sec = ADREAPERSLEEP; 3514520Snw141292 ts.tv_nsec = 0; 3524520Snw141292 3534520Snw141292 for (;;) { 3544520Snw141292 /* 3554520Snw141292 * nanosleep(3RT) is thead-safe (no SIGALRM) and more 3564520Snw141292 * portable than usleep(3C) 3574520Snw141292 */ 3584520Snw141292 (void) nanosleep(&ts, NULL); 3594520Snw141292 (void) pthread_mutex_lock(&adhostlock); 3604520Snw141292 now = time(NULL); 3614520Snw141292 for (adh = host_head; adh != NULL; adh = adh->next) { 3624520Snw141292 (void) pthread_mutex_lock(&adh->lock); 3634520Snw141292 if (adh->ref == 0 && adh->idletime != 0 && 3644520Snw141292 adh->idletime + ADCONN_TIME < now) { 3654520Snw141292 if (adh->ld) { 3664520Snw141292 (void) ldap_unbind(adh->ld); 3674520Snw141292 adh->ld = NULL; 3684520Snw141292 adh->idletime = 0; 3694520Snw141292 adh->ref = 0; 3704520Snw141292 } 3714520Snw141292 } 3724520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 3734520Snw141292 } 3744520Snw141292 (void) pthread_mutex_unlock(&adhostlock); 3754520Snw141292 } 3764520Snw141292 } 3774520Snw141292 3784520Snw141292 int 3794520Snw141292 idmap_ad_alloc(ad_t **new_ad, const char *default_domain, 3804520Snw141292 idmap_ad_partition_t part) 3814520Snw141292 { 3824520Snw141292 ad_t *ad; 3834520Snw141292 3844520Snw141292 *new_ad = NULL; 3854520Snw141292 3864520Snw141292 if ((default_domain == NULL || *default_domain == '\0') && 3874520Snw141292 part != IDMAP_AD_GLOBAL_CATALOG) 3884520Snw141292 return (-1); 3894520Snw141292 3904520Snw141292 if ((ad = calloc(1, sizeof (ad_t))) == NULL) 3914520Snw141292 return (-1); 3924520Snw141292 3934520Snw141292 ad->ref = 1; 3944520Snw141292 ad->partition = part; 3954520Snw141292 3964520Snw141292 if (default_domain == NULL) 3974520Snw141292 default_domain = ""; 3984520Snw141292 3994520Snw141292 if ((ad->dflt_w2k_dom = strdup(default_domain)) == NULL) 4004520Snw141292 goto err; 4014520Snw141292 4024520Snw141292 if (pthread_mutex_init(&ad->lock, NULL) != 0) 4034520Snw141292 goto err; 4044520Snw141292 4054520Snw141292 *new_ad = ad; 4064520Snw141292 4074520Snw141292 return (0); 4084520Snw141292 err: 4094520Snw141292 if (ad->dflt_w2k_dom != NULL) 4104520Snw141292 free(ad->dflt_w2k_dom); 4114520Snw141292 free(ad); 4124520Snw141292 return (-1); 4134520Snw141292 } 4144520Snw141292 4154520Snw141292 4164520Snw141292 void 4174520Snw141292 idmap_ad_free(ad_t **ad) 4184520Snw141292 { 4194520Snw141292 ad_host_t *p; 4205317Sjp151216 ad_host_t *prev; 4214520Snw141292 4224520Snw141292 if (ad == NULL || *ad == NULL) 4234520Snw141292 return; 4244520Snw141292 4254520Snw141292 (void) pthread_mutex_lock(&(*ad)->lock); 4264520Snw141292 4274520Snw141292 if (atomic_dec_32_nv(&(*ad)->ref) > 0) { 4284520Snw141292 (void) pthread_mutex_unlock(&(*ad)->lock); 4294520Snw141292 *ad = NULL; 4304520Snw141292 return; 4314520Snw141292 } 4324520Snw141292 4335317Sjp151216 (void) pthread_mutex_lock(&adhostlock); 4345317Sjp151216 prev = NULL; 4355317Sjp151216 p = host_head; 4365317Sjp151216 while (p != NULL) { 4375317Sjp151216 if (p->owner != (*ad)) { 4385317Sjp151216 prev = p; 4395317Sjp151216 p = p->next; 4404520Snw141292 continue; 4415317Sjp151216 } else { 4425317Sjp151216 delete_ds((*ad), p->host, p->port); 4435317Sjp151216 if (prev == NULL) 4445317Sjp151216 p = host_head; 4455317Sjp151216 else 4465317Sjp151216 p = prev->next; 4475317Sjp151216 } 4484520Snw141292 } 4495317Sjp151216 (void) pthread_mutex_unlock(&adhostlock); 4504520Snw141292 4514520Snw141292 (void) pthread_mutex_unlock(&(*ad)->lock); 4524520Snw141292 (void) pthread_mutex_destroy(&(*ad)->lock); 4534520Snw141292 4545447Snw141292 free((*ad)->dflt_w2k_dom); 4554520Snw141292 free(*ad); 4564520Snw141292 4574520Snw141292 *ad = NULL; 4584520Snw141292 } 4594520Snw141292 4605317Sjp151216 4614520Snw141292 static 4624520Snw141292 int 4635968Snw141292 idmap_open_conn(ad_host_t *adh, int timeoutsecs) 4644520Snw141292 { 4655317Sjp151216 int zero = 0; 4665317Sjp151216 int ldversion, rc; 4675968Snw141292 int timeoutms = timeoutsecs * 1000; 4685317Sjp151216 4695317Sjp151216 if (adh == NULL) 4705317Sjp151216 return (0); 4714520Snw141292 4725317Sjp151216 (void) pthread_mutex_lock(&adh->lock); 4735317Sjp151216 4745317Sjp151216 if (!adh->dead && adh->ld != NULL) 4755317Sjp151216 /* done! */ 4765317Sjp151216 goto out; 4775317Sjp151216 4785317Sjp151216 if (adh->ld != NULL) { 4794520Snw141292 (void) ldap_unbind(adh->ld); 4804520Snw141292 adh->ld = NULL; 4814520Snw141292 } 4826531Sjp151216 adh->num_requests = 0; 4834520Snw141292 4845317Sjp151216 atomic_inc_64(&adh->generation); 4854520Snw141292 4865317Sjp151216 /* Open and bind an LDAP connection */ 4875317Sjp151216 adh->ld = ldap_init(adh->host, adh->port); 4885317Sjp151216 if (adh->ld == NULL) { 4895317Sjp151216 idmapdlog(LOG_INFO, "ldap_init() to server " 4905317Sjp151216 "%s port %d failed. (%s)", adh->host, 4915317Sjp151216 adh->port, strerror(errno)); 4925317Sjp151216 goto out; 4935317Sjp151216 } 4945317Sjp151216 ldversion = LDAP_VERSION3; 4955317Sjp151216 (void) ldap_set_option(adh->ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion); 4965317Sjp151216 (void) ldap_set_option(adh->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF); 4975317Sjp151216 (void) ldap_set_option(adh->ld, LDAP_OPT_TIMELIMIT, &zero); 4985317Sjp151216 (void) ldap_set_option(adh->ld, LDAP_OPT_SIZELIMIT, &zero); 4995317Sjp151216 (void) ldap_set_option(adh->ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms); 5005317Sjp151216 (void) ldap_set_option(adh->ld, LDAP_OPT_RESTART, LDAP_OPT_ON); 5015317Sjp151216 rc = ldap_sasl_interactive_bind_s(adh->ld, "" /* binddn */, 5025317Sjp151216 adh->saslmech, NULL, NULL, adh->saslflags, &idmap_saslcallback, 5035317Sjp151216 NULL); 5044520Snw141292 5055317Sjp151216 if (rc != LDAP_SUCCESS) { 5065317Sjp151216 (void) ldap_unbind(adh->ld); 5075317Sjp151216 adh->ld = NULL; 5085317Sjp151216 idmapdlog(LOG_INFO, "ldap_sasl_interactive_bind_s() to server " 5095317Sjp151216 "%s port %d failed. (%s)", adh->host, adh->port, 5105317Sjp151216 ldap_err2string(rc)); 5114520Snw141292 } 5124520Snw141292 5135317Sjp151216 idmapdlog(LOG_DEBUG, "Using global catalog server %s:%d", 5145317Sjp151216 adh->host, adh->port); 5154520Snw141292 5165317Sjp151216 out: 5175317Sjp151216 if (adh->ld != NULL) { 5185317Sjp151216 atomic_inc_32(&adh->ref); 5195317Sjp151216 adh->idletime = time(NULL); 5205317Sjp151216 adh->dead = 0; 5215317Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 5225317Sjp151216 return (1); 5235317Sjp151216 } 5245317Sjp151216 5255317Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 5265317Sjp151216 return (0); 5274520Snw141292 } 5284520Snw141292 5294520Snw141292 5304520Snw141292 /* 5314520Snw141292 * Connection management: find an open connection or open one 5324520Snw141292 */ 5334520Snw141292 static 5344520Snw141292 ad_host_t * 5355317Sjp151216 idmap_get_conn(ad_t *ad) 5364520Snw141292 { 5374520Snw141292 ad_host_t *adh = NULL; 5385968Snw141292 int tries; 5395968Snw141292 int dscount = 0; 5405968Snw141292 int timeoutsecs = IDMAPD_LDAP_OPEN_TIMEOUT; 5414520Snw141292 5425317Sjp151216 retry: 5434520Snw141292 (void) pthread_mutex_lock(&adhostlock); 5444520Snw141292 5455968Snw141292 if (host_head == NULL) { 5465968Snw141292 (void) pthread_mutex_unlock(&adhostlock); 5475317Sjp151216 goto out; 5485968Snw141292 } 5495317Sjp151216 5505968Snw141292 if (dscount == 0) { 5515968Snw141292 /* 5525968Snw141292 * First try: count the number of DSes. 5535968Snw141292 * 5545968Snw141292 * Integer overflow is not an issue -- we can't have so many 5555968Snw141292 * DSes because they won't fit even DNS over TCP, and SMF 5565968Snw141292 * shouldn't let you set so many. 5575968Snw141292 */ 5585968Snw141292 for (adh = host_head, tries = 0; adh != NULL; adh = adh->next) { 5595968Snw141292 if (adh->owner == ad) 5605968Snw141292 dscount++; 5615968Snw141292 } 5625968Snw141292 5635968Snw141292 if (dscount == 0) { 5645968Snw141292 (void) pthread_mutex_unlock(&adhostlock); 5655968Snw141292 goto out; 5665968Snw141292 } 5675968Snw141292 5685968Snw141292 tries = dscount * 3; /* three tries per-ds */ 5695968Snw141292 5705968Snw141292 /* 5715968Snw141292 * Begin round-robin at the next DS in the list after the last 5725968Snw141292 * one that we had a connection to, else start with the first 5735968Snw141292 * DS in the list. 5745968Snw141292 */ 5755968Snw141292 adh = ad->last_adh; 5764520Snw141292 } 5774520Snw141292 5785317Sjp151216 /* 5795968Snw141292 * Round-robin -- pick the next one on the list; if the list 5805968Snw141292 * changes on us, no big deal, we'll just potentially go 5815968Snw141292 * around the wrong number of times. 5825317Sjp151216 */ 5835968Snw141292 for (;;) { 5846017Snw141292 if (adh != NULL && adh->ld != NULL && !adh->dead) 5856017Snw141292 break; 5865968Snw141292 if (adh == NULL || (adh = adh->next) == NULL) 5875968Snw141292 adh = host_head; 5885968Snw141292 if (adh->owner == ad) 5895317Sjp151216 break; 5905317Sjp151216 } 5915317Sjp151216 5925968Snw141292 ad->last_adh = adh; 5935968Snw141292 (void) pthread_mutex_unlock(&adhostlock); 5945968Snw141292 5955968Snw141292 5965968Snw141292 /* Found suitable DS, open it if not already opened */ 5975968Snw141292 if (idmap_open_conn(adh, timeoutsecs)) 5985968Snw141292 return (adh); 5995317Sjp151216 6005968Snw141292 tries--; 6015968Snw141292 6025968Snw141292 if ((tries % dscount) == 0) 6035968Snw141292 timeoutsecs *= 2; 6045968Snw141292 6055968Snw141292 if (tries > 0) 6065968Snw141292 goto retry; 6074520Snw141292 6085317Sjp151216 out: 6095968Snw141292 idmapdlog(LOG_NOTICE, "Couldn't open an LDAP connection to any global " 6105317Sjp151216 "catalog server!"); 6115317Sjp151216 6125317Sjp151216 return (NULL); 6134520Snw141292 } 6144520Snw141292 6154520Snw141292 static 6164520Snw141292 void 6174520Snw141292 idmap_release_conn(ad_host_t *adh) 6184520Snw141292 { 6194520Snw141292 (void) pthread_mutex_lock(&adh->lock); 6204520Snw141292 if (atomic_dec_32_nv(&adh->ref) == 0) 6214520Snw141292 adh->idletime = time(NULL); 6224520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 6234520Snw141292 } 6244520Snw141292 6254520Snw141292 /* 6264520Snw141292 * Take ad_host_config_t information, create a ad_host_t, 6274520Snw141292 * populate it and add it to the list of hosts. 6284520Snw141292 */ 6294520Snw141292 6304520Snw141292 int 6314520Snw141292 idmap_add_ds(ad_t *ad, const char *host, int port) 6324520Snw141292 { 6334520Snw141292 ad_host_t *p; 6344520Snw141292 ad_host_t *new = NULL; 6354520Snw141292 int ret = -1; 6364520Snw141292 6374520Snw141292 if (port == 0) 6384520Snw141292 port = (int)ad->partition; 6394520Snw141292 6404520Snw141292 (void) pthread_mutex_lock(&adhostlock); 6414520Snw141292 for (p = host_head; p != NULL; p = p->next) { 6424520Snw141292 if (p->owner != ad) 6434520Snw141292 continue; 6444520Snw141292 6454520Snw141292 if (strcmp(host, p->host) == 0 && p->port == port) { 6464520Snw141292 /* already added */ 6475317Sjp151216 ret = 0; 6484520Snw141292 goto err; 6494520Snw141292 } 6504520Snw141292 } 6514520Snw141292 6524520Snw141292 /* add new entry */ 6534520Snw141292 new = (ad_host_t *)calloc(1, sizeof (ad_host_t)); 6544520Snw141292 if (new == NULL) 6554520Snw141292 goto err; 6564520Snw141292 new->owner = ad; 6574520Snw141292 new->port = port; 6584520Snw141292 new->dead = 0; 6596531Sjp151216 new->max_requests = 80; 6606531Sjp151216 new->num_requests = 0; 6614520Snw141292 if ((new->host = strdup(host)) == NULL) 6624520Snw141292 goto err; 6634520Snw141292 6644520Snw141292 /* default to SASL GSSAPI only for now */ 6654520Snw141292 new->saslflags = LDAP_SASL_INTERACTIVE; 6664520Snw141292 new->saslmech = "GSSAPI"; 6674520Snw141292 6684520Snw141292 if ((ret = pthread_mutex_init(&new->lock, NULL)) != 0) { 6694520Snw141292 free(new->host); 6704520Snw141292 new->host = NULL; 6714520Snw141292 errno = ret; 6724520Snw141292 ret = -1; 6734520Snw141292 goto err; 6744520Snw141292 } 6754520Snw141292 6764520Snw141292 /* link in */ 6774520Snw141292 new->next = host_head; 6784520Snw141292 host_head = new; 6794520Snw141292 6804520Snw141292 /* Start reaper if it doesn't exist */ 6814520Snw141292 if (reaperid == 0) 6824520Snw141292 (void) pthread_create(&reaperid, NULL, 6834520Snw141292 (void *(*)(void *))adreaper, (void *)NULL); 6844520Snw141292 6854520Snw141292 err: 6864520Snw141292 (void) pthread_mutex_unlock(&adhostlock); 6874520Snw141292 6884520Snw141292 if (ret != 0 && new != NULL) { 6894520Snw141292 if (new->host != NULL) { 6904520Snw141292 (void) pthread_mutex_destroy(&new->lock); 6914520Snw141292 free(new->host); 6924520Snw141292 } 6934520Snw141292 free(new); 6944520Snw141292 } 6954520Snw141292 6964520Snw141292 return (ret); 6974520Snw141292 } 6984520Snw141292 6994520Snw141292 /* 7005317Sjp151216 * Free a DS configuration. 7015317Sjp151216 * Caller must lock the adhostlock mutex 7024520Snw141292 */ 7035317Sjp151216 static void 7045317Sjp151216 delete_ds(ad_t *ad, const char *host, int port) 7054520Snw141292 { 7064520Snw141292 ad_host_t **p, *q; 7074520Snw141292 7084520Snw141292 for (p = &host_head; *p != NULL; p = &((*p)->next)) { 7094520Snw141292 if ((*p)->owner != ad || strcmp(host, (*p)->host) != 0 || 7104520Snw141292 (*p)->port != port) 7114520Snw141292 continue; 7124520Snw141292 /* found */ 7135317Sjp151216 if ((*p)->ref > 0) 7144520Snw141292 break; /* still in use */ 7154520Snw141292 7164520Snw141292 q = *p; 7174520Snw141292 *p = (*p)->next; 7184520Snw141292 7194520Snw141292 (void) pthread_mutex_destroy(&q->lock); 7204520Snw141292 7214520Snw141292 if (q->ld) 7224520Snw141292 (void) ldap_unbind(q->ld); 7234520Snw141292 if (q->host) 7244520Snw141292 free(q->host); 7254520Snw141292 free(q); 7264520Snw141292 break; 7274520Snw141292 } 7285317Sjp151216 7294520Snw141292 } 7304520Snw141292 7315317Sjp151216 7324520Snw141292 /* 7334520Snw141292 * Convert a binary SID in a BerValue to a sid_t 7344520Snw141292 */ 7354520Snw141292 static 7364520Snw141292 int 7374520Snw141292 idmap_getsid(BerValue *bval, sid_t *sidp) 7384520Snw141292 { 7394520Snw141292 int i, j; 7404520Snw141292 uchar_t *v; 7414520Snw141292 uint32_t a; 7424520Snw141292 7434520Snw141292 /* 7444520Snw141292 * The binary format of a SID is as follows: 7454520Snw141292 * 7464520Snw141292 * byte #0: version, always 0x01 7474520Snw141292 * byte #1: RID count, always <= 0x0f 7484520Snw141292 * bytes #2-#7: SID authority, big-endian 48-bit unsigned int 7494520Snw141292 * 7504520Snw141292 * followed by RID count RIDs, each a little-endian, unsigned 7514520Snw141292 * 32-bit int. 7524520Snw141292 */ 7534520Snw141292 /* 7544520Snw141292 * Sanity checks: must have at least one RID, version must be 7554520Snw141292 * 0x01, and the length must be 8 + rid count * 4 7564520Snw141292 */ 7574520Snw141292 if (bval->bv_len > 8 && bval->bv_val[0] == 0x01 && 7584520Snw141292 bval->bv_len == 1 + 1 + 6 + bval->bv_val[1] * 4) { 7594520Snw141292 v = (uchar_t *)bval->bv_val; 7604520Snw141292 sidp->version = v[0]; 7614520Snw141292 sidp->sub_authority_count = v[1]; 7624520Snw141292 sidp->authority = 7634520Snw141292 /* big endian -- so start from the left */ 7644520Snw141292 ((u_longlong_t)v[2] << 40) | 7654520Snw141292 ((u_longlong_t)v[3] << 32) | 7664520Snw141292 ((u_longlong_t)v[4] << 24) | 7674520Snw141292 ((u_longlong_t)v[5] << 16) | 7684520Snw141292 ((u_longlong_t)v[6] << 8) | 7694520Snw141292 (u_longlong_t)v[7]; 7704520Snw141292 for (i = 0; i < sidp->sub_authority_count; i++) { 7714520Snw141292 j = 8 + (i * 4); 7724520Snw141292 /* little endian -- so start from the right */ 7734520Snw141292 a = (v[j + 3] << 24) | (v[j + 2] << 16) | 7744520Snw141292 (v[j + 1] << 8) | (v[j]); 7754520Snw141292 sidp->sub_authorities[i] = a; 7764520Snw141292 } 7774520Snw141292 return (0); 7784520Snw141292 } 7794520Snw141292 return (-1); 7804520Snw141292 } 7814520Snw141292 7824520Snw141292 /* 7834520Snw141292 * Convert a sid_t to S-1-... 7844520Snw141292 */ 7854520Snw141292 static 7864520Snw141292 char * 7874520Snw141292 idmap_sid2txt(sid_t *sidp) 7884520Snw141292 { 7894520Snw141292 int rlen, i, len; 7904520Snw141292 char *str, *cp; 7914520Snw141292 7924520Snw141292 if (sidp->version != 1) 7934520Snw141292 return (NULL); 7944520Snw141292 7954520Snw141292 len = sizeof ("S-1-") - 1; 7964520Snw141292 7974520Snw141292 /* 7984520Snw141292 * We could optimize like so, but, why? 7994520Snw141292 * if (sidp->authority < 10) 8004520Snw141292 * len += 2; 8014520Snw141292 * else if (sidp->authority < 100) 8024520Snw141292 * len += 3; 8034520Snw141292 * else 8044520Snw141292 * len += snprintf(NULL, 0"%llu", sidp->authority); 8054520Snw141292 */ 8064520Snw141292 len += snprintf(NULL, 0, "%llu", sidp->authority); 8074520Snw141292 8084520Snw141292 /* Max length of a uint32_t printed out in ASCII is 10 bytes */ 8094520Snw141292 len += 1 + (sidp->sub_authority_count + 1) * 10; 8104520Snw141292 8114520Snw141292 if ((cp = str = malloc(len)) == NULL) 8124520Snw141292 return (NULL); 8134520Snw141292 8144520Snw141292 rlen = snprintf(str, len, "S-1-%llu", sidp->authority); 8154520Snw141292 8164520Snw141292 cp += rlen; 8174520Snw141292 len -= rlen; 8184520Snw141292 8194520Snw141292 for (i = 0; i < sidp->sub_authority_count; i++) { 8204520Snw141292 assert(len > 0); 8214520Snw141292 rlen = snprintf(cp, len, "-%u", sidp->sub_authorities[i]); 8224520Snw141292 cp += rlen; 8234520Snw141292 len -= rlen; 8244520Snw141292 assert(len >= 0); 8254520Snw141292 } 8264520Snw141292 8274520Snw141292 return (str); 8284520Snw141292 } 8294520Snw141292 8304520Snw141292 /* 8314520Snw141292 * Convert a sid_t to on-the-wire encoding 8324520Snw141292 */ 8334520Snw141292 static 8344520Snw141292 int 8354520Snw141292 idmap_sid2binsid(sid_t *sid, uchar_t *binsid, int binsidlen) 8364520Snw141292 { 8374520Snw141292 uchar_t *p; 8384520Snw141292 int i; 8394520Snw141292 uint64_t a; 8404520Snw141292 uint32_t r; 8414520Snw141292 8424520Snw141292 if (sid->version != 1 || 8434520Snw141292 binsidlen != (1 + 1 + 6 + sid->sub_authority_count * 4)) 8444520Snw141292 return (-1); 8454520Snw141292 8464520Snw141292 p = binsid; 8474520Snw141292 *p++ = 0x01; /* version */ 8484520Snw141292 /* sub authority count */ 8494520Snw141292 *p++ = sid->sub_authority_count; 8504520Snw141292 /* Authority */ 8514520Snw141292 a = sid->authority; 8524520Snw141292 /* big-endian -- start from left */ 8534520Snw141292 *p++ = (a >> 40) & 0xFF; 8544520Snw141292 *p++ = (a >> 32) & 0xFF; 8554520Snw141292 *p++ = (a >> 24) & 0xFF; 8564520Snw141292 *p++ = (a >> 16) & 0xFF; 8574520Snw141292 *p++ = (a >> 8) & 0xFF; 8584520Snw141292 *p++ = a & 0xFF; 8594520Snw141292 8604520Snw141292 /* sub-authorities */ 8614520Snw141292 for (i = 0; i < sid->sub_authority_count; i++) { 8624520Snw141292 r = sid->sub_authorities[i]; 8634520Snw141292 /* little-endian -- start from right */ 8644520Snw141292 *p++ = (r & 0x000000FF); 8654520Snw141292 *p++ = (r & 0x0000FF00) >> 8; 8664520Snw141292 *p++ = (r & 0x00FF0000) >> 16; 8674520Snw141292 *p++ = (r & 0xFF000000) >> 24; 8684520Snw141292 } 8694520Snw141292 8704520Snw141292 return (0); 8714520Snw141292 } 8724520Snw141292 8734520Snw141292 /* 8744520Snw141292 * Convert a stringified SID (S-1-...) into a hex-encoded version of the 8754520Snw141292 * on-the-wire encoding, but with each pair of hex digits pre-pended 8764520Snw141292 * with a '\', so we can pass this to libldap. 8774520Snw141292 */ 8784520Snw141292 static 8794520Snw141292 int 8804520Snw141292 idmap_txtsid2hexbinsid(const char *txt, const rid_t *rid, 8814520Snw141292 char *hexbinsid, int hexbinsidlen) 8824520Snw141292 { 8834520Snw141292 sid_t sid = { 0 }; 8844520Snw141292 int i, j; 8854520Snw141292 const char *cp; 8864520Snw141292 char *ecp; 8874520Snw141292 u_longlong_t a; 8884520Snw141292 unsigned long r; 8894520Snw141292 uchar_t *binsid, b, hb; 8904520Snw141292 8914520Snw141292 /* Only version 1 SIDs please */ 8924520Snw141292 if (strncmp(txt, "S-1-", strlen("S-1-")) != 0) 8934520Snw141292 return (-1); 8944520Snw141292 8954520Snw141292 if (strlen(txt) < (strlen("S-1-") + 1)) 8964520Snw141292 return (-1); 8974520Snw141292 8984520Snw141292 /* count '-'s */ 8994520Snw141292 for (j = 0, cp = strchr(txt, '-'); 9004520Snw141292 cp != NULL && *cp != '\0'; 9014520Snw141292 j++, cp = strchr(cp + 1, '-')) { 9024520Snw141292 /* can't end on a '-' */ 9034520Snw141292 if (*(cp + 1) == '\0') 9044520Snw141292 return (-1); 9054520Snw141292 } 9064520Snw141292 9074864Sbaban /* Adjust count for version and authority */ 9084864Sbaban j -= 2; 9094864Sbaban 9104864Sbaban /* we know the version number and RID count */ 9114864Sbaban sid.version = 1; 9124864Sbaban sid.sub_authority_count = (rid != NULL) ? j + 1 : j; 9134864Sbaban 9144520Snw141292 /* must have at least one RID, but not too many */ 9154864Sbaban if (sid.sub_authority_count < 1 || 9164864Sbaban sid.sub_authority_count > SID_MAX_SUB_AUTHORITIES) 9174520Snw141292 return (-1); 9184520Snw141292 9194520Snw141292 /* check that we only have digits and '-' */ 9204520Snw141292 if (strspn(txt + 1, "0123456789-") < (strlen(txt) - 1)) 9214520Snw141292 return (-1); 9224520Snw141292 9234520Snw141292 cp = txt + strlen("S-1-"); 9244520Snw141292 9254520Snw141292 /* 64-bit safe parsing of unsigned 48-bit authority value */ 9264520Snw141292 errno = 0; 9274520Snw141292 a = strtoull(cp, &ecp, 10); 9284520Snw141292 9294520Snw141292 /* errors parsing the authority or too many bits */ 9304520Snw141292 if (cp == ecp || (a == 0 && errno == EINVAL) || 9314520Snw141292 (a == ULLONG_MAX && errno == ERANGE) || 9324520Snw141292 (a & 0x0000ffffffffffffULL) != a) 9334520Snw141292 return (-1); 9344520Snw141292 9354520Snw141292 cp = ecp; 9364520Snw141292 9374520Snw141292 sid.authority = (uint64_t)a; 9384520Snw141292 9394864Sbaban for (i = 0; i < j; i++) { 9404520Snw141292 if (*cp++ != '-') 9414520Snw141292 return (-1); 9424520Snw141292 /* 64-bit safe parsing of unsigned 32-bit RID */ 9434520Snw141292 errno = 0; 9444520Snw141292 r = strtoul(cp, &ecp, 10); 9454520Snw141292 /* errors parsing the RID or too many bits */ 9464520Snw141292 if (cp == ecp || (r == 0 && errno == EINVAL) || 9474520Snw141292 (r == ULONG_MAX && errno == ERANGE) || 9484520Snw141292 (r & 0xffffffffUL) != r) 9494520Snw141292 return (-1); 9504520Snw141292 sid.sub_authorities[i] = (uint32_t)r; 9514520Snw141292 cp = ecp; 9524520Snw141292 } 9534520Snw141292 9544520Snw141292 /* check that all of the string SID has been consumed */ 9554520Snw141292 if (*cp != '\0') 9564520Snw141292 return (-1); 9574520Snw141292 9584864Sbaban if (rid != NULL) 9594864Sbaban sid.sub_authorities[j] = *rid; 9604520Snw141292 9614520Snw141292 j = 1 + 1 + 6 + sid.sub_authority_count * 4; 9624520Snw141292 9634520Snw141292 if (hexbinsidlen < (j * 3)) 9644520Snw141292 return (-2); 9654520Snw141292 9664520Snw141292 /* binary encode the SID */ 9674520Snw141292 binsid = (uchar_t *)alloca(j); 9684520Snw141292 (void) idmap_sid2binsid(&sid, binsid, j); 9694520Snw141292 9704520Snw141292 /* hex encode, with a backslash before each byte */ 9714520Snw141292 for (ecp = hexbinsid, i = 0; i < j; i++) { 9724520Snw141292 b = binsid[i]; 9734520Snw141292 *ecp++ = '\\'; 9744520Snw141292 hb = (b >> 4) & 0xF; 9754520Snw141292 *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 9764520Snw141292 hb = b & 0xF; 9774520Snw141292 *ecp++ = (hb <= 0x9 ? hb + '0' : hb - 10 + 'A'); 9784520Snw141292 } 9794520Snw141292 *ecp = '\0'; 9804520Snw141292 9814520Snw141292 return (0); 9824520Snw141292 } 9834520Snw141292 9844520Snw141292 static 9854520Snw141292 char * 9864520Snw141292 convert_bval2sid(BerValue *bval, rid_t *rid) 9874520Snw141292 { 9884520Snw141292 sid_t sid; 9894520Snw141292 9904520Snw141292 if (idmap_getsid(bval, &sid) < 0) 9914520Snw141292 return (NULL); 9924520Snw141292 9934520Snw141292 /* 9944520Snw141292 * If desired and if the SID is what should be a domain/computer 9954520Snw141292 * user or group SID (i.e., S-1-5-w-x-y-z-<user/group RID>) then 9964520Snw141292 * save the last RID and truncate the SID 9974520Snw141292 */ 9984520Snw141292 if (rid != NULL && sid.authority == 5 && sid.sub_authority_count == 5) 9994520Snw141292 *rid = sid.sub_authorities[--sid.sub_authority_count]; 10004520Snw141292 return (idmap_sid2txt(&sid)); 10014520Snw141292 } 10024520Snw141292 10034520Snw141292 10044520Snw141292 idmap_retcode 10054520Snw141292 idmap_lookup_batch_start(ad_t *ad, int nqueries, idmap_query_state_t **state) 10064520Snw141292 { 10074520Snw141292 idmap_query_state_t *new_state; 10084520Snw141292 ad_host_t *adh = NULL; 10094520Snw141292 10104520Snw141292 *state = NULL; 10114520Snw141292 10126097Snw141292 if (ad == NULL) 10135731Sbaban return (IDMAP_ERR_INTERNAL); 10144520Snw141292 10154520Snw141292 adh = idmap_get_conn(ad); 10164520Snw141292 if (adh == NULL) 10175968Snw141292 return (IDMAP_ERR_RETRIABLE_NET_ERR); 10184520Snw141292 10194520Snw141292 new_state = calloc(1, sizeof (idmap_query_state_t) + 10204520Snw141292 (nqueries - 1) * sizeof (idmap_q_t)); 10214520Snw141292 10224520Snw141292 if (new_state == NULL) 10234520Snw141292 return (IDMAP_ERR_MEMORY); 10244520Snw141292 10254884Sjp151216 new_state->ref_cnt = 1; 10264520Snw141292 new_state->qadh = adh; 10274520Snw141292 new_state->qcount = nqueries; 10284520Snw141292 new_state->qadh_gen = adh->generation; 10294520Snw141292 /* should be -1, but the atomic routines want unsigned */ 10304520Snw141292 new_state->qlastsent = 0; 10314884Sjp151216 (void) pthread_cond_init(&new_state->cv, NULL); 10324520Snw141292 10334520Snw141292 (void) pthread_mutex_lock(&qstatelock); 10344520Snw141292 new_state->next = qstatehead; 10354520Snw141292 qstatehead = new_state; 10364520Snw141292 (void) pthread_mutex_unlock(&qstatelock); 10374520Snw141292 10384520Snw141292 *state = new_state; 10394520Snw141292 10404520Snw141292 return (IDMAP_SUCCESS); 10414520Snw141292 } 10424520Snw141292 10434520Snw141292 /* 10445731Sbaban * Set unixuser_attr and unixgroup_attr for AD-based name mapping 10455731Sbaban */ 10465731Sbaban void 10475731Sbaban idmap_lookup_batch_set_unixattr(idmap_query_state_t *state, 10485908Sjp151216 const char *unixuser_attr, const char *unixgroup_attr) 10495908Sjp151216 { 10505731Sbaban state->ad_unixuser_attr = unixuser_attr; 10515731Sbaban state->ad_unixgroup_attr = unixgroup_attr; 10525731Sbaban } 10535731Sbaban 10545731Sbaban /* 10554520Snw141292 * Find the idmap_query_state_t to which a given LDAP result msgid on a 10564884Sjp151216 * given connection belongs. This routine increaments the reference count 10574884Sjp151216 * so that the object can not be freed. idmap_lookup_unlock_batch() 10584884Sjp151216 * must be called to decreament the reference count. 10594520Snw141292 */ 10604520Snw141292 static 10614520Snw141292 int 10624520Snw141292 idmap_msgid2query(ad_host_t *adh, int msgid, 10634520Snw141292 idmap_query_state_t **state, int *qid) 10644520Snw141292 { 10656531Sjp151216 idmap_query_state_t *p; 10666531Sjp151216 int i; 10676531Sjp151216 int ret; 10684520Snw141292 10694520Snw141292 (void) pthread_mutex_lock(&qstatelock); 10704520Snw141292 for (p = qstatehead; p != NULL; p = p->next) { 10714520Snw141292 if (p->qadh != adh || adh->generation != p->qadh_gen) 10724520Snw141292 continue; 10734520Snw141292 for (i = 0; i < p->qcount; i++) { 10744520Snw141292 if ((p->queries[i]).msgid == msgid) { 10756531Sjp151216 if (!p->qdead) { 10766531Sjp151216 p->ref_cnt++; 10776531Sjp151216 *state = p; 10786531Sjp151216 *qid = i; 10796531Sjp151216 ret = 1; 10806531Sjp151216 } else 10816531Sjp151216 ret = 0; 10824520Snw141292 (void) pthread_mutex_unlock(&qstatelock); 10836531Sjp151216 return (ret); 10844520Snw141292 } 10854520Snw141292 } 10864520Snw141292 } 10874520Snw141292 (void) pthread_mutex_unlock(&qstatelock); 10884520Snw141292 return (0); 10894520Snw141292 } 10904520Snw141292 10914520Snw141292 /* 10926531Sjp151216 * Put the the search result onto the correct idmap_q_t given the LDAP result 10936531Sjp151216 * msgid 10946531Sjp151216 * Returns: 0 success 10956531Sjp151216 * -1 already has a search result 10966531Sjp151216 * -2 cant find message id 10976531Sjp151216 */ 10986531Sjp151216 static 10996531Sjp151216 int 11006531Sjp151216 idmap_quesearchresbymsgid(ad_host_t *adh, int msgid, LDAPMessage *search_res) 11016531Sjp151216 { 11026531Sjp151216 idmap_query_state_t *p; 11036531Sjp151216 int i; 11046531Sjp151216 int res; 11056531Sjp151216 11066531Sjp151216 (void) pthread_mutex_lock(&qstatelock); 11076531Sjp151216 for (p = qstatehead; p != NULL; p = p->next) { 11086531Sjp151216 if (p->qadh != adh || adh->generation != p->qadh_gen) 11096531Sjp151216 continue; 11106531Sjp151216 for (i = 0; i < p->qcount; i++) { 11116531Sjp151216 if ((p->queries[i]).msgid == msgid) { 11126531Sjp151216 if (p->queries[i].search_res == NULL) { 11136531Sjp151216 if (!p->qdead) { 11146531Sjp151216 p->queries[i].search_res = 11156531Sjp151216 search_res; 11166531Sjp151216 res = 0; 11176531Sjp151216 } else 11186531Sjp151216 res = -2; 11196531Sjp151216 } else 11206531Sjp151216 res = -1; 11216531Sjp151216 (void) pthread_mutex_unlock(&qstatelock); 11226531Sjp151216 return (res); 11236531Sjp151216 } 11246531Sjp151216 } 11256531Sjp151216 } 11266531Sjp151216 (void) pthread_mutex_unlock(&qstatelock); 11276531Sjp151216 return (-2); 11286531Sjp151216 } 11296531Sjp151216 11306531Sjp151216 11316531Sjp151216 /* 11325696Snw141292 * Take parsed attribute values from a search result entry and check if 11335696Snw141292 * it is the result that was desired and, if so, set the result fields 11345696Snw141292 * of the given idmap_q_t. 11355696Snw141292 * 11365731Sbaban * Frees the unused char * values. 11374520Snw141292 */ 11384520Snw141292 static 11395696Snw141292 void 11406386Sjp151216 idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr, 11416386Sjp151216 char *sid, rid_t rid, int sid_type, char *unixname) 11424520Snw141292 { 11435696Snw141292 char *domain; 11445731Sbaban int err1, err2; 11455696Snw141292 11465696Snw141292 assert(dn != NULL); 11475696Snw141292 11485696Snw141292 if ((domain = dn2dns(dn)) == NULL) 11495696Snw141292 goto out; 11505696Snw141292 11515731Sbaban if (q->ecanonname != NULL && san != NULL) { 11525731Sbaban /* Check that this is the canonname that we were looking for */ 11535696Snw141292 if (u8_strcmp(q->ecanonname, san, 0, 11545696Snw141292 U8_STRCMP_CI_LOWER, /* no normalization, for now */ 11555731Sbaban U8_UNICODE_LATEST, &err1) != 0 || err1 != 0) 11565731Sbaban goto out; 11575731Sbaban } 11585731Sbaban 11595731Sbaban if (q->edomain != NULL) { 11605731Sbaban /* Check that this is the domain that we were looking for */ 11615731Sbaban if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER, 11625696Snw141292 U8_UNICODE_LATEST, &err2) != 0 || err2 != 0) 11635696Snw141292 goto out; 11645696Snw141292 } 11655696Snw141292 11666386Sjp151216 /* Copy the DN and attr and value */ 11676386Sjp151216 if (q->dn != NULL) 11686386Sjp151216 *q->dn = strdup(dn); 11696386Sjp151216 11706386Sjp151216 if (q->attr != NULL && attr != NULL) 11716386Sjp151216 *q->attr = strdup(attr); 11726386Sjp151216 11736386Sjp151216 if (q->value != NULL && unixname != NULL) 11746386Sjp151216 *q->value = strdup(unixname); 11756386Sjp151216 11765731Sbaban /* Set results */ 11775731Sbaban if (q->sid) { 11785731Sbaban *q->sid = sid; 11795731Sbaban sid = NULL; 11805731Sbaban } 11815731Sbaban if (q->rid) 11825731Sbaban *q->rid = rid; 11835731Sbaban if (q->sid_type) 11845731Sbaban *q->sid_type = sid_type; 11855731Sbaban if (q->unixname) { 11865731Sbaban *q->unixname = unixname; 11875731Sbaban unixname = NULL; 11885731Sbaban } 11895731Sbaban if (q->domain != NULL) { 11905731Sbaban *q->domain = domain; 11915731Sbaban domain = NULL; 11925731Sbaban } 11935731Sbaban if (q->canonname != NULL) { 1194*6616Sdm199847 /* 1195*6616Sdm199847 * The caller may be replacing the given winname by its 1196*6616Sdm199847 * canonical name and therefore free any old name before 1197*6616Sdm199847 * overwriting the field by the canonical name. 1198*6616Sdm199847 */ 1199*6616Sdm199847 free(*q->canonname); 12005731Sbaban *q->canonname = san; 12015731Sbaban san = NULL; 12025731Sbaban } 12035731Sbaban 12045731Sbaban /* Always have q->rc; idmap_extract_object() asserts this */ 12055696Snw141292 *q->rc = IDMAP_SUCCESS; 12065696Snw141292 12075696Snw141292 out: 12085696Snw141292 /* Free unused attribute values */ 12095696Snw141292 free(san); 12105696Snw141292 free(sid); 12115696Snw141292 free(domain); 12125731Sbaban free(unixname); 12134520Snw141292 } 12144520Snw141292 12154520Snw141292 /* 12165696Snw141292 * The following three functions extract objectSid, sAMAccountName and 12175696Snw141292 * objectClass attribute values and, in the case of objectSid and 12185696Snw141292 * objectClass, parse them. 12195696Snw141292 * 12205696Snw141292 * idmap_setqresults() takes care of dealing with the result entry's DN. 12215696Snw141292 */ 12225696Snw141292 12235696Snw141292 /* 12245696Snw141292 * Return a NUL-terminated stringified SID from the value of an 12255696Snw141292 * objectSid attribute and put the last RID in *rid. 12264520Snw141292 */ 12274520Snw141292 static 12285696Snw141292 char * 12295696Snw141292 idmap_bv_objsid2sidstr(BerValue **bvalues, rid_t *rid) 12304520Snw141292 { 12315696Snw141292 char *sid; 12325696Snw141292 12335696Snw141292 if (bvalues == NULL) 12345696Snw141292 return (NULL); 12355696Snw141292 /* objectSid is single valued */ 12365696Snw141292 if ((sid = convert_bval2sid(bvalues[0], rid)) == NULL) 12375696Snw141292 return (NULL); 12385696Snw141292 return (sid); 12395696Snw141292 } 12405696Snw141292 12415696Snw141292 /* 12425696Snw141292 * Return a NUL-terminated string from the value of a sAMAccountName 12435731Sbaban * or unixname attribute. 12445696Snw141292 */ 12455696Snw141292 static 12465696Snw141292 char * 12475731Sbaban idmap_bv_name2str(BerValue **bvalues) 12485696Snw141292 { 12495696Snw141292 char *s; 12504520Snw141292 12514520Snw141292 if (bvalues == NULL || bvalues[0] == NULL || 12524520Snw141292 bvalues[0]->bv_val == NULL) 12535696Snw141292 return (NULL); 12545447Snw141292 12555696Snw141292 if ((s = malloc(bvalues[0]->bv_len + 1)) == NULL) 12565696Snw141292 return (NULL); 12575447Snw141292 12585696Snw141292 (void) snprintf(s, bvalues[0]->bv_len + 1, "%.*s", bvalues[0]->bv_len, 12595696Snw141292 bvalues[0]->bv_val); 12604520Snw141292 12615696Snw141292 return (s); 12624520Snw141292 } 12634520Snw141292 12644520Snw141292 12654520Snw141292 #define BVAL_CASEEQ(bv, str) \ 12664520Snw141292 (((*(bv))->bv_len == (sizeof (str) - 1)) && \ 12674520Snw141292 strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0) 12684520Snw141292 12694520Snw141292 /* 12705696Snw141292 * Extract the class of the result entry. Returns 1 on success, 0 on 12715696Snw141292 * failure. 12724520Snw141292 */ 12734520Snw141292 static 12745447Snw141292 int 12755696Snw141292 idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type) 12764520Snw141292 { 12774520Snw141292 BerValue **cbval; 12784520Snw141292 12795696Snw141292 *sid_type = _IDMAP_T_OTHER; 12804520Snw141292 if (bvalues == NULL) 12815447Snw141292 return (0); 12824520Snw141292 12835696Snw141292 /* 12845696Snw141292 * We iterate over all the values because computer is a 12855696Snw141292 * sub-class of user. 12865696Snw141292 */ 12874520Snw141292 for (cbval = bvalues; *cbval != NULL; cbval++) { 12884520Snw141292 if (BVAL_CASEEQ(cbval, "Computer")) { 12895696Snw141292 *sid_type = _IDMAP_T_COMPUTER; 12905696Snw141292 break; 12914520Snw141292 } else if (BVAL_CASEEQ(cbval, "Group")) { 12925696Snw141292 *sid_type = _IDMAP_T_GROUP; 12935696Snw141292 break; 12944520Snw141292 } else if (BVAL_CASEEQ(cbval, "USER")) { 12955696Snw141292 *sid_type = _IDMAP_T_USER; 12965696Snw141292 /* Continue looping -- this may be a computer yet */ 12975696Snw141292 } 12985696Snw141292 /* 12995696Snw141292 * "else if (*sid_type = _IDMAP_T_USER)" then this is a 13005696Snw141292 * new sub-class of user -- what to do with it?? 13015696Snw141292 */ 13024520Snw141292 } 13035447Snw141292 13045447Snw141292 return (1); 13054520Snw141292 } 13064520Snw141292 13074520Snw141292 /* 13084520Snw141292 * Handle a given search result entry 13094520Snw141292 */ 13104520Snw141292 static 13114520Snw141292 void 13124520Snw141292 idmap_extract_object(idmap_query_state_t *state, int qid, LDAPMessage *res) 13134520Snw141292 { 13144520Snw141292 BerElement *ber = NULL; 13154520Snw141292 BerValue **bvalues; 13164520Snw141292 ad_host_t *adh; 13174520Snw141292 idmap_q_t *q; 13185696Snw141292 char *attr; 13195731Sbaban const char *unixuser_attr = NULL; 13205731Sbaban const char *unixgroup_attr = NULL; 13215731Sbaban char *unixuser = NULL; 13225731Sbaban char *unixgroup = NULL; 13235696Snw141292 char *dn = NULL; 13245696Snw141292 char *san = NULL; 13255696Snw141292 char *sid = NULL; 13265696Snw141292 rid_t rid = 0; 13275731Sbaban int sid_type = _IDMAP_T_UNDEF; 13285447Snw141292 int has_class, has_san, has_sid; 13295731Sbaban int has_unixuser, has_unixgroup; 13306531Sjp151216 int num; 13314520Snw141292 13324520Snw141292 adh = state->qadh; 13334520Snw141292 13344520Snw141292 (void) pthread_mutex_lock(&adh->lock); 13354520Snw141292 13365447Snw141292 q = &(state->queries[qid]); 13375447Snw141292 13385731Sbaban assert(q->rc != NULL); 13395731Sbaban 13406531Sjp151216 if (adh->dead || (dn = ldap_get_dn(adh->ld, res)) == NULL) { 13416531Sjp151216 num = adh->num_requests; 13424520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 13436531Sjp151216 idmapdlog(LOG_DEBUG, 13446531Sjp151216 "AD error decoding search result - %d queued requests", 13456531Sjp151216 num); 13464520Snw141292 return; 13474520Snw141292 } 13484520Snw141292 13495447Snw141292 assert(q->domain == NULL || *q->domain == NULL); 13504520Snw141292 13515731Sbaban /* 13525731Sbaban * If the caller has requested unixname then determine the 13535731Sbaban * AD attribute name that will have the unixname. 13545731Sbaban */ 13555731Sbaban if (q->unixname != NULL) { 13565731Sbaban if (q->eunixtype == _IDMAP_T_USER) 13575731Sbaban unixuser_attr = state->ad_unixuser_attr; 13585731Sbaban else if (q->eunixtype == _IDMAP_T_GROUP) 13595731Sbaban unixgroup_attr = state->ad_unixgroup_attr; 13605731Sbaban else if (q->eunixtype == _IDMAP_T_UNDEF) { 13615731Sbaban /* 13625731Sbaban * This is the case where we don't know 13635731Sbaban * before hand whether we need unixuser 13645731Sbaban * or unixgroup. This will be determined 13655731Sbaban * by the "sid_type" (i.e whether the given 13665731Sbaban * winname is user or group). If sid_type 13675731Sbaban * turns out to be user we will return 13685731Sbaban * unixuser (if found) and if it is a group 13695731Sbaban * we will return unixgroup (if found). We 13705731Sbaban * lookup for both ad_unixuser_attr and 13715731Sbaban * ad_unixgroup_attr and discard one of them 13725731Sbaban * after we know the "sidtype". This 13735731Sbaban * supports the following type of lookups. 13745731Sbaban * 13755731Sbaban * Example: 13765731Sbaban * $idmap show -c winname:foo 13775731Sbaban * In the above example, idmap will 13785731Sbaban * return uid if winname is winuser 13795731Sbaban * and gid if winname is wingroup. 13805731Sbaban */ 13815731Sbaban unixuser_attr = state->ad_unixuser_attr; 13825731Sbaban unixgroup_attr = state->ad_unixgroup_attr; 13835731Sbaban } 13845731Sbaban } 13855731Sbaban 13865731Sbaban has_class = has_san = has_sid = has_unixuser = has_unixgroup = 0; 13874520Snw141292 for (attr = ldap_first_attribute(adh->ld, res, &ber); attr != NULL; 13884520Snw141292 attr = ldap_next_attribute(adh->ld, res, ber)) { 13894520Snw141292 bvalues = NULL; /* for memory management below */ 13904520Snw141292 13914520Snw141292 /* 13924520Snw141292 * If this is an attribute we are looking for and 13934520Snw141292 * haven't seen it yet, parse it 13944520Snw141292 */ 13955731Sbaban if (q->sid != NULL && !has_sid && 13965447Snw141292 strcasecmp(attr, OBJSID) == 0) { 13974520Snw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 13985696Snw141292 sid = idmap_bv_objsid2sidstr(bvalues, &rid); 13995696Snw141292 has_sid = (sid != NULL); 14005447Snw141292 } else if (!has_san && strcasecmp(attr, SAN) == 0) { 14014520Snw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 14025731Sbaban san = idmap_bv_name2str(bvalues); 14035696Snw141292 has_san = (san != NULL); 14045447Snw141292 } else if (!has_class && strcasecmp(attr, OBJCLASS) == 0) { 14054520Snw141292 bvalues = ldap_get_values_len(adh->ld, res, attr); 14065696Snw141292 has_class = idmap_bv_objclass2sidtype(bvalues, 14075696Snw141292 &sid_type); 14085731Sbaban if (has_class && q->unixname != NULL && 14095731Sbaban q->eunixtype == _IDMAP_T_UNDEF) { 14105731Sbaban /* 14115731Sbaban * This is the case where we didn't 14125731Sbaban * know whether we wanted unixuser or 14135731Sbaban * unixgroup as described above. 14145731Sbaban * Now since we know the "sid_type" 14155731Sbaban * we discard the unwanted value 14165731Sbaban * if it was retrieved before we 14175731Sbaban * got here. 14185731Sbaban */ 14195731Sbaban if (sid_type == _IDMAP_T_USER) { 14205731Sbaban free(unixgroup); 14215731Sbaban unixgroup_attr = unixgroup = NULL; 14225731Sbaban } else if (sid_type == _IDMAP_T_GROUP) { 14235731Sbaban free(unixuser); 14245731Sbaban unixuser_attr = unixuser = NULL; 14255731Sbaban } else { 14265731Sbaban free(unixuser); 14275731Sbaban free(unixgroup); 14285731Sbaban unixuser_attr = unixuser = NULL; 14295731Sbaban unixgroup_attr = unixgroup = NULL; 14305731Sbaban } 14315731Sbaban } 14325731Sbaban } else if (!has_unixuser && unixuser_attr != NULL && 14335731Sbaban strcasecmp(attr, unixuser_attr) == 0) { 14345731Sbaban bvalues = ldap_get_values_len(adh->ld, res, attr); 14355731Sbaban unixuser = idmap_bv_name2str(bvalues); 14365731Sbaban has_unixuser = (unixuser != NULL); 14376386Sjp151216 14385731Sbaban } else if (!has_unixgroup && unixgroup_attr != NULL && 14395731Sbaban strcasecmp(attr, unixgroup_attr) == 0) { 14405731Sbaban bvalues = ldap_get_values_len(adh->ld, res, attr); 14415731Sbaban unixgroup = idmap_bv_name2str(bvalues); 14425731Sbaban has_unixgroup = (unixgroup != NULL); 14434520Snw141292 } 14444520Snw141292 14454520Snw141292 if (bvalues != NULL) 14464520Snw141292 ldap_value_free_len(bvalues); 14474520Snw141292 ldap_memfree(attr); 14484520Snw141292 14495696Snw141292 if (has_class && has_san && 14505731Sbaban (q->sid == NULL || has_sid) && 14515731Sbaban (unixuser_attr == NULL || has_unixuser) && 14525731Sbaban (unixgroup_attr == NULL || has_unixgroup)) { 14535731Sbaban /* Got what we need */ 14545447Snw141292 break; 14555696Snw141292 } 14564520Snw141292 } 14574520Snw141292 14586531Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 14596531Sjp151216 14605731Sbaban if (!has_class) { 14615731Sbaban /* 14625731Sbaban * Didn't find objectclass. Something's wrong with our 14635731Sbaban * AD data. 14645731Sbaban */ 14655731Sbaban free(san); 14665731Sbaban free(sid); 14675731Sbaban free(unixuser); 14685731Sbaban free(unixgroup); 14695731Sbaban } else { 14705731Sbaban /* 14715731Sbaban * Either we got what we needed and came out of the loop 14725731Sbaban * early OR we completed the loop in which case we didn't 14735731Sbaban * find some attributes that we were looking for. In either 14745731Sbaban * case set the result with what we got. 14755731Sbaban */ 14766386Sjp151216 idmap_setqresults(q, san, dn, 14776386Sjp151216 (unixuser != NULL) ? unixuser_attr : unixgroup_attr, 14786386Sjp151216 sid, rid, sid_type, 14795731Sbaban (unixuser != NULL) ? unixuser : unixgroup); 14805731Sbaban } 14815731Sbaban 14824520Snw141292 if (ber != NULL) 14834520Snw141292 ber_free(ber, 0); 14844520Snw141292 14854520Snw141292 ldap_memfree(dn); 14864520Snw141292 } 14874520Snw141292 14884520Snw141292 /* 14894520Snw141292 * Try to get a result; if there is one, find the corresponding 14904520Snw141292 * idmap_q_t and process the result. 14916531Sjp151216 * 14926531Sjp151216 * Returns: 0 success 14936531Sjp151216 * -1 error 14946531Sjp151216 * -2 queue empty 14954520Snw141292 */ 14964520Snw141292 static 14974520Snw141292 int 14984520Snw141292 idmap_get_adobject_batch(ad_host_t *adh, struct timeval *timeout) 14994520Snw141292 { 15004520Snw141292 idmap_query_state_t *query_state; 15014520Snw141292 LDAPMessage *res = NULL; 15024520Snw141292 int rc, ret, msgid, qid; 15036531Sjp151216 idmap_q_t *que; 15046531Sjp151216 int num; 15054520Snw141292 15064520Snw141292 (void) pthread_mutex_lock(&adh->lock); 15076531Sjp151216 if (adh->dead || adh->num_requests == 0) { 15086531Sjp151216 if (adh->dead) 15096531Sjp151216 ret = -1; 15106531Sjp151216 else 15116531Sjp151216 ret = -2; 15124520Snw141292 (void) pthread_mutex_unlock(&adh->lock); 15136531Sjp151216 return (ret); 15144520Snw141292 } 15154520Snw141292 15164520Snw141292 /* Get one result */ 15174520Snw141292 rc = ldap_result(adh->ld, LDAP_RES_ANY, 0, 15184520Snw141292 timeout, &res); 15195968Snw141292 if ((timeout != NULL && timeout->tv_sec > 0 && rc == LDAP_SUCCESS) || 15205968Snw141292 rc < 0) 15214520Snw141292 adh->dead = 1; 15226531Sjp151216 15236531Sjp151216 if (rc == LDAP_RES_SEARCH_RESULT && adh->num_requests > 0) 15246531Sjp151216 adh->num_requests--; 15254520Snw141292 15266531Sjp151216 if (adh->dead) { 15276531Sjp151216 num = adh->num_requests; 15286531Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 15296531Sjp151216 idmapdlog(LOG_DEBUG, 15306531Sjp151216 "AD ldap_result error - %d queued requests", num); 15314520Snw141292 return (-1); 15326531Sjp151216 } 15334520Snw141292 switch (rc) { 15344520Snw141292 case LDAP_RES_SEARCH_RESULT: 15356531Sjp151216 /* We should have the LDAP replies for some search... */ 15364520Snw141292 msgid = ldap_msgid(res); 15376531Sjp151216 if (idmap_msgid2query(adh, msgid, &query_state, &qid)) { 15386531Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 15396531Sjp151216 que = &(query_state->queries[qid]); 15406531Sjp151216 if (que->search_res != NULL) { 15416531Sjp151216 idmap_extract_object(query_state, qid, 15426531Sjp151216 que->search_res); 15436531Sjp151216 (void) ldap_msgfree(que->search_res); 15446531Sjp151216 que->search_res = NULL; 15456531Sjp151216 } else 15466531Sjp151216 *que->rc = IDMAP_ERR_NOTFOUND; 15474520Snw141292 /* ...so we can decrement qinflight */ 15484520Snw141292 atomic_dec_32(&query_state->qinflight); 15494884Sjp151216 idmap_lookup_unlock_batch(&query_state); 15506531Sjp151216 } else { 15516531Sjp151216 num = adh->num_requests; 15526531Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 15536531Sjp151216 idmapdlog(LOG_DEBUG, 15546531Sjp151216 "AD cannot find message ID - %d queued requests", 15556531Sjp151216 num); 15564520Snw141292 } 15574520Snw141292 (void) ldap_msgfree(res); 15584520Snw141292 ret = 0; 15594520Snw141292 break; 15606531Sjp151216 15614520Snw141292 case LDAP_RES_SEARCH_REFERENCE: 15624520Snw141292 /* 15634520Snw141292 * We have no need for these at the moment. Eventually, 15644520Snw141292 * when we query things that we can't expect to find in 15654520Snw141292 * the Global Catalog then we'll need to learn to follow 15664520Snw141292 * references. 15674520Snw141292 */ 15686531Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 15694520Snw141292 (void) ldap_msgfree(res); 15704520Snw141292 ret = 0; 15714520Snw141292 break; 15726531Sjp151216 15734520Snw141292 case LDAP_RES_SEARCH_ENTRY: 15746531Sjp151216 /* Got a result - queue it */ 15754520Snw141292 msgid = ldap_msgid(res); 15766531Sjp151216 rc = idmap_quesearchresbymsgid(adh, msgid, res); 15776531Sjp151216 num = adh->num_requests; 15786531Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 15796531Sjp151216 if (rc == -1) { 15806531Sjp151216 idmapdlog(LOG_DEBUG, 15816531Sjp151216 "AD already has search result - %d queued requests", 15826531Sjp151216 num); 15836531Sjp151216 (void) ldap_msgfree(res); 15846531Sjp151216 } else if (rc == -2) { 15856531Sjp151216 idmapdlog(LOG_DEBUG, 15866531Sjp151216 "AD cannot queue by message ID " 15876531Sjp151216 "- %d queued requests", num); 15886531Sjp151216 (void) ldap_msgfree(res); 15894520Snw141292 } 15904520Snw141292 ret = 0; 15914520Snw141292 break; 15926531Sjp151216 15934520Snw141292 default: 15944520Snw141292 /* timeout or error; treat the same */ 15956531Sjp151216 (void) pthread_mutex_unlock(&adh->lock); 15964520Snw141292 ret = -1; 15974520Snw141292 break; 15984520Snw141292 } 15994520Snw141292 16004520Snw141292 return (ret); 16014520Snw141292 } 16024520Snw141292 16034884Sjp151216 /* 16044884Sjp151216 * This routine decreament the reference count of the 16054884Sjp151216 * idmap_query_state_t 16064884Sjp151216 */ 16074884Sjp151216 static void 16084884Sjp151216 idmap_lookup_unlock_batch(idmap_query_state_t **state) 16094884Sjp151216 { 16104884Sjp151216 /* 16114884Sjp151216 * Decrement reference count with qstatelock locked 16124884Sjp151216 */ 16134884Sjp151216 (void) pthread_mutex_lock(&qstatelock); 16144884Sjp151216 (*state)->ref_cnt--; 16154884Sjp151216 /* 16164884Sjp151216 * If there are no references wakup the allocating thread 16174884Sjp151216 */ 16186531Sjp151216 if ((*state)->ref_cnt <= 1) 16194884Sjp151216 (void) pthread_cond_signal(&(*state)->cv); 16204884Sjp151216 (void) pthread_mutex_unlock(&qstatelock); 16214884Sjp151216 *state = NULL; 16224884Sjp151216 } 16234884Sjp151216 16245447Snw141292 static 16255447Snw141292 void 16265447Snw141292 idmap_cleanup_batch(idmap_query_state_t *batch) 16275447Snw141292 { 16285447Snw141292 int i; 16295447Snw141292 16305447Snw141292 for (i = 0; i < batch->qcount; i++) { 16315696Snw141292 if (batch->queries[i].ecanonname != NULL) 16325696Snw141292 free(batch->queries[i].ecanonname); 16335696Snw141292 batch->queries[i].ecanonname = NULL; 16345696Snw141292 if (batch->queries[i].edomain != NULL) 16355696Snw141292 free(batch->queries[i].edomain); 16365696Snw141292 batch->queries[i].edomain = NULL; 16375447Snw141292 } 16385447Snw141292 } 16395447Snw141292 16404884Sjp151216 /* 16414884Sjp151216 * This routine frees the idmap_query_state_t structure 16424884Sjp151216 * If the reference count is greater than 1 it waits 16434884Sjp151216 * for the other threads to finish using it. 16444884Sjp151216 */ 16454520Snw141292 void 16464884Sjp151216 idmap_lookup_release_batch(idmap_query_state_t **state) 16474520Snw141292 { 16484520Snw141292 idmap_query_state_t **p; 16494520Snw141292 16504884Sjp151216 /* 16516531Sjp151216 * Set state to dead to stop further operations. 16526531Sjp151216 * Wait for reference count with qstatelock locked 16536531Sjp151216 * to get to one. 16544884Sjp151216 */ 16554884Sjp151216 (void) pthread_mutex_lock(&qstatelock); 16566531Sjp151216 (*state)->qdead = 1; 16576531Sjp151216 while ((*state)->ref_cnt > 1) { 16584884Sjp151216 (void) pthread_cond_wait(&(*state)->cv, &qstatelock); 16594884Sjp151216 } 16604520Snw141292 16614520Snw141292 /* Remove this state struct from the list of state structs */ 16624520Snw141292 for (p = &qstatehead; *p != NULL; p = &(*p)->next) { 16634520Snw141292 if (*p == (*state)) { 16644520Snw141292 *p = (*state)->next; 16654520Snw141292 break; 16664520Snw141292 } 16674520Snw141292 } 16686531Sjp151216 (void) pthread_mutex_unlock(&qstatelock); 16695447Snw141292 16705447Snw141292 idmap_cleanup_batch(*state); 16715447Snw141292 16724884Sjp151216 (void) pthread_cond_destroy(&(*state)->cv); 16734884Sjp151216 16744884Sjp151216 idmap_release_conn((*state)->qadh); 16754884Sjp151216 16764520Snw141292 free(*state); 16774520Snw141292 *state = NULL; 16784520Snw141292 } 16794520Snw141292 16806531Sjp151216 16816531Sjp151216 /* 16826531Sjp151216 * This routine waits for other threads using the 16836531Sjp151216 * idmap_query_state_t structure to finish. 16846531Sjp151216 * If the reference count is greater than 1 it waits 16856531Sjp151216 * for the other threads to finish using it. 16866531Sjp151216 */ 16876531Sjp151216 static 16886531Sjp151216 void 16896531Sjp151216 idmap_lookup_wait_batch(idmap_query_state_t *state) 16906531Sjp151216 { 16916531Sjp151216 /* 16926531Sjp151216 * Set state to dead to stop further operation. 16936531Sjp151216 * stating. 16946531Sjp151216 * Wait for reference count to get to one 16956531Sjp151216 * with qstatelock locked. 16966531Sjp151216 */ 16976531Sjp151216 (void) pthread_mutex_lock(&qstatelock); 16986531Sjp151216 state->qdead = 1; 16996531Sjp151216 while (state->ref_cnt > 1) { 17006531Sjp151216 (void) pthread_cond_wait(&state->cv, &qstatelock); 17016531Sjp151216 } 17026531Sjp151216 (void) pthread_mutex_unlock(&qstatelock); 17036531Sjp151216 } 17046531Sjp151216 17056531Sjp151216 17064520Snw141292 idmap_retcode 17075968Snw141292 idmap_lookup_batch_end(idmap_query_state_t **state) 17084520Snw141292 { 17094520Snw141292 int rc = LDAP_SUCCESS; 17104520Snw141292 idmap_retcode retcode = IDMAP_SUCCESS; 17115968Snw141292 struct timeval timeout; 17124520Snw141292 17135968Snw141292 timeout.tv_sec = IDMAPD_SEARCH_TIMEOUT; 17145968Snw141292 timeout.tv_usec = 0; 17154520Snw141292 17164520Snw141292 /* Process results until done or until timeout, if given */ 17174520Snw141292 while ((*state)->qinflight > 0) { 17184520Snw141292 if ((rc = idmap_get_adobject_batch((*state)->qadh, 17195968Snw141292 &timeout)) != 0) 17204520Snw141292 break; 17214520Snw141292 } 17226531Sjp151216 (*state)->qdead = 1; 17236531Sjp151216 /* Wait for other threads proceesing search result to finish */ 17246531Sjp151216 idmap_lookup_wait_batch(*state); 17254520Snw141292 17266531Sjp151216 if (rc == -1 || (*state)->qinflight != 0) 17274520Snw141292 retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 17284520Snw141292 17294884Sjp151216 idmap_lookup_release_batch(state); 17304520Snw141292 17314520Snw141292 return (retcode); 17324520Snw141292 } 17334520Snw141292 17344520Snw141292 /* 17354520Snw141292 * Send one prepared search, queue up msgid, process what results are 17364520Snw141292 * available 17374520Snw141292 */ 17384520Snw141292 static 17394520Snw141292 idmap_retcode 17406386Sjp151216 idmap_batch_add1(idmap_query_state_t *state, const char *filter, 17416386Sjp151216 char *ecanonname, char *edomain, int eunixtype, 17426386Sjp151216 char **dn, char **attr, char **value, 17436386Sjp151216 char **canonname, char **dname, 17446386Sjp151216 char **sid, rid_t *rid, int *sid_type, char **unixname, 17456386Sjp151216 idmap_retcode *rc) 17464520Snw141292 { 17474520Snw141292 idmap_retcode retcode = IDMAP_SUCCESS; 17485731Sbaban int lrc, qid, i; 17496531Sjp151216 int num; 17506531Sjp151216 int dead; 17514520Snw141292 struct timeval tv; 17524520Snw141292 idmap_q_t *q; 17535696Snw141292 static char *attrs[] = { 17545696Snw141292 SAN, 17555696Snw141292 OBJSID, 17565696Snw141292 OBJCLASS, 17575731Sbaban NULL, /* placeholder for unixname attr */ 17585731Sbaban NULL, /* placeholder for unixname attr */ 17595696Snw141292 NULL 17605696Snw141292 }; 17614520Snw141292 17624520Snw141292 qid = atomic_inc_32_nv(&state->qlastsent) - 1; 17634520Snw141292 17644520Snw141292 q = &(state->queries[qid]); 17654520Snw141292 17665696Snw141292 /* 17675696Snw141292 * Remember the expected canonname so we can check the results 17685696Snw141292 * agains it 17695696Snw141292 */ 17705696Snw141292 q->ecanonname = ecanonname; 17715696Snw141292 q->edomain = edomain; 17725731Sbaban q->eunixtype = eunixtype; 17735447Snw141292 17744520Snw141292 /* Remember where to put the results */ 17755696Snw141292 q->canonname = canonname; 17765731Sbaban q->sid = sid; 17774520Snw141292 q->domain = dname; 17784520Snw141292 q->rid = rid; 17794520Snw141292 q->sid_type = sid_type; 17804520Snw141292 q->rc = rc; 17815731Sbaban q->unixname = unixname; 17826386Sjp151216 q->dn = dn; 17836386Sjp151216 q->attr = attr; 17846386Sjp151216 q->value = value; 17855731Sbaban 17865731Sbaban /* Add unixuser/unixgroup attribute names to the attrs list */ 17875731Sbaban if (unixname != NULL) { 17885731Sbaban i = 3; 17895731Sbaban if (eunixtype != _IDMAP_T_GROUP && 17905731Sbaban state->ad_unixuser_attr != NULL) 17915731Sbaban attrs[i++] = (char *)state->ad_unixuser_attr; 17925731Sbaban if (eunixtype != _IDMAP_T_USER && 17935731Sbaban state->ad_unixgroup_attr != NULL) 17945731Sbaban attrs[i] = (char *)state->ad_unixgroup_attr; 17955731Sbaban } 17964520Snw141292 17974520Snw141292 /* 17984520Snw141292 * Provide sane defaults for the results in case we never hear 17994520Snw141292 * back from the DS before closing the connection. 18005447Snw141292 * 18015447Snw141292 * In particular we default the result to indicate a retriable 18025447Snw141292 * error. The first complete matching result entry will cause 18035447Snw141292 * this to be set to IDMAP_SUCCESS, and the end of the results 18045447Snw141292 * for this search will cause this to indicate "not found" if no 18055447Snw141292 * result entries arrived or no complete ones matched the lookup 18065447Snw141292 * we were doing. 18074520Snw141292 */ 18084520Snw141292 *rc = IDMAP_ERR_RETRIABLE_NET_ERR; 18095731Sbaban if (sid_type != NULL) 18105731Sbaban *sid_type = _IDMAP_T_OTHER; 18115731Sbaban if (sid != NULL) 18125731Sbaban *sid = NULL; 18134520Snw141292 if (dname != NULL) 18144520Snw141292 *dname = NULL; 18154520Snw141292 if (rid != NULL) 18164520Snw141292 *rid = 0; 18176386Sjp151216 if (dn != NULL) 18186386Sjp151216 *dn = NULL; 18196386Sjp151216 if (attr != NULL) 18206386Sjp151216 *attr = NULL; 18216386Sjp151216 if (value != NULL) 18226386Sjp151216 *value = NULL; 18234520Snw141292 18246531Sjp151216 /* Check the number of queued requests first */ 18256531Sjp151216 tv.tv_sec = IDMAPD_SEARCH_TIMEOUT; 18266531Sjp151216 tv.tv_usec = 0; 18276531Sjp151216 while (!state->qadh->dead && 18286531Sjp151216 state->qadh->num_requests > state->qadh->max_requests) { 18296531Sjp151216 if (idmap_get_adobject_batch(state->qadh, &tv) != 0) 18306531Sjp151216 break; 18316531Sjp151216 } 18326531Sjp151216 1833*6616Sdm199847 /* 1834*6616Sdm199847 * Don't set *canonname to NULL because it may be pointing to the 1835*6616Sdm199847 * given winname. Later on if we get a canonical name from AD the 1836*6616Sdm199847 * old name if any will be freed before assigning the new name. 1837*6616Sdm199847 */ 1838*6616Sdm199847 18394520Snw141292 /* Send this lookup, don't wait for a result here */ 18406531Sjp151216 lrc = LDAP_SUCCESS; 18414520Snw141292 (void) pthread_mutex_lock(&state->qadh->lock); 18424520Snw141292 18434520Snw141292 if (!state->qadh->dead) { 18444520Snw141292 state->qadh->idletime = time(NULL); 18455447Snw141292 lrc = ldap_search_ext(state->qadh->ld, "", 18465696Snw141292 LDAP_SCOPE_SUBTREE, filter, attrs, 0, NULL, NULL, 18474520Snw141292 NULL, -1, &q->msgid); 18486531Sjp151216 18496531Sjp151216 if (lrc == LDAP_SUCCESS) { 18506531Sjp151216 state->qadh->num_requests++; 18516531Sjp151216 } else if (lrc == LDAP_BUSY || lrc == LDAP_UNAVAILABLE || 18524520Snw141292 lrc == LDAP_CONNECT_ERROR || lrc == LDAP_SERVER_DOWN || 18534520Snw141292 lrc == LDAP_UNWILLING_TO_PERFORM) { 18544520Snw141292 retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 18554520Snw141292 state->qadh->dead = 1; 18566531Sjp151216 } else { 18574520Snw141292 retcode = IDMAP_ERR_OTHER; 18584520Snw141292 state->qadh->dead = 1; 18594520Snw141292 } 18604520Snw141292 } 18616531Sjp151216 dead = state->qadh->dead; 18626531Sjp151216 num = state->qadh->num_requests; 18634520Snw141292 (void) pthread_mutex_unlock(&state->qadh->lock); 18644520Snw141292 18656531Sjp151216 if (dead) { 18666531Sjp151216 if (lrc != LDAP_SUCCESS) 18676531Sjp151216 idmapdlog(LOG_DEBUG, 18686531Sjp151216 "AD ldap_search_ext error (%s) " 18696531Sjp151216 "- %d queued requests", 18706531Sjp151216 ldap_err2string(lrc), num); 18714520Snw141292 return (retcode); 18726531Sjp151216 } 18734520Snw141292 18744520Snw141292 atomic_inc_32(&state->qinflight); 18754520Snw141292 18764520Snw141292 /* 18774520Snw141292 * Reap as many requests as we can _without_ waiting 18784520Snw141292 * 18794520Snw141292 * We do this to prevent any possible TCP socket buffer 18804520Snw141292 * starvation deadlocks. 18814520Snw141292 */ 18824520Snw141292 (void) memset(&tv, 0, sizeof (tv)); 18834520Snw141292 while (idmap_get_adobject_batch(state->qadh, &tv) == 0) 18844520Snw141292 ; 18854520Snw141292 18864520Snw141292 return (IDMAP_SUCCESS); 18874520Snw141292 } 18884520Snw141292 18894520Snw141292 idmap_retcode 18904520Snw141292 idmap_name2sid_batch_add1(idmap_query_state_t *state, 18915731Sbaban const char *name, const char *dname, int eunixtype, 18926386Sjp151216 char **dn, char **attr, char **value, 18936386Sjp151216 char **canonname, char **sid, rid_t *rid, 18946386Sjp151216 int *sid_type, char **unixname, idmap_retcode *rc) 18954520Snw141292 { 18964520Snw141292 idmap_retcode retcode; 18975447Snw141292 int len, samAcctNameLen; 1898*6616Sdm199847 char *filter = NULL, *s_name; 18995696Snw141292 char *ecanonname, *edomain; /* expected canonname */ 19004520Snw141292 19014520Snw141292 /* 19025447Snw141292 * Strategy: search the global catalog for user/group by 19035447Snw141292 * sAMAccountName = user/groupname with "" as the base DN and by 19045447Snw141292 * userPrincipalName = user/groupname@domain. The result 19055447Snw141292 * entries will be checked to conform to the name and domain 19065447Snw141292 * name given here. The DN, sAMAccountName, userPrincipalName, 19075447Snw141292 * objectSid and objectClass of the result entries are all we 19085447Snw141292 * need to figure out which entries match the lookup, the SID of 19095447Snw141292 * the user/group and whether it is a user or a group. 19104520Snw141292 */ 19114520Snw141292 19124520Snw141292 /* 19135447Snw141292 * We need the name and the domain name separately and as 19145447Snw141292 * name@domain. We also allow the domain to be provided 19155447Snw141292 * separately. 19164520Snw141292 */ 19175232Snw141292 samAcctNameLen = strlen(name); 19185447Snw141292 19195696Snw141292 if ((ecanonname = strdup(name)) == NULL) 19205696Snw141292 return (IDMAP_ERR_MEMORY); 19214520Snw141292 19225447Snw141292 if (dname == NULL || *dname == '\0') { 19235696Snw141292 if ((dname = strchr(name, '@')) != NULL) { 19245696Snw141292 /* 'name' is qualified with a domain name */ 19255696Snw141292 if ((edomain = strdup(dname + 1)) == NULL) { 19265696Snw141292 free(ecanonname); 19275696Snw141292 return (IDMAP_ERR_MEMORY); 19285696Snw141292 } 19295696Snw141292 *strchr(ecanonname, '@') = '\0'; 19305696Snw141292 } else { 19316097Snw141292 /* 19326097Snw141292 * 'name' not qualified and dname not given 19336097Snw141292 * 19346097Snw141292 * Note: ad->dflt_w2k_dom cannot be NULL - see 19356097Snw141292 * idmap_ad_alloc() 19366097Snw141292 */ 19376097Snw141292 if (*state->qadh->owner->dflt_w2k_dom == '\0') { 19385696Snw141292 free(ecanonname); 19395696Snw141292 return (IDMAP_ERR_DOMAIN); 19405696Snw141292 } 19415696Snw141292 edomain = strdup(state->qadh->owner->dflt_w2k_dom); 19425696Snw141292 if (edomain == NULL) { 19435696Snw141292 free(ecanonname); 19445696Snw141292 return (IDMAP_ERR_MEMORY); 19455696Snw141292 } 19465696Snw141292 } 19475696Snw141292 } else { 19485696Snw141292 if ((edomain = strdup(dname)) == NULL) { 19495696Snw141292 free(ecanonname); 19505447Snw141292 return (IDMAP_ERR_MEMORY); 19515696Snw141292 } 19525447Snw141292 } 19534520Snw141292 1954*6616Sdm199847 s_name = sanitize_for_ldap_filter(name); 1955*6616Sdm199847 if (s_name == NULL) { 1956*6616Sdm199847 free(ecanonname); 1957*6616Sdm199847 free(edomain); 1958*6616Sdm199847 return (IDMAP_ERR_MEMORY); 1959*6616Sdm199847 } 1960*6616Sdm199847 19614520Snw141292 /* Assemble filter */ 1962*6616Sdm199847 len = snprintf(NULL, 0, SANFILTER, samAcctNameLen, s_name) + 1; 19635447Snw141292 if ((filter = (char *)malloc(len)) == NULL) { 19645696Snw141292 free(ecanonname); 1965*6616Sdm199847 free(edomain); 1966*6616Sdm199847 if (s_name != name) 1967*6616Sdm199847 free(s_name); 19684520Snw141292 return (IDMAP_ERR_MEMORY); 19694520Snw141292 } 1970*6616Sdm199847 (void) snprintf(filter, len, SANFILTER, samAcctNameLen, s_name); 1971*6616Sdm199847 if (s_name != name) 1972*6616Sdm199847 free(s_name); 19734520Snw141292 19745696Snw141292 retcode = idmap_batch_add1(state, filter, ecanonname, edomain, 19756386Sjp151216 eunixtype, dn, attr, value, canonname, NULL, sid, rid, sid_type, 19766386Sjp151216 unixname, rc); 19774520Snw141292 19784520Snw141292 free(filter); 19794520Snw141292 19804520Snw141292 return (retcode); 19814520Snw141292 } 19824520Snw141292 19834520Snw141292 idmap_retcode 19844520Snw141292 idmap_sid2name_batch_add1(idmap_query_state_t *state, 19855731Sbaban const char *sid, const rid_t *rid, int eunixtype, 19866386Sjp151216 char **dn, char **attr, char **value, 19876386Sjp151216 char **name, char **dname, int *sid_type, 19886386Sjp151216 char **unixname, idmap_retcode *rc) 19894520Snw141292 { 19904520Snw141292 idmap_retcode retcode; 19914520Snw141292 int flen, ret; 19924520Snw141292 char *filter = NULL; 19934520Snw141292 char cbinsid[MAXHEXBINSID + 1]; 19944520Snw141292 19954520Snw141292 /* 19964520Snw141292 * Strategy: search [the global catalog] for user/group by 19974520Snw141292 * objectSid = SID with empty base DN. The DN, sAMAccountName 19984520Snw141292 * and objectClass of the result are all we need to figure out 19994520Snw141292 * the name of the SID and whether it is a user, a group or a 20004520Snw141292 * computer. 20014520Snw141292 */ 20024520Snw141292 20034520Snw141292 ret = idmap_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid)); 20044520Snw141292 if (ret != 0) 20054520Snw141292 return (IDMAP_ERR_SID); 20064520Snw141292 20074520Snw141292 /* Assemble filter */ 20085447Snw141292 flen = snprintf(NULL, 0, OBJSIDFILTER, cbinsid) + 1; 20094520Snw141292 if ((filter = (char *)malloc(flen)) == NULL) 20104520Snw141292 return (IDMAP_ERR_MEMORY); 20115447Snw141292 (void) snprintf(filter, flen, OBJSIDFILTER, cbinsid); 20124520Snw141292 20135731Sbaban retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype, 20146386Sjp151216 dn, attr, value, name, dname, NULL, NULL, sid_type, unixname, rc); 20154520Snw141292 20164520Snw141292 free(filter); 20174520Snw141292 20184520Snw141292 return (retcode); 20194520Snw141292 } 20205731Sbaban 20215731Sbaban idmap_retcode 20225731Sbaban idmap_unixname2sid_batch_add1(idmap_query_state_t *state, 20235731Sbaban const char *unixname, int is_user, int is_wuser, 20246386Sjp151216 char **dn, char **attr, char **value, 20256386Sjp151216 char **sid, rid_t *rid, char **name, 20266386Sjp151216 char **dname, int *sid_type, idmap_retcode *rc) 20275731Sbaban { 20285731Sbaban idmap_retcode retcode; 20295731Sbaban int len, ulen; 2030*6616Sdm199847 char *filter = NULL, *s_unixname; 20315731Sbaban const char *attrname = NULL; 20325731Sbaban 20335731Sbaban /* Get unixuser or unixgroup AD attribute name */ 20345731Sbaban attrname = (is_user) ? 20355731Sbaban state->ad_unixuser_attr : state->ad_unixgroup_attr; 20365731Sbaban if (attrname == NULL) 20375731Sbaban return (IDMAP_ERR_NOTFOUND); 20385731Sbaban 2039*6616Sdm199847 s_unixname = sanitize_for_ldap_filter(unixname); 2040*6616Sdm199847 if (s_unixname == NULL) 2041*6616Sdm199847 return (IDMAP_ERR_MEMORY); 2042*6616Sdm199847 20435731Sbaban /* Assemble filter */ 20445731Sbaban ulen = strlen(unixname); 20455731Sbaban len = snprintf(NULL, 0, "(&(objectclass=%s)(%s=%.*s))", 2046*6616Sdm199847 is_wuser ? "user" : "group", attrname, ulen, s_unixname) + 1; 2047*6616Sdm199847 if ((filter = (char *)malloc(len)) == NULL) { 2048*6616Sdm199847 if (s_unixname != unixname) 2049*6616Sdm199847 free(s_unixname); 20505731Sbaban return (IDMAP_ERR_MEMORY); 2051*6616Sdm199847 } 20525731Sbaban (void) snprintf(filter, len, "(&(objectclass=%s)(%s=%.*s))", 2053*6616Sdm199847 is_wuser ? "user" : "group", attrname, ulen, s_unixname); 2054*6616Sdm199847 if (s_unixname != unixname) 2055*6616Sdm199847 free(s_unixname); 20565731Sbaban 20575731Sbaban retcode = idmap_batch_add1(state, filter, NULL, NULL, 20586386Sjp151216 _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type, 20596386Sjp151216 NULL, rc); 20606386Sjp151216 20616386Sjp151216 if (retcode == IDMAP_SUCCESS && attr != NULL) { 20626386Sjp151216 if ((*attr = strdup(attrname)) == NULL) 20636386Sjp151216 retcode = IDMAP_ERR_MEMORY; 20646386Sjp151216 } 20656386Sjp151216 20666386Sjp151216 if (retcode == IDMAP_SUCCESS && value != NULL) { 20676386Sjp151216 if (ulen > 0) { 20686386Sjp151216 if ((*value = strdup(unixname)) == NULL) 20696386Sjp151216 retcode = IDMAP_ERR_MEMORY; 20706386Sjp151216 } 20716386Sjp151216 else 20726386Sjp151216 *value = NULL; 20736386Sjp151216 } 20745731Sbaban 20755731Sbaban free(filter); 20765731Sbaban 20775731Sbaban return (retcode); 20785731Sbaban } 2079