1189251Ssam/* 2189251Ssam * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH) 3189251Ssam * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> 4189251Ssam * 5252726Srpaulo * This software may be distributed under the terms of the BSD license. 6252726Srpaulo * See README for more details. 7189251Ssam */ 8189251Ssam 9189251Ssam#include "includes.h" 10189251Ssam#include <dlfcn.h> 11189251Ssam 12189251Ssam#include "common.h" 13189251Ssam#include "base64.h" 14189251Ssam#include "tncs.h" 15189251Ssam#include "eap_common/eap_tlv_common.h" 16189251Ssam#include "eap_common/eap_defs.h" 17189251Ssam 18189251Ssam 19189251Ssam/* TODO: TNCS must be thread-safe; review the code and add locking etc. if 20189251Ssam * needed.. */ 21189251Ssam 22189251Ssam#define TNC_CONFIG_FILE "/etc/tnc_config" 23189251Ssam#define IF_TNCCS_START \ 24189251Ssam"<?xml version=\"1.0\"?>\n" \ 25189251Ssam"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \ 26189251Ssam"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \ 27189251Ssam"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \ 28189251Ssam"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \ 29189251Ssam"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n" 30189251Ssam#define IF_TNCCS_END "\n</TNCCS-Batch>" 31189251Ssam 32189251Ssam/* TNC IF-IMV */ 33189251Ssam 34189251Ssamtypedef unsigned long TNC_UInt32; 35189251Ssamtypedef unsigned char *TNC_BufferReference; 36189251Ssam 37189251Ssamtypedef TNC_UInt32 TNC_IMVID; 38189251Ssamtypedef TNC_UInt32 TNC_ConnectionID; 39189251Ssamtypedef TNC_UInt32 TNC_ConnectionState; 40189251Ssamtypedef TNC_UInt32 TNC_RetryReason; 41189251Ssamtypedef TNC_UInt32 TNC_IMV_Action_Recommendation; 42189251Ssamtypedef TNC_UInt32 TNC_IMV_Evaluation_Result; 43189251Ssamtypedef TNC_UInt32 TNC_MessageType; 44189251Ssamtypedef TNC_MessageType *TNC_MessageTypeList; 45189251Ssamtypedef TNC_UInt32 TNC_VendorID; 46189251Ssamtypedef TNC_UInt32 TNC_Subtype; 47189251Ssamtypedef TNC_UInt32 TNC_Version; 48189251Ssamtypedef TNC_UInt32 TNC_Result; 49189251Ssamtypedef TNC_UInt32 TNC_AttributeID; 50189251Ssam 51189251Ssamtypedef TNC_Result (*TNC_TNCS_BindFunctionPointer)( 52189251Ssam TNC_IMVID imvID, 53189251Ssam char *functionName, 54189251Ssam void **pOutfunctionPointer); 55189251Ssam 56189251Ssam#define TNC_RESULT_SUCCESS 0 57189251Ssam#define TNC_RESULT_NOT_INITIALIZED 1 58189251Ssam#define TNC_RESULT_ALREADY_INITIALIZED 2 59189251Ssam#define TNC_RESULT_NO_COMMON_VERSION 3 60189251Ssam#define TNC_RESULT_CANT_RETRY 4 61189251Ssam#define TNC_RESULT_WONT_RETRY 5 62189251Ssam#define TNC_RESULT_INVALID_PARAMETER 6 63189251Ssam#define TNC_RESULT_CANT_RESPOND 7 64189251Ssam#define TNC_RESULT_ILLEGAL_OPERATION 8 65189251Ssam#define TNC_RESULT_OTHER 9 66189251Ssam#define TNC_RESULT_FATAL 10 67189251Ssam 68189251Ssam#define TNC_CONNECTION_STATE_CREATE 0 69189251Ssam#define TNC_CONNECTION_STATE_HANDSHAKE 1 70189251Ssam#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2 71189251Ssam#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3 72189251Ssam#define TNC_CONNECTION_STATE_ACCESS_NONE 4 73189251Ssam#define TNC_CONNECTION_STATE_DELETE 5 74189251Ssam 75189251Ssam#define TNC_IFIMV_VERSION_1 1 76189251Ssam 77189251Ssam#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff) 78189251Ssam#define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff) 79189251Ssam 80189251Ssam/* TNCC-TNCS Message Types */ 81189251Ssam#define TNC_TNCCS_RECOMMENDATION 0x00000001 82189251Ssam#define TNC_TNCCS_ERROR 0x00000002 83189251Ssam#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003 84189251Ssam#define TNC_TNCCS_REASONSTRINGS 0x00000004 85189251Ssam 86189251Ssam/* Possible TNC_IMV_Action_Recommendation values: */ 87189251Ssamenum IMV_Action_Recommendation { 88189251Ssam TNC_IMV_ACTION_RECOMMENDATION_ALLOW, 89189251Ssam TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS, 90189251Ssam TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, 91189251Ssam TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION 92189251Ssam}; 93189251Ssam 94189251Ssam/* Possible TNC_IMV_Evaluation_Result values: */ 95189251Ssamenum IMV_Evaluation_Result { 96189251Ssam TNC_IMV_EVALUATION_RESULT_COMPLIANT, 97189251Ssam TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR, 98189251Ssam TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR, 99189251Ssam TNC_IMV_EVALUATION_RESULT_ERROR, 100189251Ssam TNC_IMV_EVALUATION_RESULT_DONT_KNOW 101189251Ssam}; 102189251Ssam 103189251Ssamstruct tnc_if_imv { 104189251Ssam struct tnc_if_imv *next; 105189251Ssam char *name; 106189251Ssam char *path; 107189251Ssam void *dlhandle; /* from dlopen() */ 108189251Ssam TNC_IMVID imvID; 109189251Ssam TNC_MessageTypeList supported_types; 110189251Ssam size_t num_supported_types; 111189251Ssam 112189251Ssam /* Functions implemented by IMVs (with TNC_IMV_ prefix) */ 113189251Ssam TNC_Result (*Initialize)( 114189251Ssam TNC_IMVID imvID, 115189251Ssam TNC_Version minVersion, 116189251Ssam TNC_Version maxVersion, 117189251Ssam TNC_Version *pOutActualVersion); 118189251Ssam TNC_Result (*NotifyConnectionChange)( 119189251Ssam TNC_IMVID imvID, 120189251Ssam TNC_ConnectionID connectionID, 121189251Ssam TNC_ConnectionState newState); 122189251Ssam TNC_Result (*ReceiveMessage)( 123189251Ssam TNC_IMVID imvID, 124189251Ssam TNC_ConnectionID connectionID, 125189251Ssam TNC_BufferReference message, 126189251Ssam TNC_UInt32 messageLength, 127189251Ssam TNC_MessageType messageType); 128189251Ssam TNC_Result (*SolicitRecommendation)( 129189251Ssam TNC_IMVID imvID, 130189251Ssam TNC_ConnectionID connectionID); 131189251Ssam TNC_Result (*BatchEnding)( 132189251Ssam TNC_IMVID imvID, 133189251Ssam TNC_ConnectionID connectionID); 134189251Ssam TNC_Result (*Terminate)(TNC_IMVID imvID); 135189251Ssam TNC_Result (*ProvideBindFunction)( 136189251Ssam TNC_IMVID imvID, 137189251Ssam TNC_TNCS_BindFunctionPointer bindFunction); 138189251Ssam}; 139189251Ssam 140189251Ssam 141189251Ssam#define TNC_MAX_IMV_ID 10 142189251Ssam 143189251Ssamstruct tncs_data { 144189251Ssam struct tncs_data *next; 145189251Ssam struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */ 146189251Ssam TNC_ConnectionID connectionID; 147189251Ssam unsigned int last_batchid; 148189251Ssam enum IMV_Action_Recommendation recommendation; 149189251Ssam int done; 150189251Ssam 151189251Ssam struct conn_imv { 152189251Ssam u8 *imv_send; 153189251Ssam size_t imv_send_len; 154189251Ssam enum IMV_Action_Recommendation recommendation; 155189251Ssam int recommendation_set; 156189251Ssam } imv_data[TNC_MAX_IMV_ID]; 157189251Ssam 158189251Ssam char *tncs_message; 159189251Ssam}; 160189251Ssam 161189251Ssam 162189251Ssamstruct tncs_global { 163189251Ssam struct tnc_if_imv *imv; 164189251Ssam TNC_ConnectionID next_conn_id; 165189251Ssam struct tncs_data *connections; 166189251Ssam}; 167189251Ssam 168189251Ssamstatic struct tncs_global *tncs_global_data = NULL; 169189251Ssam 170189251Ssam 171189251Ssamstatic struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID) 172189251Ssam{ 173189251Ssam struct tnc_if_imv *imv; 174189251Ssam 175189251Ssam if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL) 176189251Ssam return NULL; 177189251Ssam imv = tncs_global_data->imv; 178189251Ssam while (imv) { 179189251Ssam if (imv->imvID == imvID) 180189251Ssam return imv; 181189251Ssam imv = imv->next; 182189251Ssam } 183189251Ssam return NULL; 184189251Ssam} 185189251Ssam 186189251Ssam 187189251Ssamstatic struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID) 188189251Ssam{ 189189251Ssam struct tncs_data *tncs; 190189251Ssam 191189251Ssam if (tncs_global_data == NULL) 192189251Ssam return NULL; 193189251Ssam 194189251Ssam tncs = tncs_global_data->connections; 195189251Ssam while (tncs) { 196189251Ssam if (tncs->connectionID == connectionID) 197189251Ssam return tncs; 198189251Ssam tncs = tncs->next; 199189251Ssam } 200189251Ssam 201189251Ssam wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found", 202189251Ssam (unsigned long) connectionID); 203189251Ssam 204189251Ssam return NULL; 205189251Ssam} 206189251Ssam 207189251Ssam 208189251Ssam/* TNCS functions that IMVs can call */ 209189251SsamTNC_Result TNC_TNCS_ReportMessageTypes( 210189251Ssam TNC_IMVID imvID, 211189251Ssam TNC_MessageTypeList supportedTypes, 212189251Ssam TNC_UInt32 typeCount) 213189251Ssam{ 214189251Ssam TNC_UInt32 i; 215189251Ssam struct tnc_if_imv *imv; 216189251Ssam 217189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu " 218189251Ssam "typeCount=%lu)", 219189251Ssam (unsigned long) imvID, (unsigned long) typeCount); 220189251Ssam 221189251Ssam for (i = 0; i < typeCount; i++) { 222189251Ssam wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu", 223189251Ssam i, supportedTypes[i]); 224189251Ssam } 225189251Ssam 226189251Ssam imv = tncs_get_imv(imvID); 227189251Ssam if (imv == NULL) 228189251Ssam return TNC_RESULT_INVALID_PARAMETER; 229189251Ssam os_free(imv->supported_types); 230189251Ssam imv->supported_types = 231252726Srpaulo os_malloc(typeCount * sizeof(TNC_MessageType)); 232189251Ssam if (imv->supported_types == NULL) 233189251Ssam return TNC_RESULT_FATAL; 234189251Ssam os_memcpy(imv->supported_types, supportedTypes, 235252726Srpaulo typeCount * sizeof(TNC_MessageType)); 236189251Ssam imv->num_supported_types = typeCount; 237189251Ssam 238189251Ssam return TNC_RESULT_SUCCESS; 239189251Ssam} 240189251Ssam 241189251Ssam 242189251SsamTNC_Result TNC_TNCS_SendMessage( 243189251Ssam TNC_IMVID imvID, 244189251Ssam TNC_ConnectionID connectionID, 245189251Ssam TNC_BufferReference message, 246189251Ssam TNC_UInt32 messageLength, 247189251Ssam TNC_MessageType messageType) 248189251Ssam{ 249189251Ssam struct tncs_data *tncs; 250189251Ssam unsigned char *b64; 251189251Ssam size_t b64len; 252189251Ssam 253189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu " 254189251Ssam "connectionID=%lu messageType=%lu)", 255189251Ssam imvID, connectionID, messageType); 256189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage", 257189251Ssam message, messageLength); 258189251Ssam 259189251Ssam if (tncs_get_imv(imvID) == NULL) 260189251Ssam return TNC_RESULT_INVALID_PARAMETER; 261189251Ssam 262189251Ssam tncs = tncs_get_conn(connectionID); 263189251Ssam if (tncs == NULL) 264189251Ssam return TNC_RESULT_INVALID_PARAMETER; 265189251Ssam 266189251Ssam b64 = base64_encode(message, messageLength, &b64len); 267189251Ssam if (b64 == NULL) 268189251Ssam return TNC_RESULT_FATAL; 269189251Ssam 270189251Ssam os_free(tncs->imv_data[imvID].imv_send); 271189251Ssam tncs->imv_data[imvID].imv_send_len = 0; 272189251Ssam tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100); 273189251Ssam if (tncs->imv_data[imvID].imv_send == NULL) { 274189251Ssam os_free(b64); 275189251Ssam return TNC_RESULT_OTHER; 276189251Ssam } 277189251Ssam 278189251Ssam tncs->imv_data[imvID].imv_send_len = 279189251Ssam os_snprintf((char *) tncs->imv_data[imvID].imv_send, 280189251Ssam b64len + 100, 281189251Ssam "<IMC-IMV-Message><Type>%08X</Type>" 282189251Ssam "<Base64>%s</Base64></IMC-IMV-Message>", 283189251Ssam (unsigned int) messageType, b64); 284189251Ssam 285189251Ssam os_free(b64); 286189251Ssam 287189251Ssam return TNC_RESULT_SUCCESS; 288189251Ssam} 289189251Ssam 290189251Ssam 291189251SsamTNC_Result TNC_TNCS_RequestHandshakeRetry( 292189251Ssam TNC_IMVID imvID, 293189251Ssam TNC_ConnectionID connectionID, 294189251Ssam TNC_RetryReason reason) 295189251Ssam{ 296189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry"); 297189251Ssam /* TODO */ 298189251Ssam return TNC_RESULT_SUCCESS; 299189251Ssam} 300189251Ssam 301189251Ssam 302189251SsamTNC_Result TNC_TNCS_ProvideRecommendation( 303189251Ssam TNC_IMVID imvID, 304189251Ssam TNC_ConnectionID connectionID, 305189251Ssam TNC_IMV_Action_Recommendation recommendation, 306189251Ssam TNC_IMV_Evaluation_Result evaluation) 307189251Ssam{ 308189251Ssam struct tncs_data *tncs; 309189251Ssam 310189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu " 311189251Ssam "connectionID=%lu recommendation=%lu evaluation=%lu)", 312189251Ssam (unsigned long) imvID, (unsigned long) connectionID, 313189251Ssam (unsigned long) recommendation, (unsigned long) evaluation); 314189251Ssam 315189251Ssam if (tncs_get_imv(imvID) == NULL) 316189251Ssam return TNC_RESULT_INVALID_PARAMETER; 317189251Ssam 318189251Ssam tncs = tncs_get_conn(connectionID); 319189251Ssam if (tncs == NULL) 320189251Ssam return TNC_RESULT_INVALID_PARAMETER; 321189251Ssam 322189251Ssam tncs->imv_data[imvID].recommendation = recommendation; 323189251Ssam tncs->imv_data[imvID].recommendation_set = 1; 324189251Ssam 325189251Ssam return TNC_RESULT_SUCCESS; 326189251Ssam} 327189251Ssam 328189251Ssam 329189251SsamTNC_Result TNC_TNCS_GetAttribute( 330189251Ssam TNC_IMVID imvID, 331189251Ssam TNC_ConnectionID connectionID, 332189251Ssam TNC_AttributeID attribureID, 333189251Ssam TNC_UInt32 bufferLength, 334189251Ssam TNC_BufferReference buffer, 335189251Ssam TNC_UInt32 *pOutValueLength) 336189251Ssam{ 337189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute"); 338189251Ssam /* TODO */ 339189251Ssam return TNC_RESULT_SUCCESS; 340189251Ssam} 341189251Ssam 342189251Ssam 343189251SsamTNC_Result TNC_TNCS_SetAttribute( 344189251Ssam TNC_IMVID imvID, 345189251Ssam TNC_ConnectionID connectionID, 346189251Ssam TNC_AttributeID attribureID, 347189251Ssam TNC_UInt32 bufferLength, 348189251Ssam TNC_BufferReference buffer) 349189251Ssam{ 350189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute"); 351189251Ssam /* TODO */ 352189251Ssam return TNC_RESULT_SUCCESS; 353189251Ssam} 354189251Ssam 355189251Ssam 356189251SsamTNC_Result TNC_TNCS_BindFunction( 357189251Ssam TNC_IMVID imvID, 358189251Ssam char *functionName, 359189251Ssam void **pOutFunctionPointer) 360189251Ssam{ 361189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, " 362189251Ssam "functionName='%s')", (unsigned long) imvID, functionName); 363189251Ssam 364189251Ssam if (tncs_get_imv(imvID) == NULL) 365189251Ssam return TNC_RESULT_INVALID_PARAMETER; 366189251Ssam 367189251Ssam if (pOutFunctionPointer == NULL) 368189251Ssam return TNC_RESULT_INVALID_PARAMETER; 369189251Ssam 370189251Ssam if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0) 371189251Ssam *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes; 372189251Ssam else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0) 373189251Ssam *pOutFunctionPointer = TNC_TNCS_SendMessage; 374189251Ssam else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") == 375189251Ssam 0) 376189251Ssam *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry; 377189251Ssam else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") == 378189251Ssam 0) 379189251Ssam *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation; 380189251Ssam else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0) 381189251Ssam *pOutFunctionPointer = TNC_TNCS_GetAttribute; 382189251Ssam else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0) 383189251Ssam *pOutFunctionPointer = TNC_TNCS_SetAttribute; 384189251Ssam else 385189251Ssam *pOutFunctionPointer = NULL; 386189251Ssam 387189251Ssam return TNC_RESULT_SUCCESS; 388189251Ssam} 389189251Ssam 390189251Ssam 391189251Ssamstatic void * tncs_get_sym(void *handle, char *func) 392189251Ssam{ 393189251Ssam void *fptr; 394189251Ssam 395189251Ssam fptr = dlsym(handle, func); 396189251Ssam 397189251Ssam return fptr; 398189251Ssam} 399189251Ssam 400189251Ssam 401189251Ssamstatic int tncs_imv_resolve_funcs(struct tnc_if_imv *imv) 402189251Ssam{ 403189251Ssam void *handle = imv->dlhandle; 404189251Ssam 405189251Ssam /* Mandatory IMV functions */ 406189251Ssam imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize"); 407189251Ssam if (imv->Initialize == NULL) { 408189251Ssam wpa_printf(MSG_ERROR, "TNC: IMV does not export " 409189251Ssam "TNC_IMV_Initialize"); 410189251Ssam return -1; 411189251Ssam } 412189251Ssam 413189251Ssam imv->SolicitRecommendation = tncs_get_sym( 414189251Ssam handle, "TNC_IMV_SolicitRecommendation"); 415189251Ssam if (imv->SolicitRecommendation == NULL) { 416189251Ssam wpa_printf(MSG_ERROR, "TNC: IMV does not export " 417189251Ssam "TNC_IMV_SolicitRecommendation"); 418189251Ssam return -1; 419189251Ssam } 420189251Ssam 421189251Ssam imv->ProvideBindFunction = 422189251Ssam tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction"); 423189251Ssam if (imv->ProvideBindFunction == NULL) { 424189251Ssam wpa_printf(MSG_ERROR, "TNC: IMV does not export " 425189251Ssam "TNC_IMV_ProvideBindFunction"); 426189251Ssam return -1; 427189251Ssam } 428189251Ssam 429189251Ssam /* Optional IMV functions */ 430189251Ssam imv->NotifyConnectionChange = 431189251Ssam tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange"); 432189251Ssam imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage"); 433189251Ssam imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding"); 434189251Ssam imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate"); 435189251Ssam 436189251Ssam return 0; 437189251Ssam} 438189251Ssam 439189251Ssam 440189251Ssamstatic int tncs_imv_initialize(struct tnc_if_imv *imv) 441189251Ssam{ 442189251Ssam TNC_Result res; 443189251Ssam TNC_Version imv_ver; 444189251Ssam 445189251Ssam wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'", 446189251Ssam imv->name); 447189251Ssam res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1, 448189251Ssam TNC_IFIMV_VERSION_1, &imv_ver); 449189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu", 450189251Ssam (unsigned long) res, (unsigned long) imv_ver); 451189251Ssam 452189251Ssam return res == TNC_RESULT_SUCCESS ? 0 : -1; 453189251Ssam} 454189251Ssam 455189251Ssam 456189251Ssamstatic int tncs_imv_terminate(struct tnc_if_imv *imv) 457189251Ssam{ 458189251Ssam TNC_Result res; 459189251Ssam 460189251Ssam if (imv->Terminate == NULL) 461189251Ssam return 0; 462189251Ssam 463189251Ssam wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'", 464189251Ssam imv->name); 465189251Ssam res = imv->Terminate(imv->imvID); 466189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu", 467189251Ssam (unsigned long) res); 468189251Ssam 469189251Ssam return res == TNC_RESULT_SUCCESS ? 0 : -1; 470189251Ssam} 471189251Ssam 472189251Ssam 473189251Ssamstatic int tncs_imv_provide_bind_function(struct tnc_if_imv *imv) 474189251Ssam{ 475189251Ssam TNC_Result res; 476189251Ssam 477189251Ssam wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for " 478189251Ssam "IMV '%s'", imv->name); 479189251Ssam res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction); 480189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu", 481189251Ssam (unsigned long) res); 482189251Ssam 483189251Ssam return res == TNC_RESULT_SUCCESS ? 0 : -1; 484189251Ssam} 485189251Ssam 486189251Ssam 487189251Ssamstatic int tncs_imv_notify_connection_change(struct tnc_if_imv *imv, 488189251Ssam TNC_ConnectionID conn, 489189251Ssam TNC_ConnectionState state) 490189251Ssam{ 491189251Ssam TNC_Result res; 492189251Ssam 493189251Ssam if (imv->NotifyConnectionChange == NULL) 494189251Ssam return 0; 495189251Ssam 496189251Ssam wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)" 497189251Ssam " for IMV '%s'", (int) state, imv->name); 498189251Ssam res = imv->NotifyConnectionChange(imv->imvID, conn, state); 499189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu", 500189251Ssam (unsigned long) res); 501189251Ssam 502189251Ssam return res == TNC_RESULT_SUCCESS ? 0 : -1; 503189251Ssam} 504189251Ssam 505189251Ssam 506189251Ssamstatic int tncs_load_imv(struct tnc_if_imv *imv) 507189251Ssam{ 508189251Ssam if (imv->path == NULL) { 509189251Ssam wpa_printf(MSG_DEBUG, "TNC: No IMV configured"); 510189251Ssam return -1; 511189251Ssam } 512189251Ssam 513189251Ssam wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)", 514189251Ssam imv->name, imv->path); 515189251Ssam imv->dlhandle = dlopen(imv->path, RTLD_LAZY); 516189251Ssam if (imv->dlhandle == NULL) { 517189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s", 518189251Ssam imv->name, imv->path, dlerror()); 519189251Ssam return -1; 520189251Ssam } 521189251Ssam 522189251Ssam if (tncs_imv_resolve_funcs(imv) < 0) { 523189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions"); 524189251Ssam return -1; 525189251Ssam } 526189251Ssam 527189251Ssam if (tncs_imv_initialize(imv) < 0 || 528189251Ssam tncs_imv_provide_bind_function(imv) < 0) { 529189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV"); 530189251Ssam return -1; 531189251Ssam } 532189251Ssam 533189251Ssam return 0; 534189251Ssam} 535189251Ssam 536189251Ssam 537189251Ssamstatic void tncs_free_imv(struct tnc_if_imv *imv) 538189251Ssam{ 539189251Ssam os_free(imv->name); 540189251Ssam os_free(imv->path); 541189251Ssam os_free(imv->supported_types); 542189251Ssam} 543189251Ssam 544189251Ssamstatic void tncs_unload_imv(struct tnc_if_imv *imv) 545189251Ssam{ 546189251Ssam tncs_imv_terminate(imv); 547189251Ssam 548189251Ssam if (imv->dlhandle) 549189251Ssam dlclose(imv->dlhandle); 550189251Ssam 551189251Ssam tncs_free_imv(imv); 552189251Ssam} 553189251Ssam 554189251Ssam 555189251Ssamstatic int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type) 556189251Ssam{ 557189251Ssam size_t i; 558189251Ssam unsigned int vendor, subtype; 559189251Ssam 560189251Ssam if (imv == NULL || imv->supported_types == NULL) 561189251Ssam return 0; 562189251Ssam 563189251Ssam vendor = type >> 8; 564189251Ssam subtype = type & 0xff; 565189251Ssam 566189251Ssam for (i = 0; i < imv->num_supported_types; i++) { 567189251Ssam unsigned int svendor, ssubtype; 568189251Ssam svendor = imv->supported_types[i] >> 8; 569189251Ssam ssubtype = imv->supported_types[i] & 0xff; 570189251Ssam if ((vendor == svendor || svendor == TNC_VENDORID_ANY) && 571189251Ssam (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY)) 572189251Ssam return 1; 573189251Ssam } 574189251Ssam 575189251Ssam return 0; 576189251Ssam} 577189251Ssam 578189251Ssam 579189251Ssamstatic void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type, 580189251Ssam const u8 *msg, size_t len) 581189251Ssam{ 582189251Ssam struct tnc_if_imv *imv; 583189251Ssam TNC_Result res; 584189251Ssam 585189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len); 586189251Ssam 587189251Ssam for (imv = tncs->imv; imv; imv = imv->next) { 588189251Ssam if (imv->ReceiveMessage == NULL || 589189251Ssam !tncs_supported_type(imv, type)) 590189251Ssam continue; 591189251Ssam 592189251Ssam wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'", 593189251Ssam imv->name); 594189251Ssam res = imv->ReceiveMessage(imv->imvID, tncs->connectionID, 595189251Ssam (TNC_BufferReference) msg, len, 596189251Ssam type); 597189251Ssam wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu", 598189251Ssam (unsigned long) res); 599189251Ssam } 600189251Ssam} 601189251Ssam 602189251Ssam 603189251Ssamstatic void tncs_batch_ending(struct tncs_data *tncs) 604189251Ssam{ 605189251Ssam struct tnc_if_imv *imv; 606189251Ssam TNC_Result res; 607189251Ssam 608189251Ssam for (imv = tncs->imv; imv; imv = imv->next) { 609189251Ssam if (imv->BatchEnding == NULL) 610189251Ssam continue; 611189251Ssam 612189251Ssam wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'", 613189251Ssam imv->name); 614189251Ssam res = imv->BatchEnding(imv->imvID, tncs->connectionID); 615189251Ssam wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu", 616189251Ssam (unsigned long) res); 617189251Ssam } 618189251Ssam} 619189251Ssam 620189251Ssam 621189251Ssamstatic void tncs_solicit_recommendation(struct tncs_data *tncs) 622189251Ssam{ 623189251Ssam struct tnc_if_imv *imv; 624189251Ssam TNC_Result res; 625189251Ssam 626189251Ssam for (imv = tncs->imv; imv; imv = imv->next) { 627189251Ssam if (tncs->imv_data[imv->imvID].recommendation_set) 628189251Ssam continue; 629189251Ssam 630189251Ssam wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for " 631189251Ssam "IMV '%s'", imv->name); 632189251Ssam res = imv->SolicitRecommendation(imv->imvID, 633189251Ssam tncs->connectionID); 634189251Ssam wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu", 635189251Ssam (unsigned long) res); 636189251Ssam } 637189251Ssam} 638189251Ssam 639189251Ssam 640189251Ssamvoid tncs_init_connection(struct tncs_data *tncs) 641189251Ssam{ 642189251Ssam struct tnc_if_imv *imv; 643189251Ssam int i; 644189251Ssam 645189251Ssam for (imv = tncs->imv; imv; imv = imv->next) { 646189251Ssam tncs_imv_notify_connection_change( 647189251Ssam imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE); 648189251Ssam tncs_imv_notify_connection_change( 649189251Ssam imv, tncs->connectionID, 650189251Ssam TNC_CONNECTION_STATE_HANDSHAKE); 651189251Ssam } 652189251Ssam 653189251Ssam for (i = 0; i < TNC_MAX_IMV_ID; i++) { 654189251Ssam os_free(tncs->imv_data[i].imv_send); 655189251Ssam tncs->imv_data[i].imv_send = NULL; 656189251Ssam tncs->imv_data[i].imv_send_len = 0; 657189251Ssam } 658189251Ssam} 659189251Ssam 660189251Ssam 661189251Ssamsize_t tncs_total_send_len(struct tncs_data *tncs) 662189251Ssam{ 663189251Ssam int i; 664189251Ssam size_t len = 0; 665189251Ssam 666189251Ssam for (i = 0; i < TNC_MAX_IMV_ID; i++) 667189251Ssam len += tncs->imv_data[i].imv_send_len; 668189251Ssam if (tncs->tncs_message) 669189251Ssam len += os_strlen(tncs->tncs_message); 670189251Ssam return len; 671189251Ssam} 672189251Ssam 673189251Ssam 674189251Ssamu8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos) 675189251Ssam{ 676189251Ssam int i; 677189251Ssam 678189251Ssam for (i = 0; i < TNC_MAX_IMV_ID; i++) { 679189251Ssam if (tncs->imv_data[i].imv_send == NULL) 680189251Ssam continue; 681189251Ssam 682189251Ssam os_memcpy(pos, tncs->imv_data[i].imv_send, 683189251Ssam tncs->imv_data[i].imv_send_len); 684189251Ssam pos += tncs->imv_data[i].imv_send_len; 685189251Ssam os_free(tncs->imv_data[i].imv_send); 686189251Ssam tncs->imv_data[i].imv_send = NULL; 687189251Ssam tncs->imv_data[i].imv_send_len = 0; 688189251Ssam } 689189251Ssam 690189251Ssam if (tncs->tncs_message) { 691189251Ssam size_t len = os_strlen(tncs->tncs_message); 692189251Ssam os_memcpy(pos, tncs->tncs_message, len); 693189251Ssam pos += len; 694189251Ssam os_free(tncs->tncs_message); 695189251Ssam tncs->tncs_message = NULL; 696189251Ssam } 697189251Ssam 698189251Ssam return pos; 699189251Ssam} 700189251Ssam 701189251Ssam 702189251Ssamchar * tncs_if_tnccs_start(struct tncs_data *tncs) 703189251Ssam{ 704189251Ssam char *buf = os_malloc(1000); 705189251Ssam if (buf == NULL) 706189251Ssam return NULL; 707189251Ssam tncs->last_batchid++; 708189251Ssam os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid); 709189251Ssam return buf; 710189251Ssam} 711189251Ssam 712189251Ssam 713189251Ssamchar * tncs_if_tnccs_end(void) 714189251Ssam{ 715189251Ssam char *buf = os_malloc(100); 716189251Ssam if (buf == NULL) 717189251Ssam return NULL; 718189251Ssam os_snprintf(buf, 100, IF_TNCCS_END); 719189251Ssam return buf; 720189251Ssam} 721189251Ssam 722189251Ssam 723189251Ssamstatic int tncs_get_type(char *start, unsigned int *type) 724189251Ssam{ 725189251Ssam char *pos = os_strstr(start, "<Type>"); 726189251Ssam if (pos == NULL) 727189251Ssam return -1; 728189251Ssam pos += 6; 729189251Ssam *type = strtoul(pos, NULL, 16); 730189251Ssam return 0; 731189251Ssam} 732189251Ssam 733189251Ssam 734189251Ssamstatic unsigned char * tncs_get_base64(char *start, size_t *decoded_len) 735189251Ssam{ 736189251Ssam char *pos, *pos2; 737189251Ssam unsigned char *decoded; 738189251Ssam 739189251Ssam pos = os_strstr(start, "<Base64>"); 740189251Ssam if (pos == NULL) 741189251Ssam return NULL; 742189251Ssam 743189251Ssam pos += 8; 744189251Ssam pos2 = os_strstr(pos, "</Base64>"); 745189251Ssam if (pos2 == NULL) 746189251Ssam return NULL; 747189251Ssam *pos2 = '\0'; 748189251Ssam 749189251Ssam decoded = base64_decode((unsigned char *) pos, os_strlen(pos), 750189251Ssam decoded_len); 751189251Ssam *pos2 = '<'; 752189251Ssam if (decoded == NULL) { 753189251Ssam wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data"); 754189251Ssam } 755189251Ssam 756189251Ssam return decoded; 757189251Ssam} 758189251Ssam 759189251Ssam 760189251Ssamstatic enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs) 761189251Ssam{ 762189251Ssam enum IMV_Action_Recommendation rec; 763189251Ssam struct tnc_if_imv *imv; 764189251Ssam TNC_ConnectionState state; 765189251Ssam char *txt; 766189251Ssam 767189251Ssam wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs"); 768189251Ssam 769189251Ssam if (tncs->done) 770189251Ssam return TNCCS_PROCESS_OK_NO_RECOMMENDATION; 771189251Ssam 772189251Ssam tncs_solicit_recommendation(tncs); 773189251Ssam 774189251Ssam /* Select the most restrictive recommendation */ 775189251Ssam rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; 776189251Ssam for (imv = tncs->imv; imv; imv = imv->next) { 777189251Ssam TNC_IMV_Action_Recommendation irec; 778189251Ssam irec = tncs->imv_data[imv->imvID].recommendation; 779189251Ssam if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS) 780189251Ssam rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS; 781189251Ssam if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE && 782189251Ssam rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS) 783189251Ssam rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE; 784189251Ssam if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW && 785189251Ssam rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION) 786189251Ssam rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW; 787189251Ssam } 788189251Ssam 789189251Ssam wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec); 790189251Ssam tncs->recommendation = rec; 791189251Ssam tncs->done = 1; 792189251Ssam 793189251Ssam txt = NULL; 794189251Ssam switch (rec) { 795189251Ssam case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: 796189251Ssam case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: 797189251Ssam txt = "allow"; 798189251Ssam state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; 799189251Ssam break; 800189251Ssam case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: 801189251Ssam txt = "isolate"; 802189251Ssam state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; 803189251Ssam break; 804189251Ssam case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: 805189251Ssam txt = "none"; 806189251Ssam state = TNC_CONNECTION_STATE_ACCESS_NONE; 807189251Ssam break; 808189251Ssam default: 809189251Ssam state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; 810189251Ssam break; 811189251Ssam } 812189251Ssam 813189251Ssam if (txt) { 814189251Ssam os_free(tncs->tncs_message); 815189251Ssam tncs->tncs_message = os_zalloc(200); 816189251Ssam if (tncs->tncs_message) { 817189251Ssam os_snprintf(tncs->tncs_message, 199, 818189251Ssam "<TNCC-TNCS-Message><Type>%08X</Type>" 819189251Ssam "<XML><TNCCS-Recommendation type=\"%s\">" 820189251Ssam "</TNCCS-Recommendation></XML>" 821189251Ssam "</TNCC-TNCS-Message>", 822189251Ssam TNC_TNCCS_RECOMMENDATION, txt); 823189251Ssam } 824189251Ssam } 825189251Ssam 826189251Ssam for (imv = tncs->imv; imv; imv = imv->next) { 827189251Ssam tncs_imv_notify_connection_change(imv, tncs->connectionID, 828189251Ssam state); 829189251Ssam } 830189251Ssam 831189251Ssam switch (rec) { 832189251Ssam case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: 833189251Ssam return TNCCS_RECOMMENDATION_ALLOW; 834189251Ssam case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: 835189251Ssam return TNCCS_RECOMMENDATION_NO_ACCESS; 836189251Ssam case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: 837189251Ssam return TNCCS_RECOMMENDATION_ISOLATE; 838189251Ssam case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: 839189251Ssam return TNCCS_RECOMMENDATION_NO_RECOMMENDATION; 840189251Ssam default: 841189251Ssam return TNCCS_PROCESS_ERROR; 842189251Ssam } 843189251Ssam} 844189251Ssam 845189251Ssam 846189251Ssamenum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs, 847189251Ssam const u8 *msg, size_t len) 848189251Ssam{ 849189251Ssam char *buf, *start, *end, *pos, *pos2, *payload; 850189251Ssam unsigned int batch_id; 851189251Ssam unsigned char *decoded; 852189251Ssam size_t decoded_len; 853189251Ssam 854189251Ssam buf = os_malloc(len + 1); 855189251Ssam if (buf == NULL) 856189251Ssam return TNCCS_PROCESS_ERROR; 857189251Ssam 858189251Ssam os_memcpy(buf, msg, len); 859189251Ssam buf[len] = '\0'; 860189251Ssam start = os_strstr(buf, "<TNCCS-Batch "); 861189251Ssam end = os_strstr(buf, "</TNCCS-Batch>"); 862189251Ssam if (start == NULL || end == NULL || start > end) { 863189251Ssam os_free(buf); 864189251Ssam return TNCCS_PROCESS_ERROR; 865189251Ssam } 866189251Ssam 867189251Ssam start += 13; 868189251Ssam while (*start == ' ') 869189251Ssam start++; 870189251Ssam *end = '\0'; 871189251Ssam 872189251Ssam pos = os_strstr(start, "BatchId="); 873189251Ssam if (pos == NULL) { 874189251Ssam os_free(buf); 875189251Ssam return TNCCS_PROCESS_ERROR; 876189251Ssam } 877189251Ssam 878189251Ssam pos += 8; 879189251Ssam if (*pos == '"') 880189251Ssam pos++; 881189251Ssam batch_id = atoi(pos); 882189251Ssam wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u", 883189251Ssam batch_id); 884189251Ssam if (batch_id != tncs->last_batchid + 1) { 885189251Ssam wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId " 886189251Ssam "%u (expected %u)", 887189251Ssam batch_id, tncs->last_batchid + 1); 888189251Ssam os_free(buf); 889189251Ssam return TNCCS_PROCESS_ERROR; 890189251Ssam } 891189251Ssam tncs->last_batchid = batch_id; 892189251Ssam 893189251Ssam while (*pos != '\0' && *pos != '>') 894189251Ssam pos++; 895189251Ssam if (*pos == '\0') { 896189251Ssam os_free(buf); 897189251Ssam return TNCCS_PROCESS_ERROR; 898189251Ssam } 899189251Ssam pos++; 900189251Ssam payload = start; 901189251Ssam 902189251Ssam /* 903189251Ssam * <IMC-IMV-Message> 904189251Ssam * <Type>01234567</Type> 905189251Ssam * <Base64>foo==</Base64> 906189251Ssam * </IMC-IMV-Message> 907189251Ssam */ 908189251Ssam 909189251Ssam while (*start) { 910189251Ssam char *endpos; 911189251Ssam unsigned int type; 912189251Ssam 913189251Ssam pos = os_strstr(start, "<IMC-IMV-Message>"); 914189251Ssam if (pos == NULL) 915189251Ssam break; 916189251Ssam start = pos + 17; 917189251Ssam end = os_strstr(start, "</IMC-IMV-Message>"); 918189251Ssam if (end == NULL) 919189251Ssam break; 920189251Ssam *end = '\0'; 921189251Ssam endpos = end; 922189251Ssam end += 18; 923189251Ssam 924189251Ssam if (tncs_get_type(start, &type) < 0) { 925189251Ssam *endpos = '<'; 926189251Ssam start = end; 927189251Ssam continue; 928189251Ssam } 929189251Ssam wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type); 930189251Ssam 931189251Ssam decoded = tncs_get_base64(start, &decoded_len); 932189251Ssam if (decoded == NULL) { 933189251Ssam *endpos = '<'; 934189251Ssam start = end; 935189251Ssam continue; 936189251Ssam } 937189251Ssam 938189251Ssam tncs_send_to_imvs(tncs, type, decoded, decoded_len); 939189251Ssam 940189251Ssam os_free(decoded); 941189251Ssam 942189251Ssam start = end; 943189251Ssam } 944189251Ssam 945189251Ssam /* 946189251Ssam * <TNCC-TNCS-Message> 947189251Ssam * <Type>01234567</Type> 948189251Ssam * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML> 949189251Ssam * <Base64>foo==</Base64> 950189251Ssam * </TNCC-TNCS-Message> 951189251Ssam */ 952189251Ssam 953189251Ssam start = payload; 954189251Ssam while (*start) { 955189251Ssam unsigned int type; 956189251Ssam char *xml, *xmlend, *endpos; 957189251Ssam 958189251Ssam pos = os_strstr(start, "<TNCC-TNCS-Message>"); 959189251Ssam if (pos == NULL) 960189251Ssam break; 961189251Ssam start = pos + 19; 962189251Ssam end = os_strstr(start, "</TNCC-TNCS-Message>"); 963189251Ssam if (end == NULL) 964189251Ssam break; 965189251Ssam *end = '\0'; 966189251Ssam endpos = end; 967189251Ssam end += 20; 968189251Ssam 969189251Ssam if (tncs_get_type(start, &type) < 0) { 970189251Ssam *endpos = '<'; 971189251Ssam start = end; 972189251Ssam continue; 973189251Ssam } 974189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x", 975189251Ssam type); 976189251Ssam 977189251Ssam /* Base64 OR XML */ 978189251Ssam decoded = NULL; 979189251Ssam xml = NULL; 980189251Ssam xmlend = NULL; 981189251Ssam pos = os_strstr(start, "<XML>"); 982189251Ssam if (pos) { 983189251Ssam pos += 5; 984189251Ssam pos2 = os_strstr(pos, "</XML>"); 985189251Ssam if (pos2 == NULL) { 986189251Ssam *endpos = '<'; 987189251Ssam start = end; 988189251Ssam continue; 989189251Ssam } 990189251Ssam xmlend = pos2; 991189251Ssam xml = pos; 992189251Ssam } else { 993189251Ssam decoded = tncs_get_base64(start, &decoded_len); 994189251Ssam if (decoded == NULL) { 995189251Ssam *endpos = '<'; 996189251Ssam start = end; 997189251Ssam continue; 998189251Ssam } 999189251Ssam } 1000189251Ssam 1001189251Ssam if (decoded) { 1002189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, 1003189251Ssam "TNC: TNCC-TNCS-Message Base64", 1004189251Ssam decoded, decoded_len); 1005189251Ssam os_free(decoded); 1006189251Ssam } 1007189251Ssam 1008189251Ssam if (xml) { 1009189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, 1010189251Ssam "TNC: TNCC-TNCS-Message XML", 1011189251Ssam (unsigned char *) xml, 1012189251Ssam xmlend - xml); 1013189251Ssam } 1014189251Ssam 1015189251Ssam start = end; 1016189251Ssam } 1017189251Ssam 1018189251Ssam os_free(buf); 1019189251Ssam 1020189251Ssam tncs_batch_ending(tncs); 1021189251Ssam 1022189251Ssam if (tncs_total_send_len(tncs) == 0) 1023189251Ssam return tncs_derive_recommendation(tncs); 1024189251Ssam 1025189251Ssam return TNCCS_PROCESS_OK_NO_RECOMMENDATION; 1026189251Ssam} 1027189251Ssam 1028189251Ssam 1029189251Ssamstatic struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end, 1030189251Ssam int *error) 1031189251Ssam{ 1032189251Ssam struct tnc_if_imv *imv; 1033189251Ssam char *pos, *pos2; 1034189251Ssam 1035189251Ssam if (id >= TNC_MAX_IMV_ID) { 1036189251Ssam wpa_printf(MSG_DEBUG, "TNC: Too many IMVs"); 1037189251Ssam return NULL; 1038189251Ssam } 1039189251Ssam 1040189251Ssam imv = os_zalloc(sizeof(*imv)); 1041189251Ssam if (imv == NULL) { 1042189251Ssam *error = 1; 1043189251Ssam return NULL; 1044189251Ssam } 1045189251Ssam 1046189251Ssam imv->imvID = id; 1047189251Ssam 1048189251Ssam pos = start; 1049189251Ssam wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos); 1050189251Ssam if (pos + 1 >= end || *pos != '"') { 1051189251Ssam wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " 1052189251Ssam "(no starting quotation mark)", start); 1053189251Ssam os_free(imv); 1054189251Ssam return NULL; 1055189251Ssam } 1056189251Ssam 1057189251Ssam pos++; 1058189251Ssam pos2 = pos; 1059189251Ssam while (pos2 < end && *pos2 != '"') 1060189251Ssam pos2++; 1061189251Ssam if (pos2 >= end) { 1062189251Ssam wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " 1063189251Ssam "(no ending quotation mark)", start); 1064189251Ssam os_free(imv); 1065189251Ssam return NULL; 1066189251Ssam } 1067189251Ssam *pos2 = '\0'; 1068189251Ssam wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos); 1069189251Ssam imv->name = os_strdup(pos); 1070189251Ssam 1071189251Ssam pos = pos2 + 1; 1072189251Ssam if (pos >= end || *pos != ' ') { 1073189251Ssam wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " 1074189251Ssam "(no space after name)", start); 1075189251Ssam os_free(imv); 1076189251Ssam return NULL; 1077189251Ssam } 1078189251Ssam 1079189251Ssam pos++; 1080189251Ssam wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos); 1081189251Ssam imv->path = os_strdup(pos); 1082189251Ssam 1083189251Ssam return imv; 1084189251Ssam} 1085189251Ssam 1086189251Ssam 1087189251Ssamstatic int tncs_read_config(struct tncs_global *global) 1088189251Ssam{ 1089189251Ssam char *config, *end, *pos, *line_end; 1090189251Ssam size_t config_len; 1091189251Ssam struct tnc_if_imv *imv, *last; 1092189251Ssam int id = 0; 1093189251Ssam 1094189251Ssam last = NULL; 1095189251Ssam 1096189251Ssam config = os_readfile(TNC_CONFIG_FILE, &config_len); 1097189251Ssam if (config == NULL) { 1098189251Ssam wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration " 1099189251Ssam "file '%s'", TNC_CONFIG_FILE); 1100189251Ssam return -1; 1101189251Ssam } 1102189251Ssam 1103189251Ssam end = config + config_len; 1104189251Ssam for (pos = config; pos < end; pos = line_end + 1) { 1105189251Ssam line_end = pos; 1106189251Ssam while (*line_end != '\n' && *line_end != '\r' && 1107189251Ssam line_end < end) 1108189251Ssam line_end++; 1109189251Ssam *line_end = '\0'; 1110189251Ssam 1111189251Ssam if (os_strncmp(pos, "IMV ", 4) == 0) { 1112189251Ssam int error = 0; 1113189251Ssam 1114189251Ssam imv = tncs_parse_imv(id++, pos + 4, line_end, &error); 1115189251Ssam if (error) 1116189251Ssam return -1; 1117189251Ssam if (imv) { 1118189251Ssam if (last == NULL) 1119189251Ssam global->imv = imv; 1120189251Ssam else 1121189251Ssam last->next = imv; 1122189251Ssam last = imv; 1123189251Ssam } 1124189251Ssam } 1125189251Ssam } 1126189251Ssam 1127189251Ssam os_free(config); 1128189251Ssam 1129189251Ssam return 0; 1130189251Ssam} 1131189251Ssam 1132189251Ssam 1133189251Ssamstruct tncs_data * tncs_init(void) 1134189251Ssam{ 1135189251Ssam struct tncs_data *tncs; 1136189251Ssam 1137189251Ssam if (tncs_global_data == NULL) 1138189251Ssam return NULL; 1139189251Ssam 1140189251Ssam tncs = os_zalloc(sizeof(*tncs)); 1141189251Ssam if (tncs == NULL) 1142189251Ssam return NULL; 1143189251Ssam tncs->imv = tncs_global_data->imv; 1144189251Ssam tncs->connectionID = tncs_global_data->next_conn_id++; 1145189251Ssam tncs->next = tncs_global_data->connections; 1146189251Ssam tncs_global_data->connections = tncs; 1147189251Ssam 1148189251Ssam return tncs; 1149189251Ssam} 1150189251Ssam 1151189251Ssam 1152189251Ssamvoid tncs_deinit(struct tncs_data *tncs) 1153189251Ssam{ 1154189251Ssam int i; 1155189251Ssam struct tncs_data *prev, *conn; 1156189251Ssam 1157189251Ssam if (tncs == NULL) 1158189251Ssam return; 1159189251Ssam 1160189251Ssam for (i = 0; i < TNC_MAX_IMV_ID; i++) 1161189251Ssam os_free(tncs->imv_data[i].imv_send); 1162189251Ssam 1163189251Ssam prev = NULL; 1164189251Ssam conn = tncs_global_data->connections; 1165189251Ssam while (conn) { 1166189251Ssam if (conn == tncs) { 1167189251Ssam if (prev) 1168189251Ssam prev->next = tncs->next; 1169189251Ssam else 1170189251Ssam tncs_global_data->connections = tncs->next; 1171189251Ssam break; 1172189251Ssam } 1173189251Ssam prev = conn; 1174189251Ssam conn = conn->next; 1175189251Ssam } 1176189251Ssam 1177189251Ssam os_free(tncs->tncs_message); 1178189251Ssam os_free(tncs); 1179189251Ssam} 1180189251Ssam 1181189251Ssam 1182189251Ssamint tncs_global_init(void) 1183189251Ssam{ 1184189251Ssam struct tnc_if_imv *imv; 1185189251Ssam 1186189251Ssam tncs_global_data = os_zalloc(sizeof(*tncs_global_data)); 1187189251Ssam if (tncs_global_data == NULL) 1188189251Ssam return -1; 1189189251Ssam 1190189251Ssam if (tncs_read_config(tncs_global_data) < 0) { 1191189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration"); 1192189251Ssam goto failed; 1193189251Ssam } 1194189251Ssam 1195189251Ssam for (imv = tncs_global_data->imv; imv; imv = imv->next) { 1196189251Ssam if (tncs_load_imv(imv)) { 1197189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'", 1198189251Ssam imv->name); 1199189251Ssam goto failed; 1200189251Ssam } 1201189251Ssam } 1202189251Ssam 1203189251Ssam return 0; 1204189251Ssam 1205189251Ssamfailed: 1206189251Ssam tncs_global_deinit(); 1207189251Ssam return -1; 1208189251Ssam} 1209189251Ssam 1210189251Ssam 1211189251Ssamvoid tncs_global_deinit(void) 1212189251Ssam{ 1213189251Ssam struct tnc_if_imv *imv, *prev; 1214189251Ssam 1215189251Ssam if (tncs_global_data == NULL) 1216189251Ssam return; 1217189251Ssam 1218189251Ssam imv = tncs_global_data->imv; 1219189251Ssam while (imv) { 1220189251Ssam tncs_unload_imv(imv); 1221189251Ssam 1222189251Ssam prev = imv; 1223189251Ssam imv = imv->next; 1224189251Ssam os_free(prev); 1225189251Ssam } 1226189251Ssam 1227189251Ssam os_free(tncs_global_data); 1228214734Srpaulo tncs_global_data = NULL; 1229189251Ssam} 1230189251Ssam 1231189251Ssam 1232189251Ssamstruct wpabuf * tncs_build_soh_request(void) 1233189251Ssam{ 1234189251Ssam struct wpabuf *buf; 1235189251Ssam 1236189251Ssam /* 1237189251Ssam * Build a SoH Request TLV (to be used inside SoH EAP Extensions 1238189251Ssam * Method) 1239189251Ssam */ 1240189251Ssam 1241189251Ssam buf = wpabuf_alloc(8 + 4); 1242189251Ssam if (buf == NULL) 1243189251Ssam return NULL; 1244189251Ssam 1245189251Ssam /* Vendor-Specific TLV (Microsoft) - SoH Request */ 1246189251Ssam wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */ 1247189251Ssam wpabuf_put_be16(buf, 8); /* Length */ 1248189251Ssam 1249189251Ssam wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */ 1250189251Ssam 1251189251Ssam wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */ 1252189251Ssam wpabuf_put_be16(buf, 0); /* Length */ 1253189251Ssam 1254189251Ssam return buf; 1255189251Ssam} 1256189251Ssam 1257189251Ssam 1258189251Ssamstruct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len, 1259189251Ssam int *failure) 1260189251Ssam{ 1261189251Ssam wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len); 1262189251Ssam *failure = 0; 1263189251Ssam 1264189251Ssam /* TODO: return MS-SoH Response TLV */ 1265189251Ssam 1266189251Ssam return NULL; 1267189251Ssam} 1268