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