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 * These well-known principals are stored (as of Windows Server 2003) 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 * These principals remain constant across all operating systems. Using 911 * a hard-coded table here improves performance and avoids additional 912 * complexity in the AD lookup code in adutils.c 913 * 914 * Currently we don't support localization of well-known SID names, 915 * unlike Windows. 916 * 917 * Note that other well-known SIDs (i.e. S-1-5-<domain>-<w-k RID> and 918 * S-1-5-32-<w-k RID>) are not stored here because AD does have normal 919 * user/group objects for these objects and can be looked up using the 920 * existing AD lookup code. 921 */ 922 static wksids_table_t wksids[] = { 923 {"S-1-1", 0, "Everyone", 0, SENTINEL_PID, -1}, 924 {"S-1-3", 0, "Creator Owner", 1, IDMAP_WK_CREATOR_OWNER_UID, 0}, 925 {"S-1-3", 1, "Creator Group", 0, IDMAP_WK_CREATOR_GROUP_GID, 0}, 926 {"S-1-3", 2, "Creator Owner Server", 1, SENTINEL_PID, -1}, 927 {"S-1-3", 3, "Creator Group Server", 0, SENTINEL_PID, -1}, 928 {"S-1-5", 1, "Dialup", 0, SENTINEL_PID, -1}, 929 {"S-1-5", 2, "Network", 0, SENTINEL_PID, -1}, 930 {"S-1-5", 3, "Batch", 0, SENTINEL_PID, -1}, 931 {"S-1-5", 4, "Interactive", 0, SENTINEL_PID, -1}, 932 {"S-1-5", 6, "Service", 0, SENTINEL_PID, -1}, 933 {"S-1-5", 7, "Anonymous Logon", 0, GID_NOBODY, 0}, 934 {"S-1-5", 8, "Proxy", 0, SENTINEL_PID, -1}, 935 {"S-1-5", 9, "Enterprise Domain Controllers", 0, SENTINEL_PID, -1}, 936 {"S-1-5", 10, "Self", 0, SENTINEL_PID, -1}, 937 {"S-1-5", 11, "Authenticated Users", 0, SENTINEL_PID, -1}, 938 {"S-1-5", 12, "Restricted Code", 0, SENTINEL_PID, -1}, 939 {"S-1-5", 13, "Terminal Server User", 0, SENTINEL_PID, -1}, 940 {"S-1-5", 14, "Remote Interactive Logon", 0, SENTINEL_PID, -1}, 941 {"S-1-5", 15, "This Organization", 0, SENTINEL_PID, -1}, 942 {"S-1-5", 18, "Local System", 0, IDMAP_WK_LOCAL_SYSTEM_GID, 0}, 943 {"S-1-5", 19, "Local Service", 0, SENTINEL_PID, -1}, 944 {"S-1-5", 20, "Network Service", 0, SENTINEL_PID, -1}, 945 {"S-1-5", 1000, "Other Organization", 0, SENTINEL_PID, -1}, 946 {"S-1-5-64", 21, "Digest Authentication", 0, SENTINEL_PID, -1}, 947 {"S-1-5-64", 10, "NTLM Authentication", 0, SENTINEL_PID, -1}, 948 {"S-1-5-64", 14, "SChannel Authentication", 0, SENTINEL_PID, -1}, 949 {NULL, UINT32_MAX, NULL, -1, SENTINEL_PID, -1} 950 }; 951 952 static idmap_retcode 953 lookup_wksids_sid2pid(idmap_mapping *req, idmap_id_res *res) { 954 int i; 955 for (i = 0; wksids[i].sidprefix != NULL; i++) { 956 if (wksids[i].rid == req->id1.idmap_id_u.sid.rid && 957 (strcasecmp(wksids[i].sidprefix, 958 req->id1.idmap_id_u.sid.prefix) == 0)) { 959 960 if (wksids[i].pid == SENTINEL_PID) 961 /* Not mapped, break */ 962 break; 963 else if (wksids[i].direction == IDMAP_DIRECTION_U2W) 964 continue; 965 966 switch (req->id2.idtype) { 967 case IDMAP_UID: 968 if (wksids[i].is_user == 0) 969 continue; 970 res->id.idmap_id_u.uid = wksids[i].pid; 971 res->direction = wksids[i].direction; 972 return (IDMAP_SUCCESS); 973 case IDMAP_GID: 974 if (wksids[i].is_user == 1) 975 continue; 976 res->id.idmap_id_u.gid = wksids[i].pid; 977 res->direction = wksids[i].direction; 978 return (IDMAP_SUCCESS); 979 case IDMAP_POSIXID: 980 res->id.idmap_id_u.uid = wksids[i].pid; 981 res->id.idtype = (!wksids[i].is_user)? 982 IDMAP_GID:IDMAP_UID; 983 res->direction = wksids[i].direction; 984 return (IDMAP_SUCCESS); 985 default: 986 return (IDMAP_ERR_NOTSUPPORTED); 987 } 988 } 989 } 990 return (IDMAP_ERR_NOTFOUND); 991 } 992 993 static idmap_retcode 994 lookup_wksids_pid2sid(idmap_mapping *req, idmap_id_res *res, int is_user) { 995 int i; 996 if (req->id2.idtype != IDMAP_SID) 997 return (IDMAP_ERR_NOTSUPPORTED); 998 for (i = 0; wksids[i].sidprefix != NULL; i++) { 999 if (wksids[i].pid == req->id1.idmap_id_u.uid && 1000 wksids[i].is_user == is_user && 1001 wksids[i].direction != IDMAP_DIRECTION_W2U) { 1002 res->id.idmap_id_u.sid.rid = wksids[i].rid; 1003 res->id.idmap_id_u.sid.prefix = 1004 strdup(wksids[i].sidprefix); 1005 if (res->id.idmap_id_u.sid.prefix == NULL) { 1006 idmapdlog(LOG_ERR, "Out of memory"); 1007 return (IDMAP_ERR_MEMORY); 1008 } 1009 res->direction = wksids[i].direction; 1010 return (IDMAP_SUCCESS); 1011 } 1012 } 1013 return (IDMAP_ERR_NOTFOUND); 1014 } 1015 1016 static idmap_retcode 1017 lookup_wksids_sid2name(const char *sidprefix, idmap_rid_t rid, char **name, 1018 int *type) { 1019 int i; 1020 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1021 if ((strcasecmp(wksids[i].sidprefix, sidprefix) == 0) && 1022 wksids[i].rid == rid) { 1023 if ((*name = strdup(wksids[i].winname)) == NULL) { 1024 idmapdlog(LOG_ERR, "Out of memory"); 1025 return (IDMAP_ERR_MEMORY); 1026 } 1027 *type = (wksids[i].is_user)? 1028 _IDMAP_T_USER:_IDMAP_T_GROUP; 1029 return (IDMAP_SUCCESS); 1030 } 1031 } 1032 return (IDMAP_ERR_NOTFOUND); 1033 } 1034 1035 static idmap_retcode 1036 lookup_wksids_name2sid(const char *name, char **sidprefix, idmap_rid_t *rid, 1037 int *type) { 1038 int i; 1039 for (i = 0; wksids[i].sidprefix != NULL; i++) { 1040 if (strcasecmp(wksids[i].winname, name) == 0) { 1041 if (sidprefix != NULL && (*sidprefix = 1042 strdup(wksids[i].sidprefix)) == NULL) { 1043 idmapdlog(LOG_ERR, "Out of memory"); 1044 return (IDMAP_ERR_MEMORY); 1045 } 1046 if (type != NULL) 1047 *type = (wksids[i].is_user)? 1048 _IDMAP_T_USER:_IDMAP_T_GROUP; 1049 if (rid != NULL) 1050 *rid = wksids[i].rid; 1051 return (IDMAP_SUCCESS); 1052 } 1053 } 1054 return (IDMAP_ERR_NOTFOUND); 1055 } 1056 1057 static idmap_retcode 1058 lookup_cache_sid2pid(sqlite *cache, idmap_mapping *req, idmap_id_res *res) { 1059 char *end; 1060 char *sql = NULL; 1061 const char **values; 1062 sqlite_vm *vm = NULL; 1063 int ncol, is_user; 1064 uid_t pid; 1065 time_t curtime, exp; 1066 idmap_retcode retcode; 1067 1068 /* Current time */ 1069 errno = 0; 1070 if ((curtime = time(NULL)) == (time_t)-1) { 1071 idmapdlog(LOG_ERR, 1072 "Failed to get current time (%s)", 1073 strerror(errno)); 1074 retcode = IDMAP_ERR_INTERNAL; 1075 goto out; 1076 } 1077 1078 /* SQL to lookup the cache */ 1079 sql = sqlite_mprintf("SELECT pid, is_user, expiration, unixname, u2w " 1080 "FROM idmap_cache WHERE " 1081 "sidprefix = %Q AND rid = %u AND w2u = 1 AND " 1082 "(pid >= 2147483648 OR " 1083 "(expiration = 0 OR expiration ISNULL OR " 1084 "expiration > %d));", 1085 req->id1.idmap_id_u.sid.prefix, 1086 req->id1.idmap_id_u.sid.rid, 1087 curtime); 1088 if (sql == NULL) { 1089 idmapdlog(LOG_ERR, "Out of memory"); 1090 retcode = IDMAP_ERR_MEMORY; 1091 goto out; 1092 } 1093 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values); 1094 sqlite_freemem(sql); 1095 1096 if (retcode == IDMAP_ERR_NOTFOUND) { 1097 goto out; 1098 } else if (retcode == IDMAP_SUCCESS) { 1099 /* sanity checks */ 1100 if (values[0] == NULL || values[1] == NULL) { 1101 retcode = IDMAP_ERR_CACHE; 1102 goto out; 1103 } 1104 1105 pid = strtoul(values[0], &end, 10); 1106 is_user = strncmp(values[1], "0", 2)?1:0; 1107 1108 /* 1109 * We may have an expired ephemeral mapping. Consider 1110 * the expired entry as valid if we are not going to 1111 * perform name-based mapping. But do not renew the 1112 * expiration. 1113 * If we will be doing name-based mapping then store the 1114 * ephemeral pid in the result so that we can use it 1115 * if we end up doing dynamic mapping again. 1116 */ 1117 if (!DO_NOT_ALLOC_NEW_ID_MAPPING(req) && 1118 !AVOID_NAMESERVICE(req)) { 1119 if (IS_EPHEMERAL(pid) && values[2] != NULL) { 1120 exp = strtoll(values[2], &end, 10); 1121 if (exp && exp <= curtime) { 1122 /* Store the ephemeral pid */ 1123 res->id.idmap_id_u.uid = pid; 1124 res->id.idtype = is_user? 1125 IDMAP_UID:IDMAP_GID; 1126 res->direction = IDMAP_DIRECTION_BI; 1127 req->direction |= is_user? 1128 _IDMAP_F_EXP_EPH_UID: 1129 _IDMAP_F_EXP_EPH_GID; 1130 retcode = IDMAP_ERR_NOTFOUND; 1131 goto out; 1132 } 1133 } 1134 } 1135 1136 switch (req->id2.idtype) { 1137 case IDMAP_UID: 1138 if (!is_user) 1139 retcode = IDMAP_ERR_NOTUSER; 1140 else 1141 res->id.idmap_id_u.uid = pid; 1142 break; 1143 case IDMAP_GID: 1144 if (is_user) 1145 retcode = IDMAP_ERR_NOTGROUP; 1146 else 1147 res->id.idmap_id_u.gid = pid; 1148 break; 1149 case IDMAP_POSIXID: 1150 res->id.idmap_id_u.uid = pid; 1151 res->id.idtype = (is_user)?IDMAP_UID:IDMAP_GID; 1152 break; 1153 default: 1154 retcode = IDMAP_ERR_NOTSUPPORTED; 1155 break; 1156 } 1157 } 1158 1159 out: 1160 if (retcode == IDMAP_SUCCESS) { 1161 if (values[4] != NULL) 1162 res->direction = 1163 (strtol(values[4], &end, 10) == 0)? 1164 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; 1165 else 1166 res->direction = IDMAP_DIRECTION_W2U; 1167 1168 if (values[3] != NULL) { 1169 req->id2name = strdup(values[3]); 1170 if (req->id2name == NULL) { 1171 idmapdlog(LOG_ERR, "Out of memory"); 1172 retcode = IDMAP_ERR_MEMORY; 1173 } 1174 } 1175 } 1176 if (vm != NULL) 1177 (void) sqlite_finalize(vm, NULL); 1178 return (retcode); 1179 } 1180 1181 static idmap_retcode 1182 lookup_cache_sid2name(sqlite *cache, const char *sidprefix, idmap_rid_t rid, 1183 char **name, char **domain, int *type) { 1184 char *end; 1185 char *sql = NULL; 1186 const char **values; 1187 sqlite_vm *vm = NULL; 1188 int ncol; 1189 time_t curtime; 1190 idmap_retcode retcode = IDMAP_SUCCESS; 1191 1192 /* Get current time */ 1193 errno = 0; 1194 if ((curtime = time(NULL)) == (time_t)-1) { 1195 idmapdlog(LOG_ERR, 1196 "Failed to get current time (%s)", 1197 strerror(errno)); 1198 retcode = IDMAP_ERR_INTERNAL; 1199 goto out; 1200 } 1201 1202 /* SQL to lookup the cache */ 1203 sql = sqlite_mprintf("SELECT name, domain, type FROM name_cache WHERE " 1204 "sidprefix = %Q AND rid = %u AND " 1205 "(expiration = 0 OR expiration ISNULL OR " 1206 "expiration > %d);", 1207 sidprefix, rid, curtime); 1208 if (sql == NULL) { 1209 idmapdlog(LOG_ERR, "Out of memory"); 1210 retcode = IDMAP_ERR_MEMORY; 1211 goto out; 1212 } 1213 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values); 1214 sqlite_freemem(sql); 1215 1216 if (retcode == IDMAP_SUCCESS) { 1217 if (type != NULL) { 1218 if (values[2] == NULL) { 1219 retcode = IDMAP_ERR_CACHE; 1220 goto out; 1221 } 1222 *type = strtol(values[2], &end, 10); 1223 } 1224 1225 if (name != NULL && values[0] != NULL) { 1226 if ((*name = strdup(values[0])) == NULL) { 1227 idmapdlog(LOG_ERR, "Out of memory"); 1228 retcode = IDMAP_ERR_MEMORY; 1229 goto out; 1230 } 1231 } 1232 1233 if (domain != NULL && values[1] != NULL) { 1234 if ((*domain = strdup(values[1])) == NULL) { 1235 if (name != NULL && *name) { 1236 free(*name); 1237 *name = NULL; 1238 } 1239 idmapdlog(LOG_ERR, "Out of memory"); 1240 retcode = IDMAP_ERR_MEMORY; 1241 goto out; 1242 } 1243 } 1244 } 1245 1246 out: 1247 if (vm != NULL) 1248 (void) sqlite_finalize(vm, NULL); 1249 return (retcode); 1250 } 1251 1252 static idmap_retcode 1253 verify_type(idmap_id_type idtype, int type, idmap_id_res *res) { 1254 switch (idtype) { 1255 case IDMAP_UID: 1256 if (type != _IDMAP_T_USER) 1257 return (IDMAP_ERR_NOTUSER); 1258 res->id.idtype = IDMAP_UID; 1259 break; 1260 case IDMAP_GID: 1261 if (type != _IDMAP_T_GROUP) 1262 return (IDMAP_ERR_NOTGROUP); 1263 res->id.idtype = IDMAP_GID; 1264 break; 1265 case IDMAP_POSIXID: 1266 if (type == _IDMAP_T_USER) 1267 res->id.idtype = IDMAP_UID; 1268 else if (type == _IDMAP_T_GROUP) 1269 res->id.idtype = IDMAP_GID; 1270 else 1271 return (IDMAP_ERR_SID); 1272 break; 1273 default: 1274 return (IDMAP_ERR_NOTSUPPORTED); 1275 } 1276 return (IDMAP_SUCCESS); 1277 } 1278 1279 /* 1280 * Lookup sid to name locally 1281 */ 1282 static idmap_retcode 1283 lookup_local_sid2name(sqlite *cache, idmap_mapping *req, idmap_id_res *res) { 1284 int type = -1; 1285 idmap_retcode retcode; 1286 char *sidprefix; 1287 idmap_rid_t rid; 1288 char *name = NULL, *domain = NULL; 1289 1290 sidprefix = req->id1.idmap_id_u.sid.prefix; 1291 rid = req->id1.idmap_id_u.sid.rid; 1292 1293 /* Lookup sids to name in well-known sids table */ 1294 retcode = lookup_wksids_sid2name(sidprefix, rid, &name, &type); 1295 if (retcode != IDMAP_ERR_NOTFOUND) 1296 goto out; 1297 1298 /* Lookup sid to name in cache */ 1299 retcode = lookup_cache_sid2name(cache, sidprefix, rid, &name, 1300 &domain, &type); 1301 if (retcode != IDMAP_SUCCESS) 1302 goto out; 1303 1304 out: 1305 if (retcode == IDMAP_SUCCESS) { 1306 /* Verify that the sid type matches the request */ 1307 retcode = verify_type(req->id2.idtype, type, res); 1308 1309 /* update state in 'req' */ 1310 if (name != NULL) 1311 req->id1name = name; 1312 if (domain != NULL) 1313 req->id1domain = domain; 1314 } else { 1315 if (name != NULL) 1316 free(name); 1317 if (domain != NULL) 1318 free(domain); 1319 } 1320 return (retcode); 1321 } 1322 1323 idmap_retcode 1324 lookup_win_batch_sid2name(lookup_state_t *state, idmap_mapping_batch *batch, 1325 idmap_ids_res *result) { 1326 idmap_retcode retcode; 1327 int ret, i; 1328 int retries = 0; 1329 idmap_mapping *req; 1330 idmap_id_res *res; 1331 1332 if (state->ad_nqueries == 0) 1333 return (IDMAP_SUCCESS); 1334 1335 retry: 1336 ret = idmap_lookup_batch_start(_idmapdstate.ad, state->ad_nqueries, 1337 &state->ad_lookup); 1338 if (ret != 0) { 1339 idmapdlog(LOG_ERR, 1340 "Failed to create sid2name batch for AD lookup"); 1341 return (IDMAP_ERR_INTERNAL); 1342 } 1343 1344 for (i = 0; i < batch->idmap_mapping_batch_len; i++) { 1345 req = &batch->idmap_mapping_batch_val[i]; 1346 res = &result->ids.ids_val[i]; 1347 1348 if (req->id1.idtype == IDMAP_SID && 1349 req->direction & _IDMAP_F_S2N_AD) { 1350 if (retries == 0) 1351 res->retcode = IDMAP_ERR_RETRIABLE_NET_ERR; 1352 else if (res->retcode != IDMAP_ERR_RETRIABLE_NET_ERR) 1353 continue; 1354 retcode = idmap_sid2name_batch_add1( 1355 state->ad_lookup, 1356 req->id1.idmap_id_u.sid.prefix, 1357 &req->id1.idmap_id_u.sid.rid, 1358 &req->id1name, 1359 &req->id1domain, 1360 (int *)&res->id.idtype, 1361 &res->retcode); 1362 1363 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 1364 break; 1365 if (retcode != IDMAP_SUCCESS) 1366 goto out; 1367 } 1368 } 1369 1370 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 1371 idmap_lookup_release_batch(&state->ad_lookup); 1372 else 1373 retcode = idmap_lookup_batch_end(&state->ad_lookup, NULL); 1374 1375 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 1376 goto retry; 1377 1378 return (retcode); 1379 1380 out: 1381 idmapdlog(LOG_NOTICE, "Windows SID to user/group name lookup failed"); 1382 idmap_lookup_release_batch(&state->ad_lookup); 1383 return (retcode); 1384 } 1385 1386 idmap_retcode 1387 sid2pid_first_pass(lookup_state_t *state, sqlite *cache, idmap_mapping *req, 1388 idmap_id_res *res) { 1389 idmap_retcode retcode; 1390 1391 /* 1392 * The req->direction field is used to maintain state of the 1393 * sid2pid request. 1394 */ 1395 req->direction = _IDMAP_F_DONE; 1396 1397 if (req->id1.idmap_id_u.sid.prefix == NULL) { 1398 retcode = IDMAP_ERR_SID; 1399 goto out; 1400 } 1401 res->id.idtype = req->id2.idtype; 1402 res->id.idmap_id_u.uid = UID_NOBODY; 1403 1404 /* Lookup well-known sid to pid mapping */ 1405 retcode = lookup_wksids_sid2pid(req, res); 1406 if (retcode != IDMAP_ERR_NOTFOUND) 1407 goto out; 1408 1409 /* Lookup sid to pid in cache */ 1410 retcode = lookup_cache_sid2pid(cache, req, res); 1411 if (retcode != IDMAP_ERR_NOTFOUND) 1412 goto out; 1413 1414 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) { 1415 res->id.idmap_id_u.uid = SENTINEL_PID; 1416 goto out; 1417 } 1418 1419 /* 1420 * Failed to find non-expired entry in cache. Tell the caller 1421 * that we are not done yet. 1422 */ 1423 state->sid2pid_done = FALSE; 1424 1425 /* 1426 * Our next step is name-based mapping. To lookup name-based 1427 * mapping rules, we need the windows name and domain-name 1428 * associated with the SID. 1429 */ 1430 1431 /* 1432 * Check if we already have the name (i.e name2pid lookups) 1433 */ 1434 if (req->id1name != NULL && 1435 req->id1domain != NULL) { 1436 retcode = IDMAP_SUCCESS; 1437 req->direction |= _IDMAP_F_S2N_CACHE; 1438 goto out; 1439 } 1440 1441 /* Lookup sid to winname@domain locally first */ 1442 retcode = lookup_local_sid2name(cache, req, res); 1443 if (retcode == IDMAP_SUCCESS) { 1444 req->direction |= _IDMAP_F_S2N_CACHE; 1445 } else if (retcode == IDMAP_ERR_NOTFOUND) { 1446 /* Batch sid to name AD lookup request */ 1447 retcode = IDMAP_SUCCESS; 1448 req->direction |= _IDMAP_F_S2N_AD; 1449 state->ad_nqueries++; 1450 goto out; 1451 } 1452 1453 1454 out: 1455 res->retcode = idmap_stat4prot(retcode); 1456 return (retcode); 1457 } 1458 1459 /* 1460 * Generate SID using the following convention 1461 * <machine-sid-prefix>-<1000 + uid> 1462 * <machine-sid-prefix>-<2^31 + gid> 1463 */ 1464 static idmap_retcode 1465 generate_localsid(idmap_mapping *req, idmap_id_res *res, int is_user) { 1466 1467 if (_idmapdstate.cfg->pgcfg.machine_sid != NULL) { 1468 /* Skip 1000 UIDs */ 1469 if (is_user && req->id1.idmap_id_u.uid > 1470 (INT32_MAX - LOCALRID_MIN)) 1471 return (IDMAP_ERR_NOMAPPING); 1472 1473 RDLOCK_CONFIG(); 1474 res->id.idmap_id_u.sid.prefix = 1475 strdup(_idmapdstate.cfg->pgcfg.machine_sid); 1476 if (res->id.idmap_id_u.sid.prefix == NULL) { 1477 UNLOCK_CONFIG(); 1478 idmapdlog(LOG_ERR, "Out of memory"); 1479 return (IDMAP_ERR_MEMORY); 1480 } 1481 UNLOCK_CONFIG(); 1482 res->id.idmap_id_u.sid.rid = 1483 (is_user)?req->id1.idmap_id_u.uid + LOCALRID_MIN: 1484 req->id1.idmap_id_u.gid + INT32_MAX + 1; 1485 res->direction = IDMAP_DIRECTION_BI; 1486 1487 /* 1488 * Don't update name_cache because local sids don't have 1489 * valid windows names. 1490 * We mark the entry as being found in the namecache so that 1491 * the cache update routine doesn't update namecache. 1492 */ 1493 req->direction = _IDMAP_F_S2N_CACHE; 1494 return (IDMAP_SUCCESS); 1495 } 1496 1497 return (IDMAP_ERR_NOMAPPING); 1498 } 1499 1500 static idmap_retcode 1501 lookup_localsid2pid(idmap_mapping *req, idmap_id_res *res) { 1502 char *sidprefix; 1503 uint32_t rid; 1504 int s; 1505 1506 /* 1507 * If the sidprefix == localsid then UID = last RID - 1000 or 1508 * GID = last RID - 2^31. 1509 */ 1510 sidprefix = req->id1.idmap_id_u.sid.prefix; 1511 rid = req->id1.idmap_id_u.sid.rid; 1512 1513 RDLOCK_CONFIG(); 1514 s = (_idmapdstate.cfg->pgcfg.machine_sid)? 1515 strcasecmp(sidprefix, 1516 _idmapdstate.cfg->pgcfg.machine_sid):1; 1517 UNLOCK_CONFIG(); 1518 1519 if (s == 0) { 1520 switch (req->id2.idtype) { 1521 case IDMAP_UID: 1522 if (rid > INT32_MAX) { 1523 return (IDMAP_ERR_NOTUSER); 1524 } else if (rid < LOCALRID_MIN) { 1525 return (IDMAP_ERR_NOTFOUND); 1526 } 1527 res->id.idmap_id_u.uid = rid - LOCALRID_MIN; 1528 res->id.idtype = IDMAP_UID; 1529 break; 1530 case IDMAP_GID: 1531 if (rid <= INT32_MAX) { 1532 return (IDMAP_ERR_NOTGROUP); 1533 } 1534 res->id.idmap_id_u.gid = rid - INT32_MAX - 1; 1535 res->id.idtype = IDMAP_GID; 1536 break; 1537 case IDMAP_POSIXID: 1538 if (rid > INT32_MAX) { 1539 res->id.idmap_id_u.gid = 1540 rid - INT32_MAX - 1; 1541 res->id.idtype = IDMAP_GID; 1542 } else if (rid < LOCALRID_MIN) { 1543 return (IDMAP_ERR_NOTFOUND); 1544 } else { 1545 res->id.idmap_id_u.uid = rid - LOCALRID_MIN; 1546 res->id.idtype = IDMAP_UID; 1547 } 1548 break; 1549 default: 1550 return (IDMAP_ERR_NOTSUPPORTED); 1551 } 1552 return (IDMAP_SUCCESS); 1553 } 1554 1555 return (IDMAP_ERR_NOTFOUND); 1556 } 1557 1558 static idmap_retcode 1559 ns_lookup_byname(int is_user, const char *name, idmap_id_res *res) { 1560 struct passwd pwd; 1561 struct group grp; 1562 char buf[1024]; 1563 int errnum; 1564 const char *me = "ns_lookup_byname"; 1565 1566 if (is_user) { 1567 if (getpwnam_r(name, &pwd, buf, sizeof (buf)) == NULL) { 1568 errnum = errno; 1569 idmapdlog(LOG_WARNING, 1570 "%s: getpwnam_r(%s) failed (%s).", 1571 me, name, 1572 errnum?strerror(errnum):"not found"); 1573 if (errnum == 0) 1574 return (IDMAP_ERR_NOTFOUND); 1575 else 1576 return (IDMAP_ERR_INTERNAL); 1577 } 1578 res->id.idmap_id_u.uid = pwd.pw_uid; 1579 res->id.idtype = IDMAP_UID; 1580 } else { 1581 if (getgrnam_r(name, &grp, buf, sizeof (buf)) == NULL) { 1582 errnum = errno; 1583 idmapdlog(LOG_WARNING, 1584 "%s: getgrnam_r(%s) failed (%s).", 1585 me, name, 1586 errnum?strerror(errnum):"not found"); 1587 if (errnum == 0) 1588 return (IDMAP_ERR_NOTFOUND); 1589 else 1590 return (IDMAP_ERR_INTERNAL); 1591 } 1592 res->id.idmap_id_u.gid = grp.gr_gid; 1593 res->id.idtype = IDMAP_GID; 1594 } 1595 return (IDMAP_SUCCESS); 1596 } 1597 1598 /* 1599 * Name-based mapping 1600 * 1601 * Case 1: If no rule matches do ephemeral 1602 * 1603 * Case 2: If rule matches and unixname is "" then return no mapping. 1604 * 1605 * Case 3: If rule matches and unixname is specified then lookup name 1606 * service using the unixname. If unixname not found then return no mapping. 1607 * 1608 * Case 4: If rule matches and unixname is * then lookup name service 1609 * using winname as the unixname. If unixname not found then process 1610 * other rules using the lookup order. If no other rule matches then do 1611 * ephemeral. Otherwise, based on the matched rule do Case 2 or 3 or 4. 1612 * This allows us to specify a fallback unixname per _domain_ or no mapping 1613 * instead of the default behaviour of doing ephemeral mapping. 1614 * 1615 * Example 1: 1616 * *@sfbay == * 1617 * If looking up windows users foo@sfbay and foo does not exists in 1618 * the name service then foo@sfbay will be mapped to an ephemeral id. 1619 * 1620 * Example 2: 1621 * *@sfbay == * 1622 * *@sfbay => guest 1623 * If looking up windows users foo@sfbay and foo does not exists in 1624 * the name service then foo@sfbay will be mapped to guest. 1625 * 1626 * Example 3: 1627 * *@sfbay == * 1628 * *@sfbay => "" 1629 * If looking up windows users foo@sfbay and foo does not exists in 1630 * the name service then we will return no mapping for foo@sfbay. 1631 * 1632 */ 1633 static idmap_retcode 1634 name_based_mapping_sid2pid(sqlite *db, idmap_mapping *req, idmap_id_res *res) { 1635 const char *unixname, *winname, *windomain; 1636 char *sql = NULL, *errmsg = NULL; 1637 idmap_retcode retcode; 1638 char *end; 1639 const char **values; 1640 sqlite_vm *vm = NULL; 1641 int ncol, r, i, is_user; 1642 const char *me = "name_based_mapping_sid2pid"; 1643 1644 winname = req->id1name; 1645 windomain = req->id1domain; 1646 is_user = (res->id.idtype == IDMAP_UID)?1:0; 1647 1648 i = 0; 1649 if (windomain == NULL) { 1650 windomain = ""; 1651 } else { 1652 RDLOCK_CONFIG(); 1653 if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) { 1654 if (strcasecmp(_idmapdstate.cfg->pgcfg.mapping_domain, 1655 windomain) == 0) 1656 i = 1; 1657 } 1658 UNLOCK_CONFIG(); 1659 } 1660 1661 sql = sqlite_mprintf( 1662 "SELECT unixname, u2w_order FROM namerules WHERE " 1663 "w2u_order > 0 AND is_user = %d AND " 1664 "(winname = %Q OR winname = '*') AND " 1665 "(windomain = %Q OR windomain = '*' %s) " 1666 "ORDER BY w2u_order ASC;", 1667 is_user, winname, 1668 windomain, 1669 i?"OR windomain ISNULL OR windomain = ''":""); 1670 if (sql == NULL) { 1671 idmapdlog(LOG_ERR, "Out of memory"); 1672 retcode = IDMAP_ERR_MEMORY; 1673 goto out; 1674 } 1675 1676 if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) { 1677 retcode = IDMAP_ERR_INTERNAL; 1678 idmapdlog(LOG_ERR, 1679 "%s: database error (%s)", 1680 me, CHECK_NULL(errmsg)); 1681 sqlite_freemem(errmsg); 1682 goto out; 1683 } 1684 1685 for (; ; ) { 1686 r = sqlite_step(vm, &ncol, &values, NULL); 1687 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 1688 1689 if (r == SQLITE_ROW) { 1690 if (ncol < 2) { 1691 retcode = IDMAP_ERR_INTERNAL; 1692 goto out; 1693 } 1694 if (values[0] == NULL) { 1695 retcode = IDMAP_ERR_INTERNAL; 1696 goto out; 1697 } 1698 1699 if (EMPTY_NAME(values[0])) { 1700 retcode = IDMAP_ERR_NOMAPPING; 1701 goto out; 1702 } 1703 unixname = (values[0][0] == '*')?winname:values[0]; 1704 retcode = ns_lookup_byname(is_user, unixname, res); 1705 if (retcode == IDMAP_ERR_NOTFOUND) { 1706 if (unixname == winname) 1707 /* Case 4 */ 1708 continue; 1709 else 1710 /* Case 3 */ 1711 retcode = IDMAP_ERR_NOMAPPING; 1712 } 1713 goto out; 1714 } else if (r == SQLITE_DONE) { 1715 retcode = IDMAP_ERR_NOTFOUND; 1716 goto out; 1717 } else { 1718 (void) sqlite_finalize(vm, &errmsg); 1719 vm = NULL; 1720 idmapdlog(LOG_ERR, 1721 "%s: database error (%s)", 1722 me, CHECK_NULL(errmsg)); 1723 sqlite_freemem(errmsg); 1724 retcode = IDMAP_ERR_INTERNAL; 1725 goto out; 1726 } 1727 } 1728 1729 out: 1730 if (sql != NULL) 1731 sqlite_freemem(sql); 1732 if (retcode == IDMAP_SUCCESS) { 1733 if (values[1] != NULL) 1734 res->direction = 1735 (strtol(values[1], &end, 10) == 0)? 1736 IDMAP_DIRECTION_W2U:IDMAP_DIRECTION_BI; 1737 else 1738 res->direction = IDMAP_DIRECTION_W2U; 1739 req->id2name = strdup(unixname); 1740 } 1741 if (vm != NULL) 1742 (void) sqlite_finalize(vm, NULL); 1743 return (retcode); 1744 } 1745 1746 static 1747 int 1748 get_next_eph_uid(uid_t *next_uid) 1749 { 1750 uid_t uid; 1751 gid_t gid; 1752 int err; 1753 1754 *next_uid = (uid_t)-1; 1755 uid = _idmapdstate.next_uid++; 1756 if (uid >= _idmapdstate.limit_uid) { 1757 if ((err = allocids(0, 8192, &uid, 0, &gid)) != 0) 1758 return (err); 1759 1760 _idmapdstate.limit_uid = uid + 8192; 1761 _idmapdstate.next_uid = uid; 1762 } 1763 *next_uid = uid; 1764 1765 return (0); 1766 } 1767 1768 static 1769 int 1770 get_next_eph_gid(gid_t *next_gid) 1771 { 1772 uid_t uid; 1773 gid_t gid; 1774 int err; 1775 1776 *next_gid = (uid_t)-1; 1777 gid = _idmapdstate.next_gid++; 1778 if (gid >= _idmapdstate.limit_gid) { 1779 if ((err = allocids(0, 0, &uid, 8192, &gid)) != 0) 1780 return (err); 1781 1782 _idmapdstate.limit_gid = gid + 8192; 1783 _idmapdstate.next_gid = gid; 1784 } 1785 *next_gid = gid; 1786 1787 return (0); 1788 } 1789 1790 static 1791 int 1792 gethash(const char *str, uint32_t num, uint_t htsize) { 1793 uint_t hval, i, len; 1794 1795 if (str == NULL) 1796 return (0); 1797 for (len = strlen(str), hval = 0, i = 0; i < len; i++) { 1798 hval += str[i]; 1799 hval += (hval << 10); 1800 hval ^= (hval >> 6); 1801 } 1802 for (str = (const char *)&num, i = 0; i < sizeof (num); i++) { 1803 hval += str[i]; 1804 hval += (hval << 10); 1805 hval ^= (hval >> 6); 1806 } 1807 hval += (hval << 3); 1808 hval ^= (hval >> 11); 1809 hval += (hval << 15); 1810 return (hval % htsize); 1811 } 1812 1813 static 1814 int 1815 get_from_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid, 1816 uid_t *pid) { 1817 uint_t next, key; 1818 uint_t htsize = state->sid_history_size; 1819 idmap_sid *sid; 1820 1821 next = gethash(prefix, rid, htsize); 1822 while (next != htsize) { 1823 key = state->sid_history[next].key; 1824 if (key == htsize) 1825 return (0); 1826 sid = &state->batch->idmap_mapping_batch_val[key].id1. 1827 idmap_id_u.sid; 1828 if (sid->rid == rid && strcmp(sid->prefix, prefix) == 0) { 1829 *pid = state->result->ids.ids_val[key].id. 1830 idmap_id_u.uid; 1831 return (1); 1832 } 1833 next = state->sid_history[next].next; 1834 } 1835 return (0); 1836 } 1837 1838 static 1839 void 1840 add_to_sid_history(lookup_state_t *state, const char *prefix, uint32_t rid) { 1841 uint_t hash, next; 1842 uint_t htsize = state->sid_history_size; 1843 1844 hash = next = gethash(prefix, rid, htsize); 1845 while (state->sid_history[next].key != htsize) { 1846 next++; 1847 next %= htsize; 1848 } 1849 state->sid_history[next].key = state->curpos; 1850 if (hash == next) 1851 return; 1852 state->sid_history[next].next = state->sid_history[hash].next; 1853 state->sid_history[hash].next = next; 1854 } 1855 1856 /* ARGSUSED */ 1857 static 1858 idmap_retcode 1859 dynamic_ephemeral_mapping(lookup_state_t *state, sqlite *cache, 1860 idmap_mapping *req, idmap_id_res *res) { 1861 1862 uid_t next_pid; 1863 1864 res->direction = IDMAP_DIRECTION_BI; 1865 1866 if (IS_EPHEMERAL(res->id.idmap_id_u.uid)) 1867 return (IDMAP_SUCCESS); 1868 1869 if (state->sid_history != NULL && 1870 get_from_sid_history(state, req->id1.idmap_id_u.sid.prefix, 1871 req->id1.idmap_id_u.sid.rid, &next_pid)) { 1872 res->id.idmap_id_u.uid = next_pid; 1873 return (IDMAP_SUCCESS); 1874 } 1875 1876 if (res->id.idtype == IDMAP_UID) { 1877 if (get_next_eph_uid(&next_pid) != 0) 1878 return (IDMAP_ERR_INTERNAL); 1879 res->id.idmap_id_u.uid = next_pid; 1880 } else { 1881 if (get_next_eph_gid(&next_pid) != 0) 1882 return (IDMAP_ERR_INTERNAL); 1883 res->id.idmap_id_u.gid = next_pid; 1884 } 1885 1886 if (state->sid_history != NULL) 1887 add_to_sid_history(state, req->id1.idmap_id_u.sid.prefix, 1888 req->id1.idmap_id_u.sid.rid); 1889 1890 return (IDMAP_SUCCESS); 1891 } 1892 1893 idmap_retcode 1894 sid2pid_second_pass(lookup_state_t *state, sqlite *cache, sqlite *db, 1895 idmap_mapping *req, idmap_id_res *res) { 1896 idmap_retcode retcode; 1897 1898 /* 1899 * The req->direction field is used to maintain state of the 1900 * sid2pid request. 1901 */ 1902 1903 /* Check if second pass is needed */ 1904 if (req->direction == _IDMAP_F_DONE) 1905 return (res->retcode); 1906 1907 /* Get status from previous pass */ 1908 retcode = (res->retcode == IDMAP_NEXT)?IDMAP_SUCCESS:res->retcode; 1909 1910 if (retcode != IDMAP_SUCCESS) { 1911 /* Reset return type */ 1912 res->id.idtype = req->id2.idtype; 1913 res->id.idmap_id_u.uid = UID_NOBODY; 1914 1915 /* Check if this is a localsid */ 1916 if (retcode == IDMAP_ERR_NOTFOUND && 1917 _idmapdstate.cfg->pgcfg.machine_sid) { 1918 retcode = lookup_localsid2pid(req, res); 1919 if (retcode == IDMAP_SUCCESS) { 1920 state->sid2pid_done = FALSE; 1921 req->direction = _IDMAP_F_S2N_CACHE; 1922 } 1923 } 1924 goto out; 1925 } 1926 1927 /* 1928 * Verify that the sid type matches the request if the 1929 * SID was validated by an AD lookup. 1930 */ 1931 if (req->direction & _IDMAP_F_S2N_AD) { 1932 retcode = verify_type(req->id2.idtype, 1933 (int)res->id.idtype, res); 1934 if (retcode != IDMAP_SUCCESS) { 1935 res->id.idtype = req->id2.idtype; 1936 res->id.idmap_id_u.uid = UID_NOBODY; 1937 goto out; 1938 } 1939 } 1940 1941 /* Name-based mapping */ 1942 retcode = name_based_mapping_sid2pid(db, req, res); 1943 if (retcode == IDMAP_ERR_NOTFOUND) 1944 /* If not found, do ephemeral mapping */ 1945 goto ephemeral; 1946 else if (retcode != IDMAP_SUCCESS) 1947 goto out; 1948 1949 state->sid2pid_done = FALSE; 1950 goto out; 1951 1952 1953 ephemeral: 1954 retcode = dynamic_ephemeral_mapping(state, cache, req, res); 1955 if (retcode == IDMAP_SUCCESS) 1956 state->sid2pid_done = FALSE; 1957 1958 out: 1959 res->retcode = idmap_stat4prot(retcode); 1960 return (retcode); 1961 } 1962 1963 idmap_retcode 1964 update_cache_pid2sid(lookup_state_t *state, sqlite *cache, 1965 idmap_mapping *req, idmap_id_res *res) { 1966 char *sql = NULL; 1967 idmap_retcode retcode; 1968 1969 /* Check if we need to cache anything */ 1970 if (req->direction == _IDMAP_F_DONE) 1971 return (IDMAP_SUCCESS); 1972 1973 /* We don't cache negative entries */ 1974 if (res->retcode != IDMAP_SUCCESS) 1975 return (IDMAP_SUCCESS); 1976 1977 /* 1978 * Using NULL for u2w instead of 0 so that our trigger allows 1979 * the same pid to be the destination in multiple entries 1980 */ 1981 sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache " 1982 "(sidprefix, rid, windomain, winname, pid, unixname, " 1983 "is_user, expiration, w2u, u2w) " 1984 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, " 1985 "strftime('%%s','now') + 600, %q, 1); ", 1986 res->id.idmap_id_u.sid.prefix, 1987 res->id.idmap_id_u.sid.rid, 1988 req->id2domain, 1989 req->id2name, 1990 req->id1.idmap_id_u.uid, 1991 req->id1name, 1992 (req->id1.idtype == IDMAP_UID)?1:0, 1993 (res->direction == 0)?"1":NULL); 1994 1995 if (sql == NULL) { 1996 retcode = IDMAP_ERR_INTERNAL; 1997 idmapdlog(LOG_ERR, "Out of memory"); 1998 goto out; 1999 } 2000 2001 retcode = sql_exec_no_cb(cache, sql); 2002 if (retcode != IDMAP_SUCCESS) 2003 goto out; 2004 2005 state->pid2sid_done = FALSE; 2006 sqlite_freemem(sql); 2007 sql = NULL; 2008 2009 /* If sid2name was found in the cache, no need to update namecache */ 2010 if (req->direction & _IDMAP_F_S2N_CACHE) 2011 goto out; 2012 2013 if (req->id2name == NULL) 2014 goto out; 2015 2016 sql = sqlite_mprintf("INSERT OR REPLACE into name_cache " 2017 "(sidprefix, rid, name, domain, type, expiration) " 2018 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ", 2019 res->id.idmap_id_u.sid.prefix, 2020 res->id.idmap_id_u.sid.rid, 2021 req->id2name, 2022 req->id2domain, 2023 (req->id1.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP); 2024 2025 if (sql == NULL) { 2026 retcode = IDMAP_ERR_INTERNAL; 2027 idmapdlog(LOG_ERR, "Out of memory"); 2028 goto out; 2029 } 2030 2031 retcode = sql_exec_no_cb(cache, sql); 2032 2033 out: 2034 if (sql != NULL) 2035 sqlite_freemem(sql); 2036 return (retcode); 2037 } 2038 2039 idmap_retcode 2040 update_cache_sid2pid(lookup_state_t *state, sqlite *cache, 2041 idmap_mapping *req, idmap_id_res *res) { 2042 char *sql = NULL; 2043 idmap_retcode retcode; 2044 int is_eph_user; 2045 2046 /* Check if we need to cache anything */ 2047 if (req->direction == _IDMAP_F_DONE) 2048 return (IDMAP_SUCCESS); 2049 2050 /* We don't cache negative entries */ 2051 if (res->retcode != IDMAP_SUCCESS) 2052 return (IDMAP_SUCCESS); 2053 2054 if (req->direction & _IDMAP_F_EXP_EPH_UID) 2055 is_eph_user = 1; 2056 else if (req->direction & _IDMAP_F_EXP_EPH_GID) 2057 is_eph_user = 0; 2058 else 2059 is_eph_user = -1; 2060 2061 if (is_eph_user >= 0 && !IS_EPHEMERAL(res->id.idmap_id_u.uid)) { 2062 sql = sqlite_mprintf("UPDATE idmap_cache " 2063 "SET w2u = 0 WHERE " 2064 "sidprefix = %Q AND rid = %u AND w2u = 1 AND " 2065 "pid >= 2147483648 AND is_user = %d;", 2066 req->id1.idmap_id_u.sid.prefix, 2067 req->id1.idmap_id_u.sid.rid, 2068 is_eph_user); 2069 if (sql == NULL) { 2070 retcode = IDMAP_ERR_INTERNAL; 2071 idmapdlog(LOG_ERR, "Out of memory"); 2072 goto out; 2073 } 2074 2075 retcode = sql_exec_no_cb(cache, sql); 2076 if (retcode != IDMAP_SUCCESS) 2077 goto out; 2078 2079 sqlite_freemem(sql); 2080 sql = NULL; 2081 } 2082 2083 sql = sqlite_mprintf("INSERT OR REPLACE into idmap_cache " 2084 "(sidprefix, rid, windomain, winname, pid, unixname, " 2085 "is_user, expiration, w2u, u2w) " 2086 "VALUES(%Q, %u, %Q, %Q, %u, %Q, %d, " 2087 "strftime('%%s','now') + 600, 1, %q); ", 2088 req->id1.idmap_id_u.sid.prefix, 2089 req->id1.idmap_id_u.sid.rid, 2090 req->id1domain, 2091 req->id1name, 2092 res->id.idmap_id_u.uid, 2093 req->id2name, 2094 (res->id.idtype == IDMAP_UID)?1:0, 2095 (res->direction == 0)?"1":NULL); 2096 2097 if (sql == NULL) { 2098 retcode = IDMAP_ERR_INTERNAL; 2099 idmapdlog(LOG_ERR, "Out of memory"); 2100 goto out; 2101 } 2102 2103 retcode = sql_exec_no_cb(cache, sql); 2104 if (retcode != IDMAP_SUCCESS) 2105 goto out; 2106 2107 state->sid2pid_done = FALSE; 2108 sqlite_freemem(sql); 2109 sql = NULL; 2110 2111 /* If name2sid was found in the cache, no need to update namecache */ 2112 if (req->direction & _IDMAP_F_S2N_CACHE) 2113 goto out; 2114 2115 if (req->id1name == NULL) 2116 goto out; 2117 2118 sql = sqlite_mprintf("INSERT OR REPLACE into name_cache " 2119 "(sidprefix, rid, name, domain, type, expiration) " 2120 "VALUES(%Q, %u, %Q, %Q, %d, strftime('%%s','now') + 3600); ", 2121 req->id1.idmap_id_u.sid.prefix, 2122 req->id1.idmap_id_u.sid.rid, 2123 req->id1name, 2124 req->id1domain, 2125 (res->id.idtype == IDMAP_UID)?_IDMAP_T_USER:_IDMAP_T_GROUP); 2126 2127 if (sql == NULL) { 2128 retcode = IDMAP_ERR_INTERNAL; 2129 idmapdlog(LOG_ERR, "Out of memory"); 2130 goto out; 2131 } 2132 2133 retcode = sql_exec_no_cb(cache, sql); 2134 2135 out: 2136 if (sql != NULL) 2137 sqlite_freemem(sql); 2138 return (retcode); 2139 } 2140 2141 static idmap_retcode 2142 lookup_cache_pid2sid(sqlite *cache, idmap_mapping *req, idmap_id_res *res, 2143 int is_user, int getname) { 2144 char *end; 2145 char *sql = NULL; 2146 const char **values; 2147 sqlite_vm *vm = NULL; 2148 int ncol; 2149 idmap_retcode retcode = IDMAP_SUCCESS; 2150 time_t curtime; 2151 2152 /* Current time */ 2153 errno = 0; 2154 if ((curtime = time(NULL)) == (time_t)-1) { 2155 idmapdlog(LOG_ERR, 2156 "Failed to get current time (%s)", 2157 strerror(errno)); 2158 retcode = IDMAP_ERR_INTERNAL; 2159 goto out; 2160 } 2161 2162 /* SQL to lookup the cache */ 2163 sql = sqlite_mprintf("SELECT sidprefix, rid, winname, windomain, w2u " 2164 "FROM idmap_cache WHERE " 2165 "pid = %u AND u2w = 1 AND is_user = %d AND " 2166 "(pid >= 2147483648 OR " 2167 "(expiration = 0 OR expiration ISNULL OR " 2168 "expiration > %d));", 2169 req->id1.idmap_id_u.uid, is_user, curtime); 2170 if (sql == NULL) { 2171 idmapdlog(LOG_ERR, "Out of memory"); 2172 retcode = IDMAP_ERR_MEMORY; 2173 goto out; 2174 } 2175 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 5, &values); 2176 sqlite_freemem(sql); 2177 2178 if (retcode == IDMAP_ERR_NOTFOUND) 2179 goto out; 2180 else if (retcode == IDMAP_SUCCESS) { 2181 /* sanity checks */ 2182 if (values[0] == NULL || values[1] == NULL) { 2183 retcode = IDMAP_ERR_CACHE; 2184 goto out; 2185 } 2186 2187 switch (req->id2.idtype) { 2188 case IDMAP_SID: 2189 res->id.idmap_id_u.sid.rid = 2190 strtoul(values[1], &end, 10); 2191 res->id.idmap_id_u.sid.prefix = strdup(values[0]); 2192 if (res->id.idmap_id_u.sid.prefix == NULL) { 2193 idmapdlog(LOG_ERR, "Out of memory"); 2194 retcode = IDMAP_ERR_MEMORY; 2195 goto out; 2196 } 2197 2198 if (values[4] != NULL) 2199 res->direction = 2200 (strtol(values[4], &end, 10) == 0)? 2201 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; 2202 else 2203 res->direction = IDMAP_DIRECTION_U2W; 2204 2205 if (getname == 0 || values[2] == NULL) 2206 break; 2207 req->id2name = strdup(values[2]); 2208 if (req->id2name == NULL) { 2209 idmapdlog(LOG_ERR, "Out of memory"); 2210 retcode = IDMAP_ERR_MEMORY; 2211 goto out; 2212 } 2213 2214 if (values[3] == NULL) 2215 break; 2216 req->id2domain = strdup(values[3]); 2217 if (req->id2domain == NULL) { 2218 idmapdlog(LOG_ERR, "Out of memory"); 2219 retcode = IDMAP_ERR_MEMORY; 2220 goto out; 2221 } 2222 break; 2223 default: 2224 retcode = IDMAP_ERR_NOTSUPPORTED; 2225 break; 2226 } 2227 } 2228 2229 out: 2230 if (vm != NULL) 2231 (void) sqlite_finalize(vm, NULL); 2232 return (retcode); 2233 } 2234 2235 static idmap_retcode 2236 lookup_cache_name2sid(sqlite *cache, const char *name, const char *domain, 2237 char **sidprefix, idmap_rid_t *rid, int *type) { 2238 char *end; 2239 char *sql = NULL; 2240 const char **values; 2241 sqlite_vm *vm = NULL; 2242 int ncol; 2243 time_t curtime; 2244 idmap_retcode retcode = IDMAP_SUCCESS; 2245 2246 /* Get current time */ 2247 errno = 0; 2248 if ((curtime = time(NULL)) == (time_t)-1) { 2249 idmapdlog(LOG_ERR, 2250 "Failed to get current time (%s)", 2251 strerror(errno)); 2252 retcode = IDMAP_ERR_INTERNAL; 2253 goto out; 2254 } 2255 2256 /* SQL to lookup the cache */ 2257 sql = sqlite_mprintf("SELECT sidprefix, rid, type FROM name_cache " 2258 "WHERE name = %Q AND domain = %Q AND " 2259 "(expiration = 0 OR expiration ISNULL OR " 2260 "expiration > %d);", 2261 name, domain, curtime); 2262 if (sql == NULL) { 2263 idmapdlog(LOG_ERR, "Out of memory"); 2264 retcode = IDMAP_ERR_MEMORY; 2265 goto out; 2266 } 2267 retcode = sql_compile_n_step_once(cache, sql, &vm, &ncol, 3, &values); 2268 sqlite_freemem(sql); 2269 2270 if (retcode == IDMAP_SUCCESS) { 2271 if (type != NULL) { 2272 if (values[2] == NULL) { 2273 retcode = IDMAP_ERR_CACHE; 2274 goto out; 2275 } 2276 *type = strtol(values[2], &end, 10); 2277 } 2278 2279 if (values[0] == NULL || values[1] == NULL) { 2280 retcode = IDMAP_ERR_CACHE; 2281 goto out; 2282 } 2283 if ((*sidprefix = strdup(values[0])) == NULL) { 2284 idmapdlog(LOG_ERR, "Out of memory"); 2285 retcode = IDMAP_ERR_MEMORY; 2286 goto out; 2287 } 2288 *rid = strtoul(values[1], &end, 10); 2289 } 2290 2291 out: 2292 if (vm != NULL) 2293 (void) sqlite_finalize(vm, NULL); 2294 return (retcode); 2295 } 2296 2297 static idmap_retcode 2298 lookup_win_name2sid(const char *name, const char *domain, char **sidprefix, 2299 idmap_rid_t *rid, int *type) { 2300 int ret; 2301 int retries = 0; 2302 idmap_query_state_t *qs = NULL; 2303 idmap_retcode rc, retcode; 2304 2305 retcode = IDMAP_ERR_NOTFOUND; 2306 2307 retry: 2308 ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs); 2309 if (ret != 0) { 2310 idmapdlog(LOG_ERR, 2311 "Failed to create name2sid batch for AD lookup"); 2312 return (IDMAP_ERR_INTERNAL); 2313 } 2314 2315 retcode = idmap_name2sid_batch_add1(qs, name, domain, sidprefix, 2316 rid, type, &rc); 2317 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 2318 goto out; 2319 2320 if (retcode != IDMAP_SUCCESS) { 2321 idmapdlog(LOG_ERR, 2322 "Failed to batch name2sid for AD lookup"); 2323 idmap_lookup_release_batch(&qs); 2324 return (IDMAP_ERR_INTERNAL); 2325 } 2326 2327 out: 2328 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR) 2329 idmap_lookup_release_batch(&qs); 2330 else 2331 retcode = idmap_lookup_batch_end(&qs, NULL); 2332 2333 if (retcode == IDMAP_ERR_RETRIABLE_NET_ERR && retries++ < 2) 2334 goto retry; 2335 2336 if (retcode != IDMAP_SUCCESS) { 2337 idmapdlog(LOG_NOTICE, "Windows user/group name to SID lookup " 2338 "failed"); 2339 return (retcode); 2340 } else 2341 return (rc); 2342 /* NOTREACHED */ 2343 } 2344 2345 static idmap_retcode 2346 lookup_name2sid(sqlite *cache, const char *name, const char *domain, 2347 int *is_user, char **sidprefix, idmap_rid_t *rid, 2348 idmap_mapping *req) { 2349 int type; 2350 idmap_retcode retcode; 2351 2352 /* Lookup name@domain to sid in the well-known sids table */ 2353 retcode = lookup_wksids_name2sid(name, sidprefix, rid, &type); 2354 if (retcode == IDMAP_SUCCESS) { 2355 req->direction |= _IDMAP_F_S2N_CACHE; 2356 goto out; 2357 } else if (retcode != IDMAP_ERR_NOTFOUND) { 2358 return (retcode); 2359 } 2360 2361 /* Lookup name@domain to sid in cache */ 2362 retcode = lookup_cache_name2sid(cache, name, domain, sidprefix, 2363 rid, &type); 2364 if (retcode == IDMAP_ERR_NOTFOUND) { 2365 /* Lookup Windows NT/AD to map name@domain to sid */ 2366 retcode = lookup_win_name2sid(name, domain, sidprefix, rid, 2367 &type); 2368 if (retcode != IDMAP_SUCCESS) 2369 return (retcode); 2370 req->direction |= _IDMAP_F_S2N_AD; 2371 } else if (retcode != IDMAP_SUCCESS) { 2372 return (retcode); 2373 } else { 2374 /* Set flag */ 2375 req->direction |= _IDMAP_F_S2N_CACHE; 2376 } 2377 2378 out: 2379 /* 2380 * Entry found (cache or Windows lookup) 2381 * is_user is both input as well as output parameter 2382 */ 2383 if (*is_user == 1) { 2384 if (type != _IDMAP_T_USER) 2385 return (IDMAP_ERR_NOTUSER); 2386 } else if (*is_user == 0) { 2387 if (type != _IDMAP_T_GROUP) 2388 return (IDMAP_ERR_NOTGROUP); 2389 } else if (*is_user == -1) { 2390 /* Caller wants to know if its user or group */ 2391 if (type == _IDMAP_T_USER) 2392 *is_user = 1; 2393 else if (type == _IDMAP_T_GROUP) 2394 *is_user = 0; 2395 else 2396 return (IDMAP_ERR_SID); 2397 } 2398 2399 return (retcode); 2400 } 2401 2402 static idmap_retcode 2403 name_based_mapping_pid2sid(sqlite *db, sqlite *cache, const char *unixname, 2404 int is_user, idmap_mapping *req, idmap_id_res *res) { 2405 const char *winname, *windomain; 2406 char *mapping_domain = NULL; 2407 char *sql = NULL, *errmsg = NULL; 2408 idmap_retcode retcode; 2409 char *end; 2410 const char **values; 2411 sqlite_vm *vm = NULL; 2412 int ncol, r; 2413 const char *me = "name_based_mapping_pid2sid"; 2414 2415 RDLOCK_CONFIG(); 2416 if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) { 2417 mapping_domain = 2418 strdup(_idmapdstate.cfg->pgcfg.mapping_domain); 2419 if (mapping_domain == NULL) { 2420 UNLOCK_CONFIG(); 2421 idmapdlog(LOG_ERR, "Out of memory"); 2422 retcode = IDMAP_ERR_MEMORY; 2423 goto out; 2424 } 2425 } 2426 UNLOCK_CONFIG(); 2427 2428 sql = sqlite_mprintf( 2429 "SELECT winname, windomain, w2u_order FROM namerules WHERE " 2430 "u2w_order > 0 AND is_user = %d AND " 2431 "(unixname = %Q OR unixname = '*') " 2432 "ORDER BY u2w_order ASC;", 2433 is_user, unixname); 2434 if (sql == NULL) { 2435 idmapdlog(LOG_ERR, "Out of memory"); 2436 retcode = IDMAP_ERR_MEMORY; 2437 goto out; 2438 } 2439 2440 if (sqlite_compile(db, sql, NULL, &vm, &errmsg) != SQLITE_OK) { 2441 retcode = IDMAP_ERR_INTERNAL; 2442 idmapdlog(LOG_ERR, 2443 "%s: database error (%s)", 2444 me, CHECK_NULL(errmsg)); 2445 sqlite_freemem(errmsg); 2446 goto out; 2447 } 2448 2449 for (;;) { 2450 r = sqlite_step(vm, &ncol, &values, NULL); 2451 assert(r != SQLITE_LOCKED && r != SQLITE_BUSY); 2452 if (r == SQLITE_ROW) { 2453 if (ncol < 3) { 2454 retcode = IDMAP_ERR_INTERNAL; 2455 goto out; 2456 } 2457 if (values[0] == NULL) { 2458 /* values [1] and [2] can be null */ 2459 retcode = IDMAP_ERR_INTERNAL; 2460 goto out; 2461 } 2462 if (EMPTY_NAME(values[0])) { 2463 retcode = IDMAP_ERR_NOMAPPING; 2464 goto out; 2465 } 2466 winname = (values[0][0] == '*')?unixname:values[0]; 2467 if (values[1] != NULL) 2468 windomain = values[1]; 2469 else if (mapping_domain != NULL) 2470 windomain = mapping_domain; 2471 else { 2472 idmapdlog(LOG_ERR, 2473 "%s: no domain", me); 2474 retcode = IDMAP_ERR_DOMAIN_NOTFOUND; 2475 goto out; 2476 } 2477 /* Lookup winname@domain to sid */ 2478 retcode = lookup_name2sid(cache, winname, windomain, 2479 &is_user, &res->id.idmap_id_u.sid.prefix, 2480 &res->id.idmap_id_u.sid.rid, req); 2481 if (retcode == IDMAP_ERR_NOTFOUND) { 2482 if (winname == unixname) 2483 continue; 2484 else 2485 retcode = IDMAP_ERR_NOMAPPING; 2486 } 2487 goto out; 2488 } else if (r == SQLITE_DONE) { 2489 retcode = IDMAP_ERR_NOTFOUND; 2490 goto out; 2491 } else { 2492 (void) sqlite_finalize(vm, &errmsg); 2493 vm = NULL; 2494 idmapdlog(LOG_ERR, 2495 "%s: database error (%s)", 2496 me, CHECK_NULL(errmsg)); 2497 sqlite_freemem(errmsg); 2498 retcode = IDMAP_ERR_INTERNAL; 2499 goto out; 2500 } 2501 } 2502 2503 out: 2504 if (sql != NULL) 2505 sqlite_freemem(sql); 2506 if (retcode == IDMAP_SUCCESS) { 2507 if (values[2] != NULL) 2508 res->direction = 2509 (strtol(values[2], &end, 10) == 0)? 2510 IDMAP_DIRECTION_U2W:IDMAP_DIRECTION_BI; 2511 else 2512 res->direction = IDMAP_DIRECTION_U2W; 2513 2514 req->id2name = strdup(winname); 2515 if (req->id2name != NULL) { 2516 if (windomain == mapping_domain) { 2517 req->id2domain = (char *)windomain; 2518 mapping_domain = NULL; 2519 } else { 2520 req->id2domain = strdup(windomain); 2521 } 2522 } 2523 } 2524 if (vm != NULL) 2525 (void) sqlite_finalize(vm, NULL); 2526 if (mapping_domain != NULL) 2527 free(mapping_domain); 2528 return (retcode); 2529 } 2530 2531 idmap_retcode 2532 pid2sid_first_pass(lookup_state_t *state, sqlite *cache, sqlite *db, 2533 idmap_mapping *req, idmap_id_res *res, int is_user, 2534 int getname) { 2535 char *unixname = NULL; 2536 struct passwd pwd; 2537 struct group grp; 2538 char buf[1024]; 2539 int errnum; 2540 idmap_retcode retcode = IDMAP_SUCCESS; 2541 const char *me = "pid2sid"; 2542 2543 req->direction = _IDMAP_F_DONE; 2544 res->id.idtype = req->id2.idtype; 2545 2546 /* Lookup well-known SIDs */ 2547 retcode = lookup_wksids_pid2sid(req, res, is_user); 2548 if (retcode != IDMAP_ERR_NOTFOUND) 2549 goto out; 2550 2551 /* Lookup pid to sid in cache */ 2552 retcode = lookup_cache_pid2sid(cache, req, res, is_user, getname); 2553 if (retcode != IDMAP_ERR_NOTFOUND) 2554 goto out; 2555 2556 /* Ephemeral ids cannot be allocated during pid2sid */ 2557 if (IS_EPHEMERAL(req->id1.idmap_id_u.uid)) { 2558 retcode = IDMAP_ERR_NOMAPPING; 2559 goto out; 2560 } 2561 2562 if (DO_NOT_ALLOC_NEW_ID_MAPPING(req) || AVOID_NAMESERVICE(req)) { 2563 retcode = IDMAP_ERR_NOMAPPING; 2564 goto out; 2565 } 2566 2567 /* uid/gid to name */ 2568 if (req->id1name != NULL) { 2569 unixname = req->id1name; 2570 } else if (is_user) { 2571 errno = 0; 2572 if (getpwuid_r(req->id1.idmap_id_u.uid, &pwd, buf, 2573 sizeof (buf)) == NULL) { 2574 errnum = errno; 2575 idmapdlog(LOG_WARNING, 2576 "%s: getpwuid_r(%u) failed (%s).", 2577 me, req->id1.idmap_id_u.uid, 2578 errnum?strerror(errnum):"not found"); 2579 retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND: 2580 IDMAP_ERR_INTERNAL; 2581 goto fallback_localsid; 2582 } 2583 unixname = pwd.pw_name; 2584 } else { 2585 errno = 0; 2586 if (getgrgid_r(req->id1.idmap_id_u.gid, &grp, buf, 2587 sizeof (buf)) == NULL) { 2588 errnum = errno; 2589 idmapdlog(LOG_WARNING, 2590 "%s: getgrgid_r(%u) failed (%s).", 2591 me, req->id1.idmap_id_u.gid, 2592 errnum?strerror(errnum):"not found"); 2593 retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND: 2594 IDMAP_ERR_INTERNAL; 2595 goto fallback_localsid; 2596 } 2597 unixname = grp.gr_name; 2598 } 2599 2600 /* Name-based mapping */ 2601 retcode = name_based_mapping_pid2sid(db, cache, unixname, is_user, 2602 req, res); 2603 if (retcode == IDMAP_ERR_NOTFOUND) { 2604 retcode = generate_localsid(req, res, is_user); 2605 goto out; 2606 } else if (retcode == IDMAP_SUCCESS) 2607 goto out; 2608 2609 fallback_localsid: 2610 /* 2611 * Here we generate localsid as fallback id on errors. Our 2612 * return status is the error that's been previously assigned. 2613 */ 2614 (void) generate_localsid(req, res, is_user); 2615 2616 out: 2617 if (retcode == IDMAP_SUCCESS && req->id1name == NULL && 2618 unixname != NULL) { 2619 req->id1name = strdup(unixname); 2620 } 2621 if (req->direction != _IDMAP_F_DONE) 2622 state->pid2sid_done = FALSE; 2623 res->retcode = idmap_stat4prot(retcode); 2624 return (retcode); 2625 } 2626 2627 static idmap_retcode 2628 lookup_win_sid2name(const char *sidprefix, idmap_rid_t rid, char **name, 2629 char **domain, int *type) { 2630 int ret; 2631 idmap_query_state_t *qs = NULL; 2632 idmap_retcode rc, retcode; 2633 2634 retcode = IDMAP_ERR_NOTFOUND; 2635 2636 ret = idmap_lookup_batch_start(_idmapdstate.ad, 1, &qs); 2637 if (ret != 0) { 2638 idmapdlog(LOG_ERR, 2639 "Failed to create sid2name batch for AD lookup"); 2640 retcode = IDMAP_ERR_INTERNAL; 2641 goto out; 2642 } 2643 2644 ret = idmap_sid2name_batch_add1( 2645 qs, sidprefix, &rid, name, domain, type, &rc); 2646 if (ret != 0) { 2647 idmapdlog(LOG_ERR, 2648 "Failed to batch sid2name for AD lookup"); 2649 retcode = IDMAP_ERR_INTERNAL; 2650 goto out; 2651 } 2652 2653 out: 2654 if (qs != NULL) { 2655 ret = idmap_lookup_batch_end(&qs, NULL); 2656 if (ret != 0) { 2657 idmapdlog(LOG_ERR, 2658 "Failed to execute sid2name AD lookup"); 2659 retcode = IDMAP_ERR_INTERNAL; 2660 } else 2661 retcode = rc; 2662 } 2663 2664 return (retcode); 2665 } 2666 2667 static int 2668 copy_mapping_request(idmap_mapping *mapping, idmap_mapping *request) 2669 { 2670 (void) memset(mapping, 0, sizeof (*mapping)); 2671 2672 mapping->flag = request->flag; 2673 mapping->direction = request->direction; 2674 mapping->id2.idtype = request->id2.idtype; 2675 2676 mapping->id1.idtype = request->id1.idtype; 2677 if (request->id1.idtype == IDMAP_SID) { 2678 mapping->id1.idmap_id_u.sid.rid = 2679 request->id1.idmap_id_u.sid.rid; 2680 if (!EMPTY_STRING(request->id1.idmap_id_u.sid.prefix)) { 2681 mapping->id1.idmap_id_u.sid.prefix = 2682 strdup(request->id1.idmap_id_u.sid.prefix); 2683 if (mapping->id1.idmap_id_u.sid.prefix == NULL) 2684 goto errout; 2685 } 2686 } else { 2687 mapping->id1.idmap_id_u.uid = request->id1.idmap_id_u.uid; 2688 } 2689 2690 mapping->id1domain = strdup(request->id1domain); 2691 if (mapping->id1domain == NULL) 2692 goto errout; 2693 2694 mapping->id1name = strdup(request->id1name); 2695 if (mapping->id1name == NULL) 2696 goto errout; 2697 2698 /* We don't need the rest of the request i.e request->id2 */ 2699 return (0); 2700 2701 errout: 2702 if (mapping->id1.idmap_id_u.sid.prefix != NULL) 2703 free(mapping->id1.idmap_id_u.sid.prefix); 2704 if (mapping->id1domain != NULL) 2705 free(mapping->id1domain); 2706 if (mapping->id1name != NULL) 2707 free(mapping->id1name); 2708 2709 (void) memset(mapping, 0, sizeof (*mapping)); 2710 return (-1); 2711 } 2712 2713 2714 idmap_retcode 2715 get_w2u_mapping(sqlite *cache, sqlite *db, idmap_mapping *request, 2716 idmap_mapping *mapping) { 2717 idmap_id_res idres; 2718 lookup_state_t state; 2719 char *cp; 2720 int is_user; 2721 idmap_retcode retcode; 2722 const char *winname, *windomain; 2723 2724 (void) memset(&idres, 0, sizeof (idres)); 2725 (void) memset(&state, 0, sizeof (state)); 2726 2727 if (request->id2.idtype == IDMAP_UID) 2728 is_user = 1; 2729 else if (request->id2.idtype == IDMAP_GID) 2730 is_user = 0; 2731 else if (request->id2.idtype == IDMAP_POSIXID) 2732 is_user = -1; 2733 else { 2734 retcode = IDMAP_ERR_IDTYPE; 2735 goto out; 2736 } 2737 2738 /* Copy data from request to result */ 2739 if (copy_mapping_request(mapping, request) < 0) { 2740 retcode = IDMAP_ERR_MEMORY; 2741 goto out; 2742 } 2743 2744 winname = mapping->id1name; 2745 windomain = mapping->id1domain; 2746 2747 if (winname == NULL && windomain != NULL) { 2748 retcode = IDMAP_ERR_ARG; 2749 goto out; 2750 } 2751 2752 if (winname != NULL && windomain == NULL) { 2753 retcode = IDMAP_SUCCESS; 2754 if ((cp = strchr(winname, '@')) != NULL) { 2755 /* 2756 * if winname is qualified with a domain, use it. 2757 */ 2758 *cp = '\0'; 2759 mapping->id1domain = strdup(cp + 1); 2760 if (mapping->id1domain == NULL) 2761 retcode = IDMAP_ERR_MEMORY; 2762 } else { 2763 RDLOCK_CONFIG(); 2764 if (_idmapdstate.cfg->pgcfg.mapping_domain != NULL) { 2765 /* 2766 * otherwise use the mapping domain 2767 */ 2768 mapping->id1domain = 2769 strdup(_idmapdstate.cfg-> 2770 pgcfg.mapping_domain); 2771 if (mapping->id1domain == NULL) 2772 retcode = IDMAP_ERR_MEMORY; 2773 } 2774 UNLOCK_CONFIG(); 2775 } 2776 2777 if (retcode != IDMAP_SUCCESS) { 2778 idmapdlog(LOG_ERR, "Out of memory"); 2779 goto out; 2780 } 2781 windomain = mapping->id1domain; 2782 } 2783 2784 if (winname != NULL && mapping->id1.idmap_id_u.sid.prefix == NULL) { 2785 retcode = lookup_name2sid(cache, winname, windomain, 2786 &is_user, &mapping->id1.idmap_id_u.sid.prefix, 2787 &mapping->id1.idmap_id_u.sid.rid, mapping); 2788 if (retcode != IDMAP_SUCCESS) 2789 goto out; 2790 if (mapping->id2.idtype == IDMAP_POSIXID) 2791 mapping->id2.idtype = is_user?IDMAP_UID:IDMAP_GID; 2792 } 2793 2794 state.sid2pid_done = TRUE; 2795 retcode = sid2pid_first_pass(&state, cache, mapping, &idres); 2796 if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE) 2797 goto out; 2798 2799 if (state.ad_nqueries) { 2800 /* sid2name AD lookup */ 2801 retcode = lookup_win_sid2name( 2802 mapping->id1.idmap_id_u.sid.prefix, 2803 mapping->id1.idmap_id_u.sid.rid, 2804 &mapping->id1name, 2805 &mapping->id1domain, 2806 (int *)&idres.id.idtype); 2807 2808 idres.retcode = retcode; 2809 } 2810 2811 state.sid2pid_done = TRUE; 2812 retcode = sid2pid_second_pass(&state, cache, db, mapping, &idres); 2813 if (IDMAP_ERROR(retcode) || state.sid2pid_done == TRUE) 2814 goto out; 2815 2816 /* Update cache */ 2817 (void) update_cache_sid2pid(&state, cache, mapping, &idres); 2818 2819 out: 2820 if (retcode == IDMAP_SUCCESS) { 2821 mapping->direction = idres.direction; 2822 mapping->id2 = idres.id; 2823 (void) memset(&idres, 0, sizeof (idres)); 2824 } else { 2825 mapping->id2.idmap_id_u.uid = UID_NOBODY; 2826 } 2827 xdr_free(xdr_idmap_id_res, (caddr_t)&idres); 2828 return (retcode); 2829 } 2830 2831 idmap_retcode 2832 get_u2w_mapping(sqlite *cache, sqlite *db, idmap_mapping *request, 2833 idmap_mapping *mapping, int is_user) { 2834 idmap_id_res idres; 2835 lookup_state_t state; 2836 struct passwd pwd; 2837 struct group grp; 2838 char buf[1024]; 2839 int errnum; 2840 idmap_retcode retcode; 2841 const char *unixname; 2842 const char *me = "get_u2w_mapping"; 2843 2844 /* 2845 * In order to re-use the pid2sid code, we convert 2846 * our input data into structs that are expected by 2847 * pid2sid_first_pass. 2848 */ 2849 2850 (void) memset(&idres, 0, sizeof (idres)); 2851 (void) memset(&state, 0, sizeof (state)); 2852 2853 /* Copy data from request to result */ 2854 if (copy_mapping_request(mapping, request) < 0) { 2855 retcode = IDMAP_ERR_MEMORY; 2856 goto out; 2857 } 2858 2859 unixname = mapping->id1name; 2860 2861 if (unixname == NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) { 2862 retcode = IDMAP_ERR_ARG; 2863 goto out; 2864 } 2865 2866 if (unixname != NULL && mapping->id1.idmap_id_u.uid == SENTINEL_PID) { 2867 /* Get uid/gid by name */ 2868 if (is_user) { 2869 errno = 0; 2870 if (getpwnam_r(unixname, &pwd, buf, 2871 sizeof (buf)) == NULL) { 2872 errnum = errno; 2873 idmapdlog(LOG_WARNING, 2874 "%s: getpwnam_r(%s) failed (%s).", 2875 me, unixname, 2876 errnum?strerror(errnum):"not found"); 2877 retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND: 2878 IDMAP_ERR_INTERNAL; 2879 goto out; 2880 } 2881 mapping->id1.idmap_id_u.uid = pwd.pw_uid; 2882 } else { 2883 errno = 0; 2884 if (getgrnam_r(unixname, &grp, buf, 2885 sizeof (buf)) == NULL) { 2886 errnum = errno; 2887 idmapdlog(LOG_WARNING, 2888 "%s: getgrnam_r(%s) failed (%s).", 2889 me, unixname, 2890 errnum?strerror(errnum):"not found"); 2891 retcode = (errnum == 0)?IDMAP_ERR_NOTFOUND: 2892 IDMAP_ERR_INTERNAL; 2893 goto out; 2894 } 2895 mapping->id1.idmap_id_u.gid = grp.gr_gid; 2896 } 2897 } 2898 2899 state.pid2sid_done = TRUE; 2900 retcode = pid2sid_first_pass(&state, cache, db, mapping, &idres, 2901 is_user, 1); 2902 if (IDMAP_ERROR(retcode) || state.pid2sid_done == TRUE) 2903 goto out; 2904 2905 /* Update cache */ 2906 (void) update_cache_pid2sid(&state, cache, mapping, &idres); 2907 2908 out: 2909 mapping->direction = idres.direction; 2910 mapping->id2 = idres.id; 2911 (void) memset(&idres, 0, sizeof (idres)); 2912 xdr_free(xdr_idmap_id_res, (caddr_t)&idres); 2913 return (retcode); 2914 } 2915