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