diff options
Diffstat (limited to 'src/libcharon/plugins/tnccs_11/tnccs_11.c')
-rw-r--r-- | src/libcharon/plugins/tnccs_11/tnccs_11.c | 370 |
1 files changed, 186 insertions, 184 deletions
diff --git a/src/libcharon/plugins/tnccs_11/tnccs_11.c b/src/libcharon/plugins/tnccs_11/tnccs_11.c index b321c2671..ea185e782 100644 --- a/src/libcharon/plugins/tnccs_11/tnccs_11.c +++ b/src/libcharon/plugins/tnccs_11/tnccs_11.c @@ -14,81 +14,17 @@ */ #include "tnccs_11.h" - -#include <libtnctncc.h> -#include <libtnctncs.h> +#include "batch/tnccs_batch.h" +#include "messages/tnccs_msg.h" +#include "messages/imc_imv_msg.h" +#include "messages/tnccs_preferred_language_msg.h" #include <daemon.h> #include <debug.h> - -#define TNC_SEND_BUFFER_SIZE 32 - -static chunk_t tnc_send_buffer[TNC_SEND_BUFFER_SIZE]; - -/** - * Buffers TNCCS batch to be sent (TODO make the buffer scalable) - */ -static TNC_Result buffer_batch(u_int32_t id, const char *data, size_t len) -{ - if (id >= TNC_SEND_BUFFER_SIZE) - { - DBG1(DBG_TNC, "TNCCS Batch for Connection ID %u cannot be stored in " - "send buffer with size %d", id, TNC_SEND_BUFFER_SIZE); - return TNC_RESULT_FATAL; - } - if (tnc_send_buffer[id].ptr) - { - DBG1(DBG_TNC, "send buffer slot for Connection ID %u is already " - "occupied", id); - return TNC_RESULT_FATAL; - } - tnc_send_buffer[id] = chunk_alloc(len); - memcpy(tnc_send_buffer[id].ptr, data, len); - - return TNC_RESULT_SUCCESS; -} - -/** - * Retrieves TNCCS batch to be sent - */ -static bool retrieve_batch(u_int32_t id, chunk_t *batch) -{ - if (id >= TNC_SEND_BUFFER_SIZE) - { - DBG1(DBG_TNC, "TNCCS Batch for Connection ID %u cannot be retrieved from " - "send buffer with size %d", id, TNC_SEND_BUFFER_SIZE); - return FALSE; - } - - *batch = tnc_send_buffer[id]; - return TRUE; -} - -/** - * Frees TNCCS batch that was sent - */ -static void free_batch(u_int32_t id) -{ - if (id < TNC_SEND_BUFFER_SIZE) - { - chunk_free(&tnc_send_buffer[id]); - } -} - -/** - * Define callback functions called by the libtnc library - */ -TNC_Result TNC_TNCC_SendBatch(libtnc_tncc_connection* conn, - const char* messageBuffer, size_t messageLength) -{ - return buffer_batch(conn->connectionID, messageBuffer, messageLength); -} - -TNC_Result TNC_TNCS_SendBatch(libtnc_tncs_connection* conn, - const char* messageBuffer, size_t messageLength) -{ - return buffer_batch(conn->connectionID, messageBuffer, messageLength); -} +#include <threading/mutex.h> +#include <tnc/tncif.h> +#include <tnc/tncifimv_names.h> +#include <tnc/tnccs/tnccs.h> typedef struct private_tnccs_11_t private_tnccs_11_t; @@ -108,116 +44,219 @@ struct private_tnccs_11_t { bool is_server; /** - * TNCC Connection to IMCs + * Connection ID assigned to this TNCCS connection */ - libtnc_tncc_connection* tncc_connection; + TNC_ConnectionID connection_id; /** - * TNCS Connection to IMVs + * Last TNCCS batch ID */ - libtnc_tncs_connection* tncs_connection; + int batch_id; + + /** + * TNCCS batch being constructed + */ + tnccs_batch_t *batch; + + /** + * Mutex locking the batch in construction + */ + mutex_t *mutex; + + /** + * Flag set by IMC/IMV RequestHandshakeRetry() function + */ + bool request_handshake_retry; + + /** + * Set of IMV recommendations (TNC Server only) + */ + recommendations_t *recs; }; -METHOD(tls_t, process, status_t, - private_tnccs_11_t *this, void *buf, size_t buflen) +METHOD(tnccs_t, send_msg, void, + private_tnccs_11_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id, + TNC_BufferReference msg, + TNC_UInt32 msg_len, + TNC_MessageType msg_type) { - u_int32_t conn_id; + tnccs_msg_t *tnccs_msg; - if (this->is_server && !this->tncs_connection) + tnccs_msg = imc_imv_msg_create(msg_type, chunk_create(msg, msg_len)); + + /* adding an IMC-IMV Message to TNCCS batch */ + this->mutex->lock(this->mutex); + if (!this->batch) { - this->tncs_connection = libtnc_tncs_CreateConnection(NULL); - if (!this->tncs_connection) + this->batch = tnccs_batch_create(this->is_server, ++this->batch_id); + } + this->batch->add_msg(this->batch, tnccs_msg); + this->mutex->unlock(this->mutex); +} + +/** + * Handle a single TNCCS message according to its type + */ +static void handle_message(private_tnccs_11_t *this, tnccs_msg_t *msg) +{ + switch (msg->get_type(msg)) + { + case IMC_IMV_MSG: { - DBG1(DBG_TNC, "TNCS CreateConnection failed"); - return FAILED; + imc_imv_msg_t *imc_imv_msg; + TNC_MessageType msg_type; + chunk_t msg_body; + + imc_imv_msg = (imc_imv_msg_t*)msg; + msg_type = imc_imv_msg->get_msg_type(imc_imv_msg); + msg_body = imc_imv_msg->get_msg_body(imc_imv_msg); + + DBG2(DBG_TNC, "handling IMC_IMV message type 0x%08x", msg_type); + + if (this->is_server) + { + charon->imvs->receive_message(charon->imvs, + this->connection_id, msg_body.ptr, msg_body.len, msg_type); + } + else + { + charon->imcs->receive_message(charon->imcs, + this->connection_id, msg_body.ptr, msg_body.len,msg_type); + } + break; } - DBG1(DBG_TNC, "assigned TNCS Connection ID %u", - this->tncs_connection->connectionID); - if (libtnc_tncs_BeginSession(this->tncs_connection) != TNC_RESULT_SUCCESS) + case TNCCS_MSG_PREFERRED_LANGUAGE: { - DBG1(DBG_TNC, "TNCS BeginSession failed"); - return FAILED; + tnccs_preferred_language_msg_t *lang_msg; + char *lang; + + lang_msg = (tnccs_preferred_language_msg_t*)msg; + lang = lang_msg->get_preferred_language(lang_msg); + + DBG2(DBG_TNC, "setting preferred language to '%s'", lang); + this->recs->set_preferred_language(this->recs, + chunk_create(lang, strlen(lang))); + break; } + default: + break; } - conn_id = this->is_server ? this->tncs_connection->connectionID - : this->tncc_connection->connectionID; +} - DBG1(DBG_TNC, "received TNCCS Batch (%u bytes) for Connection ID %u", - buflen, conn_id); - DBG3(DBG_TNC, "%.*s", buflen, buf); +METHOD(tls_t, process, status_t, + private_tnccs_11_t *this, void *buf, size_t buflen) +{ + chunk_t data; + tnccs_batch_t *batch; + status_t status; - if (this->is_server) + if (this->is_server && !this->connection_id) { - if (libtnc_tncs_ReceiveBatch(this->tncs_connection, buf, buflen) != - TNC_RESULT_SUCCESS) + this->connection_id = charon->tnccs->create_connection(charon->tnccs, + (tnccs_t*)this, _send_msg, + &this->request_handshake_retry, &this->recs); + if (!this->connection_id) { - DBG1(DBG_TNC, "TNCS ReceiveBatch failed"); return FAILED; } + charon->imvs->notify_connection_change(charon->imvs, + this->connection_id, TNC_CONNECTION_STATE_CREATE); } - else + + data = chunk_create(buf, buflen); + DBG1(DBG_TNC, "received TNCCS Batch (%u bytes) for Connection ID %u", + data.len, this->connection_id); + DBG3(DBG_TNC, "%.*s", data.len, data.ptr); + batch = tnccs_batch_create_from_data(this->is_server, ++this->batch_id, data); + status = batch->process(batch); + + if (status != FAILED) { - if (libtnc_tncc_ReceiveBatch(this->tncc_connection, buf, buflen) != - TNC_RESULT_SUCCESS) + enumerator_t *enumerator; + tnccs_msg_t *msg; + + enumerator = batch->create_msg_enumerator(batch); + while (enumerator->enumerate(enumerator, &msg)) { - DBG1(DBG_TNC, "TNCC ReceiveBatch failed"); - return FAILED; + handle_message(this, msg); } + enumerator->destroy(enumerator); + } + batch->destroy(batch); + return NEED_MORE; } METHOD(tls_t, build, status_t, private_tnccs_11_t *this, void *buf, size_t *buflen, size_t *msglen) { - chunk_t batch; - u_int32_t conn_id; - size_t len; + status_t status; - if (!this->is_server && !this->tncc_connection) + /* Initialize the connection */ + if (!this->is_server && !this->connection_id) { - this->tncc_connection = libtnc_tncc_CreateConnection(NULL); - if (!this->tncc_connection) - { - DBG1(DBG_TNC, "TNCC CreateConnection failed"); - return FAILED; - } - DBG1(DBG_TNC, "assigned TNCC Connection ID %u", - this->tncc_connection->connectionID); - if (libtnc_tncc_BeginSession(this->tncc_connection) != TNC_RESULT_SUCCESS) + tnccs_msg_t *msg; + char *pref_lang; + + this->connection_id = charon->tnccs->create_connection(charon->tnccs, + (tnccs_t*)this, _send_msg, + &this->request_handshake_retry, NULL); + if (!this->connection_id) { - DBG1(DBG_TNC, "TNCC BeginSession failed"); return FAILED; } + + /* Create TNCCS-PreferredLanguage message */ + pref_lang = charon->imcs->get_preferred_language(charon->imcs); + msg = tnccs_preferred_language_msg_create(pref_lang); + this->mutex->lock(this->mutex); + this->batch = tnccs_batch_create(this->is_server, ++this->batch_id); + this->batch->add_msg(this->batch, msg); + this->mutex->unlock(this->mutex); + + charon->imcs->notify_connection_change(charon->imcs, + this->connection_id, TNC_CONNECTION_STATE_CREATE); + charon->imcs->notify_connection_change(charon->imcs, + this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE); + charon->imcs->begin_handshake(charon->imcs, this->connection_id); } - conn_id = this->is_server ? this->tncs_connection->connectionID - : this->tncc_connection->connectionID; - if (!retrieve_batch(conn_id, &batch)) - { - return FAILED; - } - len = *buflen; - len = min(len, batch.len); - *buflen = len; - if (msglen) - { - *msglen = batch.len; - } + /* Do not allow any asynchronous IMCs or IMVs to add additional messages */ + this->mutex->lock(this->mutex); - if (batch.len) + if (this->batch) { + chunk_t data; + + this->batch->build(this->batch); + data = this->batch->get_encoding(this->batch); DBG1(DBG_TNC, "sending TNCCS Batch (%d bytes) for Connection ID %u", - batch.len, conn_id); - DBG3(DBG_TNC, "%.*s", batch.len, batch.ptr); - memcpy(buf, batch.ptr, len); - free_batch(conn_id); - return ALREADY_DONE; + data.len, this->connection_id); + DBG3(DBG_TNC, "%.*s", data.len, data.ptr); + *msglen = data.len; + + if (data.len > *buflen) + { + DBG1(DBG_TNC, "fragmentation of TNCCS batch not supported yet"); + } + else + { + *buflen = data.len; + } + memcpy(buf, data.ptr, *buflen); + this->batch->destroy(this->batch); + this->batch = NULL; + status = ALREADY_DONE; } else { - return INVALID_STATE; + DBG1(DBG_TNC, "no TNCCS Batch to send"); + status = INVALID_STATE; } + this->mutex->unlock(this->mutex); + + return status; } METHOD(tls_t, is_server, bool, @@ -237,40 +276,13 @@ METHOD(tls_t, is_complete, bool, { TNC_IMV_Action_Recommendation rec; TNC_IMV_Evaluation_Result eval; - char *group; - identification_t *id; - ike_sa_t *ike_sa; - auth_cfg_t *auth; - - if (this->is_server && - libtnc_tncs_HaveRecommendation(this->tncs_connection, &rec, &eval) == - TNC_RESULT_SUCCESS) + + if (this->recs && this->recs->have_recommendation(this->recs, &rec, &eval)) { - switch (rec) - { - case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: - DBG1(DBG_TNC, "TNC recommendation is allow"); - group = "allow"; - break; - case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: - DBG1(DBG_TNC, "TNC recommendation is isolate"); - group = "isolate"; - break; - case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: - case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: - default: - DBG1(DBG_TNC, "TNC recommendation is none"); - return FALSE; - } - ike_sa = charon->bus->get_sa(charon->bus); - if (ike_sa) - { - auth = ike_sa->get_auth_cfg(ike_sa, FALSE); - id = identification_create_from_string(group); - auth->add(auth, AUTH_RULE_GROUP, id); - DBG1(DBG_TNC, "added group membership '%s' based on TNC recommendation", group); - } - return TRUE; + DBG2(DBG_TNC, "Final recommendation is '%N' and evaluation is '%N'", + action_recommendation_names, rec, evaluation_result_names, eval); + + return charon->imvs->enforce_recommendation(charon->imvs, rec); } else { @@ -287,20 +299,9 @@ METHOD(tls_t, get_eap_msk, chunk_t, METHOD(tls_t, destroy, void, private_tnccs_11_t *this) { - if (this->is_server) - { - if (this->tncs_connection) - { - libtnc_tncs_DeleteConnection(this->tncs_connection); - } - } - else - { - if (this->tncc_connection) - { - libtnc_tncc_DeleteConnection(this->tncc_connection); - } - } + charon->tnccs->remove_connection(charon->tnccs, this->connection_id); + this->mutex->destroy(this->mutex); + DESTROY_IF(this->batch); free(this); } @@ -322,6 +323,7 @@ tls_t *tnccs_11_create(bool is_server) .destroy = _destroy, }, .is_server = is_server, + .mutex = mutex_create(MUTEX_TYPE_DEFAULT), ); return &this->public; |