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