1 /* $OpenBSD: getpwent.c,v 1.41 2009/11/12 18:00:18 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> 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 int len; 450 451 key.data = (u_char *)_PW_YPTOKEN; 452 key.size = strlen(_PW_YPTOKEN); 453 454 /* Pre-token database support. */ 455 bf[0] = _PW_KEYBYNAME; 456 bf[1] = '+'; 457 pkey.data = (u_char *)bf; 458 pkey.size = sizeof(bf); 459 460 if ((_pw_db->get)(_pw_db, &key, &data, 0) && 461 (_pw_db->get)(_pw_db, &pkey, &pdata, 0)) 462 return (0); /* No YP. */ 463 return (1); 464 } 465 466 /* 467 * See if there's a master.passwd map. 468 */ 469 static int 470 __has_ypmaster(void) 471 { 472 int keylen, resultlen; 473 char *key, *result; 474 static int checked = -1; 475 static uid_t saved_uid, saved_euid; 476 uid_t uid = getuid(), euid = geteuid(); 477 478 /* 479 * Do not recheck IFF the saved UID and the saved 480 * EUID are the same. In all other cases, recheck. 481 */ 482 if (checked != -1 && saved_uid == uid && saved_euid == euid) 483 return (checked); 484 485 if (euid != 0) { 486 saved_uid = uid; 487 saved_euid = euid; 488 checked = 0; 489 return (checked); 490 } 491 492 if (!__ypdomain) { 493 if (_yp_check(&__ypdomain) == 0) { 494 saved_uid = uid; 495 saved_euid = euid; 496 checked = 0; 497 return (checked); /* No domain. */ 498 } 499 } 500 501 if (yp_first(__ypdomain, "master.passwd.byname", 502 &key, &keylen, &result, &resultlen)) { 503 saved_uid = uid; 504 saved_euid = euid; 505 checked = 0; 506 return (checked); 507 } 508 free(result); 509 if (key) 510 free(key); 511 512 saved_uid = uid; 513 saved_euid = euid; 514 checked = 1; 515 return (checked); 516 } 517 518 static struct passwd * 519 __yppwlookup(int lookup, char *name, uid_t uid, struct passwd *pw, 520 char *buf, size_t buflen, int *flagsp) 521 { 522 char bf[1 + _PW_NAME_LEN], *ypcurrent = NULL, *map = NULL; 523 int yp_pw_flags = 0, ypcurrentlen, r, s = -1, pw_keynum; 524 static long yppbuf[_PW_BUF_LEN / sizeof(long)]; 525 struct _ypexclude *ypexhead = NULL; 526 const char *host, *user, *dom; 527 DBT key; 528 529 for (pw_keynum = 1; pw_keynum; pw_keynum++) { 530 bf[0] = _PW_KEYBYNUM; 531 bcopy((char *)&pw_keynum, &bf[1], sizeof(pw_keynum)); 532 key.data = (u_char *)bf; 533 key.size = 1 + sizeof(pw_keynum); 534 if (__hashpw(&key, buf, buflen, pw, flagsp) == 0) 535 break; 536 switch (pw->pw_name[0]) { 537 case '+': 538 if (!__ypdomain) { 539 if (_yp_check(&__ypdomain) == 0) 540 continue; 541 } 542 __ypproto_set(pw, yppbuf, *flagsp, &yp_pw_flags); 543 if (!map) { 544 if (lookup == LOOKUP_BYNAME) { 545 map = PASSWD_BYNAME; 546 name = strdup(name); 547 } else { 548 map = PASSWD_BYUID; 549 asprintf(&name, "%u", uid); 550 } 551 } 552 553 switch (pw->pw_name[1]) { 554 case '\0': 555 if (ypcurrent) { 556 free(ypcurrent); 557 ypcurrent = NULL; 558 } 559 r = yp_match(__ypdomain, map, 560 name, strlen(name), 561 &ypcurrent, &ypcurrentlen); 562 if (r != 0 || ypcurrentlen > buflen) { 563 if (ypcurrent) 564 free(ypcurrent); 565 ypcurrent = NULL; 566 continue; 567 } 568 break; 569 case '@': 570 pwnam_netgrp: 571 if (ypcurrent) { 572 free(ypcurrent); 573 ypcurrent = NULL; 574 } 575 if (s == -1) /* first time */ 576 setnetgrent(pw->pw_name + 2); 577 s = getnetgrent(&host, &user, &dom); 578 if (s == 0) { /* end of group */ 579 endnetgrent(); 580 s = -1; 581 continue; 582 } else { 583 if (user && *user) { 584 r = yp_match(__ypdomain, map, 585 user, strlen(user), 586 &ypcurrent, &ypcurrentlen); 587 } else 588 goto pwnam_netgrp; 589 if (r != 0 || ypcurrentlen > buflen) { 590 if (ypcurrent) 591 free(ypcurrent); 592 ypcurrent = NULL; 593 /* 594 * just because this 595 * user is bad, doesn't 596 * mean they all are. 597 */ 598 goto pwnam_netgrp; 599 } 600 } 601 break; 602 default: 603 if (ypcurrent) { 604 free(ypcurrent); 605 ypcurrent = NULL; 606 } 607 user = pw->pw_name + 1; 608 r = yp_match(__ypdomain, map, 609 user, strlen(user), 610 &ypcurrent, &ypcurrentlen); 611 if (r != 0 || ypcurrentlen > buflen) { 612 if (ypcurrent) 613 free(ypcurrent); 614 ypcurrent = NULL; 615 continue; 616 } 617 break; 618 } 619 bcopy(ypcurrent, buf, ypcurrentlen); 620 buf[ypcurrentlen] = '\0'; 621 if (__ypparse(pw, buf, yp_pw_flags) || 622 __ypexclude_is(&ypexhead, pw->pw_name)) { 623 if (s == 1) /* inside netgrp */ 624 goto pwnam_netgrp; 625 continue; 626 } 627 break; 628 case '-': 629 /* attempted exclusion */ 630 switch (pw->pw_name[1]) { 631 case '\0': 632 break; 633 case '@': 634 setnetgrent(pw->pw_name + 2); 635 while (getnetgrent(&host, &user, &dom)) { 636 if (user && *user) 637 __ypexclude_add(&ypexhead, user); 638 } 639 endnetgrent(); 640 break; 641 default: 642 __ypexclude_add(&ypexhead, pw->pw_name + 1); 643 break; 644 } 645 break; 646 } 647 if ((lookup == LOOKUP_BYUID && pw->pw_uid == uid) || 648 (lookup == LOOKUP_BYNAME && strcmp(pw->pw_name, name) == 0)) 649 goto done; 650 if (s == 1) /* inside netgrp */ 651 goto pwnam_netgrp; 652 continue; 653 } 654 pw = NULL; 655 done: 656 __ypexclude_free(&ypexhead); 657 __ypproto = NULL; 658 if (ypcurrent) 659 free(ypcurrent); 660 ypcurrent = NULL; 661 if (map) 662 free(name); 663 return (pw); 664 } 665 #endif /* YP */ 666 667 static struct passwd * 668 _pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw, 669 int *flagsp) 670 { 671 char bf[1 + _PW_NAME_LEN]; 672 int len, r; 673 DBT key; 674 675 len = strlen(name); 676 if (len > _PW_NAME_LEN) 677 return (NULL); 678 bf[0] = _PW_KEYBYNAME; 679 bcopy(name, &bf[1], MIN(len, _PW_NAME_LEN)); 680 key.data = (u_char *)bf; 681 key.size = 1 + MIN(len, _PW_NAME_LEN); 682 r = __hashpw(&key, buf, buflen, pw, flagsp); 683 if (r) 684 return (pw); 685 return (NULL); 686 } 687 688 static struct passwd * 689 _pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw, 690 int *flagsp) 691 { 692 char bf[1 + sizeof(int)]; 693 DBT key; 694 int r; 695 696 bf[0] = _PW_KEYBYUID; 697 bcopy(&uid, &bf[1], sizeof(uid)); 698 key.data = (u_char *)bf; 699 key.size = 1 + sizeof(uid); 700 r = __hashpw(&key, buf, buflen, pw, flagsp); 701 if (r) 702 return (pw); 703 return (NULL); 704 } 705 706 int 707 getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen, 708 struct passwd **pwretp) 709 { 710 struct passwd *pwret = NULL; 711 int flags = 0, *flagsp; 712 DB *savedb; 713 714 _THREAD_PRIVATE_MUTEX_LOCK(pw); 715 savedb = _pw_db; 716 if (!_pw_db && !__initdb()) 717 goto fail; 718 719 if (pw == &_pw_passwd) 720 flagsp = &_pw_flags; 721 else 722 flagsp = &flags; 723 724 #ifdef YP 725 if (__has_yppw()) 726 pwret = __yppwlookup(LOOKUP_BYNAME, (char *)name, 0, pw, 727 buf, buflen, flagsp); 728 #endif /* YP */ 729 if (!pwret) 730 pwret = _pwhashbyname(name, buf, buflen, pw, flagsp); 731 732 if (savedb != _pw_db || !_pw_stayopen) { 733 (void)(_pw_db->close)(_pw_db); 734 _pw_db = NULL; 735 } 736 fail: 737 if (pwretp) 738 *pwretp = pwret; 739 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 740 return (pwret ? 0 : 1); 741 } 742 743 struct passwd * 744 getpwnam(const char *name) 745 { 746 struct passwd *pw = NULL; 747 748 if (getpwnam_r(name, &_pw_passwd, _pw_string, sizeof _pw_string, &pw)) 749 pw = NULL; 750 return (pw); 751 } 752 753 int 754 getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen, 755 struct passwd **pwretp) 756 { 757 struct passwd *pwret = NULL; 758 int flags = 0, *flagsp; 759 DB *savedb; 760 761 _THREAD_PRIVATE_MUTEX_LOCK(pw); 762 savedb = _pw_db; 763 if (!_pw_db && !__initdb()) 764 goto fail; 765 766 if (pw == &_pw_passwd) 767 flagsp = &_pw_flags; 768 else 769 flagsp = &flags; 770 771 #ifdef YP 772 if (__has_yppw()) 773 pwret = __yppwlookup(LOOKUP_BYUID, NULL, uid, pw, 774 buf, buflen, flagsp); 775 #endif /* YP */ 776 if (!pwret) 777 pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp); 778 779 if (savedb != _pw_db || !_pw_stayopen) { 780 (void)(_pw_db->close)(_pw_db); 781 _pw_db = NULL; 782 } 783 fail: 784 if (pwretp) 785 *pwretp = pwret; 786 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 787 return (pwret ? 0 : 1); 788 } 789 790 struct passwd * 791 getpwuid(uid_t uid) 792 { 793 struct passwd *pw = NULL; 794 795 if (getpwuid_r(uid, &_pw_passwd, _pw_string, sizeof _pw_string, &pw)) 796 pw = NULL; 797 return (pw); 798 } 799 800 int 801 setpassent(int stayopen) 802 { 803 _THREAD_PRIVATE_MUTEX_LOCK(pw); 804 _pw_keynum = 0; 805 _pw_stayopen = stayopen; 806 #ifdef YP 807 __ypmode = YPMODE_NONE; 808 if (__ypcurrent) 809 free(__ypcurrent); 810 __ypcurrent = NULL; 811 __ypexclude_free(&__ypexhead); 812 __ypproto = NULL; 813 #endif 814 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 815 return (1); 816 } 817 818 void 819 setpwent(void) 820 { 821 (void) setpassent(0); 822 } 823 824 void 825 endpwent(void) 826 { 827 _THREAD_PRIVATE_MUTEX_LOCK(pw); 828 _pw_keynum = 0; 829 if (_pw_db) { 830 (void)(_pw_db->close)(_pw_db); 831 _pw_db = NULL; 832 } 833 #ifdef YP 834 __ypmode = YPMODE_NONE; 835 if (__ypcurrent) 836 free(__ypcurrent); 837 __ypcurrent = NULL; 838 __ypexclude_free(&__ypexhead); 839 __ypproto = NULL; 840 #endif 841 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 842 } 843 844 static int 845 __initdb(void) 846 { 847 static int warned; 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 return (1); 856 if (!warned) 857 syslog(LOG_ERR, "%s: %m", _PATH_MP_DB); 858 warned = 1; 859 return (0); 860 } 861 862 static int 863 __hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw, 864 int *flagsp) 865 { 866 char *p, *t; 867 DBT data; 868 869 if ((_pw_db->get)(_pw_db, key, &data, 0)) 870 return (0); 871 p = (char *)data.data; 872 if (data.size > buflen) 873 return (0); 874 875 t = buf; 876 #define EXPAND(e) e = t; while ((*t++ = *p++)); 877 EXPAND(pw->pw_name); 878 EXPAND(pw->pw_passwd); 879 bcopy(p, (char *)&pw->pw_uid, sizeof(int)); 880 p += sizeof(int); 881 bcopy(p, (char *)&pw->pw_gid, sizeof(int)); 882 p += sizeof(int); 883 bcopy(p, (char *)&pw->pw_change, sizeof(time_t)); 884 p += sizeof(time_t); 885 EXPAND(pw->pw_class); 886 EXPAND(pw->pw_gecos); 887 EXPAND(pw->pw_dir); 888 EXPAND(pw->pw_shell); 889 bcopy(p, (char *)&pw->pw_expire, sizeof(time_t)); 890 p += sizeof(time_t); 891 892 /* See if there's any data left. If so, read in flags. */ 893 if (data.size > (p - (char *)data.data)) { 894 bcopy(p, (char *)flagsp, sizeof(int)); 895 p += sizeof(int); 896 } else 897 *flagsp = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */ 898 return (1); 899 } 900