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