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