diff --git a/configure b/configure index 1f1fafae..1d593da0 100755 --- a/configure +++ b/configure @@ -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" diff --git a/configure.in b/configure.in index 71fbe20d..15269231 100644 --- a/configure.in +++ b/configure.in @@ -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 diff --git a/src/attachment.c b/src/attachment.c new file mode 100644 index 00000000..3d66193f --- /dev/null +++ b/src/attachment.c @@ -0,0 +1,77 @@ +/* + * attachment.c, SJ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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; in_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; +} + diff --git a/src/config.h b/src/config.h index 00d0261c..c089e41f 100644 --- a/src/config.h +++ b/src/config.h @@ -11,7 +11,7 @@ #define PROGNAME "piler" -#define VERSION "0.1.3" +#define VERSION "0.1.5" #define PROGINFO VERSION ", Janos SUTO \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" diff --git a/src/defs.h b/src/defs.h index 16f16516..1805ebe6 100644 --- a/src/defs.h +++ b/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 diff --git a/src/digest.c b/src/digest.c index 456a8b83..5785e830 100644 --- a/src/digest.c +++ b/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;in_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); diff --git a/src/parser.c b/src/parser.c index d4e3a19b..42790577 100644 --- a/src/parser.c +++ b/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; iverbosity >= _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){ diff --git a/src/parser_utils.c b/src/parser_utils.c index f05f3a35..3ba7bf44 100644 --- a/src/parser_utils.c +++ b/src/parser_utils.c @@ -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); diff --git a/src/piler.c b/src/piler.c index 2726efe7..4b0b9458 100644 --- a/src/piler.c +++ b/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); diff --git a/src/piler.h b/src/piler.h index 475b3291..57687a7f 100644 --- a/src/piler.h +++ b/src/piler.h @@ -13,9 +13,12 @@ #include #include #include +#include #include +#include #include #include +#include #include #include @@ -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); diff --git a/src/rules.c b/src/rules.c new file mode 100644 index 00000000..f8c01812 --- /dev/null +++ b/src/rules.c @@ -0,0 +1,154 @@ +/* + * rules.c, SJ + */ + +#include +#include +#include +#include +#include +#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; + } +} + + + diff --git a/src/rules.h b/src/rules.h new file mode 100644 index 00000000..22ede682 --- /dev/null +++ b/src/rules.h @@ -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 */ + diff --git a/src/session.c b/src/session.c index 1d07f41f..a6e9c7b2 100644 --- a/src/session.c +++ b/src/session.c @@ -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"); diff --git a/src/store.c b/src/store.c index ac189b96..92bea7e4 100644 --- a/src/store.c +++ b/src/store.c @@ -19,9 +19,9 @@ #include -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); diff --git a/src/test.c b/src/test.c index 8e3f76f8..9f49bafa 100644 --- a/src/test.c +++ b/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 \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