static gint rspamd_control_finish_handler (struct rspamd_http_connection *conn, struct rspamd_http_message *msg) { struct ucl_parser *parser; ucl_object_t *obj; rspamd_fstring_t *out; const gchar *body; gsize body_len; struct rspamadm_control_cbdata *cbdata = conn->ud; body = rspamd_http_message_get_body (msg, &body_len); parser = ucl_parser_new (0); if (!body || !ucl_parser_add_chunk (parser, body, body_len)) { rspamd_fprintf (stderr, "cannot parse server's reply: %s\n", ucl_parser_get_error (parser)); ucl_parser_free (parser); } else { obj = ucl_parser_get_object (parser); out = rspamd_fstring_new (); if (json) { rspamd_ucl_emit_fstring (obj, UCL_EMIT_JSON, &out); } else if (compact) { rspamd_ucl_emit_fstring (obj, UCL_EMIT_JSON_COMPACT, &out); } else { if (strcmp (cbdata->path, "/fuzzystat") == 0) { rspamadm_execute_lua_ucl_subr (cbdata->L, cbdata->argc, cbdata->argv, obj, rspamadm_script_fuzzy_stat); rspamd_fstring_free (out); ucl_object_unref (obj); ucl_parser_free (parser); return 0; } else { rspamd_ucl_emit_fstring (obj, UCL_EMIT_CONFIG, &out); } } rspamd_fprintf (stdout, "%V", out); rspamd_fstring_free (out); ucl_object_unref (obj); ucl_parser_free (parser); } return 0; }
static void rspamd_server_accept (gint fd, short what, void *arg) { struct event_base *ev_base = arg; struct rspamd_http_server_session *session; rspamd_inet_addr_t *addr; gint nfd; do { if ((nfd = rspamd_accept_from_socket (fd, &addr)) == -1) { rspamd_fprintf (stderr, "accept failed: %s", strerror (errno)); return; } /* Check for EAGAIN */ if (nfd == 0) { return; } rspamd_inet_address_destroy (addr); session = g_slice_alloc (sizeof (*session)); session->conn = rspamd_http_connection_new (NULL, rspamd_server_error, rspamd_server_finish, 0, RSPAMD_HTTP_SERVER, c); rspamd_http_connection_set_key (session->conn, server_key); rspamd_http_connection_read_message (session->conn, session, nfd, &io_tv, ev_base); session->reply = FALSE; session->fd = nfd; session->ev_base = ev_base; } while (nfd > 0); }
static void rspamd_process_file (const gchar *fname, gint decode) { gint fd; gpointer map; struct stat st; guint8 *dest; gsize destlen; fd = open (fname, O_RDONLY); if (fd == -1) { rspamd_fprintf (stderr, "cannot open %s: %s", fname, strerror (errno)); exit (EXIT_FAILURE); } if (fstat (fd, &st) == -1) { rspamd_fprintf (stderr, "cannot stat %s: %s", fname, strerror (errno)); exit (EXIT_FAILURE); } map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); close (fd); if (map == MAP_FAILED) { rspamd_fprintf (stderr, "cannot mmap %s: %s", fname, strerror (errno)); exit (EXIT_FAILURE); } if (decode) { destlen = st.st_size / 4 * 3 + 10; dest = g_malloc (destlen); rspamd_cryptobox_base64_decode (map, st.st_size, dest, &destlen); } else { dest = rspamd_encode_base64 (map, st.st_size, 80, &destlen); } rspamd_printf ("%*s", (gint)destlen, dest); g_free (dest); munmap (map, st.st_size); }
static void rspamd_server_error (struct rspamd_http_connection *conn, GError *err) { struct rspamd_http_server_session *session = conn->ud; rspamd_fprintf (stderr, "http error occurred: %s\n", err->message); rspamd_http_connection_unref (conn); close (session->fd); g_slice_free1 (sizeof (*session), session); }
static void rspamadm_confighelp_show (struct rspamd_config *cfg, gint argc, gchar **argv, const char *key, const ucl_object_t *obj) { rspamd_fstring_t *out; rspamd_lua_set_path (cfg->lua_state, NULL, ucl_vars); out = rspamd_fstring_new (); if (json) { rspamd_ucl_emit_fstring (obj, UCL_EMIT_JSON, &out); } else if (compact) { rspamd_ucl_emit_fstring (obj, UCL_EMIT_JSON_COMPACT, &out); } else { /* TODO: add lua helper for output */ if (key) { rspamd_fprintf (stdout, "Showing help for %s%s:\n", keyword ? "keyword " : "", key); } else { rspamd_fprintf (stdout, "Showing help for all options:\n"); } rspamadm_execute_lua_ucl_subr (argc, argv, obj, "confighelp", TRUE); rspamd_fstring_free (out); return; } rspamd_fprintf (stdout, "%V", out); rspamd_fprintf (stdout, "\n"); rspamd_fstring_free (out); }
static void rspamadm_confighelp (gint argc, gchar **argv, const struct rspamadm_command *cmd) { struct rspamd_config *cfg; ucl_object_t *doc_obj; const ucl_object_t *elt; GOptionContext *context; GError *error = NULL; module_t *mod, **pmod; worker_t **pworker; struct module_ctx *mod_ctx; gint i, ret = 0, processed_args = 0; context = g_option_context_new ( "confighelp - displays help for the configuration options"); g_option_context_set_summary (context, "Summary:\n Rspamd administration utility version " RVERSION "\n Release id: " RID); g_option_context_add_main_entries (context, entries, NULL); g_option_context_set_ignore_unknown_options (context, TRUE); if (!g_option_context_parse (context, &argc, &argv, &error)) { rspamd_fprintf (stderr, "option parsing failed: %s\n", error->message); g_error_free (error); exit (1); } pworker = &workers[0]; while (*pworker) { /* Init string quarks */ (void) g_quark_from_static_string ((*pworker)->name); pworker++; } cfg = rspamd_config_new (RSPAMD_CONFIG_INIT_SKIP_LUA); cfg->lua_state = rspamd_main->cfg->lua_state; cfg->compiled_modules = modules; cfg->compiled_workers = workers; rspamd_rcl_config_init (cfg, NULL); lua_pushboolean (cfg->lua_state, true); lua_setglobal (cfg->lua_state, "confighelp"); rspamd_rcl_add_lua_plugins_path (cfg, plugins_path, FALSE, NULL, NULL); /* Init modules to get documentation strings */ i = 0; for (pmod = cfg->compiled_modules; pmod != NULL && *pmod != NULL; pmod++) { mod = *pmod; mod_ctx = g_malloc0 (sizeof (struct module_ctx)); if (mod->module_init_func (cfg, &mod_ctx) == 0) { g_ptr_array_add (cfg->c_modules, mod_ctx); mod_ctx->mod = mod; mod->ctx_offset = i++; mod_ctx->mod = mod; } } /* Also init all workers */ for (pworker = cfg->compiled_workers; *pworker != NULL; pworker ++) { (*pworker)->worker_init_func (cfg); } /* Init lua modules */ rspamd_lua_set_path (cfg->lua_state, cfg->rcl_obj, ucl_vars); rspamd_init_lua_filters (cfg, TRUE); if (argc > 1) { for (i = 1; i < argc; i ++) { if (argv[i][0] != '-') { if (keyword) { doc_obj = rspamadm_confighelp_search_word (cfg->doc_strings, argv[i]); } else { doc_obj = ucl_object_typed_new (UCL_OBJECT); elt = ucl_object_lookup_path (cfg->doc_strings, argv[i]); if (elt) { ucl_object_insert_key (doc_obj, ucl_object_ref (elt), argv[i], 0, false); } } if (doc_obj != NULL) { rspamadm_confighelp_show (cfg, argc, argv, argv[i], doc_obj); ucl_object_unref (doc_obj); } else { rspamd_fprintf (stderr, "Cannot find help for %s\n", argv[i]); ret = EXIT_FAILURE; } processed_args ++; } } } if (processed_args == 0) { /* Show all documentation strings */ rspamadm_confighelp_show (cfg, argc, argv, NULL, cfg->doc_strings); } rspamd_config_free (cfg); exit (ret); }
static void rspamd_control_error_handler (struct rspamd_http_connection *conn, GError *err) { rspamd_fprintf (stderr, "Cannot make HTTP request: %e\n", err); rspamd_http_connection_unref (conn); }
static void rspamadm_control (gint argc, gchar **argv) { GOptionContext *context; GError *error = NULL; struct event_base *ev_base; const gchar *cmd, *path = NULL; struct rspamd_http_connection *conn; struct rspamd_http_message *msg; rspamd_inet_addr_t *addr; struct timeval tv; static struct rspamadm_control_cbdata cbdata; lua_State *L; gint sock; context = g_option_context_new ( "control - manage rspamd main control interface"); g_option_context_set_summary (context, "Summary:\n Rspamd administration utility version " RVERSION "\n Release id: " RID); g_option_context_add_main_entries (context, entries, NULL); g_option_context_set_ignore_unknown_options (context, TRUE); if (!g_option_context_parse (context, &argc, &argv, &error)) { rspamd_fprintf (stderr, "option parsing failed: %s\n", error->message); g_error_free (error); exit (1); } if (argc <= 1) { rspamd_fprintf (stderr, "command required\n"); exit (1); } cmd = argv[1]; if (g_ascii_strcasecmp (cmd, "stat") == 0) { path = "/stat"; } else if (g_ascii_strcasecmp (cmd, "reload") == 0) { path = "/reload"; } else if (g_ascii_strcasecmp (cmd, "reresolve") == 0) { path = "/reresolve"; } else if (g_ascii_strcasecmp (cmd, "recompile") == 0) { path = "/recompile"; } else if (g_ascii_strcasecmp (cmd, "fuzzystat") == 0 || g_ascii_strcasecmp (cmd, "fuzzy_stat") == 0) { path = "/fuzzystat"; } else if (g_ascii_strcasecmp (cmd, "fuzzysync") == 0 || g_ascii_strcasecmp (cmd, "fuzzy_sync") == 0) { path = "/fuzzysync"; } else { rspamd_fprintf (stderr, "unknown command: %s\n", cmd); exit (1); } if (!rspamd_parse_inet_address (&addr, control_path, 0)) { rspamd_fprintf (stderr, "bad control path: %s\n", control_path); exit (1); } ev_base = event_init (); sock = rspamd_inet_address_connect (addr, SOCK_STREAM, TRUE); if (sock == -1) { rspamd_fprintf (stderr, "cannot connect to: %s\n", control_path); rspamd_inet_address_destroy (addr); exit (1); } L = rspamd_lua_init (); conn = rspamd_http_connection_new (NULL, rspamd_control_error_handler, rspamd_control_finish_handler, RSPAMD_HTTP_CLIENT_SIMPLE, RSPAMD_HTTP_CLIENT, NULL, NULL); msg = rspamd_http_new_message (HTTP_REQUEST); msg->url = rspamd_fstring_new_init (path, strlen (path)); double_to_tv (timeout, &tv); cbdata.L = L; cbdata.argc = argc; cbdata.argv = argv; cbdata.path = path; rspamd_http_connection_write_message (conn, msg, NULL, NULL, &cbdata, sock, &tv, ev_base); event_base_loop (ev_base, 0); rspamd_http_connection_unref (conn); rspamd_inet_address_destroy (addr); lua_close (L); close (sock); }
static void rspamadm_rescore (gint argc, gchar **argv) { GOptionContext *context; GError *error = NULL; lua_State *L; ucl_object_t *obj; context = g_option_context_new ( "rescore - Estimate optimal symbol weights from log files"); g_option_context_set_summary (context, "Summary:\n Rspamd administration utility version " RVERSION "\n Release id: " RID); g_option_context_add_main_entries (context, entries, NULL); g_option_context_set_ignore_unknown_options (context, TRUE); if (!g_option_context_parse (context, &argc, &argv, &error)) { rspamd_fprintf (stderr, "option parsing failed: %s\n", error->message); g_error_free (error); exit (EXIT_FAILURE); } if (!HAS_TORCH) { rspamd_fprintf (stderr, "Torch is not enabled. " "Use -DENABLE_TORCH=ON option while running cmake.\n"); exit (EXIT_FAILURE); } if (logdir == NULL) { rspamd_fprintf (stderr, "Please specify log directory.\n"); exit (EXIT_FAILURE); } L = rspamd_lua_init (); rspamd_lua_set_path (L, NULL, NULL); obj = ucl_object_typed_new (UCL_OBJECT); ucl_object_insert_key (obj, ucl_object_fromstring (logdir), "logdir", 0, false); ucl_object_insert_key (obj, ucl_object_fromstring (output), "output", 0, false); ucl_object_insert_key (obj, ucl_object_fromdouble (threshold), "threshold", 0, false); ucl_object_insert_key (obj, ucl_object_fromint (iters), "iters", 0, false); ucl_object_insert_key (obj, ucl_object_frombool (score_diff), "diff", 0, false); rspamadm_execute_lua_ucl_subr (L, argc, argv, obj, "rescore"); lua_close (L); ucl_object_unref (obj); }
int main (int argc, gchar **argv) { GOptionContext *context; GError *error = NULL; struct event_base *ev_base; GString *b32_key; pid_t *sfd; rspamd_inet_addr_t *addr; struct event term_ev, int_ev; struct in_addr ina = {INADDR_ANY}; rspamd_init_libs (); context = g_option_context_new ( "rspamd-http-server - test server for benchmarks"); g_option_context_set_summary (context, "Summary:\n Rspamd test HTTP server " RVERSION "\n Release id: " RID); g_option_context_add_main_entries (context, entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { rspamd_fprintf (stderr, "option parsing failed: %s\n", error->message); g_error_free (error); exit (1); } maps = g_hash_table_new (g_int_hash, g_int_equal); if (key == NULL) { server_key = rspamd_keypair_new (RSPAMD_KEYPAIR_KEX, openssl_mode ? RSPAMD_CRYPTOBOX_MODE_NIST : RSPAMD_CRYPTOBOX_MODE_25519); b32_key = rspamd_keypair_print (server_key, RSPAMD_KEYPAIR_PUBKEY | RSPAMD_KEYPAIR_BASE32); rspamd_printf ("key: %v\n", b32_key); } else { /* TODO: add key loading */ } if (cache_size > 0) { c = rspamd_keypair_cache_new (cache_size); } sfd = g_alloca (sizeof (*sfd) * nworkers); addr = rspamd_inet_address_new (AF_INET, &ina); rspamd_inet_address_set_port (addr, port); rspamd_http_start_servers (sfd, addr); /* Just wait for workers */ ev_base = event_init (); event_set (&term_ev, SIGTERM, EV_SIGNAL, rspamd_http_server_term, sfd); event_base_set (ev_base, &term_ev); event_add (&term_ev, NULL); event_set (&int_ev, SIGINT, EV_SIGNAL, rspamd_http_server_term, sfd); event_base_set (ev_base, &int_ev); event_add (&int_ev, NULL); event_base_loop (ev_base, 0); return 0; }
static void rspamadm_statconvert (gint argc, gchar **argv) { GOptionContext *context; GError *error = NULL; lua_State *L; ucl_object_t *obj; context = g_option_context_new ( "statconvert - converts statistics from sqlite3 to redis"); g_option_context_set_summary (context, "Summary:\n Rspamd administration utility version " RVERSION "\n Release id: " RID); g_option_context_add_main_entries (context, entries, NULL); g_option_context_set_ignore_unknown_options (context, TRUE); if (!g_option_context_parse (context, &argc, &argv, &error)) { rspamd_fprintf (stderr, "option parsing failed: %s\n", error->message); g_error_free (error); exit (1); } if (!source_db) { rspamd_fprintf (stderr, "source db is missing\n"); exit (1); } if (!redis_host) { rspamd_fprintf (stderr, "redis host is missing\n"); exit (1); } if (!symbol) { rspamd_fprintf (stderr, "symbol is missing\n"); exit (1); } L = rspamd_lua_init (); obj = ucl_object_typed_new (UCL_OBJECT); ucl_object_insert_key (obj, ucl_object_fromstring (source_db), "source_db", 0, false); ucl_object_insert_key (obj, ucl_object_fromstring (redis_host), "redis_host", 0, false); ucl_object_insert_key (obj, ucl_object_fromstring (symbol), "symbol", 0, false); if (cache_db != NULL) { ucl_object_insert_key (obj, ucl_object_fromstring (cache_db), "cache_db", 0, false); } rspamadm_execute_lua_ucl_subr (L, argc, argv, obj, rspamadm_script_stat_convert); lua_close (L); ucl_object_unref (obj); }
static void rspamd_process_file (const gchar *fname) { struct rspamd_task *task; GIOChannel *f; GError *err = NULL; GString *buf; struct received_header rh; gdouble t1, t2; f = g_io_channel_new_file (fname, "r", &err); if (!f) { rspamd_fprintf (stderr, "cannot open %s: %e\n", fname, err); g_error_free (err); return; } g_io_channel_set_encoding (f, NULL, NULL); buf = g_string_sized_new (8192); task = g_malloc0 (sizeof (*task)); task->task_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (), "test"); while (g_io_channel_read_line_string (f, buf, NULL, &err) == G_IO_STATUS_NORMAL) { while (buf->len > 0 && g_ascii_isspace (buf->str[buf->len - 1])) { buf->len --; } t1 = rspamd_get_virtual_ticks (); rspamd_smtp_recieved_parse (task, buf->str, buf->len, &rh); t2 = rspamd_get_virtual_ticks (); total_time += t2 - t1; total_parsed ++; if (rh.addr) { total_real_ip ++; } if (rh.real_hostname) { total_real_host ++; } if (rh.type != RSPAMD_RECEIVED_UNKNOWN) { total_known_proto ++; } if (rh.by_hostname || rh.timestamp > 0) { total_valid ++; } if (rh.timestamp != 0) { total_known_ts ++; } } if (err) { rspamd_fprintf (stderr, "cannot read %s: %e\n", fname, err); g_error_free (err); } g_io_channel_unref (f); g_string_free (buf, TRUE); rspamd_mempool_delete (task->task_pool); g_free (task); }
static void rspamd_process_file (struct rspamd_config *cfg, const gchar *fname, gint mode) { struct rspamd_task *task; gint fd; gpointer map; struct stat st; GError *err = NULL; #if 0 GMimeMessage *message; GMimeParser *parser; GMimeStream *stream; GByteArray tmp; #endif struct rspamd_mime_part *part; guint i; gdouble ts1, ts2; fd = open (fname, O_RDONLY); if (fd == -1) { rspamd_fprintf (stderr, "cannot open %s: %s\n", fname, strerror (errno)); exit (EXIT_FAILURE); } if (fstat (fd, &st) == -1) { rspamd_fprintf (stderr, "cannot stat %s: %s\n", fname, strerror (errno)); exit (EXIT_FAILURE); } map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); close (fd); if (map == MAP_FAILED) { rspamd_fprintf (stderr, "cannot mmap %s: %s\n", fname, strerror (errno)); exit (EXIT_FAILURE); } task = rspamd_task_new (NULL, cfg); task->msg.begin = map; task->msg.len = st.st_size; ts1 = rspamd_get_ticks (); if (mode == MODE_NORMAL) { if (!rspamd_mime_parse_task (task, &err)) { rspamd_fprintf (stderr, "cannot parse %s: %e\n", fname, err); g_error_free (err); } } #if 0 else if (mode == MODE_GMIME) { tmp.data = map; tmp.len = st.st_size; stream = g_mime_stream_mem_new_with_byte_array (&tmp); g_mime_stream_mem_set_owner (GMIME_STREAM_MEM (stream), FALSE); parser = g_mime_parser_new_with_stream (stream); message = g_mime_parser_construct_message (parser); } #endif ts2 = rspamd_get_ticks (); total_time += ts2 - ts1; if (mode == MODE_NORMAL) { for (i = 0; i < task->parts->len; i ++) { part = g_ptr_array_index (task->parts, i); if (part->ct->flags & RSPAMD_CONTENT_TYPE_MULTIPART) { rspamd_show_multipart (part); } else if (part->ct->flags & RSPAMD_CONTENT_TYPE_MESSAGE) { rspamd_show_message (part); } else { rspamd_show_normal (part); } } } #if 0 else if (mode == MODE_GMIME) { g_mime_message_foreach (message, mime_foreach_callback, NULL); } #endif rspamd_task_free (task); munmap (map, st.st_size); #if 0 if (mode == MODE_GMIME) { g_object_unref (message); } #endif }
static void rspamadm_signtool (gint argc, gchar **argv) { GOptionContext *context; GError *error = NULL; struct ucl_parser *parser; ucl_object_t *top; struct rspamd_cryptobox_pubkey *pk; struct rspamd_cryptobox_keypair *kp; gsize fsize, flen; gint i; context = g_option_context_new ( "keypair - create encryption keys"); g_option_context_set_summary (context, "Summary:\n Rspamd administration utility version " RVERSION "\n Release id: " RID); g_option_context_add_main_entries (context, entries, NULL); if (!g_option_context_parse (context, &argc, &argv, &error)) { rspamd_fprintf (stderr, "option parsing failed: %s\n", error->message); g_error_free (error); exit (1); } if (openssl) { mode = RSPAMD_CRYPTOBOX_MODE_NIST; } if (verify && (!pubkey && !pubkey_file)) { rspamd_fprintf (stderr, "no pubkey for verification\n"); exit (1); } else if (!verify && (!keypair_file)) { rspamd_fprintf (stderr, "no keypair for signing\n"); exit (1); } if (verify) { g_assert (pubkey || pubkey_file); if (pubkey_file) { gint fd; gchar *map; struct stat st; fd = open (pubkey_file, O_RDONLY); if (fd == -1) { rspamd_fprintf (stderr, "cannot open %s: %s\n", pubkey_file, strerror (errno)); exit (errno); } g_assert (fstat (fd, &st) != -1); fsize = st.st_size; flen = fsize; map = mmap (NULL, fsize, PROT_READ, MAP_SHARED, fd, 0); close (fd); if (map == MAP_FAILED) { rspamd_fprintf (stderr, "cannot read %s: %s\n", pubkey_file, strerror (errno)); exit (errno); } /* XXX: assume base32 pubkey now */ while (flen > 0 && g_ascii_isspace (map[flen - 1])) { flen --; } pk = rspamd_pubkey_from_base32 (map, flen, RSPAMD_KEYPAIR_SIGN, mode); if (pk == NULL) { rspamd_fprintf (stderr, "bad size %s: %ud, %ud expected\n", flen, rspamd_cryptobox_pk_sig_bytes (mode)); exit (errno); } munmap (map, fsize); } else { pk = rspamd_pubkey_from_base32 (pubkey, strlen (pubkey), RSPAMD_KEYPAIR_SIGN, mode); if (pk == NULL) { rspamd_fprintf (stderr, "bad size %s: %ud, %ud expected\n", strlen (pubkey), rspamd_cryptobox_pk_sig_bytes (mode)); exit (errno); } } for (i = 1; i < argc; i++) { /* XXX: support cmd line signature */ if (!rspamadm_verify_file (argv[i], rspamd_pubkey_get_pk (pk, NULL))) { exit (EXIT_FAILURE); } } g_free (pk); } else { g_assert (keypair_file != NULL); parser = ucl_parser_new (0); if (!ucl_parser_add_file (parser, keypair_file) || (top = ucl_parser_get_object (parser)) == NULL) { rspamd_fprintf (stderr, "cannot load keypair: %s\n", ucl_parser_get_error (parser)); exit (EINVAL); } ucl_parser_free (parser); kp = rspamd_keypair_from_ucl (top); if (kp == NULL || rspamd_keypair_type (kp) != RSPAMD_KEYPAIR_SIGN) { rspamd_fprintf (stderr, "invalid or unsuitable for signing key\n"); exit (EXIT_FAILURE); } for (i = 1; i < argc; i++) { /* XXX: support cmd line signature */ if (!rspamadm_sign_file (argv[i], kp)) { rspamd_keypair_unref (kp); exit (EXIT_FAILURE); } } rspamd_keypair_unref (kp); } }
static bool rspamadm_verify_file (const gchar *fname, const guchar *pk) { gint fd_sig, fd_input; guchar *map, *map_sig; gchar sigpath[PATH_MAX]; struct stat st, st_sig; bool ret; g_assert (rspamd_cryptobox_MAX_SIGBYTES >= rspamd_cryptobox_signature_bytes (mode)); if (suffix == NULL) { suffix = ".sig"; } fd_input = rspamd_file_xopen (fname, O_RDONLY, 0); if (fd_input == -1) { rspamd_fprintf (stderr, "cannot open %s: %s\n", fname, strerror (errno)); exit (errno); } g_assert (fstat (fd_input, &st) != -1); rspamd_snprintf (sigpath, sizeof (sigpath), "%s%s", fname, suffix); fd_sig = rspamd_file_xopen (sigpath, O_RDONLY, 0); if (fd_sig == -1) { close (fd_input); rspamd_fprintf (stderr, "cannot open %s: %s\n", sigpath, strerror (errno)); exit (errno); } map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd_input, 0); close (fd_input); if (map == MAP_FAILED) { close (fd_sig); rspamd_fprintf (stderr, "cannot open %s: %s\n", sigpath, strerror (errno)); exit (errno); } g_assert (fstat (fd_sig, &st_sig) != -1); if (st_sig.st_size != rspamd_cryptobox_signature_bytes (mode)) { close (fd_sig); rspamd_fprintf (stderr, "invalid signature size %s: %ud\n", fname, (guint)st_sig.st_size); munmap (map, st.st_size); exit (errno); } map_sig = mmap (NULL, st_sig.st_size, PROT_READ, MAP_SHARED, fd_sig, 0); close (fd_sig); if (map_sig == MAP_FAILED) { munmap (map, st.st_size); rspamd_fprintf (stderr, "cannot map %s: %s\n", sigpath, strerror (errno)); exit (errno); } ret = rspamd_cryptobox_verify (map_sig, map, st.st_size, pk, mode); munmap (map, st.st_size); munmap (map_sig, st_sig.st_size); if (!ret) { rspamd_fprintf (stderr, "cannot verify %s using %s: invalid signature\n", fname, sigpath); } else if (!quiet) { rspamd_fprintf (stdout, "verified %s using %s\n", fname, sigpath); } return ret; }
static bool rspamadm_sign_file (const gchar *fname, struct rspamd_cryptobox_keypair *kp) { gint fd_sig, fd_input; guchar sig[rspamd_cryptobox_MAX_SIGBYTES], *map; gchar sigpath[PATH_MAX]; FILE *pub_fp; struct stat st; const guchar *sk; if (suffix == NULL) { suffix = ".sig"; } if (edit) { /* We need to open editor and then sign the temporary file */ fd_input = rspamadm_edit_file (fname); } else { fd_input = rspamd_file_xopen (fname, O_RDONLY, 0); } if (fd_input == -1) { rspamd_fprintf (stderr, "cannot open %s: %s\n", fname, strerror (errno)); exit (errno); } g_assert (fstat (fd_input, &st) != -1); rspamd_snprintf (sigpath, sizeof (sigpath), "%s%s", fname, suffix); fd_sig = rspamd_file_xopen (sigpath, O_WRONLY | O_CREAT | O_TRUNC, 00644); if (fd_sig == -1) { close (fd_input); rspamd_fprintf (stderr, "cannot open %s: %s\n", sigpath, strerror (errno)); exit (errno); } map = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd_input, 0); close (fd_input); if (map == MAP_FAILED) { close (fd_sig); rspamd_fprintf (stderr, "cannot map %s: %s\n", fname, strerror (errno)); exit (errno); } g_assert (rspamd_cryptobox_MAX_SIGBYTES >= rspamd_cryptobox_signature_bytes (mode)); sk = rspamd_keypair_component (kp, RSPAMD_KEYPAIR_COMPONENT_SK, NULL); rspamd_cryptobox_sign (sig, NULL, map, st.st_size, sk, mode); if (edit) { /* We also need to rename .new file */ rspamd_snprintf (sigpath, sizeof (sigpath), "%s.new", fname); if (rename (sigpath, fname) == -1) { rspamd_fprintf (stderr, "cannot rename %s to %s: %s\n", sigpath, fname, strerror (errno)); exit (errno); } unlink (sigpath); } rspamd_snprintf (sigpath, sizeof (sigpath), "%s%s", fname, suffix); g_assert (write (fd_sig, sig, rspamd_cryptobox_signature_bytes (mode)) != -1); close (fd_sig); munmap (map, st.st_size); if (!quiet) { rspamd_fprintf (stdout, "signed %s; stored hash in %s\n", fname, sigpath); } if (pubout) { GString *b32_pk; pub_fp = fopen (pubout, "w"); if (pub_fp == NULL) { rspamd_fprintf (stderr, "cannot write pubkey to %s: %s", pubout, strerror (errno)); } else { b32_pk = rspamd_keypair_print (kp, RSPAMD_KEYPAIR_PUBKEY|RSPAMD_KEYPAIR_BASE32); if (b32_pk) { rspamd_fprintf (pub_fp, "%v", b32_pk); } fclose (pub_fp); } if (!quiet) { rspamd_fprintf (stdout, "stored pubkey in %s\n", pubout); } } return true; }
static gint rspamadm_edit_file (const gchar *fname) { gchar tmppath[PATH_MAX], run_cmdline[PATH_MAX]; guchar *map; gsize len = 0; gint fd_out, retcode, child_argc; GPid child_pid; gchar *tmpdir, **child_argv = NULL; struct stat st; GError *err = NULL; if (editor == NULL) { editor = getenv ("EDITOR"); } if (editor == NULL) { rspamd_fprintf (stderr, "cannot find editor: specify $EDITOR " "environment variable or pass --editor argument\n"); exit (EXIT_FAILURE); } tmpdir = getenv ("TMPDIR"); if (tmpdir == NULL) { tmpdir = "/tmp"; } if (stat (fname, &st) == -1 || st.st_size == 0) { /* The source does not exist, but that shouldn't be a problem */ len = 0; map = NULL; /* Try to touch source anyway */ fd_out = rspamd_file_xopen (fname, O_WRONLY|O_CREAT|O_EXCL, 00644); if (fd_out == -1) { rspamd_fprintf (stderr, "cannot open %s: %s\n", fname, strerror (errno)); exit (errno); } close (fd_out); } else { map = rspamd_file_xmap (fname, PROT_READ, &len); if (map == NULL) { rspamd_fprintf (stderr, "cannot open %s: %s\n", fname, strerror (errno)); exit (errno); } } rspamd_snprintf (tmppath, sizeof (tmppath), "%s/rspamd_sign-XXXXXXXXXX", tmpdir); mode_t cur_umask = umask (S_IRWXO|S_IRWXG); fd_out = mkstemp (tmppath); (void)umask (cur_umask); if (fd_out == -1) { rspamd_fprintf (stderr, "cannot open tempfile %s: %s\n", tmppath, strerror (errno)); exit (errno); } if (len > 0 && write (fd_out, map, len) == -1) { rspamd_fprintf (stderr, "cannot write to tempfile %s: %s\n", tmppath, strerror (errno)); unlink (tmppath); munmap (map, len); close (fd_out); exit (errno); } if (len > 0) { munmap (map, len); } fsync (fd_out); close (fd_out); /* Now we spawn editor with the filename as argument */ rspamd_snprintf (run_cmdline, sizeof (run_cmdline), "%s %s", editor, tmppath); if (!g_shell_parse_argv (run_cmdline, &child_argc, &child_argv, &err)) { rspamd_fprintf (stderr, "cannot exec %s: %e\n", editor, err); unlink (tmppath); exit (errno); } if (!g_spawn_async (NULL, child_argv, NULL, G_SPAWN_CHILD_INHERITS_STDIN|G_SPAWN_SEARCH_PATH|G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &child_pid, &err)) { rspamd_fprintf (stderr, "cannot exec %s: %e\n", editor, err); unlink (tmppath); exit (errno); } g_strfreev (child_argv); for (;;) { if (waitpid ((pid_t)child_pid, &retcode, 0) != -1) { break; } if (errno != EINTR) { rspamd_fprintf (stderr, "failed to wait for %s: %s\n", editor, strerror (errno)); unlink (tmppath); exit (errno); } } #if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 34 if (!g_spawn_check_exit_status (retcode, &err)) { unlink (tmppath); rspamd_fprintf (stderr, "%s returned error code: %d - %e\n", editor, retcode, err); exit (retcode); } #else if (retcode != 0) { unlink (tmppath); rspamd_fprintf (stderr, "%s returned error code: %d\n", editor, retcode); exit (retcode); } #endif map = rspamd_file_xmap (tmppath, PROT_READ, &len); if (map == NULL) { rspamd_fprintf (stderr, "cannot map %s: %s\n", tmppath, strerror (errno)); unlink (tmppath); exit (errno); } rspamd_snprintf (run_cmdline, sizeof (run_cmdline), "%s.new", fname); fd_out = rspamd_file_xopen (run_cmdline, O_RDWR|O_CREAT|O_TRUNC, 00600); if (fd_out == -1) { rspamd_fprintf (stderr, "cannot open new file %s: %s\n", run_cmdline, strerror (errno)); unlink (tmppath); munmap (map, len); exit (errno); } if (write (fd_out, map, len) == -1) { rspamd_fprintf (stderr, "cannot write new file %s: %s\n", run_cmdline, strerror (errno)); unlink (tmppath); unlink (run_cmdline); close (fd_out); munmap (map, len); exit (errno); } unlink (tmppath); (void)lseek (fd_out, 0, SEEK_SET); munmap (map, len); return fd_out; }
static void rspamadm_statconvert (gint argc, gchar **argv, const struct rspamadm_command *cmd) { GOptionContext *context; GError *error = NULL; ucl_object_t *obj; context = g_option_context_new ( "statconvert - converts statistics from sqlite3 to redis"); g_option_context_set_summary (context, "Summary:\n Rspamd administration utility version " RVERSION "\n Release id: " RID); g_option_context_add_main_entries (context, entries, NULL); g_option_context_set_ignore_unknown_options (context, TRUE); if (!g_option_context_parse (context, &argc, &argv, &error)) { rspamd_fprintf (stderr, "option parsing failed: %s\n", error->message); g_error_free (error); exit (1); } if (config_file) { /* Load config file, assuming that it has all information required */ struct ucl_parser *parser; parser = ucl_parser_new (0); rspamd_ucl_add_conf_variables (parser, ucl_vars); if (!ucl_parser_add_file (parser, config_file)) { msg_err ("ucl parser error: %s", ucl_parser_get_error (parser)); ucl_parser_free (parser); exit (EXIT_FAILURE); } obj = ucl_parser_get_object (parser); ucl_parser_free (parser); } else { /* We need to get all information from the command line */ ucl_object_t *classifier, *statfile_ham, *statfile_spam, *tmp, *redis; /* Check arguments sanity */ if (spam_db == NULL) { msg_err ("No spam-db specified"); exit (EXIT_FAILURE); } if (ham_db == NULL) { msg_err ("No ham-db specified"); exit (EXIT_FAILURE); } if (redis_host == NULL) { msg_err ("No redis-host specified"); exit (EXIT_FAILURE); } if (symbol_ham == NULL) { msg_err ("No symbol-ham specified"); exit (EXIT_FAILURE); } if (symbol_spam == NULL) { msg_err ("No symbol-spam specified"); exit (EXIT_FAILURE); } obj = ucl_object_typed_new (UCL_OBJECT); classifier = ucl_object_typed_new (UCL_OBJECT); ucl_object_insert_key (obj, classifier, "classifier", 0, false); /* Now we need to create "bayes" key in it */ tmp = ucl_object_typed_new (UCL_OBJECT); ucl_object_insert_key (classifier, tmp, "bayes", 0, false); classifier = tmp; ucl_object_insert_key (classifier, ucl_object_fromstring ("sqlite3"), "backend", 0, false); if (cache_db != NULL) { ucl_object_t *cache; cache = ucl_object_typed_new (UCL_OBJECT); ucl_object_insert_key (cache, ucl_object_fromstring ("sqlite3"), "type", 0, false); ucl_object_insert_key (cache, ucl_object_fromstring (cache_db), "file", 0, false); ucl_object_insert_key (classifier, cache, "cache", 0, false); } statfile_ham = ucl_object_typed_new (UCL_OBJECT); ucl_object_insert_key (statfile_ham, ucl_object_fromstring (symbol_ham), "symbol", 0, false); ucl_object_insert_key (statfile_ham, ucl_object_frombool (false), "spam", 0, false); ucl_object_insert_key (statfile_ham, ucl_object_fromstring (ham_db), "db", 0, false); statfile_spam = ucl_object_typed_new (UCL_OBJECT); ucl_object_insert_key (statfile_spam, ucl_object_fromstring (symbol_spam), "symbol", 0, false); ucl_object_insert_key (statfile_spam, ucl_object_frombool (true), "spam", 0, false); ucl_object_insert_key (statfile_spam, ucl_object_fromstring (spam_db), "db", 0, false); DL_APPEND (statfile_ham, statfile_spam); ucl_object_insert_key (classifier, statfile_ham, "statfile", 0, false); /* Deal with redis */ redis = ucl_object_typed_new (UCL_OBJECT); ucl_object_insert_key (obj, redis, "redis", 0, false); ucl_object_insert_key (redis, ucl_object_fromstring (redis_host), "servers", 0, false); if (redis_db) { ucl_object_insert_key (redis, ucl_object_fromstring (redis_db), "dbname", 0, false); } if (redis_password) { ucl_object_insert_key (redis, ucl_object_fromstring (redis_password), "password", 0, false); } } ucl_object_insert_key (obj, ucl_object_frombool (reset_previous), "reset_previous", 0, false); if (expire != 0) { ucl_object_insert_key (obj, ucl_object_fromdouble (expire), "expire", 0, false); } rspamadm_execute_lua_ucl_subr (argc, argv, obj, "stat_convert", TRUE); ucl_object_unref (obj); }