]> git.ipfire.org Git - thirdparty/rspamd.git/commitdiff
[Feature] Implement encrypted logs
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 16 Aug 2016 15:45:34 +0000 (16:45 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 16 Aug 2016 16:05:02 +0000 (17:05 +0100)
src/libserver/cfg_file.h
src/libserver/cfg_rcl.c
src/libutil/logger.c

index f0e09f0b2087a3bd2d475dd11a54dced4791a61d..2eb4185066720e785690cc460bc7c253dde2ad6e 100644 (file)
@@ -29,6 +29,7 @@ struct rspamd_stat_classifier;
 struct module_s;
 struct worker_s;
 struct rspamd_external_libs_ctx;
+struct rspamd_cryptobox_pubkey;
 
 enum { VAL_UNDEF=0, VAL_TRUE, VAL_FALSE };
 
@@ -312,6 +313,7 @@ struct rspamd_config {
        gboolean log_urls;                              /**< whether we should log URLs                         */
        GList *debug_symbols;                           /**< symbols to debug                                                                   */
        GHashTable *debug_modules;                      /**< logging modules to debug                                                   */
+       struct rspamd_cryptobox_pubkey *log_encryption_key; /**< encryption key for logs                                                */
        gboolean log_color;                             /**< output colors for console output                   */
        gboolean log_extended;                          /**< log extended information                                                   */
        gboolean log_systemd;                           /**< special case for systemd logger                                    */
index ad0629f25f5ba874f8fb347fefb9882b59b5b5a8..94c5862d74b3a4833a67381793285bd7e94fce9a 100644 (file)
@@ -1680,6 +1680,12 @@ rspamd_rcl_config_init (struct rspamd_config *cfg)
                        "Specify format string for the task logging output "
                                        "(https://rspamd.com/doc/configuration/logging.html "
                                        "for details)");
+       rspamd_rcl_add_default_handler (sub,
+                       "encryption_key",
+                       rspamd_rcl_parse_struct_pubkey,
+                       G_STRUCT_OFFSET (struct rspamd_config, log_encryption_key),
+                       0,
+                       "Encrypt sensitive information in logs using this pubkey");
        /**
         * Options section
         */
index 3f49d430de4d9cf273e22ed0abd41b7e0744ccce..a57eacfa672328f29f3ef560f49e2621c0ed3b18 100644 (file)
@@ -19,6 +19,8 @@
 #include "rspamd.h"
 #include "map.h"
 #include "cryptobox.h"
+#include "ottery.h"
+#include "keypair.h"
 #include "unix-std.h"
 
 #ifdef HAVE_SYSLOG_H
@@ -38,6 +40,8 @@
 struct rspamd_logger_s {
        rspamd_log_func_t log_func;
        struct rspamd_config *cfg;
+       struct rspamd_cryptobox_pubkey *pk;
+       struct rspamd_cryptobox_keypair *keypair;
        struct {
                guint32 size;
                guint32 used;
@@ -311,59 +315,80 @@ rspamd_set_logger (struct rspamd_config *cfg,
                GQuark ptype,
                struct rspamd_main *rspamd)
 {
+       rspamd_logger_t *logger;
+
        if (rspamd->logger == NULL) {
                rspamd->logger = g_slice_alloc0 (sizeof (rspamd_logger_t));
        }
 
-       rspamd->logger->type = cfg->log_type;
-       rspamd->logger->pid = getpid ();
-       rspamd->logger->process_type = ptype;
+       logger = rspamd->logger;
+
+       logger->type = cfg->log_type;
+       logger->pid = getpid ();
+       logger->process_type = ptype;
 
        switch (cfg->log_type) {
                case RSPAMD_LOG_CONSOLE:
-                       rspamd->logger->log_func = file_log_function;
-                       rspamd->logger->fd = STDERR_FILENO;
+                       logger->log_func = file_log_function;
+                       logger->fd = STDERR_FILENO;
                        break;
                case RSPAMD_LOG_SYSLOG:
-                       rspamd->logger->log_func = syslog_log_function;
+                       logger->log_func = syslog_log_function;
                        break;
                case RSPAMD_LOG_FILE:
-                       rspamd->logger->log_func = file_log_function;
+                       logger->log_func = file_log_function;
                        break;
        }
 
-       rspamd->logger->cfg = cfg;
+       logger->cfg = cfg;
+
        /* Set up buffer */
-       if (rspamd->cfg->log_buffered) {
-               if (rspamd->cfg->log_buf_size != 0) {
-                       rspamd->logger->io_buf.size = rspamd->cfg->log_buf_size;
+       if (cfg->log_buffered) {
+               if (cfg->log_buf_size != 0) {
+                       logger->io_buf.size = cfg->log_buf_size;
                }
                else {
-                       rspamd->logger->io_buf.size = BUFSIZ;
+                       logger->io_buf.size = BUFSIZ;
                }
-               rspamd->logger->is_buffered = TRUE;
-               rspamd->logger->io_buf.buf = g_malloc (rspamd->logger->io_buf.size);
+               logger->is_buffered = TRUE;
+               logger->io_buf.buf = g_malloc (logger->io_buf.size);
        }
        /* Set up conditional logging */
-       if (rspamd->cfg->debug_ip_map != NULL) {
+       if (cfg->debug_ip_map != NULL) {
                /* Try to add it as map first of all */
-               if (rspamd->logger->debug_ip) {
-                       radix_destroy_compressed (rspamd->logger->debug_ip);
+               if (logger->debug_ip) {
+                       radix_destroy_compressed (logger->debug_ip);
                }
 
-               rspamd->logger->debug_ip = NULL;
-
-               rspamd_config_radix_from_ucl (rspamd->cfg,
-                               rspamd->cfg->debug_ip_map,
+               logger->debug_ip = NULL;
+               rspamd_config_radix_from_ucl (cfg,
+                               cfg->debug_ip_map,
                                "IP addresses for which debug logs are enabled",
-                               &rspamd->logger->debug_ip, NULL);
+                               &logger->debug_ip, NULL);
+       }
+       else if (logger->debug_ip) {
+               radix_destroy_compressed (logger->debug_ip);
+               logger->debug_ip = NULL;
+       }
+
+       if (logger->pk) {
+               rspamd_pubkey_unref (logger->pk);
+       }
+       logger->pk = NULL;
+
+       if (logger->keypair) {
+               rspamd_keypair_unref (logger->keypair);
        }
-       else if (rspamd->logger->debug_ip) {
-               radix_destroy_compressed (rspamd->logger->debug_ip);
-               rspamd->logger->debug_ip = NULL;
+       logger->keypair = NULL;
+
+       if (cfg->log_encryption_key) {
+               logger->pk = rspamd_pubkey_ref (cfg->log_encryption_key);
+               logger->keypair = rspamd_keypair_new (RSPAMD_KEYPAIR_KEX,
+                               RSPAMD_CRYPTOBOX_MODE_25519);
+               rspamd_pubkey_calculate_nm (logger->pk, logger->keypair);
        }
 
-       default_logger = rspamd->logger;
+       default_logger = logger;
 }
 
 /**
@@ -428,12 +453,50 @@ rspamd_logger_need_log (rspamd_logger_t *rspamd_log, GLogLevelFlags log_level,
        return FALSE;
 }
 
+static gchar *
+rspamd_log_encrypt_message (const gchar *begin, const gchar *end,
+               rspamd_logger_t *rspamd_log)
+{
+       guchar *out;
+       gchar *b64;
+       guchar *p, *nonce, *mac;
+       const guchar *comp;
+       guint len, inlen;
+
+       g_assert (end > begin);
+       /* base64 (pubkey | nonce | message) */
+       inlen = rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519) +
+                       rspamd_cryptobox_pk_bytes (RSPAMD_CRYPTOBOX_MODE_25519) +
+                       rspamd_cryptobox_mac_bytes (RSPAMD_CRYPTOBOX_MODE_25519) +
+                       (end - begin);
+       out = g_malloc (inlen);
+
+       p = out;
+       comp = rspamd_pubkey_get_pk (rspamd_log->pk, &len);
+       memcpy (p, comp, len);
+       p += len;
+       ottery_rand_bytes (p, rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519));
+       nonce = p;
+       p += rspamd_cryptobox_nonce_bytes (RSPAMD_CRYPTOBOX_MODE_25519);
+       mac = p;
+       p += rspamd_cryptobox_mac_bytes (RSPAMD_CRYPTOBOX_MODE_25519);
+       memcpy (p, begin, end - begin);
+       comp = rspamd_pubkey_get_nm (rspamd_log->pk);
+       g_assert (comp != NULL);
+       rspamd_cryptobox_encrypt_nm_inplace (p, end - begin, nonce, comp, mac,
+                       RSPAMD_CRYPTOBOX_MODE_25519);
+       b64 = rspamd_encode_base64 (out, inlen, 0, NULL);
+       g_free (out);
+
+       return b64;
+}
+
 void
 rspamd_common_logv (rspamd_logger_t *rspamd_log, gint level_flags,
                const gchar *module, const gchar *id, const gchar *function,
                const gchar *fmt, va_list args)
 {
-       gchar logbuf[RSPAMD_LOGBUF_SIZE];
+       gchar logbuf[RSPAMD_LOGBUF_SIZE], *end;
        gint level = level_flags & (RSPAMD_LOG_LEVEL_MASK|G_LOG_LEVEL_MASK);
 
        if (rspamd_log == NULL) {
@@ -449,12 +512,26 @@ rspamd_common_logv (rspamd_logger_t *rspamd_log, gint level_flags,
        }
        else {
                if (rspamd_logger_need_log (rspamd_log, level, module)) {
-                       rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, args);
-                       rspamd_log->log_func (module, id,
-                                       function,
-                                       level_flags,
-                                       logbuf,
-                                       rspamd_log);
+                       end = rspamd_vsnprintf (logbuf, sizeof (logbuf), fmt, args);
+
+                       if ((level_flags & RSPAMD_LOG_ENCRYPTED) && rspamd_log->pk) {
+                               gchar *encrypted;
+
+                               encrypted = rspamd_log_encrypt_message (logbuf, end, rspamd_log);
+                               rspamd_log->log_func (module, id,
+                                               function,
+                                               level_flags,
+                                               encrypted,
+                                               rspamd_log);
+                               g_free (encrypted);
+                       }
+                       else {
+                               rspamd_log->log_func (module, id,
+                                               function,
+                                               level_flags,
+                                               logbuf,
+                                               rspamd_log);
+                       }
 
                        switch (level) {
                        case G_LOG_LEVEL_CRITICAL: