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)
90
struct tnc_if_imc *next;
93
void *dlhandle; /* from dlopen() */
95
TNC_ConnectionID connectionID;
96
TNC_MessageTypeList supported_types;
97
size_t num_supported_types;
101
/* Functions implemented by IMCs (with TNC_IMC_ prefix) */
102
TNC_Result (*Initialize)(
104
TNC_Version minVersion,
105
TNC_Version maxVersion,
106
TNC_Version *pOutActualVersion);
107
TNC_Result (*NotifyConnectionChange)(
109
TNC_ConnectionID connectionID,
110
TNC_ConnectionState newState);
111
TNC_Result (*BeginHandshake)(
113
TNC_ConnectionID connectionID);
114
TNC_Result (*ReceiveMessage)(
116
TNC_ConnectionID connectionID,
117
TNC_BufferReference messageBuffer,
118
TNC_UInt32 messageLength,
119
TNC_MessageType messageType);
120
TNC_Result (*BatchEnding)(
122
TNC_ConnectionID connectionID);
123
TNC_Result (*Terminate)(TNC_IMCID imcID);
124
TNC_Result (*ProvideBindFunction)(
126
TNC_TNCC_BindFunctionPointer bindFunction);
130
struct tnc_if_imc *imc;
131
unsigned int last_batchid;
134
#define TNC_MAX_IMC_ID 10
135
static struct tnc_if_imc *tnc_imc[TNC_MAX_IMC_ID] = { NULL };
138
/* TNCC functions that IMCs can call */
140
TNC_Result TNC_TNCC_ReportMessageTypes(
142
TNC_MessageTypeList supportedTypes,
143
TNC_UInt32 typeCount)
146
struct tnc_if_imc *imc;
148
wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_ReportMessageTypes(imcID=%lu "
150
(unsigned long) imcID, (unsigned long) typeCount);
152
for (i = 0; i < typeCount; i++) {
153
wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
154
i, supportedTypes[i]);
157
if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
158
return TNC_RESULT_INVALID_PARAMETER;
160
imc = tnc_imc[imcID];
161
os_free(imc->supported_types);
162
imc->supported_types =
163
os_malloc(typeCount * sizeof(TNC_MessageTypeList));
164
if (imc->supported_types == NULL)
165
return TNC_RESULT_FATAL;
166
os_memcpy(imc->supported_types, supportedTypes,
167
typeCount * sizeof(TNC_MessageTypeList));
168
imc->num_supported_types = typeCount;
170
return TNC_RESULT_SUCCESS;
174
TNC_Result TNC_TNCC_SendMessage(
176
TNC_ConnectionID connectionID,
177
TNC_BufferReference message,
178
TNC_UInt32 messageLength,
179
TNC_MessageType messageType)
181
struct tnc_if_imc *imc;
185
wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage(imcID=%lu "
186
"connectionID=%lu messageType=%lu)",
187
imcID, connectionID, messageType);
188
wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCC_SendMessage",
189
message, messageLength);
191
if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
192
return TNC_RESULT_INVALID_PARAMETER;
194
b64 = base64_encode(message, messageLength, &b64len);
196
return TNC_RESULT_FATAL;
198
imc = tnc_imc[imcID];
199
os_free(imc->imc_send);
200
imc->imc_send_len = 0;
201
imc->imc_send = os_zalloc(b64len + 100);
202
if (imc->imc_send == NULL) {
204
return TNC_RESULT_OTHER;
208
os_snprintf((char *) imc->imc_send, b64len + 100,
209
"<IMC-IMV-Message><Type>%08X</Type>"
210
"<Base64>%s</Base64></IMC-IMV-Message>",
211
(unsigned int) messageType, b64);
215
return TNC_RESULT_SUCCESS;
219
TNC_Result TNC_TNCC_RequestHandshakeRetry(
221
TNC_ConnectionID connectionID,
222
TNC_RetryReason reason)
224
wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_RequestHandshakeRetry");
226
if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
227
return TNC_RESULT_INVALID_PARAMETER;
230
* TODO: trigger a call to eapol_sm_request_reauth(). This would
231
* require that the IMC continues to be loaded in memory afer
235
return TNC_RESULT_SUCCESS;
239
TNC_Result TNC_9048_LogMessage(TNC_IMCID imcID, TNC_UInt32 severity,
242
wpa_printf(MSG_DEBUG, "TNC: TNC_9048_LogMessage(imcID=%lu "
243
"severity==%lu message='%s')",
244
imcID, severity, message);
245
return TNC_RESULT_SUCCESS;
249
TNC_Result TNC_9048_UserMessage(TNC_IMCID imcID, TNC_ConnectionID connectionID,
252
wpa_printf(MSG_DEBUG, "TNC: TNC_9048_UserMessage(imcID=%lu "
253
"connectionID==%lu message='%s')",
254
imcID, connectionID, message);
255
return TNC_RESULT_SUCCESS;
259
TNC_Result TNC_TNCC_BindFunction(
262
void **pOutfunctionPointer)
264
wpa_printf(MSG_DEBUG, "TNC: TNC_TNCC_BindFunction(imcID=%lu, "
265
"functionName='%s')", (unsigned long) imcID, functionName);
267
if (imcID >= TNC_MAX_IMC_ID || tnc_imc[imcID] == NULL)
268
return TNC_RESULT_INVALID_PARAMETER;
270
if (pOutfunctionPointer == NULL)
271
return TNC_RESULT_INVALID_PARAMETER;
273
if (os_strcmp(functionName, "TNC_TNCC_ReportMessageTypes") == 0)
274
*pOutfunctionPointer = TNC_TNCC_ReportMessageTypes;
275
else if (os_strcmp(functionName, "TNC_TNCC_SendMessage") == 0)
276
*pOutfunctionPointer = TNC_TNCC_SendMessage;
277
else if (os_strcmp(functionName, "TNC_TNCC_RequestHandshakeRetry") ==
279
*pOutfunctionPointer = TNC_TNCC_RequestHandshakeRetry;
280
else if (os_strcmp(functionName, "TNC_9048_LogMessage") == 0)
281
*pOutfunctionPointer = TNC_9048_LogMessage;
282
else if (os_strcmp(functionName, "TNC_9048_UserMessage") == 0)
283
*pOutfunctionPointer = TNC_9048_UserMessage;
285
*pOutfunctionPointer = NULL;
287
return TNC_RESULT_SUCCESS;
291
static void * tncc_get_sym(void *handle, char *func)
295
#ifdef CONFIG_NATIVE_WINDOWS
297
fptr = GetProcAddressA(handle, func);
298
#else /* _WIN32_WCE */
299
fptr = GetProcAddress(handle, func);
300
#endif /* _WIN32_WCE */
301
#else /* CONFIG_NATIVE_WINDOWS */
302
fptr = dlsym(handle, func);
303
#endif /* CONFIG_NATIVE_WINDOWS */
309
static int tncc_imc_resolve_funcs(struct tnc_if_imc *imc)
311
void *handle = imc->dlhandle;
313
/* Mandatory IMC functions */
314
imc->Initialize = tncc_get_sym(handle, "TNC_IMC_Initialize");
315
if (imc->Initialize == NULL) {
316
wpa_printf(MSG_ERROR, "TNC: IMC does not export "
317
"TNC_IMC_Initialize");
321
imc->BeginHandshake = tncc_get_sym(handle, "TNC_IMC_BeginHandshake");
322
if (imc->BeginHandshake == NULL) {
323
wpa_printf(MSG_ERROR, "TNC: IMC does not export "
324
"TNC_IMC_BeginHandshake");
328
imc->ProvideBindFunction =
329
tncc_get_sym(handle, "TNC_IMC_ProvideBindFunction");
330
if (imc->ProvideBindFunction == NULL) {
331
wpa_printf(MSG_ERROR, "TNC: IMC does not export "
332
"TNC_IMC_ProvideBindFunction");
336
/* Optional IMC functions */
337
imc->NotifyConnectionChange =
338
tncc_get_sym(handle, "TNC_IMC_NotifyConnectionChange");
339
imc->ReceiveMessage = tncc_get_sym(handle, "TNC_IMC_ReceiveMessage");
340
imc->BatchEnding = tncc_get_sym(handle, "TNC_IMC_BatchEnding");
341
imc->Terminate = tncc_get_sym(handle, "TNC_IMC_Terminate");
347
static int tncc_imc_initialize(struct tnc_if_imc *imc)
352
wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Initialize for IMC '%s'",
354
res = imc->Initialize(imc->imcID, TNC_IFIMC_VERSION_1,
355
TNC_IFIMC_VERSION_1, &imc_ver);
356
wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Initialize: res=%lu imc_ver=%lu",
357
(unsigned long) res, (unsigned long) imc_ver);
359
return res == TNC_RESULT_SUCCESS ? 0 : -1;
363
static int tncc_imc_terminate(struct tnc_if_imc *imc)
367
if (imc->Terminate == NULL)
370
wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_Terminate for IMC '%s'",
372
res = imc->Terminate(imc->imcID);
373
wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_Terminate: %lu",
374
(unsigned long) res);
376
return res == TNC_RESULT_SUCCESS ? 0 : -1;
380
static int tncc_imc_provide_bind_function(struct tnc_if_imc *imc)
384
wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_ProvideBindFunction for "
385
"IMC '%s'", imc->name);
386
res = imc->ProvideBindFunction(imc->imcID, TNC_TNCC_BindFunction);
387
wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_ProvideBindFunction: res=%lu",
388
(unsigned long) res);
390
return res == TNC_RESULT_SUCCESS ? 0 : -1;
394
static int tncc_imc_notify_connection_change(struct tnc_if_imc *imc,
395
TNC_ConnectionState state)
399
if (imc->NotifyConnectionChange == NULL)
402
wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_NotifyConnectionChange(%d)"
403
" for IMC '%s'", (int) state, imc->name);
404
res = imc->NotifyConnectionChange(imc->imcID, imc->connectionID,
406
wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
407
(unsigned long) res);
409
return res == TNC_RESULT_SUCCESS ? 0 : -1;
413
static int tncc_imc_begin_handshake(struct tnc_if_imc *imc)
417
wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMC_BeginHandshake for IMC "
419
res = imc->BeginHandshake(imc->imcID, imc->connectionID);
420
wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_BeginHandshake: %lu",
421
(unsigned long) res);
423
return res == TNC_RESULT_SUCCESS ? 0 : -1;
427
static int tncc_load_imc(struct tnc_if_imc *imc)
429
if (imc->path == NULL) {
430
wpa_printf(MSG_DEBUG, "TNC: No IMC configured");
434
wpa_printf(MSG_DEBUG, "TNC: Opening IMC: %s (%s)",
435
imc->name, imc->path);
436
#ifdef CONFIG_NATIVE_WINDOWS
439
TCHAR *lib = wpa_strdup_tchar(imc->path);
442
imc->dlhandle = LoadLibrary(lib);
446
imc->dlhandle = LoadLibrary(imc->path);
448
if (imc->dlhandle == NULL) {
449
wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %d",
450
imc->name, imc->path, (int) GetLastError());
453
#else /* CONFIG_NATIVE_WINDOWS */
454
imc->dlhandle = dlopen(imc->path, RTLD_LAZY);
455
if (imc->dlhandle == NULL) {
456
wpa_printf(MSG_ERROR, "TNC: Failed to open IMC '%s' (%s): %s",
457
imc->name, imc->path, dlerror());
460
#endif /* CONFIG_NATIVE_WINDOWS */
462
if (tncc_imc_resolve_funcs(imc) < 0) {
463
wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMC functions");
467
if (tncc_imc_initialize(imc) < 0 ||
468
tncc_imc_provide_bind_function(imc) < 0) {
469
wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMC");
477
static void tncc_unload_imc(struct tnc_if_imc *imc)
479
tncc_imc_terminate(imc);
480
tnc_imc[imc->imcID] = NULL;
483
#ifdef CONFIG_NATIVE_WINDOWS
484
FreeLibrary(imc->dlhandle);
485
#else /* CONFIG_NATIVE_WINDOWS */
486
dlclose(imc->dlhandle);
487
#endif /* CONFIG_NATIVE_WINDOWS */
491
os_free(imc->supported_types);
492
os_free(imc->imc_send);
496
static int tncc_supported_type(struct tnc_if_imc *imc, unsigned int type)
499
unsigned int vendor, subtype;
501
if (imc == NULL || imc->supported_types == NULL)
505
subtype = type & 0xff;
507
for (i = 0; i < imc->num_supported_types; i++) {
508
unsigned int svendor, ssubtype;
509
svendor = imc->supported_types[i] >> 8;
510
ssubtype = imc->supported_types[i] & 0xff;
511
if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
512
(subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
520
static void tncc_send_to_imcs(struct tncc_data *tncc, unsigned int type,
521
const u8 *msg, size_t len)
523
struct tnc_if_imc *imc;
526
wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMC(s)", msg, len);
528
for (imc = tncc->imc; imc; imc = imc->next) {
529
if (imc->ReceiveMessage == NULL ||
530
!tncc_supported_type(imc, type))
533
wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMC '%s'",
535
res = imc->ReceiveMessage(imc->imcID, imc->connectionID,
536
(TNC_BufferReference) msg, len,
538
wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
539
(unsigned long) res);
544
void tncc_init_connection(struct tncc_data *tncc)
546
struct tnc_if_imc *imc;
548
for (imc = tncc->imc; imc; imc = imc->next) {
549
tncc_imc_notify_connection_change(
550
imc, TNC_CONNECTION_STATE_CREATE);
551
tncc_imc_notify_connection_change(
552
imc, TNC_CONNECTION_STATE_HANDSHAKE);
554
os_free(imc->imc_send);
555
imc->imc_send = NULL;
556
imc->imc_send_len = 0;
558
tncc_imc_begin_handshake(imc);
563
size_t tncc_total_send_len(struct tncc_data *tncc)
565
struct tnc_if_imc *imc;
568
for (imc = tncc->imc; imc; imc = imc->next)
569
len += imc->imc_send_len;
574
u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos)
576
struct tnc_if_imc *imc;
578
for (imc = tncc->imc; imc; imc = imc->next) {
579
if (imc->imc_send == NULL)
582
os_memcpy(pos, imc->imc_send, imc->imc_send_len);
583
pos += imc->imc_send_len;
584
os_free(imc->imc_send);
585
imc->imc_send = NULL;
586
imc->imc_send_len = 0;
593
char * tncc_if_tnccs_start(struct tncc_data *tncc)
595
char *buf = os_malloc(1000);
598
tncc->last_batchid++;
599
os_snprintf(buf, 1000, IF_TNCCS_START, tncc->last_batchid);
604
char * tncc_if_tnccs_end(void)
606
char *buf = os_malloc(100);
609
os_snprintf(buf, 100, IF_TNCCS_END);
614
int tncc_process_if_tnccs(struct tncc_data *tncc, const u8 *msg, size_t len)
616
char *buf, *start, *end, *pos, *pos2;
617
unsigned int batch_id;
618
unsigned char *decoded;
621
buf = os_malloc(len + 1);
625
os_memcpy(buf, msg, len);
627
start = os_strstr(buf, "<TNCCS-Batch ");
628
end = os_strstr(buf, "</TNCCS-Batch>");
629
if (start == NULL || end == NULL || start > end) {
635
while (*start == ' ')
639
pos = os_strstr(start, "BatchId=");
648
batch_id = atoi(pos);
649
wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
651
if (batch_id != tncc->last_batchid + 1) {
652
wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
654
batch_id, tncc->last_batchid + 1);
658
tncc->last_batchid = batch_id;
662
* <Type>01234567</Type>
663
* <Base64>foo==</Base64>
670
pos = os_strstr(start, "<IMC-IMV-Message>");
674
end = os_strstr(start, "</IMC-IMV-Message>");
680
pos = os_strstr(start, "<Type>");
690
wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
692
pos = os_strstr(start, "<Base64>");
699
pos2 = os_strstr(pos, "</Base64>");
706
decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
708
if (decoded == NULL) {
709
wpa_printf(MSG_DEBUG, "TNC: Failed to decode "
710
"IMC-IMV-Message Base64 data");
715
tncc_send_to_imcs(tncc, type, decoded, decoded_len);
728
#ifdef CONFIG_NATIVE_WINDOWS
729
static int tncc_read_config_reg(struct tncc_data *tncc, HKEY hive)
734
struct tnc_if_imc *imc, *last;
738
while (last && last->next)
741
ret = RegOpenKeyEx(hive, TNC_WINREG_PATH, 0, KEY_ENUMERATE_SUB_KEYS,
743
if (ret != ERROR_SUCCESS)
747
TCHAR name[255], *val;
748
DWORD namelen, buflen;
751
ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
754
if (ret == ERROR_NO_MORE_ITEMS)
757
if (ret != ERROR_SUCCESS) {
758
wpa_printf(MSG_DEBUG, "TNC: RegEnumKeyEx failed: 0x%x",
765
name[namelen] = '\0';
767
wpa_printf(MSG_DEBUG, "TNC: IMC '" TSTR "'", name);
769
ret = RegOpenKeyEx(hk, name, 0, KEY_QUERY_VALUE, &hk2);
770
if (ret != ERROR_SUCCESS) {
771
wpa_printf(MSG_DEBUG, "Could not open IMC key '" TSTR
776
ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL, NULL,
778
if (ret != ERROR_SUCCESS) {
779
wpa_printf(MSG_DEBUG, "TNC: Could not read Path from "
780
"IMC key '" TSTR "'", name);
785
val = os_malloc(buflen);
791
ret = RegQueryValueEx(hk2, TEXT("Path"), NULL, NULL,
792
(LPBYTE) val, &buflen);
793
if (ret != ERROR_SUCCESS) {
801
wpa_unicode2ascii_inplace(val);
802
wpa_printf(MSG_DEBUG, "TNC: IMC Path '%s'", (char *) val);
804
for (j = 0; j < TNC_MAX_IMC_ID; j++) {
805
if (tnc_imc[j] == NULL)
808
if (j >= TNC_MAX_IMC_ID) {
809
wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
814
imc = os_zalloc(sizeof(*imc));
822
wpa_unicode2ascii_inplace(name);
823
imc->name = os_strdup((char *) name);
824
imc->path = os_strdup((char *) val);
834
tnc_imc[imc->imcID] = imc;
843
static int tncc_read_config(struct tncc_data *tncc)
845
if (tncc_read_config_reg(tncc, HKEY_LOCAL_MACHINE) < 0 ||
846
tncc_read_config_reg(tncc, HKEY_CURRENT_USER) < 0)
851
#else /* CONFIG_NATIVE_WINDOWS */
853
static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
855
struct tnc_if_imc *imc;
859
for (i = 0; i < TNC_MAX_IMC_ID; i++) {
860
if (tnc_imc[i] == NULL)
863
if (i >= TNC_MAX_IMC_ID) {
864
wpa_printf(MSG_DEBUG, "TNC: Too many IMCs");
868
imc = os_zalloc(sizeof(*imc));
877
wpa_printf(MSG_DEBUG, "TNC: Configured IMC: %s", pos);
878
if (pos + 1 >= end || *pos != '"') {
879
wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
880
"(no starting quotation mark)", start);
887
while (pos2 < end && *pos2 != '"')
890
wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
891
"(no ending quotation mark)", start);
896
wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
897
imc->name = os_strdup(pos);
900
if (pos >= end || *pos != ' ') {
901
wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
902
"(no space after name)", start);
908
wpa_printf(MSG_DEBUG, "TNC: IMC file: '%s'", pos);
909
imc->path = os_strdup(pos);
910
tnc_imc[imc->imcID] = imc;
916
static int tncc_read_config(struct tncc_data *tncc)
918
char *config, *end, *pos, *line_end;
920
struct tnc_if_imc *imc, *last;
924
config = os_readfile(TNC_CONFIG_FILE, &config_len);
925
if (config == NULL) {
926
wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
927
"file '%s'", TNC_CONFIG_FILE);
931
end = config + config_len;
932
for (pos = config; pos < end; pos = line_end + 1) {
934
while (*line_end != '\n' && *line_end != '\r' &&
939
if (os_strncmp(pos, "IMC ", 4) == 0) {
942
imc = tncc_parse_imc(pos + 4, line_end, &error);
960
#endif /* CONFIG_NATIVE_WINDOWS */
963
struct tncc_data * tncc_init(void)
965
struct tncc_data *tncc;
966
struct tnc_if_imc *imc;
968
tncc = os_zalloc(sizeof(*tncc));
973
* move loading and Initialize() to a location that is not
974
* re-initialized for every EAP-TNC session (?)
977
if (tncc_read_config(tncc) < 0) {
978
wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
982
for (imc = tncc->imc; imc; imc = imc->next) {
983
if (tncc_load_imc(imc)) {
984
wpa_printf(MSG_ERROR, "TNC: Failed to load IMC '%s'",
998
void tncc_deinit(struct tncc_data *tncc)
1000
struct tnc_if_imc *imc, *prev;
1004
tncc_unload_imc(imc);