File: [local] / src / usr.sbin / spamdb / spamdb.c (download)
Revision 1.7, Thu Mar 11 18:14:21 2004 UTC (20 years, 3 months ago) by beck
Branch: MAIN
CVS Tags: OPENBSD_3_5_BASE, OPENBSD_3_5 Changes since 1.6: +3 -1 lines
fix leak, found by Patrick Latifi <pat@eyeo.org>
ok millert@, dhartmei@
|
/* $OpenBSD: spamdb.c,v 1.7 2004/03/11 18:14:21 beck Exp $ */
/*
* Copyright (c) 2004 Bob Beck. All rights reserved.
*
* 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 THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR 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.
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>
#include <sys/wait.h>
#include <net/if.h>
#include <netinet/in.h>
#include <net/pfvar.h>
#include <arpa/inet.h>
#include <db.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "grey.h"
extern struct passwd *pw;
extern FILE * grey;
extern int debug;
size_t whitecount, whitealloc;
char **whitelist;
int pfdev;
/* borrowed from dhartmei.. */
static int
address_valid_v4(const char *a)
{
if (!*a)
return (0);
while (*a)
if ((*a >= '0' && *a <= '9') || *a == '.')
a++;
else
return (0);
return (1);
}
int
dbupdate(char *dbname, char *ip, int add)
{
BTREEINFO btreeinfo;
DBT dbk, dbd;
DB *db;
struct gdata gd;
time_t now;
int r;
now = time(NULL);
memset(&btreeinfo, 0, sizeof(btreeinfo));
db = dbopen(dbname, O_EXLOCK|O_RDWR, 0600, DB_BTREE, &btreeinfo);
if (db == NULL)
return(-1);
if (!address_valid_v4(ip)) {
warnx("invalid ip address %s\n", ip);
goto bad;
}
memset(&dbk, 0, sizeof(dbk));
dbk.size = strlen(ip);
dbk.data = ip;
memset(&dbd, 0, sizeof(dbd));
if (!add) {
/* remove whitelist entry */
r = db->get(db, &dbk, &dbd, 0);
if (r == -1) {
warn("db->get failed");
goto bad;
}
if (r) {
warnx("no entry for %s", ip);
goto bad;
} else if (db->del(db, &dbk, 0)) {
warn("db->del failed");
goto bad;
}
} else {
/* add or update whitelist entry */
r = db->get(db, &dbk, &dbd, 0);
if (r == -1) {
warn("db->get failed");
goto bad;
}
if (r) {
/* new entry */
memset(&gd, 0, sizeof(gd));
gd.first = now;
gd.bcount = 1;
gd.pass = now;
gd.expire = now + WHITEEXP;
memset(&dbk, 0, sizeof(dbk));
dbk.size = strlen(ip);
dbk.data = ip;
memset(&dbd, 0, sizeof(dbd));
dbd.size = sizeof(gd);
dbd.data = &gd;
r = db->put(db, &dbk, &dbd, 0);
if (r) {
warn("db->put failed");
goto bad;
}
} else {
if (dbd.size != sizeof(gd)) {
/* whatever this is, it doesn't belong */
db->del(db, &dbk, 0);
goto bad;
}
memcpy(&gd, dbd.data, sizeof(gd));
gd.pcount++;
gd.expire = now + WHITEEXP;
memset(&dbk, 0, sizeof(dbk));
dbk.size = strlen(ip);
dbk.data = ip;
memset(&dbd, 0, sizeof(dbd));
dbd.size = sizeof(gd);
dbd.data = &gd;
r = db->put(db, &dbk, &dbd, 0);
if (r) {
warn("db->put failed");
goto bad;
}
}
}
db->close(db);
db = NULL;
return (0);
bad:
db->close(db);
db = NULL;
return(-1);
}
int
dblist(char *dbname)
{
BTREEINFO btreeinfo;
DBT dbk, dbd;
DB *db;
struct gdata gd;
int r;
/* walk db, list in text format */
memset(&btreeinfo, 0, sizeof(btreeinfo));
db = dbopen(dbname, O_EXLOCK|O_RDONLY, 0600, DB_BTREE, &btreeinfo);
if (db == NULL)
err(1, "dbopen");
memset(&dbk, 0, sizeof(dbk));
memset(&dbd, 0, sizeof(dbd));
for (r = db->seq(db, &dbk, &dbd, R_FIRST); !r;
r = db->seq(db, &dbk, &dbd, R_NEXT)) {
char *a, *cp;
if ((dbk.size < 1) || dbd.size != sizeof(struct gdata)) {
db->close(db);
errx(1, "bogus size db entry - bad db file?");
}
memcpy(&gd, dbd.data, sizeof(gd));
a = malloc(dbk.size + 1);
if (a == NULL)
err(1, "malloc");
memcpy(a, dbk.data, dbk.size);
a[dbk.size]='\0';
cp = strchr(a, '\n');
if (cp == NULL)
/* this is a whitelist entry */
printf("WHITE:%s:::%d:%d:%d:%d:%d\n", a, gd.first,
gd.pass, gd.expire, gd.bcount, gd.pcount);
else {
char *from, *to;
/* greylist entry */
*cp = '\0';
from = cp + 1;
to = strchr(from, '\n');
if (to == NULL) {
warnx("No from part in grey key %s", a);
free(a);
goto bad;
}
*to = '\0';
to++;
printf("GREY:%s:%s:%s:%d:%d:%d:%d:%d\n",
a, from, to, gd.first, gd.pass, gd.expire,
gd.bcount, gd.pcount);
}
free(a);
}
db->close(db);
db = NULL;
return(0);
bad:
db->close(db);
db = NULL;
errx(1, "incorrect db format entry");
/* NOTREACHED */
return(-1);
}
static int
usage(void)
{
fprintf(stderr, "usage: spamdb [-a ip] [-d ip]\n");
exit(1);
}
int
main(int argc, char **argv)
{
int ch, action = 0;
char *ip = NULL;
while ((ch = getopt(argc, argv, "a:d:")) != -1) {
switch (ch) {
case 'a':
action = 1;
ip = optarg;
break;
case 'd':
action = 2;
ip = optarg;
break;
default:
usage();
break;
}
}
switch (action) {
case 0:
dblist(PATH_SPAMD_DB);
break;
case 1:
dbupdate(PATH_SPAMD_DB, ip, 1);
break;
case 2:
dbupdate(PATH_SPAMD_DB, ip, 0);
break;
default:
errx(-1, "bad action");
}
return(0);
}