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