12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319 |
- /*
- * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
- #include "includes.h"
- #ifndef CONFIG_NATIVE_WINDOWS
- #include <dlfcn.h>
- #endif /* CONFIG_NATIVE_WINDOWS */
- #include "common.h"
- #include "base64.h"
- #include "tncc.h"
- #include "eap_common/eap_tlv_common.h"
- #include "eap_common/eap_defs.h"
- #ifdef UNICODE
- #define TSTR "%S"
- #else /* UNICODE */
- #define TSTR "%s"
- #endif /* UNICODE */
- #define TNC_CONFIG_FILE "/etc/tnc_config"
- #define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
- #define IF_TNCCS_START \
- "<?xml version=\"1.0\"?>\n" \
- "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
- "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
- "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
- "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
- "IF_TNCCS#https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
- #define IF_TNCCS_END "\n</TNCCS-Batch>"
- /* TNC IF-IMC */
- typedef unsigned long TNC_UInt32;
- typedef unsigned char *TNC_BufferReference;
- typedef TNC_UInt32 TNC_IMCID;
- typedef TNC_UInt32 TNC_ConnectionID;
- typedef TNC_UInt32 TNC_ConnectionState;
- typedef TNC_UInt32 TNC_RetryReason;
- typedef TNC_UInt32 TNC_MessageType;
- typedef TNC_MessageType *TNC_MessageTypeList;
- typedef TNC_UInt32 TNC_VendorID;
- typedef TNC_UInt32 TNC_MessageSubtype;
- typedef TNC_UInt32 TNC_Version;
- typedef TNC_UInt32 TNC_Result;
- typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)(
- TNC_IMCID imcID,
- char *functionName,
- void **pOutfunctionPointer);
- #define TNC_RESULT_SUCCESS 0
- #define TNC_RESULT_NOT_INITIALIZED 1
- #define TNC_RESULT_ALREADY_INITIALIZED 2
- #define TNC_RESULT_NO_COMMON_VERSION 3
- #define TNC_RESULT_CANT_RETRY 4
- #define TNC_RESULT_WONT_RETRY 5
- #define TNC_RESULT_INVALID_PARAMETER 6
- #define TNC_RESULT_CANT_RESPOND 7
- #define TNC_RESULT_ILLEGAL_OPERATION 8
- #define TNC_RESULT_OTHER 9
- #define TNC_RESULT_FATAL 10
- #define TNC_CONNECTION_STATE_CREATE 0
- #define TNC_CONNECTION_STATE_HANDSHAKE 1
- #define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
- #define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
- #define TNC_CONNECTION_STATE_ACCESS_NONE 4
- #define TNC_CONNECTION_STATE_DELETE 5
- #define TNC_IFIMC_VERSION_1 1
- #define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
- #define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff)
- /* TNCC-TNCS Message Types */
- #define TNC_TNCCS_RECOMMENDATION 0x00000001
- #define TNC_TNCCS_ERROR 0x00000002
- #define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003
- #define TNC_TNCCS_REASONSTRINGS 0x00000004
- struct tnc_if_imc {
- struct tnc_if_imc *next;
- char *name;
- char *path;
- void *dlhandle; /* from dlopen() */
- TNC_IMCID imcID;
- TNC_ConnectionID connectionID;
- TNC_MessageTypeList supported_types;
- size_t num_supported_types;
- u8 *imc_send;
- size_t imc_send_len;
- /* Functions implemented by IMCs (with TNC_IMC_ prefix) */
- TNC_Result (*Initialize)(
- TNC_IMCID imcID,
- TNC_Version minVersion,
- TNC_Version maxVersion,
- TNC_Version *pOutActualVersion);
- TNC_Result (*NotifyConnectionChange)(
- TNC_IMCID imcID,
- TNC_ConnectionID connectionID,
- TNC_ConnectionState newState);
- TNC_Result (*BeginHandshake)(
- TNC_IMCID imcID,
- TNC_ConnectionID connectionID);
- TNC_Result (*ReceiveMessage)(
- TNC_IMCID imcID,
- TNC_ConnectionID connectionID,
- TNC_BufferReference messageBuffer,
- TNC_UInt32 messageLength,
- TNC_MessageType messageType);
- TNC_Result (*BatchEnding)(
- TNC_IMCID imcID,
- TNC_ConnectionID connectionID);
- TNC_Result (*Terminate)(TNC_IMCID imcID);
- TNC_Result (*ProvideBindFunction)(
- TNC_IMCID imcID,
- TNC_TNCC_BindFunctionPointer bindFunction);
- };
- struct tncc_data {
- struct tnc_if_imc *imc;
- unsigned int last_batchid;
- };
- #define TNC_MAX_IMC_ID 10
- static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
- /* TNCC functions that IMCs can call */
- TNC_Result TNC_TNCC_ReportMessageTypes(
- TNC_IMCID imcID,
- TNC_MessageTypeList supportedTypes,
- TNC_UInt32 typeCount)
- {
- TNC_UInt32 i;
- struct tnc_if_imc *imc;
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
- "typeCount=%lu)",
- (unsigned long) imcID, (unsigned long) typeCount);
- for (i = 0; i < typeCount; i++) {
- wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
- i, supportedTypes[i]);
- }
- if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- imc = tnc_imc[imcID];
- os_free(imc->supported_types);
- imc->supported_types =
- os_malloc(typeCount * sizeof(TNC_MessageTypeList));
- if (imc->supported_types == NULL)
- return TNC_RESULT_FATAL;
- os_memcpy(imc->supported_types, supportedTypes,
- typeCount * sizeof(TNC_MessageTypeList));
- imc->num_supported_types = typeCount;
- return TNC_RESULT_SUCCESS;
- }
- TNC_Result TNC_TNCC_SendMessage(
- TNC_IMCID imcID,
- TNC_ConnectionID connectionID,
- TNC_BufferReference message,
- TNC_UInt32 messageLength,
- TNC_MessageType messageType)
- {
- struct tnc_if_imc *imc;
- unsigned char *b64;
- size_t b64len;
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
- "connectionID=%lu messageType=%lu)",
- imcID, connectionID, messageType);
- wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
- message, messageLength);
- if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- b64 = base64_encode(message, messageLength, &b64len);
- if (b64 == NULL)
- return TNC_RESULT_FATAL;
- imc = tnc_imc[imcID];
- os_free(imc->imc_send);
- imc->imc_send_len = 0;
- imc->imc_send = os_zalloc(b64len + 100);
- if (imc->imc_send == NULL) {
- os_free(b64);
- return TNC_RESULT_OTHER;
- }
- imc->imc_send_len =
- os_snprintf((char *) imc->imc_send, b64len + 100,
- "<IMC-IMV-Message><Type>%08X</Type>"
- "<Base64>%s</Base64></IMC-IMV-Message>",
- (unsigned int) messageType, b64);
- os_free(b64);
- return TNC_RESULT_SUCCESS;
- }
- TNC_Result TNC_TNCC_RequestHandshakeRetry(
- TNC_IMCID imcID,
- TNC_ConnectionID connectionID,
- TNC_RetryReason reason)
- {
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
- if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- /*
- * TODO: trigger a call to eapol_sm_request_reauth(). This would
- * require that the IMC continues to be loaded in memory afer
- * authentication..
- */
- return TNC_RESULT_SUCCESS;
- }
- TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
- const char *message)
- {
- wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
- "severity==%lu message='%s')",
- imcID, severity, message);
- return TNC_RESULT_SUCCESS;
- }
- TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID,
- const char *message)
- {
- wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
- "connectionID==%lu message='%s')",
- imcID, connectionID, message);
- return TNC_RESULT_SUCCESS;
- }
- TNC_Result TNC_TNCC_BindFunction(
- TNC_IMCID imcID,
- char *functionName,
- void **pOutfunctionPointer)
- {
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
- "functionName='%s')", (unsigned long) imcID, functionName);
- if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- if (pOutfunctionPointer == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
- *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
- else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
- *pOutfunctionPointer = TNC_TNCC_SendMessage;
- else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
- 0)
- *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
- else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
- *pOutfunctionPointer = TNC_9048_LogMessage;
- else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
- *pOutfunctionPointer = TNC_9048_UserMessage;
- else
- *pOutfunctionPointer = NULL;
- return TNC_RESULT_SUCCESS;
- }
- static void * tncc_get_sym(void *handle, char *func)
- {
- void *fptr;
- #ifdef CONFIG_NATIVE_WINDOWS
- #ifdef _WIN32_WCE
- fptr = GetProcAddressA(handle, func);
- #else /* _WIN32_WCE */
- fptr = GetProcAddress(handle, func);
- #endif /* _WIN32_WCE */
- #else /* CONFIG_NATIVE_WINDOWS */
- fptr = dlsym(handle, func);
- #endif /* CONFIG_NATIVE_WINDOWS */
- return fptr;
- }
- static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
- {
- void *handle = imc->dlhandle;
- /* Mandatory IMC functions */
- imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
- if (imc->Initialize == NULL) {
- wpa_printf(MSG_ERROR, "TNC: IMC does not export "
- "TNC_IMC_Initialize");
- return -1;
- }
- imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
- if (imc->BeginHandshake == NULL) {
- wpa_printf(MSG_ERROR, "TNC: IMC does not export "
- "TNC_IMC_BeginHandshake");
- return -1;
- }
- imc->ProvideBindFunction =
- tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
- if (imc->ProvideBindFunction == NULL) {
- wpa_printf(MSG_ERROR, "TNC: IMC does not export "
- "TNC_IMC_ProvideBindFunction");
- return -1;
- }
- /* Optional IMC functions */
- imc->NotifyConnectionChange =
- tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
- imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
- imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
- imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
- return 0;
- }
- static int tncc_imc_initialize(struct tnc_if_imc *imc)
- {
- TNC_Result res;
- TNC_Version imc_ver;
- wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
- imc->name);
- res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
- TNC_IFIMC_VERSION_1, &imc_ver);
- wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
- (unsigned long) res, (unsigned long) imc_ver);
- return res == TNC_RESULT_SUCCESS ? 0 : -1;
- }
- static int tncc_imc_terminate(struct tnc_if_imc *imc)
- {
- TNC_Result res;
- if (imc->Terminate == NULL)
- return 0;
- wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
- imc->name);
- res = imc->Terminate(imc->imcID);
- wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
- (unsigned long) res);
- return res == TNC_RESULT_SUCCESS ? 0 : -1;
- }
- static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
- {
- TNC_Result res;
- wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
- "IMC '%s'", imc->name);
- res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
- wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
- (unsigned long) res);
- return res == TNC_RESULT_SUCCESS ? 0 : -1;
- }
- static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
- TNC_ConnectionState state)
- {
- TNC_Result res;
- if (imc->NotifyConnectionChange == NULL)
- return 0;
- wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
- " for IMC '%s'", (int) state, imc->name);
- res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
- state);
- wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
- (unsigned long) res);
- return res == TNC_RESULT_SUCCESS ? 0 : -1;
- }
- static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
- {
- TNC_Result res;
- wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
- "'%s'", imc->name);
- res = imc->BeginHandshake(imc->imcID, imc->connectionID);
- wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
- (unsigned long) res);
- return res == TNC_RESULT_SUCCESS ? 0 : -1;
- }
- static int tncc_load_imc(struct tnc_if_imc *imc)
- {
- if (imc->path == NULL) {
- wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
- imc->name, imc->path);
- #ifdef CONFIG_NATIVE_WINDOWS
- #ifdef UNICODE
- {
- TCHAR *lib = wpa_strdup_tchar(imc->path);
- if (lib == NULL)
- return -1;
- imc->dlhandle = LoadLibrary(lib);
- os_free(lib);
- }
- #else /* UNICODE */
- imc->dlhandle = LoadLibrary(imc->path);
- #endif /* UNICODE */
- if (imc->dlhandle == NULL) {
- wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
- imc->name, imc->path, (int) GetLastError());
- return -1;
- }
- #else /* CONFIG_NATIVE_WINDOWS */
- imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
- if (imc->dlhandle == NULL) {
- wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
- imc->name, imc->path, dlerror());
- return -1;
- }
- #endif /* CONFIG_NATIVE_WINDOWS */
- if (tncc_imc_resolve_funcs(imc) < 0) {
- wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
- return -1;
- }
- if (tncc_imc_initialize(imc) < 0 ||
- tncc_imc_provide_bind_function(imc) < 0) {
- wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
- return -1;
- }
- return 0;
- }
- static void tncc_unload_imc(struct tnc_if_imc *imc)
- {
- tncc_imc_terminate(imc);
- tnc_imc[imc->imcID] = NULL;
- if (imc->dlhandle) {
- #ifdef CONFIG_NATIVE_WINDOWS
- FreeLibrary(imc->dlhandle);
- #else /* CONFIG_NATIVE_WINDOWS */
- dlclose(imc->dlhandle);
- #endif /* CONFIG_NATIVE_WINDOWS */
- }
- os_free(imc->name);
- os_free(imc->path);
- os_free(imc->supported_types);
- os_free(imc->imc_send);
- }
- static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
- {
- size_t i;
- unsigned int vendor, subtype;
- if (imc == NULL || imc->supported_types == NULL)
- return 0;
- vendor = type >> 8;
- subtype = type & 0xff;
- for (i = 0; i < imc->num_supported_types; i++) {
- unsigned int svendor, ssubtype;
- svendor = imc->supported_types[i] >> 8;
- ssubtype = imc->supported_types[i] & 0xff;
- if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
- (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
- return 1;
- }
- return 0;
- }
- static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
- const u8 *msg, size_t len)
- {
- struct tnc_if_imc *imc;
- TNC_Result res;
- wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
- for (imc = tncc->imc; imc; imc = imc->next) {
- if (imc->ReceiveMessage == NULL ||
- !tncc_supported_type(imc, type))
- continue;
- wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
- imc->name);
- res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
- (TNC_BufferReference) msg, len,
- type);
- wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
- (unsigned long) res);
- }
- }
- void tncc_init_connection(struct tncc_data *tncc)
- {
- struct tnc_if_imc *imc;
- for (imc = tncc->imc; imc; imc = imc->next) {
- tncc_imc_notify_connection_change(
- imc, TNC_CONNECTION_STATE_CREATE);
- tncc_imc_notify_connection_change(
- imc, TNC_CONNECTION_STATE_HANDSHAKE);
- os_free(imc->imc_send);
- imc->imc_send = NULL;
- imc->imc_send_len = 0;
- tncc_imc_begin_handshake(imc);
- }
- }
- size_t tncc_total_send_len(struct tncc_data *tncc)
- {
- struct tnc_if_imc *imc;
- size_t len = 0;
- for (imc = tncc->imc; imc; imc = imc->next)
- len += imc->imc_send_len;
- return len;
- }
- u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
- {
- struct tnc_if_imc *imc;
- for (imc = tncc->imc; imc; imc = imc->next) {
- if (imc->imc_send == NULL)
- continue;
- os_memcpy(pos, imc->imc_send, imc->imc_send_len);
- pos += imc->imc_send_len;
- os_free(imc->imc_send);
- imc->imc_send = NULL;
- imc->imc_send_len = 0;
- }
- return pos;
- }
- char * tncc_if_tnccs_start(struct tncc_data *tncc)
- {
- char *buf = os_malloc(1000);
- if (buf == NULL)
- return NULL;
- tncc->last_batchid++;
- os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
- return buf;
- }
- char * tncc_if_tnccs_end(void)
- {
- char *buf = os_malloc(100);
- if (buf == NULL)
- return NULL;
- os_snprintf(buf, 100, IF_TNCCS_END);
- return buf;
- }
- static void tncc_notify_recommendation(struct tncc_data *tncc,
- enum tncc_process_res res)
- {
- TNC_ConnectionState state;
- struct tnc_if_imc *imc;
- switch (res) {
- case TNCCS_RECOMMENDATION_ALLOW:
- state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
- break;
- case TNCCS_RECOMMENDATION_NONE:
- state = TNC_CONNECTION_STATE_ACCESS_NONE;
- break;
- case TNCCS_RECOMMENDATION_ISOLATE:
- state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
- break;
- default:
- state = TNC_CONNECTION_STATE_ACCESS_NONE;
- break;
- }
- for (imc = tncc->imc; imc; imc = imc->next)
- tncc_imc_notify_connection_change(imc, state);
- }
- static int tncc_get_type(char *start, unsigned int *type)
- {
- char *pos = os_strstr(start, "<Type>");
- if (pos == NULL)
- return -1;
- pos += 6;
- *type = strtoul(pos, NULL, 16);
- return 0;
- }
- static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
- {
- char *pos, *pos2;
- unsigned char *decoded;
- pos = os_strstr(start, "<Base64>");
- if (pos == NULL)
- return NULL;
- pos += 8;
- pos2 = os_strstr(pos, "</Base64>");
- if (pos2 == NULL)
- return NULL;
- *pos2 = '\0';
- decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
- decoded_len);
- *pos2 = '<';
- if (decoded == NULL) {
- wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
- }
- return decoded;
- }
- static enum tncc_process_res tncc_get_recommendation(char *start)
- {
- char *pos, *pos2, saved;
- int recom;
- pos = os_strstr(start, "<TNCCS-Recommendation ");
- if (pos == NULL)
- return TNCCS_RECOMMENDATION_ERROR;
- pos += 21;
- pos = os_strstr(pos, " type=");
- if (pos == NULL)
- return TNCCS_RECOMMENDATION_ERROR;
- pos += 6;
- if (*pos == '"')
- pos++;
- pos2 = pos;
- while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
- pos2++;
- if (*pos2 == '\0')
- return TNCCS_RECOMMENDATION_ERROR;
- saved = *pos2;
- *pos2 = '\0';
- wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
- recom = TNCCS_RECOMMENDATION_ERROR;
- if (os_strcmp(pos, "allow") == 0)
- recom = TNCCS_RECOMMENDATION_ALLOW;
- else if (os_strcmp(pos, "none") == 0)
- recom = TNCCS_RECOMMENDATION_NONE;
- else if (os_strcmp(pos, "isolate") == 0)
- recom = TNCCS_RECOMMENDATION_ISOLATE;
- *pos2 = saved;
- return recom;
- }
- enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
- const u8 *msg, size_t len)
- {
- char *buf, *start, *end, *pos, *pos2, *payload;
- unsigned int batch_id;
- unsigned char *decoded;
- size_t decoded_len;
- enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
- int recommendation_msg = 0;
- buf = os_malloc(len + 1);
- if (buf == NULL)
- return TNCCS_PROCESS_ERROR;
- os_memcpy(buf, msg, len);
- buf[len] = '\0';
- start = os_strstr(buf, "<TNCCS-Batch ");
- end = os_strstr(buf, "</TNCCS-Batch>");
- if (start == NULL || end == NULL || start > end) {
- os_free(buf);
- return TNCCS_PROCESS_ERROR;
- }
- start += 13;
- while (*start == ' ')
- start++;
- *end = '\0';
- pos = os_strstr(start, "BatchId=");
- if (pos == NULL) {
- os_free(buf);
- return TNCCS_PROCESS_ERROR;
- }
- pos += 8;
- if (*pos == '"')
- pos++;
- batch_id = atoi(pos);
- wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
- batch_id);
- if (batch_id != tncc->last_batchid + 1) {
- wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
- "%u (expected %u)",
- batch_id, tncc->last_batchid + 1);
- os_free(buf);
- return TNCCS_PROCESS_ERROR;
- }
- tncc->last_batchid = batch_id;
- while (*pos != '\0' && *pos != '>')
- pos++;
- if (*pos == '\0') {
- os_free(buf);
- return TNCCS_PROCESS_ERROR;
- }
- pos++;
- payload = start;
- /*
- * <IMC-IMV-Message>
- * <Type>01234567</Type>
- * <Base64>foo==</Base64>
- * </IMC-IMV-Message>
- */
- while (*start) {
- char *endpos;
- unsigned int type;
- pos = os_strstr(start, "<IMC-IMV-Message>");
- if (pos == NULL)
- break;
- start = pos + 17;
- end = os_strstr(start, "</IMC-IMV-Message>");
- if (end == NULL)
- break;
- *end = '\0';
- endpos = end;
- end += 18;
- if (tncc_get_type(start, &type) < 0) {
- *endpos = '<';
- start = end;
- continue;
- }
- wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
- decoded = tncc_get_base64(start, &decoded_len);
- if (decoded == NULL) {
- *endpos = '<';
- start = end;
- continue;
- }
- tncc_send_to_imcs(tncc, type, decoded, decoded_len);
- os_free(decoded);
- start = end;
- }
- /*
- * <TNCC-TNCS-Message>
- * <Type>01234567</Type>
- * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
- * <Base64>foo==</Base64>
- * </TNCC-TNCS-Message>
- */
- start = payload;
- while (*start) {
- unsigned int type;
- char *xml, *xmlend, *endpos;
- pos = os_strstr(start, "<TNCC-TNCS-Message>");
- if (pos == NULL)
- break;
- start = pos + 19;
- end = os_strstr(start, "</TNCC-TNCS-Message>");
- if (end == NULL)
- break;
- *end = '\0';
- endpos = end;
- end += 20;
- if (tncc_get_type(start, &type) < 0) {
- *endpos = '<';
- start = end;
- continue;
- }
- wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
- type);
- /* Base64 OR XML */
- decoded = NULL;
- xml = NULL;
- xmlend = NULL;
- pos = os_strstr(start, "<XML>");
- if (pos) {
- pos += 5;
- pos2 = os_strstr(pos, "</XML>");
- if (pos2 == NULL) {
- *endpos = '<';
- start = end;
- continue;
- }
- xmlend = pos2;
- xml = pos;
- } else {
- decoded = tncc_get_base64(start, &decoded_len);
- if (decoded == NULL) {
- *endpos = '<';
- start = end;
- continue;
- }
- }
- if (decoded) {
- wpa_hexdump_ascii(MSG_MSGDUMP,
- "TNC: TNCC-TNCS-Message Base64",
- decoded, decoded_len);
- os_free(decoded);
- }
- if (xml) {
- wpa_hexdump_ascii(MSG_MSGDUMP,
- "TNC: TNCC-TNCS-Message XML",
- (unsigned char *) xml,
- xmlend - xml);
- }
- if (type == TNC_TNCCS_RECOMMENDATION && xml) {
- /*
- * <TNCCS-Recommendation type="allow">
- * </TNCCS-Recommendation>
- */
- *xmlend = '\0';
- res = tncc_get_recommendation(xml);
- *xmlend = '<';
- recommendation_msg = 1;
- }
- start = end;
- }
- os_free(buf);
- if (recommendation_msg)
- tncc_notify_recommendation(tncc, res);
- return res;
- }
- #ifdef CONFIG_NATIVE_WINDOWS
- static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
- {
- HKEY hk, hk2;
- LONG ret;
- DWORD i;
- struct tnc_if_imc *imc, *last;
- int j;
- last = tncc->imc;
- while (last && last->next)
- last = last->next;
- ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
- &hk);
- if (ret != ERROR_SUCCESS)
- return 0;
- for (i = 0; ; i++) {
- TCHAR name[255], *val;
- DWORD namelen, buflen;
- namelen = 255;
- ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
- NULL);
- if (ret == ERROR_NO_MORE_ITEMS)
- break;
- if (ret != ERROR_SUCCESS) {
- wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
- (unsigned int) ret);
- break;
- }
- if (namelen >= 255)
- namelen = 255 - 1;
- name[namelen] = '\0';
- wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
- ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
- if (ret != ERROR_SUCCESS) {
- wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
- "'", name);
- continue;
- }
- ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
- &buflen);
- if (ret != ERROR_SUCCESS) {
- wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
- "IMC key '" TSTR "'", name);
- RegCloseKey(hk2);
- continue;
- }
- val = os_malloc(buflen);
- if (val == NULL) {
- RegCloseKey(hk2);
- continue;
- }
- ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
- (LPBYTE) val, &buflen);
- if (ret != ERROR_SUCCESS) {
- os_free(val);
- RegCloseKey(hk2);
- continue;
- }
- RegCloseKey(hk2);
- wpa_unicode2ascii_inplace(val);
- wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
- for (j = 0; j < TNC_MAX_IMC_ID; j++) {
- if (tnc_imc[j] == NULL)
- break;
- }
- if (j >= TNC_MAX_IMC_ID) {
- wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
- os_free(val);
- continue;
- }
- imc = os_zalloc(sizeof(*imc));
- if (imc == NULL) {
- os_free(val);
- break;
- }
- imc->imcID = j;
- wpa_unicode2ascii_inplace(name);
- imc->name = os_strdup((char *) name);
- imc->path = os_strdup((char *) val);
- os_free(val);
- if (last == NULL)
- tncc->imc = imc;
- else
- last->next = imc;
- last = imc;
- tnc_imc[imc->imcID] = imc;
- }
- RegCloseKey(hk);
- return 0;
- }
- static int tncc_read_config(struct tncc_data *tncc)
- {
- if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
- tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
- return -1;
- return 0;
- }
- #else /* CONFIG_NATIVE_WINDOWS */
- static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
- {
- struct tnc_if_imc *imc;
- char *pos, *pos2;
- int i;
- for (i = 0; i < TNC_MAX_IMC_ID; i++) {
- if (tnc_imc[i] == NULL)
- break;
- }
- if (i >= TNC_MAX_IMC_ID) {
- wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
- return NULL;
- }
- imc = os_zalloc(sizeof(*imc));
- if (imc == NULL) {
- *error = 1;
- return NULL;
- }
- imc->imcID = i;
- pos = start;
- wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
- if (pos + 1 >= end || *pos != '"') {
- wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
- "(no starting quotation mark)", start);
- os_free(imc);
- return NULL;
- }
- pos++;
- pos2 = pos;
- while (pos2 < end && *pos2 != '"')
- pos2++;
- if (pos2 >= end) {
- wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
- "(no ending quotation mark)", start);
- os_free(imc);
- return NULL;
- }
- *pos2 = '\0';
- wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
- imc->name = os_strdup(pos);
- pos = pos2 + 1;
- if (pos >= end || *pos != ' ') {
- wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
- "(no space after name)", start);
- os_free(imc);
- return NULL;
- }
- pos++;
- wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
- imc->path = os_strdup(pos);
- tnc_imc[imc->imcID] = imc;
- return imc;
- }
- static int tncc_read_config(struct tncc_data *tncc)
- {
- char *config, *end, *pos, *line_end;
- size_t config_len;
- struct tnc_if_imc *imc, *last;
- last = NULL;
- config = os_readfile(TNC_CONFIG_FILE, &config_len);
- if (config == NULL) {
- wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
- "file '%s'", TNC_CONFIG_FILE);
- return -1;
- }
- end = config + config_len;
- for (pos = config; pos < end; pos = line_end + 1) {
- line_end = pos;
- while (*line_end != '\n' && *line_end != '\r' &&
- line_end < end)
- line_end++;
- *line_end = '\0';
- if (os_strncmp(pos, "IMC ", 4) == 0) {
- int error = 0;
- imc = tncc_parse_imc(pos + 4, line_end, &error);
- if (error)
- return -1;
- if (imc) {
- if (last == NULL)
- tncc->imc = imc;
- else
- last->next = imc;
- last = imc;
- }
- }
- }
- os_free(config);
- return 0;
- }
- #endif /* CONFIG_NATIVE_WINDOWS */
- struct tncc_data * tncc_init(void)
- {
- struct tncc_data *tncc;
- struct tnc_if_imc *imc;
- tncc = os_zalloc(sizeof(*tncc));
- if (tncc == NULL)
- return NULL;
- /* TODO:
- * move loading and Initialize() to a location that is not
- * re-initialized for every EAP-TNC session (?)
- */
- if (tncc_read_config(tncc) < 0) {
- wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
- goto failed;
- }
- for (imc = tncc->imc; imc; imc = imc->next) {
- if (tncc_load_imc(imc)) {
- wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
- imc->name);
- goto failed;
- }
- }
- return tncc;
- failed:
- tncc_deinit(tncc);
- return NULL;
- }
- void tncc_deinit(struct tncc_data *tncc)
- {
- struct tnc_if_imc *imc, *prev;
- imc = tncc->imc;
- while (imc) {
- tncc_unload_imc(imc);
- prev = imc;
- imc = imc->next;
- os_free(prev);
- }
- os_free(tncc);
- }
- static struct wpabuf * tncc_build_soh(void)
- {
- struct wpabuf *buf;
- u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
- u8 correlation_id[24];
- int ver = 2;
- if (os_get_random(correlation_id, sizeof(correlation_id)))
- return NULL;
- wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
- correlation_id, sizeof(correlation_id));
- buf = wpabuf_alloc(200);
- if (buf == NULL)
- return NULL;
- /* Vendor-Specific TLV (Microsoft) - SoH */
- wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
- tlv_len = wpabuf_put(buf, 2); /* Length */
- wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
- wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
- tlv_len2 = wpabuf_put(buf, 2); /* Length */
- /* SoH Header */
- wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
- outer_len = wpabuf_put(buf, 2);
- wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
- wpabuf_put_be16(buf, ver); /* Inner Type */
- inner_len = wpabuf_put(buf, 2);
- if (ver == 2) {
- /* SoH Mode Sub-Header */
- /* Outer Type */
- wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
- wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
- wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
- /* Value: */
- wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
- wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
- wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
- }
- /* SSoH TLV */
- /* System-Health-Id */
- wpabuf_put_be16(buf, 0x0002); /* Type */
- wpabuf_put_be16(buf, 4); /* Length */
- wpabuf_put_be32(buf, 79616);
- /* Vendor-Specific Attribute */
- wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
- ssoh_len = wpabuf_put(buf, 2);
- wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
- /* TODO: MS-Machine-Inventory */
- /* TODO: MS-Quarantine-State */
- /* MS-Packet-Info */
- wpabuf_put_u8(buf, 0x03);
- wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
- /* TODO: MS-MachineName */
- /* MS-CorrelationId */
- wpabuf_put_u8(buf, 0x06);
- wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
- end = wpabuf_put(buf, 0);
- WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
- /* TODO: SoHReportEntry TLV (zero or more) */
- /* Update length fields */
- end = wpabuf_put(buf, 0);
- WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
- WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
- WPA_PUT_BE16(outer_len, end - outer_len - 2);
- WPA_PUT_BE16(inner_len, end - inner_len - 2);
- return buf;
- }
- struct wpabuf * tncc_process_soh_request(const u8 *data, size_t len)
- {
- const u8 *pos;
- wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
- if (len < 12)
- return NULL;
- /* SoH Request */
- pos = data;
- /* TLV Type */
- if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
- return NULL;
- pos += 2;
- /* Length */
- if (WPA_GET_BE16(pos) < 8)
- return NULL;
- pos += 2;
- /* Vendor_Id */
- if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
- return NULL;
- pos += 4;
- /* TLV Type */
- if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
- return NULL;
- wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
- return tncc_build_soh();
- }
|