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