[Openvas-commits] r1297 - in trunk/openvas-server: . openvasd

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Tue Sep 9 09:38:51 CEST 2008


Author: mwiegand
Date: 2008-09-09 09:38:50 +0200 (Tue, 09 Sep 2008)
New Revision: 1297

Modified:
   trunk/openvas-server/ChangeLog
   trunk/openvas-server/openvasd/oval_plugins.c
Log:
Adding preliminary support for OVAL definitions. Second step for change
request #13 (Integrating the OVAL interpreter ovaldi into OpenVAS
Server) (http://www.openvas.org/openvas-cr-13.html)


Modified: trunk/openvas-server/ChangeLog
===================================================================
--- trunk/openvas-server/ChangeLog	2008-09-08 08:15:09 UTC (rev 1296)
+++ trunk/openvas-server/ChangeLog	2008-09-09 07:38:50 UTC (rev 1297)
@@ -1,5 +1,14 @@
-2008-09-02  Michael Wiegand <michael.wiegand at intevation.de>
+2008-09-09  Michael Wiegand <michael.wiegand at intevation.de>
 
+	Adding preliminary support for OVAL definitions. Second step for change
+	request #13 (Integrating the OVAL interpreter ovaldi into OpenVAS
+	Server) (http://www.openvas.org/openvas-cr-13.html)
+
+	* openvasd/oval_plugins.c: First usable proof-of-concept integration of
+	OVAL definitions into OpenVAS.
+
+2008-09-08  Michael Wiegand <michael.wiegand at intevation.de>
+
 	* openvasd/comm.c (extract_extensions): Removed superfluous else that
 	broke compilation.
 

Modified: trunk/openvas-server/openvasd/oval_plugins.c
===================================================================
--- trunk/openvas-server/openvasd/oval_plugins.c	2008-09-08 08:15:09 UTC (rev 1296)
+++ trunk/openvas-server/openvasd/oval_plugins.c	2008-09-09 07:38:50 UTC (rev 1297)
@@ -22,11 +22,25 @@
 *
 */
 
+/*
+ * DISCLAIMER: This is just a proof-of-concept for OVAL support in OpenVAS.
+ * It currently supports only a part of the objects specified in the OVAL
+ * specification and requires a patched version of ovaldi, the OVAL definition
+ * interpreter.
+ */
+
 #include <includes.h>
 #include "pluginload.h"
-// #include "log.h"
+#include "log.h"
 #include <glib.h>
+#include "processes.h"
+#include "corevers.h"
 
+static void oval_thread(struct arglist *);
+void ovaldi_launch(struct arglist * g_args);
+
+// TODO: A better way to store the results of the XML parser would be to use the
+// user_data pointer provided by the glib XML parser.
 gchar * id;
 gchar * oid;
 gchar * version;
@@ -35,18 +49,19 @@
 gboolean in_description = FALSE;
 gboolean in_definition = FALSE;
 gboolean in_title = FALSE;
+gboolean in_results = FALSE;
+gboolean in_results_definition = FALSE;
+gchar * result;
 
-void start_element (GMarkupParseContext *context,
-                    const gchar         *element_name,
-                    const gchar        **attribute_names,
-                    const gchar        **attribute_values,
-                    gpointer             user_data,
-                    GError             **error)
+void start_element (GMarkupParseContext *context, const gchar *element_name,
+                    const gchar **attribute_names,
+                    const gchar **attribute_values, gpointer user_data,
+                    GError **error)
 {
   const gchar **name_cursor = attribute_names;
   const gchar **value_cursor = attribute_values;
 
-  if(strcmp(element_name, "definition") == 0)
+  if(!in_results && strcmp(element_name, "definition") == 0)
   {
     in_definition = TRUE;
     while(*name_cursor)
@@ -54,6 +69,8 @@
       if (strcmp (*name_cursor, "id") == 0)
       {
         id = g_strrstr(g_strdup(*value_cursor), ":") + 1;
+        // TODO: This currently assigns only IDs in the range intended for
+        // RedHat security advisories.
         oid = g_strconcat("1.3.6.1.4.1.25623.1.2.2312.", id, NULL);
       }
       if (strcmp (*name_cursor, "version") == 0)
@@ -68,17 +85,32 @@
 
   if(strcmp(element_name, "title") == 0)
     in_title = TRUE;
+
+  if(strcmp(element_name, "results") == 0)
+    in_results = TRUE;
+
+  if(in_results && strcmp(element_name, "definition") == 0)
+  {
+    in_results_definition = TRUE;
+    while(*name_cursor)
+    {
+      if (strcmp (*name_cursor, "result") == 0)
+        result = g_strdup(*value_cursor);
+
+      name_cursor++;
+      value_cursor++;
+    }
+  }
 }
 
-void text(GMarkupParseContext *context,
-          const gchar         *text,
-          gsize                text_len,
-          gpointer             user_data,
-          GError             **error)
+void text(GMarkupParseContext *context, const gchar *text, gsize text_len,
+          gpointer user_data, GError **error)
 {
   if (in_description)
   {
-    description = g_strndup(text, 3070);
+    // NOTE: This currently cuts off descriptions longer than the maximum length
+    // specified in libopenvas/store_internal.h
+    description = g_strndup(text, 3190);
   }
   if (in_title)
   {
@@ -87,32 +119,32 @@
   }
 }
 
-void end_element (GMarkupParseContext *context,
-                  const gchar         *element_name,
-                  gpointer             user_data,
-                  GError             **error)
+void end_element (GMarkupParseContext *context, const gchar *element_name,
+                  gpointer user_data, GError **error)
 {
-    in_description = FALSE;
-    in_definition = FALSE;
-    in_title = FALSE;
+  in_description = FALSE;
+  in_definition = FALSE;
+  in_title = FALSE;
+  if(strcmp(element_name, "results") == 0)
+    in_results = FALSE;
+  if(in_results && strcmp(element_name, "definition") == 0)
+    in_results_definition = FALSE;
 }
 
 /*
- *  Initialize this class
+ *  Initialize the plugin class
  */
-pl_class_t* oval_plugin_init(struct arglist* prefs, struct arglist* args) {
+pl_class_t* oval_plugin_init(struct arglist* prefs, struct arglist* args)
+{
     return &oval_plugin_class;
 }
 
 /*
  * add *one* OVAL definition to the server list
  */
-struct arglist * 
-oval_plugin_add(folder, name, plugins, preferences)
-     char * folder;
-     char * name;
-     struct arglist * plugins;
-     struct arglist * preferences;
+struct arglist * oval_plugin_add(char * folder, char * name,
+                                 struct arglist * plugins,
+                                 struct arglist * preferences)
 {
   char fullname[PATH_MAX+1];
   struct arglist * args = NULL;
@@ -127,15 +159,16 @@
 
   if(args == NULL)
   {
-    // Parse plugin properties in to arglist
+    // Parse plugin properties into arglist
     parser.start_element = start_element;
     parser.end_element = end_element;
     parser.text = text;
     parser.passthrough = NULL;
     parser.error = NULL;
 
-    if (!g_file_get_contents(fullname, &filebuffer, &length, NULL)) {
-      g_warning("File %s not found", fullname);
+    if(!g_file_get_contents(fullname, &filebuffer, &length, NULL))
+    {
+      log_write("oval_plugin_add: File %s not found", fullname);
       return NULL;
     }
 
@@ -146,24 +179,27 @@
 
     args = emalloc(sizeof(struct arglist));
 
+    // NOTE: Due to the way OIDs/IDs are assigned right now, this does lead to
+    // an incorrect OID being set and reported to the client. This is due to
+    // restrictions in NTP and will likely change once the switch to OTP is
+    // complete.
     plug_set_oid(args, oid);
-    plug_set_id(args, (int)id);
+    plug_set_id(args, (int)id); // <- Overwrites OID with Legacy OID
 
     plug_set_version(args, version);
     plug_set_name(args, title, NULL);
     plug_set_description(args, description, NULL);
-    plug_set_category(args, ACT_ATTACK);
+    plug_set_category(args, ACT_END);
     plug_set_family(args, "OVAL definitions", NULL);
 
     store_plugin(args, name);
     args = store_load_plugin(folder, name, preferences);
   }
 
-  if( args != NULL )
+  if(args != NULL)
   {
     prev_plugin = arg_get_value(plugins, name);
-//     plug_set_launch(args, LAUNCH_DISABLED);
-    if( prev_plugin == NULL )
+    if(prev_plugin == NULL)
       arg_add_value(plugins, name, ARG_ARGLIST, -1, args);
     else
     {
@@ -176,20 +212,251 @@
   return NULL;
 }
 
+/*
+ * Launch an OVAL plugin
+ */
+int oval_plugin_launch(struct arglist * globals, struct arglist * plugin,
+                       struct arglist * hostinfos, struct arglist * preferences,
+                       struct kb_item ** kb, char * name)
+{
+  nthread_t module;
+  arg_add_value(plugin, "globals", ARG_ARGLIST, -1, globals);
+  arg_add_value(plugin, "HOSTNAME", ARG_ARGLIST, -1, hostinfos);
+  arg_add_value(plugin, "name", ARG_STRING, strlen(name), name);
+  arg_set_value(plugin, "preferences", -1, preferences);
+  arg_add_value(plugin, "key", ARG_PTR, -1, kb);
 
-int
-oval_plugin_launch(globals, plugin, hostinfos, preferences, kb, name)
-	struct arglist * globals;
-	struct arglist * plugin;
-	struct arglist * hostinfos;
-	struct arglist * preferences;
-	struct kb_item ** kb; /* knowledge base */
-	char * name;
+  module = create_process((process_func_t)oval_thread, plugin);
+  return module;
+}
+
+/*
+ * Create a thread for the OVAL plugin
+ */
+static void oval_thread(struct arglist * g_args)
 {
-	printf("Would launch %s ... \n", name);
-	return 0;
+  struct arglist * args = arg_get_value(g_args, "args");
+  int soc = (int)arg_get_value(g_args, "SOCKET");
+  struct arglist * globals = arg_get_value(args, "globals");
+
+  soc = dup2(soc, 4);
+  if(soc < 0)
+  {
+    log_write("oval_thread: dup2() failed ! - can not launch the plugin\n");
+    return;
+  }
+  arg_set_value(args, "SOCKET", sizeof(int), (void*)soc);
+  arg_set_value(globals, "global_socket", sizeof(int), (void*)soc);
+
+  setproctitle("testing %s (%s)",
+               (char*)arg_get_value(arg_get_value(args, "HOSTNAME"), "NAME"),
+               (char*)arg_get_value(g_args, "name"));
+  signal(SIGTERM, _exit);
+
+  ovaldi_launch(g_args);
+  internal_send(soc, NULL, INTERNAL_COMM_MSG_TYPE_CTRL | INTERNAL_COMM_CTRL_FINISHED);
 }
 
+/*
+ * This function will generate an OVAL system characteristics document from the
+ * data available in the knowledge base (KB), run ovaldi and return the results
+ * to the client.
+ */
+void ovaldi_launch(struct arglist * g_args)
+{
+  gchar * sc_filename;
+  gchar * results_filename;
+  FILE * sc_file;
+  time_t t;
+  struct tm *tmp;
+  char timestr[20];
+  struct arglist * args = arg_get_value(g_args, "args");
+  struct kbitem ** kb = arg_get_value(g_args, "key");
+  gchar * basename = g_strrstr(g_strdup((char*)arg_get_value(g_args, "name")), "/") + 1;
+  gchar * result_string = emalloc(256);
+  gchar * folder = g_strndup((char*)arg_get_value(g_args, "name"), strlen((char*)arg_get_value(g_args, "name")) - strlen(basename));
+
+  sc_filename = g_strconcat(folder, "sc-out.xml", NULL);
+  log_write("SC Filename: %s\n", sc_filename);
+  results_filename = "/tmp/results.xml";
+
+  sc_file = fopen(sc_filename, "w");
+  if(sc_file == NULL)
+  {
+    sprintf(result_string, "Could not launch ovaldi for OVAL definition %s: Could not create SC file.\n\n", basename);
+    post_note(g_args, 0, result_string);
+    efree(&sc_filename);
+  }
+  else
+  {
+    fprintf(sc_file, "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\" ?>\n");
+    fprintf(sc_file, "<oval_system_characteristics xmlns=\"http://oval.mitre.org/XMLSchema/oval-system-characteristics-5\" xmlns:linux-sc=\"http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#linux\" xmlns:oval=\"http://oval.mitre.org/XMLSchema/oval-common-5\" xmlns:oval-sc=\"http://oval.mitre.org/XMLSchema/oval-system-characteristics-5\" xmlns:unix-sc=\"http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#unix\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://oval.mitre.org/XMLSchema/oval-system-characteristics-5 oval-system-characteristics-schema.xsd http://oval.mitre.org/XMLSchema/oval-common-5 oval-common-schema.xsd http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#unix unix-system-characteristics-schema.xsd http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#linux linux-system-characteristics-schema.xsd\">\n\n");
+    
+    t = time(NULL);
+    tmp = localtime(&t);
+    strftime(timestr, sizeof(timestr), "%FT%T", tmp);
+    fprintf(sc_file, "\t<generator>\n\t\t<oval:product_name>%s</oval:product_name>\n\t\t<oval:product_version>%s</oval:product_version>\n\t\t<oval:schema_version>5.4</oval:schema_version>\n\t\t<oval:timestamp>%s</oval:timestamp>\n\t\t<vendor>The OpenVAS Project</vendor>\n\t</generator>\n\n", PROGNAME, OPENVAS_FULL_VERSION, timestr);
+    
+    fprintf(sc_file, "\t<system_info>\n\t\t<os_name></os_name>\n\t\t<os_version></os_version>\n\t\t<architecture></architecture>\n\t\t<primary_host_name>%s</primary_host_name>\n\t\t<interfaces>\n\t\t\t<interface>\n\t\t\t\t<interface_name></interface_name>\n\t\t\t\t<ip_address></ip_address>\n\t\t\t\t<mac_address></mac_address>\n\t\t\t</interface>\n\t\t</interfaces>\n\t</system_info>\n\n", (char*)arg_get_value(arg_get_value(args, "HOSTNAME"), "NAME"));
+    fprintf(sc_file, "\t<system_data>\n");
+
+    int i = 1;
+
+    // Get the open TCP ports from the KB and build <inetlisteningserver_item>
+    struct kb_item * res = kb_item_get_pattern(kb, "Ports/tcp/*");
+
+    while(res)
+    {
+      fprintf(sc_file, "\t\t<inetlisteningserver_item id=\"%d\" xmlns=\"http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#linux\">\n", i);
+      fprintf(sc_file, "\t\t\t<protocol>tcp</protocol>\n");
+      fprintf(sc_file, "\t\t\t<local_address/>\n");
+      fprintf(sc_file, "\t\t\t<local_port>%s</local_port>\n", g_strrstr(res->name, "/") + 1);
+      fprintf(sc_file, "\t\t\t<local_full_address/>\n\t\t\t<program_name/>\n\t\t\t<foreign_address/>\n\t\t\t<foreign_port/>\n\t\t\t<foreign_full_address/>\n\t\t\t<pid/>\n\t\t\t<user_id/>\n");
+      fprintf(sc_file, "\t\t</inetlisteningserver_item>\n");
+      i++;
+      res = res->next;
+    }
+
+    // Test if ssh/login/release is present in the KB; this means that an
+    // information gathering plugin has collected release and possibly package
+    // information from the remote system.
+    if(kb_item_get_str(kb, "ssh/login/release") == NULL)
+    {
+      log_write("Could not identify release, not collecting package information.\n");
+      sprintf(result_string, "Could not collect remote package information for OVAL definition %s: Result may be incomplete.\n\n", basename);
+      post_note(g_args, 0, result_string);
+
+    }
+    else
+    {
+      // TODO: Right now, every plugin needs to parse the package data in the KB
+      // by itself and dependent on the detected release since they are not
+      // stored in a structured way by the collecting plugin.
+      if(strstr(kb_item_get_str(kb, "ssh/login/release"), "DEB") != NULL)
+      {
+        log_write("Detected Debian package information\n");
+        char * packages_str = kb_item_get_str(kb, "ssh/login/packages");
+
+        if(packages_str)
+        {
+          gchar ** package = g_strsplit(packages_str, "\n", 0);
+          int j = 5;
+          while(package[j] != NULL)
+          {
+            strtok(package[j], " ");
+            fprintf(sc_file, "\t\t<dpkginfo_item id=\"%d\" xmlns=\"http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#linux\">\n", i);
+            fprintf(sc_file, "\t\t\t<name>%s</name>\n", strtok(NULL, " "));
+            fprintf(sc_file, "\t\t\t<arch/>\n");
+            fprintf(sc_file, "\t\t\t<epoch/>\n");
+            fprintf(sc_file, "\t\t\t<release/>\n");
+            fprintf(sc_file, "\t\t\t<version>%s</version>\n", strtok(NULL, " "));
+            fprintf(sc_file, "\t\t\t<evr/>\n");
+            fprintf(sc_file, "\t\t</dpkginfo_item>\n");
+            i++;
+            j++;
+          }
+          g_strfreev(package);
+        }
+      }
+
+      // NOTE: This parser should work for other RPM-based distributions as well.
+      if(strstr(kb_item_get_str(kb, "ssh/login/release"), "RH") != NULL)
+      {
+        log_write("Detected RedHat package information\n");
+        char * packages_str = kb_item_get_str(kb, "ssh/login/rpms");
+
+        if(packages_str)
+        {
+          gchar ** package = g_strsplit(packages_str, ";", 0);
+          int j = 0;
+          char keyid[17];
+          keyid[16] = '\0';
+          char * package_name;
+          char * package_version;
+          char * package_release;
+          while(package[j] != NULL)
+          {
+            gchar * pgpsig = strncpy(keyid, package[j] + strlen(package[j]) - 16, 16);
+            package_name = strtok(package[j], "~");
+            package_version = strtok(NULL, "~");
+            package_release = strtok(NULL, "~");
+            if(package_name)
+            {
+              fprintf(sc_file, "\t\t<rpminfo_item id=\"%d\" xmlns=\"http://oval.mitre.org/XMLSchema/oval-system-characteristics-5#linux\">\n", i);
+              fprintf(sc_file, "\t\t\t<name>%s</name>\n", package_name);
+              fprintf(sc_file, "\t\t\t<arch/>\n");
+              fprintf(sc_file, "\t\t\t<epoch/>\n");
+              fprintf(sc_file, "\t\t\t<release>%s</release>\n", package_release);
+              fprintf(sc_file, "\t\t\t<version>%s</version>\n", package_version);
+              fprintf(sc_file, "\t\t\t<evr/>\n");
+              fprintf(sc_file, "\t\t\t<signature_keyid>%s</signature_keyid>\n", pgpsig);
+              fprintf(sc_file, "\t\t</rpminfo_item>\n");
+            }
+            i++;
+            j++;
+          }
+          g_strfreev(package);
+        }
+      }
+    }
+
+    fprintf(sc_file, "\t</system_data>\n\n");
+    fprintf(sc_file, "</oval_system_characteristics>\n");
+  }
+  if(sc_file != NULL)
+    fclose(sc_file);
+
+  gchar ** argv = (gchar **)g_malloc (9 * sizeof (gchar *));
+  argv[0] = g_strdup("ovaldi");
+  argv[1] = g_strdup("-m");  // Do not check OVAL MD5 signature
+  argv[2] = g_strdup("-o");  // Request the use of _this_ plugin
+  argv[3] = g_strdup((char*)arg_get_value(g_args, "name"));
+  argv[4] = g_strdup("-i");  // Request the use of the system characteristics retrieved from the KB
+  argv[5] = g_strdup(sc_filename);
+  argv[6] = g_strdup("-r");  // Store the scan results where we can parse them
+  argv[7] = g_strdup(results_filename);
+  argv[8] = NULL;
+//   log_write("Launching ovaldi with: %s\n", g_strjoinv(" ", argv));
+
+  if(g_spawn_sync(NULL, argv, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL))
+  {
+    GMarkupParser parser; 
+    GMarkupParseContext *context = NULL;
+    gchar *filebuffer = NULL;
+    guint length = 0;
+
+    parser.start_element = start_element;
+    parser.end_element = end_element;
+    parser.text = text;
+    parser.passthrough = NULL;
+    parser.error = NULL;
+
+    if(!g_file_get_contents(results_filename, &filebuffer, &length, NULL))
+    {
+      sprintf(result_string,
+              "Could not return results for OVAL definition %s: Results file not found.\n\n",
+              basename);
+      post_note(g_args, 0, result_string);
+      log_write("Results file %s not found!\n", results_filename);
+    }
+    else
+    {
+      context = g_markup_parse_context_new(&parser, 0, NULL, NULL);
+      g_markup_parse_context_parse(context, filebuffer, length, NULL);
+      g_free(filebuffer);
+      g_markup_parse_context_free(context);
+      sprintf(result_string, "The OVAL definition %s returned the following result: %s\n\n", basename, result);
+      post_note(g_args, 0, result_string);
+    }
+  }
+  else
+  {
+    sprintf(result_string, "Could not launch ovaldi for OVAL definition %s: Launch failed. (Is ovaldi in your PATH?)\n\n", basename);
+    post_note(g_args, 0, result_string);
+    log_write("Could not launch ovaldi!\n");
+  }
+}
+
 pl_class_t oval_plugin_class = {
     NULL,
     ".oval",



More information about the Openvas-commits mailing list