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