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