Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / distrib / utils / libhack / getgrent.c
blobe7a2b34275579fa23615d59328a3301f8799a02b
1 /* $NetBSD: getgrent.c,v 1.11 2005/09/14 15:31:18 he Exp $ */
3 /*
4 * Copyright (c) 1989, 1991, 1993
5 * The Regents of the University of California. All rights reserved.
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.
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.
33 * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
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.
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.
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.
63 #include <sys/cdefs.h>
65 #ifdef __weak_alias
66 #define endgrent _endgrent
67 #define getgrent _getgrent
68 #define getgrgid _getgrgid
69 #define getgrnam _getgrnam
70 #define getgrnam_r _getgrnam_r
71 #define setgrent _setgrent
72 #define setgroupent _setgroupent
73 #define getgrouplist _getgrouplist
75 __weak_alias(endgrent,_endgrent)
76 __weak_alias(getgrent,_getgrent)
77 __weak_alias(getgrgid,_getgrgid)
78 __weak_alias(getgrnam,_getgrnam)
79 __weak_alias(getgrnam_r,_getgrnam_r)
80 __weak_alias(setgrent,_setgrent)
81 __weak_alias(setgroupent,_setgroupent)
82 __weak_alias(getgrouplist,_getgrouplist)
83 #endif
85 #include <sys/param.h>
87 #include <grp.h>
88 #include <limits.h>
89 #include <stdio.h>
90 #include <stdlib.h>
91 #include <string.h>
92 #include <unistd.h>
93 #include <errno.h>
95 static FILE *_gr_fp;
96 static struct group _gr_group;
97 static int _gr_stayopen;
98 static int _gr_filesdone;
100 static int grscan(int, gid_t, const char *, const char *);
101 static int grstart(void);
102 static int grmatchline(int, gid_t, const char *, const char *);
104 #define MAXGRP 200
105 #define MAXLINELENGTH 1024
107 static __aconst char *members[MAXGRP];
108 static char grline[MAXLINELENGTH];
110 struct group *
111 getgrent(void)
114 if ((!_gr_fp && !grstart()) || !grscan(0, 0, NULL, NULL))
115 return (NULL);
116 return &_gr_group;
120 getgrnam_r(const char *name, struct group *grp, char *buffer,
121 size_t buflen, struct group **result)
123 struct group *gp, *bgp;
126 * We blatantly cheat (don't provide reentrancy)
127 * and hope to get away with it
130 *result = NULL;
131 bgp = (struct group*)buffer;
132 if (buflen < sizeof(struct group))
133 return ENOMEM;
135 gp = getgrnam(name);
136 if (gp) {
137 *bgp = *gp;
138 *result = bgp;
141 return (gp) ? ENOENT : 0;
144 struct group *
145 getgrnam(const char *name)
147 int rval;
149 if (!grstart())
150 return NULL;
151 rval = grscan(1, 0, name, NULL);
152 if (!_gr_stayopen)
153 endgrent();
154 return (rval) ? &_gr_group : NULL;
157 struct group *
158 getgrgid(gid_t gid)
160 int rval;
162 if (!grstart())
163 return NULL;
164 rval = grscan(1, gid, NULL, NULL);
165 if (!_gr_stayopen)
166 endgrent();
167 return (rval) ? &_gr_group : NULL;
170 static int
171 grstart(void)
174 _gr_filesdone = 0;
175 if (_gr_fp) {
176 rewind(_gr_fp);
177 return 1;
179 return (_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0;
182 void
183 setgrent(void)
186 (void) setgroupent(0);
190 setgroupent(int stayopen)
193 if (!grstart())
194 return 0;
195 _gr_stayopen = stayopen;
196 return 1;
199 void
200 endgrent(void)
203 _gr_filesdone = 0;
204 if (_gr_fp) {
205 (void)fclose(_gr_fp);
206 _gr_fp = NULL;
211 getgrouplist(const char *uname, gid_t agroup,
212 gid_t *groups, int *grpcnt)
214 struct group *grp;
215 int maxgroups, i, ngroups, ret;
217 maxgroups = *grpcnt;
218 ret = 0;
219 ngroups = 0;
222 * install primary group
224 if (ngroups < maxgroups)
225 groups[ngroups] = agroup;
226 else
227 ret = -1;
228 ngroups++;
231 * Scan the group file to find additional groups.
233 setgrent();
234 nextgroup:
235 while ((grp = getgrent()) != NULL) {
236 if (grp->gr_gid == agroup)
237 continue;
238 for (i = 0; grp->gr_mem[i]; i++) {
239 if (strcmp(grp->gr_mem[i], uname) != 0)
240 continue;
241 for (i = 0; i < MIN(ngroups, maxgroups); i++) {
242 if (grp->gr_gid == groups[i])
243 goto nextgroup;
245 if (ngroups < maxgroups)
246 groups[ngroups] = grp->gr_gid;
247 else
248 ret = -1;
249 ngroups++;
250 break;
253 endgrent();
254 *grpcnt = ngroups;
255 return ret;
258 static int
259 grscan(int search, gid_t gid, const char *name, const char *user)
262 if (_gr_filesdone)
263 return 0;
264 for (;;) {
265 if (!fgets(grline, sizeof(grline), _gr_fp)) {
266 if (!search)
267 _gr_filesdone = 1;
268 return 0;
270 /* skip lines that are too big */
271 if (!strchr(grline, '\n')) {
272 int ch;
274 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
276 continue;
278 if (grmatchline(search, gid, name, user))
279 return 1;
281 /* NOTREACHED */
284 static int
285 grmatchline(int search, gid_t gid, const char *name, const char *user)
287 unsigned long id;
288 __aconst char **m;
289 char *cp, *bp, *ep;
291 /* name may be NULL if search is nonzero */
293 bp = grline;
294 _gr_group.gr_name = strsep(&bp, ":\n");
295 if (search && name && strcmp(_gr_group.gr_name, name))
296 return 0;
297 _gr_group.gr_passwd = strsep(&bp, ":\n");
298 if (!(cp = strsep(&bp, ":\n")))
299 return 0;
300 id = strtoul(cp, &ep, 10);
301 if (id > GID_MAX || *ep != '\0')
302 return 0;
303 _gr_group.gr_gid = (gid_t)id;
304 if (search && name == NULL && _gr_group.gr_gid != gid)
305 return 0;
306 cp = NULL;
307 if (bp == NULL)
308 return 0;
309 for (_gr_group.gr_mem = m = members;; bp++) {
310 if (m == &members[MAXGRP - 1])
311 break;
312 if (*bp == ',') {
313 if (cp) {
314 *bp = '\0';
315 *m++ = cp;
316 cp = NULL;
318 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
319 if (cp) {
320 *bp = '\0';
321 *m++ = cp;
323 break;
324 } else if (cp == NULL)
325 cp = bp;
327 *m = NULL;
328 if (user) {
329 for (m = members; *m; m++)
330 if (!strcmp(user, *m))
331 return 1;
332 return 0;
334 return 1;