xref: /freebsd/lib/libc/gen/getgrent.c (revision 8e6b01171e30297084bb0b4457c4183c2746aacc)
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 #include <rpc/rpc.h>
50 #include <rpcsvc/yp_prot.h>
51 #include <rpcsvc/ypclnt.h>
52 static int _gr_stepping_yp;
53 static int _gr_yp_enabled;
54 static int _getypgroup(struct group *, const char *, char *);
55 static int _nextypgroup(struct group *);
56 #endif
57 
58 #define	MAXGRP		200
59 static char *members[MAXGRP];
60 #define	MAXLINELENGTH	1024
61 static char line[MAXLINELENGTH];
62 
63 struct group *
64 getgrent()
65 {
66 	if (!_gr_fp && !start_gr()) {
67 		return NULL;
68 	}
69 
70 #ifdef YP
71 	if (_gr_stepping_yp) {
72 		if (_nextypgroup(&_gr_group))
73 			return(&_gr_group);
74 	}
75 tryagain:
76 #endif
77 
78 	if (!grscan(0, 0, NULL))
79 		return(NULL);
80 #ifdef YP
81 	if(_gr_group.gr_name[0] == '+' && _gr_group.gr_name[1]) {
82 		_getypgroup(&_gr_group, &_gr_group.gr_name[1],
83 			    "group.byname");
84 	} else if(_gr_group.gr_name[0] == '+') {
85 		if (!_nextypgroup(&_gr_group))
86 			goto tryagain;
87 		else
88 			return(&_gr_group);
89 	}
90 #endif
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 #ifdef YP
103 	tryagain:
104 #endif
105 	rval = grscan(1, 0, name);
106 #ifdef YP
107 	if(rval == -1 && (_gr_yp_enabled < 0 || (_gr_yp_enabled &&
108 					_gr_group.gr_name[0] == '+'))) {
109 		if (!(rval = _getypgroup(&_gr_group, name, "group.byname")))
110 			goto tryagain;
111 	}
112 #endif
113 	if (!_gr_stayopen)
114 		endgrent();
115 	return(rval ? &_gr_group : NULL);
116 }
117 
118 struct group *
119 #ifdef __STDC__
120 getgrgid(gid_t gid)
121 #else
122 getgrgid(gid)
123 	gid_t gid;
124 #endif
125 {
126 	int rval;
127 
128 	if (!start_gr())
129 		return(NULL);
130 #ifdef YP
131 	tryagain:
132 #endif
133 	rval = grscan(1, gid, NULL);
134 #ifdef YP
135 	if(rval == -1 && _gr_yp_enabled) {
136 		char buf[16];
137 		snprintf(buf, sizeof buf, "%d", (unsigned)gid);
138 		if (!(rval = _getypgroup(&_gr_group, buf, "group.bygid")))
139 			goto tryagain;
140 	}
141 #endif
142 	if (!_gr_stayopen)
143 		endgrent();
144 	return(rval ? &_gr_group : NULL);
145 }
146 
147 static int
148 start_gr()
149 {
150 	if (_gr_fp) {
151 		rewind(_gr_fp);
152 		return(1);
153 	}
154 	_gr_fp = fopen(_PATH_GROUP, "r");
155 	if(!_gr_fp) return 0;
156 #ifdef YP
157 	/*
158 	 * This is a disgusting hack, used to determine when YP is enabled.
159 	 * This would be easier if we had a group database to go along with
160 	 * the password database.
161 	 */
162 	{
163 		char *line;
164 		size_t linelen;
165 		_gr_yp_enabled = 0;
166 		while((line = fgetln(_gr_fp, &linelen)) != NULL) {
167 			if(line[0] == '+') {
168 				if(line[1] && !_gr_yp_enabled) {
169 					_gr_yp_enabled = 1;
170 				} else {
171 					_gr_yp_enabled = -1;
172 					break;
173 				}
174 			}
175 		}
176 		rewind(_gr_fp);
177 	}
178 #endif
179 	return 1;
180 }
181 
182 int
183 setgrent()
184 {
185 	return(setgroupent(0));
186 }
187 
188 int
189 setgroupent(stayopen)
190 	int stayopen;
191 {
192 	if (!start_gr())
193 		return(0);
194 	_gr_stayopen = stayopen;
195 #ifdef YP
196 	_gr_stepping_yp = 0;
197 #endif
198 	return(1);
199 }
200 
201 void
202 endgrent()
203 {
204 #ifdef YP
205 	_gr_stepping_yp = 0;
206 #endif
207 	if (_gr_fp) {
208 		(void)fclose(_gr_fp);
209 		_gr_fp = NULL;
210 	}
211 }
212 
213 static int
214 grscan(search, gid, name)
215 	register int search, gid;
216 	register char *name;
217 {
218 	register char *cp, **m;
219 	char *bp;
220 #ifdef YP
221 	int _ypfound = 0;
222 #endif;
223 	for (;;) {
224 		if (!fgets(line, sizeof(line), _gr_fp))
225 			return(0);
226 		bp = line;
227 		/* skip lines that are too big */
228 		if (!index(line, '\n')) {
229 			int ch;
230 
231 			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
232 				;
233 			continue;
234 		}
235 		if ((_gr_group.gr_name = strsep(&bp, ":\n")) == NULL)
236 			break;
237 #ifdef YP
238 		/*
239 		 * XXX   We need to be careful to avoid proceeding
240 		 * past this point under certain circumstances or
241 		 * we risk dereferencing null pointers down below.
242 		 */
243 		if (_gr_group.gr_name[0] == '+') {
244 			if (strlen(_gr_group.gr_name) == 1) {
245 				switch(search) {
246 				case 0:
247 					return(1);
248 				case 1:
249 					return(-1);
250 				default:
251 					return(0);
252 				}
253 			} else {
254 				if (!_getypgroup(&_gr_group, &_gr_group.gr_name[1],
255 						"group.byname"))
256 					continue;
257 			/* We're going to override -- tell the world. */
258 				members[0] = NULL;
259 				_ypfound++;
260 			}
261 		}
262 #else
263 		if (_gr_group.gr_name[0] == '+')
264 			continue;
265 #endif /* YP */
266 		if (search && name) {
267 			if(strcmp(_gr_group.gr_name, name)) {
268 				continue;
269 			}
270 		}
271 		if ((_gr_group.gr_passwd = strsep(&bp, ":\n")) == NULL)
272 			break;;
273 		if (!(cp = strsep(&bp, ":\n")))
274 			continue;
275 #ifdef YP
276 		if (!_ypfound)
277 #endif
278 		_gr_group.gr_gid = atoi(cp);
279 		if (search && name == NULL && _gr_group.gr_gid != gid)
280 			continue;
281 		cp = NULL;
282 		for (m = _gr_group.gr_mem = members;; bp++) {
283 			if (m == &members[MAXGRP - 1])
284 				break;
285 			if (*bp == ',') {
286 				if (cp) {
287 					*bp = '\0';
288 					*m++ = cp;
289 					cp = NULL;
290 				}
291 			} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
292 				if (cp) {
293 					*bp = '\0';
294 					*m++ = cp;
295 			}
296 				break;
297 			} else if (cp == NULL)
298 				cp = bp;
299 		}
300 		*m = NULL;
301 		return(1);
302 	}
303 	/* NOTREACHED */
304 	return (0);
305 }
306 
307 #ifdef YP
308 
309 static int
310 _gr_breakout_yp(struct group *gr, char *result)
311 {
312 	char *s, *cp;
313 	char **m;
314 
315 	/*
316 	 * XXX If 's' ends up being a NULL pointer, punt on this group.
317 	 * It means the NIS group entry is badly formatted and should
318 	 * be skipped.
319 	 */
320 	if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
321 	gr->gr_name = s;
322 
323 	if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
324 	gr->gr_passwd = s;
325 
326 	if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
327 	gr->gr_gid = atoi(s);
328 
329 	if ((s = result) == NULL) return 0;
330 	cp = 0;
331 
332 	for (m = _gr_group.gr_mem = members; /**/; s++) {
333 		if (m == &members[MAXGRP - 1]) {
334 			break;
335 		}
336 		if (*s == ',') {
337 			if (cp) {
338 				*s = '\0';
339 				*m++ = cp;
340 				cp = NULL;
341 			}
342 		} else if (*s == '\0' || *s == '\n' || *s == ' ') {
343 			if (cp) {
344 				*s = '\0';
345 				*m++ = cp;
346 			}
347 			break;
348 		} else if (cp == NULL) {
349 			cp = s;
350 		}
351 	}
352 	*m = NULL;
353 
354 	return 1;
355 }
356 
357 static char *_gr_yp_domain;
358 
359 static int
360 _getypgroup(struct group *gr, const char *name, char *map)
361 {
362 	char *result, *s;
363 	static char resultbuf[1024];
364 	int resultlen;
365 
366 	if(!_gr_yp_domain) {
367 		if(yp_get_default_domain(&_gr_yp_domain))
368 		  return 0;
369 	}
370 
371 	if(yp_match(_gr_yp_domain, map, name, strlen(name),
372 		    &result, &resultlen))
373 		return 0;
374 
375 	s = strchr(result, '\n');
376 	if(s) *s = '\0';
377 
378 	if(resultlen >= sizeof resultbuf) return 0;
379 	strcpy(resultbuf, result);
380 	result = resultbuf;
381 	return(_gr_breakout_yp(gr, resultbuf));
382 
383 }
384 
385 
386 static int
387 _nextypgroup(struct group *gr)
388 {
389 	static char *key;
390 	static int keylen;
391 	char *lastkey, *result;
392 	static char resultbuf[1024];
393 	int resultlen;
394 	int rv;
395 
396 	if(!_gr_yp_domain) {
397 		if(yp_get_default_domain(&_gr_yp_domain))
398 		  return 0;
399 	}
400 
401 	if(!_gr_stepping_yp) {
402 		if(key) free(key);
403 		rv = yp_first(_gr_yp_domain, "group.byname",
404 			      &key, &keylen, &result, &resultlen);
405 		if(rv) {
406 			return 0;
407 		}
408 		_gr_stepping_yp = 1;
409 		goto unpack;
410 	} else {
411 tryagain:
412 		lastkey = key;
413 		rv = yp_next(_gr_yp_domain, "group.byname", key, keylen,
414 			     &key, &keylen, &result, &resultlen);
415 		free(lastkey);
416 unpack:
417 		if(rv) {
418 			_gr_stepping_yp = 0;
419 			return 0;
420 		}
421 
422 		if(resultlen > sizeof(resultbuf)) {
423 			free(result);
424 			goto tryagain;
425 		}
426 
427 		strcpy(resultbuf, result);
428 		free(result);
429 		if((result = strchr(resultbuf, '\n')) != NULL)
430 			*result = '\0';
431 		if (_gr_breakout_yp(gr, resultbuf))
432 			return(1);
433 		else
434 			goto tryagain;
435 	}
436 }
437 
438 #endif /* YP */
439