xref: /freebsd/lib/libc/gen/getpwent.c (revision 6e8394b8baa7d5d9153ab90de6824bcd19b3b4e1)
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 	/* Fix for PR #12008 */
259 	_yp_enabled = -1;
260 #endif
261 }
262 
263 static 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 
278 static 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 
319 static 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  */
348 static inline int
349 lookup(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  */
370 static inline void
371 store(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  */
400 static inline int
401 unwind(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;
415 grpagain:
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 			}
438 again:
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  */
483 static inline int
484 ingr(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  */
511 static inline int
512 verf(name)
513 	const char *name;
514 {
515 	DBT key;
516 	char bf[sizeof(_pw_keynum) + 1];
517 	int keynum = 0;
518 
519 again:
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 
575 static 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 
604 static 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 
713 static 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 
739 static 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 
792 static 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 {
820 tryagain:
821 		lastkey = key;
822 			rv = yp_next(_pw_yp_domain, map, key, keylen,
823 			     &key, &keylen, &result, &resultlen);
824 		free(lastkey);
825 unpack:
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