1189251Ssam/* 2189251Ssam * EAP-TNC - TNCC (IF-IMC and IF-TNCCS) 3189251Ssam * Copyright (c) 2007, 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#ifndef CONFIG_NATIVE_WINDOWS 11189251Ssam#include <dlfcn.h> 12189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 13189251Ssam 14189251Ssam#include "common.h" 15189251Ssam#include "base64.h" 16189251Ssam#include "tncc.h" 17189251Ssam#include "eap_common/eap_tlv_common.h" 18189251Ssam#include "eap_common/eap_defs.h" 19189251Ssam 20189251Ssam 21189251Ssam#ifdef UNICODE 22189251Ssam#define TSTR "%S" 23189251Ssam#else /* UNICODE */ 24189251Ssam#define TSTR "%s" 25189251Ssam#endif /* UNICODE */ 26189251Ssam 27189251Ssam 28189251Ssam#define TNC_CONFIG_FILE "/etc/tnc_config" 29189251Ssam#define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs") 30189251Ssam#define IF_TNCCS_START \ 31189251Ssam"<?xml version=\"1.0\"?>\n" \ 32189251Ssam"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \ 33189251Ssam"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \ 34189251Ssam"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \ 35189251Ssam"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \ 36189251Ssam"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n" 37189251Ssam#define IF_TNCCS_END "\n</TNCCS-Batch>" 38189251Ssam 39189251Ssam/* TNC IF-IMC */ 40189251Ssam 41189251Ssamtypedef unsigned long TNC_UInt32; 42189251Ssamtypedef unsigned char *TNC_BufferReference; 43189251Ssam 44189251Ssamtypedef TNC_UInt32 TNC_IMCID; 45189251Ssamtypedef TNC_UInt32 TNC_ConnectionID; 46189251Ssamtypedef TNC_UInt32 TNC_ConnectionState; 47189251Ssamtypedef TNC_UInt32 TNC_RetryReason; 48189251Ssamtypedef TNC_UInt32 TNC_MessageType; 49189251Ssamtypedef TNC_MessageType *TNC_MessageTypeList; 50189251Ssamtypedef TNC_UInt32 TNC_VendorID; 51189251Ssamtypedef TNC_UInt32 TNC_MessageSubtype; 52189251Ssamtypedef TNC_UInt32 TNC_Version; 53189251Ssamtypedef TNC_UInt32 TNC_Result; 54189251Ssam 55189251Ssamtypedef TNC_Result (*TNC_TNCC_BindFunctionPointer)( 56189251Ssam TNC_IMCID imcID, 57189251Ssam char *functionName, 58189251Ssam void **pOutfunctionPointer); 59189251Ssam 60189251Ssam#define TNC_RESULT_SUCCESS 0 61189251Ssam#define TNC_RESULT_NOT_INITIALIZED 1 62189251Ssam#define TNC_RESULT_ALREADY_INITIALIZED 2 63189251Ssam#define TNC_RESULT_NO_COMMON_VERSION 3 64189251Ssam#define TNC_RESULT_CANT_RETRY 4 65189251Ssam#define TNC_RESULT_WONT_RETRY 5 66189251Ssam#define TNC_RESULT_INVALID_PARAMETER 6 67189251Ssam#define TNC_RESULT_CANT_RESPOND 7 68189251Ssam#define TNC_RESULT_ILLEGAL_OPERATION 8 69189251Ssam#define TNC_RESULT_OTHER 9 70189251Ssam#define TNC_RESULT_FATAL 10 71189251Ssam 72189251Ssam#define TNC_CONNECTION_STATE_CREATE 0 73189251Ssam#define TNC_CONNECTION_STATE_HANDSHAKE 1 74189251Ssam#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2 75189251Ssam#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3 76189251Ssam#define TNC_CONNECTION_STATE_ACCESS_NONE 4 77189251Ssam#define TNC_CONNECTION_STATE_DELETE 5 78189251Ssam 79189251Ssam#define TNC_IFIMC_VERSION_1 1 80189251Ssam 81189251Ssam#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff) 82189251Ssam#define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff) 83189251Ssam 84189251Ssam/* TNCC-TNCS Message Types */ 85189251Ssam#define TNC_TNCCS_RECOMMENDATION 0x00000001 86189251Ssam#define TNC_TNCCS_ERROR 0x00000002 87189251Ssam#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003 88189251Ssam#define TNC_TNCCS_REASONSTRINGS 0x00000004 89189251Ssam 90189251Ssam 91189251Ssam/* IF-TNCCS-SOH - SSoH and SSoHR Attributes */ 92189251Ssamenum { 93189251Ssam SSOH_MS_MACHINE_INVENTORY = 1, 94189251Ssam SSOH_MS_QUARANTINE_STATE = 2, 95189251Ssam SSOH_MS_PACKET_INFO = 3, 96189251Ssam SSOH_MS_SYSTEMGENERATED_IDS = 4, 97189251Ssam SSOH_MS_MACHINENAME = 5, 98189251Ssam SSOH_MS_CORRELATIONID = 6, 99189251Ssam SSOH_MS_INSTALLED_SHVS = 7, 100189251Ssam SSOH_MS_MACHINE_INVENTORY_EX = 8 101189251Ssam}; 102189251Ssam 103189251Ssamstruct tnc_if_imc { 104189251Ssam struct tnc_if_imc *next; 105189251Ssam char *name; 106189251Ssam char *path; 107189251Ssam void *dlhandle; /* from dlopen() */ 108189251Ssam TNC_IMCID imcID; 109189251Ssam TNC_ConnectionID connectionID; 110189251Ssam TNC_MessageTypeList supported_types; 111189251Ssam size_t num_supported_types; 112189251Ssam u8 *imc_send; 113189251Ssam size_t imc_send_len; 114189251Ssam 115189251Ssam /* Functions implemented by IMCs (with TNC_IMC_ prefix) */ 116189251Ssam TNC_Result (*Initialize)( 117189251Ssam TNC_IMCID imcID, 118189251Ssam TNC_Version minVersion, 119189251Ssam TNC_Version maxVersion, 120189251Ssam TNC_Version *pOutActualVersion); 121189251Ssam TNC_Result (*NotifyConnectionChange)( 122189251Ssam TNC_IMCID imcID, 123189251Ssam TNC_ConnectionID connectionID, 124189251Ssam TNC_ConnectionState newState); 125189251Ssam TNC_Result (*BeginHandshake)( 126189251Ssam TNC_IMCID imcID, 127189251Ssam TNC_ConnectionID connectionID); 128189251Ssam TNC_Result (*ReceiveMessage)( 129189251Ssam TNC_IMCID imcID, 130189251Ssam TNC_ConnectionID connectionID, 131189251Ssam TNC_BufferReference messageBuffer, 132189251Ssam TNC_UInt32 messageLength, 133189251Ssam TNC_MessageType messageType); 134189251Ssam TNC_Result (*BatchEnding)( 135189251Ssam TNC_IMCID imcID, 136189251Ssam TNC_ConnectionID connectionID); 137189251Ssam TNC_Result (*Terminate)(TNC_IMCID imcID); 138189251Ssam TNC_Result (*ProvideBindFunction)( 139189251Ssam TNC_IMCID imcID, 140189251Ssam TNC_TNCC_BindFunctionPointer bindFunction); 141189251Ssam}; 142189251Ssam 143189251Ssamstruct tncc_data { 144189251Ssam struct tnc_if_imc *imc; 145189251Ssam unsigned int last_batchid; 146189251Ssam}; 147189251Ssam 148189251Ssam#define TNC_MAX_IMC_ID 10 149189251Ssamstatic struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL }; 150189251Ssam 151189251Ssam 152189251Ssam/* TNCC functions that IMCs can call */ 153189251Ssam 154189251SsamTNC_Result TNC_TNCC_ReportMessageTypes( 155189251Ssam TNC_IMCID imcID, 156189251Ssam TNC_MessageTypeList supportedTypes, 157189251Ssam TNC_UInt32 typeCount) 158189251Ssam{ 159189251Ssam TNC_UInt32 i; 160189251Ssam struct tnc_if_imc *imc; 161189251Ssam 162189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu " 163189251Ssam "typeCount=%lu)", 164189251Ssam (unsigned long) imcID, (unsigned long) typeCount); 165189251Ssam 166189251Ssam for (i = 0; i < typeCount; i++) { 167189251Ssam wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu", 168189251Ssam i, supportedTypes[i]); 169189251Ssam } 170189251Ssam 171189251Ssam if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) 172189251Ssam return TNC_RESULT_INVALID_PARAMETER; 173189251Ssam 174189251Ssam imc = tnc_imc[imcID]; 175189251Ssam os_free(imc->supported_types); 176189251Ssam imc->supported_types = 177252726Srpaulo os_malloc(typeCount * sizeof(TNC_MessageType)); 178189251Ssam if (imc->supported_types == NULL) 179189251Ssam return TNC_RESULT_FATAL; 180189251Ssam os_memcpy(imc->supported_types, supportedTypes, 181252726Srpaulo typeCount * sizeof(TNC_MessageType)); 182189251Ssam imc->num_supported_types = typeCount; 183189251Ssam 184189251Ssam return TNC_RESULT_SUCCESS; 185189251Ssam} 186189251Ssam 187189251Ssam 188189251SsamTNC_Result TNC_TNCC_SendMessage( 189189251Ssam TNC_IMCID imcID, 190189251Ssam TNC_ConnectionID connectionID, 191189251Ssam TNC_BufferReference message, 192189251Ssam TNC_UInt32 messageLength, 193189251Ssam TNC_MessageType messageType) 194189251Ssam{ 195189251Ssam struct tnc_if_imc *imc; 196189251Ssam unsigned char *b64; 197189251Ssam size_t b64len; 198189251Ssam 199189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu " 200189251Ssam "connectionID=%lu messageType=%lu)", 201189251Ssam imcID, connectionID, messageType); 202189251Ssam wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage", 203189251Ssam message, messageLength); 204189251Ssam 205189251Ssam if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) 206189251Ssam return TNC_RESULT_INVALID_PARAMETER; 207189251Ssam 208189251Ssam b64 = base64_encode(message, messageLength, &b64len); 209189251Ssam if (b64 == NULL) 210189251Ssam return TNC_RESULT_FATAL; 211189251Ssam 212189251Ssam imc = tnc_imc[imcID]; 213189251Ssam os_free(imc->imc_send); 214189251Ssam imc->imc_send_len = 0; 215189251Ssam imc->imc_send = os_zalloc(b64len + 100); 216189251Ssam if (imc->imc_send == NULL) { 217189251Ssam os_free(b64); 218189251Ssam return TNC_RESULT_OTHER; 219189251Ssam } 220189251Ssam 221189251Ssam imc->imc_send_len = 222189251Ssam os_snprintf((char *) imc->imc_send, b64len + 100, 223189251Ssam "<IMC-IMV-Message><Type>%08X</Type>" 224189251Ssam "<Base64>%s</Base64></IMC-IMV-Message>", 225189251Ssam (unsigned int) messageType, b64); 226189251Ssam 227189251Ssam os_free(b64); 228189251Ssam 229189251Ssam return TNC_RESULT_SUCCESS; 230189251Ssam} 231189251Ssam 232189251Ssam 233189251SsamTNC_Result TNC_TNCC_RequestHandshakeRetry( 234189251Ssam TNC_IMCID imcID, 235189251Ssam TNC_ConnectionID connectionID, 236189251Ssam TNC_RetryReason reason) 237189251Ssam{ 238189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry"); 239189251Ssam 240189251Ssam if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) 241189251Ssam return TNC_RESULT_INVALID_PARAMETER; 242189251Ssam 243189251Ssam /* 244189251Ssam * TODO: trigger a call to eapol_sm_request_reauth(). This would 245189251Ssam * require that the IMC continues to be loaded in memory afer 246189251Ssam * authentication.. 247189251Ssam */ 248189251Ssam 249189251Ssam return TNC_RESULT_SUCCESS; 250189251Ssam} 251189251Ssam 252189251Ssam 253189251SsamTNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity, 254189251Ssam const char *message) 255189251Ssam{ 256189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu " 257189251Ssam "severity==%lu message='%s')", 258189251Ssam imcID, severity, message); 259189251Ssam return TNC_RESULT_SUCCESS; 260189251Ssam} 261189251Ssam 262189251Ssam 263189251SsamTNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID, 264189251Ssam const char *message) 265189251Ssam{ 266189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu " 267189251Ssam "connectionID==%lu message='%s')", 268189251Ssam imcID, connectionID, message); 269189251Ssam return TNC_RESULT_SUCCESS; 270189251Ssam} 271189251Ssam 272189251Ssam 273189251SsamTNC_Result TNC_TNCC_BindFunction( 274189251Ssam TNC_IMCID imcID, 275189251Ssam char *functionName, 276189251Ssam void **pOutfunctionPointer) 277189251Ssam{ 278189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, " 279189251Ssam "functionName='%s')", (unsigned long) imcID, functionName); 280189251Ssam 281189251Ssam if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) 282189251Ssam return TNC_RESULT_INVALID_PARAMETER; 283189251Ssam 284189251Ssam if (pOutfunctionPointer == NULL) 285189251Ssam return TNC_RESULT_INVALID_PARAMETER; 286189251Ssam 287189251Ssam if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0) 288189251Ssam *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes; 289189251Ssam else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0) 290189251Ssam *pOutfunctionPointer = TNC_TNCC_SendMessage; 291189251Ssam else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") == 292189251Ssam 0) 293189251Ssam *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry; 294189251Ssam else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0) 295189251Ssam *pOutfunctionPointer = TNC_9048_LogMessage; 296189251Ssam else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0) 297189251Ssam *pOutfunctionPointer = TNC_9048_UserMessage; 298189251Ssam else 299189251Ssam *pOutfunctionPointer = NULL; 300189251Ssam 301189251Ssam return TNC_RESULT_SUCCESS; 302189251Ssam} 303189251Ssam 304189251Ssam 305189251Ssamstatic void * tncc_get_sym(void *handle, char *func) 306189251Ssam{ 307189251Ssam void *fptr; 308189251Ssam 309189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 310189251Ssam#ifdef _WIN32_WCE 311189251Ssam fptr = GetProcAddressA(handle, func); 312189251Ssam#else /* _WIN32_WCE */ 313189251Ssam fptr = GetProcAddress(handle, func); 314189251Ssam#endif /* _WIN32_WCE */ 315189251Ssam#else /* CONFIG_NATIVE_WINDOWS */ 316189251Ssam fptr = dlsym(handle, func); 317189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 318189251Ssam 319189251Ssam return fptr; 320189251Ssam} 321189251Ssam 322189251Ssam 323189251Ssamstatic int tncc_imc_resolve_funcs(struct tnc_if_imc *imc) 324189251Ssam{ 325189251Ssam void *handle = imc->dlhandle; 326189251Ssam 327189251Ssam /* Mandatory IMC functions */ 328189251Ssam imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize"); 329189251Ssam if (imc->Initialize == NULL) { 330189251Ssam wpa_printf(MSG_ERROR, "TNC: IMC does not export " 331189251Ssam "TNC_IMC_Initialize"); 332189251Ssam return -1; 333189251Ssam } 334189251Ssam 335189251Ssam imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake"); 336189251Ssam if (imc->BeginHandshake == NULL) { 337189251Ssam wpa_printf(MSG_ERROR, "TNC: IMC does not export " 338189251Ssam "TNC_IMC_BeginHandshake"); 339189251Ssam return -1; 340189251Ssam } 341189251Ssam 342189251Ssam imc->ProvideBindFunction = 343189251Ssam tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction"); 344189251Ssam if (imc->ProvideBindFunction == NULL) { 345189251Ssam wpa_printf(MSG_ERROR, "TNC: IMC does not export " 346189251Ssam "TNC_IMC_ProvideBindFunction"); 347189251Ssam return -1; 348189251Ssam } 349189251Ssam 350189251Ssam /* Optional IMC functions */ 351189251Ssam imc->NotifyConnectionChange = 352189251Ssam tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange"); 353189251Ssam imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage"); 354189251Ssam imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding"); 355189251Ssam imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate"); 356189251Ssam 357189251Ssam return 0; 358189251Ssam} 359189251Ssam 360189251Ssam 361189251Ssamstatic int tncc_imc_initialize(struct tnc_if_imc *imc) 362189251Ssam{ 363189251Ssam TNC_Result res; 364189251Ssam TNC_Version imc_ver; 365189251Ssam 366189251Ssam wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'", 367189251Ssam imc->name); 368189251Ssam res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1, 369189251Ssam TNC_IFIMC_VERSION_1, &imc_ver); 370189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu", 371189251Ssam (unsigned long) res, (unsigned long) imc_ver); 372189251Ssam 373189251Ssam return res == TNC_RESULT_SUCCESS ? 0 : -1; 374189251Ssam} 375189251Ssam 376189251Ssam 377189251Ssamstatic int tncc_imc_terminate(struct tnc_if_imc *imc) 378189251Ssam{ 379189251Ssam TNC_Result res; 380189251Ssam 381189251Ssam if (imc->Terminate == NULL) 382189251Ssam return 0; 383189251Ssam 384189251Ssam wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'", 385189251Ssam imc->name); 386189251Ssam res = imc->Terminate(imc->imcID); 387189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu", 388189251Ssam (unsigned long) res); 389189251Ssam 390189251Ssam return res == TNC_RESULT_SUCCESS ? 0 : -1; 391189251Ssam} 392189251Ssam 393189251Ssam 394189251Ssamstatic int tncc_imc_provide_bind_function(struct tnc_if_imc *imc) 395189251Ssam{ 396189251Ssam TNC_Result res; 397189251Ssam 398189251Ssam wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for " 399189251Ssam "IMC '%s'", imc->name); 400189251Ssam res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction); 401189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu", 402189251Ssam (unsigned long) res); 403189251Ssam 404189251Ssam return res == TNC_RESULT_SUCCESS ? 0 : -1; 405189251Ssam} 406189251Ssam 407189251Ssam 408189251Ssamstatic int tncc_imc_notify_connection_change(struct tnc_if_imc *imc, 409189251Ssam TNC_ConnectionState state) 410189251Ssam{ 411189251Ssam TNC_Result res; 412189251Ssam 413189251Ssam if (imc->NotifyConnectionChange == NULL) 414189251Ssam return 0; 415189251Ssam 416189251Ssam wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)" 417189251Ssam " for IMC '%s'", (int) state, imc->name); 418189251Ssam res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID, 419189251Ssam state); 420189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu", 421189251Ssam (unsigned long) res); 422189251Ssam 423189251Ssam return res == TNC_RESULT_SUCCESS ? 0 : -1; 424189251Ssam} 425189251Ssam 426189251Ssam 427189251Ssamstatic int tncc_imc_begin_handshake(struct tnc_if_imc *imc) 428189251Ssam{ 429189251Ssam TNC_Result res; 430189251Ssam 431189251Ssam wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC " 432189251Ssam "'%s'", imc->name); 433189251Ssam res = imc->BeginHandshake(imc->imcID, imc->connectionID); 434189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu", 435189251Ssam (unsigned long) res); 436189251Ssam 437189251Ssam return res == TNC_RESULT_SUCCESS ? 0 : -1; 438189251Ssam} 439189251Ssam 440189251Ssam 441189251Ssamstatic int tncc_load_imc(struct tnc_if_imc *imc) 442189251Ssam{ 443189251Ssam if (imc->path == NULL) { 444189251Ssam wpa_printf(MSG_DEBUG, "TNC: No IMC configured"); 445189251Ssam return -1; 446189251Ssam } 447189251Ssam 448189251Ssam wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)", 449189251Ssam imc->name, imc->path); 450189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 451189251Ssam#ifdef UNICODE 452189251Ssam { 453189251Ssam TCHAR *lib = wpa_strdup_tchar(imc->path); 454189251Ssam if (lib == NULL) 455189251Ssam return -1; 456189251Ssam imc->dlhandle = LoadLibrary(lib); 457189251Ssam os_free(lib); 458189251Ssam } 459189251Ssam#else /* UNICODE */ 460189251Ssam imc->dlhandle = LoadLibrary(imc->path); 461189251Ssam#endif /* UNICODE */ 462189251Ssam if (imc->dlhandle == NULL) { 463189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d", 464189251Ssam imc->name, imc->path, (int) GetLastError()); 465189251Ssam return -1; 466189251Ssam } 467189251Ssam#else /* CONFIG_NATIVE_WINDOWS */ 468189251Ssam imc->dlhandle = dlopen(imc->path, RTLD_LAZY); 469189251Ssam if (imc->dlhandle == NULL) { 470189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s", 471189251Ssam imc->name, imc->path, dlerror()); 472189251Ssam return -1; 473189251Ssam } 474189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 475189251Ssam 476189251Ssam if (tncc_imc_resolve_funcs(imc) < 0) { 477189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions"); 478189251Ssam return -1; 479189251Ssam } 480189251Ssam 481189251Ssam if (tncc_imc_initialize(imc) < 0 || 482189251Ssam tncc_imc_provide_bind_function(imc) < 0) { 483189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC"); 484189251Ssam return -1; 485189251Ssam } 486189251Ssam 487189251Ssam return 0; 488189251Ssam} 489189251Ssam 490189251Ssam 491189251Ssamstatic void tncc_unload_imc(struct tnc_if_imc *imc) 492189251Ssam{ 493189251Ssam tncc_imc_terminate(imc); 494189251Ssam tnc_imc[imc->imcID] = NULL; 495189251Ssam 496189251Ssam if (imc->dlhandle) { 497189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 498189251Ssam FreeLibrary(imc->dlhandle); 499189251Ssam#else /* CONFIG_NATIVE_WINDOWS */ 500189251Ssam dlclose(imc->dlhandle); 501189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 502189251Ssam } 503189251Ssam os_free(imc->name); 504189251Ssam os_free(imc->path); 505189251Ssam os_free(imc->supported_types); 506189251Ssam os_free(imc->imc_send); 507189251Ssam} 508189251Ssam 509189251Ssam 510189251Ssamstatic int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type) 511189251Ssam{ 512189251Ssam size_t i; 513189251Ssam unsigned int vendor, subtype; 514189251Ssam 515189251Ssam if (imc == NULL || imc->supported_types == NULL) 516189251Ssam return 0; 517189251Ssam 518189251Ssam vendor = type >> 8; 519189251Ssam subtype = type & 0xff; 520189251Ssam 521189251Ssam for (i = 0; i < imc->num_supported_types; i++) { 522189251Ssam unsigned int svendor, ssubtype; 523189251Ssam svendor = imc->supported_types[i] >> 8; 524189251Ssam ssubtype = imc->supported_types[i] & 0xff; 525189251Ssam if ((vendor == svendor || svendor == TNC_VENDORID_ANY) && 526189251Ssam (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY)) 527189251Ssam return 1; 528189251Ssam } 529189251Ssam 530189251Ssam return 0; 531189251Ssam} 532189251Ssam 533189251Ssam 534189251Ssamstatic void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type, 535189251Ssam const u8 *msg, size_t len) 536189251Ssam{ 537189251Ssam struct tnc_if_imc *imc; 538189251Ssam TNC_Result res; 539189251Ssam 540189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len); 541189251Ssam 542189251Ssam for (imc = tncc->imc; imc; imc = imc->next) { 543189251Ssam if (imc->ReceiveMessage == NULL || 544189251Ssam !tncc_supported_type(imc, type)) 545189251Ssam continue; 546189251Ssam 547189251Ssam wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'", 548189251Ssam imc->name); 549189251Ssam res = imc->ReceiveMessage(imc->imcID, imc->connectionID, 550189251Ssam (TNC_BufferReference) msg, len, 551189251Ssam type); 552189251Ssam wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu", 553189251Ssam (unsigned long) res); 554189251Ssam } 555189251Ssam} 556189251Ssam 557189251Ssam 558189251Ssamvoid tncc_init_connection(struct tncc_data *tncc) 559189251Ssam{ 560189251Ssam struct tnc_if_imc *imc; 561189251Ssam 562189251Ssam for (imc = tncc->imc; imc; imc = imc->next) { 563189251Ssam tncc_imc_notify_connection_change( 564189251Ssam imc, TNC_CONNECTION_STATE_CREATE); 565189251Ssam tncc_imc_notify_connection_change( 566189251Ssam imc, TNC_CONNECTION_STATE_HANDSHAKE); 567189251Ssam 568189251Ssam os_free(imc->imc_send); 569189251Ssam imc->imc_send = NULL; 570189251Ssam imc->imc_send_len = 0; 571189251Ssam 572189251Ssam tncc_imc_begin_handshake(imc); 573189251Ssam } 574189251Ssam} 575189251Ssam 576189251Ssam 577189251Ssamsize_t tncc_total_send_len(struct tncc_data *tncc) 578189251Ssam{ 579189251Ssam struct tnc_if_imc *imc; 580189251Ssam 581189251Ssam size_t len = 0; 582189251Ssam for (imc = tncc->imc; imc; imc = imc->next) 583189251Ssam len += imc->imc_send_len; 584189251Ssam return len; 585189251Ssam} 586189251Ssam 587189251Ssam 588189251Ssamu8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos) 589189251Ssam{ 590189251Ssam struct tnc_if_imc *imc; 591189251Ssam 592189251Ssam for (imc = tncc->imc; imc; imc = imc->next) { 593189251Ssam if (imc->imc_send == NULL) 594189251Ssam continue; 595189251Ssam 596189251Ssam os_memcpy(pos, imc->imc_send, imc->imc_send_len); 597189251Ssam pos += imc->imc_send_len; 598189251Ssam os_free(imc->imc_send); 599189251Ssam imc->imc_send = NULL; 600189251Ssam imc->imc_send_len = 0; 601189251Ssam } 602189251Ssam 603189251Ssam return pos; 604189251Ssam} 605189251Ssam 606189251Ssam 607189251Ssamchar * tncc_if_tnccs_start(struct tncc_data *tncc) 608189251Ssam{ 609189251Ssam char *buf = os_malloc(1000); 610189251Ssam if (buf == NULL) 611189251Ssam return NULL; 612189251Ssam tncc->last_batchid++; 613189251Ssam os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid); 614189251Ssam return buf; 615189251Ssam} 616189251Ssam 617189251Ssam 618189251Ssamchar * tncc_if_tnccs_end(void) 619189251Ssam{ 620189251Ssam char *buf = os_malloc(100); 621189251Ssam if (buf == NULL) 622189251Ssam return NULL; 623189251Ssam os_snprintf(buf, 100, IF_TNCCS_END); 624189251Ssam return buf; 625189251Ssam} 626189251Ssam 627189251Ssam 628189251Ssamstatic void tncc_notify_recommendation(struct tncc_data *tncc, 629189251Ssam enum tncc_process_res res) 630189251Ssam{ 631189251Ssam TNC_ConnectionState state; 632189251Ssam struct tnc_if_imc *imc; 633189251Ssam 634189251Ssam switch (res) { 635189251Ssam case TNCCS_RECOMMENDATION_ALLOW: 636189251Ssam state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; 637189251Ssam break; 638189251Ssam case TNCCS_RECOMMENDATION_NONE: 639189251Ssam state = TNC_CONNECTION_STATE_ACCESS_NONE; 640189251Ssam break; 641189251Ssam case TNCCS_RECOMMENDATION_ISOLATE: 642189251Ssam state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; 643189251Ssam break; 644189251Ssam default: 645189251Ssam state = TNC_CONNECTION_STATE_ACCESS_NONE; 646189251Ssam break; 647189251Ssam } 648189251Ssam 649189251Ssam for (imc = tncc->imc; imc; imc = imc->next) 650189251Ssam tncc_imc_notify_connection_change(imc, state); 651189251Ssam} 652189251Ssam 653189251Ssam 654189251Ssamstatic int tncc_get_type(char *start, unsigned int *type) 655189251Ssam{ 656189251Ssam char *pos = os_strstr(start, "<Type>"); 657189251Ssam if (pos == NULL) 658189251Ssam return -1; 659189251Ssam pos += 6; 660189251Ssam *type = strtoul(pos, NULL, 16); 661189251Ssam return 0; 662189251Ssam} 663189251Ssam 664189251Ssam 665189251Ssamstatic unsigned char * tncc_get_base64(char *start, size_t *decoded_len) 666189251Ssam{ 667189251Ssam char *pos, *pos2; 668189251Ssam unsigned char *decoded; 669189251Ssam 670189251Ssam pos = os_strstr(start, "<Base64>"); 671189251Ssam if (pos == NULL) 672189251Ssam return NULL; 673189251Ssam 674189251Ssam pos += 8; 675189251Ssam pos2 = os_strstr(pos, "</Base64>"); 676189251Ssam if (pos2 == NULL) 677189251Ssam return NULL; 678189251Ssam *pos2 = '\0'; 679189251Ssam 680189251Ssam decoded = base64_decode((unsigned char *) pos, os_strlen(pos), 681189251Ssam decoded_len); 682189251Ssam *pos2 = '<'; 683189251Ssam if (decoded == NULL) { 684189251Ssam wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data"); 685189251Ssam } 686189251Ssam 687189251Ssam return decoded; 688189251Ssam} 689189251Ssam 690189251Ssam 691189251Ssamstatic enum tncc_process_res tncc_get_recommendation(char *start) 692189251Ssam{ 693189251Ssam char *pos, *pos2, saved; 694189251Ssam int recom; 695189251Ssam 696189251Ssam pos = os_strstr(start, "<TNCCS-Recommendation "); 697189251Ssam if (pos == NULL) 698189251Ssam return TNCCS_RECOMMENDATION_ERROR; 699189251Ssam 700189251Ssam pos += 21; 701189251Ssam pos = os_strstr(pos, " type="); 702189251Ssam if (pos == NULL) 703189251Ssam return TNCCS_RECOMMENDATION_ERROR; 704189251Ssam pos += 6; 705189251Ssam 706189251Ssam if (*pos == '"') 707189251Ssam pos++; 708189251Ssam 709189251Ssam pos2 = pos; 710189251Ssam while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>') 711189251Ssam pos2++; 712189251Ssam 713189251Ssam if (*pos2 == '\0') 714189251Ssam return TNCCS_RECOMMENDATION_ERROR; 715189251Ssam 716189251Ssam saved = *pos2; 717189251Ssam *pos2 = '\0'; 718189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos); 719189251Ssam 720189251Ssam recom = TNCCS_RECOMMENDATION_ERROR; 721189251Ssam if (os_strcmp(pos, "allow") == 0) 722189251Ssam recom = TNCCS_RECOMMENDATION_ALLOW; 723189251Ssam else if (os_strcmp(pos, "none") == 0) 724189251Ssam recom = TNCCS_RECOMMENDATION_NONE; 725189251Ssam else if (os_strcmp(pos, "isolate") == 0) 726189251Ssam recom = TNCCS_RECOMMENDATION_ISOLATE; 727189251Ssam 728189251Ssam *pos2 = saved; 729189251Ssam 730189251Ssam return recom; 731189251Ssam} 732189251Ssam 733189251Ssam 734189251Ssamenum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc, 735189251Ssam const u8 *msg, size_t len) 736189251Ssam{ 737189251Ssam char *buf, *start, *end, *pos, *pos2, *payload; 738189251Ssam unsigned int batch_id; 739189251Ssam unsigned char *decoded; 740189251Ssam size_t decoded_len; 741189251Ssam enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION; 742189251Ssam int recommendation_msg = 0; 743189251Ssam 744189251Ssam buf = os_malloc(len + 1); 745189251Ssam if (buf == NULL) 746189251Ssam return TNCCS_PROCESS_ERROR; 747189251Ssam 748189251Ssam os_memcpy(buf, msg, len); 749189251Ssam buf[len] = '\0'; 750189251Ssam start = os_strstr(buf, "<TNCCS-Batch "); 751189251Ssam end = os_strstr(buf, "</TNCCS-Batch>"); 752189251Ssam if (start == NULL || end == NULL || start > end) { 753189251Ssam os_free(buf); 754189251Ssam return TNCCS_PROCESS_ERROR; 755189251Ssam } 756189251Ssam 757189251Ssam start += 13; 758189251Ssam while (*start == ' ') 759189251Ssam start++; 760189251Ssam *end = '\0'; 761189251Ssam 762189251Ssam pos = os_strstr(start, "BatchId="); 763189251Ssam if (pos == NULL) { 764189251Ssam os_free(buf); 765189251Ssam return TNCCS_PROCESS_ERROR; 766189251Ssam } 767189251Ssam 768189251Ssam pos += 8; 769189251Ssam if (*pos == '"') 770189251Ssam pos++; 771189251Ssam batch_id = atoi(pos); 772189251Ssam wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u", 773189251Ssam batch_id); 774189251Ssam if (batch_id != tncc->last_batchid + 1) { 775189251Ssam wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId " 776189251Ssam "%u (expected %u)", 777189251Ssam batch_id, tncc->last_batchid + 1); 778189251Ssam os_free(buf); 779189251Ssam return TNCCS_PROCESS_ERROR; 780189251Ssam } 781189251Ssam tncc->last_batchid = batch_id; 782189251Ssam 783189251Ssam while (*pos != '\0' && *pos != '>') 784189251Ssam pos++; 785189251Ssam if (*pos == '\0') { 786189251Ssam os_free(buf); 787189251Ssam return TNCCS_PROCESS_ERROR; 788189251Ssam } 789189251Ssam pos++; 790189251Ssam payload = start; 791189251Ssam 792189251Ssam /* 793189251Ssam * <IMC-IMV-Message> 794189251Ssam * <Type>01234567</Type> 795189251Ssam * <Base64>foo==</Base64> 796189251Ssam * </IMC-IMV-Message> 797189251Ssam */ 798189251Ssam 799189251Ssam while (*start) { 800189251Ssam char *endpos; 801189251Ssam unsigned int type; 802189251Ssam 803189251Ssam pos = os_strstr(start, "<IMC-IMV-Message>"); 804189251Ssam if (pos == NULL) 805189251Ssam break; 806189251Ssam start = pos + 17; 807189251Ssam end = os_strstr(start, "</IMC-IMV-Message>"); 808189251Ssam if (end == NULL) 809189251Ssam break; 810189251Ssam *end = '\0'; 811189251Ssam endpos = end; 812189251Ssam end += 18; 813189251Ssam 814189251Ssam if (tncc_get_type(start, &type) < 0) { 815189251Ssam *endpos = '<'; 816189251Ssam start = end; 817189251Ssam continue; 818189251Ssam } 819189251Ssam wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type); 820189251Ssam 821189251Ssam decoded = tncc_get_base64(start, &decoded_len); 822189251Ssam if (decoded == NULL) { 823189251Ssam *endpos = '<'; 824189251Ssam start = end; 825189251Ssam continue; 826189251Ssam } 827189251Ssam 828189251Ssam tncc_send_to_imcs(tncc, type, decoded, decoded_len); 829189251Ssam 830189251Ssam os_free(decoded); 831189251Ssam 832189251Ssam start = end; 833189251Ssam } 834189251Ssam 835189251Ssam /* 836189251Ssam * <TNCC-TNCS-Message> 837189251Ssam * <Type>01234567</Type> 838189251Ssam * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML> 839189251Ssam * <Base64>foo==</Base64> 840189251Ssam * </TNCC-TNCS-Message> 841189251Ssam */ 842189251Ssam 843189251Ssam start = payload; 844189251Ssam while (*start) { 845189251Ssam unsigned int type; 846189251Ssam char *xml, *xmlend, *endpos; 847189251Ssam 848189251Ssam pos = os_strstr(start, "<TNCC-TNCS-Message>"); 849189251Ssam if (pos == NULL) 850189251Ssam break; 851189251Ssam start = pos + 19; 852189251Ssam end = os_strstr(start, "</TNCC-TNCS-Message>"); 853189251Ssam if (end == NULL) 854189251Ssam break; 855189251Ssam *end = '\0'; 856189251Ssam endpos = end; 857189251Ssam end += 20; 858189251Ssam 859189251Ssam if (tncc_get_type(start, &type) < 0) { 860189251Ssam *endpos = '<'; 861189251Ssam start = end; 862189251Ssam continue; 863189251Ssam } 864189251Ssam wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x", 865189251Ssam type); 866189251Ssam 867189251Ssam /* Base64 OR XML */ 868189251Ssam decoded = NULL; 869189251Ssam xml = NULL; 870189251Ssam xmlend = NULL; 871189251Ssam pos = os_strstr(start, "<XML>"); 872189251Ssam if (pos) { 873189251Ssam pos += 5; 874189251Ssam pos2 = os_strstr(pos, "</XML>"); 875189251Ssam if (pos2 == NULL) { 876189251Ssam *endpos = '<'; 877189251Ssam start = end; 878189251Ssam continue; 879189251Ssam } 880189251Ssam xmlend = pos2; 881189251Ssam xml = pos; 882189251Ssam } else { 883189251Ssam decoded = tncc_get_base64(start, &decoded_len); 884189251Ssam if (decoded == NULL) { 885189251Ssam *endpos = '<'; 886189251Ssam start = end; 887189251Ssam continue; 888189251Ssam } 889189251Ssam } 890189251Ssam 891189251Ssam if (decoded) { 892189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, 893189251Ssam "TNC: TNCC-TNCS-Message Base64", 894189251Ssam decoded, decoded_len); 895189251Ssam os_free(decoded); 896189251Ssam } 897189251Ssam 898189251Ssam if (xml) { 899189251Ssam wpa_hexdump_ascii(MSG_MSGDUMP, 900189251Ssam "TNC: TNCC-TNCS-Message XML", 901189251Ssam (unsigned char *) xml, 902189251Ssam xmlend - xml); 903189251Ssam } 904189251Ssam 905189251Ssam if (type == TNC_TNCCS_RECOMMENDATION && xml) { 906189251Ssam /* 907189251Ssam * <TNCCS-Recommendation type="allow"> 908189251Ssam * </TNCCS-Recommendation> 909189251Ssam */ 910189251Ssam *xmlend = '\0'; 911189251Ssam res = tncc_get_recommendation(xml); 912189251Ssam *xmlend = '<'; 913189251Ssam recommendation_msg = 1; 914189251Ssam } 915189251Ssam 916189251Ssam start = end; 917189251Ssam } 918189251Ssam 919189251Ssam os_free(buf); 920189251Ssam 921189251Ssam if (recommendation_msg) 922189251Ssam tncc_notify_recommendation(tncc, res); 923189251Ssam 924189251Ssam return res; 925189251Ssam} 926189251Ssam 927189251Ssam 928189251Ssam#ifdef CONFIG_NATIVE_WINDOWS 929189251Ssamstatic int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive) 930189251Ssam{ 931189251Ssam HKEY hk, hk2; 932189251Ssam LONG ret; 933189251Ssam DWORD i; 934189251Ssam struct tnc_if_imc *imc, *last; 935189251Ssam int j; 936189251Ssam 937189251Ssam last = tncc->imc; 938189251Ssam while (last && last->next) 939189251Ssam last = last->next; 940189251Ssam 941189251Ssam ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS, 942189251Ssam &hk); 943189251Ssam if (ret != ERROR_SUCCESS) 944189251Ssam return 0; 945189251Ssam 946189251Ssam for (i = 0; ; i++) { 947189251Ssam TCHAR name[255], *val; 948189251Ssam DWORD namelen, buflen; 949189251Ssam 950189251Ssam namelen = 255; 951189251Ssam ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL, 952189251Ssam NULL); 953189251Ssam 954189251Ssam if (ret == ERROR_NO_MORE_ITEMS) 955189251Ssam break; 956189251Ssam 957189251Ssam if (ret != ERROR_SUCCESS) { 958189251Ssam wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x", 959189251Ssam (unsigned int) ret); 960189251Ssam break; 961189251Ssam } 962189251Ssam 963189251Ssam if (namelen >= 255) 964189251Ssam namelen = 255 - 1; 965189251Ssam name[namelen] = '\0'; 966189251Ssam 967189251Ssam wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name); 968189251Ssam 969189251Ssam ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2); 970189251Ssam if (ret != ERROR_SUCCESS) { 971189251Ssam wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR 972189251Ssam "'", name); 973189251Ssam continue; 974189251Ssam } 975189251Ssam 976189251Ssam ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL, 977189251Ssam &buflen); 978189251Ssam if (ret != ERROR_SUCCESS) { 979189251Ssam wpa_printf(MSG_DEBUG, "TNC: Could not read Path from " 980189251Ssam "IMC key '" TSTR "'", name); 981189251Ssam RegCloseKey(hk2); 982189251Ssam continue; 983189251Ssam } 984189251Ssam 985189251Ssam val = os_malloc(buflen); 986189251Ssam if (val == NULL) { 987189251Ssam RegCloseKey(hk2); 988189251Ssam continue; 989189251Ssam } 990189251Ssam 991189251Ssam ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, 992189251Ssam (LPBYTE) val, &buflen); 993189251Ssam if (ret != ERROR_SUCCESS) { 994189251Ssam os_free(val); 995189251Ssam RegCloseKey(hk2); 996189251Ssam continue; 997189251Ssam } 998189251Ssam 999189251Ssam RegCloseKey(hk2); 1000189251Ssam 1001189251Ssam wpa_unicode2ascii_inplace(val); 1002189251Ssam wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val); 1003189251Ssam 1004189251Ssam for (j = 0; j < TNC_MAX_IMC_ID; j++) { 1005189251Ssam if (tnc_imc[j] == NULL) 1006189251Ssam break; 1007189251Ssam } 1008189251Ssam if (j >= TNC_MAX_IMC_ID) { 1009189251Ssam wpa_printf(MSG_DEBUG, "TNC: Too many IMCs"); 1010189251Ssam os_free(val); 1011189251Ssam continue; 1012189251Ssam } 1013189251Ssam 1014189251Ssam imc = os_zalloc(sizeof(*imc)); 1015189251Ssam if (imc == NULL) { 1016189251Ssam os_free(val); 1017189251Ssam break; 1018189251Ssam } 1019189251Ssam 1020189251Ssam imc->imcID = j; 1021189251Ssam 1022189251Ssam wpa_unicode2ascii_inplace(name); 1023189251Ssam imc->name = os_strdup((char *) name); 1024189251Ssam imc->path = os_strdup((char *) val); 1025189251Ssam 1026189251Ssam os_free(val); 1027189251Ssam 1028189251Ssam if (last == NULL) 1029189251Ssam tncc->imc = imc; 1030189251Ssam else 1031189251Ssam last->next = imc; 1032189251Ssam last = imc; 1033189251Ssam 1034189251Ssam tnc_imc[imc->imcID] = imc; 1035189251Ssam } 1036189251Ssam 1037189251Ssam RegCloseKey(hk); 1038189251Ssam 1039189251Ssam return 0; 1040189251Ssam} 1041189251Ssam 1042189251Ssam 1043189251Ssamstatic int tncc_read_config(struct tncc_data *tncc) 1044189251Ssam{ 1045189251Ssam if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 || 1046189251Ssam tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0) 1047189251Ssam return -1; 1048189251Ssam return 0; 1049189251Ssam} 1050189251Ssam 1051189251Ssam#else /* CONFIG_NATIVE_WINDOWS */ 1052189251Ssam 1053189251Ssamstatic struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error) 1054189251Ssam{ 1055189251Ssam struct tnc_if_imc *imc; 1056189251Ssam char *pos, *pos2; 1057189251Ssam int i; 1058189251Ssam 1059189251Ssam for (i = 0; i < TNC_MAX_IMC_ID; i++) { 1060189251Ssam if (tnc_imc[i] == NULL) 1061189251Ssam break; 1062189251Ssam } 1063189251Ssam if (i >= TNC_MAX_IMC_ID) { 1064189251Ssam wpa_printf(MSG_DEBUG, "TNC: Too many IMCs"); 1065189251Ssam return NULL; 1066189251Ssam } 1067189251Ssam 1068189251Ssam imc = os_zalloc(sizeof(*imc)); 1069189251Ssam if (imc == NULL) { 1070189251Ssam *error = 1; 1071189251Ssam return NULL; 1072189251Ssam } 1073189251Ssam 1074189251Ssam imc->imcID = i; 1075189251Ssam 1076189251Ssam pos = start; 1077189251Ssam wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos); 1078189251Ssam if (pos + 1 >= end || *pos != '"') { 1079189251Ssam wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " 1080189251Ssam "(no starting quotation mark)", start); 1081189251Ssam os_free(imc); 1082189251Ssam return NULL; 1083189251Ssam } 1084189251Ssam 1085189251Ssam pos++; 1086189251Ssam pos2 = pos; 1087189251Ssam while (pos2 < end && *pos2 != '"') 1088189251Ssam pos2++; 1089189251Ssam if (pos2 >= end) { 1090189251Ssam wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " 1091189251Ssam "(no ending quotation mark)", start); 1092189251Ssam os_free(imc); 1093189251Ssam return NULL; 1094189251Ssam } 1095189251Ssam *pos2 = '\0'; 1096189251Ssam wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos); 1097189251Ssam imc->name = os_strdup(pos); 1098189251Ssam 1099189251Ssam pos = pos2 + 1; 1100189251Ssam if (pos >= end || *pos != ' ') { 1101189251Ssam wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " 1102189251Ssam "(no space after name)", start); 1103209158Srpaulo os_free(imc->name); 1104189251Ssam os_free(imc); 1105189251Ssam return NULL; 1106189251Ssam } 1107189251Ssam 1108189251Ssam pos++; 1109189251Ssam wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos); 1110189251Ssam imc->path = os_strdup(pos); 1111189251Ssam tnc_imc[imc->imcID] = imc; 1112189251Ssam 1113189251Ssam return imc; 1114189251Ssam} 1115189251Ssam 1116189251Ssam 1117189251Ssamstatic int tncc_read_config(struct tncc_data *tncc) 1118189251Ssam{ 1119189251Ssam char *config, *end, *pos, *line_end; 1120189251Ssam size_t config_len; 1121189251Ssam struct tnc_if_imc *imc, *last; 1122189251Ssam 1123189251Ssam last = NULL; 1124189251Ssam 1125189251Ssam config = os_readfile(TNC_CONFIG_FILE, &config_len); 1126189251Ssam if (config == NULL) { 1127189251Ssam wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration " 1128189251Ssam "file '%s'", TNC_CONFIG_FILE); 1129189251Ssam return -1; 1130189251Ssam } 1131189251Ssam 1132189251Ssam end = config + config_len; 1133189251Ssam for (pos = config; pos < end; pos = line_end + 1) { 1134189251Ssam line_end = pos; 1135189251Ssam while (*line_end != '\n' && *line_end != '\r' && 1136189251Ssam line_end < end) 1137189251Ssam line_end++; 1138189251Ssam *line_end = '\0'; 1139189251Ssam 1140189251Ssam if (os_strncmp(pos, "IMC ", 4) == 0) { 1141189251Ssam int error = 0; 1142189251Ssam 1143189251Ssam imc = tncc_parse_imc(pos + 4, line_end, &error); 1144189251Ssam if (error) 1145189251Ssam return -1; 1146189251Ssam if (imc) { 1147189251Ssam if (last == NULL) 1148189251Ssam tncc->imc = imc; 1149189251Ssam else 1150189251Ssam last->next = imc; 1151189251Ssam last = imc; 1152189251Ssam } 1153189251Ssam } 1154189251Ssam } 1155189251Ssam 1156189251Ssam os_free(config); 1157189251Ssam 1158189251Ssam return 0; 1159189251Ssam} 1160189251Ssam 1161189251Ssam#endif /* CONFIG_NATIVE_WINDOWS */ 1162189251Ssam 1163189251Ssam 1164189251Ssamstruct tncc_data * tncc_init(void) 1165189251Ssam{ 1166189251Ssam struct tncc_data *tncc; 1167189251Ssam struct tnc_if_imc *imc; 1168189251Ssam 1169189251Ssam tncc = os_zalloc(sizeof(*tncc)); 1170189251Ssam if (tncc == NULL) 1171189251Ssam return NULL; 1172189251Ssam 1173189251Ssam /* TODO: 1174189251Ssam * move loading and Initialize() to a location that is not 1175189251Ssam * re-initialized for every EAP-TNC session (?) 1176189251Ssam */ 1177189251Ssam 1178189251Ssam if (tncc_read_config(tncc) < 0) { 1179189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration"); 1180189251Ssam goto failed; 1181189251Ssam } 1182189251Ssam 1183189251Ssam for (imc = tncc->imc; imc; imc = imc->next) { 1184189251Ssam if (tncc_load_imc(imc)) { 1185189251Ssam wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'", 1186189251Ssam imc->name); 1187189251Ssam goto failed; 1188189251Ssam } 1189189251Ssam } 1190189251Ssam 1191189251Ssam return tncc; 1192189251Ssam 1193189251Ssamfailed: 1194189251Ssam tncc_deinit(tncc); 1195189251Ssam return NULL; 1196189251Ssam} 1197189251Ssam 1198189251Ssam 1199189251Ssamvoid tncc_deinit(struct tncc_data *tncc) 1200189251Ssam{ 1201189251Ssam struct tnc_if_imc *imc, *prev; 1202189251Ssam 1203189251Ssam imc = tncc->imc; 1204189251Ssam while (imc) { 1205189251Ssam tncc_unload_imc(imc); 1206189251Ssam 1207189251Ssam prev = imc; 1208189251Ssam imc = imc->next; 1209189251Ssam os_free(prev); 1210189251Ssam } 1211189251Ssam 1212189251Ssam os_free(tncc); 1213189251Ssam} 1214189251Ssam 1215189251Ssam 1216189251Ssamstatic struct wpabuf * tncc_build_soh(int ver) 1217189251Ssam{ 1218189251Ssam struct wpabuf *buf; 1219189251Ssam u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end; 1220189251Ssam u8 correlation_id[24]; 1221189251Ssam /* TODO: get correct name */ 1222189251Ssam char *machinename = "wpa_supplicant@w1.fi"; 1223189251Ssam 1224189251Ssam if (os_get_random(correlation_id, sizeof(correlation_id))) 1225189251Ssam return NULL; 1226189251Ssam wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID", 1227189251Ssam correlation_id, sizeof(correlation_id)); 1228189251Ssam 1229189251Ssam buf = wpabuf_alloc(200); 1230189251Ssam if (buf == NULL) 1231189251Ssam return NULL; 1232189251Ssam 1233189251Ssam /* Vendor-Specific TLV (Microsoft) - SoH */ 1234189251Ssam wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */ 1235189251Ssam tlv_len = wpabuf_put(buf, 2); /* Length */ 1236189251Ssam wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */ 1237189251Ssam wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */ 1238189251Ssam tlv_len2 = wpabuf_put(buf, 2); /* Length */ 1239189251Ssam 1240189251Ssam /* SoH Header */ 1241189251Ssam wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */ 1242189251Ssam outer_len = wpabuf_put(buf, 2); 1243189251Ssam wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ 1244189251Ssam wpabuf_put_be16(buf, ver); /* Inner Type */ 1245189251Ssam inner_len = wpabuf_put(buf, 2); 1246189251Ssam 1247189251Ssam if (ver == 2) { 1248189251Ssam /* SoH Mode Sub-Header */ 1249189251Ssam /* Outer Type */ 1250189251Ssam wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); 1251189251Ssam wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */ 1252189251Ssam wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ 1253189251Ssam /* Value: */ 1254189251Ssam wpabuf_put_data(buf, correlation_id, sizeof(correlation_id)); 1255189251Ssam wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */ 1256189251Ssam wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */ 1257189251Ssam } 1258189251Ssam 1259189251Ssam /* SSoH TLV */ 1260189251Ssam /* System-Health-Id */ 1261189251Ssam wpabuf_put_be16(buf, 0x0002); /* Type */ 1262189251Ssam wpabuf_put_be16(buf, 4); /* Length */ 1263189251Ssam wpabuf_put_be32(buf, 79616); 1264189251Ssam /* Vendor-Specific Attribute */ 1265189251Ssam wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); 1266189251Ssam ssoh_len = wpabuf_put(buf, 2); 1267189251Ssam wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ 1268189251Ssam 1269189251Ssam /* MS-Packet-Info */ 1270189251Ssam wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO); 1271189251Ssam /* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be: 1272189251Ssam * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP 1273189251Ssam * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit 1274189251Ssam * would not be in the specified location. 1275189251Ssam * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits) 1276189251Ssam */ 1277189251Ssam wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */ 1278189251Ssam 1279189251Ssam /* MS-Machine-Inventory */ 1280189251Ssam /* TODO: get correct values; 0 = not applicable for OS */ 1281189251Ssam wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY); 1282189251Ssam wpabuf_put_be32(buf, 0); /* osVersionMajor */ 1283189251Ssam wpabuf_put_be32(buf, 0); /* osVersionMinor */ 1284189251Ssam wpabuf_put_be32(buf, 0); /* osVersionBuild */ 1285189251Ssam wpabuf_put_be16(buf, 0); /* spVersionMajor */ 1286189251Ssam wpabuf_put_be16(buf, 0); /* spVersionMinor */ 1287189251Ssam wpabuf_put_be16(buf, 0); /* procArch */ 1288189251Ssam 1289189251Ssam /* MS-MachineName */ 1290189251Ssam wpabuf_put_u8(buf, SSOH_MS_MACHINENAME); 1291189251Ssam wpabuf_put_be16(buf, os_strlen(machinename) + 1); 1292189251Ssam wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1); 1293189251Ssam 1294189251Ssam /* MS-CorrelationId */ 1295189251Ssam wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID); 1296189251Ssam wpabuf_put_data(buf, correlation_id, sizeof(correlation_id)); 1297189251Ssam 1298189251Ssam /* MS-Quarantine-State */ 1299189251Ssam wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE); 1300189251Ssam wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */ 1301189251Ssam wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */ 1302189251Ssam wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */ 1303189251Ssam wpabuf_put_be16(buf, 1); /* urlLenInBytes */ 1304189251Ssam wpabuf_put_u8(buf, 0); /* null termination for the url */ 1305189251Ssam 1306189251Ssam /* MS-Machine-Inventory-Ex */ 1307189251Ssam wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX); 1308189251Ssam wpabuf_put_be32(buf, 0); /* Reserved 1309189251Ssam * (note: Windows XP SP3 uses 0xdecafbad) */ 1310189251Ssam wpabuf_put_u8(buf, 1); /* ProductType: Client */ 1311189251Ssam 1312189251Ssam /* Update SSoH Length */ 1313189251Ssam end = wpabuf_put(buf, 0); 1314189251Ssam WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2); 1315189251Ssam 1316189251Ssam /* TODO: SoHReportEntry TLV (zero or more) */ 1317189251Ssam 1318189251Ssam /* Update length fields */ 1319189251Ssam end = wpabuf_put(buf, 0); 1320189251Ssam WPA_PUT_BE16(tlv_len, end - tlv_len - 2); 1321189251Ssam WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2); 1322189251Ssam WPA_PUT_BE16(outer_len, end - outer_len - 2); 1323189251Ssam WPA_PUT_BE16(inner_len, end - inner_len - 2); 1324189251Ssam 1325189251Ssam return buf; 1326189251Ssam} 1327189251Ssam 1328189251Ssam 1329189251Ssamstruct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len) 1330189251Ssam{ 1331189251Ssam const u8 *pos; 1332189251Ssam 1333189251Ssam wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len); 1334189251Ssam 1335189251Ssam if (len < 12) 1336189251Ssam return NULL; 1337189251Ssam 1338189251Ssam /* SoH Request */ 1339189251Ssam pos = data; 1340189251Ssam 1341189251Ssam /* TLV Type */ 1342189251Ssam if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV) 1343189251Ssam return NULL; 1344189251Ssam pos += 2; 1345189251Ssam 1346189251Ssam /* Length */ 1347189251Ssam if (WPA_GET_BE16(pos) < 8) 1348189251Ssam return NULL; 1349189251Ssam pos += 2; 1350189251Ssam 1351189251Ssam /* Vendor_Id */ 1352189251Ssam if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT) 1353189251Ssam return NULL; 1354189251Ssam pos += 4; 1355189251Ssam 1356189251Ssam /* TLV Type */ 1357189251Ssam if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */) 1358189251Ssam return NULL; 1359189251Ssam 1360189251Ssam wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received"); 1361189251Ssam 1362189251Ssam return tncc_build_soh(2); 1363189251Ssam} 1364