Branch data Line data Source code
1 : : /*
2 : : * EAP-TNC - TNCS (IF-IMV, IF-TNCCS, and IF-TNCCS-SOH)
3 : : * Copyright (c) 2007-2008, Jouni Malinen <j@w1.fi>
4 : : *
5 : : * This software may be distributed under the terms of the BSD license.
6 : : * See README for more details.
7 : : */
8 : :
9 : : #include "includes.h"
10 : : #include <dlfcn.h>
11 : :
12 : : #include "common.h"
13 : : #include "base64.h"
14 : : #include "tncs.h"
15 : : #include "eap_common/eap_tlv_common.h"
16 : : #include "eap_common/eap_defs.h"
17 : :
18 : :
19 : : /* TODO: TNCS must be thread-safe; review the code and add locking etc. if
20 : : * needed.. */
21 : :
22 : : #define TNC_CONFIG_FILE "/etc/tnc_config"
23 : : #define IF_TNCCS_START \
24 : : "<?xml version=\"1.0\"?>\n" \
25 : : "<TNCCS-Batch BatchId=\"%d\" Recipient=\"TNCS\" " \
26 : : "xmlns=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/IF_TNCCS#\" " \
27 : : "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " \
28 : : "xsi:schemaLocation=\"http://www.trustedcomputinggroup.org/IWG/TNC/1_0/" \
29 : : "IF_TNCCS# https://www.trustedcomputinggroup.org/XML/SCHEMA/TNCCS_1.0.xsd\">\n"
30 : : #define IF_TNCCS_END "\n</TNCCS-Batch>"
31 : :
32 : : /* TNC IF-IMV */
33 : :
34 : : typedef unsigned long TNC_UInt32;
35 : : typedef unsigned char *TNC_BufferReference;
36 : :
37 : : typedef TNC_UInt32 TNC_IMVID;
38 : : typedef TNC_UInt32 TNC_ConnectionID;
39 : : typedef TNC_UInt32 TNC_ConnectionState;
40 : : typedef TNC_UInt32 TNC_RetryReason;
41 : : typedef TNC_UInt32 TNC_IMV_Action_Recommendation;
42 : : typedef TNC_UInt32 TNC_IMV_Evaluation_Result;
43 : : typedef TNC_UInt32 TNC_MessageType;
44 : : typedef TNC_MessageType *TNC_MessageTypeList;
45 : : typedef TNC_UInt32 TNC_VendorID;
46 : : typedef TNC_UInt32 TNC_Subtype;
47 : : typedef TNC_UInt32 TNC_Version;
48 : : typedef TNC_UInt32 TNC_Result;
49 : : typedef TNC_UInt32 TNC_AttributeID;
50 : :
51 : : typedef TNC_Result (*TNC_TNCS_BindFunctionPointer)(
52 : : TNC_IMVID imvID,
53 : : char *functionName,
54 : : void **pOutfunctionPointer);
55 : :
56 : : #define TNC_RESULT_SUCCESS 0
57 : : #define TNC_RESULT_NOT_INITIALIZED 1
58 : : #define TNC_RESULT_ALREADY_INITIALIZED 2
59 : : #define TNC_RESULT_NO_COMMON_VERSION 3
60 : : #define TNC_RESULT_CANT_RETRY 4
61 : : #define TNC_RESULT_WONT_RETRY 5
62 : : #define TNC_RESULT_INVALID_PARAMETER 6
63 : : #define TNC_RESULT_CANT_RESPOND 7
64 : : #define TNC_RESULT_ILLEGAL_OPERATION 8
65 : : #define TNC_RESULT_OTHER 9
66 : : #define TNC_RESULT_FATAL 10
67 : :
68 : : #define TNC_CONNECTION_STATE_CREATE 0
69 : : #define TNC_CONNECTION_STATE_HANDSHAKE 1
70 : : #define TNC_CONNECTION_STATE_ACCESS_ALLOWED 2
71 : : #define TNC_CONNECTION_STATE_ACCESS_ISOLATED 3
72 : : #define TNC_CONNECTION_STATE_ACCESS_NONE 4
73 : : #define TNC_CONNECTION_STATE_DELETE 5
74 : :
75 : : #define TNC_IFIMV_VERSION_1 1
76 : :
77 : : #define TNC_VENDORID_ANY ((TNC_VendorID) 0xffffff)
78 : : #define TNC_SUBTYPE_ANY ((TNC_Subtype) 0xff)
79 : :
80 : : /* TNCC-TNCS Message Types */
81 : : #define TNC_TNCCS_RECOMMENDATION 0x00000001
82 : : #define TNC_TNCCS_ERROR 0x00000002
83 : : #define TNC_TNCCS_PREFERREDLANGUAGE 0x00000003
84 : : #define TNC_TNCCS_REASONSTRINGS 0x00000004
85 : :
86 : : /* Possible TNC_IMV_Action_Recommendation values: */
87 : : enum IMV_Action_Recommendation {
88 : : TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
89 : : TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS,
90 : : TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
91 : : TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
92 : : };
93 : :
94 : : /* Possible TNC_IMV_Evaluation_Result values: */
95 : : enum IMV_Evaluation_Result {
96 : : TNC_IMV_EVALUATION_RESULT_COMPLIANT,
97 : : TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR,
98 : : TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR,
99 : : TNC_IMV_EVALUATION_RESULT_ERROR,
100 : : TNC_IMV_EVALUATION_RESULT_DONT_KNOW
101 : : };
102 : :
103 : : struct tnc_if_imv {
104 : : struct tnc_if_imv *next;
105 : : char *name;
106 : : char *path;
107 : : void *dlhandle; /* from dlopen() */
108 : : TNC_IMVID imvID;
109 : : TNC_MessageTypeList supported_types;
110 : : size_t num_supported_types;
111 : :
112 : : /* Functions implemented by IMVs (with TNC_IMV_ prefix) */
113 : : TNC_Result (*Initialize)(
114 : : TNC_IMVID imvID,
115 : : TNC_Version minVersion,
116 : : TNC_Version maxVersion,
117 : : TNC_Version *pOutActualVersion);
118 : : TNC_Result (*NotifyConnectionChange)(
119 : : TNC_IMVID imvID,
120 : : TNC_ConnectionID connectionID,
121 : : TNC_ConnectionState newState);
122 : : TNC_Result (*ReceiveMessage)(
123 : : TNC_IMVID imvID,
124 : : TNC_ConnectionID connectionID,
125 : : TNC_BufferReference message,
126 : : TNC_UInt32 messageLength,
127 : : TNC_MessageType messageType);
128 : : TNC_Result (*SolicitRecommendation)(
129 : : TNC_IMVID imvID,
130 : : TNC_ConnectionID connectionID);
131 : : TNC_Result (*BatchEnding)(
132 : : TNC_IMVID imvID,
133 : : TNC_ConnectionID connectionID);
134 : : TNC_Result (*Terminate)(TNC_IMVID imvID);
135 : : TNC_Result (*ProvideBindFunction)(
136 : : TNC_IMVID imvID,
137 : : TNC_TNCS_BindFunctionPointer bindFunction);
138 : : };
139 : :
140 : :
141 : : #define TNC_MAX_IMV_ID 10
142 : :
143 : : struct tncs_data {
144 : : struct tncs_data *next;
145 : : struct tnc_if_imv *imv; /* local copy of tncs_global_data->imv */
146 : : TNC_ConnectionID connectionID;
147 : : unsigned int last_batchid;
148 : : enum IMV_Action_Recommendation recommendation;
149 : : int done;
150 : :
151 : : struct conn_imv {
152 : : u8 *imv_send;
153 : : size_t imv_send_len;
154 : : enum IMV_Action_Recommendation recommendation;
155 : : int recommendation_set;
156 : : } imv_data[TNC_MAX_IMV_ID];
157 : :
158 : : char *tncs_message;
159 : : };
160 : :
161 : :
162 : : struct tncs_global {
163 : : struct tnc_if_imv *imv;
164 : : TNC_ConnectionID next_conn_id;
165 : : struct tncs_data *connections;
166 : : };
167 : :
168 : : static struct tncs_global *tncs_global_data = NULL;
169 : :
170 : :
171 : 0 : static struct tnc_if_imv * tncs_get_imv(TNC_IMVID imvID)
172 : : {
173 : : struct tnc_if_imv *imv;
174 : :
175 [ # # ][ # # ]: 0 : if (imvID >= TNC_MAX_IMV_ID || tncs_global_data == NULL)
176 : 0 : return NULL;
177 : 0 : imv = tncs_global_data->imv;
178 [ # # ]: 0 : while (imv) {
179 [ # # ]: 0 : if (imv->imvID == imvID)
180 : 0 : return imv;
181 : 0 : imv = imv->next;
182 : : }
183 : 0 : return NULL;
184 : : }
185 : :
186 : :
187 : 0 : static struct tncs_data * tncs_get_conn(TNC_ConnectionID connectionID)
188 : : {
189 : : struct tncs_data *tncs;
190 : :
191 [ # # ]: 0 : if (tncs_global_data == NULL)
192 : 0 : return NULL;
193 : :
194 : 0 : tncs = tncs_global_data->connections;
195 [ # # ]: 0 : while (tncs) {
196 [ # # ]: 0 : if (tncs->connectionID == connectionID)
197 : 0 : return tncs;
198 : 0 : tncs = tncs->next;
199 : : }
200 : :
201 : 0 : wpa_printf(MSG_DEBUG, "TNC: Connection ID %lu not found",
202 : : (unsigned long) connectionID);
203 : :
204 : 0 : return NULL;
205 : : }
206 : :
207 : :
208 : : /* TNCS functions that IMVs can call */
209 : 0 : TNC_Result TNC_TNCS_ReportMessageTypes(
210 : : TNC_IMVID imvID,
211 : : TNC_MessageTypeList supportedTypes,
212 : : TNC_UInt32 typeCount)
213 : : {
214 : : TNC_UInt32 i;
215 : : struct tnc_if_imv *imv;
216 : :
217 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ReportMessageTypes(imvID=%lu "
218 : : "typeCount=%lu)",
219 : : (unsigned long) imvID, (unsigned long) typeCount);
220 : :
221 [ # # ]: 0 : for (i = 0; i < typeCount; i++) {
222 : 0 : wpa_printf(MSG_DEBUG, "TNC: supportedTypes[%lu] = %lu",
223 : 0 : i, supportedTypes[i]);
224 : : }
225 : :
226 : 0 : imv = tncs_get_imv(imvID);
227 [ # # ]: 0 : if (imv == NULL)
228 : 0 : return TNC_RESULT_INVALID_PARAMETER;
229 : 0 : os_free(imv->supported_types);
230 : 0 : imv->supported_types =
231 : 0 : os_malloc(typeCount * sizeof(TNC_MessageType));
232 [ # # ]: 0 : if (imv->supported_types == NULL)
233 : 0 : return TNC_RESULT_FATAL;
234 : 0 : os_memcpy(imv->supported_types, supportedTypes,
235 : : typeCount * sizeof(TNC_MessageType));
236 : 0 : imv->num_supported_types = typeCount;
237 : :
238 : 0 : return TNC_RESULT_SUCCESS;
239 : : }
240 : :
241 : :
242 : 0 : TNC_Result TNC_TNCS_SendMessage(
243 : : TNC_IMVID imvID,
244 : : TNC_ConnectionID connectionID,
245 : : TNC_BufferReference message,
246 : : TNC_UInt32 messageLength,
247 : : TNC_MessageType messageType)
248 : : {
249 : : struct tncs_data *tncs;
250 : : unsigned char *b64;
251 : : size_t b64len;
252 : :
253 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage(imvID=%lu "
254 : : "connectionID=%lu messageType=%lu)",
255 : : imvID, connectionID, messageType);
256 : 0 : wpa_hexdump_ascii(MSG_DEBUG, "TNC: TNC_TNCS_SendMessage",
257 : : message, messageLength);
258 : :
259 [ # # ]: 0 : if (tncs_get_imv(imvID) == NULL)
260 : 0 : return TNC_RESULT_INVALID_PARAMETER;
261 : :
262 : 0 : tncs = tncs_get_conn(connectionID);
263 [ # # ]: 0 : if (tncs == NULL)
264 : 0 : return TNC_RESULT_INVALID_PARAMETER;
265 : :
266 : 0 : b64 = base64_encode(message, messageLength, &b64len);
267 [ # # ]: 0 : if (b64 == NULL)
268 : 0 : return TNC_RESULT_FATAL;
269 : :
270 : 0 : os_free(tncs->imv_data[imvID].imv_send);
271 : 0 : tncs->imv_data[imvID].imv_send_len = 0;
272 : 0 : tncs->imv_data[imvID].imv_send = os_zalloc(b64len + 100);
273 [ # # ]: 0 : if (tncs->imv_data[imvID].imv_send == NULL) {
274 : 0 : os_free(b64);
275 : 0 : return TNC_RESULT_OTHER;
276 : : }
277 : :
278 : 0 : tncs->imv_data[imvID].imv_send_len =
279 : 0 : os_snprintf((char *) tncs->imv_data[imvID].imv_send,
280 : : b64len + 100,
281 : : "<IMC-IMV-Message><Type>%08X</Type>"
282 : : "<Base64>%s</Base64></IMC-IMV-Message>",
283 : : (unsigned int) messageType, b64);
284 : :
285 : 0 : os_free(b64);
286 : :
287 : 0 : return TNC_RESULT_SUCCESS;
288 : : }
289 : :
290 : :
291 : 0 : TNC_Result TNC_TNCS_RequestHandshakeRetry(
292 : : TNC_IMVID imvID,
293 : : TNC_ConnectionID connectionID,
294 : : TNC_RetryReason reason)
295 : : {
296 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_RequestHandshakeRetry");
297 : : /* TODO */
298 : 0 : return TNC_RESULT_SUCCESS;
299 : : }
300 : :
301 : :
302 : 0 : TNC_Result TNC_TNCS_ProvideRecommendation(
303 : : TNC_IMVID imvID,
304 : : TNC_ConnectionID connectionID,
305 : : TNC_IMV_Action_Recommendation recommendation,
306 : : TNC_IMV_Evaluation_Result evaluation)
307 : : {
308 : : struct tncs_data *tncs;
309 : :
310 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_ProvideRecommendation(imvID=%lu "
311 : : "connectionID=%lu recommendation=%lu evaluation=%lu)",
312 : : (unsigned long) imvID, (unsigned long) connectionID,
313 : : (unsigned long) recommendation, (unsigned long) evaluation);
314 : :
315 [ # # ]: 0 : if (tncs_get_imv(imvID) == NULL)
316 : 0 : return TNC_RESULT_INVALID_PARAMETER;
317 : :
318 : 0 : tncs = tncs_get_conn(connectionID);
319 [ # # ]: 0 : if (tncs == NULL)
320 : 0 : return TNC_RESULT_INVALID_PARAMETER;
321 : :
322 : 0 : tncs->imv_data[imvID].recommendation = recommendation;
323 : 0 : tncs->imv_data[imvID].recommendation_set = 1;
324 : :
325 : 0 : return TNC_RESULT_SUCCESS;
326 : : }
327 : :
328 : :
329 : 0 : TNC_Result TNC_TNCS_GetAttribute(
330 : : TNC_IMVID imvID,
331 : : TNC_ConnectionID connectionID,
332 : : TNC_AttributeID attribureID,
333 : : TNC_UInt32 bufferLength,
334 : : TNC_BufferReference buffer,
335 : : TNC_UInt32 *pOutValueLength)
336 : : {
337 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_GetAttribute");
338 : : /* TODO */
339 : 0 : return TNC_RESULT_SUCCESS;
340 : : }
341 : :
342 : :
343 : 0 : TNC_Result TNC_TNCS_SetAttribute(
344 : : TNC_IMVID imvID,
345 : : TNC_ConnectionID connectionID,
346 : : TNC_AttributeID attribureID,
347 : : TNC_UInt32 bufferLength,
348 : : TNC_BufferReference buffer)
349 : : {
350 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_SetAttribute");
351 : : /* TODO */
352 : 0 : return TNC_RESULT_SUCCESS;
353 : : }
354 : :
355 : :
356 : 0 : TNC_Result TNC_TNCS_BindFunction(
357 : : TNC_IMVID imvID,
358 : : char *functionName,
359 : : void **pOutFunctionPointer)
360 : : {
361 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_TNCS_BindFunction(imcID=%lu, "
362 : : "functionName='%s')", (unsigned long) imvID, functionName);
363 : :
364 [ # # ]: 0 : if (tncs_get_imv(imvID) == NULL)
365 : 0 : return TNC_RESULT_INVALID_PARAMETER;
366 : :
367 [ # # ]: 0 : if (pOutFunctionPointer == NULL)
368 : 0 : return TNC_RESULT_INVALID_PARAMETER;
369 : :
370 [ # # ]: 0 : if (os_strcmp(functionName, "TNC_TNCS_ReportMessageTypes") == 0)
371 : 0 : *pOutFunctionPointer = TNC_TNCS_ReportMessageTypes;
372 [ # # ]: 0 : else if (os_strcmp(functionName, "TNC_TNCS_SendMessage") == 0)
373 : 0 : *pOutFunctionPointer = TNC_TNCS_SendMessage;
374 [ # # ]: 0 : else if (os_strcmp(functionName, "TNC_TNCS_RequestHandshakeRetry") ==
375 : : 0)
376 : 0 : *pOutFunctionPointer = TNC_TNCS_RequestHandshakeRetry;
377 [ # # ]: 0 : else if (os_strcmp(functionName, "TNC_TNCS_ProvideRecommendation") ==
378 : : 0)
379 : 0 : *pOutFunctionPointer = TNC_TNCS_ProvideRecommendation;
380 [ # # ]: 0 : else if (os_strcmp(functionName, "TNC_TNCS_GetAttribute") == 0)
381 : 0 : *pOutFunctionPointer = TNC_TNCS_GetAttribute;
382 [ # # ]: 0 : else if (os_strcmp(functionName, "TNC_TNCS_SetAttribute") == 0)
383 : 0 : *pOutFunctionPointer = TNC_TNCS_SetAttribute;
384 : : else
385 : 0 : *pOutFunctionPointer = NULL;
386 : :
387 : 0 : return TNC_RESULT_SUCCESS;
388 : : }
389 : :
390 : :
391 : 0 : static void * tncs_get_sym(void *handle, char *func)
392 : : {
393 : : void *fptr;
394 : :
395 : 0 : fptr = dlsym(handle, func);
396 : :
397 : 0 : return fptr;
398 : : }
399 : :
400 : :
401 : 0 : static int tncs_imv_resolve_funcs(struct tnc_if_imv *imv)
402 : : {
403 : 0 : void *handle = imv->dlhandle;
404 : :
405 : : /* Mandatory IMV functions */
406 : 0 : imv->Initialize = tncs_get_sym(handle, "TNC_IMV_Initialize");
407 [ # # ]: 0 : if (imv->Initialize == NULL) {
408 : 0 : wpa_printf(MSG_ERROR, "TNC: IMV does not export "
409 : : "TNC_IMV_Initialize");
410 : 0 : return -1;
411 : : }
412 : :
413 : 0 : imv->SolicitRecommendation = tncs_get_sym(
414 : : handle, "TNC_IMV_SolicitRecommendation");
415 [ # # ]: 0 : if (imv->SolicitRecommendation == NULL) {
416 : 0 : wpa_printf(MSG_ERROR, "TNC: IMV does not export "
417 : : "TNC_IMV_SolicitRecommendation");
418 : 0 : return -1;
419 : : }
420 : :
421 : 0 : imv->ProvideBindFunction =
422 : 0 : tncs_get_sym(handle, "TNC_IMV_ProvideBindFunction");
423 [ # # ]: 0 : if (imv->ProvideBindFunction == NULL) {
424 : 0 : wpa_printf(MSG_ERROR, "TNC: IMV does not export "
425 : : "TNC_IMV_ProvideBindFunction");
426 : 0 : return -1;
427 : : }
428 : :
429 : : /* Optional IMV functions */
430 : 0 : imv->NotifyConnectionChange =
431 : 0 : tncs_get_sym(handle, "TNC_IMV_NotifyConnectionChange");
432 : 0 : imv->ReceiveMessage = tncs_get_sym(handle, "TNC_IMV_ReceiveMessage");
433 : 0 : imv->BatchEnding = tncs_get_sym(handle, "TNC_IMV_BatchEnding");
434 : 0 : imv->Terminate = tncs_get_sym(handle, "TNC_IMV_Terminate");
435 : :
436 : 0 : return 0;
437 : : }
438 : :
439 : :
440 : 0 : static int tncs_imv_initialize(struct tnc_if_imv *imv)
441 : : {
442 : : TNC_Result res;
443 : : TNC_Version imv_ver;
444 : :
445 : 0 : wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Initialize for IMV '%s'",
446 : : imv->name);
447 : 0 : res = imv->Initialize(imv->imvID, TNC_IFIMV_VERSION_1,
448 : : TNC_IFIMV_VERSION_1, &imv_ver);
449 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Initialize: res=%lu imv_ver=%lu",
450 : : (unsigned long) res, (unsigned long) imv_ver);
451 : :
452 [ # # ]: 0 : return res == TNC_RESULT_SUCCESS ? 0 : -1;
453 : : }
454 : :
455 : :
456 : 0 : static int tncs_imv_terminate(struct tnc_if_imv *imv)
457 : : {
458 : : TNC_Result res;
459 : :
460 [ # # ]: 0 : if (imv->Terminate == NULL)
461 : 0 : return 0;
462 : :
463 : 0 : wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_Terminate for IMV '%s'",
464 : : imv->name);
465 : 0 : res = imv->Terminate(imv->imvID);
466 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_Terminate: %lu",
467 : : (unsigned long) res);
468 : :
469 [ # # ]: 0 : return res == TNC_RESULT_SUCCESS ? 0 : -1;
470 : : }
471 : :
472 : :
473 : 0 : static int tncs_imv_provide_bind_function(struct tnc_if_imv *imv)
474 : : {
475 : : TNC_Result res;
476 : :
477 : 0 : wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_ProvideBindFunction for "
478 : : "IMV '%s'", imv->name);
479 : 0 : res = imv->ProvideBindFunction(imv->imvID, TNC_TNCS_BindFunction);
480 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_IMV_ProvideBindFunction: res=%lu",
481 : : (unsigned long) res);
482 : :
483 [ # # ]: 0 : return res == TNC_RESULT_SUCCESS ? 0 : -1;
484 : : }
485 : :
486 : :
487 : 0 : static int tncs_imv_notify_connection_change(struct tnc_if_imv *imv,
488 : : TNC_ConnectionID conn,
489 : : TNC_ConnectionState state)
490 : : {
491 : : TNC_Result res;
492 : :
493 [ # # ]: 0 : if (imv->NotifyConnectionChange == NULL)
494 : 0 : return 0;
495 : :
496 : 0 : wpa_printf(MSG_DEBUG, "TNC: Calling TNC_IMV_NotifyConnectionChange(%d)"
497 : : " for IMV '%s'", (int) state, imv->name);
498 : 0 : res = imv->NotifyConnectionChange(imv->imvID, conn, state);
499 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNC_IMC_NotifyConnectionChange: %lu",
500 : : (unsigned long) res);
501 : :
502 [ # # ]: 0 : return res == TNC_RESULT_SUCCESS ? 0 : -1;
503 : : }
504 : :
505 : :
506 : 0 : static int tncs_load_imv(struct tnc_if_imv *imv)
507 : : {
508 [ # # ]: 0 : if (imv->path == NULL) {
509 : 0 : wpa_printf(MSG_DEBUG, "TNC: No IMV configured");
510 : 0 : return -1;
511 : : }
512 : :
513 : 0 : wpa_printf(MSG_DEBUG, "TNC: Opening IMV: %s (%s)",
514 : : imv->name, imv->path);
515 : 0 : imv->dlhandle = dlopen(imv->path, RTLD_LAZY);
516 [ # # ]: 0 : if (imv->dlhandle == NULL) {
517 : 0 : wpa_printf(MSG_ERROR, "TNC: Failed to open IMV '%s' (%s): %s",
518 : : imv->name, imv->path, dlerror());
519 : 0 : return -1;
520 : : }
521 : :
522 [ # # ]: 0 : if (tncs_imv_resolve_funcs(imv) < 0) {
523 : 0 : wpa_printf(MSG_ERROR, "TNC: Failed to resolve IMV functions");
524 : 0 : return -1;
525 : : }
526 : :
527 [ # # # # ]: 0 : if (tncs_imv_initialize(imv) < 0 ||
528 : 0 : tncs_imv_provide_bind_function(imv) < 0) {
529 : 0 : wpa_printf(MSG_ERROR, "TNC: Failed to initialize IMV");
530 : 0 : return -1;
531 : : }
532 : :
533 : 0 : return 0;
534 : : }
535 : :
536 : :
537 : 0 : static void tncs_free_imv(struct tnc_if_imv *imv)
538 : : {
539 : 0 : os_free(imv->name);
540 : 0 : os_free(imv->path);
541 : 0 : os_free(imv->supported_types);
542 : 0 : }
543 : :
544 : 0 : static void tncs_unload_imv(struct tnc_if_imv *imv)
545 : : {
546 : 0 : tncs_imv_terminate(imv);
547 : :
548 [ # # ]: 0 : if (imv->dlhandle)
549 : 0 : dlclose(imv->dlhandle);
550 : :
551 : 0 : tncs_free_imv(imv);
552 : 0 : }
553 : :
554 : :
555 : 0 : static int tncs_supported_type(struct tnc_if_imv *imv, unsigned int type)
556 : : {
557 : : size_t i;
558 : : unsigned int vendor, subtype;
559 : :
560 [ # # ][ # # ]: 0 : if (imv == NULL || imv->supported_types == NULL)
561 : 0 : return 0;
562 : :
563 : 0 : vendor = type >> 8;
564 : 0 : subtype = type & 0xff;
565 : :
566 [ # # ]: 0 : for (i = 0; i < imv->num_supported_types; i++) {
567 : : unsigned int svendor, ssubtype;
568 : 0 : svendor = imv->supported_types[i] >> 8;
569 : 0 : ssubtype = imv->supported_types[i] & 0xff;
570 [ # # ][ # # ]: 0 : if ((vendor == svendor || svendor == TNC_VENDORID_ANY) &&
[ # # ]
571 [ # # ]: 0 : (subtype == ssubtype || ssubtype == TNC_SUBTYPE_ANY))
572 : 0 : return 1;
573 : : }
574 : :
575 : 0 : return 0;
576 : : }
577 : :
578 : :
579 : 0 : static void tncs_send_to_imvs(struct tncs_data *tncs, unsigned int type,
580 : : const u8 *msg, size_t len)
581 : : {
582 : : struct tnc_if_imv *imv;
583 : : TNC_Result res;
584 : :
585 : 0 : wpa_hexdump_ascii(MSG_MSGDUMP, "TNC: Message to IMV(s)", msg, len);
586 : :
587 [ # # ]: 0 : for (imv = tncs->imv; imv; imv = imv->next) {
588 [ # # # # ]: 0 : if (imv->ReceiveMessage == NULL ||
589 : 0 : !tncs_supported_type(imv, type))
590 : 0 : continue;
591 : :
592 : 0 : wpa_printf(MSG_DEBUG, "TNC: Call ReceiveMessage for IMV '%s'",
593 : : imv->name);
594 : 0 : res = imv->ReceiveMessage(imv->imvID, tncs->connectionID,
595 : : (TNC_BufferReference) msg, len,
596 : : type);
597 : 0 : wpa_printf(MSG_DEBUG, "TNC: ReceiveMessage: %lu",
598 : : (unsigned long) res);
599 : : }
600 : 0 : }
601 : :
602 : :
603 : 0 : static void tncs_batch_ending(struct tncs_data *tncs)
604 : : {
605 : : struct tnc_if_imv *imv;
606 : : TNC_Result res;
607 : :
608 [ # # ]: 0 : for (imv = tncs->imv; imv; imv = imv->next) {
609 [ # # ]: 0 : if (imv->BatchEnding == NULL)
610 : 0 : continue;
611 : :
612 : 0 : wpa_printf(MSG_DEBUG, "TNC: Call BatchEnding for IMV '%s'",
613 : : imv->name);
614 : 0 : res = imv->BatchEnding(imv->imvID, tncs->connectionID);
615 : 0 : wpa_printf(MSG_DEBUG, "TNC: BatchEnding: %lu",
616 : : (unsigned long) res);
617 : : }
618 : 0 : }
619 : :
620 : :
621 : 0 : static void tncs_solicit_recommendation(struct tncs_data *tncs)
622 : : {
623 : : struct tnc_if_imv *imv;
624 : : TNC_Result res;
625 : :
626 [ # # ]: 0 : for (imv = tncs->imv; imv; imv = imv->next) {
627 [ # # ]: 0 : if (tncs->imv_data[imv->imvID].recommendation_set)
628 : 0 : continue;
629 : :
630 : 0 : wpa_printf(MSG_DEBUG, "TNC: Call SolicitRecommendation for "
631 : : "IMV '%s'", imv->name);
632 : 0 : res = imv->SolicitRecommendation(imv->imvID,
633 : : tncs->connectionID);
634 : 0 : wpa_printf(MSG_DEBUG, "TNC: SolicitRecommendation: %lu",
635 : : (unsigned long) res);
636 : : }
637 : 0 : }
638 : :
639 : :
640 : 0 : void tncs_init_connection(struct tncs_data *tncs)
641 : : {
642 : : struct tnc_if_imv *imv;
643 : : int i;
644 : :
645 [ # # ]: 0 : for (imv = tncs->imv; imv; imv = imv->next) {
646 : 0 : tncs_imv_notify_connection_change(
647 : : imv, tncs->connectionID, TNC_CONNECTION_STATE_CREATE);
648 : 0 : tncs_imv_notify_connection_change(
649 : : imv, tncs->connectionID,
650 : : TNC_CONNECTION_STATE_HANDSHAKE);
651 : : }
652 : :
653 [ # # ]: 0 : for (i = 0; i < TNC_MAX_IMV_ID; i++) {
654 : 0 : os_free(tncs->imv_data[i].imv_send);
655 : 0 : tncs->imv_data[i].imv_send = NULL;
656 : 0 : tncs->imv_data[i].imv_send_len = 0;
657 : : }
658 : 0 : }
659 : :
660 : :
661 : 0 : size_t tncs_total_send_len(struct tncs_data *tncs)
662 : : {
663 : : int i;
664 : 0 : size_t len = 0;
665 : :
666 [ # # ]: 0 : for (i = 0; i < TNC_MAX_IMV_ID; i++)
667 : 0 : len += tncs->imv_data[i].imv_send_len;
668 [ # # ]: 0 : if (tncs->tncs_message)
669 : 0 : len += os_strlen(tncs->tncs_message);
670 : 0 : return len;
671 : : }
672 : :
673 : :
674 : 0 : u8 * tncs_copy_send_buf(struct tncs_data *tncs, u8 *pos)
675 : : {
676 : : int i;
677 : :
678 [ # # ]: 0 : for (i = 0; i < TNC_MAX_IMV_ID; i++) {
679 [ # # ]: 0 : if (tncs->imv_data[i].imv_send == NULL)
680 : 0 : continue;
681 : :
682 : 0 : os_memcpy(pos, tncs->imv_data[i].imv_send,
683 : : tncs->imv_data[i].imv_send_len);
684 : 0 : pos += tncs->imv_data[i].imv_send_len;
685 : 0 : os_free(tncs->imv_data[i].imv_send);
686 : 0 : tncs->imv_data[i].imv_send = NULL;
687 : 0 : tncs->imv_data[i].imv_send_len = 0;
688 : : }
689 : :
690 [ # # ]: 0 : if (tncs->tncs_message) {
691 : 0 : size_t len = os_strlen(tncs->tncs_message);
692 : 0 : os_memcpy(pos, tncs->tncs_message, len);
693 : 0 : pos += len;
694 : 0 : os_free(tncs->tncs_message);
695 : 0 : tncs->tncs_message = NULL;
696 : : }
697 : :
698 : 0 : return pos;
699 : : }
700 : :
701 : :
702 : 0 : char * tncs_if_tnccs_start(struct tncs_data *tncs)
703 : : {
704 : 0 : char *buf = os_malloc(1000);
705 [ # # ]: 0 : if (buf == NULL)
706 : 0 : return NULL;
707 : 0 : tncs->last_batchid++;
708 : 0 : os_snprintf(buf, 1000, IF_TNCCS_START, tncs->last_batchid);
709 : 0 : return buf;
710 : : }
711 : :
712 : :
713 : 0 : char * tncs_if_tnccs_end(void)
714 : : {
715 : 0 : char *buf = os_malloc(100);
716 [ # # ]: 0 : if (buf == NULL)
717 : 0 : return NULL;
718 : 0 : os_snprintf(buf, 100, IF_TNCCS_END);
719 : 0 : return buf;
720 : : }
721 : :
722 : :
723 : 0 : static int tncs_get_type(char *start, unsigned int *type)
724 : : {
725 : 0 : char *pos = os_strstr(start, "<Type>");
726 [ # # ]: 0 : if (pos == NULL)
727 : 0 : return -1;
728 : 0 : pos += 6;
729 : 0 : *type = strtoul(pos, NULL, 16);
730 : 0 : return 0;
731 : : }
732 : :
733 : :
734 : 0 : static unsigned char * tncs_get_base64(char *start, size_t *decoded_len)
735 : : {
736 : : char *pos, *pos2;
737 : : unsigned char *decoded;
738 : :
739 : 0 : pos = os_strstr(start, "<Base64>");
740 [ # # ]: 0 : if (pos == NULL)
741 : 0 : return NULL;
742 : :
743 : 0 : pos += 8;
744 : 0 : pos2 = os_strstr(pos, "</Base64>");
745 [ # # ]: 0 : if (pos2 == NULL)
746 : 0 : return NULL;
747 : 0 : *pos2 = '\0';
748 : :
749 : 0 : decoded = base64_decode((unsigned char *) pos, os_strlen(pos),
750 : : decoded_len);
751 : 0 : *pos2 = '<';
752 [ # # ]: 0 : if (decoded == NULL) {
753 : 0 : wpa_printf(MSG_DEBUG, "TNC: Failed to decode Base64 data");
754 : : }
755 : :
756 : 0 : return decoded;
757 : : }
758 : :
759 : :
760 : 0 : static enum tncs_process_res tncs_derive_recommendation(struct tncs_data *tncs)
761 : : {
762 : : enum IMV_Action_Recommendation rec;
763 : : struct tnc_if_imv *imv;
764 : : TNC_ConnectionState state;
765 : : char *txt;
766 : :
767 : 0 : wpa_printf(MSG_DEBUG, "TNC: No more messages from IMVs");
768 : :
769 [ # # ]: 0 : if (tncs->done)
770 : 0 : return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
771 : :
772 : 0 : tncs_solicit_recommendation(tncs);
773 : :
774 : : /* Select the most restrictive recommendation */
775 : 0 : rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION;
776 [ # # ]: 0 : for (imv = tncs->imv; imv; imv = imv->next) {
777 : : TNC_IMV_Action_Recommendation irec;
778 : 0 : irec = tncs->imv_data[imv->imvID].recommendation;
779 [ # # ]: 0 : if (irec == TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
780 : 0 : rec = TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS;
781 [ # # ][ # # ]: 0 : if (irec == TNC_IMV_ACTION_RECOMMENDATION_ISOLATE &&
782 : : rec != TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS)
783 : 0 : rec = TNC_IMV_ACTION_RECOMMENDATION_ISOLATE;
784 [ # # ][ # # ]: 0 : if (irec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW &&
785 : : rec == TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
786 : 0 : rec = TNC_IMV_ACTION_RECOMMENDATION_ALLOW;
787 : : }
788 : :
789 : 0 : wpa_printf(MSG_DEBUG, "TNC: Recommendation: %d", rec);
790 : 0 : tncs->recommendation = rec;
791 : 0 : tncs->done = 1;
792 : :
793 : 0 : txt = NULL;
794 [ # # # # ]: 0 : switch (rec) {
795 : : case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
796 : : case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
797 : 0 : txt = "allow";
798 : 0 : state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
799 : 0 : break;
800 : : case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
801 : 0 : txt = "isolate";
802 : 0 : state = TNC_CONNECTION_STATE_ACCESS_ISOLATED;
803 : 0 : break;
804 : : case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
805 : 0 : txt = "none";
806 : 0 : state = TNC_CONNECTION_STATE_ACCESS_NONE;
807 : 0 : break;
808 : : default:
809 : 0 : state = TNC_CONNECTION_STATE_ACCESS_ALLOWED;
810 : 0 : break;
811 : : }
812 : :
813 [ # # ]: 0 : if (txt) {
814 : 0 : os_free(tncs->tncs_message);
815 : 0 : tncs->tncs_message = os_zalloc(200);
816 [ # # ]: 0 : if (tncs->tncs_message) {
817 : 0 : os_snprintf(tncs->tncs_message, 199,
818 : : "<TNCC-TNCS-Message><Type>%08X</Type>"
819 : : "<XML><TNCCS-Recommendation type=\"%s\">"
820 : : "</TNCCS-Recommendation></XML>"
821 : : "</TNCC-TNCS-Message>",
822 : : TNC_TNCCS_RECOMMENDATION, txt);
823 : : }
824 : : }
825 : :
826 [ # # ]: 0 : for (imv = tncs->imv; imv; imv = imv->next) {
827 : 0 : tncs_imv_notify_connection_change(imv, tncs->connectionID,
828 : : state);
829 : : }
830 : :
831 [ # # # # : 0 : switch (rec) {
# ]
832 : : case TNC_IMV_ACTION_RECOMMENDATION_ALLOW:
833 : 0 : return TNCCS_RECOMMENDATION_ALLOW;
834 : : case TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS:
835 : 0 : return TNCCS_RECOMMENDATION_NO_ACCESS;
836 : : case TNC_IMV_ACTION_RECOMMENDATION_ISOLATE:
837 : 0 : return TNCCS_RECOMMENDATION_ISOLATE;
838 : : case TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION:
839 : 0 : return TNCCS_RECOMMENDATION_NO_RECOMMENDATION;
840 : : default:
841 : 0 : return TNCCS_PROCESS_ERROR;
842 : : }
843 : : }
844 : :
845 : :
846 : 0 : enum tncs_process_res tncs_process_if_tnccs(struct tncs_data *tncs,
847 : : const u8 *msg, size_t len)
848 : : {
849 : : char *buf, *start, *end, *pos, *pos2, *payload;
850 : : unsigned int batch_id;
851 : : unsigned char *decoded;
852 : : size_t decoded_len;
853 : :
854 : 0 : buf = dup_binstr(msg, len);
855 [ # # ]: 0 : if (buf == NULL)
856 : 0 : return TNCCS_PROCESS_ERROR;
857 : :
858 : 0 : start = os_strstr(buf, "<TNCCS-Batch ");
859 : 0 : end = os_strstr(buf, "</TNCCS-Batch>");
860 [ # # ][ # # ]: 0 : if (start == NULL || end == NULL || start > end) {
[ # # ]
861 : 0 : os_free(buf);
862 : 0 : return TNCCS_PROCESS_ERROR;
863 : : }
864 : :
865 : 0 : start += 13;
866 [ # # ]: 0 : while (*start == ' ')
867 : 0 : start++;
868 : 0 : *end = '\0';
869 : :
870 : 0 : pos = os_strstr(start, "BatchId=");
871 [ # # ]: 0 : if (pos == NULL) {
872 : 0 : os_free(buf);
873 : 0 : return TNCCS_PROCESS_ERROR;
874 : : }
875 : :
876 : 0 : pos += 8;
877 [ # # ]: 0 : if (*pos == '"')
878 : 0 : pos++;
879 : 0 : batch_id = atoi(pos);
880 : 0 : wpa_printf(MSG_DEBUG, "TNC: Received IF-TNCCS BatchId=%u",
881 : : batch_id);
882 [ # # ]: 0 : if (batch_id != tncs->last_batchid + 1) {
883 : 0 : wpa_printf(MSG_DEBUG, "TNC: Unexpected IF-TNCCS BatchId "
884 : : "%u (expected %u)",
885 : 0 : batch_id, tncs->last_batchid + 1);
886 : 0 : os_free(buf);
887 : 0 : return TNCCS_PROCESS_ERROR;
888 : : }
889 : 0 : tncs->last_batchid = batch_id;
890 : :
891 [ # # ][ # # ]: 0 : while (*pos != '\0' && *pos != '>')
892 : 0 : pos++;
893 [ # # ]: 0 : if (*pos == '\0') {
894 : 0 : os_free(buf);
895 : 0 : return TNCCS_PROCESS_ERROR;
896 : : }
897 : 0 : pos++;
898 : 0 : payload = start;
899 : :
900 : : /*
901 : : * <IMC-IMV-Message>
902 : : * <Type>01234567</Type>
903 : : * <Base64>foo==</Base64>
904 : : * </IMC-IMV-Message>
905 : : */
906 : :
907 [ # # ]: 0 : while (*start) {
908 : : char *endpos;
909 : : unsigned int type;
910 : :
911 : 0 : pos = os_strstr(start, "<IMC-IMV-Message>");
912 [ # # ]: 0 : if (pos == NULL)
913 : 0 : break;
914 : 0 : start = pos + 17;
915 : 0 : end = os_strstr(start, "</IMC-IMV-Message>");
916 [ # # ]: 0 : if (end == NULL)
917 : 0 : break;
918 : 0 : *end = '\0';
919 : 0 : endpos = end;
920 : 0 : end += 18;
921 : :
922 [ # # ]: 0 : if (tncs_get_type(start, &type) < 0) {
923 : 0 : *endpos = '<';
924 : 0 : start = end;
925 : 0 : continue;
926 : : }
927 : 0 : wpa_printf(MSG_DEBUG, "TNC: IMC-IMV-Message Type 0x%x", type);
928 : :
929 : 0 : decoded = tncs_get_base64(start, &decoded_len);
930 [ # # ]: 0 : if (decoded == NULL) {
931 : 0 : *endpos = '<';
932 : 0 : start = end;
933 : 0 : continue;
934 : : }
935 : :
936 : 0 : tncs_send_to_imvs(tncs, type, decoded, decoded_len);
937 : :
938 : 0 : os_free(decoded);
939 : :
940 : 0 : start = end;
941 : : }
942 : :
943 : : /*
944 : : * <TNCC-TNCS-Message>
945 : : * <Type>01234567</Type>
946 : : * <XML><TNCCS-Foo type="foo"></TNCCS-Foo></XML>
947 : : * <Base64>foo==</Base64>
948 : : * </TNCC-TNCS-Message>
949 : : */
950 : :
951 : 0 : start = payload;
952 [ # # ]: 0 : while (*start) {
953 : : unsigned int type;
954 : : char *xml, *xmlend, *endpos;
955 : :
956 : 0 : pos = os_strstr(start, "<TNCC-TNCS-Message>");
957 [ # # ]: 0 : if (pos == NULL)
958 : 0 : break;
959 : 0 : start = pos + 19;
960 : 0 : end = os_strstr(start, "</TNCC-TNCS-Message>");
961 [ # # ]: 0 : if (end == NULL)
962 : 0 : break;
963 : 0 : *end = '\0';
964 : 0 : endpos = end;
965 : 0 : end += 20;
966 : :
967 [ # # ]: 0 : if (tncs_get_type(start, &type) < 0) {
968 : 0 : *endpos = '<';
969 : 0 : start = end;
970 : 0 : continue;
971 : : }
972 : 0 : wpa_printf(MSG_DEBUG, "TNC: TNCC-TNCS-Message Type 0x%x",
973 : : type);
974 : :
975 : : /* Base64 OR XML */
976 : 0 : decoded = NULL;
977 : 0 : xml = NULL;
978 : 0 : xmlend = NULL;
979 : 0 : pos = os_strstr(start, "<XML>");
980 [ # # ]: 0 : if (pos) {
981 : 0 : pos += 5;
982 : 0 : pos2 = os_strstr(pos, "</XML>");
983 [ # # ]: 0 : if (pos2 == NULL) {
984 : 0 : *endpos = '<';
985 : 0 : start = end;
986 : 0 : continue;
987 : : }
988 : 0 : xmlend = pos2;
989 : 0 : xml = pos;
990 : : } else {
991 : 0 : decoded = tncs_get_base64(start, &decoded_len);
992 [ # # ]: 0 : if (decoded == NULL) {
993 : 0 : *endpos = '<';
994 : 0 : start = end;
995 : 0 : continue;
996 : : }
997 : : }
998 : :
999 [ # # ]: 0 : if (decoded) {
1000 : 0 : wpa_hexdump_ascii(MSG_MSGDUMP,
1001 : : "TNC: TNCC-TNCS-Message Base64",
1002 : : decoded, decoded_len);
1003 : 0 : os_free(decoded);
1004 : : }
1005 : :
1006 [ # # ]: 0 : if (xml) {
1007 : 0 : wpa_hexdump_ascii(MSG_MSGDUMP,
1008 : : "TNC: TNCC-TNCS-Message XML",
1009 : : (unsigned char *) xml,
1010 : 0 : xmlend - xml);
1011 : : }
1012 : :
1013 : 0 : start = end;
1014 : : }
1015 : :
1016 : 0 : os_free(buf);
1017 : :
1018 : 0 : tncs_batch_ending(tncs);
1019 : :
1020 [ # # ]: 0 : if (tncs_total_send_len(tncs) == 0)
1021 : 0 : return tncs_derive_recommendation(tncs);
1022 : :
1023 : 0 : return TNCCS_PROCESS_OK_NO_RECOMMENDATION;
1024 : : }
1025 : :
1026 : :
1027 : 0 : static struct tnc_if_imv * tncs_parse_imv(int id, char *start, char *end,
1028 : : int *error)
1029 : : {
1030 : : struct tnc_if_imv *imv;
1031 : : char *pos, *pos2;
1032 : :
1033 [ # # ]: 0 : if (id >= TNC_MAX_IMV_ID) {
1034 : 0 : wpa_printf(MSG_DEBUG, "TNC: Too many IMVs");
1035 : 0 : return NULL;
1036 : : }
1037 : :
1038 : 0 : imv = os_zalloc(sizeof(*imv));
1039 [ # # ]: 0 : if (imv == NULL) {
1040 : 0 : *error = 1;
1041 : 0 : return NULL;
1042 : : }
1043 : :
1044 : 0 : imv->imvID = id;
1045 : :
1046 : 0 : pos = start;
1047 : 0 : wpa_printf(MSG_DEBUG, "TNC: Configured IMV: %s", pos);
1048 [ # # ][ # # ]: 0 : if (pos + 1 >= end || *pos != '"') {
1049 : 0 : wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
1050 : : "(no starting quotation mark)", start);
1051 : 0 : os_free(imv);
1052 : 0 : return NULL;
1053 : : }
1054 : :
1055 : 0 : pos++;
1056 : 0 : pos2 = pos;
1057 [ # # ][ # # ]: 0 : while (pos2 < end && *pos2 != '"')
1058 : 0 : pos2++;
1059 [ # # ]: 0 : if (pos2 >= end) {
1060 : 0 : wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
1061 : : "(no ending quotation mark)", start);
1062 : 0 : os_free(imv);
1063 : 0 : return NULL;
1064 : : }
1065 : 0 : *pos2 = '\0';
1066 : 0 : wpa_printf(MSG_DEBUG, "TNC: Name: '%s'", pos);
1067 : 0 : imv->name = os_strdup(pos);
1068 : :
1069 : 0 : pos = pos2 + 1;
1070 [ # # ][ # # ]: 0 : if (pos >= end || *pos != ' ') {
1071 : 0 : wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMV line '%s' "
1072 : : "(no space after name)", start);
1073 : 0 : os_free(imv);
1074 : 0 : return NULL;
1075 : : }
1076 : :
1077 : 0 : pos++;
1078 : 0 : wpa_printf(MSG_DEBUG, "TNC: IMV file: '%s'", pos);
1079 : 0 : imv->path = os_strdup(pos);
1080 : :
1081 : 0 : return imv;
1082 : : }
1083 : :
1084 : :
1085 : 0 : static int tncs_read_config(struct tncs_global *global)
1086 : : {
1087 : : char *config, *end, *pos, *line_end;
1088 : : size_t config_len;
1089 : : struct tnc_if_imv *imv, *last;
1090 : 0 : int id = 0;
1091 : :
1092 : 0 : last = NULL;
1093 : :
1094 : 0 : config = os_readfile(TNC_CONFIG_FILE, &config_len);
1095 [ # # ]: 0 : if (config == NULL) {
1096 : 0 : wpa_printf(MSG_ERROR, "TNC: Could not open TNC configuration "
1097 : : "file '%s'", TNC_CONFIG_FILE);
1098 : 0 : return -1;
1099 : : }
1100 : :
1101 : 0 : end = config + config_len;
1102 [ # # ]: 0 : for (pos = config; pos < end; pos = line_end + 1) {
1103 : 0 : line_end = pos;
1104 [ # # ][ # # ]: 0 : while (*line_end != '\n' && *line_end != '\r' &&
[ # # ]
1105 : : line_end < end)
1106 : 0 : line_end++;
1107 : 0 : *line_end = '\0';
1108 : :
1109 [ # # ]: 0 : if (os_strncmp(pos, "IMV ", 4) == 0) {
1110 : 0 : int error = 0;
1111 : :
1112 : 0 : imv = tncs_parse_imv(id++, pos + 4, line_end, &error);
1113 [ # # ]: 0 : if (error)
1114 : 0 : return -1;
1115 [ # # ]: 0 : if (imv) {
1116 [ # # ]: 0 : if (last == NULL)
1117 : 0 : global->imv = imv;
1118 : : else
1119 : 0 : last->next = imv;
1120 : 0 : last = imv;
1121 : : }
1122 : : }
1123 : : }
1124 : :
1125 : 0 : os_free(config);
1126 : :
1127 : 0 : return 0;
1128 : : }
1129 : :
1130 : :
1131 : 0 : struct tncs_data * tncs_init(void)
1132 : : {
1133 : : struct tncs_data *tncs;
1134 : :
1135 [ # # ]: 0 : if (tncs_global_data == NULL)
1136 : 0 : return NULL;
1137 : :
1138 : 0 : tncs = os_zalloc(sizeof(*tncs));
1139 [ # # ]: 0 : if (tncs == NULL)
1140 : 0 : return NULL;
1141 : 0 : tncs->imv = tncs_global_data->imv;
1142 : 0 : tncs->connectionID = tncs_global_data->next_conn_id++;
1143 : 0 : tncs->next = tncs_global_data->connections;
1144 : 0 : tncs_global_data->connections = tncs;
1145 : :
1146 : 0 : return tncs;
1147 : : }
1148 : :
1149 : :
1150 : 0 : void tncs_deinit(struct tncs_data *tncs)
1151 : : {
1152 : : int i;
1153 : : struct tncs_data *prev, *conn;
1154 : :
1155 [ # # ]: 0 : if (tncs == NULL)
1156 : 0 : return;
1157 : :
1158 [ # # ]: 0 : for (i = 0; i < TNC_MAX_IMV_ID; i++)
1159 : 0 : os_free(tncs->imv_data[i].imv_send);
1160 : :
1161 : 0 : prev = NULL;
1162 : 0 : conn = tncs_global_data->connections;
1163 [ # # ]: 0 : while (conn) {
1164 [ # # ]: 0 : if (conn == tncs) {
1165 [ # # ]: 0 : if (prev)
1166 : 0 : prev->next = tncs->next;
1167 : : else
1168 : 0 : tncs_global_data->connections = tncs->next;
1169 : 0 : break;
1170 : : }
1171 : 0 : prev = conn;
1172 : 0 : conn = conn->next;
1173 : : }
1174 : :
1175 : 0 : os_free(tncs->tncs_message);
1176 : 0 : os_free(tncs);
1177 : : }
1178 : :
1179 : :
1180 : 0 : int tncs_global_init(void)
1181 : : {
1182 : : struct tnc_if_imv *imv;
1183 : :
1184 : 0 : tncs_global_data = os_zalloc(sizeof(*tncs_global_data));
1185 [ # # ]: 0 : if (tncs_global_data == NULL)
1186 : 0 : return -1;
1187 : :
1188 [ # # ]: 0 : if (tncs_read_config(tncs_global_data) < 0) {
1189 : 0 : wpa_printf(MSG_ERROR, "TNC: Failed to read TNC configuration");
1190 : 0 : goto failed;
1191 : : }
1192 : :
1193 [ # # ]: 0 : for (imv = tncs_global_data->imv; imv; imv = imv->next) {
1194 [ # # ]: 0 : if (tncs_load_imv(imv)) {
1195 : 0 : wpa_printf(MSG_ERROR, "TNC: Failed to load IMV '%s'",
1196 : : imv->name);
1197 : 0 : goto failed;
1198 : : }
1199 : : }
1200 : :
1201 : 0 : return 0;
1202 : :
1203 : : failed:
1204 : 0 : tncs_global_deinit();
1205 : 0 : return -1;
1206 : : }
1207 : :
1208 : :
1209 : 1 : void tncs_global_deinit(void)
1210 : : {
1211 : : struct tnc_if_imv *imv, *prev;
1212 : :
1213 [ + - ]: 1 : if (tncs_global_data == NULL)
1214 : 1 : return;
1215 : :
1216 : 0 : imv = tncs_global_data->imv;
1217 [ # # ]: 0 : while (imv) {
1218 : 0 : tncs_unload_imv(imv);
1219 : :
1220 : 0 : prev = imv;
1221 : 0 : imv = imv->next;
1222 : 0 : os_free(prev);
1223 : : }
1224 : :
1225 : 0 : os_free(tncs_global_data);
1226 : 0 : tncs_global_data = NULL;
1227 : : }
1228 : :
1229 : :
1230 : 0 : struct wpabuf * tncs_build_soh_request(void)
1231 : : {
1232 : : struct wpabuf *buf;
1233 : :
1234 : : /*
1235 : : * Build a SoH Request TLV (to be used inside SoH EAP Extensions
1236 : : * Method)
1237 : : */
1238 : :
1239 : 0 : buf = wpabuf_alloc(8 + 4);
1240 [ # # ]: 0 : if (buf == NULL)
1241 : 0 : return NULL;
1242 : :
1243 : : /* Vendor-Specific TLV (Microsoft) - SoH Request */
1244 : 0 : wpabuf_put_be16(buf, EAP_TLV_VENDOR_SPECIFIC_TLV); /* TLV Type */
1245 : 0 : wpabuf_put_be16(buf, 8); /* Length */
1246 : :
1247 : 0 : wpabuf_put_be32(buf, EAP_VENDOR_MICROSOFT); /* Vendor_Id */
1248 : :
1249 : 0 : wpabuf_put_be16(buf, 0x02); /* TLV Type - SoH Request TLV */
1250 : 0 : wpabuf_put_be16(buf, 0); /* Length */
1251 : :
1252 : 0 : return buf;
1253 : : }
1254 : :
1255 : :
1256 : 0 : struct wpabuf * tncs_process_soh(const u8 *soh_tlv, size_t soh_tlv_len,
1257 : : int *failure)
1258 : : {
1259 : 0 : wpa_hexdump(MSG_DEBUG, "TNC: SoH TLV", soh_tlv, soh_tlv_len);
1260 : 0 : *failure = 0;
1261 : :
1262 : : /* TODO: return MS-SoH Response TLV */
1263 : :
1264 : 0 : return NULL;
1265 : : }
|