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. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by the University of 17 * California, Berkeley and its contributors. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #if defined(LIBC_SCCS) && !defined(lint) 36 static char rcsid[] = "$OpenBSD: getpwent.c,v 1.22 2001/07/10 16:46:25 deraadt Exp $"; 37 #endif /* LIBC_SCCS and not lint */ 38 39 #include <sys/param.h> 40 #include <fcntl.h> 41 #include <db.h> 42 #include <syslog.h> 43 #include <pwd.h> 44 #include <errno.h> 45 #include <unistd.h> 46 #include <stdlib.h> 47 #include <string.h> 48 #include <limits.h> 49 #include <netgroup.h> 50 #ifdef YP 51 #include <machine/param.h> 52 #include <stdio.h> 53 #include <rpc/rpc.h> 54 #include <rpcsvc/yp.h> 55 #include <rpcsvc/ypclnt.h> 56 #include "ypinternal.h" 57 #endif 58 59 static struct passwd _pw_passwd; /* password structure */ 60 static DB *_pw_db; /* password database */ 61 static int _pw_keynum; /* key counter */ 62 static int _pw_stayopen; /* keep fd's open */ 63 static int _pw_flags; /* password flags */ 64 static int __hashpw __P((DBT *)); 65 static int __initdb __P((void)); 66 67 #ifdef YP 68 enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_USER, YPMODE_NETGRP }; 69 static enum _ypmode __ypmode; 70 71 static char *__ypcurrent, *__ypdomain; 72 static int __ypcurrentlen; 73 static struct passwd *__ypproto = (struct passwd *)NULL; 74 static int __ypflags; 75 static char __ypline[1024]; 76 static long __yppbuf[1024 / sizeof(long)]; 77 static int __yp_override_passwd = 0; 78 79 static int __has_yppw __P((void)); 80 static int __has_ypmaster __P((void)); 81 82 static int __ypexclude_add __P((const char *)); 83 static int __ypexclude_is __P((const char *)); 84 static void __ypexclude_free __P((void)); 85 static void __ypproto_set __P((void)); 86 87 /* macro for deciding which YP maps to use. */ 88 #define PASSWD_BYNAME \ 89 __has_ypmaster() ? "master.passwd.byname" : "passwd.byname" 90 #define PASSWD_BYUID \ 91 __has_ypmaster() ? "master.passwd.byuid" : "passwd.byuid" 92 93 struct _ypexclude { 94 const char *name; 95 struct _ypexclude *next; 96 }; 97 static struct _ypexclude *__ypexclude = (struct _ypexclude *)NULL; 98 99 /* 100 * Using DB for this just wastes too damn much memory. 101 */ 102 static int 103 __ypexclude_add(name) 104 const char *name; 105 { 106 struct _ypexclude *new; 107 108 if (name[0] == '\0') /* skip */ 109 return (0); 110 111 new = (struct _ypexclude *)malloc(sizeof(struct _ypexclude)); 112 if (new == (struct _ypexclude *)NULL) 113 return (1); 114 new->name = strdup(name); 115 if (new->name == (char *)NULL) { 116 free(new); 117 return (1); 118 } 119 120 new->next = __ypexclude; 121 __ypexclude = new; 122 123 return (0); 124 } 125 126 static int 127 __ypexclude_is(name) 128 const char *name; 129 { 130 struct _ypexclude *curr; 131 132 for (curr = __ypexclude; curr != (struct _ypexclude *)NULL; 133 curr = curr->next) { 134 if (strcmp(curr->name, name) == 0) 135 return (1); /* excluded */ 136 } 137 return (0); 138 } 139 140 static void 141 __ypexclude_free() 142 { 143 struct _ypexclude *curr, *next; 144 145 for (curr = __ypexclude; curr != (struct _ypexclude *)NULL; 146 curr = next) { 147 next = curr->next; 148 149 free((void *)curr->name); 150 free(curr); 151 } 152 __ypexclude = (struct _ypexclude *)NULL; 153 } 154 155 static void 156 __ypproto_set() 157 { 158 register char *ptr; 159 register struct passwd *pw = &_pw_passwd; 160 161 /* make this the new prototype */ 162 ptr = (char *)__yppbuf; 163 164 /* first allocate the struct. */ 165 __ypproto = (struct passwd *)ptr; 166 ptr += sizeof(struct passwd); 167 168 /* name */ 169 if (pw->pw_name && (pw->pw_name)[0]) { 170 ptr = (char *)ALIGN(ptr); 171 bcopy(pw->pw_name, ptr, strlen(pw->pw_name) + 1); 172 __ypproto->pw_name = ptr; 173 ptr += (strlen(pw->pw_name) + 1); 174 } else 175 __ypproto->pw_name = (char *)NULL; 176 177 /* password */ 178 if (pw->pw_passwd && (pw->pw_passwd)[0]) { 179 ptr = (char *)ALIGN(ptr); 180 bcopy(pw->pw_passwd, ptr, strlen(pw->pw_passwd) + 1); 181 __ypproto->pw_passwd = ptr; 182 ptr += (strlen(pw->pw_passwd) + 1); 183 } else 184 __ypproto->pw_passwd = (char *)NULL; 185 186 /* uid */ 187 __ypproto->pw_uid = pw->pw_uid; 188 189 /* gid */ 190 __ypproto->pw_gid = pw->pw_gid; 191 192 /* change (ignored anyway) */ 193 __ypproto->pw_change = pw->pw_change; 194 195 /* class (ignored anyway) */ 196 __ypproto->pw_class = ""; 197 198 /* gecos */ 199 if (pw->pw_gecos && (pw->pw_gecos)[0]) { 200 ptr = (char *)ALIGN(ptr); 201 bcopy(pw->pw_gecos, ptr, strlen(pw->pw_gecos) + 1); 202 __ypproto->pw_gecos = ptr; 203 ptr += (strlen(pw->pw_gecos) + 1); 204 } else 205 __ypproto->pw_gecos = (char *)NULL; 206 207 /* dir */ 208 if (pw->pw_dir && (pw->pw_dir)[0]) { 209 ptr = (char *)ALIGN(ptr); 210 bcopy(pw->pw_dir, ptr, strlen(pw->pw_dir) + 1); 211 __ypproto->pw_dir = ptr; 212 ptr += (strlen(pw->pw_dir) + 1); 213 } else 214 __ypproto->pw_dir = (char *)NULL; 215 216 /* shell */ 217 if (pw->pw_shell && (pw->pw_shell)[0]) { 218 ptr = (char *)ALIGN(ptr); 219 bcopy(pw->pw_shell, ptr, strlen(pw->pw_shell) + 1); 220 __ypproto->pw_shell = ptr; 221 ptr += (strlen(pw->pw_shell) + 1); 222 } else 223 __ypproto->pw_shell = (char *)NULL; 224 225 /* expire (ignored anyway) */ 226 __ypproto->pw_expire = pw->pw_expire; 227 228 /* flags */ 229 __ypflags = _pw_flags; 230 } 231 232 static int 233 __ypparse(pw, s) 234 struct passwd *pw; 235 char *s; 236 { 237 char *bp, *cp, *endp; 238 u_long ul; 239 int count = 0; 240 241 /* count the colons. */ 242 bp = s; 243 while (*bp != '\0') { 244 if (*bp++ == ':') 245 count++; 246 } 247 248 /* since this is currently using strsep(), parse it first */ 249 bp = s; 250 pw->pw_name = strsep(&bp, ":\n"); 251 pw->pw_passwd = strsep(&bp, ":\n"); 252 if (!(cp = strsep(&bp, ":\n"))) 253 return 1; 254 ul = strtoul(cp, &endp, 10); 255 if (endp == cp || *endp != '\0' || ul >= UID_MAX) 256 return 1; 257 pw->pw_uid = (uid_t)ul; 258 if (!(cp = strsep(&bp, ":\n"))) 259 return 1; 260 ul = strtoul(cp, &endp, 10); 261 if (endp == cp || *endp != '\0' || ul >= GID_MAX) 262 return 1; 263 pw->pw_gid = (gid_t)ul; 264 if (count == 9) { 265 long l; 266 267 /* If the ypserv gave us all the fields, use them. */ 268 pw->pw_class = strsep(&bp, ":\n"); 269 if (!(cp = strsep(&bp, ":\n"))) 270 return 1; 271 l = strtol(cp, &endp, 10); 272 if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN) 273 return 1; 274 pw->pw_change = (time_t)l; 275 if (!(cp = strsep(&bp, ":\n"))) 276 return 1; 277 l = strtol(cp, &endp, 10); 278 if (endp == cp || *endp != '\0' || l >= INT_MAX || l <= INT_MIN) 279 return 1; 280 pw->pw_expire = (time_t)l; 281 } else { 282 /* ..else it is a normal ypserv. */ 283 pw->pw_class = ""; 284 pw->pw_change = 0; 285 pw->pw_expire = 0; 286 } 287 pw->pw_gecos = strsep(&bp, ":\n"); 288 pw->pw_dir = strsep(&bp, ":\n"); 289 pw->pw_shell = strsep(&bp, ":\n"); 290 291 /* now let the prototype override, if set. */ 292 if (__ypproto != (struct passwd *)NULL) { 293 if (__yp_override_passwd && __ypproto->pw_passwd != (char *)NULL) 294 pw->pw_passwd = __ypproto->pw_passwd; 295 if (!(__ypflags & _PASSWORD_NOUID)) 296 pw->pw_uid = __ypproto->pw_uid; 297 if (!(__ypflags & _PASSWORD_NOGID)) 298 pw->pw_gid = __ypproto->pw_gid; 299 if (__ypproto->pw_gecos != (char *)NULL) 300 pw->pw_gecos = __ypproto->pw_gecos; 301 if (__ypproto->pw_dir != (char *)NULL) 302 pw->pw_dir = __ypproto->pw_dir; 303 if (__ypproto->pw_shell != (char *)NULL) 304 pw->pw_shell = __ypproto->pw_shell; 305 } 306 return 0; 307 } 308 #endif 309 310 #ifdef YP 311 static int __getpwent_has_yppw = -1; 312 #endif 313 314 struct passwd * 315 getpwent() 316 { 317 DBT key; 318 char bf[sizeof(_pw_keynum) + 1]; 319 #ifdef YP 320 static char *name = (char *)NULL; 321 const char *user, *host, *dom; 322 #endif 323 324 if (!_pw_db && !__initdb()) 325 return ((struct passwd *)NULL); 326 327 #ifdef YP 328 if (__getpwent_has_yppw == -1) 329 __getpwent_has_yppw = __has_yppw(); 330 331 again: 332 if (__getpwent_has_yppw && (__ypmode != YPMODE_NONE)) { 333 char *key, *data; 334 int keylen, datalen; 335 int r, s; 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, (PASSWD_BYNAME), 347 __ypcurrent, __ypcurrentlen, 348 &key, &keylen, &data, &datalen); 349 free(__ypcurrent); 350 if (r != 0) { 351 __ypcurrent = NULL; 352 __ypmode = YPMODE_NONE; 353 if (data) 354 free(data); 355 data = NULL; 356 goto again; 357 } 358 __ypcurrent = key; 359 __ypcurrentlen = keylen; 360 bcopy(data, __ypline, datalen); 361 free(data); 362 data = NULL; 363 } else { 364 r = yp_first(__ypdomain, (PASSWD_BYNAME), 365 &__ypcurrent, &__ypcurrentlen, 366 &data, &datalen); 367 if (r != 0) { 368 __ypmode = YPMODE_NONE; 369 if (data) 370 free(data); 371 goto again; 372 } 373 bcopy(data, __ypline, datalen); 374 free(data); 375 data = NULL; 376 } 377 break; 378 case YPMODE_NETGRP: 379 s = getnetgrent(&host, &user, &dom); 380 if (s == 0) { /* end of group */ 381 endnetgrent(); 382 __ypmode = YPMODE_NONE; 383 goto again; 384 } 385 if (user && *user) { 386 r = yp_match(__ypdomain, (PASSWD_BYNAME), 387 user, strlen(user), 388 &data, &datalen); 389 } else 390 goto again; 391 if (r != 0) { 392 /* 393 * if the netgroup is invalid, keep looking 394 * as there may be valid users later on. 395 */ 396 if (data) 397 free(data); 398 goto again; 399 } 400 bcopy(data, __ypline, datalen); 401 free(data); 402 data = (char *)NULL; 403 break; 404 case YPMODE_USER: 405 if (name != (char *)NULL) { 406 r = yp_match(__ypdomain, (PASSWD_BYNAME), 407 name, strlen(name), 408 &data, &datalen); 409 __ypmode = YPMODE_NONE; 410 free(name); 411 name = (char *)NULL; 412 if (r != 0) { 413 if (data) 414 free(data); 415 goto again; 416 } 417 bcopy(data, __ypline, datalen); 418 free(data); 419 data = (char *)NULL; 420 } else { /* XXX */ 421 __ypmode = YPMODE_NONE; 422 goto again; 423 } 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 #ifdef __STDC__ 750 getpwuid(uid_t uid) 751 #else 752 getpwuid(uid) 753 uid_t uid; 754 #endif 755 { 756 DBT key; 757 char bf[sizeof(_pw_keynum) + 1]; 758 uid_t keyuid; 759 int rval; 760 761 if (!_pw_db && !__initdb()) 762 return ((struct passwd *)NULL); 763 764 #ifdef YP 765 /* 766 * If YP is active, we must sequence through the passwd file 767 * in sequence. 768 */ 769 if (__has_yppw()) { 770 char uidbuf[20]; 771 int r; 772 int s = -1; 773 const char *host, *user, *dom; 774 775 sprintf(uidbuf, "%u", uid); 776 for (_pw_keynum=1; _pw_keynum; _pw_keynum++) { 777 bf[0] = _PW_KEYBYNUM; 778 bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum)); 779 key.data = (u_char *)bf; 780 key.size = sizeof(_pw_keynum) + 1; 781 if (__hashpw(&key) == 0) 782 break; 783 switch (_pw_passwd.pw_name[0]) { 784 case '+': 785 if (!__ypdomain) { 786 if (_yp_check(&__ypdomain) == 0) { 787 continue; 788 } 789 } 790 /* save the prototype */ 791 __ypproto_set(); 792 793 switch (_pw_passwd.pw_name[1]) { 794 case '\0': 795 if (__ypcurrent) { 796 free(__ypcurrent); 797 __ypcurrent = NULL; 798 } 799 r = yp_match(__ypdomain, (PASSWD_BYUID), 800 uidbuf, strlen(uidbuf), 801 &__ypcurrent, &__ypcurrentlen); 802 if (r != 0) { 803 if (__ypcurrent) 804 free(__ypcurrent); 805 __ypcurrent = NULL; 806 continue; 807 } 808 break; 809 case '@': 810 pwuid_netgrp: 811 if (__ypcurrent) { 812 free(__ypcurrent); 813 __ypcurrent = NULL; 814 } 815 if (s == -1) /* first time */ 816 setnetgrent(_pw_passwd.pw_name + 2); 817 s = getnetgrent(&host, &user, &dom); 818 if (s == 0) { /* end of group */ 819 endnetgrent(); 820 s = -1; 821 continue; 822 } else { 823 if (user && *user) { 824 r = yp_match(__ypdomain, 825 (PASSWD_BYNAME), 826 user, strlen(user), 827 &__ypcurrent, 828 &__ypcurrentlen); 829 } else 830 goto pwuid_netgrp; 831 if (r != 0) { 832 if (__ypcurrent) 833 free(__ypcurrent); 834 __ypcurrent = NULL; 835 /* 836 * just because this 837 * user is bad, doesn't 838 * mean they all are. 839 */ 840 goto pwuid_netgrp; 841 } 842 } 843 break; 844 default: 845 if (__ypcurrent) { 846 free(__ypcurrent); 847 __ypcurrent = NULL; 848 } 849 user = _pw_passwd.pw_name + 1; 850 r = yp_match(__ypdomain, 851 (PASSWD_BYNAME), 852 user, strlen(user), 853 &__ypcurrent, 854 &__ypcurrentlen); 855 if (r != 0) { 856 if (__ypcurrent) 857 free(__ypcurrent); 858 __ypcurrent = NULL; 859 continue; 860 } 861 break; 862 } 863 bcopy(__ypcurrent, __ypline, __ypcurrentlen); 864 __ypline[__ypcurrentlen] = '\0'; 865 if (__ypparse(&_pw_passwd, __ypline) 866 || __ypexclude_is(_pw_passwd.pw_name)) { 867 if (s == 1) /* inside netgroup */ 868 goto pwuid_netgrp; 869 continue; 870 } 871 break; 872 case '-': 873 /* attempted exclusion */ 874 switch (_pw_passwd.pw_name[1]) { 875 case '\0': 876 break; 877 case '@': 878 setnetgrent(_pw_passwd.pw_name + 2); 879 while (getnetgrent(&host, &user, &dom)) { 880 if (user && *user) 881 __ypexclude_add(user); 882 } 883 endnetgrent(); 884 break; 885 default: 886 __ypexclude_add(_pw_passwd.pw_name + 1); 887 break; 888 } 889 break; 890 } 891 if (_pw_passwd.pw_uid == uid) { 892 if (!_pw_stayopen) { 893 (void)(_pw_db->close)(_pw_db); 894 _pw_db = (DB *)NULL; 895 } 896 __ypexclude_free(); 897 __ypproto = NULL; 898 return &_pw_passwd; 899 } 900 if (s == 1) /* inside netgroup */ 901 goto pwuid_netgrp; 902 continue; 903 } 904 if (!_pw_stayopen) { 905 (void)(_pw_db->close)(_pw_db); 906 _pw_db = (DB *)NULL; 907 } 908 __ypexclude_free(); 909 __ypproto = (struct passwd *)NULL; 910 return (struct passwd *)NULL; 911 } 912 #endif /* YP */ 913 914 bf[0] = _PW_KEYBYUID; 915 keyuid = uid; 916 bcopy(&keyuid, bf + 1, sizeof(keyuid)); 917 key.data = (u_char *)bf; 918 key.size = sizeof(keyuid) + 1; 919 rval = __hashpw(&key); 920 921 if (!_pw_stayopen) { 922 (void)(_pw_db->close)(_pw_db); 923 _pw_db = (DB *)NULL; 924 } 925 return (rval ? &_pw_passwd : (struct passwd *)NULL); 926 } 927 928 int 929 setpassent(stayopen) 930 int stayopen; 931 { 932 _pw_keynum = 0; 933 _pw_stayopen = stayopen; 934 #ifdef YP 935 __ypmode = YPMODE_NONE; 936 if (__ypcurrent) 937 free(__ypcurrent); 938 __ypcurrent = NULL; 939 __ypexclude_free(); 940 __ypproto = (struct passwd *)NULL; 941 #endif 942 return (1); 943 } 944 945 void 946 setpwent() 947 { 948 (void) setpassent(0); 949 } 950 951 void 952 endpwent() 953 { 954 _pw_keynum = 0; 955 if (_pw_db) { 956 (void)(_pw_db->close)(_pw_db); 957 _pw_db = (DB *)NULL; 958 } 959 #ifdef YP 960 __ypmode = YPMODE_NONE; 961 if (__ypcurrent) 962 free(__ypcurrent); 963 __ypcurrent = NULL; 964 __ypexclude_free(); 965 __ypproto = (struct passwd *)NULL; 966 #endif 967 } 968 969 static int 970 __initdb() 971 { 972 static int warned; 973 char *p; 974 975 #ifdef YP 976 __ypmode = YPMODE_NONE; 977 __getpwent_has_yppw = -1; 978 #endif 979 p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB; 980 _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL); 981 if (_pw_db) 982 return (1); 983 if (!warned) 984 syslog(LOG_ERR, "%s: %m", p); 985 warned = 1; 986 return (0); 987 } 988 989 static int 990 __hashpw(key) 991 DBT *key; 992 { 993 register char *p, *t; 994 static u_int max; 995 static char *line; 996 DBT data; 997 998 if ((_pw_db->get)(_pw_db, key, &data, 0)) 999 return (0); 1000 p = (char *)data.data; 1001 if (data.size > max) { 1002 char *nline; 1003 1004 max = data.size + 256; 1005 nline = realloc(line, max); 1006 if (nline == NULL) { 1007 if (line) 1008 free(line); 1009 line = NULL; 1010 return 0; 1011 } 1012 line = nline; 1013 } 1014 1015 t = line; 1016 #define EXPAND(e) e = t; while ((*t++ = *p++)); 1017 EXPAND(_pw_passwd.pw_name); 1018 EXPAND(_pw_passwd.pw_passwd); 1019 bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int)); 1020 p += sizeof(int); 1021 bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int)); 1022 p += sizeof(int); 1023 bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t)); 1024 p += sizeof(time_t); 1025 EXPAND(_pw_passwd.pw_class); 1026 EXPAND(_pw_passwd.pw_gecos); 1027 EXPAND(_pw_passwd.pw_dir); 1028 EXPAND(_pw_passwd.pw_shell); 1029 bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t)); 1030 p += sizeof(time_t); 1031 1032 /* See if there's any data left. If so, read in flags. */ 1033 if (data.size > (p - (char *)data.data)) { 1034 bcopy(p, (char *)&_pw_flags, sizeof(int)); 1035 p += sizeof(int); 1036 } else 1037 _pw_flags = _PASSWORD_NOUID|_PASSWORD_NOGID; /* default */ 1038 1039 return (1); 1040 } 1041