xref: /freebsd/lib/libc/gen/getpwent.c (revision 380a989b3223d455375b4fae70fd0b9bdd43bafb)
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)
35 static 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 
52 extern void setnetgrent __P(( char * ));
53 extern int getnetgrent __P(( char **, char **, char ** ));
54 extern 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 
61 static struct passwd _pw_passwd;	/* password structure */
62 static DB *_pw_db;			/* password database */
63 static int _pw_keynum;			/* key counter */
64 static 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 
70 static struct passwd _pw_copy;
71 static DBT empty = { NULL, 0 };
72 static DB *_ypcache = (DB *)NULL;
73 static int _yp_exclusions = 0;
74 static int _yp_enabled = -1;
75 static int _pw_stepping_yp;		/* set true when stepping thru map */
76 static char _ypnam[YPMAXRECORD];
77 #define YP_HAVE_MASTER 2
78 #define YP_HAVE_ADJUNCT 1
79 #define YP_HAVE_NONE 0
80 static int _gotmaster;
81 static char *_pw_yp_domain;
82 static inline int unwind __P(( char * ));
83 static void _ypinitdb __P(( void ));
84 static int _havemaster __P((char *));
85 static int _getyppass __P((struct passwd *, const char *, const char * ));
86 static int _nextyppass __P((struct passwd *));
87 static inline int lookup __P((const char *));
88 static inline void store __P((const char *));
89 static inline int ingr __P((const char *, const char*));
90 static inline int verf __P((const char *));
91 static char * _get_adjunct_pw __P((const char *));
92 #endif
93 static int __hashpw(DBT *);
94 static int __initdb(void);
95 
96 struct passwd *
97 getpwent()
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
113 tryagain:
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 
144 struct passwd *
145 getpwnam(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 
183 struct passwd *
184 getpwuid(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 
223 int
224 setpassent(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 
235 void
236 setpwent()
237 {
238 	(void)setpassent(0);
239 }
240 
241 void
242 endpwent()
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 #endif
259 }
260 
261 static int
262 __initdb()
263 {
264 	static int warned;
265 	char *p;
266 
267 	p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
268 	_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
269 	if (_pw_db)
270 		return(1);
271 	if (!warned++)
272 		syslog(LOG_ERR, "%s: %m", p);
273 	return(0);
274 }
275 
276 static int
277 __hashpw(key)
278 	DBT *key;
279 {
280 	register char *p, *t;
281 	static u_int max;
282 	static char *line;
283 	DBT data;
284 
285 	if ((_pw_db->get)(_pw_db, key, &data, 0))
286 		return(0);
287 	p = (char *)data.data;
288 
289 	/* Increase buffer size for long lines if necessary. */
290 	if (data.size > max) {
291 		max = data.size + 1024;
292 		if (!(line = reallocf(line, max)))
293 			return(0);
294 	}
295 
296 	/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
297 	t = line;
298 #define	EXPAND(e)	e = t; while ( (*t++ = *p++) );
299 #define	SCALAR(v)	memmove(&(v), p, sizeof v); p += sizeof v
300 	EXPAND(_pw_passwd.pw_name);
301 	EXPAND(_pw_passwd.pw_passwd);
302 	SCALAR(_pw_passwd.pw_uid);
303 	SCALAR(_pw_passwd.pw_gid);
304 	SCALAR(_pw_passwd.pw_change);
305 	EXPAND(_pw_passwd.pw_class);
306 	EXPAND(_pw_passwd.pw_gecos);
307 	EXPAND(_pw_passwd.pw_dir);
308 	EXPAND(_pw_passwd.pw_shell);
309 	SCALAR(_pw_passwd.pw_expire);
310 	bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
311 	p += sizeof _pw_passwd.pw_fields;
312 	return(1);
313 }
314 
315 #ifdef YP
316 
317 static void
318 _ypinitdb()
319 {
320 	DBT key, data;
321 	char buf[] = { _PW_KEYYPENABLED };
322 	key.data = buf;
323 	key.size = 1;
324 	_yp_enabled = 0;
325 	if ((_pw_db->get)(_pw_db, &key, &data, 0) == 0) {
326 		_yp_enabled = (int)*((char *)data.data) - 2;
327 		/* Don't even bother with this if we aren't root. */
328 		if (!geteuid()) {
329 			if (!_pw_yp_domain)
330 				if (yp_get_default_domain(&_pw_yp_domain))
331 					return;
332 			_gotmaster = _havemaster(_pw_yp_domain);
333 		} else _gotmaster = YP_HAVE_NONE;
334 		/*
335 		 * Create a DB hash database in memory. Bet you didn't know you
336 		 * could do a dbopen() with a NULL filename, did you.
337 		 */
338 		if (_ypcache == (DB *)NULL)
339 			_ypcache = dbopen(NULL, O_RDWR, 600, DB_HASH, NULL);
340 	}
341 }
342 
343 /*
344  * See if a user is in the blackballed list.
345  */
346 static inline int
347 lookup(name)
348 	const char *name;
349 {
350 	DBT key;
351 
352 	if (!_yp_exclusions)
353 		return(0);
354 
355 	key.data = (char *)name;
356 	key.size = strlen(name);
357 
358 	if ((_ypcache->get)(_ypcache, &key, &empty, 0)) {
359 		return(0);
360 	}
361 
362 	return(1);
363 }
364 
365 /*
366  * Store a blackballed user in an in-core hash database.
367  */
368 static inline void
369 store(key)
370 	const char *key;
371 {
372 	DBT lkey;
373 /*
374 	if (lookup(key))
375 		return;
376 */
377 
378 	_yp_exclusions = 1;
379 
380 	lkey.data = (char *)key;
381 	lkey.size = strlen(key);
382 
383 	(void)(_ypcache->put)(_ypcache, &lkey, &empty, R_NOOVERWRITE);
384 }
385 
386 /*
387  * Parse the + entries in the password database and do appropriate
388  * NIS lookups. While ugly to look at, this is optimized to do only
389  * as many lookups as are absolutely necessary in any given case.
390  * Basically, the getpwent() function will feed us + and - lines
391  * as they appear in the database. For + lines, we do netgroup/group
392  * and user lookups to find all usernames that match the rule and
393  * extract them from the NIS passwd maps. For - lines, we save the
394  * matching names in a database and a) exlude them, and b) make sure
395  * we don't consider them when processing other + lines that appear
396  * later.
397  */
398 static inline int
399 unwind(grp)
400 	char *grp;
401 {
402 	char *user, *host, *domain;
403 	static int latch = 0;
404 	static struct group *gr = NULL;
405 	int rv = 0;
406 
407 	if (grp[0] == '+') {
408 		if (strlen(grp) == 1) {
409 			return(_nextyppass(&_pw_passwd));
410 		}
411 		if (grp[1] == '@') {
412 			_pw_stepping_yp = 1;
413 grpagain:
414 			if (gr != NULL) {
415 				if (*gr->gr_mem != NULL) {
416 					if (lookup(*gr->gr_mem)) {
417 						gr->gr_mem++;
418 						goto grpagain;
419 					}
420 					rv = _getyppass(&_pw_passwd,
421 							*gr->gr_mem,
422 							"passwd.byname");
423 					gr->gr_mem++;
424 					return(rv);
425 				} else {
426 					endgrent();
427 					latch = 0;
428 					gr = NULL;
429 					return(0);
430 				}
431 			}
432 			if (!latch) {
433 				setnetgrent(grp+2);
434 				latch++;
435 			}
436 again:
437 			if (getnetgrent(&host, &user, &domain) == 0) {
438 				if ((gr = getgrnam(grp+2)) != NULL)
439 					goto grpagain;
440 				latch = 0;
441 				_pw_stepping_yp = 0;
442 				return(0);
443 			} else {
444 				if (lookup(user))
445 					goto again;
446 				if (_getyppass(&_pw_passwd, user,
447 							"passwd.byname"))
448 					return(1);
449 				else
450 					goto again;
451 			}
452 		} else {
453 			if (lookup(grp+1))
454 				return(0);
455 			return(_getyppass(&_pw_passwd, grp+1, "passwd.byname"));
456 		}
457 	} else {
458 		if (grp[1] == '@') {
459 			setnetgrent(grp+2);
460 			rv = 0;
461 			while(getnetgrent(&host, &user, &domain) != 0) {
462 				store(user);
463 				rv++;
464 			}
465 			if (!rv && (gr = getgrnam(grp+2)) != NULL) {
466 				while(*gr->gr_mem) {
467 					store(*gr->gr_mem);
468 					gr->gr_mem++;
469 				}
470 			}
471 		} else {
472 			store(grp+1);
473 		}
474 	}
475 	return(0);
476 }
477 
478 /*
479  * See if a user is a member of a particular group.
480  */
481 static inline int
482 ingr(grp, name)
483 	const char *grp;
484 	const char *name;
485 {
486 	register struct group *gr;
487 
488 	if ((gr = getgrnam(grp)) == NULL)
489 		return(0);
490 
491 	while(*gr->gr_mem) {
492 		if (!strcmp(*gr->gr_mem, name)) {
493 			endgrent();
494 			return(1);
495 		}
496 		gr->gr_mem++;
497 	}
498 
499 	endgrent();
500 	return(0);
501 }
502 
503 /*
504  * Check a user against the +@netgroup/-@netgroup lines listed in
505  * the local password database. Also checks +user/-user lines.
506  * If no netgroup exists that matches +@netgroup/-@netgroup,
507  * try searching regular groups with the same name.
508  */
509 static inline int
510 verf(name)
511 	const char *name;
512 {
513 	DBT key;
514 	char bf[sizeof(_pw_keynum) + 1];
515 	int keynum = 0;
516 
517 again:
518 	++keynum;
519 	bf[0] = _PW_KEYYPBYNUM;
520 	bcopy((char *)&keynum, bf + 1, sizeof(keynum));
521 	key.data = (u_char *)bf;
522 	key.size = sizeof(keynum) + 1;
523 	if (!__hashpw(&key)) {
524 		/* Try again using old format */
525 		bf[0] = _PW_KEYBYNUM;
526 		bcopy((char *)&keynum, bf + 1, sizeof(keynum));
527 		key.data = (u_char *)bf;
528 		if (!__hashpw(&key))
529 			return(0);
530 	}
531 	if (_pw_passwd.pw_name[0] != '+' && (_pw_passwd.pw_name[0] != '-'))
532 		goto again;
533 	if (_pw_passwd.pw_name[0] == '+') {
534 		if (strlen(_pw_passwd.pw_name) == 1) /* Wildcard */
535 			return(1);
536 		if (_pw_passwd.pw_name[1] == '@') {
537 			if ((innetgr(_pw_passwd.pw_name+2, NULL, name,
538 							_pw_yp_domain) ||
539 			    ingr(_pw_passwd.pw_name+2, name)) && !lookup(name))
540 				return(1);
541 			else
542 				goto again;
543 		} else {
544 			if (!strcmp(name, _pw_passwd.pw_name+1) &&
545 								!lookup(name))
546 				return(1);
547 			else
548 				goto again;
549 		}
550 	}
551 	if (_pw_passwd.pw_name[0] == '-') {
552 		/* Note that a minus wildcard is a no-op. */
553 		if (_pw_passwd.pw_name[1] == '@') {
554 			if (innetgr(_pw_passwd.pw_name+2, NULL, name,
555 							_pw_yp_domain) ||
556 			    ingr(_pw_passwd.pw_name+2, name)) {
557 				store(name);
558 				return(0);
559 			} else
560 				goto again;
561 		} else {
562 			if (!strcmp(name, _pw_passwd.pw_name+1)) {
563 				store(name);
564 				return(0);
565 			} else
566 				goto again;
567 		}
568 
569 	}
570 	return(0);
571 }
572 
573 static char *
574 _get_adjunct_pw(name)
575 	const char *name;
576 {
577 	static char adjunctbuf[YPMAXRECORD+2];
578 	int rval;
579 	char *result;
580 	int resultlen;
581 	char *map = "passwd.adjunct.byname";
582 	char *s;
583 
584 	if ((rval = yp_match(_pw_yp_domain, map, name, strlen(name),
585 		    &result, &resultlen)))
586 		return(NULL);
587 
588 	strncpy(adjunctbuf, result, resultlen);
589 	adjunctbuf[resultlen] = '\0';
590 	free(result);
591 	result = (char *)&adjunctbuf;
592 
593 	/* Don't care about the name. */
594 	if ((s = strsep(&result, ":")) == NULL)
595 		return (NULL); /* name */
596 	if ((s = strsep(&result, ":")) == NULL)
597 		return (NULL); /* password */
598 
599 	return(s);
600 }
601 
602 static int
603 _pw_breakout_yp(struct passwd *pw, char *res, int resultlen, int master)
604 {
605 	char *s, *result;
606 	static char resbuf[YPMAXRECORD+2];
607 
608 	/*
609 	 * Be triple, ultra super-duper paranoid: reject entries
610 	 * that start with a + or -. yp_mkdb and /var/yp/Makefile
611 	 * are _both_ supposed to strip these out, but you never
612 	 * know.
613 	 */
614 	if (*res == '+' || *res == '-')
615 		return 0;
616 
617 	/*
618 	 * The NIS protocol definition limits the size of an NIS
619 	 * record to YPMAXRECORD bytes. We need to do a copy to
620 	 * a static buffer here since the memory pointed to by
621 	 * res will be free()ed when this function returns.
622 	 */
623 	strncpy((char *)&resbuf, res, resultlen);
624 	resbuf[resultlen] = '\0';
625 	result = (char *)&resbuf;
626 
627 	/*
628 	 * XXX Sanity check: make sure all fields are valid (no NULLs).
629 	 * If we find a badly formatted entry, we punt.
630 	 */
631 	if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
632 	/*
633 	 * We don't care what pw_fields says: we _always_ want the
634 	 * username returned to us by NIS.
635 	 */
636 	pw->pw_name = s;
637 	pw->pw_fields |= _PWF_NAME;
638 
639 	if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
640 	if(!(pw->pw_fields & _PWF_PASSWD)) {
641 		/* SunOS passwd.adjunct hack */
642 		if (master == YP_HAVE_ADJUNCT && strstr(s, "##") != NULL) {
643 			char *realpw;
644 			realpw = _get_adjunct_pw(pw->pw_name);
645 			if (realpw == NULL)
646 				pw->pw_passwd = s;
647 			else
648 				pw->pw_passwd = realpw;
649 		} else {
650 			pw->pw_passwd = s;
651 		}
652 		pw->pw_fields |= _PWF_PASSWD;
653 	}
654 
655 	if ((s = strsep(&result, ":")) == NULL) return 0; /* uid */
656 	if(!(pw->pw_fields & _PWF_UID)) {
657 		pw->pw_uid = atoi(s);
658 		pw->pw_fields |= _PWF_UID;
659 	}
660 
661 	if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
662 	if(!(pw->pw_fields & _PWF_GID))  {
663 		pw->pw_gid = atoi(s);
664 		pw->pw_fields |= _PWF_GID;
665 	}
666 
667 	if (master == YP_HAVE_MASTER) {
668 		if ((s = strsep(&result, ":")) == NULL) return 0; /* class */
669 		if(!(pw->pw_fields & _PWF_CLASS))  {
670 			pw->pw_class = s;
671 			pw->pw_fields |= _PWF_CLASS;
672 		}
673 
674 		if ((s = strsep(&result, ":")) == NULL) return 0; /* change */
675 		if(!(pw->pw_fields & _PWF_CHANGE))  {
676 			pw->pw_change = atol(s);
677 			pw->pw_fields |= _PWF_CHANGE;
678 		}
679 
680 		if ((s = strsep(&result, ":")) == NULL) return 0; /* expire */
681 		if(!(pw->pw_fields & _PWF_EXPIRE))  {
682 			pw->pw_expire = atol(s);
683 			pw->pw_fields |= _PWF_EXPIRE;
684 		}
685 	}
686 
687 	if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */
688 	if(!(pw->pw_fields & _PWF_GECOS)) {
689 		pw->pw_gecos = s;
690 		pw->pw_fields |= _PWF_GECOS;
691 	}
692 
693 	if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */
694 	if(!(pw->pw_fields & _PWF_DIR)) {
695 		pw->pw_dir = s;
696 		pw->pw_fields |= _PWF_DIR;
697 	}
698 
699 	if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */
700 	if(!(pw->pw_fields & _PWF_SHELL)) {
701 		pw->pw_shell = s;
702 		pw->pw_fields |= _PWF_SHELL;
703 	}
704 
705 	/* Be consistent. */
706 	if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0';
707 
708 	return 1;
709 }
710 
711 static int
712 _havemaster(char *_yp_domain)
713 {
714 	int order;
715 	int rval;
716 
717 	if (!(rval = yp_order(_yp_domain, "master.passwd.byname", &order)))
718 		return(YP_HAVE_MASTER);
719 
720 	/*
721 	 * NIS+ in YP compat mode doesn't support
722 	 * YPPROC_ORDER -- no point in continuing.
723 	 */
724 	if (rval == YPERR_YPERR)
725 		return(YP_HAVE_NONE);
726 
727 	/* master.passwd doesn't exist -- try passwd.adjunct */
728 	if (rval == YPERR_MAP) {
729 		rval = yp_order(_yp_domain, "passwd.adjunct.byname", &order);
730 		if (!rval)
731 			return(YP_HAVE_ADJUNCT);
732 	}
733 
734 	return (YP_HAVE_NONE);
735 }
736 
737 static int
738 _getyppass(struct passwd *pw, const char *name, const char *map)
739 {
740 	char *result, *s;
741 	int resultlen;
742 	int rv;
743 	char mastermap[YPMAXRECORD];
744 
745 	if(!_pw_yp_domain) {
746 		if(yp_get_default_domain(&_pw_yp_domain))
747 		  return 0;
748 	}
749 
750 	sprintf(mastermap,"%s",map);
751 
752 	if (_gotmaster == YP_HAVE_MASTER)
753 		sprintf(mastermap,"master.%s", map);
754 
755 	if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name),
756 		    &result, &resultlen))
757 		return 0;
758 
759 	if (!_pw_stepping_yp) {
760 		s = strchr(result, ':');
761 		if (s) {
762 			*s = '\0';
763 		} else {
764 			/* Must be a malformed entry if no colons. */
765 			free(result);
766 			return(0);
767 		}
768 
769 		if (!verf(result)) {
770 			*s = ':';
771 			free(result);
772 			return(0);
773 		}
774 
775 		*s = ':'; /* Put back the colon we previously replaced with a NUL. */
776 	}
777 
778 	rv = _pw_breakout_yp(pw, result, resultlen, _gotmaster);
779 	free(result);
780 	return(rv);
781 }
782 
783 static int
784 _nextyppass(struct passwd *pw)
785 {
786 	static char *key;
787 	static int keylen;
788 	char *lastkey, *result, *s;
789 	int resultlen;
790 	int rv;
791 	char *map = "passwd.byname";
792 
793 	if(!_pw_yp_domain) {
794 		if(yp_get_default_domain(&_pw_yp_domain))
795 		  return 0;
796 	}
797 
798 	if (_gotmaster == YP_HAVE_MASTER)
799 		map = "master.passwd.byname";
800 
801 	if(!_pw_stepping_yp) {
802 		if(key) free(key);
803 			rv = yp_first(_pw_yp_domain, map,
804 				      &key, &keylen, &result, &resultlen);
805 		if(rv) {
806 			return 0;
807 		}
808 		_pw_stepping_yp = 1;
809 		goto unpack;
810 	} else {
811 tryagain:
812 		lastkey = key;
813 			rv = yp_next(_pw_yp_domain, map, key, keylen,
814 			     &key, &keylen, &result, &resultlen);
815 		free(lastkey);
816 unpack:
817 		if(rv) {
818 			_pw_stepping_yp = 0;
819 			return 0;
820 		}
821 
822 		s = strchr(result, ':');
823 		if (s) {
824 			*s = '\0';
825 		} else {
826 			/* Must be a malformed entry if no colons. */
827 			free(result);
828 			goto tryagain;
829 		}
830 
831 		if (lookup(result)) {
832 			*s = ':';
833 			free(result);
834 			goto tryagain;
835 		}
836 
837 		*s = ':'; /* Put back the colon we previously replaced with a NUL. */
838 		if (_pw_breakout_yp(pw, result, resultlen, _gotmaster)) {
839 			free(result);
840 			return(1);
841 		} else {
842 			free(result);
843 			goto tryagain;
844 		}
845 	}
846 }
847 
848 #endif /* YP */
849