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);