This commit is contained in:
SJ 2011-11-19 21:25:44 +01:00
parent 29f312a8d2
commit d7318f94cf
17 changed files with 510 additions and 70 deletions

2
configure vendored
View File

@ -4285,7 +4285,7 @@ echo; echo
CFLAGS="$static -O2 -Wall -g" CFLAGS="$static -O2 -Wall -g"
LIBS="$antispam_libs $sunos_libs $sqlite3_libs" LIBS="$antispam_libs $sunos_libs $sqlite3_libs"
OBJS="dirs.o misc.o counters.o cfg.o sig.o decoder.o list.o parser.o parser_utils.o session.o message.o digest.o store.o tai.o $objs" OBJS="dirs.o misc.o counters.o cfg.o sig.o decoder.o list.o parser.o parser_utils.o rules.o session.o message.o attachment.o digest.o store.o tai.o $objs"
ac_config_files="$ac_config_files Makefile src/Makefile" ac_config_files="$ac_config_files Makefile src/Makefile"

View File

@ -317,7 +317,7 @@ echo; echo
CFLAGS="$static -O2 -Wall -g" CFLAGS="$static -O2 -Wall -g"
LIBS="$antispam_libs $sunos_libs $sqlite3_libs" LIBS="$antispam_libs $sunos_libs $sqlite3_libs"
OBJS="dirs.o misc.o counters.o cfg.o sig.o decoder.o list.o parser.o parser_utils.o session.o message.o digest.o store.o tai.o $objs" OBJS="dirs.o misc.o counters.o cfg.o sig.o decoder.o list.o parser.o parser_utils.o rules.o session.o message.o attachment.o digest.o store.o tai.o $objs"
AC_CONFIG_FILES([Makefile src/Makefile]) AC_CONFIG_FILES([Makefile src/Makefile])
AC_OUTPUT AC_OUTPUT

77
src/attachment.c Normal file
View File

@ -0,0 +1,77 @@
/*
* attachment.c, SJ
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#include <piler.h>
int store_attachments(struct session_data *sdata, struct _state *state, struct __config *cfg){
uint64 id=0;
int i, found;
char s[SMALLBUFSIZE];
MYSQL_RES *res;
MYSQL_ROW row;
for(i=0; i<state->n_attachments; i++){
found = 0;
id = 0;
if(strlen(state->attachments[i].filename) > 4){
snprintf(s, sizeof(s)-1, "SELECT `id` FROM `%s` WHERE `sig`='%s'", SQL_ATTACHMENT_TABLE, state->attachments[i].digest);
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: check for attachment sql: *%s*", sdata->ttmpfile, s);
if(mysql_real_query(&(sdata->mysql), s, strlen(s)) == 0){
res = mysql_store_result(&(sdata->mysql));
if(res != NULL){
row = mysql_fetch_row(res);
if(row){
id = strtoull(row[0], NULL, 10);
found = 1;
}
mysql_free_result(res);
}
}
if(found == 0){
if(store_file(sdata, state->attachments[i].internalname, 0, 0, cfg) == 0){
syslog(LOG_PRIORITY, "%s: error storing attachment: %s", sdata->ttmpfile, state->attachments[i].internalname);
return 1;
}
}
snprintf(s, sizeof(s)-1, "INSERT INTO %s (`piler_id`,`attachment_id`,`sig`,`ptr`) VALUES('%s',%d,'%s',%llu)", SQL_ATTACHMENT_TABLE, sdata->ttmpfile, i, state->attachments[i].digest, id);
if(mysql_real_query(&(sdata->mysql), s, strlen(s))){
syslog(LOG_PRIORITY, "%s attachment sql error: *%s*", sdata->ttmpfile, mysql_error(&(sdata->mysql)));
if(found == 0){
/* TODO: remove the previously stored attachment */
}
return 1;
}
}
else {
syslog(LOG_PRIORITY, "%s: skipping attachment (serial: %d, size: %d, digest: %s)", sdata->ttmpfile, i, state->attachments[i].size, state->attachments[i].digest);
}
}
return 0;
}

View File

@ -11,7 +11,7 @@
#define PROGNAME "piler" #define PROGNAME "piler"
#define VERSION "0.1.3" #define VERSION "0.1.5"
#define PROGINFO VERSION ", Janos SUTO <sj@acts.hu>\n\n" CONFIGURE_PARAMS "\n\nSend bugs/issues to https://jira.acts.hu:8443/\n" #define PROGINFO VERSION ", Janos SUTO <sj@acts.hu>\n\n" CONFIGURE_PARAMS "\n\nSend bugs/issues to https://jira.acts.hu:8443/\n"
@ -19,7 +19,7 @@
#define CONFIG_FILE CONFDIR "/piler.conf" #define CONFIG_FILE CONFDIR "/piler.conf"
#define WORK_DIR DATADIR "/spool/piler/tmp" #define WORK_DIR DATADIR "/spool/piler/tmp"
#define QUEUE_DIR DATADIR "/piler/new" #define QUEUE_DIR DATADIR "/piler/store"
#define DEFER_DIR DATADIR "/spool/piler/deferred" #define DEFER_DIR DATADIR "/spool/piler/deferred"
#define CLAMD_SOCKET "/tmp/clamd" #define CLAMD_SOCKET "/tmp/clamd"
@ -73,8 +73,8 @@
#define SQL_SPHINX_TABLE "sph_index" #define SQL_SPHINX_TABLE "sph_index"
#define SQL_METADATA_TABLE "metadata" #define SQL_METADATA_TABLE "metadata"
#define SQL_HEADER_TABLE "header" #define SQL_ATTACHMENT_TABLE "attachment"
#define SQL_BODY_TABLE "body" #define SQL_ARCHIVING_RULE_TABLE "archiving_rule"
#define SQL_COUNTER_TABLE "counter" #define SQL_COUNTER_TABLE "counter"

View File

@ -54,14 +54,31 @@ struct attachment {
int size; int size;
char type[TINYBUFSIZE]; char type[TINYBUFSIZE];
char filename[TINYBUFSIZE]; char filename[TINYBUFSIZE];
char internalname[TINYBUFSIZE];
char digest[2*DIGEST_LENGTH+1];
}; };
struct list { struct list {
char s[SMALLBUFSIZE]; char s[SMALLBUFSIZE];
struct list *r; struct list *r;
}; };
struct rule {
#ifdef HAVE_TRE
regex_t from;
regex_t to;
regex_t subject;
#endif
int size;
char _size[4];
char *rulestr;
char compiled;
struct rule *r;
};
struct _state { struct _state {
int line_num; int line_num;
int message_state; int message_state;
@ -78,9 +95,12 @@ struct _state {
int skip_html; int skip_html;
int has_to_dump; int has_to_dump;
int fd; int fd;
int mfd;
int octetstream; int octetstream;
int realbinary; int realbinary;
int content_type_is_set; int content_type_is_set;
int pushed_pointer;
int saved_size;
char attachedfile[RND_STR_LEN+SMALLBUFSIZE]; char attachedfile[RND_STR_LEN+SMALLBUFSIZE];
char message_id[SMALLBUFSIZE]; char message_id[SMALLBUFSIZE];
char miscbuf[MAX_TOKEN_LEN]; char miscbuf[MAX_TOKEN_LEN];
@ -99,7 +119,7 @@ struct _state {
struct session_data { struct session_data {
char ttmpfile[SMALLBUFSIZE], tre; char ttmpfile[SMALLBUFSIZE], tmpframe[SMALLBUFSIZE], tre;
char mailfrom[SMALLBUFSIZE], rcptto[MAX_RCPT_TO][SMALLBUFSIZE], client_addr[SMALLBUFSIZE]; char mailfrom[SMALLBUFSIZE], rcptto[MAX_RCPT_TO][SMALLBUFSIZE], client_addr[SMALLBUFSIZE];
char acceptbuf[SMALLBUFSIZE]; char acceptbuf[SMALLBUFSIZE];
char whitelist[MAXBUFSIZE], blacklist[MAXBUFSIZE]; char whitelist[MAXBUFSIZE], blacklist[MAXBUFSIZE];
@ -158,15 +178,8 @@ struct memcached_server {
struct __data { struct __data {
struct url *blackhole;
#ifdef HAVE_LIBCLAMAV
struct cl_engine *engine;
#endif
#ifdef HAVE_TRE #ifdef HAVE_TRE
regex_t pregs[NUM_OF_REGEXES]; struct rule *rules;
int n_regex;
#endif #endif
#ifdef HAVE_MEMCACHED #ifdef HAVE_MEMCACHED

View File

@ -61,3 +61,29 @@ int make_body_digest(struct session_data *sdata, struct __config *cfg){
} }
void digest_file(char *filename, char *digest){
int fd, i, n;
unsigned char buf[MAXBUFSIZE], md[DIGEST_LENGTH];
SHA256_CTX context;
memset(digest, 0, 2*DIGEST_LENGTH+1);
fd = open(filename, O_RDONLY);
if(fd == -1) return;
SHA256_Init(&context);
while((n = read(fd, buf, MAXBUFSIZE)) > 0){
SHA256_Update(&context, buf, n);
}
close(fd);
SHA256_Final(md, &context);
for(i=0;i<DIGEST_LENGTH;i++)
snprintf(digest + i*2, 2*DIGEST_LENGTH, "%02x", md[i]);
}

View File

@ -229,7 +229,7 @@ ENDE_META:
int processMessage(struct session_data *sdata, struct _state *state, struct __config *cfg){ int processMessage(struct session_data *sdata, struct _state *state, struct __config *cfg){
int rc; int i, rc;
/* discard if existing message_id */ /* discard if existing message_id */
@ -242,7 +242,25 @@ int processMessage(struct session_data *sdata, struct _state *state, struct __co
rc = is_body_digest_already_stored(sdata, state, cfg); rc = is_body_digest_already_stored(sdata, state, cfg);
rc = store_message(sdata, state, rc, cfg); /*
* TODO: check if the bodydigest were stored, then we should
* only store the header and append a 'bodypointer'
*/
if(store_attachments(sdata, state, cfg)) return ERR;
for(i=0; i<state->n_attachments; i++){
unlink(state->attachments[i].internalname);
}
rc = store_file(sdata, sdata->tmpframe, 0, 0, cfg);
if(rc == 0){
syslog(LOG_PRIORITY, "%s: error storing message: %s", sdata->ttmpfile, sdata->tmpframe);
return ERR;
}
rc = store_meta_data(sdata, state, cfg); rc = store_meta_data(sdata, state, cfg);

View File

@ -20,7 +20,7 @@ struct _state parse_message(struct session_data *sdata, struct __config *cfg){
FILE *f; FILE *f;
char buf[MAXBUFSIZE]; char buf[MAXBUFSIZE];
struct _state state; struct _state state;
int len; int i, len;
init_state(&state); init_state(&state);
@ -30,15 +30,31 @@ struct _state parse_message(struct session_data *sdata, struct __config *cfg){
return state; return state;
} }
while(fgets(buf, MAXBUFSIZE-1, f)){
parse_line(buf, &state, sdata, cfg); state.mfd = open(sdata->tmpframe, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
if(state.mfd == -1){
syslog(LOG_PRIORITY, "%s: cannot open frame file: %s", sdata->ttmpfile, sdata->tmpframe);
return state;
} }
while(fgets(buf, sizeof(buf)-1, f)){
parse_line(buf, &state, sdata, cfg);
}
close(state.mfd); state.mfd = 0;
fclose(f); fclose(f);
free_list(state.boundaries); free_list(state.boundaries);
for(i=0; i<state.n_attachments; i++){
digest_file(state.attachments[i].internalname, &(state.attachments[i].digest[0]));
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: attachment list: i:%d, name=*%s*, type: *%s*, size: %d, int.name: %s, digest: %s\n", sdata->ttmpfile, i, state.attachments[i].filename, state.attachments[i].type, state.attachments[i].size, state.attachments[i].internalname, state.attachments[i].digest);
}
if(state.message_id[0] == 0) snprintf(state.message_id, SMALLBUFSIZE-1, "null"); if(state.message_id[0] == 0) snprintf(state.message_id, SMALLBUFSIZE-1, "null");
len = strlen(state.b_from); len = strlen(state.b_from);
@ -59,6 +75,26 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, stru
state->line_num++; state->line_num++;
len = strlen(buf);
if(state->message_state == MSG_BODY && state->has_to_dump == 1 && state->pushed_pointer == 0){
snprintf(puf, sizeof(puf)-1, "ATTACHMENT_POINTER_%s.%d\n", sdata->ttmpfile, state->n_attachments);
write(state->mfd, puf, strlen(puf));
state->pushed_pointer = 1;
}
if(state->message_state == MSG_BODY && state->has_to_dump == 1 && is_item_on_string(state->boundaries, buf) == 0){
//printf("dumping: %s", buf);
write(state->fd, buf, len);
state->attachments[state->n_attachments].size += len;
}
else {
state->saved_size += len;
//printf("%s", buf);
write(state->mfd, buf, len);
}
if(*buf == '.' && *(buf+1) == '.') buf++; if(*buf == '.' && *(buf+1) == '.') buf++;
@ -138,8 +174,6 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, stru
if(p) *p = '\0'; if(p) *p = '\0';
} }
extractNameFromHeaderLine(buf, "name", state->attachments[state->n_attachments].filename);
if(strcasestr(buf, "text/plain") || if(strcasestr(buf, "text/plain") ||
strcasestr(buf, "multipart/mixed") || strcasestr(buf, "multipart/mixed") ||
@ -165,14 +199,19 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, stru
if(strcasestr(buf, "charset") && strcasestr(buf, "UTF-8")) state->utf8 = 1; if(strcasestr(buf, "charset") && strcasestr(buf, "UTF-8")) state->utf8 = 1;
}
if(strlen(state->attachments[state->n_attachments].filename) > 4){ if(state->message_state == MSG_CONTENT_TYPE || state->message_state == MSG_CONTENT_DISPOSITION){
if(strlen(state->attachments[state->n_attachments].filename) < 5){
extractNameFromHeaderLine(buf, "name", state->attachments[state->n_attachments].filename);
snprintf(state->attachments[state->n_attachments].internalname, TINYBUFSIZE-1, "%s.a%d", sdata->ttmpfile, state->n_attachments);
}
if(strlen(state->attachments[state->n_attachments].filename) > 4 && state->has_to_dump == 0){
state->has_to_dump = 1; state->has_to_dump = 1;
snprintf(puf, sizeof(puf)-1, "%s.%d", sdata->ttmpfile, state->n_attachments); //printf("DUMP FILE: %s\n", state->attachments[state->n_attachments].internalname);
printf("dump file: %s\n", puf); state->fd = open(state->attachments[state->n_attachments].internalname, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
//state->fd = open(u, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
} }
} }
@ -205,7 +244,10 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, stru
if(state->n_attachments < MAX_ATTACHMENTS-1) state->n_attachments++; if(state->n_attachments < MAX_ATTACHMENTS-1) state->n_attachments++;
/* use the previous attachment slot if it was not an attached file */ /*
Use the previous attachment slot if there was not an attached file.
This is also the case if the filename field is empty.
*/
if(state->n_attachments > 0 && strlen(state->attachments[state->n_attachments-1].filename) < 5){ if(state->n_attachments > 0 && strlen(state->attachments[state->n_attachments-1].filename) < 5){
state->n_attachments--; state->n_attachments--;
} }
@ -219,6 +261,8 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, stru
state->realbinary = 0; state->realbinary = 0;
state->pushed_pointer = 0;
return 0; return 0;
} }
@ -237,16 +281,8 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, stru
} }
if(state->message_state == MSG_BODY){ /* don't process body if it's not a text or html part */
if(state->message_state == MSG_BODY && state->textplain == 0 && state->texthtml == 0) return 0;
if(state->has_to_dump == 1){
//printf("dumping: %s *%s*\n", state->attachments[state->n_attachments].filename, buf);
state->attachments[state->n_attachments].size += strlen(buf);
}
/* don't process body if it's not a text or html part */
if(state->textplain == 0 && state->texthtml == 0) return 0;
}
if(state->base64 == 1 && state->message_state == MSG_BODY){ if(state->base64 == 1 && state->message_state == MSG_BODY){

View File

@ -49,8 +49,11 @@ void init_state(struct _state *state){
state->has_to_dump = 0; state->has_to_dump = 0;
state->fd = -1; state->fd = -1;
state->mfd = -1;
state->realbinary = 0; state->realbinary = 0;
state->octetstream = 0; state->octetstream = 0;
state->pushed_pointer = 1;
state->saved_size = 0;
state->boundaries = NULL; state->boundaries = NULL;
@ -61,6 +64,8 @@ void init_state(struct _state *state){
state->attachments[i].size = 0; state->attachments[i].size = 0;
memset(state->attachments[i].type, 0, TINYBUFSIZE); memset(state->attachments[i].type, 0, TINYBUFSIZE);
memset(state->attachments[i].filename, 0, TINYBUFSIZE); memset(state->attachments[i].filename, 0, TINYBUFSIZE);
memset(state->attachments[i].internalname, 0, TINYBUFSIZE);
memset(state->attachments[i].digest, 0, 2*DIGEST_LENGTH+1);
} }
memset(state->b_from, 0, SMALLBUFSIZE); memset(state->b_from, 0, SMALLBUFSIZE);

View File

@ -38,6 +38,8 @@ struct passwd *pwd;
void clean_exit(){ void clean_exit(){
if(sd != -1) close(sd); if(sd != -1) close(sd);
free_rule(data.rules);
syslog(LOG_PRIORITY, "%s has been terminated", PROGNAME); syslog(LOG_PRIORITY, "%s has been terminated", PROGNAME);
unlink(cfg.pidfile); unlink(cfg.pidfile);
@ -61,7 +63,8 @@ void sigchld(){
} }
void initialiseConfiguration(){ void initialise_configuration(){
struct session_data sdata;
cfg = read_config(configfile); cfg = read_config(configfile);
@ -84,7 +87,21 @@ void initialiseConfiguration(){
setlocale(LC_MESSAGES, cfg.locale); setlocale(LC_MESSAGES, cfg.locale);
setlocale(LC_CTYPE, cfg.locale); setlocale(LC_CTYPE, cfg.locale);
data.blackhole = NULL;
free_rule(data.rules);
data.rules = NULL;
mysql_init(&(sdata.mysql));
mysql_options(&(sdata.mysql), MYSQL_OPT_CONNECT_TIMEOUT, (const char*)&cfg.mysql_connect_timeout);
if(mysql_real_connect(&(sdata.mysql), cfg.mysqlhost, cfg.mysqluser, cfg.mysqlpwd, cfg.mysqldb, cfg.mysqlport, cfg.mysqlsocket, 0) == 0){
syslog(LOG_PRIORITY, "cannot connect to mysql server");
return;
}
load_archiving_rules(&sdata, &(data.rules));
mysql_close(&(sdata.mysql));
syslog(LOG_PRIORITY, "reloaded config: %s", configfile); syslog(LOG_PRIORITY, "reloaded config: %s", configfile);
@ -147,17 +164,17 @@ int main(int argc, char **argv){
sig_catch(SIGQUIT, clean_exit); sig_catch(SIGQUIT, clean_exit);
sig_catch(SIGKILL, clean_exit); sig_catch(SIGKILL, clean_exit);
sig_catch(SIGTERM, clean_exit); sig_catch(SIGTERM, clean_exit);
sig_catch(SIGHUP, initialiseConfiguration); sig_catch(SIGHUP, initialise_configuration);
data.blackhole = NULL; data.rules = NULL;
sig_block(SIGCHLD); sig_block(SIGCHLD);
sig_catch(SIGCHLD, sigchld); sig_catch(SIGCHLD, sigchld);
initialiseConfiguration(); initialise_configuration();
if(read_key(&cfg)) fatal(ERR_READING_KEY); if(read_key(&cfg)) fatal(ERR_READING_KEY);

View File

@ -13,9 +13,12 @@
#include <session.h> #include <session.h>
#include <decoder.h> #include <decoder.h>
#include <list.h> #include <list.h>
#include <rules.h>
#include <defs.h> #include <defs.h>
#include <tai.h>
#include <sig.h> #include <sig.h>
#include <av.h> #include <av.h>
#include <rules.h>
#include <config.h> #include <config.h>
#include <unistd.h> #include <unistd.h>
@ -26,9 +29,11 @@
int do_av_check(struct session_data *sdata, char *rcpttoemail, char *fromemail, char *virusinfo, struct __data *data, struct __config *cfg); int do_av_check(struct session_data *sdata, char *rcpttoemail, char *fromemail, char *virusinfo, struct __data *data, struct __config *cfg);
int make_body_digest(struct session_data *sdata, struct __config *cfg); int make_body_digest(struct session_data *sdata, struct __config *cfg);
void digest_file(char *filename, char *digest);
int processMessage(struct session_data *sdata, struct _state *sstate, struct __config *cfg); int processMessage(struct session_data *sdata, struct _state *sstate, struct __config *cfg);
int store_message(struct session_data *sdata, struct _state *state, int stored, struct __config *cfg); int store_file(struct session_data *sdata, char *filename, int startpos, int len, struct __config *cfg);
int store_attachments(struct session_data *sdata, struct _state *state, struct __config *cfg);
struct __config read_config(char *configfile); struct __config read_config(char *configfile);

154
src/rules.c Normal file
View File

@ -0,0 +1,154 @@
/*
* rules.c, SJ
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <piler.h>
#include "rules.h"
void load_archiving_rules(struct session_data *sdata, struct rule **rules){
char s[SMALLBUFSIZE];
MYSQL_RES *res;
MYSQL_ROW row;
snprintf(s, sizeof(s)-1, "SELECT `from`, `to`, `subject`, `_size`, `size` FROM `%s`", SQL_ARCHIVING_RULE_TABLE);
if(mysql_real_query(&(sdata->mysql), s, strlen(s)) == 0){
res = mysql_store_result(&(sdata->mysql));
if(res != NULL){
while((row = mysql_fetch_row(res))){
append_rule(rules, (char*)row[0], (char*)row[1], (char*)row[2], (char*)row[3], atoi(row[4]));
}
mysql_free_result(res);
}
}
}
int append_rule(struct rule **rule, char *from, char *to, char *subject, char *_size, int size){
struct rule *q, *t, *u=NULL;
q = *rule;
while(q){
u = q;
q = q->r;
}
t = create_rule_item(from, to, subject, _size, size);
if(t){
if(*rule == NULL)
*rule = t;
else if(u)
u->r = t;
return 1;
}
return -1;
}
struct rule *create_rule_item(char *from, char *to, char *subject, char *_size, int size){
struct rule *h=NULL;
char empty = '\0';
int len;
if((h = malloc(sizeof(struct rule))) == NULL)
return NULL;
h->compiled = 1;
if(!from) from = &empty;
if(regcomp(&(h->from), from, REG_ICASE | REG_EXTENDED)) h->compiled = 0;
if(!to) to = &empty;
if(regcomp(&(h->to), to, REG_ICASE | REG_EXTENDED)) h->compiled = 0;
if(!subject) subject = &empty;
if(regcomp(&(h->subject), subject, REG_ICASE | REG_EXTENDED)) h->compiled = 0;
h->size = size;
if(!_size) _size = &empty;
snprintf(h->_size, 3, "%s", _size);
len = strlen(from)+6 + strlen(to)+4 + strlen(subject)+9 + strlen(_size)+6 + 15;
h->rulestr = malloc(len);
if(h->rulestr) snprintf(h->rulestr, len-1, "from=%s,to=%s,subject=%s,size%s%d", from, to, subject, _size, size);
else h->compiled = 0;
h->r = NULL;
return h;
}
char *check_againt_ruleset(struct rule *rule, char *from, char *to, char *subject, int size){
size_t nmatch=0;
struct rule *p;
p = rule;
while(p != NULL){
if(
p->compiled == 1 &&
regexec(&(p->from), from, nmatch, NULL, 0) == 0 &&
regexec(&(p->to), to, nmatch, NULL, 0) == 0 &&
regexec(&(p->subject), subject, nmatch, NULL, 0) == 0 &&
check_size_rule(size, p->size, p->_size) == 1
){
return p->rulestr;
}
p = p->r;
}
return NULL;
}
int check_size_rule(int message_size, int size, char *_size){
if(size <= 0) return 1;
if(strcmp(_size, ">") == 0 && message_size > size) return 1;
if(strcmp(_size, "<") == 0 && message_size < size) return 1;
if(strcmp(_size, "=") == 0 && message_size == size) return 1;
if( (strcmp(_size, "<>") == 0 || strcmp(_size, "!=") == 0) && message_size != size) return 1;
return 0;
}
void free_rule(struct rule *rule){
struct rule *p, *q;
p = rule;
while(p != NULL){
q = p->r;
if(p){
regfree(&(p->from));
regfree(&(p->to));
free(p->rulestr);
free(p);
}
p = q;
}
}

18
src/rules.h Normal file
View File

@ -0,0 +1,18 @@
/*
* rules.h, SJ
*/
#ifndef _RULES_H
#define _RULES_H
#include "defs.h"
void load_archiving_rules(struct session_data *sdata, struct rule **rules);
int append_rule(struct rule **rule, char *from, char *to, char *subject, char *_size, int size);
struct rule *create_rule_item(char *from, char *to, char *subject, char *_size, int size);
char *check_againt_ruleset(struct rule *rule, char *from, char *to, char *subject, int size);
int check_size_rule(int message_size, int size, char *_size);
void free_rule(struct rule *rule);
#endif /* _RULES_H */

View File

@ -20,6 +20,7 @@ void handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg){
int i, ret, pos, n, inj=ERR, state, prevlen=0; int i, ret, pos, n, inj=ERR, state, prevlen=0;
char *p, buf[MAXBUFSIZE], puf[MAXBUFSIZE], resp[MAXBUFSIZE], prevbuf[MAXBUFSIZE], last2buf[2*MAXBUFSIZE+1]; char *p, buf[MAXBUFSIZE], puf[MAXBUFSIZE], resp[MAXBUFSIZE], prevbuf[MAXBUFSIZE], last2buf[2*MAXBUFSIZE+1];
char rctptoemail[SMALLBUFSIZE], fromemail[SMALLBUFSIZE], virusinfo[SMALLBUFSIZE], reason[SMALLBUFSIZE]; char rctptoemail[SMALLBUFSIZE], fromemail[SMALLBUFSIZE], virusinfo[SMALLBUFSIZE], reason[SMALLBUFSIZE];
char *arule = NULL;
struct session_data sdata; struct session_data sdata;
struct _state sstate; struct _state sstate;
int db_conn=0; int db_conn=0;
@ -184,7 +185,19 @@ void handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg){
inj = ERR; inj = ERR;
} else { } else {
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: processing message", sdata.ttmpfile); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: processing message", sdata.ttmpfile);
inj = processMessage(&sdata, &sstate, cfg);
/* check message against archiving rules */
arule = check_againt_ruleset(data->rules, sstate.b_from, sstate.b_to, sstate.b_subject, sdata.tot_len);
if(arule){
syslog(LOG_PRIORITY, "%s: discard message by policy: *%s*", sdata.ttmpfile, arule);
inj = OK;
}
else {
inj = processMessage(&sdata, &sstate, cfg);
}
} }
} }
@ -221,6 +234,7 @@ void handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg){
#endif #endif
unlink(sdata.ttmpfile); unlink(sdata.ttmpfile);
unlink(sdata.tmpframe);
alarm(cfg->session_timeout); alarm(cfg->session_timeout);
@ -381,6 +395,7 @@ AFTER_PERIOD:
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: sent: %s", sdata.ttmpfile, buf); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: sent: %s", sdata.ttmpfile, buf);
unlink(sdata.ttmpfile); unlink(sdata.ttmpfile);
unlink(sdata.tmpframe);
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: removed", sdata.ttmpfile); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: removed", sdata.ttmpfile);
goto QUITTING; goto QUITTING;
@ -399,6 +414,7 @@ AFTER_PERIOD:
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: removed", sdata.ttmpfile); if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: removed", sdata.ttmpfile);
unlink(sdata.ttmpfile); unlink(sdata.ttmpfile);
unlink(sdata.tmpframe);
initSessionData(&sdata); initSessionData(&sdata);
@ -472,6 +488,9 @@ void initSessionData(struct session_data *sdata){
create_id(&(sdata->ttmpfile[0])); create_id(&(sdata->ttmpfile[0]));
unlink(sdata->ttmpfile); unlink(sdata->ttmpfile);
snprintf(sdata->tmpframe, SMALLBUFSIZE-1, "%s.m", sdata->ttmpfile);
unlink(sdata->tmpframe);
memset(sdata->mailfrom, 0, SMALLBUFSIZE); memset(sdata->mailfrom, 0, SMALLBUFSIZE);
snprintf(sdata->client_addr, SMALLBUFSIZE-1, "null"); snprintf(sdata->client_addr, SMALLBUFSIZE-1, "null");

View File

@ -19,9 +19,9 @@
#include <openssl/evp.h> #include <openssl/evp.h>
int store_message(struct session_data *sdata, struct _state *state, int stored, struct __config *cfg){ int store_file(struct session_data *sdata, char *filename, int startpos, int len, struct __config *cfg){
int ret=0, rc, fd, n, len=sdata->tot_len; int ret=0, rc, fd, n;
char *addr, *p0, *p1, *p2, s[SMALLBUFSIZE]; char *addr, *p, *p0, *p1, *p2, s[SMALLBUFSIZE];
struct stat st; struct stat st;
Bytef *z=NULL; Bytef *z=NULL;
uLongf dstlen; uLongf dstlen;
@ -34,18 +34,17 @@ int store_message(struct session_data *sdata, struct _state *state, int stored,
struct timeval tv1, tv2; struct timeval tv1, tv2;
/* fix data length to store */ fd = open(filename, O_RDONLY);
/*if(stored == 1 && sdata->hdr_len > 100){
len = sdata->hdr_len;
}*/
fd = open(sdata->ttmpfile, O_RDONLY);
if(fd == -1) return ret; if(fd == -1) return ret;
if(len == 0){
if(fstat(fd, &st)) return ret;
len = st.st_size;
}
gettimeofday(&tv1, &tz); gettimeofday(&tv1, &tz);
addr = mmap(NULL, sdata->tot_len, PROT_READ, MAP_PRIVATE, fd, 0); addr = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
close(fd); close(fd);
if(addr == MAP_FAILED) return ret; if(addr == MAP_FAILED) return ret;
@ -55,7 +54,7 @@ int store_message(struct session_data *sdata, struct _state *state, int stored,
z = malloc(dstlen); z = malloc(dstlen);
if(z == NULL){ if(z == NULL){
munmap(addr, sdata->tot_len); munmap(addr, len);
return ret; return ret;
} }
@ -63,7 +62,7 @@ int store_message(struct session_data *sdata, struct _state *state, int stored,
gettimeofday(&tv2, &tz); gettimeofday(&tv2, &tz);
sdata->__compress += tvdiff(tv2, tv1); sdata->__compress += tvdiff(tv2, tv1);
munmap(addr, sdata->tot_len); munmap(addr, len);
if(rc != Z_OK) goto ENDE; if(rc != Z_OK) goto ENDE;
@ -84,9 +83,19 @@ int store_message(struct session_data *sdata, struct _state *state, int stored,
sdata->__encrypt += tvdiff(tv2, tv1); sdata->__encrypt += tvdiff(tv2, tv1);
/* create a filename according to piler_id */ /* create a filename in the store based on piler_id */
snprintf(s, sizeof(s)-1, "%s/%c%c/%c%c/%c%c/%s", cfg->queuedir, sdata->ttmpfile[RND_STR_LEN-6], sdata->ttmpfile[RND_STR_LEN-5], sdata->ttmpfile[RND_STR_LEN-4], sdata->ttmpfile[RND_STR_LEN-3], sdata->ttmpfile[RND_STR_LEN-2], sdata->ttmpfile[RND_STR_LEN-1], sdata->ttmpfile); p = strchr(filename, '.');
if(p) *p = '\0';
snprintf(s, sizeof(s)-1, "%s/%c%c/%c%c/%c%c/%s", cfg->queuedir, filename[RND_STR_LEN-6], filename[RND_STR_LEN-5], filename[RND_STR_LEN-4], filename[RND_STR_LEN-3], filename[RND_STR_LEN-2], filename[RND_STR_LEN-1], filename);
if(p){
*p = '.';
strncat(s, p, sizeof(s)-1);
}
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: trying to store %d bytes for %s", sdata->ttmpfile, len, filename);
p0 = strrchr(s, '/'); if(!p0) goto ENDE; p0 = strrchr(s, '/'); if(!p0) goto ENDE;
*p0 = '\0'; *p0 = '\0';
@ -97,16 +106,16 @@ int store_message(struct session_data *sdata, struct _state *state, int stored,
p2 = strrchr(s, '/'); if(!p2) goto ENDE; p2 = strrchr(s, '/'); if(!p2) goto ENDE;
*p2 = '\0'; *p2 = '\0';
mkdir(s, 0755); mkdir(s, 0750);
*p2 = '/'; *p2 = '/';
mkdir(s, 0755); mkdir(s, 0750);
*p1 = '/'; *p1 = '/';
mkdir(s, 0755); mkdir(s, 0770);
} }
*p0 = '/'; *p0 = '/';
fd = open(s, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); fd = open(s, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR|S_IRGRP);
if(fd == -1) goto ENDE; if(fd == -1) goto ENDE;
n = write(fd, outbuf, outlen); n = write(fd, outbuf, outlen);

View File

@ -16,11 +16,14 @@
int main(int argc, char **argv){ int main(int argc, char **argv){
int i, rc; int rc;
struct stat st; struct stat st;
struct session_data sdata; struct session_data sdata;
struct _state state; struct _state state;
struct __config cfg; struct __config cfg;
struct __data data;
char *rule;
if(argc < 2){ if(argc < 2){
fprintf(stderr, "usage: %s <message>\n", argv[0]); fprintf(stderr, "usage: %s <message>\n", argv[0]);
@ -34,9 +37,21 @@ int main(int argc, char **argv){
cfg = read_config(CONFIG_FILE); cfg = read_config(CONFIG_FILE);
mysql_init(&(sdata.mysql));
mysql_options(&(sdata.mysql), MYSQL_OPT_CONNECT_TIMEOUT, (const char*)&cfg.mysql_connect_timeout);
if(mysql_real_connect(&(sdata.mysql), cfg.mysqlhost, cfg.mysqluser, cfg.mysqlpwd, cfg.mysqldb, cfg.mysqlport, cfg.mysqlsocket, 0) == 0){
printf("cant connect to mysql server\n");
return 0;
}
printf("locale: %s\n", setlocale(LC_MESSAGES, cfg.locale)); printf("locale: %s\n", setlocale(LC_MESSAGES, cfg.locale));
setlocale(LC_CTYPE, cfg.locale); setlocale(LC_CTYPE, cfg.locale);
data.rules = NULL;
load_archiving_rules(&sdata, &(data.rules));
rc = 0; rc = 0;
sdata.num_of_rcpt_to = -1; sdata.num_of_rcpt_to = -1;
@ -45,6 +60,7 @@ int main(int argc, char **argv){
sdata.tot_len = st.st_size; sdata.tot_len = st.st_size;
memset(sdata.rcptto[0], 0, SMALLBUFSIZE); memset(sdata.rcptto[0], 0, SMALLBUFSIZE);
snprintf(sdata.ttmpfile, SMALLBUFSIZE-1, "%s", argv[1]); snprintf(sdata.ttmpfile, SMALLBUFSIZE-1, "%s", argv[1]);
snprintf(sdata.tmpframe, SMALLBUFSIZE-1, "%s.m", argv[1]);
state = parse_message(&sdata, &cfg); state = parse_message(&sdata, &cfg);
@ -52,15 +68,18 @@ int main(int argc, char **argv){
printf("from: *%s*\n", state.b_from); printf("from: *%s*\n", state.b_from);
printf("to: *%s*\n", state.b_to); printf("to: *%s*\n", state.b_to);
printf("subject: *%s*\n", state.b_subject); printf("subject: *%s*\n", state.b_subject);
printf("body: *%s*\n", state.b_body); //printf("body: *%s*\n", state.b_body);
make_body_digest(&sdata, &cfg); make_body_digest(&sdata, &cfg);
rule = check_againt_ruleset(data.rules, state.b_from, state.b_to, state.b_subject, st.st_size);
printf("body digest: %s\n", sdata.bodydigest); printf("body digest: %s\n", sdata.bodydigest);
for(i=0; i<state.n_attachments; i++){ printf("rules check: %s\n", rule);
printf("i:%d, name=*%s*, type: *%s*, size: %d\n", i, state.attachments[i].filename, state.attachments[i].type, state.attachments[i].size);
} mysql_close(&(sdata.mysql));
free_rule(data.rules);
printf("\n\n"); printf("\n\n");

View File

@ -42,6 +42,30 @@ create index metadata_idx on metadata(`piler_id`);
create index metadata_idx2 on metadata(`message_id`); create index metadata_idx2 on metadata(`message_id`);
create index metadata_idx3 on metadata(`bodydigest`); create index metadata_idx3 on metadata(`bodydigest`);
drop table if exists `attachment`;
create table `attachment` (
`id` bigint unsigned not null auto_increment,
`piler_id` char(36) not null,
`attachment_id` int not null,
`sig` char(64) not null,
`ptr` int default 0,
primary key (`id`)
) Engine=InnoDB;
create index `attachment_idx` on `attachment`(`piler_id`);
create index `attachment_idx2` on `attachment`(`sig`);
drop table if exists `archiving_rule`;
create table `archiving_rule` (
`id` bigint unsigned not null auto_increment,
`from` char(128) default null,
`to` char(255) default null,
`_size` char(2) default null,
`size` int default 0,
primary key (`id`)
);
drop table if exists `counter`; drop table if exists `counter`;
create table if not exists `counter` ( create table if not exists `counter` (
`rcvd` bigint unsigned default 0, `rcvd` bigint unsigned default 0,