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