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