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