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