getpwent.c revision 15668
119370Spst/*
219370Spst * Copyright (c) 1988, 1993
319370Spst *	The Regents of the University of California.  All rights reserved.
4130803Smarcel *
5130803Smarcel * Redistribution and use in source and binary forms, with or without
6130803Smarcel * modification, are permitted provided that the following conditions
7130803Smarcel * are met:
8130803Smarcel * 1. Redistributions of source code must retain the above copyright
9130803Smarcel *    notice, this list of conditions and the following disclaimer.
10130803Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11130803Smarcel *    notice, this list of conditions and the following disclaimer in the
12130803Smarcel *    documentation and/or other materials provided with the distribution.
13130803Smarcel * 3. All advertising materials mentioning features or use of this software
14130803Smarcel *    must display the following acknowledgement:
15130803Smarcel *	This product includes software developed by the University of
16130803Smarcel *	California, Berkeley and its contributors.
17130803Smarcel * 4. Neither the name of the University nor the names of its contributors
18130803Smarcel *    may be used to endorse or promote products derived from this software
19130803Smarcel *    without specific prior written permission.
20130803Smarcel *
21130803Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22130803Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23130803Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24130803Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25130803Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26130803Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27130803Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28130803Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29130803Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30130803Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31130803Smarcel * SUCH DAMAGE.
32130803Smarcel */
33130803Smarcel
34130803Smarcel#if defined(LIBC_SCCS) && !defined(lint)
35130803Smarcelstatic char sccsid[] = "@(#)getpwent.c	8.1 (Berkeley) 6/4/93";
36130803Smarcel#endif /* LIBC_SCCS and not lint */
37130803Smarcel
38130803Smarcel#include <stdio.h>
39130803Smarcel#include <sys/param.h>
40130803Smarcel#include <fcntl.h>
41130803Smarcel#include <db.h>
42130803Smarcel#include <syslog.h>
43130803Smarcel#include <pwd.h>
44130803Smarcel#include <utmp.h>
45130803Smarcel#include <errno.h>
46130803Smarcel#include <unistd.h>
47130803Smarcel#include <stdlib.h>
48130803Smarcel#include <string.h>
49130803Smarcel#include <limits.h>
50130803Smarcel#include <grp.h>
51130803Smarcel
52130803Smarcelstatic struct passwd _pw_passwd;	/* password structure */
53130803Smarcelstatic DB *_pw_db;			/* password database */
54130803Smarcelstatic int _pw_keynum;			/* key counter */
55130803Smarcelstatic int _pw_stayopen;		/* keep fd's open */
56130803Smarcel#ifdef YP
57130803Smarcel#include <rpc/rpc.h>
58130803Smarcel#include <rpcsvc/yp_prot.h>
59130803Smarcel#include <rpcsvc/ypclnt.h>
60130803Smarcel
61130803Smarcelstatic struct passwd _pw_copy;
62130803Smarcelstatic DBT empty = { NULL, 0 };
63130803Smarcelstatic DB *_ypcache = (DB *)NULL;
64130803Smarcelstatic int _yp_exclusions = 0;
65130803Smarcelstatic int _yp_enabled;			/* set true when yp enabled */
66130803Smarcelstatic int _pw_stepping_yp;		/* set true when stepping thru map */
67130803Smarcelstatic char _ypnam[YPMAXRECORD];
68130803Smarcelstatic int _gotmaster;
69130803Smarcelstatic char *_pw_yp_domain;
70130803Smarcelstatic inline int unwind __P(( char * ));
71130803Smarcelstatic inline void _ypinitdb __P(( void ));
72130803Smarcelstatic int _havemaster __P((char *));
73130803Smarcelstatic int _getyppass __P((struct passwd *, const char *, const char * ));
74130803Smarcelstatic int _nextyppass __P((struct passwd *));
75130803Smarcel#endif
76130803Smarcelstatic int __hashpw(), __initdb();
77130803Smarcel
78130803Smarcelstruct passwd *
79130803Smarcelgetpwent()
80130803Smarcel{
81130803Smarcel	DBT key;
82130803Smarcel	char bf[sizeof(_pw_keynum) + 1];
83130803Smarcel	int rv;
84130803Smarcel
85130803Smarcel	if (!_pw_db && !__initdb())
86130803Smarcel		return((struct passwd *)NULL);
87130803Smarcel
88130803Smarcel#ifdef YP
89130803Smarcel	if(_pw_stepping_yp) {
90130803Smarcel		_pw_passwd = _pw_copy;
91130803Smarcel		if (unwind((char *)&_ypnam))
92130803Smarcel			return(&_pw_passwd);
93130803Smarcel	}
94130803Smarcel#endif
95130803Smarceltryagain:
96130803Smarcel
97130803Smarcel	++_pw_keynum;
98130803Smarcel	bf[0] = _PW_KEYBYNUM;
99130803Smarcel	bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
100130803Smarcel	key.data = (u_char *)bf;
101130803Smarcel	key.size = sizeof(_pw_keynum) + 1;
102130803Smarcel	rv = __hashpw(&key);
103130803Smarcel	if(!rv) return (struct passwd *)NULL;
104130803Smarcel#ifdef YP
105130803Smarcel	if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
106130803Smarcel		bzero((char *)&_ypnam, sizeof(_ypnam));
107130803Smarcel		bcopy(_pw_passwd.pw_name, _ypnam,
108130803Smarcel			strlen(_pw_passwd.pw_name));
109130803Smarcel		_pw_copy = _pw_passwd;
110130803Smarcel		if (unwind((char *)&_ypnam) == 0)
111130803Smarcel			goto tryagain;
112130803Smarcel		else
113130803Smarcel			return(&_pw_passwd);
114130803Smarcel	}
115130803Smarcel#else
116130803Smarcel	/* Ignore YP password file entries when YP is disabled. */
117130803Smarcel	if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
118130803Smarcel		goto tryagain;
119130803Smarcel	}
120130803Smarcel#endif
121130803Smarcel	return(&_pw_passwd);
122130803Smarcel}
123130803Smarcel
124130803Smarcelstruct passwd *
125130803Smarcelgetpwnam(name)
126130803Smarcel	const char *name;
127130803Smarcel{
128130803Smarcel	DBT key;
129130803Smarcel	int len, rval;
130130803Smarcel	char bf[UT_NAMESIZE + 2];
131130803Smarcel
132130803Smarcel	if (!_pw_db && !__initdb())
133130803Smarcel		return((struct passwd *)NULL);
134130803Smarcel
135130803Smarcel	bf[0] = _PW_KEYBYNAME;
136130803Smarcel	len = strlen(name);
137130803Smarcel	bcopy(name, bf + 1, MIN(len, UT_NAMESIZE));
138130803Smarcel	key.data = (u_char *)bf;
139130803Smarcel	key.size = len + 1;
140130803Smarcel	rval = __hashpw(&key);
141130803Smarcel
142130803Smarcel#ifdef YP
143130803Smarcel	if (!rval && _yp_enabled)
144130803Smarcel		rval = _getyppass(&_pw_passwd, name, "passwd.byname");
145130803Smarcel#endif
146130803Smarcel	/*
147130803Smarcel	 * Prevent login attempts when YP is not enabled but YP entries
148130803Smarcel	 * are in /etc/master.passwd.
149130803Smarcel	 */
150130803Smarcel	if (rval && (_pw_passwd.pw_name[0] == '+'||
151130803Smarcel			_pw_passwd.pw_name[0] == '-')) rval = 0;
152130803Smarcel
153130803Smarcel	endpwent();
154130803Smarcel	return(rval ? &_pw_passwd : (struct passwd *)NULL);
155130803Smarcel}
156130803Smarcel
157130803Smarcelstruct passwd *
158130803Smarcel#ifdef __STDC__
159130803Smarcelgetpwuid(uid_t uid)
160130803Smarcel#else
161130803Smarcelgetpwuid(uid)
162130803Smarcel	int uid;
163130803Smarcel#endif
164130803Smarcel{
165130803Smarcel	DBT key;
166130803Smarcel	int keyuid, rval;
167130803Smarcel	char bf[sizeof(keyuid) + 1];
168130803Smarcel
169130803Smarcel	if (!_pw_db && !__initdb())
170130803Smarcel		return((struct passwd *)NULL);
171130803Smarcel
172130803Smarcel	bf[0] = _PW_KEYBYUID;
173130803Smarcel	keyuid = uid;
174130803Smarcel	bcopy(&keyuid, bf + 1, sizeof(keyuid));
175130803Smarcel	key.data = (u_char *)bf;
176130803Smarcel	key.size = sizeof(keyuid) + 1;
177130803Smarcel	rval = __hashpw(&key);
178130803Smarcel
179130803Smarcel#ifdef YP
180130803Smarcel	if (!rval && _yp_enabled) {
181130803Smarcel		char ypbuf[16];	/* big enough for 32-bit uids and then some */
182130803Smarcel		snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid);
183130803Smarcel		rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid");
184130803Smarcel	}
185130803Smarcel#endif
186130803Smarcel	/*
187130803Smarcel	 * Prevent login attempts when YP is not enabled but YP entries
188130803Smarcel	 * are in /etc/master.passwd.
189130803Smarcel	 */
190130803Smarcel	if (rval && (_pw_passwd.pw_name[0] == '+'||
191130803Smarcel			_pw_passwd.pw_name[0] == '-')) rval = 0;
192130803Smarcel
193130803Smarcel	endpwent();
194130803Smarcel	return(rval ? &_pw_passwd : (struct passwd *)NULL);
195130803Smarcel}
196130803Smarcel
197130803Smarcelint
198130803Smarcelsetpassent(stayopen)
199130803Smarcel	int stayopen;
200130803Smarcel{
201130803Smarcel	_pw_keynum = 0;
202130803Smarcel#ifdef YP
203130803Smarcel	_pw_stepping_yp = 0;
204130803Smarcel#endif
205130803Smarcel	_pw_stayopen = stayopen;
206130803Smarcel	return(1);
207130803Smarcel}
208130803Smarcel
209130803Smarcelint
210130803Smarcelsetpwent()
211130803Smarcel{
212130803Smarcel	_pw_keynum = 0;
213130803Smarcel#ifdef YP
214130803Smarcel	_pw_stepping_yp = 0;
215130803Smarcel#endif
216130803Smarcel	_pw_stayopen = 0;
217130803Smarcel	return(1);
218130803Smarcel}
219130803Smarcel
220130803Smarcelvoid
221130803Smarcelendpwent()
222130803Smarcel{
223130803Smarcel	_pw_keynum = 0;
224130803Smarcel#ifdef YP
225130803Smarcel	_pw_stepping_yp = 0;
226130803Smarcel#endif
227130803Smarcel	if (_pw_db) {
228130803Smarcel		(void)(_pw_db->close)(_pw_db);
229130803Smarcel		_pw_db = (DB *)NULL;
230130803Smarcel	}
231130803Smarcel#ifdef YP
232130803Smarcel	if (_ypcache) {
233130803Smarcel		(void)(_ypcache->close)(_ypcache);
234130803Smarcel		_ypcache = (DB *)NULL;
235130803Smarcel		_yp_exclusions = 0;
236130803Smarcel	}
237130803Smarcel#endif
238130803Smarcel}
239130803Smarcel
240130803Smarcelstatic
241130803Smarcel__initdb()
242130803Smarcel{
243130803Smarcel	static int warned;
244130803Smarcel	char *p;
245130803Smarcel
246130803Smarcel	p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
247130803Smarcel	_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
248130803Smarcel	if (_pw_db) {
249130803Smarcel#ifdef YP
250130803Smarcel		DBT key, data;
251130803Smarcel		char buf[] = { _PW_KEYYPENABLED };
252130803Smarcel		key.data = buf;
253130803Smarcel		key.size = 1;
254130803Smarcel		if ((_pw_db->get)(_pw_db, &key, &data, 0)) {
255130803Smarcel			_yp_enabled = 0;
256130803Smarcel		} else {
257130803Smarcel			_yp_enabled = (int)*((char *)data.data) - 2;
258130803Smarcel		/* Don't even bother with this if we aren't root. */
259130803Smarcel			if (!geteuid()) {
260130803Smarcel				if (!_pw_yp_domain)
261130803Smarcel					if (yp_get_default_domain(&_pw_yp_domain))
262130803Smarcel					return(1);
263130803Smarcel				_gotmaster = _havemaster(_pw_yp_domain);
264130803Smarcel			} else _gotmaster = 0;
265130803Smarcel			if (!_ypcache)
266130803Smarcel				_ypinitdb();
267130803Smarcel		}
268130803Smarcel#endif
269130803Smarcel		return(1);
270130803Smarcel	}
271130803Smarcel	if (!warned++)
272130803Smarcel		syslog(LOG_ERR, "%s: %m", p);
273130803Smarcel	return(0);
274130803Smarcel}
275130803Smarcel
276130803Smarcelstatic
277130803Smarcel__hashpw(key)
278130803Smarcel	DBT *key;
279130803Smarcel{
280130803Smarcel	register char *p, *t;
281130803Smarcel	static u_int max;
282130803Smarcel	static char *line;
283130803Smarcel	DBT data;
284130803Smarcel
285130803Smarcel	if ((_pw_db->get)(_pw_db, key, &data, 0))
286130803Smarcel		return(0);
287130803Smarcel	p = (char *)data.data;
288130803Smarcel	if (data.size > max && !(line = realloc(line, max += 1024)))
289130803Smarcel		return(0);
290130803Smarcel
291130803Smarcel	t = line;
292130803Smarcel#define	EXPAND(e)	e = t; while (*t++ = *p++);
293130803Smarcel	EXPAND(_pw_passwd.pw_name);
294130803Smarcel	EXPAND(_pw_passwd.pw_passwd);
295130803Smarcel	bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
296130803Smarcel	p += sizeof(int);
297130803Smarcel	bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
298130803Smarcel	p += sizeof(int);
299130803Smarcel	bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t));
300130803Smarcel	p += sizeof(time_t);
301130803Smarcel	EXPAND(_pw_passwd.pw_class);
302130803Smarcel	EXPAND(_pw_passwd.pw_gecos);
303130803Smarcel	EXPAND(_pw_passwd.pw_dir);
304130803Smarcel	EXPAND(_pw_passwd.pw_shell);
305130803Smarcel	bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
306130803Smarcel	p += sizeof(time_t);
307130803Smarcel	bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
308130803Smarcel	p += sizeof _pw_passwd.pw_fields;
309130803Smarcel	return(1);
310130803Smarcel}
311130803Smarcel
312130803Smarcel#ifdef YP
313130803Smarcel
314130803Smarcel/*
315130803Smarcel * Create a DB hash database in memory. Bet you didn't know you
316130803Smarcel * could do a dbopen() will a NULL filename, did you.
317130803Smarcel */
318130803Smarcelstatic inline void _ypinitdb()
319130803Smarcel{
320130803Smarcel	if (_ypcache == (DB *)NULL)
321130803Smarcel		_ypcache = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
322130803Smarcel	return;
323130803Smarcel}
324130803Smarcel
325130803Smarcel/*
326130803Smarcel * See if a user is in the blackballed list.
327130803Smarcel */
328130803Smarcelstatic inline int lookup(name)
329130803Smarcel	char *name;
330130803Smarcel{
331130803Smarcel	DBT key;
332130803Smarcel
333130803Smarcel	if (!_yp_exclusions)
334130803Smarcel		return(0);
335130803Smarcel
336130803Smarcel	key.data = name;
337130803Smarcel	key.size = strlen(name);
338130803Smarcel
339130803Smarcel	if ((_ypcache->get)(_ypcache, &key, &empty, 0)) {
340130803Smarcel		return(0);
341130803Smarcel	}
342130803Smarcel
343130803Smarcel	return(1);
344130803Smarcel}
345130803Smarcel
346130803Smarcel/*
347130803Smarcel * Store a blackballed user in an in-core hash database.
348130803Smarcel */
349130803Smarcelstatic inline void store(key)
350130803Smarcel	char *key;
351130803Smarcel{
352130803Smarcel	DBT lkey;
353130803Smarcel/*
354130803Smarcel	if (lookup(key))
355130803Smarcel		return;
356130803Smarcel*/
357130803Smarcel
358130803Smarcel	_yp_exclusions = 1;
359130803Smarcel
360130803Smarcel	lkey.data = key;
361130803Smarcel	lkey.size = strlen(key);
362130803Smarcel
363130803Smarcel	(void)(_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE);
364130803Smarcel}
365130803Smarcel
366130803Smarcel/*
367130803Smarcel * Parse the + entries in the password database and do appropriate
368130803Smarcel * NIS lookups. While ugly to look at, this is optimized to do only
369130803Smarcel * as many lookups as are absolutely necessary in any given case.
370130803Smarcel * Basically, the getpwent() function will feed us + and - lines
371130803Smarcel * as they appear in the database. For + lines, we do netgroup/group
372130803Smarcel * and user lookups to find all usernames that match the rule and
373130803Smarcel * extract them from the NIS passwd maps. For - lines, we save the
374130803Smarcel * matching names in a database and a) exlude them, and b) make sure
375130803Smarcel * we don't consider them when processing other + lines that appear
376130803Smarcel * later.
377130803Smarcel */
378130803Smarcelstatic inline int unwind(grp)
379130803Smarcel	char *grp;
380130803Smarcel{
381130803Smarcel	char *user, *host, *domain;
382130803Smarcel	static int latch = 0;
383130803Smarcel	static struct group *gr = NULL;
384130803Smarcel	int rv = 0;
385130803Smarcel
386130803Smarcel	if (grp[0] == '+') {
387130803Smarcel		if (strlen(grp) == 1) {
388130803Smarcel			return(_nextyppass(&_pw_passwd));
389130803Smarcel		}
390130803Smarcel		if (grp[1] == '@') {
391130803Smarcel			_pw_stepping_yp = 1;
392130803Smarcelgrpagain:
393130803Smarcel			if (gr != NULL) {
394130803Smarcel				if (*gr->gr_mem != NULL) {
395130803Smarcel					if (lookup(*gr->gr_mem)) {
396130803Smarcel						gr->gr_mem++;
397130803Smarcel						goto grpagain;
398130803Smarcel					}
399130803Smarcel					rv = _getyppass(&_pw_passwd,
400130803Smarcel							*gr->gr_mem,
401130803Smarcel							"passwd.byname");
402130803Smarcel					gr->gr_mem++;
403130803Smarcel					return(rv);
404130803Smarcel				} else {
405130803Smarcel					endgrent();
406130803Smarcel					latch = 0;
407130803Smarcel					gr = NULL;
408130803Smarcel					return(0);
409130803Smarcel				}
410130803Smarcel			}
411130803Smarcel			if (!latch) {
412130803Smarcel				setnetgrent(grp+2);
413130803Smarcel				latch++;
414130803Smarcel			}
415130803Smarcelagain:
416130803Smarcel			if (getnetgrent(&host, &user, &domain) == NULL) {
417130803Smarcel				if ((gr = getgrnam(grp+2)) != NULL)
418130803Smarcel					goto grpagain;
419130803Smarcel				latch = 0;
420130803Smarcel				_pw_stepping_yp = 0;
421130803Smarcel				return(0);
422130803Smarcel			} else {
423130803Smarcel				if (lookup(user))
424130803Smarcel					goto again;
425130803Smarcel				if (_getyppass(&_pw_passwd, user,
426130803Smarcel							"passwd.byname"))
427130803Smarcel					return(1);
428130803Smarcel				else
429130803Smarcel					goto again;
430130803Smarcel			}
431130803Smarcel		} else {
432130803Smarcel			if (lookup(grp+1))
433130803Smarcel				return(0);
434130803Smarcel			return(_getyppass(&_pw_passwd, grp+1, "passwd.byname"));
435130803Smarcel		}
436130803Smarcel	} else {
437104990Smp		if (grp[1] == '@') {
43898944Sobrien			setnetgrent(grp+2);
43998944Sobrien			rv = 0;
44098944Sobrien			while(getnetgrent(&host, &user, &domain) != NULL) {
44198944Sobrien				store(user);
44298944Sobrien				rv++;
44398944Sobrien			}
44498944Sobrien			if (!rv && (gr = getgrnam(grp+2)) != NULL) {
44598944Sobrien				while(gr->gr_mem) {
44698944Sobrien					store(gr->gr_mem);
44798944Sobrien					gr->gr_mem++;
44898944Sobrien				}
44998944Sobrien			}
45098944Sobrien		} else {
45198944Sobrien			store(grp+1);
45298944Sobrien		}
453104990Smp	}
454104990Smp	return(0);
455104990Smp}
456104990Smp
457104990Smp/*
458104990Smp * See if a user is a member of a particular group.
459104990Smp */
460104990Smpstatic inline int ingr(grp, name)
46198944Sobrien	char *grp;
46298944Sobrien	char *name;
46398944Sobrien{
46498944Sobrien	register struct group *gr;
46598944Sobrien
46698944Sobrien	if ((gr = getgrnam(grp)) == NULL)
46798944Sobrien		return(0);
46898944Sobrien
46998944Sobrien	while(*gr->gr_mem) {
47098944Sobrien		if (!strcmp(*gr->gr_mem, name)) {
47198944Sobrien			endgrent();
47298944Sobrien			return(1);
47398944Sobrien		}
47498944Sobrien		gr->gr_mem++;
47598944Sobrien	}
47698944Sobrien
47798944Sobrien	endgrent();
47898944Sobrien	return(0);
47998944Sobrien}
48098944Sobrien
48198944Sobrien/*
48298944Sobrien * Check a user against the +@netgroup/-@netgroup lines listed in
48398944Sobrien * the local password database. Also checks +user/-user lines.
48498944Sobrien * If no netgroup exists that matches +@netgroup/-@netgroup,
48598944Sobrien * try searching regular groups with the same name.
48698944Sobrien */
48798944Sobrienstatic inline int verf(name)
48898944Sobrien	char *name;
48998944Sobrien{
49098944Sobrien	DBT key;
49198944Sobrien	char bf[sizeof(_pw_keynum) + 1];
49298944Sobrien	int keynum = 0;
49398944Sobrien
49498944Sobrienagain:
49598944Sobrien	++keynum;
49698944Sobrien	bf[0] = _PW_KEYYPBYNUM;
49798944Sobrien	bcopy((char *)&keynum, bf + 1, sizeof(keynum));
49898944Sobrien	key.data = (u_char *)bf;
49998944Sobrien	key.size = sizeof(keynum) + 1;
50098944Sobrien	if (!__hashpw(&key)) {
50198944Sobrien		/* Try again using old format */
50298944Sobrien		bf[0] = _PW_KEYBYNUM;
50398944Sobrien		bcopy((char *)&keynum, bf + 1, sizeof(keynum));
50498944Sobrien		key.data = (u_char *)bf;
50598944Sobrien		if (!__hashpw(&key))
50698944Sobrien			return(0);
50798944Sobrien	}
50898944Sobrien	if (_pw_passwd.pw_name[0] != '+' && (_pw_passwd.pw_name[0] != '-'))
50998944Sobrien		goto again;
51098944Sobrien	if (_pw_passwd.pw_name[0] == '+') {
51198944Sobrien		if (strlen(_pw_passwd.pw_name) == 1) /* Wildcard */
51298944Sobrien			return(1);
51398944Sobrien		if (_pw_passwd.pw_name[1] == '@') {
51498944Sobrien			if ((innetgr(_pw_passwd.pw_name+2, NULL, name,
51598944Sobrien							_pw_yp_domain) ||
51698944Sobrien			    ingr(_pw_passwd.pw_name+2, name)) && !lookup(name))
51798944Sobrien				return(1);
51898944Sobrien			else
51998944Sobrien				goto again;
52098944Sobrien		} else {
52198944Sobrien			if (!strcmp(name, _pw_passwd.pw_name+1) &&
52298944Sobrien								!lookup(name))
52398944Sobrien				return(1);
52498944Sobrien			else
52598944Sobrien				goto again;
52698944Sobrien		}
52798944Sobrien	}
52898944Sobrien	if (_pw_passwd.pw_name[0] == '-') {
52998944Sobrien		/* Note that a minus wildcard is a no-op. */
53098944Sobrien		if (_pw_passwd.pw_name[1] == '@') {
53198944Sobrien			if (innetgr(_pw_passwd.pw_name+2, NULL, name,
53298944Sobrien							_pw_yp_domain) ||
53398944Sobrien			    ingr(_pw_passwd.pw_name+2, name)) {
53498944Sobrien				store(name);
53598944Sobrien				return(0);
53698944Sobrien			} else
53798944Sobrien				goto again;
53898944Sobrien		} else {
53998944Sobrien			if (!strcmp(name, _pw_passwd.pw_name+1)) {
54098944Sobrien				store(name);
54198944Sobrien				return(0);
54298944Sobrien			} else
54398944Sobrien				goto again;
54498944Sobrien		}
54598944Sobrien
54698944Sobrien	}
54798944Sobrien	return(0);
54898944Sobrien}
54998944Sobrien
55098944Sobrienstatic int
55198944Sobrien_pw_breakout_yp(struct passwd *pw, char *res, int master)
55298944Sobrien{
55398944Sobrien	char *s, *result;
55498944Sobrien	static char resbuf[YPMAXRECORD+2];
55598944Sobrien
55698944Sobrien	/*
55798944Sobrien	 * Be triple, ultra super-duper paranoid: reject entries
55898944Sobrien	 * that start with a + or -. yp_mkdb and /var/yp/Makefile
55998944Sobrien	 * are _both_ supposed to strip these out, but you never
56098944Sobrien	 * know.
56198944Sobrien	 */
56298944Sobrien	if (*res == '+' || *res == '-')
56398944Sobrien		return 0;
56498944Sobrien
56598944Sobrien	/*
56698944Sobrien	 * The NIS protocol definition limits the size of an NIS
56798944Sobrien	 * record to YPMAXRECORD bytes. We need to do a copy to
56898944Sobrien	 * a static buffer here since the memory pointed to by
56998944Sobrien	 * res will be free()ed when this function returns.
57098944Sobrien	 */
57198944Sobrien	strncpy((char *)&resbuf, res, YPMAXRECORD);
57298944Sobrien	result = (char *)&resbuf;
57398944Sobrien
57498944Sobrien	/*
57598944Sobrien	 * XXX Sanity check: make sure all fields are valid (no NULLs).
57698944Sobrien	 * If we find a badly formatted entry, we punt.
57798944Sobrien	 */
57898944Sobrien	if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
57998944Sobrien	/*
58098944Sobrien	 * We don't care what pw_fields says: we _always_ want the
58198944Sobrien	 * username returned to us by NIS.
58298944Sobrien	 */
58398944Sobrien	pw->pw_name = s;
58498944Sobrien	pw->pw_fields |= _PWF_NAME;
58598944Sobrien
58698944Sobrien	if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
58798944Sobrien	if(!(pw->pw_fields & _PWF_PASSWD)) {
58898944Sobrien		pw->pw_passwd = s;
58998944Sobrien		pw->pw_fields |= _PWF_PASSWD;
59098944Sobrien	}
59198944Sobrien
59298944Sobrien	if ((s = strsep(&result, ":")) == NULL) return 0; /* uid */
59398944Sobrien	if(!(pw->pw_fields & _PWF_UID)) {
59498944Sobrien		pw->pw_uid = atoi(s);
59598944Sobrien		pw->pw_fields |= _PWF_UID;
59698944Sobrien	}
59798944Sobrien
59898944Sobrien	if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
59998944Sobrien	if(!(pw->pw_fields & _PWF_GID))  {
60098944Sobrien		pw->pw_gid = atoi(s);
60198944Sobrien		pw->pw_fields |= _PWF_GID;
60298944Sobrien	}
60398944Sobrien
60498944Sobrien	if (master) {
60598944Sobrien		if ((s = strsep(&result, ":")) == NULL) return 0; /* class */
60698944Sobrien		if(!(pw->pw_fields & _PWF_CLASS))  {
60798944Sobrien			pw->pw_class = s;
60898944Sobrien			pw->pw_fields |= _PWF_CLASS;
60998944Sobrien		}
61098944Sobrien
61198944Sobrien		if ((s = strsep(&result, ":")) == NULL) return 0; /* change */
61298944Sobrien		if(!(pw->pw_fields & _PWF_CHANGE))  {
61398944Sobrien			pw->pw_change = atol(s);
61498944Sobrien			pw->pw_fields |= _PWF_CHANGE;
61598944Sobrien		}
61698944Sobrien
61798944Sobrien		if ((s = strsep(&result, ":")) == NULL) return 0; /* expire */
61898944Sobrien		if(!(pw->pw_fields & _PWF_EXPIRE))  {
61998944Sobrien			pw->pw_expire = atol(s);
62098944Sobrien			pw->pw_fields |= _PWF_EXPIRE;
62198944Sobrien		}
62298944Sobrien	}
62398944Sobrien
62498944Sobrien	if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */
62598944Sobrien	if(!(pw->pw_fields & _PWF_GECOS)) {
62698944Sobrien		pw->pw_gecos = s;
62798944Sobrien		pw->pw_fields |= _PWF_GECOS;
62898944Sobrien	}
62998944Sobrien
63098944Sobrien	if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */
63198944Sobrien	if(!(pw->pw_fields & _PWF_DIR)) {
63298944Sobrien		pw->pw_dir = s;
63398944Sobrien		pw->pw_fields |= _PWF_DIR;
63498944Sobrien	}
63598944Sobrien
63698944Sobrien	if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */
63798944Sobrien	if(!(pw->pw_fields & _PWF_SHELL)) {
63898944Sobrien		pw->pw_shell = s;
63998944Sobrien		pw->pw_fields |= _PWF_SHELL;
64098944Sobrien	}
64198944Sobrien
64298944Sobrien	/* Be consistent. */
64398944Sobrien	if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0';
64498944Sobrien
64598944Sobrien	return 1;
64698944Sobrien}
64798944Sobrien
64898944Sobrienstatic int
64998944Sobrien_havemaster(char *_pw_yp_domain)
65098944Sobrien{
65198944Sobrien	int keylen, resultlen;
65298944Sobrien	char *key, *result;
65398944Sobrien
65498944Sobrien	if (yp_first(_pw_yp_domain, "master.passwd.byname",
65598944Sobrien		&key, &keylen, &result, &resultlen)) {
65698944Sobrien		return 0;
65798944Sobrien	}
65898944Sobrien	free(result);
65998944Sobrien	return 1;
66098944Sobrien}
66198944Sobrien
66298944Sobrienstatic int
66398944Sobrien_getyppass(struct passwd *pw, const char *name, const char *map)
66498944Sobrien{
66598944Sobrien	char *result, *s;
66698944Sobrien	int resultlen;
66798944Sobrien	int rv;
66898944Sobrien	char mastermap[YPMAXRECORD];
66998944Sobrien
67098944Sobrien	if(!_pw_yp_domain) {
67198944Sobrien		if(yp_get_default_domain(&_pw_yp_domain))
67298944Sobrien		  return 0;
67398944Sobrien	}
67498944Sobrien
67598944Sobrien	sprintf(mastermap,"%s",map);
67698944Sobrien
67798944Sobrien	if (_gotmaster)
67898944Sobrien		sprintf(mastermap,"master.%s", map);
67998944Sobrien
68098944Sobrien	if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name),
68198944Sobrien		    &result, &resultlen))
68298944Sobrien		return 0;
68398944Sobrien
68498944Sobrien	if (!_pw_stepping_yp) {
68598944Sobrien		s = strchr(result, ':');
68698944Sobrien		if (s) {
68798944Sobrien			*s = '\0';
68898944Sobrien		} else {
68998944Sobrien			/* Must be a malformed entry if no colons. */
69098944Sobrien			free(result);
69198944Sobrien			return(0);
69298944Sobrien		}
69398944Sobrien
69498944Sobrien		if (!verf(result)) {
69598944Sobrien			*s = ':';
69698944Sobrien			free(result);
69798944Sobrien			return(0);
69898944Sobrien		}
69998944Sobrien
70098944Sobrien		*s = ':'; /* Put back the colon we previously replaced with a NUL. */
70198944Sobrien	}
70298944Sobrien
70398944Sobrien	rv = _pw_breakout_yp(pw, result, _gotmaster);
70498944Sobrien	free(result);
70598944Sobrien	return(rv);
70698944Sobrien}
70798944Sobrien
70898944Sobrienstatic int
70998944Sobrien_nextyppass(struct passwd *pw)
71098944Sobrien{
71198944Sobrien	static char *key;
71298944Sobrien	static int keylen;
71398944Sobrien	char *lastkey, *result, *s;
71498944Sobrien	int resultlen;
71598944Sobrien	int rv;
71698944Sobrien	char *map = "passwd.byname";
71798944Sobrien
71898944Sobrien	if(!_pw_yp_domain) {
71998944Sobrien		if(yp_get_default_domain(&_pw_yp_domain))
72098944Sobrien		  return 0;
72198944Sobrien	}
72298944Sobrien
72398944Sobrien	if (_gotmaster)
72498944Sobrien		map = "master.passwd.byname";
72598944Sobrien
72698944Sobrien	if(!_pw_stepping_yp) {
72798944Sobrien		if(key) free(key);
72898944Sobrien			rv = yp_first(_pw_yp_domain, map,
72998944Sobrien				      &key, &keylen, &result, &resultlen);
73098944Sobrien		if(rv) {
73198944Sobrien			return 0;
73298944Sobrien		}
73398944Sobrien		_pw_stepping_yp = 1;
73498944Sobrien		goto unpack;
73598944Sobrien	} else {
73698944Sobrientryagain:
73798944Sobrien		lastkey = key;
73898944Sobrien			rv = yp_next(_pw_yp_domain, map, key, keylen,
73998944Sobrien			     &key, &keylen, &result, &resultlen);
74098944Sobrien		free(lastkey);
74198944Sobrienunpack:
74298944Sobrien		if(rv) {
74398944Sobrien			_pw_stepping_yp = 0;
74498944Sobrien			return 0;
74598944Sobrien		}
74698944Sobrien
74798944Sobrien		s = strchr(result, ':');
74898944Sobrien		if (s) {
74998944Sobrien			*s = '\0';
75098944Sobrien		} else {
75198944Sobrien			/* Must be a malformed entry if no colons. */
75298944Sobrien			free(result);
75398944Sobrien			goto tryagain;
75498944Sobrien		}
75598944Sobrien
75698944Sobrien		if (lookup(result)) {
75798944Sobrien			*s = ':';
75898944Sobrien			free(result);
75998944Sobrien			goto tryagain;
76098944Sobrien		}
76198944Sobrien
76298944Sobrien		*s = ':'; /* Put back the colon we previously replaced with a NUL. */
76398944Sobrien		if (_pw_breakout_yp(pw, result, _gotmaster)) {
76498944Sobrien			free(result);
76598944Sobrien			return(1);
76698944Sobrien		} else {
76798944Sobrien			free(result);
76898944Sobrien			goto tryagain;
76998944Sobrien		}
77098944Sobrien	}
77198944Sobrien}
77298944Sobrien
77398944Sobrien#endif /* YP */
77498944Sobrien