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