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
/
acl.c
next >
Wrap
C/C++ Source or Header
|
2011-10-16
|
24KB
|
1,018 lines
/*
* Copyright (c) 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010, 2011
* 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: acl.c 796 2011-10-16 03:36:15Z leres $ (LBL)";
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <syslog.h>
#include "acld.h"
#include "cf.h"
/* Globals */
struct s2v str2acl[] = {
{ "notconnected", ATYPE_UNKNOWN },
{ "permitany", ATYPE_PERMITANY },
{ "blockany", ATYPE_BLOCKANY },
{ "permithost", ATYPE_PERMITHOST },
{ "blockhost", ATYPE_BLOCKHOST },
{ "permithosthost", ATYPE_PERMITHOSTHOST },
{ "blockhosthost", ATYPE_BLOCKHOSTHOST },
{ "permitnet", ATYPE_PERMITNET },
{ "blocknet", ATYPE_BLOCKNET },
{ "permitnethost", ATYPE_PERMITNETHOST },
{ "blocknethost", ATYPE_BLOCKNETHOST },
{ "permitudpport", ATYPE_PERMITUDPPORT },
{ "blockudpport", ATYPE_BLOCKUDPPORT },
{ "permittcpport", ATYPE_PERMITTCPPORT },
{ "blocktcpport", ATYPE_BLOCKTCPPORT },
{ "permitudphostport", ATYPE_PERMITUDPHOSTPORT },
{ "blockudphostport", ATYPE_BLOCKUDPHOSTPORT },
{ "permittcphostport", ATYPE_PERMITTCPHOSTPORT },
{ "blocktcphostport", ATYPE_BLOCKTCPHOSTPORT },
{ "permitudpdsthost", ATYPE_PERMITUDPDSTHOST },
{ "blockudpdsthost", ATYPE_BLOCKUDPDSTHOST },
{ "permittcpdsthost", ATYPE_PERMITTCPDSTHOST },
{ "blocktcpdsthost", ATYPE_BLOCKTCPDSTHOST },
{ "permitdsthost", ATYPE_PERMITDSTHOST },
{ "blockdsthost", ATYPE_BLOCKDSTHOST },
{ "permiticmpdsthost", ATYPE_PERMITICMPDSTHOST },
{ "blockicmpdsthost", ATYPE_BLOCKICMPDSTHOST },
{ "permitdstnet", ATYPE_PERMITDSTNET },
{ "blockdstnet", ATYPE_BLOCKDSTNET },
{ "permiticmpdstnet", ATYPE_PERMITICMPDSTNET },
{ "blockicmpdstnet", ATYPE_BLOCKICMPDSTNET },
{ "blockudpdsthostport", ATYPE_BLOCKUDPDSTHOSTPORT },
{ "blocktcpdsthostport", ATYPE_BLOCKTCPDSTHOSTPORT },
{ "permitudpdsthostport", ATYPE_PERMITUDPDSTHOSTPORT },
{ "permittcpdsthostport", ATYPE_PERMITTCPDSTHOSTPORT },
{ "permitudpnetport", ATYPE_PERMITUDPNETPORT },
{ "blockudpnetport", ATYPE_BLOCKUDPNETPORT },
{ "permittcpnetport", ATYPE_PERMITTCPNETPORT },
{ "blocktcpnetport", ATYPE_BLOCKTCPNETPORT },
{ "permitudphostsrcport", ATYPE_PERMITUDPHOSTSRCPORT },
{ "blockudphostsrcport", ATYPE_BLOCKUDPHOSTSRCPORT },
{ "permittcphostsrcport", ATYPE_PERMITTCPHOSTSRCPORT },
{ "blocktcphostsrcport", ATYPE_BLOCKTCPHOSTSRCPORT },
{ "permitudphostpairdstport", ATYPE_PERMITUDPHOSTPAIRDSTPORT },
{ "blockudphostpairdstport", ATYPE_BLOCKUDPHOSTPAIRDSTPORT },
{ "permittcphostpairdstport", ATYPE_PERMITTCPHOSTPAIRDSTPORT },
{ "blocktcphostpairdstport", ATYPE_BLOCKTCPHOSTPAIRDSTPORT },
{ "permitudpdstnet", ATYPE_PERMITUDPDSTNET },
{ "blockudpdstnet", ATYPE_BLOCKUDPDSTNET },
{ "permittcpdstnet", ATYPE_PERMITTCPDSTNET },
{ "blocktcpdstnet", ATYPE_BLOCKTCPDSTNET },
{ "permitudpdstnetport", ATYPE_PERMITUDPDSTNETPORT },
{ "blockudpdstnetport", ATYPE_BLOCKUDPDSTNETPORT },
{ "permittcpdstnetport", ATYPE_PERMITTCPDSTNETPORT },
{ "blocktcpdstnetport", ATYPE_BLOCKTCPDSTNETPORT },
{ "permitudpnethostport", ATYPE_PERMITUDPNETHOSTPORT },
{ "blockudpnethostport", ATYPE_PERMITUDPNETHOSTPORT },
{ "permittcpnethostport", ATYPE_PERMITTCPNETHOSTPORT },
{ "blocktcpnethostport", ATYPE_PERMITTCPNETHOSTPORT },
{ NULL, 0 }
};
/* Forwards */
int aclcmp(const void *, const void *);
int acllistcmp(const void *, const void *);
int addrcmp(const void *, const void *);
void
acladdacl(struct acllist *ap, struct acl *nal)
{
struct acl *al;
DYNARRAY(ap->acl, ap->acllen, &ap->aclsize,
sizeof(*ap->acl), 1024, 1024, "acl array");
al = ap->acl + ap->acllen;
aclcopy(al, nal);
++ap->acllen;
stats_sethiwater(&ap->stats, ap->acllen);
if (ap->limitp != NULL)
++ap->limitp->a_len;
/* Sort on sequence number (if we have them) */
if (ap->lastportseq >= 0 || ap->lastseq >= 0 ||
ap->lastpermithostportseq >= 0)
qsort(ap->acl, (size_t)ap->acllen, sizeof(*al), aclcmp);
}
void
acladdacllist(struct cf *cf, const char *str)
{
int an;
const char *p;
char **av;
struct addr *a;
struct acllist *ap;
an = makeargv(str, &av);
if (an != 2) {
lg(LOG_ERR, "acladdacllist wrong number of args: \"%s\"", str);
freeargv(av);
return;
}
ap = aclfindlistbyname(cf, av[0]);
if (ap == NULL) {
DYNARRAY(cf->c_acllist, cf->c_acllistlen,
&cf->c_acllistsize, sizeof(*cf->c_acllist),
1, 1, "cf acllist");
ap = cf->c_acllist + cf->c_acllistlen;
ap->name = strsave(av[0]);
++cf->c_acllistlen;
ap->lastseq = -1;
ap->lastportseq = -1;
ap->lastpermithostportseq = -1;
}
DYNARRAY(ap->addr, ap->addrlen, &ap->addrsize,
sizeof(*ap->addr), 128, 128, "acllist addrs");
stats_init(&ap->stats, 10, 60, "acladdacllist: stats");
a = ap->addr + ap->addrlen;
p = extractaddr(av[1], NULL, a);
if (p != NULL) {
lg(LOG_ERR, "acladdacllist extractaddr: %s", p);
freeargv(av);
return;
}
++ap->addrlen;
freeargv(av);
}
/* Copy an ACL saving char fields as required */
void
aclcopy(struct acl *dst, const struct acl *src)
{
*dst = *src;
if (dst->port1 != NULL)
dst->port1 = strsave(dst->port1);
if (dst->port2 != NULL)
dst->port2 = strsave(dst->port2);
if (dst->raw != NULL)
dst->raw = strsave(dst->raw);
}
int
aclcmp(const void *arg1, const void *arg2)
{
const struct acl *al1, *al2;
al1 = (const struct acl *)arg1;
al2 = (const struct acl *)arg2;
return (al1->seq - al2->seq);
}
int
acldeleteacl(struct acllist *ap, struct acl *oal)
{
struct acl *al;
int i, n;
for (i = 0, al = ap->acl; i < ap->acllen; ++i, ++al) {
if (al->type != oal->type)
continue;
/* addr1 */
if (!ADDREQ(&al->addr1, &oal->addr1))
continue;
/* addr2 */
if (!ADDREQ(&al->addr2, &oal->addr2))
continue;
/* port1 */
if ((al->port1 != NULL) ^ (oal->port1 != NULL))
continue;
if (al->port1 != NULL && strcasecmp(al->port1, oal->port1) != 0)
continue;
/* port2 */
if ((al->port2 != NULL) ^ (oal->port2 != NULL))
continue;
if (al->port2 != NULL && strcasecmp(al->port2, oal->port2) != 0)
continue;
break;
}
if (i >= ap->acllen)
return (0);
if (al->port1 != NULL) {
free(al->port1);
al->port1 = NULL;
}
if (al->port2 != NULL) {
free(al->port2);
al->port2 = NULL;
}
if (al->raw != NULL) {
free(al->raw);
al->raw = NULL;
}
n = ap->acllen - (i + 1);
memmove(al, al + 1, n * sizeof(*al));
--ap->acllen;
if (ap->limitp != NULL)
--ap->limitp->a_len;
memset(ap->acl + ap->acllen, 0, sizeof(*ap->acl));
return (1);
}
/* If checksubnet, check for address in subnet */
struct acl *
aclfindacl(struct acllist *ap, struct acl *al, int checksubnet)
{
int i;
struct acl *al2;
for (i = 0, al2 = ap->acl; i < ap->acllen; ++i, ++al2) {
if (al->type != al2->type &&
(!checksubnet ||
al->type != ATYPE_BLOCKHOST ||
al2->type != ATYPE_BLOCKNET))
continue;
switch (al->type) {
case ATYPE_PERMITHOST:
case ATYPE_BLOCKHOST:
if (checksubnet && insubnet(&al2->addr1, &al->addr1))
return (al2);
if (ADDREQ(&al->addr1, &al2->addr1))
return (al2);
break;
case ATYPE_PERMITNET:
case ATYPE_BLOCKNET:
if (ADDREQ(&al->addr1, &al2->addr1))
return (al2);
break;
case ATYPE_BLOCKHOSTHOST:
if (ADDREQ(&al->addr1, &al2->addr1) &&
ADDREQ(&al->addr2, &al2->addr2))
return (al2);
break;
case ATYPE_BLOCKUDPPORT:
case ATYPE_BLOCKTCPPORT:
if (strcasecmp(al->port1, al2->port1) == 0)
return (al2);
break;
case ATYPE_PERMITUDPDSTHOSTPORT:
case ATYPE_BLOCKUDPDSTHOSTPORT:
case ATYPE_PERMITTCPDSTHOSTPORT:
case ATYPE_BLOCKTCPDSTHOSTPORT:
if (ADDREQ(&al->addr1, &al2->addr1) &&
strcasecmp(al->port1, al2->port1) == 0)
return (al2);
break;
default:
break;
}
}
return (NULL);
}
/* XXX when searching for a network, this doesn't find the widest mask match */
struct acllist *
aclfindlistbyaddr(struct cf *cf, struct addr *a)
{
int i, j;
struct acllist *ap;
struct addr *a2;
for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
for (j = 0, a2 = ap->addr; j < ap->addrlen; ++j, ++a2)
if (insubnet(a2, a))
return (ap);
return (NULL);
}
struct acllist *
aclfindlistbyname(struct cf *cf, const char *name)
{
int i;
struct acllist *ap;
for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
if (strcmp(ap->name, name) == 0)
return (ap);
return (NULL);
}
/* Find the default ACL list for the address family of the passed addr */
struct acllist *
aclfindlistdefault(struct cf *cf, struct addr *a)
{
int i, j;
struct addr *a2;
struct acllist *ap;
/*
* XXX We could probably move the family check to the outer
* loop but we would also have to make sure that each acl
* list contained homogenious address families
* (Which we should do!)
*/
for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap)
for (j = 0, a2 = ap->addr; j < ap->addrlen; ++j, ++a2)
if (a->family == a2->family && isdefaultaddr(a2))
return (ap);
return (NULL);
}
const char *
aclformat(struct acl *al)
{
const char *p;
char *cp;
size_t size, len;
static char buf[1024];
p = val2str(str2acl, al->type);
cp = buf;
size = sizeof(buf);
(void)snprintf(cp, size, "%d %llu %s", al->seq, al->count, p);
len = strlen(cp);
size -= len;
cp += len;
switch (al->type) {
case ATYPE_PERMITANY:
case ATYPE_BLOCKANY:
break;
case ATYPE_PERMITHOST:
case ATYPE_BLOCKHOST:
case ATYPE_PERMITUDPDSTHOST:
case ATYPE_BLOCKUDPDSTHOST:
case ATYPE_PERMITTCPDSTHOST:
case ATYPE_BLOCKTCPDSTHOST:
case ATYPE_PERMITDSTHOST:
case ATYPE_BLOCKDSTHOST:
case ATYPE_PERMITICMPDSTHOST:
case ATYPE_BLOCKICMPDSTHOST:
case ATYPE_PERMITNET:
case ATYPE_BLOCKNET:
case ATYPE_PERMITDSTNET:
case ATYPE_BLOCKDSTNET:
case ATYPE_PERMITICMPDSTNET:
case ATYPE_BLOCKICMPDSTNET:
case ATYPE_PERMITUDPDSTNET:
case ATYPE_BLOCKUDPDSTNET:
case ATYPE_PERMITTCPDSTNET:
case ATYPE_BLOCKTCPDSTNET:
(void)snprintf(cp, size, " %s", addr2str(&al->addr1));
break;
case ATYPE_BLOCKHOSTHOST:
case ATYPE_PERMITHOSTHOST:
(void)snprintf(cp, size, " %s", addr2str(&al->addr1));
len = strlen(cp);
size -= len;
cp += len;
(void)snprintf(cp, size, " %s", addr2str(&al->addr2));
break;
case ATYPE_BLOCKNETHOST:
case ATYPE_PERMITNETHOST:
(void)snprintf(cp, size, " %s", addr2str(&al->addr1));
len = strlen(cp);
size -= len;
cp += len;
(void)snprintf(cp, size, " %s", addr2str(&al->addr2));
break;
case ATYPE_PERMITUDPPORT:
case ATYPE_BLOCKUDPPORT:
case ATYPE_PERMITTCPPORT:
case ATYPE_BLOCKTCPPORT:
(void)snprintf(cp, size, " %s", al->port1);
break;
case ATYPE_PERMITUDPHOSTPORT:
case ATYPE_BLOCKUDPHOSTPORT:
case ATYPE_PERMITTCPHOSTPORT:
case ATYPE_BLOCKTCPHOSTPORT:
case ATYPE_PERMITUDPDSTHOSTPORT:
case ATYPE_BLOCKUDPDSTHOSTPORT:
case ATYPE_PERMITTCPDSTHOSTPORT:
case ATYPE_BLOCKTCPDSTHOSTPORT:
case ATYPE_PERMITUDPHOSTSRCPORT:
case ATYPE_BLOCKUDPHOSTSRCPORT:
case ATYPE_PERMITTCPHOSTSRCPORT:
case ATYPE_BLOCKTCPHOSTSRCPORT:
case ATYPE_PERMITUDPDSTNETPORT:
case ATYPE_BLOCKUDPDSTNETPORT:
case ATYPE_PERMITTCPDSTNETPORT:
case ATYPE_BLOCKTCPDSTNETPORT:
(void)snprintf(cp, size, " %s %s",
addr2str(&al->addr1), al->port1);
break;
case ATYPE_PERMITUDPNETPORT:
case ATYPE_BLOCKUDPNETPORT:
case ATYPE_PERMITTCPNETPORT:
case ATYPE_BLOCKTCPNETPORT:
(void)snprintf(cp, size, " %s %s",
addr2str(&al->addr1), al->port1);
break;
case ATYPE_PERMITUDPHOSTPAIRDSTPORT:
case ATYPE_BLOCKUDPHOSTPAIRDSTPORT:
case ATYPE_PERMITTCPHOSTPAIRDSTPORT:
case ATYPE_BLOCKTCPHOSTPAIRDSTPORT:
(void)snprintf(cp, size, " %s", addr2str(&al->addr1));
len = strlen(cp);
size -= len;
cp += len;
(void)snprintf(cp, size, " %s %s",
addr2str(&al->addr2), al->port1);
break;
case ATYPE_PERMITUDPNETHOSTPORT:
case ATYPE_BLOCKUDPNETHOSTPORT:
case ATYPE_PERMITTCPNETHOSTPORT:
case ATYPE_BLOCKTCPNETHOSTPORT:
(void)snprintf(cp, size, " %s", addr2str(&al->addr1));
len = strlen(cp);
size -= len;
cp += len;
(void)snprintf(cp, size, " %s %s",
addr2str(&al->addr2), al->port1);
break;
break;
case ATYPE_UNKNOWN:
(void)snprintf(buf, sizeof(buf), "# %d unsupported ACL \"%s\"",
al->seq, al->raw != NULL ? al->raw : "");
break;
#ifdef notdef
default:
lg(LOG_ERR, "aclformat: bad type %d", al->type);
exit(EX_SOFTWARE);
#endif
}
return (buf);
}
void
aclfree(struct acllist *ap)
{
int i;
struct acl *al;
struct req *rp;
if (ap->name != NULL) {
free(ap->name);
ap->name = NULL;
}
/* Compaction cleanup */
ap->compactclient = NULL;
if ((rp = ap->compactreq) != NULL) {
ap->compactreq = NULL;
freereq(rp);
}
if (ap->acl != NULL) {
for (i = 0, al = ap->acl; i < ap->acllen; ++i, ++al) {
if (al->port1 != NULL)
free(al->port1);
if (al->port2 != NULL)
free(al->port2);
if (al->raw != NULL)
free(al->raw);
}
FREEDYNARRAY(ap->acl, &ap->acllen, &ap->aclsize);
}
if (ap->addr != NULL)
FREEDYNARRAY(ap->addr, &ap->addrlen, &ap->addrsize);
ap->sentlistacl = 0;
ap->limitp = NULL;
stats_free(&ap->stats);
}
int
acllistcmp(const void *arg1, const void *arg2)
{
const struct acllist *ap1, *ap2;
ap1 = (const struct acllist *)arg1;
ap2 = (const struct acllist *)arg2;
/* Sort on the first address (good enough to move default to the end) */
return (addrcmp(ap1->addr, ap2->addr));
}
/* Free just the ACL entries from all ACL lists */
void
acllistsfree(struct state *sp)
{
int i, j;
struct acllist *ap;
struct acl *al;
struct cf *cf;
cf = sp->cf;
for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap) {
if (ap->acl == NULL)
continue;
for (j = 0, al = ap->acl; j < ap->acllen; ++j, ++al) {
if (al->port1 != NULL)
free(al->port1);
if (al->port2 != NULL)
free(al->port2);
if (al->raw != NULL)
free(al->raw);
}
FREEDYNARRAY(ap->acl, &ap->acllen, &ap->aclsize);
ap->sentlistacl = 0;
}
sp->listedallacls = 0;
}
/* Returns number of matching host, hosthost or subnet acl entries reported */
int
aclquery(struct acllist *ap, struct addr *addrp, struct iobuf *ip)
{
int i, cnt;
struct acl *al;
char buf[128];
cnt = 0;
for (i = 0, al = ap->acl; i < ap->acllen; ++i, ++al) {
switch (al->type) {
case ATYPE_BLOCKHOST:
if (ADDREQ(addrp, &al->addr1)) {
ioappendfmt(ip, "%s",
val2str(str2acl, al->type));
++cnt;
}
break;
case ATYPE_BLOCKHOSTHOST:
if (ADDREQ(addrp, &al->addr1)) {
strncpy(buf, addr2str(&al->addr1), sizeof(buf));
buf[sizeof(buf) - 1] = '\0';
ioappendfmt(ip, "%s %s %s",
val2str(str2acl, al->type),
buf,
addr2str(&al->addr2));
++cnt;
}
break;
case ATYPE_BLOCKNET:
/*
* Look for ATYPE_BLOCKNET vs. ATYPE_BLOCKNET
* or ATYPE_BLOCKNET vs. ATYPE_BLOCKHOST
*/
if (ADDREQ(addrp, &al->addr1) ||
insubnet(&al->addr1, addrp)) {
ioappendfmt(ip, "%s %s",
val2str(str2acl, al->type),
addr2str(&al->addr1));
++cnt;
}
break;
default:
break;
}
}
return (cnt);
}
void
aclsortacls(struct cf *cf)
{
int i;
struct acllist *ap;
struct addr *a;
ap = cf->c_acllist;
qsort(ap, (size_t)cf->c_acllistlen, sizeof(*ap), acllistcmp);
for (i = 0, ap = cf->c_acllist; i < cf->c_acllistlen; ++i, ++ap) {
if (ap->addrlen > 1) {
a = ap->addr;
qsort(a, (size_t)ap->addrlen, sizeof(*a), addrcmp);
}
#ifdef HAVE_CFORCE
/* The rest of this isn't needed for the cForce */
if (cf->c_cforceaddr != NULL)
continue;
#endif
if (cf->c_lowportseq >= 0 &&
(ap->lastportseq < 0 || ap->lastportseq < cf->c_lowportseq))
ap->lastportseq = cf->c_lowportseq - 1;
if (cf->c_lowpermithostportseq >= 0 &&
(ap->lastpermithostportseq < 0 ||
ap->lastpermithostportseq < cf->c_lowpermithostportseq))
ap->lastpermithostportseq =
cf->c_lowpermithostportseq - 1;
if (cf->c_incrseq) {
if (cf->c_lowseq >= 0 &&
(ap->lastseq < 0 || ap->lastseq < cf->c_lowseq))
ap->lastseq = cf->c_lowseq - 1;
} else {
if (cf->c_highseq >= 0 &&
(ap->lastseq < 0 || ap->lastseq > cf->c_highseq))
ap->lastseq = cf->c_highseq + 1;
}
}
}
int
aclstraddacl(struct cf *cf, struct acllist *ap, const char *str)
{
int an;
const char *p;
char **av;
struct acl *al;
struct acl acl;
/* Eat leading dot; done if there was only one */
if (*str == '.') {
++str;
if (*str == '\n'|| *str == '\0')
return (1);
}
/* syslog any comments we get */
if (*str == '#') {
++str;
while (*str == ' ')
++str;
lg(LOG_INFO, "listacl: \"%s\"", str);
return (0);
}
al = &acl;
memset(al, 0, sizeof(*al));
an = makeargv(str, &av);
if (an < 3) {
lg(LOG_ERR, "aclstraddacl: missing args \"%s\"", str);
freeargv(av);
return (0);
}
al->seq = atoi(av[0]);
al->count = strtoull(av[1], NULL, 10);
al->type = str2val(str2acl, av[2]);
switch (al->type) {
case ATYPE_PERMITANY:
case ATYPE_BLOCKANY:
/* No args */
if (an != 3) {
lg(LOG_ERR, "aclstraddacl: wrong number of args \"%s\"",
str);
freeargv(av);
return (0);
}
break;
case ATYPE_PERMITHOST:
case ATYPE_BLOCKHOST:
case ATYPE_PERMITUDPDSTHOST:
case ATYPE_BLOCKUDPDSTHOST:
case ATYPE_PERMITTCPDSTHOST:
case ATYPE_BLOCKTCPDSTHOST:
case ATYPE_PERMITDSTHOST:
case ATYPE_BLOCKDSTHOST:
case ATYPE_PERMITICMPDSTHOST:
case ATYPE_BLOCKICMPDSTHOST:
case ATYPE_PERMITNET:
case ATYPE_BLOCKNET:
case ATYPE_PERMITUDPDSTNET:
case ATYPE_BLOCKUDPDSTNET:
case ATYPE_PERMITTCPDSTNET:
case ATYPE_BLOCKTCPDSTNET:
case ATYPE_PERMITDSTNET:
case ATYPE_BLOCKDSTNET:
case ATYPE_PERMITICMPDSTNET:
case ATYPE_BLOCKICMPDSTNET:
/* One host or network */
if (an != 4) {
lg(LOG_ERR, "aclstraddacl: wrong number of args \"%s\"",
str);
freeargv(av);
return (0);
}
p = extractaddr(av[3], NULL, &al->addr1);
if (p != NULL) {
lg(LOG_ERR, "aclstraddacl: bad addr: %s", p);
freeargv(av);
return (0);
}
break;
case ATYPE_PERMITHOSTHOST:
case ATYPE_BLOCKHOSTHOST:
case ATYPE_PERMITNETHOST:
case ATYPE_BLOCKNETHOST:
/* Two hosts or networks */
if (an != 5) {
lg(LOG_ERR, "aclstraddacl: wrong number of args \"%s\"",
str);
freeargv(av);
return (0);
}
if ((p = extractaddr(av[3], NULL, &al->addr1)) != NULL ||
(p = extractaddr(av[4], NULL, &al->addr2)) != NULL) {
lg(LOG_ERR, "aclstraddacl: bad addr: %s", p);
freeargv(av);
return (0);
}
break;
case ATYPE_PERMITUDPPORT:
case ATYPE_BLOCKUDPPORT:
case ATYPE_PERMITTCPPORT:
case ATYPE_BLOCKTCPPORT:
/* A port */
if (an != 4) {
lg(LOG_ERR, "aclstraddacl: wrong number of args \"%s\"",
str);
freeargv(av);
return (0);
}
al->port1 = av[3];
break;
case ATYPE_PERMITUDPHOSTPORT:
case ATYPE_BLOCKUDPHOSTPORT:
case ATYPE_PERMITTCPHOSTPORT:
case ATYPE_BLOCKTCPHOSTPORT:
case ATYPE_PERMITUDPDSTHOSTPORT:
case ATYPE_BLOCKUDPDSTHOSTPORT:
case ATYPE_PERMITTCPDSTHOSTPORT:
case ATYPE_BLOCKTCPDSTHOSTPORT:
case ATYPE_PERMITUDPHOSTSRCPORT:
case ATYPE_BLOCKUDPHOSTSRCPORT:
case ATYPE_PERMITTCPHOSTSRCPORT:
case ATYPE_BLOCKTCPHOSTSRCPORT:
case ATYPE_PERMITUDPNETPORT:
case ATYPE_BLOCKUDPNETPORT:
case ATYPE_PERMITTCPNETPORT:
case ATYPE_BLOCKTCPNETPORT:
case ATYPE_PERMITUDPDSTNETPORT:
case ATYPE_BLOCKUDPDSTNETPORT:
case ATYPE_PERMITTCPDSTNETPORT:
case ATYPE_BLOCKTCPDSTNETPORT:
/* A host or network and a port */
if (an != 5) {
lg(LOG_ERR, "aclstraddacl: wrong number of args \"%s\"",
str);
freeargv(av);
return (0);
}
p = extractaddr(av[3], NULL, &al->addr1);
if (p != NULL) {
lg(LOG_ERR, "aclstraddacl: bad addr/net: %s", p);
freeargv(av);
return (0);
}
al->port1 = av[4];
break;
case ATYPE_PERMITUDPHOSTPAIRDSTPORT:
case ATYPE_BLOCKUDPHOSTPAIRDSTPORT:
case ATYPE_PERMITTCPHOSTPAIRDSTPORT:
case ATYPE_BLOCKTCPHOSTPAIRDSTPORT:
case ATYPE_PERMITUDPNETHOSTPORT:
case ATYPE_BLOCKUDPNETHOSTPORT:
case ATYPE_PERMITTCPNETHOSTPORT:
case ATYPE_BLOCKTCPNETHOSTPORT:
/* Two hosts or networks and a port */
if (an != 6) {
lg(LOG_ERR, "aclstraddacl: wrong number of args \"%s\"",
str);
freeargv(av);
return (0);
}
if ((p = extractaddr(av[3], NULL, &al->addr1)) != NULL ||
(p = extractaddr(av[4], NULL, &al->addr2)) != NULL) {
lg(LOG_ERR, "aclstraddacl: bad addr: %s", p);
freeargv(av);
return (0);
}
al->port1 = av[5];
break;
case ATYPE_UNKNOWN:
/* Save the raw text so we can print it out later */
p = strchr(str, '#');
if (p == NULL)
p = str;
else {
++p;
while (isspace((int)*p))
++p;
}
al->raw = (char *)p;
lg(LOG_ERR, "aclstraddacl: unknown \"%s\"", str);
break;
#ifdef notdef
default:
lg(LOG_ERR, "aclstraddacl: no such type \"%s\"", str);
exit(EX_SOFTWARE);
#endif
}
acladdacl(ap, al);
if ((cf->c_highseq == 0 || al->seq <= cf->c_highseq) &&
(cf->c_lowseq == 0 || al->seq >= cf->c_lowseq)) {
if (cf->c_incrseq) {
if (ap->lastseq < al->seq)
ap->lastseq = al->seq;
} else {
if (ap->lastseq < 0 || ap->lastseq > al->seq)
ap->lastseq = al->seq;
}
}
if ((cf->c_highportseq == 0 || al->seq <= cf->c_highportseq) &&
(cf->c_lowportseq == 0 || al->seq >= cf->c_lowportseq)) {
if (ap->lastportseq < al->seq)
ap->lastportseq = al->seq;
}
if ((cf->c_highpermithostportseq == 0 ||
al->seq <= cf->c_highpermithostportseq) &&
(cf->c_lowpermithostportseq == 0 ||
al->seq >= cf->c_lowpermithostportseq)) {
if (ap->lastpermithostportseq < al->seq)
ap->lastpermithostportseq = al->seq;
}
freeargv(av);
return (0);
}
int
addrcmp(const void *arg1, const void *arg2)
{
int i, r1, r2;
const struct addr *a1, *a2;
a1 = (const struct addr *)arg1;
a2 = (const struct addr *)arg2;
/* IPv4 before IPv6 */
if (a1->family != a2->family)
return ((a1->family == AF_INET) ? -1 : 1);
switch (a1->family) {
case AF_INET:
/* Address */
if (ntohl(a1->addr4) < ntohl(a2->addr4))
r1 = -1;
else if (ntohl(a1->addr4) > ntohl(a2->addr4))
r1 = 1;
else
r1 = 0;
/* Mask */
if (ntohl(a1->mask4) < ntohl(a2->mask4))
r2 = 1;
else if (ntohl(a1->mask4) > ntohl(a2->mask4))
r2 = -1;
else
r2 = 0;
break;
case AF_INET6:
/* Address */
r1 = 0;
for (i = 0; i < 16; ++i) {
if (ntohl(a1->addr6[i]) < ntohl(a2->addr6[i])) {
r1 = -1;
break;
}
if (ntohl(a1->addr6[i]) > ntohl(a2->addr6[i])) {
r1 = 1;
break;
}
}
/* Mask */
r2 = 0;
for (i = 0; i < 16; ++i) {
if (a1->mask6[i] < a2->mask6[i]) {
r2 = 1;
break;
}
if (a1->mask6[i] > a2->mask6[i]) {
r2 = -1;
break;
}
}
break;
default:
abort();
}
/* If the masks are the same, sort on addr */
if (r2 == 0)
return (r1);
/* Otherwise, sort on mask */
return (r2);
}
void
attrclear(struct state *sp)
{
int i;
struct cf *cf;
struct attrlist *atp;
cf = sp->cf;
for (i = 0, atp = cf->c_attrlist; i < cf->c_attrlistlen; ++i, ++atp)
atp->a_sentattr = 0;
sp->sentattrs = 0;
}
const char *
attrfmt(struct attrlist *atp)
{
static char buf[64];
/* XXX only one attribute right now */
if (atp->a_attr != ATTR_IPV6)
abort();
(void)snprintf(buf, sizeof(buf), "attr %s ipv6", atp->a_acl);
return (buf);
}