1 /* $NetBSD: getpwent.c,v 1.67 2005/04/02 04:53:53 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.67 2005/04/02 04:53:53 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; 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; 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 */ 434 static int 435 _files_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 436 struct files_state *state, int search, const char *name, uid_t uid) 437 { 438 const void *from; 439 size_t fromlen; 440 DBT key; 441 int rv; 442 443 _DIAGASSERT(retval != NULL); 444 _DIAGASSERT(pw != NULL); 445 _DIAGASSERT(buffer != NULL); 446 _DIAGASSERT(state != NULL); 447 /* name is NULL to indicate searching for uid */ 448 449 *retval = 0; 450 451 if (state->db == NULL) { /* only start if file not open yet */ 452 rv = _files_start(state); 453 if (rv != NS_SUCCESS) 454 goto filespwscan_out; 455 } 456 457 for (;;) { /* search for a match */ 458 switch (search) { 459 case _PW_KEYBYNUM: 460 if (state->keynum == -1) 461 return NS_NOTFOUND; /* no more records */ 462 state->keynum++; 463 from = &state->keynum; 464 fromlen = sizeof(state->keynum); 465 break; 466 case _PW_KEYBYNAME: 467 from = name; 468 fromlen = strlen(name); 469 break; 470 case _PW_KEYBYUID: 471 from = &uid; 472 fromlen = sizeof(uid); 473 break; 474 default: 475 abort(); 476 } 477 478 if (buflen <= fromlen) { /* buffer too small */ 479 *retval = ERANGE; 480 return NS_UNAVAIL; 481 } 482 buffer[0] = search; /* setup key */ 483 memmove(buffer + 1, from, fromlen); 484 key.size = fromlen + 1; 485 key.data = (u_char *)buffer; 486 487 /* search for key */ 488 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, NULL); 489 if (rv != NS_SUCCESS) /* no match */ 490 break; 491 if (pw->pw_name[0] == '+' || pw->pw_name[0] == '-') { 492 /* if a compat line */ 493 if (search == _PW_KEYBYNUM) 494 continue; /* read next if pwent */ 495 rv = NS_NOTFOUND; /* don't match if pw{nam,uid} */ 496 break; 497 } 498 break; 499 } 500 501 if (rv == NS_NOTFOUND && search == _PW_KEYBYNUM) 502 state->keynum = -1; /* flag `no more records' */ 503 504 if (rv == NS_SUCCESS) { 505 if ((search == _PW_KEYBYUID && pw->pw_uid != uid) || 506 (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0)) 507 rv = NS_NOTFOUND; 508 } 509 510 filespwscan_out: 511 if (rv != NS_SUCCESS) 512 *retval = errno; 513 return rv; 514 } 515 516 /*ARGSUSED*/ 517 static int 518 _files_setpwent(void *nsrv, void *nscb, va_list ap) 519 { 520 521 _files_state.stayopen = 0; 522 return _files_start(&_files_state); 523 } 524 525 /*ARGSUSED*/ 526 static int 527 _files_setpassent(void *nsrv, void *nscb, va_list ap) 528 { 529 int *retval = va_arg(ap, int *); 530 int stayopen = va_arg(ap, int); 531 532 int rv; 533 534 _files_state.stayopen = stayopen; 535 rv = _files_start(&_files_state); 536 *retval = (rv == NS_SUCCESS); 537 return rv; 538 } 539 540 /*ARGSUSED*/ 541 static int 542 _files_endpwent(void *nsrv, void *nscb, va_list ap) 543 { 544 545 _files_state.stayopen = 0; 546 return _files_end(&_files_state); 547 } 548 549 /*ARGSUSED*/ 550 static int 551 _files_getpwent(void *nsrv, void *nscb, va_list ap) 552 { 553 struct passwd **retval = va_arg(ap, struct passwd **); 554 555 int rv, rerror; 556 557 _DIAGASSERT(retval != NULL); 558 559 *retval = NULL; 560 rv = _files_pwscan(&rerror, &_files_passwd, 561 _files_passwdbuf, sizeof(_files_passwdbuf), 562 &_files_state, _PW_KEYBYNUM, NULL, 0); 563 if (rv == NS_SUCCESS) 564 *retval = &_files_passwd; 565 return rv; 566 } 567 568 /*ARGSUSED*/ 569 static int 570 _files_getpwent_r(void *nsrv, void *nscb, va_list ap) 571 { 572 int *retval = va_arg(ap, int *); 573 struct passwd *pw = va_arg(ap, struct passwd *); 574 char *buffer = va_arg(ap, char *); 575 size_t buflen = va_arg(ap, size_t); 576 struct passwd **result = va_arg(ap, struct passwd **); 577 578 int rv; 579 580 _DIAGASSERT(retval != NULL); 581 _DIAGASSERT(pw != NULL); 582 _DIAGASSERT(buffer != NULL); 583 _DIAGASSERT(result != NULL); 584 585 rv = _files_pwscan(retval, pw, buffer, buflen, &_files_state, 586 _PW_KEYBYNUM, NULL, 0); 587 if (rv == NS_SUCCESS) 588 *result = pw; 589 else 590 *result = NULL; 591 return rv; 592 } 593 594 /*ARGSUSED*/ 595 static int 596 _files_getpwnam(void *nsrv, void *nscb, va_list ap) 597 { 598 struct passwd **retval = va_arg(ap, struct passwd **); 599 const char *name = va_arg(ap, const char *); 600 601 int rv, rerror; 602 603 _DIAGASSERT(retval != NULL); 604 605 *retval = NULL; 606 rv = _files_start(&_files_state); 607 if (rv != NS_SUCCESS) 608 return rv; 609 rv = _files_pwscan(&rerror, &_files_passwd, 610 _files_passwdbuf, sizeof(_files_passwdbuf), 611 &_files_state, _PW_KEYBYNAME, name, 0); 612 if (!_files_state.stayopen) 613 _files_end(&_files_state); 614 if (rv == NS_SUCCESS) 615 *retval = &_files_passwd; 616 return rv; 617 } 618 619 /*ARGSUSED*/ 620 static int 621 _files_getpwnam_r(void *nsrv, void *nscb, va_list ap) 622 { 623 int *retval = va_arg(ap, int *); 624 const char *name = va_arg(ap, const char *); 625 struct passwd *pw = va_arg(ap, struct passwd *); 626 char *buffer = va_arg(ap, char *); 627 size_t buflen = va_arg(ap, size_t); 628 struct passwd **result = va_arg(ap, struct passwd **); 629 630 struct files_state state; 631 int rv; 632 633 _DIAGASSERT(retval != NULL); 634 _DIAGASSERT(pw != NULL); 635 _DIAGASSERT(buffer != NULL); 636 _DIAGASSERT(result != NULL); 637 638 *result = NULL; 639 memset(&state, 0, sizeof(state)); 640 rv = _files_pwscan(retval, pw, buffer, buflen, &state, 641 _PW_KEYBYNAME, name, 0); 642 _files_end(&state); 643 if (rv == NS_SUCCESS) 644 *result = pw; 645 return rv; 646 } 647 648 /*ARGSUSED*/ 649 static int 650 _files_getpwuid(void *nsrv, void *nscb, va_list ap) 651 { 652 struct passwd **retval = va_arg(ap, struct passwd **); 653 uid_t uid = va_arg(ap, uid_t); 654 655 int rv, rerror; 656 657 _DIAGASSERT(retval != NULL); 658 659 *retval = NULL; 660 rv = _files_start(&_files_state); 661 if (rv != NS_SUCCESS) 662 return rv; 663 rv = _files_pwscan(&rerror, &_files_passwd, 664 _files_passwdbuf, sizeof(_files_passwdbuf), 665 &_files_state, _PW_KEYBYUID, NULL, uid); 666 if (!_files_state.stayopen) 667 _files_end(&_files_state); 668 if (rv == NS_SUCCESS) 669 *retval = &_files_passwd; 670 return rv; 671 } 672 673 /*ARGSUSED*/ 674 static int 675 _files_getpwuid_r(void *nsrv, void *nscb, va_list ap) 676 { 677 int *retval = va_arg(ap, int *); 678 uid_t uid = va_arg(ap, uid_t); 679 struct passwd *pw = va_arg(ap, struct passwd *); 680 char *buffer = va_arg(ap, char *); 681 size_t buflen = va_arg(ap, size_t); 682 struct passwd **result = va_arg(ap, struct passwd **); 683 684 struct files_state state; 685 int rv; 686 687 _DIAGASSERT(retval != NULL); 688 _DIAGASSERT(pw != NULL); 689 _DIAGASSERT(buffer != NULL); 690 _DIAGASSERT(result != NULL); 691 692 *result = NULL; 693 memset(&state, 0, sizeof(state)); 694 rv = _files_pwscan(retval, pw, buffer, buflen, &state, 695 _PW_KEYBYUID, NULL, uid); 696 _files_end(&state); 697 if (rv == NS_SUCCESS) 698 *result = pw; 699 return rv; 700 } 701 702 703 #ifdef HESIOD 704 /* 705 * dns methods 706 */ 707 708 /* state shared between dns methods */ 709 struct dns_state { 710 int stayopen; /* see getpassent(3) */ 711 void *context; /* Hesiod context */ 712 int num; /* passwd index, -1 if no more */ 713 }; 714 715 static struct dns_state _dns_state; 716 /* storage for non _r functions */ 717 static struct passwd _dns_passwd; 718 static char _dns_passwdbuf[_GETPW_R_SIZE_MAX]; 719 720 static int 721 _dns_start(struct dns_state *state) 722 { 723 724 _DIAGASSERT(state != NULL); 725 726 state->num = 0; 727 if (state->context == NULL) { /* setup Hesiod */ 728 if (hesiod_init(&state->context) == -1) 729 return NS_UNAVAIL; 730 } 731 732 return NS_SUCCESS; 733 } 734 735 static int 736 _dns_end(struct dns_state *state) 737 { 738 739 _DIAGASSERT(state != NULL); 740 741 state->num = 0; 742 if (state->context) { 743 hesiod_end(state->context); 744 state->context = NULL; 745 } 746 return NS_SUCCESS; 747 } 748 749 /* 750 * _dns_pwscan 751 * Look for the Hesiod name provided in buffer in the NULL-terminated 752 * list of zones, 753 * and decode into pw/buffer/buflen. 754 */ 755 static int 756 _dns_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 757 struct dns_state *state, const char **zones) 758 { 759 const char **curzone; 760 char **hp, *ep; 761 int rv; 762 763 _DIAGASSERT(retval != NULL); 764 _DIAGASSERT(pw != NULL); 765 _DIAGASSERT(buffer != NULL); 766 _DIAGASSERT(state != NULL); 767 _DIAGASSERT(zones != NULL); 768 769 *retval = 0; 770 771 if (state->context == NULL) { /* only start if Hesiod not setup */ 772 rv = _dns_start(state); 773 if (rv != NS_SUCCESS) 774 return rv; 775 } 776 777 hp = NULL; 778 rv = NS_NOTFOUND; 779 780 for (curzone = zones; *curzone; curzone++) { /* search zones */ 781 hp = hesiod_resolve(state->context, buffer, *curzone); 782 if (hp != NULL) 783 break; 784 if (errno != ENOENT) { 785 rv = NS_UNAVAIL; 786 goto dnspwscan_out; 787 } 788 } 789 if (*curzone == NULL) 790 goto dnspwscan_out; 791 792 if ((ep = strchr(hp[0], '\n')) != NULL) 793 *ep = '\0'; /* clear trailing \n */ 794 if (_pw_parse(hp[0], pw, buffer, buflen, 1)) /* validate line */ 795 rv = NS_SUCCESS; 796 else 797 rv = NS_UNAVAIL; 798 799 dnspwscan_out: 800 if (rv != NS_SUCCESS) 801 *retval = errno; 802 if (hp) 803 hesiod_free_list(state->context, hp); 804 return rv; 805 } 806 807 /*ARGSUSED*/ 808 static int 809 _dns_setpwent(void *nsrv, void *nscb, va_list ap) 810 { 811 812 _dns_state.stayopen = 0; 813 return _dns_start(&_dns_state); 814 } 815 816 /*ARGSUSED*/ 817 static int 818 _dns_setpassent(void *nsrv, void *nscb, va_list ap) 819 { 820 int *retval = va_arg(ap, int *); 821 int stayopen = va_arg(ap, int); 822 823 int rv; 824 825 _dns_state.stayopen = stayopen; 826 rv = _dns_start(&_dns_state); 827 *retval = (rv == NS_SUCCESS); 828 return rv; 829 } 830 831 /*ARGSUSED*/ 832 static int 833 _dns_endpwent(void *nsrv, void *nscb, va_list ap) 834 { 835 836 _dns_state.stayopen = 0; 837 return _dns_end(&_dns_state); 838 } 839 840 /*ARGSUSED*/ 841 static int 842 _dns_getpwent(void *nsrv, void *nscb, va_list ap) 843 { 844 struct passwd **retval = va_arg(ap, struct passwd **); 845 846 char **hp, *ep; 847 int rv; 848 849 _DIAGASSERT(retval != NULL); 850 851 *retval = NULL; 852 853 if (_dns_state.num == -1) /* exhausted search */ 854 return NS_NOTFOUND; 855 856 if (_dns_state.context == NULL) { 857 /* only start if Hesiod not setup */ 858 rv = _dns_start(&_dns_state); 859 if (rv != NS_SUCCESS) 860 return rv; 861 } 862 863 next_dns_entry: 864 hp = NULL; 865 rv = NS_NOTFOUND; 866 867 /* find passwd-NNN */ 868 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), 869 "passwd-%u", _dns_state.num); 870 _dns_state.num++; 871 872 hp = hesiod_resolve(_dns_state.context, _dns_passwdbuf, "passwd"); 873 if (hp == NULL) { 874 if (errno == ENOENT) 875 _dns_state.num = -1; 876 else 877 rv = NS_UNAVAIL; 878 } else { 879 if ((ep = strchr(hp[0], '\n')) != NULL) 880 *ep = '\0'; /* clear trailing \n */ 881 /* validate line */ 882 if (_pw_parse(hp[0], &_dns_passwd, 883 _dns_passwdbuf, sizeof(_dns_passwdbuf), 1)) 884 rv = NS_SUCCESS; 885 else { /* dodgy entry, try again */ 886 hesiod_free_list(_dns_state.context, hp); 887 goto next_dns_entry; 888 } 889 } 890 891 if (hp) 892 hesiod_free_list(_dns_state.context, hp); 893 if (rv == NS_SUCCESS) 894 *retval = &_dns_passwd; 895 return rv; 896 } 897 898 /*ARGSUSED*/ 899 static int 900 _dns_getpwent_r(void *nsrv, void *nscb, va_list ap) 901 { 902 int *retval = va_arg(ap, int *); 903 struct passwd *pw = va_arg(ap, struct passwd *); 904 char *buffer = va_arg(ap, char *); 905 size_t buflen = va_arg(ap, size_t); 906 struct passwd **result = va_arg(ap, struct passwd **); 907 908 char **hp, *ep; 909 int rv; 910 911 _DIAGASSERT(retval != NULL); 912 _DIAGASSERT(pw != NULL); 913 _DIAGASSERT(buffer != NULL); 914 _DIAGASSERT(result != NULL); 915 916 *retval = 0; 917 918 if (_dns_state.num == -1) /* exhausted search */ 919 return NS_NOTFOUND; 920 921 if (_dns_state.context == NULL) { 922 /* only start if Hesiod not setup */ 923 rv = _dns_start(&_dns_state); 924 if (rv != NS_SUCCESS) 925 return rv; 926 } 927 928 next_dns_entry: 929 hp = NULL; 930 rv = NS_NOTFOUND; 931 932 /* find passwd-NNN */ 933 snprintf(buffer, buflen, "passwd-%u", _dns_state.num); 934 _dns_state.num++; 935 936 hp = hesiod_resolve(_dns_state.context, buffer, "passwd"); 937 if (hp == NULL) { 938 if (errno == ENOENT) 939 _dns_state.num = -1; 940 else 941 rv = NS_UNAVAIL; 942 } else { 943 if ((ep = strchr(hp[0], '\n')) != NULL) 944 *ep = '\0'; /* clear trailing \n */ 945 /* validate line */ 946 if (_pw_parse(hp[0], pw, buffer, buflen, 1)) 947 rv = NS_SUCCESS; 948 else { /* dodgy entry, try again */ 949 hesiod_free_list(_dns_state.context, hp); 950 goto next_dns_entry; 951 } 952 } 953 954 if (hp) 955 hesiod_free_list(_dns_state.context, hp); 956 if (rv == NS_SUCCESS) 957 *result = pw; 958 else 959 *result = NULL; 960 return rv; 961 } 962 963 static const char *_dns_uid_zones[] = { 964 "uid", 965 "passwd", 966 NULL 967 }; 968 969 /*ARGSUSED*/ 970 static int 971 _dns_getpwuid(void *nsrv, void *nscb, va_list ap) 972 { 973 struct passwd **retval = va_arg(ap, struct passwd **); 974 uid_t uid = va_arg(ap, uid_t); 975 976 int rv, rerror; 977 978 _DIAGASSERT(retval != NULL); 979 980 *retval = NULL; 981 rv = _dns_start(&_dns_state); 982 if (rv != NS_SUCCESS) 983 return rv; 984 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), 985 "%u", (unsigned int)uid); 986 rv = _dns_pwscan(&rerror, &_dns_passwd, 987 _dns_passwdbuf, sizeof(_dns_passwdbuf), 988 &_dns_state, _dns_uid_zones); 989 if (!_dns_state.stayopen) 990 _dns_end(&_dns_state); 991 if (rv == NS_SUCCESS && uid == _dns_passwd.pw_uid) 992 *retval = &_dns_passwd; 993 return rv; 994 } 995 996 /*ARGSUSED*/ 997 static int 998 _dns_getpwuid_r(void *nsrv, void *nscb, va_list ap) 999 { 1000 int *retval = va_arg(ap, int *); 1001 uid_t uid = va_arg(ap, uid_t); 1002 struct passwd *pw = va_arg(ap, struct passwd *); 1003 char *buffer = va_arg(ap, char *); 1004 size_t buflen = va_arg(ap, size_t); 1005 struct passwd **result = va_arg(ap, struct passwd **); 1006 1007 struct dns_state state; 1008 int rv; 1009 1010 _DIAGASSERT(retval != NULL); 1011 _DIAGASSERT(pw != NULL); 1012 _DIAGASSERT(buffer != NULL); 1013 _DIAGASSERT(result != NULL); 1014 1015 *result = NULL; 1016 memset(&state, 0, sizeof(state)); 1017 snprintf(buffer, buflen, "%u", (unsigned int)uid); 1018 rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_uid_zones); 1019 _dns_end(&state); 1020 if (rv != NS_SUCCESS) 1021 return rv; 1022 if (uid == pw->pw_uid) { 1023 *result = pw; 1024 return NS_SUCCESS; 1025 } else 1026 return NS_NOTFOUND; 1027 } 1028 1029 static const char *_dns_nam_zones[] = { 1030 "passwd", 1031 NULL 1032 }; 1033 1034 /*ARGSUSED*/ 1035 static int 1036 _dns_getpwnam(void *nsrv, void *nscb, va_list ap) 1037 { 1038 struct passwd **retval = va_arg(ap, struct passwd **); 1039 const char *name = va_arg(ap, const char *); 1040 1041 int rv, rerror; 1042 1043 _DIAGASSERT(retval != NULL); 1044 1045 *retval = NULL; 1046 rv = _dns_start(&_dns_state); 1047 if (rv != NS_SUCCESS) 1048 return rv; 1049 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), "%s", name); 1050 rv = _dns_pwscan(&rerror, &_dns_passwd, 1051 _dns_passwdbuf, sizeof(_dns_passwdbuf), 1052 &_dns_state, _dns_nam_zones); 1053 if (!_dns_state.stayopen) 1054 _dns_end(&_dns_state); 1055 if (rv == NS_SUCCESS && strcmp(name, _dns_passwd.pw_name) == 0) 1056 *retval = &_dns_passwd; 1057 return rv; 1058 } 1059 1060 /*ARGSUSED*/ 1061 static int 1062 _dns_getpwnam_r(void *nsrv, void *nscb, va_list ap) 1063 { 1064 int *retval = va_arg(ap, int *); 1065 const char *name = va_arg(ap, const char *); 1066 struct passwd *pw = va_arg(ap, struct passwd *); 1067 char *buffer = va_arg(ap, char *); 1068 size_t buflen = va_arg(ap, size_t); 1069 struct passwd **result = va_arg(ap, struct passwd **); 1070 1071 struct dns_state state; 1072 int rv; 1073 1074 _DIAGASSERT(retval != NULL); 1075 _DIAGASSERT(pw != NULL); 1076 _DIAGASSERT(buffer != NULL); 1077 _DIAGASSERT(result != NULL); 1078 1079 *result = NULL; 1080 memset(&state, 0, sizeof(state)); 1081 snprintf(buffer, buflen, "%s", name); 1082 rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_nam_zones); 1083 _dns_end(&state); 1084 if (rv != NS_SUCCESS) 1085 return rv; 1086 if (strcmp(name, pw->pw_name) == 0) { 1087 *result = pw; 1088 return NS_SUCCESS; 1089 } else 1090 return NS_NOTFOUND; 1091 } 1092 1093 #endif /* HESIOD */ 1094 1095 1096 #ifdef YP 1097 /* 1098 * nis methods 1099 */ 1100 /* state shared between nis methods */ 1101 struct nis_state { 1102 int stayopen; /* see getpassent(3) */ 1103 char *domain; /* NIS domain */ 1104 int done; /* non-zero if search exhausted */ 1105 char *current; /* current first/next match */ 1106 int currentlen; /* length of _nis_current */ 1107 enum { /* shadow map type */ 1108 NISMAP_UNKNOWN, /* unknown ... */ 1109 NISMAP_NONE, /* none: use "passwd.by*" */ 1110 NISMAP_ADJUNCT, /* pw_passwd from "passwd.adjunct.*" */ 1111 NISMAP_MASTER /* all from "master.passwd.by*" */ 1112 } maptype; 1113 }; 1114 1115 static struct nis_state _nis_state; 1116 /* storage for non _r functions */ 1117 static struct passwd _nis_passwd; 1118 static char _nis_passwdbuf[_GETPW_R_SIZE_MAX]; 1119 1120 /* macros for deciding which NIS maps to use. */ 1121 #define PASSWD_BYNAME(x) ((x)->maptype == NISMAP_MASTER \ 1122 ? "master.passwd.byname" : "passwd.byname") 1123 #define PASSWD_BYUID(x) ((x)->maptype == NISMAP_MASTER \ 1124 ? "master.passwd.byuid" : "passwd.byuid") 1125 1126 static int 1127 _nis_start(struct nis_state *state) 1128 { 1129 1130 _DIAGASSERT(state != NULL); 1131 1132 state->done = 0; 1133 if (state->current) { 1134 free(state->current); 1135 state->current = NULL; 1136 } 1137 if (state->domain == NULL) { /* setup NIS */ 1138 switch (yp_get_default_domain(&state->domain)) { 1139 case 0: 1140 break; 1141 case YPERR_RESRC: 1142 return NS_TRYAGAIN; 1143 default: 1144 return NS_UNAVAIL; 1145 } 1146 } 1147 1148 /* determine where to get pw_passwd from */ 1149 if (state->maptype == NISMAP_UNKNOWN) { 1150 int r, order; 1151 1152 state->maptype = NISMAP_NONE; /* default to no adjunct */ 1153 if (geteuid() != 0) /* non-root can't use adjunct */ 1154 return NS_SUCCESS; 1155 1156 /* look for "master.passwd.*" */ 1157 r = yp_order(state->domain, "master.passwd.byname", &order); 1158 if (r == 0) { 1159 state->maptype = NISMAP_MASTER; 1160 return NS_SUCCESS; 1161 } 1162 1163 /* master.passwd doesn't exist, try passwd.adjunct */ 1164 if (r == YPERR_MAP) { 1165 r = yp_order(state->domain, "passwd.adjunct.byname", 1166 &order); 1167 if (r == 0) 1168 state->maptype = NISMAP_ADJUNCT; 1169 } 1170 } 1171 return NS_SUCCESS; 1172 } 1173 1174 static int 1175 _nis_end(struct nis_state *state) 1176 { 1177 1178 _DIAGASSERT(state != NULL); 1179 1180 if (state->domain) 1181 state->domain = NULL; 1182 state->done = 0; 1183 if (state->current) 1184 free(state->current); 1185 state->current = NULL; 1186 state->maptype = NISMAP_UNKNOWN; 1187 return NS_SUCCESS; 1188 } 1189 1190 /* 1191 * nis_parse 1192 * wrapper to _pw_parse that obtains the real password from the 1193 * "passwd.adjunct.byname" NIS map if the maptype is NISMAP_ADJUNCT. 1194 */ 1195 static int 1196 _nis_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen, 1197 struct nis_state *state) 1198 { 1199 size_t elen; 1200 1201 _DIAGASSERT(entry != NULL); 1202 _DIAGASSERT(pw != NULL); 1203 _DIAGASSERT(buf != NULL); 1204 _DIAGASSERT(state != NULL); 1205 1206 elen = strlen(entry); 1207 if (elen >= buflen) 1208 return 0; 1209 if (! _pw_parse(entry, pw, buf, buflen, 1210 !(state->maptype == NISMAP_MASTER))) 1211 return 0; 1212 1213 if ((state->maptype == NISMAP_ADJUNCT) && 1214 (strstr(pw->pw_passwd, "##") != NULL)) { 1215 char *data; 1216 int datalen; 1217 1218 if (yp_match(state->domain, "passwd.adjunct.byname", 1219 pw->pw_name, (int)strlen(pw->pw_name), 1220 &data, &datalen) == 0) { 1221 char *bp, *ep; 1222 /* skip name to get password */ 1223 ep = data; 1224 if ((bp = strsep(&ep, ":")) != NULL && 1225 (bp = strsep(&ep, ":")) != NULL) { 1226 /* store new pw_passwd after entry */ 1227 strlcpy(buf + elen, bp, buflen - elen); 1228 pw->pw_passwd = &buf[elen]; 1229 } 1230 free(data); 1231 } 1232 } 1233 1234 return 1; 1235 } 1236 1237 1238 /* 1239 * _nis_pwscan 1240 * Look for the yp key provided in buffer from map, 1241 * and decode into pw/buffer/buflen. 1242 */ 1243 static int 1244 _nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 1245 struct nis_state *state, const char *map) 1246 { 1247 char *data; 1248 int nisr, rv, datalen; 1249 1250 _DIAGASSERT(retval != NULL); 1251 _DIAGASSERT(pw != NULL); 1252 _DIAGASSERT(buffer != NULL); 1253 _DIAGASSERT(state != NULL); 1254 _DIAGASSERT(map != NULL); 1255 1256 *retval = 0; 1257 1258 if (state->domain == NULL) { /* only start if NIS not setup */ 1259 rv = _nis_start(state); 1260 if (rv != NS_SUCCESS) 1261 return rv; 1262 } 1263 1264 data = NULL; 1265 rv = NS_NOTFOUND; 1266 1267 /* search map */ 1268 nisr = yp_match(state->domain, map, buffer, (int)strlen(buffer), 1269 &data, &datalen); 1270 switch (nisr) { 1271 case 0: 1272 data[datalen] = '\0'; /* clear trailing \n */ 1273 if (_nis_parse(data, pw, buffer, buflen, state)) 1274 rv = NS_SUCCESS; /* validate line */ 1275 else 1276 rv = NS_UNAVAIL; 1277 break; 1278 case YPERR_KEY: 1279 break; 1280 default: 1281 rv = NS_UNAVAIL; 1282 break; 1283 } 1284 1285 if (rv != NS_SUCCESS) 1286 *retval = errno; 1287 if (data) 1288 free(data); 1289 return rv; 1290 } 1291 1292 /*ARGSUSED*/ 1293 static int 1294 _nis_setpwent(void *nsrv, void *nscb, va_list ap) 1295 { 1296 1297 _nis_state.stayopen = 0; 1298 return _nis_start(&_nis_state); 1299 } 1300 1301 /*ARGSUSED*/ 1302 static int 1303 _nis_setpassent(void *nsrv, void *nscb, va_list ap) 1304 { 1305 int *retval = va_arg(ap, int *); 1306 int stayopen = va_arg(ap, int); 1307 1308 int rv; 1309 1310 _nis_state.stayopen = stayopen; 1311 rv = _nis_start(&_nis_state); 1312 *retval = (rv == NS_SUCCESS); 1313 return rv; 1314 } 1315 1316 /*ARGSUSED*/ 1317 static int 1318 _nis_endpwent(void *nsrv, void *nscb, va_list ap) 1319 { 1320 1321 return _nis_end(&_nis_state); 1322 } 1323 1324 1325 /*ARGSUSED*/ 1326 static int 1327 _nis_getpwent(void *nsrv, void *nscb, va_list ap) 1328 { 1329 struct passwd **retval = va_arg(ap, struct passwd **); 1330 1331 char *key, *data; 1332 int keylen, datalen, rv, nisr; 1333 1334 _DIAGASSERT(retval != NULL); 1335 1336 *retval = NULL; 1337 1338 if (_nis_state.done) /* exhausted search */ 1339 return NS_NOTFOUND; 1340 if (_nis_state.domain == NULL) { 1341 /* only start if NIS not setup */ 1342 rv = _nis_start(&_nis_state); 1343 if (rv != NS_SUCCESS) 1344 return rv; 1345 } 1346 1347 next_nis_entry: 1348 key = NULL; 1349 data = NULL; 1350 rv = NS_NOTFOUND; 1351 1352 if (_nis_state.current) { /* already searching */ 1353 nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1354 _nis_state.current, _nis_state.currentlen, 1355 &key, &keylen, &data, &datalen); 1356 free(_nis_state.current); 1357 _nis_state.current = NULL; 1358 switch (nisr) { 1359 case 0: 1360 _nis_state.current = key; 1361 _nis_state.currentlen = keylen; 1362 key = NULL; 1363 break; 1364 case YPERR_NOMORE: 1365 _nis_state.done = 1; 1366 goto nisent_out; 1367 default: 1368 rv = NS_UNAVAIL; 1369 goto nisent_out; 1370 } 1371 } else { /* new search */ 1372 if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1373 &_nis_state.current, &_nis_state.currentlen, 1374 &data, &datalen)) { 1375 rv = NS_UNAVAIL; 1376 goto nisent_out; 1377 } 1378 } 1379 1380 data[datalen] = '\0'; /* clear trailing \n */ 1381 /* validate line */ 1382 if (_nis_parse(data, &_nis_passwd, 1383 _nis_passwdbuf, sizeof(_nis_passwdbuf), &_nis_state)) 1384 rv = NS_SUCCESS; 1385 else { /* dodgy entry, try again */ 1386 if (key) 1387 free(key); 1388 free(data); 1389 goto next_nis_entry; 1390 } 1391 1392 nisent_out: 1393 if (key) 1394 free(key); 1395 if (data) 1396 free(data); 1397 if (rv == NS_SUCCESS) 1398 *retval = &_nis_passwd; 1399 return rv; 1400 } 1401 1402 /*ARGSUSED*/ 1403 static int 1404 _nis_getpwent_r(void *nsrv, void *nscb, va_list ap) 1405 { 1406 int *retval = va_arg(ap, int *); 1407 struct passwd *pw = va_arg(ap, struct passwd *); 1408 char *buffer = va_arg(ap, char *); 1409 size_t buflen = va_arg(ap, size_t); 1410 struct passwd **result = va_arg(ap, struct passwd **); 1411 1412 char *key, *data; 1413 int keylen, datalen, rv, nisr; 1414 1415 _DIAGASSERT(retval != NULL); 1416 _DIAGASSERT(pw != NULL); 1417 _DIAGASSERT(buffer != NULL); 1418 _DIAGASSERT(result != NULL); 1419 1420 *retval = 0; 1421 1422 if (_nis_state.done) /* exhausted search */ 1423 return NS_NOTFOUND; 1424 if (_nis_state.domain == NULL) { 1425 /* only start if NIS not setup */ 1426 rv = _nis_start(&_nis_state); 1427 if (rv != NS_SUCCESS) 1428 return rv; 1429 } 1430 1431 next_nis_entry: 1432 key = NULL; 1433 data = NULL; 1434 rv = NS_NOTFOUND; 1435 1436 if (_nis_state.current) { /* already searching */ 1437 nisr = yp_next(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1438 _nis_state.current, _nis_state.currentlen, 1439 &key, &keylen, &data, &datalen); 1440 free(_nis_state.current); 1441 _nis_state.current = NULL; 1442 switch (nisr) { 1443 case 0: 1444 _nis_state.current = key; 1445 _nis_state.currentlen = keylen; 1446 key = NULL; 1447 break; 1448 case YPERR_NOMORE: 1449 _nis_state.done = 1; 1450 goto nisent_out; 1451 default: 1452 rv = NS_UNAVAIL; 1453 goto nisent_out; 1454 } 1455 } else { /* new search */ 1456 if (yp_first(_nis_state.domain, PASSWD_BYNAME(&_nis_state), 1457 &_nis_state.current, &_nis_state.currentlen, 1458 &data, &datalen)) { 1459 rv = NS_UNAVAIL; 1460 goto nisent_out; 1461 } 1462 } 1463 1464 data[datalen] = '\0'; /* clear trailing \n */ 1465 /* validate line */ 1466 if (_nis_parse(data, pw, buffer, buflen, &_nis_state)) 1467 rv = NS_SUCCESS; 1468 else { /* dodgy entry, try again */ 1469 if (key) 1470 free(key); 1471 free(data); 1472 goto next_nis_entry; 1473 } 1474 1475 nisent_out: 1476 if (key) 1477 free(key); 1478 if (data) 1479 free(data); 1480 if (rv == NS_SUCCESS) 1481 *result = pw; 1482 else 1483 *result = NULL; 1484 return rv; 1485 } 1486 1487 /*ARGSUSED*/ 1488 static int 1489 _nis_getpwuid(void *nsrv, void *nscb, va_list ap) 1490 { 1491 struct passwd **retval = va_arg(ap, struct passwd **); 1492 uid_t uid = va_arg(ap, uid_t); 1493 1494 int rv, rerror; 1495 1496 _DIAGASSERT(retval != NULL); 1497 1498 *retval = NULL; 1499 rv = _nis_start(&_nis_state); 1500 if (rv != NS_SUCCESS) 1501 return rv; 1502 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%u", (unsigned int)uid); 1503 rv = _nis_pwscan(&rerror, &_nis_passwd, 1504 _nis_passwdbuf, sizeof(_nis_passwdbuf), 1505 &_nis_state, PASSWD_BYUID(&_nis_state)); 1506 if (!_nis_state.stayopen) 1507 _nis_end(&_nis_state); 1508 if (rv == NS_SUCCESS && uid == _nis_passwd.pw_uid) 1509 *retval = &_nis_passwd; 1510 return rv; 1511 } 1512 1513 /*ARGSUSED*/ 1514 static int 1515 _nis_getpwuid_r(void *nsrv, void *nscb, va_list ap) 1516 { 1517 int *retval = va_arg(ap, int *); 1518 uid_t uid = va_arg(ap, uid_t); 1519 struct passwd *pw = va_arg(ap, struct passwd *); 1520 char *buffer = va_arg(ap, char *); 1521 size_t buflen = va_arg(ap, size_t); 1522 struct passwd **result = va_arg(ap, struct passwd **); 1523 1524 struct nis_state state; 1525 int rv; 1526 1527 _DIAGASSERT(retval != NULL); 1528 _DIAGASSERT(pw != NULL); 1529 _DIAGASSERT(buffer != NULL); 1530 _DIAGASSERT(result != NULL); 1531 1532 *result = NULL; 1533 memset(&state, 0, sizeof(state)); 1534 rv = _nis_start(&state); 1535 if (rv != NS_SUCCESS) 1536 return rv; 1537 snprintf(buffer, buflen, "%u", (unsigned int)uid); 1538 rv = _nis_pwscan(retval, pw, buffer, buflen, 1539 &state, PASSWD_BYUID(&state)); 1540 _nis_end(&state); 1541 if (rv != NS_SUCCESS) 1542 return rv; 1543 if (uid == pw->pw_uid) { 1544 *result = pw; 1545 return NS_SUCCESS; 1546 } else 1547 return NS_NOTFOUND; 1548 } 1549 1550 /*ARGSUSED*/ 1551 static int 1552 _nis_getpwnam(void *nsrv, void *nscb, va_list ap) 1553 { 1554 struct passwd **retval = va_arg(ap, struct passwd **); 1555 const char *name = va_arg(ap, const char *); 1556 1557 int rv, rerror; 1558 1559 _DIAGASSERT(retval != NULL); 1560 1561 *retval = NULL; 1562 rv = _nis_start(&_nis_state); 1563 if (rv != NS_SUCCESS) 1564 return rv; 1565 snprintf(_nis_passwdbuf, sizeof(_nis_passwdbuf), "%s", name); 1566 rv = _nis_pwscan(&rerror, &_nis_passwd, 1567 _nis_passwdbuf, sizeof(_nis_passwdbuf), 1568 &_nis_state, PASSWD_BYNAME(&_nis_state)); 1569 if (!_nis_state.stayopen) 1570 _nis_end(&_nis_state); 1571 if (rv == NS_SUCCESS && strcmp(name, _nis_passwd.pw_name) == 0) 1572 *retval = &_nis_passwd; 1573 return rv; 1574 } 1575 1576 /*ARGSUSED*/ 1577 static int 1578 _nis_getpwnam_r(void *nsrv, void *nscb, va_list ap) 1579 { 1580 int *retval = va_arg(ap, int *); 1581 const char *name = va_arg(ap, const char *); 1582 struct passwd *pw = va_arg(ap, struct passwd *); 1583 char *buffer = va_arg(ap, char *); 1584 size_t buflen = va_arg(ap, size_t); 1585 struct passwd **result = va_arg(ap, struct passwd **); 1586 1587 struct nis_state state; 1588 int rv; 1589 1590 _DIAGASSERT(retval != NULL); 1591 _DIAGASSERT(pw != NULL); 1592 _DIAGASSERT(buffer != NULL); 1593 _DIAGASSERT(result != NULL); 1594 1595 *result = NULL; 1596 snprintf(buffer, buflen, "%s", name); 1597 memset(&state, 0, sizeof(state)); 1598 rv = _nis_start(&state); 1599 if (rv != NS_SUCCESS) 1600 return rv; 1601 rv = _nis_pwscan(retval, pw, buffer, buflen, 1602 &state, PASSWD_BYNAME(&state)); 1603 _nis_end(&state); 1604 if (rv != NS_SUCCESS) 1605 return rv; 1606 if (strcmp(name, pw->pw_name) == 0) { 1607 *result = pw; 1608 return NS_SUCCESS; 1609 } else 1610 return NS_NOTFOUND; 1611 } 1612 1613 #endif /* YP */ 1614 1615 1616 #ifdef _PASSWD_COMPAT 1617 /* 1618 * compat methods 1619 */ 1620 1621 /* state shared between compat methods */ 1622 1623 struct compat_state { 1624 int stayopen; /* see getpassent(3) */ 1625 DB *db; /* passwd DB */ 1626 int keynum; /* key counter, -1 if no more */ 1627 enum { /* current compat mode */ 1628 COMPAT_NOTOKEN = 0, /* no compat token present */ 1629 COMPAT_NONE, /* parsing normal pwd.db line */ 1630 COMPAT_FULL, /* parsing `+' entries */ 1631 COMPAT_USER, /* parsing `+name' entries */ 1632 COMPAT_NETGROUP /* parsing `+@netgroup' entries */ 1633 } mode; 1634 char *user; /* COMPAT_USER "+name" */ 1635 DB *exclude; /* compat exclude DB */ 1636 struct passwd proto; /* proto passwd entry */ 1637 char protobuf[_GETPW_R_SIZE_MAX]; 1638 /* buffer for proto ptrs */ 1639 int protoflags; /* proto passwd flags */ 1640 }; 1641 1642 static struct compat_state _compat_state; 1643 /* storage for non _r functions */ 1644 static struct passwd _compat_passwd; 1645 static char _compat_passwdbuf[_GETPW_R_SIZE_MAX]; 1646 1647 static int 1648 _compat_start(struct compat_state *state) 1649 { 1650 int rv; 1651 1652 _DIAGASSERT(state != NULL); 1653 1654 state->keynum = 0; 1655 if (state->db == NULL) { /* not open yet */ 1656 DBT key, data; 1657 DBT pkey, pdata; 1658 char bf[MAXLOGNAME]; 1659 1660 rv = _pw_opendb(&state->db); 1661 if (rv != NS_SUCCESS) 1662 return rv; 1663 1664 state->mode = COMPAT_NOTOKEN; 1665 1666 /* 1667 * Determine if the "compat" token is present in pwd.db; 1668 * either "__YP!" or PW_KEYBYNAME+"+". 1669 * Only works if pwd_mkdb installs the token. 1670 */ 1671 key.data = (u_char *)__UNCONST(__yp_token); 1672 key.size = strlen(__yp_token); 1673 1674 bf[0] = _PW_KEYBYNAME; /* Pre-token database support. */ 1675 bf[1] = '+'; 1676 pkey.data = (u_char *)bf; 1677 pkey.size = 2; 1678 1679 if ((state->db->get)(state->db, &key, &data, 0) == 0 1680 || (state->db->get)(state->db, &pkey, &pdata, 0) == 0) 1681 state->mode = COMPAT_NONE; 1682 } 1683 return NS_SUCCESS; 1684 } 1685 1686 static int 1687 _compat_end(struct compat_state *state) 1688 { 1689 1690 _DIAGASSERT(state != NULL); 1691 1692 state->keynum = 0; 1693 if (state->db) { 1694 (void)(state->db->close)(state->db); 1695 state->db = NULL; 1696 } 1697 state->mode = COMPAT_NOTOKEN; 1698 if (state->user) 1699 free(state->user); 1700 state->user = NULL; 1701 if (state->exclude != NULL) 1702 (void)(state->exclude->close)(state->exclude); 1703 state->exclude = NULL; 1704 state->proto.pw_name = NULL; 1705 state->protoflags = 0; 1706 return NS_SUCCESS; 1707 } 1708 1709 /* 1710 * _compat_add_exclude 1711 * add the name to the exclude list in state->exclude. 1712 */ 1713 static int 1714 _compat_add_exclude(struct compat_state *state, const char *name) 1715 { 1716 DBT key, data; 1717 1718 _DIAGASSERT(state != NULL); 1719 _DIAGASSERT(name != NULL); 1720 1721 /* initialize the exclusion table if needed */ 1722 if (state->exclude == NULL) { 1723 state->exclude = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL); 1724 if (state->exclude == NULL) 1725 return 0; 1726 } 1727 1728 key.size = strlen(name); /* set up the key */ 1729 key.data = (u_char *)__UNCONST(name); 1730 1731 data.data = NULL; /* data is nothing */ 1732 data.size = 0; 1733 1734 /* store it */ 1735 if ((state->exclude->put)(state->exclude, &key, &data, 0) == -1) 1736 return 0; 1737 1738 return 1; 1739 } 1740 1741 /* 1742 * _compat_is_excluded 1743 * test if a name is on the compat mode exclude list 1744 */ 1745 static int 1746 _compat_is_excluded(struct compat_state *state, const char *name) 1747 { 1748 DBT key, data; 1749 1750 _DIAGASSERT(state != NULL); 1751 _DIAGASSERT(name != NULL); 1752 1753 if (state->exclude == NULL) 1754 return 0; /* nothing excluded */ 1755 1756 key.size = strlen(name); /* set up the key */ 1757 key.data = (u_char *)__UNCONST(name); 1758 1759 if ((state->exclude->get)(state->exclude, &key, &data, 0) == 0) 1760 return 1; /* is excluded */ 1761 1762 return 0; 1763 } 1764 1765 1766 /* 1767 * _passwdcompat_bad 1768 * log an error if "files" or "compat" is specified in 1769 * passwd_compat database 1770 */ 1771 /*ARGSUSED*/ 1772 static int 1773 _passwdcompat_bad(void *nsrv, void *nscb, va_list ap) 1774 { 1775 static int warned; 1776 1777 _DIAGASSERT(cb_data != 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 { 0 } 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 { 0 } 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 { 0 } 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 { 0 } 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 { 0 } 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 */ 1897 static int 1898 _compat_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 1899 struct compat_state *state, int search, const char *name, uid_t uid) 1900 { 1901 DBT key; 1902 int rv, r, pwflags; 1903 const char *user, *host, *dom; 1904 const void *from; 1905 size_t fromlen; 1906 1907 _DIAGASSERT(retval != NULL); 1908 _DIAGASSERT(pw != NULL); 1909 _DIAGASSERT(buffer != NULL); 1910 _DIAGASSERT(state != NULL); 1911 /* name may be NULL */ 1912 1913 *retval = 0; 1914 1915 if (state->db == NULL) { 1916 rv = _compat_start(state); 1917 if (rv != NS_SUCCESS) 1918 return rv; 1919 } 1920 if (buflen <= 1) { /* buffer too small */ 1921 *retval = ERANGE; 1922 return NS_UNAVAIL; 1923 } 1924 1925 for (;;) { /* loop over pwd.db */ 1926 rv = NS_NOTFOUND; 1927 if (state->mode != COMPAT_NOTOKEN && 1928 state->mode != COMPAT_NONE) { 1929 /* doing a compat lookup */ 1930 struct passwd cpw; 1931 char cbuf[_GETPW_R_SIZE_MAX]; 1932 1933 switch (state->mode) { 1934 1935 case COMPAT_FULL: 1936 /* get next user */ 1937 rv = _passwdcompat_pwscan(&cpw, 1938 cbuf, sizeof(cbuf), 1939 _PW_KEYBYNUM, NULL, 0); 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) 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 { 0 } 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 { 0 } 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 return (r == NS_SUCCESS) ? 0 : retval ? retval : ENOENT; 2384 } 2385 2386 2387 struct passwd * 2388 getpwnam(const char *name) 2389 { 2390 int rv; 2391 struct passwd *retval; 2392 2393 static const ns_dtab dtab[] = { 2394 NS_FILES_CB(_files_getpwnam, NULL) 2395 NS_DNS_CB(_dns_getpwnam, NULL) 2396 NS_NIS_CB(_nis_getpwnam, NULL) 2397 NS_COMPAT_CB(_compat_getpwnam, NULL) 2398 { 0 } 2399 }; 2400 2401 mutex_lock(&_pwmutex); 2402 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam", __nsdefaultcompat, 2403 &retval, name); 2404 mutex_unlock(&_pwmutex); 2405 return (rv == NS_SUCCESS) ? retval : NULL; 2406 } 2407 2408 int 2409 getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t buflen, 2410 struct passwd **result) 2411 { 2412 int r, retval; 2413 2414 static const ns_dtab dtab[] = { 2415 NS_FILES_CB(_files_getpwnam_r, NULL) 2416 NS_DNS_CB(_dns_getpwnam_r, NULL) 2417 NS_NIS_CB(_nis_getpwnam_r, NULL) 2418 NS_COMPAT_CB(_compat_getpwnam_r, NULL) 2419 { 0 } 2420 }; 2421 2422 _DIAGASSERT(name != NULL); 2423 _DIAGASSERT(pwd != NULL); 2424 _DIAGASSERT(buffer != NULL); 2425 _DIAGASSERT(result != NULL); 2426 2427 *result = NULL; 2428 retval = 0; 2429 mutex_lock(&_pwmutex); 2430 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwnam_r", __nsdefaultcompat, 2431 &retval, name, pwd, buffer, buflen, result); 2432 mutex_unlock(&_pwmutex); 2433 return (r == NS_SUCCESS) ? 0 : retval ? retval : ENOENT; 2434 } 2435 2436 struct passwd * 2437 getpwuid(uid_t uid) 2438 { 2439 int rv; 2440 struct passwd *retval; 2441 2442 static const ns_dtab dtab[] = { 2443 NS_FILES_CB(_files_getpwuid, NULL) 2444 NS_DNS_CB(_dns_getpwuid, NULL) 2445 NS_NIS_CB(_nis_getpwuid, NULL) 2446 NS_COMPAT_CB(_compat_getpwuid, NULL) 2447 { 0 } 2448 }; 2449 2450 mutex_lock(&_pwmutex); 2451 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid", __nsdefaultcompat, 2452 &retval, uid); 2453 mutex_unlock(&_pwmutex); 2454 return (rv == NS_SUCCESS) ? retval : NULL; 2455 } 2456 2457 int 2458 getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t buflen, 2459 struct passwd **result) 2460 { 2461 int r, retval; 2462 2463 static const ns_dtab dtab[] = { 2464 NS_FILES_CB(_files_getpwuid_r, NULL) 2465 NS_DNS_CB(_dns_getpwuid_r, NULL) 2466 NS_NIS_CB(_nis_getpwuid_r, NULL) 2467 NS_COMPAT_CB(_compat_getpwuid_r, NULL) 2468 { 0 } 2469 }; 2470 2471 _DIAGASSERT(pwd != NULL); 2472 _DIAGASSERT(buffer != NULL); 2473 _DIAGASSERT(result != NULL); 2474 2475 *result = NULL; 2476 retval = 0; 2477 mutex_lock(&_pwmutex); 2478 r = nsdispatch(NULL, dtab, NSDB_PASSWD, "getpwuid_r", __nsdefaultcompat, 2479 &retval, uid, pwd, buffer, buflen, result); 2480 mutex_unlock(&_pwmutex); 2481 return (r == NS_SUCCESS) ? 0 : retval ? retval : ENOENT; 2482 } 2483 2484 void 2485 endpwent(void) 2486 { 2487 static const ns_dtab dtab[] = { 2488 NS_FILES_CB(_files_endpwent, NULL) 2489 NS_DNS_CB(_dns_endpwent, NULL) 2490 NS_NIS_CB(_nis_endpwent, NULL) 2491 NS_COMPAT_CB(_compat_endpwent, NULL) 2492 { 0 } 2493 }; 2494 2495 mutex_lock(&_pwmutex); 2496 /* force all endpwent() methods */ 2497 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", 2498 __nsdefaultcompat_forceall); 2499 mutex_unlock(&_pwmutex); 2500 } 2501 2502 /*ARGSUSED*/ 2503 int 2504 setpassent(int stayopen) 2505 { 2506 static const ns_dtab dtab[] = { 2507 NS_FILES_CB(_files_setpassent, NULL) 2508 NS_DNS_CB(_dns_setpassent, NULL) 2509 NS_NIS_CB(_nis_setpassent, NULL) 2510 NS_COMPAT_CB(_compat_setpassent, NULL) 2511 { 0 } 2512 }; 2513 int rv, retval; 2514 2515 mutex_lock(&_pwmutex); 2516 /* force all setpassent() methods */ 2517 rv = nsdispatch(NULL, dtab, NSDB_PASSWD, "setpassent", 2518 __nsdefaultcompat_forceall, &retval, stayopen); 2519 mutex_unlock(&_pwmutex); 2520 return (rv == NS_SUCCESS) ? retval : 0; 2521 } 2522 2523 void 2524 setpwent(void) 2525 { 2526 static const ns_dtab dtab[] = { 2527 NS_FILES_CB(_files_setpwent, NULL) 2528 NS_DNS_CB(_dns_setpwent, NULL) 2529 NS_NIS_CB(_nis_setpwent, NULL) 2530 NS_COMPAT_CB(_compat_setpwent, NULL) 2531 { 0 } 2532 }; 2533 2534 mutex_lock(&_pwmutex); 2535 /* force all setpwent() methods */ 2536 (void) nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", 2537 __nsdefaultcompat_forceall); 2538 mutex_unlock(&_pwmutex); 2539 } 2540