1/*	$NetBSD: getpwent.c,v 1.12 2011/01/12 23:34:00 joerg Exp $	*/
2
3/*
4 * Copyright (c) 1987, 1988, 1989, 1993, 1994, 1995
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * Copied from:  lib/libc/gen/getpwent.c
34 *	NetBSD: getpwent.c,v 1.48 2000/10/03 03:22:26 enami Exp
35 * and then gutted, leaving only /etc/master.passwd support.
36 */
37
38#include <sys/cdefs.h>
39
40#ifdef __weak_alias
41#define endpwent		_endpwent
42#define getpwent		_getpwent
43#define getpwent_r		_getpwent_r
44#define getpwuid		_getpwuid
45#define getpwnam		_getpwnam
46#define setpwent		_setpwent
47#define setpassent		_setpassent
48#define getpwuid_r		_getpwuid_r
49#define getpwnam_r		_getpwnam_r
50
51__weak_alias(endpwent,_endpwent)
52__weak_alias(setpwent,_setpwent)
53__weak_alias(setpassent,_setpassent)
54
55__weak_alias(getpwent,__getpwent50)
56__weak_alias(getpwent_r,__getpwent_r50)
57__weak_alias(getpwuid,__getpwuid50)
58__weak_alias(getpwnam,__getpwnam50)
59__weak_alias(getpwuid_r,__getpwuid_r50)
60__weak_alias(getpwnam_r,__getpwnam_r50)
61#endif
62
63#include <sys/param.h>
64
65#include <limits.h>
66#include <pwd.h>
67#include <stdlib.h>
68#include <stdio.h>
69#include <string.h>
70
71static	int		pwstart(void);
72static	int		pwscan(int, uid_t, const char *, struct passwd *,
73    char *, size_t);
74static	int		pwmatchline(int, uid_t, const char *, struct passwd *,
75    char *);
76
77static	FILE		*_pw_fp;
78static	struct passwd	_pw_passwd;	/* password structure */
79static	int		_pw_stayopen;	/* keep fd's open */
80static	int		_pw_filesdone;
81
82#define	MAXLINELENGTH	1024
83
84static	char		pwline[MAXLINELENGTH];
85
86struct passwd *
87getpwent(void)
88{
89
90	if ((!_pw_fp && !pwstart()) ||
91	    !pwscan(0, 0, NULL, &_pw_passwd, pwline, sizeof(pwline)))
92		return (NULL);
93	return (&_pw_passwd);
94}
95
96int
97getpwent_r(struct passwd *pwres, char *buf, size_t bufsiz,
98    struct passwd **pwd)
99{
100	int rval;
101
102	if (!_pw_fp && !pwstart())
103		return 1;
104	rval = !pwscan(0, 0, NULL, pwres, buf, bufsiz);
105	if (rval)
106		*pwd = NULL;
107	else
108		*pwd = pwres;
109	return rval;
110}
111
112struct passwd *
113getpwnam(const char *name)
114{
115	struct passwd *pwd;
116	return getpwnam_r(name, &_pw_passwd, pwline, sizeof(pwline),
117	    &pwd) == 0 ? pwd : NULL;
118}
119
120int
121getpwnam_r(const char *name, struct passwd *pwres, char *buf, size_t bufsiz,
122    struct passwd **pwd)
123{
124	int rval;
125
126	if (!pwstart())
127		return 1;
128	rval = !pwscan(1, 0, name, pwres, buf, bufsiz);
129	if (!_pw_stayopen)
130		endpwent();
131	if (rval)
132		*pwd = NULL;
133	else
134		*pwd = pwres;
135	return rval;
136}
137
138struct passwd *
139getpwuid(uid_t uid)
140{
141	struct passwd *pwd;
142	return getpwuid_r(uid, &_pw_passwd, pwline, sizeof(pwline),
143	    &pwd) == 0 ? pwd : NULL;
144}
145
146int
147getpwuid_r(uid_t uid, struct passwd *pwres, char *buf, size_t bufsiz,
148    struct passwd **pwd)
149{
150	int rval;
151
152	if (!pwstart())
153		return 1;
154	rval = !pwscan(1, uid, NULL, pwres, buf, bufsiz);
155	if (!_pw_stayopen)
156		endpwent();
157	if (rval)
158		*pwd = NULL;
159	else
160		*pwd = pwres;
161	return rval;
162}
163
164void
165setpwent(void)
166{
167
168	(void) setpassent(0);
169}
170
171int
172setpassent(int stayopen)
173{
174
175	if (!pwstart())
176		return 0;
177	_pw_stayopen = stayopen;
178	return 1;
179}
180
181void
182endpwent(void)
183{
184
185	_pw_filesdone = 0;
186	if (_pw_fp) {
187		(void)fclose(_pw_fp);
188		_pw_fp = NULL;
189	}
190}
191
192static int
193pwstart(void)
194{
195
196	_pw_filesdone = 0;
197	if (_pw_fp) {
198		rewind(_pw_fp);
199		return 1;
200	}
201	return (_pw_fp = fopen(_PATH_MASTERPASSWD, "r")) ? 1 : 0;
202}
203
204
205static int
206pwscan(int search, uid_t uid, const char *name, struct passwd *pwd, char *buf,
207    size_t bufsiz)
208{
209
210	if (_pw_filesdone)
211		return 0;
212	for (;;) {
213		if (!fgets(buf, bufsiz, _pw_fp)) {
214			if (!search)
215				_pw_filesdone = 1;
216			return 0;
217		}
218		/* skip lines that are too big */
219		if (!strchr(buf, '\n')) {
220			int ch;
221
222			while ((ch = getc(_pw_fp)) != '\n' && ch != EOF)
223				;
224			continue;
225		}
226		if (pwmatchline(search, uid, name, pwd, buf))
227			return 1;
228	}
229	/* NOTREACHED */
230}
231
232static int
233pwmatchline(int search, uid_t uid, const char *name, struct passwd *pwd,
234    char *buf)
235{
236	unsigned long	id;
237	char		*cp, *bp, *ep;
238
239	/* name may be NULL if search is nonzero */
240
241	bp = buf;
242	memset(pwd, 0, sizeof(*pwd));
243	pwd->pw_name = strsep(&bp, ":\n");		/* name */
244	if (search && name && strcmp(pwd->pw_name, name))
245		return 0;
246
247	pwd->pw_passwd = strsep(&bp, ":\n");		/* passwd */
248
249	if (!(cp = strsep(&bp, ":\n")))				/* uid */
250		return 0;
251	id = strtoul(cp, &ep, 10);
252	if (id > UID_MAX || *ep != '\0')
253		return 0;
254	pwd->pw_uid = (uid_t)id;
255	if (search && name == NULL && pwd->pw_uid != uid)
256		return 0;
257
258	if (!(cp = strsep(&bp, ":\n")))				/* gid */
259		return 0;
260	id = strtoul(cp, &ep, 10);
261	if (id > GID_MAX || *ep != '\0')
262		return 0;
263	pwd->pw_gid = (gid_t)id;
264
265	if (!(pwd->pw_class = strsep(&bp, ":")))		/* class */
266		return 0;
267	if (!(ep = strsep(&bp, ":")))				/* change */
268		return 0;
269	if (!(ep = strsep(&bp, ":")))				/* expire */
270		return 0;
271
272	if (!(pwd->pw_gecos = strsep(&bp, ":\n")))		/* gecos */
273		return 0;
274	if (!(pwd->pw_dir = strsep(&bp, ":\n")))		/* directory */
275		return 0;
276	if (!(pwd->pw_shell = strsep(&bp, ":\n")))		/* shell */
277		return 0;
278
279	if (strchr(bp, ':') != NULL)
280		return 0;
281
282	return 1;
283}
284