69043ccbb20267c72c278b9e751d3f13aa8c5304
[strongswan.git] / src / libimcv / plugins / imv_os / imv_os.c
1 /*
2 * Copyright (C) 2012-2013 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 #define _GNU_SOURCE
16 #include <stdio.h>
17
18 #include "imv_os_state.h"
19 #include "imv_os_database.h"
20
21 #include <imcv.h>
22 #include <imv/imv_agent.h>
23 #include <imv/imv_msg.h>
24 #include <ietf/ietf_attr.h>
25 #include <ietf/ietf_attr_attr_request.h>
26 #include <ietf/ietf_attr_default_pwd_enabled.h>
27 #include <ietf/ietf_attr_fwd_enabled.h>
28 #include <ietf/ietf_attr_installed_packages.h>
29 #include <ietf/ietf_attr_numeric_version.h>
30 #include <ietf/ietf_attr_op_status.h>
31 #include <ietf/ietf_attr_pa_tnc_error.h>
32 #include <ietf/ietf_attr_product_info.h>
33 #include <ietf/ietf_attr_remediation_instr.h>
34 #include <ietf/ietf_attr_string_version.h>
35 #include <ita/ita_attr.h>
36 #include <ita/ita_attr_get_settings.h>
37 #include <ita/ita_attr_settings.h>
38 #include <ita/ita_attr_angel.h>
39 #include <ita/ita_attr_device_id.h>
40
41 #include <tncif_names.h>
42 #include <tncif_pa_subtypes.h>
43
44 #include <pen/pen.h>
45 #include <collections/linked_list.h>
46 #include <utils/debug.h>
47 #include <utils/lexparser.h>
48
49 /* IMV definitions */
50
51 static const char imv_name[] = "OS";
52
53 static pen_type_t msg_types[] = {
54 { PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM }
55 };
56
57 static imv_agent_t *imv_os;
58
59 static char non_market_apps_str[] = "install_non_market_apps";
60
61 /**
62 * Flag set when corresponding attribute has been received
63 */
64 typedef enum imv_os_attr_t imv_os_attr_t;
65
66 enum imv_os_attr_t {
67 IMV_OS_ATTR_PRODUCT_INFORMATION = (1<<0),
68 IMV_OS_ATTR_STRING_VERSION = (1<<1),
69 IMV_OS_ATTR_NUMERIC_VERSION = (1<<2),
70 IMV_OS_ATTR_OPERATIONAL_STATUS = (1<<3),
71 IMV_OS_ATTR_FORWARDING_ENABLED = (1<<4),
72 IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED = (1<<5),
73 IMV_OS_ATTR_DEVICE_ID = (1<<6),
74 IMV_OS_ATTR_MUST = (1<<7)-1,
75 IMV_OS_ATTR_INSTALLED_PACKAGES = (1<<7),
76 IMV_OS_ATTR_SETTINGS = (1<<8)
77 };
78
79 /**
80 * IMV OS database
81 */
82 static imv_os_database_t *os_db;
83
84 /*
85 * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3
86 */
87 TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
88 TNC_Version min_version,
89 TNC_Version max_version,
90 TNC_Version *actual_version)
91 {
92 if (imv_os)
93 {
94 DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
95 return TNC_RESULT_ALREADY_INITIALIZED;
96 }
97 imv_os = imv_agent_create(imv_name, msg_types, countof(msg_types),
98 imv_id, actual_version);
99 if (!imv_os)
100 {
101 return TNC_RESULT_FATAL;
102 }
103 if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
104 {
105 DBG1(DBG_IMV, "no common IF-IMV version");
106 return TNC_RESULT_NO_COMMON_VERSION;
107 }
108
109 /* attach OS database co-located with IMV database */
110 os_db = imv_os_database_create(imcv_db);
111
112 return TNC_RESULT_SUCCESS;
113 }
114
115 /**
116 * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3
117 */
118 TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
119 TNC_ConnectionID connection_id,
120 TNC_ConnectionState new_state)
121 {
122 imv_state_t *state;
123 imv_session_t *session;
124
125 if (!imv_os)
126 {
127 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
128 return TNC_RESULT_NOT_INITIALIZED;
129 }
130 switch (new_state)
131 {
132 case TNC_CONNECTION_STATE_CREATE:
133 state = imv_os_state_create(connection_id);
134 return imv_os->create_state(imv_os, state);
135 case TNC_CONNECTION_STATE_DELETE:
136 if (imcv_db && imv_os->get_state(imv_os, connection_id, &state))
137 {
138 session = state->get_session(state);
139 imcv_db->policy_script(imcv_db, session, FALSE);
140 }
141 return imv_os->delete_state(imv_os, connection_id);
142 default:
143 return imv_os->change_state(imv_os, connection_id,
144 new_state, NULL);
145 }
146 }
147
148 static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
149 {
150 imv_msg_t *out_msg;
151 imv_os_state_t *os_state;
152 enumerator_t *enumerator;
153 pa_tnc_attr_t *attr;
154 pen_type_t type;
155 TNC_Result result;
156 chunk_t os_name = chunk_empty;
157 chunk_t os_version = chunk_empty;
158 bool fatal_error = FALSE, assessment = FALSE;
159
160 os_state = (imv_os_state_t*)state;
161
162 /* parse received PA-TNC message and handle local and remote errors */
163 result = in_msg->receive(in_msg, &fatal_error);
164 if (result != TNC_RESULT_SUCCESS)
165 {
166 return result;
167 }
168
169 out_msg = imv_msg_create_as_reply(in_msg);
170
171 /* analyze PA-TNC attributes */
172 enumerator = in_msg->create_attribute_enumerator(in_msg);
173 while (enumerator->enumerate(enumerator, &attr))
174 {
175 type = attr->get_type(attr);
176
177 if (type.vendor_id == PEN_IETF)
178 {
179 switch (type.type)
180 {
181 case IETF_ATTR_PRODUCT_INFORMATION:
182 {
183 ietf_attr_product_info_t *attr_cast;
184 pen_t vendor_id;
185
186 os_state->set_received(os_state,
187 IMV_OS_ATTR_PRODUCT_INFORMATION);
188 attr_cast = (ietf_attr_product_info_t*)attr;
189 os_name = attr_cast->get_info(attr_cast, &vendor_id, NULL);
190 if (vendor_id != PEN_IETF)
191 {
192 DBG1(DBG_IMV, "operating system name is '%.*s' "
193 "from vendor %N", os_name.len, os_name.ptr,
194 pen_names, vendor_id);
195 }
196 else
197 {
198 DBG1(DBG_IMV, "operating system name is '%.*s'",
199 os_name.len, os_name.ptr);
200 }
201 break;
202 }
203 case IETF_ATTR_STRING_VERSION:
204 {
205 ietf_attr_string_version_t *attr_cast;
206
207 os_state->set_received(os_state,
208 IMV_OS_ATTR_STRING_VERSION);
209 attr_cast = (ietf_attr_string_version_t*)attr;
210 os_version = attr_cast->get_version(attr_cast, NULL, NULL);
211 if (os_version.len)
212 {
213 DBG1(DBG_IMV, "operating system version is '%.*s'",
214 os_version.len, os_version.ptr);
215 }
216 break;
217 }
218 case IETF_ATTR_NUMERIC_VERSION:
219 {
220 ietf_attr_numeric_version_t *attr_cast;
221 u_int32_t major, minor;
222
223 os_state->set_received(os_state,
224 IMV_OS_ATTR_NUMERIC_VERSION);
225 attr_cast = (ietf_attr_numeric_version_t*)attr;
226 attr_cast->get_version(attr_cast, &major, &minor);
227 DBG1(DBG_IMV, "operating system numeric version is %d.%d",
228 major, minor);
229 break;
230 }
231 case IETF_ATTR_OPERATIONAL_STATUS:
232 {
233 ietf_attr_op_status_t *attr_cast;
234 op_status_t op_status;
235 op_result_t op_result;
236 time_t last_boot;
237
238 os_state->set_received(os_state,
239 IMV_OS_ATTR_OPERATIONAL_STATUS);
240 attr_cast = (ietf_attr_op_status_t*)attr;
241 op_status = attr_cast->get_status(attr_cast);
242 op_result = attr_cast->get_result(attr_cast);
243 last_boot = attr_cast->get_last_use(attr_cast);
244 DBG1(DBG_IMV, "operational status: %N, result: %N",
245 op_status_names, op_status, op_result_names, op_result);
246 DBG1(DBG_IMV, "last boot: %T", &last_boot, TRUE);
247 break;
248 }
249 case IETF_ATTR_FORWARDING_ENABLED:
250 {
251 ietf_attr_fwd_enabled_t *attr_cast;
252 os_fwd_status_t fwd_status;
253
254 os_state->set_received(os_state,
255 IMV_OS_ATTR_FORWARDING_ENABLED);
256 attr_cast = (ietf_attr_fwd_enabled_t*)attr;
257 fwd_status = attr_cast->get_status(attr_cast);
258 DBG1(DBG_IMV, "IPv4 forwarding is %N",
259 os_fwd_status_names, fwd_status);
260 if (fwd_status == OS_FWD_ENABLED)
261 {
262 os_state->set_os_settings(os_state,
263 OS_SETTINGS_FWD_ENABLED);
264 }
265 break;
266 }
267 case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED:
268 {
269 ietf_attr_default_pwd_enabled_t *attr_cast;
270 bool default_pwd_status;
271
272 os_state->set_received(os_state,
273 IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED);
274 attr_cast = (ietf_attr_default_pwd_enabled_t*)attr;
275 default_pwd_status = attr_cast->get_status(attr_cast);
276 DBG1(DBG_IMV, "factory default password is %sabled",
277 default_pwd_status ? "en":"dis");
278 if (default_pwd_status)
279 {
280 os_state->set_os_settings(os_state,
281 OS_SETTINGS_DEFAULT_PWD_ENABLED);
282 }
283 break;
284 }
285 case IETF_ATTR_INSTALLED_PACKAGES:
286 {
287 ietf_attr_installed_packages_t *attr_cast;
288 enumerator_t *e;
289 status_t status;
290
291 os_state->set_received(os_state,
292 IMV_OS_ATTR_INSTALLED_PACKAGES);
293 if (!os_db)
294 {
295 break;
296 }
297 attr_cast = (ietf_attr_installed_packages_t*)attr;
298
299 e = attr_cast->create_enumerator(attr_cast);
300 status = os_db->check_packages(os_db, os_state, e);
301 e->destroy(e);
302
303 if (status == FAILED)
304 {
305 state->set_recommendation(state,
306 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
307 TNC_IMV_EVALUATION_RESULT_ERROR);
308 assessment = TRUE;
309 }
310 break;
311 }
312 default:
313 break;
314 }
315 }
316 else if (type.vendor_id == PEN_ITA)
317 {
318 switch (type.type)
319 {
320 case ITA_ATTR_SETTINGS:
321 {
322 ita_attr_settings_t *attr_cast;
323 enumerator_t *e;
324 char *name;
325 chunk_t value;
326
327 os_state->set_received(os_state, IMV_OS_ATTR_SETTINGS);
328
329 attr_cast = (ita_attr_settings_t*)attr;
330 e = attr_cast->create_enumerator(attr_cast);
331 while (e->enumerate(e, &name, &value))
332 {
333 if (streq(name, non_market_apps_str) &&
334 chunk_equals(value, chunk_from_chars('1')))
335 {
336 os_state->set_os_settings(os_state,
337 OS_SETTINGS_UNKNOWN_SOURCE);
338 }
339 DBG1(DBG_IMV, "setting '%s'\n %.*s",
340 name, value.len, value.ptr);
341 }
342 e->destroy(e);
343 break;
344 }
345 case ITA_ATTR_DEVICE_ID:
346 {
347 imv_session_t *session;
348 int device_id;
349 chunk_t value;
350
351 os_state->set_received(os_state, IMV_OS_ATTR_DEVICE_ID);
352
353 value = attr->get_value(attr);
354 DBG1(DBG_IMV, "device ID is %.*s", value.len, value.ptr);
355
356 if (imcv_db)
357 {
358 session = state->get_session(state);
359 device_id = imcv_db->add_device(imcv_db, session, value);
360 os_state->set_device_id(os_state, device_id);
361 }
362 break;
363 }
364 case ITA_ATTR_START_ANGEL:
365 os_state->set_angel_count(os_state, TRUE);
366 break;
367 case ITA_ATTR_STOP_ANGEL:
368 os_state->set_angel_count(os_state, FALSE);
369 break;
370 default:
371 break;
372 }
373 }
374 }
375 enumerator->destroy(enumerator);
376
377 /**
378 * The IETF Product Information and String Version attributes
379 * are supposed to arrive in the same PA-TNC message
380 */
381 if (os_name.len && os_version.len)
382 {
383 os_type_t os_type;
384
385 /* set the OS type, name and version */
386 os_type = os_type_from_name(os_name);
387 os_state->set_info(os_state,os_type, os_name, os_version);
388
389 if (imcv_db)
390 {
391 imcv_db->add_product(imcv_db, state->get_session(state),
392 os_state->get_info(os_state, NULL, NULL, NULL));
393 }
394 }
395
396 if (fatal_error)
397 {
398 state->set_recommendation(state,
399 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
400 TNC_IMV_EVALUATION_RESULT_ERROR);
401 assessment = TRUE;
402 }
403
404 if (assessment)
405 {
406 result = out_msg->send_assessment(out_msg);
407 out_msg->destroy(out_msg);
408 if (result != TNC_RESULT_SUCCESS)
409 {
410 return result;
411 }
412 return imv_os->provide_recommendation(imv_os, state);
413 }
414
415 /* send PA-TNC message with excl flag set */
416 result = out_msg->send(out_msg, TRUE);
417 out_msg->destroy(out_msg);
418
419 return result;
420 }
421
422 /**
423 * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3
424 */
425 TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
426 TNC_ConnectionID connection_id,
427 TNC_BufferReference msg,
428 TNC_UInt32 msg_len,
429 TNC_MessageType msg_type)
430 {
431 imv_state_t *state;
432 imv_msg_t *in_msg;
433 TNC_Result result;
434
435 if (!imv_os)
436 {
437 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
438 return TNC_RESULT_NOT_INITIALIZED;
439 }
440 if (!imv_os->get_state(imv_os, connection_id, &state))
441 {
442 return TNC_RESULT_FATAL;
443 }
444 in_msg = imv_msg_create_from_data(imv_os, state, connection_id, msg_type,
445 chunk_create(msg, msg_len));
446 result = receive_message(state, in_msg);
447 in_msg->destroy(in_msg);
448
449 return result;
450 }
451
452 /**
453 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
454 */
455 TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id,
456 TNC_ConnectionID connection_id,
457 TNC_UInt32 msg_flags,
458 TNC_BufferReference msg,
459 TNC_UInt32 msg_len,
460 TNC_VendorID msg_vid,
461 TNC_MessageSubtype msg_subtype,
462 TNC_UInt32 src_imc_id,
463 TNC_UInt32 dst_imv_id)
464 {
465 imv_state_t *state;
466 imv_msg_t *in_msg;
467 TNC_Result result;
468
469 if (!imv_os)
470 {
471 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
472 return TNC_RESULT_NOT_INITIALIZED;
473 }
474 if (!imv_os->get_state(imv_os, connection_id, &state))
475 {
476 return TNC_RESULT_FATAL;
477 }
478 in_msg = imv_msg_create_from_long_data(imv_os, state, connection_id,
479 src_imc_id, dst_imv_id, msg_vid, msg_subtype,
480 chunk_create(msg, msg_len));
481 result =receive_message(state, in_msg);
482 in_msg->destroy(in_msg);
483
484 return result;
485 }
486
487 /**
488 * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3
489 */
490 TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
491 TNC_ConnectionID connection_id)
492 {
493 imv_state_t *state;
494
495 if (!imv_os)
496 {
497 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
498 return TNC_RESULT_NOT_INITIALIZED;
499 }
500 if (!imv_os->get_state(imv_os, connection_id, &state))
501 {
502 return TNC_RESULT_FATAL;
503 }
504 return imv_os->provide_recommendation(imv_os, state);
505 }
506
507 /**
508 * Build an IETF Attribute Request attribute for missing attributes
509 */
510 static pa_tnc_attr_t* build_attr_request(u_int received)
511 {
512 pa_tnc_attr_t *attr;
513 ietf_attr_attr_request_t *attr_cast;
514
515 attr = ietf_attr_attr_request_create(PEN_RESERVED, 0);
516 attr_cast = (ietf_attr_attr_request_t*)attr;
517
518 if (!(received & IMV_OS_ATTR_PRODUCT_INFORMATION) ||
519 !(received & IMV_OS_ATTR_STRING_VERSION))
520 {
521 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION);
522 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION);
523 }
524 if (!(received & IMV_OS_ATTR_NUMERIC_VERSION))
525 {
526 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_NUMERIC_VERSION);
527 }
528 if (!(received & IMV_OS_ATTR_OPERATIONAL_STATUS))
529 {
530 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_OPERATIONAL_STATUS);
531 }
532 if (!(received & IMV_OS_ATTR_FORWARDING_ENABLED))
533 {
534 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_FORWARDING_ENABLED);
535 }
536 if (!(received & IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED))
537 {
538 attr_cast->add(attr_cast, PEN_IETF,
539 IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED);
540 }
541 if (!(received & IMV_OS_ATTR_DEVICE_ID))
542 {
543 attr_cast->add(attr_cast, PEN_ITA, ITA_ATTR_DEVICE_ID);
544 }
545
546 return attr;
547 }
548
549 /**
550 * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3
551 */
552 TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id, TNC_ConnectionID connection_id)
553 {
554 imv_msg_t *out_msg;
555 imv_state_t *state;
556 imv_session_t *session;
557 imv_workitem_t *workitem;
558 imv_os_state_t *os_state;
559 imv_os_handshake_state_t handshake_state;
560 pa_tnc_attr_t *attr;
561 TNC_Result result = TNC_RESULT_SUCCESS;
562 enumerator_t *enumerator;
563 u_int received;
564
565 if (!imv_os)
566 {
567 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
568 return TNC_RESULT_NOT_INITIALIZED;
569 }
570 if (!imv_os->get_state(imv_os, connection_id, &state))
571 {
572 return TNC_RESULT_FATAL;
573 }
574 os_state = (imv_os_state_t*)state;
575 handshake_state = os_state->get_handshake_state(os_state);
576 received = os_state->get_received(os_state);
577 session = state->get_session(state);
578
579 /* create an empty out message - we might need it */
580 out_msg = imv_msg_create(imv_os, state, connection_id, imv_id,
581 TNC_IMCID_ANY, msg_types[0]);
582
583 if (handshake_state == IMV_OS_STATE_INIT)
584 {
585 if ((received & IMV_OS_ATTR_MUST) != IMV_OS_ATTR_MUST)
586 {
587 /* create attribute request for missing mandatory attributes */
588 out_msg->add_attribute(out_msg, build_attr_request(received));
589 }
590 }
591
592 if (handshake_state < IMV_OS_STATE_POLICY_START)
593 {
594 if (((received & IMV_OS_ATTR_PRODUCT_INFORMATION) &&
595 (received & IMV_OS_ATTR_STRING_VERSION)) &&
596 ((received & IMV_OS_ATTR_DEVICE_ID) ||
597 (handshake_state == IMV_OS_STATE_ATTR_REQ)))
598 {
599 if (imcv_db)
600 {
601 /* trigger the policy manager */
602 imcv_db->policy_script(imcv_db, session, TRUE);
603 }
604 else
605 {
606 /* just gather information without evaluation */
607 state->set_recommendation(state,
608 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
609 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
610 }
611 handshake_state = IMV_OS_STATE_POLICY_START;
612 }
613 else if (handshake_state == IMV_OS_STATE_ATTR_REQ)
614 {
615 /**
616 * both the IETF Product Information and IETF String Version
617 * attribute should have been present
618 */
619 state->set_recommendation(state,
620 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
621 TNC_IMV_EVALUATION_RESULT_ERROR);
622
623 /* send assessment */
624 result = out_msg->send_assessment(out_msg);
625 out_msg->destroy(out_msg);
626
627 if (result != TNC_RESULT_SUCCESS)
628 {
629 return result;
630 }
631 return imv_os->provide_recommendation(imv_os, state);
632 }
633 else
634 {
635 handshake_state = IMV_OS_STATE_ATTR_REQ;
636 }
637 os_state->set_handshake_state(os_state, handshake_state);
638 }
639
640 if (handshake_state == IMV_OS_STATE_POLICY_START && session)
641 {
642 enumerator = session->create_workitem_enumerator(session);
643 if (enumerator)
644 {
645 while (enumerator->enumerate(enumerator, &workitem))
646 {
647 if (workitem->get_imv_id(workitem) != 0)
648 {
649 continue;
650 }
651 switch (workitem->get_type(workitem))
652 {
653 case IMV_WORKITEM_PACKAGES:
654 attr = ietf_attr_attr_request_create(PEN_IETF,
655 IETF_ATTR_INSTALLED_PACKAGES);
656 out_msg->add_attribute(out_msg, attr);
657 break;
658 case IMV_WORKITEM_UNKNOWN_SOURCE:
659 attr = ita_attr_get_settings_create(non_market_apps_str);
660 out_msg->add_attribute(out_msg, attr);
661 break;
662 case IMV_WORKITEM_FORWARDING:
663 case IMV_WORKITEM_DEFAULT_PWD:
664 break;
665 default:
666 continue;
667 }
668 workitem->set_imv_id(workitem, imv_id);
669 }
670 enumerator->destroy(enumerator);
671
672 handshake_state = IMV_OS_STATE_WORKITEMS;
673 os_state->set_handshake_state(os_state, handshake_state);
674 }
675 }
676
677 if (handshake_state == IMV_OS_STATE_WORKITEMS && session)
678 {
679 TNC_IMV_Evaluation_Result eval;
680 TNC_IMV_Action_Recommendation rec;
681 char buf[BUF_LEN], *result_str;
682 bool fail;
683
684 enumerator = session->create_workitem_enumerator(session);
685 while (enumerator->enumerate(enumerator, &workitem))
686 {
687 if (workitem->get_imv_id(workitem) != imv_id)
688 {
689 continue;
690 }
691 eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
692
693 switch (workitem->get_type(workitem))
694 {
695 case IMV_WORKITEM_PACKAGES:
696 {
697 int count, count_update, count_blacklist, count_ok;
698
699 if (!(received & IMV_OS_ATTR_INSTALLED_PACKAGES) ||
700 os_state->get_angel_count(os_state))
701 {
702 continue;
703 }
704 os_state->get_count(os_state, &count, &count_update,
705 &count_blacklist, &count_ok);
706 fail = count_update || count_blacklist;
707 eval = fail ? TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR :
708 TNC_IMV_EVALUATION_RESULT_COMPLIANT;
709 snprintf(buf, BUF_LEN, "processed %d packages: "
710 "%d not updated, %d blacklisted, %d ok, "
711 "%d not found",
712 count, count_update, count_blacklist, count_ok,
713 count - count_update - count_blacklist - count_ok);
714 result_str = buf;
715 break;
716 }
717 case IMV_WORKITEM_UNKNOWN_SOURCE:
718 if (!(received & IMV_OS_ATTR_SETTINGS))
719 {
720 continue;
721 }
722 fail = os_state->get_os_settings(os_state) &
723 OS_SETTINGS_UNKNOWN_SOURCE;
724 eval = fail ? TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR :
725 TNC_IMV_EVALUATION_RESULT_COMPLIANT;
726 result_str = fail ? "unknown sources enabled" : "";
727 break;
728 case IMV_WORKITEM_FORWARDING:
729 if (!(received & IMV_OS_ATTR_FORWARDING_ENABLED))
730 {
731 continue;
732 }
733 fail = os_state->get_os_settings(os_state) &
734 OS_SETTINGS_FWD_ENABLED;
735 eval = fail ? TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR :
736 TNC_IMV_EVALUATION_RESULT_COMPLIANT;
737 result_str = fail ? "forwarding enabled" : "";
738 break;
739 case IMV_WORKITEM_DEFAULT_PWD:
740 if (!(received & IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED))
741 {
742 continue;
743 }
744 fail = os_state->get_os_settings(os_state) &
745 OS_SETTINGS_DEFAULT_PWD_ENABLED;
746 eval = fail ? TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR :
747 TNC_IMV_EVALUATION_RESULT_COMPLIANT;
748 result_str = fail ? "default password enabled" : "";
749 break;
750 default:
751 continue;
752 }
753 if (eval != TNC_IMV_EVALUATION_RESULT_DONT_KNOW)
754 {
755 session->remove_workitem(session, enumerator);
756 rec = workitem->set_result(workitem, result_str, eval);
757 state->update_recommendation(state, rec, eval);
758 imcv_db->finalize_workitem(imcv_db, workitem);
759 workitem->destroy(workitem);
760 }
761 }
762 enumerator->destroy(enumerator);
763
764 /* finalized all workitems ? */
765 if (session->get_workitem_count(session, imv_id) == 0)
766 {
767 result = out_msg->send_assessment(out_msg);
768 out_msg->destroy(out_msg);
769 if (result != TNC_RESULT_SUCCESS)
770 {
771 return result;
772 }
773 return imv_os->provide_recommendation(imv_os, state);
774 }
775 }
776
777 /* send non-empty PA-TNC message with excl flag not set */
778 if (out_msg->get_attribute_count(out_msg))
779 {
780 result = out_msg->send(out_msg, FALSE);
781 }
782 out_msg->destroy(out_msg);
783
784 return result;
785 }
786
787 /**
788 * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
789 */
790 TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
791 {
792 if (!imv_os)
793 {
794 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
795 return TNC_RESULT_NOT_INITIALIZED;
796 }
797 DESTROY_IF(os_db);
798 os_db = NULL;
799
800 imv_os->destroy(imv_os);
801 imv_os = NULL;
802
803 return TNC_RESULT_SUCCESS;
804 }
805
806 /**
807 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3
808 */
809 TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
810 TNC_TNCS_BindFunctionPointer bind_function)
811 {
812 if (!imv_os)
813 {
814 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
815 return TNC_RESULT_NOT_INITIALIZED;
816 }
817 return imv_os->bind_functions(imv_os, bind_function);
818 }