]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add load/unload callbacks when symbols are found in shared objects
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 2 Mar 2017 19:23:01 +0000 (14:23 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 2 Mar 2017 19:53:40 +0000 (14:53 -0500)
src/include/dl.h
src/main/dl.c
src/main/listen.c
src/main/modules.c
src/main/radiusd.c
src/modules/rlm_cache/rlm_cache.c
src/modules/rlm_eap/rlm_eap.c
src/modules/rlm_sql/rlm_sql.c

index fc0f70e1d4e92f5dc4932998b5785419dfb70ea9..7fed7523cea117ff49d72fcacef9273817530be1 100644 (file)
@@ -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
 }
index a12c65860f0dbad3c0cd53d6aa6a46190def4640..2f8f64115a20e9d18984fc569f6c3e02496bb241 100644 (file)
@@ -25,6 +25,7 @@ RCSID("$Id$")
 
 #include <ctype.h>
 #include <freeradius-devel/dl.h>
+#include <freeradius-devel/cursor.h>
 #include <freeradius-devel/rad_assert.h>
 #include <freeradius-devel/radiusd.h>
 
@@ -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. "<modname>_" 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. "<modname>_" 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_<mod>_', '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, "<INVALID>"),
+                                                            parent->common->name, name);
+       } else {
+               to_find.name = module_name = talloc_asprintf(NULL, "%s_%s",
+                                                            fr_int2str(dl_type_prefix, type, "<INVALID>"),
+                                                            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);
+}
index 149d6e1e5116ef0d434c26216f35759f468e85a5..f2b0a97b954936956838ba129edaab108f3c774d 100644 (file)
@@ -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;
 
index aa99d5fa31ed81758328be240355e3d96ddd0420..c789640ddfe0567b6c6805ac45c29988c564d79c 100644 (file)
@@ -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;
index 1ecf89dccd5ca818a337e1d0e786ff4c03d50504..8e34a13d4795db79b04018d5b83312636e268444 100644 (file)
@@ -790,7 +790,6 @@ cleanup:
        return rcode;
 }
 
-
 /*
  *  Display the syntax for starting this program.
  */
index 7fc0a97ddfd8688f2a891f26f7f2adfd6450308d..6c9cbc679696792e50f3810f7e298721ea2ef18c 100644 (file)
@@ -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",
index e698d181e5d9736479fd5dad19d098fe53b28e04..a70e6ab30706fd70ce7ff8dbffe9a31e16895900 100644 (file)
@@ -33,6 +33,7 @@ RCSID("$Id$")
 #include <freeradius-devel/dl.h>
 #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",
index 64e9758a451c244c18a90e512a2937c7b26999d5..418cba9c632a9aa6c03cd96b1e8548361e71e142 100644 (file)
@@ -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",