implemented blacklisting of software packages
authorAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 14 Nov 2012 10:38:12 +0000 (11:38 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Wed, 14 Nov 2012 10:38:45 +0000 (11:38 +0100)
src/libimcv/os_info/os_info.c
src/libimcv/os_info/os_info.h
src/libimcv/plugins/imv_os/imv_os.c
src/libimcv/plugins/imv_os/imv_os_database.c
src/libimcv/plugins/imv_os/imv_os_state.c
src/libimcv/plugins/imv_os/imv_os_state.h
src/libimcv/plugins/imv_os/pacman.c
src/libpts/plugins/imv_attestation/attest.c
src/libpts/plugins/imv_attestation/attest_db.c
src/libpts/plugins/imv_attestation/attest_db.h

index 9716e2c..098cb1e 100644 (file)
@@ -42,6 +42,12 @@ ENUM(os_fwd_status_names, OS_FWD_DISABLED, OS_FWD_UNKNOWN,
        "unknown"
 );
 
+ENUM(os_package_state_names, OS_PACKAGE_STATE_UPDATE, OS_PACKAGE_STATE_BLACKLIST,
+       "",
+       " [s]",
+       " [b]"
+);
+
 /**
  * Private data of an os_info_t object.
  *
index 6946b1e..f474607 100644 (file)
@@ -24,6 +24,7 @@
 typedef struct os_info_t os_info_t;
 typedef enum os_type_t os_type_t;
 typedef enum os_fwd_status_t os_fwd_status_t;
+typedef enum os_package_state_t os_package_state_t;
 
 #include <library.h>
 
@@ -45,6 +46,17 @@ enum os_type_t {
 extern enum_name_t *os_type_names;
 
 /**
+ * Defines the security state of a package stored in the database
+ */
+enum os_package_state_t {
+       OS_PACKAGE_STATE_UPDATE =    0,         /* latest update */
+       OS_PACKAGE_STATE_SECURITY =  1,         /* latest security fix */
+       OS_PACKAGE_STATE_BLACKLIST = 2          /* blacklisted package */
+};
+
+extern enum_name_t *os_package_state_names;
+
+/**
  * Defines the IPv4 forwarding status
  */
 enum os_fwd_status_t {
index c1af31f..0091e3e 100644 (file)
@@ -150,7 +150,6 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
        chunk_t os_name = chunk_empty;
        chunk_t os_version = chunk_empty;
        bool fatal_error = FALSE, assessment = FALSE;
-       int count, count_bad, count_ok;
 
        os_state = (imv_os_state_t*)state;
 
@@ -391,11 +390,15 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                !os_state->get_package_request(os_state) &&
                !os_state->get_angel_count(os_state))
        {
-               os_state->get_count(os_state, &count, &count_bad, &count_ok);
-               DBG1(DBG_IMV, "processed %d packages: %d bad, %d ok, %d not found",
-                       count, count_bad, count_ok, count - count_bad - count_ok);
+               int count, count_update, count_blacklist, count_ok;
 
-               if (count_bad)
+               os_state->get_count(os_state, &count, &count_update, &count_blacklist,
+                                                                         &count_ok);
+               DBG1(DBG_IMV, "processed %d packages: %d not updated, %d blacklisted, "
+                        "%d ok, %d not found", count, count_update, count_blacklist,
+                        count_ok, count - count_update - count_blacklist - count_ok);
+
+               if (count_update || count_blacklist)
                {
                        state->set_recommendation(state,
                                                                TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
index 0048062..4ca8eb5 100644 (file)
@@ -46,8 +46,9 @@ METHOD(imv_os_database_t, check_packages, status_t,
        chunk_t os_name, os_version, name, version;
        os_type_t os_type;
        size_t os_version_len;
-       int pid, gid, security;
-       int count = 0, count_ok = 0, count_no_match = 0;
+       os_package_state_t package_state;
+       int pid, gid;
+       int count = 0, count_ok = 0, count_no_match = 0, count_blacklist = 0;
        enumerator_t *e;
        status_t status = SUCCESS;
        bool found, match;
@@ -139,10 +140,10 @@ METHOD(imv_os_database_t, check_packages, status_t,
                found = FALSE;
                match = FALSE;
 
-               while (e->enumerate(e, &cur_release, &security))
+               while (e->enumerate(e, &cur_release, &package_state))
                {
                        found = TRUE;
-                       if (streq(release, cur_release))
+                       if (streq(release, cur_release) || streq("*", cur_release))
                        {
                                match = TRUE;
                                break;
@@ -154,15 +155,25 @@ METHOD(imv_os_database_t, check_packages, status_t,
                {
                        if (match)
                        {
-                               DBG2(DBG_IMV, "package '%s' (%s)%s is ok", package, release,
-                                                          security ? " [s]" : "");
-                               count_ok++;
+                               if (package_state == OS_PACKAGE_STATE_BLACKLIST)
+                               {
+                                       DBG2(DBG_IMV, "package '%s' (%s) is blacklisted",
+                                                                  package, release);
+                                       count_blacklist++;
+                                       state->add_bad_package(state, package, package_state);
+                               }
+                               else
+                               {
+                                       DBG2(DBG_IMV, "package '%s' (%s)%N is ok", package, release,
+                                                                  os_package_state_names, package_state);
+                                       count_ok++;
+                               }
                        }
                        else
                        {
                                DBG1(DBG_IMV, "package '%s' (%s) no match", package, release);
                                count_no_match++;
-                               state->add_bad_package(state, package);
+                               state->add_bad_package(state, package, package_state);
                        }
                }
                else
@@ -173,7 +184,7 @@ METHOD(imv_os_database_t, check_packages, status_t,
                free(release);
        }
        free(product);
-       state->set_count(state, count, count_no_match, count_ok);
+       state->set_count(state, count, count_no_match, count_blacklist, count_ok);
 
        return status;
 }
index 8bb944f..318b433 100644 (file)
@@ -19,6 +19,9 @@
 #include <collections/linked_list.h>
 
 typedef struct private_imv_os_state_t private_imv_os_state_t;
+typedef struct package_entry_t package_entry_t;
+typedef struct reason_entry_t reason_entry_t;
+typedef struct instruction_entry_t instruction_entry_t;
 
 /**
  * Private data of an imv_os_state_t object.
@@ -101,9 +104,14 @@ struct private_imv_os_state_t {
        int count;
 
        /**
-        * Number of blacklisted or not updated packages
+        * Number of not updated packages
         */
-       int count_bad;
+       int count_update;
+
+       /**
+        * Number of blacklisted packages
+        */
+       int count_blacklist;
 
        /**
         * Number of whitelisted packages
@@ -122,12 +130,27 @@ struct private_imv_os_state_t {
 
 };
 
-typedef struct entry_t entry_t;
+/**
+ * Store a bad package entry
+ */
+struct package_entry_t {
+       char *name;
+       os_package_state_t state;
+};
+
+/**
+ * Free a bad package entry
+ */
+static void free_package_entry(package_entry_t *this)
+{
+       free(this->name);
+       free(this);
+}
 
 /**
  * Define an internal reason string entry
  */
-struct entry_t {
+struct reason_entry_t {
        char *lang;
        char *string;
 };
@@ -135,18 +158,30 @@ struct entry_t {
 /**
  * Table of multi-lingual reason string entries
  */
-static entry_t reasons[] = {
+static reason_entry_t reasons[] = {
        { "en", "Vulnerable or blacklisted software packages were found" },
        { "de", "Schwachstellenbehaftete oder gesperrte Softwarepakete wurden gefunden" },
 };
 
 /**
- * Table of multi-lingual remediation instruction string entries
+ * Define a remediation instruction string entry
+ */
+struct instruction_entry_t {
+       char *lang;
+       char *update_string;
+       char *removal_string;
+};
+
+/**
+ * Tables of multi-lingual remediation instruction string entries
  */
-static entry_t instructions [] = {
-       { "en", "Please update the following software packages:\n" },
-       { "de", "Bitte updaten Sie die folgenden Softwarepakete\n" },
-       { "pl", "Proszę zaktualizować następujące pakiety:\n" }
+static instruction_entry_t instructions [] = {
+       { "en", "Please update the following software packages:\n",
+                       "Please remove the following software packages:\n" },
+       { "de", "Bitte updaten Sie die folgenden Softwarepakete\n",
+                       "Bitte entfernen Sie die folgenden Softwarepakete\n" },
+       { "pl", "Proszę zaktualizować następujące pakiety:\n",
+                       "Proszę usunąć następujące pakiety:\n" }
 };
 
 METHOD(imv_state_t, get_connection_id, TNC_ConnectionID,
@@ -216,7 +251,7 @@ METHOD(imv_state_t, get_reason_string, bool,
        char *lang;
        int i;
 
-       if (!this->count_bad)
+       if (!this->count_update && !this->count_blacklist)
        {
                return FALSE;
        }
@@ -254,17 +289,14 @@ METHOD(imv_state_t, get_remediation_instructions, bool,
        bool match = FALSE;
        char *lang, *package, *pos;
        enumerator_t *enumerator;
-       int i, len;
+       package_entry_t *entry;
+       int i, i_chosen = 0, len = 0;
 
-       if (!this->count_bad)
+       if (!this->count_update && !this->count_blacklist)
        {
                return FALSE;
        }
 
-       /* set the default language */
-       *lang_code = instructions[0].lang;
-       *string    = instructions[0].string;
-
        while (language_enumerator->enumerate(language_enumerator, &lang))
        {
                for (i = 0; i < countof(instructions); i++)
@@ -272,8 +304,7 @@ METHOD(imv_state_t, get_remediation_instructions, bool,
                        if (streq(lang, instructions[i].lang))
                        {
                                match = TRUE;
-                               *lang_code = instructions[i].lang;
-                               *string    = instructions[i].string;
+                               i_chosen = i;
                                break;
                        }
                }
@@ -282,31 +313,67 @@ METHOD(imv_state_t, get_remediation_instructions, bool,
                        break;
                }
        }
+       *lang_code = instructions[i_chosen].lang;
 
        /* Compute the size of the remediation string */
-       len = strlen(*string);
+       if (this->count_update)
+       {
+               len += strlen(instructions[i_chosen].update_string);
+       }
+       if (this->count_blacklist)
+       {
+               len += strlen(instructions[i_chosen].removal_string);
+       }
 
        enumerator = this->bad_packages->create_enumerator(this->bad_packages);
-       while (enumerator->enumerate(enumerator, &package))
+       while (enumerator->enumerate(enumerator, &entry))
        {
-               len += strlen(package) + 1;
+               len += strlen(entry->name) + 1;
        }
        enumerator->destroy(enumerator);
 
+       /* Allocate memory for the remediation instructions */
        pos = this->instructions = malloc(len + 1);
-       strcpy(pos, *string);
-       pos += strlen(*string);
 
-       enumerator = this->bad_packages->create_enumerator(this->bad_packages);
-       while (enumerator->enumerate(enumerator, &package))
+       /* List of blacklisted packages, if any */
+       if (this->count_blacklist)
        {
-               strcpy(pos, package);
-               pos += strlen(package);
-               *pos++ = '\n';
+               strcpy(pos, instructions[i_chosen].removal_string);
+               pos += strlen(instructions[i_chosen].removal_string);
+
+               enumerator = this->bad_packages->create_enumerator(this->bad_packages);
+               while (enumerator->enumerate(enumerator, &entry))
+               {
+                       if (entry->state == OS_PACKAGE_STATE_BLACKLIST)
+                       {
+                               strcpy(pos, entry->name);
+                               pos += strlen(entry->name);
+                               *pos++ = '\n';
+                       }
+               }
+               enumerator->destroy(enumerator);
        }
-       enumerator->destroy(enumerator);
-       *pos = '\0';
 
+       /* List of packages in need of an update, if any */
+       if (this->count_update)
+       {
+               strcpy(pos, instructions[i_chosen].update_string);
+               pos += strlen(instructions[i_chosen].update_string);
+
+               enumerator = this->bad_packages->create_enumerator(this->bad_packages);
+               while (enumerator->enumerate(enumerator, &entry))
+               {
+                       if (entry->state != OS_PACKAGE_STATE_BLACKLIST)
+                       {
+                               strcpy(pos, entry->name);
+                               pos += strlen(entry->name);
+                               *pos++ = '\n';
+                       }
+               }
+               enumerator->destroy(enumerator);
+       }
+
+       *pos = '\0';
        *string = this->instructions;
        *uri = lib->settings->get_str(lib->settings,
                                "libimcv.plugins.imv-os.remediation_uri", NULL);
@@ -317,7 +384,8 @@ METHOD(imv_state_t, get_remediation_instructions, bool,
 METHOD(imv_state_t, destroy, void,
        private_imv_os_state_t *this)
 {
-       this->bad_packages->destroy_function(this->bad_packages, free);
+       this->bad_packages->destroy_function(this->bad_packages,
+                                                                               (void*)free_package_entry);
        free(this->instructions);
        free(this->info);
        free(this->name.ptr);
@@ -360,23 +428,30 @@ METHOD(imv_os_state_t, get_info, char*,
 }
 
 METHOD(imv_os_state_t, set_count, void,
-       private_imv_os_state_t *this, int count, int count_bad, int count_ok)
+       private_imv_os_state_t *this, int count, int count_update,
+       int count_blacklist, int count_ok)
 {
-       this->count     += count;
-       this->count_bad += count_bad;
-       this->count_ok  += count_ok;
+       this->count           += count;
+       this->count_update    += count_update;
+       this->count_blacklist += count_blacklist;
+       this->count_ok        += count_ok;
 }
 
 METHOD(imv_os_state_t, get_count, void,
-       private_imv_os_state_t *this, int *count, int *count_bad, int *count_ok)
+       private_imv_os_state_t *this, int *count, int *count_update,
+       int *count_blacklist, int *count_ok)
 {
        if (count)
        {
                *count = this->count;
        }
-       if (count_bad)
+       if (count_update)
        {
-               *count_bad = this->count_bad;
+               *count_update = this->count_update;
+       }
+       if (count_blacklist)
+       {
+               *count_blacklist = this->count_blacklist;
        }
        if (count_ok)
        {
@@ -409,9 +484,15 @@ METHOD(imv_os_state_t, get_angel_count, int,
 }
 
 METHOD(imv_os_state_t, add_bad_package, void,
-       private_imv_os_state_t *this, char *package)
+       private_imv_os_state_t *this, char *package,
+       os_package_state_t package_state)
 {
-       this->bad_packages->insert_last(this->bad_packages, strdup(package));
+       package_entry_t *entry;
+
+       entry = malloc_thing(package_entry_t);
+       entry->name = strdup(package);
+       entry->state = package_state;
+       this->bad_packages->insert_last(this->bad_packages, entry);
 }
 
 /**
index 3c9d21d..760df78 100644 (file)
@@ -62,22 +62,24 @@ struct imv_os_state_t {
        /**
         * Set [or with multiple attributes increment] package counters
         *
-        * @param count                 Number of processed packages
-        * @param count_bad             Number of blacklisted or not updated packages
-        * @param count_ok              Number of whitelisted packages
+        * @param count                         Number of processed packages
+        * @param count_update          Number of not updated packages
+        * @param count_blacklist       Number of blacklisted packages
+        * @param count_ok                      Number of whitelisted packages
         */
-       void (*set_count)(imv_os_state_t *this, int count, int count_bad,
-                                         int count_ok);
+       void (*set_count)(imv_os_state_t *this, int count, int count_update,
+                                         int count_blacklist, int count_ok);
 
        /**
         * Set [or with multiple attributes increment] package counters
         *
-        * @param count                 Number of processed packages
-        * @param count_bad             Number of blacklisted or not updated packages
-        * @param count_ok              Number of whitelisted packages
+        * @param count                         Number of processed packages
+        * @param count_update          Number of not updated packages
+        * @param count_blacklist       Number of blacklisted packages
+        * @param count_ok                      Number of whitelisted packages
         */
-       void (*get_count)(imv_os_state_t *this, int *count, int *count_bad,
-                                         int *count_ok);
+       void (*get_count)(imv_os_state_t *this, int *count, int *count_update,
+                                         int *count_blacklist, int *count_ok);
        /**
         * Set/reset OS Installed Packages request status
         *
@@ -110,8 +112,10 @@ struct imv_os_state_t {
         * Store a bad package that has to be updated or removed
         *
         * @param package               Name of software package
+        * @param package_state Security state of software package
         */
-       void (*add_bad_package)(imv_os_state_t *this, char *package);
+       void (*add_bad_package)(imv_os_state_t *this, char *package,
+                                                       os_package_state_t package_state);
 
 };
 
index 38e79db..eef5ce0 100644 (file)
@@ -22,6 +22,8 @@
 #include <syslog.h>
 #include <time.h>
 
+#include "imv_os_state.h"
+
 #include <library.h>
 #include <utils/debug.h>
 
index bcce833..281078a 100644 (file)
@@ -128,7 +128,7 @@ static void do_args(int argc, char *argv[])
                        { "delete", no_argument, NULL, 'd' },
                        { "del", no_argument, NULL, 'd' },
                        { "aik", required_argument, NULL, 'A' },
-                       { "security", no_argument, NULL, 'B' },
+                       { "blacklist", no_argument, NULL, 'B' },
                        { "component", required_argument, NULL, 'C' },
                        { "comp", required_argument, NULL, 'C' },
                        { "directory", required_argument, NULL, 'D' },
@@ -142,8 +142,9 @@ static void do_args(int argc, char *argv[])
                        { "relative", no_argument, NULL, 'R' },
                        { "rel", no_argument, NULL, 'R' },
                        { "sequence", required_argument, NULL, 'S' },
-                       { "version", required_argument, NULL, 'V' },
                        { "seq", required_argument, NULL, 'S' },
+                       { "version", required_argument, NULL, 'V' },
+                       { "security", no_argument, NULL, 'Y' },
                        { "sha1", no_argument, NULL, '1' },
                        { "sha256", no_argument, NULL, '2' },
                        { "sha384", no_argument, NULL, '3' },
@@ -229,7 +230,7 @@ static void do_args(int argc, char *argv[])
                                continue;
                        }
                        case 'B':
-                               attest->set_security(attest);
+                               attest->set_security(attest, OS_PACKAGE_STATE_BLACKLIST);
                                continue;
                        case 'C':
                                if (!attest->set_component(attest, optarg, op == OP_ADD))
@@ -290,6 +291,9 @@ static void do_args(int argc, char *argv[])
                                        exit(EXIT_FAILURE);
                                }
                                continue;
+                       case 'Y':
+                               attest->set_security(attest, OS_PACKAGE_STATE_SECURITY);
+                               continue;
                        case '1':
                                attest->set_algo(attest, PTS_MEAS_ALGO_SHA1);
                                continue;
index 6be7093..8e64d0a 100644 (file)
@@ -143,9 +143,9 @@ struct private_attest_db_t {
        bool relative;
 
        /**
-        * TRUE if a security issue exists
+        * Package security state
         */
-       bool security;
+       os_package_state_t security;
 
        /**
         * Sequence number for ordering entries
@@ -722,9 +722,9 @@ METHOD(attest_db_t, set_relative, void,
 }
 
 METHOD(attest_db_t, set_security, void,
-       private_attest_db_t *this)
+       private_attest_db_t *this, os_package_state_t security)
 {
-       this->security = TRUE;
+       this->security = security;
 }
 
 METHOD(attest_db_t, set_sequence, void,
@@ -897,7 +897,8 @@ METHOD(attest_db_t, list_packages, void,
 {
        enumerator_t *e;
        char *package, *version;
-       int gid, gid_old = 0, security, spaces, count = 0;
+       os_package_state_t security;
+       int gid, gid_old = 0, spaces, count = 0;
        time_t t;
 
        if (this->pid)
@@ -924,7 +925,8 @@ METHOD(attest_db_t, list_packages, void,
                                                printf(" ");
                                        }
                                }
-                               printf(" %T (%s) %s\n", &t, TRUE, version, security ? "[s]" : "");
+                               printf(" %T (%s)%N\n", &t, TRUE, version,
+                                        os_package_state_names, security);
                                count++;
                        }
                        e->destroy(e);
@@ -1493,9 +1495,10 @@ METHOD(attest_db_t, add, bool,
                                        DB_UINT, this->gid, DB_UINT, this->pid, DB_TEXT,
                                        this->version, DB_UINT, this->security, DB_INT, t) == 1;
 
-               printf("'%s' package %s (%s) %s%sinserted into database\n",
+               printf("'%s' package %s (%s)%N %sinserted into database\n",
                                this->product, this->package, this->version,
-                               this->security ? "[s] " : "", success ? "" : "could not be ");
+                               os_package_state_names, this->security,
+                               success ? "" : "could not be ");
        }
        return success;
 }
index cd7b5f4..81dd0ad 100644 (file)
@@ -23,7 +23,7 @@
 #define ATTEST_DB_H_
 
 #include <pts/pts_meas_algo.h>
-
+#include <os_info/os_info.h>
 #include <library.h>
 
 typedef struct attest_db_t attest_db_t;
@@ -161,9 +161,9 @@ struct attest_db_t {
        void (*set_relative)(attest_db_t *this);
 
        /**
-        * Set the security vulnerability flag
+        * Set the package security state
         */
-       void (*set_security)(attest_db_t *this);
+       void (*set_security)(attest_db_t *this, os_package_state_t security);
 
        /**
         * Set the sequence number