#include <assert.h>
#include "radiusd.h"
+#include "modpriv.h"
#include "modules.h"
+#include "modcall.h"
#include "conffile.h"
#include "ltdl.h"
/*
- * Keep track of which modules we've loaded.
- */
-typedef struct module_list_t {
- struct module_list_t *next;
- char name[MAX_STRING_LEN];
- module_t *module;
- lt_dlhandle handle;
-} module_list_t;
-
-/*
* Internal list of all of the modules we have loaded.
*/
static module_list_t *module_list = NULL;
/*
- * Per-instance data structure, to correlate the modules
- * with the instance names (may NOT be the module names!),
- * and the per-instance data structures.
- */
-typedef struct module_instance_t {
- struct module_instance_t *next;
- char name[MAX_STRING_LEN];
- module_list_t *entry;
- void *insthandle;
-#if HAVE_PTHREAD_H
- pthread_mutex_t *mutex;
-#endif
-} module_instance_t;
-
-/*
* Internal list of each module instance.
*/
static module_instance_t *module_instance_list = NULL;
-/*
- * For each authorize/authtype/etc, we have an ordered
- * list of instances to call. This data structure keeps track
- * of that order.
- */
-typedef struct config_module_t {
- struct config_module_t *next;
- module_instance_t *instance;
-} config_module_t;
-
-typedef struct indexed_config_module_t {
- struct indexed_config_module_t *next;
+typedef struct indexed_modcallable {
+ struct indexed_modcallable *next;
int idx;
- config_module_t *modulelist;
-} indexed_config_module_t;
+ modcallable *modulelist;
+} indexed_modcallable;
/*
* For each component, keep an ordered list of ones to call.
*/
-static indexed_config_module_t *components[RLM_COMPONENT_COUNT];
+static indexed_modcallable *components[RLM_COMPONENT_COUNT];
/*
* The component names.
"sesstype"
};
-static void config_list_free(config_module_t **cf)
+static void indexed_modcallable_free(indexed_modcallable **cf)
{
- config_module_t *c, *next;
+ indexed_modcallable *c, *next;
c = *cf;
while (c) {
next = c->next;
- free(c);
- c = next;
- }
- *cf = NULL;
-}
-
-static void indexed_config_list_free(indexed_config_module_t **cf)
-{
- indexed_config_module_t *c, *next;
-
- c = *cf;
- while (c) {
- next = c->next;
- config_list_free(&c->modulelist);
+ modcallable_free(&c->modulelist);
free(c);
c = next;
}
* Delete the internal component pointers.
*/
for (i = 0; i < RLM_COMPONENT_COUNT; i++) {
- indexed_config_list_free(&components[i]);
+ indexed_modcallable_free(&components[i]);
}
instance_list_free(&module_instance_list);
/*
* Find a module instance.
*/
-static module_instance_t *find_module_instance(const char *instname)
+module_instance_t *find_module_instance(const char *instname)
{
CONF_SECTION *cs, *inst_cs;
const char *name1, *name2;
free(node);
return NULL;
}
-
+
/*
* We're done. Fill in the rest of the data structure,
* and link it to the module instance list.
return node;
}
-static indexed_config_module_t *lookup_by_index(indexed_config_module_t *head, int idx)
+static indexed_modcallable *lookup_by_index(indexed_modcallable *head, int idx)
{
- indexed_config_module_t *p;
+ indexed_modcallable *p;
for (p = head; p != NULL; p = p->next) {
if( p->idx == idx)
return NULL;
}
-/*
- * Add one entry at the end of the config_module_t list.
- */
-static void add_to_list(int comp, module_instance_t *instance, int idx)
+static indexed_modcallable *new_sublist(int comp, int idx)
{
- indexed_config_module_t *subcomp;
- config_module_t *node;
- config_module_t **last;
- config_module_t **head;
-
- /* Step 1 - find the list corresponding to the given index. The
- * caller is responsible for ensuring that one exists by calling
- * new_sublist before calling add_to_list. */
- subcomp = lookup_by_index(components[comp], idx);
- assert(subcomp);
-
- /* Step 2 - walk to the end of that list */
- head = &subcomp->modulelist;
- last = head;
-
- for (node = *head; node != NULL; node = node->next) {
- last = &node->next;
- }
-
- /* Step 3 - put a new config_module_t there */
- node = (config_module_t *) rad_malloc(sizeof(config_module_t));
- node->next = NULL;
- node->instance = instance;
-
- *last = node;
-}
-
-static indexed_config_module_t *new_sublist(int comp, int idx)
-{
- indexed_config_module_t **head = &components[comp];
- indexed_config_module_t *node = *head;
- indexed_config_module_t **last = head;
+ indexed_modcallable **head = &components[comp];
+ indexed_modcallable *node = *head;
+ indexed_modcallable **last = head;
while (node) {
/* It is an error to try to create a sublist that already
return node;
}
-/* Bail out if the module in question does not supply the wanted component */
-static void sanity_check(int comp, module_t *mod, const char *filename,
- int lineno)
+static int indexed_modcall(int comp, int idx, REQUEST *request)
{
- switch (comp) {
- case RLM_COMPONENT_AUTH:
- if (!mod->authenticate) {
- radlog(L_ERR|L_CONS,
- "%s[%d] Module %s does not contain "
- "an 'authenticate' entry\n",
- filename, lineno, mod->name);
- exit(1);
- }
- break;
- case RLM_COMPONENT_AUTZ:
- if (!mod->authorize) {
- radlog(L_ERR|L_CONS,
- "%s[%d] Module %s does not contain "
- "an 'authorize' entry\n",
- filename, lineno, mod->name);
- exit(1);
- }
- break;
- case RLM_COMPONENT_PREACCT:
- if (!mod->preaccounting) {
- radlog(L_ERR|L_CONS,
- "%s[%d] Module %s does not contain "
- "a 'preacct' entry\n",
- filename, lineno, mod->name);
- exit(1);
- }
- break;
- case RLM_COMPONENT_ACCT:
- if (!mod->accounting) {
- radlog(L_ERR|L_CONS,
- "%s[%d] Module %s does not contain "
- "an 'accounting' entry\n",
- filename, lineno, mod->name);
- exit(1);
- }
- break;
- case RLM_COMPONENT_SESS:
- if (!mod->checksimul) {
- radlog(L_ERR|L_CONS,
- "%s[%d] Module %s does not contain "
- "a 'checksimul' entry\n",
- filename, lineno, mod->name);
- exit(1);
+ indexed_modcallable *this;
+
+ this = lookup_by_index(components[comp], idx);
+ if (!this) {
+ /* Return a default value appropriate for the component */
+ switch(comp) {
+ case RLM_COMPONENT_AUTZ: return RLM_MODULE_NOTFOUND;
+ case RLM_COMPONENT_AUTH: return RLM_MODULE_REJECT;
+ case RLM_COMPONENT_PREACCT: return RLM_MODULE_NOOP;
+ case RLM_COMPONENT_ACCT: return RLM_MODULE_NOOP;
+ case RLM_COMPONENT_SESS: return RLM_MODULE_FAIL;
+ default: return RLM_MODULE_FAIL;
}
- break;
- default:
- radlog(L_ERR|L_CONS, "%s[%d] Unknown component %d.\n",
- filename, lineno, comp);
- exit(1);
}
+ return modcall(comp, this->modulelist, request);
}
/* Load a flat module list, as found inside an authtype{} block */
static void load_subcomponent_section(CONF_SECTION *cs, int comp, const char *filename)
{
- module_instance_t *this;
- CONF_ITEM *modref;
- int modreflineno;
- const char *modrefname;
int idx;
+ indexed_modcallable *subcomp;
static int meaningless_counter = 1;
* nor checked for uniqueness, but all that could be fixed in a few
* minutes, if anyone finds a real use for indexed config of
* components other than auth. */
- switch (comp) {
- case RLM_COMPONENT_AUTH:
+ if (comp==RLM_COMPONENT_AUTH)
idx = new_authtype_value(cf_section_name2(cs));
- break;
- default:
+ else
idx = meaningless_counter++;
- break;
- }
- if (!new_sublist(comp, idx)) {
+ subcomp = new_sublist(comp, idx);
+ if (!subcomp) {
radlog(L_ERR|L_CONS,
"%s[%d] %s %s already configured - skipping",
filename, cf_section_lineno(cs),
return;
}
- for(modref=cf_item_find_next(cs, NULL)
- ; modref ;
- modref=cf_item_find_next(cs, modref)) {
-
- if(cf_item_is_section(modref)) {
- CONF_SECTION *scs;
- scs = cf_itemtosection(modref);
- modreflineno = cf_section_lineno(scs);
- modrefname = cf_section_name1(scs);
- } else {
- CONF_PAIR *cp;
- cp = cf_itemtopair(modref);
- modreflineno = cf_pair_lineno(cp);
- modrefname = cf_pair_attr(cp);
- }
-
- this = find_module_instance(modrefname);
- if (this == NULL) {
- /* find_module_instance logs any errors */
- exit(1);
- }
-
- sanity_check(comp, this->entry->module, filename, modreflineno);
- add_to_list(comp, this, idx);
- }
+ subcomp->modulelist = compile_modgroup(comp, cs, filename);
}
static void load_component_section(CONF_SECTION *cs, int comp, const char *filename)
{
- module_instance_t *this;
+ modcallable *this;
CONF_ITEM *modref;
int modreflineno;
- const char *modrefname;
int idx;
+ indexed_modcallable *subcomp;
+ char *modname;
for(modref=cf_item_find_next(cs, NULL)
; modref ;
if(cf_item_is_section(modref)) {
CONF_SECTION *scs;
scs = cf_itemtosection(modref);
+
if (!strcmp(cf_section_name1(scs),
subcomponent_names[comp])) {
load_subcomponent_section(scs, comp, filename);
continue;
}
+
modreflineno = cf_section_lineno(scs);
- modrefname = cf_section_name1(scs);
} else {
CONF_PAIR *cp;
cp = cf_itemtopair(modref);
modreflineno = cf_pair_lineno(cp);
- modrefname = cf_pair_attr(cp);
}
- /*
- * Find an instance for this module.
- * This means link to one if it already exists,
- * or instantiate one, or load the library and
- * instantiate/link.
- */
- this = find_module_instance(modrefname);
- if (this == NULL) {
- /* find_module_instance logs any errors */
- exit(1);
- }
-
- sanity_check(comp, this->entry->module, filename, modreflineno);
+ this = compile_modsingle(comp, modref, filename, &modname);
- switch (comp) {
- case RLM_COMPONENT_AUTH:
- idx = new_authtype_value(this->name);
- break;
- default:
+ if (comp==RLM_COMPONENT_AUTH) {
+ idx = new_authtype_value(modname);
+ } else {
/* See the comment in new_sublist() for explanation
* of the special index 0 */
idx = 0;
- break;
}
- if (!new_sublist(comp, idx)) {
+ subcomp = new_sublist(comp, idx);
+ if (!subcomp) {
radlog(L_ERR|L_CONS,
"%s[%d] %s %s already configured - skipping",
filename, modreflineno, subcomponent_names[comp],
- this->name);
+ modname);
+ modcallable_free(&this);
continue;
}
- add_to_list(comp, this, idx);
+
+ /* If subcomp->modulelist is NULL, add_to_modcallable will
+ * create it */
+ add_to_modcallable(&subcomp->modulelist, this,
+ comp, modreflineno);
}
}
return 0;
}
-#if HAVE_PTHREAD_H
-/*
- * Lock the mutex for the module
- */
-static void safe_lock(module_instance_t *instance)
-{
- if (instance->mutex) pthread_mutex_lock(instance->mutex);
-}
-
-/*
- * Unlock the mutex for the module
- */
-static void safe_unlock(module_instance_t *instance)
-{
- if (instance->mutex) pthread_mutex_unlock(instance->mutex);
-}
-#else
-/*
- * No threads: these functions become NULL's.
- */
-#define safe_lock(foo)
-#define safe_unlock(foo)
-#endif
-
/*
* Call all authorization modules until one returns
* somethings else than RLM_MODULE_OK
*/
int module_authorize(REQUEST *request)
{
- config_module_t *this;
- int rcode = RLM_MODULE_OK;
-
- this = lookup_by_index(components[RLM_COMPONENT_AUTZ], 0)->modulelist;
- rcode = RLM_MODULE_OK;
-
- while (this && rcode == RLM_MODULE_OK) {
- DEBUG2(" authorize: %s", this->instance->entry->module->name);
- safe_lock(this->instance);
- rcode = (this->instance->entry->module->authorize)(
- this->instance->insthandle, request);
- safe_unlock(this->instance);
- this = this->next;
- }
-
- return rcode;
+ return indexed_modcall(RLM_COMPONENT_AUTZ, 0, request);
}
/*
*/
int module_authenticate(int auth_type, REQUEST *request)
{
- config_module_t *this;
- int rcode = RLM_MODULE_FAIL;
-
- this = lookup_by_index(components[RLM_COMPONENT_AUTH],
- auth_type)->modulelist;
-
- while (this && rcode == RLM_MODULE_FAIL) {
- DEBUG2(" authenticate: %s",
- this->instance->entry->module->name);
- safe_lock(this->instance);
- rcode = (this->instance->entry->module->authenticate)(
- this->instance->insthandle, request);
- safe_unlock(this->instance);
- this = this->next;
- }
-
- return rcode;
+ return indexed_modcall(RLM_COMPONENT_AUTH, auth_type, request);
}
-
/*
* Do pre-accounting for ALL configured sessions
*/
int module_preacct(REQUEST *request)
{
- config_module_t *this;
- int rcode;
-
- this = lookup_by_index(components[RLM_COMPONENT_PREACCT], 0)->modulelist;
- rcode = RLM_MODULE_OK;
-
- while (this && (rcode == RLM_MODULE_OK)) {
- DEBUG2(" preacct: %s", this->instance->entry->module->name);
- safe_lock(this->instance);
- rcode = (this->instance->entry->module->preaccounting)
- (this->instance->insthandle, request);
- safe_unlock(this->instance);
- this = this->next;
- }
-
- return rcode;
+ return indexed_modcall(RLM_COMPONENT_PREACCT, 0, request);
}
/*
*/
int module_accounting(REQUEST *request)
{
- config_module_t *this;
- int rcode;
-
- this = lookup_by_index(components[RLM_COMPONENT_ACCT], 0)->modulelist;
- rcode = RLM_MODULE_OK;
-
- while (this && (rcode == RLM_MODULE_OK)) {
- DEBUG2(" accounting: %s", this->instance->entry->module->name);
- safe_lock(this->instance);
- rcode = (this->instance->entry->module->accounting)
- (this->instance->insthandle, request);
- safe_unlock(this->instance);
- this = this->next;
- }
-
- return rcode;
+ return indexed_modcall(RLM_COMPONENT_ACCT, 0, request);
}
/*
*/
int module_checksimul(REQUEST *request, int maxsimul)
{
- config_module_t *this;
int rcode;
if(!components[RLM_COMPONENT_SESS])
request->simul_max = maxsimul;
request->simul_mpp = 1;
- this = lookup_by_index(components[RLM_COMPONENT_SESS], 0)->modulelist;
- rcode = RLM_MODULE_FAIL;
-
- while (this && (rcode == RLM_MODULE_FAIL)) {
- DEBUG2(" checksimul: %s", this->instance->entry->module->name);
- safe_lock(this->instance);
- rcode = (this->instance->entry->module->checksimul)
- (this->instance->insthandle, request);
- safe_unlock(this->instance);
- this = this->next;
- }
+ rcode = indexed_modcall(RLM_COMPONENT_SESS, 0, request);
if(rcode != RLM_MODULE_OK) {
/* FIXME: Good spot for a *rate-limited* warning to the log */