implemented RADIUS Filter-ID attribute
authorAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 13 Mar 2012 15:26:10 +0000 (16:26 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Tue, 13 Mar 2012 15:27:18 +0000 (16:27 +0100)
src/libcharon/plugins/tnc_pdp/tnc_pdp.c
src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.c
src/libcharon/plugins/tnc_pdp/tnc_pdp_connections.h
src/libradius/radius_message.h

index db1f4c7..1beeb8d 100644 (file)
@@ -181,10 +181,12 @@ static void send_message(private_tnc_pdp_t *this, radius_message_t *message,
  */
 static void send_response(private_tnc_pdp_t *this,
                                                  radius_message_t *request, radius_message_code_t code,
-                                                 eap_payload_t *eap, host_t *client)
+                                                 eap_payload_t *eap, identification_t *group,
+                                                 host_t *client)
 {
        radius_message_t *response;
        chunk_t data;
+       u_int32_t tunnel_type;
 
        response = radius_message_create(code);
        if (eap)
@@ -201,6 +203,14 @@ static void send_response(private_tnc_pdp_t *this,
                }
                response->add(response, RAT_EAP_MESSAGE, data);
        }
+       if (group)
+       {
+               tunnel_type = RADIUS_TUNNEL_TYPE_ESP;
+               htoun32(data.ptr, tunnel_type);
+               data.len = sizeof(tunnel_type);
+               response->add(response, RAT_TUNNEL_TYPE, data);
+               response->add(response, RAT_FILTER_ID, group->get_encoding(group));
+       }
        response->set_identifier(response, request->get_identifier(request));
        response->sign(response, request->get_authenticator(request),
                                   this->secret, this->hasher, this->signer, NULL, TRUE);
@@ -221,10 +231,11 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
        eap_payload_t *in, *out = NULL;
        eap_method_t *method;
        eap_type_t eap_type;
+       u_int32_t eap_vendor;
        chunk_t data, message = chunk_empty;
        chunk_t user_name = chunk_empty, nas_id = chunk_empty;
+       identification_t *group = NULL;
        radius_message_code_t code = RMC_ACCESS_CHALLENGE;
-       u_int32_t eap_vendor;
        int type;
 
        enumerator = request->create_enumerator(request);
@@ -258,7 +269,6 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
                eap_type = in->get_type(in, &eap_vendor);
 
                DBG3(DBG_CFG, "%N payload %B", eap_type_names, eap_type, &message);
-               free(message.ptr);
 
                if (eap_type == EAP_IDENTITY)
                {
@@ -267,30 +277,36 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
 
                        if (message.len < 5)
                        {
-                               return;
+                               goto end;
                        }
                        eap_identity = chunk_create(message.ptr + 5, message.len - 5);
                        peer = identification_create_from_data(eap_identity);
-
                        method = charon->eap->create_instance(charon->eap, this->type,
                                                                                0, EAP_SERVER, this->server, peer); 
-                       peer->destroy(peer);
                        if (!method)
                        {
-                               in->destroy(in);
-                               return;
+                               peer->destroy(peer);
+                               goto end;
                        }
-                       this->connections->add(this->connections, nas_id, user_name, method);
+                       this->connections->add(this->connections, nas_id, user_name, peer,
+                                                                  method);
                        method->initiate(method, &out);
                }
                else
                {
-                       method = this->connections->get_method(this->connections, nas_id,
-                                                                                                  user_name);
+                       ike_sa_t *ike_sa;
+                       auth_cfg_t *auth;
+                       auth_rule_t type;
+                       identification_t *data;
+                       enumerator_t *e;
+
+                       method = this->connections->get_state(this->connections, nas_id,
+                                                                                                 user_name, &ike_sa);
                        if (!method)
                        {
-                               return;
+                               goto end;
                        }
+                       charon->bus->set_sa(charon->bus, ike_sa);
 
                        switch (method->process(method, in, &out))
                        {
@@ -299,6 +315,19 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
                                        break;
                                case SUCCESS:
                                        code = RMC_ACCESS_ACCEPT;
+
+                                       auth = ike_sa->get_auth_cfg(ike_sa, FALSE);
+                                       e = auth->create_enumerator(auth);
+                                       while (e->enumerate(e, &type, &data))
+                                       {
+                                               /* look for group memberships */
+                                               if (type == AUTH_RULE_GROUP)
+                                               {
+                                                       group = data;
+                                               }
+                                       }
+                                       e->destroy(e);
+
                                        DESTROY_IF(out);
                                        out = eap_payload_create_code(EAP_SUCCESS,
                                                                                                  in->get_identifier(in));
@@ -310,16 +339,20 @@ static void process_eap(private_tnc_pdp_t *this, radius_message_t *request,
                                        out = eap_payload_create_code(EAP_FAILURE,
                                                                                                  in->get_identifier(in));
                        }
+                       charon->bus->set_sa(charon->bus, NULL);
                }
 
+               send_response(this, request, code, out, group, source);
+               out->destroy(out);
+
                if (code == RMC_ACCESS_ACCEPT || code == RMC_ACCESS_REJECT)
                {
                        this->connections->remove(this->connections, nas_id, user_name);
                }
 
-               send_response(this, request, code, out, source);
+end:
+               free(message.ptr);
                in->destroy(in);
-               out->destroy(out);
        }
 }
 
@@ -452,13 +485,12 @@ METHOD(tnc_pdp_t, destroy, void,
 tnc_pdp_t *tnc_pdp_create(u_int16_t port)
 {
        private_tnc_pdp_t *this;
-       char *secret, *server;
+       char *secret, *server, *eap_type_str;
 
        INIT(this,
                .public = {
                        .destroy = _destroy,
                },
-               .type = EAP_TTLS,
                .ipv4 = open_socket(this, AF_INET,  port),
                .ipv6 = open_socket(this, AF_INET6, port),
                .hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5),
@@ -507,6 +539,16 @@ tnc_pdp_t *tnc_pdp_create(u_int16_t port)
        this->secret = chunk_create(secret, strlen(secret));
        this->signer->set_key(this->signer, this->secret);
 
+       eap_type_str = lib->settings->get_str(lib->settings,
+                                               "charon.plugins.tnc-pdp.method", "ttls");
+       this->type = eap_type_from_string(eap_type_str);
+       if (this->type == 0)
+       {
+               DBG1(DBG_CFG, "unrecognized eap method \"%s\"", eap_type_str);
+               destroy(this);
+               return NULL;
+       }
+       DBG1(DBG_IKE, "eap method %N selected", eap_type_names, this->type);
 
        this->job = callback_job_create_with_prio((callback_job_cb_t)receive,
                                                                                this, NULL, NULL, JOB_PRIO_CRITICAL);
index 0271840..175a57a 100644 (file)
@@ -56,6 +56,11 @@ struct entry_t {
         * EAP method state
         */
        eap_method_t *method;
+
+       /**
+        * IKE SA used for bus communication
+        */
+       ike_sa_t *ike_sa;
 };
 
 /**
@@ -64,6 +69,7 @@ struct entry_t {
 static void free_entry(entry_t *this)
 {
        this->method->destroy(this->method);
+       this->ike_sa->destroy(this->ike_sa);
        free(this->nas_id.ptr);
        free(this->user_name.ptr);
        free(this);
@@ -100,12 +106,19 @@ static void dbg_nas_user(chunk_t nas_id, chunk_t user_name, bool not, char *op)
 
 METHOD(tnc_pdp_connections_t, add, void,
        private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
-       eap_method_t *method)
+       identification_t *peer, eap_method_t *method)
 {
        enumerator_t *enumerator;
        entry_t *entry;
+       ike_sa_id_t *ike_sa_id;
+       ike_sa_t *ike_sa;
        bool found = FALSE;
 
+       ike_sa_id = ike_sa_id_create(0, 0, FALSE);
+       ike_sa = ike_sa_create(ike_sa_id);
+       ike_sa_id->destroy(ike_sa_id);
+       ike_sa->set_other_id(ike_sa, peer);
+
        enumerator = this->list->create_enumerator(this->list);
        while (enumerator->enumerate(enumerator, &entry))
        {
@@ -113,8 +126,10 @@ METHOD(tnc_pdp_connections_t, add, void,
                {
                        found = TRUE;
                        entry->method->destroy(entry->method);
+                       entry->ike_sa->destroy(entry->ike_sa);
                        DBG1(DBG_CFG, "removed stale RADIUS connection");
                        entry->method = method;
+                       entry->ike_sa = ike_sa;
                        break;
                }
        }
@@ -126,6 +141,7 @@ METHOD(tnc_pdp_connections_t, add, void,
                entry->nas_id = chunk_clone(nas_id);
                entry->user_name = chunk_clone(user_name);
                entry->method = method;
+               entry->ike_sa = ike_sa;
                this->list->insert_last(this->list, entry);
        }
        dbg_nas_user(nas_id, user_name, FALSE, "created");
@@ -151,8 +167,9 @@ METHOD(tnc_pdp_connections_t, remove_, void,
        enumerator->destroy(enumerator);
 }
 
-METHOD(tnc_pdp_connections_t, get_method, eap_method_t*,
-       private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name)
+METHOD(tnc_pdp_connections_t, get_state, eap_method_t*,
+       private_tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
+       ike_sa_t **ike_sa)
 {
        enumerator_t *enumerator;
        entry_t *entry;
@@ -164,6 +181,7 @@ METHOD(tnc_pdp_connections_t, get_method, eap_method_t*,
                if (equals_entry(entry, nas_id, user_name))
                {
                        found = entry->method;
+                       *ike_sa = entry->ike_sa;
                        break;
                }
        }
@@ -191,7 +209,7 @@ tnc_pdp_connections_t *tnc_pdp_connections_create(void)
                .public = {
                        .add = _add,
                        .remove = _remove_,
-                       .get_method = _get_method,
+                       .get_state = _get_state,
                        .destroy = _destroy,
                },
                .list = linked_list_create(),
index 6526897..b9f5d09 100644 (file)
@@ -24,6 +24,7 @@
 typedef struct tnc_pdp_connections_t tnc_pdp_connections_t;
 
 #include <library.h>
+#include <sa/ike_sa.h>
 #include <sa/authenticators/eap/eap_method.h>
 
 /**
@@ -36,10 +37,11 @@ struct tnc_pdp_connections_t {
         *
         * @param nas_id                NAS identifier of Policy Enforcement Point
         * @param user_name             User name of TNC Client
+        * @param peer                  Peer identity
         * @param method                EAP method state for this TNC PEP Connection
         */
        void (*add)(tnc_pdp_connections_t *this, chunk_t nas_id, chunk_t user_name,
-                               eap_method_t *method);
+                               identification_t *peer, eap_method_t *method);
 
        /**
         * Remove a TNC PEP RADIUS Connection
@@ -51,14 +53,15 @@ struct tnc_pdp_connections_t {
                                   chunk_t user_name);
 
        /**
-        * Get the EAP method of a registered TNC PEP RADIUS Connection
+        * Get the EAP method and IKE_SA of a registered TNC PEP RADIUS Connection
         *
         * @param nas_id                NAS identifier of Policy Enforcement Point
         * @param user_name             User name of TNC Client
+        * @param ike_sa                IKE_SA used for bus communication only
         * @return                              EAP method for this connection or NULL if not found
         */
-       eap_method_t* (*get_method)(tnc_pdp_connections_t *this, chunk_t nas_id,
-                                                               chunk_t user_name);
+       eap_method_t* (*get_state)(tnc_pdp_connections_t *this, chunk_t nas_id,
+                                                          chunk_t user_name, ike_sa_t **ike_sa);
 
        /**
         * Destroys a tnc_pdp_connections_t object.
index 55cb484..90698ae 100644 (file)
@@ -30,6 +30,8 @@
 
 #define MAX_RADIUS_ATTRIBUTE_SIZE      253
 
+#define RADIUS_TUNNEL_TYPE_ESP         9
+
 typedef struct radius_message_t radius_message_t;
 typedef enum radius_message_code_t radius_message_code_t;
 typedef enum radius_attribute_type_t radius_attribute_type_t;