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
/
whitelist.c
< prev
next >
Wrap
C/C++ Source or Header
|
2011-09-27
|
8KB
|
346 lines
/*
* Copyright (c) 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: whitelist.c 784 2011-09-28 02:05:06Z leres $ (LBL)";
#endif
#include <sys/types.h>
#include <sys/time.h>
#include <ctype.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sysexits.h>
#include <syslog.h>
#include <time.h>
#include <unistd.h>
#include "acld.h"
#include "cf.h"
#include "child.h"
#include "util.h"
#include "whitelist.h"
/* Forwards */
static void whiteliststradd(struct cf *, const char *);
/* Returns addr if address or network is whitelisted else NULL */
struct addr *
whitelist(struct cf *cf, struct addr *addr)
{
int i, w;
struct addr *a;
if (cf->c_whitelist == NULL)
return (NULL);
/* Return on any overlap */
w = maskwidth(addr);
for (i = 0, a = cf->c_whitelist; i < cf->c_whitelistlen; ++i, ++a) {
if (a->family != addr->family)
continue;
if (w >= maskwidth(a)) {
/* Test addr is more specific than whitelist addr */
if (insubnet(a, addr))
return (a);
} else {
/* Test addr is less specific than whitelist addr */
if (insubnet(addr, a))
return (a);
}
}
return (NULL);
}
/* Does not check to see if the addr is already on the list */
void
whitelistadd(struct cf *cf, struct addr *addr)
{
struct addr *a;
DYNARRAY(cf->c_whitelist, cf->c_whitelistlen,
&cf->c_whitelistsize, sizeof(*cf->c_whitelist), 1024, 1024,
"whitelistadd");
a = cf->c_whitelist + cf->c_whitelistlen;
*a = *addr;
++cf->c_whitelistlen;
}
int
whitelistdump(struct cf *cf, struct iobuf *ip)
{
int i, cnt;
struct addr *a;
cnt = 0;
for (i = 0, a = cf->c_whitelist; i < cf->c_whitelistlen; ++i, ++a) {
ioappendfmt(ip, "%s", addr2str(a));
++cnt;
}
return (cnt);
}
void
whitelistread(struct cf *cf)
{
int n;
char *cp, *cp2;
const char *errstr;
FILE *f;
char buf[1024];
if (cf->c_whitelistfn == NULL)
return;
f = fopen(cf->c_whitelistfn, "r");
if (f == NULL) {
if (errno != ENOENT) {
lg(LOG_ERR, "whitelistread: fopen %s: %s",
cf->c_whitelistfn, strerror(errno));
exit(1);
}
lg(LOG_INFO,
"whitelistread: %s missing; creating empty whitelist file",
cf->c_whitelistfn);
errstr = whitelistupdate(cf);
if (errstr != NULL) {
lg(LOG_ERR, "whitelistread: whitelistupdate: %s",
errstr);
exit(1);
}
return;
}
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 address/network */
cp2 = cp;
while (!isspace((int)*cp) && *cp != '\0')
++cp;
*cp++ = '\0';
whiteliststradd(cf, cp2);
}
(void)fclose(f);
}
int
whitelistrem(struct cf *cf, struct addr *addr)
{
int i, j;
struct addr *a;
if (cf->c_whitelist == NULL)
return (0);
for (i = 0, a = cf->c_whitelist; i < cf->c_whitelistlen; ++i, ++a)
if (ADDREQ(a, addr)) {
j = cf->c_whitelistlen - (i + 1);
if (j > 0)
memmove(cf->c_whitelist + i,
cf->c_whitelist + i + 1,
j * sizeof(cf->c_whitelist[0]));
--cf->c_whitelistlen;
ADDRZERO(&cf->c_whitelist[cf->c_whitelistlen]);
return (1);
}
a = cf->c_whitelist + cf->c_whitelistlen;
*a = *addr;
++cf->c_whitelistlen;
return (0);
}
/* Look for the exact address in the whitelist */
struct addr *
whitelistsearch(struct cf *cf, struct addr *addr)
{
int i;
struct addr *a;
if (cf->c_whitelist == NULL)
return (NULL);
for (i = 0, a = cf->c_whitelist; i < cf->c_whitelistlen; ++i, ++a)
if (ADDREQ(a, addr))
return (a);
return (NULL);
}
static void
whiteliststradd(struct cf *cf, const char *str)
{
const char *p;
struct addr *a;
struct addr addr;
/* Eat leading dot; done if there was only one */
if (*str == '.') {
++str;
if (*str == '\n'|| *str == '\0') {
lg(LOG_ERR, "whiteliststradd: junk \"%.80s\"", str);
return;
}
}
/* Eat comments */
if (*str == '#')
return;
a = &addr;
memset(a, 0, sizeof(*a));
p = extractaddr(str, NULL, a);
if (p != NULL) {
lg(LOG_ERR, "whiteliststradd: extractaddr dst %.80s: %s",
str, p);
exit(EX_SOFTWARE);
}
if (whitelistsearch(cf, a)) {
lg(LOG_ERR, "whiteliststradd: duplicate %.80s", str);
return;
}
whitelistadd(cf, a);
}
const char *
whitelistupdate(struct cf *cf)
{
int i;
FILE *f;
time_t now;
struct addr *a;
struct tm *tm;
char date[64];
char zone[32];
char temp[256];
static char errstr[256];
#ifdef HAVE_ALTZONE
int z;
#endif
if (cf->c_whitelistfn == NULL)
return ("whitelistupdate: whitelist file not configured");
(void)snprintf(temp, sizeof(temp), "%.*s-",
(int)sizeof(temp) - 2, cf->c_whitelistfn);
f = fopen(temp, "w");
if (f == NULL) {
(void)snprintf(errstr, sizeof(errstr),
"whitelistwrite: fopen %s: %s", temp, strerror(errno));
lg(LOG_ERR, "%s", errstr);
return (errstr);
}
fprintf(f, "# WARNING: dynamically updated; do not edit\n");
now = time(NULL);
tm = localtime(&now);
(void)strftime(date, sizeof(date), "%d-%b-%Y %T", tm);
#ifndef HAVE_ALTZONE
(void)strftime(zone, sizeof(zone), "%z", tm);
#else
z = altzone / -36;
if (z < 0) {
z = -z;
zone[0] = '-';
} else
zone[0] = '+';
(void)sprintf(zone + 1, "%04d", z);
#endif
fprintf(f, "# Last update: %s %s\n", date, zone);
for (i = 0, a = cf->c_whitelist; i < cf->c_whitelistlen; ++i, ++a)
fprintf(f, "%s\n", addr2str(a));
if (fclose(f) != 0) {
(void)snprintf(errstr, sizeof(errstr),
"whitelistwrite: fclose %s: %s", temp, strerror(errno));
lg(LOG_ERR, "%s", errstr);
return (errstr);
}
if (rename(temp, cf->c_whitelistfn) < 0) {
(void)snprintf(errstr, sizeof(errstr),
"whitelistwrite: rename %s -> %s: %s",
temp, cf->c_whitelistfn, strerror(errno));
lg(LOG_ERR, "%s", errstr);
return (errstr);
}
return (NULL);
}
/* Returns number of matching whitelist entries reported */
int
whitelistquery(struct cf *cf, struct addr *addr, struct iobuf *ip)
{
int i, cnt, w;
struct addr *a;
if (cf->c_whitelist == NULL)
return (0);
/* Report on any overlap */
w = maskwidth(addr);
cnt = 0;
for (i = 0, a = cf->c_whitelist; i < cf->c_whitelistlen; ++i, ++a) {
if (a->family != addr->family)
continue;
if (w >= maskwidth(a)) {
/* Test addr is more specific than whitelist addr */
if (insubnet(a, addr)) {
ioappendfmt(ip, "%s", addr2str(a));
++cnt;
}
} else {
/* Test addr is less specific than whitelist addr */
if (insubnet(addr, a)) {
ioappendfmt(ip, "%s", addr2str(a));
++cnt;
}
}
}
return (cnt);
}