implemented ITA Get Settings and ITA Settings attributes
[strongswan.git] / src / libimcv / plugins / imc_os / imc_os.c
1 /*
2 * Copyright (C) 2011-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 "imc_os_state.h"
17
18 #include <imc/imc_agent.h>
19 #include <imc/imc_msg.h>
20 #include <ietf/ietf_attr.h>
21 #include <ietf/ietf_attr_attr_request.h>
22 #include <ietf/ietf_attr_default_pwd_enabled.h>
23 #include <ietf/ietf_attr_fwd_enabled.h>
24 #include <ietf/ietf_attr_installed_packages.h>
25 #include <ietf/ietf_attr_numeric_version.h>
26 #include <ietf/ietf_attr_op_status.h>
27 #include <ietf/ietf_attr_product_info.h>
28 #include <ietf/ietf_attr_remediation_instr.h>
29 #include <ietf/ietf_attr_string_version.h>
30 #include <ita/ita_attr.h>
31 #include <ita/ita_attr_get_settings.h>
32 #include <ita/ita_attr_settings.h>
33 #include <os_info/os_info.h>
34
35 #include <tncif_pa_subtypes.h>
36
37 #include <pen/pen.h>
38 #include <utils/debug.h>
39
40 /* IMC definitions */
41
42 static const char imc_name[] = "OS";
43
44 static pen_type_t msg_types[] = {
45 { PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM }
46 };
47
48 static imc_agent_t *imc_os;
49 static os_info_t *os;
50
51 /**
52 * see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
53 */
54 TNC_Result TNC_IMC_Initialize(TNC_IMCID imc_id,
55 TNC_Version min_version,
56 TNC_Version max_version,
57 TNC_Version *actual_version)
58 {
59 if (imc_os)
60 {
61 DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
62 return TNC_RESULT_ALREADY_INITIALIZED;
63 }
64 imc_os = imc_agent_create(imc_name, msg_types, countof(msg_types),
65 imc_id, actual_version);
66 if (!imc_os)
67 {
68 return TNC_RESULT_FATAL;
69 }
70
71 os = os_info_create();
72 if (!os)
73 {
74 imc_os->destroy(imc_os);
75 imc_os = NULL;
76
77 return TNC_RESULT_FATAL;
78 }
79
80 if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
81 {
82 DBG1(DBG_IMC, "no common IF-IMC version");
83 return TNC_RESULT_NO_COMMON_VERSION;
84 }
85 return TNC_RESULT_SUCCESS;
86 }
87
88 /**
89 * see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
90 */
91 TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id,
92 TNC_ConnectionID connection_id,
93 TNC_ConnectionState new_state)
94 {
95 imc_state_t *state;
96
97 if (!imc_os)
98 {
99 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
100 return TNC_RESULT_NOT_INITIALIZED;
101 }
102 switch (new_state)
103 {
104 case TNC_CONNECTION_STATE_CREATE:
105 state = imc_os_state_create(connection_id);
106 return imc_os->create_state(imc_os, state);
107 case TNC_CONNECTION_STATE_HANDSHAKE:
108 if (imc_os->change_state(imc_os, connection_id, new_state,
109 &state) != TNC_RESULT_SUCCESS)
110 {
111 return TNC_RESULT_FATAL;
112 }
113 state->set_result(state, imc_id,
114 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
115 return TNC_RESULT_SUCCESS;
116 case TNC_CONNECTION_STATE_DELETE:
117 return imc_os->delete_state(imc_os, connection_id);
118 default:
119 return imc_os->change_state(imc_os, connection_id,
120 new_state, NULL);
121 }
122 }
123
124 /**
125 * Add IETF Product Information attribute to the send queue
126 */
127 static void add_product_info(imc_msg_t *msg)
128 {
129 pa_tnc_attr_t *attr;
130 chunk_t os_name;
131 pen_t vendor_id = PEN_IETF;
132 char *vendor;
133 int i;
134
135 typedef struct vendor_pen_t {
136 char *vendor;
137 pen_t pen;
138 } vendor_pen_t;
139
140 vendor_pen_t vendor_pens[] = {
141 { "Debian", PEN_DEBIAN },
142 { "Ubuntu", PEN_CANONICAL }
143 };
144
145 os_name = os->get_name(os);
146 for (i = 0; i < countof(vendor_pens); i++)
147 {
148 vendor = vendor_pens[i].vendor;
149 if (chunk_equals(os_name, chunk_create(vendor, strlen(vendor))))
150 {
151 vendor_id = vendor_pens[i].pen;
152 break;
153 }
154 }
155 attr = ietf_attr_product_info_create(vendor_id, 0, os_name);
156 msg->add_attribute(msg, attr);
157 }
158
159 /**
160 * Add IETF Numeric Version attribute to the send queue
161 */
162 static void add_numeric_version(imc_msg_t *msg)
163 {
164 pa_tnc_attr_t *attr;
165 u_int32_t major, minor;
166
167 os->get_numeric_version(os, &major, &minor);
168 DBG1(DBG_IMC, "operating system numeric version is %d.%d",
169 major, minor);
170
171 attr = ietf_attr_numeric_version_create(major, minor, 0, 0, 0);
172 msg->add_attribute(msg, attr);
173 }
174
175 /**
176 * Add IETF String Version attribute to the send queue
177 */
178 static void add_string_version(imc_msg_t *msg)
179 {
180 pa_tnc_attr_t *attr;
181
182 attr = ietf_attr_string_version_create(os->get_version(os),
183 chunk_empty, chunk_empty);
184 msg->add_attribute(msg, attr);
185 }
186
187 /**
188 * Add IETF Operational Status attribute to the send queue
189 */
190 static void add_op_status(imc_msg_t *msg)
191 {
192 pa_tnc_attr_t *attr;
193 time_t uptime, last_boot;
194
195 uptime = os->get_uptime(os);
196 last_boot = uptime ? time(NULL) - uptime : UNDEFINED_TIME;
197 if (last_boot != UNDEFINED_TIME)
198 {
199 DBG1(DBG_IMC, "last boot: %T, %u s ago", &last_boot, TRUE, uptime);
200 }
201 attr = ietf_attr_op_status_create(OP_STATUS_OPERATIONAL,
202 OP_RESULT_SUCCESSFUL, last_boot);
203 msg->add_attribute(msg, attr);
204 }
205
206 /**
207 * Add IETF Forwarding Enabled attribute to the send queue
208 */
209 static void add_fwd_enabled(imc_msg_t *msg)
210 {
211 pa_tnc_attr_t *attr;
212 os_fwd_status_t fwd_status;
213
214 fwd_status = os->get_fwd_status(os);
215 DBG1(DBG_IMC, "IPv4 forwarding status: %N",
216 os_fwd_status_names, fwd_status);
217 attr = ietf_attr_fwd_enabled_create(fwd_status);
218 msg->add_attribute(msg, attr);
219 }
220
221 /**
222 * Add IETF Factory Default Password Enabled attribute to the send queue
223 */
224 static void add_default_pwd_enabled(imc_msg_t *msg)
225 {
226 pa_tnc_attr_t *attr;
227
228 DBG1(DBG_IMC, "factory default password: disabled");
229 attr = ietf_attr_default_pwd_enabled_create(FALSE);
230 msg->add_attribute(msg, attr);
231 }
232
233 /**
234 * Add an IETF Installed Packages attribute to the send queue
235 */
236 static void add_installed_packages(imc_msg_t *msg)
237 {
238 pa_tnc_attr_t *attr;
239 ietf_attr_installed_packages_t *attr_cast;
240 chunk_t libc_name = { "libc-bin", 8 };
241 chunk_t libc_version = { "2.15-0ubuntu10.2", 16 };
242 chunk_t selinux_name = { "selinux", 7 };
243 chunk_t selinux_version = { "1:0.11", 6 };
244
245 attr = ietf_attr_installed_packages_create();
246 attr_cast = (ietf_attr_installed_packages_t*)attr;
247 attr_cast->add(attr_cast, libc_name, libc_version);
248 attr_cast->add(attr_cast, selinux_name, selinux_version);
249 msg->add_attribute(msg, attr);
250 }
251
252 /**
253 * Add ITA Settings attribute to the send queue
254 */
255 static void add_settings(enumerator_t *enumerator, imc_msg_t *msg)
256 {
257 pa_tnc_attr_t *attr = NULL;
258 ita_attr_settings_t *attr_cast;
259 chunk_t value;
260 char *name;
261 bool first = TRUE;
262
263 while (enumerator->enumerate(enumerator, &name))
264 {
265 DBG1(DBG_IMC, "setting '%s'", name);
266
267 value = os->get_setting(os, name);
268 if (!value.ptr)
269 {
270 DBG1(DBG_IMC, " failed to get setting");
271 continue;
272 }
273 if (first)
274 {
275 attr = ita_attr_settings_create();
276 first = FALSE;
277 }
278 attr_cast = (ita_attr_settings_t*)attr;
279 attr_cast->add(attr_cast, name, value);
280 chunk_free(&value);
281 }
282
283 if (attr)
284 {
285 msg->add_attribute(msg, attr);
286 }
287 }
288
289 /**
290 * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
291 */
292 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
293 TNC_ConnectionID connection_id)
294 {
295 imc_state_t *state;
296 imc_msg_t *out_msg;
297 TNC_Result result = TNC_RESULT_SUCCESS;
298
299 if (!imc_os)
300 {
301 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
302 return TNC_RESULT_NOT_INITIALIZED;
303 }
304 if (!imc_os->get_state(imc_os, connection_id, &state))
305 {
306 return TNC_RESULT_FATAL;
307 }
308 if (lib->settings->get_bool(lib->settings,
309 "libimcv.plugins.imc-os.send_info", TRUE))
310 {
311 out_msg = imc_msg_create(imc_os, state, connection_id, imc_id,
312 TNC_IMVID_ANY, msg_types[0]);
313 add_product_info(out_msg);
314 add_string_version(out_msg);
315 add_numeric_version(out_msg);
316 add_op_status(out_msg);
317 add_fwd_enabled(out_msg);
318 add_default_pwd_enabled(out_msg);
319
320 /* send PA-TNC message with the excl flag not set */
321 result = out_msg->send(out_msg, FALSE);
322 out_msg->destroy(out_msg);
323 }
324
325 return result;
326 }
327
328 static TNC_Result receive_message(imc_msg_t *in_msg)
329 {
330 imc_msg_t *out_msg;
331 enumerator_t *enumerator;
332 pa_tnc_attr_t *attr;
333 pen_type_t type;
334 TNC_Result result;
335 bool fatal_error = FALSE;
336
337 /* parse received PA-TNC message and handle local and remote errors */
338 result = in_msg->receive(in_msg, &fatal_error);
339 if (result != TNC_RESULT_SUCCESS)
340 {
341 return result;
342 }
343 out_msg = imc_msg_create_as_reply(in_msg);
344
345 /* analyze PA-TNC attributes */
346 enumerator = in_msg->create_attribute_enumerator(in_msg);
347 while (enumerator->enumerate(enumerator, &attr))
348 {
349 type = attr->get_type(attr);
350
351 if (type.vendor_id == PEN_IETF)
352 {
353 if (type.type == IETF_ATTR_ATTRIBUTE_REQUEST)
354 {
355 ietf_attr_attr_request_t *attr_cast;
356 pen_type_t *entry;
357 enumerator_t *e;
358
359 attr_cast = (ietf_attr_attr_request_t*)attr;
360
361 e = attr_cast->create_enumerator(attr_cast);
362 while (e->enumerate(e, &entry))
363 {
364 if (entry->vendor_id != PEN_IETF)
365 {
366 continue;
367 }
368 switch (entry->type)
369 {
370 case IETF_ATTR_PRODUCT_INFORMATION:
371 add_product_info(out_msg);
372 break;
373 case IETF_ATTR_STRING_VERSION:
374 add_string_version(out_msg);
375 break;
376 case IETF_ATTR_NUMERIC_VERSION:
377 add_numeric_version(out_msg);
378 break;
379 case IETF_ATTR_OPERATIONAL_STATUS:
380 add_op_status(out_msg);
381 break;
382 case IETF_ATTR_FORWARDING_ENABLED:
383 add_fwd_enabled(out_msg);
384 break;
385 case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED:
386 add_default_pwd_enabled(out_msg);
387 break;
388 case IETF_ATTR_INSTALLED_PACKAGES:
389 add_installed_packages(out_msg);
390 break;
391 default:
392 break;
393 }
394 }
395 e->destroy(e);
396 }
397 else if (type.type == IETF_ATTR_REMEDIATION_INSTRUCTIONS)
398 {
399 ietf_attr_remediation_instr_t *attr_cast;
400 pen_type_t parameters_type;
401 chunk_t parameters, string, lang_code;
402
403 attr_cast = (ietf_attr_remediation_instr_t*)attr;
404 parameters_type = attr_cast->get_parameters_type(attr_cast);
405 parameters = attr_cast->get_parameters(attr_cast);
406
407 if (parameters_type.vendor_id == PEN_IETF)
408 {
409 switch (parameters_type.type)
410 {
411 case IETF_REMEDIATION_PARAMETERS_URI:
412 DBG1(DBG_IMC, "remediation uri: '%.*s'",
413 parameters.len, parameters.ptr);
414 break;
415 case IETF_REMEDIATION_PARAMETERS_STRING:
416 string = attr_cast->get_string(attr_cast, &lang_code);
417 DBG1(DBG_IMC, "remediation string: '%.*s' [%.*s]",
418 string.len, string.ptr,
419 lang_code.len, lang_code.ptr);
420 break;
421 default:
422 DBG1(DBG_IMC, "remediation parameters %B", &parameters);
423 }
424 }
425 else
426 {
427 DBG1(DBG_IMC, "remediation parameters %B", &parameters);
428 }
429 }
430 }
431 else if (type.vendor_id == PEN_ITA && type.type == ITA_ATTR_GET_SETTINGS)
432 {
433 ita_attr_get_settings_t *attr_cast;
434 enumerator_t *e;
435
436 attr_cast = (ita_attr_get_settings_t*)attr;
437
438 e = attr_cast->create_enumerator(attr_cast);
439 add_settings(e, out_msg);
440 e->destroy(e);
441 }
442 }
443 enumerator->destroy(enumerator);
444
445 if (fatal_error)
446 {
447 result = TNC_RESULT_FATAL;
448 }
449 else
450 {
451 result = out_msg->send(out_msg, TRUE);
452 }
453 out_msg->destroy(out_msg);
454
455 return result;
456 }
457
458 /**
459 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
460
461 */
462 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
463 TNC_ConnectionID connection_id,
464 TNC_BufferReference msg,
465 TNC_UInt32 msg_len,
466 TNC_MessageType msg_type)
467 {
468 imc_state_t *state;
469 imc_msg_t *in_msg;
470 TNC_Result result;
471
472 if (!imc_os)
473 {
474 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
475 return TNC_RESULT_NOT_INITIALIZED;
476 }
477 if (!imc_os->get_state(imc_os, connection_id, &state))
478 {
479 return TNC_RESULT_FATAL;
480 }
481 in_msg = imc_msg_create_from_data(imc_os, state, connection_id, msg_type,
482 chunk_create(msg, msg_len));
483 result = receive_message(in_msg);
484 in_msg->destroy(in_msg);
485
486 return result;
487 }
488
489 /**
490 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
491 */
492 TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
493 TNC_ConnectionID connection_id,
494 TNC_UInt32 msg_flags,
495 TNC_BufferReference msg,
496 TNC_UInt32 msg_len,
497 TNC_VendorID msg_vid,
498 TNC_MessageSubtype msg_subtype,
499 TNC_UInt32 src_imv_id,
500 TNC_UInt32 dst_imc_id)
501 {
502 imc_state_t *state;
503 imc_msg_t *in_msg;
504 TNC_Result result;
505
506 if (!imc_os)
507 {
508 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
509 return TNC_RESULT_NOT_INITIALIZED;
510 }
511 if (!imc_os->get_state(imc_os, connection_id, &state))
512 {
513 return TNC_RESULT_FATAL;
514 }
515 in_msg = imc_msg_create_from_long_data(imc_os, state, connection_id,
516 src_imv_id, dst_imc_id,msg_vid, msg_subtype,
517 chunk_create(msg, msg_len));
518 result =receive_message(in_msg);
519 in_msg->destroy(in_msg);
520
521 return result;
522 }
523
524 /**
525 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
526 */
527 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
528 TNC_ConnectionID connection_id)
529 {
530 if (!imc_os)
531 {
532 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
533 return TNC_RESULT_NOT_INITIALIZED;
534 }
535 return TNC_RESULT_SUCCESS;
536 }
537
538 /**
539 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
540 */
541 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
542 {
543 if (!imc_os)
544 {
545 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
546 return TNC_RESULT_NOT_INITIALIZED;
547 }
548 imc_os->destroy(imc_os);
549 imc_os = NULL;
550
551 os->destroy(os);
552 os = NULL;
553
554 return TNC_RESULT_SUCCESS;
555 }
556
557 /**
558 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
559 */
560 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
561 TNC_TNCC_BindFunctionPointer bind_function)
562 {
563 if (!imc_os)
564 {
565 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
566 return TNC_RESULT_NOT_INITIALIZED;
567 }
568 return imc_os->bind_functions(imc_os, bind_function);
569 }