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