18dbcf02cSchristos /* 28dbcf02cSchristos * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH) 38dbcf02cSchristos * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> 48dbcf02cSchristos * 5e604d861Schristos * This software may be distributed under the terms of the BSD license. 6e604d861Schristos * See README for more details. 78dbcf02cSchristos */ 88dbcf02cSchristos 98dbcf02cSchristos #include "includes.h" 108dbcf02cSchristos #include <dlfcn.h> 118dbcf02cSchristos 128dbcf02cSchristos #include "common.h" 138dbcf02cSchristos #include "base64.h" 143c260e60Schristos #include "common/tnc.h" 158dbcf02cSchristos #include "tncs.h" 168dbcf02cSchristos #include "eap_common/eap_tlv_common.h" 178dbcf02cSchristos #include "eap_common/eap_defs.h" 188dbcf02cSchristos 198dbcf02cSchristos 208dbcf02cSchristos /* TODO: TNCS must be thread-safe; review the code and add locking etc. if 218dbcf02cSchristos * needed.. */ 228dbcf02cSchristos 233c260e60Schristos #ifndef TNC_CONFIG_FILE 248dbcf02cSchristos #define TNC_CONFIG_FILE "/etc/tnc_config" 253c260e60Schristos #endif /* TNC_CONFIG_FILE */ 268dbcf02cSchristos #define IF_TNCCS_START \ 278dbcf02cSchristos "<?xml version=\"1.0\"?>\n" \ 288dbcf02cSchristos "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \ 298dbcf02cSchristos "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \ 308dbcf02cSchristos "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \ 318dbcf02cSchristos "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \ 328dbcf02cSchristos "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n" 338dbcf02cSchristos #define IF_TNCCS_END "\n</TNCCS-Batch>" 348dbcf02cSchristos 358dbcf02cSchristos /* TNC IF-IMV */ 368dbcf02cSchristos 378dbcf02cSchristos struct tnc_if_imv { 388dbcf02cSchristos struct tnc_if_imv *next; 398dbcf02cSchristos char *name; 408dbcf02cSchristos char *path; 418dbcf02cSchristos void *dlhandle; /* from dlopen() */ 428dbcf02cSchristos TNC_IMVID imvID; 438dbcf02cSchristos TNC_MessageTypeList supported_types; 448dbcf02cSchristos size_t num_supported_types; 458dbcf02cSchristos 468dbcf02cSchristos /* Functions implemented by IMVs (with TNC_IMV_ prefix) */ 478dbcf02cSchristos TNC_Result (*Initialize)( 488dbcf02cSchristos TNC_IMVID imvID, 498dbcf02cSchristos TNC_Version minVersion, 508dbcf02cSchristos TNC_Version maxVersion, 518dbcf02cSchristos TNC_Version *pOutActualVersion); 528dbcf02cSchristos TNC_Result (*NotifyConnectionChange)( 538dbcf02cSchristos TNC_IMVID imvID, 548dbcf02cSchristos TNC_ConnectionID connectionID, 558dbcf02cSchristos TNC_ConnectionState newState); 568dbcf02cSchristos TNC_Result (*ReceiveMessage)( 578dbcf02cSchristos TNC_IMVID imvID, 588dbcf02cSchristos TNC_ConnectionID connectionID, 598dbcf02cSchristos TNC_BufferReference message, 608dbcf02cSchristos TNC_UInt32 messageLength, 618dbcf02cSchristos TNC_MessageType messageType); 628dbcf02cSchristos TNC_Result (*SolicitRecommendation)( 638dbcf02cSchristos TNC_IMVID imvID, 648dbcf02cSchristos TNC_ConnectionID connectionID); 658dbcf02cSchristos TNC_Result (*BatchEnding)( 668dbcf02cSchristos TNC_IMVID imvID, 678dbcf02cSchristos TNC_ConnectionID connectionID); 688dbcf02cSchristos TNC_Result (*Terminate)(TNC_IMVID imvID); 698dbcf02cSchristos TNC_Result (*ProvideBindFunction)( 708dbcf02cSchristos TNC_IMVID imvID, 718dbcf02cSchristos TNC_TNCS_BindFunctionPointer bindFunction); 728dbcf02cSchristos }; 738dbcf02cSchristos 748dbcf02cSchristos 758dbcf02cSchristos #define TNC_MAX_IMV_ID 10 768dbcf02cSchristos 778dbcf02cSchristos struct tncs_data { 788dbcf02cSchristos struct tncs_data *next; 798dbcf02cSchristos struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */ 808dbcf02cSchristos TNC_ConnectionID connectionID; 818dbcf02cSchristos unsigned int last_batchid; 828dbcf02cSchristos enum IMV_Action_Recommendation recommendation; 838dbcf02cSchristos int done; 848dbcf02cSchristos 858dbcf02cSchristos struct conn_imv { 868dbcf02cSchristos u8 *imv_send; 878dbcf02cSchristos size_t imv_send_len; 888dbcf02cSchristos enum IMV_Action_Recommendation recommendation; 898dbcf02cSchristos int recommendation_set; 908dbcf02cSchristos } imv_data[TNC_MAX_IMV_ID]; 918dbcf02cSchristos 928dbcf02cSchristos char *tncs_message; 938dbcf02cSchristos }; 948dbcf02cSchristos 958dbcf02cSchristos 968dbcf02cSchristos struct tncs_global { 978dbcf02cSchristos struct tnc_if_imv *imv; 988dbcf02cSchristos TNC_ConnectionID next_conn_id; 998dbcf02cSchristos struct tncs_data *connections; 1008dbcf02cSchristos }; 1018dbcf02cSchristos 1028dbcf02cSchristos static struct tncs_global *tncs_global_data = NULL; 1038dbcf02cSchristos 1048dbcf02cSchristos 1058dbcf02cSchristos static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID) 1068dbcf02cSchristos { 1078dbcf02cSchristos struct tnc_if_imv *imv; 1088dbcf02cSchristos 1098dbcf02cSchristos if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL) 1108dbcf02cSchristos return NULL; 1118dbcf02cSchristos imv = tncs_global_data->imv; 1128dbcf02cSchristos while (imv) { 1138dbcf02cSchristos if (imv->imvID == imvID) 1148dbcf02cSchristos return imv; 1158dbcf02cSchristos imv = imv->next; 1168dbcf02cSchristos } 1178dbcf02cSchristos return NULL; 1188dbcf02cSchristos } 1198dbcf02cSchristos 1208dbcf02cSchristos 1218dbcf02cSchristos static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID) 1228dbcf02cSchristos { 1238dbcf02cSchristos struct tncs_data *tncs; 1248dbcf02cSchristos 1258dbcf02cSchristos if (tncs_global_data == NULL) 1268dbcf02cSchristos return NULL; 1278dbcf02cSchristos 1288dbcf02cSchristos tncs = tncs_global_data->connections; 1298dbcf02cSchristos while (tncs) { 1308dbcf02cSchristos if (tncs->connectionID == connectionID) 1318dbcf02cSchristos return tncs; 1328dbcf02cSchristos tncs = tncs->next; 1338dbcf02cSchristos } 1348dbcf02cSchristos 1358dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found", 1368dbcf02cSchristos (unsigned long) connectionID); 1378dbcf02cSchristos 1388dbcf02cSchristos return NULL; 1398dbcf02cSchristos } 1408dbcf02cSchristos 1418dbcf02cSchristos 1428dbcf02cSchristos /* TNCS functions that IMVs can call */ 14336ebd06eSchristos static TNC_Result TNC_TNCS_ReportMessageTypes( 1448dbcf02cSchristos TNC_IMVID imvID, 1458dbcf02cSchristos TNC_MessageTypeList supportedTypes, 1468dbcf02cSchristos TNC_UInt32 typeCount) 1478dbcf02cSchristos { 1488dbcf02cSchristos TNC_UInt32 i; 1498dbcf02cSchristos struct tnc_if_imv *imv; 1508dbcf02cSchristos 1518dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu " 1528dbcf02cSchristos "typeCount=%lu)", 1538dbcf02cSchristos (unsigned long) imvID, (unsigned long) typeCount); 1548dbcf02cSchristos 1558dbcf02cSchristos for (i = 0; i < typeCount; i++) { 1568dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu", 1578dbcf02cSchristos i, supportedTypes[i]); 1588dbcf02cSchristos } 1598dbcf02cSchristos 1608dbcf02cSchristos imv = tncs_get_imv(imvID); 1618dbcf02cSchristos if (imv == NULL) 1628dbcf02cSchristos return TNC_RESULT_INVALID_PARAMETER; 1638dbcf02cSchristos os_free(imv->supported_types); 1640a73ee0aSchristos imv->supported_types = os_memdup(supportedTypes, 1650a73ee0aSchristos typeCount * sizeof(TNC_MessageType)); 1668dbcf02cSchristos if (imv->supported_types == NULL) 1678dbcf02cSchristos return TNC_RESULT_FATAL; 1688dbcf02cSchristos imv->num_supported_types = typeCount; 1698dbcf02cSchristos 1708dbcf02cSchristos return TNC_RESULT_SUCCESS; 1718dbcf02cSchristos } 1728dbcf02cSchristos 1738dbcf02cSchristos 17436ebd06eSchristos static TNC_Result TNC_TNCS_SendMessage( 1758dbcf02cSchristos TNC_IMVID imvID, 1768dbcf02cSchristos TNC_ConnectionID connectionID, 1778dbcf02cSchristos TNC_BufferReference message, 1788dbcf02cSchristos TNC_UInt32 messageLength, 1798dbcf02cSchristos TNC_MessageType messageType) 1808dbcf02cSchristos { 1818dbcf02cSchristos struct tncs_data *tncs; 182*bb618362Schristos char *b64; 1838dbcf02cSchristos size_t b64len; 1848dbcf02cSchristos 1858dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu " 1868dbcf02cSchristos "connectionID=%lu messageType=%lu)", 1878dbcf02cSchristos imvID, connectionID, messageType); 1888dbcf02cSchristos wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage", 1898dbcf02cSchristos message, messageLength); 1908dbcf02cSchristos 1918dbcf02cSchristos if (tncs_get_imv(imvID) == NULL) 1928dbcf02cSchristos return TNC_RESULT_INVALID_PARAMETER; 1938dbcf02cSchristos 1948dbcf02cSchristos tncs = tncs_get_conn(connectionID); 1958dbcf02cSchristos if (tncs == NULL) 1968dbcf02cSchristos return TNC_RESULT_INVALID_PARAMETER; 1978dbcf02cSchristos 1988dbcf02cSchristos b64 = base64_encode(message, messageLength, &b64len); 1998dbcf02cSchristos if (b64 == NULL) 2008dbcf02cSchristos return TNC_RESULT_FATAL; 2018dbcf02cSchristos 2028dbcf02cSchristos os_free(tncs->imv_data[imvID].imv_send); 2038dbcf02cSchristos tncs->imv_data[imvID].imv_send_len = 0; 2048dbcf02cSchristos tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100); 2058dbcf02cSchristos if (tncs->imv_data[imvID].imv_send == NULL) { 2068dbcf02cSchristos os_free(b64); 2078dbcf02cSchristos return TNC_RESULT_OTHER; 2088dbcf02cSchristos } 2098dbcf02cSchristos 2108dbcf02cSchristos tncs->imv_data[imvID].imv_send_len = 2118dbcf02cSchristos os_snprintf((char *) tncs->imv_data[imvID].imv_send, 2128dbcf02cSchristos b64len + 100, 2138dbcf02cSchristos "<IMC-IMV-Message><Type>%08X</Type>" 2148dbcf02cSchristos "<Base64>%s</Base64></IMC-IMV-Message>", 2158dbcf02cSchristos (unsigned int) messageType, b64); 2168dbcf02cSchristos 2178dbcf02cSchristos os_free(b64); 2188dbcf02cSchristos 2198dbcf02cSchristos return TNC_RESULT_SUCCESS; 2208dbcf02cSchristos } 2218dbcf02cSchristos 2228dbcf02cSchristos 22336ebd06eSchristos static TNC_Result TNC_TNCS_RequestHandshakeRetry( 2248dbcf02cSchristos TNC_IMVID imvID, 2258dbcf02cSchristos TNC_ConnectionID connectionID, 2268dbcf02cSchristos TNC_RetryReason reason) 2278dbcf02cSchristos { 2288dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry"); 2298dbcf02cSchristos /* TODO */ 2308dbcf02cSchristos return TNC_RESULT_SUCCESS; 2318dbcf02cSchristos } 2328dbcf02cSchristos 2338dbcf02cSchristos 23436ebd06eSchristos static TNC_Result TNC_TNCS_ProvideRecommendation( 2358dbcf02cSchristos TNC_IMVID imvID, 2368dbcf02cSchristos TNC_ConnectionID connectionID, 2378dbcf02cSchristos TNC_IMV_Action_Recommendation recommendation, 2388dbcf02cSchristos TNC_IMV_Evaluation_Result evaluation) 2398dbcf02cSchristos { 2408dbcf02cSchristos struct tncs_data *tncs; 2418dbcf02cSchristos 2428dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu " 2438dbcf02cSchristos "connectionID=%lu recommendation=%lu evaluation=%lu)", 2448dbcf02cSchristos (unsigned long) imvID, (unsigned long) connectionID, 2458dbcf02cSchristos (unsigned long) recommendation, (unsigned long) evaluation); 2468dbcf02cSchristos 2478dbcf02cSchristos if (tncs_get_imv(imvID) == NULL) 2488dbcf02cSchristos return TNC_RESULT_INVALID_PARAMETER; 2498dbcf02cSchristos 2508dbcf02cSchristos tncs = tncs_get_conn(connectionID); 2518dbcf02cSchristos if (tncs == NULL) 2528dbcf02cSchristos return TNC_RESULT_INVALID_PARAMETER; 2538dbcf02cSchristos 2548dbcf02cSchristos tncs->imv_data[imvID].recommendation = recommendation; 2558dbcf02cSchristos tncs->imv_data[imvID].recommendation_set = 1; 2568dbcf02cSchristos 2578dbcf02cSchristos return TNC_RESULT_SUCCESS; 2588dbcf02cSchristos } 2598dbcf02cSchristos 2608dbcf02cSchristos 26136ebd06eSchristos static TNC_Result TNC_TNCS_GetAttribute( 2628dbcf02cSchristos TNC_IMVID imvID, 2638dbcf02cSchristos TNC_ConnectionID connectionID, 2648dbcf02cSchristos TNC_AttributeID attribureID, 2658dbcf02cSchristos TNC_UInt32 bufferLength, 2668dbcf02cSchristos TNC_BufferReference buffer, 2678dbcf02cSchristos TNC_UInt32 *pOutValueLength) 2688dbcf02cSchristos { 2698dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute"); 2708dbcf02cSchristos /* TODO */ 2718dbcf02cSchristos return TNC_RESULT_SUCCESS; 2728dbcf02cSchristos } 2738dbcf02cSchristos 2748dbcf02cSchristos 27536ebd06eSchristos static TNC_Result TNC_TNCS_SetAttribute( 2768dbcf02cSchristos TNC_IMVID imvID, 2778dbcf02cSchristos TNC_ConnectionID connectionID, 2788dbcf02cSchristos TNC_AttributeID attribureID, 2798dbcf02cSchristos TNC_UInt32 bufferLength, 2808dbcf02cSchristos TNC_BufferReference buffer) 2818dbcf02cSchristos { 2828dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute"); 2838dbcf02cSchristos /* TODO */ 2848dbcf02cSchristos return TNC_RESULT_SUCCESS; 2858dbcf02cSchristos } 2868dbcf02cSchristos 2878dbcf02cSchristos 28836ebd06eSchristos static TNC_Result TNC_TNCS_BindFunction( 2898dbcf02cSchristos TNC_IMVID imvID, 2908dbcf02cSchristos char *functionName, 2918dbcf02cSchristos void **pOutFunctionPointer) 2928dbcf02cSchristos { 2938dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, " 2948dbcf02cSchristos "functionName='%s')", (unsigned long) imvID, functionName); 2958dbcf02cSchristos 2968dbcf02cSchristos if (tncs_get_imv(imvID) == NULL) 2978dbcf02cSchristos return TNC_RESULT_INVALID_PARAMETER; 2988dbcf02cSchristos 2998dbcf02cSchristos if (pOutFunctionPointer == NULL) 3008dbcf02cSchristos return TNC_RESULT_INVALID_PARAMETER; 3018dbcf02cSchristos 3028dbcf02cSchristos if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0) 3038dbcf02cSchristos *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes; 3048dbcf02cSchristos else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0) 3058dbcf02cSchristos *pOutFunctionPointer = TNC_TNCS_SendMessage; 3068dbcf02cSchristos else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") == 3078dbcf02cSchristos 0) 3088dbcf02cSchristos *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry; 3098dbcf02cSchristos else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") == 3108dbcf02cSchristos 0) 3118dbcf02cSchristos *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation; 3128dbcf02cSchristos else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0) 3138dbcf02cSchristos *pOutFunctionPointer = TNC_TNCS_GetAttribute; 3148dbcf02cSchristos else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0) 3158dbcf02cSchristos *pOutFunctionPointer = TNC_TNCS_SetAttribute; 3168dbcf02cSchristos else 3178dbcf02cSchristos *pOutFunctionPointer = NULL; 3188dbcf02cSchristos 3198dbcf02cSchristos return TNC_RESULT_SUCCESS; 3208dbcf02cSchristos } 3218dbcf02cSchristos 3228dbcf02cSchristos 3238dbcf02cSchristos static void * tncs_get_sym(void *handle, char *func) 3248dbcf02cSchristos { 3258dbcf02cSchristos void *fptr; 3268dbcf02cSchristos 3278dbcf02cSchristos fptr = dlsym(handle, func); 3288dbcf02cSchristos 3298dbcf02cSchristos return fptr; 3308dbcf02cSchristos } 3318dbcf02cSchristos 3328dbcf02cSchristos 3338dbcf02cSchristos static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv) 3348dbcf02cSchristos { 3358dbcf02cSchristos void *handle = imv->dlhandle; 3368dbcf02cSchristos 3378dbcf02cSchristos /* Mandatory IMV functions */ 3388dbcf02cSchristos imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize"); 3398dbcf02cSchristos if (imv->Initialize == NULL) { 3408dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: IMV does not export " 3418dbcf02cSchristos "TNC_IMV_Initialize"); 3428dbcf02cSchristos return -1; 3438dbcf02cSchristos } 3448dbcf02cSchristos 3458dbcf02cSchristos imv->SolicitRecommendation = tncs_get_sym( 3468dbcf02cSchristos handle, "TNC_IMV_SolicitRecommendation"); 3478dbcf02cSchristos if (imv->SolicitRecommendation == NULL) { 3488dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: IMV does not export " 3498dbcf02cSchristos "TNC_IMV_SolicitRecommendation"); 3508dbcf02cSchristos return -1; 3518dbcf02cSchristos } 3528dbcf02cSchristos 3538dbcf02cSchristos imv->ProvideBindFunction = 3548dbcf02cSchristos tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction"); 3558dbcf02cSchristos if (imv->ProvideBindFunction == NULL) { 3568dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: IMV does not export " 3578dbcf02cSchristos "TNC_IMV_ProvideBindFunction"); 3588dbcf02cSchristos return -1; 3598dbcf02cSchristos } 3608dbcf02cSchristos 3618dbcf02cSchristos /* Optional IMV functions */ 3628dbcf02cSchristos imv->NotifyConnectionChange = 3638dbcf02cSchristos tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange"); 3648dbcf02cSchristos imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage"); 3658dbcf02cSchristos imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding"); 3668dbcf02cSchristos imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate"); 3678dbcf02cSchristos 3688dbcf02cSchristos return 0; 3698dbcf02cSchristos } 3708dbcf02cSchristos 3718dbcf02cSchristos 3728dbcf02cSchristos static int tncs_imv_initialize(struct tnc_if_imv *imv) 3738dbcf02cSchristos { 3748dbcf02cSchristos TNC_Result res; 3758dbcf02cSchristos TNC_Version imv_ver; 3768dbcf02cSchristos 3778dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'", 3788dbcf02cSchristos imv->name); 3798dbcf02cSchristos res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1, 3808dbcf02cSchristos TNC_IFIMV_VERSION_1, &imv_ver); 3818dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu", 3828dbcf02cSchristos (unsigned long) res, (unsigned long) imv_ver); 3838dbcf02cSchristos 3848dbcf02cSchristos return res == TNC_RESULT_SUCCESS ? 0 : -1; 3858dbcf02cSchristos } 3868dbcf02cSchristos 3878dbcf02cSchristos 3888dbcf02cSchristos static int tncs_imv_terminate(struct tnc_if_imv *imv) 3898dbcf02cSchristos { 3908dbcf02cSchristos TNC_Result res; 3918dbcf02cSchristos 3928dbcf02cSchristos if (imv->Terminate == NULL) 3938dbcf02cSchristos return 0; 3948dbcf02cSchristos 3958dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'", 3968dbcf02cSchristos imv->name); 3978dbcf02cSchristos res = imv->Terminate(imv->imvID); 3988dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu", 3998dbcf02cSchristos (unsigned long) res); 4008dbcf02cSchristos 4018dbcf02cSchristos return res == TNC_RESULT_SUCCESS ? 0 : -1; 4028dbcf02cSchristos } 4038dbcf02cSchristos 4048dbcf02cSchristos 4058dbcf02cSchristos static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv) 4068dbcf02cSchristos { 4078dbcf02cSchristos TNC_Result res; 4088dbcf02cSchristos 4098dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for " 4108dbcf02cSchristos "IMV '%s'", imv->name); 4118dbcf02cSchristos res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction); 4128dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu", 4138dbcf02cSchristos (unsigned long) res); 4148dbcf02cSchristos 4158dbcf02cSchristos return res == TNC_RESULT_SUCCESS ? 0 : -1; 4168dbcf02cSchristos } 4178dbcf02cSchristos 4188dbcf02cSchristos 4198dbcf02cSchristos static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv, 4208dbcf02cSchristos TNC_ConnectionID conn, 4218dbcf02cSchristos TNC_ConnectionState state) 4228dbcf02cSchristos { 4238dbcf02cSchristos TNC_Result res; 4248dbcf02cSchristos 4258dbcf02cSchristos if (imv->NotifyConnectionChange == NULL) 4268dbcf02cSchristos return 0; 4278dbcf02cSchristos 4288dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)" 4298dbcf02cSchristos " for IMV '%s'", (int) state, imv->name); 4308dbcf02cSchristos res = imv->NotifyConnectionChange(imv->imvID, conn, state); 4318dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu", 4328dbcf02cSchristos (unsigned long) res); 4338dbcf02cSchristos 4348dbcf02cSchristos return res == TNC_RESULT_SUCCESS ? 0 : -1; 4358dbcf02cSchristos } 4368dbcf02cSchristos 4378dbcf02cSchristos 4388dbcf02cSchristos static int tncs_load_imv(struct tnc_if_imv *imv) 4398dbcf02cSchristos { 4408dbcf02cSchristos if (imv->path == NULL) { 4418dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: No IMV configured"); 4428dbcf02cSchristos return -1; 4438dbcf02cSchristos } 4448dbcf02cSchristos 4458dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)", 4468dbcf02cSchristos imv->name, imv->path); 4478dbcf02cSchristos imv->dlhandle = dlopen(imv->path, RTLD_LAZY); 4488dbcf02cSchristos if (imv->dlhandle == NULL) { 4498dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s", 4508dbcf02cSchristos imv->name, imv->path, dlerror()); 4518dbcf02cSchristos return -1; 4528dbcf02cSchristos } 4538dbcf02cSchristos 4548dbcf02cSchristos if (tncs_imv_resolve_funcs(imv) < 0) { 4558dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions"); 4568dbcf02cSchristos return -1; 4578dbcf02cSchristos } 4588dbcf02cSchristos 4598dbcf02cSchristos if (tncs_imv_initialize(imv) < 0 || 4608dbcf02cSchristos tncs_imv_provide_bind_function(imv) < 0) { 4618dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV"); 4628dbcf02cSchristos return -1; 4638dbcf02cSchristos } 4648dbcf02cSchristos 4658dbcf02cSchristos return 0; 4668dbcf02cSchristos } 4678dbcf02cSchristos 4688dbcf02cSchristos 4698dbcf02cSchristos static void tncs_free_imv(struct tnc_if_imv *imv) 4708dbcf02cSchristos { 4718dbcf02cSchristos os_free(imv->name); 4728dbcf02cSchristos os_free(imv->path); 4738dbcf02cSchristos os_free(imv->supported_types); 4748dbcf02cSchristos } 4758dbcf02cSchristos 4768dbcf02cSchristos static void tncs_unload_imv(struct tnc_if_imv *imv) 4778dbcf02cSchristos { 4788dbcf02cSchristos tncs_imv_terminate(imv); 4798dbcf02cSchristos 4808dbcf02cSchristos if (imv->dlhandle) 4818dbcf02cSchristos dlclose(imv->dlhandle); 4828dbcf02cSchristos 4838dbcf02cSchristos tncs_free_imv(imv); 4848dbcf02cSchristos } 4858dbcf02cSchristos 4868dbcf02cSchristos 4878dbcf02cSchristos static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type) 4888dbcf02cSchristos { 4898dbcf02cSchristos size_t i; 4908dbcf02cSchristos unsigned int vendor, subtype; 4918dbcf02cSchristos 4928dbcf02cSchristos if (imv == NULL || imv->supported_types == NULL) 4938dbcf02cSchristos return 0; 4948dbcf02cSchristos 4958dbcf02cSchristos vendor = type >> 8; 4968dbcf02cSchristos subtype = type & 0xff; 4978dbcf02cSchristos 4988dbcf02cSchristos for (i = 0; i < imv->num_supported_types; i++) { 4998dbcf02cSchristos unsigned int svendor, ssubtype; 5008dbcf02cSchristos svendor = imv->supported_types[i] >> 8; 5018dbcf02cSchristos ssubtype = imv->supported_types[i] & 0xff; 5028dbcf02cSchristos if ((vendor == svendor || svendor == TNC_VENDORID_ANY) && 5038dbcf02cSchristos (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY)) 5048dbcf02cSchristos return 1; 5058dbcf02cSchristos } 5068dbcf02cSchristos 5078dbcf02cSchristos return 0; 5088dbcf02cSchristos } 5098dbcf02cSchristos 5108dbcf02cSchristos 5118dbcf02cSchristos static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type, 5128dbcf02cSchristos const u8 *msg, size_t len) 5138dbcf02cSchristos { 5148dbcf02cSchristos struct tnc_if_imv *imv; 5158dbcf02cSchristos TNC_Result res; 5168dbcf02cSchristos 5178dbcf02cSchristos wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len); 5188dbcf02cSchristos 5198dbcf02cSchristos for (imv = tncs->imv; imv; imv = imv->next) { 5208dbcf02cSchristos if (imv->ReceiveMessage == NULL || 5218dbcf02cSchristos !tncs_supported_type(imv, type)) 5228dbcf02cSchristos continue; 5238dbcf02cSchristos 5248dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'", 5258dbcf02cSchristos imv->name); 5268dbcf02cSchristos res = imv->ReceiveMessage(imv->imvID, tncs->connectionID, 5278dbcf02cSchristos (TNC_BufferReference) msg, len, 5288dbcf02cSchristos type); 5298dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu", 5308dbcf02cSchristos (unsigned long) res); 5318dbcf02cSchristos } 5328dbcf02cSchristos } 5338dbcf02cSchristos 5348dbcf02cSchristos 5358dbcf02cSchristos static void tncs_batch_ending(struct tncs_data *tncs) 5368dbcf02cSchristos { 5378dbcf02cSchristos struct tnc_if_imv *imv; 5388dbcf02cSchristos TNC_Result res; 5398dbcf02cSchristos 5408dbcf02cSchristos for (imv = tncs->imv; imv; imv = imv->next) { 5418dbcf02cSchristos if (imv->BatchEnding == NULL) 5428dbcf02cSchristos continue; 5438dbcf02cSchristos 5448dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'", 5458dbcf02cSchristos imv->name); 5468dbcf02cSchristos res = imv->BatchEnding(imv->imvID, tncs->connectionID); 5478dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu", 5488dbcf02cSchristos (unsigned long) res); 5498dbcf02cSchristos } 5508dbcf02cSchristos } 5518dbcf02cSchristos 5528dbcf02cSchristos 5538dbcf02cSchristos static void tncs_solicit_recommendation(struct tncs_data *tncs) 5548dbcf02cSchristos { 5558dbcf02cSchristos struct tnc_if_imv *imv; 5568dbcf02cSchristos TNC_Result res; 5578dbcf02cSchristos 5588dbcf02cSchristos for (imv = tncs->imv; imv; imv = imv->next) { 5598dbcf02cSchristos if (tncs->imv_data[imv->imvID].recommendation_set) 5608dbcf02cSchristos continue; 5618dbcf02cSchristos 5628dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for " 5638dbcf02cSchristos "IMV '%s'", imv->name); 5648dbcf02cSchristos res = imv->SolicitRecommendation(imv->imvID, 5658dbcf02cSchristos tncs->connectionID); 5668dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu", 5678dbcf02cSchristos (unsigned long) res); 5688dbcf02cSchristos } 5698dbcf02cSchristos } 5708dbcf02cSchristos 5718dbcf02cSchristos 5728dbcf02cSchristos void tncs_init_connection(struct tncs_data *tncs) 5738dbcf02cSchristos { 5748dbcf02cSchristos struct tnc_if_imv *imv; 5758dbcf02cSchristos int i; 5768dbcf02cSchristos 5778dbcf02cSchristos for (imv = tncs->imv; imv; imv = imv->next) { 5788dbcf02cSchristos tncs_imv_notify_connection_change( 5798dbcf02cSchristos imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE); 5808dbcf02cSchristos tncs_imv_notify_connection_change( 5818dbcf02cSchristos imv, tncs->connectionID, 5828dbcf02cSchristos TNC_CONNECTION_STATE_HANDSHAKE); 5838dbcf02cSchristos } 5848dbcf02cSchristos 5858dbcf02cSchristos for (i = 0; i < TNC_MAX_IMV_ID; i++) { 5868dbcf02cSchristos os_free(tncs->imv_data[i].imv_send); 5878dbcf02cSchristos tncs->imv_data[i].imv_send = NULL; 5888dbcf02cSchristos tncs->imv_data[i].imv_send_len = 0; 5898dbcf02cSchristos } 5908dbcf02cSchristos } 5918dbcf02cSchristos 5928dbcf02cSchristos 5938dbcf02cSchristos size_t tncs_total_send_len(struct tncs_data *tncs) 5948dbcf02cSchristos { 5958dbcf02cSchristos int i; 5968dbcf02cSchristos size_t len = 0; 5978dbcf02cSchristos 5988dbcf02cSchristos for (i = 0; i < TNC_MAX_IMV_ID; i++) 5998dbcf02cSchristos len += tncs->imv_data[i].imv_send_len; 6008dbcf02cSchristos if (tncs->tncs_message) 6018dbcf02cSchristos len += os_strlen(tncs->tncs_message); 6028dbcf02cSchristos return len; 6038dbcf02cSchristos } 6048dbcf02cSchristos 6058dbcf02cSchristos 6068dbcf02cSchristos u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos) 6078dbcf02cSchristos { 6088dbcf02cSchristos int i; 6098dbcf02cSchristos 6108dbcf02cSchristos for (i = 0; i < TNC_MAX_IMV_ID; i++) { 6118dbcf02cSchristos if (tncs->imv_data[i].imv_send == NULL) 6128dbcf02cSchristos continue; 6138dbcf02cSchristos 6148dbcf02cSchristos os_memcpy(pos, tncs->imv_data[i].imv_send, 6158dbcf02cSchristos tncs->imv_data[i].imv_send_len); 6168dbcf02cSchristos pos += tncs->imv_data[i].imv_send_len; 6178dbcf02cSchristos os_free(tncs->imv_data[i].imv_send); 6188dbcf02cSchristos tncs->imv_data[i].imv_send = NULL; 6198dbcf02cSchristos tncs->imv_data[i].imv_send_len = 0; 6208dbcf02cSchristos } 6218dbcf02cSchristos 6228dbcf02cSchristos if (tncs->tncs_message) { 6238dbcf02cSchristos size_t len = os_strlen(tncs->tncs_message); 6248dbcf02cSchristos os_memcpy(pos, tncs->tncs_message, len); 6258dbcf02cSchristos pos += len; 6268dbcf02cSchristos os_free(tncs->tncs_message); 6278dbcf02cSchristos tncs->tncs_message = NULL; 6288dbcf02cSchristos } 6298dbcf02cSchristos 6308dbcf02cSchristos return pos; 6318dbcf02cSchristos } 6328dbcf02cSchristos 6338dbcf02cSchristos 6348dbcf02cSchristos char * tncs_if_tnccs_start(struct tncs_data *tncs) 6358dbcf02cSchristos { 6368dbcf02cSchristos char *buf = os_malloc(1000); 6378dbcf02cSchristos if (buf == NULL) 6388dbcf02cSchristos return NULL; 6398dbcf02cSchristos tncs->last_batchid++; 6408dbcf02cSchristos os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid); 6418dbcf02cSchristos return buf; 6428dbcf02cSchristos } 6438dbcf02cSchristos 6448dbcf02cSchristos 6458dbcf02cSchristos char * tncs_if_tnccs_end(void) 6468dbcf02cSchristos { 6478dbcf02cSchristos char *buf = os_malloc(100); 6488dbcf02cSchristos if (buf == NULL) 6498dbcf02cSchristos return NULL; 6508dbcf02cSchristos os_snprintf(buf, 100, IF_TNCCS_END); 6518dbcf02cSchristos return buf; 6528dbcf02cSchristos } 6538dbcf02cSchristos 6548dbcf02cSchristos 6558dbcf02cSchristos static int tncs_get_type(char *start, unsigned int *type) 6568dbcf02cSchristos { 6578dbcf02cSchristos char *pos = os_strstr(start, "<Type>"); 6588dbcf02cSchristos if (pos == NULL) 6598dbcf02cSchristos return -1; 6608dbcf02cSchristos pos += 6; 6618dbcf02cSchristos *type = strtoul(pos, NULL, 16); 6628dbcf02cSchristos return 0; 6638dbcf02cSchristos } 6648dbcf02cSchristos 6658dbcf02cSchristos 6668dbcf02cSchristos static unsigned char * tncs_get_base64(char *start, size_t *decoded_len) 6678dbcf02cSchristos { 6688dbcf02cSchristos char *pos, *pos2; 6698dbcf02cSchristos unsigned char *decoded; 6708dbcf02cSchristos 6718dbcf02cSchristos pos = os_strstr(start, "<Base64>"); 6728dbcf02cSchristos if (pos == NULL) 6738dbcf02cSchristos return NULL; 6748dbcf02cSchristos 6758dbcf02cSchristos pos += 8; 6768dbcf02cSchristos pos2 = os_strstr(pos, "</Base64>"); 6778dbcf02cSchristos if (pos2 == NULL) 6788dbcf02cSchristos return NULL; 6798dbcf02cSchristos *pos2 = '\0'; 6808dbcf02cSchristos 681*bb618362Schristos decoded = base64_decode(pos, os_strlen(pos), decoded_len); 6828dbcf02cSchristos *pos2 = '<'; 6838dbcf02cSchristos if (decoded == NULL) { 6848dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data"); 6858dbcf02cSchristos } 6868dbcf02cSchristos 6878dbcf02cSchristos return decoded; 6888dbcf02cSchristos } 6898dbcf02cSchristos 6908dbcf02cSchristos 6918dbcf02cSchristos static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs) 6928dbcf02cSchristos { 6938dbcf02cSchristos enum IMV_Action_Recommendation rec; 6948dbcf02cSchristos struct tnc_if_imv *imv; 6958dbcf02cSchristos TNC_ConnectionState state; 6968dbcf02cSchristos char *txt; 6978dbcf02cSchristos 6988dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs"); 6998dbcf02cSchristos 7008dbcf02cSchristos if (tncs->done) 7018dbcf02cSchristos return TNCCS_PROCESS_OK_NO_RECOMMENDATION; 7028dbcf02cSchristos 7038dbcf02cSchristos tncs_solicit_recommendation(tncs); 7048dbcf02cSchristos 7058dbcf02cSchristos /* Select the most restrictive recommendation */ 7068dbcf02cSchristos rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION; 7078dbcf02cSchristos for (imv = tncs->imv; imv; imv = imv->next) { 7088dbcf02cSchristos TNC_IMV_Action_Recommendation irec; 7098dbcf02cSchristos irec = tncs->imv_data[imv->imvID].recommendation; 7108dbcf02cSchristos if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS) 7118dbcf02cSchristos rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS; 7128dbcf02cSchristos if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE && 7138dbcf02cSchristos rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS) 7148dbcf02cSchristos rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE; 7158dbcf02cSchristos if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW && 7168dbcf02cSchristos rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION) 7178dbcf02cSchristos rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW; 7188dbcf02cSchristos } 7198dbcf02cSchristos 7208dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec); 7218dbcf02cSchristos tncs->recommendation = rec; 7228dbcf02cSchristos tncs->done = 1; 7238dbcf02cSchristos 7248dbcf02cSchristos txt = NULL; 7258dbcf02cSchristos switch (rec) { 7268dbcf02cSchristos case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: 7278dbcf02cSchristos case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: 7288dbcf02cSchristos txt = "allow"; 7298dbcf02cSchristos state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; 7308dbcf02cSchristos break; 7318dbcf02cSchristos case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: 7328dbcf02cSchristos txt = "isolate"; 7338dbcf02cSchristos state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; 7348dbcf02cSchristos break; 7358dbcf02cSchristos case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: 7368dbcf02cSchristos txt = "none"; 7378dbcf02cSchristos state = TNC_CONNECTION_STATE_ACCESS_NONE; 7388dbcf02cSchristos break; 7398dbcf02cSchristos default: 7408dbcf02cSchristos state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; 7418dbcf02cSchristos break; 7428dbcf02cSchristos } 7438dbcf02cSchristos 7448dbcf02cSchristos if (txt) { 7458dbcf02cSchristos os_free(tncs->tncs_message); 7468dbcf02cSchristos tncs->tncs_message = os_zalloc(200); 7478dbcf02cSchristos if (tncs->tncs_message) { 7488dbcf02cSchristos os_snprintf(tncs->tncs_message, 199, 7498dbcf02cSchristos "<TNCC-TNCS-Message><Type>%08X</Type>" 7508dbcf02cSchristos "<XML><TNCCS-Recommendation type=\"%s\">" 7518dbcf02cSchristos "</TNCCS-Recommendation></XML>" 7528dbcf02cSchristos "</TNCC-TNCS-Message>", 7538dbcf02cSchristos TNC_TNCCS_RECOMMENDATION, txt); 7548dbcf02cSchristos } 7558dbcf02cSchristos } 7568dbcf02cSchristos 7578dbcf02cSchristos for (imv = tncs->imv; imv; imv = imv->next) { 7588dbcf02cSchristos tncs_imv_notify_connection_change(imv, tncs->connectionID, 7598dbcf02cSchristos state); 7608dbcf02cSchristos } 7618dbcf02cSchristos 7628dbcf02cSchristos switch (rec) { 7638dbcf02cSchristos case TNC_IMV_ACTION_RECOMMENDATION_ALLOW: 7648dbcf02cSchristos return TNCCS_RECOMMENDATION_ALLOW; 7658dbcf02cSchristos case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS: 7668dbcf02cSchristos return TNCCS_RECOMMENDATION_NO_ACCESS; 7678dbcf02cSchristos case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE: 7688dbcf02cSchristos return TNCCS_RECOMMENDATION_ISOLATE; 7698dbcf02cSchristos case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION: 7708dbcf02cSchristos return TNCCS_RECOMMENDATION_NO_RECOMMENDATION; 7718dbcf02cSchristos default: 7728dbcf02cSchristos return TNCCS_PROCESS_ERROR; 7738dbcf02cSchristos } 7748dbcf02cSchristos } 7758dbcf02cSchristos 7768dbcf02cSchristos 7778dbcf02cSchristos enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs, 7788dbcf02cSchristos const u8 *msg, size_t len) 7798dbcf02cSchristos { 7808dbcf02cSchristos char *buf, *start, *end, *pos, *pos2, *payload; 7818dbcf02cSchristos unsigned int batch_id; 7828dbcf02cSchristos unsigned char *decoded; 7838dbcf02cSchristos size_t decoded_len; 7848dbcf02cSchristos 7853c260e60Schristos buf = dup_binstr(msg, len); 7868dbcf02cSchristos if (buf == NULL) 7878dbcf02cSchristos return TNCCS_PROCESS_ERROR; 7888dbcf02cSchristos 7898dbcf02cSchristos start = os_strstr(buf, "<TNCCS-Batch "); 7908dbcf02cSchristos end = os_strstr(buf, "</TNCCS-Batch>"); 7918dbcf02cSchristos if (start == NULL || end == NULL || start > end) { 7928dbcf02cSchristos os_free(buf); 7938dbcf02cSchristos return TNCCS_PROCESS_ERROR; 7948dbcf02cSchristos } 7958dbcf02cSchristos 7968dbcf02cSchristos start += 13; 7978dbcf02cSchristos while (*start == ' ') 7988dbcf02cSchristos start++; 7998dbcf02cSchristos *end = '\0'; 8008dbcf02cSchristos 8018dbcf02cSchristos pos = os_strstr(start, "BatchId="); 8028dbcf02cSchristos if (pos == NULL) { 8038dbcf02cSchristos os_free(buf); 8048dbcf02cSchristos return TNCCS_PROCESS_ERROR; 8058dbcf02cSchristos } 8068dbcf02cSchristos 8078dbcf02cSchristos pos += 8; 8088dbcf02cSchristos if (*pos == '"') 8098dbcf02cSchristos pos++; 8108dbcf02cSchristos batch_id = atoi(pos); 8118dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u", 8128dbcf02cSchristos batch_id); 8138dbcf02cSchristos if (batch_id != tncs->last_batchid + 1) { 8148dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId " 8158dbcf02cSchristos "%u (expected %u)", 8168dbcf02cSchristos batch_id, tncs->last_batchid + 1); 8178dbcf02cSchristos os_free(buf); 8188dbcf02cSchristos return TNCCS_PROCESS_ERROR; 8198dbcf02cSchristos } 8208dbcf02cSchristos tncs->last_batchid = batch_id; 8218dbcf02cSchristos 8228dbcf02cSchristos while (*pos != '\0' && *pos != '>') 8238dbcf02cSchristos pos++; 8248dbcf02cSchristos if (*pos == '\0') { 8258dbcf02cSchristos os_free(buf); 8268dbcf02cSchristos return TNCCS_PROCESS_ERROR; 8278dbcf02cSchristos } 8288dbcf02cSchristos pos++; 8298dbcf02cSchristos payload = start; 8308dbcf02cSchristos 8318dbcf02cSchristos /* 8328dbcf02cSchristos * <IMC-IMV-Message> 8338dbcf02cSchristos * <Type>01234567</Type> 8348dbcf02cSchristos * <Base64>foo==</Base64> 8358dbcf02cSchristos * </IMC-IMV-Message> 8368dbcf02cSchristos */ 8378dbcf02cSchristos 8388dbcf02cSchristos while (*start) { 8398dbcf02cSchristos char *endpos; 8408dbcf02cSchristos unsigned int type; 8418dbcf02cSchristos 8428dbcf02cSchristos pos = os_strstr(start, "<IMC-IMV-Message>"); 8438dbcf02cSchristos if (pos == NULL) 8448dbcf02cSchristos break; 8458dbcf02cSchristos start = pos + 17; 8468dbcf02cSchristos end = os_strstr(start, "</IMC-IMV-Message>"); 8478dbcf02cSchristos if (end == NULL) 8488dbcf02cSchristos break; 8498dbcf02cSchristos *end = '\0'; 8508dbcf02cSchristos endpos = end; 8518dbcf02cSchristos end += 18; 8528dbcf02cSchristos 8538dbcf02cSchristos if (tncs_get_type(start, &type) < 0) { 8548dbcf02cSchristos *endpos = '<'; 8558dbcf02cSchristos start = end; 8568dbcf02cSchristos continue; 8578dbcf02cSchristos } 8588dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type); 8598dbcf02cSchristos 8608dbcf02cSchristos decoded = tncs_get_base64(start, &decoded_len); 8618dbcf02cSchristos if (decoded == NULL) { 8628dbcf02cSchristos *endpos = '<'; 8638dbcf02cSchristos start = end; 8648dbcf02cSchristos continue; 8658dbcf02cSchristos } 8668dbcf02cSchristos 8678dbcf02cSchristos tncs_send_to_imvs(tncs, type, decoded, decoded_len); 8688dbcf02cSchristos 8698dbcf02cSchristos os_free(decoded); 8708dbcf02cSchristos 8718dbcf02cSchristos start = end; 8728dbcf02cSchristos } 8738dbcf02cSchristos 8748dbcf02cSchristos /* 8758dbcf02cSchristos * <TNCC-TNCS-Message> 8768dbcf02cSchristos * <Type>01234567</Type> 8778dbcf02cSchristos * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML> 8788dbcf02cSchristos * <Base64>foo==</Base64> 8798dbcf02cSchristos * </TNCC-TNCS-Message> 8808dbcf02cSchristos */ 8818dbcf02cSchristos 8828dbcf02cSchristos start = payload; 8838dbcf02cSchristos while (*start) { 8848dbcf02cSchristos unsigned int type; 8858dbcf02cSchristos char *xml, *xmlend, *endpos; 8868dbcf02cSchristos 8878dbcf02cSchristos pos = os_strstr(start, "<TNCC-TNCS-Message>"); 8888dbcf02cSchristos if (pos == NULL) 8898dbcf02cSchristos break; 8908dbcf02cSchristos start = pos + 19; 8918dbcf02cSchristos end = os_strstr(start, "</TNCC-TNCS-Message>"); 8928dbcf02cSchristos if (end == NULL) 8938dbcf02cSchristos break; 8948dbcf02cSchristos *end = '\0'; 8958dbcf02cSchristos endpos = end; 8968dbcf02cSchristos end += 20; 8978dbcf02cSchristos 8988dbcf02cSchristos if (tncs_get_type(start, &type) < 0) { 8998dbcf02cSchristos *endpos = '<'; 9008dbcf02cSchristos start = end; 9018dbcf02cSchristos continue; 9028dbcf02cSchristos } 9038dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x", 9048dbcf02cSchristos type); 9058dbcf02cSchristos 9068dbcf02cSchristos /* Base64 OR XML */ 9078dbcf02cSchristos decoded = NULL; 9088dbcf02cSchristos xml = NULL; 9098dbcf02cSchristos xmlend = NULL; 9108dbcf02cSchristos pos = os_strstr(start, "<XML>"); 9118dbcf02cSchristos if (pos) { 9128dbcf02cSchristos pos += 5; 9138dbcf02cSchristos pos2 = os_strstr(pos, "</XML>"); 9148dbcf02cSchristos if (pos2 == NULL) { 9158dbcf02cSchristos *endpos = '<'; 9168dbcf02cSchristos start = end; 9178dbcf02cSchristos continue; 9188dbcf02cSchristos } 9198dbcf02cSchristos xmlend = pos2; 9208dbcf02cSchristos xml = pos; 9218dbcf02cSchristos } else { 9228dbcf02cSchristos decoded = tncs_get_base64(start, &decoded_len); 9238dbcf02cSchristos if (decoded == NULL) { 9248dbcf02cSchristos *endpos = '<'; 9258dbcf02cSchristos start = end; 9268dbcf02cSchristos continue; 9278dbcf02cSchristos } 9288dbcf02cSchristos } 9298dbcf02cSchristos 9308dbcf02cSchristos if (decoded) { 9318dbcf02cSchristos wpa_hexdump_ascii(MSG_MSGDUMP, 9328dbcf02cSchristos "TNC: TNCC-TNCS-Message Base64", 9338dbcf02cSchristos decoded, decoded_len); 9348dbcf02cSchristos os_free(decoded); 9358dbcf02cSchristos } 9368dbcf02cSchristos 9378dbcf02cSchristos if (xml) { 9388dbcf02cSchristos wpa_hexdump_ascii(MSG_MSGDUMP, 9398dbcf02cSchristos "TNC: TNCC-TNCS-Message XML", 9408dbcf02cSchristos (unsigned char *) xml, 9418dbcf02cSchristos xmlend - xml); 9428dbcf02cSchristos } 9438dbcf02cSchristos 9448dbcf02cSchristos start = end; 9458dbcf02cSchristos } 9468dbcf02cSchristos 9478dbcf02cSchristos os_free(buf); 9488dbcf02cSchristos 9498dbcf02cSchristos tncs_batch_ending(tncs); 9508dbcf02cSchristos 9518dbcf02cSchristos if (tncs_total_send_len(tncs) == 0) 9528dbcf02cSchristos return tncs_derive_recommendation(tncs); 9538dbcf02cSchristos 9548dbcf02cSchristos return TNCCS_PROCESS_OK_NO_RECOMMENDATION; 9558dbcf02cSchristos } 9568dbcf02cSchristos 9578dbcf02cSchristos 9588dbcf02cSchristos static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end, 9598dbcf02cSchristos int *error) 9608dbcf02cSchristos { 9618dbcf02cSchristos struct tnc_if_imv *imv; 9628dbcf02cSchristos char *pos, *pos2; 9638dbcf02cSchristos 9648dbcf02cSchristos if (id >= TNC_MAX_IMV_ID) { 9658dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Too many IMVs"); 9668dbcf02cSchristos return NULL; 9678dbcf02cSchristos } 9688dbcf02cSchristos 9698dbcf02cSchristos imv = os_zalloc(sizeof(*imv)); 9708dbcf02cSchristos if (imv == NULL) { 9718dbcf02cSchristos *error = 1; 9728dbcf02cSchristos return NULL; 9738dbcf02cSchristos } 9748dbcf02cSchristos 9758dbcf02cSchristos imv->imvID = id; 9768dbcf02cSchristos 9778dbcf02cSchristos pos = start; 9788dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos); 9798dbcf02cSchristos if (pos + 1 >= end || *pos != '"') { 9808dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " 9818dbcf02cSchristos "(no starting quotation mark)", start); 9828dbcf02cSchristos os_free(imv); 9838dbcf02cSchristos return NULL; 9848dbcf02cSchristos } 9858dbcf02cSchristos 9868dbcf02cSchristos pos++; 9878dbcf02cSchristos pos2 = pos; 9888dbcf02cSchristos while (pos2 < end && *pos2 != '"') 9898dbcf02cSchristos pos2++; 9908dbcf02cSchristos if (pos2 >= end) { 9918dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " 9928dbcf02cSchristos "(no ending quotation mark)", start); 9938dbcf02cSchristos os_free(imv); 9948dbcf02cSchristos return NULL; 9958dbcf02cSchristos } 9968dbcf02cSchristos *pos2 = '\0'; 9978dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos); 9988dbcf02cSchristos imv->name = os_strdup(pos); 9998dbcf02cSchristos 10008dbcf02cSchristos pos = pos2 + 1; 10018dbcf02cSchristos if (pos >= end || *pos != ' ') { 10028dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' " 10038dbcf02cSchristos "(no space after name)", start); 10048dbcf02cSchristos os_free(imv); 10058dbcf02cSchristos return NULL; 10068dbcf02cSchristos } 10078dbcf02cSchristos 10088dbcf02cSchristos pos++; 10098dbcf02cSchristos wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos); 10108dbcf02cSchristos imv->path = os_strdup(pos); 10118dbcf02cSchristos 10128dbcf02cSchristos return imv; 10138dbcf02cSchristos } 10148dbcf02cSchristos 10158dbcf02cSchristos 10168dbcf02cSchristos static int tncs_read_config(struct tncs_global *global) 10178dbcf02cSchristos { 10188dbcf02cSchristos char *config, *end, *pos, *line_end; 10198dbcf02cSchristos size_t config_len; 10208dbcf02cSchristos struct tnc_if_imv *imv, *last; 10218dbcf02cSchristos int id = 0; 10228dbcf02cSchristos 10238dbcf02cSchristos last = NULL; 10248dbcf02cSchristos 10258dbcf02cSchristos config = os_readfile(TNC_CONFIG_FILE, &config_len); 10268dbcf02cSchristos if (config == NULL) { 10278dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration " 10288dbcf02cSchristos "file '%s'", TNC_CONFIG_FILE); 10298dbcf02cSchristos return -1; 10308dbcf02cSchristos } 10318dbcf02cSchristos 10328dbcf02cSchristos end = config + config_len; 10338dbcf02cSchristos for (pos = config; pos < end; pos = line_end + 1) { 10348dbcf02cSchristos line_end = pos; 10358dbcf02cSchristos while (*line_end != '\n' && *line_end != '\r' && 10368dbcf02cSchristos line_end < end) 10378dbcf02cSchristos line_end++; 10388dbcf02cSchristos *line_end = '\0'; 10398dbcf02cSchristos 10408dbcf02cSchristos if (os_strncmp(pos, "IMV ", 4) == 0) { 10418dbcf02cSchristos int error = 0; 10428dbcf02cSchristos 10438dbcf02cSchristos imv = tncs_parse_imv(id++, pos + 4, line_end, &error); 10448dbcf02cSchristos if (error) 10458dbcf02cSchristos return -1; 10468dbcf02cSchristos if (imv) { 10478dbcf02cSchristos if (last == NULL) 10488dbcf02cSchristos global->imv = imv; 10498dbcf02cSchristos else 10508dbcf02cSchristos last->next = imv; 10518dbcf02cSchristos last = imv; 10528dbcf02cSchristos } 10538dbcf02cSchristos } 10548dbcf02cSchristos } 10558dbcf02cSchristos 10568dbcf02cSchristos os_free(config); 10578dbcf02cSchristos 10588dbcf02cSchristos return 0; 10598dbcf02cSchristos } 10608dbcf02cSchristos 10618dbcf02cSchristos 10628dbcf02cSchristos struct tncs_data * tncs_init(void) 10638dbcf02cSchristos { 10648dbcf02cSchristos struct tncs_data *tncs; 10658dbcf02cSchristos 10668dbcf02cSchristos if (tncs_global_data == NULL) 10678dbcf02cSchristos return NULL; 10688dbcf02cSchristos 10698dbcf02cSchristos tncs = os_zalloc(sizeof(*tncs)); 10708dbcf02cSchristos if (tncs == NULL) 10718dbcf02cSchristos return NULL; 10728dbcf02cSchristos tncs->imv = tncs_global_data->imv; 10738dbcf02cSchristos tncs->connectionID = tncs_global_data->next_conn_id++; 10748dbcf02cSchristos tncs->next = tncs_global_data->connections; 10758dbcf02cSchristos tncs_global_data->connections = tncs; 10768dbcf02cSchristos 10778dbcf02cSchristos return tncs; 10788dbcf02cSchristos } 10798dbcf02cSchristos 10808dbcf02cSchristos 10818dbcf02cSchristos void tncs_deinit(struct tncs_data *tncs) 10828dbcf02cSchristos { 10838dbcf02cSchristos int i; 10848dbcf02cSchristos struct tncs_data *prev, *conn; 10858dbcf02cSchristos 10868dbcf02cSchristos if (tncs == NULL) 10878dbcf02cSchristos return; 10888dbcf02cSchristos 10898dbcf02cSchristos for (i = 0; i < TNC_MAX_IMV_ID; i++) 10908dbcf02cSchristos os_free(tncs->imv_data[i].imv_send); 10918dbcf02cSchristos 10928dbcf02cSchristos prev = NULL; 10938dbcf02cSchristos conn = tncs_global_data->connections; 10948dbcf02cSchristos while (conn) { 10958dbcf02cSchristos if (conn == tncs) { 10968dbcf02cSchristos if (prev) 10978dbcf02cSchristos prev->next = tncs->next; 10988dbcf02cSchristos else 10998dbcf02cSchristos tncs_global_data->connections = tncs->next; 11008dbcf02cSchristos break; 11018dbcf02cSchristos } 11028dbcf02cSchristos prev = conn; 11038dbcf02cSchristos conn = conn->next; 11048dbcf02cSchristos } 11058dbcf02cSchristos 11068dbcf02cSchristos os_free(tncs->tncs_message); 11078dbcf02cSchristos os_free(tncs); 11088dbcf02cSchristos } 11098dbcf02cSchristos 11108dbcf02cSchristos 11118dbcf02cSchristos int tncs_global_init(void) 11128dbcf02cSchristos { 11138dbcf02cSchristos struct tnc_if_imv *imv; 11148dbcf02cSchristos 11153c260e60Schristos if (tncs_global_data) 11163c260e60Schristos return 0; 11173c260e60Schristos 11188dbcf02cSchristos tncs_global_data = os_zalloc(sizeof(*tncs_global_data)); 11198dbcf02cSchristos if (tncs_global_data == NULL) 11208dbcf02cSchristos return -1; 11218dbcf02cSchristos 11228dbcf02cSchristos if (tncs_read_config(tncs_global_data) < 0) { 11238dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration"); 11248dbcf02cSchristos goto failed; 11258dbcf02cSchristos } 11268dbcf02cSchristos 11278dbcf02cSchristos for (imv = tncs_global_data->imv; imv; imv = imv->next) { 11288dbcf02cSchristos if (tncs_load_imv(imv)) { 11298dbcf02cSchristos wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'", 11308dbcf02cSchristos imv->name); 11318dbcf02cSchristos goto failed; 11328dbcf02cSchristos } 11338dbcf02cSchristos } 11348dbcf02cSchristos 11358dbcf02cSchristos return 0; 11368dbcf02cSchristos 11378dbcf02cSchristos failed: 11388dbcf02cSchristos tncs_global_deinit(); 11398dbcf02cSchristos return -1; 11408dbcf02cSchristos } 11418dbcf02cSchristos 11428dbcf02cSchristos 11438dbcf02cSchristos void tncs_global_deinit(void) 11448dbcf02cSchristos { 11458dbcf02cSchristos struct tnc_if_imv *imv, *prev; 11468dbcf02cSchristos 11478dbcf02cSchristos if (tncs_global_data == NULL) 11488dbcf02cSchristos return; 11498dbcf02cSchristos 11508dbcf02cSchristos imv = tncs_global_data->imv; 11518dbcf02cSchristos while (imv) { 11528dbcf02cSchristos tncs_unload_imv(imv); 11538dbcf02cSchristos 11548dbcf02cSchristos prev = imv; 11558dbcf02cSchristos imv = imv->next; 11568dbcf02cSchristos os_free(prev); 11578dbcf02cSchristos } 11588dbcf02cSchristos 11598dbcf02cSchristos os_free(tncs_global_data); 11608dbcf02cSchristos tncs_global_data = NULL; 11618dbcf02cSchristos } 11628dbcf02cSchristos 11638dbcf02cSchristos 11648dbcf02cSchristos struct wpabuf * tncs_build_soh_request(void) 11658dbcf02cSchristos { 11668dbcf02cSchristos struct wpabuf *buf; 11678dbcf02cSchristos 11688dbcf02cSchristos /* 11698dbcf02cSchristos * Build a SoH Request TLV (to be used inside SoH EAP Extensions 11708dbcf02cSchristos * Method) 11718dbcf02cSchristos */ 11728dbcf02cSchristos 11738dbcf02cSchristos buf = wpabuf_alloc(8 + 4); 11748dbcf02cSchristos if (buf == NULL) 11758dbcf02cSchristos return NULL; 11768dbcf02cSchristos 11778dbcf02cSchristos /* Vendor-Specific TLV (Microsoft) - SoH Request */ 11788dbcf02cSchristos wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */ 11798dbcf02cSchristos wpabuf_put_be16(buf, 8); /* Length */ 11808dbcf02cSchristos 11818dbcf02cSchristos wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */ 11828dbcf02cSchristos 11838dbcf02cSchristos wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */ 11848dbcf02cSchristos wpabuf_put_be16(buf, 0); /* Length */ 11858dbcf02cSchristos 11868dbcf02cSchristos return buf; 11878dbcf02cSchristos } 11888dbcf02cSchristos 11898dbcf02cSchristos 11908dbcf02cSchristos struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len, 11918dbcf02cSchristos int *failure) 11928dbcf02cSchristos { 11938dbcf02cSchristos wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len); 11948dbcf02cSchristos *failure = 0; 11958dbcf02cSchristos 11968dbcf02cSchristos /* TODO: return MS-SoH Response TLV */ 11978dbcf02cSchristos 11988dbcf02cSchristos return NULL; 11998dbcf02cSchristos } 1200