LCOV - code coverage report
Current view: top level - src/eap_server - tncs.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1443382998 Lines: 399 553 72.2 %
Date: 2015-09-27 Functions: 36 39 92.3 %

          Line data    Source code
       1             : /*
       2             :  * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
       3             :  * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
       4             :  *
       5             :  * This software may be distributed under the terms of the BSD license.
       6             :  * See README for more details.
       7             :  */
       8             : 
       9             : #include "includes.h"
      10             : #include <dlfcn.h>
      11             : 
      12             : #include "common.h"
      13             : #include "base64.h"
      14             : #include "common/tnc.h"
      15             : #include "tncs.h"
      16             : #include "eap_common/eap_tlv_common.h"
      17             : #include "eap_common/eap_defs.h"
      18             : 
      19             : 
      20             : /* TODO: TNCS must be thread-safe; review the code and add locking etc. if
      21             :  * needed.. */
      22             : 
      23             : #ifndef TNC_CONFIG_FILE
      24             : #define TNC_CONFIG_FILE "/etc/tnc_config"
      25             : #endif /* TNC_CONFIG_FILE */
      26             : #define IF_TNCCS_START \
      27             : "<?xml version=\"1.0\"?>\n" \
      28             : "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
      29             : "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
      30             : "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
      31             : "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
      32             : "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
      33             : #define IF_TNCCS_END "\n</TNCCS-Batch>"
      34             : 
      35             : /* TNC IF-IMV */
      36             : 
      37             : struct tnc_if_imv {
      38             :         struct tnc_if_imv *next;
      39             :         char *name;
      40             :         char *path;
      41             :         void *dlhandle; /* from dlopen() */
      42             :         TNC_IMVID imvID;
      43             :         TNC_MessageTypeList supported_types;
      44             :         size_t num_supported_types;
      45             : 
      46             :         /* Functions implemented by IMVs (with TNC_IMV_ prefix) */
      47             :         TNC_Result (*Initialize)(
      48             :                 TNC_IMVID imvID,
      49             :                 TNC_Version minVersion,
      50             :                 TNC_Version maxVersion,
      51             :                 TNC_Version *pOutActualVersion);
      52             :         TNC_Result (*NotifyConnectionChange)(
      53             :                 TNC_IMVID imvID,
      54             :                 TNC_ConnectionID connectionID,
      55             :                 TNC_ConnectionState newState);
      56             :         TNC_Result (*ReceiveMessage)(
      57             :                 TNC_IMVID imvID,
      58             :                 TNC_ConnectionID connectionID,
      59             :                 TNC_BufferReference message,
      60             :                 TNC_UInt32 messageLength,
      61             :                 TNC_MessageType messageType);
      62             :         TNC_Result (*SolicitRecommendation)(
      63             :                 TNC_IMVID imvID,
      64             :                 TNC_ConnectionID connectionID);
      65             :         TNC_Result (*BatchEnding)(
      66             :                 TNC_IMVID imvID,
      67             :                 TNC_ConnectionID connectionID);
      68             :         TNC_Result (*Terminate)(TNC_IMVID imvID);
      69             :         TNC_Result (*ProvideBindFunction)(
      70             :                 TNC_IMVID imvID,
      71             :                 TNC_TNCS_BindFunctionPointer bindFunction);
      72             : };
      73             : 
      74             : 
      75             : #define TNC_MAX_IMV_ID 10
      76             : 
      77             : struct tncs_data {
      78             :         struct tncs_data *next;
      79             :         struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
      80             :         TNC_ConnectionID connectionID;
      81             :         unsigned int last_batchid;
      82             :         enum IMV_Action_Recommendation recommendation;
      83             :         int done;
      84             : 
      85             :         struct conn_imv {
      86             :                 u8 *imv_send;
      87             :                 size_t imv_send_len;
      88             :                 enum IMV_Action_Recommendation recommendation;
      89             :                 int recommendation_set;
      90             :         } imv_data[TNC_MAX_IMV_ID];
      91             : 
      92             :         char *tncs_message;
      93             : };
      94             : 
      95             : 
      96             : struct tncs_global {
      97             :         struct tnc_if_imv *imv;
      98             :         TNC_ConnectionID next_conn_id;
      99             :         struct tncs_data *connections;
     100             : };
     101             : 
     102             : static struct tncs_global *tncs_global_data = NULL;
     103             : 
     104             : 
     105          26 : static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
     106             : {
     107             :         struct tnc_if_imv *imv;
     108             : 
     109          26 :         if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
     110           0 :                 return NULL;
     111          26 :         imv = tncs_global_data->imv;
     112          78 :         while (imv) {
     113          52 :                 if (imv->imvID == imvID)
     114          26 :                         return imv;
     115          26 :                 imv = imv->next;
     116             :         }
     117           0 :         return NULL;
     118             : }
     119             : 
     120             : 
     121           6 : static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
     122             : {
     123             :         struct tncs_data *tncs;
     124             : 
     125           6 :         if (tncs_global_data == NULL)
     126           0 :                 return NULL;
     127             : 
     128           6 :         tncs = tncs_global_data->connections;
     129          12 :         while (tncs) {
     130           6 :                 if (tncs->connectionID == connectionID)
     131           6 :                         return tncs;
     132           0 :                 tncs = tncs->next;
     133             :         }
     134             : 
     135           0 :         wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
     136             :                    (unsigned long) connectionID);
     137             : 
     138           0 :         return NULL;
     139             : }
     140             : 
     141             : 
     142             : /* TNCS functions that IMVs can call */
     143           4 : TNC_Result TNC_TNCS_ReportMessageTypes(
     144             :         TNC_IMVID imvID,
     145             :         TNC_MessageTypeList supportedTypes,
     146             :         TNC_UInt32 typeCount)
     147             : {
     148             :         TNC_UInt32 i;
     149             :         struct tnc_if_imv *imv;
     150             : 
     151           4 :         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
     152             :                    "typeCount=%lu)",
     153             :                    (unsigned long) imvID, (unsigned long) typeCount);
     154             : 
     155           8 :         for (i = 0; i < typeCount; i++) {
     156           4 :                 wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
     157           4 :                            i, supportedTypes[i]);
     158             :         }
     159             : 
     160           4 :         imv = tncs_get_imv(imvID);
     161           4 :         if (imv == NULL)
     162           0 :                 return TNC_RESULT_INVALID_PARAMETER;
     163           4 :         os_free(imv->supported_types);
     164           4 :         imv->supported_types =
     165           4 :                 os_malloc(typeCount * sizeof(TNC_MessageType));
     166           4 :         if (imv->supported_types == NULL)
     167           0 :                 return TNC_RESULT_FATAL;
     168           4 :         os_memcpy(imv->supported_types, supportedTypes,
     169             :                   typeCount * sizeof(TNC_MessageType));
     170           4 :         imv->num_supported_types = typeCount;
     171             : 
     172           4 :         return TNC_RESULT_SUCCESS;
     173             : }
     174             : 
     175             : 
     176           3 : TNC_Result TNC_TNCS_SendMessage(
     177             :         TNC_IMVID imvID,
     178             :         TNC_ConnectionID connectionID,
     179             :         TNC_BufferReference message,
     180             :         TNC_UInt32 messageLength,
     181             :         TNC_MessageType messageType)
     182             : {
     183             :         struct tncs_data *tncs;
     184             :         unsigned char *b64;
     185             :         size_t b64len;
     186             : 
     187           3 :         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
     188             :                    "connectionID=%lu messageType=%lu)",
     189             :                    imvID, connectionID, messageType);
     190           3 :         wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
     191             :                           message, messageLength);
     192             : 
     193           3 :         if (tncs_get_imv(imvID) == NULL)
     194           0 :                 return TNC_RESULT_INVALID_PARAMETER;
     195             : 
     196           3 :         tncs = tncs_get_conn(connectionID);
     197           3 :         if (tncs == NULL)
     198           0 :                 return TNC_RESULT_INVALID_PARAMETER;
     199             : 
     200           3 :         b64 = base64_encode(message, messageLength, &b64len);
     201           3 :         if (b64 == NULL)
     202           0 :                 return TNC_RESULT_FATAL;
     203             : 
     204           3 :         os_free(tncs->imv_data[imvID].imv_send);
     205           3 :         tncs->imv_data[imvID].imv_send_len = 0;
     206           3 :         tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
     207           3 :         if (tncs->imv_data[imvID].imv_send == NULL) {
     208           0 :                 os_free(b64);
     209           0 :                 return TNC_RESULT_OTHER;
     210             :         }
     211             : 
     212           3 :         tncs->imv_data[imvID].imv_send_len =
     213           3 :                 os_snprintf((char *) tncs->imv_data[imvID].imv_send,
     214             :                             b64len + 100,
     215             :                             "<IMC-IMV-Message><Type>%08X</Type>"
     216             :                             "<Base64>%s</Base64></IMC-IMV-Message>",
     217             :                             (unsigned int) messageType, b64);
     218             : 
     219           3 :         os_free(b64);
     220             : 
     221           3 :         return TNC_RESULT_SUCCESS;
     222             : }
     223             : 
     224             : 
     225           0 : TNC_Result TNC_TNCS_RequestHandshakeRetry(
     226             :         TNC_IMVID imvID,
     227             :         TNC_ConnectionID connectionID,
     228             :         TNC_RetryReason reason)
     229             : {
     230           0 :         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
     231             :         /* TODO */
     232           0 :         return TNC_RESULT_SUCCESS;
     233             : }
     234             : 
     235             : 
     236           3 : TNC_Result TNC_TNCS_ProvideRecommendation(
     237             :         TNC_IMVID imvID,
     238             :         TNC_ConnectionID connectionID,
     239             :         TNC_IMV_Action_Recommendation recommendation,
     240             :         TNC_IMV_Evaluation_Result evaluation)
     241             : {
     242             :         struct tncs_data *tncs;
     243             : 
     244           3 :         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
     245             :                    "connectionID=%lu recommendation=%lu evaluation=%lu)",
     246             :                    (unsigned long) imvID, (unsigned long) connectionID,
     247             :                    (unsigned long) recommendation, (unsigned long) evaluation);
     248             : 
     249           3 :         if (tncs_get_imv(imvID) == NULL)
     250           0 :                 return TNC_RESULT_INVALID_PARAMETER;
     251             : 
     252           3 :         tncs = tncs_get_conn(connectionID);
     253           3 :         if (tncs == NULL)
     254           0 :                 return TNC_RESULT_INVALID_PARAMETER;
     255             : 
     256           3 :         tncs->imv_data[imvID].recommendation = recommendation;
     257           3 :         tncs->imv_data[imvID].recommendation_set = 1;
     258             : 
     259           3 :         return TNC_RESULT_SUCCESS;
     260             : }
     261             : 
     262             : 
     263           0 : TNC_Result TNC_TNCS_GetAttribute(
     264             :         TNC_IMVID imvID,
     265             :         TNC_ConnectionID connectionID,
     266             :         TNC_AttributeID attribureID,
     267             :         TNC_UInt32 bufferLength,
     268             :         TNC_BufferReference buffer,
     269             :         TNC_UInt32 *pOutValueLength)
     270             : {
     271           0 :         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
     272             :         /* TODO */
     273           0 :         return TNC_RESULT_SUCCESS;
     274             : }
     275             : 
     276             : 
     277           0 : TNC_Result TNC_TNCS_SetAttribute(
     278             :         TNC_IMVID imvID,
     279             :         TNC_ConnectionID connectionID,
     280             :         TNC_AttributeID attribureID,
     281             :         TNC_UInt32 bufferLength,
     282             :         TNC_BufferReference buffer)
     283             : {
     284           0 :         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
     285             :         /* TODO */
     286           0 :         return TNC_RESULT_SUCCESS;
     287             : }
     288             : 
     289             : 
     290          16 : TNC_Result TNC_TNCS_BindFunction(
     291             :         TNC_IMVID imvID,
     292             :         char *functionName,
     293             :         void **pOutFunctionPointer)
     294             : {
     295          16 :         wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
     296             :                    "functionName='%s')", (unsigned long) imvID, functionName);
     297             : 
     298          16 :         if (tncs_get_imv(imvID) == NULL)
     299           0 :                 return TNC_RESULT_INVALID_PARAMETER;
     300             : 
     301          16 :         if (pOutFunctionPointer == NULL)
     302           0 :                 return TNC_RESULT_INVALID_PARAMETER;
     303             : 
     304          16 :         if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
     305           4 :                 *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
     306          12 :         else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
     307           4 :                 *pOutFunctionPointer = TNC_TNCS_SendMessage;
     308           8 :         else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
     309             :                  0)
     310           4 :                 *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
     311           4 :         else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
     312             :                  0)
     313           4 :                 *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
     314           0 :         else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
     315           0 :                 *pOutFunctionPointer = TNC_TNCS_GetAttribute;
     316           0 :         else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
     317           0 :                 *pOutFunctionPointer = TNC_TNCS_SetAttribute;
     318             :         else
     319           0 :                 *pOutFunctionPointer = NULL;
     320             : 
     321          16 :         return TNC_RESULT_SUCCESS;
     322             : }
     323             : 
     324             : 
     325          56 : static void * tncs_get_sym(void *handle, char *func)
     326             : {
     327             :         void *fptr;
     328             : 
     329          56 :         fptr = dlsym(handle, func);
     330             : 
     331          56 :         return fptr;
     332             : }
     333             : 
     334             : 
     335           8 : static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
     336             : {
     337           8 :         void *handle = imv->dlhandle;
     338             : 
     339             :         /* Mandatory IMV functions */
     340           8 :         imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
     341           8 :         if (imv->Initialize == NULL) {
     342           0 :                 wpa_printf(MSG_ERROR, "TNC: IMV does not export "
     343             :                            "TNC_IMV_Initialize");
     344           0 :                 return -1;
     345             :         }
     346             : 
     347           8 :         imv->SolicitRecommendation = tncs_get_sym(
     348             :                 handle, "TNC_IMV_SolicitRecommendation");
     349           8 :         if (imv->SolicitRecommendation == NULL) {
     350           0 :                 wpa_printf(MSG_ERROR, "TNC: IMV does not export "
     351             :                            "TNC_IMV_SolicitRecommendation");
     352           0 :                 return -1;
     353             :         }
     354             : 
     355           8 :         imv->ProvideBindFunction =
     356           8 :                 tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
     357           8 :         if (imv->ProvideBindFunction == NULL) {
     358           0 :                 wpa_printf(MSG_ERROR, "TNC: IMV does not export "
     359             :                            "TNC_IMV_ProvideBindFunction");
     360           0 :                 return -1;
     361             :         }
     362             : 
     363             :         /* Optional IMV functions */
     364           8 :         imv->NotifyConnectionChange =
     365           8 :                 tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
     366           8 :         imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
     367           8 :         imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
     368           8 :         imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
     369             : 
     370           8 :         return 0;
     371             : }
     372             : 
     373             : 
     374           8 : static int tncs_imv_initialize(struct tnc_if_imv *imv)
     375             : {
     376             :         TNC_Result res;
     377             :         TNC_Version imv_ver;
     378             : 
     379           8 :         wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
     380             :                    imv->name);
     381           8 :         res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
     382             :                               TNC_IFIMV_VERSION_1, &imv_ver);
     383           8 :         wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
     384             :                    (unsigned long) res, (unsigned long) imv_ver);
     385             : 
     386           8 :         return res == TNC_RESULT_SUCCESS ? 0 : -1;
     387             : }
     388             : 
     389             : 
     390           8 : static int tncs_imv_terminate(struct tnc_if_imv *imv)
     391             : {
     392             :         TNC_Result res;
     393             : 
     394           8 :         if (imv->Terminate == NULL)
     395           4 :                 return 0;
     396             : 
     397           4 :         wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
     398             :                    imv->name);
     399           4 :         res = imv->Terminate(imv->imvID);
     400           4 :         wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
     401             :                    (unsigned long) res);
     402             : 
     403           4 :         return res == TNC_RESULT_SUCCESS ? 0 : -1;
     404             : }
     405             : 
     406             : 
     407           8 : static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
     408             : {
     409             :         TNC_Result res;
     410             : 
     411           8 :         wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
     412             :                    "IMV '%s'", imv->name);
     413           8 :         res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
     414           8 :         wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
     415             :                    (unsigned long) res);
     416             : 
     417           8 :         return res == TNC_RESULT_SUCCESS ? 0 : -1;
     418             : }
     419             : 
     420             : 
     421          18 : static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
     422             :                                              TNC_ConnectionID conn,
     423             :                                              TNC_ConnectionState state)
     424             : {
     425             :         TNC_Result res;
     426             : 
     427          18 :         if (imv->NotifyConnectionChange == NULL)
     428           9 :                 return 0;
     429             : 
     430           9 :         wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
     431             :                    " for IMV '%s'", (int) state, imv->name);
     432           9 :         res = imv->NotifyConnectionChange(imv->imvID, conn, state);
     433           9 :         wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
     434             :                    (unsigned long) res);
     435             : 
     436           9 :         return res == TNC_RESULT_SUCCESS ? 0 : -1;
     437             : }
     438             : 
     439             : 
     440           8 : static int tncs_load_imv(struct tnc_if_imv *imv)
     441             : {
     442           8 :         if (imv->path == NULL) {
     443           0 :                 wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
     444           0 :                 return -1;
     445             :         }
     446             : 
     447           8 :         wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
     448             :                    imv->name, imv->path);
     449           8 :         imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
     450           8 :         if (imv->dlhandle == NULL) {
     451           0 :                 wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
     452             :                            imv->name, imv->path, dlerror());
     453           0 :                 return -1;
     454             :         }
     455             : 
     456           8 :         if (tncs_imv_resolve_funcs(imv) < 0) {
     457           0 :                 wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
     458           0 :                 return -1;
     459             :         }
     460             : 
     461          16 :         if (tncs_imv_initialize(imv) < 0 ||
     462           8 :             tncs_imv_provide_bind_function(imv) < 0) {
     463           0 :                 wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
     464           0 :                 return -1;
     465             :         }
     466             : 
     467           8 :         return 0;
     468             : }
     469             : 
     470             : 
     471           8 : static void tncs_free_imv(struct tnc_if_imv *imv)
     472             : {
     473           8 :         os_free(imv->name);
     474           8 :         os_free(imv->path);
     475           8 :         os_free(imv->supported_types);
     476           8 : }
     477             : 
     478           8 : static void tncs_unload_imv(struct tnc_if_imv *imv)
     479             : {
     480           8 :         tncs_imv_terminate(imv);
     481             : 
     482           8 :         if (imv->dlhandle)
     483           8 :                 dlclose(imv->dlhandle);
     484             : 
     485           8 :         tncs_free_imv(imv);
     486           8 : }
     487             : 
     488             : 
     489           6 : static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
     490             : {
     491             :         size_t i;
     492             :         unsigned int vendor, subtype;
     493             : 
     494           6 :         if (imv == NULL || imv->supported_types == NULL)
     495           0 :                 return 0;
     496             : 
     497           6 :         vendor = type >> 8;
     498           6 :         subtype = type & 0xff;
     499             : 
     500           6 :         for (i = 0; i < imv->num_supported_types; i++) {
     501             :                 unsigned int svendor, ssubtype;
     502           6 :                 svendor = imv->supported_types[i] >> 8;
     503           6 :                 ssubtype = imv->supported_types[i] & 0xff;
     504           6 :                 if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
     505           6 :                     (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
     506           6 :                         return 1;
     507             :         }
     508             : 
     509           0 :         return 0;
     510             : }
     511             : 
     512             : 
     513           6 : static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
     514             :                               const u8 *msg, size_t len)
     515             : {
     516             :         struct tnc_if_imv *imv;
     517             :         TNC_Result res;
     518             : 
     519           6 :         wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
     520             : 
     521          18 :         for (imv = tncs->imv; imv; imv = imv->next) {
     522          18 :                 if (imv->ReceiveMessage == NULL ||
     523           6 :                     !tncs_supported_type(imv, type))
     524           6 :                         continue;
     525             : 
     526           6 :                 wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
     527             :                            imv->name);
     528           6 :                 res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
     529             :                                           (TNC_BufferReference) msg, len,
     530             :                                           type);
     531           6 :                 wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
     532             :                            (unsigned long) res);
     533             :         }
     534           6 : }
     535             : 
     536             : 
     537           6 : static void tncs_batch_ending(struct tncs_data *tncs)
     538             : {
     539             :         struct tnc_if_imv *imv;
     540             :         TNC_Result res;
     541             : 
     542          18 :         for (imv = tncs->imv; imv; imv = imv->next) {
     543          12 :                 if (imv->BatchEnding == NULL)
     544           6 :                         continue;
     545             : 
     546           6 :                 wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
     547             :                            imv->name);
     548           6 :                 res = imv->BatchEnding(imv->imvID, tncs->connectionID);
     549           6 :                 wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
     550             :                            (unsigned long) res);
     551             :         }
     552           6 : }
     553             : 
     554             : 
     555           3 : static void tncs_solicit_recommendation(struct tncs_data *tncs)
     556             : {
     557             :         struct tnc_if_imv *imv;
     558             :         TNC_Result res;
     559             : 
     560           9 :         for (imv = tncs->imv; imv; imv = imv->next) {
     561           6 :                 if (tncs->imv_data[imv->imvID].recommendation_set)
     562           3 :                         continue;
     563             : 
     564           3 :                 wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
     565             :                            "IMV '%s'", imv->name);
     566           3 :                 res = imv->SolicitRecommendation(imv->imvID,
     567             :                                                  tncs->connectionID);
     568           3 :                 wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
     569             :                            (unsigned long) res);
     570             :         }
     571           3 : }
     572             : 
     573             : 
     574           3 : void tncs_init_connection(struct tncs_data *tncs)
     575             : {
     576             :         struct tnc_if_imv *imv;
     577             :         int i;
     578             : 
     579           9 :         for (imv = tncs->imv; imv; imv = imv->next) {
     580           6 :                 tncs_imv_notify_connection_change(
     581             :                         imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
     582           6 :                 tncs_imv_notify_connection_change(
     583             :                         imv, tncs->connectionID,
     584             :                         TNC_CONNECTION_STATE_HANDSHAKE);
     585             :         }
     586             : 
     587          33 :         for (i = 0; i < TNC_MAX_IMV_ID; i++) {
     588          30 :                 os_free(tncs->imv_data[i].imv_send);
     589          30 :                 tncs->imv_data[i].imv_send = NULL;
     590          30 :                 tncs->imv_data[i].imv_send_len = 0;
     591             :         }
     592           3 : }
     593             : 
     594             : 
     595          12 : size_t tncs_total_send_len(struct tncs_data *tncs)
     596             : {
     597             :         int i;
     598          12 :         size_t len = 0;
     599             : 
     600         132 :         for (i = 0; i < TNC_MAX_IMV_ID; i++)
     601         120 :                 len += tncs->imv_data[i].imv_send_len;
     602          12 :         if (tncs->tncs_message)
     603           3 :                 len += os_strlen(tncs->tncs_message);
     604          12 :         return len;
     605             : }
     606             : 
     607             : 
     608           6 : u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
     609             : {
     610             :         int i;
     611             : 
     612          66 :         for (i = 0; i < TNC_MAX_IMV_ID; i++) {
     613          60 :                 if (tncs->imv_data[i].imv_send == NULL)
     614          57 :                         continue;
     615             : 
     616           3 :                 os_memcpy(pos, tncs->imv_data[i].imv_send,
     617             :                           tncs->imv_data[i].imv_send_len);
     618           3 :                 pos += tncs->imv_data[i].imv_send_len;
     619           3 :                 os_free(tncs->imv_data[i].imv_send);
     620           3 :                 tncs->imv_data[i].imv_send = NULL;
     621           3 :                 tncs->imv_data[i].imv_send_len = 0;
     622             :         }
     623             : 
     624           6 :         if (tncs->tncs_message) {
     625           3 :                 size_t len = os_strlen(tncs->tncs_message);
     626           3 :                 os_memcpy(pos, tncs->tncs_message, len);
     627           3 :                 pos += len;
     628           3 :                 os_free(tncs->tncs_message);
     629           3 :                 tncs->tncs_message = NULL;
     630             :         }
     631             : 
     632           6 :         return pos;
     633             : }
     634             : 
     635             : 
     636           6 : char * tncs_if_tnccs_start(struct tncs_data *tncs)
     637             : {
     638           6 :         char *buf = os_malloc(1000);
     639           6 :         if (buf == NULL)
     640           0 :                 return NULL;
     641           6 :         tncs->last_batchid++;
     642           6 :         os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
     643           6 :         return buf;
     644             : }
     645             : 
     646             : 
     647           6 : char * tncs_if_tnccs_end(void)
     648             : {
     649           6 :         char *buf = os_malloc(100);
     650           6 :         if (buf == NULL)
     651           0 :                 return NULL;
     652           6 :         os_snprintf(buf, 100, IF_TNCCS_END);
     653           6 :         return buf;
     654             : }
     655             : 
     656             : 
     657           6 : static int tncs_get_type(char *start, unsigned int *type)
     658             : {
     659           6 :         char *pos = os_strstr(start, "<Type>");
     660           6 :         if (pos == NULL)
     661           0 :                 return -1;
     662           6 :         pos += 6;
     663           6 :         *type = strtoul(pos, NULL, 16);
     664           6 :         return 0;
     665             : }
     666             : 
     667             : 
     668           6 : static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
     669             : {
     670             :         char *pos, *pos2;
     671             :         unsigned char *decoded;
     672             : 
     673           6 :         pos = os_strstr(start, "<Base64>");
     674           6 :         if (pos == NULL)
     675           0 :                 return NULL;
     676             : 
     677           6 :         pos += 8;
     678           6 :         pos2 = os_strstr(pos, "</Base64>");
     679           6 :         if (pos2 == NULL)
     680           0 :                 return NULL;
     681           6 :         *pos2 = '\0';
     682             : 
     683           6 :         decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
     684             :                                 decoded_len);
     685           6 :         *pos2 = '<';
     686           6 :         if (decoded == NULL) {
     687           0 :                 wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
     688             :         }
     689             : 
     690           6 :         return decoded;
     691             : }
     692             : 
     693             : 
     694           3 : static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
     695             : {
     696             :         enum IMV_Action_Recommendation rec;
     697             :         struct tnc_if_imv *imv;
     698             :         TNC_ConnectionState state;
     699             :         char *txt;
     700             : 
     701           3 :         wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
     702             : 
     703           3 :         if (tncs->done)
     704           0 :                 return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
     705             : 
     706           3 :         tncs_solicit_recommendation(tncs);
     707             : 
     708             :         /* Select the most restrictive recommendation */
     709           3 :         rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
     710           9 :         for (imv = tncs->imv; imv; imv = imv->next) {
     711             :                 TNC_IMV_Action_Recommendation irec;
     712           6 :                 irec = tncs->imv_data[imv->imvID].recommendation;
     713           6 :                 if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
     714           0 :                         rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
     715           6 :                 if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
     716             :                     rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
     717           0 :                         rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
     718           6 :                 if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
     719             :                     rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
     720           3 :                         rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
     721             :         }
     722             : 
     723           3 :         wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
     724           3 :         tncs->recommendation = rec;
     725           3 :         tncs->done = 1;
     726             : 
     727           3 :         txt = NULL;
     728           3 :         switch (rec) {
     729             :         case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
     730             :         case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
     731           3 :                 txt = "allow";
     732           3 :                 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
     733           3 :                 break;
     734             :         case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
     735           0 :                 txt = "isolate";
     736           0 :                 state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
     737           0 :                 break;
     738             :         case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
     739           0 :                 txt = "none";
     740           0 :                 state = TNC_CONNECTION_STATE_ACCESS_NONE;
     741           0 :                 break;
     742             :         default:
     743           0 :                 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
     744           0 :                 break;
     745             :         }
     746             : 
     747           3 :         if (txt) {
     748           3 :                 os_free(tncs->tncs_message);
     749           3 :                 tncs->tncs_message = os_zalloc(200);
     750           3 :                 if (tncs->tncs_message) {
     751           3 :                         os_snprintf(tncs->tncs_message, 199,
     752             :                                     "<TNCC-TNCS-Message><Type>%08X</Type>"
     753             :                                     "<XML><TNCCS-Recommendation type=\"%s\">"
     754             :                                     "</TNCCS-Recommendation></XML>"
     755             :                                     "</TNCC-TNCS-Message>",
     756             :                                     TNC_TNCCS_RECOMMENDATION, txt);
     757             :                 }
     758             :         }
     759             : 
     760           9 :         for (imv = tncs->imv; imv; imv = imv->next) {
     761           6 :                 tncs_imv_notify_connection_change(imv, tncs->connectionID,
     762             :                                                   state);
     763             :         }
     764             : 
     765           3 :         switch (rec) {
     766             :         case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
     767           3 :                 return TNCCS_RECOMMENDATION_ALLOW;
     768             :         case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
     769           0 :                 return TNCCS_RECOMMENDATION_NO_ACCESS;
     770             :         case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
     771           0 :                 return TNCCS_RECOMMENDATION_ISOLATE;
     772             :         case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
     773           0 :                 return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
     774             :         default:
     775           0 :                 return TNCCS_PROCESS_ERROR;
     776             :         }
     777             : }
     778             : 
     779             : 
     780           6 : enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
     781             :                                             const u8 *msg, size_t len)
     782             : {
     783             :         char *buf, *start, *end, *pos, *pos2, *payload;
     784             :         unsigned int batch_id;
     785             :         unsigned char *decoded;
     786             :         size_t decoded_len;
     787             : 
     788           6 :         buf = dup_binstr(msg, len);
     789           6 :         if (buf == NULL)
     790           0 :                 return TNCCS_PROCESS_ERROR;
     791             : 
     792           6 :         start = os_strstr(buf, "<TNCCS-Batch ");
     793           6 :         end = os_strstr(buf, "</TNCCS-Batch>");
     794           6 :         if (start == NULL || end == NULL || start > end) {
     795           0 :                 os_free(buf);
     796           0 :                 return TNCCS_PROCESS_ERROR;
     797             :         }
     798             : 
     799           6 :         start += 13;
     800          12 :         while (*start == ' ')
     801           0 :                 start++;
     802           6 :         *end = '\0';
     803             : 
     804           6 :         pos = os_strstr(start, "BatchId=");
     805           6 :         if (pos == NULL) {
     806           0 :                 os_free(buf);
     807           0 :                 return TNCCS_PROCESS_ERROR;
     808             :         }
     809             : 
     810           6 :         pos += 8;
     811           6 :         if (*pos == '"')
     812           6 :                 pos++;
     813           6 :         batch_id = atoi(pos);
     814           6 :         wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
     815             :                    batch_id);
     816           6 :         if (batch_id != tncs->last_batchid + 1) {
     817           0 :                 wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
     818             :                            "%u (expected %u)",
     819           0 :                            batch_id, tncs->last_batchid + 1);
     820           0 :                 os_free(buf);
     821           0 :                 return TNCCS_PROCESS_ERROR;
     822             :         }
     823           6 :         tncs->last_batchid = batch_id;
     824             : 
     825        1710 :         while (*pos != '\0' && *pos != '>')
     826        1698 :                 pos++;
     827           6 :         if (*pos == '\0') {
     828           0 :                 os_free(buf);
     829           0 :                 return TNCCS_PROCESS_ERROR;
     830             :         }
     831           6 :         pos++;
     832           6 :         payload = start;
     833             : 
     834             :         /*
     835             :          * <IMC-IMV-Message>
     836             :          * <Type>01234567</Type>
     837             :          * <Base64>foo==</Base64>
     838             :          * </IMC-IMV-Message>
     839             :          */
     840             : 
     841          18 :         while (*start) {
     842             :                 char *endpos;
     843             :                 unsigned int type;
     844             : 
     845          12 :                 pos = os_strstr(start, "<IMC-IMV-Message>");
     846          12 :                 if (pos == NULL)
     847          12 :                         break;
     848           6 :                 start = pos + 17;
     849           6 :                 end = os_strstr(start, "</IMC-IMV-Message>");
     850           6 :                 if (end == NULL)
     851           0 :                         break;
     852           6 :                 *end = '\0';
     853           6 :                 endpos = end;
     854           6 :                 end += 18;
     855             : 
     856           6 :                 if (tncs_get_type(start, &type) < 0) {
     857           0 :                         *endpos = '<';
     858           0 :                         start = end;
     859           0 :                         continue;
     860             :                 }
     861           6 :                 wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
     862             : 
     863           6 :                 decoded = tncs_get_base64(start, &decoded_len);
     864           6 :                 if (decoded == NULL) {
     865           0 :                         *endpos = '<';
     866           0 :                         start = end;
     867           0 :                         continue;
     868             :                 }
     869             : 
     870           6 :                 tncs_send_to_imvs(tncs, type, decoded, decoded_len);
     871             : 
     872           6 :                 os_free(decoded);
     873             : 
     874           6 :                 start = end;
     875             :         }
     876             : 
     877             :         /*
     878             :          * <TNCC-TNCS-Message>
     879             :          * <Type>01234567</Type>
     880             :          * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
     881             :          * <Base64>foo==</Base64>
     882             :          * </TNCC-TNCS-Message>
     883             :          */
     884             : 
     885           6 :         start = payload;
     886          12 :         while (*start) {
     887             :                 unsigned int type;
     888             :                 char *xml, *xmlend, *endpos;
     889             : 
     890           6 :                 pos = os_strstr(start, "<TNCC-TNCS-Message>");
     891           6 :                 if (pos == NULL)
     892          12 :                         break;
     893           0 :                 start = pos + 19;
     894           0 :                 end = os_strstr(start, "</TNCC-TNCS-Message>");
     895           0 :                 if (end == NULL)
     896           0 :                         break;
     897           0 :                 *end = '\0';
     898           0 :                 endpos = end;
     899           0 :                 end += 20;
     900             : 
     901           0 :                 if (tncs_get_type(start, &type) < 0) {
     902           0 :                         *endpos = '<';
     903           0 :                         start = end;
     904           0 :                         continue;
     905             :                 }
     906           0 :                 wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
     907             :                            type);
     908             : 
     909             :                 /* Base64 OR XML */
     910           0 :                 decoded = NULL;
     911           0 :                 xml = NULL;
     912           0 :                 xmlend = NULL;
     913           0 :                 pos = os_strstr(start, "<XML>");
     914           0 :                 if (pos) {
     915           0 :                         pos += 5;
     916           0 :                         pos2 = os_strstr(pos, "</XML>");
     917           0 :                         if (pos2 == NULL) {
     918           0 :                                 *endpos = '<';
     919           0 :                                 start = end;
     920           0 :                                 continue;
     921             :                         }
     922           0 :                         xmlend = pos2;
     923           0 :                         xml = pos;
     924             :                 } else {
     925           0 :                         decoded = tncs_get_base64(start, &decoded_len);
     926           0 :                         if (decoded == NULL) {
     927           0 :                                 *endpos = '<';
     928           0 :                                 start = end;
     929           0 :                                 continue;
     930             :                         }
     931             :                 }
     932             : 
     933           0 :                 if (decoded) {
     934           0 :                         wpa_hexdump_ascii(MSG_MSGDUMP,
     935             :                                           "TNC: TNCC-TNCS-Message Base64",
     936             :                                           decoded, decoded_len);
     937           0 :                         os_free(decoded);
     938             :                 }
     939             : 
     940           0 :                 if (xml) {
     941           0 :                         wpa_hexdump_ascii(MSG_MSGDUMP,
     942             :                                           "TNC: TNCC-TNCS-Message XML",
     943             :                                           (unsigned char *) xml,
     944           0 :                                           xmlend - xml);
     945             :                 }
     946             : 
     947           0 :                 start = end;
     948             :         }
     949             : 
     950           6 :         os_free(buf);
     951             : 
     952           6 :         tncs_batch_ending(tncs);
     953             : 
     954           6 :         if (tncs_total_send_len(tncs) == 0)
     955           3 :                 return tncs_derive_recommendation(tncs);
     956             : 
     957           3 :         return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
     958             : }
     959             : 
     960             : 
     961           8 : static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
     962             :                                           int *error)
     963             : {
     964             :         struct tnc_if_imv *imv;
     965             :         char *pos, *pos2;
     966             : 
     967           8 :         if (id >= TNC_MAX_IMV_ID) {
     968           0 :                 wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
     969           0 :                 return NULL;
     970             :         }
     971             : 
     972           8 :         imv = os_zalloc(sizeof(*imv));
     973           8 :         if (imv == NULL) {
     974           0 :                 *error = 1;
     975           0 :                 return NULL;
     976             :         }
     977             : 
     978           8 :         imv->imvID = id;
     979             : 
     980           8 :         pos = start;
     981           8 :         wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
     982           8 :         if (pos + 1 >= end || *pos != '"') {
     983           0 :                 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
     984             :                            "(no starting quotation mark)", start);
     985           0 :                 os_free(imv);
     986           0 :                 return NULL;
     987             :         }
     988             : 
     989           8 :         pos++;
     990           8 :         pos2 = pos;
     991         100 :         while (pos2 < end && *pos2 != '"')
     992          84 :                 pos2++;
     993           8 :         if (pos2 >= end) {
     994           0 :                 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
     995             :                            "(no ending quotation mark)", start);
     996           0 :                 os_free(imv);
     997           0 :                 return NULL;
     998             :         }
     999           8 :         *pos2 = '\0';
    1000           8 :         wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
    1001           8 :         imv->name = os_strdup(pos);
    1002             : 
    1003           8 :         pos = pos2 + 1;
    1004           8 :         if (pos >= end || *pos != ' ') {
    1005           0 :                 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
    1006             :                            "(no space after name)", start);
    1007           0 :                 os_free(imv);
    1008           0 :                 return NULL;
    1009             :         }
    1010             : 
    1011           8 :         pos++;
    1012           8 :         wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
    1013           8 :         imv->path = os_strdup(pos);
    1014             : 
    1015           8 :         return imv;
    1016             : }
    1017             : 
    1018             : 
    1019           4 : static int tncs_read_config(struct tncs_global *global)
    1020             : {
    1021             :         char *config, *end, *pos, *line_end;
    1022             :         size_t config_len;
    1023             :         struct tnc_if_imv *imv, *last;
    1024           4 :         int id = 0;
    1025             : 
    1026           4 :         last = NULL;
    1027             : 
    1028           4 :         config = os_readfile(TNC_CONFIG_FILE, &config_len);
    1029           4 :         if (config == NULL) {
    1030           0 :                 wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
    1031             :                            "file '%s'", TNC_CONFIG_FILE);
    1032           0 :                 return -1;
    1033             :         }
    1034             : 
    1035           4 :         end = config + config_len;
    1036          20 :         for (pos = config; pos < end; pos = line_end + 1) {
    1037          16 :                 line_end = pos;
    1038         640 :                 while (*line_end != '\n' && *line_end != '\r' &&
    1039             :                        line_end < end)
    1040         608 :                         line_end++;
    1041          16 :                 *line_end = '\0';
    1042             : 
    1043          16 :                 if (os_strncmp(pos, "IMV ", 4) == 0) {
    1044           8 :                         int error = 0;
    1045             : 
    1046           8 :                         imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
    1047           8 :                         if (error)
    1048           0 :                                 return -1;
    1049           8 :                         if (imv) {
    1050           8 :                                 if (last == NULL)
    1051           4 :                                         global->imv = imv;
    1052             :                                 else
    1053           4 :                                         last->next = imv;
    1054           8 :                                 last = imv;
    1055             :                         }
    1056             :                 }
    1057             :         }
    1058             : 
    1059           4 :         os_free(config);
    1060             : 
    1061           4 :         return 0;
    1062             : }
    1063             : 
    1064             : 
    1065           3 : struct tncs_data * tncs_init(void)
    1066             : {
    1067             :         struct tncs_data *tncs;
    1068             : 
    1069           3 :         if (tncs_global_data == NULL)
    1070           0 :                 return NULL;
    1071             : 
    1072           3 :         tncs = os_zalloc(sizeof(*tncs));
    1073           3 :         if (tncs == NULL)
    1074           0 :                 return NULL;
    1075           3 :         tncs->imv = tncs_global_data->imv;
    1076           3 :         tncs->connectionID = tncs_global_data->next_conn_id++;
    1077           3 :         tncs->next = tncs_global_data->connections;
    1078           3 :         tncs_global_data->connections = tncs;
    1079             : 
    1080           3 :         return tncs;
    1081             : }
    1082             : 
    1083             : 
    1084           3 : void tncs_deinit(struct tncs_data *tncs)
    1085             : {
    1086             :         int i;
    1087             :         struct tncs_data *prev, *conn;
    1088             : 
    1089           3 :         if (tncs == NULL)
    1090           3 :                 return;
    1091             : 
    1092          33 :         for (i = 0; i < TNC_MAX_IMV_ID; i++)
    1093          30 :                 os_free(tncs->imv_data[i].imv_send);
    1094             : 
    1095           3 :         prev = NULL;
    1096           3 :         conn = tncs_global_data->connections;
    1097           6 :         while (conn) {
    1098           3 :                 if (conn == tncs) {
    1099           3 :                         if (prev)
    1100           0 :                                 prev->next = tncs->next;
    1101             :                         else
    1102           3 :                                 tncs_global_data->connections = tncs->next;
    1103           3 :                         break;
    1104             :                 }
    1105           0 :                 prev = conn;
    1106           0 :                 conn = conn->next;
    1107             :         }
    1108             : 
    1109           3 :         os_free(tncs->tncs_message);
    1110           3 :         os_free(tncs);
    1111             : }
    1112             : 
    1113             : 
    1114           4 : int tncs_global_init(void)
    1115             : {
    1116             :         struct tnc_if_imv *imv;
    1117             : 
    1118           4 :         if (tncs_global_data)
    1119           0 :                 return 0;
    1120             : 
    1121           4 :         tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
    1122           4 :         if (tncs_global_data == NULL)
    1123           0 :                 return -1;
    1124             : 
    1125           4 :         if (tncs_read_config(tncs_global_data) < 0) {
    1126           0 :                 wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
    1127           0 :                 goto failed;
    1128             :         }
    1129             : 
    1130          12 :         for (imv = tncs_global_data->imv; imv; imv = imv->next) {
    1131           8 :                 if (tncs_load_imv(imv)) {
    1132           0 :                         wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
    1133             :                                    imv->name);
    1134           0 :                         goto failed;
    1135             :                 }
    1136             :         }
    1137             : 
    1138           4 :         return 0;
    1139             : 
    1140             : failed:
    1141           0 :         tncs_global_deinit();
    1142           0 :         return -1;
    1143             : }
    1144             : 
    1145             : 
    1146          25 : void tncs_global_deinit(void)
    1147             : {
    1148             :         struct tnc_if_imv *imv, *prev;
    1149             : 
    1150          25 :         if (tncs_global_data == NULL)
    1151          46 :                 return;
    1152             : 
    1153           4 :         imv = tncs_global_data->imv;
    1154          16 :         while (imv) {
    1155           8 :                 tncs_unload_imv(imv);
    1156             : 
    1157           8 :                 prev = imv;
    1158           8 :                 imv = imv->next;
    1159           8 :                 os_free(prev);
    1160             :         }
    1161             : 
    1162           4 :         os_free(tncs_global_data);
    1163           4 :         tncs_global_data = NULL;
    1164             : }
    1165             : 
    1166             : 
    1167           3 : struct wpabuf * tncs_build_soh_request(void)
    1168             : {
    1169             :         struct wpabuf *buf;
    1170             : 
    1171             :         /*
    1172             :          * Build a SoH Request TLV (to be used inside SoH EAP Extensions
    1173             :          * Method)
    1174             :          */
    1175             : 
    1176           3 :         buf = wpabuf_alloc(8 + 4);
    1177           3 :         if (buf == NULL)
    1178           0 :                 return NULL;
    1179             : 
    1180             :         /* Vendor-Specific TLV (Microsoft) - SoH Request */
    1181           3 :         wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
    1182           3 :         wpabuf_put_be16(buf, 8); /* Length */
    1183             : 
    1184           3 :         wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
    1185             : 
    1186           3 :         wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
    1187           3 :         wpabuf_put_be16(buf, 0); /* Length */
    1188             : 
    1189           3 :         return buf;
    1190             : }
    1191             : 
    1192             : 
    1193           3 : struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
    1194             :                                  int *failure)
    1195             : {
    1196           3 :         wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
    1197           3 :         *failure = 0;
    1198             : 
    1199             :         /* TODO: return MS-SoH Response TLV */
    1200             : 
    1201           3 :         return NULL;
    1202             : }

Generated by: LCOV version 1.10