1e5b75505Sopenharmony_ci/*
2e5b75505Sopenharmony_ci * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
3e5b75505Sopenharmony_ci * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
4e5b75505Sopenharmony_ci *
5e5b75505Sopenharmony_ci * This software may be distributed under the terms of the BSD license.
6e5b75505Sopenharmony_ci * See README for more details.
7e5b75505Sopenharmony_ci */
8e5b75505Sopenharmony_ci
9e5b75505Sopenharmony_ci#include "includes.h"
10e5b75505Sopenharmony_ci#ifndef CONFIG_NATIVE_WINDOWS
11e5b75505Sopenharmony_ci#include <dlfcn.h>
12e5b75505Sopenharmony_ci#endif /* CONFIG_NATIVE_WINDOWS */
13e5b75505Sopenharmony_ci
14e5b75505Sopenharmony_ci#include "common.h"
15e5b75505Sopenharmony_ci#include "base64.h"
16e5b75505Sopenharmony_ci#include "common/tnc.h"
17e5b75505Sopenharmony_ci#include "tncc.h"
18e5b75505Sopenharmony_ci#include "eap_common/eap_tlv_common.h"
19e5b75505Sopenharmony_ci#include "eap_common/eap_defs.h"
20e5b75505Sopenharmony_ci
21e5b75505Sopenharmony_ci
22e5b75505Sopenharmony_ci#ifdef UNICODE
23e5b75505Sopenharmony_ci#define TSTR "%S"
24e5b75505Sopenharmony_ci#else /* UNICODE */
25e5b75505Sopenharmony_ci#define TSTR "%s"
26e5b75505Sopenharmony_ci#endif /* UNICODE */
27e5b75505Sopenharmony_ci
28e5b75505Sopenharmony_ci
29e5b75505Sopenharmony_ci#ifndef TNC_CONFIG_FILE
30e5b75505Sopenharmony_ci#define TNC_CONFIG_FILE "/etc/tnc_config"
31e5b75505Sopenharmony_ci#endif /* TNC_CONFIG_FILE */
32e5b75505Sopenharmony_ci#define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
33e5b75505Sopenharmony_ci#define IF_TNCCS_START \
34e5b75505Sopenharmony_ci"<?xml version=\"1.0\"?>\n" \
35e5b75505Sopenharmony_ci"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
36e5b75505Sopenharmony_ci"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
37e5b75505Sopenharmony_ci"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
38e5b75505Sopenharmony_ci"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
39e5b75505Sopenharmony_ci"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
40e5b75505Sopenharmony_ci#define IF_TNCCS_END "\n</TNCCS-Batch>"
41e5b75505Sopenharmony_ci
42e5b75505Sopenharmony_ci/* TNC IF-IMC */
43e5b75505Sopenharmony_ci
44e5b75505Sopenharmony_ci/* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
45e5b75505Sopenharmony_cienum {
46e5b75505Sopenharmony_ci	SSOH_MS_MACHINE_INVENTORY = 1,
47e5b75505Sopenharmony_ci	SSOH_MS_QUARANTINE_STATE = 2,
48e5b75505Sopenharmony_ci	SSOH_MS_PACKET_INFO = 3,
49e5b75505Sopenharmony_ci	SSOH_MS_SYSTEMGENERATED_IDS = 4,
50e5b75505Sopenharmony_ci	SSOH_MS_MACHINENAME = 5,
51e5b75505Sopenharmony_ci	SSOH_MS_CORRELATIONID = 6,
52e5b75505Sopenharmony_ci	SSOH_MS_INSTALLED_SHVS = 7,
53e5b75505Sopenharmony_ci	SSOH_MS_MACHINE_INVENTORY_EX = 8
54e5b75505Sopenharmony_ci};
55e5b75505Sopenharmony_ci
56e5b75505Sopenharmony_cistruct tnc_if_imc {
57e5b75505Sopenharmony_ci	struct tnc_if_imc *next;
58e5b75505Sopenharmony_ci	char *name;
59e5b75505Sopenharmony_ci	char *path;
60e5b75505Sopenharmony_ci	void *dlhandle; /* from dlopen() */
61e5b75505Sopenharmony_ci	TNC_IMCID imcID;
62e5b75505Sopenharmony_ci	TNC_ConnectionID connectionID;
63e5b75505Sopenharmony_ci	TNC_MessageTypeList supported_types;
64e5b75505Sopenharmony_ci	size_t num_supported_types;
65e5b75505Sopenharmony_ci	u8 *imc_send;
66e5b75505Sopenharmony_ci	size_t imc_send_len;
67e5b75505Sopenharmony_ci
68e5b75505Sopenharmony_ci	/* Functions implemented by IMCs (with TNC_IMC_ prefix) */
69e5b75505Sopenharmony_ci	TNC_Result (*Initialize)(
70e5b75505Sopenharmony_ci		TNC_IMCID imcID,
71e5b75505Sopenharmony_ci		TNC_Version minVersion,
72e5b75505Sopenharmony_ci		TNC_Version maxVersion,
73e5b75505Sopenharmony_ci		TNC_Version *pOutActualVersion);
74e5b75505Sopenharmony_ci	TNC_Result (*NotifyConnectionChange)(
75e5b75505Sopenharmony_ci		TNC_IMCID imcID,
76e5b75505Sopenharmony_ci		TNC_ConnectionID connectionID,
77e5b75505Sopenharmony_ci		TNC_ConnectionState newState);
78e5b75505Sopenharmony_ci	TNC_Result (*BeginHandshake)(
79e5b75505Sopenharmony_ci		TNC_IMCID imcID,
80e5b75505Sopenharmony_ci		TNC_ConnectionID connectionID);
81e5b75505Sopenharmony_ci	TNC_Result (*ReceiveMessage)(
82e5b75505Sopenharmony_ci		TNC_IMCID imcID,
83e5b75505Sopenharmony_ci		TNC_ConnectionID connectionID,
84e5b75505Sopenharmony_ci		TNC_BufferReference messageBuffer,
85e5b75505Sopenharmony_ci		TNC_UInt32 messageLength,
86e5b75505Sopenharmony_ci		TNC_MessageType messageType);
87e5b75505Sopenharmony_ci	TNC_Result (*BatchEnding)(
88e5b75505Sopenharmony_ci		TNC_IMCID imcID,
89e5b75505Sopenharmony_ci		TNC_ConnectionID connectionID);
90e5b75505Sopenharmony_ci	TNC_Result (*Terminate)(TNC_IMCID imcID);
91e5b75505Sopenharmony_ci	TNC_Result (*ProvideBindFunction)(
92e5b75505Sopenharmony_ci		TNC_IMCID imcID,
93e5b75505Sopenharmony_ci		TNC_TNCC_BindFunctionPointer bindFunction);
94e5b75505Sopenharmony_ci};
95e5b75505Sopenharmony_ci
96e5b75505Sopenharmony_cistruct tncc_data {
97e5b75505Sopenharmony_ci	struct tnc_if_imc *imc;
98e5b75505Sopenharmony_ci	unsigned int last_batchid;
99e5b75505Sopenharmony_ci};
100e5b75505Sopenharmony_ci
101e5b75505Sopenharmony_ci#define TNC_MAX_IMC_ID 10
102e5b75505Sopenharmony_cistatic struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
103e5b75505Sopenharmony_ci
104e5b75505Sopenharmony_ci
105e5b75505Sopenharmony_ci/* TNCC functions that IMCs can call */
106e5b75505Sopenharmony_ci
107e5b75505Sopenharmony_cistatic TNC_Result TNC_TNCC_ReportMessageTypes(
108e5b75505Sopenharmony_ci	TNC_IMCID imcID,
109e5b75505Sopenharmony_ci	TNC_MessageTypeList supportedTypes,
110e5b75505Sopenharmony_ci	TNC_UInt32 typeCount)
111e5b75505Sopenharmony_ci{
112e5b75505Sopenharmony_ci	TNC_UInt32 i;
113e5b75505Sopenharmony_ci	struct tnc_if_imc *imc;
114e5b75505Sopenharmony_ci
115e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
116e5b75505Sopenharmony_ci		   "typeCount=%lu)",
117e5b75505Sopenharmony_ci		   (unsigned long) imcID, (unsigned long) typeCount);
118e5b75505Sopenharmony_ci
119e5b75505Sopenharmony_ci	for (i = 0; i < typeCount; i++) {
120e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
121e5b75505Sopenharmony_ci			   i, supportedTypes[i]);
122e5b75505Sopenharmony_ci	}
123e5b75505Sopenharmony_ci
124e5b75505Sopenharmony_ci	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
125e5b75505Sopenharmony_ci		return TNC_RESULT_INVALID_PARAMETER;
126e5b75505Sopenharmony_ci
127e5b75505Sopenharmony_ci	imc = tnc_imc[imcID];
128e5b75505Sopenharmony_ci	os_free(imc->supported_types);
129e5b75505Sopenharmony_ci	imc->supported_types = os_memdup(supportedTypes,
130e5b75505Sopenharmony_ci					 typeCount * sizeof(TNC_MessageType));
131e5b75505Sopenharmony_ci	if (imc->supported_types == NULL)
132e5b75505Sopenharmony_ci		return TNC_RESULT_FATAL;
133e5b75505Sopenharmony_ci	imc->num_supported_types = typeCount;
134e5b75505Sopenharmony_ci
135e5b75505Sopenharmony_ci	return TNC_RESULT_SUCCESS;
136e5b75505Sopenharmony_ci}
137e5b75505Sopenharmony_ci
138e5b75505Sopenharmony_ci
139e5b75505Sopenharmony_cistatic TNC_Result TNC_TNCC_SendMessage(
140e5b75505Sopenharmony_ci	TNC_IMCID imcID,
141e5b75505Sopenharmony_ci	TNC_ConnectionID connectionID,
142e5b75505Sopenharmony_ci	TNC_BufferReference message,
143e5b75505Sopenharmony_ci	TNC_UInt32 messageLength,
144e5b75505Sopenharmony_ci	TNC_MessageType messageType)
145e5b75505Sopenharmony_ci{
146e5b75505Sopenharmony_ci	struct tnc_if_imc *imc;
147e5b75505Sopenharmony_ci	unsigned char *b64;
148e5b75505Sopenharmony_ci	size_t b64len;
149e5b75505Sopenharmony_ci
150e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
151e5b75505Sopenharmony_ci		   "connectionID=%lu messageType=%lu)",
152e5b75505Sopenharmony_ci		   imcID, connectionID, messageType);
153e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
154e5b75505Sopenharmony_ci			  message, messageLength);
155e5b75505Sopenharmony_ci
156e5b75505Sopenharmony_ci	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
157e5b75505Sopenharmony_ci		return TNC_RESULT_INVALID_PARAMETER;
158e5b75505Sopenharmony_ci
159e5b75505Sopenharmony_ci	b64 = base64_encode(message, messageLength, &b64len);
160e5b75505Sopenharmony_ci	if (b64 == NULL)
161e5b75505Sopenharmony_ci		return TNC_RESULT_FATAL;
162e5b75505Sopenharmony_ci
163e5b75505Sopenharmony_ci	imc = tnc_imc[imcID];
164e5b75505Sopenharmony_ci	os_free(imc->imc_send);
165e5b75505Sopenharmony_ci	imc->imc_send_len = 0;
166e5b75505Sopenharmony_ci	imc->imc_send = os_zalloc(b64len + 100);
167e5b75505Sopenharmony_ci	if (imc->imc_send == NULL) {
168e5b75505Sopenharmony_ci		os_free(b64);
169e5b75505Sopenharmony_ci		return TNC_RESULT_OTHER;
170e5b75505Sopenharmony_ci	}
171e5b75505Sopenharmony_ci
172e5b75505Sopenharmony_ci	imc->imc_send_len =
173e5b75505Sopenharmony_ci		os_snprintf((char *) imc->imc_send, b64len + 100,
174e5b75505Sopenharmony_ci			    "<IMC-IMV-Message><Type>%08X</Type>"
175e5b75505Sopenharmony_ci			    "<Base64>%s</Base64></IMC-IMV-Message>",
176e5b75505Sopenharmony_ci			    (unsigned int) messageType, b64);
177e5b75505Sopenharmony_ci
178e5b75505Sopenharmony_ci	os_free(b64);
179e5b75505Sopenharmony_ci
180e5b75505Sopenharmony_ci	return TNC_RESULT_SUCCESS;
181e5b75505Sopenharmony_ci}
182e5b75505Sopenharmony_ci
183e5b75505Sopenharmony_ci
184e5b75505Sopenharmony_cistatic TNC_Result TNC_TNCC_RequestHandshakeRetry(
185e5b75505Sopenharmony_ci	TNC_IMCID imcID,
186e5b75505Sopenharmony_ci	TNC_ConnectionID connectionID,
187e5b75505Sopenharmony_ci	TNC_RetryReason reason)
188e5b75505Sopenharmony_ci{
189e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
190e5b75505Sopenharmony_ci
191e5b75505Sopenharmony_ci	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
192e5b75505Sopenharmony_ci		return TNC_RESULT_INVALID_PARAMETER;
193e5b75505Sopenharmony_ci
194e5b75505Sopenharmony_ci	/*
195e5b75505Sopenharmony_ci	 * TODO: trigger a call to eapol_sm_request_reauth(). This would
196e5b75505Sopenharmony_ci	 * require that the IMC continues to be loaded in memory afer
197e5b75505Sopenharmony_ci	 * authentication..
198e5b75505Sopenharmony_ci	 */
199e5b75505Sopenharmony_ci
200e5b75505Sopenharmony_ci	return TNC_RESULT_SUCCESS;
201e5b75505Sopenharmony_ci}
202e5b75505Sopenharmony_ci
203e5b75505Sopenharmony_ci
204e5b75505Sopenharmony_cistatic TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
205e5b75505Sopenharmony_ci				      const char *message)
206e5b75505Sopenharmony_ci{
207e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
208e5b75505Sopenharmony_ci		   "severity==%lu message='%s')",
209e5b75505Sopenharmony_ci		   imcID, severity, message);
210e5b75505Sopenharmony_ci	return TNC_RESULT_SUCCESS;
211e5b75505Sopenharmony_ci}
212e5b75505Sopenharmony_ci
213e5b75505Sopenharmony_ci
214e5b75505Sopenharmony_cistatic TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID,
215e5b75505Sopenharmony_ci				       TNC_ConnectionID connectionID,
216e5b75505Sopenharmony_ci				       const char *message)
217e5b75505Sopenharmony_ci{
218e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
219e5b75505Sopenharmony_ci		   "connectionID==%lu message='%s')",
220e5b75505Sopenharmony_ci		   imcID, connectionID, message);
221e5b75505Sopenharmony_ci	return TNC_RESULT_SUCCESS;
222e5b75505Sopenharmony_ci}
223e5b75505Sopenharmony_ci
224e5b75505Sopenharmony_ci
225e5b75505Sopenharmony_cistatic TNC_Result TNC_TNCC_BindFunction(
226e5b75505Sopenharmony_ci	TNC_IMCID imcID,
227e5b75505Sopenharmony_ci	char *functionName,
228e5b75505Sopenharmony_ci	void **pOutfunctionPointer)
229e5b75505Sopenharmony_ci{
230e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
231e5b75505Sopenharmony_ci		   "functionName='%s')", (unsigned long) imcID, functionName);
232e5b75505Sopenharmony_ci
233e5b75505Sopenharmony_ci	if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
234e5b75505Sopenharmony_ci		return TNC_RESULT_INVALID_PARAMETER;
235e5b75505Sopenharmony_ci
236e5b75505Sopenharmony_ci	if (pOutfunctionPointer == NULL)
237e5b75505Sopenharmony_ci		return TNC_RESULT_INVALID_PARAMETER;
238e5b75505Sopenharmony_ci
239e5b75505Sopenharmony_ci	if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
240e5b75505Sopenharmony_ci		*pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
241e5b75505Sopenharmony_ci	else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
242e5b75505Sopenharmony_ci		*pOutfunctionPointer = TNC_TNCC_SendMessage;
243e5b75505Sopenharmony_ci	else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
244e5b75505Sopenharmony_ci		 0)
245e5b75505Sopenharmony_ci		*pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
246e5b75505Sopenharmony_ci	else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
247e5b75505Sopenharmony_ci		*pOutfunctionPointer = TNC_9048_LogMessage;
248e5b75505Sopenharmony_ci	else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
249e5b75505Sopenharmony_ci		*pOutfunctionPointer = TNC_9048_UserMessage;
250e5b75505Sopenharmony_ci	else
251e5b75505Sopenharmony_ci		*pOutfunctionPointer = NULL;
252e5b75505Sopenharmony_ci
253e5b75505Sopenharmony_ci	return TNC_RESULT_SUCCESS;
254e5b75505Sopenharmony_ci}
255e5b75505Sopenharmony_ci
256e5b75505Sopenharmony_ci
257e5b75505Sopenharmony_cistatic void * tncc_get_sym(void *handle, char *func)
258e5b75505Sopenharmony_ci{
259e5b75505Sopenharmony_ci	void *fptr;
260e5b75505Sopenharmony_ci
261e5b75505Sopenharmony_ci#ifdef CONFIG_NATIVE_WINDOWS
262e5b75505Sopenharmony_ci#ifdef _WIN32_WCE
263e5b75505Sopenharmony_ci	fptr = GetProcAddressA(handle, func);
264e5b75505Sopenharmony_ci#else /* _WIN32_WCE */
265e5b75505Sopenharmony_ci	fptr = GetProcAddress(handle, func);
266e5b75505Sopenharmony_ci#endif /* _WIN32_WCE */
267e5b75505Sopenharmony_ci#else /* CONFIG_NATIVE_WINDOWS */
268e5b75505Sopenharmony_ci	fptr = dlsym(handle, func);
269e5b75505Sopenharmony_ci#endif /* CONFIG_NATIVE_WINDOWS */
270e5b75505Sopenharmony_ci
271e5b75505Sopenharmony_ci	return fptr;
272e5b75505Sopenharmony_ci}
273e5b75505Sopenharmony_ci
274e5b75505Sopenharmony_ci
275e5b75505Sopenharmony_cistatic int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
276e5b75505Sopenharmony_ci{
277e5b75505Sopenharmony_ci	void *handle = imc->dlhandle;
278e5b75505Sopenharmony_ci
279e5b75505Sopenharmony_ci	/* Mandatory IMC functions */
280e5b75505Sopenharmony_ci	imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
281e5b75505Sopenharmony_ci	if (imc->Initialize == NULL) {
282e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
283e5b75505Sopenharmony_ci			   "TNC_IMC_Initialize");
284e5b75505Sopenharmony_ci		return -1;
285e5b75505Sopenharmony_ci	}
286e5b75505Sopenharmony_ci
287e5b75505Sopenharmony_ci	imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
288e5b75505Sopenharmony_ci	if (imc->BeginHandshake == NULL) {
289e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
290e5b75505Sopenharmony_ci			   "TNC_IMC_BeginHandshake");
291e5b75505Sopenharmony_ci		return -1;
292e5b75505Sopenharmony_ci	}
293e5b75505Sopenharmony_ci
294e5b75505Sopenharmony_ci	imc->ProvideBindFunction =
295e5b75505Sopenharmony_ci		tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
296e5b75505Sopenharmony_ci	if (imc->ProvideBindFunction == NULL) {
297e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: IMC does not export "
298e5b75505Sopenharmony_ci			   "TNC_IMC_ProvideBindFunction");
299e5b75505Sopenharmony_ci		return -1;
300e5b75505Sopenharmony_ci	}
301e5b75505Sopenharmony_ci
302e5b75505Sopenharmony_ci	/* Optional IMC functions */
303e5b75505Sopenharmony_ci	imc->NotifyConnectionChange =
304e5b75505Sopenharmony_ci		tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
305e5b75505Sopenharmony_ci	imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
306e5b75505Sopenharmony_ci	imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
307e5b75505Sopenharmony_ci	imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
308e5b75505Sopenharmony_ci
309e5b75505Sopenharmony_ci	return 0;
310e5b75505Sopenharmony_ci}
311e5b75505Sopenharmony_ci
312e5b75505Sopenharmony_ci
313e5b75505Sopenharmony_cistatic int tncc_imc_initialize(struct tnc_if_imc *imc)
314e5b75505Sopenharmony_ci{
315e5b75505Sopenharmony_ci	TNC_Result res;
316e5b75505Sopenharmony_ci	TNC_Version imc_ver;
317e5b75505Sopenharmony_ci
318e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
319e5b75505Sopenharmony_ci		   imc->name);
320e5b75505Sopenharmony_ci	res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
321e5b75505Sopenharmony_ci			      TNC_IFIMC_VERSION_1, &imc_ver);
322e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
323e5b75505Sopenharmony_ci		   (unsigned long) res, (unsigned long) imc_ver);
324e5b75505Sopenharmony_ci
325e5b75505Sopenharmony_ci	return res == TNC_RESULT_SUCCESS ? 0 : -1;
326e5b75505Sopenharmony_ci}
327e5b75505Sopenharmony_ci
328e5b75505Sopenharmony_ci
329e5b75505Sopenharmony_cistatic int tncc_imc_terminate(struct tnc_if_imc *imc)
330e5b75505Sopenharmony_ci{
331e5b75505Sopenharmony_ci	TNC_Result res;
332e5b75505Sopenharmony_ci
333e5b75505Sopenharmony_ci	if (imc->Terminate == NULL)
334e5b75505Sopenharmony_ci		return 0;
335e5b75505Sopenharmony_ci
336e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
337e5b75505Sopenharmony_ci		   imc->name);
338e5b75505Sopenharmony_ci	res = imc->Terminate(imc->imcID);
339e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
340e5b75505Sopenharmony_ci		   (unsigned long) res);
341e5b75505Sopenharmony_ci
342e5b75505Sopenharmony_ci	return res == TNC_RESULT_SUCCESS ? 0 : -1;
343e5b75505Sopenharmony_ci}
344e5b75505Sopenharmony_ci
345e5b75505Sopenharmony_ci
346e5b75505Sopenharmony_cistatic int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
347e5b75505Sopenharmony_ci{
348e5b75505Sopenharmony_ci	TNC_Result res;
349e5b75505Sopenharmony_ci
350e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
351e5b75505Sopenharmony_ci		   "IMC '%s'", imc->name);
352e5b75505Sopenharmony_ci	res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
353e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
354e5b75505Sopenharmony_ci		   (unsigned long) res);
355e5b75505Sopenharmony_ci
356e5b75505Sopenharmony_ci	return res == TNC_RESULT_SUCCESS ? 0 : -1;
357e5b75505Sopenharmony_ci}
358e5b75505Sopenharmony_ci
359e5b75505Sopenharmony_ci
360e5b75505Sopenharmony_cistatic int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
361e5b75505Sopenharmony_ci					     TNC_ConnectionState state)
362e5b75505Sopenharmony_ci{
363e5b75505Sopenharmony_ci	TNC_Result res;
364e5b75505Sopenharmony_ci
365e5b75505Sopenharmony_ci	if (imc->NotifyConnectionChange == NULL)
366e5b75505Sopenharmony_ci		return 0;
367e5b75505Sopenharmony_ci
368e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
369e5b75505Sopenharmony_ci		   " for IMC '%s'", (int) state, imc->name);
370e5b75505Sopenharmony_ci	res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
371e5b75505Sopenharmony_ci					  state);
372e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
373e5b75505Sopenharmony_ci		   (unsigned long) res);
374e5b75505Sopenharmony_ci
375e5b75505Sopenharmony_ci	return res == TNC_RESULT_SUCCESS ? 0 : -1;
376e5b75505Sopenharmony_ci}
377e5b75505Sopenharmony_ci
378e5b75505Sopenharmony_ci
379e5b75505Sopenharmony_cistatic int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
380e5b75505Sopenharmony_ci{
381e5b75505Sopenharmony_ci	TNC_Result res;
382e5b75505Sopenharmony_ci
383e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
384e5b75505Sopenharmony_ci		   "'%s'", imc->name);
385e5b75505Sopenharmony_ci	res = imc->BeginHandshake(imc->imcID, imc->connectionID);
386e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
387e5b75505Sopenharmony_ci		   (unsigned long) res);
388e5b75505Sopenharmony_ci
389e5b75505Sopenharmony_ci	return res == TNC_RESULT_SUCCESS ? 0 : -1;
390e5b75505Sopenharmony_ci}
391e5b75505Sopenharmony_ci
392e5b75505Sopenharmony_ci
393e5b75505Sopenharmony_cistatic int tncc_load_imc(struct tnc_if_imc *imc)
394e5b75505Sopenharmony_ci{
395e5b75505Sopenharmony_ci	if (imc->path == NULL) {
396e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
397e5b75505Sopenharmony_ci		return -1;
398e5b75505Sopenharmony_ci	}
399e5b75505Sopenharmony_ci
400e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
401e5b75505Sopenharmony_ci		   imc->name, imc->path);
402e5b75505Sopenharmony_ci#ifdef CONFIG_NATIVE_WINDOWS
403e5b75505Sopenharmony_ci#ifdef UNICODE
404e5b75505Sopenharmony_ci	{
405e5b75505Sopenharmony_ci		TCHAR *lib = wpa_strdup_tchar(imc->path);
406e5b75505Sopenharmony_ci		if (lib == NULL)
407e5b75505Sopenharmony_ci			return -1;
408e5b75505Sopenharmony_ci		imc->dlhandle = LoadLibrary(lib);
409e5b75505Sopenharmony_ci		os_free(lib);
410e5b75505Sopenharmony_ci	}
411e5b75505Sopenharmony_ci#else /* UNICODE */
412e5b75505Sopenharmony_ci	imc->dlhandle = LoadLibrary(imc->path);
413e5b75505Sopenharmony_ci#endif /* UNICODE */
414e5b75505Sopenharmony_ci	if (imc->dlhandle == NULL) {
415e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
416e5b75505Sopenharmony_ci			   imc->name, imc->path, (int) GetLastError());
417e5b75505Sopenharmony_ci		return -1;
418e5b75505Sopenharmony_ci	}
419e5b75505Sopenharmony_ci#else /* CONFIG_NATIVE_WINDOWS */
420e5b75505Sopenharmony_ci	imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
421e5b75505Sopenharmony_ci	if (imc->dlhandle == NULL) {
422e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
423e5b75505Sopenharmony_ci			   imc->name, imc->path, dlerror());
424e5b75505Sopenharmony_ci		return -1;
425e5b75505Sopenharmony_ci	}
426e5b75505Sopenharmony_ci#endif /* CONFIG_NATIVE_WINDOWS */
427e5b75505Sopenharmony_ci
428e5b75505Sopenharmony_ci	if (tncc_imc_resolve_funcs(imc) < 0) {
429e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
430e5b75505Sopenharmony_ci		return -1;
431e5b75505Sopenharmony_ci	}
432e5b75505Sopenharmony_ci
433e5b75505Sopenharmony_ci	if (tncc_imc_initialize(imc) < 0 ||
434e5b75505Sopenharmony_ci	    tncc_imc_provide_bind_function(imc) < 0) {
435e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
436e5b75505Sopenharmony_ci		return -1;
437e5b75505Sopenharmony_ci	}
438e5b75505Sopenharmony_ci
439e5b75505Sopenharmony_ci	return 0;
440e5b75505Sopenharmony_ci}
441e5b75505Sopenharmony_ci
442e5b75505Sopenharmony_ci
443e5b75505Sopenharmony_cistatic void tncc_unload_imc(struct tnc_if_imc *imc)
444e5b75505Sopenharmony_ci{
445e5b75505Sopenharmony_ci	tncc_imc_terminate(imc);
446e5b75505Sopenharmony_ci	tnc_imc[imc->imcID] = NULL;
447e5b75505Sopenharmony_ci
448e5b75505Sopenharmony_ci	if (imc->dlhandle) {
449e5b75505Sopenharmony_ci#ifdef CONFIG_NATIVE_WINDOWS
450e5b75505Sopenharmony_ci		FreeLibrary(imc->dlhandle);
451e5b75505Sopenharmony_ci#else /* CONFIG_NATIVE_WINDOWS */
452e5b75505Sopenharmony_ci		dlclose(imc->dlhandle);
453e5b75505Sopenharmony_ci#endif /* CONFIG_NATIVE_WINDOWS */
454e5b75505Sopenharmony_ci	}
455e5b75505Sopenharmony_ci	os_free(imc->name);
456e5b75505Sopenharmony_ci	os_free(imc->path);
457e5b75505Sopenharmony_ci	os_free(imc->supported_types);
458e5b75505Sopenharmony_ci	os_free(imc->imc_send);
459e5b75505Sopenharmony_ci}
460e5b75505Sopenharmony_ci
461e5b75505Sopenharmony_ci
462e5b75505Sopenharmony_cistatic int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
463e5b75505Sopenharmony_ci{
464e5b75505Sopenharmony_ci	size_t i;
465e5b75505Sopenharmony_ci	unsigned int vendor, subtype;
466e5b75505Sopenharmony_ci
467e5b75505Sopenharmony_ci	if (imc == NULL || imc->supported_types == NULL)
468e5b75505Sopenharmony_ci		return 0;
469e5b75505Sopenharmony_ci
470e5b75505Sopenharmony_ci	vendor = type >> 8;
471e5b75505Sopenharmony_ci	subtype = type & 0xff;
472e5b75505Sopenharmony_ci
473e5b75505Sopenharmony_ci	for (i = 0; i < imc->num_supported_types; i++) {
474e5b75505Sopenharmony_ci		unsigned int svendor, ssubtype;
475e5b75505Sopenharmony_ci		svendor = imc->supported_types[i] >> 8;
476e5b75505Sopenharmony_ci		ssubtype = imc->supported_types[i] & 0xff;
477e5b75505Sopenharmony_ci		if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
478e5b75505Sopenharmony_ci		    (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
479e5b75505Sopenharmony_ci			return 1;
480e5b75505Sopenharmony_ci	}
481e5b75505Sopenharmony_ci
482e5b75505Sopenharmony_ci	return 0;
483e5b75505Sopenharmony_ci}
484e5b75505Sopenharmony_ci
485e5b75505Sopenharmony_ci
486e5b75505Sopenharmony_cistatic void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
487e5b75505Sopenharmony_ci			      const u8 *msg, size_t len)
488e5b75505Sopenharmony_ci{
489e5b75505Sopenharmony_ci	struct tnc_if_imc *imc;
490e5b75505Sopenharmony_ci	TNC_Result res;
491e5b75505Sopenharmony_ci
492e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
493e5b75505Sopenharmony_ci
494e5b75505Sopenharmony_ci	for (imc = tncc->imc; imc; imc = imc->next) {
495e5b75505Sopenharmony_ci		if (imc->ReceiveMessage == NULL ||
496e5b75505Sopenharmony_ci		    !tncc_supported_type(imc, type))
497e5b75505Sopenharmony_ci			continue;
498e5b75505Sopenharmony_ci
499e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
500e5b75505Sopenharmony_ci			   imc->name);
501e5b75505Sopenharmony_ci		res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
502e5b75505Sopenharmony_ci					  (TNC_BufferReference) msg, len,
503e5b75505Sopenharmony_ci					  type);
504e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
505e5b75505Sopenharmony_ci			   (unsigned long) res);
506e5b75505Sopenharmony_ci	}
507e5b75505Sopenharmony_ci}
508e5b75505Sopenharmony_ci
509e5b75505Sopenharmony_ci
510e5b75505Sopenharmony_civoid tncc_init_connection(struct tncc_data *tncc)
511e5b75505Sopenharmony_ci{
512e5b75505Sopenharmony_ci	struct tnc_if_imc *imc;
513e5b75505Sopenharmony_ci
514e5b75505Sopenharmony_ci	for (imc = tncc->imc; imc; imc = imc->next) {
515e5b75505Sopenharmony_ci		tncc_imc_notify_connection_change(
516e5b75505Sopenharmony_ci			imc, TNC_CONNECTION_STATE_CREATE);
517e5b75505Sopenharmony_ci		tncc_imc_notify_connection_change(
518e5b75505Sopenharmony_ci			imc, TNC_CONNECTION_STATE_HANDSHAKE);
519e5b75505Sopenharmony_ci
520e5b75505Sopenharmony_ci		os_free(imc->imc_send);
521e5b75505Sopenharmony_ci		imc->imc_send = NULL;
522e5b75505Sopenharmony_ci		imc->imc_send_len = 0;
523e5b75505Sopenharmony_ci
524e5b75505Sopenharmony_ci		tncc_imc_begin_handshake(imc);
525e5b75505Sopenharmony_ci	}
526e5b75505Sopenharmony_ci}
527e5b75505Sopenharmony_ci
528e5b75505Sopenharmony_ci
529e5b75505Sopenharmony_cisize_t tncc_total_send_len(struct tncc_data *tncc)
530e5b75505Sopenharmony_ci{
531e5b75505Sopenharmony_ci	struct tnc_if_imc *imc;
532e5b75505Sopenharmony_ci
533e5b75505Sopenharmony_ci	size_t len = 0;
534e5b75505Sopenharmony_ci	for (imc = tncc->imc; imc; imc = imc->next)
535e5b75505Sopenharmony_ci		len += imc->imc_send_len;
536e5b75505Sopenharmony_ci	return len;
537e5b75505Sopenharmony_ci}
538e5b75505Sopenharmony_ci
539e5b75505Sopenharmony_ci
540e5b75505Sopenharmony_ciu8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
541e5b75505Sopenharmony_ci{
542e5b75505Sopenharmony_ci	struct tnc_if_imc *imc;
543e5b75505Sopenharmony_ci
544e5b75505Sopenharmony_ci	for (imc = tncc->imc; imc; imc = imc->next) {
545e5b75505Sopenharmony_ci		if (imc->imc_send == NULL)
546e5b75505Sopenharmony_ci			continue;
547e5b75505Sopenharmony_ci
548e5b75505Sopenharmony_ci		os_memcpy(pos, imc->imc_send, imc->imc_send_len);
549e5b75505Sopenharmony_ci		pos += imc->imc_send_len;
550e5b75505Sopenharmony_ci		os_free(imc->imc_send);
551e5b75505Sopenharmony_ci		imc->imc_send = NULL;
552e5b75505Sopenharmony_ci		imc->imc_send_len = 0;
553e5b75505Sopenharmony_ci	}
554e5b75505Sopenharmony_ci
555e5b75505Sopenharmony_ci	return pos;
556e5b75505Sopenharmony_ci}
557e5b75505Sopenharmony_ci
558e5b75505Sopenharmony_ci
559e5b75505Sopenharmony_cichar * tncc_if_tnccs_start(struct tncc_data *tncc)
560e5b75505Sopenharmony_ci{
561e5b75505Sopenharmony_ci	char *buf = os_malloc(1000);
562e5b75505Sopenharmony_ci	if (buf == NULL)
563e5b75505Sopenharmony_ci		return NULL;
564e5b75505Sopenharmony_ci	tncc->last_batchid++;
565e5b75505Sopenharmony_ci	os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
566e5b75505Sopenharmony_ci	return buf;
567e5b75505Sopenharmony_ci}
568e5b75505Sopenharmony_ci
569e5b75505Sopenharmony_ci
570e5b75505Sopenharmony_cichar * tncc_if_tnccs_end(void)
571e5b75505Sopenharmony_ci{
572e5b75505Sopenharmony_ci	char *buf = os_malloc(100);
573e5b75505Sopenharmony_ci	if (buf == NULL)
574e5b75505Sopenharmony_ci		return NULL;
575e5b75505Sopenharmony_ci	os_snprintf(buf, 100, IF_TNCCS_END);
576e5b75505Sopenharmony_ci	return buf;
577e5b75505Sopenharmony_ci}
578e5b75505Sopenharmony_ci
579e5b75505Sopenharmony_ci
580e5b75505Sopenharmony_cistatic void tncc_notify_recommendation(struct tncc_data *tncc,
581e5b75505Sopenharmony_ci				       enum tncc_process_res res)
582e5b75505Sopenharmony_ci{
583e5b75505Sopenharmony_ci	TNC_ConnectionState state;
584e5b75505Sopenharmony_ci	struct tnc_if_imc *imc;
585e5b75505Sopenharmony_ci
586e5b75505Sopenharmony_ci	switch (res) {
587e5b75505Sopenharmony_ci	case TNCCS_RECOMMENDATION_ALLOW:
588e5b75505Sopenharmony_ci		state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
589e5b75505Sopenharmony_ci		break;
590e5b75505Sopenharmony_ci	case TNCCS_RECOMMENDATION_NONE:
591e5b75505Sopenharmony_ci		state = TNC_CONNECTION_STATE_ACCESS_NONE;
592e5b75505Sopenharmony_ci		break;
593e5b75505Sopenharmony_ci	case TNCCS_RECOMMENDATION_ISOLATE:
594e5b75505Sopenharmony_ci		state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
595e5b75505Sopenharmony_ci		break;
596e5b75505Sopenharmony_ci	default:
597e5b75505Sopenharmony_ci		state = TNC_CONNECTION_STATE_ACCESS_NONE;
598e5b75505Sopenharmony_ci		break;
599e5b75505Sopenharmony_ci	}
600e5b75505Sopenharmony_ci
601e5b75505Sopenharmony_ci	for (imc = tncc->imc; imc; imc = imc->next)
602e5b75505Sopenharmony_ci		tncc_imc_notify_connection_change(imc, state);
603e5b75505Sopenharmony_ci}
604e5b75505Sopenharmony_ci
605e5b75505Sopenharmony_ci
606e5b75505Sopenharmony_cistatic int tncc_get_type(char *start, unsigned int *type)
607e5b75505Sopenharmony_ci{
608e5b75505Sopenharmony_ci	char *pos = os_strstr(start, "<Type>");
609e5b75505Sopenharmony_ci	if (pos == NULL)
610e5b75505Sopenharmony_ci		return -1;
611e5b75505Sopenharmony_ci	pos += 6;
612e5b75505Sopenharmony_ci	*type = strtoul(pos, NULL, 16);
613e5b75505Sopenharmony_ci	return 0;
614e5b75505Sopenharmony_ci}
615e5b75505Sopenharmony_ci
616e5b75505Sopenharmony_ci
617e5b75505Sopenharmony_cistatic unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
618e5b75505Sopenharmony_ci{
619e5b75505Sopenharmony_ci	char *pos, *pos2;
620e5b75505Sopenharmony_ci	unsigned char *decoded;
621e5b75505Sopenharmony_ci
622e5b75505Sopenharmony_ci	pos = os_strstr(start, "<Base64>");
623e5b75505Sopenharmony_ci	if (pos == NULL)
624e5b75505Sopenharmony_ci		return NULL;
625e5b75505Sopenharmony_ci
626e5b75505Sopenharmony_ci	pos += 8;
627e5b75505Sopenharmony_ci	pos2 = os_strstr(pos, "</Base64>");
628e5b75505Sopenharmony_ci	if (pos2 == NULL)
629e5b75505Sopenharmony_ci		return NULL;
630e5b75505Sopenharmony_ci	*pos2 = '\0';
631e5b75505Sopenharmony_ci
632e5b75505Sopenharmony_ci	decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
633e5b75505Sopenharmony_ci				decoded_len);
634e5b75505Sopenharmony_ci	*pos2 = '<';
635e5b75505Sopenharmony_ci	if (decoded == NULL) {
636e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
637e5b75505Sopenharmony_ci	}
638e5b75505Sopenharmony_ci
639e5b75505Sopenharmony_ci	return decoded;
640e5b75505Sopenharmony_ci}
641e5b75505Sopenharmony_ci
642e5b75505Sopenharmony_ci
643e5b75505Sopenharmony_cistatic enum tncc_process_res tncc_get_recommendation(char *start)
644e5b75505Sopenharmony_ci{
645e5b75505Sopenharmony_ci	char *pos, *pos2, saved;
646e5b75505Sopenharmony_ci	int recom;
647e5b75505Sopenharmony_ci
648e5b75505Sopenharmony_ci	pos = os_strstr(start, "<TNCCS-Recommendation ");
649e5b75505Sopenharmony_ci	if (pos == NULL)
650e5b75505Sopenharmony_ci		return TNCCS_RECOMMENDATION_ERROR;
651e5b75505Sopenharmony_ci
652e5b75505Sopenharmony_ci	pos += 21;
653e5b75505Sopenharmony_ci	pos = os_strstr(pos, " type=");
654e5b75505Sopenharmony_ci	if (pos == NULL)
655e5b75505Sopenharmony_ci		return TNCCS_RECOMMENDATION_ERROR;
656e5b75505Sopenharmony_ci	pos += 6;
657e5b75505Sopenharmony_ci
658e5b75505Sopenharmony_ci	if (*pos == '"')
659e5b75505Sopenharmony_ci		pos++;
660e5b75505Sopenharmony_ci
661e5b75505Sopenharmony_ci	pos2 = pos;
662e5b75505Sopenharmony_ci	while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
663e5b75505Sopenharmony_ci		pos2++;
664e5b75505Sopenharmony_ci
665e5b75505Sopenharmony_ci	if (*pos2 == '\0')
666e5b75505Sopenharmony_ci		return TNCCS_RECOMMENDATION_ERROR;
667e5b75505Sopenharmony_ci
668e5b75505Sopenharmony_ci	saved = *pos2;
669e5b75505Sopenharmony_ci	*pos2 = '\0';
670e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
671e5b75505Sopenharmony_ci
672e5b75505Sopenharmony_ci	recom = TNCCS_RECOMMENDATION_ERROR;
673e5b75505Sopenharmony_ci	if (os_strcmp(pos, "allow") == 0)
674e5b75505Sopenharmony_ci		recom = TNCCS_RECOMMENDATION_ALLOW;
675e5b75505Sopenharmony_ci	else if (os_strcmp(pos, "none") == 0)
676e5b75505Sopenharmony_ci		recom = TNCCS_RECOMMENDATION_NONE;
677e5b75505Sopenharmony_ci	else if (os_strcmp(pos, "isolate") == 0)
678e5b75505Sopenharmony_ci		recom = TNCCS_RECOMMENDATION_ISOLATE;
679e5b75505Sopenharmony_ci
680e5b75505Sopenharmony_ci	*pos2 = saved;
681e5b75505Sopenharmony_ci
682e5b75505Sopenharmony_ci	return recom;
683e5b75505Sopenharmony_ci}
684e5b75505Sopenharmony_ci
685e5b75505Sopenharmony_ci
686e5b75505Sopenharmony_cienum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
687e5b75505Sopenharmony_ci					    const u8 *msg, size_t len)
688e5b75505Sopenharmony_ci{
689e5b75505Sopenharmony_ci	char *buf, *start, *end, *pos, *pos2, *payload;
690e5b75505Sopenharmony_ci	unsigned int batch_id;
691e5b75505Sopenharmony_ci	unsigned char *decoded;
692e5b75505Sopenharmony_ci	size_t decoded_len;
693e5b75505Sopenharmony_ci	enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
694e5b75505Sopenharmony_ci	int recommendation_msg = 0;
695e5b75505Sopenharmony_ci
696e5b75505Sopenharmony_ci	wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Received IF-TNCCS message",
697e5b75505Sopenharmony_ci			  msg, len);
698e5b75505Sopenharmony_ci	buf = dup_binstr(msg, len);
699e5b75505Sopenharmony_ci	if (buf == NULL)
700e5b75505Sopenharmony_ci		return TNCCS_PROCESS_ERROR;
701e5b75505Sopenharmony_ci
702e5b75505Sopenharmony_ci	start = os_strstr(buf, "<TNCCS-Batch ");
703e5b75505Sopenharmony_ci	end = os_strstr(buf, "</TNCCS-Batch>");
704e5b75505Sopenharmony_ci	if (start == NULL || end == NULL || start > end) {
705e5b75505Sopenharmony_ci		os_free(buf);
706e5b75505Sopenharmony_ci		return TNCCS_PROCESS_ERROR;
707e5b75505Sopenharmony_ci	}
708e5b75505Sopenharmony_ci
709e5b75505Sopenharmony_ci	start += 13;
710e5b75505Sopenharmony_ci	while (*start == ' ')
711e5b75505Sopenharmony_ci		start++;
712e5b75505Sopenharmony_ci	*end = '\0';
713e5b75505Sopenharmony_ci
714e5b75505Sopenharmony_ci	pos = os_strstr(start, "BatchId=");
715e5b75505Sopenharmony_ci	if (pos == NULL) {
716e5b75505Sopenharmony_ci		os_free(buf);
717e5b75505Sopenharmony_ci		return TNCCS_PROCESS_ERROR;
718e5b75505Sopenharmony_ci	}
719e5b75505Sopenharmony_ci
720e5b75505Sopenharmony_ci	pos += 8;
721e5b75505Sopenharmony_ci	if (*pos == '"')
722e5b75505Sopenharmony_ci		pos++;
723e5b75505Sopenharmony_ci	batch_id = atoi(pos);
724e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
725e5b75505Sopenharmony_ci		   batch_id);
726e5b75505Sopenharmony_ci	if (batch_id != tncc->last_batchid + 1) {
727e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
728e5b75505Sopenharmony_ci			   "%u (expected %u)",
729e5b75505Sopenharmony_ci			   batch_id, tncc->last_batchid + 1);
730e5b75505Sopenharmony_ci		os_free(buf);
731e5b75505Sopenharmony_ci		return TNCCS_PROCESS_ERROR;
732e5b75505Sopenharmony_ci	}
733e5b75505Sopenharmony_ci	tncc->last_batchid = batch_id;
734e5b75505Sopenharmony_ci
735e5b75505Sopenharmony_ci	while (*pos != '\0' && *pos != '>')
736e5b75505Sopenharmony_ci		pos++;
737e5b75505Sopenharmony_ci	if (*pos == '\0') {
738e5b75505Sopenharmony_ci		os_free(buf);
739e5b75505Sopenharmony_ci		return TNCCS_PROCESS_ERROR;
740e5b75505Sopenharmony_ci	}
741e5b75505Sopenharmony_ci	pos++;
742e5b75505Sopenharmony_ci	payload = start;
743e5b75505Sopenharmony_ci
744e5b75505Sopenharmony_ci	/*
745e5b75505Sopenharmony_ci	 * <IMC-IMV-Message>
746e5b75505Sopenharmony_ci	 * <Type>01234567</Type>
747e5b75505Sopenharmony_ci	 * <Base64>foo==</Base64>
748e5b75505Sopenharmony_ci	 * </IMC-IMV-Message>
749e5b75505Sopenharmony_ci	 */
750e5b75505Sopenharmony_ci
751e5b75505Sopenharmony_ci	while (*start) {
752e5b75505Sopenharmony_ci		char *endpos;
753e5b75505Sopenharmony_ci		unsigned int type;
754e5b75505Sopenharmony_ci
755e5b75505Sopenharmony_ci		pos = os_strstr(start, "<IMC-IMV-Message>");
756e5b75505Sopenharmony_ci		if (pos == NULL)
757e5b75505Sopenharmony_ci			break;
758e5b75505Sopenharmony_ci		start = pos + 17;
759e5b75505Sopenharmony_ci		end = os_strstr(start, "</IMC-IMV-Message>");
760e5b75505Sopenharmony_ci		if (end == NULL)
761e5b75505Sopenharmony_ci			break;
762e5b75505Sopenharmony_ci		*end = '\0';
763e5b75505Sopenharmony_ci		endpos = end;
764e5b75505Sopenharmony_ci		end += 18;
765e5b75505Sopenharmony_ci
766e5b75505Sopenharmony_ci		if (tncc_get_type(start, &type) < 0) {
767e5b75505Sopenharmony_ci			*endpos = '<';
768e5b75505Sopenharmony_ci			start = end;
769e5b75505Sopenharmony_ci			continue;
770e5b75505Sopenharmony_ci		}
771e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
772e5b75505Sopenharmony_ci
773e5b75505Sopenharmony_ci		decoded = tncc_get_base64(start, &decoded_len);
774e5b75505Sopenharmony_ci		if (decoded == NULL) {
775e5b75505Sopenharmony_ci			*endpos = '<';
776e5b75505Sopenharmony_ci			start = end;
777e5b75505Sopenharmony_ci			continue;
778e5b75505Sopenharmony_ci		}
779e5b75505Sopenharmony_ci
780e5b75505Sopenharmony_ci		tncc_send_to_imcs(tncc, type, decoded, decoded_len);
781e5b75505Sopenharmony_ci
782e5b75505Sopenharmony_ci		os_free(decoded);
783e5b75505Sopenharmony_ci
784e5b75505Sopenharmony_ci		start = end;
785e5b75505Sopenharmony_ci	}
786e5b75505Sopenharmony_ci
787e5b75505Sopenharmony_ci	/*
788e5b75505Sopenharmony_ci	 * <TNCC-TNCS-Message>
789e5b75505Sopenharmony_ci	 * <Type>01234567</Type>
790e5b75505Sopenharmony_ci	 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
791e5b75505Sopenharmony_ci	 * <Base64>foo==</Base64>
792e5b75505Sopenharmony_ci	 * </TNCC-TNCS-Message>
793e5b75505Sopenharmony_ci	 */
794e5b75505Sopenharmony_ci
795e5b75505Sopenharmony_ci	start = payload;
796e5b75505Sopenharmony_ci	while (*start) {
797e5b75505Sopenharmony_ci		unsigned int type;
798e5b75505Sopenharmony_ci		char *xml, *xmlend, *endpos;
799e5b75505Sopenharmony_ci
800e5b75505Sopenharmony_ci		pos = os_strstr(start, "<TNCC-TNCS-Message>");
801e5b75505Sopenharmony_ci		if (pos == NULL)
802e5b75505Sopenharmony_ci			break;
803e5b75505Sopenharmony_ci		start = pos + 19;
804e5b75505Sopenharmony_ci		end = os_strstr(start, "</TNCC-TNCS-Message>");
805e5b75505Sopenharmony_ci		if (end == NULL)
806e5b75505Sopenharmony_ci			break;
807e5b75505Sopenharmony_ci		*end = '\0';
808e5b75505Sopenharmony_ci		endpos = end;
809e5b75505Sopenharmony_ci		end += 20;
810e5b75505Sopenharmony_ci
811e5b75505Sopenharmony_ci		if (tncc_get_type(start, &type) < 0) {
812e5b75505Sopenharmony_ci			*endpos = '<';
813e5b75505Sopenharmony_ci			start = end;
814e5b75505Sopenharmony_ci			continue;
815e5b75505Sopenharmony_ci		}
816e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
817e5b75505Sopenharmony_ci			   type);
818e5b75505Sopenharmony_ci
819e5b75505Sopenharmony_ci		/* Base64 OR XML */
820e5b75505Sopenharmony_ci		decoded = NULL;
821e5b75505Sopenharmony_ci		xml = NULL;
822e5b75505Sopenharmony_ci		xmlend = NULL;
823e5b75505Sopenharmony_ci		pos = os_strstr(start, "<XML>");
824e5b75505Sopenharmony_ci		if (pos) {
825e5b75505Sopenharmony_ci			pos += 5;
826e5b75505Sopenharmony_ci			pos2 = os_strstr(pos, "</XML>");
827e5b75505Sopenharmony_ci			if (pos2 == NULL) {
828e5b75505Sopenharmony_ci				*endpos = '<';
829e5b75505Sopenharmony_ci				start = end;
830e5b75505Sopenharmony_ci				continue;
831e5b75505Sopenharmony_ci			}
832e5b75505Sopenharmony_ci			xmlend = pos2;
833e5b75505Sopenharmony_ci			xml = pos;
834e5b75505Sopenharmony_ci		} else {
835e5b75505Sopenharmony_ci			decoded = tncc_get_base64(start, &decoded_len);
836e5b75505Sopenharmony_ci			if (decoded == NULL) {
837e5b75505Sopenharmony_ci				*endpos = '<';
838e5b75505Sopenharmony_ci				start = end;
839e5b75505Sopenharmony_ci				continue;
840e5b75505Sopenharmony_ci			}
841e5b75505Sopenharmony_ci		}
842e5b75505Sopenharmony_ci
843e5b75505Sopenharmony_ci		if (decoded) {
844e5b75505Sopenharmony_ci			wpa_hexdump_ascii(MSG_MSGDUMP,
845e5b75505Sopenharmony_ci					  "TNC: TNCC-TNCS-Message Base64",
846e5b75505Sopenharmony_ci					  decoded, decoded_len);
847e5b75505Sopenharmony_ci			os_free(decoded);
848e5b75505Sopenharmony_ci		}
849e5b75505Sopenharmony_ci
850e5b75505Sopenharmony_ci		if (xml) {
851e5b75505Sopenharmony_ci			wpa_hexdump_ascii(MSG_MSGDUMP,
852e5b75505Sopenharmony_ci					  "TNC: TNCC-TNCS-Message XML",
853e5b75505Sopenharmony_ci					  (unsigned char *) xml,
854e5b75505Sopenharmony_ci					  xmlend - xml);
855e5b75505Sopenharmony_ci		}
856e5b75505Sopenharmony_ci
857e5b75505Sopenharmony_ci		if (type == TNC_TNCCS_RECOMMENDATION && xml) {
858e5b75505Sopenharmony_ci			/*
859e5b75505Sopenharmony_ci			 * <TNCCS-Recommendation type="allow">
860e5b75505Sopenharmony_ci			 * </TNCCS-Recommendation>
861e5b75505Sopenharmony_ci			 */
862e5b75505Sopenharmony_ci			*xmlend = '\0';
863e5b75505Sopenharmony_ci			res = tncc_get_recommendation(xml);
864e5b75505Sopenharmony_ci			*xmlend = '<';
865e5b75505Sopenharmony_ci			recommendation_msg = 1;
866e5b75505Sopenharmony_ci		}
867e5b75505Sopenharmony_ci
868e5b75505Sopenharmony_ci		start = end;
869e5b75505Sopenharmony_ci	}
870e5b75505Sopenharmony_ci
871e5b75505Sopenharmony_ci	os_free(buf);
872e5b75505Sopenharmony_ci
873e5b75505Sopenharmony_ci	if (recommendation_msg)
874e5b75505Sopenharmony_ci		tncc_notify_recommendation(tncc, res);
875e5b75505Sopenharmony_ci
876e5b75505Sopenharmony_ci	return res;
877e5b75505Sopenharmony_ci}
878e5b75505Sopenharmony_ci
879e5b75505Sopenharmony_ci
880e5b75505Sopenharmony_ci#ifdef CONFIG_NATIVE_WINDOWS
881e5b75505Sopenharmony_cistatic int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
882e5b75505Sopenharmony_ci{
883e5b75505Sopenharmony_ci	HKEY hk, hk2;
884e5b75505Sopenharmony_ci	LONG ret;
885e5b75505Sopenharmony_ci	DWORD i;
886e5b75505Sopenharmony_ci	struct tnc_if_imc *imc, *last;
887e5b75505Sopenharmony_ci	int j;
888e5b75505Sopenharmony_ci
889e5b75505Sopenharmony_ci	last = tncc->imc;
890e5b75505Sopenharmony_ci	while (last && last->next)
891e5b75505Sopenharmony_ci		last = last->next;
892e5b75505Sopenharmony_ci
893e5b75505Sopenharmony_ci	ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
894e5b75505Sopenharmony_ci			   &hk);
895e5b75505Sopenharmony_ci	if (ret != ERROR_SUCCESS)
896e5b75505Sopenharmony_ci		return 0;
897e5b75505Sopenharmony_ci
898e5b75505Sopenharmony_ci	for (i = 0; ; i++) {
899e5b75505Sopenharmony_ci		TCHAR name[255], *val;
900e5b75505Sopenharmony_ci		DWORD namelen, buflen;
901e5b75505Sopenharmony_ci
902e5b75505Sopenharmony_ci		namelen = 255;
903e5b75505Sopenharmony_ci		ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
904e5b75505Sopenharmony_ci				   NULL);
905e5b75505Sopenharmony_ci
906e5b75505Sopenharmony_ci		if (ret == ERROR_NO_MORE_ITEMS)
907e5b75505Sopenharmony_ci			break;
908e5b75505Sopenharmony_ci
909e5b75505Sopenharmony_ci		if (ret != ERROR_SUCCESS) {
910e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
911e5b75505Sopenharmony_ci				   (unsigned int) ret);
912e5b75505Sopenharmony_ci			break;
913e5b75505Sopenharmony_ci		}
914e5b75505Sopenharmony_ci
915e5b75505Sopenharmony_ci		if (namelen >= 255)
916e5b75505Sopenharmony_ci			namelen = 255 - 1;
917e5b75505Sopenharmony_ci		name[namelen] = '\0';
918e5b75505Sopenharmony_ci
919e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
920e5b75505Sopenharmony_ci
921e5b75505Sopenharmony_ci		ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
922e5b75505Sopenharmony_ci		if (ret != ERROR_SUCCESS) {
923e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
924e5b75505Sopenharmony_ci				   "'", name);
925e5b75505Sopenharmony_ci			continue;
926e5b75505Sopenharmony_ci		}
927e5b75505Sopenharmony_ci
928e5b75505Sopenharmony_ci		ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
929e5b75505Sopenharmony_ci				      &buflen);
930e5b75505Sopenharmony_ci		if (ret != ERROR_SUCCESS) {
931e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
932e5b75505Sopenharmony_ci				   "IMC key '" TSTR "'", name);
933e5b75505Sopenharmony_ci			RegCloseKey(hk2);
934e5b75505Sopenharmony_ci			continue;
935e5b75505Sopenharmony_ci		}
936e5b75505Sopenharmony_ci
937e5b75505Sopenharmony_ci		val = os_malloc(buflen);
938e5b75505Sopenharmony_ci		if (val == NULL) {
939e5b75505Sopenharmony_ci			RegCloseKey(hk2);
940e5b75505Sopenharmony_ci			continue;
941e5b75505Sopenharmony_ci		}
942e5b75505Sopenharmony_ci
943e5b75505Sopenharmony_ci		ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
944e5b75505Sopenharmony_ci				      (LPBYTE) val, &buflen);
945e5b75505Sopenharmony_ci		if (ret != ERROR_SUCCESS) {
946e5b75505Sopenharmony_ci			os_free(val);
947e5b75505Sopenharmony_ci			RegCloseKey(hk2);
948e5b75505Sopenharmony_ci			continue;
949e5b75505Sopenharmony_ci		}
950e5b75505Sopenharmony_ci
951e5b75505Sopenharmony_ci		RegCloseKey(hk2);
952e5b75505Sopenharmony_ci
953e5b75505Sopenharmony_ci		wpa_unicode2ascii_inplace(val);
954e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
955e5b75505Sopenharmony_ci
956e5b75505Sopenharmony_ci		for (j = 0; j < TNC_MAX_IMC_ID; j++) {
957e5b75505Sopenharmony_ci			if (tnc_imc[j] == NULL)
958e5b75505Sopenharmony_ci				break;
959e5b75505Sopenharmony_ci		}
960e5b75505Sopenharmony_ci		if (j >= TNC_MAX_IMC_ID) {
961e5b75505Sopenharmony_ci			wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
962e5b75505Sopenharmony_ci			os_free(val);
963e5b75505Sopenharmony_ci			continue;
964e5b75505Sopenharmony_ci		}
965e5b75505Sopenharmony_ci
966e5b75505Sopenharmony_ci		imc = os_zalloc(sizeof(*imc));
967e5b75505Sopenharmony_ci		if (imc == NULL) {
968e5b75505Sopenharmony_ci			os_free(val);
969e5b75505Sopenharmony_ci			break;
970e5b75505Sopenharmony_ci		}
971e5b75505Sopenharmony_ci
972e5b75505Sopenharmony_ci		imc->imcID = j;
973e5b75505Sopenharmony_ci
974e5b75505Sopenharmony_ci		wpa_unicode2ascii_inplace(name);
975e5b75505Sopenharmony_ci		imc->name = os_strdup((char *) name);
976e5b75505Sopenharmony_ci		imc->path = os_strdup((char *) val);
977e5b75505Sopenharmony_ci
978e5b75505Sopenharmony_ci		os_free(val);
979e5b75505Sopenharmony_ci
980e5b75505Sopenharmony_ci		if (last == NULL)
981e5b75505Sopenharmony_ci			tncc->imc = imc;
982e5b75505Sopenharmony_ci		else
983e5b75505Sopenharmony_ci			last->next = imc;
984e5b75505Sopenharmony_ci		last = imc;
985e5b75505Sopenharmony_ci
986e5b75505Sopenharmony_ci		tnc_imc[imc->imcID] = imc;
987e5b75505Sopenharmony_ci	}
988e5b75505Sopenharmony_ci
989e5b75505Sopenharmony_ci	RegCloseKey(hk);
990e5b75505Sopenharmony_ci
991e5b75505Sopenharmony_ci	return 0;
992e5b75505Sopenharmony_ci}
993e5b75505Sopenharmony_ci
994e5b75505Sopenharmony_ci
995e5b75505Sopenharmony_cistatic int tncc_read_config(struct tncc_data *tncc)
996e5b75505Sopenharmony_ci{
997e5b75505Sopenharmony_ci	if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
998e5b75505Sopenharmony_ci	    tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
999e5b75505Sopenharmony_ci		return -1;
1000e5b75505Sopenharmony_ci	return 0;
1001e5b75505Sopenharmony_ci}
1002e5b75505Sopenharmony_ci
1003e5b75505Sopenharmony_ci#else /* CONFIG_NATIVE_WINDOWS */
1004e5b75505Sopenharmony_ci
1005e5b75505Sopenharmony_cistatic struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
1006e5b75505Sopenharmony_ci{
1007e5b75505Sopenharmony_ci	struct tnc_if_imc *imc;
1008e5b75505Sopenharmony_ci	char *pos, *pos2;
1009e5b75505Sopenharmony_ci	int i;
1010e5b75505Sopenharmony_ci
1011e5b75505Sopenharmony_ci	for (i = 0; i < TNC_MAX_IMC_ID; i++) {
1012e5b75505Sopenharmony_ci		if (tnc_imc[i] == NULL)
1013e5b75505Sopenharmony_ci			break;
1014e5b75505Sopenharmony_ci	}
1015e5b75505Sopenharmony_ci	if (i >= TNC_MAX_IMC_ID) {
1016e5b75505Sopenharmony_ci		wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
1017e5b75505Sopenharmony_ci		return NULL;
1018e5b75505Sopenharmony_ci	}
1019e5b75505Sopenharmony_ci
1020e5b75505Sopenharmony_ci	imc = os_zalloc(sizeof(*imc));
1021e5b75505Sopenharmony_ci	if (imc == NULL) {
1022e5b75505Sopenharmony_ci		*error = 1;
1023e5b75505Sopenharmony_ci		return NULL;
1024e5b75505Sopenharmony_ci	}
1025e5b75505Sopenharmony_ci
1026e5b75505Sopenharmony_ci	imc->imcID = i;
1027e5b75505Sopenharmony_ci
1028e5b75505Sopenharmony_ci	pos = start;
1029e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
1030e5b75505Sopenharmony_ci	if (pos + 1 >= end || *pos != '"') {
1031e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1032e5b75505Sopenharmony_ci			   "(no starting quotation mark)", start);
1033e5b75505Sopenharmony_ci		os_free(imc);
1034e5b75505Sopenharmony_ci		return NULL;
1035e5b75505Sopenharmony_ci	}
1036e5b75505Sopenharmony_ci
1037e5b75505Sopenharmony_ci	pos++;
1038e5b75505Sopenharmony_ci	pos2 = pos;
1039e5b75505Sopenharmony_ci	while (pos2 < end && *pos2 != '"')
1040e5b75505Sopenharmony_ci		pos2++;
1041e5b75505Sopenharmony_ci	if (pos2 >= end) {
1042e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1043e5b75505Sopenharmony_ci			   "(no ending quotation mark)", start);
1044e5b75505Sopenharmony_ci		os_free(imc);
1045e5b75505Sopenharmony_ci		return NULL;
1046e5b75505Sopenharmony_ci	}
1047e5b75505Sopenharmony_ci	*pos2 = '\0';
1048e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
1049e5b75505Sopenharmony_ci	imc->name = os_strdup(pos);
1050e5b75505Sopenharmony_ci
1051e5b75505Sopenharmony_ci	pos = pos2 + 1;
1052e5b75505Sopenharmony_ci	if (pos >= end || *pos != ' ') {
1053e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1054e5b75505Sopenharmony_ci			   "(no space after name)", start);
1055e5b75505Sopenharmony_ci		os_free(imc->name);
1056e5b75505Sopenharmony_ci		os_free(imc);
1057e5b75505Sopenharmony_ci		return NULL;
1058e5b75505Sopenharmony_ci	}
1059e5b75505Sopenharmony_ci
1060e5b75505Sopenharmony_ci	pos++;
1061e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
1062e5b75505Sopenharmony_ci	imc->path = os_strdup(pos);
1063e5b75505Sopenharmony_ci	tnc_imc[imc->imcID] = imc;
1064e5b75505Sopenharmony_ci
1065e5b75505Sopenharmony_ci	return imc;
1066e5b75505Sopenharmony_ci}
1067e5b75505Sopenharmony_ci
1068e5b75505Sopenharmony_ci
1069e5b75505Sopenharmony_cistatic int tncc_read_config(struct tncc_data *tncc)
1070e5b75505Sopenharmony_ci{
1071e5b75505Sopenharmony_ci	char *config, *end, *pos, *line_end;
1072e5b75505Sopenharmony_ci	size_t config_len;
1073e5b75505Sopenharmony_ci	struct tnc_if_imc *imc, *last;
1074e5b75505Sopenharmony_ci
1075e5b75505Sopenharmony_ci	last = NULL;
1076e5b75505Sopenharmony_ci
1077e5b75505Sopenharmony_ci	config = os_readfile(TNC_CONFIG_FILE, &config_len);
1078e5b75505Sopenharmony_ci	if (config == NULL) {
1079e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
1080e5b75505Sopenharmony_ci			   "file '%s'", TNC_CONFIG_FILE);
1081e5b75505Sopenharmony_ci		return -1;
1082e5b75505Sopenharmony_ci	}
1083e5b75505Sopenharmony_ci
1084e5b75505Sopenharmony_ci	end = config + config_len;
1085e5b75505Sopenharmony_ci	for (pos = config; pos < end; pos = line_end + 1) {
1086e5b75505Sopenharmony_ci		line_end = pos;
1087e5b75505Sopenharmony_ci		while (*line_end != '\n' && *line_end != '\r' &&
1088e5b75505Sopenharmony_ci		       line_end < end)
1089e5b75505Sopenharmony_ci			line_end++;
1090e5b75505Sopenharmony_ci		*line_end = '\0';
1091e5b75505Sopenharmony_ci
1092e5b75505Sopenharmony_ci		if (os_strncmp(pos, "IMC ", 4) == 0) {
1093e5b75505Sopenharmony_ci			int error = 0;
1094e5b75505Sopenharmony_ci
1095e5b75505Sopenharmony_ci			imc = tncc_parse_imc(pos + 4, line_end, &error);
1096e5b75505Sopenharmony_ci			if (error) {
1097e5b75505Sopenharmony_ci				os_free(config);
1098e5b75505Sopenharmony_ci				return -1;
1099e5b75505Sopenharmony_ci			}
1100e5b75505Sopenharmony_ci			if (imc) {
1101e5b75505Sopenharmony_ci				if (last == NULL)
1102e5b75505Sopenharmony_ci					tncc->imc = imc;
1103e5b75505Sopenharmony_ci				else
1104e5b75505Sopenharmony_ci					last->next = imc;
1105e5b75505Sopenharmony_ci				last = imc;
1106e5b75505Sopenharmony_ci			}
1107e5b75505Sopenharmony_ci		}
1108e5b75505Sopenharmony_ci	}
1109e5b75505Sopenharmony_ci
1110e5b75505Sopenharmony_ci	os_free(config);
1111e5b75505Sopenharmony_ci
1112e5b75505Sopenharmony_ci	return 0;
1113e5b75505Sopenharmony_ci}
1114e5b75505Sopenharmony_ci
1115e5b75505Sopenharmony_ci#endif /* CONFIG_NATIVE_WINDOWS */
1116e5b75505Sopenharmony_ci
1117e5b75505Sopenharmony_ci
1118e5b75505Sopenharmony_cistruct tncc_data * tncc_init(void)
1119e5b75505Sopenharmony_ci{
1120e5b75505Sopenharmony_ci	struct tncc_data *tncc;
1121e5b75505Sopenharmony_ci	struct tnc_if_imc *imc;
1122e5b75505Sopenharmony_ci
1123e5b75505Sopenharmony_ci	tncc = os_zalloc(sizeof(*tncc));
1124e5b75505Sopenharmony_ci	if (tncc == NULL)
1125e5b75505Sopenharmony_ci		return NULL;
1126e5b75505Sopenharmony_ci
1127e5b75505Sopenharmony_ci	/* TODO:
1128e5b75505Sopenharmony_ci	 * move loading and Initialize() to a location that is not
1129e5b75505Sopenharmony_ci	 *    re-initialized for every EAP-TNC session (?)
1130e5b75505Sopenharmony_ci	 */
1131e5b75505Sopenharmony_ci
1132e5b75505Sopenharmony_ci	if (tncc_read_config(tncc) < 0) {
1133e5b75505Sopenharmony_ci		wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
1134e5b75505Sopenharmony_ci		goto failed;
1135e5b75505Sopenharmony_ci	}
1136e5b75505Sopenharmony_ci
1137e5b75505Sopenharmony_ci	for (imc = tncc->imc; imc; imc = imc->next) {
1138e5b75505Sopenharmony_ci		if (tncc_load_imc(imc)) {
1139e5b75505Sopenharmony_ci			wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
1140e5b75505Sopenharmony_ci				   imc->name);
1141e5b75505Sopenharmony_ci			goto failed;
1142e5b75505Sopenharmony_ci		}
1143e5b75505Sopenharmony_ci	}
1144e5b75505Sopenharmony_ci
1145e5b75505Sopenharmony_ci	return tncc;
1146e5b75505Sopenharmony_ci
1147e5b75505Sopenharmony_cifailed:
1148e5b75505Sopenharmony_ci	tncc_deinit(tncc);
1149e5b75505Sopenharmony_ci	return NULL;
1150e5b75505Sopenharmony_ci}
1151e5b75505Sopenharmony_ci
1152e5b75505Sopenharmony_ci
1153e5b75505Sopenharmony_civoid tncc_deinit(struct tncc_data *tncc)
1154e5b75505Sopenharmony_ci{
1155e5b75505Sopenharmony_ci	struct tnc_if_imc *imc, *prev;
1156e5b75505Sopenharmony_ci
1157e5b75505Sopenharmony_ci	imc = tncc->imc;
1158e5b75505Sopenharmony_ci	while (imc) {
1159e5b75505Sopenharmony_ci		tncc_unload_imc(imc);
1160e5b75505Sopenharmony_ci
1161e5b75505Sopenharmony_ci		prev = imc;
1162e5b75505Sopenharmony_ci		imc = imc->next;
1163e5b75505Sopenharmony_ci		os_free(prev);
1164e5b75505Sopenharmony_ci	}
1165e5b75505Sopenharmony_ci
1166e5b75505Sopenharmony_ci	os_free(tncc);
1167e5b75505Sopenharmony_ci}
1168e5b75505Sopenharmony_ci
1169e5b75505Sopenharmony_ci
1170e5b75505Sopenharmony_cistatic struct wpabuf * tncc_build_soh(int ver)
1171e5b75505Sopenharmony_ci{
1172e5b75505Sopenharmony_ci	struct wpabuf *buf;
1173e5b75505Sopenharmony_ci	u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
1174e5b75505Sopenharmony_ci	u8 correlation_id[24];
1175e5b75505Sopenharmony_ci	/* TODO: get correct name */
1176e5b75505Sopenharmony_ci	char *machinename = "wpa_supplicant@w1.fi";
1177e5b75505Sopenharmony_ci
1178e5b75505Sopenharmony_ci	if (os_get_random(correlation_id, sizeof(correlation_id)))
1179e5b75505Sopenharmony_ci		return NULL;
1180e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
1181e5b75505Sopenharmony_ci		    correlation_id, sizeof(correlation_id));
1182e5b75505Sopenharmony_ci
1183e5b75505Sopenharmony_ci	buf = wpabuf_alloc(200);
1184e5b75505Sopenharmony_ci	if (buf == NULL)
1185e5b75505Sopenharmony_ci		return NULL;
1186e5b75505Sopenharmony_ci
1187e5b75505Sopenharmony_ci	/* Vendor-Specific TLV (Microsoft) - SoH */
1188e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
1189e5b75505Sopenharmony_ci	tlv_len = wpabuf_put(buf, 2); /* Length */
1190e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
1191e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
1192e5b75505Sopenharmony_ci	tlv_len2 = wpabuf_put(buf, 2); /* Length */
1193e5b75505Sopenharmony_ci
1194e5b75505Sopenharmony_ci	/* SoH Header */
1195e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
1196e5b75505Sopenharmony_ci	outer_len = wpabuf_put(buf, 2);
1197e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1198e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, ver); /* Inner Type */
1199e5b75505Sopenharmony_ci	inner_len = wpabuf_put(buf, 2);
1200e5b75505Sopenharmony_ci
1201e5b75505Sopenharmony_ci	if (ver == 2) {
1202e5b75505Sopenharmony_ci		/* SoH Mode Sub-Header */
1203e5b75505Sopenharmony_ci		/* Outer Type */
1204e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
1205e5b75505Sopenharmony_ci		wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
1206e5b75505Sopenharmony_ci		wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1207e5b75505Sopenharmony_ci		/* Value: */
1208e5b75505Sopenharmony_ci		wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
1209e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
1210e5b75505Sopenharmony_ci		wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
1211e5b75505Sopenharmony_ci	}
1212e5b75505Sopenharmony_ci
1213e5b75505Sopenharmony_ci	/* SSoH TLV */
1214e5b75505Sopenharmony_ci	/* System-Health-Id */
1215e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, 0x0002); /* Type */
1216e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, 4); /* Length */
1217e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, 79616);
1218e5b75505Sopenharmony_ci	/* Vendor-Specific Attribute */
1219e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
1220e5b75505Sopenharmony_ci	ssoh_len = wpabuf_put(buf, 2);
1221e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1222e5b75505Sopenharmony_ci
1223e5b75505Sopenharmony_ci	/* MS-Packet-Info */
1224e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO);
1225e5b75505Sopenharmony_ci	/* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be:
1226e5b75505Sopenharmony_ci	 * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP
1227e5b75505Sopenharmony_ci	 * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit
1228e5b75505Sopenharmony_ci	 * would not be in the specified location.
1229e5b75505Sopenharmony_ci	 * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits)
1230e5b75505Sopenharmony_ci	 */
1231e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
1232e5b75505Sopenharmony_ci
1233e5b75505Sopenharmony_ci	/* MS-Machine-Inventory */
1234e5b75505Sopenharmony_ci	/* TODO: get correct values; 0 = not applicable for OS */
1235e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY);
1236e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, 0); /* osVersionMajor */
1237e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, 0); /* osVersionMinor */
1238e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, 0); /* osVersionBuild */
1239e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, 0); /* spVersionMajor */
1240e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, 0); /* spVersionMinor */
1241e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, 0); /* procArch */
1242e5b75505Sopenharmony_ci
1243e5b75505Sopenharmony_ci	/* MS-MachineName */
1244e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, SSOH_MS_MACHINENAME);
1245e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, os_strlen(machinename) + 1);
1246e5b75505Sopenharmony_ci	wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1);
1247e5b75505Sopenharmony_ci
1248e5b75505Sopenharmony_ci	/* MS-CorrelationId */
1249e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID);
1250e5b75505Sopenharmony_ci	wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
1251e5b75505Sopenharmony_ci
1252e5b75505Sopenharmony_ci	/* MS-Quarantine-State */
1253e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE);
1254e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */
1255e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */
1256e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */
1257e5b75505Sopenharmony_ci	wpabuf_put_be16(buf, 1); /* urlLenInBytes */
1258e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 0); /* null termination for the url */
1259e5b75505Sopenharmony_ci
1260e5b75505Sopenharmony_ci	/* MS-Machine-Inventory-Ex */
1261e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX);
1262e5b75505Sopenharmony_ci	wpabuf_put_be32(buf, 0); /* Reserved
1263e5b75505Sopenharmony_ci				  * (note: Windows XP SP3 uses 0xdecafbad) */
1264e5b75505Sopenharmony_ci	wpabuf_put_u8(buf, 1); /* ProductType: Client */
1265e5b75505Sopenharmony_ci
1266e5b75505Sopenharmony_ci	/* Update SSoH Length */
1267e5b75505Sopenharmony_ci	end = wpabuf_put(buf, 0);
1268e5b75505Sopenharmony_ci	WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
1269e5b75505Sopenharmony_ci
1270e5b75505Sopenharmony_ci	/* TODO: SoHReportEntry TLV (zero or more) */
1271e5b75505Sopenharmony_ci
1272e5b75505Sopenharmony_ci	/* Update length fields */
1273e5b75505Sopenharmony_ci	end = wpabuf_put(buf, 0);
1274e5b75505Sopenharmony_ci	WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
1275e5b75505Sopenharmony_ci	WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
1276e5b75505Sopenharmony_ci	WPA_PUT_BE16(outer_len, end - outer_len - 2);
1277e5b75505Sopenharmony_ci	WPA_PUT_BE16(inner_len, end - inner_len - 2);
1278e5b75505Sopenharmony_ci
1279e5b75505Sopenharmony_ci	return buf;
1280e5b75505Sopenharmony_ci}
1281e5b75505Sopenharmony_ci
1282e5b75505Sopenharmony_ci
1283e5b75505Sopenharmony_cistruct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len)
1284e5b75505Sopenharmony_ci{
1285e5b75505Sopenharmony_ci	const u8 *pos;
1286e5b75505Sopenharmony_ci
1287e5b75505Sopenharmony_ci	wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
1288e5b75505Sopenharmony_ci
1289e5b75505Sopenharmony_ci	if (len < 12)
1290e5b75505Sopenharmony_ci		return NULL;
1291e5b75505Sopenharmony_ci
1292e5b75505Sopenharmony_ci	/* SoH Request */
1293e5b75505Sopenharmony_ci	pos = data;
1294e5b75505Sopenharmony_ci
1295e5b75505Sopenharmony_ci	/* TLV Type */
1296e5b75505Sopenharmony_ci	if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
1297e5b75505Sopenharmony_ci		return NULL;
1298e5b75505Sopenharmony_ci	pos += 2;
1299e5b75505Sopenharmony_ci
1300e5b75505Sopenharmony_ci	/* Length */
1301e5b75505Sopenharmony_ci	if (WPA_GET_BE16(pos) < 8)
1302e5b75505Sopenharmony_ci		return NULL;
1303e5b75505Sopenharmony_ci	pos += 2;
1304e5b75505Sopenharmony_ci
1305e5b75505Sopenharmony_ci	/* Vendor_Id */
1306e5b75505Sopenharmony_ci	if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
1307e5b75505Sopenharmony_ci		return NULL;
1308e5b75505Sopenharmony_ci	pos += 4;
1309e5b75505Sopenharmony_ci
1310e5b75505Sopenharmony_ci	/* TLV Type */
1311e5b75505Sopenharmony_ci	if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
1312e5b75505Sopenharmony_ci		return NULL;
1313e5b75505Sopenharmony_ci
1314e5b75505Sopenharmony_ci	wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
1315e5b75505Sopenharmony_ci
1316e5b75505Sopenharmony_ci	return tncc_build_soh(2);
1317e5b75505Sopenharmony_ci}
1318