diff --git a/src/gmp.c b/src/gmp.c index 1264e7028..e55c3373c 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,16 +9209,25 @@ 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 *descr = use_delta_fields + ? result_iterator_delta_description (results) + : 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 *qod = use_delta_fields + ? result_iterator_delta_qod (results) + : result_iterator_qod (results); + const char *qod_type = use_delta_fields + ? result_iterator_delta_qod_type (results) + : result_iterator_qod_type (results); + result_t result = use_delta_fields + ? result_iterator_delta_result (results) + : result_iterator_result (results); char *detect_oid, *detect_ref, *detect_cpe, *detect_loc, *detect_name; task_t selected_task; @@ -9198,7 +9246,9 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task, buffer_xml_append_printf (buffer, "", - get_iterator_uuid (results)); + use_delta_fields + ? result_iterator_delta_uuid(results) + : get_iterator_uuid (results)); selected_task = task; @@ -9212,13 +9262,17 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task, { const char *owner_name, *modification_time; - owner_name = get_iterator_owner_name (results); + owner_name = use_delta_fields + ? result_iterator_delta_owner_name (results) + : get_iterator_owner_name (results); if (owner_name) buffer_xml_append_printf (buffer, "%s", owner_name); - modification_time = get_iterator_modification_time (results); + modification_time = use_delta_fields + ? result_iterator_delta_modification_time (results) + : get_iterator_modification_time (results); if (modification_time) buffer_xml_append_printf (buffer, "%s", @@ -9232,7 +9286,9 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task, "%s", comment); - creation_time = get_iterator_creation_time (results); + creation_time = use_delta_fields + ? result_iterator_delta_creation_time (results) + : get_iterator_creation_time (results); if (creation_time) buffer_xml_append_printf (buffer, "%s", @@ -9243,11 +9299,18 @@ 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); + selected_task = use_delta_fields + ? result_iterator_delta_task (results) + : result_iterator_task (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)); + result_task_name = use_delta_fields + ? task_name(result_iterator_delta_task (results)) + : task_name (result_iterator_task (results)); + result_report_id = use_delta_fields + ? report_uuid(result_iterator_delta_report (results)) + : report_uuid (result_iterator_report (results)); + buffer_xml_append_printf (buffer, "" @@ -9299,10 +9362,16 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task, } port = result_iterator_port (results); - path = result_iterator_path (results); + path = use_delta_fields + ? result_iterator_delta_path (results) + : 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, + use_delta_fields + ? result_iterator_delta_report (results) + : result_iterator_report (results), result_iterator_host (results), port, path, &detect_oid, &detect_ref, &detect_cpe, &detect_loc, &detect_name) @@ -9330,7 +9399,9 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task, g_free (detect_name); if (result_iterator_host (results)) - asset_id = result_iterator_asset_host_id (results); + asset_id = use_delta_fields + ? result_iterator_delta_host_asset_id (results) + : result_iterator_asset_host_id (results); else asset_id = NULL; @@ -9350,7 +9421,9 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task, buffer_xml_append_printf (buffer, "%s" "", - result_iterator_hostname (results) ?: ""); + use_delta_fields + ? result_iterator_delta_hostname (results) + : result_iterator_hostname (results) ?: ""); buffer_xml_append_printf (buffer, "%s", @@ -9370,14 +9443,20 @@ buffer_results_xml (GString *buffer, iterator_t *results, task_t task, (buffer, "%s" "%s", - result_iterator_scan_nvt_version (results), - result_iterator_level (results)); + use_delta_fields + ? result_iterator_delta_nvt_version (results) + : result_iterator_scan_nvt_version (results), + use_delta_fields + ? result_iterator_delta_level (results) + : result_iterator_level (results)); buffer_xml_append_printf (buffer, "%.1f" "%s", - result_iterator_severity_double (results), + use_delta_fields + ? result_iterator_delta_severity_double (results) + : result_iterator_severity_double (results), qod ? qod : ""); if (qod_type && strlen (qod_type)) @@ -9393,74 +9472,91 @@ 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)) - buffer_xml_append_printf (buffer, + if(use_delta_fields) { + /* TODO work with both original and override */ + buffer_xml_append_printf (buffer, "%s", - result_iterator_original_severity (results)); + result_iterator_delta_severity (results)); + } else { + /* Only send the original severity if it has changed. */ + if (strncmp (result_iterator_original_severity (results), + result_iterator_severity (results), + /* Avoid rounding differences. */ + 3)) + buffer_xml_append_printf (buffer, + "%s", + result_iterator_original_severity (results)); + } } else if (include_overrides) buffer_xml_append_printf (buffer, "%s" "%s", - result_iterator_original_level (results), - result_iterator_original_severity (results)); + use_delta_fields + ? result_iterator_delta_level (results) + : result_iterator_original_level (results), + use_delta_fields + ? result_iterator_delta_severity (results) + : result_iterator_original_severity (results)); 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 +9583,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 +15292,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..6e9a175c9 100644 --- a/src/manage.h +++ b/src/manage.h @@ -1521,6 +1521,69 @@ 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_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*); + +const char * +result_iterator_delta_level (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..8bcad5351 100644 --- a/src/manage_pg.c +++ b/src/manage_pg.c @@ -836,6 +836,40 @@ 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;"); + /* 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..317b6d134 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,105 @@ 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 }, \ + { "severity_to_type (results.severity)", \ + "original_type", \ + KEYWORD_TYPE_STRING }, \ + { "(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 }, + +/** + * @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. */ @@ -23394,6 +23497,303 @@ 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_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_severity_double (iterator_t* iterator) +{ + if (iterator->done) return 0; + return iterator_double (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 2); +} + + +/** + * @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 delta level from a result iterator. + * + * @param[in] iterator Iterator. + * + * @return delta level if any, else NULL. + */ +const char * +result_iterator_delta_level (iterator_t* iterator) +{ + if (iterator->done) return 0; + return iterator_string (iterator, RESULT_ITERATOR_DELTA_COLUMN_OFFSET + 15); +} + +/** + * @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 + 16); +} + +/** + * @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 + 17); +} + +/** + * @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 + 18); +} + +/** + * @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 + 19); +} + + /** * @brief Append an NVT's references to an XML string buffer. * @@ -25252,7 +25652,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 +26032,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 +26064,8 @@ compare_and_buffer_results (GString *buffer, iterator_t *results, delta_results, 0, -1, - 0); + 0, /* Lean. */ + 0); /* Delta fields. */ } break; @@ -25694,7 +26096,8 @@ compare_and_buffer_results (GString *buffer, iterator_t *results, delta_results, 0, -1, - 0); + 0, /* Lean. */ + 0); /* Delta fields. */ } break; @@ -25725,7 +26128,8 @@ compare_and_buffer_results (GString *buffer, iterator_t *results, delta_results, 0, -1, - 0); + 0, /* Lean. */ + 0); /* Delta fields. */ } break; @@ -26888,6 +27292,155 @@ 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; + 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); + + 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, + result_iterator_lateral (apply_overrides, + dynamic_severity)); + + g_free (opts_tables); + + 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); + + 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.severity::double precision," + " r2.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.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 id, description, host, report, port, severity, nvt," + " qod, uuid, hostname, path FROM results WHERE report = %llu)" + " AS r1" + " FULL OUTER JOIN (SELECT * FROM results WHERE report = %llu) AS r2" + " ON r1.host = r2.host" + " AND r1.port = r2.port" + " AND r1.nvt = r2.nvt " + " AND (r1.severity = 0) = (r2.severity = 0)" + " )", + report, 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_debug ("%s: done", __func__); + + return ret; +} + /** * @brief Print delta results for print_report_xml. * @@ -27047,7 +27600,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 +27648,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 +28161,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 +28548,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 +28630,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 +28991,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 +29060,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 +29162,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 +29225,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 +29313,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); 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) ")))"