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