From f531e7a8adad5081b4ec998abfe8b548eefaea9f Mon Sep 17 00:00:00 2001 From: Arran Cudbard-Bell Date: Thu, 2 Mar 2017 14:23:01 -0500 Subject: [PATCH] Add load/unload callbacks when symbols are found in shared objects --- src/include/dl.h | 59 +++- src/main/dl.c | 454 +++++++++++++++++++++++++----- src/main/listen.c | 2 +- src/main/modules.c | 2 +- src/main/radiusd.c | 1 - src/modules/rlm_cache/rlm_cache.c | 5 +- src/modules/rlm_eap/rlm_eap.c | 4 +- src/modules/rlm_sql/rlm_sql.c | 5 +- 8 files changed, 447 insertions(+), 85 deletions(-) diff --git a/src/include/dl.h b/src/include/dl.h index fc0f70e1d4e9..7fed7523cea1 100644 --- a/src/include/dl.h +++ b/src/include/dl.h @@ -43,6 +43,14 @@ extern "C" { */ #define RLM_MODULE_INIT RADIUSD_MAGIC_NUMBER +typedef enum { + DL_TYPE_MODULE = 0, //!< Standard loadable module. + DL_TYPE_PROTO, //!< Protocol module. + DL_TYPE_SUBMODULE //!< Driver (or method in the case of EAP) +} dl_module_type_t; + +typedef struct dl_module dl_module_t; + /** Called when a module is first loaded * * Used to perform global library initialisation. @@ -82,22 +90,41 @@ typedef void (*module_unload_t)(void); */ typedef int (*module_detach_t)(void *instance); +/** Callback to call when a module is first loaded + * + * @param[in] module being loaded. + * @param[in] symbol in module's symbol table, who's presence triggered this function. + * @param[in] user_ctx passed to dl_module_init_register. + * @return + * - 0 on success. + * - -1 on failure + */ +typedef int (*dl_module_init_t)(dl_module_t const *module, void *symbol, void *user_ctx); + + +/** Callback when a module is destroyed + * + * @param[in] module being loaded. + * @param[in] symbol in module's symbol table, who's presence triggered this function. + * @param[in] user_ctx passed to dl_module_init_register + */ +typedef void (*dl_module_free_t)(dl_module_t const *module, void *symbol, void *user_ctx); + /** Common fields for the interface struct modules export * */ #define RAD_MODULE_COMMON \ struct { \ - uint64_t magic; \ - char const *name; \ - size_t inst_size; \ - CONF_PARSER const *config; \ - module_load_t load; \ - module_unload_t unload; \ - module_detach_t detach; \ + uint64_t magic; \ + char const *name; \ + size_t inst_size; \ + CONF_PARSER const *config; \ + module_load_t load; \ + module_unload_t unload; \ + module_detach_t detach; \ } /** Fields common to all types of loadable modules - * */ typedef struct dl_module_common { RAD_MODULE_COMMON; @@ -107,16 +134,26 @@ typedef struct dl_module_common { * * Contains module's dlhandle, and the functions it exports. */ -typedef struct dl_module { +struct dl_module { char const *name; //!< Name of the module e.g. sql. + dl_module_t const *parent; //!< of this module. + dl_module_type_t type; //!< The type of module. dl_module_common_t const *common; //!< Symbol exported by the module, containing its public //!< functions, name and behaviour control flags. void *handle; //!< Handle returned by dlopen. -} dl_module_t; +}; + +int dl_module_sym_init_register(char const *symbol, dl_module_init_t func, void *ctx); + +int dl_module_sym_free_register(char const *symbol, dl_module_free_t func, void *ctx); int dl_module_instance_data_alloc(void **out, TALLOC_CTX *ctx, dl_module_t const *module, CONF_SECTION *cs); -dl_module_t const *dl_module(CONF_SECTION *conf, char const *name, char const *prefix); + +dl_module_t const *dl_module_by_symbol(void *sym); + +dl_module_t const *dl_module(CONF_SECTION *conf, dl_module_t const *parent, + char const *name, dl_module_type_t type); #ifdef __cplusplus } diff --git a/src/main/dl.c b/src/main/dl.c index a12c65860f0d..2f8f64115a20 100644 --- a/src/main/dl.c +++ b/src/main/dl.c @@ -25,6 +25,7 @@ RCSID("$Id$") #include #include +#include #include #include @@ -49,13 +50,126 @@ RCSID("$Id$") # define DL_EXTENSION ".so" #endif +/** Symbol dependent initialisation callback + * + * Call this function when the module is loaded for the first time. + */ +typedef struct dl_module_sym_init dl_module_sym_init_t; +struct dl_module_sym_init { + char const *symbol; //!< to search for. May be NULL in which case func is always called. + dl_module_init_t func; //!< to call when symbol is found in a module's symbol table. + void *ctx; //!< User data to pass to func. + dl_module_sym_init_t *next; +}; + +/** Symbol dependent free callback + * + * Call this function before the module is unloaded. + */ +typedef struct dl_module_sym_free dl_module_sym_free_t; +struct dl_module_sym_free { + char const *symbol; //!< to search for. May be NULL in which case func is always called. + dl_module_free_t func; //!< to call when symbol is found in a module's symbol table. + void *ctx; //!< User data to pass to func. + dl_module_sym_free_t *next; +}; + +/** Name prefixes matching the types of loadable module + */ +static FR_NAME_NUMBER const dl_type_prefix[] = { + { "rlm", DL_TYPE_MODULE }, + { "proto", DL_TYPE_PROTO }, + { "", DL_TYPE_SUBMODULE }, + { NULL , -1 }, +}; + /** Path to search for modules in * */ char const *radlib_dir = NULL; +static rbtree_t *dl_module_sym_init_tree = NULL; +static rbtree_t *dl_module_sym_free_tree = NULL; +static rbtree_t *dl_module_sym_tree = NULL; static rbtree_t *dl_handle_tree = NULL; +static int dl_init(void); +static void dl_free(void); + +static int dl_module_sym_init_cmp(void const *one, void const *two) +{ + dl_module_sym_init_t const *a = one; + dl_module_sym_init_t const *b = two; + + if (a->symbol && !b->symbol) return +1; + if (!b->symbol && a->symbol) return -1; + if (a->symbol && b->symbol) return 0; + + return strcmp(a->symbol, b->symbol); +} + +static int dl_module_sym_free_cmp(void const *one, void const *two) +{ + dl_module_sym_free_t const *a = one; + dl_module_sym_free_t const *b = two; + + if (a->symbol && !b->symbol) return +1; + if (!b->symbol && a->symbol) return -1; + if (a->symbol && b->symbol) return 0; + + return strcmp(a->symbol, b->symbol); +} + +static int dl_module_sym_cmp(void const *one, void const *two) +{ + dl_module_t const *a = one; + dl_module_t const *b = two; + + if (a->common > b->common) return +1; + if (a->common < b->common) return -1; + + return 0; +} + +/** Compare the name of two dl_module_t + * + */ +static int dl_handle_cmp(void const *one, void const *two) +{ + return strcmp(((dl_module_t const *)one)->name, ((dl_module_t const *)two)->name); +} + +/* Call the load() function in a module's exported structure + * + * @param[in] dl_module to call the load function for. + * @param[in] symbol UNUSED. + * @param[in] ctx UNUSED. + * @return + * - 0 on success. + * - -1 on failure. + */ +static int dl_module_call_load_func(dl_module_t const *dl_module, UNUSED void *symbol, UNUSED void *ctx) +{ + if (dl_module->common->load && (dl_module->common->load() < 0)) { + ERROR("Initialisation failed for module \"%s\"", dl_module->common->name); + return -1; + } + + return 0; +} + +/* Call the unload() function in a module's exported structure + * + * @param[in] dl_module to call the unload function for. + * @param[in] symbol UNUSED. + * @param[in] ctx UNUSED. + */ +static void dl_module_call_unload_func(dl_module_t const *dl_module, UNUSED void *symbol, UNUSED void *ctx) +{ + if (dl_module->common->unload) dl_module->common->unload(); +} + + /** Check if the magic number in the module matches the one in the library * * This is used to detect potential ABI issues caused by running with modules which @@ -235,20 +349,127 @@ static void *dl_by_name(char const *name) return handle; } -/** Compare the name of two dl_module_t +/** Allocate module instance data, and parse the module's configuration * + * @param[out] data Module's private data, the result of parsing the config. + * @param[in] ctx to allocate this instance data in. + * @param[in] module to alloc instance data for. + * @param[in] cs module's config section. + * @return + * - 0 on success. + * - -1 on failure. */ -static int dl_handle_cmp(void const *one, void const *two) +int dl_module_instance_data_alloc(void **data, TALLOC_CTX *ctx, dl_module_t const *module, CONF_SECTION *cs) { - dl_module_t const *a = one; - dl_module_t const *b = two; + *data = NULL; + + if (module->common->inst_size == 0) return 0; - return strcmp(a->name, b->name); + /* + * If there is supposed to be instance data, allocate it now. + * Also parse the configuration data, if required. + */ + MEM(*data = talloc_zero_array(ctx, uint8_t, module->common->inst_size)); + + talloc_set_name(*data, "%s_t", module->name ? module->name : "config"); + if (module->common->config && (cf_section_parse(cs, *data, module->common->config) < 0)) { + cf_log_err_cs(cs, "Invalid configuration for module \"%s\"", module->name); + talloc_free(*data); + return -1; + } + + /* + * Set the destructor. + */ + if (module->common->detach) talloc_set_destructor((void *)*data, module->common->detach); + + return 0; +} + +/** Walk over the registered init callbacks, searching for the symbols they depend on + * + * Allows code outside of the dl API to register initialisation functions that get + * executed depending on whether the module exports a particular symbol. + * + * This cuts down the amount of boilerplate code in 'mod_load' functions. + * + * @param[in] ctx The dl_module handle to operate on. + * @param[in] data The callback to call. + * @return + * - 0 continue walking. + * - -1 error. + */ +static int _dl_module_sym_init_walk(void *ctx, void *data) +{ + dl_module_sym_init_t *head = talloc_get_type_abort(data, dl_module_sym_init_t), *init; + dl_module_t *dl_module = talloc_get_type_abort(ctx, dl_module_t); + void *sym = NULL; + fr_cursor_t cursor; + + if (head->symbol) { + char *sym_name = NULL; + + MEM(sym_name = talloc_asprintf(NULL, "%s_%s", dl_module->name, head->symbol)); + sym = dlsym(dl_module->handle, sym_name); + talloc_free(sym_name); + + if (!sym) return 0; + } + + for (init = fr_cursor_talloc_init(&cursor, &head, dl_module_sym_init_t); + init; + init = fr_cursor_next(&cursor)) { + if (init->func(dl_module, sym, init->ctx) < 0) return -1; + } + + return 0; +} + +/** Walk over the registered init callbacks, searching for the symbols they depend on + * + * Allows code outside of the dl API to register initialisation functions that get + * executed depending on whether the module exports a particular symbol. + * + * This cuts down the amount of boilerplate code in 'mod_unload' functions. + * + * @param[in] ctx The dl_module handle to operate on. + * @param[in] data The callback to call. + * @return + * - 0 continue walking. + * - -1 found suitable node. + */ +static int _dl_module_sym_free_walk(void *ctx, void *data) +{ + dl_module_sym_free_t *head = talloc_get_type_abort(data, dl_module_sym_free_t), *free; + dl_module_t *dl_module = talloc_get_type_abort(ctx, dl_module_t); + void *sym = NULL; + fr_cursor_t cursor; + + if (head->symbol) { + char *sym_name = NULL; + + MEM(sym_name = talloc_asprintf(NULL, "%s_%s", dl_module->name, head->symbol)); + sym = dlsym(dl_module->handle, sym_name); + talloc_free(sym_name); + + if (!sym) return 0; + } + + for (free = fr_cursor_talloc_init(&cursor, &head, dl_module_sym_init_t); + free; + free = fr_cursor_next(&cursor)) { + free->func(dl_module, sym, free->ctx); + } + + return 0; } /** Free a module * * Close module's dlhandle, unloading it. + * + * @param[in] dl_module to close. + * @return 0. */ static int _dl_module_free(dl_module_t *dl_module) { @@ -256,7 +477,7 @@ static int _dl_module_free(dl_module_t *dl_module) DEBUG3("Unloading module \"%s\" (%p/%p)", dl_module->name, dl_module->handle, dl_module->common); - if (dl_module->common->unload) dl_module->common->unload(); + rbtree_walk(dl_module_sym_free_tree, RBTREE_IN_ORDER, _dl_module_sym_free_walk, dl_module); /* * Only dlclose() handle if we're *NOT* running under valgrind @@ -267,99 +488,145 @@ static int _dl_module_free(dl_module_t *dl_module) dl_module->handle = NULL; rbtree_deletebydata(dl_handle_tree, dl_module); + rbtree_deletebydata(dl_module_sym_tree, dl_module); - /* - * Final cleanup... - */ - if (rbtree_num_elements(dl_handle_tree) == 0) rbtree_free(dl_handle_tree); + if (rbtree_num_elements(dl_handle_tree) == 0) dl_free(); return 0; } -/** Allocate module instance data, and parse the module's configuration +/** Register a callback to execute when a module is first loaded * - * @param[out] data Module's private data, the result of parsing the config. - * @param[in] ctx to allocate this instance data in. - * @param[in] module to alloc instance data for. - * @param[in] cs module's config section. + * @param[in] symbol that determines whether func should be called. "_" is + * added as a prefix to the symbol. The prefix is added because + * some modules are loaded with RTLD_GLOBAL into the global symbol + * space, so the symbols they export must be unique. + * May be NULL to always call the function. + * @param[in] func to register. Called when module is loaded. + * @param[in] ctx to pass to func. * @return - * - 0 on success. + * - 0 on success (or already registered). * - -1 on failure. */ -int dl_module_instance_data_alloc(void **data, TALLOC_CTX *ctx, dl_module_t const *module, CONF_SECTION *cs) +int dl_module_sym_init_register(char const *symbol, dl_module_init_t func, void *ctx) { - *data = NULL; + dl_module_sym_init_t find, *found, *new; - if (module->common->inst_size == 0) return 0; + MEM(new = talloc(dl_module_sym_init_tree, dl_module_sym_init_t)); + new->symbol = symbol; + new->func = func; + new->ctx = ctx; - /* - * If there is supposed to be instance data, allocate it now. - * Also parse the configuration data, if required. - */ - MEM(*data = talloc_zero_array(ctx, uint8_t, module->common->inst_size)); + find.symbol = symbol; + find.func = func; - talloc_set_name(*data, "%s_t", module->name ? module->name : "config"); - if (module->common->config && (cf_section_parse(cs, *data, module->common->config) < 0)) { - cf_log_err_cs(cs, "Invalid configuration for module \"%s\"", module->name); - talloc_free(*data); - return -1; + found = rbtree_finddata(dl_module_sym_init_tree, &find); + if (found) { + new->next = found; + rbtree_deletebydata(dl_module_sym_init_tree, found); } - /* - * Set the destructor. - */ - if (module->common->detach) talloc_set_destructor((void *)*data, module->common->detach); + rbtree_insert(dl_module_sym_init_tree, new); return 0; } +/** Register a callback to execute when a module is first loaded + * + * @param[in] symbol that determines whether func should be called. "_" is + * added as a prefix to the symbol. The prefix is added because + * some modules are loaded with RTLD_GLOBAL into the global symbol + * space, so the symbols they export must be unique. + * May be NULL to always call the function. + * @param[in] func to register. Called then module is unloaded. + * @param[in] ctx to pass to func. + * @return + * - 0 on success (or already registered). + * - -1 on failure. + */ +int dl_module_sym_free_register(char const *symbol, dl_module_free_t func, void *ctx) +{ + dl_module_sym_free_t find, *found, *new; + + MEM(new = talloc(dl_module_sym_free_tree, dl_module_sym_free_t)); + new->symbol = symbol; + new->func = func; + new->ctx = ctx; + + find.symbol = symbol; + find.func = func; + found = rbtree_finddata(dl_module_sym_free_tree, &find); + if (found) { + new->next = found; + rbtree_deletebydata(dl_module_sym_free_tree, found); + } + + rbtree_insert(dl_module_sym_free_tree, new); + + return 0; +} + +/** Lookup a dl_module_t via its public symbol + * + */ +dl_module_t const *dl_module_by_symbol(void *sym) +{ + dl_module_t find; + + find.common = sym; + + return rbtree_finddata(dl_module_sym_tree, &find); +} + /** Load a module library using dlopen() or return a previously loaded module from the cache * * When the dl_module_t is no longer used, talloc_free() may be used to free it. * - * When all references to the original dlhandle are freed, dlclose() wiill be called on the + * When all references to the original dlhandle are freed, dlclose() will be called on the * dlhandle to unload the module. * * @param[in] conf section describing the module's configuration. - * @param[in] name of the module. - * @param[in] prefix appropriate for the module type ('rlm_', 'rlm__', 'proto_'). + * @param[in] parent The dl_module_t of the parent module, e.g. rlm_sql for rlm_sql_postgresql. + * @param[in] name of the module e.g. sql for rlm_sql. + * @param[in] type Used to determine module name prefixes. Must be one of: + * - DL_TYPE_MODULE + * - DL_TYPE_PROTO + * - DL_TYPE_SUBMODULE * @return * - Module handle holding dlhandle, and module's public interface structure. * - NULL if module couldn't be loaded, or some other error occurred. */ -dl_module_t const *dl_module(CONF_SECTION *conf, char const *name, char const *prefix) +dl_module_t const *dl_module(CONF_SECTION *conf, dl_module_t const *parent, char const *name, dl_module_type_t type) { dl_module_t to_find; dl_module_t *dl_module = NULL; void *handle = NULL; - char *module_name; + char *module_name = NULL; char *p, *q; dl_module_common_t const *module; - to_find.name = module_name = talloc_asprintf(NULL, "%s%s", prefix, name); + if (!dl_handle_tree) dl_init(); + + if (parent) { + to_find.name = module_name = talloc_asprintf(NULL, "%s_%s_%s", + fr_int2str(dl_type_prefix, parent->type, ""), + parent->common->name, name); + } else { + to_find.name = module_name = talloc_asprintf(NULL, "%s_%s", + fr_int2str(dl_type_prefix, type, ""), + name); + } for (p = module_name, q = p + talloc_array_length(p) - 1; p < q; p++) *p = tolower(*p); /* - * Because we're lazy and initialization functions are a pain. + * If the module's already been loaded, increment the reference count. */ - if (!dl_handle_tree) { - dl_handle_tree = rbtree_create(NULL, dl_handle_cmp, NULL, 0); - if (!dl_handle_tree) { - ERROR("Failed initialising dl_handle_tree"); - error: - talloc_free(module_name); - if (handle) dlclose(handle); - talloc_free(dl_module); - return NULL; - } - } else { - dl_module = rbtree_finddata(dl_handle_tree, &to_find); - if (dl_module) { - talloc_free(module_name); - talloc_increase_ref_count(dl_module); - return dl_module; - } + dl_module = rbtree_finddata(dl_handle_tree, &to_find); + if (dl_module) { + talloc_free(module_name); + talloc_increase_ref_count(dl_module); + return dl_module; } /* @@ -370,7 +637,11 @@ dl_module_t const *dl_module(CONF_SECTION *conf, char const *name, char const *p cf_log_err_cs(conf, "Failed to link to module \"%s\": %s", module_name, fr_strerror()); cf_log_err_cs(conf, "Make sure it (and all its dependent libraries!) are in the search path" " of your system's ld"); - goto error; + error: + talloc_free(module_name); + if (handle) dlclose(handle); + talloc_free(dl_module); + return NULL; } DEBUG3("Loaded \"%s\", checking if it's valid", module_name); @@ -390,26 +661,27 @@ dl_module_t const *dl_module(CONF_SECTION *conf, char const *name, char const *p /* make room for the module type */ dl_module = talloc_zero(dl_handle_tree, dl_module_t); + dl_module->parent = parent; dl_module->common = module; dl_module->handle = handle; + dl_module->type = type; dl_module->name = talloc_steal(dl_module, module_name); /* - * Perform global library initialisation + * Call initialisation functions */ - if (dl_module->common->load && (dl_module->common->load() < 0)) { - cf_log_err_cs(conf, "Initialisation failed for module \"%s\"", dl_module->common->name); + if (rbtree_walk(dl_module_sym_init_tree, RBTREE_IN_ORDER, _dl_module_sym_init_walk, dl_module) < 0) { + cf_log_err_cs(conf, "Module initialisation failed \"%s\"", module_name); goto error; } cf_log_module(conf, "Loaded module \"%s\"", module_name); /* - * Add the module as "rlm_foo-version" to the configuration - * section. + * Add the module to the dlhandle cache */ - if (!rbtree_insert(dl_handle_tree, dl_module)) { - ERROR("Failed to cache module \"%s\"", module_name); + if (!rbtree_insert(dl_handle_tree, dl_module) || !rbtree_insert(dl_module_sym_tree, dl_module)) { + cf_log_err_cs(conf, "Failed to cache module \"%s\"", module_name); goto error; } @@ -417,3 +689,55 @@ dl_module_t const *dl_module(CONF_SECTION *conf, char const *name, char const *p return dl_module; } + +/** Initialise structures needed by the dynamic linker + * + */ +static int dl_init(void) +{ + if (dl_handle_tree && dl_module_sym_init_tree) return 0; + + dl_handle_tree = rbtree_create(NULL, dl_handle_cmp, NULL, 0); + if (!dl_handle_tree) { + ERROR("Failed initialising dl_handle_tree"); + return -1; + } + + dl_module_sym_init_tree = rbtree_create(NULL, dl_module_sym_init_cmp, NULL, 0); + if (!dl_module_sym_init_tree) { + ERROR("Failed initialising dl_module_sym_init_tree"); + return -1; + } + + dl_module_sym_free_tree = rbtree_create(NULL, dl_module_sym_free_cmp, NULL, 0); + if (!dl_module_sym_free_tree) { + ERROR("Failed initialising dl_module_sym_init_tree"); + return -1; + } + + dl_module_sym_tree = rbtree_create(NULL, dl_module_sym_cmp, NULL, 0); + if (!dl_module_sym_tree) { + ERROR("Failed initialising dl_module_sym_tree"); + return -1; + } + + if (dl_module_sym_init_register(NULL, dl_module_call_load_func, NULL) < 0) { + ERROR("Failed registering load() callback"); + return -1; + } + + if (dl_module_sym_free_register(NULL, dl_module_call_unload_func, NULL) < 0) { + ERROR("Failed registering unload() callback"); + return -1; + } + + return 0; +} + +static void dl_free(void) +{ + talloc_free(dl_handle_tree); + talloc_free(dl_module_sym_init_tree); + talloc_free(dl_module_sym_free_tree); + talloc_free(dl_module_sym_tree); +} diff --git a/src/main/listen.c b/src/main/listen.c index 149d6e1e5116..f2b0a97b9549 100644 --- a/src/main/listen.c +++ b/src/main/listen.c @@ -198,7 +198,7 @@ int listen_bootstrap(CONF_SECTION *server, CONF_SECTION *cs, char const *server_ value = buffer; } - module = dl_module(cs, value, "proto_"); + module = dl_module(cs, NULL, value, DL_TYPE_PROTO); if (!module) return -1; proto = (rad_protocol_t const *)module->common; diff --git a/src/main/modules.c b/src/main/modules.c index aa99d5fa31ed..c789640ddfe0 100644 --- a/src/main/modules.c +++ b/src/main/modules.c @@ -873,7 +873,7 @@ static module_instance_t *module_bootstrap(CONF_SECTION *modules, CONF_SECTION * /* * Load the module shared library. */ - module = dl_module(cs, name1, "rlm_"); + module = dl_module(cs, NULL, name1, DL_TYPE_MODULE); if (!module) { talloc_free(instance); return NULL; diff --git a/src/main/radiusd.c b/src/main/radiusd.c index 1ecf89dccd5c..8e34a13d4795 100644 --- a/src/main/radiusd.c +++ b/src/main/radiusd.c @@ -790,7 +790,6 @@ int main(int argc, char *argv[]) return rcode; } - /* * Display the syntax for starting this program. */ diff --git a/src/modules/rlm_cache/rlm_cache.c b/src/modules/rlm_cache/rlm_cache.c index 7fc0a97ddfd8..6c9cbc679696 100644 --- a/src/modules/rlm_cache/rlm_cache.c +++ b/src/modules/rlm_cache/rlm_cache.c @@ -34,6 +34,8 @@ RCSID("$Id$") #include "rlm_cache.h" +extern rad_module_t rlm_cache; + static const CONF_PARSER module_config[] = { { FR_CONF_OFFSET("driver", PW_TYPE_STRING, rlm_cache_config_t, driver_name), .dflt = "rlm_cache_rbtree" }, { FR_CONF_OFFSET("key", PW_TYPE_TMPL | PW_TYPE_REQUIRED, rlm_cache_config_t, key) }, @@ -939,7 +941,7 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) /* * Load the appropriate driver for our backend */ - inst->driver_handle = dl_module(driver_cs, name, "rlm_cache_"); + inst->driver_handle = dl_module(driver_cs, dl_module_by_symbol(&rlm_cache), name, DL_TYPE_SUBMODULE); if (!inst->driver_handle) return -1; inst->driver = (cache_driver_t const *)inst->driver_handle->common; @@ -1003,7 +1005,6 @@ static int mod_instantiate(CONF_SECTION *conf, void *instance) * The server will then take care of ensuring that the module * is single-threaded. */ -extern rad_module_t rlm_cache; rad_module_t rlm_cache = { .magic = RLM_MODULE_INIT, .name = "cache", diff --git a/src/modules/rlm_eap/rlm_eap.c b/src/modules/rlm_eap/rlm_eap.c index e698d181e5d9..a70e6ab30706 100644 --- a/src/modules/rlm_eap/rlm_eap.c +++ b/src/modules/rlm_eap/rlm_eap.c @@ -33,6 +33,7 @@ RCSID("$Id$") #include #include "rlm_eap.h" +extern rad_module_t rlm_eap; static const CONF_PARSER module_config[] = { { FR_CONF_OFFSET("default_eap_type", PW_TYPE_STRING, rlm_eap_config_t, default_method_name), .dflt = "md5" }, @@ -96,7 +97,7 @@ int eap_method_instantiate(rlm_eap_method_t **out, rlm_eap_t *inst, eap_type_t n /* * Load the submodule for the specified EAP method */ - method->submodule_handle = dl_module(cs, eap_type2name(num), "rlm_eap_"); + method->submodule_handle = dl_module(cs, dl_module_by_symbol(&rlm_eap), eap_type2name(num), DL_TYPE_SUBMODULE); if (!method->submodule_handle) return -1; method->submodule = (rlm_eap_submodule_t const *)method->submodule_handle->common; @@ -928,7 +929,6 @@ static rlm_rcode_t mod_post_auth(void *instance, UNUSED void *thread, REQUEST *r * The module name should be the only globally exported symbol. * That is, everything else should be 'static'. */ -extern rad_module_t rlm_eap; rad_module_t rlm_eap = { .magic = RLM_MODULE_INIT, .name = "eap", diff --git a/src/modules/rlm_sql/rlm_sql.c b/src/modules/rlm_sql/rlm_sql.c index 64e9758a451c..418cba9c632a 100644 --- a/src/modules/rlm_sql/rlm_sql.c +++ b/src/modules/rlm_sql/rlm_sql.c @@ -42,6 +42,8 @@ RCSID("$Id$") #include "rlm_sql.h" +extern rad_module_t rlm_sql; + /* * So we can do pass2 xlat checks on the queries. */ @@ -1081,7 +1083,7 @@ static int mod_bootstrap(CONF_SECTION *conf, void *instance) /* * Load the driver */ - inst->driver_handle = dl_module(driver_cs, name, "rlm_sql_"); + inst->driver_handle = dl_module(driver_cs, dl_module_by_symbol(&rlm_sql), name, DL_TYPE_SUBMODULE); if (!inst->driver_handle) return -1; inst->driver = (rlm_sql_driver_t const *)inst->driver_handle->common; @@ -1917,7 +1919,6 @@ static rlm_rcode_t mod_post_auth(void *instance, UNUSED void *thread, REQUEST *r /* globally exported name */ -extern rad_module_t rlm_sql; rad_module_t rlm_sql = { .magic = RLM_MODULE_INIT, .name = "sql",