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