xref: /netbsd-src/lib/libc/gen/getnetgrent.c (revision d9158b13b5dfe46201430699a3f7a235ecf28df3)
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[] = "from: @(#)getnetgrent.c	8.1 (Berkeley) 6/4/93";*/
39 static char *rcsid = "$Id: getnetgrent.c,v 1.1.1.1 1994/05/17 13:30:51 mycroft Exp $";
40 #endif /* LIBC_SCCS and not lint */
41 
42 #include <stdio.h>
43 #include <strings.h>
44 
45 #define _PATH_NETGROUP "/etc/netgroup"
46 
47 /*
48  * Static Variables and functions used by setnetgrent(), getnetgrent() and
49  * endnetgrent().
50  * There are two linked lists:
51  * - linelist is just used by setnetgrent() to parse the net group file via.
52  *   parse_netgrp()
53  * - netgrp is the list of entries for the current netgroup
54  */
55 struct linelist {
56 	struct linelist	*l_next;	/* Chain ptr. */
57 	int		l_parsed;	/* Flag for cycles */
58 	char		*l_groupname;	/* Name of netgroup */
59 	char		*l_line;	/* Netgroup entrie(s) to be parsed */
60 };
61 
62 struct netgrp {
63 	struct netgrp	*ng_next;	/* Chain ptr */
64 	char		*ng_str[3];	/* Field pointers, see below */
65 };
66 #define NG_HOST		0	/* Host name */
67 #define NG_USER		1	/* User name */
68 #define NG_DOM		2	/* and Domain name */
69 
70 static struct linelist	*linehead = (struct linelist *)0;
71 static struct netgrp	*nextgrp = (struct netgrp *)0;
72 static struct {
73 	struct netgrp	*gr;
74 	char		*grname;
75 } grouphead = {
76 	(struct netgrp *)0,
77 	(char *)0,
78 };
79 static FILE *netf = (FILE *)0;
80 static int parse_netgrp();
81 static struct linelist *read_for_group();
82 void setnetgrent(), endnetgrent();
83 int getnetgrent(), innetgr();
84 
85 #define	LINSIZ	1024	/* Length of netgroup file line */
86 
87 /*
88  * setnetgrent()
89  * Parse the netgroup file looking for the netgroup and build the list
90  * of netgrp structures. Let parse_netgrp() and read_for_group() do
91  * most of the work.
92  */
93 void
94 setnetgrent(group)
95 	char *group;
96 {
97 
98 	if (grouphead.gr == (struct netgrp *)0 ||
99 		strcmp(group, grouphead.grname)) {
100 		endnetgrent();
101 		if (netf = fopen(_PATH_NETGROUP, "r")) {
102 			if (parse_netgrp(group))
103 				endnetgrent();
104 			else {
105 				grouphead.grname = (char *)
106 					malloc(strlen(group) + 1);
107 				strcpy(grouphead.grname, group);
108 			}
109 			fclose(netf);
110 		}
111 	}
112 	nextgrp = grouphead.gr;
113 }
114 
115 /*
116  * Get the next netgroup off the list.
117  */
118 int
119 getnetgrent(hostp, userp, domp)
120 	char **hostp, **userp, **domp;
121 {
122 
123 	if (nextgrp) {
124 		*hostp = nextgrp->ng_str[NG_HOST];
125 		*userp = nextgrp->ng_str[NG_USER];
126 		*domp = nextgrp->ng_str[NG_DOM];
127 		nextgrp = nextgrp->ng_next;
128 		return (1);
129 	}
130 	return (0);
131 }
132 
133 /*
134  * endnetgrent() - cleanup
135  */
136 void
137 endnetgrent()
138 {
139 	register struct linelist *lp, *olp;
140 	register struct netgrp *gp, *ogp;
141 
142 	lp = linehead;
143 	while (lp) {
144 		olp = lp;
145 		lp = lp->l_next;
146 		free(olp->l_groupname);
147 		free(olp->l_line);
148 		free((char *)olp);
149 	}
150 	linehead = (struct linelist *)0;
151 	if (grouphead.grname) {
152 		free(grouphead.grname);
153 		grouphead.grname = (char *)0;
154 	}
155 	gp = grouphead.gr;
156 	while (gp) {
157 		ogp = gp;
158 		gp = gp->ng_next;
159 		if (ogp->ng_str[NG_HOST])
160 			free(ogp->ng_str[NG_HOST]);
161 		if (ogp->ng_str[NG_USER])
162 			free(ogp->ng_str[NG_USER]);
163 		if (ogp->ng_str[NG_DOM])
164 			free(ogp->ng_str[NG_DOM]);
165 		free((char *)ogp);
166 	}
167 	grouphead.gr = (struct netgrp *)0;
168 }
169 
170 /*
171  * Search for a match in a netgroup.
172  */
173 int
174 innetgr(group, host, user, dom)
175 	char *group, *host, *user, *dom;
176 {
177 	char *hst, *usr, *dm;
178 
179 	setnetgrent(group);
180 	while (getnetgrent(&hst, &usr, &dm))
181 		if ((host == (char *)0 || !strcmp(host, hst)) &&
182 		    (user == (char *)0 || !strcmp(user, usr)) &&
183 		    (dom == (char *)0 || !strcmp(dom, dm))) {
184 			endnetgrent();
185 			return (1);
186 		}
187 	endnetgrent();
188 	return (0);
189 }
190 
191 /*
192  * Parse the netgroup file setting up the linked lists.
193  */
194 static int
195 parse_netgrp(group)
196 	char *group;
197 {
198 	register char *spos, *epos;
199 	register int len, strpos;
200 	char *pos, *gpos;
201 	struct netgrp *grp;
202 	struct linelist *lp = linehead;
203 
204 	/*
205 	 * First, see if the line has already been read in.
206 	 */
207 	while (lp) {
208 		if (!strcmp(group, lp->l_groupname))
209 			break;
210 		lp = lp->l_next;
211 	}
212 	if (lp == (struct linelist *)0 &&
213 	    (lp = read_for_group(group)) == (struct linelist *)0)
214 		return (1);
215 	if (lp->l_parsed) {
216 		fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);
217 		return (1);
218 	} else
219 		lp->l_parsed = 1;
220 	pos = lp->l_line;
221 	while (*pos != '\0') {
222 		if (*pos == '(') {
223 			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
224 			bzero((char *)grp, sizeof (struct netgrp));
225 			grp->ng_next = grouphead.gr;
226 			grouphead.gr = grp;
227 			pos++;
228 			gpos = strsep(&pos, ")");
229 			for (strpos = 0; strpos < 3; strpos++) {
230 				if (spos = strsep(&gpos, ",")) {
231 					while (*spos == ' ' || *spos == '\t')
232 						spos++;
233 					if (epos = strpbrk(spos, " \t")) {
234 						*epos = '\0';
235 						len = epos - spos;
236 					} else
237 						len = strlen(spos);
238 					if (len > 0) {
239 						grp->ng_str[strpos] =  (char *)
240 							malloc(len + 1);
241 						bcopy(spos, grp->ng_str[strpos],
242 							len + 1);
243 					}
244 				} else
245 					goto errout;
246 			}
247 		} else {
248 			spos = strsep(&pos, ", \t");
249 			if (parse_netgrp(spos))
250 				return (1);
251 		}
252 		while (*pos == ' ' || *pos == ',' || *pos == '\t')
253 			pos++;
254 	}
255 	return (0);
256 errout:
257 	fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname,
258 		spos);
259 	return (1);
260 }
261 
262 /*
263  * Read the netgroup file and save lines until the line for the netgroup
264  * is found. Return 1 if eof is encountered.
265  */
266 static struct linelist *
267 read_for_group(group)
268 	char *group;
269 {
270 	register char *pos, *spos, *linep, *olinep;
271 	register int len, olen;
272 	int cont;
273 	struct linelist *lp;
274 	char line[LINSIZ + 1];
275 
276 	while (fgets(line, LINSIZ, netf) != NULL) {
277 		pos = line;
278 		if (*pos == '#')
279 			continue;
280 		while (*pos == ' ' || *pos == '\t')
281 			pos++;
282 		spos = pos;
283 		while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
284 			*pos != '\0')
285 			pos++;
286 		len = pos - spos;
287 		while (*pos == ' ' || *pos == '\t')
288 			pos++;
289 		if (*pos != '\n' && *pos != '\0') {
290 			lp = (struct linelist *)malloc(sizeof (*lp));
291 			lp->l_parsed = 0;
292 			lp->l_groupname = (char *)malloc(len + 1);
293 			bcopy(spos, lp->l_groupname, len);
294 			*(lp->l_groupname + len) = '\0';
295 			len = strlen(pos);
296 			olen = 0;
297 
298 			/*
299 			 * Loop around handling line continuations.
300 			 */
301 			do {
302 				if (*(pos + len - 1) == '\n')
303 					len--;
304 				if (*(pos + len - 1) == '\\') {
305 					len--;
306 					cont = 1;
307 				} else
308 					cont = 0;
309 				if (len > 0) {
310 					linep = (char *)malloc(olen + len + 1);
311 					if (olen > 0) {
312 						bcopy(olinep, linep, olen);
313 						free(olinep);
314 					}
315 					bcopy(pos, linep + olen, len);
316 					olen += len;
317 					*(linep + olen) = '\0';
318 					olinep = linep;
319 				}
320 				if (cont) {
321 					if (fgets(line, LINSIZ, netf)) {
322 						pos = line;
323 						len = strlen(pos);
324 					} else
325 						cont = 0;
326 				}
327 			} while (cont);
328 			lp->l_line = linep;
329 			lp->l_next = linehead;
330 			linehead = lp;
331 
332 			/*
333 			 * If this is the one we wanted, we are done.
334 			 */
335 			if (!strcmp(lp->l_groupname, group))
336 				return (lp);
337 		}
338 	}
339 	return ((struct linelist *)0);
340 }
341