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