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