📄 tncs.c
字号:
/* * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH) * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include <dlfcn.h>#include "common.h"#include "base64.h"#include "tncs.h"#include "eap_common/eap_tlv_common.h"#include "eap_common/eap_defs.h"/* TODO: TNCS must be thread-safe; review the code and add locking etc. if * needed.. */#define TNC_CONFIG_FILE "/etc/tnc_config"#define IF_TNCCS_START \"<?xml version=\"1.0\"?>\n" \"<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \"xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \"xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \"IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"#define IF_TNCCS_END "\n</TNCCS-Batch>"/* TNC IF-IMV */typedef unsigned long TNC_UInt32;typedef unsigned char *TNC_BufferReference;typedef TNC_UInt32 TNC_IMVID;typedef TNC_UInt32 TNC_ConnectionID;typedef TNC_UInt32 TNC_ConnectionState;typedef TNC_UInt32 TNC_RetryReason;typedef TNC_UInt32 TNC_IMV_Action_Recommendation;typedef TNC_UInt32 TNC_IMV_Evaluation_Result;typedef TNC_UInt32 TNC_MessageType;typedef TNC_MessageType *TNC_MessageTypeList;typedef TNC_UInt32 TNC_VendorID;typedef TNC_UInt32 TNC_Subtype;typedef TNC_UInt32 TNC_Version;typedef TNC_UInt32 TNC_Result;typedef TNC_UInt32 TNC_AttributeID;typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)( TNC_IMVID imvID, char *functionName, void **pOutfunctionPointer);#define TNC_RESULT_SUCCESS 0#define TNC_RESULT_NOT_INITIALIZED 1#define TNC_RESULT_ALREADY_INITIALIZED 2#define TNC_RESULT_NO_COMMON_VERSION 3#define TNC_RESULT_CANT_RETRY 4#define TNC_RESULT_WONT_RETRY 5#define TNC_RESULT_INVALID_PARAMETER 6#define TNC_RESULT_CANT_RESPOND 7#define TNC_RESULT_ILLEGAL_OPERATION 8#define TNC_RESULT_OTHER 9#define TNC_RESULT_FATAL 10#define TNC_CONNECTION_STATE_CREATE 0#define TNC_CONNECTION_STATE_HANDSHAKE 1#define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2#define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3#define TNC_CONNECTION_STATE_ACCESS_NONE 4#define TNC_CONNECTION_STATE_DELETE 5#define TNC_IFIMV_VERSION_1 1#define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)#define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff)/* TNCC-TNCS Message Types */#define TNC_TNCCS_RECOMMENDATION 0x00000001#define TNC_TNCCS_ERROR 0x00000002#define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003#define TNC_TNCCS_REASONSTRINGS 0x00000004/* Possible TNC_IMV_Action_Recommendation values: */enum IMV_Action_Recommendation { TNC_IMV_ACTION_RECOMMENDATION_ALLOW, TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS, TNC_IMV_ACTION_RECOMMENDATION_ISOLATE, TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION};/* Possible TNC_IMV_Evaluation_Result values: */enum IMV_Evaluation_Result { TNC_IMV_EVALUATION_RESULT_COMPLIANT, TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR, TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR, TNC_IMV_EVALUATION_RESULT_ERROR, TNC_IMV_EVALUATION_RESULT_DONT_KNOW};struct tnc_if_imv { struct tnc_if_imv *next; char *name; char *path; void *dlhandle; /* from dlopen() */ TNC_IMVID imvID; TNC_MessageTypeList supported_types; size_t num_supported_types; /* Functions implemented by IMVs (with TNC_IMV_ prefix) */ TNC_Result (*Initialize)( TNC_IMVID imvID, TNC_Version minVersion, TNC_Version maxVersion, TNC_Version *pOutActualVersion); TNC_Result (*NotifyConnectionChange)( TNC_IMVID imvID, TNC_ConnectionID connectionID, TNC_ConnectionState newState); TNC_Result (*ReceiveMessage)( TNC_IMVID imvID, TNC_ConnectionID connectionID, TNC_BufferReference message, TNC_UInt32 messageLength, TNC_MessageType messageType); TNC_Result (*SolicitRecommendation)( TNC_IMVID imvID, TNC_ConnectionID connectionID); TNC_Result (*BatchEnding)( TNC_IMVID imvID, TNC_ConnectionID connectionID); TNC_Result (*Terminate)(TNC_IMVID imvID); TNC_Result (*ProvideBindFunction)( TNC_IMVID imvID, TNC_TNCS_BindFunctionPointer bindFunction);};#define TNC_MAX_IMV_ID 10struct tncs_data { struct tncs_data *next; struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */ TNC_ConnectionID connectionID; unsigned int last_batchid; enum IMV_Action_Recommendation recommendation; int done; struct conn_imv { u8 *imv_send; size_t imv_send_len; enum IMV_Action_Recommendation recommendation; int recommendation_set; } imv_data[TNC_MAX_IMV_ID]; char *tncs_message;};struct tncs_global { struct tnc_if_imv *imv; TNC_ConnectionID next_conn_id; struct tncs_data *connections;};static struct tncs_global *tncs_global_data = NULL;static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID){ struct tnc_if_imv *imv; if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL) return NULL; imv = tncs_global_data->imv; while (imv) { if (imv->imvID == imvID) return imv; imv = imv->next; } return NULL;}static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID){ struct tncs_data *tncs; if (tncs_global_data == NULL) return NULL; tncs = tncs_global_data->connections; while (tncs) { if (tncs->connectionID == connectionID) return tncs; tncs = tncs->next; } wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found", (unsigned long) connectionID); return NULL;}/* TNCS functions that IMVs can call */TNC_Result TNC_TNCS_ReportMessageTypes( TNC_IMVID imvID, TNC_MessageTypeList supportedTypes, TNC_UInt32 typeCount){ TNC_UInt32 i; struct tnc_if_imv *imv; wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu " "typeCount=%lu)", (unsigned long) imvID, (unsigned long) typeCount); for (i = 0; i < typeCount; i++) { wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu", i, supportedTypes[i]); } imv = tncs_get_imv(imvID); if (imv == NULL) return TNC_RESULT_INVALID_PARAMETER; os_free(imv->supported_types); imv->supported_types = os_malloc(typeCount * sizeof(TNC_MessageTypeList)); if (imv->supported_types == NULL) return TNC_RESULT_FATAL; os_memcpy(imv->supported_types, supportedTypes, typeCount * sizeof(TNC_MessageTypeList)); imv->num_supported_types = typeCount; return TNC_RESULT_SUCCESS;}TNC_Result TNC_TNCS_SendMessage( TNC_IMVID imvID, TNC_ConnectionID connectionID, TNC_BufferReference message, TNC_UInt32 messageLength, TNC_MessageType messageType){ struct tncs_data *tncs; unsigned char *b64; size_t b64len; wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu " "connectionID=%lu messageType=%lu)", imvID, connectionID, messageType); wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage", message, messageLength); if (tncs_get_imv(imvID) == NULL) return TNC_RESULT_INVALID_PARAMETER; tncs = tncs_get_conn(connectionID); if (tncs == NULL) return TNC_RESULT_INVALID_PARAMETER; b64 = base64_encode(message, messageLength, &b64len); if (b64 == NULL) return TNC_RESULT_FATAL; os_free(tncs->imv_data[imvID].imv_send); tncs->imv_data[imvID].imv_send_len = 0; tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100); if (tncs->imv_data[imvID].imv_send == NULL) { os_free(b64); return TNC_RESULT_OTHER; } tncs->imv_data[imvID].imv_send_len = os_snprintf((char *) tncs->imv_data[imvID].imv_send, b64len + 100, "<IMC-IMV-Message><Type>%08X</Type>" "<Base64>%s</Base64></IMC-IMV-Message>", (unsigned int) messageType, b64); os_free(b64); return TNC_RESULT_SUCCESS;}TNC_Result TNC_TNCS_RequestHandshakeRetry( TNC_IMVID imvID, TNC_ConnectionID connectionID, TNC_RetryReason reason){ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry"); /* TODO */ return TNC_RESULT_SUCCESS;}TNC_Result TNC_TNCS_ProvideRecommendation( TNC_IMVID imvID, TNC_ConnectionID connectionID, TNC_IMV_Action_Recommendation recommendation, TNC_IMV_Evaluation_Result evaluation){ struct tncs_data *tncs; wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu " "connectionID=%lu recommendation=%lu evaluation=%lu)", (unsigned long) imvID, (unsigned long) connectionID, (unsigned long) recommendation, (unsigned long) evaluation); if (tncs_get_imv(imvID) == NULL) return TNC_RESULT_INVALID_PARAMETER; tncs = tncs_get_conn(connectionID); if (tncs == NULL) return TNC_RESULT_INVALID_PARAMETER; tncs->imv_data[imvID].recommendation = recommendation; tncs->imv_data[imvID].recommendation_set = 1; return TNC_RESULT_SUCCESS;}TNC_Result TNC_TNCS_GetAttribute( TNC_IMVID imvID, TNC_ConnectionID connectionID, TNC_AttributeID attribureID, TNC_UInt32 bufferLength, TNC_BufferReference buffer, TNC_UInt32 *pOutValueLength){ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute"); /* TODO */ return TNC_RESULT_SUCCESS;}TNC_Result TNC_TNCS_SetAttribute( TNC_IMVID imvID, TNC_ConnectionID connectionID, TNC_AttributeID attribureID, TNC_UInt32 bufferLength, TNC_BufferReference buffer){ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute"); /* TODO */ return TNC_RESULT_SUCCESS;}TNC_Result TNC_TNCS_BindFunction( TNC_IMVID imvID, char *functionName, void **pOutFunctionPointer){ wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, " "functionName='%s')", (unsigned long) imvID, functionName); if (tncs_get_imv(imvID) == NULL) return TNC_RESULT_INVALID_PARAMETER; if (pOutFunctionPointer == NULL) return TNC_RESULT_INVALID_PARAMETER; if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0) *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes; else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0) *pOutFunctionPointer = TNC_TNCS_SendMessage; else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") == 0) *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry; else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") == 0) *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation; else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0) *pOutFunctionPointer = TNC_TNCS_GetAttribute; else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0) *pOutFunctionPointer = TNC_TNCS_SetAttribute; else *pOutFunctionPointer = NULL; return TNC_RESULT_SUCCESS;}static void * tncs_get_sym(void *handle, char *func){ void *fptr; fptr = dlsym(handle, func); return fptr;}static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv){ void *handle = imv->dlhandle; /* Mandatory IMV functions */ imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize"); if (imv->Initialize == NULL) { wpa_printf(MSG_ERROR, "TNC: IMV does not export " "TNC_IMV_Initialize"); return -1; } imv->SolicitRecommendation = tncs_get_sym( handle, "TNC_IMV_SolicitRecommendation"); if (imv->SolicitRecommendation == NULL) { wpa_printf(MSG_ERROR, "TNC: IMV does not export " "TNC_IMV_SolicitRecommendation"); return -1; } imv->ProvideBindFunction = tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction"); if (imv->ProvideBindFunction == NULL) { wpa_printf(MSG_ERROR, "TNC: IMV does not export " "TNC_IMV_ProvideBindFunction"); return -1; } /* Optional IMV functions */ imv->NotifyConnectionChange = tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange"); imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage"); imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding"); imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate"); return 0;}static int tncs_imv_initialize(struct tnc_if_imv *imv){ TNC_Result res; TNC_Version imv_ver; wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'", imv->name); res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1, TNC_IFIMV_VERSION_1, &imv_ver); wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu", (unsigned long) res, (unsigned long) imv_ver); return res == TNC_RESULT_SUCCESS ? 0 : -1;}static int tncs_imv_terminate(struct tnc_if_imv *imv){ TNC_Result res; if (imv->Terminate == NULL) return 0; wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'", imv->name); res = imv->Terminate(imv->imvID); wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu", (unsigned long) res); return res == TNC_RESULT_SUCCESS ? 0 : -1;}static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv){ TNC_Result res; wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for " "IMV '%s'", imv->name); res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction); wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu", (unsigned long) res); return res == TNC_RESULT_SUCCESS ? 0 : -1;}static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv, TNC_ConnectionID conn, TNC_ConnectionState state){ TNC_Result res; if (imv->NotifyConnectionChange == NULL) return 0; wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)" " for IMV '%s'", (int) state, imv->name); res = imv->NotifyConnectionChange(imv->imvID, conn, state); wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu", (unsigned long) res); return res == TNC_RESULT_SUCCESS ? 0 : -1;}static int tncs_load_imv(struct tnc_if_imv *imv){ if (imv->path == NULL) { wpa_printf(MSG_DEBUG, "TNC: No IMV configured"); return -1; } wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)", imv->name, imv->path); imv->dlhandle = dlopen(imv->path, RTLD_LAZY); if (imv->dlhandle == NULL) { wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s", imv->name, imv->path, dlerror()); return -1; } if (tncs_imv_resolve_funcs(imv) < 0) { wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions"); return -1; } if (tncs_imv_initialize(imv) < 0 || tncs_imv_provide_bind_function(imv) < 0) { wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV"); return -1; } return 0;}static void tncs_free_imv(struct tnc_if_imv *imv){ os_free(imv->name); os_free(imv->path); os_free(imv->supported_types);}static void tncs_unload_imv(struct tnc_if_imv *imv){ tncs_imv_terminate(imv); if (imv->dlhandle) dlclose(imv->dlhandle); tncs_free_imv(imv);}static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type){ size_t i; unsigned int vendor, subtype; if (imv == NULL || imv->supported_types == NULL) return 0; vendor = type >> 8; subtype = type & 0xff; for (i = 0; i < imv->num_supported_types; i++) { unsigned int svendor, ssubtype; svendor = imv->supported_types[i] >> 8; ssubtype = imv->supported_types[i] & 0xff; if ((vendor == svendor || svendor == TNC_VENDORID_ANY) && (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY)) return 1; } return 0;}static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type, const u8 *msg, size_t len){ struct tnc_if_imv *imv; TNC_Result res; wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len); for (imv = tncs->imv; imv; imv = imv->next) { if (imv->ReceiveMessage == NULL || !tncs_supported_type(imv, type)) continue; wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'", imv->name); res = imv->ReceiveMessage(imv->imvID, tncs->connectionID, (TNC_BufferReference) msg, len, type); wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu", (unsigned long) res); }}static void tncs_batch_ending(struct tncs_data *tncs){ struct tnc_if_imv *imv; TNC_Result res; for (imv = tncs->imv; imv; imv = imv->next) { if (imv->BatchEnding == NULL) continue; wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'", imv->name); res = imv->BatchEnding(imv->imvID, tncs->connectionID); wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu", (unsigned long) res); }}static void tncs_solicit_recommendation(struct tncs_data *tncs){ struct tnc_if_imv *imv; TNC_Result res; for (imv = tncs->imv; imv; imv = imv->next) { if (tncs->imv_data[imv->imvID].recommendation_set) continue; wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for " "IMV '%s'", imv->name);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -