Home | History | Annotate | Line # | Download | only in revnetgroup
      1 /*	$NetBSD: parse_netgroup.c,v 1.6 2003/08/07 11:25:51 agc Exp $ */
      2 
      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 
     36 #include <sys/cdefs.h>
     37 #ifndef lint
     38 __RCSID("$NetBSD: parse_netgroup.c,v 1.6 2003/08/07 11:25:51 agc Exp $");
     39 #endif
     40 
     41 /*
     42  * This is a specially hacked-up version of getnetgrent.c used to parse
     43  * data from the stored hash table of netgroup info rather than from a
     44  * file. It's used mainly for the parse_netgroup() function. All the YP
     45  * stuff and file support has been stripped out since it isn't needed.
     46  */
     47 
     48 #include <stdio.h>
     49 #include <stdlib.h>
     50 #include <string.h>
     51 #include <unistd.h>
     52 
     53 #include "hash.h"
     54 
     55 /*
     56  * Static Variables and functions used by rng_setnetgrent(), rng_getnetgrent()
     57  * and rng_endnetgrent().
     58  *
     59  * There are two linked lists:
     60  * - linelist is just used by setnetgrent() to parse the net group file via.
     61  *   parse_netgrp()
     62  * - netgrp is the list of entries for the current netgroup
     63  */
     64 struct linelist {
     65 	struct linelist	*l_next;	/* Chain ptr. */
     66 	int		l_parsed;	/* Flag for cycles */
     67 	char		*l_groupname;	/* Name of netgroup */
     68 	char		*l_line;	/* Netgroup entrie(s) to be parsed */
     69 };
     70 
     71 struct netgrp {
     72 	struct netgrp	*ng_next;	/* Chain ptr */
     73 	char		*ng_str[3];	/* Field pointers, see below */
     74 };
     75 #define NG_HOST		0	/* Host name */
     76 #define NG_USER		1	/* User name */
     77 #define NG_DOM		2	/* and Domain name */
     78 
     79 static struct linelist	*linehead = (struct linelist *)0;
     80 static struct netgrp	*nextgrp = (struct netgrp *)0;
     81 static struct {
     82 	struct netgrp	*gr;
     83 	char		*grname;
     84 } grouphead = {
     85 	(struct netgrp *)0,
     86 	(char *)0,
     87 };
     88 
     89 extern struct group_entry *gtable[];
     90 
     91 static int		parse_netgrp(const char *);
     92 static struct linelist *read_for_group(const char *);
     93 
     94 
     95 /*
     96  * rng_setnetgrent()
     97  * Parse the netgroup file looking for the netgroup and build the list
     98  * of netgrp structures. Let parse_netgrp() and read_for_group() do
     99  * most of the work.
    100  */
    101 void
    102 rng_setnetgrent(const char *group)
    103 {
    104 	/* Sanity check */
    105 
    106 	if (group == NULL || !strlen(group))
    107 		return;
    108 
    109 	if (grouphead.gr == (struct netgrp *)0 ||
    110 		strcmp(group, grouphead.grname)) {
    111 		rng_endnetgrent();
    112 		if (parse_netgrp(group))
    113 			rng_endnetgrent();
    114 		else
    115 			grouphead.grname = strdup(group);
    116 	}
    117 	nextgrp = grouphead.gr;
    118 }
    119 
    120 /*
    121  * Get the next netgroup off the list.
    122  */
    123 int
    124 rng_getnetgrent(char **hostp, char **userp, char **domp)
    125 {
    126 	if (nextgrp) {
    127 		*hostp = nextgrp->ng_str[NG_HOST];
    128 		*userp = nextgrp->ng_str[NG_USER];
    129 		*domp = nextgrp->ng_str[NG_DOM];
    130 		nextgrp = nextgrp->ng_next;
    131 		return (1);
    132 	}
    133 	return (0);
    134 }
    135 
    136 /*
    137  * rng_endnetgrent() - cleanup
    138  */
    139 void
    140 rng_endnetgrent(void)
    141 {
    142 	struct linelist *lp, *olp;
    143 	struct netgrp *gp, *ogp;
    144 
    145 	lp = linehead;
    146 	while (lp) {
    147 		olp = lp;
    148 		lp = lp->l_next;
    149 		free(olp->l_groupname);
    150 		free(olp->l_line);
    151 		free((char *)olp);
    152 	}
    153 	linehead = (struct linelist *)0;
    154 	if (grouphead.grname) {
    155 		free(grouphead.grname);
    156 		grouphead.grname = (char *)0;
    157 	}
    158 	gp = grouphead.gr;
    159 	while (gp) {
    160 		ogp = gp;
    161 		gp = gp->ng_next;
    162 		if (ogp->ng_str[NG_HOST])
    163 			free(ogp->ng_str[NG_HOST]);
    164 		if (ogp->ng_str[NG_USER])
    165 			free(ogp->ng_str[NG_USER]);
    166 		if (ogp->ng_str[NG_DOM])
    167 			free(ogp->ng_str[NG_DOM]);
    168 		free((char *)ogp);
    169 	}
    170 	grouphead.gr = (struct netgrp *)0;
    171 }
    172 
    173 /*
    174  * Parse the netgroup file setting up the linked lists.
    175  */
    176 static int
    177 parse_netgrp(const char *group)
    178 {
    179 	char *spos, *epos;
    180 	int len, strpos;
    181 #ifdef DEBUG
    182 	int fields;
    183 #endif
    184 	char *pos, *gpos;
    185 	struct netgrp *grp;
    186 	struct linelist *lp = linehead;
    187 
    188 	/*
    189 	 * First, see if the line has already been read in.
    190 	 */
    191 	while (lp) {
    192 		if (!strcmp(group, lp->l_groupname))
    193 			break;
    194 		lp = lp->l_next;
    195 	}
    196 	if (lp == (struct linelist *)0 &&
    197 	    (lp = read_for_group(group)) == (struct linelist *)0)
    198 		return (1);
    199 	if (lp->l_parsed) {
    200 #ifdef DEBUG
    201 		/*
    202 		 * This error message is largely superflous since the
    203 		 * code handles the error condition successfully, and
    204 		 * spewing it out from inside libc can actually hose
    205 		 * certain programs.
    206 		 */
    207 		warnx("Cycle in netgroup %s", lp->l_groupname);
    208 #endif
    209 		return (1);
    210 	} else
    211 		lp->l_parsed = 1;
    212 	pos = lp->l_line;
    213 	/* Watch for null pointer dereferences, dammit! */
    214 	while (pos != NULL && *pos != '\0') {
    215 		if (*pos == '(') {
    216 			grp = (struct netgrp *)malloc(sizeof (struct netgrp));
    217 			memset((char *)grp, 0, sizeof (struct netgrp));
    218 			grp->ng_next = grouphead.gr;
    219 			grouphead.gr = grp;
    220 			pos++;
    221 			gpos = strsep(&pos, ")");
    222 #ifdef DEBUG
    223 			fields = 0;
    224 #endif
    225 			for (strpos = 0; strpos < 3; strpos++) {
    226 				if ((spos = strsep(&gpos, ","))) {
    227 #ifdef DEBUG
    228 					fields++;
    229 #endif
    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 						memmove(grp->ng_str[strpos],
    241 							spos, len + 1);
    242 					}
    243 				} else {
    244 					/*
    245 					 * All other systems I've tested
    246 					 * return NULL for empty netgroup
    247 					 * fields. It's up to user programs
    248 					 * to handle the NULLs appropriately.
    249 					 */
    250 					grp->ng_str[strpos] = NULL;
    251 				}
    252 			}
    253 #ifdef DEBUG
    254 			/*
    255 			 * Note: on other platforms, malformed netgroup
    256 			 * entries are not normally flagged. While we
    257 			 * can catch bad entries and report them, we should
    258 			 * stay silent by default for compatibility's sake.
    259 			 */
    260 			if (fields < 3)
    261 				warnx(
    262 				    "Bad entry (%s%s%s%s%s) in netgroup \"%s\"",
    263 				    grp->ng_str[NG_HOST] == NULL ? "" :
    264 					grp->ng_str[NG_HOST],
    265 				    grp->ng_str[NG_USER] == NULL ? "" : ",",
    266 				    grp->ng_str[NG_USER] == NULL ? "" :
    267 					grp->ng_str[NG_USER],
    268 				    grp->ng_str[NG_DOM] == NULL ? "" : ",",
    269 				    grp->ng_str[NG_DOM] == NULL ? "" :
    270 					grp->ng_str[NG_DOM],
    271 				    lp->l_groupname);
    272 #endif
    273 		} else {
    274 			spos = strsep(&pos, ", \t");
    275 			if (parse_netgrp(spos))
    276 				continue;
    277 		}
    278 		/* Watch for null pointer dereferences, dammit! */
    279 		if (pos != NULL)
    280 			while (*pos == ' ' || *pos == ',' || *pos == '\t')
    281 				pos++;
    282 	}
    283 	return (0);
    284 }
    285 
    286 /*
    287  * Read the netgroup file and save lines until the line for the netgroup
    288  * is found. Return 1 if eof is encountered.
    289  */
    290 static struct linelist *
    291 read_for_group(const char *group)
    292 {
    293 	char *pos, *spos, *linep = NULL, *olinep = NULL;
    294 	int len, olen;
    295 	int cont;
    296 	struct linelist *lp;
    297 	char line[LINSIZ + 1];
    298 	char *data = NULL;
    299 
    300 	data = lookup (gtable, group);
    301 	snprintf(line, sizeof(line), "%s %s", group, data);
    302 	pos = (char *)&line;
    303 #ifdef CANT_HAPPEN
    304 	if (*pos == '#')
    305 		continue;
    306 #endif
    307 	while (*pos == ' ' || *pos == '\t')
    308 		pos++;
    309 	spos = pos;
    310 	while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
    311 		*pos != '\0')
    312 		pos++;
    313 	len = pos - spos;
    314 	while (*pos == ' ' || *pos == '\t')
    315 		pos++;
    316 	if (*pos != '\n' && *pos != '\0') {
    317 		lp = (struct linelist *)malloc(sizeof (*lp));
    318 		lp->l_parsed = 0;
    319 		lp->l_groupname = (char *)malloc(len + 1);
    320 		memmove(lp->l_groupname, spos, len);
    321 		*(lp->l_groupname + len) = '\0';
    322 		len = strlen(pos);
    323 		olen = 0;
    324 			/*
    325 			 * Loop around handling line continuations.
    326 			 */
    327 			do {
    328 				if (*(pos + len - 1) == '\n')
    329 					len--;
    330 				if (*(pos + len - 1) == '\\') {
    331 					len--;
    332 					cont = 1;
    333 				} else
    334 					cont = 0;
    335 				if (len > 0) {
    336 					linep = (char *)malloc(olen + len + 1);
    337 					if (olen > 0) {
    338 						memmove(linep, olinep, olen);
    339 						free(olinep);
    340 					}
    341 					memmove(linep + olen, pos, len);
    342 					olen += len;
    343 					*(linep + olen) = '\0';
    344 					olinep = linep;
    345 				}
    346 #ifdef CANT_HAPPEN
    347 				if (cont) {
    348 					if (fgets(line, LINSIZ, netf)) {
    349 						pos = line;
    350 						len = strlen(pos);
    351 					} else
    352 						cont = 0;
    353 				}
    354 #endif
    355 			} while (cont);
    356 		lp->l_line = linep;
    357 		lp->l_next = linehead;
    358 		linehead = lp;
    359 #ifdef CANT_HAPPEN
    360 		/*
    361 		 * If this is the one we wanted, we are done.
    362 		 */
    363 		if (!strcmp(lp->l_groupname, group))
    364 #endif
    365 			return (lp);
    366 	}
    367 	return ((struct linelist *)0);
    368 }
    369