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