diff options
Diffstat (limited to 'src/libtnccs/plugins/tnccs_20/tnccs_20.c')
-rw-r--r-- | src/libtnccs/plugins/tnccs_20/tnccs_20.c | 864 |
1 files changed, 107 insertions, 757 deletions
diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20.c b/src/libtnccs/plugins/tnccs_20/tnccs_20.c index 997771406..33b012880 100644 --- a/src/libtnccs/plugins/tnccs_20/tnccs_20.c +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20.c @@ -15,30 +15,17 @@ */ #include "tnccs_20.h" +#include "tnccs_20_handler.h" +#include "tnccs_20_server.h" +#include "tnccs_20_client.h" #include "batch/pb_tnc_batch.h" #include "messages/pb_tnc_msg.h" #include "messages/ietf/pb_pa_msg.h" -#include "messages/ietf/pb_error_msg.h" -#include "messages/ietf/pb_assessment_result_msg.h" -#include "messages/ietf/pb_access_recommendation_msg.h" -#include "messages/ietf/pb_remediation_parameters_msg.h" -#include "messages/ietf/pb_reason_string_msg.h" -#include "messages/ietf/pb_language_preference_msg.h" -#include "messages/tcg/pb_pdp_referral_msg.h" -#include "state_machine/pb_tnc_state_machine.h" #include <tncif_names.h> #include <tncif_pa_subtypes.h> -#include <tnc/tnc.h> -#include <tnc/tnccs/tnccs_manager.h> -#include <tnc/imc/imc_manager.h> -#include <tnc/imv/imv_manager.h> - -#include <threading/mutex.h> #include <utils/debug.h> -#include <collections/linked_list.h> -#include <pen/pen.h> typedef struct private_tnccs_20_t private_tnccs_20_t; @@ -83,64 +70,49 @@ struct private_tnccs_20_t { tnc_ift_type_t transport; /** - * Type of TNC client authentication - */ - u_int32_t auth_type; - - /** - * PB-TNC State Machine - */ - pb_tnc_state_machine_t *state_machine; - - /** - * Connection ID assigned to this TNCCS connection + * TNC IF-T transport protocol for EAP methods */ - TNC_ConnectionID connection_id; + bool eap_transport; /** - * PB-TNC messages to be sent + * Type of TNC client authentication */ - linked_list_t *messages; + u_int32_t auth_type; /** - * Type of PB-TNC batch being constructed + * Mutual TNC measurements */ - pb_tnc_batch_type_t batch_type; + bool mutual; /** - * Maximum PB-TNC batch size + * Direction the next batch will go to */ - size_t max_batch_len; + bool to_server; /** - * Maximum PA-TNC message size + * TNC Server */ - size_t max_msg_len; + tnccs_20_handler_t *tnc_server; /** - * Mutex locking the batch in construction + * TNC Client */ - mutex_t *mutex; + tnccs_20_handler_t *tnc_client; /** - * Flag set while processing + * Active TNCSS handler */ - bool fatal_error; + tnccs_20_handler_t *tnccs_handler; /** - * Flag set by IMC/IMV RequestHandshakeRetry() function + * Maximum PB-TNC batch size */ - bool request_handshake_retry; - - /** - * SendMessage() by IMC/IMV only allowed if flag is set - */ - bool send_msg; + size_t max_batch_len; /** - * Set of IMV recommendations (TNC Server only) + * Maximum PA-TNC message size */ - recommendations_t *recs; + size_t max_msg_len; /** * Callback function to communicate recommendation (TNC Server only) @@ -148,69 +120,30 @@ struct private_tnccs_20_t { tnccs_cb_t callback; /** - * Data to pass to callback function (TNC Server only) - */ - void *cb_data; - - /** - * PDP server FQDN - */ - chunk_t pdp_server; - - /** - * PDP server port - */ - u_int16_t pdp_port; - - /** * reference count */ refcount_t ref; }; -/** - * 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, + TNC_UInt32 msg_flags, TNC_BufferReference msg, TNC_UInt32 msg_len, - TNC_VendorID msg_vid, - TNC_MessageSubtype msg_subtype) + TNC_VendorID msg_vid, + TNC_MessageSubtype msg_subtype) { pb_tnc_msg_t *pb_tnc_msg; - pb_tnc_batch_type_t batch_type; enum_name_t *pa_subtype_names; bool excl; - if (!this->send_msg) + if (!this->tnccs_handler->get_send_flag(this->tnccs_handler)) { DBG1(DBG_TNC, "%s %u not allowed to call SendMessage()", - this->is_server ? "IMV" : "IMC", - this->is_server ? imv_id : imc_id); + this->to_server ? "IMC" : "IMV", + this->to_server ? imc_id : imv_id); + return TNC_RESULT_ILLEGAL_OPERATION; } excl = (msg_flags & TNC_MESSAGE_FLAGS_EXCLUSIVE) != 0; @@ -230,697 +163,106 @@ METHOD(tnccs_t, send_msg, TNC_Result, DBG2(DBG_TNC, "creating PB-PA message type '%N' 0x%06x/0x%08x", pen_names, msg_vid, msg_vid, msg_subtype); } + this->tnccs_handler->add_msg(this->tnccs_handler, pb_tnc_msg); - /* 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_type == PB_BATCH_NONE) - { - this->batch_type = batch_type; - } - if (this->batch_type == batch_type) - { - this->messages->insert_last(this->messages, pb_tnc_msg); - } - else - { - pb_tnc_msg->destroy(pb_tnc_msg); - } - this->mutex->unlock(this->mutex); return TNC_RESULT_SUCCESS; } -/** - * Handle a single PB-TNC IETF standard message according to its type - */ -static void handle_ietf_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) -{ - pen_type_t msg_type = msg->get_type(msg); - - switch (msg_type.type) - { - case PB_MSG_EXPERIMENTAL: - /* nothing to do */ - break; - case PB_MSG_PA: - { - pb_pa_msg_t *pa_msg; - 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_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_subtype.vendor_id); - if (pa_subtype_names) - { - DBG2(DBG_TNC, "handling PB-PA message type '%N/%N' 0x%06x/0x%08x", - 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_subtype.vendor_id, msg_subtype.vendor_id, - msg_subtype.type); - } - - this->send_msg = TRUE; - if (this->is_server) - { - tnc->imvs->receive_message(tnc->imvs, this->connection_id, - excl, msg_body.ptr, msg_body.len, - 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_subtype.vendor_id, - msg_subtype.type, imv_id, imc_id); - } - this->send_msg = FALSE; - break; - } - case PB_MSG_ASSESSMENT_RESULT: - { - pb_assessment_result_msg_t *assess_msg; - u_int32_t result; - - assess_msg = (pb_assessment_result_msg_t*)msg; - result = assess_msg->get_assessment_result(assess_msg); - DBG1(DBG_TNC, "PB-TNC assessment result is '%N'", - TNC_IMV_Evaluation_Result_names, result); - break; - } - case PB_MSG_ACCESS_RECOMMENDATION: - { - pb_access_recommendation_msg_t *rec_msg; - pb_access_recommendation_code_t rec; - TNC_ConnectionState state = TNC_CONNECTION_STATE_ACCESS_NONE; - - rec_msg = (pb_access_recommendation_msg_t*)msg; - rec = rec_msg->get_access_recommendation(rec_msg); - DBG1(DBG_TNC, "PB-TNC access recommendation is '%N'", - pb_access_recommendation_code_names, rec); - switch (rec) - { - case PB_REC_ACCESS_ALLOWED: - state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; - break; - case PB_REC_ACCESS_DENIED: - state = TNC_CONNECTION_STATE_ACCESS_NONE; - break; - case PB_REC_QUARANTINED: - state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; - } - tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id, - state); - break; - } - case PB_MSG_REMEDIATION_PARAMETERS: - { - pb_remediation_parameters_msg_t *rem_msg; - pen_type_t parameters_type; - chunk_t parameters, string, lang_code; - - rem_msg = (pb_remediation_parameters_msg_t*)msg; - parameters_type = rem_msg->get_parameters_type(rem_msg); - parameters = rem_msg->get_parameters(rem_msg); - - if (parameters_type.vendor_id == PEN_IETF) - { - switch (parameters_type.type) - { - case PB_REMEDIATION_URI: - DBG1(DBG_TNC, "remediation uri: %.*s", - parameters.len, parameters.ptr); - break; - case PB_REMEDIATION_STRING: - string = rem_msg->get_string(rem_msg, &lang_code); - DBG1(DBG_TNC, "remediation string: [%.*s]\n%.*s", - lang_code.len, lang_code.ptr, - string.len, string.ptr); - break; - default: - DBG1(DBG_TNC, "remediation parameters: %B", ¶meters); - } - } - else - { - DBG1(DBG_TNC, "remediation parameters: %B", ¶meters); - } - break; - } - case PB_MSG_ERROR: - { - pb_error_msg_t *err_msg; - bool fatal; - u_int32_t vendor_id; - u_int16_t error_code; - - err_msg = (pb_error_msg_t*)msg; - fatal = err_msg->get_fatal_flag(err_msg); - vendor_id = err_msg->get_vendor_id(err_msg); - error_code = err_msg->get_error_code(err_msg); - - if (fatal) - { - this->fatal_error = TRUE; - } - - if (vendor_id == PEN_IETF) - { - switch (error_code) - { - case PB_ERROR_INVALID_PARAMETER: - case PB_ERROR_UNSUPPORTED_MANDATORY_MSG: - DBG1(DBG_TNC, "received %s PB-TNC error '%N' " - "(offset %u bytes)", - fatal ? "fatal" : "non-fatal", - pb_tnc_error_code_names, error_code, - err_msg->get_offset(err_msg)); - break; - case PB_ERROR_VERSION_NOT_SUPPORTED: - DBG1(DBG_TNC, "received %s PB-TNC error '%N' " - "caused by bad version 0x%02x", - fatal ? "fatal" : "non-fatal", - pb_tnc_error_code_names, error_code, - err_msg->get_bad_version(err_msg)); - break; - case PB_ERROR_UNEXPECTED_BATCH_TYPE: - case PB_ERROR_LOCAL_ERROR: - default: - DBG1(DBG_TNC, "received %s PB-TNC error '%N'", - fatal ? "fatal" : "non-fatal", - pb_tnc_error_code_names, error_code); - break; - } - } - else - { - DBG1(DBG_TNC, "received %s PB-TNC error (%u) " - "with Vendor ID 0x%06x", - fatal ? "fatal" : "non-fatal", - error_code, vendor_id); - } - break; - } - case PB_MSG_LANGUAGE_PREFERENCE: - { - pb_language_preference_msg_t *lang_msg; - chunk_t lang; - - lang_msg = (pb_language_preference_msg_t*)msg; - lang = lang_msg->get_language_preference(lang_msg); - - if (this->recs) - { - DBG2(DBG_TNC, "setting language preference to '%.*s'", - (int)lang.len, lang.ptr); - this->recs->set_preferred_language(this->recs, lang); - } - break; - } - case PB_MSG_REASON_STRING: - { - pb_reason_string_msg_t *reason_msg; - chunk_t reason_string, language_code; - - 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); - DBG1(DBG_TNC, "reason string is '%.*s' [%.*s]", - (int)reason_string.len, reason_string.ptr, - (int)language_code.len, language_code.ptr); - break; - } - default: - break; - } -} - -/** - * Handle a single PB-TNC TCG standard message according to its type - */ -static void handle_tcg_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) -{ - pen_type_t msg_type = msg->get_type(msg); - - switch (msg_type.type) - { - case PB_TCG_MSG_PDP_REFERRAL: - { - pb_pdp_referral_msg_t *pdp_msg; - pen_type_t pdp_id_type; - u_int8_t pdp_protocol; - - pdp_msg = (pb_pdp_referral_msg_t*)msg; - pdp_id_type = pdp_msg->get_identifier_type(pdp_msg); - - if (pdp_id_type.vendor_id == PEN_TCG && - pdp_id_type.type == PB_PDP_ID_FQDN) - { - this->pdp_server = chunk_clone(pdp_msg->get_fqdn(pdp_msg, - &pdp_protocol, &this->pdp_port)); - if (pdp_protocol != 0) - { - DBG1(DBG_TNC, "unsupported PDP transport protocol"); - break; - } - DBG1(DBG_TNC, "PDP server '%.*s' is listening on port %u", - this->pdp_server.len, this->pdp_server.ptr, - this->pdp_port); - } - break; - } - default: - break; - } -} - -/** - * Handle a single PB-TNC message according to its type - */ -static void handle_message(private_tnccs_20_t *this, pb_tnc_msg_t *msg) -{ - pen_type_t msg_type = msg->get_type(msg); - - switch (msg_type.vendor_id) - { - case PEN_IETF: - handle_ietf_message(this, msg); - break; - case PEN_TCG: - handle_tcg_message(this, msg); - break; - default: - break; - } -} - -/** - * Build a CRETRY or SRETRY batch - */ -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_type == batch_retry_type) - { - /* 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); - } -} - METHOD(tls_t, process, status_t, private_tnccs_20_t *this, void *buf, size_t buflen) { chunk_t data; pb_tnc_batch_t *batch; - pb_tnc_msg_t *msg; - enumerator_t *enumerator; - identification_t *pdp_server; - u_int16_t *pdp_port; + bool from_server, mutual; status_t status; - if (this->is_server && !this->connection_id) + /* On arrival of first PB-TNC batch create TNC server */ + if (this->is_server && !this->tnc_server) { - this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, - TNCCS_2_0, (tnccs_t*)this, _send_msg, - &this->request_handshake_retry, - this->max_msg_len, &this->recs); - if (!this->connection_id) + this->tnc_server = tnccs_20_server_create(&this->public, _send_msg, + this->max_batch_len, this->max_msg_len, + this->eap_transport); + if (!this->tnc_server) { return FAILED; } - tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, - TNC_CONNECTION_STATE_CREATE); - tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, - TNC_CONNECTION_STATE_HANDSHAKE); - - /* Send a PB-TNC TCG PDP Referral message if PDP is known */ - pdp_server = (identification_t*)lib->get(lib, "pt-tls-server"); - pdp_port = (u_int16_t*)lib->get(lib, "pt-tls-port"); - - if ((this->transport == TNC_IFT_EAP_1_1 || - this->transport == TNC_IFT_EAP_2_0) && pdp_server && pdp_port) - { - msg = pb_pdp_referral_msg_create_from_fqdn( - pdp_server->get_encoding(pdp_server), *pdp_port); - this->messages->insert_last(this->messages, msg); - } - + this->tnccs_handler = this->tnc_server; + this->tnccs_handler->begin_handshake(this->tnccs_handler); } data = chunk_create(buf, buflen); - DBG1(DBG_TNC, "received TNCCS batch (%u bytes) for Connection ID %u", - data.len, this->connection_id); + DBG1(DBG_TNC, "received TNCCS batch (%u bytes)", data.len); DBG3(DBG_TNC, "%B", &data); - batch = pb_tnc_batch_create_from_data(this->is_server, data); - status = batch->process(batch, this->state_machine); - if (status != FAILED) - { - enumerator_t *enumerator; - pb_tnc_msg_t *msg; - pb_tnc_batch_type_t batch_type; - bool empty = TRUE; + /* Has a mutual connection been established? */ + mutual = this->tnc_client && this->tnc_server; - batch_type = batch->get_type(batch); + /* Parse the header of the received PB-TNC batch */ + batch = pb_tnc_batch_create_from_data(data); + status = batch->process_header(batch, !mutual, this->is_server, + &from_server); + this->to_server = mutual ? from_server : !this->is_server; - if (batch_type == PB_BATCH_CRETRY) - { - /* Send an SRETRY batch in response */ - this->mutex->lock(this->mutex); - build_retry_batch(this); - this->mutex->unlock(this->mutex); - } - else if (batch_type == PB_BATCH_SRETRY) - { - /* Restart the measurements */ - tnc->imcs->notify_connection_change(tnc->imcs, - this->connection_id, TNC_CONNECTION_STATE_HANDSHAKE); - this->send_msg = TRUE; - tnc->imcs->begin_handshake(tnc->imcs, this->connection_id); - this->send_msg = FALSE; - } - - enumerator = batch->create_msg_enumerator(batch); - while (enumerator->enumerate(enumerator, &msg)) - { - handle_message(this, msg); - empty = FALSE; - } - enumerator->destroy(enumerator); - - /* received an empty CLOSE batch from PB-TNC client */ - if (this->is_server && batch_type == PB_BATCH_CLOSE && empty) - { - batch->destroy(batch); - if (this->fatal_error) - { - DBG1(DBG_TNC, "a fatal PB-TNC error occurred, " - "terminating connection"); - return FAILED; - } - else - { - return SUCCESS; - } - } - - this->send_msg = TRUE; - if (this->is_server) - { - tnc->imvs->batch_ending(tnc->imvs, this->connection_id); - } - else - { - tnc->imcs->batch_ending(tnc->imcs, this->connection_id); - } - this->send_msg = FALSE; - } + /* Set active TNCCS handler */ + this->tnccs_handler = this->to_server ? this->tnc_client : this->tnc_server; + DBG2(DBG_TNC, "TNC %s is handling the connection", + this->to_server ? "client" : "server"); - switch (status) + if (status == SUCCESS) { - case FAILED: - this->fatal_error = TRUE; - this->mutex->lock(this->mutex); - change_batch_type(this, PB_BATCH_CLOSE); - this->mutex->unlock(this->mutex); - /* fall through to add error messages to outbound batch */ - case VERIFY_ERROR: - enumerator = batch->create_error_enumerator(batch); - while (enumerator->enumerate(enumerator, &msg)) - { - this->mutex->lock(this->mutex); - this->messages->insert_last(this->messages, msg->get_ref(msg)); - this->mutex->unlock(this->mutex); - } - enumerator->destroy(enumerator); - break; - case SUCCESS: - default: - break; + status = this->tnccs_handler->process(this->tnccs_handler, batch); } - batch->destroy(batch); - - return NEED_MORE; -} - -/** - * Build a RESULT batch if a final recommendation is available - */ -static void check_and_build_recommendation(private_tnccs_20_t *this) -{ - TNC_IMV_Action_Recommendation rec; - TNC_IMV_Evaluation_Result eval; - TNC_ConnectionState state; - TNC_IMVID id; - chunk_t reason, language; - enumerator_t *enumerator; - pb_tnc_msg_t *msg; - pb_access_recommendation_code_t pb_rec; - - if (!this->recs->have_recommendation(this->recs, &rec, &eval)) + if (status == VERIFY_ERROR) { - tnc->imvs->solicit_recommendation(tnc->imvs, this->connection_id); + this->tnccs_handler->handle_errors(this->tnccs_handler, batch); + status = NEED_MORE; } - if (this->recs->have_recommendation(this->recs, &rec, &eval)) - { - this->batch_type = PB_BATCH_RESULT; - - msg = pb_assessment_result_msg_create(eval); - this->messages->insert_last(this->messages, msg); - - /** - * Map IMV Action Recommendation codes to PB Access Recommendation codes - * and communicate Access Recommendation to IMVs - */ - switch (rec) - { - case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: - state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; - pb_rec = PB_REC_ACCESS_ALLOWED; - break; - case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: - state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; - pb_rec = PB_REC_QUARANTINED; - break; - case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: - case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: - default: - state = TNC_CONNECTION_STATE_ACCESS_NONE; - pb_rec = PB_REC_ACCESS_DENIED; - } - tnc->imvs->notify_connection_change(tnc->imvs, this->connection_id, - state); - - msg = pb_access_recommendation_msg_create(pb_rec); - this->messages->insert_last(this->messages, msg); + batch->destroy(batch); - enumerator = this->recs->create_reason_enumerator(this->recs); - while (enumerator->enumerate(enumerator, &id, &reason, &language)) - { - msg = pb_reason_string_msg_create(reason, language); - this->messages->insert_last(this->messages, msg); - } - enumerator->destroy(enumerator); - } + return status; } METHOD(tls_t, build, status_t, private_tnccs_20_t *this, void *buf, size_t *buflen, size_t *msglen) { status_t status; - pb_tnc_state_t state; - - /* Initialize the connection */ - if (!this->is_server && !this->connection_id) - { - pb_tnc_msg_t *msg; - char *pref_lang; - - this->connection_id = tnc->tnccs->create_connection(tnc->tnccs, - TNCCS_2_0, (tnccs_t*)this, _send_msg, - &this->request_handshake_retry, - this->max_msg_len, NULL); - if (!this->connection_id) - { - return FAILED; - } - - /* Create PB-TNC Language Preference message */ - pref_lang = tnc->imcs->get_preferred_language(tnc->imcs); - msg = pb_language_preference_msg_create(chunk_create(pref_lang, - strlen(pref_lang))); - this->mutex->lock(this->mutex); - 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, - TNC_CONNECTION_STATE_CREATE); - tnc->imcs->notify_connection_change(tnc->imcs, this->connection_id, - TNC_CONNECTION_STATE_HANDSHAKE); - this->send_msg = TRUE; - tnc->imcs->begin_handshake(tnc->imcs, this->connection_id); - this->send_msg = FALSE; - } - - state = this->state_machine->get_state(this->state_machine); - - if (this->fatal_error && state == PB_STATE_END) - { - DBG1(DBG_TNC, "a fatal PB-TNC error occurred, terminating connection"); - return FAILED; - } - - /* Do not allow any asynchronous IMCs or IMVs to add additional messages */ - this->mutex->lock(this->mutex); - - if (this->request_handshake_retry) - { - if (state != PB_STATE_INIT) - { - build_retry_batch(this); - } - - /* Reset the flag for the next handshake retry request */ - this->request_handshake_retry = FALSE; - } - - if (this->is_server && state == PB_STATE_SERVER_WORKING && - this->recs->have_recommendation(this->recs, NULL, NULL)) - { - check_and_build_recommendation(this); - } - if (this->batch_type == PB_BATCH_NONE) + if (this->to_server) { - if (this->is_server) - { - 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 + /* Before sending the first PB-TNC batch create TNC client */ + if (!this->tnc_client) { - switch (state) + DBG2(DBG_TNC, "TNC client is handling the connection"); + this->tnc_client = tnccs_20_client_create(&this->public, _send_msg, + this->max_batch_len, + this->max_msg_len); + if (!this->tnc_client) { - case PB_STATE_CLIENT_WORKING: - DBG2(DBG_TNC, "no client data to send, " - "sending empty PB-TNC CDATA batch"); - this->batch_type = PB_BATCH_CDATA; - break; - case PB_STATE_DECIDED: - /** - * In the DECIDED state and if no CRETRY is under way, - * a PB-TNC client replies with an empty CLOSE batch. - */ - this->batch_type = PB_BATCH_CLOSE; - break; - default: - break; + status = FAILED; } + this->tnccs_handler = this->tnc_client; + this->tnccs_handler->begin_handshake(this->tnccs_handler); } } - - if (this->batch_type != PB_BATCH_NONE) + else { - pb_tnc_batch_t *batch; - pb_tnc_msg_t *msg; - chunk_t data; - int msg_count; - enumerator_t *enumerator; - - if (this->state_machine->send_batch(this->state_machine, this->batch_type)) + /* Before sending the first PB-TNC batch create TNC server */ + if (!this->tnc_server) { - 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, this->batch_type, data.len, - this->connection_id); - DBG3(DBG_TNC, "%B", &data); - - *buflen = data.len; - *msglen = 0; - memcpy(buf, data.ptr, *buflen); - batch->destroy(batch); - - msg_count = this->messages->get_count(this->messages); - if (msg_count) - { - 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 + DBG2(DBG_TNC, "TNC server is handling the connection"); + this->tnc_server = tnccs_20_server_create(&this->public, _send_msg, + this->max_batch_len, this->max_msg_len, + this->eap_transport); + if (!this->tnc_server) { - this->batch_type = PB_BATCH_NONE; + status = FAILED; } - - status = ALREADY_DONE; - } - else - { - change_batch_type(this, PB_BATCH_NONE); - status = INVALID_STATE; + this->tnccs_handler = this->tnc_server; + this->tnccs_handler->begin_handshake(this->tnccs_handler); } } - else - { - DBG1(DBG_TNC, "no PB-TNC batch to send"); - status = INVALID_STATE; - } - this->mutex->unlock(this->mutex); - + status = this->tnccs_handler->build(this->tnccs_handler, buf, buflen, msglen); + return status; } @@ -961,14 +303,17 @@ METHOD(tls_t, is_complete, bool, TNC_IMV_Action_Recommendation rec; TNC_IMV_Evaluation_Result eval; - if (this->recs && this->recs->have_recommendation(this->recs, &rec, &eval)) + if (this->tnc_server) { - return this->callback ? this->callback(rec, eval) : TRUE; - } - else - { - return FALSE; + tnccs_20_server_t *tnc_server; + + tnc_server = (tnccs_20_server_t*)this->tnc_server; + if (tnc_server->have_recommendation(tnc_server, &rec, &eval)) + { + return this->callback ? this->callback(rec, eval) : TRUE; + } } + return FALSE; } METHOD(tls_t, get_eap_msk, chunk_t, @@ -982,17 +327,12 @@ METHOD(tls_t, destroy, void, { if (ref_put(&this->ref)) { - tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id, - this->is_server); + DESTROY_IF(this->tnc_server); + DESTROY_IF(this->tnc_client); this->server_id->destroy(this->server_id); this->peer_id->destroy(this->peer_id); this->server_ip->destroy(this->server_ip); this->peer_ip->destroy(this->peer_ip); - this->state_machine->destroy(this->state_machine); - this->mutex->destroy(this->mutex); - this->messages->destroy_offset(this->messages, - offsetof(pb_tnc_msg_t, destroy)); - free(this->pdp_server.ptr); free(this); } } @@ -1036,9 +376,19 @@ METHOD(tnccs_t, set_auth_type, void, METHOD(tnccs_t, get_pdp_server, chunk_t, private_tnccs_20_t *this, u_int16_t *port) { - *port = this->pdp_port; + if (this->tnc_client) + { + tnccs_20_client_t *tnc_client; + + tnc_client = (tnccs_20_client_t*)this->tnc_client; - return this->pdp_server; + return tnc_client->get_pdp_server(tnc_client, port); + } + else + { + *port = 0; + return chunk_empty; + } } METHOD(tnccs_t, get_ref, tnccs_t*, @@ -1114,15 +464,15 @@ tnccs_t* tnccs_20_create(bool is_server, identification_t *server_id, .get_ref = _get_ref, }, .is_server = is_server, + .to_server = !is_server, .server_id = server_id->clone(server_id), .peer_id = peer_id->clone(peer_id), .server_ip = server_ip->clone(server_ip), .peer_ip = peer_ip->clone(peer_ip), .transport = transport, + .eap_transport = transport == TNC_IFT_EAP_1_1 || + transport == TNC_IFT_EAP_2_0, .callback = cb, - .state_machine = pb_tnc_state_machine_create(is_server), - .mutex = mutex_create(MUTEX_TYPE_DEFAULT), - .messages = linked_list_create(), .max_batch_len = max_batch_size, .max_msg_len = max_message_size, .ref = 1, |