xref: /freebsd/lib/libc/gen/getpwent.c (revision 3948edc24ce0e300500f56d903a4cd69ab8bcbf7)
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