1c5c4113dSnw141292 /* 2c5c4113dSnw141292 * CDDL HEADER START 3c5c4113dSnw141292 * 4c5c4113dSnw141292 * The contents of this file are subject to the terms of the 5c5c4113dSnw141292 * Common Development and Distribution License (the "License"). 6c5c4113dSnw141292 * You may not use this file except in compliance with the License. 7c5c4113dSnw141292 * 8c5c4113dSnw141292 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9c5c4113dSnw141292 * or http://www.opensolaris.org/os/licensing. 10c5c4113dSnw141292 * See the License for the specific language governing permissions 11c5c4113dSnw141292 * and limitations under the License. 12c5c4113dSnw141292 * 13c5c4113dSnw141292 * When distributing Covered Code, include this CDDL HEADER in each 14c5c4113dSnw141292 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15c5c4113dSnw141292 * If applicable, add the following below this CDDL HEADER, with the 16c5c4113dSnw141292 * fields enclosed by brackets "[]" replaced with your own identifying 17c5c4113dSnw141292 * information: Portions Copyright [yyyy] [name of copyright owner] 18c5c4113dSnw141292 * 19c5c4113dSnw141292 * CDDL HEADER END 20c5c4113dSnw141292 */ 21c5c4113dSnw141292 22c5c4113dSnw141292 /* 23*1fcced4cSJordan Brown * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24c5c4113dSnw141292 * Use is subject to license terms. 25c5c4113dSnw141292 */ 26c5c4113dSnw141292 27c5c4113dSnw141292 /* 28c5c4113dSnw141292 * Processes name2sid & sid2name batched lookups for a given user or 29c5c4113dSnw141292 * computer from an AD Directory server using GSSAPI authentication 30c5c4113dSnw141292 */ 31c5c4113dSnw141292 32c5c4113dSnw141292 #include <stdio.h> 33c5c4113dSnw141292 #include <stdlib.h> 34c5c4113dSnw141292 #include <alloca.h> 35c5c4113dSnw141292 #include <string.h> 36c5c4113dSnw141292 #include <strings.h> 37c5c4113dSnw141292 #include <lber.h> 38c5c4113dSnw141292 #include <ldap.h> 39c5c4113dSnw141292 #include <sasl/sasl.h> 40c5c4113dSnw141292 #include <string.h> 41c5c4113dSnw141292 #include <ctype.h> 42c5c4113dSnw141292 #include <pthread.h> 43c5c4113dSnw141292 #include <synch.h> 44c5c4113dSnw141292 #include <atomic.h> 45c5c4113dSnw141292 #include <errno.h> 46c5c4113dSnw141292 #include <assert.h> 47c5c4113dSnw141292 #include <limits.h> 482b4a7802SBaban Kenkre #include <time.h> 49cd37da74Snw141292 #include <sys/u8_textprep.h> 502b4a7802SBaban Kenkre #include "libadutils.h" 51479ac375Sdm199847 #include "nldaputils.h" 52c5c4113dSnw141292 #include "idmapd.h" 53c5c4113dSnw141292 54c5c4113dSnw141292 /* Attribute names and filter format strings */ 55e3c2d6aaSnw141292 #define SAN "sAMAccountName" 56e3c2d6aaSnw141292 #define OBJSID "objectSid" 57e3c2d6aaSnw141292 #define OBJCLASS "objectClass" 58c5c4113dSnw141292 #define SANFILTER "(sAMAccountName=%.*s)" 59e3c2d6aaSnw141292 #define OBJSIDFILTER "(objectSid=%s)" 60c5c4113dSnw141292 612b4a7802SBaban Kenkre void idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, 622b4a7802SBaban Kenkre int qid, void *argp); 63c5c4113dSnw141292 64c5c4113dSnw141292 /* 65c5c4113dSnw141292 * A place to put the results of a batched (async) query 66c5c4113dSnw141292 * 67c5c4113dSnw141292 * There is one of these for every query added to a batch object 68c5c4113dSnw141292 * (idmap_query_state, see below). 69c5c4113dSnw141292 */ 70c5c4113dSnw141292 typedef struct idmap_q { 71e3c2d6aaSnw141292 /* 72e3c2d6aaSnw141292 * data used for validating search result entries for name->SID 73e8c27ec8Sbaban * lookups 74e3c2d6aaSnw141292 */ 75cd37da74Snw141292 char *ecanonname; /* expected canon name */ 76cd37da74Snw141292 char *edomain; /* expected domain name */ 77e8c27ec8Sbaban int eunixtype; /* expected unix type */ 78e3c2d6aaSnw141292 /* results */ 79cd37da74Snw141292 char **canonname; /* actual canon name */ 80c5c4113dSnw141292 char **domain; /* name of domain of object */ 81e8c27ec8Sbaban char **sid; /* stringified SID */ 82e8c27ec8Sbaban rid_t *rid; /* RID */ 83e8c27ec8Sbaban int *sid_type; /* user or group SID? */ 84e8c27ec8Sbaban char **unixname; /* unixname for name mapping */ 8548258c6bSjp151216 char **dn; /* DN of entry */ 8648258c6bSjp151216 char **attr; /* Attr for name mapping */ 8748258c6bSjp151216 char **value; /* value for name mapping */ 88c5c4113dSnw141292 idmap_retcode *rc; 892b4a7802SBaban Kenkre adutils_rc ad_rc; 902b4a7802SBaban Kenkre adutils_result_t *result; 91e3c2d6aaSnw141292 92bcced03bSjp151216 /* 93bcced03bSjp151216 * The LDAP search entry result is placed here to be processed 94bcced03bSjp151216 * when the search done result is received. 95bcced03bSjp151216 */ 96bcced03bSjp151216 LDAPMessage *search_res; /* The LDAP search result */ 97c5c4113dSnw141292 } idmap_q_t; 98c5c4113dSnw141292 99c5c4113dSnw141292 /* Batch context structure; typedef is in header file */ 100c5c4113dSnw141292 struct idmap_query_state { 1012b4a7802SBaban Kenkre adutils_query_state_t *qs; 1024d61c878SJulian Pullen int qsize; /* Queue size */ 1034d61c878SJulian Pullen uint32_t qcount; /* Number of queued requests */ 104e8c27ec8Sbaban const char *ad_unixuser_attr; 105e8c27ec8Sbaban const char *ad_unixgroup_attr; 106c5c4113dSnw141292 idmap_q_t queries[1]; /* array of query results */ 107c5c4113dSnw141292 }; 108c5c4113dSnw141292 109651c0131Sbaban static pthread_t reaperid = 0; 110c5c4113dSnw141292 111c5c4113dSnw141292 /* 112c5c4113dSnw141292 * Keep connection management simple for now, extend or replace later 113c5c4113dSnw141292 * with updated libsldap code. 114c5c4113dSnw141292 */ 115c5c4113dSnw141292 #define ADREAPERSLEEP 60 116c5c4113dSnw141292 117c5c4113dSnw141292 /* 118c5c4113dSnw141292 * Idle connection reaping side of connection management 119c5c4113dSnw141292 * 120c5c4113dSnw141292 * Every minute wake up and look for connections that have been idle for 121c5c4113dSnw141292 * five minutes or more and close them. 122c5c4113dSnw141292 */ 123c5c4113dSnw141292 /*ARGSUSED*/ 124c5c4113dSnw141292 static 125c5c4113dSnw141292 void 126c5c4113dSnw141292 adreaper(void *arg) 127c5c4113dSnw141292 { 128c5c4113dSnw141292 timespec_t ts; 129c5c4113dSnw141292 130c5c4113dSnw141292 ts.tv_sec = ADREAPERSLEEP; 131c5c4113dSnw141292 ts.tv_nsec = 0; 132c5c4113dSnw141292 133c5c4113dSnw141292 for (;;) { 134c5c4113dSnw141292 /* 135c5c4113dSnw141292 * nanosleep(3RT) is thead-safe (no SIGALRM) and more 136c5c4113dSnw141292 * portable than usleep(3C) 137c5c4113dSnw141292 */ 138c5c4113dSnw141292 (void) nanosleep(&ts, NULL); 1392b4a7802SBaban Kenkre adutils_reap_idle_connections(); 140c5c4113dSnw141292 } 141c5c4113dSnw141292 } 142c5c4113dSnw141292 143c5c4113dSnw141292 /* 144c5c4113dSnw141292 * Take ad_host_config_t information, create a ad_host_t, 145c5c4113dSnw141292 * populate it and add it to the list of hosts. 146c5c4113dSnw141292 */ 147c5c4113dSnw141292 148c5c4113dSnw141292 int 1492b4a7802SBaban Kenkre idmap_add_ds(adutils_ad_t *ad, const char *host, int port) 150c5c4113dSnw141292 { 151c5c4113dSnw141292 int ret = -1; 152c5c4113dSnw141292 1532b4a7802SBaban Kenkre if (adutils_add_ds(ad, host, port) == ADUTILS_SUCCESS) 154c8e26105Sjp151216 ret = 0; 155c5c4113dSnw141292 156c5c4113dSnw141292 /* Start reaper if it doesn't exist */ 1572b4a7802SBaban Kenkre if (ret == 0 && reaperid == 0) 158c5c4113dSnw141292 (void) pthread_create(&reaperid, NULL, 159c5c4113dSnw141292 (void *(*)(void *))adreaper, (void *)NULL); 160c5c4113dSnw141292 return (ret); 161c5c4113dSnw141292 } 162c5c4113dSnw141292 163c5c4113dSnw141292 static 1642b4a7802SBaban Kenkre idmap_retcode 1652b4a7802SBaban Kenkre map_adrc2idmaprc(adutils_rc adrc) 166c5c4113dSnw141292 { 1672b4a7802SBaban Kenkre switch (adrc) { 1682b4a7802SBaban Kenkre case ADUTILS_SUCCESS: 1692b4a7802SBaban Kenkre return (IDMAP_SUCCESS); 1702b4a7802SBaban Kenkre case ADUTILS_ERR_NOTFOUND: 1712b4a7802SBaban Kenkre return (IDMAP_ERR_NOTFOUND); 1722b4a7802SBaban Kenkre case ADUTILS_ERR_MEMORY: 1732b4a7802SBaban Kenkre return (IDMAP_ERR_MEMORY); 1742b4a7802SBaban Kenkre case ADUTILS_ERR_DOMAIN: 1752b4a7802SBaban Kenkre return (IDMAP_ERR_DOMAIN); 1762b4a7802SBaban Kenkre case ADUTILS_ERR_OTHER: 1772b4a7802SBaban Kenkre return (IDMAP_ERR_OTHER); 1782b4a7802SBaban Kenkre case ADUTILS_ERR_RETRIABLE_NET_ERR: 1792b4a7802SBaban Kenkre return (IDMAP_ERR_RETRIABLE_NET_ERR); 1802b4a7802SBaban Kenkre default: 1812b4a7802SBaban Kenkre return (IDMAP_ERR_INTERNAL); 182c5c4113dSnw141292 } 1832b4a7802SBaban Kenkre /* NOTREACHED */ 184c5c4113dSnw141292 } 185c5c4113dSnw141292 186c5c4113dSnw141292 idmap_retcode 1872b4a7802SBaban Kenkre idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries, 1882b4a7802SBaban Kenkre idmap_query_state_t **state) 189c5c4113dSnw141292 { 190c5c4113dSnw141292 idmap_query_state_t *new_state; 1912b4a7802SBaban Kenkre adutils_rc rc; 192c5c4113dSnw141292 193c5c4113dSnw141292 *state = NULL; 194c5c4113dSnw141292 1954d61c878SJulian Pullen assert(ad != NULL); 196c5c4113dSnw141292 197c5c4113dSnw141292 new_state = calloc(1, sizeof (idmap_query_state_t) + 198c5c4113dSnw141292 (nqueries - 1) * sizeof (idmap_q_t)); 199c5c4113dSnw141292 if (new_state == NULL) 200c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 201c5c4113dSnw141292 2022b4a7802SBaban Kenkre if ((rc = adutils_lookup_batch_start(ad, nqueries, 2032b4a7802SBaban Kenkre idmap_ldap_res_search_cb, new_state, &new_state->qs)) 2042b4a7802SBaban Kenkre != ADUTILS_SUCCESS) { 2052b4a7802SBaban Kenkre free(new_state); 2062b4a7802SBaban Kenkre return (map_adrc2idmaprc(rc)); 2072b4a7802SBaban Kenkre } 2082b4a7802SBaban Kenkre 2094d61c878SJulian Pullen new_state->qsize = nqueries; 210c5c4113dSnw141292 *state = new_state; 211c5c4113dSnw141292 return (IDMAP_SUCCESS); 212c5c4113dSnw141292 } 213c5c4113dSnw141292 214c5c4113dSnw141292 /* 215e8c27ec8Sbaban * Set unixuser_attr and unixgroup_attr for AD-based name mapping 216e8c27ec8Sbaban */ 217e8c27ec8Sbaban void 218e8c27ec8Sbaban idmap_lookup_batch_set_unixattr(idmap_query_state_t *state, 2194edd44c5Sjp151216 const char *unixuser_attr, const char *unixgroup_attr) 2204edd44c5Sjp151216 { 221e8c27ec8Sbaban state->ad_unixuser_attr = unixuser_attr; 222e8c27ec8Sbaban state->ad_unixgroup_attr = unixgroup_attr; 223e8c27ec8Sbaban } 224e8c27ec8Sbaban 225e8c27ec8Sbaban /* 226cd37da74Snw141292 * Take parsed attribute values from a search result entry and check if 227cd37da74Snw141292 * it is the result that was desired and, if so, set the result fields 228cd37da74Snw141292 * of the given idmap_q_t. 229cd37da74Snw141292 * 230e8c27ec8Sbaban * Frees the unused char * values. 231c5c4113dSnw141292 */ 232c5c4113dSnw141292 static 233cd37da74Snw141292 void 23448258c6bSjp151216 idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr, 23548258c6bSjp151216 char *sid, rid_t rid, int sid_type, char *unixname) 236c5c4113dSnw141292 { 237cd37da74Snw141292 char *domain; 238*1fcced4cSJordan Brown int err1; 239cd37da74Snw141292 240cd37da74Snw141292 assert(dn != NULL); 241cd37da74Snw141292 2422b4a7802SBaban Kenkre if ((domain = adutils_dn2dns(dn)) == NULL) 243cd37da74Snw141292 goto out; 244cd37da74Snw141292 245e8c27ec8Sbaban if (q->ecanonname != NULL && san != NULL) { 246e8c27ec8Sbaban /* Check that this is the canonname that we were looking for */ 247cd37da74Snw141292 if (u8_strcmp(q->ecanonname, san, 0, 248cd37da74Snw141292 U8_STRCMP_CI_LOWER, /* no normalization, for now */ 249e8c27ec8Sbaban U8_UNICODE_LATEST, &err1) != 0 || err1 != 0) 250e8c27ec8Sbaban goto out; 251e8c27ec8Sbaban } 252e8c27ec8Sbaban 253e8c27ec8Sbaban if (q->edomain != NULL) { 254e8c27ec8Sbaban /* Check that this is the domain that we were looking for */ 255*1fcced4cSJordan Brown if (!domain_eq(q->edomain, domain)) 256cd37da74Snw141292 goto out; 257e8c27ec8Sbaban } 258cd37da74Snw141292 25948258c6bSjp151216 /* Copy the DN and attr and value */ 26048258c6bSjp151216 if (q->dn != NULL) 26148258c6bSjp151216 *q->dn = strdup(dn); 26248258c6bSjp151216 26348258c6bSjp151216 if (q->attr != NULL && attr != NULL) 26448258c6bSjp151216 *q->attr = strdup(attr); 26548258c6bSjp151216 26648258c6bSjp151216 if (q->value != NULL && unixname != NULL) 26748258c6bSjp151216 *q->value = strdup(unixname); 26848258c6bSjp151216 269e8c27ec8Sbaban /* Set results */ 270e8c27ec8Sbaban if (q->sid) { 271e8c27ec8Sbaban *q->sid = sid; 272cd37da74Snw141292 sid = NULL; 273e8c27ec8Sbaban } 274e8c27ec8Sbaban if (q->rid) 275e8c27ec8Sbaban *q->rid = rid; 276e8c27ec8Sbaban if (q->sid_type) 277cd37da74Snw141292 *q->sid_type = sid_type; 278e8c27ec8Sbaban if (q->unixname) { 279e8c27ec8Sbaban *q->unixname = unixname; 280e8c27ec8Sbaban unixname = NULL; 281e8c27ec8Sbaban } 282cd37da74Snw141292 if (q->domain != NULL) { 283cd37da74Snw141292 *q->domain = domain; 284cd37da74Snw141292 domain = NULL; 285e8c27ec8Sbaban } 286e8c27ec8Sbaban if (q->canonname != NULL) { 287479ac375Sdm199847 /* 288479ac375Sdm199847 * The caller may be replacing the given winname by its 289479ac375Sdm199847 * canonical name and therefore free any old name before 290479ac375Sdm199847 * overwriting the field by the canonical name. 291479ac375Sdm199847 */ 292479ac375Sdm199847 free(*q->canonname); 293e8c27ec8Sbaban *q->canonname = san; 294cd37da74Snw141292 san = NULL; 295cd37da74Snw141292 } 296cd37da74Snw141292 2972b4a7802SBaban Kenkre q->ad_rc = ADUTILS_SUCCESS; 298cd37da74Snw141292 299cd37da74Snw141292 out: 300cd37da74Snw141292 /* Free unused attribute values */ 301cd37da74Snw141292 free(san); 302cd37da74Snw141292 free(sid); 303cd37da74Snw141292 free(domain); 304e8c27ec8Sbaban free(unixname); 305c5c4113dSnw141292 } 306c5c4113dSnw141292 307c5c4113dSnw141292 #define BVAL_CASEEQ(bv, str) \ 308c5c4113dSnw141292 (((*(bv))->bv_len == (sizeof (str) - 1)) && \ 309c5c4113dSnw141292 strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0) 310c5c4113dSnw141292 311c5c4113dSnw141292 /* 312cd37da74Snw141292 * Extract the class of the result entry. Returns 1 on success, 0 on 313cd37da74Snw141292 * failure. 314c5c4113dSnw141292 */ 315c5c4113dSnw141292 static 316e3c2d6aaSnw141292 int 317cd37da74Snw141292 idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type) 318c5c4113dSnw141292 { 319c5c4113dSnw141292 BerValue **cbval; 320c5c4113dSnw141292 321cd37da74Snw141292 *sid_type = _IDMAP_T_OTHER; 322c5c4113dSnw141292 if (bvalues == NULL) 323e3c2d6aaSnw141292 return (0); 324c5c4113dSnw141292 325cd37da74Snw141292 /* 326cd37da74Snw141292 * We iterate over all the values because computer is a 327cd37da74Snw141292 * sub-class of user. 328cd37da74Snw141292 */ 329c5c4113dSnw141292 for (cbval = bvalues; *cbval != NULL; cbval++) { 330c5c4113dSnw141292 if (BVAL_CASEEQ(cbval, "Computer")) { 331cd37da74Snw141292 *sid_type = _IDMAP_T_COMPUTER; 332cd37da74Snw141292 break; 333c5c4113dSnw141292 } else if (BVAL_CASEEQ(cbval, "Group")) { 334cd37da74Snw141292 *sid_type = _IDMAP_T_GROUP; 335cd37da74Snw141292 break; 336c5c4113dSnw141292 } else if (BVAL_CASEEQ(cbval, "USER")) { 337cd37da74Snw141292 *sid_type = _IDMAP_T_USER; 338cd37da74Snw141292 /* Continue looping -- this may be a computer yet */ 339cd37da74Snw141292 } 340cd37da74Snw141292 /* 341cd37da74Snw141292 * "else if (*sid_type = _IDMAP_T_USER)" then this is a 342cd37da74Snw141292 * new sub-class of user -- what to do with it?? 343cd37da74Snw141292 */ 344c5c4113dSnw141292 } 345e3c2d6aaSnw141292 346e3c2d6aaSnw141292 return (1); 347c5c4113dSnw141292 } 348c5c4113dSnw141292 349c5c4113dSnw141292 /* 350c5c4113dSnw141292 * Handle a given search result entry 351c5c4113dSnw141292 */ 352c5c4113dSnw141292 static 353c5c4113dSnw141292 void 3542b4a7802SBaban Kenkre idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q, 3552b4a7802SBaban Kenkre LDAPMessage *res, LDAP *ld) 356c5c4113dSnw141292 { 357c5c4113dSnw141292 BerElement *ber = NULL; 358c5c4113dSnw141292 BerValue **bvalues; 359cd37da74Snw141292 char *attr; 360e8c27ec8Sbaban const char *unixuser_attr = NULL; 361e8c27ec8Sbaban const char *unixgroup_attr = NULL; 362e8c27ec8Sbaban char *unixuser = NULL; 363e8c27ec8Sbaban char *unixgroup = NULL; 364cd37da74Snw141292 char *dn = NULL; 365cd37da74Snw141292 char *san = NULL; 366cd37da74Snw141292 char *sid = NULL; 367cd37da74Snw141292 rid_t rid = 0; 368e8c27ec8Sbaban int sid_type = _IDMAP_T_UNDEF; 369e3c2d6aaSnw141292 int has_class, has_san, has_sid; 370e8c27ec8Sbaban int has_unixuser, has_unixgroup; 371e3c2d6aaSnw141292 372e8c27ec8Sbaban assert(q->rc != NULL); 373e8c27ec8Sbaban 3742b4a7802SBaban Kenkre if ((dn = ldap_get_dn(ld, res)) == NULL) 375c5c4113dSnw141292 return; 376c5c4113dSnw141292 377e3c2d6aaSnw141292 assert(q->domain == NULL || *q->domain == NULL); 378c5c4113dSnw141292 379e8c27ec8Sbaban /* 380e8c27ec8Sbaban * If the caller has requested unixname then determine the 381e8c27ec8Sbaban * AD attribute name that will have the unixname. 382e8c27ec8Sbaban */ 383e8c27ec8Sbaban if (q->unixname != NULL) { 384e8c27ec8Sbaban if (q->eunixtype == _IDMAP_T_USER) 385e8c27ec8Sbaban unixuser_attr = state->ad_unixuser_attr; 386e8c27ec8Sbaban else if (q->eunixtype == _IDMAP_T_GROUP) 387e8c27ec8Sbaban unixgroup_attr = state->ad_unixgroup_attr; 388e8c27ec8Sbaban else if (q->eunixtype == _IDMAP_T_UNDEF) { 389e8c27ec8Sbaban /* 390e8c27ec8Sbaban * This is the case where we don't know 391e8c27ec8Sbaban * before hand whether we need unixuser 392e8c27ec8Sbaban * or unixgroup. This will be determined 393e8c27ec8Sbaban * by the "sid_type" (i.e whether the given 394e8c27ec8Sbaban * winname is user or group). If sid_type 395e8c27ec8Sbaban * turns out to be user we will return 396e8c27ec8Sbaban * unixuser (if found) and if it is a group 397e8c27ec8Sbaban * we will return unixgroup (if found). We 398e8c27ec8Sbaban * lookup for both ad_unixuser_attr and 399e8c27ec8Sbaban * ad_unixgroup_attr and discard one of them 400e8c27ec8Sbaban * after we know the "sidtype". This 401e8c27ec8Sbaban * supports the following type of lookups. 402e8c27ec8Sbaban * 403e8c27ec8Sbaban * Example: 404e8c27ec8Sbaban * $idmap show -c winname:foo 405e8c27ec8Sbaban * In the above example, idmap will 406e8c27ec8Sbaban * return uid if winname is winuser 407e8c27ec8Sbaban * and gid if winname is wingroup. 408e8c27ec8Sbaban */ 409e8c27ec8Sbaban unixuser_attr = state->ad_unixuser_attr; 410e8c27ec8Sbaban unixgroup_attr = state->ad_unixgroup_attr; 411e8c27ec8Sbaban } 412e8c27ec8Sbaban } 413e8c27ec8Sbaban 414e8c27ec8Sbaban has_class = has_san = has_sid = has_unixuser = has_unixgroup = 0; 4152b4a7802SBaban Kenkre for (attr = ldap_first_attribute(ld, res, &ber); attr != NULL; 4162b4a7802SBaban Kenkre attr = ldap_next_attribute(ld, res, ber)) { 417c5c4113dSnw141292 bvalues = NULL; /* for memory management below */ 418c5c4113dSnw141292 419c5c4113dSnw141292 /* 420c5c4113dSnw141292 * If this is an attribute we are looking for and 421c5c4113dSnw141292 * haven't seen it yet, parse it 422c5c4113dSnw141292 */ 423e8c27ec8Sbaban if (q->sid != NULL && !has_sid && 424e3c2d6aaSnw141292 strcasecmp(attr, OBJSID) == 0) { 4252b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 4262b4a7802SBaban Kenkre if (bvalues != NULL) { 4272b4a7802SBaban Kenkre sid = adutils_bv_objsid2sidstr( 4282b4a7802SBaban Kenkre bvalues[0], &rid); 429cd37da74Snw141292 has_sid = (sid != NULL); 4302b4a7802SBaban Kenkre } 431e3c2d6aaSnw141292 } else if (!has_san && strcasecmp(attr, SAN) == 0) { 4322b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 4332b4a7802SBaban Kenkre if (bvalues != NULL) { 4342b4a7802SBaban Kenkre san = adutils_bv_name2str(bvalues[0]); 435cd37da74Snw141292 has_san = (san != NULL); 4362b4a7802SBaban Kenkre } 437e3c2d6aaSnw141292 } else if (!has_class && strcasecmp(attr, OBJCLASS) == 0) { 4382b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 439cd37da74Snw141292 has_class = idmap_bv_objclass2sidtype(bvalues, 440cd37da74Snw141292 &sid_type); 441e8c27ec8Sbaban if (has_class && q->unixname != NULL && 442e8c27ec8Sbaban q->eunixtype == _IDMAP_T_UNDEF) { 443e8c27ec8Sbaban /* 444e8c27ec8Sbaban * This is the case where we didn't 445e8c27ec8Sbaban * know whether we wanted unixuser or 446e8c27ec8Sbaban * unixgroup as described above. 447e8c27ec8Sbaban * Now since we know the "sid_type" 448e8c27ec8Sbaban * we discard the unwanted value 449e8c27ec8Sbaban * if it was retrieved before we 450e8c27ec8Sbaban * got here. 451e8c27ec8Sbaban */ 452e8c27ec8Sbaban if (sid_type == _IDMAP_T_USER) { 453e8c27ec8Sbaban free(unixgroup); 454e8c27ec8Sbaban unixgroup_attr = unixgroup = NULL; 455e8c27ec8Sbaban } else if (sid_type == _IDMAP_T_GROUP) { 456e8c27ec8Sbaban free(unixuser); 457e8c27ec8Sbaban unixuser_attr = unixuser = NULL; 458e8c27ec8Sbaban } else { 459e8c27ec8Sbaban free(unixuser); 460e8c27ec8Sbaban free(unixgroup); 461e8c27ec8Sbaban unixuser_attr = unixuser = NULL; 462e8c27ec8Sbaban unixgroup_attr = unixgroup = NULL; 463e8c27ec8Sbaban } 464e8c27ec8Sbaban } 465e8c27ec8Sbaban } else if (!has_unixuser && unixuser_attr != NULL && 466e8c27ec8Sbaban strcasecmp(attr, unixuser_attr) == 0) { 4672b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 4682b4a7802SBaban Kenkre if (bvalues != NULL) { 4692b4a7802SBaban Kenkre unixuser = adutils_bv_name2str(bvalues[0]); 470e8c27ec8Sbaban has_unixuser = (unixuser != NULL); 4712b4a7802SBaban Kenkre } 47248258c6bSjp151216 473e8c27ec8Sbaban } else if (!has_unixgroup && unixgroup_attr != NULL && 474e8c27ec8Sbaban strcasecmp(attr, unixgroup_attr) == 0) { 4752b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 4762b4a7802SBaban Kenkre if (bvalues != NULL) { 4772b4a7802SBaban Kenkre unixgroup = adutils_bv_name2str(bvalues[0]); 478e8c27ec8Sbaban has_unixgroup = (unixgroup != NULL); 479c5c4113dSnw141292 } 4802b4a7802SBaban Kenkre } 481c5c4113dSnw141292 482c5c4113dSnw141292 if (bvalues != NULL) 483c5c4113dSnw141292 ldap_value_free_len(bvalues); 484c5c4113dSnw141292 ldap_memfree(attr); 485c5c4113dSnw141292 486cd37da74Snw141292 if (has_class && has_san && 487e8c27ec8Sbaban (q->sid == NULL || has_sid) && 488e8c27ec8Sbaban (unixuser_attr == NULL || has_unixuser) && 489e8c27ec8Sbaban (unixgroup_attr == NULL || has_unixgroup)) { 490e8c27ec8Sbaban /* Got what we need */ 491e3c2d6aaSnw141292 break; 492c5c4113dSnw141292 } 493e3c2d6aaSnw141292 } 494e3c2d6aaSnw141292 495e8c27ec8Sbaban if (!has_class) { 496e8c27ec8Sbaban /* 497e8c27ec8Sbaban * Didn't find objectclass. Something's wrong with our 498e8c27ec8Sbaban * AD data. 499e8c27ec8Sbaban */ 500e8c27ec8Sbaban free(san); 501e8c27ec8Sbaban free(sid); 502e8c27ec8Sbaban free(unixuser); 503e8c27ec8Sbaban free(unixgroup); 504e8c27ec8Sbaban } else { 505e8c27ec8Sbaban /* 506e8c27ec8Sbaban * Either we got what we needed and came out of the loop 507e8c27ec8Sbaban * early OR we completed the loop in which case we didn't 508e8c27ec8Sbaban * find some attributes that we were looking for. In either 509e8c27ec8Sbaban * case set the result with what we got. 510e8c27ec8Sbaban */ 51148258c6bSjp151216 idmap_setqresults(q, san, dn, 51248258c6bSjp151216 (unixuser != NULL) ? unixuser_attr : unixgroup_attr, 51348258c6bSjp151216 sid, rid, sid_type, 514e8c27ec8Sbaban (unixuser != NULL) ? unixuser : unixgroup); 515e8c27ec8Sbaban } 516e8c27ec8Sbaban 517c5c4113dSnw141292 if (ber != NULL) 518c5c4113dSnw141292 ber_free(ber, 0); 519c5c4113dSnw141292 520c5c4113dSnw141292 ldap_memfree(dn); 521c5c4113dSnw141292 } 522c5c4113dSnw141292 5232b4a7802SBaban Kenkre void 5242b4a7802SBaban Kenkre idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, int qid, 5252b4a7802SBaban Kenkre void *argp) 526c5c4113dSnw141292 { 5272b4a7802SBaban Kenkre idmap_query_state_t *state = (idmap_query_state_t *)argp; 5282b4a7802SBaban Kenkre idmap_q_t *q = &(state->queries[qid]); 529c5c4113dSnw141292 530c5c4113dSnw141292 switch (rc) { 531c5c4113dSnw141292 case LDAP_RES_SEARCH_RESULT: 5322b4a7802SBaban Kenkre if (q->search_res != NULL) { 5332b4a7802SBaban Kenkre idmap_extract_object(state, q, q->search_res, ld); 5342b4a7802SBaban Kenkre (void) ldap_msgfree(q->search_res); 5352b4a7802SBaban Kenkre q->search_res = NULL; 536bcced03bSjp151216 } else 5372b4a7802SBaban Kenkre q->ad_rc = ADUTILS_ERR_NOTFOUND; 538c5c4113dSnw141292 break; 539c5c4113dSnw141292 case LDAP_RES_SEARCH_ENTRY: 5402b4a7802SBaban Kenkre if (q->search_res == NULL) { 5412b4a7802SBaban Kenkre q->search_res = *res; 5422b4a7802SBaban Kenkre *res = NULL; 543bcced03bSjp151216 } 544c5c4113dSnw141292 break; 545c5c4113dSnw141292 default: 546c5c4113dSnw141292 break; 547c5c4113dSnw141292 } 54884decf41Sjp151216 } 54984decf41Sjp151216 550e3c2d6aaSnw141292 static 551e3c2d6aaSnw141292 void 552e3c2d6aaSnw141292 idmap_cleanup_batch(idmap_query_state_t *batch) 553e3c2d6aaSnw141292 { 554e3c2d6aaSnw141292 int i; 555e3c2d6aaSnw141292 556e3c2d6aaSnw141292 for (i = 0; i < batch->qcount; i++) { 557cd37da74Snw141292 if (batch->queries[i].ecanonname != NULL) 558cd37da74Snw141292 free(batch->queries[i].ecanonname); 559cd37da74Snw141292 batch->queries[i].ecanonname = NULL; 560cd37da74Snw141292 if (batch->queries[i].edomain != NULL) 561cd37da74Snw141292 free(batch->queries[i].edomain); 562cd37da74Snw141292 batch->queries[i].edomain = NULL; 563e3c2d6aaSnw141292 } 564e3c2d6aaSnw141292 } 565e3c2d6aaSnw141292 56684decf41Sjp151216 /* 56784decf41Sjp151216 * This routine frees the idmap_query_state_t structure 56884decf41Sjp151216 */ 569c5c4113dSnw141292 void 57084decf41Sjp151216 idmap_lookup_release_batch(idmap_query_state_t **state) 571c5c4113dSnw141292 { 5722b4a7802SBaban Kenkre if (state == NULL || *state == NULL) 5732b4a7802SBaban Kenkre return; 5742b4a7802SBaban Kenkre adutils_lookup_batch_release(&(*state)->qs); 575e3c2d6aaSnw141292 idmap_cleanup_batch(*state); 576c5c4113dSnw141292 free(*state); 577c5c4113dSnw141292 *state = NULL; 578c5c4113dSnw141292 } 579c5c4113dSnw141292 580c5c4113dSnw141292 idmap_retcode 5810dcc7149Snw141292 idmap_lookup_batch_end(idmap_query_state_t **state) 582c5c4113dSnw141292 { 5832b4a7802SBaban Kenkre adutils_rc ad_rc; 5842b4a7802SBaban Kenkre int i; 5852b4a7802SBaban Kenkre idmap_query_state_t *id_qs = *state; 586c5c4113dSnw141292 5872b4a7802SBaban Kenkre ad_rc = adutils_lookup_batch_end(&id_qs->qs); 588c5c4113dSnw141292 5892b4a7802SBaban Kenkre /* 5902b4a7802SBaban Kenkre * Map adutils rc to idmap_retcode in each 5912b4a7802SBaban Kenkre * query because consumers in dbutils.c 5922b4a7802SBaban Kenkre * expects idmap_retcode. 5932b4a7802SBaban Kenkre */ 5942b4a7802SBaban Kenkre for (i = 0; i < id_qs->qcount; i++) { 5952b4a7802SBaban Kenkre *id_qs->queries[i].rc = 5962b4a7802SBaban Kenkre map_adrc2idmaprc(id_qs->queries[i].ad_rc); 597c5c4113dSnw141292 } 59884decf41Sjp151216 idmap_lookup_release_batch(state); 5992b4a7802SBaban Kenkre return (map_adrc2idmaprc(ad_rc)); 600c5c4113dSnw141292 } 601c5c4113dSnw141292 602c5c4113dSnw141292 /* 603c5c4113dSnw141292 * Send one prepared search, queue up msgid, process what results are 604c5c4113dSnw141292 * available 605c5c4113dSnw141292 */ 606c5c4113dSnw141292 static 607c5c4113dSnw141292 idmap_retcode 60848258c6bSjp151216 idmap_batch_add1(idmap_query_state_t *state, const char *filter, 60948258c6bSjp151216 char *ecanonname, char *edomain, int eunixtype, 61048258c6bSjp151216 char **dn, char **attr, char **value, 61148258c6bSjp151216 char **canonname, char **dname, 61248258c6bSjp151216 char **sid, rid_t *rid, int *sid_type, char **unixname, 61348258c6bSjp151216 idmap_retcode *rc) 614c5c4113dSnw141292 { 6152b4a7802SBaban Kenkre adutils_rc ad_rc; 6162b4a7802SBaban Kenkre int qid, i; 617c5c4113dSnw141292 idmap_q_t *q; 618cd37da74Snw141292 static char *attrs[] = { 619cd37da74Snw141292 SAN, 620cd37da74Snw141292 OBJSID, 621cd37da74Snw141292 OBJCLASS, 622e8c27ec8Sbaban NULL, /* placeholder for unixname attr */ 623e8c27ec8Sbaban NULL, /* placeholder for unixname attr */ 624cd37da74Snw141292 NULL 625cd37da74Snw141292 }; 626c5c4113dSnw141292 6274d61c878SJulian Pullen qid = atomic_inc_32_nv(&state->qcount) - 1; 628c5c4113dSnw141292 q = &(state->queries[qid]); 629c5c4113dSnw141292 6304d61c878SJulian Pullen assert(qid < state->qsize); 6314d61c878SJulian Pullen 632cd37da74Snw141292 /* 6332b4a7802SBaban Kenkre * Remember the expected canonname, domainname and unix type 6342b4a7802SBaban Kenkre * so we can check the results * against it 635cd37da74Snw141292 */ 636cd37da74Snw141292 q->ecanonname = ecanonname; 637cd37da74Snw141292 q->edomain = edomain; 638e8c27ec8Sbaban q->eunixtype = eunixtype; 639e3c2d6aaSnw141292 640c5c4113dSnw141292 /* Remember where to put the results */ 641cd37da74Snw141292 q->canonname = canonname; 642e8c27ec8Sbaban q->sid = sid; 643c5c4113dSnw141292 q->domain = dname; 644c5c4113dSnw141292 q->rid = rid; 645c5c4113dSnw141292 q->sid_type = sid_type; 646c5c4113dSnw141292 q->rc = rc; 647e8c27ec8Sbaban q->unixname = unixname; 64848258c6bSjp151216 q->dn = dn; 64948258c6bSjp151216 q->attr = attr; 65048258c6bSjp151216 q->value = value; 651e8c27ec8Sbaban 652e8c27ec8Sbaban /* Add unixuser/unixgroup attribute names to the attrs list */ 653e8c27ec8Sbaban if (unixname != NULL) { 654e8c27ec8Sbaban i = 3; 655e8c27ec8Sbaban if (eunixtype != _IDMAP_T_GROUP && 656e8c27ec8Sbaban state->ad_unixuser_attr != NULL) 657e8c27ec8Sbaban attrs[i++] = (char *)state->ad_unixuser_attr; 658e8c27ec8Sbaban if (eunixtype != _IDMAP_T_USER && 659e8c27ec8Sbaban state->ad_unixgroup_attr != NULL) 660e8c27ec8Sbaban attrs[i] = (char *)state->ad_unixgroup_attr; 661e8c27ec8Sbaban } 662c5c4113dSnw141292 663c5c4113dSnw141292 /* 664c5c4113dSnw141292 * Provide sane defaults for the results in case we never hear 665c5c4113dSnw141292 * back from the DS before closing the connection. 666e3c2d6aaSnw141292 * 667e3c2d6aaSnw141292 * In particular we default the result to indicate a retriable 668e3c2d6aaSnw141292 * error. The first complete matching result entry will cause 669e3c2d6aaSnw141292 * this to be set to IDMAP_SUCCESS, and the end of the results 670e3c2d6aaSnw141292 * for this search will cause this to indicate "not found" if no 671e3c2d6aaSnw141292 * result entries arrived or no complete ones matched the lookup 672e3c2d6aaSnw141292 * we were doing. 673c5c4113dSnw141292 */ 674c5c4113dSnw141292 *rc = IDMAP_ERR_RETRIABLE_NET_ERR; 675e8c27ec8Sbaban if (sid_type != NULL) 676c5c4113dSnw141292 *sid_type = _IDMAP_T_OTHER; 677e8c27ec8Sbaban if (sid != NULL) 678e8c27ec8Sbaban *sid = NULL; 679c5c4113dSnw141292 if (dname != NULL) 680c5c4113dSnw141292 *dname = NULL; 681c5c4113dSnw141292 if (rid != NULL) 682c5c4113dSnw141292 *rid = 0; 68348258c6bSjp151216 if (dn != NULL) 68448258c6bSjp151216 *dn = NULL; 68548258c6bSjp151216 if (attr != NULL) 68648258c6bSjp151216 *attr = NULL; 68748258c6bSjp151216 if (value != NULL) 68848258c6bSjp151216 *value = NULL; 689c5c4113dSnw141292 690479ac375Sdm199847 /* 691479ac375Sdm199847 * Don't set *canonname to NULL because it may be pointing to the 692479ac375Sdm199847 * given winname. Later on if we get a canonical name from AD the 693479ac375Sdm199847 * old name if any will be freed before assigning the new name. 694479ac375Sdm199847 */ 695479ac375Sdm199847 696c5c4113dSnw141292 /* 6972b4a7802SBaban Kenkre * Invoke the mother of all APIs i.e. the adutils API 698c5c4113dSnw141292 */ 6992b4a7802SBaban Kenkre ad_rc = adutils_lookup_batch_add(state->qs, filter, 7002b4a7802SBaban Kenkre (const char **)attrs, 7012b4a7802SBaban Kenkre edomain, &q->result, &q->ad_rc); 7022b4a7802SBaban Kenkre return (map_adrc2idmaprc(ad_rc)); 703c5c4113dSnw141292 } 704c5c4113dSnw141292 705c5c4113dSnw141292 idmap_retcode 706c5c4113dSnw141292 idmap_name2sid_batch_add1(idmap_query_state_t *state, 707e8c27ec8Sbaban const char *name, const char *dname, int eunixtype, 70848258c6bSjp151216 char **dn, char **attr, char **value, 70948258c6bSjp151216 char **canonname, char **sid, rid_t *rid, 71048258c6bSjp151216 int *sid_type, char **unixname, idmap_retcode *rc) 711c5c4113dSnw141292 { 712c5c4113dSnw141292 idmap_retcode retcode; 713e3c2d6aaSnw141292 int len, samAcctNameLen; 714479ac375Sdm199847 char *filter = NULL, *s_name; 715cd37da74Snw141292 char *ecanonname, *edomain; /* expected canonname */ 716c5c4113dSnw141292 717c5c4113dSnw141292 /* 718e3c2d6aaSnw141292 * Strategy: search the global catalog for user/group by 719e3c2d6aaSnw141292 * sAMAccountName = user/groupname with "" as the base DN and by 720e3c2d6aaSnw141292 * userPrincipalName = user/groupname@domain. The result 721e3c2d6aaSnw141292 * entries will be checked to conform to the name and domain 722e3c2d6aaSnw141292 * name given here. The DN, sAMAccountName, userPrincipalName, 723e3c2d6aaSnw141292 * objectSid and objectClass of the result entries are all we 724e3c2d6aaSnw141292 * need to figure out which entries match the lookup, the SID of 725e3c2d6aaSnw141292 * the user/group and whether it is a user or a group. 726c5c4113dSnw141292 */ 727c5c4113dSnw141292 728c5c4113dSnw141292 /* 729e3c2d6aaSnw141292 * We need the name and the domain name separately and as 730e3c2d6aaSnw141292 * name@domain. We also allow the domain to be provided 731e3c2d6aaSnw141292 * separately. 732c5c4113dSnw141292 */ 733d3a612caSnw141292 samAcctNameLen = strlen(name); 734e3c2d6aaSnw141292 735cd37da74Snw141292 if ((ecanonname = strdup(name)) == NULL) 736e3c2d6aaSnw141292 return (IDMAP_ERR_MEMORY); 737cd37da74Snw141292 738cd37da74Snw141292 if (dname == NULL || *dname == '\0') { 739cd37da74Snw141292 if ((dname = strchr(name, '@')) != NULL) { 740cd37da74Snw141292 /* 'name' is qualified with a domain name */ 741cd37da74Snw141292 if ((edomain = strdup(dname + 1)) == NULL) { 742cd37da74Snw141292 free(ecanonname); 743cd37da74Snw141292 return (IDMAP_ERR_MEMORY); 744cd37da74Snw141292 } 745cd37da74Snw141292 *strchr(ecanonname, '@') = '\0'; 746c5c4113dSnw141292 } else { 7472b4a7802SBaban Kenkre /* 'name' not qualified and dname not given */ 7484d61c878SJulian Pullen dname = adutils_lookup_batch_getdefdomain(state->qs); 7492b4a7802SBaban Kenkre assert(dname != NULL); 7502b4a7802SBaban Kenkre if (*dname == '\0') { 751cd37da74Snw141292 free(ecanonname); 752e3c2d6aaSnw141292 return (IDMAP_ERR_DOMAIN); 753e3c2d6aaSnw141292 } 7542b4a7802SBaban Kenkre edomain = strdup(dname); 755cd37da74Snw141292 if (edomain == NULL) { 756cd37da74Snw141292 free(ecanonname); 757e3c2d6aaSnw141292 return (IDMAP_ERR_MEMORY); 758cd37da74Snw141292 } 759cd37da74Snw141292 } 760cd37da74Snw141292 } else { 761cd37da74Snw141292 if ((edomain = strdup(dname)) == NULL) { 762cd37da74Snw141292 free(ecanonname); 763cd37da74Snw141292 return (IDMAP_ERR_MEMORY); 764cd37da74Snw141292 } 765e3c2d6aaSnw141292 } 766c5c4113dSnw141292 7674d61c878SJulian Pullen if (!adutils_lookup_check_domain(state->qs, dname)) { 7684d61c878SJulian Pullen free(ecanonname); 7694d61c878SJulian Pullen free(edomain); 7704d61c878SJulian Pullen return (IDMAP_ERR_DOMAIN_NOTFOUND); 7714d61c878SJulian Pullen } 7724d61c878SJulian Pullen 773479ac375Sdm199847 s_name = sanitize_for_ldap_filter(name); 774479ac375Sdm199847 if (s_name == NULL) { 775cd37da74Snw141292 free(ecanonname); 776479ac375Sdm199847 free(edomain); 777c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 778c5c4113dSnw141292 } 779479ac375Sdm199847 780479ac375Sdm199847 /* Assemble filter */ 781479ac375Sdm199847 len = snprintf(NULL, 0, SANFILTER, samAcctNameLen, s_name) + 1; 782479ac375Sdm199847 if ((filter = (char *)malloc(len)) == NULL) { 783479ac375Sdm199847 free(ecanonname); 784479ac375Sdm199847 free(edomain); 785479ac375Sdm199847 if (s_name != name) 786479ac375Sdm199847 free(s_name); 787479ac375Sdm199847 return (IDMAP_ERR_MEMORY); 788479ac375Sdm199847 } 789479ac375Sdm199847 (void) snprintf(filter, len, SANFILTER, samAcctNameLen, s_name); 790479ac375Sdm199847 if (s_name != name) 791479ac375Sdm199847 free(s_name); 792c5c4113dSnw141292 793cd37da74Snw141292 retcode = idmap_batch_add1(state, filter, ecanonname, edomain, 79448258c6bSjp151216 eunixtype, dn, attr, value, canonname, NULL, sid, rid, sid_type, 79548258c6bSjp151216 unixname, rc); 796c5c4113dSnw141292 797c5c4113dSnw141292 free(filter); 798c5c4113dSnw141292 799c5c4113dSnw141292 return (retcode); 800c5c4113dSnw141292 } 801c5c4113dSnw141292 802c5c4113dSnw141292 idmap_retcode 803c5c4113dSnw141292 idmap_sid2name_batch_add1(idmap_query_state_t *state, 804e8c27ec8Sbaban const char *sid, const rid_t *rid, int eunixtype, 80548258c6bSjp151216 char **dn, char **attr, char **value, 80648258c6bSjp151216 char **name, char **dname, int *sid_type, 80748258c6bSjp151216 char **unixname, idmap_retcode *rc) 808c5c4113dSnw141292 { 809c5c4113dSnw141292 idmap_retcode retcode; 810c5c4113dSnw141292 int flen, ret; 811c5c4113dSnw141292 char *filter = NULL; 8122b4a7802SBaban Kenkre char cbinsid[ADUTILS_MAXHEXBINSID + 1]; 813c5c4113dSnw141292 814c5c4113dSnw141292 /* 815c5c4113dSnw141292 * Strategy: search [the global catalog] for user/group by 816c5c4113dSnw141292 * objectSid = SID with empty base DN. The DN, sAMAccountName 817c5c4113dSnw141292 * and objectClass of the result are all we need to figure out 818c5c4113dSnw141292 * the name of the SID and whether it is a user, a group or a 819c5c4113dSnw141292 * computer. 820c5c4113dSnw141292 */ 821c5c4113dSnw141292 8224d61c878SJulian Pullen if (!adutils_lookup_check_sid_prefix(state->qs, sid)) 8234d61c878SJulian Pullen return (IDMAP_ERR_DOMAIN_NOTFOUND); 8244d61c878SJulian Pullen 8252b4a7802SBaban Kenkre ret = adutils_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid)); 826c5c4113dSnw141292 if (ret != 0) 827c5c4113dSnw141292 return (IDMAP_ERR_SID); 828c5c4113dSnw141292 829c5c4113dSnw141292 /* Assemble filter */ 830e3c2d6aaSnw141292 flen = snprintf(NULL, 0, OBJSIDFILTER, cbinsid) + 1; 831c5c4113dSnw141292 if ((filter = (char *)malloc(flen)) == NULL) 832c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 833e3c2d6aaSnw141292 (void) snprintf(filter, flen, OBJSIDFILTER, cbinsid); 834c5c4113dSnw141292 835e8c27ec8Sbaban retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype, 83648258c6bSjp151216 dn, attr, value, name, dname, NULL, NULL, sid_type, unixname, rc); 837e8c27ec8Sbaban 838e8c27ec8Sbaban free(filter); 839e8c27ec8Sbaban 840e8c27ec8Sbaban return (retcode); 841e8c27ec8Sbaban } 842e8c27ec8Sbaban 843e8c27ec8Sbaban idmap_retcode 844e8c27ec8Sbaban idmap_unixname2sid_batch_add1(idmap_query_state_t *state, 845e8c27ec8Sbaban const char *unixname, int is_user, int is_wuser, 84648258c6bSjp151216 char **dn, char **attr, char **value, 84748258c6bSjp151216 char **sid, rid_t *rid, char **name, 84848258c6bSjp151216 char **dname, int *sid_type, idmap_retcode *rc) 849e8c27ec8Sbaban { 850e8c27ec8Sbaban idmap_retcode retcode; 851e8c27ec8Sbaban int len, ulen; 852479ac375Sdm199847 char *filter = NULL, *s_unixname; 853e8c27ec8Sbaban const char *attrname = NULL; 854e8c27ec8Sbaban 855e8c27ec8Sbaban /* Get unixuser or unixgroup AD attribute name */ 856e8c27ec8Sbaban attrname = (is_user) ? 857e8c27ec8Sbaban state->ad_unixuser_attr : state->ad_unixgroup_attr; 858e8c27ec8Sbaban if (attrname == NULL) 859e8c27ec8Sbaban return (IDMAP_ERR_NOTFOUND); 860e8c27ec8Sbaban 861479ac375Sdm199847 s_unixname = sanitize_for_ldap_filter(unixname); 862479ac375Sdm199847 if (s_unixname == NULL) 863479ac375Sdm199847 return (IDMAP_ERR_MEMORY); 864479ac375Sdm199847 865e8c27ec8Sbaban /* Assemble filter */ 866e8c27ec8Sbaban ulen = strlen(unixname); 867e8c27ec8Sbaban len = snprintf(NULL, 0, "(&(objectclass=%s)(%s=%.*s))", 868479ac375Sdm199847 is_wuser ? "user" : "group", attrname, ulen, s_unixname) + 1; 869479ac375Sdm199847 if ((filter = (char *)malloc(len)) == NULL) { 870479ac375Sdm199847 if (s_unixname != unixname) 871479ac375Sdm199847 free(s_unixname); 872e8c27ec8Sbaban return (IDMAP_ERR_MEMORY); 873479ac375Sdm199847 } 874e8c27ec8Sbaban (void) snprintf(filter, len, "(&(objectclass=%s)(%s=%.*s))", 875479ac375Sdm199847 is_wuser ? "user" : "group", attrname, ulen, s_unixname); 876479ac375Sdm199847 if (s_unixname != unixname) 877479ac375Sdm199847 free(s_unixname); 878e8c27ec8Sbaban 879e8c27ec8Sbaban retcode = idmap_batch_add1(state, filter, NULL, NULL, 88048258c6bSjp151216 _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type, 88148258c6bSjp151216 NULL, rc); 88248258c6bSjp151216 88348258c6bSjp151216 if (retcode == IDMAP_SUCCESS && attr != NULL) { 88448258c6bSjp151216 if ((*attr = strdup(attrname)) == NULL) 88548258c6bSjp151216 retcode = IDMAP_ERR_MEMORY; 88648258c6bSjp151216 } 88748258c6bSjp151216 88848258c6bSjp151216 if (retcode == IDMAP_SUCCESS && value != NULL) { 88948258c6bSjp151216 if (ulen > 0) { 89048258c6bSjp151216 if ((*value = strdup(unixname)) == NULL) 89148258c6bSjp151216 retcode = IDMAP_ERR_MEMORY; 89248258c6bSjp151216 } 89348258c6bSjp151216 else 89448258c6bSjp151216 *value = NULL; 89548258c6bSjp151216 } 896c5c4113dSnw141292 897c5c4113dSnw141292 free(filter); 898c5c4113dSnw141292 899c5c4113dSnw141292 return (retcode); 900c5c4113dSnw141292 } 901