summaryrefslogtreecommitdiffstats
path: root/src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c')
-rw-r--r--src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c357
1 files changed, 357 insertions, 0 deletions
diff --git a/src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c b/src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c
new file mode 100644
index 0000000..a1fdbc0
--- /dev/null
+++ b/src/modules/rlm_eap/types/rlm_eap_tnc/rlm_eap_tnc.c
@@ -0,0 +1,357 @@
+/*
+ * Portions of this code unrelated to FreeRADIUS are available
+ * separately under a commercial license. If you require an
+ * implementation of EAP-TNC that is not under the GPLv2, please
+ * contact trust@f4-i.fh-hannover.de for details.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ *
+ */
+
+/**
+ * $Id$
+ * @file rlm_eap_tnc.c
+ * @brief Interfaces with the naeap library to provide EAP-TNC inner method.
+ *
+ * @copyright 2013 The FreeRADIUS project
+ * @copyright 2007 Alan DeKok <aland@deployingradius.com>
+ * @copyright 2006-2009 FH Hannover
+ */
+
+/*
+ * EAP-TNC Packet with EAP Header, general structure
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Flags | Ver | Data Length |
+ * | |L M S R R| =1 | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Data Length | Data ...
+ * | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <freeradius-devel/rad_assert.h>
+
+#include "eap.h"
+#include <naaeap/naaeap.h>
+#include <netinet/in.h>
+
+#define VERSION "0.7.0"
+#define SET_START(x) ((x) | (0x20))
+
+typedef struct rlm_eap_tnc {
+ char const *connection_string;
+} rlm_eap_tnc_t;
+
+static CONF_PARSER module_config[] = {
+ { "connection_string", FR_CONF_OFFSET(PW_TYPE_STRING | PW_TYPE_XLAT, rlm_eap_tnc_t, connection_string), "NAS Port: %{NAS-Port} NAS IP: %{NAS-IP-Address} NAS_PORT_TYPE: %{NAS-Port-Type}" },
+ CONF_PARSER_TERMINATOR
+};
+
+static int mod_instantiate(CONF_SECTION *cs, void **instance)
+{
+ rlm_eap_tnc_t *inst;
+ TNC_Result result;
+
+ *instance = inst = talloc_zero(cs, rlm_eap_tnc_t);
+ if (!inst) return -1;
+
+ /*
+ * Parse the configuration attributes.
+ */
+ if (cf_section_parse(cs, inst, module_config) < 0) {
+ return -1;
+ }
+
+ result = initializeDefault();
+ if (result != TNC_RESULT_SUCCESS) {
+ ERROR("rlm_eap_tnc: NAA-EAP initializeDefault returned an "
+ "error code");
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mod_detach(void *instance)
+{
+ TNC_Result result;
+
+ talloc_free(instance);
+
+ result = terminate();
+ if (result != TNC_RESULT_SUCCESS) {
+ ERROR("rlm_eap_tnc: NAA-EAP terminate returned an "
+ "error code whilst detaching");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * This function is called when the first EAP_IDENTITY_RESPONSE message
+ * was received.
+ *
+ * Initiates the EPA_TNC session by sending the first EAP_TNC_RESPONSE
+ * to the peer. The packet has the Start-Bit set and contains no data.
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Code | Identifier | Length |
+ * | | | |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Type | Flags | Ver |
+ * | |0 0 1 0 0|0 0 1|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ * For this package, only 'Identifier' has to be set dynamically. Any
+ * other information is static.
+ */
+static int mod_session_init(void *instance, eap_handler_t *handler)
+{
+ rlm_eap_tnc_t *inst = instance;
+ REQUEST *request = NULL;
+
+ char buff[71];
+ ssize_t len = 0;
+
+ TNC_Result result;
+ TNC_ConnectionID conn_id;
+
+ TNC_BufferReference eap_tnc_request;
+ TNC_BufferReference eap_tnc_user;
+
+ VALUE_PAIR *username;
+
+ /*
+ * Check if we run inside a secure EAP method.
+ * FIXME check concrete outer EAP method.
+ */
+ if (!handler->request || !handler->request->parent) {
+ ERROR("rlm_eap_tnc: EAP_TNC must only be used as an "
+ "inner method within a protected tunneled EAP created "
+ "by an outer EAP method");
+
+ return 0;
+ }
+
+ request = handler->request->parent;
+
+ /*
+ * Build the connection string
+ */
+ len = radius_xlat(buff, sizeof(buff), request, inst->connection_string, NULL, NULL);
+ if (len < 0){
+ return 0;
+ }
+
+ RDEBUG("Getting connection from NAA-EAP");
+
+ /*
+ * Get connection (uses a function from the NAA-EAP-library)
+ */
+ result = getConnection(buff, &conn_id);
+ if (result != TNC_RESULT_SUCCESS) {
+ ERROR("rlm_eap_tnc: NAA-EAP getConnection returned an "
+ "error code");
+
+ return 0;
+ }
+
+ /*
+ * Previous code manually parsed the EAP identity response
+ * this was wrong. rlm_eap will *always* create the Username
+ * from the EAP Identity response.
+ *
+ * Something has gone very wrong if the User-Name doesn't exist.
+ */
+ username = fr_pair_find_by_num(request->packet->vps, PW_USER_NAME, 0, TAG_ANY);
+
+ RDEBUG("Username for TNC connection: %s", username->vp_strvalue);
+
+ /*
+ * Stores the username associated with the connection
+ *
+ * What becomes of username? Who knows... but we don't free it
+ * so not safe to use talloc.
+ */
+ MEM(eap_tnc_user = (TNC_BufferReference) strdup(username->vp_strvalue));
+
+ result = storeUsername(conn_id, eap_tnc_user, username->vp_length);
+ if (result != TNC_RESULT_SUCCESS) {
+ ERROR("rlm_eap_tnc: NAA-EAP storeUsername returned an "
+ "error code");
+
+ return 0;
+ }
+
+ /*
+ * Set connection ID
+ */
+ handler->opaque = talloc(handler, TNC_ConnectionID);
+ memcpy(handler->opaque, &conn_id, sizeof(TNC_ConnectionID));
+
+ /*
+ * Bild first EAP TNC request
+ */
+
+ MEM(eap_tnc_request = talloc_array(handler->eap_ds->request, uint8_t, 1));
+ *eap_tnc_request = SET_START(1);
+
+ handler->eap_ds->request->code = PW_EAP_REQUEST;
+ handler->eap_ds->request->type.num = PW_EAP_TNC;
+
+ handler->eap_ds->request->type.length = 1;
+
+ talloc_free(handler->eap_ds->request->type.data);
+ handler->eap_ds->request->type.data = eap_tnc_request;
+
+ /*
+ * We don't need to authorize the user at this point.
+ *
+ * We also don't need to keep the challenge, as it's
+ * stored in 'handler->eap_ds', which will be given back
+ * to us...
+ */
+ handler->stage = PROCESS;
+
+ return 1;
+}
+
+/**
+ * This function is called when a EAP_TNC_RESPONSE was received.
+ * It basically forwards the EAP_TNC data to NAA-TNCS and forms
+ * and appropriate EAP_RESPONSE. Furthermore, it sets the VlanID
+ * based on the TNC_ConnectionState determined by NAA-TNCS.
+ *
+ * @param instance The configuration data.
+ * @param handler The eap_handler_t.
+ * @return True, if successfully, else false.
+ */
+static int mod_process(UNUSED void *instance, eap_handler_t *handler)
+{
+ TNC_ConnectionID conn_id;
+ TNC_Result result;
+
+ TNC_BufferReference data = NULL;
+ TNC_UInt32 datalen = 0;
+
+ TNC_ConnectionState connection_state;
+ uint8_t code = 0;
+ REQUEST *request = handler->request;
+
+ if (handler->eap_ds->response->type.num != PW_EAP_TNC) {
+ ERROR("rlm_eap_tnc: Incorrect response type");
+
+ return 0;
+ }
+
+ /*
+ * Retrieve connection ID
+ */
+ conn_id = *((TNC_ConnectionID *) (handler->opaque));
+
+ RDEBUG2("Starting authentication for connection ID %lX",
+ conn_id);
+
+ /*
+ * Pass EAP_TNC data to NAA-EAP and get answer data
+ */
+ connection_state = TNC_CONNECTION_STATE_CREATE;
+
+ /*
+ * Forwards the eap_tnc data to NAA-EAP and gets the response
+ */
+ result = processEAPTNCData(conn_id, handler->eap_ds->response->type.data,
+ handler->eap_ds->response->type.length,
+ &data, &datalen, &connection_state);
+ if (result != TNC_RESULT_SUCCESS) {
+ RDEBUG("NAA-EAP processEAPTNCData returned "
+ "an error code");
+
+ return 0;
+ }
+ /*
+ * Determine eap code for the response
+ */
+ switch (connection_state) {
+ case TNC_CONNECTION_STATE_HANDSHAKE:
+ code = PW_EAP_REQUEST;
+ break;
+
+ case TNC_CONNECTION_STATE_ACCESS_NONE:
+ code = PW_EAP_FAILURE;
+ pair_make_config("TNC-Status", "None", T_OP_SET);
+ break;
+
+ case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
+ code = PW_EAP_SUCCESS;
+ pair_make_config("TNC-Status", "Access", T_OP_SET);
+ break;
+
+ case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
+ code = PW_EAP_SUCCESS;
+ pair_make_config("TNC-Status", "Isolate", T_OP_SET);
+ break;
+
+ default:
+ ERROR("rlm_eap_tnc: Invalid connection state");
+ return 0;
+ }
+
+ /*
+ * Build the TNC EAP request
+ */
+ handler->eap_ds->request->code = code;
+ handler->eap_ds->request->type.num = PW_EAP_TNC;
+
+ handler->eap_ds->request->type.length = datalen;
+
+ talloc_free(handler->eap_ds->request->type.data);
+
+ /*
+ * "data" is not talloc'd memory.
+ */
+ handler->eap_ds->request->type.data = talloc_array(handler->eap_ds->request,
+ uint8_t, datalen);
+ memcpy(handler->eap_ds->request->type.data, data, datalen);
+ free(data);
+
+ return 1;
+}
+
+/*
+ * The module name should be the only globally exported symbol.
+ * That is, everything else should be 'static'.
+ */
+extern rlm_eap_module_t rlm_eap_tnc;
+rlm_eap_module_t rlm_eap_tnc = {
+ .name = "eap_tnc",
+ .instantiate = mod_instantiate, /* Create new submodule instance */
+ .session_init = mod_session_init, /* Initialise a new EAP session */
+ .process = mod_process, /* Process next round of EAP method */
+ .detach = mod_detach /* detach */
+};