xref: /openbsd-src/lib/libc/gen/getgrent.c (revision 8445c53715e7030056b779e8ab40efb7820981f2)
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.14 2001/09/11 04:52:50 pvalchev 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 #include <errno.h>
46 #ifdef YP
47 #include <rpc/rpc.h>
48 #include <rpcsvc/yp.h>
49 #include <rpcsvc/ypclnt.h>
50 #include "ypinternal.h"
51 #endif
52 #include "thread_private.h"
53 
54 /* This global storage is locked for the non-rentrant functions */
55 _THREAD_PRIVATE_KEY(gr_storage);
56 static struct group_storage {
57 #define	MAXGRP		200
58 	char *members[MAXGRP];
59 #define	MAXLINELENGTH	1024
60 	char line[MAXLINELENGTH];
61 } gr_storage;
62 #define GETGR_R_SIZE_MAX	(1024+200*sizeof(char*))
63 
64 /* File pointers are locked with the 'gr' mutex */
65 _THREAD_PRIVATE_KEY(gr);
66 _THREAD_PRIVATE_MUTEX(gr);
67 static FILE *_gr_fp;
68 static struct group _gr_group;
69 static int _gr_stayopen;
70 static int grscan __P((int, gid_t, const char *, struct group *, struct group_storage *));
71 static int start_gr __P((void));
72 static void endgrent_basic __P((void));
73 
74 static struct group *getgrnam_gs(const char *, struct group *,
75 	struct group_storage *);
76 static struct group *getgrgid_gs(gid_t, struct group *,
77 	struct group_storage *);
78 
79 #ifdef YP
80 enum _ypmode { YPMODE_NONE, YPMODE_FULL, YPMODE_NAME };
81 static enum _ypmode __ypmode;
82 static char	*__ypcurrent, *__ypdomain;
83 static int	__ypcurrentlen;
84 #endif
85 
86 struct group *
87 getgrent()
88 {
89 	struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL);
90 	struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,gr_storage,NULL);
91 
92 	_THREAD_PRIVATE_MUTEX_LOCK(gr);
93 	if ((!_gr_fp && !start_gr()) || !grscan(0, 0, NULL, p_gr, gs))
94 		p_gr = NULL;
95 	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
96 	return (p_gr);
97 }
98 
99 static struct group *
100 getgrnam_gs(name, p_gr, gs)
101 	const char *name;
102 	struct group *p_gr;
103 	struct group_storage *gs;
104 {
105 	int rval;
106 
107 	_THREAD_PRIVATE_MUTEX_LOCK(gr);
108 	if (!start_gr())
109 		rval = 0;
110 	else {
111 		rval = grscan(1, 0, name, p_gr, gs);
112 		if (!_gr_stayopen)
113 			endgrent_basic();
114 	}
115 	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
116 	return(rval ? p_gr : NULL);
117 }
118 
119 struct group *
120 getgrnam(name)
121 	const char *name;
122 {
123 	struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL);
124 	struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,gr_storage,NULL);
125 
126 	return getgrnam_gs(name, p_gr, gs);
127 }
128 
129 int
130 getgrnam_r(name, grp, buffer, bufsize, result)
131 	const char *name;
132 	struct group *grp;
133 	char *buffer;
134 	size_t bufsize;
135 	struct group **result;
136 {
137 	int errnosave;
138 	int ret;
139 
140 	if (bufsize < GETGR_R_SIZE_MAX)
141 		return ERANGE;
142 	errnosave = errno;
143 	*result = getgrnam_gs(name, grp, (struct group_storage *)buffer);
144 	if (*result == NULL)
145 		ret = errno;
146 	else
147 		ret = 0;
148 	errno = errnosave;
149 	return ret;
150 }
151 
152 static struct group *
153 getgrgid_gs(gid, p_gr, gs)
154 	gid_t gid;
155 	struct group *p_gr;
156 	struct group_storage *gs;
157 {
158 	int rval;
159 
160 	_THREAD_PRIVATE_MUTEX_LOCK(gr);
161 	if (!start_gr())
162 		rval = 0;
163 	else {
164 		rval = grscan(1, gid, NULL, p_gr, gs);
165 		if (!_gr_stayopen)
166 			endgrent_basic();
167 	}
168 	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
169 	return(rval ? p_gr : NULL);
170 }
171 
172 struct group *
173 getgrgid(gid)
174 	gid_t gid;
175 {
176 	struct group *p_gr = (struct group*)_THREAD_PRIVATE(gr,_gr_group,NULL);
177 	struct group_storage *gs = (struct group_storage *)_THREAD_PRIVATE(gr_storage,gr_storage,NULL);
178 
179 	return getgrgid_gs(gid, p_gr, gs);
180 }
181 
182 int
183 getgrgid_r(gid, grp, buffer, bufsize, result)
184 	gid_t gid;
185 	struct group *grp;
186 	char *buffer;
187 	size_t bufsize;
188 	struct group **result;
189 {
190 	int errnosave;
191 	int ret;
192 
193 	if (bufsize < GETGR_R_SIZE_MAX)
194 		return ERANGE;
195 	errnosave = errno;
196 	*result = getgrgid_gs(gid, grp, (struct group_storage *)buffer);
197 	if (*result == NULL)
198 		ret = errno;
199 	else
200 		ret = 0;
201 	errno = errnosave;
202 	return ret;
203 }
204 
205 static int
206 start_gr()
207 {
208 	if (_gr_fp) {
209 		rewind(_gr_fp);
210 #ifdef YP
211 		__ypmode = YPMODE_NONE;
212 		if(__ypcurrent)
213 			free(__ypcurrent);
214 		__ypcurrent = NULL;
215 #endif
216 		return(1);
217 	}
218 	return((_gr_fp = fopen(_PATH_GROUP, "r")) ? 1 : 0);
219 }
220 
221 void
222 setgrent()
223 {
224 	(void) setgroupent(0);
225 }
226 
227 int
228 setgroupent(stayopen)
229 	int stayopen;
230 {
231 	int retval;
232 
233 	_THREAD_PRIVATE_MUTEX_LOCK(gr);
234 	if (!start_gr())
235 		retval = 0;
236 	else {
237 		_gr_stayopen = stayopen;
238 		retval = 1;
239 	}
240 	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
241 	return (retval);
242 }
243 
244 static
245 void
246 endgrent_basic()
247 {
248 	if (_gr_fp) {
249 		(void)fclose(_gr_fp);
250 		_gr_fp = NULL;
251 #ifdef YP
252 		__ypmode = YPMODE_NONE;
253 		if(__ypcurrent)
254 			free(__ypcurrent);
255 		__ypcurrent = NULL;
256 #endif
257 	}
258 }
259 
260 void
261 endgrent()
262 {
263 	_THREAD_PRIVATE_MUTEX_LOCK(gr);
264 	endgrent_basic();
265 	_THREAD_PRIVATE_MUTEX_UNLOCK(gr);
266 }
267 
268 static int
269 grscan(search, gid, name, p_gr, gs)
270 	register int search;
271 	register gid_t gid;
272 	register const char *name;
273 	struct group *p_gr;
274 	struct group_storage *gs;
275 {
276 	register char *cp, **m;
277 	char *bp, *endp;
278 	u_long ul;
279 #ifdef YP
280 	char *key, *data;
281 	int keylen, datalen;
282 	int r;
283 	char *grname = (char *)NULL;
284 #endif
285 	char **members;
286 	char *line;
287 
288 	if (gs == NULL)
289 		return 0;
290 	members = gs->members;
291 	line = gs->line;
292 
293 	for (;;) {
294 #ifdef YP
295 		if(__ypmode != YPMODE_NONE) {
296 
297 			if(!__ypdomain) {
298 				if(yp_get_default_domain(&__ypdomain)) {
299 					__ypmode = YPMODE_NONE;
300 					if(grname != (char *)NULL) {
301 						free(grname);
302 						grname = (char *)NULL;
303 					}
304 					continue;
305 				}
306 			}
307 			switch(__ypmode) {
308 			case YPMODE_FULL:
309 				if(__ypcurrent) {
310 					r = yp_next(__ypdomain, "group.byname",
311 						__ypcurrent, __ypcurrentlen,
312 						&key, &keylen, &data, &datalen);
313 					free(__ypcurrent);
314 					if(r != 0) {
315 						__ypcurrent = NULL;
316 						__ypmode = YPMODE_NONE;
317 						free(data);
318 						continue;
319 					}
320 					__ypcurrent = key;
321 					__ypcurrentlen = keylen;
322 					bcopy(data, line, datalen);
323 					free(data);
324 				} else {
325 					r = yp_first(__ypdomain, "group.byname",
326 						&__ypcurrent, &__ypcurrentlen,
327 						&data, &datalen);
328 					if(r != 0) {
329 						__ypmode = YPMODE_NONE;
330 						free(data);
331 						continue;
332 					}
333 					bcopy(data, line, datalen);
334 					free(data);
335 				}
336 				break;
337 			case YPMODE_NAME:
338 				if(grname != (char *)NULL) {
339 					r = yp_match(__ypdomain, "group.byname",
340 						grname, strlen(grname),
341 						&data, &datalen);
342 					__ypmode = YPMODE_NONE;
343 					free(grname);
344 					grname = (char *)NULL;
345 					if(r != 0) {
346 						free(data);
347 						continue;
348 					}
349 					bcopy(data, line, datalen);
350 					free(data);
351 				} else {
352 					__ypmode = YPMODE_NONE;	/* ??? */
353 					continue;
354 				}
355 				break;
356 			}
357 			line[datalen] = '\0';
358 			bp = line;
359 			goto parse;
360 		}
361 #endif
362 		if (!fgets(line, sizeof(gs->line), _gr_fp))
363 			return(0);
364 		bp = line;
365 		/* skip lines that are too big */
366 		if (!strchr(line, '\n')) {
367 			int ch;
368 
369 			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
370 				;
371 			continue;
372 		}
373 #ifdef YP
374 		if (line[0] == '+') {
375 			switch(line[1]) {
376 			case ':':
377 			case '\0':
378 			case '\n':
379 				if(_yp_check(NULL)) {
380 					if (!search) {
381 						__ypmode = YPMODE_FULL;
382 						continue;
383 					}
384 					if(!__ypdomain &&
385 					   yp_get_default_domain(&__ypdomain))
386 						continue;
387 					if (name) {
388 						r = yp_match(__ypdomain,
389 							     "group.byname",
390 							     name, strlen(name),
391 							     &data, &datalen);
392 					} else {
393 						char buf[20];
394 						sprintf(buf, "%u", gid);
395 						r = yp_match(__ypdomain,
396 							     "group.bygid",
397 							     buf, strlen(buf),
398 							     &data, &datalen);
399 					}
400 					if (r != 0)
401 						continue;
402 					bcopy(data, line, datalen);
403 					free(data);
404 					line[datalen] = '\0';
405 					bp = line;
406 					p_gr->gr_name = strsep(&bp, ":\n");
407 					p_gr->gr_passwd =
408 						strsep(&bp, ":\n");
409 					if (!(cp = strsep(&bp, ":\n")))
410 						continue;
411 					if (name) {
412 						ul = strtoul(cp, &endp, 10);
413 						if (*endp != '\0' ||
414 						    endp == cp || ul >= GID_MAX)
415 							continue;
416 						p_gr->gr_gid = ul;
417 					} else
418 						p_gr->gr_gid = gid;
419 					goto found_it;
420 				}
421 				break;
422 			default:
423 				if(_yp_check(NULL)) {
424 					register char *tptr;
425 
426 					tptr = strsep(&bp, ":\n");
427 					if (search && name && strcmp(tptr, name))
428 						continue;
429 					__ypmode = YPMODE_NAME;
430 					grname = strdup(tptr + 1);
431 					continue;
432 				}
433 				break;
434 			}
435 		}
436 parse:
437 #endif
438 		p_gr->gr_name = strsep(&bp, ":\n");
439 		if (search && name && strcmp(p_gr->gr_name, name))
440 			continue;
441 		p_gr->gr_passwd = strsep(&bp, ":\n");
442 		if (!(cp = strsep(&bp, ":\n")))
443 			continue;
444 		ul = strtoul(cp, &endp, 10);
445 		if (endp == cp || *endp != '\0' || ul >= GID_MAX)
446 			continue;
447 		p_gr->gr_gid = ul;
448 		if (search && name == NULL && p_gr->gr_gid != gid)
449 			continue;
450 	found_it:
451 		cp = NULL;
452 		if (bp == NULL)
453 			continue;
454 		for (m = p_gr->gr_mem = members;; bp++) {
455 			if (m == &members[MAXGRP - 1])
456 				break;
457 			if (*bp == ',') {
458 				if (cp) {
459 					*bp = '\0';
460 					*m++ = cp;
461 					cp = NULL;
462 				}
463 			} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
464 				if (cp) {
465 					*bp = '\0';
466 					*m++ = cp;
467 				}
468 				break;
469 			} else if (cp == NULL)
470 				cp = bp;
471 		}
472 		*m = NULL;
473 		return(1);
474 	}
475 	/* NOTREACHED */
476 }
477