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