summaryrefslogtreecommitdiff
path: root/src/libcharon/plugins/tnccs_20/tnccs_20.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/plugins/tnccs_20/tnccs_20.c')
-rw-r--r--src/libcharon/plugins/tnccs_20/tnccs_20.c226
1 files changed, 151 insertions, 75 deletions
diff --git a/src/libcharon/plugins/tnccs_20/tnccs_20.c b/src/libcharon/plugins/tnccs_20/tnccs_20.c
index 606fc529b..44e1d278f 100644
--- a/src/libcharon/plugins/tnccs_20/tnccs_20.c
+++ b/src/libcharon/plugins/tnccs_20/tnccs_20.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 Sansar Choinyanbuu
- * Copyright (C) 2010-2011 Andreas Steffen
+ * Copyright (C) 2010-2012 Andreas Steffen
* HSR Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -35,7 +35,9 @@
#include <tnc/imv/imv_manager.h>
#include <debug.h>
+#include <daemon.h>
#include <threading/mutex.h>
+#include <utils/linked_list.h>
#include <pen/pen.h>
typedef struct private_tnccs_20_t private_tnccs_20_t;
@@ -66,9 +68,24 @@ struct private_tnccs_20_t {
TNC_ConnectionID connection_id;
/**
- * PB-TNC batch being constructed
+ * PB-TNC messages to be sent
*/
- pb_tnc_batch_t *batch;
+ linked_list_t *messages;
+
+ /**
+ * Type of PB-TNC batch being constructed
+ */
+ pb_tnc_batch_type_t batch_type;
+
+ /**
+ * Maximum PB-TNC batch size
+ */
+ size_t max_batch_len;
+
+ /**
+ * Maximum PA-TNC message size
+ */
+ size_t max_msg_len;
/**
* Mutex locking the batch in construction
@@ -97,6 +114,30 @@ struct private_tnccs_20_t {
};
+/**
+ * If the batch type changes then delete all accumulated PB-TNC messages
+ */
+void change_batch_type(private_tnccs_20_t *this, pb_tnc_batch_type_t batch_type)
+{
+ pb_tnc_msg_t *msg;
+
+ if (batch_type != this->batch_type)
+ {
+ if (this->batch_type != PB_BATCH_NONE)
+ {
+ DBG1(DBG_TNC, "cancelling PB-TNC %N batch",
+ pb_tnc_batch_type_names, this->batch_type);
+
+ while (this->messages->remove_last(this->messages,
+ (void**)&msg) == SUCCESS)
+ {
+ msg->destroy(msg);
+ }
+ }
+ this->batch_type = batch_type;
+ }
+}
+
METHOD(tnccs_t, send_msg, TNC_Result,
private_tnccs_20_t* this, TNC_IMCID imc_id, TNC_IMVID imv_id,
TNC_UInt32 msg_flags,
@@ -138,13 +179,13 @@ METHOD(tnccs_t, send_msg, TNC_Result,
/* adding PA message to SDATA or CDATA batch only */
batch_type = this->is_server ? PB_BATCH_SDATA : PB_BATCH_CDATA;
this->mutex->lock(this->mutex);
- if (!this->batch)
+ if (this->batch_type == PB_BATCH_NONE)
{
- this->batch = pb_tnc_batch_create(this->is_server, batch_type);
+ this->batch_type = batch_type;
}
- if (this->batch->get_type(this->batch) == batch_type)
+ if (this->batch_type == batch_type)
{
- this->batch->add_msg(this->batch, pb_tnc_msg);
+ this->messages->insert_last(this->messages, pb_tnc_msg);
}
else
{
@@ -167,30 +208,31 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg)
case PB_MSG_PA:
{
pb_pa_msg_t *pa_msg;
- u_int32_t msg_vid, msg_subtype;
+ pen_type_t msg_subtype;
u_int16_t imc_id, imv_id;
chunk_t msg_body;
bool excl;
enum_name_t *pa_subtype_names;
pa_msg = (pb_pa_msg_t*)msg;
- msg_vid = pa_msg->get_vendor_id(pa_msg, &msg_subtype);
+ msg_subtype = pa_msg->get_subtype(pa_msg);
msg_body = pa_msg->get_body(pa_msg);
imc_id = pa_msg->get_collector_id(pa_msg);
imv_id = pa_msg->get_validator_id(pa_msg);
excl = pa_msg->get_exclusive_flag(pa_msg);
- pa_subtype_names = get_pa_subtype_names(msg_vid);
+ pa_subtype_names = get_pa_subtype_names(msg_subtype.vendor_id);
if (pa_subtype_names)
{
DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x",
- pen_names, msg_vid, pa_subtype_names, msg_subtype,
- msg_vid, msg_subtype);
+ pen_names, msg_subtype.vendor_id, pa_subtype_names,
+ msg_subtype.type, msg_subtype.vendor_id, msg_subtype.type);
}
else
{
DBG2(DBG_TNC, "handling PB-PA message type '%N' 0x%06x/0x%08x",
- pen_names, msg_vid, msg_vid, msg_subtype);
+ pen_names, msg_subtype.vendor_id, msg_subtype.vendor_id,
+ msg_subtype.type);
}
this->send_msg = TRUE;
@@ -198,13 +240,15 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg)
{
tnc->imvs->receive_message(tnc->imvs, this->connection_id,
excl, msg_body.ptr, msg_body.len,
- msg_vid, msg_subtype, imc_id, imv_id);
+ msg_subtype.vendor_id,
+ msg_subtype.type, imc_id, imv_id);
}
else
{
tnc->imcs->receive_message(tnc->imcs, this->connection_id,
excl, msg_body.ptr, msg_body.len,
- msg_vid, msg_subtype, imv_id, imc_id);
+ msg_subtype.vendor_id,
+ msg_subtype.type, imv_id, imc_id);
}
this->send_msg = FALSE;
break;
@@ -313,7 +357,7 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg)
lang = lang_msg->get_language_preference(lang_msg);
DBG2(DBG_TNC, "setting language preference to '%.*s'",
- lang.len, lang.ptr);
+ (int)lang.len, lang.ptr);
this->recs->set_preferred_language(this->recs, lang);
break;
}
@@ -325,9 +369,9 @@ static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg)
reason_msg = (pb_reason_string_msg_t*)msg;
reason_string = reason_msg->get_reason_string(reason_msg);
language_code = reason_msg->get_language_code(reason_msg);
- DBG2(DBG_TNC, "reason string is '%.*s'", reason_string.len,
+ DBG2(DBG_TNC, "reason string is '%.*s'", (int)reason_string.len,
reason_string.ptr);
- DBG2(DBG_TNC, "language code is '%.*s'", language_code.len,
+ DBG2(DBG_TNC, "language code is '%.*s'", (int)language_code.len,
language_code.ptr);
break;
}
@@ -344,23 +388,20 @@ static void build_retry_batch(private_tnccs_20_t *this)
pb_tnc_batch_type_t batch_retry_type;
batch_retry_type = this->is_server ? PB_BATCH_SRETRY : PB_BATCH_CRETRY;
- if (this->batch)
+ if (this->batch_type == batch_retry_type)
{
- if (this->batch->get_type(this->batch) == batch_retry_type)
- {
- /* retry batch has already been created */
- return;
- }
- DBG1(DBG_TNC, "cancelling PB-TNC %N batch",
- pb_tnc_batch_type_names, this->batch->get_type(this->batch));
- this->batch->destroy(this->batch);
- }
+ /* retry batch has already been selected */
+ return;
+ }
+
+ change_batch_type(this, batch_retry_type);
+
if (this->is_server)
{
+ this->recs->clear_recommendation(this->recs);
tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id,
TNC_CONNECTION_STATE_HANDSHAKE);
}
- this->batch = pb_tnc_batch_create(this->is_server, batch_retry_type);
}
METHOD(tls_t, process, status_t,
@@ -375,8 +416,9 @@ METHOD(tls_t, process, status_t,
if (this->is_server && !this->connection_id)
{
this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
- TNCCS_2_0, (tnccs_t*)this, _send_msg,
- &this->request_handshake_retry, &this->recs);
+ TNCCS_2_0, (tnccs_t*)this, _send_msg,
+ &this->request_handshake_retry,
+ this->max_msg_len, &this->recs);
if (!this->connection_id)
{
return FAILED;
@@ -461,13 +503,7 @@ METHOD(tls_t, process, status_t,
case FAILED:
this->fatal_error = TRUE;
this->mutex->lock(this->mutex);
- if (this->batch)
- {
- DBG1(DBG_TNC, "cancelling PB-TNC %N batch",
- pb_tnc_batch_type_names, this->batch->get_type(this->batch));
- this->batch->destroy(this->batch);
- }
- this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_CLOSE);
+ change_batch_type(this, PB_BATCH_CLOSE);
this->mutex->unlock(this->mutex);
/* fall through to add error messages to outbound batch */
case VERIFY_ERROR:
@@ -475,7 +511,7 @@ METHOD(tls_t, process, status_t,
while (enumerator->enumerate(enumerator, &msg))
{
this->mutex->lock(this->mutex);
- this->batch->add_msg(this->batch, msg->get_ref(msg));
+ this->messages->insert_last(this->messages, msg->get_ref(msg));
this->mutex->unlock(this->mutex);
}
enumerator->destroy(enumerator);
@@ -508,10 +544,10 @@ static void check_and_build_recommendation(private_tnccs_20_t *this)
}
if (this->recs->have_recommendation(this->recs, &rec, &eval))
{
- this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_RESULT);
+ this->batch_type = PB_BATCH_RESULT;
msg = pb_assessment_result_msg_create(eval);
- this->batch->add_msg(this->batch, msg);
+ this->messages->insert_last(this->messages, msg);
/**
* Map IMV Action Recommendation codes to PB Access Recommendation codes
@@ -530,16 +566,15 @@ static void check_and_build_recommendation(private_tnccs_20_t *this)
pb_rec = PB_REC_ACCESS_DENIED;
}
msg = pb_access_recommendation_msg_create(pb_rec);
- this->batch->add_msg(this->batch, msg);
+ this->messages->insert_last(this->messages, msg);
enumerator = this->recs->create_reason_enumerator(this->recs);
while (enumerator->enumerate(enumerator, &id, &reason, &language))
{
msg = pb_reason_string_msg_create(reason, language);
- this->batch->add_msg(this->batch, msg);
+ this->messages->insert_last(this->messages, msg);
}
enumerator->destroy(enumerator);
- this->recs->clear_reasons(this->recs);
}
}
@@ -557,7 +592,8 @@ METHOD(tls_t, build, status_t,
this->connection_id = tnc->tnccs->create_connection(tnc->tnccs,
TNCCS_2_0, (tnccs_t*)this, _send_msg,
- &this->request_handshake_retry, NULL);
+ &this->request_handshake_retry,
+ this->max_msg_len, NULL);
if (!this->connection_id)
{
return FAILED;
@@ -568,8 +604,8 @@ METHOD(tls_t, build, status_t,
msg = pb_language_preference_msg_create(chunk_create(pref_lang,
strlen(pref_lang)));
this->mutex->lock(this->mutex);
- this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_CDATA);
- this->batch->add_msg(this->batch, msg);
+ this->batch_type = PB_BATCH_CDATA;
+ this->messages->insert_last(this->messages, msg);
this->mutex->unlock(this->mutex);
tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id,
@@ -583,7 +619,7 @@ METHOD(tls_t, build, status_t,
state = this->state_machine->get_state(this->state_machine);
- if (this->is_server && this->fatal_error && state == PB_STATE_END)
+ if (this->fatal_error && state == PB_STATE_END)
{
DBG1(DBG_TNC, "a fatal PB-TNC error occurred, terminating connection");
return FAILED;
@@ -603,66 +639,98 @@ METHOD(tls_t, build, status_t,
this->request_handshake_retry = FALSE;
}
- if (!this->batch)
+ if (this->is_server && state == PB_STATE_SERVER_WORKING &&
+ this->recs->have_recommendation(this->recs, NULL, NULL))
{
- if (this->is_server)
+ check_and_build_recommendation(this);
+ }
+
+ if (this->batch_type == PB_BATCH_NONE)
+ {
+ if (this->is_server && state == PB_STATE_SERVER_WORKING)
{
- if (state == PB_STATE_SERVER_WORKING)
+ if (this->state_machine->get_empty_cdata(this->state_machine))
{
check_and_build_recommendation(this);
}
+ else
+ {
+ DBG2(DBG_TNC, "no recommendation available yet, "
+ "sending empty PB-TNC SDATA batch");
+ this->batch_type = PB_BATCH_SDATA;
+ }
}
else
- {
+ {
/**
- * if the DECIDED state has been reached and no CRETRY is under way
- * or if a CLOSE batch with error messages has been received,
+ * In the DECIDED state and if no CRETRY is under way,
* a PB-TNC client replies with an empty CLOSE batch.
*/
- if (state == PB_STATE_DECIDED || state == PB_STATE_END)
+ if (state == PB_STATE_DECIDED)
{
- this->batch = pb_tnc_batch_create(this->is_server, PB_BATCH_CLOSE);
+ this->batch_type = PB_BATCH_CLOSE;
}
}
}
- if (this->batch)
+ if (this->batch_type != PB_BATCH_NONE)
{
- pb_tnc_batch_type_t batch_type;
+ pb_tnc_batch_t *batch;
+ pb_tnc_msg_t *msg;
chunk_t data;
+ int msg_count;
+ enumerator_t *enumerator;
- batch_type = this->batch->get_type(this->batch);
-
- if (this->state_machine->send_batch(this->state_machine, batch_type))
+ if (this->state_machine->send_batch(this->state_machine, this->batch_type))
{
- this->batch->build(this->batch);
- data = this->batch->get_encoding(this->batch);
+ batch = pb_tnc_batch_create(this->is_server, this->batch_type,
+ min(this->max_batch_len, *buflen));
+
+ enumerator = this->messages->create_enumerator(this->messages);
+ while (enumerator->enumerate(enumerator, &msg))
+ {
+ if (batch->add_msg(batch, msg))
+ {
+ this->messages->remove_at(this->messages, enumerator);
+ }
+ else
+ {
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ batch->build(batch);
+ data = batch->get_encoding(batch);
DBG1(DBG_TNC, "sending PB-TNC %N batch (%d bytes) for Connection ID %u",
- pb_tnc_batch_type_names, batch_type, data.len,
+ pb_tnc_batch_type_names, this->batch_type, data.len,
this->connection_id);
DBG3(DBG_TNC, "%B", &data);
- *msglen = data.len;
- if (data.len > *buflen)
+ *buflen = data.len;
+ *msglen = 0;
+ memcpy(buf, data.ptr, *buflen);
+ batch->destroy(batch);
+
+ msg_count = this->messages->get_count(this->messages);
+ if (msg_count)
{
- DBG1(DBG_TNC, "fragmentation of PB-TNC batch not supported yet");
+ DBG2(DBG_TNC, "queued %d PB-TNC message%s for next %N batch",
+ msg_count, (msg_count == 1) ? "" : "s",
+ pb_tnc_batch_type_names, this->batch_type);
}
else
{
- *buflen = data.len;
+ this->batch_type = PB_BATCH_NONE;
}
- memcpy(buf, data.ptr, *buflen);
+
status = ALREADY_DONE;
}
else
{
- DBG1(DBG_TNC, "cancelling unexpected PB-TNC batch type: %N",
- pb_tnc_batch_type_names, batch_type);
+ change_batch_type(this, PB_BATCH_NONE);
status = INVALID_STATE;
}
-
- this->batch->destroy(this->batch);
- this->batch = NULL;
}
else
{
@@ -715,7 +783,8 @@ METHOD(tls_t, destroy, void,
this->is_server);
this->state_machine->destroy(this->state_machine);
this->mutex->destroy(this->mutex);
- DESTROY_IF(this->batch);
+ this->messages->destroy_offset(this->messages,
+ offsetof(pb_tnc_msg_t, destroy));
free(this);
}
@@ -739,6 +808,13 @@ tls_t *tnccs_20_create(bool is_server)
.is_server = is_server,
.state_machine = pb_tnc_state_machine_create(is_server),
.mutex = mutex_create(MUTEX_TYPE_DEFAULT),
+ .messages = linked_list_create(),
+ .max_batch_len = lib->settings->get_int(lib->settings,
+ "%s.plugins.tnccs-20.max_batch_size", 65522,
+ charon->name),
+ .max_msg_len = lib->settings->get_int(lib->settings,
+ "%s.plugins.tnccs-20.max_message_size", 65490,
+ charon->name),
);
return &this->public;