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