aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fuzzy_storage.c88
1 files changed, 82 insertions, 6 deletions
diff --git a/src/fuzzy_storage.c b/src/fuzzy_storage.c
index bc69be98c..00f226532 100644
--- a/src/fuzzy_storage.c
+++ b/src/fuzzy_storage.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2024 Vsevolod Stakhov
+ * Copyright 2025 Vsevolod Stakhov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -124,6 +124,11 @@ fuzzy_kp_equal(gconstpointer a, gconstpointer b)
return (memcmp(pa, pb, RSPAMD_FUZZY_KEYLEN) == 0);
}
+enum fuzzy_key_op {
+ FUZZY_KEY_READ = 0x1u << 0,
+ FUZZY_KEY_WRITE = 0x1u << 1,
+ FUZZY_KEY_DELETE = 0x1u << 2,
+};
KHASH_SET_INIT_INT(fuzzy_key_ids_set);
KHASH_INIT(fuzzy_key_flag_stat, int, struct fuzzy_key_stat, 1, kh_int_hash_func,
kh_int_hash_equal);
@@ -135,10 +140,12 @@ struct fuzzy_key {
khash_t(fuzzy_key_flag_stat) * flags_stat;
khash_t(fuzzy_key_ids_set) * forbidden_ids;
struct rspamd_leaky_bucket_elt *rl_bucket;
+ ucl_object_t *extensions;
double burst;
double rate;
ev_tstamp expire;
bool expired;
+ int flags; /* enum fuzzy_key_op */
ref_entry_t ref;
};
@@ -624,12 +631,15 @@ rspamd_fuzzy_check_client(struct rspamd_fuzzy_storage_ctx *ctx,
}
static gboolean
-rspamd_fuzzy_check_write(struct fuzzy_session *session)
+rspamd_fuzzy_check_write(struct fuzzy_session *session, uint8_t cmd)
{
if (session->ctx->read_only) {
return FALSE;
}
+ /*
+ * Check IP first
+ */
if (session->ctx->update_ips != NULL && session->addr) {
if (rspamd_inet_address_get_af(session->addr) == AF_UNIX) {
return TRUE;
@@ -643,6 +653,9 @@ rspamd_fuzzy_check_write(struct fuzzy_session *session)
}
}
+ /*
+ * Check global list of the update keys
+ */
if (session->ctx->update_keys != NULL && session->key->stat && session->key->key) {
static char base32_buf[rspamd_cryptobox_HASHBYTES * 2 + 1];
unsigned int raw_len;
@@ -657,6 +670,15 @@ rspamd_fuzzy_check_write(struct fuzzy_session *session)
}
}
+ if (session->key) {
+ if (cmd == FUZZY_WRITE && session->key->flags & FUZZY_KEY_WRITE) {
+ return TRUE;
+ }
+ else if (cmd == FUZZY_DEL && session->key->flags & FUZZY_KEY_DELETE) {
+ return TRUE;
+ }
+ }
+
return FALSE;
}
@@ -711,6 +733,10 @@ fuzzy_key_dtor(gpointer p)
g_free(key->name);
}
+ if (key->extensions) {
+ ucl_object_unref(key->extensions);
+ }
+
g_free(key);
}
}
@@ -1628,6 +1654,14 @@ rspamd_fuzzy_process_command(struct fuzzy_session *session)
}
}
+ /* Key is not allowed to read */
+ if (session->key && !(session->key->flags & FUZZY_KEY_READ)) {
+ result.v1.value = 503;
+ result.v1.prob = 0.0f;
+ rspamd_fuzzy_make_reply(cmd, &result, session, send_flags);
+ return;
+ }
+
if (is_rate_allowed) {
REF_RETAIN(session);
rspamd_fuzzy_backend_check(session->ctx->backend, cmd,
@@ -1655,7 +1689,7 @@ rspamd_fuzzy_process_command(struct fuzzy_session *session)
rspamd_fuzzy_make_reply(cmd, &result, session, send_flags);
}
else {
- if (rspamd_fuzzy_check_write(session)) {
+ if (rspamd_fuzzy_check_write(session, cmd->cmd)) {
/* Check whitelist */
if (session->ctx->skip_hashes && cmd->cmd == FUZZY_WRITE) {
rspamd_encode_hex_buf(cmd->digest, sizeof(cmd->digest),
@@ -2942,6 +2976,8 @@ fuzzy_add_keypair_from_ucl(struct rspamd_config *cfg, const ucl_object_t *obj,
key->rate = NAN;
key->expire = NAN;
key->rl_bucket = NULL;
+ /* Allow read by default */
+ key->flags = FUZZY_KEY_READ;
/* Preallocate some space for flags */
kh_resize(fuzzy_key_flag_stat, key->flags_stat, 8);
const unsigned char *pk = rspamd_keypair_component(kp, RSPAMD_KEYPAIR_COMPONENT_PK,
@@ -2973,6 +3009,7 @@ fuzzy_add_keypair_from_ucl(struct rspamd_config *cfg, const ucl_object_t *obj,
const ucl_object_t *extensions = rspamd_keypair_get_extensions(kp);
if (extensions) {
+ key->extensions = ucl_object_ref(extensions);
lua_State *L = RSPAMD_LUA_CFG_STATE(cfg);
const ucl_object_t *forbidden_ids = ucl_object_lookup(extensions, "forbidden_ids");
@@ -3052,9 +3089,48 @@ fuzzy_add_keypair_from_ucl(struct rspamd_config *cfg, const ucl_object_t *obj,
if (name && ucl_object_type(name) == UCL_STRING) {
key->name = g_strdup(ucl_object_tostring(name));
}
+
+ /* Check permissions */
+ const ucl_object_t *read_only = ucl_object_lookup(extensions, "read_only");
+ if (read_only && ucl_object_type(read_only) == UCL_BOOLEAN) {
+ if (ucl_object_toboolean(read_only)) {
+ key->flags &= ~(FUZZY_KEY_WRITE | FUZZY_KEY_DELETE);
+ }
+ else {
+ key->flags |= (FUZZY_KEY_WRITE | FUZZY_KEY_DELETE);
+ }
+ }
+
+ const ucl_object_t *allowed_ops = ucl_object_lookup(extensions, "allowed_ops");
+ if (allowed_ops && ucl_object_type(allowed_ops) == UCL_ARRAY) {
+ const ucl_object_t *cur;
+ ucl_object_iter_t it = NULL;
+ /* Reset to only allowed */
+ key->flags = 0;
+
+ while ((cur = ucl_object_iterate(allowed_ops, &it, true)) != NULL) {
+ if (ucl_object_type(cur) == UCL_STRING) {
+ const char *op = ucl_object_tostring(cur);
+
+ if (g_ascii_strcasecmp(op, "read") == 0) {
+ key->flags |= FUZZY_KEY_READ;
+ }
+ else if (g_ascii_strcasecmp(op, "write") == 0) {
+ key->flags |= FUZZY_KEY_WRITE;
+ }
+ else if (g_ascii_strcasecmp(op, "delete") == 0) {
+ key->flags |= FUZZY_KEY_DELETE;
+ }
+ else {
+ msg_warn_config("invalid operation: %s", op);
+ }
+ }
+ }
+ }
}
- msg_debug("loaded keypair %*bs; expire=%f; rate=%f; burst=%f; name=%s", (int) crypto_box_publickeybytes(), pk,
+ msg_debug("loaded keypair %*bs; expire=%f; rate=%f; burst=%f; name=%s",
+ (int) crypto_box_publickeybytes(), pk,
key->expire, key->rate, key->burst, key->name);
return key;
@@ -3677,12 +3753,12 @@ start_fuzzy(struct rspamd_worker *worker)
.func = lua_fuzzy_add_pre_handler,
};
rspamd_lua_add_metamethod(ctx->cfg->lua_state, rspamd_worker_classname, &fuzzy_lua_reg);
- fuzzy_lua_reg = (luaL_Reg){
+ fuzzy_lua_reg = (luaL_Reg) {
.name = "add_fuzzy_post_handler",
.func = lua_fuzzy_add_post_handler,
};
rspamd_lua_add_metamethod(ctx->cfg->lua_state, rspamd_worker_classname, &fuzzy_lua_reg);
- fuzzy_lua_reg = (luaL_Reg){
+ fuzzy_lua_reg = (luaL_Reg) {
.name = "add_fuzzy_blacklist_handler",
.func = lua_fuzzy_add_blacklist_handler,
};