1/* $NetBSD: getpwent.c,v 1.84 2024/01/20 14:52:47 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.84 2024/01/20 14:52:47 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#include "pw_private.h" 115 116#ifdef HESIOD 117#include <hesiod.h> 118#endif 119 120#ifdef YP 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 (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 = 0, /* 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 1141static const char __nis_pw_n_1[] = "master.passwd.byname"; 1142static const char __nis_pw_n_2[] = "passwd.byname"; 1143static const char __nis_pw_u_1[] = "master.passwd.byuid"; 1144static const char __nis_pw_u_2[] = "passwd.byuid"; 1145 1146static const char * const __nis_pw_n_map[4] = { __nis_pw_n_2, __nis_pw_n_2, __nis_pw_n_2, __nis_pw_n_1 }; 1147static const char * const __nis_pw_u_map[4] = { __nis_pw_u_2, __nis_pw_u_2, __nis_pw_u_2, __nis_pw_u_1 }; 1148 1149 /* macros for deciding which NIS maps to use. */ 1150#define PASSWD_BYNAME(x) ((x)->maptype == NISMAP_MASTER ? __nis_pw_n_1 : __nis_pw_n_2) 1151#define PASSWD_BYUID(x) ((x)->maptype == NISMAP_MASTER ? __nis_pw_u_1 : __nis_pw_u_2) 1152 1153static int 1154_nis_start(struct nis_state *state) 1155{ 1156 1157 _DIAGASSERT(state != NULL); 1158 1159 state->done = 0; 1160 if (state->current) { 1161 free(state->current); 1162 state->current = NULL; 1163 } 1164 if (state->domain == NULL) { /* setup NIS */ 1165 switch (yp_get_default_domain(&state->domain)) { 1166 case 0: 1167 break; 1168 case YPERR_RESRC: 1169 return NS_TRYAGAIN; 1170 default: 1171 return NS_UNAVAIL; 1172 } 1173 } 1174 1175 /* determine where to get pw_passwd from */ 1176 if (state->maptype == NISMAP_UNKNOWN) { 1177 int r, order; 1178 1179 state->maptype = NISMAP_NONE; /* default to no adjunct */ 1180 if (geteuid() != 0) /* non-root can't use adjunct */ 1181 return NS_SUCCESS; 1182 1183 /* look for "master.passwd.*" */ 1184 r = yp_order(state->domain, "master.passwd.byname", &order); 1185 if (r == 0) { 1186 state->maptype = NISMAP_MASTER; 1187 return NS_SUCCESS; 1188 } 1189 1190 /* master.passwd doesn't exist, try passwd.adjunct */ 1191 if (r == YPERR_MAP) { 1192 r = yp_order(state->domain, "passwd.adjunct.byname", 1193 &order); 1194 if (r == 0) 1195 state->maptype = NISMAP_ADJUNCT; 1196 } 1197 } 1198 return NS_SUCCESS; 1199} 1200 1201static int 1202_nis_end(struct nis_state *state) 1203{ 1204 1205 _DIAGASSERT(state != NULL); 1206 1207 if (state->domain) 1208 state->domain = NULL; 1209 state->done = 0; 1210 if (state->current) 1211 free(state->current); 1212 state->current = NULL; 1213 state->maptype = NISMAP_UNKNOWN; 1214 return NS_SUCCESS; 1215} 1216 1217/* 1218 * nis_parse 1219 * wrapper to _pw_parse that obtains the real password from the 1220 * "passwd.adjunct.byname" NIS map if the maptype is NISMAP_ADJUNCT. 1221 */ 1222static int 1223_nis_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen, 1224 struct nis_state *state) 1225{ 1226 size_t elen; 1227 1228 _DIAGASSERT(entry != NULL); 1229 _DIAGASSERT(pw != NULL); 1230 _DIAGASSERT(buf != NULL); 1231 _DIAGASSERT(state != NULL); 1232 1233 elen = strlen(entry) + 1; 1234 if (elen >= buflen) 1235 return 0; 1236 if (! _pw_parse(entry, pw, buf, buflen, 1237 !(state->maptype == NISMAP_MASTER))) 1238 return 0; 1239 1240 if ((state->maptype == NISMAP_ADJUNCT) && 1241 (strstr(pw->pw_passwd, "##") != NULL)) { 1242 char *data; 1243 int datalen; 1244 1245 if (yp_match(state->domain, "passwd.adjunct.byname", 1246 pw->pw_name, (int)strlen(pw->pw_name), 1247 &data, &datalen) == 0) { 1248 char *bp, *ep; 1249 /* skip name to get password */ 1250 ep = data; 1251 if (strsep(&ep, ":") != NULL && 1252 (bp = strsep(&ep, ":")) != NULL) { 1253 /* store new pw_passwd after entry */ 1254 if (strlcpy(buf + elen, bp, buflen - elen) >= 1255 buflen - elen) { 1256 free(data); 1257 return 0; 1258 } 1259 pw->pw_passwd = &buf[elen]; 1260 } 1261 free(data); 1262 } 1263 } 1264 1265 return 1; 1266} 1267 1268 1269/* 1270 * _nis_pwscan 1271 * Look for the yp key provided in buffer from map, 1272 * and decode into pw/buffer/buflen. 1273 */ 1274static int 1275_nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 1276 struct nis_state *state, const char * const *map_arr, size_t nmaps) 1277{ 1278 char *data; 1279 int nisr, rv, datalen; 1280 1281 _DIAGASSERT(retval != NULL); 1282 _DIAGASSERT(pw != NULL); 1283 _DIAGASSERT(buffer != NULL); 1284 _DIAGASSERT(state != NULL); 1285 _DIAGASSERT(map_arr != NULL); 1286 1287 *retval = 0; 1288 1289 if (state->domain == NULL) { /* only start if NIS not setup */ 1290 rv = _nis_start(state); 1291 if (rv != NS_SUCCESS) 1292 return rv; 1293 } 1294 1295 data = NULL; 1296 rv = NS_NOTFOUND; 1297 _DIAGASSERT(state->maptype != NISMAP_UNKNOWN && 1298 (unsigned)state->maptype < nmaps); 1299 1300 /* search map */ 1301 nisr = yp_match(state->domain, map_arr[state->maptype], buffer, (int)strlen(buffer), 1302 &data, &datalen); 1303 switch (nisr) { 1304 case 0: 1305 data[datalen] = '\0'; /* clear trailing \n */ 1306 if (_nis_parse(data, pw, buffer, buflen, state)) 1307 rv = NS_SUCCESS; /* validate line */ 1308 else 1309 rv = NS_UNAVAIL; 1310 break; 1311 case YPERR_KEY: 1312 break; 1313 default: 1314 rv = NS_UNAVAIL; 1315 break; 1316 } 1317 1318 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 1319 *retval = errno; 1320 if (data) 1321 free(data); 1322 return rv; 1323} 1324 1325/*ARGSUSED*/ 1326static int 1327_nis_setpwent(void *nsrv, void *nscb, va_list ap) 1328{ 1329 1330 _nis_state.stayopen = 0; 1331 return _nis_start(&_nis_state); 1332} 1333 1334/*ARGSUSED*/ 1335static int 1336_nis_setpassent(void *nsrv, void *nscb, va_list ap) 1337{ 1338 int *retval = va_arg(ap, int *); 1339 int stayopen = va_arg(ap, int); 1340 1341 int rv; 1342 1343 _nis_state.stayopen = stayopen; 1344 rv = _nis_start(&_nis_state); 1345 *retval = (rv == NS_SUCCESS); 1346 return rv; 1347} 1348 1349/*ARGSUSED*/ 1350static int 1351_nis_endpwent(void *nsrv, void *nscb, va_list ap) 1352{ 1353 1354 return _nis_end(&_nis_state); 1355} 1356 1357 1358/*ARGSUSED*/ 1359static int 1360_nis_getpwent(void *nsrv, void *nscb, va_list ap) 1361{ 1362 struct passwd **retval = va_arg(ap, struct passwd **); 1363 1364 char *key, *data; 1365 int keylen, datalen, rv, nisr; 1366 1367 _DIAGASSERT(retval != NULL); 1368 1369 *retval = NULL; 1370 1371 if (_nis_state.done) /* exhausted search */ 1372 return NS_NOTFOUND; 1373 if (_nis_state.domain == NULL) { 1374 /* only start if NIS not setup */ 1375 rv = _nis_start(&_nis_state); 1376 if (rv != NS_SUCCESS) 1377 return rv; 1378 } 1379 1380 next_nis_entry: 1381 key = NULL; 1382 data = NULL; 1383 rv = NS_NOTFOUND; 1384 1385 if (_nis_state.current) { /* already searching */ 1386 nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1387 _nis_state.current, _nis_state.currentlen, 1388 &key, &keylen, &data, &datalen); 1389 free(_nis_state.current); 1390 _nis_state.current = NULL; 1391 switch (nisr) { 1392 case 0: 1393 _nis_state.current = key; 1394 _nis_state.currentlen = keylen; 1395 key = NULL; 1396 break; 1397 case YPERR_NOMORE: 1398 _nis_state.done = 1; 1399 goto nisent_out; 1400 default: 1401 rv = NS_UNAVAIL; 1402 goto nisent_out; 1403 } 1404 } else { /* new search */ 1405 if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1406 &_nis_state.current, &_nis_state.currentlen, 1407 &data, &datalen)) { 1408 rv = NS_UNAVAIL; 1409 goto nisent_out; 1410 } 1411 } 1412 1413 data[datalen] = '\0'; /* clear trailing \n */ 1414 /* validate line */ 1415 if (_nis_parse(data, &_nis_passwd, 1416 _nis_passwdbuf, sizeof(_nis_passwdbuf), &_nis_state)) 1417 rv = NS_SUCCESS; 1418 else { /* dodgy entry, try again */ 1419 free(data); 1420 goto next_nis_entry; 1421 } 1422 1423 nisent_out: 1424 if (key) 1425 free(key); 1426 if (data) 1427 free(data); 1428 if (rv == NS_SUCCESS) 1429 *retval = &_nis_passwd; 1430 return rv; 1431} 1432 1433/*ARGSUSED*/ 1434static int 1435_nis_getpwent_r(void *nsrv, void *nscb, va_list ap) 1436{ 1437 int *retval = va_arg(ap, int *); 1438 struct passwd *pw = va_arg(ap, struct passwd *); 1439 char *buffer = va_arg(ap, char *); 1440 size_t buflen = va_arg(ap, size_t); 1441 struct passwd **result = va_arg(ap, struct passwd **); 1442 1443 char *key, *data; 1444 int keylen, datalen, rv, nisr; 1445 1446 _DIAGASSERT(retval != NULL); 1447 _DIAGASSERT(pw != NULL); 1448 _DIAGASSERT(buffer != NULL); 1449 _DIAGASSERT(result != NULL); 1450 1451 *retval = 0; 1452 1453 if (_nis_state.done) /* exhausted search */ 1454 return NS_NOTFOUND; 1455 if (_nis_state.domain == NULL) { 1456 /* only start if NIS not setup */ 1457 rv = _nis_start(&_nis_state); 1458 if (rv != NS_SUCCESS) 1459 return rv; 1460 } 1461 1462 next_nis_entry: 1463 key = NULL; 1464 data = NULL; 1465 rv = NS_NOTFOUND; 1466 1467 if (_nis_state.current) { /* already searching */ 1468 nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1469 _nis_state.current, _nis_state.currentlen, 1470 &key, &keylen, &data, &datalen); 1471 free(_nis_state.current); 1472 _nis_state.current = NULL; 1473 switch (nisr) { 1474 case 0: 1475 _nis_state.current = key; 1476 _nis_state.currentlen = keylen; 1477 key = NULL; 1478 break; 1479 case YPERR_NOMORE: 1480 _nis_state.done = 1; 1481 goto nisent_out; 1482 default: 1483 rv = NS_UNAVAIL; 1484 goto nisent_out; 1485 } 1486 } else { /* new search */ 1487 if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1488 &_nis_state.current, &_nis_state.currentlen, 1489 &data, &datalen)) { 1490 rv = NS_UNAVAIL; 1491 goto nisent_out; 1492 } 1493 } 1494 1495 data[datalen] = '\0'; /* clear trailing \n */ 1496 /* validate line */ 1497 if (_nis_parse(data, pw, buffer, buflen, &_nis_state)) 1498 rv = NS_SUCCESS; 1499 else { /* dodgy entry, try again */ 1500 if (key) 1501 free(key); 1502 free(data); 1503 goto next_nis_entry; 1504 } 1505 1506 nisent_out: 1507 if (key) 1508 free(key); 1509 if (data) 1510 free(data); 1511 if (rv == NS_SUCCESS) 1512 *result = pw; 1513 else 1514 *result = NULL; 1515 return rv; 1516} 1517 1518/*ARGSUSED*/ 1519static int 1520_nis_getpwuid(void *nsrv, void *nscb, va_list ap) 1521{ 1522 struct passwd **retval = va_arg(ap, struct passwd **); 1523 uid_t uid = va_arg(ap, uid_t); 1524 1525 int rv, rerror; 1526 1527 _DIAGASSERT(retval != NULL); 1528 1529 *retval = NULL; 1530 rv = _nis_start(&_nis_state); 1531 if (rv != NS_SUCCESS) 1532 return rv; 1533 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%u", (unsigned int)uid); 1534 rv = _nis_pwscan(&rerror, &_nis_passwd, 1535 _nis_passwdbuf, sizeof(_nis_passwdbuf), 1536 &_nis_state, __nis_pw_u_map, __arraycount(__nis_pw_u_map)); 1537 if (!_nis_state.stayopen) 1538 _nis_end(&_nis_state); 1539 if (rv == NS_SUCCESS && uid == _nis_passwd.pw_uid) 1540 *retval = &_nis_passwd; 1541 return rv; 1542} 1543 1544/*ARGSUSED*/ 1545static int 1546_nis_getpwuid_r(void *nsrv, void *nscb, va_list ap) 1547{ 1548 int *retval = va_arg(ap, int *); 1549 uid_t uid = va_arg(ap, uid_t); 1550 struct passwd *pw = va_arg(ap, struct passwd *); 1551 char *buffer = va_arg(ap, char *); 1552 size_t buflen = va_arg(ap, size_t); 1553 struct passwd **result = va_arg(ap, struct passwd **); 1554 1555 struct nis_state state; 1556 int rv; 1557 1558 _DIAGASSERT(retval != NULL); 1559 _DIAGASSERT(pw != NULL); 1560 _DIAGASSERT(buffer != NULL); 1561 _DIAGASSERT(result != NULL); 1562 1563 *result = NULL; 1564 snprintf(buffer, buflen, "%u", (unsigned int)uid); 1565/* remark: we run under a global mutex inside of this module ... */ 1566 if (_nis_state.stayopen) 1567 { /* use global state only if stayopen is set - otherwise we would blow up getpwent_r() ... */ 1568 rv = _nis_pwscan(retval, pw, buffer, buflen, 1569 &_nis_state, __nis_pw_u_map, __arraycount(__nis_pw_u_map)); 1570 } 1571 else 1572 { /* keep old semantic if no stayopen set - no need to call _nis_start() here - _nis_pwscan() will do it for us ... */ 1573 /* use same way as in getgrent.c ... */ 1574 memset(&state, 0, sizeof(state)); 1575 rv = _nis_pwscan(retval, pw, buffer, buflen, 1576 &state, __nis_pw_u_map, __arraycount(__nis_pw_u_map)); 1577 _nis_end(&state); 1578 } 1579 if (rv != NS_SUCCESS) 1580 return rv; 1581 if (uid == pw->pw_uid) { 1582 *result = pw; 1583 return NS_SUCCESS; 1584 } else 1585 return NS_NOTFOUND; 1586} 1587 1588/*ARGSUSED*/ 1589static int 1590_nis_getpwnam(void *nsrv, void *nscb, va_list ap) 1591{ 1592 struct passwd **retval = va_arg(ap, struct passwd **); 1593 const char *name = va_arg(ap, const char *); 1594 1595 int rv, rerror; 1596 1597 _DIAGASSERT(retval != NULL); 1598 1599 *retval = NULL; 1600 rv = _nis_start(&_nis_state); 1601 if (rv != NS_SUCCESS) 1602 return rv; 1603 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%s", name); 1604 rv = _nis_pwscan(&rerror, &_nis_passwd, 1605 _nis_passwdbuf, sizeof(_nis_passwdbuf), 1606 &_nis_state, __nis_pw_n_map, __arraycount(__nis_pw_n_map)); 1607 if (!_nis_state.stayopen) 1608 _nis_end(&_nis_state); 1609 if (rv == NS_SUCCESS && strcmp(name, _nis_passwd.pw_name) == 0) 1610 *retval = &_nis_passwd; 1611 return rv; 1612} 1613 1614/*ARGSUSED*/ 1615static int 1616_nis_getpwnam_r(void *nsrv, void *nscb, va_list ap) 1617{ 1618 int *retval = va_arg(ap, int *); 1619 const char *name = va_arg(ap, const char *); 1620 struct passwd *pw = va_arg(ap, struct passwd *); 1621 char *buffer = va_arg(ap, char *); 1622 size_t buflen = va_arg(ap, size_t); 1623 struct passwd **result = va_arg(ap, struct passwd **); 1624 1625 struct nis_state state; 1626 int rv; 1627 1628 _DIAGASSERT(retval != NULL); 1629 _DIAGASSERT(pw != NULL); 1630 _DIAGASSERT(buffer != NULL); 1631 _DIAGASSERT(result != NULL); 1632 1633 *result = NULL; 1634 snprintf(buffer, buflen, "%s", name); 1635/* remark: we run under a global mutex inside of this module ... */ 1636 if (_nis_state.stayopen) 1637 { /* use global state only if stayopen is set - otherwise we would blow up getpwent_r() ... */ 1638 rv = _nis_pwscan(retval, pw, buffer, buflen, 1639 &_nis_state, __nis_pw_n_map, __arraycount(__nis_pw_n_map)); 1640 } 1641 else 1642 { /* keep old semantic if no stayopen set - no need to call _nis_start() here - _nis_pwscan() will do it for us ... */ 1643 /* use same way as in getgrent.c ... */ 1644 memset(&state, 0, sizeof(state)); 1645 rv = _nis_pwscan(retval, pw, buffer, buflen, 1646 &state, __nis_pw_n_map, __arraycount(__nis_pw_n_map)); 1647 _nis_end(&state); 1648 } 1649 if (rv != NS_SUCCESS) 1650 return rv; 1651 if (strcmp(name, pw->pw_name) == 0) { 1652 *result = pw; 1653 return NS_SUCCESS; 1654 } else 1655 return NS_NOTFOUND; 1656} 1657 1658#endif /* YP */ 1659 1660 1661#ifdef _PASSWD_COMPAT 1662 /* 1663 * compat methods 1664 */ 1665 1666 /* state shared between compat methods */ 1667 1668struct compat_state { 1669 int stayopen; /* see getpassent(3) */ 1670 DB *db; /* passwd DB */ 1671 int keynum; /* key counter, -1 if no more */ 1672 enum { /* current compat mode */ 1673 COMPAT_NOTOKEN = 0, /* no compat token present */ 1674 COMPAT_NONE, /* parsing normal pwd.db line */ 1675 COMPAT_FULL, /* parsing `+' entries */ 1676 COMPAT_USER, /* parsing `+name' entries */ 1677 COMPAT_NETGROUP /* parsing `+@netgroup' entries */ 1678 } mode; 1679 char *user; /* COMPAT_USER "+name" */ 1680 DB *exclude; /* compat exclude DB */ 1681 struct passwd proto; /* proto passwd entry */ 1682 char protobuf[_GETPW_R_SIZE_MAX]; 1683 /* buffer for proto ptrs */ 1684 int protoflags; /* proto passwd flags */ 1685 int version; 1686}; 1687 1688static struct compat_state _compat_state; 1689 /* storage for non _r functions */ 1690static struct passwd _compat_passwd; 1691static char _compat_passwdbuf[_GETPW_R_SIZE_MAX]; 1692 1693static int 1694_compat_start(struct compat_state *state) 1695{ 1696 int rv; 1697 1698 _DIAGASSERT(state != NULL); 1699 1700 state->keynum = 0; 1701 if (state->db == NULL) { /* not open yet */ 1702 DBT key, data; 1703 DBT pkey, pdata; 1704 char bf[MAXLOGNAME]; 1705 1706 rv = _pw_opendb(&state->db, &state->version); 1707 if (rv != NS_SUCCESS) 1708 return rv; 1709 1710 state->mode = COMPAT_NOTOKEN; 1711 1712 /* 1713 * Determine if the "compat" token is present in pwd.db; 1714 * either "__YP!" or PW_KEYBYNAME+"+". 1715 * Only works if pwd_mkdb installs the token. 1716 */ 1717 key.data = (u_char *)__UNCONST(__yp_token); 1718 key.size = strlen(__yp_token); 1719 1720 bf[0] = _PW_KEYBYNAME; /* Pre-token database support. */ 1721 bf[1] = '+'; 1722 pkey.data = (u_char *)bf; 1723 pkey.size = 2; 1724 1725 if ((state->db->get)(state->db, &key, &data, 0) == 0 1726 || (state->db->get)(state->db, &pkey, &pdata, 0) == 0) 1727 state->mode = COMPAT_NONE; 1728 } 1729 return NS_SUCCESS; 1730} 1731 1732static int 1733_compat_end(struct compat_state *state) 1734{ 1735 1736 _DIAGASSERT(state != NULL); 1737 1738 state->keynum = 0; 1739 if (state->db) { 1740 (void)(state->db->close)(state->db); 1741 state->db = NULL; 1742 } 1743 state->mode = COMPAT_NOTOKEN; 1744 if (state->user) 1745 free(state->user); 1746 state->user = NULL; 1747 if (state->exclude != NULL) 1748 (void)(state->exclude->close)(state->exclude); 1749 state->exclude = NULL; 1750 state->proto.pw_name = NULL; 1751 state->protoflags = 0; 1752 return NS_SUCCESS; 1753} 1754 1755/* 1756 * _compat_add_exclude 1757 * add the name to the exclude list in state->exclude. 1758 */ 1759static int 1760_compat_add_exclude(struct compat_state *state, const char *name) 1761{ 1762 DBT key, data; 1763 1764 _DIAGASSERT(state != NULL); 1765 _DIAGASSERT(name != NULL); 1766 1767 /* initialize the exclusion table if needed */ 1768 if (state->exclude == NULL) { 1769 state->exclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL); 1770 if (state->exclude == NULL) 1771 return 0; 1772 } 1773 1774 key.size = strlen(name); /* set up the key */ 1775 key.data = (u_char *)__UNCONST(name); 1776 1777 data.data = NULL; /* data is nothing */ 1778 data.size = 0; 1779 1780 /* store it */ 1781 if ((state->exclude->put)(state->exclude, &key, &data, 0) == -1) 1782 return 0; 1783 1784 return 1; 1785} 1786 1787/* 1788 * _compat_is_excluded 1789 * test if a name is on the compat mode exclude list 1790 */ 1791static int 1792_compat_is_excluded(struct compat_state *state, const char *name) 1793{ 1794 DBT key, data; 1795 1796 _DIAGASSERT(state != NULL); 1797 _DIAGASSERT(name != NULL); 1798 1799 if (state->exclude == NULL) 1800 return 0; /* nothing excluded */ 1801 1802 key.size = strlen(name); /* set up the key */ 1803 key.data = (u_char *)__UNCONST(name); 1804 1805 if ((state->exclude->get)(state->exclude, &key, &data, 0) == 0) 1806 return 1; /* is excluded */ 1807 1808 return 0; 1809} 1810 1811 1812/* 1813 * _passwdcompat_bad 1814 * log an error if "files" or "compat" is specified in 1815 * passwd_compat database 1816 */ 1817/*ARGSUSED*/ 1818static int 1819_passwdcompat_bad(void *nsrv, void *nscb, va_list ap) 1820{ 1821 static int warned; 1822 1823 _DIAGASSERT(nsrv != NULL); 1824 _DIAGASSERT(nscb != NULL); 1825 1826 if (!warned) { 1827 syslog(LOG_ERR, 1828 "nsswitch.conf passwd_compat database can't use '%s'", 1829 (char *)nscb); 1830 } 1831 warned = 1; 1832 return NS_UNAVAIL; 1833} 1834 1835/* 1836 * _passwdcompat_setpassent 1837 * Call setpassent for all passwd_compat sources. 1838 */ 1839static int 1840_passwdcompat_setpassent(int stayopen) 1841{ 1842 static const ns_dtab dtab[] = { 1843 NS_FILES_CB(_passwdcompat_bad, "files") 1844 NS_DNS_CB(_dns_setpassent, NULL) 1845 NS_NIS_CB(_nis_setpassent, NULL) 1846 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1847 NS_NULL_CB 1848 }; 1849 1850 int rv, result; 1851 1852 rv = nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpassent", 1853 __nsdefaultnis_forceall, &result, stayopen); 1854 return rv; 1855} 1856 1857/* 1858 * _passwdcompat_endpwent 1859 * Call endpwent for all passwd_compat sources. 1860 */ 1861static int 1862_passwdcompat_endpwent(void) 1863{ 1864 static const ns_dtab dtab[] = { 1865 NS_FILES_CB(_passwdcompat_bad, "files") 1866 NS_DNS_CB(_dns_endpwent, NULL) 1867 NS_NIS_CB(_nis_endpwent, NULL) 1868 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1869 NS_NULL_CB 1870 }; 1871 1872 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent", 1873 __nsdefaultnis_forceall); 1874} 1875 1876/* 1877 * _passwdcompat_pwscan 1878 * When a name lookup in compat mode is required (e.g., `+name', or a 1879 * name in `+@netgroup'), look it up in the 'passwd_compat' nsswitch 1880 * database. 1881 * Fail if passwd_compat contains files or compat. 1882 */ 1883static int 1884_passwdcompat_pwscan(struct passwd *pw, char *buffer, size_t buflen, 1885 int search, const char *name, uid_t uid) 1886{ 1887 static const ns_dtab compatentdtab[] = { 1888 NS_FILES_CB(_passwdcompat_bad, "files") 1889 NS_DNS_CB(_dns_getpwent_r, NULL) 1890 NS_NIS_CB(_nis_getpwent_r, NULL) 1891 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1892 NS_NULL_CB 1893 }; 1894 static const ns_dtab compatuiddtab[] = { 1895 NS_FILES_CB(_passwdcompat_bad, "files") 1896 NS_DNS_CB(_dns_getpwuid_r, NULL) 1897 NS_NIS_CB(_nis_getpwuid_r, NULL) 1898 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1899 NS_NULL_CB 1900 }; 1901 static const ns_dtab compatnamdtab[] = { 1902 NS_FILES_CB(_passwdcompat_bad, "files") 1903 NS_DNS_CB(_dns_getpwnam_r, NULL) 1904 NS_NIS_CB(_nis_getpwnam_r, NULL) 1905 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1906 NS_NULL_CB 1907 }; 1908 1909 int rv, crv; 1910 struct passwd *cpw; 1911 1912 switch (search) { 1913 case _PW_KEYBYNUM: 1914 rv = nsdispatch(NULL, compatentdtab, 1915 NSDB_PASSWD_COMPAT, "getpwent_r", __nsdefaultnis, 1916 &crv, pw, buffer, buflen, &cpw); 1917 break; 1918 case _PW_KEYBYNAME: 1919 _DIAGASSERT(name != NULL); 1920 rv = nsdispatch(NULL, compatnamdtab, 1921 NSDB_PASSWD_COMPAT, "getpwnam_r", __nsdefaultnis, 1922 &crv, name, pw, buffer, buflen, &cpw); 1923 break; 1924 case _PW_KEYBYUID: 1925 rv = nsdispatch(NULL, compatuiddtab, 1926 NSDB_PASSWD_COMPAT, "getpwuid_r", __nsdefaultnis, 1927 &crv, uid, pw, buffer, buflen, &cpw); 1928 break; 1929 default: 1930 abort(); 1931 /*NOTREACHED*/ 1932 } 1933 return rv; 1934} 1935 1936/* 1937 * _compat_pwscan 1938 * Search state->db for the next desired entry. 1939 * If search is _PW_KEYBYNUM, look for state->keynum. 1940 * If search is _PW_KEYBYNAME, look for name. 1941 * If search is _PW_KEYBYUID, look for uid. 1942 * Sets *retval to the errno if the result is not NS_SUCCESS 1943 * or NS_NOTFOUND. 1944 */ 1945static int 1946_compat_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 1947 struct compat_state *state, int search, const char *name, uid_t uid) 1948{ 1949 DBT key; 1950 int rv, r, pwflags; 1951 const char *user, *host, *dom; 1952 const void *from; 1953 size_t fromlen; 1954 1955 _DIAGASSERT(retval != NULL); 1956 _DIAGASSERT(pw != NULL); 1957 _DIAGASSERT(buffer != NULL); 1958 _DIAGASSERT(state != NULL); 1959 /* name may be NULL */ 1960 1961 *retval = 0; 1962 1963 if (state->db == NULL) { 1964 rv = _compat_start(state); 1965 if (rv != NS_SUCCESS) 1966 return rv; 1967 } 1968 if (buflen <= 1) { /* buffer too small */ 1969 *retval = ERANGE; 1970 return NS_UNAVAIL; 1971 } 1972 1973 for (;;) { /* loop over pwd.db */ 1974 rv = NS_NOTFOUND; 1975 if (state->mode != COMPAT_NOTOKEN && 1976 state->mode != COMPAT_NONE) { 1977 /* doing a compat lookup */ 1978 struct passwd cpw; 1979 char cbuf[_GETPW_R_SIZE_MAX]; 1980 1981 switch (state->mode) { 1982 1983 case COMPAT_FULL: 1984 /* get next user or lookup by key */ 1985 rv = _passwdcompat_pwscan(&cpw, 1986 cbuf, sizeof(cbuf), search, name, uid); 1987 if (rv != NS_SUCCESS) 1988 state->mode = COMPAT_NONE; 1989 break; 1990 1991 case COMPAT_NETGROUP: 1992/* XXXREENTRANT: getnetgrent is not thread safe */ 1993 /* get next user from netgroup */ 1994 r = getnetgrent(&host, &user, &dom); 1995 if (r == 0) { /* end of group */ 1996 endnetgrent(); 1997 state->mode = COMPAT_NONE; 1998 break; 1999 } 2000 if (!user || !*user) 2001 break; 2002 rv = _passwdcompat_pwscan(&cpw, 2003 cbuf, sizeof(cbuf), 2004 _PW_KEYBYNAME, user, 0); 2005 break; 2006 2007 case COMPAT_USER: 2008 /* get specific user */ 2009 if (state->user == NULL) { 2010 state->mode = COMPAT_NONE; 2011 break; 2012 } 2013 rv = _passwdcompat_pwscan(&cpw, 2014 cbuf, sizeof(cbuf), 2015 _PW_KEYBYNAME, state->user, 0); 2016 free(state->user); 2017 state->user = NULL; 2018 state->mode = COMPAT_NONE; 2019 break; 2020 2021 case COMPAT_NOTOKEN: 2022 case COMPAT_NONE: 2023 abort(); 2024 2025 } 2026 if (rv != NS_SUCCESS) /* if not matched, next loop */ 2027 continue; 2028 2029 /* copy cpw to pw, applying prototype */ 2030 if (! _pw_copy(&cpw, pw, buffer, buflen, 2031 &state->proto, state->protoflags)) { 2032 rv = NS_UNAVAIL; 2033 break; 2034 } 2035 2036 if (_compat_is_excluded(state, pw->pw_name)) 2037 continue; /* excluded; next loop */ 2038 2039 if ((search == _PW_KEYBYNAME 2040 && strcmp(pw->pw_name, name) != 0) 2041 || (search == _PW_KEYBYUID && pw->pw_uid != uid)) { 2042 continue; /* not specific; next loop */ 2043 } 2044 2045 break; /* exit loop if found */ 2046 } else { /* not a compat line */ 2047 state->proto.pw_name = NULL; 2048 /* clear prototype */ 2049 } 2050 2051 if (state->mode == COMPAT_NOTOKEN) { 2052 /* no compat token; do direct lookup */ 2053 switch (search) { 2054 case _PW_KEYBYNUM: 2055 if (state->keynum == -1) /* no more records */ 2056 return NS_NOTFOUND; 2057 state->keynum++; 2058 from = &state->keynum; 2059 fromlen = sizeof(state->keynum); 2060 break; 2061 case _PW_KEYBYNAME: 2062 from = name; 2063 fromlen = strlen(name); 2064 break; 2065 case _PW_KEYBYUID: 2066 from = &uid; 2067 fromlen = sizeof(uid); 2068 break; 2069 default: 2070 abort(); 2071 } 2072 buffer[0] = search; 2073 } else { 2074 /* compat token; do line by line */ 2075 if (state->keynum == -1) /* no more records */ 2076 return NS_NOTFOUND; 2077 state->keynum++; 2078 from = &state->keynum; 2079 fromlen = sizeof(state->keynum); 2080 buffer[0] = _PW_KEYBYNUM; 2081 } 2082 2083 if (buflen <= fromlen) { /* buffer too small */ 2084 *retval = ERANGE; 2085 return NS_UNAVAIL; 2086 } 2087 memmove(buffer + 1, from, fromlen); /* setup key */ 2088 key.size = fromlen + 1; 2089 key.data = (u_char *)buffer; 2090 2091 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, &pwflags, 2092 state->version); 2093 if (rv != NS_SUCCESS) /* stop on error */ 2094 break; 2095 2096 if (state->mode == COMPAT_NOTOKEN) 2097 break; /* stop if no compat token */ 2098 2099 if (pw->pw_name[0] == '+') { 2100 /* compat inclusion */ 2101 switch(pw->pw_name[1]) { 2102 case '\0': /* `+' */ 2103 state->mode = COMPAT_FULL; 2104 /* reset passwd_compat search */ 2105/* XXXREENTRANT: setpassent is not thread safe ? */ 2106 (void) _passwdcompat_setpassent(_compat_state.stayopen); 2107 break; 2108 case '@': /* `+@netgroup' */ 2109 state->mode = COMPAT_NETGROUP; 2110 /* reset netgroup search */ 2111/* XXXREENTRANT: setnetgrent is not thread safe */ 2112 setnetgrent(pw->pw_name + 2); 2113 break; 2114 default: /* `+name' */ 2115 state->mode = COMPAT_USER; 2116 if (state->user) 2117 free(state->user); 2118 state->user = strdup(pw->pw_name + 1); 2119 break; 2120 } 2121 /* save the prototype */ 2122 state->protoflags = pwflags; 2123 if (! _pw_copy(pw, &state->proto, state->protobuf, 2124 sizeof(state->protobuf), NULL, 0)) { 2125 rv = NS_UNAVAIL; 2126 break; 2127 } 2128 continue; /* loop again after inclusion */ 2129 } else if (pw->pw_name[0] == '-') { 2130 /* compat exclusion */ 2131 rv = NS_SUCCESS; 2132 switch(pw->pw_name[1]) { 2133 case '\0': /* `-' */ 2134 break; 2135 case '@': /* `-@netgroup' */ 2136/* XXXREENTRANT: {set,get,end}netgrent is not thread safe */ 2137 setnetgrent(pw->pw_name + 2); 2138 while (getnetgrent(&host, &user, &dom)) { 2139 if (!user || !*user) 2140 continue; 2141 if (! _compat_add_exclude(state,user)) { 2142 rv = NS_UNAVAIL; 2143 break; 2144 } 2145 } 2146 endnetgrent(); 2147 break; 2148 default: /* `-name' */ 2149 if (! _compat_add_exclude(state, 2150 pw->pw_name + 1)) { 2151 rv = NS_UNAVAIL; 2152 } 2153 break; 2154 } 2155 if (rv != NS_SUCCESS) /* exclusion failure */ 2156 break; 2157 continue; /* loop again after exclusion */ 2158 } 2159 if (search == _PW_KEYBYNUM || 2160 (search == _PW_KEYBYUID && pw->pw_uid == uid) || 2161 (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) == 0)) 2162 break; /* token mode match found */ 2163 } 2164 2165 if (rv == NS_NOTFOUND && 2166 (search == _PW_KEYBYNUM || state->mode != COMPAT_NOTOKEN)) 2167 state->keynum = -1; /* flag `no more records' */ 2168 2169 if (rv == NS_SUCCESS) { 2170 if ((search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0) 2171 || (search == _PW_KEYBYUID && pw->pw_uid != uid)) 2172 rv = NS_NOTFOUND; 2173 } 2174 2175 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 2176 *retval = errno; 2177 return rv; 2178} 2179 2180/*ARGSUSED*/ 2181static int 2182_compat_setpwent(void *nsrv, void *nscb, va_list ap) 2183{ 2184 2185 /* force passwd_compat setpwent() */ 2186 (void) _passwdcompat_setpassent(0); 2187 2188 /* reset state, keep db open */ 2189 _compat_state.stayopen = 0; 2190 return _compat_start(&_compat_state); 2191} 2192 2193/*ARGSUSED*/ 2194static int 2195_compat_setpassent(void *nsrv, void *nscb, va_list ap) 2196{ 2197 int *retval = va_arg(ap, int *); 2198 int stayopen = va_arg(ap, int); 2199 2200 int rv; 2201 2202 /* force passwd_compat setpassent() */ 2203 (void) _passwdcompat_setpassent(stayopen); 2204 2205 _compat_state.stayopen = stayopen; 2206 rv = _compat_start(&_compat_state); 2207 *retval = (rv == NS_SUCCESS); 2208 return rv; 2209} 2210 2211/*ARGSUSED*/ 2212static int 2213_compat_endpwent(void *nsrv, void *nscb, va_list ap) 2214{ 2215 2216 /* force passwd_compat endpwent() */ 2217 (void) _passwdcompat_endpwent(); 2218 2219 /* reset state, close db */ 2220 _compat_state.stayopen = 0; 2221 return _compat_end(&_compat_state); 2222} 2223 2224 2225/*ARGSUSED*/ 2226static int 2227_compat_getpwent(void *nsrv, void *nscb, va_list ap) 2228{ 2229 struct passwd **retval = va_arg(ap, struct passwd **); 2230 2231 int rv, rerror; 2232 2233 _DIAGASSERT(retval != NULL); 2234 2235 *retval = NULL; 2236 rv = _compat_pwscan(&rerror, &_compat_passwd, 2237 _compat_passwdbuf, sizeof(_compat_passwdbuf), 2238 &_compat_state, _PW_KEYBYNUM, NULL, 0); 2239 if (rv == NS_SUCCESS) 2240 *retval = &_compat_passwd; 2241 return rv; 2242} 2243 2244/*ARGSUSED*/ 2245static int 2246_compat_getpwent_r(void *nsrv, void *nscb, va_list ap) 2247{ 2248 int *retval = va_arg(ap, int *); 2249 struct passwd *pw = va_arg(ap, struct passwd *); 2250 char *buffer = va_arg(ap, char *); 2251 size_t buflen = va_arg(ap, size_t); 2252 struct passwd **result = va_arg(ap, struct passwd **); 2253 2254 int rv; 2255 2256 _DIAGASSERT(retval != NULL); 2257 _DIAGASSERT(pw != NULL); 2258 _DIAGASSERT(buffer != NULL); 2259 _DIAGASSERT(result != NULL); 2260 2261 rv = _compat_pwscan(retval, pw, buffer, buflen, &_compat_state, 2262 _PW_KEYBYNUM, NULL, 0); 2263 if (rv == NS_SUCCESS) 2264 *result = pw; 2265 else 2266 *result = NULL; 2267 return rv; 2268} 2269 2270 2271/*ARGSUSED*/ 2272static int 2273_compat_getpwnam(void *nsrv, void *nscb, va_list ap) 2274{ 2275 struct passwd **retval = va_arg(ap, struct passwd **); 2276 const char *name = va_arg(ap, const char *); 2277 2278 int rv, rerror; 2279 2280 _DIAGASSERT(retval != NULL); 2281 2282 *retval = NULL; 2283 rv = _compat_start(&_compat_state); 2284 if (rv != NS_SUCCESS) 2285 return rv; 2286 rv = _compat_pwscan(&rerror, &_compat_passwd, 2287 _compat_passwdbuf, sizeof(_compat_passwdbuf), 2288 &_compat_state, _PW_KEYBYNAME, name, 0); 2289 if (!_compat_state.stayopen) 2290 _compat_end(&_compat_state); 2291 if (rv == NS_SUCCESS) 2292 *retval = &_compat_passwd; 2293 return rv; 2294} 2295 2296/*ARGSUSED*/ 2297static int 2298_compat_getpwnam_r(void *nsrv, void *nscb, va_list ap) 2299{ 2300 int *retval = va_arg(ap, int *); 2301 const char *name = va_arg(ap, const char *); 2302 struct passwd *pw = va_arg(ap, struct passwd *); 2303 char *buffer = va_arg(ap, char *); 2304 size_t buflen = va_arg(ap, size_t); 2305 struct passwd **result = va_arg(ap, struct passwd **); 2306 2307 struct compat_state state; 2308 int rv; 2309 2310 _DIAGASSERT(retval != NULL); 2311 _DIAGASSERT(pw != NULL); 2312 _DIAGASSERT(buffer != NULL); 2313 _DIAGASSERT(result != NULL); 2314 2315 *result = NULL; 2316 memset(&state, 0, sizeof(state)); 2317 rv = _compat_pwscan(retval, pw, buffer, buflen, &state, 2318 _PW_KEYBYNAME, name, 0); 2319 _compat_end(&state); 2320 if (rv == NS_SUCCESS) 2321 *result = pw; 2322 return rv; 2323} 2324 2325/*ARGSUSED*/ 2326static int 2327_compat_getpwuid(void *nsrv, void *nscb, va_list ap) 2328{ 2329 struct passwd **retval = va_arg(ap, struct passwd **); 2330 uid_t uid = va_arg(ap, uid_t); 2331 2332 int rv, rerror; 2333 2334 _DIAGASSERT(retval != NULL); 2335 2336 *retval = NULL; 2337 rv = _compat_start(&_compat_state); 2338 if (rv != NS_SUCCESS) 2339 return rv; 2340 rv = _compat_pwscan(&rerror, &_compat_passwd, 2341 _compat_passwdbuf, sizeof(_compat_passwdbuf), 2342 &_compat_state, _PW_KEYBYUID, NULL, uid); 2343 if (!_compat_state.stayopen) 2344 _compat_end(&_compat_state); 2345 if (rv == NS_SUCCESS) 2346 *retval = &_compat_passwd; 2347 return rv; 2348} 2349 2350/*ARGSUSED*/ 2351static int 2352_compat_getpwuid_r(void *nsrv, void *nscb, va_list ap) 2353{ 2354 int *retval = va_arg(ap, int *); 2355 uid_t uid = va_arg(ap, uid_t); 2356 struct passwd *pw = va_arg(ap, struct passwd *); 2357 char *buffer = va_arg(ap, char *); 2358 size_t buflen = va_arg(ap, size_t); 2359 struct passwd **result = va_arg(ap, struct passwd **); 2360 2361 struct compat_state state; 2362 int rv; 2363 2364 _DIAGASSERT(retval != NULL); 2365 _DIAGASSERT(pw != NULL); 2366 _DIAGASSERT(buffer != NULL); 2367 _DIAGASSERT(result != NULL); 2368 2369 *result = NULL; 2370 memset(&state, 0, sizeof(state)); 2371 rv = _compat_pwscan(retval, pw, buffer, buflen, &state, 2372 _PW_KEYBYUID, NULL, uid); 2373 _compat_end(&state); 2374 if (rv == NS_SUCCESS) 2375 *result = pw; 2376 return rv; 2377} 2378 2379#endif /* _PASSWD_COMPAT */ 2380 2381 2382 /* 2383 * public functions 2384 */ 2385 2386struct passwd * 2387getpwent(void) 2388{ 2389 int r; 2390 struct passwd *retval; 2391 2392 static const ns_dtab dtab[] = { 2393 NS_FILES_CB(_files_getpwent, NULL) 2394 NS_DNS_CB(_dns_getpwent, NULL) 2395 NS_NIS_CB(_nis_getpwent, NULL) 2396 NS_COMPAT_CB(_compat_getpwent, NULL) 2397 NS_NULL_CB 2398 }; 2399 2400 mutex_lock(&_pwmutex); 2401 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", __nsdefaultcompat, 2402 &retval); 2403 mutex_unlock(&_pwmutex); 2404 return (r == NS_SUCCESS) ? retval : NULL; 2405} 2406 2407int 2408getpwent_r(struct passwd *pwd, char *buffer, size_t buflen, 2409 struct passwd **result) 2410{ 2411 int r, retval; 2412 2413 static const ns_dtab dtab[] = { 2414 NS_FILES_CB(_files_getpwent_r, NULL) 2415 NS_DNS_CB(_dns_getpwent_r, NULL) 2416 NS_NIS_CB(_nis_getpwent_r, NULL) 2417 NS_COMPAT_CB(_compat_getpwent_r, NULL) 2418 NS_NULL_CB 2419 }; 2420 2421 _DIAGASSERT(pwd != NULL); 2422 _DIAGASSERT(buffer != NULL); 2423 _DIAGASSERT(result != NULL); 2424 2425 *result = NULL; 2426 retval = 0; 2427 mutex_lock(&_pwmutex); 2428 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent_r", __nsdefaultcompat, 2429 &retval, pwd, buffer, buflen, result); 2430 mutex_unlock(&_pwmutex); 2431 switch (r) { 2432 case NS_SUCCESS: 2433 case NS_NOTFOUND: 2434 return 0; 2435 default: 2436 return retval; 2437 } 2438} 2439 2440 2441struct passwd * 2442getpwnam(const char *name) 2443{ 2444 int rv; 2445 struct passwd *retval; 2446 2447 static const ns_dtab dtab[] = { 2448 NS_FILES_CB(_files_getpwnam, NULL) 2449 NS_DNS_CB(_dns_getpwnam, NULL) 2450 NS_NIS_CB(_nis_getpwnam, NULL) 2451 NS_COMPAT_CB(_compat_getpwnam, NULL) 2452 NS_NULL_CB 2453 }; 2454 2455 mutex_lock(&_pwmutex); 2456 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", __nsdefaultcompat, 2457 &retval, name); 2458 mutex_unlock(&_pwmutex); 2459 return (rv == NS_SUCCESS) ? retval : NULL; 2460} 2461 2462int 2463getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t buflen, 2464 struct passwd **result) 2465{ 2466 int r, retval; 2467 2468 static const ns_dtab dtab[] = { 2469 NS_FILES_CB(_files_getpwnam_r, NULL) 2470 NS_DNS_CB(_dns_getpwnam_r, NULL) 2471 NS_NIS_CB(_nis_getpwnam_r, NULL) 2472 NS_COMPAT_CB(_compat_getpwnam_r, NULL) 2473 NS_NULL_CB 2474 }; 2475 2476 _DIAGASSERT(name != NULL); 2477 _DIAGASSERT(pwd != NULL); 2478 _DIAGASSERT(buffer != NULL); 2479 _DIAGASSERT(result != NULL); 2480 2481 *result = NULL; 2482 retval = 0; 2483 mutex_lock(&_pwmutex); 2484 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam_r", __nsdefaultcompat, 2485 &retval, name, pwd, buffer, buflen, result); 2486 mutex_unlock(&_pwmutex); 2487 switch (r) { 2488 case NS_SUCCESS: 2489 case NS_NOTFOUND: 2490 return 0; 2491 default: 2492 return retval; 2493 } 2494} 2495 2496struct passwd * 2497getpwuid(uid_t uid) 2498{ 2499 int rv; 2500 struct passwd *retval; 2501 2502 static const ns_dtab dtab[] = { 2503 NS_FILES_CB(_files_getpwuid, NULL) 2504 NS_DNS_CB(_dns_getpwuid, NULL) 2505 NS_NIS_CB(_nis_getpwuid, NULL) 2506 NS_COMPAT_CB(_compat_getpwuid, NULL) 2507 NS_NULL_CB 2508 }; 2509 2510 mutex_lock(&_pwmutex); 2511 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", __nsdefaultcompat, 2512 &retval, uid); 2513 mutex_unlock(&_pwmutex); 2514 return (rv == NS_SUCCESS) ? retval : NULL; 2515} 2516 2517int 2518getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen, 2519 struct passwd **result) 2520{ 2521 int r, retval; 2522 2523 static const ns_dtab dtab[] = { 2524 NS_FILES_CB(_files_getpwuid_r, NULL) 2525 NS_DNS_CB(_dns_getpwuid_r, NULL) 2526 NS_NIS_CB(_nis_getpwuid_r, NULL) 2527 NS_COMPAT_CB(_compat_getpwuid_r, NULL) 2528 NS_NULL_CB 2529 }; 2530 2531 _DIAGASSERT(pwd != NULL); 2532 _DIAGASSERT(buffer != NULL); 2533 _DIAGASSERT(result != NULL); 2534 2535 *result = NULL; 2536 retval = 0; 2537 mutex_lock(&_pwmutex); 2538 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid_r", __nsdefaultcompat, 2539 &retval, uid, pwd, buffer, buflen, result); 2540 mutex_unlock(&_pwmutex); 2541 switch (r) { 2542 case NS_SUCCESS: 2543 case NS_NOTFOUND: 2544 return 0; 2545 default: 2546 return retval; 2547 } 2548} 2549 2550void 2551endpwent(void) 2552{ 2553 static const ns_dtab dtab[] = { 2554 NS_FILES_CB(_files_endpwent, NULL) 2555 NS_DNS_CB(_dns_endpwent, NULL) 2556 NS_NIS_CB(_nis_endpwent, NULL) 2557 NS_COMPAT_CB(_compat_endpwent, NULL) 2558 NS_NULL_CB 2559 }; 2560 2561 mutex_lock(&_pwmutex); 2562 /* force all endpwent() methods */ 2563 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", 2564 __nsdefaultcompat_forceall); 2565 mutex_unlock(&_pwmutex); 2566} 2567 2568/*ARGSUSED*/ 2569int 2570setpassent(int stayopen) 2571{ 2572 static const ns_dtab dtab[] = { 2573 NS_FILES_CB(_files_setpassent, NULL) 2574 NS_DNS_CB(_dns_setpassent, NULL) 2575 NS_NIS_CB(_nis_setpassent, NULL) 2576 NS_COMPAT_CB(_compat_setpassent, NULL) 2577 NS_NULL_CB 2578 }; 2579 int rv, retval; 2580 2581 mutex_lock(&_pwmutex); 2582 /* force all setpassent() methods */ 2583 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "setpassent", 2584 __nsdefaultcompat_forceall, &retval, stayopen); 2585 mutex_unlock(&_pwmutex); 2586 return (rv == NS_SUCCESS) ? retval : 0; 2587} 2588 2589void 2590setpwent(void) 2591{ 2592 static const ns_dtab dtab[] = { 2593 NS_FILES_CB(_files_setpwent, NULL) 2594 NS_DNS_CB(_dns_setpwent, NULL) 2595 NS_NIS_CB(_nis_setpwent, NULL) 2596 NS_COMPAT_CB(_compat_setpwent, NULL) 2597 NS_NULL_CB 2598 }; 2599 2600 mutex_lock(&_pwmutex); 2601 /* force all setpwent() methods */ 2602 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", 2603 __nsdefaultcompat_forceall); 2604 mutex_unlock(&_pwmutex); 2605} 2606