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