1 /* $NetBSD: getpwent.c,v 1.40.2.2 1999/04/27 22:09:45 perry Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1993 5 * The Regents of the University of California. All rights reserved. 6 * Portions Copyright (c) 1994, 1995, 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. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #include <sys/cdefs.h> 38 #if defined(LIBC_SCCS) && !defined(lint) 39 static const char *rcsid[] = 40 "$FreeBSD$"; 41 #endif /* LIBC_SCCS and not lint */ 42 43 #include <sys/param.h> 44 #include <fcntl.h> 45 #include <db.h> 46 #include <syslog.h> 47 #include <pwd.h> 48 #include <utmp.h> 49 #include <errno.h> 50 #include <unistd.h> 51 #include <stdlib.h> 52 #include <string.h> 53 #include <limits.h> 54 #include <nsswitch.h> 55 #ifdef HESIOD 56 #include <hesiod.h> 57 #endif 58 #ifdef YP 59 #include <machine/param.h> 60 #include <stdio.h> 61 #include <rpc/rpc.h> 62 #include <rpcsvc/yp_prot.h> 63 #include <rpcsvc/ypclnt.h> 64 #endif 65 66 extern void setnetgrent __P((char *)); 67 extern int getnetgrent __P((char **, char **, char **)); 68 extern int innetgr __P((const char *, const char *, const char *, const char *)); 69 70 #include "pw_scan.h" 71 72 #if defined(YP) || defined(HESIOD) 73 #define _PASSWD_COMPAT 74 #endif 75 76 /* 77 * The lookup techniques and data extraction code here must be kept 78 * in sync with that in `pwd_mkdb'. 79 */ 80 81 static struct passwd _pw_passwd = { "", "", 0, 0, 0, "", "", "", "", 0, 0 }; 82 static DB *_pw_db; /* password database */ 83 static int _pw_keynum; /* key counter. no more records if -1 */ 84 static int _pw_stayopen; /* keep fd's open */ 85 86 static int __hashpw __P((DBT *)); 87 static int __initdb __P((void)); 88 89 static const ns_src compatsrc[] = { 90 { NSSRC_COMPAT, NS_SUCCESS }, 91 { 0 } 92 }; 93 94 #ifdef YP 95 static char *__ypcurrent, *__ypdomain; 96 static int __ypcurrentlen; 97 static int _pw_ypdone; /* non-zero if no more yp records */ 98 #endif 99 100 #ifdef HESIOD 101 static int _pw_hesnum; /* hes counter. no more records if -1 */ 102 #endif 103 104 #ifdef _PASSWD_COMPAT 105 enum _pwmode { PWMODE_NONE, PWMODE_FULL, PWMODE_USER, PWMODE_NETGRP }; 106 static enum _pwmode __pwmode; 107 108 enum _ypmap { YPMAP_NONE, YPMAP_ADJUNCT, YPMAP_MASTER }; 109 110 static struct passwd *__pwproto = (struct passwd *)NULL; 111 static int __pwproto_flags; 112 static char line[1024]; 113 static long prbuf[1024 / sizeof(long)]; 114 static DB *__pwexclude = (DB *)NULL; 115 116 static int __pwexclude_add __P((const char *)); 117 static int __pwexclude_is __P((const char *)); 118 static void __pwproto_set __P((void)); 119 static int __ypmaptype __P((void)); 120 static int __pwparse __P((struct passwd *, char *)); 121 122 /* macros for deciding which YP maps to use. */ 123 #define PASSWD_BYNAME (__ypmaptype() == YPMAP_MASTER \ 124 ? "master.passwd.byname" : "passwd.byname") 125 #define PASSWD_BYUID (__ypmaptype() == YPMAP_MASTER \ 126 ? "master.passwd.byuid" : "passwd.byuid") 127 128 /* 129 * add a name to the compat mode exclude list 130 */ 131 static int 132 __pwexclude_add(name) 133 const char *name; 134 { 135 DBT key; 136 DBT data; 137 138 /* initialize the exclusion table if needed. */ 139 if(__pwexclude == (DB *)NULL) { 140 __pwexclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL); 141 if(__pwexclude == (DB *)NULL) 142 return 1; 143 } 144 145 /* set up the key */ 146 key.size = strlen(name); 147 /* LINTED key does not get modified */ 148 key.data = (char *)name; 149 150 /* data is nothing. */ 151 data.data = NULL; 152 data.size = 0; 153 154 /* store it */ 155 if((__pwexclude->put)(__pwexclude, &key, &data, 0) == -1) 156 return 1; 157 158 return 0; 159 } 160 161 /* 162 * test if a name is on the compat mode exclude list 163 */ 164 static int 165 __pwexclude_is(name) 166 const char *name; 167 { 168 DBT key; 169 DBT data; 170 171 if(__pwexclude == (DB *)NULL) 172 return 0; /* nothing excluded */ 173 174 /* set up the key */ 175 key.size = strlen(name); 176 /* LINTED key does not get modified */ 177 key.data = (char *)name; 178 179 if((__pwexclude->get)(__pwexclude, &key, &data, 0) == 0) 180 return 1; /* excluded */ 181 182 return 0; 183 } 184 185 /* 186 * Setup the compat mode prototype template that may be used in 187 * __pwparse. Only pw_passwd, pw_uid, pw_gid, pw_gecos, pw_dir, and 188 * pw_shell are used. The other fields are zero'd. 189 */ 190 static void 191 __pwproto_set() 192 { 193 char *ptr; 194 struct passwd *pw = &_pw_passwd; 195 196 /* make this the new prototype */ 197 ptr = (char *)(void *)prbuf; 198 199 /* first allocate the struct. */ 200 __pwproto = (struct passwd *)(void *)ptr; 201 ptr += sizeof(struct passwd); 202 memset(__pwproto, 0, sizeof(*__pwproto)); 203 204 __pwproto_flags = 0; 205 206 /* password */ 207 if(pw->pw_passwd && (pw->pw_passwd)[0]) { 208 ptr = (char *)ALIGN((u_long)ptr); 209 memmove(ptr, pw->pw_passwd, strlen(pw->pw_passwd) + 1); 210 __pwproto->pw_passwd = ptr; 211 ptr += (strlen(pw->pw_passwd) + 1); 212 __pwproto_flags |= _PWF_PASSWD; 213 } 214 215 /* uid, gid */ 216 if (pw->pw_fields & _PWF_UID) { 217 __pwproto->pw_uid = pw->pw_uid; 218 __pwproto_flags |= _PWF_UID; 219 } 220 if (pw->pw_fields & _PWF_GID) { 221 __pwproto->pw_gid = pw->pw_gid; 222 __pwproto_flags |= _PWF_GID; 223 } 224 225 /* gecos */ 226 if(pw->pw_gecos && (pw->pw_gecos)[0]) { 227 ptr = (char *)ALIGN((u_long)ptr); 228 memmove(ptr, pw->pw_gecos, strlen(pw->pw_gecos) + 1); 229 __pwproto->pw_gecos = ptr; 230 ptr += (strlen(pw->pw_gecos) + 1); 231 __pwproto_flags |= _PWF_GECOS; 232 } 233 234 /* dir */ 235 if(pw->pw_dir && (pw->pw_dir)[0]) { 236 ptr = (char *)ALIGN((u_long)ptr); 237 memmove(ptr, pw->pw_dir, strlen(pw->pw_dir) + 1); 238 __pwproto->pw_dir = ptr; 239 ptr += (strlen(pw->pw_dir) + 1); 240 __pwproto_flags |= _PWF_DIR; 241 } 242 243 /* shell */ 244 if(pw->pw_shell && (pw->pw_shell)[0]) { 245 ptr = (char *)ALIGN((u_long)ptr); 246 memmove(ptr, pw->pw_shell, strlen(pw->pw_shell) + 1); 247 __pwproto->pw_shell = ptr; 248 ptr += (strlen(pw->pw_shell) + 1); 249 __pwproto_flags |= _PWF_SHELL; 250 } 251 } 252 253 static int 254 __ypmaptype() 255 { 256 static int maptype = -1; 257 int order, r; 258 259 if (maptype != -1) 260 return (maptype); 261 262 maptype = YPMAP_NONE; 263 if (geteuid() != 0) 264 return (maptype); 265 266 if (!__ypdomain) { 267 if( _yp_check(&__ypdomain) == 0) 268 return (maptype); 269 } 270 271 r = yp_order(__ypdomain, "master.passwd.byname", &order); 272 if (r == 0) { 273 maptype = YPMAP_MASTER; 274 return (maptype); 275 } 276 277 /* 278 * NIS+ in YP compat mode doesn't support 279 * YPPROC_ORDER -- no point in continuing. 280 */ 281 if (r == YPERR_YPERR) 282 return (maptype); 283 284 /* master.passwd doesn't exist -- try passwd.adjunct */ 285 if (r == YPERR_MAP) { 286 r = yp_order(__ypdomain, "passwd.adjunct.byname", &order); 287 if (r == 0) 288 maptype = YPMAP_ADJUNCT; 289 return (maptype); 290 } 291 292 return (maptype); 293 } 294 295 /* 296 * parse a passwd file line (from NIS or HESIOD). 297 * assumed to be `old-style' if maptype != YPMAP_MASTER. 298 */ 299 static int 300 __pwparse(pw, s) 301 struct passwd *pw; 302 char *s; 303 { 304 static char adjunctpw[YPMAXRECORD + 2]; 305 int flags, maptype; 306 307 maptype = __ypmaptype(); 308 flags = 0; 309 if (maptype == YPMAP_MASTER) 310 flags |= _PWSCAN_MASTER; 311 if (! __pw_scan(s, pw, flags)) 312 return 1; 313 314 /* now let the prototype override, if set. */ 315 if(__pwproto != (struct passwd *)NULL) { 316 #ifdef PW_OVERRIDE_PASSWD 317 if(__pwproto_flags & _PWF_PASSWD) 318 pw->pw_passwd = __pwproto->pw_passwd; 319 #endif 320 if(__pwproto_flags & _PWF_UID) 321 pw->pw_uid = __pwproto->pw_uid; 322 if(__pwproto_flags & _PWF_GID) 323 pw->pw_gid = __pwproto->pw_gid; 324 if(__pwproto_flags & _PWF_GECOS) 325 pw->pw_gecos = __pwproto->pw_gecos; 326 if(__pwproto_flags & _PWF_DIR) 327 pw->pw_dir = __pwproto->pw_dir; 328 if(__pwproto_flags & _PWF_SHELL) 329 pw->pw_shell = __pwproto->pw_shell; 330 } 331 if ((maptype == YPMAP_ADJUNCT) && 332 (strstr(pw->pw_passwd, "##") != NULL)) { 333 char *data, *bp; 334 int datalen; 335 336 if (yp_match(__ypdomain, "passwd.adjunct.byname", pw->pw_name, 337 (int)strlen(pw->pw_name), &data, &datalen) == 0) { 338 if (datalen > sizeof(adjunctpw) - 1) 339 datalen = sizeof(adjunctpw) - 1; 340 strncpy(adjunctpw, data, (size_t)datalen); 341 342 /* skip name to get password */ 343 if ((bp = strsep(&data, ":")) != NULL && 344 (bp = strsep(&data, ":")) != NULL) 345 pw->pw_passwd = bp; 346 } 347 } 348 return 0; 349 } 350 #endif /* _PASSWD_COMPAT */ 351 352 /* 353 * local files implementation of getpw*() 354 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] 355 */ 356 static int _local_getpw __P((void *, void *, va_list)); 357 358 /*ARGSUSED*/ 359 static int 360 _local_getpw(rv, cb_data, ap) 361 void *rv; 362 void *cb_data; 363 va_list ap; 364 { 365 DBT key; 366 char bf[/*CONSTCOND*/ MAX(MAXLOGNAME, sizeof(_pw_keynum)) + 1]; 367 uid_t uid; 368 int search, len, rval; 369 const char *name; 370 371 if (!_pw_db && !__initdb()) 372 return NS_UNAVAIL; 373 374 search = va_arg(ap, int); 375 bf[0] = search; 376 switch (search) { 377 case _PW_KEYBYNUM: 378 if (_pw_keynum == -1) 379 return NS_NOTFOUND; /* no more local records */ 380 ++_pw_keynum; 381 memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum)); 382 key.size = sizeof(_pw_keynum) + 1; 383 break; 384 case _PW_KEYBYNAME: 385 name = va_arg(ap, const char *); 386 len = strlen(name); 387 memmove(bf + 1, name, (size_t)MIN(len, MAXLOGNAME)); 388 key.size = len + 1; 389 break; 390 case _PW_KEYBYUID: 391 uid = va_arg(ap, uid_t); 392 memmove(bf + 1, &uid, sizeof(len)); 393 key.size = sizeof(uid) + 1; 394 break; 395 default: 396 abort(); 397 } 398 399 key.data = (u_char *)bf; 400 rval = __hashpw(&key); 401 if (rval == NS_NOTFOUND && search == _PW_KEYBYNUM) 402 _pw_keynum = -1; /* flag `no more local records' */ 403 404 if (!_pw_stayopen && (search != _PW_KEYBYNUM)) { 405 (void)(_pw_db->close)(_pw_db); 406 _pw_db = (DB *)NULL; 407 } 408 return (rval); 409 } 410 411 #ifdef HESIOD 412 /* 413 * hesiod implementation of getpw*() 414 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] 415 */ 416 static int _dns_getpw __P((void *, void *, va_list)); 417 418 /*ARGSUSED*/ 419 static int 420 _dns_getpw(rv, cb_data, ap) 421 void *rv; 422 void *cb_data; 423 va_list ap; 424 { 425 const char *name; 426 uid_t uid; 427 int search; 428 429 const char *map; 430 char **hp; 431 void *context; 432 int r; 433 434 search = va_arg(ap, int); 435 nextdnsbynum: 436 switch (search) { 437 case _PW_KEYBYNUM: 438 if (_pw_hesnum == -1) 439 return NS_NOTFOUND; /* no more hesiod records */ 440 snprintf(line, sizeof(line) - 1, "passwd-%u", _pw_hesnum); 441 _pw_hesnum++; 442 map = "passwd"; 443 break; 444 case _PW_KEYBYNAME: 445 name = va_arg(ap, const char *); 446 strncpy(line, name, sizeof(line)); 447 map = "passwd"; 448 break; 449 case _PW_KEYBYUID: 450 uid = va_arg(ap, uid_t); 451 snprintf(line, sizeof(line), "%u", (unsigned int)uid); 452 map = "uid"; /* XXX this is `passwd' on ultrix */ 453 break; 454 default: 455 abort(); 456 } 457 line[sizeof(line) - 1] = '\0'; 458 459 r = NS_UNAVAIL; 460 if (hesiod_init(&context) == -1) 461 return (r); 462 463 hp = hesiod_resolve(context, line, map); 464 if (hp == NULL) { 465 if (errno == ENOENT) { 466 /* flag `no more hesiod records' */ 467 if (search == _PW_KEYBYNUM) 468 _pw_hesnum = -1; 469 r = NS_NOTFOUND; 470 } 471 goto cleanup_dns_getpw; 472 } 473 474 strncpy(line, hp[0], sizeof(line)); /* only check first elem */ 475 line[sizeof(line) - 1] = '\0'; 476 hesiod_free_list(context, hp); 477 if (__pwparse(&_pw_passwd, line)) { 478 if (search == _PW_KEYBYNUM) 479 goto nextdnsbynum; /* skip dogdy entries */ 480 r = NS_UNAVAIL; 481 } else 482 r = NS_SUCCESS; 483 cleanup_dns_getpw: 484 hesiod_end(context); 485 return (r); 486 } 487 #endif 488 489 #ifdef YP 490 /* 491 * nis implementation of getpw*() 492 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] 493 */ 494 static int _nis_getpw __P((void *, void *, va_list)); 495 496 /*ARGSUSED*/ 497 static int 498 _nis_getpw(rv, cb_data, ap) 499 void *rv; 500 void *cb_data; 501 va_list ap; 502 { 503 const char *name; 504 uid_t uid; 505 int search; 506 char *key, *data; 507 char *map; 508 int keylen, datalen, r, rval; 509 510 if(__ypdomain == NULL) { 511 if(_yp_check(&__ypdomain) == 0) 512 return NS_UNAVAIL; 513 } 514 515 map = PASSWD_BYNAME; 516 search = va_arg(ap, int); 517 switch (search) { 518 case _PW_KEYBYNUM: 519 break; 520 case _PW_KEYBYNAME: 521 name = va_arg(ap, const char *); 522 strncpy(line, name, sizeof(line)); 523 break; 524 case _PW_KEYBYUID: 525 uid = va_arg(ap, uid_t); 526 snprintf(line, sizeof(line), "%u", (unsigned int)uid); 527 map = PASSWD_BYUID; 528 break; 529 default: 530 abort(); 531 } 532 line[sizeof(line) - 1] = '\0'; 533 rval = NS_UNAVAIL; 534 if (search != _PW_KEYBYNUM) { 535 data = NULL; 536 r = yp_match(__ypdomain, map, line, (int)strlen(line), 537 &data, &datalen); 538 if (r == YPERR_KEY) 539 rval = NS_NOTFOUND; 540 if (r != 0) { 541 if (data) 542 free(data); 543 return (rval); 544 } 545 data[datalen] = '\0'; /* clear trailing \n */ 546 strncpy(line, data, sizeof(line)); 547 line[sizeof(line) - 1] = '\0'; 548 free(data); 549 if (__pwparse(&_pw_passwd, line)) 550 return NS_UNAVAIL; 551 return NS_SUCCESS; 552 } 553 554 if (_pw_ypdone) 555 return NS_NOTFOUND; 556 for (;;) { 557 data = key = NULL; 558 if (__ypcurrent) { 559 r = yp_next(__ypdomain, map, 560 __ypcurrent, __ypcurrentlen, 561 &key, &keylen, &data, &datalen); 562 free(__ypcurrent); 563 switch (r) { 564 case 0: 565 __ypcurrent = key; 566 __ypcurrentlen = keylen; 567 break; 568 case YPERR_NOMORE: 569 __ypcurrent = NULL; 570 /* flag `no more yp records' */ 571 _pw_ypdone = 1; 572 rval = NS_NOTFOUND; 573 } 574 } else { 575 r = yp_first(__ypdomain, map, &__ypcurrent, 576 &__ypcurrentlen, &data, &datalen); 577 } 578 if (r != 0) { 579 if (key) 580 free(key); 581 if (data) 582 free(data); 583 return (rval); 584 } 585 data[datalen] = '\0'; /* clear trailing \n */ 586 strncpy(line, data, sizeof(line)); 587 line[sizeof(line) - 1] = '\0'; 588 free(data); 589 if (! __pwparse(&_pw_passwd, line)) 590 return NS_SUCCESS; 591 } 592 /* NOTREACHED */ 593 } /* _nis_getpw */ 594 #endif 595 596 #ifdef _PASSWD_COMPAT 597 /* 598 * See if the compat token is in the database. Only works if pwd_mkdb knows 599 * about the token. 600 */ 601 static int __has_compatpw __P((void)); 602 603 static int 604 __has_compatpw() 605 { 606 DBT key, data; 607 DBT pkey, pdata; 608 char bf[MAXLOGNAME]; 609 u_char cyp[] = { _PW_KEYYPENABLED }; 610 611 /*LINTED*/ 612 key.data = cyp; 613 key.size = 1; 614 615 /* Pre-token database support. */ 616 bf[0] = _PW_KEYBYNAME; 617 bf[1] = '+'; 618 pkey.data = (u_char *)bf; 619 pkey.size = 2; 620 621 if ((_pw_db->get)(_pw_db, &key, &data, 0) 622 && (_pw_db->get)(_pw_db, &pkey, &pdata, 0)) 623 return 0; /* No compat token */ 624 return 1; 625 } 626 627 /* 628 * log an error if "files" or "compat" is specified in passwd_compat database 629 */ 630 static int _bad_getpw __P((void *, void *, va_list)); 631 632 /*ARGSUSED*/ 633 static int 634 _bad_getpw(rv, cb_data, ap) 635 void *rv; 636 void *cb_data; 637 va_list ap; 638 { 639 static int warned; 640 if (!warned) { 641 syslog(LOG_ERR, 642 "nsswitch.conf passwd_compat database can't use '%s'", 643 (char *)cb_data); 644 } 645 warned = 1; 646 return NS_UNAVAIL; 647 } 648 649 /* 650 * when a name lookup in compat mode is required (e.g., '+name', or a name in 651 * '+@netgroup'), look it up in the 'passwd_compat' nsswitch database. 652 * only Hesiod and NIS is supported - it doesn't make sense to lookup 653 * compat names from 'files' or 'compat'. 654 */ 655 static int __getpwcompat __P((int, uid_t, const char *)); 656 657 static int 658 __getpwcompat(type, uid, name) 659 int type; 660 uid_t uid; 661 const char *name; 662 { 663 static const ns_dtab dtab[] = { 664 NS_FILES_CB(_bad_getpw, "files") 665 NS_DNS_CB(_dns_getpw, NULL) 666 NS_NIS_CB(_nis_getpw, NULL) 667 NS_COMPAT_CB(_bad_getpw, "compat") 668 { 0 } 669 }; 670 static const ns_src defaultnis[] = { 671 { NSSRC_NIS, NS_SUCCESS }, 672 { 0 } 673 }; 674 675 switch (type) { 676 case _PW_KEYBYNUM: 677 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat", 678 defaultnis, type); 679 case _PW_KEYBYNAME: 680 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat", 681 defaultnis, type, name); 682 case _PW_KEYBYUID: 683 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat", 684 defaultnis, type, uid); 685 default: 686 abort(); 687 /*NOTREACHED*/ 688 } 689 } 690 #endif /* _PASSWD_COMPAT */ 691 692 /* 693 * compat implementation of getpwent() 694 * varargs (ignored): 695 * type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] 696 */ 697 static int _compat_getpwent __P((void *, void *, va_list)); 698 699 /*ARGSUSED*/ 700 static int 701 _compat_getpwent(rv, cb_data, ap) 702 void *rv; 703 void *cb_data; 704 va_list ap; 705 { 706 DBT key; 707 int rval; 708 char bf[sizeof(_pw_keynum) + 1]; 709 #ifdef _PASSWD_COMPAT 710 static char *name = NULL; 711 char *user, *host, *dom; 712 int has_compatpw; 713 #endif 714 715 if (!_pw_db && !__initdb()) 716 return NS_UNAVAIL; 717 718 #ifdef _PASSWD_COMPAT 719 has_compatpw = __has_compatpw(); 720 721 again: 722 if (has_compatpw && (__pwmode != PWMODE_NONE)) { 723 int r; 724 725 switch (__pwmode) { 726 case PWMODE_FULL: 727 r = __getpwcompat(_PW_KEYBYNUM, 0, NULL); 728 if (r == NS_SUCCESS) 729 return r; 730 __pwmode = PWMODE_NONE; 731 break; 732 733 case PWMODE_NETGRP: 734 r = getnetgrent(&host, &user, &dom); 735 if (r == 0) { /* end of group */ 736 endnetgrent(); 737 __pwmode = PWMODE_NONE; 738 break; 739 } 740 if (!user || !*user) 741 break; 742 r = __getpwcompat(_PW_KEYBYNAME, 0, user); 743 if (r == NS_SUCCESS) 744 return r; 745 break; 746 747 case PWMODE_USER: 748 if (name == NULL) { 749 __pwmode = PWMODE_NONE; 750 break; 751 } 752 r = __getpwcompat(_PW_KEYBYNAME, 0, name); 753 free(name); 754 name = NULL; 755 if (r == NS_SUCCESS) 756 return r; 757 break; 758 759 case PWMODE_NONE: 760 abort(); 761 } 762 goto again; 763 } 764 #endif 765 766 if (_pw_keynum == -1) 767 return NS_NOTFOUND; /* no more local records */ 768 ++_pw_keynum; 769 bf[0] = _PW_KEYBYNUM; 770 memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum)); 771 key.data = (u_char *)bf; 772 key.size = sizeof(_pw_keynum) + 1; 773 rval = __hashpw(&key); 774 if (rval == NS_NOTFOUND) 775 _pw_keynum = -1; /* flag `no more local records' */ 776 else if (rval == NS_SUCCESS) { 777 #ifdef _PASSWD_COMPAT 778 /* if we don't have YP at all, don't bother. */ 779 if (has_compatpw) { 780 if(_pw_passwd.pw_name[0] == '+') { 781 /* set the mode */ 782 switch(_pw_passwd.pw_name[1]) { 783 case '\0': 784 __pwmode = PWMODE_FULL; 785 break; 786 case '@': 787 __pwmode = PWMODE_NETGRP; 788 setnetgrent(_pw_passwd.pw_name + 2); 789 break; 790 default: 791 __pwmode = PWMODE_USER; 792 name = strdup(_pw_passwd.pw_name + 1); 793 break; 794 } 795 796 /* save the prototype */ 797 __pwproto_set(); 798 goto again; 799 } else if(_pw_passwd.pw_name[0] == '-') { 800 /* an attempted exclusion */ 801 switch(_pw_passwd.pw_name[1]) { 802 case '\0': 803 break; 804 case '@': 805 setnetgrent(_pw_passwd.pw_name + 2); 806 while(getnetgrent(&host, &user, &dom)) { 807 if(user && *user) 808 __pwexclude_add(user); 809 } 810 endnetgrent(); 811 break; 812 default: 813 __pwexclude_add(_pw_passwd.pw_name + 1); 814 break; 815 } 816 goto again; 817 } 818 } 819 #endif 820 } 821 return (rval); 822 } 823 824 /* 825 * compat implementation of getpwnam() and getpwuid() 826 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] 827 */ 828 static int _compat_getpw __P((void *, void *, va_list)); 829 830 static int 831 _compat_getpw(rv, cb_data, ap) 832 void *rv; 833 void *cb_data; 834 va_list ap; 835 { 836 #ifdef _PASSWD_COMPAT 837 DBT key; 838 int search, rval, r, s, keynum; 839 uid_t uid; 840 char bf[sizeof(keynum) + 1]; 841 char *name, *host, *user, *dom; 842 #endif 843 844 if (!_pw_db && !__initdb()) 845 return NS_UNAVAIL; 846 847 /* 848 * If there isn't a compat token in the database, use files. 849 */ 850 #ifdef _PASSWD_COMPAT 851 if (! __has_compatpw()) 852 #endif 853 return (_local_getpw(rv, cb_data, ap)); 854 855 #ifdef _PASSWD_COMPAT 856 search = va_arg(ap, int); 857 uid = 0; 858 name = NULL; 859 rval = NS_NOTFOUND; 860 switch (search) { 861 case _PW_KEYBYNAME: 862 name = va_arg(ap, char *); 863 break; 864 case _PW_KEYBYUID: 865 uid = va_arg(ap, uid_t); 866 break; 867 default: 868 abort(); 869 } 870 871 for (s = -1, keynum = 1 ; ; keynum++) { 872 bf[0] = _PW_KEYBYNUM; 873 memmove(bf + 1, &keynum, sizeof(keynum)); 874 key.data = (u_char *)bf; 875 key.size = sizeof(keynum) + 1; 876 if(__hashpw(&key) != NS_SUCCESS) 877 break; 878 switch(_pw_passwd.pw_name[0]) { 879 case '+': 880 /* save the prototype */ 881 __pwproto_set(); 882 883 switch(_pw_passwd.pw_name[1]) { 884 case '\0': 885 r = __getpwcompat(search, uid, name); 886 if (r != NS_SUCCESS) 887 continue; 888 break; 889 case '@': 890 pwnam_netgrp: 891 #if 0 /* XXX: is this a hangover from pre-nsswitch? */ 892 if(__ypcurrent) { 893 free(__ypcurrent); 894 __ypcurrent = NULL; 895 } 896 #endif 897 if (s == -1) /* first time */ 898 setnetgrent(_pw_passwd.pw_name + 2); 899 s = getnetgrent(&host, &user, &dom); 900 if (s == 0) { /* end of group */ 901 endnetgrent(); 902 s = -1; 903 continue; 904 } 905 if (!user || !*user) 906 goto pwnam_netgrp; 907 908 r = __getpwcompat(_PW_KEYBYNAME, 0, user); 909 910 if (r == NS_UNAVAIL) 911 return r; 912 if (r == NS_NOTFOUND) { 913 /* 914 * just because this user is bad 915 * it doesn't mean they all are. 916 */ 917 goto pwnam_netgrp; 918 } 919 break; 920 default: 921 user = _pw_passwd.pw_name + 1; 922 r = __getpwcompat(_PW_KEYBYNAME, 0, user); 923 924 if (r == NS_UNAVAIL) 925 return r; 926 if (r == NS_NOTFOUND) 927 continue; 928 break; 929 } 930 if(__pwexclude_is(_pw_passwd.pw_name)) { 931 if(s == 1) /* inside netgroup */ 932 goto pwnam_netgrp; 933 continue; 934 } 935 break; 936 case '-': 937 /* attempted exclusion */ 938 switch(_pw_passwd.pw_name[1]) { 939 case '\0': 940 break; 941 case '@': 942 setnetgrent(_pw_passwd.pw_name + 2); 943 while(getnetgrent(&host, &user, &dom)) { 944 if(user && *user) 945 __pwexclude_add(user); 946 } 947 endnetgrent(); 948 break; 949 default: 950 __pwexclude_add(_pw_passwd.pw_name + 1); 951 break; 952 } 953 break; 954 } 955 if ((search == _PW_KEYBYNAME && 956 strcmp(_pw_passwd.pw_name, name) == 0) 957 || (search == _PW_KEYBYUID && _pw_passwd.pw_uid == uid)) { 958 rval = NS_SUCCESS; 959 break; 960 } 961 if(s == 1) /* inside netgroup */ 962 goto pwnam_netgrp; 963 continue; 964 } 965 __pwproto = (struct passwd *)NULL; 966 967 if (!_pw_stayopen) { 968 (void)(_pw_db->close)(_pw_db); 969 _pw_db = (DB *)NULL; 970 } 971 if(__pwexclude != (DB *)NULL) { 972 (void)(__pwexclude->close)(__pwexclude); 973 __pwexclude = (DB *)NULL; 974 } 975 return rval; 976 #endif /* _PASSWD_COMPAT */ 977 } 978 979 struct passwd * 980 getpwent() 981 { 982 int r; 983 static const ns_dtab dtab[] = { 984 NS_FILES_CB(_local_getpw, NULL) 985 NS_DNS_CB(_dns_getpw, NULL) 986 NS_NIS_CB(_nis_getpw, NULL) 987 NS_COMPAT_CB(_compat_getpwent, NULL) 988 { 0 } 989 }; 990 991 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", compatsrc, 992 _PW_KEYBYNUM); 993 if (r != NS_SUCCESS) 994 return (struct passwd *)NULL; 995 return &_pw_passwd; 996 } 997 998 struct passwd * 999 getpwnam(name) 1000 const char *name; 1001 { 1002 int r; 1003 static const ns_dtab dtab[] = { 1004 NS_FILES_CB(_local_getpw, NULL) 1005 NS_DNS_CB(_dns_getpw, NULL) 1006 NS_NIS_CB(_nis_getpw, NULL) 1007 NS_COMPAT_CB(_compat_getpw, NULL) 1008 { 0 } 1009 }; 1010 1011 if (name == NULL || name[0] == '\0') 1012 return (struct passwd *)NULL; 1013 1014 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", compatsrc, 1015 _PW_KEYBYNAME, name); 1016 return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL); 1017 } 1018 1019 struct passwd * 1020 getpwuid(uid) 1021 uid_t uid; 1022 { 1023 int r; 1024 static const ns_dtab dtab[] = { 1025 NS_FILES_CB(_local_getpw, NULL) 1026 NS_DNS_CB(_dns_getpw, NULL) 1027 NS_NIS_CB(_nis_getpw, NULL) 1028 NS_COMPAT_CB(_compat_getpw, NULL) 1029 { 0 } 1030 }; 1031 1032 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", compatsrc, 1033 _PW_KEYBYUID, uid); 1034 return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL); 1035 } 1036 1037 int 1038 setpassent(stayopen) 1039 int stayopen; 1040 { 1041 _pw_keynum = 0; 1042 _pw_stayopen = stayopen; 1043 #ifdef YP 1044 __pwmode = PWMODE_NONE; 1045 if(__ypcurrent) 1046 free(__ypcurrent); 1047 __ypcurrent = NULL; 1048 _pw_ypdone = 0; 1049 #endif 1050 #ifdef HESIOD 1051 _pw_hesnum = 0; 1052 #endif 1053 #ifdef _PASSWD_COMPAT 1054 if(__pwexclude != (DB *)NULL) { 1055 (void)(__pwexclude->close)(__pwexclude); 1056 __pwexclude = (DB *)NULL; 1057 } 1058 __pwproto = (struct passwd *)NULL; 1059 #endif 1060 return 1; 1061 } 1062 1063 void 1064 setpwent() 1065 { 1066 (void) setpassent(0); 1067 } 1068 1069 void 1070 endpwent() 1071 { 1072 _pw_keynum = 0; 1073 if (_pw_db) { 1074 (void)(_pw_db->close)(_pw_db); 1075 _pw_db = (DB *)NULL; 1076 } 1077 #ifdef _PASSWD_COMPAT 1078 __pwmode = PWMODE_NONE; 1079 #endif 1080 #ifdef YP 1081 if(__ypcurrent) 1082 free(__ypcurrent); 1083 __ypcurrent = NULL; 1084 _pw_ypdone = 0; 1085 #endif 1086 #ifdef HESIOD 1087 _pw_hesnum = 0; 1088 #endif 1089 #ifdef _PASSWD_COMPAT 1090 if(__pwexclude != (DB *)NULL) { 1091 (void)(__pwexclude->close)(__pwexclude); 1092 __pwexclude = (DB *)NULL; 1093 } 1094 __pwproto = (struct passwd *)NULL; 1095 #endif 1096 } 1097 1098 static int 1099 __initdb() 1100 { 1101 static int warned; 1102 char *p; 1103 1104 #ifdef _PASSWD_COMPAT 1105 __pwmode = PWMODE_NONE; 1106 #endif 1107 if (geteuid() == 0) { 1108 _pw_db = dbopen((p = _PATH_SMP_DB), O_RDONLY, 0, DB_HASH, NULL); 1109 if (_pw_db) 1110 return(1); 1111 } 1112 _pw_db = dbopen((p = _PATH_MP_DB), O_RDONLY, 0, DB_HASH, NULL); 1113 if (_pw_db) 1114 return 1; 1115 if (!warned) 1116 syslog(LOG_ERR, "%s: %m", p); 1117 warned = 1; 1118 return 0; 1119 } 1120 1121 static int 1122 __hashpw(key) 1123 DBT *key; 1124 { 1125 char *p, *t; 1126 static u_int max; 1127 static char *buf; 1128 DBT data; 1129 1130 switch ((_pw_db->get)(_pw_db, key, &data, 0)) { 1131 case 0: 1132 break; /* found */ 1133 case 1: 1134 return NS_NOTFOUND; 1135 case -1: 1136 return NS_UNAVAIL; /* error in db routines */ 1137 default: 1138 abort(); 1139 } 1140 1141 p = (char *)data.data; 1142 if (data.size > max && !(buf = realloc(buf, (max += 1024)))) 1143 return NS_UNAVAIL; 1144 1145 /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ 1146 t = buf; 1147 #define EXPAND(e) e = t; while ((*t++ = *p++)); 1148 #define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v 1149 EXPAND(_pw_passwd.pw_name); 1150 EXPAND(_pw_passwd.pw_passwd); 1151 SCALAR(_pw_passwd.pw_uid); 1152 SCALAR(_pw_passwd.pw_gid); 1153 SCALAR(_pw_passwd.pw_change); 1154 EXPAND(_pw_passwd.pw_class); 1155 EXPAND(_pw_passwd.pw_gecos); 1156 EXPAND(_pw_passwd.pw_dir); 1157 EXPAND(_pw_passwd.pw_shell); 1158 SCALAR(_pw_passwd.pw_expire); 1159 SCALAR(_pw_passwd.pw_fields); 1160 1161 return NS_SUCCESS; 1162 } 1163