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