imv-swima: Created SWIMA IMV plugin
[strongswan.git] / src / libimcv / plugins / imv_swima / imv_swima_agent.c
1 /*
2 * Copyright (C) 2017 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 #define _GNU_SOURCE
17 #include <stdio.h>
18
19 #include "imv_swima_agent.h"
20 #include "imv_swima_state.h"
21 #include "imv_swima_rest.h"
22
23 #include <imcv.h>
24 #include <imv/imv_agent.h>
25 #include <imv/imv_msg.h>
26 #include "tcg/seg/tcg_seg_attr_max_size.h"
27 #include "tcg/seg/tcg_seg_attr_seg_env.h"
28 #include "ietf/swima/ietf_swima_attr_req.h"
29 #include "ietf/swima/ietf_swima_attr_sw_inv.h"
30 #include "ietf/swima/ietf_swima_attr_sw_ev.h"
31 #include "swima/swima_error.h"
32 #include "swima/swima_inventory.h"
33 #include "swima/swima_events.h"
34 #include "swima/swima_data_model.h"
35
36 #include <tncif_names.h>
37 #include <tncif_pa_subtypes.h>
38
39 #include <pen/pen.h>
40 #include <utils/debug.h>
41 #include <bio/bio_reader.h>
42
43 typedef struct private_imv_swima_agent_t private_imv_swima_agent_t;
44
45 /* Subscribed PA-TNC message subtypes */
46 static pen_type_t msg_types[] = {
47 { PEN_IETF, PA_SUBTYPE_IETF_SW }
48 };
49
50 /**
51 * Flag set when corresponding attribute has been received
52 */
53 enum imv_swima_attr_t {
54 IMV_SWIMA_ATTR_SW_INV = (1<<0),
55 IMV_SWIMA_ATTR_SW_ID_INV = (1<<1)
56 };
57
58 /**
59 * Private data of an imv_swima_agent_t object.
60 */
61 struct private_imv_swima_agent_t {
62
63 /**
64 * Public members of imv_swima_agent_t
65 */
66 imv_agent_if_t public;
67
68 /**
69 * IMV agent responsible for generic functions
70 */
71 imv_agent_t *agent;
72
73 /**
74 * REST API to strongTNC manager
75 */
76 imv_swima_rest_t *rest_api;
77
78 };
79
80 METHOD(imv_agent_if_t, bind_functions, TNC_Result,
81 private_imv_swima_agent_t *this, TNC_TNCS_BindFunctionPointer bind_function)
82 {
83 return this->agent->bind_functions(this->agent, bind_function);
84 }
85
86 METHOD(imv_agent_if_t, notify_connection_change, TNC_Result,
87 private_imv_swima_agent_t *this, TNC_ConnectionID id,
88 TNC_ConnectionState new_state)
89 {
90 imv_state_t *state;
91
92 switch (new_state)
93 {
94 case TNC_CONNECTION_STATE_CREATE:
95 state = imv_swima_state_create(id);
96 return this->agent->create_state(this->agent, state);
97 case TNC_CONNECTION_STATE_DELETE:
98 return this->agent->delete_state(this->agent, id);
99 default:
100 return this->agent->change_state(this->agent, id, new_state, NULL);
101 }
102 }
103
104 /**
105 * Process a received message
106 */
107 static TNC_Result receive_msg(private_imv_swima_agent_t *this,
108 imv_state_t *state, imv_msg_t *in_msg)
109 {
110 imv_swima_state_t *swima_state;
111 imv_msg_t *out_msg;
112 enumerator_t *enumerator;
113 pa_tnc_attr_t *attr;
114 TNC_Result result;
115 bool fatal_error = FALSE;
116
117 /* generate an outgoing PA-TNC message - we might need it */
118 out_msg = imv_msg_create_as_reply(in_msg);
119
120 /* parse received PA-TNC message and handle local and remote errors */
121 result = in_msg->receive(in_msg, out_msg, &fatal_error);
122 if (result != TNC_RESULT_SUCCESS)
123 {
124 out_msg->destroy(out_msg);
125 return result;
126 }
127
128 swima_state = (imv_swima_state_t*)state;
129
130 /* analyze PA-TNC attributes */
131 enumerator = in_msg->create_attribute_enumerator(in_msg);
132 while (enumerator->enumerate(enumerator, &attr))
133 {
134 uint32_t request_id = 0, last_eid, eid_epoch;
135 swima_inventory_t *inventory;
136 swima_events_t *events;
137 pen_type_t type;
138
139 type = attr->get_type(attr);
140
141 if (type.vendor_id != PEN_IETF)
142 {
143 continue;
144 }
145
146 switch (type.type)
147 {
148 case IETF_ATTR_PA_TNC_ERROR:
149 {
150 ietf_attr_pa_tnc_error_t *error_attr;
151 pen_type_t error_code;
152 chunk_t msg_info, description;
153 bio_reader_t *reader;
154 uint32_t max_attr_size;
155 bool success;
156
157 error_attr = (ietf_attr_pa_tnc_error_t*)attr;
158 error_code = error_attr->get_error_code(error_attr);
159
160 if (error_code.vendor_id != PEN_IETF ||
161 error_code.type <= PA_ERROR_PA_TNC_MSG_ROOF)
162 {
163 continue;
164 }
165 msg_info = error_attr->get_msg_info(error_attr);
166 reader = bio_reader_create(msg_info);
167 success = reader->read_uint32(reader, &request_id);
168
169 DBG1(DBG_IMV, "received PA-TNC error '%N' for request %d",
170 pa_tnc_error_code_names, error_code.type, request_id);
171 if (!success)
172 {
173 reader->destroy(reader);
174 continue;
175 }
176 if (error_code.type == PA_ERROR_SW_RESPONSE_TOO_LARGE)
177 {
178 if (!reader->read_uint32(reader, &max_attr_size))
179 {
180 reader->destroy(reader);
181 continue;
182 }
183 DBG1(DBG_IMV, " maximum PA-TNC attribute size is %u bytes",
184 max_attr_size);
185 }
186 description = reader->peek(reader);
187 if (description.len)
188 {
189 DBG1(DBG_IMV, " description: %.*s", description.len,
190 description.ptr);
191 }
192 reader->destroy(reader);
193 break;
194 }
195 case IETF_ATTR_SW_ID_INVENTORY:
196 {
197 ietf_swima_attr_sw_inv_t *attr_cast;
198 uint32_t missing;
199 int sw_id_count;
200
201 state->set_action_flags(state, IMV_SWIMA_ATTR_SW_ID_INV);
202
203 attr_cast = (ietf_swima_attr_sw_inv_t*)attr;
204 request_id = attr_cast->get_request_id(attr_cast);
205 inventory = attr_cast->get_inventory(attr_cast);
206 last_eid = inventory->get_eid(inventory, &eid_epoch);
207 sw_id_count = inventory->get_count(inventory);
208 missing = attr_cast->get_record_count(attr_cast);
209 swima_state->set_missing(swima_state, missing);
210
211 DBG2(DBG_IMV, "received software identity inventory with "
212 "%d item%s for request %d at eid %d of epoch 0x%08x, "
213 "%d item%s to follow", sw_id_count,
214 (sw_id_count == 1) ? "" : "s", request_id, last_eid,
215 eid_epoch, missing, (missing == 1) ? "" : "s");
216
217 if (request_id == swima_state->get_request_id(swima_state))
218 {
219 swima_state->set_inventory(swima_state, inventory);
220 swima_state->set_count(swima_state, sw_id_count, 0,
221 in_msg->get_src_id(in_msg));
222 }
223 else
224 {
225 DBG1(DBG_IMV, "no workitem found for software identity "
226 "inventory with request ID %d", request_id);
227 }
228 attr_cast->clear_inventory(attr_cast);
229 break;
230 }
231 case IETF_ATTR_SW_INVENTORY:
232 {
233 ietf_swima_attr_sw_inv_t *attr_cast;
234 swima_record_t *sw_record;
235 json_object *jobj, *jarray, *jstring;
236 pen_type_t data_model;
237 chunk_t tag;
238 char *tag_str;
239 uint32_t missing;
240 int sw_count;
241 enumerator_t *e;
242
243 state->set_action_flags(state, IMV_SWIMA_ATTR_SW_INV);
244
245 attr_cast = (ietf_swima_attr_sw_inv_t*)attr;
246 request_id = attr_cast->get_request_id(attr_cast);
247 inventory = attr_cast->get_inventory(attr_cast);
248 last_eid = inventory->get_eid(inventory, &eid_epoch);
249 sw_count = inventory->get_count(inventory);
250 missing = attr_cast->get_record_count(attr_cast);
251 swima_state->set_missing(swima_state, missing);
252
253 DBG2(DBG_IMV, "received software inventory with %d item%s for "
254 "request %d at eid %d of epoch 0x%08x, %d item%s to follow",
255 sw_count, (sw_count == 1) ? "" : "s", request_id,
256 last_eid, eid_epoch, missing, (missing == 1) ? "" : "s");
257
258 if (request_id == swima_state->get_request_id(swima_state))
259 {
260 swima_state->set_count(swima_state, 0, sw_count,
261 in_msg->get_src_id(in_msg));
262
263 if (this->rest_api)
264 {
265 jobj = json_object_new_object();
266 jarray = json_object_new_array();
267 json_object_object_add(jobj, "data", jarray);
268
269 e = inventory->create_enumerator(inventory);
270 while (e->enumerate(e, &sw_record))
271 {
272 tag = sw_record->get_record(sw_record);
273 DBG3(DBG_IMV, "%.*s", tag.len, tag.ptr);
274
275 data_model = sw_record->get_data_model(sw_record);
276 if (!pen_type_equals(data_model,
277 swima_data_model_iso_2015_swid_xml))
278 {
279 DBG1(DBG_IMV, "only ISO/IEC 19770-2-2015 XML "
280 "data model supported");
281 continue;
282 }
283
284 tag_str = strndup(tag.ptr, tag.len);
285 jstring = json_object_new_string(tag_str);
286 json_object_array_add(jarray, jstring);
287 free(tag_str);
288 }
289 e->destroy(e);
290
291 if (this->rest_api->post(this->rest_api,
292 "swid/add-tags/", jobj, NULL) != SUCCESS)
293 {
294 DBG1(DBG_IMV, "error in REST API add-tags request");
295 }
296 json_object_put(jobj);
297 }
298 }
299 else
300 {
301 DBG1(DBG_IMV, "no workitem found for SWID tag inventory "
302 "with request ID %d", request_id);
303 }
304 attr_cast->clear_inventory(attr_cast);
305 break;
306 }
307 case IETF_ATTR_SW_ID_EVENTS:
308 {
309 ietf_swima_attr_sw_ev_t *attr_cast;
310 uint32_t missing;
311 int sw_ev_count;
312
313 state->set_action_flags(state, IMV_SWIMA_ATTR_SW_ID_INV);
314
315 attr_cast = (ietf_swima_attr_sw_ev_t*)attr;
316 request_id = attr_cast->get_request_id(attr_cast);
317 events = attr_cast->get_events(attr_cast);
318 last_eid = events->get_eid(events, &eid_epoch, NULL);
319 sw_ev_count = events->get_count(events);
320 missing = attr_cast->get_event_count(attr_cast);
321 swima_state->set_missing(swima_state, missing);
322
323 DBG2(DBG_IMV, "received software identity events with "
324 "%d item%s for request %d at eid %d of epoch 0x%08x, "
325 "%d item%s to follow", sw_ev_count,
326 (sw_ev_count == 1) ? "" : "s", request_id, last_eid,
327 eid_epoch, missing, (missing == 1) ? "" : "s");
328
329 if (request_id == swima_state->get_request_id(swima_state))
330 {
331 swima_state->set_events(swima_state, events);
332 swima_state->set_count(swima_state, sw_ev_count, 0,
333 in_msg->get_src_id(in_msg));
334 }
335 else
336 {
337 DBG1(DBG_IMV, "no workitem found for software identity "
338 "evemts with request ID %d", request_id);
339 }
340 attr_cast->clear_events(attr_cast);
341 break;
342
343 }
344 default:
345 break;
346 }
347 }
348 enumerator->destroy(enumerator);
349
350 if (fatal_error)
351 {
352 state->set_recommendation(state,
353 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
354 TNC_IMV_EVALUATION_RESULT_ERROR);
355 result = out_msg->send_assessment(out_msg);
356 if (result == TNC_RESULT_SUCCESS)
357 {
358 result = this->agent->provide_recommendation(this->agent, state);
359 }
360 }
361 else
362 {
363 /* send PA-TNC message with the EXCL flag set */
364 result = out_msg->send(out_msg, TRUE);
365 }
366 out_msg->destroy(out_msg);
367
368 return result;
369 }
370
371 METHOD(imv_agent_if_t, receive_message, TNC_Result,
372 private_imv_swima_agent_t *this, TNC_ConnectionID id,
373 TNC_MessageType msg_type, chunk_t msg)
374 {
375 imv_state_t *state;
376 imv_msg_t *in_msg;
377 TNC_Result result;
378
379 if (!this->agent->get_state(this->agent, id, &state))
380 {
381 return TNC_RESULT_FATAL;
382 }
383 in_msg = imv_msg_create_from_data(this->agent, state, id, msg_type, msg);
384 result = receive_msg(this, state, in_msg);
385 in_msg->destroy(in_msg);
386
387 return result;
388 }
389
390 METHOD(imv_agent_if_t, receive_message_long, TNC_Result,
391 private_imv_swima_agent_t *this, TNC_ConnectionID id,
392 TNC_UInt32 src_imc_id, TNC_UInt32 dst_imv_id,
393 TNC_VendorID msg_vid, TNC_MessageSubtype msg_subtype, chunk_t msg)
394 {
395 imv_state_t *state;
396 imv_msg_t *in_msg;
397 TNC_Result result;
398
399 if (!this->agent->get_state(this->agent, id, &state))
400 {
401 return TNC_RESULT_FATAL;
402 }
403 in_msg = imv_msg_create_from_long_data(this->agent, state, id,
404 src_imc_id, dst_imv_id, msg_vid, msg_subtype, msg);
405 result = receive_msg(this, state, in_msg);
406 in_msg->destroy(in_msg);
407
408 return result;
409
410 }
411
412 METHOD(imv_agent_if_t, batch_ending, TNC_Result,
413 private_imv_swima_agent_t *this, TNC_ConnectionID id)
414 {
415 imv_msg_t *out_msg;
416 imv_state_t *state;
417 imv_session_t *session;
418 imv_workitem_t *workitem;
419 imv_swima_state_t *swima_state;
420 imv_swima_handshake_state_t handshake_state;
421 pa_tnc_attr_t *attr;
422 TNC_IMVID imv_id;
423 TNC_Result result = TNC_RESULT_SUCCESS;
424 bool no_workitems = TRUE;
425 uint32_t request_id, received;
426 uint8_t flags;
427 enumerator_t *enumerator;
428
429 if (!this->agent->get_state(this->agent, id, &state))
430 {
431 return TNC_RESULT_FATAL;
432 }
433 swima_state = (imv_swima_state_t*)state;
434 handshake_state = swima_state->get_handshake_state(swima_state);
435 session = state->get_session(state);
436 imv_id = this->agent->get_id(this->agent);
437
438 if (handshake_state == IMV_SWIMA_STATE_END)
439 {
440 return TNC_RESULT_SUCCESS;
441 }
442
443 /* Create an empty out message - we might need it */
444 out_msg = imv_msg_create(this->agent, state, id, imv_id,
445 swima_state->get_imc_id(swima_state),
446 msg_types[0]);
447
448 if (!imcv_db)
449 {
450 DBG2(DBG_IMV, "no workitems available - no evaluation possible");
451 state->set_recommendation(state,
452 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
453 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
454 result = out_msg->send_assessment(out_msg);
455 out_msg->destroy(out_msg);
456 swima_state->set_handshake_state(swima_state, IMV_SWIMA_STATE_END);
457
458 if (result != TNC_RESULT_SUCCESS)
459 {
460 return result;
461 }
462 return this->agent->provide_recommendation(this->agent, state);
463 }
464
465 /* Look for SWID tag workitem and create SWID tag request */
466 if (handshake_state == IMV_SWIMA_STATE_INIT &&
467 session->get_policy_started(session))
468 {
469 size_t max_attr_size = SWIMA_MAX_ATTR_SIZE;
470 size_t max_seg_size;
471 ietf_swima_attr_req_t *cast_attr;
472 seg_contract_t *contract;
473 seg_contract_manager_t *contracts;
474 swima_inventory_t *targets;
475 uint32_t earliest_eid = 0;
476 char buf[BUF_LEN];
477
478 enumerator = session->create_workitem_enumerator(session);
479 if (enumerator)
480 {
481 while (enumerator->enumerate(enumerator, &workitem))
482 {
483 if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY ||
484 workitem->get_type(workitem) != IMV_WORKITEM_SWID_TAGS)
485 {
486 continue;
487 }
488
489 flags = IETF_SWIMA_ATTR_REQ_FLAG_NONE;
490 if (strchr(workitem->get_arg_str(workitem), 'R'))
491 {
492 flags |= IETF_SWIMA_ATTR_REQ_FLAG_R;
493 }
494 if (strchr(workitem->get_arg_str(workitem), 'S'))
495 {
496 flags |= IETF_SWIMA_ATTR_REQ_FLAG_S;
497 }
498 if (strchr(workitem->get_arg_str(workitem), 'C'))
499 {
500 flags |= IETF_SWIMA_ATTR_REQ_FLAG_C;
501 }
502
503 /* Determine maximum PA-TNC attribute segment size */
504 max_seg_size = state->get_max_msg_len(state)
505 - PA_TNC_HEADER_SIZE
506 - PA_TNC_ATTR_HEADER_SIZE
507 - TCG_SEG_ATTR_SEG_ENV_HEADER;
508
509 /* Announce support of PA-TNC segmentation to IMC */
510 contract = seg_contract_create(msg_types[0], max_attr_size,
511 max_seg_size, TRUE, imv_id, FALSE);
512 contract->get_info_string(contract, buf, BUF_LEN, TRUE);
513 DBG2(DBG_IMV, "%s", buf);
514 contracts = state->get_contracts(state);
515 contracts->add_contract(contracts, contract);
516 attr = tcg_seg_attr_max_size_create(max_attr_size,
517 max_seg_size, TRUE);
518 out_msg->add_attribute(out_msg, attr);
519
520 /* Issue a SWID request */
521 request_id = workitem->get_id(workitem);
522 swima_state->set_request_id(swima_state, request_id);
523 attr = ietf_swima_attr_req_create(flags, request_id);
524
525 /* Request software identifier events */
526 targets = swima_inventory_create();
527 targets->set_eid(targets, earliest_eid, 0);
528 cast_attr = (ietf_swima_attr_req_t*)attr;
529 cast_attr->set_targets(cast_attr, targets);
530
531 out_msg->add_attribute(out_msg, attr);
532 workitem->set_imv_id(workitem, imv_id);
533 no_workitems = FALSE;
534 DBG2(DBG_IMV, "IMV %d issues sw request %d", imv_id, request_id);
535 break;
536 }
537 enumerator->destroy(enumerator);
538
539 if (no_workitems)
540 {
541 DBG2(DBG_IMV, "IMV %d has no workitems - "
542 "no evaluation requested", imv_id);
543 state->set_recommendation(state,
544 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
545 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
546 }
547 handshake_state = IMV_SWIMA_STATE_WORKITEMS;
548 swima_state->set_handshake_state(swima_state, handshake_state);
549 }
550 }
551
552 received = state->get_action_flags(state);
553
554 if (handshake_state == IMV_SWIMA_STATE_WORKITEMS &&
555 (received & (IMV_SWIMA_ATTR_SW_INV|IMV_SWIMA_ATTR_SW_ID_INV)) &&
556 swima_state->get_missing(swima_state) == 0)
557 {
558 TNC_IMV_Evaluation_Result eval;
559 TNC_IMV_Action_Recommendation rec;
560 char result_str[BUF_LEN], *error_str = "", *command;
561 char *target_str;
562 int tag_id_count, tag_count, i;
563 json_object *jrequest, *jresponse, *jvalue;
564 ietf_swima_attr_req_t *cast_attr;
565 swima_inventory_t *targets;
566 swima_record_t *target;
567 status_t status = SUCCESS;
568
569 if (this->rest_api && (received & IMV_SWIMA_ATTR_SW_ID_INV))
570 {
571 if (asprintf(&command, "sessions/%d/swid-measurement/",
572 session->get_session_id(session, NULL, NULL)) < 0)
573 {
574 error_str = "allocation of command string failed";
575 status = FAILED;
576 }
577 else
578 {
579 jrequest = swima_state->get_inventory(swima_state);
580 status = this->rest_api->post(this->rest_api, command,
581 jrequest, &jresponse);
582 if (status == FAILED)
583 {
584 error_str = "error in REST API swid-measurement request";
585 }
586 free(command);
587 }
588 }
589
590 switch (status)
591 {
592 case SUCCESS:
593 enumerator = session->create_workitem_enumerator(session);
594 while (enumerator->enumerate(enumerator, &workitem))
595 {
596 if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
597 {
598 swima_state->get_count(swima_state, &tag_id_count,
599 &tag_count);
600 snprintf(result_str, BUF_LEN, "received inventory of "
601 "%d SWID tag ID%s and %d SWID tag%s",
602 tag_id_count, (tag_id_count == 1) ? "" : "s",
603 tag_count, (tag_count == 1) ? "" : "s");
604 session->remove_workitem(session, enumerator);
605
606 eval = TNC_IMV_EVALUATION_RESULT_COMPLIANT;
607 rec = workitem->set_result(workitem, result_str, eval);
608 state->update_recommendation(state, rec, eval);
609 imcv_db->finalize_workitem(imcv_db, workitem);
610 workitem->destroy(workitem);
611 break;
612 }
613 }
614 enumerator->destroy(enumerator);
615 break;
616 case NEED_MORE:
617 if (received & IMV_SWIMA_ATTR_SW_INV)
618 {
619 error_str = "not all requested SWID tags were received";
620 status = FAILED;
621 json_object_put(jresponse);
622 break;
623 }
624 if (json_object_get_type(jresponse) != json_type_array)
625 {
626 error_str = "response was not a json_array";
627 status = FAILED;
628 json_object_put(jresponse);
629 break;
630 }
631
632 /* Create an IETF SW Request attribute */
633 attr = ietf_swima_attr_req_create(IETF_SWIMA_ATTR_REQ_FLAG_NONE,
634 swima_state->get_request_id(swima_state));
635 tag_id_count = json_object_array_length(jresponse);
636 DBG1(DBG_IMV, "%d SWID tag target%s", tag_id_count,
637 (tag_id_count == 1) ? "" : "s");
638 swima_state->set_missing(swima_state, tag_id_count);
639 targets = swima_inventory_create();
640
641 for (i = 0; i < tag_id_count; i++)
642 {
643 jvalue = json_object_array_get_idx(jresponse, i);
644 if (json_object_get_type(jvalue) != json_type_string)
645 {
646 error_str = "json_string element expected in json_array";
647 status = FAILED;
648 json_object_put(jresponse);
649 break;
650 }
651 target_str = (char*)json_object_get_string(jvalue);
652 DBG1(DBG_IMV, " %s", target_str);
653 target = swima_record_create(0, chunk_from_str(target_str),
654 chunk_empty);
655 targets->add(targets, target);
656 }
657 json_object_put(jresponse);
658
659 cast_attr = (ietf_swima_attr_req_t*)attr;
660 cast_attr->set_targets(cast_attr, targets);
661 targets->destroy(targets);
662 out_msg->add_attribute(out_msg, attr);
663 break;
664 case FAILED:
665 default:
666 break;
667 }
668
669 if (status == FAILED)
670 {
671 enumerator = session->create_workitem_enumerator(session);
672 while (enumerator->enumerate(enumerator, &workitem))
673 {
674 if (workitem->get_type(workitem) == IMV_WORKITEM_SWID_TAGS)
675 {
676 session->remove_workitem(session, enumerator);
677 eval = TNC_IMV_EVALUATION_RESULT_ERROR;
678 rec = workitem->set_result(workitem, error_str, eval);
679 state->update_recommendation(state, rec, eval);
680 imcv_db->finalize_workitem(imcv_db, workitem);
681 workitem->destroy(workitem);
682 break;
683 }
684 }
685 enumerator->destroy(enumerator);
686 }
687 }
688
689 /* finalized all workitems ? */
690 if (handshake_state == IMV_SWIMA_STATE_WORKITEMS &&
691 session->get_workitem_count(session, imv_id) == 0)
692 {
693 result = out_msg->send_assessment(out_msg);
694 out_msg->destroy(out_msg);
695 swima_state->set_handshake_state(swima_state, IMV_SWIMA_STATE_END);
696
697 if (result != TNC_RESULT_SUCCESS)
698 {
699 return result;
700 }
701 return this->agent->provide_recommendation(this->agent, state);
702 }
703
704 /* send non-empty PA-TNC message with excl flag not set */
705 if (out_msg->get_attribute_count(out_msg))
706 {
707 result = out_msg->send(out_msg, FALSE);
708 }
709 out_msg->destroy(out_msg);
710
711 return result;
712 }
713
714 METHOD(imv_agent_if_t, solicit_recommendation, TNC_Result,
715 private_imv_swima_agent_t *this, TNC_ConnectionID id)
716 {
717 imv_state_t *state;
718
719 if (!this->agent->get_state(this->agent, id, &state))
720 {
721 return TNC_RESULT_FATAL;
722 }
723 return this->agent->provide_recommendation(this->agent, state);
724 }
725
726 METHOD(imv_agent_if_t, destroy, void,
727 private_imv_swima_agent_t *this)
728 {
729 DESTROY_IF(this->rest_api);
730 this->agent->destroy(this->agent);
731 free(this);
732 }
733
734 /**
735 * Described in header.
736 */
737 imv_agent_if_t *imv_swima_agent_create(const char *name, TNC_IMVID id,
738 TNC_Version *actual_version)
739 {
740 private_imv_swima_agent_t *this;
741 imv_agent_t *agent;
742 char *rest_api_uri;
743 u_int rest_api_timeout;
744
745 agent = imv_agent_create(name, msg_types, countof(msg_types), id,
746 actual_version);
747 if (!agent)
748 {
749 return NULL;
750 }
751 agent->add_non_fatal_attr_type(agent,
752 pen_type_create(PEN_TCG, TCG_SEG_MAX_ATTR_SIZE_REQ));
753
754 INIT(this,
755 .public = {
756 .bind_functions = _bind_functions,
757 .notify_connection_change = _notify_connection_change,
758 .receive_message = _receive_message,
759 .receive_message_long = _receive_message_long,
760 .batch_ending = _batch_ending,
761 .solicit_recommendation = _solicit_recommendation,
762 .destroy = _destroy,
763 },
764 .agent = agent,
765 );
766
767 rest_api_uri = lib->settings->get_str(lib->settings,
768 "%s.plugins.imv-swima.rest_api_uri", NULL, lib->ns);
769 rest_api_timeout = lib->settings->get_int(lib->settings,
770 "%s.plugins.imv-swima.rest_api_timeout", 120, lib->ns);
771 if (rest_api_uri)
772 {
773 this->rest_api = imv_swima_rest_create(rest_api_uri, rest_api_timeout);
774 }
775
776 return &this->public;
777 }
778