getpwent.c revision 5714
11573Srgrimes/*
21573Srgrimes * Copyright (c) 1988, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes * 3. All advertising materials mentioning features or use of this software
141573Srgrimes *    must display the following acknowledgement:
151573Srgrimes *	This product includes software developed by the University of
161573Srgrimes *	California, Berkeley and its contributors.
171573Srgrimes * 4. Neither the name of the University nor the names of its contributors
181573Srgrimes *    may be used to endorse or promote products derived from this software
191573Srgrimes *    without specific prior written permission.
201573Srgrimes *
211573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311573Srgrimes * SUCH DAMAGE.
321573Srgrimes */
331573Srgrimes
341573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
351573Srgrimesstatic char sccsid[] = "@(#)getpwent.c	8.1 (Berkeley) 6/4/93";
361573Srgrimes#endif /* LIBC_SCCS and not lint */
371573Srgrimes
381573Srgrimes#include <sys/param.h>
391573Srgrimes#include <fcntl.h>
401573Srgrimes#include <db.h>
411573Srgrimes#include <syslog.h>
421573Srgrimes#include <pwd.h>
431573Srgrimes#include <utmp.h>
441573Srgrimes#include <errno.h>
451573Srgrimes#include <unistd.h>
461573Srgrimes#include <stdlib.h>
471573Srgrimes#include <string.h>
481573Srgrimes#include <limits.h>
491573Srgrimes
501573Srgrimesstatic struct passwd _pw_passwd;	/* password structure */
511573Srgrimesstatic DB *_pw_db;			/* password database */
521573Srgrimesstatic int _pw_keynum;			/* key counter */
531573Srgrimesstatic int _pw_stayopen;		/* keep fd's open */
542917Swollman#ifdef YP
552917Swollmanstatic struct passwd _pw_copy;
562917Swollmanstatic int _yp_enabled;			/* set true when yp enabled */
572917Swollmanstatic int _pw_stepping_yp;		/* set true when stepping thru map */
582917Swollman#endif
591573Srgrimesstatic int __hashpw(), __initdb();
601573Srgrimes
612917Swollmanstatic int _getyppass(struct passwd *, const char *, const char *);
622917Swollmanstatic int _nextyppass(struct passwd *);
632917Swollman
641573Srgrimesstruct passwd *
651573Srgrimesgetpwent()
661573Srgrimes{
671573Srgrimes	DBT key;
681573Srgrimes	char bf[sizeof(_pw_keynum) + 1];
692917Swollman	int rv;
701573Srgrimes
711573Srgrimes	if (!_pw_db && !__initdb())
721573Srgrimes		return((struct passwd *)NULL);
731573Srgrimes
742917Swollman#ifdef YP
752917Swollman	if(_pw_stepping_yp) {
762917Swollman		_pw_passwd = _pw_copy;
772917Swollman		return (_nextyppass(&_pw_passwd) ? &_pw_passwd : 0);
782917Swollman	}
792917Swollman#endif
802917Swollman
812917Swollmantryagain:
821573Srgrimes	++_pw_keynum;
831573Srgrimes	bf[0] = _PW_KEYBYNUM;
841573Srgrimes	bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
851573Srgrimes	key.data = (u_char *)bf;
861573Srgrimes	key.size = sizeof(_pw_keynum) + 1;
872917Swollman	rv = __hashpw(&key);
882917Swollman	if(!rv) return (struct passwd *)NULL;
892917Swollman#ifdef YP
902917Swollman	if(_pw_passwd.pw_name[0] == '+' && _pw_passwd.pw_name[1]) {
912917Swollman		_getyppass(&_pw_passwd, &_pw_passwd.pw_name[1],
922917Swollman			   "passwd.byname");
932917Swollman	} else if(_pw_passwd.pw_name[0] == '+') {
942917Swollman		_pw_copy = _pw_passwd;
952917Swollman		return (_nextyppass(&_pw_passwd) ? &_pw_passwd : 0);
962917Swollman	}
972917Swollman#else
982917Swollman	/* Ignore YP password file entries when YP is disabled. */
992917Swollman	if(_pw_passwd.pw_name[0] == '+') {
1002917Swollman		goto tryagain;
1012917Swollman	}
1022917Swollman#endif
1032917Swollman	return(&_pw_passwd);
1041573Srgrimes}
1051573Srgrimes
1061573Srgrimesstruct passwd *
1071573Srgrimesgetpwnam(name)
1081573Srgrimes	const char *name;
1091573Srgrimes{
1101573Srgrimes	DBT key;
1111573Srgrimes	int len, rval;
1122917Swollman	char bf[UT_NAMESIZE + 2];
1131573Srgrimes
1141573Srgrimes	if (!_pw_db && !__initdb())
1151573Srgrimes		return((struct passwd *)NULL);
1161573Srgrimes
1171573Srgrimes	bf[0] = _PW_KEYBYNAME;
1181573Srgrimes	len = strlen(name);
1191573Srgrimes	bcopy(name, bf + 1, MIN(len, UT_NAMESIZE));
1201573Srgrimes	key.data = (u_char *)bf;
1211573Srgrimes	key.size = len + 1;
1221573Srgrimes	rval = __hashpw(&key);
1231573Srgrimes
1242917Swollman#ifdef YP
1252917Swollman	if (!rval && _yp_enabled) {
1262917Swollman		bf[1] = '+';
1272935Swollman		bcopy(name, bf + 2, MIN(len, UT_NAMESIZE - 1));
1282917Swollman		key.data = (u_char *)bf;
1292917Swollman		key.size = len + 2;
1302917Swollman		rval = __hashpw(&key);
1312935Swollman		if (!rval && _yp_enabled < 0) {
1322917Swollman			key.size = 2;
1332917Swollman			rval = __hashpw(&key);
1342917Swollman		}
1352935Swollman		if(rval)
1362935Swollman			rval = _getyppass(&_pw_passwd, name, "passwd.byname");
1372917Swollman	}
1385703Swollman#endif
1392917Swollman	/*
1402917Swollman	 * Prevent login attempts when YP is not enabled but YP entries
1412917Swollman	 * are in /etc/master.passwd.
1422917Swollman	 */
1432917Swollman	if (rval && _pw_passwd.pw_name[0] == '+') rval = 0;
1445714Swollman
1451573Srgrimes	if (!_pw_stayopen) {
1461573Srgrimes		(void)(_pw_db->close)(_pw_db);
1471573Srgrimes		_pw_db = (DB *)NULL;
1481573Srgrimes	}
1491573Srgrimes	return(rval ? &_pw_passwd : (struct passwd *)NULL);
1501573Srgrimes}
1511573Srgrimes
1521573Srgrimesstruct passwd *
1531573Srgrimes#ifdef __STDC__
1541573Srgrimesgetpwuid(uid_t uid)
1551573Srgrimes#else
1561573Srgrimesgetpwuid(uid)
1571573Srgrimes	int uid;
1581573Srgrimes#endif
1591573Srgrimes{
1601573Srgrimes	DBT key;
1611573Srgrimes	int keyuid, rval;
1621573Srgrimes	char bf[sizeof(keyuid) + 1];
1631573Srgrimes
1641573Srgrimes	if (!_pw_db && !__initdb())
1651573Srgrimes		return((struct passwd *)NULL);
1661573Srgrimes
1671573Srgrimes	bf[0] = _PW_KEYBYUID;
1681573Srgrimes	keyuid = uid;
1691573Srgrimes	bcopy(&keyuid, bf + 1, sizeof(keyuid));
1701573Srgrimes	key.data = (u_char *)bf;
1711573Srgrimes	key.size = sizeof(keyuid) + 1;
1721573Srgrimes	rval = __hashpw(&key);
1731573Srgrimes
1742917Swollman#ifdef YP
1752917Swollman	if (!rval && _yp_enabled) {
1762917Swollman		char ypbuf[16];	/* big enough for 32-bit uids and then some */
1772917Swollman		snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid);
1782917Swollman		rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid");
1792917Swollman	}
1802917Swollman#endif
1811573Srgrimes	if (!_pw_stayopen) {
1821573Srgrimes		(void)(_pw_db->close)(_pw_db);
1831573Srgrimes		_pw_db = (DB *)NULL;
1841573Srgrimes	}
1851573Srgrimes	return(rval ? &_pw_passwd : (struct passwd *)NULL);
1861573Srgrimes}
1871573Srgrimes
1881573Srgrimesint
1891573Srgrimessetpassent(stayopen)
1901573Srgrimes	int stayopen;
1911573Srgrimes{
1921573Srgrimes	_pw_keynum = 0;
1932917Swollman#ifdef YP
1942917Swollman	_pw_stepping_yp = 0;
1952917Swollman#endif
1961573Srgrimes	_pw_stayopen = stayopen;
1971573Srgrimes	return(1);
1981573Srgrimes}
1991573Srgrimes
2001573Srgrimesint
2011573Srgrimessetpwent()
2021573Srgrimes{
2031573Srgrimes	_pw_keynum = 0;
2042917Swollman#ifdef YP
2052917Swollman	_pw_stepping_yp = 0;
2062917Swollman#endif
2071573Srgrimes	_pw_stayopen = 0;
2081573Srgrimes	return(1);
2091573Srgrimes}
2101573Srgrimes
2111573Srgrimesvoid
2121573Srgrimesendpwent()
2131573Srgrimes{
2141573Srgrimes	_pw_keynum = 0;
2152917Swollman#ifdef YP
2162917Swollman	_pw_stepping_yp = 0;
2172917Swollman#endif
2181573Srgrimes	if (_pw_db) {
2191573Srgrimes		(void)(_pw_db->close)(_pw_db);
2201573Srgrimes		_pw_db = (DB *)NULL;
2211573Srgrimes	}
2221573Srgrimes}
2231573Srgrimes
2241573Srgrimesstatic
2251573Srgrimes__initdb()
2261573Srgrimes{
2271573Srgrimes	static int warned;
2281573Srgrimes	char *p;
2291573Srgrimes
2301573Srgrimes	p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
2311573Srgrimes	_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
2322917Swollman	if (_pw_db) {
2332917Swollman#ifdef YP
2342917Swollman		DBT key, data;
2352917Swollman		char buf[] = { _PW_KEYYPENABLED };
2362917Swollman		key.data = buf;
2372917Swollman		key.size = 1;
2382917Swollman		if ((_pw_db->get)(_pw_db, &key, &data, 0)) {
2392917Swollman			_yp_enabled = 0;
2402917Swollman		} else {
2412935Swollman			/* Distinguish between old and new versions of
2422935Swollman			   pwd_mkdb. */
2432935Swollman			if(data.size != 1) {
2442935Swollman				_yp_enabled = -1;
2452935Swollman			} else {
2462935Swollman				_yp_enabled = (int)*((char *)data.data) - 2;
2472935Swollman			}
2482917Swollman		}
2492917Swollman#endif
2501573Srgrimes		return(1);
2512917Swollman	}
2521573Srgrimes	if (!warned)
2531573Srgrimes		syslog(LOG_ERR, "%s: %m", p);
2541573Srgrimes	return(0);
2551573Srgrimes}
2561573Srgrimes
2571573Srgrimesstatic
2581573Srgrimes__hashpw(key)
2591573Srgrimes	DBT *key;
2601573Srgrimes{
2611573Srgrimes	register char *p, *t;
2621573Srgrimes	static u_int max;
2631573Srgrimes	static char *line;
2641573Srgrimes	DBT data;
2651573Srgrimes
2661573Srgrimes	if ((_pw_db->get)(_pw_db, key, &data, 0))
2671573Srgrimes		return(0);
2681573Srgrimes	p = (char *)data.data;
2691573Srgrimes	if (data.size > max && !(line = realloc(line, max += 1024)))
2701573Srgrimes		return(0);
2711573Srgrimes
2721573Srgrimes	t = line;
2731573Srgrimes#define	EXPAND(e)	e = t; while (*t++ = *p++);
2741573Srgrimes	EXPAND(_pw_passwd.pw_name);
2751573Srgrimes	EXPAND(_pw_passwd.pw_passwd);
2761573Srgrimes	bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
2771573Srgrimes	p += sizeof(int);
2781573Srgrimes	bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
2791573Srgrimes	p += sizeof(int);
2801573Srgrimes	bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t));
2811573Srgrimes	p += sizeof(time_t);
2821573Srgrimes	EXPAND(_pw_passwd.pw_class);
2831573Srgrimes	EXPAND(_pw_passwd.pw_gecos);
2841573Srgrimes	EXPAND(_pw_passwd.pw_dir);
2851573Srgrimes	EXPAND(_pw_passwd.pw_shell);
2861573Srgrimes	bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
2871573Srgrimes	p += sizeof(time_t);
2882917Swollman	bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
2892917Swollman	p += sizeof _pw_passwd.pw_fields;
2901573Srgrimes	return(1);
2911573Srgrimes}
2922917Swollman
2932917Swollman#ifdef YP
2942917Swollmanstatic void
2952917Swollman_pw_breakout_yp(struct passwd *pw, char *result)
2962917Swollman{
2972917Swollman	char *s;
2982917Swollman
2992917Swollman	s = strsep(&result, ":"); /* name */
3002917Swollman	if(!(pw->pw_fields & _PWF_NAME) || (pw->pw_name[0] == '+')) {
3012917Swollman		pw->pw_name = s;
3022917Swollman		pw->pw_fields |= _PWF_NAME;
3032917Swollman	}
3042917Swollman
3052917Swollman	s = strsep(&result, ":"); /* password */
3062917Swollman	if(!(pw->pw_fields & _PWF_PASSWD)) {
3072917Swollman		pw->pw_passwd = s;
3082917Swollman		pw->pw_fields |= _PWF_PASSWD;
3092917Swollman	}
3102917Swollman
3112917Swollman	s = strsep(&result, ":"); /* uid */
3122917Swollman	if(!(pw->pw_fields & _PWF_UID)) {
3132917Swollman		pw->pw_uid = atoi(s);
3142917Swollman		pw->pw_fields |= _PWF_UID;
3152917Swollman	}
3162917Swollman
3172917Swollman	s = strsep(&result, ":"); /* gid */
3182917Swollman	if(!(pw->pw_fields & _PWF_GID))  {
3192917Swollman		pw->pw_gid = atoi(s);
3202917Swollman		pw->pw_fields |= _PWF_GID;
3212917Swollman	}
3222917Swollman
3232917Swollman	s = strsep(&result, ":"); /* gecos */
3242917Swollman	if(!(pw->pw_fields & _PWF_GECOS)) {
3252917Swollman		pw->pw_gecos = s;
3262917Swollman		pw->pw_fields |= _PWF_GECOS;
3272917Swollman	}
3282917Swollman
3292917Swollman	s = strsep(&result, ":"); /* dir */
3302917Swollman	if(!(pw->pw_fields & _PWF_DIR)) {
3312917Swollman		pw->pw_dir = s;
3322917Swollman		pw->pw_fields |= _PWF_DIR;
3332917Swollman	}
3342917Swollman
3352917Swollman	s = strsep(&result, ":"); /* shell */
3362917Swollman	if(!(pw->pw_fields & _PWF_SHELL)) {
3372917Swollman		pw->pw_shell = s;
3382917Swollman		pw->pw_fields |= _PWF_SHELL;
3392917Swollman	}
3402917Swollman}
3412917Swollman
3422917Swollmanstatic char *_pw_yp_domain;
3432917Swollman
3442917Swollmanstatic int
3452917Swollman_getyppass(struct passwd *pw, const char *name, const char *map)
3462917Swollman{
3472917Swollman	char *result, *s;
3482917Swollman	static char resultbuf[1024];
3492917Swollman	int resultlen;
3502917Swollman
3512917Swollman	if(!_pw_yp_domain) {
3522917Swollman		if(yp_get_default_domain(&_pw_yp_domain))
3532917Swollman		  return 0;
3542917Swollman	}
3552917Swollman
3562917Swollman	if(yp_match(_pw_yp_domain, map, name, strlen(name),
3572917Swollman		    &result, &resultlen))
3582917Swollman		return 0;
3592917Swollman
3602917Swollman	s = strchr(result, '\n');
3612917Swollman	if(s) *s = '\0';
3622917Swollman
3632935Swollman	if(resultlen >= sizeof resultbuf) return 0;
3642917Swollman	strcpy(resultbuf, result);
3652917Swollman	result = resultbuf;
3662917Swollman	_pw_breakout_yp(pw, resultbuf);
3672917Swollman
3682917Swollman	return 1;
3692917Swollman}
3702917Swollman
3712917Swollmanstatic int
3722917Swollman_nextyppass(struct passwd *pw)
3732917Swollman{
3742917Swollman	static char *key;
3752917Swollman	static int keylen;
3762917Swollman	char *lastkey, *result;
3772917Swollman	static char resultbuf[1024];
3782917Swollman	int resultlen;
3792917Swollman	int rv;
3802917Swollman
3812917Swollman	if(!_pw_yp_domain) {
3822917Swollman		if(yp_get_default_domain(&_pw_yp_domain))
3832917Swollman		  return 0;
3842917Swollman	}
3852917Swollman
3862917Swollman	if(!_pw_stepping_yp) {
3872917Swollman		if(key) free(key);
3882917Swollman		rv = yp_first(_pw_yp_domain, "passwd.byname",
3892917Swollman			      &key, &keylen, &result, &resultlen);
3902917Swollman		if(rv) {
3912917Swollman			return 0;
3922917Swollman		}
3932917Swollman		_pw_stepping_yp = 1;
3942917Swollman		goto unpack;
3952917Swollman	} else {
3962917Swollmantryagain:
3972917Swollman		lastkey = key;
3982917Swollman		rv = yp_next(_pw_yp_domain, "passwd.byname", key, keylen,
3992917Swollman			     &key, &keylen, &result, &resultlen);
4002917Swollman		free(lastkey);
4012917Swollmanunpack:
4022917Swollman		if(rv) {
4032917Swollman			_pw_stepping_yp = 0;
4042917Swollman			return 0;
4052917Swollman		}
4062917Swollman
4072917Swollman		if(resultlen > sizeof(resultbuf)) {
4082917Swollman			free(result);
4092917Swollman			goto tryagain;
4102917Swollman		}
4112917Swollman
4122917Swollman		strcpy(resultbuf, result);
4132917Swollman		free(result);
4142917Swollman		if(result = strchr(resultbuf, '\n')) *result = '\0';
4152917Swollman		_pw_breakout_yp(pw, resultbuf);
4162917Swollman	}
4172917Swollman	return 1;
4182917Swollman}
4192917Swollman
4202917Swollman#endif /* YP */
421