From: Arran Cudbard-Bell Date: Tue, 14 Nov 2023 01:05:40 +0000 (-0600) Subject: cache: Move key resolution to callenv X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9fb0772c2d9f803e90e6a76276398270a9e63267;p=thirdparty%2Ffreeradius-server.git cache: Move key resolution to callenv ...weird intractable problems trying to get an old DHCPv4 config, easier to fix the code than debug it. --- diff --git a/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c b/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c index 57026db1c48..c43da55b463 100644 --- a/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c +++ b/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "../../rlm_cache.h" #include "../../serialize.h" @@ -157,7 +158,7 @@ static void cache_entry_free(rlm_cache_entry_t *c) */ static cache_status_t cache_entry_find(rlm_cache_entry_t **out, UNUSED rlm_cache_config_t const *config, UNUSED void *instance, - request_t *request, void *handle, uint8_t const *key, size_t key_len) + request_t *request, void *handle, fr_value_box_t const *key) { rlm_cache_memcached_handle_t *mandle = handle; @@ -170,7 +171,7 @@ static cache_status_t cache_entry_find(rlm_cache_entry_t **out, rlm_cache_entry_t *c; - from_store = memcached_get(mandle->handle, (char const *)key, key_len, &len, &flags, &mret); + from_store = memcached_get(mandle->handle, (char const *)key->vb_strvalue, key->vb_length, &len, &flags, &mret); if (!from_store) { if (mret == MEMCACHED_NOTFOUND) return CACHE_MISS; @@ -182,16 +183,19 @@ static cache_status_t cache_entry_find(rlm_cache_entry_t **out, RDEBUG2("Retrieved %zu bytes from memcached", len); RDEBUG2("%s", from_store); - c = talloc_zero(NULL, rlm_cache_entry_t); + MEM(c = talloc_zero(NULL, rlm_cache_entry_t)); ret = cache_deserialize(c, request->dict, from_store, len); free(from_store); if (ret < 0) { RPERROR("Invalid entry"); + error: talloc_free(c); return CACHE_ERROR; } - c->key = talloc_memdup(c, key, key_len); - c->key_len = key_len; + if (unlikely(fr_value_box_copy(c, &c->key, key) < 0)) { + RERROR("Failed copying key"); + goto error; + } *out = c; @@ -221,7 +225,7 @@ static cache_status_t cache_entry_insert(UNUSED rlm_cache_config_t const *config return CACHE_ERROR; } - ret = memcached_set(mandle->handle, (char const *)c->key, c->key_len, + ret = memcached_set(mandle->handle, (char const *)c->key.vb_strvalue, c->key.vb_length, to_store ? to_store : "", to_store ? talloc_array_length(to_store) - 1 : 0, fr_unix_time_to_sec(c->expires), 0); talloc_free(pool); @@ -240,13 +244,13 @@ static cache_status_t cache_entry_insert(UNUSED rlm_cache_config_t const *config * @copydetails cache_entry_expire_t */ static cache_status_t cache_entry_expire(UNUSED rlm_cache_config_t const *config, UNUSED void *instance, - request_t *request, void *handle, uint8_t const *key, size_t key_len) + request_t *request, void *handle, fr_value_box_t const *key) { rlm_cache_memcached_handle_t *mandle = handle; memcached_return_t ret; - ret = memcached_delete(mandle->handle, (char const *)key, key_len, 0); + ret = memcached_delete(mandle->handle, (char const *)key->vb_strvalue, key->vb_length, 0); switch (ret) { case MEMCACHED_SUCCESS: return CACHE_OK; diff --git a/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c b/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c index a03ece0fa03..4838e824d1f 100644 --- a/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c +++ b/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "../../rlm_cache.h" typedef struct { @@ -48,7 +49,7 @@ static int8_t cache_entry_cmp(void const *one, void const *two) { rlm_cache_entry_t const *a = one, *b = two; - MEMCMP_RETURN(a, b, key, key_len); + MEMCMP_RETURN(a, b, key.vb_strvalue, key.vb_length); return 0; } @@ -153,9 +154,10 @@ static rlm_cache_entry_t *cache_entry_alloc(UNUSED rlm_cache_config_t const *con */ static cache_status_t cache_entry_find(rlm_cache_entry_t **out, UNUSED rlm_cache_config_t const *config, void *instance, - request_t *request, UNUSED void *handle, uint8_t const *key, size_t key_len) + request_t *request, UNUSED void *handle, fr_value_box_t const *key) { rlm_cache_rbtree_t *driver = talloc_get_type_abort(instance, rlm_cache_rbtree_t); + rlm_cache_entry_t find = {}; rlm_cache_entry_t *c; @@ -171,10 +173,12 @@ static cache_status_t cache_entry_find(rlm_cache_entry_t **out, talloc_free(c); } + fr_value_box_copy_shallow(NULL, &find.key, key); + /* * Is there an entry for this key? */ - c = fr_rb_find(driver->cache, &(rlm_cache_entry_t){ .key = key, .key_len = key_len }); + c = fr_rb_find(driver->cache, &find); if (!c) { *out = NULL; return CACHE_MISS; @@ -192,14 +196,17 @@ static cache_status_t cache_entry_find(rlm_cache_entry_t **out, */ static cache_status_t cache_entry_expire(UNUSED rlm_cache_config_t const *config, void *instance, request_t *request, UNUSED void *handle, - uint8_t const *key, size_t key_len) + fr_value_box_t const *key) { rlm_cache_rbtree_t *driver = talloc_get_type_abort(instance, rlm_cache_rbtree_t); + rlm_cache_entry_t find = {}; rlm_cache_entry_t *c; if (!request) return CACHE_ERROR; - c = fr_rb_find(driver->cache, &(rlm_cache_entry_t){ .key = key, .key_len = key_len }); + fr_value_box_copy_shallow(NULL, &find.key, key); + + c = fr_rb_find(driver->cache, &find); if (!c) return CACHE_MISS; fr_heap_extract(&driver->heap, c); @@ -231,7 +238,7 @@ static cache_status_t cache_entry_insert(rlm_cache_config_t const *config, void * Allow overwriting */ if (!fr_rb_insert(driver->cache, c)) { - status = cache_entry_expire(config, instance, request, handle, c->key, c->key_len); + status = cache_entry_expire(config, instance, request, handle, &c->key); if ((status != CACHE_OK) && !fr_cond_assert(0)) return CACHE_ERROR; if (!fr_rb_insert(driver->cache, c)) { diff --git a/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c b/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c index ed37b6b26d4..d24a559aea2 100644 --- a/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c +++ b/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c @@ -25,6 +25,7 @@ #include #include +#include #include "../../rlm_cache.h" #include @@ -121,7 +122,7 @@ static void cache_entry_free(rlm_cache_entry_t *c) */ static cache_status_t cache_entry_find(rlm_cache_entry_t **out, UNUSED rlm_cache_config_t const *config, void *instance, - request_t *request, UNUSED void *handle, uint8_t const *key, size_t key_len) + request_t *request, UNUSED void *handle, fr_value_box_t const *key) { rlm_cache_redis_t *driver = instance; size_t i; @@ -139,19 +140,19 @@ static cache_status_t cache_entry_find(rlm_cache_entry_t **out, rlm_cache_entry_t *c; map_list_init(&head); - for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, key, key_len, false); + for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, (uint8_t const *)key->vb_strvalue, key->vb_length, false); s_ret == REDIS_RCODE_TRY_AGAIN; /* Continue */ s_ret = fr_redis_cluster_state_next(&state, &conn, driver->cluster, request, status, &reply)) { /* * Grab all the data for this hash, should return an array * of alternating keys/values which we then convert into maps. */ - RDEBUG3("LRANGE %pV 0 -1", fr_box_strvalue_len((char const *)key, key_len)); - reply = redisCommand(conn->handle, "LRANGE %b 0 -1", key, key_len); + RDEBUG3("LRANGE %pV 0 -1", key); + reply = redisCommand(conn->handle, "LRANGE %b 0 -1", key->vb_strvalue, key->vb_length); status = fr_redis_command_status(conn, reply); } if (s_ret != REDIS_RCODE_SUCCESS) { - RERROR("Failed retrieving entry for key \"%pV\"", fr_box_strvalue_len((char const *)key, key_len)); + RERROR("Failed retrieving entry for key \"%pV\"", key); error: fr_redis_reply_free(&reply); @@ -236,8 +237,8 @@ static cache_status_t cache_entry_find(rlm_cache_entry_t **out, talloc_free(map); } - c->key = talloc_memdup(c, key, key_len); - c->key_len = key_len; + if (unlikely(fr_value_box_copy(c, &c->key, key) < 0)) goto error; + map_list_move(&c->maps, &head); *out = c; @@ -322,8 +323,8 @@ static cache_status_t cache_entry_insert(UNUSED rlm_cache_config_t const *config *argv_p++ = command; *argv_len_p++ = sizeof(command) - 1; - *argv_p++ = (char const *)c->key; - *argv_len_p++ = c->key_len; + *argv_p++ = (char const *)c->key.vb_strvalue; + *argv_len_p++ = c->key.vb_length; /* * Add the maps to the command string in reverse order @@ -354,7 +355,7 @@ static cache_status_t cache_entry_insert(UNUSED rlm_cache_config_t const *config RDEBUG3("Pipelining commands"); - for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, c->key, c->key_len, false); + for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, (uint8_t const *)c->key.vb_strvalue, c->key.vb_length, false); s_ret == REDIS_RCODE_TRY_AGAIN; /* Continue */ s_ret = fr_redis_cluster_state_next(&state, &conn, driver->cluster, request, status, &reply)) { /* @@ -372,9 +373,9 @@ static cache_status_t cache_entry_insert(UNUSED rlm_cache_config_t const *config pipelined++; } - RDEBUG3("DEL \"%pV\"", fr_box_strvalue_len((char const *)c->key, c->key_len)); + RDEBUG3("DEL \"%pV\"", &c->key); - if (redisAppendCommand(conn->handle, "DEL %b", c->key, c->key_len) != REDIS_OK) goto append_error; + if (redisAppendCommand(conn->handle, "DEL %b", (uint8_t const *)c->key.vb_strvalue, c->key.vb_length) != REDIS_OK) goto append_error; pipelined++; if (RDEBUG_ENABLED3) { @@ -393,10 +394,9 @@ static cache_status_t cache_entry_insert(UNUSED rlm_cache_config_t const *config */ if (fr_unix_time_ispos(c->expires)) { RDEBUG3("EXPIREAT \"%pV\" %" PRIu64, - fr_box_strvalue_len((char const *)c->key, c->key_len), + &c->key, fr_unix_time_to_sec(c->expires)); - if (redisAppendCommand(conn->handle, "EXPIREAT %b %" PRIu64, c->key, - c->key_len, + if (redisAppendCommand(conn->handle, "EXPIREAT %b %" PRIu64, (uint8_t const *)c->key.vb_strvalue, (size_t)c->key.vb_length, fr_unix_time_to_sec(c->expires)) != REDIS_OK) goto append_error; pipelined++; RDEBUG3("EXEC"); @@ -430,7 +430,7 @@ static cache_status_t cache_entry_insert(UNUSED rlm_cache_config_t const *config * @copydetails cache_entry_expire_t */ static cache_status_t cache_entry_expire(UNUSED rlm_cache_config_t const *config, void *instance, - request_t *request, UNUSED void *handle, uint8_t const *key, size_t key_len) + request_t *request, UNUSED void *handle, fr_value_box_t const *key) { rlm_cache_redis_t *driver = instance; fr_redis_cluster_state_t state; @@ -440,10 +440,10 @@ static cache_status_t cache_entry_expire(UNUSED rlm_cache_config_t const *config int s_ret; cache_status_t cache_status; - for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, key, key_len, false); + for (s_ret = fr_redis_cluster_state_init(&state, &conn, driver->cluster, request, (uint8_t const *)key->vb_strvalue, key->vb_length, false); s_ret == REDIS_RCODE_TRY_AGAIN; /* Continue */ s_ret = fr_redis_cluster_state_next(&state, &conn, driver->cluster, request, status, &reply)) { - reply = redisCommand(conn->handle, "DEL %b", key, key_len); + reply = redisCommand(conn->handle, "DEL %b", (uint8_t const *)key->vb_strvalue, key->vb_length); status = fr_redis_command_status(conn, reply); } diff --git a/src/modules/rlm_cache/rlm_cache.c b/src/modules/rlm_cache/rlm_cache.c index 364281174f5..87c5be03690 100644 --- a/src/modules/rlm_cache/rlm_cache.c +++ b/src/modules/rlm_cache/rlm_cache.c @@ -29,6 +29,7 @@ RCSID("$Id$") #include #include #include +#include #include #include @@ -39,7 +40,6 @@ extern module_rlm_t rlm_cache; static const CONF_PARSER module_config[] = { { FR_CONF_OFFSET("driver", FR_TYPE_VOID, rlm_cache_t, driver_submodule), .dflt = "rbtree", .func = module_rlm_submodule_parse }, - { FR_CONF_OFFSET("key", FR_TYPE_TMPL | FR_TYPE_REQUIRED, rlm_cache_config_t, key) }, { FR_CONF_OFFSET("ttl", FR_TYPE_TIME_DELTA, rlm_cache_config_t, ttl), .dflt = "500s" }, { FR_CONF_OFFSET("max_entries", FR_TYPE_UINT32, rlm_cache_config_t, max_entries), .dflt = "0" }, @@ -49,6 +49,20 @@ static const CONF_PARSER module_config[] = { CONF_PARSER_TERMINATOR }; +typedef struct { + fr_value_box_t *key; +} cache_call_env_t; + +static const call_method_env_t cache_common_env = { + .inst_size = sizeof(cache_call_env_t), + .inst_type = "cache_call_env_t", + .env = (call_env_t[]) { + { FR_CALL_ENV_OFFSET("key", FR_TYPE_STRING, cache_call_env_t, key, + NULL, T_INVALID, true, false, true) }, + CALL_ENV_TERMINATOR + } +}; + static fr_dict_t const *dict_freeradius; extern fr_dict_autoload_t rlm_cache_dict[]; @@ -202,7 +216,7 @@ static rlm_rcode_t cache_merge(rlm_cache_t const *inst, request_t *request, rlm_ */ static unlang_action_t cache_find(rlm_rcode_t *p_result, rlm_cache_entry_t **out, rlm_cache_t const *inst, request_t *request, - rlm_cache_handle_t **handle, uint8_t const *key, size_t key_len) + rlm_cache_handle_t **handle, fr_value_box_t const *key) { cache_status_t ret; @@ -211,7 +225,7 @@ static unlang_action_t cache_find(rlm_rcode_t *p_result, rlm_cache_entry_t **out *out = NULL; for (;;) { - ret = inst->driver->find(&c, &inst->config, inst->driver_submodule->dl_inst->data, request, *handle, key, key_len); + ret = inst->driver->find(&c, &inst->config, inst->driver_submodule->dl_inst->data, request, *handle, key); switch (ret) { case CACHE_RECONNECT: RDEBUG2("Reconnecting..."); @@ -222,7 +236,7 @@ static unlang_action_t cache_find(rlm_rcode_t *p_result, rlm_cache_entry_t **out break; case CACHE_MISS: - RDEBUG2("No cache entry found for \"%pV\"", fr_box_strvalue_len((char const *)key, key_len)); + RDEBUG2("No cache entry found for \"%pV\"", key); RETURN_MODULE_NOTFOUND; default: @@ -239,23 +253,23 @@ static unlang_action_t cache_find(rlm_rcode_t *p_result, rlm_cache_entry_t **out */ if (fr_unix_time_lt(c->expires, fr_time_to_unix_time(request->packet->timestamp))) { RDEBUG2("Found entry for \"%pV\", but it expired %pV ago at %pV (packet received %pV). Removing it", - fr_box_strvalue_len((char const *)key, key_len), + key, fr_box_time_delta(fr_unix_time_sub(fr_time_to_unix_time(request->packet->timestamp), c->expires)), fr_box_date(c->expires), fr_box_time(request->packet->timestamp)); expired: - inst->driver->expire(&inst->config, inst->driver_submodule->dl_inst->data, request, handle, c->key, c->key_len); + inst->driver->expire(&inst->config, inst->driver_submodule->dl_inst->data, request, handle, key); cache_free(inst, &c); RETURN_MODULE_NOTFOUND; /* Couldn't find a non-expired entry */ } if (fr_unix_time_lt(c->created, fr_unix_time_from_sec(inst->config.epoch))) { RDEBUG2("Found entry for \"%pV\", but it was created before the current epoch. Removing it", - fr_box_strvalue_len((char const *)key, key_len)); + key); goto expired; } - RDEBUG2("Found entry for \"%pV\"", fr_box_strvalue_len((char const *)key, key_len)); + RDEBUG2("Found entry for \"%pV\"", key); c->hits++; *out = c; @@ -272,11 +286,10 @@ static unlang_action_t cache_find(rlm_rcode_t *p_result, rlm_cache_entry_t **out */ static unlang_action_t cache_expire(rlm_rcode_t *p_result, rlm_cache_t const *inst, request_t *request, - rlm_cache_handle_t **handle, uint8_t const *key, size_t key_len) + rlm_cache_handle_t **handle, fr_value_box_t const *key) { RDEBUG2("Expiring cache entry"); - for (;;) switch (inst->driver->expire(&inst->config, inst->driver_submodule->dl_inst->data, request, - *handle, key, key_len)) { + for (;;) switch (inst->driver->expire(&inst->config, inst->driver_submodule->dl_inst->data, request, *handle, key)) { case CACHE_RECONNECT: if (cache_reconnect(handle, inst, request) == 0) continue; FALL_THROUGH; @@ -301,7 +314,7 @@ static unlang_action_t cache_expire(rlm_rcode_t *p_result, */ static unlang_action_t cache_insert(rlm_rcode_t *p_result, rlm_cache_t const *inst, request_t *request, rlm_cache_handle_t **handle, - uint8_t const *key, size_t key_len, fr_time_delta_t ttl) + fr_value_box_t const *key, fr_time_delta_t ttl) { map_t const *map = NULL; map_t *c_map; @@ -323,8 +336,11 @@ static unlang_action_t cache_insert(rlm_rcode_t *p_result, RETURN_MODULE_FAIL; } map_list_init(&c->maps); - c->key = talloc_memdup(c, key, key_len); - c->key_len = key_len; + if (unlikely(fr_value_box_copy(c, &c->key, key) < 0)) { + RERROR("Failed copying key"); + talloc_free(c); + RETURN_MODULE_FAIL; + } /* * All in NSEC resolution @@ -540,6 +556,7 @@ static unlang_action_t CC_HINT(nonnull) mod_cache_it(rlm_rcode_t *p_result, modu { rlm_cache_entry_t *c = NULL; rlm_cache_t const *inst = talloc_get_type_abort_const(mctx->inst->data, rlm_cache_t); + cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t); rlm_cache_handle_t *handle; @@ -549,20 +566,11 @@ static unlang_action_t CC_HINT(nonnull) mod_cache_it(rlm_rcode_t *p_result, modu bool merge = true, insert = true, expire = false, set_ttl = false; int exists = -1; - uint8_t buffer[1024]; - uint8_t const *key; - ssize_t key_len; rlm_rcode_t rcode = RLM_MODULE_NOOP; fr_time_delta_t ttl = inst->config.ttl; - key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer), - request, inst->config.key, NULL, NULL); - if (key_len < 0) { - RETURN_MODULE_FAIL; - } - - if (key_len == 0) { + if (env->key->vb_length == 0) { REDEBUG("Zero length key string is invalid"); RETURN_MODULE_INVALID; } @@ -581,7 +589,7 @@ static unlang_action_t CC_HINT(nonnull) mod_cache_it(rlm_rcode_t *p_result, modu RETURN_MODULE_FAIL; } - cache_find(&rcode, &c, inst, request, &handle, key, key_len); + cache_find(&rcode, &c, inst, request, &handle, env->key); if (rcode == RLM_MODULE_FAIL) goto finish; fr_assert(!inst->driver->acquire || handle); @@ -628,7 +636,7 @@ static unlang_action_t CC_HINT(nonnull) mod_cache_it(rlm_rcode_t *p_result, modu * recording whether the entry existed. */ if (merge) { - cache_find(&rcode, &c, inst, request, &handle, key, key_len); + cache_find(&rcode, &c, inst, request, &handle, env->key); switch (rcode) { case RLM_MODULE_FAIL: goto finish; @@ -661,7 +669,7 @@ static unlang_action_t CC_HINT(nonnull) mod_cache_it(rlm_rcode_t *p_result, modu rlm_rcode_t tmp; fr_assert(!set_ttl); - cache_expire(&tmp, inst, request, &handle, key, key_len); + cache_expire(&tmp, inst, request, &handle, env->key); switch (tmp) { case RLM_MODULE_FAIL: rcode = RLM_MODULE_FAIL; @@ -693,7 +701,7 @@ static unlang_action_t CC_HINT(nonnull) mod_cache_it(rlm_rcode_t *p_result, modu if ((exists < 0) && (insert || set_ttl)) { rlm_rcode_t tmp; - cache_find(&tmp, &c, inst, request, &handle, key, key_len); + cache_find(&tmp, &c, inst, request, &handle, env->key); switch (tmp) { case RLM_MODULE_FAIL: rcode = RLM_MODULE_FAIL; @@ -749,7 +757,7 @@ static unlang_action_t CC_HINT(nonnull) mod_cache_it(rlm_rcode_t *p_result, modu if (insert && (exists == 0)) { rlm_rcode_t tmp; - cache_insert(&tmp, inst, request, &handle, key, key_len, ttl); + cache_insert(&tmp, inst, request, &handle, env->key, ttl); switch (tmp) { case RLM_MODULE_FAIL: rcode = RLM_MODULE_FAIL; @@ -818,24 +826,18 @@ xlat_action_t cache_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, { rlm_cache_entry_t *c = NULL; rlm_cache_t *inst = talloc_get_type_abort(xctx->mctx->inst->data, rlm_cache_t); + cache_call_env_t *env = talloc_get_type_abort(xctx->env_data, cache_call_env_t); rlm_cache_handle_t *handle = NULL; ssize_t slen; fr_value_box_t *attr = fr_value_box_list_head(in); - uint8_t buffer[1024]; - uint8_t const *key; - ssize_t key_len; fr_value_box_t *vb; tmpl_t *target = NULL; map_t *map = NULL; rlm_rcode_t rcode = RLM_MODULE_NOOP; - key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer), - request, inst->config.key, NULL, NULL); - if (key_len < 0) return XLAT_ACTION_FAIL; - slen = tmpl_afrom_attr_substr(ctx, NULL, &target, &FR_SBUFF_IN(attr->vb_strvalue, attr->vb_length), NULL, @@ -856,7 +858,7 @@ xlat_action_t cache_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, return XLAT_ACTION_FAIL; } - cache_find(&rcode, &c, inst, request, &handle, key, key_len); + cache_find(&rcode, &c, inst, request, &handle, env->key); switch (rcode) { case RLM_MODULE_OK: /* found */ break; @@ -929,108 +931,6 @@ static void cache_unref(request_t *request, rlm_cache_t const *inst, rlm_cache_e } } -/** Free any memory allocated under the instance - * - */ -static int mod_detach(module_detach_ctx_t const *mctx) -{ - rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t); - - /* - * We need to explicitly free all children, so if the driver - * parented any memory off the instance, their destructors - * run before we unload the bytecode for them. - * - * If we don't do this, we get a SEGV deep inside the talloc code - * when it tries to call a destructor that no longer exists. - */ - talloc_free_children(inst); - - return 0; -} - -/** Register module xlats - * - */ -static int mod_bootstrap(module_inst_ctx_t const *mctx) -{ - rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t ); - xlat_t *xlat; - - inst->driver = (rlm_cache_driver_t const *)inst->driver_submodule->dl_inst->module->common; - - /* - * Non optional fields and callbacks - */ - fr_assert(inst->driver->common.name); - fr_assert(inst->driver->find); - fr_assert(inst->driver->insert); - fr_assert(inst->driver->expire); - - /* - * Register the cache xlat function - */ - xlat = xlat_func_register_module(inst, mctx, mctx->inst->name, cache_xlat, FR_TYPE_VOID); - xlat_func_args_set(xlat, cache_xlat_args); - - return 0; -} - -/** Create a new rlm_cache_instance - * - */ -static int mod_instantiate(module_inst_ctx_t const *mctx) -{ - rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t); - CONF_SECTION *conf = mctx->inst->conf; - CONF_SECTION *update; - - fr_assert(inst->config.key); - - if (!fr_time_delta_ispos(inst->config.ttl)) { - cf_log_err(conf, "Must set 'ttl' to non-zero"); - return -1; - } - - if (inst->config.epoch != 0) { - cf_log_err(conf, "Must not set 'epoch' in the configuration files"); - return -1; - } - - update = cf_section_find(conf, "update", CF_IDENT_ANY); - if (!update) { - cf_log_err(conf, "Must have an 'update' section in order to cache anything"); - return -1; - } - - /* - * Make sure the users don't screw up too badly. - */ - { - tmpl_rules_t parse_rules = { - .attr = { - .list_def = request_attr_request, - .allow_wildcard = true, - .allow_foreign = true /* Because we don't know where we'll be called */ - } - }; - - map_list_init(&inst->maps); - if (map_afrom_cs(inst, &inst->maps, update, - &parse_rules, &parse_rules, cache_verify, inst, MAX_ATTRMAP) < 0) { - return -1; - } - } - - if (map_list_empty(&inst->maps)) { - cf_log_err(conf, "Cache config must contain an update section, and " - "that section must not be empty"); - return -1; - } - - return 0; -} - /** Get the status by ${key} (without load) * * @return @@ -1041,22 +941,14 @@ static int mod_instantiate(module_inst_ctx_t const *mctx) static unlang_action_t CC_HINT(nonnull) mod_method_status(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) { rlm_cache_t const *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t); + cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t); rlm_rcode_t rcode = RLM_MODULE_NOOP; - uint8_t buffer[1024]; - uint8_t const *key; - ssize_t key_len; rlm_cache_entry_t *entry = NULL; rlm_cache_handle_t *handle = NULL; DEBUG3("Calling %s.status", mctx->inst->name); - key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer), - request, inst->config.key, NULL, NULL); - if (key_len < 0) { - RETURN_MODULE_FAIL; - } - - if (key_len == 0) { + if (env->key->vb_length == 0) { REDEBUG("Zero length key string is invalid"); RETURN_MODULE_FAIL; } @@ -1068,7 +960,7 @@ static unlang_action_t CC_HINT(nonnull) mod_method_status(rlm_rcode_t *p_result, fr_assert(!inst->driver->acquire || handle); - cache_find(&rcode, &entry, inst, request, &handle, key, key_len); + cache_find(&rcode, &entry, inst, request, &handle, env->key); if (rcode == RLM_MODULE_FAIL) goto finish; rcode = (entry) ? RLM_MODULE_OK : RLM_MODULE_NOTFOUND; @@ -1089,22 +981,14 @@ finish: static unlang_action_t CC_HINT(nonnull) mod_method_load(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) { rlm_cache_t const *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t); + cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t); rlm_rcode_t rcode = RLM_MODULE_NOOP; - uint8_t buffer[1024]; - uint8_t const *key; - ssize_t key_len; rlm_cache_entry_t *entry = NULL; rlm_cache_handle_t *handle = NULL; DEBUG3("Calling %s.load", mctx->inst->name); - key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer), - request, inst->config.key, NULL, NULL); - if (key_len < 0) { - RETURN_MODULE_FAIL; - } - - if (key_len == 0) { + if (env->key->vb_length == 0) { REDEBUG("Zero length key string is invalid"); RETURN_MODULE_FAIL; } @@ -1114,7 +998,7 @@ static unlang_action_t CC_HINT(nonnull) mod_method_load(rlm_rcode_t *p_result, m RETURN_MODULE_FAIL; } - cache_find(&rcode, &entry, inst, request, &handle, key, key_len); + cache_find(&rcode, &entry, inst, request, &handle, env->key); if (rcode == RLM_MODULE_FAIL) goto finish; if (!entry) { @@ -1141,10 +1025,8 @@ finish: static unlang_action_t CC_HINT(nonnull) mod_method_store(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) { rlm_cache_t const *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t); + cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t); rlm_rcode_t rcode = RLM_MODULE_NOOP; - uint8_t buffer[1024]; - uint8_t const *key; - ssize_t key_len; fr_time_delta_t ttl; bool expire = false; rlm_cache_entry_t *entry = NULL; @@ -1153,13 +1035,7 @@ static unlang_action_t CC_HINT(nonnull) mod_method_store(rlm_rcode_t *p_result, DEBUG3("Calling %s.store", mctx->inst->name); - key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer), - request, inst->config.key, NULL, NULL); - if (key_len < 0) { - RETURN_MODULE_FAIL; - } - - if (key_len == 0) { + if (env->key->vb_length == 0) { REDEBUG("Zero length key string is invalid"); RETURN_MODULE_FAIL; } @@ -1188,7 +1064,7 @@ static unlang_action_t CC_HINT(nonnull) mod_method_store(rlm_rcode_t *p_result, /* * We can only alter the TTL on an entry if it exists. */ - cache_find(&rcode, &entry, inst, request, &handle, key, key_len); + cache_find(&rcode, &entry, inst, request, &handle, env->key); if (rcode == RLM_MODULE_FAIL) goto finish; if (rcode == RLM_MODULE_OK) { @@ -1212,7 +1088,7 @@ static unlang_action_t CC_HINT(nonnull) mod_method_store(rlm_rcode_t *p_result, if (expire) { DEBUG4("Set the cache expire"); - cache_expire(&rcode, inst, request, &handle, key, key_len); + cache_expire(&rcode, inst, request, &handle, env->key); if (rcode == RLM_MODULE_FAIL) goto finish; } @@ -1222,7 +1098,7 @@ static unlang_action_t CC_HINT(nonnull) mod_method_store(rlm_rcode_t *p_result, * setting the TTL, which precludes performing an * insert. */ - cache_insert(&rcode, inst, request, &handle, key, key_len, ttl); + cache_insert(&rcode, inst, request, &handle, env->key, ttl); if (rcode == RLM_MODULE_OK) rcode = RLM_MODULE_UPDATED; finish: @@ -1241,22 +1117,14 @@ finish: static unlang_action_t CC_HINT(nonnull) mod_method_clear(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) { rlm_cache_t const *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t); + cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t); rlm_rcode_t rcode = RLM_MODULE_NOOP; - uint8_t buffer[1024]; - uint8_t const *key; - ssize_t key_len; rlm_cache_entry_t *entry = NULL; rlm_cache_handle_t *handle = NULL; DEBUG3("Calling %s.clear", mctx->inst->name); - key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer), - request, inst->config.key, NULL, NULL); - if (key_len < 0) { - RETURN_MODULE_FAIL; - } - - if (key_len == 0) { + if (env->key->vb_length == 0) { REDEBUG("Zero length key string is invalid"); RETURN_MODULE_FAIL; } @@ -1266,7 +1134,7 @@ static unlang_action_t CC_HINT(nonnull) mod_method_clear(rlm_rcode_t *p_result, RETURN_MODULE_FAIL; } - cache_find(&rcode, &entry, inst, request, &handle, key, key_len); + cache_find(&rcode, &entry, inst, request, &handle, env->key); if (rcode == RLM_MODULE_FAIL) goto finish; if (!entry) { @@ -1275,7 +1143,7 @@ static unlang_action_t CC_HINT(nonnull) mod_method_clear(rlm_rcode_t *p_result, goto finish; } - cache_expire(&rcode, inst, request, &handle, key, key_len); + cache_expire(&rcode, inst, request, &handle, env->key); finish: cache_unref(request, inst, entry, handle); @@ -1293,10 +1161,8 @@ finish: static unlang_action_t CC_HINT(nonnull) mod_method_ttl(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) { rlm_cache_t const *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t); + cache_call_env_t *env = talloc_get_type_abort(mctx->env_data, cache_call_env_t); rlm_rcode_t rcode = RLM_MODULE_NOOP; - uint8_t buffer[1024]; - uint8_t const *key; - ssize_t key_len; fr_time_delta_t ttl; rlm_cache_entry_t *entry = NULL; rlm_cache_handle_t *handle = NULL; @@ -1304,13 +1170,7 @@ static unlang_action_t CC_HINT(nonnull) mod_method_ttl(rlm_rcode_t *p_result, mo DEBUG3("Calling %s.ttl", mctx->inst->name); - key_len = tmpl_expand((char const **)&key, (char *)buffer, sizeof(buffer), - request, inst->config.key, NULL, NULL); - if (key_len < 0) { - RETURN_MODULE_FAIL; - } - - if (key_len == 0) { + if (env->key->vb_length == 0) { REDEBUG("Zero length key string is invalid"); RETURN_MODULE_FAIL; } @@ -1337,7 +1197,7 @@ static unlang_action_t CC_HINT(nonnull) mod_method_ttl(rlm_rcode_t *p_result, mo /* * We can only alter the TTL on an entry if it exists. */ - cache_find(&rcode, &entry, inst, request, &handle, key, key_len); + cache_find(&rcode, &entry, inst, request, &handle, env->key); if (rcode == RLM_MODULE_FAIL) goto finish; if (rcode == RLM_MODULE_OK) { @@ -1359,6 +1219,107 @@ finish: RETURN_MODULE_RCODE(rcode); } +/** Free any memory allocated under the instance + * + */ +static int mod_detach(module_detach_ctx_t const *mctx) +{ + rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t); + + /* + * We need to explicitly free all children, so if the driver + * parented any memory off the instance, their destructors + * run before we unload the bytecode for them. + * + * If we don't do this, we get a SEGV deep inside the talloc code + * when it tries to call a destructor that no longer exists. + */ + talloc_free_children(inst); + + return 0; +} + +/** Create a new rlm_cache_instance + * + */ +static int mod_instantiate(module_inst_ctx_t const *mctx) +{ + rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t); + CONF_SECTION *conf = mctx->inst->conf; + CONF_SECTION *update; + + if (!fr_time_delta_ispos(inst->config.ttl)) { + cf_log_err(conf, "Must set 'ttl' to non-zero"); + return -1; + } + + if (inst->config.epoch != 0) { + cf_log_err(conf, "Must not set 'epoch' in the configuration files"); + return -1; + } + + update = cf_section_find(conf, "update", CF_IDENT_ANY); + if (!update) { + cf_log_err(conf, "Must have an 'update' section in order to cache anything"); + return -1; + } + + /* + * Make sure the users don't screw up too badly. + */ + { + tmpl_rules_t parse_rules = { + .attr = { + .list_def = request_attr_request, + .allow_wildcard = true, + .allow_foreign = true /* Because we don't know where we'll be called */ + } + }; + + map_list_init(&inst->maps); + if (map_afrom_cs(inst, &inst->maps, update, + &parse_rules, &parse_rules, cache_verify, inst, MAX_ATTRMAP) < 0) { + return -1; + } + } + + if (map_list_empty(&inst->maps)) { + cf_log_err(conf, "Cache config must contain an update section, and " + "that section must not be empty"); + return -1; + } + + return 0; +} + +/** Register module xlats + * + */ +static int mod_bootstrap(module_inst_ctx_t const *mctx) +{ + rlm_cache_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_cache_t ); + xlat_t *xlat; + + inst->driver = (rlm_cache_driver_t const *)inst->driver_submodule->dl_inst->module->common; + + /* + * Non optional fields and callbacks + */ + fr_assert(inst->driver->common.name); + fr_assert(inst->driver->find); + fr_assert(inst->driver->insert); + fr_assert(inst->driver->expire); + + /* + * Register the cache xlat function + */ + xlat = xlat_func_register_module(inst, mctx, mctx->inst->name, cache_xlat, FR_TYPE_VOID); + xlat_func_args_set(xlat, cache_xlat_args); + xlat_func_call_env_set(xlat, &cache_common_env); + + return 0; +} + /* * The module name should be the only globally exported symbol. * That is, everything else should be 'static'. @@ -1379,12 +1340,12 @@ module_rlm_t rlm_cache = { .detach = mod_detach }, .method_names = (module_method_name_t[]){ - { .name1 = "status", .name2 = CF_IDENT_ANY, .method = mod_method_status }, - { .name1 = "load", .name2 = CF_IDENT_ANY, .method = mod_method_load }, - { .name1 = "store", .name2 = CF_IDENT_ANY, .method = mod_method_store }, - { .name1 = "clear", .name2 = CF_IDENT_ANY, .method = mod_method_clear }, - { .name1 = "ttl", .name2 = CF_IDENT_ANY, .method = mod_method_ttl }, - { .name1 = CF_IDENT_ANY, .name2 = CF_IDENT_ANY, .method = mod_cache_it }, + { .name1 = "status", .name2 = CF_IDENT_ANY, .method = mod_method_status, .method_env = &cache_common_env }, + { .name1 = "load", .name2 = CF_IDENT_ANY, .method = mod_method_load, .method_env = &cache_common_env }, + { .name1 = "store", .name2 = CF_IDENT_ANY, .method = mod_method_store, .method_env = &cache_common_env }, + { .name1 = "clear", .name2 = CF_IDENT_ANY, .method = mod_method_clear, .method_env = &cache_common_env }, + { .name1 = "ttl", .name2 = CF_IDENT_ANY, .method = mod_method_ttl, .method_env = &cache_common_env }, + { .name1 = CF_IDENT_ANY, .name2 = CF_IDENT_ANY, .method = mod_cache_it, .method_env = &cache_common_env }, MODULE_NAME_TERMINATOR } }; diff --git a/src/modules/rlm_cache/rlm_cache.h b/src/modules/rlm_cache/rlm_cache.h index 7a64da577ef..3802cbc59a0 100644 --- a/src/modules/rlm_cache/rlm_cache.h +++ b/src/modules/rlm_cache/rlm_cache.h @@ -49,7 +49,6 @@ typedef enum { * rlm_cache instance data. */ typedef struct { - tmpl_t *key; //!< What to expand to get the value of the key. fr_time_delta_t ttl; //!< How long an entry is valid for. uint32_t max_entries; //!< Maximum entries allowed. int32_t epoch; //!< Time after which entries are considered valid. @@ -74,8 +73,7 @@ typedef struct { } rlm_cache_t; typedef struct { - uint8_t const *key; //!< Key used to identify entry. - size_t key_len; //!< Length of key data. + fr_value_box_t key; //!< Key used to identify entry. long long int hits; //!< How many times the entry has been retrieved. fr_unix_time_t created; //!< When the entry was created. fr_unix_time_t expires; //!< When the entry expires. @@ -117,7 +115,6 @@ typedef void (*cache_entry_free_t)(rlm_cache_entry_t *c); * @param[in] handle the driver gave us when we called #cache_acquire_t, or NULL if no * #cache_acquire_t callback was provided. * @param[in] key to use to lookup cache entry - * @param[in] key_len the length of the key string. * @return * - #CACHE_RECONNECT - If handle needs to be reinitialised/reconnected. * - #CACHE_ERROR - If the lookup couldn't be completed. @@ -126,7 +123,7 @@ typedef void (*cache_entry_free_t)(rlm_cache_entry_t *c); */ typedef cache_status_t (*cache_entry_find_t)(rlm_cache_entry_t **out, rlm_cache_config_t const *config, void *instance, request_t *request, void *handle, - uint8_t const *key, size_t key_len); + fr_value_box_t const *key); /** Insert an entry into the cache * @@ -169,7 +166,6 @@ typedef cache_status_t (*cache_entry_insert_t)(rlm_cache_config_t const *config, * @param[in] handle the driver gave us when we called #cache_acquire_t, or NULL if no * #cache_acquire_t callback was provided. * @param[in] key of entry to expire. - * @param[in] key_len the length of the key string. * @return * - #CACHE_RECONNECT - If handle needs to be reinitialised/reconnected. * - #CACHE_ERROR - If the entry couldn't be expired. @@ -178,7 +174,7 @@ typedef cache_status_t (*cache_entry_insert_t)(rlm_cache_config_t const *config, */ typedef cache_status_t (*cache_entry_expire_t)(rlm_cache_config_t const *config, void *instance, request_t *request, void *handle, - uint8_t const *key, size_t key_len); + fr_value_box_t const *key); /** Update the ttl of an entry in the cace *