refactored reason string and remediation instructions framework
[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 #include "imv/imv_lang_string.h"
18 #include "imv/imv_reason_string.h"
19 #include "imv/imv_remediation_string.h"
20
21 #include <utils/debug.h>
22 #include <collections/linked_list.h>
23
24 typedef struct private_imv_os_state_t private_imv_os_state_t;
25 typedef struct package_entry_t package_entry_t;
26 typedef struct entry_t entry_t;
27 typedef struct instruction_entry_t instruction_entry_t;
28
29 /**
30 * Private data of an imv_os_state_t object.
31 */
32 struct private_imv_os_state_t {
33
34 /**
35 * Public members of imv_os_state_t
36 */
37 imv_os_state_t public;
38
39 /**
40 * TNCCS connection ID
41 */
42 TNC_ConnectionID connection_id;
43
44 /**
45 * TNCCS connection state
46 */
47 TNC_ConnectionState state;
48
49 /**
50 * Does the TNCCS connection support long message types?
51 */
52 bool has_long;
53
54 /**
55 * Does the TNCCS connection support exclusive delivery?
56 */
57 bool has_excl;
58
59 /**
60 * Maximum PA-TNC message size for this TNCCS connection
61 */
62 u_int32_t max_msg_len;
63
64 /**
65 * IMV action recommendation
66 */
67 TNC_IMV_Action_Recommendation rec;
68
69 /**
70 * IMV evaluation result
71 */
72 TNC_IMV_Evaluation_Result eval;
73
74 /**
75 * OS Product Information (concatenation of OS Name and Version)
76 */
77 char *info;
78
79 /**
80 * OS Type
81 */
82 os_type_t type;
83
84 /**
85 * OS Name
86 */
87 chunk_t name;
88
89 /**
90 * OS Version
91 */
92 chunk_t version;
93
94 /**
95 * List of blacklisted packages to be removed
96 */
97 linked_list_t *remove_packages;
98
99 /**
100 * List of vulnerable packages to be updated
101 */
102 linked_list_t *update_packages;
103
104 /**
105 * TNC Reason String
106 */
107 imv_reason_string_t *reason_string;
108
109 /**
110 * IETF Remediation Instructions String
111 */
112 imv_remediation_string_t *remediation_string;
113
114 /**
115 * Number of processed packages
116 */
117 int count;
118
119 /**
120 * Number of not updated packages
121 */
122 int count_update;
123
124 /**
125 * Number of blacklisted packages
126 */
127 int count_blacklist;
128
129 /**
130 * Number of whitelisted packages
131 */
132 int count_ok;
133
134 /**
135 * OS Installed Package request sent - mandatory response expected
136 */
137 bool package_request;
138
139 /**
140 * OS Settings
141 */
142 u_int os_settings;
143
144 /**
145 * Angel count
146 */
147 int angel_count;
148
149 };
150
151 /**
152 * Supported languages
153 */
154 static char* languages[] = { "en", "de", "pl" };
155
156 /**
157 * Table of "OS settings" reason strings
158 */
159 static imv_lang_string_t reason_settings[] = {
160 { "en", "Improper OS settings were detected" },
161 { "de", "Unzulässige OS Einstellungen wurden festgestellt" },
162 { NULL, NULL }
163 };
164
165 /**
166 * Table of "software packages" reason strings
167 */
168 static imv_lang_string_t reason_packages[] = {
169 { "en", "Vulnerable or blacklisted software packages were found" },
170 { "de", "Schwachstellenbehaftete oder gesperrte Softwarepakete wurden gefunden" },
171 { NULL, NULL }
172 };
173
174 /**
175 * Table of "software packages update" instruction title strings
176 */
177 static imv_lang_string_t instr_update_packages_title[] = {
178 { "en", "Software Security Updates" },
179 { "de", "Software Sicherheitsupdates" },
180 { "pl", "Software Security Updates" }, /* TODO */
181 { NULL, NULL }
182 };
183
184 /**
185 * Table of "software packages update" instruction description strings
186 */
187 static imv_lang_string_t instr_update_packages_descr[] = {
188 { "en", "Please update the following software packages" },
189 { "de", "Bitte updaten Sie die folgenden Softwarepakete" },
190 { "pl", "Proszę zaktualizować następujące pakiety" },
191 { NULL, NULL }
192 };
193
194 /**
195 * Tables of "software package removal" instruction titlestrings
196 */
197 static imv_lang_string_t instr_remove_packages_title[] = {
198 { "en", "Blacklisted Software Packages" },
199 { "de", "Gesperrte Softwarepakete" },
200 { "pl", "Blacklisted Software Packages" }, /* TODO */
201 { NULL, NULL }
202 };
203
204 /**
205 * Tables of "software package removal" instruction strings
206 */
207 static imv_lang_string_t instr_remove_packages_descr[] = {
208 { "en", "Please remove the following software packages" },
209 { "de", "Bitte entfernen Sie die folgenden Softwarepakete" },
210 { "pl", "Proszę usunąć następujące pakiety" },
211 { NULL, NULL }
212 }
213
214 ;/**
215 * Table of "forwarding enable" instruction title strings
216 */
217 static imv_lang_string_t instr_fwd_enabled_title[] = {
218 { "en", "IP Packet Forwarding" },
219 { "de", "Weiterleitung von IP Paketen" },
220 { NULL, NULL }
221 };
222
223 /**
224 * Table of "forwarding enable" instruction description strings
225 */
226 static imv_lang_string_t instr_fwd_enabled_descr[] = {
227 { "en", "Please disable the forwarding of IP packets" },
228 { "de", "Bitte deaktivieren Sie das Forwarding von IP Paketen" },
229 { NULL, NULL }
230 };
231
232 /**
233 * Table of "default password enabled" instruction title strings
234 */
235 static imv_lang_string_t instr_default_pwd_enabled_title[] = {
236 { "en", "Default Password" },
237 { "de", "Default Passwort" },
238 { NULL, NULL }
239 };
240
241 /**
242 * Table of "default password enabled" instruction description strings
243 */
244 static imv_lang_string_t instr_default_pwd_enabled_descr[] = {
245 { "en", "Please change the default password" },
246 { "de", "Bitte ändern Sie das Default Passwort" },
247 { NULL, NULL }
248 };
249
250 /**
251 * Table of "install non market apps" instruction title strings
252 */
253 static imv_lang_string_t instr_non_market_apps_title[] = {
254 { "en", "Unknown Software Origin" },
255 { "de", "Unbekannte Softwareherkunft" },
256 { NULL, NULL }
257 };
258
259 /**
260 * Table of "install non market apps" instruction description strings
261 */
262 static imv_lang_string_t instr_non_market_apps_descr[] = {
263 { "en", "Do not allow the installation of apps from unknown sources" },
264 { "de", "Erlauben Sie nicht die Installation von Apps von unbekannten Quellen" },
265 { NULL, NULL }
266 };
267
268 METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
269 private_imv_os_state_t *this)
270 {
271 return this->connection_id;
272 }
273
274 METHOD(imv_state_t, has_long, bool,
275 private_imv_os_state_t *this)
276 {
277 return this->has_long;
278 }
279
280 METHOD(imv_state_t, has_excl, bool,
281 private_imv_os_state_t *this)
282 {
283 return this->has_excl;
284 }
285
286 METHOD(imv_state_t, set_flags, void,
287 private_imv_os_state_t *this, bool has_long, bool has_excl)
288 {
289 this->has_long = has_long;
290 this->has_excl = has_excl;
291 }
292
293 METHOD(imv_state_t, set_max_msg_len, void,
294 private_imv_os_state_t *this, u_int32_t max_msg_len)
295 {
296 this->max_msg_len = max_msg_len;
297 }
298
299 METHOD(imv_state_t, get_max_msg_len, u_int32_t,
300 private_imv_os_state_t *this)
301 {
302 return this->max_msg_len;
303 }
304
305 METHOD(imv_state_t, change_state, void,
306 private_imv_os_state_t *this, TNC_ConnectionState new_state)
307 {
308 this->state = new_state;
309 }
310
311 METHOD(imv_state_t, get_recommendation, void,
312 private_imv_os_state_t *this, TNC_IMV_Action_Recommendation *rec,
313 TNC_IMV_Evaluation_Result *eval)
314 {
315 *rec = this->rec;
316 *eval = this->eval;
317 }
318
319 METHOD(imv_state_t, set_recommendation, void,
320 private_imv_os_state_t *this, TNC_IMV_Action_Recommendation rec,
321 TNC_IMV_Evaluation_Result eval)
322 {
323 this->rec = rec;
324 this->eval = eval;
325 }
326
327 METHOD(imv_state_t, get_reason_string, bool,
328 private_imv_os_state_t *this, enumerator_t *language_enumerator,
329 chunk_t *reason_string, char **reason_language)
330 {
331 if (!this->count_update && !this->count_blacklist & !this->os_settings)
332 {
333 return FALSE;
334 }
335 *reason_language = imv_lang_string_select_lang(language_enumerator,
336 languages, countof(languages));
337
338 /* Instantiate a TNC Reason String object */
339 DESTROY_IF(this->reason_string);
340 this->reason_string = imv_reason_string_create(*reason_language);
341
342 if (this->count_update || this->count_blacklist)
343 {
344 this->reason_string->add_reason(this->reason_string, reason_packages);
345 }
346 if (this->os_settings)
347 {
348 this->reason_string->add_reason(this->reason_string, reason_settings);
349 }
350 *reason_string = this->reason_string->get_encoding(this->reason_string);
351
352 return TRUE;
353 }
354
355 METHOD(imv_state_t, get_remediation_instructions, bool,
356 private_imv_os_state_t *this, enumerator_t *language_enumerator,
357 chunk_t *string, char **lang_code, char **uri)
358 {
359 if (!this->count_update && !this->count_blacklist & !this->os_settings)
360 {
361 return FALSE;
362 }
363 *lang_code = imv_lang_string_select_lang(language_enumerator,
364 languages, countof(languages));
365
366 /* Instantiate an IETF Remediation Instructions String object */
367 DESTROY_IF(this->remediation_string);
368 this->remediation_string = imv_remediation_string_create(
369 this->type == OS_TYPE_ANDROID, *lang_code);
370
371 /* List of blacklisted packages to be removed, if any */
372 if (this->count_blacklist)
373 {
374 this->remediation_string->add_instruction(this->remediation_string,
375 instr_remove_packages_title,
376 instr_remove_packages_descr, NULL,
377 this->remove_packages);
378 }
379
380 /* List of packages in need of an update, if any */
381 if (this->count_update)
382 {
383 this->remediation_string->add_instruction(this->remediation_string,
384 instr_update_packages_title,
385 instr_update_packages_descr, NULL,
386 this->update_packages);
387 }
388
389 /* Add instructions concerning improper OS settings */
390 if (this->os_settings & OS_SETTINGS_FWD_ENABLED)
391 {
392 this->remediation_string->add_instruction(this->remediation_string,
393 instr_fwd_enabled_title,
394 instr_fwd_enabled_descr, NULL, NULL);
395 }
396 if (this->os_settings & OS_SETTINGS_DEFAULT_PWD_ENABLED)
397 {
398 this->remediation_string->add_instruction(this->remediation_string,
399 instr_default_pwd_enabled_title,
400 instr_default_pwd_enabled_descr, NULL, NULL);
401 }
402 if (this->os_settings & OS_SETTINGS_NON_MARKET_APPS)
403 {
404 this->remediation_string->add_instruction(this->remediation_string,
405 instr_non_market_apps_title,
406 instr_non_market_apps_descr, NULL, NULL);
407 }
408
409 *string = this->remediation_string->get_encoding(this->remediation_string);
410 *uri = lib->settings->get_str(lib->settings,
411 "libimcv.plugins.imv-os.remediation_uri", NULL);
412
413 return TRUE;
414 }
415
416 METHOD(imv_state_t, destroy, void,
417 private_imv_os_state_t *this)
418 {
419 DESTROY_IF(this->reason_string);
420 DESTROY_IF(this->remediation_string);
421 this->update_packages->destroy_function(this->update_packages, free);
422 this->remove_packages->destroy_function(this->remove_packages, free);
423 free(this->info);
424 free(this->name.ptr);
425 free(this->version.ptr);
426 free(this);
427 }
428
429 METHOD(imv_os_state_t, set_info, void,
430 private_imv_os_state_t *this, os_type_t type, chunk_t name, chunk_t version)
431 {
432 int len = name.len + 1 + version.len + 1;
433
434 /* OS info is a concatenation of OS name and OS version */
435 free(this->info);
436 this->info = malloc(len);
437 snprintf(this->info, len, "%.*s %.*s", name.len, name.ptr,
438 version.len, version.ptr);
439 this->type = type;
440 this->name = chunk_clone(name);
441 this->version = chunk_clone(version);
442 }
443
444 METHOD(imv_os_state_t, get_info, char*,
445 private_imv_os_state_t *this, os_type_t *type, chunk_t *name,
446 chunk_t *version)
447 {
448 if (type)
449 {
450 *type = this->type;
451 }
452 if (name)
453 {
454 *name = this->name;
455 }
456 if (version)
457 {
458 *version = this->version;
459 }
460 return this->info;
461 }
462
463 METHOD(imv_os_state_t, set_count, void,
464 private_imv_os_state_t *this, int count, int count_update,
465 int count_blacklist, int count_ok)
466 {
467 this->count += count;
468 this->count_update += count_update;
469 this->count_blacklist += count_blacklist;
470 this->count_ok += count_ok;
471 }
472
473 METHOD(imv_os_state_t, get_count, void,
474 private_imv_os_state_t *this, int *count, int *count_update,
475 int *count_blacklist, int *count_ok)
476 {
477 if (count)
478 {
479 *count = this->count;
480 }
481 if (count_update)
482 {
483 *count_update = this->count_update;
484 }
485 if (count_blacklist)
486 {
487 *count_blacklist = this->count_blacklist;
488 }
489 if (count_ok)
490 {
491 *count_ok = this->count_ok;
492 }
493 }
494
495 METHOD(imv_os_state_t, set_package_request, void,
496 private_imv_os_state_t *this, bool set)
497 {
498 this->package_request = set;
499 }
500
501 METHOD(imv_os_state_t, get_package_request, bool,
502 private_imv_os_state_t *this)
503 {
504 return this->package_request;
505 }
506
507 METHOD(imv_os_state_t, set_os_settings, void,
508 private_imv_os_state_t *this, u_int settings)
509 {
510 this->os_settings |= settings;
511 }
512
513 METHOD(imv_os_state_t, get_os_settings, u_int,
514 private_imv_os_state_t *this)
515 {
516 return this->os_settings;
517 }
518
519 METHOD(imv_os_state_t, set_angel_count, void,
520 private_imv_os_state_t *this, bool start)
521 {
522 this->angel_count += start ? 1 : -1;
523 }
524
525 METHOD(imv_os_state_t, get_angel_count, int,
526 private_imv_os_state_t *this)
527 {
528 return this->angel_count;
529 }
530
531 METHOD(imv_os_state_t, add_bad_package, void,
532 private_imv_os_state_t *this, char *package,
533 os_package_state_t package_state)
534 {
535 package = strdup(package);
536
537 if (package_state == OS_PACKAGE_STATE_BLACKLIST)
538 {
539 this->remove_packages->insert_last(this->remove_packages, package);
540 }
541 else
542 {
543 this->update_packages->insert_last(this->update_packages, package);
544 }
545 }
546
547 /**
548 * Described in header.
549 */
550 imv_state_t *imv_os_state_create(TNC_ConnectionID connection_id)
551 {
552 private_imv_os_state_t *this;
553
554 INIT(this,
555 .public = {
556 .interface = {
557 .get_connection_id = _get_connection_id,
558 .has_long = _has_long,
559 .has_excl = _has_excl,
560 .set_flags = _set_flags,
561 .set_max_msg_len = _set_max_msg_len,
562 .get_max_msg_len = _get_max_msg_len,
563 .change_state = _change_state,
564 .get_recommendation = _get_recommendation,
565 .set_recommendation = _set_recommendation,
566 .get_reason_string = _get_reason_string,
567 .get_remediation_instructions = _get_remediation_instructions,
568 .destroy = _destroy,
569 },
570 .set_info = _set_info,
571 .get_info = _get_info,
572 .set_count = _set_count,
573 .get_count = _get_count,
574 .set_package_request = _set_package_request,
575 .get_package_request = _get_package_request,
576 .set_os_settings = _set_os_settings,
577 .get_os_settings = _get_os_settings,
578 .set_angel_count = _set_angel_count,
579 .get_angel_count = _get_angel_count,
580 .add_bad_package = _add_bad_package,
581 },
582 .state = TNC_CONNECTION_STATE_CREATE,
583 .rec = TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
584 .eval = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
585 .connection_id = connection_id,
586 .update_packages = linked_list_create(),
587 .remove_packages = linked_list_create(),
588 );
589
590 return &this->public.interface;
591 }
592
593