static int http_map_read (struct rspamd_http_connection *conn, struct rspamd_http_message *msg, const gchar *chunk, gsize len) { struct http_callback_data *cbd = conn->ud; struct rspamd_map *map; if (msg->code != 200 || len == 0) { /* Ignore not full replies */ return 0; } map = cbd->map; if (write (cbd->out_fd, chunk, len) == -1) { msg_err_map ("cannot write to %s: %s", cbd->tmpfile, strerror (errno)); MAP_RELEASE (cbd); return -1; } return 0; }
void rspamd_map_remove_all (struct rspamd_config *cfg) { struct rspamd_map *map; GList *cur; struct rspamd_map_backend *bk; guint i; for (cur = cfg->maps; cur != NULL; cur = g_list_next (cur)) { map = cur->data; for (i = 0; i < map->backends->len; i ++) { bk = g_ptr_array_index (map->backends, i); MAP_RELEASE (bk, "rspamd_map_backend"); } if (g_atomic_int_compare_and_exchange (&map->cache->available, 1, 0)) { unlink (map->cache->shmem_name); } if (map->dtor) { map->dtor (map->dtor_data); } } g_list_free (cfg->maps); cfg->maps = NULL; }
/** * Callback for destroying HTTP callback data */ static void free_http_cbdata_common (struct http_callback_data *cbd, gboolean plan_new) { char fpath[PATH_MAX]; struct stat st; struct map_periodic_cbdata *periodic = cbd->periodic; if (cbd->out_fd != -1) { close (cbd->out_fd); } rspamd_snprintf (fpath, sizeof (fpath), "%s", cbd->tmpfile); if (stat (fpath, &st) != -1 && S_ISREG (st.st_mode)) { (void)unlink (fpath); } rspamd_snprintf (fpath, sizeof (fpath), "%s.pub", cbd->tmpfile); if (stat (fpath, &st) != -1 && S_ISREG (st.st_mode)) { (void)unlink (fpath); } rspamd_snprintf (fpath, sizeof (fpath), "%s.sig", cbd->tmpfile); if (stat (fpath, &st) != -1 && S_ISREG (st.st_mode)) { (void)unlink (fpath); } if (cbd->pk) { rspamd_pubkey_unref (cbd->pk); } if (cbd->conn) { rspamd_http_connection_unref (cbd->conn); cbd->conn = NULL; } if (cbd->fd != -1) { close (cbd->fd); } if (cbd->addr) { rspamd_inet_address_destroy (cbd->addr); } MAP_RELEASE (cbd->bk); MAP_RELEASE (periodic); g_slice_free1 (sizeof (struct http_callback_data), cbd); }
static void rspamd_map_periodic_callback (gint fd, short what, void *ud) { struct rspamd_map_backend *bk; struct map_periodic_cbdata *cbd = ud; if (cbd->errored) { /* We should not check other backends if some backend has failed */ rspamd_map_schedule_periodic (cbd->map, FALSE, FALSE, TRUE); g_atomic_int_set (cbd->map->locked, 0); MAP_RELEASE (cbd); return; } /* For each backend we need to check for modifications */ if (cbd->cur_backend >= cbd->map->backends->len) { /* Last backend */ MAP_RELEASE (cbd); return; } bk = g_ptr_array_index (cbd->map->backends, cbd->cur_backend); g_assert (bk != NULL); if (cbd->need_modify) { /* Load data from the next backend */ if (bk->protocol == MAP_PROTO_HTTP) { rspamd_map_http_read_callback (fd, what, cbd); } else { rspamd_map_file_read_callback (fd, what, cbd); } } else { /* Check the next backend */ if (bk->protocol == MAP_PROTO_HTTP) { rspamd_map_http_check_callback (fd, what, cbd); } else { rspamd_map_file_check_callback (fd, what, cbd); } } }
static void rspamd_map_cache_cb (gint fd, short what, gpointer ud) { struct rspamd_http_map_cached_cbdata *cache_cbd = ud; g_atomic_int_set (&cache_cbd->map->cache->available, 0); MAP_RELEASE (cache_cbd->shm, "rspamd_http_map_cached_cbdata"); event_del (&cache_cbd->timeout); g_slice_free1 (sizeof (*cache_cbd), cache_cbd); }
static void rspamd_map_dns_callback (struct rdns_reply *reply, void *arg) { struct http_callback_data *cbd = arg; struct rspamd_map *map; guint flags = RSPAMD_HTTP_CLIENT_SIMPLE|RSPAMD_HTTP_CLIENT_SHARED; map = cbd->map; if (reply->code == RDNS_RC_NOERROR) { /* * We just get the first address hoping that a resolver performs * round-robin rotation well */ if (cbd->addr == NULL) { cbd->addr = rspamd_inet_address_from_rnds (reply->entries); if (cbd->addr != NULL) { rspamd_inet_address_set_port (cbd->addr, cbd->data->port); /* Try to open a socket */ cbd->fd = rspamd_inet_address_connect (cbd->addr, SOCK_STREAM, TRUE); if (cbd->fd != -1) { cbd->stage = map_load_file; cbd->conn = rspamd_http_connection_new (NULL, http_map_error, http_map_finish, flags, RSPAMD_HTTP_CLIENT, NULL, cbd->map->cfg->libs_ctx->ssl_ctx); write_http_request (cbd); } else { rspamd_inet_address_destroy (cbd->addr); cbd->addr = NULL; } } } } else if (cbd->stage < map_load_file) { if (cbd->stage == map_resolve_host2) { /* We have still one request pending */ cbd->stage = map_resolve_host1; } else { /* We could not resolve host, so cowardly fail here */ msg_err_map ("cannot resolve %s", cbd->data->host); } } MAP_RELEASE (cbd, "http_callback_data"); }
/* * HTTP callbacks */ static void http_map_error (struct rspamd_http_connection *conn, GError *err) { struct http_callback_data *cbd = conn->ud; struct rspamd_map *map; map = cbd->map; cbd->periodic->errored = TRUE; msg_err_map ("connection with http server terminated incorrectly: %e", err); rspamd_map_periodic_callback (-1, EV_TIMEOUT, cbd->periodic); MAP_RELEASE (cbd, "http_callback_data"); }
/** * Callback for destroying HTTP callback data */ static void free_http_cbdata_common (struct http_callback_data *cbd, gboolean plan_new) { struct map_periodic_cbdata *periodic = cbd->periodic; if (cbd->shmem_sig) { rspamd_http_message_shmem_unref (cbd->shmem_sig); } if (cbd->shmem_pubkey) { rspamd_http_message_shmem_unref (cbd->shmem_pubkey); } if (cbd->shmem_data) { rspamd_http_message_shmem_unref (cbd->shmem_data); } if (cbd->pk) { rspamd_pubkey_unref (cbd->pk); } if (cbd->conn) { rspamd_http_connection_unref (cbd->conn); cbd->conn = NULL; } if (cbd->fd != -1) { close (cbd->fd); } if (cbd->addr) { rspamd_inet_address_destroy (cbd->addr); } MAP_RELEASE (cbd->bk, "rspamd_map_backend"); MAP_RELEASE (periodic, "periodic"); g_slice_free1 (sizeof (struct http_callback_data), cbd); }
void rspamd_map_remove_all (struct rspamd_config *cfg) { struct rspamd_map *map; GList *cur; struct rspamd_map_backend *bk; guint i; for (cur = cfg->maps; cur != NULL; cur = g_list_next (cur)) { map = cur->data; for (i = 0; i < map->backends->len; i ++) { bk = g_ptr_array_index (map->backends, i); MAP_RELEASE (bk); } if (map->dtor) { map->dtor (map->dtor_data); } } g_list_free (cfg->maps); cfg->maps = NULL; }
static void rspamd_map_periodic_callback (gint fd, short what, void *ud) { struct rspamd_map_backend *bk; struct map_periodic_cbdata *cbd = ud; struct rspamd_map *map; map = cbd->map; if (!cbd->locked) { if (!g_atomic_int_compare_and_exchange (cbd->map->locked, 0, 1)) { msg_debug_map ( "don't try to reread map as it is locked by other process, " "will reread it later"); rspamd_map_schedule_periodic (map, TRUE, FALSE, FALSE); MAP_RELEASE (cbd, "periodic"); return; } else { cbd->locked = TRUE; } } if (cbd->errored) { /* We should not check other backends if some backend has failed */ rspamd_map_schedule_periodic (cbd->map, FALSE, FALSE, TRUE); if (cbd->locked) { g_atomic_int_set (cbd->map->locked, 0); } MAP_RELEASE (cbd, "periodic"); return; } /* For each backend we need to check for modifications */ if (cbd->cur_backend >= cbd->map->backends->len) { /* Last backend */ MAP_RELEASE (cbd, "periodic"); return; } bk = g_ptr_array_index (cbd->map->backends, cbd->cur_backend); g_assert (bk != NULL); if (cbd->need_modify) { /* Load data from the next backend */ if (bk->protocol == MAP_PROTO_HTTP || bk->protocol == MAP_PROTO_HTTPS) { rspamd_map_http_read_callback (fd, what, cbd); } else { rspamd_map_file_read_callback (fd, what, cbd); } } else { /* Check the next backend */ if (bk->protocol == MAP_PROTO_HTTP || bk->protocol == MAP_PROTO_HTTPS) { rspamd_map_http_check_callback (fd, what, cbd); } else { rspamd_map_file_check_callback (fd, what, cbd); } } }
/** * Async HTTP callback */ static void rspamd_map_common_http_callback (struct rspamd_map *map, struct rspamd_map_backend *bk, struct map_periodic_cbdata *periodic, gboolean check) { struct http_map_data *data; struct http_callback_data *cbd; data = bk->data.hd; if (g_atomic_int_get (&map->cache->available) == 1) { /* Read cached data */ if (check) { if (data->last_checked < map->cache->last_checked) { periodic->need_modify = TRUE; /* Reset the whole chain */ periodic->cur_backend = 0; rspamd_map_periodic_callback (-1, EV_TIMEOUT, periodic); } return; } else if (rspamd_map_read_cached (map, periodic, data->host)) { /* Switch to the next backend */ periodic->cur_backend ++; rspamd_map_periodic_callback (-1, EV_TIMEOUT, periodic); data->last_checked = map->cache->last_checked; return; } } cbd = g_slice_alloc0 (sizeof (struct http_callback_data)); cbd->ev_base = map->ev_base; cbd->map = map; cbd->data = data; cbd->fd = -1; cbd->check = check; cbd->periodic = periodic; MAP_RETAIN (periodic, "periodic"); cbd->bk = bk; MAP_RETAIN (bk, "rspamd_map_backend"); cbd->stage = map_resolve_host2; double_to_tv (map->cfg->map_timeout, &cbd->tv); REF_INIT_RETAIN (cbd, free_http_cbdata); msg_debug_map ("%s map data from %s", check ? "checking" : "reading", data->host); /* Send both A and AAAA requests */ if (map->r->r) { if (rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd, map->cfg->dns_timeout, map->cfg->dns_retransmits, 1, data->host, RDNS_REQUEST_A)) { MAP_RETAIN (cbd, "http_callback_data"); } if (rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd, map->cfg->dns_timeout, map->cfg->dns_retransmits, 1, data->host, RDNS_REQUEST_AAAA)) { MAP_RETAIN (cbd, "http_callback_data"); } map->dtor = free_http_cbdata_dtor; map->dtor_data = cbd; } else { msg_warn_map ("cannot load map: DNS resolver is not initialized"); cbd->periodic->errored = TRUE; } /* We don't need own ref as it is now ref counted by DNS handlers */ MAP_RELEASE (cbd, "http_callback_data"); }
static int http_map_finish (struct rspamd_http_connection *conn, struct rspamd_http_message *msg) { struct http_callback_data *cbd = conn->ud; struct rspamd_map *map; struct rspamd_map_backend *bk; guchar *aux_data, *in = NULL; gsize inlen = 0, dlen = 0; map = cbd->map; bk = cbd->bk; if (msg->code == 200) { if (cbd->check) { cbd->periodic->need_modify = TRUE; /* Reset the whole chain */ cbd->periodic->cur_backend = 0; rspamd_map_periodic_callback (-1, EV_TIMEOUT, cbd->periodic); MAP_RELEASE (cbd, "http_callback_data"); return 0; } if (cbd->stage == map_load_file) { if (msg->last_modified) { cbd->data->last_checked = msg->last_modified; } else { cbd->data->last_checked = msg->date; } /* Maybe we need to check signature ? */ if (bk->is_signed) { if (bk->trusted_pubkey) { /* No need to load key */ cbd->stage = map_load_signature; cbd->pk = rspamd_pubkey_ref (bk->trusted_pubkey); } else { cbd->stage = map_load_pubkey; } cbd->shmem_data = rspamd_http_message_shmem_ref (msg); cbd->data_len = msg->body_buf.len; rspamd_http_connection_reset (cbd->conn); write_http_request (cbd); MAP_RELEASE (cbd, "http_callback_data"); return 0; } else { /* Unsinged version - just open file */ cbd->shmem_data = rspamd_http_message_shmem_ref (msg); cbd->data_len = msg->body_buf.len; goto read_data; } } else if (cbd->stage == map_load_pubkey) { /* We now can load pubkey */ cbd->shmem_pubkey = rspamd_http_message_shmem_ref (msg); cbd->pubkey_len = msg->body_buf.len; aux_data = rspamd_shmem_xmap (cbd->shmem_pubkey->shm_name, PROT_READ, &inlen); if (aux_data == NULL) { msg_err_map ("cannot map pubkey file %s: %s", cbd->shmem_pubkey->shm_name, strerror (errno)); goto err; } if (inlen < cbd->pubkey_len) { msg_err_map ("cannot map pubkey file %s: %s", cbd->shmem_pubkey->shm_name, strerror (errno)); munmap (aux_data, inlen); goto err; } cbd->pk = rspamd_pubkey_from_base32 (aux_data, cbd->pubkey_len, RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519); munmap (aux_data, inlen); if (cbd->pk == NULL) { msg_err_map ("cannot load pubkey file %s: bad pubkey", cbd->shmem_pubkey->shm_name); goto err; } cbd->stage = map_load_signature; rspamd_http_connection_reset (cbd->conn); write_http_request (cbd); MAP_RELEASE (cbd, "http_callback_data"); return 0; } else if (cbd->stage == map_load_signature) { /* We can now check signature */ cbd->shmem_sig = rspamd_http_message_shmem_ref (msg); cbd->sig_len = msg->body_buf.len; aux_data = rspamd_shmem_xmap (cbd->shmem_sig->shm_name, PROT_READ, &inlen); if (aux_data == NULL) { msg_err_map ("cannot map signature file %s: %s", cbd->shmem_sig->shm_name, strerror (errno)); goto err; } if (inlen < cbd->sig_len) { msg_err_map ("cannot map pubkey file %s: %s", cbd->shmem_pubkey->shm_name, strerror (errno)); munmap (aux_data, inlen); goto err; } in = rspamd_shmem_xmap (cbd->shmem_data->shm_name, PROT_READ, &dlen); if (in == NULL) { msg_err_map ("cannot read tempfile %s: %s", cbd->shmem_data->shm_name, strerror (errno)); munmap (aux_data, inlen); goto err; } if (!rspamd_map_check_sig_pk_mem (aux_data, cbd->sig_len, map, in, cbd->data_len, cbd->pk)) { munmap (aux_data, inlen); munmap (in, dlen); goto err; } munmap (in, dlen); } read_data: g_assert (cbd->shmem_data != NULL); in = rspamd_shmem_xmap (cbd->shmem_data->shm_name, PROT_READ, &dlen); if (in == NULL) { msg_err_map ("cannot read tempfile %s: %s", cbd->shmem_data->shm_name, strerror (errno)); goto err; } map->read_callback (in, cbd->data_len, &cbd->periodic->cbdata, TRUE); msg_info_map ("read map data from %s", cbd->data->host); /* * We know that a map is in the locked state */ if (g_atomic_int_compare_and_exchange (&map->cache->available, 0, 1)) { /* Store cached data */ struct rspamd_http_map_cached_cbdata *cache_cbd; struct timeval tv; rspamd_strlcpy (map->cache->shmem_name, cbd->shmem_data->shm_name, sizeof (map->cache->shmem_name)); map->cache->len = cbd->data_len; map->cache->last_checked = cbd->data->last_checked; cache_cbd = g_slice_alloc0 (sizeof (*cache_cbd)); cache_cbd->shm = cbd->shmem_data; cache_cbd->map = map; MAP_RETAIN (cache_cbd->shm, "shmem_data"); event_set (&cache_cbd->timeout, -1, EV_TIMEOUT, rspamd_map_cache_cb, cache_cbd); event_base_set (cbd->ev_base, &cache_cbd->timeout); double_to_tv (map->poll_timeout, &tv); event_add (&cache_cbd->timeout, &tv); } cbd->periodic->cur_backend ++; munmap (in, dlen); rspamd_map_periodic_callback (-1, EV_TIMEOUT, cbd->periodic); } else if (msg->code == 304 && (cbd->check && cbd->stage == map_load_file)) { msg_debug_map ("data is not modified for server %s", cbd->data->host); if (msg->last_modified) { cbd->data->last_checked = msg->last_modified; } else { cbd->data->last_checked = msg->date; } cbd->periodic->cur_backend ++; rspamd_map_periodic_callback (-1, EV_TIMEOUT, cbd->periodic); } else { msg_info_map ("cannot load map %s from %s: HTTP error %d", bk->uri, cbd->data->host, msg->code); } MAP_RELEASE (cbd, "http_callback_data"); return 0; err: cbd->periodic->errored = 1; rspamd_map_periodic_callback (-1, EV_TIMEOUT, cbd->periodic); MAP_RELEASE (cbd, "http_callback_data"); return 0; }
static struct rspamd_map_backend * rspamd_map_parse_backend (struct rspamd_config *cfg, const gchar *map_line) { struct rspamd_map_backend *bk; struct file_map_data *fdata = NULL; struct http_map_data *hdata = NULL; struct http_parser_url up; rspamd_ftok_t tok; bk = g_slice_alloc0 (sizeof (*bk)); REF_INIT_RETAIN (bk, rspamd_map_backend_dtor); if (!rspamd_map_check_proto (cfg, map_line, bk)) { goto err; } /* Now check for each proto separately */ if (bk->protocol == MAP_PROTO_FILE) { fdata = g_slice_alloc0 (sizeof (struct file_map_data)); fdata->st.st_mtime = -1; if (access (bk->uri, R_OK) == -1) { if (errno != ENOENT) { msg_err_config ("cannot open file '%s': %s", bk->uri, strerror (errno)); return NULL; } msg_info_config ( "map '%s' is not found, but it can be loaded automatically later", bk->uri); } fdata->filename = g_strdup (bk->uri); bk->data.fd = fdata; } else if (bk->protocol == MAP_PROTO_HTTP || bk->protocol == MAP_PROTO_HTTPS) { hdata = g_slice_alloc0 (sizeof (struct http_map_data)); memset (&up, 0, sizeof (up)); if (http_parser_parse_url (bk->uri, strlen (bk->uri), FALSE, &up) != 0) { msg_err_config ("cannot parse HTTP url: %s", bk->uri); goto err; } else { if (!(up.field_set & 1 << UF_HOST)) { msg_err_config ("cannot parse HTTP url: %s: no host", bk->uri); return NULL; } tok.begin = bk->uri + up.field_data[UF_HOST].off; tok.len = up.field_data[UF_HOST].len; hdata->host = rspamd_ftokdup (&tok); if (up.field_set & 1 << UF_PORT) { hdata->port = up.port; } else { if (bk->protocol == MAP_PROTO_HTTP) { hdata->port = 80; } else { hdata->port = 443; } } if (up.field_set & 1 << UF_PATH) { tok.begin = bk->uri + up.field_data[UF_PATH].off; tok.len = strlen (tok.begin); hdata->path = rspamd_ftokdup (&tok); } } bk->data.hd = hdata; } return bk; err: MAP_RELEASE (bk, "rspamd_map_backend"); if (hdata) { g_slice_free1 (sizeof (*hdata), hdata); } if (fdata) { g_slice_free1 (sizeof (*fdata), fdata); } return NULL; }
/** * Async HTTP callback */ static void rspamd_map_common_http_callback (struct rspamd_map *map, struct rspamd_map_backend *bk, struct map_periodic_cbdata *periodic, gboolean check) { struct http_map_data *data; struct http_callback_data *cbd; gchar tmpbuf[PATH_MAX]; data = bk->data.hd; cbd = g_slice_alloc0 (sizeof (struct http_callback_data)); rspamd_snprintf (tmpbuf, sizeof (tmpbuf), "%s" G_DIR_SEPARATOR_S "rspamd_map%d-XXXXXX", map->cfg->temp_dir, map->id); cbd->out_fd = mkstemp (tmpbuf); if (cbd->out_fd == -1) { msg_err_map ("cannot create tempfile: %s", strerror (errno)); g_atomic_int_set (map->locked, 0); g_slice_free1 (sizeof (*cbd), cbd); periodic->errored = TRUE; rspamd_map_periodic_callback (-1, EV_TIMEOUT, periodic); return; } cbd->tmpfile = g_strdup (tmpbuf); cbd->ev_base = map->ev_base; cbd->map = map; cbd->data = data; cbd->fd = -1; cbd->check = check; cbd->periodic = periodic; MAP_RETAIN (periodic); cbd->bk = bk; MAP_RETAIN (bk); cbd->stage = map_resolve_host2; double_to_tv (map->cfg->map_timeout, &cbd->tv); REF_INIT_RETAIN (cbd, free_http_cbdata); msg_debug_map ("%s map data from %s", check ? "checking" : "reading", data->host); /* Send both A and AAAA requests */ if (map->r->r) { if (rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd, map->cfg->dns_timeout, map->cfg->dns_retransmits, 1, data->host, RDNS_REQUEST_A)) { MAP_RETAIN (cbd); } if (rdns_make_request_full (map->r->r, rspamd_map_dns_callback, cbd, map->cfg->dns_timeout, map->cfg->dns_retransmits, 1, data->host, RDNS_REQUEST_AAAA)) { MAP_RETAIN (cbd); } map->dtor = free_http_cbdata_dtor; map->dtor_data = cbd; } else { msg_warn_map ("cannot load map: DNS resolver is not initialized"); cbd->periodic->errored = TRUE; } /* We don't need own ref as it is now ref counted by DNS handlers */ MAP_RELEASE (cbd); }
static int http_map_finish (struct rspamd_http_connection *conn, struct rspamd_http_message *msg) { struct http_callback_data *cbd = conn->ud; struct rspamd_map *map; struct rspamd_map_backend *bk; char fpath[PATH_MAX]; guchar *aux_data, *in = NULL; gsize inlen = 0; struct stat st; map = cbd->map; bk = cbd->bk; if (msg->code == 200) { if (cbd->check) { cbd->periodic->need_modify = TRUE; /* Reset the whole chain */ cbd->periodic->cur_backend = 0; rspamd_map_periodic_callback (-1, EV_TIMEOUT, cbd->periodic); MAP_RELEASE (cbd); return 0; } if (cbd->stage == map_load_file) { if (msg->last_modified) { cbd->data->last_checked = msg->last_modified; } else { cbd->data->last_checked = msg->date; } /* Maybe we need to check signature ? */ if (bk->is_signed) { close (cbd->out_fd); if (bk->trusted_pubkey) { /* No need to load key */ cbd->stage = map_load_signature; cbd->pk = rspamd_pubkey_ref (bk->trusted_pubkey); rspamd_snprintf (fpath, sizeof (fpath), "%s.sig", cbd->tmpfile); } else { rspamd_snprintf (fpath, sizeof (fpath), "%s.pub", cbd->tmpfile); cbd->stage = map_load_pubkey; } cbd->out_fd = rspamd_file_xopen (fpath, O_RDWR|O_CREAT, 00644); if (cbd->out_fd == -1) { msg_err_map ("cannot open pubkey file %s for writing: %s", fpath, strerror (errno)); goto err; } rspamd_http_connection_reset (cbd->conn); write_http_request (cbd); MAP_RELEASE (cbd); return 0; } else { /* Unsinged version - just open file */ in = rspamd_file_xmap (cbd->tmpfile, PROT_READ, &inlen); if (in == NULL) { msg_err_map ("cannot read tempfile %s: %s", cbd->tmpfile, strerror (errno)); goto err; } } } else if (cbd->stage == map_load_pubkey) { /* We now can load pubkey */ (void)lseek (cbd->out_fd, 0, SEEK_SET); if (fstat (cbd->out_fd, &st) == -1) { msg_err_map ("cannot stat pubkey file %s: %s", fpath, strerror (errno)); goto err; } aux_data = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, cbd->out_fd, 0); close (cbd->out_fd); cbd->out_fd = -1; if (aux_data == MAP_FAILED) { msg_err_map ("cannot map pubkey file %s: %s", fpath, strerror (errno)); goto err; } cbd->pk = rspamd_pubkey_from_base32 (aux_data, st.st_size, RSPAMD_KEYPAIR_SIGN, RSPAMD_CRYPTOBOX_MODE_25519); munmap (aux_data, st.st_size); if (cbd->pk == NULL) { msg_err_map ("cannot load pubkey file %s: bad pubkey", fpath); goto err; } rspamd_snprintf (fpath, sizeof (fpath), "%s.sig", cbd->tmpfile); cbd->out_fd = rspamd_file_xopen (fpath, O_RDWR|O_CREAT, 00644); if (cbd->out_fd == -1) { msg_err_map ("cannot open signature file %s for writing: %s", fpath, strerror (errno)); goto err; } cbd->stage = map_load_signature; rspamd_http_connection_reset (cbd->conn); write_http_request (cbd); MAP_RELEASE (cbd); return 0; } else if (cbd->stage == map_load_signature) { /* We can now check signature */ close (cbd->out_fd); cbd->out_fd = -1; in = rspamd_file_xmap (cbd->tmpfile, PROT_READ, &inlen); if (in == NULL) { msg_err_map ("cannot read tempfile %s: %s", cbd->tmpfile, strerror (errno)); goto err; } if (!rspamd_map_check_sig_pk (cbd->tmpfile, map, in, inlen, cbd->pk)) { goto err; } } g_assert (in != NULL); map->read_callback (in, inlen, &cbd->periodic->cbdata, TRUE); msg_info_map ("read map data from %s", cbd->data->host); cbd->periodic->cur_backend ++; rspamd_map_periodic_callback (-1, EV_TIMEOUT, cbd->periodic); } else if (msg->code == 304 && (cbd->check && cbd->stage == map_load_file)) { msg_debug_map ("data is not modified for server %s", cbd->data->host); if (msg->last_modified) { cbd->data->last_checked = msg->last_modified; } else { cbd->data->last_checked = msg->date; } } else { msg_info_map ("cannot load map %s from %s: HTTP error %d", bk->uri, cbd->data->host, msg->code); } MAP_RELEASE (cbd); return 0; err: cbd->periodic->errored = 1; rspamd_map_periodic_callback (-1, EV_TIMEOUT, cbd->periodic); MAP_RELEASE (cbd); return 0; }