1 /* 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * Portions Copyright (c) 1994, 1995, 1996, Jason Downs. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #if defined(LIBC_SCCS) && !defined(lint) 32 static char rcsid[] = "$OpenBSD: getpwent.c,v 1.31 2003/06/25 21:16:47 deraadt Exp $"; 33 #endif /* LIBC_SCCS and not lint */ 34 35 #include <sys/param.h> 36 #include <fcntl.h> 37 #include <db.h> 38 #include <syslog.h> 39 #include <pwd.h> 40 #include <errno.h> 41 #include <unistd.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <limits.h> 45 #include <netgroup.h> 46 #ifdef YP 47 #include <machine/param.h> 48 #include <stdio.h> 49 #include <rpc/rpc.h> 50 #include <rpcsvc/yp.h> 51 #include <rpcsvc/ypclnt.h> 52 #include "ypinternal.h" 53 #endif 54 55 static struct passwd _pw_passwd; /* password structure */ 56 static DB *_pw_db; /* password database */ 57 static int _pw_keynum; /* key counter */ 58 static int _pw_stayopen; /* keep fd's open */ 59 static int _pw_flags; /* password flags */ 60 static int __hashpw(DBT *); 61 static int __initdb(void); 62 63 #ifdef YP 64 enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP }; 65 static enum _ypmode __ypmode; 66 67 static char *__ypcurrent, *__ypdomain; 68 static int __ypcurrentlen; 69 static struct passwd *__ypproto = (struct passwd *)NULL; 70 static int __ypflags; 71 static char __ypline[1024]; 72 static long __yppbuf[1024 / sizeof(long)]; 73 static int __yp_override_passwd = 0; 74 75 static int __has_yppw(void); 76 static int __has_ypmaster(void); 77 78 static int __ypexclude_add(const char *); 79 static int __ypexclude_is(const char *); 80 static void __ypexclude_free(void); 81 static void __ypproto_set(void); 82 static int __ypparse(struct passwd *pw, char *s); 83 84 /* macro for deciding which YP maps to use. */ 85 #define PASSWD_BYNAME \ 86 __has_ypmaster() ? "master.passwd.byname" : "passwd.byname" 87 #define PASSWD_BYUID \ 88 __has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid" 89 90 struct _ypexclude { 91 const char *name; 92 struct _ypexclude *next; 93 }; 94 static struct _ypexclude *__ypexclude = (struct _ypexclude *)NULL; 95 96 /* 97 * Using DB for this just wastes too damn much memory. 98 */ 99 static int 100 __ypexclude_add(name) 101 const char *name; 102 { 103 struct _ypexclude *new; 104 105 if (name[0] == '\0') /* skip */ 106 return (0); 107 108 new = (struct _ypexclude *)malloc(sizeof(struct _ypexclude)); 109 if (new == NULL) 110 return (1); 111 new->name = strdup(name); 112 if (new->name == (char *)NULL) { 113 free(new); 114 return (1); 115 } 116 117 new->next = __ypexclude; 118 __ypexclude = new; 119 120 return (0); 121 } 122 123 static int 124 __ypexclude_is(name) 125 const char *name; 126 { 127 struct _ypexclude *curr; 128 129 for (curr = __ypexclude; curr != (struct _ypexclude *)NULL; 130 curr = curr->next) { 131 if (strcmp(curr->name, name) == 0) 132 return (1); /* excluded */ 133 } 134 return (0); 135 } 136 137 static void 138 __ypexclude_free() 139 { 140 struct _ypexclude *curr, *next; 141 142 for (curr = __ypexclude; curr != (struct _ypexclude *)NULL; 143 curr = next) { 144 next = curr->next; 145 146 free((void *)curr->name); 147 free(curr); 148 } 149 __ypexclude = (struct _ypexclude *)NULL; 150 } 151 152 static void 153 __ypproto_set() 154 { 155 register char *ptr; 156 register struct passwd *pw = &_pw_passwd; 157 158 /* make this the new prototype */ 159 ptr = (char *)__yppbuf; 160 161 /* first allocate the struct. */ 162 __ypproto = (struct passwd *)ptr; 163 ptr += sizeof(struct passwd); 164 165 /* name */ 166 if (pw->pw_name && (pw->pw_name)[0]) { 167 ptr = (char *)ALIGN(ptr); 168 bcopy(pw->pw_name, ptr, strlen(pw->pw_name) + 1); 169 __ypproto->pw_name = ptr; 170 ptr += (strlen(pw->pw_name) + 1); 171 } else 172 __ypproto->pw_name = (char *)NULL; 173 174 /* password */ 175 if (pw->pw_passwd && (pw->pw_passwd)[0]) { 176 ptr = (char *)ALIGN(ptr); 177 bcopy(pw->pw_passwd, ptr, strlen(pw->pw_passwd) + 1); 178 __ypproto->pw_passwd = ptr; 179 ptr += (strlen(pw->pw_passwd) + 1); 180 } else 181 __ypproto->pw_passwd = (char *)NULL; 182 183 /* uid */ 184 __ypproto->pw_uid = pw->pw_uid; 185 186 /* gid */ 187 __ypproto->pw_gid = pw->pw_gid; 188 189 /* change (ignored anyway) */ 190 __ypproto->pw_change = pw->pw_change; 191 192 /* class (ignored anyway) */ 193 __ypproto->pw_class = ""; 194 195 /* gecos */ 196 if (pw->pw_gecos && (pw->pw_gecos)[0]) { 197 ptr = (char *)ALIGN(ptr); 198 bcopy(pw->pw_gecos, ptr, strlen(pw->pw_gecos) + 1); 199 __ypproto->pw_gecos = ptr; 200 ptr += (strlen(pw->pw_gecos) + 1); 201 } else 202 __ypproto->pw_gecos = (char *)NULL; 203 204 /* dir */ 205 if (pw->pw_dir && (pw->pw_dir)[0]) { 206 ptr = (char *)ALIGN(ptr); 207 bcopy(pw->pw_dir, ptr, strlen(pw->pw_dir) + 1); 208 __ypproto->pw_dir = ptr; 209 ptr += (strlen(pw->pw_dir) + 1); 210 } else 211 __ypproto->pw_dir = (char *)NULL; 212 213 /* shell */ 214 if (pw->pw_shell && (pw->pw_shell)[0]) { 215 ptr = (char *)ALIGN(ptr); 216 bcopy(pw->pw_shell, ptr, strlen(pw->pw_shell) + 1); 217 __ypproto->pw_shell = ptr; 218 ptr += (strlen(pw->pw_shell) + 1); 219 } else 220 __ypproto->pw_shell = (char *)NULL; 221 222 /* expire (ignored anyway) */ 223 __ypproto->pw_expire = pw->pw_expire; 224 225 /* flags */ 226 __ypflags = _pw_flags; 227 } 228 229 static int 230 __ypparse(pw, s) 231 struct passwd *pw; 232 char *s; 233 { 234 char *bp, *cp, *endp; 235 u_long ul; 236 int count = 0; 237 238 /* count the colons. */ 239 bp = s; 240 while (*bp != '\0') { 241 if (*bp++ == ':') 242 count++; 243 } 244 245 /* since this is currently using strsep(), parse it first */ 246 bp = s; 247 pw->pw_name = strsep(&bp, ":\n"); 248 pw->pw_passwd = strsep(&bp, ":\n"); 249 if (!(cp = strsep(&bp, ":\n"))) 250 return 1; 251 ul = strtoul(cp, &endp, 10); 252 if (endp == cp || *endp != '\0' || ul >= UID_MAX) 253 return 1; 254 pw->pw_uid = (uid_t)ul; 255 if (!(cp = strsep(&bp, ":\n"))) 256 return 1; 257 ul = strtoul(cp, &endp, 10); 258 if (endp == cp || *endp != '\0' || ul >= GID_MAX) 259 return 1; 260 pw->pw_gid = (gid_t)ul; 261 if (count == 9) { 262 long l; 263 264 /* If the ypserv gave us all the fields, use them. */ 265 pw->pw_class = strsep(&bp, ":\n"); 266 if (!(cp = strsep(&bp, ":\n"))) 267 return 1; 268 l = strtol(cp, &endp, 10); 269 if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN) 270 return 1; 271 pw->pw_change = (time_t)l; 272 if (!(cp = strsep(&bp, ":\n"))) 273 return 1; 274 l = strtol(cp, &endp, 10); 275 if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN) 276 return 1; 277 pw->pw_expire = (time_t)l; 278 } else { 279 /* ..else it is a normal ypserv. */ 280 pw->pw_class = ""; 281 pw->pw_change = 0; 282 pw->pw_expire = 0; 283 } 284 pw->pw_gecos = strsep(&bp, ":\n"); 285 pw->pw_dir = strsep(&bp, ":\n"); 286 pw->pw_shell = strsep(&bp, ":\n"); 287 288 /* now let the prototype override, if set. */ 289 if (__ypproto != (struct passwd *)NULL) { 290 if (__yp_override_passwd && __ypproto->pw_passwd != (char *)NULL) 291 pw->pw_passwd = __ypproto->pw_passwd; 292 if (!(__ypflags & _PASSWORD_NOUID)) 293 pw->pw_uid = __ypproto->pw_uid; 294 if (!(__ypflags & _PASSWORD_NOGID)) 295 pw->pw_gid = __ypproto->pw_gid; 296 if (__ypproto->pw_gecos != (char *)NULL) 297 pw->pw_gecos = __ypproto->pw_gecos; 298 if (__ypproto->pw_dir != (char *)NULL) 299 pw->pw_dir = __ypproto->pw_dir; 300 if (__ypproto->pw_shell != (char *)NULL) 301 pw->pw_shell = __ypproto->pw_shell; 302 } 303 return 0; 304 } 305 #endif 306 307 #ifdef YP 308 static int __getpwent_has_yppw = -1; 309 #endif 310 311 struct passwd * 312 getpwent() 313 { 314 DBT key; 315 char bf[sizeof(_pw_keynum) + 1]; 316 #ifdef YP 317 static char *name = (char *)NULL; 318 const char *user, *host, *dom; 319 #endif 320 321 if (!_pw_db && !__initdb()) 322 return ((struct passwd *)NULL); 323 324 #ifdef YP 325 if (__getpwent_has_yppw == -1) 326 __getpwent_has_yppw = __has_yppw(); 327 328 again: 329 if (__getpwent_has_yppw && (__ypmode != YPMODE_NONE)) { 330 char *key, *data; 331 int keylen, datalen; 332 int r, s; 333 334 if (!__ypdomain) { 335 if (_yp_check(&__ypdomain) == 0) { 336 __ypmode = YPMODE_NONE; 337 goto again; 338 } 339 } 340 switch (__ypmode) { 341 case YPMODE_FULL: 342 if (__ypcurrent) { 343 r = yp_next(__ypdomain, (PASSWD_BYNAME), 344 __ypcurrent, __ypcurrentlen, 345 &key, &keylen, &data, &datalen); 346 free(__ypcurrent); 347 if (r != 0) { 348 __ypcurrent = NULL; 349 __ypmode = YPMODE_NONE; 350 if (data) 351 free(data); 352 data = NULL; 353 goto again; 354 } 355 __ypcurrent = key; 356 __ypcurrentlen = keylen; 357 bcopy(data, __ypline, datalen); 358 free(data); 359 data = NULL; 360 } else { 361 r = yp_first(__ypdomain, (PASSWD_BYNAME), 362 &__ypcurrent, &__ypcurrentlen, 363 &data, &datalen); 364 if (r != 0) { 365 __ypmode = YPMODE_NONE; 366 if (data) 367 free(data); 368 goto again; 369 } 370 bcopy(data, __ypline, datalen); 371 free(data); 372 data = NULL; 373 } 374 break; 375 case YPMODE_NETGRP: 376 s = getnetgrent(&host, &user, &dom); 377 if (s == 0) { /* end of group */ 378 endnetgrent(); 379 __ypmode = YPMODE_NONE; 380 goto again; 381 } 382 if (user && *user) { 383 r = yp_match(__ypdomain, (PASSWD_BYNAME), 384 user, strlen(user), 385 &data, &datalen); 386 } else 387 goto again; 388 if (r != 0) { 389 /* 390 * if the netgroup is invalid, keep looking 391 * as there may be valid users later on. 392 */ 393 if (data) 394 free(data); 395 goto again; 396 } 397 bcopy(data, __ypline, datalen); 398 free(data); 399 data = (char *)NULL; 400 break; 401 case YPMODE_USER: 402 if (name != (char *)NULL) { 403 r = yp_match(__ypdomain, (PASSWD_BYNAME), 404 name, strlen(name), 405 &data, &datalen); 406 __ypmode = YPMODE_NONE; 407 free(name); 408 name = (char *)NULL; 409 if (r != 0) { 410 if (data) 411 free(data); 412 goto again; 413 } 414 bcopy(data, __ypline, datalen); 415 free(data); 416 data = (char *)NULL; 417 } else { /* XXX */ 418 __ypmode = YPMODE_NONE; 419 goto again; 420 } 421 break; 422 case YPMODE_NONE: 423 /* NOTREACHED */ 424 break; 425 } 426 427 __ypline[datalen] = '\0'; 428 if (__ypparse(&_pw_passwd, __ypline)) 429 goto again; 430 return &_pw_passwd; 431 } 432 #endif 433 434 ++_pw_keynum; 435 bf[0] = _PW_KEYBYNUM; 436 bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum)); 437 key.data = (u_char *)bf; 438 key.size = sizeof(_pw_keynum) + 1; 439 if (__hashpw(&key)) { 440 #ifdef YP 441 /* if we don't have YP at all, don't bother. */ 442 if (__getpwent_has_yppw) { 443 if (_pw_passwd.pw_name[0] == '+') { 444 /* set the mode */ 445 switch (_pw_passwd.pw_name[1]) { 446 case '\0': 447 __ypmode = YPMODE_FULL; 448 break; 449 case '@': 450 __ypmode = YPMODE_NETGRP; 451 setnetgrent(_pw_passwd.pw_name + 2); 452 break; 453 default: 454 __ypmode = YPMODE_USER; 455 name = strdup(_pw_passwd.pw_name + 1); 456 break; 457 } 458 459 /* save the prototype */ 460 __ypproto_set(); 461 goto again; 462 } else if (_pw_passwd.pw_name[0] == '-') { 463 /* an attempted exclusion */ 464 switch (_pw_passwd.pw_name[1]) { 465 case '\0': 466 break; 467 case '@': 468 setnetgrent(_pw_passwd.pw_name + 2); 469 while (getnetgrent(&host, &user, &dom)) { 470 if (user && *user) 471 __ypexclude_add(user); 472 } 473 endnetgrent(); 474 break; 475 default: 476 __ypexclude_add(_pw_passwd.pw_name + 1); 477 break; 478 } 479 goto again; 480 } 481 } 482 #endif 483 return &_pw_passwd; 484 } 485 return (struct passwd *)NULL; 486 } 487 488 #ifdef YP 489 490 /* 491 * See if the YP token is in the database. Only works if pwd_mkdb knows 492 * about the token. 493 */ 494 static int 495 __has_yppw() 496 { 497 DBT key, data; 498 DBT pkey, pdata; 499 int len; 500 char bf[_PW_NAME_LEN + 1]; 501 502 key.data = (u_char *)_PW_YPTOKEN; 503 key.size = strlen(_PW_YPTOKEN); 504 505 /* Pre-token database support. */ 506 bf[0] = _PW_KEYBYNAME; 507 len = strlen("+"); 508 bcopy("+", bf + 1, MIN(len, _PW_NAME_LEN)); 509 pkey.data = (u_char *)bf; 510 pkey.size = MIN(len, _PW_NAME_LEN) + 1; 511 512 if ((_pw_db->get)(_pw_db, &key, &data, 0) && 513 (_pw_db->get)(_pw_db, &pkey, &pdata, 0)) 514 return (0); /* No YP. */ 515 return (1); 516 } 517 518 /* 519 * See if there's a FreeBSD-style master.passwd map set. From the FreeBSD 520 * libc code. 521 */ 522 static int 523 __has_ypmaster() 524 { 525 int keylen, resultlen; 526 char *key, *result; 527 static int checked = -1; 528 static uid_t saved_uid, saved_euid; 529 uid_t uid = getuid(), euid = geteuid(); 530 531 /* 532 * Do not recheck IFF the saved UID and the saved 533 * EUID are the same. In all other cases, recheck. 534 */ 535 if (checked != -1 && saved_uid == uid && saved_euid == euid) 536 return (checked); 537 538 if (euid != 0) { 539 saved_uid = uid; 540 saved_euid = euid; 541 checked = 0; 542 return (checked); 543 } 544 545 if (!__ypdomain) { 546 if (_yp_check(&__ypdomain) == 0) { 547 saved_uid = uid; 548 saved_euid = euid; 549 checked = 0; 550 return (checked); /* No domain. */ 551 } 552 } 553 554 if (yp_first(__ypdomain, "master.passwd.byname", 555 &key, &keylen, &result, &resultlen)) { 556 saved_uid = uid; 557 saved_euid = euid; 558 checked = 0; 559 return (checked); 560 } 561 free (result); 562 563 saved_uid = uid; 564 saved_euid = euid; 565 checked = 1; 566 return (checked); 567 } 568 #endif 569 570 struct passwd * 571 getpwnam(name) 572 const char *name; 573 { 574 DBT key; 575 int len, rval; 576 char bf[_PW_NAME_LEN + 1]; 577 578 if (!_pw_db && !__initdb()) 579 return ((struct passwd *)NULL); 580 581 #ifdef YP 582 /* 583 * If YP is active, we must sequence through the passwd file 584 * in sequence. 585 */ 586 if (__has_yppw()) { 587 int r; 588 int s = -1; 589 const char *host, *user, *dom; 590 591 for (_pw_keynum=1; _pw_keynum; _pw_keynum++) { 592 bf[0] = _PW_KEYBYNUM; 593 bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum)); 594 key.data = (u_char *)bf; 595 key.size = sizeof(_pw_keynum) + 1; 596 if (__hashpw(&key) == 0) 597 break; 598 switch (_pw_passwd.pw_name[0]) { 599 case '+': 600 if (!__ypdomain) { 601 if (_yp_check(&__ypdomain) == 0) { 602 continue; 603 } 604 } 605 /* save the prototype */ 606 __ypproto_set(); 607 608 switch (_pw_passwd.pw_name[1]) { 609 case '\0': 610 if (__ypcurrent) { 611 free(__ypcurrent); 612 __ypcurrent = NULL; 613 } 614 r = yp_match(__ypdomain, 615 (PASSWD_BYNAME), 616 name, strlen(name), 617 &__ypcurrent, &__ypcurrentlen); 618 if (r != 0) { 619 if (__ypcurrent) 620 free(__ypcurrent); 621 __ypcurrent = NULL; 622 continue; 623 } 624 break; 625 case '@': 626 pwnam_netgrp: 627 if (__ypcurrent) { 628 free(__ypcurrent); 629 __ypcurrent = NULL; 630 } 631 if (s == -1) /* first time */ 632 setnetgrent(_pw_passwd.pw_name + 2); 633 s = getnetgrent(&host, &user, &dom); 634 if (s == 0) { /* end of group */ 635 endnetgrent(); 636 s = -1; 637 continue; 638 } else { 639 if (user && *user) { 640 r = yp_match(__ypdomain, 641 (PASSWD_BYNAME), 642 user, strlen(user), 643 &__ypcurrent, 644 &__ypcurrentlen); 645 } else 646 goto pwnam_netgrp; 647 if (r != 0) { 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_passwd.pw_name + 1; 666 r = yp_match(__ypdomain, 667 (PASSWD_BYNAME), 668 user, strlen(user), 669 &__ypcurrent, 670 &__ypcurrentlen); 671 if (r != 0) { 672 if (__ypcurrent) 673 free(__ypcurrent); 674 __ypcurrent = NULL; 675 continue; 676 } 677 break; 678 } 679 bcopy(__ypcurrent, __ypline, __ypcurrentlen); 680 __ypline[__ypcurrentlen] = '\0'; 681 if (__ypparse(&_pw_passwd, __ypline) 682 || __ypexclude_is(_pw_passwd.pw_name)) { 683 if (s == 1) /* inside netgrp */ 684 goto pwnam_netgrp; 685 continue; 686 } 687 break; 688 case '-': 689 /* attempted exclusion */ 690 switch (_pw_passwd.pw_name[1]) { 691 case '\0': 692 break; 693 case '@': 694 setnetgrent(_pw_passwd.pw_name + 2); 695 while (getnetgrent(&host, &user, &dom)) { 696 if (user && *user) 697 __ypexclude_add(user); 698 } 699 endnetgrent(); 700 break; 701 default: 702 __ypexclude_add(_pw_passwd.pw_name + 1); 703 break; 704 } 705 break; 706 } 707 if (strcmp(_pw_passwd.pw_name, name) == 0) { 708 if (!_pw_stayopen) { 709 (void)(_pw_db->close)(_pw_db); 710 _pw_db = (DB *)NULL; 711 } 712 __ypexclude_free(); 713 __ypproto = (struct passwd *)NULL; 714 return &_pw_passwd; 715 } 716 if (s == 1) /* inside netgrp */ 717 goto pwnam_netgrp; 718 continue; 719 } 720 if (!_pw_stayopen) { 721 (void)(_pw_db->close)(_pw_db); 722 _pw_db = (DB *)NULL; 723 } 724 __ypexclude_free(); 725 __ypproto = (struct passwd *)NULL; 726 return (struct passwd *)NULL; 727 } 728 #endif /* YP */ 729 730 bf[0] = _PW_KEYBYNAME; 731 len = strlen(name); 732 if (len > _PW_NAME_LEN) 733 rval = 0; 734 else { 735 bcopy(name, bf + 1, MIN(len, _PW_NAME_LEN)); 736 key.data = (u_char *)bf; 737 key.size = MIN(len, _PW_NAME_LEN) + 1; 738 rval = __hashpw(&key); 739 } 740 741 if (!_pw_stayopen) { 742 (void)(_pw_db->close)(_pw_db); 743 _pw_db = (DB *)NULL; 744 } 745 return (rval ? &_pw_passwd : (struct passwd *)NULL); 746 } 747 748 struct passwd * 749 getpwuid(uid_t uid) 750 { 751 DBT key; 752 char bf[sizeof(_pw_keynum) + 1]; 753 uid_t keyuid; 754 int rval; 755 756 if (!_pw_db && !__initdb()) 757 return ((struct passwd *)NULL); 758 759 #ifdef YP 760 /* 761 * If YP is active, we must sequence through the passwd file 762 * in sequence. 763 */ 764 if (__has_yppw()) { 765 char uidbuf[20]; 766 int r; 767 int s = -1; 768 const char *host, *user, *dom; 769 770 snprintf(uidbuf, sizeof uidbuf, "%u", uid); 771 for (_pw_keynum=1; _pw_keynum; _pw_keynum++) { 772 bf[0] = _PW_KEYBYNUM; 773 bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum)); 774 key.data = (u_char *)bf; 775 key.size = sizeof(_pw_keynum) + 1; 776 if (__hashpw(&key) == 0) 777 break; 778 switch (_pw_passwd.pw_name[0]) { 779 case '+': 780 if (!__ypdomain) { 781 if (_yp_check(&__ypdomain) == 0) { 782 continue; 783 } 784 } 785 /* save the prototype */ 786 __ypproto_set(); 787 788 switch (_pw_passwd.pw_name[1]) { 789 case '\0': 790 if (__ypcurrent) { 791 free(__ypcurrent); 792 __ypcurrent = NULL; 793 } 794 r = yp_match(__ypdomain, (PASSWD_BYUID), 795 uidbuf, strlen(uidbuf), 796 &__ypcurrent, &__ypcurrentlen); 797 if (r != 0) { 798 if (__ypcurrent) 799 free(__ypcurrent); 800 __ypcurrent = NULL; 801 continue; 802 } 803 break; 804 case '@': 805 pwuid_netgrp: 806 if (__ypcurrent) { 807 free(__ypcurrent); 808 __ypcurrent = NULL; 809 } 810 if (s == -1) /* first time */ 811 setnetgrent(_pw_passwd.pw_name + 2); 812 s = getnetgrent(&host, &user, &dom); 813 if (s == 0) { /* end of group */ 814 endnetgrent(); 815 s = -1; 816 continue; 817 } else { 818 if (user && *user) { 819 r = yp_match(__ypdomain, 820 (PASSWD_BYNAME), 821 user, strlen(user), 822 &__ypcurrent, 823 &__ypcurrentlen); 824 } else 825 goto pwuid_netgrp; 826 if (r != 0) { 827 if (__ypcurrent) 828 free(__ypcurrent); 829 __ypcurrent = NULL; 830 /* 831 * just because this 832 * user is bad, doesn't 833 * mean they all are. 834 */ 835 goto pwuid_netgrp; 836 } 837 } 838 break; 839 default: 840 if (__ypcurrent) { 841 free(__ypcurrent); 842 __ypcurrent = NULL; 843 } 844 user = _pw_passwd.pw_name + 1; 845 r = yp_match(__ypdomain, 846 (PASSWD_BYNAME), 847 user, strlen(user), 848 &__ypcurrent, 849 &__ypcurrentlen); 850 if (r != 0) { 851 if (__ypcurrent) 852 free(__ypcurrent); 853 __ypcurrent = NULL; 854 continue; 855 } 856 break; 857 } 858 bcopy(__ypcurrent, __ypline, __ypcurrentlen); 859 __ypline[__ypcurrentlen] = '\0'; 860 if (__ypparse(&_pw_passwd, __ypline) 861 || __ypexclude_is(_pw_passwd.pw_name)) { 862 if (s == 1) /* inside netgroup */ 863 goto pwuid_netgrp; 864 continue; 865 } 866 break; 867 case '-': 868 /* attempted exclusion */ 869 switch (_pw_passwd.pw_name[1]) { 870 case '\0': 871 break; 872 case '@': 873 setnetgrent(_pw_passwd.pw_name + 2); 874 while (getnetgrent(&host, &user, &dom)) { 875 if (user && *user) 876 __ypexclude_add(user); 877 } 878 endnetgrent(); 879 break; 880 default: 881 __ypexclude_add(_pw_passwd.pw_name + 1); 882 break; 883 } 884 break; 885 } 886 if (_pw_passwd.pw_uid == uid) { 887 if (!_pw_stayopen) { 888 (void)(_pw_db->close)(_pw_db); 889 _pw_db = (DB *)NULL; 890 } 891 __ypexclude_free(); 892 __ypproto = NULL; 893 return &_pw_passwd; 894 } 895 if (s == 1) /* inside netgroup */ 896 goto pwuid_netgrp; 897 continue; 898 } 899 if (!_pw_stayopen) { 900 (void)(_pw_db->close)(_pw_db); 901 _pw_db = (DB *)NULL; 902 } 903 __ypexclude_free(); 904 __ypproto = (struct passwd *)NULL; 905 return (struct passwd *)NULL; 906 } 907 #endif /* YP */ 908 909 bf[0] = _PW_KEYBYUID; 910 keyuid = uid; 911 bcopy(&keyuid, bf + 1, sizeof(keyuid)); 912 key.data = (u_char *)bf; 913 key.size = sizeof(keyuid) + 1; 914 rval = __hashpw(&key); 915 916 if (!_pw_stayopen) { 917 (void)(_pw_db->close)(_pw_db); 918 _pw_db = (DB *)NULL; 919 } 920 return (rval ? &_pw_passwd : (struct passwd *)NULL); 921 } 922 923 int 924 setpassent(stayopen) 925 int stayopen; 926 { 927 _pw_keynum = 0; 928 _pw_stayopen = stayopen; 929 #ifdef YP 930 __ypmode = YPMODE_NONE; 931 if (__ypcurrent) 932 free(__ypcurrent); 933 __ypcurrent = NULL; 934 __ypexclude_free(); 935 __ypproto = (struct passwd *)NULL; 936 #endif 937 return (1); 938 } 939 940 void 941 setpwent() 942 { 943 (void) setpassent(0); 944 } 945 946 void 947 endpwent() 948 { 949 _pw_keynum = 0; 950 if (_pw_db) { 951 (void)(_pw_db->close)(_pw_db); 952 _pw_db = (DB *)NULL; 953 } 954 #ifdef YP 955 __ypmode = YPMODE_NONE; 956 if (__ypcurrent) 957 free(__ypcurrent); 958 __ypcurrent = NULL; 959 __ypexclude_free(); 960 __ypproto = (struct passwd *)NULL; 961 #endif 962 } 963 964 static int 965 __initdb() 966 { 967 static int warned; 968 969 #ifdef YP 970 __ypmode = YPMODE_NONE; 971 __getpwent_has_yppw = -1; 972 #endif 973 if ((_pw_db = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) || 974 (_pw_db = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL))) 975 return (1); 976 if (!warned) 977 syslog(LOG_ERR, "%s: %m", _PATH_MP_DB); 978 warned = 1; 979 return (0); 980 } 981 982 static int 983 __hashpw(key) 984 DBT *key; 985 { 986 register char *p, *t; 987 static u_int max; 988 static char *line; 989 DBT data; 990 991 if ((_pw_db->get)(_pw_db, key, &data, 0)) 992 return (0); 993 p = (char *)data.data; 994 if (data.size > max) { 995 char *nline; 996 997 max = data.size + 256; 998 nline = realloc(line, max); 999 if (nline == NULL) { 1000 if (line) 1001 free(line); 1002 line = NULL; 1003 max = 0; 1004 return 0; 1005 } 1006 line = nline; 1007 } 1008 1009 t = line; 1010 #define EXPAND(e) e = t; while ((*t++ = *p++)); 1011 EXPAND(_pw_passwd.pw_name); 1012 EXPAND(_pw_passwd.pw_passwd); 1013 bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int)); 1014 p += sizeof(int); 1015 bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int)); 1016 p += sizeof(int); 1017 bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t)); 1018 p += sizeof(time_t); 1019 EXPAND(_pw_passwd.pw_class); 1020 EXPAND(_pw_passwd.pw_gecos); 1021 EXPAND(_pw_passwd.pw_dir); 1022 EXPAND(_pw_passwd.pw_shell); 1023 bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t)); 1024 p += sizeof(time_t); 1025 1026 /* See if there's any data left. If so, read in flags. */ 1027 if (data.size > (p - (char *)data.data)) { 1028 bcopy(p, (char *)&_pw_flags, sizeof(int)); 1029 p += sizeof(int); 1030 } else 1031 _pw_flags = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */ 1032 1033 return (1); 1034 } 1035