示例#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;
}
示例#2
0
static gint
lua_cryptobox_signature_gc (lua_State *L)
{
	rspamd_fstring_t *sig = lua_check_cryptobox_sign (L, 1);

	rspamd_fstring_free (sig);

	return 0;
}
示例#3
0
/**
 * Sign file using specified rsa key and signature
 *
 * arguments:
 * (rsa_privkey, rsa_signature, string)
 *
 * returns:
 * true - if string match rsa signature
 * false - otherwise
 */
static gint
lua_rsa_sign_file (lua_State *L)
{
	RSA *rsa;
	rspamd_fstring_t *signature, **psig;
	const gchar *filename;
	gchar *data = NULL, *data_sig;
	gint ret, fd;
	struct stat st;

	rsa = lua_check_rsa_privkey (L, 1);
	filename = luaL_checkstring (L, 2);

	if (rsa != NULL && filename != NULL) {
		fd = open (filename, O_RDONLY);
		if (fd == -1) {
			msg_err ("cannot open file %s: %s", filename, strerror (errno));
			lua_pushnil (L);
		}
		else {
			if (fstat (fd, &st) == -1 ||
				(data =
				mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd,
				0)) == MAP_FAILED) {
				msg_err ("cannot mmap file %s: %s", filename, strerror (errno));
				lua_pushnil (L);
			}
			else {
				signature = rspamd_fstring_sized_new (RSA_size (rsa));
				data_sig = g_compute_checksum_for_string (G_CHECKSUM_SHA256,
						data,
						st.st_size);
				ret = RSA_sign (NID_sha1, data_sig, strlen (data_sig),
						signature->str, (guint *)&signature->len, rsa);
				if (ret == 0) {
					msg_info ("cannot make a signature for data: %s",
						ERR_error_string (ERR_get_error (), NULL));
					lua_pushnil (L);
					rspamd_fstring_free (signature);
				}
				else {
					psig = lua_newuserdata (L, sizeof (rspamd_fstring_t *));
					rspamd_lua_setclass (L, "rspamd{rsa_signature}", -1);
					*psig = signature;
				}
				g_free (data_sig);
				munmap (data, st.st_size);
			}
			close (fd);
		}
	}
	else {
		lua_pushnil (L);
	}

	return 1;
}
示例#4
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);
}
示例#5
0
static void
rspamadm_dump_section_obj (const ucl_object_t *obj)
{
	rspamd_fstring_t *output;

	output = rspamd_fstring_new ();

	if (json) {
		rspamd_ucl_emit_fstring (obj, UCL_EMIT_JSON, &output);
	}
	else if (compact) {
		rspamd_ucl_emit_fstring (obj, UCL_EMIT_JSON_COMPACT, &output);
	}
	else {
		rspamd_ucl_emit_fstring (obj, UCL_EMIT_CONFIG, &output);
	}

	rspamd_printf ("%V", output);

	rspamd_fstring_free (output);
}
示例#6
0
/**
 * Sign memory using specified rsa key and signature
 *
 * arguments:
 * (rsa_privkey, string)
 *
 * returns:
 * rspamd_signature object
 * nil - otherwise
 */
static gint
lua_rsa_sign_memory (lua_State *L)
{
	RSA *rsa;
	rspamd_fstring_t *signature, **psig;
	const gchar *data;
	guchar *data_sig;
	gint ret;

	rsa = lua_check_rsa_privkey (L, 1);
	data = luaL_checkstring (L, 2);

	if (rsa != NULL && data != NULL) {
		signature = rspamd_fstring_sized_new (RSA_size (rsa));
		data_sig = g_compute_checksum_for_string (G_CHECKSUM_SHA256, data, -1);
		ret = RSA_sign (NID_sha1, data_sig, strlen (data_sig),
				signature->str, (guint *)&signature->len, rsa);
		if (ret == 0) {
			msg_info ("cannot make a signature for data: %s",
				ERR_error_string (ERR_get_error (), NULL));
			lua_pushnil (L);
			rspamd_fstring_free (signature);
		}
		else {
			psig = lua_newuserdata (L, sizeof (rspamd_fstring_t *));
			rspamd_lua_setclass (L, "rspamd{rsa_signature}", -1);
			*psig = signature;
		}
		g_free (data_sig);
	}
	else {
		lua_pushnil (L);
	}

	return 1;
}
示例#7
0
void
rspamd_re_cache_init (struct rspamd_re_cache *cache, struct rspamd_config *cfg)
{
	guint i, fl;
	GHashTableIter it;
	gpointer k, v;
	struct rspamd_re_class *re_class;
	rspamd_cryptobox_hash_state_t st_global;
	rspamd_regexp_t *re;
	struct rspamd_re_cache_elt *elt;
	guchar hash_out[rspamd_cryptobox_HASHBYTES];

	g_assert (cache != NULL);

	rspamd_cryptobox_hash_init (&st_global, NULL, 0);
	/* Resort all regexps */
	g_ptr_array_sort (cache->re, rspamd_re_cache_sort_func);

	for (i = 0; i < cache->re->len; i ++) {
		elt = g_ptr_array_index (cache->re, i);
		re = elt->re;
		re_class = rspamd_regexp_get_class (re);
		g_assert (re_class != NULL);
		rspamd_regexp_set_cache_id (re, i);

		if (re_class->st == NULL) {
			re_class->st = g_slice_alloc (sizeof (*re_class->st));
			rspamd_cryptobox_hash_init (re_class->st, NULL, 0);
		}

		/* Update hashes */
		rspamd_cryptobox_hash_update (re_class->st, (gpointer) &re_class->id,
				sizeof (re_class->id));
		rspamd_cryptobox_hash_update (&st_global, (gpointer) &re_class->id,
				sizeof (re_class->id));
		rspamd_cryptobox_hash_update (re_class->st, rspamd_regexp_get_id (re),
				rspamd_cryptobox_HASHBYTES);
		rspamd_cryptobox_hash_update (&st_global, rspamd_regexp_get_id (re),
				rspamd_cryptobox_HASHBYTES);
		fl = rspamd_regexp_get_pcre_flags (re);
		rspamd_cryptobox_hash_update (re_class->st, (const guchar *)&fl,
				sizeof (fl));
		rspamd_cryptobox_hash_update (&st_global, (const guchar *) &fl,
				sizeof (fl));
		fl = rspamd_regexp_get_flags (re);
		rspamd_cryptobox_hash_update (re_class->st, (const guchar *) &fl,
				sizeof (fl));
		rspamd_cryptobox_hash_update (&st_global, (const guchar *) &fl,
				sizeof (fl));
		fl = rspamd_regexp_get_maxhits (re);
		rspamd_cryptobox_hash_update (re_class->st, (const guchar *) &fl,
				sizeof (fl));
		rspamd_cryptobox_hash_update (&st_global, (const guchar *) &fl,
				sizeof (fl));
	}

	rspamd_cryptobox_hash_final (&st_global, hash_out);
	rspamd_snprintf (cache->hash, sizeof (cache->hash), "%*xs",
			(gint) rspamd_cryptobox_HASHBYTES, hash_out);

	/* Now finalize all classes */
	g_hash_table_iter_init (&it, cache->re_classes);

	while (g_hash_table_iter_next (&it, &k, &v)) {
		re_class = v;

		if (re_class->st) {
			/*
			 * We finally update all classes with the number of expressions
			 * in the cache to ensure that if even a single re has been changed
			 * we won't be broken due to id mismatch
			 */
			rspamd_cryptobox_hash_update (re_class->st,
					(gpointer)&cache->re->len,
					sizeof (cache->re->len));
			rspamd_cryptobox_hash_final (re_class->st, hash_out);
			rspamd_snprintf (re_class->hash, sizeof (re_class->hash), "%*xs",
					(gint) rspamd_cryptobox_HASHBYTES, hash_out);
			g_slice_free1 (sizeof (*re_class->st), re_class->st);
			re_class->st = NULL;
		}
	}

#ifdef WITH_HYPERSCAN
	const gchar *platform = "generic";
	rspamd_fstring_t *features = rspamd_fstring_new ();

	cache->disable_hyperscan = cfg->disable_hyperscan;
	cache->vectorized_hyperscan = cfg->vectorized_hyperscan;

	g_assert (hs_populate_platform (&cache->plt) == HS_SUCCESS);

	/* Now decode what we do have */
	switch (cache->plt.tune) {
	case HS_TUNE_FAMILY_HSW:
		platform = "haswell";
		break;
	case HS_TUNE_FAMILY_SNB:
		platform = "sandy";
		break;
	case HS_TUNE_FAMILY_BDW:
		platform = "broadwell";
		break;
	case HS_TUNE_FAMILY_IVB:
		platform = "ivy";
		break;
	default:
		break;
	}

	if (cache->plt.cpu_features & HS_CPU_FEATURES_AVX2) {
		features = rspamd_fstring_append (features, "AVX2", 4);
	}

	hs_set_allocator (g_malloc, g_free);

	msg_info_re_cache ("loaded hyperscan engine witch cpu tune '%s' and features '%V'",
			platform, features);

	rspamd_fstring_free (features);
#endif
}
示例#8
0
rspamd_shingles_from_text (GArray *input,
		const guchar key[16],
		rspamd_mempool_t *pool,
		rspamd_shingles_filter filter,
		gpointer filterd,
		enum rspamd_shingle_alg alg)
{
	struct rspamd_shingle *res;
	guint64 **hashes;
	guchar **keys;
	rspamd_fstring_t *row;
	rspamd_stat_token_t *word;
	guint64 val;
	gint i, j, k;
	gsize hlen, beg = 0;
	enum rspamd_cryptobox_fast_hash_type ht;

	if (pool != NULL) {
		res = rspamd_mempool_alloc (pool, sizeof (*res));
	}
	else {
		res = g_malloc (sizeof (*res));
	}

	row = rspamd_fstring_sized_new (256);

	/* Init hashes pipes and keys */
	hashes = g_malloc (sizeof (*hashes) * RSPAMD_SHINGLE_SIZE);
	hlen = input->len > SHINGLES_WINDOW ?
			(input->len - SHINGLES_WINDOW + 1) : 1;
	keys = rspamd_shingles_get_keys_cached (key);

	for (i = 0; i < RSPAMD_SHINGLE_SIZE; i ++) {
		hashes[i] = g_malloc (hlen * sizeof (guint64));
	}

	/* Now parse input words into a vector of hashes using rolling window */
	if (alg == RSPAMD_SHINGLES_OLD) {
		for (i = 0; i <= (gint)input->len; i ++) {
			if (i - beg >= SHINGLES_WINDOW || i == (gint)input->len) {
				for (j = beg; j < i; j ++) {
					word = &g_array_index (input, rspamd_stat_token_t, j);
					row = rspamd_fstring_append (row, word->begin, word->len);
				}

				/* Now we need to create a new row here */
				for (j = 0; j < RSPAMD_SHINGLE_SIZE; j ++) {
					rspamd_cryptobox_siphash ((guchar *)&val, row->str, row->len,
							keys[j]);
					g_assert (hlen > beg);
					hashes[j][beg] = val;
				}

				beg++;

				row = rspamd_fstring_assign (row, "", 0);
			}
		}
	}
	else {
		guint64 res[SHINGLES_WINDOW * RSPAMD_SHINGLE_SIZE], seed;

		switch (alg) {
		case RSPAMD_SHINGLES_XXHASH:
			ht = RSPAMD_CRYPTOBOX_XXHASH64;
			break;
		case RSPAMD_SHINGLES_MUMHASH:
			ht = RSPAMD_CRYPTOBOX_MUMHASH;
			break;
		default:
			ht = RSPAMD_CRYPTOBOX_HASHFAST_INDEPENDENT;
			break;
		}

		memset (res, 0, sizeof (res));
		for (i = 0; i <= (gint)input->len; i ++) {
			if (i - beg >= SHINGLES_WINDOW || i == (gint)input->len) {

				for (j = 0; j < RSPAMD_SHINGLE_SIZE; j ++) {
					/* Shift hashes window to right */
					for (k = 0; k < SHINGLES_WINDOW - 1; k ++) {
						res[j * SHINGLES_WINDOW + k] =
								res[j * SHINGLES_WINDOW + k + 1];
					}

					word = &g_array_index (input, rspamd_stat_token_t, beg);
					/* Insert the last element to the pipe */
					memcpy (&seed, keys[j], sizeof (seed));
					res[j * SHINGLES_WINDOW + SHINGLES_WINDOW - 1] =
							rspamd_cryptobox_fast_hash_specific (ht,
									word->begin, word->len,
									seed);
					val = 0;
					for (k = 0; k < SHINGLES_WINDOW; k ++) {
						val ^= res[j * SHINGLES_WINDOW + k] >>
								(8 * (SHINGLES_WINDOW - k - 1));
					}

					g_assert (hlen > beg);
					hashes[j][beg] = val;
				}
				beg++;
			}
		}
	}

	/* Now we need to filter all hashes and make a shingles result */
	for (i = 0; i < RSPAMD_SHINGLE_SIZE; i ++) {
		res->hashes[i] = filter (hashes[i], hlen,
				i, key, filterd);
		g_free (hashes[i]);
	}

	g_free (hashes);

	rspamd_fstring_free (row);

	return res;
}
示例#9
0
gboolean
rspamd_client_command (struct rspamd_client_connection *conn,
                       const gchar *command, GQueue *attrs,
                       FILE *in, rspamd_client_callback cb,
                       gpointer ud, gboolean compressed,
                       const gchar *comp_dictionary,
                       GError **err)
{
    struct rspamd_client_request *req;
    struct rspamd_http_client_header *nh;
    gchar *p;
    gsize remain, old_len;
    GList *cur;
    GString *input = NULL;
    rspamd_fstring_t *body;
    guint dict_id = 0;
    gsize dict_len = 0;
    void *dict = NULL;
    ZSTD_CCtx *zctx;

    req = g_slice_alloc0 (sizeof (struct rspamd_client_request));
    req->conn = conn;
    req->cb = cb;
    req->ud = ud;

    req->msg = rspamd_http_new_message (HTTP_REQUEST);
    if (conn->key) {
        req->msg->peer_key = rspamd_pubkey_ref (conn->key);
    }

    if (in != NULL) {
        /* Read input stream */
        input = g_string_sized_new (BUFSIZ);

        while (!feof (in)) {
            p = input->str + input->len;
            remain = input->allocated_len - input->len - 1;
            if (remain == 0) {
                old_len = input->len;
                g_string_set_size (input, old_len * 2);
                input->len = old_len;
                continue;
            }
            remain = fread (p, 1, remain, in);
            if (remain > 0) {
                input->len += remain;
                input->str[input->len] = '\0';
            }
        }
        if (ferror (in) != 0) {
            g_set_error (err, RCLIENT_ERROR, ferror (
                             in), "input IO error: %s", strerror (ferror (in)));
            g_slice_free1 (sizeof (struct rspamd_client_request), req);
            g_string_free (input, TRUE);
            return FALSE;
        }

        if (!compressed) {
            body = rspamd_fstring_new_init (input->str, input->len);
        }
        else {
            if (comp_dictionary) {
                dict = rspamd_file_xmap (comp_dictionary, PROT_READ, &dict_len);

                if (dict == NULL) {
                    g_set_error (err, RCLIENT_ERROR, errno,
                                 "cannot open dictionary %s: %s",
                                 comp_dictionary,
                                 strerror (errno));
                    g_slice_free1 (sizeof (struct rspamd_client_request), req);
                    g_string_free (input, TRUE);

                    return FALSE;
                }

                dict_id = ZDICT_getDictID (comp_dictionary, dict_len);

                if (dict_id == 0) {
                    g_set_error (err, RCLIENT_ERROR, errno,
                                 "cannot open dictionary %s: %s",
                                 comp_dictionary,
                                 strerror (errno));
                    g_slice_free1 (sizeof (struct rspamd_client_request), req);
                    g_string_free (input, TRUE);
                    munmap (dict, dict_len);

                    return FALSE;
                }
            }

            body = rspamd_fstring_sized_new (ZSTD_compressBound (input->len));
            zctx = ZSTD_createCCtx ();
            body->len = ZSTD_compress_usingDict (zctx, body->str, body->allocated,
                                                 input->str, input->len,
                                                 dict, dict_len,
                                                 1);

            munmap (dict, dict_len);

            if (ZSTD_isError (body->len)) {
                g_set_error (err, RCLIENT_ERROR, ferror (
                                 in), "compression error");
                g_slice_free1 (sizeof (struct rspamd_client_request), req);
                g_string_free (input, TRUE);
                rspamd_fstring_free (body);
                ZSTD_freeCCtx (zctx);

                return FALSE;
            }

            ZSTD_freeCCtx (zctx);
        }

        rspamd_http_message_set_body_from_fstring_steal (req->msg, body);
        req->input = input;
    }
    else {
        req->input = NULL;
    }

    /* Convert headers */
    cur = attrs->head;
    while (cur != NULL) {
        nh = cur->data;

        rspamd_http_message_add_header (req->msg, nh->name, nh->value);
        cur = g_list_next (cur);
    }

    if (compressed) {
        rspamd_http_message_add_header (req->msg, "Compression", "zstd");

        if (dict_id != 0) {
            gchar dict_str[32];

            rspamd_snprintf (dict_str, sizeof (dict_str), "%ud", dict_id);
            rspamd_http_message_add_header (req->msg, "Dictionary", dict_str);
        }
    }

    req->msg->url = rspamd_fstring_append (req->msg->url, "/", 1);
    req->msg->url = rspamd_fstring_append (req->msg->url, command, strlen (command));

    conn->req = req;

    if (compressed) {
        rspamd_http_connection_write_message (conn->http_conn, req->msg, NULL,
                                              "application/x-compressed", req, conn->fd,
                                              &conn->timeout, conn->ev_base);
    }
    else {
        rspamd_http_connection_write_message (conn->http_conn, req->msg, NULL,
                                              "text/plain", req, conn->fd, &conn->timeout, conn->ev_base);
    }

    return TRUE;
}