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