1 /* $OpenBSD: getpwent.c,v 1.64 2021/12/07 18:13:45 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 if (_yp_check(&__ypdomain) == 0) { 337 __ypmode = YPMODE_NONE; 338 goto again; 339 } 340 } 341 switch (__ypmode) { 342 case YPMODE_FULL: 343 if (__ypcurrent) { 344 r = yp_next(__ypdomain, map, 345 __ypcurrent, __ypcurrentlen, 346 &key, &keylen, &data, &datalen); 347 free(__ypcurrent); 348 __ypcurrent = NULL; 349 if (r != 0) { 350 __ypmode = YPMODE_NONE; 351 free(data); 352 goto again; 353 } 354 __ypcurrent = key; 355 __ypcurrentlen = keylen; 356 } else { 357 r = yp_first(__ypdomain, map, 358 &__ypcurrent, &__ypcurrentlen, 359 &data, &datalen); 360 if (r != 0 || 361 __ypcurrentlen > buflen) { 362 __ypmode = YPMODE_NONE; 363 free(data); 364 goto again; 365 } 366 } 367 bcopy(data, pwbuf, datalen); 368 free(data); 369 break; 370 case YPMODE_NETGRP: 371 s = getnetgrent(&host, &user, &dom); 372 if (s == 0) { /* end of group */ 373 endnetgrent(); 374 __ypmode = YPMODE_NONE; 375 goto again; 376 } 377 if (user && *user) { 378 r = yp_match(__ypdomain, map, 379 user, strlen(user), &data, &datalen); 380 } else 381 goto again; 382 if (r != 0 || 383 __ypcurrentlen > buflen) { 384 /* 385 * if the netgroup is invalid, keep looking 386 * as there may be valid users later on. 387 */ 388 free(data); 389 goto again; 390 } 391 bcopy(data, pwbuf, datalen); 392 free(data); 393 break; 394 case YPMODE_USER: 395 if (name) { 396 r = yp_match(__ypdomain, map, 397 name, strlen(name), &data, &datalen); 398 __ypmode = YPMODE_NONE; 399 free(name); 400 name = NULL; 401 if (r != 0 || 402 __ypcurrentlen > buflen) { 403 free(data); 404 goto again; 405 } 406 bcopy(data, pwbuf, datalen); 407 free(data); 408 } else { /* XXX */ 409 __ypmode = YPMODE_NONE; 410 goto again; 411 } 412 break; 413 case YPMODE_NONE: 414 /* NOTREACHED */ 415 break; 416 } 417 418 pwbuf[datalen] = '\0'; 419 if (__ypparse(pw, pwbuf, __yp_pw_flags)) 420 goto again; 421 ret = pw; 422 goto done; 423 } 424 #endif 425 426 ++_pw_keynum; 427 bf[0] = _PW_KEYBYNUM; 428 bcopy((char *)&_pw_keynum, &bf[1], sizeof(_pw_keynum)); 429 key.data = (u_char *)bf; 430 key.size = 1 + sizeof(_pw_keynum); 431 if (__hashpw(&key, pwbuf, buflen, pw, &_pw_flags)) { 432 #ifdef YP 433 static struct pw_storage __yppbuf; 434 const char *user, *host, *dom; 435 436 /* if we don't have YP at all, don't bother. */ 437 if (__getpwent_has_yppw) { 438 if (pw->pw_name[0] == '+') { 439 /* set the mode */ 440 switch (pw->pw_name[1]) { 441 case '\0': 442 __ypmode = YPMODE_FULL; 443 break; 444 case '@': 445 __ypmode = YPMODE_NETGRP; 446 setnetgrent(pw->pw_name + 2); 447 break; 448 default: 449 __ypmode = YPMODE_USER; 450 name = strdup(pw->pw_name + 1); 451 break; 452 } 453 454 __ypproto_set(pw, &__yppbuf, _pw_flags, 455 &__yp_pw_flags); 456 goto again; 457 } else if (pw->pw_name[0] == '-') { 458 /* an attempted exclusion */ 459 switch (pw->pw_name[1]) { 460 case '\0': 461 break; 462 case '@': 463 setnetgrent(pw->pw_name + 2); 464 while (getnetgrent(&host, &user, &dom)) { 465 if (user && *user) 466 __ypexclude_add(&__ypexhead, 467 user); 468 } 469 endnetgrent(); 470 break; 471 default: 472 __ypexclude_add(&__ypexhead, 473 pw->pw_name + 1); 474 break; 475 } 476 goto again; 477 } 478 } 479 #endif 480 ret = pw; 481 goto done; 482 } 483 484 done: 485 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 486 return (ret); 487 } 488 489 #ifdef YP 490 /* 491 * See if the YP token is in the database. Only works if pwd_mkdb knows 492 * about the token. 493 */ 494 static int 495 __has_yppw(void) 496 { 497 DBT key, data, pkey, pdata; 498 char bf[2]; 499 500 key.data = (u_char *)_PW_YPTOKEN; 501 key.size = strlen(_PW_YPTOKEN); 502 503 /* Pre-token database support. */ 504 bf[0] = _PW_KEYBYNAME; 505 bf[1] = '+'; 506 pkey.data = (u_char *)bf; 507 pkey.size = sizeof(bf); 508 509 if ((_pw_db->get)(_pw_db, &key, &data, 0) && 510 (_pw_db->get)(_pw_db, &pkey, &pdata, 0)) 511 return (0); /* No YP. */ 512 return (1); 513 } 514 515 /* 516 * See if there's a master.passwd map. 517 */ 518 static int 519 __has_ypmaster(void) 520 { 521 int keylen, resultlen; 522 char *key, *result; 523 static int checked = -1; 524 static uid_t saved_uid, saved_euid; 525 uid_t uid = getuid(), euid = geteuid(); 526 527 /* 528 * Do not recheck IFF the saved UID and the saved 529 * EUID are the same. In all other cases, recheck. 530 */ 531 if (checked != -1 && saved_uid == uid && saved_euid == euid) 532 return (checked); 533 534 if (euid != 0) { 535 saved_uid = uid; 536 saved_euid = euid; 537 checked = 0; 538 return (checked); 539 } 540 541 if (!__ypdomain) { 542 if (_yp_check(&__ypdomain) == 0) { 543 saved_uid = uid; 544 saved_euid = euid; 545 checked = 0; 546 return (checked); /* No domain. */ 547 } 548 } 549 550 if (yp_first(__ypdomain, "master.passwd.byname", 551 &key, &keylen, &result, &resultlen)) { 552 saved_uid = uid; 553 saved_euid = euid; 554 checked = 0; 555 return (checked); 556 } 557 free(result); 558 free(key); 559 560 saved_uid = uid; 561 saved_euid = euid; 562 checked = 1; 563 return (checked); 564 } 565 566 static struct passwd * 567 __yppwlookup(int lookup, char *name, uid_t uid, struct passwd *pw, 568 char *buf, size_t buflen, int *flagsp) 569 { 570 char bf[1 + _PW_NAME_LEN], *ypcurrent = NULL, *map = NULL; 571 int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum; 572 static struct pw_storage __yppbuf; 573 struct _ypexclude *ypexhead = NULL; 574 const char *host, *user, *dom; 575 DBT key; 576 577 for (pw_keynum = 1; pw_keynum; pw_keynum++) { 578 bf[0] = _PW_KEYBYNUM; 579 bcopy((char *)&pw_keynum, &bf[1], sizeof(pw_keynum)); 580 key.data = (u_char *)bf; 581 key.size = 1 + sizeof(pw_keynum); 582 if (__hashpw(&key, buf, buflen, pw, flagsp) == 0) 583 break; 584 switch (pw->pw_name[0]) { 585 case '+': 586 if (!__ypdomain) { 587 if (_yp_check(&__ypdomain) == 0) 588 continue; 589 } 590 __ypproto_set(pw, &__yppbuf, *flagsp, &yp_pw_flags); 591 if (!map) { 592 if (lookup == LOOKUP_BYNAME) { 593 if ((name = strdup(name)) == NULL) { 594 pw = NULL; 595 goto done; 596 } 597 map = PASSWD_BYNAME; 598 } else { 599 if (asprintf(&name, "%u", uid) == -1) { 600 pw = NULL; 601 goto done; 602 } 603 map = PASSWD_BYUID; 604 } 605 } 606 607 switch (pw->pw_name[1]) { 608 case '\0': 609 free(ypcurrent); 610 ypcurrent = NULL; 611 r = yp_match(__ypdomain, map, 612 name, strlen(name), 613 &ypcurrent, &ypcurrentlen); 614 if (r != 0 || ypcurrentlen > buflen) { 615 free(ypcurrent); 616 ypcurrent = NULL; 617 continue; 618 } 619 break; 620 case '@': 621 pwnam_netgrp: 622 free(ypcurrent); 623 ypcurrent = NULL; 624 if (s == -1) /* first time */ 625 setnetgrent(pw->pw_name + 2); 626 s = getnetgrent(&host, &user, &dom); 627 if (s == 0) { /* end of group */ 628 endnetgrent(); 629 s = -1; 630 continue; 631 } else { 632 if (user && *user) { 633 r = yp_match(__ypdomain, map, 634 user, strlen(user), 635 &ypcurrent, &ypcurrentlen); 636 } else 637 goto pwnam_netgrp; 638 if (r != 0 || ypcurrentlen > buflen) { 639 free(ypcurrent); 640 ypcurrent = NULL; 641 /* 642 * just because this 643 * user is bad, doesn't 644 * mean they all are. 645 */ 646 goto pwnam_netgrp; 647 } 648 } 649 break; 650 default: 651 free(ypcurrent); 652 ypcurrent = NULL; 653 user = pw->pw_name + 1; 654 r = yp_match(__ypdomain, map, 655 user, strlen(user), 656 &ypcurrent, &ypcurrentlen); 657 if (r != 0 || ypcurrentlen > buflen) { 658 free(ypcurrent); 659 ypcurrent = NULL; 660 continue; 661 } 662 break; 663 } 664 bcopy(ypcurrent, buf, ypcurrentlen); 665 buf[ypcurrentlen] = '\0'; 666 if (__ypparse(pw, buf, yp_pw_flags) || 667 __ypexclude_is(&ypexhead, pw->pw_name)) { 668 if (s == 1) /* inside netgrp */ 669 goto pwnam_netgrp; 670 continue; 671 } 672 break; 673 case '-': 674 /* attempted exclusion */ 675 switch (pw->pw_name[1]) { 676 case '\0': 677 break; 678 case '@': 679 setnetgrent(pw->pw_name + 2); 680 while (getnetgrent(&host, &user, &dom)) { 681 if (user && *user) 682 __ypexclude_add(&ypexhead, user); 683 } 684 endnetgrent(); 685 break; 686 default: 687 __ypexclude_add(&ypexhead, pw->pw_name + 1); 688 break; 689 } 690 break; 691 } 692 if ((lookup == LOOKUP_BYUID && pw->pw_uid == uid) || 693 (lookup == LOOKUP_BYNAME && strcmp(pw->pw_name, name) == 0)) 694 goto done; 695 if (s == 1) /* inside netgrp */ 696 goto pwnam_netgrp; 697 continue; 698 } 699 pw = NULL; 700 done: 701 __ypexclude_free(&ypexhead); 702 __ypproto = NULL; 703 free(ypcurrent); 704 ypcurrent = NULL; 705 if (map) 706 free(name); 707 return (pw); 708 } 709 #endif /* YP */ 710 711 static struct passwd * 712 _pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw, 713 int *flagsp) 714 { 715 char bf[1 + _PW_NAME_LEN]; 716 size_t len; 717 DBT key; 718 int r; 719 720 len = strlen(name); 721 if (len > _PW_NAME_LEN) 722 return (NULL); 723 bf[0] = _PW_KEYBYNAME; 724 bcopy(name, &bf[1], MINIMUM(len, _PW_NAME_LEN)); 725 key.data = (u_char *)bf; 726 key.size = 1 + MINIMUM(len, _PW_NAME_LEN); 727 r = __hashpw(&key, buf, buflen, pw, flagsp); 728 if (r) 729 return (pw); 730 return (NULL); 731 } 732 733 static struct passwd * 734 _pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw, 735 int *flagsp) 736 { 737 char bf[1 + sizeof(int)]; 738 DBT key; 739 int r; 740 741 bf[0] = _PW_KEYBYUID; 742 bcopy(&uid, &bf[1], sizeof(uid)); 743 key.data = (u_char *)bf; 744 key.size = 1 + sizeof(uid); 745 r = __hashpw(&key, buf, buflen, pw, flagsp); 746 if (r) 747 return (pw); 748 return (NULL); 749 } 750 751 static int 752 getpwnam_internal(const char *name, struct passwd *pw, char *buf, size_t buflen, 753 struct passwd **pwretp, bool shadow, bool reentrant) 754 { 755 struct passwd *pwret = NULL; 756 int flags = 0, *flagsp = &flags; 757 int my_errno = 0; 758 int saved_errno, tmp_errno; 759 760 _THREAD_PRIVATE_MUTEX_LOCK(pw); 761 saved_errno = errno; 762 errno = 0; 763 if (!_pw_db && !__initdb(shadow)) 764 goto fail; 765 766 if (!reentrant) { 767 /* Allocate space for struct and strings, unmapping the old. */ 768 if ((pw = __get_pw_buf(&buf, &buflen, -1, name)) == NULL) 769 goto fail; 770 flagsp = &_pw_flags; 771 } 772 773 #ifdef YP 774 if (__has_yppw()) 775 pwret = __yppwlookup(LOOKUP_BYNAME, (char *)name, 0, pw, 776 buf, buflen, flagsp); 777 #endif /* YP */ 778 if (!pwret) 779 pwret = _pwhashbyname(name, buf, buflen, pw, flagsp); 780 781 if (!_pw_stayopen) { 782 tmp_errno = errno; 783 (void)(_pw_db->close)(_pw_db); 784 _pw_db = NULL; 785 errno = tmp_errno; 786 } 787 fail: 788 if (pwretp) 789 *pwretp = pwret; 790 if (pwret == NULL) 791 my_errno = errno; 792 errno = saved_errno; 793 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 794 return (my_errno); 795 } 796 797 int 798 getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen, 799 struct passwd **pwretp) 800 { 801 return getpwnam_internal(name, pw, buf, buflen, pwretp, false, true); 802 } 803 DEF_WEAK(getpwnam_r); 804 805 struct passwd * 806 getpwnam(const char *name) 807 { 808 struct passwd *pw = NULL; 809 int my_errno; 810 811 my_errno = getpwnam_internal(name, NULL, NULL, 0, &pw, false, false); 812 if (my_errno) { 813 pw = NULL; 814 errno = my_errno; 815 } 816 return (pw); 817 } 818 819 struct passwd * 820 getpwnam_shadow(const char *name) 821 { 822 struct passwd *pw = NULL; 823 int my_errno; 824 825 my_errno = getpwnam_internal(name, NULL, NULL, 0, &pw, true, false); 826 if (my_errno) { 827 pw = NULL; 828 errno = my_errno; 829 } 830 return (pw); 831 } 832 DEF_WEAK(getpwnam_shadow); 833 834 static int 835 getpwuid_internal(uid_t uid, struct passwd *pw, char *buf, size_t buflen, 836 struct passwd **pwretp, bool shadow, bool reentrant) 837 { 838 struct passwd *pwret = NULL; 839 int flags = 0, *flagsp = &flags; 840 int my_errno = 0; 841 int saved_errno, tmp_errno; 842 843 _THREAD_PRIVATE_MUTEX_LOCK(pw); 844 saved_errno = errno; 845 errno = 0; 846 if (!_pw_db && !__initdb(shadow)) 847 goto fail; 848 849 if (!reentrant) { 850 /* Allocate space for struct and strings, unmapping the old. */ 851 if ((pw = __get_pw_buf(&buf, &buflen, uid, NULL)) == NULL) 852 goto fail; 853 flagsp = &_pw_flags; 854 } 855 856 #ifdef YP 857 if (__has_yppw()) 858 pwret = __yppwlookup(LOOKUP_BYUID, NULL, uid, pw, 859 buf, buflen, flagsp); 860 #endif /* YP */ 861 if (!pwret) 862 pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp); 863 864 if (!_pw_stayopen) { 865 tmp_errno = errno; 866 (void)(_pw_db->close)(_pw_db); 867 _pw_db = NULL; 868 errno = tmp_errno; 869 } 870 fail: 871 if (pwretp) 872 *pwretp = pwret; 873 if (pwret == NULL) 874 my_errno = errno; 875 errno = saved_errno; 876 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 877 return (my_errno); 878 } 879 880 881 int 882 getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen, 883 struct passwd **pwretp) 884 { 885 return getpwuid_internal(uid, pw, buf, buflen, pwretp, false, true); 886 } 887 DEF_WEAK(getpwuid_r); 888 889 struct passwd * 890 getpwuid(uid_t uid) 891 { 892 struct passwd *pw = NULL; 893 int my_errno; 894 895 my_errno = getpwuid_internal(uid, NULL, NULL, 0, &pw, false, false); 896 if (my_errno) { 897 pw = NULL; 898 errno = my_errno; 899 } 900 return (pw); 901 } 902 903 struct passwd * 904 getpwuid_shadow(uid_t uid) 905 { 906 struct passwd *pw = NULL; 907 int my_errno; 908 909 my_errno = getpwuid_internal(uid, NULL, NULL, 0, &pw, true, false); 910 if (my_errno) { 911 pw = NULL; 912 errno = my_errno; 913 } 914 return (pw); 915 } 916 DEF_WEAK(getpwuid_shadow); 917 918 int 919 setpassent(int stayopen) 920 { 921 _THREAD_PRIVATE_MUTEX_LOCK(pw); 922 _pw_keynum = 0; 923 _pw_stayopen = stayopen; 924 #ifdef YP 925 __ypmode = YPMODE_NONE; 926 free(__ypcurrent); 927 __ypcurrent = NULL; 928 __ypexclude_free(&__ypexhead); 929 __ypproto = NULL; 930 #endif 931 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 932 return (1); 933 } 934 DEF_WEAK(setpassent); 935 936 void 937 setpwent(void) 938 { 939 (void) setpassent(0); 940 } 941 942 void 943 endpwent(void) 944 { 945 int saved_errno; 946 947 _THREAD_PRIVATE_MUTEX_LOCK(pw); 948 saved_errno = errno; 949 _pw_keynum = 0; 950 if (_pw_db) { 951 (void)(_pw_db->close)(_pw_db); 952 _pw_db = NULL; 953 } 954 #ifdef YP 955 __ypmode = YPMODE_NONE; 956 free(__ypcurrent); 957 __ypcurrent = NULL; 958 __ypexclude_free(&__ypexhead); 959 __ypproto = NULL; 960 #endif 961 errno = saved_errno; 962 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 963 } 964 965 static int 966 __initdb(int shadow) 967 { 968 static int warned; 969 int saved_errno = errno; 970 971 #ifdef YP 972 /* 973 * Hint to the kernel that a passwd database operation is happening. 974 */ 975 (void)access("/var/run/ypbind.lock", R_OK); 976 errno = saved_errno; 977 978 __ypmode = YPMODE_NONE; 979 __getpwent_has_yppw = -1; 980 #endif 981 if (shadow) 982 _pw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL); 983 if (!_pw_db) 984 _pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL); 985 if (_pw_db) { 986 errno = saved_errno; 987 return (1); 988 } 989 if (!warned) { 990 saved_errno = errno; 991 errno = saved_errno; 992 warned = 1; 993 } 994 return (0); 995 } 996 997 static int 998 __hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw, 999 int *flagsp) 1000 { 1001 char *p, *t; 1002 DBT data; 1003 1004 if ((_pw_db->get)(_pw_db, key, &data, 0)) 1005 return (0); 1006 p = (char *)data.data; 1007 if (data.size > buflen) { 1008 errno = ERANGE; 1009 return (0); 1010 } 1011 1012 t = buf; 1013 #define EXPAND(e) e = t; while ((*t++ = *p++)); 1014 EXPAND(pw->pw_name); 1015 EXPAND(pw->pw_passwd); 1016 bcopy(p, (char *)&pw->pw_uid, sizeof(int)); 1017 p += sizeof(int); 1018 bcopy(p, (char *)&pw->pw_gid, sizeof(int)); 1019 p += sizeof(int); 1020 bcopy(p, (char *)&pw->pw_change, sizeof(time_t)); 1021 p += sizeof(time_t); 1022 EXPAND(pw->pw_class); 1023 EXPAND(pw->pw_gecos); 1024 EXPAND(pw->pw_dir); 1025 EXPAND(pw->pw_shell); 1026 bcopy(p, (char *)&pw->pw_expire, sizeof(time_t)); 1027 p += sizeof(time_t); 1028 1029 /* See if there's any data left. If so, read in flags. */ 1030 if (data.size > (p - (char *)data.data)) { 1031 bcopy(p, (char *)flagsp, sizeof(int)); 1032 p += sizeof(int); 1033 } else 1034 *flagsp = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */ 1035 return (1); 1036 } 1037