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