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