[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