2 * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
3 * Copyright (c) 2007-2008, 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.
21 #include "eap_common/eap_tlv_common.h"
22 #include "eap_common/eap_defs.h"
25 /* TODO: TNCS must be thread-safe; review the code and add locking etc. if
28 #define TNC_CONFIG_FILE "/etc/tnc_config"
29 #define IF_TNCCS_START \
30 "<?xml version=\"1.0\"?>\n" \
31 "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
32 "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
33 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
34 "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
35 "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
36 #define IF_TNCCS_END "\n</TNCCS-Batch>"
40 typedef unsigned long TNC_UInt32
;
41 typedef unsigned char *TNC_BufferReference
;
43 typedef TNC_UInt32 TNC_IMVID
;
44 typedef TNC_UInt32 TNC_ConnectionID
;
45 typedef TNC_UInt32 TNC_ConnectionState
;
46 typedef TNC_UInt32 TNC_RetryReason
;
47 typedef TNC_UInt32 TNC_IMV_Action_Recommendation
;
48 typedef TNC_UInt32 TNC_IMV_Evaluation_Result
;
49 typedef TNC_UInt32 TNC_MessageType
;
50 typedef TNC_MessageType
*TNC_MessageTypeList
;
51 typedef TNC_UInt32 TNC_VendorID
;
52 typedef TNC_UInt32 TNC_Subtype
;
53 typedef TNC_UInt32 TNC_Version
;
54 typedef TNC_UInt32 TNC_Result
;
55 typedef TNC_UInt32 TNC_AttributeID
;
57 typedef TNC_Result (*TNC_TNCS_BindFunctionPointer
)(
60 void **pOutfunctionPointer
);
62 #define TNC_RESULT_SUCCESS 0
63 #define TNC_RESULT_NOT_INITIALIZED 1
64 #define TNC_RESULT_ALREADY_INITIALIZED 2
65 #define TNC_RESULT_NO_COMMON_VERSION 3
66 #define TNC_RESULT_CANT_RETRY 4
67 #define TNC_RESULT_WONT_RETRY 5
68 #define TNC_RESULT_INVALID_PARAMETER 6
69 #define TNC_RESULT_CANT_RESPOND 7
70 #define TNC_RESULT_ILLEGAL_OPERATION 8
71 #define TNC_RESULT_OTHER 9
72 #define TNC_RESULT_FATAL 10
74 #define TNC_CONNECTION_STATE_CREATE 0
75 #define TNC_CONNECTION_STATE_HANDSHAKE 1
76 #define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
77 #define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
78 #define TNC_CONNECTION_STATE_ACCESS_NONE 4
79 #define TNC_CONNECTION_STATE_DELETE 5
81 #define TNC_IFIMV_VERSION_1 1
83 #define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
84 #define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff)
86 /* TNCC-TNCS Message Types */
87 #define TNC_TNCCS_RECOMMENDATION 0x00000001
88 #define TNC_TNCCS_ERROR 0x00000002
89 #define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003
90 #define TNC_TNCCS_REASONSTRINGS 0x00000004
92 /* Possible TNC_IMV_Action_Recommendation values: */
93 enum IMV_Action_Recommendation
{
94 TNC_IMV_ACTION_RECOMMENDATION_ALLOW
,
95 TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
,
96 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
,
97 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
100 /* Possible TNC_IMV_Evaluation_Result values: */
101 enum IMV_Evaluation_Result
{
102 TNC_IMV_EVALUATION_RESULT_COMPLIANT
,
103 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR
,
104 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR
,
105 TNC_IMV_EVALUATION_RESULT_ERROR
,
106 TNC_IMV_EVALUATION_RESULT_DONT_KNOW
110 struct tnc_if_imv
*next
;
113 void *dlhandle
; /* from dlopen() */
115 TNC_MessageTypeList supported_types
;
116 size_t num_supported_types
;
118 /* Functions implemented by IMVs (with TNC_IMV_ prefix) */
119 TNC_Result (*Initialize
)(
121 TNC_Version minVersion
,
122 TNC_Version maxVersion
,
123 TNC_Version
*pOutActualVersion
);
124 TNC_Result (*NotifyConnectionChange
)(
126 TNC_ConnectionID connectionID
,
127 TNC_ConnectionState newState
);
128 TNC_Result (*ReceiveMessage
)(
130 TNC_ConnectionID connectionID
,
131 TNC_BufferReference message
,
132 TNC_UInt32 messageLength
,
133 TNC_MessageType messageType
);
134 TNC_Result (*SolicitRecommendation
)(
136 TNC_ConnectionID connectionID
);
137 TNC_Result (*BatchEnding
)(
139 TNC_ConnectionID connectionID
);
140 TNC_Result (*Terminate
)(TNC_IMVID imvID
);
141 TNC_Result (*ProvideBindFunction
)(
143 TNC_TNCS_BindFunctionPointer bindFunction
);
147 #define TNC_MAX_IMV_ID 10
150 struct tncs_data
*next
;
151 struct tnc_if_imv
*imv
; /* local copy of tncs_global_data->imv */
152 TNC_ConnectionID connectionID
;
153 unsigned int last_batchid
;
154 enum IMV_Action_Recommendation recommendation
;
160 enum IMV_Action_Recommendation recommendation
;
161 int recommendation_set
;
162 } imv_data
[TNC_MAX_IMV_ID
];
169 struct tnc_if_imv
*imv
;
170 TNC_ConnectionID next_conn_id
;
171 struct tncs_data
*connections
;
174 static struct tncs_global
*tncs_global_data
= NULL
;
177 static struct tnc_if_imv
* tncs_get_imv(TNC_IMVID imvID
)
179 struct tnc_if_imv
*imv
;
181 if (imvID
>= TNC_MAX_IMV_ID
|| tncs_global_data
== NULL
)
183 imv
= tncs_global_data
->imv
;
185 if (imv
->imvID
== imvID
)
193 static struct tncs_data
* tncs_get_conn(TNC_ConnectionID connectionID
)
195 struct tncs_data
*tncs
;
197 if (tncs_global_data
== NULL
)
200 tncs
= tncs_global_data
->connections
;
202 if (tncs
->connectionID
== connectionID
)
207 wpa_printf(MSG_DEBUG
, "TNC: Connection ID %lu not found",
208 (unsigned long) connectionID
);
214 /* TNCS functions that IMVs can call */
215 TNC_Result
TNC_TNCS_ReportMessageTypes(
217 TNC_MessageTypeList supportedTypes
,
218 TNC_UInt32 typeCount
)
221 struct tnc_if_imv
*imv
;
223 wpa_printf(MSG_DEBUG
, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
225 (unsigned long) imvID
, (unsigned long) typeCount
);
227 for (i
= 0; i
< typeCount
; i
++) {
228 wpa_printf(MSG_DEBUG
, "TNC: supportedTypes[%lu] = %lu",
229 i
, supportedTypes
[i
]);
232 imv
= tncs_get_imv(imvID
);
234 return TNC_RESULT_INVALID_PARAMETER
;
235 os_free(imv
->supported_types
);
236 imv
->supported_types
=
237 os_malloc(typeCount
* sizeof(TNC_MessageTypeList
));
238 if (imv
->supported_types
== NULL
)
239 return TNC_RESULT_FATAL
;
240 os_memcpy(imv
->supported_types
, supportedTypes
,
241 typeCount
* sizeof(TNC_MessageTypeList
));
242 imv
->num_supported_types
= typeCount
;
244 return TNC_RESULT_SUCCESS
;
248 TNC_Result
TNC_TNCS_SendMessage(
250 TNC_ConnectionID connectionID
,
251 TNC_BufferReference message
,
252 TNC_UInt32 messageLength
,
253 TNC_MessageType messageType
)
255 struct tncs_data
*tncs
;
259 wpa_printf(MSG_DEBUG
, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
260 "connectionID=%lu messageType=%lu)",
261 imvID
, connectionID
, messageType
);
262 wpa_hexdump_ascii(MSG_DEBUG
, "TNC: TNC_TNCS_SendMessage",
263 message
, messageLength
);
265 if (tncs_get_imv(imvID
) == NULL
)
266 return TNC_RESULT_INVALID_PARAMETER
;
268 tncs
= tncs_get_conn(connectionID
);
270 return TNC_RESULT_INVALID_PARAMETER
;
272 b64
= base64_encode(message
, messageLength
, &b64len
);
274 return TNC_RESULT_FATAL
;
276 os_free(tncs
->imv_data
[imvID
].imv_send
);
277 tncs
->imv_data
[imvID
].imv_send_len
= 0;
278 tncs
->imv_data
[imvID
].imv_send
= os_zalloc(b64len
+ 100);
279 if (tncs
->imv_data
[imvID
].imv_send
== NULL
) {
281 return TNC_RESULT_OTHER
;
284 tncs
->imv_data
[imvID
].imv_send_len
=
285 os_snprintf((char *) tncs
->imv_data
[imvID
].imv_send
,
287 "<IMC-IMV-Message><Type>%08X</Type>"
288 "<Base64>%s</Base64></IMC-IMV-Message>",
289 (unsigned int) messageType
, b64
);
293 return TNC_RESULT_SUCCESS
;
297 TNC_Result
TNC_TNCS_RequestHandshakeRetry(
299 TNC_ConnectionID connectionID
,
300 TNC_RetryReason reason
)
302 wpa_printf(MSG_DEBUG
, "TNC: TNC_TNCS_RequestHandshakeRetry");
304 return TNC_RESULT_SUCCESS
;
308 TNC_Result
TNC_TNCS_ProvideRecommendation(
310 TNC_ConnectionID connectionID
,
311 TNC_IMV_Action_Recommendation recommendation
,
312 TNC_IMV_Evaluation_Result evaluation
)
314 struct tncs_data
*tncs
;
316 wpa_printf(MSG_DEBUG
, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
317 "connectionID=%lu recommendation=%lu evaluation=%lu)",
318 (unsigned long) imvID
, (unsigned long) connectionID
,
319 (unsigned long) recommendation
, (unsigned long) evaluation
);
321 if (tncs_get_imv(imvID
) == NULL
)
322 return TNC_RESULT_INVALID_PARAMETER
;
324 tncs
= tncs_get_conn(connectionID
);
326 return TNC_RESULT_INVALID_PARAMETER
;
328 tncs
->imv_data
[imvID
].recommendation
= recommendation
;
329 tncs
->imv_data
[imvID
].recommendation_set
= 1;
331 return TNC_RESULT_SUCCESS
;
335 TNC_Result
TNC_TNCS_GetAttribute(
337 TNC_ConnectionID connectionID
,
338 TNC_AttributeID attribureID
,
339 TNC_UInt32 bufferLength
,
340 TNC_BufferReference buffer
,
341 TNC_UInt32
*pOutValueLength
)
343 wpa_printf(MSG_DEBUG
, "TNC: TNC_TNCS_GetAttribute");
345 return TNC_RESULT_SUCCESS
;
349 TNC_Result
TNC_TNCS_SetAttribute(
351 TNC_ConnectionID connectionID
,
352 TNC_AttributeID attribureID
,
353 TNC_UInt32 bufferLength
,
354 TNC_BufferReference buffer
)
356 wpa_printf(MSG_DEBUG
, "TNC: TNC_TNCS_SetAttribute");
358 return TNC_RESULT_SUCCESS
;
362 TNC_Result
TNC_TNCS_BindFunction(
365 void **pOutFunctionPointer
)
367 wpa_printf(MSG_DEBUG
, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
368 "functionName='%s')", (unsigned long) imvID
, functionName
);
370 if (tncs_get_imv(imvID
) == NULL
)
371 return TNC_RESULT_INVALID_PARAMETER
;
373 if (pOutFunctionPointer
== NULL
)
374 return TNC_RESULT_INVALID_PARAMETER
;
376 if (os_strcmp(functionName
, "TNC_TNCS_ReportMessageTypes") == 0)
377 *pOutFunctionPointer
= TNC_TNCS_ReportMessageTypes
;
378 else if (os_strcmp(functionName
, "TNC_TNCS_SendMessage") == 0)
379 *pOutFunctionPointer
= TNC_TNCS_SendMessage
;
380 else if (os_strcmp(functionName
, "TNC_TNCS_RequestHandshakeRetry") ==
382 *pOutFunctionPointer
= TNC_TNCS_RequestHandshakeRetry
;
383 else if (os_strcmp(functionName
, "TNC_TNCS_ProvideRecommendation") ==
385 *pOutFunctionPointer
= TNC_TNCS_ProvideRecommendation
;
386 else if (os_strcmp(functionName
, "TNC_TNCS_GetAttribute") == 0)
387 *pOutFunctionPointer
= TNC_TNCS_GetAttribute
;
388 else if (os_strcmp(functionName
, "TNC_TNCS_SetAttribute") == 0)
389 *pOutFunctionPointer
= TNC_TNCS_SetAttribute
;
391 *pOutFunctionPointer
= NULL
;
393 return TNC_RESULT_SUCCESS
;
397 static void * tncs_get_sym(void *handle
, char *func
)
401 fptr
= dlsym(handle
, func
);
407 static int tncs_imv_resolve_funcs(struct tnc_if_imv
*imv
)
409 void *handle
= imv
->dlhandle
;
411 /* Mandatory IMV functions */
412 imv
->Initialize
= tncs_get_sym(handle
, "TNC_IMV_Initialize");
413 if (imv
->Initialize
== NULL
) {
414 wpa_printf(MSG_ERROR
, "TNC: IMV does not export "
415 "TNC_IMV_Initialize");
419 imv
->SolicitRecommendation
= tncs_get_sym(
420 handle
, "TNC_IMV_SolicitRecommendation");
421 if (imv
->SolicitRecommendation
== NULL
) {
422 wpa_printf(MSG_ERROR
, "TNC: IMV does not export "
423 "TNC_IMV_SolicitRecommendation");
427 imv
->ProvideBindFunction
=
428 tncs_get_sym(handle
, "TNC_IMV_ProvideBindFunction");
429 if (imv
->ProvideBindFunction
== NULL
) {
430 wpa_printf(MSG_ERROR
, "TNC: IMV does not export "
431 "TNC_IMV_ProvideBindFunction");
435 /* Optional IMV functions */
436 imv
->NotifyConnectionChange
=
437 tncs_get_sym(handle
, "TNC_IMV_NotifyConnectionChange");
438 imv
->ReceiveMessage
= tncs_get_sym(handle
, "TNC_IMV_ReceiveMessage");
439 imv
->BatchEnding
= tncs_get_sym(handle
, "TNC_IMV_BatchEnding");
440 imv
->Terminate
= tncs_get_sym(handle
, "TNC_IMV_Terminate");
446 static int tncs_imv_initialize(struct tnc_if_imv
*imv
)
451 wpa_printf(MSG_DEBUG
, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
453 res
= imv
->Initialize(imv
->imvID
, TNC_IFIMV_VERSION_1
,
454 TNC_IFIMV_VERSION_1
, &imv_ver
);
455 wpa_printf(MSG_DEBUG
, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
456 (unsigned long) res
, (unsigned long) imv_ver
);
458 return res
== TNC_RESULT_SUCCESS
? 0 : -1;
462 static int tncs_imv_terminate(struct tnc_if_imv
*imv
)
466 if (imv
->Terminate
== NULL
)
469 wpa_printf(MSG_DEBUG
, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
471 res
= imv
->Terminate(imv
->imvID
);
472 wpa_printf(MSG_DEBUG
, "TNC: TNC_IMV_Terminate: %lu",
473 (unsigned long) res
);
475 return res
== TNC_RESULT_SUCCESS
? 0 : -1;
479 static int tncs_imv_provide_bind_function(struct tnc_if_imv
*imv
)
483 wpa_printf(MSG_DEBUG
, "TNC: Calling TNC_IMV_ProvideBindFunction for "
484 "IMV '%s'", imv
->name
);
485 res
= imv
->ProvideBindFunction(imv
->imvID
, TNC_TNCS_BindFunction
);
486 wpa_printf(MSG_DEBUG
, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
487 (unsigned long) res
);
489 return res
== TNC_RESULT_SUCCESS
? 0 : -1;
493 static int tncs_imv_notify_connection_change(struct tnc_if_imv
*imv
,
494 TNC_ConnectionID conn
,
495 TNC_ConnectionState state
)
499 if (imv
->NotifyConnectionChange
== NULL
)
502 wpa_printf(MSG_DEBUG
, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
503 " for IMV '%s'", (int) state
, imv
->name
);
504 res
= imv
->NotifyConnectionChange(imv
->imvID
, conn
, state
);
505 wpa_printf(MSG_DEBUG
, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
506 (unsigned long) res
);
508 return res
== TNC_RESULT_SUCCESS
? 0 : -1;
512 static int tncs_load_imv(struct tnc_if_imv
*imv
)
514 if (imv
->path
== NULL
) {
515 wpa_printf(MSG_DEBUG
, "TNC: No IMV configured");
519 wpa_printf(MSG_DEBUG
, "TNC: Opening IMV: %s (%s)",
520 imv
->name
, imv
->path
);
521 imv
->dlhandle
= dlopen(imv
->path
, RTLD_LAZY
);
522 if (imv
->dlhandle
== NULL
) {
523 wpa_printf(MSG_ERROR
, "TNC: Failed to open IMV '%s' (%s): %s",
524 imv
->name
, imv
->path
, dlerror());
528 if (tncs_imv_resolve_funcs(imv
) < 0) {
529 wpa_printf(MSG_ERROR
, "TNC: Failed to resolve IMV functions");
533 if (tncs_imv_initialize(imv
) < 0 ||
534 tncs_imv_provide_bind_function(imv
) < 0) {
535 wpa_printf(MSG_ERROR
, "TNC: Failed to initialize IMV");
543 static void tncs_free_imv(struct tnc_if_imv
*imv
)
547 os_free(imv
->supported_types
);
550 static void tncs_unload_imv(struct tnc_if_imv
*imv
)
552 tncs_imv_terminate(imv
);
555 dlclose(imv
->dlhandle
);
561 static int tncs_supported_type(struct tnc_if_imv
*imv
, unsigned int type
)
564 unsigned int vendor
, subtype
;
566 if (imv
== NULL
|| imv
->supported_types
== NULL
)
570 subtype
= type
& 0xff;
572 for (i
= 0; i
< imv
->num_supported_types
; i
++) {
573 unsigned int svendor
, ssubtype
;
574 svendor
= imv
->supported_types
[i
] >> 8;
575 ssubtype
= imv
->supported_types
[i
] & 0xff;
576 if ((vendor
== svendor
|| svendor
== TNC_VENDORID_ANY
) &&
577 (subtype
== ssubtype
|| ssubtype
== TNC_SUBTYPE_ANY
))
585 static void tncs_send_to_imvs(struct tncs_data
*tncs
, unsigned int type
,
586 const u8
*msg
, size_t len
)
588 struct tnc_if_imv
*imv
;
591 wpa_hexdump_ascii(MSG_MSGDUMP
, "TNC: Message to IMV(s)", msg
, len
);
593 for (imv
= tncs
->imv
; imv
; imv
= imv
->next
) {
594 if (imv
->ReceiveMessage
== NULL
||
595 !tncs_supported_type(imv
, type
))
598 wpa_printf(MSG_DEBUG
, "TNC: Call ReceiveMessage for IMV '%s'",
600 res
= imv
->ReceiveMessage(imv
->imvID
, tncs
->connectionID
,
601 (TNC_BufferReference
) msg
, len
,
603 wpa_printf(MSG_DEBUG
, "TNC: ReceiveMessage: %lu",
604 (unsigned long) res
);
609 static void tncs_batch_ending(struct tncs_data
*tncs
)
611 struct tnc_if_imv
*imv
;
614 for (imv
= tncs
->imv
; imv
; imv
= imv
->next
) {
615 if (imv
->BatchEnding
== NULL
)
618 wpa_printf(MSG_DEBUG
, "TNC: Call BatchEnding for IMV '%s'",
620 res
= imv
->BatchEnding(imv
->imvID
, tncs
->connectionID
);
621 wpa_printf(MSG_DEBUG
, "TNC: BatchEnding: %lu",
622 (unsigned long) res
);
627 static void tncs_solicit_recommendation(struct tncs_data
*tncs
)
629 struct tnc_if_imv
*imv
;
632 for (imv
= tncs
->imv
; imv
; imv
= imv
->next
) {
633 if (tncs
->imv_data
[imv
->imvID
].recommendation_set
)
636 wpa_printf(MSG_DEBUG
, "TNC: Call SolicitRecommendation for "
637 "IMV '%s'", imv
->name
);
638 res
= imv
->SolicitRecommendation(imv
->imvID
,
640 wpa_printf(MSG_DEBUG
, "TNC: SolicitRecommendation: %lu",
641 (unsigned long) res
);
646 void tncs_init_connection(struct tncs_data
*tncs
)
648 struct tnc_if_imv
*imv
;
651 for (imv
= tncs
->imv
; imv
; imv
= imv
->next
) {
652 tncs_imv_notify_connection_change(
653 imv
, tncs
->connectionID
, TNC_CONNECTION_STATE_CREATE
);
654 tncs_imv_notify_connection_change(
655 imv
, tncs
->connectionID
,
656 TNC_CONNECTION_STATE_HANDSHAKE
);
659 for (i
= 0; i
< TNC_MAX_IMV_ID
; i
++) {
660 os_free(tncs
->imv_data
[i
].imv_send
);
661 tncs
->imv_data
[i
].imv_send
= NULL
;
662 tncs
->imv_data
[i
].imv_send_len
= 0;
667 size_t tncs_total_send_len(struct tncs_data
*tncs
)
672 for (i
= 0; i
< TNC_MAX_IMV_ID
; i
++)
673 len
+= tncs
->imv_data
[i
].imv_send_len
;
674 if (tncs
->tncs_message
)
675 len
+= os_strlen(tncs
->tncs_message
);
680 u8
* tncs_copy_send_buf(struct tncs_data
*tncs
, u8
*pos
)
684 for (i
= 0; i
< TNC_MAX_IMV_ID
; i
++) {
685 if (tncs
->imv_data
[i
].imv_send
== NULL
)
688 os_memcpy(pos
, tncs
->imv_data
[i
].imv_send
,
689 tncs
->imv_data
[i
].imv_send_len
);
690 pos
+= tncs
->imv_data
[i
].imv_send_len
;
691 os_free(tncs
->imv_data
[i
].imv_send
);
692 tncs
->imv_data
[i
].imv_send
= NULL
;
693 tncs
->imv_data
[i
].imv_send_len
= 0;
696 if (tncs
->tncs_message
) {
697 size_t len
= os_strlen(tncs
->tncs_message
);
698 os_memcpy(pos
, tncs
->tncs_message
, len
);
700 os_free(tncs
->tncs_message
);
701 tncs
->tncs_message
= NULL
;
708 char * tncs_if_tnccs_start(struct tncs_data
*tncs
)
710 char *buf
= os_malloc(1000);
713 tncs
->last_batchid
++;
714 os_snprintf(buf
, 1000, IF_TNCCS_START
, tncs
->last_batchid
);
719 char * tncs_if_tnccs_end(void)
721 char *buf
= os_malloc(100);
724 os_snprintf(buf
, 100, IF_TNCCS_END
);
729 static int tncs_get_type(char *start
, unsigned int *type
)
731 char *pos
= os_strstr(start
, "<Type>");
735 *type
= strtoul(pos
, NULL
, 16);
740 static unsigned char * tncs_get_base64(char *start
, size_t *decoded_len
)
743 unsigned char *decoded
;
745 pos
= os_strstr(start
, "<Base64>");
750 pos2
= os_strstr(pos
, "</Base64>");
755 decoded
= base64_decode((unsigned char *) pos
, os_strlen(pos
),
758 if (decoded
== NULL
) {
759 wpa_printf(MSG_DEBUG
, "TNC: Failed to decode Base64 data");
766 static enum tncs_process_res
tncs_derive_recommendation(struct tncs_data
*tncs
)
768 enum IMV_Action_Recommendation rec
;
769 struct tnc_if_imv
*imv
;
770 TNC_ConnectionState state
;
773 wpa_printf(MSG_DEBUG
, "TNC: No more messages from IMVs");
776 return TNCCS_PROCESS_OK_NO_RECOMMENDATION
;
778 tncs_solicit_recommendation(tncs
);
780 /* Select the most restrictive recommendation */
781 rec
= TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
;
782 for (imv
= tncs
->imv
; imv
; imv
= imv
->next
) {
783 TNC_IMV_Action_Recommendation irec
;
784 irec
= tncs
->imv_data
[imv
->imvID
].recommendation
;
785 if (irec
== TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
)
786 rec
= TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
;
787 if (irec
== TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
&&
788 rec
!= TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
)
789 rec
= TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
;
790 if (irec
== TNC_IMV_ACTION_RECOMMENDATION_ALLOW
&&
791 rec
== TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
)
792 rec
= TNC_IMV_ACTION_RECOMMENDATION_ALLOW
;
795 wpa_printf(MSG_DEBUG
, "TNC: Recommendation: %d", rec
);
796 tncs
->recommendation
= rec
;
801 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW
:
802 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
:
804 state
= TNC_CONNECTION_STATE_ACCESS_ALLOWED
;
806 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
:
808 state
= TNC_CONNECTION_STATE_ACCESS_ISOLATED
;
810 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
:
812 state
= TNC_CONNECTION_STATE_ACCESS_NONE
;
815 state
= TNC_CONNECTION_STATE_ACCESS_ALLOWED
;
820 os_free(tncs
->tncs_message
);
821 tncs
->tncs_message
= os_zalloc(200);
822 if (tncs
->tncs_message
) {
823 os_snprintf(tncs
->tncs_message
, 199,
824 "<TNCC-TNCS-Message><Type>%08X</Type>"
825 "<XML><TNCCS-Recommendation type=\"%s\">"
826 "</TNCCS-Recommendation></XML>"
827 "</TNCC-TNCS-Message>",
828 TNC_TNCCS_RECOMMENDATION
, txt
);
832 for (imv
= tncs
->imv
; imv
; imv
= imv
->next
) {
833 tncs_imv_notify_connection_change(imv
, tncs
->connectionID
,
838 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW
:
839 return TNCCS_RECOMMENDATION_ALLOW
;
840 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
:
841 return TNCCS_RECOMMENDATION_NO_ACCESS
;
842 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
:
843 return TNCCS_RECOMMENDATION_ISOLATE
;
844 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
:
845 return TNCCS_RECOMMENDATION_NO_RECOMMENDATION
;
847 return TNCCS_PROCESS_ERROR
;
852 enum tncs_process_res
tncs_process_if_tnccs(struct tncs_data
*tncs
,
853 const u8
*msg
, size_t len
)
855 char *buf
, *start
, *end
, *pos
, *pos2
, *payload
;
856 unsigned int batch_id
;
857 unsigned char *decoded
;
860 buf
= os_malloc(len
+ 1);
862 return TNCCS_PROCESS_ERROR
;
864 os_memcpy(buf
, msg
, len
);
866 start
= os_strstr(buf
, "<TNCCS-Batch ");
867 end
= os_strstr(buf
, "</TNCCS-Batch>");
868 if (start
== NULL
|| end
== NULL
|| start
> end
) {
870 return TNCCS_PROCESS_ERROR
;
874 while (*start
== ' ')
878 pos
= os_strstr(start
, "BatchId=");
881 return TNCCS_PROCESS_ERROR
;
887 batch_id
= atoi(pos
);
888 wpa_printf(MSG_DEBUG
, "TNC: Received IF-TNCCS BatchId=%u",
890 if (batch_id
!= tncs
->last_batchid
+ 1) {
891 wpa_printf(MSG_DEBUG
, "TNC: Unexpected IF-TNCCS BatchId "
893 batch_id
, tncs
->last_batchid
+ 1);
895 return TNCCS_PROCESS_ERROR
;
897 tncs
->last_batchid
= batch_id
;
899 while (*pos
!= '\0' && *pos
!= '>')
903 return TNCCS_PROCESS_ERROR
;
910 * <Type>01234567</Type>
911 * <Base64>foo==</Base64>
919 pos
= os_strstr(start
, "<IMC-IMV-Message>");
923 end
= os_strstr(start
, "</IMC-IMV-Message>");
930 if (tncs_get_type(start
, &type
) < 0) {
935 wpa_printf(MSG_DEBUG
, "TNC: IMC-IMV-Message Type 0x%x", type
);
937 decoded
= tncs_get_base64(start
, &decoded_len
);
938 if (decoded
== NULL
) {
944 tncs_send_to_imvs(tncs
, type
, decoded
, decoded_len
);
952 * <TNCC-TNCS-Message>
953 * <Type>01234567</Type>
954 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
955 * <Base64>foo==</Base64>
956 * </TNCC-TNCS-Message>
962 char *xml
, *xmlend
, *endpos
;
964 pos
= os_strstr(start
, "<TNCC-TNCS-Message>");
968 end
= os_strstr(start
, "</TNCC-TNCS-Message>");
975 if (tncs_get_type(start
, &type
) < 0) {
980 wpa_printf(MSG_DEBUG
, "TNC: TNCC-TNCS-Message Type 0x%x",
987 pos
= os_strstr(start
, "<XML>");
990 pos2
= os_strstr(pos
, "</XML>");
999 decoded
= tncs_get_base64(start
, &decoded_len
);
1000 if (decoded
== NULL
) {
1008 wpa_hexdump_ascii(MSG_MSGDUMP
,
1009 "TNC: TNCC-TNCS-Message Base64",
1010 decoded
, decoded_len
);
1015 wpa_hexdump_ascii(MSG_MSGDUMP
,
1016 "TNC: TNCC-TNCS-Message XML",
1017 (unsigned char *) xml
,
1026 tncs_batch_ending(tncs
);
1028 if (tncs_total_send_len(tncs
) == 0)
1029 return tncs_derive_recommendation(tncs
);
1031 return TNCCS_PROCESS_OK_NO_RECOMMENDATION
;
1035 static struct tnc_if_imv
* tncs_parse_imv(int id
, char *start
, char *end
,
1038 struct tnc_if_imv
*imv
;
1041 if (id
>= TNC_MAX_IMV_ID
) {
1042 wpa_printf(MSG_DEBUG
, "TNC: Too many IMVs");
1046 imv
= os_zalloc(sizeof(*imv
));
1055 wpa_printf(MSG_DEBUG
, "TNC: Configured IMV: %s", pos
);
1056 if (pos
+ 1 >= end
|| *pos
!= '"') {
1057 wpa_printf(MSG_ERROR
, "TNC: Ignoring invalid IMV line '%s' "
1058 "(no starting quotation mark)", start
);
1065 while (pos2
< end
&& *pos2
!= '"')
1068 wpa_printf(MSG_ERROR
, "TNC: Ignoring invalid IMV line '%s' "
1069 "(no ending quotation mark)", start
);
1074 wpa_printf(MSG_DEBUG
, "TNC: Name: '%s'", pos
);
1075 imv
->name
= os_strdup(pos
);
1078 if (pos
>= end
|| *pos
!= ' ') {
1079 wpa_printf(MSG_ERROR
, "TNC: Ignoring invalid IMV line '%s' "
1080 "(no space after name)", start
);
1086 wpa_printf(MSG_DEBUG
, "TNC: IMV file: '%s'", pos
);
1087 imv
->path
= os_strdup(pos
);
1093 static int tncs_read_config(struct tncs_global
*global
)
1095 char *config
, *end
, *pos
, *line_end
;
1097 struct tnc_if_imv
*imv
, *last
;
1102 config
= os_readfile(TNC_CONFIG_FILE
, &config_len
);
1103 if (config
== NULL
) {
1104 wpa_printf(MSG_ERROR
, "TNC: Could not open TNC configuration "
1105 "file '%s'", TNC_CONFIG_FILE
);
1109 end
= config
+ config_len
;
1110 for (pos
= config
; pos
< end
; pos
= line_end
+ 1) {
1112 while (*line_end
!= '\n' && *line_end
!= '\r' &&
1117 if (os_strncmp(pos
, "IMV ", 4) == 0) {
1120 imv
= tncs_parse_imv(id
++, pos
+ 4, line_end
, &error
);
1139 struct tncs_data
* tncs_init(void)
1141 struct tncs_data
*tncs
;
1143 if (tncs_global_data
== NULL
)
1146 tncs
= os_zalloc(sizeof(*tncs
));
1149 tncs
->imv
= tncs_global_data
->imv
;
1150 tncs
->connectionID
= tncs_global_data
->next_conn_id
++;
1151 tncs
->next
= tncs_global_data
->connections
;
1152 tncs_global_data
->connections
= tncs
;
1158 void tncs_deinit(struct tncs_data
*tncs
)
1161 struct tncs_data
*prev
, *conn
;
1166 for (i
= 0; i
< TNC_MAX_IMV_ID
; i
++)
1167 os_free(tncs
->imv_data
[i
].imv_send
);
1170 conn
= tncs_global_data
->connections
;
1174 prev
->next
= tncs
->next
;
1176 tncs_global_data
->connections
= tncs
->next
;
1183 os_free(tncs
->tncs_message
);
1188 int tncs_global_init(void)
1190 struct tnc_if_imv
*imv
;
1192 tncs_global_data
= os_zalloc(sizeof(*tncs_global_data
));
1193 if (tncs_global_data
== NULL
)
1196 if (tncs_read_config(tncs_global_data
) < 0) {
1197 wpa_printf(MSG_ERROR
, "TNC: Failed to read TNC configuration");
1201 for (imv
= tncs_global_data
->imv
; imv
; imv
= imv
->next
) {
1202 if (tncs_load_imv(imv
)) {
1203 wpa_printf(MSG_ERROR
, "TNC: Failed to load IMV '%s'",
1212 tncs_global_deinit();
1217 void tncs_global_deinit(void)
1219 struct tnc_if_imv
*imv
, *prev
;
1221 if (tncs_global_data
== NULL
)
1224 imv
= tncs_global_data
->imv
;
1226 tncs_unload_imv(imv
);
1233 os_free(tncs_global_data
);
1237 struct wpabuf
* tncs_build_soh_request(void)
1242 * Build a SoH Request TLV (to be used inside SoH EAP Extensions
1246 buf
= wpabuf_alloc(8 + 4);
1250 /* Vendor-Specific TLV (Microsoft) - SoH Request */
1251 wpabuf_put_be16(buf
, EAP_TLV_VENDOR_SPECIFIC_TLV
); /* TLV Type */
1252 wpabuf_put_be16(buf
, 8); /* Length */
1254 wpabuf_put_be32(buf
, EAP_VENDOR_MICROSOFT
); /* Vendor_Id */
1256 wpabuf_put_be16(buf
, 0x02); /* TLV Type - SoH Request TLV */
1257 wpabuf_put_be16(buf
, 0); /* Length */
1263 struct wpabuf
* tncs_process_soh(const u8
*soh_tlv
, size_t soh_tlv_len
,
1266 wpa_hexdump(MSG_DEBUG
, "TNC: SoH TLV", soh_tlv
, soh_tlv_len
);
1269 /* TODO: return MS-SoH Response TLV */