Browse Source

Add signatures checks for local files

tags/1.2.0
Vsevolod Stakhov 8 years ago
parent
commit
a29d1caf57
2 changed files with 106 additions and 45 deletions
  1. 106
    43
      src/libutil/map.c
  2. 0
    2
      src/libutil/map_private.h

+ 106
- 43
src/libutil/map.c View File

@@ -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));

+ 0
- 2
src/libutil/map_private.h View File

@@ -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;
};


Loading…
Cancel
Save