Rename lt_* to fr_*. Fixes #1277
[freeradius.git] / src / modules / rlm_cache / rlm_cache.c
1 /*
2  *   This program is is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or (at
5  *   your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15  */
16
17 /**
18  * $Id$
19  * @file rlm_cache.c
20  * @brief Cache values and merge them back into future requests.
21  *
22  * @copyright 2012-2014 The FreeRADIUS server project
23  */
24 RCSID("$Id$")
25
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>
31
32 #include "rlm_cache.h"
33
34 /*
35  *      A mapping of configuration file names to internal variables.
36  *
37  *      Note that the string is dynamically allocated, so it MUST
38  *      be freed.  When the configuration file parse re-reads the string,
39  *      it free's the old one, and strdup's the new one, placing the pointer
40  *      to the strdup'd string into 'config.string'.  This gets around
41  *      buffer over-flows.
42  */
43 static const CONF_PARSER module_config[] = {
44         { "driver", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_cache_t, driver_name), "rlm_cache_rbtree" },
45         { "key", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_REQUIRED | PW_TYPE_XLAT, rlm_cache_t, key), NULL },
46         { "ttl", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_cache_t, ttl), "500" },
47         { "max_entries", FR_CONF_OFFSET(PW_TYPE_INTEGER, rlm_cache_t, max_entries), "0" },
48
49         /* Should be a type which matches time_t, @fixme before 2038 */
50         { "epoch", FR_CONF_OFFSET(PW_TYPE_SIGNED, rlm_cache_t, epoch), "0" },
51         { "add_stats", FR_CONF_OFFSET(PW_TYPE_BOOLEAN, rlm_cache_t, stats), "no" },
52         CONF_PARSER_TERMINATOR
53 };
54
55 static int cache_acquire(rlm_cache_handle_t **out, rlm_cache_t *inst, REQUEST *request)
56 {
57         if (!inst->module->acquire) return 0;
58
59         return inst->module->acquire(out, inst, request);
60 }
61
62 static void cache_release(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle)
63 {
64         if (!inst->module->release) return;
65         if (!handle || !*handle) return;
66
67         inst->module->release(inst, request, handle);
68 }
69
70 static int cache_reconnect(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle)
71 {
72         rad_assert(inst->module->reconnect);
73
74         return inst->module->reconnect(inst, request, handle);
75 }
76
77 /** Allocate a cache entry
78  *
79  *  This is used so that drivers may use their own allocation functions
80  *  to allocate structures larger than the normal rlm_cache_entry_t.
81  *
82  *  If the driver doesn't specify a custom allocation function, the cache
83  *  entry is talloced in the NULL ctx.
84  */
85 static rlm_cache_entry_t *cache_alloc(rlm_cache_t *inst, REQUEST *request)
86 {
87         if (inst->module->alloc) return inst->module->alloc(inst, request);
88
89         return talloc_zero(NULL, rlm_cache_entry_t);
90 }
91
92 /** Free memory associated with a cache entry
93  *
94  * This does not necessarily remove the entry from the cache, cache_expire
95  * should be used for that.
96  *
97  * This function should be called when an entry that is known to have been
98  * retrieved or inserted into a data store successfully, is no longer needed.
99  *
100  * Some drivers (like rlm_cache_rbtree) don't register a free function.
101  * This means that the cache entry never needs to be explicitly freed.
102  *
103  * @param c Cache entry to free.
104  * @param inst Module instance.
105  */
106 static void cache_free(rlm_cache_t *inst, rlm_cache_entry_t **c)
107 {
108         if (!c || !*c || !inst->module->free) return;
109
110         inst->module->free(*c);
111         *c = NULL;
112 }
113
114 /*
115  *      Merge a cached entry into a REQUEST.
116  */
117 static void CC_HINT(nonnull) cache_merge(rlm_cache_t *inst, REQUEST *request, rlm_cache_entry_t *c)
118 {
119         VALUE_PAIR *vp;
120
121         vp = fr_pair_find_by_num(request->config, PW_CACHE_MERGE, 0, TAG_ANY);
122         if (vp && (vp->vp_integer == 0)) {
123                 RDEBUG2("Told not to merge entry into request");
124                 return;
125         }
126
127         RDEBUG2("Merging cache entry into request");
128
129         if (c->packet && request->packet) {
130                 rdebug_pair_list(L_DBG_LVL_2, request, c->packet, "&request:");
131                 radius_pairmove(request, &request->packet->vps, fr_pair_list_copy(request->packet, c->packet), false);
132         }
133
134         if (c->reply && request->reply) {
135                 rdebug_pair_list(L_DBG_LVL_2, request, c->reply, "&reply:");
136                 radius_pairmove(request, &request->reply->vps, fr_pair_list_copy(request->reply, c->reply), false);
137         }
138
139         if (c->control) {
140                 rdebug_pair_list(L_DBG_LVL_2, request, c->control, "&control:");
141                 radius_pairmove(request, &request->config, fr_pair_list_copy(request, c->control), false);
142         }
143
144         if (c->state) {
145                 rdebug_pair_list(L_DBG_LVL_2, request, c->state, "&session-state:");
146
147                 fr_pair_list_mcopy_by_num(request->state_ctx, &request->state, &c->state, 0, 0, TAG_ANY);
148         }
149
150         if (inst->stats) {
151                 rad_assert(request->packet != NULL);
152                 vp = fr_pair_find_by_num(request->packet->vps, PW_CACHE_ENTRY_HITS, 0, TAG_ANY);
153                 if (!vp) {
154                         vp = fr_pair_afrom_num(request->packet, PW_CACHE_ENTRY_HITS, 0);
155                         rad_assert(vp != NULL);
156                         fr_pair_add(&request->packet->vps, vp);
157                 }
158                 vp->vp_integer = c->hits;
159         }
160 }
161
162
163 /** Find a cached entry.
164  *
165  * @return RLM_MODULE_OK on success, RLM_MODULE_FAIL on failure, RLM_MODULE_NOTFOUND if notfound.
166  */
167 static rlm_rcode_t cache_find(rlm_cache_entry_t **out, rlm_cache_t *inst, REQUEST *request,
168                               rlm_cache_handle_t **handle, char const *key)
169 {
170         cache_status_t ret;
171
172         rlm_cache_entry_t *c;
173
174         *out = NULL;
175
176         for (;;) {
177                 ret = inst->module->find(&c, inst, request, handle, key);
178                 switch (ret) {
179                 case CACHE_RECONNECT:
180                         RDEBUG("Reconnecting...");
181                         if (cache_reconnect(inst, request, handle) == 0) continue;
182                         return RLM_MODULE_FAIL;
183
184                 case CACHE_OK:
185                         break;
186
187                 case CACHE_MISS:
188                         RDEBUG("No cache entry found for \"%s\"", key);
189                         return RLM_MODULE_NOTFOUND;
190
191                 /* FALL-THROUGH */
192                 default:
193                         return RLM_MODULE_FAIL;
194
195                 }
196
197                 break;
198         }
199
200         /*
201          *      Yes, but it expired, OR the "forget all" epoch has
202          *      passed.  Delete it, and pretend it doesn't exist.
203          */
204         if ((c->expires < request->timestamp) || (c->created < inst->epoch)) {
205                 RDEBUG("Removing expired entry");
206
207                 inst->module->expire(inst, request, handle, c);
208                 cache_free(inst, &c);
209                 return RLM_MODULE_NOTFOUND;     /* Couldn't find a non-expired entry */
210         }
211
212         RDEBUG("Found entry for \"%s\"", key);
213
214         c->hits++;
215         *out = c;
216
217         return RLM_MODULE_OK;
218 }
219
220 /** Expire a cache entry (removing it from the datastore)
221  *
222  */
223 static void cache_expire(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle, rlm_cache_entry_t **c)
224 {
225         rad_assert(*c);
226
227         for (;;) switch (inst->module->expire(inst, request, handle, *c)) {
228         case CACHE_RECONNECT:
229                 if (cache_reconnect(inst, request, handle) == 0) continue;
230
231         /* FALL-THROUGH */
232         default:
233                 cache_free(inst, c);
234                 *c = NULL;
235                 return;
236         }
237 }
238
239 /** Create and insert a cache entry.
240  *
241  * @return RLM_MODULE_OK on success, RLM_MODULE_UPDATED if we merged the cache entry and RLM_MODULE_FAIL on failure.
242  */
243 static rlm_rcode_t cache_insert(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle,
244                                 char const *key, int ttl)
245 {
246         VALUE_PAIR *vp, *to_cache;
247         vp_cursor_t src_list, packet, reply, control, state;
248
249         vp_map_t const *map;
250
251         bool merge = true;
252         rlm_cache_entry_t *c;
253
254         if ((inst->max_entries > 0) && inst->module->count &&
255             (inst->module->count(inst, request, handle) > inst->max_entries)) {
256                 RWDEBUG("Cache is full: %d entries", inst->max_entries);
257                 return RLM_MODULE_FAIL;
258         }
259
260         c = cache_alloc(inst, request);
261         if (!c) return RLM_MODULE_FAIL;
262
263         c->key = talloc_typed_strdup(c, key);
264         c->created = c->expires = request->timestamp;
265         c->expires += ttl;
266
267         RDEBUG("Creating new cache entry");
268
269         fr_cursor_init(&packet, &c->packet);
270         fr_cursor_init(&reply, &c->reply);
271         fr_cursor_init(&control, &c->control);
272         fr_cursor_init(&state, &c->state);
273
274         for (map = inst->maps; map != NULL; map = map->next) {
275                 rad_assert(map->lhs && map->rhs);
276
277                 if (map_to_vp(c, &to_cache, request, map, NULL) < 0) {
278                         RDEBUG("Skipping %s", map->rhs->name);
279                         continue;
280                 }
281
282                 for (vp = fr_cursor_init(&src_list, &to_cache);
283                      vp;
284                      vp = fr_cursor_next(&src_list)) {
285                         VERIFY_VP(vp);
286
287                         /*
288                          *      Prevent people from accidentally caching
289                          *      cache control attributes.
290                          */
291                         if (map->rhs->type == TMPL_TYPE_LIST) switch (vp->da->attr) {
292                         case PW_CACHE_TTL:
293                         case PW_CACHE_STATUS_ONLY:
294                         case PW_CACHE_READ_ONLY:
295                         case PW_CACHE_MERGE:
296                         case PW_CACHE_ENTRY_HITS:
297                                 RDEBUG2("Skipping %s", vp->da->name);
298                                 continue;
299
300                         default:
301                                 break;
302                         }
303
304                         RINDENT();
305                         if (RDEBUG_ENABLED2) map_debug_log(request, map, vp);
306                         REXDENT();
307
308                         vp->op = map->op;
309
310                         switch (map->lhs->tmpl_list) {
311                         case PAIR_LIST_REQUEST:
312                                 fr_cursor_insert(&packet, vp);
313                                 break;
314
315                         case PAIR_LIST_REPLY:
316                                 fr_cursor_insert(&reply, vp);
317                                 break;
318
319                         case PAIR_LIST_CONTROL:
320                                 fr_cursor_insert(&control, vp);
321                                 break;
322
323                         case PAIR_LIST_STATE:
324                                 fr_cursor_insert(&state, vp);
325                                 break;
326
327                         default:
328                                 rad_assert(0);  /* should have been caught by validation */
329                         }
330                 }
331         }
332
333         /*
334          *      Check to see if we need to merge the entry into the request
335          */
336         vp = fr_pair_find_by_num(request->config, PW_CACHE_MERGE, 0, TAG_ANY);
337         if (vp && (vp->vp_integer == 0)) merge = false;
338
339         if (merge) cache_merge(inst, request, c);
340
341         for (;;) {
342                 cache_status_t ret;
343
344                 ret = inst->module->insert(inst, request, handle, c);
345                 switch (ret) {
346                 case CACHE_RECONNECT:
347                         if (cache_reconnect(inst, request, handle) == 0) continue;
348                         return RLM_MODULE_FAIL;
349
350                 case CACHE_OK:
351                         RDEBUG("Committed entry, TTL %d seconds", ttl);
352                         cache_free(inst, &c);
353                         return RLM_MODULE_UPDATED;
354
355                 default:
356                         talloc_free(c); /* Failed insertion - use talloc_free not the driver free */
357                         return RLM_MODULE_FAIL;
358                 }
359         }
360 }
361
362 /** Verify that a map in the cache section makes sense
363  *
364  */
365 static int cache_verify(vp_map_t *map, void *ctx)
366 {
367         if (modcall_fixup_update(map, ctx) < 0) return -1;
368
369         if ((map->lhs->type != TMPL_TYPE_ATTR) &&
370             (map->lhs->type != TMPL_TYPE_LIST)) {
371                 cf_log_err(map->ci, "Destination must be an attribute ref or a list");
372                 return -1;
373         }
374
375         switch (map->lhs->tmpl_list) {
376         case PAIR_LIST_REQUEST:
377         case PAIR_LIST_REPLY:
378         case PAIR_LIST_CONTROL:
379         case PAIR_LIST_STATE:
380                 break;
381
382         default:
383                 cf_log_err(map->ci, "Destination list must be one of request, reply, control or session-state");
384                 return -1;
385         }
386
387         if (map->lhs->tmpl_request != REQUEST_CURRENT) {
388                 cf_log_err(map->ci, "Cached attributes can only be inserted into the current request");
389                 return -1;
390         }
391
392         switch (map->rhs->type) {
393         case TMPL_TYPE_EXEC:
394                 cf_log_err(map->ci, "Exec values are not allowed");
395                 return -1;
396         /*
397          *      Only =, :=, += and -= operators are supported for
398          *      cache entries.
399          */
400         case TMPL_TYPE_LITERAL:
401         case TMPL_TYPE_XLAT:
402         case TMPL_TYPE_ATTR:
403                 switch (map->op) {
404                 case T_OP_SET:
405                 case T_OP_EQ:
406                 case T_OP_SUB:
407                 case T_OP_ADD:
408                         break;
409
410                 default:
411                         cf_log_err(map->ci, "Operator \"%s\" not allowed for %s values",
412                                    fr_int2str(fr_tokens, map->op, "<INVALID>"),
413                                    fr_int2str(tmpl_names, map->rhs->type, "<INVALID>"));
414                         return -1;
415                 }
416         default:
417                 break;
418         }
419
420         return 0;
421 }
422
423 /*
424  *      Do caching checks.  Since we can update ANY VP list, we do
425  *      exactly the same thing for all sections (autz / auth / etc.)
426  *
427  *      If you want to cache something different in different sections,
428  *      configure another cache module.
429  */
430 static rlm_rcode_t CC_HINT(nonnull) mod_cache_it(void *instance, REQUEST *request)
431 {
432         rlm_cache_entry_t *c;
433         rlm_cache_t *inst = instance;
434
435         rlm_cache_handle_t *handle;
436
437         vp_cursor_t cursor;
438         VALUE_PAIR *vp;
439         char buffer[1024];
440         rlm_rcode_t rcode;
441
442         int ttl = inst->ttl;
443
444         if (radius_xlat(buffer, sizeof(buffer), request, inst->key, NULL, NULL) < 0) return RLM_MODULE_FAIL;
445
446         if (buffer[0] == '\0') {
447                 REDEBUG("Zero length key string is invalid");
448                 return RLM_MODULE_INVALID;
449         }
450
451         if (cache_acquire(&handle, inst, request) < 0) return RLM_MODULE_FAIL;
452
453         rcode = cache_find(&c, inst, request, &handle, buffer);
454         if (rcode == RLM_MODULE_FAIL) goto finish;
455         rad_assert(handle);
456
457         /*
458          *      If Cache-Status-Only == yes, only return whether we found a
459          *      valid cache entry
460          */
461         vp = fr_pair_find_by_num(request->config, PW_CACHE_STATUS_ONLY, 0, TAG_ANY);
462         if (vp && vp->vp_integer) {
463                 rcode = c ? RLM_MODULE_OK:
464                             RLM_MODULE_NOTFOUND;
465                 goto finish;
466         }
467
468         /*
469          *      Update the expiry time based on the TTL.
470          *      A TTL of 0 means "delete from the cache".
471          *      A TTL < 0 means "delete from the cache and recreate the entry".
472          */
473         vp = fr_pair_find_by_num(request->config, PW_CACHE_TTL, 0, TAG_ANY);
474         if (vp) ttl = vp->vp_signed;
475
476         /*
477          *      If there's no existing cache entry, go and create a new one.
478          */
479         if (!c) {
480                 if (ttl <= 0) ttl = inst->ttl;
481                 goto insert;
482         }
483
484         /*
485          *      Expire the entry if requested to do so
486          */
487         if (vp) {
488                 if (ttl == 0) {
489                         cache_expire(inst, request, &handle, &c);
490                         RDEBUG("Forcing expiry of entry");
491                         rcode = RLM_MODULE_OK;
492                         goto finish;
493                 }
494
495                 if (ttl < 0) {
496                         RDEBUG("Forcing expiry of existing entry");
497                         cache_expire(inst, request, &handle, &c);
498                         ttl *= -1;
499                         goto insert;
500                 }
501                 c->expires = request->timestamp + ttl;
502                 RDEBUG("Setting TTL to %d", ttl);
503         }
504
505         /*
506          *      Cache entry was still valid, so we merge it into the request
507          *      and return. No need to add a new entry.
508          */
509         cache_merge(inst, request, c);
510         rcode = RLM_MODULE_OK;
511
512         goto finish;
513
514 insert:
515         /*
516          *      If Cache-Read-Only == yes, then we only allow already cached entries
517          *      to be merged into the request
518          */
519         vp = fr_pair_find_by_num(request->config, PW_CACHE_READ_ONLY, 0, TAG_ANY);
520         if (vp && vp->vp_integer) {
521                 rcode = RLM_MODULE_NOTFOUND;
522                 goto finish;
523         }
524
525         /*
526          *      Create a new entry.
527          */
528         rcode = cache_insert(inst, request, &handle, buffer, ttl);
529         rad_assert(handle);
530
531 finish:
532         cache_free(inst, &c);
533         cache_release(inst, request, &handle);
534
535         /*
536          *      Clear control attributes
537          */
538         for (vp = fr_cursor_init(&cursor, &request->config);
539              vp;
540              vp = fr_cursor_next(&cursor)) {
541                 if (vp->da->vendor == 0) switch (vp->da->attr) {
542                 case PW_CACHE_TTL:
543                 case PW_CACHE_STATUS_ONLY:
544                 case PW_CACHE_READ_ONLY:
545                 case PW_CACHE_MERGE:
546                         vp = fr_cursor_remove(&cursor);
547                         talloc_free(vp);
548                         break;
549                 }
550         }
551
552         return rcode;
553 }
554
555 static ssize_t CC_HINT(nonnull) cache_xlat(void *instance, REQUEST *request,
556                                            char const *fmt, char *out, size_t freespace);
557
558 /*
559  *      Allow single attribute values to be retrieved from the cache.
560  */
561 static ssize_t cache_xlat(void *instance, REQUEST *request,
562                           char const *fmt, char *out, size_t freespace)
563 {
564         rlm_cache_entry_t       *c = NULL;
565         rlm_cache_t             *inst = instance;
566         rlm_cache_handle_t      *handle = NULL;
567
568         VALUE_PAIR              *vp, *vps;
569         pair_lists_t            list;
570         DICT_ATTR const         *target;
571         char const              *p = fmt;
572         size_t                  len;
573         int                     ret = 0;
574
575         p += radius_list_name(&list, p, PAIR_LIST_REQUEST);
576         if (list == PAIR_LIST_UNKNOWN) {
577                 REDEBUG("Unknown list qualifier in \"%s\"", fmt);
578                 ret = -1;
579                 goto finish;
580         }
581
582         target = dict_attrbyname(p);
583         if (!target) {
584                 REDEBUG("Unknown attribute \"%s\"", p);
585                 return -1;
586         }
587
588         if (cache_acquire(&handle, inst, request) < 0) return -1;
589
590         switch (cache_find(&c, inst, request, handle, fmt)) {
591         case RLM_MODULE_OK:             /* found */
592                 break;
593
594         case RLM_MODULE_NOTFOUND:       /* not found */
595                 *out = '\0';
596                 return 0;
597
598         default:
599                 return -1;
600         }
601
602         switch (list) {
603         case PAIR_LIST_REQUEST:
604                 vps = c->packet;
605                 break;
606
607         case PAIR_LIST_REPLY:
608                 vps = c->reply;
609                 break;
610
611         case PAIR_LIST_CONTROL:
612                 vps = c->control;
613                 break;
614
615         case PAIR_LIST_STATE:
616                 vps = c->state;
617                 break;
618
619         default:
620                 REDEBUG("Unsupported list \"%s\"", fr_int2str(pair_lists, list, "<UNKNOWN>"));
621                 ret = -1;
622                 goto finish;
623         }
624
625         vp = fr_pair_find_by_num(vps, target->attr, target->vendor, TAG_ANY);
626         if (!vp) {
627                 RDEBUG("No instance of this attribute has been cached");
628                 *out = '\0';
629                 goto finish;
630         }
631
632         len = vp_prints_value(out, freespace, vp, 0);
633         if (is_truncated(len, freespace)) {
634                 REDEBUG("Insufficient buffer space to write cached value");
635                 ret = -1;
636                 goto finish;
637         }
638
639 finish:
640         cache_free(inst, &c);
641         cache_release(inst, request, &handle);
642
643         return ret;
644 }
645
646 /*
647  *      Only free memory we allocated.  The strings allocated via
648  *      cf_section_parse() do not need to be freed.
649  */
650 static int mod_detach(void *instance)
651 {
652         rlm_cache_t *inst = instance;
653
654         talloc_free(inst->maps);
655
656         /*
657          *  We need to explicitly free all children, so if the driver
658          *  parented any memory off the instance, their destructors
659          *  run before we unload the bytecode for them.
660          *
661          *  If we don't do this, we get a SEGV deep inside the talloc code
662          *  when it tries to call a destructor that no longer exists.
663          */
664         talloc_free_children(inst);
665
666         /*
667          *  Decrements the reference count. The driver object won't be unloaded
668          *  until all instances of rlm_cache that use it have been destroyed.
669          */
670         if (inst->handle) dlclose(inst->handle);
671
672         return 0;
673 }
674
675
676 static int mod_bootstrap(CONF_SECTION *conf, void *instance)
677 {
678         rlm_cache_t *inst = instance;
679
680         inst->cs = conf;
681
682         inst->name = cf_section_name2(conf);
683         if (!inst->name) inst->name = cf_section_name1(conf);
684
685         /*
686          *      Register the cache xlat function
687          */
688         xlat_register(inst->name, cache_xlat, NULL, inst);
689
690         return 0;
691 }
692
693
694 /*
695  *      Instantiate the module.
696  */
697 static int mod_instantiate(CONF_SECTION *conf, void *instance)
698 {
699         rlm_cache_t *inst = instance;
700         CONF_SECTION *update;
701
702         inst->cs = conf;
703
704         /*
705          *      Sanity check for crazy people.
706          */
707         if (strncmp(inst->driver_name, "rlm_cache_", 8) != 0) {
708                 cf_log_err_cs(conf, "\"%s\" is NOT an Cache driver!", inst->driver_name);
709                 return -1;
710         }
711
712         /*
713          *      Load the appropriate driver for our database
714          */
715         inst->handle = fr_dlopenext(inst->driver_name);
716         if (!inst->handle) {
717                 cf_log_err_cs(conf, "Could not link driver %s: %s", inst->driver_name, dlerror());
718                 cf_log_err_cs(conf, "Make sure it (and all its dependent libraries!) are in the search path"
719                               " of your system's ld");
720                 return -1;
721         }
722
723         inst->module = (cache_module_t *) dlsym(inst->handle, inst->driver_name);
724         if (!inst->module) {
725                 cf_log_err_cs(conf, "Could not link symbol %s: %s", inst->driver_name, dlerror());
726                 return -1;
727         }
728
729         DEBUG("rlm_cache (%s): Driver %s (module %s) loaded and linked", inst->name,
730               inst->driver_name, inst->module->name);
731
732         /*
733          *      Non optional fields and callbacks
734          */
735         rad_assert(inst->module->name);
736         rad_assert(inst->module->find);
737         rad_assert(inst->module->insert);
738         rad_assert(inst->module->expire);
739
740         if (inst->module->instantiate) {
741                 CONF_SECTION *cs;
742                 char const *name;
743
744                 name = strrchr(inst->driver_name, '_');
745                 if (!name) {
746                         name = inst->driver_name;
747                 } else {
748                         name++;
749                 }
750
751                 cs = cf_section_sub_find(conf, name);
752                 if (!cs) {
753                         cs = cf_section_alloc(conf, name, NULL);
754                         if (!cs) return -1;
755                 }
756
757                 /*
758                  *      It's up to the driver to register a destructor (using talloc)
759                  *
760                  *      Should write its instance data in inst->driver,
761                  *      and parent it off of inst.
762                  */
763                 if (inst->module->instantiate(cs, inst) < 0) return -1;
764         }
765
766         rad_assert(inst->key && *inst->key);
767
768         if (inst->ttl == 0) {
769                 cf_log_err_cs(conf, "Must set 'ttl' to non-zero");
770                 return -1;
771         }
772
773         if (inst->epoch != 0) {
774                 cf_log_err_cs(conf, "Must not set 'epoch' in the configuration files");
775                 return -1;
776         }
777
778         update = cf_section_sub_find(inst->cs, "update");
779         if (!update) {
780                 cf_log_err_cs(conf, "Must have an 'update' section in order to cache anything.");
781                 return -1;
782         }
783
784         /*
785          *      Make sure the users don't screw up too badly.
786          */
787         if (map_afrom_cs(&inst->maps, update,
788                          PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, cache_verify, NULL, MAX_ATTRMAP) < 0) {
789                 return -1;
790         }
791
792         if (!inst->maps) {
793                 cf_log_err_cs(inst->cs, "Cache config must contain an update section, and "
794                               "that section must not be empty");
795
796                 return -1;
797         }
798         return 0;
799 }
800
801 /*
802  *      The module name should be the only globally exported symbol.
803  *      That is, everything else should be 'static'.
804  *
805  *      If the module needs to temporarily modify it's instantiation
806  *      data, the type should be changed to RLM_TYPE_THREAD_UNSAFE.
807  *      The server will then take care of ensuring that the module
808  *      is single-threaded.
809  */
810 extern module_t rlm_cache;
811 module_t rlm_cache = {
812         .magic          = RLM_MODULE_INIT,
813         .name           = "cache",
814         .inst_size      = sizeof(rlm_cache_t),
815         .config         = module_config,
816         .bootstrap      = mod_bootstrap,
817         .instantiate    = mod_instantiate,
818         .detach         = mod_detach,
819         .methods = {
820                 [MOD_AUTHORIZE]         = mod_cache_it,
821                 [MOD_PREACCT]           = mod_cache_it,
822                 [MOD_ACCOUNTING]        = mod_cache_it,
823                 [MOD_PRE_PROXY]         = mod_cache_it,
824                 [MOD_POST_PROXY]        = mod_cache_it,
825                 [MOD_POST_AUTH]         = mod_cache_it
826         },
827 };