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 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Database related utility routines 30 */ 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <errno.h> 36 #include <sys/types.h> 37 #include <sys/stat.h> 38 #include <rpc/rpc.h> 39 #include <sys/sid.h> 40 #include <time.h> 41 #include <pwd.h> 42 #include <grp.h> 43 #include <pthread.h> 44 #include <assert.h> 45 46 #include "idmapd.h" 47 #include "adutils.h" 48 #include "string.h" 49 #include "idmap_priv.h" 50 51 52 static idmap_retcode sql_compile_n_step_once(sqlite *, char *, 53 sqlite_vm **, int *, int, const char ***); 54 static idmap_retcode lookup_wksids_name2sid(const char *, char **, 55 idmap_rid_t *, int *); 56 57 #define EMPTY_NAME(name) (*name == 0 || strcmp(name, "\"\"") == 0) 58 59 #define EMPTY_STRING(str) (str == NULL || *str == 0) 60 61 #define DO_NOT_ALLOC_NEW_ID_MAPPING(req)\ 62 (req->flag & IDMAP_REQ_FLG_NO_NEW_ID_ALLOC) 63 64 #define AVOID_NAMESERVICE(req)\ 65 (req->flag & IDMAP_REQ_FLG_NO_NAMESERVICE) 66 67 #define IS_EPHEMERAL(pid) (pid > INT32_MAX) 68 69 #define LOCALRID_MIN 1000 70 71 72 73 typedef enum init_db_option { 74 FAIL_IF_CORRUPT = 0, 75 REMOVE_IF_CORRUPT = 1 76 } init_db_option_t; 77 78 /* 79 * Thread specfic data to hold the database handles so that the 80 * databaes are not opened and closed for every request. It also 81 * contains the sqlite busy handler structure. 82 */ 83 84 struct idmap_busy { 85 const char *name; 86 const int *delays; 87 int delay_size; 88 int total; 89 int sec; 90 }; 91 92 93 typedef struct idmap_tsd { 94 sqlite *db_db; 95 sqlite *cache_db; 96 struct idmap_busy cache_busy; 97 struct idmap_busy db_busy; 98 } idmap_tsd_t; 99 100 101 102 static const int cache_delay_table[] = 103 { 1, 2, 5, 10, 15, 20, 25, 30, 35, 40, 104 50, 50, 60, 70, 80, 90, 100}; 105 106 static const int db_delay_table[] = 107 { 5, 10, 15, 20, 30, 40, 55, 70, 100}; 108 109 110 static pthread_key_t idmap_tsd_key; 111 112 void 113 idmap_tsd_destroy(void *key) 114 { 115 116 idmap_tsd_t *tsd = (idmap_tsd_t *)key; 117 if (tsd) { 118 if (tsd->db_db) 119 (void) sqlite_close(tsd->db_db); 120 if (tsd->cache_db) 121 (void) sqlite_close(tsd->cache_db); 122 free(tsd); 123 } 124 } 125 126 int 127 idmap_init_tsd_key(void) { 128 129 return (pthread_key_create(&idmap_tsd_key, idmap_tsd_destroy)); 130 } 131 132 133 134 idmap_tsd_t * 135 idmap_get_tsd(void) 136 { 137 idmap_tsd_t *tsd; 138 139 if ((tsd = pthread_getspecific(idmap_tsd_key)) == NULL) { 140 /* No thread specific data so create it */ 141 if ((tsd = malloc(sizeof (*tsd))) != NULL) { 142 /* Initialize thread specific data */ 143 (void) memset(tsd, 0, sizeof (*tsd)); 144 /* save the trhread specific data */ 145 if (pthread_setspecific(idmap_tsd_key, tsd) != 0) { 146 /* Can't store key */ 147 free(tsd); 148 tsd = NULL; 149 } 150 } else { 151 tsd = NULL; 152 } 153 } 154 155 return (tsd); 156 } 157 158 159 160 /* 161 * Initialize 'dbname' using 'sql' 162 */ 163 static int 164 init_db_instance(const char *dbname, const char *sql, init_db_option_t opt, 165 int *new_db_created) 166 { 167 int rc = 0; 168 int tries = 0; 169 sqlite *db = NULL; 170 char *str = NULL; 171 172 if (new_db_created != NULL) 173 *new_db_created = 0; 174 175 db = sqlite_open(dbname, 0600, &str); 176 while (db == NULL) { 177 idmapdlog(LOG_ERR, 178 "Error creating database %s (%s)", 179 dbname, CHECK_NULL(str)); 180 sqlite_freemem(str); 181 if (opt == FAIL_IF_CORRUPT || opt != REMOVE_IF_CORRUPT || 182 tries > 0) 183 return (-1); 184 185 tries++; 186 (void) unlink(dbname); 187 db = sqlite_open(dbname, 0600, &str); 188 } 189 190 sqlite_busy_timeout(db, 3000); 191 rc = sqlite_exec(db, "BEGIN TRANSACTION;", NULL, NULL, &str); 192 if (SQLITE_OK != rc) { 193 idmapdlog(LOG_ERR, "Cannot begin database transaction (%s)", 194 str); 195 sqlite_freemem(str); 196 sqlite_close(db); 197 return (1); 198 } 199 200 switch (sqlite_exec(db, sql, NULL, NULL, &str)) { 201 case SQLITE_ERROR: 202 /* 203 * This is the normal situation: CREATE probably failed because tables 204 * already exist. It may indicate an error in SQL as well, but we cannot 205 * tell. 206 */ 207 sqlite_freemem(str); 208 rc = sqlite_exec(db, "ROLLBACK TRANSACTION", 209 NULL, NULL, &str); 210 break; 211 case SQLITE_OK: 212 rc = sqlite_exec(db, "COMMIT TRANSACTION", 213 NULL, NULL, &str); 214 idmapdlog(LOG_INFO, 215 "Database created at %s", dbname); 216 217 if (new_db_created != NULL) 218 *new_db_created = 1; 219 break; 220 default: 221 idmapdlog(LOG_ERR, 222 "Error initializing database %s (%s)", 223 dbname, str); 224 sqlite_freemem(str); 225 rc = sqlite_exec(db, "ROLLBACK TRANSACTION", 226 NULL, NULL, &str); 227 break; 228 } 229 230 if (SQLITE_OK != rc) { 231 /* this is bad - database may be left in a locked state */ 232 idmapdlog(LOG_ERR, 233 "Error closing transaction (%s)", str); 234 sqlite_freemem(str); 235 } 236 237 (void) sqlite_close(db); 238 return (rc); 239 } 240 241 242 /* 243 * This is the SQLite database busy handler that retries the SQL 244 * operation until it is successful. 245 */ 246 int 247 /* LINTED E_FUNC_ARG_UNUSED */ 248 idmap_sqlite_busy_handler(void *arg, const char *table_name, int count) 249 { 250 struct idmap_busy *busy = arg; 251 int delay; 252 struct timespec rqtp; 253 254 if (count == 1) { 255 busy->total = 0; 256 busy->sec = 2; 257 } 258 if (busy->total > 1000 * busy->sec) { 259 idmapdlog(LOG_ERR, 260 "Thread %d waited %d sec for the %s database", 261 pthread_self(), busy->sec, busy->name); 262 busy->sec++; 263 } 264 265 if (count <= busy->delay_size) { 266 delay = busy->delays[count-1]; 267 } else { 268 delay = busy->delays[busy->delay_size - 1]; 269 } 270 busy->total += delay; 271 rqtp.tv_sec = 0; 272 rqtp.tv_nsec = delay * (NANOSEC / MILLISEC); 273 (void) nanosleep(&rqtp, NULL); 274 return (1); 275 } 276 277 278 /* 279 * Get the database handle 280 */ 281 idmap_retcode 282 get_db_handle(sqlite **db) { 283 char *errmsg; 284 idmap_tsd_t *tsd; 285 286 /* 287 * Retrieve the db handle from thread-specific storage 288 * If none exists, open and store in thread-specific storage. 289 */ 290 if ((tsd = idmap_get_tsd()) == NULL) { 291 idmapdlog(LOG_ERR, 292 "Error getting thread specific data for %s", 293 IDMAP_DBNAME); 294 return (IDMAP_ERR_MEMORY); 295 } 296 297 if (tsd->db_db == NULL) { 298 tsd->db_db = sqlite_open(IDMAP_DBNAME, 0, &errmsg); 299 if (tsd->db_db == NULL) { 300 idmapdlog(LOG_ERR, 301 "Error opening database %s (%s)", 302 IDMAP_DBNAME, CHECK_NULL(errmsg)); 303 sqlite_freemem(errmsg); 304 return (IDMAP_ERR_INTERNAL); 305 } 306 tsd->db_busy.name = IDMAP_DBNAME; 307 tsd->db_busy.delays = db_delay_table; 308 tsd->db_busy.delay_size = sizeof (db_delay_table) / 309 sizeof (int); 310 sqlite_busy_handler(tsd->db_db, idmap_sqlite_busy_handler, 311 &tsd->db_busy); 312 } 313 *db = tsd->db_db; 314 return (IDMAP_SUCCESS); 315 } 316 317 /* 318 * Get the cache handle 319 */ 320 idmap_retcode 321 get_cache_handle(sqlite **cache) { 322 char *errmsg; 323 idmap_tsd_t *tsd; 324 325 /* 326 * Retrieve the db handle from thread-specific storage 327 * If none exists, open and store in thread-specific storage. 328 */ 329 if ((tsd = idmap_get_tsd()) == NULL) { 330 idmapdlog(LOG_ERR, 331 "Error getting thread specific data for %s", 332 IDMAP_DBNAME); 333 return (IDMAP_ERR_MEMORY); 334 } 335 336 if (tsd->cache_db == NULL) { 337 tsd->cache_db = sqlite_open(IDMAP_CACHENAME, 0, &errmsg); 338 if (tsd->cache_db == NULL) { 339 idmapdlog(LOG_ERR, 340 "Error opening database %s (%s)", 341 IDMAP_CACHENAME, CHECK_NULL(errmsg)); 342 sqlite_freemem(errmsg); 343 return (IDMAP_ERR_INTERNAL); 344 } 345 tsd->cache_busy.name = IDMAP_CACHENAME; 346 tsd->cache_busy.delays = cache_delay_table; 347 tsd->cache_busy.delay_size = sizeof (cache_delay_table) / 348 sizeof (int); 349 sqlite_busy_handler(tsd->cache_db, idmap_sqlite_busy_handler, 350 &tsd->cache_busy); 351 } 352 *cache = tsd->cache_db; 353 return (IDMAP_SUCCESS); 354 } 355 356 #define CACHE_SQL\ 357 "CREATE TABLE idmap_cache ("\ 358 " sidprefix TEXT,"\ 359 " rid INTEGER,"\ 360 " windomain TEXT,"\ 361 " winname TEXT,"\ 362 " pid INTEGER,"\ 363 " unixname TEXT,"\ 364 " is_user INTEGER,"\ 365 " w2u INTEGER,"\ 366 " u2w INTEGER,"\ 367 " expiration INTEGER"\ 368 ");"\ 369 "CREATE UNIQUE INDEX idmap_cache_sid_w2u ON idmap_cache"\ 370 " (sidprefix, rid, w2u);"\ 371 "CREATE UNIQUE INDEX idmap_cache_pid_u2w ON idmap_cache"\ 372 " (pid, is_user, u2w);"\ 373 "CREATE TABLE name_cache ("\ 374 " sidprefix TEXT,"\ 375 " rid INTEGER,"\ 376 " name TEXT,"\ 377 " domain TEXT,"\ 378 " type INTEGER,"\ 379 " expiration INTEGER"\ 380 ");"\ 381 "CREATE UNIQUE INDEX name_cache_sid ON name_cache"\ 382 " (sidprefix, rid);" 383 384 #define DB_SQL\ 385 "CREATE TABLE namerules ("\ 386 " is_user INTEGER NOT NULL,"\ 387 " windomain TEXT,"\ 388 " winname TEXT NOT NULL,"\ 389 " is_nt4 INTEGER NOT NULL,"\ 390 " unixname NOT NULL,"\ 391 " w2u_order INTEGER,"\ 392 " u2w_order INTEGER"\ 393 ");"\ 394 "CREATE UNIQUE INDEX namerules_w2u ON namerules"\ 395 " (winname, windomain, is_user, w2u_order);"\ 396 "CREATE UNIQUE INDEX namerules_u2w ON namerules"\ 397 " (unixname, is_user, u2w_order);" 398 399 /* 400 * Initialize cache and db 401 */ 402 int 403 init_dbs() { 404 /* name-based mappings; probably OK to blow away in a pinch(?) */ 405 if (init_db_instance(IDMAP_DBNAME, DB_SQL, FAIL_IF_CORRUPT, NULL) < 0) 406 return (-1); 407 408 /* mappings, name/SID lookup cache + ephemeral IDs; OK to blow away */ 409 if (init_db_instance(IDMAP_CACHENAME, CACHE_SQL, REMOVE_IF_CORRUPT, 410 &_idmapdstate.new_eph_db) < 0) 411 return (-1); 412 413 return (0); 414 } 415 416 /* 417 * Finalize databases 418 */ 419 void 420 fini_dbs() { 421 } 422 423 /* 424 * This table is a listing of status codes that will returned to the 425 * client when a SQL command fails with the corresponding error message. 426 */ 427 static msg_table_t sqlmsgtable[] = { 428 {IDMAP_ERR_U2W_NAMERULE_CONFLICT, 429 "columns unixname, is_user, u2w_order are not unique"}, 430 {IDMAP_ERR_W2U_NAMERULE_CONFLICT, 431 "columns winname, windomain, is_user, w2u_order are not unique"}, 432 {-1, NULL} 433 }; 434 435 /* 436 * idmapd's version of string2stat to map SQLite messages to 437 * status codes 438 */ 439 idmap_retcode 440 idmapd_string2stat(const char *msg) { 441 int i; 442 for (i = 0; sqlmsgtable[i].msg; i++) { 443 if (strcasecmp(sqlmsgtable[i].msg, msg) == 0) 444 return (sqlmsgtable[i].retcode); 445 } 446 return (IDMAP_ERR_OTHER); 447 } 448 449 /* 450 * Execute the given SQL statment without using any callbacks 451 */ 452 idmap_retcode 453 sql_exec_no_cb(sqlite *db, char *sql) { 454 char *errmsg = NULL; 455 int r; 456 idmap_retcode retcode; 457 458 r = sqlite_exec(db, sql, NULL, NULL, &errmsg); 459 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 460 461 if (r != SQLITE_OK) { 462 idmapdlog(LOG_ERR, "Database error during %s (%s)", 463 sql, CHECK_NULL(errmsg)); 464 retcode = idmapd_string2stat(errmsg); 465 if (errmsg != NULL) 466 sqlite_freemem(errmsg); 467 return (retcode); 468 } 469 470 return (IDMAP_SUCCESS); 471 } 472 473 /* 474 * Generate expression that can be used in WHERE statements. 475 * Examples: 476 * <prefix> <col> <op> <value> <suffix> 477 * "" "unixuser" "=" "foo" "AND" 478 */ 479 idmap_retcode 480 gen_sql_expr_from_utf8str(const char *prefix, const char *col, 481 const char *op, idmap_utf8str *value, 482 const char *suffix, char **out) { 483 char *str; 484 idmap_stat retcode; 485 486 if (out == NULL) 487 return (IDMAP_ERR_ARG); 488 489 if (value == NULL) 490 return (IDMAP_SUCCESS); 491 492 retcode = idmap_utf82str(&str, 0, value); 493 if (retcode != IDMAP_SUCCESS) 494 return (retcode); 495 496 if (prefix == NULL) 497 prefix = ""; 498 if (suffix == NULL) 499 suffix = ""; 500 501 *out = sqlite_mprintf("%s %s %s %Q %s", 502 prefix, col, op, str, suffix); 503 idmap_free(str); 504 if (*out == NULL) 505 return (IDMAP_ERR_MEMORY); 506 return (IDMAP_SUCCESS); 507 } 508 509 /* 510 * Generate and execute SQL statement for LIST RPC calls 511 */ 512 idmap_retcode 513 process_list_svc_sql(sqlite *db, char *sql, uint64_t limit, 514 list_svc_cb cb, void *result) { 515 list_cb_data_t cb_data; 516 char *errmsg = NULL; 517 int r; 518 idmap_retcode retcode = IDMAP_ERR_INTERNAL; 519 520 (void) memset(&cb_data, 0, sizeof (cb_data)); 521 cb_data.result = result; 522 cb_data.limit = limit; 523 524 525 r = sqlite_exec(db, sql, cb, &cb_data, &errmsg); 526 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 527 switch (r) { 528 case SQLITE_OK: 529 retcode = IDMAP_SUCCESS; 530 break; 531 532 default: 533 retcode = IDMAP_ERR_INTERNAL; 534 idmapdlog(LOG_ERR, 535 "Database error during %s (%s)", 536 sql, CHECK_NULL(errmsg)); 537 break; 538 } 539 if (errmsg != NULL) 540 sqlite_freemem(errmsg); 541 return (retcode); 542 } 543 544 /* 545 * This routine is called by callbacks that process the results of 546 * LIST RPC calls to validate data and to allocate memory for 547 * the result array. 548 */ 549 idmap_retcode 550 validate_list_cb_data(list_cb_data_t *cb_data, int argc, char **argv, 551 int ncol, uchar_t **list, size_t valsize) { 552 size_t nsize; 553 void *tmplist; 554 555 if (cb_data->limit > 0 && cb_data->next == cb_data->limit) 556 return (IDMAP_NEXT); 557 558 if (argc < ncol || argv == NULL) { 559 idmapdlog(LOG_ERR, "Invalid data"); 560 return (IDMAP_ERR_INTERNAL); 561 } 562 563 /* alloc in bulk to reduce number of reallocs */ 564 if (cb_data->next >= cb_data->len) { 565 nsize = (cb_data->len + SIZE_INCR) * valsize; 566 tmplist = realloc(*list, nsize); 567 if (tmplist == NULL) { 568 idmapdlog(LOG_ERR, "Out of memory"); 569 return (IDMAP_ERR_MEMORY); 570 } 571 *list = tmplist; 572 (void) memset(*list + (cb_data->len * valsize), 0, 573 SIZE_INCR * valsize); 574 cb_data->len += SIZE_INCR; 575 } 576 return (IDMAP_SUCCESS); 577 } 578 579 static idmap_retcode 580 get_namerule_order(char *winname, char *windomain, char *unixname, 581 int direction, int *w2u_order, int *u2w_order) { 582 583 *w2u_order = 0; 584 *u2w_order = 0; 585 586 /* 587 * Windows to UNIX lookup order: 588 * 1. winname@domain (or winname) to "" 589 * 2. winname@domain (or winname) to unixname 590 * 3. winname@* to "" 591 * 4. winname@* to unixname 592 * 5. *@domain (or *) to * 593 * 6. *@domain (or *) to "" 594 * 7. *@domain (or *) to unixname 595 * 8. *@* to * 596 * 9. *@* to "" 597 * 10. *@* to unixname 598 * 599 * winname is a special case of winname@domain when domain is the 600 * default domain. Similarly * is a special case of *@domain when 601 * domain is the default domain. 602 * 603 * Note that "" has priority over specific names because "" inhibits 604 * mappings and traditionally deny rules always had higher priority. 605 */ 606 if (direction != IDMAP_DIRECTION_U2W) { 607 /* bi-directional or from windows to unix */ 608 if (winname == NULL) 609 return (IDMAP_ERR_W2U_NAMERULE); 610 else if (unixname == NULL) 611 return (IDMAP_ERR_W2U_NAMERULE); 612 else if (EMPTY_NAME(winname)) 613 return (IDMAP_ERR_W2U_NAMERULE); 614 else if (*winname == '*' && windomain && *windomain == '*') { 615 if (*unixname == '*') 616 *w2u_order = 8; 617 else if (EMPTY_NAME(unixname)) 618 *w2u_order = 9; 619 else /* unixname == name */ 620 *w2u_order = 10; 621 } else if (*winname == '*') { 622 if (*unixname == '*') 623 *w2u_order = 5; 624 else if (EMPTY_NAME(unixname)) 625 *w2u_order = 6; 626 else /* name */ 627 *w2u_order = 7; 628 } else if (windomain != NULL && *windomain == '*') { 629 /* winname == name */ 630 if (*unixname == '*') 631 return (IDMAP_ERR_W2U_NAMERULE); 632 else if (EMPTY_NAME(unixname)) 633 *w2u_order = 3; 634 else /* name */ 635 *w2u_order = 4; 636 } else { 637 /* winname == name && windomain == null or name */ 638 if (*unixname == '*') 639 return (IDMAP_ERR_W2U_NAMERULE); 640 else if (EMPTY_NAME(unixname)) 641 *w2u_order = 1; 642 else /* name */ 643 *w2u_order = 2; 644 } 645 } 646 647 /* 648 * 1. unixname to "" 649 * 2. unixname to winname@domain (or winname) 650 * 3. * to *@domain (or *) 651 * 4. * to "" 652 * 5. * to winname@domain (or winname) 653 */ 654 if (direction != IDMAP_DIRECTION_W2U) { 655 /* bi-directional or from unix to windows */ 656 if (unixname == NULL || EMPTY_NAME(unixname)) 657 return (IDMAP_ERR_U2W_NAMERULE); 658 else if (winname == NULL) 659 return (IDMAP_ERR_U2W_NAMERULE); 660 else if (windomain != NULL && *windomain == '*') 661 return (IDMAP_ERR_U2W_NAMERULE); 662 else if (*unixname == '*') { 663 if (*winname == '*') 664 *u2w_order = 3; 665 else if (EMPTY_NAME(winname)) 666 *u2w_order = 4; 667 else 668 *u2w_order = 5; 669 } else { 670 if (*winname == '*') 671 return (IDMAP_ERR_U2W_NAMERULE); 672 else if (EMPTY_NAME(winname)) 673 *u2w_order = 1; 674 else 675 *u2w_order = 2; 676 } 677 } 678 return (IDMAP_SUCCESS); 679 } 680 681 /* 682 * Generate and execute SQL statement to add name-based mapping rule 683 */ 684 idmap_retcode 685 add_namerule(sqlite *db, idmap_namerule *rule) { 686 char *sql = NULL; 687 idmap_stat retcode; 688 char *windomain = NULL, *winname = NULL, *dom = NULL; 689 char *unixname = NULL; 690 int w2u_order, u2w_order; 691 char w2ubuf[11], u2wbuf[11]; 692 693 retcode = idmap_utf82str(&windomain, 0, &rule->windomain); 694 if (retcode != IDMAP_SUCCESS) 695 goto out; 696 retcode = idmap_utf82str(&winname, 0, &rule->winname); 697 if (retcode != IDMAP_SUCCESS) 698 goto out; 699 retcode = idmap_utf82str(&unixname, 0, &rule->unixname); 700 if (retcode != IDMAP_SUCCESS) 701 goto out; 702 703 retcode = get_namerule_order(winname, windomain, unixname, 704 rule->direction, &w2u_order, &u2w_order); 705 if (retcode != IDMAP_SUCCESS) 706 goto out; 707 708 if (w2u_order) 709 (void) snprintf(w2ubuf, sizeof (w2ubuf), "%d", w2u_order); 710 if (u2w_order) 711 (void) snprintf(u2wbuf, sizeof (u2wbuf), "%d", u2w_order); 712 713 /* 714 * For the triggers on namerules table to work correctly: 715 * 1) Use NULL instead of 0 for w2u_order and u2w_order 716 * 2) Use "" instead of NULL for "no domain" 717 */ 718 719 if (windomain != NULL) 720 dom = windomain; 721 else if (lookup_wksids_name2sid(winname, NULL, NULL, NULL) 722 == IDMAP_SUCCESS) { 723 /* well-known SIDs don't need domain */ 724 dom = ""; 725 } 726 727 RDLOCK_CONFIG(); 728 if (dom == NULL) { 729 if (_idmapdstate.cfg->pgcfg.mapping_domain) 730 dom = _idmapdstate.cfg->pgcfg.mapping_domain; 731 else 732 dom = ""; 733 } 734 sql = sqlite_mprintf("INSERT into namerules " 735 "(is_user, windomain, winname, is_nt4, " 736 "unixname, w2u_order, u2w_order) " 737 "VALUES(%d, %Q, %Q, %d, %Q, %q, %q);", 738 rule->is_user?1:0, 739 dom, 740 winname, rule->is_nt4?1:0, 741 unixname, 742 w2u_order?w2ubuf:NULL, 743 u2w_order?u2wbuf:NULL); 744 UNLOCK_CONFIG(); 745 746 if (sql == NULL) { 747 retcode = IDMAP_ERR_INTERNAL; 748 idmapdlog(LOG_ERR, "Out of memory"); 749 goto out; 750 } 751 752 retcode = sql_exec_no_cb(db, sql); 753 754 if (retcode == IDMAP_ERR_OTHER) 755 retcode = IDMAP_ERR_CFG; 756 757 out: 758 if (windomain != NULL) 759 idmap_free(windomain); 760 if (winname != NULL) 761 idmap_free(winname); 762 if (unixname != NULL) 763 idmap_free(unixname); 764 if (sql != NULL) 765 sqlite_freemem(sql); 766 return (retcode); 767 } 768 769 /* 770 * Flush name-based mapping rules 771 */ 772 idmap_retcode 773 flush_namerules(sqlite *db, bool_t is_user) { 774 char *sql = NULL; 775 idmap_stat retcode; 776 777 sql = sqlite_mprintf("DELETE FROM namerules WHERE " 778 "is_user = %d;", is_user?1:0); 779 780 if (sql == NULL) { 781 idmapdlog(LOG_ERR, "Out of memory"); 782 return (IDMAP_ERR_MEMORY); 783 } 784 785 retcode = sql_exec_no_cb(db, sql); 786 787 sqlite_freemem(sql); 788 return (retcode); 789 } 790 791 /* 792 * Generate and execute SQL statement to remove a name-based mapping rule 793 */ 794 idmap_retcode 795 rm_namerule(sqlite *db, idmap_namerule *rule) { 796 char *sql = NULL; 797 idmap_stat retcode; 798 char *s_windomain = NULL, *s_winname = NULL; 799 char *s_unixname = NULL; 800 char buf[80]; 801 802 if (rule->direction < 0 && 803 rule->windomain.idmap_utf8str_len < 1 && 804 rule->winname.idmap_utf8str_len < 1 && 805 rule->unixname.idmap_utf8str_len < 1) 806 return (IDMAP_SUCCESS); 807 808 if (rule->direction < 0) { 809 buf[0] = 0; 810 } else if (rule->direction == IDMAP_DIRECTION_BI) { 811 (void) snprintf(buf, sizeof (buf), "AND w2u_order > 0" 812 " AND u2w_order > 0"); 813 } else if (rule->direction == IDMAP_DIRECTION_W2U) { 814 (void) snprintf(buf, sizeof (buf), "AND w2u_order > 0" 815 " AND (u2w_order = 0 OR u2w_order ISNULL)"); 816 } else if (rule->direction == IDMAP_DIRECTION_U2W) { 817 (void) snprintf(buf, sizeof (buf), "AND u2w_order > 0" 818 " AND (w2u_order = 0 OR w2u_order ISNULL)"); 819 } 820 821 retcode = IDMAP_ERR_INTERNAL; 822 if (rule->windomain.idmap_utf8str_len > 0) { 823 if (gen_sql_expr_from_utf8str("AND", "windomain", "=", 824 &rule->windomain, 825 "", &s_windomain) != IDMAP_SUCCESS) 826 goto out; 827 } 828 829 if (rule->winname.idmap_utf8str_len > 0) { 830 if (gen_sql_expr_from_utf8str("AND", "winname", "=", 831 &rule->winname, 832 "", &s_winname) != IDMAP_SUCCESS) 833 goto out; 834 } 835 836 if (rule->unixname.idmap_utf8str_len > 0) { 837 if (gen_sql_expr_from_utf8str("AND", "unixname", "=", 838 &rule->unixname, 839 "", &s_unixname) != IDMAP_SUCCESS) 840 goto out; 841 } 842 843 sql = sqlite_mprintf("DELETE FROM namerules WHERE " 844 "is_user = %d %s %s %s %s;", 845 rule->is_user?1:0, 846 s_windomain?s_windomain:"", 847 s_winname?s_winname:"", 848 s_unixname?s_unixname:"", 849 buf); 850 851 if (sql == NULL) { 852 retcode = IDMAP_ERR_INTERNAL; 853 idmapdlog(LOG_ERR, "Out of memory"); 854 goto out; 855 } 856 857 retcode = sql_exec_no_cb(db, sql); 858 859 out: 860 if (s_windomain != NULL) 861 sqlite_freemem(s_windomain); 862 if (s_winname != NULL) 863 sqlite_freemem(s_winname); 864 if (s_unixname != NULL) 865 sqlite_freemem(s_unixname); 866 if (sql != NULL) 867 sqlite_freemem(sql); 868 return (retcode); 869 } 870 871 /* 872 * Compile the given SQL query and step just once. 873 * 874 * Input: 875 * db - db handle 876 * sql - SQL statement 877 * 878 * Output: 879 * vm - virtual SQL machine 880 * ncol - number of columns in the result 881 * values - column values 882 * 883 * Return values: 884 * IDMAP_SUCCESS 885 * IDMAP_ERR_NOTFOUND 886 * IDMAP_ERR_INTERNAL 887 */ 888 889 static idmap_retcode 890 sql_compile_n_step_once(sqlite *db, char *sql, sqlite_vm **vm, int *ncol, 891 int reqcol, const char ***values) { 892 char *errmsg = NULL; 893 int r; 894 895 if ((r = sqlite_compile(db, sql, NULL, vm, &errmsg)) != SQLITE_OK) { 896 idmapdlog(LOG_ERR, 897 "Database error during %s (%s)", 898 sql, CHECK_NULL(errmsg)); 899 sqlite_freemem(errmsg); 900 return (IDMAP_ERR_INTERNAL); 901 } 902 903 r = sqlite_step(*vm, ncol, values, NULL); 904 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 905 906 if (r == SQLITE_ROW) { 907 if (ncol != NULL && *ncol < reqcol) { 908 (void) sqlite_finalize(*vm, NULL); 909 *vm = NULL; 910 return (IDMAP_ERR_INTERNAL); 911 } 912 /* Caller will call finalize after using the results */ 913 return (IDMAP_SUCCESS); 914 } else if (r == SQLITE_DONE) { 915 (void) sqlite_finalize(*vm, NULL); 916 *vm = NULL; 917 return (IDMAP_ERR_NOTFOUND); 918 } 919 920 (void) sqlite_finalize(*vm, &errmsg); 921 *vm = NULL; 922 idmapdlog(LOG_ERR, "Database error during %s (%s)", 923 sql, CHECK_NULL(errmsg)); 924 sqlite_freemem(errmsg); 925 return (IDMAP_ERR_INTERNAL); 926 } 927 928 /* 929 * Table for well-known SIDs. 930 * 931 * Background: 932 * 933 * These well-known principals are stored (as of Windows Server 2003) under: 934 * cn=WellKnown Security Principals, cn=Configuration, dc=<forestRootDomain> 935 * They belong to objectClass "foreignSecurityPrincipal". They don't have 936 * "samAccountName" nor "userPrincipalName" attributes. Their names are 937 * available in "cn" and "name" attributes. Some of these principals have a 938 * second entry under CN=ForeignSecurityPrincipals,dc=<forestRootDomain> and 939 * these duplicate entries have the stringified SID in the "name" and "cn" 940 * attributes instead of the actual name. 941 * 942 * These principals remain constant across all operating systems. Using 943 * a hard-coded table here improves performance and avoids additional 944 * complexity in the AD lookup code in adutils.c 945 * 946 * Currently we don't support localization of well-known SID names, 947 * unlike Windows. 948 * 949 * Note that other well-known SIDs (i.e. S-1-5-<domain>-<w-k RID> and 950 * S-1-5-32-<w-k RID>) are not stored here because AD does have normal 951 * user/group objects for these objects and can be looked up using the 952 * existing AD lookup code. 953 */ 954 static wksids_table_t wksids[] = { 955 {"S-1-1", 0, "Everyone", 0, SENTINEL_PID, -1}, 956 {"S-1-3", 0, "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 0}, 957 {"S-1-3", 1, "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0}, 958 {"S-1-3", 2, "Creator Owner Server", 1, SENTINEL_PID, -1}, 959 {"S-1-3", 3, "Creator Group Server", 0, SENTINEL_PID, -1}, 960 {"S-1-5", 1, "Dialup", 0, SENTINEL_PID, -1}, 961 {"S-1-5", 2, "Network", 0, SENTINEL_PID, -1}, 962 {"S-1-5", 3, "Batch", 0, SENTINEL_PID, -1}, 963 {"S-1-5", 4, "Interactive", 0, SENTINEL_PID, -1}, 964 {"S-1-5", 6, "Service", 0, SENTINEL_PID, -1}, 965 {"S-1-5", 7, "Anonymous Logon", 0, GID_NOBODY, 0}, 966 {"S-1-5", 8, "Proxy", 0, SENTINEL_PID, -1}, 967 {"S-1-5", 9, "Enterprise Domain Controllers", 0, SENTINEL_PID, -1}, 968 {"S-1-5", 10, "Self", 0, SENTINEL_PID, -1}, 969 {"S-1-5", 11, "Authenticated Users", 0, SENTINEL_PID, -1}, 970 {"S-1-5", 12, "Restricted Code", 0, SENTINEL_PID, -1}, 971 {"S-1-5", 13, "Terminal Server User", 0, SENTINEL_PID, -1}, 972 {"S-1-5", 14, "Remote Interactive Logon", 0, SENTINEL_PID, -1}, 973 {"S-1-5", 15, "This Organization", 0, SENTINEL_PID, -1}, 974 {"S-1-5", 18, "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0}, 975 {"S-1-5", 19, "Local Service", 0, SENTINEL_PID, -1}, 976 {"S-1-5", 20, "Network Service", 0, SENTINEL_PID, -1}, 977 {"S-1-5", 1000, "Other Organization", 0, SENTINEL_PID, -1}, 978 {"S-1-5-64", 21, "Digest Authentication", 0, SENTINEL_PID, -1}, 979 {"S-1-5-64", 10, "NTLM Authentication", 0, SENTINEL_PID, -1}, 980 {"S-1-5-64", 14, "SChannel Authentication", 0, SENTINEL_PID, -1}, 981 {NULL, UINT32_MAX, NULL, -1, SENTINEL_PID, -1} 982 }; 983 984 static idmap_retcode 985 lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res) { 986 int i; 987 for (i = 0; wksids[i].sidprefix != NULL; i++) { 988 if (wksids[i].rid == req->id1.idmap_id_u.sid.rid && 989 (strcasecmp(wksids[i].sidprefix, 990 req->id1.idmap_id_u.sid.prefix) == 0)) { 991 992 if (wksids[i].pid == SENTINEL_PID) 993 /* Not mapped, break */ 994 break; 995 else if (wksids[i].direction == IDMAP_DIRECTION_U2W) 996 continue; 997 998 switch (req->id2.idtype) { 999 case IDMAP_UID: 1000 if (wksids[i].is_user == 0) 1001 continue; 1002 res->id.idmap_id_u.uid = wksids[i].pid; 1003 res->direction = wksids[i].direction; 1004 return (IDMAP_SUCCESS); 1005 case IDMAP_GID: 1006 if (wksids[i].is_user == 1) 1007 continue; 1008 res->id.idmap_id_u.gid = wksids[i].pid; 1009 res->direction = wksids[i].direction; 1010 return (IDMAP_SUCCESS); 1011 case IDMAP_POSIXID: 1012 res->id.idmap_id_u.uid = wksids[i].pid; 1013 res->id.idtype = (!wksids[i].is_user)? 1014 IDMAP_GID:IDMAP_UID; 1015 res->direction = wksids[i].direction; 1016 return (IDMAP_SUCCESS); 1017 default: 1018 return (IDMAP_ERR_NOTSUPPORTED); 1019 } 1020 } 1021 } 1022 return (IDMAP_ERR_NOTFOUND); 1023 } 1024 1025 static idmap_retcode 1026 lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user) { 1027 int i; 1028 if (req->id2.idtype != IDMAP_SID) 1029 return (IDMAP_ERR_NOTSUPPORTED); 1030 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1031 if (wksids[i].pid == req->id1.idmap_id_u.uid && 1032 wksids[i].is_user == is_user && 1033 wksids[i].direction != IDMAP_DIRECTION_W2U) { 1034 res->id.idmap_id_u.sid.rid = wksids[i].rid; 1035 res->id.idmap_id_u.sid.prefix = 1036 strdup(wksids[i].sidprefix); 1037 if (res->id.idmap_id_u.sid.prefix == NULL) { 1038 idmapdlog(LOG_ERR, "Out of memory"); 1039 return (IDMAP_ERR_MEMORY); 1040 } 1041 res->direction = wksids[i].direction; 1042 return (IDMAP_SUCCESS); 1043 } 1044 } 1045 return (IDMAP_ERR_NOTFOUND); 1046 } 1047 1048 static idmap_retcode 1049 lookup_wksids_sid2name(const char *sidprefix, idmap_rid_t rid, char **name, 1050 int *type) { 1051 int i; 1052 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1053 if ((strcasecmp(wksids[i].sidprefix, sidprefix) == 0) && 1054 wksids[i].rid == rid) { 1055 if ((*name = strdup(wksids[i].winname)) == NULL) { 1056 idmapdlog(LOG_ERR, "Out of memory"); 1057 return (IDMAP_ERR_MEMORY); 1058 } 1059 *type = (wksids[i].is_user)? 1060 _IDMAP_T_USER:_IDMAP_T_GROUP; 1061 return (IDMAP_SUCCESS); 1062 } 1063 } 1064 return (IDMAP_ERR_NOTFOUND); 1065 } 1066 1067 static idmap_retcode 1068 lookup_wksids_name2sid(const char *name, char **sidprefix, idmap_rid_t *rid, 1069 int *type) { 1070 int i; 1071 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1072 if (strcasecmp(wksids[i].winname, name) == 0) { 1073 if (sidprefix != NULL && (*sidprefix = 1074 strdup(wksids[i].sidprefix)) == NULL) { 1075 idmapdlog(LOG_ERR, "Out of memory"); 1076 return (IDMAP_ERR_MEMORY); 1077 } 1078 if (type != NULL) 1079 *type = (wksids[i].is_user)? 1080 _IDMAP_T_USER:_IDMAP_T_GROUP; 1081 if (rid != NULL) 1082 *rid = wksids[i].rid; 1083 return (IDMAP_SUCCESS); 1084 } 1085 } 1086 return (IDMAP_ERR_NOTFOUND); 1087 } 1088 1089 static idmap_retcode 1090 lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res) { 1091 char *end; 1092 char *sql = NULL; 1093 const char **values; 1094 sqlite_vm *vm = NULL; 1095 int ncol, is_user; 1096 uid_t pid; 1097 idmap_utf8str *str; 1098 time_t curtime, exp; 1099 idmap_retcode retcode; 1100 1101 /* Current time */ 1102 errno = 0; 1103 if ((curtime = time(NULL)) == (time_t)-1) { 1104 idmapdlog(LOG_ERR, 1105 "Failed to get current time (%s)", 1106 strerror(errno)); 1107 retcode = IDMAP_ERR_INTERNAL; 1108 goto out; 1109 } 1110 1111 /* SQL to lookup the cache */ 1112 sql = sqlite_mprintf("SELECT pid, is_user, expiration, unixname, u2w " 1113 "FROM idmap_cache WHERE " 1114 "sidprefix = %Q AND rid = %u AND w2u = 1 AND " 1115 "(pid >= 2147483648 OR " 1116 "(expiration = 0 OR expiration ISNULL OR " 1117 "expiration > %d));", 1118 req->id1.idmap_id_u.sid.prefix, 1119 req->id1.idmap_id_u.sid.rid, 1120 curtime); 1121 if (sql == NULL) { 1122 idmapdlog(LOG_ERR, "Out of memory"); 1123 retcode = IDMAP_ERR_MEMORY; 1124 goto out; 1125 } 1126 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values); 1127 sqlite_freemem(sql); 1128 1129 if (retcode == IDMAP_ERR_NOTFOUND) { 1130 goto out; 1131 } else if (retcode == IDMAP_SUCCESS) { 1132 /* sanity checks */ 1133 if (values[0] == NULL || values[1] == NULL) { 1134 retcode = IDMAP_ERR_CACHE; 1135 goto out; 1136 } 1137 1138 pid = strtoul(values[0], &end, 10); 1139 is_user = strncmp(values[1], "0", 2)?1:0; 1140 1141 /* 1142 * We may have an expired ephemeral mapping. Consider 1143 * the expired entry as valid if we are not going to 1144 * perform name-based mapping. But do not renew the 1145 * expiration. 1146 * If we will be doing name-based mapping then store the 1147 * ephemeral pid in the result so that we can use it 1148 * if we end up doing dynamic mapping again. 1149 */ 1150 if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) && 1151 !AVOID_NAMESERVICE(req)) { 1152 if (IS_EPHEMERAL(pid) && values[2] != NULL) { 1153 exp = strtoll(values[2], &end, 10); 1154 if (exp && exp <= curtime) { 1155 /* Store the ephemeral pid */ 1156 res->id.idmap_id_u.uid = pid; 1157 res->id.idtype = is_user? 1158 IDMAP_UID:IDMAP_GID; 1159 res->direction = IDMAP_DIRECTION_BI; 1160 req->direction |= is_user? 1161 _IDMAP_F_EXP_EPH_UID: 1162 _IDMAP_F_EXP_EPH_GID; 1163 retcode = IDMAP_ERR_NOTFOUND; 1164 goto out; 1165 } 1166 } 1167 } 1168 1169 switch (req->id2.idtype) { 1170 case IDMAP_UID: 1171 if (!is_user) 1172 retcode = IDMAP_ERR_NOTUSER; 1173 else 1174 res->id.idmap_id_u.uid = pid; 1175 break; 1176 case IDMAP_GID: 1177 if (is_user) 1178 retcode = IDMAP_ERR_NOTGROUP; 1179 else 1180 res->id.idmap_id_u.gid = pid; 1181 break; 1182 case IDMAP_POSIXID: 1183 res->id.idmap_id_u.uid = pid; 1184 res->id.idtype = (is_user)?IDMAP_UID:IDMAP_GID; 1185 break; 1186 default: 1187 retcode = IDMAP_ERR_NOTSUPPORTED; 1188 break; 1189 } 1190 } 1191 1192 out: 1193 if (retcode == IDMAP_SUCCESS) { 1194 if (values[4] != NULL) 1195 res->direction = 1196 (strtol(values[4], &end, 10) == 0)? 1197 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; 1198 else 1199 res->direction = IDMAP_DIRECTION_W2U; 1200 1201 if (values[3] != NULL) { 1202 str = &req->id2name; 1203 retcode = idmap_str2utf8(&str, values[3], 0); 1204 if (retcode != IDMAP_SUCCESS) { 1205 idmapdlog(LOG_ERR, "Out of memory"); 1206 retcode = IDMAP_ERR_MEMORY; 1207 } 1208 } 1209 } 1210 if (vm != NULL) 1211 (void) sqlite_finalize(vm, NULL); 1212 return (retcode); 1213 } 1214 1215 static idmap_retcode 1216 lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid, 1217 char **name, char **domain, int *type) { 1218 char *end; 1219 char *sql = NULL; 1220 const char **values; 1221 sqlite_vm *vm = NULL; 1222 int ncol; 1223 time_t curtime; 1224 idmap_retcode retcode = IDMAP_SUCCESS; 1225 1226 /* Get current time */ 1227 errno = 0; 1228 if ((curtime = time(NULL)) == (time_t)-1) { 1229 idmapdlog(LOG_ERR, 1230 "Failed to get current time (%s)", 1231 strerror(errno)); 1232 retcode = IDMAP_ERR_INTERNAL; 1233 goto out; 1234 } 1235 1236 /* SQL to lookup the cache */ 1237 sql = sqlite_mprintf("SELECT name, domain, type FROM name_cache WHERE " 1238 "sidprefix = %Q AND rid = %u AND " 1239 "(expiration = 0 OR expiration ISNULL OR " 1240 "expiration > %d);", 1241 sidprefix, rid, curtime); 1242 if (sql == NULL) { 1243 idmapdlog(LOG_ERR, "Out of memory"); 1244 retcode = IDMAP_ERR_MEMORY; 1245 goto out; 1246 } 1247 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values); 1248 sqlite_freemem(sql); 1249 1250 if (retcode == IDMAP_SUCCESS) { 1251 if (type != NULL) { 1252 if (values[2] == NULL) { 1253 retcode = IDMAP_ERR_CACHE; 1254 goto out; 1255 } 1256 *type = strtol(values[2], &end, 10); 1257 } 1258 1259 if (name != NULL && values[0] != NULL) { 1260 if ((*name = strdup(values[0])) == NULL) { 1261 idmapdlog(LOG_ERR, "Out of memory"); 1262 retcode = IDMAP_ERR_MEMORY; 1263 goto out; 1264 } 1265 } 1266 1267 if (domain != NULL && values[1] != NULL) { 1268 if ((*domain = strdup(values[1])) == NULL) { 1269 if (name != NULL && *name) { 1270 free(*name); 1271 *name = NULL; 1272 } 1273 idmapdlog(LOG_ERR, "Out of memory"); 1274 retcode = IDMAP_ERR_MEMORY; 1275 goto out; 1276 } 1277 } 1278 } 1279 1280 out: 1281 if (vm != NULL) 1282 (void) sqlite_finalize(vm, NULL); 1283 return (retcode); 1284 } 1285 1286 static idmap_retcode 1287 verify_type(idmap_id_type idtype, int type, idmap_id_res *res) { 1288 switch (idtype) { 1289 case IDMAP_UID: 1290 if (type != _IDMAP_T_USER) 1291 return (IDMAP_ERR_NOTUSER); 1292 res->id.idtype = IDMAP_UID; 1293 break; 1294 case IDMAP_GID: 1295 if (type != _IDMAP_T_GROUP) 1296 return (IDMAP_ERR_NOTGROUP); 1297 res->id.idtype = IDMAP_GID; 1298 break; 1299 case IDMAP_POSIXID: 1300 if (type == _IDMAP_T_USER) 1301 res->id.idtype = IDMAP_UID; 1302 else if (type == _IDMAP_T_GROUP) 1303 res->id.idtype = IDMAP_GID; 1304 else 1305 return (IDMAP_ERR_SID); 1306 break; 1307 default: 1308 return (IDMAP_ERR_NOTSUPPORTED); 1309 } 1310 return (IDMAP_SUCCESS); 1311 } 1312 1313 /* 1314 * Lookup sid to name locally 1315 */ 1316 static idmap_retcode 1317 lookup_local_sid2name(sqlite *cache, idmap_mapping *req, idmap_id_res *res) { 1318 int type = -1; 1319 idmap_retcode retcode; 1320 char *sidprefix; 1321 idmap_rid_t rid; 1322 char *name = NULL, *domain = NULL; 1323 idmap_utf8str *str; 1324 1325 sidprefix = req->id1.idmap_id_u.sid.prefix; 1326 rid = req->id1.idmap_id_u.sid.rid; 1327 1328 /* Lookup sids to name in well-known sids table */ 1329 retcode = lookup_wksids_sid2name(sidprefix, rid, &name, &type); 1330 if (retcode != IDMAP_ERR_NOTFOUND) 1331 goto out; 1332 1333 /* Lookup sid to name in cache */ 1334 retcode = lookup_cache_sid2name(cache, sidprefix, rid, &name, 1335 &domain, &type); 1336 if (retcode != IDMAP_SUCCESS) 1337 goto out; 1338 1339 out: 1340 if (retcode == IDMAP_SUCCESS) { 1341 /* Verify that the sid type matches the request */ 1342 retcode = verify_type(req->id2.idtype, type, res); 1343 1344 /* update state in 'req' */ 1345 if (name != NULL) { 1346 str = &req->id1name; 1347 (void) idmap_str2utf8(&str, name, 1); 1348 } 1349 if (domain != NULL) { 1350 str = &req->id1domain; 1351 (void) idmap_str2utf8(&str, domain, 1); 1352 } 1353 } else { 1354 if (name != NULL) 1355 free(name); 1356 if (domain != NULL) 1357 free(domain); 1358 } 1359 return (retcode); 1360 } 1361 1362 idmap_retcode 1363 lookup_win_batch_sid2name(lookup_state_t *state, idmap_mapping_batch *batch, 1364 idmap_ids_res *result) { 1365 idmap_retcode retcode; 1366 int ret, i; 1367 int retries = 0; 1368 idmap_mapping *req; 1369 idmap_id_res *res; 1370 1371 if (state->ad_nqueries == 0) 1372 return (IDMAP_SUCCESS); 1373 1374 retry: 1375 ret = idmap_lookup_batch_start(_idmapdstate.ad, state->ad_nqueries, 1376 &state->ad_lookup); 1377 if (ret != 0) { 1378 idmapdlog(LOG_ERR, 1379 "Failed to create sid2name batch for AD lookup"); 1380 return (IDMAP_ERR_INTERNAL); 1381 } 1382 1383 for (i = 0; i < batch->idmap_mapping_batch_len; i++) { 1384 req = &batch->idmap_mapping_batch_val[i]; 1385 res = &result->ids.ids_val[i]; 1386 1387 if (req->id1.idtype == IDMAP_SID && 1388 req->direction & _IDMAP_F_S2N_AD) { 1389 if (retries == 0) 1390 res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 1391 else if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR) 1392 continue; 1393 retcode = idmap_sid2name_batch_add1( 1394 state->ad_lookup, 1395 req->id1.idmap_id_u.sid.prefix, 1396 &req->id1.idmap_id_u.sid.rid, 1397 &req->id1name.idmap_utf8str_val, 1398 &req->id1domain.idmap_utf8str_val, 1399 (int *)&res->id.idtype, 1400 &res->retcode); 1401 1402 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 1403 break; 1404 if (retcode != IDMAP_SUCCESS) 1405 goto out; 1406 } 1407 } 1408 1409 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 1410 idmap_lookup_release_batch(&state->ad_lookup); 1411 else 1412 retcode = idmap_lookup_batch_end(&state->ad_lookup, NULL); 1413 1414 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 1415 goto retry; 1416 1417 return (retcode); 1418 1419 out: 1420 idmapdlog(LOG_NOTICE, "Windows SID to user/group name lookup failed"); 1421 idmap_lookup_release_batch(&state->ad_lookup); 1422 return (retcode); 1423 } 1424 1425 idmap_retcode 1426 sid2pid_first_pass(lookup_state_t *state, sqlite *cache, idmap_mapping *req, 1427 idmap_id_res *res) { 1428 idmap_retcode retcode; 1429 1430 /* 1431 * The req->direction field is used to maintain state of the 1432 * sid2pid request. 1433 */ 1434 req->direction = _IDMAP_F_DONE; 1435 1436 if (req->id1.idmap_id_u.sid.prefix == NULL) { 1437 retcode = IDMAP_ERR_SID; 1438 goto out; 1439 } 1440 res->id.idtype = req->id2.idtype; 1441 res->id.idmap_id_u.uid = UID_NOBODY; 1442 1443 /* Lookup well-known sid to pid mapping */ 1444 retcode = lookup_wksids_sid2pid(req, res); 1445 if (retcode != IDMAP_ERR_NOTFOUND) 1446 goto out; 1447 1448 /* Lookup sid to pid in cache */ 1449 retcode = lookup_cache_sid2pid(cache, req, res); 1450 if (retcode != IDMAP_ERR_NOTFOUND) 1451 goto out; 1452 1453 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) { 1454 res->id.idmap_id_u.uid = SENTINEL_PID; 1455 goto out; 1456 } 1457 1458 /* 1459 * Failed to find non-expired entry in cache. Tell the caller 1460 * that we are not done yet. 1461 */ 1462 state->sid2pid_done = FALSE; 1463 1464 /* 1465 * Our next step is name-based mapping. To lookup name-based 1466 * mapping rules, we need the windows name and domain-name 1467 * associated with the SID. 1468 */ 1469 1470 /* 1471 * Check if we already have the name (i.e name2pid lookups) 1472 */ 1473 if (req->id1name.idmap_utf8str_val != NULL && 1474 req->id1domain.idmap_utf8str_val != NULL) { 1475 retcode = IDMAP_SUCCESS; 1476 req->direction |= _IDMAP_F_S2N_CACHE; 1477 goto out; 1478 } 1479 1480 /* Lookup sid to winname@domain locally first */ 1481 retcode = lookup_local_sid2name(cache, req, res); 1482 if (retcode == IDMAP_SUCCESS) { 1483 req->direction |= _IDMAP_F_S2N_CACHE; 1484 } else if (retcode == IDMAP_ERR_NOTFOUND) { 1485 /* Batch sid to name AD lookup request */ 1486 retcode = IDMAP_SUCCESS; 1487 req->direction |= _IDMAP_F_S2N_AD; 1488 state->ad_nqueries++; 1489 goto out; 1490 } 1491 1492 1493 out: 1494 res->retcode = idmap_stat4prot(retcode); 1495 return (retcode); 1496 } 1497 1498 /* 1499 * Generate SID using the following convention 1500 * <machine-sid-prefix>-<1000 + uid> 1501 * <machine-sid-prefix>-<2^31 + gid> 1502 */ 1503 static idmap_retcode 1504 generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user) { 1505 1506 if (_idmapdstate.cfg->pgcfg.machine_sid != NULL) { 1507 /* Skip 1000 UIDs */ 1508 if (is_user && req->id1.idmap_id_u.uid > 1509 (INT32_MAX - LOCALRID_MIN)) 1510 return (IDMAP_ERR_NOMAPPING); 1511 1512 RDLOCK_CONFIG(); 1513 res->id.idmap_id_u.sid.prefix = 1514 strdup(_idmapdstate.cfg->pgcfg.machine_sid); 1515 if (res->id.idmap_id_u.sid.prefix == NULL) { 1516 UNLOCK_CONFIG(); 1517 idmapdlog(LOG_ERR, "Out of memory"); 1518 return (IDMAP_ERR_MEMORY); 1519 } 1520 UNLOCK_CONFIG(); 1521 res->id.idmap_id_u.sid.rid = 1522 (is_user)?req->id1.idmap_id_u.uid + LOCALRID_MIN: 1523 req->id1.idmap_id_u.gid + INT32_MAX + 1; 1524 res->direction = IDMAP_DIRECTION_BI; 1525 1526 /* 1527 * Don't update name_cache because local sids don't have 1528 * valid windows names. 1529 * We mark the entry as being found in the namecache so that 1530 * the cache update routine doesn't update namecache. 1531 */ 1532 req->direction = _IDMAP_F_S2N_CACHE; 1533 return (IDMAP_SUCCESS); 1534 } 1535 1536 return (IDMAP_ERR_NOMAPPING); 1537 } 1538 1539 static idmap_retcode 1540 lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res) { 1541 char *sidprefix; 1542 uint32_t rid; 1543 int s; 1544 1545 /* 1546 * If the sidprefix == localsid then UID = last RID - 1000 or 1547 * GID = last RID - 2^31. 1548 */ 1549 sidprefix = req->id1.idmap_id_u.sid.prefix; 1550 rid = req->id1.idmap_id_u.sid.rid; 1551 1552 RDLOCK_CONFIG(); 1553 s = (_idmapdstate.cfg->pgcfg.machine_sid)? 1554 strcasecmp(sidprefix, 1555 _idmapdstate.cfg->pgcfg.machine_sid):1; 1556 UNLOCK_CONFIG(); 1557 1558 if (s == 0) { 1559 switch (req->id2.idtype) { 1560 case IDMAP_UID: 1561 if (rid > INT32_MAX) { 1562 return (IDMAP_ERR_NOTUSER); 1563 } else if (rid < LOCALRID_MIN) { 1564 return (IDMAP_ERR_NOTFOUND); 1565 } 1566 res->id.idmap_id_u.uid = rid - LOCALRID_MIN; 1567 res->id.idtype = IDMAP_UID; 1568 break; 1569 case IDMAP_GID: 1570 if (rid <= INT32_MAX) { 1571 return (IDMAP_ERR_NOTGROUP); 1572 } 1573 res->id.idmap_id_u.gid = rid - INT32_MAX - 1; 1574 res->id.idtype = IDMAP_GID; 1575 break; 1576 case IDMAP_POSIXID: 1577 if (rid > INT32_MAX) { 1578 res->id.idmap_id_u.gid = 1579 rid - INT32_MAX - 1; 1580 res->id.idtype = IDMAP_GID; 1581 } else if (rid < LOCALRID_MIN) { 1582 return (IDMAP_ERR_NOTFOUND); 1583 } else { 1584 res->id.idmap_id_u.uid = rid - LOCALRID_MIN; 1585 res->id.idtype = IDMAP_UID; 1586 } 1587 break; 1588 default: 1589 return (IDMAP_ERR_NOTSUPPORTED); 1590 } 1591 return (IDMAP_SUCCESS); 1592 } 1593 1594 return (IDMAP_ERR_NOTFOUND); 1595 } 1596 1597 static idmap_retcode 1598 ns_lookup_byname(int is_user, const char *name, idmap_id_res *res) { 1599 struct passwd pwd; 1600 struct group grp; 1601 char buf[1024]; 1602 int errnum; 1603 const char *me = "ns_lookup_byname"; 1604 1605 if (is_user) { 1606 if (getpwnam_r(name, &pwd, buf, sizeof (buf)) == NULL) { 1607 errnum = errno; 1608 idmapdlog(LOG_WARNING, 1609 "%s: getpwnam_r(%s) failed (%s).", 1610 me, name, 1611 errnum?strerror(errnum):"not found"); 1612 if (errnum == 0) 1613 return (IDMAP_ERR_NOTFOUND); 1614 else 1615 return (IDMAP_ERR_INTERNAL); 1616 } 1617 res->id.idmap_id_u.uid = pwd.pw_uid; 1618 res->id.idtype = IDMAP_UID; 1619 } else { 1620 if (getgrnam_r(name, &grp, buf, sizeof (buf)) == NULL) { 1621 errnum = errno; 1622 idmapdlog(LOG_WARNING, 1623 "%s: getgrnam_r(%s) failed (%s).", 1624 me, name, 1625 errnum?strerror(errnum):"not found"); 1626 if (errnum == 0) 1627 return (IDMAP_ERR_NOTFOUND); 1628 else 1629 return (IDMAP_ERR_INTERNAL); 1630 } 1631 res->id.idmap_id_u.gid = grp.gr_gid; 1632 res->id.idtype = IDMAP_GID; 1633 } 1634 return (IDMAP_SUCCESS); 1635 } 1636 1637 /* 1638 * Name-based mapping 1639 * 1640 * Case 1: If no rule matches do ephemeral 1641 * 1642 * Case 2: If rule matches and unixname is "" then return no mapping. 1643 * 1644 * Case 3: If rule matches and unixname is specified then lookup name 1645 * service using the unixname. If unixname not found then return no mapping. 1646 * 1647 * Case 4: If rule matches and unixname is * then lookup name service 1648 * using winname as the unixname. If unixname not found then process 1649 * other rules using the lookup order. If no other rule matches then do 1650 * ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4. 1651 * This allows us to specify a fallback unixname per _domain_ or no mapping 1652 * instead of the default behaviour of doing ephemeral mapping. 1653 * 1654 * Example 1: 1655 * *@sfbay == * 1656 * If looking up windows users foo@sfbay and foo does not exists in 1657 * the name service then foo@sfbay will be mapped to an ephemeral id. 1658 * 1659 * Example 2: 1660 * *@sfbay == * 1661 * *@sfbay => guest 1662 * If looking up windows users foo@sfbay and foo does not exists in 1663 * the name service then foo@sfbay will be mapped to guest. 1664 * 1665 * Example 3: 1666 * *@sfbay == * 1667 * *@sfbay => "" 1668 * If looking up windows users foo@sfbay and foo does not exists in 1669 * the name service then we will return no mapping for foo@sfbay. 1670 * 1671 */ 1672 static idmap_retcode 1673 name_based_mapping_sid2pid(sqlite *db, idmap_mapping *req, idmap_id_res *res) { 1674 const char *unixname, *winname, *windomain; 1675 char *sql = NULL, *errmsg = NULL; 1676 idmap_retcode retcode; 1677 char *end; 1678 const char **values; 1679 sqlite_vm *vm = NULL; 1680 idmap_utf8str *str; 1681 int ncol, r, i, is_user; 1682 const char *me = "name_based_mapping_sid2pid"; 1683 1684 winname = req->id1name.idmap_utf8str_val; 1685 windomain = req->id1domain.idmap_utf8str_val; 1686 is_user = (res->id.idtype == IDMAP_UID)?1:0; 1687 1688 i = 0; 1689 if (windomain == NULL) { 1690 windomain = ""; 1691 } else { 1692 RDLOCK_CONFIG(); 1693 if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) { 1694 if (strcasecmp(_idmapdstate.cfg->pgcfg.mapping_domain, 1695 windomain) == 0) 1696 i = 1; 1697 } 1698 UNLOCK_CONFIG(); 1699 } 1700 1701 sql = sqlite_mprintf( 1702 "SELECT unixname, u2w_order FROM namerules WHERE " 1703 "w2u_order > 0 AND is_user = %d AND " 1704 "(winname = %Q OR winname = '*') AND " 1705 "(windomain = %Q OR windomain = '*' %s) " 1706 "ORDER BY w2u_order ASC;", 1707 is_user, winname, 1708 windomain, 1709 i?"OR windomain ISNULL OR windomain = ''":""); 1710 if (sql == NULL) { 1711 idmapdlog(LOG_ERR, "Out of memory"); 1712 retcode = IDMAP_ERR_MEMORY; 1713 goto out; 1714 } 1715 1716 if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) { 1717 retcode = IDMAP_ERR_INTERNAL; 1718 idmapdlog(LOG_ERR, 1719 "%s: database error (%s)", 1720 me, CHECK_NULL(errmsg)); 1721 sqlite_freemem(errmsg); 1722 goto out; 1723 } 1724 1725 for (; ; ) { 1726 r = sqlite_step(vm, &ncol, &values, NULL); 1727 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 1728 1729 if (r == SQLITE_ROW) { 1730 if (ncol < 2) { 1731 retcode = IDMAP_ERR_INTERNAL; 1732 goto out; 1733 } 1734 if (values[0] == NULL) { 1735 retcode = IDMAP_ERR_INTERNAL; 1736 goto out; 1737 } 1738 1739 if (EMPTY_NAME(values[0])) { 1740 retcode = IDMAP_ERR_NOMAPPING; 1741 goto out; 1742 } 1743 unixname = (values[0][0] == '*')?winname:values[0]; 1744 retcode = ns_lookup_byname(is_user, unixname, res); 1745 if (retcode == IDMAP_ERR_NOTFOUND) { 1746 if (unixname == winname) 1747 /* Case 4 */ 1748 continue; 1749 else 1750 /* Case 3 */ 1751 retcode = IDMAP_ERR_NOMAPPING; 1752 } 1753 goto out; 1754 } else if (r == SQLITE_DONE) { 1755 retcode = IDMAP_ERR_NOTFOUND; 1756 goto out; 1757 } else { 1758 (void) sqlite_finalize(vm, &errmsg); 1759 vm = NULL; 1760 idmapdlog(LOG_ERR, 1761 "%s: database error (%s)", 1762 me, CHECK_NULL(errmsg)); 1763 sqlite_freemem(errmsg); 1764 retcode = IDMAP_ERR_INTERNAL; 1765 goto out; 1766 } 1767 } 1768 1769 out: 1770 if (sql != NULL) 1771 sqlite_freemem(sql); 1772 if (retcode == IDMAP_SUCCESS) { 1773 if (values[1] != NULL) 1774 res->direction = 1775 (strtol(values[1], &end, 10) == 0)? 1776 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; 1777 else 1778 res->direction = IDMAP_DIRECTION_W2U; 1779 str = &req->id2name; 1780 retcode = idmap_str2utf8(&str, unixname, 0); 1781 } 1782 if (vm != NULL) 1783 (void) sqlite_finalize(vm, NULL); 1784 return (retcode); 1785 } 1786 1787 static 1788 int 1789 get_next_eph_uid(uid_t *next_uid) 1790 { 1791 uid_t uid; 1792 gid_t gid; 1793 int err; 1794 1795 *next_uid = (uid_t)-1; 1796 uid = _idmapdstate.next_uid++; 1797 if (uid >= _idmapdstate.limit_uid) { 1798 if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0) 1799 return (err); 1800 1801 _idmapdstate.limit_uid = uid + 8192; 1802 _idmapdstate.next_uid = uid; 1803 } 1804 *next_uid = uid; 1805 1806 return (0); 1807 } 1808 1809 static 1810 int 1811 get_next_eph_gid(gid_t *next_gid) 1812 { 1813 uid_t uid; 1814 gid_t gid; 1815 int err; 1816 1817 *next_gid = (uid_t)-1; 1818 gid = _idmapdstate.next_gid++; 1819 if (gid >= _idmapdstate.limit_gid) { 1820 if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0) 1821 return (err); 1822 1823 _idmapdstate.limit_gid = gid + 8192; 1824 _idmapdstate.next_gid = gid; 1825 } 1826 *next_gid = gid; 1827 1828 return (0); 1829 } 1830 1831 static 1832 int 1833 gethash(const char *str, uint32_t num, uint_t htsize) { 1834 uint_t hval, i, len; 1835 1836 if (str == NULL) 1837 return (0); 1838 for (len = strlen(str), hval = 0, i = 0; i < len; i++) { 1839 hval += str[i]; 1840 hval += (hval << 10); 1841 hval ^= (hval >> 6); 1842 } 1843 for (str = (const char *)&num, i = 0; i < sizeof (num); i++) { 1844 hval += str[i]; 1845 hval += (hval << 10); 1846 hval ^= (hval >> 6); 1847 } 1848 hval += (hval << 3); 1849 hval ^= (hval >> 11); 1850 hval += (hval << 15); 1851 return (hval % htsize); 1852 } 1853 1854 static 1855 int 1856 get_from_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid, 1857 uid_t *pid) { 1858 uint_t next, key; 1859 uint_t htsize = state->sid_history_size; 1860 idmap_sid *sid; 1861 1862 next = gethash(prefix, rid, htsize); 1863 while (next != htsize) { 1864 key = state->sid_history[next].key; 1865 if (key == htsize) 1866 return (0); 1867 sid = &state->batch->idmap_mapping_batch_val[key].id1. 1868 idmap_id_u.sid; 1869 if (sid->rid == rid && strcmp(sid->prefix, prefix) == 0) { 1870 *pid = state->result->ids.ids_val[key].id. 1871 idmap_id_u.uid; 1872 return (1); 1873 } 1874 next = state->sid_history[next].next; 1875 } 1876 return (0); 1877 } 1878 1879 static 1880 void 1881 add_to_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid) { 1882 uint_t hash, next; 1883 uint_t htsize = state->sid_history_size; 1884 1885 hash = next = gethash(prefix, rid, htsize); 1886 while (state->sid_history[next].key != htsize) { 1887 next++; 1888 next %= htsize; 1889 } 1890 state->sid_history[next].key = state->curpos; 1891 if (hash == next) 1892 return; 1893 state->sid_history[next].next = state->sid_history[hash].next; 1894 state->sid_history[hash].next = next; 1895 } 1896 1897 /* ARGSUSED */ 1898 static 1899 idmap_retcode 1900 dynamic_ephemeral_mapping(lookup_state_t *state, sqlite *cache, 1901 idmap_mapping *req, idmap_id_res *res) { 1902 1903 uid_t next_pid; 1904 1905 res->direction = IDMAP_DIRECTION_BI; 1906 1907 if (IS_EPHEMERAL(res->id.idmap_id_u.uid)) 1908 return (IDMAP_SUCCESS); 1909 1910 if (state->sid_history != NULL && 1911 get_from_sid_history(state, req->id1.idmap_id_u.sid.prefix, 1912 req->id1.idmap_id_u.sid.rid, &next_pid)) { 1913 res->id.idmap_id_u.uid = next_pid; 1914 return (IDMAP_SUCCESS); 1915 } 1916 1917 if (res->id.idtype == IDMAP_UID) { 1918 if (get_next_eph_uid(&next_pid) != 0) 1919 return (IDMAP_ERR_INTERNAL); 1920 res->id.idmap_id_u.uid = next_pid; 1921 } else { 1922 if (get_next_eph_gid(&next_pid) != 0) 1923 return (IDMAP_ERR_INTERNAL); 1924 res->id.idmap_id_u.gid = next_pid; 1925 } 1926 1927 if (state->sid_history != NULL) 1928 add_to_sid_history(state, req->id1.idmap_id_u.sid.prefix, 1929 req->id1.idmap_id_u.sid.rid); 1930 1931 return (IDMAP_SUCCESS); 1932 } 1933 1934 idmap_retcode 1935 sid2pid_second_pass(lookup_state_t *state, sqlite *cache, sqlite *db, 1936 idmap_mapping *req, idmap_id_res *res) { 1937 idmap_retcode retcode; 1938 1939 /* 1940 * The req->direction field is used to maintain state of the 1941 * sid2pid request. 1942 */ 1943 1944 /* Check if second pass is needed */ 1945 if (req->direction == _IDMAP_F_DONE) 1946 return (res->retcode); 1947 1948 /* Get status from previous pass */ 1949 retcode = (res->retcode == IDMAP_NEXT)?IDMAP_SUCCESS:res->retcode; 1950 1951 if (retcode != IDMAP_SUCCESS) { 1952 /* Reset return type */ 1953 res->id.idtype = req->id2.idtype; 1954 res->id.idmap_id_u.uid = UID_NOBODY; 1955 1956 /* Check if this is a localsid */ 1957 if (retcode == IDMAP_ERR_NOTFOUND && 1958 _idmapdstate.cfg->pgcfg.machine_sid) { 1959 retcode = lookup_localsid2pid(req, res); 1960 if (retcode == IDMAP_SUCCESS) { 1961 state->sid2pid_done = FALSE; 1962 req->direction = _IDMAP_F_S2N_CACHE; 1963 } 1964 } 1965 goto out; 1966 } 1967 1968 /* 1969 * Verify that the sid type matches the request if the 1970 * SID was validated by an AD lookup. 1971 */ 1972 if (req->direction & _IDMAP_F_S2N_AD) { 1973 retcode = verify_type(req->id2.idtype, 1974 (int)res->id.idtype, res); 1975 if (retcode != IDMAP_SUCCESS) { 1976 res->id.idtype = req->id2.idtype; 1977 res->id.idmap_id_u.uid = UID_NOBODY; 1978 goto out; 1979 } 1980 } 1981 1982 /* Name-based mapping */ 1983 retcode = name_based_mapping_sid2pid(db, req, res); 1984 if (retcode == IDMAP_ERR_NOTFOUND) 1985 /* If not found, do ephemeral mapping */ 1986 goto ephemeral; 1987 else if (retcode != IDMAP_SUCCESS) 1988 goto out; 1989 1990 state->sid2pid_done = FALSE; 1991 goto out; 1992 1993 1994 ephemeral: 1995 retcode = dynamic_ephemeral_mapping(state, cache, req, res); 1996 if (retcode == IDMAP_SUCCESS) 1997 state->sid2pid_done = FALSE; 1998 1999 out: 2000 res->retcode = idmap_stat4prot(retcode); 2001 return (retcode); 2002 } 2003 2004 idmap_retcode 2005 update_cache_pid2sid(lookup_state_t *state, sqlite *cache, 2006 idmap_mapping *req, idmap_id_res *res) { 2007 char *sql = NULL; 2008 idmap_retcode retcode; 2009 2010 /* Check if we need to cache anything */ 2011 if (req->direction == _IDMAP_F_DONE) 2012 return (IDMAP_SUCCESS); 2013 2014 /* We don't cache negative entries */ 2015 if (res->retcode != IDMAP_SUCCESS) 2016 return (IDMAP_SUCCESS); 2017 2018 /* 2019 * Using NULL for u2w instead of 0 so that our trigger allows 2020 * the same pid to be the destination in multiple entries 2021 */ 2022 sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache " 2023 "(sidprefix, rid, windomain, winname, pid, unixname, " 2024 "is_user, expiration, w2u, u2w) " 2025 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, " 2026 "strftime('%%s','now') + 600, %q, 1); ", 2027 res->id.idmap_id_u.sid.prefix, 2028 res->id.idmap_id_u.sid.rid, 2029 req->id2domain.idmap_utf8str_val, 2030 req->id2name.idmap_utf8str_val, 2031 req->id1.idmap_id_u.uid, 2032 req->id1name.idmap_utf8str_val, 2033 (req->id1.idtype == IDMAP_UID)?1:0, 2034 (res->direction == 0)?"1":NULL); 2035 2036 if (sql == NULL) { 2037 retcode = IDMAP_ERR_INTERNAL; 2038 idmapdlog(LOG_ERR, "Out of memory"); 2039 goto out; 2040 } 2041 2042 retcode = sql_exec_no_cb(cache, sql); 2043 if (retcode != IDMAP_SUCCESS) 2044 goto out; 2045 2046 state->pid2sid_done = FALSE; 2047 sqlite_freemem(sql); 2048 sql = NULL; 2049 2050 /* If sid2name was found in the cache, no need to update namecache */ 2051 if (req->direction & _IDMAP_F_S2N_CACHE) 2052 goto out; 2053 2054 if (req->id2name.idmap_utf8str_val == NULL) 2055 goto out; 2056 2057 sql = sqlite_mprintf("INSERT OR REPLACE into name_cache " 2058 "(sidprefix, rid, name, domain, type, expiration) " 2059 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ", 2060 res->id.idmap_id_u.sid.prefix, 2061 res->id.idmap_id_u.sid.rid, 2062 req->id2name.idmap_utf8str_val, 2063 req->id2domain.idmap_utf8str_val, 2064 (req->id1.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP); 2065 2066 if (sql == NULL) { 2067 retcode = IDMAP_ERR_INTERNAL; 2068 idmapdlog(LOG_ERR, "Out of memory"); 2069 goto out; 2070 } 2071 2072 retcode = sql_exec_no_cb(cache, sql); 2073 2074 out: 2075 if (sql != NULL) 2076 sqlite_freemem(sql); 2077 return (retcode); 2078 } 2079 2080 idmap_retcode 2081 update_cache_sid2pid(lookup_state_t *state, sqlite *cache, 2082 idmap_mapping *req, idmap_id_res *res) { 2083 char *sql = NULL; 2084 idmap_retcode retcode; 2085 int is_eph_user; 2086 2087 /* Check if we need to cache anything */ 2088 if (req->direction == _IDMAP_F_DONE) 2089 return (IDMAP_SUCCESS); 2090 2091 /* We don't cache negative entries */ 2092 if (res->retcode != IDMAP_SUCCESS) 2093 return (IDMAP_SUCCESS); 2094 2095 if (req->direction & _IDMAP_F_EXP_EPH_UID) 2096 is_eph_user = 1; 2097 else if (req->direction & _IDMAP_F_EXP_EPH_GID) 2098 is_eph_user = 0; 2099 else 2100 is_eph_user = -1; 2101 2102 if (is_eph_user >= 0 && !IS_EPHEMERAL(res->id.idmap_id_u.uid)) { 2103 sql = sqlite_mprintf("UPDATE idmap_cache " 2104 "SET w2u = 0 WHERE " 2105 "sidprefix = %Q AND rid = %u AND w2u = 1 AND " 2106 "pid >= 2147483648 AND is_user = %d;", 2107 req->id1.idmap_id_u.sid.prefix, 2108 req->id1.idmap_id_u.sid.rid, 2109 is_eph_user); 2110 if (sql == NULL) { 2111 retcode = IDMAP_ERR_INTERNAL; 2112 idmapdlog(LOG_ERR, "Out of memory"); 2113 goto out; 2114 } 2115 2116 retcode = sql_exec_no_cb(cache, sql); 2117 if (retcode != IDMAP_SUCCESS) 2118 goto out; 2119 2120 sqlite_freemem(sql); 2121 sql = NULL; 2122 } 2123 2124 sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache " 2125 "(sidprefix, rid, windomain, winname, pid, unixname, " 2126 "is_user, expiration, w2u, u2w) " 2127 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, " 2128 "strftime('%%s','now') + 600, 1, %q); ", 2129 req->id1.idmap_id_u.sid.prefix, 2130 req->id1.idmap_id_u.sid.rid, 2131 req->id1domain.idmap_utf8str_val, 2132 req->id1name.idmap_utf8str_val, 2133 res->id.idmap_id_u.uid, 2134 req->id2name.idmap_utf8str_val, 2135 (res->id.idtype == IDMAP_UID)?1:0, 2136 (res->direction == 0)?"1":NULL); 2137 2138 if (sql == NULL) { 2139 retcode = IDMAP_ERR_INTERNAL; 2140 idmapdlog(LOG_ERR, "Out of memory"); 2141 goto out; 2142 } 2143 2144 retcode = sql_exec_no_cb(cache, sql); 2145 if (retcode != IDMAP_SUCCESS) 2146 goto out; 2147 2148 state->sid2pid_done = FALSE; 2149 sqlite_freemem(sql); 2150 sql = NULL; 2151 2152 /* If name2sid was found in the cache, no need to update namecache */ 2153 if (req->direction & _IDMAP_F_S2N_CACHE) 2154 goto out; 2155 2156 if (req->id1name.idmap_utf8str_val == NULL) 2157 goto out; 2158 2159 sql = sqlite_mprintf("INSERT OR REPLACE into name_cache " 2160 "(sidprefix, rid, name, domain, type, expiration) " 2161 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ", 2162 req->id1.idmap_id_u.sid.prefix, 2163 req->id1.idmap_id_u.sid.rid, 2164 req->id1name.idmap_utf8str_val, 2165 req->id1domain.idmap_utf8str_val, 2166 (res->id.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP); 2167 2168 if (sql == NULL) { 2169 retcode = IDMAP_ERR_INTERNAL; 2170 idmapdlog(LOG_ERR, "Out of memory"); 2171 goto out; 2172 } 2173 2174 retcode = sql_exec_no_cb(cache, sql); 2175 2176 out: 2177 if (sql != NULL) 2178 sqlite_freemem(sql); 2179 return (retcode); 2180 } 2181 2182 static idmap_retcode 2183 lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res, 2184 int is_user, int getname) { 2185 char *end; 2186 char *sql = NULL; 2187 const char **values; 2188 sqlite_vm *vm = NULL; 2189 int ncol; 2190 idmap_retcode retcode = IDMAP_SUCCESS; 2191 idmap_utf8str *str; 2192 time_t curtime; 2193 2194 /* Current time */ 2195 errno = 0; 2196 if ((curtime = time(NULL)) == (time_t)-1) { 2197 idmapdlog(LOG_ERR, 2198 "Failed to get current time (%s)", 2199 strerror(errno)); 2200 retcode = IDMAP_ERR_INTERNAL; 2201 goto out; 2202 } 2203 2204 /* SQL to lookup the cache */ 2205 sql = sqlite_mprintf("SELECT sidprefix, rid, winname, windomain, w2u " 2206 "FROM idmap_cache WHERE " 2207 "pid = %u AND u2w = 1 AND is_user = %d AND " 2208 "(pid >= 2147483648 OR " 2209 "(expiration = 0 OR expiration ISNULL OR " 2210 "expiration > %d));", 2211 req->id1.idmap_id_u.uid, is_user, curtime); 2212 if (sql == NULL) { 2213 idmapdlog(LOG_ERR, "Out of memory"); 2214 retcode = IDMAP_ERR_MEMORY; 2215 goto out; 2216 } 2217 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values); 2218 sqlite_freemem(sql); 2219 2220 if (retcode == IDMAP_ERR_NOTFOUND) 2221 goto out; 2222 else if (retcode == IDMAP_SUCCESS) { 2223 /* sanity checks */ 2224 if (values[0] == NULL || values[1] == NULL) { 2225 retcode = IDMAP_ERR_CACHE; 2226 goto out; 2227 } 2228 2229 switch (req->id2.idtype) { 2230 case IDMAP_SID: 2231 res->id.idmap_id_u.sid.rid = 2232 strtoul(values[1], &end, 10); 2233 res->id.idmap_id_u.sid.prefix = strdup(values[0]); 2234 if (res->id.idmap_id_u.sid.prefix == NULL) { 2235 idmapdlog(LOG_ERR, "Out of memory"); 2236 retcode = IDMAP_ERR_MEMORY; 2237 goto out; 2238 } 2239 2240 if (values[4] != NULL) 2241 res->direction = 2242 (strtol(values[4], &end, 10) == 0)? 2243 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; 2244 else 2245 res->direction = IDMAP_DIRECTION_U2W; 2246 2247 if (getname == 0 || values[2] == NULL) 2248 break; 2249 str = &req->id2name; 2250 retcode = idmap_str2utf8(&str, values[2], 0); 2251 if (retcode != IDMAP_SUCCESS) { 2252 idmapdlog(LOG_ERR, "Out of memory"); 2253 retcode = IDMAP_ERR_MEMORY; 2254 goto out; 2255 } 2256 2257 if (values[3] == NULL) 2258 break; 2259 str = &req->id2domain; 2260 retcode = idmap_str2utf8(&str, values[3], 0); 2261 if (retcode != IDMAP_SUCCESS) { 2262 idmapdlog(LOG_ERR, "Out of memory"); 2263 retcode = IDMAP_ERR_MEMORY; 2264 goto out; 2265 } 2266 break; 2267 default: 2268 retcode = IDMAP_ERR_NOTSUPPORTED; 2269 break; 2270 } 2271 } 2272 2273 out: 2274 if (vm != NULL) 2275 (void) sqlite_finalize(vm, NULL); 2276 return (retcode); 2277 } 2278 2279 static idmap_retcode 2280 lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain, 2281 char **sidprefix, idmap_rid_t *rid, int *type) { 2282 char *end; 2283 char *sql = NULL; 2284 const char **values; 2285 sqlite_vm *vm = NULL; 2286 int ncol; 2287 time_t curtime; 2288 idmap_retcode retcode = IDMAP_SUCCESS; 2289 2290 /* Get current time */ 2291 errno = 0; 2292 if ((curtime = time(NULL)) == (time_t)-1) { 2293 idmapdlog(LOG_ERR, 2294 "Failed to get current time (%s)", 2295 strerror(errno)); 2296 retcode = IDMAP_ERR_INTERNAL; 2297 goto out; 2298 } 2299 2300 /* SQL to lookup the cache */ 2301 sql = sqlite_mprintf("SELECT sidprefix, rid, type FROM name_cache " 2302 "WHERE name = %Q AND domain = %Q AND " 2303 "(expiration = 0 OR expiration ISNULL OR " 2304 "expiration > %d);", 2305 name, domain, curtime); 2306 if (sql == NULL) { 2307 idmapdlog(LOG_ERR, "Out of memory"); 2308 retcode = IDMAP_ERR_MEMORY; 2309 goto out; 2310 } 2311 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values); 2312 sqlite_freemem(sql); 2313 2314 if (retcode == IDMAP_SUCCESS) { 2315 if (type != NULL) { 2316 if (values[2] == NULL) { 2317 retcode = IDMAP_ERR_CACHE; 2318 goto out; 2319 } 2320 *type = strtol(values[2], &end, 10); 2321 } 2322 2323 if (values[0] == NULL || values[1] == NULL) { 2324 retcode = IDMAP_ERR_CACHE; 2325 goto out; 2326 } 2327 if ((*sidprefix = strdup(values[0])) == NULL) { 2328 idmapdlog(LOG_ERR, "Out of memory"); 2329 retcode = IDMAP_ERR_MEMORY; 2330 goto out; 2331 } 2332 *rid = strtoul(values[1], &end, 10); 2333 } 2334 2335 out: 2336 if (vm != NULL) 2337 (void) sqlite_finalize(vm, NULL); 2338 return (retcode); 2339 } 2340 2341 static idmap_retcode 2342 lookup_win_name2sid(const char *name, const char *domain, char **sidprefix, 2343 idmap_rid_t *rid, int *type) { 2344 int ret; 2345 int retries = 0; 2346 idmap_query_state_t *qs = NULL; 2347 idmap_retcode rc, retcode; 2348 2349 retcode = IDMAP_ERR_NOTFOUND; 2350 2351 retry: 2352 ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs); 2353 if (ret != 0) { 2354 idmapdlog(LOG_ERR, 2355 "Failed to create name2sid batch for AD lookup"); 2356 return (IDMAP_ERR_INTERNAL); 2357 } 2358 2359 retcode = idmap_name2sid_batch_add1(qs, name, domain, sidprefix, 2360 rid, type, &rc); 2361 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 2362 goto out; 2363 2364 if (retcode != IDMAP_SUCCESS) { 2365 idmapdlog(LOG_ERR, 2366 "Failed to batch name2sid for AD lookup"); 2367 idmap_lookup_release_batch(&qs); 2368 return (IDMAP_ERR_INTERNAL); 2369 } 2370 2371 out: 2372 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 2373 idmap_lookup_release_batch(&qs); 2374 else 2375 retcode = idmap_lookup_batch_end(&qs, NULL); 2376 2377 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 2378 goto retry; 2379 2380 if (retcode != IDMAP_SUCCESS) { 2381 idmapdlog(LOG_NOTICE, "Windows user/group name to SID lookup " 2382 "failed"); 2383 return (retcode); 2384 } else 2385 return (rc); 2386 /* NOTREACHED */ 2387 } 2388 2389 static idmap_retcode 2390 lookup_name2sid(sqlite *cache, const char *name, const char *domain, 2391 int *is_user, char **sidprefix, idmap_rid_t *rid, 2392 idmap_mapping *req) { 2393 int type; 2394 idmap_retcode retcode; 2395 2396 /* Lookup name@domain to sid in the well-known sids table */ 2397 retcode = lookup_wksids_name2sid(name, sidprefix, rid, &type); 2398 if (retcode == IDMAP_SUCCESS) { 2399 req->direction |= _IDMAP_F_S2N_CACHE; 2400 goto out; 2401 } else if (retcode != IDMAP_ERR_NOTFOUND) { 2402 return (retcode); 2403 } 2404 2405 /* Lookup name@domain to sid in cache */ 2406 retcode = lookup_cache_name2sid(cache, name, domain, sidprefix, 2407 rid, &type); 2408 if (retcode == IDMAP_ERR_NOTFOUND) { 2409 /* Lookup Windows NT/AD to map name@domain to sid */ 2410 retcode = lookup_win_name2sid(name, domain, sidprefix, rid, 2411 &type); 2412 if (retcode != IDMAP_SUCCESS) 2413 return (retcode); 2414 req->direction |= _IDMAP_F_S2N_AD; 2415 } else if (retcode != IDMAP_SUCCESS) { 2416 return (retcode); 2417 } else { 2418 /* Set flag */ 2419 req->direction |= _IDMAP_F_S2N_CACHE; 2420 } 2421 2422 out: 2423 /* 2424 * Entry found (cache or Windows lookup) 2425 * is_user is both input as well as output parameter 2426 */ 2427 if (*is_user == 1) { 2428 if (type != _IDMAP_T_USER) 2429 return (IDMAP_ERR_NOTUSER); 2430 } else if (*is_user == 0) { 2431 if (type != _IDMAP_T_GROUP) 2432 return (IDMAP_ERR_NOTGROUP); 2433 } else if (*is_user == -1) { 2434 /* Caller wants to know if its user or group */ 2435 if (type == _IDMAP_T_USER) 2436 *is_user = 1; 2437 else if (type == _IDMAP_T_GROUP) 2438 *is_user = 0; 2439 else 2440 return (IDMAP_ERR_SID); 2441 } 2442 2443 return (retcode); 2444 } 2445 2446 static idmap_retcode 2447 name_based_mapping_pid2sid(sqlite *db, sqlite *cache, const char *unixname, 2448 int is_user, idmap_mapping *req, idmap_id_res *res) { 2449 const char *winname, *windomain; 2450 char *mapping_domain = NULL; 2451 char *sql = NULL, *errmsg = NULL; 2452 idmap_retcode retcode; 2453 char *end; 2454 const char **values; 2455 sqlite_vm *vm = NULL; 2456 idmap_utf8str *str; 2457 int ncol, r; 2458 const char *me = "name_based_mapping_pid2sid"; 2459 2460 RDLOCK_CONFIG(); 2461 if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) { 2462 mapping_domain = 2463 strdup(_idmapdstate.cfg->pgcfg.mapping_domain); 2464 if (mapping_domain == NULL) { 2465 UNLOCK_CONFIG(); 2466 idmapdlog(LOG_ERR, "Out of memory"); 2467 retcode = IDMAP_ERR_MEMORY; 2468 goto out; 2469 } 2470 } 2471 UNLOCK_CONFIG(); 2472 2473 sql = sqlite_mprintf( 2474 "SELECT winname, windomain, w2u_order FROM namerules WHERE " 2475 "u2w_order > 0 AND is_user = %d AND " 2476 "(unixname = %Q OR unixname = '*') " 2477 "ORDER BY u2w_order ASC;", 2478 is_user, unixname); 2479 if (sql == NULL) { 2480 idmapdlog(LOG_ERR, "Out of memory"); 2481 retcode = IDMAP_ERR_MEMORY; 2482 goto out; 2483 } 2484 2485 if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) { 2486 retcode = IDMAP_ERR_INTERNAL; 2487 idmapdlog(LOG_ERR, 2488 "%s: database error (%s)", 2489 me, CHECK_NULL(errmsg)); 2490 sqlite_freemem(errmsg); 2491 goto out; 2492 } 2493 2494 for (;;) { 2495 r = sqlite_step(vm, &ncol, &values, NULL); 2496 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 2497 if (r == SQLITE_ROW) { 2498 if (ncol < 3) { 2499 retcode = IDMAP_ERR_INTERNAL; 2500 goto out; 2501 } 2502 if (values[0] == NULL) { 2503 /* values [1] and [2] can be null */ 2504 retcode = IDMAP_ERR_INTERNAL; 2505 goto out; 2506 } 2507 if (EMPTY_NAME(values[0])) { 2508 retcode = IDMAP_ERR_NOMAPPING; 2509 goto out; 2510 } 2511 winname = (values[0][0] == '*')?unixname:values[0]; 2512 if (values[1] != NULL) 2513 windomain = values[1]; 2514 else if (mapping_domain != NULL) 2515 windomain = mapping_domain; 2516 else { 2517 idmapdlog(LOG_ERR, 2518 "%s: no domain", me); 2519 retcode = IDMAP_ERR_DOMAIN_NOTFOUND; 2520 goto out; 2521 } 2522 /* Lookup winname@domain to sid */ 2523 retcode = lookup_name2sid(cache, winname, windomain, 2524 &is_user, &res->id.idmap_id_u.sid.prefix, 2525 &res->id.idmap_id_u.sid.rid, req); 2526 if (retcode == IDMAP_ERR_NOTFOUND) { 2527 if (winname == unixname) 2528 continue; 2529 else 2530 retcode = IDMAP_ERR_NOMAPPING; 2531 } 2532 goto out; 2533 } else if (r == SQLITE_DONE) { 2534 retcode = IDMAP_ERR_NOTFOUND; 2535 goto out; 2536 } else { 2537 (void) sqlite_finalize(vm, &errmsg); 2538 vm = NULL; 2539 idmapdlog(LOG_ERR, 2540 "%s: database error (%s)", 2541 me, CHECK_NULL(errmsg)); 2542 sqlite_freemem(errmsg); 2543 retcode = IDMAP_ERR_INTERNAL; 2544 goto out; 2545 } 2546 } 2547 2548 out: 2549 if (sql != NULL) 2550 sqlite_freemem(sql); 2551 if (retcode == IDMAP_SUCCESS) { 2552 if (values[2] != NULL) 2553 res->direction = 2554 (strtol(values[2], &end, 10) == 0)? 2555 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; 2556 else 2557 res->direction = IDMAP_DIRECTION_U2W; 2558 str = &req->id2name; 2559 retcode = idmap_str2utf8(&str, winname, 0); 2560 if (retcode == IDMAP_SUCCESS) { 2561 str = &req->id2domain; 2562 if (windomain == mapping_domain) { 2563 (void) idmap_str2utf8(&str, windomain, 1); 2564 mapping_domain = NULL; 2565 } else 2566 retcode = idmap_str2utf8(&str, windomain, 0); 2567 } 2568 } 2569 if (vm != NULL) 2570 (void) sqlite_finalize(vm, NULL); 2571 if (mapping_domain != NULL) 2572 free(mapping_domain); 2573 return (retcode); 2574 } 2575 2576 idmap_retcode 2577 pid2sid_first_pass(lookup_state_t *state, sqlite *cache, sqlite *db, 2578 idmap_mapping *req, idmap_id_res *res, int is_user, 2579 int getname) { 2580 char *unixname = NULL; 2581 struct passwd pwd; 2582 struct group grp; 2583 idmap_utf8str *str; 2584 char buf[1024]; 2585 int errnum; 2586 idmap_retcode retcode = IDMAP_SUCCESS; 2587 const char *me = "pid2sid"; 2588 2589 req->direction = _IDMAP_F_DONE; 2590 res->id.idtype = req->id2.idtype; 2591 2592 /* Lookup well-known SIDs */ 2593 retcode = lookup_wksids_pid2sid(req, res, is_user); 2594 if (retcode != IDMAP_ERR_NOTFOUND) 2595 goto out; 2596 2597 /* Lookup pid to sid in cache */ 2598 retcode = lookup_cache_pid2sid(cache, req, res, is_user, getname); 2599 if (retcode != IDMAP_ERR_NOTFOUND) 2600 goto out; 2601 2602 /* Ephemeral ids cannot be allocated during pid2sid */ 2603 if (IS_EPHEMERAL(req->id1.idmap_id_u.uid)) { 2604 retcode = IDMAP_ERR_NOMAPPING; 2605 goto out; 2606 } 2607 2608 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) { 2609 retcode = IDMAP_ERR_NOMAPPING; 2610 goto out; 2611 } 2612 2613 /* uid/gid to name */ 2614 if (req->id1name.idmap_utf8str_val != NULL) { 2615 unixname = req->id1name.idmap_utf8str_val; 2616 } if (is_user) { 2617 errno = 0; 2618 if (getpwuid_r(req->id1.idmap_id_u.uid, &pwd, buf, 2619 sizeof (buf)) == NULL) { 2620 errnum = errno; 2621 idmapdlog(LOG_WARNING, 2622 "%s: getpwuid_r(%u) failed (%s).", 2623 me, req->id1.idmap_id_u.uid, 2624 errnum?strerror(errnum):"not found"); 2625 retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND: 2626 IDMAP_ERR_INTERNAL; 2627 goto fallback_localsid; 2628 } 2629 unixname = pwd.pw_name; 2630 } else { 2631 errno = 0; 2632 if (getgrgid_r(req->id1.idmap_id_u.gid, &grp, buf, 2633 sizeof (buf)) == NULL) { 2634 errnum = errno; 2635 idmapdlog(LOG_WARNING, 2636 "%s: getgrgid_r(%u) failed (%s).", 2637 me, req->id1.idmap_id_u.gid, 2638 errnum?strerror(errnum):"not found"); 2639 retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND: 2640 IDMAP_ERR_INTERNAL; 2641 goto fallback_localsid; 2642 } 2643 unixname = grp.gr_name; 2644 } 2645 2646 /* Name-based mapping */ 2647 retcode = name_based_mapping_pid2sid(db, cache, unixname, is_user, 2648 req, res); 2649 if (retcode == IDMAP_ERR_NOTFOUND) { 2650 retcode = generate_localsid(req, res, is_user); 2651 goto out; 2652 } else if (retcode == IDMAP_SUCCESS) 2653 goto out; 2654 2655 fallback_localsid: 2656 /* 2657 * Here we generate localsid as fallback id on errors. Our 2658 * return status is the error that's been previously assigned. 2659 */ 2660 (void) generate_localsid(req, res, is_user); 2661 2662 out: 2663 if (retcode == IDMAP_SUCCESS) { 2664 if (req->id1name.idmap_utf8str_val == NULL && 2665 unixname != NULL) { 2666 str = &req->id1name; 2667 retcode = idmap_str2utf8(&str, unixname, 0); 2668 } 2669 } 2670 if (req->direction != _IDMAP_F_DONE) 2671 state->pid2sid_done = FALSE; 2672 res->retcode = idmap_stat4prot(retcode); 2673 return (retcode); 2674 } 2675 2676 static idmap_retcode 2677 lookup_win_sid2name(const char *sidprefix, idmap_rid_t rid, char **name, 2678 char **domain, int *type) { 2679 int ret; 2680 idmap_query_state_t *qs = NULL; 2681 idmap_retcode rc, retcode; 2682 2683 retcode = IDMAP_ERR_NOTFOUND; 2684 2685 ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs); 2686 if (ret != 0) { 2687 idmapdlog(LOG_ERR, 2688 "Failed to create sid2name batch for AD lookup"); 2689 retcode = IDMAP_ERR_INTERNAL; 2690 goto out; 2691 } 2692 2693 ret = idmap_sid2name_batch_add1( 2694 qs, sidprefix, &rid, name, domain, type, &rc); 2695 if (ret != 0) { 2696 idmapdlog(LOG_ERR, 2697 "Failed to batch sid2name for AD lookup"); 2698 retcode = IDMAP_ERR_INTERNAL; 2699 goto out; 2700 } 2701 2702 out: 2703 if (qs != NULL) { 2704 ret = idmap_lookup_batch_end(&qs, NULL); 2705 if (ret != 0) { 2706 idmapdlog(LOG_ERR, 2707 "Failed to execute sid2name AD lookup"); 2708 retcode = IDMAP_ERR_INTERNAL; 2709 } else 2710 retcode = rc; 2711 } 2712 2713 return (retcode); 2714 } 2715 2716 static int 2717 copy_mapping_request(idmap_mapping *mapping, idmap_mapping *request) 2718 { 2719 (void) memset(mapping, 0, sizeof (*mapping)); 2720 2721 mapping->flag = request->flag; 2722 mapping->direction = request->direction; 2723 mapping->id2.idtype = request->id2.idtype; 2724 2725 mapping->id1.idtype = request->id1.idtype; 2726 if (request->id1.idtype == IDMAP_SID) { 2727 mapping->id1.idmap_id_u.sid.rid = 2728 request->id1.idmap_id_u.sid.rid; 2729 if (!EMPTY_STRING(request->id1.idmap_id_u.sid.prefix)) { 2730 mapping->id1.idmap_id_u.sid.prefix = 2731 strdup(request->id1.idmap_id_u.sid.prefix); 2732 if (mapping->id1.idmap_id_u.sid.prefix == NULL) 2733 return (-1); 2734 } 2735 } else { 2736 mapping->id1.idmap_id_u.uid = request->id1.idmap_id_u.uid; 2737 } 2738 2739 mapping->id1domain.idmap_utf8str_len = 2740 request->id1domain.idmap_utf8str_len; 2741 if (mapping->id1domain.idmap_utf8str_len) { 2742 mapping->id1domain.idmap_utf8str_val = 2743 strdup(request->id1domain.idmap_utf8str_val); 2744 if (mapping->id1domain.idmap_utf8str_val == NULL) 2745 return (-1); 2746 } 2747 2748 mapping->id1name.idmap_utf8str_len = 2749 request->id1name.idmap_utf8str_len; 2750 if (mapping->id1name.idmap_utf8str_len) { 2751 mapping->id1name.idmap_utf8str_val = 2752 strdup(request->id1name.idmap_utf8str_val); 2753 if (mapping->id1name.idmap_utf8str_val == NULL) 2754 return (-1); 2755 } 2756 2757 /* We don't need the rest of the request i.e request->id2 */ 2758 return (0); 2759 2760 errout: 2761 if (mapping->id1.idmap_id_u.sid.prefix != NULL) { 2762 free(mapping->id1.idmap_id_u.sid.prefix); 2763 mapping->id1.idmap_id_u.sid.prefix = NULL; 2764 } 2765 2766 if (mapping->id1domain.idmap_utf8str_val != NULL) { 2767 free(mapping->id1domain.idmap_utf8str_val); 2768 mapping->id1domain.idmap_utf8str_val = NULL; 2769 mapping->id1domain.idmap_utf8str_len = 0; 2770 } 2771 2772 if (mapping->id1name.idmap_utf8str_val != NULL) { 2773 free(mapping->id1name.idmap_utf8str_val); 2774 mapping->id1name.idmap_utf8str_val = NULL; 2775 mapping->id1name.idmap_utf8str_len = 0; 2776 } 2777 2778 (void) memset(mapping, 0, sizeof (*mapping)); 2779 return (-1); 2780 } 2781 2782 2783 idmap_retcode 2784 get_w2u_mapping(sqlite *cache, sqlite *db, idmap_mapping *request, 2785 idmap_mapping *mapping) { 2786 idmap_id_res idres; 2787 lookup_state_t state; 2788 idmap_utf8str *str; 2789 char *cp; 2790 int is_user; 2791 idmap_retcode retcode; 2792 const char *winname, *windomain; 2793 2794 (void) memset(&idres, 0, sizeof (idres)); 2795 (void) memset(&state, 0, sizeof (state)); 2796 2797 if (request->id2.idtype == IDMAP_UID) 2798 is_user = 1; 2799 else if (request->id2.idtype == IDMAP_GID) 2800 is_user = 0; 2801 else if (request->id2.idtype == IDMAP_POSIXID) 2802 is_user = -1; 2803 else { 2804 retcode = IDMAP_ERR_IDTYPE; 2805 goto out; 2806 } 2807 2808 /* Copy data from request to result */ 2809 if (copy_mapping_request(mapping, request) < 0) { 2810 retcode = IDMAP_ERR_MEMORY; 2811 goto out; 2812 } 2813 2814 winname = mapping->id1name.idmap_utf8str_val; 2815 windomain = mapping->id1domain.idmap_utf8str_val; 2816 2817 if (winname == NULL && windomain != NULL) { 2818 retcode = IDMAP_ERR_ARG; 2819 goto out; 2820 } 2821 2822 if (winname != NULL && windomain == NULL) { 2823 str = &mapping->id1domain; 2824 2825 if ((cp = strchr(winname, '@')) != NULL) { 2826 /* 2827 * if winname is qualified with a domain, use it. 2828 */ 2829 *cp = '\0'; 2830 retcode = idmap_str2utf8(&str, cp + 1, 0); 2831 } else if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) { 2832 /* 2833 * otherwise use the mapping domain 2834 */ 2835 RDLOCK_CONFIG(); 2836 retcode = idmap_str2utf8(&str, 2837 _idmapdstate.cfg->pgcfg.mapping_domain, 0); 2838 UNLOCK_CONFIG(); 2839 } else 2840 retcode = IDMAP_SUCCESS; 2841 2842 if (retcode != IDMAP_SUCCESS) { 2843 idmapdlog(LOG_ERR, "Out of memory"); 2844 goto out; 2845 } 2846 windomain = mapping->id1domain.idmap_utf8str_val; 2847 } 2848 2849 if (winname != NULL && mapping->id1.idmap_id_u.sid.prefix == NULL) { 2850 retcode = lookup_name2sid(cache, winname, windomain, 2851 &is_user, &mapping->id1.idmap_id_u.sid.prefix, 2852 &mapping->id1.idmap_id_u.sid.rid, mapping); 2853 if (retcode != IDMAP_SUCCESS) 2854 goto out; 2855 if (mapping->id2.idtype == IDMAP_POSIXID) 2856 mapping->id2.idtype = is_user?IDMAP_UID:IDMAP_GID; 2857 } 2858 2859 state.sid2pid_done = TRUE; 2860 retcode = sid2pid_first_pass(&state, cache, mapping, &idres); 2861 if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE) 2862 goto out; 2863 2864 if (state.ad_nqueries) { 2865 /* sid2name AD lookup */ 2866 retcode = lookup_win_sid2name( 2867 mapping->id1.idmap_id_u.sid.prefix, 2868 mapping->id1.idmap_id_u.sid.rid, 2869 &mapping->id1name.idmap_utf8str_val, 2870 &mapping->id1domain.idmap_utf8str_val, 2871 (int *)&idres.id.idtype); 2872 2873 idres.retcode = retcode; 2874 } 2875 2876 state.sid2pid_done = TRUE; 2877 retcode = sid2pid_second_pass(&state, cache, db, mapping, &idres); 2878 if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE) 2879 goto out; 2880 2881 /* Update cache */ 2882 (void) update_cache_sid2pid(&state, cache, mapping, &idres); 2883 2884 out: 2885 if (retcode == IDMAP_SUCCESS) { 2886 mapping->direction = idres.direction; 2887 mapping->id2 = idres.id; 2888 (void) memset(&idres, 0, sizeof (idres)); 2889 } else { 2890 mapping->id2.idmap_id_u.uid = UID_NOBODY; 2891 } 2892 xdr_free(xdr_idmap_id_res, (caddr_t)&idres); 2893 return (retcode); 2894 } 2895 2896 idmap_retcode 2897 get_u2w_mapping(sqlite *cache, sqlite *db, idmap_mapping *request, 2898 idmap_mapping *mapping, int is_user) { 2899 idmap_id_res idres; 2900 lookup_state_t state; 2901 struct passwd pwd; 2902 struct group grp; 2903 char buf[1024]; 2904 int errnum; 2905 idmap_retcode retcode; 2906 const char *unixname; 2907 const char *me = "get_u2w_mapping"; 2908 2909 /* 2910 * In order to re-use the pid2sid code, we convert 2911 * our input data into structs that are expected by 2912 * pid2sid_first_pass. 2913 */ 2914 2915 (void) memset(&idres, 0, sizeof (idres)); 2916 (void) memset(&state, 0, sizeof (state)); 2917 2918 /* Copy data from request to result */ 2919 if (copy_mapping_request(mapping, request) < 0) { 2920 retcode = IDMAP_ERR_MEMORY; 2921 goto out; 2922 } 2923 2924 unixname = mapping->id1name.idmap_utf8str_val; 2925 2926 if (unixname == NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) { 2927 retcode = IDMAP_ERR_ARG; 2928 goto out; 2929 } 2930 2931 if (unixname != NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) { 2932 /* Get uid/gid by name */ 2933 if (is_user) { 2934 errno = 0; 2935 if (getpwnam_r(unixname, &pwd, buf, 2936 sizeof (buf)) == NULL) { 2937 errnum = errno; 2938 idmapdlog(LOG_WARNING, 2939 "%s: getpwnam_r(%s) failed (%s).", 2940 me, unixname, 2941 errnum?strerror(errnum):"not found"); 2942 retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND: 2943 IDMAP_ERR_INTERNAL; 2944 goto out; 2945 } 2946 mapping->id1.idmap_id_u.uid = pwd.pw_uid; 2947 } else { 2948 errno = 0; 2949 if (getgrnam_r(unixname, &grp, buf, 2950 sizeof (buf)) == NULL) { 2951 errnum = errno; 2952 idmapdlog(LOG_WARNING, 2953 "%s: getgrnam_r(%s) failed (%s).", 2954 me, unixname, 2955 errnum?strerror(errnum):"not found"); 2956 retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND: 2957 IDMAP_ERR_INTERNAL; 2958 goto out; 2959 } 2960 mapping->id1.idmap_id_u.gid = grp.gr_gid; 2961 } 2962 } 2963 2964 state.pid2sid_done = TRUE; 2965 retcode = pid2sid_first_pass(&state, cache, db, mapping, &idres, 2966 is_user, 1); 2967 if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE) 2968 goto out; 2969 2970 /* Update cache */ 2971 (void) update_cache_pid2sid(&state, cache, mapping, &idres); 2972 2973 out: 2974 mapping->direction = idres.direction; 2975 mapping->id2 = idres.id; 2976 (void) memset(&idres, 0, sizeof (idres)); 2977 xdr_free(xdr_idmap_id_res, (caddr_t)&idres); 2978 return (retcode); 2979 } 2980