getnetgrent.c revision 7336
10SN/A/*
217237Sserb * Copyright (c) 1992, 1993
30SN/A *	The Regents of the University of California.  All rights reserved.
40SN/A *
50SN/A * This code is derived from software contributed to Berkeley by
60SN/A * Rick Macklem at The University of Guelph.
72362SN/A *
80SN/A * Redistribution and use in source and binary forms, with or without
92362SN/A * modification, are permitted provided that the following conditions
100SN/A * are met:
110SN/A * 1. Redistributions of source code must retain the above copyright
120SN/A *    notice, this list of conditions and the following disclaimer.
130SN/A * 2. Redistributions in binary form must reproduce the above copyright
140SN/A *    notice, this list of conditions and the following disclaimer in the
150SN/A *    documentation and/or other materials provided with the distribution.
160SN/A * 3. All advertising materials mentioning features or use of this software
170SN/A *    must display the following acknowledgement:
180SN/A *	This product includes software developed by the University of
190SN/A *	California, Berkeley and its contributors.
200SN/A * 4. Neither the name of the University nor the names of its contributors
212362SN/A *    may be used to endorse or promote products derived from this software
222362SN/A *    without specific prior written permission.
232362SN/A *
240SN/A * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
250SN/A * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
260SN/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
270SN/A * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
280SN/A * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
290SN/A * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3017237Sserb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3117237Sserb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
320SN/A * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3317189Smli * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
340SN/A * SUCH DAMAGE.
350SN/A */
360SN/A
370SN/A#if defined(LIBC_SCCS) && !defined(lint)
380SN/Astatic char sccsid[] = "@(#)getnetgrent.c	8.1 (Berkeley) 6/4/93";
390SN/A#endif /* LIBC_SCCS and not lint */
400SN/A
410SN/A#include <stdio.h>
420SN/A#include <strings.h>
430SN/A
440SN/A#define _PATH_NETGROUP "/etc/netgroup"
4517237Sserb
4617237Sserb/*
470SN/A * Static Variables and functions used by setnetgrent(), getnetgrent() and
480SN/A * endnetgrent().
490SN/A * There are two linked lists:
500SN/A * - linelist is just used by setnetgrent() to parse the net group file via.
510SN/A *   parse_netgrp()
52 * - netgrp is the list of entries for the current netgroup
53 */
54struct linelist {
55	struct linelist	*l_next;	/* Chain ptr. */
56	int		l_parsed;	/* Flag for cycles */
57	char		*l_groupname;	/* Name of netgroup */
58	char		*l_line;	/* Netgroup entrie(s) to be parsed */
59};
60
61struct netgrp {
62	struct netgrp	*ng_next;	/* Chain ptr */
63	char		*ng_str[3];	/* Field pointers, see below */
64};
65#define NG_HOST		0	/* Host name */
66#define NG_USER		1	/* User name */
67#define NG_DOM		2	/* and Domain name */
68
69static struct linelist	*linehead = (struct linelist *)0;
70static struct netgrp	*nextgrp = (struct netgrp *)0;
71static struct {
72	struct netgrp	*gr;
73	char		*grname;
74} grouphead = {
75	(struct netgrp *)0,
76	(char *)0,
77};
78static FILE *netf = (FILE *)0;
79static int parse_netgrp();
80#ifdef YP
81static int _netgr_yp_enabled;
82#endif
83static struct linelist *read_for_group();
84void setnetgrent(), endnetgrent();
85int getnetgrent(), innetgr();
86
87#define	LINSIZ	1024	/* Length of netgroup file line */
88
89/*
90 * setnetgrent()
91 * Parse the netgroup file looking for the netgroup and build the list
92 * of netgrp structures. Let parse_netgrp() and read_for_group() do
93 * most of the work.
94 */
95void
96setnetgrent(group)
97	char *group;
98{
99	/* Sanity check */
100
101	if (group == NULL || !strlen(group))
102		return;
103
104	if (grouphead.gr == (struct netgrp *)0 ||
105		strcmp(group, grouphead.grname)) {
106		endnetgrent();
107		if (netf = fopen(_PATH_NETGROUP, "r")) {
108			if (parse_netgrp(group))
109				endnetgrent();
110			else {
111				grouphead.grname = (char *)
112					malloc(strlen(group) + 1);
113				strcpy(grouphead.grname, group);
114			}
115			fclose(netf);
116		}
117	}
118	nextgrp = grouphead.gr;
119}
120
121/*
122 * Get the next netgroup off the list.
123 */
124int
125getnetgrent(hostp, userp, domp)
126	char **hostp, **userp, **domp;
127{
128
129	if (nextgrp) {
130		*hostp = nextgrp->ng_str[NG_HOST];
131		*userp = nextgrp->ng_str[NG_USER];
132		*domp = nextgrp->ng_str[NG_DOM];
133		nextgrp = nextgrp->ng_next;
134		return (1);
135	}
136	return (0);
137}
138
139/*
140 * endnetgrent() - cleanup
141 */
142void
143endnetgrent()
144{
145	register struct linelist *lp, *olp;
146	register struct netgrp *gp, *ogp;
147
148	lp = linehead;
149	while (lp) {
150		olp = lp;
151		lp = lp->l_next;
152		free(olp->l_groupname);
153		free(olp->l_line);
154		free((char *)olp);
155	}
156	linehead = (struct linelist *)0;
157	if (grouphead.grname) {
158		free(grouphead.grname);
159		grouphead.grname = (char *)0;
160	}
161	gp = grouphead.gr;
162	while (gp) {
163		ogp = gp;
164		gp = gp->ng_next;
165		if (ogp->ng_str[NG_HOST])
166			free(ogp->ng_str[NG_HOST]);
167		if (ogp->ng_str[NG_USER])
168			free(ogp->ng_str[NG_USER]);
169		if (ogp->ng_str[NG_DOM])
170			free(ogp->ng_str[NG_DOM]);
171		free((char *)ogp);
172	}
173	grouphead.gr = (struct netgrp *)0;
174#ifdef YP
175	_netgr_yp_enabled = 0;
176#endif
177}
178
179/*
180 * Search for a match in a netgroup.
181 */
182int
183innetgr(group, host, user, dom)
184	char *group, *host, *user, *dom;
185{
186	char *hst, *usr, *dm;
187
188	/* Sanity check */
189
190	if (group == NULL || !strlen(group))
191		return (0);
192
193	setnetgrent(group);
194	while (getnetgrent(&hst, &usr, &dm))
195		if ((host == (char *)0 || !strcmp(host, hst)) &&
196		    (user == (char *)0 || !strcmp(user, usr)) &&
197		    (dom == (char *)0 || !strcmp(dom, dm))) {
198			endnetgrent();
199			return (1);
200		}
201	endnetgrent();
202	return (0);
203}
204
205/*
206 * Parse the netgroup file setting up the linked lists.
207 */
208static int
209parse_netgrp(group)
210	char *group;
211{
212	register char *spos, *epos;
213	register int len, strpos;
214	char *pos, *gpos;
215	struct netgrp *grp;
216	struct linelist *lp = linehead;
217
218	/*
219	 * First, see if the line has already been read in.
220	 */
221	while (lp) {
222		if (!strcmp(group, lp->l_groupname))
223			break;
224		lp = lp->l_next;
225	}
226	if (lp == (struct linelist *)0 &&
227	    (lp = read_for_group(group)) == (struct linelist *)0)
228		return (1);
229	if (lp->l_parsed) {
230		fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);
231		return (1);
232	} else
233		lp->l_parsed = 1;
234	pos = lp->l_line;
235	/* Watch for null pointer dereferences, dammit! */
236	while (pos != NULL && *pos != '\0') {
237		if (*pos == '(') {
238			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
239			bzero((char *)grp, sizeof (struct netgrp));
240			grp->ng_next = grouphead.gr;
241			grouphead.gr = grp;
242			pos++;
243			gpos = strsep(&pos, ")");
244			for (strpos = 0; strpos < 3; strpos++) {
245				if (spos = strsep(&gpos, ",")) {
246					while (*spos == ' ' || *spos == '\t')
247						spos++;
248					if (epos = strpbrk(spos, " \t")) {
249						*epos = '\0';
250						len = epos - spos;
251					} else
252						len = strlen(spos);
253					if (len > 0) {
254						grp->ng_str[strpos] =  (char *)
255							malloc(len + 1);
256						bcopy(spos, grp->ng_str[strpos],
257							len + 1);
258					}
259				} else
260					goto errout;
261			}
262		} else {
263			spos = strsep(&pos, ", \t");
264			if (parse_netgrp(spos))
265				continue;
266		}
267		/* Watch for null pointer dereferences, dammit! */
268		if (pos != NULL)
269			while (*pos == ' ' || *pos == ',' || *pos == '\t')
270				pos++;
271	}
272	return (0);
273errout:
274	fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname,
275		spos);
276	return (1);
277}
278
279/*
280 * Read the netgroup file and save lines until the line for the netgroup
281 * is found. Return 1 if eof is encountered.
282 */
283static struct linelist *
284read_for_group(group)
285	char *group;
286{
287	register char *pos, *spos, *linep, *olinep;
288	register int len, olen;
289	int cont;
290	struct linelist *lp;
291	char line[LINSIZ + 1];
292#ifdef YP
293	static char *_netgr_yp_domain;
294	char *result;
295	int resultlen;
296
297	while (_netgr_yp_enabled || fgets(line, LINSIZ, netf) != NULL) {
298		if (_netgr_yp_enabled) {
299			if(!_netgr_yp_domain)
300				if(yp_get_default_domain(&_netgr_yp_domain))
301					continue;
302			if (yp_match(_netgr_yp_domain, "netgroup", group,
303					strlen(group), &result, &resultlen)) {
304				free(result);
305				return ((struct linelist *)0);
306			}
307			sprintf(line, "%s %s", group, result);
308			free(result);
309		}
310#else
311	while (fgets(line, LINSIZ, netf) != NULL) {
312#endif
313		pos = (char *)&line;
314#ifdef YP
315		/*
316		 * Once we default over to NIS, only
317		 * endnetgrent() can get us out again.
318		 */
319		if (*pos == '+') {
320			_netgr_yp_enabled = 1;
321			continue;
322		}
323#endif
324		if (*pos == '#')
325			continue;
326		while (*pos == ' ' || *pos == '\t')
327			pos++;
328		spos = pos;
329		while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
330			*pos != '\0')
331			pos++;
332		len = pos - spos;
333		while (*pos == ' ' || *pos == '\t')
334			pos++;
335		if (*pos != '\n' && *pos != '\0') {
336			lp = (struct linelist *)malloc(sizeof (*lp));
337			lp->l_parsed = 0;
338			lp->l_groupname = (char *)malloc(len + 1);
339			bcopy(spos, lp->l_groupname, len);
340			*(lp->l_groupname + len) = '\0';
341			len = strlen(pos);
342			olen = 0;
343
344			/*
345			 * Loop around handling line continuations.
346			 */
347			do {
348				if (*(pos + len - 1) == '\n')
349					len--;
350				if (*(pos + len - 1) == '\\') {
351					len--;
352					cont = 1;
353				} else
354					cont = 0;
355				if (len > 0) {
356					linep = (char *)malloc(olen + len + 1);
357					if (olen > 0) {
358						bcopy(olinep, linep, olen);
359						free(olinep);
360					}
361					bcopy(pos, linep + olen, len);
362					olen += len;
363					*(linep + olen) = '\0';
364					olinep = linep;
365				}
366				if (cont) {
367					if (fgets(line, LINSIZ, netf)) {
368						pos = line;
369						len = strlen(pos);
370					} else
371						cont = 0;
372				}
373			} while (cont);
374			lp->l_line = linep;
375			lp->l_next = linehead;
376			linehead = lp;
377
378			/*
379			 * If this is the one we wanted, we are done.
380			 */
381			if (!strcmp(lp->l_groupname, group))
382				return (lp);
383		}
384	}
385	return ((struct linelist *)0);
386}
387