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