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