2 * Copyright (C) 2012 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
18 #include "ietf/ietf_attr.h"
19 #include "ietf/ietf_attr_assess_result.h"
20 #include "ietf/ietf_attr_remediation_instr.h"
22 #include <tncif_names.h>
25 #include <collections/linked_list.h>
26 #include <utils/debug.h>
28 typedef struct private_imv_msg_t private_imv_msg_t
;
31 * Private data of a imv_msg_t object.
34 struct private_imv_msg_t
{
37 * Public imv_msg_t interface.
44 TNC_ConnectionID connection_id
;
62 * List of PA-TNC attributes to be sent
64 linked_list_t
*attr_list
;
82 METHOD(imv_msg_t
, get_src_id
, TNC_UInt32
,
83 private_imv_msg_t
*this)
88 METHOD(imv_msg_t
, get_dst_id
, TNC_UInt32
,
89 private_imv_msg_t
*this)
94 METHOD(imv_msg_t
, set_msg_type
, void,
95 private_imv_msg_t
*this, pen_type_t msg_type
)
97 if (msg_type
.vendor_id
!= this->msg_type
.vendor_id
||
98 msg_type
.type
!= this->msg_type
.type
)
100 this->msg_type
= msg_type
;
101 this->dst_id
= TNC_IMCID_ANY
;
105 METHOD(imv_msg_t
, add_attribute
, void,
106 private_imv_msg_t
*this, pa_tnc_attr_t
*attr
)
108 this->attr_list
->insert_last(this->attr_list
, attr
);
111 METHOD(imv_msg_t
, send_
, TNC_Result
,
112 private_imv_msg_t
*this, bool excl
)
114 pa_tnc_msg_t
*pa_tnc_msg
;
116 TNC_UInt32 msg_flags
;
117 TNC_MessageType msg_type
;
120 enumerator_t
*enumerator
;
121 TNC_Result result
= TNC_RESULT_SUCCESS
;
123 while (this->attr_list
->get_count(this->attr_list
))
125 pa_tnc_msg
= pa_tnc_msg_create(this->state
->get_max_msg_len(this->state
));
128 enumerator
= this->attr_list
->create_enumerator(this->attr_list
);
129 while (enumerator
->enumerate(enumerator
, &attr
))
131 if (pa_tnc_msg
->add_attribute(pa_tnc_msg
, attr
))
143 DBG1(DBG_IMV
, "PA-TNC attribute too large to send, deleted");
147 this->attr_list
->remove_at(this->attr_list
, enumerator
);
149 enumerator
->destroy(enumerator
);
151 /* build and send the PA-TNC message via the IF-IMV interface */
152 if (!pa_tnc_msg
->build(pa_tnc_msg
))
154 pa_tnc_msg
->destroy(pa_tnc_msg
);
155 return TNC_RESULT_FATAL
;
157 msg
= pa_tnc_msg
->get_encoding(pa_tnc_msg
);
158 DBG3(DBG_IMV
, "created PA-TNC message: %B", &msg
);
160 if (this->state
->has_long(this->state
) && this->agent
->send_message_long
)
162 excl
= excl
&& this->state
->has_excl(this->state
) &&
163 this->dst_id
!= TNC_IMCID_ANY
;
164 msg_flags
= excl ? TNC_MESSAGE_FLAGS_EXCLUSIVE
: 0;
165 result
= this->agent
->send_message_long(this->src_id
,
166 this->connection_id
, msg_flags
, msg
.ptr
, msg
.len
,
167 this->msg_type
.vendor_id
, this->msg_type
.type
,
170 else if (this->agent
->send_message
)
172 msg_type
= (this->msg_type
.vendor_id
<< 8) |
173 (this->msg_type
.type
& 0x000000ff);
174 result
= this->agent
->send_message(this->src_id
, this->connection_id
,
175 msg
.ptr
, msg
.len
, msg_type
);
178 pa_tnc_msg
->destroy(pa_tnc_msg
);
180 if (result
!= TNC_RESULT_SUCCESS
)
188 METHOD(imv_msg_t
, send_assessment
, TNC_Result
,
189 private_imv_msg_t
*this)
191 TNC_IMV_Action_Recommendation rec
;
192 TNC_IMV_Evaluation_Result eval
;
194 char *string
= NULL
, *lang_code
= NULL
, *uri
= NULL
;
197 /* Send an IETF Assessment Result attribute if enabled */
198 if (lib
->settings
->get_bool(lib
->settings
, "libimcv.assessment_result",
201 this->state
->get_recommendation(this->state
, &rec
, &eval
);
202 attr
= ietf_attr_assess_result_create(eval
);
203 add_attribute(this, attr
);
205 /* Send IETF Remediation Instructions if available */
206 if (eval
!= TNC_IMV_EVALUATION_RESULT_COMPLIANT
)
208 e
= this->agent
->create_language_enumerator(this->agent
,
210 if (this->state
->get_remediation_instructions(this->state
,
211 e
, &string
, &lang_code
, &uri
))
213 if (string
&& lang_code
)
215 attr
= ietf_attr_remediation_instr_create_from_string(
216 chunk_create(string
, strlen(string
)),
217 chunk_create(lang_code
, strlen(lang_code
)));
218 add_attribute(this, attr
);
222 attr
= ietf_attr_remediation_instr_create_from_uri(
223 chunk_create(uri
, strlen(uri
)));
224 add_attribute(this, attr
);
230 /* send PA-TNC message with the excl flag set */
231 return send_(this, TRUE
);
233 return TNC_RESULT_SUCCESS
;
236 METHOD(imv_msg_t
, receive
, TNC_Result
,
237 private_imv_msg_t
*this, bool *fatal_error
)
239 enumerator_t
*enumerator
;
243 if (this->state
->has_long(this->state
))
245 if (this->dst_id
!= TNC_IMVID_ANY
)
247 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
248 "from IMC %u to IMV %u",
249 this->agent
->get_id(this->agent
),
250 this->agent
->get_name(this->agent
),
251 this->connection_id
, this->src_id
, this->dst_id
);
255 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u "
256 "from IMC %u", this->agent
->get_id(this->agent
),
257 this->agent
->get_name(this->agent
),
258 this->connection_id
, this->src_id
);
263 DBG2(DBG_IMV
, "IMV %u \"%s\" received message for Connection ID %u",
264 this->agent
->get_id(this->agent
),
265 this->agent
->get_name(this->agent
),
266 this->connection_id
);
268 msg
= this->pa_msg
->get_encoding(this->pa_msg
);
269 DBG3(DBG_IMV
, "%B", &msg
);
271 switch (this->pa_msg
->process(this->pa_msg
))
277 imv_msg_t
*error_msg
;
280 error_msg
= imv_msg_create_as_reply(&this->public);
282 /* extract and copy by reference all error attributes */
283 enumerator
= this->pa_msg
->create_error_enumerator(this->pa_msg
);
284 while (enumerator
->enumerate(enumerator
, &attr
))
286 error_msg
->add_attribute(error_msg
, attr
->get_ref(attr
));
288 enumerator
->destroy(enumerator
);
291 * send the PA-TNC message containing all error attributes
292 * with the excl flag set
294 result
= error_msg
->send(error_msg
, TRUE
);
295 error_msg
->destroy(error_msg
);
300 return TNC_RESULT_FATAL
;
303 /* preprocess any received IETF standard error attributes */
304 *fatal_error
= this->pa_msg
->process_ietf_std_errors(this->pa_msg
);
306 return TNC_RESULT_SUCCESS
;
309 METHOD(imv_msg_t
, delete_attributes
, void,
310 private_imv_msg_t
*this)
314 while (this->attr_list
->remove_last(this->attr_list
, (void**)&attr
) == SUCCESS
)
320 METHOD(imv_msg_t
, create_attribute_enumerator
, enumerator_t
*,
321 private_imv_msg_t
*this)
323 return this->pa_msg
->create_attribute_enumerator(this->pa_msg
);
326 METHOD(imv_msg_t
, destroy
, void,
327 private_imv_msg_t
*this)
329 this->attr_list
->destroy_offset(this->attr_list
,
330 offsetof(pa_tnc_attr_t
, destroy
));
331 DESTROY_IF(this->pa_msg
);
338 imv_msg_t
*imv_msg_create(imv_agent_t
*agent
, imv_state_t
*state
,
339 TNC_ConnectionID connection_id
,
340 TNC_UInt32 src_id
, TNC_UInt32 dst_id
,
343 private_imv_msg_t
*this;
347 .get_src_id
= _get_src_id
,
348 .get_dst_id
= _get_dst_id
,
349 .set_msg_type
= _set_msg_type
,
351 .send_assessment
= _send_assessment
,
353 .add_attribute
= _add_attribute
,
354 .delete_attributes
= _delete_attributes
,
355 .create_attribute_enumerator
= _create_attribute_enumerator
,
358 .connection_id
= connection_id
,
361 .msg_type
= msg_type
,
362 .attr_list
= linked_list_create(),
367 return &this->public;
373 imv_msg_t
* imv_msg_create_as_reply(imv_msg_t
*msg
)
375 private_imv_msg_t
*in
;
378 in
= (private_imv_msg_t
*)msg
;
379 src_id
= (in
->dst_id
!= TNC_IMVID_ANY
) ?
380 in
->dst_id
: in
->agent
->get_id(in
->agent
);
382 return imv_msg_create(in
->agent
, in
->state
, in
->connection_id
, src_id
,
383 in
->src_id
, in
->msg_type
);
389 imv_msg_t
*imv_msg_create_from_data(imv_agent_t
*agent
, imv_state_t
*state
,
390 TNC_ConnectionID connection_id
,
391 TNC_MessageType msg_type
,
394 TNC_VendorID msg_vid
;
395 TNC_MessageSubtype msg_subtype
;
397 msg_vid
= msg_type
>> 8;
398 msg_subtype
= msg_type
& TNC_SUBTYPE_ANY
;
400 return imv_msg_create_from_long_data(agent
, state
, connection_id
,
401 TNC_IMCID_ANY
, agent
->get_id(agent
),
402 msg_vid
, msg_subtype
, msg
);
408 imv_msg_t
*imv_msg_create_from_long_data(imv_agent_t
*agent
, imv_state_t
*state
,
409 TNC_ConnectionID connection_id
,
412 TNC_VendorID msg_vid
,
413 TNC_MessageSubtype msg_subtype
,
416 private_imv_msg_t
*this;
420 .get_src_id
= _get_src_id
,
421 .get_dst_id
= _get_dst_id
,
422 .set_msg_type
= _set_msg_type
,
424 .send_assessment
= _send_assessment
,
426 .add_attribute
= _add_attribute
,
427 .delete_attributes
= _delete_attributes
,
428 .create_attribute_enumerator
= _create_attribute_enumerator
,
431 .connection_id
= connection_id
,
434 .msg_type
= pen_type_create(msg_vid
, msg_subtype
),
435 .attr_list
= linked_list_create(),
436 .pa_msg
= pa_tnc_msg_create_from_data(msg
),
441 return &this->public;