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