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