LCOV - code coverage report
Current view: top level - src/eap_peer - tncc.c (source / functions) Hit Total Coverage
Test: wpa_supplicant/hostapd combined for hwsim test run 1475438200 Lines: 494 546 90.5 %
Date: 2016-10-02 Functions: 30 33 90.9 %

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

Generated by: LCOV version 1.10