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