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