From: Vsevolod Stakhov Date: Sat, 20 May 2017 08:48:40 +0000 (+0100) Subject: [Feature] Check dkim sign keys for modifications X-Git-Tag: 1.6.0~161 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=f252d9ca75387b92efd809da1a899eac627a8ca6;p=rspamd.git [Feature] Check dkim sign keys for modifications --- 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 #include #include -#include /* 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 @@ -150,6 +150,15 @@ rspamd_dkim_sign_key_t* rspamd_dkim_sign_key_load (const gchar *what, gsize len, enum rspamd_dkim_sign_key_type type, 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 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;