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