16d49e1aeSJan Lentfer /*
26d49e1aeSJan Lentfer * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
36d49e1aeSJan Lentfer * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
46d49e1aeSJan Lentfer *
53ff40c12SJohn Marino * This software may be distributed under the terms of the BSD license.
63ff40c12SJohn Marino * See README for more details.
76d49e1aeSJan Lentfer */
86d49e1aeSJan Lentfer
96d49e1aeSJan Lentfer #include "includes.h"
106d49e1aeSJan Lentfer #ifndef CONFIG_NATIVE_WINDOWS
116d49e1aeSJan Lentfer #include <dlfcn.h>
126d49e1aeSJan Lentfer #endif /* CONFIG_NATIVE_WINDOWS */
136d49e1aeSJan Lentfer
146d49e1aeSJan Lentfer #include "common.h"
156d49e1aeSJan Lentfer #include "base64.h"
16*a1157835SDaniel Fojt #include "common/tnc.h"
176d49e1aeSJan Lentfer #include "tncc.h"
186d49e1aeSJan Lentfer #include "eap_common/eap_tlv_common.h"
196d49e1aeSJan Lentfer #include "eap_common/eap_defs.h"
206d49e1aeSJan Lentfer
216d49e1aeSJan Lentfer
226d49e1aeSJan Lentfer #ifdef UNICODE
236d49e1aeSJan Lentfer #define TSTR "%S"
246d49e1aeSJan Lentfer #else /* UNICODE */
256d49e1aeSJan Lentfer #define TSTR "%s"
266d49e1aeSJan Lentfer #endif /* UNICODE */
276d49e1aeSJan Lentfer
286d49e1aeSJan Lentfer
29*a1157835SDaniel Fojt #ifndef TNC_CONFIG_FILE
306d49e1aeSJan Lentfer #define TNC_CONFIG_FILE "/etc/tnc_config"
31*a1157835SDaniel Fojt #endif /* TNC_CONFIG_FILE */
326d49e1aeSJan Lentfer #define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
336d49e1aeSJan Lentfer #define IF_TNCCS_START \
346d49e1aeSJan Lentfer "<?xml version=\"1.0\"?>\n" \
356d49e1aeSJan Lentfer "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
366d49e1aeSJan Lentfer "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
376d49e1aeSJan Lentfer "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
386d49e1aeSJan Lentfer "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
396d49e1aeSJan Lentfer "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
406d49e1aeSJan Lentfer #define IF_TNCCS_END "\n</TNCCS-Batch>"
416d49e1aeSJan Lentfer
426d49e1aeSJan Lentfer /* TNC IF-IMC */
436d49e1aeSJan Lentfer
446d49e1aeSJan Lentfer /* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
456d49e1aeSJan Lentfer enum {
466d49e1aeSJan Lentfer SSOH_MS_MACHINE_INVENTORY = 1,
476d49e1aeSJan Lentfer SSOH_MS_QUARANTINE_STATE = 2,
486d49e1aeSJan Lentfer SSOH_MS_PACKET_INFO = 3,
496d49e1aeSJan Lentfer SSOH_MS_SYSTEMGENERATED_IDS = 4,
506d49e1aeSJan Lentfer SSOH_MS_MACHINENAME = 5,
516d49e1aeSJan Lentfer SSOH_MS_CORRELATIONID = 6,
526d49e1aeSJan Lentfer SSOH_MS_INSTALLED_SHVS = 7,
536d49e1aeSJan Lentfer SSOH_MS_MACHINE_INVENTORY_EX = 8
546d49e1aeSJan Lentfer };
556d49e1aeSJan Lentfer
566d49e1aeSJan Lentfer struct tnc_if_imc {
576d49e1aeSJan Lentfer struct tnc_if_imc *next;
586d49e1aeSJan Lentfer char *name;
596d49e1aeSJan Lentfer char *path;
606d49e1aeSJan Lentfer void *dlhandle; /* from dlopen() */
616d49e1aeSJan Lentfer TNC_IMCID imcID;
626d49e1aeSJan Lentfer TNC_ConnectionID connectionID;
636d49e1aeSJan Lentfer TNC_MessageTypeList supported_types;
646d49e1aeSJan Lentfer size_t num_supported_types;
656d49e1aeSJan Lentfer u8 *imc_send;
666d49e1aeSJan Lentfer size_t imc_send_len;
676d49e1aeSJan Lentfer
686d49e1aeSJan Lentfer /* Functions implemented by IMCs (with TNC_IMC_ prefix) */
696d49e1aeSJan Lentfer TNC_Result (*Initialize)(
706d49e1aeSJan Lentfer TNC_IMCID imcID,
716d49e1aeSJan Lentfer TNC_Version minVersion,
726d49e1aeSJan Lentfer TNC_Version maxVersion,
736d49e1aeSJan Lentfer TNC_Version *pOutActualVersion);
746d49e1aeSJan Lentfer TNC_Result (*NotifyConnectionChange)(
756d49e1aeSJan Lentfer TNC_IMCID imcID,
766d49e1aeSJan Lentfer TNC_ConnectionID connectionID,
776d49e1aeSJan Lentfer TNC_ConnectionState newState);
786d49e1aeSJan Lentfer TNC_Result (*BeginHandshake)(
796d49e1aeSJan Lentfer TNC_IMCID imcID,
806d49e1aeSJan Lentfer TNC_ConnectionID connectionID);
816d49e1aeSJan Lentfer TNC_Result (*ReceiveMessage)(
826d49e1aeSJan Lentfer TNC_IMCID imcID,
836d49e1aeSJan Lentfer TNC_ConnectionID connectionID,
846d49e1aeSJan Lentfer TNC_BufferReference messageBuffer,
856d49e1aeSJan Lentfer TNC_UInt32 messageLength,
866d49e1aeSJan Lentfer TNC_MessageType messageType);
876d49e1aeSJan Lentfer TNC_Result (*BatchEnding)(
886d49e1aeSJan Lentfer TNC_IMCID imcID,
896d49e1aeSJan Lentfer TNC_ConnectionID connectionID);
906d49e1aeSJan Lentfer TNC_Result (*Terminate)(TNC_IMCID imcID);
916d49e1aeSJan Lentfer TNC_Result (*ProvideBindFunction)(
926d49e1aeSJan Lentfer TNC_IMCID imcID,
936d49e1aeSJan Lentfer TNC_TNCC_BindFunctionPointer bindFunction);
946d49e1aeSJan Lentfer };
956d49e1aeSJan Lentfer
966d49e1aeSJan Lentfer struct tncc_data {
976d49e1aeSJan Lentfer struct tnc_if_imc *imc;
986d49e1aeSJan Lentfer unsigned int last_batchid;
996d49e1aeSJan Lentfer };
1006d49e1aeSJan Lentfer
1016d49e1aeSJan Lentfer #define TNC_MAX_IMC_ID 10
1026d49e1aeSJan Lentfer static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
1036d49e1aeSJan Lentfer
1046d49e1aeSJan Lentfer
1056d49e1aeSJan Lentfer /* TNCC functions that IMCs can call */
1066d49e1aeSJan Lentfer
TNC_TNCC_ReportMessageTypes(TNC_IMCID imcID,TNC_MessageTypeList supportedTypes,TNC_UInt32 typeCount)107*a1157835SDaniel Fojt static TNC_Result TNC_TNCC_ReportMessageTypes(
1086d49e1aeSJan Lentfer TNC_IMCID imcID,
1096d49e1aeSJan Lentfer TNC_MessageTypeList supportedTypes,
1106d49e1aeSJan Lentfer TNC_UInt32 typeCount)
1116d49e1aeSJan Lentfer {
1126d49e1aeSJan Lentfer TNC_UInt32 i;
1136d49e1aeSJan Lentfer struct tnc_if_imc *imc;
1146d49e1aeSJan Lentfer
1156d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
1166d49e1aeSJan Lentfer "typeCount=%lu)",
1176d49e1aeSJan Lentfer (unsigned long) imcID, (unsigned long) typeCount);
1186d49e1aeSJan Lentfer
1196d49e1aeSJan Lentfer for (i = 0; i < typeCount; i++) {
1206d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
1216d49e1aeSJan Lentfer i, supportedTypes[i]);
1226d49e1aeSJan Lentfer }
1236d49e1aeSJan Lentfer
1246d49e1aeSJan Lentfer if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
1256d49e1aeSJan Lentfer return TNC_RESULT_INVALID_PARAMETER;
1266d49e1aeSJan Lentfer
1276d49e1aeSJan Lentfer imc = tnc_imc[imcID];
1286d49e1aeSJan Lentfer os_free(imc->supported_types);
129*a1157835SDaniel Fojt imc->supported_types = os_memdup(supportedTypes,
130*a1157835SDaniel Fojt typeCount * sizeof(TNC_MessageType));
1316d49e1aeSJan Lentfer if (imc->supported_types == NULL)
1326d49e1aeSJan Lentfer return TNC_RESULT_FATAL;
1336d49e1aeSJan Lentfer imc->num_supported_types = typeCount;
1346d49e1aeSJan Lentfer
1356d49e1aeSJan Lentfer return TNC_RESULT_SUCCESS;
1366d49e1aeSJan Lentfer }
1376d49e1aeSJan Lentfer
1386d49e1aeSJan Lentfer
TNC_TNCC_SendMessage(TNC_IMCID imcID,TNC_ConnectionID connectionID,TNC_BufferReference message,TNC_UInt32 messageLength,TNC_MessageType messageType)139*a1157835SDaniel Fojt static TNC_Result TNC_TNCC_SendMessage(
1406d49e1aeSJan Lentfer TNC_IMCID imcID,
1416d49e1aeSJan Lentfer TNC_ConnectionID connectionID,
1426d49e1aeSJan Lentfer TNC_BufferReference message,
1436d49e1aeSJan Lentfer TNC_UInt32 messageLength,
1446d49e1aeSJan Lentfer TNC_MessageType messageType)
1456d49e1aeSJan Lentfer {
1466d49e1aeSJan Lentfer struct tnc_if_imc *imc;
1476d49e1aeSJan Lentfer unsigned char *b64;
1486d49e1aeSJan Lentfer size_t b64len;
1496d49e1aeSJan Lentfer
1506d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
1516d49e1aeSJan Lentfer "connectionID=%lu messageType=%lu)",
1526d49e1aeSJan Lentfer imcID, connectionID, messageType);
1536d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
1546d49e1aeSJan Lentfer message, messageLength);
1556d49e1aeSJan Lentfer
1566d49e1aeSJan Lentfer if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
1576d49e1aeSJan Lentfer return TNC_RESULT_INVALID_PARAMETER;
1586d49e1aeSJan Lentfer
1596d49e1aeSJan Lentfer b64 = base64_encode(message, messageLength, &b64len);
1606d49e1aeSJan Lentfer if (b64 == NULL)
1616d49e1aeSJan Lentfer return TNC_RESULT_FATAL;
1626d49e1aeSJan Lentfer
1636d49e1aeSJan Lentfer imc = tnc_imc[imcID];
1646d49e1aeSJan Lentfer os_free(imc->imc_send);
1656d49e1aeSJan Lentfer imc->imc_send_len = 0;
1666d49e1aeSJan Lentfer imc->imc_send = os_zalloc(b64len + 100);
1676d49e1aeSJan Lentfer if (imc->imc_send == NULL) {
1686d49e1aeSJan Lentfer os_free(b64);
1696d49e1aeSJan Lentfer return TNC_RESULT_OTHER;
1706d49e1aeSJan Lentfer }
1716d49e1aeSJan Lentfer
1726d49e1aeSJan Lentfer imc->imc_send_len =
1736d49e1aeSJan Lentfer os_snprintf((char *) imc->imc_send, b64len + 100,
1746d49e1aeSJan Lentfer "<IMC-IMV-Message><Type>%08X</Type>"
1756d49e1aeSJan Lentfer "<Base64>%s</Base64></IMC-IMV-Message>",
1766d49e1aeSJan Lentfer (unsigned int) messageType, b64);
1776d49e1aeSJan Lentfer
1786d49e1aeSJan Lentfer os_free(b64);
1796d49e1aeSJan Lentfer
1806d49e1aeSJan Lentfer return TNC_RESULT_SUCCESS;
1816d49e1aeSJan Lentfer }
1826d49e1aeSJan Lentfer
1836d49e1aeSJan Lentfer
TNC_TNCC_RequestHandshakeRetry(TNC_IMCID imcID,TNC_ConnectionID connectionID,TNC_RetryReason reason)184*a1157835SDaniel Fojt static TNC_Result TNC_TNCC_RequestHandshakeRetry(
1856d49e1aeSJan Lentfer TNC_IMCID imcID,
1866d49e1aeSJan Lentfer TNC_ConnectionID connectionID,
1876d49e1aeSJan Lentfer TNC_RetryReason reason)
1886d49e1aeSJan Lentfer {
1896d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
1906d49e1aeSJan Lentfer
1916d49e1aeSJan Lentfer if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
1926d49e1aeSJan Lentfer return TNC_RESULT_INVALID_PARAMETER;
1936d49e1aeSJan Lentfer
1946d49e1aeSJan Lentfer /*
1956d49e1aeSJan Lentfer * TODO: trigger a call to eapol_sm_request_reauth(). This would
1966d49e1aeSJan Lentfer * require that the IMC continues to be loaded in memory afer
1976d49e1aeSJan Lentfer * authentication..
1986d49e1aeSJan Lentfer */
1996d49e1aeSJan Lentfer
2006d49e1aeSJan Lentfer return TNC_RESULT_SUCCESS;
2016d49e1aeSJan Lentfer }
2026d49e1aeSJan Lentfer
2036d49e1aeSJan Lentfer
TNC_9048_LogMessage(TNC_IMCID imcID,TNC_UInt32 severity,const char * message)204*a1157835SDaniel Fojt static TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
2056d49e1aeSJan Lentfer const char *message)
2066d49e1aeSJan Lentfer {
2076d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
2086d49e1aeSJan Lentfer "severity==%lu message='%s')",
2096d49e1aeSJan Lentfer imcID, severity, message);
2106d49e1aeSJan Lentfer return TNC_RESULT_SUCCESS;
2116d49e1aeSJan Lentfer }
2126d49e1aeSJan Lentfer
2136d49e1aeSJan Lentfer
TNC_9048_UserMessage(TNC_IMCID imcID,TNC_ConnectionID connectionID,const char * message)214*a1157835SDaniel Fojt static TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID,
215*a1157835SDaniel Fojt TNC_ConnectionID connectionID,
2166d49e1aeSJan Lentfer const char *message)
2176d49e1aeSJan Lentfer {
2186d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
2196d49e1aeSJan Lentfer "connectionID==%lu message='%s')",
2206d49e1aeSJan Lentfer imcID, connectionID, message);
2216d49e1aeSJan Lentfer return TNC_RESULT_SUCCESS;
2226d49e1aeSJan Lentfer }
2236d49e1aeSJan Lentfer
2246d49e1aeSJan Lentfer
TNC_TNCC_BindFunction(TNC_IMCID imcID,char * functionName,void ** pOutfunctionPointer)225*a1157835SDaniel Fojt static TNC_Result TNC_TNCC_BindFunction(
2266d49e1aeSJan Lentfer TNC_IMCID imcID,
2276d49e1aeSJan Lentfer char *functionName,
2286d49e1aeSJan Lentfer void **pOutfunctionPointer)
2296d49e1aeSJan Lentfer {
2306d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
2316d49e1aeSJan Lentfer "functionName='%s')", (unsigned long) imcID, functionName);
2326d49e1aeSJan Lentfer
2336d49e1aeSJan Lentfer if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
2346d49e1aeSJan Lentfer return TNC_RESULT_INVALID_PARAMETER;
2356d49e1aeSJan Lentfer
2366d49e1aeSJan Lentfer if (pOutfunctionPointer == NULL)
2376d49e1aeSJan Lentfer return TNC_RESULT_INVALID_PARAMETER;
2386d49e1aeSJan Lentfer
2396d49e1aeSJan Lentfer if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
2406d49e1aeSJan Lentfer *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
2416d49e1aeSJan Lentfer else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
2426d49e1aeSJan Lentfer *pOutfunctionPointer = TNC_TNCC_SendMessage;
2436d49e1aeSJan Lentfer else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
2446d49e1aeSJan Lentfer 0)
2456d49e1aeSJan Lentfer *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
2466d49e1aeSJan Lentfer else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
2476d49e1aeSJan Lentfer *pOutfunctionPointer = TNC_9048_LogMessage;
2486d49e1aeSJan Lentfer else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
2496d49e1aeSJan Lentfer *pOutfunctionPointer = TNC_9048_UserMessage;
2506d49e1aeSJan Lentfer else
2516d49e1aeSJan Lentfer *pOutfunctionPointer = NULL;
2526d49e1aeSJan Lentfer
2536d49e1aeSJan Lentfer return TNC_RESULT_SUCCESS;
2546d49e1aeSJan Lentfer }
2556d49e1aeSJan Lentfer
2566d49e1aeSJan Lentfer
tncc_get_sym(void * handle,char * func)2576d49e1aeSJan Lentfer static void * tncc_get_sym(void *handle, char *func)
2586d49e1aeSJan Lentfer {
2596d49e1aeSJan Lentfer void *fptr;
2606d49e1aeSJan Lentfer
2616d49e1aeSJan Lentfer #ifdef CONFIG_NATIVE_WINDOWS
2626d49e1aeSJan Lentfer #ifdef _WIN32_WCE
2636d49e1aeSJan Lentfer fptr = GetProcAddressA(handle, func);
2646d49e1aeSJan Lentfer #else /* _WIN32_WCE */
2656d49e1aeSJan Lentfer fptr = GetProcAddress(handle, func);
2666d49e1aeSJan Lentfer #endif /* _WIN32_WCE */
2676d49e1aeSJan Lentfer #else /* CONFIG_NATIVE_WINDOWS */
2686d49e1aeSJan Lentfer fptr = dlsym(handle, func);
2696d49e1aeSJan Lentfer #endif /* CONFIG_NATIVE_WINDOWS */
2706d49e1aeSJan Lentfer
2716d49e1aeSJan Lentfer return fptr;
2726d49e1aeSJan Lentfer }
2736d49e1aeSJan Lentfer
2746d49e1aeSJan Lentfer
tncc_imc_resolve_funcs(struct tnc_if_imc * imc)2756d49e1aeSJan Lentfer static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
2766d49e1aeSJan Lentfer {
2776d49e1aeSJan Lentfer void *handle = imc->dlhandle;
2786d49e1aeSJan Lentfer
2796d49e1aeSJan Lentfer /* Mandatory IMC functions */
2806d49e1aeSJan Lentfer imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
2816d49e1aeSJan Lentfer if (imc->Initialize == NULL) {
2826d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: IMC does not export "
2836d49e1aeSJan Lentfer "TNC_IMC_Initialize");
2846d49e1aeSJan Lentfer return -1;
2856d49e1aeSJan Lentfer }
2866d49e1aeSJan Lentfer
2876d49e1aeSJan Lentfer imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
2886d49e1aeSJan Lentfer if (imc->BeginHandshake == NULL) {
2896d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: IMC does not export "
2906d49e1aeSJan Lentfer "TNC_IMC_BeginHandshake");
2916d49e1aeSJan Lentfer return -1;
2926d49e1aeSJan Lentfer }
2936d49e1aeSJan Lentfer
2946d49e1aeSJan Lentfer imc->ProvideBindFunction =
2956d49e1aeSJan Lentfer tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
2966d49e1aeSJan Lentfer if (imc->ProvideBindFunction == NULL) {
2976d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: IMC does not export "
2986d49e1aeSJan Lentfer "TNC_IMC_ProvideBindFunction");
2996d49e1aeSJan Lentfer return -1;
3006d49e1aeSJan Lentfer }
3016d49e1aeSJan Lentfer
3026d49e1aeSJan Lentfer /* Optional IMC functions */
3036d49e1aeSJan Lentfer imc->NotifyConnectionChange =
3046d49e1aeSJan Lentfer tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
3056d49e1aeSJan Lentfer imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
3066d49e1aeSJan Lentfer imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
3076d49e1aeSJan Lentfer imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
3086d49e1aeSJan Lentfer
3096d49e1aeSJan Lentfer return 0;
3106d49e1aeSJan Lentfer }
3116d49e1aeSJan Lentfer
3126d49e1aeSJan Lentfer
tncc_imc_initialize(struct tnc_if_imc * imc)3136d49e1aeSJan Lentfer static int tncc_imc_initialize(struct tnc_if_imc *imc)
3146d49e1aeSJan Lentfer {
3156d49e1aeSJan Lentfer TNC_Result res;
3166d49e1aeSJan Lentfer TNC_Version imc_ver;
3176d49e1aeSJan Lentfer
3186d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
3196d49e1aeSJan Lentfer imc->name);
3206d49e1aeSJan Lentfer res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
3216d49e1aeSJan Lentfer TNC_IFIMC_VERSION_1, &imc_ver);
3226d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
3236d49e1aeSJan Lentfer (unsigned long) res, (unsigned long) imc_ver);
3246d49e1aeSJan Lentfer
3256d49e1aeSJan Lentfer return res == TNC_RESULT_SUCCESS ? 0 : -1;
3266d49e1aeSJan Lentfer }
3276d49e1aeSJan Lentfer
3286d49e1aeSJan Lentfer
tncc_imc_terminate(struct tnc_if_imc * imc)3296d49e1aeSJan Lentfer static int tncc_imc_terminate(struct tnc_if_imc *imc)
3306d49e1aeSJan Lentfer {
3316d49e1aeSJan Lentfer TNC_Result res;
3326d49e1aeSJan Lentfer
3336d49e1aeSJan Lentfer if (imc->Terminate == NULL)
3346d49e1aeSJan Lentfer return 0;
3356d49e1aeSJan Lentfer
3366d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
3376d49e1aeSJan Lentfer imc->name);
3386d49e1aeSJan Lentfer res = imc->Terminate(imc->imcID);
3396d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
3406d49e1aeSJan Lentfer (unsigned long) res);
3416d49e1aeSJan Lentfer
3426d49e1aeSJan Lentfer return res == TNC_RESULT_SUCCESS ? 0 : -1;
3436d49e1aeSJan Lentfer }
3446d49e1aeSJan Lentfer
3456d49e1aeSJan Lentfer
tncc_imc_provide_bind_function(struct tnc_if_imc * imc)3466d49e1aeSJan Lentfer static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
3476d49e1aeSJan Lentfer {
3486d49e1aeSJan Lentfer TNC_Result res;
3496d49e1aeSJan Lentfer
3506d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
3516d49e1aeSJan Lentfer "IMC '%s'", imc->name);
3526d49e1aeSJan Lentfer res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
3536d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
3546d49e1aeSJan Lentfer (unsigned long) res);
3556d49e1aeSJan Lentfer
3566d49e1aeSJan Lentfer return res == TNC_RESULT_SUCCESS ? 0 : -1;
3576d49e1aeSJan Lentfer }
3586d49e1aeSJan Lentfer
3596d49e1aeSJan Lentfer
tncc_imc_notify_connection_change(struct tnc_if_imc * imc,TNC_ConnectionState state)3606d49e1aeSJan Lentfer static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
3616d49e1aeSJan Lentfer TNC_ConnectionState state)
3626d49e1aeSJan Lentfer {
3636d49e1aeSJan Lentfer TNC_Result res;
3646d49e1aeSJan Lentfer
3656d49e1aeSJan Lentfer if (imc->NotifyConnectionChange == NULL)
3666d49e1aeSJan Lentfer return 0;
3676d49e1aeSJan Lentfer
3686d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
3696d49e1aeSJan Lentfer " for IMC '%s'", (int) state, imc->name);
3706d49e1aeSJan Lentfer res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
3716d49e1aeSJan Lentfer state);
3726d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
3736d49e1aeSJan Lentfer (unsigned long) res);
3746d49e1aeSJan Lentfer
3756d49e1aeSJan Lentfer return res == TNC_RESULT_SUCCESS ? 0 : -1;
3766d49e1aeSJan Lentfer }
3776d49e1aeSJan Lentfer
3786d49e1aeSJan Lentfer
tncc_imc_begin_handshake(struct tnc_if_imc * imc)3796d49e1aeSJan Lentfer static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
3806d49e1aeSJan Lentfer {
3816d49e1aeSJan Lentfer TNC_Result res;
3826d49e1aeSJan Lentfer
3836d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
3846d49e1aeSJan Lentfer "'%s'", imc->name);
3856d49e1aeSJan Lentfer res = imc->BeginHandshake(imc->imcID, imc->connectionID);
3866d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
3876d49e1aeSJan Lentfer (unsigned long) res);
3886d49e1aeSJan Lentfer
3896d49e1aeSJan Lentfer return res == TNC_RESULT_SUCCESS ? 0 : -1;
3906d49e1aeSJan Lentfer }
3916d49e1aeSJan Lentfer
3926d49e1aeSJan Lentfer
tncc_load_imc(struct tnc_if_imc * imc)3936d49e1aeSJan Lentfer static int tncc_load_imc(struct tnc_if_imc *imc)
3946d49e1aeSJan Lentfer {
3956d49e1aeSJan Lentfer if (imc->path == NULL) {
3966d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
3976d49e1aeSJan Lentfer return -1;
3986d49e1aeSJan Lentfer }
3996d49e1aeSJan Lentfer
4006d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
4016d49e1aeSJan Lentfer imc->name, imc->path);
4026d49e1aeSJan Lentfer #ifdef CONFIG_NATIVE_WINDOWS
4036d49e1aeSJan Lentfer #ifdef UNICODE
4046d49e1aeSJan Lentfer {
4056d49e1aeSJan Lentfer TCHAR *lib = wpa_strdup_tchar(imc->path);
4066d49e1aeSJan Lentfer if (lib == NULL)
4076d49e1aeSJan Lentfer return -1;
4086d49e1aeSJan Lentfer imc->dlhandle = LoadLibrary(lib);
4096d49e1aeSJan Lentfer os_free(lib);
4106d49e1aeSJan Lentfer }
4116d49e1aeSJan Lentfer #else /* UNICODE */
4126d49e1aeSJan Lentfer imc->dlhandle = LoadLibrary(imc->path);
4136d49e1aeSJan Lentfer #endif /* UNICODE */
4146d49e1aeSJan Lentfer if (imc->dlhandle == NULL) {
4156d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
4166d49e1aeSJan Lentfer imc->name, imc->path, (int) GetLastError());
4176d49e1aeSJan Lentfer return -1;
4186d49e1aeSJan Lentfer }
4196d49e1aeSJan Lentfer #else /* CONFIG_NATIVE_WINDOWS */
4206d49e1aeSJan Lentfer imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
4216d49e1aeSJan Lentfer if (imc->dlhandle == NULL) {
4226d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
4236d49e1aeSJan Lentfer imc->name, imc->path, dlerror());
4246d49e1aeSJan Lentfer return -1;
4256d49e1aeSJan Lentfer }
4266d49e1aeSJan Lentfer #endif /* CONFIG_NATIVE_WINDOWS */
4276d49e1aeSJan Lentfer
4286d49e1aeSJan Lentfer if (tncc_imc_resolve_funcs(imc) < 0) {
4296d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
4306d49e1aeSJan Lentfer return -1;
4316d49e1aeSJan Lentfer }
4326d49e1aeSJan Lentfer
4336d49e1aeSJan Lentfer if (tncc_imc_initialize(imc) < 0 ||
4346d49e1aeSJan Lentfer tncc_imc_provide_bind_function(imc) < 0) {
4356d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
4366d49e1aeSJan Lentfer return -1;
4376d49e1aeSJan Lentfer }
4386d49e1aeSJan Lentfer
4396d49e1aeSJan Lentfer return 0;
4406d49e1aeSJan Lentfer }
4416d49e1aeSJan Lentfer
4426d49e1aeSJan Lentfer
tncc_unload_imc(struct tnc_if_imc * imc)4436d49e1aeSJan Lentfer static void tncc_unload_imc(struct tnc_if_imc *imc)
4446d49e1aeSJan Lentfer {
4456d49e1aeSJan Lentfer tncc_imc_terminate(imc);
4466d49e1aeSJan Lentfer tnc_imc[imc->imcID] = NULL;
4476d49e1aeSJan Lentfer
4486d49e1aeSJan Lentfer if (imc->dlhandle) {
4496d49e1aeSJan Lentfer #ifdef CONFIG_NATIVE_WINDOWS
4506d49e1aeSJan Lentfer FreeLibrary(imc->dlhandle);
4516d49e1aeSJan Lentfer #else /* CONFIG_NATIVE_WINDOWS */
4526d49e1aeSJan Lentfer dlclose(imc->dlhandle);
4536d49e1aeSJan Lentfer #endif /* CONFIG_NATIVE_WINDOWS */
4546d49e1aeSJan Lentfer }
4556d49e1aeSJan Lentfer os_free(imc->name);
4566d49e1aeSJan Lentfer os_free(imc->path);
4576d49e1aeSJan Lentfer os_free(imc->supported_types);
4586d49e1aeSJan Lentfer os_free(imc->imc_send);
4596d49e1aeSJan Lentfer }
4606d49e1aeSJan Lentfer
4616d49e1aeSJan Lentfer
tncc_supported_type(struct tnc_if_imc * imc,unsigned int type)4626d49e1aeSJan Lentfer static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
4636d49e1aeSJan Lentfer {
4646d49e1aeSJan Lentfer size_t i;
4656d49e1aeSJan Lentfer unsigned int vendor, subtype;
4666d49e1aeSJan Lentfer
4676d49e1aeSJan Lentfer if (imc == NULL || imc->supported_types == NULL)
4686d49e1aeSJan Lentfer return 0;
4696d49e1aeSJan Lentfer
4706d49e1aeSJan Lentfer vendor = type >> 8;
4716d49e1aeSJan Lentfer subtype = type & 0xff;
4726d49e1aeSJan Lentfer
4736d49e1aeSJan Lentfer for (i = 0; i < imc->num_supported_types; i++) {
4746d49e1aeSJan Lentfer unsigned int svendor, ssubtype;
4756d49e1aeSJan Lentfer svendor = imc->supported_types[i] >> 8;
4766d49e1aeSJan Lentfer ssubtype = imc->supported_types[i] & 0xff;
4776d49e1aeSJan Lentfer if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
4786d49e1aeSJan Lentfer (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
4796d49e1aeSJan Lentfer return 1;
4806d49e1aeSJan Lentfer }
4816d49e1aeSJan Lentfer
4826d49e1aeSJan Lentfer return 0;
4836d49e1aeSJan Lentfer }
4846d49e1aeSJan Lentfer
4856d49e1aeSJan Lentfer
tncc_send_to_imcs(struct tncc_data * tncc,unsigned int type,const u8 * msg,size_t len)4866d49e1aeSJan Lentfer static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
4876d49e1aeSJan Lentfer const u8 *msg, size_t len)
4886d49e1aeSJan Lentfer {
4896d49e1aeSJan Lentfer struct tnc_if_imc *imc;
4906d49e1aeSJan Lentfer TNC_Result res;
4916d49e1aeSJan Lentfer
4926d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
4936d49e1aeSJan Lentfer
4946d49e1aeSJan Lentfer for (imc = tncc->imc; imc; imc = imc->next) {
4956d49e1aeSJan Lentfer if (imc->ReceiveMessage == NULL ||
4966d49e1aeSJan Lentfer !tncc_supported_type(imc, type))
4976d49e1aeSJan Lentfer continue;
4986d49e1aeSJan Lentfer
4996d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
5006d49e1aeSJan Lentfer imc->name);
5016d49e1aeSJan Lentfer res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
5026d49e1aeSJan Lentfer (TNC_BufferReference) msg, len,
5036d49e1aeSJan Lentfer type);
5046d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
5056d49e1aeSJan Lentfer (unsigned long) res);
5066d49e1aeSJan Lentfer }
5076d49e1aeSJan Lentfer }
5086d49e1aeSJan Lentfer
5096d49e1aeSJan Lentfer
tncc_init_connection(struct tncc_data * tncc)5106d49e1aeSJan Lentfer void tncc_init_connection(struct tncc_data *tncc)
5116d49e1aeSJan Lentfer {
5126d49e1aeSJan Lentfer struct tnc_if_imc *imc;
5136d49e1aeSJan Lentfer
5146d49e1aeSJan Lentfer for (imc = tncc->imc; imc; imc = imc->next) {
5156d49e1aeSJan Lentfer tncc_imc_notify_connection_change(
5166d49e1aeSJan Lentfer imc, TNC_CONNECTION_STATE_CREATE);
5176d49e1aeSJan Lentfer tncc_imc_notify_connection_change(
5186d49e1aeSJan Lentfer imc, TNC_CONNECTION_STATE_HANDSHAKE);
5196d49e1aeSJan Lentfer
5206d49e1aeSJan Lentfer os_free(imc->imc_send);
5216d49e1aeSJan Lentfer imc->imc_send = NULL;
5226d49e1aeSJan Lentfer imc->imc_send_len = 0;
5236d49e1aeSJan Lentfer
5246d49e1aeSJan Lentfer tncc_imc_begin_handshake(imc);
5256d49e1aeSJan Lentfer }
5266d49e1aeSJan Lentfer }
5276d49e1aeSJan Lentfer
5286d49e1aeSJan Lentfer
tncc_total_send_len(struct tncc_data * tncc)5296d49e1aeSJan Lentfer size_t tncc_total_send_len(struct tncc_data *tncc)
5306d49e1aeSJan Lentfer {
5316d49e1aeSJan Lentfer struct tnc_if_imc *imc;
5326d49e1aeSJan Lentfer
5336d49e1aeSJan Lentfer size_t len = 0;
5346d49e1aeSJan Lentfer for (imc = tncc->imc; imc; imc = imc->next)
5356d49e1aeSJan Lentfer len += imc->imc_send_len;
5366d49e1aeSJan Lentfer return len;
5376d49e1aeSJan Lentfer }
5386d49e1aeSJan Lentfer
5396d49e1aeSJan Lentfer
tncc_copy_send_buf(struct tncc_data * tncc,u8 * pos)5406d49e1aeSJan Lentfer u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
5416d49e1aeSJan Lentfer {
5426d49e1aeSJan Lentfer struct tnc_if_imc *imc;
5436d49e1aeSJan Lentfer
5446d49e1aeSJan Lentfer for (imc = tncc->imc; imc; imc = imc->next) {
5456d49e1aeSJan Lentfer if (imc->imc_send == NULL)
5466d49e1aeSJan Lentfer continue;
5476d49e1aeSJan Lentfer
5486d49e1aeSJan Lentfer os_memcpy(pos, imc->imc_send, imc->imc_send_len);
5496d49e1aeSJan Lentfer pos += imc->imc_send_len;
5506d49e1aeSJan Lentfer os_free(imc->imc_send);
5516d49e1aeSJan Lentfer imc->imc_send = NULL;
5526d49e1aeSJan Lentfer imc->imc_send_len = 0;
5536d49e1aeSJan Lentfer }
5546d49e1aeSJan Lentfer
5556d49e1aeSJan Lentfer return pos;
5566d49e1aeSJan Lentfer }
5576d49e1aeSJan Lentfer
5586d49e1aeSJan Lentfer
tncc_if_tnccs_start(struct tncc_data * tncc)5596d49e1aeSJan Lentfer char * tncc_if_tnccs_start(struct tncc_data *tncc)
5606d49e1aeSJan Lentfer {
5616d49e1aeSJan Lentfer char *buf = os_malloc(1000);
5626d49e1aeSJan Lentfer if (buf == NULL)
5636d49e1aeSJan Lentfer return NULL;
5646d49e1aeSJan Lentfer tncc->last_batchid++;
5656d49e1aeSJan Lentfer os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
5666d49e1aeSJan Lentfer return buf;
5676d49e1aeSJan Lentfer }
5686d49e1aeSJan Lentfer
5696d49e1aeSJan Lentfer
tncc_if_tnccs_end(void)5706d49e1aeSJan Lentfer char * tncc_if_tnccs_end(void)
5716d49e1aeSJan Lentfer {
5726d49e1aeSJan Lentfer char *buf = os_malloc(100);
5736d49e1aeSJan Lentfer if (buf == NULL)
5746d49e1aeSJan Lentfer return NULL;
5756d49e1aeSJan Lentfer os_snprintf(buf, 100, IF_TNCCS_END);
5766d49e1aeSJan Lentfer return buf;
5776d49e1aeSJan Lentfer }
5786d49e1aeSJan Lentfer
5796d49e1aeSJan Lentfer
tncc_notify_recommendation(struct tncc_data * tncc,enum tncc_process_res res)5806d49e1aeSJan Lentfer static void tncc_notify_recommendation(struct tncc_data *tncc,
5816d49e1aeSJan Lentfer enum tncc_process_res res)
5826d49e1aeSJan Lentfer {
5836d49e1aeSJan Lentfer TNC_ConnectionState state;
5846d49e1aeSJan Lentfer struct tnc_if_imc *imc;
5856d49e1aeSJan Lentfer
5866d49e1aeSJan Lentfer switch (res) {
5876d49e1aeSJan Lentfer case TNCCS_RECOMMENDATION_ALLOW:
5886d49e1aeSJan Lentfer state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
5896d49e1aeSJan Lentfer break;
5906d49e1aeSJan Lentfer case TNCCS_RECOMMENDATION_NONE:
5916d49e1aeSJan Lentfer state = TNC_CONNECTION_STATE_ACCESS_NONE;
5926d49e1aeSJan Lentfer break;
5936d49e1aeSJan Lentfer case TNCCS_RECOMMENDATION_ISOLATE:
5946d49e1aeSJan Lentfer state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
5956d49e1aeSJan Lentfer break;
5966d49e1aeSJan Lentfer default:
5976d49e1aeSJan Lentfer state = TNC_CONNECTION_STATE_ACCESS_NONE;
5986d49e1aeSJan Lentfer break;
5996d49e1aeSJan Lentfer }
6006d49e1aeSJan Lentfer
6016d49e1aeSJan Lentfer for (imc = tncc->imc; imc; imc = imc->next)
6026d49e1aeSJan Lentfer tncc_imc_notify_connection_change(imc, state);
6036d49e1aeSJan Lentfer }
6046d49e1aeSJan Lentfer
6056d49e1aeSJan Lentfer
tncc_get_type(char * start,unsigned int * type)6066d49e1aeSJan Lentfer static int tncc_get_type(char *start, unsigned int *type)
6076d49e1aeSJan Lentfer {
6086d49e1aeSJan Lentfer char *pos = os_strstr(start, "<Type>");
6096d49e1aeSJan Lentfer if (pos == NULL)
6106d49e1aeSJan Lentfer return -1;
6116d49e1aeSJan Lentfer pos += 6;
6126d49e1aeSJan Lentfer *type = strtoul(pos, NULL, 16);
6136d49e1aeSJan Lentfer return 0;
6146d49e1aeSJan Lentfer }
6156d49e1aeSJan Lentfer
6166d49e1aeSJan Lentfer
tncc_get_base64(char * start,size_t * decoded_len)6176d49e1aeSJan Lentfer static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
6186d49e1aeSJan Lentfer {
6196d49e1aeSJan Lentfer char *pos, *pos2;
6206d49e1aeSJan Lentfer unsigned char *decoded;
6216d49e1aeSJan Lentfer
6226d49e1aeSJan Lentfer pos = os_strstr(start, "<Base64>");
6236d49e1aeSJan Lentfer if (pos == NULL)
6246d49e1aeSJan Lentfer return NULL;
6256d49e1aeSJan Lentfer
6266d49e1aeSJan Lentfer pos += 8;
6276d49e1aeSJan Lentfer pos2 = os_strstr(pos, "</Base64>");
6286d49e1aeSJan Lentfer if (pos2 == NULL)
6296d49e1aeSJan Lentfer return NULL;
6306d49e1aeSJan Lentfer *pos2 = '\0';
6316d49e1aeSJan Lentfer
6326d49e1aeSJan Lentfer decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
6336d49e1aeSJan Lentfer decoded_len);
6346d49e1aeSJan Lentfer *pos2 = '<';
6356d49e1aeSJan Lentfer if (decoded == NULL) {
6366d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
6376d49e1aeSJan Lentfer }
6386d49e1aeSJan Lentfer
6396d49e1aeSJan Lentfer return decoded;
6406d49e1aeSJan Lentfer }
6416d49e1aeSJan Lentfer
6426d49e1aeSJan Lentfer
tncc_get_recommendation(char * start)6436d49e1aeSJan Lentfer static enum tncc_process_res tncc_get_recommendation(char *start)
6446d49e1aeSJan Lentfer {
6456d49e1aeSJan Lentfer char *pos, *pos2, saved;
6466d49e1aeSJan Lentfer int recom;
6476d49e1aeSJan Lentfer
6486d49e1aeSJan Lentfer pos = os_strstr(start, "<TNCCS-Recommendation ");
6496d49e1aeSJan Lentfer if (pos == NULL)
6506d49e1aeSJan Lentfer return TNCCS_RECOMMENDATION_ERROR;
6516d49e1aeSJan Lentfer
6526d49e1aeSJan Lentfer pos += 21;
6536d49e1aeSJan Lentfer pos = os_strstr(pos, " type=");
6546d49e1aeSJan Lentfer if (pos == NULL)
6556d49e1aeSJan Lentfer return TNCCS_RECOMMENDATION_ERROR;
6566d49e1aeSJan Lentfer pos += 6;
6576d49e1aeSJan Lentfer
6586d49e1aeSJan Lentfer if (*pos == '"')
6596d49e1aeSJan Lentfer pos++;
6606d49e1aeSJan Lentfer
6616d49e1aeSJan Lentfer pos2 = pos;
6626d49e1aeSJan Lentfer while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
6636d49e1aeSJan Lentfer pos2++;
6646d49e1aeSJan Lentfer
6656d49e1aeSJan Lentfer if (*pos2 == '\0')
6666d49e1aeSJan Lentfer return TNCCS_RECOMMENDATION_ERROR;
6676d49e1aeSJan Lentfer
6686d49e1aeSJan Lentfer saved = *pos2;
6696d49e1aeSJan Lentfer *pos2 = '\0';
6706d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
6716d49e1aeSJan Lentfer
6726d49e1aeSJan Lentfer recom = TNCCS_RECOMMENDATION_ERROR;
6736d49e1aeSJan Lentfer if (os_strcmp(pos, "allow") == 0)
6746d49e1aeSJan Lentfer recom = TNCCS_RECOMMENDATION_ALLOW;
6756d49e1aeSJan Lentfer else if (os_strcmp(pos, "none") == 0)
6766d49e1aeSJan Lentfer recom = TNCCS_RECOMMENDATION_NONE;
6776d49e1aeSJan Lentfer else if (os_strcmp(pos, "isolate") == 0)
6786d49e1aeSJan Lentfer recom = TNCCS_RECOMMENDATION_ISOLATE;
6796d49e1aeSJan Lentfer
6806d49e1aeSJan Lentfer *pos2 = saved;
6816d49e1aeSJan Lentfer
6826d49e1aeSJan Lentfer return recom;
6836d49e1aeSJan Lentfer }
6846d49e1aeSJan Lentfer
6856d49e1aeSJan Lentfer
tncc_process_if_tnccs(struct tncc_data * tncc,const u8 * msg,size_t len)6866d49e1aeSJan Lentfer enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
6876d49e1aeSJan Lentfer const u8 *msg, size_t len)
6886d49e1aeSJan Lentfer {
6896d49e1aeSJan Lentfer char *buf, *start, *end, *pos, *pos2, *payload;
6906d49e1aeSJan Lentfer unsigned int batch_id;
6916d49e1aeSJan Lentfer unsigned char *decoded;
6926d49e1aeSJan Lentfer size_t decoded_len;
6936d49e1aeSJan Lentfer enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
6946d49e1aeSJan Lentfer int recommendation_msg = 0;
6956d49e1aeSJan Lentfer
696*a1157835SDaniel Fojt wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Received IF-TNCCS message",
697*a1157835SDaniel Fojt msg, len);
6983ff40c12SJohn Marino buf = dup_binstr(msg, len);
6996d49e1aeSJan Lentfer if (buf == NULL)
7006d49e1aeSJan Lentfer return TNCCS_PROCESS_ERROR;
7016d49e1aeSJan Lentfer
7026d49e1aeSJan Lentfer start = os_strstr(buf, "<TNCCS-Batch ");
7036d49e1aeSJan Lentfer end = os_strstr(buf, "</TNCCS-Batch>");
7046d49e1aeSJan Lentfer if (start == NULL || end == NULL || start > end) {
7056d49e1aeSJan Lentfer os_free(buf);
7066d49e1aeSJan Lentfer return TNCCS_PROCESS_ERROR;
7076d49e1aeSJan Lentfer }
7086d49e1aeSJan Lentfer
7096d49e1aeSJan Lentfer start += 13;
7106d49e1aeSJan Lentfer while (*start == ' ')
7116d49e1aeSJan Lentfer start++;
7126d49e1aeSJan Lentfer *end = '\0';
7136d49e1aeSJan Lentfer
7146d49e1aeSJan Lentfer pos = os_strstr(start, "BatchId=");
7156d49e1aeSJan Lentfer if (pos == NULL) {
7166d49e1aeSJan Lentfer os_free(buf);
7176d49e1aeSJan Lentfer return TNCCS_PROCESS_ERROR;
7186d49e1aeSJan Lentfer }
7196d49e1aeSJan Lentfer
7206d49e1aeSJan Lentfer pos += 8;
7216d49e1aeSJan Lentfer if (*pos == '"')
7226d49e1aeSJan Lentfer pos++;
7236d49e1aeSJan Lentfer batch_id = atoi(pos);
7246d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
7256d49e1aeSJan Lentfer batch_id);
7266d49e1aeSJan Lentfer if (batch_id != tncc->last_batchid + 1) {
7276d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
7286d49e1aeSJan Lentfer "%u (expected %u)",
7296d49e1aeSJan Lentfer batch_id, tncc->last_batchid + 1);
7306d49e1aeSJan Lentfer os_free(buf);
7316d49e1aeSJan Lentfer return TNCCS_PROCESS_ERROR;
7326d49e1aeSJan Lentfer }
7336d49e1aeSJan Lentfer tncc->last_batchid = batch_id;
7346d49e1aeSJan Lentfer
7356d49e1aeSJan Lentfer while (*pos != '\0' && *pos != '>')
7366d49e1aeSJan Lentfer pos++;
7376d49e1aeSJan Lentfer if (*pos == '\0') {
7386d49e1aeSJan Lentfer os_free(buf);
7396d49e1aeSJan Lentfer return TNCCS_PROCESS_ERROR;
7406d49e1aeSJan Lentfer }
7416d49e1aeSJan Lentfer pos++;
7426d49e1aeSJan Lentfer payload = start;
7436d49e1aeSJan Lentfer
7446d49e1aeSJan Lentfer /*
7456d49e1aeSJan Lentfer * <IMC-IMV-Message>
7466d49e1aeSJan Lentfer * <Type>01234567</Type>
7476d49e1aeSJan Lentfer * <Base64>foo==</Base64>
7486d49e1aeSJan Lentfer * </IMC-IMV-Message>
7496d49e1aeSJan Lentfer */
7506d49e1aeSJan Lentfer
7516d49e1aeSJan Lentfer while (*start) {
7526d49e1aeSJan Lentfer char *endpos;
7536d49e1aeSJan Lentfer unsigned int type;
7546d49e1aeSJan Lentfer
7556d49e1aeSJan Lentfer pos = os_strstr(start, "<IMC-IMV-Message>");
7566d49e1aeSJan Lentfer if (pos == NULL)
7576d49e1aeSJan Lentfer break;
7586d49e1aeSJan Lentfer start = pos + 17;
7596d49e1aeSJan Lentfer end = os_strstr(start, "</IMC-IMV-Message>");
7606d49e1aeSJan Lentfer if (end == NULL)
7616d49e1aeSJan Lentfer break;
7626d49e1aeSJan Lentfer *end = '\0';
7636d49e1aeSJan Lentfer endpos = end;
7646d49e1aeSJan Lentfer end += 18;
7656d49e1aeSJan Lentfer
7666d49e1aeSJan Lentfer if (tncc_get_type(start, &type) < 0) {
7676d49e1aeSJan Lentfer *endpos = '<';
7686d49e1aeSJan Lentfer start = end;
7696d49e1aeSJan Lentfer continue;
7706d49e1aeSJan Lentfer }
7716d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
7726d49e1aeSJan Lentfer
7736d49e1aeSJan Lentfer decoded = tncc_get_base64(start, &decoded_len);
7746d49e1aeSJan Lentfer if (decoded == NULL) {
7756d49e1aeSJan Lentfer *endpos = '<';
7766d49e1aeSJan Lentfer start = end;
7776d49e1aeSJan Lentfer continue;
7786d49e1aeSJan Lentfer }
7796d49e1aeSJan Lentfer
7806d49e1aeSJan Lentfer tncc_send_to_imcs(tncc, type, decoded, decoded_len);
7816d49e1aeSJan Lentfer
7826d49e1aeSJan Lentfer os_free(decoded);
7836d49e1aeSJan Lentfer
7846d49e1aeSJan Lentfer start = end;
7856d49e1aeSJan Lentfer }
7866d49e1aeSJan Lentfer
7876d49e1aeSJan Lentfer /*
7886d49e1aeSJan Lentfer * <TNCC-TNCS-Message>
7896d49e1aeSJan Lentfer * <Type>01234567</Type>
7906d49e1aeSJan Lentfer * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
7916d49e1aeSJan Lentfer * <Base64>foo==</Base64>
7926d49e1aeSJan Lentfer * </TNCC-TNCS-Message>
7936d49e1aeSJan Lentfer */
7946d49e1aeSJan Lentfer
7956d49e1aeSJan Lentfer start = payload;
7966d49e1aeSJan Lentfer while (*start) {
7976d49e1aeSJan Lentfer unsigned int type;
7986d49e1aeSJan Lentfer char *xml, *xmlend, *endpos;
7996d49e1aeSJan Lentfer
8006d49e1aeSJan Lentfer pos = os_strstr(start, "<TNCC-TNCS-Message>");
8016d49e1aeSJan Lentfer if (pos == NULL)
8026d49e1aeSJan Lentfer break;
8036d49e1aeSJan Lentfer start = pos + 19;
8046d49e1aeSJan Lentfer end = os_strstr(start, "</TNCC-TNCS-Message>");
8056d49e1aeSJan Lentfer if (end == NULL)
8066d49e1aeSJan Lentfer break;
8076d49e1aeSJan Lentfer *end = '\0';
8086d49e1aeSJan Lentfer endpos = end;
8096d49e1aeSJan Lentfer end += 20;
8106d49e1aeSJan Lentfer
8116d49e1aeSJan Lentfer if (tncc_get_type(start, &type) < 0) {
8126d49e1aeSJan Lentfer *endpos = '<';
8136d49e1aeSJan Lentfer start = end;
8146d49e1aeSJan Lentfer continue;
8156d49e1aeSJan Lentfer }
8166d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
8176d49e1aeSJan Lentfer type);
8186d49e1aeSJan Lentfer
8196d49e1aeSJan Lentfer /* Base64 OR XML */
8206d49e1aeSJan Lentfer decoded = NULL;
8216d49e1aeSJan Lentfer xml = NULL;
8226d49e1aeSJan Lentfer xmlend = NULL;
8236d49e1aeSJan Lentfer pos = os_strstr(start, "<XML>");
8246d49e1aeSJan Lentfer if (pos) {
8256d49e1aeSJan Lentfer pos += 5;
8266d49e1aeSJan Lentfer pos2 = os_strstr(pos, "</XML>");
8276d49e1aeSJan Lentfer if (pos2 == NULL) {
8286d49e1aeSJan Lentfer *endpos = '<';
8296d49e1aeSJan Lentfer start = end;
8306d49e1aeSJan Lentfer continue;
8316d49e1aeSJan Lentfer }
8326d49e1aeSJan Lentfer xmlend = pos2;
8336d49e1aeSJan Lentfer xml = pos;
8346d49e1aeSJan Lentfer } else {
8356d49e1aeSJan Lentfer decoded = tncc_get_base64(start, &decoded_len);
8366d49e1aeSJan Lentfer if (decoded == NULL) {
8376d49e1aeSJan Lentfer *endpos = '<';
8386d49e1aeSJan Lentfer start = end;
8396d49e1aeSJan Lentfer continue;
8406d49e1aeSJan Lentfer }
8416d49e1aeSJan Lentfer }
8426d49e1aeSJan Lentfer
8436d49e1aeSJan Lentfer if (decoded) {
8446d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_MSGDUMP,
8456d49e1aeSJan Lentfer "TNC: TNCC-TNCS-Message Base64",
8466d49e1aeSJan Lentfer decoded, decoded_len);
8476d49e1aeSJan Lentfer os_free(decoded);
8486d49e1aeSJan Lentfer }
8496d49e1aeSJan Lentfer
8506d49e1aeSJan Lentfer if (xml) {
8516d49e1aeSJan Lentfer wpa_hexdump_ascii(MSG_MSGDUMP,
8526d49e1aeSJan Lentfer "TNC: TNCC-TNCS-Message XML",
8536d49e1aeSJan Lentfer (unsigned char *) xml,
8546d49e1aeSJan Lentfer xmlend - xml);
8556d49e1aeSJan Lentfer }
8566d49e1aeSJan Lentfer
8576d49e1aeSJan Lentfer if (type == TNC_TNCCS_RECOMMENDATION && xml) {
8586d49e1aeSJan Lentfer /*
8596d49e1aeSJan Lentfer * <TNCCS-Recommendation type="allow">
8606d49e1aeSJan Lentfer * </TNCCS-Recommendation>
8616d49e1aeSJan Lentfer */
8626d49e1aeSJan Lentfer *xmlend = '\0';
8636d49e1aeSJan Lentfer res = tncc_get_recommendation(xml);
8646d49e1aeSJan Lentfer *xmlend = '<';
8656d49e1aeSJan Lentfer recommendation_msg = 1;
8666d49e1aeSJan Lentfer }
8676d49e1aeSJan Lentfer
8686d49e1aeSJan Lentfer start = end;
8696d49e1aeSJan Lentfer }
8706d49e1aeSJan Lentfer
8716d49e1aeSJan Lentfer os_free(buf);
8726d49e1aeSJan Lentfer
8736d49e1aeSJan Lentfer if (recommendation_msg)
8746d49e1aeSJan Lentfer tncc_notify_recommendation(tncc, res);
8756d49e1aeSJan Lentfer
8766d49e1aeSJan Lentfer return res;
8776d49e1aeSJan Lentfer }
8786d49e1aeSJan Lentfer
8796d49e1aeSJan Lentfer
8806d49e1aeSJan Lentfer #ifdef CONFIG_NATIVE_WINDOWS
tncc_read_config_reg(struct tncc_data * tncc,HKEY hive)8816d49e1aeSJan Lentfer static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
8826d49e1aeSJan Lentfer {
8836d49e1aeSJan Lentfer HKEY hk, hk2;
8846d49e1aeSJan Lentfer LONG ret;
8856d49e1aeSJan Lentfer DWORD i;
8866d49e1aeSJan Lentfer struct tnc_if_imc *imc, *last;
8876d49e1aeSJan Lentfer int j;
8886d49e1aeSJan Lentfer
8896d49e1aeSJan Lentfer last = tncc->imc;
8906d49e1aeSJan Lentfer while (last && last->next)
8916d49e1aeSJan Lentfer last = last->next;
8926d49e1aeSJan Lentfer
8936d49e1aeSJan Lentfer ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
8946d49e1aeSJan Lentfer &hk);
8956d49e1aeSJan Lentfer if (ret != ERROR_SUCCESS)
8966d49e1aeSJan Lentfer return 0;
8976d49e1aeSJan Lentfer
8986d49e1aeSJan Lentfer for (i = 0; ; i++) {
8996d49e1aeSJan Lentfer TCHAR name[255], *val;
9006d49e1aeSJan Lentfer DWORD namelen, buflen;
9016d49e1aeSJan Lentfer
9026d49e1aeSJan Lentfer namelen = 255;
9036d49e1aeSJan Lentfer ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
9046d49e1aeSJan Lentfer NULL);
9056d49e1aeSJan Lentfer
9066d49e1aeSJan Lentfer if (ret == ERROR_NO_MORE_ITEMS)
9076d49e1aeSJan Lentfer break;
9086d49e1aeSJan Lentfer
9096d49e1aeSJan Lentfer if (ret != ERROR_SUCCESS) {
9106d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
9116d49e1aeSJan Lentfer (unsigned int) ret);
9126d49e1aeSJan Lentfer break;
9136d49e1aeSJan Lentfer }
9146d49e1aeSJan Lentfer
9156d49e1aeSJan Lentfer if (namelen >= 255)
9166d49e1aeSJan Lentfer namelen = 255 - 1;
9176d49e1aeSJan Lentfer name[namelen] = '\0';
9186d49e1aeSJan Lentfer
9196d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
9206d49e1aeSJan Lentfer
9216d49e1aeSJan Lentfer ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
9226d49e1aeSJan Lentfer if (ret != ERROR_SUCCESS) {
9236d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
9246d49e1aeSJan Lentfer "'", name);
9256d49e1aeSJan Lentfer continue;
9266d49e1aeSJan Lentfer }
9276d49e1aeSJan Lentfer
9286d49e1aeSJan Lentfer ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
9296d49e1aeSJan Lentfer &buflen);
9306d49e1aeSJan Lentfer if (ret != ERROR_SUCCESS) {
9316d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
9326d49e1aeSJan Lentfer "IMC key '" TSTR "'", name);
9336d49e1aeSJan Lentfer RegCloseKey(hk2);
9346d49e1aeSJan Lentfer continue;
9356d49e1aeSJan Lentfer }
9366d49e1aeSJan Lentfer
9376d49e1aeSJan Lentfer val = os_malloc(buflen);
9386d49e1aeSJan Lentfer if (val == NULL) {
9396d49e1aeSJan Lentfer RegCloseKey(hk2);
9406d49e1aeSJan Lentfer continue;
9416d49e1aeSJan Lentfer }
9426d49e1aeSJan Lentfer
9436d49e1aeSJan Lentfer ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
9446d49e1aeSJan Lentfer (LPBYTE) val, &buflen);
9456d49e1aeSJan Lentfer if (ret != ERROR_SUCCESS) {
9466d49e1aeSJan Lentfer os_free(val);
9476d49e1aeSJan Lentfer RegCloseKey(hk2);
9486d49e1aeSJan Lentfer continue;
9496d49e1aeSJan Lentfer }
9506d49e1aeSJan Lentfer
9516d49e1aeSJan Lentfer RegCloseKey(hk2);
9526d49e1aeSJan Lentfer
9536d49e1aeSJan Lentfer wpa_unicode2ascii_inplace(val);
9546d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
9556d49e1aeSJan Lentfer
9566d49e1aeSJan Lentfer for (j = 0; j < TNC_MAX_IMC_ID; j++) {
9576d49e1aeSJan Lentfer if (tnc_imc[j] == NULL)
9586d49e1aeSJan Lentfer break;
9596d49e1aeSJan Lentfer }
9606d49e1aeSJan Lentfer if (j >= TNC_MAX_IMC_ID) {
9616d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
9626d49e1aeSJan Lentfer os_free(val);
9636d49e1aeSJan Lentfer continue;
9646d49e1aeSJan Lentfer }
9656d49e1aeSJan Lentfer
9666d49e1aeSJan Lentfer imc = os_zalloc(sizeof(*imc));
9676d49e1aeSJan Lentfer if (imc == NULL) {
9686d49e1aeSJan Lentfer os_free(val);
9696d49e1aeSJan Lentfer break;
9706d49e1aeSJan Lentfer }
9716d49e1aeSJan Lentfer
9726d49e1aeSJan Lentfer imc->imcID = j;
9736d49e1aeSJan Lentfer
9746d49e1aeSJan Lentfer wpa_unicode2ascii_inplace(name);
9756d49e1aeSJan Lentfer imc->name = os_strdup((char *) name);
9766d49e1aeSJan Lentfer imc->path = os_strdup((char *) val);
9776d49e1aeSJan Lentfer
9786d49e1aeSJan Lentfer os_free(val);
9796d49e1aeSJan Lentfer
9806d49e1aeSJan Lentfer if (last == NULL)
9816d49e1aeSJan Lentfer tncc->imc = imc;
9826d49e1aeSJan Lentfer else
9836d49e1aeSJan Lentfer last->next = imc;
9846d49e1aeSJan Lentfer last = imc;
9856d49e1aeSJan Lentfer
9866d49e1aeSJan Lentfer tnc_imc[imc->imcID] = imc;
9876d49e1aeSJan Lentfer }
9886d49e1aeSJan Lentfer
9896d49e1aeSJan Lentfer RegCloseKey(hk);
9906d49e1aeSJan Lentfer
9916d49e1aeSJan Lentfer return 0;
9926d49e1aeSJan Lentfer }
9936d49e1aeSJan Lentfer
9946d49e1aeSJan Lentfer
tncc_read_config(struct tncc_data * tncc)9956d49e1aeSJan Lentfer static int tncc_read_config(struct tncc_data *tncc)
9966d49e1aeSJan Lentfer {
9976d49e1aeSJan Lentfer if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
9986d49e1aeSJan Lentfer tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
9996d49e1aeSJan Lentfer return -1;
10006d49e1aeSJan Lentfer return 0;
10016d49e1aeSJan Lentfer }
10026d49e1aeSJan Lentfer
10036d49e1aeSJan Lentfer #else /* CONFIG_NATIVE_WINDOWS */
10046d49e1aeSJan Lentfer
tncc_parse_imc(char * start,char * end,int * error)10056d49e1aeSJan Lentfer static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
10066d49e1aeSJan Lentfer {
10076d49e1aeSJan Lentfer struct tnc_if_imc *imc;
10086d49e1aeSJan Lentfer char *pos, *pos2;
10096d49e1aeSJan Lentfer int i;
10106d49e1aeSJan Lentfer
10116d49e1aeSJan Lentfer for (i = 0; i < TNC_MAX_IMC_ID; i++) {
10126d49e1aeSJan Lentfer if (tnc_imc[i] == NULL)
10136d49e1aeSJan Lentfer break;
10146d49e1aeSJan Lentfer }
10156d49e1aeSJan Lentfer if (i >= TNC_MAX_IMC_ID) {
10166d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
10176d49e1aeSJan Lentfer return NULL;
10186d49e1aeSJan Lentfer }
10196d49e1aeSJan Lentfer
10206d49e1aeSJan Lentfer imc = os_zalloc(sizeof(*imc));
10216d49e1aeSJan Lentfer if (imc == NULL) {
10226d49e1aeSJan Lentfer *error = 1;
10236d49e1aeSJan Lentfer return NULL;
10246d49e1aeSJan Lentfer }
10256d49e1aeSJan Lentfer
10266d49e1aeSJan Lentfer imc->imcID = i;
10276d49e1aeSJan Lentfer
10286d49e1aeSJan Lentfer pos = start;
10296d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
10306d49e1aeSJan Lentfer if (pos + 1 >= end || *pos != '"') {
10316d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
10326d49e1aeSJan Lentfer "(no starting quotation mark)", start);
10336d49e1aeSJan Lentfer os_free(imc);
10346d49e1aeSJan Lentfer return NULL;
10356d49e1aeSJan Lentfer }
10366d49e1aeSJan Lentfer
10376d49e1aeSJan Lentfer pos++;
10386d49e1aeSJan Lentfer pos2 = pos;
10396d49e1aeSJan Lentfer while (pos2 < end && *pos2 != '"')
10406d49e1aeSJan Lentfer pos2++;
10416d49e1aeSJan Lentfer if (pos2 >= end) {
10426d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
10436d49e1aeSJan Lentfer "(no ending quotation mark)", start);
10446d49e1aeSJan Lentfer os_free(imc);
10456d49e1aeSJan Lentfer return NULL;
10466d49e1aeSJan Lentfer }
10476d49e1aeSJan Lentfer *pos2 = '\0';
10486d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
10496d49e1aeSJan Lentfer imc->name = os_strdup(pos);
10506d49e1aeSJan Lentfer
10516d49e1aeSJan Lentfer pos = pos2 + 1;
10526d49e1aeSJan Lentfer if (pos >= end || *pos != ' ') {
10536d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
10546d49e1aeSJan Lentfer "(no space after name)", start);
10556d49e1aeSJan Lentfer os_free(imc->name);
10566d49e1aeSJan Lentfer os_free(imc);
10576d49e1aeSJan Lentfer return NULL;
10586d49e1aeSJan Lentfer }
10596d49e1aeSJan Lentfer
10606d49e1aeSJan Lentfer pos++;
10616d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
10626d49e1aeSJan Lentfer imc->path = os_strdup(pos);
10636d49e1aeSJan Lentfer tnc_imc[imc->imcID] = imc;
10646d49e1aeSJan Lentfer
10656d49e1aeSJan Lentfer return imc;
10666d49e1aeSJan Lentfer }
10676d49e1aeSJan Lentfer
10686d49e1aeSJan Lentfer
tncc_read_config(struct tncc_data * tncc)10696d49e1aeSJan Lentfer static int tncc_read_config(struct tncc_data *tncc)
10706d49e1aeSJan Lentfer {
10716d49e1aeSJan Lentfer char *config, *end, *pos, *line_end;
10726d49e1aeSJan Lentfer size_t config_len;
10736d49e1aeSJan Lentfer struct tnc_if_imc *imc, *last;
10746d49e1aeSJan Lentfer
10756d49e1aeSJan Lentfer last = NULL;
10766d49e1aeSJan Lentfer
10776d49e1aeSJan Lentfer config = os_readfile(TNC_CONFIG_FILE, &config_len);
10786d49e1aeSJan Lentfer if (config == NULL) {
10796d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
10806d49e1aeSJan Lentfer "file '%s'", TNC_CONFIG_FILE);
10816d49e1aeSJan Lentfer return -1;
10826d49e1aeSJan Lentfer }
10836d49e1aeSJan Lentfer
10846d49e1aeSJan Lentfer end = config + config_len;
10856d49e1aeSJan Lentfer for (pos = config; pos < end; pos = line_end + 1) {
10866d49e1aeSJan Lentfer line_end = pos;
10876d49e1aeSJan Lentfer while (*line_end != '\n' && *line_end != '\r' &&
10886d49e1aeSJan Lentfer line_end < end)
10896d49e1aeSJan Lentfer line_end++;
10906d49e1aeSJan Lentfer *line_end = '\0';
10916d49e1aeSJan Lentfer
10926d49e1aeSJan Lentfer if (os_strncmp(pos, "IMC ", 4) == 0) {
10936d49e1aeSJan Lentfer int error = 0;
10946d49e1aeSJan Lentfer
10956d49e1aeSJan Lentfer imc = tncc_parse_imc(pos + 4, line_end, &error);
1096*a1157835SDaniel Fojt if (error) {
1097*a1157835SDaniel Fojt os_free(config);
10986d49e1aeSJan Lentfer return -1;
1099*a1157835SDaniel Fojt }
11006d49e1aeSJan Lentfer if (imc) {
11016d49e1aeSJan Lentfer if (last == NULL)
11026d49e1aeSJan Lentfer tncc->imc = imc;
11036d49e1aeSJan Lentfer else
11046d49e1aeSJan Lentfer last->next = imc;
11056d49e1aeSJan Lentfer last = imc;
11066d49e1aeSJan Lentfer }
11076d49e1aeSJan Lentfer }
11086d49e1aeSJan Lentfer }
11096d49e1aeSJan Lentfer
11106d49e1aeSJan Lentfer os_free(config);
11116d49e1aeSJan Lentfer
11126d49e1aeSJan Lentfer return 0;
11136d49e1aeSJan Lentfer }
11146d49e1aeSJan Lentfer
11156d49e1aeSJan Lentfer #endif /* CONFIG_NATIVE_WINDOWS */
11166d49e1aeSJan Lentfer
11176d49e1aeSJan Lentfer
tncc_init(void)11186d49e1aeSJan Lentfer struct tncc_data * tncc_init(void)
11196d49e1aeSJan Lentfer {
11206d49e1aeSJan Lentfer struct tncc_data *tncc;
11216d49e1aeSJan Lentfer struct tnc_if_imc *imc;
11226d49e1aeSJan Lentfer
11236d49e1aeSJan Lentfer tncc = os_zalloc(sizeof(*tncc));
11246d49e1aeSJan Lentfer if (tncc == NULL)
11256d49e1aeSJan Lentfer return NULL;
11266d49e1aeSJan Lentfer
11276d49e1aeSJan Lentfer /* TODO:
11286d49e1aeSJan Lentfer * move loading and Initialize() to a location that is not
11296d49e1aeSJan Lentfer * re-initialized for every EAP-TNC session (?)
11306d49e1aeSJan Lentfer */
11316d49e1aeSJan Lentfer
11326d49e1aeSJan Lentfer if (tncc_read_config(tncc) < 0) {
11336d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
11346d49e1aeSJan Lentfer goto failed;
11356d49e1aeSJan Lentfer }
11366d49e1aeSJan Lentfer
11376d49e1aeSJan Lentfer for (imc = tncc->imc; imc; imc = imc->next) {
11386d49e1aeSJan Lentfer if (tncc_load_imc(imc)) {
11396d49e1aeSJan Lentfer wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
11406d49e1aeSJan Lentfer imc->name);
11416d49e1aeSJan Lentfer goto failed;
11426d49e1aeSJan Lentfer }
11436d49e1aeSJan Lentfer }
11446d49e1aeSJan Lentfer
11456d49e1aeSJan Lentfer return tncc;
11466d49e1aeSJan Lentfer
11476d49e1aeSJan Lentfer failed:
11486d49e1aeSJan Lentfer tncc_deinit(tncc);
11496d49e1aeSJan Lentfer return NULL;
11506d49e1aeSJan Lentfer }
11516d49e1aeSJan Lentfer
11526d49e1aeSJan Lentfer
tncc_deinit(struct tncc_data * tncc)11536d49e1aeSJan Lentfer void tncc_deinit(struct tncc_data *tncc)
11546d49e1aeSJan Lentfer {
11556d49e1aeSJan Lentfer struct tnc_if_imc *imc, *prev;
11566d49e1aeSJan Lentfer
11576d49e1aeSJan Lentfer imc = tncc->imc;
11586d49e1aeSJan Lentfer while (imc) {
11596d49e1aeSJan Lentfer tncc_unload_imc(imc);
11606d49e1aeSJan Lentfer
11616d49e1aeSJan Lentfer prev = imc;
11626d49e1aeSJan Lentfer imc = imc->next;
11636d49e1aeSJan Lentfer os_free(prev);
11646d49e1aeSJan Lentfer }
11656d49e1aeSJan Lentfer
11666d49e1aeSJan Lentfer os_free(tncc);
11676d49e1aeSJan Lentfer }
11686d49e1aeSJan Lentfer
11696d49e1aeSJan Lentfer
tncc_build_soh(int ver)11706d49e1aeSJan Lentfer static struct wpabuf * tncc_build_soh(int ver)
11716d49e1aeSJan Lentfer {
11726d49e1aeSJan Lentfer struct wpabuf *buf;
11736d49e1aeSJan Lentfer u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
11746d49e1aeSJan Lentfer u8 correlation_id[24];
11756d49e1aeSJan Lentfer /* TODO: get correct name */
11766d49e1aeSJan Lentfer char *machinename = "wpa_supplicant@w1.fi";
11776d49e1aeSJan Lentfer
11786d49e1aeSJan Lentfer if (os_get_random(correlation_id, sizeof(correlation_id)))
11796d49e1aeSJan Lentfer return NULL;
11806d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
11816d49e1aeSJan Lentfer correlation_id, sizeof(correlation_id));
11826d49e1aeSJan Lentfer
11836d49e1aeSJan Lentfer buf = wpabuf_alloc(200);
11846d49e1aeSJan Lentfer if (buf == NULL)
11856d49e1aeSJan Lentfer return NULL;
11866d49e1aeSJan Lentfer
11876d49e1aeSJan Lentfer /* Vendor-Specific TLV (Microsoft) - SoH */
11886d49e1aeSJan Lentfer wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
11896d49e1aeSJan Lentfer tlv_len = wpabuf_put(buf, 2); /* Length */
11906d49e1aeSJan Lentfer wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
11916d49e1aeSJan Lentfer wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
11926d49e1aeSJan Lentfer tlv_len2 = wpabuf_put(buf, 2); /* Length */
11936d49e1aeSJan Lentfer
11946d49e1aeSJan Lentfer /* SoH Header */
11956d49e1aeSJan Lentfer wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
11966d49e1aeSJan Lentfer outer_len = wpabuf_put(buf, 2);
11976d49e1aeSJan Lentfer wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
11986d49e1aeSJan Lentfer wpabuf_put_be16(buf, ver); /* Inner Type */
11996d49e1aeSJan Lentfer inner_len = wpabuf_put(buf, 2);
12006d49e1aeSJan Lentfer
12016d49e1aeSJan Lentfer if (ver == 2) {
12026d49e1aeSJan Lentfer /* SoH Mode Sub-Header */
12036d49e1aeSJan Lentfer /* Outer Type */
12046d49e1aeSJan Lentfer wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
12056d49e1aeSJan Lentfer wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
12066d49e1aeSJan Lentfer wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
12076d49e1aeSJan Lentfer /* Value: */
12086d49e1aeSJan Lentfer wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
12096d49e1aeSJan Lentfer wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
12106d49e1aeSJan Lentfer wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
12116d49e1aeSJan Lentfer }
12126d49e1aeSJan Lentfer
12136d49e1aeSJan Lentfer /* SSoH TLV */
12146d49e1aeSJan Lentfer /* System-Health-Id */
12156d49e1aeSJan Lentfer wpabuf_put_be16(buf, 0x0002); /* Type */
12166d49e1aeSJan Lentfer wpabuf_put_be16(buf, 4); /* Length */
12176d49e1aeSJan Lentfer wpabuf_put_be32(buf, 79616);
12186d49e1aeSJan Lentfer /* Vendor-Specific Attribute */
12196d49e1aeSJan Lentfer wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
12206d49e1aeSJan Lentfer ssoh_len = wpabuf_put(buf, 2);
12216d49e1aeSJan Lentfer wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
12226d49e1aeSJan Lentfer
12236d49e1aeSJan Lentfer /* MS-Packet-Info */
12246d49e1aeSJan Lentfer wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO);
12256d49e1aeSJan Lentfer /* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be:
12266d49e1aeSJan Lentfer * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP
12276d49e1aeSJan Lentfer * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit
12286d49e1aeSJan Lentfer * would not be in the specified location.
12296d49e1aeSJan Lentfer * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits)
12306d49e1aeSJan Lentfer */
12316d49e1aeSJan Lentfer wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
12326d49e1aeSJan Lentfer
12336d49e1aeSJan Lentfer /* MS-Machine-Inventory */
12346d49e1aeSJan Lentfer /* TODO: get correct values; 0 = not applicable for OS */
12356d49e1aeSJan Lentfer wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY);
12366d49e1aeSJan Lentfer wpabuf_put_be32(buf, 0); /* osVersionMajor */
12376d49e1aeSJan Lentfer wpabuf_put_be32(buf, 0); /* osVersionMinor */
12386d49e1aeSJan Lentfer wpabuf_put_be32(buf, 0); /* osVersionBuild */
12396d49e1aeSJan Lentfer wpabuf_put_be16(buf, 0); /* spVersionMajor */
12406d49e1aeSJan Lentfer wpabuf_put_be16(buf, 0); /* spVersionMinor */
12416d49e1aeSJan Lentfer wpabuf_put_be16(buf, 0); /* procArch */
12426d49e1aeSJan Lentfer
12436d49e1aeSJan Lentfer /* MS-MachineName */
12446d49e1aeSJan Lentfer wpabuf_put_u8(buf, SSOH_MS_MACHINENAME);
12456d49e1aeSJan Lentfer wpabuf_put_be16(buf, os_strlen(machinename) + 1);
12466d49e1aeSJan Lentfer wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1);
12476d49e1aeSJan Lentfer
12486d49e1aeSJan Lentfer /* MS-CorrelationId */
12496d49e1aeSJan Lentfer wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID);
12506d49e1aeSJan Lentfer wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
12516d49e1aeSJan Lentfer
12526d49e1aeSJan Lentfer /* MS-Quarantine-State */
12536d49e1aeSJan Lentfer wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE);
12546d49e1aeSJan Lentfer wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */
12556d49e1aeSJan Lentfer wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */
12566d49e1aeSJan Lentfer wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */
12576d49e1aeSJan Lentfer wpabuf_put_be16(buf, 1); /* urlLenInBytes */
12586d49e1aeSJan Lentfer wpabuf_put_u8(buf, 0); /* null termination for the url */
12596d49e1aeSJan Lentfer
12606d49e1aeSJan Lentfer /* MS-Machine-Inventory-Ex */
12616d49e1aeSJan Lentfer wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX);
12626d49e1aeSJan Lentfer wpabuf_put_be32(buf, 0); /* Reserved
12636d49e1aeSJan Lentfer * (note: Windows XP SP3 uses 0xdecafbad) */
12646d49e1aeSJan Lentfer wpabuf_put_u8(buf, 1); /* ProductType: Client */
12656d49e1aeSJan Lentfer
12666d49e1aeSJan Lentfer /* Update SSoH Length */
12676d49e1aeSJan Lentfer end = wpabuf_put(buf, 0);
12686d49e1aeSJan Lentfer WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
12696d49e1aeSJan Lentfer
12706d49e1aeSJan Lentfer /* TODO: SoHReportEntry TLV (zero or more) */
12716d49e1aeSJan Lentfer
12726d49e1aeSJan Lentfer /* Update length fields */
12736d49e1aeSJan Lentfer end = wpabuf_put(buf, 0);
12746d49e1aeSJan Lentfer WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
12756d49e1aeSJan Lentfer WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
12766d49e1aeSJan Lentfer WPA_PUT_BE16(outer_len, end - outer_len - 2);
12776d49e1aeSJan Lentfer WPA_PUT_BE16(inner_len, end - inner_len - 2);
12786d49e1aeSJan Lentfer
12796d49e1aeSJan Lentfer return buf;
12806d49e1aeSJan Lentfer }
12816d49e1aeSJan Lentfer
12826d49e1aeSJan Lentfer
tncc_process_soh_request(int ver,const u8 * data,size_t len)12836d49e1aeSJan Lentfer struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len)
12846d49e1aeSJan Lentfer {
12856d49e1aeSJan Lentfer const u8 *pos;
12866d49e1aeSJan Lentfer
12876d49e1aeSJan Lentfer wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
12886d49e1aeSJan Lentfer
12896d49e1aeSJan Lentfer if (len < 12)
12906d49e1aeSJan Lentfer return NULL;
12916d49e1aeSJan Lentfer
12926d49e1aeSJan Lentfer /* SoH Request */
12936d49e1aeSJan Lentfer pos = data;
12946d49e1aeSJan Lentfer
12956d49e1aeSJan Lentfer /* TLV Type */
12966d49e1aeSJan Lentfer if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
12976d49e1aeSJan Lentfer return NULL;
12986d49e1aeSJan Lentfer pos += 2;
12996d49e1aeSJan Lentfer
13006d49e1aeSJan Lentfer /* Length */
13016d49e1aeSJan Lentfer if (WPA_GET_BE16(pos) < 8)
13026d49e1aeSJan Lentfer return NULL;
13036d49e1aeSJan Lentfer pos += 2;
13046d49e1aeSJan Lentfer
13056d49e1aeSJan Lentfer /* Vendor_Id */
13066d49e1aeSJan Lentfer if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
13076d49e1aeSJan Lentfer return NULL;
13086d49e1aeSJan Lentfer pos += 4;
13096d49e1aeSJan Lentfer
13106d49e1aeSJan Lentfer /* TLV Type */
13116d49e1aeSJan Lentfer if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
13126d49e1aeSJan Lentfer return NULL;
13136d49e1aeSJan Lentfer
13146d49e1aeSJan Lentfer wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
13156d49e1aeSJan Lentfer
13166d49e1aeSJan Lentfer return tncc_build_soh(2);
13176d49e1aeSJan Lentfer }
1318