home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.ee.lbl.gov
/
2014.05.ftp.ee.lbl.gov.tar
/
ftp.ee.lbl.gov
/
acld-1.11.tar.gz
/
acld-1.11.tar
/
acld-1.11
/
cf.c
< prev
next >
Wrap
C/C++ Source or Header
|
2012-02-07
|
21KB
|
863 lines
/*
* Copyright (c) 2002, 2003, 2004, 2006, 2008, 2009, 2010, 2011, 2012
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that: (1) source code distributions
* retain the above copyright notice and this paragraph in its entirety, (2)
* distributions including binary code include the above copyright notice and
* this paragraph in its entirety in the documentation or other materials
* provided with the distribution, and (3) all advertising materials mentioning
* features or use of this software display the following acknowledgement:
* ``This product includes software developed by the University of California,
* Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
* the University nor the names of its contributors may be used to endorse
* or promote products derived from this software without specific prior
* written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
static const char rcsid[] =
"@(#) $Id: cf.c 806 2012-02-08 03:40:06Z leres $ (LBL)";
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <syslog.h>
#include "acld.h"
#include "cf.h"
/* Locals */
static int errors;
/* Forwards */
static void acllimitadd(struct cf *, const char *);
static void acllimitfree(struct acllimit *);
static void attrlistadd(struct cf *, const char *);
static void attrlistfree(struct attrlist *);
static void intlistadd(struct cf *, const char *);
static void intlistfree(struct intlist *);
static int readcf(const char *, struct cf *, int);
/* Open, read and parse one config file */
static int
readcf(const char *fn, struct cf *cf, int mustexist)
{
int n, errs, *ip, *ip2;
struct addr *a;
char *cp, *cp2, **pp;
const char *p;
time_t t;
FILE *f;
struct stat sbuf;
char buf[1024];
char at[1024];
errs = 0;
f = fopen(fn, "r");
if (f == NULL) {
if (mustexist) {
lg(LOG_ERR, "readcf: fopen %s: %s",
fn, strerror(errno));
++errs;
}
return (errs);
}
/* Get the config file mod time */
if (fstat(fileno(f), &sbuf) >= 0) {
t = (sbuf.st_mtime > sbuf.st_ctime) ?
sbuf.st_mtime : sbuf.st_ctime;
if (cf->c_time < t)
cf->c_time = t;
} else {
lg(LOG_ERR, "readcf: fstat %s: %s", fn, strerror(errno));
++errs;
}
n = 0;
while (fgets(buf, sizeof(buf), f) != NULL) {
++n;
/* Eat comments */
cp = strchr(buf, '#');
if (cp)
*cp = '\0';
/* Eat trailing whitesapce */
cp = buf + strlen(buf) - 1;
while (cp >= buf && isspace((int)*cp))
*cp-- = '\0';
cp = buf;
/* Skip blank lines */
if (*cp == '\n' || *cp == '\0')
continue;
/* Get command */
cp2 = cp;
while (!isspace((int)*cp) && *cp != '\0')
++cp;
*cp++ = '\0';
(void)sprintf(at, "%s:%d", fn, n);
/* Find start of next keyword */
while (isspace((int)*cp))
++cp;
/* Quoted one line commands */
if ((pp = &cf->c_cuser, strcasecmp(cp2, "cuser") == 0) ||
#ifdef HAVE_CFORCE
(pp = &cf->c_cforceaddr,
strcasecmp(cp2, "cforceaddr") == 0) ||
(pp = &cf->c_cforcedata,
strcasecmp(cp2, "cforcedata") == 0) ||
#endif
(pp = &cf->c_cpass1, strcasecmp(cp2, "cpass1") == 0) ||
(pp = &cf->c_cpass2, strcasecmp(cp2, "cpass2") == 0) ||
(pp = &cf->c_epass1, strcasecmp(cp2, "epass1") == 0) ||
(pp = &cf->c_epass2, strcasecmp(cp2, "epass2") == 0) ||
(pp = &cf->c_euser, strcasecmp(cp2, "euser") == 0) ||
(pp = &cf->c_expect, strcasecmp(cp2, "expect") == 0) ||
(pp = &cf->c_id, strcasecmp(cp2, "id") == 0) ||
(pp = &cf->c_router, strcasecmp(cp2, "router") == 0) ||
(pp = &cf->c_script, strcasecmp(cp2, "script") == 0) ||
(pp = &cf->c_whitelistfn,
strcasecmp(cp2, "whitelist") == 0)) {
if (*cp++ != '"') {
lg(LOG_ERR, "%s missing leading double quote",
at);
++errors;
continue;
}
if (*pp != NULL) {
lg(LOG_ERR, "%s only one \"%s\" is allowed",
at, cp2);
++errors;
continue;
}
*pp = strsave(cp);
cp = *pp;
cp2 = cp + strlen(cp) - 1;
if (cp > cp2 || *cp2 != '"') {
lg(LOG_ERR, "%s missing trailing double quote",
at);
++errors;
free(*pp);
*pp = NULL;
continue;
}
*cp2 = '\0';
continue;
}
/* Commands with numeric arguments */
if ((ip = &cf->c_ayt_secs, strcasecmp(cp2, "ayt_secs") == 0) ||
(ip = &cf->c_incrseq, strcasecmp(cp2, "incrseq") == 0) ||
(ip = &cf->c_ipv4_maxwidth,
strcasecmp(cp2, "ipv4_maxwidth") == 0) ||
(ip = &cf->c_ipv6_maxwidth,
strcasecmp(cp2, "ipv6_maxwidth") == 0) ||
(ip = &cf->c_login_secs,
strcasecmp(cp2, "login_secs") == 0) ||
(ip = &cf->c_nullzeromax,
strcasecmp(cp2, "nullzeromax") == 0) ||
(ip = &cf->c_maxseq, strcasecmp(cp2, "maxseq") == 0) ||
(ip = &cf->c_port, strcasecmp(cp2, "port") == 0) ||
#ifdef HAVE_BROCCOLI
(ip = &cf->c_portbro, strcasecmp(cp2, "portbro") == 0) ||
#endif
#ifdef HAVE_CFORCE
(ip = &cf->c_portcforce,
strcasecmp(cp2, "portcforce") == 0) ||
#endif
(ip = &cf->c_portro, strcasecmp(cp2, "portro") == 0) ||
(ip = &cf->c_portweb, strcasecmp(cp2, "portweb") == 0) ||
(ip = &cf->c_select_secs,
strcasecmp(cp2, "select_secs") == 0) ||
(ip = &cf->c_sync_secs,
strcasecmp(cp2, "sync_secs") == 0)) {
*ip = atoi(cp);
if (*cp == '-' || *cp == '+')
++cp;
while (isdigit((int)*cp))
++cp;
while (isspace((int)*cp))
++cp;
if (*cp != '\0') {
lg(LOG_ERR, "%s trailing garbage (%s)", at, cp);
++errors;
}
continue;
}
/* Commands with two numeric arguments */
if ((ip = &cf->c_lowseq, ip2 = &cf->c_highseq,
strcasecmp(cp2, "seqrange") == 0) ||
(ip = &cf->c_lowportseq, ip2 = &cf->c_highportseq,
strcasecmp(cp2, "portseqrange") == 0) ||
(ip = &cf->c_lowpermithostportseq,
ip2 = &cf->c_highpermithostportseq,
strcasecmp(cp2, "permithostportseqrange") == 0)) {
/* Low value */
*ip = atoi(cp);
if (*cp == '-' || *cp == '+')
++cp;
if (!isdigit((int)*cp)) {
lg(LOG_ERR, "%s missing low %s", at, cp2);
++errors;
}
while (isdigit((int)*cp))
++cp;
if (!isspace((int)*cp)) {
lg(LOG_ERR, "%s missing %s whitespace",
at, cp2);
++errors;
}
while (isspace((int)*cp))
++cp;
/* High value */
*ip2 = atoi(cp);
if (*cp == '-' || *cp == '+')
++cp;
if (!isdigit((int)*cp)) {
lg(LOG_ERR, "%s missing high %s", at, cp2);
++errors;
}
while (isdigit((int)*cp))
++cp;
while (isspace((int)*cp))
++cp;
if (*cp != '\0') {
lg(LOG_ERR, "%s %s trailing garbage", at, cp2);
++errors;
}
continue;
}
/* Commands with ip address arguments */
if ((a = &cf->c_bindaddr, strcasecmp(cp2, "bindaddr") == 0)
#ifdef HAVE_BROCCOLI
|| (a = &cf->c_broaddr, strcasecmp(cp2, "broaddr") == 0)
#endif
) {
p = extractaddr(cp, NULL, a);
if (p != NULL) {
lg(LOG_ERR, "%s bogus ip address: %s", at, p);
++errors;
}
continue;
}
/* ACL limits */
if (strcasecmp(cp2, "limit") == 0) {
acllimitadd(cf, cp);
continue;
}
/* ACLs */
if (strcasecmp(cp2, "acl") == 0) {
acladdacllist(cf, cp);
continue;
}
/* Attributes */
if (strcasecmp(cp2, "attr") == 0) {
attrlistadd(cf, cp);
continue;
}
/* Interfaces */
if (strcasecmp(cp2, "interface") == 0) {
intlistadd(cf, cp);
continue;
}
/* Null zero nets */
if (strcasecmp(cp2, "nullzeronet") == 0) {
if (!nullzeronetadd(cf, cp))
++errors;
continue;
}
/* nets_log() syslog facility */
if (strcasecmp(cp2, "netsfac") == 0) {
cf->c_netsfac = str2val(syslog2str, cp);
if (cf->c_netsfac < 0) {
lg(LOG_ERR, "error: bogus netpri value \"%s\"",
cp);
++errors;
}
continue;
}
/* Bad commands */
lg(LOG_ERR, "%s unknown command \"%s\"", at, cp2);
++errors;
}
(void)fclose(f);
return (errs);
}
static void
acllimitadd(struct cf *cf, const char *str)
{
long v;
int an;
char **av;
char *cp;
struct acllimit *alp;
v = strtol(str, &cp, 10);
if (!isspace(*cp)) {
lg(LOG_ERR, "acllimitadd: trailing garbage (%s)", str);
++errors;
}
if (v <= 0) {
lg(LOG_ERR, "acllimitadd: bad value (%ld)", v);
++errors;
}
++cp;
while (isspace(*cp))
++cp;
/* Make a list of ACL names */
an = makeargv(cp, &av);
if (an <= 0) {
lg(LOG_ERR, "acllimitadd: missing ACL name(s) \"%s\"", str);
return;
}
DYNARRAY(cf->c_acllimit, cf->c_acllimitlen, &cf->c_acllimitsize,
sizeof(*cf->c_acllimit), 8, 8, "cf acllimit");
alp = cf->c_acllimit + cf->c_acllimitlen;
++cf->c_acllimitlen;
alp->a_maxseq = v;
alp->a_nacls = an;
alp->a_acls = av;
}
static void
acllimitfree(struct acllimit *alp)
{
if (alp->a_acls != NULL) {
freeargv(alp->a_acls);
alp->a_acls = NULL;
alp->a_nacls = 0;
}
}
static void
attrlistadd(struct cf *cf, const char *str)
{
struct attrlist *atp, *atp2;
int an, i;
char **av;
an = makeargv(str, &av);
if (an < 2) {
lg(LOG_ERR, "attrlistadd: wrong number of args: \"%s\"", str);
freeargv(av);
return;
}
/* Find access list */
atp = NULL;
for (i = 0, atp2 = cf->c_attrlist; i < cf->c_attrlistlen; ++i, ++atp2)
if (strcmp(av[0], atp2->a_acl) == 0) {
atp = atp2;
break;
}
if (atp == NULL) {
/* New entry */
DYNARRAY(cf->c_attrlist, cf->c_attrlistlen, &cf->c_attrlistsize,
sizeof(*cf->c_attrlist), 8, 8, "cf attrlist");
atp = cf->c_attrlist + cf->c_attrlistlen;
++cf->c_attrlistlen;
atp->a_acl = strsave(av[0]);
}
for (i = 1; i < an; ++i) {
if (strcmp(av[i], "ipv6") == 0) {
atp->a_attr |= ATTR_IPV6;
continue;
}
lg(LOG_ERR, "attrlistadd: unknown attr \"%s\"", av[i]);
++errors;
}
freeargv(av);
}
static void
attrlistfree(struct attrlist *atp)
{
if (atp->a_acl != NULL) {
free(atp->a_acl);
atp->a_acl = NULL;
}
}
struct cf *
parsecf(const char *fn)
{
int i, j, seqrange, portseqrange, permithostportseqrange;
char *cp;
const char *p;
struct cf *cf;
struct acllimit *alp;
struct attrlist *atp;
struct acllist *ap;
struct intlist *ip;
cf = (struct cf *)new(1, sizeof(*cf), "parsecf cf");
/* Defaults */
cf->c_ayt_secs = AYT_SECS;
cf->c_login_secs = LOGIN_SECS;
cf->c_select_secs = SELECT_SECS;
cf->c_sync_secs = SYNC_SECS;
cf->c_incrseq = 1;
cf->c_lowseq = -1;
cf->c_highseq = -1;
cf->c_lowportseq = -1;
cf->c_highportseq = -1;
cf->c_lowpermithostportseq = -1;
cf->c_highpermithostportseq = -1;
cf->c_ipv4_maxwidth = DEFAULT_IPV4_WIDTH;
cf->c_ipv6_maxwidth = DEFAULT_IPV6_WIDTH;
#ifdef HAVE_CFORCE
cf->c_cforcedata = "/var/run/cforce.data";
#endif
p = extractaddr("127.0.0.1", NULL, &cf->c_bindaddr);
if (p != NULL)
abort();
errors += readcf(fn, cf, 1);
if ((cp = "acl", cf->c_acllist == NULL) ||
(cp = "interface", cf->c_intlist == NULL)) {
lg(LOG_ERR, "error: \"%s\" missing but required", cp);
++errors;
}
#ifdef HAVE_CFORCE
if (cf->c_router != NULL) {
#endif
/*
* Without cForce:
* Need expect+router+script
*/
if ((cp = "expect", cf->c_expect == NULL) ||
(cp = "script", cf->c_script == NULL) ||
(cp = "router", cf->c_router == NULL)) {
lg(LOG_ERR, "error: \"%s\" missing but required", cp);
++errors;
}
#ifdef HAVE_CFORCE
} else {
/*
* With cForce:
* Need either expect+router+script or cforceaddr+portcforce
*/
i = 0;
if (cf->c_cforceaddr != NULL)
++i;
if (cf->c_portcforce > 0)
++i;
j = 0;
if (cf->c_expect != NULL)
++j;
if (cf->c_script != NULL)
++j;
if (cf->c_script != NULL)
++j;
if (!((i == 2 && j == 0) || (i == 0 && j == 3))) {
lg(LOG_ERR,
"error: Only \"expect\", \"router\" and \"script\""
" or \"cforceaddr\" and \"portcforce\" allowed");
++errors;
}
/* cForce: sequence numbers are assigned by the appliance */
if (cf->c_lowseq >= 0 || cf->c_highseq >= 0) {
lg(LOG_ERR, "error: cForce does not use seqrange");
++errors;
}
/* cForce: nullzero routes are not support */
if (cf->c_nullzeronets != NULL || cf->c_nullzeromax != 0) {
lg(LOG_ERR,
"error: cForce does not support nullzero routes");
++errors;
}
if (!cf->c_incrseq) {
lg(LOG_ERR, "error: cForce does not use incrseq");
++errors;
}
if (!cf->c_sync_secs > 0) {
lg(LOG_ERR, "error: cForce does not use sync_secs");
++errors;
}
}
#endif
if (cf->c_ipv4_maxwidth < MAX_IPV4_WIDTH) {
lg(LOG_ERR, "error: \"ipv4_maxwidth\" must > %d",
MAX_IPV4_WIDTH);
++errors;
} else if (cf->c_ipv4_maxwidth > 32) {
lg(LOG_ERR, "error: \"ipv4_maxwidth\" must <= 32");
++errors;
}
if (cf->c_ipv6_maxwidth < MAX_IPV6_WIDTH) {
lg(LOG_ERR, "error: \"ipv6_maxwidth\" must > %d",
MAX_IPV6_WIDTH);
++errors;
} else if (cf->c_ipv6_maxwidth > 128) {
lg(LOG_ERR, "error: \"ipv6_maxwidth\" must <= 128");
++errors;
}
if ((cp = "login_secs", cf->c_login_secs <= 0) ||
(cp = "port", cf->c_port <= 0) ||
(cp = "select_secs", cf->c_select_secs <= 0)) {
lg(LOG_ERR, "error: \"%s\" must be non-zero", cp);
++errors;
}
if ((cp = "port", !VALID_PORT(cf->c_port)) ||
(cp = "portro", !VALID_PORT(cf->c_portro) && cf->c_portro != 0) ||
(cp = "portweb", !VALID_PORT(cf->c_portweb) &&
cf->c_portweb != 0)) {
lg(LOG_ERR, "error: \"%s\" is out of range", cp);
++errors;
}
if ((cf->c_portro > 0 && (cp = "portro", cf->c_portro == cf->c_port)) ||
(cf->c_portweb > 0 && (cp = "portweb",
cf->c_portweb == cf->c_port))) {
lg(LOG_ERR, "error: \"%s\" can't be the same as \"port\"", cp);
++errors;
}
if (cf->c_portro > 0 && cf->c_portweb > 0 &&
cf->c_portro == cf->c_portweb) {
lg(LOG_ERR,
"error: \"portro\" can't be the same as \"portweb\"");
++errors;
}
seqrange = (cf->c_lowseq >= 0 || cf->c_highseq >= 0);
portseqrange = (cf->c_lowportseq > 0 || cf->c_highportseq > 0);
permithostportseqrange = (cf->c_lowpermithostportseq >= 0 ||
cf->c_highpermithostportseq >= 0);
#define IN_SEQRANGE(n) ((n) >= cf->c_lowseq && (n) <= cf->c_highseq)
#define IN_PORTSEQRANGE(n) ((n) >= cf->c_lowportseq && (n) <= cf->c_highportseq)
#define IN_PERMITHOSTPORTSEQRANGE(n) \
((n) >= cf->c_lowpermithostportseq && (n) <= cf->c_highpermithostportseq)
if (seqrange) {
if (cf->c_lowseq >= cf->c_highseq) {
lg(LOG_ERR, "error: \"seqrange\" must be increasing");
++errors;
}
if (portseqrange && (IN_SEQRANGE(cf->c_lowportseq) ||
IN_SEQRANGE(cf->c_highportseq))) {
lg(LOG_ERR,
"error: \"seqrange\" and \"portseqrange\" overlap");
++errors;
}
}
if (portseqrange) {
if (cf->c_lowportseq >= cf->c_highportseq) {
lg(LOG_ERR,
"error: \"portseqrange\" must be increasing");
++errors;
}
if (permithostportseqrange &&
(IN_PERMITHOSTPORTSEQRANGE(cf->c_lowseq) ||
IN_PERMITHOSTPORTSEQRANGE(cf->c_highseq))) {
lg(LOG_ERR, "error: \"portseqrange\" and"
" \"permithostportseqrange\" overlap");
++errors;
}
}
if (permithostportseqrange) {
if (cf->c_lowpermithostportseq >= cf->c_highpermithostportseq) {
lg(LOG_ERR, "error: \"permithostportseqrange\" must"
" be increasing");
++errors;
}
if (seqrange &&
(IN_SEQRANGE(cf->c_lowpermithostportseq) ||
IN_SEQRANGE(cf->c_highpermithostportseq))) {
lg(LOG_ERR, "error: \"seqrange\" and"
" \"permithostportseqrange\" overlap");
++errors;
}
}
#define GOOD_PORT(p) ((p) > 0 && (p) <= 2 << 16)
if (cf->c_port != 0 && !GOOD_PORT(cf->c_port)) {
lg(LOG_ERR, "error: bad \"port\" port value");
++errors;
}
if (cf->c_portro != 0 && !GOOD_PORT(cf->c_portro)) {
lg(LOG_ERR, "error: bad \"portro\" port value");
++errors;
}
if (cf->c_portweb != 0 && !GOOD_PORT(cf->c_portweb)) {
lg(LOG_ERR, "error: bad \"portweb\" port value");
++errors;
}
#ifdef HAVE_BROCCOLI
if (cf->c_portbro != 0 && !GOOD_PORT(cf->c_portbro)) {
lg(LOG_ERR, "error: bad \"portbro\" port value");
++errors;
}
#endif
#define ESCAPESTR(str) { \
cp = str; \
str = strsave(escapestr(cp)); \
if (cp != NULL) \
free(cp); \
}
ESCAPESTR(cf->c_cuser);
ESCAPESTR(cf->c_cpass1);
ESCAPESTR(cf->c_cpass2);
ESCAPESTR(cf->c_euser);
ESCAPESTR(cf->c_epass1);
ESCAPESTR(cf->c_epass2);
/* Hook interfaces into acls */
for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
for (j = 0, ip = cf->c_intlist; j < cf->c_intlistlen; ++j, ++ip)
if (strcmp(ap->name, ip->i_acl) == 0) {
ap->intlist = ip;
break;
}
for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
if (ap->intlist == NULL) {
lg(LOG_ERR, "error: ACL %s missing interface",
ap->name);
++errors;
}
/* Hook ACL limits into ACLs */
for (i = 0, alp = cf->c_acllimit; i < cf->c_acllimitlen; ++i, ++alp)
for (j = 0; j < alp->a_nacls; ++j) {
ap = aclfindlistbyname(cf, alp->a_acls[j]);
if (ap == NULL) {
lg(LOG_ERR, "error: ACL %s not defined",
alp->a_acls[j]);
++errors;
continue;
}
if (ap->limitp != NULL) {
lg(LOG_ERR, "error: ACL %s already limited",
ap->name);
++errors;
continue;
}
ap->limitp = alp;
}
/* Check for limits on undefined ACLs */
for (i = 0, atp = cf->c_attrlist; i < cf->c_attrlistlen; ++i, ++atp) {
ap = aclfindlistbyname(cf, atp->a_acl);
if (ap == NULL) {
lg(LOG_ERR, "error: ACL %s not defined", atp->a_acl);
++errors;
}
}
/* If any ACLs are limited, check for unlimited */
if (cf->c_acllimitlen > 0) {
for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
if (ap->limitp == NULL) {
lg(LOG_ERR, "error: ACL %s is unlimited",
ap->name);
++errors;
}
}
/* Whitelist */
whitelistread(cf);
#ifdef HAVE_BROCCOLI
/* Default broaddr to bindaddr */
if (cf->c_portbro != 0 && cf->c_broaddr.family == 0)
cf->c_broaddr = cf->c_bindaddr;
#endif
if (errors > 0)
exit(EX_CONFIG);
return (cf);
}
static void
freeone(void *p)
{
if (p != NULL)
free(p);
}
void
freecf(struct cf *cf)
{
int i;
struct acllist *ap;
struct acllimit *alp;
struct attrlist *atp;
struct intlist *ip;
/* Single line options */
#ifdef HAVE_CFORCE
freeone(cf->c_cforceaddr);
#endif
freeone(cf->c_cpass1);
freeone(cf->c_cpass2);
freeone(cf->c_epass1);
freeone(cf->c_epass2);
freeone(cf->c_expect);
freeone(cf->c_router);
freeone(cf->c_script);
/* ACL limits */
for (i = 0, alp = cf->c_acllimit; i < cf->c_acllimitlen; ++i, ++alp)
acllimitfree(alp);
cf->c_acllimit = NULL;
cf->c_acllimitlen = 0;
cf->c_acllimitsize = 0;
/* ACLs */
for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
aclfree(ap);
cf->c_acllist = NULL;
cf->c_acllistlen = 0;
cf->c_acllistsize = 0;
/* Attributes */
for (i = 0, atp = cf->c_attrlist; i < cf->c_attrlistlen; ++i, ++atp)
attrlistfree(atp);
cf->c_attrlist = NULL;
cf->c_attrlistlen = 0;
cf->c_attrlistsize = 0;
/* Interfaces */
for (i = 0, ip = cf->c_intlist; i < cf->c_intlistlen; ++i, ++ip)
intlistfree(ip);
cf->c_intlist = NULL;
cf->c_intlistlen = 0;
cf->c_intlistsize = 0;
/* Null zero routes */
if (cf->c_nullzeronets != NULL) {
free(cf->c_nullzeronets);
cf->c_nullzeronets = NULL;
cf->c_nullzeronetslen = 0;
cf->c_nullzeronetssize = 0;
}
/* Whitelist */
if (cf->c_whitelist != NULL) {
free(cf->c_whitelist);
cf->c_whitelist = NULL;
cf->c_whitelistlen = 0;
cf->c_whitelistsize = 0;
}
if (cf->c_whitelistfn != NULL) {
free(cf->c_whitelistfn);
cf->c_whitelistfn = NULL;
}
free(cf);
}
static void
intlistadd(struct cf *cf, const char *str)
{
struct intlist *ip;
int an, i;
char **av;
char buf[1024];
char *cp;
size_t size, len;
an = makeargv(str, &av);
if (an < 2) {
lg(LOG_ERR, "intlistadd: wrong number of args: \"%s\"", str);
freeargv(av);
return;
}
DYNARRAY(cf->c_intlist, cf->c_intlistlen, &cf->c_intlistsize,
sizeof(*cf->c_intlist), 8, 8, "cf intlist");
ip = cf->c_intlist + cf->c_intlistlen;
++cf->c_intlistlen;
ip->i_acl = strsave(av[an - 1]);
size = sizeof(buf);
cp = buf;
for (i = 0; i < an - 1; ++i) {
(void)snprintf(cp, size, " %s", av[i]);
len = strlen(cp);
cp += len;
size -= len;
}
cp = buf + 1;
ip->i_name = strsave(cp);
freeargv(av);
}
static void
intlistfree(struct intlist *ip)
{
if (ip->i_acl != NULL) {
free(ip->i_acl);
ip->i_acl = NULL;
}
if (ip->i_name != NULL) {
free(ip->i_name);
ip->i_name = NULL;
}
}