1 /* $NetBSD: getpwent.c,v 1.82 2017/01/14 22:19:29 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.82 2017/01/14 22:19:29 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 <rpc/rpc.h> 121 #include <rpcsvc/yp_prot.h> 122 #include <rpcsvc/ypclnt.h> 123 #endif 124 125 #include "pw_private.h" 126 127 #define _PASSWD_COMPAT /* "passwd" defaults to compat, so always provide it */ 128 129 #ifdef __weak_alias 130 __weak_alias(endpwent,_endpwent) 131 __weak_alias(setpassent,_setpassent) 132 __weak_alias(setpwent,_setpwent) 133 #endif 134 135 #ifdef _REENTRANT 136 static mutex_t _pwmutex = MUTEX_INITIALIZER; 137 #endif 138 139 const char __yp_token[] = "__YP!"; /* Let pwd_mkdb pull this in. */ 140 141 142 /* 143 * The pwd.db lookup techniques and data extraction code here must be kept 144 * in sync with that in `pwd_mkdb'. 145 */ 146 147 #if defined(YP) || defined(HESIOD) 148 /* 149 * _pw_parse 150 * Parses entry using pw_scan(3) (without the trailing \n) 151 * after copying to buf, and fills in pw with corresponding values. 152 * If old is non-zero, entry is in _PASSWORD_OLDFMT. 153 * Returns 1 if parsed successfully, 0 on parse failure. 154 */ 155 static int 156 _pw_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen, 157 int old) 158 { 159 int flags; 160 161 _DIAGASSERT(entry != NULL); 162 _DIAGASSERT(pw != NULL); 163 _DIAGASSERT(buf != NULL); 164 165 if (strlcpy(buf, entry, buflen) >= buflen) 166 return 0; 167 flags = _PASSWORD_NOWARN; 168 if (old) 169 flags |= _PASSWORD_OLDFMT; 170 return __pw_scan(buf, pw, &flags); 171 } 172 #endif /* YP || HESIOD */ 173 174 /* 175 * _pw_opendb 176 * if *db is NULL, dbopen(3) /etc/spwd.db or /etc/pwd.db (depending 177 * upon permissions, etc) 178 */ 179 static int 180 _pw_opendb(DB **db, int *version) 181 { 182 static int warned; 183 DBT key; 184 DBT value; 185 186 const char *dbfile = NULL; 187 188 _DIAGASSERT(db != NULL); 189 _DIAGASSERT(version != NULL); 190 if (*db != NULL) /* open *db */ 191 return NS_SUCCESS; 192 193 if (geteuid() == 0) { 194 dbfile = _PATH_SMP_DB; 195 *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL); 196 } 197 if (*db == NULL) { 198 dbfile = _PATH_MP_DB; 199 *db = dbopen(dbfile, O_RDONLY, 0, DB_HASH, NULL); 200 } 201 if (*db == NULL) { 202 if (!warned) { 203 int serrno = errno; 204 syslog(LOG_ERR, "%s: %m", dbfile); 205 errno = serrno; 206 } 207 warned = 1; 208 return NS_UNAVAIL; 209 } 210 key.data = __UNCONST("VERSION"); 211 key.size = strlen((char *)key.data) + 1; 212 switch ((*(*db)->get)(*db, &key, &value, 0)) { 213 case 0: 214 if (sizeof(*version) != value.size) 215 return NS_UNAVAIL; 216 (void)memcpy(version, value.data, value.size); 217 break; /* found */ 218 case 1: 219 *version = 0; /* not found */ 220 break; 221 case -1: 222 return NS_UNAVAIL; /* error in db routines */ 223 default: 224 abort(); 225 } 226 return NS_SUCCESS; 227 } 228 229 /* 230 * _pw_getkey 231 * Lookup key in *db, filling in pw 232 * with the result, allocating memory from buffer (size buflen). 233 * (The caller may point key.data to buffer on entry; the contents 234 * of key.data will be invalid on exit.) 235 */ 236 static int 237 _pw_getkey(DB *db, DBT *key, 238 struct passwd *pw, char *buffer, size_t buflen, int *pwflags, 239 int version) 240 { 241 char *p, *t; 242 DBT data; 243 244 _DIAGASSERT(db != NULL); 245 _DIAGASSERT(key != NULL); 246 _DIAGASSERT(pw != NULL); 247 _DIAGASSERT(buffer != NULL); 248 /* pwflags may be NULL (if we don't care about them */ 249 250 if (db == NULL) /* this shouldn't happen */ 251 return NS_UNAVAIL; 252 253 switch ((db->get)(db, key, &data, 0)) { 254 case 0: 255 break; /* found */ 256 case 1: 257 return NS_NOTFOUND; /* not found */ 258 case -1: 259 return NS_UNAVAIL; /* error in db routines */ 260 default: 261 abort(); 262 } 263 264 p = (char *)data.data; 265 if (data.size > buflen) { 266 errno = ERANGE; 267 return NS_UNAVAIL; 268 } 269 270 /* 271 * THE DECODING BELOW MUST MATCH THAT IN pwd_mkdb. 272 */ 273 t = buffer; 274 #define MACRO(a) do { a } while (/*CONSTCOND*/0) 275 #define EXPAND(e) MACRO(e = t; while ((*t++ = *p++));) 276 #define SCALAR(v) MACRO(memmove(&(v), p, sizeof v); p += sizeof v;) 277 EXPAND(pw->pw_name); 278 EXPAND(pw->pw_passwd); 279 SCALAR(pw->pw_uid); 280 SCALAR(pw->pw_gid); 281 if (version == 0) { 282 int32_t tmp; 283 SCALAR(tmp); 284 pw->pw_change = tmp; 285 } else 286 SCALAR(pw->pw_change); 287 EXPAND(pw->pw_class); 288 EXPAND(pw->pw_gecos); 289 EXPAND(pw->pw_dir); 290 EXPAND(pw->pw_shell); 291 if (version == 0) { 292 int32_t tmp; 293 SCALAR(tmp); 294 pw->pw_expire = tmp; 295 } else 296 SCALAR(pw->pw_expire); 297 if (pwflags) { 298 /* See if there's any data left. If so, read in flags. */ 299 if (data.size > (size_t) (p - (char *)data.data)) { 300 SCALAR(*pwflags); 301 } else { /* default */ 302 *pwflags = _PASSWORD_NOUID|_PASSWORD_NOGID; 303 } 304 } 305 306 return NS_SUCCESS; 307 } 308 309 /* 310 * _pw_memfrombuf 311 * Obtain want bytes from buffer (of size buflen) and return a pointer 312 * to the available memory after adjusting buffer/buflen. 313 * Returns NULL if there is insufficient space. 314 */ 315 static char * 316 _pw_memfrombuf(size_t want, char **buffer, size_t *buflen) 317 { 318 char *rv; 319 320 if (want > *buflen) { 321 errno = ERANGE; 322 return NULL; 323 } 324 rv = *buffer; 325 *buffer += want; 326 *buflen -= want; 327 return rv; 328 } 329 330 /* 331 * _pw_copy 332 * Copy the contents of frompw to pw; memory for strings 333 * and arrays will be allocated from buf (of size buflen). 334 * If proto != NULL, use various fields in proto in preference to frompw. 335 * Returns 1 if copied successfully, 0 on copy failure. 336 * NOTE: frompw must not use buf for its own pointers. 337 */ 338 static int 339 _pw_copy(const struct passwd *frompw, struct passwd *pw, 340 char *buf, size_t buflen, const struct passwd *protopw, int protoflags) 341 { 342 size_t count; 343 int useproto; 344 345 _DIAGASSERT(frompw != NULL); 346 _DIAGASSERT(pw != NULL); 347 _DIAGASSERT(buf != NULL); 348 /* protopw may be NULL */ 349 350 useproto = protopw && protopw->pw_name; 351 352 #define COPYSTR(to, from) \ 353 do { \ 354 count = strlen((from)); \ 355 (to) = _pw_memfrombuf(count+1, &buf, &buflen); \ 356 if ((to) == NULL) \ 357 return 0; \ 358 memmove((to), (from), count); \ 359 to[count] = '\0'; \ 360 } while (0) /* LINTED */ 361 362 #define COPYFIELD(field) COPYSTR(pw->field, frompw->field) 363 364 #define COPYPROTOFIELD(field) COPYSTR(pw->field, \ 365 (useproto && *protopw->field ? protopw->field : frompw->field)) 366 367 COPYFIELD(pw_name); 368 369 #ifdef PW_OVERRIDE_PASSWD 370 COPYPROTOFIELD(pw_passwd); 371 #else 372 COPYFIELD(pw_passwd); 373 #endif 374 375 if (useproto && !(protoflags & _PASSWORD_NOUID)) 376 pw->pw_uid = protopw->pw_uid; 377 else 378 pw->pw_uid = frompw->pw_uid; 379 380 if (useproto && !(protoflags & _PASSWORD_NOGID)) 381 pw->pw_gid = protopw->pw_gid; 382 else 383 pw->pw_gid = frompw->pw_gid; 384 385 pw->pw_change = frompw->pw_change; 386 COPYFIELD(pw_class); 387 COPYPROTOFIELD(pw_gecos); 388 COPYPROTOFIELD(pw_dir); 389 COPYPROTOFIELD(pw_shell); 390 391 #undef COPYSTR 392 #undef COPYFIELD 393 #undef COPYPROTOFIELD 394 395 return 1; 396 } 397 398 399 /* 400 * files methods 401 */ 402 403 /* state shared between files methods */ 404 struct files_state { 405 int stayopen; /* see getpassent(3) */ 406 DB *db; /* passwd file handle */ 407 int keynum; /* key counter, -1 if no more */ 408 int version; 409 }; 410 411 static struct files_state _files_state; 412 /* storage for non _r functions */ 413 static struct passwd _files_passwd; 414 static char _files_passwdbuf[_GETPW_R_SIZE_MAX]; 415 416 static int 417 _files_start(struct files_state *state) 418 { 419 int rv; 420 421 _DIAGASSERT(state != NULL); 422 423 state->keynum = 0; 424 rv = _pw_opendb(&state->db, &state->version); 425 if (rv != NS_SUCCESS) 426 return rv; 427 return NS_SUCCESS; 428 } 429 430 static int 431 _files_end(struct files_state *state) 432 { 433 434 _DIAGASSERT(state != NULL); 435 436 state->keynum = 0; 437 if (state->db) { 438 (void)(state->db->close)(state->db); 439 state->db = NULL; 440 } 441 return NS_SUCCESS; 442 } 443 444 /* 445 * _files_pwscan 446 * Search state->db for the next desired entry. 447 * If search is _PW_KEYBYNUM, look for state->keynum. 448 * If search is _PW_KEYBYNAME, look for name. 449 * If search is _PW_KEYBYUID, look for uid. 450 * Sets *retval to the errno if the result is not NS_SUCCESS 451 * or NS_NOTFOUND. 452 */ 453 static int 454 _files_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 455 struct files_state *state, int search, const char *name, uid_t uid) 456 { 457 const void *from; 458 size_t fromlen; 459 DBT key; 460 int rv; 461 462 _DIAGASSERT(retval != NULL); 463 _DIAGASSERT(pw != NULL); 464 _DIAGASSERT(buffer != NULL); 465 _DIAGASSERT(state != NULL); 466 /* name is NULL to indicate searching for uid */ 467 468 *retval = 0; 469 470 if (state->db == NULL) { /* only start if file not open yet */ 471 rv = _files_start(state); 472 if (rv != NS_SUCCESS) 473 goto filespwscan_out; 474 } 475 476 for (;;) { /* search for a match */ 477 switch (search) { 478 case _PW_KEYBYNUM: 479 if (state->keynum == -1) 480 return NS_NOTFOUND; /* no more records */ 481 state->keynum++; 482 from = &state->keynum; 483 fromlen = sizeof(state->keynum); 484 break; 485 case _PW_KEYBYNAME: 486 from = name; 487 fromlen = strlen(name); 488 break; 489 case _PW_KEYBYUID: 490 from = &uid; 491 fromlen = sizeof(uid); 492 break; 493 default: 494 abort(); 495 } 496 497 if (buflen <= fromlen) { /* buffer too small */ 498 *retval = ERANGE; 499 return NS_UNAVAIL; 500 } 501 buffer[0] = search; /* setup key */ 502 memmove(buffer + 1, from, fromlen); 503 key.size = fromlen + 1; 504 key.data = (u_char *)buffer; 505 506 /* search for key */ 507 rv = _pw_getkey(state->db, &key, pw, buffer, buflen, NULL, 508 state->version); 509 if (rv != NS_SUCCESS) /* no match */ 510 break; 511 if (pw->pw_name[0] == '+' || pw->pw_name[0] == '-') { 512 /* if a compat line */ 513 if (search == _PW_KEYBYNUM) 514 continue; /* read next if pwent */ 515 rv = NS_NOTFOUND; /* don't match if pw{nam,uid} */ 516 break; 517 } 518 break; 519 } 520 521 if (rv == NS_NOTFOUND && search == _PW_KEYBYNUM) 522 state->keynum = -1; /* flag `no more records' */ 523 524 if (rv == NS_SUCCESS) { 525 if ((search == _PW_KEYBYUID && pw->pw_uid != uid) || 526 (search == _PW_KEYBYNAME && strcmp(pw->pw_name, name) != 0)) 527 rv = NS_NOTFOUND; 528 } 529 530 filespwscan_out: 531 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 532 *retval = errno; 533 return rv; 534 } 535 536 /*ARGSUSED*/ 537 static int 538 _files_setpwent(void *nsrv, void *nscb, va_list ap) 539 { 540 541 _files_state.stayopen = 0; 542 return _files_start(&_files_state); 543 } 544 545 /*ARGSUSED*/ 546 static int 547 _files_setpassent(void *nsrv, void *nscb, va_list ap) 548 { 549 int *retval = va_arg(ap, int *); 550 int stayopen = va_arg(ap, int); 551 552 int rv; 553 554 _files_state.stayopen = stayopen; 555 rv = _files_start(&_files_state); 556 *retval = (rv == NS_SUCCESS); 557 return rv; 558 } 559 560 /*ARGSUSED*/ 561 static int 562 _files_endpwent(void *nsrv, void *nscb, va_list ap) 563 { 564 565 _files_state.stayopen = 0; 566 return _files_end(&_files_state); 567 } 568 569 /*ARGSUSED*/ 570 static int 571 _files_getpwent(void *nsrv, void *nscb, va_list ap) 572 { 573 struct passwd **retval = va_arg(ap, struct passwd **); 574 575 int rv, rerror; 576 577 _DIAGASSERT(retval != NULL); 578 579 *retval = NULL; 580 rv = _files_pwscan(&rerror, &_files_passwd, 581 _files_passwdbuf, sizeof(_files_passwdbuf), 582 &_files_state, _PW_KEYBYNUM, NULL, 0); 583 if (rv == NS_SUCCESS) 584 *retval = &_files_passwd; 585 return rv; 586 } 587 588 /*ARGSUSED*/ 589 static int 590 _files_getpwent_r(void *nsrv, void *nscb, va_list ap) 591 { 592 int *retval = va_arg(ap, int *); 593 struct passwd *pw = va_arg(ap, struct passwd *); 594 char *buffer = va_arg(ap, char *); 595 size_t buflen = va_arg(ap, size_t); 596 struct passwd **result = va_arg(ap, struct passwd **); 597 598 int rv; 599 600 _DIAGASSERT(retval != NULL); 601 _DIAGASSERT(pw != NULL); 602 _DIAGASSERT(buffer != NULL); 603 _DIAGASSERT(result != NULL); 604 605 rv = _files_pwscan(retval, pw, buffer, buflen, &_files_state, 606 _PW_KEYBYNUM, NULL, 0); 607 if (rv == NS_SUCCESS) 608 *result = pw; 609 else 610 *result = NULL; 611 return rv; 612 } 613 614 /*ARGSUSED*/ 615 static int 616 _files_getpwnam(void *nsrv, void *nscb, va_list ap) 617 { 618 struct passwd **retval = va_arg(ap, struct passwd **); 619 const char *name = va_arg(ap, const char *); 620 621 int rv, rerror; 622 623 _DIAGASSERT(retval != NULL); 624 625 *retval = NULL; 626 rv = _files_start(&_files_state); 627 if (rv != NS_SUCCESS) 628 return rv; 629 rv = _files_pwscan(&rerror, &_files_passwd, 630 _files_passwdbuf, sizeof(_files_passwdbuf), 631 &_files_state, _PW_KEYBYNAME, name, 0); 632 if (!_files_state.stayopen) 633 _files_end(&_files_state); 634 if (rv == NS_SUCCESS) 635 *retval = &_files_passwd; 636 return rv; 637 } 638 639 /*ARGSUSED*/ 640 static int 641 _files_getpwnam_r(void *nsrv, void *nscb, va_list ap) 642 { 643 int *retval = va_arg(ap, int *); 644 const char *name = va_arg(ap, const char *); 645 struct passwd *pw = va_arg(ap, struct passwd *); 646 char *buffer = va_arg(ap, char *); 647 size_t buflen = va_arg(ap, size_t); 648 struct passwd **result = va_arg(ap, struct passwd **); 649 650 struct files_state state; 651 int rv; 652 653 _DIAGASSERT(retval != NULL); 654 _DIAGASSERT(pw != NULL); 655 _DIAGASSERT(buffer != NULL); 656 _DIAGASSERT(result != NULL); 657 658 *result = NULL; 659 memset(&state, 0, sizeof(state)); 660 rv = _files_pwscan(retval, pw, buffer, buflen, &state, 661 _PW_KEYBYNAME, name, 0); 662 _files_end(&state); 663 if (rv == NS_SUCCESS) 664 *result = pw; 665 return rv; 666 } 667 668 /*ARGSUSED*/ 669 static int 670 _files_getpwuid(void *nsrv, void *nscb, va_list ap) 671 { 672 struct passwd **retval = va_arg(ap, struct passwd **); 673 uid_t uid = va_arg(ap, uid_t); 674 675 int rv, rerror; 676 677 _DIAGASSERT(retval != NULL); 678 679 *retval = NULL; 680 rv = _files_start(&_files_state); 681 if (rv != NS_SUCCESS) 682 return rv; 683 rv = _files_pwscan(&rerror, &_files_passwd, 684 _files_passwdbuf, sizeof(_files_passwdbuf), 685 &_files_state, _PW_KEYBYUID, NULL, uid); 686 if (!_files_state.stayopen) 687 _files_end(&_files_state); 688 if (rv == NS_SUCCESS) 689 *retval = &_files_passwd; 690 return rv; 691 } 692 693 /*ARGSUSED*/ 694 static int 695 _files_getpwuid_r(void *nsrv, void *nscb, va_list ap) 696 { 697 int *retval = va_arg(ap, int *); 698 uid_t uid = va_arg(ap, uid_t); 699 struct passwd *pw = va_arg(ap, struct passwd *); 700 char *buffer = va_arg(ap, char *); 701 size_t buflen = va_arg(ap, size_t); 702 struct passwd **result = va_arg(ap, struct passwd **); 703 704 struct files_state state; 705 int rv; 706 707 _DIAGASSERT(retval != NULL); 708 _DIAGASSERT(pw != NULL); 709 _DIAGASSERT(buffer != NULL); 710 _DIAGASSERT(result != NULL); 711 712 *result = NULL; 713 memset(&state, 0, sizeof(state)); 714 rv = _files_pwscan(retval, pw, buffer, buflen, &state, 715 _PW_KEYBYUID, NULL, uid); 716 _files_end(&state); 717 if (rv == NS_SUCCESS) 718 *result = pw; 719 return rv; 720 } 721 722 723 #ifdef HESIOD 724 /* 725 * dns methods 726 */ 727 728 /* state shared between dns methods */ 729 struct dns_state { 730 int stayopen; /* see getpassent(3) */ 731 void *context; /* Hesiod context */ 732 int num; /* passwd index, -1 if no more */ 733 }; 734 735 static struct dns_state _dns_state; 736 /* storage for non _r functions */ 737 static struct passwd _dns_passwd; 738 static char _dns_passwdbuf[_GETPW_R_SIZE_MAX]; 739 740 static int 741 _dns_start(struct dns_state *state) 742 { 743 744 _DIAGASSERT(state != NULL); 745 746 state->num = 0; 747 if (state->context == NULL) { /* setup Hesiod */ 748 if (hesiod_init(&state->context) == -1) 749 return NS_UNAVAIL; 750 } 751 752 return NS_SUCCESS; 753 } 754 755 static int 756 _dns_end(struct dns_state *state) 757 { 758 759 _DIAGASSERT(state != NULL); 760 761 state->num = 0; 762 if (state->context) { 763 hesiod_end(state->context); 764 state->context = NULL; 765 } 766 return NS_SUCCESS; 767 } 768 769 /* 770 * _dns_pwscan 771 * Look for the Hesiod name provided in buffer in the NULL-terminated 772 * list of zones, 773 * and decode into pw/buffer/buflen. 774 */ 775 static int 776 _dns_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 777 struct dns_state *state, const char **zones) 778 { 779 const char **curzone; 780 char **hp, *ep; 781 int rv; 782 783 _DIAGASSERT(retval != NULL); 784 _DIAGASSERT(pw != NULL); 785 _DIAGASSERT(buffer != NULL); 786 _DIAGASSERT(state != NULL); 787 _DIAGASSERT(zones != NULL); 788 789 *retval = 0; 790 791 if (state->context == NULL) { /* only start if Hesiod not setup */ 792 rv = _dns_start(state); 793 if (rv != NS_SUCCESS) 794 return rv; 795 } 796 797 hp = NULL; 798 rv = NS_NOTFOUND; 799 800 for (curzone = zones; *curzone; curzone++) { /* search zones */ 801 hp = hesiod_resolve(state->context, buffer, *curzone); 802 if (hp != NULL) 803 break; 804 if (errno != ENOENT) { 805 rv = NS_UNAVAIL; 806 goto dnspwscan_out; 807 } 808 } 809 if (*curzone == NULL) 810 goto dnspwscan_out; 811 812 if ((ep = strchr(hp[0], '\n')) != NULL) 813 *ep = '\0'; /* clear trailing \n */ 814 if (_pw_parse(hp[0], pw, buffer, buflen, 1)) /* validate line */ 815 rv = NS_SUCCESS; 816 else 817 rv = NS_UNAVAIL; 818 819 dnspwscan_out: 820 if (rv != NS_SUCCESS && rv != NS_NOTFOUND) 821 *retval = errno; 822 if (hp) 823 hesiod_free_list(state->context, hp); 824 return rv; 825 } 826 827 /*ARGSUSED*/ 828 static int 829 _dns_setpwent(void *nsrv, void *nscb, va_list ap) 830 { 831 832 _dns_state.stayopen = 0; 833 return _dns_start(&_dns_state); 834 } 835 836 /*ARGSUSED*/ 837 static int 838 _dns_setpassent(void *nsrv, void *nscb, va_list ap) 839 { 840 int *retval = va_arg(ap, int *); 841 int stayopen = va_arg(ap, int); 842 843 int rv; 844 845 _dns_state.stayopen = stayopen; 846 rv = _dns_start(&_dns_state); 847 *retval = (rv == NS_SUCCESS); 848 return rv; 849 } 850 851 /*ARGSUSED*/ 852 static int 853 _dns_endpwent(void *nsrv, void *nscb, va_list ap) 854 { 855 856 _dns_state.stayopen = 0; 857 return _dns_end(&_dns_state); 858 } 859 860 /*ARGSUSED*/ 861 static int 862 _dns_getpwent(void *nsrv, void *nscb, va_list ap) 863 { 864 struct passwd **retval = va_arg(ap, struct passwd **); 865 866 char **hp, *ep; 867 int rv; 868 869 _DIAGASSERT(retval != NULL); 870 871 *retval = NULL; 872 873 if (_dns_state.num == -1) /* exhausted search */ 874 return NS_NOTFOUND; 875 876 if (_dns_state.context == NULL) { 877 /* only start if Hesiod not setup */ 878 rv = _dns_start(&_dns_state); 879 if (rv != NS_SUCCESS) 880 return rv; 881 } 882 883 next_dns_entry: 884 hp = NULL; 885 rv = NS_NOTFOUND; 886 887 /* find passwd-NNN */ 888 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), 889 "passwd-%u", _dns_state.num); 890 _dns_state.num++; 891 892 hp = hesiod_resolve(_dns_state.context, _dns_passwdbuf, "passwd"); 893 if (hp == NULL) { 894 if (errno == ENOENT) 895 _dns_state.num = -1; 896 else 897 rv = NS_UNAVAIL; 898 } else { 899 if ((ep = strchr(hp[0], '\n')) != NULL) 900 *ep = '\0'; /* clear trailing \n */ 901 /* validate line */ 902 if (_pw_parse(hp[0], &_dns_passwd, 903 _dns_passwdbuf, sizeof(_dns_passwdbuf), 1)) 904 rv = NS_SUCCESS; 905 else { /* dodgy entry, try again */ 906 hesiod_free_list(_dns_state.context, hp); 907 goto next_dns_entry; 908 } 909 } 910 911 if (hp) 912 hesiod_free_list(_dns_state.context, hp); 913 if (rv == NS_SUCCESS) 914 *retval = &_dns_passwd; 915 return rv; 916 } 917 918 /*ARGSUSED*/ 919 static int 920 _dns_getpwent_r(void *nsrv, void *nscb, va_list ap) 921 { 922 int *retval = va_arg(ap, int *); 923 struct passwd *pw = va_arg(ap, struct passwd *); 924 char *buffer = va_arg(ap, char *); 925 size_t buflen = va_arg(ap, size_t); 926 struct passwd **result = va_arg(ap, struct passwd **); 927 928 char **hp, *ep; 929 int rv; 930 931 _DIAGASSERT(retval != NULL); 932 _DIAGASSERT(pw != NULL); 933 _DIAGASSERT(buffer != NULL); 934 _DIAGASSERT(result != NULL); 935 936 *retval = 0; 937 938 if (_dns_state.num == -1) /* exhausted search */ 939 return NS_NOTFOUND; 940 941 if (_dns_state.context == NULL) { 942 /* only start if Hesiod not setup */ 943 rv = _dns_start(&_dns_state); 944 if (rv != NS_SUCCESS) 945 return rv; 946 } 947 948 next_dns_entry: 949 hp = NULL; 950 rv = NS_NOTFOUND; 951 952 /* find passwd-NNN */ 953 snprintf(buffer, buflen, "passwd-%u", _dns_state.num); 954 _dns_state.num++; 955 956 hp = hesiod_resolve(_dns_state.context, buffer, "passwd"); 957 if (hp == NULL) { 958 if (errno == ENOENT) 959 _dns_state.num = -1; 960 else 961 rv = NS_UNAVAIL; 962 } else { 963 if ((ep = strchr(hp[0], '\n')) != NULL) 964 *ep = '\0'; /* clear trailing \n */ 965 /* validate line */ 966 if (_pw_parse(hp[0], pw, buffer, buflen, 1)) 967 rv = NS_SUCCESS; 968 else { /* dodgy entry, try again */ 969 hesiod_free_list(_dns_state.context, hp); 970 goto next_dns_entry; 971 } 972 } 973 974 if (hp) 975 hesiod_free_list(_dns_state.context, hp); 976 if (rv == NS_SUCCESS) 977 *result = pw; 978 else 979 *result = NULL; 980 return rv; 981 } 982 983 static const char *_dns_uid_zones[] = { 984 "uid", 985 "passwd", 986 NULL 987 }; 988 989 /*ARGSUSED*/ 990 static int 991 _dns_getpwuid(void *nsrv, void *nscb, va_list ap) 992 { 993 struct passwd **retval = va_arg(ap, struct passwd **); 994 uid_t uid = va_arg(ap, uid_t); 995 996 int rv, rerror; 997 998 _DIAGASSERT(retval != NULL); 999 1000 *retval = NULL; 1001 rv = _dns_start(&_dns_state); 1002 if (rv != NS_SUCCESS) 1003 return rv; 1004 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), 1005 "%u", (unsigned int)uid); 1006 rv = _dns_pwscan(&rerror, &_dns_passwd, 1007 _dns_passwdbuf, sizeof(_dns_passwdbuf), 1008 &_dns_state, _dns_uid_zones); 1009 if (!_dns_state.stayopen) 1010 _dns_end(&_dns_state); 1011 if (rv == NS_SUCCESS && uid == _dns_passwd.pw_uid) 1012 *retval = &_dns_passwd; 1013 return rv; 1014 } 1015 1016 /*ARGSUSED*/ 1017 static int 1018 _dns_getpwuid_r(void *nsrv, void *nscb, va_list ap) 1019 { 1020 int *retval = va_arg(ap, int *); 1021 uid_t uid = va_arg(ap, uid_t); 1022 struct passwd *pw = va_arg(ap, struct passwd *); 1023 char *buffer = va_arg(ap, char *); 1024 size_t buflen = va_arg(ap, size_t); 1025 struct passwd **result = va_arg(ap, struct passwd **); 1026 1027 struct dns_state state; 1028 int rv; 1029 1030 _DIAGASSERT(retval != NULL); 1031 _DIAGASSERT(pw != NULL); 1032 _DIAGASSERT(buffer != NULL); 1033 _DIAGASSERT(result != NULL); 1034 1035 *result = NULL; 1036 memset(&state, 0, sizeof(state)); 1037 snprintf(buffer, buflen, "%u", (unsigned int)uid); 1038 rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_uid_zones); 1039 _dns_end(&state); 1040 if (rv != NS_SUCCESS) 1041 return rv; 1042 if (uid == pw->pw_uid) { 1043 *result = pw; 1044 return NS_SUCCESS; 1045 } else 1046 return NS_NOTFOUND; 1047 } 1048 1049 static const char *_dns_nam_zones[] = { 1050 "passwd", 1051 NULL 1052 }; 1053 1054 /*ARGSUSED*/ 1055 static int 1056 _dns_getpwnam(void *nsrv, void *nscb, va_list ap) 1057 { 1058 struct passwd **retval = va_arg(ap, struct passwd **); 1059 const char *name = va_arg(ap, const char *); 1060 1061 int rv, rerror; 1062 1063 _DIAGASSERT(retval != NULL); 1064 1065 *retval = NULL; 1066 rv = _dns_start(&_dns_state); 1067 if (rv != NS_SUCCESS) 1068 return rv; 1069 snprintf(_dns_passwdbuf, sizeof(_dns_passwdbuf), "%s", name); 1070 rv = _dns_pwscan(&rerror, &_dns_passwd, 1071 _dns_passwdbuf, sizeof(_dns_passwdbuf), 1072 &_dns_state, _dns_nam_zones); 1073 if (!_dns_state.stayopen) 1074 _dns_end(&_dns_state); 1075 if (rv == NS_SUCCESS && strcmp(name, _dns_passwd.pw_name) == 0) 1076 *retval = &_dns_passwd; 1077 return rv; 1078 } 1079 1080 /*ARGSUSED*/ 1081 static int 1082 _dns_getpwnam_r(void *nsrv, void *nscb, va_list ap) 1083 { 1084 int *retval = va_arg(ap, int *); 1085 const char *name = va_arg(ap, const char *); 1086 struct passwd *pw = va_arg(ap, struct passwd *); 1087 char *buffer = va_arg(ap, char *); 1088 size_t buflen = va_arg(ap, size_t); 1089 struct passwd **result = va_arg(ap, struct passwd **); 1090 1091 struct dns_state state; 1092 int rv; 1093 1094 _DIAGASSERT(retval != NULL); 1095 _DIAGASSERT(pw != NULL); 1096 _DIAGASSERT(buffer != NULL); 1097 _DIAGASSERT(result != NULL); 1098 1099 *result = NULL; 1100 memset(&state, 0, sizeof(state)); 1101 snprintf(buffer, buflen, "%s", name); 1102 rv = _dns_pwscan(retval, pw, buffer, buflen, &state, _dns_nam_zones); 1103 _dns_end(&state); 1104 if (rv != NS_SUCCESS) 1105 return rv; 1106 if (strcmp(name, pw->pw_name) == 0) { 1107 *result = pw; 1108 return NS_SUCCESS; 1109 } else 1110 return NS_NOTFOUND; 1111 } 1112 1113 #endif /* HESIOD */ 1114 1115 1116 #ifdef YP 1117 /* 1118 * nis methods 1119 */ 1120 /* state shared between nis methods */ 1121 struct nis_state { 1122 int stayopen; /* see getpassent(3) */ 1123 char *domain; /* NIS domain */ 1124 int done; /* non-zero if search exhausted */ 1125 char *current; /* current first/next match */ 1126 int currentlen; /* length of _nis_current */ 1127 enum { /* shadow map type */ 1128 NISMAP_UNKNOWN = 0, /* unknown ... */ 1129 NISMAP_NONE, /* none: use "passwd.by*" */ 1130 NISMAP_ADJUNCT, /* pw_passwd from "passwd.adjunct.*" */ 1131 NISMAP_MASTER /* all from "master.passwd.by*" */ 1132 } maptype; 1133 }; 1134 1135 static struct nis_state _nis_state; 1136 /* storage for non _r functions */ 1137 static struct passwd _nis_passwd; 1138 static char _nis_passwdbuf[_GETPW_R_SIZE_MAX]; 1139 1140 static const char __nis_pw_n_1[] = "master.passwd.byname"; 1141 static const char __nis_pw_n_2[] = "passwd.byname"; 1142 static const char __nis_pw_u_1[] = "master.passwd.byuid"; 1143 static const char __nis_pw_u_2[] = "passwd.byuid"; 1144 1145 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 }; 1146 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 }; 1147 1148 /* macros for deciding which NIS maps to use. */ 1149 #define PASSWD_BYNAME(x) ((x)->maptype == NISMAP_MASTER ? __nis_pw_n_1 : __nis_pw_n_2) 1150 #define PASSWD_BYUID(x) ((x)->maptype == NISMAP_MASTER ? __nis_pw_u_1 : __nis_pw_u_2) 1151 1152 static int 1153 _nis_start(struct nis_state *state) 1154 { 1155 1156 _DIAGASSERT(state != NULL); 1157 1158 state->done = 0; 1159 if (state->current) { 1160 free(state->current); 1161 state->current = NULL; 1162 } 1163 if (state->domain == NULL) { /* setup NIS */ 1164 switch (yp_get_default_domain(&state->domain)) { 1165 case 0: 1166 break; 1167 case YPERR_RESRC: 1168 return NS_TRYAGAIN; 1169 default: 1170 return NS_UNAVAIL; 1171 } 1172 } 1173 1174 /* determine where to get pw_passwd from */ 1175 if (state->maptype == NISMAP_UNKNOWN) { 1176 int r, order; 1177 1178 state->maptype = NISMAP_NONE; /* default to no adjunct */ 1179 if (geteuid() != 0) /* non-root can't use adjunct */ 1180 return NS_SUCCESS; 1181 1182 /* look for "master.passwd.*" */ 1183 r = yp_order(state->domain, "master.passwd.byname", &order); 1184 if (r == 0) { 1185 state->maptype = NISMAP_MASTER; 1186 return NS_SUCCESS; 1187 } 1188 1189 /* master.passwd doesn't exist, try passwd.adjunct */ 1190 if (r == YPERR_MAP) { 1191 r = yp_order(state->domain, "passwd.adjunct.byname", 1192 &order); 1193 if (r == 0) 1194 state->maptype = NISMAP_ADJUNCT; 1195 } 1196 } 1197 return NS_SUCCESS; 1198 } 1199 1200 static int 1201 _nis_end(struct nis_state *state) 1202 { 1203 1204 _DIAGASSERT(state != NULL); 1205 1206 if (state->domain) 1207 state->domain = NULL; 1208 state->done = 0; 1209 if (state->current) 1210 free(state->current); 1211 state->current = NULL; 1212 state->maptype = NISMAP_UNKNOWN; 1213 return NS_SUCCESS; 1214 } 1215 1216 /* 1217 * nis_parse 1218 * wrapper to _pw_parse that obtains the real password from the 1219 * "passwd.adjunct.byname" NIS map if the maptype is NISMAP_ADJUNCT. 1220 */ 1221 static int 1222 _nis_parse(const char *entry, struct passwd *pw, char *buf, size_t buflen, 1223 struct nis_state *state) 1224 { 1225 size_t elen; 1226 1227 _DIAGASSERT(entry != NULL); 1228 _DIAGASSERT(pw != NULL); 1229 _DIAGASSERT(buf != NULL); 1230 _DIAGASSERT(state != NULL); 1231 1232 elen = strlen(entry) + 1; 1233 if (elen >= buflen) 1234 return 0; 1235 if (! _pw_parse(entry, pw, buf, buflen, 1236 !(state->maptype == NISMAP_MASTER))) 1237 return 0; 1238 1239 if ((state->maptype == NISMAP_ADJUNCT) && 1240 (strstr(pw->pw_passwd, "##") != NULL)) { 1241 char *data; 1242 int datalen; 1243 1244 if (yp_match(state->domain, "passwd.adjunct.byname", 1245 pw->pw_name, (int)strlen(pw->pw_name), 1246 &data, &datalen) == 0) { 1247 char *bp, *ep; 1248 /* skip name to get password */ 1249 ep = data; 1250 if (strsep(&ep, ":") != NULL && 1251 (bp = strsep(&ep, ":")) != NULL) { 1252 /* store new pw_passwd after entry */ 1253 if (strlcpy(buf + elen, bp, buflen - elen) >= 1254 buflen - elen) { 1255 free(data); 1256 return 0; 1257 } 1258 pw->pw_passwd = &buf[elen]; 1259 } 1260 free(data); 1261 } 1262 } 1263 1264 return 1; 1265 } 1266 1267 1268 /* 1269 * _nis_pwscan 1270 * Look for the yp key provided in buffer from map, 1271 * and decode into pw/buffer/buflen. 1272 */ 1273 static int 1274 _nis_pwscan(int *retval, struct passwd *pw, char *buffer, size_t buflen, 1275 struct nis_state *state, const char * const *map_arr, size_t nmaps) 1276 { 1277 char *data; 1278 int nisr, rv, datalen; 1279 1280 _DIAGASSERT(retval != NULL); 1281 _DIAGASSERT(pw != NULL); 1282 _DIAGASSERT(buffer != NULL); 1283 _DIAGASSERT(state != NULL); 1284 _DIAGASSERT(map_arr != NULL); 1285 1286 *retval = 0; 1287 1288 if (state->domain == NULL) { /* only start if NIS not setup */ 1289 rv = _nis_start(state); 1290 if (rv != NS_SUCCESS) 1291 return rv; 1292 } 1293 1294 data = NULL; 1295 rv = NS_NOTFOUND; 1296 _DIAGASSERT(state->maptype != NISMAP_UNKNOWN && 1297 (unsigned)state->maptype < nmaps); 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, __arraycount(__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, __arraycount(__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, __arraycount(__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, __arraycount(__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, __arraycount(__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, __arraycount(__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