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