xref: /netbsd-src/distrib/utils/libhack/getgrent.c (revision 1c9b56c830954ccf3b57004ac65562e3d6afacf6)
1 /*	$NetBSD: getgrent.c,v 1.9 2005/01/06 15:10:45 lukem 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 setgrent		_setgrent
71 #define setgroupent		_setgroupent
72 #define getgroupmembership	_getgroupmembership
73 
74 __weak_alias(endgrent,_endgrent)
75 __weak_alias(getgrent,_getgrent)
76 __weak_alias(getgrgid,_getgrgid)
77 __weak_alias(getgrnam,_getgrnam)
78 __weak_alias(setgrent,_setgrent)
79 __weak_alias(setgroupent,_setgroupent)
80 __weak_alias(getgroupmembership,_getgroupmembership)
81 #endif
82 
83 #include <sys/param.h>
84 
85 #include <grp.h>
86 #include <limits.h>
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 
91 static FILE		*_gr_fp;
92 static struct group	_gr_group;
93 static int		_gr_stayopen;
94 static int		_gr_filesdone;
95 
96 static int grscan(int, gid_t, const char *, const char *);
97 static int grstart(void);
98 static int grmatchline(int, gid_t, const char *, const char *);
99 
100 #define	MAXGRP		200
101 #define	MAXLINELENGTH	1024
102 
103 static __aconst char	*members[MAXGRP];
104 static char		grline[MAXLINELENGTH];
105 
106 struct group *
107 getgrent(void)
108 {
109 
110 	if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, NULL))
111  		return (NULL);
112 	return &_gr_group;
113 }
114 
115 struct group *
116 getgrnam(const char *name)
117 {
118 	int rval;
119 
120 	if (!grstart())
121 		return NULL;
122 	rval = grscan(1, 0, name, NULL);
123 	if (!_gr_stayopen)
124 		endgrent();
125 	return (rval) ? &_gr_group : NULL;
126 }
127 
128 struct group *
129 getgrgid(gid_t gid)
130 {
131 	int rval;
132 
133 	if (!grstart())
134 		return NULL;
135 	rval = grscan(1, gid, NULL, NULL);
136 	if (!_gr_stayopen)
137 		endgrent();
138 	return (rval) ? &_gr_group : NULL;
139 }
140 
141 static int
142 grstart(void)
143 {
144 
145 	_gr_filesdone = 0;
146 	if (_gr_fp) {
147 		rewind(_gr_fp);
148 		return 1;
149 	}
150 	return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0;
151 }
152 
153 void
154 setgrent(void)
155 {
156 
157 	(void) setgroupent(0);
158 }
159 
160 int
161 setgroupent(int stayopen)
162 {
163 
164 	if (!grstart())
165 		return 0;
166 	_gr_stayopen = stayopen;
167 	return 1;
168 }
169 
170 void
171 endgrent(void)
172 {
173 
174 	_gr_filesdone = 0;
175 	if (_gr_fp) {
176 		(void)fclose(_gr_fp);
177 		_gr_fp = NULL;
178 	}
179 }
180 
181 int
182 getgroupmembership(const char *uname, gid_t agroup,
183     gid_t *groups, int maxgroups, int *grpcnt)
184 {
185 	struct group *grp;
186 	int i, ngroups, ret;
187 
188 	ret = 0;
189 	ngroups = 0;
190 
191 	/*
192 	 * install primary group
193 	 */
194 	if (ngroups < maxgroups)
195 		groups[ngroups] = agroup;
196 	else
197 		ret = -1;
198 	ngroups++;
199 
200 	/*
201 	 * Scan the group file to find additional groups.
202 	 */
203 	setgrent();
204  nextgroup:
205 	while ((grp = getgrent()) != NULL) {
206 		if (grp->gr_gid == agroup)
207 			continue;
208 		for (i = 0; grp->gr_mem[i]; i++) {
209 			if (strcmp(grp->gr_mem[i], uname) != 0)
210 				continue;
211 			for (i = 0; i < MIN(ngroups, maxgroups); i++) {
212 				if (grp->gr_gid == groups[i])
213 					goto nextgroup;
214 			}
215 			if (ngroups < maxgroups)
216 				groups[ngroups] = grp->gr_gid;
217 			else
218 				ret = -1;
219 			ngroups++;
220 			break;
221 		}
222 	}
223 	endgrent();
224 	*grpcnt = ngroups;
225 	return ret;
226 }
227 
228 static int
229 grscan(int search, gid_t gid, const char *name, const char *user)
230 {
231 
232 	if (_gr_filesdone)
233 		return 0;
234 	for (;;) {
235 		if (!fgets(grline, sizeof(grline), _gr_fp)) {
236 			if (!search)
237 				_gr_filesdone = 1;
238 			return 0;
239 		}
240 		/* skip lines that are too big */
241 		if (!strchr(grline, '\n')) {
242 			int ch;
243 
244 			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
245 				;
246 			continue;
247 		}
248 		if (grmatchline(search, gid, name, user))
249 			return 1;
250 	}
251 	/* NOTREACHED */
252 }
253 
254 static int
255 grmatchline(int search, gid_t gid, const char *name, const char *user)
256 {
257 	unsigned long	id;
258 	__aconst char	**m;
259 	char		*cp, *bp, *ep;
260 
261 	/* name may be NULL if search is nonzero */
262 
263 	bp = grline;
264 	_gr_group.gr_name = strsep(&bp, ":\n");
265 	if (search && name && strcmp(_gr_group.gr_name, name))
266 		return 0;
267 	_gr_group.gr_passwd = strsep(&bp, ":\n");
268 	if (!(cp = strsep(&bp, ":\n")))
269 		return 0;
270 	id = strtoul(cp, &ep, 10);
271 	if (id > GID_MAX || *ep != '\0')
272 		return 0;
273 	_gr_group.gr_gid = (gid_t)id;
274 	if (search && name == NULL && _gr_group.gr_gid != gid)
275 		return 0;
276 	cp = NULL;
277 	if (bp == NULL)
278 		return 0;
279 	for (_gr_group.gr_mem = m = members;; bp++) {
280 		if (m == &members[MAXGRP - 1])
281 			break;
282 		if (*bp == ',') {
283 			if (cp) {
284 				*bp = '\0';
285 				*m++ = cp;
286 				cp = NULL;
287 			}
288 		} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
289 			if (cp) {
290 				*bp = '\0';
291 				*m++ = cp;
292 			}
293 			break;
294 		} else if (cp == NULL)
295 			cp = bp;
296 	}
297 	*m = NULL;
298 	if (user) {
299 		for (m = members; *m; m++)
300 			if (!strcmp(user, *m))
301 				return 1;
302 		return 0;
303 	}
304 	return 1;
305 }
306