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