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