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