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