$search
00001 /* 00002 * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH) 00003 * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 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 /* TODO: TNCS must be thread-safe; review the code and add locking etc. if 00026 * needed.. */ 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 /* TNC IF-IMV */ 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 /* TNCC-TNCS Message Types */ 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 /* Possible TNC_IMV_Action_Recommendation values: */ 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 /* Possible TNC_IMV_Evaluation_Result values: */ 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; /* from dlopen() */ 00114 TNC_IMVID imvID; 00115 TNC_MessageTypeList supported_types; 00116 size_t num_supported_types; 00117 00118 /* Functions implemented by IMVs (with TNC_IMV_ prefix) */ 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; /* local copy of tncs_global_data->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 /* TNCS functions that IMVs can call */ 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 /* TODO */ 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 /* TODO */ 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 /* TODO */ 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 /* Mandatory IMV functions */ 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 /* Optional IMV functions */ 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 /* Select the most restrictive recommendation */ 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 * <IMC-IMV-Message> 00910 * <Type>01234567</Type> 00911 * <Base64>foo==</Base64> 00912 * </IMC-IMV-Message> 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 * <TNCC-TNCS-Message> 00953 * <Type>01234567</Type> 00954 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML> 00955 * <Base64>foo==</Base64> 00956 * </TNCC-TNCS-Message> 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 /* Base64 OR XML */ 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 * Build a SoH Request TLV (to be used inside SoH EAP Extensions 01244 * Method) 01245 */ 01246 01247 buf = wpabuf_alloc(8 + 4); 01248 if (buf == NULL) 01249 return NULL; 01250 01251 /* Vendor-Specific TLV (Microsoft) - SoH Request */ 01252 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */ 01253 wpabuf_put_be16(buf, 8); /* Length */ 01254 01255 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */ 01256 01257 wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */ 01258 wpabuf_put_be16(buf, 0); /* Length */ 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 /* TODO: return MS-SoH Response TLV */ 01271 01272 return NULL; 01273 }