implemented IETF Factory Default Password Enabled attribute
[strongswan.git] / src / libimcv / plugins / imv_os / imv_os.c
1 /*
2 * Copyright (C) 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 "imv_os_state.h"
17
18 #include <imv/imv_agent.h>
19 #include <pa_tnc/pa_tnc_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_pa_tnc_error.h>
26 #include <ietf/ietf_attr_product_info.h>
27 #include <ietf/ietf_attr_string_version.h>
28 #include <os_info/os_info.h>
29
30 #include <tncif_names.h>
31 #include <tncif_pa_subtypes.h>
32
33 #include <pen/pen.h>
34 #include <utils/linked_list.h>
35 #include <debug.h>
36
37 /* IMV definitions */
38
39 static const char imv_name[] = "OS";
40
41 #define IMV_VENDOR_ID PEN_IETF
42 #define IMV_SUBTYPE PA_SUBTYPE_IETF_OPERATING_SYSTEM
43
44 static imv_agent_t *imv_os;
45
46 /*
47 * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3
48 */
49 TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
50 TNC_Version min_version,
51 TNC_Version max_version,
52 TNC_Version *actual_version)
53 {
54 if (imv_os)
55 {
56 DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
57 return TNC_RESULT_ALREADY_INITIALIZED;
58 }
59 imv_os = imv_agent_create(imv_name, IMV_VENDOR_ID, IMV_SUBTYPE,
60 imv_id, actual_version);
61 if (!imv_os)
62 {
63 return TNC_RESULT_FATAL;
64 }
65 if (min_version > TNC_IFIMV_VERSION_1 || max_version < TNC_IFIMV_VERSION_1)
66 {
67 DBG1(DBG_IMV, "no common IF-IMV version");
68 return TNC_RESULT_NO_COMMON_VERSION;
69 }
70
71 return TNC_RESULT_SUCCESS;
72 }
73
74 /**
75 * see section 3.8.2 of TCG TNC IF-IMV Specification 1.3
76 */
77 TNC_Result TNC_IMV_NotifyConnectionChange(TNC_IMVID imv_id,
78 TNC_ConnectionID connection_id,
79 TNC_ConnectionState new_state)
80 {
81 imv_state_t *state;
82
83 if (!imv_os)
84 {
85 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
86 return TNC_RESULT_NOT_INITIALIZED;
87 }
88 switch (new_state)
89 {
90 case TNC_CONNECTION_STATE_CREATE:
91 state = imv_os_state_create(connection_id);
92 return imv_os->create_state(imv_os, state);
93 case TNC_CONNECTION_STATE_DELETE:
94 return imv_os->delete_state(imv_os, connection_id);
95 default:
96 return imv_os->change_state(imv_os, connection_id,
97 new_state, NULL);
98 }
99 }
100
101 static TNC_Result receive_message(TNC_IMVID imv_id,
102 TNC_ConnectionID connection_id,
103 TNC_UInt32 msg_flags,
104 chunk_t msg,
105 TNC_VendorID msg_vid,
106 TNC_MessageSubtype msg_subtype,
107 TNC_UInt32 src_imc_id,
108 TNC_UInt32 dst_imv_id)
109 {
110 pa_tnc_msg_t *pa_tnc_msg;
111 pa_tnc_attr_t *attr;
112 pen_type_t type;
113 linked_list_t *attr_list;
114 imv_state_t *state;
115 imv_os_state_t *os_state;
116 enumerator_t *enumerator;
117 TNC_Result result;
118 chunk_t os_name = chunk_empty;
119 chunk_t os_version = chunk_empty;
120 bool fatal_error, assessment = FALSE;
121
122 if (!imv_os)
123 {
124 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
125 return TNC_RESULT_NOT_INITIALIZED;
126 }
127
128 /* get current IMV state */
129 if (!imv_os->get_state(imv_os, connection_id, &state))
130 {
131 return TNC_RESULT_FATAL;
132 }
133 os_state = (imv_os_state_t*)state;
134
135 /* parse received PA-TNC message and automatically handle any errors */
136 result = imv_os->receive_message(imv_os, state, msg, msg_vid,
137 msg_subtype, src_imc_id, dst_imv_id, &pa_tnc_msg);
138
139 /* no parsed PA-TNC attributes available if an error occurred */
140 if (!pa_tnc_msg)
141 {
142 return result;
143 }
144
145 /* preprocess any IETF standard error attributes */
146 fatal_error = pa_tnc_msg->process_ietf_std_errors(pa_tnc_msg);
147
148 /* analyze PA-TNC attributes */
149 attr_list = linked_list_create();
150 enumerator = pa_tnc_msg->create_attribute_enumerator(pa_tnc_msg);
151 while (enumerator->enumerate(enumerator, &attr))
152 {
153 type = attr->get_type(attr);
154
155 if (type.vendor_id != PEN_IETF)
156 {
157 continue;
158 }
159 switch (type.type)
160 {
161 case IETF_ATTR_PRODUCT_INFORMATION:
162 {
163 ietf_attr_product_info_t *attr_cast;
164
165 attr_cast = (ietf_attr_product_info_t*)attr;
166 os_name = attr_cast->get_info(attr_cast, NULL, NULL);
167 DBG1(DBG_IMV, "operating system name is '%.*s'",
168 os_name.len, os_name.ptr);
169 break;
170 }
171 case IETF_ATTR_STRING_VERSION:
172 {
173 ietf_attr_string_version_t *attr_cast;
174
175 attr_cast = (ietf_attr_string_version_t*)attr;
176 os_version = attr_cast->get_version(attr_cast, NULL, NULL);
177 if (os_version.len)
178 {
179 DBG1(DBG_IMV, "operating system version is '%.*s'",
180 os_version.len, os_version.ptr);
181 }
182 break;
183 }
184 case IETF_ATTR_FORWARDING_ENABLED:
185 {
186 ietf_attr_fwd_enabled_t *attr_cast;
187 os_fwd_status_t fwd_status;
188
189 attr_cast = (ietf_attr_fwd_enabled_t*)attr;
190 fwd_status = attr_cast->get_status(attr_cast);
191 DBG1(DBG_IMV, "IPv4 forwarding status: %N",
192 os_fwd_status_names, fwd_status);
193 break;
194 }
195 case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED:
196 {
197 ietf_attr_default_pwd_enabled_t *attr_cast;
198 bool default_pwd_status;
199
200 attr_cast = (ietf_attr_default_pwd_enabled_t*)attr;
201 default_pwd_status = attr_cast->get_status(attr_cast);
202 DBG1(DBG_IMV, "factory default password: %sabled",
203 default_pwd_status ? "en":"dis");
204 break;
205 }
206 case IETF_ATTR_INSTALLED_PACKAGES:
207 {
208 ietf_attr_installed_packages_t *attr_cast;
209 enumerator_t *e;
210 chunk_t name, version;
211
212 attr_cast = (ietf_attr_installed_packages_t*)attr;
213 e = attr_cast->create_enumerator(attr_cast);
214 while (e->enumerate(e, &name, &version))
215 {
216 DBG1(DBG_IMV, "package '%.*s' %.*s", name.len, name.ptr,
217 version.len, version.ptr);
218 }
219 e->destroy(e);
220
221 state->set_recommendation(state,
222 TNC_IMV_ACTION_RECOMMENDATION_ALLOW,
223 TNC_IMV_EVALUATION_RESULT_COMPLIANT);
224 assessment = TRUE;
225 break;
226 }
227 default:
228 break;
229 }
230 }
231 enumerator->destroy(enumerator);
232
233 if (os_name.len && os_version.len)
234 {
235 char *product_info;
236
237 os_state->set_info(os_state, os_name, os_version);
238 product_info = os_state->get_info(os_state);
239
240 if (streq(product_info, "Windows 1.2.3"))
241 {
242 DBG1(DBG_IMV, "OS '%s' is not supported", product_info);
243
244 state->set_recommendation(state,
245 TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
246 TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR);
247 assessment = TRUE;
248 }
249 else
250 {
251 DBG1(DBG_IMV, "requesting installed packages for '%s'",
252 product_info);
253 attr = ietf_attr_attr_request_create(PEN_IETF,
254 IETF_ATTR_INSTALLED_PACKAGES);
255 attr_list->insert_last(attr_list, attr);
256 }
257 }
258 pa_tnc_msg->destroy(pa_tnc_msg);
259
260 if (fatal_error)
261 {
262 state->set_recommendation(state,
263 TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
264 TNC_IMV_EVALUATION_RESULT_ERROR);
265 assessment = TRUE;
266 }
267
268 if (assessment)
269 {
270 attr_list->destroy_offset(attr_list, offsetof(pa_tnc_attr_t, destroy));
271 return imv_os->provide_recommendation(imv_os, connection_id, src_imc_id);
272 }
273
274 result = imv_os->send_message(imv_os, connection_id, TRUE, imv_id,
275 src_imc_id, attr_list);
276 attr_list->destroy(attr_list);
277
278 return result;
279 }
280
281 /**
282 * see section 3.8.4 of TCG TNC IF-IMV Specification 1.3
283 */
284 TNC_Result TNC_IMV_ReceiveMessage(TNC_IMVID imv_id,
285 TNC_ConnectionID connection_id,
286 TNC_BufferReference msg,
287 TNC_UInt32 msg_len,
288 TNC_MessageType msg_type)
289 {
290 TNC_VendorID msg_vid;
291 TNC_MessageSubtype msg_subtype;
292
293 msg_vid = msg_type >> 8;
294 msg_subtype = msg_type & TNC_SUBTYPE_ANY;
295
296 return receive_message(imv_id, connection_id, 0, chunk_create(msg, msg_len),
297 msg_vid, msg_subtype, 0, TNC_IMVID_ANY);
298 }
299
300 /**
301 * see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
302 */
303 TNC_Result TNC_IMV_ReceiveMessageLong(TNC_IMVID imv_id,
304 TNC_ConnectionID connection_id,
305 TNC_UInt32 msg_flags,
306 TNC_BufferReference msg,
307 TNC_UInt32 msg_len,
308 TNC_VendorID msg_vid,
309 TNC_MessageSubtype msg_subtype,
310 TNC_UInt32 src_imc_id,
311 TNC_UInt32 dst_imv_id)
312 {
313 return receive_message(imv_id, connection_id, msg_flags,
314 chunk_create(msg, msg_len), msg_vid, msg_subtype,
315 src_imc_id, dst_imv_id);
316 }
317
318 /**
319 * see section 3.8.7 of TCG TNC IF-IMV Specification 1.3
320 */
321 TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
322 TNC_ConnectionID connection_id)
323 {
324 if (!imv_os)
325 {
326 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
327 return TNC_RESULT_NOT_INITIALIZED;
328 }
329 return imv_os->provide_recommendation(imv_os, connection_id,
330 TNC_IMCID_ANY);
331 }
332
333 /**
334 * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3
335 */
336 TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
337 TNC_ConnectionID connection_id)
338 {
339 imv_state_t *state;
340 imv_os_state_t *os_state;
341 TNC_Result result = TNC_RESULT_SUCCESS;
342
343 if (!imv_os)
344 {
345 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
346 return TNC_RESULT_NOT_INITIALIZED;
347 }
348
349 /* get current IMV state */
350 if (!imv_os->get_state(imv_os, connection_id, &state))
351 {
352 return TNC_RESULT_FATAL;
353 }
354 os_state = (imv_os_state_t*)state;
355
356 if (os_state->get_info(os_state) == NULL)
357 {
358 pa_tnc_attr_t *attr;
359 linked_list_t *attr_list;
360 ietf_attr_attr_request_t *attr_cast;
361
362 attr_list = linked_list_create();
363 attr = ietf_attr_attr_request_create(PEN_IETF,
364 IETF_ATTR_PRODUCT_INFORMATION);
365 attr_cast = (ietf_attr_attr_request_t*)attr;
366 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION);
367 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_FORWARDING_ENABLED);
368 attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED);
369 attr_list->insert_last(attr_list, attr);
370 result = imv_os->send_message(imv_os, connection_id, FALSE, imv_id,
371 TNC_IMCID_ANY, attr_list);
372 attr_list->destroy(attr_list);
373 }
374
375 return result;
376 }
377
378 /**
379 * see section 3.8.9 of TCG TNC IF-IMV Specification 1.3
380 */
381 TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
382 {
383 if (!imv_os)
384 {
385 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
386 return TNC_RESULT_NOT_INITIALIZED;
387 }
388 imv_os->destroy(imv_os);
389 imv_os = NULL;
390
391 return TNC_RESULT_SUCCESS;
392 }
393
394 /**
395 * see section 4.2.8.1 of TCG TNC IF-IMV Specification 1.3
396 */
397 TNC_Result TNC_IMV_ProvideBindFunction(TNC_IMVID imv_id,
398 TNC_TNCS_BindFunctionPointer bind_function)
399 {
400 if (!imv_os)
401 {
402 DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
403 return TNC_RESULT_NOT_INITIALIZED;
404 }
405 return imv_os->bind_functions(imv_os, bind_function);
406 }