]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
cache: Move key resolution to callenv
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 14 Nov 2023 01:05:40 +0000 (19:05 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 14 Nov 2023 01:05:40 +0000 (19:05 -0600)
...weird intractable problems trying to get an old DHCPv4 config, easier to fix the code than debug it.

src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c
src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c
src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c
src/modules/rlm_cache/rlm_cache.c
src/modules/rlm_cache/rlm_cache.h

index 57026db1c481c1d4b36693a4e98f27b523bf4eef..c43da55b46317a2f9221929a672f8121cfe4532a 100644 (file)
@@ -29,6 +29,7 @@
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/module_rlm.h>
 #include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/value.h>
 
 #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;
index a03ece0fa03f6745e14f0fe922e1075577863962..4838e824d1fc721f0f4f478f972840bcb0898121 100644 (file)
@@ -24,6 +24,7 @@
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/util/heap.h>
 #include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/value.h>
 #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)) {
index ed37b6b26d41654f57fb3e0f7ccd79a01768db8d..d24a559aea2abc5f4ffcc792bc4e07b760178172 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/util/debug.h>
+#include <freeradius-devel/util/value.h>
 
 #include "../../rlm_cache.h"
 #include <freeradius-devel/redis/base.h>
@@ -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);
        }
 
index 364281174f56a9ce92d6fd39bbc3227220b98221..87c5be03690fed636a2f0ef349b1c1e6dfb8b3ac 100644 (file)
@@ -29,6 +29,7 @@ RCSID("$Id$")
 #include <freeradius-devel/server/module_rlm.h>
 #include <freeradius-devel/server/modpriv.h>
 #include <freeradius-devel/server/dl_module.h>
+#include <freeradius-devel/server/rcode.h>
 #include <freeradius-devel/util/debug.h>
 #include <freeradius-devel/unlang/xlat_func.h>
 
@@ -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
        }
 };
index 7a64da577efaf79e6b5feae083d98bddb190ffa1..3802cbc59a04a0008389901c23d66fd101c71fce 100644 (file)
@@ -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
  *