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