Build all IMC/IMVs with -no-undefined
[strongswan.git] / src / libimcv / plugins / imc_test / imc_test.c
1 /*
2 * Copyright (C) 2011-2012 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "imc_test_state.h"
17
18 #include <imc/imc_agent.h>
19 #include <imc/imc_msg.h>
20 #include <ietf/ietf_attr.h>
21 #include <ita/ita_attr.h>
22 #include <ita/ita_attr_command.h>
23 #include <ita/ita_attr_dummy.h>
24
25 #include <tncif_pa_subtypes.h>
26
27 #include <pen/pen.h>
28 #include <utils/debug.h>
29
30 /* IMC definitions */
31
32 static const char imc_name[] = "Test";
33
34 static pen_type_t msg_types[] = {
35 { PEN_ITA, PA_SUBTYPE_ITA_TEST }
36 };
37
38 static imc_agent_t *imc_test;
39
40 /**
41 * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
42 */
43 TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
44 TNC_Version min_version,
45 TNC_Version max_version,
46 TNC_Version *actual_version)
47 {
48 if (imc_test)
49 {
50 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
51 return TNC_RESULT_ALREADY_INITIALIZED;
52 }
53 imc_test = imc_agent_create(imc_name, msg_types, countof(msg_types),
54 imc_id, actual_version);
55 if (!imc_test)
56 {
57 return TNC_RESULT_FATAL;
58 }
59 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
60 {
61 DBG1(DBG_IMC, "no common IF-IMC version");
62 return TNC_RESULT_NO_COMMON_VERSION;
63 }
64 return TNC_RESULT_SUCCESS;
65 }
66
67 /**
68 * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
69 */
70 TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
71 TNC_ConnectionID connection_id,
72 TNC_ConnectionState new_state)
73 {
74 imc_state_t *state;
75 imc_test_state_t *test_state;
76 TNC_Result result;
77 TNC_UInt32 additional_id;
78 char *command;
79 bool retry;
80 void *pointer;
81 enumerator_t *enumerator;
82 int dummy_size, additional_ids;
83
84 if (!imc_test)
85 {
86 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
87 return TNC_RESULT_NOT_INITIALIZED;
88 }
89
90 switch (new_state)
91 {
92 case TNC_CONNECTION_STATE_CREATE:
93 command = lib->settings->get_str(lib->settings,
94 "libimcv.plugins.imc-test.command", "none");
95 dummy_size = lib->settings->get_int(lib->settings,
96 "libimcv.plugins.imc-test.dummy_size", 0);
97 retry = lib->settings->get_bool(lib->settings,
98 "libimcv.plugins.imc-test.retry", FALSE);
99 state = imc_test_state_create(connection_id, command, dummy_size,
100 retry);
101
102 result = imc_test->create_state(imc_test, state);
103 if (result != TNC_RESULT_SUCCESS)
104 {
105 return result;
106 }
107
108 /* Optionally reserve additional IMC IDs */
109 additional_ids = lib->settings->get_int(lib->settings,
110 "libimcv.plugins.imc-test.additional_ids", 0);
111 imc_test->reserve_additional_ids(imc_test, additional_ids -
112 imc_test->count_additional_ids(imc_test));
113
114 return TNC_RESULT_SUCCESS;
115
116 case TNC_CONNECTION_STATE_HANDSHAKE:
117 /* get updated IMC state */
118 result = imc_test->change_state(imc_test, connection_id,
119 new_state, &state);
120 if (result != TNC_RESULT_SUCCESS)
121 {
122 return TNC_RESULT_FATAL;
123 }
124 test_state = (imc_test_state_t*)state;
125
126 /* is it the first handshake or a retry ? */
127 if (!test_state->is_first_handshake(test_state))
128 {
129 command = lib->settings->get_str(lib->settings,
130 "libimcv.plugins.imc-test.retry_command",
131 test_state->get_command(test_state));
132 test_state->set_command(test_state, command);
133 }
134
135 state->set_result(state, imc_id, TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
136
137 /* Exit if there are no additional IMC IDs */
138 if (!imc_test->count_additional_ids(imc_test))
139 {
140 return result;
141 }
142
143 enumerator = imc_test->create_id_enumerator(imc_test);
144 while (enumerator->enumerate(enumerator, &pointer))
145 {
146 /* interpret pointer as scalar value */
147 additional_id = (TNC_UInt32)pointer;
148
149 state->set_result(state, additional_id,
150 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
151 }
152 enumerator->destroy(enumerator);
153
154 return TNC_RESULT_SUCCESS;
155
156 case TNC_CONNECTION_STATE_DELETE:
157 return imc_test->delete_state(imc_test, connection_id);
158
159 case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
160 case TNC_CONNECTION_STATE_ACCESS_NONE:
161 /* get updated IMC state */
162 result = imc_test->change_state(imc_test, connection_id,
163 new_state, &state);
164 if (result != TNC_RESULT_SUCCESS)
165 {
166 return TNC_RESULT_FATAL;
167 }
168 test_state = (imc_test_state_t*)state;
169
170 /* do a handshake retry? */
171 if (test_state->do_handshake_retry(test_state))
172 {
173 return imc_test->request_handshake_retry(imc_id, connection_id,
174 TNC_RETRY_REASON_IMC_REMEDIATION_COMPLETE);
175 }
176 return TNC_RESULT_SUCCESS;
177
178 default:
179 return imc_test->change_state(imc_test, connection_id,
180 new_state, NULL);
181 }
182 }
183
184 static TNC_Result send_message(imc_state_t *state, imc_msg_t *out_msg)
185 {
186 imc_test_state_t *test_state;
187 pa_tnc_attr_t *attr;
188
189 test_state = (imc_test_state_t*)state;
190 if (test_state->get_dummy_size(test_state))
191 {
192 attr = ita_attr_dummy_create(test_state->get_dummy_size(test_state));
193 attr->set_noskip_flag(attr, TRUE);
194 out_msg->add_attribute(out_msg, attr);
195 }
196 attr = ita_attr_command_create(test_state->get_command(test_state));
197 attr->set_noskip_flag(attr, TRUE);
198 out_msg->add_attribute(out_msg, attr);
199
200 /* send PA-TNC message with the excl flag set */
201 return out_msg->send(out_msg, TRUE);
202 }
203
204 /**
205 * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
206 */
207 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
208 TNC_ConnectionID connection_id)
209 {
210 imc_state_t *state;
211 imc_msg_t *out_msg;
212 enumerator_t *enumerator;
213 void *pointer;
214 TNC_UInt32 additional_id;
215 TNC_Result result;
216
217 if (!imc_test)
218 {
219 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
220 return TNC_RESULT_NOT_INITIALIZED;
221 }
222 if (!imc_test->get_state(imc_test, connection_id, &state))
223 {
224 return TNC_RESULT_FATAL;
225 }
226
227 /* send PA message for primary IMC ID */
228 out_msg = imc_msg_create(imc_test, state, connection_id, imc_id,
229 TNC_IMVID_ANY, msg_types[0]);
230 result = send_message(state, out_msg);
231 out_msg->destroy(out_msg);
232
233 /* Exit if there are no additional IMC IDs */
234 if (!imc_test->count_additional_ids(imc_test))
235 {
236 return result;
237 }
238
239 /* Do we have support for transporting multiple IMC IDs? */
240 if (!state->has_long(state))
241 {
242 DBG1(DBG_IMC, "IMC %u \"%s\" did not detect support for transporting "
243 "multiple IMC IDs", imc_id, imc_name);
244 return result;
245 }
246
247 /* send PA messages for additional IMC IDs */
248 enumerator = imc_test->create_id_enumerator(imc_test);
249 while (result == TNC_RESULT_SUCCESS &&
250 enumerator->enumerate(enumerator, &pointer))
251 {
252 /* interpret pointer as scalar value */
253 additional_id = (TNC_UInt32)pointer;
254 out_msg = imc_msg_create(imc_test, state, connection_id, additional_id,
255 TNC_IMVID_ANY, msg_types[0]);
256 result = send_message(state, out_msg);
257 out_msg->destroy(out_msg);
258 }
259 enumerator->destroy(enumerator);
260
261 return result;
262 }
263
264 static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
265 {
266 imc_msg_t *out_msg;
267 enumerator_t *enumerator;
268 pa_tnc_attr_t *attr;
269 pen_type_t attr_type;
270 TNC_Result result;
271 bool fatal_error = FALSE;
272
273 /* parse received PA-TNC message and handle local and remote errors */
274 result = in_msg->receive(in_msg, &fatal_error);
275 if (result != TNC_RESULT_SUCCESS)
276 {
277 return result;
278 }
279
280 /* analyze PA-TNC attributes */
281 enumerator = in_msg->create_attribute_enumerator(in_msg);
282 while (enumerator->enumerate(enumerator, &attr))
283 {
284 attr_type = attr->get_type(attr);
285
286 if (attr_type.vendor_id != PEN_ITA)
287 {
288 continue;
289 }
290 if (attr_type.type == ITA_ATTR_COMMAND)
291 {
292 ita_attr_command_t *ita_attr;
293
294 ita_attr = (ita_attr_command_t*)attr;
295 DBG1(DBG_IMC, "received command '%s'",
296 ita_attr->get_command(ita_attr));
297 }
298 else if (attr_type.type == ITA_ATTR_DUMMY)
299 {
300 ita_attr_dummy_t *ita_attr;
301
302 ita_attr = (ita_attr_dummy_t*)attr;
303 DBG1(DBG_IMC, "received dummy attribute value (%d bytes)",
304 ita_attr->get_size(ita_attr));
305 }
306 }
307 enumerator->destroy(enumerator);
308
309 if (fatal_error)
310 {
311 return TNC_RESULT_FATAL;
312 }
313
314 /* if no assessment result is known then repeat the measurement */
315 if (state->get_result(state, in_msg->get_dst_id(in_msg), NULL))
316 {
317 return TNC_RESULT_SUCCESS;
318 }
319 out_msg = imc_msg_create_as_reply(in_msg);
320 result = send_message(state, out_msg);
321 out_msg->destroy(out_msg);
322
323 return result;
324 }
325
326 /**
327 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
328 */
329 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
330 TNC_ConnectionID connection_id,
331 TNC_BufferReference msg,
332 TNC_UInt32 msg_len,
333 TNC_MessageType msg_type)
334 {
335 imc_state_t *state;
336 imc_msg_t *in_msg;
337 TNC_Result result;
338
339 if (!imc_test)
340 {
341 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
342 return TNC_RESULT_NOT_INITIALIZED;
343 }
344 if (!imc_test->get_state(imc_test, connection_id, &state))
345 {
346 return TNC_RESULT_FATAL;
347 }
348
349 in_msg = imc_msg_create_from_data(imc_test, state, connection_id, msg_type,
350 chunk_create(msg, msg_len));
351 result = receive_message(state, in_msg);
352 in_msg->destroy(in_msg);
353
354 return result;
355 }
356
357 /**
358 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
359 */
360 TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
361 TNC_ConnectionID connection_id,
362 TNC_UInt32 msg_flags,
363 TNC_BufferReference msg,
364 TNC_UInt32 msg_len,
365 TNC_VendorID msg_vid,
366 TNC_MessageSubtype msg_subtype,
367 TNC_UInt32 src_imv_id,
368 TNC_UInt32 dst_imc_id)
369 {
370 imc_state_t *state;
371 imc_msg_t *in_msg;
372 TNC_Result result;
373
374 if (!imc_test)
375 {
376 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
377 return TNC_RESULT_NOT_INITIALIZED;
378 }
379 if (!imc_test->get_state(imc_test, connection_id, &state))
380 {
381 return TNC_RESULT_FATAL;
382 }
383 in_msg = imc_msg_create_from_long_data(imc_test, state, connection_id,
384 src_imv_id, dst_imc_id, msg_vid, msg_subtype,
385 chunk_create(msg, msg_len));
386 result =receive_message(state, in_msg);
387 in_msg->destroy(in_msg);
388
389 return result;
390 }
391
392 /**
393 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
394 */
395 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
396 TNC_ConnectionID connection_id)
397 {
398 if (!imc_test)
399 {
400 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
401 return TNC_RESULT_NOT_INITIALIZED;
402 }
403 return TNC_RESULT_SUCCESS;
404 }
405
406 /**
407 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
408 */
409 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
410 {
411 if (!imc_test)
412 {
413 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
414 return TNC_RESULT_NOT_INITIALIZED;
415 }
416 imc_test->destroy(imc_test);
417 imc_test = NULL;
418
419 return TNC_RESULT_SUCCESS;
420 }
421
422 /**
423 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
424 */
425 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
426 TNC_TNCC_BindFunctionPointer bind_function)
427 {
428 if (!imc_test)
429 {
430 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
431 return TNC_RESULT_NOT_INITIALIZED;
432 }
433 return imc_test->bind_functions(imc_test, bind_function);
434 }