xref: /openbsd/lib/libc/gen/getgrent.c (revision 133306f0)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * Portions Copyright (c) 1994, Jason Downs. All Rights Reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by the University of
17  *	California, Berkeley and its contributors.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #if defined(LIBC_SCCS) && !defined(lint)
36 static char rcsid[] = "$OpenBSD: getgrent.c,v 1.13 2000/09/24 14:35:10 d Exp $";
37 #endif /* LIBC_SCCS and not lint */
38 
39 #include <sys/types.h>
40 #include <sys/param.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <grp.h>
45 #ifdef YP
46 #include <rpc/rpc.h>
47 #include <rpcsvc/yp.h>
48 #include <rpcsvc/ypclnt.h>
49 #include "ypinternal.h"
50 #endif
51 #include "thread_private.h"
52 
53 _THREAD_PRIVATE_KEY(gr);
54 _THREAD_PRIVATE_MUTEX(gr);
55 static FILE *_gr_fp;
56 static struct group _gr_group;
57 static int _gr_stayopen;
58 static int grscan __P((int, gid_t, const char *, struct group *));
59 static int start_gr __P((void));
60 static void endgrent_basic __P((void));
61 
62 _THREAD_PRIVATE_KEY(gr_storage);
63 static struct group_storage {
64 #define	MAXGRP		200
65 	char *members[MAXGRP];
66 #define	MAXLINELENGTH	1024
67 	char line[MAXLINELENGTH];
68 } gr_storage;
69 
70 #ifdef YP
71 enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_NAME };
72 static enum _ypmode __ypmode;
73 static char	*__ypcurrent, *__ypdomain;
74 static int	__ypcurrentlen;
75 #endif
76 
77 struct group *
78 getgrent_r(p_gr)
79 struct group *p_gr;
80 {
81 	_THREAD_PRIVATE_MUTEX_LOCK(gr);
82 	if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL, p_gr))
83 		p_gr = NULL;
84 	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
85 	return (p_gr);
86 }
87 
88 struct group *
89 getgrent()
90 {
91 	struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL);
92 
93 	return getgrent_r(p_gr);
94 }
95 
96 struct group *
97 getgrnam_r(name, p_gr)
98 	const char *name;
99 	struct group *p_gr;
100 {
101 	int rval;
102 
103 	_THREAD_PRIVATE_MUTEX_LOCK(gr);
104 	if (!start_gr())
105 		rval = 0;
106 	else {
107 		rval = grscan(1, 0, name, p_gr);
108 		if (!_gr_stayopen)
109 			endgrent_basic();
110 	}
111 	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
112 	return(rval ? p_gr : NULL);
113 }
114 
115 struct group *
116 getgrnam(name)
117 	const char *name;
118 {
119 	struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL);
120 
121 	return getgrnam_r(name, p_gr);
122 }
123 
124 struct group *
125 getgrgid_r(gid, p_gr)
126 	gid_t gid;
127 	struct group *p_gr;
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);
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 *
144 getgrgid(gid)
145 	gid_t gid;
146 {
147 	struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL);
148 
149 	return getgrgid_r(gid, p_gr);
150 }
151 
152 static int
153 start_gr()
154 {
155 	if (_gr_fp) {
156 		rewind(_gr_fp);
157 #ifdef YP
158 		__ypmode = YPMODE_NONE;
159 		if(__ypcurrent)
160 			free(__ypcurrent);
161 		__ypcurrent = NULL;
162 #endif
163 		return(1);
164 	}
165 	return((_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0);
166 }
167 
168 void
169 setgrent()
170 {
171 	(void) setgroupent(0);
172 }
173 
174 int
175 setgroupent(stayopen)
176 	int stayopen;
177 {
178 	int retval;
179 
180 	_THREAD_PRIVATE_MUTEX_LOCK(gr);
181 	if (!start_gr())
182 		retval = 0;
183 	else {
184 		_gr_stayopen = stayopen;
185 		retval = 1;
186 	}
187 	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
188 	return (retval);
189 }
190 
191 static
192 void
193 endgrent_basic()
194 {
195 	if (_gr_fp) {
196 		(void)fclose(_gr_fp);
197 		_gr_fp = NULL;
198 #ifdef YP
199 		__ypmode = YPMODE_NONE;
200 		if(__ypcurrent)
201 			free(__ypcurrent);
202 		__ypcurrent = NULL;
203 #endif
204 	}
205 }
206 
207 void
208 endgrent()
209 {
210 	_THREAD_PRIVATE_MUTEX_LOCK(gr);
211 	endgrent_basic();
212 	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
213 }
214 
215 static int
216 grscan(search, gid, name, p_gr)
217 	register int search;
218 	register gid_t gid;
219 	register const char *name;
220 	struct group *p_gr;
221 {
222 	register char *cp, **m;
223 	char *bp, *endp;
224 	u_long ul;
225 #ifdef YP
226 	char *key, *data;
227 	int keylen, datalen;
228 	int r;
229 	char *grname = (char *)NULL;
230 #endif
231 	char **members;
232 	char *line;
233 	struct group_storage *gs;
234 
235 	/* Always use thread-specific storage for member data. */
236 	gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,gr_storage,NULL);
237 	if (gs == NULL)
238 		return 0;
239 	members = gs->members;
240 	line = gs->line;
241 
242 	for (;;) {
243 #ifdef YP
244 		if(__ypmode != YPMODE_NONE) {
245 
246 			if(!__ypdomain) {
247 				if(yp_get_default_domain(&__ypdomain)) {
248 					__ypmode = YPMODE_NONE;
249 					if(grname != (char *)NULL) {
250 						free(grname);
251 						grname = (char *)NULL;
252 					}
253 					continue;
254 				}
255 			}
256 			switch(__ypmode) {
257 			case YPMODE_FULL:
258 				if(__ypcurrent) {
259 					r = yp_next(__ypdomain, "group.byname",
260 						__ypcurrent, __ypcurrentlen,
261 						&key, &keylen, &data, &datalen);
262 					free(__ypcurrent);
263 					if(r != 0) {
264 						__ypcurrent = NULL;
265 						__ypmode = YPMODE_NONE;
266 						free(data);
267 						continue;
268 					}
269 					__ypcurrent = key;
270 					__ypcurrentlen = keylen;
271 					bcopy(data, line, datalen);
272 					free(data);
273 				} else {
274 					r = yp_first(__ypdomain, "group.byname",
275 						&__ypcurrent, &__ypcurrentlen,
276 						&data, &datalen);
277 					if(r != 0) {
278 						__ypmode = YPMODE_NONE;
279 						free(data);
280 						continue;
281 					}
282 					bcopy(data, line, datalen);
283 					free(data);
284 				}
285 				break;
286 			case YPMODE_NAME:
287 				if(grname != (char *)NULL) {
288 					r = yp_match(__ypdomain, "group.byname",
289 						grname, strlen(grname),
290 						&data, &datalen);
291 					__ypmode = YPMODE_NONE;
292 					free(grname);
293 					grname = (char *)NULL;
294 					if(r != 0) {
295 						free(data);
296 						continue;
297 					}
298 					bcopy(data, line, datalen);
299 					free(data);
300 				} else {
301 					__ypmode = YPMODE_NONE;	/* ??? */
302 					continue;
303 				}
304 				break;
305 			}
306 			line[datalen] = '\0';
307 			bp = line;
308 			goto parse;
309 		}
310 #endif
311 		if (!fgets(line, sizeof(gs->line), _gr_fp))
312 			return(0);
313 		bp = line;
314 		/* skip lines that are too big */
315 		if (!strchr(line, '\n')) {
316 			int ch;
317 
318 			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
319 				;
320 			continue;
321 		}
322 #ifdef YP
323 		if (line[0] == '+') {
324 			switch(line[1]) {
325 			case ':':
326 			case '\0':
327 			case '\n':
328 				if(_yp_check(NULL)) {
329 					if (!search) {
330 						__ypmode = YPMODE_FULL;
331 						continue;
332 					}
333 					if(!__ypdomain &&
334 					   yp_get_default_domain(&__ypdomain))
335 						continue;
336 					if (name) {
337 						r = yp_match(__ypdomain,
338 							     "group.byname",
339 							     name, strlen(name),
340 							     &data, &datalen);
341 					} else {
342 						char buf[20];
343 						sprintf(buf, "%u", gid);
344 						r = yp_match(__ypdomain,
345 							     "group.bygid",
346 							     buf, strlen(buf),
347 							     &data, &datalen);
348 					}
349 					if (r != 0)
350 						continue;
351 					bcopy(data, line, datalen);
352 					free(data);
353 					line[datalen] = '\0';
354 					bp = line;
355 					p_gr->gr_name = strsep(&bp, ":\n");
356 					p_gr->gr_passwd =
357 						strsep(&bp, ":\n");
358 					if (!(cp = strsep(&bp, ":\n")))
359 						continue;
360 					if (name) {
361 						ul = strtoul(cp, &endp, 10);
362 						if (*endp != '\0' ||
363 						    endp == cp || ul >= GID_MAX)
364 							continue;
365 						p_gr->gr_gid = ul;
366 					} else
367 						p_gr->gr_gid = gid;
368 					goto found_it;
369 				}
370 				break;
371 			default:
372 				if(_yp_check(NULL)) {
373 					register char *tptr;
374 
375 					tptr = strsep(&bp, ":\n");
376 					if (search && name && strcmp(tptr, name))
377 						continue;
378 					__ypmode = YPMODE_NAME;
379 					grname = strdup(tptr + 1);
380 					continue;
381 				}
382 				break;
383 			}
384 		}
385 parse:
386 #endif
387 		p_gr->gr_name = strsep(&bp, ":\n");
388 		if (search && name && strcmp(p_gr->gr_name, name))
389 			continue;
390 		p_gr->gr_passwd = strsep(&bp, ":\n");
391 		if (!(cp = strsep(&bp, ":\n")))
392 			continue;
393 		ul = strtoul(cp, &endp, 10);
394 		if (endp == cp || *endp != '\0' || ul >= GID_MAX)
395 			continue;
396 		p_gr->gr_gid = ul;
397 		if (search && name == NULL && p_gr->gr_gid != gid)
398 			continue;
399 	found_it:
400 		cp = NULL;
401 		if (bp == NULL)
402 			continue;
403 		for (m = p_gr->gr_mem = members;; bp++) {
404 			if (m == &members[MAXGRP - 1])
405 				break;
406 			if (*bp == ',') {
407 				if (cp) {
408 					*bp = '\0';
409 					*m++ = cp;
410 					cp = NULL;
411 				}
412 			} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
413 				if (cp) {
414 					*bp = '\0';
415 					*m++ = cp;
416 				}
417 				break;
418 			} else if (cp == NULL)
419 				cp = bp;
420 		}
421 		*m = NULL;
422 		return(1);
423 	}
424 	/* NOTREACHED */
425 }
426