Path: blob/main/libexec/revnetgroup/parse_netgroup.c
34822 views
/*-1* SPDX-License-Identifier: BSD-3-Clause2*3* Copyright (c) 1992, 19934* The Regents of the University of California. All rights reserved.5*6* This code is derived from software contributed to Berkeley by7* Rick Macklem at The University of Guelph.8*9* Redistribution and use in source and binary forms, with or without10* modification, are permitted provided that the following conditions11* are met:12* 1. Redistributions of source code must retain the above copyright13* notice, this list of conditions and the following disclaimer.14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17* 3. Neither the name of the University nor the names of its contributors18* may be used to endorse or promote products derived from this software19* without specific prior written permission.20*21* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND22* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE23* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE24* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE25* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL26* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS27* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)28* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT29* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY30* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF31* SUCH DAMAGE.32*/3334/*35* This is a specially hacked-up version of getnetgrent.c used to parse36* data from the stored hash table of netgroup info rather than from a37* file. It's used mainly for the parse_netgroup() function. All the YP38* stuff and file support has been stripped out since it isn't needed.39*/4041#include <stdio.h>42#include <string.h>43#include <strings.h>44#include <stdlib.h>45#include <unistd.h>46#include "hash.h"4748/*49* Static Variables and functions used by setnetgrent(), getnetgrent() and50* __endnetgrent().51* There are two linked lists:52* - linelist is just used by setnetgrent() to parse the net group file via.53* parse_netgrp()54* - netgrp is the list of entries for the current netgroup55*/56struct linelist {57struct linelist *l_next; /* Chain ptr. */58int l_parsed; /* Flag for cycles */59char *l_groupname; /* Name of netgroup */60char *l_line; /* Netgroup entrie(s) to be parsed */61};6263struct netgrp {64struct netgrp *ng_next; /* Chain ptr */65char *ng_str[3]; /* Field pointers, see below */66};67#define NG_HOST 0 /* Host name */68#define NG_USER 1 /* User name */69#define NG_DOM 2 /* and Domain name */7071static struct linelist *linehead = (struct linelist *)0;72static struct netgrp *nextgrp = (struct netgrp *)0;73static struct {74struct netgrp *gr;75char *grname;76} grouphead = {77(struct netgrp *)0,78(char *)0,79};80static int parse_netgrp(char *group);81static struct linelist *read_for_group(char *group);82extern struct group_entry *gtable[];8384/*85* setnetgrent()86* Parse the netgroup file looking for the netgroup and build the list87* of netgrp structures. Let parse_netgrp() and read_for_group() do88* most of the work.89*/90void91__setnetgrent(char *group)92{93/* Sanity check */9495if (group == NULL || !strlen(group))96return;9798if (grouphead.gr == (struct netgrp *)0 ||99strcmp(group, grouphead.grname)) {100__endnetgrent();101if (parse_netgrp(group))102__endnetgrent();103else {104grouphead.grname = (char *)105malloc(strlen(group) + 1);106strcpy(grouphead.grname, group);107}108}109nextgrp = grouphead.gr;110}111112/*113* Get the next netgroup off the list.114*/115int116__getnetgrent(char **hostp, char **userp, char **domp)117{118if (nextgrp) {119*hostp = nextgrp->ng_str[NG_HOST];120*userp = nextgrp->ng_str[NG_USER];121*domp = nextgrp->ng_str[NG_DOM];122nextgrp = nextgrp->ng_next;123return (1);124}125return (0);126}127128/*129* __endnetgrent() - cleanup130*/131void132__endnetgrent(void)133{134struct linelist *lp, *olp;135struct netgrp *gp, *ogp;136137lp = linehead;138while (lp) {139olp = lp;140lp = lp->l_next;141free(olp->l_groupname);142free(olp->l_line);143free((char *)olp);144}145linehead = (struct linelist *)0;146if (grouphead.grname) {147free(grouphead.grname);148grouphead.grname = (char *)0;149}150gp = grouphead.gr;151while (gp) {152ogp = gp;153gp = gp->ng_next;154if (ogp->ng_str[NG_HOST])155free(ogp->ng_str[NG_HOST]);156if (ogp->ng_str[NG_USER])157free(ogp->ng_str[NG_USER]);158if (ogp->ng_str[NG_DOM])159free(ogp->ng_str[NG_DOM]);160free((char *)ogp);161}162grouphead.gr = (struct netgrp *)0;163}164165/*166* Parse the netgroup file setting up the linked lists.167*/168static int169parse_netgrp(char *group)170{171char *spos, *epos;172int len, strpos;173#ifdef DEBUG174int fields;175#endif176char *pos, *gpos;177struct netgrp *grp;178struct linelist *lp = linehead;179180/*181* First, see if the line has already been read in.182*/183while (lp) {184if (!strcmp(group, lp->l_groupname))185break;186lp = lp->l_next;187}188if (lp == (struct linelist *)0 &&189(lp = read_for_group(group)) == (struct linelist *)0)190return (1);191if (lp->l_parsed) {192#ifdef DEBUG193/*194* This error message is largely superfluous since the195* code handles the error condition successfully, and196* spewing it out from inside libc can actually hose197* certain programs.198*/199warnx("cycle in netgroup %s", lp->l_groupname);200#endif201return (1);202} else203lp->l_parsed = 1;204pos = lp->l_line;205/* Watch for null pointer dereferences, dammit! */206while (pos != NULL && *pos != '\0') {207if (*pos == '(') {208grp = (struct netgrp *)malloc(sizeof (struct netgrp));209bzero((char *)grp, sizeof (struct netgrp));210grp->ng_next = grouphead.gr;211grouphead.gr = grp;212pos++;213gpos = strsep(&pos, ")");214#ifdef DEBUG215fields = 0;216#endif217for (strpos = 0; strpos < 3; strpos++) {218if ((spos = strsep(&gpos, ","))) {219#ifdef DEBUG220fields++;221#endif222while (*spos == ' ' || *spos == '\t')223spos++;224if ((epos = strpbrk(spos, " \t"))) {225*epos = '\0';226len = epos - spos;227} else228len = strlen(spos);229if (len > 0) {230grp->ng_str[strpos] = (char *)231malloc(len + 1);232bcopy(spos, grp->ng_str[strpos],233len + 1);234}235} else {236/*237* All other systems I've tested238* return NULL for empty netgroup239* fields. It's up to user programs240* to handle the NULLs appropriately.241*/242grp->ng_str[strpos] = NULL;243}244}245#ifdef DEBUG246/*247* Note: on other platforms, malformed netgroup248* entries are not normally flagged. While we249* can catch bad entries and report them, we should250* stay silent by default for compatibility's sake.251*/252if (fields < 3)253warnx("bad entry (%s%s%s%s%s) in netgroup \"%s\"",254grp->ng_str[NG_HOST] == NULL ? "" : grp->ng_str[NG_HOST],255grp->ng_str[NG_USER] == NULL ? "" : ",",256grp->ng_str[NG_USER] == NULL ? "" : grp->ng_str[NG_USER],257grp->ng_str[NG_DOM] == NULL ? "" : ",",258grp->ng_str[NG_DOM] == NULL ? "" : grp->ng_str[NG_DOM],259lp->l_groupname);260#endif261} else {262spos = strsep(&pos, ", \t");263if (parse_netgrp(spos))264continue;265}266/* Watch for null pointer dereferences, dammit! */267if (pos != NULL)268while (*pos == ' ' || *pos == ',' || *pos == '\t')269pos++;270}271return (0);272}273274/*275* Read the netgroup file and save lines until the line for the netgroup276* is found. Return 1 if eof is encountered.277*/278static struct linelist *279read_for_group(char *group)280{281char *pos, *spos, *linep = NULL, *olinep = NULL;282int len, olen;283int cont;284struct linelist *lp;285char line[LINSIZ + 1];286char *data = NULL;287288data = lookup (gtable, group);289sprintf(line, "%s %s", group, data);290pos = (char *)&line;291#ifdef CANT_HAPPEN292if (*pos == '#')293continue;294#endif295while (*pos == ' ' || *pos == '\t')296pos++;297spos = pos;298while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&299*pos != '\0')300pos++;301len = pos - spos;302while (*pos == ' ' || *pos == '\t')303pos++;304if (*pos != '\n' && *pos != '\0') {305lp = (struct linelist *)malloc(sizeof (*lp));306lp->l_parsed = 0;307lp->l_groupname = (char *)malloc(len + 1);308bcopy(spos, lp->l_groupname, len);309*(lp->l_groupname + len) = '\0';310len = strlen(pos);311olen = 0;312/*313* Loop around handling line continuations.314*/315do {316if (*(pos + len - 1) == '\n')317len--;318if (*(pos + len - 1) == '\\') {319len--;320cont = 1;321} else322cont = 0;323if (len > 0) {324linep = (char *)malloc(olen + len + 1);325if (olen > 0) {326bcopy(olinep, linep, olen);327free(olinep);328}329bcopy(pos, linep + olen, len);330olen += len;331*(linep + olen) = '\0';332olinep = linep;333}334#ifdef CANT_HAPPEN335if (cont) {336if (fgets(line, LINSIZ, netf)) {337pos = line;338len = strlen(pos);339} else340cont = 0;341}342#endif343} while (cont);344lp->l_line = linep;345lp->l_next = linehead;346linehead = lp;347#ifdef CANT_HAPPEN348/*349* If this is the one we wanted, we are done.350*/351if (!strcmp(lp->l_groupname, group))352#endif353return (lp);354}355return ((struct linelist *)0);356}357358359