xref: /netbsd/distrib/utils/libhack/getpwent.c (revision 6550d01e)
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 
71 static	int		pwstart(void);
72 static	int		pwscan(int, uid_t, const char *, struct passwd *,
73     char *, size_t);
74 static	int		pwmatchline(int, uid_t, const char *, struct passwd *,
75     char *);
76 
77 static	FILE		*_pw_fp;
78 static	struct passwd	_pw_passwd;	/* password structure */
79 static	int		_pw_stayopen;	/* keep fd's open */
80 static	int		_pw_filesdone;
81 
82 #define	MAXLINELENGTH	1024
83 
84 static	char		pwline[MAXLINELENGTH];
85 
86 struct passwd *
87 getpwent(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 
96 int
97 getpwent_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 
112 struct passwd *
113 getpwnam(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 
120 int
121 getpwnam_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 
138 struct passwd *
139 getpwuid(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 
146 int
147 getpwuid_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 
164 void
165 setpwent(void)
166 {
167 
168 	(void) setpassent(0);
169 }
170 
171 int
172 setpassent(int stayopen)
173 {
174 
175 	if (!pwstart())
176 		return 0;
177 	_pw_stayopen = stayopen;
178 	return 1;
179 }
180 
181 void
182 endpwent(void)
183 {
184 
185 	_pw_filesdone = 0;
186 	if (_pw_fp) {
187 		(void)fclose(_pw_fp);
188 		_pw_fp = NULL;
189 	}
190 }
191 
192 static int
193 pwstart(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 
205 static int
206 pwscan(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 
232 static int
233 pwmatchline(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