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