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 state->eph_map_unres_sids = 0; 1081 if (_idmapdstate.cfg->pgcfg.eph_map_unres_sids) 1082 state->eph_map_unres_sids = 1; 1083 1084 if (_idmapdstate.cfg->pgcfg.default_domain != NULL) { 1085 state->defdom = 1086 strdup(_idmapdstate.cfg->pgcfg.default_domain); 1087 if (state->defdom == NULL) { 1088 UNLOCK_CONFIG(); 1089 return (IDMAP_ERR_MEMORY); 1090 } 1091 } else { 1092 UNLOCK_CONFIG(); 1093 return (IDMAP_SUCCESS); 1094 } 1095 if (_idmapdstate.cfg->pgcfg.ds_name_mapping_enabled == FALSE) { 1096 UNLOCK_CONFIG(); 1097 return (IDMAP_SUCCESS); 1098 } 1099 if (_idmapdstate.cfg->pgcfg.nldap_winname_attr != NULL) { 1100 state->nm_siduid = 1101 (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL) 1102 ? IDMAP_NM_MIXED : IDMAP_NM_NLDAP; 1103 state->nm_sidgid = 1104 (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL) 1105 ? IDMAP_NM_MIXED : IDMAP_NM_NLDAP; 1106 } else { 1107 state->nm_siduid = 1108 (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL) 1109 ? IDMAP_NM_AD : IDMAP_NM_NONE; 1110 state->nm_sidgid = 1111 (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL) 1112 ? IDMAP_NM_AD : IDMAP_NM_NONE; 1113 } 1114 if (_idmapdstate.cfg->pgcfg.ad_unixuser_attr != NULL) { 1115 state->ad_unixuser_attr = 1116 strdup(_idmapdstate.cfg->pgcfg.ad_unixuser_attr); 1117 if (state->ad_unixuser_attr == NULL) { 1118 UNLOCK_CONFIG(); 1119 return (IDMAP_ERR_MEMORY); 1120 } 1121 } 1122 if (_idmapdstate.cfg->pgcfg.ad_unixgroup_attr != NULL) { 1123 state->ad_unixgroup_attr = 1124 strdup(_idmapdstate.cfg->pgcfg.ad_unixgroup_attr); 1125 if (state->ad_unixgroup_attr == NULL) { 1126 UNLOCK_CONFIG(); 1127 return (IDMAP_ERR_MEMORY); 1128 } 1129 } 1130 if (_idmapdstate.cfg->pgcfg.nldap_winname_attr != NULL) { 1131 state->nldap_winname_attr = 1132 strdup(_idmapdstate.cfg->pgcfg.nldap_winname_attr); 1133 if (state->nldap_winname_attr == NULL) { 1134 UNLOCK_CONFIG(); 1135 return (IDMAP_ERR_MEMORY); 1136 } 1137 } 1138 UNLOCK_CONFIG(); 1139 return (IDMAP_SUCCESS); 1140 } 1141 1142 /* 1143 * Set the rule with sepecified values. 1144 * All the strings are copied. 1145 */ 1146 static void 1147 idmap_namerule_set(idmap_namerule *rule, const char *windomain, 1148 const char *winname, const char *unixname, boolean_t is_user, 1149 boolean_t is_wuser, boolean_t is_nt4, int direction) 1150 { 1151 /* 1152 * Only update if they differ because we have to free 1153 * and duplicate the strings 1154 */ 1155 if (rule->windomain == NULL || windomain == NULL || 1156 strcmp(rule->windomain, windomain) != 0) { 1157 if (rule->windomain != NULL) { 1158 free(rule->windomain); 1159 rule->windomain = NULL; 1160 } 1161 if (windomain != NULL) 1162 rule->windomain = strdup(windomain); 1163 } 1164 1165 if (rule->winname == NULL || winname == NULL || 1166 strcmp(rule->winname, winname) != 0) { 1167 if (rule->winname != NULL) { 1168 free(rule->winname); 1169 rule->winname = NULL; 1170 } 1171 if (winname != NULL) 1172 rule->winname = strdup(winname); 1173 } 1174 1175 if (rule->unixname == NULL || unixname == NULL || 1176 strcmp(rule->unixname, unixname) != 0) { 1177 if (rule->unixname != NULL) { 1178 free(rule->unixname); 1179 rule->unixname = NULL; 1180 } 1181 if (unixname != NULL) 1182 rule->unixname = strdup(unixname); 1183 } 1184 1185 rule->is_user = is_user; 1186 rule->is_wuser = is_wuser; 1187 rule->is_nt4 = is_nt4; 1188 rule->direction = direction; 1189 } 1190 1191 1192 /* 1193 * Table for well-known SIDs. 1194 * 1195 * Background: 1196 * 1197 * Some of the well-known principals are stored under: 1198 * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain> 1199 * They belong to objectClass "foreignSecurityPrincipal". They don't have 1200 * "samAccountName" nor "userPrincipalName" attributes. Their names are 1201 * available in "cn" and "name" attributes. Some of these principals have a 1202 * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and 1203 * these duplicate entries have the stringified SID in the "name" and "cn" 1204 * attributes instead of the actual name. 1205 * 1206 * Those of the form S-1-5-32-X are Builtin groups and are stored in the 1207 * cn=builtin container (except, Power Users which is not stored in AD) 1208 * 1209 * These principals are and will remain constant. Therefore doing AD lookups 1210 * provides no benefit. Also, using hard-coded table (and thus avoiding AD 1211 * lookup) improves performance and avoids additional complexity in the 1212 * adutils.c code. Moreover these SIDs can be used when no Active Directory 1213 * is available (such as the CIFS server's "workgroup" mode). 1214 * 1215 * Notes: 1216 * 1. Currently we don't support localization of well-known SID names, 1217 * unlike Windows. 1218 * 1219 * 2. Other well-known SIDs i.e. S-1-5-<domain>-<w-k RID> are not stored 1220 * here. AD does have normal user/group objects for these objects and 1221 * can be looked up using the existing AD lookup code. 1222 * 1223 * 3. See comments above lookup_wksids_sid2pid() for more information 1224 * on how we lookup the wksids table. 1225 */ 1226 static wksids_table_t wksids[] = { 1227 {"S-1-0", 0, "Nobody", 0, SENTINEL_PID, -1, 1}, 1228 {"S-1-1", 0, "Everyone", 0, SENTINEL_PID, -1, -1}, 1229 {"S-1-3", 0, "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 1, 0}, 1230 {"S-1-3", 1, "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0, 0}, 1231 {"S-1-3", 2, "Creator Owner Server", 1, SENTINEL_PID, -1, -1}, 1232 {"S-1-3", 3, "Creator Group Server", 0, SENTINEL_PID, -1, 1}, 1233 {"S-1-3", 4, "Owner Rights", 0, SENTINEL_PID, -1, -1}, 1234 {"S-1-5", 1, "Dialup", 0, SENTINEL_PID, -1, -1}, 1235 {"S-1-5", 2, "Network", 0, SENTINEL_PID, -1, -1}, 1236 {"S-1-5", 3, "Batch", 0, SENTINEL_PID, -1, -1}, 1237 {"S-1-5", 4, "Interactive", 0, SENTINEL_PID, -1, -1}, 1238 {"S-1-5", 6, "Service", 0, SENTINEL_PID, -1, -1}, 1239 {"S-1-5", 7, "Anonymous Logon", 0, GID_NOBODY, 0, 0}, 1240 {"S-1-5", 7, "Anonymous Logon", 0, UID_NOBODY, 1, 0}, 1241 {"S-1-5", 8, "Proxy", 0, SENTINEL_PID, -1, -1}, 1242 {"S-1-5", 9, "Enterprise Domain Controllers", 0, SENTINEL_PID, -1, -1}, 1243 {"S-1-5", 10, "Self", 0, SENTINEL_PID, -1, -1}, 1244 {"S-1-5", 11, "Authenticated Users", 0, SENTINEL_PID, -1, -1}, 1245 {"S-1-5", 12, "Restricted Code", 0, SENTINEL_PID, -1, -1}, 1246 {"S-1-5", 13, "Terminal Server User", 0, SENTINEL_PID, -1, -1}, 1247 {"S-1-5", 14, "Remote Interactive Logon", 0, SENTINEL_PID, -1, -1}, 1248 {"S-1-5", 15, "This Organization", 0, SENTINEL_PID, -1, -1}, 1249 {"S-1-5", 17, "IUSR", 0, SENTINEL_PID, -1, -1}, 1250 {"S-1-5", 18, "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0, 0}, 1251 {"S-1-5", 19, "Local Service", 0, SENTINEL_PID, -1, -1}, 1252 {"S-1-5", 20, "Network Service", 0, SENTINEL_PID, -1, -1}, 1253 {"S-1-5", 1000, "Other Organization", 0, SENTINEL_PID, -1, -1}, 1254 {"S-1-5-32", 544, "Administrators", 0, SENTINEL_PID, -1, -1}, 1255 {"S-1-5-32", 545, "Users", 0, SENTINEL_PID, -1, -1}, 1256 {"S-1-5-32", 546, "Guests", 0, SENTINEL_PID, -1, -1}, 1257 {"S-1-5-32", 547, "Power Users", 0, SENTINEL_PID, -1, -1}, 1258 {"S-1-5-32", 548, "Account Operators", 0, SENTINEL_PID, -1, -1}, 1259 {"S-1-5-32", 549, "Server Operators", 0, SENTINEL_PID, -1, -1}, 1260 {"S-1-5-32", 550, "Print Operators", 0, SENTINEL_PID, -1, -1}, 1261 {"S-1-5-32", 551, "Backup Operators", 0, SENTINEL_PID, -1, -1}, 1262 {"S-1-5-32", 552, "Replicator", 0, SENTINEL_PID, -1, -1}, 1263 {"S-1-5-32", 554, "Pre-Windows 2000 Compatible Access", 0, 1264 SENTINEL_PID, -1, -1}, 1265 {"S-1-5-32", 555, "Remote Desktop Users", 0, SENTINEL_PID, -1, -1}, 1266 {"S-1-5-32", 556, "Network Configuration Operators", 0, 1267 SENTINEL_PID, -1, -1}, 1268 {"S-1-5-32", 557, "Incoming Forest Trust Builders", 0, 1269 SENTINEL_PID, -1, -1}, 1270 {"S-1-5-32", 558, "Performance Monitor Users", 0, SENTINEL_PID, -1, -1}, 1271 {"S-1-5-32", 559, "Performance Log Users", 0, SENTINEL_PID, -1, -1}, 1272 {"S-1-5-32", 560, "Windows Authorization Access Group", 0, 1273 SENTINEL_PID, -1, -1}, 1274 {"S-1-5-32", 561, "Terminal Server License Servers", 0, 1275 SENTINEL_PID, -1, -1}, 1276 {"S-1-5-32", 561, "Distributed COM Users", 0, SENTINEL_PID, -1, -1}, 1277 {"S-1-5-32", 568, "IIS_IUSRS", 0, SENTINEL_PID, -1, -1}, 1278 {"S-1-5-32", 569, "Cryptographic Operators", 0, SENTINEL_PID, -1, -1}, 1279 {"S-1-5-32", 573, "Event Log Readers", 0, SENTINEL_PID, -1, -1}, 1280 {"S-1-5-32", 574, "Certificate Service DCOM Access", 0, 1281 SENTINEL_PID, -1, -1}, 1282 {"S-1-5-64", 21, "Digest Authentication", 0, SENTINEL_PID, -1, -1}, 1283 {"S-1-5-64", 10, "NTLM Authentication", 0, SENTINEL_PID, -1, -1}, 1284 {"S-1-5-64", 14, "SChannel Authentication", 0, SENTINEL_PID, -1, -1}, 1285 {NULL, UINT32_MAX, NULL, -1, SENTINEL_PID, -1, -1} 1286 }; 1287 1288 /* 1289 * Lookup well-known SIDs table either by winname or by SID. 1290 * If the given winname or SID is a well-known SID then we set wksid 1291 * variable and then proceed to see if the SID has a hard mapping to 1292 * a particular UID/GID (Ex: Creator Owner/Creator Group mapped to 1293 * fixed ephemeral ids). If we find such mapping then we return 1294 * success otherwise notfound. If a well-known SID is mapped to 1295 * SENTINEL_PID and the direction field is set (bi-directional or 1296 * win2unix) then we treat it as inhibited mapping and return no 1297 * mapping (Ex. S-1-0-0). 1298 */ 1299 static 1300 idmap_retcode 1301 lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res, int *wksid) 1302 { 1303 int i; 1304 1305 *wksid = 0; 1306 1307 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1308 if (req->id1.idmap_id_u.sid.prefix != NULL) { 1309 if ((strcasecmp(wksids[i].sidprefix, 1310 req->id1.idmap_id_u.sid.prefix) != 0) || 1311 wksids[i].rid != req->id1.idmap_id_u.sid.rid) 1312 /* this is not our SID */ 1313 continue; 1314 if (req->id1name == NULL) { 1315 req->id1name = strdup(wksids[i].winname); 1316 if (req->id1name == NULL) 1317 return (IDMAP_ERR_MEMORY); 1318 } 1319 } else if (req->id1name != NULL) { 1320 if (strcasecmp(wksids[i].winname, req->id1name) != 0) 1321 /* this is not our winname */ 1322 continue; 1323 req->id1.idmap_id_u.sid.prefix = 1324 strdup(wksids[i].sidprefix); 1325 if (req->id1.idmap_id_u.sid.prefix == NULL) 1326 return (IDMAP_ERR_MEMORY); 1327 req->id1.idmap_id_u.sid.rid = wksids[i].rid; 1328 } 1329 1330 *wksid = 1; 1331 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; 1332 1333 req->id1.idtype = (wksids[i].is_wuser) ? 1334 IDMAP_USID : IDMAP_GSID; 1335 1336 if (wksids[i].pid == SENTINEL_PID) { 1337 if (wksids[i].direction == IDMAP_DIRECTION_BI || 1338 wksids[i].direction == IDMAP_DIRECTION_W2U) 1339 /* Inhibited */ 1340 return (IDMAP_ERR_NOMAPPING); 1341 /* Not mapped */ 1342 if (res->id.idtype == IDMAP_POSIXID) { 1343 res->id.idtype = 1344 (wksids[i].is_wuser) ? 1345 IDMAP_UID : IDMAP_GID; 1346 } 1347 return (IDMAP_ERR_NOTFOUND); 1348 } else if (wksids[i].direction == IDMAP_DIRECTION_U2W) 1349 continue; 1350 1351 switch (res->id.idtype) { 1352 case IDMAP_UID: 1353 if (wksids[i].is_user == 0) 1354 continue; 1355 res->id.idmap_id_u.uid = wksids[i].pid; 1356 res->direction = wksids[i].direction; 1357 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 1358 res->info.how.map_type = 1359 IDMAP_MAP_TYPE_KNOWN_SID; 1360 res->info.src = IDMAP_MAP_SRC_HARD_CODED; 1361 } 1362 return (IDMAP_SUCCESS); 1363 case IDMAP_GID: 1364 if (wksids[i].is_user == 1) 1365 continue; 1366 res->id.idmap_id_u.gid = wksids[i].pid; 1367 res->direction = wksids[i].direction; 1368 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 1369 res->info.how.map_type = 1370 IDMAP_MAP_TYPE_KNOWN_SID; 1371 res->info.src = IDMAP_MAP_SRC_HARD_CODED; 1372 } 1373 return (IDMAP_SUCCESS); 1374 case IDMAP_POSIXID: 1375 res->id.idmap_id_u.uid = wksids[i].pid; 1376 res->id.idtype = (!wksids[i].is_user) ? 1377 IDMAP_GID : IDMAP_UID; 1378 res->direction = wksids[i].direction; 1379 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 1380 res->info.how.map_type = 1381 IDMAP_MAP_TYPE_KNOWN_SID; 1382 res->info.src = IDMAP_MAP_SRC_HARD_CODED; 1383 } 1384 return (IDMAP_SUCCESS); 1385 default: 1386 return (IDMAP_ERR_NOTSUPPORTED); 1387 } 1388 } 1389 return (IDMAP_ERR_NOTFOUND); 1390 } 1391 1392 1393 static 1394 idmap_retcode 1395 lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user) 1396 { 1397 int i; 1398 if (req->id1.idmap_id_u.uid == SENTINEL_PID) 1399 return (IDMAP_ERR_NOTFOUND); 1400 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1401 if (wksids[i].pid == req->id1.idmap_id_u.uid && 1402 wksids[i].is_user == is_user && 1403 wksids[i].direction != IDMAP_DIRECTION_W2U) { 1404 if (res->id.idtype == IDMAP_SID) { 1405 res->id.idtype = (wksids[i].is_wuser) ? 1406 IDMAP_USID : IDMAP_GSID; 1407 } 1408 res->id.idmap_id_u.sid.rid = wksids[i].rid; 1409 res->id.idmap_id_u.sid.prefix = 1410 strdup(wksids[i].sidprefix); 1411 if (res->id.idmap_id_u.sid.prefix == NULL) { 1412 idmapdlog(LOG_ERR, "Out of memory"); 1413 return (IDMAP_ERR_MEMORY); 1414 } 1415 res->direction = wksids[i].direction; 1416 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 1417 res->info.how.map_type = 1418 IDMAP_MAP_TYPE_KNOWN_SID; 1419 res->info.src = IDMAP_MAP_SRC_HARD_CODED; 1420 } 1421 return (IDMAP_SUCCESS); 1422 } 1423 } 1424 return (IDMAP_ERR_NOTFOUND); 1425 } 1426 1427 idmap_retcode 1428 lookup_wksids_name2sid(const char *name, char **canonname, char **sidprefix, 1429 idmap_rid_t *rid, int *type) 1430 { 1431 int i; 1432 1433 if ((strncasecmp(name, "BUILTIN\\", 8) == 0) || 1434 (strncasecmp(name, "BUILTIN/", 8) == 0)) 1435 name += 8; 1436 1437 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1438 if (strcasecmp(wksids[i].winname, name) != 0) 1439 continue; 1440 if (sidprefix != NULL && 1441 (*sidprefix = strdup(wksids[i].sidprefix)) == NULL) { 1442 idmapdlog(LOG_ERR, "Out of memory"); 1443 return (IDMAP_ERR_MEMORY); 1444 } 1445 if (canonname != NULL && 1446 (*canonname = strdup(wksids[i].winname)) == NULL) { 1447 idmapdlog(LOG_ERR, "Out of memory"); 1448 if (sidprefix != NULL) { 1449 free(*sidprefix); 1450 *sidprefix = NULL; 1451 } 1452 return (IDMAP_ERR_MEMORY); 1453 } 1454 if (type != NULL) 1455 *type = (wksids[i].is_wuser) ? 1456 _IDMAP_T_USER : _IDMAP_T_GROUP; 1457 if (rid != NULL) 1458 *rid = wksids[i].rid; 1459 return (IDMAP_SUCCESS); 1460 } 1461 return (IDMAP_ERR_NOTFOUND); 1462 } 1463 1464 static 1465 idmap_retcode 1466 lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res) 1467 { 1468 char *end; 1469 char *sql = NULL; 1470 const char **values; 1471 sqlite_vm *vm = NULL; 1472 int ncol, is_user; 1473 uid_t pid; 1474 time_t curtime, exp; 1475 idmap_retcode retcode; 1476 char *is_user_string, *lower_name; 1477 1478 /* Current time */ 1479 errno = 0; 1480 if ((curtime = time(NULL)) == (time_t)-1) { 1481 idmapdlog(LOG_ERR, "Failed to get current time (%s)", 1482 strerror(errno)); 1483 retcode = IDMAP_ERR_INTERNAL; 1484 goto out; 1485 } 1486 1487 switch (res->id.idtype) { 1488 case IDMAP_UID: 1489 is_user_string = "1"; 1490 break; 1491 case IDMAP_GID: 1492 is_user_string = "0"; 1493 break; 1494 case IDMAP_POSIXID: 1495 /* the non-diagonal mapping */ 1496 is_user_string = "is_wuser"; 1497 break; 1498 default: 1499 retcode = IDMAP_ERR_NOTSUPPORTED; 1500 goto out; 1501 } 1502 1503 /* SQL to lookup the cache */ 1504 1505 if (req->id1.idmap_id_u.sid.prefix != NULL) { 1506 sql = sqlite_mprintf("SELECT pid, is_user, expiration, " 1507 "unixname, u2w, is_wuser, " 1508 "map_type, map_dn, map_attr, map_value, " 1509 "map_windomain, map_winname, map_unixname, map_is_nt4 " 1510 "FROM idmap_cache WHERE is_user = %s AND " 1511 "sidprefix = %Q AND rid = %u AND w2u = 1 AND " 1512 "(pid >= 2147483648 OR " 1513 "(expiration = 0 OR expiration ISNULL OR " 1514 "expiration > %d));", 1515 is_user_string, req->id1.idmap_id_u.sid.prefix, 1516 req->id1.idmap_id_u.sid.rid, curtime); 1517 } else if (req->id1name != NULL) { 1518 if ((lower_name = tolower_u8(req->id1name)) == NULL) 1519 lower_name = req->id1name; 1520 sql = sqlite_mprintf("SELECT pid, is_user, expiration, " 1521 "unixname, u2w, is_wuser, " 1522 "map_type, map_dn, map_attr, map_value, " 1523 "map_windomain, map_winname, map_unixname, map_is_nt4 " 1524 "FROM idmap_cache WHERE is_user = %s AND " 1525 "winname = %Q AND windomain = %Q AND w2u = 1 AND " 1526 "(pid >= 2147483648 OR " 1527 "(expiration = 0 OR expiration ISNULL OR " 1528 "expiration > %d));", 1529 is_user_string, lower_name, req->id1domain, 1530 curtime); 1531 if (lower_name != req->id1name) 1532 free(lower_name); 1533 } else { 1534 retcode = IDMAP_ERR_ARG; 1535 goto out; 1536 } 1537 if (sql == NULL) { 1538 idmapdlog(LOG_ERR, "Out of memory"); 1539 retcode = IDMAP_ERR_MEMORY; 1540 goto out; 1541 } 1542 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 1543 14, &values); 1544 sqlite_freemem(sql); 1545 1546 if (retcode == IDMAP_ERR_NOTFOUND) { 1547 goto out; 1548 } else if (retcode == IDMAP_SUCCESS) { 1549 /* sanity checks */ 1550 if (values[0] == NULL || values[1] == NULL) { 1551 retcode = IDMAP_ERR_CACHE; 1552 goto out; 1553 } 1554 1555 pid = strtoul(values[0], &end, 10); 1556 is_user = strncmp(values[1], "0", 2) ? 1 : 0; 1557 1558 if (is_user) { 1559 res->id.idtype = IDMAP_UID; 1560 res->id.idmap_id_u.uid = pid; 1561 } else { 1562 res->id.idtype = IDMAP_GID; 1563 res->id.idmap_id_u.gid = pid; 1564 } 1565 1566 /* 1567 * We may have an expired ephemeral mapping. Consider 1568 * the expired entry as valid if we are not going to 1569 * perform name-based mapping. But do not renew the 1570 * expiration. 1571 * If we will be doing name-based mapping then store the 1572 * ephemeral pid in the result so that we can use it 1573 * if we end up doing dynamic mapping again. 1574 */ 1575 if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) && 1576 !AVOID_NAMESERVICE(req) && 1577 IS_EPHEMERAL(pid) && values[2] != NULL) { 1578 exp = strtoll(values[2], &end, 10); 1579 if (exp && exp <= curtime) { 1580 /* Store the ephemeral pid */ 1581 res->direction = IDMAP_DIRECTION_BI; 1582 req->direction |= is_user 1583 ? _IDMAP_F_EXP_EPH_UID 1584 : _IDMAP_F_EXP_EPH_GID; 1585 retcode = IDMAP_ERR_NOTFOUND; 1586 } 1587 } 1588 } 1589 1590 out: 1591 if (retcode == IDMAP_SUCCESS) { 1592 if (values[4] != NULL) 1593 res->direction = 1594 (strtol(values[4], &end, 10) == 0)? 1595 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; 1596 else 1597 res->direction = IDMAP_DIRECTION_W2U; 1598 1599 if (values[3] != NULL) { 1600 if (req->id2name != NULL) 1601 free(req->id2name); 1602 req->id2name = strdup(values[3]); 1603 if (req->id2name == NULL) { 1604 idmapdlog(LOG_ERR, "Out of memory"); 1605 retcode = IDMAP_ERR_MEMORY; 1606 } 1607 } 1608 1609 req->id1.idtype = strncmp(values[5], "0", 2) ? 1610 IDMAP_USID : IDMAP_GSID; 1611 1612 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 1613 res->info.src = IDMAP_MAP_SRC_CACHE; 1614 res->info.how.map_type = strtoul(values[6], &end, 10); 1615 switch (res->info.how.map_type) { 1616 case IDMAP_MAP_TYPE_DS_AD: 1617 res->info.how.idmap_how_u.ad.dn = 1618 strdup(values[7]); 1619 res->info.how.idmap_how_u.ad.attr = 1620 strdup(values[8]); 1621 res->info.how.idmap_how_u.ad.value = 1622 strdup(values[9]); 1623 break; 1624 1625 case IDMAP_MAP_TYPE_DS_NLDAP: 1626 res->info.how.idmap_how_u.nldap.dn = 1627 strdup(values[7]); 1628 res->info.how.idmap_how_u.nldap.attr = 1629 strdup(values[8]); 1630 res->info.how.idmap_how_u.nldap.value = 1631 strdup(values[9]); 1632 break; 1633 1634 case IDMAP_MAP_TYPE_RULE_BASED: 1635 res->info.how.idmap_how_u.rule.windomain = 1636 strdup(values[10]); 1637 res->info.how.idmap_how_u.rule.winname = 1638 strdup(values[11]); 1639 res->info.how.idmap_how_u.rule.unixname = 1640 strdup(values[12]); 1641 res->info.how.idmap_how_u.rule.is_nt4 = 1642 strtoul(values[13], &end, 1); 1643 res->info.how.idmap_how_u.rule.is_user = 1644 is_user; 1645 res->info.how.idmap_how_u.rule.is_wuser = 1646 strtoul(values[5], &end, 1); 1647 break; 1648 1649 case IDMAP_MAP_TYPE_EPHEMERAL: 1650 break; 1651 1652 case IDMAP_MAP_TYPE_LOCAL_SID: 1653 break; 1654 1655 case IDMAP_MAP_TYPE_KNOWN_SID: 1656 break; 1657 1658 default: 1659 /* Unknow mapping type */ 1660 assert(FALSE); 1661 } 1662 } 1663 } 1664 if (vm != NULL) 1665 (void) sqlite_finalize(vm, NULL); 1666 return (retcode); 1667 } 1668 1669 static 1670 idmap_retcode 1671 lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid, 1672 char **name, char **domain, int *type) 1673 { 1674 char *end; 1675 char *sql = NULL; 1676 const char **values; 1677 sqlite_vm *vm = NULL; 1678 int ncol; 1679 time_t curtime; 1680 idmap_retcode retcode = IDMAP_SUCCESS; 1681 1682 /* Get current time */ 1683 errno = 0; 1684 if ((curtime = time(NULL)) == (time_t)-1) { 1685 idmapdlog(LOG_ERR, "Failed to get current time (%s)", 1686 strerror(errno)); 1687 retcode = IDMAP_ERR_INTERNAL; 1688 goto out; 1689 } 1690 1691 /* SQL to lookup the cache */ 1692 sql = sqlite_mprintf("SELECT canon_name, domain, type " 1693 "FROM name_cache WHERE " 1694 "sidprefix = %Q AND rid = %u AND " 1695 "(expiration = 0 OR expiration ISNULL OR " 1696 "expiration > %d);", 1697 sidprefix, rid, curtime); 1698 if (sql == NULL) { 1699 idmapdlog(LOG_ERR, "Out of memory"); 1700 retcode = IDMAP_ERR_MEMORY; 1701 goto out; 1702 } 1703 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values); 1704 sqlite_freemem(sql); 1705 1706 if (retcode == IDMAP_SUCCESS) { 1707 if (type != NULL) { 1708 if (values[2] == NULL) { 1709 retcode = IDMAP_ERR_CACHE; 1710 goto out; 1711 } 1712 *type = strtol(values[2], &end, 10); 1713 } 1714 1715 if (name != NULL && values[0] != NULL) { 1716 if ((*name = strdup(values[0])) == NULL) { 1717 idmapdlog(LOG_ERR, "Out of memory"); 1718 retcode = IDMAP_ERR_MEMORY; 1719 goto out; 1720 } 1721 } 1722 1723 if (domain != NULL && values[1] != NULL) { 1724 if ((*domain = strdup(values[1])) == NULL) { 1725 if (name != NULL && *name) { 1726 free(*name); 1727 *name = NULL; 1728 } 1729 idmapdlog(LOG_ERR, "Out of memory"); 1730 retcode = IDMAP_ERR_MEMORY; 1731 goto out; 1732 } 1733 } 1734 } 1735 1736 out: 1737 if (vm != NULL) 1738 (void) sqlite_finalize(vm, NULL); 1739 return (retcode); 1740 } 1741 1742 /* 1743 * Given SID, find winname using name_cache OR 1744 * Given winname, find SID using name_cache. 1745 * Used when mapping win to unix i.e. req->id1 is windows id and 1746 * req->id2 is unix id 1747 */ 1748 static 1749 idmap_retcode 1750 lookup_name_cache(sqlite *cache, idmap_mapping *req, idmap_id_res *res) 1751 { 1752 int type = -1; 1753 idmap_retcode retcode; 1754 char *sidprefix = NULL; 1755 idmap_rid_t rid; 1756 char *name = NULL, *domain = NULL; 1757 1758 /* Done if we've both sid and winname */ 1759 if (req->id1.idmap_id_u.sid.prefix != NULL && req->id1name != NULL) 1760 return (IDMAP_SUCCESS); 1761 1762 /* Lookup sid to winname */ 1763 if (req->id1.idmap_id_u.sid.prefix != NULL) { 1764 retcode = lookup_cache_sid2name(cache, 1765 req->id1.idmap_id_u.sid.prefix, 1766 req->id1.idmap_id_u.sid.rid, &name, &domain, &type); 1767 goto out; 1768 } 1769 1770 /* Lookup winame to sid */ 1771 retcode = lookup_cache_name2sid(cache, req->id1name, req->id1domain, 1772 &name, &sidprefix, &rid, &type); 1773 1774 out: 1775 if (retcode != IDMAP_SUCCESS) { 1776 free(name); 1777 free(domain); 1778 free(sidprefix); 1779 return (retcode); 1780 } 1781 1782 if (res->id.idtype == IDMAP_POSIXID) { 1783 res->id.idtype = (type == _IDMAP_T_USER) ? 1784 IDMAP_UID : IDMAP_GID; 1785 } 1786 req->id1.idtype = (type == _IDMAP_T_USER) ? 1787 IDMAP_USID : IDMAP_GSID; 1788 1789 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; 1790 if (name != NULL) { 1791 free(req->id1name); /* Free existing winname */ 1792 req->id1name = name; /* and use canonical name instead */ 1793 } 1794 if (req->id1domain == NULL) 1795 req->id1domain = domain; 1796 if (req->id1.idmap_id_u.sid.prefix == NULL) { 1797 req->id1.idmap_id_u.sid.prefix = sidprefix; 1798 req->id1.idmap_id_u.sid.rid = rid; 1799 } 1800 return (retcode); 1801 } 1802 1803 /* 1804 * Batch AD lookups 1805 */ 1806 idmap_retcode 1807 ad_lookup_batch(lookup_state_t *state, idmap_mapping_batch *batch, 1808 idmap_ids_res *result) 1809 { 1810 idmap_retcode retcode; 1811 int i, add, type, is_wuser, is_user; 1812 int retries = 0, eunixtype; 1813 char **unixname; 1814 idmap_mapping *req; 1815 idmap_id_res *res; 1816 idmap_query_state_t *qs = NULL; 1817 idmap_how *how; 1818 char **dn, **attr, **value; 1819 1820 /* 1821 * Since req->id2.idtype is unused, we will use it here 1822 * to retrieve the value of sid_type. But it needs to be 1823 * reset to IDMAP_NONE before we return to prevent xdr 1824 * from mis-interpreting req->id2 when it tries to free 1825 * the input argument. Other option is to allocate an 1826 * array of integers and use it instead for the batched 1827 * call. But why un-necessarily allocate memory. That may 1828 * be an option if req->id2.idtype cannot be re-used in 1829 * future. 1830 */ 1831 1832 if (state->ad_nqueries == 0) 1833 return (IDMAP_SUCCESS); 1834 1835 for (i = 0; i < batch->idmap_mapping_batch_len; i++) { 1836 req = &batch->idmap_mapping_batch_val[i]; 1837 res = &result->ids.ids_val[i]; 1838 1839 /* Skip if not marked for AD lookup or already in error. */ 1840 if (!(req->direction & _IDMAP_F_LOOKUP_AD) || 1841 res->retcode != IDMAP_SUCCESS) 1842 continue; 1843 1844 /* Init status */ 1845 res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 1846 } 1847 1848 retry: 1849 retcode = idmap_lookup_batch_start(_idmapdstate.ad, state->ad_nqueries, 1850 &qs); 1851 if (retcode != IDMAP_SUCCESS) { 1852 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 1853 goto retry; 1854 degrade_svc(1, "failed to create batch for AD lookup"); 1855 goto out; 1856 } 1857 1858 restore_svc(); 1859 1860 idmap_lookup_batch_set_unixattr(qs, state->ad_unixuser_attr, 1861 state->ad_unixgroup_attr); 1862 1863 for (i = 0, add = 0; i < batch->idmap_mapping_batch_len; i++) { 1864 req = &batch->idmap_mapping_batch_val[i]; 1865 res = &result->ids.ids_val[i]; 1866 how = &res->info.how; 1867 1868 retcode = IDMAP_SUCCESS; 1869 req->id2.idtype = IDMAP_NONE; 1870 1871 /* Skip if not marked for AD lookup */ 1872 if (!(req->direction & _IDMAP_F_LOOKUP_AD)) 1873 continue; 1874 1875 if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR) 1876 continue; 1877 1878 if (IS_REQUEST_SID(*req, 1)) { 1879 1880 /* win2unix request: */ 1881 1882 unixname = dn = attr = value = NULL; 1883 eunixtype = _IDMAP_T_UNDEF; 1884 if (req->id2name == NULL) { 1885 if (res->id.idtype == IDMAP_UID && 1886 AD_OR_MIXED(state->nm_siduid)) { 1887 eunixtype = _IDMAP_T_USER; 1888 unixname = &req->id2name; 1889 } else if (res->id.idtype == IDMAP_GID && 1890 AD_OR_MIXED(state->nm_sidgid)) { 1891 eunixtype = _IDMAP_T_GROUP; 1892 unixname = &req->id2name; 1893 } else if (AD_OR_MIXED(state->nm_siduid) || 1894 AD_OR_MIXED(state->nm_sidgid)) { 1895 unixname = &req->id2name; 1896 } 1897 } 1898 add = 1; 1899 if (unixname != NULL) { 1900 /* 1901 * Get how info for DS-based name 1902 * mapping only if AD or MIXED 1903 * mode is enabled. 1904 */ 1905 idmap_info_free(&res->info); 1906 res->info.src = IDMAP_MAP_SRC_NEW; 1907 how->map_type = IDMAP_MAP_TYPE_DS_AD; 1908 dn = &how->idmap_how_u.ad.dn; 1909 attr = &how->idmap_how_u.ad.attr; 1910 value = &how->idmap_how_u.ad.value; 1911 } 1912 if (req->id1.idmap_id_u.sid.prefix != NULL) { 1913 /* Lookup AD by SID */ 1914 retcode = idmap_sid2name_batch_add1( 1915 qs, req->id1.idmap_id_u.sid.prefix, 1916 &req->id1.idmap_id_u.sid.rid, eunixtype, 1917 dn, attr, value, 1918 (req->id1name == NULL) ? 1919 &req->id1name : NULL, 1920 (req->id1domain == NULL) ? 1921 &req->id1domain : NULL, 1922 (int *)&req->id2.idtype, unixname, 1923 &res->retcode); 1924 } else { 1925 /* Lookup AD by winname */ 1926 assert(req->id1name != NULL); 1927 retcode = idmap_name2sid_batch_add1( 1928 qs, req->id1name, req->id1domain, 1929 eunixtype, 1930 dn, attr, value, 1931 &req->id1name, 1932 &req->id1.idmap_id_u.sid.prefix, 1933 &req->id1.idmap_id_u.sid.rid, 1934 (int *)&req->id2.idtype, unixname, 1935 &res->retcode); 1936 } 1937 1938 } else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) { 1939 1940 /* unix2win request: */ 1941 1942 if (res->id.idmap_id_u.sid.prefix != NULL && 1943 req->id2name != NULL) { 1944 /* Already have SID and winname -- done */ 1945 res->retcode = IDMAP_SUCCESS; 1946 continue; 1947 } 1948 1949 if (res->id.idmap_id_u.sid.prefix != NULL) { 1950 /* 1951 * SID but no winname -- lookup AD by 1952 * SID to get winname. 1953 * how info is not needed here because 1954 * we are not retrieving unixname from 1955 * AD. 1956 */ 1957 add = 1; 1958 retcode = idmap_sid2name_batch_add1( 1959 qs, res->id.idmap_id_u.sid.prefix, 1960 &res->id.idmap_id_u.sid.rid, 1961 _IDMAP_T_UNDEF, 1962 NULL, NULL, NULL, 1963 &req->id2name, 1964 &req->id2domain, (int *)&req->id2.idtype, 1965 NULL, &res->retcode); 1966 } else if (req->id2name != NULL) { 1967 /* 1968 * winname but no SID -- lookup AD by 1969 * winname to get SID. 1970 * how info is not needed here because 1971 * we are not retrieving unixname from 1972 * AD. 1973 */ 1974 add = 1; 1975 retcode = idmap_name2sid_batch_add1( 1976 qs, req->id2name, req->id2domain, 1977 _IDMAP_T_UNDEF, 1978 NULL, NULL, NULL, NULL, 1979 &res->id.idmap_id_u.sid.prefix, 1980 &res->id.idmap_id_u.sid.rid, 1981 (int *)&req->id2.idtype, NULL, 1982 &res->retcode); 1983 } else if (req->id1name != NULL) { 1984 /* 1985 * No SID and no winname but we've unixname -- 1986 * lookup AD by unixname to get SID. 1987 */ 1988 is_user = (IS_REQUEST_UID(*req)) ? 1 : 0; 1989 if (res->id.idtype == IDMAP_USID) 1990 is_wuser = 1; 1991 else if (res->id.idtype == IDMAP_GSID) 1992 is_wuser = 0; 1993 else 1994 is_wuser = is_user; 1995 add = 1; 1996 idmap_info_free(&res->info); 1997 res->info.src = IDMAP_MAP_SRC_NEW; 1998 how->map_type = IDMAP_MAP_TYPE_DS_AD; 1999 retcode = idmap_unixname2sid_batch_add1( 2000 qs, req->id1name, is_user, is_wuser, 2001 &how->idmap_how_u.ad.dn, 2002 &how->idmap_how_u.ad.attr, 2003 &how->idmap_how_u.ad.value, 2004 &res->id.idmap_id_u.sid.prefix, 2005 &res->id.idmap_id_u.sid.rid, 2006 &req->id2name, &req->id2domain, 2007 (int *)&req->id2.idtype, &res->retcode); 2008 } 2009 } 2010 if (retcode != IDMAP_SUCCESS) { 2011 idmap_lookup_release_batch(&qs); 2012 break; 2013 } 2014 } 2015 2016 if (retcode == IDMAP_SUCCESS) { 2017 /* add keeps track if we added an entry to the batch */ 2018 if (add) 2019 retcode = idmap_lookup_batch_end(&qs); 2020 else 2021 idmap_lookup_release_batch(&qs); 2022 } 2023 2024 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 2025 goto retry; 2026 else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 2027 degrade_svc(1, "some AD lookups timed out repeatedly"); 2028 2029 if (retcode != IDMAP_SUCCESS) 2030 idmapdlog(LOG_NOTICE, "Failed to batch AD lookup requests"); 2031 2032 out: 2033 /* 2034 * This loop does the following: 2035 * 1. Reset _IDMAP_F_LOOKUP_AD flag from the request. 2036 * 2. Reset req->id2.idtype to IDMAP_NONE 2037 * 3. If batch_start or batch_add failed then set the status 2038 * of each request marked for AD lookup to that error. 2039 * 4. Evaluate the type of the AD object (i.e. user or group) and 2040 * update the idtype in request. 2041 */ 2042 for (i = 0; i < batch->idmap_mapping_batch_len; i++) { 2043 req = &batch->idmap_mapping_batch_val[i]; 2044 type = req->id2.idtype; 2045 req->id2.idtype = IDMAP_NONE; 2046 res = &result->ids.ids_val[i]; 2047 how = &res->info.how; 2048 if (!(req->direction & _IDMAP_F_LOOKUP_AD)) 2049 continue; 2050 2051 /* Reset AD lookup flag */ 2052 req->direction &= ~(_IDMAP_F_LOOKUP_AD); 2053 2054 /* 2055 * If batch_start or batch_add failed then set the status 2056 * of each request marked for AD lookup to that error. 2057 */ 2058 if (retcode != IDMAP_SUCCESS) { 2059 res->retcode = retcode; 2060 continue; 2061 } 2062 2063 if (!add) 2064 continue; 2065 2066 if (res->retcode == IDMAP_ERR_NOTFOUND) { 2067 /* Nothing found - remove the preset info */ 2068 idmap_info_free(&res->info); 2069 } 2070 2071 if (IS_REQUEST_SID(*req, 1)) { 2072 if (res->retcode != IDMAP_SUCCESS) 2073 continue; 2074 /* Evaluate result type */ 2075 switch (type) { 2076 case _IDMAP_T_USER: 2077 if (res->id.idtype == IDMAP_POSIXID) 2078 res->id.idtype = IDMAP_UID; 2079 req->id1.idtype = IDMAP_USID; 2080 break; 2081 case _IDMAP_T_GROUP: 2082 if (res->id.idtype == IDMAP_POSIXID) 2083 res->id.idtype = IDMAP_GID; 2084 req->id1.idtype = IDMAP_GSID; 2085 break; 2086 default: 2087 res->retcode = IDMAP_ERR_SID; 2088 break; 2089 } 2090 if (res->retcode == IDMAP_SUCCESS && 2091 req->id1name != NULL && 2092 (req->id2name == NULL || 2093 res->id.idmap_id_u.uid == SENTINEL_PID) && 2094 NLDAP_MODE(res->id.idtype, state)) { 2095 req->direction |= _IDMAP_F_LOOKUP_NLDAP; 2096 state->nldap_nqueries++; 2097 } 2098 } else if (IS_REQUEST_UID(*req) || IS_REQUEST_GID(*req)) { 2099 if (res->retcode != IDMAP_SUCCESS) { 2100 if ((!(IDMAP_FATAL_ERROR(res->retcode))) && 2101 res->id.idmap_id_u.sid.prefix == NULL && 2102 req->id2name == NULL && /* no winname */ 2103 req->id1name != NULL) /* unixname */ 2104 /* 2105 * If AD lookup by unixname failed 2106 * with non fatal error then clear 2107 * the error (i.e set res->retcode 2108 * to success). This allows the next 2109 * pass to process other mapping 2110 * mechanisms for this request. 2111 */ 2112 res->retcode = IDMAP_SUCCESS; 2113 continue; 2114 } 2115 /* Evaluate result type */ 2116 switch (type) { 2117 case _IDMAP_T_USER: 2118 if (res->id.idtype == IDMAP_SID) 2119 res->id.idtype = IDMAP_USID; 2120 break; 2121 case _IDMAP_T_GROUP: 2122 if (res->id.idtype == IDMAP_SID) 2123 res->id.idtype = IDMAP_GSID; 2124 break; 2125 default: 2126 res->retcode = IDMAP_ERR_SID; 2127 break; 2128 } 2129 } 2130 } 2131 2132 /* AD lookups done. Reset state->ad_nqueries and return */ 2133 state->ad_nqueries = 0; 2134 return (retcode); 2135 } 2136 2137 /* 2138 * Convention when processing win2unix requests: 2139 * 2140 * Windows identity: 2141 * req->id1name = 2142 * winname if given otherwise winname found will be placed 2143 * here. 2144 * req->id1domain = 2145 * windomain if given otherwise windomain found will be 2146 * placed here. 2147 * req->id1.idtype = 2148 * Either IDMAP_SID/USID/GSID. If this is IDMAP_SID then it'll 2149 * be set to IDMAP_USID/GSID depending upon whether the 2150 * given SID is user or group respectively. The user/group-ness 2151 * is determined either when looking up well-known SIDs table OR 2152 * if the SID is found in namecache OR by ad_lookup_one() OR by 2153 * ad_lookup_batch(). 2154 * req->id1..sid.[prefix, rid] = 2155 * SID if given otherwise SID found will be placed here. 2156 * 2157 * Unix identity: 2158 * req->id2name = 2159 * unixname found will be placed here. 2160 * req->id2domain = 2161 * NOT USED 2162 * res->id.idtype = 2163 * Target type initialized from req->id2.idtype. If 2164 * it is IDMAP_POSIXID then actual type (IDMAP_UID/GID) found 2165 * will be placed here. 2166 * res->id..[uid or gid] = 2167 * UID/GID found will be placed here. 2168 * 2169 * Others: 2170 * res->retcode = 2171 * Return status for this request will be placed here. 2172 * res->direction = 2173 * Direction found will be placed here. Direction 2174 * meaning whether the resultant mapping is valid 2175 * only from win2unix or bi-directional. 2176 * req->direction = 2177 * INTERNAL USE. Used by idmapd to set various 2178 * flags (_IDMAP_F_xxxx) to aid in processing 2179 * of the request. 2180 * req->id2.idtype = 2181 * INTERNAL USE. Initially this is the requested target 2182 * type and is used to initialize res->id.idtype. 2183 * ad_lookup_batch() uses this field temporarily to store 2184 * sid_type obtained by the batched AD lookups and after 2185 * use resets it to IDMAP_NONE to prevent xdr from 2186 * mis-interpreting the contents of req->id2. 2187 * req->id2..[uid or gid or sid] = 2188 * NOT USED 2189 */ 2190 2191 /* 2192 * This function does the following: 2193 * 1. Lookup well-known SIDs table. 2194 * 2. Check if the given SID is a local-SID and if so extract UID/GID from it. 2195 * 3. Lookup cache. 2196 * 4. Check if the client does not want new mapping to be allocated 2197 * in which case this pass is the final pass. 2198 * 5. Set AD lookup flag if it determines that the next stage needs 2199 * to do AD lookup. 2200 */ 2201 idmap_retcode 2202 sid2pid_first_pass(lookup_state_t *state, idmap_mapping *req, 2203 idmap_id_res *res) 2204 { 2205 idmap_retcode retcode; 2206 int wksid; 2207 2208 /* Initialize result */ 2209 res->id.idtype = req->id2.idtype; 2210 res->id.idmap_id_u.uid = SENTINEL_PID; 2211 res->direction = IDMAP_DIRECTION_UNDEF; 2212 wksid = 0; 2213 2214 if (EMPTY_STRING(req->id1.idmap_id_u.sid.prefix)) { 2215 if (req->id1name == NULL) { 2216 retcode = IDMAP_ERR_ARG; 2217 goto out; 2218 } 2219 /* sanitize sidprefix */ 2220 free(req->id1.idmap_id_u.sid.prefix); 2221 req->id1.idmap_id_u.sid.prefix = NULL; 2222 } 2223 2224 /* Lookup well-known SIDs table */ 2225 retcode = lookup_wksids_sid2pid(req, res, &wksid); 2226 if (retcode != IDMAP_ERR_NOTFOUND) 2227 goto out; 2228 2229 /* Check if this is a localsid */ 2230 if (!wksid) { 2231 retcode = lookup_localsid2pid(req, res); 2232 if (retcode != IDMAP_ERR_NOTFOUND) 2233 goto out; 2234 } 2235 2236 /* Lookup cache */ 2237 retcode = lookup_cache_sid2pid(state->cache, req, res); 2238 if (retcode != IDMAP_ERR_NOTFOUND) 2239 goto out; 2240 2241 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) { 2242 retcode = IDMAP_ERR_NONEGENERATED; 2243 goto out; 2244 } 2245 2246 /* 2247 * Failed to find non-expired entry in cache. Next step is 2248 * to determine if this request needs to be batched for AD lookup. 2249 * 2250 * At this point we have either sid or winname or both. If we don't 2251 * have both then lookup name_cache for the sid or winname 2252 * whichever is missing. If not found then this request will be 2253 * batched for AD lookup. 2254 */ 2255 retcode = lookup_name_cache(state->cache, req, res); 2256 if (retcode != IDMAP_SUCCESS && retcode != IDMAP_ERR_NOTFOUND) 2257 goto out; 2258 2259 /* 2260 * Set the flag to indicate that we are not done yet so that 2261 * subsequent passes considers this request for name-based 2262 * mapping and ephemeral mapping. 2263 */ 2264 state->sid2pid_done = FALSE; 2265 req->direction |= _IDMAP_F_NOTDONE; 2266 2267 /* 2268 * Even if we have both sid and winname, we still may need to batch 2269 * this request for AD lookup if we don't have unixname and 2270 * directory-based name mapping (AD or mixed) is enabled. 2271 * We avoid AD lookup for well-known SIDs because they don't have 2272 * regular AD objects. 2273 */ 2274 if (retcode != IDMAP_SUCCESS || 2275 (!wksid && req->id2name == NULL && 2276 AD_OR_MIXED_MODE(res->id.idtype, state))) { 2277 retcode = IDMAP_SUCCESS; 2278 req->direction |= _IDMAP_F_LOOKUP_AD; 2279 state->ad_nqueries++; 2280 } else if (NLDAP_MODE(res->id.idtype, state)) { 2281 req->direction |= _IDMAP_F_LOOKUP_NLDAP; 2282 state->nldap_nqueries++; 2283 } 2284 2285 2286 out: 2287 res->retcode = idmap_stat4prot(retcode); 2288 /* 2289 * If we are done and there was an error then set fallback pid 2290 * in the result. 2291 */ 2292 if (ARE_WE_DONE(req->direction) && res->retcode != IDMAP_SUCCESS) 2293 res->id.idmap_id_u.uid = UID_NOBODY; 2294 return (retcode); 2295 } 2296 2297 /* 2298 * Generate SID using the following convention 2299 * <machine-sid-prefix>-<1000 + uid> 2300 * <machine-sid-prefix>-<2^31 + gid> 2301 */ 2302 static 2303 idmap_retcode 2304 generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user, 2305 int fallback) 2306 { 2307 free(res->id.idmap_id_u.sid.prefix); 2308 res->id.idmap_id_u.sid.prefix = NULL; 2309 2310 /* 2311 * Diagonal mapping for localSIDs not supported because of the 2312 * way we generate localSIDs. 2313 */ 2314 if (is_user && res->id.idtype == IDMAP_GSID) 2315 return (IDMAP_ERR_NOMAPPING); 2316 if (!is_user && res->id.idtype == IDMAP_USID) 2317 return (IDMAP_ERR_NOMAPPING); 2318 2319 /* Skip 1000 UIDs */ 2320 if (is_user && req->id1.idmap_id_u.uid > 2321 (INT32_MAX - LOCALRID_MIN)) 2322 return (IDMAP_ERR_NOMAPPING); 2323 2324 RDLOCK_CONFIG(); 2325 /* 2326 * machine_sid is never NULL because if it is we won't be here. 2327 * No need to assert because stdrup(NULL) will core anyways. 2328 */ 2329 res->id.idmap_id_u.sid.prefix = 2330 strdup(_idmapdstate.cfg->pgcfg.machine_sid); 2331 if (res->id.idmap_id_u.sid.prefix == NULL) { 2332 UNLOCK_CONFIG(); 2333 idmapdlog(LOG_ERR, "Out of memory"); 2334 return (IDMAP_ERR_MEMORY); 2335 } 2336 UNLOCK_CONFIG(); 2337 res->id.idmap_id_u.sid.rid = 2338 (is_user) ? req->id1.idmap_id_u.uid + LOCALRID_MIN : 2339 req->id1.idmap_id_u.gid + INT32_MAX + 1; 2340 res->direction = IDMAP_DIRECTION_BI; 2341 if (res->id.idtype == IDMAP_SID) 2342 res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID; 2343 2344 if (!fallback && req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 2345 res->info.how.map_type = IDMAP_MAP_TYPE_LOCAL_SID; 2346 res->info.src = IDMAP_MAP_SRC_ALGORITHMIC; 2347 } 2348 2349 /* 2350 * Don't update name_cache because local sids don't have 2351 * valid windows names. 2352 */ 2353 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; 2354 return (IDMAP_SUCCESS); 2355 } 2356 2357 static 2358 idmap_retcode 2359 lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res) 2360 { 2361 char *sidprefix; 2362 uint32_t rid; 2363 int s; 2364 2365 /* 2366 * If the sidprefix == localsid then UID = last RID - 1000 or 2367 * GID = last RID - 2^31. 2368 */ 2369 if ((sidprefix = req->id1.idmap_id_u.sid.prefix) == NULL) 2370 /* This means we are looking up by winname */ 2371 return (IDMAP_ERR_NOTFOUND); 2372 rid = req->id1.idmap_id_u.sid.rid; 2373 2374 RDLOCK_CONFIG(); 2375 s = (_idmapdstate.cfg->pgcfg.machine_sid) ? 2376 strcasecmp(sidprefix, _idmapdstate.cfg->pgcfg.machine_sid) : 1; 2377 UNLOCK_CONFIG(); 2378 2379 /* 2380 * If the given sidprefix does not match machine_sid then this is 2381 * not a local SID. 2382 */ 2383 if (s != 0) 2384 return (IDMAP_ERR_NOTFOUND); 2385 2386 switch (res->id.idtype) { 2387 case IDMAP_UID: 2388 if (rid > INT32_MAX || rid < LOCALRID_MIN) 2389 return (IDMAP_ERR_ARG); 2390 res->id.idmap_id_u.uid = rid - LOCALRID_MIN; 2391 break; 2392 case IDMAP_GID: 2393 if (rid <= INT32_MAX) 2394 return (IDMAP_ERR_ARG); 2395 res->id.idmap_id_u.gid = rid - INT32_MAX - 1; 2396 break; 2397 case IDMAP_POSIXID: 2398 if (rid > INT32_MAX) { 2399 res->id.idmap_id_u.gid = rid - INT32_MAX - 1; 2400 res->id.idtype = IDMAP_GID; 2401 } else if (rid < LOCALRID_MIN) { 2402 return (IDMAP_ERR_ARG); 2403 } else { 2404 res->id.idmap_id_u.uid = rid - LOCALRID_MIN; 2405 res->id.idtype = IDMAP_UID; 2406 } 2407 break; 2408 default: 2409 return (IDMAP_ERR_NOTSUPPORTED); 2410 } 2411 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 2412 res->info.how.map_type = IDMAP_MAP_TYPE_LOCAL_SID; 2413 res->info.src = IDMAP_MAP_SRC_ALGORITHMIC; 2414 } 2415 return (IDMAP_SUCCESS); 2416 } 2417 2418 /* 2419 * Name service lookup by unixname to get pid 2420 */ 2421 static 2422 idmap_retcode 2423 ns_lookup_byname(const char *name, const char *lower_name, idmap_id *id) 2424 { 2425 struct passwd pwd, *pwdp; 2426 struct group grp, *grpp; 2427 char buf[1024]; 2428 int errnum; 2429 const char *me = "ns_lookup_byname"; 2430 2431 switch (id->idtype) { 2432 case IDMAP_UID: 2433 pwdp = getpwnam_r(name, &pwd, buf, sizeof (buf)); 2434 if (pwdp == NULL && errno == 0 && lower_name != NULL && 2435 name != lower_name && strcmp(name, lower_name) != 0) 2436 pwdp = getpwnam_r(lower_name, &pwd, buf, sizeof (buf)); 2437 if (pwdp == NULL) { 2438 errnum = errno; 2439 idmapdlog(LOG_WARNING, 2440 "%s: getpwnam_r(%s) failed (%s).", 2441 me, name, errnum ? strerror(errnum) : "not found"); 2442 if (errnum == 0) 2443 return (IDMAP_ERR_NOTFOUND); 2444 else 2445 return (IDMAP_ERR_INTERNAL); 2446 } 2447 id->idmap_id_u.uid = pwd.pw_uid; 2448 break; 2449 case IDMAP_GID: 2450 grpp = getgrnam_r(name, &grp, buf, sizeof (buf)); 2451 if (grpp == NULL && errno == 0 && lower_name != NULL && 2452 name != lower_name && strcmp(name, lower_name) != 0) 2453 grpp = getgrnam_r(lower_name, &grp, buf, sizeof (buf)); 2454 if (grpp == NULL) { 2455 errnum = errno; 2456 idmapdlog(LOG_WARNING, 2457 "%s: getgrnam_r(%s) failed (%s).", 2458 me, name, errnum ? strerror(errnum) : "not found"); 2459 if (errnum == 0) 2460 return (IDMAP_ERR_NOTFOUND); 2461 else 2462 return (IDMAP_ERR_INTERNAL); 2463 } 2464 id->idmap_id_u.gid = grp.gr_gid; 2465 break; 2466 default: 2467 return (IDMAP_ERR_ARG); 2468 } 2469 return (IDMAP_SUCCESS); 2470 } 2471 2472 2473 /* 2474 * Name service lookup by pid to get unixname 2475 */ 2476 static 2477 idmap_retcode 2478 ns_lookup_bypid(uid_t pid, int is_user, char **unixname) 2479 { 2480 struct passwd pwd; 2481 struct group grp; 2482 char buf[1024]; 2483 int errnum; 2484 const char *me = "ns_lookup_bypid"; 2485 2486 if (is_user) { 2487 errno = 0; 2488 if (getpwuid_r(pid, &pwd, buf, sizeof (buf)) == NULL) { 2489 errnum = errno; 2490 idmapdlog(LOG_WARNING, 2491 "%s: getpwuid_r(%u) failed (%s).", 2492 me, pid, errnum ? strerror(errnum) : "not found"); 2493 if (errnum == 0) 2494 return (IDMAP_ERR_NOTFOUND); 2495 else 2496 return (IDMAP_ERR_INTERNAL); 2497 } 2498 *unixname = strdup(pwd.pw_name); 2499 } else { 2500 errno = 0; 2501 if (getgrgid_r(pid, &grp, buf, sizeof (buf)) == NULL) { 2502 errnum = errno; 2503 idmapdlog(LOG_WARNING, 2504 "%s: getgrgid_r(%u) failed (%s).", 2505 me, pid, errnum ? strerror(errnum) : "not found"); 2506 if (errnum == 0) 2507 return (IDMAP_ERR_NOTFOUND); 2508 else 2509 return (IDMAP_ERR_INTERNAL); 2510 } 2511 *unixname = strdup(grp.gr_name); 2512 } 2513 if (*unixname == NULL) 2514 return (IDMAP_ERR_MEMORY); 2515 return (IDMAP_SUCCESS); 2516 } 2517 2518 /* 2519 * Name-based mapping 2520 * 2521 * Case 1: If no rule matches do ephemeral 2522 * 2523 * Case 2: If rule matches and unixname is "" then return no mapping. 2524 * 2525 * Case 3: If rule matches and unixname is specified then lookup name 2526 * service using the unixname. If unixname not found then return no mapping. 2527 * 2528 * Case 4: If rule matches and unixname is * then lookup name service 2529 * using winname as the unixname. If unixname not found then process 2530 * other rules using the lookup order. If no other rule matches then do 2531 * ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4. 2532 * This allows us to specify a fallback unixname per _domain_ or no mapping 2533 * instead of the default behaviour of doing ephemeral mapping. 2534 * 2535 * Example 1: 2536 * *@sfbay == * 2537 * If looking up windows users foo@sfbay and foo does not exists in 2538 * the name service then foo@sfbay will be mapped to an ephemeral id. 2539 * 2540 * Example 2: 2541 * *@sfbay == * 2542 * *@sfbay => guest 2543 * If looking up windows users foo@sfbay and foo does not exists in 2544 * the name service then foo@sfbay will be mapped to guest. 2545 * 2546 * Example 3: 2547 * *@sfbay == * 2548 * *@sfbay => "" 2549 * If looking up windows users foo@sfbay and foo does not exists in 2550 * the name service then we will return no mapping for foo@sfbay. 2551 * 2552 */ 2553 static 2554 idmap_retcode 2555 name_based_mapping_sid2pid(lookup_state_t *state, 2556 idmap_mapping *req, idmap_id_res *res) 2557 { 2558 const char *unixname, *windomain; 2559 char *sql = NULL, *errmsg = NULL, *lower_winname = NULL; 2560 idmap_retcode retcode; 2561 char *end, *lower_unixname, *winname; 2562 const char **values; 2563 sqlite_vm *vm = NULL; 2564 int ncol, r, i, is_user, is_wuser; 2565 idmap_namerule *rule = &res->info.how.idmap_how_u.rule; 2566 int direction; 2567 const char *me = "name_based_mapping_sid2pid"; 2568 2569 assert(req->id1name != NULL); /* We have winname */ 2570 assert(req->id2name == NULL); /* We don't have unixname */ 2571 2572 winname = req->id1name; 2573 windomain = req->id1domain; 2574 2575 switch (req->id1.idtype) { 2576 case IDMAP_USID: 2577 is_wuser = 1; 2578 break; 2579 case IDMAP_GSID: 2580 is_wuser = 0; 2581 break; 2582 default: 2583 idmapdlog(LOG_ERR, "%s: Unable to determine if the " 2584 "given Windows id is user or group.", me); 2585 return (IDMAP_ERR_INTERNAL); 2586 } 2587 2588 switch (res->id.idtype) { 2589 case IDMAP_UID: 2590 is_user = 1; 2591 break; 2592 case IDMAP_GID: 2593 is_user = 0; 2594 break; 2595 case IDMAP_POSIXID: 2596 is_user = is_wuser; 2597 res->id.idtype = is_user ? IDMAP_UID : IDMAP_GID; 2598 break; 2599 } 2600 2601 i = 0; 2602 if (windomain == NULL) 2603 windomain = ""; 2604 else if (state->defdom != NULL && 2605 strcasecmp(state->defdom, windomain) == 0) 2606 i = 1; 2607 2608 if ((lower_winname = tolower_u8(winname)) == NULL) 2609 lower_winname = winname; /* hope for the best */ 2610 sql = sqlite_mprintf( 2611 "SELECT unixname, u2w_order, winname_display, windomain, is_nt4 " 2612 "FROM namerules WHERE " 2613 "w2u_order > 0 AND is_user = %d AND is_wuser = %d AND " 2614 "(winname = %Q OR winname = '*') AND " 2615 "(windomain = %Q OR windomain = '*' %s) " 2616 "ORDER BY w2u_order ASC;", 2617 is_user, is_wuser, lower_winname, windomain, 2618 i ? "OR windomain ISNULL OR windomain = ''" : ""); 2619 if (sql == NULL) { 2620 idmapdlog(LOG_ERR, "Out of memory"); 2621 retcode = IDMAP_ERR_MEMORY; 2622 goto out; 2623 } 2624 2625 if (sqlite_compile(state->db, sql, NULL, &vm, &errmsg) != SQLITE_OK) { 2626 retcode = IDMAP_ERR_INTERNAL; 2627 idmapdlog(LOG_ERR, "%s: database error (%s)", me, 2628 CHECK_NULL(errmsg)); 2629 sqlite_freemem(errmsg); 2630 goto out; 2631 } 2632 2633 for (;;) { 2634 r = sqlite_step(vm, &ncol, &values, NULL); 2635 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 2636 2637 if (r == SQLITE_ROW) { 2638 if (ncol < 5) { 2639 retcode = IDMAP_ERR_INTERNAL; 2640 goto out; 2641 } 2642 if (values[0] == NULL) { 2643 retcode = IDMAP_ERR_INTERNAL; 2644 goto out; 2645 } 2646 2647 if (values[1] != NULL) 2648 direction = 2649 (strtol(values[1], &end, 10) == 0)? 2650 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; 2651 else 2652 direction = IDMAP_DIRECTION_W2U; 2653 2654 if (EMPTY_NAME(values[0])) { 2655 idmap_namerule_set(rule, values[3], values[2], 2656 values[0], is_wuser, is_user, 2657 strtol(values[4], &end, 10), 2658 direction); 2659 retcode = IDMAP_ERR_NOMAPPING; 2660 goto out; 2661 } 2662 2663 if (values[0][0] == '*') { 2664 unixname = winname; 2665 lower_unixname = lower_winname; 2666 } else { 2667 unixname = values[0]; 2668 lower_unixname = NULL; 2669 } 2670 2671 retcode = ns_lookup_byname(unixname, lower_unixname, 2672 &res->id); 2673 if (retcode == IDMAP_ERR_NOTFOUND) { 2674 if (values[0][0] == '*') 2675 /* Case 4 */ 2676 continue; 2677 else { 2678 /* Case 3 */ 2679 idmap_namerule_set(rule, values[3], 2680 values[2], values[0], is_wuser, 2681 is_user, 2682 strtol(values[4], &end, 10), 2683 direction); 2684 retcode = IDMAP_ERR_NOMAPPING; 2685 } 2686 } 2687 goto out; 2688 } else if (r == SQLITE_DONE) { 2689 retcode = IDMAP_ERR_NOTFOUND; 2690 goto out; 2691 } else { 2692 (void) sqlite_finalize(vm, &errmsg); 2693 vm = NULL; 2694 idmapdlog(LOG_ERR, "%s: database error (%s)", me, 2695 CHECK_NULL(errmsg)); 2696 sqlite_freemem(errmsg); 2697 retcode = IDMAP_ERR_INTERNAL; 2698 goto out; 2699 } 2700 } 2701 2702 out: 2703 if (sql != NULL) 2704 sqlite_freemem(sql); 2705 res->info.how.map_type = IDMAP_MAP_TYPE_RULE_BASED; 2706 if (retcode == IDMAP_SUCCESS) { 2707 if (values[1] != NULL) 2708 res->direction = 2709 (strtol(values[1], &end, 10) == 0)? 2710 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; 2711 else 2712 res->direction = IDMAP_DIRECTION_W2U; 2713 2714 req->id2name = strdup(unixname); 2715 if (req->id2name == NULL) { 2716 retcode = IDMAP_ERR_MEMORY; 2717 } 2718 } 2719 2720 if (retcode == IDMAP_SUCCESS) { 2721 idmap_namerule_set(rule, values[3], values[2], 2722 values[0], is_wuser, is_user, strtol(values[4], &end, 10), 2723 res->direction); 2724 res->info.src = IDMAP_MAP_SRC_NEW; 2725 } 2726 2727 if (lower_winname != NULL && lower_winname != winname) 2728 free(lower_winname); 2729 if (vm != NULL) 2730 (void) sqlite_finalize(vm, NULL); 2731 return (retcode); 2732 } 2733 2734 static 2735 int 2736 get_next_eph_uid(uid_t *next_uid) 2737 { 2738 uid_t uid; 2739 gid_t gid; 2740 int err; 2741 2742 *next_uid = (uid_t)-1; 2743 uid = _idmapdstate.next_uid++; 2744 if (uid >= _idmapdstate.limit_uid) { 2745 if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0) 2746 return (err); 2747 2748 _idmapdstate.limit_uid = uid + 8192; 2749 _idmapdstate.next_uid = uid; 2750 } 2751 *next_uid = uid; 2752 2753 return (0); 2754 } 2755 2756 static 2757 int 2758 get_next_eph_gid(gid_t *next_gid) 2759 { 2760 uid_t uid; 2761 gid_t gid; 2762 int err; 2763 2764 *next_gid = (uid_t)-1; 2765 gid = _idmapdstate.next_gid++; 2766 if (gid >= _idmapdstate.limit_gid) { 2767 if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0) 2768 return (err); 2769 2770 _idmapdstate.limit_gid = gid + 8192; 2771 _idmapdstate.next_gid = gid; 2772 } 2773 *next_gid = gid; 2774 2775 return (0); 2776 } 2777 2778 static 2779 int 2780 gethash(const char *str, uint32_t num, uint_t htsize) 2781 { 2782 uint_t hval, i, len; 2783 2784 if (str == NULL) 2785 return (0); 2786 for (len = strlen(str), hval = 0, i = 0; i < len; i++) { 2787 hval += str[i]; 2788 hval += (hval << 10); 2789 hval ^= (hval >> 6); 2790 } 2791 for (str = (const char *)&num, i = 0; i < sizeof (num); i++) { 2792 hval += str[i]; 2793 hval += (hval << 10); 2794 hval ^= (hval >> 6); 2795 } 2796 hval += (hval << 3); 2797 hval ^= (hval >> 11); 2798 hval += (hval << 15); 2799 return (hval % htsize); 2800 } 2801 2802 static 2803 int 2804 get_from_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid, 2805 uid_t *pid) 2806 { 2807 uint_t next, key; 2808 uint_t htsize = state->sid_history_size; 2809 idmap_sid *sid; 2810 2811 next = gethash(prefix, rid, htsize); 2812 while (next != htsize) { 2813 key = state->sid_history[next].key; 2814 if (key == htsize) 2815 return (0); 2816 sid = &state->batch->idmap_mapping_batch_val[key].id1. 2817 idmap_id_u.sid; 2818 if (sid->rid == rid && strcmp(sid->prefix, prefix) == 0) { 2819 *pid = state->result->ids.ids_val[key].id. 2820 idmap_id_u.uid; 2821 return (1); 2822 } 2823 next = state->sid_history[next].next; 2824 } 2825 return (0); 2826 } 2827 2828 static 2829 void 2830 add_to_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid) 2831 { 2832 uint_t hash, next; 2833 uint_t htsize = state->sid_history_size; 2834 2835 hash = next = gethash(prefix, rid, htsize); 2836 while (state->sid_history[next].key != htsize) { 2837 next++; 2838 next %= htsize; 2839 } 2840 state->sid_history[next].key = state->curpos; 2841 if (hash == next) 2842 return; 2843 state->sid_history[next].next = state->sid_history[hash].next; 2844 state->sid_history[hash].next = next; 2845 } 2846 2847 void 2848 cleanup_lookup_state(lookup_state_t *state) 2849 { 2850 free(state->sid_history); 2851 free(state->ad_unixuser_attr); 2852 free(state->ad_unixgroup_attr); 2853 free(state->nldap_winname_attr); 2854 free(state->defdom); 2855 } 2856 2857 /* ARGSUSED */ 2858 static 2859 idmap_retcode 2860 dynamic_ephemeral_mapping(lookup_state_t *state, 2861 idmap_mapping *req, idmap_id_res *res) 2862 { 2863 2864 uid_t next_pid; 2865 2866 res->direction = IDMAP_DIRECTION_BI; 2867 2868 if (IS_EPHEMERAL(res->id.idmap_id_u.uid)) { 2869 res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL; 2870 res->info.src = IDMAP_MAP_SRC_CACHE; 2871 return (IDMAP_SUCCESS); 2872 } 2873 2874 if (state->sid_history != NULL && 2875 get_from_sid_history(state, req->id1.idmap_id_u.sid.prefix, 2876 req->id1.idmap_id_u.sid.rid, &next_pid)) { 2877 res->id.idmap_id_u.uid = next_pid; 2878 res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL; 2879 res->info.src = IDMAP_MAP_SRC_NEW; 2880 return (IDMAP_SUCCESS); 2881 } 2882 2883 if (res->id.idtype == IDMAP_UID) { 2884 if (get_next_eph_uid(&next_pid) != 0) 2885 return (IDMAP_ERR_INTERNAL); 2886 res->id.idmap_id_u.uid = next_pid; 2887 } else { 2888 if (get_next_eph_gid(&next_pid) != 0) 2889 return (IDMAP_ERR_INTERNAL); 2890 res->id.idmap_id_u.gid = next_pid; 2891 } 2892 2893 res->info.how.map_type = IDMAP_MAP_TYPE_EPHEMERAL; 2894 res->info.src = IDMAP_MAP_SRC_NEW; 2895 if (state->sid_history != NULL) 2896 add_to_sid_history(state, req->id1.idmap_id_u.sid.prefix, 2897 req->id1.idmap_id_u.sid.rid); 2898 2899 return (IDMAP_SUCCESS); 2900 } 2901 2902 idmap_retcode 2903 sid2pid_second_pass(lookup_state_t *state, 2904 idmap_mapping *req, idmap_id_res *res) 2905 { 2906 idmap_retcode retcode; 2907 2908 /* Check if second pass is needed */ 2909 if (ARE_WE_DONE(req->direction)) 2910 return (res->retcode); 2911 2912 /* Get status from previous pass */ 2913 retcode = res->retcode; 2914 if (retcode != IDMAP_SUCCESS && state->eph_map_unres_sids && 2915 !EMPTY_STRING(req->id1.idmap_id_u.sid.prefix) && 2916 EMPTY_STRING(req->id1name)) { 2917 /* 2918 * We are asked to map an unresolvable SID to a UID or 2919 * GID, but, which? We'll treat all unresolvable SIDs 2920 * as users unless the caller specified which of a UID 2921 * or GID they want. 2922 */ 2923 if (res->id.idtype == IDMAP_POSIXID) 2924 res->id.idtype = IDMAP_UID; 2925 goto do_eph; 2926 } 2927 if (retcode != IDMAP_SUCCESS) 2928 goto out; 2929 2930 /* 2931 * If directory-based name mapping is enabled then the unixname 2932 * may already have been retrieved from the AD object (AD-mode or 2933 * mixed-mode) or from native LDAP object (nldap-mode) -- done. 2934 */ 2935 if (req->id2name != NULL) { 2936 assert(res->id.idtype != IDMAP_POSIXID); 2937 if (AD_MODE(res->id.idtype, state)) 2938 res->direction = IDMAP_DIRECTION_BI; 2939 else if (NLDAP_MODE(res->id.idtype, state)) 2940 res->direction = IDMAP_DIRECTION_BI; 2941 else if (MIXED_MODE(res->id.idtype, state)) 2942 res->direction = IDMAP_DIRECTION_W2U; 2943 2944 /* 2945 * Special case: (1) If the ad_unixuser_attr and 2946 * ad_unixgroup_attr uses the same attribute 2947 * name and (2) if this is a diagonal mapping 2948 * request and (3) the unixname has been retrieved 2949 * from the AD object -- then we ignore it and fallback 2950 * to name-based mapping rules and ephemeral mapping 2951 * 2952 * Example: 2953 * Properties: 2954 * config/ad_unixuser_attr = "unixname" 2955 * config/ad_unixgroup_attr = "unixname" 2956 * AD user object: 2957 * dn: cn=bob ... 2958 * objectclass: user 2959 * sam: bob 2960 * unixname: bob1234 2961 * AD group object: 2962 * dn: cn=winadmins ... 2963 * objectclass: group 2964 * sam: winadmins 2965 * unixname: unixadmins 2966 * 2967 * In this example whether "unixname" refers to a unixuser 2968 * or unixgroup depends upon the AD object. 2969 * 2970 * $idmap show -c winname:bob gid 2971 * AD lookup by "samAccountName=bob" for 2972 * "ad_unixgroup_attr (i.e unixname)" for directory-based 2973 * mapping would get "bob1234" which is not what we want. 2974 * Now why not getgrnam_r("bob1234") and use it if it 2975 * is indeed a unixgroup? That's because Unix can have 2976 * users and groups with the same name and we clearly 2977 * don't know the intention of the admin here. 2978 * Therefore we ignore this and fallback to name-based 2979 * mapping rules or ephemeral mapping. 2980 */ 2981 if ((AD_MODE(res->id.idtype, state) || 2982 MIXED_MODE(res->id.idtype, state)) && 2983 state->ad_unixuser_attr != NULL && 2984 state->ad_unixgroup_attr != NULL && 2985 strcasecmp(state->ad_unixuser_attr, 2986 state->ad_unixgroup_attr) == 0 && 2987 ((req->id1.idtype == IDMAP_USID && 2988 res->id.idtype == IDMAP_GID) || 2989 (req->id1.idtype == IDMAP_GSID && 2990 res->id.idtype == IDMAP_UID))) { 2991 free(req->id2name); 2992 req->id2name = NULL; 2993 res->id.idmap_id_u.uid = SENTINEL_PID; 2994 /* fallback */ 2995 } else { 2996 if (res->id.idmap_id_u.uid == SENTINEL_PID) 2997 retcode = ns_lookup_byname(req->id2name, 2998 NULL, &res->id); 2999 /* 3000 * If ns_lookup_byname() fails that means the 3001 * unixname (req->id2name), which was obtained 3002 * from the AD object by directory-based mapping, 3003 * is not a valid Unix user/group and therefore 3004 * we return the error to the client instead of 3005 * doing rule-based mapping or ephemeral mapping. 3006 * This way the client can detect the issue. 3007 */ 3008 goto out; 3009 } 3010 } 3011 3012 /* Free any mapping info from Directory based mapping */ 3013 if (res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN) 3014 idmap_info_free(&res->info); 3015 3016 /* 3017 * If we don't have unixname then evaluate local name-based 3018 * mapping rules. 3019 */ 3020 retcode = name_based_mapping_sid2pid(state, req, res); 3021 if (retcode != IDMAP_ERR_NOTFOUND) 3022 goto out; 3023 3024 do_eph: 3025 /* If not found, do ephemeral mapping */ 3026 retcode = dynamic_ephemeral_mapping(state, req, res); 3027 3028 out: 3029 res->retcode = idmap_stat4prot(retcode); 3030 if (res->retcode != IDMAP_SUCCESS) { 3031 req->direction = _IDMAP_F_DONE; 3032 res->id.idmap_id_u.uid = UID_NOBODY; 3033 } 3034 if (!ARE_WE_DONE(req->direction)) 3035 state->sid2pid_done = FALSE; 3036 return (retcode); 3037 } 3038 3039 idmap_retcode 3040 update_cache_pid2sid(lookup_state_t *state, 3041 idmap_mapping *req, idmap_id_res *res) 3042 { 3043 char *sql = NULL; 3044 idmap_retcode retcode; 3045 char *map_dn = NULL; 3046 char *map_attr = NULL; 3047 char *map_value = NULL; 3048 char *map_windomain = NULL; 3049 char *map_winname = NULL; 3050 char *map_unixname = NULL; 3051 int map_is_nt4 = FALSE; 3052 3053 /* Check if we need to cache anything */ 3054 if (ARE_WE_DONE(req->direction)) 3055 return (IDMAP_SUCCESS); 3056 3057 /* We don't cache negative entries */ 3058 if (res->retcode != IDMAP_SUCCESS) 3059 return (IDMAP_SUCCESS); 3060 3061 assert(res->direction != IDMAP_DIRECTION_UNDEF); 3062 assert(req->id1.idmap_id_u.uid != SENTINEL_PID); 3063 assert(res->id.idtype != IDMAP_SID); 3064 3065 assert(res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN); 3066 switch (res->info.how.map_type) { 3067 case IDMAP_MAP_TYPE_DS_AD: 3068 map_dn = res->info.how.idmap_how_u.ad.dn; 3069 map_attr = res->info.how.idmap_how_u.ad.attr; 3070 map_value = res->info.how.idmap_how_u.ad.value; 3071 break; 3072 3073 case IDMAP_MAP_TYPE_DS_NLDAP: 3074 map_dn = res->info.how.idmap_how_u.nldap.dn; 3075 map_attr = res->info.how.idmap_how_u.nldap.attr; 3076 map_value = res->info.how.idmap_how_u.nldap.value; 3077 break; 3078 3079 case IDMAP_MAP_TYPE_RULE_BASED: 3080 map_windomain = res->info.how.idmap_how_u.rule.windomain; 3081 map_winname = res->info.how.idmap_how_u.rule.winname; 3082 map_unixname = res->info.how.idmap_how_u.rule.unixname; 3083 map_is_nt4 = res->info.how.idmap_how_u.rule.is_nt4; 3084 break; 3085 3086 case IDMAP_MAP_TYPE_EPHEMERAL: 3087 break; 3088 3089 case IDMAP_MAP_TYPE_LOCAL_SID: 3090 break; 3091 3092 default: 3093 /* Dont cache other mapping types */ 3094 assert(FALSE); 3095 } 3096 3097 /* 3098 * Using NULL for u2w instead of 0 so that our trigger allows 3099 * the same pid to be the destination in multiple entries 3100 */ 3101 sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache " 3102 "(sidprefix, rid, windomain, canon_winname, pid, unixname, " 3103 "is_user, is_wuser, expiration, w2u, u2w, " 3104 "map_type, map_dn, map_attr, map_value, map_windomain, " 3105 "map_winname, map_unixname, map_is_nt4) " 3106 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, " 3107 "strftime('%%s','now') + 600, %q, 1, " 3108 "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d); ", 3109 res->id.idmap_id_u.sid.prefix, res->id.idmap_id_u.sid.rid, 3110 req->id2domain, req->id2name, req->id1.idmap_id_u.uid, 3111 req->id1name, (req->id1.idtype == IDMAP_UID) ? 1 : 0, 3112 (res->id.idtype == IDMAP_USID) ? 1 : 0, 3113 (res->direction == 0) ? "1" : NULL, 3114 res->info.how.map_type, map_dn, map_attr, map_value, 3115 map_windomain, map_winname, map_unixname, map_is_nt4); 3116 3117 if (sql == NULL) { 3118 retcode = IDMAP_ERR_INTERNAL; 3119 idmapdlog(LOG_ERR, "Out of memory"); 3120 goto out; 3121 } 3122 3123 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); 3124 if (retcode != IDMAP_SUCCESS) 3125 goto out; 3126 3127 state->pid2sid_done = FALSE; 3128 sqlite_freemem(sql); 3129 sql = NULL; 3130 3131 /* Check if we need to update namecache */ 3132 if (req->direction & _IDMAP_F_DONT_UPDATE_NAMECACHE) 3133 goto out; 3134 3135 if (req->id2name == NULL) 3136 goto out; 3137 3138 sql = sqlite_mprintf("INSERT OR REPLACE into name_cache " 3139 "(sidprefix, rid, canon_name, domain, type, expiration) " 3140 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ", 3141 res->id.idmap_id_u.sid.prefix, res->id.idmap_id_u.sid.rid, 3142 req->id2name, req->id2domain, 3143 (res->id.idtype == IDMAP_USID) ? _IDMAP_T_USER : _IDMAP_T_GROUP); 3144 3145 if (sql == NULL) { 3146 retcode = IDMAP_ERR_INTERNAL; 3147 idmapdlog(LOG_ERR, "Out of memory"); 3148 goto out; 3149 } 3150 3151 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); 3152 3153 out: 3154 if (!(req->flag & IDMAP_REQ_FLG_MAPPING_INFO)) 3155 idmap_info_free(&res->info); 3156 if (sql != NULL) 3157 sqlite_freemem(sql); 3158 return (retcode); 3159 } 3160 3161 idmap_retcode 3162 update_cache_sid2pid(lookup_state_t *state, 3163 idmap_mapping *req, idmap_id_res *res) 3164 { 3165 char *sql = NULL; 3166 idmap_retcode retcode; 3167 int is_eph_user; 3168 char *map_dn = NULL; 3169 char *map_attr = NULL; 3170 char *map_value = NULL; 3171 char *map_windomain = NULL; 3172 char *map_winname = NULL; 3173 char *map_unixname = NULL; 3174 int map_is_nt4 = FALSE; 3175 3176 /* Check if we need to cache anything */ 3177 if (ARE_WE_DONE(req->direction)) 3178 return (IDMAP_SUCCESS); 3179 3180 /* We don't cache negative entries */ 3181 if (res->retcode != IDMAP_SUCCESS) 3182 return (IDMAP_SUCCESS); 3183 3184 if (req->direction & _IDMAP_F_EXP_EPH_UID) 3185 is_eph_user = 1; 3186 else if (req->direction & _IDMAP_F_EXP_EPH_GID) 3187 is_eph_user = 0; 3188 else 3189 is_eph_user = -1; 3190 3191 if (is_eph_user >= 0 && !IS_EPHEMERAL(res->id.idmap_id_u.uid)) { 3192 sql = sqlite_mprintf("UPDATE idmap_cache " 3193 "SET w2u = 0 WHERE " 3194 "sidprefix = %Q AND rid = %u AND w2u = 1 AND " 3195 "pid >= 2147483648 AND is_user = %d;", 3196 req->id1.idmap_id_u.sid.prefix, 3197 req->id1.idmap_id_u.sid.rid, 3198 is_eph_user); 3199 if (sql == NULL) { 3200 retcode = IDMAP_ERR_INTERNAL; 3201 idmapdlog(LOG_ERR, "Out of memory"); 3202 goto out; 3203 } 3204 3205 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); 3206 if (retcode != IDMAP_SUCCESS) 3207 goto out; 3208 3209 sqlite_freemem(sql); 3210 sql = NULL; 3211 } 3212 3213 assert(res->direction != IDMAP_DIRECTION_UNDEF); 3214 assert(res->id.idmap_id_u.uid != SENTINEL_PID); 3215 3216 switch (res->info.how.map_type) { 3217 case IDMAP_MAP_TYPE_DS_AD: 3218 map_dn = res->info.how.idmap_how_u.ad.dn; 3219 map_attr = res->info.how.idmap_how_u.ad.attr; 3220 map_value = res->info.how.idmap_how_u.ad.value; 3221 break; 3222 3223 case IDMAP_MAP_TYPE_DS_NLDAP: 3224 map_dn = res->info.how.idmap_how_u.nldap.dn; 3225 map_attr = res->info.how.idmap_how_u.ad.attr; 3226 map_value = res->info.how.idmap_how_u.nldap.value; 3227 break; 3228 3229 case IDMAP_MAP_TYPE_RULE_BASED: 3230 map_windomain = res->info.how.idmap_how_u.rule.windomain; 3231 map_winname = res->info.how.idmap_how_u.rule.winname; 3232 map_unixname = res->info.how.idmap_how_u.rule.unixname; 3233 map_is_nt4 = res->info.how.idmap_how_u.rule.is_nt4; 3234 break; 3235 3236 case IDMAP_MAP_TYPE_EPHEMERAL: 3237 break; 3238 3239 default: 3240 /* Dont cache other mapping types */ 3241 assert(FALSE); 3242 } 3243 3244 sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache " 3245 "(sidprefix, rid, windomain, canon_winname, pid, unixname, " 3246 "is_user, is_wuser, expiration, w2u, u2w, " 3247 "map_type, map_dn, map_attr, map_value, map_windomain, " 3248 "map_winname, map_unixname, map_is_nt4) " 3249 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, %d, " 3250 "strftime('%%s','now') + 600, 1, %q, " 3251 "%d, %Q, %Q, %Q, %Q, %Q, %Q, %d);", 3252 req->id1.idmap_id_u.sid.prefix, req->id1.idmap_id_u.sid.rid, 3253 (req->id1domain != NULL) ? req->id1domain : "", req->id1name, 3254 res->id.idmap_id_u.uid, req->id2name, 3255 (res->id.idtype == IDMAP_UID) ? 1 : 0, 3256 (req->id1.idtype == IDMAP_USID) ? 1 : 0, 3257 (res->direction == 0) ? "1" : NULL, 3258 res->info.how.map_type, map_dn, map_attr, map_value, 3259 map_windomain, map_winname, map_unixname, map_is_nt4); 3260 3261 if (sql == NULL) { 3262 retcode = IDMAP_ERR_INTERNAL; 3263 idmapdlog(LOG_ERR, "Out of memory"); 3264 goto out; 3265 } 3266 3267 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); 3268 if (retcode != IDMAP_SUCCESS) 3269 goto out; 3270 3271 state->sid2pid_done = FALSE; 3272 sqlite_freemem(sql); 3273 sql = NULL; 3274 3275 /* Check if we need to update namecache */ 3276 if (req->direction & _IDMAP_F_DONT_UPDATE_NAMECACHE) 3277 goto out; 3278 3279 if (EMPTY_STRING(req->id1name)) 3280 goto out; 3281 3282 sql = sqlite_mprintf("INSERT OR REPLACE into name_cache " 3283 "(sidprefix, rid, canon_name, domain, type, expiration) " 3284 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ", 3285 req->id1.idmap_id_u.sid.prefix, req->id1.idmap_id_u.sid.rid, 3286 req->id1name, req->id1domain, 3287 (req->id1.idtype == IDMAP_USID) ? _IDMAP_T_USER : _IDMAP_T_GROUP); 3288 3289 if (sql == NULL) { 3290 retcode = IDMAP_ERR_INTERNAL; 3291 idmapdlog(LOG_ERR, "Out of memory"); 3292 goto out; 3293 } 3294 3295 retcode = sql_exec_no_cb(state->cache, IDMAP_CACHENAME, sql); 3296 3297 out: 3298 if (!(req->flag & IDMAP_REQ_FLG_MAPPING_INFO)) 3299 idmap_info_free(&res->info); 3300 3301 if (sql != NULL) 3302 sqlite_freemem(sql); 3303 return (retcode); 3304 } 3305 3306 static 3307 idmap_retcode 3308 lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res, 3309 int is_user, int getname) 3310 { 3311 char *end; 3312 char *sql = NULL; 3313 const char **values; 3314 sqlite_vm *vm = NULL; 3315 int ncol; 3316 idmap_retcode retcode = IDMAP_SUCCESS; 3317 time_t curtime; 3318 idmap_id_type idtype; 3319 3320 /* Current time */ 3321 errno = 0; 3322 if ((curtime = time(NULL)) == (time_t)-1) { 3323 idmapdlog(LOG_ERR, "Failed to get current time (%s)", 3324 strerror(errno)); 3325 retcode = IDMAP_ERR_INTERNAL; 3326 goto out; 3327 } 3328 3329 /* SQL to lookup the cache by pid or by unixname */ 3330 if (req->id1.idmap_id_u.uid != SENTINEL_PID) { 3331 sql = sqlite_mprintf("SELECT sidprefix, rid, " 3332 "canon_winname, windomain, w2u, is_wuser, " 3333 "map_type, map_dn, map_attr, map_value, map_windomain, " 3334 "map_winname, map_unixname, map_is_nt4 " 3335 "FROM idmap_cache WHERE " 3336 "pid = %u AND u2w = 1 AND is_user = %d AND " 3337 "(pid >= 2147483648 OR " 3338 "(expiration = 0 OR expiration ISNULL OR " 3339 "expiration > %d));", 3340 req->id1.idmap_id_u.uid, is_user, curtime); 3341 } else if (req->id1name != NULL) { 3342 sql = sqlite_mprintf("SELECT sidprefix, rid, " 3343 "canon_winname, windomain, w2u, is_wuser, " 3344 "map_type, map_dn, map_attr, map_value, map_windomain, " 3345 "map_winname, map_unixname, map_is_nt4 " 3346 "FROM idmap_cache WHERE " 3347 "unixname = %Q AND u2w = 1 AND is_user = %d AND " 3348 "(pid >= 2147483648 OR " 3349 "(expiration = 0 OR expiration ISNULL OR " 3350 "expiration > %d));", 3351 req->id1name, is_user, curtime); 3352 } else { 3353 retcode = IDMAP_ERR_ARG; 3354 goto out; 3355 } 3356 3357 if (sql == NULL) { 3358 idmapdlog(LOG_ERR, "Out of memory"); 3359 retcode = IDMAP_ERR_MEMORY; 3360 goto out; 3361 } 3362 retcode = sql_compile_n_step_once( 3363 cache, sql, &vm, &ncol, 14, &values); 3364 sqlite_freemem(sql); 3365 3366 if (retcode == IDMAP_ERR_NOTFOUND) 3367 goto out; 3368 else if (retcode == IDMAP_SUCCESS) { 3369 /* sanity checks */ 3370 if (values[0] == NULL || values[1] == NULL) { 3371 retcode = IDMAP_ERR_CACHE; 3372 goto out; 3373 } 3374 3375 switch (res->id.idtype) { 3376 case IDMAP_SID: 3377 case IDMAP_USID: 3378 case IDMAP_GSID: 3379 idtype = strtol(values[5], &end, 10) == 1 3380 ? IDMAP_USID : IDMAP_GSID; 3381 3382 if (res->id.idtype == IDMAP_USID && 3383 idtype != IDMAP_USID) { 3384 retcode = IDMAP_ERR_NOTUSER; 3385 goto out; 3386 } else if (res->id.idtype == IDMAP_GSID && 3387 idtype != IDMAP_GSID) { 3388 retcode = IDMAP_ERR_NOTGROUP; 3389 goto out; 3390 } 3391 res->id.idtype = idtype; 3392 3393 res->id.idmap_id_u.sid.rid = 3394 strtoul(values[1], &end, 10); 3395 res->id.idmap_id_u.sid.prefix = strdup(values[0]); 3396 if (res->id.idmap_id_u.sid.prefix == NULL) { 3397 idmapdlog(LOG_ERR, "Out of memory"); 3398 retcode = IDMAP_ERR_MEMORY; 3399 goto out; 3400 } 3401 3402 if (values[4] != NULL) 3403 res->direction = 3404 (strtol(values[4], &end, 10) == 0)? 3405 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; 3406 else 3407 res->direction = IDMAP_DIRECTION_U2W; 3408 3409 if (getname == 0 || values[2] == NULL) 3410 break; 3411 req->id2name = strdup(values[2]); 3412 if (req->id2name == NULL) { 3413 idmapdlog(LOG_ERR, "Out of memory"); 3414 retcode = IDMAP_ERR_MEMORY; 3415 goto out; 3416 } 3417 3418 if (values[3] == NULL) 3419 break; 3420 req->id2domain = strdup(values[3]); 3421 if (req->id2domain == NULL) { 3422 idmapdlog(LOG_ERR, "Out of memory"); 3423 retcode = IDMAP_ERR_MEMORY; 3424 goto out; 3425 } 3426 3427 break; 3428 default: 3429 retcode = IDMAP_ERR_NOTSUPPORTED; 3430 break; 3431 } 3432 if (req->flag & IDMAP_REQ_FLG_MAPPING_INFO) { 3433 res->info.src = IDMAP_MAP_SRC_CACHE; 3434 res->info.how.map_type = strtoul(values[6], &end, 10); 3435 switch (res->info.how.map_type) { 3436 case IDMAP_MAP_TYPE_DS_AD: 3437 res->info.how.idmap_how_u.ad.dn = 3438 strdup(values[7]); 3439 res->info.how.idmap_how_u.ad.attr = 3440 strdup(values[8]); 3441 res->info.how.idmap_how_u.ad.value = 3442 strdup(values[9]); 3443 break; 3444 3445 case IDMAP_MAP_TYPE_DS_NLDAP: 3446 res->info.how.idmap_how_u.nldap.dn = 3447 strdup(values[7]); 3448 res->info.how.idmap_how_u.nldap.attr = 3449 strdup(values[8]); 3450 res->info.how.idmap_how_u.nldap.value = 3451 strdup(values[9]); 3452 break; 3453 3454 case IDMAP_MAP_TYPE_RULE_BASED: 3455 res->info.how.idmap_how_u.rule.windomain = 3456 strdup(values[10]); 3457 res->info.how.idmap_how_u.rule.winname = 3458 strdup(values[11]); 3459 res->info.how.idmap_how_u.rule.unixname = 3460 strdup(values[12]); 3461 res->info.how.idmap_how_u.rule.is_nt4 = 3462 strtoul(values[13], &end, 10); 3463 res->info.how.idmap_how_u.rule.is_user = 3464 is_user; 3465 res->info.how.idmap_how_u.rule.is_wuser = 3466 strtol(values[5], &end, 10); 3467 break; 3468 3469 case IDMAP_MAP_TYPE_EPHEMERAL: 3470 break; 3471 3472 case IDMAP_MAP_TYPE_LOCAL_SID: 3473 break; 3474 3475 case IDMAP_MAP_TYPE_KNOWN_SID: 3476 break; 3477 3478 default: 3479 /* Unknow mapping type */ 3480 assert(FALSE); 3481 } 3482 } 3483 } 3484 3485 out: 3486 if (vm != NULL) 3487 (void) sqlite_finalize(vm, NULL); 3488 return (retcode); 3489 } 3490 3491 static 3492 idmap_retcode 3493 lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain, 3494 char **canonname, char **sidprefix, idmap_rid_t *rid, int *type) 3495 { 3496 char *end, *lower_name; 3497 char *sql = NULL; 3498 const char **values; 3499 sqlite_vm *vm = NULL; 3500 int ncol; 3501 time_t curtime; 3502 idmap_retcode retcode = IDMAP_SUCCESS; 3503 3504 /* Get current time */ 3505 errno = 0; 3506 if ((curtime = time(NULL)) == (time_t)-1) { 3507 idmapdlog(LOG_ERR, "Failed to get current time (%s)", 3508 strerror(errno)); 3509 retcode = IDMAP_ERR_INTERNAL; 3510 goto out; 3511 } 3512 3513 /* SQL to lookup the cache */ 3514 if ((lower_name = tolower_u8(name)) == NULL) 3515 lower_name = (char *)name; 3516 sql = sqlite_mprintf("SELECT sidprefix, rid, type, canon_name " 3517 "FROM name_cache WHERE name = %Q AND domain = %Q AND " 3518 "(expiration = 0 OR expiration ISNULL OR " 3519 "expiration > %d);", lower_name, domain, curtime); 3520 if (lower_name != name) 3521 free(lower_name); 3522 if (sql == NULL) { 3523 idmapdlog(LOG_ERR, "Out of memory"); 3524 retcode = IDMAP_ERR_MEMORY; 3525 goto out; 3526 } 3527 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 4, &values); 3528 sqlite_freemem(sql); 3529 3530 if (retcode == IDMAP_SUCCESS) { 3531 if (type != NULL) { 3532 if (values[2] == NULL) { 3533 retcode = IDMAP_ERR_CACHE; 3534 goto out; 3535 } 3536 *type = strtol(values[2], &end, 10); 3537 } 3538 3539 if (values[0] == NULL || values[1] == NULL) { 3540 retcode = IDMAP_ERR_CACHE; 3541 goto out; 3542 } 3543 3544 if (canonname != NULL) { 3545 assert(values[3] != NULL); 3546 if ((*canonname = strdup(values[3])) == NULL) { 3547 idmapdlog(LOG_ERR, "Out of memory"); 3548 retcode = IDMAP_ERR_MEMORY; 3549 goto out; 3550 } 3551 } 3552 3553 if ((*sidprefix = strdup(values[0])) == NULL) { 3554 idmapdlog(LOG_ERR, "Out of memory"); 3555 retcode = IDMAP_ERR_MEMORY; 3556 if (canonname != NULL) { 3557 free(*canonname); 3558 *canonname = NULL; 3559 } 3560 goto out; 3561 } 3562 *rid = strtoul(values[1], &end, 10); 3563 } 3564 3565 out: 3566 if (vm != NULL) 3567 (void) sqlite_finalize(vm, NULL); 3568 return (retcode); 3569 } 3570 3571 static 3572 idmap_retcode 3573 ad_lookup_by_winname(lookup_state_t *state, 3574 const char *name, const char *domain, int eunixtype, 3575 char **dn, char **attr, char **value, char **canonname, 3576 char **sidprefix, idmap_rid_t *rid, int *wintype, 3577 char **unixname) 3578 { 3579 int retries = 0; 3580 idmap_query_state_t *qs = NULL; 3581 idmap_retcode rc, retcode; 3582 3583 retry: 3584 retcode = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs); 3585 if (retcode != IDMAP_SUCCESS) { 3586 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 3587 goto retry; 3588 degrade_svc(1, "failed to create request for AD lookup " 3589 "by winname"); 3590 return (retcode); 3591 } 3592 3593 restore_svc(); 3594 3595 if (state != NULL) 3596 idmap_lookup_batch_set_unixattr(qs, state->ad_unixuser_attr, 3597 state->ad_unixgroup_attr); 3598 3599 retcode = idmap_name2sid_batch_add1(qs, name, domain, eunixtype, 3600 dn, attr, value, canonname, sidprefix, rid, wintype, unixname, &rc); 3601 3602 if (retcode != IDMAP_SUCCESS) 3603 idmap_lookup_release_batch(&qs); 3604 else 3605 retcode = idmap_lookup_batch_end(&qs); 3606 3607 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 3608 goto retry; 3609 else if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 3610 degrade_svc(1, "some AD lookups timed out repeatedly"); 3611 3612 if (retcode != IDMAP_SUCCESS) { 3613 idmapdlog(LOG_NOTICE, "AD lookup by winname failed"); 3614 return (retcode); 3615 } 3616 return (rc); 3617 } 3618 3619 idmap_retcode 3620 lookup_name2sid(sqlite *cache, const char *name, const char *domain, 3621 int *is_wuser, char **canonname, char **sidprefix, 3622 idmap_rid_t *rid, idmap_mapping *req, int local_only) 3623 { 3624 int type; 3625 idmap_retcode retcode; 3626 3627 *sidprefix = NULL; 3628 if (canonname != NULL) 3629 *canonname = NULL; 3630 3631 /* Lookup well-known SIDs table */ 3632 retcode = lookup_wksids_name2sid(name, canonname, sidprefix, rid, 3633 &type); 3634 if (retcode == IDMAP_SUCCESS) { 3635 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; 3636 goto out; 3637 } else if (retcode != IDMAP_ERR_NOTFOUND) { 3638 return (retcode); 3639 } 3640 3641 /* Lookup cache */ 3642 retcode = lookup_cache_name2sid(cache, name, domain, canonname, 3643 sidprefix, rid, &type); 3644 if (retcode == IDMAP_SUCCESS) { 3645 req->direction |= _IDMAP_F_DONT_UPDATE_NAMECACHE; 3646 goto out; 3647 } else if (retcode != IDMAP_ERR_NOTFOUND) { 3648 return (retcode); 3649 } 3650 3651 /* 3652 * The caller may be using this function to determine if this 3653 * request needs to be marked for AD lookup or not 3654 * (i.e. _IDMAP_F_LOOKUP_AD) and therefore may not want this 3655 * function to AD lookup now. 3656 */ 3657 if (local_only) 3658 return (retcode); 3659 3660 /* Lookup AD */ 3661 retcode = ad_lookup_by_winname(NULL, name, domain, _IDMAP_T_UNDEF, 3662 NULL, NULL, NULL, canonname, sidprefix, rid, &type, NULL); 3663 if (retcode != IDMAP_SUCCESS) 3664 return (retcode); 3665 3666 out: 3667 /* 3668 * Entry found (cache or Windows lookup) 3669 * is_wuser is both input as well as output parameter 3670 */ 3671 if (*is_wuser == 1 && type != _IDMAP_T_USER) 3672 retcode = IDMAP_ERR_NOTUSER; 3673 else if (*is_wuser == 0 && type != _IDMAP_T_GROUP) 3674 retcode = IDMAP_ERR_NOTGROUP; 3675 else if (*is_wuser == -1) { 3676 /* Caller wants to know if its user or group */ 3677 if (type == _IDMAP_T_USER) 3678 *is_wuser = 1; 3679 else if (type == _IDMAP_T_GROUP) 3680 *is_wuser = 0; 3681 else 3682 retcode = IDMAP_ERR_SID; 3683 } 3684 3685 if (retcode != IDMAP_SUCCESS) { 3686 free(*sidprefix); 3687 *sidprefix = NULL; 3688 if (canonname != NULL) { 3689 free(*canonname); 3690 *canonname = NULL; 3691 } 3692 } 3693 return (retcode); 3694 } 3695 3696 static 3697 idmap_retcode 3698 name_based_mapping_pid2sid(lookup_state_t *state, const char *unixname, 3699 int is_user, idmap_mapping *req, idmap_id_res *res) 3700 { 3701 const char *winname, *windomain; 3702 char *canonname; 3703 char *sql = NULL, *errmsg = NULL; 3704 idmap_retcode retcode; 3705 char *end; 3706 const char **values; 3707 sqlite_vm *vm = NULL; 3708 int ncol, r; 3709 int is_wuser; 3710 const char *me = "name_based_mapping_pid2sid"; 3711 int non_wild_match = FALSE; 3712 idmap_namerule *rule = &res->info.how.idmap_how_u.rule; 3713 int direction; 3714 3715 assert(unixname != NULL); /* We have unixname */ 3716 assert(req->id2name == NULL); /* We don't have winname */ 3717 assert(res->id.idmap_id_u.sid.prefix == NULL); /* No SID either */ 3718 3719 sql = sqlite_mprintf( 3720 "SELECT winname_display, windomain, w2u_order, " 3721 "is_wuser, unixname, is_nt4 " 3722 "FROM namerules WHERE " 3723 "u2w_order > 0 AND is_user = %d AND " 3724 "(unixname = %Q OR unixname = '*') " 3725 "ORDER BY u2w_order ASC;", is_user, unixname); 3726 if (sql == NULL) { 3727 idmapdlog(LOG_ERR, "Out of memory"); 3728 retcode = IDMAP_ERR_MEMORY; 3729 goto out; 3730 } 3731 3732 if (sqlite_compile(state->db, sql, NULL, &vm, &errmsg) != SQLITE_OK) { 3733 retcode = IDMAP_ERR_INTERNAL; 3734 idmapdlog(LOG_ERR, "%s: database error (%s)", me, 3735 CHECK_NULL(errmsg)); 3736 sqlite_freemem(errmsg); 3737 goto out; 3738 } 3739 3740 for (;;) { 3741 r = sqlite_step(vm, &ncol, &values, NULL); 3742 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 3743 if (r == SQLITE_ROW) { 3744 if (ncol < 6) { 3745 retcode = IDMAP_ERR_INTERNAL; 3746 goto out; 3747 } 3748 if (values[0] == NULL) { 3749 /* values [1] and [2] can be null */ 3750 retcode = IDMAP_ERR_INTERNAL; 3751 goto out; 3752 } 3753 3754 if (values[2] != NULL) 3755 direction = 3756 (strtol(values[2], &end, 10) == 0)? 3757 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; 3758 else 3759 direction = IDMAP_DIRECTION_U2W; 3760 3761 if (EMPTY_NAME(values[0])) { 3762 idmap_namerule_set(rule, values[1], values[0], 3763 values[4], is_user, 3764 strtol(values[3], &end, 10), 3765 strtol(values[5], &end, 10), 3766 direction); 3767 retcode = IDMAP_ERR_NOMAPPING; 3768 goto out; 3769 } 3770 3771 if (values[0][0] == '*') { 3772 winname = unixname; 3773 if (non_wild_match) { 3774 /* 3775 * There were non-wildcard rules 3776 * where the Windows identity doesn't 3777 * exist. Return no mapping. 3778 */ 3779 retcode = IDMAP_ERR_NOMAPPING; 3780 goto out; 3781 } 3782 } else { 3783 /* Save first non-wild match rule */ 3784 if (!non_wild_match) { 3785 idmap_namerule_set(rule, values[1], 3786 values[0], values[4], 3787 is_user, 3788 strtol(values[3], &end, 10), 3789 strtol(values[5], &end, 10), 3790 direction); 3791 non_wild_match = TRUE; 3792 } 3793 winname = values[0]; 3794 } 3795 is_wuser = res->id.idtype == IDMAP_USID ? 1 3796 : res->id.idtype == IDMAP_GSID ? 0 3797 : -1; 3798 if (values[1] != NULL) 3799 windomain = values[1]; 3800 else if (state->defdom != NULL) 3801 windomain = state->defdom; 3802 else { 3803 idmapdlog(LOG_ERR, "%s: no domain", me); 3804 retcode = IDMAP_ERR_DOMAIN_NOTFOUND; 3805 goto out; 3806 } 3807 3808 retcode = lookup_name2sid(state->cache, 3809 winname, windomain, 3810 &is_wuser, &canonname, 3811 &res->id.idmap_id_u.sid.prefix, 3812 &res->id.idmap_id_u.sid.rid, req, 0); 3813 3814 if (retcode == IDMAP_ERR_NOTFOUND) { 3815 continue; 3816 } 3817 goto out; 3818 3819 } else if (r == SQLITE_DONE) { 3820 /* 3821 * If there were non-wildcard rules where 3822 * Windows identity doesn't exist 3823 * return no mapping. 3824 */ 3825 if (non_wild_match) 3826 retcode = IDMAP_ERR_NOMAPPING; 3827 else 3828 retcode = IDMAP_ERR_NOTFOUND; 3829 goto out; 3830 } else { 3831 (void) sqlite_finalize(vm, &errmsg); 3832 vm = NULL; 3833 idmapdlog(LOG_ERR, "%s: database error (%s)", me, 3834 CHECK_NULL(errmsg)); 3835 sqlite_freemem(errmsg); 3836 retcode = IDMAP_ERR_INTERNAL; 3837 goto out; 3838 } 3839 } 3840 3841 out: 3842 if (sql != NULL) 3843 sqlite_freemem(sql); 3844 res->info.how.map_type = IDMAP_MAP_TYPE_RULE_BASED; 3845 if (retcode == IDMAP_SUCCESS) { 3846 res->id.idtype = is_wuser ? IDMAP_USID : IDMAP_GSID; 3847 3848 if (values[2] != NULL) 3849 res->direction = 3850 (strtol(values[2], &end, 10) == 0)? 3851 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; 3852 else 3853 res->direction = IDMAP_DIRECTION_U2W; 3854 3855 req->id2name = canonname; 3856 if (req->id2name != NULL) { 3857 req->id2domain = strdup(windomain); 3858 if (req->id2domain == NULL) 3859 retcode = IDMAP_ERR_MEMORY; 3860 } 3861 } 3862 3863 if (retcode == IDMAP_SUCCESS) { 3864 idmap_namerule_set(rule, values[1], values[0], values[4], 3865 is_user, strtol(values[3], &end, 10), 3866 strtol(values[5], &end, 10), 3867 rule->direction); 3868 res->info.src = IDMAP_MAP_SRC_NEW; 3869 } 3870 if (vm != NULL) 3871 (void) sqlite_finalize(vm, NULL); 3872 return (retcode); 3873 } 3874 3875 /* 3876 * Convention when processing unix2win requests: 3877 * 3878 * Unix identity: 3879 * req->id1name = 3880 * unixname if given otherwise unixname found will be placed 3881 * here. 3882 * req->id1domain = 3883 * NOT USED 3884 * req->id1.idtype = 3885 * Given type (IDMAP_UID or IDMAP_GID) 3886 * req->id1..[uid or gid] = 3887 * UID/GID if given otherwise UID/GID found will be placed here. 3888 * 3889 * Windows identity: 3890 * req->id2name = 3891 * winname found will be placed here. 3892 * req->id2domain = 3893 * windomain found will be placed here. 3894 * res->id.idtype = 3895 * Target type initialized from req->id2.idtype. If 3896 * it is IDMAP_SID then actual type (IDMAP_USID/GSID) found 3897 * will be placed here. 3898 * req->id..sid.[prefix, rid] = 3899 * SID found will be placed here. 3900 * 3901 * Others: 3902 * res->retcode = 3903 * Return status for this request will be placed here. 3904 * res->direction = 3905 * Direction found will be placed here. Direction 3906 * meaning whether the resultant mapping is valid 3907 * only from unix2win or bi-directional. 3908 * req->direction = 3909 * INTERNAL USE. Used by idmapd to set various 3910 * flags (_IDMAP_F_xxxx) to aid in processing 3911 * of the request. 3912 * req->id2.idtype = 3913 * INTERNAL USE. Initially this is the requested target 3914 * type and is used to initialize res->id.idtype. 3915 * ad_lookup_batch() uses this field temporarily to store 3916 * sid_type obtained by the batched AD lookups and after 3917 * use resets it to IDMAP_NONE to prevent xdr from 3918 * mis-interpreting the contents of req->id2. 3919 * req->id2..[uid or gid or sid] = 3920 * NOT USED 3921 */ 3922 3923 /* 3924 * This function does the following: 3925 * 1. Lookup well-known SIDs table. 3926 * 2. Lookup cache. 3927 * 3. Check if the client does not want new mapping to be allocated 3928 * in which case this pass is the final pass. 3929 * 4. Set AD/NLDAP lookup flags if it determines that the next stage needs 3930 * to do AD/NLDAP lookup. 3931 */ 3932 idmap_retcode 3933 pid2sid_first_pass(lookup_state_t *state, idmap_mapping *req, 3934 idmap_id_res *res, int is_user, int getname) 3935 { 3936 idmap_retcode retcode; 3937 bool_t gen_localsid_on_err = FALSE; 3938 3939 /* Initialize result */ 3940 res->id.idtype = req->id2.idtype; 3941 res->direction = IDMAP_DIRECTION_UNDEF; 3942 3943 if (req->id2.idmap_id_u.sid.prefix != NULL) { 3944 /* sanitize sidprefix */ 3945 free(req->id2.idmap_id_u.sid.prefix); 3946 req->id2.idmap_id_u.sid.prefix = NULL; 3947 } 3948 3949 /* Find pid */ 3950 if (req->id1.idmap_id_u.uid == SENTINEL_PID) { 3951 if (ns_lookup_byname(req->id1name, NULL, &req->id1) 3952 != IDMAP_SUCCESS) { 3953 retcode = IDMAP_ERR_NOMAPPING; 3954 goto out; 3955 } 3956 } 3957 3958 /* Lookup well-known SIDs table */ 3959 retcode = lookup_wksids_pid2sid(req, res, is_user); 3960 if (retcode != IDMAP_ERR_NOTFOUND) 3961 goto out; 3962 3963 /* Lookup cache */ 3964 retcode = lookup_cache_pid2sid(state->cache, req, res, is_user, 3965 getname); 3966 if (retcode != IDMAP_ERR_NOTFOUND) 3967 goto out; 3968 3969 /* Ephemeral ids cannot be allocated during pid2sid */ 3970 if (IS_EPHEMERAL(req->id1.idmap_id_u.uid)) { 3971 retcode = IDMAP_ERR_NOMAPPING; 3972 goto out; 3973 } 3974 3975 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req)) { 3976 retcode = IDMAP_ERR_NONEGENERATED; 3977 goto out; 3978 } 3979 3980 if (AVOID_NAMESERVICE(req)) { 3981 gen_localsid_on_err = TRUE; 3982 retcode = IDMAP_ERR_NOMAPPING; 3983 goto out; 3984 } 3985 3986 /* Set flags for the next stage */ 3987 if (AD_MODE(req->id1.idtype, state)) { 3988 /* 3989 * If AD-based name mapping is enabled then the next stage 3990 * will need to lookup AD using unixname to get the 3991 * corresponding winname. 3992 */ 3993 if (req->id1name == NULL) { 3994 /* Get unixname if only pid is given. */ 3995 retcode = ns_lookup_bypid(req->id1.idmap_id_u.uid, 3996 is_user, &req->id1name); 3997 if (retcode != IDMAP_SUCCESS) { 3998 gen_localsid_on_err = TRUE; 3999 goto out; 4000 } 4001 } 4002 req->direction |= _IDMAP_F_LOOKUP_AD; 4003 state->ad_nqueries++; 4004 } else if (NLDAP_OR_MIXED_MODE(req->id1.idtype, state)) { 4005 /* 4006 * If native LDAP or mixed mode is enabled for name mapping 4007 * then the next stage will need to lookup native LDAP using 4008 * unixname/pid to get the corresponding winname. 4009 */ 4010 req->direction |= _IDMAP_F_LOOKUP_NLDAP; 4011 state->nldap_nqueries++; 4012 } 4013 4014 /* 4015 * Failed to find non-expired entry in cache. Set the flag to 4016 * indicate that we are not done yet. 4017 */ 4018 state->pid2sid_done = FALSE; 4019 req->direction |= _IDMAP_F_NOTDONE; 4020 retcode = IDMAP_SUCCESS; 4021 4022 out: 4023 res->retcode = idmap_stat4prot(retcode); 4024 if (ARE_WE_DONE(req->direction) && res->retcode != IDMAP_SUCCESS) 4025 if (gen_localsid_on_err == TRUE) 4026 (void) generate_localsid(req, res, is_user, TRUE); 4027 return (retcode); 4028 } 4029 4030 idmap_retcode 4031 pid2sid_second_pass(lookup_state_t *state, idmap_mapping *req, 4032 idmap_id_res *res, int is_user) 4033 { 4034 bool_t gen_localsid_on_err = TRUE; 4035 idmap_retcode retcode = IDMAP_SUCCESS; 4036 4037 /* Check if second pass is needed */ 4038 if (ARE_WE_DONE(req->direction)) 4039 return (res->retcode); 4040 4041 /* Get status from previous pass */ 4042 retcode = res->retcode; 4043 if (retcode != IDMAP_SUCCESS) 4044 goto out; 4045 4046 /* 4047 * If directory-based name mapping is enabled then the winname 4048 * may already have been retrieved from the AD object (AD-mode) 4049 * or from native LDAP object (nldap-mode or mixed-mode). 4050 * Note that if we have winname but no SID then it's an error 4051 * because this implies that the Native LDAP entry contains 4052 * winname which does not exist and it's better that we return 4053 * an error instead of doing rule-based mapping so that the user 4054 * can detect the issue and take appropriate action. 4055 */ 4056 if (req->id2name != NULL) { 4057 /* Return notfound if we've winname but no SID. */ 4058 if (res->id.idmap_id_u.sid.prefix == NULL) { 4059 retcode = IDMAP_ERR_NOTFOUND; 4060 goto out; 4061 } 4062 if (AD_MODE(req->id1.idtype, state)) 4063 res->direction = IDMAP_DIRECTION_BI; 4064 else if (NLDAP_MODE(req->id1.idtype, state)) 4065 res->direction = IDMAP_DIRECTION_BI; 4066 else if (MIXED_MODE(req->id1.idtype, state)) 4067 res->direction = IDMAP_DIRECTION_W2U; 4068 goto out; 4069 } else if (res->id.idmap_id_u.sid.prefix != NULL) { 4070 /* 4071 * We've SID but no winname. This is fine because 4072 * the caller may have only requested SID. 4073 */ 4074 goto out; 4075 } 4076 4077 /* Free any mapping info from Directory based mapping */ 4078 if (res->info.how.map_type != IDMAP_MAP_TYPE_UNKNOWN) 4079 idmap_info_free(&res->info); 4080 4081 if (req->id1name == NULL) { 4082 /* Get unixname from name service */ 4083 retcode = ns_lookup_bypid(req->id1.idmap_id_u.uid, is_user, 4084 &req->id1name); 4085 if (retcode != IDMAP_SUCCESS) 4086 goto out; 4087 } else if (req->id1.idmap_id_u.uid == SENTINEL_PID) { 4088 /* Get pid from name service */ 4089 retcode = ns_lookup_byname(req->id1name, NULL, &req->id1); 4090 if (retcode != IDMAP_SUCCESS) { 4091 gen_localsid_on_err = FALSE; 4092 goto out; 4093 } 4094 } 4095 4096 /* Use unixname to evaluate local name-based mapping rules */ 4097 retcode = name_based_mapping_pid2sid(state, req->id1name, is_user, 4098 req, res); 4099 if (retcode == IDMAP_ERR_NOTFOUND) { 4100 retcode = generate_localsid(req, res, is_user, FALSE); 4101 gen_localsid_on_err = FALSE; 4102 } 4103 4104 out: 4105 res->retcode = idmap_stat4prot(retcode); 4106 if (res->retcode != IDMAP_SUCCESS) { 4107 req->direction = _IDMAP_F_DONE; 4108 free(req->id2name); 4109 req->id2name = NULL; 4110 free(req->id2domain); 4111 req->id2domain = NULL; 4112 if (gen_localsid_on_err == TRUE) 4113 (void) generate_localsid(req, res, is_user, TRUE); 4114 else 4115 res->id.idtype = is_user ? IDMAP_USID : IDMAP_GSID; 4116 } 4117 if (!ARE_WE_DONE(req->direction)) 4118 state->pid2sid_done = FALSE; 4119 return (retcode); 4120 } 4121 4122 static 4123 int 4124 copy_mapping_request(idmap_mapping *mapping, idmap_mapping *request) 4125 { 4126 (void) memset(mapping, 0, sizeof (*mapping)); 4127 4128 mapping->flag = request->flag; 4129 mapping->direction = _IDMAP_F_DONE; 4130 mapping->id2.idtype = request->id2.idtype; 4131 4132 mapping->id1.idtype = request->id1.idtype; 4133 if (IS_REQUEST_SID(*request, 1)) { 4134 mapping->id1.idmap_id_u.sid.rid = 4135 request->id1.idmap_id_u.sid.rid; 4136 if (!EMPTY_STRING(request->id1.idmap_id_u.sid.prefix)) { 4137 mapping->id1.idmap_id_u.sid.prefix = 4138 strdup(request->id1.idmap_id_u.sid.prefix); 4139 if (mapping->id1.idmap_id_u.sid.prefix == NULL) 4140 goto errout; 4141 } 4142 } else { 4143 mapping->id1.idmap_id_u.uid = request->id1.idmap_id_u.uid; 4144 } 4145 4146 if (!EMPTY_STRING(request->id1domain)) { 4147 mapping->id1domain = strdup(request->id1domain); 4148 if (mapping->id1domain == NULL) 4149 goto errout; 4150 } 4151 4152 if (!EMPTY_STRING(request->id1name)) { 4153 mapping->id1name = strdup(request->id1name); 4154 if (mapping->id1name == NULL) 4155 goto errout; 4156 } 4157 4158 /* We don't need the rest of the request i.e request->id2 */ 4159 return (0); 4160 4161 errout: 4162 if (mapping->id1.idmap_id_u.sid.prefix != NULL) 4163 free(mapping->id1.idmap_id_u.sid.prefix); 4164 if (mapping->id1domain != NULL) 4165 free(mapping->id1domain); 4166 if (mapping->id1name != NULL) 4167 free(mapping->id1name); 4168 4169 (void) memset(mapping, 0, sizeof (*mapping)); 4170 return (-1); 4171 } 4172 4173 4174 idmap_retcode 4175 get_w2u_mapping(sqlite *cache, sqlite *db, idmap_mapping *request, 4176 idmap_mapping *mapping) 4177 { 4178 idmap_id_res idres; 4179 lookup_state_t state; 4180 char *cp; 4181 idmap_retcode retcode; 4182 const char *winname, *windomain; 4183 4184 (void) memset(&idres, 0, sizeof (idres)); 4185 (void) memset(&state, 0, sizeof (state)); 4186 state.cache = cache; 4187 state.db = db; 4188 4189 /* Get directory-based name mapping info */ 4190 retcode = load_cfg_in_state(&state); 4191 if (retcode != IDMAP_SUCCESS) 4192 goto out; 4193 4194 /* 4195 * Copy data from "request" to "mapping". Note that 4196 * empty strings are not copied from "request" to 4197 * "mapping" and therefore the coresponding strings in 4198 * "mapping" will be NULL. This eliminates having to 4199 * check for empty strings henceforth. 4200 */ 4201 if (copy_mapping_request(mapping, request) < 0) { 4202 retcode = IDMAP_ERR_MEMORY; 4203 goto out; 4204 } 4205 4206 winname = mapping->id1name; 4207 windomain = mapping->id1domain; 4208 4209 if (winname == NULL && windomain != NULL) { 4210 retcode = IDMAP_ERR_ARG; 4211 goto out; 4212 } 4213 4214 /* Need atleast winname or sid to proceed */ 4215 if (winname == NULL && mapping->id1.idmap_id_u.sid.prefix == NULL) { 4216 retcode = IDMAP_ERR_ARG; 4217 goto out; 4218 } 4219 4220 /* 4221 * If domainname is not given but we have a fully qualified 4222 * winname then extract the domainname from the winname, 4223 * otherwise use the default_domain from the config 4224 */ 4225 if (winname != NULL && windomain == NULL) { 4226 retcode = IDMAP_SUCCESS; 4227 if ((cp = strchr(winname, '@')) != NULL) { 4228 *cp = '\0'; 4229 mapping->id1domain = strdup(cp + 1); 4230 if (mapping->id1domain == NULL) 4231 retcode = IDMAP_ERR_MEMORY; 4232 } else if (lookup_wksids_name2sid(winname, NULL, NULL, NULL, 4233 NULL) != IDMAP_SUCCESS) { 4234 if (state.defdom == NULL) { 4235 /* 4236 * We have a non-qualified winname which is 4237 * neither the name of a well-known SID nor 4238 * there is a default domain with which we can 4239 * qualify it. 4240 */ 4241 retcode = IDMAP_ERR_DOMAIN_NOTFOUND; 4242 } else { 4243 mapping->id1domain = strdup(state.defdom); 4244 if (mapping->id1domain == NULL) 4245 retcode = IDMAP_ERR_MEMORY; 4246 } 4247 } 4248 if (retcode != IDMAP_SUCCESS) 4249 goto out; 4250 } 4251 4252 /* 4253 * First pass looks up the well-known SIDs table and cache 4254 * and handles localSIDs 4255 */ 4256 state.sid2pid_done = TRUE; 4257 retcode = sid2pid_first_pass(&state, mapping, &idres); 4258 if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE) 4259 goto out; 4260 4261 /* AD lookup */ 4262 if (state.ad_nqueries > 0) { 4263 retcode = ad_lookup_one(&state, mapping, &idres); 4264 if (IDMAP_ERROR(retcode)) 4265 goto out; 4266 } 4267 4268 /* nldap lookup */ 4269 if (state.nldap_nqueries > 0) { 4270 retcode = nldap_lookup_one(&state, mapping, &idres); 4271 if (IDMAP_FATAL_ERROR(retcode)) 4272 goto out; 4273 } 4274 4275 /* Next pass performs name-based mapping and ephemeral mapping. */ 4276 state.sid2pid_done = TRUE; 4277 retcode = sid2pid_second_pass(&state, mapping, &idres); 4278 if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE) 4279 goto out; 4280 4281 /* Update cache */ 4282 (void) update_cache_sid2pid(&state, mapping, &idres); 4283 4284 out: 4285 /* 4286 * Note that "mapping" is returned to the client. Therefore 4287 * copy whatever we have in "idres" to mapping->id2 and 4288 * free idres. 4289 */ 4290 mapping->direction = idres.direction; 4291 mapping->id2 = idres.id; 4292 if (mapping->flag & IDMAP_REQ_FLG_MAPPING_INFO || 4293 retcode != IDMAP_SUCCESS) 4294 (void) idmap_info_mov(&mapping->info, &idres.info); 4295 else 4296 idmap_info_free(&idres.info); 4297 (void) memset(&idres, 0, sizeof (idres)); 4298 if (retcode != IDMAP_SUCCESS) 4299 mapping->id2.idmap_id_u.uid = UID_NOBODY; 4300 xdr_free(xdr_idmap_id_res, (caddr_t)&idres); 4301 cleanup_lookup_state(&state); 4302 return (retcode); 4303 } 4304 4305 idmap_retcode 4306 get_u2w_mapping(sqlite *cache, sqlite *db, idmap_mapping *request, 4307 idmap_mapping *mapping, int is_user) 4308 { 4309 idmap_id_res idres; 4310 lookup_state_t state; 4311 idmap_retcode retcode; 4312 4313 /* 4314 * In order to re-use the pid2sid code, we convert 4315 * our input data into structs that are expected by 4316 * pid2sid_first_pass. 4317 */ 4318 4319 (void) memset(&idres, 0, sizeof (idres)); 4320 (void) memset(&state, 0, sizeof (state)); 4321 state.cache = cache; 4322 state.db = db; 4323 4324 /* Get directory-based name mapping info */ 4325 retcode = load_cfg_in_state(&state); 4326 if (retcode != IDMAP_SUCCESS) 4327 goto out; 4328 4329 /* 4330 * Copy data from "request" to "mapping". Note that 4331 * empty strings are not copied from "request" to 4332 * "mapping" and therefore the coresponding strings in 4333 * "mapping" will be NULL. This eliminates having to 4334 * check for empty strings henceforth. 4335 */ 4336 if (copy_mapping_request(mapping, request) < 0) { 4337 retcode = IDMAP_ERR_MEMORY; 4338 goto out; 4339 } 4340 4341 /* 4342 * For unix to windows mapping request, we need atleast a 4343 * unixname or uid/gid to proceed 4344 */ 4345 if (mapping->id1name == NULL && 4346 mapping->id1.idmap_id_u.uid == SENTINEL_PID) { 4347 retcode = IDMAP_ERR_ARG; 4348 goto out; 4349 } 4350 4351 /* First pass looks up cache and well-known SIDs */ 4352 state.pid2sid_done = TRUE; 4353 retcode = pid2sid_first_pass(&state, mapping, &idres, is_user, 1); 4354 if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE) 4355 goto out; 4356 4357 /* nldap lookup */ 4358 if (state.nldap_nqueries > 0) { 4359 retcode = nldap_lookup_one(&state, mapping, &idres); 4360 if (IDMAP_FATAL_ERROR(retcode)) 4361 goto out; 4362 } 4363 4364 /* AD lookup */ 4365 if (state.ad_nqueries > 0) { 4366 retcode = ad_lookup_one(&state, mapping, &idres); 4367 if (IDMAP_FATAL_ERROR(retcode)) 4368 goto out; 4369 } 4370 4371 /* 4372 * Next pass processes the result of the preceding passes/lookups. 4373 * It returns if there's nothing more to be done otherwise it 4374 * evaluates local name-based mapping rules 4375 */ 4376 state.pid2sid_done = TRUE; 4377 retcode = pid2sid_second_pass(&state, mapping, &idres, is_user); 4378 if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE) 4379 goto out; 4380 4381 /* Update cache */ 4382 (void) update_cache_pid2sid(&state, mapping, &idres); 4383 4384 out: 4385 /* 4386 * Note that "mapping" is returned to the client. Therefore 4387 * copy whatever we have in "idres" to mapping->id2 and 4388 * free idres. 4389 */ 4390 mapping->direction = idres.direction; 4391 mapping->id2 = idres.id; 4392 if (mapping->flag & IDMAP_REQ_FLG_MAPPING_INFO || 4393 retcode != IDMAP_SUCCESS) 4394 (void) idmap_info_mov(&mapping->info, &idres.info); 4395 else 4396 idmap_info_free(&idres.info); 4397 (void) memset(&idres, 0, sizeof (idres)); 4398 xdr_free(xdr_idmap_id_res, (caddr_t)&idres); 4399 cleanup_lookup_state(&state); 4400 return (retcode); 4401 } 4402 4403 /*ARGSUSED*/ 4404 static 4405 idmap_retcode 4406 ad_lookup_one(lookup_state_t *state, idmap_mapping *req, idmap_id_res *res) 4407 { 4408 idmap_mapping_batch batch; 4409 idmap_ids_res result; 4410 4411 batch.idmap_mapping_batch_len = 1; 4412 batch.idmap_mapping_batch_val = req; 4413 result.ids.ids_len = 1; 4414 result.ids.ids_val = res; 4415 return (ad_lookup_batch(state, &batch, &result)); 4416 } 4417