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> 48*2b4a7802SBaban Kenkre #include <time.h> 49cd37da74Snw141292 #include <sys/u8_textprep.h> 50*2b4a7802SBaban 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 61*2b4a7802SBaban Kenkre void idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, 62*2b4a7802SBaban 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; 89*2b4a7802SBaban Kenkre adutils_rc ad_rc; 90*2b4a7802SBaban 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 { 101*2b4a7802SBaban Kenkre adutils_query_state_t *qs; 102c5c4113dSnw141292 int qcount; /* how many queries */ 103c5c4113dSnw141292 uint32_t qlastsent; 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); 139*2b4a7802SBaban 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 149*2b4a7802SBaban Kenkre idmap_add_ds(adutils_ad_t *ad, const char *host, int port) 150c5c4113dSnw141292 { 151c5c4113dSnw141292 int ret = -1; 152c5c4113dSnw141292 153*2b4a7802SBaban Kenkre if (adutils_add_ds(ad, host, port) == ADUTILS_SUCCESS) 154c8e26105Sjp151216 ret = 0; 155c5c4113dSnw141292 156c5c4113dSnw141292 /* Start reaper if it doesn't exist */ 157*2b4a7802SBaban 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 164*2b4a7802SBaban Kenkre idmap_retcode 165*2b4a7802SBaban Kenkre map_adrc2idmaprc(adutils_rc adrc) 166c5c4113dSnw141292 { 167*2b4a7802SBaban Kenkre switch (adrc) { 168*2b4a7802SBaban Kenkre case ADUTILS_SUCCESS: 169*2b4a7802SBaban Kenkre return (IDMAP_SUCCESS); 170*2b4a7802SBaban Kenkre case ADUTILS_ERR_NOTFOUND: 171*2b4a7802SBaban Kenkre return (IDMAP_ERR_NOTFOUND); 172*2b4a7802SBaban Kenkre case ADUTILS_ERR_MEMORY: 173*2b4a7802SBaban Kenkre return (IDMAP_ERR_MEMORY); 174*2b4a7802SBaban Kenkre case ADUTILS_ERR_DOMAIN: 175*2b4a7802SBaban Kenkre return (IDMAP_ERR_DOMAIN); 176*2b4a7802SBaban Kenkre case ADUTILS_ERR_OTHER: 177*2b4a7802SBaban Kenkre return (IDMAP_ERR_OTHER); 178*2b4a7802SBaban Kenkre case ADUTILS_ERR_RETRIABLE_NET_ERR: 179*2b4a7802SBaban Kenkre return (IDMAP_ERR_RETRIABLE_NET_ERR); 180*2b4a7802SBaban Kenkre default: 181*2b4a7802SBaban Kenkre return (IDMAP_ERR_INTERNAL); 182c5c4113dSnw141292 } 183*2b4a7802SBaban Kenkre /* NOTREACHED */ 184c5c4113dSnw141292 } 185c5c4113dSnw141292 186c5c4113dSnw141292 idmap_retcode 187*2b4a7802SBaban Kenkre idmap_lookup_batch_start(adutils_ad_t *ad, int nqueries, 188*2b4a7802SBaban Kenkre idmap_query_state_t **state) 189c5c4113dSnw141292 { 190c5c4113dSnw141292 idmap_query_state_t *new_state; 191*2b4a7802SBaban Kenkre adutils_rc rc; 192c5c4113dSnw141292 193c5c4113dSnw141292 *state = NULL; 194c5c4113dSnw141292 195349d5d8fSnw141292 if (ad == NULL) 196e8c27ec8Sbaban return (IDMAP_ERR_INTERNAL); 197c5c4113dSnw141292 198c5c4113dSnw141292 new_state = calloc(1, sizeof (idmap_query_state_t) + 199c5c4113dSnw141292 (nqueries - 1) * sizeof (idmap_q_t)); 200c5c4113dSnw141292 if (new_state == NULL) 201c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 202c5c4113dSnw141292 203*2b4a7802SBaban Kenkre if ((rc = adutils_lookup_batch_start(ad, nqueries, 204*2b4a7802SBaban Kenkre idmap_ldap_res_search_cb, new_state, &new_state->qs)) 205*2b4a7802SBaban Kenkre != ADUTILS_SUCCESS) { 206*2b4a7802SBaban Kenkre free(new_state); 207*2b4a7802SBaban Kenkre return (map_adrc2idmaprc(rc)); 208*2b4a7802SBaban Kenkre } 209*2b4a7802SBaban Kenkre 210c5c4113dSnw141292 new_state->qcount = nqueries; 211c5c4113dSnw141292 *state = new_state; 212c5c4113dSnw141292 return (IDMAP_SUCCESS); 213c5c4113dSnw141292 } 214c5c4113dSnw141292 215c5c4113dSnw141292 /* 216e8c27ec8Sbaban * Set unixuser_attr and unixgroup_attr for AD-based name mapping 217e8c27ec8Sbaban */ 218e8c27ec8Sbaban void 219e8c27ec8Sbaban idmap_lookup_batch_set_unixattr(idmap_query_state_t *state, 2204edd44c5Sjp151216 const char *unixuser_attr, const char *unixgroup_attr) 2214edd44c5Sjp151216 { 222e8c27ec8Sbaban state->ad_unixuser_attr = unixuser_attr; 223e8c27ec8Sbaban state->ad_unixgroup_attr = unixgroup_attr; 224e8c27ec8Sbaban } 225e8c27ec8Sbaban 226e8c27ec8Sbaban /* 227cd37da74Snw141292 * Take parsed attribute values from a search result entry and check if 228cd37da74Snw141292 * it is the result that was desired and, if so, set the result fields 229cd37da74Snw141292 * of the given idmap_q_t. 230cd37da74Snw141292 * 231e8c27ec8Sbaban * Frees the unused char * values. 232c5c4113dSnw141292 */ 233c5c4113dSnw141292 static 234cd37da74Snw141292 void 23548258c6bSjp151216 idmap_setqresults(idmap_q_t *q, char *san, char *dn, const char *attr, 23648258c6bSjp151216 char *sid, rid_t rid, int sid_type, char *unixname) 237c5c4113dSnw141292 { 238cd37da74Snw141292 char *domain; 239e8c27ec8Sbaban int err1, err2; 240cd37da74Snw141292 241cd37da74Snw141292 assert(dn != NULL); 242cd37da74Snw141292 243*2b4a7802SBaban Kenkre if ((domain = adutils_dn2dns(dn)) == NULL) 244cd37da74Snw141292 goto out; 245cd37da74Snw141292 246e8c27ec8Sbaban if (q->ecanonname != NULL && san != NULL) { 247e8c27ec8Sbaban /* Check that this is the canonname that we were looking for */ 248cd37da74Snw141292 if (u8_strcmp(q->ecanonname, san, 0, 249cd37da74Snw141292 U8_STRCMP_CI_LOWER, /* no normalization, for now */ 250e8c27ec8Sbaban U8_UNICODE_LATEST, &err1) != 0 || err1 != 0) 251e8c27ec8Sbaban goto out; 252e8c27ec8Sbaban } 253e8c27ec8Sbaban 254e8c27ec8Sbaban if (q->edomain != NULL) { 255e8c27ec8Sbaban /* Check that this is the domain that we were looking for */ 256e8c27ec8Sbaban if (u8_strcmp(q->edomain, domain, 0, U8_STRCMP_CI_LOWER, 257cd37da74Snw141292 U8_UNICODE_LATEST, &err2) != 0 || err2 != 0) 258cd37da74Snw141292 goto out; 259e8c27ec8Sbaban } 260cd37da74Snw141292 26148258c6bSjp151216 /* Copy the DN and attr and value */ 26248258c6bSjp151216 if (q->dn != NULL) 26348258c6bSjp151216 *q->dn = strdup(dn); 26448258c6bSjp151216 26548258c6bSjp151216 if (q->attr != NULL && attr != NULL) 26648258c6bSjp151216 *q->attr = strdup(attr); 26748258c6bSjp151216 26848258c6bSjp151216 if (q->value != NULL && unixname != NULL) 26948258c6bSjp151216 *q->value = strdup(unixname); 27048258c6bSjp151216 271e8c27ec8Sbaban /* Set results */ 272e8c27ec8Sbaban if (q->sid) { 273e8c27ec8Sbaban *q->sid = sid; 274cd37da74Snw141292 sid = NULL; 275e8c27ec8Sbaban } 276e8c27ec8Sbaban if (q->rid) 277e8c27ec8Sbaban *q->rid = rid; 278e8c27ec8Sbaban if (q->sid_type) 279cd37da74Snw141292 *q->sid_type = sid_type; 280e8c27ec8Sbaban if (q->unixname) { 281e8c27ec8Sbaban *q->unixname = unixname; 282e8c27ec8Sbaban unixname = NULL; 283e8c27ec8Sbaban } 284cd37da74Snw141292 if (q->domain != NULL) { 285cd37da74Snw141292 *q->domain = domain; 286cd37da74Snw141292 domain = NULL; 287e8c27ec8Sbaban } 288e8c27ec8Sbaban if (q->canonname != NULL) { 289479ac375Sdm199847 /* 290479ac375Sdm199847 * The caller may be replacing the given winname by its 291479ac375Sdm199847 * canonical name and therefore free any old name before 292479ac375Sdm199847 * overwriting the field by the canonical name. 293479ac375Sdm199847 */ 294479ac375Sdm199847 free(*q->canonname); 295e8c27ec8Sbaban *q->canonname = san; 296cd37da74Snw141292 san = NULL; 297cd37da74Snw141292 } 298cd37da74Snw141292 299*2b4a7802SBaban Kenkre q->ad_rc = ADUTILS_SUCCESS; 300cd37da74Snw141292 301cd37da74Snw141292 out: 302cd37da74Snw141292 /* Free unused attribute values */ 303cd37da74Snw141292 free(san); 304cd37da74Snw141292 free(sid); 305cd37da74Snw141292 free(domain); 306e8c27ec8Sbaban free(unixname); 307c5c4113dSnw141292 } 308c5c4113dSnw141292 309c5c4113dSnw141292 #define BVAL_CASEEQ(bv, str) \ 310c5c4113dSnw141292 (((*(bv))->bv_len == (sizeof (str) - 1)) && \ 311c5c4113dSnw141292 strncasecmp((*(bv))->bv_val, str, (*(bv))->bv_len) == 0) 312c5c4113dSnw141292 313c5c4113dSnw141292 /* 314cd37da74Snw141292 * Extract the class of the result entry. Returns 1 on success, 0 on 315cd37da74Snw141292 * failure. 316c5c4113dSnw141292 */ 317c5c4113dSnw141292 static 318e3c2d6aaSnw141292 int 319cd37da74Snw141292 idmap_bv_objclass2sidtype(BerValue **bvalues, int *sid_type) 320c5c4113dSnw141292 { 321c5c4113dSnw141292 BerValue **cbval; 322c5c4113dSnw141292 323cd37da74Snw141292 *sid_type = _IDMAP_T_OTHER; 324c5c4113dSnw141292 if (bvalues == NULL) 325e3c2d6aaSnw141292 return (0); 326c5c4113dSnw141292 327cd37da74Snw141292 /* 328cd37da74Snw141292 * We iterate over all the values because computer is a 329cd37da74Snw141292 * sub-class of user. 330cd37da74Snw141292 */ 331c5c4113dSnw141292 for (cbval = bvalues; *cbval != NULL; cbval++) { 332c5c4113dSnw141292 if (BVAL_CASEEQ(cbval, "Computer")) { 333cd37da74Snw141292 *sid_type = _IDMAP_T_COMPUTER; 334cd37da74Snw141292 break; 335c5c4113dSnw141292 } else if (BVAL_CASEEQ(cbval, "Group")) { 336cd37da74Snw141292 *sid_type = _IDMAP_T_GROUP; 337cd37da74Snw141292 break; 338c5c4113dSnw141292 } else if (BVAL_CASEEQ(cbval, "USER")) { 339cd37da74Snw141292 *sid_type = _IDMAP_T_USER; 340cd37da74Snw141292 /* Continue looping -- this may be a computer yet */ 341cd37da74Snw141292 } 342cd37da74Snw141292 /* 343cd37da74Snw141292 * "else if (*sid_type = _IDMAP_T_USER)" then this is a 344cd37da74Snw141292 * new sub-class of user -- what to do with it?? 345cd37da74Snw141292 */ 346c5c4113dSnw141292 } 347e3c2d6aaSnw141292 348e3c2d6aaSnw141292 return (1); 349c5c4113dSnw141292 } 350c5c4113dSnw141292 351c5c4113dSnw141292 /* 352c5c4113dSnw141292 * Handle a given search result entry 353c5c4113dSnw141292 */ 354c5c4113dSnw141292 static 355c5c4113dSnw141292 void 356*2b4a7802SBaban Kenkre idmap_extract_object(idmap_query_state_t *state, idmap_q_t *q, 357*2b4a7802SBaban Kenkre LDAPMessage *res, LDAP *ld) 358c5c4113dSnw141292 { 359c5c4113dSnw141292 BerElement *ber = NULL; 360c5c4113dSnw141292 BerValue **bvalues; 361cd37da74Snw141292 char *attr; 362e8c27ec8Sbaban const char *unixuser_attr = NULL; 363e8c27ec8Sbaban const char *unixgroup_attr = NULL; 364e8c27ec8Sbaban char *unixuser = NULL; 365e8c27ec8Sbaban char *unixgroup = NULL; 366cd37da74Snw141292 char *dn = NULL; 367cd37da74Snw141292 char *san = NULL; 368cd37da74Snw141292 char *sid = NULL; 369cd37da74Snw141292 rid_t rid = 0; 370e8c27ec8Sbaban int sid_type = _IDMAP_T_UNDEF; 371e3c2d6aaSnw141292 int has_class, has_san, has_sid; 372e8c27ec8Sbaban int has_unixuser, has_unixgroup; 373e3c2d6aaSnw141292 374e8c27ec8Sbaban assert(q->rc != NULL); 375e8c27ec8Sbaban 376*2b4a7802SBaban Kenkre if ((dn = ldap_get_dn(ld, res)) == NULL) 377c5c4113dSnw141292 return; 378c5c4113dSnw141292 379e3c2d6aaSnw141292 assert(q->domain == NULL || *q->domain == NULL); 380c5c4113dSnw141292 381e8c27ec8Sbaban /* 382e8c27ec8Sbaban * If the caller has requested unixname then determine the 383e8c27ec8Sbaban * AD attribute name that will have the unixname. 384e8c27ec8Sbaban */ 385e8c27ec8Sbaban if (q->unixname != NULL) { 386e8c27ec8Sbaban if (q->eunixtype == _IDMAP_T_USER) 387e8c27ec8Sbaban unixuser_attr = state->ad_unixuser_attr; 388e8c27ec8Sbaban else if (q->eunixtype == _IDMAP_T_GROUP) 389e8c27ec8Sbaban unixgroup_attr = state->ad_unixgroup_attr; 390e8c27ec8Sbaban else if (q->eunixtype == _IDMAP_T_UNDEF) { 391e8c27ec8Sbaban /* 392e8c27ec8Sbaban * This is the case where we don't know 393e8c27ec8Sbaban * before hand whether we need unixuser 394e8c27ec8Sbaban * or unixgroup. This will be determined 395e8c27ec8Sbaban * by the "sid_type" (i.e whether the given 396e8c27ec8Sbaban * winname is user or group). If sid_type 397e8c27ec8Sbaban * turns out to be user we will return 398e8c27ec8Sbaban * unixuser (if found) and if it is a group 399e8c27ec8Sbaban * we will return unixgroup (if found). We 400e8c27ec8Sbaban * lookup for both ad_unixuser_attr and 401e8c27ec8Sbaban * ad_unixgroup_attr and discard one of them 402e8c27ec8Sbaban * after we know the "sidtype". This 403e8c27ec8Sbaban * supports the following type of lookups. 404e8c27ec8Sbaban * 405e8c27ec8Sbaban * Example: 406e8c27ec8Sbaban * $idmap show -c winname:foo 407e8c27ec8Sbaban * In the above example, idmap will 408e8c27ec8Sbaban * return uid if winname is winuser 409e8c27ec8Sbaban * and gid if winname is wingroup. 410e8c27ec8Sbaban */ 411e8c27ec8Sbaban unixuser_attr = state->ad_unixuser_attr; 412e8c27ec8Sbaban unixgroup_attr = state->ad_unixgroup_attr; 413e8c27ec8Sbaban } 414e8c27ec8Sbaban } 415e8c27ec8Sbaban 416e8c27ec8Sbaban has_class = has_san = has_sid = has_unixuser = has_unixgroup = 0; 417*2b4a7802SBaban Kenkre for (attr = ldap_first_attribute(ld, res, &ber); attr != NULL; 418*2b4a7802SBaban Kenkre attr = ldap_next_attribute(ld, res, ber)) { 419c5c4113dSnw141292 bvalues = NULL; /* for memory management below */ 420c5c4113dSnw141292 421c5c4113dSnw141292 /* 422c5c4113dSnw141292 * If this is an attribute we are looking for and 423c5c4113dSnw141292 * haven't seen it yet, parse it 424c5c4113dSnw141292 */ 425e8c27ec8Sbaban if (q->sid != NULL && !has_sid && 426e3c2d6aaSnw141292 strcasecmp(attr, OBJSID) == 0) { 427*2b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 428*2b4a7802SBaban Kenkre if (bvalues != NULL) { 429*2b4a7802SBaban Kenkre sid = adutils_bv_objsid2sidstr( 430*2b4a7802SBaban Kenkre bvalues[0], &rid); 431cd37da74Snw141292 has_sid = (sid != NULL); 432*2b4a7802SBaban Kenkre } 433e3c2d6aaSnw141292 } else if (!has_san && strcasecmp(attr, SAN) == 0) { 434*2b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 435*2b4a7802SBaban Kenkre if (bvalues != NULL) { 436*2b4a7802SBaban Kenkre san = adutils_bv_name2str(bvalues[0]); 437cd37da74Snw141292 has_san = (san != NULL); 438*2b4a7802SBaban Kenkre } 439e3c2d6aaSnw141292 } else if (!has_class && strcasecmp(attr, OBJCLASS) == 0) { 440*2b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 441cd37da74Snw141292 has_class = idmap_bv_objclass2sidtype(bvalues, 442cd37da74Snw141292 &sid_type); 443e8c27ec8Sbaban if (has_class && q->unixname != NULL && 444e8c27ec8Sbaban q->eunixtype == _IDMAP_T_UNDEF) { 445e8c27ec8Sbaban /* 446e8c27ec8Sbaban * This is the case where we didn't 447e8c27ec8Sbaban * know whether we wanted unixuser or 448e8c27ec8Sbaban * unixgroup as described above. 449e8c27ec8Sbaban * Now since we know the "sid_type" 450e8c27ec8Sbaban * we discard the unwanted value 451e8c27ec8Sbaban * if it was retrieved before we 452e8c27ec8Sbaban * got here. 453e8c27ec8Sbaban */ 454e8c27ec8Sbaban if (sid_type == _IDMAP_T_USER) { 455e8c27ec8Sbaban free(unixgroup); 456e8c27ec8Sbaban unixgroup_attr = unixgroup = NULL; 457e8c27ec8Sbaban } else if (sid_type == _IDMAP_T_GROUP) { 458e8c27ec8Sbaban free(unixuser); 459e8c27ec8Sbaban unixuser_attr = unixuser = NULL; 460e8c27ec8Sbaban } else { 461e8c27ec8Sbaban free(unixuser); 462e8c27ec8Sbaban free(unixgroup); 463e8c27ec8Sbaban unixuser_attr = unixuser = NULL; 464e8c27ec8Sbaban unixgroup_attr = unixgroup = NULL; 465e8c27ec8Sbaban } 466e8c27ec8Sbaban } 467e8c27ec8Sbaban } else if (!has_unixuser && unixuser_attr != NULL && 468e8c27ec8Sbaban strcasecmp(attr, unixuser_attr) == 0) { 469*2b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 470*2b4a7802SBaban Kenkre if (bvalues != NULL) { 471*2b4a7802SBaban Kenkre unixuser = adutils_bv_name2str(bvalues[0]); 472e8c27ec8Sbaban has_unixuser = (unixuser != NULL); 473*2b4a7802SBaban Kenkre } 47448258c6bSjp151216 475e8c27ec8Sbaban } else if (!has_unixgroup && unixgroup_attr != NULL && 476e8c27ec8Sbaban strcasecmp(attr, unixgroup_attr) == 0) { 477*2b4a7802SBaban Kenkre bvalues = ldap_get_values_len(ld, res, attr); 478*2b4a7802SBaban Kenkre if (bvalues != NULL) { 479*2b4a7802SBaban Kenkre unixgroup = adutils_bv_name2str(bvalues[0]); 480e8c27ec8Sbaban has_unixgroup = (unixgroup != NULL); 481c5c4113dSnw141292 } 482*2b4a7802SBaban Kenkre } 483c5c4113dSnw141292 484c5c4113dSnw141292 if (bvalues != NULL) 485c5c4113dSnw141292 ldap_value_free_len(bvalues); 486c5c4113dSnw141292 ldap_memfree(attr); 487c5c4113dSnw141292 488cd37da74Snw141292 if (has_class && has_san && 489e8c27ec8Sbaban (q->sid == NULL || has_sid) && 490e8c27ec8Sbaban (unixuser_attr == NULL || has_unixuser) && 491e8c27ec8Sbaban (unixgroup_attr == NULL || has_unixgroup)) { 492e8c27ec8Sbaban /* Got what we need */ 493e3c2d6aaSnw141292 break; 494c5c4113dSnw141292 } 495e3c2d6aaSnw141292 } 496e3c2d6aaSnw141292 497e8c27ec8Sbaban if (!has_class) { 498e8c27ec8Sbaban /* 499e8c27ec8Sbaban * Didn't find objectclass. Something's wrong with our 500e8c27ec8Sbaban * AD data. 501e8c27ec8Sbaban */ 502e8c27ec8Sbaban free(san); 503e8c27ec8Sbaban free(sid); 504e8c27ec8Sbaban free(unixuser); 505e8c27ec8Sbaban free(unixgroup); 506e8c27ec8Sbaban } else { 507e8c27ec8Sbaban /* 508e8c27ec8Sbaban * Either we got what we needed and came out of the loop 509e8c27ec8Sbaban * early OR we completed the loop in which case we didn't 510e8c27ec8Sbaban * find some attributes that we were looking for. In either 511e8c27ec8Sbaban * case set the result with what we got. 512e8c27ec8Sbaban */ 51348258c6bSjp151216 idmap_setqresults(q, san, dn, 51448258c6bSjp151216 (unixuser != NULL) ? unixuser_attr : unixgroup_attr, 51548258c6bSjp151216 sid, rid, sid_type, 516e8c27ec8Sbaban (unixuser != NULL) ? unixuser : unixgroup); 517e8c27ec8Sbaban } 518e8c27ec8Sbaban 519c5c4113dSnw141292 if (ber != NULL) 520c5c4113dSnw141292 ber_free(ber, 0); 521c5c4113dSnw141292 522c5c4113dSnw141292 ldap_memfree(dn); 523c5c4113dSnw141292 } 524c5c4113dSnw141292 525*2b4a7802SBaban Kenkre void 526*2b4a7802SBaban Kenkre idmap_ldap_res_search_cb(LDAP *ld, LDAPMessage **res, int rc, int qid, 527*2b4a7802SBaban Kenkre void *argp) 528c5c4113dSnw141292 { 529*2b4a7802SBaban Kenkre idmap_query_state_t *state = (idmap_query_state_t *)argp; 530*2b4a7802SBaban Kenkre idmap_q_t *q = &(state->queries[qid]); 531c5c4113dSnw141292 532c5c4113dSnw141292 switch (rc) { 533c5c4113dSnw141292 case LDAP_RES_SEARCH_RESULT: 534*2b4a7802SBaban Kenkre if (q->search_res != NULL) { 535*2b4a7802SBaban Kenkre idmap_extract_object(state, q, q->search_res, ld); 536*2b4a7802SBaban Kenkre (void) ldap_msgfree(q->search_res); 537*2b4a7802SBaban Kenkre q->search_res = NULL; 538bcced03bSjp151216 } else 539*2b4a7802SBaban Kenkre q->ad_rc = ADUTILS_ERR_NOTFOUND; 540c5c4113dSnw141292 break; 541c5c4113dSnw141292 case LDAP_RES_SEARCH_ENTRY: 542*2b4a7802SBaban Kenkre if (q->search_res == NULL) { 543*2b4a7802SBaban Kenkre q->search_res = *res; 544*2b4a7802SBaban Kenkre *res = NULL; 545bcced03bSjp151216 } 546c5c4113dSnw141292 break; 547c5c4113dSnw141292 default: 548c5c4113dSnw141292 break; 549c5c4113dSnw141292 } 55084decf41Sjp151216 } 55184decf41Sjp151216 552e3c2d6aaSnw141292 static 553e3c2d6aaSnw141292 void 554e3c2d6aaSnw141292 idmap_cleanup_batch(idmap_query_state_t *batch) 555e3c2d6aaSnw141292 { 556e3c2d6aaSnw141292 int i; 557e3c2d6aaSnw141292 558e3c2d6aaSnw141292 for (i = 0; i < batch->qcount; i++) { 559cd37da74Snw141292 if (batch->queries[i].ecanonname != NULL) 560cd37da74Snw141292 free(batch->queries[i].ecanonname); 561cd37da74Snw141292 batch->queries[i].ecanonname = NULL; 562cd37da74Snw141292 if (batch->queries[i].edomain != NULL) 563cd37da74Snw141292 free(batch->queries[i].edomain); 564cd37da74Snw141292 batch->queries[i].edomain = NULL; 565e3c2d6aaSnw141292 } 566e3c2d6aaSnw141292 } 567e3c2d6aaSnw141292 56884decf41Sjp151216 /* 56984decf41Sjp151216 * This routine frees the idmap_query_state_t structure 57084decf41Sjp151216 */ 571c5c4113dSnw141292 void 57284decf41Sjp151216 idmap_lookup_release_batch(idmap_query_state_t **state) 573c5c4113dSnw141292 { 574*2b4a7802SBaban Kenkre if (state == NULL || *state == NULL) 575*2b4a7802SBaban Kenkre return; 576*2b4a7802SBaban Kenkre adutils_lookup_batch_release(&(*state)->qs); 577e3c2d6aaSnw141292 idmap_cleanup_batch(*state); 578c5c4113dSnw141292 free(*state); 579c5c4113dSnw141292 *state = NULL; 580c5c4113dSnw141292 } 581c5c4113dSnw141292 582c5c4113dSnw141292 idmap_retcode 5830dcc7149Snw141292 idmap_lookup_batch_end(idmap_query_state_t **state) 584c5c4113dSnw141292 { 585*2b4a7802SBaban Kenkre adutils_rc ad_rc; 586*2b4a7802SBaban Kenkre int i; 587*2b4a7802SBaban Kenkre idmap_query_state_t *id_qs = *state; 588c5c4113dSnw141292 589*2b4a7802SBaban Kenkre ad_rc = adutils_lookup_batch_end(&id_qs->qs); 590c5c4113dSnw141292 591*2b4a7802SBaban Kenkre /* 592*2b4a7802SBaban Kenkre * Map adutils rc to idmap_retcode in each 593*2b4a7802SBaban Kenkre * query because consumers in dbutils.c 594*2b4a7802SBaban Kenkre * expects idmap_retcode. 595*2b4a7802SBaban Kenkre */ 596*2b4a7802SBaban Kenkre for (i = 0; i < id_qs->qcount; i++) { 597*2b4a7802SBaban Kenkre *id_qs->queries[i].rc = 598*2b4a7802SBaban Kenkre map_adrc2idmaprc(id_qs->queries[i].ad_rc); 599c5c4113dSnw141292 } 60084decf41Sjp151216 idmap_lookup_release_batch(state); 601*2b4a7802SBaban Kenkre return (map_adrc2idmaprc(ad_rc)); 602c5c4113dSnw141292 } 603c5c4113dSnw141292 604c5c4113dSnw141292 /* 605c5c4113dSnw141292 * Send one prepared search, queue up msgid, process what results are 606c5c4113dSnw141292 * available 607c5c4113dSnw141292 */ 608c5c4113dSnw141292 static 609c5c4113dSnw141292 idmap_retcode 61048258c6bSjp151216 idmap_batch_add1(idmap_query_state_t *state, const char *filter, 61148258c6bSjp151216 char *ecanonname, char *edomain, int eunixtype, 61248258c6bSjp151216 char **dn, char **attr, char **value, 61348258c6bSjp151216 char **canonname, char **dname, 61448258c6bSjp151216 char **sid, rid_t *rid, int *sid_type, char **unixname, 61548258c6bSjp151216 idmap_retcode *rc) 616c5c4113dSnw141292 { 617*2b4a7802SBaban Kenkre adutils_rc ad_rc; 618*2b4a7802SBaban Kenkre int qid, i; 619c5c4113dSnw141292 idmap_q_t *q; 620cd37da74Snw141292 static char *attrs[] = { 621cd37da74Snw141292 SAN, 622cd37da74Snw141292 OBJSID, 623cd37da74Snw141292 OBJCLASS, 624e8c27ec8Sbaban NULL, /* placeholder for unixname attr */ 625e8c27ec8Sbaban NULL, /* placeholder for unixname attr */ 626cd37da74Snw141292 NULL 627cd37da74Snw141292 }; 628c5c4113dSnw141292 629c5c4113dSnw141292 qid = atomic_inc_32_nv(&state->qlastsent) - 1; 630c5c4113dSnw141292 q = &(state->queries[qid]); 631c5c4113dSnw141292 632cd37da74Snw141292 /* 633*2b4a7802SBaban Kenkre * Remember the expected canonname, domainname and unix type 634*2b4a7802SBaban 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 /* 697*2b4a7802SBaban Kenkre * Invoke the mother of all APIs i.e. the adutils API 698c5c4113dSnw141292 */ 699*2b4a7802SBaban Kenkre ad_rc = adutils_lookup_batch_add(state->qs, filter, 700*2b4a7802SBaban Kenkre (const char **)attrs, 701*2b4a7802SBaban Kenkre edomain, &q->result, &q->ad_rc); 702*2b4a7802SBaban 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 { 747*2b4a7802SBaban Kenkre /* 'name' not qualified and dname not given */ 748*2b4a7802SBaban Kenkre dname = adutils_lookup_batch_getdefdomain( 749*2b4a7802SBaban Kenkre state->qs); 750*2b4a7802SBaban Kenkre assert(dname != NULL); 751*2b4a7802SBaban Kenkre if (*dname == '\0') { 752cd37da74Snw141292 free(ecanonname); 753e3c2d6aaSnw141292 return (IDMAP_ERR_DOMAIN); 754e3c2d6aaSnw141292 } 755*2b4a7802SBaban 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 768479ac375Sdm199847 s_name = sanitize_for_ldap_filter(name); 769479ac375Sdm199847 if (s_name == NULL) { 770cd37da74Snw141292 free(ecanonname); 771479ac375Sdm199847 free(edomain); 772c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 773c5c4113dSnw141292 } 774479ac375Sdm199847 775479ac375Sdm199847 /* Assemble filter */ 776479ac375Sdm199847 len = snprintf(NULL, 0, SANFILTER, samAcctNameLen, s_name) + 1; 777479ac375Sdm199847 if ((filter = (char *)malloc(len)) == NULL) { 778479ac375Sdm199847 free(ecanonname); 779479ac375Sdm199847 free(edomain); 780479ac375Sdm199847 if (s_name != name) 781479ac375Sdm199847 free(s_name); 782479ac375Sdm199847 return (IDMAP_ERR_MEMORY); 783479ac375Sdm199847 } 784479ac375Sdm199847 (void) snprintf(filter, len, SANFILTER, samAcctNameLen, s_name); 785479ac375Sdm199847 if (s_name != name) 786479ac375Sdm199847 free(s_name); 787c5c4113dSnw141292 788cd37da74Snw141292 retcode = idmap_batch_add1(state, filter, ecanonname, edomain, 78948258c6bSjp151216 eunixtype, dn, attr, value, canonname, NULL, sid, rid, sid_type, 79048258c6bSjp151216 unixname, rc); 791c5c4113dSnw141292 792c5c4113dSnw141292 free(filter); 793c5c4113dSnw141292 794c5c4113dSnw141292 return (retcode); 795c5c4113dSnw141292 } 796c5c4113dSnw141292 797c5c4113dSnw141292 idmap_retcode 798c5c4113dSnw141292 idmap_sid2name_batch_add1(idmap_query_state_t *state, 799e8c27ec8Sbaban const char *sid, const rid_t *rid, int eunixtype, 80048258c6bSjp151216 char **dn, char **attr, char **value, 80148258c6bSjp151216 char **name, char **dname, int *sid_type, 80248258c6bSjp151216 char **unixname, idmap_retcode *rc) 803c5c4113dSnw141292 { 804c5c4113dSnw141292 idmap_retcode retcode; 805c5c4113dSnw141292 int flen, ret; 806c5c4113dSnw141292 char *filter = NULL; 807*2b4a7802SBaban Kenkre char cbinsid[ADUTILS_MAXHEXBINSID + 1]; 808c5c4113dSnw141292 809c5c4113dSnw141292 /* 810c5c4113dSnw141292 * Strategy: search [the global catalog] for user/group by 811c5c4113dSnw141292 * objectSid = SID with empty base DN. The DN, sAMAccountName 812c5c4113dSnw141292 * and objectClass of the result are all we need to figure out 813c5c4113dSnw141292 * the name of the SID and whether it is a user, a group or a 814c5c4113dSnw141292 * computer. 815c5c4113dSnw141292 */ 816c5c4113dSnw141292 817*2b4a7802SBaban Kenkre ret = adutils_txtsid2hexbinsid(sid, rid, &cbinsid[0], sizeof (cbinsid)); 818c5c4113dSnw141292 if (ret != 0) 819c5c4113dSnw141292 return (IDMAP_ERR_SID); 820c5c4113dSnw141292 821c5c4113dSnw141292 /* Assemble filter */ 822e3c2d6aaSnw141292 flen = snprintf(NULL, 0, OBJSIDFILTER, cbinsid) + 1; 823c5c4113dSnw141292 if ((filter = (char *)malloc(flen)) == NULL) 824c5c4113dSnw141292 return (IDMAP_ERR_MEMORY); 825e3c2d6aaSnw141292 (void) snprintf(filter, flen, OBJSIDFILTER, cbinsid); 826c5c4113dSnw141292 827e8c27ec8Sbaban retcode = idmap_batch_add1(state, filter, NULL, NULL, eunixtype, 82848258c6bSjp151216 dn, attr, value, name, dname, NULL, NULL, sid_type, unixname, rc); 829e8c27ec8Sbaban 830e8c27ec8Sbaban free(filter); 831e8c27ec8Sbaban 832e8c27ec8Sbaban return (retcode); 833e8c27ec8Sbaban } 834e8c27ec8Sbaban 835e8c27ec8Sbaban idmap_retcode 836e8c27ec8Sbaban idmap_unixname2sid_batch_add1(idmap_query_state_t *state, 837e8c27ec8Sbaban const char *unixname, int is_user, int is_wuser, 83848258c6bSjp151216 char **dn, char **attr, char **value, 83948258c6bSjp151216 char **sid, rid_t *rid, char **name, 84048258c6bSjp151216 char **dname, int *sid_type, idmap_retcode *rc) 841e8c27ec8Sbaban { 842e8c27ec8Sbaban idmap_retcode retcode; 843e8c27ec8Sbaban int len, ulen; 844479ac375Sdm199847 char *filter = NULL, *s_unixname; 845e8c27ec8Sbaban const char *attrname = NULL; 846e8c27ec8Sbaban 847e8c27ec8Sbaban /* Get unixuser or unixgroup AD attribute name */ 848e8c27ec8Sbaban attrname = (is_user) ? 849e8c27ec8Sbaban state->ad_unixuser_attr : state->ad_unixgroup_attr; 850e8c27ec8Sbaban if (attrname == NULL) 851e8c27ec8Sbaban return (IDMAP_ERR_NOTFOUND); 852e8c27ec8Sbaban 853479ac375Sdm199847 s_unixname = sanitize_for_ldap_filter(unixname); 854479ac375Sdm199847 if (s_unixname == NULL) 855479ac375Sdm199847 return (IDMAP_ERR_MEMORY); 856479ac375Sdm199847 857e8c27ec8Sbaban /* Assemble filter */ 858e8c27ec8Sbaban ulen = strlen(unixname); 859e8c27ec8Sbaban len = snprintf(NULL, 0, "(&(objectclass=%s)(%s=%.*s))", 860479ac375Sdm199847 is_wuser ? "user" : "group", attrname, ulen, s_unixname) + 1; 861479ac375Sdm199847 if ((filter = (char *)malloc(len)) == NULL) { 862479ac375Sdm199847 if (s_unixname != unixname) 863479ac375Sdm199847 free(s_unixname); 864e8c27ec8Sbaban return (IDMAP_ERR_MEMORY); 865479ac375Sdm199847 } 866e8c27ec8Sbaban (void) snprintf(filter, len, "(&(objectclass=%s)(%s=%.*s))", 867479ac375Sdm199847 is_wuser ? "user" : "group", attrname, ulen, s_unixname); 868479ac375Sdm199847 if (s_unixname != unixname) 869479ac375Sdm199847 free(s_unixname); 870e8c27ec8Sbaban 871e8c27ec8Sbaban retcode = idmap_batch_add1(state, filter, NULL, NULL, 87248258c6bSjp151216 _IDMAP_T_UNDEF, dn, NULL, NULL, name, dname, sid, rid, sid_type, 87348258c6bSjp151216 NULL, rc); 87448258c6bSjp151216 87548258c6bSjp151216 if (retcode == IDMAP_SUCCESS && attr != NULL) { 87648258c6bSjp151216 if ((*attr = strdup(attrname)) == NULL) 87748258c6bSjp151216 retcode = IDMAP_ERR_MEMORY; 87848258c6bSjp151216 } 87948258c6bSjp151216 88048258c6bSjp151216 if (retcode == IDMAP_SUCCESS && value != NULL) { 88148258c6bSjp151216 if (ulen > 0) { 88248258c6bSjp151216 if ((*value = strdup(unixname)) == NULL) 88348258c6bSjp151216 retcode = IDMAP_ERR_MEMORY; 88448258c6bSjp151216 } 88548258c6bSjp151216 else 88648258c6bSjp151216 *value = NULL; 88748258c6bSjp151216 } 888c5c4113dSnw141292 889c5c4113dSnw141292 free(filter); 890c5c4113dSnw141292 891c5c4113dSnw141292 return (retcode); 892c5c4113dSnw141292 } 893