2 * modules.c Radius module support.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2003 The FreeRADIUS server project
21 * Copyright 2000 Alan DeKok <aland@ox.org>
22 * Copyright 2000 Alan Curry <pacman@world.std.com>
25 static const char rcsid[] = "$Id$";
28 #include "libradius.h"
40 #include "rad_assert.h"
43 * Internal list of all of the modules we have loaded.
45 static module_list_t *module_list = NULL;
48 * Internal list of each module instance.
50 static module_instance_t *module_instance_list = NULL;
52 typedef struct indexed_modcallable {
53 struct indexed_modcallable *next;
55 modcallable *modulelist;
56 } indexed_modcallable;
59 * For each component, keep an ordered list of ones to call.
61 static indexed_modcallable *components[RLM_COMPONENT_COUNT];
64 * The component names.
66 * Hmm... we probably should be getting these from the configuration
69 const char *component_names[RLM_COMPONENT_COUNT] =
84 static const char *old_subcomponent_names[RLM_COMPONENT_COUNT] =
96 static const char *subcomponent_names[RLM_COMPONENT_COUNT] =
108 static void indexed_modcallable_free(indexed_modcallable **cf)
110 indexed_modcallable *c, *next;
115 modcallable_free(&c->modulelist);
122 static void instance_list_free(module_instance_t **i)
124 module_instance_t *c, *next;
129 if(c->entry->module->detach)
130 (c->entry->module->detach)(c->insthandle);
131 #ifdef HAVE_PTHREAD_H
135 * The mutex MIGHT be locked...
136 * we'll check for that later, I guess.
138 pthread_mutex_destroy(c->mutex);
149 * Remove all of the modules.
151 int detach_modules(void)
153 module_list_t *ml, *next;
157 * Delete the internal component pointers.
159 for (i = 0; i < RLM_COMPONENT_COUNT; i++) {
160 indexed_modcallable_free(&components[i]);
163 instance_list_free(&module_instance_list);
168 if (ml->module->destroy)
169 (ml->module->destroy)();
170 lt_dlclose(ml->handle); /* ignore any errors */
181 * Find a module on disk or in memory, and link to it.
183 static module_list_t *linkto_module(const char *module_name,
184 const char *cffilename, int cflineno)
188 char module_struct[256];
192 * Look through the global module library list for the
195 for (node = module_list; node != NULL; node = node->next) {
197 * Found the named module. Return it.
199 if (strcmp(node->name, module_name) == 0)
205 * Keep the handle around so we can dlclose() it.
207 handle = lt_dlopenext(module_name);
208 if (handle == NULL) {
209 radlog(L_ERR|L_CONS, "%s[%d] Failed to link to module '%s':"
210 " %s\n", cffilename, cflineno, module_name, lt_dlerror());
214 /* make room for the module type */
215 node = (module_list_t *) rad_malloc(sizeof(module_list_t));
217 /* fill in the module structure */
219 node->handle = handle;
220 strNcpy(node->name, module_name, sizeof(node->name));
223 * Link to the module's rlm_FOO{} module structure.
225 /* module_name has the version embedded; strip it. */
226 strcpy(module_struct, module_name);
227 p = strrchr(module_struct, '-');
230 node->module = (module_t *) lt_dlsym(node->handle, module_struct);
232 radlog(L_ERR|L_CONS, "%s[%d] Failed linking to "
233 "%s structure in %s: %s\n",
234 cffilename, cflineno,
235 module_name, cffilename, lt_dlerror());
236 lt_dlclose(node->handle); /* ignore any errors */
241 /* call the modules initialization */
242 if (node->module->init && (node->module->init)() < 0) {
243 radlog(L_ERR|L_CONS, "%s[%d] Module initialization failed.\n",
244 cffilename, cflineno);
245 lt_dlclose(node->handle); /* ignore any errors */
250 DEBUG("Module: Loaded %s ", node->module->name);
252 node->next = module_list;
259 * Find a module instance.
261 module_instance_t *find_module_instance(const char *instname)
263 CONF_SECTION *cs, *inst_cs;
264 const char *name1, *name2;
265 module_instance_t *node, **last;
266 char module_name[256];
269 * Look through the global module instance list for the
272 last = &module_instance_list;
273 for (node = module_instance_list; node != NULL; node = node->next) {
275 * Found the named instance. Return it.
277 if (strcmp(node->name, instname) == 0)
281 * Keep a pointer to the last entry to update...
287 * Instance doesn't exist yet. Try to find the
288 * corresponding configuration section and create it.
292 * Look for the 'modules' configuration section.
294 cs = cf_section_find("modules");
296 radlog(L_ERR|L_CONS, "ERROR: Cannot find a 'modules' section in the configuration file.\n");
301 * Module instances are declared in the modules{} block
302 * and referenced later by their name, which is the
303 * name2 from the config section, or name1 if there was
306 name1 = name2 = NULL;
307 for(inst_cs=cf_subsection_find_next(cs, NULL, NULL);
309 inst_cs=cf_subsection_find_next(cs, inst_cs, NULL)) {
310 name1 = cf_section_name1(inst_cs);
311 name2 = cf_section_name2(inst_cs);
312 if ( (name2 && !strcmp(name2, instname)) ||
313 (!name2 && !strcmp(name1, instname)) )
316 if (inst_cs == NULL) {
317 radlog(L_ERR|L_CONS, "ERROR: Cannot find a configuration entry for module \"%s\".\n", instname);
322 * Found the configuration entry.
324 node = rad_malloc(sizeof(*node));
326 node->insthandle = NULL;
329 * Link to the module by name: rlm_FOO-major.minor
331 if (strncmp(name1, "rlm_", 4)) {
333 snprintf(module_name, sizeof(module_name), "rlm_%s-%d.%d",
334 name1, RADIUSD_MAJOR_VERSION, RADIUSD_MINOR_VERSION);
336 snprintf(module_name, sizeof(module_name), "rlm_%s",
340 strNcpy(module_name, name1, sizeof(module_name));
345 * FIXME: "radiusd.conf" is wrong here; must find cf filename
347 node->entry = linkto_module(module_name, "radiusd.conf",
348 cf_section_lineno(inst_cs));
351 /* linkto_module logs any errors */
356 * Call the module's instantiation routine.
358 if ((node->entry->module->instantiate) &&
359 ((node->entry->module->instantiate)(inst_cs,
360 &node->insthandle) < 0)) {
362 "radiusd.conf[%d]: %s: Module instantiation failed.\n",
363 cf_section_lineno(inst_cs), instname);
369 * We're done. Fill in the rest of the data structure,
370 * and link it to the module instance list.
372 strNcpy(node->name, instname, sizeof(node->name));
374 #ifdef HAVE_PTHREAD_H
376 * If we're threaded, check if the module is thread-safe.
378 * If it isn't, we create a mutex.
380 if ((node->entry->module->type & RLM_TYPE_THREAD_UNSAFE) != 0) {
381 node->mutex = (pthread_mutex_t *) rad_malloc(sizeof(pthread_mutex_t));
383 * Initialize the mutex.
385 pthread_mutex_init(node->mutex, NULL);
388 * The module is thread-safe. Don't give it a mutex.
396 DEBUG("Module: Instantiated %s (%s) ", name1, node->name);
401 static indexed_modcallable *lookup_by_index(indexed_modcallable *head, int idx)
403 indexed_modcallable *p;
405 for (p = head; p != NULL; p = p->next) {
412 static indexed_modcallable *new_sublist(int comp, int idx)
414 indexed_modcallable **head = &components[comp];
415 indexed_modcallable *node = *head;
416 indexed_modcallable **last = head;
419 /* It is an error to try to create a sublist that already
420 * exists. It would almost certainly be caused by accidental
421 * duplication in the config file.
423 * index 0 is the exception, because it is used when we want
424 * to collect _all_ listed modules under a single index by
425 * default, which is currently the case in all components
426 * except authenticate. */
427 if (node->idx == idx) {
437 node = rad_malloc(sizeof *node);
439 node->modulelist = NULL;
445 static int indexed_modcall(int comp, int idx, REQUEST *request)
447 indexed_modcallable *this;
449 this = lookup_by_index(components[comp], idx);
451 if (idx != 0) DEBUG2(" ERROR: Unknown value specified for %s. Cannot perform requested action.",
452 subcomponent_names[comp]);
453 /* Return a default value appropriate for the component */
455 case RLM_COMPONENT_AUTZ: return RLM_MODULE_NOTFOUND;
456 case RLM_COMPONENT_AUTH: return RLM_MODULE_REJECT;
457 case RLM_COMPONENT_PREACCT: return RLM_MODULE_NOOP;
458 case RLM_COMPONENT_ACCT: return RLM_MODULE_NOOP;
459 case RLM_COMPONENT_SESS: return RLM_MODULE_FAIL;
460 case RLM_COMPONENT_PRE_PROXY: return RLM_MODULE_NOOP;
461 case RLM_COMPONENT_POST_PROXY: return RLM_MODULE_NOOP;
462 case RLM_COMPONENT_POST_AUTH: return RLM_MODULE_NOOP;
463 default: return RLM_MODULE_FAIL;
467 DEBUG2(" Processing the %s section of radiusd.conf",
468 component_names[comp]);
469 return modcall(comp, this->modulelist, request);
472 /* Load a flat module list, as found inside an authtype{} block */
473 static int load_subcomponent_section(CONF_SECTION *cs, int comp,
474 const char *filename)
477 indexed_modcallable *subcomp;
481 static int meaningless_counter = 1;
483 ml = compile_modgroup(comp, cs, filename);
488 /* We must assign a numeric index to this subcomponent. For
489 * auth, it is generated and placed in the dictionary by
490 * new_sectiontype_value(). The others are just numbers that are pulled
491 * out of thin air, and the names are neither put into the dictionary
492 * nor checked for uniqueness, but all that could be fixed in a few
493 * minutes, if anyone finds a real use for indexed config of
494 * components other than auth. */
496 if (comp==RLM_COMPONENT_AUTH) {
497 dval = dict_valbyname(PW_AUTH_TYPE, cf_section_name2(cs));
498 } else if (comp == RLM_COMPONENT_AUTZ) {
499 dval = dict_valbyname(PW_AUTZ_TYPE, cf_section_name2(cs));
500 } else if (comp == RLM_COMPONENT_ACCT) {
501 dval = dict_valbyname(PW_ACCT_TYPE, cf_section_name2(cs));
502 } else if (comp == RLM_COMPONENT_SESS) {
503 dval = dict_valbyname(PW_SESSION_TYPE, cf_section_name2(cs));
504 } else if (comp == RLM_COMPONENT_PRE_PROXY) {
505 dval = dict_valbyname(PW_PRE_PROXY_TYPE, cf_section_name2(cs));
506 } else if (comp == RLM_COMPONENT_POST_PROXY) {
507 dval = dict_valbyname(PW_POST_PROXY_TYPE, cf_section_name2(cs));
508 } else if (comp == RLM_COMPONENT_POST_AUTH) {
509 dval = dict_valbyname(PW_POST_AUTH_TYPE, cf_section_name2(cs));
515 idx = meaningless_counter++;
518 subcomp = new_sublist(comp, idx);
521 "%s[%d] %s %s already configured - skipping",
522 filename, cf_section_lineno(cs),
523 subcomponent_names[comp], cf_section_name2(cs));
524 modcallable_free(&ml);
528 subcomp->modulelist = ml;
533 static int load_component_section(CONF_SECTION *cs, int comp,
534 const char *filename)
539 indexed_modcallable *subcomp;
543 for (modref=cf_item_find_next(cs, NULL);
545 modref=cf_item_find_next(cs, modref)) {
546 CONF_PAIR *cp = NULL;
547 CONF_SECTION *scs = NULL;
549 if (cf_item_is_section(modref)) {
550 const char *sec_name;
551 scs = cf_itemtosection(modref);
553 sec_name = cf_section_name1(scs);
556 subcomponent_names[comp]) == 0) {
557 if (!load_subcomponent_section(scs, comp,
559 return -1; /* FIXME: memleak? */
565 * Allow old names, too.
568 old_subcomponent_names[comp]) == 0) {
569 if (!load_subcomponent_section(scs, comp,
571 return -1; /* FIXME: memleak? */
577 cp = cf_itemtopair(modref);
580 this = compile_modsingle(comp, modref, filename, &modname);
583 "%s[%d] Failed to parse %s section.\n",
584 filename, cf_section_lineno(cs),
585 cf_section_name1(cs));
589 if (comp == RLM_COMPONENT_AUTH) {
591 const char *modrefname = NULL;
595 modrefname = cf_pair_attr(cp);
596 lineno = cf_pair_lineno(cp);
598 modrefname = cf_section_name2(scs);
599 lineno = cf_section_lineno(scs);
603 "%s[%d] Failed to parse %s sub-section.\n",
605 cf_section_name1(scs));
610 dval = dict_valbyname(PW_AUTH_TYPE, modrefname);
613 * It's a section, but nothing we
616 radlog(L_ERR|L_CONS, "%s[%d] Unknown Auth-Type \"%s\" in %s section.",
618 modrefname, component_names[comp]);
623 /* See the comment in new_sublist() for explanation
624 * of the special index 0 */
628 subcomp = new_sublist(comp, idx);
629 if (subcomp == NULL) {
630 radlog(L_INFO|L_CONS,
631 "%s %s %s already configured - skipping",
632 filename, subcomponent_names[comp],
634 modcallable_free(&this);
638 /* If subcomp->modulelist is NULL, add_to_modcallable will
640 visiblename = cf_section_name2(cs);
641 if (visiblename == NULL)
642 visiblename = cf_section_name1(cs);
643 add_to_modcallable(&subcomp->modulelist, this,
650 typedef struct section_type_value_t {
652 const char *typename;
654 } section_type_value_t;
656 static const section_type_value_t section_type_value[] = {
657 { "authorize", "Autz-Type", PW_AUTZ_TYPE },
658 { "authenticate", "Auth-Type", PW_AUTH_TYPE },
659 { "accounting", "Acct-Type", PW_ACCT_TYPE },
660 { "session", "Session-Type", PW_SESSION_TYPE },
661 { "post-auth", "Post-Auth-Type", PW_POST_AUTH_TYPE },
662 { "preacct", "Pre-Acct-Type", PW_PRE_ACCT_TYPE },
663 { "post-proxy", "Post-Proxy-Type", PW_POST_PROXY_TYPE },
664 { "pre-proxy", "Pre-Proxy-Type", PW_PRE_PROXY_TYPE },
671 static const section_type_value_t old_section_type_value[] = {
672 { "authorize", "autztype", PW_AUTZ_TYPE },
673 { "authenticate", "authtype", PW_AUTH_TYPE },
674 { "accounting", "acctype", PW_ACCT_TYPE },
675 { "session", "sesstype", PW_SESSION_TYPE },
676 { "post-auth", "post-authtype", PW_POST_AUTH_TYPE },
681 * Parse the module config sections, and load
682 * and call each module's init() function.
684 * Libtool makes your life a LOT easier, especially with libltdl.
685 * see: http://www.gnu.org/software/libtool/
687 int setup_modules(void)
693 * FIXME: This should be pulled from somewhere else.
695 const char *filename="radiusd.conf";
698 * No current list of modules: Go initialize libltdl.
702 * Set the default list of preloaded symbols.
703 * This is used to initialize libltdl's list of
706 * i.e. Static modules.
708 LTDL_SET_PRELOADED_SYMBOLS();
710 if (lt_dlinit() != 0) {
711 radlog(L_ERR|L_CONS, "Failed to initialize libraries: %s\n",
718 * Set the search path to ONLY our library directory.
719 * This prevents the modules from being found from
720 * any location on the disk.
722 lt_dlsetsearchpath(radlib_dir);
724 DEBUG2("Module: Library search path is %s",
725 lt_dlgetsearchpath());
728 * Initialize the components.
730 for (comp = 0; comp < RLM_COMPONENT_COUNT; comp++) {
731 components[comp] = NULL;
739 * Create any DICT_VALUE's for the types. See
740 * 'doc/configurable_failover' for examples of 'authtype'
741 * used to create new Auth-Type values. In order to
742 * let the user create new names, we've got to look for
743 * those names, and create DICT_VALUE's for them.
745 for (comp = 0; section_type_value[comp].section != NULL; comp++) {
749 CONF_SECTION *sub, *next;
755 static int my_value = 32767;
757 cs = cf_section_find(section_type_value[comp].section);
764 * See if there's a sub-section by that
767 next = cf_subsection_find_next(cs, sub,
768 section_type_value[comp].typename);
771 * Allow some old names, too.
773 if (!next && (comp <= 4)) {
775 next = cf_subsection_find_next(cs, sub,
776 old_section_type_value[comp].typename);
781 * If so, look for it to define a new
784 name2 = cf_section_name2(sub);
785 if (!name2) continue;
789 * If the value already exists, don't
792 dval = dict_valbyname(section_type_value[comp].attr,
797 * Find the attribute for the value.
799 dattr = dict_attrbyvalue(section_type_value[comp].attr);
800 if (!dattr) continue;
803 * Finally, create the new attribute.
805 if (dict_addvalue(name2, dattr->name, my_value++) < 0) {
806 radlog(L_ERR, "%s", librad_errstr);
809 } while (sub != NULL);
812 * Loop over the non-sub-sections, too.
817 * See if there's a conf-pair by that
820 cp = cf_pair_find_next(cs, cp, NULL);
825 * If the value already exists, don't
828 name2 = cf_pair_attr(cp);
829 dval = dict_valbyname(section_type_value[comp].attr,
834 * Find the attribute for the value.
836 dattr = dict_attrbyvalue(section_type_value[comp].attr);
837 if (!dattr) continue;
840 * Finally, create the new attribute.
842 if (dict_addvalue(name2, dattr->name, my_value++) < 0) {
843 radlog(L_ERR, "%s", librad_errstr);
846 } while (cp != NULL);
847 } /* over the sections which can have redundent sub-sections */
850 * Look for the 'instantiate' section, which tells us
851 * the instantiation order of the modules, and also allows
852 * us to load modules with no authorize/authenticate/etc.
855 cs = cf_section_find("instantiate");
859 module_instance_t *module;
863 * Loop over the items in the 'instantiate' section.
865 for (ci=cf_item_find_next(cs, NULL);
867 ci=cf_item_find_next(cs, ci)) {
869 if (cf_item_is_section(ci)) {
871 "%s[%d] Subsection for module instantiate is not allowed\n", filename,
873 cf_section_lineno(cf_itemtosection(ci)));
877 cp = cf_itemtopair(ci);
878 name = cf_pair_attr(cp);
879 module = find_module_instance(name);
883 } /* loop over items in the subsection */
884 } /* if there's an 'instantiate' section. */
887 * Loop over all of the known components, finding their
888 * configuration section, and loading it.
890 for (comp = 0; comp < RLM_COMPONENT_COUNT; ++comp) {
891 cs = cf_section_find(component_names[comp]);
895 if (load_component_section(cs, comp, filename) < 0) {
904 * Call all authorization modules until one returns
905 * somethings else than RLM_MODULE_OK
907 int module_authorize(int autz_type, REQUEST *request)
910 * We have a proxied packet, and we've been told
911 * to NOT pass proxied packets through 'authorize'
912 * a second time. So stop.
914 if ((request->proxy != NULL &&
915 mainconfig.post_proxy_authorize == FALSE)) {
916 DEBUG2(" authorize: Skipping authorize in post-proxy stage");
917 return RLM_MODULE_NOOP;
920 return indexed_modcall(RLM_COMPONENT_AUTZ, autz_type, request);
924 * Authenticate a user/password with various methods.
926 int module_authenticate(int auth_type, REQUEST *request)
928 return indexed_modcall(RLM_COMPONENT_AUTH, auth_type, request);
932 * Do pre-accounting for ALL configured sessions
934 int module_preacct(REQUEST *request)
936 return indexed_modcall(RLM_COMPONENT_PREACCT, 0, request);
940 * Do accounting for ALL configured sessions
942 int module_accounting(int acct_type, REQUEST *request)
944 return indexed_modcall(RLM_COMPONENT_ACCT, acct_type, request);
948 * See if a user is already logged in.
950 * Returns: 0 == OK, 1 == double logins, 2 == multilink attempt
952 int module_checksimul(int sess_type, REQUEST *request, int maxsimul)
956 if(!components[RLM_COMPONENT_SESS])
959 if(!request->username)
962 request->simul_count = 0;
963 request->simul_max = maxsimul;
964 request->simul_mpp = 1;
966 rcode = indexed_modcall(RLM_COMPONENT_SESS, sess_type, request);
968 if (rcode != RLM_MODULE_OK) {
969 /* FIXME: Good spot for a *rate-limited* warning to the log */
973 return (request->simul_count < maxsimul) ? 0 : request->simul_mpp;
977 * Do pre-proxying for ALL configured sessions
979 int module_pre_proxy(int type, REQUEST *request)
981 return indexed_modcall(RLM_COMPONENT_PRE_PROXY, type, request);
985 * Do post-proxying for ALL configured sessions
987 int module_post_proxy(int type, REQUEST *request)
989 return indexed_modcall(RLM_COMPONENT_POST_PROXY, type, request);
993 * Do post-authentication for ALL configured sessions
995 int module_post_auth(int postauth_type, REQUEST *request)
997 return indexed_modcall(RLM_COMPONENT_POST_AUTH, postauth_type, request);