]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
Resolve and connect to RADIUS servers not before required
authorMartin Willi <martin@revosec.ch>
Thu, 21 Apr 2011 09:40:25 +0000 (11:40 +0200)
committerMartin Willi <martin@revosec.ch>
Thu, 21 Apr 2011 12:01:25 +0000 (14:01 +0200)
src/libcharon/plugins/eap_radius/eap_radius_plugin.c
src/libcharon/plugins/eap_radius/radius_client.c
src/libcharon/plugins/eap_radius/radius_server.c
src/libcharon/plugins/eap_radius/radius_server.h
src/libcharon/plugins/eap_radius/radius_socket.c
src/libcharon/plugins/eap_radius/radius_socket.h
src/libcharon/sa/authenticators/eap_authenticator.c

index 9b1525662783a9888094e4012a8892d24633e55e..c218bd48b68209778de8cecd4e9a1ce6cb4c8f49 100644 (file)
@@ -82,7 +82,7 @@ static void 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)
                {
@@ -120,7 +120,7 @@ static void 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)
                {
index 0d7276af439fdd9630413d7bf6755a47c409a83f..245308e5948b824bcb450ed6d605621baf6fc284 100644 (file)
@@ -98,13 +98,14 @@ METHOD(radius_client_t, request, radius_message_t*,
                req->add(req, RAT_STATE, this->state);
        }
        socket = this->server->get_socket(this->server);
-       DBG1(DBG_CFG, "sending RADIUS %N to %#H", radius_message_code_names,
-                req->get_code(req), this->server->get_address(this->server));
+       DBG1(DBG_CFG, "sending RADIUS %N to server '%s'", radius_message_code_names,
+                req->get_code(req), this->server->get_name(this->server));
        res = socket->request(socket, req);
        if (res)
        {
-               DBG1(DBG_CFG, "received RADIUS %N from %#H", radius_message_code_names,
-                        res->get_code(res), this->server->get_address(this->server));
+               DBG1(DBG_CFG, "received RADIUS %N from server '%s'",
+                        radius_message_code_names, res->get_code(res),
+                        this->server->get_name(this->server));
                save_state(this, res);
                if (res->get_code(res) == RMC_ACCESS_ACCEPT)
                {
@@ -160,16 +161,16 @@ radius_client_t *radius_client_create()
                        /* for two with equal preference, 50-50 chance */
                        (current == best && random() % 2 == 0))
                {
-                       DBG2(DBG_CFG, "RADIUS server %H is candidate: %d",
-                                server->get_address(server), current);
+                       DBG2(DBG_CFG, "RADIUS server '%s' is candidate: %d",
+                                server->get_name(server), current);
                        best = current;
                        DESTROY_IF(this->server);
                        this->server = server->get_ref(server);
                }
                else
                {
-                       DBG2(DBG_CFG, "RADIUS server %H skipped: %d",
-                                server->get_address(server), current);
+                       DBG2(DBG_CFG, "RADIUS server '%s' skipped: %d",
+                                server->get_name(server), current);
                }
        }
        enumerator->destroy(enumerator);
index 37a2d331ecc9036ebc85be9ab1dca383ad35700f..3baf398070fcf2b81bdd159c46e12de10780e81b 100644 (file)
@@ -31,11 +31,6 @@ struct private_radius_server_t {
         */
        radius_server_t public;
 
-       /**
-        * RADIUS server address
-        */
-       host_t *host;
-
        /**
         * list of radius sockets, as radius_socket_t
         */
@@ -57,9 +52,9 @@ struct private_radius_server_t {
        condvar_t *condvar;
 
        /**
-        * RADIUS secret
+        * Server name
         */
-       chunk_t secret;
+       char *name;
 
        /**
         * NAS-Identifier
@@ -152,10 +147,10 @@ METHOD(radius_server_t, get_preference, int,
        return pref;
 }
 
-METHOD(radius_server_t, get_address, host_t*,
+METHOD(radius_server_t, get_name, char*,
        private_radius_server_t *this)
 {
-       return this->host;
+       return this->name;
 }
 
 METHOD(radius_server_t, get_ref, radius_server_t*,
@@ -171,12 +166,10 @@ METHOD(radius_server_t, destroy, void,
 {
        if (ref_put(&this->ref))
        {
-               DESTROY_IF(this->host);
                this->mutex->destroy(this->mutex);
                this->condvar->destroy(this->condvar);
                this->sockets->destroy_offset(this->sockets,
                                                                          offsetof(radius_socket_t, destroy));
-               free(this->nas_identifier.ptr);
                free(this);
        }
 }
@@ -184,7 +177,7 @@ METHOD(radius_server_t, destroy, void,
 /**
  * See header
  */
-radius_server_t *radius_server_create(char *server, u_int16_t port,
+radius_server_t *radius_server_create(char *name, char *address, u_int16_t port,
                                char *nas_identifier, char *secret, int sockets, int preference)
 {
        private_radius_server_t *this;
@@ -196,7 +189,7 @@ radius_server_t *radius_server_create(char *server, u_int16_t port,
                        .put_socket = _put_socket,
                        .get_nas_identifier = _get_nas_identifier,
                        .get_preference = _get_preference,
-                       .get_address = _get_address,
+                       .get_name = _get_name,
                        .get_ref = _get_ref,
                        .destroy = _destroy,
                },
@@ -206,19 +199,14 @@ radius_server_t *radius_server_create(char *server, u_int16_t port,
                .sockets = linked_list_create(),
                .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
                .condvar = condvar_create(CONDVAR_TYPE_DEFAULT),
-               .host = host_create_from_dns(server, 0, port),
+               .name = name,
                .preference = preference,
                .ref = 1,
        );
 
-       if (!this->host)
-       {
-               destroy(this);
-               return NULL;
-       }
        while (sockets--)
        {
-               socket = radius_socket_create(this->host,
+               socket = radius_socket_create(address, port,
                                                                          chunk_create(secret, strlen(secret)));
                if (!socket)
                {
index a9bc721808285710350539f8d3625f3d0a6fc278..c59361c491368a92569aeca3f374a526eb1f19d7 100644 (file)
@@ -61,11 +61,11 @@ struct radius_server_t {
        int (*get_preference)(radius_server_t *this);
 
        /**
-        * Get the address of the RADIUS server.
+        * Get the name of the RADIUS server.
         *
-        * @return                      address, internal data
+        * @return                      server name
         */
-       host_t* (*get_address)(radius_server_t *this);
+       char* (*get_name)(radius_server_t *this);
 
        /**
         * Increase reference count of this server.
@@ -83,14 +83,15 @@ struct radius_server_t {
 /**
  * Create a radius_server instance.
  *
- * @param server                       server address
+ * @param name                         server name
+ * @param address                      server address
  * @param port                         server port
  * @param nas_identifier       NAS-Identifier to use with this server
  * @param secret                       secret to use with this server
  * @param sockets                      number of sockets to create in pool
  * @param preference           preference boost for this server
  */
-radius_server_t *radius_server_create(char *server, u_int16_t port,
+radius_server_t *radius_server_create(char *name, char *address, u_int16_t port,
                        char *nas_identifier, char *secret, int sockets, int preference);
 
 #endif /** RADIUS_SERVER_H_ @}*/
index 76993e75607ccaf57c1f26ed54b87ae4919308db..b3229c28872cd3ce33e946ee47326f3c9c59bf21 100644 (file)
@@ -48,6 +48,16 @@ struct private_radius_socket_t {
         */
        int fd;
 
+       /**
+        * Server address
+        */
+       char *address;
+
+       /**
+        * Server port
+        */
+       u_int16_t port;
+
        /**
         * current RADIUS identifier
         */
@@ -74,6 +84,45 @@ struct private_radius_socket_t {
        chunk_t secret;
 };
 
+/**
+ * Check or establish RADIUS connection
+ */
+static bool check_connection(private_radius_socket_t *this)
+{
+       if (this->fd == -1)
+       {
+               host_t *server;
+
+               server = host_create_from_dns(this->address, AF_UNSPEC, this->port);
+               if (!server)
+               {
+                       DBG1(DBG_CFG, "resolving RADIUS server address '%s' failed",
+                                this->address);
+                       return FALSE;
+               }
+               this->fd = socket(server->get_family(server), SOCK_DGRAM, IPPROTO_UDP);
+               if (this->fd == -1)
+               {
+                       DBG1(DBG_CFG, "opening RADIUS socket for %#H failed: %s",
+                                server, strerror(errno));
+                       server->destroy(server);
+                       return FALSE;
+               }
+               if (connect(this->fd, server->get_sockaddr(server),
+                                       *server->get_sockaddr_len(server)) < 0)
+               {
+                       DBG1(DBG_CFG, "connecting RADIUS socket to %#H failed: %s",
+                                server, strerror(errno));
+                       server->destroy(server);
+                       close(this->fd);
+                       this->fd = -1;
+                       return FALSE;
+               }
+               server->destroy(server);
+       }
+       return TRUE;
+}
+
 METHOD(radius_socket_t, request, radius_message_t*,
        private_radius_socket_t *this, radius_message_t *request)
 {
@@ -85,6 +134,11 @@ METHOD(radius_socket_t, request, radius_message_t*,
        /* sign the request */
        request->sign(request, this->rng, this->signer);
 
+       if (!check_connection(this))
+       {
+               return NULL;
+       }
+
        data = request->get_encoding(request);
        /* timeout after 2, 3, 4, 5 seconds */
        for (i = 2; i <= 5; i++)
@@ -257,15 +311,18 @@ METHOD(radius_socket_t, destroy, void,
        DESTROY_IF(this->hasher);
        DESTROY_IF(this->signer);
        DESTROY_IF(this->rng);
-       chunk_clear(&this->secret);
-       close(this->fd);
+       if (this->fd != -1)
+       {
+               close(this->fd);
+       }
        free(this);
 }
 
 /**
  * See header
  */
-radius_socket_t *radius_socket_create(host_t *host, chunk_t secret)
+radius_socket_t *radius_socket_create(char *address, u_int16_t port,
+                                                                         chunk_t secret)
 {
        private_radius_socket_t *this;
 
@@ -275,23 +332,11 @@ radius_socket_t *radius_socket_create(host_t *host, chunk_t secret)
                        .decrypt_msk = _decrypt_msk,
                        .destroy = _destroy,
                },
+               .address = address,
+               .port = port,
+               .fd = -1,
        );
 
-       this->fd = socket(host->get_family(host), SOCK_DGRAM, IPPROTO_UDP);
-       if (this->fd < 0)
-       {
-               DBG1(DBG_CFG, "opening RADIUS socket failed: %s", strerror(errno));
-               free(this);
-               return NULL;
-       }
-       if (connect(this->fd, host->get_sockaddr(host),
-                               *host->get_sockaddr_len(host)) < 0)
-       {
-               DBG1(DBG_CFG, "connecting RADIUS socket failed");
-               close(this->fd);
-               free(this);
-               return NULL;
-       }
        this->hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5);
        this->signer = lib->crypto->create_signer(lib->crypto, AUTH_HMAC_MD5_128);
        this->rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
index fe8491a8feb3feab22923e46e10467781adff8fc..2875008eb13b88f2c2814b0603495b223e6fa0ee 100644 (file)
@@ -34,7 +34,7 @@ struct radius_socket_t {
 
        /**
         * Send a RADIUS request, wait for response.
-
+        *
         * The socket fills in RADIUS Message identifier, builds a
         * Request-Authenticator and calculates the Message-Authenticator
         * attribute.
@@ -66,9 +66,11 @@ struct radius_socket_t {
 /**
  * Create a radius_socket instance.
  *
- * @param host         RADIUS server address to connect to
+ * @param address      server name
+ * @param port         server port
  * @param secret       RADIUS secret
  */
-radius_socket_t *radius_socket_create(host_t *host, chunk_t secret);
+radius_socket_t *radius_socket_create(char *address, u_int16_t port,
+                                                                         chunk_t secret);
 
 #endif /** RADIUS_SOCKET_H_ @}*/
index 6cae0034b5efb4ad6b365472737379d86f046d91..d442acb00d97fdb1e8ded00672586edf1f07f6f6 100644 (file)
@@ -183,6 +183,7 @@ static eap_payload_t* server_initiate_eap(private_eap_authenticator_t *this,
        if (this->method)
        {
                action = "initiating";
+               type = this->method->get_type(this->method, &vendor);
                if (this->method->initiate(this->method, &out) == NEED_MORE)
                {
                        if (vendor)