xref: /freebsd/contrib/wpa/src/eap_peer/tncc.c (revision c1d255d3)
139beb93cSSam Leffler /*
239beb93cSSam Leffler  * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
339beb93cSSam Leffler  * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
439beb93cSSam Leffler  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
739beb93cSSam Leffler  */
839beb93cSSam Leffler 
939beb93cSSam Leffler #include "includes.h"
1039beb93cSSam Leffler #ifndef CONFIG_NATIVE_WINDOWS
1139beb93cSSam Leffler #include <dlfcn.h>
1239beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
1339beb93cSSam Leffler 
1439beb93cSSam Leffler #include "common.h"
1539beb93cSSam Leffler #include "base64.h"
165b9c547cSRui Paulo #include "common/tnc.h"
1739beb93cSSam Leffler #include "tncc.h"
1839beb93cSSam Leffler #include "eap_common/eap_tlv_common.h"
1939beb93cSSam Leffler #include "eap_common/eap_defs.h"
2039beb93cSSam Leffler 
2139beb93cSSam Leffler 
2239beb93cSSam Leffler #ifdef UNICODE
2339beb93cSSam Leffler #define TSTR "%S"
2439beb93cSSam Leffler #else /* UNICODE */
2539beb93cSSam Leffler #define TSTR "%s"
2639beb93cSSam Leffler #endif /* UNICODE */
2739beb93cSSam Leffler 
2839beb93cSSam Leffler 
295b9c547cSRui Paulo #ifndef TNC_CONFIG_FILE
3039beb93cSSam Leffler #define TNC_CONFIG_FILE "/etc/tnc_config"
315b9c547cSRui Paulo #endif /* TNC_CONFIG_FILE */
3239beb93cSSam Leffler #define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
3339beb93cSSam Leffler #define IF_TNCCS_START \
3439beb93cSSam Leffler "<?xml version=\"1.0\"?>\n" \
3539beb93cSSam Leffler "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
3639beb93cSSam Leffler "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
3739beb93cSSam Leffler "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
3839beb93cSSam Leffler "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
3939beb93cSSam Leffler "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
4039beb93cSSam Leffler #define IF_TNCCS_END "\n</TNCCS-Batch>"
4139beb93cSSam Leffler 
4239beb93cSSam Leffler /* TNC IF-IMC */
4339beb93cSSam Leffler 
4439beb93cSSam Leffler /* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
4539beb93cSSam Leffler enum {
4639beb93cSSam Leffler 	SSOH_MS_MACHINE_INVENTORY = 1,
4739beb93cSSam Leffler 	SSOH_MS_QUARANTINE_STATE = 2,
4839beb93cSSam Leffler 	SSOH_MS_PACKET_INFO = 3,
4939beb93cSSam Leffler 	SSOH_MS_SYSTEMGENERATED_IDS = 4,
5039beb93cSSam Leffler 	SSOH_MS_MACHINENAME = 5,
5139beb93cSSam Leffler 	SSOH_MS_CORRELATIONID = 6,
5239beb93cSSam Leffler 	SSOH_MS_INSTALLED_SHVS = 7,
5339beb93cSSam Leffler 	SSOH_MS_MACHINE_INVENTORY_EX = 8
5439beb93cSSam Leffler };
5539beb93cSSam Leffler 
5639beb93cSSam Leffler struct tnc_if_imc {
5739beb93cSSam Leffler 	struct tnc_if_imc *next;
5839beb93cSSam Leffler 	char *name;
5939beb93cSSam Leffler 	char *path;
6039beb93cSSam Leffler 	void *dlhandle; /* from dlopen() */
6139beb93cSSam Leffler 	TNC_IMCID imcID;
6239beb93cSSam Leffler 	TNC_ConnectionID connectionID;
6339beb93cSSam Leffler 	TNC_MessageTypeList supported_types;
6439beb93cSSam Leffler 	size_t num_supported_types;
6539beb93cSSam Leffler 	u8 *imc_send;
6639beb93cSSam Leffler 	size_t imc_send_len;
6739beb93cSSam Leffler 
6839beb93cSSam Leffler 	/* Functions implemented by IMCs (with TNC_IMC_ prefix) */
6939beb93cSSam Leffler 	TNC_Result (*Initialize)(
7039beb93cSSam Leffler 		TNC_IMCID imcID,
7139beb93cSSam Leffler 		TNC_Version minVersion,
7239beb93cSSam Leffler 		TNC_Version maxVersion,
7339beb93cSSam Leffler 		TNC_Version *pOutActualVersion);
7439beb93cSSam Leffler 	TNC_Result (*NotifyConnectionChange)(
7539beb93cSSam Leffler 		TNC_IMCID imcID,
7639beb93cSSam Leffler 		TNC_ConnectionID connectionID,
7739beb93cSSam Leffler 		TNC_ConnectionState newState);
7839beb93cSSam Leffler 	TNC_Result (*BeginHandshake)(
7939beb93cSSam Leffler 		TNC_IMCID imcID,
8039beb93cSSam Leffler 		TNC_ConnectionID connectionID);
8139beb93cSSam Leffler 	TNC_Result (*ReceiveMessage)(
8239beb93cSSam Leffler 		TNC_IMCID imcID,
8339beb93cSSam Leffler 		TNC_ConnectionID connectionID,
8439beb93cSSam Leffler 		TNC_BufferReference messageBuffer,
8539beb93cSSam Leffler 		TNC_UInt32 messageLength,
8639beb93cSSam Leffler 		TNC_MessageType messageType);
8739beb93cSSam Leffler 	TNC_Result (*BatchEnding)(
8839beb93cSSam Leffler 		TNC_IMCID imcID,
8939beb93cSSam Leffler 		TNC_ConnectionID connectionID);
9039beb93cSSam Leffler 	TNC_Result (*Terminate)(TNC_IMCID imcID);
9139beb93cSSam Leffler 	TNC_Result (*ProvideBindFunction)(
9239beb93cSSam Leffler 		TNC_IMCID imcID,
9339beb93cSSam Leffler 		TNC_TNCC_BindFunctionPointer bindFunction);
9439beb93cSSam Leffler };
9539beb93cSSam Leffler 
9639beb93cSSam Leffler struct tncc_data {
9739beb93cSSam Leffler 	struct tnc_if_imc *imc;
9839beb93cSSam Leffler 	unsigned int last_batchid;
9939beb93cSSam Leffler };
10039beb93cSSam Leffler 
10139beb93cSSam Leffler #define TNC_MAX_IMC_ID 10
10239beb93cSSam Leffler static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
10339beb93cSSam Leffler 
10439beb93cSSam Leffler 
10539beb93cSSam Leffler /* TNCC functions that IMCs can call */
10639beb93cSSam Leffler 
TNC_TNCC_ReportMessageTypes(TNC_IMCID imcID,TNC_MessageTypeList supportedTypes,TNC_UInt32 typeCount)107780fb4a2SCy Schubert static TNC_Result TNC_TNCC_ReportMessageTypes(
10839beb93cSSam Leffler 	TNC_IMCID imcID,
10939beb93cSSam Leffler 	TNC_MessageTypeList supportedTypes,
11039beb93cSSam Leffler 	TNC_UInt32 typeCount)
11139beb93cSSam Leffler {
11239beb93cSSam Leffler 	TNC_UInt32 i;
11339beb93cSSam Leffler 	struct tnc_if_imc *imc;
11439beb93cSSam Leffler 
11539beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
11639beb93cSSam Leffler 		   "typeCount=%lu)",
11739beb93cSSam Leffler 		   (unsigned long) imcID, (unsigned long) typeCount);
11839beb93cSSam Leffler 
11939beb93cSSam Leffler 	for (i = 0; i < typeCount; i++) {
12039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
12139beb93cSSam Leffler 			   i, supportedTypes[i]);
12239beb93cSSam Leffler 	}
12339beb93cSSam Leffler 
12439beb93cSSam Leffler 	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
12539beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
12639beb93cSSam Leffler 
12739beb93cSSam Leffler 	imc = tnc_imc[imcID];
12839beb93cSSam Leffler 	os_free(imc->supported_types);
12985732ac8SCy Schubert 	imc->supported_types = os_memdup(supportedTypes,
13085732ac8SCy Schubert 					 typeCount * sizeof(TNC_MessageType));
13139beb93cSSam Leffler 	if (imc->supported_types == NULL)
13239beb93cSSam Leffler 		return TNC_RESULT_FATAL;
13339beb93cSSam Leffler 	imc->num_supported_types = typeCount;
13439beb93cSSam Leffler 
13539beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
13639beb93cSSam Leffler }
13739beb93cSSam Leffler 
13839beb93cSSam Leffler 
TNC_TNCC_SendMessage(TNC_IMCID imcID,TNC_ConnectionID connectionID,TNC_BufferReference message,TNC_UInt32 messageLength,TNC_MessageType messageType)139780fb4a2SCy Schubert static TNC_Result TNC_TNCC_SendMessage(
14039beb93cSSam Leffler 	TNC_IMCID imcID,
14139beb93cSSam Leffler 	TNC_ConnectionID connectionID,
14239beb93cSSam Leffler 	TNC_BufferReference message,
14339beb93cSSam Leffler 	TNC_UInt32 messageLength,
14439beb93cSSam Leffler 	TNC_MessageType messageType)
14539beb93cSSam Leffler {
14639beb93cSSam Leffler 	struct tnc_if_imc *imc;
147*c1d255d3SCy Schubert 	char *b64;
14839beb93cSSam Leffler 	size_t b64len;
14939beb93cSSam Leffler 
15039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
15139beb93cSSam Leffler 		   "connectionID=%lu messageType=%lu)",
15239beb93cSSam Leffler 		   imcID, connectionID, messageType);
15339beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
15439beb93cSSam Leffler 			  message, messageLength);
15539beb93cSSam Leffler 
15639beb93cSSam Leffler 	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
15739beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
15839beb93cSSam Leffler 
15939beb93cSSam Leffler 	b64 = base64_encode(message, messageLength, &b64len);
16039beb93cSSam Leffler 	if (b64 == NULL)
16139beb93cSSam Leffler 		return TNC_RESULT_FATAL;
16239beb93cSSam Leffler 
16339beb93cSSam Leffler 	imc = tnc_imc[imcID];
16439beb93cSSam Leffler 	os_free(imc->imc_send);
16539beb93cSSam Leffler 	imc->imc_send_len = 0;
16639beb93cSSam Leffler 	imc->imc_send = os_zalloc(b64len + 100);
16739beb93cSSam Leffler 	if (imc->imc_send == NULL) {
16839beb93cSSam Leffler 		os_free(b64);
16939beb93cSSam Leffler 		return TNC_RESULT_OTHER;
17039beb93cSSam Leffler 	}
17139beb93cSSam Leffler 
17239beb93cSSam Leffler 	imc->imc_send_len =
17339beb93cSSam Leffler 		os_snprintf((char *) imc->imc_send, b64len + 100,
17439beb93cSSam Leffler 			    "<IMC-IMV-Message><Type>%08X</Type>"
17539beb93cSSam Leffler 			    "<Base64>%s</Base64></IMC-IMV-Message>",
17639beb93cSSam Leffler 			    (unsigned int) messageType, b64);
17739beb93cSSam Leffler 
17839beb93cSSam Leffler 	os_free(b64);
17939beb93cSSam Leffler 
18039beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
18139beb93cSSam Leffler }
18239beb93cSSam Leffler 
18339beb93cSSam Leffler 
TNC_TNCC_RequestHandshakeRetry(TNC_IMCID imcID,TNC_ConnectionID connectionID,TNC_RetryReason reason)184780fb4a2SCy Schubert static TNC_Result TNC_TNCC_RequestHandshakeRetry(
18539beb93cSSam Leffler 	TNC_IMCID imcID,
18639beb93cSSam Leffler 	TNC_ConnectionID connectionID,
18739beb93cSSam Leffler 	TNC_RetryReason reason)
18839beb93cSSam Leffler {
18939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
19039beb93cSSam Leffler 
19139beb93cSSam Leffler 	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
19239beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
19339beb93cSSam Leffler 
19439beb93cSSam Leffler 	/*
19539beb93cSSam Leffler 	 * TODO: trigger a call to eapol_sm_request_reauth(). This would
19639beb93cSSam Leffler 	 * require that the IMC continues to be loaded in memory afer
19739beb93cSSam Leffler 	 * authentication..
19839beb93cSSam Leffler 	 */
19939beb93cSSam Leffler 
20039beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
20139beb93cSSam Leffler }
20239beb93cSSam Leffler 
20339beb93cSSam Leffler 
TNC_9048_LogMessage(TNC_IMCID imcID,TNC_UInt32 severity,const char * message)204780fb4a2SCy Schubert static TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
20539beb93cSSam Leffler 				      const char *message)
20639beb93cSSam Leffler {
20739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
20839beb93cSSam Leffler 		   "severity==%lu message='%s')",
20939beb93cSSam Leffler 		   imcID, severity, message);
21039beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
21139beb93cSSam Leffler }
21239beb93cSSam Leffler 
21339beb93cSSam Leffler 
TNC_9048_UserMessage(TNC_IMCID imcID,TNC_ConnectionID connectionID,const char * message)214780fb4a2SCy Schubert static TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID,
215780fb4a2SCy Schubert 				       TNC_ConnectionID connectionID,
21639beb93cSSam Leffler 				       const char *message)
21739beb93cSSam Leffler {
21839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
21939beb93cSSam Leffler 		   "connectionID==%lu message='%s')",
22039beb93cSSam Leffler 		   imcID, connectionID, message);
22139beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
22239beb93cSSam Leffler }
22339beb93cSSam Leffler 
22439beb93cSSam Leffler 
TNC_TNCC_BindFunction(TNC_IMCID imcID,char * functionName,void ** pOutfunctionPointer)225780fb4a2SCy Schubert static TNC_Result TNC_TNCC_BindFunction(
22639beb93cSSam Leffler 	TNC_IMCID imcID,
22739beb93cSSam Leffler 	char *functionName,
22839beb93cSSam Leffler 	void **pOutfunctionPointer)
22939beb93cSSam Leffler {
23039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
23139beb93cSSam Leffler 		   "functionName='%s')", (unsigned long) imcID, functionName);
23239beb93cSSam Leffler 
23339beb93cSSam Leffler 	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
23439beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
23539beb93cSSam Leffler 
23639beb93cSSam Leffler 	if (pOutfunctionPointer == NULL)
23739beb93cSSam Leffler 		return TNC_RESULT_INVALID_PARAMETER;
23839beb93cSSam Leffler 
23939beb93cSSam Leffler 	if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
24039beb93cSSam Leffler 		*pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
24139beb93cSSam Leffler 	else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
24239beb93cSSam Leffler 		*pOutfunctionPointer = TNC_TNCC_SendMessage;
24339beb93cSSam Leffler 	else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
24439beb93cSSam Leffler 		 0)
24539beb93cSSam Leffler 		*pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
24639beb93cSSam Leffler 	else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
24739beb93cSSam Leffler 		*pOutfunctionPointer = TNC_9048_LogMessage;
24839beb93cSSam Leffler 	else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
24939beb93cSSam Leffler 		*pOutfunctionPointer = TNC_9048_UserMessage;
25039beb93cSSam Leffler 	else
25139beb93cSSam Leffler 		*pOutfunctionPointer = NULL;
25239beb93cSSam Leffler 
25339beb93cSSam Leffler 	return TNC_RESULT_SUCCESS;
25439beb93cSSam Leffler }
25539beb93cSSam Leffler 
25639beb93cSSam Leffler 
tncc_get_sym(void * handle,char * func)25739beb93cSSam Leffler static void * tncc_get_sym(void *handle, char *func)
25839beb93cSSam Leffler {
25939beb93cSSam Leffler 	void *fptr;
26039beb93cSSam Leffler 
26139beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
26239beb93cSSam Leffler #ifdef _WIN32_WCE
26339beb93cSSam Leffler 	fptr = GetProcAddressA(handle, func);
26439beb93cSSam Leffler #else /* _WIN32_WCE */
26539beb93cSSam Leffler 	fptr = GetProcAddress(handle, func);
26639beb93cSSam Leffler #endif /* _WIN32_WCE */
26739beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
26839beb93cSSam Leffler 	fptr = dlsym(handle, func);
26939beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
27039beb93cSSam Leffler 
27139beb93cSSam Leffler 	return fptr;
27239beb93cSSam Leffler }
27339beb93cSSam Leffler 
27439beb93cSSam Leffler 
tncc_imc_resolve_funcs(struct tnc_if_imc * imc)27539beb93cSSam Leffler static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
27639beb93cSSam Leffler {
27739beb93cSSam Leffler 	void *handle = imc->dlhandle;
27839beb93cSSam Leffler 
27939beb93cSSam Leffler 	/* Mandatory IMC functions */
28039beb93cSSam Leffler 	imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
28139beb93cSSam Leffler 	if (imc->Initialize == NULL) {
28239beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
28339beb93cSSam Leffler 			   "TNC_IMC_Initialize");
28439beb93cSSam Leffler 		return -1;
28539beb93cSSam Leffler 	}
28639beb93cSSam Leffler 
28739beb93cSSam Leffler 	imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
28839beb93cSSam Leffler 	if (imc->BeginHandshake == NULL) {
28939beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
29039beb93cSSam Leffler 			   "TNC_IMC_BeginHandshake");
29139beb93cSSam Leffler 		return -1;
29239beb93cSSam Leffler 	}
29339beb93cSSam Leffler 
29439beb93cSSam Leffler 	imc->ProvideBindFunction =
29539beb93cSSam Leffler 		tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
29639beb93cSSam Leffler 	if (imc->ProvideBindFunction == NULL) {
29739beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
29839beb93cSSam Leffler 			   "TNC_IMC_ProvideBindFunction");
29939beb93cSSam Leffler 		return -1;
30039beb93cSSam Leffler 	}
30139beb93cSSam Leffler 
30239beb93cSSam Leffler 	/* Optional IMC functions */
30339beb93cSSam Leffler 	imc->NotifyConnectionChange =
30439beb93cSSam Leffler 		tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
30539beb93cSSam Leffler 	imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
30639beb93cSSam Leffler 	imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
30739beb93cSSam Leffler 	imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
30839beb93cSSam Leffler 
30939beb93cSSam Leffler 	return 0;
31039beb93cSSam Leffler }
31139beb93cSSam Leffler 
31239beb93cSSam Leffler 
tncc_imc_initialize(struct tnc_if_imc * imc)31339beb93cSSam Leffler static int tncc_imc_initialize(struct tnc_if_imc *imc)
31439beb93cSSam Leffler {
31539beb93cSSam Leffler 	TNC_Result res;
31639beb93cSSam Leffler 	TNC_Version imc_ver;
31739beb93cSSam Leffler 
31839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
31939beb93cSSam Leffler 		   imc->name);
32039beb93cSSam Leffler 	res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
32139beb93cSSam Leffler 			      TNC_IFIMC_VERSION_1, &imc_ver);
32239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
32339beb93cSSam Leffler 		   (unsigned long) res, (unsigned long) imc_ver);
32439beb93cSSam Leffler 
32539beb93cSSam Leffler 	return res == TNC_RESULT_SUCCESS ? 0 : -1;
32639beb93cSSam Leffler }
32739beb93cSSam Leffler 
32839beb93cSSam Leffler 
tncc_imc_terminate(struct tnc_if_imc * imc)32939beb93cSSam Leffler static int tncc_imc_terminate(struct tnc_if_imc *imc)
33039beb93cSSam Leffler {
33139beb93cSSam Leffler 	TNC_Result res;
33239beb93cSSam Leffler 
33339beb93cSSam Leffler 	if (imc->Terminate == NULL)
33439beb93cSSam Leffler 		return 0;
33539beb93cSSam Leffler 
33639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
33739beb93cSSam Leffler 		   imc->name);
33839beb93cSSam Leffler 	res = imc->Terminate(imc->imcID);
33939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
34039beb93cSSam Leffler 		   (unsigned long) res);
34139beb93cSSam Leffler 
34239beb93cSSam Leffler 	return res == TNC_RESULT_SUCCESS ? 0 : -1;
34339beb93cSSam Leffler }
34439beb93cSSam Leffler 
34539beb93cSSam Leffler 
tncc_imc_provide_bind_function(struct tnc_if_imc * imc)34639beb93cSSam Leffler static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
34739beb93cSSam Leffler {
34839beb93cSSam Leffler 	TNC_Result res;
34939beb93cSSam Leffler 
35039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
35139beb93cSSam Leffler 		   "IMC '%s'", imc->name);
35239beb93cSSam Leffler 	res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
35339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
35439beb93cSSam Leffler 		   (unsigned long) res);
35539beb93cSSam Leffler 
35639beb93cSSam Leffler 	return res == TNC_RESULT_SUCCESS ? 0 : -1;
35739beb93cSSam Leffler }
35839beb93cSSam Leffler 
35939beb93cSSam Leffler 
tncc_imc_notify_connection_change(struct tnc_if_imc * imc,TNC_ConnectionState state)36039beb93cSSam Leffler static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
36139beb93cSSam Leffler 					     TNC_ConnectionState state)
36239beb93cSSam Leffler {
36339beb93cSSam Leffler 	TNC_Result res;
36439beb93cSSam Leffler 
36539beb93cSSam Leffler 	if (imc->NotifyConnectionChange == NULL)
36639beb93cSSam Leffler 		return 0;
36739beb93cSSam Leffler 
36839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
36939beb93cSSam Leffler 		   " for IMC '%s'", (int) state, imc->name);
37039beb93cSSam Leffler 	res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
37139beb93cSSam Leffler 					  state);
37239beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
37339beb93cSSam Leffler 		   (unsigned long) res);
37439beb93cSSam Leffler 
37539beb93cSSam Leffler 	return res == TNC_RESULT_SUCCESS ? 0 : -1;
37639beb93cSSam Leffler }
37739beb93cSSam Leffler 
37839beb93cSSam Leffler 
tncc_imc_begin_handshake(struct tnc_if_imc * imc)37939beb93cSSam Leffler static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
38039beb93cSSam Leffler {
38139beb93cSSam Leffler 	TNC_Result res;
38239beb93cSSam Leffler 
38339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
38439beb93cSSam Leffler 		   "'%s'", imc->name);
38539beb93cSSam Leffler 	res = imc->BeginHandshake(imc->imcID, imc->connectionID);
38639beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
38739beb93cSSam Leffler 		   (unsigned long) res);
38839beb93cSSam Leffler 
38939beb93cSSam Leffler 	return res == TNC_RESULT_SUCCESS ? 0 : -1;
39039beb93cSSam Leffler }
39139beb93cSSam Leffler 
39239beb93cSSam Leffler 
tncc_load_imc(struct tnc_if_imc * imc)39339beb93cSSam Leffler static int tncc_load_imc(struct tnc_if_imc *imc)
39439beb93cSSam Leffler {
39539beb93cSSam Leffler 	if (imc->path == NULL) {
39639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
39739beb93cSSam Leffler 		return -1;
39839beb93cSSam Leffler 	}
39939beb93cSSam Leffler 
40039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
40139beb93cSSam Leffler 		   imc->name, imc->path);
40239beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
40339beb93cSSam Leffler #ifdef UNICODE
40439beb93cSSam Leffler 	{
40539beb93cSSam Leffler 		TCHAR *lib = wpa_strdup_tchar(imc->path);
40639beb93cSSam Leffler 		if (lib == NULL)
40739beb93cSSam Leffler 			return -1;
40839beb93cSSam Leffler 		imc->dlhandle = LoadLibrary(lib);
40939beb93cSSam Leffler 		os_free(lib);
41039beb93cSSam Leffler 	}
41139beb93cSSam Leffler #else /* UNICODE */
41239beb93cSSam Leffler 	imc->dlhandle = LoadLibrary(imc->path);
41339beb93cSSam Leffler #endif /* UNICODE */
41439beb93cSSam Leffler 	if (imc->dlhandle == NULL) {
41539beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
41639beb93cSSam Leffler 			   imc->name, imc->path, (int) GetLastError());
41739beb93cSSam Leffler 		return -1;
41839beb93cSSam Leffler 	}
41939beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
42039beb93cSSam Leffler 	imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
42139beb93cSSam Leffler 	if (imc->dlhandle == NULL) {
42239beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
42339beb93cSSam Leffler 			   imc->name, imc->path, dlerror());
42439beb93cSSam Leffler 		return -1;
42539beb93cSSam Leffler 	}
42639beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
42739beb93cSSam Leffler 
42839beb93cSSam Leffler 	if (tncc_imc_resolve_funcs(imc) < 0) {
42939beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
43039beb93cSSam Leffler 		return -1;
43139beb93cSSam Leffler 	}
43239beb93cSSam Leffler 
43339beb93cSSam Leffler 	if (tncc_imc_initialize(imc) < 0 ||
43439beb93cSSam Leffler 	    tncc_imc_provide_bind_function(imc) < 0) {
43539beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
43639beb93cSSam Leffler 		return -1;
43739beb93cSSam Leffler 	}
43839beb93cSSam Leffler 
43939beb93cSSam Leffler 	return 0;
44039beb93cSSam Leffler }
44139beb93cSSam Leffler 
44239beb93cSSam Leffler 
tncc_unload_imc(struct tnc_if_imc * imc)44339beb93cSSam Leffler static void tncc_unload_imc(struct tnc_if_imc *imc)
44439beb93cSSam Leffler {
44539beb93cSSam Leffler 	tncc_imc_terminate(imc);
44639beb93cSSam Leffler 	tnc_imc[imc->imcID] = NULL;
44739beb93cSSam Leffler 
44839beb93cSSam Leffler 	if (imc->dlhandle) {
44939beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
45039beb93cSSam Leffler 		FreeLibrary(imc->dlhandle);
45139beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
45239beb93cSSam Leffler 		dlclose(imc->dlhandle);
45339beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
45439beb93cSSam Leffler 	}
45539beb93cSSam Leffler 	os_free(imc->name);
45639beb93cSSam Leffler 	os_free(imc->path);
45739beb93cSSam Leffler 	os_free(imc->supported_types);
45839beb93cSSam Leffler 	os_free(imc->imc_send);
45939beb93cSSam Leffler }
46039beb93cSSam Leffler 
46139beb93cSSam Leffler 
tncc_supported_type(struct tnc_if_imc * imc,unsigned int type)46239beb93cSSam Leffler static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
46339beb93cSSam Leffler {
46439beb93cSSam Leffler 	size_t i;
46539beb93cSSam Leffler 	unsigned int vendor, subtype;
46639beb93cSSam Leffler 
46739beb93cSSam Leffler 	if (imc == NULL || imc->supported_types == NULL)
46839beb93cSSam Leffler 		return 0;
46939beb93cSSam Leffler 
47039beb93cSSam Leffler 	vendor = type >> 8;
47139beb93cSSam Leffler 	subtype = type & 0xff;
47239beb93cSSam Leffler 
47339beb93cSSam Leffler 	for (i = 0; i < imc->num_supported_types; i++) {
47439beb93cSSam Leffler 		unsigned int svendor, ssubtype;
47539beb93cSSam Leffler 		svendor = imc->supported_types[i] >> 8;
47639beb93cSSam Leffler 		ssubtype = imc->supported_types[i] & 0xff;
47739beb93cSSam Leffler 		if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
47839beb93cSSam Leffler 		    (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
47939beb93cSSam Leffler 			return 1;
48039beb93cSSam Leffler 	}
48139beb93cSSam Leffler 
48239beb93cSSam Leffler 	return 0;
48339beb93cSSam Leffler }
48439beb93cSSam Leffler 
48539beb93cSSam Leffler 
tncc_send_to_imcs(struct tncc_data * tncc,unsigned int type,const u8 * msg,size_t len)48639beb93cSSam Leffler static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
48739beb93cSSam Leffler 			      const u8 *msg, size_t len)
48839beb93cSSam Leffler {
48939beb93cSSam Leffler 	struct tnc_if_imc *imc;
49039beb93cSSam Leffler 	TNC_Result res;
49139beb93cSSam Leffler 
49239beb93cSSam Leffler 	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
49339beb93cSSam Leffler 
49439beb93cSSam Leffler 	for (imc = tncc->imc; imc; imc = imc->next) {
49539beb93cSSam Leffler 		if (imc->ReceiveMessage == NULL ||
49639beb93cSSam Leffler 		    !tncc_supported_type(imc, type))
49739beb93cSSam Leffler 			continue;
49839beb93cSSam Leffler 
49939beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
50039beb93cSSam Leffler 			   imc->name);
50139beb93cSSam Leffler 		res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
50239beb93cSSam Leffler 					  (TNC_BufferReference) msg, len,
50339beb93cSSam Leffler 					  type);
50439beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
50539beb93cSSam Leffler 			   (unsigned long) res);
50639beb93cSSam Leffler 	}
50739beb93cSSam Leffler }
50839beb93cSSam Leffler 
50939beb93cSSam Leffler 
tncc_init_connection(struct tncc_data * tncc)51039beb93cSSam Leffler void tncc_init_connection(struct tncc_data *tncc)
51139beb93cSSam Leffler {
51239beb93cSSam Leffler 	struct tnc_if_imc *imc;
51339beb93cSSam Leffler 
51439beb93cSSam Leffler 	for (imc = tncc->imc; imc; imc = imc->next) {
51539beb93cSSam Leffler 		tncc_imc_notify_connection_change(
51639beb93cSSam Leffler 			imc, TNC_CONNECTION_STATE_CREATE);
51739beb93cSSam Leffler 		tncc_imc_notify_connection_change(
51839beb93cSSam Leffler 			imc, TNC_CONNECTION_STATE_HANDSHAKE);
51939beb93cSSam Leffler 
52039beb93cSSam Leffler 		os_free(imc->imc_send);
52139beb93cSSam Leffler 		imc->imc_send = NULL;
52239beb93cSSam Leffler 		imc->imc_send_len = 0;
52339beb93cSSam Leffler 
52439beb93cSSam Leffler 		tncc_imc_begin_handshake(imc);
52539beb93cSSam Leffler 	}
52639beb93cSSam Leffler }
52739beb93cSSam Leffler 
52839beb93cSSam Leffler 
tncc_total_send_len(struct tncc_data * tncc)52939beb93cSSam Leffler size_t tncc_total_send_len(struct tncc_data *tncc)
53039beb93cSSam Leffler {
53139beb93cSSam Leffler 	struct tnc_if_imc *imc;
53239beb93cSSam Leffler 
53339beb93cSSam Leffler 	size_t len = 0;
53439beb93cSSam Leffler 	for (imc = tncc->imc; imc; imc = imc->next)
53539beb93cSSam Leffler 		len += imc->imc_send_len;
53639beb93cSSam Leffler 	return len;
53739beb93cSSam Leffler }
53839beb93cSSam Leffler 
53939beb93cSSam Leffler 
tncc_copy_send_buf(struct tncc_data * tncc,u8 * pos)54039beb93cSSam Leffler u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
54139beb93cSSam Leffler {
54239beb93cSSam Leffler 	struct tnc_if_imc *imc;
54339beb93cSSam Leffler 
54439beb93cSSam Leffler 	for (imc = tncc->imc; imc; imc = imc->next) {
54539beb93cSSam Leffler 		if (imc->imc_send == NULL)
54639beb93cSSam Leffler 			continue;
54739beb93cSSam Leffler 
54839beb93cSSam Leffler 		os_memcpy(pos, imc->imc_send, imc->imc_send_len);
54939beb93cSSam Leffler 		pos += imc->imc_send_len;
55039beb93cSSam Leffler 		os_free(imc->imc_send);
55139beb93cSSam Leffler 		imc->imc_send = NULL;
55239beb93cSSam Leffler 		imc->imc_send_len = 0;
55339beb93cSSam Leffler 	}
55439beb93cSSam Leffler 
55539beb93cSSam Leffler 	return pos;
55639beb93cSSam Leffler }
55739beb93cSSam Leffler 
55839beb93cSSam Leffler 
tncc_if_tnccs_start(struct tncc_data * tncc)55939beb93cSSam Leffler char * tncc_if_tnccs_start(struct tncc_data *tncc)
56039beb93cSSam Leffler {
56139beb93cSSam Leffler 	char *buf = os_malloc(1000);
56239beb93cSSam Leffler 	if (buf == NULL)
56339beb93cSSam Leffler 		return NULL;
56439beb93cSSam Leffler 	tncc->last_batchid++;
56539beb93cSSam Leffler 	os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
56639beb93cSSam Leffler 	return buf;
56739beb93cSSam Leffler }
56839beb93cSSam Leffler 
56939beb93cSSam Leffler 
tncc_if_tnccs_end(void)57039beb93cSSam Leffler char * tncc_if_tnccs_end(void)
57139beb93cSSam Leffler {
57239beb93cSSam Leffler 	char *buf = os_malloc(100);
57339beb93cSSam Leffler 	if (buf == NULL)
57439beb93cSSam Leffler 		return NULL;
57539beb93cSSam Leffler 	os_snprintf(buf, 100, IF_TNCCS_END);
57639beb93cSSam Leffler 	return buf;
57739beb93cSSam Leffler }
57839beb93cSSam Leffler 
57939beb93cSSam Leffler 
tncc_notify_recommendation(struct tncc_data * tncc,enum tncc_process_res res)58039beb93cSSam Leffler static void tncc_notify_recommendation(struct tncc_data *tncc,
58139beb93cSSam Leffler 				       enum tncc_process_res res)
58239beb93cSSam Leffler {
58339beb93cSSam Leffler 	TNC_ConnectionState state;
58439beb93cSSam Leffler 	struct tnc_if_imc *imc;
58539beb93cSSam Leffler 
58639beb93cSSam Leffler 	switch (res) {
58739beb93cSSam Leffler 	case TNCCS_RECOMMENDATION_ALLOW:
58839beb93cSSam Leffler 		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
58939beb93cSSam Leffler 		break;
59039beb93cSSam Leffler 	case TNCCS_RECOMMENDATION_NONE:
59139beb93cSSam Leffler 		state = TNC_CONNECTION_STATE_ACCESS_NONE;
59239beb93cSSam Leffler 		break;
59339beb93cSSam Leffler 	case TNCCS_RECOMMENDATION_ISOLATE:
59439beb93cSSam Leffler 		state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
59539beb93cSSam Leffler 		break;
59639beb93cSSam Leffler 	default:
59739beb93cSSam Leffler 		state = TNC_CONNECTION_STATE_ACCESS_NONE;
59839beb93cSSam Leffler 		break;
59939beb93cSSam Leffler 	}
60039beb93cSSam Leffler 
60139beb93cSSam Leffler 	for (imc = tncc->imc; imc; imc = imc->next)
60239beb93cSSam Leffler 		tncc_imc_notify_connection_change(imc, state);
60339beb93cSSam Leffler }
60439beb93cSSam Leffler 
60539beb93cSSam Leffler 
tncc_get_type(char * start,unsigned int * type)60639beb93cSSam Leffler static int tncc_get_type(char *start, unsigned int *type)
60739beb93cSSam Leffler {
60839beb93cSSam Leffler 	char *pos = os_strstr(start, "<Type>");
60939beb93cSSam Leffler 	if (pos == NULL)
61039beb93cSSam Leffler 		return -1;
61139beb93cSSam Leffler 	pos += 6;
61239beb93cSSam Leffler 	*type = strtoul(pos, NULL, 16);
61339beb93cSSam Leffler 	return 0;
61439beb93cSSam Leffler }
61539beb93cSSam Leffler 
61639beb93cSSam Leffler 
tncc_get_base64(char * start,size_t * decoded_len)61739beb93cSSam Leffler static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
61839beb93cSSam Leffler {
61939beb93cSSam Leffler 	char *pos, *pos2;
62039beb93cSSam Leffler 	unsigned char *decoded;
62139beb93cSSam Leffler 
62239beb93cSSam Leffler 	pos = os_strstr(start, "<Base64>");
62339beb93cSSam Leffler 	if (pos == NULL)
62439beb93cSSam Leffler 		return NULL;
62539beb93cSSam Leffler 
62639beb93cSSam Leffler 	pos += 8;
62739beb93cSSam Leffler 	pos2 = os_strstr(pos, "</Base64>");
62839beb93cSSam Leffler 	if (pos2 == NULL)
62939beb93cSSam Leffler 		return NULL;
63039beb93cSSam Leffler 	*pos2 = '\0';
63139beb93cSSam Leffler 
632*c1d255d3SCy Schubert 	decoded = base64_decode(pos, os_strlen(pos), decoded_len);
63339beb93cSSam Leffler 	*pos2 = '<';
63439beb93cSSam Leffler 	if (decoded == NULL) {
63539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
63639beb93cSSam Leffler 	}
63739beb93cSSam Leffler 
63839beb93cSSam Leffler 	return decoded;
63939beb93cSSam Leffler }
64039beb93cSSam Leffler 
64139beb93cSSam Leffler 
tncc_get_recommendation(char * start)64239beb93cSSam Leffler static enum tncc_process_res tncc_get_recommendation(char *start)
64339beb93cSSam Leffler {
64439beb93cSSam Leffler 	char *pos, *pos2, saved;
64539beb93cSSam Leffler 	int recom;
64639beb93cSSam Leffler 
64739beb93cSSam Leffler 	pos = os_strstr(start, "<TNCCS-Recommendation ");
64839beb93cSSam Leffler 	if (pos == NULL)
64939beb93cSSam Leffler 		return TNCCS_RECOMMENDATION_ERROR;
65039beb93cSSam Leffler 
65139beb93cSSam Leffler 	pos += 21;
65239beb93cSSam Leffler 	pos = os_strstr(pos, " type=");
65339beb93cSSam Leffler 	if (pos == NULL)
65439beb93cSSam Leffler 		return TNCCS_RECOMMENDATION_ERROR;
65539beb93cSSam Leffler 	pos += 6;
65639beb93cSSam Leffler 
65739beb93cSSam Leffler 	if (*pos == '"')
65839beb93cSSam Leffler 		pos++;
65939beb93cSSam Leffler 
66039beb93cSSam Leffler 	pos2 = pos;
66139beb93cSSam Leffler 	while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
66239beb93cSSam Leffler 		pos2++;
66339beb93cSSam Leffler 
66439beb93cSSam Leffler 	if (*pos2 == '\0')
66539beb93cSSam Leffler 		return TNCCS_RECOMMENDATION_ERROR;
66639beb93cSSam Leffler 
66739beb93cSSam Leffler 	saved = *pos2;
66839beb93cSSam Leffler 	*pos2 = '\0';
66939beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
67039beb93cSSam Leffler 
67139beb93cSSam Leffler 	recom = TNCCS_RECOMMENDATION_ERROR;
67239beb93cSSam Leffler 	if (os_strcmp(pos, "allow") == 0)
67339beb93cSSam Leffler 		recom = TNCCS_RECOMMENDATION_ALLOW;
67439beb93cSSam Leffler 	else if (os_strcmp(pos, "none") == 0)
67539beb93cSSam Leffler 		recom = TNCCS_RECOMMENDATION_NONE;
67639beb93cSSam Leffler 	else if (os_strcmp(pos, "isolate") == 0)
67739beb93cSSam Leffler 		recom = TNCCS_RECOMMENDATION_ISOLATE;
67839beb93cSSam Leffler 
67939beb93cSSam Leffler 	*pos2 = saved;
68039beb93cSSam Leffler 
68139beb93cSSam Leffler 	return recom;
68239beb93cSSam Leffler }
68339beb93cSSam Leffler 
68439beb93cSSam Leffler 
tncc_process_if_tnccs(struct tncc_data * tncc,const u8 * msg,size_t len)68539beb93cSSam Leffler enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
68639beb93cSSam Leffler 					    const u8 *msg, size_t len)
68739beb93cSSam Leffler {
68839beb93cSSam Leffler 	char *buf, *start, *end, *pos, *pos2, *payload;
68939beb93cSSam Leffler 	unsigned int batch_id;
69039beb93cSSam Leffler 	unsigned char *decoded;
69139beb93cSSam Leffler 	size_t decoded_len;
69239beb93cSSam Leffler 	enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
69339beb93cSSam Leffler 	int recommendation_msg = 0;
69439beb93cSSam Leffler 
695780fb4a2SCy Schubert 	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Received IF-TNCCS message",
696780fb4a2SCy Schubert 			  msg, len);
6975b9c547cSRui Paulo 	buf = dup_binstr(msg, len);
69839beb93cSSam Leffler 	if (buf == NULL)
69939beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
70039beb93cSSam Leffler 
70139beb93cSSam Leffler 	start = os_strstr(buf, "<TNCCS-Batch ");
70239beb93cSSam Leffler 	end = os_strstr(buf, "</TNCCS-Batch>");
70339beb93cSSam Leffler 	if (start == NULL || end == NULL || start > end) {
70439beb93cSSam Leffler 		os_free(buf);
70539beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
70639beb93cSSam Leffler 	}
70739beb93cSSam Leffler 
70839beb93cSSam Leffler 	start += 13;
70939beb93cSSam Leffler 	while (*start == ' ')
71039beb93cSSam Leffler 		start++;
71139beb93cSSam Leffler 	*end = '\0';
71239beb93cSSam Leffler 
71339beb93cSSam Leffler 	pos = os_strstr(start, "BatchId=");
71439beb93cSSam Leffler 	if (pos == NULL) {
71539beb93cSSam Leffler 		os_free(buf);
71639beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
71739beb93cSSam Leffler 	}
71839beb93cSSam Leffler 
71939beb93cSSam Leffler 	pos += 8;
72039beb93cSSam Leffler 	if (*pos == '"')
72139beb93cSSam Leffler 		pos++;
72239beb93cSSam Leffler 	batch_id = atoi(pos);
72339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
72439beb93cSSam Leffler 		   batch_id);
72539beb93cSSam Leffler 	if (batch_id != tncc->last_batchid + 1) {
72639beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
72739beb93cSSam Leffler 			   "%u (expected %u)",
72839beb93cSSam Leffler 			   batch_id, tncc->last_batchid + 1);
72939beb93cSSam Leffler 		os_free(buf);
73039beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
73139beb93cSSam Leffler 	}
73239beb93cSSam Leffler 	tncc->last_batchid = batch_id;
73339beb93cSSam Leffler 
73439beb93cSSam Leffler 	while (*pos != '\0' && *pos != '>')
73539beb93cSSam Leffler 		pos++;
73639beb93cSSam Leffler 	if (*pos == '\0') {
73739beb93cSSam Leffler 		os_free(buf);
73839beb93cSSam Leffler 		return TNCCS_PROCESS_ERROR;
73939beb93cSSam Leffler 	}
74039beb93cSSam Leffler 	pos++;
74139beb93cSSam Leffler 	payload = start;
74239beb93cSSam Leffler 
74339beb93cSSam Leffler 	/*
74439beb93cSSam Leffler 	 * <IMC-IMV-Message>
74539beb93cSSam Leffler 	 * <Type>01234567</Type>
74639beb93cSSam Leffler 	 * <Base64>foo==</Base64>
74739beb93cSSam Leffler 	 * </IMC-IMV-Message>
74839beb93cSSam Leffler 	 */
74939beb93cSSam Leffler 
75039beb93cSSam Leffler 	while (*start) {
75139beb93cSSam Leffler 		char *endpos;
75239beb93cSSam Leffler 		unsigned int type;
75339beb93cSSam Leffler 
75439beb93cSSam Leffler 		pos = os_strstr(start, "<IMC-IMV-Message>");
75539beb93cSSam Leffler 		if (pos == NULL)
75639beb93cSSam Leffler 			break;
75739beb93cSSam Leffler 		start = pos + 17;
75839beb93cSSam Leffler 		end = os_strstr(start, "</IMC-IMV-Message>");
75939beb93cSSam Leffler 		if (end == NULL)
76039beb93cSSam Leffler 			break;
76139beb93cSSam Leffler 		*end = '\0';
76239beb93cSSam Leffler 		endpos = end;
76339beb93cSSam Leffler 		end += 18;
76439beb93cSSam Leffler 
76539beb93cSSam Leffler 		if (tncc_get_type(start, &type) < 0) {
76639beb93cSSam Leffler 			*endpos = '<';
76739beb93cSSam Leffler 			start = end;
76839beb93cSSam Leffler 			continue;
76939beb93cSSam Leffler 		}
77039beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
77139beb93cSSam Leffler 
77239beb93cSSam Leffler 		decoded = tncc_get_base64(start, &decoded_len);
77339beb93cSSam Leffler 		if (decoded == NULL) {
77439beb93cSSam Leffler 			*endpos = '<';
77539beb93cSSam Leffler 			start = end;
77639beb93cSSam Leffler 			continue;
77739beb93cSSam Leffler 		}
77839beb93cSSam Leffler 
77939beb93cSSam Leffler 		tncc_send_to_imcs(tncc, type, decoded, decoded_len);
78039beb93cSSam Leffler 
78139beb93cSSam Leffler 		os_free(decoded);
78239beb93cSSam Leffler 
78339beb93cSSam Leffler 		start = end;
78439beb93cSSam Leffler 	}
78539beb93cSSam Leffler 
78639beb93cSSam Leffler 	/*
78739beb93cSSam Leffler 	 * <TNCC-TNCS-Message>
78839beb93cSSam Leffler 	 * <Type>01234567</Type>
78939beb93cSSam Leffler 	 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
79039beb93cSSam Leffler 	 * <Base64>foo==</Base64>
79139beb93cSSam Leffler 	 * </TNCC-TNCS-Message>
79239beb93cSSam Leffler 	 */
79339beb93cSSam Leffler 
79439beb93cSSam Leffler 	start = payload;
79539beb93cSSam Leffler 	while (*start) {
79639beb93cSSam Leffler 		unsigned int type;
79739beb93cSSam Leffler 		char *xml, *xmlend, *endpos;
79839beb93cSSam Leffler 
79939beb93cSSam Leffler 		pos = os_strstr(start, "<TNCC-TNCS-Message>");
80039beb93cSSam Leffler 		if (pos == NULL)
80139beb93cSSam Leffler 			break;
80239beb93cSSam Leffler 		start = pos + 19;
80339beb93cSSam Leffler 		end = os_strstr(start, "</TNCC-TNCS-Message>");
80439beb93cSSam Leffler 		if (end == NULL)
80539beb93cSSam Leffler 			break;
80639beb93cSSam Leffler 		*end = '\0';
80739beb93cSSam Leffler 		endpos = end;
80839beb93cSSam Leffler 		end += 20;
80939beb93cSSam Leffler 
81039beb93cSSam Leffler 		if (tncc_get_type(start, &type) < 0) {
81139beb93cSSam Leffler 			*endpos = '<';
81239beb93cSSam Leffler 			start = end;
81339beb93cSSam Leffler 			continue;
81439beb93cSSam Leffler 		}
81539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
81639beb93cSSam Leffler 			   type);
81739beb93cSSam Leffler 
81839beb93cSSam Leffler 		/* Base64 OR XML */
81939beb93cSSam Leffler 		decoded = NULL;
82039beb93cSSam Leffler 		xml = NULL;
82139beb93cSSam Leffler 		xmlend = NULL;
82239beb93cSSam Leffler 		pos = os_strstr(start, "<XML>");
82339beb93cSSam Leffler 		if (pos) {
82439beb93cSSam Leffler 			pos += 5;
82539beb93cSSam Leffler 			pos2 = os_strstr(pos, "</XML>");
82639beb93cSSam Leffler 			if (pos2 == NULL) {
82739beb93cSSam Leffler 				*endpos = '<';
82839beb93cSSam Leffler 				start = end;
82939beb93cSSam Leffler 				continue;
83039beb93cSSam Leffler 			}
83139beb93cSSam Leffler 			xmlend = pos2;
83239beb93cSSam Leffler 			xml = pos;
83339beb93cSSam Leffler 		} else {
83439beb93cSSam Leffler 			decoded = tncc_get_base64(start, &decoded_len);
83539beb93cSSam Leffler 			if (decoded == NULL) {
83639beb93cSSam Leffler 				*endpos = '<';
83739beb93cSSam Leffler 				start = end;
83839beb93cSSam Leffler 				continue;
83939beb93cSSam Leffler 			}
84039beb93cSSam Leffler 		}
84139beb93cSSam Leffler 
84239beb93cSSam Leffler 		if (decoded) {
84339beb93cSSam Leffler 			wpa_hexdump_ascii(MSG_MSGDUMP,
84439beb93cSSam Leffler 					  "TNC: TNCC-TNCS-Message Base64",
84539beb93cSSam Leffler 					  decoded, decoded_len);
84639beb93cSSam Leffler 			os_free(decoded);
84739beb93cSSam Leffler 		}
84839beb93cSSam Leffler 
84939beb93cSSam Leffler 		if (xml) {
85039beb93cSSam Leffler 			wpa_hexdump_ascii(MSG_MSGDUMP,
85139beb93cSSam Leffler 					  "TNC: TNCC-TNCS-Message XML",
85239beb93cSSam Leffler 					  (unsigned char *) xml,
85339beb93cSSam Leffler 					  xmlend - xml);
85439beb93cSSam Leffler 		}
85539beb93cSSam Leffler 
85639beb93cSSam Leffler 		if (type == TNC_TNCCS_RECOMMENDATION && xml) {
85739beb93cSSam Leffler 			/*
85839beb93cSSam Leffler 			 * <TNCCS-Recommendation type="allow">
85939beb93cSSam Leffler 			 * </TNCCS-Recommendation>
86039beb93cSSam Leffler 			 */
86139beb93cSSam Leffler 			*xmlend = '\0';
86239beb93cSSam Leffler 			res = tncc_get_recommendation(xml);
86339beb93cSSam Leffler 			*xmlend = '<';
86439beb93cSSam Leffler 			recommendation_msg = 1;
86539beb93cSSam Leffler 		}
86639beb93cSSam Leffler 
86739beb93cSSam Leffler 		start = end;
86839beb93cSSam Leffler 	}
86939beb93cSSam Leffler 
87039beb93cSSam Leffler 	os_free(buf);
87139beb93cSSam Leffler 
87239beb93cSSam Leffler 	if (recommendation_msg)
87339beb93cSSam Leffler 		tncc_notify_recommendation(tncc, res);
87439beb93cSSam Leffler 
87539beb93cSSam Leffler 	return res;
87639beb93cSSam Leffler }
87739beb93cSSam Leffler 
87839beb93cSSam Leffler 
87939beb93cSSam Leffler #ifdef CONFIG_NATIVE_WINDOWS
tncc_read_config_reg(struct tncc_data * tncc,HKEY hive)88039beb93cSSam Leffler static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
88139beb93cSSam Leffler {
88239beb93cSSam Leffler 	HKEY hk, hk2;
88339beb93cSSam Leffler 	LONG ret;
88439beb93cSSam Leffler 	DWORD i;
88539beb93cSSam Leffler 	struct tnc_if_imc *imc, *last;
88639beb93cSSam Leffler 	int j;
88739beb93cSSam Leffler 
88839beb93cSSam Leffler 	last = tncc->imc;
88939beb93cSSam Leffler 	while (last && last->next)
89039beb93cSSam Leffler 		last = last->next;
89139beb93cSSam Leffler 
89239beb93cSSam Leffler 	ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
89339beb93cSSam Leffler 			   &hk);
89439beb93cSSam Leffler 	if (ret != ERROR_SUCCESS)
89539beb93cSSam Leffler 		return 0;
89639beb93cSSam Leffler 
89739beb93cSSam Leffler 	for (i = 0; ; i++) {
89839beb93cSSam Leffler 		TCHAR name[255], *val;
89939beb93cSSam Leffler 		DWORD namelen, buflen;
90039beb93cSSam Leffler 
90139beb93cSSam Leffler 		namelen = 255;
90239beb93cSSam Leffler 		ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
90339beb93cSSam Leffler 				   NULL);
90439beb93cSSam Leffler 
90539beb93cSSam Leffler 		if (ret == ERROR_NO_MORE_ITEMS)
90639beb93cSSam Leffler 			break;
90739beb93cSSam Leffler 
90839beb93cSSam Leffler 		if (ret != ERROR_SUCCESS) {
90939beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
91039beb93cSSam Leffler 				   (unsigned int) ret);
91139beb93cSSam Leffler 			break;
91239beb93cSSam Leffler 		}
91339beb93cSSam Leffler 
91439beb93cSSam Leffler 		if (namelen >= 255)
91539beb93cSSam Leffler 			namelen = 255 - 1;
91639beb93cSSam Leffler 		name[namelen] = '\0';
91739beb93cSSam Leffler 
91839beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
91939beb93cSSam Leffler 
92039beb93cSSam Leffler 		ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
92139beb93cSSam Leffler 		if (ret != ERROR_SUCCESS) {
92239beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
92339beb93cSSam Leffler 				   "'", name);
92439beb93cSSam Leffler 			continue;
92539beb93cSSam Leffler 		}
92639beb93cSSam Leffler 
92739beb93cSSam Leffler 		ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
92839beb93cSSam Leffler 				      &buflen);
92939beb93cSSam Leffler 		if (ret != ERROR_SUCCESS) {
93039beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
93139beb93cSSam Leffler 				   "IMC key '" TSTR "'", name);
93239beb93cSSam Leffler 			RegCloseKey(hk2);
93339beb93cSSam Leffler 			continue;
93439beb93cSSam Leffler 		}
93539beb93cSSam Leffler 
93639beb93cSSam Leffler 		val = os_malloc(buflen);
93739beb93cSSam Leffler 		if (val == NULL) {
93839beb93cSSam Leffler 			RegCloseKey(hk2);
93939beb93cSSam Leffler 			continue;
94039beb93cSSam Leffler 		}
94139beb93cSSam Leffler 
94239beb93cSSam Leffler 		ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
94339beb93cSSam Leffler 				      (LPBYTE) val, &buflen);
94439beb93cSSam Leffler 		if (ret != ERROR_SUCCESS) {
94539beb93cSSam Leffler 			os_free(val);
94639beb93cSSam Leffler 			RegCloseKey(hk2);
94739beb93cSSam Leffler 			continue;
94839beb93cSSam Leffler 		}
94939beb93cSSam Leffler 
95039beb93cSSam Leffler 		RegCloseKey(hk2);
95139beb93cSSam Leffler 
95239beb93cSSam Leffler 		wpa_unicode2ascii_inplace(val);
95339beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
95439beb93cSSam Leffler 
95539beb93cSSam Leffler 		for (j = 0; j < TNC_MAX_IMC_ID; j++) {
95639beb93cSSam Leffler 			if (tnc_imc[j] == NULL)
95739beb93cSSam Leffler 				break;
95839beb93cSSam Leffler 		}
95939beb93cSSam Leffler 		if (j >= TNC_MAX_IMC_ID) {
96039beb93cSSam Leffler 			wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
96139beb93cSSam Leffler 			os_free(val);
96239beb93cSSam Leffler 			continue;
96339beb93cSSam Leffler 		}
96439beb93cSSam Leffler 
96539beb93cSSam Leffler 		imc = os_zalloc(sizeof(*imc));
96639beb93cSSam Leffler 		if (imc == NULL) {
96739beb93cSSam Leffler 			os_free(val);
96839beb93cSSam Leffler 			break;
96939beb93cSSam Leffler 		}
97039beb93cSSam Leffler 
97139beb93cSSam Leffler 		imc->imcID = j;
97239beb93cSSam Leffler 
97339beb93cSSam Leffler 		wpa_unicode2ascii_inplace(name);
97439beb93cSSam Leffler 		imc->name = os_strdup((char *) name);
97539beb93cSSam Leffler 		imc->path = os_strdup((char *) val);
97639beb93cSSam Leffler 
97739beb93cSSam Leffler 		os_free(val);
97839beb93cSSam Leffler 
97939beb93cSSam Leffler 		if (last == NULL)
98039beb93cSSam Leffler 			tncc->imc = imc;
98139beb93cSSam Leffler 		else
98239beb93cSSam Leffler 			last->next = imc;
98339beb93cSSam Leffler 		last = imc;
98439beb93cSSam Leffler 
98539beb93cSSam Leffler 		tnc_imc[imc->imcID] = imc;
98639beb93cSSam Leffler 	}
98739beb93cSSam Leffler 
98839beb93cSSam Leffler 	RegCloseKey(hk);
98939beb93cSSam Leffler 
99039beb93cSSam Leffler 	return 0;
99139beb93cSSam Leffler }
99239beb93cSSam Leffler 
99339beb93cSSam Leffler 
tncc_read_config(struct tncc_data * tncc)99439beb93cSSam Leffler static int tncc_read_config(struct tncc_data *tncc)
99539beb93cSSam Leffler {
99639beb93cSSam Leffler 	if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
99739beb93cSSam Leffler 	    tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
99839beb93cSSam Leffler 		return -1;
99939beb93cSSam Leffler 	return 0;
100039beb93cSSam Leffler }
100139beb93cSSam Leffler 
100239beb93cSSam Leffler #else /* CONFIG_NATIVE_WINDOWS */
100339beb93cSSam Leffler 
tncc_parse_imc(char * start,char * end,int * error)100439beb93cSSam Leffler static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
100539beb93cSSam Leffler {
100639beb93cSSam Leffler 	struct tnc_if_imc *imc;
100739beb93cSSam Leffler 	char *pos, *pos2;
100839beb93cSSam Leffler 	int i;
100939beb93cSSam Leffler 
101039beb93cSSam Leffler 	for (i = 0; i < TNC_MAX_IMC_ID; i++) {
101139beb93cSSam Leffler 		if (tnc_imc[i] == NULL)
101239beb93cSSam Leffler 			break;
101339beb93cSSam Leffler 	}
101439beb93cSSam Leffler 	if (i >= TNC_MAX_IMC_ID) {
101539beb93cSSam Leffler 		wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
101639beb93cSSam Leffler 		return NULL;
101739beb93cSSam Leffler 	}
101839beb93cSSam Leffler 
101939beb93cSSam Leffler 	imc = os_zalloc(sizeof(*imc));
102039beb93cSSam Leffler 	if (imc == NULL) {
102139beb93cSSam Leffler 		*error = 1;
102239beb93cSSam Leffler 		return NULL;
102339beb93cSSam Leffler 	}
102439beb93cSSam Leffler 
102539beb93cSSam Leffler 	imc->imcID = i;
102639beb93cSSam Leffler 
102739beb93cSSam Leffler 	pos = start;
102839beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
102939beb93cSSam Leffler 	if (pos + 1 >= end || *pos != '"') {
103039beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
103139beb93cSSam Leffler 			   "(no starting quotation mark)", start);
103239beb93cSSam Leffler 		os_free(imc);
103339beb93cSSam Leffler 		return NULL;
103439beb93cSSam Leffler 	}
103539beb93cSSam Leffler 
103639beb93cSSam Leffler 	pos++;
103739beb93cSSam Leffler 	pos2 = pos;
103839beb93cSSam Leffler 	while (pos2 < end && *pos2 != '"')
103939beb93cSSam Leffler 		pos2++;
104039beb93cSSam Leffler 	if (pos2 >= end) {
104139beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
104239beb93cSSam Leffler 			   "(no ending quotation mark)", start);
104339beb93cSSam Leffler 		os_free(imc);
104439beb93cSSam Leffler 		return NULL;
104539beb93cSSam Leffler 	}
104639beb93cSSam Leffler 	*pos2 = '\0';
104739beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
104839beb93cSSam Leffler 	imc->name = os_strdup(pos);
104939beb93cSSam Leffler 
105039beb93cSSam Leffler 	pos = pos2 + 1;
105139beb93cSSam Leffler 	if (pos >= end || *pos != ' ') {
105239beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
105339beb93cSSam Leffler 			   "(no space after name)", start);
10543157ba21SRui Paulo 		os_free(imc->name);
105539beb93cSSam Leffler 		os_free(imc);
105639beb93cSSam Leffler 		return NULL;
105739beb93cSSam Leffler 	}
105839beb93cSSam Leffler 
105939beb93cSSam Leffler 	pos++;
106039beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
106139beb93cSSam Leffler 	imc->path = os_strdup(pos);
106239beb93cSSam Leffler 	tnc_imc[imc->imcID] = imc;
106339beb93cSSam Leffler 
106439beb93cSSam Leffler 	return imc;
106539beb93cSSam Leffler }
106639beb93cSSam Leffler 
106739beb93cSSam Leffler 
tncc_read_config(struct tncc_data * tncc)106839beb93cSSam Leffler static int tncc_read_config(struct tncc_data *tncc)
106939beb93cSSam Leffler {
107039beb93cSSam Leffler 	char *config, *end, *pos, *line_end;
107139beb93cSSam Leffler 	size_t config_len;
107239beb93cSSam Leffler 	struct tnc_if_imc *imc, *last;
107339beb93cSSam Leffler 
107439beb93cSSam Leffler 	last = NULL;
107539beb93cSSam Leffler 
107639beb93cSSam Leffler 	config = os_readfile(TNC_CONFIG_FILE, &config_len);
107739beb93cSSam Leffler 	if (config == NULL) {
107839beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
107939beb93cSSam Leffler 			   "file '%s'", TNC_CONFIG_FILE);
108039beb93cSSam Leffler 		return -1;
108139beb93cSSam Leffler 	}
108239beb93cSSam Leffler 
108339beb93cSSam Leffler 	end = config + config_len;
108439beb93cSSam Leffler 	for (pos = config; pos < end; pos = line_end + 1) {
108539beb93cSSam Leffler 		line_end = pos;
108639beb93cSSam Leffler 		while (*line_end != '\n' && *line_end != '\r' &&
108739beb93cSSam Leffler 		       line_end < end)
108839beb93cSSam Leffler 			line_end++;
108939beb93cSSam Leffler 		*line_end = '\0';
109039beb93cSSam Leffler 
109139beb93cSSam Leffler 		if (os_strncmp(pos, "IMC ", 4) == 0) {
109239beb93cSSam Leffler 			int error = 0;
109339beb93cSSam Leffler 
109439beb93cSSam Leffler 			imc = tncc_parse_imc(pos + 4, line_end, &error);
10955b9c547cSRui Paulo 			if (error) {
10965b9c547cSRui Paulo 				os_free(config);
109739beb93cSSam Leffler 				return -1;
10985b9c547cSRui Paulo 			}
109939beb93cSSam Leffler 			if (imc) {
110039beb93cSSam Leffler 				if (last == NULL)
110139beb93cSSam Leffler 					tncc->imc = imc;
110239beb93cSSam Leffler 				else
110339beb93cSSam Leffler 					last->next = imc;
110439beb93cSSam Leffler 				last = imc;
110539beb93cSSam Leffler 			}
110639beb93cSSam Leffler 		}
110739beb93cSSam Leffler 	}
110839beb93cSSam Leffler 
110939beb93cSSam Leffler 	os_free(config);
111039beb93cSSam Leffler 
111139beb93cSSam Leffler 	return 0;
111239beb93cSSam Leffler }
111339beb93cSSam Leffler 
111439beb93cSSam Leffler #endif /* CONFIG_NATIVE_WINDOWS */
111539beb93cSSam Leffler 
111639beb93cSSam Leffler 
tncc_init(void)111739beb93cSSam Leffler struct tncc_data * tncc_init(void)
111839beb93cSSam Leffler {
111939beb93cSSam Leffler 	struct tncc_data *tncc;
112039beb93cSSam Leffler 	struct tnc_if_imc *imc;
112139beb93cSSam Leffler 
112239beb93cSSam Leffler 	tncc = os_zalloc(sizeof(*tncc));
112339beb93cSSam Leffler 	if (tncc == NULL)
112439beb93cSSam Leffler 		return NULL;
112539beb93cSSam Leffler 
112639beb93cSSam Leffler 	/* TODO:
112739beb93cSSam Leffler 	 * move loading and Initialize() to a location that is not
112839beb93cSSam Leffler 	 *    re-initialized for every EAP-TNC session (?)
112939beb93cSSam Leffler 	 */
113039beb93cSSam Leffler 
113139beb93cSSam Leffler 	if (tncc_read_config(tncc) < 0) {
113239beb93cSSam Leffler 		wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
113339beb93cSSam Leffler 		goto failed;
113439beb93cSSam Leffler 	}
113539beb93cSSam Leffler 
113639beb93cSSam Leffler 	for (imc = tncc->imc; imc; imc = imc->next) {
113739beb93cSSam Leffler 		if (tncc_load_imc(imc)) {
113839beb93cSSam Leffler 			wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
113939beb93cSSam Leffler 				   imc->name);
114039beb93cSSam Leffler 			goto failed;
114139beb93cSSam Leffler 		}
114239beb93cSSam Leffler 	}
114339beb93cSSam Leffler 
114439beb93cSSam Leffler 	return tncc;
114539beb93cSSam Leffler 
114639beb93cSSam Leffler failed:
114739beb93cSSam Leffler 	tncc_deinit(tncc);
114839beb93cSSam Leffler 	return NULL;
114939beb93cSSam Leffler }
115039beb93cSSam Leffler 
115139beb93cSSam Leffler 
tncc_deinit(struct tncc_data * tncc)115239beb93cSSam Leffler void tncc_deinit(struct tncc_data *tncc)
115339beb93cSSam Leffler {
115439beb93cSSam Leffler 	struct tnc_if_imc *imc, *prev;
115539beb93cSSam Leffler 
115639beb93cSSam Leffler 	imc = tncc->imc;
115739beb93cSSam Leffler 	while (imc) {
115839beb93cSSam Leffler 		tncc_unload_imc(imc);
115939beb93cSSam Leffler 
116039beb93cSSam Leffler 		prev = imc;
116139beb93cSSam Leffler 		imc = imc->next;
116239beb93cSSam Leffler 		os_free(prev);
116339beb93cSSam Leffler 	}
116439beb93cSSam Leffler 
116539beb93cSSam Leffler 	os_free(tncc);
116639beb93cSSam Leffler }
116739beb93cSSam Leffler 
116839beb93cSSam Leffler 
tncc_build_soh(int ver)116939beb93cSSam Leffler static struct wpabuf * tncc_build_soh(int ver)
117039beb93cSSam Leffler {
117139beb93cSSam Leffler 	struct wpabuf *buf;
117239beb93cSSam Leffler 	u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
117339beb93cSSam Leffler 	u8 correlation_id[24];
117439beb93cSSam Leffler 	/* TODO: get correct name */
117539beb93cSSam Leffler 	char *machinename = "wpa_supplicant@w1.fi";
117639beb93cSSam Leffler 
117739beb93cSSam Leffler 	if (os_get_random(correlation_id, sizeof(correlation_id)))
117839beb93cSSam Leffler 		return NULL;
117939beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
118039beb93cSSam Leffler 		    correlation_id, sizeof(correlation_id));
118139beb93cSSam Leffler 
118239beb93cSSam Leffler 	buf = wpabuf_alloc(200);
118339beb93cSSam Leffler 	if (buf == NULL)
118439beb93cSSam Leffler 		return NULL;
118539beb93cSSam Leffler 
118639beb93cSSam Leffler 	/* Vendor-Specific TLV (Microsoft) - SoH */
118739beb93cSSam Leffler 	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
118839beb93cSSam Leffler 	tlv_len = wpabuf_put(buf, 2); /* Length */
118939beb93cSSam Leffler 	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
119039beb93cSSam Leffler 	wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
119139beb93cSSam Leffler 	tlv_len2 = wpabuf_put(buf, 2); /* Length */
119239beb93cSSam Leffler 
119339beb93cSSam Leffler 	/* SoH Header */
119439beb93cSSam Leffler 	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
119539beb93cSSam Leffler 	outer_len = wpabuf_put(buf, 2);
119639beb93cSSam Leffler 	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
119739beb93cSSam Leffler 	wpabuf_put_be16(buf, ver); /* Inner Type */
119839beb93cSSam Leffler 	inner_len = wpabuf_put(buf, 2);
119939beb93cSSam Leffler 
120039beb93cSSam Leffler 	if (ver == 2) {
120139beb93cSSam Leffler 		/* SoH Mode Sub-Header */
120239beb93cSSam Leffler 		/* Outer Type */
120339beb93cSSam Leffler 		wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
120439beb93cSSam Leffler 		wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
120539beb93cSSam Leffler 		wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
120639beb93cSSam Leffler 		/* Value: */
120739beb93cSSam Leffler 		wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
120839beb93cSSam Leffler 		wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
120939beb93cSSam Leffler 		wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
121039beb93cSSam Leffler 	}
121139beb93cSSam Leffler 
121239beb93cSSam Leffler 	/* SSoH TLV */
121339beb93cSSam Leffler 	/* System-Health-Id */
121439beb93cSSam Leffler 	wpabuf_put_be16(buf, 0x0002); /* Type */
121539beb93cSSam Leffler 	wpabuf_put_be16(buf, 4); /* Length */
121639beb93cSSam Leffler 	wpabuf_put_be32(buf, 79616);
121739beb93cSSam Leffler 	/* Vendor-Specific Attribute */
121839beb93cSSam Leffler 	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
121939beb93cSSam Leffler 	ssoh_len = wpabuf_put(buf, 2);
122039beb93cSSam Leffler 	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
122139beb93cSSam Leffler 
122239beb93cSSam Leffler 	/* MS-Packet-Info */
122339beb93cSSam Leffler 	wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO);
122439beb93cSSam Leffler 	/* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be:
122539beb93cSSam Leffler 	 * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP
122639beb93cSSam Leffler 	 * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit
122739beb93cSSam Leffler 	 * would not be in the specified location.
122839beb93cSSam Leffler 	 * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits)
122939beb93cSSam Leffler 	 */
123039beb93cSSam Leffler 	wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
123139beb93cSSam Leffler 
123239beb93cSSam Leffler 	/* MS-Machine-Inventory */
123339beb93cSSam Leffler 	/* TODO: get correct values; 0 = not applicable for OS */
123439beb93cSSam Leffler 	wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY);
123539beb93cSSam Leffler 	wpabuf_put_be32(buf, 0); /* osVersionMajor */
123639beb93cSSam Leffler 	wpabuf_put_be32(buf, 0); /* osVersionMinor */
123739beb93cSSam Leffler 	wpabuf_put_be32(buf, 0); /* osVersionBuild */
123839beb93cSSam Leffler 	wpabuf_put_be16(buf, 0); /* spVersionMajor */
123939beb93cSSam Leffler 	wpabuf_put_be16(buf, 0); /* spVersionMinor */
124039beb93cSSam Leffler 	wpabuf_put_be16(buf, 0); /* procArch */
124139beb93cSSam Leffler 
124239beb93cSSam Leffler 	/* MS-MachineName */
124339beb93cSSam Leffler 	wpabuf_put_u8(buf, SSOH_MS_MACHINENAME);
124439beb93cSSam Leffler 	wpabuf_put_be16(buf, os_strlen(machinename) + 1);
124539beb93cSSam Leffler 	wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1);
124639beb93cSSam Leffler 
124739beb93cSSam Leffler 	/* MS-CorrelationId */
124839beb93cSSam Leffler 	wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID);
124939beb93cSSam Leffler 	wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
125039beb93cSSam Leffler 
125139beb93cSSam Leffler 	/* MS-Quarantine-State */
125239beb93cSSam Leffler 	wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE);
125339beb93cSSam Leffler 	wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */
125439beb93cSSam Leffler 	wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */
125539beb93cSSam Leffler 	wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */
125639beb93cSSam Leffler 	wpabuf_put_be16(buf, 1); /* urlLenInBytes */
125739beb93cSSam Leffler 	wpabuf_put_u8(buf, 0); /* null termination for the url */
125839beb93cSSam Leffler 
125939beb93cSSam Leffler 	/* MS-Machine-Inventory-Ex */
126039beb93cSSam Leffler 	wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX);
126139beb93cSSam Leffler 	wpabuf_put_be32(buf, 0); /* Reserved
126239beb93cSSam Leffler 				  * (note: Windows XP SP3 uses 0xdecafbad) */
126339beb93cSSam Leffler 	wpabuf_put_u8(buf, 1); /* ProductType: Client */
126439beb93cSSam Leffler 
126539beb93cSSam Leffler 	/* Update SSoH Length */
126639beb93cSSam Leffler 	end = wpabuf_put(buf, 0);
126739beb93cSSam Leffler 	WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
126839beb93cSSam Leffler 
126939beb93cSSam Leffler 	/* TODO: SoHReportEntry TLV (zero or more) */
127039beb93cSSam Leffler 
127139beb93cSSam Leffler 	/* Update length fields */
127239beb93cSSam Leffler 	end = wpabuf_put(buf, 0);
127339beb93cSSam Leffler 	WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
127439beb93cSSam Leffler 	WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
127539beb93cSSam Leffler 	WPA_PUT_BE16(outer_len, end - outer_len - 2);
127639beb93cSSam Leffler 	WPA_PUT_BE16(inner_len, end - inner_len - 2);
127739beb93cSSam Leffler 
127839beb93cSSam Leffler 	return buf;
127939beb93cSSam Leffler }
128039beb93cSSam Leffler 
128139beb93cSSam Leffler 
tncc_process_soh_request(int ver,const u8 * data,size_t len)128239beb93cSSam Leffler struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len)
128339beb93cSSam Leffler {
128439beb93cSSam Leffler 	const u8 *pos;
128539beb93cSSam Leffler 
128639beb93cSSam Leffler 	wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
128739beb93cSSam Leffler 
128839beb93cSSam Leffler 	if (len < 12)
128939beb93cSSam Leffler 		return NULL;
129039beb93cSSam Leffler 
129139beb93cSSam Leffler 	/* SoH Request */
129239beb93cSSam Leffler 	pos = data;
129339beb93cSSam Leffler 
129439beb93cSSam Leffler 	/* TLV Type */
129539beb93cSSam Leffler 	if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
129639beb93cSSam Leffler 		return NULL;
129739beb93cSSam Leffler 	pos += 2;
129839beb93cSSam Leffler 
129939beb93cSSam Leffler 	/* Length */
130039beb93cSSam Leffler 	if (WPA_GET_BE16(pos) < 8)
130139beb93cSSam Leffler 		return NULL;
130239beb93cSSam Leffler 	pos += 2;
130339beb93cSSam Leffler 
130439beb93cSSam Leffler 	/* Vendor_Id */
130539beb93cSSam Leffler 	if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
130639beb93cSSam Leffler 		return NULL;
130739beb93cSSam Leffler 	pos += 4;
130839beb93cSSam Leffler 
130939beb93cSSam Leffler 	/* TLV Type */
131039beb93cSSam Leffler 	if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
131139beb93cSSam Leffler 		return NULL;
131239beb93cSSam Leffler 
131339beb93cSSam Leffler 	wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
131439beb93cSSam Leffler 
131539beb93cSSam Leffler 	return tncc_build_soh(2);
131639beb93cSSam Leffler }
1317