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