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