]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Allow submodules to determine if they should be set for a given identity
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 23 Apr 2021 18:21:00 +0000 (13:21 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Fri, 23 Apr 2021 18:22:59 +0000 (13:22 -0500)
src/lib/eap/submodule.h
src/lib/eap/types.h
src/modules/rlm_eap/rlm_eap.c
src/modules/rlm_eap/rlm_eap.h

index c0b5ae0b8de47377251facd8e9ed74eb8463bb0c..b1bd7e30bca4ddd10ae3a71bd1fd87b507ed3ee0 100644 (file)
 #include <freeradius-devel/server/dl_module.h>
 #include <freeradius-devel/server/module.h>
 
-#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
index 24bccf90b6455d33d18ae286509f8137be624d9a..b046e5ad2b62abe225cdd11d03460dd1815c9a80 100644 (file)
@@ -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 */
index 52f0ba6c653ed060b943864c8030ada1742a1f0a..10f3f742f020170e68f12e5aa9241ce7011ddefa 100644 (file)
@@ -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;
 }
 
index abb6846d8e31a8039008fb1a2a1adc7342f97104..b43601245db020d209e25a2fd1102a39007f66ea 100644 (file)
@@ -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).