summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--rules/regexp/headers.lua44
-rw-r--r--src/libmime/content_type.c6
-rw-r--r--src/libmime/content_type.h3
-rw-r--r--src/libmime/mime_parser.c81
4 files changed, 107 insertions, 27 deletions
diff --git a/rules/regexp/headers.lua b/rules/regexp/headers.lua
index c47205fea..516fc1232 100644
--- a/rules/regexp/headers.lua
+++ b/rules/regexp/headers.lua
@@ -153,15 +153,6 @@ reconf['R_MISSING_CHARSET'] = {
mime_only = true,
}
--- Subject seems to be spam
-reconf['R_SAJDING'] = {
- re = 'Subject=/\\bsajding(?:om|a)?\\b/iH',
- score = 8.0,
- description = 'Subject seems to be spam',
- group = 'headers',
- mime_only = true,
-}
-
-- Find forged Outlook MUA
-- Yahoo groups messages
local yahoo_bulk = 'Received=/from \\[\\S+\\] by \\S+\\.(?:groups|scd|dcn)\\.yahoo\\.com with NNFMP/H'
@@ -436,20 +427,9 @@ reconf['FORGED_MUA_KMAIL_MSGID_UNKNOWN'] = {
local opera1x_mua = 'User-Agent=/^\\s*Opera Mail\\/1[01]\\.\\d+ /H'
-- Opera Mail Message-ID template
local opera1x_msgid = 'Message-ID=/^<?op\\.[a-z\\d]{14}\\@\\S+>?$/H'
--- Suspicious Opera Mail User-Agent header
-local suspicious_opera10w_mua = 'User-Agent=/^\\s*Opera Mail\\/10\\.\\d+ \\(Windows\\)$/H'
--- Suspicious Opera Mail Message-ID, apparently from KMail
-local suspicious_opera10w_msgid = 'Message-Id=/^<?2009\\d{8}\\.\\d+\\.\\S+\\@\\S+?>$/H'
--- Summary rule for forged Opera Mail User-Agent header and Message-ID header from KMail
-reconf['SUSPICIOUS_OPERA_10W_MSGID'] = {
- re = string.format('(%s) & (%s)', suspicious_opera10w_mua, suspicious_opera10w_msgid),
- score = 4.0,
- description = 'Message pretends to be send from suspicious Opera Mail/10.x (Windows) but has forged Message-ID, apparently from KMail',
- group = 'mua'
-}
--- Summary rule for forged Opera Mail Message-ID header
+-- Rule for forged Opera Mail Message-ID header
reconf['FORGED_MUA_OPERA_MSGID'] = {
- re = string.format('(%s) & !(%s) & !(%s) & !(%s)', opera1x_mua, opera1x_msgid, reconf['SUSPICIOUS_OPERA_10W_MSGID']['re'], unusable_msgid),
+ re = string.format('(%s) & !(%s) & !(%s)', opera1x_mua, opera1x_msgid, unusable_msgid),
score = 4.0,
description = 'Message pretends to be send from Opera Mail but has forged Message-ID',
group = 'mua'
@@ -993,3 +973,23 @@ reconf['OLD_X_MAILER'] = {
score = 2.0,
group = 'headers',
}
+
+-- X-Mailer header values which should not occur (in the modern mail) at all
+local bad_x_mailers = {
+ -- header name repeated in the header value
+ [[X-Mailer: ]],
+ -- Mozilla Thunderbird uses User-Agnet header, not X-Mailer
+ -- Early Thunderbird had U-A like:
+ -- Mozilla Thunderbird 1.0.2 (Windows/20050317)
+ -- Thunderbird 2.0.0.23 (X11/20090812)
+ [[(?:Mozilla )?Thunderbird \d]],
+ -- Was used by Yahoo Groups in 2000s
+ [[eGroups Message Poster]],
+}
+
+reconf['FORGED_X_MAILER'] = {
+ description = 'Forged X-Mailer header',
+ re = string.format('X-Mailer=/^(?:%s)/', table.concat(bad_x_mailers, '|')),
+ score = 4.0,
+ group = 'headers',
+}
diff --git a/src/libmime/content_type.c b/src/libmime/content_type.c
index 0c06f51fb..7b9c213ca 100644
--- a/src/libmime/content_type.c
+++ b/src/libmime/content_type.c
@@ -706,6 +706,12 @@ rspamd_content_type_parse (const gchar *in,
res->flags |= RSPAMD_CONTENT_TYPE_BROKEN;
RSPAMD_FTOK_ASSIGN (&res->subtype, "alternative");
}
+
+ /* PKCS7 smime */
+ RSPAMD_FTOK_ASSIGN (&srch, "x-pkcs7-mime");
+ if (rspamd_ftok_casecmp (&res->subtype, &srch) == 0) {
+ res->flags |= RSPAMD_CONTENT_TYPE_SMIME;
+ }
}
RSPAMD_FTOK_ASSIGN (&srch, "multipart");
diff --git a/src/libmime/content_type.h b/src/libmime/content_type.h
index 3991e6785..6bc7262e7 100644
--- a/src/libmime/content_type.h
+++ b/src/libmime/content_type.h
@@ -32,7 +32,8 @@ enum rspamd_content_type_flags {
RSPAMD_CONTENT_TYPE_MESSAGE = 1 << 3,
RSPAMD_CONTENT_TYPE_DSN = 1 << 4,
RSPAMD_CONTENT_TYPE_MISSING = 1 << 5,
- RSPAMD_CONTENT_TYPE_ENCRYPTED = 1 << 1,
+ RSPAMD_CONTENT_TYPE_ENCRYPTED = 1 << 6,
+ RSPAMD_CONTENT_TYPE_SMIME = 1 << 7,
};
enum rspamd_content_param_flags {
diff --git a/src/libmime/mime_parser.c b/src/libmime/mime_parser.c
index 213eb99d2..207bd4462 100644
--- a/src/libmime/mime_parser.c
+++ b/src/libmime/mime_parser.c
@@ -23,6 +23,8 @@
#include "multipattern.h"
#include "contrib/libottery/ottery.h"
#include "contrib/uthash/utlist.h"
+#include <openssl/cms.h>
+#include <openssl/pkcs7.h>
struct rspamd_mime_parser_lib_ctx {
struct rspamd_multipattern *mp_boundary;
@@ -77,8 +79,17 @@ static enum rspamd_mime_parse_error
rspamd_mime_parse_normal_part (struct rspamd_task *task,
struct rspamd_mime_part *part,
struct rspamd_mime_parser_ctx *st,
+ struct rspamd_content_type *ct,
GError **err);
+static enum rspamd_mime_parse_error
+rspamd_mime_process_multipart_node (struct rspamd_task *task,
+ struct rspamd_mime_parser_ctx *st,
+ struct rspamd_mime_part *multipart,
+ const gchar *start, const gchar *end,
+ gboolean is_finished,
+ GError **err);
+
#define RSPAMD_MIME_QUARK (rspamd_mime_parser_quark())
static GQuark
@@ -575,6 +586,7 @@ static enum rspamd_mime_parse_error
rspamd_mime_parse_normal_part (struct rspamd_task *task,
struct rspamd_mime_part *part,
struct rspamd_mime_parser_ctx *st,
+ struct rspamd_content_type *ct,
GError **err)
{
rspamd_fstring_t *parsed;
@@ -690,6 +702,67 @@ rspamd_mime_parse_normal_part (struct rspamd_task *task,
part->raw_data.len, rspamd_cte_to_string (part->cte));
rspamd_mime_parser_calc_digest (part);
+ if (ct && (ct->flags & RSPAMD_CONTENT_TYPE_SMIME)) {
+ CMS_ContentInfo *cms;
+ const unsigned char *der_beg = part->parsed_data.begin;
+ cms = d2i_CMS_ContentInfo (NULL, &der_beg, part->parsed_data.len);
+
+ if (cms) {
+ const ASN1_OBJECT *asn_ct = CMS_get0_eContentType (cms);
+ int ct_nid = OBJ_obj2nid (asn_ct);
+
+ if (ct_nid == NID_pkcs7_data) {
+ BIO *bio = BIO_new_mem_buf (part->parsed_data.begin,
+ part->parsed_data.len);
+
+ PKCS7 *p7;
+ p7 = d2i_PKCS7_bio (bio, NULL);
+
+ if (p7) {
+ ct_nid = OBJ_obj2nid (p7->type);
+
+ if (ct_nid == NID_pkcs7_signed) {
+ PKCS7 *p7_signed_content = p7->d.sign->contents;
+
+ ct_nid = OBJ_obj2nid (p7_signed_content->type);
+
+ if (ct_nid == NID_pkcs7_data) {
+ int ret;
+
+ msg_debug_mime ("found an additional part inside of "
+ "smime structure of type %T/%T; length=%d",
+ &ct->type, &ct->subtype, p7_signed_content->d.data->length);
+ /*
+ * Since ASN.1 structures are freed, we need to copy
+ * the content
+ */
+ gchar *cpy = rspamd_mempool_alloc (task->task_pool,
+ p7_signed_content->d.data->length);
+ memcpy (cpy, p7_signed_content->d.data->data,
+ p7_signed_content->d.data->length);
+ ret = rspamd_mime_process_multipart_node (task,
+ st, NULL,
+ cpy,cpy + p7_signed_content->d.data->length,
+ TRUE, err);
+
+ PKCS7_free (p7);
+ BIO_free (bio);
+ CMS_ContentInfo_free (cms);
+
+ return ret;
+ }
+ }
+
+ PKCS7_free (p7);
+ }
+
+ BIO_free (bio);
+ }
+
+ CMS_ContentInfo_free (cms);
+ }
+ }
+
return RSPAMD_MIME_PARSE_OK;
}
@@ -839,13 +912,13 @@ rspamd_mime_process_multipart_node (struct rspamd_task *task,
g_ptr_array_add (st->stack, npart);
npart->part_type = RSPAMD_MIME_PART_MESSAGE;
- if ((ret = rspamd_mime_parse_normal_part (task, npart, st, err))
+ if ((ret = rspamd_mime_parse_normal_part (task, npart, st, sel, err))
== RSPAMD_MIME_PARSE_OK) {
ret = rspamd_mime_parse_message (task, npart, st, err);
}
}
else {
- ret = rspamd_mime_parse_normal_part (task, npart, st, err);
+ ret = rspamd_mime_parse_normal_part (task, npart, st, sel, err);
}
return ret;
@@ -1478,14 +1551,14 @@ rspamd_mime_parse_message (struct rspamd_task *task,
ret = rspamd_mime_parse_multipart_part (task, npart, nst, err);
}
else if (sel->flags & RSPAMD_CONTENT_TYPE_MESSAGE) {
- if ((ret = rspamd_mime_parse_normal_part (task, npart, nst, err))
+ if ((ret = rspamd_mime_parse_normal_part (task, npart, nst, sel, err))
== RSPAMD_MIME_PARSE_OK) {
npart->part_type = RSPAMD_MIME_PART_MESSAGE;
ret = rspamd_mime_parse_message (task, npart, nst, err);
}
}
else {
- ret = rspamd_mime_parse_normal_part (task, npart, nst, err);
+ ret = rspamd_mime_parse_normal_part (task, npart, nst, sel, err);
}
if (ret != RSPAMD_MIME_PARSE_OK) {