Exemple #1
0
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;
}
Exemple #2
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);
}
Exemple #3
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);
}
Exemple #5
0
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);
}
Exemple #6
0
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);
}
Exemple #7
0
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);
}
Exemple #8
0
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);
}
Exemple #9
0
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;
}
Exemple #11
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);
}
Exemple #13
0
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
}
Exemple #14
0
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);
	}
}
Exemple #15
0
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;
}
Exemple #16
0
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;
}
Exemple #17
0
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;
}
Exemple #18
0
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);
}