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