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