1 /* 2 * EAP-TNC - TNCC (IF-IMC and IF-TNCCS) 3 * Copyright (c) 2007, Jouni Malinen <j (at) w1.fi> 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "includes.h" 10 #ifndef CONFIG_NATIVE_WINDOWS 11 #include <dlfcn.h> 12 #endif /* CONFIG_NATIVE_WINDOWS */ 13 14 #include "common.h" 15 #include "base64.h" 16 #include "tncc.h" 17 #include "eap_common/eap_tlv_common.h" 18 #include "eap_common/eap_defs.h" 19 20 21 #ifdef UNICODE 22 #define TSTR "%S" 23 #else /* UNICODE */ 24 #define TSTR "%s" 25 #endif /* UNICODE */ 26 27 28 #define TNC_CONFIG_FILE "/etc/tnc_config" 29 #define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs") 30 #define IF_TNCCS_START \ 31 "<?xml version=\"1.0\"?>\n" \ 32 "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \ 33 "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \ 34 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \ 35 "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \ 36 "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n" 37 #define IF_TNCCS_END "\n</TNCCS-Batch>" 38 39 /* TNC IF-IMC */ 40 41 typedef unsigned long TNC_UInt32; 42 typedef unsigned char *TNC_BufferReference; 43 44 typedef TNC_UInt32 TNC_IMCID; 45 typedef TNC_UInt32 TNC_ConnectionID; 46 typedef TNC_UInt32 TNC_ConnectionState; 47 typedef TNC_UInt32 TNC_RetryReason; 48 typedef TNC_UInt32 TNC_MessageType; 49 typedef TNC_MessageType *TNC_MessageTypeList; 50 typedef TNC_UInt32 TNC_VendorID; 51 typedef TNC_UInt32 TNC_MessageSubtype; 52 typedef TNC_UInt32 TNC_Version; 53 typedef TNC_UInt32 TNC_Result; 54 55 typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)( 56 TNC_IMCID imcID, 57 char *functionName, 58 void **pOutfunctionPointer); 59 60 #define TNC_RESULT_SUCCESS 0 61 #define TNC_RESULT_NOT_INITIALIZED 1 62 #define TNC_RESULT_ALREADY_INITIALIZED 2 63 #define TNC_RESULT_NO_COMMON_VERSION 3 64 #define TNC_RESULT_CANT_RETRY 4 65 #define TNC_RESULT_WONT_RETRY 5 66 #define TNC_RESULT_INVALID_PARAMETER 6 67 #define TNC_RESULT_CANT_RESPOND 7 68 #define TNC_RESULT_ILLEGAL_OPERATION 8 69 #define TNC_RESULT_OTHER 9 70 #define TNC_RESULT_FATAL 10 71 72 #define TNC_CONNECTION_STATE_CREATE 0 73 #define TNC_CONNECTION_STATE_HANDSHAKE 1 74 #define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2 75 #define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3 76 #define TNC_CONNECTION_STATE_ACCESS_NONE 4 77 #define TNC_CONNECTION_STATE_DELETE 5 78 79 #define TNC_IFIMC_VERSION_1 1 80 81 #define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff) 82 #define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff) 83 84 /* TNCC-TNCS Message Types */ 85 #define TNC_TNCCS_RECOMMENDATION 0x00000001 86 #define TNC_TNCCS_ERROR 0x00000002 87 #define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003 88 #define TNC_TNCCS_REASONSTRINGS 0x00000004 89 90 91 /* IF-TNCCS-SOH - SSoH and SSoHR Attributes */ 92 enum { 93 SSOH_MS_MACHINE_INVENTORY = 1, 94 SSOH_MS_QUARANTINE_STATE = 2, 95 SSOH_MS_PACKET_INFO = 3, 96 SSOH_MS_SYSTEMGENERATED_IDS = 4, 97 SSOH_MS_MACHINENAME = 5, 98 SSOH_MS_CORRELATIONID = 6, 99 SSOH_MS_INSTALLED_SHVS = 7, 100 SSOH_MS_MACHINE_INVENTORY_EX = 8 101 }; 102 103 struct tnc_if_imc { 104 struct tnc_if_imc *next; 105 char *name; 106 char *path; 107 void *dlhandle; /* from dlopen() */ 108 TNC_IMCID imcID; 109 TNC_ConnectionID connectionID; 110 TNC_MessageTypeList supported_types; 111 size_t num_supported_types; 112 u8 *imc_send; 113 size_t imc_send_len; 114 115 /* Functions implemented by IMCs (with TNC_IMC_ prefix) */ 116 TNC_Result (*Initialize)( 117 TNC_IMCID imcID, 118 TNC_Version minVersion, 119 TNC_Version maxVersion, 120 TNC_Version *pOutActualVersion); 121 TNC_Result (*NotifyConnectionChange)( 122 TNC_IMCID imcID, 123 TNC_ConnectionID connectionID, 124 TNC_ConnectionState newState); 125 TNC_Result (*BeginHandshake)( 126 TNC_IMCID imcID, 127 TNC_ConnectionID connectionID); 128 TNC_Result (*ReceiveMessage)( 129 TNC_IMCID imcID, 130 TNC_ConnectionID connectionID, 131 TNC_BufferReference messageBuffer, 132 TNC_UInt32 messageLength, 133 TNC_MessageType messageType); 134 TNC_Result (*BatchEnding)( 135 TNC_IMCID imcID, 136 TNC_ConnectionID connectionID); 137 TNC_Result (*Terminate)(TNC_IMCID imcID); 138 TNC_Result (*ProvideBindFunction)( 139 TNC_IMCID imcID, 140 TNC_TNCC_BindFunctionPointer bindFunction); 141 }; 142 143 struct tncc_data { 144 struct tnc_if_imc *imc; 145 unsigned int last_batchid; 146 }; 147 148 #define TNC_MAX_IMC_ID 10 149 static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL }; 150 151 152 /* TNCC functions that IMCs can call */ 153 154 TNC_Result TNC_TNCC_ReportMessageTypes( 155 TNC_IMCID imcID, 156 TNC_MessageTypeList supportedTypes, 157 TNC_UInt32 typeCount) 158 { 159 TNC_UInt32 i; 160 struct tnc_if_imc *imc; 161 162 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu " 163 "typeCount=%lu)", 164 (unsigned long) imcID, (unsigned long) typeCount); 165 166 for (i = 0; i < typeCount; i++) { 167 wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu", 168 i, supportedTypes[i]); 169 } 170 171 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) 172 return TNC_RESULT_INVALID_PARAMETER; 173 174 imc = tnc_imc[imcID]; 175 os_free(imc->supported_types); 176 imc->supported_types = 177 os_malloc(typeCount * sizeof(TNC_MessageType)); 178 if (imc->supported_types == NULL) 179 return TNC_RESULT_FATAL; 180 os_memcpy(imc->supported_types, supportedTypes, 181 typeCount * sizeof(TNC_MessageType)); 182 imc->num_supported_types = typeCount; 183 184 return TNC_RESULT_SUCCESS; 185 } 186 187 188 TNC_Result TNC_TNCC_SendMessage( 189 TNC_IMCID imcID, 190 TNC_ConnectionID connectionID, 191 TNC_BufferReference message, 192 TNC_UInt32 messageLength, 193 TNC_MessageType messageType) 194 { 195 struct tnc_if_imc *imc; 196 unsigned char *b64; 197 size_t b64len; 198 199 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu " 200 "connectionID=%lu messageType=%lu)", 201 imcID, connectionID, messageType); 202 wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage", 203 message, messageLength); 204 205 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) 206 return TNC_RESULT_INVALID_PARAMETER; 207 208 b64 = base64_encode(message, messageLength, &b64len); 209 if (b64 == NULL) 210 return TNC_RESULT_FATAL; 211 212 imc = tnc_imc[imcID]; 213 os_free(imc->imc_send); 214 imc->imc_send_len = 0; 215 imc->imc_send = os_zalloc(b64len + 100); 216 if (imc->imc_send == NULL) { 217 os_free(b64); 218 return TNC_RESULT_OTHER; 219 } 220 221 imc->imc_send_len = 222 os_snprintf((char *) imc->imc_send, b64len + 100, 223 "<IMC-IMV-Message><Type>%08X</Type>" 224 "<Base64>%s</Base64></IMC-IMV-Message>", 225 (unsigned int) messageType, b64); 226 227 os_free(b64); 228 229 return TNC_RESULT_SUCCESS; 230 } 231 232 233 TNC_Result TNC_TNCC_RequestHandshakeRetry( 234 TNC_IMCID imcID, 235 TNC_ConnectionID connectionID, 236 TNC_RetryReason reason) 237 { 238 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry"); 239 240 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) 241 return TNC_RESULT_INVALID_PARAMETER; 242 243 /* 244 * TODO: trigger a call to eapol_sm_request_reauth(). This would 245 * require that the IMC continues to be loaded in memory afer 246 * authentication.. 247 */ 248 249 return TNC_RESULT_SUCCESS; 250 } 251 252 253 TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity, 254 const char *message) 255 { 256 wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu " 257 "severity==%lu message='%s')", 258 imcID, severity, message); 259 return TNC_RESULT_SUCCESS; 260 } 261 262 263 TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID, 264 const char *message) 265 { 266 wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu " 267 "connectionID==%lu message='%s')", 268 imcID, connectionID, message); 269 return TNC_RESULT_SUCCESS; 270 } 271 272 273 TNC_Result TNC_TNCC_BindFunction( 274 TNC_IMCID imcID, 275 char *functionName, 276 void **pOutfunctionPointer) 277 { 278 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, " 279 "functionName='%s')", (unsigned long) imcID, functionName); 280 281 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL) 282 return TNC_RESULT_INVALID_PARAMETER; 283 284 if (pOutfunctionPointer == NULL) 285 return TNC_RESULT_INVALID_PARAMETER; 286 287 if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0) 288 *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes; 289 else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0) 290 *pOutfunctionPointer = TNC_TNCC_SendMessage; 291 else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") == 292 0) 293 *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry; 294 else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0) 295 *pOutfunctionPointer = TNC_9048_LogMessage; 296 else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0) 297 *pOutfunctionPointer = TNC_9048_UserMessage; 298 else 299 *pOutfunctionPointer = NULL; 300 301 return TNC_RESULT_SUCCESS; 302 } 303 304 305 static void * tncc_get_sym(void *handle, char *func) 306 { 307 void *fptr; 308 309 #ifdef CONFIG_NATIVE_WINDOWS 310 #ifdef _WIN32_WCE 311 fptr = GetProcAddressA(handle, func); 312 #else /* _WIN32_WCE */ 313 fptr = GetProcAddress(handle, func); 314 #endif /* _WIN32_WCE */ 315 #else /* CONFIG_NATIVE_WINDOWS */ 316 fptr = dlsym(handle, func); 317 #endif /* CONFIG_NATIVE_WINDOWS */ 318 319 return fptr; 320 } 321 322 323 static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc) 324 { 325 void *handle = imc->dlhandle; 326 327 /* Mandatory IMC functions */ 328 imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize"); 329 if (imc->Initialize == NULL) { 330 wpa_printf(MSG_ERROR, "TNC: IMC does not export " 331 "TNC_IMC_Initialize"); 332 return -1; 333 } 334 335 imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake"); 336 if (imc->BeginHandshake == NULL) { 337 wpa_printf(MSG_ERROR, "TNC: IMC does not export " 338 "TNC_IMC_BeginHandshake"); 339 return -1; 340 } 341 342 imc->ProvideBindFunction = 343 tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction"); 344 if (imc->ProvideBindFunction == NULL) { 345 wpa_printf(MSG_ERROR, "TNC: IMC does not export " 346 "TNC_IMC_ProvideBindFunction"); 347 return -1; 348 } 349 350 /* Optional IMC functions */ 351 imc->NotifyConnectionChange = 352 tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange"); 353 imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage"); 354 imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding"); 355 imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate"); 356 357 return 0; 358 } 359 360 361 static int tncc_imc_initialize(struct tnc_if_imc *imc) 362 { 363 TNC_Result res; 364 TNC_Version imc_ver; 365 366 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'", 367 imc->name); 368 res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1, 369 TNC_IFIMC_VERSION_1, &imc_ver); 370 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu", 371 (unsigned long) res, (unsigned long) imc_ver); 372 373 return res == TNC_RESULT_SUCCESS ? 0 : -1; 374 } 375 376 377 static int tncc_imc_terminate(struct tnc_if_imc *imc) 378 { 379 TNC_Result res; 380 381 if (imc->Terminate == NULL) 382 return 0; 383 384 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'", 385 imc->name); 386 res = imc->Terminate(imc->imcID); 387 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu", 388 (unsigned long) res); 389 390 return res == TNC_RESULT_SUCCESS ? 0 : -1; 391 } 392 393 394 static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc) 395 { 396 TNC_Result res; 397 398 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for " 399 "IMC '%s'", imc->name); 400 res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction); 401 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu", 402 (unsigned long) res); 403 404 return res == TNC_RESULT_SUCCESS ? 0 : -1; 405 } 406 407 408 static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc, 409 TNC_ConnectionState state) 410 { 411 TNC_Result res; 412 413 if (imc->NotifyConnectionChange == NULL) 414 return 0; 415 416 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)" 417 " for IMC '%s'", (int) state, imc->name); 418 res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID, 419 state); 420 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu", 421 (unsigned long) res); 422 423 return res == TNC_RESULT_SUCCESS ? 0 : -1; 424 } 425 426 427 static int tncc_imc_begin_handshake(struct tnc_if_imc *imc) 428 { 429 TNC_Result res; 430 431 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC " 432 "'%s'", imc->name); 433 res = imc->BeginHandshake(imc->imcID, imc->connectionID); 434 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu", 435 (unsigned long) res); 436 437 return res == TNC_RESULT_SUCCESS ? 0 : -1; 438 } 439 440 441 static int tncc_load_imc(struct tnc_if_imc *imc) 442 { 443 if (imc->path == NULL) { 444 wpa_printf(MSG_DEBUG, "TNC: No IMC configured"); 445 return -1; 446 } 447 448 wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)", 449 imc->name, imc->path); 450 #ifdef CONFIG_NATIVE_WINDOWS 451 #ifdef UNICODE 452 { 453 TCHAR *lib = wpa_strdup_tchar(imc->path); 454 if (lib == NULL) 455 return -1; 456 imc->dlhandle = LoadLibrary(lib); 457 os_free(lib); 458 } 459 #else /* UNICODE */ 460 imc->dlhandle = LoadLibrary(imc->path); 461 #endif /* UNICODE */ 462 if (imc->dlhandle == NULL) { 463 wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d", 464 imc->name, imc->path, (int) GetLastError()); 465 return -1; 466 } 467 #else /* CONFIG_NATIVE_WINDOWS */ 468 imc->dlhandle = dlopen(imc->path, RTLD_LAZY); 469 if (imc->dlhandle == NULL) { 470 wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s", 471 imc->name, imc->path, dlerror()); 472 return -1; 473 } 474 #endif /* CONFIG_NATIVE_WINDOWS */ 475 476 if (tncc_imc_resolve_funcs(imc) < 0) { 477 wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions"); 478 return -1; 479 } 480 481 if (tncc_imc_initialize(imc) < 0 || 482 tncc_imc_provide_bind_function(imc) < 0) { 483 wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC"); 484 return -1; 485 } 486 487 return 0; 488 } 489 490 491 static void tncc_unload_imc(struct tnc_if_imc *imc) 492 { 493 tncc_imc_terminate(imc); 494 tnc_imc[imc->imcID] = NULL; 495 496 if (imc->dlhandle) { 497 #ifdef CONFIG_NATIVE_WINDOWS 498 FreeLibrary(imc->dlhandle); 499 #else /* CONFIG_NATIVE_WINDOWS */ 500 dlclose(imc->dlhandle); 501 #endif /* CONFIG_NATIVE_WINDOWS */ 502 } 503 os_free(imc->name); 504 os_free(imc->path); 505 os_free(imc->supported_types); 506 os_free(imc->imc_send); 507 } 508 509 510 static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type) 511 { 512 size_t i; 513 unsigned int vendor, subtype; 514 515 if (imc == NULL || imc->supported_types == NULL) 516 return 0; 517 518 vendor = type >> 8; 519 subtype = type & 0xff; 520 521 for (i = 0; i < imc->num_supported_types; i++) { 522 unsigned int svendor, ssubtype; 523 svendor = imc->supported_types[i] >> 8; 524 ssubtype = imc->supported_types[i] & 0xff; 525 if ((vendor == svendor || svendor == TNC_VENDORID_ANY) && 526 (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY)) 527 return 1; 528 } 529 530 return 0; 531 } 532 533 534 static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type, 535 const u8 *msg, size_t len) 536 { 537 struct tnc_if_imc *imc; 538 TNC_Result res; 539 540 wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len); 541 542 for (imc = tncc->imc; imc; imc = imc->next) { 543 if (imc->ReceiveMessage == NULL || 544 !tncc_supported_type(imc, type)) 545 continue; 546 547 wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'", 548 imc->name); 549 res = imc->ReceiveMessage(imc->imcID, imc->connectionID, 550 (TNC_BufferReference) msg, len, 551 type); 552 wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu", 553 (unsigned long) res); 554 } 555 } 556 557 558 void tncc_init_connection(struct tncc_data *tncc) 559 { 560 struct tnc_if_imc *imc; 561 562 for (imc = tncc->imc; imc; imc = imc->next) { 563 tncc_imc_notify_connection_change( 564 imc, TNC_CONNECTION_STATE_CREATE); 565 tncc_imc_notify_connection_change( 566 imc, TNC_CONNECTION_STATE_HANDSHAKE); 567 568 os_free(imc->imc_send); 569 imc->imc_send = NULL; 570 imc->imc_send_len = 0; 571 572 tncc_imc_begin_handshake(imc); 573 } 574 } 575 576 577 size_t tncc_total_send_len(struct tncc_data *tncc) 578 { 579 struct tnc_if_imc *imc; 580 581 size_t len = 0; 582 for (imc = tncc->imc; imc; imc = imc->next) 583 len += imc->imc_send_len; 584 return len; 585 } 586 587 588 u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos) 589 { 590 struct tnc_if_imc *imc; 591 592 for (imc = tncc->imc; imc; imc = imc->next) { 593 if (imc->imc_send == NULL) 594 continue; 595 596 os_memcpy(pos, imc->imc_send, imc->imc_send_len); 597 pos += imc->imc_send_len; 598 os_free(imc->imc_send); 599 imc->imc_send = NULL; 600 imc->imc_send_len = 0; 601 } 602 603 return pos; 604 } 605 606 607 char * tncc_if_tnccs_start(struct tncc_data *tncc) 608 { 609 char *buf = os_malloc(1000); 610 if (buf == NULL) 611 return NULL; 612 tncc->last_batchid++; 613 os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid); 614 return buf; 615 } 616 617 618 char * tncc_if_tnccs_end(void) 619 { 620 char *buf = os_malloc(100); 621 if (buf == NULL) 622 return NULL; 623 os_snprintf(buf, 100, IF_TNCCS_END); 624 return buf; 625 } 626 627 628 static void tncc_notify_recommendation(struct tncc_data *tncc, 629 enum tncc_process_res res) 630 { 631 TNC_ConnectionState state; 632 struct tnc_if_imc *imc; 633 634 switch (res) { 635 case TNCCS_RECOMMENDATION_ALLOW: 636 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED; 637 break; 638 case TNCCS_RECOMMENDATION_NONE: 639 state = TNC_CONNECTION_STATE_ACCESS_NONE; 640 break; 641 case TNCCS_RECOMMENDATION_ISOLATE: 642 state = TNC_CONNECTION_STATE_ACCESS_ISOLATED; 643 break; 644 default: 645 state = TNC_CONNECTION_STATE_ACCESS_NONE; 646 break; 647 } 648 649 for (imc = tncc->imc; imc; imc = imc->next) 650 tncc_imc_notify_connection_change(imc, state); 651 } 652 653 654 static int tncc_get_type(char *start, unsigned int *type) 655 { 656 char *pos = os_strstr(start, "<Type>"); 657 if (pos == NULL) 658 return -1; 659 pos += 6; 660 *type = strtoul(pos, NULL, 16); 661 return 0; 662 } 663 664 665 static unsigned char * tncc_get_base64(char *start, size_t *decoded_len) 666 { 667 char *pos, *pos2; 668 unsigned char *decoded; 669 670 pos = os_strstr(start, "<Base64>"); 671 if (pos == NULL) 672 return NULL; 673 674 pos += 8; 675 pos2 = os_strstr(pos, "</Base64>"); 676 if (pos2 == NULL) 677 return NULL; 678 *pos2 = '\0'; 679 680 decoded = base64_decode((unsigned char *) pos, os_strlen(pos), 681 decoded_len); 682 *pos2 = '<'; 683 if (decoded == NULL) { 684 wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data"); 685 } 686 687 return decoded; 688 } 689 690 691 static enum tncc_process_res tncc_get_recommendation(char *start) 692 { 693 char *pos, *pos2, saved; 694 int recom; 695 696 pos = os_strstr(start, "<TNCCS-Recommendation "); 697 if (pos == NULL) 698 return TNCCS_RECOMMENDATION_ERROR; 699 700 pos += 21; 701 pos = os_strstr(pos, " type="); 702 if (pos == NULL) 703 return TNCCS_RECOMMENDATION_ERROR; 704 pos += 6; 705 706 if (*pos == '"') 707 pos++; 708 709 pos2 = pos; 710 while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>') 711 pos2++; 712 713 if (*pos2 == '\0') 714 return TNCCS_RECOMMENDATION_ERROR; 715 716 saved = *pos2; 717 *pos2 = '\0'; 718 wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos); 719 720 recom = TNCCS_RECOMMENDATION_ERROR; 721 if (os_strcmp(pos, "allow") == 0) 722 recom = TNCCS_RECOMMENDATION_ALLOW; 723 else if (os_strcmp(pos, "none") == 0) 724 recom = TNCCS_RECOMMENDATION_NONE; 725 else if (os_strcmp(pos, "isolate") == 0) 726 recom = TNCCS_RECOMMENDATION_ISOLATE; 727 728 *pos2 = saved; 729 730 return recom; 731 } 732 733 734 enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc, 735 const u8 *msg, size_t len) 736 { 737 char *buf, *start, *end, *pos, *pos2, *payload; 738 unsigned int batch_id; 739 unsigned char *decoded; 740 size_t decoded_len; 741 enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION; 742 int recommendation_msg = 0; 743 744 buf = dup_binstr(msg, len); 745 if (buf == NULL) 746 return TNCCS_PROCESS_ERROR; 747 748 start = os_strstr(buf, "<TNCCS-Batch "); 749 end = os_strstr(buf, "</TNCCS-Batch>"); 750 if (start == NULL || end == NULL || start > end) { 751 os_free(buf); 752 return TNCCS_PROCESS_ERROR; 753 } 754 755 start += 13; 756 while (*start == ' ') 757 start++; 758 *end = '\0'; 759 760 pos = os_strstr(start, "BatchId="); 761 if (pos == NULL) { 762 os_free(buf); 763 return TNCCS_PROCESS_ERROR; 764 } 765 766 pos += 8; 767 if (*pos == '"') 768 pos++; 769 batch_id = atoi(pos); 770 wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u", 771 batch_id); 772 if (batch_id != tncc->last_batchid + 1) { 773 wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId " 774 "%u (expected %u)", 775 batch_id, tncc->last_batchid + 1); 776 os_free(buf); 777 return TNCCS_PROCESS_ERROR; 778 } 779 tncc->last_batchid = batch_id; 780 781 while (*pos != '\0' && *pos != '>') 782 pos++; 783 if (*pos == '\0') { 784 os_free(buf); 785 return TNCCS_PROCESS_ERROR; 786 } 787 pos++; 788 payload = start; 789 790 /* 791 * <IMC-IMV-Message> 792 * <Type>01234567</Type> 793 * <Base64>foo==</Base64> 794 * </IMC-IMV-Message> 795 */ 796 797 while (*start) { 798 char *endpos; 799 unsigned int type; 800 801 pos = os_strstr(start, "<IMC-IMV-Message>"); 802 if (pos == NULL) 803 break; 804 start = pos + 17; 805 end = os_strstr(start, "</IMC-IMV-Message>"); 806 if (end == NULL) 807 break; 808 *end = '\0'; 809 endpos = end; 810 end += 18; 811 812 if (tncc_get_type(start, &type) < 0) { 813 *endpos = '<'; 814 start = end; 815 continue; 816 } 817 wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type); 818 819 decoded = tncc_get_base64(start, &decoded_len); 820 if (decoded == NULL) { 821 *endpos = '<'; 822 start = end; 823 continue; 824 } 825 826 tncc_send_to_imcs(tncc, type, decoded, decoded_len); 827 828 os_free(decoded); 829 830 start = end; 831 } 832 833 /* 834 * <TNCC-TNCS-Message> 835 * <Type>01234567</Type> 836 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML> 837 * <Base64>foo==</Base64> 838 * </TNCC-TNCS-Message> 839 */ 840 841 start = payload; 842 while (*start) { 843 unsigned int type; 844 char *xml, *xmlend, *endpos; 845 846 pos = os_strstr(start, "<TNCC-TNCS-Message>"); 847 if (pos == NULL) 848 break; 849 start = pos + 19; 850 end = os_strstr(start, "</TNCC-TNCS-Message>"); 851 if (end == NULL) 852 break; 853 *end = '\0'; 854 endpos = end; 855 end += 20; 856 857 if (tncc_get_type(start, &type) < 0) { 858 *endpos = '<'; 859 start = end; 860 continue; 861 } 862 wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x", 863 type); 864 865 /* Base64 OR XML */ 866 decoded = NULL; 867 xml = NULL; 868 xmlend = NULL; 869 pos = os_strstr(start, "<XML>"); 870 if (pos) { 871 pos += 5; 872 pos2 = os_strstr(pos, "</XML>"); 873 if (pos2 == NULL) { 874 *endpos = '<'; 875 start = end; 876 continue; 877 } 878 xmlend = pos2; 879 xml = pos; 880 } else { 881 decoded = tncc_get_base64(start, &decoded_len); 882 if (decoded == NULL) { 883 *endpos = '<'; 884 start = end; 885 continue; 886 } 887 } 888 889 if (decoded) { 890 wpa_hexdump_ascii(MSG_MSGDUMP, 891 "TNC: TNCC-TNCS-Message Base64", 892 decoded, decoded_len); 893 os_free(decoded); 894 } 895 896 if (xml) { 897 wpa_hexdump_ascii(MSG_MSGDUMP, 898 "TNC: TNCC-TNCS-Message XML", 899 (unsigned char *) xml, 900 xmlend - xml); 901 } 902 903 if (type == TNC_TNCCS_RECOMMENDATION && xml) { 904 /* 905 * <TNCCS-Recommendation type="allow"> 906 * </TNCCS-Recommendation> 907 */ 908 *xmlend = '\0'; 909 res = tncc_get_recommendation(xml); 910 *xmlend = '<'; 911 recommendation_msg = 1; 912 } 913 914 start = end; 915 } 916 917 os_free(buf); 918 919 if (recommendation_msg) 920 tncc_notify_recommendation(tncc, res); 921 922 return res; 923 } 924 925 926 #ifdef CONFIG_NATIVE_WINDOWS 927 static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive) 928 { 929 HKEY hk, hk2; 930 LONG ret; 931 DWORD i; 932 struct tnc_if_imc *imc, *last; 933 int j; 934 935 last = tncc->imc; 936 while (last && last->next) 937 last = last->next; 938 939 ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS, 940 &hk); 941 if (ret != ERROR_SUCCESS) 942 return 0; 943 944 for (i = 0; ; i++) { 945 TCHAR name[255], *val; 946 DWORD namelen, buflen; 947 948 namelen = 255; 949 ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL, 950 NULL); 951 952 if (ret == ERROR_NO_MORE_ITEMS) 953 break; 954 955 if (ret != ERROR_SUCCESS) { 956 wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x", 957 (unsigned int) ret); 958 break; 959 } 960 961 if (namelen >= 255) 962 namelen = 255 - 1; 963 name[namelen] = '\0'; 964 965 wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name); 966 967 ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2); 968 if (ret != ERROR_SUCCESS) { 969 wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR 970 "'", name); 971 continue; 972 } 973 974 ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL, 975 &buflen); 976 if (ret != ERROR_SUCCESS) { 977 wpa_printf(MSG_DEBUG, "TNC: Could not read Path from " 978 "IMC key '" TSTR "'", name); 979 RegCloseKey(hk2); 980 continue; 981 } 982 983 val = os_malloc(buflen); 984 if (val == NULL) { 985 RegCloseKey(hk2); 986 continue; 987 } 988 989 ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, 990 (LPBYTE) val, &buflen); 991 if (ret != ERROR_SUCCESS) { 992 os_free(val); 993 RegCloseKey(hk2); 994 continue; 995 } 996 997 RegCloseKey(hk2); 998 999 wpa_unicode2ascii_inplace(val); 1000 wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val); 1001 1002 for (j = 0; j < TNC_MAX_IMC_ID; j++) { 1003 if (tnc_imc[j] == NULL) 1004 break; 1005 } 1006 if (j >= TNC_MAX_IMC_ID) { 1007 wpa_printf(MSG_DEBUG, "TNC: Too many IMCs"); 1008 os_free(val); 1009 continue; 1010 } 1011 1012 imc = os_zalloc(sizeof(*imc)); 1013 if (imc == NULL) { 1014 os_free(val); 1015 break; 1016 } 1017 1018 imc->imcID = j; 1019 1020 wpa_unicode2ascii_inplace(name); 1021 imc->name = os_strdup((char *) name); 1022 imc->path = os_strdup((char *) val); 1023 1024 os_free(val); 1025 1026 if (last == NULL) 1027 tncc->imc = imc; 1028 else 1029 last->next = imc; 1030 last = imc; 1031 1032 tnc_imc[imc->imcID] = imc; 1033 } 1034 1035 RegCloseKey(hk); 1036 1037 return 0; 1038 } 1039 1040 1041 static int tncc_read_config(struct tncc_data *tncc) 1042 { 1043 if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 || 1044 tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0) 1045 return -1; 1046 return 0; 1047 } 1048 1049 #else /* CONFIG_NATIVE_WINDOWS */ 1050 1051 static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error) 1052 { 1053 struct tnc_if_imc *imc; 1054 char *pos, *pos2; 1055 int i; 1056 1057 for (i = 0; i < TNC_MAX_IMC_ID; i++) { 1058 if (tnc_imc[i] == NULL) 1059 break; 1060 } 1061 if (i >= TNC_MAX_IMC_ID) { 1062 wpa_printf(MSG_DEBUG, "TNC: Too many IMCs"); 1063 return NULL; 1064 } 1065 1066 imc = os_zalloc(sizeof(*imc)); 1067 if (imc == NULL) { 1068 *error = 1; 1069 return NULL; 1070 } 1071 1072 imc->imcID = i; 1073 1074 pos = start; 1075 wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos); 1076 if (pos + 1 >= end || *pos != '"') { 1077 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " 1078 "(no starting quotation mark)", start); 1079 os_free(imc); 1080 return NULL; 1081 } 1082 1083 pos++; 1084 pos2 = pos; 1085 while (pos2 < end && *pos2 != '"') 1086 pos2++; 1087 if (pos2 >= end) { 1088 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " 1089 "(no ending quotation mark)", start); 1090 os_free(imc); 1091 return NULL; 1092 } 1093 *pos2 = '\0'; 1094 wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos); 1095 imc->name = os_strdup(pos); 1096 1097 pos = pos2 + 1; 1098 if (pos >= end || *pos != ' ') { 1099 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' " 1100 "(no space after name)", start); 1101 os_free(imc->name); 1102 os_free(imc); 1103 return NULL; 1104 } 1105 1106 pos++; 1107 wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos); 1108 imc->path = os_strdup(pos); 1109 tnc_imc[imc->imcID] = imc; 1110 1111 return imc; 1112 } 1113 1114 1115 static int tncc_read_config(struct tncc_data *tncc) 1116 { 1117 char *config, *end, *pos, *line_end; 1118 size_t config_len; 1119 struct tnc_if_imc *imc, *last; 1120 1121 last = NULL; 1122 1123 config = os_readfile(TNC_CONFIG_FILE, &config_len); 1124 if (config == NULL) { 1125 wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration " 1126 "file '%s'", TNC_CONFIG_FILE); 1127 return -1; 1128 } 1129 1130 end = config + config_len; 1131 for (pos = config; pos < end; pos = line_end + 1) { 1132 line_end = pos; 1133 while (*line_end != '\n' && *line_end != '\r' && 1134 line_end < end) 1135 line_end++; 1136 *line_end = '\0'; 1137 1138 if (os_strncmp(pos, "IMC ", 4) == 0) { 1139 int error = 0; 1140 1141 imc = tncc_parse_imc(pos + 4, line_end, &error); 1142 if (error) 1143 return -1; 1144 if (imc) { 1145 if (last == NULL) 1146 tncc->imc = imc; 1147 else 1148 last->next = imc; 1149 last = imc; 1150 } 1151 } 1152 } 1153 1154 os_free(config); 1155 1156 return 0; 1157 } 1158 1159 #endif /* CONFIG_NATIVE_WINDOWS */ 1160 1161 1162 struct tncc_data * tncc_init(void) 1163 { 1164 struct tncc_data *tncc; 1165 struct tnc_if_imc *imc; 1166 1167 tncc = os_zalloc(sizeof(*tncc)); 1168 if (tncc == NULL) 1169 return NULL; 1170 1171 /* TODO: 1172 * move loading and Initialize() to a location that is not 1173 * re-initialized for every EAP-TNC session (?) 1174 */ 1175 1176 if (tncc_read_config(tncc) < 0) { 1177 wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration"); 1178 goto failed; 1179 } 1180 1181 for (imc = tncc->imc; imc; imc = imc->next) { 1182 if (tncc_load_imc(imc)) { 1183 wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'", 1184 imc->name); 1185 goto failed; 1186 } 1187 } 1188 1189 return tncc; 1190 1191 failed: 1192 tncc_deinit(tncc); 1193 return NULL; 1194 } 1195 1196 1197 void tncc_deinit(struct tncc_data *tncc) 1198 { 1199 struct tnc_if_imc *imc, *prev; 1200 1201 imc = tncc->imc; 1202 while (imc) { 1203 tncc_unload_imc(imc); 1204 1205 prev = imc; 1206 imc = imc->next; 1207 os_free(prev); 1208 } 1209 1210 os_free(tncc); 1211 } 1212 1213 1214 static struct wpabuf * tncc_build_soh(int ver) 1215 { 1216 struct wpabuf *buf; 1217 u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end; 1218 u8 correlation_id[24]; 1219 /* TODO: get correct name */ 1220 char *machinename = "wpa_supplicant (at) w1.fi"; 1221 1222 if (os_get_random(correlation_id, sizeof(correlation_id))) 1223 return NULL; 1224 wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID", 1225 correlation_id, sizeof(correlation_id)); 1226 1227 buf = wpabuf_alloc(200); 1228 if (buf == NULL) 1229 return NULL; 1230 1231 /* Vendor-Specific TLV (Microsoft) - SoH */ 1232 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */ 1233 tlv_len = wpabuf_put(buf, 2); /* Length */ 1234 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */ 1235 wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */ 1236 tlv_len2 = wpabuf_put(buf, 2); /* Length */ 1237 1238 /* SoH Header */ 1239 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */ 1240 outer_len = wpabuf_put(buf, 2); 1241 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ 1242 wpabuf_put_be16(buf, ver); /* Inner Type */ 1243 inner_len = wpabuf_put(buf, 2); 1244 1245 if (ver == 2) { 1246 /* SoH Mode Sub-Header */ 1247 /* Outer Type */ 1248 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); 1249 wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */ 1250 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ 1251 /* Value: */ 1252 wpabuf_put_data(buf, correlation_id, sizeof(correlation_id)); 1253 wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */ 1254 wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */ 1255 } 1256 1257 /* SSoH TLV */ 1258 /* System-Health-Id */ 1259 wpabuf_put_be16(buf, 0x0002); /* Type */ 1260 wpabuf_put_be16(buf, 4); /* Length */ 1261 wpabuf_put_be32(buf, 79616); 1262 /* Vendor-Specific Attribute */ 1263 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); 1264 ssoh_len = wpabuf_put(buf, 2); 1265 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */ 1266 1267 /* MS-Packet-Info */ 1268 wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO); 1269 /* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be: 1270 * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP 1271 * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit 1272 * would not be in the specified location. 1273 * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits) 1274 */ 1275 wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */ 1276 1277 /* MS-Machine-Inventory */ 1278 /* TODO: get correct values; 0 = not applicable for OS */ 1279 wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY); 1280 wpabuf_put_be32(buf, 0); /* osVersionMajor */ 1281 wpabuf_put_be32(buf, 0); /* osVersionMinor */ 1282 wpabuf_put_be32(buf, 0); /* osVersionBuild */ 1283 wpabuf_put_be16(buf, 0); /* spVersionMajor */ 1284 wpabuf_put_be16(buf, 0); /* spVersionMinor */ 1285 wpabuf_put_be16(buf, 0); /* procArch */ 1286 1287 /* MS-MachineName */ 1288 wpabuf_put_u8(buf, SSOH_MS_MACHINENAME); 1289 wpabuf_put_be16(buf, os_strlen(machinename) + 1); 1290 wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1); 1291 1292 /* MS-CorrelationId */ 1293 wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID); 1294 wpabuf_put_data(buf, correlation_id, sizeof(correlation_id)); 1295 1296 /* MS-Quarantine-State */ 1297 wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE); 1298 wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */ 1299 wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */ 1300 wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */ 1301 wpabuf_put_be16(buf, 1); /* urlLenInBytes */ 1302 wpabuf_put_u8(buf, 0); /* null termination for the url */ 1303 1304 /* MS-Machine-Inventory-Ex */ 1305 wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX); 1306 wpabuf_put_be32(buf, 0); /* Reserved 1307 * (note: Windows XP SP3 uses 0xdecafbad) */ 1308 wpabuf_put_u8(buf, 1); /* ProductType: Client */ 1309 1310 /* Update SSoH Length */ 1311 end = wpabuf_put(buf, 0); 1312 WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2); 1313 1314 /* TODO: SoHReportEntry TLV (zero or more) */ 1315 1316 /* Update length fields */ 1317 end = wpabuf_put(buf, 0); 1318 WPA_PUT_BE16(tlv_len, end - tlv_len - 2); 1319 WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2); 1320 WPA_PUT_BE16(outer_len, end - outer_len - 2); 1321 WPA_PUT_BE16(inner_len, end - inner_len - 2); 1322 1323 return buf; 1324 } 1325 1326 1327 struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len) 1328 { 1329 const u8 *pos; 1330 1331 wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len); 1332 1333 if (len < 12) 1334 return NULL; 1335 1336 /* SoH Request */ 1337 pos = data; 1338 1339 /* TLV Type */ 1340 if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV) 1341 return NULL; 1342 pos += 2; 1343 1344 /* Length */ 1345 if (WPA_GET_BE16(pos) < 8) 1346 return NULL; 1347 pos += 2; 1348 1349 /* Vendor_Id */ 1350 if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT) 1351 return NULL; 1352 pos += 4; 1353 1354 /* TLV Type */ 1355 if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */) 1356 return NULL; 1357 1358 wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received"); 1359 1360 return tncc_build_soh(2); 1361 } 1362