diff options
Diffstat (limited to 'src/libtnccs/plugins/tnccs_20/tnccs_20.c')
-rw-r--r-- | src/libtnccs/plugins/tnccs_20/tnccs_20.c | 945 |
1 files changed, 193 insertions, 752 deletions
diff --git a/src/libtnccs/plugins/tnccs_20/tnccs_20.c b/src/libtnccs/plugins/tnccs_20/tnccs_20.c index dc4da51c6..a1a95733f 100644 --- a/src/libtnccs/plugins/tnccs_20/tnccs_20.c +++ b/src/libtnccs/plugins/tnccs_20/tnccs_20.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Sansar Choinyanbuu - * Copyright (C) 2010-2013 Andreas Steffen + * Copyright (C) 2010-2015 Andreas Steffen * HSR Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -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; @@ -60,77 +47,72 @@ struct private_tnccs_20_t { /** * Server identity */ - identification_t *server; + identification_t *server_id; /** * Client identity */ - identification_t *peer; + identification_t *peer_id; /** - * Underlying TNC IF-T transport protocol + * Server IP address */ - tnc_ift_type_t transport; + host_t *server_ip; /** - * Type of TNC client authentication + * Client IP address */ - u_int32_t auth_type; + host_t *peer_ip; /** - * PB-TNC State Machine + * Underlying TNC IF-T transport protocol */ - pb_tnc_state_machine_t *state_machine; + tnc_ift_type_t transport; /** - * 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 PB-TNC protocol enabled */ - 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) @@ -138,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; @@ -220,698 +163,169 @@ 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, fatal_header_error = FALSE; status_t status; + chunk_t data; - if (this->is_server && !this->connection_id) + /* On arrival of first batch from TNC client 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, FALSE); } 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) + /* Parse the header of the received PB-TNC batch */ + batch = pb_tnc_batch_create_from_data(data); + status = batch->process_header(batch, !this->mutual, this->is_server, + &from_server); + if (status == FAILED) { - enumerator_t *enumerator; - pb_tnc_msg_t *msg; - pb_tnc_batch_type_t batch_type; - bool empty = TRUE; - - batch_type = batch->get_type(batch); - - 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); + fatal_header_error = TRUE; + status = VERIFY_ERROR; + } + this->to_server = this->mutual ? from_server : !this->is_server; - /* received an empty CLOSE batch from PB-TNC client */ - if (this->is_server && batch_type == PB_BATCH_CLOSE && empty) + /* In the mutual case, first batch from TNC server requires a TNC client */ + if (this->to_server && !this->tnc_client) + { + this->tnc_client = tnccs_20_client_create(&this->public, _send_msg, + this->max_batch_len, this->max_msg_len); + if (!this->tnc_client) { 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); + return FAILED; } - this->send_msg = FALSE; + this->tnccs_handler = this->tnc_client; + this->tnccs_handler->begin_handshake(this->tnccs_handler, this->mutual); } + else + { + /* Set active TNCCS handler for processing */ + this->tnccs_handler = this->to_server ? this->tnc_client : + this->tnc_server; + } + DBG2(DBG_TNC, "TNC %s is handling inbound 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); + } + if (status == VERIFY_ERROR) + { + this->tnccs_handler->handle_errors(this->tnccs_handler, batch, + fatal_header_error); + status = NEED_MORE; } batch->destroy(batch); - return NEED_MORE; -} + /* Has a mutual connection been established? */ + this->mutual = this->is_server ? + this->tnc_server->get_mutual(this->tnc_server) : + this->tnc_client->get_mutual(this->tnc_client); -/** - * 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)) - { - tnc->imvs->solicit_recommendation(tnc->imvs, this->connection_id); - } - if (this->recs->have_recommendation(this->recs, &rec, &eval)) + if (this->mutual && !this->is_server) { - this->batch_type = PB_BATCH_RESULT; + pb_tnc_state_t client_state, server_state; - msg = pb_assessment_result_msg_create(eval); - this->messages->insert_last(this->messages, msg); + client_state = !this->tnc_client ? PB_STATE_INIT : + this->tnc_client->get_state(this->tnc_client); + server_state = !this->tnc_server ? PB_STATE_INIT : + this->tnc_server->get_state(this->tnc_server); - /** - * Map IMV Action Recommendation codes to PB Access Recommendation codes - * and communicate Access Recommendation to IMVs - */ - switch (rec) + /* In half-duplex mutual mode toggle the direction on the client side */ + if ((!this->to_server && client_state != PB_STATE_DECIDED) || + ( this->to_server && server_state != PB_STATE_END)) { - 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; + this->to_server = !this->to_server; + } + else if (client_state == PB_STATE_DECIDED && + server_state == PB_STATE_END) + { + /* Cause the final CLOSE batch to be sent to the TNC server */ + this->to_server = TRUE; } - 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); - enumerator = this->recs->create_reason_enumerator(this->recs); - while (enumerator->enumerate(enumerator, &id, &reason, &language)) + /* Suppress a successful CLOSE batch coming from the TNC server */ + if (status == SUCCESS) { - msg = pb_reason_string_msg_create(reason, language); - this->messages->insert_last(this->messages, msg); + status = NEED_MORE; } - 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)) + if (this->to_server) { - check_and_build_recommendation(this); - } + DBG2(DBG_TNC, "TNC client is handling outbound connection"); - if (this->batch_type == PB_BATCH_NONE) - { - if (this->is_server) + /* Before sending the first PB-TNC batch create TNC client */ + if (this->tnc_client) { - 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; - } - } + this->tnccs_handler = this->tnc_client; } else { - switch (state) + 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; + return FAILED; } + this->tnccs_handler = this->tnc_client; + this->tnccs_handler->begin_handshake(this->tnccs_handler, + this->mutual); } } - - 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; + DBG2(DBG_TNC, "TNC server is handling outbound connection"); - 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 - { - this->batch_type = PB_BATCH_NONE; - } - - status = ALREADY_DONE; + this->tnccs_handler = this->tnc_server; } else { - change_batch_type(this, PB_BATCH_NONE); - status = INVALID_STATE; + 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; + } + this->tnccs_handler = this->tnc_server; + this->tnccs_handler->begin_handshake(this->tnccs_handler, + this->mutual); } } - else - { - DBG1(DBG_TNC, "no PB-TNC batch to send"); - status = INVALID_STATE; - } - this->mutex->unlock(this->mutex); - - return status; + return this->tnccs_handler->build(this->tnccs_handler, buf, buflen, msglen); } METHOD(tls_t, is_server, bool, @@ -923,20 +337,20 @@ METHOD(tls_t, is_server, bool, METHOD(tls_t, get_server_id, identification_t*, private_tnccs_20_t *this) { - return this->server; + return this->server_id; } METHOD(tls_t, set_peer_id, void, private_tnccs_20_t *this, identification_t *id) { - DESTROY_IF(this->peer); - this->peer = id->clone(id); + DESTROY_IF(this->peer_id); + this->peer_id = id->clone(id); } METHOD(tls_t, get_peer_id, identification_t*, private_tnccs_20_t *this) { - return this->peer; + return this->peer_id; } METHOD(tls_t, get_purpose, tls_purpose_t, @@ -951,14 +365,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, @@ -972,19 +389,28 @@ METHOD(tls_t, destroy, void, { if (ref_put(&this->ref)) { - tnc->tnccs->remove_connection(tnc->tnccs, this->connection_id, - this->is_server); - this->server->destroy(this->server); - this->peer->destroy(this->peer); - 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); + 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); free(this); } } +METHOD(tnccs_t, get_server_ip, host_t*, + private_tnccs_20_t *this) +{ + return this->server_ip; +} + +METHOD(tnccs_t, get_peer_ip, host_t*, + private_tnccs_20_t *this) +{ + return this->peer_ip; +} + METHOD(tnccs_t, get_transport, tnc_ift_type_t, private_tnccs_20_t *this) { @@ -1012,9 +438,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*, @@ -1027,9 +463,10 @@ METHOD(tnccs_t, get_ref, tnccs_t*, /** * See header */ -tnccs_t* tnccs_20_create(bool is_server, - identification_t *server, identification_t *peer, - tnc_ift_type_t transport, tnccs_cb_t cb) +tnccs_t* tnccs_20_create(bool is_server, identification_t *server_id, + identification_t *peer_id, host_t *server_ip, + host_t *peer_ip, tnc_ift_type_t transport, + tnccs_cb_t cb) { private_tnccs_20_t *this; size_t max_batch_size, default_max_batch_size; @@ -1079,6 +516,8 @@ tnccs_t* tnccs_20_create(bool is_server, .get_eap_msk = _get_eap_msk, .destroy = _destroy, }, + .get_server_ip = _get_server_ip, + .get_peer_ip = _get_peer_ip, .get_transport = _get_transport, .set_transport = _set_transport, .get_auth_type = _get_auth_type, @@ -1087,13 +526,15 @@ tnccs_t* tnccs_20_create(bool is_server, .get_ref = _get_ref, }, .is_server = is_server, - .server = server->clone(server), - .peer = peer->clone(peer), + .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, |