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