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