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