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