getgrent.c revision 20756
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)) != 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
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;
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#ifdef YP
294			if (_ypfound)
295				return(1);
296			else
297#endif
298				continue;
299#ifdef YP
300		/*
301		 * Hurm. Should we be doing this? We allow UIDs to
302		 * be overridden -- what about GIDs?
303		 */
304		if (!_ypfound)
305#endif
306		_gr_group.gr_gid = atoi(cp);
307		if (search && name == NULL && _gr_group.gr_gid != gid)
308			continue;
309		cp = NULL;
310		if (bp == NULL) /* !!! Must check for this! */
311			break;
312#ifdef YP
313		if ((cp = strsep(&bp, ":\n")) == NULL)
314			break;
315
316		if (!strlen(cp) && _ypfound)
317			return(1);
318		else
319			members[0] = NULL;
320		bp = cp;
321		cp = NULL;
322#endif
323		for (m = _gr_group.gr_mem = members;; bp++) {
324			if (m == &members[MAXGRP - 1])
325				break;
326			if (*bp == ',') {
327				if (cp) {
328					*bp = '\0';
329					*m++ = cp;
330					cp = NULL;
331				}
332			} else if (*bp == '\0' || *bp == '\n' || *bp == ' ') {
333				if (cp) {
334					*bp = '\0';
335					*m++ = cp;
336			}
337				break;
338			} else if (cp == NULL)
339				cp = bp;
340		}
341		*m = NULL;
342		return(1);
343	}
344	/* NOTREACHED */
345	return (0);
346}
347
348#ifdef YP
349
350static int
351_gr_breakout_yp(struct group *gr, char *result)
352{
353	char *s, *cp;
354	char **m;
355
356	/*
357	 * XXX If 's' ends up being a NULL pointer, punt on this group.
358	 * It means the NIS group entry is badly formatted and should
359	 * be skipped.
360	 */
361	if ((s = strsep(&result, ":")) == NULL) return 0; /* name */
362	gr->gr_name = s;
363
364	if ((s = strsep(&result, ":")) == NULL) return 0; /* password */
365	gr->gr_passwd = s;
366
367	if ((s = strsep(&result, ":")) == NULL) return 0; /* gid */
368	gr->gr_gid = atoi(s);
369
370	if ((s = result) == NULL) return 0;
371	cp = 0;
372
373	for (m = _gr_group.gr_mem = members; /**/; s++) {
374		if (m == &members[MAXGRP - 1]) {
375			break;
376		}
377		if (*s == ',') {
378			if (cp) {
379				*s = '\0';
380				*m++ = cp;
381				cp = NULL;
382			}
383		} else if (*s == '\0' || *s == '\n' || *s == ' ') {
384			if (cp) {
385				*s = '\0';
386				*m++ = cp;
387			}
388			break;
389		} else if (cp == NULL) {
390			cp = s;
391		}
392	}
393	*m = NULL;
394
395	return 1;
396}
397
398static char *_gr_yp_domain;
399
400static int
401_getypgroup(struct group *gr, const char *name, char *map)
402{
403	char *result, *s;
404	static char resultbuf[1024];
405	int resultlen;
406
407	if(!_gr_yp_domain) {
408		if(yp_get_default_domain(&_gr_yp_domain))
409		  return 0;
410	}
411
412	if(yp_match(_gr_yp_domain, map, name, strlen(name),
413		    &result, &resultlen))
414		return 0;
415
416	s = strchr(result, '\n');
417	if(s) *s = '\0';
418
419	if(resultlen >= sizeof resultbuf) return 0;
420	strncpy(resultbuf, result, resultlen);
421	free(result);
422	return(_gr_breakout_yp(gr, resultbuf));
423
424}
425
426
427static int
428_nextypgroup(struct group *gr)
429{
430	static char *key;
431	static int keylen;
432	char *lastkey, *result;
433	static char resultbuf[1024];
434	int resultlen;
435	int rv;
436
437	if(!_gr_yp_domain) {
438		if(yp_get_default_domain(&_gr_yp_domain))
439		  return 0;
440	}
441
442	if(!_gr_stepping_yp) {
443		if(key) free(key);
444		rv = yp_first(_gr_yp_domain, "group.byname",
445			      &key, &keylen, &result, &resultlen);
446		if(rv) {
447			return 0;
448		}
449		_gr_stepping_yp = 1;
450		goto unpack;
451	} else {
452tryagain:
453		lastkey = key;
454		rv = yp_next(_gr_yp_domain, "group.byname", key, keylen,
455			     &key, &keylen, &result, &resultlen);
456		free(lastkey);
457unpack:
458		if(rv) {
459			_gr_stepping_yp = 0;
460			return 0;
461		}
462
463		if(resultlen > sizeof(resultbuf)) {
464			free(result);
465			goto tryagain;
466		}
467
468		strcpy(resultbuf, result);
469		free(result);
470		if((result = strchr(resultbuf, '\n')) != NULL)
471			*result = '\0';
472		if (_gr_breakout_yp(gr, resultbuf))
473			return(1);
474		else
475			goto tryagain;
476	}
477}
478
479#endif /* YP */
480