diff options
author | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2016-02-15 16:47:57 +0000 |
---|---|---|
committer | Vsevolod Stakhov <vsevolod@highsecure.ru> | 2016-02-15 16:47:57 +0000 |
commit | a29d1caf57379e4864ab9680abfbf105f23b0be1 (patch) | |
tree | 18a2f97a4ef4c63a2627aac651a22d366092c94f /src | |
parent | 2575a3dc952f1875037029fbeaadf3f724902611 (diff) | |
download | rspamd-a29d1caf57379e4864ab9680abfbf105f23b0be1.tar.gz rspamd-a29d1caf57379e4864ab9680abfbf105f23b0be1.zip |
Add signatures checks for local files
Diffstat (limited to 'src')
-rw-r--r-- | src/libutil/map.c | 149 | ||||
-rw-r--r-- | src/libutil/map_private.h | 2 |
2 files changed, 106 insertions, 45 deletions
diff --git a/src/libutil/map.c b/src/libutil/map.c index 44048d743..805086633 100644 --- a/src/libutil/map.c +++ b/src/libutil/map.c @@ -26,12 +26,6 @@ static const gchar *hash_fill = "1"; -/* Value in seconds after whitch we would try to do stat on list file */ - -/* HTTP timeouts */ -#define HTTP_CONNECT_TIMEOUT 2 -#define HTTP_READ_TIMEOUT 10 - /** * Helper for HTTP connection establishment */ @@ -197,6 +191,91 @@ http_map_read (struct rspamd_http_connection *conn, return 0; } +static gboolean +rspamd_map_check_file_sig (const char *fname, + struct rspamd_map *map, const guchar *input, + gsize inlen) +{ + gchar fpath[PATH_MAX]; + rspamd_mempool_t *pool = map->pool; + guchar *data; + struct rspamd_cryptobox_pubkey *pk = NULL; + GString *b32_key; + gsize len = 0; + + if (map->trusted_pubkey == NULL) { + /* Try to load and check pubkey */ + rspamd_snprintf (fpath, sizeof (fpath), "%s.pub", fname); + + data = rspamd_file_xmap (fpath, PROT_READ, &len); + + if (data == NULL) { + msg_err_pool ("can't open pubkey %s: %s", fpath, strerror (errno)); + return FALSE; + } + + pk = rspamd_pubkey_from_base32 (data, len, RSPAMD_KEYPAIR_SIGN, + RSPAMD_CRYPTOBOX_MODE_25519); + munmap (data, len); + + if (pk == NULL) { + msg_err_pool ("can't load pubkey %s", fpath); + return FALSE; + } + + /* We just check pk against the trusted db of keys */ + b32_key = rspamd_pubkey_print (pk, + RSPAMD_KEYPAIR_BASE32|RSPAMD_KEYPAIR_PUBKEY); + g_assert (b32_key != NULL); + + if (g_hash_table_lookup (map->cfg->trusted_keys, b32_key->str) == NULL) { + msg_err_pool ("pubkey loaded from %s is untrusted: %v", fpath, + b32_key); + g_string_free (b32_key, TRUE); + rspamd_pubkey_unref (pk); + + return FALSE; + } + + g_string_free (b32_key, TRUE); + } + else { + pk = rspamd_pubkey_ref (map->trusted_pubkey); + } + + /* Now load signature */ + rspamd_snprintf (fpath, sizeof (fpath), "%s.sig", fname); + data = rspamd_file_xmap (fpath, PROT_READ, &len); + + if (data == NULL) { + msg_err_pool ("can't open signature %s: %s", fpath, strerror (errno)); + rspamd_pubkey_unref (pk); + return FALSE; + } + + if (len != rspamd_cryptobox_signature_bytes (RSPAMD_CRYPTOBOX_MODE_25519)) { + msg_err_pool ("can't open signature %s: invalid signature", fpath); + rspamd_pubkey_unref (pk); + munmap (data, len); + + return FALSE; + } + + if (!rspamd_cryptobox_verify (data, input, inlen, + rspamd_pubkey_get_pk (pk, NULL), RSPAMD_CRYPTOBOX_MODE_25519)) { + msg_err_pool ("can't verify signature %s: incorrect signature", fpath); + rspamd_pubkey_unref (pk); + munmap (data, len); + + return FALSE; + } + + rspamd_pubkey_unref (pk); + munmap (data, len); + + return TRUE; +} + /** * Callback for reading data from file */ @@ -204,9 +283,8 @@ static void read_map_file (struct rspamd_map *map, struct file_map_data *data) { struct map_cb_data cbdata; - gchar buf[BUFSIZ], *remain = NULL; - ssize_t r; - gint fd, rlen, tlen; + guchar *bytes; + gsize len; rspamd_mempool_t *pool = map->pool; if (map->read_callback == NULL || map->fin_callback == NULL) { @@ -214,9 +292,10 @@ read_map_file (struct rspamd_map *map, struct file_map_data *data) return; } - if ((fd = open (data->filename, O_RDONLY)) == -1) { - msg_warn_pool ("cannot open file '%s': %s", data->filename, - strerror (errno)); + bytes = rspamd_file_xmap (data->filename, PROT_READ, &len); + + if (bytes == NULL) { + msg_err_pool ("can't open map %s: %s", data->filename, strerror (errno)); return; } @@ -225,38 +304,22 @@ read_map_file (struct rspamd_map *map, struct file_map_data *data) cbdata.cur_data = NULL; cbdata.map = map; - rlen = 0; - tlen = 0; - while ((r = read (fd, buf + rlen, sizeof (buf) - rlen - 2)) > 0) { - r += rlen; - tlen += r; - buf[r] = '\0'; - remain = map->read_callback (map->pool, buf, r, &cbdata); - - if (remain != NULL) { - /* copy remaining buffer to start of buffer */ - rlen = r - (remain - buf); - memmove (buf, remain, rlen); - } - else { - rlen = 0; - } - } + if (map->is_signed) { + if (!rspamd_map_check_file_sig (data->filename, map, bytes, len)) { + munmap (bytes, len); - if (remain != NULL && remain > buf) { - g_assert (rlen <= (gint)sizeof (buf) - 2); - buf[rlen++] = '\n'; - buf[rlen] = '\0'; - tlen += rlen; - map->read_callback (map->pool, buf, rlen, &cbdata); + return; + } } - close (fd); + map->read_callback (map->pool, bytes, len, &cbdata); - if (tlen > 0) { + if (len > 0) { map->fin_callback (map->pool, &cbdata); *map->user_data = cbdata.cur_data; } + + munmap (bytes, len); } static void @@ -356,7 +419,7 @@ http_callback (gint fd, short what, void *ud) cbd->cbdata.prev_data = *cbd->map->user_data; cbd->cbdata.cur_data = NULL; cbd->cbdata.map = cbd->map; - cbd->tv.tv_sec = HTTP_CONNECT_TIMEOUT; + cbd->tv.tv_sec = 5; cbd->tv.tv_usec = 0; cbd->fd = sock; data->conn->ud = cbd; @@ -450,6 +513,8 @@ rspamd_map_check_proto (struct rspamd_config *cfg, } } + map->protocol = MAP_PROTO_FILE; + if (g_ascii_strncasecmp (pos, "http://", sizeof ("http://") - 1) == 0) { map->protocol = MAP_PROTO_HTTP; @@ -459,18 +524,17 @@ rspamd_map_check_proto (struct rspamd_config *cfg, } else if (g_ascii_strncasecmp (pos, "file://", sizeof ("file://") - 1) == 0) { - map->protocol = MAP_PROTO_FILE; pos += sizeof ("file://") - 1; /* Exclude file:// */ map->uri = rspamd_mempool_strdup (cfg->cfg_pool, pos); } else if (*pos == '/') { /* Trivial file case */ - map->protocol = MAP_PROTO_FILE; map->uri = rspamd_mempool_strdup (cfg->cfg_pool, pos); } else { msg_err_config ("invalid map fetching protocol: %s", map_line); + return NULL; } @@ -487,7 +551,6 @@ rspamd_map_add (struct rspamd_config *cfg, void **user_data) { struct rspamd_map *new_map; - enum fetch_proto proto; const gchar *def, *p, *hostend; struct file_map_data *fdata; struct http_map_data *hdata; @@ -525,7 +588,7 @@ rspamd_map_add (struct rspamd_config *cfg, } /* Now check for each proto separately */ - if (proto == MAP_PROTO_FILE) { + if (new_map->protocol == MAP_PROTO_FILE) { fdata = rspamd_mempool_alloc0 (cfg->map_pool, sizeof (struct file_map_data)); @@ -548,7 +611,7 @@ rspamd_map_add (struct rspamd_config *cfg, fdata->filename = rspamd_mempool_strdup (cfg->map_pool, def); new_map->map_data = fdata; } - else if (proto == MAP_PROTO_HTTP) { + else if (new_map->protocol == MAP_PROTO_HTTP) { hdata = rspamd_mempool_alloc0 (cfg->map_pool, sizeof (struct http_map_data)); diff --git a/src/libutil/map_private.h b/src/libutil/map_private.h index 39a546de6..4bfd9b9d3 100644 --- a/src/libutil/map_private.h +++ b/src/libutil/map_private.h @@ -74,9 +74,7 @@ struct http_callback_data { struct rspamd_map *map; struct http_map_data *data; struct map_cb_data cbdata; - GString *remain_buf; - gint fd; }; |