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