/* $Id: dspam_clean.c,v 1.247 2011/06/28 00:13:48 sbajic Exp $ */
/*
DSPAM
COPYRIGHT (C) 2002-2012 DSPAM PROJECT
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#ifdef TIME_WITH_SYS_TIME
# include
# include
#else
# ifdef HAVE_SYS_TIME_H
# include
# else
# include
# endif
#endif
#include "libdspam.h"
#include "language.h"
#include "read_config.h"
#include "config_api.h"
#include "pref.h"
#include "error.h"
DSPAM_CTX *open_ctx = NULL, *open_mtx = NULL;
int process_sigs (DSPAM_CTX * CTX, int age);
int process_probs (DSPAM_CTX * CTX, int age);
int process_unused (DSPAM_CTX * CTX, int any, int quota, int nospam, int onehit);
void dieout (int signal);
#define CLEANSYNTAX "dspam_clean [-s[age] -p[age] -u[any,hapax,nospam,onehit] -h] [user1 user2 ... userN]\n"
int
main (int argc, char *argv[])
{
DSPAM_CTX *CTX = NULL, *CTX2;
char *user;
int do_sigs = 0;
int do_probs = 0;
int do_unused = 0;
int age_sigs = 14;
int age_probs = 30;
int age_unused[4] = { 90, 30, 15, 15 };
int i, help = 0;
struct nt *users = NULL;
struct nt_node *node = NULL;
#ifndef _WIN32
#ifdef TRUSTED_USER_SECURITY
struct passwd *p = getpwuid (getuid ());
#endif
#endif
/* Read dspam.conf */
agent_config = read_config(NULL);
if (!agent_config) {
LOG(LOG_ERR, ERR_AGENT_READ_CONFIG);
fprintf (stderr, ERR_AGENT_READ_CONFIG "\n");
exit(EXIT_FAILURE);
}
if (!_ds_read_attribute(agent_config, "Home")) {
LOG(LOG_ERR, ERR_AGENT_DSPAM_HOME);
fprintf (stderr, ERR_AGENT_DSPAM_HOME "\n");
goto bail;
}
if (libdspam_init(_ds_read_attribute(agent_config, "StorageDriver")) != 0) {
LOG(LOG_ERR, ERR_DRV_INIT);
fprintf (stderr, ERR_DRV_INIT "\n");
_ds_destroy_config(agent_config);
exit(EXIT_FAILURE);
}
#ifndef _WIN32
#ifdef TRUSTED_USER_SECURITY
if (!_ds_match_attribute(agent_config, "Trust", p->pw_name) && p->pw_uid) {
fprintf(stderr, ERR_TRUSTED_MODE "\n");
goto bail;
}
#endif
#endif
for(i=0;i2)
age_probs = atoi(argv[i]+2);
}
else if (!strncmp(argv[i], "-s", 2)) {
do_sigs = 1;
if (strlen(argv[i])>2)
age_sigs = atoi(argv[i]+2);
} else if (!strncmp(argv[i], "-u", 2)) {
do_unused = 1;
if (strlen(argv[i])>2) {
char *c = strdup(argv[i]+2);
char *d = strtok(c, ",");
int j = 0;
while(d != NULL && j<4) {
age_unused[j] = atoi(d);
j++;
d = strtok(NULL, ",");
}
free(c);
}
}
else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
help = 1;
else if (i>0)
nt_add(users, argv[i]);
}
if (help || (!do_probs && !do_sigs && !do_unused)) {
fprintf(stderr, "%s", CLEANSYNTAX);
_ds_destroy_config(agent_config);
nt_destroy(users);
libdspam_shutdown();
if (help) {
exit(EXIT_SUCCESS);
}
exit(EXIT_FAILURE);
}
open_ctx = open_mtx = NULL;
signal (SIGINT, dieout);
signal (SIGPIPE, dieout);
signal (SIGTERM, dieout);
dspam_init_driver (NULL);
if (users->items == 0) {
CTX = dspam_create (NULL, NULL, _ds_read_attribute(agent_config, "Home"), DSM_TOOLS, 0);
open_ctx = CTX;
if (CTX == NULL)
{
fprintf (stderr, "Could not initialize context: %s\n", strerror (errno));
dspam_shutdown_driver (NULL);
goto bail;
}
set_libdspam_attributes(CTX);
if (dspam_attach(CTX, NULL)) {
LOG (LOG_WARNING, "unable to attach dspam context");
fprintf (stderr, "Unable to attach DSPAM context\n");
goto bail;
}
user = _ds_get_nextuser (CTX);
} else {
node = users->first;
if (node != NULL)
user = node->ptr;
else
goto bail;
}
while (user != NULL)
{
#ifdef DEBUG
printf ("PROCESSING USER: %s\n", user);
#endif
CTX2 = dspam_create (user, NULL, _ds_read_attribute(agent_config, "Home"), DSM_TOOLS, 0);
open_mtx = CTX2;
if (CTX2 == NULL)
{
fprintf (stderr, "Could not initialize context: %s\n",
strerror (errno));
return EUNKNOWN;
}
set_libdspam_attributes(CTX2);
if (dspam_attach(CTX2, NULL)) {
LOG (LOG_WARNING, "unable to attach dspam context");
fprintf (stderr, "Unable to attach DSPAM context\n");
goto bail;
}
if (do_sigs)
process_sigs(CTX2, age_sigs);
if (do_probs)
process_probs(CTX2, age_probs);
if (do_unused)
process_unused(CTX2, age_unused[0], age_unused[1], age_unused[2], age_unused[3]);
dspam_destroy (CTX2);
open_mtx = NULL;
if (users->items == 0) {
user = _ds_get_nextuser (CTX);
} else {
if (node == NULL || node->next == NULL) {
node = NULL;
user = NULL;
} else {
node = node->next;
user = node->ptr;
}
}
}
if (users->items == 0) {
dspam_destroy (CTX);
open_ctx = NULL;
}
dspam_shutdown_driver (NULL);
_ds_destroy_config(agent_config);
nt_destroy(users);
libdspam_shutdown();
exit (EXIT_SUCCESS);
bail:
if (open_ctx)
dspam_destroy(open_ctx);
if (open_mtx)
dspam_destroy(open_mtx);
_ds_destroy_config(agent_config);
nt_destroy(users);
libdspam_shutdown();
exit(EXIT_FAILURE);
}
int
process_sigs (DSPAM_CTX * CTX, int age)
{
struct _ds_storage_signature *ss;
struct nt *del;
struct nt_node *node;
int delta;
del = nt_create(NT_CHAR);
if (del == NULL)
return -1;
#ifdef DEBUG
printf ("Processing sigs; age: %d\n", age);
#endif
ss = _ds_get_nextsignature (CTX);
while (ss != NULL)
{
#ifdef DEBUG
printf ("Signature: %s\n Created: %s\n", ss->signature,
ctime (&ss->created_on));
#endif
delta = (((time (NULL) - ss->created_on) / 60) / 60) / 24;
if (age == 0 || delta > age)
{
#ifdef DEBUG
printf (" DELETED!\n");
#endif
nt_add(del, ss->signature);
}
free(ss->data);
free(ss);
ss = _ds_get_nextsignature (CTX);
}
node = del->first;
while(node != NULL) {
_ds_delete_signature (CTX, node->ptr);
node = node->next;
}
nt_destroy(del);
return 0;
}
int process_probs (DSPAM_CTX *CTX, int age) {
struct _ds_storage_record *sr;
struct _ds_spam_stat s;
ds_diction_t del;
int delta;
#ifdef DEBUG
printf("Processing probabilities; age: %d\n", age);
#endif
del = ds_diction_create(196613);
if (del == NULL)
return -1;
sr = _ds_get_nexttoken (CTX);
while (sr != NULL)
{
s.innocent_hits = sr->innocent_hits;
s.spam_hits = sr->spam_hits;
s.probability = 0.00000;
_ds_calc_stat(CTX, NULL, &s, DTT_DEFAULT, NULL);
if (s.probability >= 0.3500 && s.probability <= 0.6500) {
delta = (((time (NULL) - sr->last_hit) / 60) / 60) / 24;
if (age == 0 || delta > age)
ds_diction_touch(del, sr->token, "", 0);
}
free (sr);
sr = _ds_get_nexttoken (CTX);
}
_ds_delall_spamrecords(CTX, del);
ds_diction_destroy(del);
return 0;
}
int process_unused (DSPAM_CTX *CTX, int any, int quota, int nospam, int onehit) {
struct _ds_storage_record *sr;
ds_diction_t del;
time_t t = time(NULL);
int delta, toe = 0, tum = 0;
agent_pref_t PTX;
#ifdef DEBUG
printf("Processing unused; any: %d quota: %d nospam: %d onehit: %d\n",
any, quota, nospam, onehit);
#endif
PTX = _ds_pref_load(agent_config, CTX->username, _ds_read_attribute(agent_config, "Home"), NULL);
if (PTX == NULL || PTX[0] == 0) {
if (PTX)
_ds_pref_free(PTX);
PTX = pref_config();
}
if (!strcasecmp(_ds_pref_val(PTX, "trainingMode"), "toe")) {
#ifdef DEBUG
printf("Limiting unused token purges for user %s - TOE Training Mode Set\n", CTX->username);
#endif
toe = 1;
}
if (!strcasecmp(_ds_pref_val(PTX, "trainingMode"), "tum")) {
#ifdef DEBUG
printf("Limiting unused token purges for user %s - TUM Training Mode Set\n", CTX->username);
#endif
tum = 1;
}
if (PTX)
_ds_pref_free(PTX);
del = ds_diction_create(196613);
if (del == NULL)
return -1;
sr = _ds_get_nexttoken (CTX);
while (sr != NULL)
{
delta = (((t - sr->last_hit) / 60) / 60) / 24;
if (!toe && (any == 0 || delta > any))
{
if (!tum || sr->innocent_hits + sr->spam_hits < 50)
ds_diction_touch(del, sr->token, "", 0);
}
else if ((sr->innocent_hits*2) + sr->spam_hits < 5)
{
if (quota == 0 || delta > quota)
{
ds_diction_touch(del, sr->token, "", 0);
}
else if (sr->innocent_hits == 0 && sr->spam_hits == 1 &&
(nospam == 0 || delta > nospam))
{
ds_diction_touch(del, sr->token, "", 0);
}
else if (sr->innocent_hits == 1 && sr->spam_hits == 0 &&
(onehit == 0 || delta > onehit))
{
ds_diction_touch(del, sr->token, "", 0);
}
}
free (sr);
sr = _ds_get_nexttoken (CTX);
}
_ds_delall_spamrecords(CTX, del);
ds_diction_destroy(del);
return 0;
}
void
dieout (int signal)
{
signal = signal; /* Keep compiler happy */
fprintf (stderr, "terminated.\n");
if (open_ctx != NULL)
dspam_destroy (open_ctx);
if (open_mtx != NULL)
dspam_destroy (open_mtx);
_ds_destroy_config(agent_config);
exit (EXIT_SUCCESS);
}