예제 #1
0
/***
 * @function rspamd_cryptobox_pubkey.load(file[, type[, alg]])
 * Loads public key from base32 encoded file
 * @param {string} file filename to load
 * @param {string} type optional 'sign' or 'kex' for signing and encryption
 * @param {string} alg optional 'default' or 'nist' for curve25519/nistp256 keys
 * @return {cryptobox_pubkey} new public key
 */
static gint
lua_cryptobox_pubkey_load (lua_State *L)
{
	struct rspamd_cryptobox_pubkey *pkey = NULL, **ppkey;
	const gchar *filename, *arg;
	gint type = RSPAMD_KEYPAIR_SIGN;
	gint alg = RSPAMD_CRYPTOBOX_MODE_25519;
	guchar *map;
	gsize len;

	filename = luaL_checkstring (L, 1);
	if (filename != NULL) {
		map = rspamd_file_xmap (filename, PROT_READ, &len);

		if (map == NULL) {
			msg_err ("cannot open pubkey from file: %s, %s",
				filename,
				strerror (errno));
			lua_pushnil (L);
		}
		else {
			if (lua_type (L, 2) == LUA_TSTRING) {
				/* keypair type */
				arg = lua_tostring (L, 2);

				if (strcmp (arg, "sign") == 0) {
					type = RSPAMD_KEYPAIR_SIGN;
				}
				else if (strcmp (arg, "kex") == 0) {
					type = RSPAMD_KEYPAIR_KEX;
				}
			}
			if (lua_type (L, 3) == LUA_TSTRING) {
				/* algorithm */
				arg = lua_tostring (L, 3);

				if (strcmp (arg, "default") == 0 || strcmp (arg, "curve25519") == 0) {
					type = RSPAMD_CRYPTOBOX_MODE_25519;
				}
				else if (strcmp (arg, "nist") == 0) {
					type = RSPAMD_CRYPTOBOX_MODE_NIST;
				}
			}

			pkey = rspamd_pubkey_from_base32 (map, len, type, alg);

			if (pkey == NULL) {
				msg_err ("cannot open pubkey from file: %s", filename);
				munmap (map, len);
				lua_pushnil (L);
			}
			else {
				munmap (map, len);
				ppkey = lua_newuserdata (L, sizeof (void *));
				rspamd_lua_setclass (L, "rspamd{cryptobox_pubkey}", -1);
				*ppkey = pkey;
			}
		}
	}
	else {
		return luaL_error (L, "bad input arguments");
	}

	return 1;
}
예제 #2
0
/***
 * @function rspamd_tcp.request({params})
 * This function creates and sends TCP request to the specified host and port,
 * resolves hostname (if needed) and invokes continuation callback upon data received
 * from the remote peer. This function accepts table of arguments with the following
 * attributes
 *
 * - `task`: rspamd task objects (implies `pool`, `session`, `ev_base` and `resolver` arguments)
 * - `ev_base`: event base (if no task specified)
 * - `resolver`: DNS resolver (no task)
 * - `session`: events session (no task)
 * - `pool`: memory pool (no task)
 * - `host`: IP or name of the peer (required)
 * - `port`: remote port to use (required)
 * - `data`: a table of strings or `rspamd_text` objects that contains data pieces
 * - `callback`: continuation function (required)
 * - `timeout`: floating point value that specifies timeout for IO operations in seconds
 * - `partial`: boolean flag that specifies that callback should be called on any data portion received
 * - `stop_pattern`: stop reading on finding a certain pattern (e.g. \r\n.\r\n for smtp)
 * @return {boolean} true if request has been sent
 */
static gint
lua_tcp_request (lua_State *L)
{
	const gchar *host;
	gchar *stop_pattern = NULL;
	guint port;
	gint cbref, tp;
	struct event_base *ev_base;
	struct lua_tcp_cbdata *cbd;
	struct rspamd_dns_resolver *resolver;
	struct rspamd_async_session *session;
	struct rspamd_task *task = NULL;
	rspamd_mempool_t *pool;
	struct iovec *iov = NULL;
	guint niov = 0, total_out;
	gdouble timeout = default_tcp_timeout;
	gboolean partial = FALSE;

	if (lua_type (L, 1) == LUA_TTABLE) {
		lua_pushstring (L, "host");
		lua_gettable (L, -2);
		host = luaL_checkstring (L, -1);
		lua_pop (L, 1);

		lua_pushstring (L, "port");
		lua_gettable (L, -2);
		port = luaL_checknumber (L, -1);
		lua_pop (L, 1);

		lua_pushstring (L, "callback");
		lua_gettable (L, -2);
		if (host == NULL || lua_type (L, -1) != LUA_TFUNCTION) {
			lua_pop (L, 1);
			msg_err ("tcp request has bad params");
			lua_pushboolean (L, FALSE);
			return 1;
		}
		cbref = luaL_ref (L, LUA_REGISTRYINDEX);

		lua_pushstring (L, "task");
		lua_gettable (L, -2);
		if (lua_type (L, -1) == LUA_TUSERDATA) {
			task = lua_check_task (L, -1);
			ev_base = task->ev_base;
			resolver = task->resolver;
			session = task->s;
			pool = task->task_pool;
		}
		lua_pop (L, 1);

		if (task == NULL) {
			lua_pushstring (L, "ev_base");
			lua_gettable (L, -2);
			if (luaL_checkudata (L, -1, "rspamd{ev_base}")) {
				ev_base = *(struct event_base **)lua_touserdata (L, -1);
			}
			else {
				ev_base = NULL;
			}
			lua_pop (L, 1);

			lua_pushstring (L, "pool");
			lua_gettable (L, -2);
			if (luaL_checkudata (L, -1, "rspamd{mempool}")) {
				pool = *(rspamd_mempool_t **)lua_touserdata (L, -1);
			}
			else {
				pool = NULL;
			}
			lua_pop (L, 1);

			lua_pushstring (L, "resolver");
			lua_gettable (L, -2);
			if (luaL_checkudata (L, -1, "rspamd{resolver}")) {
				resolver = *(struct rspamd_dns_resolver **)lua_touserdata (L, -1);
			}
			else {
				resolver = lua_tcp_global_resolver (ev_base);
			}
			lua_pop (L, 1);

			lua_pushstring (L, "session");
			lua_gettable (L, -2);
			if (luaL_checkudata (L, -1, "rspamd{session}")) {
				session = *(struct rspamd_async_session **)lua_touserdata (L, -1);
			}
			else {
				session = NULL;
			}
			lua_pop (L, 1);
		}

		lua_pushstring (L, "timeout");
		lua_gettable (L, -2);
		if (lua_type (L, -1) == LUA_TNUMBER) {
			timeout = lua_tonumber (L, -1) * 1000.;
		}
		lua_pop (L, 1);

		lua_pushstring (L, "stop_pattern");
		lua_gettable (L, -2);
		if (lua_type (L, -1) == LUA_TSTRING) {
			stop_pattern = rspamd_mempool_strdup (pool, lua_tostring (L, -1));
		}
		lua_pop (L, 1);

		lua_pushstring (L, "partial");
		lua_gettable (L, -2);
		if (lua_type (L, -1) == LUA_TBOOLEAN) {
			partial = lua_toboolean (L, -1);
		}
		lua_pop (L, 1);

		if (pool == NULL) {
			lua_pop (L, 1);
			msg_err ("tcp request has no memory pool associated");
			lua_pushboolean (L, FALSE);
			return 1;
		}

		lua_pushstring (L, "data");
		lua_gettable (L, -2);
		total_out = 0;

		tp = lua_type (L, -1);
		if (tp == LUA_TSTRING || tp == LUA_TUSERDATA) {
			iov = rspamd_mempool_alloc (pool, sizeof (*iov));
			niov = 1;

			if (!lua_tcp_arg_toiovec (L, -1, pool, iov)) {
				lua_pop (L, 1);
				msg_err ("tcp request has bad data argument");
				lua_pushboolean (L, FALSE);
				return 1;
			}

			total_out = iov[0].iov_len;
		}
		else if (tp == LUA_TTABLE) {
			/* Count parts */
			lua_pushnil (L);
			while (lua_next (L, -2) != 0) {
				niov ++;
				lua_pop (L, 1);
			}

			iov = rspamd_mempool_alloc (pool, sizeof (*iov) * niov);
			lua_pushnil (L);
			niov = 0;

			while (lua_next (L, -2) != 0) {
				if (!lua_tcp_arg_toiovec (L, -1, pool, &iov[niov])) {
					lua_pop (L, 2);
					msg_err ("tcp request has bad data argument at pos %d", niov);
					lua_pushboolean (L, FALSE);
					return 1;
				}

				total_out += iov[niov].iov_len;
				niov ++;

				lua_pop (L, 1);
			}
		}

		lua_pop (L, 1);
	}
	else {
		msg_err ("tcp request has bad params");
		lua_pushboolean (L, FALSE);

		return 1;
	}

	cbd = g_slice_alloc0 (sizeof (*cbd));
	cbd->L = L;
	cbd->cbref = cbref;
	cbd->ev_base = ev_base;
	msec_to_tv (timeout, &cbd->tv);
	cbd->fd = -1;
	cbd->pool = pool;
	cbd->partial = partial;
	cbd->iov = iov;
	cbd->iovlen = niov;
	cbd->total = total_out;
	cbd->pos = 0;
	cbd->port = port;
	cbd->stop_pattern = stop_pattern;

	if (session) {
		cbd->session = session;
		rspamd_session_add_event (session,
				(event_finalizer_t)lua_tcp_fin,
				cbd,
				g_quark_from_static_string ("lua tcp"));
	}

	if (rspamd_parse_inet_address (&cbd->addr, host, 0)) {
		rspamd_inet_address_set_port (cbd->addr, port);
		/* Host is numeric IP, no need to resolve */
		if (!lua_tcp_make_connection (cbd)) {
			lua_tcp_maybe_free (cbd);
			lua_pushboolean (L, FALSE);

			return 1;
		}
	}
	else {
		if (task == NULL) {
			if (!make_dns_request (resolver, session, NULL, lua_tcp_dns_handler, cbd,
					RDNS_REQUEST_A, host)) {
				lua_tcp_push_error (cbd, "cannot resolve host");
				lua_tcp_maybe_free (cbd);
			}
		}
		else {
			if (!make_dns_request_task (task, lua_tcp_dns_handler, cbd,
					RDNS_REQUEST_A, host)) {
				lua_tcp_push_error (cbd, "cannot resolve host");
				lua_tcp_maybe_free (cbd);
			}
		}
	}

	lua_pushboolean (L, TRUE);
	return 1;
}
예제 #3
0
static gboolean
rspamd_redis_try_ucl (struct redis_stat_ctx *backend,
		const ucl_object_t *obj,
		struct rspamd_config *cfg,
		const gchar *symbol)
{
	const ucl_object_t *elt, *relt, *users_enabled;
	const gchar *lua_script;

	elt = ucl_object_lookup_any (obj, "read_servers", "servers", NULL);

	if (elt == NULL) {
		return FALSE;
	}

	backend->read_servers = rspamd_upstreams_create (cfg->ups_ctx);
	if (!rspamd_upstreams_from_ucl (backend->read_servers, elt,
			REDIS_DEFAULT_PORT, NULL)) {
		msg_err ("statfile %s cannot get read servers configuration",
				symbol);
		return FALSE;
	}

	relt = elt;

	elt = ucl_object_lookup (obj, "write_servers");
	if (elt == NULL) {
		/* Use read servers as write ones */
		g_assert (relt != NULL);
		backend->write_servers = rspamd_upstreams_create (cfg->ups_ctx);
		if (!rspamd_upstreams_from_ucl (backend->write_servers, relt,
				REDIS_DEFAULT_PORT, NULL)) {
			msg_err ("statfile %s cannot get write servers configuration",
					symbol);
			return FALSE;
		}
	}
	else {
		backend->write_servers = rspamd_upstreams_create (cfg->ups_ctx);
		if (!rspamd_upstreams_from_ucl (backend->write_servers, elt,
				REDIS_DEFAULT_PORT, NULL)) {
			msg_err ("statfile %s cannot get write servers configuration",
					symbol);
			rspamd_upstreams_destroy (backend->write_servers);
			backend->write_servers = NULL;
		}
	}

	elt = ucl_object_lookup (obj, "prefix");
	if (elt == NULL || ucl_object_type (elt) != UCL_STRING) {
		/* Default non-users statistics */
		backend->redis_object = REDIS_DEFAULT_OBJECT;

		/*
		 * Make redis backend compatible with sqlite3 backend in users settings
		 */
		users_enabled = ucl_object_lookup_any (obj, "per_user",
				"users_enabled", NULL);

		if (users_enabled != NULL) {
			if (ucl_object_type (users_enabled) == UCL_BOOLEAN) {
				backend->enable_users = ucl_object_toboolean (users_enabled);
				backend->cbref_user = -1;

				if (backend->enable_users) {
					backend->redis_object = REDIS_DEFAULT_USERS_OBJECT;
				}
			}
			else if (ucl_object_type (users_enabled) == UCL_STRING) {
				lua_script = ucl_object_tostring (users_enabled);

				if (luaL_dostring (cfg->lua_state, lua_script) != 0) {
					msg_err_config ("cannot execute lua script for users "
							"extraction: %s", lua_tostring (cfg->lua_state, -1));
				}
				else {
					if (lua_type (cfg->lua_state, -1) == LUA_TFUNCTION) {
						backend->enable_users = TRUE;
						backend->cbref_user = luaL_ref (cfg->lua_state,
								LUA_REGISTRYINDEX);
					}
					else {
						msg_err_config ("lua script must return "
								"function(task) and not %s",
								lua_typename (cfg->lua_state, lua_type (
										cfg->lua_state, -1)));
					}
				}
			}
		}
		else {
			backend->enable_users = FALSE;
		}
	}
	else {
		/* XXX: sanity check */
		backend->redis_object = ucl_object_tostring (elt);
	}

	elt = ucl_object_lookup (obj, "timeout");
	if (elt) {
		backend->timeout = ucl_object_todouble (elt);
	}
	else {
		backend->timeout = REDIS_DEFAULT_TIMEOUT;
	}

	elt = ucl_object_lookup (obj, "password");
	if (elt) {
		backend->password = ucl_object_tostring (elt);
	}
	else {
		backend->password = NULL;
	}

	elt = ucl_object_lookup_any (obj, "db", "database", "dbname", NULL);
	if (elt) {
		backend->dbname = ucl_object_tostring (elt);
	}
	else {
		backend->dbname = NULL;
	}

	return TRUE;
}
예제 #4
0
/* Do post load initialization based on lua */
void
rspamd_lua_post_load_config (struct rspamd_config *cfg)
{
	lua_State *L = cfg->lua_state;
	const gchar *name, *val;
	gchar *sym;
	struct rspamd_expression *expr, *old_expr;
	ucl_object_t *obj;
	gsize keylen;
	GError *err = NULL;

	/* First check all module options that may be overriden in 'config' global */
	lua_getglobal (L, "config");

	if (lua_istable (L, -1)) {
		/* Iterate */
		for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
			/* 'key' is at index -2 and 'value' is at index -1 */
			/* Key must be a string and value must be a table */
			name = luaL_checklstring (L, -2, &keylen);
			if (name != NULL && lua_istable (L, -1)) {
				obj = ucl_object_lua_import (L, lua_gettop (L));
				if (obj != NULL) {
					ucl_object_insert_key_merged (cfg->rcl_obj,
						obj,
						name,
						keylen,
						true);
				}
			}
		}
	}

	/* Check metrics settings */
	lua_getglobal (L, "metrics");

	if (lua_istable (L, -1)) {
		/* Iterate */
		for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
			/* 'key' is at index -2 and 'value' is at index -1 */
			/* Key must be a string and value must be a table */
			name = luaL_checkstring (L, -2);
			if (name != NULL && lua_istable (L, -1)) {
				lua_process_metric (L, name, cfg);
			}
		}
	}

	/* Check composites */
	lua_getglobal (L, "composites");

	if (lua_istable (L, -1)) {
		/* Iterate */
		for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
			/* 'key' is at index -2 and 'value' is at index -1 */
			/* Key must be a string and value must be a table */
			name = luaL_checkstring (L, -2);
			if (name != NULL && lua_isstring (L, -1)) {
				val = lua_tostring (L, -1);
				sym = rspamd_mempool_strdup (cfg->cfg_pool, name);
				if (!rspamd_parse_expression (val, 0, &composite_expr_subr, NULL,
							cfg->cfg_pool, &err, &expr)) {
					msg_err ("cannot parse composite expression '%s': %s", val,
							err->message);
					g_error_free (err);
					err = NULL;
					continue;
				}
				/* Now check hash table for this composite */
				if ((old_expr =
					g_hash_table_lookup (cfg->composite_symbols,
					name)) != NULL) {
					msg_info ("replacing composite symbol %s", name);
					g_hash_table_replace (cfg->composite_symbols, sym, expr);
				}
				else {
					g_hash_table_insert (cfg->composite_symbols, sym, expr);
					rspamd_symbols_cache_add_symbol (cfg->cache, sym,
							0, NULL, NULL, SYMBOL_TYPE_COMPOSITE, -1);
				}
			}
		}
	}
}
예제 #5
0
struct rspamd_worker *
rspamd_fork_worker (struct rspamd_main *rspamd_main,
		struct rspamd_worker_conf *cf,
		guint index,
		struct event_base *ev_base)
{
	struct rspamd_worker *wrk;
	gint rc;
	struct rlimit rlim;

	/* Starting worker process */
	wrk = (struct rspamd_worker *) g_malloc0 (sizeof (struct rspamd_worker));

	if (!rspamd_socketpair (wrk->control_pipe)) {
		msg_err ("socketpair failure: %s", strerror (errno));
		exit (-errno);
	}

	if (!rspamd_socketpair (wrk->srv_pipe)) {
		msg_err ("socketpair failure: %s", strerror (errno));
		exit (-errno);
	}

	wrk->srv = rspamd_main;
	wrk->type = cf->type;
	wrk->cf = cf;
	REF_RETAIN (cf);
	wrk->index = index;
	wrk->ctx = cf->ctx;
	wrk->finish_actions = g_ptr_array_new ();

	wrk->pid = fork ();

	switch (wrk->pid) {
	case 0:
		/* Update pid for logging */
		rspamd_log_update_pid (cf->type, rspamd_main->logger);

		/* Init PRNG after fork */
		rc = ottery_init (rspamd_main->cfg->libs_ctx->ottery_cfg);
		if (rc != OTTERY_ERR_NONE) {
			msg_err_main ("cannot initialize PRNG: %d", rc);
			g_assert (0);
		}

		rspamd_random_seed_fast ();
		g_random_set_seed (ottery_rand_uint32 ());
#ifdef HAVE_EVUTIL_RNG_INIT
		evutil_secure_rng_init ();
#endif

		/* Remove the inherited event base */
		event_reinit (rspamd_main->ev_base);
		event_base_free (rspamd_main->ev_base);

		/* Drop privilleges */
		rspamd_worker_drop_priv (rspamd_main);
		/* Set limits */
		rspamd_worker_set_limits (rspamd_main, cf);
		/* Re-set stack limit */
		getrlimit (RLIMIT_STACK, &rlim);
		rlim.rlim_cur = 100 * 1024 * 1024;
		rlim.rlim_max = rlim.rlim_cur;
		setrlimit (RLIMIT_STACK, &rlim);

		setproctitle ("%s process", cf->worker->name);
		rspamd_pidfile_close (rspamd_main->pfh);
		/* Do silent log reopen to avoid collisions */
		rspamd_log_close (rspamd_main->logger);
		rspamd_log_open (rspamd_main->logger);
		wrk->start_time = rspamd_get_calendar_ticks ();

#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
# if (GLIB_MINOR_VERSION > 20)
		/* Ugly hack for old glib */
		if (!g_thread_get_initialized ()) {
			g_thread_init (NULL);
		}
# else
		g_thread_init (NULL);
# endif
#endif
		msg_info_main ("starting %s process %P (%d)", cf->worker->name,
				getpid (), index);
		/* Close parent part of socketpair */
		close (wrk->control_pipe[0]);
		close (wrk->srv_pipe[0]);
		rspamd_socket_nonblocking (wrk->control_pipe[1]);
		rspamd_socket_nonblocking (wrk->srv_pipe[1]);
		/* Execute worker */
		cf->worker->worker_start_func (wrk);
		exit (EXIT_FAILURE);
		break;
	case -1:
		msg_err_main ("cannot fork main process. %s", strerror (errno));
		rspamd_pidfile_remove (rspamd_main->pfh);
		exit (-errno);
		break;
	default:
		/* Close worker part of socketpair */
		close (wrk->control_pipe[1]);
		close (wrk->srv_pipe[1]);
		rspamd_socket_nonblocking (wrk->control_pipe[0]);
		rspamd_socket_nonblocking (wrk->srv_pipe[0]);
		rspamd_srv_start_watching (wrk, ev_base);
		/* Insert worker into worker's table, pid is index */
		g_hash_table_insert (rspamd_main->workers, GSIZE_TO_POINTER (
				wrk->pid), wrk);
		break;
	}

	return wrk;
}
예제 #6
0
/**
 * Apply configuration to the specified configuration
 * @param conf_metrics
 * @param cfg
 */
static void
apply_dynamic_conf (const ucl_object_t *top, struct rspamd_config *cfg)
{
	gint test_act;
	const ucl_object_t *cur_elt, *cur_nm, *it_val;
	ucl_object_iter_t it = NULL;
	struct metric *real_metric;
	struct metric_action *cur_action;
	struct rspamd_symbol_def *s;

	while ((cur_elt = ucl_iterate_object (top, &it, true))) {
		if (ucl_object_type (cur_elt) != UCL_OBJECT) {
			msg_err ("loaded json array element is not an object");
			continue;
		}

		cur_nm = ucl_object_find_key (cur_elt, "metric");
		if (!cur_nm || ucl_object_type (cur_nm) != UCL_STRING) {
			msg_err (
					"loaded json metric object element has no 'metric' attribute");
			continue;
		}
		real_metric = g_hash_table_lookup (cfg->metrics,
							ucl_object_tostring (cur_nm));
		if (real_metric == NULL) {
			msg_warn ("cannot find metric %s", ucl_object_tostring (cur_nm));
			continue;
		}

		cur_nm = ucl_object_find_key (cur_elt, "symbols");
		/* Parse symbols */
		if (cur_nm && ucl_object_type (cur_nm) == UCL_ARRAY) {
			ucl_object_iter_t nit = NULL;

			while ((it_val = ucl_iterate_object (cur_nm, &nit, true))) {
				if (ucl_object_find_key (it_val, "name") &&
						ucl_object_find_key (it_val, "value")) {
					const ucl_object_t *n =
							ucl_object_find_key (it_val, "name");
					const ucl_object_t *v =
							ucl_object_find_key (it_val, "value");

					if((s = g_hash_table_lookup (real_metric->symbols,
							ucl_object_tostring (n))) != NULL) {
						*s->weight_ptr = ucl_object_todouble (v);
					}
				}
				else {
					msg_info (
							"json symbol object has no mandatory 'name' and 'value' attributes");
				}
			}
		}
		else {
			ucl_object_t *arr;

			arr = ucl_object_typed_new (UCL_ARRAY);
			ucl_object_insert_key ((ucl_object_t *)cur_elt, arr, "symbols",
					sizeof ("symbols") - 1, false);
		}
		cur_nm = ucl_object_find_key (cur_elt, "actions");
		/* Parse actions */
		if (cur_nm && ucl_object_type (cur_nm) == UCL_ARRAY) {
			ucl_object_iter_t nit = NULL;

			while ((it_val = ucl_iterate_object (cur_nm, &nit, true))) {
				if (ucl_object_find_key (it_val, "name") &&
						ucl_object_find_key (it_val, "value")) {
					if (!rspamd_action_from_str (ucl_object_tostring (
							ucl_object_find_key (it_val, "name")), &test_act)) {
						msg_err ("unknown action: %s",
								ucl_object_tostring (ucl_object_find_key (it_val,
										"name")));
						continue;
					}
					cur_action = &real_metric->actions[test_act];
					cur_action->action = test_act;
					cur_action->score =
							ucl_object_todouble (ucl_object_find_key (it_val,
									"value"));
				}
				else {
					msg_info (
							"json action object has no mandatory 'name' and 'value' attributes");
				}
			}
		}
		else {
			ucl_object_t *arr;

			arr = ucl_object_typed_new (UCL_ARRAY);
			ucl_object_insert_key ((ucl_object_t *)cur_elt, arr, "actions",
					sizeof ("actions") - 1, false);
		}
	}
}
예제 #7
0
파일: rw.c 프로젝트: JamesLinus/vsta
/*
 * nvram_readwrite()
 *	Read the contents of NVRAM
 */
void
nvram_readwrite(struct msg *m, struct file *f)
{
	int tsfr_count, ret = 0;
	uchar tbyte;

	/*
	 * Check that the transfer is sane
	 */
	if (m->m_arg == 0) {
		msg_err(m->m_sender, EINVAL);
		return;
	}

	/*
	 * Check that the permissions are good
	 */
	if ((m->m_op == FS_WRITE) ?  (!(f->f_flags & ACC_WRITE)) :
			(!(f->f_flags & ACC_READ))) {
		msg_err(m->m_sender, EPERM);
		return;
	}

	/*
	 * How many bytes are we going to transfer?
	 */
	tsfr_count = m->m_arg;

	/*
	 * Read/write the NVRAM via the transfer buffer.  We assume
	 * here that on * exit from whichever the appropriate
	 * routine is we return a status in * "ret".  If ret is
	 * non-zero we have a fail, otherwise we have a pass.
	 */
	if (m->m_op == FS_READ) {
		/*
		* Handle device reads
		*/
		switch(f->f_node) {
		case ROOT_INO :
			nvram_readdir(m, f);
			ret = 0;
			break;

		case ALL_INO :
			CAP_TSFR(tsfr_count, f->f_pos, nvram_bytes);
			ret = do_rw_all(f->f_pos, tsfr_count,
				nvram_buffer, READING);
			break;

		case RTC_INO :
			CAP_TSFR(tsfr_count, f->f_pos, 7);
			ret = do_rw_rtc(f->f_pos, tsfr_count,
				nvram_buffer, READING);
			break;

		case FD0_INO :
			CAP_TSFR(tsfr_count, f->f_pos, 1);
			ret = do_readbyte(0x10, nvram_buffer);
			nvram_buffer[0] >>= 4;
			break;

		case FD1_INO :
			CAP_TSFR(tsfr_count, f->f_pos, 1);
			ret = do_readbyte(0x10, nvram_buffer);
			nvram_buffer[0] &= 0x0f;
			break;

		case WD0_INO :
			CAP_TSFR(tsfr_count, f->f_pos, 1);
			ret = do_readbyte(0x12, nvram_buffer);
			nvram_buffer[0] >>= 4;
			if (nvram_buffer[0] == 0x0f) {
				ret = do_readbyte(0x19, nvram_buffer);
			}
			break;

		case WD1_INO :
			CAP_TSFR(tsfr_count, f->f_pos, 1);
			ret = do_readbyte(0x12, nvram_buffer);
			nvram_buffer[0] &= 0x0f;
			if (nvram_buffer[0] == 0x0f) {
				ret = do_readbyte(0x1a, nvram_buffer);
			}
			break;

		default :
			msg_err(m->m_sender, EINVAL);
			return;
		}
	} else {
		/*
		* Handle device writes
		*/
		switch(f->f_node) {
예제 #8
0
파일: rw.c 프로젝트: JamesLinus/vsta
/*
 * tmpfs_read()
 *	Read bytes out of the current file or directory
 *
 * Directories get their own routine.
 */
void
tmpfs_read(struct msg *m, struct file *f)
{
	uint nseg, cnt, lim, blk;
	struct openfile *o;
	char *blkp, *tmpbuf = NULL;
	seg_t *mp;

	/*
	 * Directory--only one is the root
	 */
	if ((o = f->f_file) == 0) {
		tmpfs_readdir(m, f);
		return;
	}

	/*
	 * Access?
	 */
	if (!(f->f_perm & ACC_READ)) {
		msg_err(m->m_sender, EPERM);
		return;
	}

	/*
	 * EOF?
	 */
	if (f->f_pos >= o->o_len) {
		m->m_arg = m->m_arg1 = m->m_buflen = m->m_nseg = 0;
		msg_reply(m->m_sender, m);
		return;
	}

	/*
	 * Calculate # bytes to get
	 */
	lim = m->m_arg;
	if (lim > (o->o_len - f->f_pos)) {
		lim = o->o_len - f->f_pos;
	}

	/*
	 * Build message segments
	 */
	cnt = 0;
	for (nseg = 0; (cnt < lim) && (nseg < MSGSEGS); ++nseg) {
		uint off, sz;

		/*
		 * Get next block of data.  We simulate sparse
		 * files by using our pre-allocated source of
		 * zeroes.
		 */
		blk = blknum(f->f_pos);
		blkp = hash_lookup(o->o_blocks, blk);
		if (blkp == 0) {
			extern char *zeroes;

			blkp = zeroes;
		}

		/*
		 * Calculate how much of the block to add to
		 * the message.
		 */
		blkoff(f->f_pos, &off, &sz);
		if ((cnt+sz) > lim) {
			sz = lim - cnt;
		}

		/*
		 * Put into next message segment
		 */
		m->m_seg[nseg].s_buf = blkp+off;
		m->m_seg[nseg].s_buflen = sz;

		/*
		 * Advance counter
		 */
		cnt += sz;
		f->f_pos += sz;
	}

	/*
	 * If we couldn't satisfy the read using our scatter/gather
	 * allowance of buffers, use the last slot as a pointer to
	 * a buffer which will hold all the necessary data.
	 */
	if (cnt < lim) {
		uint tmpoff = 0;

		/*
		 * Get a buffer which can hold the last data of
		 * the message segments already assembled, plus
		 * all the data we haven't read in yet.
		 */
		mp = &m->m_seg[MSGSEGS-1];
		tmpoff = mp->s_buflen;
		tmpbuf = malloc(tmpoff + (lim - cnt));
		if (tmpbuf == NULL) {
			goto retshort;
		}

		/*
		 * Copy in the current data
		 */
		bcopy(mp->s_buf, tmpbuf, tmpoff);

		/*
		 * Now bring in the rest of the data from the file
		 */
		while (cnt < lim) {
			uint off, sz;

			/*
			 * Get next block of data.  We simulate sparse
			 * files by using our pre-allocated source of
			 * zeroes.
			 */
			blk = blknum(f->f_pos);
			blkp = hash_lookup(o->o_blocks, blk);
			if (blkp == 0) {
				extern char *zeroes;

				blkp = zeroes;
			}

			/*
			 * Calculate how much of the block to add to
			 * the message.
			 */
			blkoff(f->f_pos, &off, &sz);
			if ((cnt+sz) > lim) {
				sz = lim - cnt;
			}

			/*
			 * Put into next message segment
			 */
			bcopy(blkp+off, tmpbuf+tmpoff, sz);

			/*
			 * Advance counter
			 */
			cnt += sz;
			f->f_pos += sz;
			tmpoff += sz;
		}

		/*
		 * Point the last message segment into this buffer
		 */
		mp->s_buf = tmpbuf;
		mp->s_buflen = tmpoff;
	}

	/*
	 * Send back reply
	 */
retshort:
	m->m_arg = cnt;
	m->m_nseg = nseg;
	m->m_arg1 = 0;
	msg_reply(m->m_sender, m);

	/*
	 * Free our extra buffer if it's been used
	 */
	if (tmpbuf) {
		free(tmpbuf);
	}
}
예제 #9
0
파일: lua_buffer.c 프로젝트: wiedi/rspamd
/*
 * rspamd_dispatcher.create(base,fd, read_cb, write_cb, err_cb[, timeout])
 */
static int
lua_io_dispatcher_create (lua_State *L)
{
	struct rspamd_io_dispatcher_s *io_dispatcher, **pdispatcher;
	gint fd;
	struct lua_dispatcher_cbdata *cbdata;
	struct timeval tv = {0, 0};
	double tv_num, tmp;

	if (lua_gettop (L) >= 5 && lua_isfunction (L, 3) && lua_isfunction (L, 5)) {
		cbdata = g_slice_alloc0 (sizeof (struct lua_dispatcher_cbdata));
		cbdata->base = lua_check_event_base (L);
		if (cbdata->base == NULL) {
			/* Create new event base */
			msg_warn ("create new event base as it is not specified");
			cbdata->base = event_init ();
		}
		cbdata->L = L;
		fd = lua_tointeger (L, 2);
		lua_pushvalue (L, 3);
		cbdata->cbref_read = luaL_ref (L, LUA_REGISTRYINDEX);
		if (lua_isfunction (L, 4)) {
			/* Push write callback as well */
			lua_pushvalue (L, 4);
			cbdata->cbref_write = luaL_ref (L, LUA_REGISTRYINDEX);
		}
		/* Error callback */
		lua_pushvalue (L, 5);
		cbdata->cbref_err = luaL_ref (L, LUA_REGISTRYINDEX);

		if (lua_gettop (L) > 5) {
			tv_num = lua_tonumber (L, 6);
			tv.tv_sec = trunc (tv_num);
			tv.tv_usec = modf (tv_num, &tmp) * 1000.;
			io_dispatcher = rspamd_create_dispatcher (cbdata->base,
					fd,
					BUFFER_LINE,
					lua_io_read_cb,
					lua_io_write_cb,
					lua_io_err_cb,
					&tv,
					cbdata);
		}
		else {
			io_dispatcher = rspamd_create_dispatcher (cbdata->base,
					fd,
					BUFFER_LINE,
					lua_io_read_cb,
					lua_io_write_cb,
					lua_io_err_cb,
					NULL,
					cbdata);
		}

		cbdata->d = io_dispatcher;
		/* Push result */
		pdispatcher =
			lua_newuserdata (L, sizeof (struct rspamd_io_dispatcher_s *));
		rspamd_lua_setclass (L, "rspamd{io_dispatcher}", -1);
		*pdispatcher = io_dispatcher;
	}
	else {
		msg_err ("invalid number of arguments to io_dispatcher.create: %d",
			lua_gettop (L));
		lua_pushnil (L);
	}

	return 1;
}
예제 #10
0
파일: conf.c 프로젝트: kinpro/ussd-1
/*****************************************************************************
 * Reads configuration file.
 *****************************************************************************/
void read_config_file() {
	char line[INPUT_LINE_MAXLEN + 1], *p, *q, *r;
	int f_line_too_long, f_used, line_number, i;
	char var[VAR_MAXLEN + 1], *var_b, *var_e;
	char command[SHELL_COMMAND_MAXLEN + 1];
	uint32_t ip;
	struct in_addr in_addr;
	uint16_t port;
	uint8_t f_unixsock;
	FILE *f;
	char ipv6_any[] = "::";

	/* set default values */
	conf.apache_count = 0;
	conf.nginx_count = 0;
	conf.memcache_count = 0;
	conf.socket_count = 0;
	conf.socket_interval = 0;
	conf.exec_count = 0;

	/* open config file */
	if ((f = fopen(conf.configfile, "r")) == NULL) {
		msg_syswarn("%s: fopen(%s)", __FUNCTION__, conf.configfile);
		return;
	}

	f_line_too_long = 0;
	line_number = 0;
	while (fgets(line, sizeof(line), f)) {
		/* remove end of line for easy parsing */
		parse_chomp(line);

		/* line too long, ignoring */
		if (strlen(line) == (sizeof(line) - 1)) {
			f_line_too_long = 1;
			continue;
		}

		line_number++;

		/* skip the rest of too long line */
		if (f_line_too_long) {
			f_line_too_long = 0;
			msg_err(0, "%s: line %d: line is too long", __FUNCTION__, line_number);
			continue;
		}

		/* remove trailing white spaces for easy parsing */
		parse_rtrim(line);

		/* do parsing */
		/* empty lines and comments */
		if (!*line || parse_get_ch(line, &p, '#')) {
			continue;
		} else if (parse_get_str(line, &p, "apache")) {
			/* format: apache <variable> <ip> <port> */
			if (parse_get_wspace(p, &var_b) &&
			    parse_get_chset(var_b, &var_e, VAR_CHSET, -(int)(sizeof(var) - 1)) &&
			    parse_get_wspace(var_e, &p) &&
			    parse_get_ip4(p, &p, &ip) &&
			    parse_get_wspace(p, &p) &&
			    parse_get_uint16(p, &p, &port) && !*p) {
				strncpy(var, var_b, var_e - var_b);
				var[var_e - var_b] = 0;
				parse_tolower(var);

				/* check if variable is already used */
				f_used = 0;
				for (i = 0; i < conf.apache_count; i++)
					if (strcmp(conf.apache_conf[i].var, var) == 0) {
						f_used = 1;
						break;
					}
				if (f_used) {
					msg_err(0, "%s: line %d: dublicated variable '%s'", __FUNCTION__, line_number, var);
					continue;
				}

				/* check if too many apache directives */
				if (conf.apache_count == APACHE_MAXN) {
					msg_err(0, "%s: line %d: too many 'apache' directives (maximum %d allowed)", __FUNCTION__, line_number, APACHE_MAXN);
					continue;
				}

				/* add line to apache configuration */
				strcpy(conf.apache_conf[conf.apache_count].var, var);
				conf.apache_conf[conf.apache_count].ip = ip;
				in_addr.s_addr = ip;
				strcpy(conf.apache_conf[conf.apache_count].ip_str, inet_ntoa(in_addr));
				conf.apache_conf[conf.apache_count].port = port;
				conf.apache_count++;
			} else
				msg_err(0, "%s: line %d: can't parse 'apache' directive", __FUNCTION__, line_number);
		} else if (parse_get_str(line, &p, "nginx")) {
			/* format: nginx <variable> <ip> <port> */
			if (parse_get_wspace(p, &var_b) &&
			    parse_get_chset(var_b, &var_e, VAR_CHSET, -(int)(sizeof(var) - 1)) &&
			    parse_get_wspace(var_e, &p) &&
			    parse_get_ip4(p, &p, &ip) &&
			    parse_get_wspace(p, &p) &&
			    parse_get_uint16(p, &p, &port) && !*p) {
				strncpy(var, var_b, var_e - var_b);
				var[var_e - var_b] = 0;
				parse_tolower(var);

				/* check if variable is already used */
				f_used = 0;
				for (i = 0; i < conf.nginx_count; i++)
					if (strcmp(conf.nginx_conf[i].var, var) == 0) {
						f_used = 1;
						break;
					}
				if (f_used) {
					msg_err(0, "%s: line %d: dublicated variable '%s'", __FUNCTION__, line_number, var);
					continue;
				}

				/* check if too many nginx directives */
				if (conf.nginx_count == NGINX_MAXN) {
					msg_err(0, "%s: line %d: too many 'nginx' directives (maximum %d allowed)", __FUNCTION__, line_number, NGINX_MAXN);
					continue;
				}

				/* add line to nginx configuration */
				strcpy(conf.nginx_conf[conf.nginx_count].var, var);
				conf.nginx_conf[conf.nginx_count].ip = ip;
				in_addr.s_addr = ip;
				strcpy(conf.nginx_conf[conf.nginx_count].ip_str, inet_ntoa(in_addr));
				conf.nginx_conf[conf.nginx_count].port = port;
				conf.nginx_count++;
			} else
				msg_err(0, "%s: line %d: can't parse 'nginx' directive", __FUNCTION__, line_number);
		} else if (parse_get_str(line, &p, "memcache")) {
			/* format 1: memcache <variable> <ip> <port> */
			/* format 2: memcache <variable> <sockname> */
			if (parse_get_wspace(p, &var_b) &&
			    parse_get_chset(var_b, &var_e, VAR_CHSET, -(int)(sizeof(var) - 1)) &&
			    parse_get_wspace(var_e, &p) &&
			    ((parse_get_ip4(p, &q, &ip) && parse_get_wspace(q, &q) &&
			    parse_get_uint16(q, &q, &port) && (f_unixsock = 0, 1)) ||
			    (parse_get_chset(p, &q, "^ \t", -SOCKNAME_MAXLEN) &&
			    (f_unixsock = 1, 1))) &&
			    !*q) {
				strncpy(var, var_b, var_e - var_b);
				var[var_e - var_b] = 0;
				parse_tolower(var);

				/* check if variable is already used */
				f_used = 0;
				for (i = 0; i < conf.memcache_count; i++)
					if (strcmp(conf.memcache_conf[i].var, var) == 0) {
						f_used = 1;
						break;
					}
				if (f_used) {
					msg_err(0, "%s: line %d: dublicated variable '%s'", __FUNCTION__, line_number, var);
					continue;
				}

				/* check if too many memcache directives */
				if (conf.memcache_count == MEMCACHE_MAXN) {
					msg_err(0, "%s: line %d: too many 'memcache' directives (maximum %d allowed)", __FUNCTION__, line_number, MEMCACHE_MAXN);
					continue;
				}

				/* add line to memcache configuration */
				strcpy(conf.memcache_conf[conf.memcache_count].var, var);
				conf.memcache_conf[conf.memcache_count].f_unixsock = f_unixsock;
				if (f_unixsock) {
					strncpy(conf.memcache_conf[conf.memcache_count].sockname,
					    p, q - p);
					conf.memcache_conf[conf.memcache_count].sockname[q - p] = 0;
				} else {
					conf.memcache_conf[conf.memcache_count].ip = ip;
					conf.memcache_conf[conf.memcache_count].port = port;
				}
				conf.memcache_count++;
			} else
				msg_err(0, "%s: line %d: can't parse 'memcache' directive", __FUNCTION__, line_number);
		} else if (parse_get_str(line, &p, "socket")) {
			/* format 1: socket tcp|udp <variable> <ip> <port> */
			/* format 2: socket (tcp|udp)6 <variable> <ip6> <port> */
			/* format 3: socket unix <variable> <path> */
			if (parse_get_wspace(p, &var_b) &&
			parse_get_chset(var_b, &var_e, VAR_CHSET, -(int)(sizeof(var) - 1)) &&
			parse_get_wspace(var_e, &p) && (
			(((parse_get_str(p, &q, "tcp") && (f_unixsock = 0, 1)) ||
			 (parse_get_str(p, &q, "udp") && (f_unixsock = 1, 1))) &&
			 parse_get_wspace(q, &q) &&
			 (parse_get_ip4(q, &q, &ip) ||
			  (parse_get_ch(q, &q, '*') && (ip = 0, 1))) &&
			 parse_get_wspace(q, &q) &&
			 parse_get_uint16(q, &q, &port)) ||
			(((parse_get_str(p, &q, "tcp6") && (f_unixsock = 2, 1)) ||
			 (parse_get_str(p, &q, "udp6") && (f_unixsock = 3, 1))) &&
			 parse_get_wspace(q, &p) &&
			 (parse_get_chset(p, &r, "0123456789aAbBcCdDeEfF:.", -64) ||
			  (parse_get_ch(p, &r, '*') && (p = ipv6_any, 1))) &&
			 parse_get_wspace(r, &q) && parse_get_uint16(q, &q, &port)) ||
			(parse_get_str(p, &r, "unix") && (f_unixsock = 4, 1) &&
			 parse_get_wspace(r, &r) &&
			 parse_get_chset(r, &q, "^ \t", -SOCKNAME_MAXLEN))) &&
			!*q) {
				strncpy(var, var_b, var_e - var_b);
				var[var_e - var_b] = 0;
				parse_tolower(var);

				/* check if variable is already used */
				f_used = 0;
				for (i = 0; i < conf.socket_count; i++)
					if(strcmp(conf.socket_conf[i].var, var) == 0) {
						f_used = 1;
						break;
					}
				if (f_used) {
					msg_err(0, "%s: line %d: dublicated variable '%s'", __FUNCTION__, line_number, var);
					continue;
				}

				/* check if too many socket directives */
				if (conf.socket_count == SOCKET_MAXN) {
					msg_err(0, "%s: line %d: too many 'socket' directives (maximum %d allowed)", __FUNCTION__, line_number, SOCKET_MAXN);
					continue;
				}

				/* add line to socket configuration */
				strcpy(conf.socket_conf[conf.socket_count].var, var);
				conf.socket_conf[conf.socket_count].type = f_unixsock;
				bzero(&conf.socket_conf[conf.socket_count].sockaddr, sizeof(conf.socket_conf[conf.socket_count].sockaddr));
				if (f_unixsock == 4) {
					conf.socket_conf[conf.socket_count].sockaddr.sun.sun_family = AF_LOCAL;
					strncpy(conf.socket_conf[conf.socket_count].sockaddr.sun.sun_path,
					r, q - r);
					conf.socket_conf[conf.socket_count].sockaddr.sun.sun_path[q - p] = 0;
				} else if (f_unixsock == 0 || f_unixsock == 1) {
					conf.socket_conf[conf.socket_count].sockaddr.sin.sin_family = AF_INET;
					conf.socket_conf[conf.socket_count].sockaddr.sin.sin_port = htons(port);
					conf.socket_conf[conf.socket_count].sockaddr.sin.sin_addr.s_addr = ip;
				} else {
					conf.socket_conf[conf.socket_count].sockaddr.sin6.sin6_family = AF_INET6;
					conf.socket_conf[conf.socket_count].sockaddr.sin6.sin6_port = htons(port);
					*r = 0;
					if (inet_pton(AF_INET6, p, &conf.socket_conf[conf.socket_count].sockaddr.sin6.sin6_addr) != 1) {
						msg_err(0, "%s: line %d: can't parse ipv6 addr %s", __FUNCTION__, line_number, p);
						continue;
					}
				}
				conf.socket_count++;
			} else
				msg_err(0, "%s: line %d: can't parse 'socket' directive, error at (%d) ^%s, q=%s, r=%s", __FUNCTION__, line_number, q-p, p, q, r);
		} else if (parse_get_str(line, &p, "exec")) {
			/* format: exec <command> */
			if (parse_get_wspace(p, &p) &&
			    (strlen(p) < sizeof(command))) {
				strcpy(command, p);

				/* check if too many exec directives */
				if (conf.exec_count == EXEC_MAXN) {
					msg_err(0, "%s: line %d: too many 'exec' directives (maximum %d allowed)", __FUNCTION__, line_number, EXEC_MAXN);
					continue;
				}

				/* add line to exec configuration */
				strcpy(conf.exec_conf[conf.exec_count].command, command);
				conf.exec_count++;
			} else
				msg_err(0, "%s: line %d: can't parse 'exec' directive", __FUNCTION__, line_number);
		} else if (parse_get_str(line, &p, "sock_la_interval")) {
			/* format: sock_la_interval <seconds> */
			if (!parse_get_wspace(p, &p) ||
			    !parse_get_int(p, &p, &conf.socket_interval) ||
			    (*p))
				msg_err(0, "%s: line %d: can't parse 'sock_la_interval' directive", __FUNCTION__, line_number);
		} else if (parse_get_str(line, &p, "no_smart_enable")) {
			if (!*p) {
				conf.f_enable_smart = 0;
			} else
				msg_err(0, "%s: line %d: can't parse 'no_smart_enable' directive", __FUNCTION__, line_number);
		} else if (parse_get_str(line, &p, "no_hdds_la")) {
			if (!*p) {
				conf.f_disable_hdds_la = 1;
			} else
				msg_err(0, "%s: line %d: can't parse 'no_hdds_la' directive", __FUNCTION__, line_number);
		} else if (parse_get_str(line, &p, "no_p2p_interfaces")) {
			if (!*p) {
				conf.f_skip_p2p_interfaces = 1;
			} else
				msg_err(0, "%s: line %d: can't parse 'no_p2p_interfaces' directive", __FUNCTION__, line_number);
		} else {
			msg_err(0, "%s: line %d: can't parse line", __FUNCTION__, line_number);
		}
	}
	if (ferror(f)) {
		msg_syserr(0, "%s: fgets", __FUNCTION__);
		fclose(f);
		return;
	}

	fclose(f);
	if (f_started)
		msg_info("configuration file processed");
}
예제 #11
0
파일: rw.c 프로젝트: JamesLinus/vsta
/*
 * tmpfs_readdir()
 *	Do reads on directory entries
 */
static void
tmpfs_readdir(struct msg *m, struct file *f)
{
	char *buf;
	uint len, pos, bufcnt;
	struct llist *l;
	struct openfile *o;
	extern struct llist files;

	/*
	 * Get a buffer of the requested size, but put a sanity
	 * cap on it.
	 */
	len = m->m_arg;
	if (len > 256) {
		len = 256;
	}
	if ((buf = malloc(len+1)) == 0) {
		msg_err(m->m_sender, strerror());
		return;
	}
	buf[0] = '\0';

	/*
	 * Assemble as many names as will fit, starting at
	 * given byte offset.  We assume the caller's position
	 * always advances in units of a whole directory entry.
	 */
	bufcnt = pos = 0;
	for (l = LL_NEXT(&files); l != &files; l = LL_NEXT(l)) {
		uint slen;

		/*
		 * Point to next file.  Get its length.
		 */
		o = l->l_data;
		slen = strlen(o->o_name)+1;

		/*
		 * If we've reached an offset the caller hasn't seen
		 * yet, assemble the entry into the buffer.
		 */
		if (pos >= f->f_pos) {
			/*
			 * No more room in buffer--return results
			 */
			if (slen >= len) {
				break;
			}

			/*
			 * Put string with newline at end of buffer
			 */
			sprintf(buf + bufcnt, "%s\n", o->o_name);

			/*
			 * Update counters
			 */
			len -= slen;
			bufcnt += slen;
		}

		/*
		 * Update position
		 */
		pos += slen;
	}

	/*
	 * Send back results
	 */
	m->m_buf = buf;
	m->m_arg = m->m_buflen = bufcnt;
	m->m_nseg = ((bufcnt > 0) ? 1 : 0);
	m->m_arg1 = 0;
	msg_reply(m->m_sender, m);
	free(buf);
	f->f_pos = pos;
}
예제 #12
0
파일: symbols_cache.c 프로젝트: Sp1l/rspamd
gboolean
rspamd_symbols_cache_validate (struct symbols_cache *cache,
	struct rspamd_config *cfg,
	gboolean strict)
{
	struct cache_item *item;
	GHashTableIter it;
	GList *cur;
	gpointer k, v;
	struct rspamd_symbol_def *sym_def;
	struct metric *metric;
	gboolean ignore_symbol = FALSE, ret = TRUE;

	if (cache == NULL) {
		msg_err ("empty cache is invalid");
		return FALSE;
	}

	/* Now adjust symbol weights according to default metric */
	if (cfg->default_metric != NULL) {
		g_hash_table_foreach (cfg->default_metric->symbols,
			rspamd_symbols_cache_metric_validate_cb,
			cache);
	}

	g_hash_table_foreach (cache->items_by_symbol,
			rspamd_symbols_cache_validate_cb,
			cache);
	/* Now check each metric item and find corresponding symbol in a cache */
	g_hash_table_iter_init (&it, cfg->metrics_symbols);

	while (g_hash_table_iter_next (&it, &k, &v)) {
		ignore_symbol = FALSE;
		cur = v;

		while (cur) {
			metric = cur->data;
			sym_def = g_hash_table_lookup (metric->symbols, k);

			if (sym_def && (sym_def->flags & RSPAMD_SYMBOL_FLAG_IGNORE)) {
				ignore_symbol = TRUE;
				break;
			}

			cur = g_list_next (cur);
		}

		if (!ignore_symbol) {
			item = g_hash_table_lookup (cache->items_by_symbol, k);

			if (item == NULL) {
				msg_warn_cache (
						"symbol '%s' has its score defined but there is no "
								"corresponding rule registered",
						k);
				if (strict) {
					ret = FALSE;
				}
			}
		}
	}

	return ret;
}
예제 #13
0
파일: logger.c 프로젝트: rayyang2000/rspamd
void
rspamd_log_close_priv (rspamd_logger_t *rspamd_log, uid_t uid, gid_t gid)
{
	gchar tmpbuf[256];
	rspamd_log_flush (rspamd_log);

	switch (rspamd_log->type) {
		case RSPAMD_LOG_CONSOLE:
			/* Do nothing special */
			break;
		case RSPAMD_LOG_SYSLOG:
#ifdef HAVE_SYSLOG_H
			closelog ();
#endif
			break;
		case RSPAMD_LOG_FILE:
			if (rspamd_log->enabled) {
				if (rspamd_log->repeats > REPEATS_MIN) {
					rspamd_snprintf (tmpbuf,
							sizeof (tmpbuf),
							"Last message repeated %ud times",
							rspamd_log->repeats);
					rspamd_log->repeats = 0;
					if (rspamd_log->saved_message) {
						file_log_function (NULL,
								rspamd_log->saved_module,
								rspamd_log->saved_id,
								rspamd_log->saved_function,
								rspamd_log->cfg->log_level,
								rspamd_log->saved_message,
								TRUE,
								rspamd_log);

						g_free (rspamd_log->saved_message);
						g_free (rspamd_log->saved_function);
						g_free (rspamd_log->saved_module);
						g_free (rspamd_log->saved_id);
						rspamd_log->saved_message = NULL;
						rspamd_log->saved_function = NULL;
						rspamd_log->saved_module = NULL;
						rspamd_log->saved_id = NULL;
					}
					/* It is safe to use temporary buffer here as it is not static */
					file_log_function (NULL, NULL, NULL,
							G_STRFUNC,
							rspamd_log->cfg->log_level,
							tmpbuf,
							TRUE,
							rspamd_log);
					return;
				}

				if (fsync (rspamd_log->fd) == -1) {
					msg_err ("error syncing log file: %s", strerror (errno));
				}
				close (rspamd_log->fd);
			}
			break;
	}

	rspamd_log->enabled = FALSE;
}
예제 #14
0
파일: main.c 프로젝트: JamesLinus/vsta
/*
 * nvram_main()
 *	Endless loop to receive and serve requests
 */
static void
nvram_main()
{
	struct msg msg;
	int x;
	struct file *f;

loop:
	/*
	 * Receive a message, log an error and then keep going
	 */
	x = msg_receive(nvram_port, &msg);
	if (x < 0) {
		syslog(LOG_ERR, "msg_receive");
		goto loop;
	}

	/*
	 * All incoming data should fit in one buffer
	 */
	if (msg.m_nseg > 1) {
		msg_err(msg.m_sender, EINVAL);
		goto loop;
	}

	/*
	 * Categorize by basic message operation
	 */
	f = hash_lookup(filehash, msg.m_sender);
	msg.m_op &= MSG_MASK;
	switch (msg.m_op) {

	case M_CONNECT:		/* New client */
		nvram_new_client(&msg);
		break;

	case M_DISCONNECT:		/* Client done */
		nvram_dead_client(&msg, f);
		break;

	case M_DUP:			/* File handle dup during exec() */
		nvram_dup_client(&msg, f);
		break;

	case M_ABORT:			/* Aborted operation */
		/*
		 * We're synchronous, so presumably the operation is
		 * done and this abort is old news
		 */
		msg_reply(msg.m_sender, &msg);
		break;

	case FS_SEEK:			/* Set position */
		if (!f || (msg.m_arg < 0)) {
			msg_err(msg.m_sender, EINVAL);
			break;
		}
		f->f_pos = msg.m_arg;
		msg.m_arg = msg.m_arg1 = msg.m_nseg = 0;
		msg_reply(msg.m_sender, &msg);
		break;

	case FS_ABSREAD:		/* Set position, then read */
	case FS_ABSWRITE:		/* Set position, then write */
		if (!f || (msg.m_arg1 < 0)) {
			msg_err(msg.m_sender, EINVAL);
			break;
		}
		f->f_pos = msg.m_arg1;
		msg.m_op = (msg.m_op == FS_ABSREAD) ? FS_READ : FS_WRITE;

		/*
		 * Now fall into FS_READ/FS_WRITE 
		 */

	case FS_READ:			/* Read file */
	case FS_WRITE:		/* Write file */
		if (nvram_check_gen(&msg, f)) {
			break;
		}
		nvram_readwrite(&msg, f);
		break;

	case FS_STAT:			/* Get stat of file */
		if (nvram_check_gen(&msg, f)) {
			break;
		}
		nvram_stat(&msg, f);
		break;

	case FS_WSTAT:		/* Writes stats */
		if (nvram_check_gen(&msg, f)) {
			break;
		}
		nvram_wstat(&msg, f);
		break;

	case FS_OPEN:			/* Move from dir down into drive */
		if (!valid_fname(msg.m_buf, x)) {
			msg_err(msg.m_sender, EINVAL);
			break;
		}
		nvram_open(&msg, f);
		break;

	default:			/* Unknown */
		msg_err(msg.m_sender, EINVAL);
		break;
	}
	goto loop;
}
예제 #15
0
void
json_config_fin_cb (rspamd_mempool_t * pool, struct map_cb_data *data)
{
	struct config_json_buf *jb;
	ucl_object_t *top;
	struct ucl_parser *parser;

	if (data->prev_data) {
		jb = data->prev_data;
		/* Clean prev data */
		if (jb->buf) {
			g_free (jb->buf);
		}
		g_free (jb);
	}

	/* Now parse json */
	if (data->cur_data) {
		jb = data->cur_data;
	}
	else {
		msg_err ("no data read");
		return;
	}
	if (jb->buf == NULL) {
		msg_err ("no data read");
		return;
	}
	/* NULL terminate current buf */
	*jb->pos = '\0';

	parser = ucl_parser_new (0);
	if (!ucl_parser_add_chunk (parser, jb->buf, jb->pos - jb->buf)) {
		msg_err ("cannot load json data: parse error %s",
				ucl_parser_get_error (parser));
		ucl_parser_free (parser);
		return;
	}

	top = ucl_parser_get_object (parser);
	ucl_parser_free (parser);

	if (ucl_object_type (top) != UCL_ARRAY) {
		ucl_object_unref (top);
		msg_err ("loaded json is not an array");
		return;
	}

	jb->cfg->current_dynamic_conf = NULL;
	ucl_object_unref (jb->obj);
	jb->obj = top;

	/*
	 * Note about thread safety: we are updating values that are gdoubles so it is not atomic in general case
	 * but on the other hand all that data is used only in the main thread, so why it is *likely* safe
	 * to do this task in this way without explicit lock.
	 */
	apply_dynamic_conf (jb->obj, jb->cfg);

	jb->cfg->current_dynamic_conf = jb->obj;
}
예제 #16
0
/* Fd must be opened for writing, after creating file is mmapped */
static gboolean
create_cache_file (struct symbols_cache *cache,
	const gchar *filename,
	gint fd,
	rspamd_mempool_t *pool)
{
	GChecksum *cksum;
	u_char *digest;
	gsize cklen;
	GList *cur;
	struct cache_item *item;

	/* Calculate checksum */
	cksum = get_mem_cksum (cache);
	if (cksum == NULL) {
		msg_err ("cannot calculate checksum for symbols");
		close (fd);
		return FALSE;
	}

	cklen = g_checksum_type_get_length (G_CHECKSUM_SHA1);
	digest = g_malloc (cklen);

	g_checksum_get_digest (cksum, digest, &cklen);
	/* Now write data to file */
	cur = g_list_first (cache->negative_items);
	while (cur) {
		item = cur->data;
		if (write (fd, item->s, sizeof (struct saved_cache_item)) == -1) {
			msg_err ("cannot write to file %d, %s", errno, strerror (errno));
			close (fd);
			g_checksum_free (cksum);
			g_free (digest);
			return FALSE;
		}
		cur = g_list_next (cur);
	}
	cur = g_list_first (cache->static_items);
	while (cur) {
		item = cur->data;
		if (write (fd, item->s, sizeof (struct saved_cache_item)) == -1) {
			msg_err ("cannot write to file %d, %s", errno, strerror (errno));
			close (fd);
			g_checksum_free (cksum);
			g_free (digest);
			return FALSE;
		}
		cur = g_list_next (cur);
	}
	/* Write checksum */
	if (write (fd, digest, cklen) == -1) {
		msg_err ("cannot write to file %d, %s", errno, strerror (errno));
		close (fd);
		g_checksum_free (cksum);
		g_free (digest);
		return FALSE;
	}

	close (fd);
	g_checksum_free (cksum);
	g_free (digest);
	/* Reopen for reading */
	if ((fd = open (filename, O_RDWR)) == -1) {
		msg_info ("cannot open file %s, error %d, %s", errno, strerror (errno));
		return FALSE;
	}

	return mmap_cache_file (cache, fd, pool);
}
예제 #17
0
/**
 * Dump dynamic configuration to the disk
 * @param cfg
 * @return
 */
gboolean
dump_dynamic_config (struct rspamd_config *cfg)
{
	struct stat st;
	gchar *dir, pathbuf[PATH_MAX];
	gint fd;

	if (cfg->dynamic_conf == NULL || cfg->current_dynamic_conf == NULL) {
		/* No dynamic conf has been specified, so do not try to dump it */
		return FALSE;
	}

	dir = g_path_get_dirname (cfg->dynamic_conf);
	if (dir == NULL) {
		msg_err ("invalid path: %s", cfg->dynamic_conf);
		return FALSE;
	}

	if (stat (cfg->dynamic_conf, &st) == -1) {
		msg_debug ("%s is unavailable: %s", cfg->dynamic_conf,
			strerror (errno));
		st.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
	}
	if (access (dir, W_OK | R_OK) == -1) {
		msg_warn ("%s is inaccessible: %s", dir, strerror (errno));
		g_free (dir);
		return FALSE;
	}
	rspamd_snprintf (pathbuf,
		sizeof (pathbuf),
		"%s%crconf-XXXXXX",
		dir,
		G_DIR_SEPARATOR);
	g_free (dir);
#ifdef HAVE_MKSTEMP
	/* Umask is set before */
	fd = mkstemp (pathbuf);
#else
	fd = g_mkstemp_full (pathbuf, O_RDWR, S_IWUSR | S_IRUSR);
#endif
	if (fd == -1) {
		msg_err ("mkstemp error: %s", strerror (errno));

		return FALSE;
	}

	if (!ucl_object_emit_full (cfg->current_dynamic_conf, UCL_EMIT_JSON,
			ucl_object_emit_fd_funcs (fd))) {
		msg_err ("cannot emit ucl object: %s", strerror (errno));
		close (fd);
		return FALSE;
	}

	(void)unlink (cfg->dynamic_conf);

	/* Rename old config */
	if (rename (pathbuf, cfg->dynamic_conf) == -1) {
		msg_err ("rename error: %s", strerror (errno));
		close (fd);
		unlink (pathbuf);
		return FALSE;
	}
	/* Set permissions */

	if (chmod (cfg->dynamic_conf, st.st_mode) == -1) {
		msg_warn ("chmod failed: %s", strerror (errno));
	}

	close (fd);
	return TRUE;
}
예제 #18
0
파일: stat.c 프로젝트: JamesLinus/vsta
/*
 * fd_wstat()
 *	Allow writing of supported stat messages
 */
void
fd_wstat(struct msg *m, struct file *f)
{
	char *field, *val;
	struct floppy *fl;
	
	fl = unit(f->f_unit);

	/*
	 * See if common handling code can do it
	 */
	if (do_wstat(m, &fd_prot, f->f_flags, &field, &val) == 0) {
		return;
	}

	/*
	 * Process each of the fields we handle specially here
	 */
	if (!strcmp(field, "mediachg") && (f->f_slot != ROOTDIR)) {
		/*
		 * Number of times we've detected media changes
		 */
		int chg;
		
		if (val) {
			chg = atoi(val);
		} else {
			chg = 0;
		}
		fl->f_mediachg = chg;
	} else if (!strcmp(field, "retries")) {
		/*
		 * Number of times we attempt to retry an operation
		 */
		int retr, x;

		if (val) {
			retr = atoi(val);
		} else {
			retr = FD_MAXERR;
		}
		if (f->f_slot == ROOTDIR) {
			/*
			 * Set the global retry count
			 */
			fd_retries = retr;
			for (x = 0; x < NFD; x++) {
				if (floppies[x].f_state != F_NXIO) {
					floppies[x].f_retries = retr;
				}
			}
		} else {
			/*
			 * Set the specific drive's retry count
			 */
			fl->f_retries = retr;
		}
	} else if (!strcmp(field, "messages")) {
		/*
		 * When will we issue syslog messages?
		 */
		int x, fdm = -1;

		if (val) {
			for (fdm = FDM_ALL; fdm <= FDM_CRITICAL + 1; fdm++) {
				if (fdm > FDM_CRITICAL) {
					/*
					 * Ehh?
					 */
					msg_err(m->m_sender, EINVAL);
					return;
				}
				if (!strcmp(val, fdm_opts[fdm])) {
					break;
				}
			}
		} else {
			fdm = FDM_FAIL;
		}
		if (f->f_slot == ROOTDIR) {
			/*
			 * Set the global messaging level
			 */
			fd_messages = fdm;
			for (x = 0; x < NFD; x++) {
				if (floppies[x].f_state != F_NXIO) {
					floppies[x].f_messages = fdm;
				}
			}
		} else {
			/*
			 * Set the specific drive's messaging level
			 */
			fl->f_messages = fdm;
		}
	} else if (!strcmp(field, "findparms") 
		   && (f->f_slot == SPECIALNODE)) {
		/*
		 * How are we going to determine the special node's diskette
		 * media parameters?
		 */
		if (!strcmp(val, "auto")) {
			/*
			 * Selected autoprobing of the media details
			 */
			fl->f_density = fl->f_specialdens = DISK_AUTOPROBE;
			fl->f_parms.f_size = FD_PUNDEF;
		} else if (!strcmp(val, "userdef")) {
			/*
			 * Selected user defined parameters
			 */
			fl->f_density = fl->f_specialdens = DISK_USERDEF;
			fl->f_parms = fl->f_userp;
		} else {
			/*
			 * We don't understand that option
			 */
			msg_err(m->m_sender, EINVAL);
			return;
		}
	} else if (!strcmp(field, "parms")
		   && (f->f_slot == SPECIALNODE)) {
		/*
		 * What parameters would the user like?
		 */
		if (!strcmp(val, "undefined")) {
			/*
			 * None at all... effectively disable device
			 */
			fl->f_parms.f_size = FD_PUNDEF;
		} else {
			if (!scan_parms(val, &fl->f_userp)) {
				msg_err(m->m_sender, EINVAL);
				return;
			}
			if (fl->f_density == DISK_USERDEF) {
				fl->f_parms = fl->f_userp;
			}
		}
	} else {
		/*
		 * Not a message we understand
		 */
		msg_err(m->m_sender, EINVAL);
		return;
	}
	
	/*
	 * Return success
	 */
	m->m_buflen = m->m_nseg = m->m_arg = m->m_arg1 = 0;
	msg_reply(m->m_sender, m);
}
예제 #19
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);
}
예제 #20
0
파일: stat.c 프로젝트: JamesLinus/vsta
/*
 * fd_stat()
 *	Do stat
 */
void
fd_stat(struct msg *m, struct file *f)
{
	char buf[MAXSTAT];
	int size, ino;
	char type;
	struct floppy *fl = NULL;


	if (!(f->f_flags & ACC_READ)) {
		msg_err(m->m_sender, EPERM);
		return;
	}
	if (f->f_slot == ROOTDIR) {
		int x;
		
		size = 0;
		ino = 0;
		type = 'd';
		
		/*
		 * Work out the dir size
		 */
		for (x = 0; x < NFD; x++) {
			if (floppies[x].f_state != F_NXIO) {
				int y;
				struct floppy *fl = &floppies[x];
				
				size++;
				for (y = 0; fl->f_posdens[y] != -1; y++) {
					size++;
				}
			}
		}
	} else {
		fl = unit(f->f_unit);
		size = fl->f_parms.f_size;
		ino = MKNODE(f->f_unit, f->f_slot) + UNITSTEP;
		type = 's';
	}
	sprintf(buf,
		"size=%d\ntype=%c\nowner=0\ninode=%d\n" \
		"fdc=%s\nirq=%d\ndma=%d\nbaseio=0x%0x\nretries=%d\n" \
		"messages=%s\n",
		size, type, ino, fdc_names[fdc_type],
		fd_irq, fd_dma, fd_baseio,
		(f->f_slot == ROOTDIR ? fd_retries : fl->f_retries),
		fdm_opts[(f->f_slot == ROOTDIR
			  ? fd_messages : fl->f_messages)]);
	strcat(buf, perm_print(&fd_prot));
	if (f->f_slot != ROOTDIR) {
		/*
		 * If we're a device we report on media changes and
		 * the size of blocks we'll handle
		 */
		sprintf(&buf[strlen(buf)], "blksize=%d\nmediachg=%d\n",
			(size != FD_PUNDEF
			 ? SECSZ(fl->f_parms.f_secsize) : 512),
			fl->f_mediachg);
	}
	if (f->f_slot == SPECIALNODE) {
		/*
		 * If we're the special node we can deal with drive/media
		 * parameters
		 */
		struct fdparms *fp;
		fp = (fl->f_specialdens == DISK_USERDEF)
		     ? &fl->f_userp : &fl->f_parms;

		sprintf(&buf[strlen(buf)], "findparms=%s\n",
			fl->f_specialdens == DISK_USERDEF ? "userdef" : "auto");
		if (fp->f_size == FD_PUNDEF) {
			sprintf(&buf[strlen(buf)], "parms=undefined\n");
		} else {
			sprintf(&buf[strlen(buf)],
				"parms=%d:%d:%d:%d:%d:0x%02x:0x%02x:" \
				"0x%02x:0x%02x:0x%02x:0x%02x\n",
				fp->f_size, fp->f_tracks, fp->f_heads,
				fp->f_sectors, fp->f_stretch, fp->f_gap,
				fp->f_fmtgap, fp->f_rate, fp->f_spec1,
				fp->f_spec2, fp->f_secsize);
		}
	} 
	m->m_buf = buf;
	m->m_buflen = strlen(buf);
	m->m_nseg = 1;
	m->m_arg = m->m_arg1 = 0;
	msg_reply(m->m_sender, m);
}
예제 #21
0
gboolean
write_smtp_reply (struct smtp_session *session)
{
	gchar logbuf[1024], *new_subject;
	const gchar *old_subject;
	struct smtp_metric_callback_data cd;
	GMimeStream *stream;
	gint old_fd, sublen;

	/* Check metrics */
	cd.session = session;
	cd.action = METRIC_ACTION_NOACTION;
	cd.res = NULL;
	cd.log_buf = logbuf;
	cd.log_offset = rspamd_snprintf (logbuf,
			sizeof (logbuf),
			"id: <%s>, qid: <%s>, ",
			session->task->message_id,
			session->task->queue_id);
	cd.log_size = sizeof (logbuf);
	if (session->task->user) {
		cd.log_offset += rspamd_snprintf (logbuf + cd.log_offset,
				sizeof (logbuf) - cd.log_offset,
				"user: %s, ",
				session->task->user);
	}

	g_hash_table_foreach (session->task->results, smtp_metric_callback, &cd);

	msg_info ("%s", logbuf);

	if (cd.action <= METRIC_ACTION_REJECT) {
		if (!rspamd_dispatcher_write (session->dispatcher,
			session->ctx->reject_message, 0, FALSE, TRUE)) {
			return FALSE;
		}
		if (!rspamd_dispatcher_write (session->dispatcher, CRLF, sizeof (CRLF) -
			1, FALSE, TRUE)) {
			return FALSE;
		}
		rspamd_session_destroy (session->s);
		return FALSE;
	}
	else if (cd.action <= METRIC_ACTION_ADD_HEADER || cd.action <=
		METRIC_ACTION_REWRITE_SUBJECT) {
		old_fd = session->temp_fd;
		if (!make_smtp_tempfile (session)) {
			session->error = SMTP_ERROR_FILE;
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				0, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}

		if (cd.action <= METRIC_ACTION_REWRITE_SUBJECT) {
			/* XXX: add this action */
			old_subject = g_mime_message_get_subject (session->task->message);
			if (old_subject != NULL) {
				sublen = strlen (old_subject) + sizeof (SPAM_SUBJECT);
				new_subject = rspamd_mempool_alloc (session->pool, sublen);
				rspamd_snprintf (new_subject,
					sublen,
					"%s%s",
					SPAM_SUBJECT,
					old_subject);
			}
			else {
				new_subject = SPAM_SUBJECT;
			}
			g_mime_message_set_subject (session->task->message, new_subject);
		}
		else if (cd.action <= METRIC_ACTION_ADD_HEADER) {
#ifndef GMIME24
			g_mime_message_add_header (session->task->message, "X-Spam",
				"true");
#else
			g_mime_object_append_header (GMIME_OBJECT (
					session->task->message), "X-Spam", "true");
#endif
		}
		stream = g_mime_stream_fs_new (session->temp_fd);
		g_mime_stream_fs_set_owner (GMIME_STREAM_FS (stream), FALSE);
		close (old_fd);

		if (g_mime_object_write_to_stream (GMIME_OBJECT (session->task->message),
			stream) == -1) {
			msg_err ("cannot write MIME object to stream: %s",
				strerror (errno));
			session->error = SMTP_ERROR_FILE;
			session->state = SMTP_STATE_CRITICAL_ERROR;
			rspamd_dispatcher_restore (session->dispatcher);
			if (!rspamd_dispatcher_write (session->dispatcher, session->error,
				0, FALSE, TRUE)) {
				goto err;
			}
			rspamd_session_destroy (session->s);
			return FALSE;
		}
		g_object_unref (stream);
	}
	/* XXX: Add other actions */
	return smtp_send_upstream_message (session);
err:
	session->error = SMTP_ERROR_FILE;
	session->state = SMTP_STATE_CRITICAL_ERROR;
	if (!rspamd_dispatcher_write (session->dispatcher, session->error, 0, FALSE,
		TRUE)) {
		return FALSE;
	}
	rspamd_session_destroy (session->s);
	return FALSE;
}
예제 #22
0
static gint
fuzzy_parse_rule (struct rspamd_config *cfg, const ucl_object_t *obj, gint cb_id)
{
	const ucl_object_t *value, *cur;
	struct fuzzy_rule *rule;
	ucl_object_iter_t it = NULL;
	const char *k = NULL;

	if (obj->type != UCL_OBJECT) {
		msg_err ("invalid rule definition");
		return -1;
	}

	rule = fuzzy_rule_new (fuzzy_module_ctx->default_symbol,
			fuzzy_module_ctx->fuzzy_pool);

	if ((value = ucl_object_find_key (obj, "mime_types")) != NULL) {
		it = NULL;
		while ((cur = ucl_iterate_object (value, &it, obj->type == UCL_ARRAY))
				!= NULL) {
			rule->mime_types = g_list_concat (rule->mime_types,
					parse_mime_types (ucl_obj_tostring (cur)));
		}
	}

	if (rule->mime_types != NULL) {
		rspamd_mempool_add_destructor (fuzzy_module_ctx->fuzzy_pool,
			(rspamd_mempool_destruct_t)g_list_free, rule->mime_types);
	}

	if ((value = ucl_object_find_key (obj, "max_score")) != NULL) {
		rule->max_score = ucl_obj_todouble (value);
	}
	if ((value = ucl_object_find_key (obj,  "symbol")) != NULL) {
		rule->symbol = ucl_obj_tostring (value);
	}
	if ((value = ucl_object_find_key (obj, "read_only")) != NULL) {
		rule->read_only = ucl_obj_toboolean (value);
	}
	if ((value = ucl_object_find_key (obj, "skip_unknown")) != NULL) {
		rule->skip_unknown = ucl_obj_toboolean (value);
	}

	if ((value = ucl_object_find_key (obj, "servers")) != NULL) {
		rule->servers = rspamd_upstreams_create ();
		rspamd_mempool_add_destructor (fuzzy_module_ctx->fuzzy_pool,
				(rspamd_mempool_destruct_t)rspamd_upstreams_destroy,
				rule->servers);
		rspamd_upstreams_from_ucl (rule->servers, value, DEFAULT_PORT, NULL);
	}
	if ((value = ucl_object_find_key (obj, "fuzzy_map")) != NULL) {
		it = NULL;
		while ((cur = ucl_iterate_object (value, &it, true)) != NULL) {
			parse_flags (rule, cfg, cur, cb_id);
		}
	}

	if ((value = ucl_object_find_key (obj, "fuzzy_key")) != NULL) {
		/* Create key from user's input */
		k = ucl_object_tostring (value);
	}

	/* Setup keys */
	if (k == NULL) {
		/* Use some default key for all ops */
		k = "rspamd";
	}
	rule->hash_key = g_string_sized_new (BLAKE2B_KEYBYTES);
	blake2 (rule->hash_key->str, k, NULL, BLAKE2B_KEYBYTES, strlen (k), 0);
	rule->hash_key->len = BLAKE2B_KEYBYTES;

	if ((value = ucl_object_find_key (obj, "fuzzy_shingles_key")) != NULL) {
		k = ucl_object_tostring (value);
	}
	if (k == NULL) {
		k = "rspamd";
	}
	rule->shingles_key = g_string_sized_new (16);
	blake2 (rule->shingles_key->str, k, NULL, 16, strlen (k), 0);
	rule->shingles_key->len = 16;

	if (rspamd_upstreams_count (rule->servers) == 0) {
		msg_err ("no servers defined for fuzzy rule with symbol: %s",
			rule->symbol);
		return -1;
	}
	else {
		fuzzy_module_ctx->fuzzy_rules = g_list_prepend (
			fuzzy_module_ctx->fuzzy_rules,
			rule);
		if (rule->symbol != fuzzy_module_ctx->default_symbol) {
			rspamd_symbols_cache_add_symbol_virtual (cfg->cache, rule->symbol,
					1.0, cb_id);
		}
	}

	rspamd_mempool_add_destructor (fuzzy_module_ctx->fuzzy_pool, fuzzy_free_rule,
			rule);

	return 0;
}
예제 #23
0
gboolean
rspamd_lua_check_condition (struct rspamd_config *cfg, const gchar *condition)
{
	lua_State *L = cfg->lua_state;
	gchar *hostbuf, *condbuf;
	gsize hostlen;
	gboolean res;
#ifdef HAVE_SYS_UTSNAME_H
	struct utsname uts;
#endif

	/* Set some globals for condition */
	/* XXX: think what other variables can be useful */
	hostlen = sysconf (_SC_HOST_NAME_MAX) + 1;
	hostbuf = alloca (hostlen);
	gethostname (hostbuf, hostlen);
	hostbuf[hostlen - 1] = '\0';

	/* Hostname */
	lua_pushstring (L, hostbuf);
	lua_setglobal (L, "hostname");
	/* Config file name */
	lua_pushstring (L, cfg->cfg_name);
	lua_setglobal (L, "cfg_name");
	/* Check for uname */
#ifdef HAVE_SYS_UTSNAME_H
	uname (&uts);
	lua_pushstring (L, uts.sysname);
	lua_setglobal (L, "osname");
	lua_pushstring (L, uts.release);
	lua_setglobal (L, "osrelease");
#else
	lua_pushstring (L, "unknown");
	lua_setglobal (L, "osname");
	lua_pushstring (L, "");
	lua_setglobal (L, "osrelease");
#endif

#ifdef HAVE_OPENSSL
	lua_pushboolean (L, TRUE);
#else
	lua_pushboolean (L, FALSE);
#endif
	lua_setglobal (L, "rspamd_supports_rsa");

	/* Rspamd paths */
	lua_newtable (L);
	rspamd_lua_table_set (L, "confdir",	  RSPAMD_CONFDIR);
	rspamd_lua_table_set (L, "rundir",	  RSPAMD_RUNDIR);
	rspamd_lua_table_set (L, "dbdir",	  RSPAMD_DBDIR);
	rspamd_lua_table_set (L, "logdir",	  RSPAMD_LOGDIR);
	rspamd_lua_table_set (L, "pluginsdir", RSPAMD_PLUGINSDIR);
	rspamd_lua_table_set (L, "prefix",	  RSPAMD_PREFIX);
	lua_setglobal (L, "rspamd_paths");

	/* Make fake string */
	hostlen = sizeof (FAKE_RES_VAR "=") + strlen (condition);
	condbuf = g_malloc (hostlen);
	rspamd_strlcpy (condbuf, FAKE_RES_VAR "=", sizeof (FAKE_RES_VAR "="));
	g_strlcat (condbuf, condition, hostlen);
	/* Evaluate condition */
	if (luaL_dostring (L, condbuf) != 0) {
		msg_err ("eval of '%s' failed: '%s'", condition, lua_tostring (L, -1));
		g_free (condbuf);
		return FALSE;
	}
	/* Get global variable res to get result */
	lua_getglobal (L, FAKE_RES_VAR);
	if (!lua_isboolean (L, -1)) {
		msg_err ("bad string evaluated: %s, type: %s", condbuf,
			lua_typename (L, lua_type (L, -1)));
		g_free (condbuf);
		return FALSE;
	}

	res = lua_toboolean (L, -1);
	g_free (condbuf);

	return res;
}
예제 #24
0
파일: worker_util.c 프로젝트: mwidz/rspamd
struct rspamd_worker *
rspamd_fork_worker (struct rspamd_main *rspamd_main,
		struct rspamd_worker_conf *cf,
		guint index)
{
	struct rspamd_worker *cur;
	/* Starting worker process */
	cur = (struct rspamd_worker *) g_malloc0 (sizeof (struct rspamd_worker));

	if (!rspamd_socketpair (cur->control_pipe)) {
		msg_err ("socketpair failure: %s", strerror (errno));
		exit (-errno);
	}

	cur->srv = rspamd_main;
	cur->type = cf->type;
	cur->cf = g_malloc (sizeof (struct rspamd_worker_conf));
	memcpy (cur->cf, cf, sizeof (struct rspamd_worker_conf));
	cur->index = index;
	cur->ctx = cf->ctx;

	cur->pid = fork ();

	switch (cur->pid) {
	case 0:
		/* Update pid for logging */
		rspamd_log_update_pid (cf->type, rspamd_main->logger);
		/* Lock statfile pool if possible XXX */
		/* Init PRNG after fork */
		ottery_init (NULL);
		g_random_set_seed (ottery_rand_uint32 ());
		/* Drop privilleges */
		rspamd_worker_drop_priv (rspamd_main);
		/* Set limits */
		rspamd_worker_set_limits (rspamd_main, cf);
		setproctitle ("%s process", cf->worker->name);
		rspamd_pidfile_close (rspamd_main->pfh);
		/* Do silent log reopen to avoid collisions */
		rspamd_log_close (rspamd_main->logger);
		rspamd_log_open (rspamd_main->logger);
		cur->start_time = rspamd_get_calendar_ticks ();

#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
# if (GLIB_MINOR_VERSION > 20)
		/* Ugly hack for old glib */
		if (!g_thread_get_initialized ()) {
			g_thread_init (NULL);
		}
# else
		g_thread_init (NULL);
# endif
#endif
		msg_info_main ("starting %s process %P", cf->worker->name, getpid ());
		/* Close parent part of socketpair */
		close (cur->control_pipe[0]);
		rspamd_socket_nonblocking (cur->control_pipe[1]);
		/* Execute worker */
		cf->worker->worker_start_func (cur);
		break;
	case -1:
		msg_err_main ("cannot fork main process. %s", strerror (errno));
		rspamd_pidfile_remove (rspamd_main->pfh);
		exit (-errno);
		break;
	default:
		/* Close worker part of socketpair */
		close (cur->control_pipe[1]);
		rspamd_socket_nonblocking (cur->control_pipe[0]);
		/* Insert worker into worker's table, pid is index */
		g_hash_table_insert (rspamd_main->workers, GSIZE_TO_POINTER (
				cur->pid), cur);
		break;
	}

	return cur;
}
예제 #25
0
파일: mem_pool.c 프로젝트: moisseev/rspamd
static struct _pool_chain *
rspamd_mempool_chain_new (gsize size, enum rspamd_mempool_chain_type pool_type)
{
	struct _pool_chain *chain;
	gpointer map;

	g_return_val_if_fail (size > 0, NULL);

	if (pool_type == RSPAMD_MEMPOOL_SHARED) {
#if defined(HAVE_MMAP_ANON)
		map = mmap (NULL,
				size + sizeof (struct _pool_chain),
				PROT_READ | PROT_WRITE,
				MAP_ANON | MAP_SHARED,
				-1,
				0);
		if (map == MAP_FAILED) {
			msg_err ("cannot allocate %z bytes of shared memory, aborting", size +
					sizeof (struct _pool_chain));
			abort ();
		}
		chain = map;
		chain->begin = ((guint8 *) chain) + sizeof (struct _pool_chain);
#elif defined(HAVE_MMAP_ZERO)
		gint fd;

		fd = open ("/dev/zero", O_RDWR);
		if (fd == -1) {
			return NULL;
		}
		map = mmap (NULL,
				size + sizeof (struct _pool_chain),
				PROT_READ | PROT_WRITE,
				MAP_SHARED,
				fd,
				0);
		if (map == MAP_FAILED) {
			msg_err ("cannot allocate %z bytes, aborting", size +
					sizeof (struct _pool_chain));
			abort ();
		}
		chain = map;
		chain->begin = ((guint8 *) chain) + sizeof (struct _pool_chain);
#else
#error No mmap methods are defined
#endif
		g_atomic_int_inc (&mem_pool_stat->shared_chunks_allocated);
		g_atomic_int_add (&mem_pool_stat->bytes_allocated, size);
	}
	else {
		map = g_slice_alloc (sizeof (struct _pool_chain) + size);
		chain = map;
		chain->begin = ((guint8 *) chain) + sizeof (struct _pool_chain);
		g_atomic_int_add (&mem_pool_stat->bytes_allocated, size);
		g_atomic_int_inc (&mem_pool_stat->chunks_allocated);
	}

	chain->pos = align_ptr (chain->begin, MEM_ALIGNMENT);
	chain->len = size;
	chain->lock = NULL;

	return chain;
}
예제 #26
0
gint
rspamd_symbols_cache_add_symbol (struct symbols_cache *cache,
	const gchar *name,
	double weight,
	gint priority,
	symbol_func_t func,
	gpointer user_data,
	enum rspamd_symbol_type type,
	gint parent)
{
	struct cache_item *item = NULL;

	g_assert (cache != NULL);

	if (name == NULL && type != SYMBOL_TYPE_CALLBACK) {
		msg_warn ("no name for non-callback symbol!");
	}
	else if (type == SYMBOL_TYPE_VIRTUAL && parent == -1) {
		msg_warn ("no parent symbol is associated with virtual symbol %s",
			name);
	}

	if (name != NULL) {
		if (g_hash_table_lookup (cache->items_by_symbol, name) != NULL) {
			msg_err ("skip duplicate symbol registration for %s", name);
			return -1;
		}
	}

	item = rspamd_mempool_alloc0_shared (cache->static_pool,
			sizeof (struct cache_item));
	/*
	 * We do not share cd to skip locking, instead we'll just calculate it on
	 * save or accumulate
	 */
	item->cd = rspamd_mempool_alloc0 (cache->static_pool,
			sizeof (struct counter_data));

	if (name != NULL) {
		item->symbol = rspamd_mempool_strdup (cache->static_pool, name);
	}

	item->func = func;
	item->user_data = user_data;
	item->priority = priority;
	item->type = type;
	item->weight = weight;

	if (item->weight < 0 && item->priority == 0) {
		/* Make priority for negative weighted symbols */
		item->priority = 1;
	}

	item->id = cache->used_items;
	item->parent = parent;
	cache->used_items ++;
	msg_debug ("used items: %d, added symbol: %s", cache->used_items, name);
	rspamd_set_counter (item, 0);
	g_ptr_array_add (cache->items_by_id, item);
	g_ptr_array_add (cache->items_by_order, item);
	item->deps = g_ptr_array_new ();
	item->rdeps = g_ptr_array_new ();
	rspamd_mempool_add_destructor (cache->static_pool,
			rspamd_ptr_array_free_hard, item->deps);
	rspamd_mempool_add_destructor (cache->static_pool,
			rspamd_ptr_array_free_hard, item->rdeps);

	if (name != NULL) {
		g_hash_table_insert (cache->items_by_symbol, item->symbol, item);
	}

	return item->id;
}
예제 #27
0
/* Called when we have connected to the redis server and got keys to check */
static void
rspamd_redis_stat_keys (redisAsyncContext *c, gpointer r, gpointer priv)
{
	struct rspamd_redis_stat_cbdata *cbdata = priv;
	redisReply *reply = r, *elt;
	gchar **pk, *k;
	guint i, processed = 0;


	if (cbdata->wanna_die) {
		return;
	}

	cbdata->inflight --;

	if (c->err == 0 && r != NULL) {
		if (reply->type == REDIS_REPLY_ARRAY) {
			g_ptr_array_set_size (cbdata->cur_keys, reply->elements);

			for (i = 0; i < reply->elements; i ++) {
				elt = reply->element[i];

				if (elt->type == REDIS_REPLY_STRING) {
					pk = (gchar **)&g_ptr_array_index (cbdata->cur_keys, i);
					*pk = g_malloc (elt->len + 1);
					rspamd_strlcpy (*pk, elt->str, elt->len + 1);
					processed ++;
				}
			}

			if (processed) {
				for (i = 0; i < cbdata->cur_keys->len; i ++) {
					k = (gchar *)g_ptr_array_index (cbdata->cur_keys, i);

					if (k) {
						redisAsyncCommand (cbdata->redis, rspamd_redis_stat_key,
								cbdata,
								"HLEN %s",
								k);
						redisAsyncCommand (cbdata->redis, rspamd_redis_stat_learns,
								cbdata,
								"HGET %s learns",
								k);
						cbdata->inflight += 2;
					}
				}
			}
		}

		/* Set up the required keys */
		ucl_object_insert_key (cbdata->cur,
				ucl_object_typed_new (UCL_INT), "revision", 0, false);
		ucl_object_insert_key (cbdata->cur,
				ucl_object_typed_new (UCL_INT), "used", 0, false);
		ucl_object_insert_key (cbdata->cur,
				ucl_object_typed_new (UCL_INT), "total", 0, false);
		ucl_object_insert_key (cbdata->cur,
				ucl_object_typed_new (UCL_INT), "size", 0, false);
		ucl_object_insert_key (cbdata->cur,
				ucl_object_fromstring (cbdata->elt->ctx->stcf->symbol),
				"symbol", 0, false);
		ucl_object_insert_key (cbdata->cur, ucl_object_fromstring ("redis"),
				"type", 0, false);
		ucl_object_insert_key (cbdata->cur, ucl_object_fromint (0),
				"languages", 0, false);
		ucl_object_insert_key (cbdata->cur, ucl_object_fromint (processed),
				"users", 0, false);

		rspamd_upstream_ok (cbdata->selected);
	}
	else {
		msg_err ("cannot get keys to gather stat");
		rspamd_upstream_fail (cbdata->selected);
		rspamd_redis_async_cbdata_cleanup (cbdata);
	}

	if (cbdata->inflight == 0) {
		rspamd_redis_async_cbdata_cleanup (cbdata);
	}
}
예제 #28
0
static gint
lua_worker_spawn_process (lua_State *L)
{
	struct rspamd_worker *w = lua_check_worker (L, 1);
	struct rspamd_lua_process_cbdata *cbdata;
	struct rspamd_abstract_worker_ctx *actx;
	struct rspamd_srv_command srv_cmd;
	const gchar *cmdline = NULL, *input = NULL;
	gsize inputlen = 0;
	pid_t pid;
	GError *err = NULL;
	gint func_cbref, cb_cbref;

	if (!rspamd_lua_parse_table_arguments (L, 2, &err,
			"func=F;exec=S;stdin=V;*on_complete=F", &func_cbref,
			&cmdline, &inputlen, &input, &cb_cbref)) {
		msg_err ("cannot get parameters list: %e", err);

		if (err) {
			g_error_free (err);
		}

		return 0;
	}

	cbdata = g_malloc0 (sizeof (*cbdata));
	cbdata->cb_cbref = cb_cbref;
	cbdata->func_cbref = func_cbref;

	if (input) {
		cbdata->out_buf = g_string_new_len (input, inputlen);
		cbdata->out_pos = 0;
	}

	if (rspamd_socketpair (cbdata->sp, TRUE) == -1) {
		msg_err ("cannot spawn socketpair: %s", strerror (errno));
		luaL_unref (L, LUA_REGISTRYINDEX, cbdata->func_cbref);
		luaL_unref (L, LUA_REGISTRYINDEX, cbdata->cb_cbref);
		g_free (cbdata);

		return 0;
	}

	actx = w->ctx;
	cbdata->wrk = w;
	cbdata->L = L;
	cbdata->ev_base = actx->ev_base;
	cbdata->sz = (guint64)-1;

	pid = fork ();

	if (pid == -1) {
		msg_err ("cannot spawn process: %s", strerror (errno));
		close (cbdata->sp[0]);
		close (cbdata->sp[1]);
		luaL_unref (L, LUA_REGISTRYINDEX, cbdata->func_cbref);
		luaL_unref (L, LUA_REGISTRYINDEX, cbdata->cb_cbref);
		g_free (cbdata);

		return 0;
	}
	else if (pid == 0) {
		/* Child */
		gint rc;
		gchar inbuf[4];

		rspamd_log_update_pid (w->cf->type, w->srv->logger);
		rc = ottery_init (w->srv->cfg->libs_ctx->ottery_cfg);

		if (rc != OTTERY_ERR_NONE) {
			msg_err ("cannot initialize PRNG: %d", rc);
			abort ();
		}
		rspamd_random_seed_fast ();
#ifdef HAVE_EVUTIL_RNG_INIT
		evutil_secure_rng_init ();
#endif

		close (cbdata->sp[0]);
		/* Here we assume that we can block on writing results */
		rspamd_socket_blocking (cbdata->sp[1]);
		event_reinit (cbdata->ev_base);
		g_hash_table_remove_all (w->signal_events);
		rspamd_worker_unblock_signals ();
		rspamd_lua_execute_lua_subprocess (L, cbdata);

		/* Wait for parent to reply and exit */
		rc = read (cbdata->sp[1], inbuf, sizeof (inbuf));

		if (memcmp (inbuf, "\0\0\0\0", 4) == 0) {
			exit (EXIT_SUCCESS);
		}
		else {
			msg_err ("got invalid reply from parent");

			exit (EXIT_FAILURE);
		}

	}

	cbdata->cpid = pid;
	cbdata->io_buf = g_string_sized_new (8);
	/* Notify main */
	memset (&srv_cmd, 0, sizeof (srv_cmd));
	srv_cmd.type = RSPAMD_SRV_ON_FORK;
	srv_cmd.cmd.on_fork.state = child_create;
	srv_cmd.cmd.on_fork.cpid = pid;
	srv_cmd.cmd.on_fork.ppid = getpid ();
	rspamd_srv_send_command (w, cbdata->ev_base, &srv_cmd, -1, NULL, NULL);

	close (cbdata->sp[1]);
	rspamd_socket_nonblocking (cbdata->sp[0]);
	/* Parent */
	rspamd_worker_set_signal_handler (SIGCHLD, w, cbdata->ev_base,
			rspamd_lua_cld_handler,
			cbdata);

	/* Add result pipe waiting */
	event_set (&cbdata->ev, cbdata->sp[0], EV_READ | EV_PERSIST,
			rspamd_lua_subprocess_io, cbdata);
	event_base_set (cbdata->ev_base, &cbdata->ev);
	/* TODO: maybe add timeout? */
	event_add (&cbdata->ev, NULL);

	return 0;
}
예제 #29
0
static int check_specific_limit(struct mlfi_priv *priv, struct config_file *cfg,
		enum keytype type, bucket_t *bucket, double tm, const char *rcpt,
		int is_update)
{
	struct memcached_server *selected;
	struct ratelimit_bucket_s *b;
	char key[MAXKEYLEN];
	size_t klen, dlen;

	if (bucket->burst == 0 || bucket->rate == 0) {
		return 1;
	}

	klen = make_key (key, sizeof(key), type, priv, rcpt);

	if (klen == 0) {
		msg_err("<%s>; check_specific_limit: got error bad too long key", priv->mlfi_id);
		return -1;
	}

	dlen = sizeof (*b);

	if (!rmilter_query_cache (cfg, RMILTER_QUERY_RATELIMIT, key, klen,
			(unsigned char **) &b, &dlen, priv)) {
		b = calloc (1, sizeof (*b));
		dlen = sizeof (*b);

		if (b == NULL) {
			msg_err("<%s>; check_specific_limit: calloc failed: %s",
				priv->mlfi_id, strerror (errno));
			return -1;
		}
	}

	msg_debug("<%s>; check_specific_limit: got limit for key: '%s', "
			"count: %.1f, time: %.1f", priv->mlfi_id, key, b->count, b->tm);
	/* Leak from bucket at specified rate */
	if (b->count > 0) {
		b->count -= (tm - b->tm) * bucket->rate;
	}

	b->count += is_update;
	b->tm = tm;
	if (b->count < 0) {
		b->count = 0;
	}

	if (is_update && b->count == 0) {
		/* Delete key if bucket is empty */
		rmilter_delete_cache (cfg, RMILTER_QUERY_RATELIMIT, key, klen, priv);
	}
	else {
		/* Update rate limit */
		rmilter_set_cache (cfg, RMILTER_QUERY_RATELIMIT, key, klen,
				(unsigned char *) b, dlen, EXPIRE_TIME, priv);
	}

	if (b->count > bucket->burst && !is_update) {
		/* Rate limit exceeded */
		msg_info(
				"<%s>; rate_check: ratelimit exceeded for key: %s, count: %.2f, burst: %u",
				priv->mlfi_id, key, b->count, bucket->burst);
		free (b);

		return 0;
	}

	free (b);
	/* Rate limit not exceeded */
	return 1;
}
예제 #30
0
파일: regexp.c 프로젝트: smfreegard/rspamd
/* PCRE 2 version */
gboolean
rspamd_regexp_search (rspamd_regexp_t *re, const gchar *text, gsize len,
		const gchar **start, const gchar **end, gboolean raw,
		GArray *captures)
{
	pcre2_match_data *match_data;
	pcre2_match_context *mcontext;
	PCRE_T *r;
	const gchar *mt;
	gsize remain = 0, *ovec;
	gint rc, match_flags, novec, i;
	gboolean ret = FALSE;

	g_assert (re != NULL);
	g_assert (text != NULL);

	if (len == 0) {
		len = strlen (text);
	}

	if (end != NULL && *end != NULL) {
		/* Incremental search */
		mt = (*end);

		if ((gint)len > (mt - text)) {
			remain = len - (mt - text);
		}
	}
	else {
		mt = text;
		remain = len;
	}

	if (remain == 0) {
		return FALSE;
	}

	match_flags = 0;

	if (raw || re->re == re->raw_re) {
		r = re->raw_re;
		mcontext = re->raw_mcontext;
	}
	else {
		r = re->re;
		mcontext = re->mcontext;
	}

	match_data = pcre2_match_data_create (re->ncaptures + 1, NULL);

#ifdef HAVE_PCRE_JIT
	if (!(re->flags & RSPAMD_REGEXP_FLAG_DISABLE_JIT) && can_jit) {
		if (re->re != re->raw_re && !g_utf8_validate (mt, remain, NULL)) {
			msg_err ("bad utf8 input for JIT re");
			return FALSE;
		}

		rc = pcre2_jit_match (r,  mt, remain, 0, match_flags, match_data,
				mcontext);
	}
	else {
		rc = pcre2_match (r,  mt, remain, 0, match_flags, match_data,
				mcontext);
	}
#else
	rc = pcre2_match (r,  mt, remain, 0, match_flags, match_data,
					mcontext);
#endif

	if (rc >= 0) {
		novec = pcre2_get_ovector_count (match_data);
		ovec = pcre2_get_ovector_pointer (match_data);

		if (start) {
			*start = mt + ovec[0];
		}
		if (end) {
			*end = mt + ovec[1];
		}

		if (captures != NULL && novec > 1) {
			struct rspamd_re_capture *elt;

			g_assert (g_array_get_element_size (captures) ==
					sizeof (struct rspamd_re_capture));
			g_array_set_size (captures, novec);

			for (i = 0; i < novec; i ++) {
				elt = &g_array_index (captures, struct rspamd_re_capture, i);
				elt->p = mt + ovec[i * 2];
				elt->len = (mt + ovec[i * 2 + 1]) - elt->p;

			}
		}

		ret = TRUE;

		if (re->flags & RSPAMD_REGEXP_FLAG_FULL_MATCH) {
			/* We also ensure that the match is full */
			if (ovec[0] != 0 || (guint)ovec[1] < len) {
				ret = FALSE;
			}
		}
	}