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_test_agent.h"
17 #include "imv_test_state.h"
19 #include <imv/imv_agent.h>
20 #include <imv/imv_msg.h>
21 #include <ietf/ietf_attr.h>
22 #include <ietf/ietf_attr_pa_tnc_error.h>
23 #include <ita/ita_attr.h>
24 #include <ita/ita_attr_get_settings.h>
25 #include <ita/ita_attr_command.h>
26 #include <ita/ita_attr_dummy.h>
28 #include <tncif_names.h>
29 #include <tncif_pa_subtypes.h>
32 #include <utils/debug.h>
34 typedef struct private_imv_test_agent_t private_imv_test_agent_t
;
36 /* Subscribed PA-TNC message subtypes */
37 static pen_type_t msg_types
[] = {
38 { PEN_ITA
, PA_SUBTYPE_ITA_TEST
}
42 * Private data of an imv_test_agent_t object.
44 struct private_imv_test_agent_t
{
47 * Public members of imv_test_agent_t
49 imv_agent_if_t
public;
52 * IMV agent responsible for generic functions
58 METHOD(imv_agent_if_t
, bind_functions
, TNC_Result
,
59 private_imv_test_agent_t
*this, TNC_TNCS_BindFunctionPointer bind_function
)
61 return this->agent
->bind_functions(this->agent
, bind_function
);
64 METHOD(imv_agent_if_t
, notify_connection_change
, TNC_Result
,
65 private_imv_test_agent_t
*this, TNC_ConnectionID id
,
66 TNC_ConnectionState new_state
)
72 case TNC_CONNECTION_STATE_CREATE
:
73 state
= imv_test_state_create(id
);
74 return this->agent
->create_state(this->agent
, state
);
75 case TNC_CONNECTION_STATE_DELETE
:
76 return this->agent
->delete_state(this->agent
, id
);
78 return this->agent
->change_state(this->agent
, id
, new_state
, NULL
);
83 * Process a received message
85 static TNC_Result
receive_msg(private_imv_test_agent_t
*this, imv_state_t
*state
,
89 imv_test_state_t
*test_state
;
90 enumerator_t
*enumerator
;
95 bool fatal_error
= FALSE
, received_command
= FALSE
, retry
= FALSE
;
97 /* parse received PA-TNC message and handle local and remote errors */
98 result
= in_msg
->receive(in_msg
, &fatal_error
);
99 if (result
!= TNC_RESULT_SUCCESS
)
104 /* add any new IMC and set its number of rounds */
105 rounds
= lib
->settings
->get_int(lib
->settings
,
106 "libimcv.plugins.imv-test.rounds", 0);
107 test_state
= (imv_test_state_t
*)state
;
108 test_state
->add_imc(test_state
, in_msg
->get_src_id(in_msg
), rounds
);
110 /* analyze PA-TNC attributes */
111 enumerator
= in_msg
->create_attribute_enumerator(in_msg
);
112 while (enumerator
->enumerate(enumerator
, &attr
))
114 attr_type
= attr
->get_type(attr
);
116 if (attr_type
.vendor_id
!= PEN_ITA
)
120 if (attr_type
.type
== ITA_ATTR_COMMAND
)
122 ita_attr_command_t
*ita_attr
;
125 received_command
= TRUE
;
126 ita_attr
= (ita_attr_command_t
*)attr
;
127 command
= ita_attr
->get_command(ita_attr
);
129 if (streq(command
, "allow"))
131 state
->set_recommendation(state
,
132 TNC_IMV_ACTION_RECOMMENDATION_ALLOW
,
133 TNC_IMV_EVALUATION_RESULT_COMPLIANT
);
135 else if (streq(command
, "isolate"))
137 state
->set_recommendation(state
,
138 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE
,
139 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR
);
141 else if (streq(command
, "block") || streq(command
, "none"))
143 state
->set_recommendation(state
,
144 TNC_IMV_ACTION_RECOMMENDATION_NO_ACCESS
,
145 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR
);
147 else if (streq(command
, "retry"))
153 DBG1(DBG_IMV
, "unsupported ITA Command '%s'", command
);
154 state
->set_recommendation(state
,
155 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
156 TNC_IMV_EVALUATION_RESULT_ERROR
);
159 else if (attr_type
.type
== ITA_ATTR_DUMMY
)
161 ita_attr_dummy_t
*ita_attr
;
163 ita_attr
= (ita_attr_dummy_t
*)attr
;
164 DBG1(DBG_IMV
, "received dummy attribute value (%d bytes)",
165 ita_attr
->get_size(ita_attr
));
168 enumerator
->destroy(enumerator
);
172 state
->set_recommendation(state
,
173 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION
,
174 TNC_IMV_EVALUATION_RESULT_ERROR
);
175 out_msg
= imv_msg_create_as_reply(in_msg
);
176 result
= out_msg
->send_assessment(out_msg
);
177 out_msg
->destroy(out_msg
);
178 if (result
!= TNC_RESULT_SUCCESS
)
182 return this->agent
->provide_recommendation(this->agent
, state
);
185 /* request a handshake retry ? */
188 test_state
->set_rounds(test_state
, rounds
);
189 return this->agent
->request_handshake_retry(
190 this->agent
->get_id(this->agent
),
191 state
->get_connection_id(state
),
192 TNC_RETRY_REASON_IMV_SERIOUS_EVENT
);
195 /* repeat the measurement ? */
196 if (test_state
->another_round(test_state
, in_msg
->get_src_id(in_msg
)))
198 out_msg
= imv_msg_create_as_reply(in_msg
);
199 attr
= ita_attr_command_create("repeat");
200 out_msg
->add_attribute(out_msg
, attr
);
202 /* send PA-TNC message with excl flag set */
203 result
= out_msg
->send(out_msg
, TRUE
);
204 out_msg
->destroy(out_msg
);
209 if (received_command
)
211 out_msg
= imv_msg_create_as_reply(in_msg
);
212 result
= out_msg
->send_assessment(out_msg
);
213 out_msg
->destroy(out_msg
);
214 if (result
!= TNC_RESULT_SUCCESS
)
218 return this->agent
->provide_recommendation(this->agent
, state
);
222 return TNC_RESULT_SUCCESS
;
226 METHOD(imv_agent_if_t
, receive_message
, TNC_Result
,
227 private_imv_test_agent_t
*this, TNC_ConnectionID id
,
228 TNC_MessageType msg_type
, chunk_t msg
)
234 if (!this->agent
->get_state(this->agent
, id
, &state
))
236 return TNC_RESULT_FATAL
;
238 in_msg
= imv_msg_create_from_data(this->agent
, state
, id
, msg_type
, msg
);
239 result
= receive_msg(this, state
, in_msg
);
240 in_msg
->destroy(in_msg
);
245 METHOD(imv_agent_if_t
, receive_message_long
, TNC_Result
,
246 private_imv_test_agent_t
*this, TNC_ConnectionID id
,
247 TNC_UInt32 src_imc_id
, TNC_UInt32 dst_imv_id
,
248 TNC_VendorID msg_vid
, TNC_MessageSubtype msg_subtype
, chunk_t msg
)
254 if (!this->agent
->get_state(this->agent
, id
, &state
))
256 return TNC_RESULT_FATAL
;
258 in_msg
= imv_msg_create_from_long_data(this->agent
, state
, id
,
259 src_imc_id
, dst_imv_id
, msg_vid
, msg_subtype
, msg
);
260 result
= receive_msg(this, state
, in_msg
);
261 in_msg
->destroy(in_msg
);
267 METHOD(imv_agent_if_t
, batch_ending
, TNC_Result
,
268 private_imv_test_agent_t
*this, TNC_ConnectionID id
)
270 return TNC_RESULT_SUCCESS
;
273 METHOD(imv_agent_if_t
, solicit_recommendation
, TNC_Result
,
274 private_imv_test_agent_t
*this, TNC_ConnectionID id
)
278 if (!this->agent
->get_state(this->agent
, id
, &state
))
280 return TNC_RESULT_FATAL
;
282 return this->agent
->provide_recommendation(this->agent
, state
);
285 METHOD(imv_agent_if_t
, destroy
, void,
286 private_imv_test_agent_t
*this)
288 DESTROY_IF(this->agent
);
293 * Described in header.
295 imv_agent_if_t
*imv_test_agent_create(const char *name
, TNC_IMVID id
,
296 TNC_Version
*actual_version
)
298 private_imv_test_agent_t
*this;
301 agent
= imv_agent_create(name
, msg_types
, countof(msg_types
), id
,
310 .bind_functions
= _bind_functions
,
311 .notify_connection_change
= _notify_connection_change
,
312 .receive_message
= _receive_message
,
313 .receive_message_long
= _receive_message_long
,
314 .batch_ending
= _batch_ending
,
315 .solicit_recommendation
= _solicit_recommendation
,
321 return &this->public;