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