24 RCSID(
"$Id: e856bf912afe470b43e46a6472460fdd1de18c83 $")
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/modpriv.h>
29 #include <freeradius-devel/modcall.h>
30 #include <freeradius-devel/rad_assert.h>
71 if (!handle || !*handle)
return;
137 RDEBUG2(
"Merging cache entry into request");
139 for (map = c->
maps; map; map = map->
next) {
151 RDEBUG(
"Skipping %s", buffer);
167 vp->vp_integer = c->
hits;
195 RDEBUG(
"Reconnecting...");
206 p =
fr_asprint(request, (
char const *)key, key_len,
'"');
207 RDEBUG(
"No cache entry found for \"%s\"", p);
229 p =
fr_asprint(request, (
char const *)key, key_len,
'"');
230 RDEBUG2(
"Found entry for \"%s\", but it expired %li seconds ago. Removing it", p,
243 p =
fr_asprint(request, (
char const *)key, key_len,
'"');
244 RDEBUG2(
"Found entry for \"%s\"", p);
264 RDEBUG(
"Expiring cache entry");
266 *handle, key, key_len)) {
290 uint8_t
const *key,
size_t key_len,
int ttl)
311 c->
key = talloc_memdup(c, key, key_len);
318 RDEBUG(
"Creating new cache entry");
324 pool = talloc_pool(NULL, 1024);
325 for (map = inst->
maps; map != NULL; map = map->
next) {
335 if (
map_to_vp(pool, &to_cache, request, map, NULL) < 0) {
349 case PW_CACHE_STATUS_ONLY:
350 case PW_CACHE_READ_ONLY:
352 case PW_CACHE_ENTRY_HITS:
382 REDEBUG(
"Failed copying attribute value");
388 c_map->
rhs->tmpl_data_type = vp->
da->
type;
405 c_map->
lhs->tmpl_da = vp->
da;
406 c_map->
lhs->tmpl_tag = vp->
tag;
407 c_map->
lhs->tmpl_list = map->
lhs->tmpl_list;
408 c_map->
lhs->tmpl_num = map->
lhs->tmpl_num;
409 c_map->
lhs->tmpl_request = map->
lhs->tmpl_request;
417 REDEBUG(
"Serialized attribute too long. Must be < "
418 STRINGIFY(
sizeof(attr))
" bytes, got %zu bytes", len);
422 c_map->
lhs->
name = talloc_strdup(map->
lhs, attr);
430 last = &(*last)->
next;
432 talloc_free_children(pool);
440 if (vp && (vp->vp_integer > 0)) merge =
true;
454 RDEBUG(
"Committed entry, TTL %d seconds", ttl);
488 RDEBUG(
"Updated entry TTL");
510 RDEBUG(
"Updated entry TTL");
528 cf_log_err(map->
ci,
"Destination must be an attribute ref or a list");
554 bool merge =
true, insert =
true, expire =
false, set_ttl =
false;
557 uint8_t buffer[1024];
564 key_len =
tmpl_expand((
char const **)&key, (
char *)buffer,
sizeof(buffer),
569 REDEBUG(
"Zero length key string is invalid");
578 if (vp && vp->vp_integer) {
581 rcode =
cache_find(&c, inst, request, &handle, key, key_len);
594 if (vp) merge = (bool)vp->vp_integer;
597 if (vp) insert = (bool)vp->vp_integer;
601 if (vp->vp_signed == 0) {
603 }
else if (vp->vp_signed < 0) {
605 ttl = -(vp->vp_signed);
620 rcode =
cache_find(&c, inst, request, &handle, key, key_len);
648 if (expire && ((exists == -1) || (exists == 1))) {
651 switch (
cache_expire(inst, request, &handle, key, key_len)) {
679 if ((exists < 0) && (insert || set_ttl)) {
680 switch (
cache_find(&c, inst, request, &handle, key, key_len)) {
703 if (set_ttl && (exists == 1)) {
729 if (insert && (exists == 0)) {
730 switch (
cache_insert(inst, request, &handle, key, key_len, ttl)) {
763 case PW_CACHE_STATUS_ONLY:
764 case PW_CACHE_ALLOW_MERGE:
765 case PW_CACHE_ALLOW_INSERT:
781 void const *mod_inst,
UNUSED void const *xlat_inst,
784 void const *mod_inst,
UNUSED void const *xlat_inst,
785 REQUEST *request,
char const *fmt)
794 uint8_t buffer[1024];
801 key_len =
tmpl_expand((
char const **)&key, (
char *)buffer,
sizeof(buffer),
803 if (key_len < 0)
return -1;
811 if (
cache_acquire(&handle, mod_inst, request) < 0)
return -1;
813 switch (
cache_find(&c, mod_inst, request, handle, key, key_len)) {
824 for (map = c->
maps; map; map = map->
next) {
825 if ((map->
lhs->tmpl_da != target.tmpl_da) ||
826 (map->
lhs->tmpl_tag != target.tmpl_tag) ||
827 (map->
lhs->tmpl_list != target.tmpl_list))
continue;
830 &map->
rhs->tmpl_data_value,
'\0');
831 ret = talloc_array_length(*out) - 1;
853 talloc_free(inst->
maps);
863 talloc_free_children(inst);
920 cf_log_err_cs(conf,
"Make sure it (and all its dependent libraries!) are in the search path"
921 " of your system's ld");
975 cf_log_err_cs(conf,
"Must not set 'epoch' in the configuration files");
981 cf_log_err_cs(conf,
"Must have an 'update' section in order to cache anything.");
994 cf_log_err_cs(inst->
cs,
"Cache config must contain an update section, and "
995 "that section must not be empty");
1016 .config = module_config,
size_t map_snprint(char *out, size_t outlen, vp_map_t const *map)
Print a map to a string.
5 methods index for preproxy section.
static void cache_free(rlm_cache_t const *inst, rlm_cache_entry_t **c)
Free memory associated with a cache entry.
ssize_t tmpl_expand(char const **out, char *buff, size_t outlen, REQUEST *request, vp_tmpl_t const *vpt, xlat_escape_t escape, void *escape_ctx)
Expand a vp_tmpl_t to a string writing the result to a buffer.
static int cache_verify(vp_map_t *map, void *ctx)
Verify that a map in the cache section makes sense.
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
void map_debug_log(REQUEST *request, vp_map_t const *map, VALUE_PAIR const *vp) CC_HINT(nonnull(1
#define RINDENT()
Indent R* messages by one level.
int int map_to_request(REQUEST *request, vp_map_t const *map, radius_map_getvalue_t func, void *ctx)
Convert vp_map_t to VALUE_PAIR (s) and add them to a REQUEST.
cache_driver_t * driver
Driver.
int xlat_register(void *mod_inst, char const *name, xlat_func_t func, xlat_escape_t escape, xlat_instantiate_t instantiate, size_t inst_size, size_t buf_len)
Register an xlat function.
The module is OK, continue.
Metadata exported by the module.
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
#define RDEBUG_ENABLED2
True if request debug level 1-2 messages are enabled.
char const * name
Raw string used to create the template.
lt_dlhandle lt_dlopenext(char const *name)
vp_tmpl_t * lhs
Typically describes the attribute to add, modify or compare.
static const CONF_PARSER module_config[]
7 methods index for postauth section.
cache_acquire_t acquire
(optional) Acquire exclusive access to a resource used to retrieve the cache entry.
vp_tmpl_t * rhs
Typically describes a literal value or a src attribute to copy or compare.
cache_entry_insert_t insert
Add a new entry.
cache_reconnect_t reconnect
(optional) Re-initialise resource.
ssize_t tmpl_from_attr_substr(vp_tmpl_t *vpt, char const *name, request_refs_t request_def, pair_lists_t list_def, bool allow_unknown, bool allow_undefined)
Parse a string into a TMPL_TYPE_ATTR_* or TMPL_TYPE_LIST type vp_tmpl_t.
int8_t tag
Tag value used to group valuepairs.
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
#define CONF_PARSER_TERMINATOR
vp_tmpl_t * key
What to expand to get the value of the key.
int32_t epoch
Time after which entries are considered valid.
uint32_t max_entries
Maximum entries allowed.
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
struct rlm_cache_t rlm_cache_t
Handle needs to be reconnected.
static int cache_reconnect(rlm_cache_handle_t **handle, rlm_cache_t const *inst, REQUEST *request)
Reconnect an suspected inviable handle.
The module considers the request invalid.
rlm_cache_config_t config
Must come first because of icky hacks.
uint32_t ttl
How long an entry is valid for.
bool stats
Generate statistics.
static rlm_rcode_t mod_cache_it(void *instance, REQUEST *request) CC_HINT(nonnull)
Do caching checks.
Defines a CONF_PAIR to C data type mapping.
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
struct vp_map * next
The next valuepair map.
static void cache_release(rlm_cache_t const *inst, REQUEST *request, rlm_cache_handle_t **handle)
Release a handle we previously acquired.
#define is_truncated(_ret, _max)
cache_release_t release
(optional) Release access to resource acquired with acquire callback.
size_t key_len
Length of key data.
int map_afrom_cs(vp_map_t **out, CONF_SECTION *cs, pair_lists_t dst_list_def, pair_lists_t src_list_def, map_validate_t validate, void *ctx, unsigned int max) CC_HINT(nonnull(1
time_t expires
When the entry expires.
bool is_printable(void const *value, size_t len)
Check whether the string is made up of printable UTF8 chars.
static int cache_acquire(rlm_cache_handle_t **out, rlm_cache_t const *inst, REQUEST *request)
Get exclusive use of a handle to access the cache.
static rlm_cache_entry_t * cache_alloc(rlm_cache_t const *inst, REQUEST *request)
Allocate a cache entry.
static rlm_rcode_t cache_merge(rlm_cache_t const *inst, REQUEST *request, rlm_cache_entry_t *c) CC_HINT(nonnull)
Merge a cached entry into a REQUEST.
cache_entry_alloc_t alloc
(optional) Allocate a new entry.
vp_map_t * maps
Attribute map applied to users.
cache_entry_free_t free
(optional) Free memory used by an entry.
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
unsigned int attr
Attribute number.
Attributes in incoming or internally proxied request.
long long int hits
How many times the entry has been retrieved.
static rlm_rcode_t cache_expire(rlm_cache_t const *inst, REQUEST *request, rlm_cache_handle_t **handle, uint8_t const *key, size_t key_len)
Expire a cache entry (removing it from the datastore)
3 methods index for accounting section.
unsigned int vendor
Vendor that defines this attribute.
Stores an attribute, a value and various bits of other data.
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
#define REXDENT()
Exdent (unindent) R* messages by one level.
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
tmpl_type_t type
What type of value tmpl refers to.
cache_entry_set_ttl_t set_ttl
(Optional) Update the TTL of an entry.
char const * fr_strerror(void)
Get the last library error.
time_t created
When the entry was created.
size_t len
Length of the raw string used to create the template.
static rlm_rcode_t cache_insert(rlm_cache_t const *inst, REQUEST *request, rlm_cache_handle_t **handle, uint8_t const *key, size_t key_len, int ttl)
Create and insert a cache entry.
CONF_SECTION * cf_section_sub_find(CONF_SECTION const *, char const *name)
Find a sub-section in a section.
cache_entry_expire_t expire
Remove an old entry.
int value_data_copy(TALLOC_CTX *ctx, value_data_t *dst, PW_TYPE type, const value_data_t *src)
Copy value data verbatim duplicating any buffers.
char const * cf_section_name1(CONF_SECTION const *cs)
vp_tmpl_t * tmpl_init(vp_tmpl_t *vpt, tmpl_type_t type, char const *name, ssize_t len, FR_TOKEN quote)
Initialise stack allocated vp_tmpl_t.
Module succeeded without doing anything.
cache_entry_count_t count
(Optional) Number of entries currently in the cache.
char name[1]
Attribute name.
uint64_t magic
Used to validate module struct.
Module failed, don't reply.
void cf_log_err(CONF_ITEM const *ci, char const *fmt,...) CC_HINT(format(printf
FR_TOKEN op
The operator that controls insertion of the dst attribute.
Cache entry found/updated.
int modcall_fixup_update(vp_map_t *map, void *ctx)
struct timeval timestamp
When we started processing the request.
#define FR_CONF_OFFSET(_n, _t, _s, _f)
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
static rlm_rcode_t cache_set_ttl(rlm_cache_t const *inst, REQUEST *request, rlm_cache_handle_t **handle, rlm_cache_entry_t *c)
Update the TTL of an entry.
char const * name
Name of xlat function to register.
char * fr_asprint(TALLOC_CTX *ctx, char const *in, ssize_t inlen, char quote)
Escape string that may contain binary data, and write it to a new buffer.
size_t tmpl_snprint(char *buffer, size_t bufsize, vp_tmpl_t const *vpt, fr_dict_attr_t const *values)
Print a vp_tmpl_t to a string.
char const * driver_name
Driver name.
RADIUS_PACKET * packet
Incoming request.
CONF_SECTION * cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2)
Allocate a CONF_SECTION.
void * handle
Driver handle.
void * driver_inst
Driver instance data.
int map_to_vp(TALLOC_CTX *ctx, VALUE_PAIR **out, REQUEST *request, vp_map_t const *map, void *uctx) CC_HINT(nonnull(2
6 methods index for postproxy section.
2 methods index for preacct section.
#define PW_TYPE_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
VALUE_PAIR * fr_cursor_remove(vp_cursor_t *cursor)
Remove the current pair.
static rlm_rcode_t cache_find(rlm_cache_entry_t **out, rlm_cache_t const *inst, REQUEST *request, rlm_cache_handle_t **handle, uint8_t const *key, size_t key_len)
Find a cached entry.
cache_entry_find_t find
Retrieve an existing cache entry.
cache_instantiate_t instantiate
(optional) Instantiate a driver.
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
static int mod_detach(void *instance)
Free any memory allocated under the instance.
vp_map_t * maps
Head of the maps list.
String of printable characters.
char const * name
Driver name.
FR_TOKEN quote
What type of quoting was around the raw string.
#define PW_TYPE_TMPL
CONF_PAIR should be parsed as a template.
1 methods index for authorize section.
size_t inst_size
How many bytes should be allocated for the driver's instance data.
static int mod_instantiate(CONF_SECTION *conf, void *instance)
Create a new rlm_cache_instance.
uint8_t const * key
Key used to identify entry.
A source or sink of value data.
char * value_data_asprint(TALLOC_CTX *ctx, PW_TYPE type, fr_dict_attr_t const *enumv, value_data_t const *data, char quote)
Print one attribute value to a string.
static int mod_bootstrap(CONF_SECTION *conf, void *instance)
Register module xlats.
CONF_ITEM * ci
Config item that the map was created from.
char const * cf_section_name2(CONF_SECTION const *cs)
static ssize_t cache_xlat(char **out, UNUSED size_t freespace, void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt) CC_HINT(nonnull)
Allow single attribute values to be retrieved from the cache.
Configuration for the rlm_cache module.