1 /* 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)getpwent.c 8.2 (Berkeley) 4/27/95 34 * $FreeBSD: src/lib/libc/gen/getpwent.c,v 1.53.2.2 2001/03/05 09:52:13 obrien Exp $ 35 * $DragonFly: src/lib/libc/gen/getpwent.c,v 1.5 2005/01/31 22:29:15 dillon Exp $ 36 */ 37 38 #include "namespace.h" 39 #include <stdio.h> 40 #include <sys/param.h> 41 #include <fcntl.h> 42 #include <syslog.h> 43 #include <pwd.h> 44 #include <utmp.h> 45 #include <errno.h> 46 #include <unistd.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <limits.h> 50 #include <grp.h> 51 #include "un-namespace.h" 52 53 #include <db.h> 54 55 extern void setnetgrent ( char * ); 56 extern int getnetgrent ( char **, char **, char ** ); 57 extern int innetgr ( const char *, const char *, const char *, const char * ); 58 59 /* 60 * The lookup techniques and data extraction code here must be kept 61 * in sync with that in `pwd_mkdb'. 62 */ 63 64 static struct passwd _pw_passwd; /* password structure */ 65 static DB *_pw_db; /* password database */ 66 static int _pw_keynum; /* key counter */ 67 static int _pw_stayopen; /* keep fd's open */ 68 #ifdef YP 69 #include <rpc/rpc.h> 70 #include <rpcsvc/yp_prot.h> 71 #include <rpcsvc/ypclnt.h> 72 73 static struct passwd _pw_copy; 74 static DBT empty = { NULL, 0 }; 75 static DB *_ypcache = (DB *)NULL; 76 static int _yp_exclusions = 0; 77 static int _yp_enabled = -1; 78 static int _pw_stepping_yp; /* set true when stepping thru map */ 79 static char _ypnam[YPMAXRECORD]; 80 #define YP_HAVE_MASTER 2 81 #define YP_HAVE_ADJUNCT 1 82 #define YP_HAVE_NONE 0 83 static int _gotmaster; 84 static char *_pw_yp_domain; 85 static inline int unwind ( char * ); 86 static void _ypinitdb ( void ); 87 static int _havemaster (char *); 88 static int _getyppass (struct passwd *, const char *, const char * ); 89 static int _nextyppass (struct passwd *); 90 static inline int lookup (const char *); 91 static inline void store (const char *); 92 static inline int ingr (const char *, const char*); 93 static inline int verf (const char *); 94 static char * _get_adjunct_pw (const char *); 95 #endif 96 static int __hashpw(DBT *); 97 static int __initdb(void); 98 99 struct passwd * 100 getpwent() 101 { 102 DBT key; 103 char bf[sizeof(_pw_keynum) + 1]; 104 int rv; 105 106 if (!_pw_db && !__initdb()) 107 return((struct passwd *)NULL); 108 109 #ifdef YP 110 if(_pw_stepping_yp) { 111 _pw_passwd = _pw_copy; 112 if (unwind((char *)&_ypnam)) 113 return(&_pw_passwd); 114 } 115 #endif 116 tryagain: 117 118 ++_pw_keynum; 119 bf[0] = _PW_KEYBYNUM; 120 bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum)); 121 key.data = (u_char *)bf; 122 key.size = sizeof(_pw_keynum) + 1; 123 rv = __hashpw(&key); 124 if(!rv) return (struct passwd *)NULL; 125 #ifdef YP 126 if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') { 127 if (_yp_enabled == -1) 128 _ypinitdb(); 129 bzero((char *)&_ypnam, sizeof(_ypnam)); 130 bcopy(_pw_passwd.pw_name, _ypnam, 131 strlen(_pw_passwd.pw_name)); 132 _pw_copy = _pw_passwd; 133 if (unwind((char *)&_ypnam) == 0) 134 goto tryagain; 135 else 136 return(&_pw_passwd); 137 } 138 #else 139 /* Ignore YP password file entries when YP is disabled. */ 140 if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') { 141 goto tryagain; 142 } 143 #endif 144 return(&_pw_passwd); 145 } 146 147 struct passwd * 148 getpwnam(name) 149 const char *name; 150 { 151 DBT key; 152 int len, rval; 153 char bf[UT_NAMESIZE + 2]; 154 155 if (!_pw_db && !__initdb()) 156 return((struct passwd *)NULL); 157 158 bf[0] = _PW_KEYBYNAME; 159 len = strlen(name); 160 if (len > UT_NAMESIZE) 161 return(NULL); 162 bcopy(name, bf + 1, len); 163 key.data = (u_char *)bf; 164 key.size = len + 1; 165 rval = __hashpw(&key); 166 167 #ifdef YP 168 if (!rval) { 169 if (_yp_enabled == -1) 170 _ypinitdb(); 171 if (_yp_enabled) 172 rval = _getyppass(&_pw_passwd, name, "passwd.byname"); 173 } 174 #endif 175 /* 176 * Prevent login attempts when YP is not enabled but YP entries 177 * are in /etc/master.passwd. 178 */ 179 if (rval && (_pw_passwd.pw_name[0] == '+'|| 180 _pw_passwd.pw_name[0] == '-')) rval = 0; 181 182 if (!_pw_stayopen) 183 endpwent(); 184 return(rval ? &_pw_passwd : (struct passwd *)NULL); 185 } 186 187 struct passwd * 188 getpwuid(uid) 189 uid_t uid; 190 { 191 DBT key; 192 int keyuid, rval; 193 char bf[sizeof(keyuid) + 1]; 194 195 if (!_pw_db && !__initdb()) 196 return((struct passwd *)NULL); 197 198 bf[0] = _PW_KEYBYUID; 199 keyuid = uid; 200 bcopy(&keyuid, bf + 1, sizeof(keyuid)); 201 key.data = (u_char *)bf; 202 key.size = sizeof(keyuid) + 1; 203 rval = __hashpw(&key); 204 205 #ifdef YP 206 if (!rval) { 207 if (_yp_enabled == -1) 208 _ypinitdb(); 209 if (_yp_enabled) { 210 char ypbuf[16]; /* big enough for 32-bit uids */ 211 snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid); 212 rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid"); 213 } 214 } 215 #endif 216 /* 217 * Prevent login attempts when YP is not enabled but YP entries 218 * are in /etc/master.passwd. 219 */ 220 if (rval && (_pw_passwd.pw_name[0] == '+'|| 221 _pw_passwd.pw_name[0] == '-')) rval = 0; 222 223 if (!_pw_stayopen) 224 endpwent(); 225 return(rval ? &_pw_passwd : (struct passwd *)NULL); 226 } 227 228 int 229 setpassent(stayopen) 230 int stayopen; 231 { 232 _pw_keynum = 0; 233 #ifdef YP 234 _pw_stepping_yp = 0; 235 if (stayopen) 236 setgroupent(1); 237 #endif 238 _pw_stayopen = stayopen; 239 return(1); 240 } 241 242 void 243 setpwent() 244 { 245 (void)setpassent(0); 246 } 247 248 void 249 endpwent() 250 { 251 _pw_keynum = 0; 252 #ifdef YP 253 _pw_stepping_yp = 0; 254 #endif 255 if (_pw_db) { 256 (void)(_pw_db->close)(_pw_db); 257 _pw_db = (DB *)NULL; 258 } 259 #ifdef YP 260 if (_ypcache) { 261 (void)(_ypcache->close)(_ypcache); 262 _ypcache = (DB *)NULL; 263 _yp_exclusions = 0; 264 } 265 /* Fix for PR #12008 */ 266 _yp_enabled = -1; 267 #endif 268 } 269 270 static int 271 __initdb() 272 { 273 static int warned; 274 char *p; 275 276 p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB; 277 _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL); 278 if (_pw_db) 279 return(1); 280 if (!warned++) 281 syslog(LOG_ERR, "%s: %m", p); 282 return(0); 283 } 284 285 static int 286 __hashpw(key) 287 DBT *key; 288 { 289 char *p, *t; 290 static u_int max; 291 static char *line; 292 DBT data; 293 294 if ((_pw_db->get)(_pw_db, key, &data, 0)) 295 return(0); 296 p = (char *)data.data; 297 298 /* Increase buffer size for long lines if necessary. */ 299 if (data.size > max) { 300 max = data.size + 1024; 301 if (!(line = reallocf(line, max))) 302 return(0); 303 } 304 305 /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ 306 t = line; 307 #define EXPAND(e) e = t; while ( (*t++ = *p++) ); 308 #define SCALAR(v) memmove(&(v), p, sizeof v); p += sizeof v 309 EXPAND(_pw_passwd.pw_name); 310 EXPAND(_pw_passwd.pw_passwd); 311 SCALAR(_pw_passwd.pw_uid); 312 SCALAR(_pw_passwd.pw_gid); 313 SCALAR(_pw_passwd.pw_change); 314 EXPAND(_pw_passwd.pw_class); 315 EXPAND(_pw_passwd.pw_gecos); 316 EXPAND(_pw_passwd.pw_dir); 317 EXPAND(_pw_passwd.pw_shell); 318 SCALAR(_pw_passwd.pw_expire); 319 bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields); 320 p += sizeof _pw_passwd.pw_fields; 321 return(1); 322 } 323 324 #ifdef YP 325 326 static void 327 _ypinitdb() 328 { 329 DBT key, data; 330 char buf[] = { _PW_KEYYPENABLED }; 331 key.data = buf; 332 key.size = 1; 333 _yp_enabled = 0; 334 if ((_pw_db->get)(_pw_db, &key, &data, 0) == 0) { 335 _yp_enabled = (int)*((char *)data.data) - 2; 336 /* Don't even bother with this if we aren't root. */ 337 if (!geteuid()) { 338 if (!_pw_yp_domain) 339 if (yp_get_default_domain(&_pw_yp_domain)) 340 return; 341 _gotmaster = _havemaster(_pw_yp_domain); 342 } else _gotmaster = YP_HAVE_NONE; 343 /* 344 * Create a DB hash database in memory. Bet you didn't know you 345 * could do a dbopen() with a NULL filename, did you. 346 */ 347 if (_ypcache == (DB *)NULL) 348 _ypcache = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL); 349 } 350 } 351 352 /* 353 * See if a user is in the blackballed list. 354 */ 355 static inline int 356 lookup(name) 357 const char *name; 358 { 359 DBT key; 360 361 if (!_yp_exclusions) 362 return(0); 363 364 key.data = (char *)name; 365 key.size = strlen(name); 366 367 if ((_ypcache->get)(_ypcache, &key, &empty, 0)) { 368 return(0); 369 } 370 371 return(1); 372 } 373 374 /* 375 * Store a blackballed user in an in-core hash database. 376 */ 377 static inline void 378 store(key) 379 const char *key; 380 { 381 DBT lkey; 382 /* 383 if (lookup(key)) 384 return; 385 */ 386 387 _yp_exclusions = 1; 388 389 lkey.data = (char *)key; 390 lkey.size = strlen(key); 391 392 (void)(_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE); 393 } 394 395 /* 396 * Parse the + entries in the password database and do appropriate 397 * NIS lookups. While ugly to look at, this is optimized to do only 398 * as many lookups as are absolutely necessary in any given case. 399 * Basically, the getpwent() function will feed us + and - lines 400 * as they appear in the database. For + lines, we do netgroup/group 401 * and user lookups to find all usernames that match the rule and 402 * extract them from the NIS passwd maps. For - lines, we save the 403 * matching names in a database and a) exlude them, and b) make sure 404 * we don't consider them when processing other + lines that appear 405 * later. 406 */ 407 static inline int 408 unwind(grp) 409 char *grp; 410 { 411 char *user, *host, *domain; 412 static int latch = 0; 413 static struct group *gr = NULL; 414 int rv = 0; 415 416 if (grp[0] == '+') { 417 if (strlen(grp) == 1) { 418 return(_nextyppass(&_pw_passwd)); 419 } 420 if (grp[1] == '@') { 421 _pw_stepping_yp = 1; 422 grpagain: 423 if (gr != NULL) { 424 if (*gr->gr_mem != NULL) { 425 if (lookup(*gr->gr_mem)) { 426 gr->gr_mem++; 427 goto grpagain; 428 } 429 rv = _getyppass(&_pw_passwd, 430 *gr->gr_mem, 431 "passwd.byname"); 432 gr->gr_mem++; 433 return(rv); 434 } else { 435 latch = 0; 436 _pw_stepping_yp = 0; 437 gr = NULL; 438 return(0); 439 } 440 } 441 if (!latch) { 442 setnetgrent(grp+2); 443 latch++; 444 } 445 again: 446 if (getnetgrent(&host, &user, &domain) == 0) { 447 if ((gr = getgrnam(grp+2)) != NULL) 448 goto grpagain; 449 latch = 0; 450 _pw_stepping_yp = 0; 451 return(0); 452 } else { 453 if (lookup(user)) 454 goto again; 455 if (_getyppass(&_pw_passwd, user, 456 "passwd.byname")) 457 return(1); 458 else 459 goto again; 460 } 461 } else { 462 if (lookup(grp+1)) 463 return(0); 464 return(_getyppass(&_pw_passwd, grp+1, "passwd.byname")); 465 } 466 } else { 467 if (grp[1] == '@') { 468 setnetgrent(grp+2); 469 rv = 0; 470 while(getnetgrent(&host, &user, &domain) != 0) { 471 store(user); 472 rv++; 473 } 474 if (!rv && (gr = getgrnam(grp+2)) != NULL) { 475 while(*gr->gr_mem) { 476 store(*gr->gr_mem); 477 gr->gr_mem++; 478 } 479 } 480 } else { 481 store(grp+1); 482 } 483 } 484 return(0); 485 } 486 487 /* 488 * See if a user is a member of a particular group. 489 */ 490 static inline int 491 ingr(grp, name) 492 const char *grp; 493 const char *name; 494 { 495 struct group *gr; 496 497 if ((gr = getgrnam(grp)) == NULL) 498 return(0); 499 500 while(*gr->gr_mem) { 501 if (!strcmp(*gr->gr_mem, name)) 502 return(1); 503 gr->gr_mem++; 504 } 505 506 return(0); 507 } 508 509 /* 510 * Check a user against the +@netgroup/-@netgroup lines listed in 511 * the local password database. Also checks +user/-user lines. 512 * If no netgroup exists that matches +@netgroup/-@netgroup, 513 * try searching regular groups with the same name. 514 */ 515 static inline int 516 verf(name) 517 const char *name; 518 { 519 DBT key; 520 char bf[sizeof(_pw_keynum) + 1]; 521 int keynum = 0; 522 523 again: 524 ++keynum; 525 bf[0] = _PW_KEYYPBYNUM; 526 bcopy((char *)&keynum, bf + 1, sizeof(keynum)); 527 key.data = (u_char *)bf; 528 key.size = sizeof(keynum) + 1; 529 if (!__hashpw(&key)) { 530 /* Try again using old format */ 531 bf[0] = _PW_KEYBYNUM; 532 bcopy((char *)&keynum, bf + 1, sizeof(keynum)); 533 key.data = (u_char *)bf; 534 if (!__hashpw(&key)) 535 return(0); 536 } 537 if (_pw_passwd.pw_name[0] != '+' && (_pw_passwd.pw_name[0] != '-')) 538 goto again; 539 if (_pw_passwd.pw_name[0] == '+') { 540 if (strlen(_pw_passwd.pw_name) == 1) /* Wildcard */ 541 return(1); 542 if (_pw_passwd.pw_name[1] == '@') { 543 if ((innetgr(_pw_passwd.pw_name+2, NULL, name, 544 _pw_yp_domain) || 545 ingr(_pw_passwd.pw_name+2, name)) && !lookup(name)) 546 return(1); 547 else 548 goto again; 549 } else { 550 if (!strcmp(name, _pw_passwd.pw_name+1) && 551 !lookup(name)) 552 return(1); 553 else 554 goto again; 555 } 556 } 557 if (_pw_passwd.pw_name[0] == '-') { 558 /* Note that a minus wildcard is a no-op. */ 559 if (_pw_passwd.pw_name[1] == '@') { 560 if (innetgr(_pw_passwd.pw_name+2, NULL, name, 561 _pw_yp_domain) || 562 ingr(_pw_passwd.pw_name+2, name)) { 563 store(name); 564 return(0); 565 } else 566 goto again; 567 } else { 568 if (!strcmp(name, _pw_passwd.pw_name+1)) { 569 store(name); 570 return(0); 571 } else 572 goto again; 573 } 574 575 } 576 return(0); 577 } 578 579 static char * 580 _get_adjunct_pw(name) 581 const char *name; 582 { 583 static char adjunctbuf[YPMAXRECORD+2]; 584 int rval; 585 char *result; 586 int resultlen; 587 char *map = "passwd.adjunct.byname"; 588 char *s; 589 590 if ((rval = yp_match(_pw_yp_domain, map, name, strlen(name), 591 &result, &resultlen))) 592 return(NULL); 593 594 strncpy(adjunctbuf, result, resultlen); 595 adjunctbuf[resultlen] = '\0'; 596 free(result); 597 result = (char *)&adjunctbuf; 598 599 /* Don't care about the name. */ 600 if ((s = strsep(&result, ":")) == NULL) 601 return (NULL); /* name */ 602 if ((s = strsep(&result, ":")) == NULL) 603 return (NULL); /* password */ 604 605 return(s); 606 } 607 608 static int 609 _pw_breakout_yp(struct passwd *pw, char *res, int resultlen, int master) 610 { 611 char *s, *result; 612 static char resbuf[YPMAXRECORD+2]; 613 614 /* 615 * Be triple, ultra super-duper paranoid: reject entries 616 * that start with a + or -. yp_mkdb and /var/yp/Makefile 617 * are _both_ supposed to strip these out, but you never 618 * know. 619 */ 620 if (*res == '+' || *res == '-') 621 return 0; 622 623 /* 624 * The NIS protocol definition limits the size of an NIS 625 * record to YPMAXRECORD bytes. We need to do a copy to 626 * a static buffer here since the memory pointed to by 627 * res will be free()ed when this function returns. 628 */ 629 strncpy((char *)&resbuf, res, resultlen); 630 resbuf[resultlen] = '\0'; 631 result = (char *)&resbuf; 632 633 /* 634 * XXX Sanity check: make sure all fields are valid (no NULLs). 635 * If we find a badly formatted entry, we punt. 636 */ 637 if ((s = strsep(&result, ":")) == NULL) return 0; /* name */ 638 /* 639 * We don't care what pw_fields says: we _always_ want the 640 * username returned to us by NIS. 641 */ 642 pw->pw_name = s; 643 pw->pw_fields |= _PWF_NAME; 644 645 if ((s = strsep(&result, ":")) == NULL) return 0; /* password */ 646 if(!(pw->pw_fields & _PWF_PASSWD)) { 647 /* SunOS passwd.adjunct hack */ 648 if (master == YP_HAVE_ADJUNCT && strstr(s, "##") != NULL) { 649 char *realpw; 650 realpw = _get_adjunct_pw(pw->pw_name); 651 if (realpw == NULL) 652 pw->pw_passwd = s; 653 else 654 pw->pw_passwd = realpw; 655 } else { 656 pw->pw_passwd = s; 657 } 658 pw->pw_fields |= _PWF_PASSWD; 659 } 660 661 if ((s = strsep(&result, ":")) == NULL) return 0; /* uid */ 662 if(!(pw->pw_fields & _PWF_UID)) { 663 pw->pw_uid = atoi(s); 664 pw->pw_fields |= _PWF_UID; 665 } 666 667 if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */ 668 if(!(pw->pw_fields & _PWF_GID)) { 669 pw->pw_gid = atoi(s); 670 pw->pw_fields |= _PWF_GID; 671 } 672 673 if (master == YP_HAVE_MASTER) { 674 if ((s = strsep(&result, ":")) == NULL) return 0; /* class */ 675 if(!(pw->pw_fields & _PWF_CLASS)) { 676 pw->pw_class = s; 677 pw->pw_fields |= _PWF_CLASS; 678 } 679 680 if ((s = strsep(&result, ":")) == NULL) return 0; /* change */ 681 if(!(pw->pw_fields & _PWF_CHANGE)) { 682 pw->pw_change = atol(s); 683 pw->pw_fields |= _PWF_CHANGE; 684 } 685 686 if ((s = strsep(&result, ":")) == NULL) return 0; /* expire */ 687 if(!(pw->pw_fields & _PWF_EXPIRE)) { 688 pw->pw_expire = atol(s); 689 pw->pw_fields |= _PWF_EXPIRE; 690 } 691 } 692 693 if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */ 694 if(!(pw->pw_fields & _PWF_GECOS)) { 695 pw->pw_gecos = s; 696 pw->pw_fields |= _PWF_GECOS; 697 } 698 699 if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */ 700 if(!(pw->pw_fields & _PWF_DIR)) { 701 pw->pw_dir = s; 702 pw->pw_fields |= _PWF_DIR; 703 } 704 705 if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */ 706 if(!(pw->pw_fields & _PWF_SHELL)) { 707 pw->pw_shell = s; 708 pw->pw_fields |= _PWF_SHELL; 709 } 710 711 /* Be consistent. */ 712 if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0'; 713 714 return 1; 715 } 716 717 static int 718 _havemaster(char *_yp_domain) 719 { 720 int order; 721 int rval; 722 723 if (!(rval = yp_order(_yp_domain, "master.passwd.byname", &order))) 724 return(YP_HAVE_MASTER); 725 726 /* 727 * NIS+ in YP compat mode doesn't support 728 * YPPROC_ORDER -- no point in continuing. 729 */ 730 if (rval == YPERR_YPERR) 731 return(YP_HAVE_NONE); 732 733 /* master.passwd doesn't exist -- try passwd.adjunct */ 734 if (rval == YPERR_MAP) { 735 rval = yp_order(_yp_domain, "passwd.adjunct.byname", &order); 736 if (!rval) 737 return(YP_HAVE_ADJUNCT); 738 } 739 740 return (YP_HAVE_NONE); 741 } 742 743 static int 744 _getyppass(struct passwd *pw, const char *name, const char *map) 745 { 746 char *result, *s; 747 int resultlen; 748 int rv; 749 char mastermap[YPMAXRECORD]; 750 751 if(!_pw_yp_domain) { 752 if(yp_get_default_domain(&_pw_yp_domain)) 753 return 0; 754 } 755 756 if (_gotmaster == YP_HAVE_MASTER) 757 snprintf(mastermap, sizeof(mastermap), "master.%s", map); 758 else 759 snprintf(mastermap, sizeof(mastermap), "%s", map); 760 761 if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name), 762 &result, &resultlen)) { 763 if (_gotmaster != YP_HAVE_MASTER) 764 return 0; 765 snprintf(mastermap, sizeof(mastermap), "%s", map); 766 if (yp_match(_pw_yp_domain, (char *)&mastermap, 767 name, strlen(name), &result, &resultlen)) 768 return 0; 769 _gotmaster = YP_HAVE_NONE; 770 } 771 772 if (!_pw_stepping_yp) { 773 s = strchr(result, ':'); 774 if (s) { 775 *s = '\0'; 776 } else { 777 /* Must be a malformed entry if no colons. */ 778 free(result); 779 return(0); 780 } 781 782 if (!verf(result)) { 783 *s = ':'; 784 free(result); 785 return(0); 786 } 787 788 *s = ':'; /* Put back the colon we previously replaced with a NUL. */ 789 } 790 791 rv = _pw_breakout_yp(pw, result, resultlen, _gotmaster); 792 free(result); 793 return(rv); 794 } 795 796 static int 797 _nextyppass(struct passwd *pw) 798 { 799 static char *key; 800 static int keylen; 801 char *lastkey, *result, *s; 802 int resultlen; 803 int rv; 804 char *map = "passwd.byname"; 805 806 if(!_pw_yp_domain) { 807 if(yp_get_default_domain(&_pw_yp_domain)) 808 return 0; 809 } 810 811 if (_gotmaster == YP_HAVE_MASTER) 812 map = "master.passwd.byname"; 813 814 if(!_pw_stepping_yp) { 815 if(key) free(key); 816 rv = yp_first(_pw_yp_domain, map, 817 &key, &keylen, &result, &resultlen); 818 if(rv) { 819 return 0; 820 } 821 _pw_stepping_yp = 1; 822 goto unpack; 823 } else { 824 tryagain: 825 lastkey = key; 826 rv = yp_next(_pw_yp_domain, map, key, keylen, 827 &key, &keylen, &result, &resultlen); 828 free(lastkey); 829 unpack: 830 if(rv) { 831 _pw_stepping_yp = 0; 832 return 0; 833 } 834 835 s = strchr(result, ':'); 836 if (s) { 837 *s = '\0'; 838 } else { 839 /* Must be a malformed entry if no colons. */ 840 free(result); 841 goto tryagain; 842 } 843 844 if (lookup(result)) { 845 *s = ':'; 846 free(result); 847 goto tryagain; 848 } 849 850 *s = ':'; /* Put back the colon we previously replaced with a NUL. */ 851 if (_pw_breakout_yp(pw, result, resultlen, _gotmaster)) { 852 free(result); 853 return(1); 854 } else { 855 free(result); 856 goto tryagain; 857 } 858 } 859 } 860 861 #endif /* YP */ 862