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