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 /* 234edd44c5Sjp151216 * Copyright 2008 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; 102*4d61c878SJulian Pullen int qsize; /* Queue size */ 103*4d61c878SJulian 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 195*4d61c878SJulian 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 209*4d61c878SJulian 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; 238e8c27ec8Sbaban int err1, err2; 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 */ 255e8c27ec8Sbaban if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER, 256cd37da74Snw141292 U8_UNICODE_LATEST, &err2) != 0 || err2 != 0) 257cd37da74Snw141292 goto out; 258e8c27ec8Sbaban } 259cd37da74Snw141292 26048258c6bSjp151216 /* Copy the DN and attr and value */ 26148258c6bSjp151216 if (q->dn != NULL) 26248258c6bSjp151216 *q->dn = strdup(dn); 26348258c6bSjp151216 26448258c6bSjp151216 if (q->attr != NULL && attr != NULL) 26548258c6bSjp151216 *q->attr = strdup(attr); 26648258c6bSjp151216 26748258c6bSjp151216 if (q->value != NULL && unixname != NULL) 26848258c6bSjp151216 *q->value = strdup(unixname); 26948258c6bSjp151216 270e8c27ec8Sbaban /* Set results */ 271e8c27ec8Sbaban if (q->sid) { 272e8c27ec8Sbaban *q->sid = sid; 273cd37da74Snw141292 sid = NULL; 274e8c27ec8Sbaban } 275e8c27ec8Sbaban if (q->rid) 276e8c27ec8Sbaban *q->rid = rid; 277e8c27ec8Sbaban if (q->sid_type) 278cd37da74Snw141292 *q->sid_type = sid_type; 279e8c27ec8Sbaban if (q->unixname) { 280e8c27ec8Sbaban *q->unixname = unixname; 281e8c27ec8Sbaban unixname = NULL; 282e8c27ec8Sbaban } 283cd37da74Snw141292 if (q->domain != NULL) { 284cd37da74Snw141292 *q->domain = domain; 285cd37da74Snw141292 domain = NULL; 286e8c27ec8Sbaban } 287e8c27ec8Sbaban if (q->canonname != NULL) { 288479ac375Sdm199847 /* 289479ac375Sdm199847 * The caller may be replacing the given winname by its 290479ac375Sdm199847 * canonical name and therefore free any old name before 291479ac375Sdm199847 * overwriting the field by the canonical name. 292479ac375Sdm199847 */ 293479ac375Sdm199847 free(*q->canonname); 294e8c27ec8Sbaban *q->canonname = san; 295cd37da74Snw141292 san = NULL; 296cd37da74Snw141292 } 297cd37da74Snw141292 2982b4a7802SBaban Kenkre q->ad_rc = ADUTILS_SUCCESS; 299cd37da74Snw141292 300cd37da74Snw141292 out: 301cd37da74Snw141292 /* Free unused attribute values */ 302cd37da74Snw141292 free(san); 303cd37da74Snw141292 free(sid); 304cd37da74Snw141292 free(domain); 305e8c27ec8Sbaban free(unixname); 306c5c4113dSnw141292 } 307c5c4113dSnw141292 308c5c4113dSnw141292 #define BVAL_CASEEQ(bv, str) \ 309c5c4113dSnw141292 (((*(bv))->bv_len == (sizeof (str) - 1)) && \ 310c5c4113dSnw141292 strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0) 311c5c4113dSnw141292 312c5c4113dSnw141292 /* 313cd37da74Snw141292 * Extract the class of the result entry. Returns 1 on success, 0 on 314cd37da74Snw141292 * failure. 315c5c4113dSnw141292 */ 316c5c4113dSnw141292 static 317e3c2d6aaSnw141292 int 318cd37da74Snw141292 idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type) 319c5c4113dSnw141292 { 320c5c4113dSnw141292 BerValue **cbval; 321c5c4113dSnw141292 322cd37da74Snw141292 *sid_type = _IDMAP_T_OTHER; 323c5c4113dSnw141292 if (bvalues == NULL) 324e3c2d6aaSnw141292 return (0); 325c5c4113dSnw141292 326cd37da74Snw141292 /* 327cd37da74Snw141292 * We iterate over all the values because computer is a 328cd37da74Snw141292 * sub-class of user. 329cd37da74Snw141292 */ 330c5c4113dSnw141292 for (cbval = bvalues; *cbval != NULL; cbval++) { 331c5c4113dSnw141292 if (BVAL_CASEEQ(cbval, "Computer")) { 332cd37da74Snw141292 *sid_type = _IDMAP_T_COMPUTER; 333cd37da74Snw141292 break; 334c5c4113dSnw141292 } else if (BVAL_CASEEQ(cbval, "Group")) { 335cd37da74Snw141292 *sid_type = _IDMAP_T_GROUP; 336cd37da74Snw141292 break; 337c5c4113dSnw141292 } else if (BVAL_CASEEQ(cbval, "USER")) { 338cd37da74Snw141292 *sid_type = _IDMAP_T_USER; 339cd37da74Snw141292 /* Continue looping -- this may be a computer yet */ 340cd37da74Snw141292 } 341cd37da74Snw141292 /* 342cd37da74Snw141292 * "else if (*sid_type = _IDMAP_T_USER)" then this is a 343cd37da74Snw141292 * new sub-class of user -- what to do with it?? 344cd37da74Snw141292 */ 345c5c4113dSnw141292 } 346e3c2d6aaSnw141292 347e3c2d6aaSnw141292 return (1); 348c5c4113dSnw141292 } 349c5c4113dSnw141292 350c5c4113dSnw141292 /* 351c5c4113dSnw141292 * Handle a given search result entry 352c5c4113dSnw141292 */ 353c5c4113dSnw141292 static 354c5c4113dSnw141292 void 3552b4a7802SBaban Kenkre idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q, 3562b4a7802SBaban Kenkre LDAPMessage *res, LDAP *ld) 357c5c4113dSnw141292 { 358c5c4113dSnw141292 BerElement *ber = NULL; 359c5c4113dSnw141292 BerValue **bvalues; 360cd37da74Snw141292 char *attr; 361e8c27ec8Sbaban const char *unixuser_attr = NULL; 362e8c27ec8Sbaban const char *unixgroup_attr = NULL; 363e8c27ec8Sbaban char *unixuser = NULL; 364e8c27ec8Sbaban char *unixgroup = NULL; 365cd37da74Snw141292 char *dn = NULL; 366cd37da74Snw141292 char *san = NULL; 367cd37da74Snw141292 char *sid = NULL; 368cd37da74Snw141292 rid_t rid = 0; 369e8c27ec8Sbaban int sid_type = _IDMAP_T_UNDEF; 370e3c2d6aaSnw141292 int has_class, has_san, has_sid; 371e8c27ec8Sbaban int has_unixuser, has_unixgroup; 372e3c2d6aaSnw141292 373e8c27ec8Sbaban assert(q->rc != NULL); 374e8c27ec8Sbaban 3752b4a7802SBaban Kenkre if ((dn = ldap_get_dn(ld, res)) == NULL) 376c5c4113dSnw141292 return; 377c5c4113dSnw141292 378e3c2d6aaSnw141292 assert(q->domain == NULL || *q->domain == NULL); 379c5c4113dSnw141292 380e8c27ec8Sbaban /* 381e8c27ec8Sbaban * If the caller has requested unixname then determine the 382e8c27ec8Sbaban * AD attribute name that will have the unixname. 383e8c27ec8Sbaban */ 384e8c27ec8Sbaban if (q->unixname != NULL) { 385e8c27ec8Sbaban if (q->eunixtype == _IDMAP_T_USER) 386e8c27ec8Sbaban unixuser_attr = state->ad_unixuser_attr; 387e8c27ec8Sbaban else if (q->eunixtype == _IDMAP_T_GROUP) 388e8c27ec8Sbaban unixgroup_attr = state->ad_unixgroup_attr; 389e8c27ec8Sbaban else if (q->eunixtype == _IDMAP_T_UNDEF) { 390e8c27ec8Sbaban /* 391e8c27ec8Sbaban * This is the case where we don't know 392e8c27ec8Sbaban * before hand whether we need unixuser 393e8c27ec8Sbaban * or unixgroup. This will be determined 394e8c27ec8Sbaban * by the "sid_type" (i.e whether the given 395e8c27ec8Sbaban * winname is user or group). If sid_type 396e8c27ec8Sbaban * turns out to be user we will return 397e8c27ec8Sbaban * unixuser (if found) and if it is a group 398e8c27ec8Sbaban * we will return unixgroup (if found). We 399e8c27ec8Sbaban * lookup for both ad_unixuser_attr and 400e8c27ec8Sbaban * ad_unixgroup_attr and discard one of them 401e8c27ec8Sbaban * after we know the "sidtype". This 402e8c27ec8Sbaban * supports the following type of lookups. 403e8c27ec8Sbaban * 404e8c27ec8Sbaban * Example: 405e8c27ec8Sbaban * $idmap show -c winname:foo 406e8c27ec8Sbaban * In the above example, idmap will 407e8c27ec8Sbaban * return uid if winname is winuser 408e8c27ec8Sbaban * and gid if winname is wingroup. 409e8c27ec8Sbaban */ 410e8c27ec8Sbaban unixuser_attr = state->ad_unixuser_attr; 411e8c27ec8Sbaban unixgroup_attr = state->ad_unixgroup_attr; 412e8c27ec8Sbaban } 413e8c27ec8Sbaban } 414e8c27ec8Sbaban 415e8c27ec8Sbaban has_class = has_san = has_sid = has_unixuser = has_unixgroup = 0; 4162b4a7802SBaban Kenkre for (attr = ldap_first_attribute(ld, res, &ber); attr != NULL; 4172b4a7802SBaban Kenkre attr = ldap_next_attribute(ld, res, ber)) { 418c5c4113dSnw141292 bvalues = NULL; /* for memory management below */ 419c5c4113dSnw141292 420c5c4113dSnw141292 /* 421c5c4113dSnw141292 * If this is an attribute we are looking for and 422c5c4113dSnw141292 * haven't seen it yet, parse it 423c5c4113dSnw141292 */ 424e8c27ec8Sbaban if (q->sid != NULL && !has_sid && 425e3c2d6aaSnw141292 strcasecmp(attr, OBJSID) == 0) { 4262b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 4272b4a7802SBaban Kenkre if (bvalues != NULL) { 4282b4a7802SBaban Kenkre sid = adutils_bv_objsid2sidstr( 4292b4a7802SBaban Kenkre bvalues[0], &rid); 430cd37da74Snw141292 has_sid = (sid != NULL); 4312b4a7802SBaban Kenkre } 432e3c2d6aaSnw141292 } else if (!has_san && strcasecmp(attr, SAN) == 0) { 4332b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 4342b4a7802SBaban Kenkre if (bvalues != NULL) { 4352b4a7802SBaban Kenkre san = adutils_bv_name2str(bvalues[0]); 436cd37da74Snw141292 has_san = (san != NULL); 4372b4a7802SBaban Kenkre } 438e3c2d6aaSnw141292 } else if (!has_class && strcasecmp(attr, OBJCLASS) == 0) { 4392b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 440cd37da74Snw141292 has_class = idmap_bv_objclass2sidtype(bvalues, 441cd37da74Snw141292 &sid_type); 442e8c27ec8Sbaban if (has_class && q->unixname != NULL && 443e8c27ec8Sbaban q->eunixtype == _IDMAP_T_UNDEF) { 444e8c27ec8Sbaban /* 445e8c27ec8Sbaban * This is the case where we didn't 446e8c27ec8Sbaban * know whether we wanted unixuser or 447e8c27ec8Sbaban * unixgroup as described above. 448e8c27ec8Sbaban * Now since we know the "sid_type" 449e8c27ec8Sbaban * we discard the unwanted value 450e8c27ec8Sbaban * if it was retrieved before we 451e8c27ec8Sbaban * got here. 452e8c27ec8Sbaban */ 453e8c27ec8Sbaban if (sid_type == _IDMAP_T_USER) { 454e8c27ec8Sbaban free(unixgroup); 455e8c27ec8Sbaban unixgroup_attr = unixgroup = NULL; 456e8c27ec8Sbaban } else if (sid_type == _IDMAP_T_GROUP) { 457e8c27ec8Sbaban free(unixuser); 458e8c27ec8Sbaban unixuser_attr = unixuser = NULL; 459e8c27ec8Sbaban } else { 460e8c27ec8Sbaban free(unixuser); 461e8c27ec8Sbaban free(unixgroup); 462e8c27ec8Sbaban unixuser_attr = unixuser = NULL; 463e8c27ec8Sbaban unixgroup_attr = unixgroup = NULL; 464e8c27ec8Sbaban } 465e8c27ec8Sbaban } 466e8c27ec8Sbaban } else if (!has_unixuser && unixuser_attr != NULL && 467e8c27ec8Sbaban strcasecmp(attr, unixuser_attr) == 0) { 4682b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 4692b4a7802SBaban Kenkre if (bvalues != NULL) { 4702b4a7802SBaban Kenkre unixuser = adutils_bv_name2str(bvalues[0]); 471e8c27ec8Sbaban has_unixuser = (unixuser != NULL); 4722b4a7802SBaban Kenkre } 47348258c6bSjp151216 474e8c27ec8Sbaban } else if (!has_unixgroup && unixgroup_attr != NULL && 475e8c27ec8Sbaban strcasecmp(attr, unixgroup_attr) == 0) { 4762b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 4772b4a7802SBaban Kenkre if (bvalues != NULL) { 4782b4a7802SBaban Kenkre unixgroup = adutils_bv_name2str(bvalues[0]); 479e8c27ec8Sbaban has_unixgroup = (unixgroup != NULL); 480c5c4113dSnw141292 } 4812b4a7802SBaban Kenkre } 482c5c4113dSnw141292 483c5c4113dSnw141292 if (bvalues != NULL) 484c5c4113dSnw141292 ldap_value_free_len(bvalues); 485c5c4113dSnw141292 ldap_memfree(attr); 486c5c4113dSnw141292 487cd37da74Snw141292 if (has_class && has_san && 488e8c27ec8Sbaban (q->sid == NULL || has_sid) && 489e8c27ec8Sbaban (unixuser_attr == NULL || has_unixuser) && 490e8c27ec8Sbaban (unixgroup_attr == NULL || has_unixgroup)) { 491e8c27ec8Sbaban /* Got what we need */ 492e3c2d6aaSnw141292 break; 493c5c4113dSnw141292 } 494e3c2d6aaSnw141292 } 495e3c2d6aaSnw141292 496e8c27ec8Sbaban if (!has_class) { 497e8c27ec8Sbaban /* 498e8c27ec8Sbaban * Didn't find objectclass. Something's wrong with our 499e8c27ec8Sbaban * AD data. 500e8c27ec8Sbaban */ 501e8c27ec8Sbaban free(san); 502e8c27ec8Sbaban free(sid); 503e8c27ec8Sbaban free(unixuser); 504e8c27ec8Sbaban free(unixgroup); 505e8c27ec8Sbaban } else { 506e8c27ec8Sbaban /* 507e8c27ec8Sbaban * Either we got what we needed and came out of the loop 508e8c27ec8Sbaban * early OR we completed the loop in which case we didn't 509e8c27ec8Sbaban * find some attributes that we were looking for. In either 510e8c27ec8Sbaban * case set the result with what we got. 511e8c27ec8Sbaban */ 51248258c6bSjp151216 idmap_setqresults(q, san, dn, 51348258c6bSjp151216 (unixuser != NULL) ? unixuser_attr : unixgroup_attr, 51448258c6bSjp151216 sid, rid, sid_type, 515e8c27ec8Sbaban (unixuser != NULL) ? unixuser : unixgroup); 516e8c27ec8Sbaban } 517e8c27ec8Sbaban 518c5c4113dSnw141292 if (ber != NULL) 519c5c4113dSnw141292 ber_free(ber, 0); 520c5c4113dSnw141292 521c5c4113dSnw141292 ldap_memfree(dn); 522c5c4113dSnw141292 } 523c5c4113dSnw141292 5242b4a7802SBaban Kenkre void 5252b4a7802SBaban Kenkre idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, int qid, 5262b4a7802SBaban Kenkre void *argp) 527c5c4113dSnw141292 { 5282b4a7802SBaban Kenkre idmap_query_state_t *state = (idmap_query_state_t *)argp; 5292b4a7802SBaban Kenkre idmap_q_t *q = &(state->queries[qid]); 530c5c4113dSnw141292 531c5c4113dSnw141292 switch (rc) { 532c5c4113dSnw141292 case LDAP_RES_SEARCH_RESULT: 5332b4a7802SBaban Kenkre if (q->search_res != NULL) { 5342b4a7802SBaban Kenkre idmap_extract_object(state, q, q->search_res, ld); 5352b4a7802SBaban Kenkre (void) ldap_msgfree(q->search_res); 5362b4a7802SBaban Kenkre q->search_res = NULL; 537bcced03bSjp151216 } else 5382b4a7802SBaban Kenkre q->ad_rc = ADUTILS_ERR_NOTFOUND; 539c5c4113dSnw141292 break; 540c5c4113dSnw141292 case LDAP_RES_SEARCH_ENTRY: 5412b4a7802SBaban Kenkre if (q->search_res == NULL) { 5422b4a7802SBaban Kenkre q->search_res = *res; 5432b4a7802SBaban Kenkre *res = NULL; 544bcced03bSjp151216 } 545c5c4113dSnw141292 break; 546c5c4113dSnw141292 default: 547c5c4113dSnw141292 break; 548c5c4113dSnw141292 } 54984decf41Sjp151216 } 55084decf41Sjp151216 551e3c2d6aaSnw141292 static 552e3c2d6aaSnw141292 void 553e3c2d6aaSnw141292 idmap_cleanup_batch(idmap_query_state_t *batch) 554e3c2d6aaSnw141292 { 555e3c2d6aaSnw141292 int i; 556e3c2d6aaSnw141292 557e3c2d6aaSnw141292 for (i = 0; i < batch->qcount; i++) { 558cd37da74Snw141292 if (batch->queries[i].ecanonname != NULL) 559cd37da74Snw141292 free(batch->queries[i].ecanonname); 560cd37da74Snw141292 batch->queries[i].ecanonname = NULL; 561cd37da74Snw141292 if (batch->queries[i].edomain != NULL) 562cd37da74Snw141292 free(batch->queries[i].edomain); 563cd37da74Snw141292 batch->queries[i].edomain = NULL; 564e3c2d6aaSnw141292 } 565e3c2d6aaSnw141292 } 566e3c2d6aaSnw141292 56784decf41Sjp151216 /* 56884decf41Sjp151216 * This routine frees the idmap_query_state_t structure 56984decf41Sjp151216 */ 570c5c4113dSnw141292 void 57184decf41Sjp151216 idmap_lookup_release_batch(idmap_query_state_t **state) 572c5c4113dSnw141292 { 5732b4a7802SBaban Kenkre if (state == NULL || *state == NULL) 5742b4a7802SBaban Kenkre return; 5752b4a7802SBaban Kenkre adutils_lookup_batch_release(&(*state)->qs); 576e3c2d6aaSnw141292 idmap_cleanup_batch(*state); 577c5c4113dSnw141292 free(*state); 578c5c4113dSnw141292 *state = NULL; 579c5c4113dSnw141292 } 580c5c4113dSnw141292 581c5c4113dSnw141292 idmap_retcode 5820dcc7149Snw141292 idmap_lookup_batch_end(idmap_query_state_t **state) 583c5c4113dSnw141292 { 5842b4a7802SBaban Kenkre adutils_rc ad_rc; 5852b4a7802SBaban Kenkre int i; 5862b4a7802SBaban Kenkre idmap_query_state_t *id_qs = *state; 587c5c4113dSnw141292 5882b4a7802SBaban Kenkre ad_rc = adutils_lookup_batch_end(&id_qs->qs); 589c5c4113dSnw141292 5902b4a7802SBaban Kenkre /* 5912b4a7802SBaban Kenkre * Map adutils rc to idmap_retcode in each 5922b4a7802SBaban Kenkre * query because consumers in dbutils.c 5932b4a7802SBaban Kenkre * expects idmap_retcode. 5942b4a7802SBaban Kenkre */ 5952b4a7802SBaban Kenkre for (i = 0; i < id_qs->qcount; i++) { 5962b4a7802SBaban Kenkre *id_qs->queries[i].rc = 5972b4a7802SBaban Kenkre map_adrc2idmaprc(id_qs->queries[i].ad_rc); 598c5c4113dSnw141292 } 59984decf41Sjp151216 idmap_lookup_release_batch(state); 6002b4a7802SBaban Kenkre return (map_adrc2idmaprc(ad_rc)); 601c5c4113dSnw141292 } 602c5c4113dSnw141292 603c5c4113dSnw141292 /* 604c5c4113dSnw141292 * Send one prepared search, queue up msgid, process what results are 605c5c4113dSnw141292 * available 606c5c4113dSnw141292 */ 607c5c4113dSnw141292 static 608c5c4113dSnw141292 idmap_retcode 60948258c6bSjp151216 idmap_batch_add1(idmap_query_state_t *state, const char *filter, 61048258c6bSjp151216 char *ecanonname, char *edomain, int eunixtype, 61148258c6bSjp151216 char **dn, char **attr, char **value, 61248258c6bSjp151216 char **canonname, char **dname, 61348258c6bSjp151216 char **sid, rid_t *rid, int *sid_type, char **unixname, 61448258c6bSjp151216 idmap_retcode *rc) 615c5c4113dSnw141292 { 6162b4a7802SBaban Kenkre adutils_rc ad_rc; 6172b4a7802SBaban Kenkre int qid, i; 618c5c4113dSnw141292 idmap_q_t *q; 619cd37da74Snw141292 static char *attrs[] = { 620cd37da74Snw141292 SAN, 621cd37da74Snw141292 OBJSID, 622cd37da74Snw141292 OBJCLASS, 623e8c27ec8Sbaban NULL, /* placeholder for unixname attr */ 624e8c27ec8Sbaban NULL, /* placeholder for unixname attr */ 625cd37da74Snw141292 NULL 626cd37da74Snw141292 }; 627c5c4113dSnw141292 628*4d61c878SJulian Pullen qid = atomic_inc_32_nv(&state->qcount) - 1; 629c5c4113dSnw141292 q = &(state->queries[qid]); 630c5c4113dSnw141292 631*4d61c878SJulian Pullen assert(qid < state->qsize); 632*4d61c878SJulian Pullen 633cd37da74Snw141292 /* 6342b4a7802SBaban Kenkre * Remember the expected canonname, domainname and unix type 6352b4a7802SBaban Kenkre * so we can check the results * against it 636cd37da74Snw141292 */ 637cd37da74Snw141292 q->ecanonname = ecanonname; 638cd37da74Snw141292 q->edomain = edomain; 639e8c27ec8Sbaban q->eunixtype = eunixtype; 640e3c2d6aaSnw141292 641c5c4113dSnw141292 /* Remember where to put the results */ 642cd37da74Snw141292 q->canonname = canonname; 643e8c27ec8Sbaban q->sid = sid; 644c5c4113dSnw141292 q->domain = dname; 645c5c4113dSnw141292 q->rid = rid; 646c5c4113dSnw141292 q->sid_type = sid_type; 647c5c4113dSnw141292 q->rc = rc; 648e8c27ec8Sbaban q->unixname = unixname; 64948258c6bSjp151216 q->dn = dn; 65048258c6bSjp151216 q->attr = attr; 65148258c6bSjp151216 q->value = value; 652e8c27ec8Sbaban 653e8c27ec8Sbaban /* Add unixuser/unixgroup attribute names to the attrs list */ 654e8c27ec8Sbaban if (unixname != NULL) { 655e8c27ec8Sbaban i = 3; 656e8c27ec8Sbaban if (eunixtype != _IDMAP_T_GROUP && 657e8c27ec8Sbaban state->ad_unixuser_attr != NULL) 658e8c27ec8Sbaban attrs[i++] = (char *)state->ad_unixuser_attr; 659e8c27ec8Sbaban if (eunixtype != _IDMAP_T_USER && 660e8c27ec8Sbaban state->ad_unixgroup_attr != NULL) 661e8c27ec8Sbaban attrs[i] = (char *)state->ad_unixgroup_attr; 662e8c27ec8Sbaban } 663c5c4113dSnw141292 664c5c4113dSnw141292 /* 665c5c4113dSnw141292 * Provide sane defaults for the results in case we never hear 666c5c4113dSnw141292 * back from the DS before closing the connection. 667e3c2d6aaSnw141292 * 668e3c2d6aaSnw141292 * In particular we default the result to indicate a retriable 669e3c2d6aaSnw141292 * error. The first complete matching result entry will cause 670e3c2d6aaSnw141292 * this to be set to IDMAP_SUCCESS, and the end of the results 671e3c2d6aaSnw141292 * for this search will cause this to indicate "not found" if no 672e3c2d6aaSnw141292 * result entries arrived or no complete ones matched the lookup 673e3c2d6aaSnw141292 * we were doing. 674c5c4113dSnw141292 */ 675c5c4113dSnw141292 *rc = IDMAP_ERR_RETRIABLE_NET_ERR; 676e8c27ec8Sbaban if (sid_type != NULL) 677c5c4113dSnw141292 *sid_type = _IDMAP_T_OTHER; 678e8c27ec8Sbaban if (sid != NULL) 679e8c27ec8Sbaban *sid = NULL; 680c5c4113dSnw141292 if (dname != NULL) 681c5c4113dSnw141292 *dname = NULL; 682c5c4113dSnw141292 if (rid != NULL) 683c5c4113dSnw141292 *rid = 0; 68448258c6bSjp151216 if (dn != NULL) 68548258c6bSjp151216 *dn = NULL; 68648258c6bSjp151216 if (attr != NULL) 68748258c6bSjp151216 *attr = NULL; 68848258c6bSjp151216 if (value != NULL) 68948258c6bSjp151216 *value = NULL; 690c5c4113dSnw141292 691479ac375Sdm199847 /* 692479ac375Sdm199847 * Don't set *canonname to NULL because it may be pointing to the 693479ac375Sdm199847 * given winname. Later on if we get a canonical name from AD the 694479ac375Sdm199847 * old name if any will be freed before assigning the new name. 695479ac375Sdm199847 */ 696479ac375Sdm199847 697c5c4113dSnw141292 /* 6982b4a7802SBaban Kenkre * Invoke the mother of all APIs i.e. the adutils API 699c5c4113dSnw141292 */ 7002b4a7802SBaban Kenkre ad_rc = adutils_lookup_batch_add(state->qs, filter, 7012b4a7802SBaban Kenkre (const char **)attrs, 7022b4a7802SBaban Kenkre edomain, &q->result, &q->ad_rc); 7032b4a7802SBaban Kenkre return (map_adrc2idmaprc(ad_rc)); 704c5c4113dSnw141292 } 705c5c4113dSnw141292 706c5c4113dSnw141292 idmap_retcode 707c5c4113dSnw141292 idmap_name2sid_batch_add1(idmap_query_state_t *state, 708e8c27ec8Sbaban const char *name, const char *dname, int eunixtype, 70948258c6bSjp151216 char **dn, char **attr, char **value, 71048258c6bSjp151216 char **canonname, char **sid, rid_t *rid, 71148258c6bSjp151216 int *sid_type, char **unixname, idmap_retcode *rc) 712c5c4113dSnw141292 { 713c5c4113dSnw141292 idmap_retcode retcode; 714e3c2d6aaSnw141292 int len, samAcctNameLen; 715479ac375Sdm199847 char *filter = NULL, *s_name; 716cd37da74Snw141292 char *ecanonname, *edomain; /* expected canonname */ 717c5c4113dSnw141292 718c5c4113dSnw141292 /* 719e3c2d6aaSnw141292 * Strategy: search the global catalog for user/group by 720e3c2d6aaSnw141292 * sAMAccountName = user/groupname with "" as the base DN and by 721e3c2d6aaSnw141292 * userPrincipalName = user/groupname@domain. The result 722e3c2d6aaSnw141292 * entries will be checked to conform to the name and domain 723e3c2d6aaSnw141292 * name given here. The DN, sAMAccountName, userPrincipalName, 724e3c2d6aaSnw141292 * objectSid and objectClass of the result entries are all we 725e3c2d6aaSnw141292 * need to figure out which entries match the lookup, the SID of 726e3c2d6aaSnw141292 * the user/group and whether it is a user or a group. 727c5c4113dSnw141292 */ 728c5c4113dSnw141292 729c5c4113dSnw141292 /* 730e3c2d6aaSnw141292 * We need the name and the domain name separately and as 731e3c2d6aaSnw141292 * name@domain. We also allow the domain to be provided 732e3c2d6aaSnw141292 * separately. 733c5c4113dSnw141292 */ 734d3a612caSnw141292 samAcctNameLen = strlen(name); 735e3c2d6aaSnw141292 736cd37da74Snw141292 if ((ecanonname = strdup(name)) == NULL) 737e3c2d6aaSnw141292 return (IDMAP_ERR_MEMORY); 738cd37da74Snw141292 739cd37da74Snw141292 if (dname == NULL || *dname == '\0') { 740cd37da74Snw141292 if ((dname = strchr(name, '@')) != NULL) { 741cd37da74Snw141292 /* 'name' is qualified with a domain name */ 742cd37da74Snw141292 if ((edomain = strdup(dname + 1)) == NULL) { 743cd37da74Snw141292 free(ecanonname); 744cd37da74Snw141292 return (IDMAP_ERR_MEMORY); 745cd37da74Snw141292 } 746cd37da74Snw141292 *strchr(ecanonname, '@') = '\0'; 747c5c4113dSnw141292 } else { 7482b4a7802SBaban Kenkre /* 'name' not qualified and dname not given */ 749*4d61c878SJulian Pullen dname = adutils_lookup_batch_getdefdomain(state->qs); 7502b4a7802SBaban Kenkre assert(dname != NULL); 7512b4a7802SBaban Kenkre if (*dname == '\0') { 752cd37da74Snw141292 free(ecanonname); 753e3c2d6aaSnw141292 return (IDMAP_ERR_DOMAIN); 754e3c2d6aaSnw141292 } 7552b4a7802SBaban Kenkre edomain = strdup(dname); 756cd37da74Snw141292 if (edomain == NULL) { 757cd37da74Snw141292 free(ecanonname); 758e3c2d6aaSnw141292 return (IDMAP_ERR_MEMORY); 759cd37da74Snw141292 } 760cd37da74Snw141292 } 761cd37da74Snw141292 } else { 762cd37da74Snw141292 if ((edomain = strdup(dname)) == NULL) { 763cd37da74Snw141292 free(ecanonname); 764cd37da74Snw141292 return (IDMAP_ERR_MEMORY); 765cd37da74Snw141292 } 766e3c2d6aaSnw141292 } 767c5c4113dSnw141292 768*4d61c878SJulian Pullen if (!adutils_lookup_check_domain(state->qs, dname)) { 769*4d61c878SJulian Pullen free(ecanonname); 770*4d61c878SJulian Pullen free(edomain); 771*4d61c878SJulian Pullen return (IDMAP_ERR_DOMAIN_NOTFOUND); 772*4d61c878SJulian Pullen } 773*4d61c878SJulian Pullen 774479ac375Sdm199847 s_name = sanitize_for_ldap_filter(name); 775479ac375Sdm199847 if (s_name == NULL) { 776cd37da74Snw141292 free(ecanonname); 777479ac375Sdm199847 free(edomain); 778c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 779c5c4113dSnw141292 } 780479ac375Sdm199847 781479ac375Sdm199847 /* Assemble filter */ 782479ac375Sdm199847 len = snprintf(NULL, 0, SANFILTER, samAcctNameLen, s_name) + 1; 783479ac375Sdm199847 if ((filter = (char *)malloc(len)) == NULL) { 784479ac375Sdm199847 free(ecanonname); 785479ac375Sdm199847 free(edomain); 786479ac375Sdm199847 if (s_name != name) 787479ac375Sdm199847 free(s_name); 788479ac375Sdm199847 return (IDMAP_ERR_MEMORY); 789479ac375Sdm199847 } 790479ac375Sdm199847 (void) snprintf(filter, len, SANFILTER, samAcctNameLen, s_name); 791479ac375Sdm199847 if (s_name != name) 792479ac375Sdm199847 free(s_name); 793c5c4113dSnw141292 794cd37da74Snw141292 retcode = idmap_batch_add1(state, filter, ecanonname, edomain, 79548258c6bSjp151216 eunixtype, dn, attr, value, canonname, NULL, sid, rid, sid_type, 79648258c6bSjp151216 unixname, rc); 797c5c4113dSnw141292 798c5c4113dSnw141292 free(filter); 799c5c4113dSnw141292 800c5c4113dSnw141292 return (retcode); 801c5c4113dSnw141292 } 802c5c4113dSnw141292 803c5c4113dSnw141292 idmap_retcode 804c5c4113dSnw141292 idmap_sid2name_batch_add1(idmap_query_state_t *state, 805e8c27ec8Sbaban const char *sid, const rid_t *rid, int eunixtype, 80648258c6bSjp151216 char **dn, char **attr, char **value, 80748258c6bSjp151216 char **name, char **dname, int *sid_type, 80848258c6bSjp151216 char **unixname, idmap_retcode *rc) 809c5c4113dSnw141292 { 810c5c4113dSnw141292 idmap_retcode retcode; 811c5c4113dSnw141292 int flen, ret; 812c5c4113dSnw141292 char *filter = NULL; 8132b4a7802SBaban Kenkre char cbinsid[ADUTILS_MAXHEXBINSID + 1]; 814c5c4113dSnw141292 815c5c4113dSnw141292 /* 816c5c4113dSnw141292 * Strategy: search [the global catalog] for user/group by 817c5c4113dSnw141292 * objectSid = SID with empty base DN. The DN, sAMAccountName 818c5c4113dSnw141292 * and objectClass of the result are all we need to figure out 819c5c4113dSnw141292 * the name of the SID and whether it is a user, a group or a 820c5c4113dSnw141292 * computer. 821c5c4113dSnw141292 */ 822c5c4113dSnw141292 823*4d61c878SJulian Pullen if (!adutils_lookup_check_sid_prefix(state->qs, sid)) 824*4d61c878SJulian Pullen return (IDMAP_ERR_DOMAIN_NOTFOUND); 825*4d61c878SJulian Pullen 8262b4a7802SBaban Kenkre ret = adutils_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid)); 827c5c4113dSnw141292 if (ret != 0) 828c5c4113dSnw141292 return (IDMAP_ERR_SID); 829c5c4113dSnw141292 830c5c4113dSnw141292 /* Assemble filter */ 831e3c2d6aaSnw141292 flen = snprintf(NULL, 0, OBJSIDFILTER, cbinsid) + 1; 832c5c4113dSnw141292 if ((filter = (char *)malloc(flen)) == NULL) 833c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 834e3c2d6aaSnw141292 (void) snprintf(filter, flen, OBJSIDFILTER, cbinsid); 835c5c4113dSnw141292 836e8c27ec8Sbaban retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype, 83748258c6bSjp151216 dn, attr, value, name, dname, NULL, NULL, sid_type, unixname, rc); 838e8c27ec8Sbaban 839e8c27ec8Sbaban free(filter); 840e8c27ec8Sbaban 841e8c27ec8Sbaban return (retcode); 842e8c27ec8Sbaban } 843e8c27ec8Sbaban 844e8c27ec8Sbaban idmap_retcode 845e8c27ec8Sbaban idmap_unixname2sid_batch_add1(idmap_query_state_t *state, 846e8c27ec8Sbaban const char *unixname, int is_user, int is_wuser, 84748258c6bSjp151216 char **dn, char **attr, char **value, 84848258c6bSjp151216 char **sid, rid_t *rid, char **name, 84948258c6bSjp151216 char **dname, int *sid_type, idmap_retcode *rc) 850e8c27ec8Sbaban { 851e8c27ec8Sbaban idmap_retcode retcode; 852e8c27ec8Sbaban int len, ulen; 853479ac375Sdm199847 char *filter = NULL, *s_unixname; 854e8c27ec8Sbaban const char *attrname = NULL; 855e8c27ec8Sbaban 856e8c27ec8Sbaban /* Get unixuser or unixgroup AD attribute name */ 857e8c27ec8Sbaban attrname = (is_user) ? 858e8c27ec8Sbaban state->ad_unixuser_attr : state->ad_unixgroup_attr; 859e8c27ec8Sbaban if (attrname == NULL) 860e8c27ec8Sbaban return (IDMAP_ERR_NOTFOUND); 861e8c27ec8Sbaban 862479ac375Sdm199847 s_unixname = sanitize_for_ldap_filter(unixname); 863479ac375Sdm199847 if (s_unixname == NULL) 864479ac375Sdm199847 return (IDMAP_ERR_MEMORY); 865479ac375Sdm199847 866e8c27ec8Sbaban /* Assemble filter */ 867e8c27ec8Sbaban ulen = strlen(unixname); 868e8c27ec8Sbaban len = snprintf(NULL, 0, "(&(objectclass=%s)(%s=%.*s))", 869479ac375Sdm199847 is_wuser ? "user" : "group", attrname, ulen, s_unixname) + 1; 870479ac375Sdm199847 if ((filter = (char *)malloc(len)) == NULL) { 871479ac375Sdm199847 if (s_unixname != unixname) 872479ac375Sdm199847 free(s_unixname); 873e8c27ec8Sbaban return (IDMAP_ERR_MEMORY); 874479ac375Sdm199847 } 875e8c27ec8Sbaban (void) snprintf(filter, len, "(&(objectclass=%s)(%s=%.*s))", 876479ac375Sdm199847 is_wuser ? "user" : "group", attrname, ulen, s_unixname); 877479ac375Sdm199847 if (s_unixname != unixname) 878479ac375Sdm199847 free(s_unixname); 879e8c27ec8Sbaban 880e8c27ec8Sbaban retcode = idmap_batch_add1(state, filter, NULL, NULL, 88148258c6bSjp151216 _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type, 88248258c6bSjp151216 NULL, rc); 88348258c6bSjp151216 88448258c6bSjp151216 if (retcode == IDMAP_SUCCESS && attr != NULL) { 88548258c6bSjp151216 if ((*attr = strdup(attrname)) == NULL) 88648258c6bSjp151216 retcode = IDMAP_ERR_MEMORY; 88748258c6bSjp151216 } 88848258c6bSjp151216 88948258c6bSjp151216 if (retcode == IDMAP_SUCCESS && value != NULL) { 89048258c6bSjp151216 if (ulen > 0) { 89148258c6bSjp151216 if ((*value = strdup(unixname)) == NULL) 89248258c6bSjp151216 retcode = IDMAP_ERR_MEMORY; 89348258c6bSjp151216 } 89448258c6bSjp151216 else 89548258c6bSjp151216 *value = NULL; 89648258c6bSjp151216 } 897c5c4113dSnw141292 898c5c4113dSnw141292 free(filter); 899c5c4113dSnw141292 900c5c4113dSnw141292 return (retcode); 901c5c4113dSnw141292 } 902