xref: /netbsd-src/lib/libc/gen/getgrent.c (revision a5a68ff5f29de57339ca14f6c671c0a87714f1f8)
1 /*	$NetBSD: getgrent.c,v 1.21 1997/07/21 14:07:05 jtc 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.21 1997/07/21 14:07:05 jtc 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, 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, 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, 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, strlen(name),
296 							     &data, &datalen);
297 					} else {
298 						char buf[20];
299 						snprintf(buf, sizeof(buf),
300 						    "%u", gid);
301 						r = yp_match(__ypdomain,
302 							     "group.bygid",
303 							     buf, strlen(buf),
304 							     &data, &datalen);
305 					}
306 					if (r != 0) {
307 						if (data)
308 							free(data);
309 						continue;
310 					}
311 					bcopy(data, line, datalen);
312 					free(data);
313 					line[datalen] = '\0';
314 					bp = line;
315 					_gr_group.gr_name = strsep(&bp, ":\n");
316 					_gr_group.gr_passwd =
317 					    strsep(&bp, ":\n");
318 					if (!(cp = strsep(&bp, ":\n")))
319 						continue;
320 					if (name) {
321 						id = strtoul(cp, &ep, 10);
322 						if (id > GID_MAX || *ep != '\0')
323 							continue;
324 						_gr_group.gr_gid = (gid_t)id;
325 					} else
326 						_gr_group.gr_gid = gid;
327 					goto found_it;
328 				}
329 				break;
330 			default:
331 				if (_yp_check(NULL)) {
332 					char *tptr;
333 
334 					tptr = strsep(&bp, ":\n");
335 					if (search && name &&
336 					    strcmp(tptr, name))
337 						continue;
338 					__ypmode = YPMODE_NAME;
339 					grname = strdup(tptr + 1);
340 					continue;
341 				}
342 				break;
343 			}
344 		}
345 parse:
346 #endif /* YP */
347 		_gr_group.gr_name = strsep(&bp, ":\n");
348 		if (search && name && strcmp(_gr_group.gr_name, name))
349 			continue;
350 		_gr_group.gr_passwd = strsep(&bp, ":\n");
351 		if (!(cp = strsep(&bp, ":\n")))
352 			continue;
353 		id = strtoul(cp, &ep, 10);
354 		if (id > GID_MAX || *ep != '\0')
355 			continue;
356 		_gr_group.gr_gid = (gid_t)id;
357 		if (search && name == NULL && _gr_group.gr_gid != gid)
358 			continue;
359 	found_it:
360 		cp = NULL;
361 		if (bp == NULL)
362 			continue;
363 		for (m = _gr_group.gr_mem = members;; bp++) {
364 			if (m == &members[MAXGRP - 1])
365 				break;
366 			if (*bp == ',') {
367 				if (cp) {
368 					*bp = '\0';
369 					*m++ = cp;
370 					cp = NULL;
371 				}
372 			} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
373 				if (cp) {
374 					*bp = '\0';
375 					*m++ = cp;
376 				}
377 				break;
378 			} else if (cp == NULL)
379 				cp = bp;
380 		}
381 		*m = NULL;
382 		return(1);
383 	}
384 	/* NOTREACHED */
385 }
386