1 /* $OpenBSD: getgrent.c,v 1.23 2005/08/08 08:05:34 espie Exp $ */
2 /*
3 * Copyright (c) 1989, 1993
4 * The Regents of the University of California. All rights reserved.
5 * Portions Copyright (c) 1994, Jason Downs. 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 #include <sys/param.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <grp.h>
37 #include <errno.h>
38 #include "thread_private.h"
39
40 __RCSID("$MirOS: src/lib/libc/gen/getgrent.c,v 1.3 2005/09/22 20:39:59 tg Exp $");
41
42 /* This global storage is locked for the non-rentrant functions */
43 _THREAD_PRIVATE_KEY(gr_storage);
44 static struct group_storage {
45 #define MAXGRP 200
46 char *members[MAXGRP];
47 #define MAXLINELENGTH 1024
48 char line[MAXLINELENGTH];
49 } gr_storage;
50 #define GETGR_R_SIZE_MAX (1024+200*sizeof(char*))
51
52 /* File pointers are locked with the 'gr' mutex */
53 _THREAD_PRIVATE_KEY(gr);
54 static FILE *_gr_fp;
55 static struct group _gr_group;
56 static int _gr_stayopen;
57 static int grscan(int, gid_t, const char *, struct group *, struct group_storage *);
58 static int start_gr(void);
59 static void endgrent_basic(void);
60
61 static struct group *getgrnam_gs(const char *, struct group *,
62 struct group_storage *);
63 static struct group *getgrgid_gs(gid_t, struct group *,
64 struct group_storage *);
65
66 struct group *
getgrent(void)67 getgrent(void)
68 {
69 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr, _gr_group, NULL);
70 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,
71 gr_storage, NULL);
72
73 _THREAD_PRIVATE_MUTEX_LOCK(gr);
74 if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL, p_gr, gs))
75 p_gr = NULL;
76 _THREAD_PRIVATE_MUTEX_UNLOCK(gr);
77 return (p_gr);
78 }
79
80 static struct group *
getgrnam_gs(const char * name,struct group * p_gr,struct group_storage * gs)81 getgrnam_gs(const char *name, struct group *p_gr, struct group_storage *gs)
82 {
83 int rval;
84
85 _THREAD_PRIVATE_MUTEX_LOCK(gr);
86 if (!start_gr())
87 rval = 0;
88 else {
89 rval = grscan(1, 0, name, p_gr, gs);
90 if (!_gr_stayopen)
91 endgrent_basic();
92 }
93 _THREAD_PRIVATE_MUTEX_UNLOCK(gr);
94 return(rval ? p_gr : NULL);
95 }
96
97 struct group *
getgrnam(const char * name)98 getgrnam(const char *name)
99 {
100 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL);
101 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,
102 gr_storage, NULL);
103
104 return getgrnam_gs(name, p_gr, gs);
105 }
106
107 int
getgrnam_r(const char * name,struct group * grp,char * buffer,size_t bufsize,struct group ** result)108 getgrnam_r(const char *name, struct group *grp, char *buffer,
109 size_t bufsize, struct group **result)
110 {
111 int errnosave;
112 int ret;
113
114 if (bufsize < GETGR_R_SIZE_MAX)
115 return ERANGE;
116 errnosave = errno;
117 *result = getgrnam_gs(name, grp, (struct group_storage *)buffer);
118 if (*result == NULL)
119 ret = errno;
120 else
121 ret = 0;
122 errno = errnosave;
123 return ret;
124 }
125
126 static struct group *
getgrgid_gs(gid_t gid,struct group * p_gr,struct group_storage * gs)127 getgrgid_gs(gid_t gid, struct group *p_gr, struct group_storage *gs)
128 {
129 int rval;
130
131 _THREAD_PRIVATE_MUTEX_LOCK(gr);
132 if (!start_gr())
133 rval = 0;
134 else {
135 rval = grscan(1, gid, NULL, p_gr, gs);
136 if (!_gr_stayopen)
137 endgrent_basic();
138 }
139 _THREAD_PRIVATE_MUTEX_UNLOCK(gr);
140 return(rval ? p_gr : NULL);
141 }
142
143 struct group *
getgrgid(gid_t gid)144 getgrgid(gid_t gid)
145 {
146 struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr, _gr_group, NULL);
147 struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,
148 gr_storage, NULL);
149
150 return getgrgid_gs(gid, p_gr, gs);
151 }
152
153 int
getgrgid_r(gid_t gid,struct group * grp,char * buffer,size_t bufsize,struct group ** result)154 getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize,
155 struct group **result)
156 {
157 int errnosave;
158 int ret;
159
160 if (bufsize < GETGR_R_SIZE_MAX)
161 return ERANGE;
162 errnosave = errno;
163 *result = getgrgid_gs(gid, grp, (struct group_storage *)buffer);
164 if (*result == NULL)
165 ret = errno;
166 else
167 ret = 0;
168 errno = errnosave;
169 return ret;
170 }
171
172 static int
start_gr(void)173 start_gr(void)
174 {
175 if (_gr_fp) {
176 rewind(_gr_fp);
177 return(1);
178 }
179 return((_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0);
180 }
181
182 void
setgrent(void)183 setgrent(void)
184 {
185 (void) setgroupent(0);
186 }
187
188 int
setgroupent(int stayopen)189 setgroupent(int stayopen)
190 {
191 int retval;
192
193 _THREAD_PRIVATE_MUTEX_LOCK(gr);
194 if (!start_gr())
195 retval = 0;
196 else {
197 _gr_stayopen = stayopen;
198 retval = 1;
199 }
200 _THREAD_PRIVATE_MUTEX_UNLOCK(gr);
201 return (retval);
202 }
203
204 static
205 void
endgrent_basic(void)206 endgrent_basic(void)
207 {
208 if (_gr_fp) {
209 (void)fclose(_gr_fp);
210 _gr_fp = NULL;
211 }
212 }
213
214 void
endgrent(void)215 endgrent(void)
216 {
217 _THREAD_PRIVATE_MUTEX_LOCK(gr);
218 endgrent_basic();
219 _THREAD_PRIVATE_MUTEX_UNLOCK(gr);
220 }
221
222 static int
grscan(int search,gid_t gid,const char * name,struct group * p_gr,struct group_storage * gs)223 grscan(int search, gid_t gid, const char *name, struct group *p_gr,
224 struct group_storage *gs)
225 {
226 char *cp, **m;
227 char *bp, *endp;
228 u_long ul;
229 char **members;
230 char *line;
231
232 if (gs == NULL)
233 return 0;
234 members = gs->members;
235 line = gs->line;
236
237 for (;;) {
238 if (!fgets(line, sizeof(gs->line), _gr_fp))
239 return(0);
240 bp = line;
241 /* skip lines that are too big */
242 if (!strchr(line, '\n')) {
243 int ch;
244
245 while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
246 ;
247 continue;
248 }
249 p_gr->gr_name = strsep(&bp, ":\n");
250 if (search && name && strcmp(p_gr->gr_name, name))
251 continue;
252 p_gr->gr_passwd = strsep(&bp, ":\n");
253 if (!(cp = strsep(&bp, ":\n")))
254 continue;
255 ul = strtoul(cp, &endp, 10);
256 if (endp == cp || *endp != '\0' || ul >= GID_MAX)
257 continue;
258 p_gr->gr_gid = ul;
259 if (search && name == NULL && p_gr->gr_gid != gid)
260 continue;
261 /* found_it: */
262 cp = NULL;
263 if (bp == NULL)
264 continue;
265 for (m = p_gr->gr_mem = members;; bp++) {
266 if (m == &members[MAXGRP - 1])
267 break;
268 if (*bp == ',') {
269 if (cp) {
270 *bp = '\0';
271 *m++ = cp;
272 cp = NULL;
273 }
274 } else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
275 if (cp) {
276 *bp = '\0';
277 *m++ = cp;
278 }
279 break;
280 } else if (cp == NULL)
281 cp = bp;
282 }
283 *m = NULL;
284 return(1);
285 }
286 /* NOTREACHED */
287 }
288