2 * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
3 * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
10 #ifndef CONFIG_NATIVE_WINDOWS
12 #endif /* CONFIG_NATIVE_WINDOWS */
16 #include "common/tnc.h"
18 #include "eap_common/eap_tlv_common.h"
19 #include "eap_common/eap_defs.h"
29 #ifndef TNC_CONFIG_FILE
30 #define TNC_CONFIG_FILE "/etc/tnc_config"
31 #endif /* TNC_CONFIG_FILE */
32 #define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
33 #define IF_TNCCS_START \
34 "<?xml version=\"1.0\"?>\n" \
35 "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
36 "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
37 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
38 "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
39 "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
40 #define IF_TNCCS_END "\n</TNCCS-Batch>"
44 /* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
46 SSOH_MS_MACHINE_INVENTORY = 1,
47 SSOH_MS_QUARANTINE_STATE = 2,
48 SSOH_MS_PACKET_INFO = 3,
49 SSOH_MS_SYSTEMGENERATED_IDS = 4,
50 SSOH_MS_MACHINENAME = 5,
51 SSOH_MS_CORRELATIONID = 6,
52 SSOH_MS_INSTALLED_SHVS = 7,
53 SSOH_MS_MACHINE_INVENTORY_EX = 8
57 struct tnc_if_imc *next;
60 void *dlhandle; /* from dlopen() */
62 TNC_ConnectionID connectionID;
63 TNC_MessageTypeList supported_types;
64 size_t num_supported_types;
68 /* Functions implemented by IMCs (with TNC_IMC_ prefix) */
69 TNC_Result (*Initialize)(
71 TNC_Version minVersion,
72 TNC_Version maxVersion,
73 TNC_Version *pOutActualVersion);
74 TNC_Result (*NotifyConnectionChange)(
76 TNC_ConnectionID connectionID,
77 TNC_ConnectionState newState);
78 TNC_Result (*BeginHandshake)(
80 TNC_ConnectionID connectionID);
81 TNC_Result (*ReceiveMessage)(
83 TNC_ConnectionID connectionID,
84 TNC_BufferReference messageBuffer,
85 TNC_UInt32 messageLength,
86 TNC_MessageType messageType);
87 TNC_Result (*BatchEnding)(
89 TNC_ConnectionID connectionID);
90 TNC_Result (*Terminate)(TNC_IMCID imcID);
91 TNC_Result (*ProvideBindFunction)(
93 TNC_TNCC_BindFunctionPointer bindFunction);
97 struct tnc_if_imc *imc;
98 unsigned int last_batchid;
101 #define TNC_MAX_IMC_ID 10
102 static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
105 /* TNCC functions that IMCs can call */
107 static TNC_Result TNC_TNCC_ReportMessageTypes(
109 TNC_MessageTypeList supportedTypes,
110 TNC_UInt32 typeCount)
113 struct tnc_if_imc *imc;
115 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
117 (unsigned long) imcID, (unsigned long) typeCount);
119 for (i = 0; i < typeCount; i++) {
120 wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
121 i, supportedTypes[i]);
124 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
125 return TNC_RESULT_INVALID_PARAMETER;
127 imc = tnc_imc[imcID];
128 os_free(imc->supported_types);
129 imc->supported_types =
130 os_malloc(typeCount * sizeof(TNC_MessageType));
131 if (imc->supported_types == NULL)
132 return TNC_RESULT_FATAL;
133 os_memcpy(imc->supported_types, supportedTypes,
134 typeCount * sizeof(TNC_MessageType));
135 imc->num_supported_types = typeCount;
137 return TNC_RESULT_SUCCESS;
141 static TNC_Result TNC_TNCC_SendMessage(
143 TNC_ConnectionID connectionID,
144 TNC_BufferReference message,
145 TNC_UInt32 messageLength,
146 TNC_MessageType messageType)
148 struct tnc_if_imc *imc;
152 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
153 "connectionID=%lu messageType=%lu)",
154 imcID, connectionID, messageType);
155 wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
156 message, messageLength);
158 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
159 return TNC_RESULT_INVALID_PARAMETER;
161 b64 = base64_encode(message, messageLength, &b64len);
163 return TNC_RESULT_FATAL;
165 imc = tnc_imc[imcID];
166 os_free(imc->imc_send);
167 imc->imc_send_len = 0;
168 imc->imc_send = os_zalloc(b64len + 100);
169 if (imc->imc_send == NULL) {
171 return TNC_RESULT_OTHER;
175 os_snprintf((char *) imc->imc_send, b64len + 100,
176 "<IMC-IMV-Message><Type>%08X</Type>"
177 "<Base64>%s</Base64></IMC-IMV-Message>",
178 (unsigned int) messageType, b64);
182 return TNC_RESULT_SUCCESS;
186 static TNC_Result TNC_TNCC_RequestHandshakeRetry(
188 TNC_ConnectionID connectionID,
189 TNC_RetryReason reason)
191 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
193 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
194 return TNC_RESULT_INVALID_PARAMETER;
197 * TODO: trigger a call to eapol_sm_request_reauth(). This would
198 * require that the IMC continues to be loaded in memory afer
202 return TNC_RESULT_SUCCESS;
206 static TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
209 wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
210 "severity==%lu message='%s')",
211 imcID, severity, message);
212 return TNC_RESULT_SUCCESS;
216 static TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID,
217 TNC_ConnectionID connectionID,
220 wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
221 "connectionID==%lu message='%s')",
222 imcID, connectionID, message);
223 return TNC_RESULT_SUCCESS;
227 static TNC_Result TNC_TNCC_BindFunction(
230 void **pOutfunctionPointer)
232 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
233 "functionName='%s')", (unsigned long) imcID, functionName);
235 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
236 return TNC_RESULT_INVALID_PARAMETER;
238 if (pOutfunctionPointer == NULL)
239 return TNC_RESULT_INVALID_PARAMETER;
241 if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
242 *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
243 else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
244 *pOutfunctionPointer = TNC_TNCC_SendMessage;
245 else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
247 *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
248 else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
249 *pOutfunctionPointer = TNC_9048_LogMessage;
250 else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
251 *pOutfunctionPointer = TNC_9048_UserMessage;
253 *pOutfunctionPointer = NULL;
255 return TNC_RESULT_SUCCESS;
259 static void * tncc_get_sym(void *handle, char *func)
263 #ifdef CONFIG_NATIVE_WINDOWS
265 fptr = GetProcAddressA(handle, func);
266 #else /* _WIN32_WCE */
267 fptr = GetProcAddress(handle, func);
268 #endif /* _WIN32_WCE */
269 #else /* CONFIG_NATIVE_WINDOWS */
270 fptr = dlsym(handle, func);
271 #endif /* CONFIG_NATIVE_WINDOWS */
277 static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
279 void *handle = imc->dlhandle;
281 /* Mandatory IMC functions */
282 imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
283 if (imc->Initialize == NULL) {
284 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
285 "TNC_IMC_Initialize");
289 imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
290 if (imc->BeginHandshake == NULL) {
291 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
292 "TNC_IMC_BeginHandshake");
296 imc->ProvideBindFunction =
297 tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
298 if (imc->ProvideBindFunction == NULL) {
299 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
300 "TNC_IMC_ProvideBindFunction");
304 /* Optional IMC functions */
305 imc->NotifyConnectionChange =
306 tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
307 imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
308 imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
309 imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
315 static int tncc_imc_initialize(struct tnc_if_imc *imc)
320 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
322 res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
323 TNC_IFIMC_VERSION_1, &imc_ver);
324 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
325 (unsigned long) res, (unsigned long) imc_ver);
327 return res == TNC_RESULT_SUCCESS ? 0 : -1;
331 static int tncc_imc_terminate(struct tnc_if_imc *imc)
335 if (imc->Terminate == NULL)
338 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
340 res = imc->Terminate(imc->imcID);
341 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
342 (unsigned long) res);
344 return res == TNC_RESULT_SUCCESS ? 0 : -1;
348 static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
352 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
353 "IMC '%s'", imc->name);
354 res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
355 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
356 (unsigned long) res);
358 return res == TNC_RESULT_SUCCESS ? 0 : -1;
362 static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
363 TNC_ConnectionState state)
367 if (imc->NotifyConnectionChange == NULL)
370 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
371 " for IMC '%s'", (int) state, imc->name);
372 res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
374 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
375 (unsigned long) res);
377 return res == TNC_RESULT_SUCCESS ? 0 : -1;
381 static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
385 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
387 res = imc->BeginHandshake(imc->imcID, imc->connectionID);
388 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
389 (unsigned long) res);
391 return res == TNC_RESULT_SUCCESS ? 0 : -1;
395 static int tncc_load_imc(struct tnc_if_imc *imc)
397 if (imc->path == NULL) {
398 wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
402 wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
403 imc->name, imc->path);
404 #ifdef CONFIG_NATIVE_WINDOWS
407 TCHAR *lib = wpa_strdup_tchar(imc->path);
410 imc->dlhandle = LoadLibrary(lib);
414 imc->dlhandle = LoadLibrary(imc->path);
416 if (imc->dlhandle == NULL) {
417 wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
418 imc->name, imc->path, (int) GetLastError());
421 #else /* CONFIG_NATIVE_WINDOWS */
422 imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
423 if (imc->dlhandle == NULL) {
424 wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
425 imc->name, imc->path, dlerror());
428 #endif /* CONFIG_NATIVE_WINDOWS */
430 if (tncc_imc_resolve_funcs(imc) < 0) {
431 wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
435 if (tncc_imc_initialize(imc) < 0 ||
436 tncc_imc_provide_bind_function(imc) < 0) {
437 wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
445 static void tncc_unload_imc(struct tnc_if_imc *imc)
447 tncc_imc_terminate(imc);
448 tnc_imc[imc->imcID] = NULL;
451 #ifdef CONFIG_NATIVE_WINDOWS
452 FreeLibrary(imc->dlhandle);
453 #else /* CONFIG_NATIVE_WINDOWS */
454 dlclose(imc->dlhandle);
455 #endif /* CONFIG_NATIVE_WINDOWS */
459 os_free(imc->supported_types);
460 os_free(imc->imc_send);
464 static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
467 unsigned int vendor, subtype;
469 if (imc == NULL || imc->supported_types == NULL)
473 subtype = type & 0xff;
475 for (i = 0; i < imc->num_supported_types; i++) {
476 unsigned int svendor, ssubtype;
477 svendor = imc->supported_types[i] >> 8;
478 ssubtype = imc->supported_types[i] & 0xff;
479 if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
480 (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
488 static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
489 const u8 *msg, size_t len)
491 struct tnc_if_imc *imc;
494 wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
496 for (imc = tncc->imc; imc; imc = imc->next) {
497 if (imc->ReceiveMessage == NULL ||
498 !tncc_supported_type(imc, type))
501 wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
503 res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
504 (TNC_BufferReference) msg, len,
506 wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
507 (unsigned long) res);
512 void tncc_init_connection(struct tncc_data *tncc)
514 struct tnc_if_imc *imc;
516 for (imc = tncc->imc; imc; imc = imc->next) {
517 tncc_imc_notify_connection_change(
518 imc, TNC_CONNECTION_STATE_CREATE);
519 tncc_imc_notify_connection_change(
520 imc, TNC_CONNECTION_STATE_HANDSHAKE);
522 os_free(imc->imc_send);
523 imc->imc_send = NULL;
524 imc->imc_send_len = 0;
526 tncc_imc_begin_handshake(imc);
531 size_t tncc_total_send_len(struct tncc_data *tncc)
533 struct tnc_if_imc *imc;
536 for (imc = tncc->imc; imc; imc = imc->next)
537 len += imc->imc_send_len;
542 u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
544 struct tnc_if_imc *imc;
546 for (imc = tncc->imc; imc; imc = imc->next) {
547 if (imc->imc_send == NULL)
550 os_memcpy(pos, imc->imc_send, imc->imc_send_len);
551 pos += imc->imc_send_len;
552 os_free(imc->imc_send);
553 imc->imc_send = NULL;
554 imc->imc_send_len = 0;
561 char * tncc_if_tnccs_start(struct tncc_data *tncc)
563 char *buf = os_malloc(1000);
566 tncc->last_batchid++;
567 os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
572 char * tncc_if_tnccs_end(void)
574 char *buf = os_malloc(100);
577 os_snprintf(buf, 100, IF_TNCCS_END);
582 static void tncc_notify_recommendation(struct tncc_data *tncc,
583 enum tncc_process_res res)
585 TNC_ConnectionState state;
586 struct tnc_if_imc *imc;
589 case TNCCS_RECOMMENDATION_ALLOW:
590 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
592 case TNCCS_RECOMMENDATION_NONE:
593 state = TNC_CONNECTION_STATE_ACCESS_NONE;
595 case TNCCS_RECOMMENDATION_ISOLATE:
596 state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
599 state = TNC_CONNECTION_STATE_ACCESS_NONE;
603 for (imc = tncc->imc; imc; imc = imc->next)
604 tncc_imc_notify_connection_change(imc, state);
608 static int tncc_get_type(char *start, unsigned int *type)
610 char *pos = os_strstr(start, "<Type>");
614 *type = strtoul(pos, NULL, 16);
619 static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
622 unsigned char *decoded;
624 pos = os_strstr(start, "<Base64>");
629 pos2 = os_strstr(pos, "</Base64>");
634 decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
637 if (decoded == NULL) {
638 wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
645 static enum tncc_process_res tncc_get_recommendation(char *start)
647 char *pos, *pos2, saved;
650 pos = os_strstr(start, "<TNCCS-Recommendation ");
652 return TNCCS_RECOMMENDATION_ERROR;
655 pos = os_strstr(pos, " type=");
657 return TNCCS_RECOMMENDATION_ERROR;
664 while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
668 return TNCCS_RECOMMENDATION_ERROR;
672 wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
674 recom = TNCCS_RECOMMENDATION_ERROR;
675 if (os_strcmp(pos, "allow") == 0)
676 recom = TNCCS_RECOMMENDATION_ALLOW;
677 else if (os_strcmp(pos, "none") == 0)
678 recom = TNCCS_RECOMMENDATION_NONE;
679 else if (os_strcmp(pos, "isolate") == 0)
680 recom = TNCCS_RECOMMENDATION_ISOLATE;
688 enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
689 const u8 *msg, size_t len)
691 char *buf, *start, *end, *pos, *pos2, *payload;
692 unsigned int batch_id;
693 unsigned char *decoded;
695 enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
696 int recommendation_msg = 0;
698 wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Received IF-TNCCS message",
700 buf = dup_binstr(msg, len);
702 return TNCCS_PROCESS_ERROR;
704 start = os_strstr(buf, "<TNCCS-Batch ");
705 end = os_strstr(buf, "</TNCCS-Batch>");
706 if (start == NULL || end == NULL || start > end) {
708 return TNCCS_PROCESS_ERROR;
712 while (*start == ' ')
716 pos = os_strstr(start, "BatchId=");
719 return TNCCS_PROCESS_ERROR;
725 batch_id = atoi(pos);
726 wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
728 if (batch_id != tncc->last_batchid + 1) {
729 wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
731 batch_id, tncc->last_batchid + 1);
733 return TNCCS_PROCESS_ERROR;
735 tncc->last_batchid = batch_id;
737 while (*pos != '\0' && *pos != '>')
741 return TNCCS_PROCESS_ERROR;
748 * <Type>01234567</Type>
749 * <Base64>foo==</Base64>
757 pos = os_strstr(start, "<IMC-IMV-Message>");
761 end = os_strstr(start, "</IMC-IMV-Message>");
768 if (tncc_get_type(start, &type) < 0) {
773 wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
775 decoded = tncc_get_base64(start, &decoded_len);
776 if (decoded == NULL) {
782 tncc_send_to_imcs(tncc, type, decoded, decoded_len);
790 * <TNCC-TNCS-Message>
791 * <Type>01234567</Type>
792 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
793 * <Base64>foo==</Base64>
794 * </TNCC-TNCS-Message>
800 char *xml, *xmlend, *endpos;
802 pos = os_strstr(start, "<TNCC-TNCS-Message>");
806 end = os_strstr(start, "</TNCC-TNCS-Message>");
813 if (tncc_get_type(start, &type) < 0) {
818 wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
825 pos = os_strstr(start, "<XML>");
828 pos2 = os_strstr(pos, "</XML>");
837 decoded = tncc_get_base64(start, &decoded_len);
838 if (decoded == NULL) {
846 wpa_hexdump_ascii(MSG_MSGDUMP,
847 "TNC: TNCC-TNCS-Message Base64",
848 decoded, decoded_len);
853 wpa_hexdump_ascii(MSG_MSGDUMP,
854 "TNC: TNCC-TNCS-Message XML",
855 (unsigned char *) xml,
859 if (type == TNC_TNCCS_RECOMMENDATION && xml) {
861 * <TNCCS-Recommendation type="allow">
862 * </TNCCS-Recommendation>
865 res = tncc_get_recommendation(xml);
867 recommendation_msg = 1;
875 if (recommendation_msg)
876 tncc_notify_recommendation(tncc, res);
882 #ifdef CONFIG_NATIVE_WINDOWS
883 static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
888 struct tnc_if_imc *imc, *last;
892 while (last && last->next)
895 ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
897 if (ret != ERROR_SUCCESS)
901 TCHAR name[255], *val;
902 DWORD namelen, buflen;
905 ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
908 if (ret == ERROR_NO_MORE_ITEMS)
911 if (ret != ERROR_SUCCESS) {
912 wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
919 name[namelen] = '\0';
921 wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
923 ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
924 if (ret != ERROR_SUCCESS) {
925 wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
930 ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
932 if (ret != ERROR_SUCCESS) {
933 wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
934 "IMC key '" TSTR "'", name);
939 val = os_malloc(buflen);
945 ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
946 (LPBYTE) val, &buflen);
947 if (ret != ERROR_SUCCESS) {
955 wpa_unicode2ascii_inplace(val);
956 wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
958 for (j = 0; j < TNC_MAX_IMC_ID; j++) {
959 if (tnc_imc[j] == NULL)
962 if (j >= TNC_MAX_IMC_ID) {
963 wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
968 imc = os_zalloc(sizeof(*imc));
976 wpa_unicode2ascii_inplace(name);
977 imc->name = os_strdup((char *) name);
978 imc->path = os_strdup((char *) val);
988 tnc_imc[imc->imcID] = imc;
997 static int tncc_read_config(struct tncc_data *tncc)
999 if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
1000 tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
1005 #else /* CONFIG_NATIVE_WINDOWS */
1007 static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
1009 struct tnc_if_imc *imc;
1013 for (i = 0; i < TNC_MAX_IMC_ID; i++) {
1014 if (tnc_imc[i] == NULL)
1017 if (i >= TNC_MAX_IMC_ID) {
1018 wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
1022 imc = os_zalloc(sizeof(*imc));
1031 wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
1032 if (pos + 1 >= end || *pos != '"') {
1033 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1034 "(no starting quotation mark)", start);
1041 while (pos2 < end && *pos2 != '"')
1044 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1045 "(no ending quotation mark)", start);
1050 wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
1051 imc->name = os_strdup(pos);
1054 if (pos >= end || *pos != ' ') {
1055 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1056 "(no space after name)", start);
1063 wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
1064 imc->path = os_strdup(pos);
1065 tnc_imc[imc->imcID] = imc;
1071 static int tncc_read_config(struct tncc_data *tncc)
1073 char *config, *end, *pos, *line_end;
1075 struct tnc_if_imc *imc, *last;
1079 config = os_readfile(TNC_CONFIG_FILE, &config_len);
1080 if (config == NULL) {
1081 wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
1082 "file '%s'", TNC_CONFIG_FILE);
1086 end = config + config_len;
1087 for (pos = config; pos < end; pos = line_end + 1) {
1089 while (*line_end != '\n' && *line_end != '\r' &&
1094 if (os_strncmp(pos, "IMC ", 4) == 0) {
1097 imc = tncc_parse_imc(pos + 4, line_end, &error);
1117 #endif /* CONFIG_NATIVE_WINDOWS */
1120 struct tncc_data * tncc_init(void)
1122 struct tncc_data *tncc;
1123 struct tnc_if_imc *imc;
1125 tncc = os_zalloc(sizeof(*tncc));
1130 * move loading and Initialize() to a location that is not
1131 * re-initialized for every EAP-TNC session (?)
1134 if (tncc_read_config(tncc) < 0) {
1135 wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
1139 for (imc = tncc->imc; imc; imc = imc->next) {
1140 if (tncc_load_imc(imc)) {
1141 wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
1155 void tncc_deinit(struct tncc_data *tncc)
1157 struct tnc_if_imc *imc, *prev;
1161 tncc_unload_imc(imc);
1172 static struct wpabuf * tncc_build_soh(int ver)
1175 u8 *tlv_len, *tlv_len2, *outer_len, *inner_len, *ssoh_len, *end;
1176 u8 correlation_id[24];
1177 /* TODO: get correct name */
1178 char *machinename = "wpa_supplicant@w1.fi";
1180 if (os_get_random(correlation_id, sizeof(correlation_id)))
1182 wpa_hexdump(MSG_DEBUG, "TNC: SoH Correlation ID",
1183 correlation_id, sizeof(correlation_id));
1185 buf = wpabuf_alloc(200);
1189 /* Vendor-Specific TLV (Microsoft) - SoH */
1190 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
1191 tlv_len = wpabuf_put(buf, 2); /* Length */
1192 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
1193 wpabuf_put_be16(buf, 0x01); /* TLV Type - SoH TLV */
1194 tlv_len2 = wpabuf_put(buf, 2); /* Length */
1197 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* Outer Type */
1198 outer_len = wpabuf_put(buf, 2);
1199 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1200 wpabuf_put_be16(buf, ver); /* Inner Type */
1201 inner_len = wpabuf_put(buf, 2);
1204 /* SoH Mode Sub-Header */
1206 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
1207 wpabuf_put_be16(buf, 4 + 24 + 1 + 1); /* Length */
1208 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1210 wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
1211 wpabuf_put_u8(buf, 0x01); /* Intent Flag - Request */
1212 wpabuf_put_u8(buf, 0x00); /* Content-Type Flag */
1216 /* System-Health-Id */
1217 wpabuf_put_be16(buf, 0x0002); /* Type */
1218 wpabuf_put_be16(buf, 4); /* Length */
1219 wpabuf_put_be32(buf, 79616);
1220 /* Vendor-Specific Attribute */
1221 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV);
1222 ssoh_len = wpabuf_put(buf, 2);
1223 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* IANA SMI Code */
1225 /* MS-Packet-Info */
1226 wpabuf_put_u8(buf, SSOH_MS_PACKET_INFO);
1227 /* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be:
1228 * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP
1229 * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit
1230 * would not be in the specified location.
1231 * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits)
1233 wpabuf_put_u8(buf, 0x11); /* r=request, vers=1 */
1235 /* MS-Machine-Inventory */
1236 /* TODO: get correct values; 0 = not applicable for OS */
1237 wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY);
1238 wpabuf_put_be32(buf, 0); /* osVersionMajor */
1239 wpabuf_put_be32(buf, 0); /* osVersionMinor */
1240 wpabuf_put_be32(buf, 0); /* osVersionBuild */
1241 wpabuf_put_be16(buf, 0); /* spVersionMajor */
1242 wpabuf_put_be16(buf, 0); /* spVersionMinor */
1243 wpabuf_put_be16(buf, 0); /* procArch */
1245 /* MS-MachineName */
1246 wpabuf_put_u8(buf, SSOH_MS_MACHINENAME);
1247 wpabuf_put_be16(buf, os_strlen(machinename) + 1);
1248 wpabuf_put_data(buf, machinename, os_strlen(machinename) + 1);
1250 /* MS-CorrelationId */
1251 wpabuf_put_u8(buf, SSOH_MS_CORRELATIONID);
1252 wpabuf_put_data(buf, correlation_id, sizeof(correlation_id));
1254 /* MS-Quarantine-State */
1255 wpabuf_put_u8(buf, SSOH_MS_QUARANTINE_STATE);
1256 wpabuf_put_be16(buf, 1); /* Flags: ExtState=0, f=0, qState=1 */
1257 wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (hi) */
1258 wpabuf_put_be32(buf, 0xffffffff); /* ProbTime (lo) */
1259 wpabuf_put_be16(buf, 1); /* urlLenInBytes */
1260 wpabuf_put_u8(buf, 0); /* null termination for the url */
1262 /* MS-Machine-Inventory-Ex */
1263 wpabuf_put_u8(buf, SSOH_MS_MACHINE_INVENTORY_EX);
1264 wpabuf_put_be32(buf, 0); /* Reserved
1265 * (note: Windows XP SP3 uses 0xdecafbad) */
1266 wpabuf_put_u8(buf, 1); /* ProductType: Client */
1268 /* Update SSoH Length */
1269 end = wpabuf_put(buf, 0);
1270 WPA_PUT_BE16(ssoh_len, end - ssoh_len - 2);
1272 /* TODO: SoHReportEntry TLV (zero or more) */
1274 /* Update length fields */
1275 end = wpabuf_put(buf, 0);
1276 WPA_PUT_BE16(tlv_len, end - tlv_len - 2);
1277 WPA_PUT_BE16(tlv_len2, end - tlv_len2 - 2);
1278 WPA_PUT_BE16(outer_len, end - outer_len - 2);
1279 WPA_PUT_BE16(inner_len, end - inner_len - 2);
1285 struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len)
1289 wpa_hexdump(MSG_DEBUG, "TNC: SoH Request", data, len);
1298 if (WPA_GET_BE16(pos) != EAP_TLV_VENDOR_SPECIFIC_TLV)
1303 if (WPA_GET_BE16(pos) < 8)
1308 if (WPA_GET_BE32(pos) != EAP_VENDOR_MICROSOFT)
1313 if (WPA_GET_BE16(pos) != 0x02 /* SoH request TLV */)
1316 wpa_printf(MSG_DEBUG, "TNC: SoH Request TLV received");
1318 return tncc_build_soh(2);