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
*/
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
*/
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) {
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;
}
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
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;
}
}
+ map->protocol = MAP_PROTO_FILE;
+
if (g_ascii_strncasecmp (pos, "http://",
sizeof ("http://") - 1) == 0) {
map->protocol = MAP_PROTO_HTTP;
}
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;
}
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;
}
/* 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));
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));