1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * native LDAP related utility routines 29 */ 30 31 #include "idmapd.h" 32 #include "idmap_priv.h" 33 #include "ns_sldap.h" 34 #include "nldaputils.h" 35 #include <assert.h> 36 37 /* 38 * The following are format strings used to construct LDAP search filters 39 * when looking up Native LDAP directory service. The _F_XXX_SSD format 40 * is used by the libsldap API if a corresponding SSD is defined in 41 * Native LDAP configuration. The SSD contains a string that replaces 42 * the first %s in _F_XXX_SSD. If no SSD is defined then the regular 43 * _F_XXX format is used. 44 * 45 * Note that '\\' needs to be represented as "\\5c" in LDAP filters. 46 */ 47 48 /* Native LDAP lookup using UNIX username */ 49 #define _F_GETPWNAM "(&(objectClass=posixAccount)(uid=%s))" 50 #define _F_GETPWNAM_SSD "(&(%%s)(uid=%s))" 51 52 /* 53 * Native LDAP user lookup using names of well-known SIDs 54 * Note the use of 1$, 2$ in the format string which basically 55 * allows snprintf to re-use its first two arguments. 56 */ 57 #define _F_GETPWWNAMWK \ 58 "(&(objectClass=posixAccount)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))" 59 #define _F_GETPWWNAMWK_SSD "(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))" 60 61 /* Native LDAP user lookup using winname@windomain OR windomain\winname */ 62 #define _F_GETPWWNAMDOM \ 63 "(&(objectClass=posixAccount)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))" 64 #define _F_GETPWWNAMDOM_SSD "(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))" 65 66 /* Native LDAP lookup using UID */ 67 #define _F_GETPWUID "(&(objectClass=posixAccount)(uidNumber=%u))" 68 #define _F_GETPWUID_SSD "(&(%%s)(uidNumber=%u))" 69 70 /* Native LDAP lookup using UNIX groupname */ 71 #define _F_GETGRNAM "(&(objectClass=posixGroup)(cn=%s))" 72 #define _F_GETGRNAM_SSD "(&(%%s)(cn=%s))" 73 74 /* Native LDAP group lookup using names of well-known SIDs */ 75 #define _F_GETGRWNAMWK \ 76 "(&(objectClass=posixGroup)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))" 77 #define _F_GETGRWNAMWK_SSD "(&(%%s)(|(%s=%s)(%1$s=BUILTIN\\5c%2$s)))" 78 79 /* Native LDAP group lookup using winname@windomain OR windomain\winname */ 80 #define _F_GETGRWNAMDOM \ 81 "(&(objectClass=posixGroup)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))" 82 #define _F_GETGRWNAMDOM_SSD "(&(%%s)(|(%s=%s@%s)(%1$s=%3$s\\5c%2$s)))" 83 84 /* Native LDAP lookup using GID */ 85 #define _F_GETGRGID "(&(objectClass=posixGroup)(gidNumber=%u))" 86 #define _F_GETGRGID_SSD "(&(%%s)(gidNumber=%u))" 87 88 /* Native LDAP attribute names */ 89 #define UID "uid" 90 #define CN "cn" 91 #define UIDNUMBER "uidnumber" 92 #define GIDNUMBER "gidnumber" 93 #define DN "dn" 94 95 #define IS_NLDAP_RC_FATAL(x) ((x == NS_LDAP_MEMORY) ? 1 : 0) 96 97 typedef struct idmap_nldap_q { 98 char **winname; 99 char **windomain; 100 char **unixname; 101 uid_t *pid; 102 char **dn; 103 char **attr; 104 char **value; 105 int is_user; 106 idmap_retcode *rc; 107 int lrc; 108 ns_ldap_result_t *result; 109 ns_ldap_error_t *errorp; 110 char *filter; 111 char *udata; 112 } idmap_nldap_q_t; 113 114 typedef struct idmap_nldap_query_state { 115 const char *nldap_winname_attr; 116 const char *defdom; 117 int nqueries; 118 int qid; 119 int flag; 120 ns_ldap_list_batch_t *batch; 121 idmap_nldap_q_t queries[1]; 122 } idmap_nldap_query_state_t; 123 124 /* 125 * This routine has been copied from lib/nsswitch/ldap/common/ldap_utils.c 126 * after removing the debug statements. 127 * 128 * This is a generic filter callback function for merging the filter 129 * from service search descriptor with an existing search filter. This 130 * routine expects userdata to contain a format string with a single %s 131 * in it, and will use the format string with sprintf() to insert the 132 * SSD filter. 133 * 134 * This routine and userdata are passed to the __ns_ldap_list_batch_add() 135 * API. 136 * 137 * Consider an example that uses __ns_ldap_list_batch_add() to lookup 138 * native LDAP directory using a given userid 'xy12345'. In this 139 * example the userdata will contain the filter "(&(%s)(cn=xy1234))". 140 * If a SSD is defined to replace the rfc2307bis specified filter 141 * i.e. (objectClass=posixAccount) by a site-specific filter 142 * say (department=sds) then this routine when called will produce 143 * "(&(department=sds)(uid=xy1234))" as the real search filter. 144 */ 145 static 146 int 147 merge_SSD_filter(const ns_ldap_search_desc_t *desc, 148 char **realfilter, const void *userdata) 149 { 150 int len; 151 if (realfilter == NULL) 152 return (NS_LDAP_INVALID_PARAM); 153 *realfilter = NULL; 154 if (desc == NULL || desc->filter == NULL || userdata == NULL) 155 return (NS_LDAP_INVALID_PARAM); 156 len = strlen(userdata) + strlen(desc->filter) + 1; 157 *realfilter = (char *)malloc(len); 158 if (*realfilter == NULL) 159 return (NS_LDAP_MEMORY); 160 (void) sprintf(*realfilter, (char *)userdata, desc->filter); 161 return (NS_LDAP_SUCCESS); 162 } 163 164 static 165 char 166 hex_char(int n) 167 { 168 return ("0123456789abcdef"[n & 0xf]); 169 } 170 171 /* 172 * If the input string contains special characters that needs to be 173 * escaped before the string can be used in a LDAP filter then this 174 * function will return a new sanitized string. Otherwise this function 175 * returns the input string (This saves us un-necessary memory allocations 176 * especially when processing a batch of requests). The caller must free 177 * the returned string if it isn't the input string. 178 * 179 * The escape mechanism for LDAP filter is described in RFC2254 basically 180 * it's \hh where hh are the two hexadecimal digits representing the ASCII 181 * value of the encoded character (case of hh is not significant). 182 * Example: * -> \2a, ( -> \28, ) -> \29, \ -> \5c, 183 * 184 * outstring = sanitize_for_ldap_filter(instring); 185 * if (outstring == NULL) 186 * Out of memory 187 * else 188 * Use outstring 189 * if (outstring != instring) 190 * free(outstring); 191 * done 192 */ 193 char * 194 sanitize_for_ldap_filter(const char *str) 195 { 196 const char *p; 197 char *q, *s_str = NULL; 198 int n; 199 200 /* Get a count of special characters */ 201 for (p = str, n = 0; *p; p++) 202 if (*p == '*' || *p == '(' || *p == ')' || 203 *p == '\\' || *p == '%') 204 n++; 205 /* If count is zero then no need to sanitize */ 206 if (n == 0) 207 return ((char *)str); 208 /* Create output buffer that will contain the sanitized value */ 209 s_str = calloc(1, n * 2 + strlen(str) + 1); 210 if (s_str == NULL) 211 return (NULL); 212 for (p = str, q = s_str; *p; p++) { 213 if (*p == '*' || *p == '(' || *p == ')' || 214 *p == '\\' || *p == '%') { 215 *q++ = '\\'; 216 *q++ = hex_char(*p >> 4); 217 *q++ = hex_char(*p & 0xf); 218 } else 219 *q++ = *p; 220 } 221 return (s_str); 222 } 223 224 /* 225 * Map libsldap status to idmap status 226 */ 227 static 228 idmap_retcode 229 nldaprc2retcode(int rc) 230 { 231 switch (rc) { 232 case NS_LDAP_SUCCESS: 233 case NS_LDAP_SUCCESS_WITH_INFO: 234 return (IDMAP_SUCCESS); 235 case NS_LDAP_NOTFOUND: 236 return (IDMAP_ERR_NOTFOUND); 237 case NS_LDAP_MEMORY: 238 return (IDMAP_ERR_MEMORY); 239 case NS_LDAP_CONFIG: 240 return (IDMAP_ERR_NS_LDAP_CFG); 241 case NS_LDAP_OP_FAILED: 242 return (IDMAP_ERR_NS_LDAP_OP_FAILED); 243 case NS_LDAP_PARTIAL: 244 return (IDMAP_ERR_NS_LDAP_PARTIAL); 245 case NS_LDAP_INTERNAL: 246 return (IDMAP_ERR_INTERNAL); 247 case NS_LDAP_INVALID_PARAM: 248 return (IDMAP_ERR_ARG); 249 default: 250 return (IDMAP_ERR_OTHER); 251 } 252 /*NOTREACHED*/ 253 } 254 255 /* 256 * Create a batch for native LDAP lookup. 257 */ 258 static 259 idmap_retcode 260 idmap_nldap_lookup_batch_start(int nqueries, idmap_nldap_query_state_t **qs) 261 { 262 idmap_nldap_query_state_t *s; 263 264 s = calloc(1, sizeof (*s) + 265 (nqueries - 1) * sizeof (idmap_nldap_q_t)); 266 if (s == NULL) 267 return (IDMAP_ERR_MEMORY); 268 if (__ns_ldap_list_batch_start(&s->batch) != NS_LDAP_SUCCESS) { 269 free(s); 270 return (IDMAP_ERR_MEMORY); 271 } 272 s->nqueries = nqueries; 273 s->flag = NS_LDAP_KEEP_CONN; 274 *qs = s; 275 return (IDMAP_SUCCESS); 276 } 277 278 /* 279 * Add a lookup by winname request to the batch. 280 */ 281 static 282 idmap_retcode 283 idmap_nldap_bywinname_batch_add(idmap_nldap_query_state_t *qs, 284 const char *winname, const char *windomain, int is_user, 285 char **dn, char **attr, char **value, 286 char **unixname, uid_t *pid, idmap_retcode *rc) 287 { 288 idmap_nldap_q_t *q; 289 const char *db, *filter, *udata; 290 int flen, ulen, wksid = 0; 291 char *s_winname, *s_windomain; 292 const char **attrs; 293 const char *pwd_attrs[] = {UID, UIDNUMBER, NULL, NULL}; 294 const char *grp_attrs[] = {CN, GIDNUMBER, NULL, NULL}; 295 296 s_winname = s_windomain = NULL; 297 q = &(qs->queries[qs->qid++]); 298 q->unixname = unixname; 299 q->pid = pid; 300 q->rc = rc; 301 q->is_user = is_user; 302 q->dn = dn; 303 q->attr = attr; 304 q->value = value; 305 306 if (is_user) { 307 db = "passwd"; 308 if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, NULL, 309 NULL, NULL) == IDMAP_SUCCESS) { 310 filter = _F_GETPWWNAMWK; 311 udata = _F_GETPWWNAMWK_SSD; 312 wksid = 1; 313 } else if (windomain != NULL) { 314 filter = _F_GETPWWNAMDOM; 315 udata = _F_GETPWWNAMDOM_SSD; 316 } else { 317 *q->rc = IDMAP_ERR_DOMAIN_NOTFOUND; 318 goto errout; 319 } 320 pwd_attrs[2] = qs->nldap_winname_attr; 321 attrs = pwd_attrs; 322 } else { 323 db = "group"; 324 if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, NULL, 325 NULL, NULL) == IDMAP_SUCCESS) { 326 filter = _F_GETGRWNAMWK; 327 udata = _F_GETGRWNAMWK_SSD; 328 wksid = 1; 329 } else if (windomain != NULL) { 330 filter = _F_GETGRWNAMDOM; 331 udata = _F_GETGRWNAMDOM_SSD; 332 } else { 333 *q->rc = IDMAP_ERR_DOMAIN_NOTFOUND; 334 goto errout; 335 } 336 grp_attrs[2] = qs->nldap_winname_attr; 337 attrs = grp_attrs; 338 } 339 340 /* 341 * Sanitize names. No need to sanitize qs->nldap_winname_attr 342 * because if it contained any of the special characters then 343 * it would have been rejected by the function that reads it 344 * from the SMF config. LDAP attribute names can only contain 345 * letters, digits or hyphens. 346 */ 347 s_winname = sanitize_for_ldap_filter(winname); 348 if (s_winname == NULL) { 349 *q->rc = IDMAP_ERR_MEMORY; 350 goto errout; 351 } 352 /* windomain could be NULL for names of well-known SIDs */ 353 if (windomain != NULL) { 354 s_windomain = sanitize_for_ldap_filter(windomain); 355 if (s_windomain == NULL) { 356 *q->rc = IDMAP_ERR_MEMORY; 357 goto errout; 358 } 359 } 360 361 /* Construct the filter and udata using snprintf. */ 362 if (wksid) { 363 flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr, 364 s_winname) + 1; 365 ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr, 366 s_winname) + 1; 367 } else { 368 flen = snprintf(NULL, 0, filter, qs->nldap_winname_attr, 369 s_winname, s_windomain) + 1; 370 ulen = snprintf(NULL, 0, udata, qs->nldap_winname_attr, 371 s_winname, s_windomain) + 1; 372 } 373 374 q->filter = malloc(flen); 375 if (q->filter == NULL) { 376 *q->rc = IDMAP_ERR_MEMORY; 377 goto errout; 378 } 379 q->udata = malloc(ulen); 380 if (q->udata == NULL) { 381 *q->rc = IDMAP_ERR_MEMORY; 382 goto errout; 383 } 384 385 if (wksid) { 386 (void) snprintf(q->filter, flen, filter, 387 qs->nldap_winname_attr, s_winname); 388 (void) snprintf(q->udata, ulen, udata, 389 qs->nldap_winname_attr, s_winname); 390 } else { 391 (void) snprintf(q->filter, flen, filter, 392 qs->nldap_winname_attr, s_winname, s_windomain); 393 (void) snprintf(q->udata, ulen, udata, 394 qs->nldap_winname_attr, s_winname, s_windomain); 395 } 396 397 if (s_winname != winname) 398 free(s_winname); 399 if (s_windomain != windomain) 400 free(s_windomain); 401 402 q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter, 403 merge_SSD_filter, attrs, NULL, qs->flag, &q->result, 404 &q->errorp, &q->lrc, NULL, q->udata); 405 406 if (IS_NLDAP_RC_FATAL(q->lrc)) 407 return (nldaprc2retcode(q->lrc)); 408 return (IDMAP_SUCCESS); 409 410 errout: 411 /* query q and its content will be freed by batch_release */ 412 if (s_winname != winname) 413 free(s_winname); 414 if (s_windomain != windomain) 415 free(s_windomain); 416 return (*q->rc); 417 } 418 419 /* 420 * Add a lookup by uid/gid request to the batch. 421 */ 422 static 423 idmap_retcode 424 idmap_nldap_bypid_batch_add(idmap_nldap_query_state_t *qs, 425 uid_t pid, int is_user, char **dn, char **attr, char **value, 426 char **winname, char **windomain, 427 char **unixname, idmap_retcode *rc) 428 { 429 idmap_nldap_q_t *q; 430 const char *db, *filter, *udata; 431 int len; 432 const char **attrs; 433 const char *pwd_attrs[] = {UID, NULL, NULL}; 434 const char *grp_attrs[] = {CN, NULL, NULL}; 435 436 q = &(qs->queries[qs->qid++]); 437 q->winname = winname; 438 q->windomain = windomain; 439 q->unixname = unixname; 440 q->rc = rc; 441 q->is_user = is_user; 442 q->dn = dn; 443 q->attr = attr; 444 q->value = value; 445 446 if (is_user) { 447 db = "passwd"; 448 filter = _F_GETPWUID; 449 udata = _F_GETPWUID_SSD; 450 pwd_attrs[1] = qs->nldap_winname_attr; 451 attrs = pwd_attrs; 452 } else { 453 db = "group"; 454 filter = _F_GETGRGID; 455 udata = _F_GETGRGID_SSD; 456 grp_attrs[1] = qs->nldap_winname_attr; 457 attrs = grp_attrs; 458 } 459 460 len = snprintf(NULL, 0, filter, pid) + 1; 461 q->filter = malloc(len); 462 if (q->filter == NULL) { 463 *q->rc = IDMAP_ERR_MEMORY; 464 return (IDMAP_ERR_MEMORY); 465 } 466 (void) snprintf(q->filter, len, filter, pid); 467 468 len = snprintf(NULL, 0, udata, pid) + 1; 469 q->udata = malloc(len); 470 if (q->udata == NULL) { 471 *q->rc = IDMAP_ERR_MEMORY; 472 return (IDMAP_ERR_MEMORY); 473 } 474 (void) snprintf(q->udata, len, udata, pid); 475 476 q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter, 477 merge_SSD_filter, attrs, NULL, qs->flag, &q->result, 478 &q->errorp, &q->lrc, NULL, q->udata); 479 480 if (IS_NLDAP_RC_FATAL(q->lrc)) 481 return (nldaprc2retcode(q->lrc)); 482 return (IDMAP_SUCCESS); 483 } 484 485 /* 486 * Add a lookup by user/group name request to the batch. 487 */ 488 static 489 idmap_retcode 490 idmap_nldap_byunixname_batch_add(idmap_nldap_query_state_t *qs, 491 const char *unixname, int is_user, 492 char **dn, char **attr, char **value, 493 char **winname, char **windomain, uid_t *pid, idmap_retcode *rc) 494 { 495 idmap_nldap_q_t *q; 496 const char *db, *filter, *udata; 497 int len; 498 char *s_unixname = NULL; 499 const char **attrs; 500 const char *pwd_attrs[] = {UIDNUMBER, NULL, NULL}; 501 const char *grp_attrs[] = {GIDNUMBER, NULL, NULL}; 502 503 q = &(qs->queries[qs->qid++]); 504 q->winname = winname; 505 q->windomain = windomain; 506 q->pid = pid; 507 q->rc = rc; 508 q->is_user = is_user; 509 q->dn = dn; 510 q->attr = attr; 511 q->value = value; 512 513 if (is_user) { 514 db = "passwd"; 515 filter = _F_GETPWNAM; 516 udata = _F_GETPWNAM_SSD; 517 pwd_attrs[1] = qs->nldap_winname_attr; 518 attrs = pwd_attrs; 519 } else { 520 db = "group"; 521 filter = _F_GETGRNAM; 522 udata = _F_GETGRNAM_SSD; 523 grp_attrs[1] = qs->nldap_winname_attr; 524 attrs = grp_attrs; 525 } 526 527 s_unixname = sanitize_for_ldap_filter(unixname); 528 if (s_unixname == NULL) { 529 *q->rc = IDMAP_ERR_MEMORY; 530 return (IDMAP_ERR_MEMORY); 531 } 532 533 len = snprintf(NULL, 0, filter, s_unixname) + 1; 534 q->filter = malloc(len); 535 if (q->filter == NULL) { 536 if (s_unixname != unixname) 537 free(s_unixname); 538 *q->rc = IDMAP_ERR_MEMORY; 539 return (IDMAP_ERR_MEMORY); 540 } 541 (void) snprintf(q->filter, len, filter, s_unixname); 542 543 len = snprintf(NULL, 0, udata, s_unixname) + 1; 544 q->udata = malloc(len); 545 if (q->udata == NULL) { 546 if (s_unixname != unixname) 547 free(s_unixname); 548 *q->rc = IDMAP_ERR_MEMORY; 549 return (IDMAP_ERR_MEMORY); 550 } 551 (void) snprintf(q->udata, len, udata, s_unixname); 552 553 if (s_unixname != unixname) 554 free(s_unixname); 555 556 q->lrc = __ns_ldap_list_batch_add(qs->batch, db, q->filter, 557 merge_SSD_filter, attrs, NULL, qs->flag, &q->result, 558 &q->errorp, &q->lrc, NULL, q->udata); 559 560 if (IS_NLDAP_RC_FATAL(q->lrc)) 561 return (nldaprc2retcode(q->lrc)); 562 return (IDMAP_SUCCESS); 563 } 564 565 /* 566 * Free the batch 567 */ 568 static 569 void 570 idmap_nldap_lookup_batch_release(idmap_nldap_query_state_t *qs) 571 { 572 idmap_nldap_q_t *q; 573 int i; 574 575 if (qs->batch != NULL) 576 (void) __ns_ldap_list_batch_release(qs->batch); 577 for (i = 0; i < qs->qid; i++) { 578 q = &(qs->queries[i]); 579 free(q->filter); 580 free(q->udata); 581 if (q->errorp != NULL) 582 (void) __ns_ldap_freeError(&q->errorp); 583 if (q->result != NULL) 584 (void) __ns_ldap_freeResult(&q->result); 585 } 586 free(qs); 587 } 588 589 /* 590 * Process all requests added to the batch and then free the batch. 591 * The results for individual requests will be accessible using the 592 * pointers passed during idmap_nldap_lookup_batch_end. 593 */ 594 static 595 idmap_retcode 596 idmap_nldap_lookup_batch_end(idmap_nldap_query_state_t *qs) 597 { 598 idmap_nldap_q_t *q; 599 int i; 600 ns_ldap_entry_t *entry; 601 char **val, *end, *str, *name, *dom; 602 idmap_retcode rc = IDMAP_SUCCESS; 603 604 (void) __ns_ldap_list_batch_end(qs->batch); 605 qs->batch = NULL; 606 for (i = 0; i < qs->qid; i++) { 607 q = &(qs->queries[i]); 608 *q->rc = nldaprc2retcode(q->lrc); 609 if (*q->rc != IDMAP_SUCCESS) 610 continue; 611 if (q->result == NULL || 612 !q->result->entries_count || 613 (entry = q->result->entry) == NULL || 614 !entry->attr_count) { 615 *q->rc = IDMAP_ERR_NOTFOUND; 616 continue; 617 } 618 /* Get uid/gid */ 619 if (q->pid != NULL) { 620 val = __ns_ldap_getAttr(entry, 621 (q->is_user) ? UIDNUMBER : GIDNUMBER); 622 if (val != NULL && *val != NULL) 623 *q->pid = strtoul(*val, &end, 10); 624 } 625 /* Get unixname */ 626 if (q->unixname != NULL) { 627 val = __ns_ldap_getAttr(entry, 628 (q->is_user) ? UID : CN); 629 if (val != NULL && *val != NULL) { 630 *q->unixname = strdup(*val); 631 if (*q->unixname == NULL) { 632 rc = *q->rc = IDMAP_ERR_MEMORY; 633 goto out; 634 } 635 } 636 } 637 /* Get DN for how info */ 638 if (q->dn != NULL) { 639 val = __ns_ldap_getAttr(entry, DN); 640 if (val != NULL && *val != NULL) { 641 *q->dn = strdup(*val); 642 if (*q->dn == NULL) { 643 rc = *q->rc = IDMAP_ERR_MEMORY; 644 goto out; 645 } 646 } 647 } 648 /* Get nldap name mapping attr name for how info */ 649 if (q->attr != NULL) { 650 *q->attr = strdup(qs->nldap_winname_attr); 651 if (*q->attr == NULL) { 652 rc = *q->rc = IDMAP_ERR_MEMORY; 653 goto out; 654 } 655 } 656 /* Get nldap name mapping attr value for how info */ 657 val = __ns_ldap_getAttr(entry, qs->nldap_winname_attr); 658 if (val == NULL || *val == NULL) 659 continue; 660 if (q->value != NULL) { 661 *q->value = strdup(*val); 662 if (*q->value == NULL) { 663 rc = *q->rc = IDMAP_ERR_MEMORY; 664 goto out; 665 } 666 } 667 668 /* Get winname and windomain */ 669 if (q->winname == NULL && q->windomain == NULL) 670 continue; 671 /* 672 * We need to split the value into winname and 673 * windomain. The value could be either in NT4 674 * style (i.e. dom\name) or AD-style (i.e. name@dom). 675 * We choose the first '\\' if it's in NT4 style and 676 * the last '@' if it's in AD-style for the split. 677 */ 678 name = dom = NULL; 679 if (lookup_wksids_name2sid(*val, NULL, NULL, NULL, NULL, NULL, 680 NULL) == IDMAP_SUCCESS) { 681 name = *val; 682 dom = NULL; 683 } else if ((str = strchr(*val, '\\')) != NULL) { 684 *str = '\0'; 685 name = str + 1; 686 dom = *val; 687 } else if ((str = strrchr(*val, '@')) != NULL) { 688 *str = '\0'; 689 name = *val; 690 dom = str + 1; 691 } else { 692 idmapdlog(LOG_INFO, "Domain-less " 693 "winname (%s) found in Native LDAP", *val); 694 *q->rc = IDMAP_ERR_NS_LDAP_BAD_WINNAME; 695 continue; 696 } 697 if (q->winname != NULL) { 698 *q->winname = strdup(name); 699 if (*q->winname == NULL) { 700 rc = *q->rc = IDMAP_ERR_MEMORY; 701 goto out; 702 } 703 } 704 if (q->windomain != NULL && dom != NULL) { 705 *q->windomain = strdup(dom); 706 if (*q->windomain == NULL) { 707 rc = *q->rc = IDMAP_ERR_MEMORY; 708 goto out; 709 } 710 } 711 } 712 713 out: 714 (void) idmap_nldap_lookup_batch_release(qs); 715 return (rc); 716 } 717 718 /* ARGSUSED */ 719 idmap_retcode 720 nldap_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch, 721 idmap_ids_res *result) 722 { 723 idmap_retcode retcode, rc1; 724 int i, add, is_wuser; 725 idmap_mapping *req; 726 idmap_id_res *res; 727 idmap_nldap_query_state_t *qs = NULL; 728 idmap_how *how; 729 730 if (state->nldap_nqueries == 0) 731 return (IDMAP_SUCCESS); 732 733 /* Create nldap lookup batch */ 734 retcode = idmap_nldap_lookup_batch_start(state->nldap_nqueries, &qs); 735 if (retcode != IDMAP_SUCCESS) { 736 idmapdlog(LOG_ERR, 737 "Failed to create batch for native LDAP lookup"); 738 goto out; 739 } 740 741 qs->nldap_winname_attr = state->nldap_winname_attr; 742 qs->defdom = state->defdom; 743 744 /* Add requests to the batch */ 745 for (i = 0, add = 0; i < batch->idmap_mapping_batch_len; i++) { 746 req = &batch->idmap_mapping_batch_val[i]; 747 res = &result->ids.ids_val[i]; 748 retcode = IDMAP_SUCCESS; 749 750 /* Skip if not marked for nldap lookup */ 751 if (!(req->direction & _IDMAP_F_LOOKUP_NLDAP)) 752 continue; 753 754 if (IS_REQUEST_SID(*req, 1)) { 755 756 /* win2unix request: */ 757 758 /* 759 * When processing a win2unix request, nldap lookup 760 * is performed after AD lookup or a successful 761 * name-cache lookup. Therefore we should already 762 * have sid, winname and sidtype. Note that 763 * windomain could be NULL e.g. well-known SIDs. 764 */ 765 assert(req->id1name != NULL && 766 (res->id.idtype == IDMAP_UID || 767 res->id.idtype == IDMAP_GID)); 768 769 /* Skip if we already have pid and unixname */ 770 if (req->id2name != NULL && 771 res->id.idmap_id_u.uid != IDMAP_SENTINEL_PID) { 772 res->retcode = IDMAP_SUCCESS; 773 continue; 774 } 775 776 /* Clear leftover value */ 777 free(req->id2name); 778 req->id2name = NULL; 779 780 /* Lookup nldap by winname to get pid and unixname */ 781 add = 1; 782 idmap_info_free(&res->info); 783 res->info.src = IDMAP_MAP_SRC_NEW; 784 how = &res->info.how; 785 how->map_type = IDMAP_MAP_TYPE_DS_NLDAP; 786 retcode = idmap_nldap_bywinname_batch_add( 787 qs, req->id1name, req->id1domain, 788 (res->id.idtype == IDMAP_UID) ? 1 : 0, 789 &how->idmap_how_u.nldap.dn, 790 &how->idmap_how_u.nldap.attr, 791 &how->idmap_how_u.nldap.value, 792 &req->id2name, &res->id.idmap_id_u.uid, 793 &res->retcode); 794 795 } else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) { 796 797 /* unix2win request: */ 798 799 /* Skip if we already have winname */ 800 if (req->id2name != NULL) { 801 res->retcode = IDMAP_SUCCESS; 802 continue; 803 } 804 805 /* Clear old value */ 806 free(req->id2domain); 807 req->id2domain = NULL; 808 809 /* Set how info */ 810 idmap_info_free(&res->info); 811 res->info.src = IDMAP_MAP_SRC_NEW; 812 how = &res->info.how; 813 how->map_type = IDMAP_MAP_TYPE_DS_NLDAP; 814 815 /* Lookup nldap by pid or unixname to get winname */ 816 if (req->id1.idmap_id_u.uid != IDMAP_SENTINEL_PID) { 817 add = 1; 818 retcode = idmap_nldap_bypid_batch_add( 819 qs, req->id1.idmap_id_u.uid, 820 (req->id1.idtype == IDMAP_UID) ? 1 : 0, 821 &how->idmap_how_u.nldap.dn, 822 &how->idmap_how_u.nldap.attr, 823 &how->idmap_how_u.nldap.value, 824 &req->id2name, &req->id2domain, 825 (req->id1name == NULL) ? 826 &req->id1name : NULL, 827 &res->retcode); 828 } else if (req->id1name != NULL) { 829 add = 1; 830 retcode = idmap_nldap_byunixname_batch_add( 831 qs, req->id1name, 832 (req->id1.idtype == IDMAP_UID) ? 1 : 0, 833 &how->idmap_how_u.nldap.dn, 834 &how->idmap_how_u.nldap.attr, 835 &how->idmap_how_u.nldap.value, 836 &req->id2name, &req->id2domain, 837 &req->id1.idmap_id_u.uid, &res->retcode); 838 } 839 840 } 841 842 /* 843 * nldap_batch_add API returns error only on fatal failures 844 * otherwise it returns success and the actual status 845 * is stored in the individual request (res->retcode). 846 * Stop adding requests to this batch on fatal failures 847 * (i.e. if retcode != success) 848 */ 849 if (retcode != IDMAP_SUCCESS) 850 break; 851 } 852 853 if (!add) 854 idmap_nldap_lookup_batch_release(qs); 855 else if (retcode != IDMAP_SUCCESS) 856 idmap_nldap_lookup_batch_release(qs); 857 else 858 retcode = idmap_nldap_lookup_batch_end(qs); 859 860 out: 861 for (i = 0; i < batch->idmap_mapping_batch_len; i++) { 862 req = &batch->idmap_mapping_batch_val[i]; 863 res = &result->ids.ids_val[i]; 864 if (!(req->direction & _IDMAP_F_LOOKUP_NLDAP)) 865 continue; 866 867 /* Reset nldap flag */ 868 req->direction &= ~(_IDMAP_F_LOOKUP_NLDAP); 869 870 /* 871 * As noted earlier retcode != success if there were fatal 872 * errors during batch_start and batch_adds. If so then set 873 * the status of each nldap request to that error. 874 */ 875 if (retcode != IDMAP_SUCCESS) { 876 res->retcode = retcode; 877 continue; 878 } 879 if (!add) 880 continue; 881 882 /* 883 * If we successfully retrieved winname from nldap entry 884 * then lookup winname2sid locally. If not found locally 885 * then mark this request for AD lookup. 886 */ 887 if (res->retcode == IDMAP_SUCCESS && 888 req->id2name != NULL && 889 res->id.idmap_id_u.sid.prefix == NULL && 890 (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req))) { 891 892 is_wuser = -1; 893 rc1 = lookup_name2sid(state->cache, 894 req->id2name, req->id2domain, &is_wuser, 895 NULL, NULL, 896 &res->id.idmap_id_u.sid.prefix, 897 &res->id.idmap_id_u.sid.rid, req, 1); 898 if (rc1 == IDMAP_SUCCESS) 899 res->id.idtype = 900 is_wuser ? IDMAP_USID : IDMAP_GSID; 901 else if (rc1 == IDMAP_ERR_NOTFOUND) { 902 req->direction |= _IDMAP_F_LOOKUP_AD; 903 state->ad_nqueries++; 904 } else 905 res->retcode = rc1; 906 } 907 908 /* 909 * Unset non-fatal errors in individual request. This allows 910 * the next pass to process other mapping mechanisms for 911 * this request. 912 */ 913 if (res->retcode != IDMAP_SUCCESS && 914 res->retcode != IDMAP_ERR_NS_LDAP_BAD_WINNAME && 915 !(IDMAP_FATAL_ERROR(res->retcode))) { 916 idmap_info_free(&res->info); 917 res->retcode = IDMAP_SUCCESS; 918 } 919 } 920 921 state->nldap_nqueries = 0; 922 return (retcode); 923 } 924