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