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