158f0484fSRodney W. Grimes /* 258f0484fSRodney W. Grimes * Copyright (c) 1988, 1993 358f0484fSRodney W. Grimes * The Regents of the University of California. All rights reserved. 458f0484fSRodney W. Grimes * 558f0484fSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 658f0484fSRodney W. Grimes * modification, are permitted provided that the following conditions 758f0484fSRodney W. Grimes * are met: 858f0484fSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 958f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 1058f0484fSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 1158f0484fSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 1258f0484fSRodney W. Grimes * documentation and/or other materials provided with the distribution. 1358f0484fSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 1458f0484fSRodney W. Grimes * must display the following acknowledgement: 1558f0484fSRodney W. Grimes * This product includes software developed by the University of 1658f0484fSRodney W. Grimes * California, Berkeley and its contributors. 1758f0484fSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 1858f0484fSRodney W. Grimes * may be used to endorse or promote products derived from this software 1958f0484fSRodney W. Grimes * without specific prior written permission. 2058f0484fSRodney W. Grimes * 2158f0484fSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2258f0484fSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2358f0484fSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2458f0484fSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2558f0484fSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2658f0484fSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2758f0484fSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2858f0484fSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2958f0484fSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3058f0484fSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3158f0484fSRodney W. Grimes * SUCH DAMAGE. 3258f0484fSRodney W. Grimes */ 3358f0484fSRodney W. Grimes 3458f0484fSRodney W. Grimes #if defined(LIBC_SCCS) && !defined(lint) 3558f0484fSRodney W. Grimes static char sccsid[] = "@(#)getpwent.c 8.1 (Berkeley) 6/4/93"; 3658f0484fSRodney W. Grimes #endif /* LIBC_SCCS and not lint */ 3758f0484fSRodney W. Grimes 38958f4e36SBill Paul #include <stdio.h> 3958f0484fSRodney W. Grimes #include <sys/param.h> 4058f0484fSRodney W. Grimes #include <fcntl.h> 4158f0484fSRodney W. Grimes #include <db.h> 4258f0484fSRodney W. Grimes #include <syslog.h> 4358f0484fSRodney W. Grimes #include <pwd.h> 4458f0484fSRodney W. Grimes #include <utmp.h> 4558f0484fSRodney W. Grimes #include <errno.h> 4658f0484fSRodney W. Grimes #include <unistd.h> 4758f0484fSRodney W. Grimes #include <stdlib.h> 4858f0484fSRodney W. Grimes #include <string.h> 4958f0484fSRodney W. Grimes #include <limits.h> 50958f4e36SBill Paul #include <grp.h> 5158f0484fSRodney W. Grimes 5258f0484fSRodney W. Grimes static struct passwd _pw_passwd; /* password structure */ 5358f0484fSRodney W. Grimes static DB *_pw_db; /* password database */ 5458f0484fSRodney W. Grimes static int _pw_keynum; /* key counter */ 5558f0484fSRodney W. Grimes static int _pw_stayopen; /* keep fd's open */ 56d5b7518dSGarrett Wollman #ifdef YP 57958f4e36SBill Paul #include <rpc/rpc.h> 58958f4e36SBill Paul #include <rpcsvc/yp_prot.h> 59958f4e36SBill Paul #include <rpcsvc/ypclnt.h> 609531ca93SBill Paul struct _namelist { 619531ca93SBill Paul char *name; 629531ca93SBill Paul struct _namelist *next; 639531ca93SBill Paul }; 64d5b7518dSGarrett Wollman static struct passwd _pw_copy; 659531ca93SBill Paul struct _pw_cache { 669531ca93SBill Paul struct passwd pw_entry; 679531ca93SBill Paul struct _namelist *namelist; 689531ca93SBill Paul struct _pw_cache *next; 699531ca93SBill Paul }; 7089395683SBill Paul static int _pluscnt, _minuscnt; 7189395683SBill Paul static struct _pw_cache *_plushead = NULL, *_minushead = NULL; 729531ca93SBill Paul static void _createcaches(), _freecaches(); 73d454389cSBill Paul static int _scancaches(char *); 74d5b7518dSGarrett Wollman static int _yp_enabled; /* set true when yp enabled */ 75d5b7518dSGarrett Wollman static int _pw_stepping_yp; /* set true when stepping thru map */ 76d454389cSBill Paul static int _yp_done; 773948edc2SBill Paul static int _gotmaster; 783948edc2SBill Paul static char *_pw_yp_domain; 79958f4e36SBill Paul static int _havemaster(char *); 80d5b7518dSGarrett Wollman static int _getyppass(struct passwd *, const char *, const char *); 81d5b7518dSGarrett Wollman static int _nextyppass(struct passwd *); 823948edc2SBill Paul #endif 833948edc2SBill Paul static int __hashpw(), __initdb(); 84d5b7518dSGarrett Wollman 8558f0484fSRodney W. Grimes struct passwd * 8658f0484fSRodney W. Grimes getpwent() 8758f0484fSRodney W. Grimes { 8858f0484fSRodney W. Grimes DBT key; 8958f0484fSRodney W. Grimes char bf[sizeof(_pw_keynum) + 1]; 90d5b7518dSGarrett Wollman int rv; 9158f0484fSRodney W. Grimes 9258f0484fSRodney W. Grimes if (!_pw_db && !__initdb()) 9358f0484fSRodney W. Grimes return((struct passwd *)NULL); 9458f0484fSRodney W. Grimes 95d5b7518dSGarrett Wollman #ifdef YP 96d5b7518dSGarrett Wollman if(_pw_stepping_yp) { 97d5b7518dSGarrett Wollman _pw_passwd = _pw_copy; 98d454389cSBill Paul if (_nextyppass(&_pw_passwd)) 99d454389cSBill Paul return (&_pw_passwd); 100d454389cSBill Paul else 101d454389cSBill Paul _yp_done = 1; 102d5b7518dSGarrett Wollman } 103958f4e36SBill Paul #endif 104d454389cSBill Paul tryagain: 105d454389cSBill Paul 10658f0484fSRodney W. Grimes ++_pw_keynum; 10758f0484fSRodney W. Grimes bf[0] = _PW_KEYBYNUM; 10858f0484fSRodney W. Grimes bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum)); 10958f0484fSRodney W. Grimes key.data = (u_char *)bf; 11058f0484fSRodney W. Grimes key.size = sizeof(_pw_keynum) + 1; 111d5b7518dSGarrett Wollman rv = __hashpw(&key); 112d5b7518dSGarrett Wollman if(!rv) return (struct passwd *)NULL; 113d5b7518dSGarrett Wollman #ifdef YP 11482844700SBill Paul if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') { 115d5b7518dSGarrett Wollman _pw_copy = _pw_passwd; 116d454389cSBill Paul if (_yp_done || !_nextyppass(&_pw_passwd)) 117d454389cSBill Paul goto tryagain; 118d454389cSBill Paul else 119d454389cSBill Paul return (&_pw_passwd); 120d5b7518dSGarrett Wollman } 121d5b7518dSGarrett Wollman #else 122d5b7518dSGarrett Wollman /* Ignore YP password file entries when YP is disabled. */ 12382844700SBill Paul if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') { 124d5b7518dSGarrett Wollman goto tryagain; 125d5b7518dSGarrett Wollman } 126d5b7518dSGarrett Wollman #endif 127d5b7518dSGarrett Wollman return(&_pw_passwd); 12858f0484fSRodney W. Grimes } 12958f0484fSRodney W. Grimes 13058f0484fSRodney W. Grimes struct passwd * 13158f0484fSRodney W. Grimes getpwnam(name) 13258f0484fSRodney W. Grimes const char *name; 13358f0484fSRodney W. Grimes { 13458f0484fSRodney W. Grimes DBT key; 13558f0484fSRodney W. Grimes int len, rval; 136d5b7518dSGarrett Wollman char bf[UT_NAMESIZE + 2]; 13758f0484fSRodney W. Grimes 13858f0484fSRodney W. Grimes if (!_pw_db && !__initdb()) 13958f0484fSRodney W. Grimes return((struct passwd *)NULL); 14058f0484fSRodney W. Grimes 14158f0484fSRodney W. Grimes bf[0] = _PW_KEYBYNAME; 14258f0484fSRodney W. Grimes len = strlen(name); 14358f0484fSRodney W. Grimes bcopy(name, bf + 1, MIN(len, UT_NAMESIZE)); 14458f0484fSRodney W. Grimes key.data = (u_char *)bf; 14558f0484fSRodney W. Grimes key.size = len + 1; 14658f0484fSRodney W. Grimes rval = __hashpw(&key); 14758f0484fSRodney W. Grimes 148d5b7518dSGarrett Wollman #ifdef YP 1495f115c9dSBill Paul if (!rval && _yp_enabled) 150d5b7518dSGarrett Wollman rval = _getyppass(&_pw_passwd, name, "passwd.byname"); 151c7da24ddSGarrett Wollman #endif 152d5b7518dSGarrett Wollman /* 153d5b7518dSGarrett Wollman * Prevent login attempts when YP is not enabled but YP entries 154d5b7518dSGarrett Wollman * are in /etc/master.passwd. 155d5b7518dSGarrett Wollman */ 15682844700SBill Paul if (rval && (_pw_passwd.pw_name[0] == '+'|| 15782844700SBill Paul _pw_passwd.pw_name[0] == '-')) rval = 0; 158bb38a730SGarrett Wollman 1599531ca93SBill Paul endpwent(); 16058f0484fSRodney W. Grimes return(rval ? &_pw_passwd : (struct passwd *)NULL); 16158f0484fSRodney W. Grimes } 16258f0484fSRodney W. Grimes 16358f0484fSRodney W. Grimes struct passwd * 16458f0484fSRodney W. Grimes #ifdef __STDC__ 16558f0484fSRodney W. Grimes getpwuid(uid_t uid) 16658f0484fSRodney W. Grimes #else 16758f0484fSRodney W. Grimes getpwuid(uid) 16858f0484fSRodney W. Grimes int uid; 16958f0484fSRodney W. Grimes #endif 17058f0484fSRodney W. Grimes { 17158f0484fSRodney W. Grimes DBT key; 17258f0484fSRodney W. Grimes int keyuid, rval; 17358f0484fSRodney W. Grimes char bf[sizeof(keyuid) + 1]; 17458f0484fSRodney W. Grimes 17558f0484fSRodney W. Grimes if (!_pw_db && !__initdb()) 17658f0484fSRodney W. Grimes return((struct passwd *)NULL); 17758f0484fSRodney W. Grimes 17858f0484fSRodney W. Grimes bf[0] = _PW_KEYBYUID; 17958f0484fSRodney W. Grimes keyuid = uid; 18058f0484fSRodney W. Grimes bcopy(&keyuid, bf + 1, sizeof(keyuid)); 18158f0484fSRodney W. Grimes key.data = (u_char *)bf; 18258f0484fSRodney W. Grimes key.size = sizeof(keyuid) + 1; 18358f0484fSRodney W. Grimes rval = __hashpw(&key); 18458f0484fSRodney W. Grimes 185d5b7518dSGarrett Wollman #ifdef YP 186d5b7518dSGarrett Wollman if (!rval && _yp_enabled) { 187d5b7518dSGarrett Wollman char ypbuf[16]; /* big enough for 32-bit uids and then some */ 188d5b7518dSGarrett Wollman snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid); 189d5b7518dSGarrett Wollman rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid"); 190d5b7518dSGarrett Wollman } 191d5b7518dSGarrett Wollman #endif 19282844700SBill Paul /* 19382844700SBill Paul * Prevent login attempts when YP is not enabled but YP entries 19482844700SBill Paul * are in /etc/master.passwd. 19582844700SBill Paul */ 19682844700SBill Paul if (rval && (_pw_passwd.pw_name[0] == '+'|| 19782844700SBill Paul _pw_passwd.pw_name[0] == '-')) rval = 0; 1989531ca93SBill Paul 1999531ca93SBill Paul endpwent(); 20058f0484fSRodney W. Grimes return(rval ? &_pw_passwd : (struct passwd *)NULL); 20158f0484fSRodney W. Grimes } 20258f0484fSRodney W. Grimes 20358f0484fSRodney W. Grimes int 20458f0484fSRodney W. Grimes setpassent(stayopen) 20558f0484fSRodney W. Grimes int stayopen; 20658f0484fSRodney W. Grimes { 20758f0484fSRodney W. Grimes _pw_keynum = 0; 208d5b7518dSGarrett Wollman #ifdef YP 209d454389cSBill Paul _pw_stepping_yp = _yp_done = 0; 210d5b7518dSGarrett Wollman #endif 21158f0484fSRodney W. Grimes _pw_stayopen = stayopen; 21258f0484fSRodney W. Grimes return(1); 21358f0484fSRodney W. Grimes } 21458f0484fSRodney W. Grimes 21558f0484fSRodney W. Grimes int 21658f0484fSRodney W. Grimes setpwent() 21758f0484fSRodney W. Grimes { 21858f0484fSRodney W. Grimes _pw_keynum = 0; 219d5b7518dSGarrett Wollman #ifdef YP 220d454389cSBill Paul _pw_stepping_yp = _yp_done = 0; 221d5b7518dSGarrett Wollman #endif 22258f0484fSRodney W. Grimes _pw_stayopen = 0; 22358f0484fSRodney W. Grimes return(1); 22458f0484fSRodney W. Grimes } 22558f0484fSRodney W. Grimes 22658f0484fSRodney W. Grimes void 22758f0484fSRodney W. Grimes endpwent() 22858f0484fSRodney W. Grimes { 22958f0484fSRodney W. Grimes _pw_keynum = 0; 230d5b7518dSGarrett Wollman #ifdef YP 231d454389cSBill Paul _pw_stepping_yp = _yp_done = 0; 232d5b7518dSGarrett Wollman #endif 23358f0484fSRodney W. Grimes if (_pw_db) { 23458f0484fSRodney W. Grimes (void)(_pw_db->close)(_pw_db); 23558f0484fSRodney W. Grimes _pw_db = (DB *)NULL; 2369531ca93SBill Paul #ifdef YP 2379531ca93SBill Paul _freecaches(); 2389531ca93SBill Paul #endif 23958f0484fSRodney W. Grimes } 24058f0484fSRodney W. Grimes } 24158f0484fSRodney W. Grimes 24258f0484fSRodney W. Grimes static 24358f0484fSRodney W. Grimes __initdb() 24458f0484fSRodney W. Grimes { 24558f0484fSRodney W. Grimes static int warned; 24658f0484fSRodney W. Grimes char *p; 24758f0484fSRodney W. Grimes 24858f0484fSRodney W. Grimes p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB; 24958f0484fSRodney W. Grimes _pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL); 250d5b7518dSGarrett Wollman if (_pw_db) { 251d5b7518dSGarrett Wollman #ifdef YP 252d5b7518dSGarrett Wollman DBT key, data; 253d5b7518dSGarrett Wollman char buf[] = { _PW_KEYYPENABLED }; 254d5b7518dSGarrett Wollman key.data = buf; 255d5b7518dSGarrett Wollman key.size = 1; 256d5b7518dSGarrett Wollman if ((_pw_db->get)(_pw_db, &key, &data, 0)) { 257d5b7518dSGarrett Wollman _yp_enabled = 0; 258d5b7518dSGarrett Wollman } else { 259468bb86aSGarrett Wollman _yp_enabled = (int)*((char *)data.data) - 2; 2609531ca93SBill Paul _createcaches(); 2613948edc2SBill Paul /* Don't even bother with this if we aren't root. */ 2623948edc2SBill Paul if (!geteuid()) { 2633948edc2SBill Paul if (!_pw_yp_domain) 2643948edc2SBill Paul if (yp_get_default_domain(&_pw_yp_domain)) 2653948edc2SBill Paul return(1); 2663948edc2SBill Paul _gotmaster = _havemaster(_pw_yp_domain); 2673948edc2SBill Paul } else _gotmaster = 0; 268d5b7518dSGarrett Wollman } 269d5b7518dSGarrett Wollman #endif 27058f0484fSRodney W. Grimes return(1); 271d5b7518dSGarrett Wollman } 27258f0484fSRodney W. Grimes if (!warned) 27358f0484fSRodney W. Grimes syslog(LOG_ERR, "%s: %m", p); 27458f0484fSRodney W. Grimes return(0); 27558f0484fSRodney W. Grimes } 27658f0484fSRodney W. Grimes 27758f0484fSRodney W. Grimes static 27858f0484fSRodney W. Grimes __hashpw(key) 27958f0484fSRodney W. Grimes DBT *key; 28058f0484fSRodney W. Grimes { 28158f0484fSRodney W. Grimes register char *p, *t; 28258f0484fSRodney W. Grimes static u_int max; 28358f0484fSRodney W. Grimes static char *line; 28458f0484fSRodney W. Grimes DBT data; 28558f0484fSRodney W. Grimes 2865f115c9dSBill Paul if ((_pw_db->get)(_pw_db, key, &data, 0)) 28758f0484fSRodney W. Grimes return(0); 28858f0484fSRodney W. Grimes p = (char *)data.data; 2895f115c9dSBill Paul if (data.size > max && !(line = realloc(line, max += 1024))) 29058f0484fSRodney W. Grimes return(0); 29158f0484fSRodney W. Grimes 29258f0484fSRodney W. Grimes t = line; 29358f0484fSRodney W. Grimes #define EXPAND(e) e = t; while (*t++ = *p++); 29458f0484fSRodney W. Grimes EXPAND(_pw_passwd.pw_name); 29558f0484fSRodney W. Grimes EXPAND(_pw_passwd.pw_passwd); 29658f0484fSRodney W. Grimes bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int)); 29758f0484fSRodney W. Grimes p += sizeof(int); 29858f0484fSRodney W. Grimes bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int)); 29958f0484fSRodney W. Grimes p += sizeof(int); 30058f0484fSRodney W. Grimes bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t)); 30158f0484fSRodney W. Grimes p += sizeof(time_t); 30258f0484fSRodney W. Grimes EXPAND(_pw_passwd.pw_class); 30358f0484fSRodney W. Grimes EXPAND(_pw_passwd.pw_gecos); 30458f0484fSRodney W. Grimes EXPAND(_pw_passwd.pw_dir); 30558f0484fSRodney W. Grimes EXPAND(_pw_passwd.pw_shell); 30658f0484fSRodney W. Grimes bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t)); 30758f0484fSRodney W. Grimes p += sizeof(time_t); 308d5b7518dSGarrett Wollman bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields); 309d5b7518dSGarrett Wollman p += sizeof _pw_passwd.pw_fields; 31058f0484fSRodney W. Grimes return(1); 31158f0484fSRodney W. Grimes } 312d5b7518dSGarrett Wollman 313d5b7518dSGarrett Wollman #ifdef YP 3149531ca93SBill Paul /* 315d34ef3d6SBill Paul * Build special +@netgroup and -@netgroup caches. We also handle ordinary 316d34ef3d6SBill Paul * +user/-user entries, *and* +@group/-@group entries, which are special 317d34ef3d6SBill Paul * cases of the +@netgroup/-@netgroup substitutions: if we can't find 318d34ef3d6SBill Paul * netgroup 'foo', we look for a regular user group called 'foo' and 319d34ef3d6SBill Paul * match against that instead. The netgroup takes precedence since the 320d34ef3d6SBill Paul * +group/-group support is basically just a hack to make Justin T. Gibbs 321d34ef3d6SBill Paul * happy. :) Sorting out all the funny business here lets us have a 3225f115c9dSBill Paul * yp_enabled flag with a simple on or off value instead of the somewhat 3235f115c9dSBill Paul * bogus setup we had before. 324d34ef3d6SBill Paul * 3255f115c9dSBill Paul * We cache everything here in one shot so that we only have to scan 326d34ef3d6SBill Paul * each netgroup/group once. The alternative is to use innetgr() inside the 3275f115c9dSBill Paul * NIS lookup functions, which would make retrieving the whole password 328d34ef3d6SBill Paul * database though getpwent() very slow. +user/-user entries are treated 329d34ef3d6SBill Paul * like @groups/@netgroups with only one member. 3309531ca93SBill Paul */ 3319531ca93SBill Paul static void 3329531ca93SBill Paul _createcaches() 3339531ca93SBill Paul { 3349531ca93SBill Paul DBT key, data; 33589395683SBill Paul int i; 3369531ca93SBill Paul char bf[UT_NAMESIZE + 2]; 3379531ca93SBill Paul struct _pw_cache *p, *m; 3389531ca93SBill Paul struct _namelist *n, *namehead; 3399531ca93SBill Paul char *user, *host, *domain; 340d34ef3d6SBill Paul struct group *grp; 3419531ca93SBill Paul 34289395683SBill Paul /* 34389395683SBill Paul * Assume that the database has already been initialized 34489395683SBill Paul * but be paranoid and check that YP is in fact enabled. 34589395683SBill Paul */ 3469531ca93SBill Paul 34789395683SBill Paul if (!_yp_enabled) 34889395683SBill Paul return; 3499531ca93SBill Paul /* 350d34ef3d6SBill Paul * For the plus list, we have to store both the linked list of 3515f115c9dSBill Paul * names and the +entries from the password database so we can 3529531ca93SBill Paul * do the substitution later if we find a match. 3539531ca93SBill Paul */ 3549531ca93SBill Paul bf[0] = _PW_KEYPLUSCNT; 3559531ca93SBill Paul key.data = (u_char*)bf; 3569531ca93SBill Paul key.size = 1; 3579531ca93SBill Paul if (!(_pw_db->get)(_pw_db, &key, &data, 0)) { 35889395683SBill Paul _pluscnt = (int)*((char *)data.data); 35989395683SBill Paul for (i = 0; i < _pluscnt; i++) { 3609531ca93SBill Paul bf[0] = _PW_KEYPLUSBYNUM; 3619531ca93SBill Paul bcopy(&i, bf + 1, sizeof(i) + 1); 3629531ca93SBill Paul key.size = (sizeof(i)) + 1; 36389395683SBill Paul if (__hashpw(&key)) { 3649531ca93SBill Paul p = (struct _pw_cache *)malloc(sizeof (struct _pw_cache)); 365d34ef3d6SBill Paul if (strlen(_pw_passwd.pw_name) > 2 && _pw_passwd.pw_name[1] == '@') { 3669531ca93SBill Paul setnetgrent(_pw_passwd.pw_name+2); 3679531ca93SBill Paul namehead = NULL; 3689531ca93SBill Paul while(getnetgrent(&host, &user, &domain)) { 3699531ca93SBill Paul n = (struct _namelist *)malloc(sizeof (struct _namelist)); 3709531ca93SBill Paul n->name = strdup(user); 3719531ca93SBill Paul n->next = namehead; 3729531ca93SBill Paul namehead = n; 3739531ca93SBill Paul } 374d34ef3d6SBill Paul /* 375d34ef3d6SBill Paul * If netgroup 'foo' doesn't exist, 376d34ef3d6SBill Paul * try group 'foo' instead. 377d34ef3d6SBill Paul */ 378d34ef3d6SBill Paul if (namehead == NULL && (grp = getgrnam(_pw_passwd.pw_name+2)) != NULL) { 379d34ef3d6SBill Paul while(*grp->gr_mem) { 380d34ef3d6SBill Paul n = (struct _namelist *)malloc(sizeof (struct _namelist)); 381d34ef3d6SBill Paul n->name = strdup(*grp->gr_mem); 382d34ef3d6SBill Paul n->next = namehead; 383d34ef3d6SBill Paul namehead = n; 384d34ef3d6SBill Paul grp->gr_mem++; 385d34ef3d6SBill Paul } 386d34ef3d6SBill Paul } 387d34ef3d6SBill Paul } else { 388d34ef3d6SBill Paul if (_pw_passwd.pw_name[1] != '@') { 389d34ef3d6SBill Paul namehead = (struct _namelist *)malloc(sizeof (struct _namelist)); 390d34ef3d6SBill Paul namehead->name = strdup(_pw_passwd.pw_name+1); 391d34ef3d6SBill Paul namehead->next = NULL; 392d34ef3d6SBill Paul } 393d34ef3d6SBill Paul } 394d34ef3d6SBill Paul p->namelist = namehead; 3959531ca93SBill Paul p->pw_entry.pw_name = strdup(_pw_passwd.pw_name); 3969531ca93SBill Paul p->pw_entry.pw_passwd = strdup(_pw_passwd.pw_passwd); 3979531ca93SBill Paul p->pw_entry.pw_uid = _pw_passwd.pw_uid; 3989531ca93SBill Paul p->pw_entry.pw_gid = _pw_passwd.pw_gid; 3999531ca93SBill Paul p->pw_entry.pw_expire = _pw_passwd.pw_expire; 4009531ca93SBill Paul p->pw_entry.pw_change = _pw_passwd.pw_change; 4019531ca93SBill Paul p->pw_entry.pw_class = strdup(_pw_passwd.pw_class); 4029531ca93SBill Paul p->pw_entry.pw_gecos = strdup(_pw_passwd.pw_gecos); 4039531ca93SBill Paul p->pw_entry.pw_dir = strdup(_pw_passwd.pw_dir); 4049531ca93SBill Paul p->pw_entry.pw_shell = strdup(_pw_passwd.pw_shell); 4059531ca93SBill Paul p->pw_entry.pw_fields = _pw_passwd.pw_fields; 40689395683SBill Paul p->next = _plushead; 40789395683SBill Paul _plushead = p; 4089531ca93SBill Paul } 4099531ca93SBill Paul } 4109531ca93SBill Paul } 4119531ca93SBill Paul 4129531ca93SBill Paul /* 413d34ef3d6SBill Paul * All we need for the minuslist is the usernames. 414d34ef3d6SBill Paul * The actual -entries data can be ignored since no substitution 4159531ca93SBill Paul * will be done: anybody on the minus list is treated like a 4169531ca93SBill Paul * non-person. 4179531ca93SBill Paul */ 4189531ca93SBill Paul bf[0] = _PW_KEYMINUSCNT; 4199531ca93SBill Paul key.data = (u_char*)bf; 4209531ca93SBill Paul key.size = 1; 4219531ca93SBill Paul if (!(_pw_db->get)(_pw_db, &key, &data, 0)) { 42289395683SBill Paul _minuscnt = (int)*((char *)data.data); 423d454389cSBill Paul for (i = _minuscnt; i > -1; i--) { 4249531ca93SBill Paul bf[0] = _PW_KEYMINUSBYNUM; 4259531ca93SBill Paul bcopy(&i, bf + 1, sizeof(i) + 1); 4269531ca93SBill Paul key.size = (sizeof(i)) + 1; 42789395683SBill Paul if (__hashpw(&key)) { 4289531ca93SBill Paul m = (struct _pw_cache *)malloc(sizeof (struct _pw_cache)); 429d34ef3d6SBill Paul if (strlen (_pw_passwd.pw_name) > 2 && _pw_passwd.pw_name[1] == '@') { 4309531ca93SBill Paul namehead = NULL; 431d34ef3d6SBill Paul setnetgrent(_pw_passwd.pw_name+2); 4329531ca93SBill Paul while(getnetgrent(&host, &user, &domain)) { 4339531ca93SBill Paul n = (struct _namelist *)malloc(sizeof (struct _namelist)); 4349531ca93SBill Paul n->name = strdup(user); 4359531ca93SBill Paul n->next = namehead; 4369531ca93SBill Paul namehead = n; 4379531ca93SBill Paul } 438d34ef3d6SBill Paul /* 439d34ef3d6SBill Paul * If netgroup 'foo' doesn't exist, 440d34ef3d6SBill Paul * try group 'foo' instead. 441d34ef3d6SBill Paul */ 442d34ef3d6SBill Paul if (namehead == NULL && (grp = getgrnam(_pw_passwd.pw_name+2)) != NULL) { 443d34ef3d6SBill Paul while(*grp->gr_mem) { 444d34ef3d6SBill Paul n = (struct _namelist *)malloc(sizeof (struct _namelist)); 445d34ef3d6SBill Paul n->name = strdup(*grp->gr_mem); 446d34ef3d6SBill Paul n->next = namehead; 447d34ef3d6SBill Paul namehead = n; 448d34ef3d6SBill Paul grp->gr_mem++; 449d34ef3d6SBill Paul } 450d34ef3d6SBill Paul } 451d34ef3d6SBill Paul } else { 4525f115c9dSBill Paul if (_pw_passwd.pw_name[1] != '@') { 453d34ef3d6SBill Paul namehead = (struct _namelist *)malloc(sizeof (struct _namelist)); 454d34ef3d6SBill Paul namehead->name = strdup(_pw_passwd.pw_name+1); 455d34ef3d6SBill Paul namehead->next = NULL; 456d34ef3d6SBill Paul } 457d34ef3d6SBill Paul } 458d454389cSBill Paul /* Save just the name */ 459d454389cSBill Paul m->pw_entry.pw_name = strdup(_pw_passwd.pw_name); 4609531ca93SBill Paul m->namelist = namehead; 46189395683SBill Paul m->next = _minushead; 46289395683SBill Paul _minushead = m; 4639531ca93SBill Paul } 4649531ca93SBill Paul } 4659531ca93SBill Paul } 466f05daed9SBill Paul endgrent(); 467f05daed9SBill Paul endnetgrent(); 4689531ca93SBill Paul } 4699531ca93SBill Paul 4709531ca93SBill Paul /* 4719531ca93SBill Paul * Free the +@netgroup/-@netgroup caches. Should be called 4729531ca93SBill Paul * from endpwent(). We have to blow away both the list of 4739531ca93SBill Paul * netgroups and the attached linked lists of usernames. 4749531ca93SBill Paul */ 4759531ca93SBill Paul static void 4769531ca93SBill Paul _freecaches() 4779531ca93SBill Paul { 4789531ca93SBill Paul struct _pw_cache *p, *m; 4799531ca93SBill Paul struct _namelist *n; 4809531ca93SBill Paul 48189395683SBill Paul while (_plushead) { 48289395683SBill Paul while(_plushead->namelist) { 48389395683SBill Paul n = _plushead->namelist->next; 484243ae8c7SBill Paul free(_plushead->namelist->name); 48589395683SBill Paul free(_plushead->namelist); 48689395683SBill Paul _plushead->namelist = n; 4879531ca93SBill Paul } 488243ae8c7SBill Paul free(_plushead->pw_entry.pw_name); 489243ae8c7SBill Paul free(_plushead->pw_entry.pw_passwd); 490243ae8c7SBill Paul free(_plushead->pw_entry.pw_class); 491243ae8c7SBill Paul free(_plushead->pw_entry.pw_gecos); 492243ae8c7SBill Paul free(_plushead->pw_entry.pw_dir); 493243ae8c7SBill Paul free(_plushead->pw_entry.pw_shell); 49489395683SBill Paul p = _plushead->next; 49589395683SBill Paul free(_plushead); 49689395683SBill Paul _plushead = p; 4979531ca93SBill Paul } 4989531ca93SBill Paul 49989395683SBill Paul while(_minushead) { 50089395683SBill Paul while(_minushead->namelist) { 50189395683SBill Paul n = _minushead->namelist->next; 502243ae8c7SBill Paul free(_minushead->namelist->name); 50389395683SBill Paul free(_minushead->namelist); 50489395683SBill Paul _minushead->namelist = n; 5059531ca93SBill Paul } 50689395683SBill Paul m = _minushead->next; 50789395683SBill Paul free(_minushead); 50889395683SBill Paul _minushead = m; 5099531ca93SBill Paul } 51089395683SBill Paul _pluscnt = _minuscnt = 0; 5119531ca93SBill Paul } 5129531ca93SBill Paul 513d454389cSBill Paul static int _scancaches(user) 514d454389cSBill Paul char *user; 515d454389cSBill Paul { 516d454389cSBill Paul register struct _pw_cache *m, *p; 517d454389cSBill Paul register struct _namelist *n; 518d454389cSBill Paul 519d454389cSBill Paul if (_minuscnt && _minushead) { 520d454389cSBill Paul m = _minushead; 521d454389cSBill Paul while (m) { 522d454389cSBill Paul n = m->namelist; 523d454389cSBill Paul while (n) { 524d454389cSBill Paul if (!strcmp(n->name,user) || *n->name == '\0') 525d454389cSBill Paul return (1); 526d454389cSBill Paul n = n->next; 527d454389cSBill Paul } 528d454389cSBill Paul m = m->next; 529d454389cSBill Paul } 530d454389cSBill Paul } 531d454389cSBill Paul if (_pluscnt && _plushead) { 532d454389cSBill Paul p = _plushead; 533d454389cSBill Paul while (p) { 534d454389cSBill Paul n = p->namelist; 535d454389cSBill Paul while (n) { 536d454389cSBill Paul if (!strcmp(n->name, user) || *n->name == '\0') 537d454389cSBill Paul bcopy((char *)&p->pw_entry, 538d454389cSBill Paul (char *)&_pw_passwd, sizeof(p->pw_entry)); 539d454389cSBill Paul n = n->next; 540d454389cSBill Paul } 541d454389cSBill Paul p = p->next; 542d454389cSBill Paul } 543d454389cSBill Paul } 544d454389cSBill Paul return(0); 545d454389cSBill Paul } 546d454389cSBill Paul 5476c0828a6SBill Paul static int 5483948edc2SBill Paul _pw_breakout_yp(struct passwd *pw, char *res, int master) 549d5b7518dSGarrett Wollman { 5503948edc2SBill Paul char *s, *c, *result; 5513948edc2SBill Paul static char resbuf[YPMAXRECORD+2]; 552d3628763SRodney W. Grimes 5533948edc2SBill Paul /* 5543948edc2SBill Paul * Be triple, ultra super-duper paranoid: reject entries 5553948edc2SBill Paul * that start with a + or -. yp_mkdb and /var/yp/Makefile 5563948edc2SBill Paul * are _both_ supposed to strip these out, but you never 5573948edc2SBill Paul * know. 5583948edc2SBill Paul */ 5593948edc2SBill Paul if (*res == '+' || *res == '-') 5603948edc2SBill Paul return 0; 5613948edc2SBill Paul 5623948edc2SBill Paul /* 5633948edc2SBill Paul * The NIS protocol definition limits the size of an NIS 5643948edc2SBill Paul * record to YPMAXRECORD bytes. We need to do a copy to 5653948edc2SBill Paul * a static buffer here since the memory pointed to by 5663948edc2SBill Paul * res will be free()ed when this function returns. 5673948edc2SBill Paul */ 5683948edc2SBill Paul strncpy((char *)&resbuf, res, YPMAXRECORD); 5693948edc2SBill Paul result = (char *)&resbuf; 570d5b7518dSGarrett Wollman 5716c0828a6SBill Paul /* 5726c0828a6SBill Paul * XXX Sanity check: make sure all fields are valid (no NULLs). 5736c0828a6SBill Paul * If we find a badly formatted entry, we punt. 5746c0828a6SBill Paul */ 5756c0828a6SBill Paul if ((s = strsep(&result, ":")) == NULL) return 0; /* name */ 5763948edc2SBill Paul /* 5773948edc2SBill Paul * We don't care what pw_fields says: we _always_ want the 5783948edc2SBill Paul * username returned to us by NIS. 5793948edc2SBill Paul */ 580d5b7518dSGarrett Wollman pw->pw_name = s; 581d5b7518dSGarrett Wollman pw->pw_fields |= _PWF_NAME; 582d5b7518dSGarrett Wollman 5836c0828a6SBill Paul if ((s = strsep(&result, ":")) == NULL) return 0; /* password */ 584d5b7518dSGarrett Wollman if(!(pw->pw_fields & _PWF_PASSWD)) { 585d5b7518dSGarrett Wollman pw->pw_passwd = s; 586d5b7518dSGarrett Wollman pw->pw_fields |= _PWF_PASSWD; 587d5b7518dSGarrett Wollman } 588d5b7518dSGarrett Wollman 5896c0828a6SBill Paul if ((s = strsep(&result, ":")) == NULL) return 0; /* uid */ 590d5b7518dSGarrett Wollman if(!(pw->pw_fields & _PWF_UID)) { 591d5b7518dSGarrett Wollman pw->pw_uid = atoi(s); 592d5b7518dSGarrett Wollman pw->pw_fields |= _PWF_UID; 593d5b7518dSGarrett Wollman } 594d5b7518dSGarrett Wollman 5956c0828a6SBill Paul if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */ 596d5b7518dSGarrett Wollman if(!(pw->pw_fields & _PWF_GID)) { 597d5b7518dSGarrett Wollman pw->pw_gid = atoi(s); 598d5b7518dSGarrett Wollman pw->pw_fields |= _PWF_GID; 599d5b7518dSGarrett Wollman } 600d5b7518dSGarrett Wollman 601d66efc62SBill Paul if (master) { 6026c0828a6SBill Paul if ((s = strsep(&result, ":")) == NULL) return 0; /* class */ 603d0ef6688SBill Paul if(!(pw->pw_fields & _PWF_CLASS)) { 604d0ef6688SBill Paul pw->pw_class = s; 605d0ef6688SBill Paul pw->pw_fields |= _PWF_CLASS; 606d0ef6688SBill Paul } 607d0ef6688SBill Paul 6086c0828a6SBill Paul if ((s = strsep(&result, ":")) == NULL) return 0; /* change */ 609d0ef6688SBill Paul if(!(pw->pw_fields & _PWF_CHANGE)) { 610d0ef6688SBill Paul pw->pw_change = atol(s); 611d0ef6688SBill Paul pw->pw_fields |= _PWF_CHANGE; 612d0ef6688SBill Paul } 613d0ef6688SBill Paul 6146c0828a6SBill Paul if ((s = strsep(&result, ":")) == NULL) return 0; /* expire */ 615d0ef6688SBill Paul if(!(pw->pw_fields & _PWF_EXPIRE)) { 616d0ef6688SBill Paul pw->pw_expire = atol(s); 617d0ef6688SBill Paul pw->pw_fields |= _PWF_EXPIRE; 618d0ef6688SBill Paul } 619d66efc62SBill Paul } 620d0ef6688SBill Paul 6216c0828a6SBill Paul if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */ 622d0ef6688SBill Paul if(!(pw->pw_fields & _PWF_GECOS)) { 623d0ef6688SBill Paul pw->pw_gecos = s; 624d0ef6688SBill Paul pw->pw_fields |= _PWF_GECOS; 625d0ef6688SBill Paul } 626d0ef6688SBill Paul 6276c0828a6SBill Paul if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */ 628d0ef6688SBill Paul if(!(pw->pw_fields & _PWF_DIR)) { 629d0ef6688SBill Paul pw->pw_dir = s; 630d0ef6688SBill Paul pw->pw_fields |= _PWF_DIR; 631d0ef6688SBill Paul } 632d0ef6688SBill Paul 6336c0828a6SBill Paul if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */ 634d0ef6688SBill Paul if(!(pw->pw_fields & _PWF_SHELL)) { 635d0ef6688SBill Paul pw->pw_shell = s; 636d0ef6688SBill Paul pw->pw_fields |= _PWF_SHELL; 637d0ef6688SBill Paul } 6386c0828a6SBill Paul 6393948edc2SBill Paul /* Be consistent. */ 6403948edc2SBill Paul if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0'; 6413948edc2SBill Paul 6426c0828a6SBill Paul return 1; 643d0ef6688SBill Paul } 644d0ef6688SBill Paul 645d5b7518dSGarrett Wollman static int 646958f4e36SBill Paul _havemaster(char *_pw_yp_domain) 647d0ef6688SBill Paul { 64885e8f5beSBill Paul int keylen, resultlen; 64985e8f5beSBill Paul char *key, *result; 650d0ef6688SBill Paul 65185e8f5beSBill Paul if (yp_first(_pw_yp_domain, "master.passwd.byname", 65285e8f5beSBill Paul &key, &keylen, &result, &resultlen)) { 65385e8f5beSBill Paul free(result); 654d0ef6688SBill Paul return 0; 655b38bb6d3SBill Paul } 65685e8f5beSBill Paul free(result); 657d0ef6688SBill Paul return 1; 658d0ef6688SBill Paul } 659d0ef6688SBill Paul 660d0ef6688SBill Paul static int 661d5b7518dSGarrett Wollman _getyppass(struct passwd *pw, const char *name, const char *map) 662d5b7518dSGarrett Wollman { 663d5b7518dSGarrett Wollman char *result, *s; 664d5b7518dSGarrett Wollman int resultlen; 6653948edc2SBill Paul int rv; 666d0ef6688SBill Paul char mastermap[1024]; 667d5b7518dSGarrett Wollman 668d5b7518dSGarrett Wollman if(!_pw_yp_domain) { 669d5b7518dSGarrett Wollman if(yp_get_default_domain(&_pw_yp_domain)) 670d5b7518dSGarrett Wollman return 0; 671d5b7518dSGarrett Wollman } 672d5b7518dSGarrett Wollman 673d0ef6688SBill Paul sprintf(mastermap,"%s",map); 674d0ef6688SBill Paul 6753948edc2SBill Paul if (_gotmaster) 676320ce7b7SBill Paul sprintf(mastermap,"master.%s", map); 677d0ef6688SBill Paul 678958f4e36SBill Paul if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name), 679d5b7518dSGarrett Wollman &result, &resultlen)) 680d5b7518dSGarrett Wollman return 0; 681d5b7518dSGarrett Wollman 6823948edc2SBill Paul s = strchr(result, ':'); 6833948edc2SBill Paul if (s) { 6843948edc2SBill Paul *s = '\0'; 6853948edc2SBill Paul } else { 6863948edc2SBill Paul /* Must be a malformed entry if no colons. */ 6873948edc2SBill Paul free(result); 6883948edc2SBill Paul return(0); 6893948edc2SBill Paul } 690c98fda6eSBill Paul _pw_passwd.pw_fields = -1; /* Impossible value */ 6913948edc2SBill Paul if (_scancaches(result)) { 6929531ca93SBill Paul free(result); 6939531ca93SBill Paul return(0); 6943948edc2SBill Paul } 695c98fda6eSBill Paul /* No hits in the plus or minus lists: Bzzt! reject. */ 6963948edc2SBill Paul if (_pw_passwd.pw_fields == -1) { 6973948edc2SBill Paul free(result); 698c98fda6eSBill Paul return(0); 6993948edc2SBill Paul } 7003948edc2SBill Paul *s = ':'; /* Put back the colon we previously replaced with a NUL. */ 7013948edc2SBill Paul rv = _pw_breakout_yp(pw, result, _gotmaster); 7023948edc2SBill Paul free(result); 7033948edc2SBill Paul return(rv); 704d5b7518dSGarrett Wollman } 705d5b7518dSGarrett Wollman 706d5b7518dSGarrett Wollman static int 707d5b7518dSGarrett Wollman _nextyppass(struct passwd *pw) 708d5b7518dSGarrett Wollman { 709958f4e36SBill Paul static char *key; 710d5b7518dSGarrett Wollman static int keylen; 7113948edc2SBill Paul char *lastkey, *result, *s; 712d5b7518dSGarrett Wollman int resultlen; 713d5b7518dSGarrett Wollman int rv; 714d0ef6688SBill Paul char *map = "passwd.byname"; 715d5b7518dSGarrett Wollman 716d5b7518dSGarrett Wollman if(!_pw_yp_domain) { 717d5b7518dSGarrett Wollman if(yp_get_default_domain(&_pw_yp_domain)) 718d5b7518dSGarrett Wollman return 0; 719d5b7518dSGarrett Wollman } 720d5b7518dSGarrett Wollman 7213948edc2SBill Paul if (_gotmaster) 722d0ef6688SBill Paul map = "master.passwd.byname"; 723d0ef6688SBill Paul 724d5b7518dSGarrett Wollman if(!_pw_stepping_yp) { 725d5b7518dSGarrett Wollman if(key) free(key); 726d0ef6688SBill Paul rv = yp_first(_pw_yp_domain, map, 727d5b7518dSGarrett Wollman &key, &keylen, &result, &resultlen); 728d5b7518dSGarrett Wollman if(rv) { 729d5b7518dSGarrett Wollman return 0; 730d5b7518dSGarrett Wollman } 731d5b7518dSGarrett Wollman _pw_stepping_yp = 1; 732d5b7518dSGarrett Wollman goto unpack; 733d5b7518dSGarrett Wollman } else { 734d5b7518dSGarrett Wollman tryagain: 735d5b7518dSGarrett Wollman lastkey = key; 736d0ef6688SBill Paul rv = yp_next(_pw_yp_domain, map, key, keylen, 737d5b7518dSGarrett Wollman &key, &keylen, &result, &resultlen); 738d5b7518dSGarrett Wollman free(lastkey); 739d5b7518dSGarrett Wollman unpack: 740d5b7518dSGarrett Wollman if(rv) { 741d5b7518dSGarrett Wollman _pw_stepping_yp = 0; 742d5b7518dSGarrett Wollman return 0; 743d5b7518dSGarrett Wollman } 744d5b7518dSGarrett Wollman 7453948edc2SBill Paul s = strchr(result, ':'); 7463948edc2SBill Paul if (s) { 7473948edc2SBill Paul *s = '\0'; 7483948edc2SBill Paul } else { 7493948edc2SBill Paul /* Must be a malformed entry if no colon. */ 750d5b7518dSGarrett Wollman free(result); 751d5b7518dSGarrett Wollman goto tryagain; 752d5b7518dSGarrett Wollman } 753c98fda6eSBill Paul _pw_passwd.pw_fields = -1; /* Impossible value */ 7543948edc2SBill Paul if (_scancaches(result)) { 7559531ca93SBill Paul free(result); 7569531ca93SBill Paul goto tryagain; 7573948edc2SBill Paul } 758c98fda6eSBill Paul /* No plus or minus hits: Bzzzt! reject. */ 7593948edc2SBill Paul if (_pw_passwd.pw_fields == -1) { 7603948edc2SBill Paul free(result); 761c98fda6eSBill Paul goto tryagain; 7623948edc2SBill Paul } 7633948edc2SBill Paul *s = ':'; /* Put back colon we previously replaced with a NUL. */ 7643948edc2SBill Paul if(s = strchr(result, '\n')) *s = '\0'; 7653948edc2SBill Paul if (_pw_breakout_yp(pw, result, _gotmaster)) { 7663948edc2SBill Paul free(result); 767400b8413SBill Paul return(1); 7683948edc2SBill Paul } else { 7693948edc2SBill Paul free(result); 770400b8413SBill Paul goto tryagain; 771d5b7518dSGarrett Wollman } 772d5b7518dSGarrett Wollman } 7733948edc2SBill Paul } 774d5b7518dSGarrett Wollman 775d5b7518dSGarrett Wollman #endif /* YP */ 776