2 * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
3 * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
14 #include "common/tnc.h"
16 #include "eap_common/eap_tlv_common.h"
17 #include "eap_common/eap_defs.h"
20 /* TODO: TNCS must be thread-safe; review the code and add locking etc. if
23 #ifndef TNC_CONFIG_FILE
24 #define TNC_CONFIG_FILE "/etc/tnc_config"
25 #endif /* TNC_CONFIG_FILE */
26 #define IF_TNCCS_START \
27 "<?xml version=\"1.0\"?>\n" \
28 "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
29 "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
30 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
31 "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
32 "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
33 #define IF_TNCCS_END "\n</TNCCS-Batch>"
38 struct tnc_if_imv *next;
41 void *dlhandle; /* from dlopen() */
43 TNC_MessageTypeList supported_types;
44 size_t num_supported_types;
46 /* Functions implemented by IMVs (with TNC_IMV_ prefix) */
47 TNC_Result (*Initialize)(
49 TNC_Version minVersion,
50 TNC_Version maxVersion,
51 TNC_Version *pOutActualVersion);
52 TNC_Result (*NotifyConnectionChange)(
54 TNC_ConnectionID connectionID,
55 TNC_ConnectionState newState);
56 TNC_Result (*ReceiveMessage)(
58 TNC_ConnectionID connectionID,
59 TNC_BufferReference message,
60 TNC_UInt32 messageLength,
61 TNC_MessageType messageType);
62 TNC_Result (*SolicitRecommendation)(
64 TNC_ConnectionID connectionID);
65 TNC_Result (*BatchEnding)(
67 TNC_ConnectionID connectionID);
68 TNC_Result (*Terminate)(TNC_IMVID imvID);
69 TNC_Result (*ProvideBindFunction)(
71 TNC_TNCS_BindFunctionPointer bindFunction);
75 #define TNC_MAX_IMV_ID 10
78 struct tncs_data *next;
79 struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
80 TNC_ConnectionID connectionID;
81 unsigned int last_batchid;
82 enum IMV_Action_Recommendation recommendation;
88 enum IMV_Action_Recommendation recommendation;
89 int recommendation_set;
90 } imv_data[TNC_MAX_IMV_ID];
97 struct tnc_if_imv *imv;
98 TNC_ConnectionID next_conn_id;
99 struct tncs_data *connections;
102 static struct tncs_global *tncs_global_data = NULL;
105 static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
107 struct tnc_if_imv *imv;
109 if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
111 imv = tncs_global_data->imv;
113 if (imv->imvID == imvID)
121 static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
123 struct tncs_data *tncs;
125 if (tncs_global_data == NULL)
128 tncs = tncs_global_data->connections;
130 if (tncs->connectionID == connectionID)
135 wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
136 (unsigned long) connectionID);
142 /* TNCS functions that IMVs can call */
143 static TNC_Result TNC_TNCS_ReportMessageTypes(
145 TNC_MessageTypeList supportedTypes,
146 TNC_UInt32 typeCount)
149 struct tnc_if_imv *imv;
151 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
153 (unsigned long) imvID, (unsigned long) typeCount);
155 for (i = 0; i < typeCount; i++) {
156 wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
157 i, supportedTypes[i]);
160 imv = tncs_get_imv(imvID);
162 return TNC_RESULT_INVALID_PARAMETER;
163 os_free(imv->supported_types);
164 imv->supported_types = os_memdup(supportedTypes,
165 typeCount * sizeof(TNC_MessageType));
166 if (imv->supported_types == NULL)
167 return TNC_RESULT_FATAL;
168 imv->num_supported_types = typeCount;
170 return TNC_RESULT_SUCCESS;
174 static TNC_Result TNC_TNCS_SendMessage(
176 TNC_ConnectionID connectionID,
177 TNC_BufferReference message,
178 TNC_UInt32 messageLength,
179 TNC_MessageType messageType)
181 struct tncs_data *tncs;
185 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
186 "connectionID=%lu messageType=%lu)",
187 imvID, connectionID, messageType);
188 wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
189 message, messageLength);
191 if (tncs_get_imv(imvID) == NULL)
192 return TNC_RESULT_INVALID_PARAMETER;
194 tncs = tncs_get_conn(connectionID);
196 return TNC_RESULT_INVALID_PARAMETER;
198 b64 = base64_encode(message, messageLength, &b64len);
200 return TNC_RESULT_FATAL;
202 os_free(tncs->imv_data[imvID].imv_send);
203 tncs->imv_data[imvID].imv_send_len = 0;
204 tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
205 if (tncs->imv_data[imvID].imv_send == NULL) {
207 return TNC_RESULT_OTHER;
210 tncs->imv_data[imvID].imv_send_len =
211 os_snprintf((char *) tncs->imv_data[imvID].imv_send,
213 "<IMC-IMV-Message><Type>%08X</Type>"
214 "<Base64>%s</Base64></IMC-IMV-Message>",
215 (unsigned int) messageType, b64);
219 return TNC_RESULT_SUCCESS;
223 static TNC_Result TNC_TNCS_RequestHandshakeRetry(
225 TNC_ConnectionID connectionID,
226 TNC_RetryReason reason)
228 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
230 return TNC_RESULT_SUCCESS;
234 static TNC_Result TNC_TNCS_ProvideRecommendation(
236 TNC_ConnectionID connectionID,
237 TNC_IMV_Action_Recommendation recommendation,
238 TNC_IMV_Evaluation_Result evaluation)
240 struct tncs_data *tncs;
242 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
243 "connectionID=%lu recommendation=%lu evaluation=%lu)",
244 (unsigned long) imvID, (unsigned long) connectionID,
245 (unsigned long) recommendation, (unsigned long) evaluation);
247 if (tncs_get_imv(imvID) == NULL)
248 return TNC_RESULT_INVALID_PARAMETER;
250 tncs = tncs_get_conn(connectionID);
252 return TNC_RESULT_INVALID_PARAMETER;
254 tncs->imv_data[imvID].recommendation = recommendation;
255 tncs->imv_data[imvID].recommendation_set = 1;
257 return TNC_RESULT_SUCCESS;
261 static TNC_Result TNC_TNCS_GetAttribute(
263 TNC_ConnectionID connectionID,
264 TNC_AttributeID attribureID,
265 TNC_UInt32 bufferLength,
266 TNC_BufferReference buffer,
267 TNC_UInt32 *pOutValueLength)
269 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
271 return TNC_RESULT_SUCCESS;
275 static TNC_Result TNC_TNCS_SetAttribute(
277 TNC_ConnectionID connectionID,
278 TNC_AttributeID attribureID,
279 TNC_UInt32 bufferLength,
280 TNC_BufferReference buffer)
282 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
284 return TNC_RESULT_SUCCESS;
288 static TNC_Result TNC_TNCS_BindFunction(
291 void **pOutFunctionPointer)
293 wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
294 "functionName='%s')", (unsigned long) imvID, functionName);
296 if (tncs_get_imv(imvID) == NULL)
297 return TNC_RESULT_INVALID_PARAMETER;
299 if (pOutFunctionPointer == NULL)
300 return TNC_RESULT_INVALID_PARAMETER;
302 if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
303 *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
304 else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
305 *pOutFunctionPointer = TNC_TNCS_SendMessage;
306 else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
308 *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
309 else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
311 *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
312 else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
313 *pOutFunctionPointer = TNC_TNCS_GetAttribute;
314 else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
315 *pOutFunctionPointer = TNC_TNCS_SetAttribute;
317 *pOutFunctionPointer = NULL;
319 return TNC_RESULT_SUCCESS;
323 static void * tncs_get_sym(void *handle, char *func)
327 fptr = dlsym(handle, func);
333 static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
335 void *handle = imv->dlhandle;
337 /* Mandatory IMV functions */
338 imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
339 if (imv->Initialize == NULL) {
340 wpa_printf(MSG_ERROR, "TNC: IMV does not export "
341 "TNC_IMV_Initialize");
345 imv->SolicitRecommendation = tncs_get_sym(
346 handle, "TNC_IMV_SolicitRecommendation");
347 if (imv->SolicitRecommendation == NULL) {
348 wpa_printf(MSG_ERROR, "TNC: IMV does not export "
349 "TNC_IMV_SolicitRecommendation");
353 imv->ProvideBindFunction =
354 tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
355 if (imv->ProvideBindFunction == NULL) {
356 wpa_printf(MSG_ERROR, "TNC: IMV does not export "
357 "TNC_IMV_ProvideBindFunction");
361 /* Optional IMV functions */
362 imv->NotifyConnectionChange =
363 tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
364 imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
365 imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
366 imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
372 static int tncs_imv_initialize(struct tnc_if_imv *imv)
377 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
379 res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
380 TNC_IFIMV_VERSION_1, &imv_ver);
381 wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
382 (unsigned long) res, (unsigned long) imv_ver);
384 return res == TNC_RESULT_SUCCESS ? 0 : -1;
388 static int tncs_imv_terminate(struct tnc_if_imv *imv)
392 if (imv->Terminate == NULL)
395 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
397 res = imv->Terminate(imv->imvID);
398 wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
399 (unsigned long) res);
401 return res == TNC_RESULT_SUCCESS ? 0 : -1;
405 static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
409 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
410 "IMV '%s'", imv->name);
411 res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
412 wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
413 (unsigned long) res);
415 return res == TNC_RESULT_SUCCESS ? 0 : -1;
419 static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
420 TNC_ConnectionID conn,
421 TNC_ConnectionState state)
425 if (imv->NotifyConnectionChange == NULL)
428 wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
429 " for IMV '%s'", (int) state, imv->name);
430 res = imv->NotifyConnectionChange(imv->imvID, conn, state);
431 wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
432 (unsigned long) res);
434 return res == TNC_RESULT_SUCCESS ? 0 : -1;
438 static int tncs_load_imv(struct tnc_if_imv *imv)
440 if (imv->path == NULL) {
441 wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
445 wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
446 imv->name, imv->path);
447 imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
448 if (imv->dlhandle == NULL) {
449 wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
450 imv->name, imv->path, dlerror());
454 if (tncs_imv_resolve_funcs(imv) < 0) {
455 wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
459 if (tncs_imv_initialize(imv) < 0 ||
460 tncs_imv_provide_bind_function(imv) < 0) {
461 wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
469 static void tncs_free_imv(struct tnc_if_imv *imv)
473 os_free(imv->supported_types);
476 static void tncs_unload_imv(struct tnc_if_imv *imv)
478 tncs_imv_terminate(imv);
481 dlclose(imv->dlhandle);
487 static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
490 unsigned int vendor, subtype;
492 if (imv == NULL || imv->supported_types == NULL)
496 subtype = type & 0xff;
498 for (i = 0; i < imv->num_supported_types; i++) {
499 unsigned int svendor, ssubtype;
500 svendor = imv->supported_types[i] >> 8;
501 ssubtype = imv->supported_types[i] & 0xff;
502 if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
503 (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
511 static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
512 const u8 *msg, size_t len)
514 struct tnc_if_imv *imv;
517 wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
519 for (imv = tncs->imv; imv; imv = imv->next) {
520 if (imv->ReceiveMessage == NULL ||
521 !tncs_supported_type(imv, type))
524 wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
526 res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
527 (TNC_BufferReference) msg, len,
529 wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
530 (unsigned long) res);
535 static void tncs_batch_ending(struct tncs_data *tncs)
537 struct tnc_if_imv *imv;
540 for (imv = tncs->imv; imv; imv = imv->next) {
541 if (imv->BatchEnding == NULL)
544 wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
546 res = imv->BatchEnding(imv->imvID, tncs->connectionID);
547 wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
548 (unsigned long) res);
553 static void tncs_solicit_recommendation(struct tncs_data *tncs)
555 struct tnc_if_imv *imv;
558 for (imv = tncs->imv; imv; imv = imv->next) {
559 if (tncs->imv_data[imv->imvID].recommendation_set)
562 wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
563 "IMV '%s'", imv->name);
564 res = imv->SolicitRecommendation(imv->imvID,
566 wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
567 (unsigned long) res);
572 void tncs_init_connection(struct tncs_data *tncs)
574 struct tnc_if_imv *imv;
577 for (imv = tncs->imv; imv; imv = imv->next) {
578 tncs_imv_notify_connection_change(
579 imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
580 tncs_imv_notify_connection_change(
581 imv, tncs->connectionID,
582 TNC_CONNECTION_STATE_HANDSHAKE);
585 for (i = 0; i < TNC_MAX_IMV_ID; i++) {
586 os_free(tncs->imv_data[i].imv_send);
587 tncs->imv_data[i].imv_send = NULL;
588 tncs->imv_data[i].imv_send_len = 0;
593 size_t tncs_total_send_len(struct tncs_data *tncs)
598 for (i = 0; i < TNC_MAX_IMV_ID; i++)
599 len += tncs->imv_data[i].imv_send_len;
600 if (tncs->tncs_message)
601 len += os_strlen(tncs->tncs_message);
606 u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
610 for (i = 0; i < TNC_MAX_IMV_ID; i++) {
611 if (tncs->imv_data[i].imv_send == NULL)
614 os_memcpy(pos, tncs->imv_data[i].imv_send,
615 tncs->imv_data[i].imv_send_len);
616 pos += tncs->imv_data[i].imv_send_len;
617 os_free(tncs->imv_data[i].imv_send);
618 tncs->imv_data[i].imv_send = NULL;
619 tncs->imv_data[i].imv_send_len = 0;
622 if (tncs->tncs_message) {
623 size_t len = os_strlen(tncs->tncs_message);
624 os_memcpy(pos, tncs->tncs_message, len);
626 os_free(tncs->tncs_message);
627 tncs->tncs_message = NULL;
634 char * tncs_if_tnccs_start(struct tncs_data *tncs)
636 char *buf = os_malloc(1000);
639 tncs->last_batchid++;
640 os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
645 char * tncs_if_tnccs_end(void)
647 char *buf = os_malloc(100);
650 os_snprintf(buf, 100, IF_TNCCS_END);
655 static int tncs_get_type(char *start, unsigned int *type)
657 char *pos = os_strstr(start, "<Type>");
661 *type = strtoul(pos, NULL, 16);
666 static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
669 unsigned char *decoded;
671 pos = os_strstr(start, "<Base64>");
676 pos2 = os_strstr(pos, "</Base64>");
681 decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
684 if (decoded == NULL) {
685 wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
692 static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
694 enum IMV_Action_Recommendation rec;
695 struct tnc_if_imv *imv;
696 TNC_ConnectionState state;
699 wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
702 return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
704 tncs_solicit_recommendation(tncs);
706 /* Select the most restrictive recommendation */
707 rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
708 for (imv = tncs->imv; imv; imv = imv->next) {
709 TNC_IMV_Action_Recommendation irec;
710 irec = tncs->imv_data[imv->imvID].recommendation;
711 if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
712 rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
713 if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
714 rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
715 rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
716 if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
717 rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
718 rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
721 wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
722 tncs->recommendation = rec;
727 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
728 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
730 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
732 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
734 state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
736 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
738 state = TNC_CONNECTION_STATE_ACCESS_NONE;
741 state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
746 os_free(tncs->tncs_message);
747 tncs->tncs_message = os_zalloc(200);
748 if (tncs->tncs_message) {
749 os_snprintf(tncs->tncs_message, 199,
750 "<TNCC-TNCS-Message><Type>%08X</Type>"
751 "<XML><TNCCS-Recommendation type=\"%s\">"
752 "</TNCCS-Recommendation></XML>"
753 "</TNCC-TNCS-Message>",
754 TNC_TNCCS_RECOMMENDATION, txt);
758 for (imv = tncs->imv; imv; imv = imv->next) {
759 tncs_imv_notify_connection_change(imv, tncs->connectionID,
764 case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
765 return TNCCS_RECOMMENDATION_ALLOW;
766 case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
767 return TNCCS_RECOMMENDATION_NO_ACCESS;
768 case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
769 return TNCCS_RECOMMENDATION_ISOLATE;
770 case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
771 return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
773 return TNCCS_PROCESS_ERROR;
778 enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
779 const u8 *msg, size_t len)
781 char *buf, *start, *end, *pos, *pos2, *payload;
782 unsigned int batch_id;
783 unsigned char *decoded;
786 buf = dup_binstr(msg, len);
788 return TNCCS_PROCESS_ERROR;
790 start = os_strstr(buf, "<TNCCS-Batch ");
791 end = os_strstr(buf, "</TNCCS-Batch>");
792 if (start == NULL || end == NULL || start > end) {
794 return TNCCS_PROCESS_ERROR;
798 while (*start == ' ')
802 pos = os_strstr(start, "BatchId=");
805 return TNCCS_PROCESS_ERROR;
811 batch_id = atoi(pos);
812 wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
814 if (batch_id != tncs->last_batchid + 1) {
815 wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
817 batch_id, tncs->last_batchid + 1);
819 return TNCCS_PROCESS_ERROR;
821 tncs->last_batchid = batch_id;
823 while (*pos != '\0' && *pos != '>')
827 return TNCCS_PROCESS_ERROR;
834 * <Type>01234567</Type>
835 * <Base64>foo==</Base64>
843 pos = os_strstr(start, "<IMC-IMV-Message>");
847 end = os_strstr(start, "</IMC-IMV-Message>");
854 if (tncs_get_type(start, &type) < 0) {
859 wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
861 decoded = tncs_get_base64(start, &decoded_len);
862 if (decoded == NULL) {
868 tncs_send_to_imvs(tncs, type, decoded, decoded_len);
876 * <TNCC-TNCS-Message>
877 * <Type>01234567</Type>
878 * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
879 * <Base64>foo==</Base64>
880 * </TNCC-TNCS-Message>
886 char *xml, *xmlend, *endpos;
888 pos = os_strstr(start, "<TNCC-TNCS-Message>");
892 end = os_strstr(start, "</TNCC-TNCS-Message>");
899 if (tncs_get_type(start, &type) < 0) {
904 wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
911 pos = os_strstr(start, "<XML>");
914 pos2 = os_strstr(pos, "</XML>");
923 decoded = tncs_get_base64(start, &decoded_len);
924 if (decoded == NULL) {
932 wpa_hexdump_ascii(MSG_MSGDUMP,
933 "TNC: TNCC-TNCS-Message Base64",
934 decoded, decoded_len);
939 wpa_hexdump_ascii(MSG_MSGDUMP,
940 "TNC: TNCC-TNCS-Message XML",
941 (unsigned char *) xml,
950 tncs_batch_ending(tncs);
952 if (tncs_total_send_len(tncs) == 0)
953 return tncs_derive_recommendation(tncs);
955 return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
959 static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
962 struct tnc_if_imv *imv;
965 if (id >= TNC_MAX_IMV_ID) {
966 wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
970 imv = os_zalloc(sizeof(*imv));
979 wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
980 if (pos + 1 >= end || *pos != '"') {
981 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
982 "(no starting quotation mark)", start);
989 while (pos2 < end && *pos2 != '"')
992 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
993 "(no ending quotation mark)", start);
998 wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
999 imv->name = os_strdup(pos);
1002 if (pos >= end || *pos != ' ') {
1003 wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
1004 "(no space after name)", start);
1010 wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
1011 imv->path = os_strdup(pos);
1017 static int tncs_read_config(struct tncs_global *global)
1019 char *config, *end, *pos, *line_end;
1021 struct tnc_if_imv *imv, *last;
1026 config = os_readfile(TNC_CONFIG_FILE, &config_len);
1027 if (config == NULL) {
1028 wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
1029 "file '%s'", TNC_CONFIG_FILE);
1033 end = config + config_len;
1034 for (pos = config; pos < end; pos = line_end + 1) {
1036 while (*line_end != '\n' && *line_end != '\r' &&
1041 if (os_strncmp(pos, "IMV ", 4) == 0) {
1044 imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
1063 struct tncs_data * tncs_init(void)
1065 struct tncs_data *tncs;
1067 if (tncs_global_data == NULL)
1070 tncs = os_zalloc(sizeof(*tncs));
1073 tncs->imv = tncs_global_data->imv;
1074 tncs->connectionID = tncs_global_data->next_conn_id++;
1075 tncs->next = tncs_global_data->connections;
1076 tncs_global_data->connections = tncs;
1082 void tncs_deinit(struct tncs_data *tncs)
1085 struct tncs_data *prev, *conn;
1090 for (i = 0; i < TNC_MAX_IMV_ID; i++)
1091 os_free(tncs->imv_data[i].imv_send);
1094 conn = tncs_global_data->connections;
1098 prev->next = tncs->next;
1100 tncs_global_data->connections = tncs->next;
1107 os_free(tncs->tncs_message);
1112 int tncs_global_init(void)
1114 struct tnc_if_imv *imv;
1116 if (tncs_global_data)
1119 tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
1120 if (tncs_global_data == NULL)
1123 if (tncs_read_config(tncs_global_data) < 0) {
1124 wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
1128 for (imv = tncs_global_data->imv; imv; imv = imv->next) {
1129 if (tncs_load_imv(imv)) {
1130 wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
1139 tncs_global_deinit();
1144 void tncs_global_deinit(void)
1146 struct tnc_if_imv *imv, *prev;
1148 if (tncs_global_data == NULL)
1151 imv = tncs_global_data->imv;
1153 tncs_unload_imv(imv);
1160 os_free(tncs_global_data);
1161 tncs_global_data = NULL;
1165 struct wpabuf * tncs_build_soh_request(void)
1170 * Build a SoH Request TLV (to be used inside SoH EAP Extensions
1174 buf = wpabuf_alloc(8 + 4);
1178 /* Vendor-Specific TLV (Microsoft) - SoH Request */
1179 wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
1180 wpabuf_put_be16(buf, 8); /* Length */
1182 wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
1184 wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
1185 wpabuf_put_be16(buf, 0); /* Length */
1191 struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
1194 wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
1197 /* TODO: return MS-SoH Response TLV */