00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "includes.h"
00016 #include <dlfcn.h>
00017
00018 #include "common.h"
00019 #include "base64.h"
00020 #include "tncs.h"
00021 #include "eap_common/eap_tlv_common.h"
00022 #include "eap_common/eap_defs.h"
00023
00024
00025
00026
00027
00028 #define TNC_CONFIG_FILE "/etc/tnc_config"
00029 #define IF_TNCCS_START \
00030 "<?xml version=\"1.0\"?>\n" \
00031 "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
00032 "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
00033 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
00034 "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
00035 "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
00036 #define IF_TNCCS_END "\n</TNCCS-Batch>"
00037
00038
00039
00040 typedef unsigned long TNC_UInt32;
00041 typedef unsigned char *TNC_BufferReference;
00042
00043 typedef TNC_UInt32 TNC_IMVID;
00044 typedef TNC_UInt32 TNC_ConnectionID;
00045 typedef TNC_UInt32 TNC_ConnectionState;
00046 typedef TNC_UInt32 TNC_RetryReason;
00047 typedef TNC_UInt32 TNC_IMV_Action_Recommendation;
00048 typedef TNC_UInt32 TNC_IMV_Evaluation_Result;
00049 typedef TNC_UInt32 TNC_MessageType;
00050 typedef TNC_MessageType *TNC_MessageTypeList;
00051 typedef TNC_UInt32 TNC_VendorID;
00052 typedef TNC_UInt32 TNC_Subtype;
00053 typedef TNC_UInt32 TNC_Version;
00054 typedef TNC_UInt32 TNC_Result;
00055 typedef TNC_UInt32 TNC_AttributeID;
00056
00057 typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)(
00058 TNC_IMVID imvID,
00059 char *functionName,
00060 void **pOutfunctionPointer);
00061
00062 #define TNC_RESULT_SUCCESS 0
00063 #define TNC_RESULT_NOT_INITIALIZED 1
00064 #define TNC_RESULT_ALREADY_INITIALIZED 2
00065 #define TNC_RESULT_NO_COMMON_VERSION 3
00066 #define TNC_RESULT_CANT_RETRY 4
00067 #define TNC_RESULT_WONT_RETRY 5
00068 #define TNC_RESULT_INVALID_PARAMETER 6
00069 #define TNC_RESULT_CANT_RESPOND 7
00070 #define TNC_RESULT_ILLEGAL_OPERATION 8
00071 #define TNC_RESULT_OTHER 9
00072 #define TNC_RESULT_FATAL 10
00073
00074 #define TNC_CONNECTION_STATE_CREATE 0
00075 #define TNC_CONNECTION_STATE_HANDSHAKE 1
00076 #define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
00077 #define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
00078 #define TNC_CONNECTION_STATE_ACCESS_NONE 4
00079 #define TNC_CONNECTION_STATE_DELETE 5
00080
00081 #define TNC_IFIMV_VERSION_1 1
00082
00083 #define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
00084 #define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff)
00085
00086
00087 #define TNC_TNCCS_RECOMMENDATION 0x00000001
00088 #define TNC_TNCCS_ERROR 0x00000002
00089 #define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003
00090 #define TNC_TNCCS_REASONSTRINGS 0x00000004
00091
00092
00093 enum IMV_Action_Recommendation {
00094 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
00095 TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS,
00096 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
00097 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
00098 };
00099
00100
00101 enum IMV_Evaluation_Result {
00102 TNC_IMV_EVALUATION_RESULT_COMPLIANT,
00103 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR,
00104 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR,
00105 TNC_IMV_EVALUATION_RESULT_ERROR,
00106 TNC_IMV_EVALUATION_RESULT_DONT_KNOW
00107 };
00108
00109 struct tnc_if_imv {
00110 struct tnc_if_imv *next;
00111 char *name;
00112 char *path;
00113 void *dlhandle;
00114 TNC_IMVID imvID;
00115 TNC_MessageTypeList supported_types;
00116 size_t num_supported_types;
00117
00118
00119 TNC_Result (*Initialize)(
00120 TNC_IMVID imvID,
00121 TNC_Version minVersion,
00122 TNC_Version maxVersion,
00123 TNC_Version *pOutActualVersion);
00124 TNC_Result (*NotifyConnectionChange)(
00125 TNC_IMVID imvID,
00126 TNC_ConnectionID connectionID,
00127 TNC_ConnectionState newState);
00128 TNC_Result (*ReceiveMessage)(
00129 TNC_IMVID imvID,
00130 TNC_ConnectionID connectionID,
00131 TNC_BufferReference message,
00132 TNC_UInt32 messageLength,
00133 TNC_MessageType messageType);
00134 TNC_Result (*SolicitRecommendation)(
00135 TNC_IMVID imvID,
00136 TNC_ConnectionID connectionID);
00137 TNC_Result (*BatchEnding)(
00138 TNC_IMVID imvID,
00139 TNC_ConnectionID connectionID);
00140 TNC_Result (*Terminate)(TNC_IMVID imvID);
00141 TNC_Result (*ProvideBindFunction)(
00142 TNC_IMVID imvID,
00143 TNC_TNCS_BindFunctionPointer bindFunction);
00144 };
00145
00146
00147 #define TNC_MAX_IMV_ID 10
00148
00149 struct tncs_data {
00150 struct tncs_data *next;
00151 struct tnc_if_imv *imv;
00152 TNC_ConnectionID connectionID;
00153 unsigned int last_batchid;
00154 enum IMV_Action_Recommendation recommendation;
00155 int done;
00156
00157 struct conn_imv {
00158 u8 *imv_send;
00159 size_t imv_send_len;
00160 enum IMV_Action_Recommendation recommendation;
00161 int recommendation_set;
00162 } imv_data[TNC_MAX_IMV_ID];
00163
00164 char *tncs_message;
00165 };
00166
00167
00168 struct tncs_global {
00169 struct tnc_if_imv *imv;
00170 TNC_ConnectionID next_conn_id;
00171 struct tncs_data *connections;
00172 };
00173
00174 static struct tncs_global *tncs_global_data = NULL;
00175
00176
00177 static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
00178 {
00179 struct tnc_if_imv *imv;
00180
00181 if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
00182 return NULL;
00183 imv = tncs_global_data->imv;
00184 while (imv) {
00185 if (imv->imvID == imvID)
00186 return imv;
00187 imv = imv->next;
00188 }
00189 return NULL;
00190 }
00191
00192
00193 static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
00194 {
00195 struct tncs_data *tncs;
00196
00197 if (tncs_global_data == NULL)
00198 return NULL;
00199
00200 tncs = tncs_global_data->connections;
00201 while (tncs) {
00202 if (tncs->connectionID == connectionID)
00203 return tncs;
00204 tncs = tncs->next;
00205 }
00206
00207 wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
00208 (unsigned long) connectionID);
00209
00210 return NULL;
00211 }
00212
00213
00214
00215 TNC_Result TNC_TNCS_ReportMessageTypes(
00216 TNC_IMVID imvID,
00217 TNC_MessageTypeList supportedTypes,
00218 TNC_UInt32 typeCount)
00219 {
00220 TNC_UInt32 i;
00221 struct tnc_if_imv *imv;
00222
00223 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
00224 "typeCount=%lu)",
00225 (unsigned long) imvID, (unsigned long) typeCount);
00226
00227 for (i = 0; i < typeCount; i++) {
00228 wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
00229 i, supportedTypes[i]);
00230 }
00231
00232 imv = tncs_get_imv(imvID);
00233 if (imv == NULL)
00234 return TNC_RESULT_INVALID_PARAMETER;
00235 os_free(imv->supported_types);
00236 imv->supported_types =
00237 os_malloc(typeCount * sizeof(TNC_MessageTypeList));
00238 if (imv->supported_types == NULL)
00239 return TNC_RESULT_FATAL;
00240 os_memcpy(imv->supported_types, supportedTypes,
00241 typeCount * sizeof(TNC_MessageTypeList));
00242 imv->num_supported_types = typeCount;
00243
00244 return TNC_RESULT_SUCCESS;
00245 }
00246
00247
00248 TNC_Result TNC_TNCS_SendMessage(
00249 TNC_IMVID imvID,
00250 TNC_ConnectionID connectionID,
00251 TNC_BufferReference message,
00252 TNC_UInt32 messageLength,
00253 TNC_MessageType messageType)
00254 {
00255 struct tncs_data *tncs;
00256 unsigned char *b64;
00257 size_t b64len;
00258
00259 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
00260 "connectionID=%lu messageType=%lu)",
00261 imvID, connectionID, messageType);
00262 wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
00263 message, messageLength);
00264
00265 if (tncs_get_imv(imvID) == NULL)
00266 return TNC_RESULT_INVALID_PARAMETER;
00267
00268 tncs = tncs_get_conn(connectionID);
00269 if (tncs == NULL)
00270 return TNC_RESULT_INVALID_PARAMETER;
00271
00272 b64 = base64_encode(message, messageLength, &b64len);
00273 if (b64 == NULL)
00274 return TNC_RESULT_FATAL;
00275
00276 os_free(tncs->imv_data[imvID].imv_send);
00277 tncs->imv_data[imvID].imv_send_len = 0;
00278 tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
00279 if (tncs->imv_data[imvID].imv_send == NULL) {
00280 os_free(b64);
00281 return TNC_RESULT_OTHER;
00282 }
00283
00284 tncs->imv_data[imvID].imv_send_len =
00285 os_snprintf((char *) tncs->imv_data[imvID].imv_send,
00286 b64len + 100,
00287 "<IMC-IMV-Message><Type>%08X</Type>"
00288 "<Base64>%s</Base64></IMC-IMV-Message>",
00289 (unsigned int) messageType, b64);
00290
00291 os_free(b64);
00292
00293 return TNC_RESULT_SUCCESS;
00294 }
00295
00296
00297 TNC_Result TNC_TNCS_RequestHandshakeRetry(
00298 TNC_IMVID imvID,
00299 TNC_ConnectionID connectionID,
00300 TNC_RetryReason reason)
00301 {
00302 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
00303
00304 return TNC_RESULT_SUCCESS;
00305 }
00306
00307
00308 TNC_Result TNC_TNCS_ProvideRecommendation(
00309 TNC_IMVID imvID,
00310 TNC_ConnectionID connectionID,
00311 TNC_IMV_Action_Recommendation recommendation,
00312 TNC_IMV_Evaluation_Result evaluation)
00313 {
00314 struct tncs_data *tncs;
00315
00316 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
00317 "connectionID=%lu recommendation=%lu evaluation=%lu)",
00318 (unsigned long) imvID, (unsigned long) connectionID,
00319 (unsigned long) recommendation, (unsigned long) evaluation);
00320
00321 if (tncs_get_imv(imvID) == NULL)
00322 return TNC_RESULT_INVALID_PARAMETER;
00323
00324 tncs = tncs_get_conn(connectionID);
00325 if (tncs == NULL)
00326 return TNC_RESULT_INVALID_PARAMETER;
00327
00328 tncs->imv_data[imvID].recommendation = recommendation;
00329 tncs->imv_data[imvID].recommendation_set = 1;
00330
00331 return TNC_RESULT_SUCCESS;
00332 }
00333
00334
00335 TNC_Result TNC_TNCS_GetAttribute(
00336 TNC_IMVID imvID,
00337 TNC_ConnectionID connectionID,
00338 TNC_AttributeID attribureID,
00339 TNC_UInt32 bufferLength,
00340 TNC_BufferReference buffer,
00341 TNC_UInt32 *pOutValueLength)
00342 {
00343 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
00344
00345 return TNC_RESULT_SUCCESS;
00346 }
00347
00348
00349 TNC_Result TNC_TNCS_SetAttribute(
00350 TNC_IMVID imvID,
00351 TNC_ConnectionID connectionID,
00352 TNC_AttributeID attribureID,
00353 TNC_UInt32 bufferLength,
00354 TNC_BufferReference buffer)
00355 {
00356 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
00357
00358 return TNC_RESULT_SUCCESS;
00359 }
00360
00361
00362 TNC_Result TNC_TNCS_BindFunction(
00363 TNC_IMVID imvID,
00364 char *functionName,
00365 void **pOutFunctionPointer)
00366 {
00367 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
00368 "functionName='%s')", (unsigned long) imvID, functionName);
00369
00370 if (tncs_get_imv(imvID) == NULL)
00371 return TNC_RESULT_INVALID_PARAMETER;
00372
00373 if (pOutFunctionPointer == NULL)
00374 return TNC_RESULT_INVALID_PARAMETER;
00375
00376 if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
00377 *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
00378 else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
00379 *pOutFunctionPointer = TNC_TNCS_SendMessage;
00380 else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
00381 0)
00382 *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
00383 else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
00384 0)
00385 *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
00386 else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
00387 *pOutFunctionPointer = TNC_TNCS_GetAttribute;
00388 else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
00389 *pOutFunctionPointer = TNC_TNCS_SetAttribute;
00390 else
00391 *pOutFunctionPointer = NULL;
00392
00393 return TNC_RESULT_SUCCESS;
00394 }
00395
00396
00397 static void * tncs_get_sym(void *handle, char *func)
00398 {
00399 void *fptr;
00400
00401 fptr = dlsym(handle, func);
00402
00403 return fptr;
00404 }
00405
00406
00407 static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
00408 {
00409 void *handle = imv->dlhandle;
00410
00411
00412 imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
00413 if (imv->Initialize == NULL) {
00414 wpa_printf(MSG_ERROR, "TNC: IMV does not export "
00415 "TNC_IMV_Initialize");
00416 return -1;
00417 }
00418
00419 imv->SolicitRecommendation = tncs_get_sym(
00420 handle, "TNC_IMV_SolicitRecommendation");
00421 if (imv->SolicitRecommendation == NULL) {
00422 wpa_printf(MSG_ERROR, "TNC: IMV does not export "
00423 "TNC_IMV_SolicitRecommendation");
00424 return -1;
00425 }
00426
00427 imv->ProvideBindFunction =
00428 tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
00429 if (imv->ProvideBindFunction == NULL) {
00430 wpa_printf(MSG_ERROR, "TNC: IMV does not export "
00431 "TNC_IMV_ProvideBindFunction");
00432 return -1;
00433 }
00434
00435
00436 imv->NotifyConnectionChange =
00437 tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
00438 imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
00439 imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
00440 imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
00441
00442 return 0;
00443 }
00444
00445
00446 static int tncs_imv_initialize(struct tnc_if_imv *imv)
00447 {
00448 TNC_Result res;
00449 TNC_Version imv_ver;
00450
00451 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
00452 imv->name);
00453 res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
00454 TNC_IFIMV_VERSION_1, &imv_ver);
00455 wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
00456 (unsigned long) res, (unsigned long) imv_ver);
00457
00458 return res == TNC_RESULT_SUCCESS ? 0 : -1;
00459 }
00460
00461
00462 static int tncs_imv_terminate(struct tnc_if_imv *imv)
00463 {
00464 TNC_Result res;
00465
00466 if (imv->Terminate == NULL)
00467 return 0;
00468
00469 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
00470 imv->name);
00471 res = imv->Terminate(imv->imvID);
00472 wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
00473 (unsigned long) res);
00474
00475 return res == TNC_RESULT_SUCCESS ? 0 : -1;
00476 }
00477
00478
00479 static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
00480 {
00481 TNC_Result res;
00482
00483 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
00484 "IMV '%s'", imv->name);
00485 res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
00486 wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
00487 (unsigned long) res);
00488
00489 return res == TNC_RESULT_SUCCESS ? 0 : -1;
00490 }
00491
00492
00493 static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
00494 TNC_ConnectionID conn,
00495 TNC_ConnectionState state)
00496 {
00497 TNC_Result res;
00498
00499 if (imv->NotifyConnectionChange == NULL)
00500 return 0;
00501
00502 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
00503 " for IMV '%s'", (int) state, imv->name);
00504 res = imv->NotifyConnectionChange(imv->imvID, conn, state);
00505 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
00506 (unsigned long) res);
00507
00508 return res == TNC_RESULT_SUCCESS ? 0 : -1;
00509 }
00510
00511
00512 static int tncs_load_imv(struct tnc_if_imv *imv)
00513 {
00514 if (imv->path == NULL) {
00515 wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
00516 return -1;
00517 }
00518
00519 wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
00520 imv->name, imv->path);
00521 imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
00522 if (imv->dlhandle == NULL) {
00523 wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
00524 imv->name, imv->path, dlerror());
00525 return -1;
00526 }
00527
00528 if (tncs_imv_resolve_funcs(imv) < 0) {
00529 wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
00530 return -1;
00531 }
00532
00533 if (tncs_imv_initialize(imv) < 0 ||
00534 tncs_imv_provide_bind_function(imv) < 0) {
00535 wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
00536 return -1;
00537 }
00538
00539 return 0;
00540 }
00541
00542
00543 static void tncs_free_imv(struct tnc_if_imv *imv)
00544 {
00545 os_free(imv->name);
00546 os_free(imv->path);
00547 os_free(imv->supported_types);
00548 }
00549
00550 static void tncs_unload_imv(struct tnc_if_imv *imv)
00551 {
00552 tncs_imv_terminate(imv);
00553
00554 if (imv->dlhandle)
00555 dlclose(imv->dlhandle);
00556
00557 tncs_free_imv(imv);
00558 }
00559
00560
00561 static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
00562 {
00563 size_t i;
00564 unsigned int vendor, subtype;
00565
00566 if (imv == NULL || imv->supported_types == NULL)
00567 return 0;
00568
00569 vendor = type >> 8;
00570 subtype = type & 0xff;
00571
00572 for (i = 0; i < imv->num_supported_types; i++) {
00573 unsigned int svendor, ssubtype;
00574 svendor = imv->supported_types[i] >> 8;
00575 ssubtype = imv->supported_types[i] & 0xff;
00576 if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
00577 (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
00578 return 1;
00579 }
00580
00581 return 0;
00582 }
00583
00584
00585 static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
00586 const u8 *msg, size_t len)
00587 {
00588 struct tnc_if_imv *imv;
00589 TNC_Result res;
00590
00591 wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
00592
00593 for (imv = tncs->imv; imv; imv = imv->next) {
00594 if (imv->ReceiveMessage == NULL ||
00595 !tncs_supported_type(imv, type))
00596 continue;
00597
00598 wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
00599 imv->name);
00600 res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
00601 (TNC_BufferReference) msg, len,
00602 type);
00603 wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
00604 (unsigned long) res);
00605 }
00606 }
00607
00608
00609 static void tncs_batch_ending(struct tncs_data *tncs)
00610 {
00611 struct tnc_if_imv *imv;
00612 TNC_Result res;
00613
00614 for (imv = tncs->imv; imv; imv = imv->next) {
00615 if (imv->BatchEnding == NULL)
00616 continue;
00617
00618 wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
00619 imv->name);
00620 res = imv->BatchEnding(imv->imvID, tncs->connectionID);
00621 wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
00622 (unsigned long) res);
00623 }
00624 }
00625
00626
00627 static void tncs_solicit_recommendation(struct tncs_data *tncs)
00628 {
00629 struct tnc_if_imv *imv;
00630 TNC_Result res;
00631
00632 for (imv = tncs->imv; imv; imv = imv->next) {
00633 if (tncs->imv_data[imv->imvID].recommendation_set)
00634 continue;
00635
00636 wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
00637 "IMV '%s'", imv->name);
00638 res = imv->SolicitRecommendation(imv->imvID,
00639 tncs->connectionID);
00640 wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
00641 (unsigned long) res);
00642 }
00643 }
00644
00645
00646 void tncs_init_connection(struct tncs_data *tncs)
00647 {
00648 struct tnc_if_imv *imv;
00649 int i;
00650
00651 for (imv = tncs->imv; imv; imv = imv->next) {
00652 tncs_imv_notify_connection_change(
00653 imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
00654 tncs_imv_notify_connection_change(
00655 imv, tncs->connectionID,
00656 TNC_CONNECTION_STATE_HANDSHAKE);
00657 }
00658
00659 for (i = 0; i < TNC_MAX_IMV_ID; i++) {
00660 os_free(tncs->imv_data[i].imv_send);
00661 tncs->imv_data[i].imv_send = NULL;
00662 tncs->imv_data[i].imv_send_len = 0;
00663 }
00664 }
00665
00666
00667 size_t tncs_total_send_len(struct tncs_data *tncs)
00668 {
00669 int i;
00670 size_t len = 0;
00671
00672 for (i = 0; i < TNC_MAX_IMV_ID; i++)
00673 len += tncs->imv_data[i].imv_send_len;
00674 if (tncs->tncs_message)
00675 len += os_strlen(tncs->tncs_message);
00676 return len;
00677 }
00678
00679
00680 u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
00681 {
00682 int i;
00683
00684 for (i = 0; i < TNC_MAX_IMV_ID; i++) {
00685 if (tncs->imv_data[i].imv_send == NULL)
00686 continue;
00687
00688 os_memcpy(pos, tncs->imv_data[i].imv_send,
00689 tncs->imv_data[i].imv_send_len);
00690 pos += tncs->imv_data[i].imv_send_len;
00691 os_free(tncs->imv_data[i].imv_send);
00692 tncs->imv_data[i].imv_send = NULL;
00693 tncs->imv_data[i].imv_send_len = 0;
00694 }
00695
00696 if (tncs->tncs_message) {
00697 size_t len = os_strlen(tncs->tncs_message);
00698 os_memcpy(pos, tncs->tncs_message, len);
00699 pos += len;
00700 os_free(tncs->tncs_message);
00701 tncs->tncs_message = NULL;
00702 }
00703
00704 return pos;
00705 }
00706
00707
00708 char * tncs_if_tnccs_start(struct tncs_data *tncs)
00709 {
00710 char *buf = os_malloc(1000);
00711 if (buf == NULL)
00712 return NULL;
00713 tncs->last_batchid++;
00714 os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
00715 return buf;
00716 }
00717
00718
00719 char * tncs_if_tnccs_end(void)
00720 {
00721 char *buf = os_malloc(100);
00722 if (buf == NULL)
00723 return NULL;
00724 os_snprintf(buf, 100, IF_TNCCS_END);
00725 return buf;
00726 }
00727
00728
00729 static int tncs_get_type(char *start, unsigned int *type)
00730 {
00731 char *pos = os_strstr(start, "<Type>");
00732 if (pos == NULL)
00733 return -1;
00734 pos += 6;
00735 *type = strtoul(pos, NULL, 16);
00736 return 0;
00737 }
00738
00739
00740 static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
00741 {
00742 char *pos, *pos2;
00743 unsigned char *decoded;
00744
00745 pos = os_strstr(start, "<Base64>");
00746 if (pos == NULL)
00747 return NULL;
00748
00749 pos += 8;
00750 pos2 = os_strstr(pos, "</Base64>");
00751 if (pos2 == NULL)
00752 return NULL;
00753 *pos2 = '\0';
00754
00755 decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
00756 decoded_len);
00757 *pos2 = '<';
00758 if (decoded == NULL) {
00759 wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
00760 }
00761
00762 return decoded;
00763 }
00764
00765
00766 static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
00767 {
00768 enum IMV_Action_Recommendation rec;
00769 struct tnc_if_imv *imv;
00770 TNC_ConnectionState state;
00771 char *txt;
00772
00773 wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
00774
00775 if (tncs->done)
00776 return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
00777
00778 tncs_solicit_recommendation(tncs);
00779
00780
00781 rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
00782 for (imv = tncs->imv; imv; imv = imv->next) {
00783 TNC_IMV_Action_Recommendation irec;
00784 irec = tncs->imv_data[imv->imvID].recommendation;
00785 if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
00786 rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
00787 if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
00788 rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
00789 rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
00790 if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
00791 rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
00792 rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
00793 }
00794
00795 wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
00796 tncs->recommendation = rec;
00797 tncs->done = 1;
00798
00799 txt = NULL;
00800 switch (rec) {
00801 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
00802 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
00803 txt = "allow";
00804 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
00805 break;
00806 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
00807 txt = "isolate";
00808 state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
00809 break;
00810 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
00811 txt = "none";
00812 state = TNC_CONNECTION_STATE_ACCESS_NONE;
00813 break;
00814 default:
00815 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
00816 break;
00817 }
00818
00819 if (txt) {
00820 os_free(tncs->tncs_message);
00821 tncs->tncs_message = os_zalloc(200);
00822 if (tncs->tncs_message) {
00823 os_snprintf(tncs->tncs_message, 199,
00824 "<TNCC-TNCS-Message><Type>%08X</Type>"
00825 "<XML><TNCCS-Recommendation type=\"%s\">"
00826 "</TNCCS-Recommendation></XML>"
00827 "</TNCC-TNCS-Message>",
00828 TNC_TNCCS_RECOMMENDATION, txt);
00829 }
00830 }
00831
00832 for (imv = tncs->imv; imv; imv = imv->next) {
00833 tncs_imv_notify_connection_change(imv, tncs->connectionID,
00834 state);
00835 }
00836
00837 switch (rec) {
00838 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
00839 return TNCCS_RECOMMENDATION_ALLOW;
00840 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
00841 return TNCCS_RECOMMENDATION_NO_ACCESS;
00842 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
00843 return TNCCS_RECOMMENDATION_ISOLATE;
00844 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
00845 return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
00846 default:
00847 return TNCCS_PROCESS_ERROR;
00848 }
00849 }
00850
00851
00852 enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
00853 const u8 *msg, size_t len)
00854 {
00855 char *buf, *start, *end, *pos, *pos2, *payload;
00856 unsigned int batch_id;
00857 unsigned char *decoded;
00858 size_t decoded_len;
00859
00860 buf = os_malloc(len + 1);
00861 if (buf == NULL)
00862 return TNCCS_PROCESS_ERROR;
00863
00864 os_memcpy(buf, msg, len);
00865 buf[len] = '\0';
00866 start = os_strstr(buf, "<TNCCS-Batch ");
00867 end = os_strstr(buf, "</TNCCS-Batch>");
00868 if (start == NULL || end == NULL || start > end) {
00869 os_free(buf);
00870 return TNCCS_PROCESS_ERROR;
00871 }
00872
00873 start += 13;
00874 while (*start == ' ')
00875 start++;
00876 *end = '\0';
00877
00878 pos = os_strstr(start, "BatchId=");
00879 if (pos == NULL) {
00880 os_free(buf);
00881 return TNCCS_PROCESS_ERROR;
00882 }
00883
00884 pos += 8;
00885 if (*pos == '"')
00886 pos++;
00887 batch_id = atoi(pos);
00888 wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
00889 batch_id);
00890 if (batch_id != tncs->last_batchid + 1) {
00891 wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
00892 "%u (expected %u)",
00893 batch_id, tncs->last_batchid + 1);
00894 os_free(buf);
00895 return TNCCS_PROCESS_ERROR;
00896 }
00897 tncs->last_batchid = batch_id;
00898
00899 while (*pos != '\0' && *pos != '>')
00900 pos++;
00901 if (*pos == '\0') {
00902 os_free(buf);
00903 return TNCCS_PROCESS_ERROR;
00904 }
00905 pos++;
00906 payload = start;
00907
00908
00909
00910
00911
00912
00913
00914
00915 while (*start) {
00916 char *endpos;
00917 unsigned int type;
00918
00919 pos = os_strstr(start, "<IMC-IMV-Message>");
00920 if (pos == NULL)
00921 break;
00922 start = pos + 17;
00923 end = os_strstr(start, "</IMC-IMV-Message>");
00924 if (end == NULL)
00925 break;
00926 *end = '\0';
00927 endpos = end;
00928 end += 18;
00929
00930 if (tncs_get_type(start, &type) < 0) {
00931 *endpos = '<';
00932 start = end;
00933 continue;
00934 }
00935 wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
00936
00937 decoded = tncs_get_base64(start, &decoded_len);
00938 if (decoded == NULL) {
00939 *endpos = '<';
00940 start = end;
00941 continue;
00942 }
00943
00944 tncs_send_to_imvs(tncs, type, decoded, decoded_len);
00945
00946 os_free(decoded);
00947
00948 start = end;
00949 }
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959 start = payload;
00960 while (*start) {
00961 unsigned int type;
00962 char *xml, *xmlend, *endpos;
00963
00964 pos = os_strstr(start, "<TNCC-TNCS-Message>");
00965 if (pos == NULL)
00966 break;
00967 start = pos + 19;
00968 end = os_strstr(start, "</TNCC-TNCS-Message>");
00969 if (end == NULL)
00970 break;
00971 *end = '\0';
00972 endpos = end;
00973 end += 20;
00974
00975 if (tncs_get_type(start, &type) < 0) {
00976 *endpos = '<';
00977 start = end;
00978 continue;
00979 }
00980 wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
00981 type);
00982
00983
00984 decoded = NULL;
00985 xml = NULL;
00986 xmlend = NULL;
00987 pos = os_strstr(start, "<XML>");
00988 if (pos) {
00989 pos += 5;
00990 pos2 = os_strstr(pos, "</XML>");
00991 if (pos2 == NULL) {
00992 *endpos = '<';
00993 start = end;
00994 continue;
00995 }
00996 xmlend = pos2;
00997 xml = pos;
00998 } else {
00999 decoded = tncs_get_base64(start, &decoded_len);
01000 if (decoded == NULL) {
01001 *endpos = '<';
01002 start = end;
01003 continue;
01004 }
01005 }
01006
01007 if (decoded) {
01008 wpa_hexdump_ascii(MSG_MSGDUMP,
01009 "TNC: TNCC-TNCS-Message Base64",
01010 decoded, decoded_len);
01011 os_free(decoded);
01012 }
01013
01014 if (xml) {
01015 wpa_hexdump_ascii(MSG_MSGDUMP,
01016 "TNC: TNCC-TNCS-Message XML",
01017 (unsigned char *) xml,
01018 xmlend - xml);
01019 }
01020
01021 start = end;
01022 }
01023
01024 os_free(buf);
01025
01026 tncs_batch_ending(tncs);
01027
01028 if (tncs_total_send_len(tncs) == 0)
01029 return tncs_derive_recommendation(tncs);
01030
01031 return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
01032 }
01033
01034
01035 static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
01036 int *error)
01037 {
01038 struct tnc_if_imv *imv;
01039 char *pos, *pos2;
01040
01041 if (id >= TNC_MAX_IMV_ID) {
01042 wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
01043 return NULL;
01044 }
01045
01046 imv = os_zalloc(sizeof(*imv));
01047 if (imv == NULL) {
01048 *error = 1;
01049 return NULL;
01050 }
01051
01052 imv->imvID = id;
01053
01054 pos = start;
01055 wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
01056 if (pos + 1 >= end || *pos != '"') {
01057 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
01058 "(no starting quotation mark)", start);
01059 os_free(imv);
01060 return NULL;
01061 }
01062
01063 pos++;
01064 pos2 = pos;
01065 while (pos2 < end && *pos2 != '"')
01066 pos2++;
01067 if (pos2 >= end) {
01068 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
01069 "(no ending quotation mark)", start);
01070 os_free(imv);
01071 return NULL;
01072 }
01073 *pos2 = '\0';
01074 wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
01075 imv->name = os_strdup(pos);
01076
01077 pos = pos2 + 1;
01078 if (pos >= end || *pos != ' ') {
01079 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
01080 "(no space after name)", start);
01081 os_free(imv);
01082 return NULL;
01083 }
01084
01085 pos++;
01086 wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
01087 imv->path = os_strdup(pos);
01088
01089 return imv;
01090 }
01091
01092
01093 static int tncs_read_config(struct tncs_global *global)
01094 {
01095 char *config, *end, *pos, *line_end;
01096 size_t config_len;
01097 struct tnc_if_imv *imv, *last;
01098 int id = 0;
01099
01100 last = NULL;
01101
01102 config = os_readfile(TNC_CONFIG_FILE, &config_len);
01103 if (config == NULL) {
01104 wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
01105 "file '%s'", TNC_CONFIG_FILE);
01106 return -1;
01107 }
01108
01109 end = config + config_len;
01110 for (pos = config; pos < end; pos = line_end + 1) {
01111 line_end = pos;
01112 while (*line_end != '\n' && *line_end != '\r' &&
01113 line_end < end)
01114 line_end++;
01115 *line_end = '\0';
01116
01117 if (os_strncmp(pos, "IMV ", 4) == 0) {
01118 int error = 0;
01119
01120 imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
01121 if (error)
01122 return -1;
01123 if (imv) {
01124 if (last == NULL)
01125 global->imv = imv;
01126 else
01127 last->next = imv;
01128 last = imv;
01129 }
01130 }
01131 }
01132
01133 os_free(config);
01134
01135 return 0;
01136 }
01137
01138
01139 struct tncs_data * tncs_init(void)
01140 {
01141 struct tncs_data *tncs;
01142
01143 if (tncs_global_data == NULL)
01144 return NULL;
01145
01146 tncs = os_zalloc(sizeof(*tncs));
01147 if (tncs == NULL)
01148 return NULL;
01149 tncs->imv = tncs_global_data->imv;
01150 tncs->connectionID = tncs_global_data->next_conn_id++;
01151 tncs->next = tncs_global_data->connections;
01152 tncs_global_data->connections = tncs;
01153
01154 return tncs;
01155 }
01156
01157
01158 void tncs_deinit(struct tncs_data *tncs)
01159 {
01160 int i;
01161 struct tncs_data *prev, *conn;
01162
01163 if (tncs == NULL)
01164 return;
01165
01166 for (i = 0; i < TNC_MAX_IMV_ID; i++)
01167 os_free(tncs->imv_data[i].imv_send);
01168
01169 prev = NULL;
01170 conn = tncs_global_data->connections;
01171 while (conn) {
01172 if (conn == tncs) {
01173 if (prev)
01174 prev->next = tncs->next;
01175 else
01176 tncs_global_data->connections = tncs->next;
01177 break;
01178 }
01179 prev = conn;
01180 conn = conn->next;
01181 }
01182
01183 os_free(tncs->tncs_message);
01184 os_free(tncs);
01185 }
01186
01187
01188 int tncs_global_init(void)
01189 {
01190 struct tnc_if_imv *imv;
01191
01192 tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
01193 if (tncs_global_data == NULL)
01194 return -1;
01195
01196 if (tncs_read_config(tncs_global_data) < 0) {
01197 wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
01198 goto failed;
01199 }
01200
01201 for (imv = tncs_global_data->imv; imv; imv = imv->next) {
01202 if (tncs_load_imv(imv)) {
01203 wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
01204 imv->name);
01205 goto failed;
01206 }
01207 }
01208
01209 return 0;
01210
01211 failed:
01212 tncs_global_deinit();
01213 return -1;
01214 }
01215
01216
01217 void tncs_global_deinit(void)
01218 {
01219 struct tnc_if_imv *imv, *prev;
01220
01221 if (tncs_global_data == NULL)
01222 return;
01223
01224 imv = tncs_global_data->imv;
01225 while (imv) {
01226 tncs_unload_imv(imv);
01227
01228 prev = imv;
01229 imv = imv->next;
01230 os_free(prev);
01231 }
01232
01233 os_free(tncs_global_data);
01234 tncs_global_data = NULL;
01235 }
01236
01237
01238 struct wpabuf * tncs_build_soh_request(void)
01239 {
01240 struct wpabuf *buf;
01241
01242
01243
01244
01245
01246
01247 buf = wpabuf_alloc(8 + 4);
01248 if (buf == NULL)
01249 return NULL;
01250
01251
01252 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
01253 wpabuf_put_be16(buf, 8);
01254
01255 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT);
01256
01257 wpabuf_put_be16(buf, 0x02);
01258 wpabuf_put_be16(buf, 0);
01259
01260 return buf;
01261 }
01262
01263
01264 struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
01265 int *failure)
01266 {
01267 wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
01268 *failure = 0;
01269
01270
01271
01272 return NULL;
01273 }