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