1/* $OpenBSD: getpwent.c,v 1.68 2024/01/22 21:07:09 deraadt Exp $ */ 2/* 3 * Copyright (c) 2008 Theo de Raadt 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * Portions Copyright (c) 1994, 1995, 1996, Jason Downs. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/types.h> 34#include <sys/mman.h> 35#include <fcntl.h> 36#include <db.h> 37#include <syslog.h> 38#include <pwd.h> 39#include <errno.h> 40#include <unistd.h> 41#include <stdbool.h> 42#include <stdlib.h> 43#include <string.h> 44#include <limits.h> 45#include <netgroup.h> 46#ifdef YP 47#include <stdio.h> 48#include <rpc/rpc.h> 49#include <rpcsvc/yp.h> 50#include <rpcsvc/ypclnt.h> 51#include "ypinternal.h" 52#include "ypexclude.h" 53#endif 54#include "thread_private.h" 55 56#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 57 58struct pw_storage { 59 struct passwd pw; 60 uid_t uid; 61 char name[_PW_NAME_LEN + 1]; 62 char pwbuf[_PW_BUF_LEN]; 63}; 64 65_THREAD_PRIVATE_KEY(pw); 66 67static DB *_pw_db; /* password database */ 68 69/* mmap'd password storage */ 70static struct pw_storage *_pw_storage = MAP_FAILED; 71 72/* Following are used only by setpwent(), getpwent(), and endpwent() */ 73static int _pw_keynum; /* key counter */ 74static int _pw_stayopen; /* keep fd's open */ 75static int _pw_flags; /* password flags */ 76 77static int __hashpw(DBT *, char *buf, size_t buflen, struct passwd *, int *); 78static int __initdb(int); 79static struct passwd *_pwhashbyname(const char *name, char *buf, 80 size_t buflen, struct passwd *pw, int *); 81static struct passwd *_pwhashbyuid(uid_t uid, char *buf, 82 size_t buflen, struct passwd *pw, int *); 83 84#ifdef YP 85static char *__ypdomain; 86 87/* Following are used only by setpwent(), getpwent(), and endpwent() */ 88enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP }; 89static enum _ypmode __ypmode; 90static char *__ypcurrent; 91static int __ypcurrentlen; 92static int __yp_pw_flags; 93static int __getpwent_has_yppw = -1; 94static struct _ypexclude *__ypexhead; 95 96static int __has_yppw(void); 97static int __has_ypmaster(void); 98static int __ypparse(struct passwd *pw, char *s, int); 99 100#define LOOKUP_BYNAME 0 101#define LOOKUP_BYUID 1 102static struct passwd *__yppwlookup(int, char *, uid_t, struct passwd *, 103 char *, size_t, int *); 104 105/* macro for deciding which YP maps to use. */ 106#define PASSWD_BYNAME \ 107 (__has_ypmaster() ? "master.passwd.byname" : "passwd.byname") 108#define PASSWD_BYUID \ 109 (__has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid") 110 111static struct passwd *__ypproto; 112 113static void __ypproto_set(struct passwd *, struct pw_storage *, int, int *); 114 115static void 116__ypproto_set(struct passwd *pw, struct pw_storage *buf, int flags, 117 int *yp_pw_flagsp) 118{ 119 char *ptr = buf->pwbuf; 120 __ypproto = &buf->pw; 121 122 /* name */ 123 if (pw->pw_name && (pw->pw_name)[0]) { 124 bcopy(pw->pw_name, ptr, strlen(pw->pw_name) + 1); 125 __ypproto->pw_name = ptr; 126 ptr += (strlen(pw->pw_name) + 1); 127 } else 128 __ypproto->pw_name = NULL; 129 130 /* password */ 131 if (pw->pw_passwd && (pw->pw_passwd)[0]) { 132 bcopy(pw->pw_passwd, ptr, strlen(pw->pw_passwd) + 1); 133 __ypproto->pw_passwd = ptr; 134 ptr += (strlen(pw->pw_passwd) + 1); 135 } else 136 __ypproto->pw_passwd = NULL; 137 138 /* uid */ 139 __ypproto->pw_uid = pw->pw_uid; 140 141 /* gid */ 142 __ypproto->pw_gid = pw->pw_gid; 143 144 /* change (ignored anyway) */ 145 __ypproto->pw_change = pw->pw_change; 146 147 /* class (ignored anyway) */ 148 __ypproto->pw_class = ""; 149 150 /* gecos */ 151 if (pw->pw_gecos && (pw->pw_gecos)[0]) { 152 bcopy(pw->pw_gecos, ptr, strlen(pw->pw_gecos) + 1); 153 __ypproto->pw_gecos = ptr; 154 ptr += (strlen(pw->pw_gecos) + 1); 155 } else 156 __ypproto->pw_gecos = NULL; 157 158 /* dir */ 159 if (pw->pw_dir && (pw->pw_dir)[0]) { 160 bcopy(pw->pw_dir, ptr, strlen(pw->pw_dir) + 1); 161 __ypproto->pw_dir = ptr; 162 ptr += (strlen(pw->pw_dir) + 1); 163 } else 164 __ypproto->pw_dir = NULL; 165 166 /* shell */ 167 if (pw->pw_shell && (pw->pw_shell)[0]) { 168 bcopy(pw->pw_shell, ptr, strlen(pw->pw_shell) + 1); 169 __ypproto->pw_shell = ptr; 170 ptr += (strlen(pw->pw_shell) + 1); 171 } else 172 __ypproto->pw_shell = NULL; 173 174 /* expire (ignored anyway) */ 175 __ypproto->pw_expire = pw->pw_expire; 176 177 /* flags */ 178 *yp_pw_flagsp = flags; 179} 180 181static int 182__ypparse(struct passwd *pw, char *s, int yp_pw_flags) 183{ 184 char *bp, *cp, *endp; 185 u_long ul; 186 int count = 0; 187 188 /* count the colons. */ 189 bp = s; 190 while (*bp != '\0') { 191 if (*bp++ == ':') 192 count++; 193 } 194 195 /* since this is currently using strsep(), parse it first */ 196 bp = s; 197 pw->pw_name = strsep(&bp, ":\n"); 198 pw->pw_passwd = strsep(&bp, ":\n"); 199 if (!(cp = strsep(&bp, ":\n"))) 200 return (1); 201 ul = strtoul(cp, &endp, 10); 202 if (endp == cp || *endp != '\0' || ul >= UID_MAX) 203 return (1); 204 pw->pw_uid = (uid_t)ul; 205 if (!(cp = strsep(&bp, ":\n"))) 206 return (1); 207 ul = strtoul(cp, &endp, 10); 208 if (endp == cp || *endp != '\0' || ul >= GID_MAX) 209 return (1); 210 pw->pw_gid = (gid_t)ul; 211 if (count == 9) { 212 long l; 213 214 /* If the ypserv gave us all the fields, use them. */ 215 pw->pw_class = strsep(&bp, ":\n"); 216 if (!(cp = strsep(&bp, ":\n"))) 217 return (1); 218 l = strtol(cp, &endp, 10); 219 if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN) 220 return (1); 221 pw->pw_change = (time_t)l; 222 if (!(cp = strsep(&bp, ":\n"))) 223 return (1); 224 l = strtol(cp, &endp, 10); 225 if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN) 226 return (1); 227 pw->pw_expire = (time_t)l; 228 } else { 229 /* ..else it is a normal ypserv. */ 230 pw->pw_class = ""; 231 pw->pw_change = 0; 232 pw->pw_expire = 0; 233 } 234 pw->pw_gecos = strsep(&bp, ":\n"); 235 pw->pw_dir = strsep(&bp, ":\n"); 236 pw->pw_shell = strsep(&bp, ":\n"); 237 238 /* now let the prototype override, if set. */ 239 if (__ypproto) { 240 if (!(yp_pw_flags & _PASSWORD_NOUID)) 241 pw->pw_uid = __ypproto->pw_uid; 242 if (!(yp_pw_flags & _PASSWORD_NOGID)) 243 pw->pw_gid = __ypproto->pw_gid; 244 if (__ypproto->pw_gecos) 245 pw->pw_gecos = __ypproto->pw_gecos; 246 if (__ypproto->pw_dir) 247 pw->pw_dir = __ypproto->pw_dir; 248 if (__ypproto->pw_shell) 249 pw->pw_shell = __ypproto->pw_shell; 250 } 251 return (0); 252} 253#endif 254 255static struct passwd * 256__get_pw_buf(char **bufp, size_t *buflenp, uid_t uid, const char *name) 257{ 258 bool remap = true; 259 260 /* Unmap the old buffer unless we are looking up the same uid/name */ 261 if (_pw_storage != MAP_FAILED) { 262 if (name != NULL) { 263 if (strcmp(_pw_storage->name, name) == 0) { 264#ifdef PWDEBUG 265 struct syslog_data sdata = SYSLOG_DATA_INIT; 266 syslog_r(LOG_CRIT | LOG_CONS, &sdata, 267 "repeated passwd lookup of user \"%s\"", 268 name); 269#endif 270 remap = false; 271 } 272 } else if (uid != (uid_t)-1) { 273 if (_pw_storage->uid == uid) { 274#ifdef PWDEBUG 275 struct syslog_data sdata = SYSLOG_DATA_INIT; 276 syslog_r(LOG_CRIT | LOG_CONS, &sdata, 277 "repeated passwd lookup of uid %u", 278 uid); 279#endif 280 remap = false; 281 } 282 } 283 if (remap) 284 munmap(_pw_storage, sizeof(*_pw_storage)); 285 } 286 287 if (remap) { 288 _pw_storage = mmap(NULL, sizeof(*_pw_storage), 289 PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); 290 if (_pw_storage == MAP_FAILED) 291 return NULL; 292 if (name != NULL) 293 strlcpy(_pw_storage->name, name, sizeof(_pw_storage->name)); 294 _pw_storage->uid = uid; 295 } 296 297 *bufp = _pw_storage->pwbuf; 298 *buflenp = sizeof(_pw_storage->pwbuf); 299 return &_pw_storage->pw; 300} 301 302struct passwd * 303getpwent(void) 304{ 305#ifdef YP 306 static char *name = NULL; 307 char *map; 308#endif 309 char bf[1 + sizeof(_pw_keynum)]; 310 struct passwd *pw, *ret = NULL; 311 char *pwbuf; 312 size_t buflen; 313 DBT key; 314 315 _THREAD_PRIVATE_MUTEX_LOCK(pw); 316 if (!_pw_db && !__initdb(0)) 317 goto done; 318 319 /* Allocate space for struct and strings, unmapping the old. */ 320 if ((pw = __get_pw_buf(&pwbuf, &buflen, -1, NULL)) == NULL) 321 goto done; 322 323#ifdef YP 324 map = PASSWD_BYNAME; 325 326 if (__getpwent_has_yppw == -1) 327 __getpwent_has_yppw = __has_yppw(); 328 329again: 330 if (__getpwent_has_yppw && (__ypmode != YPMODE_NONE)) { 331 const char *user, *host, *dom; 332 int keylen, datalen, r, s; 333 char *key, *data = NULL; 334 335 if (!__ypdomain) 336 yp_get_default_domain(&__ypdomain); 337 switch (__ypmode) { 338 case YPMODE_FULL: 339 if (__ypcurrent) { 340 r = yp_next(__ypdomain, map, 341 __ypcurrent, __ypcurrentlen, 342 &key, &keylen, &data, &datalen); 343 free(__ypcurrent); 344 __ypcurrent = NULL; 345 if (r != 0) { 346 __ypmode = YPMODE_NONE; 347 free(data); 348 goto again; 349 } 350 __ypcurrent = key; 351 __ypcurrentlen = keylen; 352 } else { 353 r = yp_first(__ypdomain, map, 354 &__ypcurrent, &__ypcurrentlen, 355 &data, &datalen); 356 if (r != 0 || 357 __ypcurrentlen > buflen) { 358 __ypmode = YPMODE_NONE; 359 free(data); 360 goto again; 361 } 362 } 363 bcopy(data, pwbuf, datalen); 364 free(data); 365 break; 366 case YPMODE_NETGRP: 367 s = getnetgrent(&host, &user, &dom); 368 if (s == 0) { /* end of group */ 369 endnetgrent(); 370 __ypmode = YPMODE_NONE; 371 goto again; 372 } 373 if (user && *user) { 374 r = yp_match(__ypdomain, map, 375 user, strlen(user), &data, &datalen); 376 } else 377 goto again; 378 if (r != 0 || 379 __ypcurrentlen > buflen) { 380 /* 381 * if the netgroup is invalid, keep looking 382 * as there may be valid users later on. 383 */ 384 free(data); 385 goto again; 386 } 387 bcopy(data, pwbuf, datalen); 388 free(data); 389 break; 390 case YPMODE_USER: 391 if (name) { 392 r = yp_match(__ypdomain, map, 393 name, strlen(name), &data, &datalen); 394 __ypmode = YPMODE_NONE; 395 free(name); 396 name = NULL; 397 if (r != 0 || 398 __ypcurrentlen > buflen) { 399 free(data); 400 goto again; 401 } 402 bcopy(data, pwbuf, datalen); 403 free(data); 404 } else { /* XXX */ 405 __ypmode = YPMODE_NONE; 406 goto again; 407 } 408 break; 409 case YPMODE_NONE: 410 /* NOTREACHED */ 411 break; 412 } 413 414 pwbuf[datalen] = '\0'; 415 if (__ypparse(pw, pwbuf, __yp_pw_flags)) 416 goto again; 417 ret = pw; 418 goto done; 419 } 420#endif 421 422 ++_pw_keynum; 423 bf[0] = _PW_KEYBYNUM; 424 bcopy((char *)&_pw_keynum, &bf[1], sizeof(_pw_keynum)); 425 key.data = (u_char *)bf; 426 key.size = 1 + sizeof(_pw_keynum); 427 if (__hashpw(&key, pwbuf, buflen, pw, &_pw_flags)) { 428#ifdef YP 429 static struct pw_storage __yppbuf; 430 const char *user, *host, *dom; 431 432 /* if we don't have YP at all, don't bother. */ 433 if (__getpwent_has_yppw) { 434 if (pw->pw_name[0] == '+') { 435 /* set the mode */ 436 switch (pw->pw_name[1]) { 437 case '\0': 438 __ypmode = YPMODE_FULL; 439 break; 440 case '@': 441 __ypmode = YPMODE_NETGRP; 442 setnetgrent(pw->pw_name + 2); 443 break; 444 default: 445 __ypmode = YPMODE_USER; 446 name = strdup(pw->pw_name + 1); 447 break; 448 } 449 450 __ypproto_set(pw, &__yppbuf, _pw_flags, 451 &__yp_pw_flags); 452 goto again; 453 } else if (pw->pw_name[0] == '-') { 454 /* an attempted exclusion */ 455 switch (pw->pw_name[1]) { 456 case '\0': 457 break; 458 case '@': 459 setnetgrent(pw->pw_name + 2); 460 while (getnetgrent(&host, &user, &dom)) { 461 if (user && *user) 462 __ypexclude_add(&__ypexhead, 463 user); 464 } 465 endnetgrent(); 466 break; 467 default: 468 __ypexclude_add(&__ypexhead, 469 pw->pw_name + 1); 470 break; 471 } 472 goto again; 473 } 474 } 475#endif 476 ret = pw; 477 goto done; 478 } 479 480done: 481 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 482 return (ret); 483} 484 485#ifdef YP 486/* 487 * See if the YP token is in the database. Only works if pwd_mkdb knows 488 * about the token. 489 */ 490static int 491__has_yppw(void) 492{ 493 DBT key, data, pkey, pdata; 494 char bf[2]; 495 496 key.data = (u_char *)_PW_YPTOKEN; 497 key.size = strlen(_PW_YPTOKEN); 498 499 /* Pre-token database support. */ 500 bf[0] = _PW_KEYBYNAME; 501 bf[1] = '+'; 502 pkey.data = (u_char *)bf; 503 pkey.size = sizeof(bf); 504 505 if ((_pw_db->get)(_pw_db, &key, &data, 0) && 506 (_pw_db->get)(_pw_db, &pkey, &pdata, 0)) 507 return (0); /* No YP. */ 508 return (1); 509} 510 511/* 512 * See if there's a master.passwd map. 513 */ 514static int 515__has_ypmaster(void) 516{ 517 int keylen, resultlen; 518 char *key, *result; 519 static int checked = -1; 520 static uid_t saved_uid, saved_euid; 521 uid_t uid = getuid(), euid = geteuid(); 522 523 /* 524 * Do not recheck IFF the saved UID and the saved 525 * EUID are the same. In all other cases, recheck. 526 */ 527 if (checked != -1 && saved_uid == uid && saved_euid == euid) 528 return (checked); 529 530 if (euid != 0) { 531 saved_uid = uid; 532 saved_euid = euid; 533 checked = 0; 534 return (checked); 535 } 536 537 if (!__ypdomain) 538 yp_get_default_domain(&__ypdomain); 539 540 if (yp_first(__ypdomain, "master.passwd.byname", 541 &key, &keylen, &result, &resultlen)) { 542 saved_uid = uid; 543 saved_euid = euid; 544 checked = 0; 545 return (checked); 546 } 547 free(result); 548 free(key); 549 550 saved_uid = uid; 551 saved_euid = euid; 552 checked = 1; 553 return (checked); 554} 555 556static struct passwd * 557__yppwlookup(int lookup, char *name, uid_t uid, struct passwd *pw, 558 char *buf, size_t buflen, int *flagsp) 559{ 560 char bf[1 + _PW_NAME_LEN], *ypcurrent = NULL, *map = NULL; 561 int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum; 562 static struct pw_storage __yppbuf; 563 struct _ypexclude *ypexhead = NULL; 564 const char *host, *user, *dom; 565 DBT key; 566 567 for (pw_keynum = 1; pw_keynum; pw_keynum++) { 568 bf[0] = _PW_KEYBYNUM; 569 bcopy((char *)&pw_keynum, &bf[1], sizeof(pw_keynum)); 570 key.data = (u_char *)bf; 571 key.size = 1 + sizeof(pw_keynum); 572 if (__hashpw(&key, buf, buflen, pw, flagsp) == 0) 573 break; 574 switch (pw->pw_name[0]) { 575 case '+': 576 if (!__ypdomain) 577 yp_get_default_domain(&__ypdomain); 578 __ypproto_set(pw, &__yppbuf, *flagsp, &yp_pw_flags); 579 if (!map) { 580 if (lookup == LOOKUP_BYNAME) { 581 if ((name = strdup(name)) == NULL) { 582 pw = NULL; 583 goto done; 584 } 585 map = PASSWD_BYNAME; 586 } else { 587 if (asprintf(&name, "%u", uid) == -1) { 588 pw = NULL; 589 goto done; 590 } 591 map = PASSWD_BYUID; 592 } 593 } 594 595 switch (pw->pw_name[1]) { 596 case '\0': 597 free(ypcurrent); 598 ypcurrent = NULL; 599 r = yp_match(__ypdomain, map, 600 name, strlen(name), 601 &ypcurrent, &ypcurrentlen); 602 if (r != 0 || ypcurrentlen > buflen) { 603 free(ypcurrent); 604 ypcurrent = NULL; 605 continue; 606 } 607 break; 608 case '@': 609pwnam_netgrp: 610 free(ypcurrent); 611 ypcurrent = NULL; 612 if (s == -1) /* first time */ 613 setnetgrent(pw->pw_name + 2); 614 s = getnetgrent(&host, &user, &dom); 615 if (s == 0) { /* end of group */ 616 endnetgrent(); 617 s = -1; 618 continue; 619 } else { 620 if (user && *user) { 621 r = yp_match(__ypdomain, map, 622 user, strlen(user), 623 &ypcurrent, &ypcurrentlen); 624 } else 625 goto pwnam_netgrp; 626 if (r != 0 || ypcurrentlen > buflen) { 627 free(ypcurrent); 628 ypcurrent = NULL; 629 /* 630 * just because this 631 * user is bad, doesn't 632 * mean they all are. 633 */ 634 goto pwnam_netgrp; 635 } 636 } 637 break; 638 default: 639 free(ypcurrent); 640 ypcurrent = NULL; 641 user = pw->pw_name + 1; 642 r = yp_match(__ypdomain, map, 643 user, strlen(user), 644 &ypcurrent, &ypcurrentlen); 645 if (r != 0 || ypcurrentlen > buflen) { 646 free(ypcurrent); 647 ypcurrent = NULL; 648 continue; 649 } 650 break; 651 } 652 bcopy(ypcurrent, buf, ypcurrentlen); 653 buf[ypcurrentlen] = '\0'; 654 if (__ypparse(pw, buf, yp_pw_flags) || 655 __ypexclude_is(&ypexhead, pw->pw_name)) { 656 if (s == 1) /* inside netgrp */ 657 goto pwnam_netgrp; 658 continue; 659 } 660 break; 661 case '-': 662 /* attempted exclusion */ 663 switch (pw->pw_name[1]) { 664 case '\0': 665 break; 666 case '@': 667 setnetgrent(pw->pw_name + 2); 668 while (getnetgrent(&host, &user, &dom)) { 669 if (user && *user) 670 __ypexclude_add(&ypexhead, user); 671 } 672 endnetgrent(); 673 break; 674 default: 675 __ypexclude_add(&ypexhead, pw->pw_name + 1); 676 break; 677 } 678 break; 679 } 680 if ((lookup == LOOKUP_BYUID && pw->pw_uid == uid) || 681 (lookup == LOOKUP_BYNAME && strcmp(pw->pw_name, name) == 0)) 682 goto done; 683 if (s == 1) /* inside netgrp */ 684 goto pwnam_netgrp; 685 continue; 686 } 687 pw = NULL; 688done: 689 __ypexclude_free(&ypexhead); 690 __ypproto = NULL; 691 free(ypcurrent); 692 ypcurrent = NULL; 693 if (map) 694 free(name); 695 return (pw); 696} 697#endif /* YP */ 698 699static struct passwd * 700_pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw, 701 int *flagsp) 702{ 703 char bf[1 + _PW_NAME_LEN]; 704 size_t len; 705 DBT key; 706 int r; 707 708 len = strlen(name); 709 if (len > _PW_NAME_LEN) 710 return (NULL); 711 bf[0] = _PW_KEYBYNAME; 712 bcopy(name, &bf[1], MINIMUM(len, _PW_NAME_LEN)); 713 key.data = (u_char *)bf; 714 key.size = 1 + MINIMUM(len, _PW_NAME_LEN); 715 r = __hashpw(&key, buf, buflen, pw, flagsp); 716 if (r) 717 return (pw); 718 return (NULL); 719} 720 721static struct passwd * 722_pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw, 723 int *flagsp) 724{ 725 char bf[1 + sizeof(int)]; 726 DBT key; 727 int r; 728 729 bf[0] = _PW_KEYBYUID; 730 bcopy(&uid, &bf[1], sizeof(uid)); 731 key.data = (u_char *)bf; 732 key.size = 1 + sizeof(uid); 733 r = __hashpw(&key, buf, buflen, pw, flagsp); 734 if (r) 735 return (pw); 736 return (NULL); 737} 738 739static int 740getpwnam_internal(const char *name, struct passwd *pw, char *buf, size_t buflen, 741 struct passwd **pwretp, bool shadow, bool reentrant) 742{ 743 struct passwd *pwret = NULL; 744 int flags = 0, *flagsp = &flags; 745 int my_errno = 0; 746 int saved_errno, tmp_errno; 747 748 _THREAD_PRIVATE_MUTEX_LOCK(pw); 749 saved_errno = errno; 750 errno = 0; 751 if (!_pw_db && !__initdb(shadow)) 752 goto fail; 753 754 if (!reentrant) { 755 /* Allocate space for struct and strings, unmapping the old. */ 756 if ((pw = __get_pw_buf(&buf, &buflen, -1, name)) == NULL) 757 goto fail; 758 flagsp = &_pw_flags; 759 } 760 761#ifdef YP 762 if (__has_yppw()) 763 pwret = __yppwlookup(LOOKUP_BYNAME, (char *)name, 0, pw, 764 buf, buflen, flagsp); 765#endif /* YP */ 766 if (!pwret) 767 pwret = _pwhashbyname(name, buf, buflen, pw, flagsp); 768 769 if (!_pw_stayopen) { 770 tmp_errno = errno; 771 (void)(_pw_db->close)(_pw_db); 772 _pw_db = NULL; 773 errno = tmp_errno; 774 } 775fail: 776 if (pwretp) 777 *pwretp = pwret; 778 if (pwret == NULL) 779 my_errno = errno; 780 errno = saved_errno; 781 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 782 return (my_errno); 783} 784 785int 786getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen, 787 struct passwd **pwretp) 788{ 789 return getpwnam_internal(name, pw, buf, buflen, pwretp, false, true); 790} 791DEF_WEAK(getpwnam_r); 792 793struct passwd * 794getpwnam(const char *name) 795{ 796 struct passwd *pw = NULL; 797 int my_errno; 798 799 my_errno = getpwnam_internal(name, NULL, NULL, 0, &pw, false, false); 800 if (my_errno) { 801 pw = NULL; 802 errno = my_errno; 803 } 804 return (pw); 805} 806 807struct passwd * 808getpwnam_shadow(const char *name) 809{ 810 struct passwd *pw = NULL; 811 int my_errno; 812 813 my_errno = getpwnam_internal(name, NULL, NULL, 0, &pw, true, false); 814 if (my_errno) { 815 pw = NULL; 816 errno = my_errno; 817 } 818 return (pw); 819} 820DEF_WEAK(getpwnam_shadow); 821 822static int 823getpwuid_internal(uid_t uid, struct passwd *pw, char *buf, size_t buflen, 824 struct passwd **pwretp, bool shadow, bool reentrant) 825{ 826 struct passwd *pwret = NULL; 827 int flags = 0, *flagsp = &flags; 828 int my_errno = 0; 829 int saved_errno, tmp_errno; 830 831 _THREAD_PRIVATE_MUTEX_LOCK(pw); 832 saved_errno = errno; 833 errno = 0; 834 if (!_pw_db && !__initdb(shadow)) 835 goto fail; 836 837 if (!reentrant) { 838 /* Allocate space for struct and strings, unmapping the old. */ 839 if ((pw = __get_pw_buf(&buf, &buflen, uid, NULL)) == NULL) 840 goto fail; 841 flagsp = &_pw_flags; 842 } 843 844#ifdef YP 845 if (__has_yppw()) 846 pwret = __yppwlookup(LOOKUP_BYUID, NULL, uid, pw, 847 buf, buflen, flagsp); 848#endif /* YP */ 849 if (!pwret) 850 pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp); 851 852 if (!_pw_stayopen) { 853 tmp_errno = errno; 854 (void)(_pw_db->close)(_pw_db); 855 _pw_db = NULL; 856 errno = tmp_errno; 857 } 858fail: 859 if (pwretp) 860 *pwretp = pwret; 861 if (pwret == NULL) 862 my_errno = errno; 863 errno = saved_errno; 864 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 865 return (my_errno); 866} 867 868 869int 870getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen, 871 struct passwd **pwretp) 872{ 873 return getpwuid_internal(uid, pw, buf, buflen, pwretp, false, true); 874} 875DEF_WEAK(getpwuid_r); 876 877struct passwd * 878getpwuid(uid_t uid) 879{ 880 struct passwd *pw = NULL; 881 int my_errno; 882 883 my_errno = getpwuid_internal(uid, NULL, NULL, 0, &pw, false, false); 884 if (my_errno) { 885 pw = NULL; 886 errno = my_errno; 887 } 888 return (pw); 889} 890 891struct passwd * 892getpwuid_shadow(uid_t uid) 893{ 894 struct passwd *pw = NULL; 895 int my_errno; 896 897 my_errno = getpwuid_internal(uid, NULL, NULL, 0, &pw, true, false); 898 if (my_errno) { 899 pw = NULL; 900 errno = my_errno; 901 } 902 return (pw); 903} 904DEF_WEAK(getpwuid_shadow); 905 906int 907setpassent(int stayopen) 908{ 909 _THREAD_PRIVATE_MUTEX_LOCK(pw); 910 _pw_keynum = 0; 911 _pw_stayopen = stayopen; 912#ifdef YP 913 __ypmode = YPMODE_NONE; 914 free(__ypcurrent); 915 __ypcurrent = NULL; 916 __ypexclude_free(&__ypexhead); 917 __ypproto = NULL; 918#endif 919 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 920 return (1); 921} 922DEF_WEAK(setpassent); 923 924void 925setpwent(void) 926{ 927 (void) setpassent(0); 928} 929 930void 931endpwent(void) 932{ 933 int saved_errno; 934 935 _THREAD_PRIVATE_MUTEX_LOCK(pw); 936 saved_errno = errno; 937 _pw_keynum = 0; 938 if (_pw_db) { 939 (void)(_pw_db->close)(_pw_db); 940 _pw_db = NULL; 941 } 942#ifdef YP 943 __ypmode = YPMODE_NONE; 944 free(__ypcurrent); 945 __ypcurrent = NULL; 946 __ypexclude_free(&__ypexhead); 947 __ypproto = NULL; 948#endif 949 errno = saved_errno; 950 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 951} 952 953static int 954__initdb(int shadow) 955{ 956 static int warned; 957 int saved_errno = errno; 958 959#ifdef YP 960 __ypmode = YPMODE_NONE; 961 __getpwent_has_yppw = -1; 962#endif 963 if (shadow) { 964#ifdef FORCE_DBOPEN 965 _pw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL); 966#else 967 _pw_db = __hash_open(_PATH_SMP_DB, O_RDONLY, 0, NULL, 0); 968#endif 969 } 970 if (!_pw_db) { 971#ifdef FORCE_DBOPEN 972 _pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL); 973#else 974 _pw_db = __hash_open(_PATH_MP_DB, O_RDONLY, 0, NULL, 0); 975#endif 976 } 977 if (_pw_db) { 978 errno = saved_errno; 979 return (1); 980 } 981 if (!warned) { 982 saved_errno = errno; 983 errno = saved_errno; 984 warned = 1; 985 } 986 return (0); 987} 988 989static int 990__hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw, 991 int *flagsp) 992{ 993 char *p, *t; 994 DBT data; 995 996 if ((_pw_db->get)(_pw_db, key, &data, 0)) 997 return (0); 998 p = (char *)data.data; 999 if (data.size > buflen) { 1000 errno = ERANGE; 1001 return (0); 1002 } 1003 1004 t = buf; 1005#define EXPAND(e) e = t; while ((*t++ = *p++)); 1006 EXPAND(pw->pw_name); 1007 EXPAND(pw->pw_passwd); 1008 bcopy(p, (char *)&pw->pw_uid, sizeof(int)); 1009 p += sizeof(int); 1010 bcopy(p, (char *)&pw->pw_gid, sizeof(int)); 1011 p += sizeof(int); 1012 bcopy(p, (char *)&pw->pw_change, sizeof(time_t)); 1013 p += sizeof(time_t); 1014 EXPAND(pw->pw_class); 1015 EXPAND(pw->pw_gecos); 1016 EXPAND(pw->pw_dir); 1017 EXPAND(pw->pw_shell); 1018 bcopy(p, (char *)&pw->pw_expire, sizeof(time_t)); 1019 p += sizeof(time_t); 1020 1021 /* See if there's any data left. If so, read in flags. */ 1022 if (data.size > (p - (char *)data.data)) { 1023 bcopy(p, (char *)flagsp, sizeof(int)); 1024 p += sizeof(int); 1025 } else 1026 *flagsp = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */ 1027 return (1); 1028} 1029