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