implemented reason string and remediation instructions for OS IMV
[strongswan.git] / src / libimcv / plugins / imv_os / imv_os_state.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 <utils/debug.h>
19 #include <collections/linked_list.h>
20
21 typedef struct private_imv_os_state_t private_imv_os_state_t;
22
23 /**
24 * Private data of an imv_os_state_t object.
25 */
26 struct private_imv_os_state_t {
27
28 /**
29 * Public members of imv_os_state_t
30 */
31 imv_os_state_t public;
32
33 /**
34 * TNCCS connection ID
35 */
36 TNC_ConnectionID connection_id;
37
38 /**
39 * TNCCS connection state
40 */
41 TNC_ConnectionState state;
42
43 /**
44 * Does the TNCCS connection support long message types?
45 */
46 bool has_long;
47
48 /**
49 * Does the TNCCS connection support exclusive delivery?
50 */
51 bool has_excl;
52
53 /**
54 * Maximum PA-TNC message size for this TNCCS connection
55 */
56 u_int32_t max_msg_len;
57
58 /**
59 * IMV action recommendation
60 */
61 TNC_IMV_Action_Recommendation rec;
62
63 /**
64 * IMV evaluation result
65 */
66 TNC_IMV_Evaluation_Result eval;
67
68 /**
69 * OS Product Information (concatenation of OS Name and Version)
70 */
71 char *info;
72
73 /**
74 * OS Type
75 */
76 os_type_t type;
77
78 /**
79 * OS Name
80 */
81 chunk_t name;
82
83 /**
84 * OS Version
85 */
86 chunk_t version;
87
88 /**
89 * List of vulnerable or blacklisted packages
90 */
91 linked_list_t *bad_packages;
92
93 /**
94 * Local copy of the remediation instruction string
95 */
96 char *instructions;
97
98 /**
99 * Number of processed packages
100 */
101 int count;
102
103 /**
104 * Number of blacklisted or not updated packages
105 */
106 int count_bad;
107
108 /**
109 * Number of whitelisted packages
110 */
111 int count_ok;
112
113 /**
114 * OS Installed Package request sent - mandatory response expected
115 */
116 bool package_request;
117
118 /**
119 * Angel count
120 */
121 int angel_count;
122
123 };
124
125 typedef struct entry_t entry_t;
126
127 /**
128 * Define an internal reason string entry
129 */
130 struct entry_t {
131 char *lang;
132 char *string;
133 };
134
135 /**
136 * Table of multi-lingual reason string entries
137 */
138 static entry_t reasons[] = {
139 { "en", "Vulnerable or blacklisted software packages were found" },
140 { "de", "Schwachstellenbehaftete oder gesperrte Softwarepakete wurden gefunden" },
141 };
142
143 /**
144 * Table of multi-lingual remediation instruction string entries
145 */
146 static entry_t instructions [] = {
147 { "en", "Please update the following software packages:\n" },
148 { "de", "Bitte updaten Sie die folgenden Softwarepakete\n" },
149 { "pl", "Proszę zaktualizować następujące pakiety:\n" }
150 };
151
152 METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
153 private_imv_os_state_t *this)
154 {
155 return this->connection_id;
156 }
157
158 METHOD(imv_state_t, has_long, bool,
159 private_imv_os_state_t *this)
160 {
161 return this->has_long;
162 }
163
164 METHOD(imv_state_t, has_excl, bool,
165 private_imv_os_state_t *this)
166 {
167 return this->has_excl;
168 }
169
170 METHOD(imv_state_t, set_flags, void,
171 private_imv_os_state_t *this, bool has_long, bool has_excl)
172 {
173 this->has_long = has_long;
174 this->has_excl = has_excl;
175 }
176
177 METHOD(imv_state_t, set_max_msg_len, void,
178 private_imv_os_state_t *this, u_int32_t max_msg_len)
179 {
180 this->max_msg_len = max_msg_len;
181 }
182
183 METHOD(imv_state_t, get_max_msg_len, u_int32_t,
184 private_imv_os_state_t *this)
185 {
186 return this->max_msg_len;
187 }
188
189 METHOD(imv_state_t, change_state, void,
190 private_imv_os_state_t *this, TNC_ConnectionState new_state)
191 {
192 this->state = new_state;
193 }
194
195 METHOD(imv_state_t, get_recommendation, void,
196 private_imv_os_state_t *this, TNC_IMV_Action_Recommendation *rec,
197 TNC_IMV_Evaluation_Result *eval)
198 {
199 *rec = this->rec;
200 *eval = this->eval;
201 }
202
203 METHOD(imv_state_t, set_recommendation, void,
204 private_imv_os_state_t *this, TNC_IMV_Action_Recommendation rec,
205 TNC_IMV_Evaluation_Result eval)
206 {
207 this->rec = rec;
208 this->eval = eval;
209 }
210
211 METHOD(imv_state_t, get_reason_string, bool,
212 private_imv_os_state_t *this, enumerator_t *language_enumerator,
213 char **reason_string, char **reason_language)
214 {
215 bool match = FALSE;
216 char *lang;
217 int i;
218
219 if (!this->count_bad)
220 {
221 return FALSE;
222 }
223
224 /* set the default language */
225 *reason_language = reasons[0].lang;
226 *reason_string = reasons[0].string;
227
228 while (language_enumerator->enumerate(language_enumerator, &lang))
229 {
230 for (i = 0; i < countof(reasons); i++)
231 {
232 if (streq(lang, reasons[i].lang))
233 {
234 match = TRUE;
235 *reason_language = reasons[i].lang;
236 *reason_string = reasons[i].string;
237 break;
238 }
239 }
240 if (match)
241 {
242 break;
243 }
244 }
245
246 return TRUE;
247
248 }
249
250 METHOD(imv_state_t, get_remediation_instructions, bool,
251 private_imv_os_state_t *this, enumerator_t *language_enumerator,
252 char **string, char **lang_code, char **uri)
253 {
254 bool match = FALSE;
255 char *lang, *package, *pos;
256 enumerator_t *enumerator;
257 int i, len;
258
259 if (!this->count_bad)
260 {
261 return FALSE;
262 }
263
264 /* set the default language */
265 *lang_code = instructions[0].lang;
266 *string = instructions[0].string;
267
268 while (language_enumerator->enumerate(language_enumerator, &lang))
269 {
270 for (i = 0; i < countof(instructions); i++)
271 {
272 if (streq(lang, instructions[i].lang))
273 {
274 match = TRUE;
275 *lang_code = instructions[i].lang;
276 *string = instructions[i].string;
277 break;
278 }
279 }
280 if (match)
281 {
282 break;
283 }
284 }
285
286 /* Compute the size of the remediation string */
287 len = strlen(*string);
288
289 enumerator = this->bad_packages->create_enumerator(this->bad_packages);
290 while (enumerator->enumerate(enumerator, &package))
291 {
292 len += strlen(package);
293 }
294 enumerator->destroy(enumerator);
295
296 pos = this->instructions = malloc(len + 1);
297 strcopy(pos, *string);
298 pos += strlen(*string);
299
300 enumerator = this->bad_packages->create_enumerator(this->bad_packages);
301 while (enumerator->enumerate(enumerator, &package))
302 {
303 strcpy(pos, package);
304 pos += strlen(package);
305 }
306 enumerator->destroy(enumerator);
307
308 *string = this->instructions;
309 *uri = lib->settings->get_str(lib->settings,
310 "libimcv.plugins.imv-os.remediation_uri", NULL);
311
312 return TRUE;
313 }
314
315 METHOD(imv_state_t, destroy, void,
316 private_imv_os_state_t *this)
317 {
318 this->bad_packages->destroy_function(this->bad_packages, free);
319 free(this->instructions);
320 free(this->info);
321 free(this->name.ptr);
322 free(this->version.ptr);
323 free(this);
324 }
325
326 METHOD(imv_os_state_t, set_info, void,
327 private_imv_os_state_t *this, os_type_t type, chunk_t name, chunk_t version)
328 {
329 int len = name.len + 1 + version.len + 1;
330
331 /* OS info is a concatenation of OS name and OS version */
332 free(this->info);
333 this->info = malloc(len);
334 snprintf(this->info, len, "%.*s %.*s", name.len, name.ptr,
335 version.len, version.ptr);
336 this->type = type;
337 this->name = chunk_clone(name);
338 this->version = chunk_clone(version);
339 }
340
341 METHOD(imv_os_state_t, get_info, char*,
342 private_imv_os_state_t *this, os_type_t *type, chunk_t *name,
343 chunk_t *version)
344 {
345 if (type)
346 {
347 *type = this->type;
348 }
349 if (name)
350 {
351 *name = this->name;
352 }
353 if (version)
354 {
355 *version = this->version;
356 }
357 return this->info;
358 }
359
360 METHOD(imv_os_state_t, set_count, void,
361 private_imv_os_state_t *this, int count, int count_bad, int count_ok)
362 {
363 this->count += count;
364 this->count_bad += count_bad;
365 this->count_ok += count_ok;
366 }
367
368 METHOD(imv_os_state_t, get_count, void,
369 private_imv_os_state_t *this, int *count, int *count_bad, int *count_ok)
370 {
371 if (count)
372 {
373 *count = this->count;
374 }
375 if (count_bad)
376 {
377 *count_bad = this->count_bad;
378 }
379 if (count_ok)
380 {
381 *count_ok = this->count_ok;
382 }
383 }
384
385 METHOD(imv_os_state_t, set_package_request, void,
386 private_imv_os_state_t *this, bool set)
387 {
388 this->package_request = set;
389 }
390
391 METHOD(imv_os_state_t, get_package_request, bool,
392 private_imv_os_state_t *this)
393 {
394 return this->package_request;
395 }
396
397 METHOD(imv_os_state_t, set_angel_count, void,
398 private_imv_os_state_t *this, bool start)
399 {
400 this->angel_count += start ? 1 : -1;
401 }
402
403 METHOD(imv_os_state_t, get_angel_count, int,
404 private_imv_os_state_t *this)
405 {
406 return this->angel_count;
407 }
408
409 METHOD(imv_os_state_t, add_bad_package, void,
410 private_imv_os_state_t *this, char *package)
411 {
412 this->bad_packages->insert_last(this->bad_packages, strdup(package));
413 }
414
415 /**
416 * Described in header.
417 */
418 imv_state_t *imv_os_state_create(TNC_ConnectionID connection_id)
419 {
420 private_imv_os_state_t *this;
421
422 INIT(this,
423 .public = {
424 .interface = {
425 .get_connection_id = _get_connection_id,
426 .has_long = _has_long,
427 .has_excl = _has_excl,
428 .set_flags = _set_flags,
429 .set_max_msg_len = _set_max_msg_len,
430 .get_max_msg_len = _get_max_msg_len,
431 .change_state = _change_state,
432 .get_recommendation = _get_recommendation,
433 .set_recommendation = _set_recommendation,
434 .get_reason_string = _get_reason_string,
435 .get_remediation_instructions = _get_remediation_instructions,
436 .destroy = _destroy,
437 },
438 .set_info = _set_info,
439 .get_info = _get_info,
440 .set_count = _set_count,
441 .get_count = _get_count,
442 .set_package_request = _set_package_request,
443 .get_package_request = _get_package_request,
444 .set_angel_count = _set_angel_count,
445 .get_angel_count = _get_angel_count,
446 .add_bad_package = _add_bad_package,
447 },
448 .state = TNC_CONNECTION_STATE_CREATE,
449 .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
450 .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
451 .connection_id = connection_id,
452 .bad_packages = linked_list_create(),
453 );
454
455 return &this->public.interface;
456 }
457
458