xref: /netbsd-src/usr.sbin/ypserv/revnetgroup/parse_netgroup.c (revision 326b2259b73e878289ebd80cd9d20bc5aee35e99)
1*326b2259Sagc /*	$NetBSD: parse_netgroup.c,v 1.6 2003/08/07 11:25:51 agc Exp $ */
27307c9a9Slukem 
342f1aa04Slukem /*
442f1aa04Slukem  * Copyright (c) 1992, 1993
542f1aa04Slukem  *	The Regents of the University of California.  All rights reserved.
642f1aa04Slukem  *
742f1aa04Slukem  * This code is derived from software contributed to Berkeley by
842f1aa04Slukem  * Rick Macklem at The University of Guelph.
942f1aa04Slukem  *
1042f1aa04Slukem  * Redistribution and use in source and binary forms, with or without
1142f1aa04Slukem  * modification, are permitted provided that the following conditions
1242f1aa04Slukem  * are met:
1342f1aa04Slukem  * 1. Redistributions of source code must retain the above copyright
1442f1aa04Slukem  *    notice, this list of conditions and the following disclaimer.
1542f1aa04Slukem  * 2. Redistributions in binary form must reproduce the above copyright
1642f1aa04Slukem  *    notice, this list of conditions and the following disclaimer in the
1742f1aa04Slukem  *    documentation and/or other materials provided with the distribution.
18*326b2259Sagc  * 3. Neither the name of the University nor the names of its contributors
1942f1aa04Slukem  *    may be used to endorse or promote products derived from this software
2042f1aa04Slukem  *    without specific prior written permission.
2142f1aa04Slukem  *
2242f1aa04Slukem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2342f1aa04Slukem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2442f1aa04Slukem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2542f1aa04Slukem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2642f1aa04Slukem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2742f1aa04Slukem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2842f1aa04Slukem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2942f1aa04Slukem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3042f1aa04Slukem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3142f1aa04Slukem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3242f1aa04Slukem  * SUCH DAMAGE.
3342f1aa04Slukem  *
3442f1aa04Slukem  */
3542f1aa04Slukem 
367307c9a9Slukem #include <sys/cdefs.h>
377307c9a9Slukem #ifndef lint
38*326b2259Sagc __RCSID("$NetBSD: parse_netgroup.c,v 1.6 2003/08/07 11:25:51 agc Exp $");
397307c9a9Slukem #endif
407307c9a9Slukem 
4142f1aa04Slukem /*
4242f1aa04Slukem  * This is a specially hacked-up version of getnetgrent.c used to parse
4342f1aa04Slukem  * data from the stored hash table of netgroup info rather than from a
4442f1aa04Slukem  * file. It's used mainly for the parse_netgroup() function. All the YP
4542f1aa04Slukem  * stuff and file support has been stripped out since it isn't needed.
4642f1aa04Slukem  */
4742f1aa04Slukem 
4842f1aa04Slukem #include <stdio.h>
4942f1aa04Slukem #include <stdlib.h>
507307c9a9Slukem #include <string.h>
5142f1aa04Slukem #include <unistd.h>
527307c9a9Slukem 
5342f1aa04Slukem #include "hash.h"
5442f1aa04Slukem 
5542f1aa04Slukem /*
567307c9a9Slukem  * Static Variables and functions used by rng_setnetgrent(), rng_getnetgrent()
577307c9a9Slukem  * and rng_endnetgrent().
587307c9a9Slukem  *
5942f1aa04Slukem  * There are two linked lists:
6042f1aa04Slukem  * - linelist is just used by setnetgrent() to parse the net group file via.
6142f1aa04Slukem  *   parse_netgrp()
6242f1aa04Slukem  * - netgrp is the list of entries for the current netgroup
6342f1aa04Slukem  */
6442f1aa04Slukem struct linelist {
6542f1aa04Slukem 	struct linelist	*l_next;	/* Chain ptr. */
6642f1aa04Slukem 	int		l_parsed;	/* Flag for cycles */
6742f1aa04Slukem 	char		*l_groupname;	/* Name of netgroup */
6842f1aa04Slukem 	char		*l_line;	/* Netgroup entrie(s) to be parsed */
6942f1aa04Slukem };
7042f1aa04Slukem 
7142f1aa04Slukem struct netgrp {
7242f1aa04Slukem 	struct netgrp	*ng_next;	/* Chain ptr */
7342f1aa04Slukem 	char		*ng_str[3];	/* Field pointers, see below */
7442f1aa04Slukem };
7542f1aa04Slukem #define NG_HOST		0	/* Host name */
7642f1aa04Slukem #define NG_USER		1	/* User name */
7742f1aa04Slukem #define NG_DOM		2	/* and Domain name */
7842f1aa04Slukem 
7942f1aa04Slukem static struct linelist	*linehead = (struct linelist *)0;
8042f1aa04Slukem static struct netgrp	*nextgrp = (struct netgrp *)0;
8142f1aa04Slukem static struct {
8242f1aa04Slukem 	struct netgrp	*gr;
8342f1aa04Slukem 	char		*grname;
8442f1aa04Slukem } grouphead = {
8542f1aa04Slukem 	(struct netgrp *)0,
8642f1aa04Slukem 	(char *)0,
8742f1aa04Slukem };
887307c9a9Slukem 
8942f1aa04Slukem extern struct group_entry *gtable[];
9042f1aa04Slukem 
913a0b8f6eSwiz static int		parse_netgrp(const char *);
923a0b8f6eSwiz static struct linelist *read_for_group(const char *);
937307c9a9Slukem 
947307c9a9Slukem 
9542f1aa04Slukem /*
967307c9a9Slukem  * rng_setnetgrent()
9742f1aa04Slukem  * Parse the netgroup file looking for the netgroup and build the list
9842f1aa04Slukem  * of netgrp structures. Let parse_netgrp() and read_for_group() do
9942f1aa04Slukem  * most of the work.
10042f1aa04Slukem  */
10142f1aa04Slukem void
rng_setnetgrent(const char * group)1023a0b8f6eSwiz rng_setnetgrent(const char *group)
10342f1aa04Slukem {
10442f1aa04Slukem 	/* Sanity check */
10542f1aa04Slukem 
10642f1aa04Slukem 	if (group == NULL || !strlen(group))
10742f1aa04Slukem 		return;
10842f1aa04Slukem 
10942f1aa04Slukem 	if (grouphead.gr == (struct netgrp *)0 ||
11042f1aa04Slukem 		strcmp(group, grouphead.grname)) {
1117307c9a9Slukem 		rng_endnetgrent();
11242f1aa04Slukem 		if (parse_netgrp(group))
1137307c9a9Slukem 			rng_endnetgrent();
11497a29a12Sitojun 		else
11597a29a12Sitojun 			grouphead.grname = strdup(group);
11642f1aa04Slukem 	}
11742f1aa04Slukem 	nextgrp = grouphead.gr;
11842f1aa04Slukem }
11942f1aa04Slukem 
12042f1aa04Slukem /*
12142f1aa04Slukem  * Get the next netgroup off the list.
12242f1aa04Slukem  */
12342f1aa04Slukem int
rng_getnetgrent(char ** hostp,char ** userp,char ** domp)1243a0b8f6eSwiz rng_getnetgrent(char **hostp, char **userp, char **domp)
12542f1aa04Slukem {
12642f1aa04Slukem 	if (nextgrp) {
12742f1aa04Slukem 		*hostp = nextgrp->ng_str[NG_HOST];
12842f1aa04Slukem 		*userp = nextgrp->ng_str[NG_USER];
12942f1aa04Slukem 		*domp = nextgrp->ng_str[NG_DOM];
13042f1aa04Slukem 		nextgrp = nextgrp->ng_next;
13142f1aa04Slukem 		return (1);
13242f1aa04Slukem 	}
13342f1aa04Slukem 	return (0);
13442f1aa04Slukem }
13542f1aa04Slukem 
13642f1aa04Slukem /*
1377307c9a9Slukem  * rng_endnetgrent() - cleanup
13842f1aa04Slukem  */
13942f1aa04Slukem void
rng_endnetgrent(void)1403a0b8f6eSwiz rng_endnetgrent(void)
14142f1aa04Slukem {
1427307c9a9Slukem 	struct linelist *lp, *olp;
1437307c9a9Slukem 	struct netgrp *gp, *ogp;
14442f1aa04Slukem 
14542f1aa04Slukem 	lp = linehead;
14642f1aa04Slukem 	while (lp) {
14742f1aa04Slukem 		olp = lp;
14842f1aa04Slukem 		lp = lp->l_next;
14942f1aa04Slukem 		free(olp->l_groupname);
15042f1aa04Slukem 		free(olp->l_line);
15142f1aa04Slukem 		free((char *)olp);
15242f1aa04Slukem 	}
15342f1aa04Slukem 	linehead = (struct linelist *)0;
15442f1aa04Slukem 	if (grouphead.grname) {
15542f1aa04Slukem 		free(grouphead.grname);
15642f1aa04Slukem 		grouphead.grname = (char *)0;
15742f1aa04Slukem 	}
15842f1aa04Slukem 	gp = grouphead.gr;
15942f1aa04Slukem 	while (gp) {
16042f1aa04Slukem 		ogp = gp;
16142f1aa04Slukem 		gp = gp->ng_next;
16242f1aa04Slukem 		if (ogp->ng_str[NG_HOST])
16342f1aa04Slukem 			free(ogp->ng_str[NG_HOST]);
16442f1aa04Slukem 		if (ogp->ng_str[NG_USER])
16542f1aa04Slukem 			free(ogp->ng_str[NG_USER]);
16642f1aa04Slukem 		if (ogp->ng_str[NG_DOM])
16742f1aa04Slukem 			free(ogp->ng_str[NG_DOM]);
16842f1aa04Slukem 		free((char *)ogp);
16942f1aa04Slukem 	}
17042f1aa04Slukem 	grouphead.gr = (struct netgrp *)0;
17142f1aa04Slukem }
17242f1aa04Slukem 
17342f1aa04Slukem /*
17442f1aa04Slukem  * Parse the netgroup file setting up the linked lists.
17542f1aa04Slukem  */
17642f1aa04Slukem static int
parse_netgrp(const char * group)1773a0b8f6eSwiz parse_netgrp(const char *group)
17842f1aa04Slukem {
1797307c9a9Slukem 	char *spos, *epos;
1807307c9a9Slukem 	int len, strpos;
18142f1aa04Slukem #ifdef DEBUG
1827307c9a9Slukem 	int fields;
18342f1aa04Slukem #endif
18442f1aa04Slukem 	char *pos, *gpos;
18542f1aa04Slukem 	struct netgrp *grp;
18642f1aa04Slukem 	struct linelist *lp = linehead;
18742f1aa04Slukem 
18842f1aa04Slukem 	/*
18942f1aa04Slukem 	 * First, see if the line has already been read in.
19042f1aa04Slukem 	 */
19142f1aa04Slukem 	while (lp) {
19242f1aa04Slukem 		if (!strcmp(group, lp->l_groupname))
19342f1aa04Slukem 			break;
19442f1aa04Slukem 		lp = lp->l_next;
19542f1aa04Slukem 	}
19642f1aa04Slukem 	if (lp == (struct linelist *)0 &&
19742f1aa04Slukem 	    (lp = read_for_group(group)) == (struct linelist *)0)
19842f1aa04Slukem 		return (1);
19942f1aa04Slukem 	if (lp->l_parsed) {
20042f1aa04Slukem #ifdef DEBUG
20142f1aa04Slukem 		/*
20242f1aa04Slukem 		 * This error message is largely superflous since the
2039115df8cSwiz 		 * code handles the error condition successfully, and
20442f1aa04Slukem 		 * spewing it out from inside libc can actually hose
20542f1aa04Slukem 		 * certain programs.
20642f1aa04Slukem 		 */
2077307c9a9Slukem 		warnx("Cycle in netgroup %s", lp->l_groupname);
20842f1aa04Slukem #endif
20942f1aa04Slukem 		return (1);
21042f1aa04Slukem 	} else
21142f1aa04Slukem 		lp->l_parsed = 1;
21242f1aa04Slukem 	pos = lp->l_line;
21342f1aa04Slukem 	/* Watch for null pointer dereferences, dammit! */
21442f1aa04Slukem 	while (pos != NULL && *pos != '\0') {
21542f1aa04Slukem 		if (*pos == '(') {
21642f1aa04Slukem 			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
2177307c9a9Slukem 			memset((char *)grp, 0, sizeof (struct netgrp));
21842f1aa04Slukem 			grp->ng_next = grouphead.gr;
21942f1aa04Slukem 			grouphead.gr = grp;
22042f1aa04Slukem 			pos++;
22142f1aa04Slukem 			gpos = strsep(&pos, ")");
22242f1aa04Slukem #ifdef DEBUG
22342f1aa04Slukem 			fields = 0;
22442f1aa04Slukem #endif
22542f1aa04Slukem 			for (strpos = 0; strpos < 3; strpos++) {
22642f1aa04Slukem 				if ((spos = strsep(&gpos, ","))) {
22742f1aa04Slukem #ifdef DEBUG
22842f1aa04Slukem 					fields++;
22942f1aa04Slukem #endif
23042f1aa04Slukem 					while (*spos == ' ' || *spos == '\t')
23142f1aa04Slukem 						spos++;
23242f1aa04Slukem 					if ((epos = strpbrk(spos, " \t"))) {
23342f1aa04Slukem 						*epos = '\0';
23442f1aa04Slukem 						len = epos - spos;
23542f1aa04Slukem 					} else
23642f1aa04Slukem 						len = strlen(spos);
23742f1aa04Slukem 					if (len > 0) {
23842f1aa04Slukem 						grp->ng_str[strpos] =  (char *)
23942f1aa04Slukem 							malloc(len + 1);
2407307c9a9Slukem 						memmove(grp->ng_str[strpos],
2417307c9a9Slukem 							spos, len + 1);
24242f1aa04Slukem 					}
24342f1aa04Slukem 				} else {
24442f1aa04Slukem 					/*
24542f1aa04Slukem 					 * All other systems I've tested
24642f1aa04Slukem 					 * return NULL for empty netgroup
24742f1aa04Slukem 					 * fields. It's up to user programs
24842f1aa04Slukem 					 * to handle the NULLs appropriately.
24942f1aa04Slukem 					 */
25042f1aa04Slukem 					grp->ng_str[strpos] = NULL;
25142f1aa04Slukem 				}
25242f1aa04Slukem 			}
25342f1aa04Slukem #ifdef DEBUG
25442f1aa04Slukem 			/*
25542f1aa04Slukem 			 * Note: on other platforms, malformed netgroup
25642f1aa04Slukem 			 * entries are not normally flagged. While we
25742f1aa04Slukem 			 * can catch bad entries and report them, we should
25842f1aa04Slukem 			 * stay silent by default for compatibility's sake.
25942f1aa04Slukem 			 */
26042f1aa04Slukem 			if (fields < 3)
2617307c9a9Slukem 				warnx(
2627307c9a9Slukem 				    "Bad entry (%s%s%s%s%s) in netgroup \"%s\"",
2637307c9a9Slukem 				    grp->ng_str[NG_HOST] == NULL ? "" :
2647307c9a9Slukem 					grp->ng_str[NG_HOST],
26542f1aa04Slukem 				    grp->ng_str[NG_USER] == NULL ? "" : ",",
2667307c9a9Slukem 				    grp->ng_str[NG_USER] == NULL ? "" :
2677307c9a9Slukem 					grp->ng_str[NG_USER],
26842f1aa04Slukem 				    grp->ng_str[NG_DOM] == NULL ? "" : ",",
2697307c9a9Slukem 				    grp->ng_str[NG_DOM] == NULL ? "" :
2707307c9a9Slukem 					grp->ng_str[NG_DOM],
27142f1aa04Slukem 				    lp->l_groupname);
27242f1aa04Slukem #endif
27342f1aa04Slukem 		} else {
27442f1aa04Slukem 			spos = strsep(&pos, ", \t");
27542f1aa04Slukem 			if (parse_netgrp(spos))
27642f1aa04Slukem 				continue;
27742f1aa04Slukem 		}
27842f1aa04Slukem 		/* Watch for null pointer dereferences, dammit! */
27942f1aa04Slukem 		if (pos != NULL)
28042f1aa04Slukem 			while (*pos == ' ' || *pos == ',' || *pos == '\t')
28142f1aa04Slukem 				pos++;
28242f1aa04Slukem 	}
28342f1aa04Slukem 	return (0);
28442f1aa04Slukem }
28542f1aa04Slukem 
28642f1aa04Slukem /*
28742f1aa04Slukem  * Read the netgroup file and save lines until the line for the netgroup
28842f1aa04Slukem  * is found. Return 1 if eof is encountered.
28942f1aa04Slukem  */
29042f1aa04Slukem static struct linelist *
read_for_group(const char * group)2913a0b8f6eSwiz read_for_group(const char *group)
29242f1aa04Slukem {
2937307c9a9Slukem 	char *pos, *spos, *linep = NULL, *olinep = NULL;
2947307c9a9Slukem 	int len, olen;
29542f1aa04Slukem 	int cont;
29642f1aa04Slukem 	struct linelist *lp;
29742f1aa04Slukem 	char line[LINSIZ + 1];
29842f1aa04Slukem 	char *data = NULL;
29942f1aa04Slukem 
30042f1aa04Slukem 	data = lookup (gtable, group);
30197a29a12Sitojun 	snprintf(line, sizeof(line), "%s %s", group, data);
30242f1aa04Slukem 	pos = (char *)&line;
30342f1aa04Slukem #ifdef CANT_HAPPEN
30442f1aa04Slukem 	if (*pos == '#')
30542f1aa04Slukem 		continue;
30642f1aa04Slukem #endif
30742f1aa04Slukem 	while (*pos == ' ' || *pos == '\t')
30842f1aa04Slukem 		pos++;
30942f1aa04Slukem 	spos = pos;
31042f1aa04Slukem 	while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
31142f1aa04Slukem 		*pos != '\0')
31242f1aa04Slukem 		pos++;
31342f1aa04Slukem 	len = pos - spos;
31442f1aa04Slukem 	while (*pos == ' ' || *pos == '\t')
31542f1aa04Slukem 		pos++;
31642f1aa04Slukem 	if (*pos != '\n' && *pos != '\0') {
31742f1aa04Slukem 		lp = (struct linelist *)malloc(sizeof (*lp));
31842f1aa04Slukem 		lp->l_parsed = 0;
31942f1aa04Slukem 		lp->l_groupname = (char *)malloc(len + 1);
3207307c9a9Slukem 		memmove(lp->l_groupname, spos, len);
32142f1aa04Slukem 		*(lp->l_groupname + len) = '\0';
32242f1aa04Slukem 		len = strlen(pos);
32342f1aa04Slukem 		olen = 0;
32442f1aa04Slukem 			/*
32542f1aa04Slukem 			 * Loop around handling line continuations.
32642f1aa04Slukem 			 */
32742f1aa04Slukem 			do {
32842f1aa04Slukem 				if (*(pos + len - 1) == '\n')
32942f1aa04Slukem 					len--;
33042f1aa04Slukem 				if (*(pos + len - 1) == '\\') {
33142f1aa04Slukem 					len--;
33242f1aa04Slukem 					cont = 1;
33342f1aa04Slukem 				} else
33442f1aa04Slukem 					cont = 0;
33542f1aa04Slukem 				if (len > 0) {
33642f1aa04Slukem 					linep = (char *)malloc(olen + len + 1);
33742f1aa04Slukem 					if (olen > 0) {
3387307c9a9Slukem 						memmove(linep, olinep, olen);
33942f1aa04Slukem 						free(olinep);
34042f1aa04Slukem 					}
3417307c9a9Slukem 					memmove(linep + olen, pos, len);
34242f1aa04Slukem 					olen += len;
34342f1aa04Slukem 					*(linep + olen) = '\0';
34442f1aa04Slukem 					olinep = linep;
34542f1aa04Slukem 				}
34642f1aa04Slukem #ifdef CANT_HAPPEN
34742f1aa04Slukem 				if (cont) {
34842f1aa04Slukem 					if (fgets(line, LINSIZ, netf)) {
34942f1aa04Slukem 						pos = line;
35042f1aa04Slukem 						len = strlen(pos);
35142f1aa04Slukem 					} else
35242f1aa04Slukem 						cont = 0;
35342f1aa04Slukem 				}
35442f1aa04Slukem #endif
35542f1aa04Slukem 			} while (cont);
35642f1aa04Slukem 		lp->l_line = linep;
35742f1aa04Slukem 		lp->l_next = linehead;
35842f1aa04Slukem 		linehead = lp;
35942f1aa04Slukem #ifdef CANT_HAPPEN
36042f1aa04Slukem 		/*
36142f1aa04Slukem 		 * If this is the one we wanted, we are done.
36242f1aa04Slukem 		 */
36342f1aa04Slukem 		if (!strcmp(lp->l_groupname, group))
36442f1aa04Slukem #endif
36542f1aa04Slukem 			return (lp);
36642f1aa04Slukem 	}
36742f1aa04Slukem 	return ((struct linelist *)0);
36842f1aa04Slukem }
369