/*
* EnderUNIX Software Development Team, (c) 2002
* Istanbul / Turkiye
*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include <sys/types.h>
#include "loadconfig.h"
#include "functions.h"
#include "wildmat.h"
extern char mail_command[VALSIZE];
extern char makemap_command[VALSIZE];
extern char sysadmin[VALSIZE];
extern char statfile[VALSIZE];
extern char badmailfile[VALSIZE];
extern int wcnt;
extern int bcnt;
extern int pcnt;
extern int w;
extern int b;
extern int p;
/* check if the supplied mail address exist in our "ignored" linked list */
int isIgnored(char *email)
{
iaddr *l = iaddrlist;
for ( ; l != NULL; l = l->next) {
if (DoMatch(email, l->mail) == TRUE)
return 1;
}
return -1;
}
/* Check if the email address if already in list.
* If so, increment its hit count; if not,
* add it to end of the list */
void check_addr(char *email)
{
int h;
maddr *sym = NULL;
/* Calculate hash sum, locate and inc. cnt if email exists,
* otherwise place it in spammer_hash */
h = hash(email);
for (sym = spammer_hash[h]; sym != NULL; sym = sym->next)
if (strcmp(email, sym->mail) == 0) {
sym->cnt++;
return;
}
sym = (maddr *)malloc(sizeof(maddr));
/* No need a malloc for mail, because, email's been malloc'ed before */
sym->mail = email;
sym->cnt = 1;
sym->next = spammer_hash[h];
spammer_hash[h] = sym;
return;
}
void addToIgnored(char *email)
{
iaddr *new = NULL;
new = (iaddr *)malloc(sizeof(iaddr));
new->mail = email;
new->next = iaddrlist;
iaddrlist = new;
}
/* remove some unnecessary characters */
void rmspace(char *s, char *t)
{
while( *s != '\0') {
if (*s == ' ' || *s == '\n' || *s == '\r' || *s == '\t')
s++;
else
*t++ = *s++;
}
}
/* notifying system administrator of spammer activity */
int send_notify_mail(char *n)
{
FILE *inpp;
char tmpfile[BUFSIZE];
char mailcmd[BUFSIZE];
int fd, retval, ret;
size_t bytes;
strncpy(tmpfile, "/tmp/qstspam-XXXXXX", BUFSIZE);
if ((fd = mkstemp(tmpfile)) == -1) {
puts("Couldn't create temporary file name");
perror("mkstemp");
return errno;
}
if ((bytes = write(fd, n, strlen(n))) < bytes) {
fprintf(stderr, "Couldn't write to temporary file");
return errno;
}
if ((ret = close(fd)) == -1) {
fprintf(stderr, "Couldn't close temporary file");
perror("close");
return errno;
}
strcpy(mailcmd, mail_command);
strcat(mailcmd, " -s \"spamGuard notification!\" ");
strcat(mailcmd, sysadmin);
strcat(mailcmd, " < ");
strcat(mailcmd, tmpfile);
if ((inpp = popen(mailcmd, "r")) == NULL) {
fprintf(stderr, "Couldn't send mail");
perror("popen");
return errno;
}
if ((retval = pclose(inpp)) == -1) {
perror("pclose");
return errno;
}
if ((ret = unlink(tmpfile)) == -1) {
perror("unlink");
return errno;
}
return retval;
}
unsigned int hash(char *str)
{
unsigned int h;
unsigned char *p = NULL;
h = 0;
for (p = (unsigned char *)str; *p != '\0'; p++)
h = MULTIPLIER * h + *p;
return h % MAXADDR;
}
void save_pos(hist_stat *h)
{
FILE *fp;
if ((fp = fopen(statfile, "w")) == NULL) {
fprintf(stderr, "Couldn't open %s: %s\n", statfile, strerror(errno));
return;
}
fprintf(fp, "%d %d", h->inode, h->saved_pos);
if ((fclose(fp)) == -1) {
fprintf(stderr, "Couldn't close %s: %s\n", statfile, strerror(errno));
return;
}
}
void get_saved_pos(hist_stat *h)
{
FILE *fp;
char inode[16];
char pos[16];
if ((fp = fopen(statfile, "r")) == NULL) {
fprintf(stderr, "Couldn't open %s: %s\n", statfile, strerror(errno));
return;
}
fscanf(fp, "%s %s", inode, pos);
if (inode != NULL)
h->inode = atoi(inode);
if (pos != NULL)
h->saved_pos = atoi(pos);
if ((fclose(fp)) == -1) {
fprintf(stderr, "Couldn't close %s: %s\n", statfile, strerror(errno));
return;
}
}
int makemap(void)
{
FILE *fp;
int retval;
if ((fp = popen(makemap_command, "r")) == NULL) {
fprintf(stderr, "Couldn't create hash database file\n");
perror("popen");
}
if ((retval = pclose(fp)) == -1) {
perror("pclose");
return errno;
}
return retval;
}
/* loads ignore user list from spam-ignore.txt */
void loadIgnoreList(char *fn)
{
FILE *fp;
char buf[1024];
char *t;
t = (char *) calloc(1024, sizeof(char));
if ((fp = fopen(fn, "r")) == NULL) {
fprintf(stderr, "fopen: %s: %s\n", fn, strerror(errno));
exit(-1);
}
memset(buf, 0, 1024);
memset(t, 0, 1024);
while ((fgets(buf, 1024, fp)) != NULL) {
rmspace(buf, t);
addToIgnored(strdup(t));
memset(t, 0, 1024);
memset(buf, 0, 1024);
}
free(t);
fclose(fp);
}
/* fills our ignore list. these addresses will not be treated as spammers */
void loadIgnore_sendmail(char *fn)
{
FILE *fp;
char buf[1024];
char *m;
char *t;
if ((fp = fopen(fn, "r")) == NULL) {
fprintf(stderr, "fopen: %s: %s\n", fn, strerror(errno));
exit(-1);
}
memset(buf, 0, 1024);
while ((fgets(buf, 1024, fp)) != NULL) {
if (buf[0] == '#' || buf[0] == ' ')
continue;
m = strtok(buf, "\t");
t = (char *)calloc(strlen(m), sizeof(char));
rmspace(m, t);
addToIgnored(t);
memset(buf, 0, 1024);
}
fclose(fp);
}
/* This function reads the logfile and fills the " from " linked list */
/* traverse "from" linked list and decide whether the hit count per mail address
* exceeds the "spammer threshold" */
int qmail_finalize(void)
{
FILE *fp;
maddr *ptr;
char mailbuf[2048];
int spamcnt = 0;
int i;
if ((fp = fopen(badmailfile, "a+")) == NULL) {
fprintf(stderr, "fopen: %s: %s\n", badmailfile, strerror(errno));
exit(-1);
}
for (i = 0; i < MAXADDR; i++)
for (ptr = spammer_hash[i]; ptr != NULL; ptr = ptr->next) {
/* printf ("mail: %s\n", ptr->mail); */
if ((ptr->cnt < bcnt) && w == 1 && (ptr->cnt >= wcnt) && (isIgnored(ptr->mail) < 0)) {
printf("Light Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n This mail is to notify you that this email address sent more emails than\n your \"warning threshold\", I'm not adding it to %s\n\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION);
send_notify_mail(mailbuf);
}
else
if (ptr->cnt > bcnt) {
if (p == 1 && (ptr->cnt >= pcnt)) {
spamcnt = 1;
fprintf(fp, "%s\n", ptr->mail);
printf("Paranoid Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n No matter this mail address is matched against your ignore list, or not,\n I'm still adding it to blacklist since s/he sent more mails then\n your paranoid threshold.\n\n Source mail address has been added to %s file\n Target successfully nuked!\n\n Regards,\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION);
send_notify_mail(mailbuf);
}
else if ((isIgnored(ptr->mail)) < 0) {
spamcnt = 1;
fprintf(fp, "%s\n", ptr->mail);
printf("Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n Source mail address has been added to %s file\n Target successfully nuked!\n\n Regards,\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION);
send_notify_mail(mailbuf);
}
}
}
fclose(fp);
return spamcnt;
}
int sendmail_finalize(void)
{
FILE *fp;
maddr *ptr;
char mailbuf[2048];
int spamcnt = 0;
int i;
if ((fp = fopen(badmailfile, "a+")) == NULL) {
fprintf(stderr, "fopen: %s: %s\n", badmailfile, strerror(errno));
exit(-1);
}
for (i = 0; i < MAXADDR; i++)
for (ptr = spammer_hash[i]; ptr != NULL; ptr = ptr->next) {
if ((ptr->cnt < bcnt) && w && (ptr->cnt >= wcnt) && (isIgnored(ptr->mail) < 0)) {
printf("Light Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n This mail is to notify you that this email address sent more emails than\n your \"warning threshold\", I'm not adding it to %s\n\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION);
send_notify_mail(mailbuf);
}
else
if (ptr->cnt > bcnt) {
if (p && (ptr->cnt >= pcnt)) {
spamcnt = 1;
fprintf(fp, "%s\tERROR:\"550: Your address is blocked because of spammer activity [http://www.enderunix.org/spamguard]\"\n", ptr->mail);
printf("Paranoid Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n No matter this mail address is matched against your ignore list, or not,\n I'm still adding it to blacklist since s/he sent more mails then\n your paranoid threshold.\n\n Source mail address has been added to %s file\n Target successfully nuked!\n\n Regards,\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION);
send_notify_mail(mailbuf);
}
else if ((isIgnored(ptr->mail)) < 0) {
spamcnt = 1;
fprintf(fp, "%s\tERROR:\"550: Your address is blocked because of spammer activity [http://www.enderunix.org/spamguard]\"\n", ptr->mail);
printf("Spammer:%s sent %d mails\n", ptr->mail, ptr->cnt);
sprintf(mailbuf, " %s has been spamming your box! (sent %d mails)\n Source mail address has been added to %s file\n Target successfully nuked!\n\n Regards,\n -EnderUNIX spamGuard %s\n http://www.enderunix.org/spamguard\n", ptr->mail, ptr->cnt, badmailfile, VERSION);
send_notify_mail(mailbuf);
}
}
}
fclose(fp);
return spamcnt;
}
void print_list(int list)
{
int i;
maddr *m;
list = 0;
for (i = 0; i < MAXADDR; i++)
if (spammer_hash[i] != NULL)
for (m = spammer_hash[i]; m != NULL; m = m->next)
printf("%s - %d mails\n", m->mail, m->cnt);
}
syntax highlighted by Code2HTML, v. 0.9.1