getgrent.c revision 11286
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)
35static 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
44static FILE *_gr_fp;
45static struct group _gr_group;
46static int _gr_stayopen;
47static int grscan(), start_gr();
48#ifdef YP
49#include <rpc/rpc.h>
50#include <rpcsvc/yp_prot.h>
51#include <rpcsvc/ypclnt.h>
52static int _gr_stepping_yp;
53static int _gr_yp_enabled;
54static int _getypgroup(struct group *, const char *, char *);
55static int _nextypgroup(struct group *);
56#endif
57
58#define	MAXGRP		200
59static char *members[MAXGRP];
60#define	MAXLINELENGTH	1024
61static char line[MAXLINELENGTH];
62
63struct group *
64getgrent()
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	}
75tryagain:
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
94struct group *
95getgrnam(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
118struct group *
119#ifdef __STDC__
120getgrgid(gid_t gid)
121#else
122getgrgid(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
147static int
148start_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)) {
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
182int
183setgrent()
184{
185	return(setgroupent(0));
186}
187
188int
189setgroupent(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
201void
202endgrent()
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
213static int
214grscan(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}
305
306#ifdef YP
307
308static int
309_gr_breakout_yp(struct group *gr, char *result)
310{
311	char *s, *cp;
312	char **m;
313
314	/*
315	 * XXX If 's' ends up being a NULL pointer, punt on this group.
316	 * It means the NIS group entry is badly formatted and should
317	 * be skipped.
318	 */
319	if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
320	gr->gr_name = s;
321
322	if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
323	gr->gr_passwd = s;
324
325	if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
326	gr->gr_gid = atoi(s);
327
328	if ((s = result) == NULL) return 0;
329	cp = 0;
330
331	for (m = _gr_group.gr_mem = members; /**/; s++) {
332		if (m == &members[MAXGRP - 1]) {
333			break;
334		}
335		if (*s == ',') {
336			if (cp) {
337				*s = '\0';
338				*m++ = cp;
339				cp = NULL;
340			}
341		} else if (*s == '\0' || *s == '\n' || *s == ' ') {
342			if (cp) {
343				*s = '\0';
344				*m++ = cp;
345			}
346			break;
347		} else if (cp == NULL) {
348			cp = s;
349		}
350	}
351	*m = NULL;
352
353	return 1;
354}
355
356static char *_gr_yp_domain;
357
358static int
359_getypgroup(struct group *gr, const char *name, char *map)
360{
361	char *result, *s;
362	static char resultbuf[1024];
363	int resultlen;
364
365	if(!_gr_yp_domain) {
366		if(yp_get_default_domain(&_gr_yp_domain))
367		  return 0;
368	}
369
370	if(yp_match(_gr_yp_domain, map, name, strlen(name),
371		    &result, &resultlen))
372		return 0;
373
374	s = strchr(result, '\n');
375	if(s) *s = '\0';
376
377	if(resultlen >= sizeof resultbuf) return 0;
378	strcpy(resultbuf, result);
379	result = resultbuf;
380	return(_gr_breakout_yp(gr, resultbuf));
381
382}
383
384
385static int
386_nextypgroup(struct group *gr)
387{
388	static char *key;
389	static int keylen;
390	char *lastkey, *result;
391	static char resultbuf[1024];
392	int resultlen;
393	int rv;
394
395	if(!_gr_yp_domain) {
396		if(yp_get_default_domain(&_gr_yp_domain))
397		  return 0;
398	}
399
400	if(!_gr_stepping_yp) {
401		if(key) free(key);
402		rv = yp_first(_gr_yp_domain, "group.byname",
403			      &key, &keylen, &result, &resultlen);
404		if(rv) {
405			return 0;
406		}
407		_gr_stepping_yp = 1;
408		goto unpack;
409	} else {
410tryagain:
411		lastkey = key;
412		rv = yp_next(_gr_yp_domain, "group.byname", key, keylen,
413			     &key, &keylen, &result, &resultlen);
414		free(lastkey);
415unpack:
416		if(rv) {
417			_gr_stepping_yp = 0;
418			return 0;
419		}
420
421		if(resultlen > sizeof(resultbuf)) {
422			free(result);
423			goto tryagain;
424		}
425
426		strcpy(resultbuf, result);
427		free(result);
428		if(result = strchr(resultbuf, '\n')) *result = '\0';
429		if (_gr_breakout_yp(gr, resultbuf))
430			return(1);
431		else
432			goto tryagain;
433	}
434}
435
436#endif /* YP */
437