diff options
Diffstat (limited to 'src/libcharon/plugins/tnccs_20/tnccs_20.c')
-rw-r--r-- | src/libcharon/plugins/tnccs_20/tnccs_20.c | 226 |
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; |