Merge tag 'upstream/0.9.2' into debian
[mech_eap.git] / libeap / src / eap_server / tncs.c
diff --git a/libeap/src/eap_server/tncs.c b/libeap/src/eap_server/tncs.c
deleted file mode 100644 (file)
index 497b51a..0000000
+++ /dev/null
@@ -1,1273 +0,0 @@
-/*
- * 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_MessageTypeList));
-       if (imv->supported_types == NULL)
-               return TNC_RESULT_FATAL;
-       os_memcpy(imv->supported_types, supportedTypes,
-                 typeCount * sizeof(TNC_MessageTypeList));
-       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;
-}