Add features support to eap-radius plugin
[strongswan.git] / src / libcharon / plugins / eap_radius / eap_radius_plugin.c
index 91aae2f..4119ec5 100644 (file)
@@ -20,6 +20,7 @@
 #include "radius_server.h"
 
 #include <daemon.h>
+#include <threading/rwlock.h>
 
 /**
  * Default RADIUS server port, when not configured
@@ -42,6 +43,11 @@ struct private_eap_radius_plugin_t {
         * List of RADIUS servers
         */
        linked_list_t *servers;
+
+       /**
+        * Lock for server list
+        */
+       rwlock_t *lock;
 };
 
 /**
@@ -49,20 +55,10 @@ struct private_eap_radius_plugin_t {
  */
 static private_eap_radius_plugin_t *instance = NULL;
 
-METHOD(plugin_t, destroy, void,
-       private_eap_radius_plugin_t *this)
-{
-       charon->eap->remove_method(charon->eap, (eap_constructor_t)eap_radius_create);
-       this->servers->destroy_offset(this->servers,
-                                                                 offsetof(radius_server_t, destroy));
-       free(this);
-       instance = NULL;
-}
-
 /**
  * Load RADIUS servers from configuration
  */
-static bool load_servers(private_eap_radius_plugin_t *this)
+static void load_servers(private_eap_radius_plugin_t *this)
 {
        enumerator_t *enumerator;
        radius_server_t *server;
@@ -78,7 +74,7 @@ static bool load_servers(private_eap_radius_plugin_t *this)
                if (!secret)
                {
                        DBG1(DBG_CFG, "no RADUIS secret defined");
-                       return FALSE;
+                       return;
                }
                nas_identifier = lib->settings->get_str(lib->settings,
                                        "charon.plugins.eap-radius.nas_identifier", "strongSwan");
@@ -86,15 +82,15 @@ static bool load_servers(private_eap_radius_plugin_t *this)
                                        "charon.plugins.eap-radius.port", RADIUS_PORT);
                sockets = lib->settings->get_int(lib->settings,
                                        "charon.plugins.eap-radius.sockets", 1);
-               server = radius_server_create(address, port, nas_identifier,
+               server = radius_server_create(address, address, port, nas_identifier,
                                                                          secret, sockets, 0);
                if (!server)
                {
                        DBG1(DBG_CFG, "no RADUIS server defined");
-                       return FALSE;
+                       return;
                }
                this->servers->insert_last(this->servers, server);
-               return TRUE;
+               return;
        }
 
        enumerator = lib->settings->create_section_enumerator(lib->settings,
@@ -124,7 +120,7 @@ static bool load_servers(private_eap_radius_plugin_t *this)
                        "charon.plugins.eap-radius.servers.%s.sockets", 1, section);
                preference = lib->settings->get_int(lib->settings,
                        "charon.plugins.eap-radius.servers.%s.preference", 0, section);
-               server = radius_server_create(address, port, nas_identifier,
+               server = radius_server_create(section, address, port, nas_identifier,
                                                                          secret, sockets, preference);
                if (!server)
                {
@@ -135,14 +131,53 @@ static bool load_servers(private_eap_radius_plugin_t *this)
        }
        enumerator->destroy(enumerator);
 
-       if (this->servers->get_count(this->servers) == 0)
-       {
-               DBG1(DBG_CFG, "no valid RADIUS server configuration found");
-               return FALSE;
-       }
+       DBG1(DBG_CFG, "loaded %d RADIUS server configuration%s",
+                this->servers->get_count(this->servers),
+                this->servers->get_count(this->servers) == 1 ? "" : "s");
+}
+
+METHOD(plugin_t, get_name, char*,
+       private_eap_radius_plugin_t *this)
+{
+       return "eap-radius";
+}
+
+METHOD(plugin_t, get_features, int,
+       eap_radius_plugin_t *this, plugin_feature_t *features[])
+{
+       static plugin_feature_t f[] = {
+               PLUGIN_CALLBACK(eap_method_register, eap_radius_create),
+                       PLUGIN_PROVIDE(EAP_SERVER, EAP_RADIUS),
+                               PLUGIN_DEPENDS(HASHER, HASH_MD5),
+                               PLUGIN_DEPENDS(SIGNER, AUTH_HMAC_MD5_128),
+                               PLUGIN_DEPENDS(RNG, RNG_WEAK),
+       };
+       *features = f;
+       return countof(f);
+}
+
+METHOD(plugin_t, reload, bool,
+       private_eap_radius_plugin_t *this)
+{
+       this->lock->write_lock(this->lock);
+       this->servers->destroy_offset(this->servers,
+                                                                 offsetof(radius_server_t, destroy));
+       this->servers = linked_list_create();
+       load_servers(this);
+       this->lock->unlock(this->lock);
        return TRUE;
 }
 
+METHOD(plugin_t, destroy, void,
+       private_eap_radius_plugin_t *this)
+{
+       this->servers->destroy_offset(this->servers,
+                                                                 offsetof(radius_server_t, destroy));
+       this->lock->destroy(this->lock);
+       free(this);
+       instance = NULL;
+}
+
 /*
  * see header file
  */
@@ -151,18 +186,19 @@ plugin_t *eap_radius_plugin_create()
        private_eap_radius_plugin_t *this;
 
        INIT(this,
-               .public.plugin.destroy = _destroy,
+               .public = {
+                       .plugin = {
+                               .get_name = _get_name,
+                               .get_features = _get_features,
+                               .reload = _reload,
+                               .destroy = _destroy,
+                       },
+               },
                .servers = linked_list_create(),
+               .lock = rwlock_create(RWLOCK_TYPE_DEFAULT),
        );
 
-       if (!load_servers(this))
-       {
-               destroy(this);
-               return NULL;
-       }
-       charon->eap->add_method(charon->eap, EAP_RADIUS, 0,
-                                                       EAP_SERVER, (eap_constructor_t)eap_radius_create);
-
+       load_servers(this);
        instance = this;
 
        return &this->public.plugin;
@@ -175,7 +211,10 @@ enumerator_t *eap_radius_create_server_enumerator()
 {
        if (instance)
        {
-               return instance->servers->create_enumerator(instance->servers);
+               instance->lock->read_lock(instance->lock);
+               return enumerator_create_cleaner(
+                                       instance->servers->create_enumerator(instance->servers),
+                                       (void*)instance->lock->unlock, instance->lock);
        }
        return enumerator_create_empty();
 }