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