implemented the Forwarding Enabled attribute
[strongswan.git] / src / libimcv / plugins / imv_os / imv_os.c
1 /*
2 * Copyright (C) 2012 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 #include "imv_os_state.h"
17
18 #include <imv/imv_agent.h>
19 #include <pa_tnc/pa_tnc_msg.h>
20 #include <ietf/ietf_attr.h>
21 #include <ietf/ietf_attr_attr_request.h>
22 #include <ietf/ietf_attr_fwd_enabled.h>
23 #include <ietf/ietf_attr_installed_packages.h>
24 #include <ietf/ietf_attr_pa_tnc_error.h>
25 #include <ietf/ietf_attr_product_info.h>
26 #include <ietf/ietf_attr_string_version.h>
27 #include <os_info/os_info.h>
28
29 #include <tncif_names.h>
30 #include <tncif_pa_subtypes.h>
31
32 #include <pen/pen.h>
33 #include <utils/linked_list.h>
34 #include <debug.h>
35
36 /* IMV definitions */
37
38 static const char imv_name[] = "OS";
39
40 #define IMV_VENDOR_ID PEN_IETF
41 #define IMV_SUBTYPE PA_SUBTYPE_IETF_OPERATING_SYSTEM
42
43 static imv_agent_t *imv_os;
44
45 /*
46 * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3
47 */
48 TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
49 TNC_Version min_version,
50 TNC_Version max_version,
51 TNC_Version *actual_version)
52 {
53 if (imv_os)
54 {
55 DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
56 return TNC_RESULT_ALREADY_INITIALIZED;
57 }
58 imv_os = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE,
59 imv_id, actual_version);
60 if (!imv_os)
61 {
62 return TNC_RESULT_FATAL;
63 }
64 if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
65 {
66 DBG1(DBG_IMV, "no common IF-IMV version");
67 return TNC_RESULT_NO_COMMON_VERSION;
68 }
69
70 return TNC_RESULT_SUCCESS;
71 }
72
73 /**
74 * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3
75 */
76 TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
77 TNC_ConnectionID connection_id,
78 TNC_ConnectionState new_state)
79 {
80 imv_state_t *state;
81
82 if (!imv_os)
83 {
84 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
85 return TNC_RESULT_NOT_INITIALIZED;
86 }
87 switch (new_state)
88 {
89 case TNC_CONNECTION_STATE_CREATE:
90 state = imv_os_state_create(connection_id);
91 return imv_os->create_state(imv_os, state);
92 case TNC_CONNECTION_STATE_DELETE:
93 return imv_os->delete_state(imv_os, connection_id);
94 default:
95 return imv_os->change_state(imv_os, connection_id,
96 new_state, NULL);
97 }
98 }
99
100 static TNC_Result receive_message(TNC_IMVID imv_id,
101 TNC_ConnectionID connection_id,
102 TNC_UInt32 msg_flags,
103 chunk_t msg,
104 TNC_VendorID msg_vid,
105 TNC_MessageSubtype msg_subtype,
106 TNC_UInt32 src_imc_id,
107 TNC_UInt32 dst_imv_id)
108 {
109 pa_tnc_msg_t *pa_tnc_msg;
110 pa_tnc_attr_t *attr;
111 pen_type_t type;
112 linked_list_t *attr_list;
113 imv_state_t *state;
114 imv_os_state_t *os_state;
115 enumerator_t *enumerator;
116 TNC_Result result;
117 chunk_t os_name = chunk_empty;
118 chunk_t os_version = chunk_empty;
119 bool fatal_error, assessment = FALSE;
120
121 if (!imv_os)
122 {
123 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
124 return TNC_RESULT_NOT_INITIALIZED;
125 }
126
127 /* get current IMV state */
128 if (!imv_os->get_state(imv_os, connection_id, &state))
129 {
130 return TNC_RESULT_FATAL;
131 }
132 os_state = (imv_os_state_t*)state;
133
134 /* parse received PA-TNC message and automatically handle any errors */
135 result = imv_os->receive_message(imv_os, state, msg, msg_vid,
136 msg_subtype, src_imc_id, dst_imv_id, &pa_tnc_msg);
137
138 /* no parsed PA-TNC attributes available if an error occurred */
139 if (!pa_tnc_msg)
140 {
141 return result;
142 }
143
144 /* preprocess any IETF standard error attributes */
145 fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg);
146
147 /* analyze PA-TNC attributes */
148 attr_list = linked_list_create();
149 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
150 while (enumerator->enumerate(enumerator, &attr))
151 {
152 type = attr->get_type(attr);
153
154 if (type.vendor_id != PEN_IETF)
155 {
156 continue;
157 }
158 switch (type.type)
159 {
160 case IETF_ATTR_PRODUCT_INFORMATION:
161 {
162 ietf_attr_product_info_t *attr_cast;
163
164 attr_cast = (ietf_attr_product_info_t*)attr;
165 os_name = attr_cast->get_info(attr_cast, NULL, NULL);
166 DBG1(DBG_IMV, "operating system name is '%.*s'",
167 os_name.len, os_name.ptr);
168 break;
169 }
170 case IETF_ATTR_STRING_VERSION:
171 {
172 ietf_attr_string_version_t *attr_cast;
173
174 attr_cast = (ietf_attr_string_version_t*)attr;
175 os_version = attr_cast->get_version(attr_cast, NULL, NULL);
176 if (os_version.len)
177 {
178 DBG1(DBG_IMV, "operating system version is '%.*s'",
179 os_version.len, os_version.ptr);
180 }
181 break;
182 }
183 case IETF_ATTR_FORWARDING_ENABLED:
184 {
185 ietf_attr_fwd_enabled_t *attr_cast;
186 os_fwd_status_t fwd_status;
187
188 attr_cast = (ietf_attr_fwd_enabled_t*)attr;
189 fwd_status = attr_cast->get_status(attr_cast);
190 DBG1(DBG_IMV, "IPv4 forwarding status: %N",
191 os_fwd_status_names, fwd_status);
192 break;
193 }
194 case IETF_ATTR_INSTALLED_PACKAGES:
195 {
196 ietf_attr_installed_packages_t *attr_cast;
197 enumerator_t *e;
198 chunk_t name, version;
199
200 attr_cast = (ietf_attr_installed_packages_t*)attr;
201 e = attr_cast->create_enumerator(attr_cast);
202 while (e->enumerate(e, &name, &version))
203 {
204 DBG1(DBG_IMV, "package '%.*s' %.*s", name.len, name.ptr,
205 version.len, version.ptr);
206 }
207 e->destroy(e);
208
209 state->set_recommendation(state,
210 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
211 TNC_IMV_EVALUATION_RESULT_COMPLIANT);
212 assessment = TRUE;
213 break;
214 }
215 default:
216 break;
217 }
218 }
219 enumerator->destroy(enumerator);
220
221 if (os_name.len && os_version.len)
222 {
223 char *product_info;
224
225 os_state->set_info(os_state, os_name, os_version);
226 product_info = os_state->get_info(os_state);
227
228 if (streq(product_info, "Windows 1.2.3"))
229 {
230 DBG1(DBG_IMV, "OS '%s' is not supported", product_info);
231
232 state->set_recommendation(state,
233 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
234 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR);
235 assessment = TRUE;
236 }
237 else
238 {
239 DBG1(DBG_IMV, "requesting installed packages for '%s'",
240 product_info);
241 attr = ietf_attr_attr_request_create(PEN_IETF,
242 IETF_ATTR_INSTALLED_PACKAGES);
243 attr_list->insert_last(attr_list, attr);
244 }
245 }
246 pa_tnc_msg->destroy(pa_tnc_msg);
247
248 if (fatal_error)
249 {
250 state->set_recommendation(state,
251 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
252 TNC_IMV_EVALUATION_RESULT_ERROR);
253 assessment = TRUE;
254 }
255
256 if (assessment)
257 {
258 attr_list->destroy_offset(attr_list, offsetof(pa_tnc_attr_t, destroy));
259 return imv_os->provide_recommendation(imv_os, connection_id, src_imc_id);
260 }
261
262 result = imv_os->send_message(imv_os, connection_id, TRUE, imv_id,
263 src_imc_id, attr_list);
264 attr_list->destroy(attr_list);
265
266 return result;
267 }
268
269 /**
270 * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3
271 */
272 TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
273 TNC_ConnectionID connection_id,
274 TNC_BufferReference msg,
275 TNC_UInt32 msg_len,
276 TNC_MessageType msg_type)
277 {
278 TNC_VendorID msg_vid;
279 TNC_MessageSubtype msg_subtype;
280
281 msg_vid = msg_type >> 8;
282 msg_subtype = msg_type & TNC_SUBTYPE_ANY;
283
284 return receive_message(imv_id, connection_id, 0, chunk_create(msg, msg_len),
285 msg_vid, msg_subtype, 0, TNC_IMVID_ANY);
286 }
287
288 /**
289 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
290 */
291 TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id,
292 TNC_ConnectionID connection_id,
293 TNC_UInt32 msg_flags,
294 TNC_BufferReference msg,
295 TNC_UInt32 msg_len,
296 TNC_VendorID msg_vid,
297 TNC_MessageSubtype msg_subtype,
298 TNC_UInt32 src_imc_id,
299 TNC_UInt32 dst_imv_id)
300 {
301 return receive_message(imv_id, connection_id, msg_flags,
302 chunk_create(msg, msg_len), msg_vid, msg_subtype,
303 src_imc_id, dst_imv_id);
304 }
305
306 /**
307 * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3
308 */
309 TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
310 TNC_ConnectionID connection_id)
311 {
312 if (!imv_os)
313 {
314 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
315 return TNC_RESULT_NOT_INITIALIZED;
316 }
317 return imv_os->provide_recommendation(imv_os, connection_id,
318 TNC_IMCID_ANY);
319 }
320
321 /**
322 * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3
323 */
324 TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
325 TNC_ConnectionID connection_id)
326 {
327 imv_state_t *state;
328 imv_os_state_t *os_state;
329 TNC_Result result = TNC_RESULT_SUCCESS;
330
331 if (!imv_os)
332 {
333 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
334 return TNC_RESULT_NOT_INITIALIZED;
335 }
336
337 /* get current IMV state */
338 if (!imv_os->get_state(imv_os, connection_id, &state))
339 {
340 return TNC_RESULT_FATAL;
341 }
342 os_state = (imv_os_state_t*)state;
343
344 if (os_state->get_info(os_state) == NULL)
345 {
346 pa_tnc_attr_t *attr;
347 linked_list_t *attr_list;
348 ietf_attr_attr_request_t *attr_cast;
349
350 attr_list = linked_list_create();
351 attr = ietf_attr_attr_request_create(PEN_IETF,
352 IETF_ATTR_PRODUCT_INFORMATION);
353 attr_cast = (ietf_attr_attr_request_t*)attr;
354 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION);
355 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_FORWARDING_ENABLED);
356 attr_list->insert_last(attr_list, attr);
357 result = imv_os->send_message(imv_os, connection_id, FALSE, imv_id,
358 TNC_IMCID_ANY, attr_list);
359 attr_list->destroy(attr_list);
360 }
361
362 return result;
363 }
364
365 /**
366 * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
367 */
368 TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
369 {
370 if (!imv_os)
371 {
372 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
373 return TNC_RESULT_NOT_INITIALIZED;
374 }
375 imv_os->destroy(imv_os);
376 imv_os = NULL;
377
378 return TNC_RESULT_SUCCESS;
379 }
380
381 /**
382 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3
383 */
384 TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
385 TNC_TNCS_BindFunctionPointer bind_function)
386 {
387 if (!imv_os)
388 {
389 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
390 return TNC_RESULT_NOT_INITIALIZED;
391 }
392 return imv_os->bind_functions(imv_os, bind_function);
393 }