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