111814Swpaul/* 211814Swpaul * Copyright (c) 1992, 1993 311814Swpaul * The Regents of the University of California. All rights reserved. 411814Swpaul * 511814Swpaul * This code is derived from software contributed to Berkeley by 611814Swpaul * Rick Macklem at The University of Guelph. 711814Swpaul * 811814Swpaul * Redistribution and use in source and binary forms, with or without 911814Swpaul * modification, are permitted provided that the following conditions 1011814Swpaul * are met: 1111814Swpaul * 1. Redistributions of source code must retain the above copyright 1211814Swpaul * notice, this list of conditions and the following disclaimer. 1311814Swpaul * 2. Redistributions in binary form must reproduce the above copyright 1411814Swpaul * notice, this list of conditions and the following disclaimer in the 1511814Swpaul * documentation and/or other materials provided with the distribution. 1611814Swpaul * 3. All advertising materials mentioning features or use of this software 1711814Swpaul * must display the following acknowledgement: 1811814Swpaul * This product includes software developed by the University of 1911814Swpaul * California, Berkeley and its contributors. 2011814Swpaul * 4. Neither the name of the University nor the names of its contributors 2111814Swpaul * may be used to endorse or promote products derived from this software 2211814Swpaul * without specific prior written permission. 2311814Swpaul * 2411814Swpaul * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2511814Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2611814Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2711814Swpaul * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2811814Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2911814Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3011814Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3111814Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3211814Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3311814Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3411814Swpaul * SUCH DAMAGE. 3511814Swpaul */ 3611814Swpaul 3731404Scharnier#ifndef lint 3831404Scharnierstatic const char rcsid[] = 3950476Speter "$FreeBSD$"; 4031404Scharnier#endif /* not lint */ 4111814Swpaul 4211814Swpaul/* 4311814Swpaul * This is a specially hacked-up version of getnetgrent.c used to parse 4411814Swpaul * data from the stored hash table of netgroup info rather than from a 4511814Swpaul * file. It's used mainly for the parse_netgroup() function. All the YP 4611814Swpaul * stuff and file support has been stripped out since it isn't needed. 4711814Swpaul */ 4811814Swpaul 4911814Swpaul#include <stdio.h> 5093590Smike#include <string.h> 5111814Swpaul#include <strings.h> 5211814Swpaul#include <stdlib.h> 5311814Swpaul#include <unistd.h> 5411814Swpaul#include "hash.h" 5511814Swpaul 5611814Swpaul/* 5711814Swpaul * Static Variables and functions used by setnetgrent(), getnetgrent() and 5811814Swpaul * __endnetgrent(). 5911814Swpaul * There are two linked lists: 6011814Swpaul * - linelist is just used by setnetgrent() to parse the net group file via. 6111814Swpaul * parse_netgrp() 6211814Swpaul * - netgrp is the list of entries for the current netgroup 6311814Swpaul */ 6411814Swpaulstruct linelist { 6511814Swpaul struct linelist *l_next; /* Chain ptr. */ 6611814Swpaul int l_parsed; /* Flag for cycles */ 6711814Swpaul char *l_groupname; /* Name of netgroup */ 6811814Swpaul char *l_line; /* Netgroup entrie(s) to be parsed */ 6911814Swpaul}; 7011814Swpaul 7111814Swpaulstruct netgrp { 7211814Swpaul struct netgrp *ng_next; /* Chain ptr */ 7311814Swpaul char *ng_str[3]; /* Field pointers, see below */ 7411814Swpaul}; 7511814Swpaul#define NG_HOST 0 /* Host name */ 7611814Swpaul#define NG_USER 1 /* User name */ 7711814Swpaul#define NG_DOM 2 /* and Domain name */ 7811814Swpaul 7911814Swpaulstatic struct linelist *linehead = (struct linelist *)0; 8011814Swpaulstatic struct netgrp *nextgrp = (struct netgrp *)0; 8111814Swpaulstatic struct { 8211814Swpaul struct netgrp *gr; 8311814Swpaul char *grname; 8411814Swpaul} grouphead = { 8511814Swpaul (struct netgrp *)0, 8611814Swpaul (char *)0, 8711814Swpaul}; 8890377Simpstatic int parse_netgrp(char *group); 8990377Simpstatic struct linelist *read_for_group(char *group); 9011814Swpaulextern struct group_entry *gtable[]; 9111814Swpaul 9211814Swpaul/* 9311814Swpaul * setnetgrent() 9411814Swpaul * Parse the netgroup file looking for the netgroup and build the list 9511814Swpaul * of netgrp structures. Let parse_netgrp() and read_for_group() do 9611814Swpaul * most of the work. 9711814Swpaul */ 9811814Swpaulvoid 9990377Simp__setnetgrent(char *group) 10011814Swpaul{ 10111814Swpaul /* Sanity check */ 10211814Swpaul 10311814Swpaul if (group == NULL || !strlen(group)) 10411814Swpaul return; 10511814Swpaul 10611814Swpaul if (grouphead.gr == (struct netgrp *)0 || 10711814Swpaul strcmp(group, grouphead.grname)) { 10811814Swpaul __endnetgrent(); 10911814Swpaul if (parse_netgrp(group)) 11011814Swpaul __endnetgrent(); 11111814Swpaul else { 11211814Swpaul grouphead.grname = (char *) 11311814Swpaul malloc(strlen(group) + 1); 11411814Swpaul strcpy(grouphead.grname, group); 11511814Swpaul } 11611814Swpaul } 11711814Swpaul nextgrp = grouphead.gr; 11811814Swpaul} 11911814Swpaul 12011814Swpaul/* 12111814Swpaul * Get the next netgroup off the list. 12211814Swpaul */ 12311814Swpaulint 12490377Simp__getnetgrent(char **hostp, char **userp, char **domp) 12511814Swpaul{ 12611814Swpaul if (nextgrp) { 12711814Swpaul *hostp = nextgrp->ng_str[NG_HOST]; 12811814Swpaul *userp = nextgrp->ng_str[NG_USER]; 12911814Swpaul *domp = nextgrp->ng_str[NG_DOM]; 13011814Swpaul nextgrp = nextgrp->ng_next; 13111814Swpaul return (1); 13211814Swpaul } 13311814Swpaul return (0); 13411814Swpaul} 13511814Swpaul 13611814Swpaul/* 13711814Swpaul * __endnetgrent() - cleanup 13811814Swpaul */ 13911814Swpaulvoid 14090377Simp__endnetgrent(void) 14111814Swpaul{ 14290377Simp struct linelist *lp, *olp; 14390377Simp struct netgrp *gp, *ogp; 14411814Swpaul 14511814Swpaul lp = linehead; 14611814Swpaul while (lp) { 14711814Swpaul olp = lp; 14811814Swpaul lp = lp->l_next; 14911814Swpaul free(olp->l_groupname); 15011814Swpaul free(olp->l_line); 15111814Swpaul free((char *)olp); 15211814Swpaul } 15311814Swpaul linehead = (struct linelist *)0; 15411814Swpaul if (grouphead.grname) { 15511814Swpaul free(grouphead.grname); 15611814Swpaul grouphead.grname = (char *)0; 15711814Swpaul } 15811814Swpaul gp = grouphead.gr; 15911814Swpaul while (gp) { 16011814Swpaul ogp = gp; 16111814Swpaul gp = gp->ng_next; 16211814Swpaul if (ogp->ng_str[NG_HOST]) 16311814Swpaul free(ogp->ng_str[NG_HOST]); 16411814Swpaul if (ogp->ng_str[NG_USER]) 16511814Swpaul free(ogp->ng_str[NG_USER]); 16611814Swpaul if (ogp->ng_str[NG_DOM]) 16711814Swpaul free(ogp->ng_str[NG_DOM]); 16811814Swpaul free((char *)ogp); 16911814Swpaul } 17011814Swpaul grouphead.gr = (struct netgrp *)0; 17111814Swpaul} 17211814Swpaul 17311814Swpaul/* 17411814Swpaul * Parse the netgroup file setting up the linked lists. 17511814Swpaul */ 17611814Swpaulstatic int 17790377Simpparse_netgrp(char *group) 17811814Swpaul{ 17990377Simp char *spos, *epos; 18090377Simp int len, strpos; 18111814Swpaul#ifdef DEBUG 18290377Simp int fields; 18311814Swpaul#endif 18411814Swpaul char *pos, *gpos; 18511814Swpaul struct netgrp *grp; 18611814Swpaul struct linelist *lp = linehead; 18711814Swpaul 18811814Swpaul /* 18911814Swpaul * First, see if the line has already been read in. 19011814Swpaul */ 19111814Swpaul while (lp) { 19211814Swpaul if (!strcmp(group, lp->l_groupname)) 19311814Swpaul break; 19411814Swpaul lp = lp->l_next; 19511814Swpaul } 19611814Swpaul if (lp == (struct linelist *)0 && 19711814Swpaul (lp = read_for_group(group)) == (struct linelist *)0) 19811814Swpaul return (1); 19911814Swpaul if (lp->l_parsed) { 20011814Swpaul#ifdef DEBUG 20111814Swpaul /* 20211814Swpaul * This error message is largely superflous since the 20311814Swpaul * code handles the error condition sucessfully, and 20411814Swpaul * spewing it out from inside libc can actually hose 20511814Swpaul * certain programs. 20611814Swpaul */ 20731404Scharnier warnx("cycle in netgroup %s", lp->l_groupname); 20811814Swpaul#endif 20911814Swpaul return (1); 21011814Swpaul } else 21111814Swpaul lp->l_parsed = 1; 21211814Swpaul pos = lp->l_line; 21311814Swpaul /* Watch for null pointer dereferences, dammit! */ 21411814Swpaul while (pos != NULL && *pos != '\0') { 21511814Swpaul if (*pos == '(') { 21611814Swpaul grp = (struct netgrp *)malloc(sizeof (struct netgrp)); 21711814Swpaul bzero((char *)grp, sizeof (struct netgrp)); 21811814Swpaul grp->ng_next = grouphead.gr; 21911814Swpaul grouphead.gr = grp; 22011814Swpaul pos++; 22111814Swpaul gpos = strsep(&pos, ")"); 22211814Swpaul#ifdef DEBUG 22311814Swpaul fields = 0; 22411814Swpaul#endif 22511814Swpaul for (strpos = 0; strpos < 3; strpos++) { 22611814Swpaul if ((spos = strsep(&gpos, ","))) { 22711814Swpaul#ifdef DEBUG 22811814Swpaul fields++; 22911814Swpaul#endif 23011814Swpaul while (*spos == ' ' || *spos == '\t') 23111814Swpaul spos++; 23211814Swpaul if ((epos = strpbrk(spos, " \t"))) { 23311814Swpaul *epos = '\0'; 23411814Swpaul len = epos - spos; 23511814Swpaul } else 23611814Swpaul len = strlen(spos); 23711814Swpaul if (len > 0) { 23811814Swpaul grp->ng_str[strpos] = (char *) 23911814Swpaul malloc(len + 1); 24011814Swpaul bcopy(spos, grp->ng_str[strpos], 24111814Swpaul len + 1); 24211814Swpaul } 24311814Swpaul } else { 24411814Swpaul /* 24511814Swpaul * All other systems I've tested 24611814Swpaul * return NULL for empty netgroup 24711814Swpaul * fields. It's up to user programs 24811814Swpaul * to handle the NULLs appropriately. 24911814Swpaul */ 25011814Swpaul grp->ng_str[strpos] = NULL; 25111814Swpaul } 25211814Swpaul } 25311814Swpaul#ifdef DEBUG 25411814Swpaul /* 25511814Swpaul * Note: on other platforms, malformed netgroup 25611814Swpaul * entries are not normally flagged. While we 25711814Swpaul * can catch bad entries and report them, we should 25811814Swpaul * stay silent by default for compatibility's sake. 25911814Swpaul */ 26011814Swpaul if (fields < 3) 26131404Scharnier warnx("bad entry (%s%s%s%s%s) in netgroup \"%s\"", 26211814Swpaul grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST], 26311814Swpaul grp->ng_str[NG_USER] == NULL ? "" : ",", 26411814Swpaul grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER], 26511814Swpaul grp->ng_str[NG_DOM] == NULL ? "" : ",", 26611814Swpaul grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM], 26711814Swpaul lp->l_groupname); 26811814Swpaul#endif 26911814Swpaul } else { 27011814Swpaul spos = strsep(&pos, ", \t"); 27111814Swpaul if (parse_netgrp(spos)) 27211814Swpaul continue; 27311814Swpaul } 27411814Swpaul /* Watch for null pointer dereferences, dammit! */ 27511814Swpaul if (pos != NULL) 27611814Swpaul while (*pos == ' ' || *pos == ',' || *pos == '\t') 27711814Swpaul pos++; 27811814Swpaul } 27911814Swpaul return (0); 28011814Swpaul} 28111814Swpaul 28211814Swpaul/* 28311814Swpaul * Read the netgroup file and save lines until the line for the netgroup 28411814Swpaul * is found. Return 1 if eof is encountered. 28511814Swpaul */ 28611814Swpaulstatic struct linelist * 28790377Simpread_for_group(char *group) 28811814Swpaul{ 28990377Simp char *pos, *spos, *linep = NULL, *olinep = NULL; 29090377Simp int len, olen; 29111814Swpaul int cont; 29211814Swpaul struct linelist *lp; 29311814Swpaul char line[LINSIZ + 1]; 29420387Swpaul char *data = NULL; 29511814Swpaul 29611814Swpaul data = lookup (gtable, group); 29711814Swpaul sprintf(line, "%s %s", group, data); 29811814Swpaul pos = (char *)&line; 29911814Swpaul#ifdef CANT_HAPPEN 30011814Swpaul if (*pos == '#') 30111814Swpaul continue; 30211814Swpaul#endif 30311814Swpaul while (*pos == ' ' || *pos == '\t') 30411814Swpaul pos++; 30511814Swpaul spos = pos; 30611814Swpaul while (*pos != ' ' && *pos != '\t' && *pos != '\n' && 30711814Swpaul *pos != '\0') 30811814Swpaul pos++; 30911814Swpaul len = pos - spos; 31011814Swpaul while (*pos == ' ' || *pos == '\t') 31111814Swpaul pos++; 31211814Swpaul if (*pos != '\n' && *pos != '\0') { 31311814Swpaul lp = (struct linelist *)malloc(sizeof (*lp)); 31411814Swpaul lp->l_parsed = 0; 31511814Swpaul lp->l_groupname = (char *)malloc(len + 1); 31611814Swpaul bcopy(spos, lp->l_groupname, len); 31711814Swpaul *(lp->l_groupname + len) = '\0'; 31811814Swpaul len = strlen(pos); 31911814Swpaul olen = 0; 32011814Swpaul /* 32111814Swpaul * Loop around handling line continuations. 32211814Swpaul */ 32311814Swpaul do { 32411814Swpaul if (*(pos + len - 1) == '\n') 32511814Swpaul len--; 32611814Swpaul if (*(pos + len - 1) == '\\') { 32711814Swpaul len--; 32811814Swpaul cont = 1; 32911814Swpaul } else 33011814Swpaul cont = 0; 33111814Swpaul if (len > 0) { 33211814Swpaul linep = (char *)malloc(olen + len + 1); 33311814Swpaul if (olen > 0) { 33411814Swpaul bcopy(olinep, linep, olen); 33511814Swpaul free(olinep); 33611814Swpaul } 33711814Swpaul bcopy(pos, linep + olen, len); 33811814Swpaul olen += len; 33911814Swpaul *(linep + olen) = '\0'; 34011814Swpaul olinep = linep; 34111814Swpaul } 34211814Swpaul#ifdef CANT_HAPPEN 34311814Swpaul if (cont) { 34411814Swpaul if (fgets(line, LINSIZ, netf)) { 34511814Swpaul pos = line; 34611814Swpaul len = strlen(pos); 34711814Swpaul } else 34811814Swpaul cont = 0; 34911814Swpaul } 35011814Swpaul#endif 35111814Swpaul } while (cont); 35211814Swpaul lp->l_line = linep; 35311814Swpaul lp->l_next = linehead; 35411814Swpaul linehead = lp; 35511814Swpaul#ifdef CANT_HAPPEN 35611814Swpaul /* 35711814Swpaul * If this is the one we wanted, we are done. 35811814Swpaul */ 35911814Swpaul if (!strcmp(lp->l_groupname, group)) 36011814Swpaul#endif 36111814Swpaul return (lp); 36211814Swpaul } 36311814Swpaul return ((struct linelist *)0); 36411814Swpaul} 365