1/* $NetBSD: getpwent.c,v 1.76 2009/01/11 02:46:27 christos Exp $ */ 2 3/*- 4 * Copyright (c) 1997-2000, 2004-2005 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Luke Mewburn. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32/* 33 * Copyright (c) 1988, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 */ 60 61/* 62 * Portions Copyright (c) 1994, 1995, Jason Downs. All rights reserved. 63 * 64 * Redistribution and use in source and binary forms, with or without 65 * modification, are permitted provided that the following conditions 66 * are met: 67 * 1. Redistributions of source code must retain the above copyright 68 * notice, this list of conditions and the following disclaimer. 69 * 2. Redistributions in binary form must reproduce the above copyright 70 * notice, this list of conditions and the following disclaimer in the 71 * documentation and/or other materials provided with the distribution. 72 * 73 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 74 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 75 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 76 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, 77 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 78 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 79 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 80 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 81 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 82 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 83 * SUCH DAMAGE. 84 */ 85 86#include <sys/cdefs.h> 87#if defined(LIBC_SCCS) && !defined(lint) 88#if 0 89static char sccsid[] = "@(#)getpwent.c 8.2 (Berkeley) 4/27/95"; 90#else 91__RCSID("$NetBSD: getpwent.c,v 1.76 2009/01/11 02:46:27 christos Exp $"); 92#endif 93#endif /* LIBC_SCCS and not lint */ 94 95#include "namespace.h" 96#include "reentrant.h" 97 98#include <sys/param.h> 99 100#include <assert.h> 101#include <db.h> 102#include <errno.h> 103#include <fcntl.h> 104#include <limits.h> 105#include <netgroup.h> 106#include <nsswitch.h> 107#include <pwd.h> 108#include <stdarg.h> 109#include <stdio.h> 110#include <stdlib.h> 111#include <string.h> 112#include <syslog.h> 113#include <unistd.h> 114 115#ifdef HESIOD 116#include <hesiod.h> 117#endif 118 119#ifdef YP 120#include <machine/param.h> 121#include <rpc/rpc.h> 122#include <rpcsvc/yp_prot.h> 123#include <rpcsvc/ypclnt.h> 124#endif 125 126#include "pw_private.h" 127 128#define _PASSWD_COMPAT /* "passwd" defaults to compat, so always provide it */ 129 130#ifdef __weak_alias 131__weak_alias(endpwent,_endpwent) 132__weak_alias(setpassent,_setpassent) 133__weak_alias(setpwent,_setpwent) 134#endif 135 136#ifdef _REENTRANT 137static mutex_t _pwmutex = MUTEX_INITIALIZER; 138#endif 139 140const char __yp_token[] = "__YP!"; /* Let pwd_mkdb pull this in. */ 141 142 143/* 144 * The pwd.db lookup techniques and data extraction code here must be kept 145 * in sync with that in `pwd_mkdb'. 146 */ 147 148#if defined(YP) || defined(HESIOD) 149/* 150 * _pw_parse 151 * Parses entry using pw_scan(3) (without the trailing \n) 152 * after copying to buf, and fills in pw with corresponding values. 153 * If old is non-zero, entry is in _PASSWORD_OLDFMT. 154 * Returns 1 if parsed successfully, 0 on parse failure. 155 */ 156static int 157_pw_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen, 158 int old) 159{ 160 int flags; 161 162 _DIAGASSERT(entry != NULL); 163 _DIAGASSERT(pw != NULL); 164 _DIAGASSERT(buf != NULL); 165 166 if (strlcpy(buf, entry, buflen) >= buflen) 167 return 0; 168 flags = _PASSWORD_NOWARN; 169 if (old) 170 flags |= _PASSWORD_OLDFMT; 171 return __pw_scan(buf, pw, &flags); 172} 173#endif /* YP || HESIOD */ 174 175/* 176 * _pw_opendb 177 * if *db is NULL, dbopen(3) /etc/spwd.db or /etc/pwd.db (depending 178 * upon permissions, etc) 179 */ 180static int 181_pw_opendb(DB **db, int *version) 182{ 183 static int warned; 184 DBT key; 185 DBT value; 186 187 const char *dbfile = NULL; 188 189 _DIAGASSERT(db != NULL); 190 _DIAGASSERT(version != NULL); 191 if (*db != NULL) /* open *db */ 192 return NS_SUCCESS; 193 194 if (geteuid() == 0) { 195 dbfile = _PATH_SMP_DB; 196 *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL); 197 } 198 if (*db == NULL) { 199 dbfile = _PATH_MP_DB; 200 *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL); 201 } 202 if (*db == NULL) { 203 if (!warned) { 204 int serrno = errno; 205 syslog(LOG_ERR, "%s: %m", dbfile); 206 errno = serrno; 207 } 208 warned = 1; 209 return NS_UNAVAIL; 210 } 211 key.data = __UNCONST("VERSION"); 212 key.size = strlen((char *)key.data) + 1; 213 switch ((*(*db)->get)(*db, &key, &value, 0)) { 214 case 0: 215 if (sizeof(*version) != value.size) 216 return NS_UNAVAIL; 217 (void)memcpy(version, value.data, value.size); 218 break; /* found */ 219 case 1: 220 *version = 0; /* not found */ 221 break; 222 case -1: 223 return NS_UNAVAIL; /* error in db routines */ 224 default: 225 abort(); 226 } 227 return NS_SUCCESS; 228} 229 230/* 231 * _pw_getkey 232 * Lookup key in *db, filling in pw 233 * with the result, allocating memory from buffer (size buflen). 234 * (The caller may point key.data to buffer on entry; the contents 235 * of key.data will be invalid on exit.) 236 */ 237static int 238_pw_getkey(DB *db, DBT *key, 239 struct passwd *pw, char *buffer, size_t buflen, int *pwflags, 240 int version) 241{ 242 char *p, *t; 243 DBT data; 244 245 _DIAGASSERT(db != NULL); 246 _DIAGASSERT(key != NULL); 247 _DIAGASSERT(pw != NULL); 248 _DIAGASSERT(buffer != NULL); 249 /* pwflags may be NULL (if we don't care about them */ 250 251 if (db == NULL) /* this shouldn't happen */ 252 return NS_UNAVAIL; 253 254 switch ((db->get)(db, key, &data, 0)) { 255 case 0: 256 break; /* found */ 257 case 1: 258 return NS_NOTFOUND; /* not found */ 259 case -1: 260 return NS_UNAVAIL; /* error in db routines */ 261 default: 262 abort(); 263 } 264 265 p = (char *)data.data; 266 if (data.size > buflen) { 267 errno = ERANGE; 268 return NS_UNAVAIL; 269 } 270 271 /* 272 * THE DECODING BELOW MUST MATCH THAT IN pwd_mkdb. 273 */ 274 t = buffer; 275#define MACRO(a) do { a } while (/*CONSTCOND*/0) 276#define EXPAND(e) MACRO(e = t; while ((*t++ = *p++));) 277#define SCALAR(v) MACRO(memmove(&(v), p, sizeof v); p += sizeof v;) 278 EXPAND(pw->pw_name); 279 EXPAND(pw->pw_passwd); 280 SCALAR(pw->pw_uid); 281 SCALAR(pw->pw_gid); 282 if (version == 0) { 283 int32_t tmp; 284 SCALAR(tmp); 285 pw->pw_change = tmp; 286 } else 287 SCALAR(pw->pw_change); 288 EXPAND(pw->pw_class); 289 EXPAND(pw->pw_gecos); 290 EXPAND(pw->pw_dir); 291 EXPAND(pw->pw_shell); 292 if (version == 0) { 293 int32_t tmp; 294 SCALAR(tmp); 295 pw->pw_expire = tmp; 296 } else 297 SCALAR(pw->pw_expire); 298 if (pwflags) { 299 /* See if there's any data left. If so, read in flags. */ 300 if (data.size > (size_t) (p - (char *)data.data)) { 301 SCALAR(*pwflags); 302 } else { /* default */ 303 *pwflags = _PASSWORD_NOUID|_PASSWORD_NOGID; 304 } 305 } 306 307 return NS_SUCCESS; 308} 309 310/* 311 * _pw_memfrombuf 312 * Obtain want bytes from buffer (of size buflen) and return a pointer 313 * to the available memory after adjusting buffer/buflen. 314 * Returns NULL if there is insufficient space. 315 */ 316static char * 317_pw_memfrombuf(size_t want, char **buffer, size_t *buflen) 318{ 319 char *rv; 320 321 if (want > *buflen) { 322 errno = ERANGE; 323 return NULL; 324 } 325 rv = *buffer; 326 *buffer += want; 327 *buflen -= want; 328 return rv; 329} 330 331/* 332 * _pw_copy 333 * Copy the contents of frompw to pw; memory for strings 334 * and arrays will be allocated from buf (of size buflen). 335 * If proto != NULL, use various fields in proto in preference to frompw. 336 * Returns 1 if copied successfully, 0 on copy failure. 337 * NOTE: frompw must not use buf for its own pointers. 338 */ 339static int 340_pw_copy(const struct passwd *frompw, struct passwd *pw, 341 char *buf, size_t buflen, const struct passwd *protopw, int protoflags) 342{ 343 size_t count; 344 int useproto; 345 346 _DIAGASSERT(frompw != NULL); 347 _DIAGASSERT(pw != NULL); 348 _DIAGASSERT(buf != NULL); 349 /* protopw may be NULL */ 350 351 useproto = protopw && protopw->pw_name; 352 353#define COPYSTR(to, from) \ 354 do { \ 355 count = strlen((from)); \ 356 (to) = _pw_memfrombuf(count+1, &buf, &buflen); \ 357 if ((to) == NULL) \ 358 return 0; \ 359 memmove((to), (from), count); \ 360 to[count] = '\0'; \ 361 } while (0) /* LINTED */ 362 363#define COPYFIELD(field) COPYSTR(pw->field, frompw->field) 364 365#define COPYPROTOFIELD(field) COPYSTR(pw->field, \ 366 (useproto && *protopw->field ? protopw->field : frompw->field)) 367 368 COPYFIELD(pw_name); 369 370#ifdef PW_OVERRIDE_PASSWD 371 COPYPROTOFIELD(pw_passwd); 372#else 373 COPYFIELD(pw_passwd); 374#endif 375 376 if (useproto && !(protoflags & _PASSWORD_NOUID)) 377 pw->pw_uid = protopw->pw_uid; 378 else 379 pw->pw_uid = frompw->pw_uid; 380 381 if (useproto && !(protoflags & _PASSWORD_NOGID)) 382 pw->pw_gid = protopw->pw_gid; 383 else 384 pw->pw_gid = frompw->pw_gid; 385 386 pw->pw_change = frompw->pw_change; 387 COPYFIELD(pw_class); 388 COPYPROTOFIELD(pw_gecos); 389 COPYPROTOFIELD(pw_dir); 390 COPYPROTOFIELD(pw_shell); 391 392#undef COPYSTR 393#undef COPYFIELD 394#undef COPYPROTOFIELD 395 396 return 1; 397} 398 399 400 /* 401 * files methods 402 */ 403 404 /* state shared between files methods */ 405struct files_state { 406 int stayopen; /* see getpassent(3) */ 407 DB *db; /* passwd file handle */ 408 int keynum; /* key counter, -1 if no more */ 409 int version; 410}; 411 412static struct files_state _files_state; 413 /* storage for non _r functions */ 414static struct passwd _files_passwd; 415static char _files_passwdbuf[_GETPW_R_SIZE_MAX]; 416 417static int 418_files_start(struct files_state *state) 419{ 420 int rv; 421 422 _DIAGASSERT(state != NULL); 423 424 state->keynum = 0; 425 rv = _pw_opendb(&state->db, &state->version); 426 if (rv != NS_SUCCESS) 427 return rv; 428 return NS_SUCCESS; 429} 430 431static int 432_files_end(struct files_state *state) 433{ 434 435 _DIAGASSERT(state != NULL); 436 437 state->keynum = 0; 438 if (state->db) { 439 (void)(state->db->close)(state->db); 440 state->db = NULL; 441 } 442 return NS_SUCCESS; 443} 444 445/* 446 * _files_pwscan 447 * Search state->db for the next desired entry. 448 * If search is _PW_KEYBYNUM, look for state->keynum. 449 * If search is _PW_KEYBYNAME, look for name. 450 * If search is _PW_KEYBYUID, look for uid. 451 * Sets *retval to the errno if the result is not NS_SUCCESS 452 * or NS_NOTFOUND. 453 */ 454static int 455_files_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 456 struct files_state *state, int search, const char *name, uid_t uid) 457{ 458 const void *from; 459 size_t fromlen; 460 DBT key; 461 int rv; 462 463 _DIAGASSERT(retval != NULL); 464 _DIAGASSERT(pw != NULL); 465 _DIAGASSERT(buffer != NULL); 466 _DIAGASSERT(state != NULL); 467 /* name is NULL to indicate searching for uid */ 468 469 *retval = 0; 470 471 if (state->db == NULL) { /* only start if file not open yet */ 472 rv = _files_start(state); 473 if (rv != NS_SUCCESS) 474 goto filespwscan_out; 475 } 476 477 for (;;) { /* search for a match */ 478 switch (search) { 479 case _PW_KEYBYNUM: 480 if (state->keynum == -1) 481 return NS_NOTFOUND; /* no more records */ 482 state->keynum++; 483 from = &state->keynum; 484 fromlen = sizeof(state->keynum); 485 break; 486 case _PW_KEYBYNAME: 487 from = name; 488 fromlen = strlen(name); 489 break; 490 case _PW_KEYBYUID: 491 from = &uid; 492 fromlen = sizeof(uid); 493 break; 494 default: 495 abort(); 496 } 497 498 if (buflen <= fromlen) { /* buffer too small */ 499 *retval = ERANGE; 500 return NS_UNAVAIL; 501 } 502 buffer[0] = search; /* setup key */ 503 memmove(buffer + 1, from, fromlen); 504 key.size = fromlen + 1; 505 key.data = (u_char *)buffer; 506 507 /* search for key */ 508 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, NULL, 509 state->version); 510 if (rv != NS_SUCCESS) /* no match */ 511 break; 512 if (pw->pw_name[0] == '+' || pw->pw_name[0] == '-') { 513 /* if a compat line */ 514 if (search == _PW_KEYBYNUM) 515 continue; /* read next if pwent */ 516 rv = NS_NOTFOUND; /* don't match if pw{nam,uid} */ 517 break; 518 } 519 break; 520 } 521 522 if (rv == NS_NOTFOUND && search == _PW_KEYBYNUM) 523 state->keynum = -1; /* flag `no more records' */ 524 525 if (rv == NS_SUCCESS) { 526 if ((search == _PW_KEYBYUID && pw->pw_uid != uid) || 527 (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0)) 528 rv = NS_NOTFOUND; 529 } 530 531 filespwscan_out: 532 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 533 *retval = errno; 534 return rv; 535} 536 537/*ARGSUSED*/ 538static int 539_files_setpwent(void *nsrv, void *nscb, va_list ap) 540{ 541 542 _files_state.stayopen = 0; 543 return _files_start(&_files_state); 544} 545 546/*ARGSUSED*/ 547static int 548_files_setpassent(void *nsrv, void *nscb, va_list ap) 549{ 550 int *retval = va_arg(ap, int *); 551 int stayopen = va_arg(ap, int); 552 553 int rv; 554 555 _files_state.stayopen = stayopen; 556 rv = _files_start(&_files_state); 557 *retval = (rv == NS_SUCCESS); 558 return rv; 559} 560 561/*ARGSUSED*/ 562static int 563_files_endpwent(void *nsrv, void *nscb, va_list ap) 564{ 565 566 _files_state.stayopen = 0; 567 return _files_end(&_files_state); 568} 569 570/*ARGSUSED*/ 571static int 572_files_getpwent(void *nsrv, void *nscb, va_list ap) 573{ 574 struct passwd **retval = va_arg(ap, struct passwd **); 575 576 int rv, rerror; 577 578 _DIAGASSERT(retval != NULL); 579 580 *retval = NULL; 581 rv = _files_pwscan(&rerror, &_files_passwd, 582 _files_passwdbuf, sizeof(_files_passwdbuf), 583 &_files_state, _PW_KEYBYNUM, NULL, 0); 584 if (rv == NS_SUCCESS) 585 *retval = &_files_passwd; 586 return rv; 587} 588 589/*ARGSUSED*/ 590static int 591_files_getpwent_r(void *nsrv, void *nscb, va_list ap) 592{ 593 int *retval = va_arg(ap, int *); 594 struct passwd *pw = va_arg(ap, struct passwd *); 595 char *buffer = va_arg(ap, char *); 596 size_t buflen = va_arg(ap, size_t); 597 struct passwd **result = va_arg(ap, struct passwd **); 598 599 int rv; 600 601 _DIAGASSERT(retval != NULL); 602 _DIAGASSERT(pw != NULL); 603 _DIAGASSERT(buffer != NULL); 604 _DIAGASSERT(result != NULL); 605 606 rv = _files_pwscan(retval, pw, buffer, buflen, &_files_state, 607 _PW_KEYBYNUM, NULL, 0); 608 if (rv == NS_SUCCESS) 609 *result = pw; 610 else 611 *result = NULL; 612 return rv; 613} 614 615/*ARGSUSED*/ 616static int 617_files_getpwnam(void *nsrv, void *nscb, va_list ap) 618{ 619 struct passwd **retval = va_arg(ap, struct passwd **); 620 const char *name = va_arg(ap, const char *); 621 622 int rv, rerror; 623 624 _DIAGASSERT(retval != NULL); 625 626 *retval = NULL; 627 rv = _files_start(&_files_state); 628 if (rv != NS_SUCCESS) 629 return rv; 630 rv = _files_pwscan(&rerror, &_files_passwd, 631 _files_passwdbuf, sizeof(_files_passwdbuf), 632 &_files_state, _PW_KEYBYNAME, name, 0); 633 if (!_files_state.stayopen) 634 _files_end(&_files_state); 635 if (rv == NS_SUCCESS) 636 *retval = &_files_passwd; 637 return rv; 638} 639 640/*ARGSUSED*/ 641static int 642_files_getpwnam_r(void *nsrv, void *nscb, va_list ap) 643{ 644 int *retval = va_arg(ap, int *); 645 const char *name = va_arg(ap, const char *); 646 struct passwd *pw = va_arg(ap, struct passwd *); 647 char *buffer = va_arg(ap, char *); 648 size_t buflen = va_arg(ap, size_t); 649 struct passwd **result = va_arg(ap, struct passwd **); 650 651 struct files_state state; 652 int rv; 653 654 _DIAGASSERT(retval != NULL); 655 _DIAGASSERT(pw != NULL); 656 _DIAGASSERT(buffer != NULL); 657 _DIAGASSERT(result != NULL); 658 659 *result = NULL; 660 memset(&state, 0, sizeof(state)); 661 rv = _files_pwscan(retval, pw, buffer, buflen, &state, 662 _PW_KEYBYNAME, name, 0); 663 _files_end(&state); 664 if (rv == NS_SUCCESS) 665 *result = pw; 666 return rv; 667} 668 669/*ARGSUSED*/ 670static int 671_files_getpwuid(void *nsrv, void *nscb, va_list ap) 672{ 673 struct passwd **retval = va_arg(ap, struct passwd **); 674 uid_t uid = va_arg(ap, uid_t); 675 676 int rv, rerror; 677 678 _DIAGASSERT(retval != NULL); 679 680 *retval = NULL; 681 rv = _files_start(&_files_state); 682 if (rv != NS_SUCCESS) 683 return rv; 684 rv = _files_pwscan(&rerror, &_files_passwd, 685 _files_passwdbuf, sizeof(_files_passwdbuf), 686 &_files_state, _PW_KEYBYUID, NULL, uid); 687 if (!_files_state.stayopen) 688 _files_end(&_files_state); 689 if (rv == NS_SUCCESS) 690 *retval = &_files_passwd; 691 return rv; 692} 693 694/*ARGSUSED*/ 695static int 696_files_getpwuid_r(void *nsrv, void *nscb, va_list ap) 697{ 698 int *retval = va_arg(ap, int *); 699 uid_t uid = va_arg(ap, uid_t); 700 struct passwd *pw = va_arg(ap, struct passwd *); 701 char *buffer = va_arg(ap, char *); 702 size_t buflen = va_arg(ap, size_t); 703 struct passwd **result = va_arg(ap, struct passwd **); 704 705 struct files_state state; 706 int rv; 707 708 _DIAGASSERT(retval != NULL); 709 _DIAGASSERT(pw != NULL); 710 _DIAGASSERT(buffer != NULL); 711 _DIAGASSERT(result != NULL); 712 713 *result = NULL; 714 memset(&state, 0, sizeof(state)); 715 rv = _files_pwscan(retval, pw, buffer, buflen, &state, 716 _PW_KEYBYUID, NULL, uid); 717 _files_end(&state); 718 if (rv == NS_SUCCESS) 719 *result = pw; 720 return rv; 721} 722 723 724#ifdef HESIOD 725 /* 726 * dns methods 727 */ 728 729 /* state shared between dns methods */ 730struct dns_state { 731 int stayopen; /* see getpassent(3) */ 732 void *context; /* Hesiod context */ 733 int num; /* passwd index, -1 if no more */ 734}; 735 736static struct dns_state _dns_state; 737 /* storage for non _r functions */ 738static struct passwd _dns_passwd; 739static char _dns_passwdbuf[_GETPW_R_SIZE_MAX]; 740 741static int 742_dns_start(struct dns_state *state) 743{ 744 745 _DIAGASSERT(state != NULL); 746 747 state->num = 0; 748 if (state->context == NULL) { /* setup Hesiod */ 749 if (hesiod_init(&state->context) == -1) 750 return NS_UNAVAIL; 751 } 752 753 return NS_SUCCESS; 754} 755 756static int 757_dns_end(struct dns_state *state) 758{ 759 760 _DIAGASSERT(state != NULL); 761 762 state->num = 0; 763 if (state->context) { 764 hesiod_end(state->context); 765 state->context = NULL; 766 } 767 return NS_SUCCESS; 768} 769 770/* 771 * _dns_pwscan 772 * Look for the Hesiod name provided in buffer in the NULL-terminated 773 * list of zones, 774 * and decode into pw/buffer/buflen. 775 */ 776static int 777_dns_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 778 struct dns_state *state, const char **zones) 779{ 780 const char **curzone; 781 char **hp, *ep; 782 int rv; 783 784 _DIAGASSERT(retval != NULL); 785 _DIAGASSERT(pw != NULL); 786 _DIAGASSERT(buffer != NULL); 787 _DIAGASSERT(state != NULL); 788 _DIAGASSERT(zones != NULL); 789 790 *retval = 0; 791 792 if (state->context == NULL) { /* only start if Hesiod not setup */ 793 rv = _dns_start(state); 794 if (rv != NS_SUCCESS) 795 return rv; 796 } 797 798 hp = NULL; 799 rv = NS_NOTFOUND; 800 801 for (curzone = zones; *curzone; curzone++) { /* search zones */ 802 hp = hesiod_resolve(state->context, buffer, *curzone); 803 if (hp != NULL) 804 break; 805 if (errno != ENOENT) { 806 rv = NS_UNAVAIL; 807 goto dnspwscan_out; 808 } 809 } 810 if (*curzone == NULL) 811 goto dnspwscan_out; 812 813 if ((ep = strchr(hp[0], '\n')) != NULL) 814 *ep = '\0'; /* clear trailing \n */ 815 if (_pw_parse(hp[0], pw, buffer, buflen, 1)) /* validate line */ 816 rv = NS_SUCCESS; 817 else 818 rv = NS_UNAVAIL; 819 820 dnspwscan_out: 821 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 822 *retval = errno; 823 if (hp) 824 hesiod_free_list(state->context, hp); 825 return rv; 826} 827 828/*ARGSUSED*/ 829static int 830_dns_setpwent(void *nsrv, void *nscb, va_list ap) 831{ 832 833 _dns_state.stayopen = 0; 834 return _dns_start(&_dns_state); 835} 836 837/*ARGSUSED*/ 838static int 839_dns_setpassent(void *nsrv, void *nscb, va_list ap) 840{ 841 int *retval = va_arg(ap, int *); 842 int stayopen = va_arg(ap, int); 843 844 int rv; 845 846 _dns_state.stayopen = stayopen; 847 rv = _dns_start(&_dns_state); 848 *retval = (rv == NS_SUCCESS); 849 return rv; 850} 851 852/*ARGSUSED*/ 853static int 854_dns_endpwent(void *nsrv, void *nscb, va_list ap) 855{ 856 857 _dns_state.stayopen = 0; 858 return _dns_end(&_dns_state); 859} 860 861/*ARGSUSED*/ 862static int 863_dns_getpwent(void *nsrv, void *nscb, va_list ap) 864{ 865 struct passwd **retval = va_arg(ap, struct passwd **); 866 867 char **hp, *ep; 868 int rv; 869 870 _DIAGASSERT(retval != NULL); 871 872 *retval = NULL; 873 874 if (_dns_state.num == -1) /* exhausted search */ 875 return NS_NOTFOUND; 876 877 if (_dns_state.context == NULL) { 878 /* only start if Hesiod not setup */ 879 rv = _dns_start(&_dns_state); 880 if (rv != NS_SUCCESS) 881 return rv; 882 } 883 884 next_dns_entry: 885 hp = NULL; 886 rv = NS_NOTFOUND; 887 888 /* find passwd-NNN */ 889 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), 890 "passwd-%u", _dns_state.num); 891 _dns_state.num++; 892 893 hp = hesiod_resolve(_dns_state.context, _dns_passwdbuf, "passwd"); 894 if (hp == NULL) { 895 if (errno == ENOENT) 896 _dns_state.num = -1; 897 else 898 rv = NS_UNAVAIL; 899 } else { 900 if ((ep = strchr(hp[0], '\n')) != NULL) 901 *ep = '\0'; /* clear trailing \n */ 902 /* validate line */ 903 if (_pw_parse(hp[0], &_dns_passwd, 904 _dns_passwdbuf, sizeof(_dns_passwdbuf), 1)) 905 rv = NS_SUCCESS; 906 else { /* dodgy entry, try again */ 907 hesiod_free_list(_dns_state.context, hp); 908 goto next_dns_entry; 909 } 910 } 911 912 if (hp) 913 hesiod_free_list(_dns_state.context, hp); 914 if (rv == NS_SUCCESS) 915 *retval = &_dns_passwd; 916 return rv; 917} 918 919/*ARGSUSED*/ 920static int 921_dns_getpwent_r(void *nsrv, void *nscb, va_list ap) 922{ 923 int *retval = va_arg(ap, int *); 924 struct passwd *pw = va_arg(ap, struct passwd *); 925 char *buffer = va_arg(ap, char *); 926 size_t buflen = va_arg(ap, size_t); 927 struct passwd **result = va_arg(ap, struct passwd **); 928 929 char **hp, *ep; 930 int rv; 931 932 _DIAGASSERT(retval != NULL); 933 _DIAGASSERT(pw != NULL); 934 _DIAGASSERT(buffer != NULL); 935 _DIAGASSERT(result != NULL); 936 937 *retval = 0; 938 939 if (_dns_state.num == -1) /* exhausted search */ 940 return NS_NOTFOUND; 941 942 if (_dns_state.context == NULL) { 943 /* only start if Hesiod not setup */ 944 rv = _dns_start(&_dns_state); 945 if (rv != NS_SUCCESS) 946 return rv; 947 } 948 949 next_dns_entry: 950 hp = NULL; 951 rv = NS_NOTFOUND; 952 953 /* find passwd-NNN */ 954 snprintf(buffer, buflen, "passwd-%u", _dns_state.num); 955 _dns_state.num++; 956 957 hp = hesiod_resolve(_dns_state.context, buffer, "passwd"); 958 if (hp == NULL) { 959 if (errno == ENOENT) 960 _dns_state.num = -1; 961 else 962 rv = NS_UNAVAIL; 963 } else { 964 if ((ep = strchr(hp[0], '\n')) != NULL) 965 *ep = '\0'; /* clear trailing \n */ 966 /* validate line */ 967 if (_pw_parse(hp[0], pw, buffer, buflen, 1)) 968 rv = NS_SUCCESS; 969 else { /* dodgy entry, try again */ 970 hesiod_free_list(_dns_state.context, hp); 971 goto next_dns_entry; 972 } 973 } 974 975 if (hp) 976 hesiod_free_list(_dns_state.context, hp); 977 if (rv == NS_SUCCESS) 978 *result = pw; 979 else 980 *result = NULL; 981 return rv; 982} 983 984static const char *_dns_uid_zones[] = { 985 "uid", 986 "passwd", 987 NULL 988}; 989 990/*ARGSUSED*/ 991static int 992_dns_getpwuid(void *nsrv, void *nscb, va_list ap) 993{ 994 struct passwd **retval = va_arg(ap, struct passwd **); 995 uid_t uid = va_arg(ap, uid_t); 996 997 int rv, rerror; 998 999 _DIAGASSERT(retval != NULL); 1000 1001 *retval = NULL; 1002 rv = _dns_start(&_dns_state); 1003 if (rv != NS_SUCCESS) 1004 return rv; 1005 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), 1006 "%u", (unsigned int)uid); 1007 rv = _dns_pwscan(&rerror, &_dns_passwd, 1008 _dns_passwdbuf, sizeof(_dns_passwdbuf), 1009 &_dns_state, _dns_uid_zones); 1010 if (!_dns_state.stayopen) 1011 _dns_end(&_dns_state); 1012 if (rv == NS_SUCCESS && uid == _dns_passwd.pw_uid) 1013 *retval = &_dns_passwd; 1014 return rv; 1015} 1016 1017/*ARGSUSED*/ 1018static int 1019_dns_getpwuid_r(void *nsrv, void *nscb, va_list ap) 1020{ 1021 int *retval = va_arg(ap, int *); 1022 uid_t uid = va_arg(ap, uid_t); 1023 struct passwd *pw = va_arg(ap, struct passwd *); 1024 char *buffer = va_arg(ap, char *); 1025 size_t buflen = va_arg(ap, size_t); 1026 struct passwd **result = va_arg(ap, struct passwd **); 1027 1028 struct dns_state state; 1029 int rv; 1030 1031 _DIAGASSERT(retval != NULL); 1032 _DIAGASSERT(pw != NULL); 1033 _DIAGASSERT(buffer != NULL); 1034 _DIAGASSERT(result != NULL); 1035 1036 *result = NULL; 1037 memset(&state, 0, sizeof(state)); 1038 snprintf(buffer, buflen, "%u", (unsigned int)uid); 1039 rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_uid_zones); 1040 _dns_end(&state); 1041 if (rv != NS_SUCCESS) 1042 return rv; 1043 if (uid == pw->pw_uid) { 1044 *result = pw; 1045 return NS_SUCCESS; 1046 } else 1047 return NS_NOTFOUND; 1048} 1049 1050static const char *_dns_nam_zones[] = { 1051 "passwd", 1052 NULL 1053}; 1054 1055/*ARGSUSED*/ 1056static int 1057_dns_getpwnam(void *nsrv, void *nscb, va_list ap) 1058{ 1059 struct passwd **retval = va_arg(ap, struct passwd **); 1060 const char *name = va_arg(ap, const char *); 1061 1062 int rv, rerror; 1063 1064 _DIAGASSERT(retval != NULL); 1065 1066 *retval = NULL; 1067 rv = _dns_start(&_dns_state); 1068 if (rv != NS_SUCCESS) 1069 return rv; 1070 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), "%s", name); 1071 rv = _dns_pwscan(&rerror, &_dns_passwd, 1072 _dns_passwdbuf, sizeof(_dns_passwdbuf), 1073 &_dns_state, _dns_nam_zones); 1074 if (!_dns_state.stayopen) 1075 _dns_end(&_dns_state); 1076 if (rv == NS_SUCCESS && strcmp(name, _dns_passwd.pw_name) == 0) 1077 *retval = &_dns_passwd; 1078 return rv; 1079} 1080 1081/*ARGSUSED*/ 1082static int 1083_dns_getpwnam_r(void *nsrv, void *nscb, va_list ap) 1084{ 1085 int *retval = va_arg(ap, int *); 1086 const char *name = va_arg(ap, const char *); 1087 struct passwd *pw = va_arg(ap, struct passwd *); 1088 char *buffer = va_arg(ap, char *); 1089 size_t buflen = va_arg(ap, size_t); 1090 struct passwd **result = va_arg(ap, struct passwd **); 1091 1092 struct dns_state state; 1093 int rv; 1094 1095 _DIAGASSERT(retval != NULL); 1096 _DIAGASSERT(pw != NULL); 1097 _DIAGASSERT(buffer != NULL); 1098 _DIAGASSERT(result != NULL); 1099 1100 *result = NULL; 1101 memset(&state, 0, sizeof(state)); 1102 snprintf(buffer, buflen, "%s", name); 1103 rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_nam_zones); 1104 _dns_end(&state); 1105 if (rv != NS_SUCCESS) 1106 return rv; 1107 if (strcmp(name, pw->pw_name) == 0) { 1108 *result = pw; 1109 return NS_SUCCESS; 1110 } else 1111 return NS_NOTFOUND; 1112} 1113 1114#endif /* HESIOD */ 1115 1116 1117#ifdef YP 1118 /* 1119 * nis methods 1120 */ 1121 /* state shared between nis methods */ 1122struct nis_state { 1123 int stayopen; /* see getpassent(3) */ 1124 char *domain; /* NIS domain */ 1125 int done; /* non-zero if search exhausted */ 1126 char *current; /* current first/next match */ 1127 int currentlen; /* length of _nis_current */ 1128 enum { /* shadow map type */ 1129 NISMAP_UNKNOWN, /* unknown ... */ 1130 NISMAP_NONE, /* none: use "passwd.by*" */ 1131 NISMAP_ADJUNCT, /* pw_passwd from "passwd.adjunct.*" */ 1132 NISMAP_MASTER /* all from "master.passwd.by*" */ 1133 } maptype; 1134}; 1135 1136static struct nis_state _nis_state; 1137 /* storage for non _r functions */ 1138static struct passwd _nis_passwd; 1139static char _nis_passwdbuf[_GETPW_R_SIZE_MAX]; 1140 1141 /* macros for deciding which NIS maps to use. */ 1142#define PASSWD_BYNAME(x) ((x)->maptype == NISMAP_MASTER \ 1143 ? "master.passwd.byname" : "passwd.byname") 1144#define PASSWD_BYUID(x) ((x)->maptype == NISMAP_MASTER \ 1145 ? "master.passwd.byuid" : "passwd.byuid") 1146 1147static int 1148_nis_start(struct nis_state *state) 1149{ 1150 1151 _DIAGASSERT(state != NULL); 1152 1153 state->done = 0; 1154 if (state->current) { 1155 free(state->current); 1156 state->current = NULL; 1157 } 1158 if (state->domain == NULL) { /* setup NIS */ 1159 switch (yp_get_default_domain(&state->domain)) { 1160 case 0: 1161 break; 1162 case YPERR_RESRC: 1163 return NS_TRYAGAIN; 1164 default: 1165 return NS_UNAVAIL; 1166 } 1167 } 1168 1169 /* determine where to get pw_passwd from */ 1170 if (state->maptype == NISMAP_UNKNOWN) { 1171 int r, order; 1172 1173 state->maptype = NISMAP_NONE; /* default to no adjunct */ 1174 if (geteuid() != 0) /* non-root can't use adjunct */ 1175 return NS_SUCCESS; 1176 1177 /* look for "master.passwd.*" */ 1178 r = yp_order(state->domain, "master.passwd.byname", &order); 1179 if (r == 0) { 1180 state->maptype = NISMAP_MASTER; 1181 return NS_SUCCESS; 1182 } 1183 1184 /* master.passwd doesn't exist, try passwd.adjunct */ 1185 if (r == YPERR_MAP) { 1186 r = yp_order(state->domain, "passwd.adjunct.byname", 1187 &order); 1188 if (r == 0) 1189 state->maptype = NISMAP_ADJUNCT; 1190 } 1191 } 1192 return NS_SUCCESS; 1193} 1194 1195static int 1196_nis_end(struct nis_state *state) 1197{ 1198 1199 _DIAGASSERT(state != NULL); 1200 1201 if (state->domain) 1202 state->domain = NULL; 1203 state->done = 0; 1204 if (state->current) 1205 free(state->current); 1206 state->current = NULL; 1207 state->maptype = NISMAP_UNKNOWN; 1208 return NS_SUCCESS; 1209} 1210 1211/* 1212 * nis_parse 1213 * wrapper to _pw_parse that obtains the real password from the 1214 * "passwd.adjunct.byname" NIS map if the maptype is NISMAP_ADJUNCT. 1215 */ 1216static int 1217_nis_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen, 1218 struct nis_state *state) 1219{ 1220 size_t elen; 1221 1222 _DIAGASSERT(entry != NULL); 1223 _DIAGASSERT(pw != NULL); 1224 _DIAGASSERT(buf != NULL); 1225 _DIAGASSERT(state != NULL); 1226 1227 elen = strlen(entry); 1228 if (elen >= buflen) 1229 return 0; 1230 if (! _pw_parse(entry, pw, buf, buflen, 1231 !(state->maptype == NISMAP_MASTER))) 1232 return 0; 1233 1234 if ((state->maptype == NISMAP_ADJUNCT) && 1235 (strstr(pw->pw_passwd, "##") != NULL)) { 1236 char *data; 1237 int datalen; 1238 1239 if (yp_match(state->domain, "passwd.adjunct.byname", 1240 pw->pw_name, (int)strlen(pw->pw_name), 1241 &data, &datalen) == 0) { 1242 char *bp, *ep; 1243 /* skip name to get password */ 1244 ep = data; 1245 if ((bp = strsep(&ep, ":")) != NULL && 1246 (bp = strsep(&ep, ":")) != NULL) { 1247 /* store new pw_passwd after entry */ 1248 strlcpy(buf + elen, bp, buflen - elen); 1249 pw->pw_passwd = &buf[elen]; 1250 } 1251 free(data); 1252 } 1253 } 1254 1255 return 1; 1256} 1257 1258 1259/* 1260 * _nis_pwscan 1261 * Look for the yp key provided in buffer from map, 1262 * and decode into pw/buffer/buflen. 1263 */ 1264static int 1265_nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 1266 struct nis_state *state, const char *map) 1267{ 1268 char *data; 1269 int nisr, rv, datalen; 1270 1271 _DIAGASSERT(retval != NULL); 1272 _DIAGASSERT(pw != NULL); 1273 _DIAGASSERT(buffer != NULL); 1274 _DIAGASSERT(state != NULL); 1275 _DIAGASSERT(map != NULL); 1276 1277 *retval = 0; 1278 1279 if (state->domain == NULL) { /* only start if NIS not setup */ 1280 rv = _nis_start(state); 1281 if (rv != NS_SUCCESS) 1282 return rv; 1283 } 1284 1285 data = NULL; 1286 rv = NS_NOTFOUND; 1287 1288 /* search map */ 1289 nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer), 1290 &data, &datalen); 1291 switch (nisr) { 1292 case 0: 1293 data[datalen] = '\0'; /* clear trailing \n */ 1294 if (_nis_parse(data, pw, buffer, buflen, state)) 1295 rv = NS_SUCCESS; /* validate line */ 1296 else 1297 rv = NS_UNAVAIL; 1298 break; 1299 case YPERR_KEY: 1300 break; 1301 default: 1302 rv = NS_UNAVAIL; 1303 break; 1304 } 1305 1306 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 1307 *retval = errno; 1308 if (data) 1309 free(data); 1310 return rv; 1311} 1312 1313/*ARGSUSED*/ 1314static int 1315_nis_setpwent(void *nsrv, void *nscb, va_list ap) 1316{ 1317 1318 _nis_state.stayopen = 0; 1319 return _nis_start(&_nis_state); 1320} 1321 1322/*ARGSUSED*/ 1323static int 1324_nis_setpassent(void *nsrv, void *nscb, va_list ap) 1325{ 1326 int *retval = va_arg(ap, int *); 1327 int stayopen = va_arg(ap, int); 1328 1329 int rv; 1330 1331 _nis_state.stayopen = stayopen; 1332 rv = _nis_start(&_nis_state); 1333 *retval = (rv == NS_SUCCESS); 1334 return rv; 1335} 1336 1337/*ARGSUSED*/ 1338static int 1339_nis_endpwent(void *nsrv, void *nscb, va_list ap) 1340{ 1341 1342 return _nis_end(&_nis_state); 1343} 1344 1345 1346/*ARGSUSED*/ 1347static int 1348_nis_getpwent(void *nsrv, void *nscb, va_list ap) 1349{ 1350 struct passwd **retval = va_arg(ap, struct passwd **); 1351 1352 char *key, *data; 1353 int keylen, datalen, rv, nisr; 1354 1355 _DIAGASSERT(retval != NULL); 1356 1357 *retval = NULL; 1358 1359 if (_nis_state.done) /* exhausted search */ 1360 return NS_NOTFOUND; 1361 if (_nis_state.domain == NULL) { 1362 /* only start if NIS not setup */ 1363 rv = _nis_start(&_nis_state); 1364 if (rv != NS_SUCCESS) 1365 return rv; 1366 } 1367 1368 next_nis_entry: 1369 key = NULL; 1370 data = NULL; 1371 rv = NS_NOTFOUND; 1372 1373 if (_nis_state.current) { /* already searching */ 1374 nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1375 _nis_state.current, _nis_state.currentlen, 1376 &key, &keylen, &data, &datalen); 1377 free(_nis_state.current); 1378 _nis_state.current = NULL; 1379 switch (nisr) { 1380 case 0: 1381 _nis_state.current = key; 1382 _nis_state.currentlen = keylen; 1383 key = NULL; 1384 break; 1385 case YPERR_NOMORE: 1386 _nis_state.done = 1; 1387 goto nisent_out; 1388 default: 1389 rv = NS_UNAVAIL; 1390 goto nisent_out; 1391 } 1392 } else { /* new search */ 1393 if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1394 &_nis_state.current, &_nis_state.currentlen, 1395 &data, &datalen)) { 1396 rv = NS_UNAVAIL; 1397 goto nisent_out; 1398 } 1399 } 1400 1401 data[datalen] = '\0'; /* clear trailing \n */ 1402 /* validate line */ 1403 if (_nis_parse(data, &_nis_passwd, 1404 _nis_passwdbuf, sizeof(_nis_passwdbuf), &_nis_state)) 1405 rv = NS_SUCCESS; 1406 else { /* dodgy entry, try again */ 1407 free(data); 1408 goto next_nis_entry; 1409 } 1410 1411 nisent_out: 1412 if (key) 1413 free(key); 1414 if (data) 1415 free(data); 1416 if (rv == NS_SUCCESS) 1417 *retval = &_nis_passwd; 1418 return rv; 1419} 1420 1421/*ARGSUSED*/ 1422static int 1423_nis_getpwent_r(void *nsrv, void *nscb, va_list ap) 1424{ 1425 int *retval = va_arg(ap, int *); 1426 struct passwd *pw = va_arg(ap, struct passwd *); 1427 char *buffer = va_arg(ap, char *); 1428 size_t buflen = va_arg(ap, size_t); 1429 struct passwd **result = va_arg(ap, struct passwd **); 1430 1431 char *key, *data; 1432 int keylen, datalen, rv, nisr; 1433 1434 _DIAGASSERT(retval != NULL); 1435 _DIAGASSERT(pw != NULL); 1436 _DIAGASSERT(buffer != NULL); 1437 _DIAGASSERT(result != NULL); 1438 1439 *retval = 0; 1440 1441 if (_nis_state.done) /* exhausted search */ 1442 return NS_NOTFOUND; 1443 if (_nis_state.domain == NULL) { 1444 /* only start if NIS not setup */ 1445 rv = _nis_start(&_nis_state); 1446 if (rv != NS_SUCCESS) 1447 return rv; 1448 } 1449 1450 next_nis_entry: 1451 key = NULL; 1452 data = NULL; 1453 rv = NS_NOTFOUND; 1454 1455 if (_nis_state.current) { /* already searching */ 1456 nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1457 _nis_state.current, _nis_state.currentlen, 1458 &key, &keylen, &data, &datalen); 1459 free(_nis_state.current); 1460 _nis_state.current = NULL; 1461 switch (nisr) { 1462 case 0: 1463 _nis_state.current = key; 1464 _nis_state.currentlen = keylen; 1465 key = NULL; 1466 break; 1467 case YPERR_NOMORE: 1468 _nis_state.done = 1; 1469 goto nisent_out; 1470 default: 1471 rv = NS_UNAVAIL; 1472 goto nisent_out; 1473 } 1474 } else { /* new search */ 1475 if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1476 &_nis_state.current, &_nis_state.currentlen, 1477 &data, &datalen)) { 1478 rv = NS_UNAVAIL; 1479 goto nisent_out; 1480 } 1481 } 1482 1483 data[datalen] = '\0'; /* clear trailing \n */ 1484 /* validate line */ 1485 if (_nis_parse(data, pw, buffer, buflen, &_nis_state)) 1486 rv = NS_SUCCESS; 1487 else { /* dodgy entry, try again */ 1488 if (key) 1489 free(key); 1490 free(data); 1491 goto next_nis_entry; 1492 } 1493 1494 nisent_out: 1495 if (key) 1496 free(key); 1497 if (data) 1498 free(data); 1499 if (rv == NS_SUCCESS) 1500 *result = pw; 1501 else 1502 *result = NULL; 1503 return rv; 1504} 1505 1506/*ARGSUSED*/ 1507static int 1508_nis_getpwuid(void *nsrv, void *nscb, va_list ap) 1509{ 1510 struct passwd **retval = va_arg(ap, struct passwd **); 1511 uid_t uid = va_arg(ap, uid_t); 1512 1513 int rv, rerror; 1514 1515 _DIAGASSERT(retval != NULL); 1516 1517 *retval = NULL; 1518 rv = _nis_start(&_nis_state); 1519 if (rv != NS_SUCCESS) 1520 return rv; 1521 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%u", (unsigned int)uid); 1522 rv = _nis_pwscan(&rerror, &_nis_passwd, 1523 _nis_passwdbuf, sizeof(_nis_passwdbuf), 1524 &_nis_state, PASSWD_BYUID(&_nis_state)); 1525 if (!_nis_state.stayopen) 1526 _nis_end(&_nis_state); 1527 if (rv == NS_SUCCESS && uid == _nis_passwd.pw_uid) 1528 *retval = &_nis_passwd; 1529 return rv; 1530} 1531 1532/*ARGSUSED*/ 1533static int 1534_nis_getpwuid_r(void *nsrv, void *nscb, va_list ap) 1535{ 1536 int *retval = va_arg(ap, int *); 1537 uid_t uid = va_arg(ap, uid_t); 1538 struct passwd *pw = va_arg(ap, struct passwd *); 1539 char *buffer = va_arg(ap, char *); 1540 size_t buflen = va_arg(ap, size_t); 1541 struct passwd **result = va_arg(ap, struct passwd **); 1542 1543 struct nis_state state; 1544 int rv; 1545 1546 _DIAGASSERT(retval != NULL); 1547 _DIAGASSERT(pw != NULL); 1548 _DIAGASSERT(buffer != NULL); 1549 _DIAGASSERT(result != NULL); 1550 1551 *result = NULL; 1552 memset(&state, 0, sizeof(state)); 1553 rv = _nis_start(&state); 1554 if (rv != NS_SUCCESS) 1555 return rv; 1556 snprintf(buffer, buflen, "%u", (unsigned int)uid); 1557 rv = _nis_pwscan(retval, pw, buffer, buflen, 1558 &state, PASSWD_BYUID(&state)); 1559 _nis_end(&state); 1560 if (rv != NS_SUCCESS) 1561 return rv; 1562 if (uid == pw->pw_uid) { 1563 *result = pw; 1564 return NS_SUCCESS; 1565 } else 1566 return NS_NOTFOUND; 1567} 1568 1569/*ARGSUSED*/ 1570static int 1571_nis_getpwnam(void *nsrv, void *nscb, va_list ap) 1572{ 1573 struct passwd **retval = va_arg(ap, struct passwd **); 1574 const char *name = va_arg(ap, const char *); 1575 1576 int rv, rerror; 1577 1578 _DIAGASSERT(retval != NULL); 1579 1580 *retval = NULL; 1581 rv = _nis_start(&_nis_state); 1582 if (rv != NS_SUCCESS) 1583 return rv; 1584 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%s", name); 1585 rv = _nis_pwscan(&rerror, &_nis_passwd, 1586 _nis_passwdbuf, sizeof(_nis_passwdbuf), 1587 &_nis_state, PASSWD_BYNAME(&_nis_state)); 1588 if (!_nis_state.stayopen) 1589 _nis_end(&_nis_state); 1590 if (rv == NS_SUCCESS && strcmp(name, _nis_passwd.pw_name) == 0) 1591 *retval = &_nis_passwd; 1592 return rv; 1593} 1594 1595/*ARGSUSED*/ 1596static int 1597_nis_getpwnam_r(void *nsrv, void *nscb, va_list ap) 1598{ 1599 int *retval = va_arg(ap, int *); 1600 const char *name = va_arg(ap, const char *); 1601 struct passwd *pw = va_arg(ap, struct passwd *); 1602 char *buffer = va_arg(ap, char *); 1603 size_t buflen = va_arg(ap, size_t); 1604 struct passwd **result = va_arg(ap, struct passwd **); 1605 1606 struct nis_state state; 1607 int rv; 1608 1609 _DIAGASSERT(retval != NULL); 1610 _DIAGASSERT(pw != NULL); 1611 _DIAGASSERT(buffer != NULL); 1612 _DIAGASSERT(result != NULL); 1613 1614 *result = NULL; 1615 snprintf(buffer, buflen, "%s", name); 1616 memset(&state, 0, sizeof(state)); 1617 rv = _nis_start(&state); 1618 if (rv != NS_SUCCESS) 1619 return rv; 1620 rv = _nis_pwscan(retval, pw, buffer, buflen, 1621 &state, PASSWD_BYNAME(&state)); 1622 _nis_end(&state); 1623 if (rv != NS_SUCCESS) 1624 return rv; 1625 if (strcmp(name, pw->pw_name) == 0) { 1626 *result = pw; 1627 return NS_SUCCESS; 1628 } else 1629 return NS_NOTFOUND; 1630} 1631 1632#endif /* YP */ 1633 1634 1635#ifdef _PASSWD_COMPAT 1636 /* 1637 * compat methods 1638 */ 1639 1640 /* state shared between compat methods */ 1641 1642struct compat_state { 1643 int stayopen; /* see getpassent(3) */ 1644 DB *db; /* passwd DB */ 1645 int keynum; /* key counter, -1 if no more */ 1646 enum { /* current compat mode */ 1647 COMPAT_NOTOKEN = 0, /* no compat token present */ 1648 COMPAT_NONE, /* parsing normal pwd.db line */ 1649 COMPAT_FULL, /* parsing `+' entries */ 1650 COMPAT_USER, /* parsing `+name' entries */ 1651 COMPAT_NETGROUP /* parsing `+@netgroup' entries */ 1652 } mode; 1653 char *user; /* COMPAT_USER "+name" */ 1654 DB *exclude; /* compat exclude DB */ 1655 struct passwd proto; /* proto passwd entry */ 1656 char protobuf[_GETPW_R_SIZE_MAX]; 1657 /* buffer for proto ptrs */ 1658 int protoflags; /* proto passwd flags */ 1659 int version; 1660}; 1661 1662static struct compat_state _compat_state; 1663 /* storage for non _r functions */ 1664static struct passwd _compat_passwd; 1665static char _compat_passwdbuf[_GETPW_R_SIZE_MAX]; 1666 1667static int 1668_compat_start(struct compat_state *state) 1669{ 1670 int rv; 1671 1672 _DIAGASSERT(state != NULL); 1673 1674 state->keynum = 0; 1675 if (state->db == NULL) { /* not open yet */ 1676 DBT key, data; 1677 DBT pkey, pdata; 1678 char bf[MAXLOGNAME]; 1679 1680 rv = _pw_opendb(&state->db, &state->version); 1681 if (rv != NS_SUCCESS) 1682 return rv; 1683 1684 state->mode = COMPAT_NOTOKEN; 1685 1686 /* 1687 * Determine if the "compat" token is present in pwd.db; 1688 * either "__YP!" or PW_KEYBYNAME+"+". 1689 * Only works if pwd_mkdb installs the token. 1690 */ 1691 key.data = (u_char *)__UNCONST(__yp_token); 1692 key.size = strlen(__yp_token); 1693 1694 bf[0] = _PW_KEYBYNAME; /* Pre-token database support. */ 1695 bf[1] = '+'; 1696 pkey.data = (u_char *)bf; 1697 pkey.size = 2; 1698 1699 if ((state->db->get)(state->db, &key, &data, 0) == 0 1700 || (state->db->get)(state->db, &pkey, &pdata, 0) == 0) 1701 state->mode = COMPAT_NONE; 1702 } 1703 return NS_SUCCESS; 1704} 1705 1706static int 1707_compat_end(struct compat_state *state) 1708{ 1709 1710 _DIAGASSERT(state != NULL); 1711 1712 state->keynum = 0; 1713 if (state->db) { 1714 (void)(state->db->close)(state->db); 1715 state->db = NULL; 1716 } 1717 state->mode = COMPAT_NOTOKEN; 1718 if (state->user) 1719 free(state->user); 1720 state->user = NULL; 1721 if (state->exclude != NULL) 1722 (void)(state->exclude->close)(state->exclude); 1723 state->exclude = NULL; 1724 state->proto.pw_name = NULL; 1725 state->protoflags = 0; 1726 return NS_SUCCESS; 1727} 1728 1729/* 1730 * _compat_add_exclude 1731 * add the name to the exclude list in state->exclude. 1732 */ 1733static int 1734_compat_add_exclude(struct compat_state *state, const char *name) 1735{ 1736 DBT key, data; 1737 1738 _DIAGASSERT(state != NULL); 1739 _DIAGASSERT(name != NULL); 1740 1741 /* initialize the exclusion table if needed */ 1742 if (state->exclude == NULL) { 1743 state->exclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL); 1744 if (state->exclude == NULL) 1745 return 0; 1746 } 1747 1748 key.size = strlen(name); /* set up the key */ 1749 key.data = (u_char *)__UNCONST(name); 1750 1751 data.data = NULL; /* data is nothing */ 1752 data.size = 0; 1753 1754 /* store it */ 1755 if ((state->exclude->put)(state->exclude, &key, &data, 0) == -1) 1756 return 0; 1757 1758 return 1; 1759} 1760 1761/* 1762 * _compat_is_excluded 1763 * test if a name is on the compat mode exclude list 1764 */ 1765static int 1766_compat_is_excluded(struct compat_state *state, const char *name) 1767{ 1768 DBT key, data; 1769 1770 _DIAGASSERT(state != NULL); 1771 _DIAGASSERT(name != NULL); 1772 1773 if (state->exclude == NULL) 1774 return 0; /* nothing excluded */ 1775 1776 key.size = strlen(name); /* set up the key */ 1777 key.data = (u_char *)__UNCONST(name); 1778 1779 if ((state->exclude->get)(state->exclude, &key, &data, 0) == 0) 1780 return 1; /* is excluded */ 1781 1782 return 0; 1783} 1784 1785 1786/* 1787 * _passwdcompat_bad 1788 * log an error if "files" or "compat" is specified in 1789 * passwd_compat database 1790 */ 1791/*ARGSUSED*/ 1792static int 1793_passwdcompat_bad(void *nsrv, void *nscb, va_list ap) 1794{ 1795 static int warned; 1796 1797 _DIAGASSERT(nsrv != NULL); 1798 _DIAGASSERT(nscb != NULL); 1799 1800 if (!warned) { 1801 syslog(LOG_ERR, 1802 "nsswitch.conf passwd_compat database can't use '%s'", 1803 (char *)nscb); 1804 } 1805 warned = 1; 1806 return NS_UNAVAIL; 1807} 1808 1809/* 1810 * _passwdcompat_setpassent 1811 * Call setpassent for all passwd_compat sources. 1812 */ 1813static int 1814_passwdcompat_setpassent(int stayopen) 1815{ 1816 static const ns_dtab dtab[] = { 1817 NS_FILES_CB(_passwdcompat_bad, "files") 1818 NS_DNS_CB(_dns_setpassent, NULL) 1819 NS_NIS_CB(_nis_setpassent, NULL) 1820 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1821 NS_NULL_CB 1822 }; 1823 1824 int rv, result; 1825 1826 rv = nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpassent", 1827 __nsdefaultnis_forceall, &result, stayopen); 1828 return rv; 1829} 1830 1831/* 1832 * _passwdcompat_endpwent 1833 * Call endpwent for all passwd_compat sources. 1834 */ 1835static int 1836_passwdcompat_endpwent(void) 1837{ 1838 static const ns_dtab dtab[] = { 1839 NS_FILES_CB(_passwdcompat_bad, "files") 1840 NS_DNS_CB(_dns_endpwent, NULL) 1841 NS_NIS_CB(_nis_endpwent, NULL) 1842 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1843 NS_NULL_CB 1844 }; 1845 1846 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent", 1847 __nsdefaultnis_forceall); 1848} 1849 1850/* 1851 * _passwdcompat_pwscan 1852 * When a name lookup in compat mode is required (e.g., `+name', or a 1853 * name in `+@netgroup'), look it up in the 'passwd_compat' nsswitch 1854 * database. 1855 * Fail if passwd_compat contains files or compat. 1856 */ 1857static int 1858_passwdcompat_pwscan(struct passwd *pw, char *buffer, size_t buflen, 1859 int search, const char *name, uid_t uid) 1860{ 1861 static const ns_dtab compatentdtab[] = { 1862 NS_FILES_CB(_passwdcompat_bad, "files") 1863 NS_DNS_CB(_dns_getpwent_r, NULL) 1864 NS_NIS_CB(_nis_getpwent_r, NULL) 1865 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1866 NS_NULL_CB 1867 }; 1868 static const ns_dtab compatuiddtab[] = { 1869 NS_FILES_CB(_passwdcompat_bad, "files") 1870 NS_DNS_CB(_dns_getpwuid_r, NULL) 1871 NS_NIS_CB(_nis_getpwuid_r, NULL) 1872 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1873 NS_NULL_CB 1874 }; 1875 static const ns_dtab compatnamdtab[] = { 1876 NS_FILES_CB(_passwdcompat_bad, "files") 1877 NS_DNS_CB(_dns_getpwnam_r, NULL) 1878 NS_NIS_CB(_nis_getpwnam_r, NULL) 1879 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1880 NS_NULL_CB 1881 }; 1882 1883 int rv, crv; 1884 struct passwd *cpw; 1885 1886 switch (search) { 1887 case _PW_KEYBYNUM: 1888 rv = nsdispatch(NULL, compatentdtab, 1889 NSDB_PASSWD_COMPAT, "getpwent_r", __nsdefaultnis, 1890 &crv, pw, buffer, buflen, &cpw); 1891 break; 1892 case _PW_KEYBYNAME: 1893 _DIAGASSERT(name != NULL); 1894 rv = nsdispatch(NULL, compatnamdtab, 1895 NSDB_PASSWD_COMPAT, "getpwnam_r", __nsdefaultnis, 1896 &crv, name, pw, buffer, buflen, &cpw); 1897 break; 1898 case _PW_KEYBYUID: 1899 rv = nsdispatch(NULL, compatuiddtab, 1900 NSDB_PASSWD_COMPAT, "getpwuid_r", __nsdefaultnis, 1901 &crv, uid, pw, buffer, buflen, &cpw); 1902 break; 1903 default: 1904 abort(); 1905 /*NOTREACHED*/ 1906 } 1907 return rv; 1908} 1909 1910/* 1911 * _compat_pwscan 1912 * Search state->db for the next desired entry. 1913 * If search is _PW_KEYBYNUM, look for state->keynum. 1914 * If search is _PW_KEYBYNAME, look for name. 1915 * If search is _PW_KEYBYUID, look for uid. 1916 * Sets *retval to the errno if the result is not NS_SUCCESS 1917 * or NS_NOTFOUND. 1918 */ 1919static int 1920_compat_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 1921 struct compat_state *state, int search, const char *name, uid_t uid) 1922{ 1923 DBT key; 1924 int rv, r, pwflags; 1925 const char *user, *host, *dom; 1926 const void *from; 1927 size_t fromlen; 1928 1929 _DIAGASSERT(retval != NULL); 1930 _DIAGASSERT(pw != NULL); 1931 _DIAGASSERT(buffer != NULL); 1932 _DIAGASSERT(state != NULL); 1933 /* name may be NULL */ 1934 1935 *retval = 0; 1936 1937 if (state->db == NULL) { 1938 rv = _compat_start(state); 1939 if (rv != NS_SUCCESS) 1940 return rv; 1941 } 1942 if (buflen <= 1) { /* buffer too small */ 1943 *retval = ERANGE; 1944 return NS_UNAVAIL; 1945 } 1946 1947 for (;;) { /* loop over pwd.db */ 1948 rv = NS_NOTFOUND; 1949 if (state->mode != COMPAT_NOTOKEN && 1950 state->mode != COMPAT_NONE) { 1951 /* doing a compat lookup */ 1952 struct passwd cpw; 1953 char cbuf[_GETPW_R_SIZE_MAX]; 1954 1955 switch (state->mode) { 1956 1957 case COMPAT_FULL: 1958 /* get next user or lookup by key */ 1959 rv = _passwdcompat_pwscan(&cpw, 1960 cbuf, sizeof(cbuf), search, name, uid); 1961 if (rv != NS_SUCCESS) 1962 state->mode = COMPAT_NONE; 1963 break; 1964 1965 case COMPAT_NETGROUP: 1966/* XXXREENTRANT: getnetgrent is not thread safe */ 1967 /* get next user from netgroup */ 1968 r = getnetgrent(&host, &user, &dom); 1969 if (r == 0) { /* end of group */ 1970 endnetgrent(); 1971 state->mode = COMPAT_NONE; 1972 break; 1973 } 1974 if (!user || !*user) 1975 break; 1976 rv = _passwdcompat_pwscan(&cpw, 1977 cbuf, sizeof(cbuf), 1978 _PW_KEYBYNAME, user, 0); 1979 break; 1980 1981 case COMPAT_USER: 1982 /* get specific user */ 1983 if (state->user == NULL) { 1984 state->mode = COMPAT_NONE; 1985 break; 1986 } 1987 rv = _passwdcompat_pwscan(&cpw, 1988 cbuf, sizeof(cbuf), 1989 _PW_KEYBYNAME, state->user, 0); 1990 free(state->user); 1991 state->user = NULL; 1992 state->mode = COMPAT_NONE; 1993 break; 1994 1995 case COMPAT_NOTOKEN: 1996 case COMPAT_NONE: 1997 abort(); 1998 1999 } 2000 if (rv != NS_SUCCESS) /* if not matched, next loop */ 2001 continue; 2002 2003 /* copy cpw to pw, applying prototype */ 2004 if (! _pw_copy(&cpw, pw, buffer, buflen, 2005 &state->proto, state->protoflags)) { 2006 rv = NS_UNAVAIL; 2007 break; 2008 } 2009 2010 if (_compat_is_excluded(state, pw->pw_name)) 2011 continue; /* excluded; next loop */ 2012 2013 if ((search == _PW_KEYBYNAME 2014 && strcmp(pw->pw_name, name) != 0) 2015 || (search == _PW_KEYBYUID && pw->pw_uid != uid)) { 2016 continue; /* not specific; next loop */ 2017 } 2018 2019 break; /* exit loop if found */ 2020 } else { /* not a compat line */ 2021 state->proto.pw_name = NULL; 2022 /* clear prototype */ 2023 } 2024 2025 if (state->mode == COMPAT_NOTOKEN) { 2026 /* no compat token; do direct lookup */ 2027 switch (search) { 2028 case _PW_KEYBYNUM: 2029 if (state->keynum == -1) /* no more records */ 2030 return NS_NOTFOUND; 2031 state->keynum++; 2032 from = &state->keynum; 2033 fromlen = sizeof(state->keynum); 2034 break; 2035 case _PW_KEYBYNAME: 2036 from = name; 2037 fromlen = strlen(name); 2038 break; 2039 case _PW_KEYBYUID: 2040 from = &uid; 2041 fromlen = sizeof(uid); 2042 break; 2043 default: 2044 abort(); 2045 } 2046 buffer[0] = search; 2047 } else { 2048 /* compat token; do line by line */ 2049 if (state->keynum == -1) /* no more records */ 2050 return NS_NOTFOUND; 2051 state->keynum++; 2052 from = &state->keynum; 2053 fromlen = sizeof(state->keynum); 2054 buffer[0] = _PW_KEYBYNUM; 2055 } 2056 2057 if (buflen <= fromlen) { /* buffer too small */ 2058 *retval = ERANGE; 2059 return NS_UNAVAIL; 2060 } 2061 memmove(buffer + 1, from, fromlen); /* setup key */ 2062 key.size = fromlen + 1; 2063 key.data = (u_char *)buffer; 2064 2065 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, &pwflags, 2066 state->version); 2067 if (rv != NS_SUCCESS) /* stop on error */ 2068 break; 2069 2070 if (state->mode == COMPAT_NOTOKEN) 2071 break; /* stop if no compat token */ 2072 2073 if (pw->pw_name[0] == '+') { 2074 /* compat inclusion */ 2075 switch(pw->pw_name[1]) { 2076 case '\0': /* `+' */ 2077 state->mode = COMPAT_FULL; 2078 /* reset passwd_compat search */ 2079/* XXXREENTRANT: setpassent is not thread safe ? */ 2080 (void) _passwdcompat_setpassent(0); 2081 break; 2082 case '@': /* `+@netgroup' */ 2083 state->mode = COMPAT_NETGROUP; 2084 /* reset netgroup search */ 2085/* XXXREENTRANT: setnetgrent is not thread safe */ 2086 setnetgrent(pw->pw_name + 2); 2087 break; 2088 default: /* `+name' */ 2089 state->mode = COMPAT_USER; 2090 if (state->user) 2091 free(state->user); 2092 state->user = strdup(pw->pw_name + 1); 2093 break; 2094 } 2095 /* save the prototype */ 2096 state->protoflags = pwflags; 2097 if (! _pw_copy(pw, &state->proto, state->protobuf, 2098 sizeof(state->protobuf), NULL, 0)) { 2099 rv = NS_UNAVAIL; 2100 break; 2101 } 2102 continue; /* loop again after inclusion */ 2103 } else if (pw->pw_name[0] == '-') { 2104 /* compat exclusion */ 2105 rv = NS_SUCCESS; 2106 switch(pw->pw_name[1]) { 2107 case '\0': /* `-' */ 2108 break; 2109 case '@': /* `-@netgroup' */ 2110/* XXXREENTRANT: {set,get,end}netgrent is not thread safe */ 2111 setnetgrent(pw->pw_name + 2); 2112 while (getnetgrent(&host, &user, &dom)) { 2113 if (!user || !*user) 2114 continue; 2115 if (! _compat_add_exclude(state,user)) { 2116 rv = NS_UNAVAIL; 2117 break; 2118 } 2119 } 2120 endnetgrent(); 2121 break; 2122 default: /* `-name' */ 2123 if (! _compat_add_exclude(state, 2124 pw->pw_name + 1)) { 2125 rv = NS_UNAVAIL; 2126 } 2127 break; 2128 } 2129 if (rv != NS_SUCCESS) /* exclusion failure */ 2130 break; 2131 continue; /* loop again after exclusion */ 2132 } 2133 if (search == _PW_KEYBYNUM || 2134 (search == _PW_KEYBYUID && pw->pw_uid == uid) || 2135 (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) == 0)) 2136 break; /* token mode match found */ 2137 } 2138 2139 if (rv == NS_NOTFOUND && 2140 (search == _PW_KEYBYNUM || state->mode != COMPAT_NOTOKEN)) 2141 state->keynum = -1; /* flag `no more records' */ 2142 2143 if (rv == NS_SUCCESS) { 2144 if ((search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0) 2145 || (search == _PW_KEYBYUID && pw->pw_uid != uid)) 2146 rv = NS_NOTFOUND; 2147 } 2148 2149 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 2150 *retval = errno; 2151 return rv; 2152} 2153 2154/*ARGSUSED*/ 2155static int 2156_compat_setpwent(void *nsrv, void *nscb, va_list ap) 2157{ 2158 2159 /* force passwd_compat setpwent() */ 2160 (void) _passwdcompat_setpassent(0); 2161 2162 /* reset state, keep db open */ 2163 _compat_state.stayopen = 0; 2164 return _compat_start(&_compat_state); 2165} 2166 2167/*ARGSUSED*/ 2168static int 2169_compat_setpassent(void *nsrv, void *nscb, va_list ap) 2170{ 2171 int *retval = va_arg(ap, int *); 2172 int stayopen = va_arg(ap, int); 2173 2174 int rv; 2175 2176 /* force passwd_compat setpassent() */ 2177 (void) _passwdcompat_setpassent(stayopen); 2178 2179 _compat_state.stayopen = stayopen; 2180 rv = _compat_start(&_compat_state); 2181 *retval = (rv == NS_SUCCESS); 2182 return rv; 2183} 2184 2185/*ARGSUSED*/ 2186static int 2187_compat_endpwent(void *nsrv, void *nscb, va_list ap) 2188{ 2189 2190 /* force passwd_compat endpwent() */ 2191 (void) _passwdcompat_endpwent(); 2192 2193 /* reset state, close db */ 2194 _compat_state.stayopen = 0; 2195 return _compat_end(&_compat_state); 2196} 2197 2198 2199/*ARGSUSED*/ 2200static int 2201_compat_getpwent(void *nsrv, void *nscb, va_list ap) 2202{ 2203 struct passwd **retval = va_arg(ap, struct passwd **); 2204 2205 int rv, rerror; 2206 2207 _DIAGASSERT(retval != NULL); 2208 2209 *retval = NULL; 2210 rv = _compat_pwscan(&rerror, &_compat_passwd, 2211 _compat_passwdbuf, sizeof(_compat_passwdbuf), 2212 &_compat_state, _PW_KEYBYNUM, NULL, 0); 2213 if (rv == NS_SUCCESS) 2214 *retval = &_compat_passwd; 2215 return rv; 2216} 2217 2218/*ARGSUSED*/ 2219static int 2220_compat_getpwent_r(void *nsrv, void *nscb, va_list ap) 2221{ 2222 int *retval = va_arg(ap, int *); 2223 struct passwd *pw = va_arg(ap, struct passwd *); 2224 char *buffer = va_arg(ap, char *); 2225 size_t buflen = va_arg(ap, size_t); 2226 struct passwd **result = va_arg(ap, struct passwd **); 2227 2228 int rv; 2229 2230 _DIAGASSERT(retval != NULL); 2231 _DIAGASSERT(pw != NULL); 2232 _DIAGASSERT(buffer != NULL); 2233 _DIAGASSERT(result != NULL); 2234 2235 rv = _compat_pwscan(retval, pw, buffer, buflen, &_compat_state, 2236 _PW_KEYBYNUM, NULL, 0); 2237 if (rv == NS_SUCCESS) 2238 *result = pw; 2239 else 2240 *result = NULL; 2241 return rv; 2242} 2243 2244 2245/*ARGSUSED*/ 2246static int 2247_compat_getpwnam(void *nsrv, void *nscb, va_list ap) 2248{ 2249 struct passwd **retval = va_arg(ap, struct passwd **); 2250 const char *name = va_arg(ap, const char *); 2251 2252 int rv, rerror; 2253 2254 _DIAGASSERT(retval != NULL); 2255 2256 *retval = NULL; 2257 rv = _compat_start(&_compat_state); 2258 if (rv != NS_SUCCESS) 2259 return rv; 2260 rv = _compat_pwscan(&rerror, &_compat_passwd, 2261 _compat_passwdbuf, sizeof(_compat_passwdbuf), 2262 &_compat_state, _PW_KEYBYNAME, name, 0); 2263 if (!_compat_state.stayopen) 2264 _compat_end(&_compat_state); 2265 if (rv == NS_SUCCESS) 2266 *retval = &_compat_passwd; 2267 return rv; 2268} 2269 2270/*ARGSUSED*/ 2271static int 2272_compat_getpwnam_r(void *nsrv, void *nscb, va_list ap) 2273{ 2274 int *retval = va_arg(ap, int *); 2275 const char *name = va_arg(ap, const char *); 2276 struct passwd *pw = va_arg(ap, struct passwd *); 2277 char *buffer = va_arg(ap, char *); 2278 size_t buflen = va_arg(ap, size_t); 2279 struct passwd **result = va_arg(ap, struct passwd **); 2280 2281 struct compat_state state; 2282 int rv; 2283 2284 _DIAGASSERT(retval != NULL); 2285 _DIAGASSERT(pw != NULL); 2286 _DIAGASSERT(buffer != NULL); 2287 _DIAGASSERT(result != NULL); 2288 2289 *result = NULL; 2290 memset(&state, 0, sizeof(state)); 2291 rv = _compat_pwscan(retval, pw, buffer, buflen, &state, 2292 _PW_KEYBYNAME, name, 0); 2293 _compat_end(&state); 2294 if (rv == NS_SUCCESS) 2295 *result = pw; 2296 return rv; 2297} 2298 2299/*ARGSUSED*/ 2300static int 2301_compat_getpwuid(void *nsrv, void *nscb, va_list ap) 2302{ 2303 struct passwd **retval = va_arg(ap, struct passwd **); 2304 uid_t uid = va_arg(ap, uid_t); 2305 2306 int rv, rerror; 2307 2308 _DIAGASSERT(retval != NULL); 2309 2310 *retval = NULL; 2311 rv = _compat_start(&_compat_state); 2312 if (rv != NS_SUCCESS) 2313 return rv; 2314 rv = _compat_pwscan(&rerror, &_compat_passwd, 2315 _compat_passwdbuf, sizeof(_compat_passwdbuf), 2316 &_compat_state, _PW_KEYBYUID, NULL, uid); 2317 if (!_compat_state.stayopen) 2318 _compat_end(&_compat_state); 2319 if (rv == NS_SUCCESS) 2320 *retval = &_compat_passwd; 2321 return rv; 2322} 2323 2324/*ARGSUSED*/ 2325static int 2326_compat_getpwuid_r(void *nsrv, void *nscb, va_list ap) 2327{ 2328 int *retval = va_arg(ap, int *); 2329 uid_t uid = va_arg(ap, uid_t); 2330 struct passwd *pw = va_arg(ap, struct passwd *); 2331 char *buffer = va_arg(ap, char *); 2332 size_t buflen = va_arg(ap, size_t); 2333 struct passwd **result = va_arg(ap, struct passwd **); 2334 2335 struct compat_state state; 2336 int rv; 2337 2338 _DIAGASSERT(retval != NULL); 2339 _DIAGASSERT(pw != NULL); 2340 _DIAGASSERT(buffer != NULL); 2341 _DIAGASSERT(result != NULL); 2342 2343 *result = NULL; 2344 memset(&state, 0, sizeof(state)); 2345 rv = _compat_pwscan(retval, pw, buffer, buflen, &state, 2346 _PW_KEYBYUID, NULL, uid); 2347 _compat_end(&state); 2348 if (rv == NS_SUCCESS) 2349 *result = pw; 2350 return rv; 2351} 2352 2353#endif /* _PASSWD_COMPAT */ 2354 2355 2356 /* 2357 * public functions 2358 */ 2359 2360struct passwd * 2361getpwent(void) 2362{ 2363 int r; 2364 struct passwd *retval; 2365 2366 static const ns_dtab dtab[] = { 2367 NS_FILES_CB(_files_getpwent, NULL) 2368 NS_DNS_CB(_dns_getpwent, NULL) 2369 NS_NIS_CB(_nis_getpwent, NULL) 2370 NS_COMPAT_CB(_compat_getpwent, NULL) 2371 NS_NULL_CB 2372 }; 2373 2374 mutex_lock(&_pwmutex); 2375 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", __nsdefaultcompat, 2376 &retval); 2377 mutex_unlock(&_pwmutex); 2378 return (r == NS_SUCCESS) ? retval : NULL; 2379} 2380 2381int 2382getpwent_r(struct passwd *pwd, char *buffer, size_t buflen, 2383 struct passwd **result) 2384{ 2385 int r, retval; 2386 2387 static const ns_dtab dtab[] = { 2388 NS_FILES_CB(_files_getpwent_r, NULL) 2389 NS_DNS_CB(_dns_getpwent_r, NULL) 2390 NS_NIS_CB(_nis_getpwent_r, NULL) 2391 NS_COMPAT_CB(_compat_getpwent_r, NULL) 2392 NS_NULL_CB 2393 }; 2394 2395 _DIAGASSERT(pwd != NULL); 2396 _DIAGASSERT(buffer != NULL); 2397 _DIAGASSERT(result != NULL); 2398 2399 *result = NULL; 2400 retval = 0; 2401 mutex_lock(&_pwmutex); 2402 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent_r", __nsdefaultcompat, 2403 &retval, pwd, buffer, buflen, result); 2404 mutex_unlock(&_pwmutex); 2405 switch (r) { 2406 case NS_SUCCESS: 2407 case NS_NOTFOUND: 2408 return 0; 2409 default: 2410 return retval; 2411 } 2412} 2413 2414 2415struct passwd * 2416getpwnam(const char *name) 2417{ 2418 int rv; 2419 struct passwd *retval; 2420 2421 static const ns_dtab dtab[] = { 2422 NS_FILES_CB(_files_getpwnam, NULL) 2423 NS_DNS_CB(_dns_getpwnam, NULL) 2424 NS_NIS_CB(_nis_getpwnam, NULL) 2425 NS_COMPAT_CB(_compat_getpwnam, NULL) 2426 NS_NULL_CB 2427 }; 2428 2429 mutex_lock(&_pwmutex); 2430 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", __nsdefaultcompat, 2431 &retval, name); 2432 mutex_unlock(&_pwmutex); 2433 return (rv == NS_SUCCESS) ? retval : NULL; 2434} 2435 2436int 2437getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t buflen, 2438 struct passwd **result) 2439{ 2440 int r, retval; 2441 2442 static const ns_dtab dtab[] = { 2443 NS_FILES_CB(_files_getpwnam_r, NULL) 2444 NS_DNS_CB(_dns_getpwnam_r, NULL) 2445 NS_NIS_CB(_nis_getpwnam_r, NULL) 2446 NS_COMPAT_CB(_compat_getpwnam_r, NULL) 2447 NS_NULL_CB 2448 }; 2449 2450 _DIAGASSERT(name != NULL); 2451 _DIAGASSERT(pwd != NULL); 2452 _DIAGASSERT(buffer != NULL); 2453 _DIAGASSERT(result != NULL); 2454 2455 *result = NULL; 2456 retval = 0; 2457 mutex_lock(&_pwmutex); 2458 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam_r", __nsdefaultcompat, 2459 &retval, name, pwd, buffer, buflen, result); 2460 mutex_unlock(&_pwmutex); 2461 switch (r) { 2462 case NS_SUCCESS: 2463 case NS_NOTFOUND: 2464 return 0; 2465 default: 2466 return retval; 2467 } 2468} 2469 2470struct passwd * 2471getpwuid(uid_t uid) 2472{ 2473 int rv; 2474 struct passwd *retval; 2475 2476 static const ns_dtab dtab[] = { 2477 NS_FILES_CB(_files_getpwuid, NULL) 2478 NS_DNS_CB(_dns_getpwuid, NULL) 2479 NS_NIS_CB(_nis_getpwuid, NULL) 2480 NS_COMPAT_CB(_compat_getpwuid, NULL) 2481 NS_NULL_CB 2482 }; 2483 2484 mutex_lock(&_pwmutex); 2485 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", __nsdefaultcompat, 2486 &retval, uid); 2487 mutex_unlock(&_pwmutex); 2488 return (rv == NS_SUCCESS) ? retval : NULL; 2489} 2490 2491int 2492getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen, 2493 struct passwd **result) 2494{ 2495 int r, retval; 2496 2497 static const ns_dtab dtab[] = { 2498 NS_FILES_CB(_files_getpwuid_r, NULL) 2499 NS_DNS_CB(_dns_getpwuid_r, NULL) 2500 NS_NIS_CB(_nis_getpwuid_r, NULL) 2501 NS_COMPAT_CB(_compat_getpwuid_r, NULL) 2502 NS_NULL_CB 2503 }; 2504 2505 _DIAGASSERT(pwd != NULL); 2506 _DIAGASSERT(buffer != NULL); 2507 _DIAGASSERT(result != NULL); 2508 2509 *result = NULL; 2510 retval = 0; 2511 mutex_lock(&_pwmutex); 2512 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid_r", __nsdefaultcompat, 2513 &retval, uid, pwd, buffer, buflen, result); 2514 mutex_unlock(&_pwmutex); 2515 switch (r) { 2516 case NS_SUCCESS: 2517 case NS_NOTFOUND: 2518 return 0; 2519 default: 2520 return retval; 2521 } 2522} 2523 2524void 2525endpwent(void) 2526{ 2527 static const ns_dtab dtab[] = { 2528 NS_FILES_CB(_files_endpwent, NULL) 2529 NS_DNS_CB(_dns_endpwent, NULL) 2530 NS_NIS_CB(_nis_endpwent, NULL) 2531 NS_COMPAT_CB(_compat_endpwent, NULL) 2532 NS_NULL_CB 2533 }; 2534 2535 mutex_lock(&_pwmutex); 2536 /* force all endpwent() methods */ 2537 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", 2538 __nsdefaultcompat_forceall); 2539 mutex_unlock(&_pwmutex); 2540} 2541 2542/*ARGSUSED*/ 2543int 2544setpassent(int stayopen) 2545{ 2546 static const ns_dtab dtab[] = { 2547 NS_FILES_CB(_files_setpassent, NULL) 2548 NS_DNS_CB(_dns_setpassent, NULL) 2549 NS_NIS_CB(_nis_setpassent, NULL) 2550 NS_COMPAT_CB(_compat_setpassent, NULL) 2551 NS_NULL_CB 2552 }; 2553 int rv, retval; 2554 2555 mutex_lock(&_pwmutex); 2556 /* force all setpassent() methods */ 2557 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "setpassent", 2558 __nsdefaultcompat_forceall, &retval, stayopen); 2559 mutex_unlock(&_pwmutex); 2560 return (rv == NS_SUCCESS) ? retval : 0; 2561} 2562 2563void 2564setpwent(void) 2565{ 2566 static const ns_dtab dtab[] = { 2567 NS_FILES_CB(_files_setpwent, NULL) 2568 NS_DNS_CB(_dns_setpwent, NULL) 2569 NS_NIS_CB(_nis_setpwent, NULL) 2570 NS_COMPAT_CB(_compat_setpwent, NULL) 2571 NS_NULL_CB 2572 }; 2573 2574 mutex_lock(&_pwmutex); 2575 /* force all setpwent() methods */ 2576 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", 2577 __nsdefaultcompat_forceall); 2578 mutex_unlock(&_pwmutex); 2579} 2580