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 */
23 #include "eap_common/eap_tlv_common.h"
24 #include "eap_common/eap_defs.h"
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>"
47 typedef unsigned long TNC_UInt32
;
48 typedef unsigned char *TNC_BufferReference
;
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
;
61 typedef TNC_Result (*TNC_TNCC_BindFunctionPointer
)(
64 void **pOutfunctionPointer
);
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
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
85 #define TNC_IFIMC_VERSION_1 1
87 #define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
88 #define TNC_SUBTYPE_ANY ((TNC_MessageSubtype) 0xff)
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
97 /* IF-TNCCS-SOH - SSoH and SSoHR Attributes */
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
110 struct tnc_if_imc
*next
;
113 void *dlhandle
; /* from dlopen() */
115 TNC_ConnectionID connectionID
;
116 TNC_MessageTypeList supported_types
;
117 size_t num_supported_types
;
121 /* Functions implemented by IMCs (with TNC_IMC_ prefix) */
122 TNC_Result (*Initialize
)(
124 TNC_Version minVersion
,
125 TNC_Version maxVersion
,
126 TNC_Version
*pOutActualVersion
);
127 TNC_Result (*NotifyConnectionChange
)(
129 TNC_ConnectionID connectionID
,
130 TNC_ConnectionState newState
);
131 TNC_Result (*BeginHandshake
)(
133 TNC_ConnectionID connectionID
);
134 TNC_Result (*ReceiveMessage
)(
136 TNC_ConnectionID connectionID
,
137 TNC_BufferReference messageBuffer
,
138 TNC_UInt32 messageLength
,
139 TNC_MessageType messageType
);
140 TNC_Result (*BatchEnding
)(
142 TNC_ConnectionID connectionID
);
143 TNC_Result (*Terminate
)(TNC_IMCID imcID
);
144 TNC_Result (*ProvideBindFunction
)(
146 TNC_TNCC_BindFunctionPointer bindFunction
);
150 struct tnc_if_imc
*imc
;
151 unsigned int last_batchid
;
154 #define TNC_MAX_IMC_ID 10
155 static struct tnc_if_imc
*tnc_imc
[TNC_MAX_IMC_ID
] = { NULL
};
158 /* TNCC functions that IMCs can call */
160 TNC_Result
TNC_TNCC_ReportMessageTypes(
162 TNC_MessageTypeList supportedTypes
,
163 TNC_UInt32 typeCount
)
166 struct tnc_if_imc
*imc
;
168 wpa_printf(MSG_DEBUG
, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
170 (unsigned long) imcID
, (unsigned long) typeCount
);
172 for (i
= 0; i
< typeCount
; i
++) {
173 wpa_printf(MSG_DEBUG
, "TNC: supportedTypes[%lu] = %lu",
174 i
, supportedTypes
[i
]);
177 if (imcID
>= TNC_MAX_IMC_ID
|| tnc_imc
[imcID
] == NULL
)
178 return TNC_RESULT_INVALID_PARAMETER
;
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
;
190 return TNC_RESULT_SUCCESS
;
194 TNC_Result
TNC_TNCC_SendMessage(
196 TNC_ConnectionID connectionID
,
197 TNC_BufferReference message
,
198 TNC_UInt32 messageLength
,
199 TNC_MessageType messageType
)
201 struct tnc_if_imc
*imc
;
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
);
211 if (imcID
>= TNC_MAX_IMC_ID
|| tnc_imc
[imcID
] == NULL
)
212 return TNC_RESULT_INVALID_PARAMETER
;
214 b64
= base64_encode(message
, messageLength
, &b64len
);
216 return TNC_RESULT_FATAL
;
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
) {
224 return TNC_RESULT_OTHER
;
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
);
235 return TNC_RESULT_SUCCESS
;
239 TNC_Result
TNC_TNCC_RequestHandshakeRetry(
241 TNC_ConnectionID connectionID
,
242 TNC_RetryReason reason
)
244 wpa_printf(MSG_DEBUG
, "TNC: TNC_TNCC_RequestHandshakeRetry");
246 if (imcID
>= TNC_MAX_IMC_ID
|| tnc_imc
[imcID
] == NULL
)
247 return TNC_RESULT_INVALID_PARAMETER
;
250 * TODO: trigger a call to eapol_sm_request_reauth(). This would
251 * require that the IMC continues to be loaded in memory afer
255 return TNC_RESULT_SUCCESS
;
259 TNC_Result
TNC_9048_LogMessage(TNC_IMCID imcID
, TNC_UInt32 severity
,
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
;
269 TNC_Result
TNC_9048_UserMessage(TNC_IMCID imcID
, TNC_ConnectionID connectionID
,
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
;
279 TNC_Result
TNC_TNCC_BindFunction(
282 void **pOutfunctionPointer
)
284 wpa_printf(MSG_DEBUG
, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
285 "functionName='%s')", (unsigned long) imcID
, functionName
);
287 if (imcID
>= TNC_MAX_IMC_ID
|| tnc_imc
[imcID
] == NULL
)
288 return TNC_RESULT_INVALID_PARAMETER
;
290 if (pOutfunctionPointer
== NULL
)
291 return TNC_RESULT_INVALID_PARAMETER
;
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") ==
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
;
305 *pOutfunctionPointer
= NULL
;
307 return TNC_RESULT_SUCCESS
;
311 static void * tncc_get_sym(void *handle
, char *func
)
315 #ifdef CONFIG_NATIVE_WINDOWS
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 */
329 static int tncc_imc_resolve_funcs(struct tnc_if_imc
*imc
)
331 void *handle
= imc
->dlhandle
;
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");
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");
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");
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");
367 static int tncc_imc_initialize(struct tnc_if_imc
*imc
)
372 wpa_printf(MSG_DEBUG
, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
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
);
379 return res
== TNC_RESULT_SUCCESS
? 0 : -1;
383 static int tncc_imc_terminate(struct tnc_if_imc
*imc
)
387 if (imc
->Terminate
== NULL
)
390 wpa_printf(MSG_DEBUG
, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
392 res
= imc
->Terminate(imc
->imcID
);
393 wpa_printf(MSG_DEBUG
, "TNC: TNC_IMC_Terminate: %lu",
394 (unsigned long) res
);
396 return res
== TNC_RESULT_SUCCESS
? 0 : -1;
400 static int tncc_imc_provide_bind_function(struct tnc_if_imc
*imc
)
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
);
410 return res
== TNC_RESULT_SUCCESS
? 0 : -1;
414 static int tncc_imc_notify_connection_change(struct tnc_if_imc
*imc
,
415 TNC_ConnectionState state
)
419 if (imc
->NotifyConnectionChange
== NULL
)
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
,
426 wpa_printf(MSG_DEBUG
, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
427 (unsigned long) res
);
429 return res
== TNC_RESULT_SUCCESS
? 0 : -1;
433 static int tncc_imc_begin_handshake(struct tnc_if_imc
*imc
)
437 wpa_printf(MSG_DEBUG
, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
439 res
= imc
->BeginHandshake(imc
->imcID
, imc
->connectionID
);
440 wpa_printf(MSG_DEBUG
, "TNC: TNC_IMC_BeginHandshake: %lu",
441 (unsigned long) res
);
443 return res
== TNC_RESULT_SUCCESS
? 0 : -1;
447 static int tncc_load_imc(struct tnc_if_imc
*imc
)
449 if (imc
->path
== NULL
) {
450 wpa_printf(MSG_DEBUG
, "TNC: No IMC configured");
454 wpa_printf(MSG_DEBUG
, "TNC: Opening IMC: %s (%s)",
455 imc
->name
, imc
->path
);
456 #ifdef CONFIG_NATIVE_WINDOWS
459 TCHAR
*lib
= wpa_strdup_tchar(imc
->path
);
462 imc
->dlhandle
= LoadLibrary(lib
);
466 imc
->dlhandle
= LoadLibrary(imc
->path
);
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());
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());
480 #endif /* CONFIG_NATIVE_WINDOWS */
482 if (tncc_imc_resolve_funcs(imc
) < 0) {
483 wpa_printf(MSG_ERROR
, "TNC: Failed to resolve IMC functions");
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");
497 static void tncc_unload_imc(struct tnc_if_imc
*imc
)
499 tncc_imc_terminate(imc
);
500 tnc_imc
[imc
->imcID
] = NULL
;
503 #ifdef CONFIG_NATIVE_WINDOWS
504 FreeLibrary(imc
->dlhandle
);
505 #else /* CONFIG_NATIVE_WINDOWS */
506 dlclose(imc
->dlhandle
);
507 #endif /* CONFIG_NATIVE_WINDOWS */
511 os_free(imc
->supported_types
);
512 os_free(imc
->imc_send
);
516 static int tncc_supported_type(struct tnc_if_imc
*imc
, unsigned int type
)
519 unsigned int vendor
, subtype
;
521 if (imc
== NULL
|| imc
->supported_types
== NULL
)
525 subtype
= type
& 0xff;
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
))
540 static void tncc_send_to_imcs(struct tncc_data
*tncc
, unsigned int type
,
541 const u8
*msg
, size_t len
)
543 struct tnc_if_imc
*imc
;
546 wpa_hexdump_ascii(MSG_MSGDUMP
, "TNC: Message to IMC(s)", msg
, len
);
548 for (imc
= tncc
->imc
; imc
; imc
= imc
->next
) {
549 if (imc
->ReceiveMessage
== NULL
||
550 !tncc_supported_type(imc
, type
))
553 wpa_printf(MSG_DEBUG
, "TNC: Call ReceiveMessage for IMC '%s'",
555 res
= imc
->ReceiveMessage(imc
->imcID
, imc
->connectionID
,
556 (TNC_BufferReference
) msg
, len
,
558 wpa_printf(MSG_DEBUG
, "TNC: ReceiveMessage: %lu",
559 (unsigned long) res
);
564 void tncc_init_connection(struct tncc_data
*tncc
)
566 struct tnc_if_imc
*imc
;
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
);
574 os_free(imc
->imc_send
);
575 imc
->imc_send
= NULL
;
576 imc
->imc_send_len
= 0;
578 tncc_imc_begin_handshake(imc
);
583 size_t tncc_total_send_len(struct tncc_data
*tncc
)
585 struct tnc_if_imc
*imc
;
588 for (imc
= tncc
->imc
; imc
; imc
= imc
->next
)
589 len
+= imc
->imc_send_len
;
594 u8
* tncc_copy_send_buf(struct tncc_data
*tncc
, u8
*pos
)
596 struct tnc_if_imc
*imc
;
598 for (imc
= tncc
->imc
; imc
; imc
= imc
->next
) {
599 if (imc
->imc_send
== NULL
)
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;
613 char * tncc_if_tnccs_start(struct tncc_data
*tncc
)
615 char *buf
= os_malloc(1000);
618 tncc
->last_batchid
++;
619 os_snprintf(buf
, 1000, IF_TNCCS_START
, tncc
->last_batchid
);
624 char * tncc_if_tnccs_end(void)
626 char *buf
= os_malloc(100);
629 os_snprintf(buf
, 100, IF_TNCCS_END
);
634 static void tncc_notify_recommendation(struct tncc_data
*tncc
,
635 enum tncc_process_res res
)
637 TNC_ConnectionState state
;
638 struct tnc_if_imc
*imc
;
641 case TNCCS_RECOMMENDATION_ALLOW
:
642 state
= TNC_CONNECTION_STATE_ACCESS_ALLOWED
;
644 case TNCCS_RECOMMENDATION_NONE
:
645 state
= TNC_CONNECTION_STATE_ACCESS_NONE
;
647 case TNCCS_RECOMMENDATION_ISOLATE
:
648 state
= TNC_CONNECTION_STATE_ACCESS_ISOLATED
;
651 state
= TNC_CONNECTION_STATE_ACCESS_NONE
;
655 for (imc
= tncc
->imc
; imc
; imc
= imc
->next
)
656 tncc_imc_notify_connection_change(imc
, state
);
660 static int tncc_get_type(char *start
, unsigned int *type
)
662 char *pos
= os_strstr(start
, "<Type>");
666 *type
= strtoul(pos
, NULL
, 16);
671 static unsigned char * tncc_get_base64(char *start
, size_t *decoded_len
)
674 unsigned char *decoded
;
676 pos
= os_strstr(start
, "<Base64>");
681 pos2
= os_strstr(pos
, "</Base64>");
686 decoded
= base64_decode((unsigned char *) pos
, os_strlen(pos
),
689 if (decoded
== NULL
) {
690 wpa_printf(MSG_DEBUG
, "TNC: Failed to decode Base64 data");
697 static enum tncc_process_res
tncc_get_recommendation(char *start
)
699 char *pos
, *pos2
, saved
;
702 pos
= os_strstr(start
, "<TNCCS-Recommendation ");
704 return TNCCS_RECOMMENDATION_ERROR
;
707 pos
= os_strstr(pos
, " type=");
709 return TNCCS_RECOMMENDATION_ERROR
;
716 while (*pos2
!= '\0' && *pos2
!= '"' && *pos2
!= '>')
720 return TNCCS_RECOMMENDATION_ERROR
;
724 wpa_printf(MSG_DEBUG
, "TNC: TNCCS-Recommendation: '%s'", pos
);
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
;
740 enum tncc_process_res
tncc_process_if_tnccs(struct tncc_data
*tncc
,
741 const u8
*msg
, size_t len
)
743 char *buf
, *start
, *end
, *pos
, *pos2
, *payload
;
744 unsigned int batch_id
;
745 unsigned char *decoded
;
747 enum tncc_process_res res
= TNCCS_PROCESS_OK_NO_RECOMMENDATION
;
748 int recommendation_msg
= 0;
750 buf
= os_malloc(len
+ 1);
752 return TNCCS_PROCESS_ERROR
;
754 os_memcpy(buf
, msg
, len
);
756 start
= os_strstr(buf
, "<TNCCS-Batch ");
757 end
= os_strstr(buf
, "</TNCCS-Batch>");
758 if (start
== NULL
|| end
== NULL
|| start
> end
) {
760 return TNCCS_PROCESS_ERROR
;
764 while (*start
== ' ')
768 pos
= os_strstr(start
, "BatchId=");
771 return TNCCS_PROCESS_ERROR
;
777 batch_id
= atoi(pos
);
778 wpa_printf(MSG_DEBUG
, "TNC: Received IF-TNCCS BatchId=%u",
780 if (batch_id
!= tncc
->last_batchid
+ 1) {
781 wpa_printf(MSG_DEBUG
, "TNC: Unexpected IF-TNCCS BatchId "
783 batch_id
, tncc
->last_batchid
+ 1);
785 return TNCCS_PROCESS_ERROR
;
787 tncc
->last_batchid
= batch_id
;
789 while (*pos
!= '\0' && *pos
!= '>')
793 return TNCCS_PROCESS_ERROR
;
800 * <Type>01234567</Type>
801 * <Base64>foo==</Base64>
809 pos
= os_strstr(start
, "<IMC-IMV-Message>");
813 end
= os_strstr(start
, "</IMC-IMV-Message>");
820 if (tncc_get_type(start
, &type
) < 0) {
825 wpa_printf(MSG_DEBUG
, "TNC: IMC-IMV-Message Type 0x%x", type
);
827 decoded
= tncc_get_base64(start
, &decoded_len
);
828 if (decoded
== NULL
) {
834 tncc_send_to_imcs(tncc
, type
, decoded
, decoded_len
);
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>
852 char *xml
, *xmlend
, *endpos
;
854 pos
= os_strstr(start
, "<TNCC-TNCS-Message>");
858 end
= os_strstr(start
, "</TNCC-TNCS-Message>");
865 if (tncc_get_type(start
, &type
) < 0) {
870 wpa_printf(MSG_DEBUG
, "TNC: TNCC-TNCS-Message Type 0x%x",
877 pos
= os_strstr(start
, "<XML>");
880 pos2
= os_strstr(pos
, "</XML>");
889 decoded
= tncc_get_base64(start
, &decoded_len
);
890 if (decoded
== NULL
) {
898 wpa_hexdump_ascii(MSG_MSGDUMP
,
899 "TNC: TNCC-TNCS-Message Base64",
900 decoded
, decoded_len
);
905 wpa_hexdump_ascii(MSG_MSGDUMP
,
906 "TNC: TNCC-TNCS-Message XML",
907 (unsigned char *) xml
,
911 if (type
== TNC_TNCCS_RECOMMENDATION
&& xml
) {
913 * <TNCCS-Recommendation type="allow">
914 * </TNCCS-Recommendation>
917 res
= tncc_get_recommendation(xml
);
919 recommendation_msg
= 1;
927 if (recommendation_msg
)
928 tncc_notify_recommendation(tncc
, res
);
934 #ifdef CONFIG_NATIVE_WINDOWS
935 static int tncc_read_config_reg(struct tncc_data
*tncc
, HKEY hive
)
940 struct tnc_if_imc
*imc
, *last
;
944 while (last
&& last
->next
)
947 ret
= RegOpenKeyEx(hive
, TNC_WINREG_PATH
, 0, KEY_ENUMERATE_SUB_KEYS
,
949 if (ret
!= ERROR_SUCCESS
)
953 TCHAR name
[255], *val
;
954 DWORD namelen
, buflen
;
957 ret
= RegEnumKeyEx(hk
, i
, name
, &namelen
, NULL
, NULL
, NULL
,
960 if (ret
== ERROR_NO_MORE_ITEMS
)
963 if (ret
!= ERROR_SUCCESS
) {
964 wpa_printf(MSG_DEBUG
, "TNC: RegEnumKeyEx failed: 0x%x",
971 name
[namelen
] = '\0';
973 wpa_printf(MSG_DEBUG
, "TNC: IMC '" TSTR
"'", name
);
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
982 ret
= RegQueryValueEx(hk2
, TEXT("Path"), NULL
, NULL
, NULL
,
984 if (ret
!= ERROR_SUCCESS
) {
985 wpa_printf(MSG_DEBUG
, "TNC: Could not read Path from "
986 "IMC key '" TSTR
"'", name
);
991 val
= os_malloc(buflen
);
997 ret
= RegQueryValueEx(hk2
, TEXT("Path"), NULL
, NULL
,
998 (LPBYTE
) val
, &buflen
);
999 if (ret
!= ERROR_SUCCESS
) {
1007 wpa_unicode2ascii_inplace(val
);
1008 wpa_printf(MSG_DEBUG
, "TNC: IMC Path '%s'", (char *) val
);
1010 for (j
= 0; j
< TNC_MAX_IMC_ID
; j
++) {
1011 if (tnc_imc
[j
] == NULL
)
1014 if (j
>= TNC_MAX_IMC_ID
) {
1015 wpa_printf(MSG_DEBUG
, "TNC: Too many IMCs");
1020 imc
= os_zalloc(sizeof(*imc
));
1028 wpa_unicode2ascii_inplace(name
);
1029 imc
->name
= os_strdup((char *) name
);
1030 imc
->path
= os_strdup((char *) val
);
1040 tnc_imc
[imc
->imcID
] = imc
;
1049 static int tncc_read_config(struct tncc_data
*tncc
)
1051 if (tncc_read_config_reg(tncc
, HKEY_LOCAL_MACHINE
) < 0 ||
1052 tncc_read_config_reg(tncc
, HKEY_CURRENT_USER
) < 0)
1057 #else /* CONFIG_NATIVE_WINDOWS */
1059 static struct tnc_if_imc
* tncc_parse_imc(char *start
, char *end
, int *error
)
1061 struct tnc_if_imc
*imc
;
1065 for (i
= 0; i
< TNC_MAX_IMC_ID
; i
++) {
1066 if (tnc_imc
[i
] == NULL
)
1069 if (i
>= TNC_MAX_IMC_ID
) {
1070 wpa_printf(MSG_DEBUG
, "TNC: Too many IMCs");
1074 imc
= os_zalloc(sizeof(*imc
));
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
);
1093 while (pos2
< end
&& *pos2
!= '"')
1096 wpa_printf(MSG_ERROR
, "TNC: Ignoring invalid IMC line '%s' "
1097 "(no ending quotation mark)", start
);
1102 wpa_printf(MSG_DEBUG
, "TNC: Name: '%s'", pos
);
1103 imc
->name
= os_strdup(pos
);
1106 if (pos
>= end
|| *pos
!= ' ') {
1107 wpa_printf(MSG_ERROR
, "TNC: Ignoring invalid IMC line '%s' "
1108 "(no space after name)", start
);
1115 wpa_printf(MSG_DEBUG
, "TNC: IMC file: '%s'", pos
);
1116 imc
->path
= os_strdup(pos
);
1117 tnc_imc
[imc
->imcID
] = imc
;
1123 static int tncc_read_config(struct tncc_data
*tncc
)
1125 char *config
, *end
, *pos
, *line_end
;
1127 struct tnc_if_imc
*imc
, *last
;
1131 config
= os_readfile(TNC_CONFIG_FILE
, &config_len
);
1132 if (config
== NULL
) {
1133 wpa_printf(MSG_ERROR
, "TNC: Could not open TNC configuration "
1134 "file '%s'", TNC_CONFIG_FILE
);
1138 end
= config
+ config_len
;
1139 for (pos
= config
; pos
< end
; pos
= line_end
+ 1) {
1141 while (*line_end
!= '\n' && *line_end
!= '\r' &&
1146 if (os_strncmp(pos
, "IMC ", 4) == 0) {
1149 imc
= tncc_parse_imc(pos
+ 4, line_end
, &error
);
1167 #endif /* CONFIG_NATIVE_WINDOWS */
1170 struct tncc_data
* tncc_init(void)
1172 struct tncc_data
*tncc
;
1173 struct tnc_if_imc
*imc
;
1175 tncc
= os_zalloc(sizeof(*tncc
));
1180 * move loading and Initialize() to a location that is not
1181 * re-initialized for every EAP-TNC session (?)
1184 if (tncc_read_config(tncc
) < 0) {
1185 wpa_printf(MSG_ERROR
, "TNC: Failed to read TNC configuration");
1189 for (imc
= tncc
->imc
; imc
; imc
= imc
->next
) {
1190 if (tncc_load_imc(imc
)) {
1191 wpa_printf(MSG_ERROR
, "TNC: Failed to load IMC '%s'",
1205 void tncc_deinit(struct tncc_data
*tncc
)
1207 struct tnc_if_imc
*imc
, *prev
;
1211 tncc_unload_imc(imc
);
1222 static struct wpabuf
* tncc_build_soh(int ver
)
1225 u8
*tlv_len
, *tlv_len2
, *outer_len
, *inner_len
, *ssoh_len
, *end
;
1226 u8 correlation_id
[24];
1227 /* TODO: get correct name */
1228 char *machinename
= "wpa_supplicant@w1.fi";
1230 if (os_get_random(correlation_id
, sizeof(correlation_id
)))
1232 wpa_hexdump(MSG_DEBUG
, "TNC: SoH Correlation ID",
1233 correlation_id
, sizeof(correlation_id
));
1235 buf
= wpabuf_alloc(200);
1239 /* Vendor-Specific TLV (Microsoft) - SoH */
1240 wpabuf_put_be16(buf
, EAP_TLV_VENDOR_SPECIFIC_TLV
); /* TLV Type */
1241 tlv_len
= wpabuf_put(buf
, 2); /* Length */
1242 wpabuf_put_be32(buf
, EAP_VENDOR_MICROSOFT
); /* Vendor_Id */
1243 wpabuf_put_be16(buf
, 0x01); /* TLV Type - SoH TLV */
1244 tlv_len2
= wpabuf_put(buf
, 2); /* Length */
1247 wpabuf_put_be16(buf
, EAP_TLV_VENDOR_SPECIFIC_TLV
); /* Outer Type */
1248 outer_len
= wpabuf_put(buf
, 2);
1249 wpabuf_put_be32(buf
, EAP_VENDOR_MICROSOFT
); /* IANA SMI Code */
1250 wpabuf_put_be16(buf
, ver
); /* Inner Type */
1251 inner_len
= wpabuf_put(buf
, 2);
1254 /* SoH Mode Sub-Header */
1256 wpabuf_put_be16(buf
, EAP_TLV_VENDOR_SPECIFIC_TLV
);
1257 wpabuf_put_be16(buf
, 4 + 24 + 1 + 1); /* Length */
1258 wpabuf_put_be32(buf
, EAP_VENDOR_MICROSOFT
); /* IANA SMI Code */
1260 wpabuf_put_data(buf
, correlation_id
, sizeof(correlation_id
));
1261 wpabuf_put_u8(buf
, 0x01); /* Intent Flag - Request */
1262 wpabuf_put_u8(buf
, 0x00); /* Content-Type Flag */
1266 /* System-Health-Id */
1267 wpabuf_put_be16(buf
, 0x0002); /* Type */
1268 wpabuf_put_be16(buf
, 4); /* Length */
1269 wpabuf_put_be32(buf
, 79616);
1270 /* Vendor-Specific Attribute */
1271 wpabuf_put_be16(buf
, EAP_TLV_VENDOR_SPECIFIC_TLV
);
1272 ssoh_len
= wpabuf_put(buf
, 2);
1273 wpabuf_put_be32(buf
, EAP_VENDOR_MICROSOFT
); /* IANA SMI Code */
1275 /* MS-Packet-Info */
1276 wpabuf_put_u8(buf
, SSOH_MS_PACKET_INFO
);
1277 /* Note: IF-TNCCS-SOH v1.0 r8 claims this field to be:
1278 * Reserved(4 bits) r(1 bit) Vers(3 bits), but Windows XP
1279 * SP3 seems to be sending 0x11 for SSoH, i.e., r(request/response) bit
1280 * would not be in the specified location.
1281 * [MS-SOH] 4.0.2: Reserved(3 bits) r(1 bit) Vers(4 bits)
1283 wpabuf_put_u8(buf
, 0x11); /* r=request, vers=1 */
1285 /* MS-Machine-Inventory */
1286 /* TODO: get correct values; 0 = not applicable for OS */
1287 wpabuf_put_u8(buf
, SSOH_MS_MACHINE_INVENTORY
);
1288 wpabuf_put_be32(buf
, 0); /* osVersionMajor */
1289 wpabuf_put_be32(buf
, 0); /* osVersionMinor */
1290 wpabuf_put_be32(buf
, 0); /* osVersionBuild */
1291 wpabuf_put_be16(buf
, 0); /* spVersionMajor */
1292 wpabuf_put_be16(buf
, 0); /* spVersionMinor */
1293 wpabuf_put_be16(buf
, 0); /* procArch */
1295 /* MS-MachineName */
1296 wpabuf_put_u8(buf
, SSOH_MS_MACHINENAME
);
1297 wpabuf_put_be16(buf
, os_strlen(machinename
) + 1);
1298 wpabuf_put_data(buf
, machinename
, os_strlen(machinename
) + 1);
1300 /* MS-CorrelationId */
1301 wpabuf_put_u8(buf
, SSOH_MS_CORRELATIONID
);
1302 wpabuf_put_data(buf
, correlation_id
, sizeof(correlation_id
));
1304 /* MS-Quarantine-State */
1305 wpabuf_put_u8(buf
, SSOH_MS_QUARANTINE_STATE
);
1306 wpabuf_put_be16(buf
, 1); /* Flags: ExtState=0, f=0, qState=1 */
1307 wpabuf_put_be32(buf
, 0xffffffff); /* ProbTime (hi) */
1308 wpabuf_put_be32(buf
, 0xffffffff); /* ProbTime (lo) */
1309 wpabuf_put_be16(buf
, 1); /* urlLenInBytes */
1310 wpabuf_put_u8(buf
, 0); /* null termination for the url */
1312 /* MS-Machine-Inventory-Ex */
1313 wpabuf_put_u8(buf
, SSOH_MS_MACHINE_INVENTORY_EX
);
1314 wpabuf_put_be32(buf
, 0); /* Reserved
1315 * (note: Windows XP SP3 uses 0xdecafbad) */
1316 wpabuf_put_u8(buf
, 1); /* ProductType: Client */
1318 /* Update SSoH Length */
1319 end
= wpabuf_put(buf
, 0);
1320 WPA_PUT_BE16(ssoh_len
, end
- ssoh_len
- 2);
1322 /* TODO: SoHReportEntry TLV (zero or more) */
1324 /* Update length fields */
1325 end
= wpabuf_put(buf
, 0);
1326 WPA_PUT_BE16(tlv_len
, end
- tlv_len
- 2);
1327 WPA_PUT_BE16(tlv_len2
, end
- tlv_len2
- 2);
1328 WPA_PUT_BE16(outer_len
, end
- outer_len
- 2);
1329 WPA_PUT_BE16(inner_len
, end
- inner_len
- 2);
1335 struct wpabuf
* tncc_process_soh_request(int ver
, const u8
*data
, size_t len
)
1339 wpa_hexdump(MSG_DEBUG
, "TNC: SoH Request", data
, len
);
1348 if (WPA_GET_BE16(pos
) != EAP_TLV_VENDOR_SPECIFIC_TLV
)
1353 if (WPA_GET_BE16(pos
) < 8)
1358 if (WPA_GET_BE32(pos
) != EAP_VENDOR_MICROSOFT
)
1363 if (WPA_GET_BE16(pos
) != 0x02 /* SoH request TLV */)
1366 wpa_printf(MSG_DEBUG
, "TNC: SoH Request TLV received");
1368 return tncc_build_soh(2);