updated strongswan.conf man page
[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_string_version.h>
29 #include <ita/ita_attr.h>
30 #include <ita/ita_attr_get_settings.h>
31 #include <ita/ita_attr_settings.h>
32 #include <ita/ita_attr_angel.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 os_type_t os_type;
131 pen_t vendor_id = PEN_IETF;
132 int i;
133
134 typedef struct vendor_pen_t {
135 os_type_t os_type;
136 pen_t pen;
137 } vendor_pen_t;
138
139 vendor_pen_t vendor_pens[] = {
140 { OS_TYPE_DEBIAN, PEN_DEBIAN },
141 { OS_TYPE_UBUNTU, PEN_CANONICAL },
142 { OS_TYPE_FEDORA, PEN_FEDORA },
143 { OS_TYPE_REDHAT, PEN_REDHAT },
144 { OS_TYPE_ANDROID, PEN_GOOGLE }
145 };
146
147 os_type = os->get_type(os);
148 for (i = 0; i < countof(vendor_pens); i++)
149 {
150 if (os_type == vendor_pens[i].os_type)
151 {
152 vendor_id = vendor_pens[i].pen;
153 break;
154 }
155 }
156 attr = ietf_attr_product_info_create(vendor_id, 0, os->get_name(os));
157 msg->add_attribute(msg, attr);
158 }
159
160 /**
161 * Add IETF Numeric Version attribute to the send queue
162 */
163 static void add_numeric_version(imc_msg_t *msg)
164 {
165 pa_tnc_attr_t *attr;
166 u_int32_t major, minor;
167
168 os->get_numeric_version(os, &major, &minor);
169 DBG1(DBG_IMC, "operating system numeric version is %d.%d",
170 major, minor);
171
172 attr = ietf_attr_numeric_version_create(major, minor, 0, 0, 0);
173 msg->add_attribute(msg, attr);
174 }
175
176 /**
177 * Add IETF String Version attribute to the send queue
178 */
179 static void add_string_version(imc_msg_t *msg)
180 {
181 pa_tnc_attr_t *attr;
182
183 attr = ietf_attr_string_version_create(os->get_version(os),
184 chunk_empty, chunk_empty);
185 msg->add_attribute(msg, attr);
186 }
187
188 /**
189 * Add IETF Operational Status attribute to the send queue
190 */
191 static void add_op_status(imc_msg_t *msg)
192 {
193 pa_tnc_attr_t *attr;
194 time_t uptime, last_boot;
195
196 uptime = os->get_uptime(os);
197 last_boot = uptime ? time(NULL) - uptime : UNDEFINED_TIME;
198 if (last_boot != UNDEFINED_TIME)
199 {
200 DBG1(DBG_IMC, "last boot: %T, %u s ago", &last_boot, TRUE, uptime);
201 }
202 attr = ietf_attr_op_status_create(OP_STATUS_OPERATIONAL,
203 OP_RESULT_SUCCESSFUL, last_boot);
204 msg->add_attribute(msg, attr);
205 }
206
207 /**
208 * Add IETF Forwarding Enabled attribute to the send queue
209 */
210 static void add_fwd_enabled(imc_msg_t *msg)
211 {
212 pa_tnc_attr_t *attr;
213 os_fwd_status_t fwd_status;
214
215 fwd_status = os->get_fwd_status(os);
216 DBG1(DBG_IMC, "IPv4 forwarding status: %N",
217 os_fwd_status_names, fwd_status);
218 attr = ietf_attr_fwd_enabled_create(fwd_status);
219 msg->add_attribute(msg, attr);
220 }
221
222 /**
223 * Add IETF Factory Default Password Enabled attribute to the send queue
224 */
225 static void add_default_pwd_enabled(imc_msg_t *msg)
226 {
227 pa_tnc_attr_t *attr;
228
229 DBG1(DBG_IMC, "factory default password: disabled");
230 attr = ietf_attr_default_pwd_enabled_create(FALSE);
231 msg->add_attribute(msg, attr);
232 }
233
234 /**
235 * Add an IETF Installed Packages attribute to the send queue
236 */
237 static void add_installed_packages(imc_state_t *state, imc_msg_t *msg)
238 {
239 pa_tnc_attr_t *attr = NULL, *attr_angel;
240 ietf_attr_installed_packages_t *attr_cast;
241 enumerator_t *enumerator;
242 chunk_t name, version;
243 size_t max_attr_size, attr_size, entry_size;
244 bool first = TRUE;
245
246 /**
247 * Compute the maximum IETF Installed Packages attribute size
248 * leaving space for an additional ITA Angel attribute
249 */
250 max_attr_size = state->get_max_msg_len(state) - 8 - 12;
251
252 /* At least one IETF Installed Packages attribute is sent */
253 attr = ietf_attr_installed_packages_create();
254 attr_size = 12 + 4;
255
256 enumerator = os->create_package_enumerator(os);
257 if (enumerator)
258 {
259 while (enumerator->enumerate(enumerator, &name, &version))
260 {
261 DBG2(DBG_IMC, "package '%.*s' (%.*s)",
262 name.len, name.ptr, version.len, version.ptr);
263
264 entry_size = 2 + name.len + version.len;
265 if (attr_size + entry_size > max_attr_size)
266 {
267 if (first)
268 {
269 /**
270 * Send an ITA Start Angel attribute to the IMV signalling
271 * that multiple ITA Installed Package attributes follow.
272 */
273 attr_angel = ita_attr_angel_create(TRUE);
274 msg->add_attribute(msg, attr_angel);
275 first = FALSE;
276 }
277 msg->add_attribute(msg, attr);
278
279 /* create the next IETF Installed Packages attribute */
280 attr = ietf_attr_installed_packages_create();
281 attr_size = 12 + 4;
282 }
283 attr_cast = (ietf_attr_installed_packages_t*)attr;
284 attr_cast->add(attr_cast, name, version);
285 attr_size += entry_size;
286 }
287 enumerator->destroy(enumerator);
288 }
289 msg->add_attribute(msg, attr);
290
291 if (!first)
292 {
293 /**
294 * If we sent an ITA Start Angel attribute in the first place,
295 * terminate by appending a matching ITA Stop Angel attribute.
296 */
297 attr_angel = ita_attr_angel_create(FALSE);
298 msg->add_attribute(msg, attr_angel);
299 }
300 }
301
302 /**
303 * Add ITA Settings attribute to the send queue
304 */
305 static void add_settings(enumerator_t *enumerator, imc_msg_t *msg)
306 {
307 pa_tnc_attr_t *attr = NULL;
308 ita_attr_settings_t *attr_cast;
309 chunk_t value;
310 char *name;
311 bool first = TRUE;
312
313 while (enumerator->enumerate(enumerator, &name))
314 {
315 DBG1(DBG_IMC, "setting '%s'", name);
316
317 value = os->get_setting(os, name);
318 if (!value.ptr)
319 {
320 continue;
321 }
322 if (first)
323 {
324 attr = ita_attr_settings_create();
325 first = FALSE;
326 }
327 attr_cast = (ita_attr_settings_t*)attr;
328 attr_cast->add(attr_cast, name, value);
329 chunk_free(&value);
330 }
331
332 if (attr)
333 {
334 msg->add_attribute(msg, attr);
335 }
336 }
337
338 /**
339 * see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
340 */
341 TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
342 TNC_ConnectionID connection_id)
343 {
344 imc_state_t *state;
345 imc_msg_t *out_msg;
346 TNC_Result result = TNC_RESULT_SUCCESS;
347
348 if (!imc_os)
349 {
350 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
351 return TNC_RESULT_NOT_INITIALIZED;
352 }
353 if (!imc_os->get_state(imc_os, connection_id, &state))
354 {
355 return TNC_RESULT_FATAL;
356 }
357 if (lib->settings->get_bool(lib->settings,
358 "libimcv.plugins.imc-os.push_info", TRUE))
359 {
360 out_msg = imc_msg_create(imc_os, state, connection_id, imc_id,
361 TNC_IMVID_ANY, msg_types[0]);
362 add_product_info(out_msg);
363 add_string_version(out_msg);
364 add_numeric_version(out_msg);
365 add_op_status(out_msg);
366 add_fwd_enabled(out_msg);
367 add_default_pwd_enabled(out_msg);
368
369 /* send PA-TNC message with the excl flag not set */
370 result = out_msg->send(out_msg, FALSE);
371 out_msg->destroy(out_msg);
372 }
373
374 return result;
375 }
376
377 static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
378 {
379 imc_msg_t *out_msg;
380 enumerator_t *enumerator;
381 pa_tnc_attr_t *attr;
382 pen_type_t type;
383 TNC_Result result;
384 bool fatal_error = FALSE;
385
386 /* parse received PA-TNC message and handle local and remote errors */
387 result = in_msg->receive(in_msg, &fatal_error);
388 if (result != TNC_RESULT_SUCCESS)
389 {
390 return result;
391 }
392 out_msg = imc_msg_create_as_reply(in_msg);
393
394 /* analyze PA-TNC attributes */
395 enumerator = in_msg->create_attribute_enumerator(in_msg);
396 while (enumerator->enumerate(enumerator, &attr))
397 {
398 type = attr->get_type(attr);
399
400 if (type.vendor_id == PEN_IETF)
401 {
402 if (type.type == IETF_ATTR_ATTRIBUTE_REQUEST)
403 {
404 ietf_attr_attr_request_t *attr_cast;
405 pen_type_t *entry;
406 enumerator_t *e;
407
408 attr_cast = (ietf_attr_attr_request_t*)attr;
409
410 e = attr_cast->create_enumerator(attr_cast);
411 while (e->enumerate(e, &entry))
412 {
413 if (entry->vendor_id != PEN_IETF)
414 {
415 continue;
416 }
417 switch (entry->type)
418 {
419 case IETF_ATTR_PRODUCT_INFORMATION:
420 add_product_info(out_msg);
421 break;
422 case IETF_ATTR_STRING_VERSION:
423 add_string_version(out_msg);
424 break;
425 case IETF_ATTR_NUMERIC_VERSION:
426 add_numeric_version(out_msg);
427 break;
428 case IETF_ATTR_OPERATIONAL_STATUS:
429 add_op_status(out_msg);
430 break;
431 case IETF_ATTR_FORWARDING_ENABLED:
432 add_fwd_enabled(out_msg);
433 break;
434 case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED:
435 add_default_pwd_enabled(out_msg);
436 break;
437 case IETF_ATTR_INSTALLED_PACKAGES:
438 add_installed_packages(state, out_msg);
439 break;
440 default:
441 break;
442 }
443 }
444 e->destroy(e);
445 }
446 }
447 else if (type.vendor_id == PEN_ITA && type.type == ITA_ATTR_GET_SETTINGS)
448 {
449 ita_attr_get_settings_t *attr_cast;
450 enumerator_t *e;
451
452 attr_cast = (ita_attr_get_settings_t*)attr;
453
454 e = attr_cast->create_enumerator(attr_cast);
455 add_settings(e, out_msg);
456 e->destroy(e);
457 }
458 }
459 enumerator->destroy(enumerator);
460
461 if (fatal_error)
462 {
463 result = TNC_RESULT_FATAL;
464 }
465 else
466 {
467 result = out_msg->send(out_msg, TRUE);
468 }
469 out_msg->destroy(out_msg);
470
471 return result;
472 }
473
474 /**
475 * see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
476
477 */
478 TNC_Result TNC_IMC_ReceiveMessage(TNC_IMCID imc_id,
479 TNC_ConnectionID connection_id,
480 TNC_BufferReference msg,
481 TNC_UInt32 msg_len,
482 TNC_MessageType msg_type)
483 {
484 imc_state_t *state;
485 imc_msg_t *in_msg;
486 TNC_Result result;
487
488 if (!imc_os)
489 {
490 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
491 return TNC_RESULT_NOT_INITIALIZED;
492 }
493 if (!imc_os->get_state(imc_os, connection_id, &state))
494 {
495 return TNC_RESULT_FATAL;
496 }
497 in_msg = imc_msg_create_from_data(imc_os, state, connection_id, msg_type,
498 chunk_create(msg, msg_len));
499 result = receive_message(state, in_msg);
500 in_msg->destroy(in_msg);
501
502 return result;
503 }
504
505 /**
506 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
507 */
508 TNC_Result TNC_IMC_ReceiveMessageLong(TNC_IMCID imc_id,
509 TNC_ConnectionID connection_id,
510 TNC_UInt32 msg_flags,
511 TNC_BufferReference msg,
512 TNC_UInt32 msg_len,
513 TNC_VendorID msg_vid,
514 TNC_MessageSubtype msg_subtype,
515 TNC_UInt32 src_imv_id,
516 TNC_UInt32 dst_imc_id)
517 {
518 imc_state_t *state;
519 imc_msg_t *in_msg;
520 TNC_Result result;
521
522 if (!imc_os)
523 {
524 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
525 return TNC_RESULT_NOT_INITIALIZED;
526 }
527 if (!imc_os->get_state(imc_os, connection_id, &state))
528 {
529 return TNC_RESULT_FATAL;
530 }
531 in_msg = imc_msg_create_from_long_data(imc_os, state, connection_id,
532 src_imv_id, dst_imc_id,msg_vid, msg_subtype,
533 chunk_create(msg, msg_len));
534 result =receive_message(state, in_msg);
535 in_msg->destroy(in_msg);
536
537 return result;
538 }
539
540 /**
541 * see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
542 */
543 TNC_Result TNC_IMC_BatchEnding(TNC_IMCID imc_id,
544 TNC_ConnectionID connection_id)
545 {
546 if (!imc_os)
547 {
548 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
549 return TNC_RESULT_NOT_INITIALIZED;
550 }
551 return TNC_RESULT_SUCCESS;
552 }
553
554 /**
555 * see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
556 */
557 TNC_Result TNC_IMC_Terminate(TNC_IMCID imc_id)
558 {
559 if (!imc_os)
560 {
561 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
562 return TNC_RESULT_NOT_INITIALIZED;
563 }
564 imc_os->destroy(imc_os);
565 imc_os = NULL;
566
567 os->destroy(os);
568 os = NULL;
569
570 return TNC_RESULT_SUCCESS;
571 }
572
573 /**
574 * see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
575 */
576 TNC_Result TNC_IMC_ProvideBindFunction(TNC_IMCID imc_id,
577 TNC_TNCC_BindFunctionPointer bind_function)
578 {
579 if (!imc_os)
580 {
581 DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
582 return TNC_RESULT_NOT_INITIALIZED;
583 }
584 return imc_os->bind_functions(imc_os, bind_function);
585 }