1 /* $NetBSD: getpwent.c,v 1.74 2007/02/03 16:22:48 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1997-2000, 2004-2005 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Luke Mewburn. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 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.74 2007/02/03 16:22:48 christos 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 free(data); 1388 goto next_nis_entry; 1389 } 1390 1391 nisent_out: 1392 if (key) 1393 free(key); 1394 if (data) 1395 free(data); 1396 if (rv == NS_SUCCESS) 1397 *retval = &_nis_passwd; 1398 return rv; 1399 } 1400 1401 /*ARGSUSED*/ 1402 static int 1403 _nis_getpwent_r(void *nsrv, void *nscb, va_list ap) 1404 { 1405 int *retval = va_arg(ap, int *); 1406 struct passwd *pw = va_arg(ap, struct passwd *); 1407 char *buffer = va_arg(ap, char *); 1408 size_t buflen = va_arg(ap, size_t); 1409 struct passwd **result = va_arg(ap, struct passwd **); 1410 1411 char *key, *data; 1412 int keylen, datalen, rv, nisr; 1413 1414 _DIAGASSERT(retval != NULL); 1415 _DIAGASSERT(pw != NULL); 1416 _DIAGASSERT(buffer != NULL); 1417 _DIAGASSERT(result != NULL); 1418 1419 *retval = 0; 1420 1421 if (_nis_state.done) /* exhausted search */ 1422 return NS_NOTFOUND; 1423 if (_nis_state.domain == NULL) { 1424 /* only start if NIS not setup */ 1425 rv = _nis_start(&_nis_state); 1426 if (rv != NS_SUCCESS) 1427 return rv; 1428 } 1429 1430 next_nis_entry: 1431 key = NULL; 1432 data = NULL; 1433 rv = NS_NOTFOUND; 1434 1435 if (_nis_state.current) { /* already searching */ 1436 nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1437 _nis_state.current, _nis_state.currentlen, 1438 &key, &keylen, &data, &datalen); 1439 free(_nis_state.current); 1440 _nis_state.current = NULL; 1441 switch (nisr) { 1442 case 0: 1443 _nis_state.current = key; 1444 _nis_state.currentlen = keylen; 1445 key = NULL; 1446 break; 1447 case YPERR_NOMORE: 1448 _nis_state.done = 1; 1449 goto nisent_out; 1450 default: 1451 rv = NS_UNAVAIL; 1452 goto nisent_out; 1453 } 1454 } else { /* new search */ 1455 if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1456 &_nis_state.current, &_nis_state.currentlen, 1457 &data, &datalen)) { 1458 rv = NS_UNAVAIL; 1459 goto nisent_out; 1460 } 1461 } 1462 1463 data[datalen] = '\0'; /* clear trailing \n */ 1464 /* validate line */ 1465 if (_nis_parse(data, pw, buffer, buflen, &_nis_state)) 1466 rv = NS_SUCCESS; 1467 else { /* dodgy entry, try again */ 1468 if (key) 1469 free(key); 1470 free(data); 1471 goto next_nis_entry; 1472 } 1473 1474 nisent_out: 1475 if (key) 1476 free(key); 1477 if (data) 1478 free(data); 1479 if (rv == NS_SUCCESS) 1480 *result = pw; 1481 else 1482 *result = NULL; 1483 return rv; 1484 } 1485 1486 /*ARGSUSED*/ 1487 static int 1488 _nis_getpwuid(void *nsrv, void *nscb, va_list ap) 1489 { 1490 struct passwd **retval = va_arg(ap, struct passwd **); 1491 uid_t uid = va_arg(ap, uid_t); 1492 1493 int rv, rerror; 1494 1495 _DIAGASSERT(retval != NULL); 1496 1497 *retval = NULL; 1498 rv = _nis_start(&_nis_state); 1499 if (rv != NS_SUCCESS) 1500 return rv; 1501 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%u", (unsigned int)uid); 1502 rv = _nis_pwscan(&rerror, &_nis_passwd, 1503 _nis_passwdbuf, sizeof(_nis_passwdbuf), 1504 &_nis_state, PASSWD_BYUID(&_nis_state)); 1505 if (!_nis_state.stayopen) 1506 _nis_end(&_nis_state); 1507 if (rv == NS_SUCCESS && uid == _nis_passwd.pw_uid) 1508 *retval = &_nis_passwd; 1509 return rv; 1510 } 1511 1512 /*ARGSUSED*/ 1513 static int 1514 _nis_getpwuid_r(void *nsrv, void *nscb, va_list ap) 1515 { 1516 int *retval = va_arg(ap, int *); 1517 uid_t uid = va_arg(ap, uid_t); 1518 struct passwd *pw = va_arg(ap, struct passwd *); 1519 char *buffer = va_arg(ap, char *); 1520 size_t buflen = va_arg(ap, size_t); 1521 struct passwd **result = va_arg(ap, struct passwd **); 1522 1523 struct nis_state state; 1524 int rv; 1525 1526 _DIAGASSERT(retval != NULL); 1527 _DIAGASSERT(pw != NULL); 1528 _DIAGASSERT(buffer != NULL); 1529 _DIAGASSERT(result != NULL); 1530 1531 *result = NULL; 1532 memset(&state, 0, sizeof(state)); 1533 rv = _nis_start(&state); 1534 if (rv != NS_SUCCESS) 1535 return rv; 1536 snprintf(buffer, buflen, "%u", (unsigned int)uid); 1537 rv = _nis_pwscan(retval, pw, buffer, buflen, 1538 &state, PASSWD_BYUID(&state)); 1539 _nis_end(&state); 1540 if (rv != NS_SUCCESS) 1541 return rv; 1542 if (uid == pw->pw_uid) { 1543 *result = pw; 1544 return NS_SUCCESS; 1545 } else 1546 return NS_NOTFOUND; 1547 } 1548 1549 /*ARGSUSED*/ 1550 static int 1551 _nis_getpwnam(void *nsrv, void *nscb, va_list ap) 1552 { 1553 struct passwd **retval = va_arg(ap, struct passwd **); 1554 const char *name = va_arg(ap, const char *); 1555 1556 int rv, rerror; 1557 1558 _DIAGASSERT(retval != NULL); 1559 1560 *retval = NULL; 1561 rv = _nis_start(&_nis_state); 1562 if (rv != NS_SUCCESS) 1563 return rv; 1564 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%s", name); 1565 rv = _nis_pwscan(&rerror, &_nis_passwd, 1566 _nis_passwdbuf, sizeof(_nis_passwdbuf), 1567 &_nis_state, PASSWD_BYNAME(&_nis_state)); 1568 if (!_nis_state.stayopen) 1569 _nis_end(&_nis_state); 1570 if (rv == NS_SUCCESS && strcmp(name, _nis_passwd.pw_name) == 0) 1571 *retval = &_nis_passwd; 1572 return rv; 1573 } 1574 1575 /*ARGSUSED*/ 1576 static int 1577 _nis_getpwnam_r(void *nsrv, void *nscb, va_list ap) 1578 { 1579 int *retval = va_arg(ap, int *); 1580 const char *name = va_arg(ap, const char *); 1581 struct passwd *pw = va_arg(ap, struct passwd *); 1582 char *buffer = va_arg(ap, char *); 1583 size_t buflen = va_arg(ap, size_t); 1584 struct passwd **result = va_arg(ap, struct passwd **); 1585 1586 struct nis_state state; 1587 int rv; 1588 1589 _DIAGASSERT(retval != NULL); 1590 _DIAGASSERT(pw != NULL); 1591 _DIAGASSERT(buffer != NULL); 1592 _DIAGASSERT(result != NULL); 1593 1594 *result = NULL; 1595 snprintf(buffer, buflen, "%s", name); 1596 memset(&state, 0, sizeof(state)); 1597 rv = _nis_start(&state); 1598 if (rv != NS_SUCCESS) 1599 return rv; 1600 rv = _nis_pwscan(retval, pw, buffer, buflen, 1601 &state, PASSWD_BYNAME(&state)); 1602 _nis_end(&state); 1603 if (rv != NS_SUCCESS) 1604 return rv; 1605 if (strcmp(name, pw->pw_name) == 0) { 1606 *result = pw; 1607 return NS_SUCCESS; 1608 } else 1609 return NS_NOTFOUND; 1610 } 1611 1612 #endif /* YP */ 1613 1614 1615 #ifdef _PASSWD_COMPAT 1616 /* 1617 * compat methods 1618 */ 1619 1620 /* state shared between compat methods */ 1621 1622 struct compat_state { 1623 int stayopen; /* see getpassent(3) */ 1624 DB *db; /* passwd DB */ 1625 int keynum; /* key counter, -1 if no more */ 1626 enum { /* current compat mode */ 1627 COMPAT_NOTOKEN = 0, /* no compat token present */ 1628 COMPAT_NONE, /* parsing normal pwd.db line */ 1629 COMPAT_FULL, /* parsing `+' entries */ 1630 COMPAT_USER, /* parsing `+name' entries */ 1631 COMPAT_NETGROUP /* parsing `+@netgroup' entries */ 1632 } mode; 1633 char *user; /* COMPAT_USER "+name" */ 1634 DB *exclude; /* compat exclude DB */ 1635 struct passwd proto; /* proto passwd entry */ 1636 char protobuf[_GETPW_R_SIZE_MAX]; 1637 /* buffer for proto ptrs */ 1638 int protoflags; /* proto passwd flags */ 1639 }; 1640 1641 static struct compat_state _compat_state; 1642 /* storage for non _r functions */ 1643 static struct passwd _compat_passwd; 1644 static char _compat_passwdbuf[_GETPW_R_SIZE_MAX]; 1645 1646 static int 1647 _compat_start(struct compat_state *state) 1648 { 1649 int rv; 1650 1651 _DIAGASSERT(state != NULL); 1652 1653 state->keynum = 0; 1654 if (state->db == NULL) { /* not open yet */ 1655 DBT key, data; 1656 DBT pkey, pdata; 1657 char bf[MAXLOGNAME]; 1658 1659 rv = _pw_opendb(&state->db); 1660 if (rv != NS_SUCCESS) 1661 return rv; 1662 1663 state->mode = COMPAT_NOTOKEN; 1664 1665 /* 1666 * Determine if the "compat" token is present in pwd.db; 1667 * either "__YP!" or PW_KEYBYNAME+"+". 1668 * Only works if pwd_mkdb installs the token. 1669 */ 1670 key.data = (u_char *)__UNCONST(__yp_token); 1671 key.size = strlen(__yp_token); 1672 1673 bf[0] = _PW_KEYBYNAME; /* Pre-token database support. */ 1674 bf[1] = '+'; 1675 pkey.data = (u_char *)bf; 1676 pkey.size = 2; 1677 1678 if ((state->db->get)(state->db, &key, &data, 0) == 0 1679 || (state->db->get)(state->db, &pkey, &pdata, 0) == 0) 1680 state->mode = COMPAT_NONE; 1681 } 1682 return NS_SUCCESS; 1683 } 1684 1685 static int 1686 _compat_end(struct compat_state *state) 1687 { 1688 1689 _DIAGASSERT(state != NULL); 1690 1691 state->keynum = 0; 1692 if (state->db) { 1693 (void)(state->db->close)(state->db); 1694 state->db = NULL; 1695 } 1696 state->mode = COMPAT_NOTOKEN; 1697 if (state->user) 1698 free(state->user); 1699 state->user = NULL; 1700 if (state->exclude != NULL) 1701 (void)(state->exclude->close)(state->exclude); 1702 state->exclude = NULL; 1703 state->proto.pw_name = NULL; 1704 state->protoflags = 0; 1705 return NS_SUCCESS; 1706 } 1707 1708 /* 1709 * _compat_add_exclude 1710 * add the name to the exclude list in state->exclude. 1711 */ 1712 static int 1713 _compat_add_exclude(struct compat_state *state, const char *name) 1714 { 1715 DBT key, data; 1716 1717 _DIAGASSERT(state != NULL); 1718 _DIAGASSERT(name != NULL); 1719 1720 /* initialize the exclusion table if needed */ 1721 if (state->exclude == NULL) { 1722 state->exclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL); 1723 if (state->exclude == NULL) 1724 return 0; 1725 } 1726 1727 key.size = strlen(name); /* set up the key */ 1728 key.data = (u_char *)__UNCONST(name); 1729 1730 data.data = NULL; /* data is nothing */ 1731 data.size = 0; 1732 1733 /* store it */ 1734 if ((state->exclude->put)(state->exclude, &key, &data, 0) == -1) 1735 return 0; 1736 1737 return 1; 1738 } 1739 1740 /* 1741 * _compat_is_excluded 1742 * test if a name is on the compat mode exclude list 1743 */ 1744 static int 1745 _compat_is_excluded(struct compat_state *state, const char *name) 1746 { 1747 DBT key, data; 1748 1749 _DIAGASSERT(state != NULL); 1750 _DIAGASSERT(name != NULL); 1751 1752 if (state->exclude == NULL) 1753 return 0; /* nothing excluded */ 1754 1755 key.size = strlen(name); /* set up the key */ 1756 key.data = (u_char *)__UNCONST(name); 1757 1758 if ((state->exclude->get)(state->exclude, &key, &data, 0) == 0) 1759 return 1; /* is excluded */ 1760 1761 return 0; 1762 } 1763 1764 1765 /* 1766 * _passwdcompat_bad 1767 * log an error if "files" or "compat" is specified in 1768 * passwd_compat database 1769 */ 1770 /*ARGSUSED*/ 1771 static int 1772 _passwdcompat_bad(void *nsrv, void *nscb, va_list ap) 1773 { 1774 static int warned; 1775 1776 _DIAGASSERT(nsrv != NULL); 1777 _DIAGASSERT(nscb != NULL); 1778 1779 if (!warned) { 1780 syslog(LOG_ERR, 1781 "nsswitch.conf passwd_compat database can't use '%s'", 1782 (char *)nscb); 1783 } 1784 warned = 1; 1785 return NS_UNAVAIL; 1786 } 1787 1788 /* 1789 * _passwdcompat_setpassent 1790 * Call setpassent for all passwd_compat sources. 1791 */ 1792 static int 1793 _passwdcompat_setpassent(int stayopen) 1794 { 1795 static const ns_dtab dtab[] = { 1796 NS_FILES_CB(_passwdcompat_bad, "files") 1797 NS_DNS_CB(_dns_setpassent, NULL) 1798 NS_NIS_CB(_nis_setpassent, NULL) 1799 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1800 NS_NULL_CB 1801 }; 1802 1803 int rv, result; 1804 1805 rv = nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpassent", 1806 __nsdefaultnis_forceall, &result, stayopen); 1807 return rv; 1808 } 1809 1810 /* 1811 * _passwdcompat_endpwent 1812 * Call endpwent for all passwd_compat sources. 1813 */ 1814 static int 1815 _passwdcompat_endpwent(void) 1816 { 1817 static const ns_dtab dtab[] = { 1818 NS_FILES_CB(_passwdcompat_bad, "files") 1819 NS_DNS_CB(_dns_endpwent, NULL) 1820 NS_NIS_CB(_nis_endpwent, NULL) 1821 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1822 NS_NULL_CB 1823 }; 1824 1825 return nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent", 1826 __nsdefaultnis_forceall); 1827 } 1828 1829 /* 1830 * _passwdcompat_pwscan 1831 * When a name lookup in compat mode is required (e.g., `+name', or a 1832 * name in `+@netgroup'), look it up in the 'passwd_compat' nsswitch 1833 * database. 1834 * Fail if passwd_compat contains files or compat. 1835 */ 1836 static int 1837 _passwdcompat_pwscan(struct passwd *pw, char *buffer, size_t buflen, 1838 int search, const char *name, uid_t uid) 1839 { 1840 static const ns_dtab compatentdtab[] = { 1841 NS_FILES_CB(_passwdcompat_bad, "files") 1842 NS_DNS_CB(_dns_getpwent_r, NULL) 1843 NS_NIS_CB(_nis_getpwent_r, NULL) 1844 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1845 NS_NULL_CB 1846 }; 1847 static const ns_dtab compatuiddtab[] = { 1848 NS_FILES_CB(_passwdcompat_bad, "files") 1849 NS_DNS_CB(_dns_getpwuid_r, NULL) 1850 NS_NIS_CB(_nis_getpwuid_r, NULL) 1851 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1852 NS_NULL_CB 1853 }; 1854 static const ns_dtab compatnamdtab[] = { 1855 NS_FILES_CB(_passwdcompat_bad, "files") 1856 NS_DNS_CB(_dns_getpwnam_r, NULL) 1857 NS_NIS_CB(_nis_getpwnam_r, NULL) 1858 NS_COMPAT_CB(_passwdcompat_bad, "compat") 1859 NS_NULL_CB 1860 }; 1861 1862 int rv, crv; 1863 struct passwd *cpw; 1864 1865 switch (search) { 1866 case _PW_KEYBYNUM: 1867 rv = nsdispatch(NULL, compatentdtab, 1868 NSDB_PASSWD_COMPAT, "getpwent_r", __nsdefaultnis, 1869 &crv, pw, buffer, buflen, &cpw); 1870 break; 1871 case _PW_KEYBYNAME: 1872 _DIAGASSERT(name != NULL); 1873 rv = nsdispatch(NULL, compatnamdtab, 1874 NSDB_PASSWD_COMPAT, "getpwnam_r", __nsdefaultnis, 1875 &crv, name, pw, buffer, buflen, &cpw); 1876 break; 1877 case _PW_KEYBYUID: 1878 rv = nsdispatch(NULL, compatuiddtab, 1879 NSDB_PASSWD_COMPAT, "getpwuid_r", __nsdefaultnis, 1880 &crv, uid, pw, buffer, buflen, &cpw); 1881 break; 1882 default: 1883 abort(); 1884 /*NOTREACHED*/ 1885 } 1886 return rv; 1887 } 1888 1889 /* 1890 * _compat_pwscan 1891 * Search state->db for the next desired entry. 1892 * If search is _PW_KEYBYNUM, look for state->keynum. 1893 * If search is _PW_KEYBYNAME, look for name. 1894 * If search is _PW_KEYBYUID, look for uid. 1895 * Sets *retval to the errno if the result is not NS_SUCCESS 1896 * or NS_NOTFOUND. 1897 */ 1898 static int 1899 _compat_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 1900 struct compat_state *state, int search, const char *name, uid_t uid) 1901 { 1902 DBT key; 1903 int rv, r, pwflags; 1904 const char *user, *host, *dom; 1905 const void *from; 1906 size_t fromlen; 1907 1908 _DIAGASSERT(retval != NULL); 1909 _DIAGASSERT(pw != NULL); 1910 _DIAGASSERT(buffer != NULL); 1911 _DIAGASSERT(state != NULL); 1912 /* name may be NULL */ 1913 1914 *retval = 0; 1915 1916 if (state->db == NULL) { 1917 rv = _compat_start(state); 1918 if (rv != NS_SUCCESS) 1919 return rv; 1920 } 1921 if (buflen <= 1) { /* buffer too small */ 1922 *retval = ERANGE; 1923 return NS_UNAVAIL; 1924 } 1925 1926 for (;;) { /* loop over pwd.db */ 1927 rv = NS_NOTFOUND; 1928 if (state->mode != COMPAT_NOTOKEN && 1929 state->mode != COMPAT_NONE) { 1930 /* doing a compat lookup */ 1931 struct passwd cpw; 1932 char cbuf[_GETPW_R_SIZE_MAX]; 1933 1934 switch (state->mode) { 1935 1936 case COMPAT_FULL: 1937 /* get next user or lookup by key */ 1938 rv = _passwdcompat_pwscan(&cpw, 1939 cbuf, sizeof(cbuf), search, name, uid); 1940 if (rv != NS_SUCCESS) 1941 state->mode = COMPAT_NONE; 1942 break; 1943 1944 case COMPAT_NETGROUP: 1945 /* XXXREENTRANT: getnetgrent is not thread safe */ 1946 /* get next user from netgroup */ 1947 r = getnetgrent(&host, &user, &dom); 1948 if (r == 0) { /* end of group */ 1949 endnetgrent(); 1950 state->mode = COMPAT_NONE; 1951 break; 1952 } 1953 if (!user || !*user) 1954 break; 1955 rv = _passwdcompat_pwscan(&cpw, 1956 cbuf, sizeof(cbuf), 1957 _PW_KEYBYNAME, user, 0); 1958 break; 1959 1960 case COMPAT_USER: 1961 /* get specific user */ 1962 if (state->user == NULL) { 1963 state->mode = COMPAT_NONE; 1964 break; 1965 } 1966 rv = _passwdcompat_pwscan(&cpw, 1967 cbuf, sizeof(cbuf), 1968 _PW_KEYBYNAME, state->user, 0); 1969 free(state->user); 1970 state->user = NULL; 1971 state->mode = COMPAT_NONE; 1972 break; 1973 1974 case COMPAT_NOTOKEN: 1975 case COMPAT_NONE: 1976 abort(); 1977 1978 } 1979 if (rv != NS_SUCCESS) /* if not matched, next loop */ 1980 continue; 1981 1982 /* copy cpw to pw, applying prototype */ 1983 if (! _pw_copy(&cpw, pw, buffer, buflen, 1984 &state->proto, state->protoflags)) { 1985 rv = NS_UNAVAIL; 1986 break; 1987 } 1988 1989 if (_compat_is_excluded(state, pw->pw_name)) 1990 continue; /* excluded; next loop */ 1991 1992 if ((search == _PW_KEYBYNAME 1993 && strcmp(pw->pw_name, name) != 0) 1994 || (search == _PW_KEYBYUID && pw->pw_uid != uid)) { 1995 continue; /* not specific; next loop */ 1996 } 1997 1998 break; /* exit loop if found */ 1999 } else { /* not a compat line */ 2000 state->proto.pw_name = NULL; 2001 /* clear prototype */ 2002 } 2003 2004 if (state->mode == COMPAT_NOTOKEN) { 2005 /* no compat token; do direct lookup */ 2006 switch (search) { 2007 case _PW_KEYBYNUM: 2008 if (state->keynum == -1) /* no more records */ 2009 return NS_NOTFOUND; 2010 state->keynum++; 2011 from = &state->keynum; 2012 fromlen = sizeof(state->keynum); 2013 break; 2014 case _PW_KEYBYNAME: 2015 from = name; 2016 fromlen = strlen(name); 2017 break; 2018 case _PW_KEYBYUID: 2019 from = &uid; 2020 fromlen = sizeof(uid); 2021 break; 2022 default: 2023 abort(); 2024 } 2025 buffer[0] = search; 2026 } else { 2027 /* compat token; do line by line */ 2028 if (state->keynum == -1) /* no more records */ 2029 return NS_NOTFOUND; 2030 state->keynum++; 2031 from = &state->keynum; 2032 fromlen = sizeof(state->keynum); 2033 buffer[0] = _PW_KEYBYNUM; 2034 } 2035 2036 if (buflen <= fromlen) { /* buffer too small */ 2037 *retval = ERANGE; 2038 return NS_UNAVAIL; 2039 } 2040 memmove(buffer + 1, from, fromlen); /* setup key */ 2041 key.size = fromlen + 1; 2042 key.data = (u_char *)buffer; 2043 2044 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, &pwflags); 2045 if (rv != NS_SUCCESS) /* stop on error */ 2046 break; 2047 2048 if (state->mode == COMPAT_NOTOKEN) 2049 break; /* stop if no compat token */ 2050 2051 if (pw->pw_name[0] == '+') { 2052 /* compat inclusion */ 2053 switch(pw->pw_name[1]) { 2054 case '\0': /* `+' */ 2055 state->mode = COMPAT_FULL; 2056 /* reset passwd_compat search */ 2057 /* XXXREENTRANT: setpassent is not thread safe ? */ 2058 (void) _passwdcompat_setpassent(0); 2059 break; 2060 case '@': /* `+@netgroup' */ 2061 state->mode = COMPAT_NETGROUP; 2062 /* reset netgroup search */ 2063 /* XXXREENTRANT: setnetgrent is not thread safe */ 2064 setnetgrent(pw->pw_name + 2); 2065 break; 2066 default: /* `+name' */ 2067 state->mode = COMPAT_USER; 2068 if (state->user) 2069 free(state->user); 2070 state->user = strdup(pw->pw_name + 1); 2071 break; 2072 } 2073 /* save the prototype */ 2074 state->protoflags = pwflags; 2075 if (! _pw_copy(pw, &state->proto, state->protobuf, 2076 sizeof(state->protobuf), NULL, 0)) { 2077 rv = NS_UNAVAIL; 2078 break; 2079 } 2080 continue; /* loop again after inclusion */ 2081 } else if (pw->pw_name[0] == '-') { 2082 /* compat exclusion */ 2083 rv = NS_SUCCESS; 2084 switch(pw->pw_name[1]) { 2085 case '\0': /* `-' */ 2086 break; 2087 case '@': /* `-@netgroup' */ 2088 /* XXXREENTRANT: {set,get,end}netgrent is not thread safe */ 2089 setnetgrent(pw->pw_name + 2); 2090 while (getnetgrent(&host, &user, &dom)) { 2091 if (!user || !*user) 2092 continue; 2093 if (! _compat_add_exclude(state,user)) { 2094 rv = NS_UNAVAIL; 2095 break; 2096 } 2097 } 2098 endnetgrent(); 2099 break; 2100 default: /* `-name' */ 2101 if (! _compat_add_exclude(state, 2102 pw->pw_name + 1)) { 2103 rv = NS_UNAVAIL; 2104 } 2105 break; 2106 } 2107 if (rv != NS_SUCCESS) /* exclusion failure */ 2108 break; 2109 continue; /* loop again after exclusion */ 2110 } 2111 if (search == _PW_KEYBYNUM || 2112 (search == _PW_KEYBYUID && pw->pw_uid == uid) || 2113 (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) == 0)) 2114 break; /* token mode match found */ 2115 } 2116 2117 if (rv == NS_NOTFOUND && 2118 (search == _PW_KEYBYNUM || state->mode != COMPAT_NOTOKEN)) 2119 state->keynum = -1; /* flag `no more records' */ 2120 2121 if (rv == NS_SUCCESS) { 2122 if ((search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0) 2123 || (search == _PW_KEYBYUID && pw->pw_uid != uid)) 2124 rv = NS_NOTFOUND; 2125 } 2126 2127 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 2128 *retval = errno; 2129 return rv; 2130 } 2131 2132 /*ARGSUSED*/ 2133 static int 2134 _compat_setpwent(void *nsrv, void *nscb, va_list ap) 2135 { 2136 2137 /* force passwd_compat setpwent() */ 2138 (void) _passwdcompat_setpassent(0); 2139 2140 /* reset state, keep db open */ 2141 _compat_state.stayopen = 0; 2142 return _compat_start(&_compat_state); 2143 } 2144 2145 /*ARGSUSED*/ 2146 static int 2147 _compat_setpassent(void *nsrv, void *nscb, va_list ap) 2148 { 2149 int *retval = va_arg(ap, int *); 2150 int stayopen = va_arg(ap, int); 2151 2152 int rv; 2153 2154 /* force passwd_compat setpassent() */ 2155 (void) _passwdcompat_setpassent(stayopen); 2156 2157 _compat_state.stayopen = stayopen; 2158 rv = _compat_start(&_compat_state); 2159 *retval = (rv == NS_SUCCESS); 2160 return rv; 2161 } 2162 2163 /*ARGSUSED*/ 2164 static int 2165 _compat_endpwent(void *nsrv, void *nscb, va_list ap) 2166 { 2167 2168 /* force passwd_compat endpwent() */ 2169 (void) _passwdcompat_endpwent(); 2170 2171 /* reset state, close db */ 2172 _compat_state.stayopen = 0; 2173 return _compat_end(&_compat_state); 2174 } 2175 2176 2177 /*ARGSUSED*/ 2178 static int 2179 _compat_getpwent(void *nsrv, void *nscb, va_list ap) 2180 { 2181 struct passwd **retval = va_arg(ap, struct passwd **); 2182 2183 int rv, rerror; 2184 2185 _DIAGASSERT(retval != NULL); 2186 2187 *retval = NULL; 2188 rv = _compat_pwscan(&rerror, &_compat_passwd, 2189 _compat_passwdbuf, sizeof(_compat_passwdbuf), 2190 &_compat_state, _PW_KEYBYNUM, NULL, 0); 2191 if (rv == NS_SUCCESS) 2192 *retval = &_compat_passwd; 2193 return rv; 2194 } 2195 2196 /*ARGSUSED*/ 2197 static int 2198 _compat_getpwent_r(void *nsrv, void *nscb, va_list ap) 2199 { 2200 int *retval = va_arg(ap, int *); 2201 struct passwd *pw = va_arg(ap, struct passwd *); 2202 char *buffer = va_arg(ap, char *); 2203 size_t buflen = va_arg(ap, size_t); 2204 struct passwd **result = va_arg(ap, struct passwd **); 2205 2206 int rv; 2207 2208 _DIAGASSERT(retval != NULL); 2209 _DIAGASSERT(pw != NULL); 2210 _DIAGASSERT(buffer != NULL); 2211 _DIAGASSERT(result != NULL); 2212 2213 rv = _compat_pwscan(retval, pw, buffer, buflen, &_compat_state, 2214 _PW_KEYBYNUM, NULL, 0); 2215 if (rv == NS_SUCCESS) 2216 *result = pw; 2217 else 2218 *result = NULL; 2219 return rv; 2220 } 2221 2222 2223 /*ARGSUSED*/ 2224 static int 2225 _compat_getpwnam(void *nsrv, void *nscb, va_list ap) 2226 { 2227 struct passwd **retval = va_arg(ap, struct passwd **); 2228 const char *name = va_arg(ap, const char *); 2229 2230 int rv, rerror; 2231 2232 _DIAGASSERT(retval != NULL); 2233 2234 *retval = NULL; 2235 rv = _compat_start(&_compat_state); 2236 if (rv != NS_SUCCESS) 2237 return rv; 2238 rv = _compat_pwscan(&rerror, &_compat_passwd, 2239 _compat_passwdbuf, sizeof(_compat_passwdbuf), 2240 &_compat_state, _PW_KEYBYNAME, name, 0); 2241 if (!_compat_state.stayopen) 2242 _compat_end(&_compat_state); 2243 if (rv == NS_SUCCESS) 2244 *retval = &_compat_passwd; 2245 return rv; 2246 } 2247 2248 /*ARGSUSED*/ 2249 static int 2250 _compat_getpwnam_r(void *nsrv, void *nscb, va_list ap) 2251 { 2252 int *retval = va_arg(ap, int *); 2253 const char *name = va_arg(ap, const char *); 2254 struct passwd *pw = va_arg(ap, struct passwd *); 2255 char *buffer = va_arg(ap, char *); 2256 size_t buflen = va_arg(ap, size_t); 2257 struct passwd **result = va_arg(ap, struct passwd **); 2258 2259 struct compat_state state; 2260 int rv; 2261 2262 _DIAGASSERT(retval != NULL); 2263 _DIAGASSERT(pw != NULL); 2264 _DIAGASSERT(buffer != NULL); 2265 _DIAGASSERT(result != NULL); 2266 2267 *result = NULL; 2268 memset(&state, 0, sizeof(state)); 2269 rv = _compat_pwscan(retval, pw, buffer, buflen, &state, 2270 _PW_KEYBYNAME, name, 0); 2271 _compat_end(&state); 2272 if (rv == NS_SUCCESS) 2273 *result = pw; 2274 return rv; 2275 } 2276 2277 /*ARGSUSED*/ 2278 static int 2279 _compat_getpwuid(void *nsrv, void *nscb, va_list ap) 2280 { 2281 struct passwd **retval = va_arg(ap, struct passwd **); 2282 uid_t uid = va_arg(ap, uid_t); 2283 2284 int rv, rerror; 2285 2286 _DIAGASSERT(retval != NULL); 2287 2288 *retval = NULL; 2289 rv = _compat_start(&_compat_state); 2290 if (rv != NS_SUCCESS) 2291 return rv; 2292 rv = _compat_pwscan(&rerror, &_compat_passwd, 2293 _compat_passwdbuf, sizeof(_compat_passwdbuf), 2294 &_compat_state, _PW_KEYBYUID, NULL, uid); 2295 if (!_compat_state.stayopen) 2296 _compat_end(&_compat_state); 2297 if (rv == NS_SUCCESS) 2298 *retval = &_compat_passwd; 2299 return rv; 2300 } 2301 2302 /*ARGSUSED*/ 2303 static int 2304 _compat_getpwuid_r(void *nsrv, void *nscb, va_list ap) 2305 { 2306 int *retval = va_arg(ap, int *); 2307 uid_t uid = va_arg(ap, uid_t); 2308 struct passwd *pw = va_arg(ap, struct passwd *); 2309 char *buffer = va_arg(ap, char *); 2310 size_t buflen = va_arg(ap, size_t); 2311 struct passwd **result = va_arg(ap, struct passwd **); 2312 2313 struct compat_state state; 2314 int rv; 2315 2316 _DIAGASSERT(retval != NULL); 2317 _DIAGASSERT(pw != NULL); 2318 _DIAGASSERT(buffer != NULL); 2319 _DIAGASSERT(result != NULL); 2320 2321 *result = NULL; 2322 memset(&state, 0, sizeof(state)); 2323 rv = _compat_pwscan(retval, pw, buffer, buflen, &state, 2324 _PW_KEYBYUID, NULL, uid); 2325 _compat_end(&state); 2326 if (rv == NS_SUCCESS) 2327 *result = pw; 2328 return rv; 2329 } 2330 2331 #endif /* _PASSWD_COMPAT */ 2332 2333 2334 /* 2335 * public functions 2336 */ 2337 2338 struct passwd * 2339 getpwent(void) 2340 { 2341 int r; 2342 struct passwd *retval; 2343 2344 static const ns_dtab dtab[] = { 2345 NS_FILES_CB(_files_getpwent, NULL) 2346 NS_DNS_CB(_dns_getpwent, NULL) 2347 NS_NIS_CB(_nis_getpwent, NULL) 2348 NS_COMPAT_CB(_compat_getpwent, NULL) 2349 NS_NULL_CB 2350 }; 2351 2352 mutex_lock(&_pwmutex); 2353 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent", __nsdefaultcompat, 2354 &retval); 2355 mutex_unlock(&_pwmutex); 2356 return (r == NS_SUCCESS) ? retval : NULL; 2357 } 2358 2359 int 2360 getpwent_r(struct passwd *pwd, char *buffer, size_t buflen, 2361 struct passwd **result) 2362 { 2363 int r, retval; 2364 2365 static const ns_dtab dtab[] = { 2366 NS_FILES_CB(_files_getpwent_r, NULL) 2367 NS_DNS_CB(_dns_getpwent_r, NULL) 2368 NS_NIS_CB(_nis_getpwent_r, NULL) 2369 NS_COMPAT_CB(_compat_getpwent_r, NULL) 2370 NS_NULL_CB 2371 }; 2372 2373 _DIAGASSERT(pwd != NULL); 2374 _DIAGASSERT(buffer != NULL); 2375 _DIAGASSERT(result != NULL); 2376 2377 *result = NULL; 2378 retval = 0; 2379 mutex_lock(&_pwmutex); 2380 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwent_r", __nsdefaultcompat, 2381 &retval, pwd, buffer, buflen, result); 2382 mutex_unlock(&_pwmutex); 2383 switch (r) { 2384 case NS_SUCCESS: 2385 case NS_NOTFOUND: 2386 return 0; 2387 default: 2388 return retval; 2389 } 2390 } 2391 2392 2393 struct passwd * 2394 getpwnam(const char *name) 2395 { 2396 int rv; 2397 struct passwd *retval; 2398 2399 static const ns_dtab dtab[] = { 2400 NS_FILES_CB(_files_getpwnam, NULL) 2401 NS_DNS_CB(_dns_getpwnam, NULL) 2402 NS_NIS_CB(_nis_getpwnam, NULL) 2403 NS_COMPAT_CB(_compat_getpwnam, NULL) 2404 NS_NULL_CB 2405 }; 2406 2407 mutex_lock(&_pwmutex); 2408 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", __nsdefaultcompat, 2409 &retval, name); 2410 mutex_unlock(&_pwmutex); 2411 return (rv == NS_SUCCESS) ? retval : NULL; 2412 } 2413 2414 int 2415 getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t buflen, 2416 struct passwd **result) 2417 { 2418 int r, retval; 2419 2420 static const ns_dtab dtab[] = { 2421 NS_FILES_CB(_files_getpwnam_r, NULL) 2422 NS_DNS_CB(_dns_getpwnam_r, NULL) 2423 NS_NIS_CB(_nis_getpwnam_r, NULL) 2424 NS_COMPAT_CB(_compat_getpwnam_r, NULL) 2425 NS_NULL_CB 2426 }; 2427 2428 _DIAGASSERT(name != NULL); 2429 _DIAGASSERT(pwd != NULL); 2430 _DIAGASSERT(buffer != NULL); 2431 _DIAGASSERT(result != NULL); 2432 2433 *result = NULL; 2434 retval = 0; 2435 mutex_lock(&_pwmutex); 2436 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam_r", __nsdefaultcompat, 2437 &retval, name, pwd, buffer, buflen, result); 2438 mutex_unlock(&_pwmutex); 2439 switch (r) { 2440 case NS_SUCCESS: 2441 case NS_NOTFOUND: 2442 return 0; 2443 default: 2444 return retval; 2445 } 2446 } 2447 2448 struct passwd * 2449 getpwuid(uid_t uid) 2450 { 2451 int rv; 2452 struct passwd *retval; 2453 2454 static const ns_dtab dtab[] = { 2455 NS_FILES_CB(_files_getpwuid, NULL) 2456 NS_DNS_CB(_dns_getpwuid, NULL) 2457 NS_NIS_CB(_nis_getpwuid, NULL) 2458 NS_COMPAT_CB(_compat_getpwuid, NULL) 2459 NS_NULL_CB 2460 }; 2461 2462 mutex_lock(&_pwmutex); 2463 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", __nsdefaultcompat, 2464 &retval, uid); 2465 mutex_unlock(&_pwmutex); 2466 return (rv == NS_SUCCESS) ? retval : NULL; 2467 } 2468 2469 int 2470 getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen, 2471 struct passwd **result) 2472 { 2473 int r, retval; 2474 2475 static const ns_dtab dtab[] = { 2476 NS_FILES_CB(_files_getpwuid_r, NULL) 2477 NS_DNS_CB(_dns_getpwuid_r, NULL) 2478 NS_NIS_CB(_nis_getpwuid_r, NULL) 2479 NS_COMPAT_CB(_compat_getpwuid_r, NULL) 2480 NS_NULL_CB 2481 }; 2482 2483 _DIAGASSERT(pwd != NULL); 2484 _DIAGASSERT(buffer != NULL); 2485 _DIAGASSERT(result != NULL); 2486 2487 *result = NULL; 2488 retval = 0; 2489 mutex_lock(&_pwmutex); 2490 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid_r", __nsdefaultcompat, 2491 &retval, uid, pwd, buffer, buflen, result); 2492 mutex_unlock(&_pwmutex); 2493 switch (r) { 2494 case NS_SUCCESS: 2495 case NS_NOTFOUND: 2496 return 0; 2497 default: 2498 return retval; 2499 } 2500 } 2501 2502 void 2503 endpwent(void) 2504 { 2505 static const ns_dtab dtab[] = { 2506 NS_FILES_CB(_files_endpwent, NULL) 2507 NS_DNS_CB(_dns_endpwent, NULL) 2508 NS_NIS_CB(_nis_endpwent, NULL) 2509 NS_COMPAT_CB(_compat_endpwent, NULL) 2510 NS_NULL_CB 2511 }; 2512 2513 mutex_lock(&_pwmutex); 2514 /* force all endpwent() methods */ 2515 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", 2516 __nsdefaultcompat_forceall); 2517 mutex_unlock(&_pwmutex); 2518 } 2519 2520 /*ARGSUSED*/ 2521 int 2522 setpassent(int stayopen) 2523 { 2524 static const ns_dtab dtab[] = { 2525 NS_FILES_CB(_files_setpassent, NULL) 2526 NS_DNS_CB(_dns_setpassent, NULL) 2527 NS_NIS_CB(_nis_setpassent, NULL) 2528 NS_COMPAT_CB(_compat_setpassent, NULL) 2529 NS_NULL_CB 2530 }; 2531 int rv, retval; 2532 2533 mutex_lock(&_pwmutex); 2534 /* force all setpassent() methods */ 2535 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "setpassent", 2536 __nsdefaultcompat_forceall, &retval, stayopen); 2537 mutex_unlock(&_pwmutex); 2538 return (rv == NS_SUCCESS) ? retval : 0; 2539 } 2540 2541 void 2542 setpwent(void) 2543 { 2544 static const ns_dtab dtab[] = { 2545 NS_FILES_CB(_files_setpwent, NULL) 2546 NS_DNS_CB(_dns_setpwent, NULL) 2547 NS_NIS_CB(_nis_setpwent, NULL) 2548 NS_COMPAT_CB(_compat_setpwent, NULL) 2549 NS_NULL_CB 2550 }; 2551 2552 mutex_lock(&_pwmutex); 2553 /* force all setpwent() methods */ 2554 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", 2555 __nsdefaultcompat_forceall); 2556 mutex_unlock(&_pwmutex); 2557 } 2558