From: Arran Cudbard-Bell Date: Fri, 23 Apr 2021 18:21:00 +0000 (-0500) Subject: Allow submodules to determine if they should be set for a given identity X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ef6befcdb554b9624c6a71ea6e866c8ffa2daa4c;p=thirdparty%2Ffreeradius-server.git Allow submodules to determine if they should be set for a given identity --- diff --git a/src/lib/eap/submodule.h b/src/lib/eap/submodule.h index c0b5ae0b8de..b1bd7e30bca 100644 --- a/src/lib/eap/submodule.h +++ b/src/lib/eap/submodule.h @@ -25,7 +25,23 @@ #include #include -#define MAX_PROVIDED_METHODS 10 +#define MAX_PROVIDED_METHODS 5 + +/** Allow a module to vouch explicitly for an identity + * + * This is mainly used for EAP-SIM/EAP-AKA/EAP-AKA' where the preferred + * eap method is specified by the first byte of the identity. + * + * @param[in] inst Submodule instance. + * @param[in] id To check. Do NOT assume the identity is binary safe, + * it is common for some identities to be prefixed with + * a \0 byte. + * @param[in] id_len Length of the identity. + * @return + * - FR_EAP_METHOD_INVALID if we don't recognise the identity. + * - Another FR_EAP_METHOD_* to run as the initial EAP method. + */ +typedef eap_type_t (*eap_type_identity_t)(void *inst, char const *id, size_t id_len); /** Interface exported by EAP submodules * @@ -35,14 +51,16 @@ typedef struct { FR_MODULE_COMMON; //!< Common fields for all instantiated modules. FR_MODULE_THREADED_COMMON; //!< Common fields for threaded modules. - eap_type_t provides[MAX_PROVIDED_METHODS]; //!< Allow the module to register itself for more - ///< than one EAP-Method. + eap_type_t provides[MAX_PROVIDED_METHODS]; //!< Allow the module to register itself for more + ///< than one EAP-Method. + + eap_type_identity_t type_identity; //!< Do we recognise this identity? - module_method_t session_init; //!< Callback for creating a new #eap_session_t. + module_method_t session_init; //!< Callback for creating a new #eap_session_t. - fr_dict_t const **namespace; //!< Namespace children should be allocated in. + fr_dict_t const **namespace; //!< Namespace children should be allocated in. - bool clone_parent_lists; //!< HACK until all eap methods run their own sections. + bool clone_parent_lists; //!< HACK until all eap methods run their own sections. } rlm_eap_submodule_t; /** Private structure to hold handles and interfaces for an EAP method diff --git a/src/lib/eap/types.h b/src/lib/eap/types.h index 24bccf90b64..b046e5ad2b6 100644 --- a/src/lib/eap/types.h +++ b/src/lib/eap/types.h @@ -41,7 +41,7 @@ typedef enum eap_code { FR_EAP_CODE_MAX } eap_code_t; -typedef enum eap_method { +typedef enum eap_type { FR_EAP_METHOD_INVALID = 0, /* 0 */ FR_EAP_METHOD_IDENTITY, /* 1 */ FR_EAP_METHOD_NOTIFICATION, /* 2 */ diff --git a/src/modules/rlm_eap/rlm_eap.c b/src/modules/rlm_eap/rlm_eap.c index 52f0ba6c653..10f3f742f02 100644 --- a/src/modules/rlm_eap/rlm_eap.c +++ b/src/modules/rlm_eap/rlm_eap.c @@ -55,8 +55,7 @@ static int eap_type_parse(UNUSED TALLOC_CTX *ctx, void *out, UNUSED void *parent CONF_ITEM *ci, UNUSED CONF_PARSER const *rule); static const CONF_PARSER module_config[] = { - { FR_CONF_OFFSET("default_eap_type", FR_TYPE_VOID, rlm_eap_t, default_method), - .dflt = "md5", .func = eap_type_parse }, + { FR_CONF_OFFSET_IS_SET("default_eap_type", FR_TYPE_VOID, rlm_eap_t, default_method), .func = eap_type_parse }, { FR_CONF_OFFSET("type", FR_TYPE_VOID | FR_TYPE_MULTI | FR_TYPE_NOT_EMPTY, rlm_eap_t, submodule_cs), .func = submodule_parse }, @@ -488,7 +487,7 @@ static unlang_action_t eap_method_select(rlm_rcode_t *p_result, module_ctx_t con { rlm_eap_t const *inst = talloc_get_type_abort_const(mctx->instance, rlm_eap_t); eap_type_data_t *type = &eap_session->this_round->response->type; - request_t *request = eap_session->request; + request_t *request = eap_session->request; rlm_eap_method_t const *method; @@ -540,6 +539,28 @@ static unlang_action_t eap_method_select(rlm_rcode_t *p_result, module_ctx_t con if (vp) { RDEBUG2("Using method from &control.EAP-Type"); next = vp->vp_uint32; + /* + * We have an array of the submodules which + * have a type_identity callback. Call + * each of these in turn to see if any of + * them recognise the identity. + */ + } else if (inst->type_identity_submodule) { + size_t i; + + for (i = 0; i < inst->type_identity_submodule_len; i++) { + rlm_eap_submodule_t const *submodule = + (rlm_eap_submodule_t const *)inst->type_identity_submodule[i]->module; + eap_type_t ret; + + ret = submodule->type_identity(inst->type_identity_submodule[i]->dl_inst->data, + eap_session->identity, + talloc_array_length(eap_session->identity) - 1); + if (ret != FR_EAP_METHOD_INVALID) { + next = ret; + break; + } + } } /* @@ -1010,8 +1031,18 @@ static int mod_bootstrap(void *instance, CONF_SECTION *cs) * and we haven't completed our own bootstrap phase yet. */ loaded = talloc_array_length(inst->submodule_cs); + + /* + * Pre-allocate the method identity to be the number + * of modules we're going to load. + * + * We'll shrink it later. + */ + if (!inst->default_method_is_set) { + MEM(inst->type_identity_submodule = talloc_array(inst, module_instance_t const *, loaded)); + } + for (i = 0; i < loaded; i++) { - eap_type_t method; CONF_SECTION *submodule_cs = inst->submodule_cs[i]; rlm_eap_submodule_t const *submodule; module_instance_t *submodule_inst; @@ -1026,9 +1057,19 @@ static int mod_bootstrap(void *instance, CONF_SECTION *cs) * Add the methods the submodule provides */ for (j = 0; j < MAX_PROVIDED_METHODS; j++) { + eap_type_t method; + if (!submodule->provides[j]) break; method = submodule->provides[j]; + + /* + * If the user didn't specify a default method + * take the first method provided by the first + * submodule as the default. + */ + if (!inst->default_method_is_set && (i == 0)) inst->default_method = method; + /* * Check for duplicates */ @@ -1046,14 +1087,47 @@ static int mod_bootstrap(void *instance, CONF_SECTION *cs) inst->methods[method].submodule = submodule; } + /* + * This module provides a method identity + * callback. We need to call each of these + * in turn if default_eap_type isn't set, + * to figure out the default eap type. + */ + if (!inst->default_method_is_set && submodule->type_identity) { + inst->type_identity_submodule[inst->type_identity_submodule_len++] = submodule_inst; + } count++; } + /* + * Check if the default method specified is actually + * allowed by the config. + */ + if (inst->default_method_is_set && !inst->methods[inst->default_method].submodule) { + cf_log_err_by_child(cs, "default_eap_type", "EAP-Type \"%s\" is not enabled", + eap_type2name(inst->default_method)); + return -1; + } + if (count == 0) { cf_log_err(cs, "No EAP method configured, module cannot do anything"); return -1; } + /* + * Shrink the method identity array so it's the + * correct length. + */ + if (!inst->default_method_is_set) { + if (inst->type_identity_submodule_len > 0) { + MEM(inst->type_identity_submodule = talloc_realloc(inst, inst->type_identity_submodule, + module_instance_t const *, + inst->type_identity_submodule_len)); + } else { + TALLOC_FREE(inst->type_identity_submodule); + } + } + return 0; } diff --git a/src/modules/rlm_eap/rlm_eap.h b/src/modules/rlm_eap/rlm_eap.h index abb6846d8e3..b43601245db 100644 --- a/src/modules/rlm_eap/rlm_eap.h +++ b/src/modules/rlm_eap/rlm_eap.h @@ -41,7 +41,16 @@ typedef struct { rlm_eap_method_t methods[FR_EAP_METHOD_MAX]; //!< Array of loaded (or not), submodules. char const *default_method_name; //!< Default method to attempt to start. + eap_type_t default_method; //!< Resolved default_method_name. + bool default_method_is_set; //!< Whether the user specified a default + ///< eap method. + + module_instance_t const **type_identity_submodule; //!< List of submodules which have a + ///< method identity callback, i.e. those + ///< which may set themselves to be the default + ///< EAP-Type based on the identity provided. + size_t type_identity_submodule_len; //!< How many submodules are in the list. bool ignore_unknown_types; //!< Ignore unknown types (for later proxying).