/* $NetBSD: lcl_ng.c,v 1.1.1.2 2012/09/09 16:07:54 christos Exp $ */
/*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-1999 by Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "Id: lcl_ng.c,v 1.3 2005/04/27 04:56:31 sra Exp ";
#endif
/* Imports */
#include "port_before.h"
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <resolv.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <irs.h>
#include <isc/memcluster.h>
#include "port_after.h"
#include "irs_p.h"
#include "lcl_p.h"
/* Definitions */
#define NG_HOST 0 /*%< Host name */
#define NG_USER 1 /*%< User name */
#define NG_DOM 2 /*%< and Domain name */
#define LINSIZ 1024 /*%< Length of netgroup file line */
/*
* XXX Warning XXX
* This code is a hack-and-slash special. It realy needs to be
* rewritten with things like strdup, and realloc in mind.
* More reasonable data structures would not be a bad thing.
*/
/*%
* Static Variables and functions used by setnetgrent(), getnetgrent() and
* endnetgrent().
*
* There are two linked lists:
* \li linelist is just used by setnetgrent() to parse the net group file via.
* parse_netgrp()
* \li netgrp is the list of entries for the current netgroup
*/
struct linelist {
struct linelist *l_next; /*%< Chain ptr. */
int l_parsed; /*%< Flag for cycles */
char * l_groupname; /*%< Name of netgroup */
char * l_line; /*%< Netgroup entrie(s) to be parsed */
};
struct ng_old_struct {
struct ng_old_struct *ng_next; /*%< Chain ptr */
char * ng_str[3]; /*%< Field pointers, see below */
};
struct pvt {
FILE *fp;
struct linelist *linehead;
struct ng_old_struct *nextgrp;
struct {
struct ng_old_struct *gr;
char *grname;
} grouphead;
};
/* Forward */
static void ng_rewind(struct irs_ng *, const char*);
static void ng_close(struct irs_ng *);
static int ng_next(struct irs_ng *, const char **,
const char **, const char **);
static int ng_test(struct irs_ng *, const char *,
const char *, const char *,
const char *);
static void ng_minimize(struct irs_ng *);
static int parse_netgrp(struct irs_ng *, const char*);
static struct linelist *read_for_group(struct irs_ng *, const char *);
static void freelists(struct irs_ng *);
/* Public */
struct irs_ng *
irs_lcl_ng(struct irs_acc *this) {
struct irs_ng *ng;
struct pvt *pvt;
UNUSED(this);
if (!(ng = memget(sizeof *ng))) {
errno = ENOMEM;
return (NULL);
}
memset(ng, 0x5e, sizeof *ng);
if (!(pvt = memget(sizeof *pvt))) {
memput(ng, sizeof *ng);
errno = ENOMEM;
return (NULL);
}
memset(pvt, 0, sizeof *pvt);
ng->private = pvt;
ng->close = ng_close;
ng->next = ng_next;
ng->test = ng_test;
ng->rewind = ng_rewind;
ng->minimize = ng_minimize;
return (ng);
}
/* Methods */
static void
ng_close(struct irs_ng *this) {
struct pvt *pvt = (struct pvt *)this->private;
if (pvt->fp != NULL)
fclose(pvt->fp);
freelists(this);
memput(pvt, sizeof *pvt);
memput(this, sizeof *this);
}
/*%
* Parse the netgroup file looking for the netgroup and build the list
* of netgrp structures. Let parse_netgrp() and read_for_group() do
* most of the work.
*/
static void
ng_rewind(struct irs_ng *this, const char *group) {
struct pvt *pvt = (struct pvt *)this->private;
if (pvt->fp != NULL && fseek(pvt->fp, SEEK_CUR, 0L) == -1) {
fclose(pvt->fp);
pvt->fp = NULL;
}
if (pvt->fp == NULL || pvt->grouphead.gr == NULL ||
strcmp(group, pvt->grouphead.grname)) {
freelists(this);
if (pvt->fp != NULL)
fclose(pvt->fp);
pvt->fp = fopen(_PATH_NETGROUP, "r");
if (pvt->fp != NULL) {
if (parse_netgrp(this, group))
freelists(this);
if (!(pvt->grouphead.grname = strdup(group)))
freelists(this);
fclose(pvt->fp);
pvt->fp = NULL;
}
}
pvt->nextgrp = pvt->grouphead.gr;
}
/*%
* Get the next netgroup off the list.
*/
static int
ng_next(struct irs_ng *this, const char **host, const char **user,
const char **domain)
{
struct pvt *pvt = (struct pvt *)this->private;
if (pvt->nextgrp) {
*host = pvt->nextgrp->ng_str[NG_HOST];
*user = pvt->nextgrp->ng_str[NG_USER];
*domain = pvt->nextgrp->ng_str[NG_DOM];
pvt->nextgrp = pvt->nextgrp->ng_next;
return (1);
}
return (0);
}
/*%
* Search for a match in a netgroup.
*/
static int
ng_test(struct irs_ng *this, const char *name,
const char *host, const char *user, const char *domain)
{
const char *ng_host, *ng_user, *ng_domain;
ng_rewind(this, name);
while (ng_next(this, &ng_host, &ng_user, &ng_domain))
if ((host == NULL || ng_host == NULL ||
!strcmp(host, ng_host)) &&
(user == NULL || ng_user == NULL ||
!strcmp(user, ng_user)) &&
(domain == NULL || ng_domain == NULL ||
!strcmp(domain, ng_domain))) {
freelists(this);
return (1);
}
freelists(this);
return (0);
}
static void
ng_minimize(struct irs_ng *this) {
struct pvt *pvt = (struct pvt *)this->private;
if (pvt->fp != NULL) {
(void)fclose(pvt->fp);
pvt->fp = NULL;
}
}
/* Private */
/*%
* endnetgrent() - cleanup
*/
static void
freelists(struct irs_ng *this) {
struct pvt *pvt = (struct pvt *)this->private;
struct linelist *lp, *olp;
struct ng_old_struct *gp, *ogp;
lp = pvt->linehead;
while (lp) {
olp = lp;
lp = lp->l_next;
free(olp->l_groupname);
free(olp->l_line);
free((char *)olp);
}
pvt->linehead = NULL;
if (pvt->grouphead.grname) {
free(pvt->grouphead.grname);
pvt->grouphead.grname = NULL;
}
gp = pvt->grouphead.gr;
while (gp) {
ogp = gp;
gp = gp->ng_next;
if (ogp->ng_str[NG_HOST])
free(ogp->ng_str[NG_HOST]);
if (ogp->ng_str[NG_USER])
free(ogp->ng_str[NG_USER]);
if (ogp->ng_str[NG_DOM])
free(ogp->ng_str[NG_DOM]);
free((char *)ogp);
}
pvt->grouphead.gr = NULL;
}
/*%
* Parse the netgroup file setting up the linked lists.
*/
static int
parse_netgrp(struct irs_ng *this, const char *group) {
struct pvt *pvt = (struct pvt *)this->private;
char *spos, *epos;
int len, strpos;
char *pos, *gpos;
struct ng_old_struct *grp;
struct linelist *lp = pvt->linehead;
/*
* First, see if the line has already been read in.
*/
while (lp) {
if (!strcmp(group, lp->l_groupname))
break;
lp = lp->l_next;
}
if (lp == NULL &&
(lp = read_for_group(this, group)) == NULL)
return (1);
if (lp->l_parsed) {
/*fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname);*/
return (1);
} else
lp->l_parsed = 1;
pos = lp->l_line;
while (*pos != '\0') {
if (*pos == '(') {
if (!(grp = malloc(sizeof (struct ng_old_struct)))) {
freelists(this);
errno = ENOMEM;
return (1);
}
memset(grp, 0, sizeof (struct ng_old_struct));
grp->ng_next = pvt->grouphead.gr;
pvt->grouphead.gr = grp;
pos++;
gpos = strsep(&pos, ")");
for (strpos = 0; strpos < 3; strpos++) {
if ((spos = strsep(&gpos, ","))) {
while (*spos == ' ' || *spos == '\t')
spos++;
if ((epos = strpbrk(spos, " \t"))) {
*epos = '\0';
len = epos - spos;
} else
len = strlen(spos);
if (len > 0) {
if(!(grp->ng_str[strpos]
= (char *)
malloc(len + 1))) {
freelists(this);
return (1);
}
memcpy(grp->ng_str[strpos],
spos,
len + 1);
}
} else
goto errout;
}
} else {
spos = strsep(&pos, ", \t");
if (spos != NULL && parse_netgrp(this, spos)) {
freelists(this);
return (1);
}
}
if (pos == NULL)
break;
while (*pos == ' ' || *pos == ',' || *pos == '\t')
pos++;
}
return (0);
errout:
/*fprintf(stderr, "Bad netgroup %s at ..%s\n", lp->l_groupname,
spos);*/
return (1);
}
/*%
* Read the netgroup file and save lines until the line for the netgroup
* is found. Return 1 if eof is encountered.
*/
static struct linelist *
read_for_group(struct irs_ng *this, const char *group) {
struct pvt *pvt = (struct pvt *)this->private;
char *pos, *spos, *linep = NULL, *olinep;
int len, olen, cont;
struct linelist *lp;
char line[LINSIZ + 1];
while (fgets(line, LINSIZ, pvt->fp) != NULL) {
pos = line;
if (*pos == '#')
continue;
while (*pos == ' ' || *pos == '\t')
pos++;
spos = pos;
while (*pos != ' ' && *pos != '\t' && *pos != '\n' &&
*pos != '\0')
pos++;
len = pos - spos;
while (*pos == ' ' || *pos == '\t')
pos++;
if (*pos != '\n' && *pos != '\0') {
if (!(lp = malloc(sizeof (*lp)))) {
freelists(this);
return (NULL);
}
lp->l_parsed = 0;
if (!(lp->l_groupname = malloc(len + 1))) {
free(lp);
freelists(this);
return (NULL);
}
memcpy(lp->l_groupname, spos, len);
*(lp->l_groupname + len) = '\0';
len = strlen(pos);
olen = 0;
olinep = NULL;
/*
* Loop around handling line continuations.
*/
do {
if (*(pos + len - 1) == '\n')
len--;
if (*(pos + len - 1) == '\\') {
len--;
cont = 1;
} else
cont = 0;
if (len > 0) {
if (!(linep = malloc(olen + len + 1))){
if (olen > 0)
free(olinep);
free(lp->l_groupname);
free(lp);
freelists(this);
errno = ENOMEM;
return (NULL);
}
if (olen > 0) {
memcpy(linep, olinep, olen);
free(olinep);
}
memcpy(linep + olen, pos, len);
olen += len;
*(linep + olen) = '\0';
olinep = linep;
}
if (cont) {
if (fgets(line, LINSIZ, pvt->fp)) {
pos = line;
len = strlen(pos);
} else
cont = 0;
}
} while (cont);
lp->l_line = linep;
lp->l_next = pvt->linehead;
pvt->linehead = lp;
/*
* If this is the one we wanted, we are done.
*/
if (!strcmp(lp->l_groupname, group))
return (lp);
}
}
return (NULL);
}
/*! \file */