diff --git a/src/gmp.c b/src/gmp.c
index 1264e7028..6674d870a 100644
--- a/src/gmp.c
+++ b/src/gmp.c
@@ -138,7 +138,7 @@
/** @todo Exported for manage_sql.c. */
void
buffer_results_xml (GString *, iterator_t *, task_t, int, int, int, int, int,
- int, int, const char *, iterator_t *, int, int, int);
+ int, int, const char *, iterator_t *, int, int, int, int);
/* Helper functions. */
@@ -8181,7 +8181,8 @@ buffer_notes_xml (GString *buffer, iterator_t *notes, int include_notes_details,
NULL,
0,
-1,
- 0); /* Lean. */
+ 0, /* Lean. */
+ 0); /* Delta fields. */
cleanup_iterator (&results);
}
else
@@ -8464,7 +8465,8 @@ buffer_overrides_xml (GString *buffer, iterator_t *overrides,
NULL,
0,
-1,
- 0); /* Lean. */
+ 0, /* Lean. */
+ 0); /* Delta fields. */
cleanup_iterator (&results);
}
else
@@ -9137,6 +9139,42 @@ results_xml_append_nvt (iterator_t *results, GString *buffer, int cert_loaded)
buffer_xml_append_printf (buffer, "");
}
+/**
+ * @brief Append a diff of the two result descriptions to an XML buffer.
+ *
+ * @param[in] buffer Buffer.
+ * @param[in] descr First result description.
+ * @param[in] delta_descr Second result description.
+ *
+ */
+void
+buffer_diff(GString *buffer, const char *descr, const char *delta_descr)
+{
+
+ gchar *diff = strdiff (descr ? descr : "",
+ delta_descr ? delta_descr : "");
+ if (diff)
+ {
+ gchar **split, *diff_xml;
+ /* Remove the leading filename lines. */
+ split = g_strsplit ((gchar*) diff, "\n", 3);
+ if (split[0] && split[1] && split[2])
+ diff_xml = xml_escape_text_truncated (split[2],
+ TRUNCATE_TEXT_LENGTH,
+ TRUNCATE_TEXT_SUFFIX);
+ else
+ diff_xml = xml_escape_text_truncated (diff,
+ TRUNCATE_TEXT_LENGTH,
+ TRUNCATE_TEXT_SUFFIX);
+ g_strfreev (split);
+ g_string_append_printf (buffer, "%s", diff_xml);
+ g_free (diff_xml);
+ g_free (diff);
+ }
+ else
+ g_string_append (buffer, "Error creating diff.");
+}
+
/** @todo Exported for manage_sql.c. */
/**
* @brief Buffer XML for some results.
@@ -9162,6 +9200,7 @@ results_xml_append_nvt (iterator_t *results, GString *buffer, int cert_loaded)
* @param[in] cert_loaded Whether the CERT db is loaded. 0 not loaded,
* -1 needs to be checked, else loaded.
* @param[in] lean Whether to include less info.
+ * @param[in] use_delta_fields Whether to use delta result fields.
*/
void
buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
@@ -9170,18 +9209,62 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
int include_tags, int include_tags_details,
int include_details,
const char *delta_state, iterator_t *delta_results,
- int changed, int cert_loaded, int lean)
+ int changed, int cert_loaded, int lean, int use_delta_fields)
{
- const char *descr = result_iterator_descr (results);
- const char *name, *comment, *creation_time;
- const char *port, *path;
- const char *asset_id;
- gchar *nl_descr, *nl_descr_escaped;
- const char *qod = result_iterator_qod (results);
- const char *qod_type = result_iterator_qod_type (results);
- result_t result = result_iterator_result (results);
+
+ const char *descr, *name, *comment, *creation_time;
+ const char *severity, *original_severity, *original_level;
+ const char *host, *hostname, *result_id, *port, *path, *asset_id, *qod, *qod_type;
char *detect_oid, *detect_ref, *detect_cpe, *detect_loc, *detect_name;
+ double severity_double;
+ gchar *nl_descr, *nl_descr_escaped;
+ result_t result;
+ report_t report;
task_t selected_task;
+
+ comment = get_iterator_comment (results);
+ name = get_iterator_name (results);
+ host = result_iterator_host (results);
+ port = result_iterator_port (results);
+ asset_id = NULL;
+
+ if (use_delta_fields)
+ {
+ descr = result_iterator_delta_description (results);
+ severity = result_iterator_delta_severity (results);
+ severity_double = result_iterator_delta_severity_double (results);
+ original_severity = result_iterator_delta_original_severity (results);
+ original_level = result_iterator_delta_original_level (results);
+ qod = result_iterator_delta_qod (results);
+ qod_type = result_iterator_delta_qod_type (results);
+ result = result_iterator_delta_result (results);
+ creation_time = result_iterator_delta_creation_time (results);
+ result_id = result_iterator_delta_uuid (results);
+ path = result_iterator_delta_path (results);
+ report = result_iterator_delta_report (results);
+ hostname = result_iterator_delta_hostname (results);
+ if (host)
+ asset_id = result_iterator_delta_host_asset_id (results);
+ }
+ else
+ {
+ descr = result_iterator_descr (results);
+ severity = result_iterator_severity (results);
+ severity_double = result_iterator_severity_double (results);
+ original_severity = result_iterator_original_severity (results);
+ original_level = result_iterator_original_level (results);
+ qod = result_iterator_qod (results);
+ qod_type = result_iterator_qod_type (results);
+ result = result_iterator_result (results);
+ creation_time = get_iterator_creation_time (results);
+ result_id = get_iterator_uuid (results);
+ path = result_iterator_path (results);
+ report = result_iterator_report (results);
+ hostname = result_iterator_hostname (results);
+ if (host)
+ asset_id = result_iterator_asset_host_id (results);
+ }
+
if (descr)
{
@@ -9198,11 +9281,10 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
buffer_xml_append_printf (buffer,
"",
- get_iterator_uuid (results));
+ result_id);
selected_task = task;
- name = get_iterator_name (results);
if (name)
buffer_xml_append_printf (buffer,
"%s",
@@ -9211,28 +9293,35 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
if (lean == 0)
{
const char *owner_name, *modification_time;
+
+ if (use_delta_fields)
+ {
+ owner_name = result_iterator_delta_owner_name (results);
+ modification_time = result_iterator_delta_modification_time (results);
+ }
+ else
+ {
+ owner_name = get_iterator_owner_name (results);
+ modification_time = get_iterator_modification_time (results);
+ }
- owner_name = get_iterator_owner_name (results);
if (owner_name)
buffer_xml_append_printf (buffer,
"%s",
owner_name);
- modification_time = get_iterator_modification_time (results);
if (modification_time)
buffer_xml_append_printf (buffer,
"%s",
modification_time);
}
- comment = get_iterator_comment (results);
if (comment
&& (lean == 0 || strlen (comment)))
buffer_xml_append_printf (buffer,
"%s",
comment);
- creation_time = get_iterator_creation_time (results);
if (creation_time)
buffer_xml_append_printf (buffer,
"%s",
@@ -9242,13 +9331,23 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
{
char *result_report_id, *result_task_id, *result_task_name;
- if (task == 0)
- selected_task = result_iterator_task (results);
-
+ if(use_delta_fields)
+ {
+ if (task == 0)
+ selected_task = result_iterator_delta_task (results);
+
+ result_task_name = task_name(result_iterator_delta_task (results));
+ result_report_id = report_uuid(result_iterator_delta_report (results));
+ }
+ else
+ {
+ if (task == 0)
+ selected_task = result_iterator_task (results);
+
+ result_task_name = task_name (result_iterator_task (results));
+ result_report_id = report_uuid (result_iterator_report (results));
+ }
task_uuid (selected_task, &result_task_id);
- result_task_name = task_name (result_iterator_task (results));
- result_report_id = report_uuid (result_iterator_report (results));
-
buffer_xml_append_printf (buffer,
""
"%s",
@@ -9298,11 +9397,11 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
}
}
- port = result_iterator_port (results);
- path = result_iterator_path (results);
detect_oid = detect_ref = detect_cpe = detect_loc = detect_name = NULL;
- if (result_detection_reference (result, result_iterator_report (results),
+
+ if (result_detection_reference (result,
+ report,
result_iterator_host (results), port, path,
&detect_oid, &detect_ref, &detect_cpe,
&detect_loc, &detect_name)
@@ -9329,15 +9428,10 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
g_free (detect_loc);
g_free (detect_name);
- if (result_iterator_host (results))
- asset_id = result_iterator_asset_host_id (results);
- else
- asset_id = NULL;
-
buffer_xml_append_printf (buffer,
""
"%s",
- result_iterator_host (results) ?: "");
+ host ?: "");
if (asset_id && strlen (asset_id))
buffer_xml_append_printf (buffer,
@@ -9350,7 +9444,7 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
buffer_xml_append_printf (buffer,
"%s"
"",
- result_iterator_hostname (results) ?: "");
+ hostname ?: "");
buffer_xml_append_printf (buffer,
"%s",
@@ -9366,18 +9460,31 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
results_xml_append_nvt (results, buffer, cert_loaded);
if (lean == 0)
- buffer_xml_append_printf
- (buffer,
- "%s"
- "%s",
- result_iterator_scan_nvt_version (results),
- result_iterator_level (results));
+ {
+ const char *nvt_version, *level;
+ if (use_delta_fields)
+ {
+ nvt_version = result_iterator_delta_nvt_version (results);
+ level = result_iterator_delta_level (results);
+ }
+ else
+ {
+ nvt_version = result_iterator_scan_nvt_version (results);
+ level = result_iterator_level (results);
+ }
+ buffer_xml_append_printf
+ (buffer,
+ "%s"
+ "%s",
+ nvt_version,
+ level);
+ }
buffer_xml_append_printf
(buffer,
"%.1f"
"%s",
- result_iterator_severity_double (results),
+ severity_double,
qod ? qod : "");
if (qod_type && strlen (qod_type))
@@ -9394,73 +9501,79 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
if (include_overrides && lean)
{
/* Only send the original severity if it has changed. */
- if (strncmp (result_iterator_original_severity (results),
- result_iterator_severity (results),
- /* Avoid rounding differences. */
- 3))
+ if (strncmp (original_severity,
+ severity,
+ /* Avoid rounding differences. */
+ 3))
buffer_xml_append_printf (buffer,
"%s",
- result_iterator_original_severity (results));
+ original_severity);
}
else if (include_overrides)
buffer_xml_append_printf (buffer,
"%s"
"%s",
- result_iterator_original_level (results),
- result_iterator_original_severity (results));
+ original_level,
+ original_severity);
if (include_notes
- && result_iterator_may_have_notes (results))
+ && use_delta_fields
+ ? result_iterator_delta_may_have_notes (results)
+ : result_iterator_may_have_notes (results))
buffer_result_notes_xml (buffer, result,
selected_task, include_notes_details, lean);
if (include_overrides
- && result_iterator_may_have_overrides (results))
+ && use_delta_fields
+ ? result_iterator_delta_may_have_overrides (results)
+ : result_iterator_may_have_overrides (results))
buffer_result_overrides_xml (buffer, result,
selected_task, include_overrides_details,
lean);
- if (delta_state || delta_results)
+ if (delta_state && use_delta_fields == 0)
{
g_string_append (buffer, "");
if (delta_state)
g_string_append_printf (buffer, "%s", delta_state);
- if (changed && delta_results)
- {
- gchar *diff, *delta_nl_descr;
- const char *delta_descr;
- buffer_results_xml (buffer, delta_results, selected_task,
- include_notes, include_notes_details,
- include_overrides, include_overrides_details,
- include_tags, include_tags_details,
- include_details, delta_state, NULL, 0, -1, lean);
- delta_descr = result_iterator_descr (delta_results);
- delta_nl_descr = delta_descr ? convert_to_newlines (delta_descr)
- : NULL;
- diff = strdiff (descr ? nl_descr : "",
- delta_descr ? delta_nl_descr : "");
- g_free (delta_nl_descr);
- if (diff)
- {
- gchar **split, *diff_xml;
- /* Remove the leading filename lines. */
- split = g_strsplit ((gchar*) diff, "\n", 3);
- if (split[0] && split[1] && split[2])
- diff_xml = xml_escape_text_truncated (split[2],
- TRUNCATE_TEXT_LENGTH,
- TRUNCATE_TEXT_SUFFIX);
- else
- diff_xml = xml_escape_text_truncated (diff,
- TRUNCATE_TEXT_LENGTH,
- TRUNCATE_TEXT_SUFFIX);
- g_strfreev (split);
- g_string_append_printf (buffer, "%s", diff_xml);
- g_free (diff_xml);
- g_free (diff);
- }
- else
- g_string_append (buffer, "Error creating diff.");
- }
+
+ if(delta_results) {
+ /* delta reports version 1 */
+ if (changed)
+ {
+ gchar *delta_nl_descr;
+ const char *delta_descr;
+ buffer_results_xml (buffer, delta_results, selected_task,
+ include_notes, include_notes_details,
+ include_overrides, include_overrides_details,
+ include_tags, include_tags_details,
+ include_details, delta_state, NULL, 0, -1,
+ lean, 0);
+ delta_descr = result_iterator_descr (delta_results);
+ delta_nl_descr = delta_descr ? convert_to_newlines (delta_descr)
+ : NULL;
+ buffer_diff (buffer, nl_descr, delta_nl_descr);
+ g_free (delta_nl_descr);
+ }
+ } else {
+ /* delta reports version 2 */
+ if (changed)
+ {
+ gchar *delta_nl_descr;
+ const char *delta_descr;
+ buffer_results_xml (buffer, results, selected_task,
+ include_notes, include_notes_details,
+ include_overrides, include_overrides_details,
+ include_tags, include_tags_details,
+ include_details, delta_state, NULL, 0, -1,
+ lean, 1);
+ delta_descr = result_iterator_delta_description (results);
+ delta_nl_descr = delta_descr ? convert_to_newlines (delta_descr)
+ : NULL;
+ buffer_diff (buffer, delta_nl_descr, nl_descr);
+ g_free (delta_nl_descr);
+ }
+ }
if (delta_results)
{
@@ -9487,7 +9600,9 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task,
g_free (nl_descr_escaped);
}
- if (result_iterator_may_have_tickets (results))
+ if (use_delta_fields
+ ? result_iterator_delta_may_have_tickets (results)
+ : result_iterator_may_have_tickets (results))
buffer_result_tickets_xml (buffer, result);
g_string_append (buffer, "");
@@ -15194,7 +15309,8 @@ handle_get_results (gmp_parser_t *gmp_parser, GError **error)
NULL,
0,
-1,
- 0); /* Lean. */
+ 0, /* Lean. */
+ 0); /* Delta fields. */
SEND_TO_CLIENT_OR_FAIL (buffer->str);
g_string_free (buffer, TRUE);
count ++;
diff --git a/src/manage.h b/src/manage.h
index 0b871973e..0e5399067 100644
--- a/src/manage.h
+++ b/src/manage.h
@@ -1521,6 +1521,78 @@ result_iterator_cert_bunds (iterator_t*);
gchar **
result_iterator_dfn_certs (iterator_t*);
+const char *
+result_iterator_delta_state (iterator_t*);
+
+const char *
+result_iterator_delta_description (iterator_t*);
+
+const char *
+result_iterator_delta_severity (iterator_t*);
+
+double
+result_iterator_delta_severity_double (iterator_t*);
+
+const char*
+result_iterator_delta_level (iterator_t*);
+
+const char *
+result_iterator_delta_original_severity (iterator_t*);
+
+double
+result_iterator_delta_original_severity_double (iterator_t*);
+
+const char*
+result_iterator_delta_original_level (iterator_t*);
+
+const char *
+result_iterator_delta_qod (iterator_t*);
+
+const char *
+result_iterator_delta_uuid (iterator_t*);
+
+const char *
+result_iterator_delta_qod_type (iterator_t*);
+
+const char *
+result_iterator_delta_creation_time (iterator_t*);
+
+const char *
+result_iterator_delta_modification_time (iterator_t*);
+
+task_t
+result_iterator_delta_task (iterator_t*);
+
+report_t
+result_iterator_delta_report (iterator_t*);
+
+const char *
+result_iterator_delta_owner_name (iterator_t*);
+
+const char *
+result_iterator_delta_path (iterator_t*);
+
+const char *
+result_iterator_delta_host_asset_id (iterator_t*);
+
+const char *
+result_iterator_delta_nvt_version (iterator_t*);
+
+result_t
+result_iterator_delta_result (iterator_t*);
+
+int
+result_iterator_delta_may_have_notes (iterator_t*);
+
+int
+result_iterator_delta_may_have_overrides (iterator_t*);
+
+int
+result_iterator_delta_may_have_tickets (iterator_t*);
+
+const char *
+result_iterator_delta_hostname (iterator_t*);
+
int
cleanup_result_nvts ();
diff --git a/src/manage_pg.c b/src/manage_pg.c
index 1e67cac98..b39368f7f 100644
--- a/src/manage_pg.c
+++ b/src/manage_pg.c
@@ -836,6 +836,53 @@ manage_create_sql_functions ()
"$$ LANGUAGE plpgsql"
" STABLE COST 1000;");
+ sql ("CREATE OR REPLACE FUNCTION compare_results ("
+ " description1 text,"
+ " description2 text,"
+ " severity1 double precision,"
+ " severity2 double precision,"
+ " qod1 integer,"
+ " qod2 integer,"
+ " hostname1 text,"
+ " hostname2 text,"
+ " path1 text,"
+ " path2 text)"
+ "RETURNS text AS $$ "
+ "BEGIN"
+ " CASE"
+ " WHEN description1 is null"
+ " OR severity1 is null"
+ " OR qod1 is null"
+ " THEN RETURN 'gone';"
+ " WHEN description2 is null"
+ " OR severity2 is null"
+ " OR qod2 is null"
+ " THEN RETURN 'new';"
+ " WHEN description1 != description2"
+ " OR severity1 != severity2"
+ " OR qod1 != qod2"
+ " OR hostname1 != hostname2"
+ " OR path1 != path2"
+ " THEN RETURN 'changed';"
+ " ELSE RETURN 'same';"
+ " END CASE;"
+ "END;"
+ "$$ LANGUAGE plpgsql"
+ " IMMUTABLE;");
+
+ sql ("CREATE OR REPLACE FUNCTION normalize_port ("
+ " port text)"
+ "RETURNS text AS $$ "
+ "BEGIN"
+ " CASE"
+ " WHEN port = 'package'"
+ " THEN RETURN 'general/tcp';"
+ " ELSE RETURN port;"
+ " END CASE;"
+ "END;"
+ "$$ LANGUAGE plpgsql"
+ " IMMUTABLE;");
+
/* Functions in SQL. */
if (sql_int ("SELECT (EXISTS (SELECT * FROM information_schema.tables"
diff --git a/src/manage_sql.c b/src/manage_sql.c
index 2445b63dd..9c61ab50e 100644
--- a/src/manage_sql.c
+++ b/src/manage_sql.c
@@ -22030,7 +22030,7 @@ where_qod (int min_qod)
" END)", \
NULL, \
KEYWORD_TYPE_INTEGER }, \
- { TICKET_SQL_RESULT_MAY_HAVE_TICKETS, \
+ { TICKET_SQL_RESULT_MAY_HAVE_TICKETS("results.id"), \
NULL, \
KEYWORD_TYPE_INTEGER }, \
{ "(SELECT name FROM tasks WHERE tasks.id = task)", \
@@ -22061,6 +22061,19 @@ where_qod (int min_qod)
{ NULL, NULL, KEYWORD_TYPE_UNKNOWN } \
}
+#define RESULT_HOSTNAME_SQL(hostname_col, host_col, report_col) \
+ "(CASE WHEN (" hostname_col " IS NULL) " \
+ " OR (" hostname_col " = '')" \
+ " THEN (SELECT value FROM report_host_details" \
+ " WHERE name = 'hostname'" \
+ " AND report_host = (SELECT id FROM report_hosts " \
+ " WHERE report_hosts.host = " host_col \
+ " AND" \
+ " report_hosts.report = " report_col ")" \
+ " LIMIT 1)" \
+ " ELSE " hostname_col \
+ " END)"
+
/**
* @brief Result iterator columns.
*/
@@ -22120,18 +22133,9 @@ where_qod (int min_qod)
KEYWORD_TYPE_STRING }, \
{ "results.qod", "qod", KEYWORD_TYPE_INTEGER }, \
{ "results.qod_type", NULL, KEYWORD_TYPE_STRING }, \
- { "(CASE WHEN (hostname IS NULL) OR (hostname = '')" \
- " THEN (SELECT value FROM report_host_details" \
- " WHERE name = 'hostname'" \
- " AND report_host = (SELECT id FROM report_hosts" \
- " WHERE report_hosts.host=results.host" \
- " AND report_hosts.report = results.report)" \
- " LIMIT 1)" \
- " ELSE hostname" \
- " END)", \
- "hostname", \
- KEYWORD_TYPE_STRING \
- }, \
+ { RESULT_HOSTNAME_SQL("hostname", "results.host", "results.report"), \
+ "hostname", \
+ KEYWORD_TYPE_STRING }, \
{ "(SELECT uuid FROM tasks WHERE id = task)", \
"task_id", \
KEYWORD_TYPE_STRING }, \
@@ -22175,7 +22179,7 @@ where_qod (int min_qod)
" END)", \
NULL, \
KEYWORD_TYPE_INTEGER }, \
- { TICKET_SQL_RESULT_MAY_HAVE_TICKETS, \
+ { TICKET_SQL_RESULT_MAY_HAVE_TICKETS("results.id"), \
NULL, \
KEYWORD_TYPE_INTEGER }, \
/* ^ 35 = 25 */ \
@@ -22229,6 +22233,103 @@ where_qod (int min_qod)
{ NULL, NULL, KEYWORD_TYPE_UNKNOWN } \
}
+/**
+ * @brief Delta result iterator columns.
+ */
+#define DELTA_RESULT_COLUMNS \
+ { "comparison.state", "delta_state", KEYWORD_TYPE_STRING }, \
+ { "comparison.delta_description", NULL, KEYWORD_TYPE_STRING }, \
+ { "comparison.delta_severity", NULL, KEYWORD_TYPE_DOUBLE }, \
+ { "comparison.delta_qod", NULL, KEYWORD_TYPE_INTEGER }, \
+ { "comparison.delta_uuid", NULL, KEYWORD_TYPE_STRING }, \
+ { "delta_qod_type", NULL, KEYWORD_TYPE_STRING }, \
+ { " iso_time (delta_date, opts.user_zone)", \
+ "delta_creation_time", \
+ KEYWORD_TYPE_STRING }, \
+ { " iso_time (delta_date, opts.user_zone)", \
+ "delta_modification_time", \
+ KEYWORD_TYPE_STRING }, \
+ { "delta_task", NULL, KEYWORD_TYPE_INTEGER }, \
+ { "delta_report", NULL, KEYWORD_TYPE_INTEGER }, \
+ { "(SELECT name FROM users WHERE users.id = results.owner)", \
+ "_owner", \
+ KEYWORD_TYPE_STRING }, \
+ { "delta_path", NULL, KEYWORD_TYPE_STRING }, \
+ { "(SELECT CASE WHEN delta_host IS NULL" \
+ " THEN NULL" \
+ " ELSE (SELECT uuid FROM hosts" \
+ " WHERE id = (SELECT host FROM host_identifiers" \
+ " WHERE source_type = 'Report Host'" \
+ " AND name = 'ip'" \
+ " AND source_id" \
+ " = (SELECT uuid" \
+ " FROM reports" \
+ " WHERE id = results.report)" \
+ " AND value = delta_host" \
+ " LIMIT 1))" \
+ " END)", \
+ NULL, \
+ KEYWORD_TYPE_STRING }, \
+ { "delta_nvt_version", NULL, KEYWORD_TYPE_STRING }, \
+ { "result2_id", NULL, KEYWORD_TYPE_INTEGER }, \
+ { "(SELECT CASE" \
+ " WHEN EXISTS (SELECT * FROM notes" \
+ " WHERE (result = result2_id" \
+ " OR (result = 0 AND nvt = results.nvt))" \
+ " AND (task = 0 OR task = delta_task))" \
+ " THEN 1" \
+ " ELSE 0" \
+ " END)", \
+ NULL, \
+ KEYWORD_TYPE_INTEGER }, \
+ { "(SELECT CASE" \
+ " WHEN EXISTS (SELECT * FROM overrides" \
+ " WHERE (result = result2_id" \
+ " OR (result = 0 AND nvt = results.nvt))" \
+ " AND (task = 0 OR task = delta_task))" \
+ " THEN 1" \
+ " ELSE 0" \
+ " END)", \
+ NULL, \
+ KEYWORD_TYPE_INTEGER }, \
+ { TICKET_SQL_RESULT_MAY_HAVE_TICKETS("result2_id"), \
+ NULL, \
+ KEYWORD_TYPE_INTEGER }, \
+ { "delta_hostname", NULL, KEYWORD_TYPE_STRING }, \
+ { "delta_new_severity", NULL, KEYWORD_TYPE_DOUBLE },
+
+/**
+ * @brief Delta result iterator columns.
+ */
+#define DELTA_RESULT_ITERATOR_COLUMNS \
+ { \
+ BASE_RESULT_ITERATOR_COLUMNS \
+ { SECINFO_SQL_RESULT_CERT_BUNDS, \
+ NULL, \
+ KEYWORD_TYPE_INTEGER }, \
+ { SECINFO_SQL_RESULT_DFN_CERTS, \
+ NULL, \
+ KEYWORD_TYPE_INTEGER }, \
+ DELTA_RESULT_COLUMNS \
+ { NULL, NULL, KEYWORD_TYPE_UNKNOWN } \
+ }
+
+/**
+ * @brief Result iterator columns, when CERT db is not loaded.
+ */
+#define DELTA_RESULT_ITERATOR_COLUMNS_NO_CERT \
+ { \
+ BASE_RESULT_ITERATOR_COLUMNS \
+ { "0", \
+ NULL, \
+ KEYWORD_TYPE_INTEGER }, \
+ { "0", \
+ NULL, \
+ KEYWORD_TYPE_INTEGER }, \
+ DELTA_RESULT_COLUMNS \
+ { NULL, NULL, KEYWORD_TYPE_UNKNOWN } \
+ }
+
/**
* @brief Result iterator columns, when CERT db is not loaded.
*/
@@ -22679,49 +22780,68 @@ init_result_get_iterator_severity (iterator_t* iterator, const get_data_t *get,
* @brief SQL for getting current severity.
*/
#define CURRENT_SEVERITY_SQL \
- "coalesce ((CASE WHEN results.severity > " G_STRINGIFY (SEVERITY_LOG) \
- " THEN CAST (nvts.cvss_base AS double precision)" \
- " ELSE results.severity" \
+ "coalesce ((CASE WHEN %s.severity > " G_STRINGIFY (SEVERITY_LOG) \
+ " THEN CAST (%s.cvss_base AS double precision)" \
+ " ELSE %s.severity" \
" END)," \
- " results.severity)"
+ " %s.severity)"
/**
* @brief Get LATERAL clause for result iterator.
*
* @param[in] apply_overrides Whether to apply overrides.
* @param[in] dynamic_severity Whether to use dynamic severity.
+ * @param[in] nvts_table NVTS table.
+ * @param[in] results_table Results table.
*
* @return SQL clause for FROM.
*/
-static const gchar *
-result_iterator_lateral (int apply_overrides, int dynamic_severity)
+static gchar *
+result_iterator_lateral (int apply_overrides,
+ int dynamic_severity,
+ const char *results_table,
+ const char *nvts_table)
{
if (apply_overrides && dynamic_severity)
/* Overrides, dynamic. */
- return "(WITH curr AS (SELECT " CURRENT_SEVERITY_SQL " AS curr_severity)"
- " SELECT coalesce ((SELECT ov_new_severity FROM result_overrides"
- " WHERE result = results.id"
- " AND result_overrides.user = opts.user_id"
- " AND severity_matches_ov"
- " ((SELECT curr_severity FROM curr LIMIT 1),"
- " ov_old_severity)"
- " LIMIT 1),"
- " (SELECT curr_severity FROM curr LIMIT 1))"
- " AS new_severity)";
+ return g_strdup_printf(
+ " (WITH curr AS (SELECT " CURRENT_SEVERITY_SQL " AS curr_severity)"
+ " SELECT coalesce ((SELECT ov_new_severity FROM result_overrides"
+ " WHERE result = %s.id"
+ " AND result_overrides.user = opts.user_id"
+ " AND severity_matches_ov"
+ " ((SELECT curr_severity FROM curr LIMIT 1),"
+ " ov_old_severity)"
+ " LIMIT 1),"
+ " (SELECT curr_severity FROM curr LIMIT 1))"
+ " AS new_severity)",
+ results_table,
+ nvts_table,
+ results_table,
+ results_table,
+ results_table);
+
if (apply_overrides)
/* Overrides, no dynamic. */
- return "(SELECT new_severity"
- " FROM result_new_severities_static"
- " WHERE result_new_severities_static.result = results.id"
- " AND result_new_severities_static.user = opts.user_id"
- " LIMIT 1)";
+ return g_strdup_printf(
+ "(SELECT new_severity"
+ " FROM result_new_severities_static"
+ " WHERE result_new_severities_static.result = %s.id"
+ " AND result_new_severities_static.user = opts.user_id"
+ " LIMIT 1)",
+ results_table);
+
if (dynamic_severity)
/* No overrides, dynamic. */
- return "(SELECT " CURRENT_SEVERITY_SQL " AS new_severity)";
+ return g_strdup_printf("(SELECT " CURRENT_SEVERITY_SQL " AS new_severity)",
+ results_table,
+ nvts_table,
+ results_table,
+ results_table);
/* No overrides, no dynamic.
*
* SELECT because results.severity gives syntax error. */
- return "(SELECT results.severity AS new_severity)";
+ return g_strdup_printf("(SELECT %s.severity AS new_severity)", results_table);
}
/**
@@ -22745,7 +22865,8 @@ init_result_get_iterator (iterator_t* iterator, const get_data_t *get,
static column_t columns[] = RESULT_ITERATOR_COLUMNS;
static column_t columns_no_cert[] = RESULT_ITERATOR_COLUMNS_NO_CERT;
int ret;
- gchar *filter, *extra_tables, *extra_where, *extra_where_single, *opts_tables;
+ gchar *filter, *extra_tables, *extra_where, *extra_where_single;
+ gchar *opts_tables, *lateral_clause;
int apply_overrides, dynamic_severity;
column_t *actual_columns;
@@ -22776,13 +22897,19 @@ init_result_get_iterator (iterator_t* iterator, const get_data_t *get,
actual_columns = columns_no_cert;
opts_tables = result_iterator_opts_table (apply_overrides, dynamic_severity);
+
+ lateral_clause = result_iterator_lateral (apply_overrides,
+ dynamic_severity,
+ "results",
+ "nvts");
+
extra_tables = g_strdup_printf (" LEFT OUTER JOIN nvts"
" ON results.nvt = nvts.oid %s,"
" LATERAL %s AS lateral_new_severity",
opts_tables,
- result_iterator_lateral (apply_overrides,
- dynamic_severity));
+ lateral_clause);
g_free (opts_tables);
+ g_free (lateral_clause);
extra_where = results_extra_where (get->trash, report, host,
apply_overrides, dynamic_severity,
@@ -22839,7 +22966,7 @@ result_count (const get_data_t *get, report_t report, const char* host)
static column_t columns[] = RESULT_ITERATOR_COLUMNS;
static column_t columns_no_cert[] = RESULT_ITERATOR_COLUMNS_NO_CERT;
int ret;
- gchar *filter, *extra_tables, *extra_where, *opts_tables;
+ gchar *filter, *extra_tables, *extra_where, *opts_tables, *lateral_clause;
int apply_overrides, dynamic_severity;
if (report == -1)
@@ -22859,13 +22986,19 @@ result_count (const get_data_t *get, report_t report, const char* host)
dynamic_severity = setting_dynamic_severity_int ();
opts_tables = result_iterator_opts_table (apply_overrides, dynamic_severity);
+
+ lateral_clause = result_iterator_lateral (apply_overrides,
+ dynamic_severity,
+ "results",
+ "nvts");
+
extra_tables = g_strdup_printf (" LEFT OUTER JOIN nvts"
" ON results.nvt = nvts.oid %s,"
" LATERAL %s AS lateral_new_severity",
opts_tables,
- result_iterator_lateral (apply_overrides,
- dynamic_severity));
+ lateral_clause);
g_free (opts_tables);
+ g_free (lateral_clause);
extra_where = results_extra_where (get->trash, report, host,
apply_overrides, dynamic_severity,
@@ -23394,6 +23527,375 @@ result_iterator_nvt_solution_method (iterator_t *iterator)
return NULL;
}
+/**
+ * @brief Get delta reports state from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta reports state if any, else NULL.
+ */
+const char *
+result_iterator_delta_state (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET);
+}
+
+/**
+ * @brief Get delta description from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta description if any, else NULL.
+ */
+const char *
+result_iterator_delta_description (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 1);
+}
+
+/**
+ * @brief Get delta severity from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta severity if any, else NULL.
+ */
+const char *
+result_iterator_delta_original_severity (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 2);
+}
+
+/**
+ * @brief Get delta severity (double) from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta severity (double) if any, else 0.
+ */
+double
+result_iterator_delta_original_severity_double (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_double (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 2);
+}
+
+/**
+ * @brief Get the severity/threat level from a delta result iterator.
+ *
+ * This is the the original level.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The threat level of the delta result. Caller must only use before
+ * calling cleanup_iterator.
+ */
+const char*
+result_iterator_delta_original_level (iterator_t* iterator)
+{
+ double severity;
+ const char* ret;
+
+ if (iterator->done)
+ return "";
+
+ /* new_severity */
+ if (iterator_null (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 2))
+ return "";
+
+ severity = iterator_double (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 2);
+
+ ret = severity_to_level (severity, 0);
+ return ret ? ret : "";
+}
+
+/**
+ * @brief Get delta qod from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta qod if any, else NULL.
+ */
+const char *
+result_iterator_delta_qod (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 3);
+}
+
+/**
+ * @brief Get delta uuid from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta uuid if any, else NULL.
+ */
+const char *
+result_iterator_delta_uuid (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 4);
+}
+
+
+/**
+ * @brief Get delta qod type from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta qod type if any, else NULL.
+ */
+const char *
+result_iterator_delta_qod_type (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 5);
+}
+
+/**
+ * @brief Get delta creation time from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta creation time if any, else NULL.
+ */
+const char *
+result_iterator_delta_creation_time (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 6);
+}
+
+/**
+ * @brief Get delta modification time from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta modification time if any, else NULL.
+ */
+const char *
+result_iterator_delta_modification_time (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 7);
+}
+
+/**
+ * @brief Get delta task from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta task if any, else 0.
+ */
+task_t
+result_iterator_delta_task (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_int64 (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 8);
+}
+
+/**
+ * @brief Get delta report from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta report if any, else 0.
+ */
+report_t
+result_iterator_delta_report (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_int64 (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 9);
+}
+
+/**
+ * @brief Get delta owner from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta owner if any, else NULL.
+ */
+const char *
+result_iterator_delta_owner_name (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 10);
+}
+
+/**
+ * @brief Get delta path from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta path if any, else NULL.
+ */
+const char *
+result_iterator_delta_path (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 11);
+}
+
+/**
+ * @brief Get delta host asset id from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta host asset id if any, else NULL.
+ */
+const char *
+result_iterator_delta_host_asset_id (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 12);
+}
+
+/**
+ * @brief Get delta nvt version from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta nvt version if any, else NULL.
+ */
+const char *
+result_iterator_delta_nvt_version (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 13);
+}
+
+/**
+ * @brief Get delta result from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta result if any, else 0.
+ */
+result_t
+result_iterator_delta_result (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_int64 (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 14);
+}
+
+/**
+ * @brief Get whether there are notes for the delta result from the iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return whether there are notes.
+ */
+int
+result_iterator_delta_may_have_notes (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_int (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 15);
+}
+
+/**
+ * @brief Get whether there are overrides for the delta result from the iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return whether there are overrides.
+ */
+int
+result_iterator_delta_may_have_overrides (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_int (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 16);
+}
+
+/**
+ * @brief Get whether there are tickets for the delta result from the iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return whether there are tickets.
+ */
+int
+result_iterator_delta_may_have_tickets (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_int (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 17);
+}
+
+/**
+ * @brief Get delta hostname from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta hostname if any, else NULL.
+ */
+const char *
+result_iterator_delta_hostname (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 18);
+}
+
+
+/**
+ * @brief Get delta severity from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta severity if any, else NULL.
+ */
+const char *
+result_iterator_delta_severity (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 19);
+}
+
+/**
+ * @brief Get delta severity (double) from a result iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return delta severity (double) if any, else 0.
+ */
+double
+result_iterator_delta_severity_double (iterator_t* iterator)
+{
+ if (iterator->done) return 0;
+ return iterator_double (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 19);
+}
+
+/**
+ * @brief Get the severity/threat level from a delta result iterator.
+ *
+ * This is the the overridden level.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The threat level of the delta result. Caller must only use before
+ * calling cleanup_iterator.
+ */
+const char*
+result_iterator_delta_level (iterator_t* iterator)
+{
+ double severity;
+ const char* ret;
+
+ if (iterator->done)
+ return "";
+
+ /* new_severity */
+ if (iterator_null (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 19))
+ return "";
+
+ severity = iterator_double (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 19);
+
+ ret = severity_to_level (severity, 0);
+ return ret ? ret : "";
+}
+
+
/**
* @brief Append an NVT's references to an XML string buffer.
*
@@ -25252,7 +25754,7 @@ compare_port_severity (gconstpointer arg_one, gconstpointer arg_two)
/** @todo Defined in gmp.c! */
void buffer_results_xml (GString *, iterator_t *, task_t, int, int, int,
int, int, int, int, const char *, iterator_t *,
- int, int, int);
+ int, int, int, int);
/**
* @brief Comparison returns.
@@ -25632,7 +26134,8 @@ compare_and_buffer_results (GString *buffer, iterator_t *results,
/* This is the only case that uses 1. */
1, /* Whether result is "changed". */
-1,
- 0);
+ 0, /* Lean. */
+ 0); /* Delta fields. */
}
break;
@@ -25663,7 +26166,8 @@ compare_and_buffer_results (GString *buffer, iterator_t *results,
delta_results,
0,
-1,
- 0);
+ 0, /* Lean. */
+ 0); /* Delta fields. */
}
break;
@@ -25694,7 +26198,8 @@ compare_and_buffer_results (GString *buffer, iterator_t *results,
delta_results,
0,
-1,
- 0);
+ 0, /* Lean. */
+ 0); /* Delta fields. */
}
break;
@@ -25725,7 +26230,8 @@ compare_and_buffer_results (GString *buffer, iterator_t *results,
delta_results,
0,
-1,
- 0);
+ 0, /* Lean. */
+ 0); /* Delta fields. */
}
break;
@@ -26888,6 +27394,186 @@ init_delta_iterators (report_t report, iterator_t *results, report_t delta,
return 0;
}
+/**
+ * @brief Init v2 delta iterator for print_report_xml.
+ *
+ * @param[in] report The report.
+ * @param[in] results Report result iterator.
+ * @param[in] delta Delta report.
+ * @param[in] get GET command data.
+ * @param[in] term Filter term.
+ * @param[out] sort_field Sort field.
+ *
+ * @return 0 on success, -1 error.
+ */
+static int
+init_v2_delta_iterator (report_t report, iterator_t *results, report_t delta,
+ const get_data_t *get, const char *term,
+ const char *sort_field)
+{
+ int ret;
+ static const char *filter_columns[] = RESULT_ITERATOR_FILTER_COLUMNS;
+ static column_t columns_no_cert[] = DELTA_RESULT_ITERATOR_COLUMNS_NO_CERT;
+ static column_t columns[] = DELTA_RESULT_ITERATOR_COLUMNS;
+
+
+ gchar *filter, *extra_tables, *extra_where, *extra_where_single;
+ gchar *opts_tables, *extra_with, *lateral_clause, *with_lateral;
+ int apply_overrides, dynamic_severity;
+ column_t *actual_columns;
+
+ g_debug ("%s", __func__);
+
+ if (report == -1)
+ {
+ init_iterator (results, "SELECT NULL WHERE false;");
+ return 0;
+ }
+
+ if (get->filt_id && strcmp (get->filt_id, FILT_ID_NONE))
+ {
+ filter = filter_term (get->filt_id);
+ if (filter == NULL)
+ return 2;
+ }
+ else
+ filter = NULL;
+
+ apply_overrides
+ = filter_term_apply_overrides (filter ? filter : get->filter);
+ dynamic_severity = setting_dynamic_severity_int ();
+
+ if (manage_cert_loaded ())
+ actual_columns = columns;
+ else
+ actual_columns = columns_no_cert;
+
+ opts_tables = result_iterator_opts_table (apply_overrides, dynamic_severity);
+
+ lateral_clause = result_iterator_lateral (apply_overrides,
+ dynamic_severity,
+ "results",
+ "nvts");
+
+ extra_tables = g_strdup_printf (" JOIN comparison "
+ " ON results.id = COALESCE (result1_id,"
+ " result2_id)"
+ " LEFT OUTER JOIN nvts"
+ " ON results.nvt = nvts.oid %s,"
+ " LATERAL %s AS lateral_new_severity",
+ opts_tables,
+ lateral_clause);
+
+ g_free (lateral_clause);
+
+ extra_where = results_extra_where (get->trash, 0, NULL,
+ apply_overrides, dynamic_severity,
+ filter ? filter : get->filter,
+ NULL);
+
+ extra_where_single = results_extra_where (get->trash, 0, NULL,
+ apply_overrides,
+ dynamic_severity,
+ "min_qod=0",
+ NULL);
+
+ free (filter);
+
+ with_lateral = result_iterator_lateral (apply_overrides,
+ dynamic_severity,
+ "results",
+ "nvts_cols");
+
+ extra_with = g_strdup_printf(" comparison AS ("
+ " SELECT r1.id AS result1_id,"
+ " r2.id AS result2_id,"
+ " compare_results("
+ " r1.description,"
+ " r2.description,"
+ " r1.new_severity::double precision,"
+ " r2.new_severity::double precision,"
+ " r1.qod::integer,"
+ " r2.qod::integer,"
+ RESULT_HOSTNAME_SQL("r1.hostname", "r1.host", "r1.report")","
+ RESULT_HOSTNAME_SQL("r2.hostname", "r2.host", "r2.report")","
+ " r1.path,"
+ " r2.path) AS state,"
+ " r2.description AS delta_description,"
+ " r2.new_severity AS delta_new_severity,"
+ " r2.severity AS delta_severity,"
+ " r2.qod AS delta_qod,"
+ " r2.qod_type AS delta_qod_type,"
+ " r2.uuid AS delta_uuid,"
+ " r2.date AS delta_date,"
+ " r2.task AS delta_task,"
+ " r2.report AS delta_report,"
+ " r2.owner AS delta_owner,"
+ " r2.path AS delta_path,"
+ " r2.host AS delta_host,"
+ RESULT_HOSTNAME_SQL("r2.hostname", "r2.host", "r2.report")
+ " AS delta_hostname,"
+ " r2.nvt_version AS delta_nvt_version"
+ " FROM (SELECT results.id, description, host, report, port,"
+ " severity, nvt, results.qod, results.uuid, hostname,"
+ " path, r1_lateral.new_severity as new_severity "
+ " FROM results "
+ " LEFT JOIN (SELECT cvss_base, oid AS nvts_oid from nvts)"
+ " AS nvts_cols"
+ " ON nvts_cols.nvts_oid = results.nvt"
+ " %s, LATERAL %s AS r1_lateral"
+ " WHERE report = %llu)"
+ " AS r1"
+ " FULL OUTER JOIN (SELECT results.*, r2_lateral.new_severity AS new_severity"
+ " FROM results"
+ " LEFT JOIN (SELECT cvss_base, oid AS nvts_oid from nvts)"
+ " AS nvts_cols"
+ " ON nvts_cols.nvts_oid = results.nvt"
+ " %s, LATERAL %s AS r2_lateral"
+ " WHERE report = %llu)"
+ " AS r2"
+ " ON r1.host = r2.host"
+ " AND normalize_port(r1.port) = normalize_port(r2.port)"
+ " AND r1.nvt = r2.nvt "
+ " AND (r1.new_severity = 0) = (r2.new_severity = 0)"
+ " )",
+ opts_tables,
+ with_lateral,
+ report,
+ opts_tables,
+ with_lateral,
+ delta);
+
+ ret = init_get_iterator2_with (results,
+ "result",
+ get,
+ /* SELECT columns. */
+ actual_columns,
+ NULL,
+ /* Filterable columns not in SELECT columns. */
+ NULL,
+ NULL,
+ filter_columns,
+ 0,
+ extra_tables,
+ extra_where,
+ extra_where_single,
+ TRUE,
+ report ? TRUE : FALSE,
+ NULL,
+ extra_with,
+ 0,
+ 0);
+ g_free (extra_tables);
+ g_free (extra_where);
+ g_free (extra_where_single);
+ g_free (with_lateral);
+ g_free (opts_tables);
+
+ g_debug ("%s: done", __func__);
+
+ return ret;
+}
+
/**
* @brief Print delta results for print_report_xml.
*
@@ -27047,7 +27733,8 @@ print_report_delta_xml (FILE *out, iterator_t *results,
NULL,
0,
-1,
- 0);
+ 0, /* Lean. */
+ 0); /* Delta fields. */
if (fprintf (out, "%s", buffer->str) < 0)
return -1;
g_string_free (buffer, TRUE);
@@ -27094,7 +27781,8 @@ print_report_delta_xml (FILE *out, iterator_t *results,
NULL,
0,
-1,
- 0);
+ 0, /* Lean. */
+ 0); /* Delta fields. */
if (fprintf (out, "%s", buffer->str) < 0)
return -1;
g_string_free (buffer, TRUE);
@@ -27606,6 +28294,135 @@ print_report_delta_xml (FILE *out, iterator_t *results,
return 0;
}
+/**
+ * @brief Print v2 delta results for print_report_xml.
+ *
+ * @param[in] out File stream to write to.
+ * @param[in] results Report result iterator.
+ * @param[in] delta_states String describing delta states to include in count
+ * (for example, "sngc" Same, New, Gone and Changed).
+ * All levels if NULL.
+ * @param[in] first_result First result.
+ * @param[in] max_results Max results.
+ * @param[in] task The task.
+ * @param[in] notes Whether to include notes.
+ * @param[in] notes_details Whether to include note details.
+ * @param[in] overrides Whether to include overrides.
+ * @param[in] overrides_details Whether to include override details.
+ * @param[in] sort_order Sort order.
+ * @param[in] sort_field Sort field.
+ * @param[in] result_hosts_only Whether to only include hosts with results.
+ * @param[in] orig_filtered_result_count Result count.
+ * @param[in] filtered_result_count Result count.
+ * @param[in] orig_f_holes Result count.
+ * @param[in] f_holes Result count.
+ * @param[in] orig_f_infos Result count.
+ * @param[in] f_infos Result count.
+ * @param[in] orig_f_logs Result count.
+ * @param[in] f_logs Result count.
+ * @param[in] orig_f_warnings Result count.
+ * @param[in] f_warnings Result count.
+ * @param[in] orig_f_false_positives Result count.
+ * @param[in] f_false_positives Result count.
+ * @param[in] result_hosts Result hosts.
+ *
+ * @return 0 on success, -1 error.
+ */
+static int
+print_v2_report_delta_xml (FILE *out, iterator_t *results,
+ const char *delta_states,
+ int first_result, int max_results, task_t task,
+ int notes, int notes_details, int overrides,
+ int overrides_details, int sort_order,
+ const char *sort_field, int result_hosts_only,
+ int *orig_filtered_result_count,
+ int *filtered_result_count,
+ int *orig_f_holes, int *f_holes,
+ int *orig_f_infos, int *f_infos,
+ int *orig_f_logs, int *f_logs,
+ int *orig_f_warnings, int *f_warnings,
+ int *orig_f_false_positives, int *f_false_positives,
+ array_t *result_hosts)
+{
+ GString *buffer = g_string_new ("");
+
+ *orig_f_holes = *f_holes;
+ *orig_f_infos = *f_infos;
+ *orig_f_logs = *f_logs;
+ *orig_f_warnings = *f_warnings;
+ *orig_f_false_positives = *f_false_positives;
+ *orig_filtered_result_count = *filtered_result_count;
+
+ while (next (results)) {
+
+ const char *state = result_iterator_delta_state (results);
+
+ if (strchr (delta_states, state[0]) == NULL) continue;
+
+ const char *level;
+ /* Increase the result count. */
+ level = result_iterator_level (results);
+ (*orig_filtered_result_count)++;
+ (*filtered_result_count)++;
+ if (strcmp (level, "High") == 0)
+ {
+ (*orig_f_holes)++;
+ (*f_holes)++;
+ }
+ else if (strcmp (level, "Medium") == 0)
+ {
+ (*orig_f_warnings)++;
+ (*f_warnings)++;
+ }
+ else if (strcmp (level, "Low") == 0)
+ {
+ (*orig_f_infos)++;
+ (*f_infos)++;
+ }
+ else if (strcmp (level, "Log") == 0)
+ {
+ (*orig_f_logs)++;
+ (*f_logs)++;
+ }
+ else if (strcmp (level, "False Positive") == 0)
+ {
+ (*orig_f_false_positives)++;
+ (*f_false_positives)++;
+ }
+
+
+ buffer_results_xml (buffer,
+ results,
+ task,
+ notes,
+ notes_details,
+ overrides,
+ overrides_details,
+ 0,
+ 0,
+ 0,
+ state,
+ NULL,
+ (strcmp (state, "changed") == 0),
+ -1,
+ 0, /* Lean. */
+ 0); /* Delta fields. */
+
+ if (fprintf (out, "%s", buffer->str) < 0)
+ {
+ g_string_free (buffer, TRUE);
+ return -1;
+ }
+ g_string_truncate (buffer, 0);
+ }
+ g_string_free (buffer, TRUE);
+ if (fprintf (out, "") < 0)
+ {
+ return -1;
+ }
+ return 0;
+}
+
/**
* @brief Print the main XML content for a report to a file.
*
@@ -27864,7 +28681,8 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
"");
}
- count_filtered = (delta == 0 && ignore_pagination && get->details);
+ count_filtered = (delta == 0 && ignore_pagination && get->details)
+ || (delta_reports_version == 2);
if (report)
{
@@ -27945,7 +28763,8 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
term = clean;
if (delta
- && sort_field
+ && sort_field
+ && (delta_reports_version == 1)
/* These are all checked in result_cmp. */
&& strcmp (sort_field, "name")
&& strcmp (sort_field, "vulnerability")
@@ -28305,14 +29124,28 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
if (delta && get->details)
{
- if (init_delta_iterators (report, &results, delta, &delta_results, get,
- term, sort_field))
+ if (delta_reports_version == 1)
{
+ if (init_delta_iterators (report, &results, delta,
+ &delta_results, get,
+ term, sort_field))
+ {
+ g_free (term);
+ g_hash_table_destroy (f_host_ports);
+ return -1;
+ }
g_free (term);
- g_hash_table_destroy (f_host_ports);
- return -1;
+ }
+ else
+ {
+ if (init_v2_delta_iterator (report, &results, delta,
+ get, term, sort_field))
+ {
+ g_free (term);
+ g_hash_table_destroy (f_host_ports);
+ return -1;
+ }
}
- g_free (term);
}
else if (get->details)
{
@@ -28360,38 +29193,80 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
if (delta && get->details)
{
- if (print_report_delta_xml (out, &results, &delta_results, delta_states,
- ignore_pagination ? 0 : first_result,
- ignore_pagination ? -1 : max_results,
- task, notes,
- notes_details, overrides, overrides_details,
- sort_order, sort_field, result_hosts_only,
- &orig_filtered_result_count,
- &filtered_result_count,
- &orig_f_holes, &f_holes,
- &orig_f_infos, &f_infos,
- &orig_f_logs, &f_logs,
- &orig_f_warnings, &f_warnings,
- &orig_f_false_positives, &f_false_positives,
- result_hosts))
- {
- fclose (out);
- g_free (sort_field);
- g_free (levels);
- g_free (search_phrase);
- g_free (min_qod);
- g_free (delta_states);
- cleanup_iterator (&results);
- cleanup_iterator (&delta_results);
- tz_revert (zone, tz, old_tz_override);
- g_hash_table_destroy (f_host_ports);
- g_hash_table_destroy (f_host_holes);
- g_hash_table_destroy (f_host_warnings);
- g_hash_table_destroy (f_host_infos);
- g_hash_table_destroy (f_host_logs);
- g_hash_table_destroy (f_host_false_positives);
-
- return -1;
+ if (delta_reports_version == 1)
+ {
+ if (print_report_delta_xml (out, &results, &delta_results,
+ delta_states,
+ ignore_pagination ? 0 : first_result,
+ ignore_pagination ? -1 : max_results,
+ task, notes,
+ notes_details, overrides,
+ overrides_details, sort_order,
+ sort_field, result_hosts_only,
+ &orig_filtered_result_count,
+ &filtered_result_count,
+ &orig_f_holes, &f_holes,
+ &orig_f_infos, &f_infos,
+ &orig_f_logs, &f_logs,
+ &orig_f_warnings, &f_warnings,
+ &orig_f_false_positives,
+ &f_false_positives,
+ result_hosts))
+ {
+ fclose (out);
+ g_free (sort_field);
+ g_free (levels);
+ g_free (search_phrase);
+ g_free (min_qod);
+ g_free (delta_states);
+ cleanup_iterator (&results);
+ cleanup_iterator (&delta_results);
+ tz_revert (zone, tz, old_tz_override);
+ g_hash_table_destroy (f_host_ports);
+ g_hash_table_destroy (f_host_holes);
+ g_hash_table_destroy (f_host_warnings);
+ g_hash_table_destroy (f_host_infos);
+ g_hash_table_destroy (f_host_logs);
+ g_hash_table_destroy (f_host_false_positives);
+ return -1;
+ }
+ }
+ else
+ {
+ if (print_v2_report_delta_xml (out, &results, delta_states,
+ ignore_pagination ? 0 : first_result,
+ ignore_pagination ? -1 : max_results,
+ task, notes,
+ notes_details, overrides,
+ overrides_details, sort_order,
+ sort_field, result_hosts_only,
+ &orig_filtered_result_count,
+ &filtered_result_count,
+ &orig_f_holes, &f_holes,
+ &orig_f_infos, &f_infos,
+ &orig_f_logs, &f_logs,
+ &orig_f_warnings, &f_warnings,
+ &orig_f_false_positives,
+ &f_false_positives,
+ result_hosts))
+ {
+ fclose (out);
+ g_free (sort_field);
+ g_free (levels);
+ g_free (search_phrase);
+ g_free (min_qod);
+ g_free (delta_states);
+ cleanup_iterator (&results);
+ cleanup_iterator (&delta_results);
+ tz_revert (zone, tz, old_tz_override);
+ g_hash_table_destroy (f_host_ports);
+ g_hash_table_destroy (f_host_holes);
+ g_hash_table_destroy (f_host_warnings);
+ g_hash_table_destroy (f_host_infos);
+ g_hash_table_destroy (f_host_logs);
+ g_hash_table_destroy (f_host_false_positives);
+ return -1;
+ }
}
}
else if (get->details)
@@ -28420,7 +29295,8 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
NULL,
0,
cert_loaded,
- lean);
+ lean,
+ 0); /* Delta fields. */
PRINT_XML (out, buffer->str);
g_string_free (buffer, TRUE);
if (result_hosts_only)
@@ -28482,7 +29358,7 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
}
if (get->details)
cleanup_iterator (&results);
- if (delta && get->details)
+ if (delta && get->details && delta_reports_version == 1)
cleanup_iterator (&delta_results);
/* Print result counts and severity. */
@@ -28570,7 +29446,7 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
iterator_t hosts;
init_report_host_iterator (&hosts, report, result_host, 0);
present = next (&hosts);
- if (delta && (present == FALSE))
+ if (delta && (present == FALSE) && delta_reports_version == 1)
{
cleanup_iterator (&hosts);
init_report_host_iterator (&hosts, delta, result_host, 0);
@@ -56153,7 +57029,7 @@ type_build_select (const char *type, const char *columns_str,
{
gchar *filter, *with;
gchar *from_table, *opts_table;
- gchar *clause, *extra_where, *filter_order;
+ gchar *clause, *extra_where, *lateral_clause, *filter_order;
int first, max;
gchar *owned_clause, *owner_filter;
array_t *permissions;
@@ -56197,13 +57073,18 @@ type_build_select (const char *type, const char *columns_str,
original = opts_table;
+ lateral_clause = result_iterator_lateral (overrides,
+ dynamic,
+ "results",
+ "nvts");
+
opts_table = g_strdup_printf (" LEFT OUTER JOIN nvts"
" ON results.nvt = nvts.oid %s,"
" LATERAL %s AS lateral_new_severity",
original,
- result_iterator_lateral (overrides,
- dynamic));
+ lateral_clause);
g_free (original);
+ g_free (lateral_clause);
}
// WHERE ... part
diff --git a/src/manage_sql.h b/src/manage_sql.h
index e39e30b90..6ea3ac24c 100644
--- a/src/manage_sql.h
+++ b/src/manage_sql.h
@@ -288,6 +288,11 @@ typedef struct
*/
#define GET_ITERATOR_COLUMN_COUNT 10
+/**
+ * @brief Delta results columns offset for result iterator.
+ */
+#define RESULT_ITERATOR_DELTA_COLUMN_OFFSET GET_ITERATOR_COLUMN_COUNT + 37
+
/* Variables */
diff --git a/src/manage_sql_tickets.h b/src/manage_sql_tickets.h
index f89851824..a1b75f336 100644
--- a/src/manage_sql_tickets.h
+++ b/src/manage_sql_tickets.h
@@ -24,10 +24,10 @@
/**
* @brief SQL to check if a result may have tickets.
*/
-#define TICKET_SQL_RESULT_MAY_HAVE_TICKETS \
+#define TICKET_SQL_RESULT_MAY_HAVE_TICKETS(result_col) \
"(SELECT EXISTS (SELECT * FROM tickets" \
" WHERE id IN (SELECT ticket FROM ticket_results" \
- " WHERE result = results.id" \
+ " WHERE result = " result_col \
" AND result_location" \
" = " G_STRINGIFY (LOCATION_TABLE) ")))"