getpwent.c revision 68577
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) 39static const char *rcsid[] = 40 "$FreeBSD: head/lib/libc/gen/getpwent.c 68577 2000-11-10 19:11:14Z nectar $"; 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 66extern void setnetgrent __P((char *)); 67extern int getnetgrent __P((char **, char **, char **)); 68extern 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 81static struct passwd _pw_passwd = { "", "", 0, 0, 0, "", "", "", "", 0, 0 }; 82static DB *_pw_db; /* password database */ 83static int _pw_keynum; /* key counter. no more records if -1 */ 84static int _pw_stayopen; /* keep fd's open */ 85 86static int __hashpw __P((DBT *)); 87static int __initdb __P((void)); 88 89static const ns_src compatsrc[] = { 90 { NSSRC_COMPAT, NS_SUCCESS }, 91 { 0 } 92}; 93 94#ifdef YP 95static char *__ypcurrent, *__ypdomain; 96static int __ypcurrentlen; 97static int _pw_ypdone; /* non-zero if no more yp records */ 98#endif 99 100#ifdef HESIOD 101static int _pw_hesnum; /* hes counter. no more records if -1 */ 102#endif 103 104#ifdef _PASSWD_COMPAT 105enum _pwmode { PWMODE_NONE, PWMODE_FULL, PWMODE_USER, PWMODE_NETGRP }; 106static enum _pwmode __pwmode; 107 108enum _ypmap { YPMAP_NONE, YPMAP_ADJUNCT, YPMAP_MASTER }; 109 110static struct passwd *__pwproto = (struct passwd *)NULL; 111static int __pwproto_flags; 112static char line[1024]; 113static long prbuf[1024 / sizeof(long)]; 114static DB *__pwexclude = (DB *)NULL; 115 116static int __pwexclude_add __P((const char *)); 117static int __pwexclude_is __P((const char *)); 118static void __pwproto_set __P((void)); 119static int __ypmaptype __P((void)); 120static 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 */ 131static 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 */ 164static 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 */ 190static 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 __pwproto->pw_uid = pw->pw_uid; 217 __pwproto->pw_gid = pw->pw_gid; 218 __pwproto_flags |= _PWF_UID | _PWF_GID; 219 220 /* gecos */ 221 if(pw->pw_gecos && (pw->pw_gecos)[0]) { 222 ptr = (char *)ALIGN((u_long)ptr); 223 memmove(ptr, pw->pw_gecos, strlen(pw->pw_gecos) + 1); 224 __pwproto->pw_gecos = ptr; 225 ptr += (strlen(pw->pw_gecos) + 1); 226 __pwproto_flags |= _PWF_GECOS; 227 } 228 229 /* dir */ 230 if(pw->pw_dir && (pw->pw_dir)[0]) { 231 ptr = (char *)ALIGN((u_long)ptr); 232 memmove(ptr, pw->pw_dir, strlen(pw->pw_dir) + 1); 233 __pwproto->pw_dir = ptr; 234 ptr += (strlen(pw->pw_dir) + 1); 235 __pwproto_flags |= _PWF_DIR; 236 } 237 238 /* shell */ 239 if(pw->pw_shell && (pw->pw_shell)[0]) { 240 ptr = (char *)ALIGN((u_long)ptr); 241 memmove(ptr, pw->pw_shell, strlen(pw->pw_shell) + 1); 242 __pwproto->pw_shell = ptr; 243 ptr += (strlen(pw->pw_shell) + 1); 244 __pwproto_flags |= _PWF_SHELL; 245 } 246} 247 248static int 249__ypmaptype() 250{ 251 static int maptype = -1; 252 int order, r; 253 254 if (maptype != -1) 255 return (maptype); 256 257 maptype = YPMAP_NONE; 258 if (geteuid() != 0) 259 return (maptype); 260 261 if (!__ypdomain) { 262 if( _yp_check(&__ypdomain) == 0) 263 return (maptype); 264 } 265 266 r = yp_order(__ypdomain, "master.passwd.byname", &order); 267 if (r == 0) { 268 maptype = YPMAP_MASTER; 269 return (maptype); 270 } 271 272 /* 273 * NIS+ in YP compat mode doesn't support 274 * YPPROC_ORDER -- no point in continuing. 275 */ 276 if (r == YPERR_YPERR) 277 return (maptype); 278 279 /* master.passwd doesn't exist -- try passwd.adjunct */ 280 if (r == YPERR_MAP) { 281 r = yp_order(__ypdomain, "passwd.adjunct.byname", &order); 282 if (r == 0) 283 maptype = YPMAP_ADJUNCT; 284 return (maptype); 285 } 286 287 return (maptype); 288} 289 290/* 291 * parse a passwd file line (from NIS or HESIOD). 292 * assumed to be `old-style' if maptype != YPMAP_MASTER. 293 */ 294static int 295__pwparse(pw, s) 296 struct passwd *pw; 297 char *s; 298{ 299 static char adjunctpw[YPMAXRECORD + 2]; 300 int flags, maptype; 301 302 maptype = __ypmaptype(); 303 flags = 0; 304 if (maptype == YPMAP_MASTER) 305 flags |= _PWSCAN_MASTER; 306 if (! __pw_scan(s, pw, flags)) 307 return 1; 308 309 /* now let the prototype override, if set. */ 310 if(__pwproto != (struct passwd *)NULL) { 311#ifdef PW_OVERRIDE_PASSWD 312 if(__pwproto_flags & _PWF_PASSWD) 313 pw->pw_passwd = __pwproto->pw_passwd; 314#endif 315 if(__pwproto_flags & _PWF_UID) 316 pw->pw_uid = __pwproto->pw_uid; 317 if(__pwproto_flags & _PWF_GID) 318 pw->pw_gid = __pwproto->pw_gid; 319 if(__pwproto_flags & _PWF_GECOS) 320 pw->pw_gecos = __pwproto->pw_gecos; 321 if(__pwproto_flags & _PWF_DIR) 322 pw->pw_dir = __pwproto->pw_dir; 323 if(__pwproto_flags & _PWF_SHELL) 324 pw->pw_shell = __pwproto->pw_shell; 325 } 326 if ((maptype == YPMAP_ADJUNCT) && 327 (strstr(pw->pw_passwd, "##") != NULL)) { 328 char *data, *bp; 329 int datalen; 330 331 if (yp_match(__ypdomain, "passwd.adjunct.byname", pw->pw_name, 332 (int)strlen(pw->pw_name), &data, &datalen) == 0) { 333 if (datalen > sizeof(adjunctpw) - 1) 334 datalen = sizeof(adjunctpw) - 1; 335 strncpy(adjunctpw, data, (size_t)datalen); 336 337 /* skip name to get password */ 338 if ((bp = strsep(&data, ":")) != NULL && 339 (bp = strsep(&data, ":")) != NULL) 340 pw->pw_passwd = bp; 341 } 342 } 343 return 0; 344} 345#endif /* _PASSWD_COMPAT */ 346 347/* 348 * local files implementation of getpw*() 349 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] 350 */ 351static int _local_getpw __P((void *, void *, va_list)); 352 353/*ARGSUSED*/ 354static int 355_local_getpw(rv, cb_data, ap) 356 void *rv; 357 void *cb_data; 358 va_list ap; 359{ 360 DBT key; 361 char bf[/*CONSTCOND*/ MAX(MAXLOGNAME, sizeof(_pw_keynum)) + 1]; 362 uid_t uid; 363 int search, len, rval; 364 const char *name; 365 366 if (!_pw_db && !__initdb()) 367 return NS_UNAVAIL; 368 369 search = va_arg(ap, int); 370 bf[0] = search; 371 switch (search) { 372 case _PW_KEYBYNUM: 373 if (_pw_keynum == -1) 374 return NS_NOTFOUND; /* no more local records */ 375 ++_pw_keynum; 376 memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum)); 377 key.size = sizeof(_pw_keynum) + 1; 378 break; 379 case _PW_KEYBYNAME: 380 name = va_arg(ap, const char *); 381 len = strlen(name); 382 memmove(bf + 1, name, (size_t)MIN(len, MAXLOGNAME)); 383 key.size = len + 1; 384 break; 385 case _PW_KEYBYUID: 386 uid = va_arg(ap, uid_t); 387 memmove(bf + 1, &uid, sizeof(len)); 388 key.size = sizeof(uid) + 1; 389 break; 390 default: 391 abort(); 392 } 393 394 key.data = (u_char *)bf; 395 rval = __hashpw(&key); 396 if (rval == NS_NOTFOUND && search == _PW_KEYBYNUM) 397 _pw_keynum = -1; /* flag `no more local records' */ 398 399 if (!_pw_stayopen && (search != _PW_KEYBYNUM)) { 400 (void)(_pw_db->close)(_pw_db); 401 _pw_db = (DB *)NULL; 402 } 403 return (rval); 404} 405 406#ifdef HESIOD 407/* 408 * hesiod implementation of getpw*() 409 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] 410 */ 411static int _dns_getpw __P((void *, void *, va_list)); 412 413/*ARGSUSED*/ 414static int 415_dns_getpw(rv, cb_data, ap) 416 void *rv; 417 void *cb_data; 418 va_list ap; 419{ 420 const char *name; 421 uid_t uid; 422 int search; 423 424 const char *map; 425 char **hp; 426 void *context; 427 int r; 428 429 search = va_arg(ap, int); 430 nextdnsbynum: 431 switch (search) { 432 case _PW_KEYBYNUM: 433 if (_pw_hesnum == -1) 434 return NS_NOTFOUND; /* no more hesiod records */ 435 snprintf(line, sizeof(line) - 1, "passwd-%u", _pw_hesnum); 436 _pw_hesnum++; 437 map = "passwd"; 438 break; 439 case _PW_KEYBYNAME: 440 name = va_arg(ap, const char *); 441 strncpy(line, name, sizeof(line)); 442 map = "passwd"; 443 break; 444 case _PW_KEYBYUID: 445 uid = va_arg(ap, uid_t); 446 snprintf(line, sizeof(line), "%u", (unsigned int)uid); 447 map = "uid"; /* XXX this is `passwd' on ultrix */ 448 break; 449 default: 450 abort(); 451 } 452 line[sizeof(line) - 1] = '\0'; 453 454 r = NS_UNAVAIL; 455 if (hesiod_init(&context) == -1) 456 return (r); 457 458 hp = hesiod_resolve(context, line, map); 459 if (hp == NULL) { 460 if (errno == ENOENT) { 461 /* flag `no more hesiod records' */ 462 if (search == _PW_KEYBYNUM) 463 _pw_hesnum = -1; 464 r = NS_NOTFOUND; 465 } 466 goto cleanup_dns_getpw; 467 } 468 469 strncpy(line, hp[0], sizeof(line)); /* only check first elem */ 470 line[sizeof(line) - 1] = '\0'; 471 hesiod_free_list(context, hp); 472 if (__pwparse(&_pw_passwd, line)) { 473 if (search == _PW_KEYBYNUM) 474 goto nextdnsbynum; /* skip dogdy entries */ 475 r = NS_UNAVAIL; 476 } else 477 r = NS_SUCCESS; 478 cleanup_dns_getpw: 479 hesiod_end(context); 480 return (r); 481} 482#endif 483 484#ifdef YP 485/* 486 * nis implementation of getpw*() 487 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] 488 */ 489static int _nis_getpw __P((void *, void *, va_list)); 490 491/*ARGSUSED*/ 492static int 493_nis_getpw(rv, cb_data, ap) 494 void *rv; 495 void *cb_data; 496 va_list ap; 497{ 498 const char *name; 499 uid_t uid; 500 int search; 501 char *key, *data; 502 char *map; 503 int keylen, datalen, r, rval; 504 505 if(__ypdomain == NULL) { 506 if(_yp_check(&__ypdomain) == 0) 507 return NS_UNAVAIL; 508 } 509 510 map = PASSWD_BYNAME; 511 search = va_arg(ap, int); 512 switch (search) { 513 case _PW_KEYBYNUM: 514 break; 515 case _PW_KEYBYNAME: 516 name = va_arg(ap, const char *); 517 strncpy(line, name, sizeof(line)); 518 break; 519 case _PW_KEYBYUID: 520 uid = va_arg(ap, uid_t); 521 snprintf(line, sizeof(line), "%u", (unsigned int)uid); 522 map = PASSWD_BYUID; 523 break; 524 default: 525 abort(); 526 } 527 line[sizeof(line) - 1] = '\0'; 528 rval = NS_UNAVAIL; 529 if (search != _PW_KEYBYNUM) { 530 data = NULL; 531 r = yp_match(__ypdomain, map, line, (int)strlen(line), 532 &data, &datalen); 533 if (r == YPERR_KEY) 534 rval = NS_NOTFOUND; 535 if (r != 0) { 536 if (data) 537 free(data); 538 return (rval); 539 } 540 data[datalen] = '\0'; /* clear trailing \n */ 541 strncpy(line, data, sizeof(line)); 542 line[sizeof(line) - 1] = '\0'; 543 free(data); 544 if (__pwparse(&_pw_passwd, line)) 545 return NS_UNAVAIL; 546 return NS_SUCCESS; 547 } 548 549 if (_pw_ypdone) 550 return NS_NOTFOUND; 551 for (;;) { 552 data = key = NULL; 553 if (__ypcurrent) { 554 r = yp_next(__ypdomain, map, 555 __ypcurrent, __ypcurrentlen, 556 &key, &keylen, &data, &datalen); 557 free(__ypcurrent); 558 switch (r) { 559 case 0: 560 __ypcurrent = key; 561 __ypcurrentlen = keylen; 562 break; 563 case YPERR_NOMORE: 564 __ypcurrent = NULL; 565 /* flag `no more yp records' */ 566 _pw_ypdone = 1; 567 rval = NS_NOTFOUND; 568 } 569 } else { 570 r = yp_first(__ypdomain, map, &__ypcurrent, 571 &__ypcurrentlen, &data, &datalen); 572 } 573 if (r != 0) { 574 if (key) 575 free(key); 576 if (data) 577 free(data); 578 return (rval); 579 } 580 data[datalen] = '\0'; /* clear trailing \n */ 581 strncpy(line, data, sizeof(line)); 582 line[sizeof(line) - 1] = '\0'; 583 free(data); 584 if (! __pwparse(&_pw_passwd, line)) 585 return NS_SUCCESS; 586 } 587 /* NOTREACHED */ 588} /* _nis_getpw */ 589#endif 590 591#ifdef _PASSWD_COMPAT 592/* 593 * See if the compat token is in the database. Only works if pwd_mkdb knows 594 * about the token. 595 */ 596static int __has_compatpw __P((void)); 597 598static int 599__has_compatpw() 600{ 601 DBT key, data; 602 DBT pkey, pdata; 603 char bf[MAXLOGNAME]; 604 u_char cyp[] = { _PW_KEYYPENABLED }; 605 606 /*LINTED*/ 607 key.data = cyp; 608 key.size = 1; 609 610 /* Pre-token database support. */ 611 bf[0] = _PW_KEYBYNAME; 612 bf[1] = '+'; 613 pkey.data = (u_char *)bf; 614 pkey.size = 2; 615 616 if ((_pw_db->get)(_pw_db, &key, &data, 0) 617 && (_pw_db->get)(_pw_db, &pkey, &pdata, 0)) 618 return 0; /* No compat token */ 619 return 1; 620} 621 622/* 623 * log an error if "files" or "compat" is specified in passwd_compat database 624 */ 625static int _bad_getpw __P((void *, void *, va_list)); 626 627/*ARGSUSED*/ 628static int 629_bad_getpw(rv, cb_data, ap) 630 void *rv; 631 void *cb_data; 632 va_list ap; 633{ 634 static int warned; 635 if (!warned) { 636 syslog(LOG_ERR, 637 "nsswitch.conf passwd_compat database can't use '%s'", 638 (char *)cb_data); 639 } 640 warned = 1; 641 return NS_UNAVAIL; 642} 643 644/* 645 * when a name lookup in compat mode is required (e.g., '+name', or a name in 646 * '+@netgroup'), look it up in the 'passwd_compat' nsswitch database. 647 * only Hesiod and NIS is supported - it doesn't make sense to lookup 648 * compat names from 'files' or 'compat'. 649 */ 650static int __getpwcompat __P((int, uid_t, const char *)); 651 652static int 653__getpwcompat(type, uid, name) 654 int type; 655 uid_t uid; 656 const char *name; 657{ 658 static const ns_dtab dtab[] = { 659 NS_FILES_CB(_bad_getpw, "files") 660 NS_DNS_CB(_dns_getpw, NULL) 661 NS_NIS_CB(_nis_getpw, NULL) 662 NS_COMPAT_CB(_bad_getpw, "compat") 663 { 0 } 664 }; 665 static const ns_src defaultnis[] = { 666 { NSSRC_NIS, NS_SUCCESS }, 667 { 0 } 668 }; 669 670 switch (type) { 671 case _PW_KEYBYNUM: 672 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat", 673 defaultnis, type); 674 case _PW_KEYBYNAME: 675 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat", 676 defaultnis, type, name); 677 case _PW_KEYBYUID: 678 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "getpwcompat", 679 defaultnis, type, uid); 680 default: 681 abort(); 682 /*NOTREACHED*/ 683 } 684} 685#endif /* _PASSWD_COMPAT */ 686 687/* 688 * compat implementation of getpwent() 689 * varargs (ignored): 690 * type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] 691 */ 692static int _compat_getpwent __P((void *, void *, va_list)); 693 694/*ARGSUSED*/ 695static int 696_compat_getpwent(rv, cb_data, ap) 697 void *rv; 698 void *cb_data; 699 va_list ap; 700{ 701 DBT key; 702 int rval; 703 char bf[sizeof(_pw_keynum) + 1]; 704#ifdef _PASSWD_COMPAT 705 static char *name = NULL; 706 char *user, *host, *dom; 707 int has_compatpw; 708#endif 709 710 if (!_pw_db && !__initdb()) 711 return NS_UNAVAIL; 712 713#ifdef _PASSWD_COMPAT 714 has_compatpw = __has_compatpw(); 715 716again: 717 if (has_compatpw && (__pwmode != PWMODE_NONE)) { 718 int r; 719 720 switch (__pwmode) { 721 case PWMODE_FULL: 722 r = __getpwcompat(_PW_KEYBYNUM, 0, NULL); 723 if (r == NS_SUCCESS) 724 return r; 725 __pwmode = PWMODE_NONE; 726 break; 727 728 case PWMODE_NETGRP: 729 r = getnetgrent(&host, &user, &dom); 730 if (r == 0) { /* end of group */ 731 endnetgrent(); 732 __pwmode = PWMODE_NONE; 733 break; 734 } 735 if (!user || !*user) 736 break; 737 r = __getpwcompat(_PW_KEYBYNAME, 0, user); 738 if (r == NS_SUCCESS) 739 return r; 740 break; 741 742 case PWMODE_USER: 743 if (name == NULL) { 744 __pwmode = PWMODE_NONE; 745 break; 746 } 747 r = __getpwcompat(_PW_KEYBYNAME, 0, name); 748 free(name); 749 name = NULL; 750 if (r == NS_SUCCESS) 751 return r; 752 break; 753 754 case PWMODE_NONE: 755 abort(); 756 } 757 goto again; 758 } 759#endif 760 761 if (_pw_keynum == -1) 762 return NS_NOTFOUND; /* no more local records */ 763 ++_pw_keynum; 764 bf[0] = _PW_KEYBYNUM; 765 memmove(bf + 1, &_pw_keynum, sizeof(_pw_keynum)); 766 key.data = (u_char *)bf; 767 key.size = sizeof(_pw_keynum) + 1; 768 rval = __hashpw(&key); 769 if (rval == NS_NOTFOUND) 770 _pw_keynum = -1; /* flag `no more local records' */ 771 else if (rval == NS_SUCCESS) { 772#ifdef _PASSWD_COMPAT 773 /* if we don't have YP at all, don't bother. */ 774 if (has_compatpw) { 775 if(_pw_passwd.pw_name[0] == '+') { 776 /* set the mode */ 777 switch(_pw_passwd.pw_name[1]) { 778 case '\0': 779 __pwmode = PWMODE_FULL; 780 break; 781 case '@': 782 __pwmode = PWMODE_NETGRP; 783 setnetgrent(_pw_passwd.pw_name + 2); 784 break; 785 default: 786 __pwmode = PWMODE_USER; 787 name = strdup(_pw_passwd.pw_name + 1); 788 break; 789 } 790 791 /* save the prototype */ 792 __pwproto_set(); 793 goto again; 794 } else if(_pw_passwd.pw_name[0] == '-') { 795 /* an attempted exclusion */ 796 switch(_pw_passwd.pw_name[1]) { 797 case '\0': 798 break; 799 case '@': 800 setnetgrent(_pw_passwd.pw_name + 2); 801 while(getnetgrent(&host, &user, &dom)) { 802 if(user && *user) 803 __pwexclude_add(user); 804 } 805 endnetgrent(); 806 break; 807 default: 808 __pwexclude_add(_pw_passwd.pw_name + 1); 809 break; 810 } 811 goto again; 812 } 813 } 814#endif 815 } 816 return (rval); 817} 818 819/* 820 * compat implementation of getpwnam() and getpwuid() 821 * varargs: type, [ uid (type == _PW_KEYBYUID) | name (type == _PW_KEYBYNAME) ] 822 */ 823static int _compat_getpw __P((void *, void *, va_list)); 824 825static int 826_compat_getpw(rv, cb_data, ap) 827 void *rv; 828 void *cb_data; 829 va_list ap; 830{ 831#ifdef _PASSWD_COMPAT 832 DBT key; 833 int search, rval, r, s, keynum; 834 uid_t uid; 835 char bf[sizeof(keynum) + 1]; 836 char *name, *host, *user, *dom; 837#endif 838 839 if (!_pw_db && !__initdb()) 840 return NS_UNAVAIL; 841 842 /* 843 * If there isn't a compat token in the database, use files. 844 */ 845#ifdef _PASSWD_COMPAT 846 if (! __has_compatpw()) 847#endif 848 return (_local_getpw(rv, cb_data, ap)); 849 850#ifdef _PASSWD_COMPAT 851 search = va_arg(ap, int); 852 uid = 0; 853 name = NULL; 854 rval = NS_NOTFOUND; 855 switch (search) { 856 case _PW_KEYBYNAME: 857 name = va_arg(ap, char *); 858 break; 859 case _PW_KEYBYUID: 860 uid = va_arg(ap, uid_t); 861 break; 862 default: 863 abort(); 864 } 865 866 for (s = -1, keynum = 1 ; ; keynum++) { 867 bf[0] = _PW_KEYBYNUM; 868 memmove(bf + 1, &keynum, sizeof(keynum)); 869 key.data = (u_char *)bf; 870 key.size = sizeof(keynum) + 1; 871 if(__hashpw(&key) != NS_SUCCESS) 872 break; 873 switch(_pw_passwd.pw_name[0]) { 874 case '+': 875 /* save the prototype */ 876 __pwproto_set(); 877 878 switch(_pw_passwd.pw_name[1]) { 879 case '\0': 880 r = __getpwcompat(search, uid, name); 881 if (r != NS_SUCCESS) 882 continue; 883 break; 884 case '@': 885pwnam_netgrp: 886#if 0 /* XXX: is this a hangover from pre-nsswitch? */ 887 if(__ypcurrent) { 888 free(__ypcurrent); 889 __ypcurrent = NULL; 890 } 891#endif 892 if (s == -1) /* first time */ 893 setnetgrent(_pw_passwd.pw_name + 2); 894 s = getnetgrent(&host, &user, &dom); 895 if (s == 0) { /* end of group */ 896 endnetgrent(); 897 s = -1; 898 continue; 899 } 900 if (!user || !*user) 901 goto pwnam_netgrp; 902 903 r = __getpwcompat(_PW_KEYBYNAME, 0, user); 904 905 if (r == NS_UNAVAIL) 906 return r; 907 if (r == NS_NOTFOUND) { 908 /* 909 * just because this user is bad 910 * it doesn't mean they all are. 911 */ 912 goto pwnam_netgrp; 913 } 914 break; 915 default: 916 user = _pw_passwd.pw_name + 1; 917 r = __getpwcompat(_PW_KEYBYNAME, 0, user); 918 919 if (r == NS_UNAVAIL) 920 return r; 921 if (r == NS_NOTFOUND) 922 continue; 923 break; 924 } 925 if(__pwexclude_is(_pw_passwd.pw_name)) { 926 if(s == 1) /* inside netgroup */ 927 goto pwnam_netgrp; 928 continue; 929 } 930 break; 931 case '-': 932 /* attempted exclusion */ 933 switch(_pw_passwd.pw_name[1]) { 934 case '\0': 935 break; 936 case '@': 937 setnetgrent(_pw_passwd.pw_name + 2); 938 while(getnetgrent(&host, &user, &dom)) { 939 if(user && *user) 940 __pwexclude_add(user); 941 } 942 endnetgrent(); 943 break; 944 default: 945 __pwexclude_add(_pw_passwd.pw_name + 1); 946 break; 947 } 948 break; 949 } 950 if ((search == _PW_KEYBYNAME && 951 strcmp(_pw_passwd.pw_name, name) == 0) 952 || (search == _PW_KEYBYUID && _pw_passwd.pw_uid == uid)) { 953 rval = NS_SUCCESS; 954 break; 955 } 956 if(s == 1) /* inside netgroup */ 957 goto pwnam_netgrp; 958 continue; 959 } 960 __pwproto = (struct passwd *)NULL; 961 962 if (!_pw_stayopen) { 963 (void)(_pw_db->close)(_pw_db); 964 _pw_db = (DB *)NULL; 965 } 966 if(__pwexclude != (DB *)NULL) { 967 (void)(__pwexclude->close)(__pwexclude); 968 __pwexclude = (DB *)NULL; 969 } 970 return rval; 971#endif /* _PASSWD_COMPAT */ 972} 973 974struct passwd * 975getpwent() 976{ 977 int r; 978 static const ns_dtab dtab[] = { 979 NS_FILES_CB(_local_getpw, NULL) 980 NS_DNS_CB(_dns_getpw, NULL) 981 NS_NIS_CB(_nis_getpw, NULL) 982 NS_COMPAT_CB(_compat_getpwent, NULL) 983 { 0 } 984 }; 985 986 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", compatsrc, 987 _PW_KEYBYNUM); 988 if (r != NS_SUCCESS) 989 return (struct passwd *)NULL; 990 return &_pw_passwd; 991} 992 993struct passwd * 994getpwnam(name) 995 const char *name; 996{ 997 int r; 998 static const ns_dtab dtab[] = { 999 NS_FILES_CB(_local_getpw, NULL) 1000 NS_DNS_CB(_dns_getpw, NULL) 1001 NS_NIS_CB(_nis_getpw, NULL) 1002 NS_COMPAT_CB(_compat_getpw, NULL) 1003 { 0 } 1004 }; 1005 1006 if (name == NULL || name[0] == '\0') 1007 return (struct passwd *)NULL; 1008 1009 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", compatsrc, 1010 _PW_KEYBYNAME, name); 1011 return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL); 1012} 1013 1014struct passwd * 1015getpwuid(uid) 1016 uid_t uid; 1017{ 1018 int r; 1019 static const ns_dtab dtab[] = { 1020 NS_FILES_CB(_local_getpw, NULL) 1021 NS_DNS_CB(_dns_getpw, NULL) 1022 NS_NIS_CB(_nis_getpw, NULL) 1023 NS_COMPAT_CB(_compat_getpw, NULL) 1024 { 0 } 1025 }; 1026 1027 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", compatsrc, 1028 _PW_KEYBYUID, uid); 1029 return (r == NS_SUCCESS ? &_pw_passwd : (struct passwd *)NULL); 1030} 1031 1032int 1033setpassent(stayopen) 1034 int stayopen; 1035{ 1036 _pw_keynum = 0; 1037 _pw_stayopen = stayopen; 1038#ifdef YP 1039 __pwmode = PWMODE_NONE; 1040 if(__ypcurrent) 1041 free(__ypcurrent); 1042 __ypcurrent = NULL; 1043 _pw_ypdone = 0; 1044#endif 1045#ifdef HESIOD 1046 _pw_hesnum = 0; 1047#endif 1048#ifdef _PASSWD_COMPAT 1049 if(__pwexclude != (DB *)NULL) { 1050 (void)(__pwexclude->close)(__pwexclude); 1051 __pwexclude = (DB *)NULL; 1052 } 1053 __pwproto = (struct passwd *)NULL; 1054#endif 1055 return 1; 1056} 1057 1058void 1059setpwent() 1060{ 1061 (void) setpassent(0); 1062} 1063 1064void 1065endpwent() 1066{ 1067 _pw_keynum = 0; 1068 if (_pw_db) { 1069 (void)(_pw_db->close)(_pw_db); 1070 _pw_db = (DB *)NULL; 1071 } 1072#ifdef _PASSWD_COMPAT 1073 __pwmode = PWMODE_NONE; 1074#endif 1075#ifdef YP 1076 if(__ypcurrent) 1077 free(__ypcurrent); 1078 __ypcurrent = NULL; 1079 _pw_ypdone = 0; 1080#endif 1081#ifdef HESIOD 1082 _pw_hesnum = 0; 1083#endif 1084#ifdef _PASSWD_COMPAT 1085 if(__pwexclude != (DB *)NULL) { 1086 (void)(__pwexclude->close)(__pwexclude); 1087 __pwexclude = (DB *)NULL; 1088 } 1089 __pwproto = (struct passwd *)NULL; 1090#endif 1091} 1092 1093static int 1094__initdb() 1095{ 1096 static int warned; 1097 char *p; 1098 1099#ifdef _PASSWD_COMPAT 1100 __pwmode = PWMODE_NONE; 1101#endif 1102 if (geteuid() == 0) { 1103 _pw_db = dbopen((p = _PATH_SMP_DB), O_RDONLY, 0, DB_HASH, NULL); 1104 if (_pw_db) 1105 return(1); 1106 } 1107 _pw_db = dbopen((p = _PATH_MP_DB), O_RDONLY, 0, DB_HASH, NULL); 1108 if (_pw_db) 1109 return 1; 1110 if (!warned) 1111 syslog(LOG_ERR, "%s: %m", p); 1112 warned = 1; 1113 return 0; 1114} 1115 1116static int 1117__hashpw(key) 1118 DBT *key; 1119{ 1120 char *p, *t; 1121 static u_int max; 1122 static char *buf; 1123 DBT data; 1124 1125 switch ((_pw_db->get)(_pw_db, key, &data, 0)) { 1126 case 0: 1127 break; /* found */ 1128 case 1: 1129 return NS_NOTFOUND; 1130 case -1: 1131 return NS_UNAVAIL; /* error in db routines */ 1132 default: 1133 abort(); 1134 } 1135 1136 p = (char *)data.data; 1137 if (data.size > max && !(buf = realloc(buf, (max += 1024)))) 1138 return NS_UNAVAIL; 1139 1140 /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ 1141 t = buf; 1142#define EXPAND(e) e = t; while ((*t++ = *p++)); 1143#define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v 1144 EXPAND(_pw_passwd.pw_name); 1145 EXPAND(_pw_passwd.pw_passwd); 1146 SCALAR(_pw_passwd.pw_uid); 1147 SCALAR(_pw_passwd.pw_gid); 1148 SCALAR(_pw_passwd.pw_change); 1149 EXPAND(_pw_passwd.pw_class); 1150 EXPAND(_pw_passwd.pw_gecos); 1151 EXPAND(_pw_passwd.pw_dir); 1152 EXPAND(_pw_passwd.pw_shell); 1153 SCALAR(_pw_passwd.pw_expire); 1154 SCALAR(_pw_passwd.pw_fields); 1155 1156 return NS_SUCCESS; 1157} 1158