/** Iterate over an array of named module methods, looking for matches
*
- * @param[in] bindings A terminated array of module method bindings.
- * pre-sorted using #section_name_cmp with name2
- * sublists populated.
+ * @param[in] mmg A structure containing a terminated array of
+ * module method bindings. pre-sorted using #section_name_cmp
+ * with name2 sublists populated.
* @param[in] section name1 of the method being called can be one of the following:
* - An itenfier.
* - CF_IDENT_ANY if the method is a wildcard.
* - NULL on not found.
*/
static CC_HINT(nonnull)
-module_method_binding_t const *module_binding_find(module_method_binding_t const *bindings, section_name_t const *section)
+module_method_binding_t const *module_binding_find(module_method_group_t const *mmg, section_name_t const *section)
{
+ module_method_group_t const *mmg_p = mmg;
module_method_binding_t const *p;
- /*
- * This could potentially be improved by using a binary search
- * but given the small number of items, reduced branches and
- * sequential access just scanning the list, it's probably not
- * worth it.
- */
- for (p = bindings; p->section; p++) {
- switch (section_name_match(p->section, section)) {
- case 1: /* match */
- return p;
+ while (mmg_p) {
+ /*
+ * This could potentially be improved by using a binary search
+ * but given the small number of items, reduced branches and
+ * sequential access just scanning the list, it's probably not
+ * worth it.
+ */
+ for (p = mmg_p->bindings; p->section; p++) {
+ switch (section_name_match(p->section, section)) {
+ case 1: /* match */
+ return p;
- case -1: /* name1 didn't match, skip to the end of the sub-list */
- p = fr_dlist_tail(&p->same_name1);
- break;
+ case -1: /* name1 didn't match, skip to the end of the sub-list */
+ p = fr_dlist_tail(&p->same_name1);
+ break;
- case 0: /* name1 did match - see if we can find a matching name2 */
- {
- fr_dlist_head_t const *same_name1 = &p->same_name1;
+ case 0: /* name1 did match - see if we can find a matching name2 */
+ {
+ fr_dlist_head_t const *same_name1 = &p->same_name1;
- while ((p = fr_dlist_next(same_name1, p))) {
- if (section_name2_match(p->section, section)) return p;
+ while ((p = fr_dlist_next(same_name1, p))) {
+ if (section_name2_match(p->section, section)) return p;
+ }
+ p = fr_dlist_tail(same_name1);
+ }
+ break;
}
- p = fr_dlist_tail(same_name1);
- }
- break;
- }
#ifdef __clang_analyzer__
- /* Will never be NULL, worse case, p doesn't change*/
- if (!p) break;
+ /* Will never be NULL, worse case, p doesn't change*/
+ if (!p) break;
#endif
+ }
+
+ /*
+ * Failed to match, search the next deepest group in the chain.
+ */
+ mmg_p = mmg_p->next;
}
return NULL;
/** Dump the available bindings for the module into the strerror stack
*
- * @param[in] mmb bindings to push onto the strerror stack.
+ * @note Methods from _all_ linked module method groups will be pushed onto the error stack.
+ *
+ * @param[in] mmg module method group to evaluate.
*/
-static void module_rlm_methods_to_strerror(module_method_binding_t const *mmb)
+static void module_rlm_methods_to_strerror(module_method_group_t const *mmg)
{
- module_method_binding_t const *mmb_p;
+ module_method_group_t const *mmg_p = mmg;
+ module_method_binding_t const *mmb_p;
+ bool first = true;
- if (!mmb || !mmb[0].section) {
- fr_strerror_const_push("Module provides no methods");
- return;
- }
+ while (mmg_p) {
+ mmb_p = mmg_p->bindings;
- fr_strerror_const_push("Available methods are:");
+ if (!mmb_p || !mmb_p[0].section) goto next;
- for (mmb_p = mmb; mmb_p->section; mmb_p++) {
- char const *name1 = section_name_str(mmb_p->section->name1);
- char const *name2 = section_name_str(mmb_p->section->name2);
+ if (first) {
+ fr_strerror_const_push("Available methods are:");
+ first = false;
+ }
+
+ for (; mmb_p->section; mmb_p++) {
+ char const *name1 = section_name_str(mmb_p->section->name1);
+ char const *name2 = section_name_str(mmb_p->section->name2);
+
+ fr_strerror_printf_push(" %s%s%s",
+ name1, name2 ? "." : "", name2 ? name2 : "");
+ }
+ next:
+ mmg_p = mmg_p->next;
+ }
- fr_strerror_printf_push(" %s%s%s",
- name1, name2 ? "." : "", name2 ? name2 : "");
+ if (first) {
+ fr_strerror_const_push("No methods available");
}
}
.name2 = fr_sbuff_used(elem2) ? elem2->start : NULL
};
- mmb = module_binding_find(mmc->rlm->method.bindings, &method);
+ mmb = module_binding_find(&mmc->rlm->method_group, &method);
if (!mmb) {
fr_strerror_printf("Module \"%s\" does not have method %s%s%s",
mmc->mi->name,
method.name2 ? method.name2 : ""
);
- module_rlm_methods_to_strerror(mmc->rlm->method.bindings);
+ module_rlm_methods_to_strerror(&mmc->rlm->method_group);
return fr_sbuff_error(&meth_start);
}
mmc->mmb = *mmb; /* For locality of reference and fewer derefs */
*
* If that fails, we're done.
*/
- mmb = module_binding_find(mmc->rlm->method.bindings, section);
+ mmb = module_binding_find(&mmc->rlm->method_group, section);
if (!mmb) {
section_name_t const **alt_p = virtual_server_section_methods(vs, section);
if (alt_p) {
for (; *alt_p; alt_p++) {
- mmb = module_binding_find(mmc->rlm->method.bindings, *alt_p);
+ mmb = module_binding_find(&mmc->rlm->method_group, *alt_p);
if (mmb) {
if (mmc_out) section_name_dup(ctx, &mmc->asked, *alt_p);
break;
section->name2 ? "." : "",
section->name2 ? section->name2 : ""
);
- module_rlm_methods_to_strerror(mmc->rlm->method.bindings);
+ module_rlm_methods_to_strerror(&mmc->rlm->method_group);
return fr_sbuff_error(&meth_start);
}
{
module_rlm_t *mrlm = module_rlm_from_module(mi->exported);
- return module_method_group_validate(&mrlm->method);
+ return module_method_group_validate(&mrlm->method_group);
}
/** Allocate a rlm module instance
struct module_rlm_s {
module_t common; //!< Common fields presented by all modules.
- module_method_group_t method; //!< named methods
+ module_method_group_t method_group; //!< named methods
};
struct module_rlm_instance_s {
.instantiate = mod_instantiate,
.detach = mod_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_always_return },
MODULE_BINDING_TERMINATOR
.config = module_config,
.instantiate = mod_instantiate,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
/*
* Hack to support old configurations
.instantiate = mod_instantiate,
.detach = mod_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("clear", CF_IDENT_ANY), .method = mod_method_clear, .method_env = &cache_method_env },
{ .section = SECTION_NAME("load", CF_IDENT_ANY), .method = mod_method_load, .method_env = &cache_method_env },
.config = module_config,
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &chap_auth_method_env },
{ .section = SECTION_NAME("recv", "Access-Request"), .method = mod_authorize, .method_env = &chap_autz_method_env },
.onload = mod_load,
.unload = mod_unload
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_authorize },
MODULE_BINDING_TERMINATOR
.instantiate = mod_instantiate,
.detach = mod_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting },
{ .section = SECTION_NAME("recv", CF_IDENT_ANY), .method = mod_authorize },
.bootstrap = mod_bootstrap,
.instantiate = mod_instantiate,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_process },
MODULE_BINDING_TERMINATOR
.config = module_config,
.bootstrap = mod_bootstrap
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_delay },
MODULE_BINDING_TERMINATOR
.config = module_config,
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting, .method_env = &method_env },
{ .section = SECTION_NAME("recv", "accounting-request"), .method = mod_accounting, .method_env = &method_env },
.thread_inst_type = "rlm_dhcpv4_thread_t",
.thread_instantiate = mod_thread_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_process },
MODULE_BINDING_TERMINATOR
.inst_size = sizeof(rlm_digest_t),
.instantiate = mod_instantiate,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
{ .section = SECTION_NAME("recv", "Access-Request"), .method = mod_authorize },
.unload = mod_unload,
.instantiate = mod_instantiate,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
{ .section = SECTION_NAME("recv", "Access-Request"), .method = mod_authorize },
.bootstrap = mod_bootstrap,
.instantiate = mob_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_exec_dispatch_oneshot, .method_env = &exec_method_env },
MODULE_BINDING_TERMINATOR
.inst_size = sizeof(rlm_files_t),
.config = module_config,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_files, .method_env = &method_env },
MODULE_BINDING_TERMINATOR
.thread_instantiate = mod_thread_instantiate,
.thread_detach = mod_thread_detach,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
MODULE_BINDING_TERMINATOR
.config = module_config,
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("recv", CF_IDENT_ANY), .method = mod_authorize },
{ .section = SECTION_NAME("send", CF_IDENT_ANY), .method = mod_post_auth },
.instantiate = mod_instantiate,
.detach = mod_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
MODULE_BINDING_TERMINATOR
.thread_instantiate = mod_thread_instantiate,
.thread_detach = mod_thread_detach,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
/*
* Hack to support old configurations
.instantiate = mod_instantiate,
.detach = mod_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_do_linelog, .method_env = &linelog_method_env },
MODULE_BINDING_TERMINATOR
.instantiate = mod_instantiate,
.thread_instantiate = mod_thread_instantiate,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_insert_logtee },
MODULE_BINDING_TERMINATOR
.instantiate = mod_instantiate,
.detach = mod_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &mschap_auth_method_env },
{ .section = SECTION_NAME("recv", CF_IDENT_ANY), .method = mod_authorize, .method_env = &mschap_autz_method_env },
.inst_size = sizeof(rlm_opendirectory_t),
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
{ .section = SECTION_NAME("recv", CF_IDENT_ANY), .method = mod_authorize },
.config = module_config,
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
MODULE_BINDING_TERMINATOR
.config = module_config,
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
/*
* Hack to support old configurations
.instantiate = mod_instantiate,
.detach = mod_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_passwd_map },
MODULE_BINDING_TERMINATOR
.thread_instantiate = mod_thread_instantiate,
.thread_detach = mod_thread_detach,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
/*
* Hack to support old configurations
.thread_instantiate = mod_thread_instantiate,
.thread_detach = mod_thread_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
/*
* Hack to support old configurations
.instantiate = mod_instantiate,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_process },
MODULE_BINDING_TERMINATOR
.instantiate = mod_instantiate,
.detach = mod_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting, .method_env = &method_env },
MODULE_BINDING_TERMINATOR
.onload = mod_load,
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("recv", "Access-Request"), .method = mod_alloc, .method_env = &redis_ippool_alloc_method_env }, /* radius */
{ .section = SECTION_NAME("accounting", "Start"), .method = mod_update, .method_env = &redis_ippool_update_method_env }, /* radius */
.onload = mod_load,
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting },
MODULE_BINDING_TERMINATOR
.thread_instantiate = mod_thread_instantiate,
.thread_detach = mod_thread_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
/*
* Hack to support old configurations
.thread_instantiate = mod_thread_instantiate,
.thread_detach = mod_thread_detach,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &auth_env },
{ .section = SECTION_NAME("mail", CF_IDENT_ANY), .method = mod_mail, .method_env = &method_env },
.config = module_config,
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("send", CF_IDENT_ANY), .method = mod_sometimes_reply },
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_sometimes_packet },
.thread_instantiate = mod_thread_instantiate,
.thread_detach = mod_thread_detach,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
/*
* Hack to support old configurations
.bootstrap = mod_bootstrap,
.instantiate = mod_instantiate,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_authorize, .method_env = &sqlcounter_call_env },
MODULE_BINDING_TERMINATOR
.config = module_config,
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
/*
* RADIUS specific
.thread_instantiate = mod_thread_instantiate,
.thread_detach = mod_thread_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_stats },
MODULE_BINDING_TERMINATOR
.instantiate = mod_instantiate,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_process },
MODULE_BINDING_TERMINATOR
.thread_instantiate = mod_thread_instantiate,
.thread_detach = mod_thread_detach
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting },
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
.config = module_config,
.instantiate = mod_instantiate
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate, .method_env = &method_env },
MODULE_BINDING_TERMINATOR
.config = module_config,
.bootstrap = mod_bootstrap
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("accounting", CF_IDENT_ANY), .method = mod_accounting },
{ .section = SECTION_NAME("recv", "Access-Request"), .method = mod_authorize },
.magic = MODULE_MAGIC_INIT,
.name = "utf8"
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME(CF_IDENT_ANY, CF_IDENT_ANY), .method = mod_utf8_clean },
MODULE_BINDING_TERMINATOR
.inst_size = sizeof(rlm_wimax_t),
.config = module_config,
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("recv", "accounting-request"), .method = mod_preacct },
{ .section = SECTION_NAME("recv", CF_IDENT_ANY), .method = mod_authorize },
.detach = mod_detach,
#endif
},
- .method = {
+ .method_group = {
.bindings = (module_method_binding_t[]){
{ .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
{ .section = SECTION_NAME("recv", "Access-Request"), .method = mod_authorize },