getgrent.c revision 1.6
1/*	$NetBSD: getgrent.c,v 1.6 2003/02/19 08:04:29 elric Exp $	*/
2
3/*
4 * Copyright (c) 1989, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37/*
38 * Copied from:  lib/libc/gen/getgrent.c
39 *     NetBSD: getgrent.c,v 1.46 2003/02/17 00:11:54 simonb Exp
40 * and then gutted, leaving only /etc/group support.
41 */
42
43#include <sys/cdefs.h>
44
45#ifdef __weak_alias
46#define endgrent		_endgrent
47#define getgrent		_getgrent
48#define getgrgid		_getgrgid
49#define getgrnam		_getgrnam
50#define setgrent		_setgrent
51#define setgroupent		_setgroupent
52
53__weak_alias(endgrent,_endgrent)
54__weak_alias(getgrent,_getgrent)
55__weak_alias(getgrgid,_getgrgid)
56__weak_alias(getgrnam,_getgrnam)
57__weak_alias(setgrent,_setgrent)
58__weak_alias(setgroupent,_setgroupent)
59#endif
60
61#include <sys/types.h>
62
63#include <grp.h>
64#include <limits.h>
65#include <stdio.h>
66#include <stdlib.h>
67#include <string.h>
68
69struct group *_getgrent_user(const char *);
70
71static FILE		*_gr_fp;
72static struct group	_gr_group;
73static int		_gr_stayopen;
74static int		_gr_filesdone;
75
76static int grscan(int, gid_t, const char *, const char *);
77static int grstart(void);
78static int grmatchline(int, gid_t, const char *, const char *);
79
80#define	MAXGRP		200
81#define	MAXLINELENGTH	1024
82
83static __aconst char	*members[MAXGRP];
84static char		grline[MAXLINELENGTH];
85
86struct group *
87getgrent(void)
88{
89
90	if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, NULL))
91 		return (NULL);
92	return &_gr_group;
93}
94
95/*
96 * _getgrent_user() is designed only to be called by getgrouplist(3) and
97 * hence makes no guarantees about filling the entire structure that it
98 * returns.  It may only fill in the group name and gid fields.
99 */
100
101struct group *
102_getgrent_user(const char *user)
103{
104
105	if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, user))
106 		return (NULL);
107	return &_gr_group;
108}
109
110struct group *
111getgrnam(const char *name)
112{
113	int rval;
114
115	if (!grstart())
116		return NULL;
117	rval = grscan(1, 0, name, NULL);
118	if (!_gr_stayopen)
119		endgrent();
120	return (rval) ? &_gr_group : NULL;
121}
122
123struct group *
124getgrgid(gid_t gid)
125{
126	int rval;
127
128	if (!grstart())
129		return NULL;
130	rval = grscan(1, gid, NULL, NULL);
131	if (!_gr_stayopen)
132		endgrent();
133	return (rval) ? &_gr_group : NULL;
134}
135
136static int
137grstart(void)
138{
139
140	_gr_filesdone = 0;
141	if (_gr_fp) {
142		rewind(_gr_fp);
143		return 1;
144	}
145	return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0;
146}
147
148void
149setgrent(void)
150{
151
152	(void) setgroupent(0);
153}
154
155int
156setgroupent(int stayopen)
157{
158
159	if (!grstart())
160		return 0;
161	_gr_stayopen = stayopen;
162	return 1;
163}
164
165void
166endgrent(void)
167{
168
169	_gr_filesdone = 0;
170	if (_gr_fp) {
171		(void)fclose(_gr_fp);
172		_gr_fp = NULL;
173	}
174}
175
176static int
177grscan(int search, gid_t gid, const char *name, const char *user)
178{
179
180	if (_gr_filesdone)
181		return 0;
182	for (;;) {
183		if (!fgets(grline, sizeof(grline), _gr_fp)) {
184			if (!search)
185				_gr_filesdone = 1;
186			return 0;
187		}
188		/* skip lines that are too big */
189		if (!strchr(grline, '\n')) {
190			int ch;
191
192			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
193				;
194			continue;
195		}
196		if (grmatchline(search, gid, name, user))
197			return 1;
198	}
199	/* NOTREACHED */
200}
201
202static int
203grmatchline(int search, gid_t gid, const char *name, const char *user)
204{
205	unsigned long	id;
206	__aconst char	**m;
207	char		*cp, *bp, *ep;
208
209	/* name may be NULL if search is nonzero */
210
211	bp = grline;
212	_gr_group.gr_name = strsep(&bp, ":\n");
213	if (search && name && strcmp(_gr_group.gr_name, name))
214		return 0;
215	_gr_group.gr_passwd = strsep(&bp, ":\n");
216	if (!(cp = strsep(&bp, ":\n")))
217		return 0;
218	id = strtoul(cp, &ep, 10);
219	if (id > GID_MAX || *ep != '\0')
220		return 0;
221	_gr_group.gr_gid = (gid_t)id;
222	if (search && name == NULL && _gr_group.gr_gid != gid)
223		return 0;
224	cp = NULL;
225	if (bp == NULL)
226		return 0;
227	for (_gr_group.gr_mem = m = members;; bp++) {
228		if (m == &members[MAXGRP - 1])
229			break;
230		if (*bp == ',') {
231			if (cp) {
232				*bp = '\0';
233				*m++ = cp;
234				cp = NULL;
235			}
236		} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
237			if (cp) {
238				*bp = '\0';
239				*m++ = cp;
240			}
241			break;
242		} else if (cp == NULL)
243			cp = bp;
244	}
245	*m = NULL;
246	if (user) {
247		for (m = members; *m; m++)
248			if (!strcmp(user, *m))
249				return 1;
250		return 0;
251	}
252	return 1;
253}
254