From bafda406db82a4825ba49ddac05cb4aa93baca7b Mon Sep 17 00:00:00 2001 From: Juan Jose Nicola Date: Mon, 1 Jul 2024 15:02:56 -0300 Subject: [PATCH] Add: functions to handle an Openvasd scan task --- src/CMakeLists.txt | 29 +- src/gvmd.c | 4 + src/manage.c | 757 +++++++++++++++++++++++++++++++++++++++ src/manage.h | 9 +- src/manage_sql.c | 380 +++++++++++++++++++- src/manage_sql.h | 3 + src/manage_sql_configs.c | 5 + 7 files changed, 1167 insertions(+), 20 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2f27baf66a..959644914a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,7 @@ pkg_check_modules (LIBGVM_BASE REQUIRED libgvm_base>=22.10) pkg_check_modules (LIBGVM_UTIL REQUIRED libgvm_util>=22.10) pkg_check_modules (LIBGVM_OSP REQUIRED libgvm_osp>=22.10) pkg_check_modules (LIBGVM_GMP REQUIRED libgvm_gmp>=22.10) +pkg_check_modules (LIBGVM_OPENVASD REQUIRED libgvm_openvasd>=22.10) pkg_check_modules (GNUTLS REQUIRED gnutls>=3.2.15) pkg_check_modules (GLIB REQUIRED glib-2.0>=2.42) pkg_check_modules (LIBBSD REQUIRED libbsd) @@ -91,7 +92,7 @@ else (WITH_LIBTHEIA) set (OPT_THEIA_TGT "") endif (WITH_LIBTHEIA) -include_directories (${LIBGVM_GMP_INCLUDE_DIRS} +include_directories (${LIBGVM_GMP_INCLUDE_DIRS} ${LIBGVM_OPENVASD_INCLUDE_DIRS} ${LIBGVM_BASE_INCLUDE_DIRS} ${LIBGVM_UTIL_INCLUDE_DIRS} ${LIBGVM_OSP_INCLUDE_DIRS} ${LIBBSD_INCLUDE_DIRS} ${GLIB_INCLUDE_DIRS}) @@ -307,34 +308,34 @@ add_executable (gvmd target_link_libraries (gvmd m ${GNUTLS_LDFLAGS} ${GPGME_LDFLAGS} ${CMAKE_THREAD_LIBS_INIT} ${LINKER_HARDENING_FLAGS} ${LINKER_DEBUG_FLAGS} ${PostgreSQL_LIBRARIES} ${LIBBSD_LDFLAGS} ${CJSON_LDFLAGS} ${GLIB_LDFLAGS} ${GTHREAD_LDFLAGS} - ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_GMP_LDFLAGS} - ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) + ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_OPENVASD_LDFLAGS} + ${LIBGVM_GMP_LDFLAGS} ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) target_link_libraries (manage-test cgreen m ${GNUTLS_LDFLAGS} ${GPGME_LDFLAGS} ${CMAKE_THREAD_LIBS_INIT} ${LINKER_HARDENING_FLAGS} ${LINKER_DEBUG_FLAGS} ${PostgreSQL_LIBRARIES} ${LIBBSD_LDFLAGS} ${CJSON_LDFLAGS} ${GLIB_LDFLAGS} ${GTHREAD_LDFLAGS} - ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_GMP_LDFLAGS} - ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) + ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_OPENVASD_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} + ${LIBGVM_GMP_LDFLAGS} ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) target_link_libraries (manage-sql-test cgreen m ${GNUTLS_LDFLAGS} ${GPGME_LDFLAGS} ${CMAKE_THREAD_LIBS_INIT} ${LINKER_HARDENING_FLAGS} ${LINKER_DEBUG_FLAGS} ${PostgreSQL_LIBRARIES} ${LIBBSD_LDFLAGS} ${CJSON_LDFLAGS} ${GLIB_LDFLAGS} ${GTHREAD_LDFLAGS} - ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_GMP_LDFLAGS} - ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) + ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_OPENVASD_LDFLAGS} + ${LIBGVM_GMP_LDFLAGS} ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) target_link_libraries (manage-utils-test cgreen m ${GNUTLS_LDFLAGS} ${GPGME_LDFLAGS} ${CMAKE_THREAD_LIBS_INIT} ${LINKER_HARDENING_FLAGS} ${LINKER_DEBUG_FLAGS} ${PostgreSQL_LIBRARIES} ${LIBBSD_LDFLAGS} ${CJSON_LDFLAGS} ${GLIB_LDFLAGS} ${GTHREAD_LDFLAGS} - ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_GMP_LDFLAGS} - ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) + ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_OPENVASD_LDFLAGS} + ${LIBGVM_GMP_LDFLAGS} ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) target_link_libraries (gmp-tickets-test cgreen m ${GNUTLS_LDFLAGS} ${GPGME_LDFLAGS} ${CMAKE_THREAD_LIBS_INIT} ${LINKER_HARDENING_FLAGS} ${LINKER_DEBUG_FLAGS} ${PostgreSQL_LIBRARIES} ${LIBBSD_LDFLAGS} ${CJSON_LDFLAGS} ${GLIB_LDFLAGS} ${GTHREAD_LDFLAGS} - ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_GMP_LDFLAGS} - ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) + ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_OPENVASD_LDFLAGS} + ${LIBGVM_GMP_LDFLAGS} ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) target_link_libraries (utils-test cgreen m ${GNUTLS_LDFLAGS} ${GPGME_LDFLAGS} ${CMAKE_THREAD_LIBS_INIT} ${LINKER_HARDENING_FLAGS} ${LINKER_DEBUG_FLAGS} ${PostgreSQL_LIBRARIES} ${LIBBSD_LDFLAGS} ${CJSON_LDFLAGS} ${GLIB_LDFLAGS} ${GTHREAD_LDFLAGS} - ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_GMP_LDFLAGS} - ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) -target_link_libraries (gvm-pg-server ${LIBBSD_LDFLAGS} ${GLIB_LDFLAGS} ${GTHREAD_LDFLAGS} ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS}) + ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBGVM_OSP_LDFLAGS} ${LIBGVM_OPENVASD_LDFLAGS} + ${LIBGVM_GMP_LDFLAGS} ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS} ${OPT_THEIA_TGT}) +target_link_libraries (gvm-pg-server ${LIBBSD_LDFLAGS} ${GLIB_LDFLAGS} ${GTHREAD_LDFLAGS} ${LIBGVM_BASE_LDFLAGS} ${LIBGVM_OPENVASD_LDFLAGS} ${LIBGVM_UTIL_LDFLAGS} ${LIBICAL_LDFLAGS} ${LINKER_HARDENING_FLAGS}) set_target_properties (gvmd PROPERTIES LINKER_LANGUAGE C) set_target_properties (manage-test PROPERTIES LINKER_LANGUAGE C) diff --git a/src/gvmd.c b/src/gvmd.c index 4ffdab4e84..abb0cea49f 100644 --- a/src/gvmd.c +++ b/src/gvmd.c @@ -2802,6 +2802,8 @@ gvmd (int argc, char** argv, char *env[]) type = SCANNER_TYPE_OPENVAS; else if (!strcasecmp (scanner_type, "OSP-Sensor")) type = SCANNER_TYPE_OSP_SENSOR; + else if (!strcasecmp (scanner_type, "Openvasd")) + type = SCANNER_TYPE_OPENVASD; else { type = atoi (scanner_type); @@ -2844,6 +2846,8 @@ gvmd (int argc, char** argv, char *env[]) type = SCANNER_TYPE_OPENVAS; else if (!strcasecmp (scanner_type, "OSP-Sensor")) type = SCANNER_TYPE_OSP_SENSOR; + else if (!strcasecmp (scanner_type, "Openvasd")) + type = SCANNER_TYPE_OPENVASD; else { type = atoi (scanner_type); diff --git a/src/manage.c b/src/manage.c index 0af8a54860..f9225674e9 100644 --- a/src/manage.c +++ b/src/manage.c @@ -84,6 +84,7 @@ #include #include #include +#include #include #include #include @@ -3588,6 +3589,11 @@ slave_get_relay (const char *original_host, return ret; } + +/* Prototype */ +static int +run_openvasd_task (task_t task, int from, char **report_id); + /** * @brief Start or resume a task. * @@ -3650,6 +3656,9 @@ run_task (const char *task_id, char **report_id, int from) || scanner_type (scanner) == SCANNER_TYPE_OSP_SENSOR) return run_osp_task (task, from, report_id); + if (scanner_type (scanner) == SCANNER_TYPE_OPENVASD) + return run_openvasd_task (task, from, report_id); + return -1; // Unknown scanner type } @@ -3776,6 +3785,9 @@ stop_task_internal (task_t task) return 0; } +static int +stop_openvasd_task (task_t task); + /** * @brief Initiate stopping a task. * @@ -3802,6 +3814,9 @@ stop_task (const char *task_id) || scanner_type (task_scanner (task)) == SCANNER_TYPE_OSP_SENSOR) return stop_osp_task (task); + if (scanner_type (task_scanner (task)) == SCANNER_TYPE_OPENVASD) + return stop_openvasd_task (task); + return stop_task_internal (task); } @@ -7619,3 +7634,745 @@ delete_resource (const char *type, const char *resource_id, int ultimate) assert (0); return -1; } + +/* Openvasd */ + +/** + * @brief Stop an Openvasd task. + * + * @param[in] task The task. + * + * @return 0 on success, else -1. + */ +static int +stop_openvasd_task (task_t task) +{ + int ret = -1; + report_t scan_report; + char *scan_id; + task_t previous_task; + report_t previous_report; + + scanner_t scanner; + openvasd_resp_t response; + openvasd_connector_t connector = NULL; + + previous_task = current_scanner_task; + previous_report = global_current_report; + + scan_report = task_running_report (task); + scan_id = report_uuid (scan_report); + if (!scan_id) + goto end_stop_openvasd; + scanner = task_scanner (task); + connector = openvasd_scanner_connect (scanner, scan_id); + if (!connector) + goto end_stop_openvasd; + + current_scanner_task = task; + global_current_report = task_running_report (task); + set_task_run_status (task, TASK_STATUS_STOP_REQUESTED); + response = openvasd_stop_scan (&connector); + if (response->code < 0) + { + g_free (scan_id); + goto end_stop_openvasd; + } + + response = openvasd_delete_scan (&connector); + g_free (scan_id); + +end_stop_openvasd: + openvasd_connector_free(&connector); + set_task_end_time_epoch (task, time (NULL)); + set_task_run_status (task, TASK_STATUS_STOPPED); + if (scan_report) + { + set_scan_end_time_epoch (scan_report, time (NULL)); + set_report_scan_run_status (scan_report, TASK_STATUS_STOPPED); + } + current_scanner_task = previous_task; + global_current_report = previous_report; + if (ret) + return -1; + return 0; +} + +/** + * @brief Launch an OpenVAS via Openvasd task. + * + * @param[in] task The task. + * @param[in] target The target. + * @param[in] scan_id The scan uuid. + * @param[in] from 0 start from beginning, 1 continue from stopped, + * 2 continue if stopped else start from beginning. + * @param[out] error Error return. + * + * @return An http code on success, -1 if error. + */ +static int +launch_openvasd_openvas_task (task_t task, target_t target, const char *scan_id, + int from, char **error) +{ + openvasd_connector_t connection; + char *hosts_str, *ports_str, *exclude_hosts_str, *finished_hosts_str; + gchar *clean_hosts, *clean_exclude_hosts, *clean_finished_hosts_str; + int alive_test, reverse_lookup_only, reverse_lookup_unify; + int arp = 0, icmp = 0, tcp_ack = 0, tcp_syn = 0, consider_alive = 0; + openvasd_target_t *openvasd_target; + GSList *openvasd_targets, *vts; + GHashTable *vts_hash_table; + openvasd_credential_t *ssh_credential, *smb_credential, *esxi_credential; + openvasd_credential_t *snmp_credential; + gchar *max_checks, *max_hosts, *hosts_ordering; + GHashTable *scanner_options; + openvasd_resp_t response; + int ret, empty; + config_t config; + iterator_t scanner_prefs_iter, families, prefs; + + connection = NULL; + config = task_config (task); + + alive_test = 0; + reverse_lookup_unify = 0; + reverse_lookup_only = 0; + + /* Prepare the report */ + if (from) + { + ret = prepare_osp_scan_for_resume (task, scan_id, error); + if (ret == 0) + return 0; + else if (ret == -1) + return -1; + finished_hosts_str = report_finished_hosts_str (global_current_report); + clean_finished_hosts_str = clean_hosts_string (finished_hosts_str); + } + else + { + finished_hosts_str = NULL; + clean_finished_hosts_str = NULL; + } + + /* Set up target(s) */ + hosts_str = target_hosts (target); + ports_str = target_port_range (target); + exclude_hosts_str = target_exclude_hosts (target); + + clean_hosts = clean_hosts_string (hosts_str); + clean_exclude_hosts = clean_hosts_string (exclude_hosts_str); + + alive_test = 0; + if (target_alive_tests (target) > 0) + alive_test = target_alive_tests (target); + + if (target_reverse_lookup_only (target) != NULL) + reverse_lookup_only = atoi (target_reverse_lookup_only (target)); + + if (target_reverse_lookup_unify (target) != NULL) + reverse_lookup_unify = atoi (target_reverse_lookup_unify (target)); + + if (finished_hosts_str) + { + gchar *new_exclude_hosts; + + new_exclude_hosts = g_strdup_printf ("%s,%s", + clean_exclude_hosts, + clean_finished_hosts_str); + free (clean_exclude_hosts); + clean_exclude_hosts = new_exclude_hosts; + } + + openvasd_target = openvasd_target_new (scan_id, clean_hosts, ports_str, + clean_exclude_hosts, + reverse_lookup_unify, + reverse_lookup_only); + if (finished_hosts_str) + openvasd_target_set_finished_hosts (openvasd_target, finished_hosts_str); + + if (alive_test & ALIVE_TEST_ARP) + arp = 1; + if (alive_test & ALIVE_TEST_ICMP) + icmp = 1; + if (alive_test & ALIVE_TEST_TCP_ACK_SERVICE) + tcp_ack = 1; + if (alive_test & ALIVE_TEST_TCP_SYN_SERVICE) + tcp_syn = 1; + if (alive_test & ALIVE_TEST_CONSIDER_ALIVE) + consider_alive = 1; + + openvasd_target_add_alive_test_methods (openvasd_target, icmp, tcp_syn, + tcp_ack, arp, consider_alive); + + free (hosts_str); + free (ports_str); + free (exclude_hosts_str); + free (finished_hosts_str); + g_free (clean_hosts); + g_free (clean_exclude_hosts); + g_free (clean_finished_hosts_str); + openvasd_targets = g_slist_append (NULL, openvasd_target); + + ssh_credential = (openvasd_credential_t *) target_osp_ssh_credential (target); + if (ssh_credential) + openvasd_target_add_credential (openvasd_target, ssh_credential); + + smb_credential = (openvasd_credential_t *) target_osp_smb_credential (target); + if (smb_credential) + openvasd_target_add_credential (openvasd_target, smb_credential); + + esxi_credential = + (openvasd_credential_t *) target_osp_esxi_credential (target); + if (esxi_credential) + openvasd_target_add_credential (openvasd_target, esxi_credential); + + snmp_credential = + (openvasd_credential_t *) target_osp_snmp_credential (target); + if (snmp_credential) + openvasd_target_add_credential (openvasd_target, snmp_credential); + + /* Initialize vts table for vulnerability tests and their preferences */ + vts = NULL; + vts_hash_table + = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, + /* Value is freed in vts list. */ + NULL); + + /* Setup of vulnerability tests (without preferences) */ + init_family_iterator (&families, 0, NULL, 1); + empty = 1; + while (next (&families)) + { + const char *family = family_iterator_name (&families); + if (family) + { + iterator_t nvts; + init_nvt_iterator (&nvts, 0, config, family, NULL, 1, NULL); + while (next (&nvts)) + { + const char *oid; + openvasd_vt_single_t *new_vt; + + empty = 0; + oid = nvt_iterator_oid (&nvts); + new_vt = openvasd_vt_single_new (oid); + + vts = g_slist_prepend (vts, new_vt); + g_hash_table_replace (vts_hash_table, g_strdup (oid), new_vt); + } + cleanup_iterator (&nvts); + } + } + cleanup_iterator (&families); + + if (empty) { + if (error) + *error = g_strdup ("Exiting because VT list is empty " + "(e.g. feed not synced yet)"); + g_slist_free_full (openvasd_targets, (GDestroyNotify) openvasd_target_free); + // Credentials are freed with target + g_slist_free_full (vts, (GDestroyNotify) openvasd_vt_single_free); + return -1; + } + + /* Setup general scanner preferences */ + scanner_options + = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + init_preference_iterator (&scanner_prefs_iter, config, "SERVER_PREFS"); + while (next (&scanner_prefs_iter)) + { + const char *name, *value; + name = preference_iterator_name (&scanner_prefs_iter); + value = preference_iterator_value (&scanner_prefs_iter); + if (name && value && !g_str_has_prefix (name, "timeout.")) + { + const char *openvasd_value; + + // Workaround for boolean scanner preferences + if (strcmp (value, "0") == 0) + openvasd_value = "no"; + else if (strcmp (value, "1") == 0) + openvasd_value = "yes"; + else + openvasd_value = value; + g_hash_table_replace (scanner_options, + g_strdup (name), + g_strdup (openvasd_value)); + } + /* Timeouts are stored as SERVER_PREFS, but are actually + script preferences. This prefs is converted into a + script preference to be sent to the scanner. */ + else if (name && value && g_str_has_prefix (name, "timeout.")) + { + char **oid = NULL; + openvasd_vt_single_t *openvasd_vt = NULL; + + oid = g_strsplit (name, ".", 2); + openvasd_vt = g_hash_table_lookup (vts_hash_table, oid[1]); + if (openvasd_vt) + openvasd_vt_single_add_value (openvasd_vt, "0", value); + g_strfreev (oid); + } + + } + cleanup_iterator (&scanner_prefs_iter); + + /* Setup user-specific scanner preference */ + add_user_scan_preferences (scanner_options); + + /* Setup general task preferences */ + max_checks = task_preference_value (task, "max_checks"); + g_hash_table_insert (scanner_options, g_strdup ("max_checks"), + max_checks ? max_checks : g_strdup (MAX_CHECKS_DEFAULT)); + + max_hosts = task_preference_value (task, "max_hosts"); + g_hash_table_insert (scanner_options, g_strdup ("max_hosts"), + max_hosts ? max_hosts : g_strdup (MAX_HOSTS_DEFAULT)); + + hosts_ordering = task_hosts_ordering (task); + if (hosts_ordering) + g_hash_table_insert (scanner_options, g_strdup ("hosts_ordering"), + hosts_ordering); + + /* Setup VT preferences */ + init_preference_iterator (&prefs, config, "PLUGINS_PREFS"); + while (next (&prefs)) + { + const char *full_name, *value; + openvasd_vt_single_t *openvasd_vt; + gchar **split_name; + + full_name = preference_iterator_name (&prefs); + value = preference_iterator_value (&prefs); + split_name = g_strsplit (full_name, ":", 4); + + openvasd_vt = NULL; + if (split_name && split_name[0] && split_name[1] && split_name[2]) + { + const char *oid = split_name[0]; + const char *pref_id = split_name[1]; + const char *type = split_name[2]; + gchar *openvasd_value = NULL; + + if (strcmp (type, "checkbox") == 0) + { + if (strcmp (value, "yes") == 0) + openvasd_value = g_strdup ("1"); + else + openvasd_value = g_strdup ("0"); + } + else if (strcmp (type, "radio") == 0) + { + gchar** split_value; + split_value = g_strsplit (value, ";", 2); + openvasd_value = g_strdup (split_value[0]); + g_strfreev (split_value); + } + else if (strcmp (type, "file") == 0) + openvasd_value = g_base64_encode ((guchar*) value, strlen (value)); + + openvasd_vt = g_hash_table_lookup (vts_hash_table, oid); + if (openvasd_vt) + openvasd_vt_single_add_value (openvasd_vt, pref_id, + openvasd_value ? openvasd_value : value); + g_free (openvasd_value); + } + + g_strfreev (split_name); + } + cleanup_iterator (&prefs); + g_hash_table_destroy (vts_hash_table); + + /* Start the scan */ + connection = openvasd_scanner_connect (task_scanner (task), scan_id); + if (!connection) + { + if (error) + *error = g_strdup ("Could not connect to Scanner"); + g_slist_free_full (openvasd_targets, + (GDestroyNotify) openvasd_target_free); + // Credentials are freed with target + g_slist_free_full (vts, (GDestroyNotify) openvasd_vt_single_free); + g_hash_table_destroy (scanner_options); + return -1; + } + + gchar *scan_config = NULL; + scan_config = + openvasd_build_scan_config_json(openvasd_target, scanner_options, vts); + + response = openvasd_start_scan (&connection, scan_config); + openvasd_target_free(openvasd_target); + // Credentials are freed with target + g_slist_free_full (vts, (GDestroyNotify) openvasd_vt_single_free); + g_hash_table_destroy (scanner_options); + ret = response->code; + openvasd_response_free (response); + + return ret; +} + +/** + * @brief Handle an ongoing Openvasd scan, until success or failure. + * + * @param[in] task The task. + * @param[in] report The report. + * @param[in] scan_id The UUID of the scan on the scanner. + * + * @return 0 if success, -1 if error, -2 if scan was stopped, + * -3 if the scan was interrupted, -4 already stopped. + */ +static int +handle_openvasd_scan (task_t task, report_t report, const char *scan_id) +{ + int rc; + scanner_t scanner; + gboolean started, queued_status_updated; + int retry, connection_retry; + openvasd_resp_t response; + openvasd_connector_t connector; + + scanner = task_scanner (task); + connector = openvasd_scanner_connect (scanner, scan_id); + response = NULL; + started = FALSE; + queued_status_updated = FALSE; + connection_retry = get_scanner_connection_retry (); + + retry = connection_retry; + rc = -1; + while (retry >= 0) + { + int run_status, progress; + + run_status = task_run_status (task); + if (run_status == TASK_STATUS_STOPPED + || run_status == TASK_STATUS_STOP_REQUESTED) + { + rc = -4; + break; + } + + progress = openvasd_get_scan_progress (&connector); + + if (progress < 0 || progress > 100) + { + if (retry > 0 && progress == -1) + { + retry--; + g_warning ("Connection lost with the scanner." + "Trying again in 1 second."); + gvm_sleep (1); + continue; + } + else if (progress == -2) + { + rc = -2; + break; + } + result_t result = make_osp_result + (task, "", "", "", + threat_message_type ("Error"), + "Erroneous scan progress value", "", "", + QOD_DEFAULT, NULL, NULL); + report_add_result (report, result); + response = openvasd_delete_scan(&connector); + rc = -1; + break; + } + else + { + /* Get the full openvasd report. */ + progress = openvasd_get_scan_progress (&connector); + + if (progress < 0 || progress > 100) + { + if (retry > 0 && progress == -1) + { + retry--; + g_warning ("Connection lost with the scanner. " + "Trying again in 1 second."); + gvm_sleep (1); + continue; + } + else if (progress == -2) + { + rc = -2; + break; + } + result_t result = make_osp_result + (task, "", "", "", + threat_message_type ("Error"), + "Erroneous scan progress value", "", "", + QOD_DEFAULT, NULL, NULL); + report_add_result (report, result); + rc = -1; + break; + } + else + { + GSList *results = NULL; + static unsigned long result_start = 0; + static unsigned long result_end = -1; // get up to the end + openvasd_status_t current_status; + time_t start_time, end_time; + openvasd_scan_status_t openvasd_scan_status; + + set_report_slave_progress (report, progress); + + openvasd_parsed_results (&connector, result_start, + result_end, &results); + result_start += g_slist_length (results); + + gvm_sleep(1); + openvasd_scan_status = openvasd_parsed_scan_status (&connector); + start_time = openvasd_scan_status->start_time; + end_time = openvasd_scan_status->end_time; + current_status = openvasd_scan_status->status; + progress = openvasd_scan_status->progress; + g_free (openvasd_scan_status); + + if (g_slist_length(results)) + { + parse_openvasd_report (task, report, results, + start_time, end_time); + } + if (current_status == OPENVASD_SCAN_STATUS_STORED) + { + if (queued_status_updated == FALSE) + { + set_task_run_status (task, TASK_STATUS_QUEUED); + set_report_scan_run_status (global_current_report, + TASK_STATUS_QUEUED); + queued_status_updated = TRUE; + } + } + else if (current_status == OPENVASD_SCAN_STATUS_FAILED) + { + result_t result = make_osp_result + (task, "", "", "", + threat_message_type ("Error"), + "Task interrupted unexpectedly", "", "", + QOD_DEFAULT, NULL, NULL); + report_add_result (report, result); + response = openvasd_delete_scan (&connector); + rc = -3; + break; + } + else if (progress >= 0 && progress < 100 + && current_status == OPENVASD_SCAN_STATUS_STOPPED) + { + if (retry > 0) + { + retry--; + g_warning ("Connection lost with the scanner. " + "Trying again in 1 second."); + gvm_sleep (1); + continue; + } + + result_t result = make_osp_result + (task, "", "", "", + threat_message_type ("Error"), + "Scan stopped unexpectedly by the server", "", "", + QOD_DEFAULT, NULL, NULL); + report_add_result (report, result); + response = openvasd_delete_scan (&connector); + rc = -1; + break; + } + else if (progress == 100 + && current_status == OPENVASD_SCAN_STATUS_SUCCEEDED) + { + response = openvasd_delete_scan (&connector); + rc = response->code; + break; + } + else if (current_status == OPENVASD_SCAN_STATUS_RUNNING + && started == FALSE) + { + set_task_run_status (task, TASK_STATUS_RUNNING); + set_report_scan_run_status (global_current_report, + TASK_STATUS_RUNNING); + started = TRUE; + } + } + } + + retry = connection_retry; + gvm_sleep (5); + } + openvasd_response_free (response); + openvasd_connector_free(&connector); + return rc; +} + + +/** + * @brief Fork a child to handle an Openvasd scan's fetching and inserting. + * + * @param[in] task The task. + * @param[in] target The target. + * @param[in] from 0 start from beginning, 1 continue from stopped, + * 2 continue if stopped else start from beginning. + * @param[out] report_id_return UUID of the report. + * + * @return Parent returns with 0 if success, -1 if failure. Child process + * doesn't return and simply exits. + */ +static int +fork_openvasd_scan_handler (task_t task, target_t target, int from, + char **report_id_return) +{ + char *report_id, *error = NULL; + int rc; + + assert (task); + assert (target); + + if (report_id_return) + *report_id_return = NULL; + + if (run_osp_scan_get_report (task, from, &report_id)) + return -1; + + current_scanner_task = task; + set_task_run_status (task, TASK_STATUS_REQUESTED); + + switch (fork ()) + { + case 0: + init_sentry (); + break; + case -1: + /* Parent, failed to fork. */ + global_current_report = 0; + g_warning ("%s: Failed to fork: %s", + __func__, + strerror (errno)); + set_task_interrupted (task, + "Error forking scan handler." + " Interrupting scan."); + set_report_scan_run_status (global_current_report, + TASK_STATUS_INTERRUPTED); + global_current_report = (report_t) 0; + current_scanner_task = 0; + g_free (report_id); + return -9; + default: + /* Parent, successfully forked. */ + global_current_report = 0; + current_scanner_task = 0; + if (report_id_return) + *report_id_return = report_id; + else + g_free (report_id); + return 0; + } + + /* Child: Re-open DB after fork and periodically check scan progress. + * If progress == 100%: Parse the report results and other info then exit(0). + * Else, exit(1) in error cases like connection to scanner failure. + */ + reinit_manage_process (); + manage_session_init (current_credentials.uuid); + + rc = launch_openvasd_openvas_task (task, target, report_id, from, &error); + + if (rc < 0) + { + result_t result; + + g_warning ("Openvasd start_scan %s: %s", report_id, error); + result = make_osp_result (task, "", "", "", + threat_message_type ("Error"), + 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); + set_task_end_time_epoch (task, time (NULL)); + set_scan_end_time_epoch (global_current_report, time (NULL)); + + g_free (error); + g_free (report_id); + gvm_close_sentry (); + exit (-1); + } + + setproctitle ("Openvasd: Handling scan %s", report_id); + + rc = handle_openvasd_scan (task, global_current_report, report_id); + g_free (report_id); + + if (rc >= 0) + { + set_task_run_status (task, TASK_STATUS_PROCESSING); + set_report_scan_run_status (global_current_report, + TASK_STATUS_PROCESSING); + hosts_set_identifiers (global_current_report); + hosts_set_max_severity (global_current_report, NULL, NULL); + hosts_set_details (global_current_report); + set_task_run_status (task, TASK_STATUS_DONE); + set_report_scan_run_status (global_current_report, TASK_STATUS_DONE); + } + else if (rc == -1 || rc == -2) + { + set_task_run_status (task, TASK_STATUS_STOPPED); + set_report_scan_run_status (global_current_report, TASK_STATUS_STOPPED); + } + else if (rc == -3) + { + set_task_run_status (task, TASK_STATUS_INTERRUPTED); + set_report_scan_run_status (global_current_report, + TASK_STATUS_INTERRUPTED); + } + + set_task_end_time_epoch (task, time (NULL)); + set_scan_end_time_epoch (global_current_report, time (NULL)); + global_current_report = 0; + current_scanner_task = (task_t) 0; + gvm_close_sentry (); + exit (rc); +} + + +/** + * @brief Start a task on an Openvasd scanner. + * + * @param[in] task The task. + * @param[in] from 0 start from beginning, 1 continue from stopped, + * 2 continue if stopped else start from beginning. + * @param[out] report_id The report ID. + * + * @return 0 success, 99 permission denied, -1 error. + */ +static int +run_openvasd_task (task_t task, int from, char **report_id) +{ + target_t target; + + target = task_target (task); + if (target) + { + char *uuid; + target_t found; + + uuid = target_uuid (target); + if (find_target_with_permission (uuid, &found, "get_targets")) + { + g_free (uuid); + return -1; + } + g_free (uuid); + if (found == 0) + return 99; + } + + if (fork_openvasd_scan_handler (task, target, from, report_id)) + { + g_warning ("Couldn't fork Openvasd scan handler"); + return -1; + } + return 0; +} diff --git a/src/manage.h b/src/manage.h index 9e7bbbce92..2baf44772d 100644 --- a/src/manage.h +++ b/src/manage.h @@ -39,6 +39,7 @@ #include #include #include +#include #include /** @@ -327,7 +328,8 @@ typedef enum scanner_type SCANNER_TYPE_CVE = 3, /* 4 was removed (SCANNER_TYPE_GMP). */ SCANNER_TYPE_OSP_SENSOR = 5, - SCANNER_TYPE_MAX = 6, + SCANNER_TYPE_OPENVASD = 6, + SCANNER_TYPE_MAX = 7, } scanner_type_t; int @@ -3958,4 +3960,9 @@ get_vt_verification_collation (); void set_vt_verification_collation (const char *); +/* Openvasd*/ +openvasd_connector_t +openvasd_scanner_connect (scanner_t, const char *); + + #endif /* not _GVMD_MANAGE_H */ diff --git a/src/manage_sql.c b/src/manage_sql.c index 100030655c..f3fb76fd7c 100644 --- a/src/manage_sql.c +++ b/src/manage_sql.c @@ -24,6 +24,8 @@ /** * @brief Enable extra GNU functions. */ +#include "manage.h" +#include #define _GNU_SOURCE #include "debug_utils.h" @@ -67,6 +69,8 @@ #include #include #include +#include +#include #include #include @@ -82,6 +86,7 @@ #include #include #include +#include #include "manage_report_configs.h" #undef G_LOG_DOMAIN @@ -19954,14 +19959,17 @@ nvt_severity (const char *nvt_id, const char *type) { char *severity = NULL; - if (strcasecmp (type, "Alarm") == 0 && nvt_id) + if ((strcasecmp (type, "alarm") == 0 || strcasecmp (type, "Alarm") == 0) && nvt_id) severity = sql_string ("SELECT coalesce(cvss_base, '0.0')" " FROM nvts WHERE uuid = '%s';", nvt_id); - else if (strcasecmp (type, "Alarm") == 0) + else if (strcasecmp (type, "Alarm") == 0 + || strcasecmp (type, "alarm") == 0) g_warning ("%s result type requires an NVT", type); - else if (strcasecmp (type, "Log Message") == 0) + else if (strcasecmp (type, "Log Message") == 0 + || strcasecmp (type, "log") == 0) severity = g_strdup (G_STRINGIFY (SEVERITY_LOG)); - else if (strcasecmp (type, "Error Message") == 0) + else if (strcasecmp (type, "Error Message") == 0 + || strcasecmp (type, "error") == 0) severity = g_strdup (G_STRINGIFY (SEVERITY_ERROR)); else g_warning ("Invalid result nvt type %s", type); @@ -41342,7 +41350,7 @@ create_scanner (const char* name, const char *comment, const char *host, if (!host || !port || !type) return 2; - if (*host == '/') + if (*host == '/' || *host == 'h') { unix_socket = 1; ca_pub = NULL; @@ -42570,6 +42578,7 @@ osp_scanner_connect (scanner_t scanner) return connection; } + /** * @brief Get an OSP Scanner's get_version info. * @@ -42668,6 +42677,11 @@ verify_scanner (const char *scanner_id, char **version) return 2; return 0; } + else if (scanner_iterator_type (&scanner) == SCANNER_TYPE_OPENVASD) + { + cleanup_iterator (&scanner); + return 0; + } else if (scanner_iterator_type (&scanner) == SCANNER_TYPE_CVE) { if (version) @@ -42725,6 +42739,9 @@ manage_get_scanners (GSList *log_config, const db_conn_info_t *database) case SCANNER_TYPE_OSP_SENSOR: scanner_type_str = "OSP-Sensor"; break; + case SCANNER_TYPE_OPENVASD: + scanner_type_str = "Openvasd"; + break; default: scanner_type_str = NULL; } @@ -59114,3 +59131,356 @@ cleanup_ids_for_table (const char *table) free (sequence_name); return 0; } + + +/** + * @brief Create a new connection to an OSP scanner. + * + * @param[in] scanner Scanner. + * + * @return New connection if success, NULL otherwise. + */ +openvasd_connector_t +openvasd_scanner_connect (scanner_t scanner, const char *scan_id) +{ + int port; + openvasd_connector_t connection; + char *server, *ca_pub, *key_pub, *key_priv; + + assert (scanner); + server = scanner_host (scanner); + port = scanner_port (scanner); + ca_pub = scanner_ca_pub (scanner); + key_pub = scanner_key_pub (scanner); + key_priv = scanner_key_priv (scanner); + + connection = openvasd_connector_new(); + + openvasd_connector_builder (&connection, OPENVASD_SERVER, server); + openvasd_connector_builder (&connection, OPENVASD_CA_CERT, ca_pub); + openvasd_connector_builder (&connection, OPENVASD_KEY, key_priv); + openvasd_connector_builder (&connection, OPENVASD_CERT, key_pub); + openvasd_connector_builder (&connection, OPENVASD_PORT, (void *) &port); + + if (scan_id && scan_id[0] != '\0') + openvasd_connector_builder (&connection, OPENVASD_SCAN_ID, scan_id); + + g_free (server); + g_free (ca_pub); + g_free (key_pub); + g_free (key_priv); + + return connection; +} + +/** + * @brief Generate the hash value for the fields of the result and + * check if openvasd result for report already exists + * + * @param[in] report Report. + * @param[in] task Task. + * @param[in] r_entity entity of the result. + * @param[out] entity_hash_value The generated hash value of r_entity. + * + * @return "1" if openvasd result already exists, else "0" + */ +static int +check_openvasd_result_exists (report_t report, task_t task, + openvasd_result_t res, char **entity_hash_value, + GHashTable *hashed_openvasd_results) +{ + GString *result_string; + int return_value = 0; + char *port_str = NULL; + if (res->port == 0 && res->detail_value && *res->detail_value) + port_str = g_strdup ("general/Host_Details"); + else if (res->port > 0) + { + char buf[6]; + snprintf (buf, sizeof(buf) , "%d", res->port); + port_str = g_strdup (buf); + } + else + port_str = ""; + + result_string = g_string_new (""); + g_string_append_printf (result_string, "host:%s\n" + "hostname:%s\n" + "type:%s\n" + "description:%s\n" + "port:%s",res->ip_address, res->hostname, + res->type, res->message, port_str); + + *entity_hash_value = get_md5_hash_from_string (result_string->str); + if (g_hash_table_contains (hashed_openvasd_results, *entity_hash_value)) + { + return_value = 1; + } + else + { + g_hash_table_insert (hashed_openvasd_results, + g_strdup(*entity_hash_value), + GINT_TO_POINTER(1)); + if (sql_int ("SELECT EXISTS" + " (SELECT * FROM results" + " WHERE report = %llu and hash_value = '%s');", + report, *entity_hash_value)) + { + const char *desc, *type, *severity = NULL, *host; + const char *hostname, *port = NULL, *path = NULL; + gchar *quoted_desc, *quoted_type, *quoted_host; + gchar *quoted_hostname, *quoted_port, *quoted_path; + double severity_double = 0.0; + int qod_int = QOD_DEFAULT; + + host = res->ip_address; + hostname = res->hostname; + type = res->type; + desc = res->message; + qod_int = QOD_DEFAULT; + + if (!severity || !strcmp (severity, "")) + { + if (!strcmp (type, severity_to_type (SEVERITY_ERROR))) + severity_double = SEVERITY_ERROR; + else + { + g_debug ("%s: Result without severity", __func__); + return 0; + } + } + else + { + severity_double = strtod (severity, NULL); + } + + quoted_host = sql_quote (host ?: ""); + quoted_hostname = sql_quote (hostname ?: ""); + quoted_type = sql_quote (type ?: ""); + quoted_desc = sql_quote (desc ?: ""); + quoted_port = sql_quote (port ?: ""); + quoted_path = sql_quote (path ?: ""); + + 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 = %1.1f" + " and qod = %d and path = '%s'" + " );", + report, *entity_hash_value, + quoted_host, quoted_hostname, + quoted_type, quoted_desc, + quoted_port, severity_double, + qod_int, quoted_path)) + { + g_info ("Captured duplicate result, report: %llu hash_value: %s", + report, *entity_hash_value); + g_debug ("Entity string: %s", result_string->str); + return_value = 1; + } + + g_free (quoted_host); + g_free (quoted_hostname); + g_free (quoted_type); + g_free (quoted_desc); + g_free (quoted_port); + g_free (quoted_path); + } + } + if (return_value) + { + g_debug ("Captured duplicate result, report: %llu hash_value: %s", + report, *entity_hash_value); + g_debug ("Entity string: %s", result_string->str); + } + g_string_free (result_string, TRUE); + return return_value; +} + +/* Struct to be sent as user data to the GFunc for adding results */ +struct report_aux { + GArray *results_array; + report_t report; + task_t task; + GHashTable *hash_results; + GHashTable *hash_hostdetails; +}; + +static void +add_openvasd_result_to_report (openvasd_result_t res, gpointer *results_aux) +{ + + struct report_aux *rep_aux = *results_aux; + result_t result; + char *type, *name, *severity, *host, *hostname, *test_id; + char *port = NULL, *path = NULL; + char *desc = NULL, *nvt_id = NULL, *severity_str = NULL; + int qod_int; + + type = res->type; + name = NULL; + severity = NULL; + test_id = res->oid; + host = res->ip_address; + hostname = res->hostname; + + if (res->port == 0 && res->detail_value && *res->detail_value) + port = g_strdup ("general/Host_Details"); + else if (res->port > 0) + { + char buf[6]; + snprintf(buf, sizeof(buf) , "%d", res->port); + port = g_strdup (buf); + } + + /* Add report host if it doesn't exist. */ + manage_report_host_add (rep_aux->report, host, 0, 0); + if (!strcmp (type, "host_detail")) + { + gchar *hash_value = NULL; + if (!check_host_detail_exists (rep_aux->report, host, "openvasd", "", + "Openvasd Host Detail", res->detail_name, + res->detail_value, &hash_value, + rep_aux->hash_hostdetails)) + { + + insert_report_host_detail (rep_aux->report, host, "openvasd", "", + "Openvasd Host Detail", res->detail_name, + res->detail_value, hash_value); + } + g_free (hash_value); + g_free (port); + return; + } + else if (g_str_has_prefix (test_id, "1.3.6.1.4.1.25623.1.")) + { + nvt_id = g_strdup (test_id); + severity_str = nvt_severity (test_id, type); + desc = res->message; + } + else + { + nvt_id = g_strdup (name); + desc = res->message; + } + qod_int = QOD_DEFAULT; + if (port && strcmp (port, "general/Host_Details") == 0) + { + /* TODO: This should probably be handled by the "Host Detail" + * result type with extra source info in OSP. + */ + if (manage_report_host_detail (rep_aux->report, host, desc, + rep_aux->hash_hostdetails)) + g_warning ("%s: Failed to add report detail for host '%s': %s", + __func__, host, desc); + } + else if (host && desc && (strcmp (type, "host_start") == 0)) + { + set_scan_host_start_time_ctime (rep_aux->report, host, desc); + } + else if (host && desc && (strcmp (type, "host_end") == 0)) + { + set_scan_host_end_time_ctime (rep_aux->report, host, desc); + add_assets_from_host_in_report (rep_aux->report, host); + } + else + { + char *hash_value; + if (!check_openvasd_result_exists (rep_aux->report, rep_aux->task, res, + &hash_value, rep_aux->hash_results)) + { + result = make_osp_result (rep_aux->task, + host ?: "", + hostname ?: "", + nvt_id ?: "", + type ?: "", + desc ?: "", + port ?: "", + severity_str ?: severity, + qod_int, + path ?: "", + hash_value); + g_array_append_val (rep_aux->results_array, result); + } + g_free (hash_value); + } + + g_free (port); + g_free (nvt_id); + + return; +} + +/** + * @brief Parse Openvasd results. + * + * @param[in] task Task. + * @param[in] report Report. + * @param[in] results Openvasd results. + */ +void +parse_openvasd_report (task_t task, report_t report, GSList *results, + time_t start_time, time_t end_time) +{ + char *defs_file = NULL; + gboolean has_results = FALSE; + GArray *results_array = NULL; + GHashTable *hashed_openvasd_results = NULL; + GHashTable *hashed_host_details = NULL; + struct report_aux *rep_aux; + + assert (task); + assert (report); + + hashed_openvasd_results = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + NULL); + + hashed_host_details = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + NULL); + + sql_begin_immediate (); + /* Set the report's start and end times. */ + + if (start_time) + set_scan_start_time_epoch (report, start_time); + + if (end_time) + set_scan_end_time_epoch (report, end_time); + + if (g_slist_length (results)) + has_results = TRUE; + + defs_file = task_definitions_file (task); + + results_array = g_array_new(TRUE, TRUE, sizeof(result_t)); + rep_aux = g_malloc0 (sizeof (struct report_aux)); + rep_aux->report = report; + rep_aux->task = task; + rep_aux->results_array = results_array; + rep_aux->hash_results = hashed_openvasd_results; + rep_aux->hash_hostdetails = hashed_host_details; + + g_slist_foreach(results, (GFunc) add_openvasd_result_to_report, &rep_aux); + + if (has_results) + { + sql ("UPDATE reports SET modification_time = m_now() WHERE id = %llu;", + report); + report_add_results_array (report, results_array); + } + + sql_commit (); + if (results_array && has_results) + g_array_free (results_array, TRUE); + + g_hash_table_destroy (hashed_openvasd_results); + g_hash_table_destroy (hashed_host_details); + g_free (defs_file); + g_free (rep_aux); +} diff --git a/src/manage_sql.h b/src/manage_sql.h index 29b5988a10..df025ac2e9 100644 --- a/src/manage_sql.h +++ b/src/manage_sql.h @@ -25,6 +25,7 @@ #define _GVMD_MANAGE_SQL_H #include +#include #include "manage.h" #include "manage_utils.h" @@ -526,4 +527,6 @@ cleanup_nvt_sequences (); int cleanup_ids_for_table (const char *); +void +parse_openvasd_report (task_t, report_t, GSList *, time_t, time_t); #endif /* not _GVMD_MANAGE_SQL_H */ diff --git a/src/manage_sql_configs.c b/src/manage_sql_configs.c index 039cc3f989..01c4031ea0 100644 --- a/src/manage_sql_configs.c +++ b/src/manage_sql_configs.c @@ -2762,6 +2762,8 @@ create_task_check_scanner_type (scanner_t scanner) return 1; if (stype == SCANNER_TYPE_OSP_SENSOR) return 1; + if (stype == SCANNER_TYPE_OPENVASD) + return 1; return 0; } @@ -2831,6 +2833,9 @@ modify_task_check_config_scanner (task_t task, const char *config_id, if (stype == SCANNER_TYPE_OSP_SENSOR) return 0; + if (stype == SCANNER_TYPE_OPENVASD) + return 0; + /* Default Scanner with OpenVAS Config. */ if (scanner == 0) return 0;