diff --git a/CMakeLists.txt b/CMakeLists.txt index f41fb8cc2..29155fb0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,7 +96,7 @@ include (CPack) ## Variables -set (GVMD_DATABASE_VERSION 251) +set (GVMD_DATABASE_VERSION 253) set (GVMD_SCAP_DATABASE_VERSION 20) diff --git a/src/manage.c b/src/manage.c index 13436bd5c..cdf705bf1 100644 --- a/src/manage.c +++ b/src/manage.c @@ -1791,7 +1791,7 @@ handle_osp_scan (task_t task, report_t report, const char *scan_id) (task, "", "", "", threat_message_type ("Error"), "Erroneous scan progress value", "", "", - QOD_DEFAULT, NULL); + QOD_DEFAULT, NULL, NULL); report_add_result (report, result); delete_osp_scan (scan_id, host, port, ca_pub, key_pub, key_priv); @@ -1824,7 +1824,7 @@ handle_osp_scan (task_t task, report_t report, const char *scan_id) (task, "", "", "", threat_message_type ("Error"), "Erroneous scan progress value", "", "", - QOD_DEFAULT, NULL); + QOD_DEFAULT, NULL, NULL); report_add_result (report, result); rc = -1; break; @@ -1854,7 +1854,7 @@ handle_osp_scan (task_t task, report_t report, const char *scan_id) (task, "", "", "", threat_message_type ("Error"), "Task interrupted unexpectedly", "", "", - QOD_DEFAULT, NULL); + QOD_DEFAULT, NULL, NULL); report_add_result (report, result); delete_osp_scan (scan_id, host, port, ca_pub, key_pub, key_priv); @@ -1877,7 +1877,7 @@ handle_osp_scan (task_t task, report_t report, const char *scan_id) (task, "", "", "", threat_message_type ("Error"), "Scan stopped unexpectedly by the server", "", "", - QOD_DEFAULT, NULL); + QOD_DEFAULT, NULL, NULL); report_add_result (report, result); delete_osp_scan (scan_id, host, port, ca_pub, key_pub, key_priv); @@ -2748,7 +2748,7 @@ fork_osp_scan_handler (task_t task, target_t target, int from, g_warning ("OSP start_scan %s: %s", report_id, error); result = make_osp_result (task, "", "", "", threat_message_type ("Error"), - error, "", "", QOD_DEFAULT, NULL); + error, "", "", QOD_DEFAULT, NULL, NULL); report_add_result (global_current_report, result); set_task_run_status (task, TASK_STATUS_DONE); set_report_scan_run_status (global_current_report, TASK_STATUS_DONE); @@ -2936,7 +2936,7 @@ cve_scan_host (task_t task, report_t report, gvm_host_t *gvm_host) locations = g_string_new(""); insert_report_host_detail (global_current_report, ip, "cve", cve, - "CVE Scanner", "App", app); + "CVE Scanner", "App", app, NULL); init_app_locations_iterator (&locations_iter, report_host, app); @@ -2957,16 +2957,16 @@ cve_scan_host (task_t task, report_t report, gvm_host_t *gvm_host) g_string_append (locations, location); insert_report_host_detail (report, ip, "cve", cve, - "CVE Scanner", app, location); + "CVE Scanner", app, location, NULL); insert_report_host_detail (report, ip, "cve", cve, "CVE Scanner", "detected_at", - location); + location, NULL); insert_report_host_detail (report, ip, "cve", cve, "CVE Scanner", "detected_by", /* Detected by itself. */ - cve); + cve, NULL); } desc = g_strdup_printf ("The host carries the product: %s\n" @@ -3010,26 +3010,29 @@ cve_scan_host (task_t task, report_t report, gvm_host_t *gvm_host) hostname = report_host_hostname (report_host); if (hostname) { insert_report_host_detail (report, ip, "cve", "", - "CVE Scanner", "hostname", hostname); + "CVE Scanner", "hostname", hostname, + NULL); g_free(hostname); } best = report_host_best_os_cpe (report_host); if (best) { insert_report_host_detail (report, ip, "cve", "", - "CVE Scanner", "best_os_cpe", best); + "CVE Scanner", "best_os_cpe", best, + NULL); g_free(best); } best = report_host_best_os_txt (report_host); if (best) { insert_report_host_detail (report, ip, "cve", "", - "CVE Scanner", "best_os_txt", best); + "CVE Scanner", "best_os_txt", best, + NULL); g_free(best); } insert_report_host_detail (report, ip, "cve", "", - "CVE Scanner", "CVE Scan", "1"); + "CVE Scanner", "CVE Scan", "1", NULL); update_report_modification_time (report); } } diff --git a/src/manage.h b/src/manage.h index 20f7954d7..c3f23a0c3 100644 --- a/src/manage.h +++ b/src/manage.h @@ -1182,7 +1182,8 @@ make_result (task_t, const char*, const char*, const char*, const char*, result_t make_osp_result (task_t, const char*, const char*, const char*, const char*, - const char *, const char *, const char *, int, const char*); + const char *, const char *, const char *, int, const char*, + const char *); result_t make_cve_result (task_t, const char*, const char*, double, const char*); @@ -1234,7 +1235,8 @@ host_detail_free (host_detail_t *); void insert_report_host_detail (report_t, const char *, const char *, const char *, - const char *, const char *, const char *); + const char *, const char *, const char *, + const char *); int manage_report_host_detail (report_t, const char *, const char *); diff --git a/src/manage_migrators.c b/src/manage_migrators.c index c129a0305..011d1b2d8 100644 --- a/src/manage_migrators.c +++ b/src/manage_migrators.c @@ -2996,6 +2996,69 @@ migrate_250_to_251 () return 0; } +/** + * @brief Migrate the database from version 251 to version 252. + * + * @return 0 success, -1 error. + */ +int +migrate_251_to_252 () +{ + sql_begin_immediate (); + + /* Ensure that the database is currently version 251. */ + + if (manage_db_version () != 251) + { + sql_rollback (); + return -1; + } + + /* Update the database. */ + + sql ("ALTER TABLE IF EXISTS results ADD COLUMN hash_value text;"); + + /* Set the database version to 252. */ + + set_db_version (252); + + sql_commit (); + + return 0; +} + +/** + * @brief Migrate the database from version 252 to version 253. + * + * @return 0 success, -1 error. + */ +int +migrate_252_to_253 () +{ + sql_begin_immediate (); + + /* Ensure that the database is currently version 252. */ + + if (manage_db_version () != 252) + { + sql_rollback (); + return -1; + } + + /* Update the database. */ + + sql ("ALTER TABLE IF EXISTS report_host_details ADD COLUMN hash_value text;"); + + /* Set the database version to 253. */ + + set_db_version (253); + + sql_commit (); + + return 0; +} + + #undef UPDATE_DASHBOARD_SETTINGS /** @@ -3053,6 +3116,8 @@ static migrator_t database_migrators[] = { {249, migrate_248_to_249}, {250, migrate_249_to_250}, {251, migrate_250_to_251}, + {252, migrate_251_to_252}, + {253, migrate_252_to_253}, /* End marker. */ {-1, NULL}}; diff --git a/src/manage_sql.c b/src/manage_sql.c index a4c4d7aec..0a1a8e70d 100644 --- a/src/manage_sql.c +++ b/src/manage_sql.c @@ -19067,14 +19067,15 @@ result_t make_osp_result (task_t task, const char *host, const char *hostname, const char *nvt, const char *type, const char *description, const char *port, const char *severity, int qod, - const char *path) + const char *path, const char *hash_value) { char *nvt_revision = NULL, *quoted_desc, *quoted_nvt, *result_severity; - char *quoted_port, *quoted_hostname, *quoted_path; + char *quoted_port, *quoted_hostname, *quoted_path, *quoted_hash_value; assert (task); assert (type); + quoted_hash_value = sql_quote(hash_value ?: ""); quoted_desc = sql_quote (description ?: ""); quoted_nvt = sql_quote (nvt ?: ""); quoted_port = sql_quote (port ?: ""); @@ -19111,14 +19112,14 @@ make_osp_result (task_t task, const char *host, const char *hostname, sql ("INSERT into results" " (owner, date, task, host, hostname, port, nvt," " nvt_version, severity, type, qod, qod_type, description," - " path, uuid, result_nvt)" + " path, uuid, result_nvt, hash_value)" " VALUES (NULL, m_now(), %llu, '%s', '%s', '%s', '%s'," " '%s', '%s', '%s', %d, '', '%s'," " '%s', make_uuid ()," - " (SELECT id FROM result_nvts WHERE nvt = '%s'));", + " (SELECT id FROM result_nvts WHERE nvt = '%s'), '%s');", task, host ?: "", quoted_hostname, quoted_port, quoted_nvt, nvt_revision ?: "", result_severity ?: "0", - type, qod, quoted_desc, quoted_path, quoted_nvt); + type, qod, quoted_desc, quoted_path, quoted_nvt, quoted_hash_value); g_free (result_severity); g_free (nvt_revision); g_free (quoted_desc); @@ -19126,6 +19127,7 @@ make_osp_result (task_t task, const char *host, const char *hostname, g_free (quoted_port); g_free (quoted_hostname); g_free (quoted_path); + g_free (quoted_hash_value); return sql_last_insert_id (); } @@ -20348,10 +20350,11 @@ void insert_report_host_detail (report_t report, const char *host, const char *s_type, const char *s_name, const char *s_desc, const char *name, - const char *value) + const char *value, const char * hash_value) { char *quoted_host, *quoted_source_name, *quoted_source_type; char *quoted_source_desc, *quoted_name, *quoted_value; + char *quoted_hash_value; quoted_host = sql_quote (host); quoted_source_type = sql_quote (s_type); @@ -20359,15 +20362,16 @@ insert_report_host_detail (report_t report, const char *host, quoted_source_desc = sql_quote (s_desc); quoted_name = sql_quote (name); quoted_value = sql_quote (value); + quoted_hash_value = sql_quote(hash_value ?: ""); sql ("INSERT INTO report_host_details" " (report_host, source_type, source_name, source_description," - " name, value)" + " name, value, hash_value)" " VALUES" " ((SELECT id FROM report_hosts" " WHERE report = %llu AND host = '%s')," - " '%s', '%s', '%s', '%s', '%s');", + " '%s', '%s', '%s', '%s', '%s', '%s');", report, quoted_host, quoted_source_type, quoted_source_name, - quoted_source_desc, quoted_name, quoted_value); + quoted_source_desc, quoted_name, quoted_value, quoted_hash_value); g_free (quoted_host); g_free (quoted_source_type); @@ -20375,6 +20379,7 @@ insert_report_host_detail (report_t report, const char *host, g_free (quoted_source_desc); g_free (quoted_name); g_free (quoted_value); + g_free (quoted_hash_value); } /** @@ -28942,6 +28947,126 @@ report_host_noticeable (report_t report, const gchar *host) && report_host_result_count (report_host) > 0; } +/* + * @brief Generate the hash value for the entity of the result and + * check if osp result for report already exists + * + * @param[in] report Report. + * @param[in] task Task. + * @param[in] r_entity entity of the result. + * + * @param[out] hash_value The generated hash value of r_entity. + * + * @return "1" if osp result already exists, else "0" + */ +static int +check_osp_result_exists (report_t report, task_t task, + entity_t r_entity, char **entity_hash_value) +{ + GString *entity_string; + int return_value = 0; + + entity_string = g_string_new (""); + print_entity_to_string (r_entity, entity_string); + *entity_hash_value = get_md5_hash_from_string (entity_string->str); + g_string_free(entity_string, TRUE); + if (sql_int ("SELECT EXISTS" + " (SELECT * FROM results" + " WHERE report = %llu and hash_value = '%s');", + report, *entity_hash_value)) + { + const char *type, *severity, *host, *hostname, *port; + const char *qod, *path; + gchar * desc; + + host = entity_attribute (r_entity, "host"); + hostname = entity_attribute (r_entity, "hostname"); + type = entity_attribute (r_entity, "type"); + desc = sql_quote (entity_text (r_entity)); + port = entity_attribute (r_entity, "port") ?: ""; + severity = entity_attribute (r_entity, "severity"); + qod = entity_attribute (r_entity, "qod") ?: ""; + path = entity_attribute (r_entity, "uri") ?: ""; + + if (sql_int ("SELECT EXISTS" + " (SELECT * FROM results" + " WHERE report = %llu and hash_value = '%s'" + " and host = '%s' and hostname = '%s'" + " and type = '%s' and description = '%s'" + " and port = '%s' and severity = %s" + " and qod = %s and path = '%s'" + " );", + report, *entity_hash_value, + host, hostname, + type, desc, + port, severity, + qod, path)) + { + g_info ("Captured duplicate result, report: %llu hash_value: %s", + report, *entity_hash_value); + return_value = 1; + } + g_free (desc); + } + return return_value; +} + +/* + * @brief Generate the hash value for the report host detail and + * check if the report host detail entry already exists + * + * @param[in] report Report. + * @param[in] task Task. + * @param[in] r_entity entity of the result. + * + * @param[out] hash_value The generated hash value of r_entity. + * + * @return "1" if osp result already exists, else "0" + */ +static int +check_host_detail_exists (report_t report, const char *host, const char *s_type, + const char *s_name, const char *s_desc, const char *name, + const char *value, char **detail_hash_value) +{ + char *hash_string; + long long int report_host; + int return_value = 0; + + hash_string = g_strdup_printf ("%llu-%s-%s-%s-%s-%s-%s", report, host, s_type, + s_name, s_desc, name, value); + *detail_hash_value = get_md5_hash_from_string (hash_string); + g_free (hash_string); + + sql_int64 (&report_host, "SELECT id FROM report_hosts" + " WHERE report = %llu AND host = '%s';", + report, host); + + if (sql_int ("SELECT EXISTS" + " (SELECT * FROM report_host_details" + " WHERE report_host = %llu and hash_value = '%s');", + report_host, *detail_hash_value)) + { + gchar *quoted_s_desc = sql_quote ((gchar*) s_desc); + + if (sql_int ("SELECT EXISTS" + " (SELECT * FROM report_host_details" + " WHERE report_host = %llu and hash_value = '%s'" + " and source_type = '%s' and source_name = '%s'" + " and source_description = '%s'" + " and name = '%s' and value = '%s'" + " );", + report_host, *detail_hash_value, s_type, s_name, + quoted_s_desc, name, value)) + { + g_info ("Captured duplicate report host detail, report: %llu hash_value: %s", + report, *detail_hash_value); + return_value = 1; + } + g_free (quoted_s_desc); + } + return return_value; +} + /** * @brief Parse an OSP report. * @@ -29042,8 +29167,15 @@ parse_osp_report (task_t task, report_t report, const char *report_xml) manage_report_host_add (report, host, start_time, end_time); if (!strcmp (type, "Host Detail")) { - insert_report_host_detail (report, host, "osp", "", "OSP Host Detail", - name, entity_text (r_entity)); + gchar *hash_value = NULL; + if (!check_host_detail_exists (report, host, "osp", "", + "OSP Host Detail", name, + entity_text (r_entity), &hash_value)) + { + insert_report_host_detail (report, host, "osp", "", "OSP Host Detail", + name, entity_text (r_entity), hash_value); + } + g_free (hash_value); results = next_entities (results); continue; } @@ -29069,9 +29201,7 @@ parse_osp_report (task_t task, report_t report, const char *report_xml) */ if (manage_report_host_detail (report, host, desc)) g_warning ("%s: Failed to add report detail for host '%s': %s", - __func__, - host, - desc); + __func__, host, desc); } else if (host && nvt_id && desc && (strcmp (nvt_id, "HOST_START") == 0)) { @@ -29084,17 +29214,23 @@ parse_osp_report (task_t task, report_t report, const char *report_xml) } else { - result = make_osp_result (task, - host, - hostname, - nvt_id, - type, - desc, - port ?: "", - severity_str ?: severity, - qod_int, - path); - g_array_append_val (results_array, result); + char *hash_value; + if (!check_osp_result_exists (report, task, r_entity, &hash_value)) + { + result = make_osp_result (task, + host, + hostname, + nvt_id, + type, + desc, + port ?: "", + severity_str ?: severity, + qod_int, + path, + hash_value); + g_array_append_val (results_array, result); + } + g_free (hash_value); } g_free (nvt_id); g_free (desc); @@ -47896,6 +48032,7 @@ manage_report_host_details (report_t report, const char *ip, entity_t entity) entities_t details; entity_t detail; char *uuid; + char *hash_value; in_assets = sql_int ("SELECT not(value = 'no') FROM task_preferences" " WHERE task = (SELECT task FROM reports" @@ -47934,9 +48071,26 @@ manage_report_host_details (report_t report, const char *ip, entity_t entity) value = entity_child (detail, "value"); if (value == NULL) goto error; - insert_report_host_detail - (report, ip, entity_text (source_type), entity_text (source_name), - entity_text (source_desc), entity_text (name), entity_text (value)); + + if (!check_host_detail_exists (report, ip, entity_text (source_type), + entity_text (source_name), + entity_text (source_desc), + entity_text (name), + entity_text (value), + (char**) &hash_value)) + { + insert_report_host_detail + (report, ip, entity_text (source_type), entity_text (source_name), + entity_text (source_desc), entity_text (name), entity_text (value), + hash_value); + g_free (hash_value); + } + else + { + g_free (hash_value); + details = next_entities (details); + continue; + } /* Only add to assets if "Add to Assets" is set on the task. */ if (in_assets)