diff --git a/RELEASE_NOTES b/RELEASE_NOTES index 5b84e188..60c346e7 100644 --- a/RELEASE_NOTES +++ b/RELEASE_NOTES @@ -1,3 +1,9 @@ +1.3.10: +------- + +- Added security header feature + + 1.3.9: ------ diff --git a/VERSION b/VERSION index d4c4950a..0c00f610 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.3.9 +1.3.10 diff --git a/etc/example.conf b/etc/example.conf index c002a15d..70e20231 100644 --- a/etc/example.conf +++ b/etc/example.conf @@ -221,3 +221,11 @@ tweak_sent_time_offset=0 ; whether to enable (1) or not (0) the extra mmap dedup test feature ; if you change it, be sure to stop, then start piler mmap_dedup_test=0 + +; security header that must be present in the first mail header of +; the message. If the security_header value is not empty, then the +; parser checks for this header line. Unless it's found it will discard +; the given email. Note that this feature is supposed to be a security +; mechanism against unwanted email in the archive if limiting smtp +; clients via an IP-address list is not feasible. +security_header= diff --git a/src/cfg.c b/src/cfg.c index 0c40b705..023d04e6 100644 --- a/src/cfg.c +++ b/src/cfg.c @@ -84,6 +84,7 @@ struct _parse_rule config_parse_rules[] = { "piler_header_field", "string", (void*) string_parser, offsetof(struct config, piler_header_field), "X-piler-id:", MAXVAL-1}, { "process_rcpt_to_addresses", "integer", (void*) int_parser, offsetof(struct config, process_rcpt_to_addresses), "0", sizeof(int)}, { "queuedir", "string", (void*) string_parser, offsetof(struct config, queuedir), QUEUE_DIR, MAXVAL-1}, + { "security_header", "string", (void*) string_parser, offsetof(struct config, security_header), "", MAXVAL-1}, { "server_id", "integer", (void*) int_parser, offsetof(struct config, server_id), "0", sizeof(int)}, { "smtp_timeout", "integer", (void*) int_parser, offsetof(struct config, smtp_timeout), "60", sizeof(int)}, { "spam_header_line", "string", (void*) string_parser, offsetof(struct config, spam_header_line), "", MAXVAL-1}, diff --git a/src/cfg.h b/src/cfg.h index 03ea7d12..6932a6c4 100644 --- a/src/cfg.h +++ b/src/cfg.h @@ -64,6 +64,8 @@ struct config { int default_retention_days; + char security_header[MAXVAL]; + // mysql stuff char mysqlcharset[MAXVAL]; diff --git a/src/defs.h b/src/defs.h index f7477a65..7361b453 100644 --- a/src/defs.h +++ b/src/defs.h @@ -209,6 +209,8 @@ struct parser_state { unsigned int bodylen; unsigned int tolen; unsigned int todomainlen; + unsigned int found_security_header; + int journaltolen; int retention; diff --git a/src/parser.c b/src/parser.c index 3329effd..e3c36528 100644 --- a/src/parser.c +++ b/src/parser.c @@ -199,6 +199,10 @@ int parse_line(char *buf, struct parser_state *state, struct session_data *sdata sdata->restored_copy = 1; } + if(cfg->security_header && state->found_security_header == 0 && strstr(buf, cfg->security_header)){ + state->found_security_header = 1; + } + if(*(cfg->piler_header_field) != 0 && strncmp(buf, cfg->piler_header_field, strlen(cfg->piler_header_field)) == 0){ sdata->restored_copy = 1; } diff --git a/src/parser_utils.c b/src/parser_utils.c index 45e03048..5c56a6e3 100644 --- a/src/parser_utils.c +++ b/src/parser_utils.c @@ -102,6 +102,8 @@ void init_state(struct parser_state *state){ state->journaltolen = 0; state->retention = 0; + + state->found_security_header = 0; } diff --git a/src/piler.c b/src/piler.c index 46b99e18..684d90de 100644 --- a/src/piler.c +++ b/src/piler.c @@ -101,11 +101,43 @@ void child_sighup_handler(int sig){ } +int perform_checks(char *filename, struct session_data *sdata, struct data *data, struct parser_state *parser_state, struct config *cfg){ + + if(cfg->security_header && parser_state->found_security_header == 0){ + syslog(LOG_PRIORITY, "%s: discarding: missing security header", filename); + return ERR_DISCARDED; + } + + char *arule = check_against_ruleset(data->archiving_rules, parser_state, sdata->tot_len, sdata->spam_message); + + if(arule){ + syslog(LOG_PRIORITY, "%s: discarding: archiving policy: *%s*", filename, arule); + return ERR_DISCARDED; + } + + + if(cfg->archive_only_mydomains == 1 && sdata->internal_sender == 0 && sdata->internal_recipient == 0){ + syslog(LOG_PRIORITY, "%s: discarding: not on mydomains", filename); + return ERR_DISCARDED; + } + + make_digests(sdata, cfg); + + if(sdata->hdr_len < 10){ + syslog(LOG_PRIORITY, "%s: invalid message, hdr_len: %d", filename, sdata->hdr_len); + return ERR; + } + + int rc = process_message(sdata, parser_state, data, cfg); + unlink(parser_state->message_id_hash); + + return rc; +} + + int process_email(char *filename, struct session_data *sdata, struct data *data, int size, struct config *cfg){ - int rc; char tmpbuf[SMALLBUFSIZE]; char *status=S_STATUS_UNDEF; - char *arule; char *p; struct timezone tz; struct timeval tv1, tv2; @@ -144,29 +176,7 @@ int process_email(char *filename, struct session_data *sdata, struct data *data, } while(rcpt); } - arule = check_against_ruleset(data->archiving_rules, &parser_state, sdata->tot_len, sdata->spam_message); - - if(arule){ - syslog(LOG_PRIORITY, "%s: discarding: archiving policy: *%s*", filename, arule); - rc = ERR_DISCARDED; - } - else if(cfg->archive_only_mydomains == 1 && sdata->internal_sender == 0 && sdata->internal_recipient == 0){ - syslog(LOG_PRIORITY, "%s: discarding: not on mydomains", filename); - rc = ERR_DISCARDED; - } - else { - make_digests(sdata, cfg); - - if(sdata->hdr_len < 10){ - syslog(LOG_PRIORITY, "%s: invalid message, hdr_len: %d", filename, sdata->hdr_len); - rc = ERR; - } - else { - rc = process_message(sdata, &parser_state, data, cfg); - unlink(parser_state.message_id_hash); - } - } - + int rc = perform_checks(filename, sdata, data, &parser_state, cfg); unlink(sdata->tmpframe); remove_stripped_attachments(&parser_state);