From 99b2e070e27cc589e10e5eea9bf645990d97c2cf Mon Sep 17 00:00:00 2001 From: Arran Cudbard-Bell Date: Fri, 8 Apr 2022 21:22:58 -0500 Subject: [PATCH] Use separate module lists for proto, process and rlm modules --- raddb/sites-available/default | 4 +- src/bin/dhcpclient.c | 6 +- src/bin/fuzzer.c | 2 +- src/bin/radclient.c | 2 +- src/bin/radict.c | 2 +- src/bin/radiusd.c | 70 +- src/bin/radsniff.c | 2 +- src/bin/radwho.c | 2 +- src/bin/unit_test_attribute.c | 32 +- src/bin/unit_test_map.c | 2 +- src/bin/unit_test_module.c | 64 +- src/lib/io/master.c | 24 +- src/lib/server/base.c | 12 +- src/lib/server/cf_file.c | 2 +- src/lib/server/cf_parse.c | 7 +- src/lib/server/cf_util.h | 15 +- src/lib/server/dl_module.c | 115 +- src/lib/server/dl_module.h | 13 +- src/lib/server/main_config.c | 2 +- src/lib/server/modpriv.h | 2 - src/lib/server/module.c | 737 +++++---- src/lib/server/module.h | 86 +- src/lib/server/module_rlm.c | 113 +- src/lib/server/module_rlm.h | 27 +- src/lib/server/virtual_servers.c | 1390 ++++++++--------- src/lib/server/virtual_servers.h | 57 +- src/lib/unlang/call.c | 2 +- src/lib/unlang/compile.c | 2 +- src/lib/unlang/module.c | 8 +- src/lib/unlang/xlat_inst.c | 2 +- src/lib/util/dict.h | 4 +- src/lib/util/dict_priv.h | 3 + src/lib/util/dict_test.c | 2 +- src/lib/util/dict_util.c | 50 +- src/lib/util/log.c | 2 + src/listen/arp/proto_arp.c | 7 +- src/listen/control/proto_control.c | 5 +- src/listen/control/radmin.c | 2 +- src/listen/cron/proto_cron.c | 7 +- src/listen/detail/proto_detail.c | 14 +- src/listen/dhcpv4/proto_dhcpv4.c | 5 +- src/listen/dhcpv6/proto_dhcpv6.c | 5 +- src/listen/dns/proto_dns.c | 5 +- src/listen/load/proto_load.c | 7 +- src/listen/radius/proto_radius.c | 5 +- src/listen/tacacs/proto_tacacs.c | 5 +- src/listen/vmps/proto_vmps.c | 5 +- src/modules/proto_ldap_sync/sync_touch.c | 2 +- src/modules/rlm_always/rlm_always.c | 2 +- .../rlm_cache_memcached/rlm_cache_memcached.c | 2 +- .../rlm_cache_rbtree/rlm_cache_rbtree.c | 2 +- .../drivers/rlm_cache_redis/rlm_cache_redis.c | 2 +- src/modules/rlm_cache/rlm_cache.c | 2 +- src/modules/rlm_eap/rlm_eap.c | 2 +- src/modules/rlm_ldap/rlm_ldap.c | 10 +- src/modules/rlm_radius/rlm_radius.c | 2 +- .../rlm_sql_cassandra/rlm_sql_cassandra.c | 2 +- .../rlm_sql/drivers/rlm_sql_db2/rlm_sql_db2.c | 2 +- .../rlm_sql_firebird/rlm_sql_firebird.c | 2 +- .../drivers/rlm_sql_freetds/rlm_sql_freetds.c | 2 +- .../drivers/rlm_sql_mysql/rlm_sql_mysql.c | 2 +- .../drivers/rlm_sql_null/rlm_sql_null.c | 2 +- .../drivers/rlm_sql_oracle/rlm_sql_oracle.c | 2 +- .../rlm_sql_postgresql/rlm_sql_postgresql.c | 2 +- .../drivers/rlm_sql_sqlite/rlm_sql_sqlite.c | 2 +- .../rlm_sql_unixodbc/rlm_sql_unixodbc.c | 2 +- src/modules/rlm_sql/rlm_sql.c | 2 +- src/modules/rlm_sqlippool/rlm_sqlippool.c | 2 +- src/process/arp/base.c | 2 +- src/process/control/base.c | 2 +- src/process/dhcpv4/base.c | 2 +- src/process/dhcpv6/base.c | 2 +- src/process/dns/base.c | 2 +- src/process/eap_aka/base.c | 2 +- src/process/eap_aka_prime/base.c | 2 +- src/process/eap_sim/base.c | 2 +- src/process/radius/base.c | 2 +- src/process/tacacs/base.c | 2 +- src/process/tls/base.c | 2 +- src/process/ttls/base.c | 2 +- src/process/vmps/base.c | 2 +- src/tests/radmin/show-server-list.out | 2 +- 82 files changed, 1654 insertions(+), 1361 deletions(-) diff --git a/raddb/sites-available/default b/raddb/sites-available/default index efe4dd6245c..bc9f53ef82f 100644 --- a/raddb/sites-available/default +++ b/raddb/sites-available/default @@ -540,7 +540,7 @@ server default { } } - listen { + listen tcp_auth { type = Access-Request type = Status-Server @@ -597,7 +597,7 @@ server default { # # ### Listen for Accounting-Request packets # - listen { + listen udp_acct { type = Accounting-Request transport = udp diff --git a/src/bin/dhcpclient.c b/src/bin/dhcpclient.c index 516a4b57d09..304d5ea892c 100644 --- a/src/bin/dhcpclient.c +++ b/src/bin/dhcpclient.c @@ -551,8 +551,6 @@ int main(int argc, char **argv) fr_radius_packet_t *reply = NULL; fr_pair_list_t reply_vps; - TALLOC_CTX *autofree; - int ret; fr_pair_list_init(&packet_vps); @@ -563,8 +561,6 @@ int main(int argc, char **argv) */ fr_atexit_global_setup(); - autofree = talloc_autofree_context(); - fr_debug_lvl = 1; while ((c = getopt(argc, argv, "d:D:f:hr:t:vxi:")) != -1) switch(c) { @@ -611,7 +607,7 @@ int main(int argc, char **argv) if (argc < 2) usage(); - if (!fr_dict_global_ctx_init(autofree, dict_dir)) { + if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) { fr_perror("dhcpclient"); fr_exit(EXIT_FAILURE); } diff --git a/src/bin/fuzzer.c b/src/bin/fuzzer.c index b851dfd07c9..7829c825d17 100644 --- a/src/bin/fuzzer.c +++ b/src/bin/fuzzer.c @@ -146,7 +146,7 @@ int LLVMFuzzerInitialize(int *argc, char ***argv) fr_exit_now(EXIT_FAILURE); } - dict_gctx = fr_dict_global_ctx_init(NULL, dict_dir); + dict_gctx = fr_dict_global_ctx_init(NULL, true, dict_dir); if (!dict_gctx) { fr_perror("dict_global"); fr_exit_now(EXIT_FAILURE); diff --git a/src/bin/radclient.c b/src/bin/radclient.c index 3d21453b50d..7fc7145f97d 100644 --- a/src/bin/radclient.c +++ b/src/bin/radclient.c @@ -1322,7 +1322,7 @@ int main(int argc, char **argv) fr_exit_now(EXIT_FAILURE); } - if (!fr_dict_global_ctx_init(autofree, dict_dir)) { + if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) { fr_perror("radclient"); fr_exit_now(EXIT_FAILURE); } diff --git a/src/bin/radict.c b/src/bin/radict.c index e784bce3119..2e3a37365d2 100644 --- a/src/bin/radict.c +++ b/src/bin/radict.c @@ -312,7 +312,7 @@ int main(int argc, char *argv[]) goto finish; } - our_dict_gctx = fr_dict_global_ctx_init(autofree, dict_dir); + our_dict_gctx = fr_dict_global_ctx_init(NULL, true, dict_dir); if (!our_dict_gctx) { fr_perror("radict"); ret = 1; diff --git a/src/bin/radiusd.c b/src/bin/radiusd.c index 7dcfd914d2d..c737a0e43fd 100644 --- a/src/bin/radiusd.c +++ b/src/bin/radiusd.c @@ -129,7 +129,10 @@ static int talloc_config_set(main_config_t *config) */ static int thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el, UNUSED void *uctx) { - if (modules_thread_instantiate(ctx, el) < 0) return -1; + if (modules_rlm_thread_instantiate(ctx, el) < 0) return -1; + + if (virtual_servers_thread_instantiate(ctx, el) < 0) return -1; + if (xlat_thread_instantiate(ctx, el) < 0) return -1; #ifdef WITH_TLS if (fr_openssl_thread_init(main_config->openssl_async_pool_init, @@ -143,7 +146,10 @@ static int thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el, UNUSED void */ static void thread_detach(UNUSED void *uctx) { - modules_thread_detach(); + virtual_servers_thread_detach(); + + modules_rlm_thread_detach(); + xlat_thread_detach(); } @@ -234,10 +240,6 @@ int main(int argc, char *argv[]) void *pool_page_start = NULL, *pool_page_end = NULL; bool do_mprotect; - fr_dict_gctx_t const *dict_gctx = NULL; - - dl_module_loader_t *dl_modules = NULL; - #ifndef NDEBUG fr_time_delta_t exit_after = fr_time_delta_wrap(0); #endif @@ -540,18 +542,13 @@ int main(int argc, char *argv[]) * config file parser. Note that we pass an empty path * here, as we haven't yet read the configuration file. */ - dl_modules = dl_module_loader_init(NULL); - if (!dl_modules) { - fr_perror("%s", program); - EXIT_WITH_FAILURE; - } + modules_init(NULL); /* * Initialise the top level dictionary hashes which hold * the protocols. */ - dict_gctx = fr_dict_global_ctx_init(global_ctx, config->dict_dir); - if (!dict_gctx) { + if (!fr_dict_global_ctx_init(NULL, true, config->dict_dir)) { fr_perror("%s", program); EXIT_WITH_FAILURE; } @@ -563,6 +560,19 @@ int main(int argc, char *argv[]) } #endif + /* + * Setup the global structures for module lists + */ + if (modules_rlm_init() < 0) { + fr_perror("%s", program); + EXIT_WITH_FAILURE; + } + + if (virtual_servers_init() < 0) { + fr_perror("%s", program); + EXIT_WITH_FAILURE; + } + /* * Read the configuration files, BEFORE doing anything else. */ @@ -587,16 +597,6 @@ int main(int argc, char *argv[]) } } - if (modules_init() < 0) { - fr_perror("%s", program); - EXIT_WITH_FAILURE; - } - - if (virtual_servers_init(config->root_cs) < 0) { - fr_perror("%s", program); - EXIT_WITH_FAILURE; - } - /* * Set panic_action from the main config if one wasn't specified in the * environment. @@ -1083,26 +1083,24 @@ cleanup: if (config) talloc_memory_report = config->talloc_memory_report; /* Grab this before we free the config */ /* - * And now nothing should be left anywhere except the - * parsed configuration items. + * Free modules, this needs to be done explicitly + * because some libraries used by modules use atexit + * handlers registered after ours, and they may deinit + * themselves before we free the modules and cause + * crashes on exit. */ - main_config_free(&config); + modules_rlm_free(); /* - * Free the modules that we loaded. + * Same with virtual servers and proto modules. */ - if (dl_modules) talloc_free(dl_modules); + virtual_servers_free(); /* - * Complain in debug builds about dictionaries - * that haven't been freed. + * And now nothing should be left anywhere except the + * parsed configuration items. */ - if (fr_dict_global_ctx_free(dict_gctx) < 0) { -#ifndef NDEBUG - fr_perror("radiusd"); - ret = EXIT_FAILURE; -#endif - } + main_config_free(&config); /* * Cleanup everything else diff --git a/src/bin/radsniff.c b/src/bin/radsniff.c index 03183af1776..66aec78bbe4 100644 --- a/src/bin/radsniff.c +++ b/src/bin/radsniff.c @@ -2597,7 +2597,7 @@ int main(int argc, char *argv[]) conf->pcap_filter, conf->pcap_filter); } - dict_gctx = fr_dict_global_ctx_init(conf, dict_dir); + dict_gctx = fr_dict_global_ctx_init(NULL, true, dict_dir); if (!dict_gctx) { fr_perror("radsniff"); fr_exit_now(EXIT_FAILURE); diff --git a/src/bin/radwho.c b/src/bin/radwho.c index 9bdd53faf6d..e1d57d7a16d 100644 --- a/src/bin/radwho.c +++ b/src/bin/radwho.c @@ -307,7 +307,7 @@ int main(int argc, char **argv) return 1; } - dict_gctx = fr_dict_global_ctx_init(autofree, config->dict_dir); + dict_gctx = fr_dict_global_ctx_init(NULL, true, config->dict_dir); if (!dict_gctx) { fr_perror("%s", main_config->name); fr_exit_now(EXIT_FAILURE); diff --git a/src/bin/unit_test_attribute.c b/src/bin/unit_test_attribute.c index fb9686b1862..39e810cc0b6 100644 --- a/src/bin/unit_test_attribute.c +++ b/src/bin/unit_test_attribute.c @@ -3137,7 +3137,7 @@ static command_file_ctx_t *command_ctx_alloc(TALLOC_CTX *ctx, * go in this context, and don't affect the main * dictionary context. */ - cc->test_gctx = fr_dict_global_ctx_init(cc, cc->config->dict_dir); + cc->test_gctx = fr_dict_global_ctx_init(cc, false, cc->config->dict_dir); if (!cc->test_gctx) { fr_perror("Failed allocating test dict_gctx"); return NULL; @@ -3169,7 +3169,7 @@ static void command_ctx_reset(command_file_ctx_t *cc, TALLOC_CTX *ctx) if (fr_dict_global_ctx_free(cc->test_gctx) < 0) fr_perror("unit_test_attribute"); - cc->test_gctx = fr_dict_global_ctx_init(cc, cc->config->dict_dir); + cc->test_gctx = fr_dict_global_ctx_init(cc, false, cc->config->dict_dir); if (fr_dict_internal_afrom_file(&cc->test_internal_dict, FR_DICTIONARY_INTERNAL_DIR, __FILE__) < 0) { fr_perror("Failed loading test dict_gctx internal dictionary"); } @@ -3476,7 +3476,6 @@ int main(int argc, char *argv[]) CONF_SECTION *cs; int ret = EXIT_SUCCESS; TALLOC_CTX *autofree; - dl_module_loader_t *dl_modules = NULL; bool exit_now = false; command_config_t config = { @@ -3601,11 +3600,7 @@ int main(int argc, char *argv[]) fr_openssl_init(); #endif - dl_modules = dl_module_loader_init(NULL); - if (!dl_modules) { - fr_perror("unit_test_attribute"); - EXIT_WITH_FAILURE; - } + modules_init(NULL); dl_loader = dl_loader_init(autofree, NULL, false, false); if (!dl_loader) { @@ -3613,7 +3608,7 @@ int main(int argc, char *argv[]) EXIT_WITH_FAILURE; } - config.dict_gctx = fr_dict_global_ctx_init(autofree, config.dict_dir); + config.dict_gctx = fr_dict_global_ctx_init(NULL, true, config.dict_dir); if (!config.dict_gctx) { fr_perror("unit_test_attribute"); EXIT_WITH_FAILURE; @@ -3736,11 +3731,13 @@ cleanup: fr_openssl_free(); #endif - if (talloc_free(dl_modules) < 0) { - fr_perror("unit_test_attribute - dl_modules - "); /* Print free order issues */ - } - if (talloc_free(dl_loader) < 0) { + /* + * dl_loader check needed as talloc_free + * returns -1 on failure. + */ + if (dl_loader && (talloc_free(dl_loader) < 0)) { fr_perror("unit_test_attribute - dl_loader - "); /* Print free order issues */ + ret = EXIT_FAILURE; } if (fr_dict_free(&config.dict, __FILE__) < 0) { fr_perror("unit_test_attribute"); @@ -3749,15 +3746,6 @@ cleanup: unlang_free_global(); - /* - * Dictionaries get freed towards the end - * because it breaks "autofree". - */ - if (fr_dict_global_ctx_free(config.dict_gctx) < 0) { - fr_perror("unit_test_attribute"); /* Print free order issues */ - ret = EXIT_FAILURE; - } - if (receipt_file && (ret == EXIT_SUCCESS) && (fr_touch(NULL, receipt_file, 0644, true, 0755) <= 0)) { fr_perror("unit_test_attribute"); ret = EXIT_FAILURE; diff --git a/src/bin/unit_test_map.c b/src/bin/unit_test_map.c index e12c0c7104d..13300e7ba9c 100644 --- a/src/bin/unit_test_map.c +++ b/src/bin/unit_test_map.c @@ -237,7 +237,7 @@ int main(int argc, char *argv[]) EXIT_WITH_FAILURE; } - dict_gctx = fr_dict_global_ctx_init(autofree, dict_dir); + dict_gctx = fr_dict_global_ctx_init(NULL, true, dict_dir); if (!dict_gctx) { fr_perror("unit_test_map"); EXIT_WITH_FAILURE; diff --git a/src/bin/unit_test_module.c b/src/bin/unit_test_module.c index ee59421f0bb..e0131bf6f04 100644 --- a/src/bin/unit_test_module.c +++ b/src/bin/unit_test_module.c @@ -553,7 +553,6 @@ int main(int argc, char *argv[]) char *p; main_config_t *config; - dl_module_loader_t *dl_modules = NULL; CONF_SECTION *server_cs; @@ -722,13 +721,9 @@ int main(int argc, char *argv[]) * Initialize the DL infrastructure, which is used by the * config file parser. */ - dl_modules = dl_module_loader_init(config->lib_dir); - if (!dl_modules) { - fr_perror("%s", config->name); - EXIT_WITH_FAILURE; - } + modules_init(config->lib_dir); - dict_gctx = fr_dict_global_ctx_init(autofree, config->dict_dir); + dict_gctx = fr_dict_global_ctx_init(NULL, true, config->dict_dir); if (!dict_gctx) { fr_perror("%s", config->name); EXIT_WITH_FAILURE; @@ -785,18 +780,19 @@ int main(int argc, char *argv[]) setenv("PROTOCOL", PROTOCOL_NAME, true); } - /* Read the configuration files, BEFORE doing anything else. */ - if (main_config_init(config) < 0) { + /* + * Setup the global structures for module lists + */ + if (modules_rlm_init() < 0) { + fr_perror("%s", config->name); EXIT_WITH_FAILURE; } - - if (modules_init() < 0) { + if (virtual_servers_init() < 0) { fr_perror("%s", config->name); EXIT_WITH_FAILURE; } - if (virtual_servers_init(config->root_cs) < 0) { - fr_perror("%s", config->name); + if (main_config_init(config) < 0) { EXIT_WITH_FAILURE; } @@ -821,7 +817,7 @@ int main(int argc, char *argv[]) /* * Do some sanity checking. */ - dict_check = virtual_server_namespace("default"); + dict_check = virtual_server_dict_by_name("default"); if (!dict_check || (dict_check != dict_protocol)) { ERROR("Virtual server namespace does not match requested namespace '%s'", PROTOCOL_NAME); EXIT_WITH_FAILURE; @@ -836,7 +832,8 @@ int main(int argc, char *argv[]) /* * Simulate thread specific instantiation */ - if (modules_thread_instantiate(thread_ctx, el) < 0) EXIT_WITH_FAILURE; + if (modules_rlm_thread_instantiate(thread_ctx, el) < 0) EXIT_WITH_FAILURE; + if (virtual_servers_thread_instantiate(thread_ctx, el) < 0) EXIT_WITH_FAILURE; if (xlat_thread_instantiate(thread_ctx, el) < 0) EXIT_WITH_FAILURE; unlang_thread_instantiate(thread_ctx); @@ -994,6 +991,14 @@ cleanup: */ talloc_free(thread_ctx); + /* + * Ensure all thread local memory is cleaned up + * at the appropriate time. This emulates what's + * done with worker/network threads in the + * scheduler. + */ + fr_atexit_thread_trigger_all(); + /* * Give processes a chance to exit */ @@ -1024,6 +1029,20 @@ cleanup: */ unlang_free_global(); + /* + * Free modules, this needs to be done explicitly + * because some libraries used by modules use atexit + * handlers registered after ours, and they may deinit + * themselves before we free the modules and cause + * crashes on exit. + */ + modules_rlm_free(); + + /* + * Same with virtual servers and proto modules. + */ + virtual_servers_free(); + /* * And now nothing should be left anywhere except the * parsed configuration items. @@ -1039,12 +1058,10 @@ cleanup: * Free our explicitly loaded internal dictionary */ if (fr_dict_free(&dict, __FILE__) < 0) { - fr_perror("unit_test_module"); + fr_perror("unit_test_module - dict"); ret = EXIT_FAILURE; } - if (dl_modules) talloc_free(dl_modules); - /* * Free any openssl resources and the TLS dictionary */ @@ -1052,22 +1069,13 @@ cleanup: fr_openssl_free(); #endif - /* - * Free all the dictionaries, and complain/fail if - * they still have dependents. - */ - if (fr_dict_global_ctx_free(dict_gctx) < 0) { - fr_perror("unit_test_module"); - ret = EXIT_FAILURE; - } - if (receipt_file && (ret == EXIT_SUCCESS) && (fr_touch(NULL, receipt_file, 0644, true, 0755) <= 0)) { fr_perror("unit_test_module"); ret = EXIT_FAILURE; } if (talloc_free(autofree) < 0) { - fr_perror("unit_test_module"); + fr_perror("unit_test_module - autofree"); ret = EXIT_FAILURE; } diff --git a/src/lib/io/master.c b/src/lib/io/master.c index 47e0150b67a..ad1f6d57df0 100644 --- a/src/lib/io/master.c +++ b/src/lib/io/master.c @@ -46,6 +46,7 @@ typedef struct { // @todo - count num_nak_clients, and num_nak_connections, too uint32_t num_connections; //!< number of dynamic connections uint32_t num_pending_packets; //!< number of pending packets + uint64_t client_id; //!< Unique client identifier. } fr_io_thread_t; /** A saved packet @@ -475,6 +476,8 @@ static fr_io_connection_t *fr_io_connection_alloc(fr_io_instance_t const *inst, * called when the instance data is freed. */ if (!nak) { + char *inst_name; + if (inst->max_connections || client->radclient->limit.max_connections) { uint32_t max_connections = inst->max_connections ? inst->max_connections : client->radclient->limit.max_connections; @@ -495,16 +498,24 @@ static fr_io_connection_t *fr_io_connection_alloc(fr_io_instance_t const *inst, } } - if (dl_module_instance(NULL, &dl_inst, NULL, inst->dl_inst, inst->transport, DL_MODULE_TYPE_SUBMODULE) < 0) { + /* + * FIXME - This is not at all thread safe + */ + inst_name = talloc_asprintf(NULL, "%s%"PRIu64, inst->transport, thread->client_id++); + if (dl_module_instance(NULL, &dl_inst, inst->dl_inst, + DL_MODULE_TYPE_SUBMODULE, inst->transport, inst_name) < 0) { + talloc_free(inst_name); DEBUG("Failed to find proto_%s_%s", inst->app->common.name, inst->transport); return NULL; } + talloc_free(inst_name); - if (dl_module_conf_parse(dl_inst) < 0) { +/* + if (dl_module_conf_parse(dl_inst, inst->server_cs) < 0) { TALLOC_FREE(dl_inst); return NULL; } - +*/ fr_assert(dl_inst != NULL); } else { dl_inst = talloc_init_const("nak"); @@ -2602,12 +2613,13 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx) * Load proto_dhcpv4_dynamic_client */ if (dl_module_instance(conf, &inst->dynamic_submodule, - conf, inst->dl_inst, "dynamic_client", DL_MODULE_TYPE_SUBMODULE) < 0) { + inst->dl_inst, + DL_MODULE_TYPE_SUBMODULE, inst->app->common.name, "dynamic_client") < 0) { cf_log_err(conf, "Failed finding proto_%s_dynamic_client", inst->app->common.name); return -1; } - if (dl_module_conf_parse(inst->dynamic_submodule) < 0) { + if (dl_module_conf_parse(inst->dynamic_submodule, conf) < 0) { TALLOC_FREE(inst->dynamic_submodule); return -1; } @@ -2682,7 +2694,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx) if (app_process->compile_list) { tmpl_rules_t parse_rules = { .attr = { - .dict_def = virtual_server_namespace(cf_section_name2(inst->server_cs)) + .dict_def = virtual_server_dict_by_name(cf_section_name2(inst->server_cs)) } }; diff --git a/src/lib/server/base.c b/src/lib/server/base.c index 2ddfe40c0ee..8ad85d9a6fe 100644 --- a/src/lib/server/base.c +++ b/src/lib/server/base.c @@ -83,7 +83,7 @@ int server_init(CONF_SECTION *cs) /* * Instantiate the modules */ - if (modules_instantiate(cs) < 0) return -1; + if (modules_rlm_instantiate() < 0) return -1; /* * Call xlat instantiation functions (after the xlats have been compiled) @@ -105,11 +105,6 @@ void server_free(void) */ xlat_instances_free(); - /* - * Detach modules, connection pools, registered xlats / paircmps / maps. - */ - modules_free(); - /* * The only paircmps remaining are the ones registered by the server core. */ @@ -130,11 +125,6 @@ void server_free(void) */ map_proc_free(); - /* - * Free information associated with the virtual servers. - */ - virtual_servers_free(); - /* * Now we're sure no more triggers can fire, free the * trigger tree. diff --git a/src/lib/server/cf_file.c b/src/lib/server/cf_file.c index a482fe303eb..3d5612faba0 100644 --- a/src/lib/server/cf_file.c +++ b/src/lib/server/cf_file.c @@ -1165,7 +1165,7 @@ static CONF_ITEM *process_if(cf_stack_t *stack) buff[1] = stack->buff[1]; buff[2] = stack->buff[2]; - dict = virtual_server_namespace_by_ci(cf_section_to_item(parent)); + dict = virtual_server_dict_by_child_ci(cf_section_to_item(parent)); /* * fr_cond_tokenize needs the current section, so we diff --git a/src/lib/server/cf_parse.c b/src/lib/server/cf_parse.c index d1746bb8376..652ba170407 100644 --- a/src/lib/server/cf_parse.c +++ b/src/lib/server/cf_parse.c @@ -1222,9 +1222,10 @@ int cf_section_parse(TALLOC_CTX *ctx, void *base, CONF_SECTION *cs) rule = cf_data_value(rule_cd); /* - * Ignore ON_READ parse rules + * Ignore ON_READ parse rules if there's no subsequent + * parse functions. */ - if (rule->on_read) continue; + if (!rule->func && rule->on_read) continue; /* * Pre-allocate the config structure to hold default values @@ -1467,7 +1468,7 @@ int cf_section_parse_pass2(void *base, CONF_SECTION *cs) * Search for dictionary data somewhere in the virtual * server. */ - dict = virtual_server_namespace_by_ci(cf_section_to_item(cs)); + dict = virtual_server_dict_by_child_ci(cf_section_to_item(cs)); /* * Parse (and throw away) the xlat string (for validation). diff --git a/src/lib/server/cf_util.h b/src/lib/server/cf_util.h index a8b4771d961..a507bd77fce 100644 --- a/src/lib/server/cf_util.h +++ b/src/lib/server/cf_util.h @@ -211,7 +211,20 @@ CONF_DATA const *_cf_data_add(CONF_ITEM *ci, void const *data, char const *name, #define cf_data_add_static(_cf, _data, _type, _name) _cf_data_add_static(CF_TO_ITEM(_cf), _data, #_type, _name, __FILE__, __LINE__) CONF_DATA const *_cf_data_add_static(CONF_ITEM *ci, void const *data, char const *type, char const *name, char const *filename, int lineno); -#define cf_data_remove(_cf, _cd) _cf_data_remove(CF_TO_ITEM(_cf), _cd); +/** Remove an item from a parent by type and name + * + * @param[in] _cf conf section or pair to remove data from. + * @param[in] _type of data to remove. + * @param[in] _name of data to remove. + */ +#define cf_data_remove(_cf, _type, _name) _cf_data_remove(CF_TO_ITEM(_cf), cf_data_find(_cf, _type, _name)); + +/** Remove an item from a parent + * + * @param[in] _cf conf section or pair to remove data from. + * @param[in] _cd conf data to remove. + */ +#define cf_data_remove_by_data(_cf, _cd) _cf_data_remove(CF_TO_ITEM(_cf), _cd); void *_cf_data_remove(CONF_ITEM *ci, CONF_DATA const *_cd); #define cf_data_walk(_cf, _type, _cb, _ctx) _cf_data_walk(CF_TO_ITEM(_cf), #_type, _cb, _ctx) diff --git a/src/lib/server/dl_module.c b/src/lib/server/dl_module.c index a3709bfd346..4eeac4922be 100644 --- a/src/lib/server/dl_module.c +++ b/src/lib/server/dl_module.c @@ -150,7 +150,6 @@ static void dl_module_unload_func(dl_t const *dl, UNUSED void *symbol, UNUSED vo * This is used to detect potential ABI issues caused by running with modules which * were built for a different version of the server. * - * @param[in] cs being parsed. * @param[in] module Common fields from module's exported interface struct. * @returns * - 0 on success. @@ -158,7 +157,7 @@ static void dl_module_unload_func(dl_t const *dl, UNUSED void *symbol, UNUSED vo * - -2 if version mismatch. * - -3 if commit mismatch. */ -static int dl_module_magic_verify(CONF_SECTION const *cs, dl_module_common_t const *module) +static int dl_module_magic_verify(dl_module_common_t const *module) { #ifdef HAVE_DLADDR Dl_info dl_info; @@ -167,10 +166,10 @@ static int dl_module_magic_verify(CONF_SECTION const *cs, dl_module_common_t con if (MAGIC_PREFIX(module->magic) != MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER)) { #ifdef HAVE_DLADDR - cf_log_err(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname); + ERROR("Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname); #endif - cf_log_err(cs, "Application and rlm_%s magic number (prefix) mismatch." - " application: %x module: %x", module->name, + ERROR("Application and rlm_%s magic number (prefix) mismatch." + " application: %x module: %x", module->name, MAGIC_PREFIX(RADIUSD_MAGIC_NUMBER), MAGIC_PREFIX(module->magic)); return -1; @@ -178,29 +177,37 @@ static int dl_module_magic_verify(CONF_SECTION const *cs, dl_module_common_t con if (MAGIC_VERSION(module->magic) != MAGIC_VERSION(RADIUSD_MAGIC_NUMBER)) { #ifdef HAVE_DLADDR - cf_log_err(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname); + ERROR("Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname); #endif - cf_log_err(cs, "Application and rlm_%s magic number (version) mismatch." - " application: %lx module: %lx", module->name, - (unsigned long) MAGIC_VERSION(RADIUSD_MAGIC_NUMBER), - (unsigned long) MAGIC_VERSION(module->magic)); + ERROR("Application and rlm_%s magic number (version) mismatch." + " application: %lx module: %lx", module->name, + (unsigned long) MAGIC_VERSION(RADIUSD_MAGIC_NUMBER), + (unsigned long) MAGIC_VERSION(module->magic)); return -2; } if (MAGIC_COMMIT(module->magic) != MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER)) { #ifdef HAVE_DLADDR - cf_log_err(cs, "Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname); + ERROR("Failed loading module rlm_%s from file %s", module->name, dl_info.dli_fname); #endif - cf_log_err(cs, "Application and rlm_%s magic number (commit) mismatch." - " application: %lx module: %lx", module->name, - (unsigned long) MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER), - (unsigned long) MAGIC_COMMIT(module->magic)); + ERROR("Application and rlm_%s magic number (commit) mismatch." + " application: %lx module: %lx", module->name, + (unsigned long) MAGIC_COMMIT(RADIUSD_MAGIC_NUMBER), + (unsigned long) MAGIC_COMMIT(module->magic)); return -3; } return 0; } +/** Lookup a module's parent + * + */ +dl_module_inst_t const *dl_module_parent_instance(dl_module_inst_t const *child) +{ + return child->parent; +} + /** Lookup a dl_module_inst_t via instance data * */ @@ -361,8 +368,6 @@ static int _dl_module_free(dl_module_t *dl_module) * When all references to the original dlhandle are freed, dlclose() will be called on the * dlhandle to unload the module. * - * @param[in] conf section describing the module's configuration. This is only used - * to give error messages context, and for initialization. * @param[in] parent The dl_module_t of the parent module, e.g. rlm_sql for rlm_sql_postgresql. * @param[in] name of the module e.g. sql for rlm_sql. * @param[in] type Used to determine module name prefixes. Must be one of: @@ -373,7 +378,7 @@ static int _dl_module_free(dl_module_t *dl_module) * - Module handle holding dlhandle, and module's public interface structure. * - NULL if module couldn't be loaded, or some other error occurred. */ -dl_module_t const *dl_module(CONF_SECTION *conf, dl_module_t const *parent, char const *name, dl_module_type_t type) +dl_module_t const *dl_module(dl_module_t const *parent, char const *name, dl_module_type_t type) { dl_module_t *dl_module = NULL; dl_t *dl = NULL; @@ -402,7 +407,7 @@ dl_module_t const *dl_module(CONF_SECTION *conf, dl_module_t const *parent, char * If the module's already been loaded, increment the reference count. */ dl_module = fr_rb_find(dl_module_loader->module_tree, - &(dl_module_t){ .dl = &(dl_t){ .name = module_name }}); + &(dl_module_t){ .dl = &(dl_t){ .name = module_name }}); if (dl_module) { talloc_free(module_name); talloc_increase_ref_count(dl_module); @@ -420,9 +425,9 @@ dl_module_t const *dl_module(CONF_SECTION *conf, dl_module_t const *parent, char */ dl = dl_by_name(dl_module_loader->dl_loader, module_name, dl_module, false); if (!dl) { - cf_log_perr(conf, "Failed to link to module \"%s\"", module_name); - cf_log_err(conf, "Make sure it (and all its dependent libraries!) are in the search path" - " of your system's ld"); + ERROR("Failed to link to module \"%s\"", module_name); + ERROR("Make sure it (and all its dependent libraries!) are in the search path" + " of your system's ld"); error: talloc_free(module_name); talloc_free(dl_module); /* Do not free dl explicitly, it's handled by the destructor */ @@ -434,7 +439,7 @@ dl_module_t const *dl_module(CONF_SECTION *conf, dl_module_t const *parent, char common = dlsym(dl->handle, module_name); if (!common) { - cf_log_err(conf, "Could not find \"%s\" symbol in module: %s", module_name, dlerror()); + ERROR("Could not find \"%s\" symbol in module: %s", module_name, dlerror()); goto error; } dl_module->common = common; @@ -442,23 +447,23 @@ dl_module_t const *dl_module(CONF_SECTION *conf, dl_module_t const *parent, char /* * Before doing anything else, check if it's sane. */ - if (dl_module_magic_verify(conf, common) < 0) goto error; + if (dl_module_magic_verify(common) < 0) goto error; DEBUG3("%s validated. Handle address %p, symbol address %p", module_name, dl, common); if (dl_symbol_init(dl_module_loader->dl_loader, dl) < 0) { - cf_log_perr(conf, "Failed calling initializers for module \"%s\"", module_name); + ERROR("Failed calling initializers for module \"%s\"", module_name); goto error; } - cf_log_info(conf, "Loaded module \"%s\"", module_name); + DEBUG2("Loaded module %s", module_name); /* * Add the module to the dl cache */ dl_module->in_tree = fr_rb_insert(dl_module_loader->module_tree, dl_module); if (!dl_module->in_tree) { - cf_log_err(conf, "Failed caching module \"%s\"", module_name); + ERROR("Failed caching module \"%s\"", module_name); goto error; } @@ -533,66 +538,67 @@ void *dl_module_instance_symbol(dl_module_inst_t const *dl_inst, char const *sym * @param[in] ctx to allocate structures in. * @param[out] out where to write our #dl_module_inst_t containing the module * handle and instance. - * @param[in] conf section to parse. * @param[in] parent of module instance. - * @param[in] name of the module to load .e.g. 'udp' for 'proto_radius_udp' - * if the parent were 'proto_radius'. * @param[in] type of module to load. + * @param[in] mod_name of the module to load .e.g. 'udp' for 'proto_radius_udp' + * if the parent were 'proto_radius'. + * @param[in] inst_name The name of the instance .e.g. 'sql_aws_dc01' * * @return * - 0 on success. * - -1 on failure. */ int dl_module_instance(TALLOC_CTX *ctx, dl_module_inst_t **out, - CONF_SECTION *conf, dl_module_inst_t const *parent, - char const *name, dl_module_type_t type) + dl_module_inst_t const *parent, + dl_module_type_t type, char const *mod_name, char const *inst_name) { dl_module_inst_t *dl_inst; - char const *name2; DL_INIT_CHECK; MEM(dl_inst = talloc_zero(ctx, dl_module_inst_t)); - /* - * Find a section with the same name as the module - */ - dl_inst->module = dl_module(conf, parent ? parent->module : NULL, name, type); + dl_inst->module = dl_module(parent ? parent->module : NULL, mod_name, type); if (!dl_inst->module) { talloc_free(dl_inst); return -1; } + dl_inst->name = talloc_typed_strdup(dl_inst, inst_name); /* * ctx here is the main module's instance data */ dl_module_instance_data_alloc(dl_inst, dl_inst->module); - talloc_set_destructor(dl_inst, _dl_module_instance_free); - /* - * Associate the module instance with the conf section - * *before* executing any parse rules that might need it. - */ - cf_data_add(conf, dl_inst, dl_inst->module->dl->name, false); - - name2 = cf_section_name2(conf); - if (name2) { - dl_inst->name = talloc_typed_strdup(dl_inst, name2); - } else { - dl_inst->name = talloc_typed_strdup(dl_inst, cf_section_name1(conf)); - } - - dl_inst->conf = conf; dl_inst->parent = parent; - *out = dl_inst; return 0; } -int dl_module_conf_parse(dl_module_inst_t *dl_inst) +/** Avoid boilerplate when setting the module instance name + * + */ +char const *dl_module_inst_name_from_conf(CONF_SECTION *conf) { + char const *name2; + + name2 = cf_section_name2(conf); + if (name2) return name2; + + return cf_section_name1(conf); +} + +int dl_module_conf_parse(dl_module_inst_t *dl_inst, CONF_SECTION *conf) +{ + /* + * Associate the module instance with the conf section + * *before* executing any parse rules that might need it. + */ + cf_data_add(conf, dl_inst, dl_inst->module->dl->name, false); + dl_inst->conf = conf; + if (dl_inst->module->common->config && dl_inst->conf) { if ((cf_section_rules_push(dl_inst->conf, dl_inst->module->common->config)) < 0 || (cf_section_parse(dl_inst->data, dl_inst->data, dl_inst->conf) < 0)) { @@ -601,6 +607,7 @@ int dl_module_conf_parse(dl_module_inst_t *dl_inst) return -1; } } + return 0; } diff --git a/src/lib/server/dl_module.h b/src/lib/server/dl_module.h index 82396f6832d..9b36be5bfc3 100644 --- a/src/lib/server/dl_module.h +++ b/src/lib/server/dl_module.h @@ -170,8 +170,9 @@ struct dl_module_instance_s { extern fr_table_num_sorted_t const dl_module_type_prefix[]; extern size_t dl_module_type_prefix_len; -dl_module_t const *dl_module(CONF_SECTION *conf, dl_module_t const *parent, - char const *name, dl_module_type_t type); +dl_module_t const *dl_module(dl_module_t const *parent, char const *name, dl_module_type_t type); + +dl_module_inst_t const *dl_module_parent_instance(dl_module_inst_t const *child); dl_module_inst_t const *dl_module_instance_by_data(void const *data); @@ -184,10 +185,12 @@ void *dl_module_parent_data_by_child_data(void const *data); void *dl_module_instance_symbol(dl_module_inst_t const *instance, char const *sym_name); int dl_module_instance(TALLOC_CTX *ctx, dl_module_inst_t **out, - CONF_SECTION *conf, dl_module_inst_t const *parent, - char const *name, dl_module_type_t type); + dl_module_inst_t const *parent, + dl_module_type_t type, char const *name, char const *inst_name); + +char const *dl_module_inst_name_from_conf(CONF_SECTION *conf); -int dl_module_conf_parse(dl_module_inst_t *dl_inst); +int dl_module_conf_parse(dl_module_inst_t *dl_inst, CONF_SECTION *conf); char const *dl_module_search_path(void); diff --git a/src/lib/server/main_config.c b/src/lib/server/main_config.c index 7de02bbf3dc..4599f247933 100644 --- a/src/lib/server/main_config.c +++ b/src/lib/server/main_config.c @@ -1250,7 +1250,7 @@ do {\ if (cf_section_rules_push(cs, server_config) < 0) goto failure; if (cf_section_rules_push(cs, virtual_servers_config) < 0) goto failure; - DEBUG("Parsing main configuration."); + DEBUG("Parsing main configuration"); if (cf_section_parse(config, config, cs) < 0) goto failure; /* diff --git a/src/lib/server/modpriv.h b/src/lib/server/modpriv.h index e1e655ba2ce..49528c94352 100644 --- a/src/lib/server/modpriv.h +++ b/src/lib/server/modpriv.h @@ -38,8 +38,6 @@ 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); diff --git a/src/lib/server/module.c b/src/lib/server/module.c index ce4a23df727..4a5565c099a 100644 --- a/src/lib/server/module.c +++ b/src/lib/server/module.c @@ -36,23 +36,36 @@ RCSID("$Id$") #include #include -static TALLOC_CTX *instance_ctx = NULL; -static size_t instance_num = 1; +/** Heap of all lists/modules used to get a common index with module_thread_inst_list + * + */ +static fr_heap_t *module_global_inst_list; -/* - * For simplicity, this is just array[instance_num]. Once we - * finish with modules_rlm_bootstrap(), the "instance_num" above MUST - * NOT change. +/** An array of thread-local module lists + * + * The indexes in this array are identical to module_list_global, allowing + * O(1) lookups. Arrays are used here as there's no performance penalty + * once they're populated. */ -static _Thread_local module_thread_instance_t **module_thread_inst_array; +static _Thread_local module_thread_instance_t **module_thread_inst_list; -/** Lookup module instances by name and lineage +/** Toggle used to determine if it's safe to use index based lookups + * + * Index based heap lookups are significantly more efficient than binary + * searches, but they can only be performed when all module data is inserted + * into both the global module list and the thread local module list. + * + * When we start removing module lists or modules from the thread local + * heap those heaps no longer have a common index with the global module + * list so we need to revert back to doing binary searches instead of using + * common indexes. */ -static fr_rb_tree_t *module_instance_name_tree; +static _Thread_local bool module_list_in_sync = true; -/** Lookup module by instance data +/** dl module tracking + * */ -static fr_rb_tree_t *module_instance_data_tree; +static dl_module_loader_t *dl_modules = NULL; 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); @@ -134,21 +147,18 @@ static int cmd_show_module_config(FILE *fp, UNUSED FILE *fp_err, void *ctx, UNUS return 0; } -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 module_name_tab_expand(UNUSED TALLOC_CTX *talloc_ctx, UNUSED void *uctx, + fr_cmd_info_t *info, int max_expansions, char const **expansions) { - fr_rb_iter_inorder_t iter; - void *instance; - char const *text; - int count; + char const *text; + int count; if (info->argc <= 0) return 0; text = info->argv[info->argc - 1]; count = 0; - for (instance = fr_rb_iter_init_inorder(&iter, module_instance_name_tree); - instance; - instance = fr_rb_iter_next_inorder(&iter)) { + fr_heap_foreach(module_global_inst_list, module_instance_t, instance) { module_instance_t *mi = talloc_get_type_abort(instance, module_instance_t); if (count >= max_expansions) { @@ -158,24 +168,18 @@ static int module_name_tab_expand(UNUSED TALLOC_CTX *talloc_ctx, UNUSED void *uc expansions[count] = strdup(mi->name); count++; } - } + }} return count; } - static int cmd_show_module_list(FILE *fp, UNUSED FILE *fp_err, UNUSED void *uctx, UNUSED fr_cmd_info_t const *info) { - fr_rb_iter_inorder_t iter; - void *instance; - - for (instance = fr_rb_iter_init_inorder(&iter, module_instance_name_tree); - instance; - instance = fr_rb_iter_next_inorder(&iter)) { + fr_heap_foreach(module_global_inst_list, module_instance_t, instance) { module_instance_t *mi = talloc_get_type_abort(instance, module_instance_t); fprintf(fp, "\t%s\n", mi->name); - } + }} return 0; } @@ -216,6 +220,26 @@ static int cmd_set_module_status(UNUSED FILE *fp, FILE *fp_err, void *ctx, fr_cm return 0; } +/** Sort module instance data first by list then by number + * + * The module's position in the global instance heap informs of us + * of its position in the thread-specific heap, which allows for + * O(1) lookups. + */ +static int8_t _module_instance_global_cmp(void const *one, void const *two) +{ + module_instance_t const *a = talloc_get_type_abort(one, module_instance_t); + module_instance_t const *b = talloc_get_type_abort(two, module_instance_t); + int8_t ret; + + fr_assert(a->ml && b->ml); + + ret = CMP(a->ml, b->ml); + if (ret != 0) return 0; + + return CMP(a->number, b->number); +} + /** Compare module instances by parent and name * * The reason why we need parent, is because we could have submodules with names @@ -276,18 +300,20 @@ static int8_t module_instance_data_cmp(void const *one, void const *two) * @param[in] parent This _must_ point to the instance data of the parent * module. * @param[in] ci The CONF_PAIR containing the name of the submodule to load. - * @param[in] rule unused. + * @param[in] rule uctx pointer must be a pointer to a module_list_t ** + * containing the list to search in. * @return * - 0 on success. * - -1 if we failed to load the submodule. */ int module_submodule_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, - CONF_ITEM *ci, UNUSED CONF_PARSER const *rule) + CONF_ITEM *ci, CONF_PARSER const *rule) { char const *name = cf_pair_value(cf_item_to_pair(ci)); CONF_SECTION *cs = cf_item_to_section(cf_parent(ci)); CONF_SECTION *submodule_cs; module_instance_t *mi; + module_list_t *ml = talloc_get_type_abort(*((void * const *)rule->uctx), module_list_t); /* * We assume the submodule's config is the @@ -302,20 +328,38 @@ int module_submodule_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, */ if (!submodule_cs) submodule_cs = cf_section_alloc(cs, cs, name, NULL); - mi = module_bootstrap(DL_MODULE_TYPE_SUBMODULE, module_by_data(parent), submodule_cs); + /* + * The submodule name dictates the module loaded + * the instance name is always the submodule name + * and will be appended to the parent's instance + * name. + */ + mi = module_alloc(ml, module_by_data(ml, parent), DL_MODULE_TYPE_SUBMODULE, name, name); if (unlikely(mi == NULL)) { cf_log_err(submodule_cs, "Failed loading submodule"); return -1; } + if (unlikely(module_conf_parse(mi, submodule_cs) < 0)) { + cf_log_err(submodule_cs, "Failed parsing submodule config"); + error: + talloc_free(mi); + return -1; + } + + if (unlikely(module_bootstrap(mi) < 0)) { + cf_log_err(submodule_cs, "Failed bootstrapping submodule"); + goto error; + + } *((module_instance_t **)out) = mi; return 0; } - /** Find an existing module instance by its name and parent * + * @param[in] ml to search in. * @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 @@ -324,12 +368,12 @@ int module_submodule_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, * - 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) +module_instance_t *module_by_name(module_list_t const *ml, module_instance_t const *parent, char const *asked_name) { char const *inst_name; void *inst; - if (!module_instance_name_tree) return NULL; + if (!ml->name_tree) return NULL; /* * Look for the real name. Ignore the first character, @@ -339,28 +383,46 @@ module_instance_t *module_by_name(module_instance_t const *parent, char const *a 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 - }); + inst = fr_rb_find(ml->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 the module's parent (if any) + * + * @param[in] child to locate the parent for. + * @return + * - The module's parent. + * - NULL on error. + */ +module_instance_t *module_parent(module_instance_t const *child) +{ + dl_module_inst_t const *parent; + + parent = dl_module_parent_instance(child->dl_inst); + if (!parent) return NULL; + + return module_by_data(child->ml, parent->data); +} + /** Find an existing module instance by its private instance data * + * @param[in] ml to search in. * @param[in] data to resolve to module_instance_t. * @return * - Module instance matching data. * - NULL if no such module exists. */ -module_instance_t *module_by_data(void const *data) +module_instance_t *module_by_data(module_list_t const *ml, void const *data) { module_instance_t *mi; - mi = fr_rb_find(module_instance_data_tree, + mi = fr_rb_find(ml->data_tree, &(module_instance_t){ .dl_inst = &(dl_module_inst_t){ .data = UNCONST(void *, data) }, }); @@ -379,17 +441,23 @@ module_instance_t *module_by_data(void const *data) */ module_thread_instance_t *module_thread(module_instance_t *mi) { - module_thread_instance_t **array = module_thread_inst_array; - - if (!mi) return NULL; - - fr_assert(mi->number < talloc_array_length(array)); - - return array[mi->number]; + module_thread_instance_t *ti; + + fr_assert(mi->number < talloc_array_length(module_thread_inst_list)); + fr_assert(module_list_in_sync); + fr_assert_msg(fr_heap_num_elements(module_global_inst_list) == talloc_array_length(module_thread_inst_list), + "mismatch between global module heap (%u entries) and thread local (%zu entries)", + fr_heap_num_elements(module_global_inst_list), talloc_array_length(module_thread_inst_list)); + + ti = talloc_get_type_abort(module_thread_inst_list[mi->inst_idx - 1], module_thread_instance_t); + fr_assert_msg(ti->mi == mi, "thread/module mismatch thread %s (%p), module %s (%p)", + ti->mi->name, ti->mi, mi->name, mi); + return ti; } /** Retrieve module/thread specific instance data for a module * + * @param[in] ml Module list module belongs to. * @param[in] data Private instance data of the module. * Same as what would be provided by * #module_by_data. @@ -397,16 +465,22 @@ module_thread_instance_t *module_thread(module_instance_t *mi) * - Thread specific instance data on success. * - NULL if module has no thread instance data. */ -module_thread_instance_t *module_thread_by_data(void const *data) +module_thread_instance_t *module_thread_by_data(module_list_t const *ml, void const *data) { - module_thread_instance_t **array = module_thread_inst_array; - module_instance_t *mi = module_by_data(data); - + module_instance_t *mi = module_by_data(ml, data); + module_thread_instance_t *ti; if (!mi) return NULL; - fr_assert(mi->number < talloc_array_length(array)); + fr_assert(mi->number < ml->last_number); + fr_assert(module_list_in_sync); + fr_assert_msg(fr_heap_num_elements(module_global_inst_list) == talloc_array_length(module_thread_inst_list), + "mismatch between global module heap (%u entries) and thread local (%zu entries)", + fr_heap_num_elements(module_global_inst_list), talloc_array_length(module_thread_inst_list)); - return array[mi->number]; + ti = talloc_get_type_abort(module_thread_inst_list[mi->inst_idx - 1], module_thread_instance_t); + fr_assert_msg(ti->mi == mi, "thread/module mismatch thread %s (%p), module %s (%p)", + ti->mi->name, ti->mi, mi->name, mi); + return ti; } /** Explicitly free a module if a fatal error occurs during bootstrap @@ -418,81 +492,119 @@ void module_free(module_instance_t *mi) talloc_free(mi); } -/** Destructor for module_thread_instance_t array +/** Remove thread-specific data for a given module list + * + * Removes all module thread data for the */ -static int _module_thread_inst_array_free(module_thread_instance_t **array) +void modules_thread_detach(module_list_t const *ml) { - size_t i, len; + fr_rb_iter_inorder_t iter; + void *instance; - len = talloc_array_length(array); - for (i = 0; i < len; i++) { - module_thread_instance_t *ti; + /* + * Loop over all the modules in the module list + * finding and extracting their thread specific + * data, and calling their detach methods. + */ + for (instance = fr_rb_iter_init_inorder(&iter, ml->name_tree); + instance; + instance = fr_rb_iter_next_inorder(&iter)) { + module_instance_t *mi = talloc_get_type_abort(instance, module_instance_t); - if (!array[i]) continue; + talloc_free(module_thread_inst_list[mi->inst_idx - 1]); + } +} - ti = talloc_get_type_abort(array[i], module_thread_instance_t); +static int _module_thread_inst_free(module_thread_instance_t *ti) +{ + module_instance_t const *mi = ti->mi; - if (ti->mi) DEBUG4("Worker cleaning up %s thread instance data (%p/%p)", - ti->mi->module->name, ti, ti->data); + module_list_in_sync = false; /* Help catch anything attempting to do lookups */ - /* - * Check for ti->module is a hack - * and should be removed along with - * starting the instance number at 0 - */ - if (ti->mi && ti->mi->module->thread_detach) { - ti->mi->module->thread_detach(&(module_thread_inst_ctx_t const ){ - .inst = ti->mi->dl_inst, - .thread = ti->data, - .el = ti->el - }); - } - talloc_free(ti); + DEBUG4("Worker cleaning up %s thread instance data (%p/%p)", + mi->module->name, ti, ti->data); + + if (mi->module->thread_detach) { + mi->module->thread_detach(&(module_thread_inst_ctx_t const ){ + .inst = ti->mi->dl_inst, + .thread = ti->data, + .el = ti->el + }); } + /* + * Pull the thread instance out of the tree + */ + module_thread_inst_list[ti->mi->inst_idx - 1] = NULL; return 0; } +/** Free the thread local heap on exit + * + * All thread local module lists should have been destroyed by this point + */ +static void _module_thread_inst_list_free(void *tilp) +{ + module_thread_instance_t **til = talloc_get_type_abort(tilp, module_thread_instance_t *); + size_t i, len = talloc_array_length(til); + unsigned int found = 0; + + for (i = 0; i < len; i++) if (til[i]) found++; + + + if (!fr_cond_assert_msg(found == 0, + "Thread local array has %u non-null elements remaining on exit. This is a leak", + found)) { + return; + } + + talloc_free(til); +} + /** Creates per-thread instance data for modules which need it * * Must be called by any new threads before attempting to execute unlang sections. * - * @param[in] ctx to bind instance tree lifetime to. Must not be - * shared between multiple threads. + * @param[in] ctx Talloc ctx to bind thread specific data to. + * @param[in] ml Module list to perform thread instantiation for. * @param[in] el Event list servived by this thread. * @return * - 0 on success. * - -1 on failure. */ -int modules_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el) +int modules_thread_instantiate(TALLOC_CTX *ctx, module_list_t const *ml, fr_event_list_t *el) { void *instance; fr_rb_iter_inorder_t iter; /* - * Initialise the thread specific tree if this is the first time through + * Initialise the thread specific tree if this is the + * first time through or if everything else was + * de-initialised. */ - if (!module_thread_inst_array) { - MEM(module_thread_inst_array = talloc_zero_array(ctx, module_thread_instance_t *, instance_num + 1)); - talloc_set_destructor(module_thread_inst_array, _module_thread_inst_array_free); - } + if (!module_thread_inst_list) { + module_thread_instance_t **arr; - /* - * Index 0 is populated with a catchall entry - * FIXME - This is only required so we can - * fake out module instance data. As soon - * as we have multiple module lists this can - * be removed. - */ - MEM(module_thread_inst_array[0] = talloc_zero(module_thread_inst_array, module_thread_instance_t)); + arr = talloc_zero_array(NULL, module_thread_instance_t *, + fr_heap_num_elements(module_global_inst_list)); + + fr_atexit_thread_local(module_thread_inst_list, _module_thread_inst_list_free, arr); + } - for (instance = fr_rb_iter_init_inorder(&iter, module_instance_name_tree); + for (instance = fr_rb_iter_init_inorder(&iter, ml->name_tree); instance; instance = fr_rb_iter_next_inorder(&iter)) { module_instance_t *mi = talloc_get_type_abort(instance, module_instance_t); module_thread_instance_t *ti; + TALLOC_CTX *our_ctx = ctx; - MEM(ti = talloc_zero(module_thread_inst_array, module_thread_instance_t)); + /* + * Check the list pointers are ok + */ + (void)talloc_get_type_abort(mi->ml, module_list_t); + + MEM(ti = talloc_zero(our_ctx, module_thread_instance_t)); + talloc_set_destructor(ti, _module_thread_inst_free); ti->el = el; ti->mi = mi; @@ -504,7 +616,10 @@ int modules_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el) * talloc_get_type_abort() on it... */ if (!mi->module->thread_inst_type) { - talloc_set_name(ti->data, "rlm_%s_thread_t", mi->module->name); + talloc_set_name(ti->data, "%s_%s_thread_t", + fr_table_str_by_value(dl_module_type_prefix, + mi->dl_inst->module->type, ""), + mi->module->name); } else { talloc_set_name_const(ti->data, mi->module->thread_inst_type); } @@ -514,40 +629,33 @@ int modules_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el) if (mi->module->thread_instantiate && mi->module->thread_instantiate(MODULE_THREAD_INST_CTX(mi->dl_inst, ti->data, el)) < 0) { PERROR("Thread instantiation failed for module \"%s\"", mi->name); - TALLOC_FREE(module_thread_inst_array); + modules_thread_detach(ml); + TALLOC_FREE(module_thread_inst_list); return -1; } - fr_assert(mi->number < talloc_array_length(module_thread_inst_array)); - module_thread_inst_array[mi->number] = ti; + module_thread_inst_list[ti->mi->inst_idx - 1] = ti; } return 0; } -/** Explicitly call thread_detach and free any module thread instances - * - * Call this function if the module thread instances need to be free explicitly before - * another resource like the even loop is freed. - */ -void modules_thread_detach(void) -{ - if (!module_thread_inst_array) return; - TALLOC_FREE(module_thread_inst_array); -} - -/** Complete module setup by calling its instantiate function +/** Manually complete module setup by calling its instantiate function * * @param[in] instance of module to complete instantiation for. * @return * - 0 on success. * - -1 on failure. */ -int module_instantiate(void *instance) +int module_instantiate(module_instance_t *instance) { module_instance_t *mi = talloc_get_type_abort(instance, module_instance_t); + CONF_SECTION *cs = mi->dl_inst->conf; - if (mi->instantiated) return 0; + /* + * We only instantiate modules in the bootstrapped state + */ + if (mi->state != MODULE_INSTANCE_BOOTSTRAPPED) return 0; if (fr_command_register_hook(NULL, mi->name, mi, module_cmd_table) < 0) { PERROR("Failed registering radmin commands for module %s", mi->name); @@ -565,7 +673,10 @@ int module_instantiate(void *instance) * Call the instantiate method, if any. */ if (mi->module->instantiate) { - cf_log_debug(mi->dl_inst->conf, "Instantiating module \"%s\"", mi->name); + cf_log_debug(cs, "Instantiating %s_%s \"%s\"", + fr_table_str_by_value(dl_module_type_prefix, mi->dl_inst->module->type, ""), + mi->dl_inst->module->common->name, + mi->name); /* * Call the module's instantiation routine. @@ -580,18 +691,10 @@ int module_instantiate(void *instance) /* * If we're threaded, check if the module is thread-safe. * - * If it isn't, we create a mutex. + * If it isn't, we init the mutex. */ - if ((mi->module->type & MODULE_TYPE_THREAD_UNSAFE) != 0) { - mi->mutex = talloc_zero(mi, pthread_mutex_t); - - /* - * Initialize the mutex. - */ - pthread_mutex_init(mi->mutex, NULL); - } - - mi->instantiated = true; + if ((mi->module->type & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_init(&mi->mutex, NULL); + mi->state = MODULE_INSTANCE_INSTANTIATED; return 0; } @@ -601,95 +704,129 @@ int module_instantiate(void *instance) * Allows the module to initialise connection pools, and complete any registrations that depend on * attributes created during the bootstrap phase. * - * @param[in] root of the server configuration. + * @param[in] ml containing modules ot instantiate. * @return * - 0 on success. * - -1 on failure. */ -int modules_instantiate(UNUSED CONF_SECTION *root) +int modules_instantiate(module_list_t const *ml) { void *instance; fr_rb_iter_inorder_t iter; - DEBUG2("#### Instantiating modules ####"); + DEBUG2("#### Instantiating %s modules ####", ml->name); - for (instance = fr_rb_iter_init_inorder(&iter, module_instance_name_tree); + for (instance = fr_rb_iter_init_inorder(&iter, ml->name_tree); instance; instance = fr_rb_iter_next_inorder(&iter)) { - if (module_instantiate(instance) < 0) return -1; + module_instance_t *mi = talloc_get_type_abort(instance, module_instance_t); + if (mi->state != MODULE_INSTANCE_BOOTSTRAPPED) continue; + + if (module_instantiate(mi) < 0) return -1; } return 0; } -/** Recursive component of module_instance_name +/** Manually complete module bootstrap by calling its instantiate function + * + * - Parse the module configuration. + * - Call the modules "bootstrap" method. * + * @param[in] mi Module instance to bootstrap. + * @return + * - 0 on success. + * - -1 on failure. */ -static size_t _module_instance_name(TALLOC_CTX *ctx, char **out, module_instance_t const *parent, size_t need) +int module_bootstrap(module_instance_t *mi) { - if (parent) { - size_t our_len = talloc_array_length(parent->name) - 1; - char *p, *end; - size_t used; - - used = _module_instance_name(ctx, out, - parent->dl_inst->parent ? - module_by_data(parent->dl_inst->parent->data) : NULL, - (need + our_len + 1)); /* +1 for '.' */ - p = (*out) + used; - end = (*out) + talloc_array_length(*out); + /* + * We only bootstrap modules in the init state + */ + if (mi->state != MODULE_INSTANCE_INIT) return 0; - strlcpy(p, parent->name, end - p); - p += our_len; + /* + * Bootstrap the module. + * This must be done last so that the + * module can find its module_instance_t + * in the trees if it needs to bootstrap + * submodules. + */ + if (mi->module->bootstrap) { + CONF_SECTION *cs = mi->dl_inst->conf; - *p++ = '.'; /* Add the separator */ + cf_log_debug(cs, "Bootstrapping %s_%s \"%s\"", + fr_table_str_by_value(dl_module_type_prefix, mi->dl_inst->module->type, ""), + mi->dl_inst->module->common->name, + mi->name); - return (p - (*out)); + if (mi->module->bootstrap(MODULE_INST_CTX(mi->dl_inst)) < 0) { + cf_log_err(cs, "Bootstrap failed for module \"%s\"", mi->name); + return -1; + } } + mi->state = MODULE_INSTANCE_BOOTSTRAPPED; - /* - * Head on back up the stack - */ - *out = talloc_array(ctx, char, need + 1); + return 0; +} + +/** Bootstrap any modules which have not been bootstrapped already + * + * Allows the module to initialise connection pools, and complete any registrations that depend on + * attributes created during the bootstrap phase. + * + * @param[in] ml containing modules to bootstrap. + * @return + * - 0 on success. + * - -1 on failure. + */ +int modules_bootstrap(module_list_t const *ml) +{ + void *instance; + fr_rb_iter_inorder_t iter; + + DEBUG2("#### Bootstrapping %s modules ####", ml->name); + + for (instance = fr_rb_iter_init_inorder(&iter, ml->name_tree); + instance; + instance = fr_rb_iter_next_inorder(&iter)) { + module_instance_t *mi = talloc_get_type_abort(instance, module_instance_t); + if (mi->state != MODULE_INSTANCE_INIT) continue; + + if (module_bootstrap(mi) < 0) return -1; + } return 0; } -/** Generate a module name from the module's section name and its parents +/** Generate a module name from the module's name and its parents * - * @param[in] ctx Where to allocate the module name. - * @param[out] out Where to write a pointer to the instance name. - * @param[in] parent of the module. - * @param[in] cs module's configuration section. + * @param[in] ctx Where to allocate the module name. + * @param[out] out Where to write a pointer to the instance name. + * @param[in] parent of the module. + * @param[in] inst_name module's instance name. */ -static size_t module_instance_name(TALLOC_CTX *ctx, char **out, module_instance_t const *parent, CONF_SECTION *cs) +static fr_slen_t module_instance_name(TALLOC_CTX *ctx, char **out, module_list_t const *ml, + module_instance_t const *parent, char const *inst_name) { - char const *name1, *inst_name; - size_t our_len; - char *p, *end; - size_t used; + fr_sbuff_t *agg; - name1 = cf_section_name1(cs); - inst_name = cf_section_name2(cs); - if (!inst_name) inst_name = name1; + FR_SBUFF_TALLOC_THREAD_LOCAL(&agg, 64, 256); - our_len = talloc_array_length(inst_name) - 1; + while (parent) { + FR_SBUFF_IN_STRCPY_RETURN(agg, parent->name); + FR_SBUFF_IN_CHAR_RETURN(agg, '.'); - used = _module_instance_name(ctx, out, parent, our_len); - p = (*out) + used; - end = (*out) + talloc_array_length(*out); + if (!parent->dl_inst->parent) break; - strlcpy(p, inst_name, end - p); /* \0 terminates */ - p += our_len; + parent = module_by_data(ml, parent->dl_inst->parent->data); + } - /* - * Check we used the entire buffer - * ...because recursive code still makes - * my head hurt. - */ - fr_assert((size_t)(p - (*out)) == (talloc_array_length(*out) - 1)); + FR_SBUFF_IN_STRCPY_RETURN(agg, inst_name); - return (p - (*out)); + MEM(*out = talloc_bstrndup(ctx, fr_sbuff_start(agg), fr_sbuff_used(agg))); + + return fr_sbuff_used(agg); } @@ -700,17 +837,30 @@ static size_t module_instance_name(TALLOC_CTX *ctx, char **out, module_instance_ */ static int _module_instance_free(module_instance_t *mi) { + module_list_t *ml = mi->ml; + DEBUG3("Freeing %s (%p)", mi->name, mi); - if (mi->in_name_tree) if (!fr_cond_assert(fr_rb_delete(module_instance_name_tree, mi))) return 1; - if (mi->in_data_tree) if (!fr_cond_assert(fr_rb_delete(module_instance_data_tree, mi))) return 1; - if (mi->mutex) { + if (fr_heap_entry_inserted(mi->inst_idx) && !fr_cond_assert(fr_heap_extract(&module_global_inst_list, mi) == 0)) return 1; + if (fr_rb_node_inline_in_tree(&mi->name_node) && !fr_cond_assert(fr_rb_delete(ml->name_tree, mi))) return 1; + if (fr_rb_node_inline_in_tree(&mi->data_node) && !fr_cond_assert(fr_rb_delete(ml->data_tree, mi))) return 1; + + /* + * mi->module may be NULL if we failed loading the module + */ + if (mi->module && ((mi->module->type & MODULE_TYPE_THREAD_UNSAFE) != 0)) { +#ifndef NDEBUG /* - * FIXME - * The mutex MIGHT be locked... - * we'll check for that later, I guess. + * If the mutex is locked that means + * the server exited without cleaning + * up requests. + * + * Assert that the mutex is not held. */ - pthread_mutex_destroy(mi->mutex); + fr_assert(pthread_mutex_trylock(&mi->mutex) == 0); + pthread_mutex_unlock(&mi->mutex); +#endif + pthread_mutex_destroy(&mi->mutex); } /* @@ -738,82 +888,118 @@ static int _module_instance_free(module_instance_t *mi) return 0; } -/** Bootstrap a module +/** Parse the configuration associated with a module + * + * @param[in] mi To parse the configuration for. + * @param[in] mod_conf To parse. + * @return + * - 0 on success. + * - -1 on failure. + */ +int module_conf_parse(module_instance_t *mi, CONF_SECTION *mod_conf) +{ + if (dl_module_conf_parse(mi->dl_inst, mod_conf) < 0) return -1; + + return 0; +} + +/** Allocate a new module and add it to a module list for later bootstrap/instantiation * - * Load the module shared library, allocate instance data for it, - * parse the module configuration, and call the modules "bootstrap" method. + * - Load the module shared library. + * - Allocate instance data for it. * + * @param[in] ml To add module to. + * @param[in] parent of the module being bootstrapped, if this is a submodule. + * If this is not a submodule parent must be NULL. * @param[in] type What type of module we're loading. Determines the prefix * added to the library name. Should be one of: * - DL_MODULE_TYPE_MODULE - Standard backend module. * - DL_MODULE_TYPE_SUBMODULE - Usually a driver for a backend module. + * - DL_MODULE_TYPE_PROTO - A module associated with a listen section. * - DL_MODULE_TYPE_PROCESS - Protocol state machine bound to a virtual server. - * @param[in] parent of the module being bootstrapped, if this is a submodule. - * If this is not a submodule parent must be NULL. - * @param[in] cs containing the configuration for this module or submodule. + * @param[in] mod_name The name of this module, i.e. 'redis' for 'rlm_redis'. + * @param[in] inst_name Instance name for this module, i.e. "aws_redis_01". + * The notable exception is if this is a submodule, in which case + * inst_name is usually the mod_name. * @return * - A new module instance handle, containing the module's public interface, * and private instance data. * - NULL on error. */ -module_instance_t *module_bootstrap(dl_module_type_t type, module_instance_t const *parent, CONF_SECTION *cs) +module_instance_t *module_alloc(module_list_t *ml, + module_instance_t const *parent, + dl_module_type_t type, char const *mod_name, char const *inst_name) { - char *inst_name = NULL; + char *qual_inst_name = NULL; module_instance_t *mi; - char const *name1 = cf_section_name1(cs); fr_assert((type == DL_MODULE_TYPE_MODULE) || (parent && (type == DL_MODULE_TYPE_SUBMODULE)) || + (type == DL_MODULE_TYPE_PROTO) || (type == DL_MODULE_TYPE_PROCESS)); - module_instance_name(NULL, &inst_name, parent, cs); + /* + * Takes the inst_name and adds qualifiers + * if this is a submodule. + */ + module_instance_name(NULL, &qual_inst_name, ml, parent, inst_name); /* * See if the module already exists. */ - mi = module_by_name(parent, inst_name); + mi = module_by_name(ml, parent, qual_inst_name); if (mi) { - ERROR("Duplicate module \"%s\" in file %s[%d] and file %s[%d]", - inst_name, - cf_filename(cs), - cf_lineno(cs), - cf_filename(mi->dl_inst->conf), - cf_lineno(mi->dl_inst->conf)); - talloc_free(inst_name); + /* + * We may not have configuration data yet + * for the duplicate module. + */ + if (mi->dl_inst->conf) { + ERROR("Duplicate %s_%s instance \"%s\", previous instance defined at %s[%d]", + fr_table_str_by_value(dl_module_type_prefix, mi->dl_inst->module->type, ""), + mi->dl_inst->module->common->name, + qual_inst_name, + cf_filename(mi->dl_inst->conf), + cf_lineno(mi->dl_inst->conf)); + + } else { + ERROR("Duplicate %s_%s instance \"%s\"", + fr_table_str_by_value(dl_module_type_prefix, mi->dl_inst->module->type, ""), + mi->dl_inst->module->common->name, + qual_inst_name); + } + talloc_free(qual_inst_name); return NULL; } - MEM(mi = talloc_zero(parent ? parent : instance_ctx, module_instance_t)); + MEM(mi = talloc_zero(parent ? (void const *)parent : (void const *)ml, module_instance_t)); talloc_set_destructor(mi, _module_instance_free); - if (dl_module_instance(mi, &mi->dl_inst, cs, - parent ? parent->dl_inst : NULL, - name1, - type) < 0) { + if (dl_module_instance(mi, &mi->dl_inst, parent ? parent->dl_inst : NULL, + type, mod_name, qual_inst_name) < 0) { error: - mi->name = inst_name; /* Assigned purely for debug log output when mi is freed */ + mi->name = qual_inst_name; /* Assigned purely for debug log output when mi is freed */ talloc_free(mi); - talloc_free(inst_name); + talloc_free(qual_inst_name); return NULL; } fr_assert(mi->dl_inst); - mi->name = talloc_typed_strdup(mi, inst_name); - talloc_free(inst_name); /* Avoid stealing */ + mi->name = talloc_typed_strdup(mi, qual_inst_name); + talloc_free(qual_inst_name); /* Avoid stealing */ mi->module = (module_t const *)mi->dl_inst->module->common; if (!mi->module) { - cf_log_err(cs, "Missing public structure for \"%s\"", inst_name); + ERROR("Missing public structure for \"%s\"", qual_inst_name); talloc_free(mi); return NULL; } - mi->number = instance_num++; + mi->number = ml->last_number++; + mi->ml = ml; /* * Remember the module for later. */ - if (!fr_cond_assert(fr_rb_insert(module_instance_name_tree, mi))) goto error; - mi->in_name_tree = true; + if (!fr_cond_assert(fr_rb_insert(ml->name_tree, mi))) goto error; /* * Allow modules to get at their own @@ -821,78 +1007,91 @@ module_instance_t *module_bootstrap(dl_module_type_t type, module_instance_t con * looking up thread specific data * and for bootstrapping submodules. */ - if (mi->dl_inst->data) { - if (!fr_cond_assert(fr_rb_insert(module_instance_data_tree, mi))) goto error; - mi->in_data_tree = true; - } + if (mi->dl_inst->data && !fr_cond_assert(fr_rb_insert(ml->data_tree, mi))) goto error; /* - * Do this after inserting the module instance into the tree + * ...and finally insert the module + * into the global heap so we can + * get common thread-local indexes. */ - if (dl_module_conf_parse(mi->dl_inst) < 0) { - TALLOC_FREE(mi); - return NULL; - } + if (fr_heap_insert(&module_global_inst_list, mi) < 0) goto error; + + return mi; +} + +/** Free all modules loaded by the server + * + * @param[in] ml Module list being freed. + * @return 0 + */ +static int _module_list_free(module_list_t *ml) +{ + fr_rb_iter_inorder_t iter; + module_instance_t *mi; /* - * Bootstrap the module. - * This must be done last so that the - * module can find its module_instance_t - * in the trees if it needs to bootstrap - * submodules. + * We explicitly free modules so that + * they're done in a stable order. */ - if (mi->module->bootstrap) { - cf_log_debug(mi->dl_inst->conf, "Bootstrapping module \"%s\"", mi->name); - - if (mi->module->bootstrap(MODULE_INST_CTX(mi->dl_inst)) < 0) { - cf_log_err(cs, "Bootstrap failed for module \"%s\"", mi->name); - talloc_free(mi); - return NULL; - } + for (mi = fr_rb_iter_init_inorder(&iter, ml->name_tree); + mi; + mi = fr_rb_iter_next_inorder(&iter)) { + fr_rb_iter_delete_inorder(&iter); /* Keeps the iterator sane */ + talloc_free(mi); } - return mi; + return 0; } -/** Free all modules loaded by the server +/** Allocate a new module list + * + * This is used to instantiate and destroy modules in distinct phases + * for example, we may need to load all proto modules before rlm modules. + * + * If the list is freed all module instance data will be freed. + * If no more instances of the module exist the module be unloaded. + * + * @param[in] ctx To allocate the list in. + * @return A new module list. */ -void modules_free(void) +module_list_t *module_list_alloc(TALLOC_CTX *ctx, char const *name) { - if (module_instance_name_tree) { - fr_rb_iter_inorder_t iter; - module_instance_t *mi; + module_list_t *ml; - 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; + MEM(ml = talloc_zero(ctx, module_list_t)); + talloc_set_destructor(ml, _module_list_free); - fr_rb_iter_delete_inorder(&iter); - fr_rb_remove(module_instance_data_tree, mi); + MEM(ml->name = talloc_typed_strdup(ml, name)); + MEM(ml->name_tree = fr_rb_inline_alloc(ml, module_instance_t, name_node, module_instance_name_cmp, NULL)); + MEM(ml->data_tree = fr_rb_inline_alloc(ml, module_instance_t, data_node, module_instance_data_cmp, NULL)); - talloc_free(mi); - } - TALLOC_FREE(module_instance_name_tree); - } - TALLOC_FREE(module_instance_data_tree); - modules_rlm_free(); - TALLOC_FREE(instance_ctx); + return ml; } -/** Allocate the global module tree +static void _module_global_list_init(void *uctx) +{ + dl_modules = dl_module_loader_init(uctx); + MEM(module_global_inst_list = fr_heap_alloc(NULL, _module_instance_global_cmp, module_instance_t, inst_idx, 256)); +} + +static void _module_global_list_free(UNUSED void *uctx) +{ + if (!fr_cond_assert_msg(fr_heap_num_elements(module_global_inst_list) == 0, + "Global module heap has %u elements remaining on exit. This is a leak", + fr_heap_num_elements(module_global_inst_list))) return; + TALLOC_FREE(module_global_inst_list); + TALLOC_FREE(dl_modules); +} + +/** Perform global initialisation for modules * - * 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_init(void) +void modules_init(char const *lib_dir) { - 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; + /* + * Create the global module heap we use for + * common indexes in the thread-specific + * heaps. + */ + fr_atexit_global_once(_module_global_list_init, _module_global_list_free, UNCONST(char *, lib_dir)); } diff --git a/src/lib/server/module.h b/src/lib/server/module.h index def8bd30188..41f0efdb685 100644 --- a/src/lib/server/module.h +++ b/src/lib/server/module.h @@ -19,8 +19,9 @@ * $Id$ * * @file lib/server/module.h - * @brief Interface to the RADIUS module system. + * @brief Interface to the FreeRADIUS module system. * + * @copyright 2022 Arran Cudbard-Bell * @copyright 2013 The FreeRADIUS server project */ RCSIDH(modules_h, "$Id$") @@ -40,6 +41,7 @@ typedef struct module_s module_t; typedef struct module_method_names_s module_method_names_t; typedef struct module_instance_s module_instance_t; typedef struct module_thread_instance_s module_thread_instance_t; +typedef struct module_list_t module_list_t; #define MODULE_TYPE_THREAD_SAFE (0 << 0) //!< Module is threadsafe. #define MODULE_TYPE_THREAD_UNSAFE (1 << 0) //!< Module is not threadsafe. @@ -143,6 +145,15 @@ struct module_s { size_t thread_inst_size; }; +/** What state the module instance is currently in + * + */ +typedef enum { + MODULE_INSTANCE_INIT = 0, + MODULE_INSTANCE_BOOTSTRAPPED, + MODULE_INSTANCE_INSTANTIATED +} module_instance_state_t; + /** Per instance data * * Per-instance data structure, to correlate the modules with the @@ -150,9 +161,17 @@ struct module_s { * data structures. */ struct module_instance_s { + fr_heap_index_t inst_idx; //!< Entry in the bootstrap/instantiation heap. + //!< should be an identical value to the thread-specific + ///< data for this module. + fr_rb_node_t name_node; //!< Entry in the name tree. fr_rb_node_t data_node; //!< Entry in the data tree. + module_list_t *ml; //!< Module list this instance belongs to. + + uint32_t number; //!< Unique module number. + char const *name; //!< Instance name e.g. user_database. dl_module_inst_t *dl_inst; //!< Structure containing the module's instance data, @@ -164,13 +183,10 @@ struct module_instance_s { ///< This exports module methods, i.e. the functions ///< which allow the module to perform actions. - pthread_mutex_t *mutex; //!< Used prevent multiple threads entering a thread + pthread_mutex_t mutex; //!< Used prevent multiple threads entering a thread ///< unsafe module simultaneously. - uint32_t number; //!< unique module number. Used as a lookup into the - ///< thread instance array. - - bool instantiated; //!< Whether the module has been instantiated yet. + module_instance_state_t state; //!< What's been done with this module so far. /** @name Return code overrides * @{ @@ -184,13 +200,6 @@ struct module_instance_s { unlang_actions_t actions; //!< default actions and retries. /** @} */ - - /** @name Tree insertion tracking - * @{ - */ - bool in_name_tree; //!< Whether this is in the name lookup tree. - bool in_data_tree; //!< Whether this is in the data lookup tree. - /** @} */ }; /** Per thread per instance data @@ -198,6 +207,10 @@ struct module_instance_s { * Stores module and thread specific data. */ struct module_thread_instance_s { + fr_heap_index_t inst_idx; //!< Entry in the thread-specific bootstrap heap. + ///< Should be an identical value to the global + ///< instance data for the same module. + void *data; //!< Thread specific instance data. fr_event_list_t *el; //!< Event list associated with this thread. @@ -208,6 +221,18 @@ struct module_thread_instance_s { uint64_t active_callers; //! number of active callers. i.e. number of current yields }; +/** A list of modules + * + * This allows modules to be instantiated and freed in phases, + * i.e. proto modules before rlm modules. + */ +struct module_list_t { + uint32_t last_number; //!< Last identifier assigned to a module instance. + char const *name; //!< Friendly list identifier. + fr_rb_tree_t *name_tree; //!< Modules indexed by name. + fr_rb_tree_t *data_tree; //!< Modules indexed by data. +}; + /** Map string values to module state method * */ @@ -216,7 +241,6 @@ typedef struct { module_method_t func; //!< State function. } module_state_func_table_t; - /** @name Callbacks for the CONF_PARSER * * @{ @@ -229,14 +253,16 @@ int module_submodule_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, * * @{ */ -module_instance_t *module_by_name(module_instance_t const *parent, char const *asked_name); +module_instance_t *module_parent(module_instance_t const *child); -module_instance_t *module_by_data(void const *data); +module_instance_t *module_by_name(module_list_t const *ml, module_instance_t const *parent, char const *asked_name) + CC_HINT(nonnull(1,3)); -module_thread_instance_t *module_thread(module_instance_t *mi); +module_instance_t *module_by_data(module_list_t const *ml, void const *data); -module_thread_instance_t *module_thread_by_data(void const *data); +module_thread_instance_t *module_thread(module_instance_t *mi); +module_thread_instance_t *module_thread_by_data(module_list_t const *ml, void const *data); /** @} */ /** @name Module and module thread initialisation and instantiation @@ -245,18 +271,28 @@ module_thread_instance_t *module_thread_by_data(void const *data); */ void module_free(module_instance_t *mi); -int modules_init(void); +void modules_thread_detach(module_list_t const *ml); + +int modules_thread_instantiate(TALLOC_CTX *ctx, module_list_t const *ml, fr_event_list_t *el) CC_HINT(nonnull); + +int module_instantiate(module_instance_t *mi) CC_HINT(nonnull); + +int modules_instantiate(module_list_t const *ml) CC_HINT(nonnull); + +int module_bootstrap(module_instance_t *mi) CC_HINT(nonnull); -void modules_free(void); +int modules_bootstrap(module_list_t const *ml) CC_HINT(nonnull); -int modules_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el) CC_HINT(nonnull); +int module_conf_parse(module_instance_t *mi, CONF_SECTION *mod_cs) CC_HINT(nonnull); -void modules_thread_detach(void); +module_instance_t *module_alloc(module_list_t *ml, + module_instance_t const *parent, + dl_module_type_t type, char const *mod_name, char const *inst_name) + CC_HINT(nonnull(1)); -int modules_instantiate(CONF_SECTION *root) CC_HINT(nonnull); +module_list_t *module_list_alloc(TALLOC_CTX *ctx, char const *name); -module_instance_t *module_bootstrap(dl_module_type_t type, module_instance_t const *parent, CONF_SECTION *cs) - CC_HINT(nonnull(3)); +void modules_init(char const *lib_dir); /** @} */ #ifdef __cplusplus diff --git a/src/lib/server/module_rlm.c b/src/lib/server/module_rlm.c index 8b2559d73a0..b25829c5802 100644 --- a/src/lib/server/module_rlm.c +++ b/src/lib/server/module_rlm.c @@ -33,6 +33,7 @@ RCSID("$Id$") #include #include #include +#include /** Lookup virtual module by name */ @@ -65,6 +66,11 @@ char const *section_type_value[MOD_COUNT] = { "post-auth" }; +/** Global module list for all backend modules + * + */ +static module_list_t *rlm_modules; + /** Initialise a module specific exfile handle * * @see exfile_init @@ -175,14 +181,14 @@ int module_rlm_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, ch * instantiation order issues. */ inst_name = cf_pair_value(cp); - mi = module_by_name(NULL, inst_name); + mi = module_by_name(rlm_modules, NULL, inst_name); if (!mi) { cf_log_err(cp, "Unknown module instance \"%s\"", inst_name); return -1; } - if (!mi->instantiated) { + if (mi->state != MODULE_INSTANCE_INSTANTIATED) { CONF_SECTION *parent = module; /* @@ -197,14 +203,14 @@ int module_rlm_sibling_section_find(CONF_SECTION **out, CONF_SECTION *module, ch parent = tmp; } while (true); - module_instantiate(module_by_name(NULL, inst_name)); + module_instantiate(module_by_name(rlm_modules, NULL, inst_name)); } /* * Remove the config data we added for loop * detection. */ - cf_data_remove(module, cd); + cf_data_remove_by_data(module, cd); /* * Check the module instances are of the same type. @@ -450,7 +456,7 @@ module_instance_t *module_rlm_by_name_and_method(module_method_t *method, rlm_co * Module names are allowed to contain '.' * so we search for the bare module name first. */ - mi = module_by_name(NULL, name); + mi = module_by_name(rlm_modules, NULL, name); if (mi) { virtual_server_method_t const *allowed_list; @@ -610,7 +616,7 @@ module_instance_t *module_rlm_by_name_and_method(module_method_t *method, rlm_co do { *p = '\0'; - mi = module_by_name(NULL, inst_name); + mi = module_by_name(rlm_modules, NULL, inst_name); if (mi) break; /* @@ -808,6 +814,16 @@ CONF_SECTION *module_rlm_by_name_virtual(char const *asked_name) return inst->cs; } +module_thread_instance_t *module_rlm_thread_by_data(void const *data) +{ + return module_thread_by_data(rlm_modules, data); +} + +module_instance_t *module_rlm_by_name(module_instance_t const *parent, char const *asked_name) +{ + return module_by_name(rlm_modules, parent, asked_name); +} + /** Create a virtual module. * * @param[in] cs that defines the virtual module. @@ -852,7 +868,7 @@ static int module_rlm_bootstrap_virtual(CONF_SECTION *cs) /* * Ensure that the module doesn't exist. */ - mi = module_by_name(NULL, name); + mi = module_by_name(rlm_modules, NULL, name); if (mi) { ERROR("Duplicate module \"%s\" in file %s[%d] and file %s[%d]", name, @@ -928,6 +944,51 @@ static int module_rlm_bootstrap_virtual(CONF_SECTION *cs) return 0; } +/** Generic CONF_PARSER func for loading drivers + * + */ +int module_rlm_submodule_parse(TALLOC_CTX *ctx, void *out, void *parent, + CONF_ITEM *ci, CONF_PARSER const *rule) +{ + CONF_PARSER our_rule = *rule; + + our_rule.uctx = &rlm_modules; + + return module_submodule_parse(ctx, out, parent, ci, &our_rule); +} + +/** Frees thread-specific data for all registered backend modules + * + */ +void modules_rlm_thread_detach(void) +{ + modules_thread_detach(rlm_modules); +} + +/** Allocates thread-specific data for all registered backend modules + * + * @param[in] ctx To allocate any thread-specific data in. + * @param[in] el to register events. + * @return + * - 0 if all modules were instantiated successfully. + * - -1 if a module failed instantiation. + */ +int modules_rlm_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el) +{ + return modules_thread_instantiate(ctx, rlm_modules, el); +} + +/** Performs the instantiation phase for all backend modules + * + * @return + * - 0 if all modules were instantiated successfully. + * - -1 if a module failed instantiation. + */ +int modules_rlm_instantiate(void) +{ + return modules_instantiate(rlm_modules); +} + /** Bootstrap modules and virtual modules * * Parse the module config sections, and load and call each module's init() function. @@ -1009,8 +1070,24 @@ int modules_rlm_bootstrap(CONF_SECTION *root) continue; } - mi = module_bootstrap(DL_MODULE_TYPE_MODULE, NULL, subcs); - if (!mi) return -1; + mi = module_alloc(rlm_modules, NULL, DL_MODULE_TYPE_MODULE, name, dl_module_inst_name_from_conf(subcs)); + if (unlikely(mi == NULL)) { + cf_log_perr(subcs, "Failed loading module"); + return -1; + + } + + if (module_conf_parse(mi, subcs) < 0) { + cf_log_perr(subcs, "Failed parsing module config"); + error: + talloc_free(mi); + return -1; + } + + if (module_bootstrap(mi) < 0) { + cf_log_perr(subcs, "Failed bootstrapping module"); + goto error; + } /* * Compile the default "actions" subsection, which includes retries. @@ -1018,7 +1095,7 @@ int modules_rlm_bootstrap(CONF_SECTION *root) actions = cf_section_find(subcs, "actions", NULL); if (actions && unlang_compile_actions(&mi->actions, actions, (mi->module->type & MODULE_TYPE_RETRY) != 0)) { talloc_free(mi); - return -1; + goto error; } } @@ -1082,14 +1159,30 @@ int modules_rlm_bootstrap(CONF_SECTION *root) return 0; } +/** Cleanup all global structures + * + * Automatically called on exit. + */ void modules_rlm_free(void) { + TALLOC_FREE(rlm_modules); TALLOC_FREE(module_rlm_virtual_name_tree); } +static void _modules_rlm_free_atexit(UNUSED void *uctx) +{ + modules_rlm_free(); +} + +/** Initialise the module list structure + * + */ int modules_rlm_init(void) { + MEM(rlm_modules = module_list_alloc(NULL, "rlm")); MEM(module_rlm_virtual_name_tree = fr_rb_inline_alloc(NULL, module_rlm_virtual_t, name_node, module_rlm_virtual_name_cmp, NULL)); + fr_atexit_global(_modules_rlm_free_atexit, NULL); + return 0; } diff --git a/src/lib/server/module_rlm.h b/src/lib/server/module_rlm.h index 5a3a9de4ef9..904b9e06cb3 100644 --- a/src/lib/server/module_rlm.h +++ b/src/lib/server/module_rlm.h @@ -90,20 +90,43 @@ module_instance_t *module_rlm_by_name_and_method(module_method_t *method, rlm_co char const **name1, char const **name2, char const *asked_name); +module_thread_instance_t *module_rlm_thread_by_data(void const *data); + +module_instance_t *module_rlm_by_name(module_instance_t const *parent, char const *asked_name); + CONF_SECTION *module_rlm_by_name_virtual(char const *asked_name); /** @} */ +/** @name Support functions + * + * @{ + */ +int module_rlm_submodule_parse(TALLOC_CTX *ctx, void *out, void *parent, + CONF_ITEM *ci, CONF_PARSER const *rule); +/** @} */ + /** @name Module and module thread initialisation and instantiation * * @{ */ +void modules_rlm_thread_detach(void); + +int modules_rlm_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el) CC_HINT(nonnull(2)); + +int modules_rlm_instantiate(void); + int modules_rlm_bootstrap(CONF_SECTION *root) CC_HINT(nonnull); /** @} */ -void modules_rlm_free(void); +/** @name Global initialisation and free functions + * + * @{ + */ +void modules_rlm_free(void); -int modules_rlm_init(void); +int modules_rlm_init(void); +/** @} */ #ifdef __cplusplus } diff --git a/src/lib/server/virtual_servers.c b/src/lib/server/virtual_servers.c index abebb742014..ff68831f26b 100644 --- a/src/lib/server/virtual_servers.c +++ b/src/lib/server/virtual_servers.c @@ -42,16 +42,20 @@ RCSID("$Id$") #include typedef struct { - dl_module_inst_t *proto_module; //!< The proto_* module for a listen section. - fr_app_t const *app; //!< Easy access to the exported struct. + module_instance_t *proto_mi; //!< The proto_* module for a listen section. + fr_app_t const *proto_module; //!< Public interface to the proto_mi. + ///< cached for convenience. } fr_virtual_listen_t; typedef struct { - CONF_SECTION *server_cs; //!< The server section. - char const *namespace; //!< Protocol namespace - fr_virtual_listen_t **listener; //!< Listeners in this virtual server. - dl_module_inst_t *process_module; //!< the process_* module for a virtual server - dl_module_inst_t *dynamic_client_module; //!< the process_* module for a dynamic client + CONF_SECTION *server_cs; //!< The server section. + fr_virtual_listen_t **listeners; //!< Listeners in this virtual server. + + module_instance_t *process_mi; //!< The process_* module for a virtual server. + ///< Contains the dictionary used by the virtual + ///< server and the entry point for the state machine. + fr_process_module_t const *process_module; //!< Public interface to the process_mi. + ///< cached for convenience. } fr_virtual_server_t; static fr_dict_t const *dict_freeradius; @@ -71,6 +75,20 @@ fr_dict_attr_autoload_t virtual_server_dict_attr_autoload[] = { { NULL } }; +/** List of process modules we've loaded + * + * This is global for all virtual servers. Must be initialised + * _before_ the configuration is loaded. + */ +static module_list_t *process_modules; + +/** List of proto modules we've loaded + * + * This is global for all virtual servers. Must be initialised + * _before_ the configuration is loaded. + */ +static module_list_t *proto_modules; + /** Top level structure holding all virtual servers * */ @@ -92,7 +110,6 @@ static fr_rb_tree_t *server_section_name_tree = NULL; static int8_t server_section_name_cmp(void const *one, void const *two); static int namespace_on_read(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, CONF_PARSER const *rule); -static int listen_on_read(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, CONF_PARSER const *rule); static int server_on_read(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule); static int namespace_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, CONF_PARSER const *rule); @@ -100,15 +117,9 @@ static int listen_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_IT static int server_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule); static const CONF_PARSER server_on_read_config[] = { - { FR_CONF_OFFSET("namespace", FR_TYPE_STRING | FR_TYPE_REQUIRED, fr_virtual_server_t, namespace), + { FR_CONF_OFFSET("namespace", FR_TYPE_VOID | FR_TYPE_REQUIRED, fr_virtual_server_t, process_mi), .on_read = namespace_on_read }, - { FR_CONF_OFFSET("listen", FR_TYPE_SUBSECTION | FR_TYPE_MULTI | FR_TYPE_OK_MISSING, - fr_virtual_server_t, listener), - .ident2 = CF_IDENT_ANY, - .subcs_size = sizeof(fr_virtual_listen_t), .subcs_type = "fr_virtual_listen_t", - .on_read = listen_on_read }, - CONF_PARSER_TERMINATOR }; @@ -126,11 +137,11 @@ const CONF_PARSER virtual_servers_on_read_config[] = { }; static const CONF_PARSER server_config[] = { - { FR_CONF_OFFSET("namespace", FR_TYPE_STRING | FR_TYPE_REQUIRED, fr_virtual_server_t, namespace), + { FR_CONF_OFFSET("namespace", FR_TYPE_VOID | FR_TYPE_REQUIRED, fr_virtual_server_t, process_mi), .func = namespace_parse }, { FR_CONF_OFFSET("listen", FR_TYPE_SUBSECTION | FR_TYPE_MULTI | FR_TYPE_OK_MISSING, - fr_virtual_server_t, listener), + fr_virtual_server_t, listeners), .ident2 = CF_IDENT_ANY, .subcs_size = sizeof(fr_virtual_listen_t), .subcs_type = "fr_virtual_listen_t", .func = listen_parse }, @@ -151,60 +162,13 @@ const CONF_PARSER virtual_servers_config[] = { CONF_PARSER_TERMINATOR }; -typedef struct { - fr_dict_t const *dict; - char const *server; -} virtual_server_dict_t; - -/** Decrement references on dictionaries as the config sections are freed +/** Parse a "namespace" parameter * - */ -static int _virtual_server_dict_free(virtual_server_dict_t *cd) -{ - fr_dict_const_free(&cd->dict, cd->server); - return 0; -} - - -void virtual_server_dict_set(CONF_SECTION *server_cs, fr_dict_t const *dict, bool reference) -{ - virtual_server_dict_t *p; - CONF_DATA const *cd; - - cd = cf_data_find(server_cs, virtual_server_dict_t, "dictionary"); - if (cd) { - p = (virtual_server_dict_t *) cf_data_value(cd); - if (p->dict == dict) return; - - cf_log_warn(server_cs, "Attempt to add multiple different dictionaries %s and %s", - fr_dict_root(p->dict)->name, fr_dict_root(dict)->name); - return; - } - - p = talloc_zero(server_cs, virtual_server_dict_t); - p->dict = dict; - p->server = talloc_strdup(p, cf_section_name2(server_cs)); - talloc_set_destructor(p, _virtual_server_dict_free); - - if (reference) fr_dict_dependent_add(dict, p->server); - - cf_data_add(server_cs, p, "dictionary", true); -} - -fr_dict_t const *virtual_server_dict(CONF_SECTION *server_cs) -{ - virtual_server_dict_t *p; - CONF_DATA const *cd; - - cd = cf_data_find(server_cs, virtual_server_dict_t, "dictionary"); - if (cd) { - p = (virtual_server_dict_t *) cf_data_value(cd); - return p->dict; - } - return NULL; -} - -/** Parse a "namespace" parameter. + * We need to load the process module before continuing to parse the virtual server contents + * as we need to know the namespace so that we can resolve attribute names. + * + * We also need the compilation list from the proto module to figure out which sections we + * need to compile. * * @param[in] ctx to allocate data in. * @param[out] out always NULL @@ -218,17 +182,17 @@ fr_dict_t const *virtual_server_dict(CONF_SECTION *server_cs) static int namespace_on_read(TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule) { - CONF_PAIR *cp = cf_item_to_pair(ci); - CONF_SECTION *server_cs = cf_item_to_section(cf_parent(ci)); - char const *namespace = cf_pair_value(cp); - dl_module_t const *module; - char *module_name, *p, *end; + CONF_PAIR *cp = cf_item_to_pair(ci); + CONF_SECTION *server_cs = cf_item_to_section(cf_parent(ci)); + module_instance_t *mi; + char const *namespace; + char *module_name, *p, *end; + fr_process_module_t const *process; - if (!namespace || !*namespace) { - cf_log_err(ci, "Missing value for 'namespace'"); - return -1; - } + fr_cond_assert_msg(process_modules, + "virtual_servers_init MUST be called before reading virtual server config"); + namespace = cf_pair_value(cp); module_name = talloc_strdup(ctx, namespace); /* @@ -238,89 +202,31 @@ static int namespace_on_read(TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *par p < end; p++) if (*p == '-') *p = '_'; + /* - * Pass server_cs, even though it's wrong. We don't have - * anything else to pass, and the dl_module() function - * only uses the CONF_SECTION for printing. + * The module being loaded is the namespace with all '-' + * transformed to '_'. + * + * The instance name is the virtual server name. */ - module = dl_module(server_cs, NULL, module_name, DL_MODULE_TYPE_PROCESS); + mi = module_alloc(process_modules, NULL, DL_MODULE_TYPE_PROCESS, + module_name, dl_module_inst_name_from_conf(server_cs)); talloc_free(module_name); - if (module) { - fr_process_module_t const *process = (fr_process_module_t const *) module->common; - - if (*process->dict) { - virtual_server_dict_set(server_cs, *process->dict, false); - } - } - - if (!module) { + if (mi == NULL) { cf_log_perr(ci, "Failed loading process module"); return -1; } - - cf_data_add(server_cs, module, "process module", true); - - return 0; -} - -/** dl_open a proto_* module - * - * @param[in] ctx to allocate data in. - * @param[out] out always NULL - * @param[in] parent Base structure address. - * @param[in] ci #CONF_SECTION containing the listen section. - * @param[in] rule unused. - * @return - * - 0 on success. - * - -1 on failure. - */ -static int listen_on_read(UNUSED TALLOC_CTX *ctx, UNUSED void *out, UNUSED void *parent, - CONF_ITEM *ci, UNUSED CONF_PARSER const *rule) -{ - CONF_SECTION *listen_cs = cf_item_to_section(ci); - CONF_SECTION *server_cs = cf_item_to_section(cf_parent(ci)); - CONF_PAIR *namespace = cf_pair_find(server_cs, "namespace"); - char const *value; - dl_module_t const *module; - fr_app_t const *app; - bool set_dict; - - if (!namespace) { - cf_log_err(server_cs, "No 'namespace' set for virtual server"); - cf_log_err(server_cs, "Please add 'namespace = ' inside of the 'server %s { ... }' section", - cf_section_name2(server_cs)); - return -1; - } - - value = cf_section_name2(listen_cs); - if (value) { - set_dict = false; - - - } else { - value = cf_pair_value(namespace); - fr_assert(value); - set_dict = true; - - } - - if (DEBUG_ENABLED4) cf_log_debug(ci, "Loading proto_%s", value); - module = dl_module(listen_cs, NULL, value, DL_MODULE_TYPE_PROTO); - if (!module) { - cf_log_err(listen_cs, "Failed loading proto_%s module", value); + process = (fr_process_module_t const *)mi->dl_inst->module->common; + if (!*(process->dict)) { + cf_log_err(ci, "Process module is invalid - missing namespace dictionary"); + talloc_free(mi); return -1; } - cf_data_add(listen_cs, module, "proto module", true); - - if (!set_dict) return 0; - - app = (fr_app_t const *) module->common; - if (app->dict) virtual_server_dict_set(server_cs, *app->dict, true); + cf_data_add(server_cs, mi, "process_module", false); return 0; } - /** Callback when a "server" section is created. * * This callback exists only as a place-holder to ensure that the @@ -343,6 +249,28 @@ static int server_on_read(UNUSED TALLOC_CTX *ctx, UNUSED void *out, UNUSED void return 0; } + +static inline CC_HINT(always_inline) +int add_compile_list(CONF_SECTION *cs, virtual_server_compile_t const *compile_list, char const *name) +{ + int i; + virtual_server_compile_t const *list = compile_list; + + if (!compile_list) return 0; + + for (i = 0; list[i].name != NULL; i++) { + if (list[i].name == CF_IDENT_ANY) continue; + + if (virtual_server_section_register(&list[i]) < 0) { + cf_log_err(cs, "Failed registering processing section name %s for %s", + list[i].name, name); + return -1; + } + } + + return 0; +} + /** dl_open a process_* module * * @param[in] ctx to allocate data in. @@ -354,22 +282,24 @@ static int server_on_read(UNUSED TALLOC_CTX *ctx, UNUSED void *out, UNUSED void * - 0 on success. * - -1 on failure. */ -static int namespace_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule) +static int namespace_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule) { + CONF_PAIR *cp = cf_item_to_pair(ci); CONF_SECTION *server_cs = cf_item_to_section(cf_parent(ci)); CONF_SECTION *process_cs; - char const *namespace = cf_pair_value(cf_item_to_pair(ci)); - char *module_name = talloc_strdup(ctx, namespace); - char *p, *end; - fr_virtual_server_t *server = (fr_virtual_server_t *) (((uint8_t *) out) - offsetof(fr_virtual_server_t, namespace)); - int ret; - - (void) talloc_get_type_abort(server, fr_virtual_server_t); - fr_assert(namespace != NULL); + fr_virtual_server_t *server = talloc_get_type_abort(((uint8_t *) out) - offsetof(fr_virtual_server_t, process_mi), fr_virtual_server_t); + char const *namespace = cf_pair_value(cp); + module_instance_t *mi = cf_data_value(cf_data_find(server_cs, module_instance_t, "process_module")); - server->namespace = namespace; + /* + * We don't have access to fr_virtual_server_t + * in the onread callback, so we need to do the + * fixups here. + */ + server->process_mi = mi; + server->process_module = (fr_process_module_t const *)mi->dl_inst->module->common; - if (DEBUG_ENABLED4) cf_log_debug(ci, "Loading process %s into %p", namespace, out); + *(module_instance_t const **)out = mi; /* * Enforce that the protocol process configuration is in @@ -380,27 +310,26 @@ static int namespace_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF process_cs = cf_section_alloc(server_cs, server_cs, namespace, NULL); } + if (module_conf_parse(mi, process_cs) < 0) { + error: + cf_log_perr(ci, "Failed bootstrapping process module"); + cf_data_remove(server_cs, mi, "process_module"); + TALLOC_FREE(server->process_mi); + return -1; + } + /* - * Smush all hyphens to underscores for module names + * Pass server_cs, even though it's wrong. We don't have + * anything else to pass, and the dl_module() function + * only uses the CONF_SECTION for printing. */ - for (p = module_name, end = module_name + talloc_array_length(module_name) - 1; - p < end; - p++) if (*p == '-') *p = '_'; + if (module_bootstrap(server->process_mi) < 0) goto error; /* - * We now require a process module for everything. + * Pull the list of sections we need to compile out of + * the process module's public struct. */ - ret = dl_module_instance(ctx, &server->process_module, process_cs, NULL, module_name, DL_MODULE_TYPE_PROCESS); - talloc_free(module_name); - if (ret < 0) { - cf_log_warn(server_cs, "Failed loading process module"); - return -1; - } - - if (dl_module_conf_parse(server->process_module) < 0) { - TALLOC_FREE(server->process_module); - return -1; - } + add_compile_list(server->process_mi->dl_inst->conf, server->process_module->compile_list, namespace); return 0; } @@ -416,29 +345,122 @@ static int namespace_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF * - 0 on success. * - -1 on failure. */ -static int listen_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule) +static int listen_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF_ITEM *ci, UNUSED CONF_PARSER const *rule) { - fr_virtual_listen_t *listen = talloc_get_type_abort(out, fr_virtual_listen_t); /* Pre-allocated for us */ - CONF_SECTION *listen_cs = cf_item_to_section(ci); + fr_virtual_listen_t *listener = talloc_get_type_abort(out, fr_virtual_listen_t); /* Pre-allocated for us */ + CONF_SECTION *listener_cs = cf_item_to_section(ci); CONF_SECTION *server_cs = cf_item_to_section(cf_parent(ci)); CONF_PAIR *namespace = cf_pair_find(server_cs, "namespace"); - char const *value; - value = cf_section_name2(listen_cs); - if (!value) value = cf_pair_value(namespace); + CONF_PAIR *proto; + char const *mod_name; + char const *inst_name; + char *qual_inst_name; - if (DEBUG_ENABLED4) cf_log_debug(ci, "Loading %s listener into %p", value, out); + module_instance_t *mi; - if (dl_module_instance(ctx, &listen->proto_module, listen_cs, NULL, value, DL_MODULE_TYPE_PROTO) < 0) { - cf_log_err(listen_cs, "Failed loading proto module"); + fr_cond_assert_msg(proto_modules, + "virtual_servers_init MUST be called before reading virtual server config"); + + if (!namespace) { + cf_log_err(server_cs, "No 'namespace' set for virtual server"); + cf_log_err(server_cs, "Please add 'namespace = ' inside of the 'server %s { ... }' section", + cf_section_name2(server_cs)); return -1; } - if (dl_module_conf_parse(listen->proto_module) < 0) { - TALLOC_FREE(listen->proto_module); + /* + * Module name comes from the 'proto' pair if the + * listen section has one else it comes from the + * namespace of the virtual server. + * + * The following results in proto_radius being loaded: + * + * server foo { + * namespace = radius + * listen { + * + * } + * } + * + * The following results in proto_load being loaded: + * + * server foo { + * namespace = radius + * listen { + * proto = load + * + * } + * } + * + * In this way the server behaves reasonably out + * of the box, but allows foreign or generic listeners + * to be included in the server. + * + */ + proto = cf_pair_find(listener_cs, "proto"); + if (proto) { + mod_name = cf_pair_value(proto); + } else { + mod_name = cf_pair_value(namespace); + } + + /* + * Inst name comes from the 'listen' name2 + * or from the module name. + * + * The inst name is qualified with the name + * of the server the listener appears in. + * + * The following results in the instance name of 'foo.radius': + * + * server foo { + * namespace = radius + * listen { + * + * } + * } + * + * The following results in the instance name 'foo.my_network': + * + * server foo { + * namespace = radius + * listen my_network { + * + * } + * } + */ + inst_name = cf_section_name2(listener_cs); + if (!inst_name) inst_name = mod_name; + + qual_inst_name = talloc_asprintf(NULL, "%s.%s", cf_section_name2(server_cs), inst_name); + mi = module_alloc(proto_modules, NULL, DL_MODULE_TYPE_PROTO, mod_name, qual_inst_name); + talloc_free(qual_inst_name); + if (mi == NULL) return -1; + + if (DEBUG_ENABLED4) cf_log_debug(ci, "Loading %s listener into %p", inst_name, out); + + if (module_conf_parse(mi, listener_cs) < 0) { + cf_log_perr(ci, "Failed parsing config for listener"); + error: + talloc_free(mi); return -1; } + /* + * Pass server_cs, even though it's wrong. We don't have + * anything else to pass, and the dl_module() function + * only uses the CONF_SECTION for printing. + */ + if (module_bootstrap(mi) < 0) { + cf_log_perr(ci, "Failed bootstrapping listener"); + goto error; + } + + listener->proto_mi = mi; + listener->proto_module = (fr_app_t const *)listener->proto_mi->dl_inst->module->common; + cf_data_add(listener_cs, mi, "proto_module", false); + return 0; } @@ -468,7 +490,6 @@ static int server_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, } server->server_cs = server_cs; - server->namespace = cf_pair_value(namespace); /* * Now parse the listeners @@ -483,122 +504,137 @@ static int server_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, return 0; } -/** Set the request processing function. +/** Return the namespace for the named virtual server * - * Short-term hack + * @param[in] virtual_server to look for namespace in. + * @return + * - NULL on error. + * - Namespace on success. */ -unlang_action_t virtual_server_push(request_t *request, CONF_SECTION *server_cs, bool top_frame) +fr_dict_t const *virtual_server_dict_by_name(char const *virtual_server) { - fr_virtual_server_t *server; - fr_process_module_t const *process; - module_instance_t *mi = talloc_zero(request, module_instance_t); + CONF_SECTION const *server_cs; - server = cf_data_value(cf_data_find(server_cs, fr_virtual_server_t, "vs")); - if (!server) { - REDEBUG("server_cs does not contain virtual server data"); - return UNLANG_ACTION_FAIL; - } + server_cs = virtual_server_find(virtual_server); + if (!server_cs) return NULL; - mi->name = server->process_module->name; - mi->module = (module_t *)server->process_module; - mi->number = 0; /* Hacky hack hack */ + return virtual_server_dict_by_cs(server_cs); +} - process = (fr_process_module_t const *) server->process_module->module->common; - mi->dl_inst = server->process_module; - mi->instantiated = true; +/** Return the namespace for the virtual server specified by a config section + * + * @param[in] server_cs to look for namespace in. + * @return + * - NULL on error. + * - Namespace on success. + */ +fr_dict_t const *virtual_server_dict_by_cs(CONF_SECTION const *server_cs) +{ + CONF_DATA const *cd; - /* - * Bootstrap the stack with a module instance. - * - * @todo - src/lib/unlang/module.c calls module_thread(), - * which looks up mi->number in various data structures. - * It's probably best to initialize instance_num=1 in - * src/lib/server/module.c, that reserves 0 for "nothing - * is initialized". - */ - if (unlang_module_push(&request->rcode, request, mi, process->process, top_frame) < 0) return UNLANG_ACTION_FAIL; + cd = cf_data_find(server_cs, module_instance_t, "process_module"); + if (cd) { + module_instance_t const *mi = cf_data_value(cd); + fr_process_module_t const *process = (fr_process_module_t const *)mi->module; - return UNLANG_ACTION_PUSHED_CHILD; + return *(process->dict); + } + return NULL; } -/** Allow dynamic clients in this virtual server. +/** Return the namespace for a given virtual server specified by a CONF_ITEM within the virtual server * - * Short-term hack -*/ -int virtual_server_dynamic_clients_allow(CONF_SECTION *server_cs) + * @param[in] ci to look for namespace in. + * @return + * - NULL on error. + * - Namespace on success. + */ +fr_dict_t const *virtual_server_dict_by_child_ci(CONF_ITEM const *ci) { - fr_virtual_server_t *server; - - server = cf_data_value(cf_data_find(server_cs, fr_virtual_server_t, "vs")); - if (server->dynamic_client_module) return 0; + CONF_DATA const *cd; - if (dl_module_instance(server_cs, &server->dynamic_client_module, server_cs, NULL, "dynamic_client", DL_MODULE_TYPE_PROCESS) < 0) { - cf_log_err(server_cs, "Failed loading dynamic client module"); - return -1; - } + cd = cf_data_find_in_parent(ci, module_instance_t, "process_module"); + if (cd) { + module_instance_t const *mi = cf_data_value(cd); + fr_process_module_t const *process = (fr_process_module_t const *)mi->module; - if (dl_module_conf_parse(server->dynamic_client_module) < 0) { - TALLOC_FREE(server->dynamic_client_module); - return -1; + return *(process->dict); } - - return 0; + return NULL; } -/** Define a values for Auth-Type attributes by the sections present in a virtual-server +/** Verify that a given virtual_server exists and is of a particular namespace * - * The ident2 value of any sections found will be converted into values of the specified da. + * Mostly used by modules to check virtual servers specified by their configs. * - * @param[in] server_cs The virtual server containing the sections. - * @param[in] subcs_name of the subsection to search for. - * @param[in] da to add enumeration values for. + * @param[out] out we found. May be NULL if just checking for existence. + * @param[in] virtual_server to check. + * @param[in] namespace the virtual server must belong to. + * @param[in] ci to log errors against. May be NULL if caller + * doesn't want errors logged. * @return - * - 0 all values added successfully. - * - -1 an error occurred. + * - 0 on success. + * - -1 if no virtual server could be found. + * - -2 if virtual server is not of the correct namespace. */ -int virtual_server_section_attribute_define(CONF_SECTION *server_cs, char const *subcs_name, fr_dict_attr_t const *da) +int virtual_server_has_namespace(CONF_SECTION **out, + char const *virtual_server, fr_dict_t const *namespace, CONF_ITEM *ci) { - int rcode = 0; - CONF_SECTION *subcs = NULL; - - fr_assert(strcmp(cf_section_name1(server_cs), "server") == 0); - - while ((subcs = cf_section_find_next(server_cs, subcs, subcs_name, CF_IDENT_ANY))) { - char const *name2; - fr_dict_enum_value_t *dv; + CONF_SECTION *server_cs; + fr_dict_t const *dict; - name2 = cf_section_name2(subcs); - if (!name2) { - cf_log_err(subcs, "Invalid '%s { ... }' section, it must have a name", subcs_name); - return -1; - } - - /* - * If the value already exists, don't - * create it again. - */ - dv = fr_dict_enum_by_name(da, name2, -1); - if (dv) continue; - - cf_log_debug(subcs, "Creating %s = %s", da->name, name2); + if (out) *out = NULL; + server_cs = virtual_server_find(virtual_server); + if (!server_cs) { + if (ci) cf_log_err(ci, "Can't find virtual server \"%s\"", virtual_server); + return -1; + } + dict = virtual_server_dict_by_name(virtual_server); + if (!dict) { /* - * Create a new unique value with a meaningless - * number. You can't look at it from outside of - * this code, so it doesn't matter. The only - * requirement is that it's unique. + * Not sure this is even a valid state? */ - if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(da), name2) < 0) { - PERROR("Failed adding section value"); - return -1; - } + if (ci) cf_log_err(ci, "No namespace found in virtual server \"%s\"", virtual_server); + return -2; + } - rcode = 1; + if (dict != namespace) { + if (ci) { + cf_log_err(ci, + "Expected virtual server \"%s\" to be of namespace \"%s\", got namespace \"%s\"", + virtual_server, fr_dict_root(namespace)->name, fr_dict_root(dict)->name); + } + return -2; } - return rcode; + if (out) *out = server_cs; + + return 0; } +/** Set the request processing function. + * + * Short-term hack + */ +unlang_action_t virtual_server_push(request_t *request, CONF_SECTION *server_cs, bool top_frame) +{ + fr_virtual_server_t *server; + + server = cf_data_value(cf_data_find(server_cs, fr_virtual_server_t, "vs")); + if (!server) { + REDEBUG("server_cs does not contain virtual server data"); + return UNLANG_ACTION_FAIL; + } + + /* + * Bootstrap the stack with a module instance. + */ + if (unlang_module_push(&request->rcode, request, server->process_mi, + server->process_module->process, top_frame) < 0) return UNLANG_ACTION_FAIL; + + return UNLANG_ACTION_PUSHED_CHILD; +} static int cmd_show_server_list(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, UNUSED fr_cmd_info_t const *info) { @@ -608,7 +644,7 @@ static int cmd_show_server_list(FILE *fp, UNUSED FILE *fp_err, UNUSED void *ctx, for (i = 0; i < server_cnt; i++) { fprintf(fp, "%-30snamespace = %s\n", cf_section_name2(virtual_servers[i]->server_cs), - virtual_servers[i]->namespace); + fr_dict_root(*(virtual_servers[i]->process_module->dict))->name); } return 0; @@ -725,343 +761,6 @@ bool listen_record(fr_listen_t *li) return fr_rb_insert(listen_addr_root, li); } -static int process_instantiate(CONF_SECTION *server_cs, dl_module_inst_t *dl_inst, fr_dict_t const *dict) -{ - fr_process_module_t const *process = (fr_process_module_t const *) dl_inst->module->common; - - if (process->common.instantiate && - (process->common.instantiate(MODULE_INST_CTX(dl_inst)) < 0)) { - cf_log_err(dl_inst->conf, "Instantiate failed"); - return -1; - } - - /* - * Compile the processing sections. - */ - if (process->compile_list) { - tmpl_rules_t parse_rules; - - memset(&parse_rules, 0, sizeof(parse_rules)); - parse_rules.attr.dict_def = dict; - fr_assert(parse_rules.attr.dict_def != NULL); - - if (virtual_server_compile_sections(server_cs, process->compile_list, &parse_rules, - dl_inst->data) < 0) { - return -1; - } - } - - return 0; -} - - -/** Instantiate all the virtual servers - * - * @return - * - 0 on success. - * - -1 on failure. - */ -int virtual_servers_instantiate(void) -{ - size_t i, server_cnt = virtual_servers ? talloc_array_length(virtual_servers) : 0; - - fr_assert(virtual_servers); - - DEBUG2("#### Instantiating listeners ####"); - - if (fr_command_register_hook(NULL, NULL, virtual_server_root, cmd_table) < 0) { - PERROR("Failed registering radmin commands for virtual servers"); - return -1; - } - - for (i = 0; i < server_cnt; i++) { - fr_virtual_listen_t **listener; - size_t j, listen_cnt; - CONF_ITEM *ci = NULL; - CONF_SECTION *server_cs = virtual_servers[i]->server_cs; - CONF_DATA const *cd; - virtual_server_dict_t *dict = NULL; - - cd = cf_data_find(server_cs, virtual_server_dict_t, "dictionary"); - if (cd) { /* only NULl for the control socket */ - dict = (virtual_server_dict_t *) cf_data_value(cd); - fr_assert(dict != NULL); - } - - listener = virtual_servers[i]->listener; - listen_cnt = talloc_array_length(listener); - - DEBUG("Compiling policies in server %s { ... }", cf_section_name2(server_cs)); - - fr_assert(virtual_servers[i]->namespace != NULL); - - for (j = 0; j < listen_cnt; j++) { - fr_virtual_listen_t *listen = listener[j]; - - fr_assert(listen != NULL); - fr_assert(listen->proto_module != NULL); - fr_assert(listen->app != NULL); - - if (listen->app->common.instantiate && - listen->app->common.instantiate(MODULE_INST_CTX(listen->proto_module)) < 0) { - cf_log_err(listen->proto_module->conf, "Could not load virtual server \"%s\".", - cf_section_name2(server_cs)); - return -1; - } - } - - fr_assert(virtual_servers[i]->process_module); - - if (!dict) { - cf_log_err(server_cs, "No dictionary for namespace %s", virtual_servers[i]->namespace); - return -1; /* should never happen */ - } - - if (process_instantiate(server_cs, virtual_servers[i]->process_module, dict->dict) < 0) return -1; - - if (virtual_servers[i]->dynamic_client_module && - (process_instantiate(server_cs, virtual_servers[i]->dynamic_client_module, dict->dict) < 0)) return -1; - - /* - * Print out warnings for unused "recv" and - * "send" sections. - * - * @todo - check against the "compile_list" - * registered for this virtual server, instead of hard-coding stuff. - */ - while ((ci = cf_item_next(server_cs, ci))) { - char const *name; - CONF_SECTION *subcs; - - if (!cf_item_is_section(ci)) continue; - - subcs = cf_item_to_section(ci); - name = cf_section_name1(subcs); - - /* - * Skip known "other" sections - */ - if ((strcmp(name, "listen") == 0) || (strcmp(name, "client") == 0)) continue; - - /* - * For every other section, warn if it hasn't - * been compiled. - */ - if (!cf_data_find(subcs, unlang_group_t, NULL)) { - char const *name2; - - name2 = cf_section_name2(subcs); - if (!name2) name2 = ""; - - cf_log_warn(subcs, "%s %s { ... } section is unused", name, name2); - } - } - } - - return 0; -} - -static int add_compile_list(CONF_SECTION *cs, virtual_server_compile_t const *compile_list, char const *name) -{ - int i; - virtual_server_compile_t const *list = compile_list; - - if (!compile_list) return 0; - - for (i = 0; list[i].name != NULL; i++) { - if (list[i].name == CF_IDENT_ANY) continue; - - if (virtual_server_section_register(&list[i]) < 0) { - cf_log_err(cs, "Failed registering processing section name %s for %s", - list[i].name, name); - return -1; - } - } - - return 0; -} - -static int process_bootstrap(dl_module_inst_t *dl_inst, char const *namespace) -{ - fr_process_module_t const *process = (fr_process_module_t const *) dl_inst->module->common; - - if (process->common.bootstrap && - (process->common.bootstrap(MODULE_INST_CTX(dl_inst)) < 0)) { - cf_log_err(dl_inst->conf, "Bootstrap failed"); - return -1; - } - - return add_compile_list(dl_inst->conf, process->compile_list, namespace); -} - -/** Load protocol modules and call their bootstrap methods - * - * @return - * - 0 on success. - * - -1 on failure. - */ -int virtual_servers_bootstrap(CONF_SECTION *config) -{ - size_t i, server_cnt = 0; - CONF_SECTION *cs = NULL; - - if (!virtual_servers) { - ERROR("No server { ... } sections found"); - return -1; - } - - /* - * Check the talloc hierarchy is sane - */ - talloc_get_type_abort(virtual_servers, fr_virtual_server_t *); - server_cnt = talloc_array_length(virtual_servers); - - DEBUG2("#### Bootstrapping listeners ####"); - - /* - * Load all of the virtual servers. - */ - while ((cs = cf_section_find_next(config, cs, "server", CF_IDENT_ANY))) { - char const *server_name; - CONF_SECTION *bad; - - server_name = cf_section_name2(cs); - if (!server_name) { - cf_log_err(cs, "server sections must have a name"); - return -1; - } - - bad = cf_section_find_next(config, cs, "server", server_name); - if (bad) { - cf_log_err(bad, "Duplicate virtual servers are forbidden."); - cf_log_err(cs, "Previous definition occurs here."); - return -1; - } - - /* - * Ignore internally generated "server" sections, - * they're for the unit tests. - */ - if (!cf_filename(cs)) continue; - - /* - * Forbid old-style virtual servers. - */ - if (!cf_pair_find(cs, "namespace")) { - cf_log_err(cs, "server %s { ...} section must set 'namespace = ...' to define the server protocol", server_name); - return -1; - } - } - - for (i = 0; i < server_cnt; i++) { - fr_virtual_listen_t **listener; - size_t j, listen_cnt; - - fr_assert(virtual_servers[i] != NULL); - - /* - * The only listener which can't have a dictionary is "control". - */ - fr_assert((cf_data_find(virtual_servers[i]->server_cs, virtual_server_dict_t, "dictionary") != NULL) || - (virtual_servers[i]->listener && - (strcmp(((fr_virtual_listen_t *) virtual_servers[i]->listener[0])->proto_module->module->common->name, "control") == 0))); - - if (!virtual_servers[i]->listener) goto bootstrap; - - listener = talloc_get_type_abort(virtual_servers[i]->listener, fr_virtual_listen_t *); - listen_cnt = talloc_array_length(listener); - - for (j = 0; j < listen_cnt; j++) { - fr_virtual_listen_t *listen = listener[j]; - - fr_assert(listen != NULL); - fr_assert(listen->proto_module != NULL); - - (void) talloc_get_type_abort(listen, fr_virtual_listen_t); - - talloc_get_type_abort(listen->proto_module, dl_module_inst_t); - listen->app = (fr_app_t const *)listen->proto_module->module->common; - - if (listen->app->common.bootstrap && - listen->app->common.bootstrap(MODULE_INST_CTX(listen->proto_module)) < 0) { - cf_log_err(listen->proto_module->conf, "Bootstrap failed"); - return -1; - } - } - - bootstrap: - fr_assert(virtual_servers[i]->process_module); - - if (process_bootstrap(virtual_servers[i]->process_module, - virtual_servers[i]->namespace) < 0) return -1; - - if (virtual_servers[i]->dynamic_client_module && - (process_bootstrap(virtual_servers[i]->process_module, - virtual_servers[i]->namespace) < 0)) return -1; - } - - return 0; -} - -/** Open all the listen sockets - * - * @param[in] sc Scheduler to add I/O paths to. - * @return - * - 0 on success. - * - -1 on failure. - */ -int virtual_servers_open(fr_schedule_t *sc) -{ - size_t i, server_cnt = virtual_servers ? talloc_array_length(virtual_servers) : 0; - - fr_assert(virtual_servers); - - DEBUG2("#### Opening listener interfaces ####"); - fr_strerror_clear(); - - for (i = 0; i < server_cnt; i++) { - fr_virtual_listen_t **listener; - size_t j, listen_cnt; - - listener = virtual_servers[i]->listener; - listen_cnt = talloc_array_length(listener); - - for (j = 0; j < listen_cnt; j++) { - fr_virtual_listen_t *listen = listener[j]; - - fr_assert(listen != NULL); - fr_assert(listen->proto_module != NULL); - fr_assert(listen->app != NULL); - - /* - * The socket is opened with app_instance, - * but all subsequent calls (network.c, etc.) use app_io_instance. - * - * The reason is that we call (for example) proto_radius to - * open the socket, and proto_radius is responsible for setting up - * proto_radius_udp, and then calling proto_radius_udp->open. - * - * Even then, proto_radius usually calls fr_master_io_listen() in order - * to create the fr_listen_t structure. - */ - if (listen->app->open && - listen->app->open(listen->proto_module->data, sc, listen->proto_module->conf) < 0) { - cf_log_perr(listen->proto_module->conf, "Opening %s I/O interface failed", - listen->app->common.name); - return -1; - } - - /* - * Socket information is printed out by - * the socket handlers. e.g. proto_radius_udp - */ - DEBUG3("Opened listener for %s", listen->app->common.name); - } - } - - return 0; -} - /** Return virtual server matching the specified name * * @note May be called in bootstrap or instantiate as all servers should be present. @@ -1088,146 +787,21 @@ CONF_SECTION *virtual_server_by_child(CONF_SECTION *section) return cf_section_find_in_parent(section, "server", CF_IDENT_ANY); } -/** Wrapper for the config parser to allow pass1 resolution of virtual servers - * - */ -int virtual_server_cf_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, - CONF_ITEM *ci, UNUSED CONF_PARSER const *rule) -{ - CONF_SECTION *server_cs; - - server_cs = virtual_server_find(cf_pair_value(cf_item_to_pair(ci))); - if (!server_cs) { - cf_log_err(ci, "virtual-server \"%s\" not found", cf_pair_value(cf_item_to_pair(ci))); - return -1; - } - - *((CONF_SECTION **)out) = server_cs; - - return 0; -} - - -/** Return the namespace for a given virtual server - * - * @param[in] virtual_server to look for namespace in. - * @return - * - NULL on error. - * - Namespace on success. - */ -fr_dict_t const *virtual_server_namespace(char const *virtual_server) -{ - CONF_SECTION const *server_cs; - CONF_DATA const *cd; - virtual_server_dict_t *dict; - - server_cs = virtual_server_find(virtual_server); - if (!server_cs) return NULL; - - cd = cf_data_find(server_cs, virtual_server_dict_t, "dictionary"); - if (!cd) return NULL; - - dict = (virtual_server_dict_t *) cf_data_value(cd); - - return dict->dict; -} - -/** Return the namespace for a given virtual server specified by a CONF_ITEM within the virtual server - * - * @param[in] ci to look for namespace in. - * @return - * - NULL on error. - * - Namespace on success. - */ -fr_dict_t const *virtual_server_namespace_by_ci(CONF_ITEM *ci) -{ - CONF_DATA const *cd; - virtual_server_dict_t *dict; - - cd = cf_data_find_in_parent(ci, virtual_server_dict_t, "dictionary"); - if (!cd) return NULL; - - dict = (virtual_server_dict_t *) cf_data_value(cd); - - return dict->dict; -} - -/** Verify that a given virtual_server exists and is of a particular namespace - * - * Mostly used by modules to check virtual servers specified by their configs. - * - * @param[out] out we found. May be NULL if just checking for existence. - * @param[in] virtual_server to check. - * @param[in] namespace the virtual server must belong to. - * @param[in] ci to log errors against. May be NULL if caller - * doesn't want errors logged. - * @return - * - 0 on success. - * - -1 if no virtual server could be found. - * - -2 if virtual server is not of the correct namespace. - */ -int virtual_server_has_namespace(CONF_SECTION **out, - char const *virtual_server, fr_dict_t const *namespace, CONF_ITEM *ci) -{ - CONF_SECTION *server_cs; - fr_dict_t const *dict; - - if (out) *out = NULL; - - server_cs = virtual_server_find(virtual_server); - if (!server_cs) { - if (ci) cf_log_err(ci, "Can't find virtual server \"%s\"", virtual_server); - return -1; - } - dict = virtual_server_namespace(virtual_server); - if (!dict) { - /* - * Not sure this is even a valid state? - */ - if (ci) cf_log_err(ci, "No namespace found in virtual server \"%s\"", virtual_server); - return -2; - } - - if (dict != namespace) { - if (ci) { - cf_log_err(ci, - "Expected virtual server \"%s\" to be of namespace \"%s\", got namespace \"%s\"", - virtual_server, fr_dict_root(namespace)->name, fr_dict_root(dict)->name); - } - return -2; - } - - if (out) *out = server_cs; - - return 0; -} - -int virtual_servers_init(CONF_SECTION *config) -{ - virtual_server_root = config; - - if (fr_dict_autoload(virtual_server_dict_autoload) < 0) { - PERROR("%s", __FUNCTION__); - return -1; - } - if (fr_dict_attr_autoload(virtual_server_dict_attr_autoload) < 0) { - PERROR("%s", __FUNCTION__); - fr_dict_autofree(virtual_server_dict_autoload); - return -1; - } - - MEM(listen_addr_root = fr_rb_inline_alloc(NULL, fr_listen_t, virtual_server_node, listen_addr_cmp, NULL)); - MEM(server_section_name_tree = fr_rb_alloc(NULL, server_section_name_cmp, NULL)); - - return 0; -} - -int virtual_servers_free(void) +/** Wrapper for the config parser to allow pass1 resolution of virtual servers + * + */ +int virtual_server_cf_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent, + CONF_ITEM *ci, UNUSED CONF_PARSER const *rule) { - TALLOC_FREE(listen_addr_root); - TALLOC_FREE(server_section_name_tree); + CONF_SECTION *server_cs; - fr_dict_autofree(virtual_server_dict_autoload); + server_cs = virtual_server_find(cf_pair_value(cf_item_to_pair(ci))); + if (!server_cs) { + cf_log_err(ci, "virtual-server \"%s\" not found", cf_pair_value(cf_item_to_pair(ci))); + return -1; + } + + *((CONF_SECTION **)out) = server_cs; return 0; } @@ -1279,7 +853,6 @@ unlang_action_t process_authenticate(rlm_rcode_t *p_result, int auth_type, reque request->module = NULL; request->component = "authenticate"; - if (unlang_interpret_push_section(request, subcs, RLM_MODULE_REJECT, UNLANG_TOP_FRAME) < 0) { RETURN_MODULE_FAIL; } @@ -1555,3 +1128,318 @@ virtual_server_method_t const *virtual_server_section_methods(char const *name1, return entry->methods; } + +/** Define a values for Auth-Type attributes by the sections present in a virtual-server + * + * The ident2 value of any sections found will be converted into values of the specified da. + * + * @param[in] server_cs The virtual server containing the sections. + * @param[in] subcs_name of the subsection to search for. + * @param[in] da to add enumeration values for. + * @return + * - 0 all values added successfully. + * - -1 an error occurred. + */ +int virtual_server_section_attribute_define(CONF_SECTION *server_cs, char const *subcs_name, fr_dict_attr_t const *da) +{ + int rcode = 0; + CONF_SECTION *subcs = NULL; + + fr_assert(strcmp(cf_section_name1(server_cs), "server") == 0); + + while ((subcs = cf_section_find_next(server_cs, subcs, subcs_name, CF_IDENT_ANY))) { + char const *name2; + fr_dict_enum_value_t *dv; + + name2 = cf_section_name2(subcs); + if (!name2) { + cf_log_err(subcs, "Invalid '%s { ... }' section, it must have a name", subcs_name); + return -1; + } + + /* + * If the value already exists, don't + * create it again. + */ + dv = fr_dict_enum_by_name(da, name2, -1); + if (dv) continue; + + cf_log_debug(subcs, "Creating %s = %s", da->name, name2); + + /* + * Create a new unique value with a meaningless + * number. You can't look at it from outside of + * this code, so it doesn't matter. The only + * requirement is that it's unique. + */ + if (fr_dict_enum_add_name_next(fr_dict_attr_unconst(da), name2) < 0) { + PERROR("Failed adding section value"); + return -1; + } + + rcode = 1; + } + + return rcode; +} + +/** Open all the listen sockets + * + * @param[in] sc Scheduler to add I/O paths to. + * @return + * - 0 on success. + * - -1 on failure. + */ +int virtual_servers_open(fr_schedule_t *sc) +{ + size_t i, server_cnt = virtual_servers ? talloc_array_length(virtual_servers) : 0; + + fr_assert(virtual_servers); + + DEBUG2("#### Opening listener interfaces ####"); + fr_strerror_clear(); + + for (i = 0; i < server_cnt; i++) { + fr_virtual_listen_t **listeners; + size_t j, listener_cnt; + + listeners = virtual_servers[i]->listeners; + listener_cnt = talloc_array_length(listeners); + + for (j = 0; j < listener_cnt; j++) { + fr_virtual_listen_t *listener = listeners[j]; + + fr_assert(listener != NULL); + fr_assert(listener->proto_mi != NULL); + fr_assert(listener->proto_module != NULL); + + /* + * The socket is opened with app_instance, + * but all subsequent calls (network.c, etc.) use app_io_instance. + * + * The reason is that we call (for example) proto_radius to + * open the socket, and proto_radius is responsible for setting up + * proto_radius_udp, and then calling proto_radius_udp->open. + * + * Even then, proto_radius usually calls fr_master_io_listen() in order + * to create the fr_listen_t structure. + */ + if (listener->proto_module->open && + listener->proto_module->open(listener->proto_mi->dl_inst->data, sc, + listener->proto_mi->dl_inst->conf) < 0) { + cf_log_err(listener->proto_mi->dl_inst->conf, + "Opening %s I/O interface failed", + listener->proto_module->common.name); + return -1; + } + + /* + * Socket information is printed out by + * the socket handlers. e.g. proto_radius_udp + */ + DEBUG3("Opened listener for %s", listener->proto_module->common.name); + } + } + + return 0; +} + +/** Free thread-specific data for all process modules and listeners + * + */ +void virtual_servers_thread_detach(void) +{ + modules_thread_detach(proto_modules); + modules_thread_detach(process_modules); +} + +/** Perform thread instantiation for all process modules and listeners + * + */ +int virtual_servers_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el) +{ + if (modules_thread_instantiate(ctx, process_modules, el) < 0) return -1; + if (modules_thread_instantiate(ctx, proto_modules, el) < 0) { + modules_thread_detach(process_modules); + return -1; + } + return 0; +} + +/** Instantiate all the virtual servers + * + * @return + * - 0 on success. + * - -1 on failure. + */ +int virtual_servers_instantiate(void) +{ + size_t i, server_cnt = virtual_servers ? talloc_array_length(virtual_servers) : 0; + + fr_assert(virtual_servers); + + DEBUG2("#### Instantiating listeners ####"); + + if (fr_command_register_hook(NULL, NULL, virtual_server_root, cmd_table) < 0) { + PERROR("Failed registering radmin commands for virtual servers"); + return -1; + } + + for (i = 0; i < server_cnt; i++) { + fr_virtual_listen_t **listeners; + size_t j, listener_cnt; + CONF_ITEM *ci = NULL; + CONF_SECTION *server_cs = virtual_servers[i]->server_cs; + fr_virtual_server_t const *vs = virtual_servers[i]; + fr_process_module_t const *process = (fr_process_module_t const *) + vs->process_mi->dl_inst->module->common; + listeners = virtual_servers[i]->listeners; + listener_cnt = talloc_array_length(listeners); + + DEBUG("Compiling policies in server %s { ... }", cf_section_name2(server_cs)); + + for (j = 0; j < listener_cnt; j++) { + fr_virtual_listen_t *listener = listeners[j]; + + fr_assert(listener != NULL); + fr_assert(listener->proto_mi != NULL); + fr_assert(listener->proto_module != NULL); + + if (module_instantiate(listener->proto_mi) < 0) { + cf_log_perr(listener->proto_mi->dl_inst->conf, + "Failed instantiating listener"); + return -1; + } + } + + fr_assert(virtual_servers[i]->process_mi); + + /* + * Complete final instantiation of the process module + */ + if (module_instantiate(virtual_servers[i]->process_mi) < 0) { + cf_log_perr(virtual_servers[i]->process_mi->dl_inst->conf, + "Failed instantiating process module"); + return -1; + } + + /* + * Compile the processing sections indicated by + * the process module. + */ + if (process->compile_list) { + tmpl_rules_t parse_rules; + + memset(&parse_rules, 0, sizeof(parse_rules)); + parse_rules.attr.dict_def = *(process->dict); + fr_assert(parse_rules.attr.dict_def != NULL); + + if (virtual_server_compile_sections(server_cs, process->compile_list, &parse_rules, + vs->process_mi->dl_inst->data) < 0) { + return -1; + } + } + + /* + * Print out warnings for unused "recv" and + * "send" sections. + * + * @todo - check against the "compile_list" + * registered for this virtual server, instead of hard-coding stuff. + */ + while ((ci = cf_item_next(server_cs, ci))) { + char const *name; + CONF_SECTION *subcs; + + if (!cf_item_is_section(ci)) continue; + + subcs = cf_item_to_section(ci); + name = cf_section_name1(subcs); + + /* + * Skip known "other" sections + */ + if ((strcmp(name, "listen") == 0) || (strcmp(name, "client") == 0)) continue; + + /* + * For every other section, warn if it hasn't + * been compiled. + */ + if (!cf_data_find(subcs, unlang_group_t, NULL)) { + char const *name2; + + name2 = cf_section_name2(subcs); + if (!name2) name2 = ""; + + cf_log_warn(subcs, "%s %s { ... } section is unused", name, name2); + } + } + } + + return 0; +} + +/** Load protocol modules and call their bootstrap methods + * + * @param[in] config section containing the virtual servers to bootstrap. + * @return + * - 0 on success. + * - -1 on failure. + */ +int virtual_servers_bootstrap(CONF_SECTION *config) +{ + virtual_server_root = config; + + if (modules_bootstrap(process_modules) < 0) return -1; + if (modules_bootstrap(proto_modules) < 0) return -1; + + return 0; +} + +void virtual_servers_free(void) +{ + TALLOC_FREE(listen_addr_root); + TALLOC_FREE(server_section_name_tree); + TALLOC_FREE(process_modules); + TALLOC_FREE(proto_modules); + fr_dict_autofree(virtual_server_dict_autoload); +} + +static void _virtual_servers_atexit(UNUSED void *uctx) +{ + virtual_servers_free(); +} + +/** Performs global initialisation for the virtual server code + * + * This has to be done separately and explicitly, because the above code makes + * use of "onread" callbacks. + * + * Will automatically free module lists on exit, but all modules should have + * been removed from this list by the point that happens. + */ +int virtual_servers_init(void) +{ + if (fr_dict_autoload(virtual_server_dict_autoload) < 0) { + PERROR("%s", __FUNCTION__); + return -1; + } + if (fr_dict_attr_autoload(virtual_server_dict_attr_autoload) < 0) { + PERROR("%s", __FUNCTION__); + fr_dict_autofree(virtual_server_dict_autoload); + return -1; + } + + MEM(process_modules = module_list_alloc(NULL, "process")); + MEM(proto_modules = module_list_alloc(NULL, "protocol")); + MEM(listen_addr_root = fr_rb_inline_alloc(NULL, fr_listen_t, virtual_server_node, listen_addr_cmp, NULL)); + MEM(server_section_name_tree = fr_rb_alloc(NULL, server_section_name_cmp, NULL)); + + /* + * Create a list to hold all the proto_* modules + * that get loaded during startup. + */ + fr_atexit_global(_virtual_servers_atexit, NULL); + + return 0; +} diff --git a/src/lib/server/virtual_servers.h b/src/lib/server/virtual_servers.h index 7e712d79f72..27c12ad377a 100644 --- a/src/lib/server/virtual_servers.h +++ b/src/lib/server/virtual_servers.h @@ -36,32 +36,19 @@ extern "C" { extern const CONF_PARSER virtual_servers_config[]; extern const CONF_PARSER virtual_servers_on_read_config[]; -/** @name Parsing, bootstrap and instantiation +/** @name Namespace management * * @{ */ -void virtual_server_dict_set(CONF_SECTION *server_cs, fr_dict_t const *dict, bool do_free) CC_HINT(nonnull); - -fr_dict_t const *virtual_server_dict(CONF_SECTION *server_cs) CC_HINT(nonnull); - -int virtual_server_section_attribute_define(CONF_SECTION *server_cs, char const *subcs_name, - fr_dict_attr_t const *da) CC_HINT(nonnull); +fr_dict_t const *virtual_server_dict_by_name(char const *virtual_server) CC_HINT(nonnull); -int virtual_servers_instantiate(void); +fr_dict_t const *virtual_server_dict_by_cs(CONF_SECTION const *server_cs) CC_HINT(nonnull); -int virtual_servers_bootstrap(CONF_SECTION *config) CC_HINT(nonnull); - -int virtual_servers_init(CONF_SECTION *config) CC_HINT(nonnull); - -int virtual_servers_free(void); - -/** @} */ +fr_dict_t const *virtual_server_dict_by_child_ci(CONF_ITEM const *ci) CC_HINT(nonnull); -/** @name Runtime management - * - * @{ - */ -int virtual_servers_open(fr_schedule_t *sc); +int virtual_server_has_namespace(CONF_SECTION **out, + char const *virtual_server, fr_dict_t const *namespace, + CONF_ITEM *ci) CC_HINT(nonnull(2,3)); /** @} */ /** @name Lookup and namespace management @@ -74,14 +61,6 @@ CONF_SECTION *virtual_server_by_child(CONF_SECTION *section) CC_HINT(nonnull); int virtual_server_cf_parse(TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *ci, CONF_PARSER const *rule) CC_HINT(nonnull(2,4)); - -fr_dict_t const *virtual_server_namespace(char const *virtual_server) CC_HINT(nonnull); - -fr_dict_t const *virtual_server_namespace_by_ci(CONF_ITEM *ci) CC_HINT(nonnull); - -int virtual_server_has_namespace(CONF_SECTION **out, - char const *virtual_server, fr_dict_t const *namespace, - CONF_ITEM *ci) CC_HINT(nonnull(2,3)); /** @} */ unlang_action_t process_authenticate(rlm_rcode_t *p_result, int auth_type, request_t *request, CONF_SECTION *server_cs) CC_HINT(nonnull); @@ -128,7 +107,27 @@ virtual_server_method_t const *virtual_server_section_methods(char const *name1, unlang_action_t virtual_server_push(request_t *request, CONF_SECTION *server_cs, bool top_frame) CC_HINT(nonnull); -int virtual_server_dynamic_clients_allow(CONF_SECTION *server_cs) CC_HINT(nonnull); +/** @name Parsing, bootstrap and instantiation + * + * @{ + */ +int virtual_server_section_attribute_define(CONF_SECTION *server_cs, char const *subcs_name, + fr_dict_attr_t const *da) CC_HINT(nonnull); + +int virtual_servers_open(fr_schedule_t *sc); + +void virtual_servers_thread_detach(void); + +int virtual_servers_thread_instantiate(TALLOC_CTX *ctx, fr_event_list_t *el) CC_HINT(nonnull); + +int virtual_servers_instantiate(void) CC_HINT(nonnull); + +int virtual_servers_bootstrap(CONF_SECTION *config) CC_HINT(nonnull); + +void virtual_servers_free(void); + +int virtual_servers_init(void) CC_HINT(nonnull); +/** @} */ #ifdef __cplusplus } diff --git a/src/lib/unlang/call.c b/src/lib/unlang/call.c index bf6586e2fe2..6bd86da28d6 100644 --- a/src/lib/unlang/call.c +++ b/src/lib/unlang/call.c @@ -164,7 +164,7 @@ unlang_action_t unlang_call_push(request_t *request, CONF_SECTION *server_cs, bo /* * Temporary hack until packet->code is removed */ - dict = virtual_server_dict(server_cs); + dict = virtual_server_dict_by_cs(server_cs); if (!dict) { REDEBUG("Virtual server \"%s\" not compiled", cf_section_name2(server_cs)); return UNLANG_ACTION_FAIL; diff --git a/src/lib/unlang/compile.c b/src/lib/unlang/compile.c index 5e129c7a3e6..24d849022d0 100644 --- a/src/lib/unlang/compile.c +++ b/src/lib/unlang/compile.c @@ -3678,7 +3678,7 @@ static unlang_t *compile_call(unlang_t *parent, unlang_compile_t *unlang_ctx, CO /* * The dictionaries are not compatible, forbid it. */ - dict = virtual_server_namespace(server); + dict = virtual_server_dict_by_name(server); if (!dict) { cf_log_err(cs, "Cannot call virtual server '%s', failed retrieving its namespace", server); diff --git a/src/lib/unlang/module.c b/src/lib/unlang/module.c index c8f431bca16..06a3d75a070 100644 --- a/src/lib/unlang/module.c +++ b/src/lib/unlang/module.c @@ -590,17 +590,17 @@ unlang_action_t unlang_module_yield(request_t *request, /* * Lock the mutex for the module */ -static inline CC_HINT(always_inline) void safe_lock(module_instance_t *instance) +static inline CC_HINT(always_inline) void safe_lock(module_instance_t *mi) { - if (instance->mutex) pthread_mutex_lock(instance->mutex); + if ((mi->module->type & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_lock(&mi->mutex); } /* * Unlock the mutex for the module */ -static inline CC_HINT(always_inline) void safe_unlock(module_instance_t *instance) +static inline CC_HINT(always_inline) void safe_unlock(module_instance_t *mi) { - if (instance->mutex) pthread_mutex_unlock(instance->mutex); + if ((mi->module->type & MODULE_TYPE_THREAD_UNSAFE) != 0) pthread_mutex_unlock(&mi->mutex); } /** Send a signal (usually stop) to a request diff --git a/src/lib/unlang/xlat_inst.c b/src/lib/unlang/xlat_inst.c index 8c16142c55e..2115ec8e61d 100644 --- a/src/lib/unlang/xlat_inst.c +++ b/src/lib/unlang/xlat_inst.c @@ -158,7 +158,7 @@ static xlat_thread_inst_t *xlat_thread_inst_alloc(TALLOC_CTX *ctx, fr_event_list module_ctx_t *mctx; mctx = module_ctx_from_inst(xt, call->func->mctx); - mctx->thread = module_thread_by_data(mctx->inst->data)->data; + mctx->thread = module_rlm_thread_by_data(mctx->inst->data)->data; xt->mctx = mctx; } diff --git a/src/lib/util/dict.h b/src/lib/util/dict.h index 47dd352677e..8e2020c475f 100644 --- a/src/lib/util/dict.h +++ b/src/lib/util/dict.h @@ -629,7 +629,7 @@ int fr_dict_const_free(fr_dict_t const **dict, char const *dependent) CC_HINT( * * @{ */ -fr_dict_gctx_t const *fr_dict_global_ctx_init(TALLOC_CTX *ctx, char const *dict_dir); +fr_dict_gctx_t const *fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir); void fr_dict_global_ctx_set(fr_dict_gctx_t const *gctx); @@ -639,7 +639,7 @@ int fr_dict_global_ctx_dir_set(char const *dict_dir); void fr_dict_global_ctx_read_only(void); -void fr_dict_global_ctx_debug(void); +void fr_dict_global_ctx_debug(fr_dict_gctx_t const *gctx); char const *fr_dict_global_ctx_dir(void); diff --git a/src/lib/util/dict_priv.h b/src/lib/util/dict_priv.h index 68a25fa9667..585e68759f3 100644 --- a/src/lib/util/dict_priv.h +++ b/src/lib/util/dict_priv.h @@ -111,7 +111,10 @@ struct fr_dict { }; struct fr_dict_gctx_s { + bool free_at_exit; //!< This gctx will be freed on exit. + bool read_only; + char *dict_dir_default; //!< The default location for loading dictionaries if one ///< wasn't provided. diff --git a/src/lib/util/dict_test.c b/src/lib/util/dict_test.c index 54918f165a7..9a9c04903be 100644 --- a/src/lib/util/dict_test.c +++ b/src/lib/util/dict_test.c @@ -234,7 +234,7 @@ int fr_dict_test_init(TALLOC_CTX *ctx, fr_dict_t **dict_p, fr_dict_test_attr_t c fr_dict_gctx_t const *our_dict_gctx; fr_dict_t *dict; - our_dict_gctx = fr_dict_global_ctx_init(ctx, "share/dictionary"); + our_dict_gctx = fr_dict_global_ctx_init(ctx, false, "share/dictionary"); if (!our_dict_gctx) return -1; if (!test_defs) test_defs = fr_dict_test_attrs; diff --git a/src/lib/util/dict_util.c b/src/lib/util/dict_util.c index 93b9a271e7f..4e3b1501bd7 100644 --- a/src/lib/util/dict_util.c +++ b/src/lib/util/dict_util.c @@ -27,6 +27,7 @@ RCSID("$Id$") #include #include #include +#include #ifdef HAVE_SYS_STAT_H # include @@ -3617,12 +3618,23 @@ static int _dict_validation_onload(dl_t const *dl, void *symbol, UNUSED void *us return 0; } +static void _dict_global_free_at_exit(void *uctx) +{ + talloc_free(uctx); +} + static int _dict_global_free(fr_dict_gctx_t *gctx) { fr_hash_iter_t iter; fr_dict_t *dict; bool still_loaded = false; + /* + * Make sure this doesn't fire later and mess + * things up... + */ + if (gctx->free_at_exit) fr_atexit_global_disarm(true, _dict_global_free_at_exit, gctx); + if (gctx->internal) { dict_dependent_remove(gctx->internal, "global"); /* remove our dependency */ @@ -3638,8 +3650,12 @@ static int _dict_global_free(fr_dict_gctx_t *gctx) if (talloc_free(dict) < 0) still_loaded = true; } - if (still_loaded) return -1; - + if (still_loaded) { +#ifndef NDEBUG + fr_dict_global_ctx_debug(gctx); +#endif + return -1; + } /* * Set this to NULL just in case the caller tries to use * dict_global_init() again. @@ -3653,13 +3669,16 @@ static int _dict_global_free(fr_dict_gctx_t *gctx) * * @note Must be called before any other dictionary functions. * - * @param[in] ctx to allocate global resources in. - * @param[in] dict_dir the default location for the dictionaries. + * @param[in] ctx to allocate global resources in. + * @param[in] free_at_exit Install an at_exit handler to free the global ctx. + * This is useful when dictionaries are held by other + * libraries which free them using atexit handlers. + * @param[in] dict_dir the default location for the dictionaries. * @return * - A pointer to the new global context on success. * - NULL on failure. */ -fr_dict_gctx_t const *fr_dict_global_ctx_init(TALLOC_CTX *ctx, char const *dict_dir) +fr_dict_gctx_t const *fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir) { fr_dict_gctx_t *new_ctx; @@ -3696,11 +3715,14 @@ fr_dict_gctx_t const *fr_dict_global_ctx_init(TALLOC_CTX *ctx, char const *dict_ if (dl_symbol_init_cb_register(new_ctx->dict_loader, 0, "dict_protocol", _dict_validation_onload, NULL) < 0) goto error; + new_ctx->free_at_exit = free_at_exit; talloc_set_destructor(new_ctx, _dict_global_free); if (!dict_gctx) dict_gctx = new_ctx; /* Set as the default */ + if (free_at_exit) fr_atexit_global(_dict_global_free_at_exit, new_ctx); + return new_ctx; } @@ -3783,22 +3805,24 @@ void fr_dict_global_ctx_read_only(void) * * Intended to be called from a debugger */ -void fr_dict_global_ctx_debug(void) +void fr_dict_global_ctx_debug(fr_dict_gctx_t const *gctx) { fr_hash_iter_t dict_iter; fr_dict_t *dict; - fr_rb_iter_inorder_t dep_iter; + fr_rb_iter_inorder_t dep_iter; fr_dict_dependent_t *dep; - if (!dict_gctx) { + if (gctx == NULL) gctx = dict_gctx; + + if (!gctx) { FR_FAULT_LOG("gctx not initialised"); return; } FR_FAULT_LOG("gctx %p report", dict_gctx); - for (dict = fr_hash_table_iter_init(dict_gctx->protocol_by_num, &dict_iter); + for (dict = fr_hash_table_iter_init(gctx->protocol_by_num, &dict_iter); dict; - dict = fr_hash_table_iter_next(dict_gctx->protocol_by_num, &dict_iter)) { + dict = fr_hash_table_iter_next(gctx->protocol_by_num, &dict_iter)) { for (dep = fr_rb_iter_init_inorder(&dep_iter, dict->dependents); dep; dep = fr_rb_iter_next_inorder(&dep_iter)) { @@ -3806,11 +3830,11 @@ void fr_dict_global_ctx_debug(void) } } - if (dict_gctx->internal) { - for (dep = fr_rb_iter_init_inorder(&dep_iter, dict_gctx->internal->dependents); + if (gctx->internal) { + for (dep = fr_rb_iter_init_inorder(&dep_iter, gctx->internal->dependents); dep; dep = fr_rb_iter_next_inorder(&dep_iter)) { - FR_FAULT_LOG("\t%s refs %s (%u)", dict_gctx->internal->root->name, dep->dependent, dep->count); + FR_FAULT_LOG("\t%s refs %s (%u)", gctx->internal->root->name, dep->dependent, dep->count); } } } diff --git a/src/lib/util/log.c b/src/lib/util/log.c index 5580a2e7dd9..fba985a2129 100644 --- a/src/lib/util/log.c +++ b/src/lib/util/log.c @@ -317,6 +317,8 @@ TALLOC_CTX *fr_log_pool_init(void) pool = fr_log_pool; if (unlikely(!pool)) { + if (fr_atexit_is_exiting()) return NULL; /* No new pools if we're exiting */ + pool = talloc_pool(NULL, 16384); if (!pool) { fr_perror("Failed allocating memory for vlog_request_pool"); diff --git a/src/listen/arp/proto_arp.c b/src/listen/arp/proto_arp.c index 03327e7a7d3..24d246fe659 100644 --- a/src/listen/arp/proto_arp.c +++ b/src/listen/arp/proto_arp.c @@ -259,13 +259,14 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx) parent_inst = cf_data_value(cf_data_find(inst->cs, dl_module_inst_t, "proto_arp")); fr_assert(parent_inst); - if (dl_module_instance(inst->cs, &inst->io_submodule, inst->cs, - parent_inst, "ethernet", DL_MODULE_TYPE_SUBMODULE) < 0) { + if (dl_module_instance(inst->cs, &inst->io_submodule, + parent_inst, + DL_MODULE_TYPE_SUBMODULE, "ethernet", dl_module_inst_name_from_conf(inst->cs)) < 0) { cf_log_perr(inst->cs, "Failed to load proto_arp_ethernet"); return -1; } - if (dl_module_conf_parse(inst->io_submodule) < 0) { + if (dl_module_conf_parse(inst->io_submodule, inst->cs) < 0) { TALLOC_FREE(inst->io_submodule); return -1; } diff --git a/src/listen/control/proto_control.c b/src/listen/control/proto_control.c index 9021f8e65fd..56caeb5811b 100644 --- a/src/listen/control/proto_control.c +++ b/src/listen/control/proto_control.c @@ -103,8 +103,9 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF inst = talloc_get_type_abort(parent_inst->data, proto_control_t); inst->io.transport = name; - if (dl_module_instance(ctx, &dl_mod_inst, transport_cs, parent_inst, name, DL_MODULE_TYPE_SUBMODULE) < 0) return -1; - if (dl_module_conf_parse(dl_mod_inst) < 0) { + if (dl_module_instance(ctx, &dl_mod_inst, parent_inst, + DL_MODULE_TYPE_SUBMODULE, name, dl_module_inst_name_from_conf(transport_cs)) < 0) return -1; + if (dl_module_conf_parse(dl_mod_inst, transport_cs) < 0) { talloc_free(dl_mod_inst); return -1; } diff --git a/src/listen/control/radmin.c b/src/listen/control/radmin.c index 32da21adb66..aaebe903969 100644 --- a/src/listen/control/radmin.c +++ b/src/listen/control/radmin.c @@ -975,7 +975,7 @@ int main(int argc, char **argv) * Need to read in the dictionaries, else we may get * validation errors when we try and parse the config. */ - dict_gctx = fr_dict_global_ctx_init(autofree, dict_dir); + dict_gctx = fr_dict_global_ctx_init(NULL, true, dict_dir); if (!dict_gctx) { fr_perror("radmin"); fr_exit_now(64); diff --git a/src/listen/cron/proto_cron.c b/src/listen/cron/proto_cron.c index d14a3d4c88b..dfb472fee7d 100644 --- a/src/listen/cron/proto_cron.c +++ b/src/listen/cron/proto_cron.c @@ -110,7 +110,7 @@ static int type_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *((char const **) out) = value; - inst->dict = virtual_server_namespace_by_ci(ci); + inst->dict = virtual_server_dict_by_child_ci(ci); if (!inst->dict) { cf_log_err(ci, "Please define 'namespace' in this virtual server"); return -1; @@ -168,8 +168,9 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, parent_inst = cf_data_value(cf_data_find(listen_cs, dl_module_inst_t, "proto_cron")); fr_assert(parent_inst); - if (dl_module_instance(ctx, &dl_mod_inst, transport_cs, parent_inst, name, DL_MODULE_TYPE_SUBMODULE) < 0) return -1; - if (dl_module_conf_parse(dl_mod_inst) < 0) { + if (dl_module_instance(ctx, &dl_mod_inst, parent_inst, + DL_MODULE_TYPE_SUBMODULE, name, dl_module_inst_name_from_conf(transport_cs)) < 0) return -1; + if (dl_module_conf_parse(dl_mod_inst, transport_cs) < 0) { talloc_free(dl_mod_inst); return -1; } diff --git a/src/listen/detail/proto_detail.c b/src/listen/detail/proto_detail.c index 085e3735478..3ebe8d91094 100644 --- a/src/listen/detail/proto_detail.c +++ b/src/listen/detail/proto_detail.c @@ -121,7 +121,7 @@ static int type_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *((char const **) out) = value; - inst->dict = virtual_server_namespace_by_ci(ci); + inst->dict = virtual_server_dict_by_child_ci(ci); if (!inst->dict) { cf_log_err(ci, "Please define 'namespace' in this virtual server"); return -1; @@ -179,8 +179,9 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, parent_inst = cf_data_value(cf_data_find(listen_cs, dl_module_inst_t, "proto_detail")); fr_assert(parent_inst); - if (dl_module_instance(ctx, &dl_mod_inst, transport_cs, parent_inst, name, DL_MODULE_TYPE_SUBMODULE) < 0) return -1; - if (dl_module_conf_parse(dl_mod_inst) < 0) { + if (dl_module_instance(ctx, &dl_mod_inst, parent_inst, + DL_MODULE_TYPE_SUBMODULE, name, dl_module_inst_name_from_conf(transport_cs)) < 0) return -1; + if (dl_module_conf_parse(dl_mod_inst, transport_cs) < 0) { talloc_free(dl_mod_inst); return -1; } @@ -547,13 +548,14 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx) } } - if (dl_module_instance(inst->cs, &inst->work_submodule, transport_cs, - parent_inst, "work", DL_MODULE_TYPE_SUBMODULE) < 0) { + if (dl_module_instance(inst->cs, &inst->work_submodule, + parent_inst, + DL_MODULE_TYPE_SUBMODULE, "work", dl_module_inst_name_from_conf(transport_cs)) < 0) { cf_log_perr(inst->cs, "Failed to load proto_detail_work"); return -1; } - if (dl_module_conf_parse(inst->work_submodule) < 0) { + if (dl_module_conf_parse(inst->work_submodule, transport_cs) < 0) { TALLOC_FREE(inst->work_submodule); return -1; } diff --git a/src/listen/dhcpv4/proto_dhcpv4.c b/src/listen/dhcpv4/proto_dhcpv4.c index 305b35a9662..8146e64caa8 100644 --- a/src/listen/dhcpv4/proto_dhcpv4.c +++ b/src/listen/dhcpv4/proto_dhcpv4.c @@ -176,8 +176,9 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, inst = talloc_get_type_abort(parent_inst->data, proto_dhcpv4_t); inst->io.transport = name; - if (dl_module_instance(ctx, &dl_mod_inst, transport_cs, parent_inst, name, DL_MODULE_TYPE_SUBMODULE) < 0) return -1; - if (dl_module_conf_parse(dl_mod_inst) < 0) { + if (dl_module_instance(ctx, &dl_mod_inst, parent_inst, + DL_MODULE_TYPE_SUBMODULE, name, dl_module_inst_name_from_conf(transport_cs)) < 0) return -1; + if (dl_module_conf_parse(dl_mod_inst, transport_cs) < 0) { talloc_free(dl_mod_inst); return -1; } diff --git a/src/listen/dhcpv6/proto_dhcpv6.c b/src/listen/dhcpv6/proto_dhcpv6.c index 5f35c47d93d..f301737a63b 100644 --- a/src/listen/dhcpv6/proto_dhcpv6.c +++ b/src/listen/dhcpv6/proto_dhcpv6.c @@ -176,8 +176,9 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, inst = talloc_get_type_abort(parent_inst->data, proto_dhcpv6_t); inst->io.transport = name; - if (dl_module_instance(ctx, &dl_mod_inst, transport_cs, parent_inst, name, DL_MODULE_TYPE_SUBMODULE) < 0) return -1; - if (dl_module_conf_parse(dl_mod_inst) < 0) { + if (dl_module_instance(ctx, &dl_mod_inst, parent_inst, + DL_MODULE_TYPE_SUBMODULE, name, dl_module_inst_name_from_conf(transport_cs)) < 0) return -1; + if (dl_module_conf_parse(dl_mod_inst, transport_cs) < 0) { talloc_free(dl_mod_inst); return -1; } diff --git a/src/listen/dns/proto_dns.c b/src/listen/dns/proto_dns.c index 94f19a6645b..5d3621c780c 100644 --- a/src/listen/dns/proto_dns.c +++ b/src/listen/dns/proto_dns.c @@ -157,8 +157,9 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, inst = talloc_get_type_abort(parent_inst->data, proto_dns_t); inst->io.transport = name; - if (dl_module_instance(ctx, &dl_mod_inst, transport_cs, parent_inst, name, DL_MODULE_TYPE_SUBMODULE) < 0) return -1; - if (dl_module_conf_parse(dl_mod_inst) < 0) { + if (dl_module_instance(ctx, &dl_mod_inst, parent_inst, + DL_MODULE_TYPE_SUBMODULE, name, dl_module_inst_name_from_conf(transport_cs)) < 0) return -1; + if (dl_module_conf_parse(dl_mod_inst, transport_cs) < 0) { talloc_free(dl_mod_inst); return -1; } diff --git a/src/listen/load/proto_load.c b/src/listen/load/proto_load.c index 481e77f8209..ca12d6de824 100644 --- a/src/listen/load/proto_load.c +++ b/src/listen/load/proto_load.c @@ -110,7 +110,7 @@ static int type_parse(UNUSED TALLOC_CTX *ctx, void *out, void *parent, CONF_ITEM *((char const **) out) = value; - inst->dict = virtual_server_namespace_by_ci(ci); + inst->dict = virtual_server_dict_by_child_ci(ci); if (!inst->dict) { cf_log_err(ci, "Please define 'namespace' in this virtual server"); return -1; @@ -168,8 +168,9 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, parent_inst = cf_data_value(cf_data_find(listen_cs, dl_module_inst_t, "proto_load")); fr_assert(parent_inst); - if (dl_module_instance(ctx, &dl_mod_inst, transport_cs, parent_inst, name, DL_MODULE_TYPE_SUBMODULE) < 0) return -1; - if (dl_module_conf_parse(dl_mod_inst) < 0) { + if (dl_module_instance(ctx, &dl_mod_inst, parent_inst, + DL_MODULE_TYPE_SUBMODULE, name, dl_module_inst_name_from_conf(transport_cs)) < 0) return -1; + if (dl_module_conf_parse(dl_mod_inst, transport_cs) < 0) { talloc_free(dl_mod_inst); return -1; } diff --git a/src/listen/radius/proto_radius.c b/src/listen/radius/proto_radius.c index c1e36a7a281..7c2e4576f86 100644 --- a/src/listen/radius/proto_radius.c +++ b/src/listen/radius/proto_radius.c @@ -183,8 +183,9 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF inst->io.app_io_conf = transport_cs; } - if (dl_module_instance(ctx, &dl_mod_inst, transport_cs, parent_inst, name, DL_MODULE_TYPE_SUBMODULE) < 0) return -1; - if (dl_module_conf_parse(dl_mod_inst) < 0) { + if (dl_module_instance(ctx, &dl_mod_inst, parent_inst, + DL_MODULE_TYPE_SUBMODULE, name, dl_module_inst_name_from_conf(transport_cs)) < 0) return -1; + if (dl_module_conf_parse(dl_mod_inst, transport_cs) < 0) { talloc_free(dl_mod_inst); return -1; } diff --git a/src/listen/tacacs/proto_tacacs.c b/src/listen/tacacs/proto_tacacs.c index 2cf64ea6173..af1569d22bf 100644 --- a/src/listen/tacacs/proto_tacacs.c +++ b/src/listen/tacacs/proto_tacacs.c @@ -156,8 +156,9 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, CONF inst->io.app_io_conf = transport_cs; } - if (dl_module_instance(ctx, &dl_mod_inst, transport_cs, parent_inst, name, DL_MODULE_TYPE_SUBMODULE) < 0) return -1; - if (dl_module_conf_parse(dl_mod_inst) < 0) { + if (dl_module_instance(ctx, &dl_mod_inst, parent_inst, + DL_MODULE_TYPE_SUBMODULE, name, dl_module_inst_name_from_conf(transport_cs)) < 0) return -1; + if (dl_module_conf_parse(dl_mod_inst, transport_cs) < 0) { talloc_free(dl_mod_inst); return -1; } diff --git a/src/listen/vmps/proto_vmps.c b/src/listen/vmps/proto_vmps.c index 5f88ecf4524..1d9ce7ffbd4 100644 --- a/src/listen/vmps/proto_vmps.c +++ b/src/listen/vmps/proto_vmps.c @@ -165,8 +165,9 @@ static int transport_parse(TALLOC_CTX *ctx, void *out, UNUSED void *parent, inst = talloc_get_type_abort(parent_inst->data, proto_vmps_t); inst->io.transport = name; - if (dl_module_instance(ctx, &dl_mod_inst, transport_cs, parent_inst, name, DL_MODULE_TYPE_SUBMODULE) < 0) return -1; - if (dl_module_conf_parse(dl_mod_inst) < 0) { + if (dl_module_instance(ctx, &dl_mod_inst, parent_inst, + DL_MODULE_TYPE_SUBMODULE, name, dl_module_inst_name_from_conf(transport_cs)) < 0) return -1; + if (dl_module_conf_parse(dl_mod_inst, transport_cs) < 0) { talloc_free(dl_mod_inst); return -1; } diff --git a/src/modules/proto_ldap_sync/sync_touch.c b/src/modules/proto_ldap_sync/sync_touch.c index 70dfe2d255b..c3215168ca6 100644 --- a/src/modules/proto_ldap_sync/sync_touch.c +++ b/src/modules/proto_ldap_sync/sync_touch.c @@ -133,7 +133,7 @@ int main(int argc, char **argv) fr_exit_now(EXIT_FAILURE); } - if (!fr_dict_global_ctx_init(autofree, dict_dir)) { + if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) { fr_perror("sync_touch"); fr_exit_now(EXIT_FAILURE); } diff --git a/src/modules/rlm_always/rlm_always.c b/src/modules/rlm_always/rlm_always.c index 7964948fc11..da193967094 100644 --- a/src/modules/rlm_always/rlm_always.c +++ b/src/modules/rlm_always/rlm_always.c @@ -119,7 +119,7 @@ static int mod_bootstrap(module_inst_ctx_t const *mctx) rlm_always_t *inst = talloc_get_type_abort(mctx->inst->data, rlm_always_t); xlat_t *xlat; - inst->mi = module_by_name(NULL, mctx->inst->name); + inst->mi = module_rlm_by_name(NULL, mctx->inst->name); if (!inst->mi) { cf_log_err(mctx->inst->conf, "Can't find the module instance data for this module: %s", mctx->inst->name); return -1; diff --git a/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c b/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c index 787646016f7..7145c2458f0 100644 --- a/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c +++ b/src/modules/rlm_cache/drivers/rlm_cache_memcached/rlm_cache_memcached.c @@ -318,7 +318,7 @@ extern rlm_cache_driver_t rlm_cache_memcached; rlm_cache_driver_t rlm_cache_memcached = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "rlm_cache_memcached", + .name = "cache_memcached", .inst_size = sizeof(rlm_cache_memcached_t), .config = driver_config, diff --git a/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c b/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c index e0ed9d69281..a03ece0fa03 100644 --- a/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c +++ b/src/modules/rlm_cache/drivers/rlm_cache_rbtree/rlm_cache_rbtree.c @@ -336,7 +336,7 @@ extern rlm_cache_driver_t rlm_cache_rbtree; rlm_cache_driver_t rlm_cache_rbtree = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "rlm_cache_rbtree", + .name = "cache_rbtree", .instantiate = mod_instantiate, .detach = mod_detach, .inst_size = sizeof(rlm_cache_rbtree_t), diff --git a/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c b/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c index 29dd1cfc67b..d8ee23b7d60 100644 --- a/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c +++ b/src/modules/rlm_cache/drivers/rlm_cache_redis/rlm_cache_redis.c @@ -473,7 +473,7 @@ extern rlm_cache_driver_t rlm_cache_redis; rlm_cache_driver_t rlm_cache_redis = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "rlm_cache_redis", + .name = "cache_redis", .onload = mod_load, .instantiate = mod_instantiate, .inst_size = sizeof(rlm_cache_redis_t), diff --git a/src/modules/rlm_cache/rlm_cache.c b/src/modules/rlm_cache/rlm_cache.c index a995efec888..65383f71370 100644 --- a/src/modules/rlm_cache/rlm_cache.c +++ b/src/modules/rlm_cache/rlm_cache.c @@ -37,7 +37,7 @@ extern module_rlm_t rlm_cache; static const CONF_PARSER module_config[] = { { FR_CONF_OFFSET("driver", FR_TYPE_VOID, rlm_cache_t, driver_submodule), .dflt = "rbtree", - .func = module_submodule_parse }, + .func = module_rlm_submodule_parse }, { FR_CONF_OFFSET("key", FR_TYPE_TMPL | FR_TYPE_REQUIRED, rlm_cache_config_t, key) }, { FR_CONF_OFFSET("ttl", FR_TYPE_TIME_DELTA, rlm_cache_config_t, ttl), .dflt = "500s" }, { FR_CONF_OFFSET("max_entries", FR_TYPE_UINT32, rlm_cache_config_t, max_entries), .dflt = "0" }, diff --git a/src/modules/rlm_eap/rlm_eap.c b/src/modules/rlm_eap/rlm_eap.c index 6aff01df626..febe5529fd5 100644 --- a/src/modules/rlm_eap/rlm_eap.c +++ b/src/modules/rlm_eap/rlm_eap.c @@ -191,7 +191,7 @@ static int submodule_parse(TALLOC_CTX *ctx, void *out, void *parent, break; } #endif - return module_submodule_parse(ctx, out, parent, ci, rule); + return module_rlm_submodule_parse(ctx, out, parent, ci, rule); } /** Convert EAP type strings to eap_type_t values diff --git a/src/modules/rlm_ldap/rlm_ldap.c b/src/modules/rlm_ldap/rlm_ldap.c index 8ec4a2133e8..431b24ad407 100644 --- a/src/modules/rlm_ldap/rlm_ldap.c +++ b/src/modules/rlm_ldap/rlm_ldap.c @@ -733,7 +733,7 @@ static rlm_rcode_t mod_map_proc(void *mod_inst, UNUSED void *proc_inst, request_ { rlm_rcode_t rcode = RLM_MODULE_UPDATED; rlm_ldap_t *inst = talloc_get_type_abort(mod_inst, rlm_ldap_t); - fr_ldap_thread_t *thread = talloc_get_type_abort(module_thread_by_data(inst)->data, fr_ldap_thread_t); + fr_ldap_thread_t *thread = talloc_get_type_abort(module_rlm_thread_by_data(inst)->data, fr_ldap_thread_t); LDAPURLDesc *ldap_url; @@ -902,7 +902,7 @@ free_urldesc: static int rlm_ldap_groupcmp(void *instance, request_t *request, UNUSED fr_pair_list_t *request_list, fr_pair_t const *check) { rlm_ldap_t const *inst = talloc_get_type_abort_const(instance, rlm_ldap_t); - fr_ldap_thread_t *thread = talloc_get_type_abort(module_thread_by_data(inst)->data, fr_ldap_thread_t); + fr_ldap_thread_t *thread = talloc_get_type_abort(module_rlm_thread_by_data(inst)->data, fr_ldap_thread_t); rlm_rcode_t rcode; bool found = false; @@ -1032,7 +1032,7 @@ cleanup: static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) { rlm_ldap_t const *inst = talloc_get_type_abort_const(mctx->inst->data, rlm_ldap_t); - fr_ldap_thread_t *thread = talloc_get_type_abort(module_thread_by_data(inst)->data, fr_ldap_thread_t); + fr_ldap_thread_t *thread = talloc_get_type_abort(module_rlm_thread_by_data(inst)->data, fr_ldap_thread_t); rlm_rcode_t rcode; char const *dn; fr_ldap_thread_trunk_t *ttrunk = NULL; @@ -1214,7 +1214,7 @@ static unlang_action_t rlm_ldap_map_profile(rlm_rcode_t *p_result, rlm_ldap_t co static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request) { rlm_ldap_t const *inst = talloc_get_type_abort_const(mctx->inst->data, rlm_ldap_t); - fr_ldap_thread_t *thread = talloc_get_type_abort(module_thread_by_data(inst)->data, fr_ldap_thread_t); + fr_ldap_thread_t *thread = talloc_get_type_abort(module_rlm_thread_by_data(inst)->data, fr_ldap_thread_t); rlm_rcode_t rcode = RLM_MODULE_OK; int ldap_errno; int i; @@ -1442,7 +1442,7 @@ static unlang_action_t user_modify(rlm_rcode_t *p_result, rlm_ldap_t const *inst request_t *request, ldap_acct_section_t *section) { rlm_rcode_t rcode = RLM_MODULE_OK; - fr_ldap_thread_t *thread = talloc_get_type_abort(module_thread_by_data(inst)->data, fr_ldap_thread_t); + fr_ldap_thread_t *thread = talloc_get_type_abort(module_rlm_thread_by_data(inst)->data, fr_ldap_thread_t); fr_ldap_thread_trunk_t *ttrunk = NULL; fr_ldap_query_t *query = NULL; diff --git a/src/modules/rlm_radius/rlm_radius.c b/src/modules/rlm_radius/rlm_radius.c index 19b32c704e6..98819eddbbc 100644 --- a/src/modules/rlm_radius/rlm_radius.c +++ b/src/modules/rlm_radius/rlm_radius.c @@ -100,7 +100,7 @@ static CONF_PARSER disconnect_config[] = { */ static CONF_PARSER const module_config[] = { { FR_CONF_OFFSET("transport", FR_TYPE_VOID, rlm_radius_t, io_submodule), - .func = module_submodule_parse }, + .func = module_rlm_submodule_parse }, { FR_CONF_OFFSET("type", FR_TYPE_UINT32 | FR_TYPE_MULTI | FR_TYPE_NOT_EMPTY | FR_TYPE_REQUIRED, rlm_radius_t, types), .func = type_parse }, diff --git a/src/modules/rlm_sql/drivers/rlm_sql_cassandra/rlm_sql_cassandra.c b/src/modules/rlm_sql/drivers/rlm_sql_cassandra/rlm_sql_cassandra.c index c689b4724b5..13ede0cf0fe 100644 --- a/src/modules/rlm_sql/drivers/rlm_sql_cassandra/rlm_sql_cassandra.c +++ b/src/modules/rlm_sql/drivers/rlm_sql_cassandra/rlm_sql_cassandra.c @@ -963,7 +963,7 @@ static int mod_load(void) extern rlm_sql_driver_t rlm_sql_cassandra; rlm_sql_driver_t rlm_sql_cassandra = { .common = { - .name = "rlm_sql_cassandra", + .name = "sql_cassandra", .magic = MODULE_MAGIC_INIT, .inst_size = sizeof(rlm_sql_cassandra_t), .onload = mod_load, diff --git a/src/modules/rlm_sql/drivers/rlm_sql_db2/rlm_sql_db2.c b/src/modules/rlm_sql/drivers/rlm_sql_db2/rlm_sql_db2.c index 381da7ea92b..a0860efd660 100644 --- a/src/modules/rlm_sql/drivers/rlm_sql_db2/rlm_sql_db2.c +++ b/src/modules/rlm_sql/drivers/rlm_sql_db2/rlm_sql_db2.c @@ -289,7 +289,7 @@ extern rlm_sql_driver_t rlm_sql_db2; rlm_sql_driver_t rlm_sql_db2 = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "rlm_sql_db2", + .name = "sql_db2", }, .sql_socket_init = sql_socket_init, .sql_query = sql_query, diff --git a/src/modules/rlm_sql/drivers/rlm_sql_firebird/rlm_sql_firebird.c b/src/modules/rlm_sql/drivers/rlm_sql_firebird/rlm_sql_firebird.c index be6ef061024..7032454fdc1 100644 --- a/src/modules/rlm_sql/drivers/rlm_sql_firebird/rlm_sql_firebird.c +++ b/src/modules/rlm_sql/drivers/rlm_sql_firebird/rlm_sql_firebird.c @@ -294,7 +294,7 @@ static int sql_affected_rows(rlm_sql_handle_t *handle, UNUSED rlm_sql_config_t c extern rlm_sql_driver_t rlm_sql_firebird; rlm_sql_driver_t rlm_sql_firebird = { .common = { - .name = "rlm_sql_firebird", + .name = "sql_firebird", .magic = MODULE_MAGIC_INIT }, .sql_socket_init = sql_socket_init, diff --git a/src/modules/rlm_sql/drivers/rlm_sql_freetds/rlm_sql_freetds.c b/src/modules/rlm_sql/drivers/rlm_sql_freetds/rlm_sql_freetds.c index 2440aa30e4e..e62883e0991 100644 --- a/src/modules/rlm_sql/drivers/rlm_sql_freetds/rlm_sql_freetds.c +++ b/src/modules/rlm_sql/drivers/rlm_sql_freetds/rlm_sql_freetds.c @@ -817,7 +817,7 @@ extern rlm_sql_driver_t rlm_sql_freetds; rlm_sql_driver_t rlm_sql_freetds = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "rlm_sql_freetds" + .name = "sql_freetds" }, .sql_socket_init = sql_socket_init, .sql_query = sql_query, diff --git a/src/modules/rlm_sql/drivers/rlm_sql_mysql/rlm_sql_mysql.c b/src/modules/rlm_sql/drivers/rlm_sql_mysql/rlm_sql_mysql.c index fa127408fb5..e3b2766f9d8 100644 --- a/src/modules/rlm_sql/drivers/rlm_sql_mysql/rlm_sql_mysql.c +++ b/src/modules/rlm_sql/drivers/rlm_sql_mysql/rlm_sql_mysql.c @@ -845,7 +845,7 @@ static size_t sql_escape_func(UNUSED request_t *request, char *out, size_t outle extern rlm_sql_driver_t rlm_sql_mysql; rlm_sql_driver_t rlm_sql_mysql = { .common = { - .name = "rlm_sql_mysql", + .name = "sql_mysql", .magic = MODULE_MAGIC_INIT, .inst_size = sizeof(rlm_sql_mysql_t), .onload = mod_load, diff --git a/src/modules/rlm_sql/drivers/rlm_sql_null/rlm_sql_null.c b/src/modules/rlm_sql/drivers/rlm_sql_null/rlm_sql_null.c index 7e15b0854da..b4f4e43a049 100644 --- a/src/modules/rlm_sql/drivers/rlm_sql_null/rlm_sql_null.c +++ b/src/modules/rlm_sql/drivers/rlm_sql_null/rlm_sql_null.c @@ -100,7 +100,7 @@ extern rlm_sql_driver_t rlm_sql_null; rlm_sql_driver_t rlm_sql_null = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "rlm_sql_null" + .name = "sql_null" }, .sql_socket_init = sql_socket_init, .sql_query = sql_query, diff --git a/src/modules/rlm_sql/drivers/rlm_sql_oracle/rlm_sql_oracle.c b/src/modules/rlm_sql/drivers/rlm_sql_oracle/rlm_sql_oracle.c index 4bbfded9451..843ca33c26a 100644 --- a/src/modules/rlm_sql/drivers/rlm_sql_oracle/rlm_sql_oracle.c +++ b/src/modules/rlm_sql/drivers/rlm_sql_oracle/rlm_sql_oracle.c @@ -613,7 +613,7 @@ static int sql_affected_rows(rlm_sql_handle_t *handle, rlm_sql_config_t const *c extern rlm_sql_driver_t rlm_sql_oracle; rlm_sql_driver_t rlm_sql_oracle = { .common = { - .name = "rlm_sql_oracle", + .name = "sql_oracle", .magic = MODULE_MAGIC_INIT, .inst_size = sizeof(rlm_sql_oracle_t), .config = driver_config, diff --git a/src/modules/rlm_sql/drivers/rlm_sql_postgresql/rlm_sql_postgresql.c b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/rlm_sql_postgresql.c index 95aeb368561..aa788718fbb 100644 --- a/src/modules/rlm_sql/drivers/rlm_sql_postgresql/rlm_sql_postgresql.c +++ b/src/modules/rlm_sql/drivers/rlm_sql_postgresql/rlm_sql_postgresql.c @@ -671,7 +671,7 @@ extern rlm_sql_driver_t rlm_sql_postgresql; rlm_sql_driver_t rlm_sql_postgresql = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "rlm_sql_postgresql", + .name = "sql_postgresql", .inst_size = sizeof(rlm_sql_postgresql_t), .onload = mod_load, .config = driver_config, diff --git a/src/modules/rlm_sql/drivers/rlm_sql_sqlite/rlm_sql_sqlite.c b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/rlm_sql_sqlite.c index 46de6365d07..56ce5c5e63f 100644 --- a/src/modules/rlm_sql/drivers/rlm_sql_sqlite/rlm_sql_sqlite.c +++ b/src/modules/rlm_sql/drivers/rlm_sql_sqlite/rlm_sql_sqlite.c @@ -815,7 +815,7 @@ static int mod_load(void) extern rlm_sql_driver_t rlm_sql_sqlite; rlm_sql_driver_t rlm_sql_sqlite = { .common = { - .name = "rlm_sql_sqlite", + .name = "sql_sqlite", .magic = MODULE_MAGIC_INIT, .inst_size = sizeof(rlm_sql_sqlite_t), .config = driver_config, diff --git a/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/rlm_sql_unixodbc.c b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/rlm_sql_unixodbc.c index 855a9b850a2..2bbaca58ac3 100644 --- a/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/rlm_sql_unixodbc.c +++ b/src/modules/rlm_sql/drivers/rlm_sql_unixodbc/rlm_sql_unixodbc.c @@ -391,7 +391,7 @@ extern rlm_sql_driver_t rlm_sql_unixodbc; rlm_sql_driver_t rlm_sql_unixodbc = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "rlm_sql_unixodbc" + .name = "sql_unixodbc" }, .sql_socket_init = sql_socket_init, .sql_query = sql_query, diff --git a/src/modules/rlm_sql/rlm_sql.c b/src/modules/rlm_sql/rlm_sql.c index 1cd997cd650..48ae1c15bc8 100644 --- a/src/modules/rlm_sql/rlm_sql.c +++ b/src/modules/rlm_sql/rlm_sql.c @@ -83,7 +83,7 @@ static const CONF_PARSER postauth_config[] = { static const CONF_PARSER module_config[] = { { FR_CONF_OFFSET("driver", FR_TYPE_VOID, rlm_sql_t, driver_submodule), .dflt = "null", - .func = module_submodule_parse }, + .func = module_rlm_submodule_parse }, { FR_CONF_OFFSET("server", FR_TYPE_STRING, rlm_sql_config_t, sql_server), .dflt = "" }, /* Must be zero length so drivers can determine if it was set */ { FR_CONF_OFFSET("port", FR_TYPE_UINT32, rlm_sql_config_t, sql_port), .dflt = "0" }, { FR_CONF_OFFSET("login", FR_TYPE_STRING, rlm_sql_config_t, sql_login), .dflt = "" }, diff --git a/src/modules/rlm_sqlippool/rlm_sqlippool.c b/src/modules/rlm_sqlippool/rlm_sqlippool.c index 87375e6db48..0883692c4ed 100644 --- a/src/modules/rlm_sqlippool/rlm_sqlippool.c +++ b/src/modules/rlm_sqlippool/rlm_sqlippool.c @@ -428,7 +428,7 @@ static int mod_instantiate(module_inst_ctx_t const *mctx) } else { inst->pool_name = talloc_typed_strdup(inst, "ippool"); } - sql_inst = module_by_name(NULL, inst->sql_instance_name); + sql_inst = module_rlm_by_name(NULL, inst->sql_instance_name); if (!sql_inst) { cf_log_err(conf, "failed to find sql instance named %s", inst->sql_instance_name); diff --git a/src/process/arp/base.c b/src/process/arp/base.c index 651fea3f222..a947ced041b 100644 --- a/src/process/arp/base.c +++ b/src/process/arp/base.c @@ -244,7 +244,7 @@ extern fr_process_module_t process_arp; fr_process_module_t process_arp = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_arp", + .name = "arp", .inst_size = sizeof(process_arp_t) }, .process = mod_process, diff --git a/src/process/control/base.c b/src/process/control/base.c index c303446cb31..6c4ece5fce0 100644 --- a/src/process/control/base.c +++ b/src/process/control/base.c @@ -53,7 +53,7 @@ extern fr_process_module_t process_control; fr_process_module_t process_control = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_control" + .name = "control" }, .process = mod_process, .dict = &dict_freeradius diff --git a/src/process/dhcpv4/base.c b/src/process/dhcpv4/base.c index 4d8e2eabd59..b4970a462d3 100644 --- a/src/process/dhcpv4/base.c +++ b/src/process/dhcpv4/base.c @@ -453,7 +453,7 @@ extern fr_process_module_t process_dhcpv4; fr_process_module_t process_dhcpv4 = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_dhcpv4", + .name = "dhcpv4", .inst_size = sizeof(process_dhcpv4_t) }, .process = mod_process, diff --git a/src/process/dhcpv6/base.c b/src/process/dhcpv6/base.c index 6b95f731d7d..bff44364664 100644 --- a/src/process/dhcpv6/base.c +++ b/src/process/dhcpv6/base.c @@ -1233,7 +1233,7 @@ extern fr_process_module_t process_dhcpv6; fr_process_module_t process_dhcpv6 = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_dhcpv6", + .name = "dhcpv6", .config = dhcpv6_process_config, .inst_size = sizeof(process_dhcpv6_t), diff --git a/src/process/dns/base.c b/src/process/dns/base.c index a28ca562cf6..332a6af8ac6 100644 --- a/src/process/dns/base.c +++ b/src/process/dns/base.c @@ -192,7 +192,7 @@ extern fr_process_module_t process_dns; fr_process_module_t process_dns = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_dns", + .name = "dns", .inst_size = sizeof(process_dns_t) }, .process = mod_process, diff --git a/src/process/eap_aka/base.c b/src/process/eap_aka/base.c index d9e6c51d4dd..0d9a08b2f3c 100644 --- a/src/process/eap_aka/base.c +++ b/src/process/eap_aka/base.c @@ -267,7 +267,7 @@ extern fr_process_module_t process_eap_aka; fr_process_module_t process_eap_aka = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_eap_aka", + .name = "eap_aka", .onload = mod_load, .unload = mod_unload, .config = submodule_config, diff --git a/src/process/eap_aka_prime/base.c b/src/process/eap_aka_prime/base.c index e0b6d5bd437..4f665a1d034 100644 --- a/src/process/eap_aka_prime/base.c +++ b/src/process/eap_aka_prime/base.c @@ -268,7 +268,7 @@ extern fr_process_module_t process_eap_aka_prime; fr_process_module_t process_eap_aka_prime = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_eap_aka_prime", + .name = "eap_aka_prime", .onload = mod_load, .unload = mod_unload, .config = submodule_config, diff --git a/src/process/eap_sim/base.c b/src/process/eap_sim/base.c index afa97c75b20..d98ec6d44e7 100644 --- a/src/process/eap_sim/base.c +++ b/src/process/eap_sim/base.c @@ -255,7 +255,7 @@ extern fr_process_module_t process_eap_sim; fr_process_module_t process_eap_sim = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_eap_sim", + .name = "eap_sim", .onload = mod_load, .unload = mod_unload, .config = submodule_config, diff --git a/src/process/radius/base.c b/src/process/radius/base.c index efd365c0202..db91d208451 100644 --- a/src/process/radius/base.c +++ b/src/process/radius/base.c @@ -1127,7 +1127,7 @@ extern fr_process_module_t process_radius; fr_process_module_t process_radius = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_radius", + .name = "radius", .config = config, .inst_size = sizeof(process_radius_t), diff --git a/src/process/tacacs/base.c b/src/process/tacacs/base.c index 8a633d7cc61..5d1e7e7fbb7 100644 --- a/src/process/tacacs/base.c +++ b/src/process/tacacs/base.c @@ -707,7 +707,7 @@ extern fr_process_module_t process_tacacs; fr_process_module_t process_tacacs = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_tacacs", + .name = "tacacs", .config = config, .inst_size = sizeof(process_tacacs_t), .bootstrap = mod_bootstrap, diff --git a/src/process/tls/base.c b/src/process/tls/base.c index 025aeff734f..85a68830b1e 100644 --- a/src/process/tls/base.c +++ b/src/process/tls/base.c @@ -183,7 +183,7 @@ extern fr_process_module_t process_tls; fr_process_module_t process_tls = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_tls", + .name = "tls", .inst_size = sizeof(process_tls_t) }, .process = mod_process, diff --git a/src/process/ttls/base.c b/src/process/ttls/base.c index ebf275eb535..305de933ce1 100644 --- a/src/process/ttls/base.c +++ b/src/process/ttls/base.c @@ -821,7 +821,7 @@ extern fr_process_module_t process_ttls; fr_process_module_t process_ttls = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_ttls", + .name = "ttls", .config = config, .inst_size = sizeof(process_ttls_t), diff --git a/src/process/vmps/base.c b/src/process/vmps/base.c index 450ce25c102..1d76482820d 100644 --- a/src/process/vmps/base.c +++ b/src/process/vmps/base.c @@ -261,7 +261,7 @@ extern fr_process_module_t process_vmps; fr_process_module_t process_vmps = { .common = { .magic = MODULE_MAGIC_INIT, - .name = "process_vmps", + .name = "vmps", .inst_size = sizeof(process_vmps_t) }, .process = mod_process, diff --git a/src/tests/radmin/show-server-list.out b/src/tests/radmin/show-server-list.out index a15458814de..4731316e2ef 100644 --- a/src/tests/radmin/show-server-list.out +++ b/src/tests/radmin/show-server-list.out @@ -1 +1 @@ -control namespace = control +control namespace = internal -- 2.47.3