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