parse_netgroup.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1992, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Rick Macklem at The University of Guelph.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#ifndef lint
36static const char rcsid[] =
37  "$FreeBSD: stable/11/libexec/revnetgroup/parse_netgroup.c 330897 2018-03-14 03:19:51Z eadler $";
38#endif /* not lint */
39
40/*
41 * This is a specially hacked-up version of getnetgrent.c used to parse
42 * data from the stored hash table of netgroup info rather than from a
43 * file. It's used mainly for the parse_netgroup() function. All the YP
44 * stuff and file support has been stripped out since it isn't needed.
45 */
46
47#include <stdio.h>
48#include <string.h>
49#include <strings.h>
50#include <stdlib.h>
51#include <unistd.h>
52#include "hash.h"
53
54/*
55 * Static Variables and functions used by setnetgrent(), getnetgrent() and
56 * __endnetgrent().
57 * There are two linked lists:
58 * - linelist is just used by setnetgrent() to parse the net group file via.
59 *   parse_netgrp()
60 * - netgrp is the list of entries for the current netgroup
61 */
62struct linelist {
63	struct linelist	*l_next;	/* Chain ptr. */
64	int		l_parsed;	/* Flag for cycles */
65	char		*l_groupname;	/* Name of netgroup */
66	char		*l_line;	/* Netgroup entrie(s) to be parsed */
67};
68
69struct netgrp {
70	struct netgrp	*ng_next;	/* Chain ptr */
71	char		*ng_str[3];	/* Field pointers, see below */
72};
73#define NG_HOST		0	/* Host name */
74#define NG_USER		1	/* User name */
75#define NG_DOM		2	/* and Domain name */
76
77static struct linelist	*linehead = (struct linelist *)0;
78static struct netgrp	*nextgrp = (struct netgrp *)0;
79static struct {
80	struct netgrp	*gr;
81	char		*grname;
82} grouphead = {
83	(struct netgrp *)0,
84	(char *)0,
85};
86static int parse_netgrp(char *group);
87static struct linelist *read_for_group(char *group);
88extern struct group_entry *gtable[];
89
90/*
91 * setnetgrent()
92 * Parse the netgroup file looking for the netgroup and build the list
93 * of netgrp structures. Let parse_netgrp() and read_for_group() do
94 * most of the work.
95 */
96void
97__setnetgrent(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 (parse_netgrp(group))
108			__endnetgrent();
109		else {
110			grouphead.grname = (char *)
111				malloc(strlen(group) + 1);
112			strcpy(grouphead.grname, group);
113		}
114	}
115	nextgrp = grouphead.gr;
116}
117
118/*
119 * Get the next netgroup off the list.
120 */
121int
122__getnetgrent(char **hostp, char **userp, char **domp)
123{
124	if (nextgrp) {
125		*hostp = nextgrp->ng_str[NG_HOST];
126		*userp = nextgrp->ng_str[NG_USER];
127		*domp = nextgrp->ng_str[NG_DOM];
128		nextgrp = nextgrp->ng_next;
129		return (1);
130	}
131	return (0);
132}
133
134/*
135 * __endnetgrent() - cleanup
136 */
137void
138__endnetgrent(void)
139{
140	struct linelist *lp, *olp;
141	struct netgrp *gp, *ogp;
142
143	lp = linehead;
144	while (lp) {
145		olp = lp;
146		lp = lp->l_next;
147		free(olp->l_groupname);
148		free(olp->l_line);
149		free((char *)olp);
150	}
151	linehead = (struct linelist *)0;
152	if (grouphead.grname) {
153		free(grouphead.grname);
154		grouphead.grname = (char *)0;
155	}
156	gp = grouphead.gr;
157	while (gp) {
158		ogp = gp;
159		gp = gp->ng_next;
160		if (ogp->ng_str[NG_HOST])
161			free(ogp->ng_str[NG_HOST]);
162		if (ogp->ng_str[NG_USER])
163			free(ogp->ng_str[NG_USER]);
164		if (ogp->ng_str[NG_DOM])
165			free(ogp->ng_str[NG_DOM]);
166		free((char *)ogp);
167	}
168	grouphead.gr = (struct netgrp *)0;
169}
170
171/*
172 * Parse the netgroup file setting up the linked lists.
173 */
174static int
175parse_netgrp(char *group)
176{
177	char *spos, *epos;
178	int len, strpos;
179#ifdef DEBUG
180	int fields;
181#endif
182	char *pos, *gpos;
183	struct netgrp *grp;
184	struct linelist *lp = linehead;
185
186	/*
187	 * First, see if the line has already been read in.
188	 */
189	while (lp) {
190		if (!strcmp(group, lp->l_groupname))
191			break;
192		lp = lp->l_next;
193	}
194	if (lp == (struct linelist *)0 &&
195	    (lp = read_for_group(group)) == (struct linelist *)0)
196		return (1);
197	if (lp->l_parsed) {
198#ifdef DEBUG
199		/*
200		 * This error message is largely superfluous since the
201		 * code handles the error condition successfully, and
202		 * spewing it out from inside libc can actually hose
203		 * certain programs.
204		 */
205		warnx("cycle in netgroup %s", lp->l_groupname);
206#endif
207		return (1);
208	} else
209		lp->l_parsed = 1;
210	pos = lp->l_line;
211	/* Watch for null pointer dereferences, dammit! */
212	while (pos != NULL && *pos != '\0') {
213		if (*pos == '(') {
214			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
215			bzero((char *)grp, sizeof (struct netgrp));
216			grp->ng_next = grouphead.gr;
217			grouphead.gr = grp;
218			pos++;
219			gpos = strsep(&pos, ")");
220#ifdef DEBUG
221			fields = 0;
222#endif
223			for (strpos = 0; strpos < 3; strpos++) {
224				if ((spos = strsep(&gpos, ","))) {
225#ifdef DEBUG
226					fields++;
227#endif
228					while (*spos == ' ' || *spos == '\t')
229						spos++;
230					if ((epos = strpbrk(spos, " \t"))) {
231						*epos = '\0';
232						len = epos - spos;
233					} else
234						len = strlen(spos);
235					if (len > 0) {
236						grp->ng_str[strpos] =  (char *)
237							malloc(len + 1);
238						bcopy(spos, grp->ng_str[strpos],
239							len + 1);
240					}
241				} else {
242					/*
243					 * All other systems I've tested
244					 * return NULL for empty netgroup
245					 * fields. It's up to user programs
246					 * to handle the NULLs appropriately.
247					 */
248					grp->ng_str[strpos] = NULL;
249				}
250			}
251#ifdef DEBUG
252			/*
253			 * Note: on other platforms, malformed netgroup
254			 * entries are not normally flagged. While we
255			 * can catch bad entries and report them, we should
256			 * stay silent by default for compatibility's sake.
257			 */
258			if (fields < 3)
259					warnx("bad entry (%s%s%s%s%s) in netgroup \"%s\"",
260						grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],
261						grp->ng_str[NG_USER] == NULL ? "" : ",",
262						grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],
263						grp->ng_str[NG_DOM] == NULL ? "" : ",",
264						grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],
265						lp->l_groupname);
266#endif
267		} else {
268			spos = strsep(&pos, ", \t");
269			if (parse_netgrp(spos))
270				continue;
271		}
272		/* Watch for null pointer dereferences, dammit! */
273		if (pos != NULL)
274			while (*pos == ' ' || *pos == ',' || *pos == '\t')
275				pos++;
276	}
277	return (0);
278}
279
280/*
281 * Read the netgroup file and save lines until the line for the netgroup
282 * is found. Return 1 if eof is encountered.
283 */
284static struct linelist *
285read_for_group(char *group)
286{
287	char *pos, *spos, *linep = NULL, *olinep = NULL;
288	int len, olen;
289	int cont;
290	struct linelist *lp;
291	char line[LINSIZ + 1];
292	char *data = NULL;
293
294	data = lookup (gtable, group);
295	sprintf(line, "%s %s", group, data);
296	pos = (char *)&line;
297#ifdef CANT_HAPPEN
298	if (*pos == '#')
299		continue;
300#endif
301	while (*pos == ' ' || *pos == '\t')
302		pos++;
303	spos = pos;
304	while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
305		*pos != '\0')
306		pos++;
307	len = pos - spos;
308	while (*pos == ' ' || *pos == '\t')
309		pos++;
310	if (*pos != '\n' && *pos != '\0') {
311		lp = (struct linelist *)malloc(sizeof (*lp));
312		lp->l_parsed = 0;
313		lp->l_groupname = (char *)malloc(len + 1);
314		bcopy(spos, lp->l_groupname, len);
315		*(lp->l_groupname + len) = '\0';
316		len = strlen(pos);
317		olen = 0;
318			/*
319			 * Loop around handling line continuations.
320			 */
321			do {
322				if (*(pos + len - 1) == '\n')
323					len--;
324				if (*(pos + len - 1) == '\\') {
325					len--;
326					cont = 1;
327				} else
328					cont = 0;
329				if (len > 0) {
330					linep = (char *)malloc(olen + len + 1);
331					if (olen > 0) {
332						bcopy(olinep, linep, olen);
333						free(olinep);
334					}
335					bcopy(pos, linep + olen, len);
336					olen += len;
337					*(linep + olen) = '\0';
338					olinep = linep;
339				}
340#ifdef CANT_HAPPEN
341				if (cont) {
342					if (fgets(line, LINSIZ, netf)) {
343						pos = line;
344						len = strlen(pos);
345					} else
346						cont = 0;
347				}
348#endif
349			} while (cont);
350		lp->l_line = linep;
351		lp->l_next = linehead;
352		linehead = lp;
353#ifdef CANT_HAPPEN
354		/*
355		 * If this is the one we wanted, we are done.
356		 */
357		if (!strcmp(lp->l_groupname, group))
358#endif
359			return (lp);
360	}
361	return ((struct linelist *)0);
362}
363