2 * Copyright (C) 2013 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
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>.
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
16 #include "imv_swid_agent.h"
17 #include "imv_swid_state.h"
20 #include "tcg/swid/tcg_swid_attr_req.h"
21 #include "tcg/swid/tcg_swid_attr_tag_id_inv.h"
24 #include <imv/imv_agent.h>
25 #include <imv/imv_msg.h>
27 #include <tncif_names.h>
28 #include <tncif_pa_subtypes.h>
31 #include <utils/debug.h>
33 typedef struct private_imv_swid_agent_t private_imv_swid_agent_t
;
35 /* Subscribed PA-TNC message subtypes */
36 static pen_type_t msg_types
[] = {
37 { PEN_TCG
, PA_SUBTYPE_TCG_SWID
}
41 * Private data of an imv_swid_agent_t object.
43 struct private_imv_swid_agent_t
{
46 * Public members of imv_swid_agent_t
48 imv_agent_if_t
public;
51 * IMV agent responsible for generic functions
57 METHOD(imv_agent_if_t
, bind_functions
, TNC_Result
,
58 private_imv_swid_agent_t
*this, TNC_TNCS_BindFunctionPointer bind_function
)
60 return this->agent
->bind_functions(this->agent
, bind_function
);
63 METHOD(imv_agent_if_t
, notify_connection_change
, TNC_Result
,
64 private_imv_swid_agent_t
*this, TNC_ConnectionID id
,
65 TNC_ConnectionState new_state
)
71 case TNC_CONNECTION_STATE_CREATE
:
72 state
= imv_swid_state_create(id
);
73 return this->agent
->create_state(this->agent
, state
);
74 case TNC_CONNECTION_STATE_DELETE
:
75 return this->agent
->delete_state(this->agent
, id
);
77 return this->agent
->change_state(this->agent
, id
, new_state
, NULL
);
82 * Process a received message
84 static TNC_Result
receive_msg(private_imv_swid_agent_t
*this,
85 imv_state_t
*state
, imv_msg_t
*in_msg
)
88 imv_session_t
*session
;
89 imv_workitem_t
*workitem
, *found
= NULL
;
90 enumerator_t
*enumerator
;
93 TNC_IMV_Evaluation_Result eval
;
94 TNC_IMV_Action_Recommendation rec
;
97 bool fatal_error
= FALSE
;
99 /* parse received PA-TNC message and handle local and remote errors */
100 result
= in_msg
->receive(in_msg
, &fatal_error
);
101 if (result
!= TNC_RESULT_SUCCESS
)
106 session
= state
->get_session(state
);
108 /* analyze PA-TNC attributes */
109 enumerator
= in_msg
->create_attribute_enumerator(in_msg
);
110 while (enumerator
->enumerate(enumerator
, &attr
))
112 type
= attr
->get_type(attr
);
114 if (type
.vendor_id
!= PEN_TCG
)
120 case TCG_SWID_TAG_ID_INVENTORY
:
122 tcg_swid_attr_tag_id_inv_t
*attr_cast
;
123 u_int32_t request_id
;
124 swid_tag_id_t
*tag_id
;
125 chunk_t tag_creator
, unique_sw_id
;
126 enumerator_t
*et
, *ew
;
128 attr_cast
= (tcg_swid_attr_tag_id_inv_t
*)attr
;
129 request_id
= attr_cast
->get_request_id(attr_cast
);
131 DBG2(DBG_IMV
, "received SWID tag ID inventory for request %d",
133 et
= attr_cast
->create_tag_id_enumerator(attr_cast
);
134 while (et
->enumerate(et
, &tag_id
))
136 tag_creator
= tag_id
->get_tag_creator(tag_id
);
137 unique_sw_id
= tag_id
->get_unique_sw_id(tag_id
, NULL
);
138 DBG3(DBG_IMV
, " %.*s_%.*s.swidtag",
139 tag_creator
.len
, tag_creator
.ptr
,
140 unique_sw_id
.len
, unique_sw_id
.ptr
);
146 /* TODO handle subscribed messages */
150 ew
= session
->create_workitem_enumerator(session
);
151 while (ew
->enumerate(ew
, &workitem
))
153 if (workitem
->get_id(workitem
) == request_id
)
162 DBG1(DBG_IMV
, "no workitem found for SWID tag ID inventory "
163 "with request ID %d", request_id
);
168 eval
= TNC_IMV_EVALUATION_RESULT_COMPLIANT
;
169 result_str
= "received SWID tag ID inventory";
170 session
->remove_workitem(session
, ew
);
172 rec
= found
->set_result(found
, result_str
, eval
);
173 state
->update_recommendation(state
, rec
, eval
);
174 imcv_db
->finalize_workitem(imcv_db
, found
);
175 found
->destroy(found
);
178 case TCG_SWID_TAG_INVENTORY
:
184 enumerator
->destroy(enumerator
);
188 state
->set_recommendation(state
,
189 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
190 TNC_IMV_EVALUATION_RESULT_ERROR
);
191 out_msg
= imv_msg_create_as_reply(in_msg
);
192 result
= out_msg
->send_assessment(out_msg
);
193 out_msg
->destroy(out_msg
);
194 if (result
!= TNC_RESULT_SUCCESS
)
198 return this->agent
->provide_recommendation(this->agent
, state
);
201 return TNC_RESULT_SUCCESS
;
204 METHOD(imv_agent_if_t
, receive_message
, TNC_Result
,
205 private_imv_swid_agent_t
*this, TNC_ConnectionID id
,
206 TNC_MessageType msg_type
, chunk_t msg
)
212 if (!this->agent
->get_state(this->agent
, id
, &state
))
214 return TNC_RESULT_FATAL
;
216 in_msg
= imv_msg_create_from_data(this->agent
, state
, id
, msg_type
, msg
);
217 result
= receive_msg(this, state
, in_msg
);
218 in_msg
->destroy(in_msg
);
223 METHOD(imv_agent_if_t
, receive_message_long
, TNC_Result
,
224 private_imv_swid_agent_t
*this, TNC_ConnectionID id
,
225 TNC_UInt32 src_imc_id
, TNC_UInt32 dst_imv_id
,
226 TNC_VendorID msg_vid
, TNC_MessageSubtype msg_subtype
, chunk_t msg
)
232 if (!this->agent
->get_state(this->agent
, id
, &state
))
234 return TNC_RESULT_FATAL
;
236 in_msg
= imv_msg_create_from_long_data(this->agent
, state
, id
,
237 src_imc_id
, dst_imv_id
, msg_vid
, msg_subtype
, msg
);
238 result
= receive_msg(this, state
, in_msg
);
239 in_msg
->destroy(in_msg
);
245 METHOD(imv_agent_if_t
, batch_ending
, TNC_Result
,
246 private_imv_swid_agent_t
*this, TNC_ConnectionID id
)
250 imv_session_t
*session
;
251 imv_workitem_t
*workitem
;
252 imv_swid_state_t
*swid_state
;
253 imv_swid_handshake_state_t handshake_state
;
256 TNC_Result result
= TNC_RESULT_SUCCESS
;
257 bool no_workitems
= TRUE
;
258 u_int32_t request_id
;
260 enumerator_t
*enumerator
;
262 if (!this->agent
->get_state(this->agent
, id
, &state
))
264 return TNC_RESULT_FATAL
;
266 swid_state
= (imv_swid_state_t
*)state
;
267 handshake_state
= swid_state
->get_handshake_state(swid_state
);
268 session
= state
->get_session(state
);
269 imv_id
= this->agent
->get_id(this->agent
);
271 if (handshake_state
== IMV_SWID_STATE_END
)
273 return TNC_RESULT_SUCCESS
;
276 /* create an empty out message - we might need it */
277 out_msg
= imv_msg_create(this->agent
, state
, id
, imv_id
, TNC_IMCID_ANY
,
282 DBG2(DBG_IMV
, "no workitems available - no evaluation possible");
283 state
->set_recommendation(state
,
284 TNC_IMV_ACTION_RECOMMENDATION_ALLOW
,
285 TNC_IMV_EVALUATION_RESULT_DONT_KNOW
);
286 result
= out_msg
->send_assessment(out_msg
);
287 out_msg
->destroy(out_msg
);
288 swid_state
->set_handshake_state(swid_state
, IMV_SWID_STATE_END
);
290 if (result
!= TNC_RESULT_SUCCESS
)
294 return this->agent
->provide_recommendation(this->agent
, state
);
297 if (handshake_state
== IMV_SWID_STATE_INIT
)
299 enumerator
= session
->create_workitem_enumerator(session
);
302 while (enumerator
->enumerate(enumerator
, &workitem
))
304 if (workitem
->get_imv_id(workitem
) != TNC_IMVID_ANY
||
305 workitem
->get_type(workitem
) != IMV_WORKITEM_SWID_TAGS
)
310 flags
= TCG_SWID_ATTR_REQ_FLAG_NONE
;
311 if (strchr(workitem
->get_arg_str(workitem
), 'R'))
313 flags
|= TCG_SWID_ATTR_REQ_FLAG_R
;
315 if (strchr(workitem
->get_arg_str(workitem
), 'S'))
317 flags
|= TCG_SWID_ATTR_REQ_FLAG_S
;
319 if (strchr(workitem
->get_arg_str(workitem
), 'C'))
321 flags
|= TCG_SWID_ATTR_REQ_FLAG_C
;
323 request_id
= workitem
->get_id(workitem
);
325 DBG2(DBG_IMV
, "IMV %d issues SWID tag request %d",
327 attr
= tcg_swid_attr_req_create(flags
, request_id
, 0);
328 out_msg
->add_attribute(out_msg
, attr
);
329 workitem
->set_imv_id(workitem
, imv_id
);
330 no_workitems
= FALSE
;
332 enumerator
->destroy(enumerator
);
336 DBG2(DBG_IMV
, "IMV %d has no workitems - "
337 "no evaluation requested", imv_id
);
338 state
->set_recommendation(state
,
339 TNC_IMV_ACTION_RECOMMENDATION_ALLOW
,
340 TNC_IMV_EVALUATION_RESULT_DONT_KNOW
);
342 handshake_state
= IMV_SWID_STATE_WORKITEMS
;
343 swid_state
->set_handshake_state(swid_state
, handshake_state
);
347 /* finalized all workitems ? */
348 if (handshake_state
== IMV_SWID_STATE_WORKITEMS
&&
349 session
->get_workitem_count(session
, imv_id
) == 0)
351 result
= out_msg
->send_assessment(out_msg
);
352 out_msg
->destroy(out_msg
);
353 swid_state
->set_handshake_state(swid_state
, IMV_SWID_STATE_END
);
355 if (result
!= TNC_RESULT_SUCCESS
)
359 return this->agent
->provide_recommendation(this->agent
, state
);
362 /* send non-empty PA-TNC message with excl flag not set */
363 if (out_msg
->get_attribute_count(out_msg
))
365 result
= out_msg
->send(out_msg
, FALSE
);
367 out_msg
->destroy(out_msg
);
372 METHOD(imv_agent_if_t
, solicit_recommendation
, TNC_Result
,
373 private_imv_swid_agent_t
*this, TNC_ConnectionID id
)
377 if (!this->agent
->get_state(this->agent
, id
, &state
))
379 return TNC_RESULT_FATAL
;
381 return this->agent
->provide_recommendation(this->agent
, state
);
384 METHOD(imv_agent_if_t
, destroy
, void,
385 private_imv_swid_agent_t
*this)
387 this->agent
->destroy(this->agent
);
393 * Described in header.
395 imv_agent_if_t
*imv_swid_agent_create(const char *name
, TNC_IMVID id
,
396 TNC_Version
*actual_version
)
398 private_imv_swid_agent_t
*this;
401 agent
= imv_agent_create(name
, msg_types
, countof(msg_types
), id
,
410 .bind_functions
= _bind_functions
,
411 .notify_connection_change
= _notify_connection_change
,
412 .receive_message
= _receive_message
,
413 .receive_message_long
= _receive_message_long
,
414 .batch_ending
= _batch_ending
,
415 .solicit_recommendation
= _solicit_recommendation
,
423 return &this->public;