2 * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
3 * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
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.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
16 #ifndef CONFIG_NATIVE_WINDOWS
18 #endif /* CONFIG_NATIVE_WINDOWS */
32 #define TNC_CONFIG_FILE "/etc/tnc_config"
33 #define TNC_WINREG_PATH TEXT("SOFTWARE\\Trusted Computing Group\\TNC\\IMCs")
34 #define IF_TNCCS_START \
35 "<?xml version=\"1.0\"?>\n" \
36 "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
37 "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
38 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
39 "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
40 "IF_TNCCS#https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
41 #define IF_TNCCS_END "\n</TNCCS-Batch>"
45 typedef unsigned long TNC_UInt32;
46 typedef unsigned char *TNC_BufferReference;
48 typedef TNC_UInt32 TNC_IMCID;
49 typedef TNC_UInt32 TNC_ConnectionID;
50 typedef TNC_UInt32 TNC_ConnectionState;
51 typedef TNC_UInt32 TNC_RetryReason;
52 typedef TNC_UInt32 TNC_MessageType;
53 typedef TNC_MessageType *TNC_MessageTypeList;
54 typedef TNC_UInt32 TNC_VendorID;
55 typedef TNC_UInt32 TNC_MessageSubtype;
56 typedef TNC_UInt32 TNC_Version;
57 typedef TNC_UInt32 TNC_Result;
59 typedef TNC_Result (*TNC_TNCC_BindFunctionPointer)(
62 void **pOutfunctionPointer);
64 #define TNC_RESULT_SUCCESS 0
65 #define TNC_RESULT_NOT_INITIALIZED 1
66 #define TNC_RESULT_ALREADY_INITIALIZED 2
67 #define TNC_RESULT_NO_COMMON_VERSION 3
68 #define TNC_RESULT_CANT_RETRY 4
69 #define TNC_RESULT_WONT_RETRY 5
70 #define TNC_RESULT_INVALID_PARAMETER 6
71 #define TNC_RESULT_CANT_RESPOND 7
72 #define TNC_RESULT_ILLEGAL_OPERATION 8
73 #define TNC_RESULT_OTHER 9
74 #define TNC_RESULT_FATAL 10
76 #define TNC_CONNECTION_STATE_CREATE 0
77 #define TNC_CONNECTION_STATE_HANDSHAKE 1
78 #define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
79 #define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
80 #define TNC_CONNECTION_STATE_ACCESS_NONE 4
81 #define TNC_CONNECTION_STATE_DELETE 5
83 #define TNC_IFIMC_VERSION_1 1
85 #define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
86 #define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff)
88 /* TNCC-TNCS Message Types */
89 #define TNC_TNCCS_RECOMMENDATION 0x00000001
90 #define TNC_TNCCS_ERROR 0x00000002
91 #define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003
92 #define TNC_TNCCS_REASONSTRINGS 0x00000004
96 struct tnc_if_imc *next;
99 void *dlhandle; /* from dlopen() */
101 TNC_ConnectionID connectionID;
102 TNC_MessageTypeList supported_types;
103 size_t num_supported_types;
107 /* Functions implemented by IMCs (with TNC_IMC_ prefix) */
108 TNC_Result (*Initialize)(
110 TNC_Version minVersion,
111 TNC_Version maxVersion,
112 TNC_Version *pOutActualVersion);
113 TNC_Result (*NotifyConnectionChange)(
115 TNC_ConnectionID connectionID,
116 TNC_ConnectionState newState);
117 TNC_Result (*BeginHandshake)(
119 TNC_ConnectionID connectionID);
120 TNC_Result (*ReceiveMessage)(
122 TNC_ConnectionID connectionID,
123 TNC_BufferReference messageBuffer,
124 TNC_UInt32 messageLength,
125 TNC_MessageType messageType);
126 TNC_Result (*BatchEnding)(
128 TNC_ConnectionID connectionID);
129 TNC_Result (*Terminate)(TNC_IMCID imcID);
130 TNC_Result (*ProvideBindFunction)(
132 TNC_TNCC_BindFunctionPointer bindFunction);
136 struct tnc_if_imc *imc;
137 unsigned int last_batchid;
140 #define TNC_MAX_IMC_ID 10
141 static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
144 /* TNCC functions that IMCs can call */
146 TNC_Result TNC_TNCC_ReportMessageTypes(
148 TNC_MessageTypeList supportedTypes,
149 TNC_UInt32 typeCount)
152 struct tnc_if_imc *imc;
154 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
156 (unsigned long) imcID, (unsigned long) typeCount);
158 for (i = 0; i < typeCount; i++) {
159 wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
160 i, supportedTypes[i]);
163 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
164 return TNC_RESULT_INVALID_PARAMETER;
166 imc = tnc_imc[imcID];
167 os_free(imc->supported_types);
168 imc->supported_types =
169 os_malloc(typeCount * sizeof(TNC_MessageTypeList));
170 if (imc->supported_types == NULL)
171 return TNC_RESULT_FATAL;
172 os_memcpy(imc->supported_types, supportedTypes,
173 typeCount * sizeof(TNC_MessageTypeList));
174 imc->num_supported_types = typeCount;
176 return TNC_RESULT_SUCCESS;
180 TNC_Result TNC_TNCC_SendMessage(
182 TNC_ConnectionID connectionID,
183 TNC_BufferReference message,
184 TNC_UInt32 messageLength,
185 TNC_MessageType messageType)
187 struct tnc_if_imc *imc;
191 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
192 "connectionID=%lu messageType=%lu)",
193 imcID, connectionID, messageType);
194 wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
195 message, messageLength);
197 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
198 return TNC_RESULT_INVALID_PARAMETER;
200 b64 = base64_encode(message, messageLength, &b64len);
202 return TNC_RESULT_FATAL;
204 imc = tnc_imc[imcID];
205 os_free(imc->imc_send);
206 imc->imc_send_len = 0;
207 imc->imc_send = os_zalloc(b64len + 100);
208 if (imc->imc_send == NULL) {
210 return TNC_RESULT_OTHER;
214 os_snprintf((char *) imc->imc_send, b64len + 100,
215 "<IMC-IMV-Message><Type>%08X</Type>"
216 "<Base64>%s</Base64></IMC-IMV-Message>",
217 (unsigned int) messageType, b64);
221 return TNC_RESULT_SUCCESS;
225 TNC_Result TNC_TNCC_RequestHandshakeRetry(
227 TNC_ConnectionID connectionID,
228 TNC_RetryReason reason)
230 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
232 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
233 return TNC_RESULT_INVALID_PARAMETER;
236 * TODO: trigger a call to eapol_sm_request_reauth(). This would
237 * require that the IMC continues to be loaded in memory afer
241 return TNC_RESULT_SUCCESS;
245 TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
248 wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
249 "severity==%lu message='%s')",
250 imcID, severity, message);
251 return TNC_RESULT_SUCCESS;
255 TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID,
258 wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
259 "connectionID==%lu message='%s')",
260 imcID, connectionID, message);
261 return TNC_RESULT_SUCCESS;
265 TNC_Result TNC_TNCC_BindFunction(
268 void **pOutfunctionPointer)
270 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
271 "functionName='%s')", (unsigned long) imcID, functionName);
273 if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
274 return TNC_RESULT_INVALID_PARAMETER;
276 if (pOutfunctionPointer == NULL)
277 return TNC_RESULT_INVALID_PARAMETER;
279 if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
280 *pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
281 else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
282 *pOutfunctionPointer = TNC_TNCC_SendMessage;
283 else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
285 *pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
286 else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
287 *pOutfunctionPointer = TNC_9048_LogMessage;
288 else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
289 *pOutfunctionPointer = TNC_9048_UserMessage;
291 *pOutfunctionPointer = NULL;
293 return TNC_RESULT_SUCCESS;
297 static void * tncc_get_sym(void *handle, char *func)
301 #ifdef CONFIG_NATIVE_WINDOWS
303 fptr = GetProcAddressA(handle, func);
304 #else /* _WIN32_WCE */
305 fptr = GetProcAddress(handle, func);
306 #endif /* _WIN32_WCE */
307 #else /* CONFIG_NATIVE_WINDOWS */
308 fptr = dlsym(handle, func);
309 #endif /* CONFIG_NATIVE_WINDOWS */
315 static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
317 void *handle = imc->dlhandle;
319 /* Mandatory IMC functions */
320 imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
321 if (imc->Initialize == NULL) {
322 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
323 "TNC_IMC_Initialize");
327 imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
328 if (imc->BeginHandshake == NULL) {
329 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
330 "TNC_IMC_BeginHandshake");
334 imc->ProvideBindFunction =
335 tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
336 if (imc->ProvideBindFunction == NULL) {
337 wpa_printf(MSG_ERROR, "TNC: IMC does not export "
338 "TNC_IMC_ProvideBindFunction");
342 /* Optional IMC functions */
343 imc->NotifyConnectionChange =
344 tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
345 imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
346 imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
347 imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
353 static int tncc_imc_initialize(struct tnc_if_imc *imc)
358 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
360 res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
361 TNC_IFIMC_VERSION_1, &imc_ver);
362 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
363 (unsigned long) res, (unsigned long) imc_ver);
365 return res == TNC_RESULT_SUCCESS ? 0 : -1;
369 static int tncc_imc_terminate(struct tnc_if_imc *imc)
373 if (imc->Terminate == NULL)
376 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
378 res = imc->Terminate(imc->imcID);
379 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
380 (unsigned long) res);
382 return res == TNC_RESULT_SUCCESS ? 0 : -1;
386 static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
390 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
391 "IMC '%s'", imc->name);
392 res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
393 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
394 (unsigned long) res);
396 return res == TNC_RESULT_SUCCESS ? 0 : -1;
400 static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
401 TNC_ConnectionState state)
405 if (imc->NotifyConnectionChange == NULL)
408 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
409 " for IMC '%s'", (int) state, imc->name);
410 res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
412 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
413 (unsigned long) res);
415 return res == TNC_RESULT_SUCCESS ? 0 : -1;
419 static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
423 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
425 res = imc->BeginHandshake(imc->imcID, imc->connectionID);
426 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
427 (unsigned long) res);
429 return res == TNC_RESULT_SUCCESS ? 0 : -1;
433 static int tncc_load_imc(struct tnc_if_imc *imc)
435 if (imc->path == NULL) {
436 wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
440 wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
441 imc->name, imc->path);
442 #ifdef CONFIG_NATIVE_WINDOWS
445 TCHAR *lib = wpa_strdup_tchar(imc->path);
448 imc->dlhandle = LoadLibrary(lib);
452 imc->dlhandle = LoadLibrary(imc->path);
454 if (imc->dlhandle == NULL) {
455 wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
456 imc->name, imc->path, (int) GetLastError());
459 #else /* CONFIG_NATIVE_WINDOWS */
460 imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
461 if (imc->dlhandle == NULL) {
462 wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
463 imc->name, imc->path, dlerror());
466 #endif /* CONFIG_NATIVE_WINDOWS */
468 if (tncc_imc_resolve_funcs(imc) < 0) {
469 wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
473 if (tncc_imc_initialize(imc) < 0 ||
474 tncc_imc_provide_bind_function(imc) < 0) {
475 wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
483 static void tncc_unload_imc(struct tnc_if_imc *imc)
485 tncc_imc_terminate(imc);
486 tnc_imc[imc->imcID] = NULL;
489 #ifdef CONFIG_NATIVE_WINDOWS
490 FreeLibrary(imc->dlhandle);
491 #else /* CONFIG_NATIVE_WINDOWS */
492 dlclose(imc->dlhandle);
493 #endif /* CONFIG_NATIVE_WINDOWS */
497 os_free(imc->supported_types);
498 os_free(imc->imc_send);
502 static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
505 unsigned int vendor, subtype;
507 if (imc == NULL || imc->supported_types == NULL)
511 subtype = type & 0xff;
513 for (i = 0; i < imc->num_supported_types; i++) {
514 unsigned int svendor, ssubtype;
515 svendor = imc->supported_types[i] >> 8;
516 ssubtype = imc->supported_types[i] & 0xff;
517 if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
518 (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
526 static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
527 const u8 *msg, size_t len)
529 struct tnc_if_imc *imc;
532 wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
534 for (imc = tncc->imc; imc; imc = imc->next) {
535 if (imc->ReceiveMessage == NULL ||
536 !tncc_supported_type(imc, type))
539 wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
541 res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
542 (TNC_BufferReference) msg, len,
544 wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
545 (unsigned long) res);
550 void tncc_init_connection(struct tncc_data *tncc)
552 struct tnc_if_imc *imc;
554 for (imc = tncc->imc; imc; imc = imc->next) {
555 tncc_imc_notify_connection_change(
556 imc, TNC_CONNECTION_STATE_CREATE);
557 tncc_imc_notify_connection_change(
558 imc, TNC_CONNECTION_STATE_HANDSHAKE);
560 os_free(imc->imc_send);
561 imc->imc_send = NULL;
562 imc->imc_send_len = 0;
564 tncc_imc_begin_handshake(imc);
569 size_t tncc_total_send_len(struct tncc_data *tncc)
571 struct tnc_if_imc *imc;
574 for (imc = tncc->imc; imc; imc = imc->next)
575 len += imc->imc_send_len;
580 u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
582 struct tnc_if_imc *imc;
584 for (imc = tncc->imc; imc; imc = imc->next) {
585 if (imc->imc_send == NULL)
588 os_memcpy(pos, imc->imc_send, imc->imc_send_len);
589 pos += imc->imc_send_len;
590 os_free(imc->imc_send);
591 imc->imc_send = NULL;
592 imc->imc_send_len = 0;
599 char * tncc_if_tnccs_start(struct tncc_data *tncc)
601 char *buf = os_malloc(1000);
604 tncc->last_batchid++;
605 os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
610 char * tncc_if_tnccs_end(void)
612 char *buf = os_malloc(100);
615 os_snprintf(buf, 100, IF_TNCCS_END);
620 static void tncc_notify_recommendation(struct tncc_data *tncc,
621 enum tncc_process_res res)
623 TNC_ConnectionState state;
624 struct tnc_if_imc *imc;
627 case TNCCS_RECOMMENDATION_ALLOW:
628 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
630 case TNCCS_RECOMMENDATION_NONE:
631 state = TNC_CONNECTION_STATE_ACCESS_NONE;
633 case TNCCS_RECOMMENDATION_ISOLATE:
634 state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
637 state = TNC_CONNECTION_STATE_ACCESS_NONE;
641 for (imc = tncc->imc; imc; imc = imc->next)
642 tncc_imc_notify_connection_change(imc, state);
646 static int tncc_get_type(char *start, unsigned int *type)
648 char *pos = os_strstr(start, "<Type>");
652 *type = strtoul(pos, NULL, 16);
657 static unsigned char * tncc_get_base64(char *start, size_t *decoded_len)
660 unsigned char *decoded;
662 pos = os_strstr(start, "<Base64>");
667 pos2 = os_strstr(pos, "</Base64>");
672 decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
675 if (decoded == NULL) {
676 wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
683 static enum tncc_process_res tncc_get_recommendation(char *start)
685 char *pos, *pos2, saved;
688 pos = os_strstr(start, "<TNCCS-Recommendation ");
690 return TNCCS_RECOMMENDATION_ERROR;
693 pos = os_strstr(pos, " type=");
695 return TNCCS_RECOMMENDATION_ERROR;
702 while (*pos2 != '\0' && *pos2 != '"' && *pos2 != '>')
706 return TNCCS_RECOMMENDATION_ERROR;
710 wpa_printf(MSG_DEBUG, "TNC: TNCCS-Recommendation: '%s'", pos);
712 recom = TNCCS_RECOMMENDATION_ERROR;
713 if (os_strcmp(pos, "allow") == 0)
714 recom = TNCCS_RECOMMENDATION_ALLOW;
715 else if (os_strcmp(pos, "none") == 0)
716 recom = TNCCS_RECOMMENDATION_NONE;
717 else if (os_strcmp(pos, "isolate") == 0)
718 recom = TNCCS_RECOMMENDATION_ISOLATE;
726 enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
727 const u8 *msg, size_t len)
729 char *buf, *start, *end, *pos, *pos2, *payload;
730 unsigned int batch_id;
731 unsigned char *decoded;
733 enum tncc_process_res res = TNCCS_PROCESS_OK_NO_RECOMMENDATION;
734 int recommendation_msg = 0;
736 buf = os_malloc(len + 1);
738 return TNCCS_PROCESS_ERROR;
740 os_memcpy(buf, msg, len);
742 start = os_strstr(buf, "<TNCCS-Batch ");
743 end = os_strstr(buf, "</TNCCS-Batch>");
744 if (start == NULL || end == NULL || start > end) {
746 return TNCCS_PROCESS_ERROR;
750 while (*start == ' ')
754 pos = os_strstr(start, "BatchId=");
757 return TNCCS_PROCESS_ERROR;
763 batch_id = atoi(pos);
764 wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
766 if (batch_id != tncc->last_batchid + 1) {
767 wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
769 batch_id, tncc->last_batchid + 1);
771 return TNCCS_PROCESS_ERROR;
773 tncc->last_batchid = batch_id;
775 while (*pos != '\0' && *pos != '>')
779 return TNCCS_PROCESS_ERROR;
786 * <Type>01234567</Type>
787 * <Base64>foo==</Base64>
795 pos = os_strstr(start, "<IMC-IMV-Message>");
799 end = os_strstr(start, "</IMC-IMV-Message>");
806 if (tncc_get_type(start, &type) < 0) {
811 wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
813 decoded = tncc_get_base64(start, &decoded_len);
814 if (decoded == NULL) {
820 tncc_send_to_imcs(tncc, type, decoded, decoded_len);
828 * <TNCC-TNCS-Message>
829 * <Type>01234567</Type>
830 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
831 * <Base64>foo==</Base64>
832 * </TNCC-TNCS-Message>
838 char *xml, *xmlend, *endpos;
840 pos = os_strstr(start, "<TNCC-TNCS-Message>");
844 end = os_strstr(start, "</TNCC-TNCS-Message>");
851 if (tncc_get_type(start, &type) < 0) {
856 wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
863 pos = os_strstr(start, "<XML>");
866 pos2 = os_strstr(pos, "</XML>");
875 decoded = tncc_get_base64(start, &decoded_len);
876 if (decoded == NULL) {
884 wpa_hexdump_ascii(MSG_MSGDUMP,
885 "TNC: TNCC-TNCS-Message Base64",
886 decoded, decoded_len);
891 wpa_hexdump_ascii(MSG_MSGDUMP,
892 "TNC: TNCC-TNCS-Message XML",
893 (unsigned char *) xml,
897 if (type == TNC_TNCCS_RECOMMENDATION && xml) {
899 * <TNCCS-Recommendation type="allow">
900 * </TNCCS-Recommendation>
903 res = tncc_get_recommendation(xml);
905 recommendation_msg = 1;
913 if (recommendation_msg)
914 tncc_notify_recommendation(tncc, res);
920 #ifdef CONFIG_NATIVE_WINDOWS
921 static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
926 struct tnc_if_imc *imc, *last;
930 while (last && last->next)
933 ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
935 if (ret != ERROR_SUCCESS)
939 TCHAR name[255], *val;
940 DWORD namelen, buflen;
943 ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
946 if (ret == ERROR_NO_MORE_ITEMS)
949 if (ret != ERROR_SUCCESS) {
950 wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
957 name[namelen] = '\0';
959 wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
961 ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
962 if (ret != ERROR_SUCCESS) {
963 wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
968 ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
970 if (ret != ERROR_SUCCESS) {
971 wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
972 "IMC key '" TSTR "'", name);
977 val = os_malloc(buflen);
983 ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
984 (LPBYTE) val, &buflen);
985 if (ret != ERROR_SUCCESS) {
993 wpa_unicode2ascii_inplace(val);
994 wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
996 for (j = 0; j < TNC_MAX_IMC_ID; j++) {
997 if (tnc_imc[j] == NULL)
1000 if (j >= TNC_MAX_IMC_ID) {
1001 wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
1006 imc = os_zalloc(sizeof(*imc));
1014 wpa_unicode2ascii_inplace(name);
1015 imc->name = os_strdup((char *) name);
1016 imc->path = os_strdup((char *) val);
1026 tnc_imc[imc->imcID] = imc;
1035 static int tncc_read_config(struct tncc_data *tncc)
1037 if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
1038 tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
1043 #else /* CONFIG_NATIVE_WINDOWS */
1045 static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
1047 struct tnc_if_imc *imc;
1051 for (i = 0; i < TNC_MAX_IMC_ID; i++) {
1052 if (tnc_imc[i] == NULL)
1055 if (i >= TNC_MAX_IMC_ID) {
1056 wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
1060 imc = os_zalloc(sizeof(*imc));
1069 wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
1070 if (pos + 1 >= end || *pos != '"') {
1071 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1072 "(no starting quotation mark)", start);
1079 while (pos2 < end && *pos2 != '"')
1082 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1083 "(no ending quotation mark)", start);
1088 wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
1089 imc->name = os_strdup(pos);
1092 if (pos >= end || *pos != ' ') {
1093 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
1094 "(no space after name)", start);
1100 wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
1101 imc->path = os_strdup(pos);
1102 tnc_imc[imc->imcID] = imc;
1108 static int tncc_read_config(struct tncc_data *tncc)
1110 char *config, *end, *pos, *line_end;
1112 struct tnc_if_imc *imc, *last;
1116 config = os_readfile(TNC_CONFIG_FILE, &config_len);
1117 if (config == NULL) {
1118 wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
1119 "file '%s'", TNC_CONFIG_FILE);
1123 end = config + config_len;
1124 for (pos = config; pos < end; pos = line_end + 1) {
1126 while (*line_end != '\n' && *line_end != '\r' &&
1131 if (os_strncmp(pos, "IMC ", 4) == 0) {
1134 imc = tncc_parse_imc(pos + 4, line_end, &error);
1152 #endif /* CONFIG_NATIVE_WINDOWS */
1155 struct tncc_data * tncc_init(void)
1157 struct tncc_data *tncc;
1158 struct tnc_if_imc *imc;
1160 tncc = os_zalloc(sizeof(*tncc));
1165 * move loading and Initialize() to a location that is not
1166 * re-initialized for every EAP-TNC session (?)
1169 if (tncc_read_config(tncc) < 0) {
1170 wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
1174 for (imc = tncc->imc; imc; imc = imc->next) {
1175 if (tncc_load_imc(imc)) {
1176 wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
1190 void tncc_deinit(struct tncc_data *tncc)
1192 struct tnc_if_imc *imc, *prev;
1196 tncc_unload_imc(imc);