1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273 |
- /*
- * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
- * Copyright (c) 2007-2008, 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"
- #include <dlfcn.h>
- #include "common.h"
- #include "base64.h"
- #include "tncs.h"
- #include "eap_common/eap_tlv_common.h"
- #include "eap_common/eap_defs.h"
- /* TODO: TNCS must be thread-safe; review the code and add locking etc. if
- * needed.. */
- #define TNC_CONFIG_FILE "/etc/tnc_config"
- #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-IMV */
- typedef unsigned long TNC_UInt32;
- typedef unsigned char *TNC_BufferReference;
- typedef TNC_UInt32 TNC_IMVID;
- typedef TNC_UInt32 TNC_ConnectionID;
- typedef TNC_UInt32 TNC_ConnectionState;
- typedef TNC_UInt32 TNC_RetryReason;
- typedef TNC_UInt32 TNC_IMV_Action_Recommendation;
- typedef TNC_UInt32 TNC_IMV_Evaluation_Result;
- typedef TNC_UInt32 TNC_MessageType;
- typedef TNC_MessageType *TNC_MessageTypeList;
- typedef TNC_UInt32 TNC_VendorID;
- typedef TNC_UInt32 TNC_Subtype;
- typedef TNC_UInt32 TNC_Version;
- typedef TNC_UInt32 TNC_Result;
- typedef TNC_UInt32 TNC_AttributeID;
- typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)(
- TNC_IMVID imvID,
- 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_IFIMV_VERSION_1 1
- #define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
- #define TNC_SUBTYPE_ANY ((TNC_Subtype) 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
- /* Possible TNC_IMV_Action_Recommendation values: */
- enum IMV_Action_Recommendation {
- TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
- TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS,
- TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
- TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
- };
- /* Possible TNC_IMV_Evaluation_Result values: */
- enum IMV_Evaluation_Result {
- TNC_IMV_EVALUATION_RESULT_COMPLIANT,
- TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR,
- TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR,
- TNC_IMV_EVALUATION_RESULT_ERROR,
- TNC_IMV_EVALUATION_RESULT_DONT_KNOW
- };
- struct tnc_if_imv {
- struct tnc_if_imv *next;
- char *name;
- char *path;
- void *dlhandle; /* from dlopen() */
- TNC_IMVID imvID;
- TNC_MessageTypeList supported_types;
- size_t num_supported_types;
- /* Functions implemented by IMVs (with TNC_IMV_ prefix) */
- TNC_Result (*Initialize)(
- TNC_IMVID imvID,
- TNC_Version minVersion,
- TNC_Version maxVersion,
- TNC_Version *pOutActualVersion);
- TNC_Result (*NotifyConnectionChange)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_ConnectionState newState);
- TNC_Result (*ReceiveMessage)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_BufferReference message,
- TNC_UInt32 messageLength,
- TNC_MessageType messageType);
- TNC_Result (*SolicitRecommendation)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID);
- TNC_Result (*BatchEnding)(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID);
- TNC_Result (*Terminate)(TNC_IMVID imvID);
- TNC_Result (*ProvideBindFunction)(
- TNC_IMVID imvID,
- TNC_TNCS_BindFunctionPointer bindFunction);
- };
- #define TNC_MAX_IMV_ID 10
- struct tncs_data {
- struct tncs_data *next;
- struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
- TNC_ConnectionID connectionID;
- unsigned int last_batchid;
- enum IMV_Action_Recommendation recommendation;
- int done;
- struct conn_imv {
- u8 *imv_send;
- size_t imv_send_len;
- enum IMV_Action_Recommendation recommendation;
- int recommendation_set;
- } imv_data[TNC_MAX_IMV_ID];
- char *tncs_message;
- };
- struct tncs_global {
- struct tnc_if_imv *imv;
- TNC_ConnectionID next_conn_id;
- struct tncs_data *connections;
- };
- static struct tncs_global *tncs_global_data = NULL;
- static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
- {
- struct tnc_if_imv *imv;
- if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
- return NULL;
- imv = tncs_global_data->imv;
- while (imv) {
- if (imv->imvID == imvID)
- return imv;
- imv = imv->next;
- }
- return NULL;
- }
- static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
- {
- struct tncs_data *tncs;
- if (tncs_global_data == NULL)
- return NULL;
- tncs = tncs_global_data->connections;
- while (tncs) {
- if (tncs->connectionID == connectionID)
- return tncs;
- tncs = tncs->next;
- }
- wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
- (unsigned long) connectionID);
- return NULL;
- }
- /* TNCS functions that IMVs can call */
- TNC_Result TNC_TNCS_ReportMessageTypes(
- TNC_IMVID imvID,
- TNC_MessageTypeList supportedTypes,
- TNC_UInt32 typeCount)
- {
- TNC_UInt32 i;
- struct tnc_if_imv *imv;
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
- "typeCount=%lu)",
- (unsigned long) imvID, (unsigned long) typeCount);
- for (i = 0; i < typeCount; i++) {
- wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
- i, supportedTypes[i]);
- }
- imv = tncs_get_imv(imvID);
- if (imv == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- os_free(imv->supported_types);
- imv->supported_types =
- os_malloc(typeCount * sizeof(TNC_MessageType));
- if (imv->supported_types == NULL)
- return TNC_RESULT_FATAL;
- os_memcpy(imv->supported_types, supportedTypes,
- typeCount * sizeof(TNC_MessageType));
- imv->num_supported_types = typeCount;
- return TNC_RESULT_SUCCESS;
- }
- TNC_Result TNC_TNCS_SendMessage(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_BufferReference message,
- TNC_UInt32 messageLength,
- TNC_MessageType messageType)
- {
- struct tncs_data *tncs;
- unsigned char *b64;
- size_t b64len;
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
- "connectionID=%lu messageType=%lu)",
- imvID, connectionID, messageType);
- wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
- message, messageLength);
- if (tncs_get_imv(imvID) == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- tncs = tncs_get_conn(connectionID);
- if (tncs == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- b64 = base64_encode(message, messageLength, &b64len);
- if (b64 == NULL)
- return TNC_RESULT_FATAL;
- os_free(tncs->imv_data[imvID].imv_send);
- tncs->imv_data[imvID].imv_send_len = 0;
- tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
- if (tncs->imv_data[imvID].imv_send == NULL) {
- os_free(b64);
- return TNC_RESULT_OTHER;
- }
- tncs->imv_data[imvID].imv_send_len =
- os_snprintf((char *) tncs->imv_data[imvID].imv_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_TNCS_RequestHandshakeRetry(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_RetryReason reason)
- {
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
- /* TODO */
- return TNC_RESULT_SUCCESS;
- }
- TNC_Result TNC_TNCS_ProvideRecommendation(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_IMV_Action_Recommendation recommendation,
- TNC_IMV_Evaluation_Result evaluation)
- {
- struct tncs_data *tncs;
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
- "connectionID=%lu recommendation=%lu evaluation=%lu)",
- (unsigned long) imvID, (unsigned long) connectionID,
- (unsigned long) recommendation, (unsigned long) evaluation);
- if (tncs_get_imv(imvID) == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- tncs = tncs_get_conn(connectionID);
- if (tncs == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- tncs->imv_data[imvID].recommendation = recommendation;
- tncs->imv_data[imvID].recommendation_set = 1;
- return TNC_RESULT_SUCCESS;
- }
- TNC_Result TNC_TNCS_GetAttribute(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_AttributeID attribureID,
- TNC_UInt32 bufferLength,
- TNC_BufferReference buffer,
- TNC_UInt32 *pOutValueLength)
- {
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
- /* TODO */
- return TNC_RESULT_SUCCESS;
- }
- TNC_Result TNC_TNCS_SetAttribute(
- TNC_IMVID imvID,
- TNC_ConnectionID connectionID,
- TNC_AttributeID attribureID,
- TNC_UInt32 bufferLength,
- TNC_BufferReference buffer)
- {
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
- /* TODO */
- return TNC_RESULT_SUCCESS;
- }
- TNC_Result TNC_TNCS_BindFunction(
- TNC_IMVID imvID,
- char *functionName,
- void **pOutFunctionPointer)
- {
- wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
- "functionName='%s')", (unsigned long) imvID, functionName);
- if (tncs_get_imv(imvID) == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- if (pOutFunctionPointer == NULL)
- return TNC_RESULT_INVALID_PARAMETER;
- if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
- *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
- else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
- *pOutFunctionPointer = TNC_TNCS_SendMessage;
- else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
- 0)
- *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
- else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
- 0)
- *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
- else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
- *pOutFunctionPointer = TNC_TNCS_GetAttribute;
- else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
- *pOutFunctionPointer = TNC_TNCS_SetAttribute;
- else
- *pOutFunctionPointer = NULL;
- return TNC_RESULT_SUCCESS;
- }
- static void * tncs_get_sym(void *handle, char *func)
- {
- void *fptr;
- fptr = dlsym(handle, func);
- return fptr;
- }
- static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
- {
- void *handle = imv->dlhandle;
- /* Mandatory IMV functions */
- imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
- if (imv->Initialize == NULL) {
- wpa_printf(MSG_ERROR, "TNC: IMV does not export "
- "TNC_IMV_Initialize");
- return -1;
- }
- imv->SolicitRecommendation = tncs_get_sym(
- handle, "TNC_IMV_SolicitRecommendation");
- if (imv->SolicitRecommendation == NULL) {
- wpa_printf(MSG_ERROR, "TNC: IMV does not export "
- "TNC_IMV_SolicitRecommendation");
- return -1;
- }
- imv->ProvideBindFunction =
- tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
- if (imv->ProvideBindFunction == NULL) {
- wpa_printf(MSG_ERROR, "TNC: IMV does not export "
- "TNC_IMV_ProvideBindFunction");
- return -1;
- }
- /* Optional IMV functions */
- imv->NotifyConnectionChange =
- tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
- imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
- imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
- imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
- return 0;
- }
- static int tncs_imv_initialize(struct tnc_if_imv *imv)
- {
- TNC_Result res;
- TNC_Version imv_ver;
- wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
- imv->name);
- res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
- TNC_IFIMV_VERSION_1, &imv_ver);
- wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
- (unsigned long) res, (unsigned long) imv_ver);
- return res == TNC_RESULT_SUCCESS ? 0 : -1;
- }
- static int tncs_imv_terminate(struct tnc_if_imv *imv)
- {
- TNC_Result res;
- if (imv->Terminate == NULL)
- return 0;
- wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
- imv->name);
- res = imv->Terminate(imv->imvID);
- wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
- (unsigned long) res);
- return res == TNC_RESULT_SUCCESS ? 0 : -1;
- }
- static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
- {
- TNC_Result res;
- wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
- "IMV '%s'", imv->name);
- res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
- wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
- (unsigned long) res);
- return res == TNC_RESULT_SUCCESS ? 0 : -1;
- }
- static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
- TNC_ConnectionID conn,
- TNC_ConnectionState state)
- {
- TNC_Result res;
- if (imv->NotifyConnectionChange == NULL)
- return 0;
- wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
- " for IMV '%s'", (int) state, imv->name);
- res = imv->NotifyConnectionChange(imv->imvID, conn, state);
- wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
- (unsigned long) res);
- return res == TNC_RESULT_SUCCESS ? 0 : -1;
- }
- static int tncs_load_imv(struct tnc_if_imv *imv)
- {
- if (imv->path == NULL) {
- wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
- return -1;
- }
- wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
- imv->name, imv->path);
- imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
- if (imv->dlhandle == NULL) {
- wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
- imv->name, imv->path, dlerror());
- return -1;
- }
- if (tncs_imv_resolve_funcs(imv) < 0) {
- wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
- return -1;
- }
- if (tncs_imv_initialize(imv) < 0 ||
- tncs_imv_provide_bind_function(imv) < 0) {
- wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
- return -1;
- }
- return 0;
- }
- static void tncs_free_imv(struct tnc_if_imv *imv)
- {
- os_free(imv->name);
- os_free(imv->path);
- os_free(imv->supported_types);
- }
- static void tncs_unload_imv(struct tnc_if_imv *imv)
- {
- tncs_imv_terminate(imv);
- if (imv->dlhandle)
- dlclose(imv->dlhandle);
- tncs_free_imv(imv);
- }
- static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
- {
- size_t i;
- unsigned int vendor, subtype;
- if (imv == NULL || imv->supported_types == NULL)
- return 0;
- vendor = type >> 8;
- subtype = type & 0xff;
- for (i = 0; i < imv->num_supported_types; i++) {
- unsigned int svendor, ssubtype;
- svendor = imv->supported_types[i] >> 8;
- ssubtype = imv->supported_types[i] & 0xff;
- if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
- (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
- return 1;
- }
- return 0;
- }
- static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
- const u8 *msg, size_t len)
- {
- struct tnc_if_imv *imv;
- TNC_Result res;
- wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
- for (imv = tncs->imv; imv; imv = imv->next) {
- if (imv->ReceiveMessage == NULL ||
- !tncs_supported_type(imv, type))
- continue;
- wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
- imv->name);
- res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
- (TNC_BufferReference) msg, len,
- type);
- wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
- (unsigned long) res);
- }
- }
- static void tncs_batch_ending(struct tncs_data *tncs)
- {
- struct tnc_if_imv *imv;
- TNC_Result res;
- for (imv = tncs->imv; imv; imv = imv->next) {
- if (imv->BatchEnding == NULL)
- continue;
- wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
- imv->name);
- res = imv->BatchEnding(imv->imvID, tncs->connectionID);
- wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
- (unsigned long) res);
- }
- }
- static void tncs_solicit_recommendation(struct tncs_data *tncs)
- {
- struct tnc_if_imv *imv;
- TNC_Result res;
- for (imv = tncs->imv; imv; imv = imv->next) {
- if (tncs->imv_data[imv->imvID].recommendation_set)
- continue;
- wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
- "IMV '%s'", imv->name);
- res = imv->SolicitRecommendation(imv->imvID,
- tncs->connectionID);
- wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
- (unsigned long) res);
- }
- }
- void tncs_init_connection(struct tncs_data *tncs)
- {
- struct tnc_if_imv *imv;
- int i;
- for (imv = tncs->imv; imv; imv = imv->next) {
- tncs_imv_notify_connection_change(
- imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
- tncs_imv_notify_connection_change(
- imv, tncs->connectionID,
- TNC_CONNECTION_STATE_HANDSHAKE);
- }
- for (i = 0; i < TNC_MAX_IMV_ID; i++) {
- os_free(tncs->imv_data[i].imv_send);
- tncs->imv_data[i].imv_send = NULL;
- tncs->imv_data[i].imv_send_len = 0;
- }
- }
- size_t tncs_total_send_len(struct tncs_data *tncs)
- {
- int i;
- size_t len = 0;
- for (i = 0; i < TNC_MAX_IMV_ID; i++)
- len += tncs->imv_data[i].imv_send_len;
- if (tncs->tncs_message)
- len += os_strlen(tncs->tncs_message);
- return len;
- }
- u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
- {
- int i;
- for (i = 0; i < TNC_MAX_IMV_ID; i++) {
- if (tncs->imv_data[i].imv_send == NULL)
- continue;
- os_memcpy(pos, tncs->imv_data[i].imv_send,
- tncs->imv_data[i].imv_send_len);
- pos += tncs->imv_data[i].imv_send_len;
- os_free(tncs->imv_data[i].imv_send);
- tncs->imv_data[i].imv_send = NULL;
- tncs->imv_data[i].imv_send_len = 0;
- }
- if (tncs->tncs_message) {
- size_t len = os_strlen(tncs->tncs_message);
- os_memcpy(pos, tncs->tncs_message, len);
- pos += len;
- os_free(tncs->tncs_message);
- tncs->tncs_message = NULL;
- }
- return pos;
- }
- char * tncs_if_tnccs_start(struct tncs_data *tncs)
- {
- char *buf = os_malloc(1000);
- if (buf == NULL)
- return NULL;
- tncs->last_batchid++;
- os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
- return buf;
- }
- char * tncs_if_tnccs_end(void)
- {
- char *buf = os_malloc(100);
- if (buf == NULL)
- return NULL;
- os_snprintf(buf, 100, IF_TNCCS_END);
- return buf;
- }
- static int tncs_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 * tncs_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 tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
- {
- enum IMV_Action_Recommendation rec;
- struct tnc_if_imv *imv;
- TNC_ConnectionState state;
- char *txt;
- wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
- if (tncs->done)
- return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
- tncs_solicit_recommendation(tncs);
- /* Select the most restrictive recommendation */
- rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
- for (imv = tncs->imv; imv; imv = imv->next) {
- TNC_IMV_Action_Recommendation irec;
- irec = tncs->imv_data[imv->imvID].recommendation;
- if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
- rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
- if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
- rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
- rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
- if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
- rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
- rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
- }
- wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
- tncs->recommendation = rec;
- tncs->done = 1;
- txt = NULL;
- switch (rec) {
- case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
- case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
- txt = "allow";
- state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
- break;
- case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
- txt = "isolate";
- state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
- break;
- case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
- txt = "none";
- state = TNC_CONNECTION_STATE_ACCESS_NONE;
- break;
- default:
- state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
- break;
- }
- if (txt) {
- os_free(tncs->tncs_message);
- tncs->tncs_message = os_zalloc(200);
- if (tncs->tncs_message) {
- os_snprintf(tncs->tncs_message, 199,
- "<TNCC-TNCS-Message><Type>%08X</Type>"
- "<XML><TNCCS-Recommendation type=\"%s\">"
- "</TNCCS-Recommendation></XML>"
- "</TNCC-TNCS-Message>",
- TNC_TNCCS_RECOMMENDATION, txt);
- }
- }
- for (imv = tncs->imv; imv; imv = imv->next) {
- tncs_imv_notify_connection_change(imv, tncs->connectionID,
- state);
- }
- switch (rec) {
- case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
- return TNCCS_RECOMMENDATION_ALLOW;
- case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
- return TNCCS_RECOMMENDATION_NO_ACCESS;
- case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
- return TNCCS_RECOMMENDATION_ISOLATE;
- case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
- return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
- default:
- return TNCCS_PROCESS_ERROR;
- }
- }
- enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
- const u8 *msg, size_t len)
- {
- char *buf, *start, *end, *pos, *pos2, *payload;
- unsigned int batch_id;
- unsigned char *decoded;
- size_t decoded_len;
- 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 != tncs->last_batchid + 1) {
- wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
- "%u (expected %u)",
- batch_id, tncs->last_batchid + 1);
- os_free(buf);
- return TNCCS_PROCESS_ERROR;
- }
- tncs->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 (tncs_get_type(start, &type) < 0) {
- *endpos = '<';
- start = end;
- continue;
- }
- wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
- decoded = tncs_get_base64(start, &decoded_len);
- if (decoded == NULL) {
- *endpos = '<';
- start = end;
- continue;
- }
- tncs_send_to_imvs(tncs, 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 (tncs_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 = tncs_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);
- }
- start = end;
- }
- os_free(buf);
- tncs_batch_ending(tncs);
- if (tncs_total_send_len(tncs) == 0)
- return tncs_derive_recommendation(tncs);
- return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
- }
- static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
- int *error)
- {
- struct tnc_if_imv *imv;
- char *pos, *pos2;
- if (id >= TNC_MAX_IMV_ID) {
- wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
- return NULL;
- }
- imv = os_zalloc(sizeof(*imv));
- if (imv == NULL) {
- *error = 1;
- return NULL;
- }
- imv->imvID = id;
- pos = start;
- wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
- if (pos + 1 >= end || *pos != '"') {
- wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
- "(no starting quotation mark)", start);
- os_free(imv);
- return NULL;
- }
- pos++;
- pos2 = pos;
- while (pos2 < end && *pos2 != '"')
- pos2++;
- if (pos2 >= end) {
- wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
- "(no ending quotation mark)", start);
- os_free(imv);
- return NULL;
- }
- *pos2 = '\0';
- wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
- imv->name = os_strdup(pos);
- pos = pos2 + 1;
- if (pos >= end || *pos != ' ') {
- wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
- "(no space after name)", start);
- os_free(imv);
- return NULL;
- }
- pos++;
- wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
- imv->path = os_strdup(pos);
- return imv;
- }
- static int tncs_read_config(struct tncs_global *global)
- {
- char *config, *end, *pos, *line_end;
- size_t config_len;
- struct tnc_if_imv *imv, *last;
- int id = 0;
- 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, "IMV ", 4) == 0) {
- int error = 0;
- imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
- if (error)
- return -1;
- if (imv) {
- if (last == NULL)
- global->imv = imv;
- else
- last->next = imv;
- last = imv;
- }
- }
- }
- os_free(config);
- return 0;
- }
- struct tncs_data * tncs_init(void)
- {
- struct tncs_data *tncs;
- if (tncs_global_data == NULL)
- return NULL;
- tncs = os_zalloc(sizeof(*tncs));
- if (tncs == NULL)
- return NULL;
- tncs->imv = tncs_global_data->imv;
- tncs->connectionID = tncs_global_data->next_conn_id++;
- tncs->next = tncs_global_data->connections;
- tncs_global_data->connections = tncs;
- return tncs;
- }
- void tncs_deinit(struct tncs_data *tncs)
- {
- int i;
- struct tncs_data *prev, *conn;
- if (tncs == NULL)
- return;
- for (i = 0; i < TNC_MAX_IMV_ID; i++)
- os_free(tncs->imv_data[i].imv_send);
- prev = NULL;
- conn = tncs_global_data->connections;
- while (conn) {
- if (conn == tncs) {
- if (prev)
- prev->next = tncs->next;
- else
- tncs_global_data->connections = tncs->next;
- break;
- }
- prev = conn;
- conn = conn->next;
- }
- os_free(tncs->tncs_message);
- os_free(tncs);
- }
- int tncs_global_init(void)
- {
- struct tnc_if_imv *imv;
- tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
- if (tncs_global_data == NULL)
- return -1;
- if (tncs_read_config(tncs_global_data) < 0) {
- wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
- goto failed;
- }
- for (imv = tncs_global_data->imv; imv; imv = imv->next) {
- if (tncs_load_imv(imv)) {
- wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
- imv->name);
- goto failed;
- }
- }
- return 0;
- failed:
- tncs_global_deinit();
- return -1;
- }
- void tncs_global_deinit(void)
- {
- struct tnc_if_imv *imv, *prev;
- if (tncs_global_data == NULL)
- return;
- imv = tncs_global_data->imv;
- while (imv) {
- tncs_unload_imv(imv);
- prev = imv;
- imv = imv->next;
- os_free(prev);
- }
- os_free(tncs_global_data);
- tncs_global_data = NULL;
- }
- struct wpabuf * tncs_build_soh_request(void)
- {
- struct wpabuf *buf;
- /*
- * Build a SoH Request TLV (to be used inside SoH EAP Extensions
- * Method)
- */
- buf = wpabuf_alloc(8 + 4);
- if (buf == NULL)
- return NULL;
- /* Vendor-Specific TLV (Microsoft) - SoH Request */
- wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
- wpabuf_put_be16(buf, 8); /* Length */
- wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
- wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
- wpabuf_put_be16(buf, 0); /* Length */
- return buf;
- }
- struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
- int *failure)
- {
- wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
- *failure = 0;
- /* TODO: return MS-SoH Response TLV */
- return NULL;
- }
|