c2ad76498c105fb147d707d7fc31079e336ae681
[strongswan.git] / src / libimcv / plugins / imv_os / imv_os_batch_ending.c
1 /*
2 * Copyright (C) 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
16 #include "imv_os_batch_ending.h"
17 #include "imv_os_state.h"
18 #include "imv_os_database.h"
19
20 #include <imcv.h>
21 #include <imv/imv_msg.h>
22 #include <ietf/ietf_attr_attr_request.h>
23 #include <ita/ita_attr.h>
24 #include <ita/ita_attr_get_settings.h>
25
26 #include <utils/debug.h>
27
28 /**
29 * Build an IETF Attribute Request attribute for missing attributes
30 */
31 static pa_tnc_attr_t* build_attr_request(u_int received)
32 {
33 pa_tnc_attr_t *attr;
34 ietf_attr_attr_request_t *attr_cast;
35
36 attr = ietf_attr_attr_request_create(PEN_RESERVED, 0);
37 attr_cast = (ietf_attr_attr_request_t*)attr;
38
39 if (!(received & IMV_OS_ATTR_PRODUCT_INFORMATION) ||
40 !(received & IMV_OS_ATTR_STRING_VERSION))
41 {
42 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION);
43 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION);
44 }
45 if (!(received & IMV_OS_ATTR_NUMERIC_VERSION))
46 {
47 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_NUMERIC_VERSION);
48 }
49 if (!(received & IMV_OS_ATTR_OPERATIONAL_STATUS))
50 {
51 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_OPERATIONAL_STATUS);
52 }
53 if (!(received & IMV_OS_ATTR_FORWARDING_ENABLED))
54 {
55 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_FORWARDING_ENABLED);
56 }
57 if (!(received & IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED))
58 {
59 attr_cast->add(attr_cast, PEN_IETF,
60 IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED);
61 }
62 if (!(received & IMV_OS_ATTR_DEVICE_ID))
63 {
64 attr_cast->add(attr_cast, PEN_ITA, ITA_ATTR_DEVICE_ID);
65 }
66
67 return attr;
68 }
69
70 /**
71 * See header
72 */
73 TNC_Result imv_os_batch_ending(imv_agent_t *imv_os, imv_state_t *state,
74 TNC_IMVID imv_id, pen_type_t msg_type)
75 {
76 imv_msg_t *out_msg;
77 imv_session_t *session;
78 imv_workitem_t *workitem;
79 imv_os_state_t *os_state;
80 imv_os_handshake_state_t handshake_state;
81 pa_tnc_attr_t *attr;
82 TNC_ConnectionID connection_id;
83 TNC_Result result = TNC_RESULT_SUCCESS;
84 bool no_workitems = TRUE;
85 enumerator_t *enumerator;
86 u_int received;
87
88 os_state = (imv_os_state_t*)state;
89 handshake_state = os_state->get_handshake_state(os_state);
90 received = os_state->get_received(os_state);
91 connection_id = state->get_connection_id(state);
92 session = state->get_session(state);
93
94 /* create an empty out message - we might need it */
95 out_msg = imv_msg_create(imv_os, state, connection_id, imv_id,
96 TNC_IMCID_ANY, msg_type);
97
98 if (handshake_state == IMV_OS_STATE_INIT)
99 {
100 if ((received & IMV_OS_ATTR_MUST) != IMV_OS_ATTR_MUST)
101 {
102 /* create attribute request for missing mandatory attributes */
103 out_msg->add_attribute(out_msg, build_attr_request(received));
104 }
105 }
106
107 if (handshake_state < IMV_OS_STATE_POLICY_START)
108 {
109 if (((received & IMV_OS_ATTR_PRODUCT_INFORMATION) &&
110 (received & IMV_OS_ATTR_STRING_VERSION)) &&
111 ((received & IMV_OS_ATTR_DEVICE_ID) ||
112 (handshake_state == IMV_OS_STATE_ATTR_REQ)))
113 {
114 if (imcv_db)
115 {
116 /* trigger the policy manager */
117 imcv_db->policy_script(imcv_db, session, TRUE);
118 }
119 else
120 {
121 DBG2(DBG_IMV, "no workitems available - no evaluation possible");
122 state->set_recommendation(state,
123 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
124 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
125 }
126 handshake_state = IMV_OS_STATE_POLICY_START;
127 }
128 else if (handshake_state == IMV_OS_STATE_ATTR_REQ)
129 {
130 /**
131 * both the IETF Product Information and IETF String Version
132 * attribute should have been present
133 */
134 state->set_recommendation(state,
135 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
136 TNC_IMV_EVALUATION_RESULT_ERROR);
137
138 /* send assessment */
139 result = out_msg->send_assessment(out_msg);
140 out_msg->destroy(out_msg);
141
142 if (result != TNC_RESULT_SUCCESS)
143 {
144 return result;
145 }
146 return imv_os->provide_recommendation(imv_os, state);
147 }
148 else
149 {
150 handshake_state = IMV_OS_STATE_ATTR_REQ;
151 }
152 os_state->set_handshake_state(os_state, handshake_state);
153 }
154
155 if (handshake_state == IMV_OS_STATE_POLICY_START && session)
156 {
157 enumerator = session->create_workitem_enumerator(session);
158 if (enumerator)
159 {
160 while (enumerator->enumerate(enumerator, &workitem))
161 {
162 if (workitem->get_imv_id(workitem) != TNC_IMVID_ANY)
163 {
164 continue;
165 }
166 no_workitems = FALSE;
167
168 switch (workitem->get_type(workitem))
169 {
170 case IMV_WORKITEM_PACKAGES:
171 attr = ietf_attr_attr_request_create(PEN_IETF,
172 IETF_ATTR_INSTALLED_PACKAGES);
173 out_msg->add_attribute(out_msg, attr);
174 break;
175 case IMV_WORKITEM_UNKNOWN_SOURCE:
176 attr = ita_attr_get_settings_create(
177 "install_non_market_apps");
178 out_msg->add_attribute(out_msg, attr);
179 break;
180 case IMV_WORKITEM_FORWARDING:
181 case IMV_WORKITEM_DEFAULT_PWD:
182 break;
183 default:
184 continue;
185 }
186 workitem->set_imv_id(workitem, imv_id);
187 }
188 enumerator->destroy(enumerator);
189
190 if (no_workitems)
191 {
192 DBG2(DBG_IMV, "no workitems generated - no evaluation requested");
193 state->set_recommendation(state,
194 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
195 TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
196 }
197 handshake_state = IMV_OS_STATE_WORKITEMS;
198 os_state->set_handshake_state(os_state, handshake_state);
199 }
200 }
201
202 if (handshake_state == IMV_OS_STATE_WORKITEMS && session)
203 {
204 TNC_IMV_Evaluation_Result eval;
205 TNC_IMV_Action_Recommendation rec;
206 char buf[BUF_LEN], *result_str;
207 bool fail;
208
209 enumerator = session->create_workitem_enumerator(session);
210 while (enumerator->enumerate(enumerator, &workitem))
211 {
212 if (workitem->get_imv_id(workitem) != imv_id)
213 {
214 continue;
215 }
216 eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
217
218 switch (workitem->get_type(workitem))
219 {
220 case IMV_WORKITEM_PACKAGES:
221 {
222 int count, count_update, count_blacklist, count_ok;
223
224 if (!(received & IMV_OS_ATTR_INSTALLED_PACKAGES) ||
225 os_state->get_angel_count(os_state))
226 {
227 continue;
228 }
229 os_state->get_count(os_state, &count, &count_update,
230 &count_blacklist, &count_ok);
231 fail = count_update || count_blacklist;
232 eval = fail ? TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR :
233 TNC_IMV_EVALUATION_RESULT_COMPLIANT;
234 snprintf(buf, BUF_LEN, "processed %d packages: "
235 "%d not updated, %d blacklisted, %d ok, "
236 "%d not found",
237 count, count_update, count_blacklist, count_ok,
238 count - count_update - count_blacklist - count_ok);
239 result_str = buf;
240 break;
241 }
242 case IMV_WORKITEM_UNKNOWN_SOURCE:
243 if (!(received & IMV_OS_ATTR_SETTINGS))
244 {
245 continue;
246 }
247 fail = os_state->get_os_settings(os_state) &
248 OS_SETTINGS_UNKNOWN_SOURCE;
249 eval = fail ? TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR :
250 TNC_IMV_EVALUATION_RESULT_COMPLIANT;
251 result_str = fail ? "unknown sources enabled" : "";
252 break;
253 case IMV_WORKITEM_FORWARDING:
254 if (!(received & IMV_OS_ATTR_FORWARDING_ENABLED))
255 {
256 continue;
257 }
258 fail = os_state->get_os_settings(os_state) &
259 OS_SETTINGS_FWD_ENABLED;
260 eval = fail ? TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR :
261 TNC_IMV_EVALUATION_RESULT_COMPLIANT;
262 result_str = fail ? "forwarding enabled" : "";
263 break;
264 case IMV_WORKITEM_DEFAULT_PWD:
265 if (!(received & IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED))
266 {
267 continue;
268 }
269 fail = os_state->get_os_settings(os_state) &
270 OS_SETTINGS_DEFAULT_PWD_ENABLED;
271 eval = fail ? TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MAJOR :
272 TNC_IMV_EVALUATION_RESULT_COMPLIANT;
273 result_str = fail ? "default password enabled" : "";
274 break;
275 default:
276 continue;
277 }
278 if (eval != TNC_IMV_EVALUATION_RESULT_DONT_KNOW)
279 {
280 session->remove_workitem(session, enumerator);
281 rec = workitem->set_result(workitem, result_str, eval);
282 state->update_recommendation(state, rec, eval);
283 imcv_db->finalize_workitem(imcv_db, workitem);
284 workitem->destroy(workitem);
285 }
286 }
287 enumerator->destroy(enumerator);
288
289 /* finalized all workitems ? */
290 if (session->get_workitem_count(session, imv_id) == 0)
291 {
292 result = out_msg->send_assessment(out_msg);
293 out_msg->destroy(out_msg);
294 if (result != TNC_RESULT_SUCCESS)
295 {
296 return result;
297 }
298 return imv_os->provide_recommendation(imv_os, state);
299 }
300 }
301
302 /* send non-empty PA-TNC message with excl flag not set */
303 if (out_msg->get_attribute_count(out_msg))
304 {
305 result = out_msg->send(out_msg, FALSE);
306 }
307 out_msg->destroy(out_msg);
308
309 return result;
310 }
311