]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Split out rlm module code from modules.c
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 2 Mar 2022 00:03:48 +0000 (18:03 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Wed, 2 Mar 2022 00:04:14 +0000 (18:04 -0600)
29 files changed:
doc/antora/modules/developers/pages/todo.adoc
src/lib/redis/base.h
src/lib/server/base.c
src/lib/server/libfreeradius-server.mk
src/lib/server/modpriv.h
src/lib/server/module.c
src/lib/server/module.h
src/lib/server/module_rlm.c [new file with mode: 0644]
src/lib/server/module_rlm.h [new file with mode: 0644]
src/lib/unlang/compile.c
src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c
src/modules/rlm_chap/rlm_chap.c
src/modules/rlm_couchbase/rlm_couchbase.c
src/modules/rlm_detail/rlm_detail.c
src/modules/rlm_digest/rlm_digest.c
src/modules/rlm_eap/rlm_eap.c
src/modules/rlm_krb5/rlm_krb5.c
src/modules/rlm_ldap/rlm_ldap.c
src/modules/rlm_linelog/rlm_linelog.c
src/modules/rlm_mschap/rlm_mschap.c
src/modules/rlm_opendirectory/rlm_opendirectory.c
src/modules/rlm_pap/rlm_pap.c
src/modules/rlm_rest/rlm_rest.c
src/modules/rlm_sigtran/libosmo-abis [new submodule]
src/modules/rlm_sigtran/libosmo-netif [new submodule]
src/modules/rlm_sql/rlm_sql.c
src/modules/rlm_winbind/rlm_winbind.c
src/modules/rlm_yubikey/rlm_yubikey.c
src/modules/rlm_yubikey/validate.c

index d4ec8d393826a405d76fd5d829b42ff12050ef21..809a8ffda3d5e2b88480de2b53604ee1a2a7d568 100644 (file)
@@ -149,7 +149,7 @@ sections.
 We will hope that the packet names are different in every protocol.
 
 The processing modules can now export a list of _additional_ methods
-that they take. The `*module_by_name_and_method()` function walks down
+that they take. The `*module_rlm_by_name_and_method()` function walks down
 that list:
 
 * if method[COMPONTENT] is set, then return that
index 301dde918631d1242bbda80fd82a3b9142144f40..01560a2a97f1e9396581da6c61baf02b3971160d 100644 (file)
@@ -99,7 +99,7 @@ typedef struct {
 
 /** Configuration parameters for a redis connection
  *
- * @note should be passed as instance data to #module_connection_pool_init.
+ * @note should be passed as instance data to #module_rlm_connection_pool_init.
  */
 typedef struct {
        char const              **hostname;     //!< of Redis server.
index 35ba2ef2b4545942d4f96ec88fcb2d482b379e92..4a779be720dd1349ef5fb32720b44bde5b63f0c1 100644 (file)
@@ -72,7 +72,7 @@ int server_init(CONF_SECTION *cs)
         *
         *      After this step, all dynamic attributes, xlats, etc. are defined.
         */
-       if (modules_bootstrap(cs) < 0) return -1;
+       if (modules_rlm_bootstrap(cs) < 0) return -1;
 
        /*
         *      And then load the virtual servers.
index 3e6501cc85d115d72c26966653fdaee1e6f1aff8..575d6dda586dc44ff73d3c18378434ba342eb800 100644 (file)
@@ -24,6 +24,7 @@ SOURCES       := \
        map_proc.c \
        method.c \
        module.c \
+       module_rlm.c \
        paircmp.c \
        pairmove.c \
        password.c \
@@ -67,7 +68,7 @@ LOG_ID_LIB    := 1
 $(call DEFINE_LOG_ID_SECTION,config,   1,cf_file.c cf_parse.c cf_util.c)
 $(call DEFINE_LOG_ID_SECTION,conditions,2,conf_eval.c cond_tokenize.c)
 $(call DEFINE_LOG_ID_SECTION,exec,     3,exec.c exec_legacy.c)
-$(call DEFINE_LOG_ID_SECTION,modules,  4,dl_module.c module.c method.c)
+$(call DEFINE_LOG_ID_SECTION,modules,  4,dl_module.c module.c module_rlm.c method.c)
 $(call DEFINE_LOG_ID_SECTION,map,      5,map.c map_proc.c map_async.c)
 $(call DEFINE_LOG_ID_SECTION,snmp,     6,snmp.c)
 $(call DEFINE_LOG_ID_SECTION,templates,        7,tmpl_eval.c tmpl_tokenize.c)
index 4b1bef1509155a92c0479cf2d536775494079b67..e1e655ba2ce1caf783c5697247d0cc6b101247fd 100644 (file)
@@ -33,7 +33,14 @@ RCSIDH(modpriv_h, "$Id$")
 #ifdef __cplusplus
 extern "C" {
 #endif
-int                    module_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char const *name);
+
+extern fr_cmd_table_t  module_cmd_table[];
+
+extern fr_cmd_table_t  module_cmd_list_table[];
+
+int                    module_instantiate(void *instance);
+
+int                    module_rlm_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char const *name);
 
 int                    unlang_fixup_update(map_t *map, void *ctx);
 
index a76a2ce661ac31a9eb125d3a4658458f4f1877a6..5caa00a9230e5b95a06bd3f76d6fdaaeb5afbad4 100644 (file)
@@ -32,6 +32,7 @@ RCSID("$Id$")
 #include <freeradius-devel/server/cf_file.h>
 #include <freeradius-devel/server/cond.h>
 #include <freeradius-devel/server/modpriv.h>
+#include <freeradius-devel/server/module_rlm.h>
 #include <freeradius-devel/server/radmin.h>
 #include <freeradius-devel/server/request_data.h>
 
@@ -40,7 +41,7 @@ static size_t instance_num = 1;
 
 /*
  *     For simplicity, this is just array[instance_num].  Once we
- *     finish with modules_bootstrap(), the "instance_num" above MUST
+ *     finish with modules_rlm_bootstrap(), the "instance_num" above MUST
  *     NOT change.
  */
 static _Thread_local module_thread_instance_t **module_thread_inst_array;
@@ -53,38 +54,75 @@ static fr_rb_tree_t *module_instance_name_tree;
  */
 static fr_rb_tree_t *module_instance_data_tree;
 
-/** Lookup virtual module by name
- */
-static fr_rb_tree_t *virtual_module_name_tree;
+static int cmd_show_module_config(FILE *fp, UNUSED FILE *fp_err, void *ctx, UNUSED fr_cmd_info_t const *info);
+static int module_name_tab_expand(UNUSED TALLOC_CTX *talloc_ctx, UNUSED void *uctx, fr_cmd_info_t *info, int max_expansions, char const **expansions);
+static int cmd_show_module_list(FILE *fp, UNUSED FILE *fp_err, UNUSED void *uctx, UNUSED fr_cmd_info_t const *info);
+static int cmd_show_module_status(FILE *fp, UNUSED FILE *fp_err, void *ctx, UNUSED fr_cmd_info_t const *info);
+static int cmd_set_module_status(UNUSED FILE *fp, FILE *fp_err, void *ctx, fr_cmd_info_t const *info);
 
-typedef struct {
-       fr_rb_node_t                    name_node;      //!< Entry in the name tree.
-       char const                      *name;          //!< module name
-       CONF_SECTION                    *cs;            //!< CONF_SECTION where it is defined
-       bool                            all_same;
-} virtual_module_t;
+fr_cmd_table_t module_cmd_table[] = {
+       {
+               .parent = "show module",
+               .add_name = true,
+               .name = "status",
+               .func = cmd_show_module_status,
+               .help = "Show the status of a particular module.",
+               .read_only = true,
+       },
 
+       {
+               .parent = "show module",
+               .add_name = true,
+               .name = "config",
+               .func = cmd_show_module_config,
+               .help = "Show configuration for a module",
+               // @todo - do tab expand, by walking over the whole module list...
+               .read_only = true,
+       },
 
-/** Module command table
- */
-static fr_cmd_table_t cmd_module_table[];
+       {
+               .parent = "set module",
+               .add_name = true,
+               .name = "status",
+               .syntax = "(alive|disallow|fail|reject|handled|invalid|notfound|noop|ok|updated)",
+               .func = cmd_set_module_status,
+               .help = "Change module status to fixed value.",
+               .read_only = false,
+       },
 
-static int _module_instantiate(void *instance);
+       CMD_TABLE_END
+};
 
-static int virtual_module_bootstrap(CONF_SECTION *vm_cs);
+fr_cmd_table_t module_cmd_list_table[] = {
+       {
+               .parent = "show",
+               .name = "module",
+               .help = "Show information about modules.",
+               .tab_expand = module_name_tab_expand,
+               .read_only = true,
+       },
 
-/*
- *     Ordered by component
- */
-const char *section_type_value[MOD_COUNT] = {
-       "authenticate",
-       "authorize",
-       "preacct",
-       "accounting",
-       "post-auth"
-};
+       // @todo - what if there's a module called "list" ?
+       {
+               .parent = "show module",
+               .name = "list",
+               .func = cmd_show_module_list,
+               .help = "Show the list of modules loaded in the server.",
+               .read_only = true,
+       },
+
+       {
+               .parent = "set",
+               .name = "module",
+               .help = "Change module settings.",
+               .tab_expand = module_name_tab_expand,
+               .read_only = false,
+       },
 
 
+       CMD_TABLE_END
+};
+
 static int cmd_show_module_config(FILE *fp, UNUSED FILE *fp_err, void *ctx, UNUSED fr_cmd_info_t const *info)
 {
        module_instance_t *mi = ctx;
@@ -178,71 +216,6 @@ static int cmd_set_module_status(UNUSED FILE *fp, FILE *fp_err, void *ctx, fr_cm
        return 0;
 }
 
-
-static fr_cmd_table_t cmd_module_table[] = {
-       {
-               .parent = "show module",
-               .add_name = true,
-               .name = "status",
-               .func = cmd_show_module_status,
-               .help = "Show the status of a particular module.",
-               .read_only = true,
-       },
-
-       {
-               .parent = "show module",
-               .add_name = true,
-               .name = "config",
-               .func = cmd_show_module_config,
-               .help = "Show configuration for a module",
-               // @todo - do tab expand, by walking over the whole module list...
-               .read_only = true,
-       },
-
-       {
-               .parent = "set module",
-               .add_name = true,
-               .name = "status",
-               .syntax = "(alive|disallow|fail|reject|handled|invalid|notfound|noop|ok|updated)",
-               .func = cmd_set_module_status,
-               .help = "Change module status to fixed value.",
-               .read_only = false,
-       },
-
-       CMD_TABLE_END
-};
-
-
-static fr_cmd_table_t cmd_table[] = {
-       {
-               .parent = "show",
-               .name = "module",
-               .help = "Show information about modules.",
-               .tab_expand = module_name_tab_expand,
-               .read_only = true,
-       },
-
-       // @todo - what if there's a module called "list" ?
-       {
-               .parent = "show module",
-               .name = "list",
-               .func = cmd_show_module_list,
-               .help = "Show the list of modules loaded in the server.",
-               .read_only = true,
-       },
-
-       {
-               .parent = "set",
-               .name = "module",
-               .help = "Change module settings.",
-               .tab_expand = module_name_tab_expand,
-               .read_only = false,
-       },
-
-
-       CMD_TABLE_END
-};
-
 /** Compare module instances by parent and name
  *
  * The reason why we need parent, is because we could have submodules with names
@@ -254,817 +227,79 @@ static int8_t module_instance_name_cmp(void const *one, void const *two)
        module_instance_t const *b = two;
        dl_module_inst_t const  *dl_inst;
        int a_depth = 0, b_depth = 0;
-       int ret;
-
-       /*
-        *      Sort by depth, so for tree walking we start
-        *      at the shallowest node, and finish with
-        *      the deepest child.
-        */
-       for (dl_inst = a->dl_inst; dl_inst; dl_inst = dl_inst->parent) a_depth++;
-       for (dl_inst = b->dl_inst; dl_inst; dl_inst = dl_inst->parent) b_depth++;
-
-       ret = CMP(a_depth, b_depth);
-       if (ret != 0) return ret;
-
-       /*
-        *      This happens, as dl_inst is is used in
-        *      as the loop condition above.
-        */
-#ifdef __clang_analyzer__
-       if (!fr_cond_assert(a->dl_inst)) return +1;
-       if (!fr_cond_assert(b->dl_inst)) return -1;
-#endif
-
-       ret = CMP(a->dl_inst->parent, b->dl_inst->parent);
-       if (ret != 0) return ret;
-
-       ret = strcmp(a->name, b->name);
-       return CMP(ret, 0);
-}
-
-/** Compare module's by their private instance data
- *
- */
-static int8_t module_instance_data_cmp(void const *one, void const *two)
-{
-       void const *a = (((module_instance_t const *)one)->dl_inst)->data;
-       void const *b = (((module_instance_t const *)two)->dl_inst)->data;
-
-       return CMP(a, b);
-}
-
-/** Compare virtual modules by name
- */
-static int8_t virtual_module_name_cmp(void const *one, void const *two)
-{
-       virtual_module_t const *a = one;
-       virtual_module_t const *b = two;
-       int ret;
-
-       ret = strcmp(a->name, b->name);
-       return CMP(ret, 0);
-}
-
-/** Initialise a module specific exfile handle
- *
- * @see exfile_init
- *
- * @param[in] ctx              to bind the lifetime of the exfile handle to.
- * @param[in] module           section.
- * @param[in] max_entries      Max file descriptors to cache, and manage locks for.
- * @param[in] max_idle         Maximum time a file descriptor can be idle before it's closed.
- * @param[in] locking          Whether or not to lock the files.
- * @param[in] trigger_prefix   if NULL will be set automatically from the module CONF_SECTION.
- * @param[in] trigger_args     to make available in any triggers executed by the connection pool.
- * @return
- *     - New connection pool.
- *     - NULL on error.
- */
-exfile_t *module_exfile_init(TALLOC_CTX *ctx,
-                            CONF_SECTION *module,
-                            uint32_t max_entries,
-                            fr_time_delta_t max_idle,
-                            bool locking,
-                            char const *trigger_prefix,
-                            fr_pair_list_t *trigger_args)
-{
-       char            trigger_prefix_buff[128];
-       exfile_t        *handle;
-
-       if (!trigger_prefix) {
-               snprintf(trigger_prefix_buff, sizeof(trigger_prefix_buff), "modules.%s.file", cf_section_name1(module));
-               trigger_prefix = trigger_prefix_buff;
-       }
-
-       handle = exfile_init(ctx, max_entries, max_idle, locking);
-       if (!handle) return NULL;
-
-       exfile_enable_triggers(handle, cf_section_find(module, "file", NULL), trigger_prefix, trigger_args);
-
-       return handle;
-}
-
-/** Resolve polymorphic item's from a module's #CONF_SECTION to a subsection in another module
- *
- * This allows certain module sections to reference module sections in other instances
- * of the same module and share #CONF_DATA associated with them.
- *
- * @verbatim
-   example {
-       data {
-               ...
-       }
-   }
-
-   example inst {
-       data = example
-   }
- * @endverbatim
- *
- * @param[out] out where to write the pointer to a module's config section.  May be NULL on success,
- *     indicating the config item was not found within the module #CONF_SECTION
- *     or the chain of module references was followed and the module at the end of the chain
- *     did not a subsection.
- * @param[in] module #CONF_SECTION.
- * @param[in] name of the polymorphic sub-section.
- * @return
- *     - 0 on success with referenced section.
- *     - 1 on success with local section.
- *     - -1 on failure.
- */
-int module_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char const *name)
-{
-       CONF_PAIR               *cp;
-       CONF_SECTION            *cs;
-       CONF_DATA const         *cd;
-
-
-       module_instance_t       *mi;
-       char const              *inst_name;
-
-#define FIND_SIBLING_CF_KEY "find_sibling"
-
-       *out = NULL;
-
-       /*
-        *      Is a real section (not referencing sibling module).
-        */
-       cs = cf_section_find(module, name, NULL);
-       if (cs) {
-               *out = cs;
-
-               return 0;
-       }
-
-       /*
-        *      Item omitted completely from module config.
-        */
-       cp = cf_pair_find(module, name);
-       if (!cp) return 0;
-
-       if (cf_data_find(module, CONF_SECTION, FIND_SIBLING_CF_KEY)) {
-               cf_log_err(cp, "Module reference loop found");
-
-               return -1;
-       }
-       cd = cf_data_add(module, module, FIND_SIBLING_CF_KEY, false);
-
-       /*
-        *      Item found, resolve it to a module instance.
-        *      This triggers module loading, so we don't have
-        *      instantiation order issues.
-        */
-       inst_name = cf_pair_value(cp);
-       mi = module_by_name(NULL, inst_name);
-       if (!mi) {
-               cf_log_err(cp, "Unknown module instance \"%s\"", inst_name);
-
-               return -1;
-       }
-
-       if (!mi->instantiated) {
-               CONF_SECTION *parent = module;
-
-               /*
-                *      Find the root of the config...
-                */
-               do {
-                       CONF_SECTION *tmp;
-
-                       tmp = cf_item_to_section(cf_parent(parent));
-                       if (!tmp) break;
-
-                       parent = tmp;
-               } while (true);
-
-               _module_instantiate(module_by_name(NULL, inst_name));
-       }
-
-       /*
-        *      Remove the config data we added for loop
-        *      detection.
-        */
-       cf_data_remove(module, cd);
-
-       /*
-        *      Check the module instances are of the same type.
-        */
-       if (strcmp(cf_section_name1(mi->dl_inst->conf), cf_section_name1(module)) != 0) {
-               cf_log_err(cp, "Referenced module is a rlm_%s instance, must be a rlm_%s instance",
-                             cf_section_name1(mi->dl_inst->conf), cf_section_name1(module));
-
-               return -1;
-       }
-
-       *out = cf_section_find(mi->dl_inst->conf, name, NULL);
-
-       return 1;
-}
-
-/** Initialise a module specific connection pool
- *
- * @see fr_pool_init
- *
- * @param[in] module           section.
- * @param[in] opaque           data pointer to pass to callbacks.
- * @param[in] c                        Callback to create new connections.
- * @param[in] a                        Callback to check the status of connections.
- * @param[in] log_prefix       override, if NULL will be set automatically from the module CONF_SECTION.
- * @param[in] trigger_prefix   if NULL will be set automatically from the module CONF_SECTION.
- * @param[in] trigger_args     to make available in any triggers executed by the connection pool.
- * @return
- *     - New connection pool.
- *     - NULL on error.
- */
-fr_pool_t *module_connection_pool_init(CONF_SECTION *module,
-                                      void *opaque,
-                                      fr_pool_connection_create_t c,
-                                      fr_pool_connection_alive_t a,
-                                      char const *log_prefix,
-                                      char const *trigger_prefix,
-                                      fr_pair_list_t *trigger_args)
-{
-       CONF_SECTION *cs, *mycs;
-       char log_prefix_buff[128];
-       char trigger_prefix_buff[128];
-
-       fr_pool_t *pool;
-       char const *cs_name1, *cs_name2;
-
-       int ret;
-
-#define parent_name(_x) cf_section_name(cf_item_to_section(cf_parent(_x)))
-
-       cs_name1 = cf_section_name1(module);
-       cs_name2 = cf_section_name2(module);
-       if (!cs_name2) cs_name2 = cs_name1;
-
-       if (!trigger_prefix) {
-               snprintf(trigger_prefix_buff, sizeof(trigger_prefix_buff), "modules.%s.pool", cs_name1);
-               trigger_prefix = trigger_prefix_buff;
-       }
-
-       if (!log_prefix) {
-               snprintf(log_prefix_buff, sizeof(log_prefix_buff), "rlm_%s (%s)", cs_name1, cs_name2);
-               log_prefix = log_prefix_buff;
-       }
-
-       /*
-        *      Get sibling's pool config section
-        */
-       ret = module_sibling_section_find(&cs, module, "pool");
-       switch (ret) {
-       case -1:
-               return NULL;
-
-       case 1:
-               DEBUG4("%s: Using pool section from \"%s\"", log_prefix, parent_name(cs));
-               break;
-
-       case 0:
-               DEBUG4("%s: Using local pool section", log_prefix);
-               break;
-       }
-
-       /*
-        *      Get our pool config section
-        */
-       mycs = cf_section_find(module, "pool", NULL);
-       if (!mycs) {
-               DEBUG4("%s: Adding pool section to config item \"%s\" to store pool references", log_prefix,
-                      cf_section_name(module));
-
-               mycs = cf_section_alloc(module, module, "pool", NULL);
-       }
-
-       /*
-        *      Sibling didn't have a pool config section
-        *      Use our own local pool.
-        */
-       if (!cs) {
-               DEBUG4("%s: \"%s.pool\" section not found, using \"%s.pool\"", log_prefix,
-                      parent_name(cs), parent_name(mycs));
-               cs = mycs;
-       }
-
-       /*
-        *      If fr_pool_init has already been called
-        *      for this config section, reuse the previous instance.
-        *
-        *      This allows modules to pass in the config sections
-        *      they would like to use the connection pool from.
-        */
-       pool = cf_data_value(cf_data_find(cs, fr_pool_t, NULL));
-       if (!pool) {
-               DEBUG4("%s: No pool reference found for config item \"%s.pool\"", log_prefix, parent_name(cs));
-               pool = fr_pool_init(cs, cs, opaque, c, a, log_prefix);
-               if (!pool) return NULL;
-
-               fr_pool_enable_triggers(pool, trigger_prefix, trigger_args);
-
-               if (fr_pool_start(pool) < 0) {
-                       ERROR("%s: Starting initial connections failed", log_prefix);
-                       return NULL;
-               }
-
-               DEBUG4("%s: Adding pool reference %p to config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
-               cf_data_add(cs, pool, NULL, false);
-               return pool;
-       }
-       fr_pool_ref(pool);
-
-       DEBUG4("%s: Found pool reference %p in config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
-
-       /*
-        *      We're reusing pool data add it to our local config
-        *      section. This allows other modules to transitively
-        *      re-use a pool through this module.
-        */
-       if (mycs != cs) {
-               DEBUG4("%s: Copying pool reference %p from config item \"%s.pool\" to config item \"%s.pool\"",
-                      log_prefix, pool, parent_name(cs), parent_name(mycs));
-               cf_data_add(mycs, pool, NULL, false);
-       }
-
-       return pool;
-}
-
-
-/*
- *     Convert a string to an integer
- */
-module_method_t module_state_str_to_method(module_state_func_table_t const *table,
-                                          char const *name, module_method_t def)
-{
-       module_state_func_table_t const *this;
-
-       if (!name) return def;
-
-       for (this = table; this->name != NULL; this++) {
-               if (strcasecmp(this->name, name) == 0) return this->func;
-       }
-
-       return def;
-}
-
-/*
- *     Convert an integer to a string.
- */
-char const *module_state_method_to_str(module_state_func_table_t const *table,
-                                      module_method_t method, char const *def)
-{
-       module_state_func_table_t const *this;
-
-       for (this = table; this->name != NULL; this++) if (this->func == method) return this->name;
-
-       return def;
-}
-
-/** Set the next section type if it's not already set
- *
- * @param[in] request          The current request.
- * @param[in] type_da          to use.  Usually attr_auth_type.
- * @param[in] enumv            Enumeration value of the specified type_da.
- */
-bool module_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv)
-{
-       fr_pair_t *vp;
-
-       switch (pair_update_control(&vp, type_da)) {
-       case 0:
-               fr_value_box_copy(vp, &vp->data, enumv->value);
-               vp->data.enumv = vp->da;        /* So we get the correct string alias */
-               RDEBUG2("Setting &control.%pP", vp);
-               return true;
-
-       case 1:
-               RDEBUG2("&control.%s already set.  Not setting to %s", vp->da->name, enumv->name);
-               return false;
-
-       default:
-               return false;
-       }
-}
-
-/** Find an existing module instance by its name and parent
- *
- * @param[in] parent           to qualify search with.
- * @param[in] asked_name       The name of the module we're attempting to find.
- *                             May include '-' which indicates that it's ok for
- *                             the module not to be loaded.
- * @return
- *     - Module instance matching name.
- *     - NULL if no such module exists.
- */
-module_instance_t *module_by_name(module_instance_t const *parent, char const *asked_name)
-{
-       char const              *inst_name;
-       void                    *inst;
-
-       if (!module_instance_name_tree) return NULL;
-
-       /*
-        *      Look for the real name.  Ignore the first character,
-        *      which tells the server "it's OK for this module to not
-        *      exist."
-        */
-       inst_name = asked_name;
-       if (inst_name[0] == '-') inst_name++;
-
-       inst = fr_rb_find(module_instance_name_tree,
-                              &(module_instance_t){
-                                       .dl_inst = &(dl_module_inst_t){ .parent = parent ? parent->dl_inst : NULL },
-                                       .name = inst_name
-                              });
-       if (!inst) return NULL;
-
-       return talloc_get_type_abort(inst, module_instance_t);
-}
-
-/** Find an existing module instance and verify it implements the specified method
- *
- * Extracts the method from the module name where the format is @verbatim <module>.<method> @endverbatim
- * and ensures the module implements the specified method.
- *
- * @param[out] method          the method function we will call
- * @param[in,out] component    the default component to use.  Updated to be the found component
- * @param[out] name1           name1 of the method being called
- * @param[out] name2           name2 of the method being called
- * @param[in] name             The name of the module we're attempting to find, possibly concatenated with the method
- * @return
- *     - The module instance on success.
- *     - NULL on not found
- *
- *  If the module exists but the method doesn't exist, then `method` is set to NULL.
- */
-module_instance_t *module_by_name_and_method(module_method_t *method, rlm_components_t *component,
-                                            char const **name1, char const **name2,
-                                            char const *name)
-{
-       char                            *p, *q, *inst_name;
-       size_t                          len;
-       int                             j;
-       rlm_components_t                i;
-       module_instance_t               *mi;
-       module_method_names_t const     *methods;
-       char const                      *method_name1, *method_name2;
-
-       if (method) *method = NULL;
-
-       method_name1 = method_name2 = NULL;
-       if (name1) {
-               method_name1 = *name1;
-               *name1 = NULL;
-       }
-       if (name2) {
-               method_name2 = *name2;
-               *name2 = NULL;
-       }
-
-       /*
-        *      Module names are allowed to contain '.'
-        *      so we search for the bare module name first.
-        */
-       mi = module_by_name(NULL, name);
-       if (mi) {
-               virtual_server_method_t const *allowed_list;
-
-               if (!method) return mi;
-
-               /*
-                *      We're not searching for a named method, OR the
-                *      module has no named methods.  Try to return a
-                *      method based on the component.
-                */
-               if (!method_name1 || !mi->module->method_names) goto return_component;
-
-               /*
-                *      Walk through the module, finding a matching
-                *      method.
-                */
-               for (j = 0; mi->module->method_names[j].name1 != NULL; j++) {
-                       methods = &mi->module->method_names[j];
-
-                       /*
-                        *      Wildcard match name1, we're
-                        *      done.
-                        */
-                       if (methods->name1 == CF_IDENT_ANY) {
-                       found:
-                               *method = methods->method;
-                               if (name1) *name1 = method_name1;
-                               if (name2) *name2 = method_name2;
-                               return mi;
-                       }
-
-                       /*
-                        *      If name1 doesn't match, skip it.
-                        */
-                       if (strcmp(methods->name1, method_name1) != 0) continue;
-
-                       /*
-                        *      The module can declare a
-                        *      wildcard for name2, in which
-                        *      case it's a match.
-                        */
-                       if (methods->name2 == CF_IDENT_ANY) goto found;
-
-                       /*
-                        *      No name2 is also a match to no name2.
-                        */
-                       if (!methods->name2 && !method_name2) goto found;
-
-                       /*
-                        *      Don't do strcmp on NULLs
-                        */
-                       if (!methods->name2 || !method_name2) continue;
-
-                       if (strcmp(methods->name2, method_name2) == 0) goto found;
-               }
-
-               /*
-                *      No match for "recv Access-Request", or
-                *      whatever else the section is.  Let's see if
-                *      the section has a list of allowed methods.
-                */
-               allowed_list = virtual_server_section_methods(method_name1, method_name2);
-               if (!allowed_list) goto return_component;
-
-               /*
-                *      Walk over allowed methods for this section,
-                *      (implicitly ordered by priority), and see if
-                *      the allowed method matches any of the module
-                *      methods.  This process lets us reference a
-                *      module as "foo" in the configuration.  If the
-                *      module exports a "recv bar" method, and the
-                *      virtual server has a "recv bar" processing
-                *      section, then they shoul match.
-                *
-                *      Unfortunately, this process is O(N*M).
-                *      Luckily, we only do it if all else fails, so
-                *      it's mostly OK.
-                *
-                *      Note that the "allowed" list CANNOT include
-                *      CF_IDENT_ANY.  Only the module can do that.
-                *      If the "allowed" list exported CF_IDENT_ANY,
-                *      then any module method would match, which is
-                *      bad.
-                */
-               for (j = 0; allowed_list[j].name != NULL; j++) {
-                       int k;
-                       virtual_server_method_t const *allowed = &allowed_list[j];
-
-                       for (k = 0; mi->module->method_names[k].name1 != NULL; k++) {
-                               methods = &mi->module->method_names[k];
-
-                               fr_assert(methods->name1 != CF_IDENT_ANY); /* should have been caught above */
-
-                               if (strcmp(methods->name1, allowed->name) != 0) continue;
-
-                               /*
-                                *      The module matches "recv *",
-                                *      call this method.
-                                */
-                               if (methods->name2 == CF_IDENT_ANY) {
-                               found_allowed:
-                                       *method = methods->method;
-                                       return mi;
-                               }
-
-                               /*
-                                *      No name2 is also a match to no name2.
-                                */
-                               if (!methods->name2 && !allowed->name2) goto found_allowed;
-
-                               /*
-                                *      Don't do strcmp on NULLs
-                                */
-                               if (!methods->name2 || !allowed->name2) continue;
-
-                               if (strcmp(methods->name2, allowed->name2) == 0) goto found_allowed;
-                       }
-               }
-
-       return_component:
-               /*
-                *      No matching method.  Just return a method
-                *      based on the component.
-                */
-               if (component && mi->module->methods[*component]) {
-                       *method = mi->module->methods[*component];
-               }
-
-               /*
-                *      Didn't find a matching method.  Just return
-                *      the module.
-                */
-               return mi;
-       }
-
-       /*
-        *      Find out if the instance name contains
-        *      a method, if it doesn't, then the module
-        *      doesn't exist.
-        */
-       p = strchr(name, '.');
-       if (!p) return NULL;
-
-       /*
-        *      The module name may have a '.' in it, AND it may have
-        *      a method <sigh> So we try to find out which is which.
-        */
-       inst_name = talloc_strdup(NULL, name);
-       p = inst_name + (p - name);
-
-       /*
-        *      Loop over the '.' portions, gradually looking up a
-        *      longer string, in order to find the full module name.
-        */
-       do {
-               *p = '\0';
-
-               mi = module_by_name(NULL, inst_name);
-               if (mi) break;
-
-               /*
-                *      Find the next '.'
-                */
-               *p = '.';
-               p = strchr(p + 1, '.');
-       } while (p);
-
-       /*
-        *      No such module, we're done.
-        */
-       if (!mi) {
-               talloc_free(inst_name);
-               return NULL;
-       }
-
-       /*
-        *      We have a module, but the caller doesn't care about
-        *      method or names, so just return the module.
-        */
-       if (!method || !method_name1 || !method_name2) {
-               talloc_free(inst_name);
-               return mi;
-       }
-
-       /*
-        *      We MAY have two names.
-        */
-       p++;
-       q = strchr(p, '.');
-
-       /*
-        *      If there's only one component, look for it in the
-        *      "authorize", etc. list first.
-        */
-       if (!q) {
-               for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
-                       if (strcmp(section_type_value[i], p) != 0) continue;
-
-                       /*
-                        *      Tell the caller which component was
-                        *      referenced, and set the method to the found
-                        *      function.
-                        */
-                       if (component) {
-                               *component = i;
-                               if (method) *method = mi->module->methods[*component];
-                       }
-
-                       /*
-                        *      The string matched.  Return it.  Also set the
-                        *      names so that the caller gets told the method
-                        *      name being used.
-                        */
-                       *name1 = name + (p - inst_name);
-                       *name2 = NULL;
-                       talloc_free(inst_name);
-                       return mi;
-               }
-       }
-
-       /*
-        *      We've found the module, but it has no named methods.
-        */
-       if (!mi->module->method_names) {
-               *name1 = name + (p - inst_name);
-               *name2 = NULL;
-               talloc_free(inst_name);
-               return mi;
-       }
-
-       /*
-        *      We have "module.METHOD", but METHOD doesn't match
-        *      "authorize", "authenticate", etc.  Let's see if it
-        *      matches anything else.
-        */
-       if (!q) {
-               for (j = 0; mi->module->method_names[j].name1 != NULL; j++) {
-                       methods = &mi->module->method_names[j];
-
-                       /*
-                        *      If we do not have the second $method, then ignore it!
-                        */
-                       if (methods->name2 && (methods->name2 != CF_IDENT_ANY)) continue;
-
-                       /*
-                        *      Wildcard match name1, we're
-                        *      done.
-                        */
-                       if (!methods->name1 || (methods->name1 == CF_IDENT_ANY)) goto found_name1;
-
-                       /*
-                        *      If name1 doesn't match, skip it.
-                        */
-                       if (strcmp(methods->name1, p) != 0) continue;
-
-               found_name1:
-                       /*
-                        *      We've matched "*", or "name1" or
-                        *      "name1 *".  Return that.
-                        */
-                       *name1 = p;
-                       *name2 = NULL;
-                       *method = methods->method;
-                       break;
-               }
-
-               /*
-                *      Return the found module.
-                */
-               talloc_free(inst_name);
-               return mi;
-       }
+       int ret;
 
        /*
-        *      We CANNOT have '.' in method names.
+        *      Sort by depth, so for tree walking we start
+        *      at the shallowest node, and finish with
+        *      the deepest child.
         */
-       if (strchr(q + 1, '.') != 0) {
-               talloc_free(inst_name);
-               return mi;
-       }
+       for (dl_inst = a->dl_inst; dl_inst; dl_inst = dl_inst->parent) a_depth++;
+       for (dl_inst = b->dl_inst; dl_inst; dl_inst = dl_inst->parent) b_depth++;
 
-       len = q - p;
+       ret = CMP(a_depth, b_depth);
+       if (ret != 0) return ret;
 
        /*
-        *      Trim the '.'.
+        *      This happens, as dl_inst is is used in
+        *      as the loop condition above.
         */
-       if (*q == '.' && *(q + 1)) q++;
+#ifdef __clang_analyzer__
+       if (!fr_cond_assert(a->dl_inst)) return +1;
+       if (!fr_cond_assert(b->dl_inst)) return -1;
+#endif
 
-       /*
-        *      We have "module.METHOD1.METHOD2".
-        *
-        *      Loop over the method names, seeing if we have a match.
-        */
-       for (j = 0; mi->module->method_names[j].name1 != NULL; j++) {
-               methods = &mi->module->method_names[j];
+       ret = CMP(a->dl_inst->parent, b->dl_inst->parent);
+       if (ret != 0) return ret;
 
-               /*
-                *      If name1 doesn't match, skip it.
-                */
-               if (strncmp(methods->name1, p, len) != 0) continue;
+       ret = strcmp(a->name, b->name);
+       return CMP(ret, 0);
+}
 
-               /*
-                *      It may have been a partial match, like "rec",
-                *      instead of "recv".  In which case check if it
-                *      was a FULL match.
-                */
-               if (strlen(methods->name1) != len) continue;
+/** Compare module's by their private instance data
+ *
+ */
+static int8_t module_instance_data_cmp(void const *one, void const *two)
+{
+       void const *a = (((module_instance_t const *)one)->dl_inst)->data;
+       void const *b = (((module_instance_t const *)two)->dl_inst)->data;
 
-               /*
-                *      The module can declare a
-                *      wildcard for name2, in which
-                *      case it's a match.
-                */
-               if (!methods->name2 || (methods->name2 == CF_IDENT_ANY)) goto found_name2;
+       return CMP(a, b);
+}
 
-               /*
-                *      Don't do strcmp on NULLs
-                */
-               if (!methods->name2) continue;
+/** Find an existing module instance by its name and parent
+ *
+ * @param[in] parent           to qualify search with.
+ * @param[in] asked_name       The name of the module we're attempting to find.
+ *                             May include '-' which indicates that it's ok for
+ *                             the module not to be loaded.
+ * @return
+ *     - Module instance matching name.
+ *     - NULL if no such module exists.
+ */
+module_instance_t *module_by_name(module_instance_t const *parent, char const *asked_name)
+{
+       char const              *inst_name;
+       void                    *inst;
 
-               if (strcmp(methods->name2, q) != 0) continue;
+       if (!module_instance_name_tree) return NULL;
 
-       found_name2:
-               /*
-                *      Update name1/name2 with the methods
-                *      that were found.
-                */
-               *name1 = methods->name1;
-               *name2 = name + (q - inst_name);
-               *method = methods->method;
-               break;
-       }
+       /*
+        *      Look for the real name.  Ignore the first character,
+        *      which tells the server "it's OK for this module to not
+        *      exist."
+        */
+       inst_name = asked_name;
+       if (inst_name[0] == '-') inst_name++;
 
-       *name1 = name + (p - inst_name);
-       *name2 = NULL;
+       inst = fr_rb_find(module_instance_name_tree,
+                              &(module_instance_t){
+                                       .dl_inst = &(dl_module_inst_t){ .parent = parent ? parent->dl_inst : NULL },
+                                       .name = inst_name
+                              });
+       if (!inst) return NULL;
 
-       talloc_free(inst_name);
-       return mi;
+       return talloc_get_type_abort(inst, module_instance_t);
 }
 
 /** Find an existing module instance by its private instance data
@@ -1136,47 +371,6 @@ void module_free(module_instance_t *mi)
        talloc_free(mi);
 }
 
-
-/** Free all modules loaded by the server
- */
-void modules_free(void)
-{
-       if (module_instance_name_tree) {
-               fr_rb_iter_inorder_t    iter;
-               module_instance_t               *mi;
-
-               for (mi = fr_rb_iter_init_inorder(&iter, module_instance_name_tree);
-                    mi;
-                    mi = fr_rb_iter_next_inorder(&iter)) {
-                       mi->in_name_tree = false; /* about to be deleted */
-                       mi->in_data_tree = false;
-
-                       fr_rb_iter_delete_inorder(&iter);
-                       fr_rb_remove(module_instance_data_tree, mi);
-
-                       talloc_free(mi);
-               }
-               TALLOC_FREE(module_instance_name_tree);
-       }
-
-       TALLOC_FREE(module_instance_data_tree);
-       TALLOC_FREE(virtual_module_name_tree);
-       TALLOC_FREE(instance_ctx);
-}
-
-int modules_init(void)
-{
-       MEM(module_instance_name_tree = fr_rb_inline_alloc(NULL, module_instance_t, name_node,
-                                                          module_instance_name_cmp, NULL));
-       MEM(module_instance_data_tree = fr_rb_inline_alloc(NULL, module_instance_t, data_node,
-                                                          module_instance_data_cmp, NULL));
-       MEM(virtual_module_name_tree = fr_rb_inline_alloc(NULL, virtual_module_t, name_node,
-                                                          virtual_module_name_cmp, NULL));
-       instance_ctx = talloc_init("module instance context");
-
-       return 0;
-}
-
 /** Destructor for module_thread_instance_t array
  */
 static int _module_thread_inst_array_free(module_thread_instance_t **array)
@@ -1302,13 +496,13 @@ void modules_thread_detach(void)
  *     - 0 on success.
  *     - -1 on failure.
  */
-static int _module_instantiate(void *instance)
+int module_instantiate(void *instance)
 {
        module_instance_t *mi = talloc_get_type_abort(instance, module_instance_t);
 
        if (mi->instantiated) return 0;
 
-       if (fr_command_register_hook(NULL, mi->name, mi, cmd_module_table) < 0) {
+       if (fr_command_register_hook(NULL, mi->name, mi, module_cmd_table) < 0) {
                PERROR("Failed registering radmin commands for module %s", mi->name);
                return -1;
        }
@@ -1375,9 +569,7 @@ int modules_instantiate(UNUSED CONF_SECTION *root)
        for (instance = fr_rb_iter_init_inorder(&iter, module_instance_name_tree);
             instance;
             instance = fr_rb_iter_next_inorder(&iter)) {
-               if (_module_instantiate(instance) < 0) {
-                       return -1;
-               }
+               if (module_instantiate(instance) < 0) return -1;
        }
 
        return 0;
@@ -1517,7 +709,6 @@ module_instance_t *module_bootstrap(module_instance_t const *parent, CONF_SECTIO
        char                    *inst_name = NULL;
        module_instance_t       *mi;
        char const              *name1 = cf_section_name1(cs);
-       CONF_SECTION            *actions;
 
        module_instance_name(NULL, &inst_name, parent, cs);
 
@@ -1596,294 +787,48 @@ module_instance_t *module_bootstrap(module_instance_t const *parent, CONF_SECTIO
                }
        }
 
-       /*
-        *      Compile the default "actions" subsection, which includes retries.
-        */
-       actions = cf_section_find(cs, "actions", NULL);
-       if (actions && unlang_compile_actions(&mi->actions, actions, (mi->module->type & RLM_TYPE_RETRY) != 0)) {
-               talloc_free(mi);
-               return NULL;
-       }
-
        return mi;
 }
 
-CONF_SECTION *module_by_name_virtual(char const *asked_name)
-{
-       virtual_module_t *inst;
-
-       inst = fr_rb_find(virtual_module_name_tree,
-                              &(virtual_module_t){
-                                       .name = asked_name,
-                              });
-       if (!inst) return NULL;
-
-       return inst->cs;
-}
-
-/** Create a virtual module.
- *
- * @param[in] cs       that defines the virtual module.
- * @return
- *     - 0 on success.
- *     - -1 on failure.
+/** Free all modules loaded by the server
  */
-static int virtual_module_bootstrap(CONF_SECTION *cs)
+void modules_free(void)
 {
-       char const              *name;
-       bool                    all_same;
-       module_t const  *last = NULL;
-       CONF_ITEM               *sub_ci = NULL;
-       CONF_PAIR               *cp;
-       module_instance_t       *mi;
-       virtual_module_t        *inst;
-
-       name = cf_section_name1(cs);
-
-       /*
-        *      Groups, etc. must have a name.
-        */
-       if ((strcmp(name, "group") == 0) ||
-           (strcmp(name, "redundant") == 0) ||
-           (strcmp(name, "redundant-load-balance") == 0) ||
-           (strcmp(name, "load-balance") == 0)) {
-               name = cf_section_name2(cs);
-               if (!name) {
-                       cf_log_err(cs, "Keyword module must have a second name");
-                       return -1;
-               }
-
-               /*
-                *      name2 was already checked in modules_bootstrap()
-                */
-               fr_assert(!unlang_compile_is_keyword(name));
-       } else {
-               cf_log_err(cs, "Module names cannot be unlang keywords '%s'", name);
-               return -1;
-       }
-
-       /*
-        *      Ensure that the module doesn't exist.
-        */
-       mi = module_by_name(NULL, name);
-       if (mi) {
-               ERROR("Duplicate module \"%s\" in file %s[%d] and file %s[%d]",
-                     name,
-                     cf_filename(cs),
-                     cf_lineno(cs),
-                     cf_filename(mi->dl_inst->conf),
-                     cf_lineno(mi->dl_inst->conf));
-               return -1;
-       }
-
-       /*
-        *      Don't bother registering redundant xlats for a simple "group".
-        */
-       all_same = (strcmp(cf_section_name1(cs), "group") != 0);
+       if (module_instance_name_tree) {
+               fr_rb_iter_inorder_t    iter;
+               module_instance_t       *mi;
 
-       /*
-        *      Ensure that the modules we reference here exist.
-        */
-       while ((sub_ci = cf_item_next(cs, sub_ci))) {
-               if (cf_item_is_pair(sub_ci)) {
-                       cp = cf_item_to_pair(sub_ci);
-                       if (cf_pair_value(cp)) {
-                               cf_log_err(sub_ci, "Cannot set return codes in a %s block", cf_section_name1(cs));
-                               return -1;
-                       }
+               for (mi = fr_rb_iter_init_inorder(&iter, module_instance_name_tree);
+                    mi;
+                    mi = fr_rb_iter_next_inorder(&iter)) {
+                       mi->in_name_tree = false; /* about to be deleted */
+                       mi->in_data_tree = false;
 
-                       /*
-                        *      Allow "foo.authorize" in subsections.
-                        *
-                        *      Note that we don't care what the method is, just that it exists.
-                        *
-                        *      This check is needed only because we
-                        *      want to know if we need to register a
-                        *      redundant xlat for the virtual module.
-                        */
-                       mi = module_by_name_and_method(NULL, NULL, NULL, NULL, cf_pair_attr(cp));
-                       if (!mi) {
-                               cf_log_err(sub_ci, "Module instance \"%s\" referenced in %s block, does not exist",
-                                          cf_pair_attr(cp), cf_section_name1(cs));
-                               return -1;
-                       }
+                       fr_rb_iter_delete_inorder(&iter);
+                       fr_rb_remove(module_instance_data_tree, mi);
 
-                       if (all_same) {
-                               if (!last) {
-                                       last = mi->module;
-                               } else if (last != mi->module) {
-                                       last = NULL;
-                                       all_same = false;
-                               }
-                       }
-               } else {
-                       all_same = false;
+                       talloc_free(mi);
                }
-
-               /*
-                *      Don't check subsections for now.  That check
-                *      happens later in the unlang compiler.
-                */
-       } /* loop over things in a virtual module section */
-
-       inst = talloc_zero(cs, virtual_module_t);
-       if (!inst) return -1;
-
-       inst->cs = cs;
-       inst->name = talloc_strdup(inst, name);
-       inst->all_same = all_same;
-
-       if (!fr_cond_assert(fr_rb_insert(virtual_module_name_tree, inst))) {
-               talloc_free(inst);
-               return -1;
+               TALLOC_FREE(module_instance_name_tree);
        }
-
-       return 0;
+       TALLOC_FREE(module_instance_data_tree);
+       modules_rlm_init();
+       TALLOC_FREE(instance_ctx);
 }
 
-
-/** Bootstrap modules and virtual modules
+/** Allocate the global module tree
  *
- * Parse the module config sections, and load and call each module's init() function.
- *
- * @param[in] root of the server configuration.
- * @return
- *     - 0 if all modules were bootstrapped successfully.
- *     - -1 if a module/virtual module failed to boostrap.
+ * This allocates all the trees necessary to hold module name and module instance data,
+ * as well as the main ctx all module data gets allocated in.
  */
-int modules_bootstrap(CONF_SECTION *root)
+int modules_init(void)
 {
-       CONF_ITEM *ci;
-       CONF_SECTION *cs, *modules;
-       virtual_module_t        *vm;
-       fr_rb_iter_inorder_t    iter;
-
-       /*
-        *      Remember where the modules were stored.
-        */
-       modules = cf_section_find(root, "modules", NULL);
-       if (!modules) {
-               WARN("Cannot find a \"modules\" section in the configuration file!");
-               return 0;
-       }
-
-       DEBUG2("#### Bootstrapping modules ####");
-
-       cf_log_debug(modules, " modules {");
-
-       /*
-        *      Loop over module definitions, looking for duplicates.
-        *
-        *      This is O(N^2) in the number of modules, but most
-        *      systems should have less than 100 modules.
-        */
-       for (ci = cf_item_next(modules, NULL);
-            ci != NULL;
-            ci = cf_item_next(modules, ci)) {
-               char const *name;
-               CONF_SECTION *subcs;
-               module_instance_t *instance;
-
-               /*
-                *      @todo - maybe this should be a warning?
-                */
-               if (!cf_item_is_section(ci)) continue;
-
-               subcs = cf_item_to_section(ci);
-
-               /*
-                *      name2 can't be a keyword
-                */
-               name = cf_section_name2(subcs);
-               if (name && unlang_compile_is_keyword(name)) {
-               invalid_name:
-                       cf_log_err(subcs, "Module names cannot be unlang keywords '%s'", name);
-                       return -1;
-               }
-
-               name = cf_section_name1(subcs);
-
-               /*
-                *      For now, ignore name1 which is a keyword.
-                */
-               if (unlang_compile_is_keyword(name)) {
-                       if (!cf_section_name2(subcs)) {
-                               cf_log_err(subcs, "Missing second name at '%s'", name);
-                               return -1;
-                       }
-
-                       if (virtual_module_bootstrap(subcs) < 0) return -1;
-                       continue;
-               }
-
-               /*
-                *      Skip inline templates, and disallow "template { ... }"
-                */
-               if (strcmp(name, "template") == 0) {
-                       if (!cf_section_name2(subcs)) goto invalid_name;
-                       continue;
-               }
-
-               instance = module_bootstrap(NULL, subcs);
-               if (!instance) return -1;
-       }
-
-       cf_log_debug(modules, " } # modules");
-
-       if (fr_command_register_hook(NULL, NULL, modules, cmd_table) < 0) {
-               PERROR("Failed registering radmin commands for modules");
-               return -1;
-       }
-
-       /*
-        *      Check for duplicate policies.  They're treated as
-        *      modules, so we might as well check them here.
-        */
-       cs = cf_section_find(root, "policy", NULL);
-       if (cs) {
-               while ((ci = cf_item_next(cs, ci))) {
-                       CONF_SECTION *subcs, *problemcs;
-                       char const *name1;
-
-                       /*
-                        *      Skip anything that isn't a section.
-                        */
-                       if (!cf_item_is_section(ci)) continue;
-
-                       subcs = cf_item_to_section(ci);
-                       name1 = cf_section_name1(subcs);
-
-                       if (unlang_compile_is_keyword(name1)) {
-                               cf_log_err(subcs, "Policy name '%s' cannot be an unlang keyword", name1);
-                               return -1;
-                       }
-
-                       if (cf_section_name2(subcs)) {
-                               cf_log_err(subcs, "Policies cannot have two names");
-                               return -1;
-                       }
-
-                       problemcs = cf_section_find_next(cs, subcs, name1, CF_IDENT_ANY);
-                       if (!problemcs) continue;
-
-                       cf_log_err(problemcs, "Duplicate policy '%s' is forbidden.",
-                                  cf_section_name1(subcs));
-                       return -1;
-               }
-       }
-
-       /*
-        *      Now that all of the xlat things have been registered,
-        *      register our redundant xlats.  But only when all of
-        *      the items in such a section are the same.
-        */
-       for (vm = fr_rb_iter_init_inorder(&iter, virtual_module_name_tree);
-            vm;
-            vm = fr_rb_iter_next_inorder(&iter)) {
-               if (!vm->all_same) continue;
-
-               if (xlat_register_redundant(vm->cs) < 0) return -1;
-       }
+       MEM(module_instance_name_tree = fr_rb_inline_alloc(NULL, module_instance_t, name_node,
+                                                          module_instance_name_cmp, NULL));
+       MEM(module_instance_data_tree = fr_rb_inline_alloc(NULL, module_instance_t, data_node,
+                                                          module_instance_data_cmp, NULL));
+       modules_rlm_init();
+       instance_ctx = talloc_init("module instance context");
 
        return 0;
 }
index e5974d7adb11c39b82c574bb2b6750d8da2a1ae5..a61f7b9de1da5c5e668fa7c5cb7dbd58162f34c8 100644 (file)
@@ -132,12 +132,6 @@ typedef int (*module_thread_detach_t)(module_thread_inst_ctx_t const *mctx);
 extern "C" {
 #endif
 
-/** Mappings between section names, and control attributes
- *
- * Defined in module.c.
- */
-extern const char *section_type_value[MOD_COUNT];
-
 /** Common fields for submodules
  *
  * This should either be the first field in the structure exported from
@@ -255,14 +249,14 @@ typedef struct {
  *
  * @{
  */
-fr_pool_t      *module_connection_pool_init(CONF_SECTION *module,
+fr_pool_t      *module_rlm_connection_pool_init(CONF_SECTION *module,
                                             void *opaque,
                                             fr_pool_connection_create_t c,
                                             fr_pool_connection_alive_t a,
                                             char const *log_prefix,
                                             char const *trigger_prefix,
                                             fr_pair_list_t *trigger_args);
-exfile_t       *module_exfile_init(TALLOC_CTX *ctx,
+exfile_t       *module_rlm_exfile_init(TALLOC_CTX *ctx,
                                    CONF_SECTION *module,
                                    uint32_t max_entries,
                                    fr_time_delta_t max_idle,
@@ -275,13 +269,13 @@ exfile_t  *module_exfile_init(TALLOC_CTX *ctx,
  *
  * @{
  */
-module_method_t        module_state_str_to_method(module_state_func_table_t const *table,
+module_method_t        module_rlm_state_str_to_method(module_state_func_table_t const *table,
                                           char const *name, module_method_t def);
 
-char const     *module_state_method_to_str(module_state_func_table_t const *table,
+char const     *module_rlm_state_method_to_str(module_state_func_table_t const *table,
                                            module_method_t method, char const *def);
 
-bool           module_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv);
+bool           module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv);
 /** @} */
 
 /** @name Module and module thread lookup
@@ -290,7 +284,7 @@ bool                module_section_type_set(request_t *request, fr_dict_attr_t const *type_da,
  */
 module_instance_t      *module_by_name(module_instance_t const *parent, char const *asked_name);
 
-module_instance_t      *module_by_name_and_method(module_method_t *method, rlm_components_t *component,
+module_instance_t      *module_rlm_by_name_and_method(module_method_t *method, rlm_components_t *component,
                                                   char const **name1, char const **name2,
                                                   char const *asked_name);
 
@@ -300,7 +294,7 @@ module_thread_instance_t *module_thread(module_instance_t *mi);
 
 module_thread_instance_t *module_thread_by_data(void const *data);
 
-CONF_SECTION           *module_by_name_virtual(char const *asked_name);
+CONF_SECTION           *module_rlm_by_name_virtual(char const *asked_name);
 
 /** @} */
 
@@ -322,7 +316,7 @@ int         modules_instantiate(CONF_SECTION *root) CC_HINT(nonnull);
 
 module_instance_t *module_bootstrap(module_instance_t const *parent, CONF_SECTION *cs) CC_HINT(nonnull(2));
 
-int            modules_bootstrap(CONF_SECTION *root) CC_HINT(nonnull);
+int            modules_rlm_bootstrap(CONF_SECTION *root) CC_HINT(nonnull);
 /** @} */
 
 #ifdef __cplusplus
diff --git a/src/lib/server/module_rlm.c b/src/lib/server/module_rlm.c
new file mode 100644 (file)
index 0000000..e362e11
--- /dev/null
@@ -0,0 +1,1090 @@
+/*
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file src/lib/server/module_rlm.c
+ * @brief Defines functions for rlm module (re-)initialisation.
+ *
+ * @copyright 2003,2006,2016 The FreeRADIUS server project
+ * @copyright 2016 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ * @copyright 2000 Alan DeKok (aland@freeradius.org)
+ * @copyright 2000 Alan Curry (pacman@world.std.com)
+ */
+
+RCSID("$Id$")
+
+#include <freeradius-devel/server/cf_file.h>
+#include <freeradius-devel/server/modpriv.h>
+#include <freeradius-devel/server/module_rlm.h>
+#include <freeradius-devel/server/pair.h>
+#include <freeradius-devel/server/virtual_servers.h>
+
+/** Lookup virtual module by name
+ */
+static fr_rb_tree_t *module_rlm_virtual_name_tree;
+
+typedef struct {
+       fr_rb_node_t                    name_node;      //!< Entry in the name tree.
+       char const                      *name;          //!< module name
+       CONF_SECTION                    *cs;            //!< CONF_SECTION where it is defined
+       bool                            all_same;
+} module_rlm_virtual_t;
+
+/** Compare virtual modules by name
+ */
+static int8_t module_rlm_virtual_name_cmp(void const *one, void const *two)
+{
+       module_rlm_virtual_t const *a = one;
+       module_rlm_virtual_t const *b = two;
+       int ret;
+
+       ret = strcmp(a->name, b->name);
+       return CMP(ret, 0);
+}
+
+char const *section_type_value[MOD_COUNT] = {
+       "authenticate",
+       "authorize",
+       "preacct",
+       "accounting",
+       "post-auth"
+};
+
+/** Initialise a module specific exfile handle
+ *
+ * @see exfile_init
+ *
+ * @param[in] ctx              to bind the lifetime of the exfile handle to.
+ * @param[in] module           section.
+ * @param[in] max_entries      Max file descriptors to cache, and manage locks for.
+ * @param[in] max_idle         Maximum time a file descriptor can be idle before it's closed.
+ * @param[in] locking          Whether or not to lock the files.
+ * @param[in] trigger_prefix   if NULL will be set automatically from the module CONF_SECTION.
+ * @param[in] trigger_args     to make available in any triggers executed by the connection pool.
+ * @return
+ *     - New connection pool.
+ *     - NULL on error.
+ */
+exfile_t *module_rlm_exfile_init(TALLOC_CTX *ctx,
+                                CONF_SECTION *module,
+                                uint32_t max_entries,
+                                fr_time_delta_t max_idle,
+                                bool locking,
+                                char const *trigger_prefix,
+                                fr_pair_list_t *trigger_args)
+{
+       char            trigger_prefix_buff[128];
+       exfile_t        *handle;
+
+       if (!trigger_prefix) {
+               snprintf(trigger_prefix_buff, sizeof(trigger_prefix_buff), "modules.%s.file", cf_section_name1(module));
+               trigger_prefix = trigger_prefix_buff;
+       }
+
+       handle = exfile_init(ctx, max_entries, max_idle, locking);
+       if (!handle) return NULL;
+
+       exfile_enable_triggers(handle, cf_section_find(module, "file", NULL), trigger_prefix, trigger_args);
+
+       return handle;
+}
+
+/** Resolve polymorphic item's from a module's #CONF_SECTION to a subsection in another module
+ *
+ * This allows certain module sections to reference module sections in other instances
+ * of the same module and share #CONF_DATA associated with them.
+ *
+ * @verbatim
+   example {
+       data {
+               ...
+       }
+   }
+
+   example inst {
+       data = example
+   }
+ * @endverbatim
+ *
+ * @param[out] out where to write the pointer to a module's config section.  May be NULL on success,
+ *     indicating the config item was not found within the module #CONF_SECTION
+ *     or the chain of module references was followed and the module at the end of the chain
+ *     did not a subsection.
+ * @param[in] module #CONF_SECTION.
+ * @param[in] name of the polymorphic sub-section.
+ * @return
+ *     - 0 on success with referenced section.
+ *     - 1 on success with local section.
+ *     - -1 on failure.
+ */
+int module_rlm_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, char const *name)
+{
+       CONF_PAIR               *cp;
+       CONF_SECTION            *cs;
+       CONF_DATA const         *cd;
+
+
+       module_instance_t       *mi;
+       char const              *inst_name;
+
+#define FIND_SIBLING_CF_KEY "find_sibling"
+
+       *out = NULL;
+
+       /*
+        *      Is a real section (not referencing sibling module).
+        */
+       cs = cf_section_find(module, name, NULL);
+       if (cs) {
+               *out = cs;
+
+               return 0;
+       }
+
+       /*
+        *      Item omitted completely from module config.
+        */
+       cp = cf_pair_find(module, name);
+       if (!cp) return 0;
+
+       if (cf_data_find(module, CONF_SECTION, FIND_SIBLING_CF_KEY)) {
+               cf_log_err(cp, "Module reference loop found");
+
+               return -1;
+       }
+       cd = cf_data_add(module, module, FIND_SIBLING_CF_KEY, false);
+
+       /*
+        *      Item found, resolve it to a module instance.
+        *      This triggers module loading, so we don't have
+        *      instantiation order issues.
+        */
+       inst_name = cf_pair_value(cp);
+       mi = module_by_name(NULL, inst_name);
+       if (!mi) {
+               cf_log_err(cp, "Unknown module instance \"%s\"", inst_name);
+
+               return -1;
+       }
+
+       if (!mi->instantiated) {
+               CONF_SECTION *parent = module;
+
+               /*
+                *      Find the root of the config...
+                */
+               do {
+                       CONF_SECTION *tmp;
+
+                       tmp = cf_item_to_section(cf_parent(parent));
+                       if (!tmp) break;
+
+                       parent = tmp;
+               } while (true);
+
+               module_instantiate(module_by_name(NULL, inst_name));
+       }
+
+       /*
+        *      Remove the config data we added for loop
+        *      detection.
+        */
+       cf_data_remove(module, cd);
+
+       /*
+        *      Check the module instances are of the same type.
+        */
+       if (strcmp(cf_section_name1(mi->dl_inst->conf), cf_section_name1(module)) != 0) {
+               cf_log_err(cp, "Referenced module is a rlm_%s instance, must be a rlm_%s instance",
+                             cf_section_name1(mi->dl_inst->conf), cf_section_name1(module));
+
+               return -1;
+       }
+
+       *out = cf_section_find(mi->dl_inst->conf, name, NULL);
+
+       return 1;
+}
+
+/** Initialise a module specific connection pool
+ *
+ * @see fr_pool_init
+ *
+ * @param[in] module           section.
+ * @param[in] opaque           data pointer to pass to callbacks.
+ * @param[in] c                        Callback to create new connections.
+ * @param[in] a                        Callback to check the status of connections.
+ * @param[in] log_prefix       override, if NULL will be set automatically from the module CONF_SECTION.
+ * @param[in] trigger_prefix   if NULL will be set automatically from the module CONF_SECTION.
+ * @param[in] trigger_args     to make available in any triggers executed by the connection pool.
+ * @return
+ *     - New connection pool.
+ *     - NULL on error.
+ */
+fr_pool_t *module_rlm_connection_pool_init(CONF_SECTION *module,
+                                          void *opaque,
+                                          fr_pool_connection_create_t c,
+                                          fr_pool_connection_alive_t a,
+                                          char const *log_prefix,
+                                          char const *trigger_prefix,
+                                          fr_pair_list_t *trigger_args)
+{
+       CONF_SECTION *cs, *mycs;
+       char log_prefix_buff[128];
+       char trigger_prefix_buff[128];
+
+       fr_pool_t *pool;
+       char const *cs_name1, *cs_name2;
+
+       int ret;
+
+#define parent_name(_x) cf_section_name(cf_item_to_section(cf_parent(_x)))
+
+       cs_name1 = cf_section_name1(module);
+       cs_name2 = cf_section_name2(module);
+       if (!cs_name2) cs_name2 = cs_name1;
+
+       if (!trigger_prefix) {
+               snprintf(trigger_prefix_buff, sizeof(trigger_prefix_buff), "modules.%s.pool", cs_name1);
+               trigger_prefix = trigger_prefix_buff;
+       }
+
+       if (!log_prefix) {
+               snprintf(log_prefix_buff, sizeof(log_prefix_buff), "rlm_%s (%s)", cs_name1, cs_name2);
+               log_prefix = log_prefix_buff;
+       }
+
+       /*
+        *      Get sibling's pool config section
+        */
+       ret = module_rlm_sibling_section_find(&cs, module, "pool");
+       switch (ret) {
+       case -1:
+               return NULL;
+
+       case 1:
+               DEBUG4("%s: Using pool section from \"%s\"", log_prefix, parent_name(cs));
+               break;
+
+       case 0:
+               DEBUG4("%s: Using local pool section", log_prefix);
+               break;
+       }
+
+       /*
+        *      Get our pool config section
+        */
+       mycs = cf_section_find(module, "pool", NULL);
+       if (!mycs) {
+               DEBUG4("%s: Adding pool section to config item \"%s\" to store pool references", log_prefix,
+                      cf_section_name(module));
+
+               mycs = cf_section_alloc(module, module, "pool", NULL);
+       }
+
+       /*
+        *      Sibling didn't have a pool config section
+        *      Use our own local pool.
+        */
+       if (!cs) {
+               DEBUG4("%s: \"%s.pool\" section not found, using \"%s.pool\"", log_prefix,
+                      parent_name(cs), parent_name(mycs));
+               cs = mycs;
+       }
+
+       /*
+        *      If fr_pool_init has already been called
+        *      for this config section, reuse the previous instance.
+        *
+        *      This allows modules to pass in the config sections
+        *      they would like to use the connection pool from.
+        */
+       pool = cf_data_value(cf_data_find(cs, fr_pool_t, NULL));
+       if (!pool) {
+               DEBUG4("%s: No pool reference found for config item \"%s.pool\"", log_prefix, parent_name(cs));
+               pool = fr_pool_init(cs, cs, opaque, c, a, log_prefix);
+               if (!pool) return NULL;
+
+               fr_pool_enable_triggers(pool, trigger_prefix, trigger_args);
+
+               if (fr_pool_start(pool) < 0) {
+                       ERROR("%s: Starting initial connections failed", log_prefix);
+                       return NULL;
+               }
+
+               DEBUG4("%s: Adding pool reference %p to config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
+               cf_data_add(cs, pool, NULL, false);
+               return pool;
+       }
+       fr_pool_ref(pool);
+
+       DEBUG4("%s: Found pool reference %p in config item \"%s.pool\"", log_prefix, pool, parent_name(cs));
+
+       /*
+        *      We're reusing pool data add it to our local config
+        *      section. This allows other modules to transitively
+        *      re-use a pool through this module.
+        */
+       if (mycs != cs) {
+               DEBUG4("%s: Copying pool reference %p from config item \"%s.pool\" to config item \"%s.pool\"",
+                      log_prefix, pool, parent_name(cs), parent_name(mycs));
+               cf_data_add(mycs, pool, NULL, false);
+       }
+
+       return pool;
+}
+
+/*
+ *     Convert a string to an integer
+ */
+module_method_t module_rlm_state_str_to_method(module_state_func_table_t const *table,
+                                              char const *name, module_method_t def)
+{
+       module_state_func_table_t const *this;
+
+       if (!name) return def;
+
+       for (this = table; this->name != NULL; this++) {
+               if (strcasecmp(this->name, name) == 0) return this->func;
+       }
+
+       return def;
+}
+
+/*
+ *     Convert an integer to a string.
+ */
+char const *module_rlm_state_method_to_str(module_state_func_table_t const *table,
+                                          module_method_t method, char const *def)
+{
+       module_state_func_table_t const *this;
+
+       for (this = table; this->name != NULL; this++) if (this->func == method) return this->name;
+
+       return def;
+}
+
+/** Set the next section type if it's not already set
+ *
+ * @param[in] request          The current request.
+ * @param[in] type_da          to use.  Usually attr_auth_type.
+ * @param[in] enumv            Enumeration value of the specified type_da.
+ */
+bool module_rlm_section_type_set(request_t *request, fr_dict_attr_t const *type_da, fr_dict_enum_value_t const *enumv)
+{
+       fr_pair_t *vp;
+
+       switch (pair_update_control(&vp, type_da)) {
+       case 0:
+               fr_value_box_copy(vp, &vp->data, enumv->value);
+               vp->data.enumv = vp->da;        /* So we get the correct string alias */
+               RDEBUG2("Setting &control.%pP", vp);
+               return true;
+
+       case 1:
+               RDEBUG2("&control.%s already set.  Not setting to %s", vp->da->name, enumv->name);
+               return false;
+
+       default:
+               return false;
+       }
+}
+
+/** Find an existing module instance and verify it implements the specified method
+ *
+ * Extracts the method from the module name where the format is @verbatim <module>.<method> @endverbatim
+ * and ensures the module implements the specified method.
+ *
+ * @param[out] method          the method function we will call
+ * @param[in,out] component    the default component to use.  Updated to be the found component
+ * @param[out] name1           name1 of the method being called
+ * @param[out] name2           name2 of the method being called
+ * @param[in] name             The name of the module we're attempting to find, possibly concatenated with the method
+ * @return
+ *     - The module instance on success.
+ *     - NULL on not found
+ *
+ *  If the module exists but the method doesn't exist, then `method` is set to NULL.
+ */
+module_instance_t *module_rlm_by_name_and_method(module_method_t *method, rlm_components_t *component,
+                                                char const **name1, char const **name2,
+                                                char const *name)
+{
+       char                            *p, *q, *inst_name;
+       size_t                          len;
+       int                             j;
+       rlm_components_t                i;
+       module_instance_t               *mi;
+       module_method_names_t const     *methods;
+       char const                      *method_name1, *method_name2;
+
+       if (method) *method = NULL;
+
+       method_name1 = method_name2 = NULL;
+       if (name1) {
+               method_name1 = *name1;
+               *name1 = NULL;
+       }
+       if (name2) {
+               method_name2 = *name2;
+               *name2 = NULL;
+       }
+
+       /*
+        *      Module names are allowed to contain '.'
+        *      so we search for the bare module name first.
+        */
+       mi = module_by_name(NULL, name);
+       if (mi) {
+               virtual_server_method_t const *allowed_list;
+
+               if (!method) return mi;
+
+               /*
+                *      We're not searching for a named method, OR the
+                *      module has no named methods.  Try to return a
+                *      method based on the component.
+                */
+               if (!method_name1 || !mi->module->method_names) goto return_component;
+
+               /*
+                *      Walk through the module, finding a matching
+                *      method.
+                */
+               for (j = 0; mi->module->method_names[j].name1 != NULL; j++) {
+                       methods = &mi->module->method_names[j];
+
+                       /*
+                        *      Wildcard match name1, we're
+                        *      done.
+                        */
+                       if (methods->name1 == CF_IDENT_ANY) {
+                       found:
+                               *method = methods->method;
+                               if (name1) *name1 = method_name1;
+                               if (name2) *name2 = method_name2;
+                               return mi;
+                       }
+
+                       /*
+                        *      If name1 doesn't match, skip it.
+                        */
+                       if (strcmp(methods->name1, method_name1) != 0) continue;
+
+                       /*
+                        *      The module can declare a
+                        *      wildcard for name2, in which
+                        *      case it's a match.
+                        */
+                       if (methods->name2 == CF_IDENT_ANY) goto found;
+
+                       /*
+                        *      No name2 is also a match to no name2.
+                        */
+                       if (!methods->name2 && !method_name2) goto found;
+
+                       /*
+                        *      Don't do strcmp on NULLs
+                        */
+                       if (!methods->name2 || !method_name2) continue;
+
+                       if (strcmp(methods->name2, method_name2) == 0) goto found;
+               }
+
+               /*
+                *      No match for "recv Access-Request", or
+                *      whatever else the section is.  Let's see if
+                *      the section has a list of allowed methods.
+                */
+               allowed_list = virtual_server_section_methods(method_name1, method_name2);
+               if (!allowed_list) goto return_component;
+
+               /*
+                *      Walk over allowed methods for this section,
+                *      (implicitly ordered by priority), and see if
+                *      the allowed method matches any of the module
+                *      methods.  This process lets us reference a
+                *      module as "foo" in the configuration.  If the
+                *      module exports a "recv bar" method, and the
+                *      virtual server has a "recv bar" processing
+                *      section, then they shoul match.
+                *
+                *      Unfortunately, this process is O(N*M).
+                *      Luckily, we only do it if all else fails, so
+                *      it's mostly OK.
+                *
+                *      Note that the "allowed" list CANNOT include
+                *      CF_IDENT_ANY.  Only the module can do that.
+                *      If the "allowed" list exported CF_IDENT_ANY,
+                *      then any module method would match, which is
+                *      bad.
+                */
+               for (j = 0; allowed_list[j].name != NULL; j++) {
+                       int k;
+                       virtual_server_method_t const *allowed = &allowed_list[j];
+
+                       for (k = 0; mi->module->method_names[k].name1 != NULL; k++) {
+                               methods = &mi->module->method_names[k];
+
+                               fr_assert(methods->name1 != CF_IDENT_ANY); /* should have been caught above */
+
+                               if (strcmp(methods->name1, allowed->name) != 0) continue;
+
+                               /*
+                                *      The module matches "recv *",
+                                *      call this method.
+                                */
+                               if (methods->name2 == CF_IDENT_ANY) {
+                               found_allowed:
+                                       *method = methods->method;
+                                       return mi;
+                               }
+
+                               /*
+                                *      No name2 is also a match to no name2.
+                                */
+                               if (!methods->name2 && !allowed->name2) goto found_allowed;
+
+                               /*
+                                *      Don't do strcmp on NULLs
+                                */
+                               if (!methods->name2 || !allowed->name2) continue;
+
+                               if (strcmp(methods->name2, allowed->name2) == 0) goto found_allowed;
+                       }
+               }
+
+       return_component:
+               /*
+                *      No matching method.  Just return a method
+                *      based on the component.
+                */
+               if (component && mi->module->methods[*component]) {
+                       *method = mi->module->methods[*component];
+               }
+
+               /*
+                *      Didn't find a matching method.  Just return
+                *      the module.
+                */
+               return mi;
+       }
+
+       /*
+        *      Find out if the instance name contains
+        *      a method, if it doesn't, then the module
+        *      doesn't exist.
+        */
+       p = strchr(name, '.');
+       if (!p) return NULL;
+
+       /*
+        *      The module name may have a '.' in it, AND it may have
+        *      a method <sigh> So we try to find out which is which.
+        */
+       inst_name = talloc_strdup(NULL, name);
+       p = inst_name + (p - name);
+
+       /*
+        *      Loop over the '.' portions, gradually looking up a
+        *      longer string, in order to find the full module name.
+        */
+       do {
+               *p = '\0';
+
+               mi = module_by_name(NULL, inst_name);
+               if (mi) break;
+
+               /*
+                *      Find the next '.'
+                */
+               *p = '.';
+               p = strchr(p + 1, '.');
+       } while (p);
+
+       /*
+        *      No such module, we're done.
+        */
+       if (!mi) {
+               talloc_free(inst_name);
+               return NULL;
+       }
+
+       /*
+        *      We have a module, but the caller doesn't care about
+        *      method or names, so just return the module.
+        */
+       if (!method || !method_name1 || !method_name2) {
+               talloc_free(inst_name);
+               return mi;
+       }
+
+       /*
+        *      We MAY have two names.
+        */
+       p++;
+       q = strchr(p, '.');
+
+       /*
+        *      If there's only one component, look for it in the
+        *      "authorize", etc. list first.
+        */
+       if (!q) {
+               for (i = MOD_AUTHENTICATE; i < MOD_COUNT; i++) {
+                       if (strcmp(section_type_value[i], p) != 0) continue;
+
+                       /*
+                        *      Tell the caller which component was
+                        *      referenced, and set the method to the found
+                        *      function.
+                        */
+                       if (component) {
+                               *component = i;
+                               if (method) *method = mi->module->methods[*component];
+                       }
+
+                       /*
+                        *      The string matched.  Return it.  Also set the
+                        *      names so that the caller gets told the method
+                        *      name being used.
+                        */
+                       *name1 = name + (p - inst_name);
+                       *name2 = NULL;
+                       talloc_free(inst_name);
+                       return mi;
+               }
+       }
+
+       /*
+        *      We've found the module, but it has no named methods.
+        */
+       if (!mi->module->method_names) {
+               *name1 = name + (p - inst_name);
+               *name2 = NULL;
+               talloc_free(inst_name);
+               return mi;
+       }
+
+       /*
+        *      We have "module.METHOD", but METHOD doesn't match
+        *      "authorize", "authenticate", etc.  Let's see if it
+        *      matches anything else.
+        */
+       if (!q) {
+               for (j = 0; mi->module->method_names[j].name1 != NULL; j++) {
+                       methods = &mi->module->method_names[j];
+
+                       /*
+                        *      If we do not have the second $method, then ignore it!
+                        */
+                       if (methods->name2 && (methods->name2 != CF_IDENT_ANY)) continue;
+
+                       /*
+                        *      Wildcard match name1, we're
+                        *      done.
+                        */
+                       if (!methods->name1 || (methods->name1 == CF_IDENT_ANY)) goto found_name1;
+
+                       /*
+                        *      If name1 doesn't match, skip it.
+                        */
+                       if (strcmp(methods->name1, p) != 0) continue;
+
+               found_name1:
+                       /*
+                        *      We've matched "*", or "name1" or
+                        *      "name1 *".  Return that.
+                        */
+                       *name1 = p;
+                       *name2 = NULL;
+                       *method = methods->method;
+                       break;
+               }
+
+               /*
+                *      Return the found module.
+                */
+               talloc_free(inst_name);
+               return mi;
+       }
+
+       /*
+        *      We CANNOT have '.' in method names.
+        */
+       if (strchr(q + 1, '.') != 0) {
+               talloc_free(inst_name);
+               return mi;
+       }
+
+       len = q - p;
+
+       /*
+        *      Trim the '.'.
+        */
+       if (*q == '.' && *(q + 1)) q++;
+
+       /*
+        *      We have "module.METHOD1.METHOD2".
+        *
+        *      Loop over the method names, seeing if we have a match.
+        */
+       for (j = 0; mi->module->method_names[j].name1 != NULL; j++) {
+               methods = &mi->module->method_names[j];
+
+               /*
+                *      If name1 doesn't match, skip it.
+                */
+               if (strncmp(methods->name1, p, len) != 0) continue;
+
+               /*
+                *      It may have been a partial match, like "rec",
+                *      instead of "recv".  In which case check if it
+                *      was a FULL match.
+                */
+               if (strlen(methods->name1) != len) continue;
+
+               /*
+                *      The module can declare a
+                *      wildcard for name2, in which
+                *      case it's a match.
+                */
+               if (!methods->name2 || (methods->name2 == CF_IDENT_ANY)) goto found_name2;
+
+               /*
+                *      Don't do strcmp on NULLs
+                */
+               if (!methods->name2) continue;
+
+               if (strcmp(methods->name2, q) != 0) continue;
+
+       found_name2:
+               /*
+                *      Update name1/name2 with the methods
+                *      that were found.
+                */
+               *name1 = methods->name1;
+               *name2 = name + (q - inst_name);
+               *method = methods->method;
+               break;
+       }
+
+       *name1 = name + (p - inst_name);
+       *name2 = NULL;
+
+       talloc_free(inst_name);
+       return mi;
+}
+
+CONF_SECTION *module_rlm_by_name_virtual(char const *asked_name)
+{
+       module_rlm_virtual_t *inst;
+
+       inst = fr_rb_find(module_rlm_virtual_name_tree,
+                         &(module_rlm_virtual_t){
+                               .name = asked_name,
+                         });
+       if (!inst) return NULL;
+
+       return inst->cs;
+}
+
+/** Create a virtual module.
+ *
+ * @param[in] cs       that defines the virtual module.
+ * @return
+ *     - 0 on success.
+ *     - -1 on failure.
+ */
+static int module_rlm_bootstrap_virtual(CONF_SECTION *cs)
+{
+       char const              *name;
+       bool                    all_same;
+       module_t const  *last = NULL;
+       CONF_ITEM               *sub_ci = NULL;
+       CONF_PAIR               *cp;
+       module_instance_t       *mi;
+       module_rlm_virtual_t    *inst;
+
+       name = cf_section_name1(cs);
+
+       /*
+        *      Groups, etc. must have a name.
+        */
+       if ((strcmp(name, "group") == 0) ||
+           (strcmp(name, "redundant") == 0) ||
+           (strcmp(name, "redundant-load-balance") == 0) ||
+           (strcmp(name, "load-balance") == 0)) {
+               name = cf_section_name2(cs);
+               if (!name) {
+                       cf_log_err(cs, "Keyword module must have a second name");
+                       return -1;
+               }
+
+               /*
+                *      name2 was already checked in modules_rlm_bootstrap()
+                */
+               fr_assert(!unlang_compile_is_keyword(name));
+       } else {
+               cf_log_err(cs, "Module names cannot be unlang keywords '%s'", name);
+               return -1;
+       }
+
+       /*
+        *      Ensure that the module doesn't exist.
+        */
+       mi = module_by_name(NULL, name);
+       if (mi) {
+               ERROR("Duplicate module \"%s\" in file %s[%d] and file %s[%d]",
+                     name,
+                     cf_filename(cs),
+                     cf_lineno(cs),
+                     cf_filename(mi->dl_inst->conf),
+                     cf_lineno(mi->dl_inst->conf));
+               return -1;
+       }
+
+       /*
+        *      Don't bother registering redundant xlats for a simple "group".
+        */
+       all_same = (strcmp(cf_section_name1(cs), "group") != 0);
+
+       /*
+        *      Ensure that the modules we reference here exist.
+        */
+       while ((sub_ci = cf_item_next(cs, sub_ci))) {
+               if (cf_item_is_pair(sub_ci)) {
+                       cp = cf_item_to_pair(sub_ci);
+                       if (cf_pair_value(cp)) {
+                               cf_log_err(sub_ci, "Cannot set return codes in a %s block", cf_section_name1(cs));
+                               return -1;
+                       }
+
+                       /*
+                        *      Allow "foo.authorize" in subsections.
+                        *
+                        *      Note that we don't care what the method is, just that it exists.
+                        *
+                        *      This check is needed only because we
+                        *      want to know if we need to register a
+                        *      redundant xlat for the virtual module.
+                        */
+                       mi = module_rlm_by_name_and_method(NULL, NULL, NULL, NULL, cf_pair_attr(cp));
+                       if (!mi) {
+                               cf_log_err(sub_ci, "Module instance \"%s\" referenced in %s block, does not exist",
+                                          cf_pair_attr(cp), cf_section_name1(cs));
+                               return -1;
+                       }
+
+                       if (all_same) {
+                               if (!last) {
+                                       last = mi->module;
+                               } else if (last != mi->module) {
+                                       last = NULL;
+                                       all_same = false;
+                               }
+                       }
+               } else {
+                       all_same = false;
+               }
+
+               /*
+                *      Don't check subsections for now.  That check
+                *      happens later in the unlang compiler.
+                */
+       } /* loop over things in a virtual module section */
+
+       inst = talloc_zero(cs, module_rlm_virtual_t);
+       if (!inst) return -1;
+
+       inst->cs = cs;
+       inst->name = talloc_strdup(inst, name);
+       inst->all_same = all_same;
+
+       if (!fr_cond_assert(fr_rb_insert(module_rlm_virtual_name_tree, inst))) {
+               talloc_free(inst);
+               return -1;
+       }
+
+       return 0;
+}
+
+/** Bootstrap modules and virtual modules
+ *
+ * Parse the module config sections, and load and call each module's init() function.
+ *
+ * @param[in] root of the server configuration.
+ * @return
+ *     - 0 if all modules were bootstrapped successfully.
+ *     - -1 if a module/virtual module failed to boostrap.
+ */
+int modules_rlm_bootstrap(CONF_SECTION *root)
+{
+       CONF_ITEM               *ci;
+       CONF_SECTION            *cs, *modules;
+       module_rlm_virtual_t    *vm;
+       fr_rb_iter_inorder_t    iter;
+       CONF_SECTION            *actions;
+       /*
+        *      Remember where the modules were stored.
+        */
+       modules = cf_section_find(root, "modules", NULL);
+       if (!modules) {
+               WARN("Cannot find a \"modules\" section in the configuration file!");
+               return 0;
+       }
+
+       DEBUG2("#### Bootstrapping modules ####");
+
+       cf_log_debug(modules, " modules {");
+
+       /*
+        *      Loop over module definitions, looking for duplicates.
+        *
+        *      This is O(N^2) in the number of modules, but most
+        *      systems should have less than 100 modules.
+        */
+       for (ci = cf_item_next(modules, NULL);
+            ci != NULL;
+            ci = cf_item_next(modules, ci)) {
+               char const *name;
+               CONF_SECTION *subcs;
+               module_instance_t *mi;
+
+               /*
+                *      @todo - maybe this should be a warning?
+                */
+               if (!cf_item_is_section(ci)) continue;
+
+               subcs = cf_item_to_section(ci);
+
+               /*
+                *      name2 can't be a keyword
+                */
+               name = cf_section_name2(subcs);
+               if (name && unlang_compile_is_keyword(name)) {
+               invalid_name:
+                       cf_log_err(subcs, "Module names cannot be unlang keywords '%s'", name);
+                       return -1;
+               }
+
+               name = cf_section_name1(subcs);
+
+               /*
+                *      For now, ignore name1 which is a keyword.
+                */
+               if (unlang_compile_is_keyword(name)) {
+                       if (!cf_section_name2(subcs)) {
+                               cf_log_err(subcs, "Missing second name at '%s'", name);
+                               return -1;
+                       }
+                       if (module_rlm_bootstrap_virtual(subcs) < 0) return -1;
+                       continue;
+               }
+
+               /*
+                *      Skip inline templates, and disallow "template { ... }"
+                */
+               if (strcmp(name, "template") == 0) {
+                       if (!cf_section_name2(subcs)) goto invalid_name;
+                       continue;
+               }
+
+               mi = module_bootstrap(NULL, subcs);
+               if (!mi) return -1;
+
+               /*
+                *      Compile the default "actions" subsection, which includes retries.
+                */
+               actions = cf_section_find(subcs, "actions", NULL);
+               if (actions && unlang_compile_actions(&mi->actions, actions, (mi->module->type & RLM_TYPE_RETRY) != 0)) {
+                       talloc_free(mi);
+                       return -1;
+               }
+       }
+
+       cf_log_debug(modules, " } # modules");
+
+       if (fr_command_register_hook(NULL, NULL, modules, module_cmd_list_table) < 0) {
+               PERROR("Failed registering radmin commands for modules");
+               return -1;
+       }
+
+       /*
+        *      Check for duplicate policies.  They're treated as
+        *      modules, so we might as well check them here.
+        */
+       cs = cf_section_find(root, "policy", NULL);
+       if (cs) {
+               while ((ci = cf_item_next(cs, ci))) {
+                       CONF_SECTION *subcs, *problemcs;
+                       char const *name1;
+
+                       /*
+                        *      Skip anything that isn't a section.
+                        */
+                       if (!cf_item_is_section(ci)) continue;
+
+                       subcs = cf_item_to_section(ci);
+                       name1 = cf_section_name1(subcs);
+
+                       if (unlang_compile_is_keyword(name1)) {
+                               cf_log_err(subcs, "Policy name '%s' cannot be an unlang keyword", name1);
+                               return -1;
+                       }
+
+                       if (cf_section_name2(subcs)) {
+                               cf_log_err(subcs, "Policies cannot have two names");
+                               return -1;
+                       }
+
+                       problemcs = cf_section_find_next(cs, subcs, name1, CF_IDENT_ANY);
+                       if (!problemcs) continue;
+
+                       cf_log_err(problemcs, "Duplicate policy '%s' is forbidden.",
+                                  cf_section_name1(subcs));
+                       return -1;
+               }
+       }
+
+       /*
+        *      Now that all of the xlat things have been registered,
+        *      register our redundant xlats.  But only when all of
+        *      the items in such a section are the same.
+        */
+       for (vm = fr_rb_iter_init_inorder(&iter, module_rlm_virtual_name_tree);
+            vm;
+            vm = fr_rb_iter_next_inorder(&iter)) {
+               if (!vm->all_same) continue;
+
+               if (xlat_register_redundant(vm->cs) < 0) return -1;
+       }
+
+       return 0;
+}
+
+void modules_rlm_free(void)
+{
+       TALLOC_FREE(module_rlm_virtual_name_tree);
+}
+
+int modules_rlm_init(void)
+{
+       MEM(module_rlm_virtual_name_tree = fr_rb_inline_alloc(NULL, module_rlm_virtual_t, name_node,
+                                                             module_rlm_virtual_name_cmp, NULL));
+       return 0;
+}
diff --git a/src/lib/server/module_rlm.h b/src/lib/server/module_rlm.h
new file mode 100644 (file)
index 0000000..b4c3fce
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+/**
+ * $Id$
+ *
+ * @file src/lib/server/module_rlm.h
+ * @brief Defines functions for rlm module (re-)initialisation.
+ *
+ * @copyright 2022 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
+ */
+RCSIDH(module_rlm_h, "$Id$")
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+extern char const *section_type_value[MOD_COUNT];
+
+void   modules_rlm_free(void);
+
+int    modules_rlm_init(void);
+
+#ifdef __cplusplus
+}
+#endif
index a40c745e79674b51b82cb7a63f04b1df1bf7aeb0..72a15000c54633cfb9f30c167871690cc7bfcb91 100644 (file)
@@ -3915,7 +3915,7 @@ static CONF_SECTION *virtual_module_find_cs(CONF_ITEM *ci, rlm_components_t *pco
         *
         *      Return it to the caller, with the updated method.
         */
-       subcs = module_by_name_virtual(virtual_name);
+       subcs = module_rlm_by_name_virtual(virtual_name);
        if (subcs) {
                *pcomponent = method;
                goto check_for_loop;
@@ -4253,7 +4253,7 @@ check_for_module:
         *      name2, etc.
         */
        UPDATE_CTX2;
-       inst = module_by_name_and_method(&method, &unlang_ctx2.component,
+       inst = module_rlm_by_name_and_method(&method, &unlang_ctx2.component,
                                         &unlang_ctx2.section_name1, &unlang_ctx2.section_name2,
                                         realname);
        if (inst) {
index df1719ffae314e2d2965215ed107dcf8fc58522f..3f5d705e83911dcd7f31a60c2a1d4539329195bb 100644 (file)
@@ -123,7 +123,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
                return -1;
        }
 
-       driver->pool = module_connection_pool_init(conf, driver, mod_conn_create, NULL,
+       driver->pool = module_rlm_connection_pool_init(conf, driver, mod_conn_create, NULL,
                                                   buffer, "modules.rlm_cache.pool", NULL);
        if (!driver->pool) return -1;
 
index b33516fcdf921d003cbd252336f3d27e413a3a67..0e302071fa4a0a68c35208caf5448b3aadea9d93 100644 (file)
@@ -145,7 +145,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
                RETURN_MODULE_NOOP;
        }
 
-       if (!module_section_type_set(request, attr_auth_type, inst->auth_type)) {
+       if (!module_rlm_section_type_set(request, attr_auth_type, inst->auth_type)) {
                RETURN_MODULE_NOOP;
        }
 
index 9d7e19507dab9bfab925234049b1586845e3d688..f9114d0b3bc095f05939c993fe36dd25b6afba46 100644 (file)
@@ -490,7 +490,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
        }
 
        /* initiate connection pool */
-       inst->pool = module_connection_pool_init(conf, inst, mod_conn_create, mod_conn_alive, NULL, NULL, NULL);
+       inst->pool = module_rlm_connection_pool_init(conf, inst, mod_conn_create, mod_conn_alive, NULL, NULL, NULL);
 
        /* check connection pool */
        if (!inst->pool) {
index 8a7a894478da2bdba53d4bd4d09c6bb657eaead3..543898f07e735dbfe72e3b9d04f8766230d90476 100644 (file)
@@ -144,7 +144,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
                inst->escape_func = rad_filename_make_safe;
        }
 
-       inst->ef = module_exfile_init(inst, conf, 256, fr_time_delta_from_sec(30), inst->locking, NULL, NULL);
+       inst->ef = module_rlm_exfile_init(inst, conf, 256, fr_time_delta_from_sec(30), inst->locking, NULL, NULL);
        if (!inst->ef) {
                cf_log_err(conf, "Failed creating log file context");
                return -1;
index e437ba0252cead264bdb01b6c09c4a59cb9343b9..f6e665363d4c75c14c404ea4c72fede5e6f43bc4 100644 (file)
@@ -103,7 +103,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
        /*
         *      Everything's OK, add a digest authentication type.
         */
-       if (!module_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
+       if (!module_rlm_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
 
        RETURN_MODULE_OK;
 }
index eb31358779bb42ee1ac9ced307353e3e4ce54c84..26c3a8db71714f6f417bb39238afc7b824c1afef 100644 (file)
@@ -963,7 +963,7 @@ static unlang_action_t mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *
                break;
        }
 
-       if (!module_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
+       if (!module_rlm_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
 
        if (status == RLM_MODULE_OK) RETURN_MODULE_OK;
 
index 681e1c2d661a1db832b0228a8ffec8ae397c915f..58a6ebbe1a353853b68fd3d2c95f9a76d0f2cd2b 100644 (file)
@@ -222,7 +222,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
        /*
         *      Initialize the socket pool.
         */
-       inst->pool = module_connection_pool_init(mctx->inst->conf, inst, krb5_mod_conn_create, NULL, NULL, NULL, NULL);
+       inst->pool = module_rlm_connection_pool_init(mctx->inst->conf, inst, krb5_mod_conn_create, NULL, NULL, NULL, NULL);
        if (!inst->pool) return -1;
 #else
        inst->conn = krb5_mod_conn_create(inst, inst, fr_time_delta_wrap(0));
index e848b1ec85247662212ef1f0707c005144e7d3ea..4d5606372e34d79c16da908877dbd94ea66f9329 100644 (file)
@@ -37,6 +37,7 @@ USES_APPLE_DEPRECATED_API
 #include "rlm_ldap.h"
 
 #include <freeradius-devel/server/map_proc.h>
+#include <freeradius-devel/server/module_rlm.h>
 
 static CONF_PARSER sasl_mech_dynamic[] = {
        { FR_CONF_OFFSET("mech", FR_TYPE_TMPL | FR_TYPE_NOT_EMPTY, fr_ldap_sasl_t_dynamic_t, mech) },
index 73ef2e11ca0415c1634d00a894ea2110f6c6158e..6ff317a13ecf79fcf29030dbd0baf96260eca4e6 100644 (file)
@@ -322,7 +322,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
                        return -1;
                }
 
-               inst->file.ef = module_exfile_init(inst, conf, 256, fr_time_delta_from_sec(30), true, NULL, NULL);
+               inst->file.ef = module_rlm_exfile_init(inst, conf, 256, fr_time_delta_from_sec(30), true, NULL, NULL);
                if (!inst->file.ef) {
                        cf_log_err(conf, "Failed creating log file context");
                        return -1;
@@ -375,20 +375,20 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
                cf_log_err(conf, "Unix sockets are not supported on this sytem");
                return -1;
 #else
-               inst->pool = module_connection_pool_init(cf_section_find(conf, "unix", NULL),
+               inst->pool = module_rlm_connection_pool_init(cf_section_find(conf, "unix", NULL),
                                                         inst, mod_conn_create, NULL, prefix, NULL, NULL);
                if (!inst->pool) return -1;
 #endif
                break;
 
        case LINELOG_DST_UDP:
-               inst->pool = module_connection_pool_init(cf_section_find(conf, "udp", NULL),
+               inst->pool = module_rlm_connection_pool_init(cf_section_find(conf, "udp", NULL),
                                                         inst, mod_conn_create, NULL, prefix, NULL, NULL);
                if (!inst->pool) return -1;
                break;
 
        case LINELOG_DST_TCP:
-               inst->pool = module_connection_pool_init(cf_section_find(conf, "tcp", NULL),
+               inst->pool = module_rlm_connection_pool_init(cf_section_find(conf, "tcp", NULL),
                                                         inst, mod_conn_create, NULL, prefix, NULL, NULL);
                if (!inst->pool) return -1;
                break;
index 18723a2c94dbb4fe6ac45260769055030de1cea5..3ec09184a26c016f3d356deeb813cb8bcd74540e 100644 (file)
@@ -1471,7 +1471,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
                RETURN_MODULE_NOOP;
        }
 
-       if (!module_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
+       if (!module_rlm_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
 
        RETURN_MODULE_OK;
 }
@@ -2222,7 +2222,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
 #ifdef WITH_AUTH_WINBIND
                inst->method = AUTH_WBCLIENT;
 
-               inst->wb_pool = module_connection_pool_init(conf, inst, mod_conn_create, NULL, NULL, NULL, NULL);
+               inst->wb_pool = module_rlm_connection_pool_init(conf, inst, mod_conn_create, NULL, NULL, NULL, NULL);
                if (!inst->wb_pool) {
                        cf_log_err(conf, "Unable to initialise winbind connection pool");
                        return -1;
index 6363df10a62c93aa7efc9355c64a5b29bf1c0d3b..29ff569b9c70e95953f9026e073a15bb72b5235a 100644 (file)
@@ -509,7 +509,7 @@ setup_auth_type:
                RETURN_MODULE_NOOP;
        }
 
-       if (!module_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
+       if (!module_rlm_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
 
        RETURN_MODULE_OK;
 }
index 53acee092179b91b7cb07f3647dd5857afc1996b..b709235d4d0231d5aa5c46a7b8ef14bf1cd13650 100644 (file)
@@ -157,7 +157,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
                RETURN_MODULE_NOOP;
        }
 
-       if (!module_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
+       if (!module_rlm_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
 
        RETURN_MODULE_UPDATED;
 }
index 7b5257cadd95b1eb3bb6fee6f9b9fccf75b59900..e0e18b32aa9a921371b961f4222bdba795952521 100644 (file)
@@ -26,6 +26,7 @@ RCSID("$Id$")
 #include <freeradius-devel/curl/base.h>
 #include <freeradius-devel/server/base.h>
 #include <freeradius-devel/server/module.h>
+#include <freeradius-devel/server/module_rlm.h>
 #include <freeradius-devel/server/pairmove.h>
 #include <freeradius-devel/tls/base.h>
 #include <freeradius-devel/util/debug.h>
diff --git a/src/modules/rlm_sigtran/libosmo-abis b/src/modules/rlm_sigtran/libosmo-abis
new file mode 160000 (submodule)
index 0000000..f5f31d3
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit f5f31d34d1f4c21cc5cd2342930c7cf481651a1f
diff --git a/src/modules/rlm_sigtran/libosmo-netif b/src/modules/rlm_sigtran/libosmo-netif
new file mode 160000 (submodule)
index 0000000..2687d8f
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit 2687d8fb7246a6c516fec9ec91746af4376d0ffb
index a8e29a1b5d4169144d56c36d1526c89c29b3a6a3..1dbbb3379eb83e75755a7a5010cef27c8f3e588f 100644 (file)
@@ -1200,7 +1200,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
                                inst->driver->sql_escape_func :
                                sql_escape_func;
 
-       inst->ef = module_exfile_init(inst, conf, 256, fr_time_delta_from_sec(30), true, NULL, NULL);
+       inst->ef = module_rlm_exfile_init(inst, conf, 256, fr_time_delta_from_sec(30), true, NULL, NULL);
        if (!inst->ef) {
                cf_log_err(conf, "Failed creating log file context");
                return -1;
@@ -1211,7 +1211,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
         */
        INFO("Attempting to connect to database \"%s\"", inst->config.sql_db);
 
-       inst->pool = module_connection_pool_init(conf, inst, sql_mod_conn_create, NULL, NULL, NULL, NULL);
+       inst->pool = module_rlm_connection_pool_init(conf, inst, sql_mod_conn_create, NULL, NULL, NULL, NULL);
        if (!inst->pool) return -1;
 
        return 0;
index b4dab032b3dd60d7f6831ebe2887a8fd3982505b..0a0e01f5e5c468cfedf50181539c30c618f6a447 100644 (file)
@@ -365,7 +365,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx)
                return -1;
        }
 
-       inst->wb_pool = module_connection_pool_init(conf, inst, mod_conn_create, NULL, NULL, NULL, NULL);
+       inst->wb_pool = module_rlm_connection_pool_init(conf, inst, mod_conn_create, NULL, NULL, NULL, NULL);
        if (!inst->wb_pool) {
                cf_log_err(conf, "Unable to initialise winbind connection pool");
                return -1;
@@ -480,7 +480,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
                RETURN_MODULE_NOOP;
        }
 
-       if (!module_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
+       if (!module_rlm_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
 
        RETURN_MODULE_OK;
 }
index fb8643ebf28cbd72b60fda833a66043de276ece8..5aa567d042139677a7b928ad426a206678581c56 100644 (file)
@@ -374,7 +374,7 @@ static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, mod
                RETURN_MODULE_NOOP;
        }
 
-       if (!module_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
+       if (!module_rlm_section_type_set(request, attr_auth_type, inst->auth_type)) RETURN_MODULE_NOOP;
 
        RETURN_MODULE_OK;
 }
index b58b73c655dbe3266f739236ce743073d7aed220..5369f3cddda0a55998a936cc2d91fa0efe752f0e 100644 (file)
@@ -127,7 +127,7 @@ init:
                return -1;
        }
 
-       inst->pool = module_connection_pool_init(conf, inst, mod_conn_create, NULL, inst->name, NULL, NULL);
+       inst->pool = module_rlm_connection_pool_init(conf, inst, mod_conn_create, NULL, inst->name, NULL, NULL);
        if (!inst->pool) {
                ykclient_done(&inst->ykc);