check installed packages in OS database
authorAndreas Steffen <andreas.steffen@strongswan.org>
Mon, 5 Nov 2012 20:00:56 +0000 (21:00 +0100)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Mon, 5 Nov 2012 20:00:56 +0000 (21:00 +0100)
src/libimcv/plugins/imv_os/Makefile.am
src/libimcv/plugins/imv_os/imv_os.c
src/libimcv/plugins/imv_os/imv_os_database.c [new file with mode: 0644]
src/libimcv/plugins/imv_os/imv_os_database.h [new file with mode: 0644]

index 195c458..e0a04af 100644 (file)
@@ -9,7 +9,9 @@ imcv_LTLIBRARIES = imv-os.la
 imv_os_la_LIBADD = $(top_builddir)/src/libimcv/libimcv.la \
        $(top_builddir)/src/libstrongswan/libstrongswan.la
 
-imv_os_la_SOURCES = imv_os.c imv_os_state.h imv_os_state.c
+imv_os_la_SOURCES = \
+       imv_os.c imv_os_state.h imv_os_state.c \
+       imv_os_database.c imv_os_database.h
 
 imv_os_la_LDFLAGS = -module -avoid-version
 
index a9ba0f9..f2e00da 100644 (file)
@@ -14,6 +14,7 @@
  */
 
 #include "imv_os_state.h"
+#include "imv_os_database.h"
 
 #include <imv/imv_agent.h>
 #include <imv/imv_msg.h>
@@ -51,6 +52,11 @@ static pen_type_t msg_types[] = {
 
 static imv_agent_t *imv_os;
 
+/**
+ * IMV OS database
+ */
+static imv_os_database_t *os_db;
+
 /*
  * see section 3.8.1 of TCG TNC IF-IMV Specification 1.3
  */
@@ -59,6 +65,8 @@ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
                                                          TNC_Version max_version,
                                                          TNC_Version *actual_version)
 {
+       char *uri;
+
        if (imv_os)
        {
                DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name);
@@ -76,6 +84,14 @@ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id,
                return TNC_RESULT_NO_COMMON_VERSION;
        }
 
+       /* attach OS database */
+       uri = lib->settings->get_str(lib->settings,
+                               "libimcv.plugins.imv-os.database", NULL);
+       if (uri)
+       {
+               os_db = imv_os_database_create(uri);
+       }
+
        return TNC_RESULT_SUCCESS;
 }
 
@@ -242,19 +258,39 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                                {
                                        ietf_attr_installed_packages_t *attr_cast;
                                        enumerator_t *e;
-                                       chunk_t name, version;
+                                       status_t status;
 
-                                       attr_cast = (ietf_attr_installed_packages_t*)attr;
-                                       e = attr_cast->create_enumerator(attr_cast);
-                                       while (e->enumerate(e, &name, &version))
+                                       /* Received at least one Installed Packages attribute */
+                                       os_state->set_package_request(os_state, FALSE);
+
+                                       if (!os_db)
                                        {
-                                               DBG1(DBG_IMV, "package '%.*s' %.*s", name.len, name.ptr,
-                                                                          version.len, version.ptr);
+                                               break;
                                        }
+                                       attr_cast = (ietf_attr_installed_packages_t*)attr;
+
+                                       e = attr_cast->create_enumerator(attr_cast);
+                                       status = os_db->check_packages(os_db,
+                                                                       os_state->get_info(os_state), e);
                                        e->destroy(e);
 
-                                       /* Received at least one Installed Packages attribute */
-                                       os_state->set_package_request(os_state, FALSE);
+                                       switch (status)
+                                       {
+                                               case VERIFY_ERROR:
+                                                       state->set_recommendation(state,
+                                                               TNC_IMV_ACTION_RECOMMENDATION_ISOLATE,
+                                                               TNC_IMV_EVALUATION_RESULT_NONCOMPLIANT_MINOR);
+                                                       assessment = TRUE;
+                                                       break;
+                                               case FAILED:
+                                                       state->set_recommendation(state,
+                                                               TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
+                                                               TNC_IMV_EVALUATION_RESULT_ERROR);
+                                                       assessment = TRUE;
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
                                        break;
                                }
                                default:
@@ -529,6 +565,8 @@ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id)
                DBG1(DBG_IMV, "IMV \"%s\" has not been initialized", imv_name);
                return TNC_RESULT_NOT_INITIALIZED;
        }
+       DESTROY_IF(os_db);
+
        imv_os->destroy(imv_os);
        imv_os = NULL;
 
diff --git a/src/libimcv/plugins/imv_os/imv_os_database.c b/src/libimcv/plugins/imv_os/imv_os_database.c
new file mode 100644 (file)
index 0000000..a2be433
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2012 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include "imv_os_database.h"
+
+#include <utils/debug.h>
+
+typedef struct private_imv_os_database_t private_imv_os_database_t;
+
+/**
+ * Private data of a imv_os_database_t object.
+ *
+ */
+struct private_imv_os_database_t {
+
+       /**
+        * Public imv_os_database_t interface.
+        */
+       imv_os_database_t public;
+
+       /**
+        * database instance
+        */
+       database_t *db;
+
+};
+
+METHOD(imv_os_database_t, check_packages, status_t,
+       private_imv_os_database_t *this, char *os_info,
+       enumerator_t *package_enumerator)
+{
+       char *product, *package, *release, *cur_release, *pos;
+       size_t len;
+       int pid, gid, security, i;
+       int count = 0, count_ok = 0, count_no_match = 0, count_not_found = 0;
+       enumerator_t *e;
+       chunk_t name, version;
+       status_t status = SUCCESS;
+       bool found, match;
+
+       char *platform[] = {
+               "i686",
+               "x86_64"
+       };
+
+       /* looking for appended platform info */
+       for (i = 0; i < countof(platform); i++)
+       {
+               pos = strstr(os_info, platform[i]);
+               if (pos)
+               {
+                       break;
+               }
+       }
+       if (pos)
+       {
+               /* Remove platform info, leaving OS name and version only */
+               len = pos - os_info - 1;
+               product = malloc(len + 1);
+               memcpy(product, os_info, len);
+               product[len] = '\0';
+       }
+       else
+       {
+               product = strdup(os_info);
+       }
+
+       /* Get primary key of product */
+       e = this->db->query(this->db,
+                               "SELECT id FROM products WHERE name = ?",
+                               DB_TEXT, product, DB_INT);
+       if (!e)
+       {
+               free(product);
+               return FAILED;
+       }
+       if (!e->enumerate(e, &pid))
+       {
+               e->destroy(e);
+               free(product);
+               return NOT_FOUND;
+       }
+       e->destroy(e);
+
+       DBG1(DBG_IMV, "'%s': pid = %d", product, pid);
+
+       while (package_enumerator->enumerate(package_enumerator, &name, &version))
+       {
+               /* Convert package name chunk to a string */
+               package = malloc(name.len + 1);
+               memcpy(package, name.ptr, name.len);
+               package[name.len] = '\0';
+               count++;
+
+               /* Get primary key of package */
+               e = this->db->query(this->db,
+                                       "SELECT id FROM packages WHERE name = ?",
+                                       DB_TEXT, package, DB_INT);
+               if (!e)
+               {
+                       free(product);
+                       free(package);
+                       return FAILED;
+               }
+               if (!e->enumerate(e, &gid))
+               {
+                       /* not found in database vor any product - skip */
+                       count_not_found++;
+                       e->destroy(e);
+                       continue;
+               }
+               e->destroy(e);
+
+               /* Convert package version chunk to a string */
+               release = malloc(version.len + 1);
+               memcpy(release, version.ptr, version.len);
+               release[version.len] = '\0';
+
+               /* Enumerate over all acceptable versions */
+               e = this->db->query(this->db,
+                               "SELECT release, security FROM versions "
+                               "WHERE product = ? AND package = ?",
+                               DB_INT, pid, DB_INT, gid, DB_TEXT, DB_INT);
+               if (!e)
+               {
+                       free(product);
+                       free(package);
+                       free(release);
+                       return FAILED;
+               }
+               found = FALSE;
+               match = FALSE;
+
+               while (e->enumerate(e, &cur_release, &security))
+               {
+                       found = TRUE;
+                       if (streq(release, cur_release))
+                       {
+                               match = TRUE;
+                               break;
+                       }
+               }
+               e->destroy(e);
+               
+               if (found)
+               {
+                       if (match)
+                       {
+                               DBG2(DBG_IMV, "package '%s' (%s)%s is ok", package, release,
+                                                          security ? " [s]" : "");
+                               count_ok++;
+                       }
+                       else
+                       {
+                               DBG1(DBG_IMV, "package '%s' (%s) no match", package, release);
+                               count_no_match++;
+                               status = VERIFY_ERROR;
+                       }
+               }
+               else
+               {
+                       count_not_found++;
+               }
+               free(package);
+               free(release);
+       }
+       free(product);
+
+       DBG1(DBG_IMV, "processed %d packages: %d ok, %d no match, %d not found",
+                count, count_ok, count_no_match, count_not_found);
+
+       return status;
+}
+
+METHOD(imv_os_database_t, destroy, void,
+       private_imv_os_database_t *this)
+{
+       this->db->destroy(this->db);
+       free(this);
+}
+
+/**
+ * See header
+ */
+imv_os_database_t *imv_os_database_create(char *uri)
+{
+       private_imv_os_database_t *this;
+
+       INIT(this,
+               .public = {
+                       .check_packages = _check_packages,
+                       .destroy = _destroy,
+               },
+               .db = lib->db->create(lib->db, uri),
+       );
+
+       if (!this->db)
+       {
+               DBG1(DBG_IMV,
+                        "failed to connect to OS database '%s'", uri);
+               free(this);
+               return NULL;
+       }
+
+       return &this->public;
+}
+
diff --git a/src/libimcv/plugins/imv_os/imv_os_database.h b/src/libimcv/plugins/imv_os/imv_os_database.h
new file mode 100644 (file)
index 0000000..b1e6b90
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2012 Andreas Steffen
+ * HSR Hochschule fuer Technik Rapperswil
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ *
+ * @defgroup imv_os_database_t imv_os_database
+ * @{ @ingroup imv_os_database
+ */
+
+#ifndef IMV_OS_DATABASE_H_
+#define IMV_OS_DATABASE_H_
+
+#include <library.h>
+
+typedef struct imv_os_database_t imv_os_database_t;
+
+/**
+ * Internal state of an imv_os_database_t instance
+ */
+struct imv_os_database_t {
+
+       /**
+        * Check Installed Packages for a given OS
+        *
+        * @param os_info                               OS name and version
+        * @param package_enumerator    enumerates over installed packages
+        */
+       status_t (*check_packages)(imv_os_database_t *this, char* os_info,
+                                                          enumerator_t *package_enumerator);
+
+       /**
+       * Destroys an imv_os_database_t object.
+       */
+       void (*destroy)(imv_os_database_t *this);
+
+};
+
+/**
+ * Create an imv_os_database_t instance
+ *
+ * @param uri                  database uri
+ */
+imv_os_database_t* imv_os_database_create(char *uri);
+
+#endif /** IMV_OS_DATABASE_H_ @}*/