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