xref: /freebsd/lib/libc/gen/getpwent.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
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.1 (Berkeley) 6/4/93";
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 static struct passwd _pw_passwd;	/* password structure */
53 static DB *_pw_db;			/* password database */
54 static int _pw_keynum;			/* key counter */
55 static int _pw_stayopen;		/* keep fd's open */
56 #ifdef YP
57 #include <rpc/rpc.h>
58 #include <rpcsvc/yp_prot.h>
59 #include <rpcsvc/ypclnt.h>
60 struct _namelist {
61 	char *name;
62 	struct _namelist *next;
63 };
64 static struct passwd _pw_copy;
65 struct _pw_cache {
66 	struct passwd pw_entry;
67 	struct _namelist *namelist;
68 	struct _pw_cache *next;
69 };
70 static int _pluscnt, _minuscnt;
71 static struct _pw_cache *_plushead = NULL, *_minushead = NULL;
72 static void _createcaches(), _freecaches();
73 static int _scancaches(char *);
74 static int _yp_enabled;			/* set true when yp enabled */
75 static int _pw_stepping_yp;		/* set true when stepping thru map */
76 static int _yp_done;
77 static int _gotmaster;
78 static char *_pw_yp_domain;
79 static int _havemaster(char *);
80 static int _getyppass(struct passwd *, const char *, const char *);
81 static int _nextyppass(struct passwd *);
82 #endif
83 static int __hashpw(), __initdb();
84 
85 struct passwd *
86 getpwent()
87 {
88 	DBT key;
89 	char bf[sizeof(_pw_keynum) + 1];
90 	int rv;
91 
92 	if (!_pw_db && !__initdb())
93 		return((struct passwd *)NULL);
94 
95 #ifdef YP
96 	if(_pw_stepping_yp) {
97 		_pw_passwd = _pw_copy;
98 		if (_nextyppass(&_pw_passwd))
99 			return (&_pw_passwd);
100 		else
101 			_yp_done = 1;
102 	}
103 #endif
104 tryagain:
105 
106 	++_pw_keynum;
107 	bf[0] = _PW_KEYBYNUM;
108 	bcopy((char *)&_pw_keynum, bf + 1, sizeof(_pw_keynum));
109 	key.data = (u_char *)bf;
110 	key.size = sizeof(_pw_keynum) + 1;
111 	rv = __hashpw(&key);
112 	if(!rv) return (struct passwd *)NULL;
113 #ifdef YP
114 	if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
115 		_pw_copy = _pw_passwd;
116 		if (_yp_done || !_nextyppass(&_pw_passwd))
117 			goto tryagain;
118 		else
119 			return (&_pw_passwd);
120 	}
121 #else
122 	/* Ignore YP password file entries when YP is disabled. */
123 	if(_pw_passwd.pw_name[0] == '+' || _pw_passwd.pw_name[0] == '-') {
124 		goto tryagain;
125 	}
126 #endif
127 	return(&_pw_passwd);
128 }
129 
130 struct passwd *
131 getpwnam(name)
132 	const char *name;
133 {
134 	DBT key;
135 	int len, rval;
136 	char bf[UT_NAMESIZE + 2];
137 
138 	if (!_pw_db && !__initdb())
139 		return((struct passwd *)NULL);
140 
141 	bf[0] = _PW_KEYBYNAME;
142 	len = strlen(name);
143 	bcopy(name, bf + 1, MIN(len, UT_NAMESIZE));
144 	key.data = (u_char *)bf;
145 	key.size = len + 1;
146 	rval = __hashpw(&key);
147 
148 #ifdef YP
149 	if (!rval && _yp_enabled)
150 		rval = _getyppass(&_pw_passwd, name, "passwd.byname");
151 #endif
152 	/*
153 	 * Prevent login attempts when YP is not enabled but YP entries
154 	 * are in /etc/master.passwd.
155 	 */
156 	if (rval && (_pw_passwd.pw_name[0] == '+'||
157 			_pw_passwd.pw_name[0] == '-')) rval = 0;
158 
159 	endpwent();
160 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
161 }
162 
163 struct passwd *
164 #ifdef __STDC__
165 getpwuid(uid_t uid)
166 #else
167 getpwuid(uid)
168 	int uid;
169 #endif
170 {
171 	DBT key;
172 	int keyuid, rval;
173 	char bf[sizeof(keyuid) + 1];
174 
175 	if (!_pw_db && !__initdb())
176 		return((struct passwd *)NULL);
177 
178 	bf[0] = _PW_KEYBYUID;
179 	keyuid = uid;
180 	bcopy(&keyuid, bf + 1, sizeof(keyuid));
181 	key.data = (u_char *)bf;
182 	key.size = sizeof(keyuid) + 1;
183 	rval = __hashpw(&key);
184 
185 #ifdef YP
186 	if (!rval && _yp_enabled) {
187 		char ypbuf[16];	/* big enough for 32-bit uids and then some */
188 		snprintf(ypbuf, sizeof ypbuf, "%u", (unsigned)uid);
189 		rval = _getyppass(&_pw_passwd, ypbuf, "passwd.byuid");
190 	}
191 #endif
192 	/*
193 	 * Prevent login attempts when YP is not enabled but YP entries
194 	 * are in /etc/master.passwd.
195 	 */
196 	if (rval && (_pw_passwd.pw_name[0] == '+'||
197 			_pw_passwd.pw_name[0] == '-')) rval = 0;
198 
199 	endpwent();
200 	return(rval ? &_pw_passwd : (struct passwd *)NULL);
201 }
202 
203 int
204 setpassent(stayopen)
205 	int stayopen;
206 {
207 	_pw_keynum = 0;
208 #ifdef YP
209 	_pw_stepping_yp = _yp_done = 0;
210 #endif
211 	_pw_stayopen = stayopen;
212 	return(1);
213 }
214 
215 int
216 setpwent()
217 {
218 	_pw_keynum = 0;
219 #ifdef YP
220 	_pw_stepping_yp = _yp_done = 0;
221 #endif
222 	_pw_stayopen = 0;
223 	return(1);
224 }
225 
226 void
227 endpwent()
228 {
229 	_pw_keynum = 0;
230 #ifdef YP
231 	_pw_stepping_yp = _yp_done = 0;
232 #endif
233 	if (_pw_db) {
234 		(void)(_pw_db->close)(_pw_db);
235 		_pw_db = (DB *)NULL;
236 #ifdef YP
237 		_freecaches();
238 #endif
239 	}
240 }
241 
242 static
243 __initdb()
244 {
245 	static int warned;
246 	char *p;
247 
248 	p = (geteuid()) ? _PATH_MP_DB : _PATH_SMP_DB;
249 	_pw_db = dbopen(p, O_RDONLY, 0, DB_HASH, NULL);
250 	if (_pw_db) {
251 #ifdef YP
252 		DBT key, data;
253 		char buf[] = { _PW_KEYYPENABLED };
254 		key.data = buf;
255 		key.size = 1;
256 		if ((_pw_db->get)(_pw_db, &key, &data, 0)) {
257 			_yp_enabled = 0;
258 		} else {
259 			_yp_enabled = (int)*((char *)data.data) - 2;
260 			_createcaches();
261 		/* Don't even bother with this if we aren't root. */
262 			if (!geteuid()) {
263 				if (!_pw_yp_domain)
264 					if (yp_get_default_domain(&_pw_yp_domain))
265 					return(1);
266 				_gotmaster = _havemaster(_pw_yp_domain);
267 			} else _gotmaster = 0;
268 		}
269 #endif
270 		return(1);
271 	}
272 	if (!warned)
273 		syslog(LOG_ERR, "%s: %m", p);
274 	return(0);
275 }
276 
277 static
278 __hashpw(key)
279 	DBT *key;
280 {
281 	register char *p, *t;
282 	static u_int max;
283 	static char *line;
284 	DBT data;
285 
286 	if ((_pw_db->get)(_pw_db, key, &data, 0))
287 		return(0);
288 	p = (char *)data.data;
289 	if (data.size > max && !(line = realloc(line, max += 1024)))
290 		return(0);
291 
292 	t = line;
293 #define	EXPAND(e)	e = t; while (*t++ = *p++);
294 	EXPAND(_pw_passwd.pw_name);
295 	EXPAND(_pw_passwd.pw_passwd);
296 	bcopy(p, (char *)&_pw_passwd.pw_uid, sizeof(int));
297 	p += sizeof(int);
298 	bcopy(p, (char *)&_pw_passwd.pw_gid, sizeof(int));
299 	p += sizeof(int);
300 	bcopy(p, (char *)&_pw_passwd.pw_change, sizeof(time_t));
301 	p += sizeof(time_t);
302 	EXPAND(_pw_passwd.pw_class);
303 	EXPAND(_pw_passwd.pw_gecos);
304 	EXPAND(_pw_passwd.pw_dir);
305 	EXPAND(_pw_passwd.pw_shell);
306 	bcopy(p, (char *)&_pw_passwd.pw_expire, sizeof(time_t));
307 	p += sizeof(time_t);
308 	bcopy(p, (char *)&_pw_passwd.pw_fields, sizeof _pw_passwd.pw_fields);
309 	p += sizeof _pw_passwd.pw_fields;
310 	return(1);
311 }
312 
313 #ifdef YP
314 /*
315  * Build special +@netgroup and -@netgroup caches. We also handle ordinary
316  * +user/-user entries, *and* +@group/-@group entries, which are special
317  * cases of the +@netgroup/-@netgroup substitutions: if we can't find
318  * netgroup 'foo', we look for a regular user group called 'foo' and
319  * match against that instead. The netgroup takes precedence since the
320  * +group/-group support is basically just a hack to make Justin T. Gibbs
321  * happy. :) Sorting out all the funny business here lets us have a
322  * yp_enabled flag with a simple on or off value instead of the somewhat
323  * bogus setup we had before.
324  *
325  * We cache everything here in one shot so that we only have to scan
326  * each netgroup/group once. The alternative is to use innetgr() inside the
327  * NIS lookup functions, which would make retrieving the whole password
328  * database though getpwent() very slow. +user/-user entries are treated
329  * like @groups/@netgroups with only one member.
330  */
331 static void
332 _createcaches()
333 {
334 	DBT key, data;
335 	int i;
336 	char bf[UT_NAMESIZE + 2];
337 	struct _pw_cache *p, *m;
338 	struct _namelist *n, *namehead;
339 	char *user, *host, *domain;
340 	struct group *grp;
341 
342 	/*
343 	 * Assume that the database has already been initialized
344 	 * but be paranoid and check that YP is in fact enabled.
345 	 */
346 
347 	if (!_yp_enabled)
348 		return;
349 	/*
350 	 * For the plus list, we have to store both the linked list of
351 	 * names and the +entries from the password database so we can
352 	 * do the substitution later if we find a match.
353 	 */
354 	bf[0] = _PW_KEYPLUSCNT;
355 	key.data = (u_char*)bf;
356 	key.size = 1;
357 	if (!(_pw_db->get)(_pw_db, &key, &data, 0)) {
358 		_pluscnt = (int)*((char *)data.data);
359 		for (i = 0; i < _pluscnt; i++) {
360 			bf[0] = _PW_KEYPLUSBYNUM;
361 			bcopy(&i, bf + 1, sizeof(i) + 1);
362 			key.size = (sizeof(i)) + 1;
363 			if (__hashpw(&key)) {
364 				p = (struct _pw_cache *)malloc(sizeof (struct _pw_cache));
365 				if (strlen(_pw_passwd.pw_name) > 2 && _pw_passwd.pw_name[1] == '@') {
366 					setnetgrent(_pw_passwd.pw_name+2);
367 					namehead = NULL;
368 					while(getnetgrent(&host, &user, &domain)) {
369 						n = (struct _namelist *)malloc(sizeof (struct _namelist));
370 						n->name = strdup(user);
371 						n->next = namehead;
372 						namehead = n;
373 					}
374 					/*
375 					 * If netgroup 'foo' doesn't exist,
376 					 * try group 'foo' instead.
377 					 */
378 					if (namehead == NULL && (grp = getgrnam(_pw_passwd.pw_name+2)) != NULL) {
379 						while(*grp->gr_mem) {
380 							n = (struct _namelist *)malloc(sizeof (struct _namelist));
381 							n->name = strdup(*grp->gr_mem);
382 							n->next = namehead;
383 							namehead = n;
384 							grp->gr_mem++;
385 						}
386 					}
387 				} else {
388 					if (_pw_passwd.pw_name[1] != '@') {
389 						namehead = (struct _namelist *)malloc(sizeof (struct _namelist));
390 						namehead->name = strdup(_pw_passwd.pw_name+1);
391 						namehead->next = NULL;
392 					}
393 				}
394 				p->namelist = namehead;
395 				p->pw_entry.pw_name = strdup(_pw_passwd.pw_name);
396 				p->pw_entry.pw_passwd = strdup(_pw_passwd.pw_passwd);
397 				p->pw_entry.pw_uid = _pw_passwd.pw_uid;
398 				p->pw_entry.pw_gid = _pw_passwd.pw_gid;
399 				p->pw_entry.pw_expire = _pw_passwd.pw_expire;
400 				p->pw_entry.pw_change = _pw_passwd.pw_change;
401 				p->pw_entry.pw_class = strdup(_pw_passwd.pw_class);
402 				p->pw_entry.pw_gecos = strdup(_pw_passwd.pw_gecos);
403 				p->pw_entry.pw_dir = strdup(_pw_passwd.pw_dir);
404 				p->pw_entry.pw_shell = strdup(_pw_passwd.pw_shell);
405 				p->pw_entry.pw_fields = _pw_passwd.pw_fields;
406 				p->next = _plushead;
407 				_plushead = p;
408 			}
409 		}
410 	}
411 
412 	/*
413 	 * All we need for the minuslist is the usernames.
414 	 * The actual -entries data can be ignored since no substitution
415 	 * will be done: anybody on the minus list is treated like a
416 	 * non-person.
417 	 */
418 	bf[0] = _PW_KEYMINUSCNT;
419 	key.data = (u_char*)bf;
420 	key.size = 1;
421 	if (!(_pw_db->get)(_pw_db, &key, &data, 0)) {
422 		_minuscnt = (int)*((char *)data.data);
423 		for (i = _minuscnt; i > -1; i--) {
424 			bf[0] = _PW_KEYMINUSBYNUM;
425 			bcopy(&i, bf + 1, sizeof(i) + 1);
426 			key.size = (sizeof(i)) + 1;
427 			if (__hashpw(&key)) {
428 				m = (struct _pw_cache *)malloc(sizeof (struct _pw_cache));
429 				if (strlen (_pw_passwd.pw_name) > 2 && _pw_passwd.pw_name[1] == '@') {
430 					namehead = NULL;
431 					setnetgrent(_pw_passwd.pw_name+2);
432 					while(getnetgrent(&host, &user, &domain)) {
433 						n = (struct _namelist *)malloc(sizeof (struct _namelist));
434 						n->name = strdup(user);
435 						n->next = namehead;
436 						namehead = n;
437 					}
438 					/*
439 					 * If netgroup 'foo' doesn't exist,
440 					 * try group 'foo' instead.
441 					 */
442 					if (namehead == NULL && (grp = getgrnam(_pw_passwd.pw_name+2)) != NULL) {
443 						while(*grp->gr_mem) {
444 							n = (struct _namelist *)malloc(sizeof (struct _namelist));
445 							n->name = strdup(*grp->gr_mem);
446 							n->next = namehead;
447 							namehead = n;
448 							grp->gr_mem++;
449 						}
450 					}
451 				} else {
452 					if (_pw_passwd.pw_name[1] != '@') {
453 						namehead = (struct _namelist *)malloc(sizeof (struct _namelist));
454 						namehead->name = strdup(_pw_passwd.pw_name+1);
455 						namehead->next = NULL;
456 					}
457 				}
458 				/* Save just the name */
459 				m->pw_entry.pw_name = strdup(_pw_passwd.pw_name);
460 				m->namelist = namehead;
461 				m->next = _minushead;
462 				_minushead = m;
463 			}
464 		}
465 	}
466 	endgrent();
467 	endnetgrent();
468 }
469 
470 /*
471  * Free the +@netgroup/-@netgroup caches. Should be called
472  * from endpwent(). We have to blow away both the list of
473  * netgroups and the attached linked lists of usernames.
474  */
475 static void
476 _freecaches()
477 {
478 struct _pw_cache *p, *m;
479 struct _namelist *n;
480 
481 	while (_plushead) {
482 		while(_plushead->namelist) {
483 			n = _plushead->namelist->next;
484 			free(_plushead->namelist->name);
485 			free(_plushead->namelist);
486 			_plushead->namelist = n;
487 		}
488 		free(_plushead->pw_entry.pw_name);
489 		free(_plushead->pw_entry.pw_passwd);
490 		free(_plushead->pw_entry.pw_class);
491 		free(_plushead->pw_entry.pw_gecos);
492 		free(_plushead->pw_entry.pw_dir);
493 		free(_plushead->pw_entry.pw_shell);
494 		p = _plushead->next;
495 		free(_plushead);
496 		_plushead = p;
497 	}
498 
499 	while(_minushead) {
500 		while(_minushead->namelist) {
501 			n = _minushead->namelist->next;
502 			free(_minushead->namelist->name);
503 			free(_minushead->namelist);
504 			_minushead->namelist = n;
505 		}
506 		m = _minushead->next;
507 		free(_minushead);
508 		_minushead = m;
509 	}
510 	_pluscnt = _minuscnt = 0;
511 }
512 
513 static int _scancaches(user)
514 char *user;
515 {
516 	register struct _pw_cache *m, *p;
517 	register struct _namelist *n;
518 
519 	if (_minuscnt && _minushead) {
520 		m = _minushead;
521 		while (m) {
522 			n = m->namelist;
523 			while (n) {
524 				if (!strcmp(n->name,user) || *n->name == '\0')
525 					return (1);
526 				n = n->next;
527 			}
528 			m = m->next;
529 		}
530 	}
531 	if (_pluscnt && _plushead) {
532 		p = _plushead;
533 		while (p) {
534 			n = p->namelist;
535 			while (n) {
536 				if (!strcmp(n->name, user) || *n->name == '\0')
537 					bcopy((char *)&p->pw_entry,
538 					(char *)&_pw_passwd, sizeof(p->pw_entry));
539 				n = n->next;
540 			}
541 			p = p->next;
542 		}
543 	}
544 	return(0);
545 }
546 
547 static int
548 _pw_breakout_yp(struct passwd *pw, char *res, int master)
549 {
550 	char *s, *result;
551 	static char resbuf[YPMAXRECORD+2];
552 
553 	/*
554 	 * Be triple, ultra super-duper paranoid: reject entries
555 	 * that start with a + or -. yp_mkdb and /var/yp/Makefile
556 	 * are _both_ supposed to strip these out, but you never
557 	 * know.
558 	 */
559 	if (*res == '+' || *res == '-')
560 		return 0;
561 
562 	/*
563 	 * The NIS protocol definition limits the size of an NIS
564 	 * record to YPMAXRECORD bytes. We need to do a copy to
565 	 * a static buffer here since the memory pointed to by
566 	 * res will be free()ed when this function returns.
567 	 */
568 	strncpy((char *)&resbuf, res, YPMAXRECORD);
569 	result = (char *)&resbuf;
570 
571 	/*
572 	 * XXX Sanity check: make sure all fields are valid (no NULLs).
573 	 * If we find a badly formatted entry, we punt.
574 	 */
575 	if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
576 	/*
577 	 * We don't care what pw_fields says: we _always_ want the
578 	 * username returned to us by NIS.
579 	 */
580 	pw->pw_name = s;
581 	pw->pw_fields |= _PWF_NAME;
582 
583 	if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
584 	if(!(pw->pw_fields & _PWF_PASSWD)) {
585 		pw->pw_passwd = s;
586 		pw->pw_fields |= _PWF_PASSWD;
587 	}
588 
589 	if ((s = strsep(&result, ":")) == NULL) return 0; /* uid */
590 	if(!(pw->pw_fields & _PWF_UID)) {
591 		pw->pw_uid = atoi(s);
592 		pw->pw_fields |= _PWF_UID;
593 	}
594 
595 	if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
596 	if(!(pw->pw_fields & _PWF_GID))  {
597 		pw->pw_gid = atoi(s);
598 		pw->pw_fields |= _PWF_GID;
599 	}
600 
601 	if (master) {
602 		if ((s = strsep(&result, ":")) == NULL) return 0; /* class */
603 		if(!(pw->pw_fields & _PWF_CLASS))  {
604 			pw->pw_class = s;
605 			pw->pw_fields |= _PWF_CLASS;
606 		}
607 
608 		if ((s = strsep(&result, ":")) == NULL) return 0; /* change */
609 		if(!(pw->pw_fields & _PWF_CHANGE))  {
610 			pw->pw_change = atol(s);
611 			pw->pw_fields |= _PWF_CHANGE;
612 		}
613 
614 		if ((s = strsep(&result, ":")) == NULL) return 0; /* expire */
615 		if(!(pw->pw_fields & _PWF_EXPIRE))  {
616 			pw->pw_expire = atol(s);
617 			pw->pw_fields |= _PWF_EXPIRE;
618 		}
619 	}
620 
621 	if ((s = strsep(&result, ":")) == NULL) return 0; /* gecos */
622 	if(!(pw->pw_fields & _PWF_GECOS)) {
623 		pw->pw_gecos = s;
624 		pw->pw_fields |= _PWF_GECOS;
625 	}
626 
627 	if ((s = strsep(&result, ":")) == NULL) return 0; /* dir */
628 	if(!(pw->pw_fields & _PWF_DIR)) {
629 		pw->pw_dir = s;
630 		pw->pw_fields |= _PWF_DIR;
631 	}
632 
633 	if ((s = strsep(&result, ":")) == NULL) return 0; /* shell */
634 	if(!(pw->pw_fields & _PWF_SHELL)) {
635 		pw->pw_shell = s;
636 		pw->pw_fields |= _PWF_SHELL;
637 	}
638 
639 	/* Be consistent. */
640 	if ((s = strchr(pw->pw_shell, '\n'))) *s = '\0';
641 
642 	return 1;
643 }
644 
645 static int
646 _havemaster(char *_pw_yp_domain)
647 {
648 	int keylen, resultlen;
649 	char *key, *result;
650 
651 	if (yp_first(_pw_yp_domain, "master.passwd.byname",
652 		&key, &keylen, &result, &resultlen)) {
653 		free(result);
654 		return 0;
655 	}
656 	free(result);
657 	return 1;
658 }
659 
660 static int
661 _getyppass(struct passwd *pw, const char *name, const char *map)
662 {
663 	char *result, *s;
664 	int resultlen;
665 	int rv;
666 	char mastermap[1024];
667 
668 	if(!_pw_yp_domain) {
669 		if(yp_get_default_domain(&_pw_yp_domain))
670 		  return 0;
671 	}
672 
673 	sprintf(mastermap,"%s",map);
674 
675 	if (_gotmaster)
676 		sprintf(mastermap,"master.%s", map);
677 
678 	if(yp_match(_pw_yp_domain, (char *)&mastermap, name, strlen(name),
679 		    &result, &resultlen))
680 		return 0;
681 
682 	s = strchr(result, ':');
683 	if (s) {
684 		*s = '\0';
685 	} else {
686 		/* Must be a malformed entry if no colons. */
687 		free(result);
688 		return(0);
689 	}
690 	_pw_passwd.pw_fields = -1; /* Impossible value */
691 	if (_scancaches(result)) {
692 		free(result);
693 		return(0);
694 	}
695 	/* No hits in the plus or minus lists: Bzzt! reject. */
696 	if (_pw_passwd.pw_fields == -1) {
697 		free(result);
698 		return(0);
699 	}
700 	*s = ':'; /* Put back the colon we previously replaced with a NUL. */
701 	rv = _pw_breakout_yp(pw, result, _gotmaster);
702 	free(result);
703 	return(rv);
704 }
705 
706 static int
707 _nextyppass(struct passwd *pw)
708 {
709 	static char *key;
710 	static int keylen;
711 	char *lastkey, *result, *s;
712 	int resultlen;
713 	int rv;
714 	char *map = "passwd.byname";
715 
716 	if(!_pw_yp_domain) {
717 		if(yp_get_default_domain(&_pw_yp_domain))
718 		  return 0;
719 	}
720 
721 	if (_gotmaster)
722 		map = "master.passwd.byname";
723 
724 	if(!_pw_stepping_yp) {
725 		if(key) free(key);
726 			rv = yp_first(_pw_yp_domain, map,
727 				      &key, &keylen, &result, &resultlen);
728 		if(rv) {
729 			return 0;
730 		}
731 		_pw_stepping_yp = 1;
732 		goto unpack;
733 	} else {
734 tryagain:
735 		lastkey = key;
736 			rv = yp_next(_pw_yp_domain, map, key, keylen,
737 			     &key, &keylen, &result, &resultlen);
738 		free(lastkey);
739 unpack:
740 		if(rv) {
741 			_pw_stepping_yp = 0;
742 			return 0;
743 		}
744 
745 		s = strchr(result, ':');
746 		if (s) {
747 			*s = '\0';
748 		} else {
749 			/* Must be a malformed entry if no colon. */
750 			free(result);
751 			goto tryagain;
752 		}
753 		_pw_passwd.pw_fields = -1; /* Impossible value */
754 		if (_scancaches(result)) {
755 			free(result);
756 			goto tryagain;
757 		}
758 		/* No plus or minus hits: Bzzzt! reject. */
759 		if (_pw_passwd.pw_fields == -1) {
760 			free(result);
761 			goto tryagain;
762 		}
763 		*s = ':';	/* Put back colon we previously replaced with a NUL. */
764 		if(s = strchr(result, '\n')) *s = '\0';
765 		if (_pw_breakout_yp(pw, result, _gotmaster)) {
766 			free(result);
767 			return(1);
768 		} else {
769 			free(result);
770 			goto tryagain;
771 		}
772 	}
773 }
774 
775 #endif /* YP */
776