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