1 /* $OpenBSD: getpwent.c,v 1.38 2008/07/23 19:36:47 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 #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; 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 if (lookup == LOOKUP_BYNAME) { 588 map = PASSWD_BYNAME; 589 name = strdup(name); 590 } else { 591 map = PASSWD_BYUID; 592 asprintf(&name, "%u", uid); 593 } 594 595 for (pw_keynum = 1; pw_keynum; pw_keynum++) { 596 bf[0] = _PW_KEYBYNUM; 597 bcopy((char *)&pw_keynum, &bf[1], sizeof(pw_keynum)); 598 key.data = (u_char *)bf; 599 key.size = 1 + sizeof(pw_keynum); 600 if (__hashpw(&key, buf, buflen, pw, flagsp) == 0) 601 break; 602 switch (pw->pw_name[0]) { 603 case '+': 604 if (!__ypdomain) { 605 if (_yp_check(&__ypdomain) == 0) 606 continue; 607 } 608 __ypproto_set(pw, yppbuf, *flagsp, &yp_pw_flags); 609 610 switch (pw->pw_name[1]) { 611 case '\0': 612 if (ypcurrent) { 613 free(ypcurrent); 614 ypcurrent = NULL; 615 } 616 r = yp_match(__ypdomain, map, 617 name, strlen(name), 618 &ypcurrent, &ypcurrentlen); 619 if (r != 0 || ypcurrentlen > buflen) { 620 if (ypcurrent) 621 free(ypcurrent); 622 ypcurrent = NULL; 623 continue; 624 } 625 break; 626 case '@': 627 pwnam_netgrp: 628 if (ypcurrent) { 629 free(ypcurrent); 630 ypcurrent = NULL; 631 } 632 if (s == -1) /* first time */ 633 setnetgrent(pw->pw_name + 2); 634 s = getnetgrent(&host, &user, &dom); 635 if (s == 0) { /* end of group */ 636 endnetgrent(); 637 s = -1; 638 continue; 639 } else { 640 if (user && *user) { 641 r = yp_match(__ypdomain, map, 642 user, strlen(user), 643 &ypcurrent, &ypcurrentlen); 644 } else 645 goto pwnam_netgrp; 646 if (r != 0 || ypcurrentlen > buflen) { 647 if (ypcurrent) 648 free(ypcurrent); 649 ypcurrent = NULL; 650 /* 651 * just because this 652 * user is bad, doesn't 653 * mean they all are. 654 */ 655 goto pwnam_netgrp; 656 } 657 } 658 break; 659 default: 660 if (ypcurrent) { 661 free(ypcurrent); 662 ypcurrent = NULL; 663 } 664 user = pw->pw_name + 1; 665 r = yp_match(__ypdomain, map, 666 user, strlen(user), 667 &ypcurrent, &ypcurrentlen); 668 if (r != 0 || ypcurrentlen > buflen) { 669 if (ypcurrent) 670 free(ypcurrent); 671 ypcurrent = NULL; 672 continue; 673 } 674 break; 675 } 676 bcopy(ypcurrent, buf, ypcurrentlen); 677 buf[ypcurrentlen] = '\0'; 678 if (__ypparse(pw, buf, yp_pw_flags) || 679 __ypexclude_is(&ypexhead, pw->pw_name)) { 680 if (s == 1) /* inside netgrp */ 681 goto pwnam_netgrp; 682 continue; 683 } 684 break; 685 case '-': 686 /* attempted exclusion */ 687 switch (pw->pw_name[1]) { 688 case '\0': 689 break; 690 case '@': 691 setnetgrent(pw->pw_name + 2); 692 while (getnetgrent(&host, &user, &dom)) { 693 if (user && *user) 694 __ypexclude_add(&ypexhead, user); 695 } 696 endnetgrent(); 697 break; 698 default: 699 __ypexclude_add(&ypexhead, pw->pw_name + 1); 700 break; 701 } 702 break; 703 } 704 if ((lookup == LOOKUP_BYUID && pw->pw_uid == uid) || 705 (lookup == LOOKUP_BYNAME && strcmp(pw->pw_name, name) == 0)) 706 goto done; 707 if (s == 1) /* inside netgrp */ 708 goto pwnam_netgrp; 709 continue; 710 } 711 pw = NULL; 712 done: 713 __ypexclude_free(&ypexhead); 714 __ypproto = NULL; 715 if (ypcurrent) 716 free(ypcurrent); 717 ypcurrent = NULL; 718 free(name); 719 return (pw); 720 } 721 #endif /* YP */ 722 723 static struct passwd * 724 _pwhashbyname(const char *name, char *buf, size_t buflen, struct passwd *pw, 725 int *flagsp) 726 { 727 char bf[1 + _PW_NAME_LEN]; 728 int len, r; 729 DBT key; 730 731 len = strlen(name); 732 if (len > _PW_NAME_LEN) 733 return (NULL); 734 bf[0] = _PW_KEYBYNAME; 735 bcopy(name, &bf[1], MIN(len, _PW_NAME_LEN)); 736 key.data = (u_char *)bf; 737 key.size = 1 + MIN(len, _PW_NAME_LEN); 738 r = __hashpw(&key, buf, buflen, pw, flagsp); 739 if (r) 740 return (pw); 741 return (NULL); 742 } 743 744 static struct passwd * 745 _pwhashbyuid(uid_t uid, char *buf, size_t buflen, struct passwd *pw, 746 int *flagsp) 747 { 748 char bf[1 + sizeof(int)]; 749 DBT key; 750 int r; 751 752 bf[0] = _PW_KEYBYUID; 753 bcopy(&uid, &bf[1], sizeof(uid)); 754 key.data = (u_char *)bf; 755 key.size = 1 + sizeof(uid); 756 r = __hashpw(&key, buf, buflen, pw, flagsp); 757 if (r) 758 return (pw); 759 return (NULL); 760 } 761 762 int 763 getpwnam_r(const char *name, struct passwd *pw, char *buf, size_t buflen, 764 struct passwd **pwretp) 765 { 766 struct passwd *pwret = NULL; 767 int flags = 0, *flagsp; 768 DB *savedb; 769 770 _THREAD_PRIVATE_MUTEX_LOCK(pw); 771 savedb = _pw_db; 772 if (!_pw_db && !__initdb()) 773 goto fail; 774 775 if (pw == &_pw_passwd) 776 flagsp = &_pw_flags; 777 else 778 flagsp = &flags; 779 780 #ifdef YP 781 if (__has_yppw()) 782 pwret = __yppwlookup(LOOKUP_BYNAME, (char *)name, 0, pw, 783 buf, buflen, flagsp); 784 #endif /* YP */ 785 if (!pwret) 786 pwret = _pwhashbyname(name, buf, buflen, pw, flagsp); 787 788 if (savedb != _pw_db || !_pw_stayopen) { 789 (void)(_pw_db->close)(_pw_db); 790 _pw_db = NULL; 791 } 792 fail: 793 if (pwretp) 794 *pwretp = pwret; 795 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 796 return (pwret ? 0 : 1); 797 } 798 799 struct passwd * 800 getpwnam(const char *name) 801 { 802 struct passwd *pw = NULL; 803 804 if (getpwnam_r(name, &_pw_passwd, _pw_string, sizeof _pw_string, &pw)) 805 pw = NULL; 806 return (pw); 807 } 808 809 int 810 getpwuid_r(uid_t uid, struct passwd *pw, char *buf, size_t buflen, 811 struct passwd **pwretp) 812 { 813 struct passwd *pwret = NULL; 814 int flags = 0, *flagsp; 815 DB *savedb; 816 817 _THREAD_PRIVATE_MUTEX_LOCK(pw); 818 savedb = _pw_db; 819 if (!_pw_db && !__initdb()) 820 goto fail; 821 822 if (pw == &_pw_passwd) 823 flagsp = &_pw_flags; 824 else 825 flagsp = &flags; 826 827 #ifdef YP 828 if (__has_yppw()) 829 pwret = __yppwlookup(LOOKUP_BYUID, NULL, uid, pw, 830 buf, buflen, flagsp); 831 #endif /* YP */ 832 if (!pwret) 833 pwret = _pwhashbyuid(uid, buf, buflen, pw, flagsp); 834 835 if (savedb != _pw_db || !_pw_stayopen) { 836 (void)(_pw_db->close)(_pw_db); 837 _pw_db = NULL; 838 } 839 fail: 840 if (pwretp) 841 *pwretp = pwret; 842 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 843 return (pwret ? 0 : 1); 844 } 845 846 struct passwd * 847 getpwuid(uid_t uid) 848 { 849 struct passwd *pw = NULL; 850 851 if (getpwuid_r(uid, &_pw_passwd, _pw_string, sizeof _pw_string, &pw)) 852 pw = NULL; 853 return (pw); 854 } 855 856 int 857 setpassent(int stayopen) 858 { 859 _THREAD_PRIVATE_MUTEX_LOCK(pw); 860 _pw_keynum = 0; 861 _pw_stayopen = stayopen; 862 #ifdef YP 863 __ypmode = YPMODE_NONE; 864 if (__ypcurrent) 865 free(__ypcurrent); 866 __ypcurrent = NULL; 867 __ypexclude_free(&__ypexhead); 868 __ypproto = NULL; 869 #endif 870 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 871 return (1); 872 } 873 874 void 875 setpwent(void) 876 { 877 (void) setpassent(0); 878 } 879 880 void 881 endpwent(void) 882 { 883 _THREAD_PRIVATE_MUTEX_LOCK(pw); 884 _pw_keynum = 0; 885 if (_pw_db) { 886 (void)(_pw_db->close)(_pw_db); 887 _pw_db = NULL; 888 } 889 #ifdef YP 890 __ypmode = YPMODE_NONE; 891 if (__ypcurrent) 892 free(__ypcurrent); 893 __ypcurrent = NULL; 894 __ypexclude_free(&__ypexhead); 895 __ypproto = NULL; 896 #endif 897 _THREAD_PRIVATE_MUTEX_UNLOCK(pw); 898 } 899 900 static int 901 __initdb(void) 902 { 903 static int warned; 904 905 #ifdef YP 906 __ypmode = YPMODE_NONE; 907 __getpwent_has_yppw = -1; 908 #endif 909 if ((_pw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) || 910 (_pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL))) 911 return (1); 912 if (!warned) 913 syslog(LOG_ERR, "%s: %m", _PATH_MP_DB); 914 warned = 1; 915 return (0); 916 } 917 918 static int 919 __hashpw(DBT *key, char *buf, size_t buflen, struct passwd *pw, 920 int *flagsp) 921 { 922 char *p, *t; 923 DBT data; 924 925 if ((_pw_db->get)(_pw_db, key, &data, 0)) 926 return (0); 927 p = (char *)data.data; 928 if (data.size > buflen) 929 return (0); 930 931 t = buf; 932 #define EXPAND(e) e = t; while ((*t++ = *p++)); 933 EXPAND(pw->pw_name); 934 EXPAND(pw->pw_passwd); 935 bcopy(p, (char *)&pw->pw_uid, sizeof(int)); 936 p += sizeof(int); 937 bcopy(p, (char *)&pw->pw_gid, sizeof(int)); 938 p += sizeof(int); 939 bcopy(p, (char *)&pw->pw_change, sizeof(time_t)); 940 p += sizeof(time_t); 941 EXPAND(pw->pw_class); 942 EXPAND(pw->pw_gecos); 943 EXPAND(pw->pw_dir); 944 EXPAND(pw->pw_shell); 945 bcopy(p, (char *)&pw->pw_expire, sizeof(time_t)); 946 p += sizeof(time_t); 947 948 /* See if there's any data left. If so, read in flags. */ 949 if (data.size > (p - (char *)data.data)) { 950 bcopy(p, (char *)flagsp, sizeof(int)); 951 p += sizeof(int); 952 } else 953 *flagsp = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */ 954 return (1); 955 } 956