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