summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVsevolod Stakhov <vsevolod@highsecure.ru>2017-05-20 09:48:40 +0100
committerVsevolod Stakhov <vsevolod@highsecure.ru>2017-05-20 09:48:40 +0100
commitf252d9ca75387b92efd809da1a899eac627a8ca6 (patch)
tree692f7b3c106e0c0cf14cf0b8fe694ee2893d8ce1
parentbc5cf4c2403854857c61025b8a19ab5abb2e28df (diff)
downloadrspamd-f252d9ca75387b92efd809da1a899eac627a8ca6.tar.gz
rspamd-f252d9ca75387b92efd809da1a899eac627a8ca6.zip
[Feature] Check dkim sign keys for modifications
-rw-r--r--src/libserver/dkim.c41
-rw-r--r--src/libserver/dkim.h9
-rw-r--r--src/plugins/dkim_check.c26
3 files changed, 74 insertions, 2 deletions
diff --git a/src/libserver/dkim.c b/src/libserver/dkim.c
index 3a314cac9..bb1113d00 100644
--- a/src/libserver/dkim.c
+++ b/src/libserver/dkim.c
@@ -19,11 +19,11 @@
#include "dkim.h"
#include "dns.h"
#include "utlist.h"
+#include "unix-std.h"
#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/engine.h>
-#include <sys/mman.h>
/* special DNS tokens */
#define DKIM_DNSKEYNAME "_domainkey"
@@ -127,6 +127,7 @@ struct rspamd_dkim_sign_key_s {
RSA *key_rsa;
BIO *key_bio;
EVP_PKEY *key_evp;
+ time_t mtime;
ref_entry_t ref;
};
@@ -1968,11 +1969,23 @@ rspamd_dkim_sign_key_load (const gchar *what, gsize len,
gpointer map;
gsize map_len = 0;
rspamd_dkim_sign_key_t *nkey;
+ struct stat st;
+ time_t mtime = 0;
if (type == RSPAMD_DKIM_SIGN_KEY_FILE) {
gchar fpath[PATH_MAX];
rspamd_snprintf (fpath, sizeof (fpath), "%*s", (gint)len, what);
+
+ if (stat (fpath, &st) == -1) {
+ g_set_error (err, dkim_error_quark (), DKIM_SIGERROR_KEYFAIL,
+ "cannot stat private key %s: %s",
+ fpath, strerror (errno));
+
+ return NULL;
+ }
+
+ mtime = st.st_mtime;
map = rspamd_file_xmap (fpath, PROT_READ, &map_len, TRUE);
if (map == NULL) {
@@ -1986,6 +1999,7 @@ rspamd_dkim_sign_key_load (const gchar *what, gsize len,
nkey = g_slice_alloc0 (sizeof (*nkey));
nkey->type = type;
+ nkey->mtime = mtime;
switch (type) {
case RSPAMD_DKIM_SIGN_KEY_FILE:
@@ -2064,6 +2078,31 @@ rspamd_dkim_sign_key_load (const gchar *what, gsize len,
return nkey;
}
+gboolean
+rspamd_dkim_sign_key_maybe_invalidate (rspamd_dkim_sign_key_t *key,
+ enum rspamd_dkim_sign_key_type type,
+ const gchar *what, gsize len)
+{
+ struct stat st;
+
+ if (type == RSPAMD_DKIM_SIGN_KEY_FILE) {
+ gchar fpath[PATH_MAX];
+
+ rspamd_snprintf (fpath, sizeof (fpath), "%*s", (gint) len, what);
+
+ if (stat (fpath, &st) == -1) {
+ /* Prefer to use cached key since it is absent on FS */
+ return FALSE;
+ }
+
+ if (st.st_mtime > key->mtime) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
rspamd_dkim_sign_context_t *
rspamd_create_dkim_sign_context (struct rspamd_task *task,
rspamd_dkim_sign_key_t *priv_key,
diff --git a/src/libserver/dkim.h b/src/libserver/dkim.h
index a2bd4d0e2..7e025a4c0 100644
--- a/src/libserver/dkim.h
+++ b/src/libserver/dkim.h
@@ -151,6 +151,15 @@ rspamd_dkim_sign_key_t* rspamd_dkim_sign_key_load (const gchar *what, gsize len,
GError **err);
/**
+ * Invalidate modified sign key
+ * @param key
+ * @return
+ */
+gboolean rspamd_dkim_sign_key_maybe_invalidate (rspamd_dkim_sign_key_t *key,
+ enum rspamd_dkim_sign_key_type type,
+ const gchar *what, gsize len);
+
+/**
* Make DNS request for specified context and obtain and parse key
* @param ctx dkim context from signature
* @param resolver dns resolver object
diff --git a/src/plugins/dkim_check.c b/src/plugins/dkim_check.c
index e83137339..2a1706c3d 100644
--- a/src/plugins/dkim_check.c
+++ b/src/plugins/dkim_check.c
@@ -1117,7 +1117,31 @@ dkim_sign_callback (struct rspamd_task *task, void *unused)
if (dkim_key == NULL) {
msg_err_task ("cannot load dkim key %s: %e",
- key, err);
+ lru_key, err);
+ g_error_free (err);
+
+ return;
+ }
+
+ rspamd_lru_hash_insert (dkim_module_ctx->dkim_sign_hash,
+ g_strdup (lru_key), dkim_key,
+ time (NULL), 0);
+ }
+ else if (rspamd_dkim_sign_key_maybe_invalidate (dkim_key,
+ sign_type, key, len)) {
+ /*
+ * Invalidate and reload DKIM key,
+ * removal from lru cache also cleanup the key and value
+ */
+
+ rspamd_lru_hash_remove (dkim_module_ctx->dkim_sign_hash,
+ lru_key);
+ dkim_key = rspamd_dkim_sign_key_load (key, len,
+ sign_type, &err);
+
+ if (dkim_key == NULL) {
+ msg_err_task ("cannot load dkim key %s: %e",
+ lru_key, err);
g_error_free (err);
return;