mirror of
https://bitbucket.org/jsuto/piler.git
synced 2024-12-24 04:40:13 +01:00
0.1.5
This commit is contained in:
parent
29f312a8d2
commit
d7318f94cf
2
configure
vendored
2
configure
vendored
@ -4285,7 +4285,7 @@ echo; echo
|
||||
|
||||
CFLAGS="$static -O2 -Wall -g"
|
||||
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"
|
||||
|
||||
|
@ -317,7 +317,7 @@ echo; echo
|
||||
|
||||
CFLAGS="$static -O2 -Wall -g"
|
||||
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_OUTPUT
|
||||
|
77
src/attachment.c
Normal file
77
src/attachment.c
Normal 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;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#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"
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
|
||||
#define CONFIG_FILE CONFDIR "/piler.conf"
|
||||
#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 CLAMD_SOCKET "/tmp/clamd"
|
||||
@ -73,8 +73,8 @@
|
||||
|
||||
#define SQL_SPHINX_TABLE "sph_index"
|
||||
#define SQL_METADATA_TABLE "metadata"
|
||||
#define SQL_HEADER_TABLE "header"
|
||||
#define SQL_BODY_TABLE "body"
|
||||
#define SQL_ATTACHMENT_TABLE "attachment"
|
||||
#define SQL_ARCHIVING_RULE_TABLE "archiving_rule"
|
||||
#define SQL_COUNTER_TABLE "counter"
|
||||
|
||||
|
||||
|
31
src/defs.h
31
src/defs.h
@ -54,14 +54,31 @@ struct attachment {
|
||||
int size;
|
||||
char type[TINYBUFSIZE];
|
||||
char filename[TINYBUFSIZE];
|
||||
char internalname[TINYBUFSIZE];
|
||||
char digest[2*DIGEST_LENGTH+1];
|
||||
};
|
||||
|
||||
|
||||
struct list {
|
||||
char s[SMALLBUFSIZE];
|
||||
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 {
|
||||
int line_num;
|
||||
int message_state;
|
||||
@ -78,9 +95,12 @@ struct _state {
|
||||
int skip_html;
|
||||
int has_to_dump;
|
||||
int fd;
|
||||
int mfd;
|
||||
int octetstream;
|
||||
int realbinary;
|
||||
int content_type_is_set;
|
||||
int pushed_pointer;
|
||||
int saved_size;
|
||||
char attachedfile[RND_STR_LEN+SMALLBUFSIZE];
|
||||
char message_id[SMALLBUFSIZE];
|
||||
char miscbuf[MAX_TOKEN_LEN];
|
||||
@ -99,7 +119,7 @@ struct _state {
|
||||
|
||||
|
||||
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 acceptbuf[SMALLBUFSIZE];
|
||||
char whitelist[MAXBUFSIZE], blacklist[MAXBUFSIZE];
|
||||
@ -158,15 +178,8 @@ struct memcached_server {
|
||||
|
||||
|
||||
struct __data {
|
||||
struct url *blackhole;
|
||||
|
||||
#ifdef HAVE_LIBCLAMAV
|
||||
struct cl_engine *engine;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TRE
|
||||
regex_t pregs[NUM_OF_REGEXES];
|
||||
int n_regex;
|
||||
struct rule *rules;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_MEMCACHED
|
||||
|
26
src/digest.c
26
src/digest.c
@ -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]);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -229,7 +229,7 @@ ENDE_META:
|
||||
|
||||
|
||||
int processMessage(struct session_data *sdata, struct _state *state, struct __config *cfg){
|
||||
int rc;
|
||||
int i, rc;
|
||||
|
||||
/* 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 = 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);
|
||||
|
78
src/parser.c
78
src/parser.c
@ -20,7 +20,7 @@ struct _state parse_message(struct session_data *sdata, struct __config *cfg){
|
||||
FILE *f;
|
||||
char buf[MAXBUFSIZE];
|
||||
struct _state state;
|
||||
int len;
|
||||
int i, len;
|
||||
|
||||
init_state(&state);
|
||||
|
||||
@ -30,15 +30,31 @@ struct _state parse_message(struct session_data *sdata, struct __config *cfg){
|
||||
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);
|
||||
|
||||
|
||||
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");
|
||||
|
||||
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++;
|
||||
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++;
|
||||
|
||||
@ -138,8 +174,6 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, stru
|
||||
if(p) *p = '\0';
|
||||
}
|
||||
|
||||
extractNameFromHeaderLine(buf, "name", state->attachments[state->n_attachments].filename);
|
||||
|
||||
|
||||
if(strcasestr(buf, "text/plain") ||
|
||||
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(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;
|
||||
snprintf(puf, sizeof(puf)-1, "%s.%d", sdata->ttmpfile, state->n_attachments);
|
||||
printf("dump file: %s\n", puf);
|
||||
|
||||
//state->fd = open(u, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR);
|
||||
//printf("DUMP FILE: %s\n", state->attachments[state->n_attachments].internalname);
|
||||
state->fd = open(state->attachments[state->n_attachments].internalname, 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++;
|
||||
|
||||
/* 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){
|
||||
state->n_attachments--;
|
||||
}
|
||||
@ -219,6 +261,8 @@ int parse_line(char *buf, struct _state *state, struct session_data *sdata, stru
|
||||
|
||||
state->realbinary = 0;
|
||||
|
||||
state->pushed_pointer = 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){
|
||||
|
||||
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;
|
||||
}
|
||||
/* 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->base64 == 1 && state->message_state == MSG_BODY){
|
||||
|
@ -49,8 +49,11 @@ void init_state(struct _state *state){
|
||||
|
||||
state->has_to_dump = 0;
|
||||
state->fd = -1;
|
||||
state->mfd = -1;
|
||||
state->realbinary = 0;
|
||||
state->octetstream = 0;
|
||||
state->pushed_pointer = 1;
|
||||
state->saved_size = 0;
|
||||
|
||||
state->boundaries = NULL;
|
||||
|
||||
@ -61,6 +64,8 @@ void init_state(struct _state *state){
|
||||
state->attachments[i].size = 0;
|
||||
memset(state->attachments[i].type, 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);
|
||||
|
27
src/piler.c
27
src/piler.c
@ -38,6 +38,8 @@ struct passwd *pwd;
|
||||
void clean_exit(){
|
||||
if(sd != -1) close(sd);
|
||||
|
||||
free_rule(data.rules);
|
||||
|
||||
syslog(LOG_PRIORITY, "%s has been terminated", PROGNAME);
|
||||
|
||||
unlink(cfg.pidfile);
|
||||
@ -61,7 +63,8 @@ void sigchld(){
|
||||
}
|
||||
|
||||
|
||||
void initialiseConfiguration(){
|
||||
void initialise_configuration(){
|
||||
struct session_data sdata;
|
||||
|
||||
cfg = read_config(configfile);
|
||||
|
||||
@ -84,7 +87,21 @@ void initialiseConfiguration(){
|
||||
setlocale(LC_MESSAGES, 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);
|
||||
|
||||
@ -147,17 +164,17 @@ int main(int argc, char **argv){
|
||||
sig_catch(SIGQUIT, clean_exit);
|
||||
sig_catch(SIGKILL, 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_catch(SIGCHLD, sigchld);
|
||||
|
||||
|
||||
initialiseConfiguration();
|
||||
initialise_configuration();
|
||||
|
||||
|
||||
if(read_key(&cfg)) fatal(ERR_READING_KEY);
|
||||
|
@ -13,9 +13,12 @@
|
||||
#include <session.h>
|
||||
#include <decoder.h>
|
||||
#include <list.h>
|
||||
#include <rules.h>
|
||||
#include <defs.h>
|
||||
#include <tai.h>
|
||||
#include <sig.h>
|
||||
#include <av.h>
|
||||
#include <rules.h>
|
||||
#include <config.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 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 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);
|
||||
|
||||
|
154
src/rules.c
Normal file
154
src/rules.c
Normal 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 = ∅
|
||||
if(regcomp(&(h->from), from, REG_ICASE | REG_EXTENDED)) h->compiled = 0;
|
||||
|
||||
if(!to) to = ∅
|
||||
if(regcomp(&(h->to), to, REG_ICASE | REG_EXTENDED)) h->compiled = 0;
|
||||
|
||||
if(!subject) subject = ∅
|
||||
if(regcomp(&(h->subject), subject, REG_ICASE | REG_EXTENDED)) h->compiled = 0;
|
||||
|
||||
h->size = size;
|
||||
|
||||
if(!_size) _size = ∅
|
||||
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
18
src/rules.h
Normal 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 */
|
||||
|
@ -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;
|
||||
char *p, buf[MAXBUFSIZE], puf[MAXBUFSIZE], resp[MAXBUFSIZE], prevbuf[MAXBUFSIZE], last2buf[2*MAXBUFSIZE+1];
|
||||
char rctptoemail[SMALLBUFSIZE], fromemail[SMALLBUFSIZE], virusinfo[SMALLBUFSIZE], reason[SMALLBUFSIZE];
|
||||
char *arule = NULL;
|
||||
struct session_data sdata;
|
||||
struct _state sstate;
|
||||
int db_conn=0;
|
||||
@ -184,7 +185,19 @@ void handle_smtp_session(int new_sd, struct __data *data, struct __config *cfg){
|
||||
inj = ERR;
|
||||
} else {
|
||||
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
|
||||
|
||||
unlink(sdata.ttmpfile);
|
||||
unlink(sdata.tmpframe);
|
||||
|
||||
|
||||
alarm(cfg->session_timeout);
|
||||
@ -381,6 +395,7 @@ AFTER_PERIOD:
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: sent: %s", sdata.ttmpfile, buf);
|
||||
|
||||
unlink(sdata.ttmpfile);
|
||||
unlink(sdata.tmpframe);
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: removed", sdata.ttmpfile);
|
||||
|
||||
goto QUITTING;
|
||||
@ -399,6 +414,7 @@ AFTER_PERIOD:
|
||||
|
||||
if(cfg->verbosity >= _LOG_DEBUG) syslog(LOG_PRIORITY, "%s: removed", sdata.ttmpfile);
|
||||
unlink(sdata.ttmpfile);
|
||||
unlink(sdata.tmpframe);
|
||||
|
||||
initSessionData(&sdata);
|
||||
|
||||
@ -472,6 +488,9 @@ void initSessionData(struct session_data *sdata){
|
||||
create_id(&(sdata->ttmpfile[0]));
|
||||
unlink(sdata->ttmpfile);
|
||||
|
||||
snprintf(sdata->tmpframe, SMALLBUFSIZE-1, "%s.m", sdata->ttmpfile);
|
||||
unlink(sdata->tmpframe);
|
||||
|
||||
memset(sdata->mailfrom, 0, SMALLBUFSIZE);
|
||||
snprintf(sdata->client_addr, SMALLBUFSIZE-1, "null");
|
||||
|
||||
|
47
src/store.c
47
src/store.c
@ -19,9 +19,9 @@
|
||||
#include <openssl/evp.h>
|
||||
|
||||
|
||||
int store_message(struct session_data *sdata, struct _state *state, int stored, struct __config *cfg){
|
||||
int ret=0, rc, fd, n, len=sdata->tot_len;
|
||||
char *addr, *p0, *p1, *p2, s[SMALLBUFSIZE];
|
||||
int store_file(struct session_data *sdata, char *filename, int startpos, int len, struct __config *cfg){
|
||||
int ret=0, rc, fd, n;
|
||||
char *addr, *p, *p0, *p1, *p2, s[SMALLBUFSIZE];
|
||||
struct stat st;
|
||||
Bytef *z=NULL;
|
||||
uLongf dstlen;
|
||||
@ -34,18 +34,17 @@ int store_message(struct session_data *sdata, struct _state *state, int stored,
|
||||
struct timeval tv1, tv2;
|
||||
|
||||
|
||||
/* fix data length to store */
|
||||
|
||||
/*if(stored == 1 && sdata->hdr_len > 100){
|
||||
len = sdata->hdr_len;
|
||||
}*/
|
||||
|
||||
fd = open(sdata->ttmpfile, O_RDONLY);
|
||||
fd = open(filename, O_RDONLY);
|
||||
if(fd == -1) return ret;
|
||||
|
||||
if(len == 0){
|
||||
if(fstat(fd, &st)) return ret;
|
||||
len = st.st_size;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
if(z == NULL){
|
||||
munmap(addr, sdata->tot_len);
|
||||
munmap(addr, len);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -63,7 +62,7 @@ int store_message(struct session_data *sdata, struct _state *state, int stored,
|
||||
gettimeofday(&tv2, &tz);
|
||||
sdata->__compress += tvdiff(tv2, tv1);
|
||||
|
||||
munmap(addr, sdata->tot_len);
|
||||
munmap(addr, len);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
/* 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 = '\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 = '\0';
|
||||
|
||||
mkdir(s, 0755);
|
||||
mkdir(s, 0750);
|
||||
*p2 = '/';
|
||||
mkdir(s, 0755);
|
||||
mkdir(s, 0750);
|
||||
*p1 = '/';
|
||||
mkdir(s, 0755);
|
||||
mkdir(s, 0770);
|
||||
}
|
||||
|
||||
*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;
|
||||
|
||||
n = write(fd, outbuf, outlen);
|
||||
|
31
src/test.c
31
src/test.c
@ -16,11 +16,14 @@
|
||||
|
||||
|
||||
int main(int argc, char **argv){
|
||||
int i, rc;
|
||||
int rc;
|
||||
struct stat st;
|
||||
struct session_data sdata;
|
||||
struct _state state;
|
||||
struct __config cfg;
|
||||
struct __data data;
|
||||
char *rule;
|
||||
|
||||
|
||||
if(argc < 2){
|
||||
fprintf(stderr, "usage: %s <message>\n", argv[0]);
|
||||
@ -34,9 +37,21 @@ int main(int argc, char **argv){
|
||||
|
||||
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));
|
||||
setlocale(LC_CTYPE, cfg.locale);
|
||||
|
||||
data.rules = NULL;
|
||||
|
||||
|
||||
load_archiving_rules(&sdata, &(data.rules));
|
||||
|
||||
rc = 0;
|
||||
|
||||
sdata.num_of_rcpt_to = -1;
|
||||
@ -45,6 +60,7 @@ int main(int argc, char **argv){
|
||||
sdata.tot_len = st.st_size;
|
||||
memset(sdata.rcptto[0], 0, SMALLBUFSIZE);
|
||||
snprintf(sdata.ttmpfile, SMALLBUFSIZE-1, "%s", argv[1]);
|
||||
snprintf(sdata.tmpframe, SMALLBUFSIZE-1, "%s.m", argv[1]);
|
||||
|
||||
state = parse_message(&sdata, &cfg);
|
||||
|
||||
@ -52,15 +68,18 @@ int main(int argc, char **argv){
|
||||
printf("from: *%s*\n", state.b_from);
|
||||
printf("to: *%s*\n", state.b_to);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
for(i=0; i<state.n_attachments; i++){
|
||||
printf("i:%d, name=*%s*, type: *%s*, size: %d\n", i, state.attachments[i].filename, state.attachments[i].type, state.attachments[i].size);
|
||||
}
|
||||
printf("rules check: %s\n", rule);
|
||||
|
||||
mysql_close(&(sdata.mysql));
|
||||
|
||||
free_rule(data.rules);
|
||||
|
||||
printf("\n\n");
|
||||
|
||||
|
@ -42,6 +42,30 @@ create index metadata_idx on metadata(`piler_id`);
|
||||
create index metadata_idx2 on metadata(`message_id`);
|
||||
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`;
|
||||
create table if not exists `counter` (
|
||||
`rcvd` bigint unsigned default 0,
|
||||
|
Loading…
Reference in New Issue
Block a user