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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Database related utility routines 30 */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <errno.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <rpc/rpc.h> 39 #include <sys/sid.h> 40 #include <time.h> 41 #include <pwd.h> 42 #include <grp.h> 43 #include <pthread.h> 44 #include <assert.h> 45 #include <sys/u8_textprep.h> 46 47 #include "idmapd.h" 48 #include "adutils.h" 49 #include "string.h" 50 #include "idmap_priv.h" 51 #include "schema.h" 52 #include "nldaputils.h" 53 54 55 static idmap_retcode sql_compile_n_step_once(sqlite *, char *, 56 sqlite_vm **, int *, int, const char ***); 57 static idmap_retcode ad_lookup_one(lookup_state_t *, idmap_mapping *, 58 idmap_id_res *); 59 static idmap_retcode lookup_localsid2pid(idmap_mapping *, idmap_id_res *); 60 static idmap_retcode lookup_cache_name2sid(sqlite *, const char *, 61 const char *, char **, char **, idmap_rid_t *, int *); 62 63 64 #define EMPTY_NAME(name) (*name == 0 || strcmp(name, "\"\"") == 0) 65 66 #define DO_NOT_ALLOC_NEW_ID_MAPPING(req)\ 67 (req->flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC) 68 69 #define AVOID_NAMESERVICE(req)\ 70 (req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE) 71 72 #define IS_EPHEMERAL(pid) (pid > INT32_MAX && pid != SENTINEL_PID) 73 74 #define LOCALRID_MIN 1000 75 76 77 typedef enum init_db_option { 78 FAIL_IF_CORRUPT = 0, 79 REMOVE_IF_CORRUPT = 1 80 } init_db_option_t; 81 82 /* 83 * Data structure to store well-known SIDs and 84 * associated mappings (if any) 85 */ 86 typedef struct wksids_table { 87 const char *sidprefix; 88 uint32_t rid; 89 const char *winname; 90 int is_wuser; 91 uid_t pid; 92 int is_user; 93 int direction; 94 } wksids_table_t; 95 96 /* 97 * Thread specfic data to hold the database handles so that the 98 * databaes are not opened and closed for every request. It also 99 * contains the sqlite busy handler structure. 100 */ 101 102 struct idmap_busy { 103 const char *name; 104 const int *delays; 105 int delay_size; 106 int total; 107 int sec; 108 }; 109 110 111 typedef struct idmap_tsd { 112 sqlite *db_db; 113 sqlite *cache_db; 114 struct idmap_busy cache_busy; 115 struct idmap_busy db_busy; 116 } idmap_tsd_t; 117 118 119 120 static const int cache_delay_table[] = 121 { 1, 2, 5, 10, 15, 20, 25, 30, 35, 40, 122 50, 50, 60, 70, 80, 90, 100}; 123 124 static const int db_delay_table[] = 125 { 5, 10, 15, 20, 30, 40, 55, 70, 100}; 126 127 128 static pthread_key_t idmap_tsd_key; 129 130 void 131 idmap_tsd_destroy(void *key) 132 { 133 134 idmap_tsd_t *tsd = (idmap_tsd_t *)key; 135 if (tsd) { 136 if (tsd->db_db) 137 (void) sqlite_close(tsd->db_db); 138 if (tsd->cache_db) 139 (void) sqlite_close(tsd->cache_db); 140 free(tsd); 141 } 142 } 143 144 int 145 idmap_init_tsd_key(void) 146 { 147 return (pthread_key_create(&idmap_tsd_key, idmap_tsd_destroy)); 148 } 149 150 151 152 idmap_tsd_t * 153 idmap_get_tsd(void) 154 { 155 idmap_tsd_t *tsd; 156 157 if ((tsd = pthread_getspecific(idmap_tsd_key)) == NULL) { 158 /* No thread specific data so create it */ 159 if ((tsd = malloc(sizeof (*tsd))) != NULL) { 160 /* Initialize thread specific data */ 161 (void) memset(tsd, 0, sizeof (*tsd)); 162 /* save the trhread specific data */ 163 if (pthread_setspecific(idmap_tsd_key, tsd) != 0) { 164 /* Can't store key */ 165 free(tsd); 166 tsd = NULL; 167 } 168 } else { 169 tsd = NULL; 170 } 171 } 172 173 return (tsd); 174 } 175 176 /* 177 * A simple wrapper around u8_textprep_str() that returns the Unicode 178 * lower-case version of some string. The result must be freed. 179 */ 180 char * 181 tolower_u8(const char *s) 182 { 183 char *res = NULL; 184 char *outs; 185 size_t inlen, outlen, inbytesleft, outbytesleft; 186 int rc, err; 187 188 /* 189 * u8_textprep_str() does not allocate memory. The input and 190 * output buffers may differ in size (though that would be more 191 * likely when normalization is done). We have to loop over it... 192 * 193 * To improve the chances that we can avoid looping we add 10 194 * bytes of output buffer room the first go around. 195 */ 196 inlen = inbytesleft = strlen(s); 197 outlen = outbytesleft = inlen + 10; 198 if ((res = malloc(outlen)) == NULL) 199 return (NULL); 200 outs = res; 201 202 while ((rc = u8_textprep_str((char *)s, &inbytesleft, outs, 203 &outbytesleft, U8_TEXTPREP_TOLOWER, U8_UNICODE_LATEST, &err)) < 0 && 204 err == E2BIG) { 205 if ((res = realloc(res, outlen + inbytesleft)) == NULL) 206 return (NULL); 207 /* adjust input/output buffer pointers */ 208 s += (inlen - inbytesleft); 209 outs = res + outlen - outbytesleft; 210 /* adjust outbytesleft and outlen */ 211 outlen += inbytesleft; 212 outbytesleft += inbytesleft; 213 } 214 215 if (rc < 0) { 216 free(res); 217 res = NULL; 218 return (NULL); 219 } 220 221 res[outlen - outbytesleft] = '\0'; 222 223 return (res); 224 } 225 226 static int sql_exec_tran_no_cb(sqlite *db, char *sql, const char *dbname, 227 const char *while_doing); 228 229 230 /* 231 * Initialize 'dbname' using 'sql' 232 */ 233 static 234 int 235 init_db_instance(const char *dbname, int version, 236 const char *detect_version_sql, char * const *sql, 237 init_db_option_t opt, int *created, int *upgraded) 238 { 239 int rc, curr_version; 240 int tries = 1; 241 int prio = LOG_NOTICE; 242 sqlite *db = NULL; 243 char *errmsg = NULL; 244 245 *created = 0; 246 *upgraded = 0; 247 248 if (opt == REMOVE_IF_CORRUPT) 249 tries = 3; 250 251 rinse_repeat: 252 if (tries == 0) { 253 idmapdlog(LOG_ERR, "Failed to initialize db %s", dbname); 254 return (-1); 255 } 256 if (tries-- == 1) 257 /* Last try, log errors */ 258 prio = LOG_ERR; 259 260 db = sqlite_open(dbname, 0600, &errmsg); 261 if (db == NULL) { 262 idmapdlog(prio, "Error creating database %s (%s)", 263 dbname, CHECK_NULL(errmsg)); 264 sqlite_freemem(errmsg); 265 if (opt == REMOVE_IF_CORRUPT) 266 (void) unlink(dbname); 267 goto rinse_repeat; 268 } 269 270 sqlite_busy_timeout(db, 3000); 271 272 /* Detect current version of schema in the db, if any */ 273 curr_version = 0; 274 if (detect_version_sql != NULL) { 275 char *end, **results; 276 int nrow; 277 278 #ifdef IDMAPD_DEBUG 279 (void) fprintf(stderr, "Schema version detection SQL: %s\n", 280 detect_version_sql); 281 #endif /* IDMAPD_DEBUG */ 282 rc = sqlite_get_table(db, detect_version_sql, &results, 283 &nrow, NULL, &errmsg); 284 if (rc != SQLITE_OK) { 285 idmapdlog(prio, 286 "Error detecting schema version of db %s (%s)", 287 dbname, errmsg); 288 sqlite_freemem(errmsg); 289 sqlite_free_table(results); 290 sqlite_close(db); 291 return (-1); 292 } 293 if (nrow != 1) { 294 idmapdlog(prio, 295 "Error detecting schema version of db %s", dbname); 296 sqlite_close(db); 297 sqlite_free_table(results); 298 return (-1); 299 } 300 curr_version = strtol(results[1], &end, 10); 301 sqlite_free_table(results); 302 } 303 304 if (curr_version < 0) { 305 if (opt == REMOVE_IF_CORRUPT) 306 (void) unlink(dbname); 307 goto rinse_repeat; 308 } 309 310 if (curr_version == version) 311 goto done; 312 313 /* Install or upgrade schema */ 314 #ifdef IDMAPD_DEBUG 315 (void) fprintf(stderr, "Schema init/upgrade SQL: %s\n", 316 sql[curr_version]); 317 #endif /* IDMAPD_DEBUG */ 318 rc = sql_exec_tran_no_cb(db, sql[curr_version], dbname, 319 (curr_version == 0) ? "installing schema" : "upgrading schema"); 320 if (rc != 0) { 321 idmapdlog(prio, "Error %s schema for db %s", dbname, 322 (curr_version == 0) ? "installing schema" : 323 "upgrading schema"); 324 if (opt == REMOVE_IF_CORRUPT) 325 (void) unlink(dbname); 326 goto rinse_repeat; 327 } 328 329 *upgraded = (curr_version > 0); 330 *created = (curr_version == 0); 331 332 done: 333 (void) sqlite_close(db); 334 return (0); 335 } 336 337 338 /* 339 * This is the SQLite database busy handler that retries the SQL 340 * operation until it is successful. 341 */ 342 int 343 /* LINTED E_FUNC_ARG_UNUSED */ 344 idmap_sqlite_busy_handler(void *arg, const char *table_name, int count) 345 { 346 struct idmap_busy *busy = arg; 347 int delay; 348 struct timespec rqtp; 349 350 if (count == 1) { 351 busy->total = 0; 352 busy->sec = 2; 353 } 354 if (busy->total > 1000 * busy->sec) { 355 idmapdlog(LOG_DEBUG, 356 "Thread %d waited %d sec for the %s database", 357 pthread_self(), busy->sec, busy->name); 358 busy->sec++; 359 } 360 361 if (count <= busy->delay_size) { 362 delay = busy->delays[count-1]; 363 } else { 364 delay = busy->delays[busy->delay_size - 1]; 365 } 366 busy->total += delay; 367 rqtp.tv_sec = 0; 368 rqtp.tv_nsec = delay * (NANOSEC / MILLISEC); 369 (void) nanosleep(&rqtp, NULL); 370 return (1); 371 } 372 373 374 /* 375 * Get the database handle 376 */ 377 idmap_retcode 378 get_db_handle(sqlite **db) 379 { 380 char *errmsg; 381 idmap_tsd_t *tsd; 382 383 /* 384 * Retrieve the db handle from thread-specific storage 385 * If none exists, open and store in thread-specific storage. 386 */ 387 if ((tsd = idmap_get_tsd()) == NULL) { 388 idmapdlog(LOG_ERR, 389 "Error getting thread specific data for %s", IDMAP_DBNAME); 390 return (IDMAP_ERR_MEMORY); 391 } 392 393 if (tsd->db_db == NULL) { 394 tsd->db_db = sqlite_open(IDMAP_DBNAME, 0, &errmsg); 395 if (tsd->db_db == NULL) { 396 idmapdlog(LOG_ERR, "Error opening database %s (%s)", 397 IDMAP_DBNAME, CHECK_NULL(errmsg)); 398 sqlite_freemem(errmsg); 399 return (IDMAP_ERR_DB); 400 } 401 402 tsd->db_busy.name = IDMAP_DBNAME; 403 tsd->db_busy.delays = db_delay_table; 404 tsd->db_busy.delay_size = sizeof (db_delay_table) / 405 sizeof (int); 406 sqlite_busy_handler(tsd->db_db, idmap_sqlite_busy_handler, 407 &tsd->db_busy); 408 } 409 *db = tsd->db_db; 410 return (IDMAP_SUCCESS); 411 } 412 413 /* 414 * Get the cache handle 415 */ 416 idmap_retcode 417 get_cache_handle(sqlite **cache) 418 { 419 char *errmsg; 420 idmap_tsd_t *tsd; 421 422 /* 423 * Retrieve the db handle from thread-specific storage 424 * If none exists, open and store in thread-specific storage. 425 */ 426 if ((tsd = idmap_get_tsd()) == NULL) { 427 idmapdlog(LOG_ERR, "Error getting thread specific data for %s", 428 IDMAP_DBNAME); 429 return (IDMAP_ERR_MEMORY); 430 } 431 432 if (tsd->cache_db == NULL) { 433 tsd->cache_db = sqlite_open(IDMAP_CACHENAME, 0, &errmsg); 434 if (tsd->cache_db == NULL) { 435 idmapdlog(LOG_ERR, "Error opening database %s (%s)", 436 IDMAP_CACHENAME, CHECK_NULL(errmsg)); 437 sqlite_freemem(errmsg); 438 return (IDMAP_ERR_DB); 439 } 440 441 tsd->cache_busy.name = IDMAP_CACHENAME; 442 tsd->cache_busy.delays = cache_delay_table; 443 tsd->cache_busy.delay_size = sizeof (cache_delay_table) / 444 sizeof (int); 445 sqlite_busy_handler(tsd->cache_db, idmap_sqlite_busy_handler, 446 &tsd->cache_busy); 447 } 448 *cache = tsd->cache_db; 449 return (IDMAP_SUCCESS); 450 } 451 452 /* 453 * Initialize cache and db 454 */ 455 int 456 init_dbs() 457 { 458 char *sql[4]; 459 int created, upgraded; 460 461 /* name-based mappings; probably OK to blow away in a pinch(?) */ 462 sql[0] = DB_INSTALL_SQL; 463 sql[1] = DB_UPGRADE_FROM_v1_SQL; 464 sql[2] = NULL; 465 466 if (init_db_instance(IDMAP_DBNAME, DB_VERSION, DB_VERSION_SQL, sql, 467 FAIL_IF_CORRUPT, &created, &upgraded) < 0) 468 return (-1); 469 470 /* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */ 471 sql[0] = CACHE_INSTALL_SQL; 472 sql[1] = CACHE_UPGRADE_FROM_v1_SQL; 473 sql[2] = CACHE_UPGRADE_FROM_v2_SQL; 474 sql[3] = NULL; 475 476 if (init_db_instance(IDMAP_CACHENAME, CACHE_VERSION, CACHE_VERSION_SQL, 477 sql, REMOVE_IF_CORRUPT, &created, &upgraded) < 0) 478 return (-1); 479 480 _idmapdstate.new_eph_db = (created || upgraded) ? 1 : 0; 481 482 return (0); 483 } 484 485 /* 486 * Finalize databases 487 */ 488 void 489 fini_dbs() 490 { 491 } 492 493 /* 494 * This table is a listing of status codes that will be returned to the 495 * client when a SQL command fails with the corresponding error message. 496 */ 497 static msg_table_t sqlmsgtable[] = { 498 {IDMAP_ERR_U2W_NAMERULE_CONFLICT, 499 "columns unixname, is_user, u2w_order are not unique"}, 500 {IDMAP_ERR_W2U_NAMERULE_CONFLICT, 501 "columns winname, windomain, is_user, is_wuser, w2u_order are not" 502 " unique"}, 503 {IDMAP_ERR_W2U_NAMERULE_CONFLICT, "Conflicting w2u namerules"}, 504 {-1, NULL} 505 }; 506 507 /* 508 * idmapd's version of string2stat to map SQLite messages to 509 * status codes 510 */ 511 idmap_retcode 512 idmapd_string2stat(const char *msg) 513 { 514 int i; 515 for (i = 0; sqlmsgtable[i].msg; i++) { 516 if (strcasecmp(sqlmsgtable[i].msg, msg) == 0) 517 return (sqlmsgtable[i].retcode); 518 } 519 return (IDMAP_ERR_OTHER); 520 } 521 522 /* 523 * Executes some SQL in a transaction. 524 * 525 * Returns 0 on success, -1 if it failed but the rollback succeeded, -2 526 * if the rollback failed. 527 */ 528 static 529 int 530 sql_exec_tran_no_cb(sqlite *db, char *sql, const char *dbname, 531 const char *while_doing) 532 { 533 char *errmsg = NULL; 534 int rc; 535 536 rc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &errmsg); 537 if (rc != SQLITE_OK) { 538 idmapdlog(LOG_ERR, "Begin transaction failed (%s) " 539 "while %s (%s)", errmsg, while_doing, dbname); 540 sqlite_freemem(errmsg); 541 return (-1); 542 } 543 544 rc = sqlite_exec(db, sql, NULL, NULL, &errmsg); 545 if (rc != SQLITE_OK) { 546 idmapdlog(LOG_ERR, "Database error (%s) while %s (%s)", errmsg, 547 while_doing, dbname); 548 sqlite_freemem(errmsg); 549 errmsg = NULL; 550 goto rollback; 551 } 552 553 rc = sqlite_exec(db, "COMMIT TRANSACTION", NULL, NULL, &errmsg); 554 if (rc == SQLITE_OK) { 555 sqlite_freemem(errmsg); 556 return (0); 557 } 558 559 idmapdlog(LOG_ERR, "Database commit error (%s) while s (%s)", 560 errmsg, while_doing, dbname); 561 sqlite_freemem(errmsg); 562 errmsg = NULL; 563 564 rollback: 565 rc = sqlite_exec(db, "ROLLBACK TRANSACTION", NULL, NULL, &errmsg); 566 if (rc != SQLITE_OK) { 567 idmapdlog(LOG_ERR, "Rollback failed (%s) while %s (%s)", 568 errmsg, while_doing, dbname); 569 sqlite_freemem(errmsg); 570 return (-2); 571 } 572 sqlite_freemem(errmsg); 573 574 return (-1); 575 } 576 577 /* 578 * Execute the given SQL statment without using any callbacks 579 */ 580 idmap_retcode 581 sql_exec_no_cb(sqlite *db, const char *dbname, char *sql) 582 { 583 char *errmsg = NULL; 584 int r; 585 idmap_retcode retcode; 586 587 r = sqlite_exec(db, sql, NULL, NULL, &errmsg); 588 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 589 590 if (r != SQLITE_OK) { 591 idmapdlog(LOG_ERR, "Database error on %s while executing %s " 592 "(%s)", dbname, sql, CHECK_NULL(errmsg)); 593 retcode = idmapd_string2stat(errmsg); 594 if (errmsg != NULL) 595 sqlite_freemem(errmsg); 596 return (retcode); 597 } 598 599 return (IDMAP_SUCCESS); 600 } 601 602 /* 603 * Generate expression that can be used in WHERE statements. 604 * Examples: 605 * <prefix> <col> <op> <value> <suffix> 606 * "" "unixuser" "=" "foo" "AND" 607 */ 608 idmap_retcode 609 gen_sql_expr_from_rule(idmap_namerule *rule, char **out) 610 { 611 char *s_windomain = NULL, *s_winname = NULL; 612 char *s_unixname = NULL; 613 char *lower_winname; 614 int retcode = IDMAP_SUCCESS; 615 616 if (out == NULL) 617 return (IDMAP_ERR_ARG); 618 619 620 if (!EMPTY_STRING(rule->windomain)) { 621 s_windomain = sqlite_mprintf("AND windomain = %Q ", 622 rule->windomain); 623 if (s_windomain == NULL) { 624 retcode = IDMAP_ERR_MEMORY; 625 goto out; 626 } 627 } 628 629 if (!EMPTY_STRING(rule->winname)) { 630 if ((lower_winname = tolower_u8(rule->winname)) == NULL) 631 lower_winname = rule->winname; 632 s_winname = sqlite_mprintf( 633 "AND winname = %Q AND is_wuser = %d ", 634 lower_winname, rule->is_wuser ? 1 : 0); 635 if (lower_winname != rule->winname) 636 free(lower_winname); 637 if (s_winname == NULL) { 638 retcode = IDMAP_ERR_MEMORY; 639 goto out; 640 } 641 } 642 643 if (!EMPTY_STRING(rule->unixname)) { 644 s_unixname = sqlite_mprintf( 645 "AND unixname = %Q AND is_user = %d ", 646 rule->unixname, rule->is_user ? 1 : 0); 647 if (s_unixname == NULL) { 648 retcode = IDMAP_ERR_MEMORY; 649 goto out; 650 } 651 } 652 653 *out = sqlite_mprintf("%s %s %s", 654 s_windomain ? s_windomain : "", 655 s_winname ? s_winname : "", 656 s_unixname ? s_unixname : ""); 657 658 if (*out == NULL) { 659 retcode = IDMAP_ERR_MEMORY; 660 idmapdlog(LOG_ERR, "Out of memory"); 661 goto out; 662 } 663 664 out: 665 if (s_windomain != NULL) 666 sqlite_freemem(s_windomain); 667 if (s_winname != NULL) 668 sqlite_freemem(s_winname); 669 if (s_unixname != NULL) 670 sqlite_freemem(s_unixname); 671 672 return (retcode); 673 } 674 675 676 677 /* 678 * Generate and execute SQL statement for LIST RPC calls 679 */ 680 idmap_retcode 681 process_list_svc_sql(sqlite *db, const char *dbname, char *sql, uint64_t limit, 682 int flag, list_svc_cb cb, void *result) 683 { 684 list_cb_data_t cb_data; 685 char *errmsg = NULL; 686 int r; 687 idmap_retcode retcode = IDMAP_ERR_INTERNAL; 688 689 (void) memset(&cb_data, 0, sizeof (cb_data)); 690 cb_data.result = result; 691 cb_data.limit = limit; 692 cb_data.flag = flag; 693 694 695 r = sqlite_exec(db, sql, cb, &cb_data, &errmsg); 696 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 697 switch (r) { 698 case SQLITE_OK: 699 retcode = IDMAP_SUCCESS; 700 break; 701 702 default: 703 retcode = IDMAP_ERR_INTERNAL; 704 idmapdlog(LOG_ERR, "Database error on %s while executing " 705 "%s (%s)", dbname, sql, CHECK_NULL(errmsg)); 706 break; 707 } 708 if (errmsg != NULL) 709 sqlite_freemem(errmsg); 710 return (retcode); 711 } 712 713 /* 714 * This routine is called by callbacks that process the results of 715 * LIST RPC calls to validate data and to allocate memory for 716 * the result array. 717 */ 718 idmap_retcode 719 validate_list_cb_data(list_cb_data_t *cb_data, int argc, char **argv, 720 int ncol, uchar_t **list, size_t valsize) 721 { 722 size_t nsize; 723 void *tmplist; 724 725 if (cb_data->limit > 0 && cb_data->next == cb_data->limit) 726 return (IDMAP_NEXT); 727 728 if (argc < ncol || argv == NULL) { 729 idmapdlog(LOG_ERR, "Invalid data"); 730 return (IDMAP_ERR_INTERNAL); 731 } 732 733 /* alloc in bulk to reduce number of reallocs */ 734 if (cb_data->next >= cb_data->len) { 735 nsize = (cb_data->len + SIZE_INCR) * valsize; 736 tmplist = realloc(*list, nsize); 737 if (tmplist == NULL) { 738 idmapdlog(LOG_ERR, "Out of memory"); 739 return (IDMAP_ERR_MEMORY); 740 } 741 *list = tmplist; 742 (void) memset(*list + (cb_data->len * valsize), 0, 743 SIZE_INCR * valsize); 744 cb_data->len += SIZE_INCR; 745 } 746 return (IDMAP_SUCCESS); 747 } 748 749 static 750 idmap_retcode 751 get_namerule_order(char *winname, char *windomain, char *unixname, 752 int direction, int is_diagonal, int *w2u_order, int *u2w_order) 753 { 754 *w2u_order = 0; 755 *u2w_order = 0; 756 757 /* 758 * Windows to UNIX lookup order: 759 * 1. winname@domain (or winname) to "" 760 * 2. winname@domain (or winname) to unixname 761 * 3. winname@* to "" 762 * 4. winname@* to unixname 763 * 5. *@domain (or *) to * 764 * 6. *@domain (or *) to "" 765 * 7. *@domain (or *) to unixname 766 * 8. *@* to * 767 * 9. *@* to "" 768 * 10. *@* to unixname 769 * 770 * winname is a special case of winname@domain when domain is the 771 * default domain. Similarly * is a special case of *@domain when 772 * domain is the default domain. 773 * 774 * Note that "" has priority over specific names because "" inhibits 775 * mappings and traditionally deny rules always had higher priority. 776 */ 777 if (direction != IDMAP_DIRECTION_U2W) { 778 /* bi-directional or from windows to unix */ 779 if (winname == NULL) 780 return (IDMAP_ERR_W2U_NAMERULE); 781 else if (unixname == NULL) 782 return (IDMAP_ERR_W2U_NAMERULE); 783 else if (EMPTY_NAME(winname)) 784 return (IDMAP_ERR_W2U_NAMERULE); 785 else if (*winname == '*' && windomain && *windomain == '*') { 786 if (*unixname == '*') 787 *w2u_order = 8; 788 else if (EMPTY_NAME(unixname)) 789 *w2u_order = 9; 790 else /* unixname == name */ 791 *w2u_order = 10; 792 } else if (*winname == '*') { 793 if (*unixname == '*') 794 *w2u_order = 5; 795 else if (EMPTY_NAME(unixname)) 796 *w2u_order = 6; 797 else /* name */ 798 *w2u_order = 7; 799 } else if (windomain != NULL && *windomain == '*') { 800 /* winname == name */ 801 if (*unixname == '*') 802 return (IDMAP_ERR_W2U_NAMERULE); 803 else if (EMPTY_NAME(unixname)) 804 *w2u_order = 3; 805 else /* name */ 806 *w2u_order = 4; 807 } else { 808 /* winname == name && windomain == null or name */ 809 if (*unixname == '*') 810 return (IDMAP_ERR_W2U_NAMERULE); 811 else if (EMPTY_NAME(unixname)) 812 *w2u_order = 1; 813 else /* name */ 814 *w2u_order = 2; 815 } 816 817 } 818 819 /* 820 * 1. unixname to "", non-diagonal 821 * 2. unixname to winname@domain (or winname), non-diagonal 822 * 3. unixname to "", diagonal 823 * 4. unixname to winname@domain (or winname), diagonal 824 * 5. * to *@domain (or *), non-diagonal 825 * 5. * to *@domain (or *), diagonal 826 * 7. * to "" 827 * 8. * to winname@domain (or winname) 828 * 9. * to "", non-diagonal 829 * 10. * to winname@domain (or winname), diagonal 830 */ 831 if (direction != IDMAP_DIRECTION_W2U) { 832 int diagonal = is_diagonal ? 1 : 0; 833 834 /* bi-directional or from unix to windows */ 835 if (unixname == NULL || EMPTY_NAME(unixname)) 836 return (IDMAP_ERR_U2W_NAMERULE); 837 else if (winname == NULL) 838 return (IDMAP_ERR_U2W_NAMERULE); 839 else if (windomain != NULL && *windomain == '*') 840 return (IDMAP_ERR_U2W_NAMERULE); 841 else if (*unixname == '*') { 842 if (*winname == '*') 843 *u2w_order = 5 + diagonal; 844 else if (EMPTY_NAME(winname)) 845 *u2w_order = 7 + 2 * diagonal; 846 else 847 *u2w_order = 8 + 2 * diagonal; 848 } else { 849 if (*winname == '*') 850 return (IDMAP_ERR_U2W_NAMERULE); 851 else if (EMPTY_NAME(winname)) 852 *u2w_order = 1 + 2 * diagonal; 853 else 854 *u2w_order = 2 + 2 * diagonal; 855 } 856 } 857 return (IDMAP_SUCCESS); 858 } 859 860 /* 861 * Generate and execute SQL statement to add name-based mapping rule 862 */ 863 idmap_retcode 864 add_namerule(sqlite *db, idmap_namerule *rule) 865 { 866 char *sql = NULL; 867 idmap_stat retcode; 868 char *dom = NULL; 869 int w2u_order, u2w_order; 870 char w2ubuf[11], u2wbuf[11]; 871 872 retcode = get_namerule_order(rule->winname, rule->windomain, 873 rule->unixname, rule->direction, 874 rule->is_user == rule->is_wuser ? 0 : 1, &w2u_order, &u2w_order); 875 if (retcode != IDMAP_SUCCESS) 876 goto out; 877 878 if (w2u_order) 879 (void) snprintf(w2ubuf, sizeof (w2ubuf), "%d", w2u_order); 880 if (u2w_order) 881 (void) snprintf(u2wbuf, sizeof (u2wbuf), "%d", u2w_order); 882 883 /* 884 * For the triggers on namerules table to work correctly: 885 * 1) Use NULL instead of 0 for w2u_order and u2w_order 886 * 2) Use "" instead of NULL for "no domain" 887 */ 888 889 if (!EMPTY_STRING(rule->windomain)) 890 dom = rule->windomain; 891 else if (lookup_wksids_name2sid(rule->winname, NULL, NULL, NULL, NULL) 892 == IDMAP_SUCCESS) { 893 /* well-known SIDs don't need domain */ 894 dom = ""; 895 } 896 897 RDLOCK_CONFIG(); 898 if (dom == NULL) { 899 if (_idmapdstate.cfg->pgcfg.default_domain) 900 dom = _idmapdstate.cfg->pgcfg.default_domain; 901 else 902 dom = ""; 903 } 904 sql = sqlite_mprintf("INSERT into namerules " 905 "(is_user, is_wuser, windomain, winname_display, is_nt4, " 906 "unixname, w2u_order, u2w_order) " 907 "VALUES(%d, %d, %Q, %Q, %d, %Q, %q, %q);", 908 rule->is_user ? 1 : 0, rule->is_wuser ? 1 : 0, dom, 909 rule->winname, rule->is_nt4 ? 1 : 0, rule->unixname, 910 w2u_order ? w2ubuf : NULL, u2w_order ? u2wbuf : NULL); 911 UNLOCK_CONFIG(); 912 913 if (sql == NULL) { 914 retcode = IDMAP_ERR_INTERNAL; 915 idmapdlog(LOG_ERR, "Out of memory"); 916 goto out; 917 } 918 919 retcode = sql_exec_no_cb(db, IDMAP_DBNAME, sql); 920 921 if (retcode == IDMAP_ERR_OTHER) 922 retcode = IDMAP_ERR_CFG; 923 924 out: 925 if (sql != NULL) 926 sqlite_freemem(sql); 927 return (retcode); 928 } 929 930 /* 931 * Flush name-based mapping rules 932 */ 933 idmap_retcode 934 flush_namerules(sqlite *db) 935 { 936 idmap_stat retcode; 937 938 retcode = sql_exec_no_cb(db, IDMAP_DBNAME, "DELETE FROM namerules;"); 939 940 return (retcode); 941 } 942 943 /* 944 * Generate and execute SQL statement to remove a name-based mapping rule 945 */ 946 idmap_retcode 947 rm_namerule(sqlite *db, idmap_namerule *rule) 948 { 949 char *sql = NULL; 950 idmap_stat retcode; 951 char buf[80]; 952 char *expr = NULL; 953 954 if (rule->direction < 0 && EMPTY_STRING(rule->windomain) && 955 EMPTY_STRING(rule->winname) && EMPTY_STRING(rule->unixname)) 956 return (IDMAP_SUCCESS); 957 958 buf[0] = 0; 959 960 if (rule->direction == IDMAP_DIRECTION_BI) 961 (void) snprintf(buf, sizeof (buf), "AND w2u_order > 0" 962 " AND u2w_order > 0"); 963 else if (rule->direction == IDMAP_DIRECTION_W2U) 964 (void) snprintf(buf, sizeof (buf), "AND w2u_order > 0" 965 " AND (u2w_order = 0 OR u2w_order ISNULL)"); 966 else if (rule->direction == IDMAP_DIRECTION_U2W) 967 (void) snprintf(buf, sizeof (buf), "AND u2w_order > 0" 968 " AND (w2u_order = 0 OR w2u_order ISNULL)"); 969 970 retcode = gen_sql_expr_from_rule(rule, &expr); 971 if (retcode != IDMAP_SUCCESS) 972 goto out; 973 974 sql = sqlite_mprintf("DELETE FROM namerules WHERE 1 %s %s;", expr, 975 buf); 976 977 if (sql == NULL) { 978 retcode = IDMAP_ERR_INTERNAL; 979 idmapdlog(LOG_ERR, "Out of memory"); 980 goto out; 981 } 982 983 984 retcode = sql_exec_no_cb(db, IDMAP_DBNAME, sql); 985 986 out: 987 if (expr != NULL) 988 sqlite_freemem(expr); 989 if (sql != NULL) 990 sqlite_freemem(sql); 991 return (retcode); 992 } 993 994 /* 995 * Compile the given SQL query and step just once. 996 * 997 * Input: 998 * db - db handle 999 * sql - SQL statement 1000 * 1001 * Output: 1002 * vm - virtual SQL machine 1003 * ncol - number of columns in the result 1004 * values - column values 1005 * 1006 * Return values: 1007 * IDMAP_SUCCESS 1008 * IDMAP_ERR_NOTFOUND 1009 * IDMAP_ERR_INTERNAL 1010 */ 1011 1012 static 1013 idmap_retcode 1014 sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol, 1015 int reqcol, const char ***values) 1016 { 1017 char *errmsg = NULL; 1018 int r; 1019 1020 if ((r = sqlite_compile(db, sql, NULL, vm, &errmsg)) != SQLITE_OK) { 1021 idmapdlog(LOG_ERR, "Database error during %s (%s)", sql, 1022 CHECK_NULL(errmsg)); 1023 sqlite_freemem(errmsg); 1024 return (IDMAP_ERR_INTERNAL); 1025 } 1026 1027 r = sqlite_step(*vm, ncol, values, NULL); 1028 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 1029 1030 if (r == SQLITE_ROW) { 1031 if (ncol != NULL && *ncol < reqcol) { 1032 (void) sqlite_finalize(*vm, NULL); 1033 *vm = NULL; 1034 return (IDMAP_ERR_INTERNAL); 1035 } 1036 /* Caller will call finalize after using the results */ 1037 return (IDMAP_SUCCESS); 1038 } else if (r == SQLITE_DONE) { 1039 (void) sqlite_finalize(*vm, NULL); 1040 *vm = NULL; 1041 return (IDMAP_ERR_NOTFOUND); 1042 } 1043 1044 (void) sqlite_finalize(*vm, &errmsg); 1045 *vm = NULL; 1046 idmapdlog(LOG_ERR, "Database error during %s (%s)", sql, 1047 CHECK_NULL(errmsg)); 1048 sqlite_freemem(errmsg); 1049 return (IDMAP_ERR_INTERNAL); 1050 } 1051 1052 /* 1053 * Load config in the state. 1054 * 1055 * nm_siduid and nm_sidgid fields: 1056 * state->nm_siduid represents mode used by sid2uid and uid2sid 1057 * requests for directory-based name mappings. Similarly, 1058 * state->nm_sidgid represents mode used by sid2gid and gid2sid 1059 * requests. 1060 * 1061 * sid2uid/uid2sid: 1062 * none -> ds_name_mapping_enabled != true 1063 * AD-mode -> !nldap_winname_attr && ad_unixuser_attr 1064 * nldap-mode -> nldap_winname_attr && !ad_unixuser_attr 1065 * mixed-mode -> nldap_winname_attr && ad_unixuser_attr 1066 * 1067 * sid2gid/gid2sid: 1068 * none -> ds_name_mapping_enabled != true 1069 * AD-mode -> !nldap_winname_attr && ad_unixgroup_attr 1070 * nldap-mode -> nldap_winname_attr && !ad_unixgroup_attr 1071 * mixed-mode -> nldap_winname_attr && ad_unixgroup_attr 1072 */ 1073 idmap_retcode 1074 load_cfg_in_state(lookup_state_t *state) 1075 { 1076 state->nm_siduid = IDMAP_NM_NONE; 1077 state->nm_sidgid = IDMAP_NM_NONE; 1078 RDLOCK_CONFIG(); 1079 1080 if (_idmapdstate.cfg->pgcfg.default_domain != NULL) { 1081 state->defdom = 1082 strdup(_idmapdstate.cfg->pgcfg.default_domain); 1083 if (state->defdom == NULL) { 1084 UNLOCK_CONFIG(); 1085 return (IDMAP_ERR_MEMORY); 1086 } 1087 } else { 1088 UNLOCK_CONFIG(); 1089 return (IDMAP_SUCCESS); 1090 } 1091 if (_idmapdstate.cfg->pgcfg.ds_name_mapping_enabled == FALSE) { 1092 UNLOCK_CONFIG(); 1093 return (IDMAP_SUCCESS); 1094 } 1095 if (_idmapdstate.cfg->pgcfg.nldap_winname_attr != NULL) { 1096 state->nm_siduid = 1097 (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL) 1098 ? IDMAP_NM_MIXED : IDMAP_NM_NLDAP; 1099 state->nm_sidgid = 1100 (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL) 1101 ? IDMAP_NM_MIXED : IDMAP_NM_NLDAP; 1102 } else { 1103 state->nm_siduid = 1104 (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL) 1105 ? IDMAP_NM_AD : IDMAP_NM_NONE; 1106 state->nm_sidgid = 1107 (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL) 1108 ? IDMAP_NM_AD : IDMAP_NM_NONE; 1109 } 1110 if (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL) { 1111 state->ad_unixuser_attr = 1112 strdup(_idmapdstate.cfg->pgcfg.ad_unixuser_attr); 1113 if (state->ad_unixuser_attr == NULL) { 1114 UNLOCK_CONFIG(); 1115 return (IDMAP_ERR_MEMORY); 1116 } 1117 } 1118 if (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL) { 1119 state->ad_unixgroup_attr = 1120 strdup(_idmapdstate.cfg->pgcfg.ad_unixgroup_attr); 1121 if (state->ad_unixgroup_attr == NULL) { 1122 UNLOCK_CONFIG(); 1123 return (IDMAP_ERR_MEMORY); 1124 } 1125 } 1126 if (_idmapdstate.cfg->pgcfg.nldap_winname_attr != NULL) { 1127 state->nldap_winname_attr = 1128 strdup(_idmapdstate.cfg->pgcfg.nldap_winname_attr); 1129 if (state->nldap_winname_attr == NULL) { 1130 UNLOCK_CONFIG(); 1131 return (IDMAP_ERR_MEMORY); 1132 } 1133 } 1134 UNLOCK_CONFIG(); 1135 return (IDMAP_SUCCESS); 1136 } 1137 1138 /* 1139 * Set the rule with sepecified values. 1140 * All the strings are copied. 1141 */ 1142 static void 1143 idmap_namerule_set(idmap_namerule *rule, const char *windomain, 1144 const char *winname, const char *unixname, boolean_t is_user, 1145 boolean_t is_wuser, boolean_t is_nt4, int direction) 1146 { 1147 /* 1148 * Only update if they differ because we have to free 1149 * and duplicate the strings 1150 */ 1151 if (rule->windomain == NULL || windomain == NULL || 1152 strcmp(rule->windomain, windomain) != 0) { 1153 if (rule->windomain != NULL) { 1154 free(rule->windomain); 1155 rule->windomain = NULL; 1156 } 1157 if (windomain != NULL) 1158 rule->windomain = strdup(windomain); 1159 } 1160 1161 if (rule->winname == NULL || winname == NULL || 1162 strcmp(rule->winname, winname) != 0) { 1163 if (rule->winname != NULL) { 1164 free(rule->winname); 1165 rule->winname = NULL; 1166 } 1167 if (winname != NULL) 1168 rule->winname = strdup(winname); 1169 } 1170 1171 if (rule->unixname == NULL || unixname == NULL || 1172 strcmp(rule->unixname, unixname) != 0) { 1173 if (rule->unixname != NULL) { 1174 free(rule->unixname); 1175 rule->unixname = NULL; 1176 } 1177 if (unixname != NULL) 1178 rule->unixname = strdup(unixname); 1179 } 1180 1181 rule->is_user = is_user; 1182 rule->is_wuser = is_wuser; 1183 rule->is_nt4 = is_nt4; 1184 rule->direction = direction; 1185 } 1186 1187 1188 /* 1189 * Table for well-known SIDs. 1190 * 1191 * Background: 1192 * 1193 * Some of the well-known principals are stored under: 1194 * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain> 1195 * They belong to objectClass "foreignSecurityPrincipal". They don't have 1196 * "samAccountName" nor "userPrincipalName" attributes. Their names are 1197 * available in "cn" and "name" attributes. Some of these principals have a 1198 * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and 1199 * these duplicate entries have the stringified SID in the "name" and "cn" 1200 * attributes instead of the actual name. 1201 * 1202 * Those of the form S-1-5-32-X are Builtin groups and are stored in the 1203 * cn=builtin container (except, Power Users which is not stored in AD) 1204 * 1205 * These principals are and will remain constant. Therefore doing AD lookups 1206 * provides no benefit. Also, using hard-coded table (and thus avoiding AD 1207 * lookup) improves performance and avoids additional complexity in the 1208 * adutils.c code. Moreover these SIDs can be used when no Active Directory 1209 * is available (such as the CIFS server's "workgroup" mode). 1210 * 1211 * Notes: 1212 * 1. Currently we don't support localization of well-known SID names, 1213 * unlike Windows. 1214 * 1215 * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored 1216 * here. AD does have normal user/group objects for these objects and 1217 * can be looked up using the existing AD lookup code. 1218 * 1219 * 3. See comments above lookup_wksids_sid2pid() for more information 1220 * on how we lookup the wksids table. 1221 */ 1222 static wksids_table_t wksids[] = { 1223 {"S-1-0", 0, "Nobody", 0, SENTINEL_PID, -1, 1}, 1224 {"S-1-1", 0, "Everyone", 0, SENTINEL_PID, -1, -1}, 1225 {"S-1-3", 0, "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 1, 0}, 1226 {"S-1-3", 1, "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0, 0}, 1227 {"S-1-3", 2, "Creator Owner Server", 1, SENTINEL_PID, -1, -1}, 1228 {"S-1-3", 3, "Creator Group Server", 0, SENTINEL_PID, -1, 1}, 1229 {"S-1-3", 4, "Owner Rights", 0, SENTINEL_PID, -1, -1}, 1230 {"S-1-5", 1, "Dialup", 0, SENTINEL_PID, -1, -1}, 1231 {"S-1-5", 2, "Network", 0, SENTINEL_PID, -1, -1}, 1232 {"S-1-5", 3, "Batch", 0, SENTINEL_PID, -1, -1}, 1233 {"S-1-5", 4, "Interactive", 0, SENTINEL_PID, -1, -1}, 1234 {"S-1-5", 6, "Service", 0, SENTINEL_PID, -1, -1}, 1235 {"S-1-5", 7, "Anonymous Logon", 0, GID_NOBODY, 0, 0}, 1236 {"S-1-5", 7, "Anonymous Logon", 0, UID_NOBODY, 1, 0}, 1237 {"S-1-5", 8, "Proxy", 0, SENTINEL_PID, -1, -1}, 1238 {"S-1-5", 9, "Enterprise Domain Controllers", 0, SENTINEL_PID, -1, -1}, 1239 {"S-1-5", 10, "Self", 0, SENTINEL_PID, -1, -1}, 1240 {"S-1-5", 11, "Authenticated Users", 0, SENTINEL_PID, -1, -1}, 1241 {"S-1-5", 12, "Restricted Code", 0, SENTINEL_PID, -1, -1}, 1242 {"S-1-5", 13, "Terminal Server User", 0, SENTINEL_PID, -1, -1}, 1243 {"S-1-5", 14, "Remote Interactive Logon", 0, SENTINEL_PID, -1, -1}, 1244 {"S-1-5", 15, "This Organization", 0, SENTINEL_PID, -1, -1}, 1245 {"S-1-5", 17, "IUSR", 0, SENTINEL_PID, -1, -1}, 1246 {"S-1-5", 18, "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0, 0}, 1247 {"S-1-5", 19, "Local Service", 0, SENTINEL_PID, -1, -1}, 1248 {"S-1-5", 20, "Network Service", 0, SENTINEL_PID, -1, -1}, 1249 {"S-1-5", 1000, "Other Organization", 0, SENTINEL_PID, -1, -1}, 1250 {"S-1-5-32", 544, "Administrators", 0, SENTINEL_PID, -1, -1}, 1251 {"S-1-5-32", 545, "Users", 0, SENTINEL_PID, -1, -1}, 1252 {"S-1-5-32", 546, "Guests", 0, SENTINEL_PID, -1, -1}, 1253 {"S-1-5-32", 547, "Power Users", 0, SENTINEL_PID, -1, -1}, 1254 {"S-1-5-32", 548, "Account Operators", 0, SENTINEL_PID, -1, -1}, 1255 {"S-1-5-32", 549, "Server Operators", 0, SENTINEL_PID, -1, -1}, 1256 {"S-1-5-32", 550, "Print Operators", 0, SENTINEL_PID, -1, -1}, 1257 {"S-1-5-32", 551, "Backup Operators", 0, SENTINEL_PID, -1, -1}, 1258 {"S-1-5-32", 552, "Replicator", 0, SENTINEL_PID, -1, -1}, 1259 {"S-1-5-32", 554, "Pre-Windows 2000 Compatible Access", 0, 1260 SENTINEL_PID, -1, -1}, 1261 {"S-1-5-32", 555, "Remote Desktop Users", 0, SENTINEL_PID, -1, -1}, 1262 {"S-1-5-32", 556, "Network Configuration Operators", 0, 1263 SENTINEL_PID, -1, -1}, 1264 {"S-1-5-32", 557, "Incoming Forest Trust Builders", 0, 1265 SENTINEL_PID, -1, -1}, 1266 {"S-1-5-32", 558, "Performance Monitor Users", 0, SENTINEL_PID, -1, -1}, 1267 {"S-1-5-32", 559, "Performance Log Users", 0, SENTINEL_PID, -1, -1}, 1268 {"S-1-5-32", 560, "Windows Authorization Access Group", 0, 1269 SENTINEL_PID, -1, -1}, 1270 {"S-1-5-32", 561, "Terminal Server License Servers", 0, 1271 SENTINEL_PID, -1, -1}, 1272 {"S-1-5-32", 561, "Distributed COM Users", 0, SENTINEL_PID, -1, -1}, 1273 {"S-1-5-32", 568, "IIS_IUSRS", 0, SENTINEL_PID, -1, -1}, 1274 {"S-1-5-32", 569, "Cryptographic Operators", 0, SENTINEL_PID, -1, -1}, 1275 {"S-1-5-32", 573, "Event Log Readers", 0, SENTINEL_PID, -1, -1}, 1276 {"S-1-5-32", 574, "Certificate Service DCOM Access", 0, 1277 SENTINEL_PID, -1, -1}, 1278 {"S-1-5-64", 21, "Digest Authentication", 0, SENTINEL_PID, -1, -1}, 1279 {"S-1-5-64", 10, "NTLM Authentication", 0, SENTINEL_PID, -1, -1}, 1280 {"S-1-5-64", 14, "SChannel Authentication", 0, SENTINEL_PID, -1, -1}, 1281 {NULL, UINT32_MAX, NULL, -1, SENTINEL_PID, -1, -1} 1282 }; 1283 1284 /* 1285 * Lookup well-known SIDs table either by winname or by SID. 1286 * If the given winname or SID is a well-known SID then we set wksid 1287 * variable and then proceed to see if the SID has a hard mapping to 1288 * a particular UID/GID (Ex: Creator Owner/Creator Group mapped to 1289 * fixed ephemeral ids). If we find such mapping then we return 1290 * success otherwise notfound. If a well-known SID is mapped to 1291 * SENTINEL_PID and the direction field is set (bi-directional or 1292 * win2unix) then we treat it as inhibited mapping and return no 1293 * mapping (Ex. S-1-0-0). 1294 */ 1295 static 1296 idmap_retcode 1297 lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res, int *wksid) 1298 { 1299 int i; 1300 1301 *wksid = 0; 1302 1303 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1304 if (req->id1.idmap_id_u.sid.prefix != NULL) { 1305 if ((strcasecmp(wksids[i].sidprefix, 1306 req->id1.idmap_id_u.sid.prefix) != 0) || 1307 wksids[i].rid != req->id1.idmap_id_u.sid.rid) 1308 /* this is not our SID */ 1309 continue; 1310 if (req->id1name == NULL) { 1311 req->id1name = strdup(wksids[i].winname); 1312 if (req->id1name == NULL) 1313 return (IDMAP_ERR_MEMORY); 1314 } 1315 } else if (req->id1name != NULL) { 1316 if (strcasecmp(wksids[i].winname, req->id1name) != 0) 1317 /* this is not our winname */ 1318 continue; 1319 req->id1.idmap_id_u.sid.prefix = 1320 strdup(wksids[i].sidprefix); 1321 if (req->id1.idmap_id_u.sid.prefix == NULL) 1322 return (IDMAP_ERR_MEMORY); 1323 req->id1.idmap_id_u.sid.rid = wksids[i].rid; 1324 } 1325 1326 *wksid = 1; 1327 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; 1328 1329 req->id1.idtype = (wksids[i].is_wuser) ? 1330 IDMAP_USID : IDMAP_GSID; 1331 1332 if (wksids[i].pid == SENTINEL_PID) { 1333 if (wksids[i].direction == IDMAP_DIRECTION_BI || 1334 wksids[i].direction == IDMAP_DIRECTION_W2U) 1335 /* Inhibited */ 1336 return (IDMAP_ERR_NOMAPPING); 1337 /* Not mapped */ 1338 if (res->id.idtype == IDMAP_POSIXID) { 1339 res->id.idtype = 1340 (wksids[i].is_wuser) ? 1341 IDMAP_UID : IDMAP_GID; 1342 } 1343 return (IDMAP_ERR_NOTFOUND); 1344 } else if (wksids[i].direction == IDMAP_DIRECTION_U2W) 1345 continue; 1346 1347 switch (res->id.idtype) { 1348 case IDMAP_UID: 1349 if (wksids[i].is_user == 0) 1350 continue; 1351 res->id.idmap_id_u.uid = wksids[i].pid; 1352 res->direction = wksids[i].direction; 1353 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 1354 res->info.how.map_type = 1355 IDMAP_MAP_TYPE_KNOWN_SID; 1356 res->info.src = IDMAP_MAP_SRC_HARD_CODED; 1357 } 1358 return (IDMAP_SUCCESS); 1359 case IDMAP_GID: 1360 if (wksids[i].is_user == 1) 1361 continue; 1362 res->id.idmap_id_u.gid = wksids[i].pid; 1363 res->direction = wksids[i].direction; 1364 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 1365 res->info.how.map_type = 1366 IDMAP_MAP_TYPE_KNOWN_SID; 1367 res->info.src = IDMAP_MAP_SRC_HARD_CODED; 1368 } 1369 return (IDMAP_SUCCESS); 1370 case IDMAP_POSIXID: 1371 res->id.idmap_id_u.uid = wksids[i].pid; 1372 res->id.idtype = (!wksids[i].is_user) ? 1373 IDMAP_GID : IDMAP_UID; 1374 res->direction = wksids[i].direction; 1375 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 1376 res->info.how.map_type = 1377 IDMAP_MAP_TYPE_KNOWN_SID; 1378 res->info.src = IDMAP_MAP_SRC_HARD_CODED; 1379 } 1380 return (IDMAP_SUCCESS); 1381 default: 1382 return (IDMAP_ERR_NOTSUPPORTED); 1383 } 1384 } 1385 return (IDMAP_ERR_NOTFOUND); 1386 } 1387 1388 1389 static 1390 idmap_retcode 1391 lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user) 1392 { 1393 int i; 1394 if (req->id1.idmap_id_u.uid == SENTINEL_PID) 1395 return (IDMAP_ERR_NOTFOUND); 1396 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1397 if (wksids[i].pid == req->id1.idmap_id_u.uid && 1398 wksids[i].is_user == is_user && 1399 wksids[i].direction != IDMAP_DIRECTION_W2U) { 1400 if (res->id.idtype == IDMAP_SID) { 1401 res->id.idtype = (wksids[i].is_wuser) ? 1402 IDMAP_USID : IDMAP_GSID; 1403 } 1404 res->id.idmap_id_u.sid.rid = wksids[i].rid; 1405 res->id.idmap_id_u.sid.prefix = 1406 strdup(wksids[i].sidprefix); 1407 if (res->id.idmap_id_u.sid.prefix == NULL) { 1408 idmapdlog(LOG_ERR, "Out of memory"); 1409 return (IDMAP_ERR_MEMORY); 1410 } 1411 res->direction = wksids[i].direction; 1412 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 1413 res->info.how.map_type = 1414 IDMAP_MAP_TYPE_KNOWN_SID; 1415 res->info.src = IDMAP_MAP_SRC_HARD_CODED; 1416 } 1417 return (IDMAP_SUCCESS); 1418 } 1419 } 1420 return (IDMAP_ERR_NOTFOUND); 1421 } 1422 1423 idmap_retcode 1424 lookup_wksids_name2sid(const char *name, char **canonname, char **sidprefix, 1425 idmap_rid_t *rid, int *type) 1426 { 1427 int i; 1428 1429 if ((strncasecmp(name, "BUILTIN\\", 8) == 0) || 1430 (strncasecmp(name, "BUILTIN/", 8) == 0)) 1431 name += 8; 1432 1433 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1434 if (strcasecmp(wksids[i].winname, name) != 0) 1435 continue; 1436 if (sidprefix != NULL && 1437 (*sidprefix = strdup(wksids[i].sidprefix)) == NULL) { 1438 idmapdlog(LOG_ERR, "Out of memory"); 1439 return (IDMAP_ERR_MEMORY); 1440 } 1441 if (canonname != NULL && 1442 (*canonname = strdup(wksids[i].winname)) == NULL) { 1443 idmapdlog(LOG_ERR, "Out of memory"); 1444 if (sidprefix != NULL) { 1445 free(*sidprefix); 1446 *sidprefix = NULL; 1447 } 1448 return (IDMAP_ERR_MEMORY); 1449 } 1450 if (type != NULL) 1451 *type = (wksids[i].is_wuser) ? 1452 _IDMAP_T_USER : _IDMAP_T_GROUP; 1453 if (rid != NULL) 1454 *rid = wksids[i].rid; 1455 return (IDMAP_SUCCESS); 1456 } 1457 return (IDMAP_ERR_NOTFOUND); 1458 } 1459 1460 static 1461 idmap_retcode 1462 lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res) 1463 { 1464 char *end; 1465 char *sql = NULL; 1466 const char **values; 1467 sqlite_vm *vm = NULL; 1468 int ncol, is_user; 1469 uid_t pid; 1470 time_t curtime, exp; 1471 idmap_retcode retcode; 1472 char *is_user_string, *lower_name; 1473 1474 /* Current time */ 1475 errno = 0; 1476 if ((curtime = time(NULL)) == (time_t)-1) { 1477 idmapdlog(LOG_ERR, "Failed to get current time (%s)", 1478 strerror(errno)); 1479 retcode = IDMAP_ERR_INTERNAL; 1480 goto out; 1481 } 1482 1483 switch (res->id.idtype) { 1484 case IDMAP_UID: 1485 is_user_string = "1"; 1486 break; 1487 case IDMAP_GID: 1488 is_user_string = "0"; 1489 break; 1490 case IDMAP_POSIXID: 1491 /* the non-diagonal mapping */ 1492 is_user_string = "is_wuser"; 1493 break; 1494 default: 1495 retcode = IDMAP_ERR_NOTSUPPORTED; 1496 goto out; 1497 } 1498 1499 /* SQL to lookup the cache */ 1500 1501 if (req->id1.idmap_id_u.sid.prefix != NULL) { 1502 sql = sqlite_mprintf("SELECT pid, is_user, expiration, " 1503 "unixname, u2w, is_wuser, " 1504 "map_type, map_dn, map_attr, map_value, " 1505 "map_windomain, map_winname, map_unixname, map_is_nt4 " 1506 "FROM idmap_cache WHERE is_user = %s AND " 1507 "sidprefix = %Q AND rid = %u AND w2u = 1 AND " 1508 "(pid >= 2147483648 OR " 1509 "(expiration = 0 OR expiration ISNULL OR " 1510 "expiration > %d));", 1511 is_user_string, req->id1.idmap_id_u.sid.prefix, 1512 req->id1.idmap_id_u.sid.rid, curtime); 1513 } else if (req->id1name != NULL) { 1514 if ((lower_name = tolower_u8(req->id1name)) == NULL) 1515 lower_name = req->id1name; 1516 sql = sqlite_mprintf("SELECT pid, is_user, expiration, " 1517 "unixname, u2w, is_wuser, " 1518 "map_type, map_dn, map_attr, map_value, " 1519 "map_windomain, map_winname, map_unixname, map_is_nt4 " 1520 "FROM idmap_cache WHERE is_user = %s AND " 1521 "winname = %Q AND windomain = %Q AND w2u = 1 AND " 1522 "(pid >= 2147483648 OR " 1523 "(expiration = 0 OR expiration ISNULL OR " 1524 "expiration > %d));", 1525 is_user_string, lower_name, req->id1domain, 1526 curtime); 1527 if (lower_name != req->id1name) 1528 free(lower_name); 1529 } else { 1530 retcode = IDMAP_ERR_ARG; 1531 goto out; 1532 } 1533 if (sql == NULL) { 1534 idmapdlog(LOG_ERR, "Out of memory"); 1535 retcode = IDMAP_ERR_MEMORY; 1536 goto out; 1537 } 1538 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 1539 14, &values); 1540 sqlite_freemem(sql); 1541 1542 if (retcode == IDMAP_ERR_NOTFOUND) { 1543 goto out; 1544 } else if (retcode == IDMAP_SUCCESS) { 1545 /* sanity checks */ 1546 if (values[0] == NULL || values[1] == NULL) { 1547 retcode = IDMAP_ERR_CACHE; 1548 goto out; 1549 } 1550 1551 pid = strtoul(values[0], &end, 10); 1552 is_user = strncmp(values[1], "0", 2) ? 1 : 0; 1553 1554 if (is_user) { 1555 res->id.idtype = IDMAP_UID; 1556 res->id.idmap_id_u.uid = pid; 1557 } else { 1558 res->id.idtype = IDMAP_GID; 1559 res->id.idmap_id_u.gid = pid; 1560 } 1561 1562 /* 1563 * We may have an expired ephemeral mapping. Consider 1564 * the expired entry as valid if we are not going to 1565 * perform name-based mapping. But do not renew the 1566 * expiration. 1567 * If we will be doing name-based mapping then store the 1568 * ephemeral pid in the result so that we can use it 1569 * if we end up doing dynamic mapping again. 1570 */ 1571 if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) && 1572 !AVOID_NAMESERVICE(req) && 1573 IS_EPHEMERAL(pid) && values[2] != NULL) { 1574 exp = strtoll(values[2], &end, 10); 1575 if (exp && exp <= curtime) { 1576 /* Store the ephemeral pid */ 1577 res->direction = IDMAP_DIRECTION_BI; 1578 req->direction |= is_user 1579 ? _IDMAP_F_EXP_EPH_UID 1580 : _IDMAP_F_EXP_EPH_GID; 1581 retcode = IDMAP_ERR_NOTFOUND; 1582 } 1583 } 1584 } 1585 1586 out: 1587 if (retcode == IDMAP_SUCCESS) { 1588 if (values[4] != NULL) 1589 res->direction = 1590 (strtol(values[4], &end, 10) == 0)? 1591 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; 1592 else 1593 res->direction = IDMAP_DIRECTION_W2U; 1594 1595 if (values[3] != NULL) { 1596 if (req->id2name != NULL) 1597 free(req->id2name); 1598 req->id2name = strdup(values[3]); 1599 if (req->id2name == NULL) { 1600 idmapdlog(LOG_ERR, "Out of memory"); 1601 retcode = IDMAP_ERR_MEMORY; 1602 } 1603 } 1604 1605 req->id1.idtype = strncmp(values[5], "0", 2) ? 1606 IDMAP_USID : IDMAP_GSID; 1607 1608 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 1609 res->info.src = IDMAP_MAP_SRC_CACHE; 1610 res->info.how.map_type = strtoul(values[6], &end, 10); 1611 switch (res->info.how.map_type) { 1612 case IDMAP_MAP_TYPE_DS_AD: 1613 res->info.how.idmap_how_u.ad.dn = 1614 strdup(values[7]); 1615 res->info.how.idmap_how_u.ad.attr = 1616 strdup(values[8]); 1617 res->info.how.idmap_how_u.ad.value = 1618 strdup(values[9]); 1619 break; 1620 1621 case IDMAP_MAP_TYPE_DS_NLDAP: 1622 res->info.how.idmap_how_u.nldap.dn = 1623 strdup(values[7]); 1624 res->info.how.idmap_how_u.nldap.attr = 1625 strdup(values[8]); 1626 res->info.how.idmap_how_u.nldap.value = 1627 strdup(values[9]); 1628 break; 1629 1630 case IDMAP_MAP_TYPE_RULE_BASED: 1631 res->info.how.idmap_how_u.rule.windomain = 1632 strdup(values[10]); 1633 res->info.how.idmap_how_u.rule.winname = 1634 strdup(values[11]); 1635 res->info.how.idmap_how_u.rule.unixname = 1636 strdup(values[12]); 1637 res->info.how.idmap_how_u.rule.is_nt4 = 1638 strtoul(values[13], &end, 1); 1639 res->info.how.idmap_how_u.rule.is_user = 1640 is_user; 1641 res->info.how.idmap_how_u.rule.is_wuser = 1642 strtoul(values[5], &end, 1); 1643 break; 1644 1645 case IDMAP_MAP_TYPE_EPHEMERAL: 1646 break; 1647 1648 case IDMAP_MAP_TYPE_LOCAL_SID: 1649 break; 1650 1651 case IDMAP_MAP_TYPE_KNOWN_SID: 1652 break; 1653 1654 default: 1655 /* Unknow mapping type */ 1656 assert(FALSE); 1657 } 1658 } 1659 } 1660 if (vm != NULL) 1661 (void) sqlite_finalize(vm, NULL); 1662 return (retcode); 1663 } 1664 1665 static 1666 idmap_retcode 1667 lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid, 1668 char **name, char **domain, int *type) 1669 { 1670 char *end; 1671 char *sql = NULL; 1672 const char **values; 1673 sqlite_vm *vm = NULL; 1674 int ncol; 1675 time_t curtime; 1676 idmap_retcode retcode = IDMAP_SUCCESS; 1677 1678 /* Get current time */ 1679 errno = 0; 1680 if ((curtime = time(NULL)) == (time_t)-1) { 1681 idmapdlog(LOG_ERR, "Failed to get current time (%s)", 1682 strerror(errno)); 1683 retcode = IDMAP_ERR_INTERNAL; 1684 goto out; 1685 } 1686 1687 /* SQL to lookup the cache */ 1688 sql = sqlite_mprintf("SELECT canon_name, domain, type " 1689 "FROM name_cache WHERE " 1690 "sidprefix = %Q AND rid = %u AND " 1691 "(expiration = 0 OR expiration ISNULL OR " 1692 "expiration > %d);", 1693 sidprefix, rid, curtime); 1694 if (sql == NULL) { 1695 idmapdlog(LOG_ERR, "Out of memory"); 1696 retcode = IDMAP_ERR_MEMORY; 1697 goto out; 1698 } 1699 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values); 1700 sqlite_freemem(sql); 1701 1702 if (retcode == IDMAP_SUCCESS) { 1703 if (type != NULL) { 1704 if (values[2] == NULL) { 1705 retcode = IDMAP_ERR_CACHE; 1706 goto out; 1707 } 1708 *type = strtol(values[2], &end, 10); 1709 } 1710 1711 if (name != NULL && values[0] != NULL) { 1712 if ((*name = strdup(values[0])) == NULL) { 1713 idmapdlog(LOG_ERR, "Out of memory"); 1714 retcode = IDMAP_ERR_MEMORY; 1715 goto out; 1716 } 1717 } 1718 1719 if (domain != NULL && values[1] != NULL) { 1720 if ((*domain = strdup(values[1])) == NULL) { 1721 if (name != NULL && *name) { 1722 free(*name); 1723 *name = NULL; 1724 } 1725 idmapdlog(LOG_ERR, "Out of memory"); 1726 retcode = IDMAP_ERR_MEMORY; 1727 goto out; 1728 } 1729 } 1730 } 1731 1732 out: 1733 if (vm != NULL) 1734 (void) sqlite_finalize(vm, NULL); 1735 return (retcode); 1736 } 1737 1738 /* 1739 * Given SID, find winname using name_cache OR 1740 * Given winname, find SID using name_cache. 1741 * Used when mapping win to unix i.e. req->id1 is windows id and 1742 * req->id2 is unix id 1743 */ 1744 static 1745 idmap_retcode 1746 lookup_name_cache(sqlite *cache, idmap_mapping *req, idmap_id_res *res) 1747 { 1748 int type = -1; 1749 idmap_retcode retcode; 1750 char *sidprefix = NULL; 1751 idmap_rid_t rid; 1752 char *name = NULL, *domain = NULL; 1753 1754 /* Done if we've both sid and winname */ 1755 if (req->id1.idmap_id_u.sid.prefix != NULL && req->id1name != NULL) 1756 return (IDMAP_SUCCESS); 1757 1758 /* Lookup sid to winname */ 1759 if (req->id1.idmap_id_u.sid.prefix != NULL) { 1760 retcode = lookup_cache_sid2name(cache, 1761 req->id1.idmap_id_u.sid.prefix, 1762 req->id1.idmap_id_u.sid.rid, &name, &domain, &type); 1763 goto out; 1764 } 1765 1766 /* Lookup winame to sid */ 1767 retcode = lookup_cache_name2sid(cache, req->id1name, req->id1domain, 1768 &name, &sidprefix, &rid, &type); 1769 1770 out: 1771 if (retcode != IDMAP_SUCCESS) { 1772 free(name); 1773 free(domain); 1774 free(sidprefix); 1775 return (retcode); 1776 } 1777 1778 if (res->id.idtype == IDMAP_POSIXID) { 1779 res->id.idtype = (type == _IDMAP_T_USER) ? 1780 IDMAP_UID : IDMAP_GID; 1781 } 1782 req->id1.idtype = (type == _IDMAP_T_USER) ? 1783 IDMAP_USID : IDMAP_GSID; 1784 1785 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; 1786 if (name != NULL) { 1787 free(req->id1name); /* Free existing winname */ 1788 req->id1name = name; /* and use canonical name instead */ 1789 } 1790 if (req->id1domain == NULL) 1791 req->id1domain = domain; 1792 if (req->id1.idmap_id_u.sid.prefix == NULL) { 1793 req->id1.idmap_id_u.sid.prefix = sidprefix; 1794 req->id1.idmap_id_u.sid.rid = rid; 1795 } 1796 return (retcode); 1797 } 1798 1799 /* 1800 * Batch AD lookups 1801 */ 1802 idmap_retcode 1803 ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch, 1804 idmap_ids_res *result) 1805 { 1806 idmap_retcode retcode; 1807 int i, add, type, is_wuser, is_user; 1808 int retries = 0, eunixtype; 1809 char **unixname; 1810 idmap_mapping *req; 1811 idmap_id_res *res; 1812 idmap_query_state_t *qs = NULL; 1813 idmap_how *how; 1814 char **dn, **attr, **value; 1815 1816 /* 1817 * Since req->id2.idtype is unused, we will use it here 1818 * to retrieve the value of sid_type. But it needs to be 1819 * reset to IDMAP_NONE before we return to prevent xdr 1820 * from mis-interpreting req->id2 when it tries to free 1821 * the input argument. Other option is to allocate an 1822 * array of integers and use it instead for the batched 1823 * call. But why un-necessarily allocate memory. That may 1824 * be an option if req->id2.idtype cannot be re-used in 1825 * future. 1826 */ 1827 1828 if (state->ad_nqueries == 0) 1829 return (IDMAP_SUCCESS); 1830 1831 for (i = 0; i < batch->idmap_mapping_batch_len; i++) { 1832 req = &batch->idmap_mapping_batch_val[i]; 1833 res = &result->ids.ids_val[i]; 1834 1835 /* Skip if not marked for AD lookup or already in error. */ 1836 if (!(req->direction & _IDMAP_F_LOOKUP_AD) || 1837 res->retcode != IDMAP_SUCCESS) 1838 continue; 1839 1840 /* Init status */ 1841 res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 1842 } 1843 1844 retry: 1845 retcode = idmap_lookup_batch_start(_idmapdstate.ad, state->ad_nqueries, 1846 &qs); 1847 if (retcode != IDMAP_SUCCESS) { 1848 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 1849 goto retry; 1850 degrade_svc(1, "failed to create batch for AD lookup"); 1851 goto out; 1852 } 1853 1854 restore_svc(); 1855 1856 idmap_lookup_batch_set_unixattr(qs, state->ad_unixuser_attr, 1857 state->ad_unixgroup_attr); 1858 1859 for (i = 0, add = 0; i < batch->idmap_mapping_batch_len; i++) { 1860 req = &batch->idmap_mapping_batch_val[i]; 1861 res = &result->ids.ids_val[i]; 1862 how = &res->info.how; 1863 1864 retcode = IDMAP_SUCCESS; 1865 req->id2.idtype = IDMAP_NONE; 1866 1867 /* Skip if not marked for AD lookup */ 1868 if (!(req->direction & _IDMAP_F_LOOKUP_AD)) 1869 continue; 1870 1871 if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR) 1872 continue; 1873 1874 if (IS_REQUEST_SID(*req, 1)) { 1875 1876 /* win2unix request: */ 1877 1878 unixname = dn = attr = value = NULL; 1879 eunixtype = _IDMAP_T_UNDEF; 1880 if (req->id2name == NULL) { 1881 if (res->id.idtype == IDMAP_UID && 1882 AD_OR_MIXED(state->nm_siduid)) { 1883 eunixtype = _IDMAP_T_USER; 1884 unixname = &req->id2name; 1885 } else if (res->id.idtype == IDMAP_GID && 1886 AD_OR_MIXED(state->nm_sidgid)) { 1887 eunixtype = _IDMAP_T_GROUP; 1888 unixname = &req->id2name; 1889 } else if (AD_OR_MIXED(state->nm_siduid) || 1890 AD_OR_MIXED(state->nm_sidgid)) { 1891 unixname = &req->id2name; 1892 } 1893 } 1894 add = 1; 1895 if (unixname != NULL) { 1896 /* 1897 * Get how info for DS-based name 1898 * mapping only if AD or MIXED 1899 * mode is enabled. 1900 */ 1901 idmap_info_free(&res->info); 1902 res->info.src = IDMAP_MAP_SRC_NEW; 1903 how->map_type = IDMAP_MAP_TYPE_DS_AD; 1904 dn = &how->idmap_how_u.ad.dn; 1905 attr = &how->idmap_how_u.ad.attr; 1906 value = &how->idmap_how_u.ad.value; 1907 } 1908 if (req->id1.idmap_id_u.sid.prefix != NULL) { 1909 /* Lookup AD by SID */ 1910 retcode = idmap_sid2name_batch_add1( 1911 qs, req->id1.idmap_id_u.sid.prefix, 1912 &req->id1.idmap_id_u.sid.rid, eunixtype, 1913 dn, attr, value, 1914 (req->id1name == NULL) ? 1915 &req->id1name : NULL, 1916 (req->id1domain == NULL) ? 1917 &req->id1domain : NULL, 1918 (int *)&req->id2.idtype, unixname, 1919 &res->retcode); 1920 } else { 1921 /* Lookup AD by winname */ 1922 assert(req->id1name != NULL); 1923 retcode = idmap_name2sid_batch_add1( 1924 qs, req->id1name, req->id1domain, 1925 eunixtype, 1926 dn, attr, value, 1927 &req->id1name, 1928 &req->id1.idmap_id_u.sid.prefix, 1929 &req->id1.idmap_id_u.sid.rid, 1930 (int *)&req->id2.idtype, unixname, 1931 &res->retcode); 1932 } 1933 1934 } else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) { 1935 1936 /* unix2win request: */ 1937 1938 if (res->id.idmap_id_u.sid.prefix != NULL && 1939 req->id2name != NULL) { 1940 /* Already have SID and winname -- done */ 1941 res->retcode = IDMAP_SUCCESS; 1942 continue; 1943 } 1944 1945 if (res->id.idmap_id_u.sid.prefix != NULL) { 1946 /* 1947 * SID but no winname -- lookup AD by 1948 * SID to get winname. 1949 * how info is not needed here because 1950 * we are not retrieving unixname from 1951 * AD. 1952 */ 1953 add = 1; 1954 retcode = idmap_sid2name_batch_add1( 1955 qs, res->id.idmap_id_u.sid.prefix, 1956 &res->id.idmap_id_u.sid.rid, 1957 _IDMAP_T_UNDEF, 1958 NULL, NULL, NULL, 1959 &req->id2name, 1960 &req->id2domain, (int *)&req->id2.idtype, 1961 NULL, &res->retcode); 1962 } else if (req->id2name != NULL) { 1963 /* 1964 * winname but no SID -- lookup AD by 1965 * winname to get SID. 1966 * how info is not needed here because 1967 * we are not retrieving unixname from 1968 * AD. 1969 */ 1970 add = 1; 1971 retcode = idmap_name2sid_batch_add1( 1972 qs, req->id2name, req->id2domain, 1973 _IDMAP_T_UNDEF, 1974 NULL, NULL, NULL, NULL, 1975 &res->id.idmap_id_u.sid.prefix, 1976 &res->id.idmap_id_u.sid.rid, 1977 (int *)&req->id2.idtype, NULL, 1978 &res->retcode); 1979 } else if (req->id1name != NULL) { 1980 /* 1981 * No SID and no winname but we've unixname -- 1982 * lookup AD by unixname to get SID. 1983 */ 1984 is_user = (IS_REQUEST_UID(*req)) ? 1 : 0; 1985 if (res->id.idtype == IDMAP_USID) 1986 is_wuser = 1; 1987 else if (res->id.idtype == IDMAP_GSID) 1988 is_wuser = 0; 1989 else 1990 is_wuser = is_user; 1991 add = 1; 1992 idmap_info_free(&res->info); 1993 res->info.src = IDMAP_MAP_SRC_NEW; 1994 how->map_type = IDMAP_MAP_TYPE_DS_AD; 1995 retcode = idmap_unixname2sid_batch_add1( 1996 qs, req->id1name, is_user, is_wuser, 1997 &how->idmap_how_u.ad.dn, 1998 &how->idmap_how_u.ad.attr, 1999 &how->idmap_how_u.ad.value, 2000 &res->id.idmap_id_u.sid.prefix, 2001 &res->id.idmap_id_u.sid.rid, 2002 &req->id2name, &req->id2domain, 2003 (int *)&req->id2.idtype, &res->retcode); 2004 } 2005 } 2006 if (retcode != IDMAP_SUCCESS) { 2007 idmap_lookup_release_batch(&qs); 2008 break; 2009 } 2010 } 2011 2012 if (retcode == IDMAP_SUCCESS) { 2013 /* add keeps track if we added an entry to the batch */ 2014 if (add) 2015 retcode = idmap_lookup_batch_end(&qs); 2016 else 2017 idmap_lookup_release_batch(&qs); 2018 } 2019 2020 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 2021 goto retry; 2022 else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 2023 degrade_svc(1, "some AD lookups timed out repeatedly"); 2024 2025 if (retcode != IDMAP_SUCCESS) 2026 idmapdlog(LOG_NOTICE, "Failed to batch AD lookup requests"); 2027 2028 out: 2029 /* 2030 * This loop does the following: 2031 * 1. Reset _IDMAP_F_LOOKUP_AD flag from the request. 2032 * 2. Reset req->id2.idtype to IDMAP_NONE 2033 * 3. If batch_start or batch_add failed then set the status 2034 * of each request marked for AD lookup to that error. 2035 * 4. Evaluate the type of the AD object (i.e. user or group) and 2036 * update the idtype in request. 2037 */ 2038 for (i = 0; i < batch->idmap_mapping_batch_len; i++) { 2039 req = &batch->idmap_mapping_batch_val[i]; 2040 type = req->id2.idtype; 2041 req->id2.idtype = IDMAP_NONE; 2042 res = &result->ids.ids_val[i]; 2043 how = &res->info.how; 2044 if (!(req->direction & _IDMAP_F_LOOKUP_AD)) 2045 continue; 2046 2047 /* Reset AD lookup flag */ 2048 req->direction &= ~(_IDMAP_F_LOOKUP_AD); 2049 2050 /* 2051 * If batch_start or batch_add failed then set the status 2052 * of each request marked for AD lookup to that error. 2053 */ 2054 if (retcode != IDMAP_SUCCESS) { 2055 res->retcode = retcode; 2056 continue; 2057 } 2058 2059 if (!add) 2060 continue; 2061 2062 if (res->retcode == IDMAP_ERR_NOTFOUND) { 2063 /* Nothing found - remove the preset info */ 2064 idmap_info_free(&res->info); 2065 } 2066 2067 if (IS_REQUEST_SID(*req, 1)) { 2068 if (res->retcode != IDMAP_SUCCESS) 2069 continue; 2070 /* Evaluate result type */ 2071 switch (type) { 2072 case _IDMAP_T_USER: 2073 if (res->id.idtype == IDMAP_POSIXID) 2074 res->id.idtype = IDMAP_UID; 2075 req->id1.idtype = IDMAP_USID; 2076 break; 2077 case _IDMAP_T_GROUP: 2078 if (res->id.idtype == IDMAP_POSIXID) 2079 res->id.idtype = IDMAP_GID; 2080 req->id1.idtype = IDMAP_GSID; 2081 break; 2082 default: 2083 res->retcode = IDMAP_ERR_SID; 2084 break; 2085 } 2086 if (res->retcode == IDMAP_SUCCESS && 2087 req->id1name != NULL && 2088 (req->id2name == NULL || 2089 res->id.idmap_id_u.uid == SENTINEL_PID) && 2090 NLDAP_MODE(res->id.idtype, state)) { 2091 req->direction |= _IDMAP_F_LOOKUP_NLDAP; 2092 state->nldap_nqueries++; 2093 } 2094 } else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) { 2095 if (res->retcode != IDMAP_SUCCESS) { 2096 if ((!(IDMAP_FATAL_ERROR(res->retcode))) && 2097 res->id.idmap_id_u.sid.prefix == NULL && 2098 req->id2name == NULL && /* no winname */ 2099 req->id1name != NULL) /* unixname */ 2100 /* 2101 * If AD lookup by unixname failed 2102 * with non fatal error then clear 2103 * the error (i.e set res->retcode 2104 * to success). This allows the next 2105 * pass to process other mapping 2106 * mechanisms for this request. 2107 */ 2108 res->retcode = IDMAP_SUCCESS; 2109 continue; 2110 } 2111 /* Evaluate result type */ 2112 switch (type) { 2113 case _IDMAP_T_USER: 2114 if (res->id.idtype == IDMAP_SID) 2115 res->id.idtype = IDMAP_USID; 2116 break; 2117 case _IDMAP_T_GROUP: 2118 if (res->id.idtype == IDMAP_SID) 2119 res->id.idtype = IDMAP_GSID; 2120 break; 2121 default: 2122 res->retcode = IDMAP_ERR_SID; 2123 break; 2124 } 2125 } 2126 } 2127 2128 /* AD lookups done. Reset state->ad_nqueries and return */ 2129 state->ad_nqueries = 0; 2130 return (retcode); 2131 } 2132 2133 /* 2134 * Convention when processing win2unix requests: 2135 * 2136 * Windows identity: 2137 * req->id1name = 2138 * winname if given otherwise winname found will be placed 2139 * here. 2140 * req->id1domain = 2141 * windomain if given otherwise windomain found will be 2142 * placed here. 2143 * req->id1.idtype = 2144 * Either IDMAP_SID/USID/GSID. If this is IDMAP_SID then it'll 2145 * be set to IDMAP_USID/GSID depending upon whether the 2146 * given SID is user or group respectively. The user/group-ness 2147 * is determined either when looking up well-known SIDs table OR 2148 * if the SID is found in namecache OR by ad_lookup_one() OR by 2149 * ad_lookup_batch(). 2150 * req->id1..sid.[prefix, rid] = 2151 * SID if given otherwise SID found will be placed here. 2152 * 2153 * Unix identity: 2154 * req->id2name = 2155 * unixname found will be placed here. 2156 * req->id2domain = 2157 * NOT USED 2158 * res->id.idtype = 2159 * Target type initialized from req->id2.idtype. If 2160 * it is IDMAP_POSIXID then actual type (IDMAP_UID/GID) found 2161 * will be placed here. 2162 * res->id..[uid or gid] = 2163 * UID/GID found will be placed here. 2164 * 2165 * Others: 2166 * res->retcode = 2167 * Return status for this request will be placed here. 2168 * res->direction = 2169 * Direction found will be placed here. Direction 2170 * meaning whether the resultant mapping is valid 2171 * only from win2unix or bi-directional. 2172 * req->direction = 2173 * INTERNAL USE. Used by idmapd to set various 2174 * flags (_IDMAP_F_xxxx) to aid in processing 2175 * of the request. 2176 * req->id2.idtype = 2177 * INTERNAL USE. Initially this is the requested target 2178 * type and is used to initialize res->id.idtype. 2179 * ad_lookup_batch() uses this field temporarily to store 2180 * sid_type obtained by the batched AD lookups and after 2181 * use resets it to IDMAP_NONE to prevent xdr from 2182 * mis-interpreting the contents of req->id2. 2183 * req->id2..[uid or gid or sid] = 2184 * NOT USED 2185 */ 2186 2187 /* 2188 * This function does the following: 2189 * 1. Lookup well-known SIDs table. 2190 * 2. Check if the given SID is a local-SID and if so extract UID/GID from it. 2191 * 3. Lookup cache. 2192 * 4. Check if the client does not want new mapping to be allocated 2193 * in which case this pass is the final pass. 2194 * 5. Set AD lookup flag if it determines that the next stage needs 2195 * to do AD lookup. 2196 */ 2197 idmap_retcode 2198 sid2pid_first_pass(lookup_state_t *state, idmap_mapping *req, 2199 idmap_id_res *res) 2200 { 2201 idmap_retcode retcode; 2202 int wksid; 2203 2204 /* Initialize result */ 2205 res->id.idtype = req->id2.idtype; 2206 res->id.idmap_id_u.uid = SENTINEL_PID; 2207 res->direction = IDMAP_DIRECTION_UNDEF; 2208 wksid = 0; 2209 2210 if (EMPTY_STRING(req->id1.idmap_id_u.sid.prefix)) { 2211 if (req->id1name == NULL) { 2212 retcode = IDMAP_ERR_ARG; 2213 goto out; 2214 } 2215 /* sanitize sidprefix */ 2216 free(req->id1.idmap_id_u.sid.prefix); 2217 req->id1.idmap_id_u.sid.prefix = NULL; 2218 } 2219 2220 /* Lookup well-known SIDs table */ 2221 retcode = lookup_wksids_sid2pid(req, res, &wksid); 2222 if (retcode != IDMAP_ERR_NOTFOUND) 2223 goto out; 2224 2225 /* Check if this is a localsid */ 2226 if (!wksid) { 2227 retcode = lookup_localsid2pid(req, res); 2228 if (retcode != IDMAP_ERR_NOTFOUND) 2229 goto out; 2230 } 2231 2232 /* Lookup cache */ 2233 retcode = lookup_cache_sid2pid(state->cache, req, res); 2234 if (retcode != IDMAP_ERR_NOTFOUND) 2235 goto out; 2236 2237 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) { 2238 retcode = IDMAP_ERR_NONEGENERATED; 2239 goto out; 2240 } 2241 2242 /* 2243 * Failed to find non-expired entry in cache. Next step is 2244 * to determine if this request needs to be batched for AD lookup. 2245 * 2246 * At this point we have either sid or winname or both. If we don't 2247 * have both then lookup name_cache for the sid or winname 2248 * whichever is missing. If not found then this request will be 2249 * batched for AD lookup. 2250 */ 2251 retcode = lookup_name_cache(state->cache, req, res); 2252 if (retcode != IDMAP_SUCCESS && retcode != IDMAP_ERR_NOTFOUND) 2253 goto out; 2254 2255 /* 2256 * Set the flag to indicate that we are not done yet so that 2257 * subsequent passes considers this request for name-based 2258 * mapping and ephemeral mapping. 2259 */ 2260 state->sid2pid_done = FALSE; 2261 req->direction |= _IDMAP_F_NOTDONE; 2262 2263 /* 2264 * Even if we have both sid and winname, we still may need to batch 2265 * this request for AD lookup if we don't have unixname and 2266 * directory-based name mapping (AD or mixed) is enabled. 2267 * We avoid AD lookup for well-known SIDs because they don't have 2268 * regular AD objects. 2269 */ 2270 if (retcode != IDMAP_SUCCESS || 2271 (!wksid && req->id2name == NULL && 2272 AD_OR_MIXED_MODE(res->id.idtype, state))) { 2273 retcode = IDMAP_SUCCESS; 2274 req->direction |= _IDMAP_F_LOOKUP_AD; 2275 state->ad_nqueries++; 2276 } else if (NLDAP_MODE(res->id.idtype, state)) { 2277 req->direction |= _IDMAP_F_LOOKUP_NLDAP; 2278 state->nldap_nqueries++; 2279 } 2280 2281 2282 out: 2283 res->retcode = idmap_stat4prot(retcode); 2284 /* 2285 * If we are done and there was an error then set fallback pid 2286 * in the result. 2287 */ 2288 if (ARE_WE_DONE(req->direction) && res->retcode != IDMAP_SUCCESS) 2289 res->id.idmap_id_u.uid = UID_NOBODY; 2290 return (retcode); 2291 } 2292 2293 /* 2294 * Generate SID using the following convention 2295 * <machine-sid-prefix>-<1000 + uid> 2296 * <machine-sid-prefix>-<2^31 + gid> 2297 */ 2298 static 2299 idmap_retcode 2300 generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user, 2301 int fallback) 2302 { 2303 free(res->id.idmap_id_u.sid.prefix); 2304 res->id.idmap_id_u.sid.prefix = NULL; 2305 2306 /* 2307 * Diagonal mapping for localSIDs not supported because of the 2308 * way we generate localSIDs. 2309 */ 2310 if (is_user && res->id.idtype == IDMAP_GSID) 2311 return (IDMAP_ERR_NOMAPPING); 2312 if (!is_user && res->id.idtype == IDMAP_USID) 2313 return (IDMAP_ERR_NOMAPPING); 2314 2315 /* Skip 1000 UIDs */ 2316 if (is_user && req->id1.idmap_id_u.uid > 2317 (INT32_MAX - LOCALRID_MIN)) 2318 return (IDMAP_ERR_NOMAPPING); 2319 2320 RDLOCK_CONFIG(); 2321 /* 2322 * machine_sid is never NULL because if it is we won't be here. 2323 * No need to assert because stdrup(NULL) will core anyways. 2324 */ 2325 res->id.idmap_id_u.sid.prefix = 2326 strdup(_idmapdstate.cfg->pgcfg.machine_sid); 2327 if (res->id.idmap_id_u.sid.prefix == NULL) { 2328 UNLOCK_CONFIG(); 2329 idmapdlog(LOG_ERR, "Out of memory"); 2330 return (IDMAP_ERR_MEMORY); 2331 } 2332 UNLOCK_CONFIG(); 2333 res->id.idmap_id_u.sid.rid = 2334 (is_user) ? req->id1.idmap_id_u.uid + LOCALRID_MIN : 2335 req->id1.idmap_id_u.gid + INT32_MAX + 1; 2336 res->direction = IDMAP_DIRECTION_BI; 2337 if (res->id.idtype == IDMAP_SID) 2338 res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID; 2339 2340 if (!fallback && req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 2341 res->info.how.map_type = IDMAP_MAP_TYPE_LOCAL_SID; 2342 res->info.src = IDMAP_MAP_SRC_ALGORITHMIC; 2343 } 2344 2345 /* 2346 * Don't update name_cache because local sids don't have 2347 * valid windows names. 2348 */ 2349 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; 2350 return (IDMAP_SUCCESS); 2351 } 2352 2353 static 2354 idmap_retcode 2355 lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res) 2356 { 2357 char *sidprefix; 2358 uint32_t rid; 2359 int s; 2360 2361 /* 2362 * If the sidprefix == localsid then UID = last RID - 1000 or 2363 * GID = last RID - 2^31. 2364 */ 2365 if ((sidprefix = req->id1.idmap_id_u.sid.prefix) == NULL) 2366 /* This means we are looking up by winname */ 2367 return (IDMAP_ERR_NOTFOUND); 2368 rid = req->id1.idmap_id_u.sid.rid; 2369 2370 RDLOCK_CONFIG(); 2371 s = (_idmapdstate.cfg->pgcfg.machine_sid) ? 2372 strcasecmp(sidprefix, _idmapdstate.cfg->pgcfg.machine_sid) : 1; 2373 UNLOCK_CONFIG(); 2374 2375 /* 2376 * If the given sidprefix does not match machine_sid then this is 2377 * not a local SID. 2378 */ 2379 if (s != 0) 2380 return (IDMAP_ERR_NOTFOUND); 2381 2382 switch (res->id.idtype) { 2383 case IDMAP_UID: 2384 if (rid > INT32_MAX || rid < LOCALRID_MIN) 2385 return (IDMAP_ERR_ARG); 2386 res->id.idmap_id_u.uid = rid - LOCALRID_MIN; 2387 break; 2388 case IDMAP_GID: 2389 if (rid <= INT32_MAX) 2390 return (IDMAP_ERR_ARG); 2391 res->id.idmap_id_u.gid = rid - INT32_MAX - 1; 2392 break; 2393 case IDMAP_POSIXID: 2394 if (rid > INT32_MAX) { 2395 res->id.idmap_id_u.gid = rid - INT32_MAX - 1; 2396 res->id.idtype = IDMAP_GID; 2397 } else if (rid < LOCALRID_MIN) { 2398 return (IDMAP_ERR_ARG); 2399 } else { 2400 res->id.idmap_id_u.uid = rid - LOCALRID_MIN; 2401 res->id.idtype = IDMAP_UID; 2402 } 2403 break; 2404 default: 2405 return (IDMAP_ERR_NOTSUPPORTED); 2406 } 2407 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 2408 res->info.how.map_type = IDMAP_MAP_TYPE_LOCAL_SID; 2409 res->info.src = IDMAP_MAP_SRC_ALGORITHMIC; 2410 } 2411 return (IDMAP_SUCCESS); 2412 } 2413 2414 /* 2415 * Name service lookup by unixname to get pid 2416 */ 2417 static 2418 idmap_retcode 2419 ns_lookup_byname(const char *name, const char *lower_name, idmap_id *id) 2420 { 2421 struct passwd pwd, *pwdp; 2422 struct group grp, *grpp; 2423 char buf[1024]; 2424 int errnum; 2425 const char *me = "ns_lookup_byname"; 2426 2427 switch (id->idtype) { 2428 case IDMAP_UID: 2429 pwdp = getpwnam_r(name, &pwd, buf, sizeof (buf)); 2430 if (pwdp == NULL && errno == 0 && lower_name != NULL && 2431 name != lower_name && strcmp(name, lower_name) != 0) 2432 pwdp = getpwnam_r(lower_name, &pwd, buf, sizeof (buf)); 2433 if (pwdp == NULL) { 2434 errnum = errno; 2435 idmapdlog(LOG_WARNING, 2436 "%s: getpwnam_r(%s) failed (%s).", 2437 me, name, errnum ? strerror(errnum) : "not found"); 2438 if (errnum == 0) 2439 return (IDMAP_ERR_NOTFOUND); 2440 else 2441 return (IDMAP_ERR_INTERNAL); 2442 } 2443 id->idmap_id_u.uid = pwd.pw_uid; 2444 break; 2445 case IDMAP_GID: 2446 grpp = getgrnam_r(name, &grp, buf, sizeof (buf)); 2447 if (grpp == NULL && errno == 0 && lower_name != NULL && 2448 name != lower_name && strcmp(name, lower_name) != 0) 2449 grpp = getgrnam_r(lower_name, &grp, buf, sizeof (buf)); 2450 if (grpp == NULL) { 2451 errnum = errno; 2452 idmapdlog(LOG_WARNING, 2453 "%s: getgrnam_r(%s) failed (%s).", 2454 me, name, errnum ? strerror(errnum) : "not found"); 2455 if (errnum == 0) 2456 return (IDMAP_ERR_NOTFOUND); 2457 else 2458 return (IDMAP_ERR_INTERNAL); 2459 } 2460 id->idmap_id_u.gid = grp.gr_gid; 2461 break; 2462 default: 2463 return (IDMAP_ERR_ARG); 2464 } 2465 return (IDMAP_SUCCESS); 2466 } 2467 2468 2469 /* 2470 * Name service lookup by pid to get unixname 2471 */ 2472 static 2473 idmap_retcode 2474 ns_lookup_bypid(uid_t pid, int is_user, char **unixname) 2475 { 2476 struct passwd pwd; 2477 struct group grp; 2478 char buf[1024]; 2479 int errnum; 2480 const char *me = "ns_lookup_bypid"; 2481 2482 if (is_user) { 2483 errno = 0; 2484 if (getpwuid_r(pid, &pwd, buf, sizeof (buf)) == NULL) { 2485 errnum = errno; 2486 idmapdlog(LOG_WARNING, 2487 "%s: getpwuid_r(%u) failed (%s).", 2488 me, pid, errnum ? strerror(errnum) : "not found"); 2489 if (errnum == 0) 2490 return (IDMAP_ERR_NOTFOUND); 2491 else 2492 return (IDMAP_ERR_INTERNAL); 2493 } 2494 *unixname = strdup(pwd.pw_name); 2495 } else { 2496 errno = 0; 2497 if (getgrgid_r(pid, &grp, buf, sizeof (buf)) == NULL) { 2498 errnum = errno; 2499 idmapdlog(LOG_WARNING, 2500 "%s: getgrgid_r(%u) failed (%s).", 2501 me, pid, errnum ? strerror(errnum) : "not found"); 2502 if (errnum == 0) 2503 return (IDMAP_ERR_NOTFOUND); 2504 else 2505 return (IDMAP_ERR_INTERNAL); 2506 } 2507 *unixname = strdup(grp.gr_name); 2508 } 2509 if (*unixname == NULL) 2510 return (IDMAP_ERR_MEMORY); 2511 return (IDMAP_SUCCESS); 2512 } 2513 2514 /* 2515 * Name-based mapping 2516 * 2517 * Case 1: If no rule matches do ephemeral 2518 * 2519 * Case 2: If rule matches and unixname is "" then return no mapping. 2520 * 2521 * Case 3: If rule matches and unixname is specified then lookup name 2522 * service using the unixname. If unixname not found then return no mapping. 2523 * 2524 * Case 4: If rule matches and unixname is * then lookup name service 2525 * using winname as the unixname. If unixname not found then process 2526 * other rules using the lookup order. If no other rule matches then do 2527 * ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4. 2528 * This allows us to specify a fallback unixname per _domain_ or no mapping 2529 * instead of the default behaviour of doing ephemeral mapping. 2530 * 2531 * Example 1: 2532 * *@sfbay == * 2533 * If looking up windows users foo@sfbay and foo does not exists in 2534 * the name service then foo@sfbay will be mapped to an ephemeral id. 2535 * 2536 * Example 2: 2537 * *@sfbay == * 2538 * *@sfbay => guest 2539 * If looking up windows users foo@sfbay and foo does not exists in 2540 * the name service then foo@sfbay will be mapped to guest. 2541 * 2542 * Example 3: 2543 * *@sfbay == * 2544 * *@sfbay => "" 2545 * If looking up windows users foo@sfbay and foo does not exists in 2546 * the name service then we will return no mapping for foo@sfbay. 2547 * 2548 */ 2549 static 2550 idmap_retcode 2551 name_based_mapping_sid2pid(lookup_state_t *state, 2552 idmap_mapping *req, idmap_id_res *res) 2553 { 2554 const char *unixname, *windomain; 2555 char *sql = NULL, *errmsg = NULL, *lower_winname = NULL; 2556 idmap_retcode retcode; 2557 char *end, *lower_unixname, *winname; 2558 const char **values; 2559 sqlite_vm *vm = NULL; 2560 int ncol, r, i, is_user, is_wuser; 2561 idmap_namerule *rule = &res->info.how.idmap_how_u.rule; 2562 int direction; 2563 const char *me = "name_based_mapping_sid2pid"; 2564 2565 assert(req->id1name != NULL); /* We have winname */ 2566 assert(req->id2name == NULL); /* We don't have unixname */ 2567 2568 winname = req->id1name; 2569 windomain = req->id1domain; 2570 2571 switch (req->id1.idtype) { 2572 case IDMAP_USID: 2573 is_wuser = 1; 2574 break; 2575 case IDMAP_GSID: 2576 is_wuser = 0; 2577 break; 2578 default: 2579 idmapdlog(LOG_ERR, "%s: Unable to determine if the " 2580 "given Windows id is user or group.", me); 2581 return (IDMAP_ERR_INTERNAL); 2582 } 2583 2584 switch (res->id.idtype) { 2585 case IDMAP_UID: 2586 is_user = 1; 2587 break; 2588 case IDMAP_GID: 2589 is_user = 0; 2590 break; 2591 case IDMAP_POSIXID: 2592 is_user = is_wuser; 2593 res->id.idtype = is_user ? IDMAP_UID : IDMAP_GID; 2594 break; 2595 } 2596 2597 i = 0; 2598 if (windomain == NULL) 2599 windomain = ""; 2600 else if (state->defdom != NULL && 2601 strcasecmp(state->defdom, windomain) == 0) 2602 i = 1; 2603 2604 if ((lower_winname = tolower_u8(winname)) == NULL) 2605 lower_winname = winname; /* hope for the best */ 2606 sql = sqlite_mprintf( 2607 "SELECT unixname, u2w_order, winname_display, windomain, is_nt4 " 2608 "FROM namerules WHERE " 2609 "w2u_order > 0 AND is_user = %d AND is_wuser = %d AND " 2610 "(winname = %Q OR winname = '*') AND " 2611 "(windomain = %Q OR windomain = '*' %s) " 2612 "ORDER BY w2u_order ASC;", 2613 is_user, is_wuser, lower_winname, windomain, 2614 i ? "OR windomain ISNULL OR windomain = ''" : ""); 2615 if (sql == NULL) { 2616 idmapdlog(LOG_ERR, "Out of memory"); 2617 retcode = IDMAP_ERR_MEMORY; 2618 goto out; 2619 } 2620 2621 if (sqlite_compile(state->db, sql, NULL, &vm, &errmsg) != SQLITE_OK) { 2622 retcode = IDMAP_ERR_INTERNAL; 2623 idmapdlog(LOG_ERR, "%s: database error (%s)", me, 2624 CHECK_NULL(errmsg)); 2625 sqlite_freemem(errmsg); 2626 goto out; 2627 } 2628 2629 for (;;) { 2630 r = sqlite_step(vm, &ncol, &values, NULL); 2631 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 2632 2633 if (r == SQLITE_ROW) { 2634 if (ncol < 5) { 2635 retcode = IDMAP_ERR_INTERNAL; 2636 goto out; 2637 } 2638 if (values[0] == NULL) { 2639 retcode = IDMAP_ERR_INTERNAL; 2640 goto out; 2641 } 2642 2643 if (values[1] != NULL) 2644 direction = 2645 (strtol(values[1], &end, 10) == 0)? 2646 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; 2647 else 2648 direction = IDMAP_DIRECTION_W2U; 2649 2650 if (EMPTY_NAME(values[0])) { 2651 idmap_namerule_set(rule, values[3], values[2], 2652 values[0], is_wuser, is_user, 2653 strtol(values[4], &end, 10), 2654 direction); 2655 retcode = IDMAP_ERR_NOMAPPING; 2656 goto out; 2657 } 2658 2659 if (values[0][0] == '*') { 2660 unixname = winname; 2661 lower_unixname = lower_winname; 2662 } else { 2663 unixname = values[0]; 2664 lower_unixname = NULL; 2665 } 2666 2667 retcode = ns_lookup_byname(unixname, lower_unixname, 2668 &res->id); 2669 if (retcode == IDMAP_ERR_NOTFOUND) { 2670 if (values[0][0] == '*') 2671 /* Case 4 */ 2672 continue; 2673 else { 2674 /* Case 3 */ 2675 idmap_namerule_set(rule, values[3], 2676 values[2], values[0], is_wuser, 2677 is_user, 2678 strtol(values[4], &end, 10), 2679 direction); 2680 retcode = IDMAP_ERR_NOMAPPING; 2681 } 2682 } 2683 goto out; 2684 } else if (r == SQLITE_DONE) { 2685 retcode = IDMAP_ERR_NOTFOUND; 2686 goto out; 2687 } else { 2688 (void) sqlite_finalize(vm, &errmsg); 2689 vm = NULL; 2690 idmapdlog(LOG_ERR, "%s: database error (%s)", me, 2691 CHECK_NULL(errmsg)); 2692 sqlite_freemem(errmsg); 2693 retcode = IDMAP_ERR_INTERNAL; 2694 goto out; 2695 } 2696 } 2697 2698 out: 2699 if (sql != NULL) 2700 sqlite_freemem(sql); 2701 res->info.how.map_type = IDMAP_MAP_TYPE_RULE_BASED; 2702 if (retcode == IDMAP_SUCCESS) { 2703 if (values[1] != NULL) 2704 res->direction = 2705 (strtol(values[1], &end, 10) == 0)? 2706 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; 2707 else 2708 res->direction = IDMAP_DIRECTION_W2U; 2709 2710 req->id2name = strdup(unixname); 2711 if (req->id2name == NULL) { 2712 retcode = IDMAP_ERR_MEMORY; 2713 } 2714 } 2715 2716 if (retcode == IDMAP_SUCCESS) { 2717 idmap_namerule_set(rule, values[3], values[2], 2718 values[0], is_wuser, is_user, strtol(values[4], &end, 10), 2719 res->direction); 2720 res->info.src = IDMAP_MAP_SRC_NEW; 2721 } 2722 2723 if (lower_winname != NULL && lower_winname != winname) 2724 free(lower_winname); 2725 if (vm != NULL) 2726 (void) sqlite_finalize(vm, NULL); 2727 return (retcode); 2728 } 2729 2730 static 2731 int 2732 get_next_eph_uid(uid_t *next_uid) 2733 { 2734 uid_t uid; 2735 gid_t gid; 2736 int err; 2737 2738 *next_uid = (uid_t)-1; 2739 uid = _idmapdstate.next_uid++; 2740 if (uid >= _idmapdstate.limit_uid) { 2741 if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0) 2742 return (err); 2743 2744 _idmapdstate.limit_uid = uid + 8192; 2745 _idmapdstate.next_uid = uid; 2746 } 2747 *next_uid = uid; 2748 2749 return (0); 2750 } 2751 2752 static 2753 int 2754 get_next_eph_gid(gid_t *next_gid) 2755 { 2756 uid_t uid; 2757 gid_t gid; 2758 int err; 2759 2760 *next_gid = (uid_t)-1; 2761 gid = _idmapdstate.next_gid++; 2762 if (gid >= _idmapdstate.limit_gid) { 2763 if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0) 2764 return (err); 2765 2766 _idmapdstate.limit_gid = gid + 8192; 2767 _idmapdstate.next_gid = gid; 2768 } 2769 *next_gid = gid; 2770 2771 return (0); 2772 } 2773 2774 static 2775 int 2776 gethash(const char *str, uint32_t num, uint_t htsize) 2777 { 2778 uint_t hval, i, len; 2779 2780 if (str == NULL) 2781 return (0); 2782 for (len = strlen(str), hval = 0, i = 0; i < len; i++) { 2783 hval += str[i]; 2784 hval += (hval << 10); 2785 hval ^= (hval >> 6); 2786 } 2787 for (str = (const char *)&num, i = 0; i < sizeof (num); i++) { 2788 hval += str[i]; 2789 hval += (hval << 10); 2790 hval ^= (hval >> 6); 2791 } 2792 hval += (hval << 3); 2793 hval ^= (hval >> 11); 2794 hval += (hval << 15); 2795 return (hval % htsize); 2796 } 2797 2798 static 2799 int 2800 get_from_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid, 2801 uid_t *pid) 2802 { 2803 uint_t next, key; 2804 uint_t htsize = state->sid_history_size; 2805 idmap_sid *sid; 2806 2807 next = gethash(prefix, rid, htsize); 2808 while (next != htsize) { 2809 key = state->sid_history[next].key; 2810 if (key == htsize) 2811 return (0); 2812 sid = &state->batch->idmap_mapping_batch_val[key].id1. 2813 idmap_id_u.sid; 2814 if (sid->rid == rid && strcmp(sid->prefix, prefix) == 0) { 2815 *pid = state->result->ids.ids_val[key].id. 2816 idmap_id_u.uid; 2817 return (1); 2818 } 2819 next = state->sid_history[next].next; 2820 } 2821 return (0); 2822 } 2823 2824 static 2825 void 2826 add_to_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid) 2827 { 2828 uint_t hash, next; 2829 uint_t htsize = state->sid_history_size; 2830 2831 hash = next = gethash(prefix, rid, htsize); 2832 while (state->sid_history[next].key != htsize) { 2833 next++; 2834 next %= htsize; 2835 } 2836 state->sid_history[next].key = state->curpos; 2837 if (hash == next) 2838 return; 2839 state->sid_history[next].next = state->sid_history[hash].next; 2840 state->sid_history[hash].next = next; 2841 } 2842 2843 void 2844 cleanup_lookup_state(lookup_state_t *state) 2845 { 2846 free(state->sid_history); 2847 free(state->ad_unixuser_attr); 2848 free(state->ad_unixgroup_attr); 2849 free(state->nldap_winname_attr); 2850 free(state->defdom); 2851 } 2852 2853 /* ARGSUSED */ 2854 static 2855 idmap_retcode 2856 dynamic_ephemeral_mapping(lookup_state_t *state, 2857 idmap_mapping *req, idmap_id_res *res) 2858 { 2859 2860 uid_t next_pid; 2861 2862 res->direction = IDMAP_DIRECTION_BI; 2863 2864 if (IS_EPHEMERAL(res->id.idmap_id_u.uid)) { 2865 res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL; 2866 res->info.src = IDMAP_MAP_SRC_CACHE; 2867 return (IDMAP_SUCCESS); 2868 } 2869 2870 if (state->sid_history != NULL && 2871 get_from_sid_history(state, req->id1.idmap_id_u.sid.prefix, 2872 req->id1.idmap_id_u.sid.rid, &next_pid)) { 2873 res->id.idmap_id_u.uid = next_pid; 2874 res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL; 2875 res->info.src = IDMAP_MAP_SRC_NEW; 2876 return (IDMAP_SUCCESS); 2877 } 2878 2879 if (res->id.idtype == IDMAP_UID) { 2880 if (get_next_eph_uid(&next_pid) != 0) 2881 return (IDMAP_ERR_INTERNAL); 2882 res->id.idmap_id_u.uid = next_pid; 2883 } else { 2884 if (get_next_eph_gid(&next_pid) != 0) 2885 return (IDMAP_ERR_INTERNAL); 2886 res->id.idmap_id_u.gid = next_pid; 2887 } 2888 2889 res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL; 2890 res->info.src = IDMAP_MAP_SRC_NEW; 2891 if (state->sid_history != NULL) 2892 add_to_sid_history(state, req->id1.idmap_id_u.sid.prefix, 2893 req->id1.idmap_id_u.sid.rid); 2894 2895 return (IDMAP_SUCCESS); 2896 } 2897 2898 idmap_retcode 2899 sid2pid_second_pass(lookup_state_t *state, 2900 idmap_mapping *req, idmap_id_res *res) 2901 { 2902 idmap_retcode retcode; 2903 2904 /* Check if second pass is needed */ 2905 if (ARE_WE_DONE(req->direction)) 2906 return (res->retcode); 2907 2908 /* Get status from previous pass */ 2909 retcode = res->retcode; 2910 if (retcode != IDMAP_SUCCESS) 2911 goto out; 2912 2913 /* 2914 * If directory-based name mapping is enabled then the unixname 2915 * may already have been retrieved from the AD object (AD-mode or 2916 * mixed-mode) or from native LDAP object (nldap-mode) -- done. 2917 */ 2918 if (req->id2name != NULL) { 2919 assert(res->id.idtype != IDMAP_POSIXID); 2920 if (AD_MODE(res->id.idtype, state)) 2921 res->direction = IDMAP_DIRECTION_BI; 2922 else if (NLDAP_MODE(res->id.idtype, state)) 2923 res->direction = IDMAP_DIRECTION_BI; 2924 else if (MIXED_MODE(res->id.idtype, state)) 2925 res->direction = IDMAP_DIRECTION_W2U; 2926 2927 /* 2928 * Special case: (1) If the ad_unixuser_attr and 2929 * ad_unixgroup_attr uses the same attribute 2930 * name and (2) if this is a diagonal mapping 2931 * request and (3) the unixname has been retrieved 2932 * from the AD object -- then we ignore it and fallback 2933 * to name-based mapping rules and ephemeral mapping 2934 * 2935 * Example: 2936 * Properties: 2937 * config/ad_unixuser_attr = "unixname" 2938 * config/ad_unixgroup_attr = "unixname" 2939 * AD user object: 2940 * dn: cn=bob ... 2941 * objectclass: user 2942 * sam: bob 2943 * unixname: bob1234 2944 * AD group object: 2945 * dn: cn=winadmins ... 2946 * objectclass: group 2947 * sam: winadmins 2948 * unixname: unixadmins 2949 * 2950 * In this example whether "unixname" refers to a unixuser 2951 * or unixgroup depends upon the AD object. 2952 * 2953 * $idmap show -c winname:bob gid 2954 * AD lookup by "samAccountName=bob" for 2955 * "ad_unixgroup_attr (i.e unixname)" for directory-based 2956 * mapping would get "bob1234" which is not what we want. 2957 * Now why not getgrnam_r("bob1234") and use it if it 2958 * is indeed a unixgroup? That's because Unix can have 2959 * users and groups with the same name and we clearly 2960 * don't know the intention of the admin here. 2961 * Therefore we ignore this and fallback to name-based 2962 * mapping rules or ephemeral mapping. 2963 */ 2964 if ((AD_MODE(res->id.idtype, state) || 2965 MIXED_MODE(res->id.idtype, state)) && 2966 state->ad_unixuser_attr != NULL && 2967 state->ad_unixgroup_attr != NULL && 2968 strcasecmp(state->ad_unixuser_attr, 2969 state->ad_unixgroup_attr) == 0 && 2970 ((req->id1.idtype == IDMAP_USID && 2971 res->id.idtype == IDMAP_GID) || 2972 (req->id1.idtype == IDMAP_GSID && 2973 res->id.idtype == IDMAP_UID))) { 2974 free(req->id2name); 2975 req->id2name = NULL; 2976 res->id.idmap_id_u.uid = SENTINEL_PID; 2977 /* fallback */ 2978 } else { 2979 if (res->id.idmap_id_u.uid == SENTINEL_PID) 2980 retcode = ns_lookup_byname(req->id2name, 2981 NULL, &res->id); 2982 /* 2983 * If ns_lookup_byname() fails that means the 2984 * unixname (req->id2name), which was obtained 2985 * from the AD object by directory-based mapping, 2986 * is not a valid Unix user/group and therefore 2987 * we return the error to the client instead of 2988 * doing rule-based mapping or ephemeral mapping. 2989 * This way the client can detect the issue. 2990 */ 2991 goto out; 2992 } 2993 } 2994 2995 /* Free any mapping info from Directory based mapping */ 2996 if (res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN) 2997 idmap_info_free(&res->info); 2998 2999 /* 3000 * If we don't have unixname then evaluate local name-based 3001 * mapping rules. 3002 */ 3003 retcode = name_based_mapping_sid2pid(state, req, res); 3004 if (retcode != IDMAP_ERR_NOTFOUND) 3005 goto out; 3006 3007 /* If not found, do ephemeral mapping */ 3008 retcode = dynamic_ephemeral_mapping(state, req, res); 3009 3010 out: 3011 res->retcode = idmap_stat4prot(retcode); 3012 if (res->retcode != IDMAP_SUCCESS) { 3013 req->direction = _IDMAP_F_DONE; 3014 res->id.idmap_id_u.uid = UID_NOBODY; 3015 } 3016 if (!ARE_WE_DONE(req->direction)) 3017 state->sid2pid_done = FALSE; 3018 return (retcode); 3019 } 3020 3021 idmap_retcode 3022 update_cache_pid2sid(lookup_state_t *state, 3023 idmap_mapping *req, idmap_id_res *res) 3024 { 3025 char *sql = NULL; 3026 idmap_retcode retcode; 3027 char *map_dn = NULL; 3028 char *map_attr = NULL; 3029 char *map_value = NULL; 3030 char *map_windomain = NULL; 3031 char *map_winname = NULL; 3032 char *map_unixname = NULL; 3033 int map_is_nt4 = FALSE; 3034 3035 /* Check if we need to cache anything */ 3036 if (ARE_WE_DONE(req->direction)) 3037 return (IDMAP_SUCCESS); 3038 3039 /* We don't cache negative entries */ 3040 if (res->retcode != IDMAP_SUCCESS) 3041 return (IDMAP_SUCCESS); 3042 3043 assert(res->direction != IDMAP_DIRECTION_UNDEF); 3044 assert(req->id1.idmap_id_u.uid != SENTINEL_PID); 3045 assert(res->id.idtype != IDMAP_SID); 3046 3047 assert(res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN); 3048 switch (res->info.how.map_type) { 3049 case IDMAP_MAP_TYPE_DS_AD: 3050 map_dn = res->info.how.idmap_how_u.ad.dn; 3051 map_attr = res->info.how.idmap_how_u.ad.attr; 3052 map_value = res->info.how.idmap_how_u.ad.value; 3053 break; 3054 3055 case IDMAP_MAP_TYPE_DS_NLDAP: 3056 map_dn = res->info.how.idmap_how_u.nldap.dn; 3057 map_attr = res->info.how.idmap_how_u.nldap.attr; 3058 map_value = res->info.how.idmap_how_u.nldap.value; 3059 break; 3060 3061 case IDMAP_MAP_TYPE_RULE_BASED: 3062 map_windomain = res->info.how.idmap_how_u.rule.windomain; 3063 map_winname = res->info.how.idmap_how_u.rule.winname; 3064 map_unixname = res->info.how.idmap_how_u.rule.unixname; 3065 map_is_nt4 = res->info.how.idmap_how_u.rule.is_nt4; 3066 break; 3067 3068 case IDMAP_MAP_TYPE_EPHEMERAL: 3069 break; 3070 3071 case IDMAP_MAP_TYPE_LOCAL_SID: 3072 break; 3073 3074 default: 3075 /* Dont cache other mapping types */ 3076 assert(FALSE); 3077 } 3078 3079 /* 3080 * Using NULL for u2w instead of 0 so that our trigger allows 3081 * the same pid to be the destination in multiple entries 3082 */ 3083 sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache " 3084 "(sidprefix, rid, windomain, canon_winname, pid, unixname, " 3085 "is_user, is_wuser, expiration, w2u, u2w, " 3086 "map_type, map_dn, map_attr, map_value, map_windomain, " 3087 "map_winname, map_unixname, map_is_nt4) " 3088 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, " 3089 "strftime('%%s','now') + 600, %q, 1, " 3090 "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d); ", 3091 res->id.idmap_id_u.sid.prefix, res->id.idmap_id_u.sid.rid, 3092 req->id2domain, req->id2name, req->id1.idmap_id_u.uid, 3093 req->id1name, (req->id1.idtype == IDMAP_UID) ? 1 : 0, 3094 (res->id.idtype == IDMAP_USID) ? 1 : 0, 3095 (res->direction == 0) ? "1" : NULL, 3096 res->info.how.map_type, map_dn, map_attr, map_value, 3097 map_windomain, map_winname, map_unixname, map_is_nt4); 3098 3099 if (sql == NULL) { 3100 retcode = IDMAP_ERR_INTERNAL; 3101 idmapdlog(LOG_ERR, "Out of memory"); 3102 goto out; 3103 } 3104 3105 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); 3106 if (retcode != IDMAP_SUCCESS) 3107 goto out; 3108 3109 state->pid2sid_done = FALSE; 3110 sqlite_freemem(sql); 3111 sql = NULL; 3112 3113 /* Check if we need to update namecache */ 3114 if (req->direction & _IDMAP_F_DONT_UPDATE_NAMECACHE) 3115 goto out; 3116 3117 if (req->id2name == NULL) 3118 goto out; 3119 3120 sql = sqlite_mprintf("INSERT OR REPLACE into name_cache " 3121 "(sidprefix, rid, canon_name, domain, type, expiration) " 3122 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ", 3123 res->id.idmap_id_u.sid.prefix, res->id.idmap_id_u.sid.rid, 3124 req->id2name, req->id2domain, 3125 (res->id.idtype == IDMAP_USID) ? _IDMAP_T_USER : _IDMAP_T_GROUP); 3126 3127 if (sql == NULL) { 3128 retcode = IDMAP_ERR_INTERNAL; 3129 idmapdlog(LOG_ERR, "Out of memory"); 3130 goto out; 3131 } 3132 3133 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); 3134 3135 out: 3136 if (!(req->flag & IDMAP_REQ_FLG_MAPPING_INFO)) 3137 idmap_info_free(&res->info); 3138 if (sql != NULL) 3139 sqlite_freemem(sql); 3140 return (retcode); 3141 } 3142 3143 idmap_retcode 3144 update_cache_sid2pid(lookup_state_t *state, 3145 idmap_mapping *req, idmap_id_res *res) 3146 { 3147 char *sql = NULL; 3148 idmap_retcode retcode; 3149 int is_eph_user; 3150 char *map_dn = NULL; 3151 char *map_attr = NULL; 3152 char *map_value = NULL; 3153 char *map_windomain = NULL; 3154 char *map_winname = NULL; 3155 char *map_unixname = NULL; 3156 int map_is_nt4 = FALSE; 3157 3158 /* Check if we need to cache anything */ 3159 if (ARE_WE_DONE(req->direction)) 3160 return (IDMAP_SUCCESS); 3161 3162 /* We don't cache negative entries */ 3163 if (res->retcode != IDMAP_SUCCESS) 3164 return (IDMAP_SUCCESS); 3165 3166 if (req->direction & _IDMAP_F_EXP_EPH_UID) 3167 is_eph_user = 1; 3168 else if (req->direction & _IDMAP_F_EXP_EPH_GID) 3169 is_eph_user = 0; 3170 else 3171 is_eph_user = -1; 3172 3173 if (is_eph_user >= 0 && !IS_EPHEMERAL(res->id.idmap_id_u.uid)) { 3174 sql = sqlite_mprintf("UPDATE idmap_cache " 3175 "SET w2u = 0 WHERE " 3176 "sidprefix = %Q AND rid = %u AND w2u = 1 AND " 3177 "pid >= 2147483648 AND is_user = %d;", 3178 req->id1.idmap_id_u.sid.prefix, 3179 req->id1.idmap_id_u.sid.rid, 3180 is_eph_user); 3181 if (sql == NULL) { 3182 retcode = IDMAP_ERR_INTERNAL; 3183 idmapdlog(LOG_ERR, "Out of memory"); 3184 goto out; 3185 } 3186 3187 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); 3188 if (retcode != IDMAP_SUCCESS) 3189 goto out; 3190 3191 sqlite_freemem(sql); 3192 sql = NULL; 3193 } 3194 3195 assert(res->direction != IDMAP_DIRECTION_UNDEF); 3196 assert(res->id.idmap_id_u.uid != SENTINEL_PID); 3197 3198 switch (res->info.how.map_type) { 3199 case IDMAP_MAP_TYPE_DS_AD: 3200 map_dn = res->info.how.idmap_how_u.ad.dn; 3201 map_attr = res->info.how.idmap_how_u.ad.attr; 3202 map_value = res->info.how.idmap_how_u.ad.value; 3203 break; 3204 3205 case IDMAP_MAP_TYPE_DS_NLDAP: 3206 map_dn = res->info.how.idmap_how_u.nldap.dn; 3207 map_attr = res->info.how.idmap_how_u.ad.attr; 3208 map_value = res->info.how.idmap_how_u.nldap.value; 3209 break; 3210 3211 case IDMAP_MAP_TYPE_RULE_BASED: 3212 map_windomain = res->info.how.idmap_how_u.rule.windomain; 3213 map_winname = res->info.how.idmap_how_u.rule.winname; 3214 map_unixname = res->info.how.idmap_how_u.rule.unixname; 3215 map_is_nt4 = res->info.how.idmap_how_u.rule.is_nt4; 3216 break; 3217 3218 case IDMAP_MAP_TYPE_EPHEMERAL: 3219 break; 3220 3221 default: 3222 /* Dont cache other mapping types */ 3223 assert(FALSE); 3224 } 3225 3226 sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache " 3227 "(sidprefix, rid, windomain, canon_winname, pid, unixname, " 3228 "is_user, is_wuser, expiration, w2u, u2w, " 3229 "map_type, map_dn, map_attr, map_value, map_windomain, " 3230 "map_winname, map_unixname, map_is_nt4) " 3231 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, " 3232 "strftime('%%s','now') + 600, 1, %q, " 3233 "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d);", 3234 req->id1.idmap_id_u.sid.prefix, req->id1.idmap_id_u.sid.rid, 3235 (req->id1domain != NULL) ? req->id1domain : "", req->id1name, 3236 res->id.idmap_id_u.uid, req->id2name, 3237 (res->id.idtype == IDMAP_UID) ? 1 : 0, 3238 (req->id1.idtype == IDMAP_USID) ? 1 : 0, 3239 (res->direction == 0) ? "1" : NULL, 3240 res->info.how.map_type, map_dn, map_attr, map_value, 3241 map_windomain, map_winname, map_unixname, map_is_nt4); 3242 3243 if (sql == NULL) { 3244 retcode = IDMAP_ERR_INTERNAL; 3245 idmapdlog(LOG_ERR, "Out of memory"); 3246 goto out; 3247 } 3248 3249 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); 3250 if (retcode != IDMAP_SUCCESS) 3251 goto out; 3252 3253 state->sid2pid_done = FALSE; 3254 sqlite_freemem(sql); 3255 sql = NULL; 3256 3257 /* Check if we need to update namecache */ 3258 if (req->direction & _IDMAP_F_DONT_UPDATE_NAMECACHE) 3259 goto out; 3260 3261 if (EMPTY_STRING(req->id1name)) 3262 goto out; 3263 3264 sql = sqlite_mprintf("INSERT OR REPLACE into name_cache " 3265 "(sidprefix, rid, canon_name, domain, type, expiration) " 3266 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ", 3267 req->id1.idmap_id_u.sid.prefix, req->id1.idmap_id_u.sid.rid, 3268 req->id1name, req->id1domain, 3269 (req->id1.idtype == IDMAP_USID) ? _IDMAP_T_USER : _IDMAP_T_GROUP); 3270 3271 if (sql == NULL) { 3272 retcode = IDMAP_ERR_INTERNAL; 3273 idmapdlog(LOG_ERR, "Out of memory"); 3274 goto out; 3275 } 3276 3277 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); 3278 3279 out: 3280 if (!(req->flag & IDMAP_REQ_FLG_MAPPING_INFO)) 3281 idmap_info_free(&res->info); 3282 3283 if (sql != NULL) 3284 sqlite_freemem(sql); 3285 return (retcode); 3286 } 3287 3288 static 3289 idmap_retcode 3290 lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res, 3291 int is_user, int getname) 3292 { 3293 char *end; 3294 char *sql = NULL; 3295 const char **values; 3296 sqlite_vm *vm = NULL; 3297 int ncol; 3298 idmap_retcode retcode = IDMAP_SUCCESS; 3299 time_t curtime; 3300 idmap_id_type idtype; 3301 3302 /* Current time */ 3303 errno = 0; 3304 if ((curtime = time(NULL)) == (time_t)-1) { 3305 idmapdlog(LOG_ERR, "Failed to get current time (%s)", 3306 strerror(errno)); 3307 retcode = IDMAP_ERR_INTERNAL; 3308 goto out; 3309 } 3310 3311 /* SQL to lookup the cache by pid or by unixname */ 3312 if (req->id1.idmap_id_u.uid != SENTINEL_PID) { 3313 sql = sqlite_mprintf("SELECT sidprefix, rid, " 3314 "canon_winname, windomain, w2u, is_wuser, " 3315 "map_type, map_dn, map_attr, map_value, map_windomain, " 3316 "map_winname, map_unixname, map_is_nt4 " 3317 "FROM idmap_cache WHERE " 3318 "pid = %u AND u2w = 1 AND is_user = %d AND " 3319 "(pid >= 2147483648 OR " 3320 "(expiration = 0 OR expiration ISNULL OR " 3321 "expiration > %d));", 3322 req->id1.idmap_id_u.uid, is_user, curtime); 3323 } else if (req->id1name != NULL) { 3324 sql = sqlite_mprintf("SELECT sidprefix, rid, " 3325 "canon_winname, windomain, w2u, is_wuser, " 3326 "map_type, map_dn, map_attr, map_value, map_windomain, " 3327 "map_winname, map_unixname, map_is_nt4 " 3328 "FROM idmap_cache WHERE " 3329 "unixname = %Q AND u2w = 1 AND is_user = %d AND " 3330 "(pid >= 2147483648 OR " 3331 "(expiration = 0 OR expiration ISNULL OR " 3332 "expiration > %d));", 3333 req->id1name, is_user, curtime); 3334 } else { 3335 retcode = IDMAP_ERR_ARG; 3336 goto out; 3337 } 3338 3339 if (sql == NULL) { 3340 idmapdlog(LOG_ERR, "Out of memory"); 3341 retcode = IDMAP_ERR_MEMORY; 3342 goto out; 3343 } 3344 retcode = sql_compile_n_step_once( 3345 cache, sql, &vm, &ncol, 14, &values); 3346 sqlite_freemem(sql); 3347 3348 if (retcode == IDMAP_ERR_NOTFOUND) 3349 goto out; 3350 else if (retcode == IDMAP_SUCCESS) { 3351 /* sanity checks */ 3352 if (values[0] == NULL || values[1] == NULL) { 3353 retcode = IDMAP_ERR_CACHE; 3354 goto out; 3355 } 3356 3357 switch (res->id.idtype) { 3358 case IDMAP_SID: 3359 case IDMAP_USID: 3360 case IDMAP_GSID: 3361 idtype = strtol(values[5], &end, 10) == 1 3362 ? IDMAP_USID : IDMAP_GSID; 3363 3364 if (res->id.idtype == IDMAP_USID && 3365 idtype != IDMAP_USID) { 3366 retcode = IDMAP_ERR_NOTUSER; 3367 goto out; 3368 } else if (res->id.idtype == IDMAP_GSID && 3369 idtype != IDMAP_GSID) { 3370 retcode = IDMAP_ERR_NOTGROUP; 3371 goto out; 3372 } 3373 res->id.idtype = idtype; 3374 3375 res->id.idmap_id_u.sid.rid = 3376 strtoul(values[1], &end, 10); 3377 res->id.idmap_id_u.sid.prefix = strdup(values[0]); 3378 if (res->id.idmap_id_u.sid.prefix == NULL) { 3379 idmapdlog(LOG_ERR, "Out of memory"); 3380 retcode = IDMAP_ERR_MEMORY; 3381 goto out; 3382 } 3383 3384 if (values[4] != NULL) 3385 res->direction = 3386 (strtol(values[4], &end, 10) == 0)? 3387 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; 3388 else 3389 res->direction = IDMAP_DIRECTION_U2W; 3390 3391 if (getname == 0 || values[2] == NULL) 3392 break; 3393 req->id2name = strdup(values[2]); 3394 if (req->id2name == NULL) { 3395 idmapdlog(LOG_ERR, "Out of memory"); 3396 retcode = IDMAP_ERR_MEMORY; 3397 goto out; 3398 } 3399 3400 if (values[3] == NULL) 3401 break; 3402 req->id2domain = strdup(values[3]); 3403 if (req->id2domain == NULL) { 3404 idmapdlog(LOG_ERR, "Out of memory"); 3405 retcode = IDMAP_ERR_MEMORY; 3406 goto out; 3407 } 3408 3409 break; 3410 default: 3411 retcode = IDMAP_ERR_NOTSUPPORTED; 3412 break; 3413 } 3414 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 3415 res->info.src = IDMAP_MAP_SRC_CACHE; 3416 res->info.how.map_type = strtoul(values[6], &end, 10); 3417 switch (res->info.how.map_type) { 3418 case IDMAP_MAP_TYPE_DS_AD: 3419 res->info.how.idmap_how_u.ad.dn = 3420 strdup(values[7]); 3421 res->info.how.idmap_how_u.ad.attr = 3422 strdup(values[8]); 3423 res->info.how.idmap_how_u.ad.value = 3424 strdup(values[9]); 3425 break; 3426 3427 case IDMAP_MAP_TYPE_DS_NLDAP: 3428 res->info.how.idmap_how_u.nldap.dn = 3429 strdup(values[7]); 3430 res->info.how.idmap_how_u.nldap.attr = 3431 strdup(values[8]); 3432 res->info.how.idmap_how_u.nldap.value = 3433 strdup(values[9]); 3434 break; 3435 3436 case IDMAP_MAP_TYPE_RULE_BASED: 3437 res->info.how.idmap_how_u.rule.windomain = 3438 strdup(values[10]); 3439 res->info.how.idmap_how_u.rule.winname = 3440 strdup(values[11]); 3441 res->info.how.idmap_how_u.rule.unixname = 3442 strdup(values[12]); 3443 res->info.how.idmap_how_u.rule.is_nt4 = 3444 strtoul(values[13], &end, 10); 3445 res->info.how.idmap_how_u.rule.is_user = 3446 is_user; 3447 res->info.how.idmap_how_u.rule.is_wuser = 3448 strtol(values[5], &end, 10); 3449 break; 3450 3451 case IDMAP_MAP_TYPE_EPHEMERAL: 3452 break; 3453 3454 case IDMAP_MAP_TYPE_LOCAL_SID: 3455 break; 3456 3457 case IDMAP_MAP_TYPE_KNOWN_SID: 3458 break; 3459 3460 default: 3461 /* Unknow mapping type */ 3462 assert(FALSE); 3463 } 3464 } 3465 } 3466 3467 out: 3468 if (vm != NULL) 3469 (void) sqlite_finalize(vm, NULL); 3470 return (retcode); 3471 } 3472 3473 static 3474 idmap_retcode 3475 lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain, 3476 char **canonname, char **sidprefix, idmap_rid_t *rid, int *type) 3477 { 3478 char *end, *lower_name; 3479 char *sql = NULL; 3480 const char **values; 3481 sqlite_vm *vm = NULL; 3482 int ncol; 3483 time_t curtime; 3484 idmap_retcode retcode = IDMAP_SUCCESS; 3485 3486 /* Get current time */ 3487 errno = 0; 3488 if ((curtime = time(NULL)) == (time_t)-1) { 3489 idmapdlog(LOG_ERR, "Failed to get current time (%s)", 3490 strerror(errno)); 3491 retcode = IDMAP_ERR_INTERNAL; 3492 goto out; 3493 } 3494 3495 /* SQL to lookup the cache */ 3496 if ((lower_name = tolower_u8(name)) == NULL) 3497 lower_name = (char *)name; 3498 sql = sqlite_mprintf("SELECT sidprefix, rid, type, canon_name " 3499 "FROM name_cache WHERE name = %Q AND domain = %Q AND " 3500 "(expiration = 0 OR expiration ISNULL OR " 3501 "expiration > %d);", lower_name, domain, curtime); 3502 if (lower_name != name) 3503 free(lower_name); 3504 if (sql == NULL) { 3505 idmapdlog(LOG_ERR, "Out of memory"); 3506 retcode = IDMAP_ERR_MEMORY; 3507 goto out; 3508 } 3509 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 4, &values); 3510 sqlite_freemem(sql); 3511 3512 if (retcode == IDMAP_SUCCESS) { 3513 if (type != NULL) { 3514 if (values[2] == NULL) { 3515 retcode = IDMAP_ERR_CACHE; 3516 goto out; 3517 } 3518 *type = strtol(values[2], &end, 10); 3519 } 3520 3521 if (values[0] == NULL || values[1] == NULL) { 3522 retcode = IDMAP_ERR_CACHE; 3523 goto out; 3524 } 3525 3526 if (canonname != NULL) { 3527 assert(values[3] != NULL); 3528 if ((*canonname = strdup(values[3])) == NULL) { 3529 idmapdlog(LOG_ERR, "Out of memory"); 3530 retcode = IDMAP_ERR_MEMORY; 3531 goto out; 3532 } 3533 } 3534 3535 if ((*sidprefix = strdup(values[0])) == NULL) { 3536 idmapdlog(LOG_ERR, "Out of memory"); 3537 retcode = IDMAP_ERR_MEMORY; 3538 if (canonname != NULL) { 3539 free(*canonname); 3540 *canonname = NULL; 3541 } 3542 goto out; 3543 } 3544 *rid = strtoul(values[1], &end, 10); 3545 } 3546 3547 out: 3548 if (vm != NULL) 3549 (void) sqlite_finalize(vm, NULL); 3550 return (retcode); 3551 } 3552 3553 static 3554 idmap_retcode 3555 ad_lookup_by_winname(lookup_state_t *state, 3556 const char *name, const char *domain, int eunixtype, 3557 char **dn, char **attr, char **value, char **canonname, 3558 char **sidprefix, idmap_rid_t *rid, int *wintype, 3559 char **unixname) 3560 { 3561 int retries = 0; 3562 idmap_query_state_t *qs = NULL; 3563 idmap_retcode rc, retcode; 3564 3565 retry: 3566 retcode = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs); 3567 if (retcode != IDMAP_SUCCESS) { 3568 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 3569 goto retry; 3570 degrade_svc(1, "failed to create request for AD lookup " 3571 "by winname"); 3572 return (retcode); 3573 } 3574 3575 restore_svc(); 3576 3577 if (state != NULL) 3578 idmap_lookup_batch_set_unixattr(qs, state->ad_unixuser_attr, 3579 state->ad_unixgroup_attr); 3580 3581 retcode = idmap_name2sid_batch_add1(qs, name, domain, eunixtype, 3582 dn, attr, value, canonname, sidprefix, rid, wintype, unixname, &rc); 3583 3584 if (retcode != IDMAP_SUCCESS) 3585 idmap_lookup_release_batch(&qs); 3586 else 3587 retcode = idmap_lookup_batch_end(&qs); 3588 3589 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 3590 goto retry; 3591 else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 3592 degrade_svc(1, "some AD lookups timed out repeatedly"); 3593 3594 if (retcode != IDMAP_SUCCESS) { 3595 idmapdlog(LOG_NOTICE, "AD lookup by winname failed"); 3596 return (retcode); 3597 } 3598 return (rc); 3599 } 3600 3601 idmap_retcode 3602 lookup_name2sid(sqlite *cache, const char *name, const char *domain, 3603 int *is_wuser, char **canonname, char **sidprefix, 3604 idmap_rid_t *rid, idmap_mapping *req, int local_only) 3605 { 3606 int type; 3607 idmap_retcode retcode; 3608 3609 *sidprefix = NULL; 3610 if (canonname != NULL) 3611 *canonname = NULL; 3612 3613 /* Lookup well-known SIDs table */ 3614 retcode = lookup_wksids_name2sid(name, canonname, sidprefix, rid, 3615 &type); 3616 if (retcode == IDMAP_SUCCESS) { 3617 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; 3618 goto out; 3619 } else if (retcode != IDMAP_ERR_NOTFOUND) { 3620 return (retcode); 3621 } 3622 3623 /* Lookup cache */ 3624 retcode = lookup_cache_name2sid(cache, name, domain, canonname, 3625 sidprefix, rid, &type); 3626 if (retcode == IDMAP_SUCCESS) { 3627 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; 3628 goto out; 3629 } else if (retcode != IDMAP_ERR_NOTFOUND) { 3630 return (retcode); 3631 } 3632 3633 /* 3634 * The caller may be using this function to determine if this 3635 * request needs to be marked for AD lookup or not 3636 * (i.e. _IDMAP_F_LOOKUP_AD) and therefore may not want this 3637 * function to AD lookup now. 3638 */ 3639 if (local_only) 3640 return (retcode); 3641 3642 /* Lookup AD */ 3643 retcode = ad_lookup_by_winname(NULL, name, domain, _IDMAP_T_UNDEF, 3644 NULL, NULL, NULL, canonname, sidprefix, rid, &type, NULL); 3645 if (retcode != IDMAP_SUCCESS) 3646 return (retcode); 3647 3648 out: 3649 /* 3650 * Entry found (cache or Windows lookup) 3651 * is_wuser is both input as well as output parameter 3652 */ 3653 if (*is_wuser == 1 && type != _IDMAP_T_USER) 3654 retcode = IDMAP_ERR_NOTUSER; 3655 else if (*is_wuser == 0 && type != _IDMAP_T_GROUP) 3656 retcode = IDMAP_ERR_NOTGROUP; 3657 else if (*is_wuser == -1) { 3658 /* Caller wants to know if its user or group */ 3659 if (type == _IDMAP_T_USER) 3660 *is_wuser = 1; 3661 else if (type == _IDMAP_T_GROUP) 3662 *is_wuser = 0; 3663 else 3664 retcode = IDMAP_ERR_SID; 3665 } 3666 3667 if (retcode != IDMAP_SUCCESS) { 3668 free(*sidprefix); 3669 *sidprefix = NULL; 3670 if (canonname != NULL) { 3671 free(*canonname); 3672 *canonname = NULL; 3673 } 3674 } 3675 return (retcode); 3676 } 3677 3678 static 3679 idmap_retcode 3680 name_based_mapping_pid2sid(lookup_state_t *state, const char *unixname, 3681 int is_user, idmap_mapping *req, idmap_id_res *res) 3682 { 3683 const char *winname, *windomain; 3684 char *canonname; 3685 char *sql = NULL, *errmsg = NULL; 3686 idmap_retcode retcode; 3687 char *end; 3688 const char **values; 3689 sqlite_vm *vm = NULL; 3690 int ncol, r; 3691 int is_wuser; 3692 const char *me = "name_based_mapping_pid2sid"; 3693 int non_wild_match = FALSE; 3694 idmap_namerule *rule = &res->info.how.idmap_how_u.rule; 3695 int direction; 3696 3697 assert(unixname != NULL); /* We have unixname */ 3698 assert(req->id2name == NULL); /* We don't have winname */ 3699 assert(res->id.idmap_id_u.sid.prefix == NULL); /* No SID either */ 3700 3701 sql = sqlite_mprintf( 3702 "SELECT winname_display, windomain, w2u_order, " 3703 "is_wuser, unixname, is_nt4 " 3704 "FROM namerules WHERE " 3705 "u2w_order > 0 AND is_user = %d AND " 3706 "(unixname = %Q OR unixname = '*') " 3707 "ORDER BY u2w_order ASC;", is_user, unixname); 3708 if (sql == NULL) { 3709 idmapdlog(LOG_ERR, "Out of memory"); 3710 retcode = IDMAP_ERR_MEMORY; 3711 goto out; 3712 } 3713 3714 if (sqlite_compile(state->db, sql, NULL, &vm, &errmsg) != SQLITE_OK) { 3715 retcode = IDMAP_ERR_INTERNAL; 3716 idmapdlog(LOG_ERR, "%s: database error (%s)", me, 3717 CHECK_NULL(errmsg)); 3718 sqlite_freemem(errmsg); 3719 goto out; 3720 } 3721 3722 for (;;) { 3723 r = sqlite_step(vm, &ncol, &values, NULL); 3724 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 3725 if (r == SQLITE_ROW) { 3726 if (ncol < 6) { 3727 retcode = IDMAP_ERR_INTERNAL; 3728 goto out; 3729 } 3730 if (values[0] == NULL) { 3731 /* values [1] and [2] can be null */ 3732 retcode = IDMAP_ERR_INTERNAL; 3733 goto out; 3734 } 3735 3736 if (values[2] != NULL) 3737 direction = 3738 (strtol(values[2], &end, 10) == 0)? 3739 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; 3740 else 3741 direction = IDMAP_DIRECTION_U2W; 3742 3743 if (EMPTY_NAME(values[0])) { 3744 idmap_namerule_set(rule, values[1], values[0], 3745 values[4], is_user, 3746 strtol(values[3], &end, 10), 3747 strtol(values[5], &end, 10), 3748 direction); 3749 retcode = IDMAP_ERR_NOMAPPING; 3750 goto out; 3751 } 3752 3753 if (values[0][0] == '*') { 3754 winname = unixname; 3755 if (non_wild_match) { 3756 /* 3757 * There were non-wildcard rules 3758 * where the Windows identity doesn't 3759 * exist. Return no mapping. 3760 */ 3761 retcode = IDMAP_ERR_NOMAPPING; 3762 goto out; 3763 } 3764 } else { 3765 /* Save first non-wild match rule */ 3766 if (!non_wild_match) { 3767 idmap_namerule_set(rule, values[1], 3768 values[0], values[4], 3769 is_user, 3770 strtol(values[3], &end, 10), 3771 strtol(values[5], &end, 10), 3772 direction); 3773 non_wild_match = TRUE; 3774 } 3775 winname = values[0]; 3776 } 3777 is_wuser = res->id.idtype == IDMAP_USID ? 1 3778 : res->id.idtype == IDMAP_GSID ? 0 3779 : -1; 3780 if (values[1] != NULL) 3781 windomain = values[1]; 3782 else if (state->defdom != NULL) 3783 windomain = state->defdom; 3784 else { 3785 idmapdlog(LOG_ERR, "%s: no domain", me); 3786 retcode = IDMAP_ERR_DOMAIN_NOTFOUND; 3787 goto out; 3788 } 3789 3790 retcode = lookup_name2sid(state->cache, 3791 winname, windomain, 3792 &is_wuser, &canonname, 3793 &res->id.idmap_id_u.sid.prefix, 3794 &res->id.idmap_id_u.sid.rid, req, 0); 3795 3796 if (retcode == IDMAP_ERR_NOTFOUND) { 3797 continue; 3798 } 3799 goto out; 3800 3801 } else if (r == SQLITE_DONE) { 3802 /* 3803 * If there were non-wildcard rules where 3804 * Windows identity doesn't exist 3805 * return no mapping. 3806 */ 3807 if (non_wild_match) 3808 retcode = IDMAP_ERR_NOMAPPING; 3809 else 3810 retcode = IDMAP_ERR_NOTFOUND; 3811 goto out; 3812 } else { 3813 (void) sqlite_finalize(vm, &errmsg); 3814 vm = NULL; 3815 idmapdlog(LOG_ERR, "%s: database error (%s)", me, 3816 CHECK_NULL(errmsg)); 3817 sqlite_freemem(errmsg); 3818 retcode = IDMAP_ERR_INTERNAL; 3819 goto out; 3820 } 3821 } 3822 3823 out: 3824 if (sql != NULL) 3825 sqlite_freemem(sql); 3826 res->info.how.map_type = IDMAP_MAP_TYPE_RULE_BASED; 3827 if (retcode == IDMAP_SUCCESS) { 3828 res->id.idtype = is_wuser ? IDMAP_USID : IDMAP_GSID; 3829 3830 if (values[2] != NULL) 3831 res->direction = 3832 (strtol(values[2], &end, 10) == 0)? 3833 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; 3834 else 3835 res->direction = IDMAP_DIRECTION_U2W; 3836 3837 req->id2name = canonname; 3838 if (req->id2name != NULL) { 3839 req->id2domain = strdup(windomain); 3840 if (req->id2domain == NULL) 3841 retcode = IDMAP_ERR_MEMORY; 3842 } 3843 } 3844 3845 if (retcode == IDMAP_SUCCESS) { 3846 idmap_namerule_set(rule, values[1], values[0], values[4], 3847 is_user, strtol(values[3], &end, 10), 3848 strtol(values[5], &end, 10), 3849 rule->direction); 3850 res->info.src = IDMAP_MAP_SRC_NEW; 3851 } 3852 if (vm != NULL) 3853 (void) sqlite_finalize(vm, NULL); 3854 return (retcode); 3855 } 3856 3857 /* 3858 * Convention when processing unix2win requests: 3859 * 3860 * Unix identity: 3861 * req->id1name = 3862 * unixname if given otherwise unixname found will be placed 3863 * here. 3864 * req->id1domain = 3865 * NOT USED 3866 * req->id1.idtype = 3867 * Given type (IDMAP_UID or IDMAP_GID) 3868 * req->id1..[uid or gid] = 3869 * UID/GID if given otherwise UID/GID found will be placed here. 3870 * 3871 * Windows identity: 3872 * req->id2name = 3873 * winname found will be placed here. 3874 * req->id2domain = 3875 * windomain found will be placed here. 3876 * res->id.idtype = 3877 * Target type initialized from req->id2.idtype. If 3878 * it is IDMAP_SID then actual type (IDMAP_USID/GSID) found 3879 * will be placed here. 3880 * req->id..sid.[prefix, rid] = 3881 * SID found will be placed here. 3882 * 3883 * Others: 3884 * res->retcode = 3885 * Return status for this request will be placed here. 3886 * res->direction = 3887 * Direction found will be placed here. Direction 3888 * meaning whether the resultant mapping is valid 3889 * only from unix2win or bi-directional. 3890 * req->direction = 3891 * INTERNAL USE. Used by idmapd to set various 3892 * flags (_IDMAP_F_xxxx) to aid in processing 3893 * of the request. 3894 * req->id2.idtype = 3895 * INTERNAL USE. Initially this is the requested target 3896 * type and is used to initialize res->id.idtype. 3897 * ad_lookup_batch() uses this field temporarily to store 3898 * sid_type obtained by the batched AD lookups and after 3899 * use resets it to IDMAP_NONE to prevent xdr from 3900 * mis-interpreting the contents of req->id2. 3901 * req->id2..[uid or gid or sid] = 3902 * NOT USED 3903 */ 3904 3905 /* 3906 * This function does the following: 3907 * 1. Lookup well-known SIDs table. 3908 * 2. Lookup cache. 3909 * 3. Check if the client does not want new mapping to be allocated 3910 * in which case this pass is the final pass. 3911 * 4. Set AD/NLDAP lookup flags if it determines that the next stage needs 3912 * to do AD/NLDAP lookup. 3913 */ 3914 idmap_retcode 3915 pid2sid_first_pass(lookup_state_t *state, idmap_mapping *req, 3916 idmap_id_res *res, int is_user, int getname) 3917 { 3918 idmap_retcode retcode; 3919 bool_t gen_localsid_on_err = FALSE; 3920 3921 /* Initialize result */ 3922 res->id.idtype = req->id2.idtype; 3923 res->direction = IDMAP_DIRECTION_UNDEF; 3924 3925 if (req->id2.idmap_id_u.sid.prefix != NULL) { 3926 /* sanitize sidprefix */ 3927 free(req->id2.idmap_id_u.sid.prefix); 3928 req->id2.idmap_id_u.sid.prefix = NULL; 3929 } 3930 3931 /* Find pid */ 3932 if (req->id1.idmap_id_u.uid == SENTINEL_PID) { 3933 if (ns_lookup_byname(req->id1name, NULL, &req->id1) 3934 != IDMAP_SUCCESS) { 3935 retcode = IDMAP_ERR_NOMAPPING; 3936 goto out; 3937 } 3938 } 3939 3940 /* Lookup well-known SIDs table */ 3941 retcode = lookup_wksids_pid2sid(req, res, is_user); 3942 if (retcode != IDMAP_ERR_NOTFOUND) 3943 goto out; 3944 3945 /* Lookup cache */ 3946 retcode = lookup_cache_pid2sid(state->cache, req, res, is_user, 3947 getname); 3948 if (retcode != IDMAP_ERR_NOTFOUND) 3949 goto out; 3950 3951 /* Ephemeral ids cannot be allocated during pid2sid */ 3952 if (IS_EPHEMERAL(req->id1.idmap_id_u.uid)) { 3953 retcode = IDMAP_ERR_NOMAPPING; 3954 goto out; 3955 } 3956 3957 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req)) { 3958 retcode = IDMAP_ERR_NONEGENERATED; 3959 goto out; 3960 } 3961 3962 if (AVOID_NAMESERVICE(req)) { 3963 gen_localsid_on_err = TRUE; 3964 retcode = IDMAP_ERR_NOMAPPING; 3965 goto out; 3966 } 3967 3968 /* Set flags for the next stage */ 3969 if (AD_MODE(req->id1.idtype, state)) { 3970 /* 3971 * If AD-based name mapping is enabled then the next stage 3972 * will need to lookup AD using unixname to get the 3973 * corresponding winname. 3974 */ 3975 if (req->id1name == NULL) { 3976 /* Get unixname if only pid is given. */ 3977 retcode = ns_lookup_bypid(req->id1.idmap_id_u.uid, 3978 is_user, &req->id1name); 3979 if (retcode != IDMAP_SUCCESS) { 3980 gen_localsid_on_err = TRUE; 3981 goto out; 3982 } 3983 } 3984 req->direction |= _IDMAP_F_LOOKUP_AD; 3985 state->ad_nqueries++; 3986 } else if (NLDAP_OR_MIXED_MODE(req->id1.idtype, state)) { 3987 /* 3988 * If native LDAP or mixed mode is enabled for name mapping 3989 * then the next stage will need to lookup native LDAP using 3990 * unixname/pid to get the corresponding winname. 3991 */ 3992 req->direction |= _IDMAP_F_LOOKUP_NLDAP; 3993 state->nldap_nqueries++; 3994 } 3995 3996 /* 3997 * Failed to find non-expired entry in cache. Set the flag to 3998 * indicate that we are not done yet. 3999 */ 4000 state->pid2sid_done = FALSE; 4001 req->direction |= _IDMAP_F_NOTDONE; 4002 retcode = IDMAP_SUCCESS; 4003 4004 out: 4005 res->retcode = idmap_stat4prot(retcode); 4006 if (ARE_WE_DONE(req->direction) && res->retcode != IDMAP_SUCCESS) 4007 if (gen_localsid_on_err == TRUE) 4008 (void) generate_localsid(req, res, is_user, TRUE); 4009 return (retcode); 4010 } 4011 4012 idmap_retcode 4013 pid2sid_second_pass(lookup_state_t *state, idmap_mapping *req, 4014 idmap_id_res *res, int is_user) 4015 { 4016 bool_t gen_localsid_on_err = TRUE; 4017 idmap_retcode retcode = IDMAP_SUCCESS; 4018 4019 /* Check if second pass is needed */ 4020 if (ARE_WE_DONE(req->direction)) 4021 return (res->retcode); 4022 4023 /* Get status from previous pass */ 4024 retcode = res->retcode; 4025 if (retcode != IDMAP_SUCCESS) 4026 goto out; 4027 4028 /* 4029 * If directory-based name mapping is enabled then the winname 4030 * may already have been retrieved from the AD object (AD-mode) 4031 * or from native LDAP object (nldap-mode or mixed-mode). 4032 * Note that if we have winname but no SID then it's an error 4033 * because this implies that the Native LDAP entry contains 4034 * winname which does not exist and it's better that we return 4035 * an error instead of doing rule-based mapping so that the user 4036 * can detect the issue and take appropriate action. 4037 */ 4038 if (req->id2name != NULL) { 4039 /* Return notfound if we've winname but no SID. */ 4040 if (res->id.idmap_id_u.sid.prefix == NULL) { 4041 retcode = IDMAP_ERR_NOTFOUND; 4042 goto out; 4043 } 4044 if (AD_MODE(req->id1.idtype, state)) 4045 res->direction = IDMAP_DIRECTION_BI; 4046 else if (NLDAP_MODE(req->id1.idtype, state)) 4047 res->direction = IDMAP_DIRECTION_BI; 4048 else if (MIXED_MODE(req->id1.idtype, state)) 4049 res->direction = IDMAP_DIRECTION_W2U; 4050 goto out; 4051 } else if (res->id.idmap_id_u.sid.prefix != NULL) { 4052 /* 4053 * We've SID but no winname. This is fine because 4054 * the caller may have only requested SID. 4055 */ 4056 goto out; 4057 } 4058 4059 /* Free any mapping info from Directory based mapping */ 4060 if (res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN) 4061 idmap_info_free(&res->info); 4062 4063 if (req->id1name == NULL) { 4064 /* Get unixname from name service */ 4065 retcode = ns_lookup_bypid(req->id1.idmap_id_u.uid, is_user, 4066 &req->id1name); 4067 if (retcode != IDMAP_SUCCESS) 4068 goto out; 4069 } else if (req->id1.idmap_id_u.uid == SENTINEL_PID) { 4070 /* Get pid from name service */ 4071 retcode = ns_lookup_byname(req->id1name, NULL, &req->id1); 4072 if (retcode != IDMAP_SUCCESS) { 4073 gen_localsid_on_err = FALSE; 4074 goto out; 4075 } 4076 } 4077 4078 /* Use unixname to evaluate local name-based mapping rules */ 4079 retcode = name_based_mapping_pid2sid(state, req->id1name, is_user, 4080 req, res); 4081 if (retcode == IDMAP_ERR_NOTFOUND) { 4082 retcode = generate_localsid(req, res, is_user, FALSE); 4083 gen_localsid_on_err = FALSE; 4084 } 4085 4086 out: 4087 res->retcode = idmap_stat4prot(retcode); 4088 if (res->retcode != IDMAP_SUCCESS) { 4089 req->direction = _IDMAP_F_DONE; 4090 free(req->id2name); 4091 req->id2name = NULL; 4092 free(req->id2domain); 4093 req->id2domain = NULL; 4094 if (gen_localsid_on_err == TRUE) 4095 (void) generate_localsid(req, res, is_user, TRUE); 4096 else 4097 res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID; 4098 } 4099 if (!ARE_WE_DONE(req->direction)) 4100 state->pid2sid_done = FALSE; 4101 return (retcode); 4102 } 4103 4104 static 4105 int 4106 copy_mapping_request(idmap_mapping *mapping, idmap_mapping *request) 4107 { 4108 (void) memset(mapping, 0, sizeof (*mapping)); 4109 4110 mapping->flag = request->flag; 4111 mapping->direction = _IDMAP_F_DONE; 4112 mapping->id2.idtype = request->id2.idtype; 4113 4114 mapping->id1.idtype = request->id1.idtype; 4115 if (IS_REQUEST_SID(*request, 1)) { 4116 mapping->id1.idmap_id_u.sid.rid = 4117 request->id1.idmap_id_u.sid.rid; 4118 if (!EMPTY_STRING(request->id1.idmap_id_u.sid.prefix)) { 4119 mapping->id1.idmap_id_u.sid.prefix = 4120 strdup(request->id1.idmap_id_u.sid.prefix); 4121 if (mapping->id1.idmap_id_u.sid.prefix == NULL) 4122 goto errout; 4123 } 4124 } else { 4125 mapping->id1.idmap_id_u.uid = request->id1.idmap_id_u.uid; 4126 } 4127 4128 if (!EMPTY_STRING(request->id1domain)) { 4129 mapping->id1domain = strdup(request->id1domain); 4130 if (mapping->id1domain == NULL) 4131 goto errout; 4132 } 4133 4134 if (!EMPTY_STRING(request->id1name)) { 4135 mapping->id1name = strdup(request->id1name); 4136 if (mapping->id1name == NULL) 4137 goto errout; 4138 } 4139 4140 /* We don't need the rest of the request i.e request->id2 */ 4141 return (0); 4142 4143 errout: 4144 if (mapping->id1.idmap_id_u.sid.prefix != NULL) 4145 free(mapping->id1.idmap_id_u.sid.prefix); 4146 if (mapping->id1domain != NULL) 4147 free(mapping->id1domain); 4148 if (mapping->id1name != NULL) 4149 free(mapping->id1name); 4150 4151 (void) memset(mapping, 0, sizeof (*mapping)); 4152 return (-1); 4153 } 4154 4155 4156 idmap_retcode 4157 get_w2u_mapping(sqlite *cache, sqlite *db, idmap_mapping *request, 4158 idmap_mapping *mapping) 4159 { 4160 idmap_id_res idres; 4161 lookup_state_t state; 4162 char *cp; 4163 idmap_retcode retcode; 4164 const char *winname, *windomain; 4165 4166 (void) memset(&idres, 0, sizeof (idres)); 4167 (void) memset(&state, 0, sizeof (state)); 4168 state.cache = cache; 4169 state.db = db; 4170 4171 /* Get directory-based name mapping info */ 4172 retcode = load_cfg_in_state(&state); 4173 if (retcode != IDMAP_SUCCESS) 4174 goto out; 4175 4176 /* 4177 * Copy data from "request" to "mapping". Note that 4178 * empty strings are not copied from "request" to 4179 * "mapping" and therefore the coresponding strings in 4180 * "mapping" will be NULL. This eliminates having to 4181 * check for empty strings henceforth. 4182 */ 4183 if (copy_mapping_request(mapping, request) < 0) { 4184 retcode = IDMAP_ERR_MEMORY; 4185 goto out; 4186 } 4187 4188 winname = mapping->id1name; 4189 windomain = mapping->id1domain; 4190 4191 if (winname == NULL && windomain != NULL) { 4192 retcode = IDMAP_ERR_ARG; 4193 goto out; 4194 } 4195 4196 /* Need atleast winname or sid to proceed */ 4197 if (winname == NULL && mapping->id1.idmap_id_u.sid.prefix == NULL) { 4198 retcode = IDMAP_ERR_ARG; 4199 goto out; 4200 } 4201 4202 /* 4203 * If domainname is not given but we have a fully qualified 4204 * winname then extract the domainname from the winname, 4205 * otherwise use the default_domain from the config 4206 */ 4207 if (winname != NULL && windomain == NULL) { 4208 retcode = IDMAP_SUCCESS; 4209 if ((cp = strchr(winname, '@')) != NULL) { 4210 *cp = '\0'; 4211 mapping->id1domain = strdup(cp + 1); 4212 if (mapping->id1domain == NULL) 4213 retcode = IDMAP_ERR_MEMORY; 4214 } else if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, 4215 NULL) != IDMAP_SUCCESS) { 4216 if (state.defdom == NULL) { 4217 /* 4218 * We have a non-qualified winname which is 4219 * neither the name of a well-known SID nor 4220 * there is a default domain with which we can 4221 * qualify it. 4222 */ 4223 retcode = IDMAP_ERR_DOMAIN_NOTFOUND; 4224 } else { 4225 mapping->id1domain = strdup(state.defdom); 4226 if (mapping->id1domain == NULL) 4227 retcode = IDMAP_ERR_MEMORY; 4228 } 4229 } 4230 if (retcode != IDMAP_SUCCESS) 4231 goto out; 4232 } 4233 4234 /* 4235 * First pass looks up the well-known SIDs table and cache 4236 * and handles localSIDs 4237 */ 4238 state.sid2pid_done = TRUE; 4239 retcode = sid2pid_first_pass(&state, mapping, &idres); 4240 if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE) 4241 goto out; 4242 4243 /* AD lookup */ 4244 if (state.ad_nqueries > 0) { 4245 retcode = ad_lookup_one(&state, mapping, &idres); 4246 if (IDMAP_ERROR(retcode)) 4247 goto out; 4248 } 4249 4250 /* nldap lookup */ 4251 if (state.nldap_nqueries > 0) { 4252 retcode = nldap_lookup_one(&state, mapping, &idres); 4253 if (IDMAP_FATAL_ERROR(retcode)) 4254 goto out; 4255 } 4256 4257 /* Next pass performs name-based mapping and ephemeral mapping. */ 4258 state.sid2pid_done = TRUE; 4259 retcode = sid2pid_second_pass(&state, mapping, &idres); 4260 if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE) 4261 goto out; 4262 4263 /* Update cache */ 4264 (void) update_cache_sid2pid(&state, mapping, &idres); 4265 4266 out: 4267 /* 4268 * Note that "mapping" is returned to the client. Therefore 4269 * copy whatever we have in "idres" to mapping->id2 and 4270 * free idres. 4271 */ 4272 mapping->direction = idres.direction; 4273 mapping->id2 = idres.id; 4274 if (mapping->flag & IDMAP_REQ_FLG_MAPPING_INFO || 4275 retcode != IDMAP_SUCCESS) 4276 (void) idmap_info_mov(&mapping->info, &idres.info); 4277 else 4278 idmap_info_free(&idres.info); 4279 (void) memset(&idres, 0, sizeof (idres)); 4280 if (retcode != IDMAP_SUCCESS) 4281 mapping->id2.idmap_id_u.uid = UID_NOBODY; 4282 xdr_free(xdr_idmap_id_res, (caddr_t)&idres); 4283 cleanup_lookup_state(&state); 4284 return (retcode); 4285 } 4286 4287 idmap_retcode 4288 get_u2w_mapping(sqlite *cache, sqlite *db, idmap_mapping *request, 4289 idmap_mapping *mapping, int is_user) 4290 { 4291 idmap_id_res idres; 4292 lookup_state_t state; 4293 idmap_retcode retcode; 4294 4295 /* 4296 * In order to re-use the pid2sid code, we convert 4297 * our input data into structs that are expected by 4298 * pid2sid_first_pass. 4299 */ 4300 4301 (void) memset(&idres, 0, sizeof (idres)); 4302 (void) memset(&state, 0, sizeof (state)); 4303 state.cache = cache; 4304 state.db = db; 4305 4306 /* Get directory-based name mapping info */ 4307 retcode = load_cfg_in_state(&state); 4308 if (retcode != IDMAP_SUCCESS) 4309 goto out; 4310 4311 /* 4312 * Copy data from "request" to "mapping". Note that 4313 * empty strings are not copied from "request" to 4314 * "mapping" and therefore the coresponding strings in 4315 * "mapping" will be NULL. This eliminates having to 4316 * check for empty strings henceforth. 4317 */ 4318 if (copy_mapping_request(mapping, request) < 0) { 4319 retcode = IDMAP_ERR_MEMORY; 4320 goto out; 4321 } 4322 4323 /* 4324 * For unix to windows mapping request, we need atleast a 4325 * unixname or uid/gid to proceed 4326 */ 4327 if (mapping->id1name == NULL && 4328 mapping->id1.idmap_id_u.uid == SENTINEL_PID) { 4329 retcode = IDMAP_ERR_ARG; 4330 goto out; 4331 } 4332 4333 /* First pass looks up cache and well-known SIDs */ 4334 state.pid2sid_done = TRUE; 4335 retcode = pid2sid_first_pass(&state, mapping, &idres, is_user, 1); 4336 if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE) 4337 goto out; 4338 4339 /* nldap lookup */ 4340 if (state.nldap_nqueries > 0) { 4341 retcode = nldap_lookup_one(&state, mapping, &idres); 4342 if (IDMAP_FATAL_ERROR(retcode)) 4343 goto out; 4344 } 4345 4346 /* AD lookup */ 4347 if (state.ad_nqueries > 0) { 4348 retcode = ad_lookup_one(&state, mapping, &idres); 4349 if (IDMAP_FATAL_ERROR(retcode)) 4350 goto out; 4351 } 4352 4353 /* 4354 * Next pass processes the result of the preceding passes/lookups. 4355 * It returns if there's nothing more to be done otherwise it 4356 * evaluates local name-based mapping rules 4357 */ 4358 state.pid2sid_done = TRUE; 4359 retcode = pid2sid_second_pass(&state, mapping, &idres, is_user); 4360 if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE) 4361 goto out; 4362 4363 /* Update cache */ 4364 (void) update_cache_pid2sid(&state, mapping, &idres); 4365 4366 out: 4367 /* 4368 * Note that "mapping" is returned to the client. Therefore 4369 * copy whatever we have in "idres" to mapping->id2 and 4370 * free idres. 4371 */ 4372 mapping->direction = idres.direction; 4373 mapping->id2 = idres.id; 4374 if (mapping->flag & IDMAP_REQ_FLG_MAPPING_INFO || 4375 retcode != IDMAP_SUCCESS) 4376 (void) idmap_info_mov(&mapping->info, &idres.info); 4377 else 4378 idmap_info_free(&idres.info); 4379 (void) memset(&idres, 0, sizeof (idres)); 4380 xdr_free(xdr_idmap_id_res, (caddr_t)&idres); 4381 cleanup_lookup_state(&state); 4382 return (retcode); 4383 } 4384 4385 /*ARGSUSED*/ 4386 static 4387 idmap_retcode 4388 ad_lookup_one(lookup_state_t *state, idmap_mapping *req, idmap_id_res *res) 4389 { 4390 idmap_mapping_batch batch; 4391 idmap_ids_res result; 4392 4393 batch.idmap_mapping_batch_len = 1; 4394 batch.idmap_mapping_batch_val = req; 4395 result.ids.ids_len = 1; 4396 result.ids.ids_val = res; 4397 return (ad_lookup_batch(state, &batch, &result)); 4398 } 4399