xref: /freebsd/lib/libc/gen/getnetgrent.c (revision afe61c15161c324a7af299a9b8457aba5afc92db)
1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #if defined(LIBC_SCCS) && !defined(lint)
38 static char sccsid[] = "@(#)getnetgrent.c	8.1 (Berkeley) 6/4/93";
39 #endif /* LIBC_SCCS and not lint */
40 
41 #include <stdio.h>
42 #include <strings.h>
43 
44 #define _PATH_NETGROUP "/etc/netgroup"
45 
46 /*
47  * Static Variables and functions used by setnetgrent(), getnetgrent() and
48  * endnetgrent().
49  * There are two linked lists:
50  * - linelist is just used by setnetgrent() to parse the net group file via.
51  *   parse_netgrp()
52  * - netgrp is the list of entries for the current netgroup
53  */
54 struct 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 
61 struct 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 
69 static struct linelist	*linehead = (struct linelist *)0;
70 static struct netgrp	*nextgrp = (struct netgrp *)0;
71 static struct {
72 	struct netgrp	*gr;
73 	char		*grname;
74 } grouphead = {
75 	(struct netgrp *)0,
76 	(char *)0,
77 };
78 static FILE *netf = (FILE *)0;
79 static int parse_netgrp();
80 static struct linelist *read_for_group();
81 void setnetgrent(), endnetgrent();
82 int getnetgrent(), innetgr();
83 
84 #define	LINSIZ	1024	/* Length of netgroup file line */
85 
86 /*
87  * setnetgrent()
88  * Parse the netgroup file looking for the netgroup and build the list
89  * of netgrp structures. Let parse_netgrp() and read_for_group() do
90  * most of the work.
91  */
92 void
93 setnetgrent(group)
94 	char *group;
95 {
96 
97 	if (grouphead.gr == (struct netgrp *)0 ||
98 		strcmp(group, grouphead.grname)) {
99 		endnetgrent();
100 		if (netf = fopen(_PATH_NETGROUP, "r")) {
101 			if (parse_netgrp(group))
102 				endnetgrent();
103 			else {
104 				grouphead.grname = (char *)
105 					malloc(strlen(group) + 1);
106 				strcpy(grouphead.grname, group);
107 			}
108 			fclose(netf);
109 		}
110 	}
111 	nextgrp = grouphead.gr;
112 }
113 
114 /*
115  * Get the next netgroup off the list.
116  */
117 int
118 getnetgrent(hostp, userp, domp)
119 	char **hostp, **userp, **domp;
120 {
121 
122 	if (nextgrp) {
123 		*hostp = nextgrp->ng_str[NG_HOST];
124 		*userp = nextgrp->ng_str[NG_USER];
125 		*domp = nextgrp->ng_str[NG_DOM];
126 		nextgrp = nextgrp->ng_next;
127 		return (1);
128 	}
129 	return (0);
130 }
131 
132 /*
133  * endnetgrent() - cleanup
134  */
135 void
136 endnetgrent()
137 {
138 	register struct linelist *lp, *olp;
139 	register struct netgrp *gp, *ogp;
140 
141 	lp = linehead;
142 	while (lp) {
143 		olp = lp;
144 		lp = lp->l_next;
145 		free(olp->l_groupname);
146 		free(olp->l_line);
147 		free((char *)olp);
148 	}
149 	linehead = (struct linelist *)0;
150 	if (grouphead.grname) {
151 		free(grouphead.grname);
152 		grouphead.grname = (char *)0;
153 	}
154 	gp = grouphead.gr;
155 	while (gp) {
156 		ogp = gp;
157 		gp = gp->ng_next;
158 		if (ogp->ng_str[NG_HOST])
159 			free(ogp->ng_str[NG_HOST]);
160 		if (ogp->ng_str[NG_USER])
161 			free(ogp->ng_str[NG_USER]);
162 		if (ogp->ng_str[NG_DOM])
163 			free(ogp->ng_str[NG_DOM]);
164 		free((char *)ogp);
165 	}
166 	grouphead.gr = (struct netgrp *)0;
167 }
168 
169 /*
170  * Search for a match in a netgroup.
171  */
172 int
173 innetgr(group, host, user, dom)
174 	char *group, *host, *user, *dom;
175 {
176 	char *hst, *usr, *dm;
177 
178 	setnetgrent(group);
179 	while (getnetgrent(&hst, &usr, &dm))
180 		if ((host == (char *)0 || !strcmp(host, hst)) &&
181 		    (user == (char *)0 || !strcmp(user, usr)) &&
182 		    (dom == (char *)0 || !strcmp(dom, dm))) {
183 			endnetgrent();
184 			return (1);
185 		}
186 	endnetgrent();
187 	return (0);
188 }
189 
190 /*
191  * Parse the netgroup file setting up the linked lists.
192  */
193 static int
194 parse_netgrp(group)
195 	char *group;
196 {
197 	register char *spos, *epos;
198 	register int len, strpos;
199 	char *pos, *gpos;
200 	struct netgrp *grp;
201 	struct linelist *lp = linehead;
202 
203 	/*
204 	 * First, see if the line has already been read in.
205 	 */
206 	while (lp) {
207 		if (!strcmp(group, lp->l_groupname))
208 			break;
209 		lp = lp->l_next;
210 	}
211 	if (lp == (struct linelist *)0 &&
212 	    (lp = read_for_group(group)) == (struct linelist *)0)
213 		return (1);
214 	if (lp->l_parsed) {
215 		fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);
216 		return (1);
217 	} else
218 		lp->l_parsed = 1;
219 	pos = lp->l_line;
220 	while (*pos != '\0') {
221 		if (*pos == '(') {
222 			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
223 			bzero((char *)grp, sizeof (struct netgrp));
224 			grp->ng_next = grouphead.gr;
225 			grouphead.gr = grp;
226 			pos++;
227 			gpos = strsep(&pos, ")");
228 			for (strpos = 0; strpos < 3; strpos++) {
229 				if (spos = strsep(&gpos, ",")) {
230 					while (*spos == ' ' || *spos == '\t')
231 						spos++;
232 					if (epos = strpbrk(spos, " \t")) {
233 						*epos = '\0';
234 						len = epos - spos;
235 					} else
236 						len = strlen(spos);
237 					if (len > 0) {
238 						grp->ng_str[strpos] =  (char *)
239 							malloc(len + 1);
240 						bcopy(spos, grp->ng_str[strpos],
241 							len + 1);
242 					}
243 				} else
244 					goto errout;
245 			}
246 		} else {
247 			spos = strsep(&pos, ", \t");
248 			if (parse_netgrp(spos))
249 				return (1);
250 		}
251 		while (*pos == ' ' || *pos == ',' || *pos == '\t')
252 			pos++;
253 	}
254 	return (0);
255 errout:
256 	fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname,
257 		spos);
258 	return (1);
259 }
260 
261 /*
262  * Read the netgroup file and save lines until the line for the netgroup
263  * is found. Return 1 if eof is encountered.
264  */
265 static struct linelist *
266 read_for_group(group)
267 	char *group;
268 {
269 	register char *pos, *spos, *linep, *olinep;
270 	register int len, olen;
271 	int cont;
272 	struct linelist *lp;
273 	char line[LINSIZ + 1];
274 
275 	while (fgets(line, LINSIZ, netf) != NULL) {
276 		pos = line;
277 		if (*pos == '#')
278 			continue;
279 		while (*pos == ' ' || *pos == '\t')
280 			pos++;
281 		spos = pos;
282 		while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
283 			*pos != '\0')
284 			pos++;
285 		len = pos - spos;
286 		while (*pos == ' ' || *pos == '\t')
287 			pos++;
288 		if (*pos != '\n' && *pos != '\0') {
289 			lp = (struct linelist *)malloc(sizeof (*lp));
290 			lp->l_parsed = 0;
291 			lp->l_groupname = (char *)malloc(len + 1);
292 			bcopy(spos, lp->l_groupname, len);
293 			*(lp->l_groupname + len) = '\0';
294 			len = strlen(pos);
295 			olen = 0;
296 
297 			/*
298 			 * Loop around handling line continuations.
299 			 */
300 			do {
301 				if (*(pos + len - 1) == '\n')
302 					len--;
303 				if (*(pos + len - 1) == '\\') {
304 					len--;
305 					cont = 1;
306 				} else
307 					cont = 0;
308 				if (len > 0) {
309 					linep = (char *)malloc(olen + len + 1);
310 					if (olen > 0) {
311 						bcopy(olinep, linep, olen);
312 						free(olinep);
313 					}
314 					bcopy(pos, linep + olen, len);
315 					olen += len;
316 					*(linep + olen) = '\0';
317 					olinep = linep;
318 				}
319 				if (cont) {
320 					if (fgets(line, LINSIZ, netf)) {
321 						pos = line;
322 						len = strlen(pos);
323 					} else
324 						cont = 0;
325 				}
326 			} while (cont);
327 			lp->l_line = linep;
328 			lp->l_next = linehead;
329 			linehead = lp;
330 
331 			/*
332 			 * If this is the one we wanted, we are done.
333 			 */
334 			if (!strcmp(lp->l_groupname, group))
335 				return (lp);
336 		}
337 	}
338 	return ((struct linelist *)0);
339 }
340