getgrent.c revision 1.9
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
91static FILE		*_gr_fp;
92static struct group	_gr_group;
93static int		_gr_stayopen;
94static int		_gr_filesdone;
95
96static int grscan(int, gid_t, const char *, const char *);
97static int grstart(void);
98static int grmatchline(int, gid_t, const char *, const char *);
99
100#define	MAXGRP		200
101#define	MAXLINELENGTH	1024
102
103static __aconst char	*members[MAXGRP];
104static char		grline[MAXLINELENGTH];
105
106struct group *
107getgrent(void)
108{
109
110	if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, NULL))
111 		return (NULL);
112	return &_gr_group;
113}
114
115struct group *
116getgrnam(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
128struct group *
129getgrgid(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
141static int
142grstart(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
153void
154setgrent(void)
155{
156
157	(void) setgroupent(0);
158}
159
160int
161setgroupent(int stayopen)
162{
163
164	if (!grstart())
165		return 0;
166	_gr_stayopen = stayopen;
167	return 1;
168}
169
170void
171endgrent(void)
172{
173
174	_gr_filesdone = 0;
175	if (_gr_fp) {
176		(void)fclose(_gr_fp);
177		_gr_fp = NULL;
178	}
179}
180
181int
182getgroupmembership(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
228static int
229grscan(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
254static int
255grmatchline(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