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