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