1 /* $OpenBSD: getpwent.c,v 1.66 2022/08/02 17:00:15 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 58 struct 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 67 static DB *_pw_db; /* password database */ 68 69 /* mmap'd password storage */ 70 static struct pw_storage *_pw_storage = MAP_FAILED; 71 72 /* Following are used only by setpwent(), getpwent(), and endpwent() */ 73 static int _pw_keynum; /* key counter */ 74 static int _pw_stayopen; /* keep fd's open */ 75 static int _pw_flags; /* password flags */ 76 77 static int __hashpw(DBT *, char *buf, size_t buflen, struct passwd *, int *); 78 static int __initdb(int); 79 static struct passwd *_pwhashbyname(const char *name, char *buf, 80 size_t buflen, struct passwd *pw, int *); 81 static struct passwd *_pwhashbyuid(uid_t uid, char *buf, 82 size_t buflen, struct passwd *pw, int *); 83 84 #ifdef YP 85 static char *__ypdomain; 86 87 /* Following are used only by setpwent(), getpwent(), and endpwent() */ 88 enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP }; 89 static enum _ypmode __ypmode; 90 static char *__ypcurrent; 91 static int __ypcurrentlen; 92 static int __yp_pw_flags; 93 static int __getpwent_has_yppw = -1; 94 static struct _ypexclude *__ypexhead; 95 96 static int __has_yppw(void); 97 static int __has_ypmaster(void); 98 static int __ypparse(struct passwd *pw, char *s, int); 99 100 #define LOOKUP_BYNAME 0 101 #define LOOKUP_BYUID 1 102 static 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 111 static struct passwd *__ypproto; 112 113 static void __ypproto_set(struct passwd *, struct pw_storage *, int, int *); 114 115 static 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 181 static 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 255 static 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 302 struct passwd * 303 getpwent(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 329 again: 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 480 done: 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 */ 490 static 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 */ 514 static 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 556 static 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 '@': 609 pwnam_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; 688 done: 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 699 static 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 721 static 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 739 static int 740 getpwnam_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 } 775 fail: 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 785 int 786 getpwnam_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 } 791 DEF_WEAK(getpwnam_r); 792 793 struct passwd * 794 getpwnam(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 807 struct passwd * 808 getpwnam_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 } 820 DEF_WEAK(getpwnam_shadow); 821 822 static int 823 getpwuid_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 } 858 fail: 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 869 int 870 getpwuid_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 } 875 DEF_WEAK(getpwuid_r); 876 877 struct passwd * 878 getpwuid(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 891 struct passwd * 892 getpwuid_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 } 904 DEF_WEAK(getpwuid_shadow); 905 906 int 907 setpassent(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 } 922 DEF_WEAK(setpassent); 923 924 void 925 setpwent(void) 926 { 927 (void) setpassent(0); 928 } 929 930 void 931 endpwent(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 953 static 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 _pw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL); 965 if (!_pw_db) 966 _pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL); 967 if (_pw_db) { 968 errno = saved_errno; 969 return (1); 970 } 971 if (!warned) { 972 saved_errno = errno; 973 errno = saved_errno; 974 warned = 1; 975 } 976 return (0); 977 } 978 979 static int 980 __hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw, 981 int *flagsp) 982 { 983 char *p, *t; 984 DBT data; 985 986 if ((_pw_db->get)(_pw_db, key, &data, 0)) 987 return (0); 988 p = (char *)data.data; 989 if (data.size > buflen) { 990 errno = ERANGE; 991 return (0); 992 } 993 994 t = buf; 995 #define EXPAND(e) e = t; while ((*t++ = *p++)); 996 EXPAND(pw->pw_name); 997 EXPAND(pw->pw_passwd); 998 bcopy(p, (char *)&pw->pw_uid, sizeof(int)); 999 p += sizeof(int); 1000 bcopy(p, (char *)&pw->pw_gid, sizeof(int)); 1001 p += sizeof(int); 1002 bcopy(p, (char *)&pw->pw_change, sizeof(time_t)); 1003 p += sizeof(time_t); 1004 EXPAND(pw->pw_class); 1005 EXPAND(pw->pw_gecos); 1006 EXPAND(pw->pw_dir); 1007 EXPAND(pw->pw_shell); 1008 bcopy(p, (char *)&pw->pw_expire, sizeof(time_t)); 1009 p += sizeof(time_t); 1010 1011 /* See if there's any data left. If so, read in flags. */ 1012 if (data.size > (p - (char *)data.data)) { 1013 bcopy(p, (char *)flagsp, sizeof(int)); 1014 p += sizeof(int); 1015 } else 1016 *flagsp = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */ 1017 return (1); 1018 } 1019