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