xref: /freebsd/lib/libc/gen/getgrent.c (revision e627b39baccd1ec9129690167cf5e6d860509655)
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] && 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;
222 #endif;
223 	for (;;) {
224 #ifdef YP
225 		_ypfound = 0;
226 #endif
227 		if (!fgets(line, sizeof(line), _gr_fp))
228 			return(0);
229 		bp = line;
230 		/* skip lines that are too big */
231 		if (!index(line, '\n')) {
232 			int ch;
233 
234 			while ((ch = getc(_gr_fp)) != '\n' && ch != EOF)
235 				;
236 			continue;
237 		}
238 		if ((_gr_group.gr_name = strsep(&bp, ":\n")) == NULL)
239 			break;
240 #ifdef YP
241 		/*
242 		 * XXX   We need to be careful to avoid proceeding
243 		 * past this point under certain circumstances or
244 		 * we risk dereferencing null pointers down below.
245 		 */
246 		if (_gr_group.gr_name[0] == '+') {
247 			if (strlen(_gr_group.gr_name) == 1) {
248 				switch(search) {
249 				case 0:
250 					return(1);
251 				case 1:
252 					return(-1);
253 				default:
254 					return(0);
255 				}
256 			} else {
257 				cp = &_gr_group.gr_name[1];
258 				if (search && name != NULL)
259 					if (strcmp(cp, name))
260 						continue;
261 				if (!_getypgroup(&_gr_group, cp,
262 						"group.byname"))
263 					continue;
264 				if (search && name == NULL)
265 					if (gid != _gr_group.gr_gid)
266 						continue;
267 			/* We're going to override -- tell the world. */
268 				_ypfound++;
269 			}
270 		}
271 #else
272 		if (_gr_group.gr_name[0] == '+')
273 			continue;
274 #endif /* YP */
275 		if (search && name) {
276 			if(strcmp(_gr_group.gr_name, name)) {
277 				continue;
278 			}
279 		}
280 #ifdef YP
281 		if ((cp = strsep(&bp, ":\n")) == NULL)
282 			if (_ypfound)
283 				return(1);
284 			else
285 				break;
286 		if (strlen(cp) || !_ypfound)
287 			_gr_group.gr_passwd = cp;
288 #else
289 		if ((_gr_group.gr_passwd = strsep(&bp, ":\n")) == NULL)
290 			break;
291 #endif
292 		if (!(cp = strsep(&bp, ":\n")))
293 			if (_ypfound)
294 				return(1);
295 			else
296 				continue;
297 #ifdef YP
298 		/*
299 		 * Hurm. Should we be doing this? We allow UIDs to
300 		 * be overridden -- what about GIDs?
301 		 */
302 		if (!_ypfound)
303 #endif
304 		_gr_group.gr_gid = atoi(cp);
305 		if (search && name == NULL && _gr_group.gr_gid != gid)
306 			continue;
307 		cp = NULL;
308 		if (bp == NULL) /* !!! Must check for this! */
309 			break;
310 #ifdef YP
311 		if ((cp = strsep(&bp, ":\n")) == NULL)
312 			break;
313 
314 		if (!strlen(cp) && _ypfound)
315 			return(1);
316 		else
317 			members[0] = NULL;
318 		bp = cp;
319 		cp = NULL;
320 #endif
321 		for (m = _gr_group.gr_mem = members;; bp++) {
322 			if (m == &members[MAXGRP - 1])
323 				break;
324 			if (*bp == ',') {
325 				if (cp) {
326 					*bp = '\0';
327 					*m++ = cp;
328 					cp = NULL;
329 				}
330 			} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
331 				if (cp) {
332 					*bp = '\0';
333 					*m++ = cp;
334 			}
335 				break;
336 			} else if (cp == NULL)
337 				cp = bp;
338 		}
339 		*m = NULL;
340 		return(1);
341 	}
342 	/* NOTREACHED */
343 	return (0);
344 }
345 
346 #ifdef YP
347 
348 static int
349 _gr_breakout_yp(struct group *gr, char *result)
350 {
351 	char *s, *cp;
352 	char **m;
353 
354 	/*
355 	 * XXX If 's' ends up being a NULL pointer, punt on this group.
356 	 * It means the NIS group entry is badly formatted and should
357 	 * be skipped.
358 	 */
359 	if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
360 	gr->gr_name = s;
361 
362 	if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
363 	gr->gr_passwd = s;
364 
365 	if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
366 	gr->gr_gid = atoi(s);
367 
368 	if ((s = result) == NULL) return 0;
369 	cp = 0;
370 
371 	for (m = _gr_group.gr_mem = members; /**/; s++) {
372 		if (m == &members[MAXGRP - 1]) {
373 			break;
374 		}
375 		if (*s == ',') {
376 			if (cp) {
377 				*s = '\0';
378 				*m++ = cp;
379 				cp = NULL;
380 			}
381 		} else if (*s == '\0' || *s == '\n' || *s == ' ') {
382 			if (cp) {
383 				*s = '\0';
384 				*m++ = cp;
385 			}
386 			break;
387 		} else if (cp == NULL) {
388 			cp = s;
389 		}
390 	}
391 	*m = NULL;
392 
393 	return 1;
394 }
395 
396 static char *_gr_yp_domain;
397 
398 static int
399 _getypgroup(struct group *gr, const char *name, char *map)
400 {
401 	char *result, *s;
402 	static char resultbuf[1024];
403 	int resultlen;
404 
405 	if(!_gr_yp_domain) {
406 		if(yp_get_default_domain(&_gr_yp_domain))
407 		  return 0;
408 	}
409 
410 	if(yp_match(_gr_yp_domain, map, name, strlen(name),
411 		    &result, &resultlen))
412 		return 0;
413 
414 	s = strchr(result, '\n');
415 	if(s) *s = '\0';
416 
417 	if(resultlen >= sizeof resultbuf) return 0;
418 	strncpy(resultbuf, result, resultlen);
419 	free(result);
420 	return(_gr_breakout_yp(gr, resultbuf));
421 
422 }
423 
424 
425 static int
426 _nextypgroup(struct group *gr)
427 {
428 	static char *key;
429 	static int keylen;
430 	char *lastkey, *result;
431 	static char resultbuf[1024];
432 	int resultlen;
433 	int rv;
434 
435 	if(!_gr_yp_domain) {
436 		if(yp_get_default_domain(&_gr_yp_domain))
437 		  return 0;
438 	}
439 
440 	if(!_gr_stepping_yp) {
441 		if(key) free(key);
442 		rv = yp_first(_gr_yp_domain, "group.byname",
443 			      &key, &keylen, &result, &resultlen);
444 		if(rv) {
445 			return 0;
446 		}
447 		_gr_stepping_yp = 1;
448 		goto unpack;
449 	} else {
450 tryagain:
451 		lastkey = key;
452 		rv = yp_next(_gr_yp_domain, "group.byname", key, keylen,
453 			     &key, &keylen, &result, &resultlen);
454 		free(lastkey);
455 unpack:
456 		if(rv) {
457 			_gr_stepping_yp = 0;
458 			return 0;
459 		}
460 
461 		if(resultlen > sizeof(resultbuf)) {
462 			free(result);
463 			goto tryagain;
464 		}
465 
466 		strcpy(resultbuf, result);
467 		free(result);
468 		if((result = strchr(resultbuf, '\n')) != NULL)
469 			*result = '\0';
470 		if (_gr_breakout_yp(gr, resultbuf))
471 			return(1);
472 		else
473 			goto tryagain;
474 	}
475 }
476 
477 #endif /* YP */
478