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