xref: /netbsd-src/distrib/utils/libhack/getgrent.c (revision a8675b3763e5b09ee12feaf551380f45d47dad14)
1 /*	$NetBSD: getgrent.c,v 1.12 2005/09/14 15:54:53 drochner Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1991, 1993
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  * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
34  *
35  * Redistribution and use in source and binary forms, with or without
36  * modification, are permitted provided that the following conditions
37  * are met:
38  * 1. Redistributions of source code must retain the above copyright
39  *    notice, this list of conditions and the following disclaimer.
40  * 2. Redistributions in binary form must reproduce the above copyright
41  *    notice, this list of conditions and the following disclaimer in the
42  *    documentation and/or other materials provided with the distribution.
43  *
44  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
45  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
46  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
47  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT,
48  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
49  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
50  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
51  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54  * SUCH DAMAGE.
55  */
56 
57 /*
58  * Copied from:  lib/libc/gen/getgrent.c
59  *     NetBSD: getgrent.c,v 1.46 2003/02/17 00:11:54 simonb Exp
60  * and then gutted, leaving only /etc/group support.
61  */
62 
63 #include <sys/cdefs.h>
64 
65 #ifdef __weak_alias
66 #define endgrent		_endgrent
67 #define getgrent		_getgrent
68 #define getgrgid		_getgrgid
69 #define getgrnam		_getgrnam
70 #define getgrnam_r		_getgrnam_r
71 #define setgrent		_setgrent
72 #define setgroupent		_setgroupent
73 #define getgrouplist		_getgrouplist
74 
75 __weak_alias(endgrent,_endgrent)
76 __weak_alias(getgrent,_getgrent)
77 __weak_alias(getgrgid,_getgrgid)
78 __weak_alias(getgrnam,_getgrnam)
79 __weak_alias(getgrnam_r,_getgrnam_r)
80 __weak_alias(setgrent,_setgrent)
81 __weak_alias(setgroupent,_setgroupent)
82 __weak_alias(getgrouplist,_getgrouplist)
83 #endif
84 
85 #include <sys/param.h>
86 
87 #include <grp.h>
88 #include <limits.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <string.h>
92 #include <unistd.h>
93 #include <errno.h>
94 
95 static FILE		*_gr_fp;
96 static struct group	_gr_group;
97 static int		_gr_stayopen;
98 static int		_gr_filesdone;
99 
100 static int grscan(int, gid_t, const char *, const char *);
101 static int grstart(void);
102 static int grmatchline(int, gid_t, const char *, const char *);
103 
104 #define	MAXGRP		200
105 #define	MAXLINELENGTH	1024
106 
107 static __aconst char	*members[MAXGRP];
108 static char		grline[MAXLINELENGTH];
109 
110 struct group *
getgrent(void)111 getgrent(void)
112 {
113 
114 	if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, NULL))
115  		return (NULL);
116 	return &_gr_group;
117 }
118 
119 int
getgrnam_r(const char * name,struct group * grp,char * buffer,size_t buflen,struct group ** result)120 getgrnam_r(const char *name, struct group *grp, char *buffer,
121 	size_t buflen, struct group **result)
122 {
123 	struct group *gp, *bgp;
124 
125 	/*
126 	 * We blatantly cheat (don't provide reentrancy)
127 	 * and hope to get away with it
128 	 */
129 
130 	*result = NULL;
131 	bgp = (struct group*)buffer;
132 	if (buflen < sizeof(struct group))
133 		return ENOMEM;
134 
135 	gp = getgrnam(name);
136 	if (gp) {
137 		*bgp = *gp;
138 		*result = bgp;
139 	}
140 
141 	return (gp) ? ENOENT : 0;
142 }
143 
144 struct group *
getgrnam(const char * name)145 getgrnam(const char *name)
146 {
147 	int rval;
148 
149 	if (!grstart())
150 		return NULL;
151 	rval = grscan(1, 0, name, NULL);
152 	if (!_gr_stayopen)
153 		endgrent();
154 	return (rval) ? &_gr_group : NULL;
155 }
156 
157 struct group *
getgrgid(gid_t gid)158 getgrgid(gid_t gid)
159 {
160 	int rval;
161 
162 	if (!grstart())
163 		return NULL;
164 	rval = grscan(1, gid, NULL, NULL);
165 	if (!_gr_stayopen)
166 		endgrent();
167 	return (rval) ? &_gr_group : NULL;
168 }
169 
170 static int
grstart(void)171 grstart(void)
172 {
173 
174 	_gr_filesdone = 0;
175 	if (_gr_fp) {
176 		rewind(_gr_fp);
177 		return 1;
178 	}
179 	return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0;
180 }
181 
182 void
setgrent(void)183 setgrent(void)
184 {
185 
186 	(void) setgroupent(0);
187 }
188 
189 int
setgroupent(int stayopen)190 setgroupent(int stayopen)
191 {
192 
193 	if (!grstart())
194 		return 0;
195 	_gr_stayopen = stayopen;
196 	return 1;
197 }
198 
199 void
endgrent(void)200 endgrent(void)
201 {
202 
203 	_gr_filesdone = 0;
204 	if (_gr_fp) {
205 		(void)fclose(_gr_fp);
206 		_gr_fp = NULL;
207 	}
208 }
209 
210 int
getgrouplist(const char * uname,gid_t agroup,gid_t * groups,int * grpcnt)211 getgrouplist(const char *uname, gid_t agroup,
212     gid_t *groups, int *grpcnt)
213 {
214 	struct group *grp;
215 	int maxgroups, i, ngroups, ret;
216 
217 	maxgroups = *grpcnt;
218 	ret = 0;
219 	ngroups = 0;
220 
221 	/*
222 	 * install primary group
223 	 */
224 	if (ngroups < maxgroups)
225 		groups[ngroups] = agroup;
226 	else
227 		ret = -1;
228 	ngroups++;
229 
230 	/*
231 	 * Scan the group file to find additional groups.
232 	 */
233 	setgrent();
234  nextgroup:
235 	while ((grp = getgrent()) != NULL) {
236 		if (grp->gr_gid == agroup)
237 			continue;
238 		for (i = 0; grp->gr_mem[i]; i++) {
239 			if (strcmp(grp->gr_mem[i], uname) != 0)
240 				continue;
241 			for (i = 0; i < MIN(ngroups, maxgroups); i++) {
242 				if (grp->gr_gid == groups[i])
243 					goto nextgroup;
244 			}
245 			if (ngroups < maxgroups)
246 				groups[ngroups] = grp->gr_gid;
247 			else
248 				ret = -1;
249 			ngroups++;
250 			break;
251 		}
252 	}
253 	endgrent();
254 	*grpcnt = ngroups;
255 	return ret;
256 }
257 
258 static int
grscan(int search,gid_t gid,const char * name,const char * user)259 grscan(int search, gid_t gid, const char *name, const char *user)
260 {
261 
262 	if (_gr_filesdone)
263 		return 0;
264 	for (;;) {
265 		if (!fgets(grline, sizeof(grline), _gr_fp)) {
266 			if (!search)
267 				_gr_filesdone = 1;
268 			return 0;
269 		}
270 		/* skip lines that are too big */
271 		if (!strchr(grline, '\n')) {
272 			int ch;
273 
274 			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
275 				;
276 			continue;
277 		}
278 		if (grmatchline(search, gid, name, user))
279 			return 1;
280 	}
281 	/* NOTREACHED */
282 }
283 
284 static int
grmatchline(int search,gid_t gid,const char * name,const char * user)285 grmatchline(int search, gid_t gid, const char *name, const char *user)
286 {
287 	unsigned long	id;
288 	__aconst char	**m;
289 	char		*cp, *bp, *ep;
290 
291 	/* name may be NULL if search is nonzero */
292 
293 	bp = grline;
294 	_gr_group.gr_name = strsep(&bp, ":\n");
295 	if (search && name && strcmp(_gr_group.gr_name, name))
296 		return 0;
297 	_gr_group.gr_passwd = strsep(&bp, ":\n");
298 	if (!(cp = strsep(&bp, ":\n")))
299 		return 0;
300 	id = strtoul(cp, &ep, 10);
301 	if (id > GID_MAX || *ep != '\0')
302 		return 0;
303 	_gr_group.gr_gid = (gid_t)id;
304 	if (search && name == NULL && _gr_group.gr_gid != gid)
305 		return 0;
306 	cp = NULL;
307 	if (bp == NULL)
308 		return 0;
309 	for (_gr_group.gr_mem = m = members;; bp++) {
310 		if (m == &members[MAXGRP - 1])
311 			break;
312 		if (*bp == ',') {
313 			if (cp) {
314 				*bp = '\0';
315 				*m++ = cp;
316 				cp = NULL;
317 			}
318 		} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
319 			if (cp) {
320 				*bp = '\0';
321 				*m++ = cp;
322 			}
323 			break;
324 		} else if (cp == NULL)
325 			cp = bp;
326 	}
327 	*m = NULL;
328 	if (user) {
329 		for (m = members; *m; m++)
330 			if (!strcmp(user, *m))
331 				return 1;
332 		return 0;
333 	}
334 	return 1;
335 }
336