xref: /netbsd-src/distrib/utils/libhack/getpwent.c (revision 179b12252ecaf3553d9c2b7458ce62b6a2203d0c)
1 /*	$NetBSD: getpwent.c,v 1.11 2009/01/16 14:48:04 he 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(getpwent,_getpwent)
53 __weak_alias(getpwent_r,_getpwent_r)
54 __weak_alias(getpwuid,_getpwuid)
55 __weak_alias(getpwnam,_getpwnam)
56 __weak_alias(setpwent,_setpwent)
57 __weak_alias(setpassent,_setpassent)
58 __weak_alias(getpwuid_r,_getpwuid_r)
59 __weak_alias(getpwnam_r,_getpwnam_r)
60 
61 __weak_alias(__getpwent50,_getpwent)
62 __weak_alias(__getpwent_r50,_getpwent_r)
63 __weak_alias(__getpwuid50,_getpwuid)
64 __weak_alias(__getpwnam50,_getpwnam)
65 __weak_alias(__getpwuid_r50,_getpwuid_r)
66 __weak_alias(__getpwnam_r50,_getpwnam_r)
67 #endif
68 
69 #include <sys/param.h>
70 
71 #include <limits.h>
72 #include <pwd.h>
73 #include <stdlib.h>
74 #include <stdio.h>
75 #include <string.h>
76 
77 static	int		pwstart(void);
78 static	int		pwscan(int, uid_t, const char *, struct passwd *,
79     char *, size_t);
80 static	int		pwmatchline(int, uid_t, const char *, struct passwd *,
81     char *);
82 
83 static	FILE		*_pw_fp;
84 static	struct passwd	_pw_passwd;	/* password structure */
85 static	int		_pw_stayopen;	/* keep fd's open */
86 static	int		_pw_filesdone;
87 
88 #define	MAXLINELENGTH	1024
89 
90 static	char		pwline[MAXLINELENGTH];
91 
92 struct passwd *
93 getpwent(void)
94 {
95 
96 	if ((!_pw_fp && !pwstart()) ||
97 	    !pwscan(0, 0, NULL, &_pw_passwd, pwline, sizeof(pwline)))
98 		return (NULL);
99 	return (&_pw_passwd);
100 }
101 
102 int
103 getpwent_r(struct passwd *pwres, char *buf, size_t bufsiz,
104     struct passwd **pwd)
105 {
106 	int rval;
107 
108 	if (!_pw_fp && !pwstart())
109 		return 1;
110 	rval = !pwscan(0, 0, NULL, pwres, buf, bufsiz);
111 	if (rval)
112 		*pwd = NULL;
113 	else
114 		*pwd = pwres;
115 	return rval;
116 }
117 
118 struct passwd *
119 getpwnam(const char *name)
120 {
121 	struct passwd *pwd;
122 	return getpwnam_r(name, &_pw_passwd, pwline, sizeof(pwline),
123 	    &pwd) == 0 ? pwd : NULL;
124 }
125 
126 int
127 getpwnam_r(const char *name, struct passwd *pwres, char *buf, size_t bufsiz,
128     struct passwd **pwd)
129 {
130 	int rval;
131 
132 	if (!pwstart())
133 		return 1;
134 	rval = !pwscan(1, 0, name, pwres, buf, bufsiz);
135 	if (!_pw_stayopen)
136 		endpwent();
137 	if (rval)
138 		*pwd = NULL;
139 	else
140 		*pwd = pwres;
141 	return rval;
142 }
143 
144 struct passwd *
145 getpwuid(uid_t uid)
146 {
147 	struct passwd *pwd;
148 	return getpwuid_r(uid, &_pw_passwd, pwline, sizeof(pwline),
149 	    &pwd) == 0 ? pwd : NULL;
150 }
151 
152 int
153 getpwuid_r(uid_t uid, struct passwd *pwres, char *buf, size_t bufsiz,
154     struct passwd **pwd)
155 {
156 	int rval;
157 
158 	if (!pwstart())
159 		return 1;
160 	rval = !pwscan(1, uid, NULL, pwres, buf, bufsiz);
161 	if (!_pw_stayopen)
162 		endpwent();
163 	if (rval)
164 		*pwd = NULL;
165 	else
166 		*pwd = pwres;
167 	return rval;
168 }
169 
170 void
171 setpwent(void)
172 {
173 
174 	(void) setpassent(0);
175 }
176 
177 int
178 setpassent(int stayopen)
179 {
180 
181 	if (!pwstart())
182 		return 0;
183 	_pw_stayopen = stayopen;
184 	return 1;
185 }
186 
187 void
188 endpwent(void)
189 {
190 
191 	_pw_filesdone = 0;
192 	if (_pw_fp) {
193 		(void)fclose(_pw_fp);
194 		_pw_fp = NULL;
195 	}
196 }
197 
198 static int
199 pwstart(void)
200 {
201 
202 	_pw_filesdone = 0;
203 	if (_pw_fp) {
204 		rewind(_pw_fp);
205 		return 1;
206 	}
207 	return (_pw_fp = fopen(_PATH_MASTERPASSWD, "r")) ? 1 : 0;
208 }
209 
210 
211 static int
212 pwscan(int search, uid_t uid, const char *name, struct passwd *pwd, char *buf,
213     size_t bufsiz)
214 {
215 
216 	if (_pw_filesdone)
217 		return 0;
218 	for (;;) {
219 		if (!fgets(buf, bufsiz, _pw_fp)) {
220 			if (!search)
221 				_pw_filesdone = 1;
222 			return 0;
223 		}
224 		/* skip lines that are too big */
225 		if (!strchr(buf, '\n')) {
226 			int ch;
227 
228 			while ((ch = getc(_pw_fp)) != '\n' && ch != EOF)
229 				;
230 			continue;
231 		}
232 		if (pwmatchline(search, uid, name, pwd, buf))
233 			return 1;
234 	}
235 	/* NOTREACHED */
236 }
237 
238 static int
239 pwmatchline(int search, uid_t uid, const char *name, struct passwd *pwd,
240     char *buf)
241 {
242 	unsigned long	id;
243 	char		*cp, *bp, *ep;
244 
245 	/* name may be NULL if search is nonzero */
246 
247 	bp = buf;
248 	memset(pwd, 0, sizeof(*pwd));
249 	pwd->pw_name = strsep(&bp, ":\n");		/* name */
250 	if (search && name && strcmp(pwd->pw_name, name))
251 		return 0;
252 
253 	pwd->pw_passwd = strsep(&bp, ":\n");		/* passwd */
254 
255 	if (!(cp = strsep(&bp, ":\n")))				/* uid */
256 		return 0;
257 	id = strtoul(cp, &ep, 10);
258 	if (id > UID_MAX || *ep != '\0')
259 		return 0;
260 	pwd->pw_uid = (uid_t)id;
261 	if (search && name == NULL && pwd->pw_uid != uid)
262 		return 0;
263 
264 	if (!(cp = strsep(&bp, ":\n")))				/* gid */
265 		return 0;
266 	id = strtoul(cp, &ep, 10);
267 	if (id > GID_MAX || *ep != '\0')
268 		return 0;
269 	pwd->pw_gid = (gid_t)id;
270 
271 	if (!(pwd->pw_class = strsep(&bp, ":")))		/* class */
272 		return 0;
273 	if (!(ep = strsep(&bp, ":")))				/* change */
274 		return 0;
275 	if (!(ep = strsep(&bp, ":")))				/* expire */
276 		return 0;
277 
278 	if (!(pwd->pw_gecos = strsep(&bp, ":\n")))		/* gecos */
279 		return 0;
280 	if (!(pwd->pw_dir = strsep(&bp, ":\n")))		/* directory */
281 		return 0;
282 	if (!(pwd->pw_shell = strsep(&bp, ":\n")))		/* shell */
283 		return 0;
284 
285 	if (strchr(bp, ':') != NULL)
286 		return 0;
287 
288 	return 1;
289 }
290