getpwent.c revision 47721
1/*
2 * Copyright (c) 1988, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if defined(LIBC_SCCS) && !defined(lint)
35static char sccsid[] = "@(#)getpwent.c	8.2 (Berkeley) 4/27/95";
36#endif /* LIBC_SCCS and not lint */
37
38#include <stdio.h>
39#include <sys/param.h>
40#include <fcntl.h>
41#include <db.h>
42#include <syslog.h>
43#include <pwd.h>
44#include <utmp.h>
45#include <errno.h>
46#include <unistd.h>
47#include <stdlib.h>
48#include <string.h>
49#include <limits.h>
50#include <grp.h>
51
52extern void setnetgrent __P(( char * ));
53extern int getnetgrent __P(( char **, char **, char ** ));
54extern int innetgr __P(( const char *, const char *, const char *, const char * ));
55
56/*
57 * The lookup techniques and data extraction code here must be kept
58 * in sync with that in `pwd_mkdb'.
59 */
60
61static struct passwd _pw_passwd;	/* password structure */
62static DB *_pw_db;			/* password database */
63static int _pw_keynum;			/* key counter */
64static int _pw_stayopen;		/* keep fd's open */
65#ifdef YP
66#include <rpc/rpc.h>
67#include <rpcsvc/yp_prot.h>
68#include <rpcsvc/ypclnt.h>
69
70static struct passwd _pw_copy;
71static DBT empty = { NULL, 0 };
72static DB *_ypcache = (DB *)NULL;
73static int _yp_exclusions = 0;
74static int _yp_enabled = -1;
75static int _pw_stepping_yp;		/* set true when stepping thru map */
76static char _ypnam[YPMAXRECORD];
77#define YP_HAVE_MASTER 2
78#define YP_HAVE_ADJUNCT 1
79#define YP_HAVE_NONE 0
80static int _gotmaster;
81static char *_pw_yp_domain;
82static inline int unwind __P(( char * ));
83static void _ypinitdb __P(( void ));
84static int _havemaster __P((char *));
85static int _getyppass __P((struct passwd *, const char *, const char * ));
86static int _nextyppass __P((struct passwd *));
87static inline int lookup __P((const char *));
88static inline void store __P((const char *));
89static inline int ingr __P((const char *, const char*));
90static inline int verf __P((const char *));
91static char * _get_adjunct_pw __P((const char *));
92#endif
93static int __hashpw(DBT *);
94static int __initdb(void);
95
96struct passwd *
97getpwent()
98{
99	DBT key;
100	char bf[sizeof(_pw_keynum) + 1];
101	int rv;
102
103	if (!_pw_db && !__initdb())
104		return((struct passwd *)NULL);
105
106#ifdef YP
107	if(_pw_stepping_yp) {
108		_pw_passwd = _pw_copy;
109		if (unwind((char *)&_ypnam))
110			return(&_pw_passwd);
111	}
112#endif
113tryagain:
114
115	++_pw_keynum;
116	bf[0] = _PW_KEYBYNUM;
117	bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
118	key.data = (u_char *)bf;
119	key.size = sizeof(_pw_keynum) + 1;
120	rv = __hashpw(&key);
121	if(!rv) return (struct passwd *)NULL;
122#ifdef YP
123	if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
124		if (_yp_enabled == -1)
125			_ypinitdb();
126		bzero((char *)&_ypnam, sizeof(_ypnam));
127		bcopy(_pw_passwd.pw_name, _ypnam,
128			strlen(_pw_passwd.pw_name));
129		_pw_copy = _pw_passwd;
130		if (unwind((char *)&_ypnam) == 0)
131			goto tryagain;
132		else
133			return(&_pw_passwd);
134	}
135#else
136	/* Ignore YP password file entries when YP is disabled. */
137	if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
138		goto tryagain;
139	}
140#endif
141	return(&_pw_passwd);
142}
143
144struct passwd *
145getpwnam(name)
146	const char *name;
147{
148	DBT key;
149	int len, rval;
150	char bf[UT_NAMESIZE + 2];
151
152	if (!_pw_db && !__initdb())
153		return((struct passwd *)NULL);
154
155	bf[0] = _PW_KEYBYNAME;
156	len = strlen(name);
157	if (len > UT_NAMESIZE)
158		return(NULL);
159	bcopy(name, bf + 1, len);
160	key.data = (u_char *)bf;
161	key.size = len + 1;
162	rval = __hashpw(&key);
163
164#ifdef YP
165	if (!rval) {
166		if (_yp_enabled == -1)
167			_ypinitdb();
168		if (_yp_enabled)
169			rval = _getyppass(&_pw_passwd, name, "passwd.byname");
170	}
171#endif
172	/*
173	 * Prevent login attempts when YP is not enabled but YP entries
174	 * are in /etc/master.passwd.
175	 */
176	if (rval && (_pw_passwd.pw_name[0] == '+'||
177			_pw_passwd.pw_name[0] == '-')) rval = 0;
178
179	endpwent();
180	return(rval ? &_pw_passwd : (struct passwd *)NULL);
181}
182
183struct passwd *
184getpwuid(uid)
185	uid_t uid;
186{
187	DBT key;
188	int keyuid, rval;
189	char bf[sizeof(keyuid) + 1];
190
191	if (!_pw_db && !__initdb())
192		return((struct passwd *)NULL);
193
194	bf[0] = _PW_KEYBYUID;
195	keyuid = uid;
196	bcopy(&keyuid, bf + 1, sizeof(keyuid));
197	key.data = (u_char *)bf;
198	key.size = sizeof(keyuid) + 1;
199	rval = __hashpw(&key);
200
201#ifdef YP
202	if (!rval) {
203		if (_yp_enabled == -1)
204			_ypinitdb();
205		if (_yp_enabled) {
206			char ypbuf[16];	/* big enough for 32-bit uids */
207			snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid);
208			rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid");
209		}
210	}
211#endif
212	/*
213	 * Prevent login attempts when YP is not enabled but YP entries
214	 * are in /etc/master.passwd.
215	 */
216	if (rval && (_pw_passwd.pw_name[0] == '+'||
217			_pw_passwd.pw_name[0] == '-')) rval = 0;
218
219	endpwent();
220	return(rval ? &_pw_passwd : (struct passwd *)NULL);
221}
222
223int
224setpassent(stayopen)
225	int stayopen;
226{
227	_pw_keynum = 0;
228#ifdef YP
229	_pw_stepping_yp = 0;
230#endif
231	_pw_stayopen = stayopen;
232	return(1);
233}
234
235void
236setpwent()
237{
238	(void)setpassent(0);
239}
240
241void
242endpwent()
243{
244	_pw_keynum = 0;
245#ifdef YP
246	_pw_stepping_yp = 0;
247#endif
248	if (_pw_db) {
249		(void)(_pw_db->close)(_pw_db);
250		_pw_db = (DB *)NULL;
251	}
252#ifdef YP
253	if (_ypcache) {
254		(void)(_ypcache->close)(_ypcache);
255		_ypcache = (DB *)NULL;
256		_yp_exclusions = 0;
257	}
258	/* Fix for PR #12008 */
259	_yp_enabled = -1;
260#endif
261}
262
263static int
264__initdb()
265{
266	static int warned;
267	char *p;
268
269	p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
270	_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
271	if (_pw_db)
272		return(1);
273	if (!warned++)
274		syslog(LOG_ERR, "%s: %m", p);
275	return(0);
276}
277
278static int
279__hashpw(key)
280	DBT *key;
281{
282	register char *p, *t;
283	static u_int max;
284	static char *line;
285	DBT data;
286
287	if ((_pw_db->get)(_pw_db, key, &data, 0))
288		return(0);
289	p = (char *)data.data;
290
291	/* Increase buffer size for long lines if necessary. */
292	if (data.size > max) {
293		max = data.size + 1024;
294		if (!(line = reallocf(line, max)))
295			return(0);
296	}
297
298	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
299	t = line;
300#define	EXPAND(e)	e = t; while ( (*t++ = *p++) );
301#define	SCALAR(v)	memmove(&(v), p, sizeof v); p += sizeof v
302	EXPAND(_pw_passwd.pw_name);
303	EXPAND(_pw_passwd.pw_passwd);
304	SCALAR(_pw_passwd.pw_uid);
305	SCALAR(_pw_passwd.pw_gid);
306	SCALAR(_pw_passwd.pw_change);
307	EXPAND(_pw_passwd.pw_class);
308	EXPAND(_pw_passwd.pw_gecos);
309	EXPAND(_pw_passwd.pw_dir);
310	EXPAND(_pw_passwd.pw_shell);
311	SCALAR(_pw_passwd.pw_expire);
312	bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
313	p += sizeof _pw_passwd.pw_fields;
314	return(1);
315}
316
317#ifdef YP
318
319static void
320_ypinitdb()
321{
322	DBT key, data;
323	char buf[] = { _PW_KEYYPENABLED };
324	key.data = buf;
325	key.size = 1;
326	_yp_enabled = 0;
327	if ((_pw_db->get)(_pw_db, &key, &data, 0) == 0) {
328		_yp_enabled = (int)*((char *)data.data) - 2;
329		/* Don't even bother with this if we aren't root. */
330		if (!geteuid()) {
331			if (!_pw_yp_domain)
332				if (yp_get_default_domain(&_pw_yp_domain))
333					return;
334			_gotmaster = _havemaster(_pw_yp_domain);
335		} else _gotmaster = YP_HAVE_NONE;
336		/*
337		 * Create a DB hash database in memory. Bet you didn't know you
338		 * could do a dbopen() with a NULL filename, did you.
339		 */
340		if (_ypcache == (DB *)NULL)
341			_ypcache = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
342	}
343}
344
345/*
346 * See if a user is in the blackballed list.
347 */
348static inline int
349lookup(name)
350	const char *name;
351{
352	DBT key;
353
354	if (!_yp_exclusions)
355		return(0);
356
357	key.data = (char *)name;
358	key.size = strlen(name);
359
360	if ((_ypcache->get)(_ypcache, &key, &empty, 0)) {
361		return(0);
362	}
363
364	return(1);
365}
366
367/*
368 * Store a blackballed user in an in-core hash database.
369 */
370static inline void
371store(key)
372	const char *key;
373{
374	DBT lkey;
375/*
376	if (lookup(key))
377		return;
378*/
379
380	_yp_exclusions = 1;
381
382	lkey.data = (char *)key;
383	lkey.size = strlen(key);
384
385	(void)(_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE);
386}
387
388/*
389 * Parse the + entries in the password database and do appropriate
390 * NIS lookups. While ugly to look at, this is optimized to do only
391 * as many lookups as are absolutely necessary in any given case.
392 * Basically, the getpwent() function will feed us + and - lines
393 * as they appear in the database. For + lines, we do netgroup/group
394 * and user lookups to find all usernames that match the rule and
395 * extract them from the NIS passwd maps. For - lines, we save the
396 * matching names in a database and a) exlude them, and b) make sure
397 * we don't consider them when processing other + lines that appear
398 * later.
399 */
400static inline int
401unwind(grp)
402	char *grp;
403{
404	char *user, *host, *domain;
405	static int latch = 0;
406	static struct group *gr = NULL;
407	int rv = 0;
408
409	if (grp[0] == '+') {
410		if (strlen(grp) == 1) {
411			return(_nextyppass(&_pw_passwd));
412		}
413		if (grp[1] == '@') {
414			_pw_stepping_yp = 1;
415grpagain:
416			if (gr != NULL) {
417				if (*gr->gr_mem != NULL) {
418					if (lookup(*gr->gr_mem)) {
419						gr->gr_mem++;
420						goto grpagain;
421					}
422					rv = _getyppass(&_pw_passwd,
423							*gr->gr_mem,
424							"passwd.byname");
425					gr->gr_mem++;
426					return(rv);
427				} else {
428					endgrent();
429					latch = 0;
430					gr = NULL;
431					return(0);
432				}
433			}
434			if (!latch) {
435				setnetgrent(grp+2);
436				latch++;
437			}
438again:
439			if (getnetgrent(&host, &user, &domain) == 0) {
440				if ((gr = getgrnam(grp+2)) != NULL)
441					goto grpagain;
442				latch = 0;
443				_pw_stepping_yp = 0;
444				return(0);
445			} else {
446				if (lookup(user))
447					goto again;
448				if (_getyppass(&_pw_passwd, user,
449							"passwd.byname"))
450					return(1);
451				else
452					goto again;
453			}
454		} else {
455			if (lookup(grp+1))
456				return(0);
457			return(_getyppass(&_pw_passwd, grp+1, "passwd.byname"));
458		}
459	} else {
460		if (grp[1] == '@') {
461			setnetgrent(grp+2);
462			rv = 0;
463			while(getnetgrent(&host, &user, &domain) != 0) {
464				store(user);
465				rv++;
466			}
467			if (!rv && (gr = getgrnam(grp+2)) != NULL) {
468				while(*gr->gr_mem) {
469					store(*gr->gr_mem);
470					gr->gr_mem++;
471				}
472			}
473		} else {
474			store(grp+1);
475		}
476	}
477	return(0);
478}
479
480/*
481 * See if a user is a member of a particular group.
482 */
483static inline int
484ingr(grp, name)
485	const char *grp;
486	const char *name;
487{
488	register struct group *gr;
489
490	if ((gr = getgrnam(grp)) == NULL)
491		return(0);
492
493	while(*gr->gr_mem) {
494		if (!strcmp(*gr->gr_mem, name)) {
495			endgrent();
496			return(1);
497		}
498		gr->gr_mem++;
499	}
500
501	endgrent();
502	return(0);
503}
504
505/*
506 * Check a user against the +@netgroup/-@netgroup lines listed in
507 * the local password database. Also checks +user/-user lines.
508 * If no netgroup exists that matches +@netgroup/-@netgroup,
509 * try searching regular groups with the same name.
510 */
511static inline int
512verf(name)
513	const char *name;
514{
515	DBT key;
516	char bf[sizeof(_pw_keynum) + 1];
517	int keynum = 0;
518
519again:
520	++keynum;
521	bf[0] = _PW_KEYYPBYNUM;
522	bcopy((char *)&keynum, bf + 1, sizeof(keynum));
523	key.data = (u_char *)bf;
524	key.size = sizeof(keynum) + 1;
525	if (!__hashpw(&key)) {
526		/* Try again using old format */
527		bf[0] = _PW_KEYBYNUM;
528		bcopy((char *)&keynum, bf + 1, sizeof(keynum));
529		key.data = (u_char *)bf;
530		if (!__hashpw(&key))
531			return(0);
532	}
533	if (_pw_passwd.pw_name[0] != '+' && (_pw_passwd.pw_name[0] != '-'))
534		goto again;
535	if (_pw_passwd.pw_name[0] == '+') {
536		if (strlen(_pw_passwd.pw_name) == 1) /* Wildcard */
537			return(1);
538		if (_pw_passwd.pw_name[1] == '@') {
539			if ((innetgr(_pw_passwd.pw_name+2, NULL, name,
540							_pw_yp_domain) ||
541			    ingr(_pw_passwd.pw_name+2, name)) && !lookup(name))
542				return(1);
543			else
544				goto again;
545		} else {
546			if (!strcmp(name, _pw_passwd.pw_name+1) &&
547								!lookup(name))
548				return(1);
549			else
550				goto again;
551		}
552	}
553	if (_pw_passwd.pw_name[0] == '-') {
554		/* Note that a minus wildcard is a no-op. */
555		if (_pw_passwd.pw_name[1] == '@') {
556			if (innetgr(_pw_passwd.pw_name+2, NULL, name,
557							_pw_yp_domain) ||
558			    ingr(_pw_passwd.pw_name+2, name)) {
559				store(name);
560				return(0);
561			} else
562				goto again;
563		} else {
564			if (!strcmp(name, _pw_passwd.pw_name+1)) {
565				store(name);
566				return(0);
567			} else
568				goto again;
569		}
570
571	}
572	return(0);
573}
574
575static char *
576_get_adjunct_pw(name)
577	const char *name;
578{
579	static char adjunctbuf[YPMAXRECORD+2];
580	int rval;
581	char *result;
582	int resultlen;
583	char *map = "passwd.adjunct.byname";
584	char *s;
585
586	if ((rval = yp_match(_pw_yp_domain, map, name, strlen(name),
587		    &result, &resultlen)))
588		return(NULL);
589
590	strncpy(adjunctbuf, result, resultlen);
591	adjunctbuf[resultlen] = '\0';
592	free(result);
593	result = (char *)&adjunctbuf;
594
595	/* Don't care about the name. */
596	if ((s = strsep(&result, ":")) == NULL)
597		return (NULL); /* name */
598	if ((s = strsep(&result, ":")) == NULL)
599		return (NULL); /* password */
600
601	return(s);
602}
603
604static int
605_pw_breakout_yp(struct passwd *pw, char *res, int resultlen, int master)
606{
607	char *s, *result;
608	static char resbuf[YPMAXRECORD+2];
609
610	/*
611	 * Be triple, ultra super-duper paranoid: reject entries
612	 * that start with a + or -. yp_mkdb and /var/yp/Makefile
613	 * are _both_ supposed to strip these out, but you never
614	 * know.
615	 */
616	if (*res == '+' || *res == '-')
617		return 0;
618
619	/*
620	 * The NIS protocol definition limits the size of an NIS
621	 * record to YPMAXRECORD bytes. We need to do a copy to
622	 * a static buffer here since the memory pointed to by
623	 * res will be free()ed when this function returns.
624	 */
625	strncpy((char *)&resbuf, res, resultlen);
626	resbuf[resultlen] = '\0';
627	result = (char *)&resbuf;
628
629	/*
630	 * XXX Sanity check: make sure all fields are valid (no NULLs).
631	 * If we find a badly formatted entry, we punt.
632	 */
633	if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
634	/*
635	 * We don't care what pw_fields says: we _always_ want the
636	 * username returned to us by NIS.
637	 */
638	pw->pw_name = s;
639	pw->pw_fields |= _PWF_NAME;
640
641	if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
642	if(!(pw->pw_fields & _PWF_PASSWD)) {
643		/* SunOS passwd.adjunct hack */
644		if (master == YP_HAVE_ADJUNCT && strstr(s, "##") != NULL) {
645			char *realpw;
646			realpw = _get_adjunct_pw(pw->pw_name);
647			if (realpw == NULL)
648				pw->pw_passwd = s;
649			else
650				pw->pw_passwd = realpw;
651		} else {
652			pw->pw_passwd = s;
653		}
654		pw->pw_fields |= _PWF_PASSWD;
655	}
656
657	if ((s = strsep(&result, ":")) == NULL) return 0; /* uid */
658	if(!(pw->pw_fields & _PWF_UID)) {
659		pw->pw_uid = atoi(s);
660		pw->pw_fields |= _PWF_UID;
661	}
662
663	if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
664	if(!(pw->pw_fields & _PWF_GID))  {
665		pw->pw_gid = atoi(s);
666		pw->pw_fields |= _PWF_GID;
667	}
668
669	if (master == YP_HAVE_MASTER) {
670		if ((s = strsep(&result, ":")) == NULL) return 0; /* class */
671		if(!(pw->pw_fields & _PWF_CLASS))  {
672			pw->pw_class = s;
673			pw->pw_fields |= _PWF_CLASS;
674		}
675
676		if ((s = strsep(&result, ":")) == NULL) return 0; /* change */
677		if(!(pw->pw_fields & _PWF_CHANGE))  {
678			pw->pw_change = atol(s);
679			pw->pw_fields |= _PWF_CHANGE;
680		}
681
682		if ((s = strsep(&result, ":")) == NULL) return 0; /* expire */
683		if(!(pw->pw_fields & _PWF_EXPIRE))  {
684			pw->pw_expire = atol(s);
685			pw->pw_fields |= _PWF_EXPIRE;
686		}
687	}
688
689	if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */
690	if(!(pw->pw_fields & _PWF_GECOS)) {
691		pw->pw_gecos = s;
692		pw->pw_fields |= _PWF_GECOS;
693	}
694
695	if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */
696	if(!(pw->pw_fields & _PWF_DIR)) {
697		pw->pw_dir = s;
698		pw->pw_fields |= _PWF_DIR;
699	}
700
701	if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */
702	if(!(pw->pw_fields & _PWF_SHELL)) {
703		pw->pw_shell = s;
704		pw->pw_fields |= _PWF_SHELL;
705	}
706
707	/* Be consistent. */
708	if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0';
709
710	return 1;
711}
712
713static int
714_havemaster(char *_yp_domain)
715{
716	int order;
717	int rval;
718
719	if (!(rval = yp_order(_yp_domain, "master.passwd.byname", &order)))
720		return(YP_HAVE_MASTER);
721
722	/*
723	 * NIS+ in YP compat mode doesn't support
724	 * YPPROC_ORDER -- no point in continuing.
725	 */
726	if (rval == YPERR_YPERR)
727		return(YP_HAVE_NONE);
728
729	/* master.passwd doesn't exist -- try passwd.adjunct */
730	if (rval == YPERR_MAP) {
731		rval = yp_order(_yp_domain, "passwd.adjunct.byname", &order);
732		if (!rval)
733			return(YP_HAVE_ADJUNCT);
734	}
735
736	return (YP_HAVE_NONE);
737}
738
739static int
740_getyppass(struct passwd *pw, const char *name, const char *map)
741{
742	char *result, *s;
743	int resultlen;
744	int rv;
745	char mastermap[YPMAXRECORD];
746
747	if(!_pw_yp_domain) {
748		if(yp_get_default_domain(&_pw_yp_domain))
749		  return 0;
750	}
751
752	if (_gotmaster == YP_HAVE_MASTER)
753		sprintf(mastermap,"master.%s", map);
754	else
755		sprintf(mastermap,"%s",map);
756
757	if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name),
758		    &result, &resultlen)) {
759		if (_gotmaster != YP_HAVE_MASTER)
760			return 0;
761		sprintf(mastermap,"%s",map);
762		if (yp_match(_pw_yp_domain, (char *)&mastermap,
763			     name, strlen(name), &result, &resultlen))
764			return 0;
765		_gotmaster = YP_HAVE_NONE;
766	}
767
768	if (!_pw_stepping_yp) {
769		s = strchr(result, ':');
770		if (s) {
771			*s = '\0';
772		} else {
773			/* Must be a malformed entry if no colons. */
774			free(result);
775			return(0);
776		}
777
778		if (!verf(result)) {
779			*s = ':';
780			free(result);
781			return(0);
782		}
783
784		*s = ':'; /* Put back the colon we previously replaced with a NUL. */
785	}
786
787	rv = _pw_breakout_yp(pw, result, resultlen, _gotmaster);
788	free(result);
789	return(rv);
790}
791
792static int
793_nextyppass(struct passwd *pw)
794{
795	static char *key;
796	static int keylen;
797	char *lastkey, *result, *s;
798	int resultlen;
799	int rv;
800	char *map = "passwd.byname";
801
802	if(!_pw_yp_domain) {
803		if(yp_get_default_domain(&_pw_yp_domain))
804		  return 0;
805	}
806
807	if (_gotmaster == YP_HAVE_MASTER)
808		map = "master.passwd.byname";
809
810	if(!_pw_stepping_yp) {
811		if(key) free(key);
812			rv = yp_first(_pw_yp_domain, map,
813				      &key, &keylen, &result, &resultlen);
814		if(rv) {
815			return 0;
816		}
817		_pw_stepping_yp = 1;
818		goto unpack;
819	} else {
820tryagain:
821		lastkey = key;
822			rv = yp_next(_pw_yp_domain, map, key, keylen,
823			     &key, &keylen, &result, &resultlen);
824		free(lastkey);
825unpack:
826		if(rv) {
827			_pw_stepping_yp = 0;
828			return 0;
829		}
830
831		s = strchr(result, ':');
832		if (s) {
833			*s = '\0';
834		} else {
835			/* Must be a malformed entry if no colons. */
836			free(result);
837			goto tryagain;
838		}
839
840		if (lookup(result)) {
841			*s = ':';
842			free(result);
843			goto tryagain;
844		}
845
846		*s = ':'; /* Put back the colon we previously replaced with a NUL. */
847		if (_pw_breakout_yp(pw, result, resultlen, _gotmaster)) {
848			free(result);
849			return(1);
850		} else {
851			free(result);
852			goto tryagain;
853		}
854	}
855}
856
857#endif /* YP */
858