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