/** Avoid boilerplate when setting the module instance name
*
*/
-char const *module_instance_name_from_conf(CONF_SECTION *conf)
+fr_slen_t module_instance_name_from_conf(char const **name, CONF_SECTION *conf)
{
- char const *name2;
+ char const *name2;
+ char const *inst_name;
+ fr_slen_t slen;
name2 = cf_section_name2(conf);
- if (name2) return name2;
+ if (name2) {
+ inst_name = name2;
+ goto done;
+ }
+
+ inst_name = cf_section_name1(conf);
+done:
+ slen = module_instance_name_valid(inst_name);
+ if (slen < 0) {
+ cf_log_perr(conf, "Invalid module configuration");
+ *name = NULL;
+ return slen;
+ }
- return cf_section_name1(conf);
+ *name = inst_name;
+
+ return 0;
}
/** Covert a CONF_SECTION into parsed module instance data
*out = data;
}
+/** Check to see if a module instance name is valid
+ *
+ * @note On failure the error message may be retrieved with fr_strerror().
+ *
+ * @param[in] inst_name to check.
+ *
+ * @return
+ * - 0 on success.
+ * - Negative value on error indicating the position of the bad char.
+ */
+fr_slen_t module_instance_name_valid(char const *inst_name)
+{
+ static bool const inst_allowed_chars[UINT8_MAX + 1] = {
+ ['-'] = true, ['/'] = true, ['_'] = true,
+ ['0'] = true, ['1'] = true, ['2'] = true, ['3'] = true, ['4'] = true,
+ ['5'] = true, ['6'] = true, ['7'] = true, ['8'] = true, ['9'] = true,
+ ['A'] = true, ['B'] = true, ['C'] = true, ['D'] = true, ['E'] = true,
+ ['F'] = true, ['G'] = true, ['H'] = true, ['I'] = true, ['J'] = true,
+ ['K'] = true, ['L'] = true, ['M'] = true, ['N'] = true, ['O'] = true,
+ ['P'] = true, ['Q'] = true, ['R'] = true, ['S'] = true, ['T'] = true,
+ ['U'] = true, ['V'] = true, ['W'] = true, ['X'] = true, ['Y'] = true,
+ ['Z'] = true,
+ ['a'] = true, ['b'] = true, ['c'] = true, ['d'] = true, ['e'] = true,
+ ['f'] = true, ['g'] = true, ['h'] = true, ['i'] = true, ['j'] = true,
+ ['k'] = true, ['l'] = true, ['m'] = true, ['n'] = true, ['o'] = true,
+ ['p'] = true, ['q'] = true, ['r'] = true, ['s'] = true, ['t'] = true,
+ ['u'] = true, ['v'] = true, ['w'] = true, ['x'] = true, ['y'] = true,
+ ['z'] = true
+ };
+
+ /*
+ * [] are used for dynamic module selection.
+ * . is used as a method and submodule separator.
+ * Quoting and other characters would just confuse the parser in too many
+ * instances so they're disallowed too.
+ */
+ {
+ size_t len = strlen(inst_name);
+
+ for (size_t i = 0; i < len; i++) {
+ if (!inst_allowed_chars[(uint8_t)inst_name[i]]) {
+ fr_strerror_printf("Instance name \"%s\" contains an invalid character. "
+ "Valid characters are [0-9a-zA-Z/_-]", inst_name);
+ return -(i + 1);
+ }
+ }
+ }
+
+ return 0;
+}
+
+
/** Allocate a new module and add it to a module list for later bootstrap/instantiation
*
* - Load the module shared library.
*
* @{
*/
-char const *module_instance_name_from_conf(CONF_SECTION *conf);
+fr_slen_t module_instance_name_from_conf(char const **name, CONF_SECTION *conf);
int module_instance_conf_parse(module_instance_t *mi, CONF_SECTION *conf);
int modules_bootstrap(module_list_t const *ml) CC_HINT(nonnull) CC_HINT(warn_unused_result);
+fr_slen_t module_instance_name_valid(char const *inst_name) CC_HINT(nonnull);
+
module_instance_t *module_instance_copy(module_list_t *dst, module_instance_t const *src, char const *inst_name)
CC_HINT(nonnull(1,2)) CC_HINT(warn_unused_result);
static int module_conf_parse(module_list_t *ml, CONF_SECTION *mod_conf)
{
char const *name;
+ char const *inst_name;
module_instance_t *mi = NULL;
CONF_SECTION *actions;
return 0;
}
- mi = module_instance_alloc(ml, NULL, DL_MODULE_TYPE_MODULE, name, module_instance_name_from_conf(mod_conf), 0);
+ if (module_instance_name_from_conf(&inst_name, mod_conf) < 0) goto invalid_name;
+
+ mi = module_instance_alloc(ml, NULL, DL_MODULE_TYPE_MODULE, name, inst_name, 0);
if (unlikely(mi == NULL)) {
cf_log_perr(mod_conf, "Failed loading module");
return -1;
module_instance_t *mi;
char const *namespace;
char *module_name, *p, *end;
+ char const *inst_name;
fr_process_module_t const *process;
fr_cond_assert_msg(process_modules,
p < end;
p++) if (*p == '-') *p = '_';
+ if (module_instance_name_from_conf(&inst_name, server_cs) < 0) return -1;
/*
* The module being loaded is the namespace with all '-'
* The instance name is the virtual server name.
*/
mi = module_instance_alloc(process_modules, NULL, DL_MODULE_TYPE_PROCESS,
- module_name, module_instance_name_from_conf(server_cs),
+ module_name, inst_name,
0);
talloc_free(module_name);
if (mi == NULL) {
inst_name = cf_section_name2(listener_cs);
if (!inst_name) inst_name = mod_name;
- MEM(qual_inst_name = talloc_asprintf(NULL, "%s.%s", cf_section_name2(server_cs), inst_name));
- mi = module_instance_alloc(proto_modules, NULL, DL_MODULE_TYPE_PROTO, mod_name, qual_inst_name, 0);
- talloc_free(qual_inst_name);
- if (!mi) {
+ if (module_instance_name_valid(inst_name) < 0) {
error:
cf_log_err(listener_cs, "Failed loading listener");
return -1;
}
+
+ MEM(qual_inst_name = talloc_asprintf(NULL, "%s.%s", cf_section_name2(server_cs), inst_name));
+ mi = module_instance_alloc(proto_modules, NULL, DL_MODULE_TYPE_PROTO, mod_name, qual_inst_name, 0);
+ talloc_free(qual_inst_name);
+ if (!mi) goto error;
+
if (unlikely(module_instance_conf_parse(mi, listener_cs) < 0)) goto error;
if (DEBUG_ENABLED4) cf_log_debug(ci, "Loading %s listener into %p", inst_name, out);
* If we're not loading the work submodule directly, then try to load it here.
*/
if (strcmp(inst->io_submodule->module->dl->name, "proto_detail_work") != 0) {
- CONF_SECTION *transport_cs;
- module_instance_t *mi;
+ CONF_SECTION *transport_cs;
+ module_instance_t *mi;
+ char const *inst_name;
inst->work_submodule = NULL;
}
}
+ if (module_instance_name_from_conf(&inst_name, transport_cs) < 0) return -1;
+
/*
* This *should* get bootstrapped at some point after this module
* as it's inserted into the three the caller is iterating over.
* of that list.
*/
inst->work_submodule = module_instance_alloc(mi->ml, mi, DL_MODULE_TYPE_SUBMODULE,
- "work", module_instance_name_from_conf(transport_cs), 0);
+ "work", inst_name, 0);
if (inst->work_submodule == NULL) {
error:
cf_log_perr(mi->conf, "Failed to load proto_detail_work");