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