/* Copyright (C) 2009-2021 Greenbone Networks GmbH * * SPDX-License-Identifier: AGPL-3.0-or-later * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ /** * @file manage_sql_nvts.c * @brief GVM management layer: NVTs * * The NVT parts of the GVM management layer. */ /** * @brief Enable extra GNU functions. */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "manage_sql_nvts.h" #include "manage_preferences.h" #include "manage_sql.h" #include "manage_sql_configs.h" #include "sql.h" #include "utils.h" #undef G_LOG_DOMAIN /** * @brief GLib log domain. */ #define G_LOG_DOMAIN "md manage" /* NVT related global options */ /** * @brief File socket for OSP NVT update. */ static gchar *osp_vt_update_socket = NULL; /** * @brief Get the current file socket for OSP NVT update. * * @return The path of the file socket for OSP NVT update. */ const gchar * get_osp_vt_update_socket () { return osp_vt_update_socket; } /** * @brief Set the file socket for OSP NVT update. * * @param new_socket The new path of the file socket for OSP NVT update. */ void set_osp_vt_update_socket (const char *new_socket) { if (new_socket) { g_free (osp_vt_update_socket); osp_vt_update_socket = g_strdup (new_socket); } } /** * @brief Check the files socket used for OSP NVT update. * * @return 0 success, 1 no socket found. */ int check_osp_vt_update_socket () { if (get_osp_vt_update_socket () == NULL) { char *default_socket; /* Try to get OSP VT update socket from default scanner. */ default_socket = openvas_default_scanner_host (); if (default_socket == NULL) return 1; g_debug ("%s: Using OSP VT update socket from default OpenVAS" " scanner: %s", __func__, default_socket); set_osp_vt_update_socket (default_socket); free (default_socket); } return 0; } /* NVT's. */ /** * @brief Ensures the sanity of nvts cache in DB. */ void check_db_nvts () { /* Ensure the nvti cache update flag exists and is clear. */ if (sql_int ("SELECT count(*) FROM %s.meta" " WHERE name = 'update_nvti_cache';", sql_schema ())) sql ("UPDATE %s.meta SET value = 0 WHERE name = 'update_nvti_cache';", sql_schema ()); else sql ("INSERT INTO %s.meta (name, value)" " VALUES ('update_nvti_cache', 0);", sql_schema ()); } /** * @brief Get the name of an NVT. * * @param[in] nvt NVT. * * @return Freshly allocated name of NVT if possible, else NULL. */ char * manage_nvt_name (nvt_t nvt) { return sql_string ("SELECT name FROM nvts WHERE id = %llu;", nvt); } /** * @brief Get the name of an NVT given its OID. * * @param[in] oid OID of NVT. * * @return Name of NVT if possible, else NULL. */ char * nvt_name (const char *oid) { gchar *quoted_oid = sql_quote (oid); char *ret = sql_string ("SELECT name FROM nvts WHERE oid = '%s' LIMIT 1;", quoted_oid); g_free (quoted_oid); return ret; } /** * @brief Return feed version of the plugins in the plugin cache. * * @return Feed version of plugins if the plugins are cached, else NULL. */ char* nvts_feed_version () { return sql_string ("SELECT value FROM %s.meta" " WHERE name = 'nvts_feed_version';", sql_schema ()); } /** * @brief Return feed version of the plugins as seconds since epoch. * * @return Feed version in seconds since epoch of plugins. */ time_t nvts_feed_version_epoch () { gchar *feed_version; struct tm tm; feed_version = nvts_feed_version (); if (feed_version == NULL) return 0; memset (&tm, 0, sizeof (struct tm)); strptime (feed_version, "%Y%m%d%H%M%S", &tm); g_free (feed_version); return mktime (&tm); } /** * @brief Set the feed version of the plugins in the plugin cache. * * @param[in] feed_version New feed version. * * Also queue an update to the nvti cache. */ void set_nvts_feed_version (const char *feed_version) { gchar* quoted = sql_quote (feed_version); sql ("DELETE FROM %s.meta WHERE name = 'nvts_feed_version';", sql_schema ()); sql ("INSERT INTO %s.meta (name, value)" " VALUES ('nvts_feed_version', '%s');", sql_schema (), quoted); g_free (quoted); } /** * @brief Find an NVT given an identifier. * * @param[in] oid An NVT identifier. * @param[out] nvt NVT return, 0 if successfully failed to find task. * * @return FALSE on success (including if failed to find NVT), TRUE on error. */ gboolean find_nvt (const char* oid, nvt_t* nvt) { gchar *quoted_oid; int ret; quoted_oid = sql_quote (oid); ret = sql_int64 (nvt, "SELECT id FROM nvts WHERE oid = '%s';", quoted_oid); g_free (quoted_oid); switch (ret) { case 0: break; case 1: /* Too few rows in result of query. */ *nvt = 0; break; default: /* Programming error. */ assert (0); case -1: return TRUE; break; } return FALSE; } /** * @brief Insert an NVT. * * @param[in] nvti NVT Information. */ static void insert_nvt (const nvti_t *nvti) { gchar *qod_str, *qod_type, *cve; gchar *quoted_name, *quoted_summary, *quoted_insight, *quoted_affected; gchar *quoted_impact, *quoted_detection, *quoted_cve, *quoted_tag; gchar *quoted_cvss_base, *quoted_qod_type, *quoted_family; gchar *quoted_solution, *quoted_solution_type, *quoted_solution_method; int qod, i; double highest; cve = nvti_refs (nvti, "cve", "", 0); quoted_name = sql_quote (nvti_name (nvti) ? nvti_name (nvti) : ""); quoted_summary = sql_quote (nvti_summary (nvti) ? nvti_summary (nvti) : ""); quoted_insight = sql_quote (nvti_insight (nvti) ? nvti_insight (nvti) : ""); quoted_affected = sql_quote (nvti_affected (nvti) ? nvti_affected (nvti) : ""); quoted_impact = sql_quote (nvti_impact (nvti) ? nvti_impact (nvti) : ""); quoted_cve = sql_quote (cve ? cve : ""); g_free (cve); quoted_solution = sql_quote (nvti_solution (nvti) ? nvti_solution (nvti) : ""); quoted_solution_type = sql_quote (nvti_solution_type (nvti) ? nvti_solution_type (nvti) : ""); quoted_solution_method = sql_quote (nvti_solution_method (nvti) ? nvti_solution_method (nvti) : ""); quoted_detection = sql_quote (nvti_detection (nvti) ? nvti_detection (nvti) : ""); quoted_tag = sql_quote (nvti_tag (nvti) ? nvti_tag (nvti) : ""); quoted_cvss_base = sql_quote (nvti_cvss_base (nvti) ? nvti_cvss_base (nvti) : ""); qod_str = nvti_qod (nvti); qod_type = nvti_qod_type (nvti); if (qod_str == NULL || sscanf (qod_str, "%d", &qod) != 1) qod = qod_from_type (qod_type); quoted_qod_type = sql_quote (qod_type ? qod_type : ""); quoted_family = sql_quote (nvti_family (nvti) ? nvti_family (nvti) : ""); if (sql_int ("SELECT EXISTS (SELECT * FROM nvts WHERE oid = '%s');", nvti_oid (nvti))) sql ("DELETE FROM nvts WHERE oid = '%s';", nvti_oid (nvti)); sql ("INSERT into nvts (oid, name, summary, insight, affected," " impact, cve, tag, category, family, cvss_base," " creation_time, modification_time, uuid, solution_type," " solution_method, solution, detection, qod, qod_type)" " VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s'," " '%s', %i, '%s', '%s', %i, %i, '%s', '%s', '%s', '%s', '%s', %d, '%s');", nvti_oid (nvti), quoted_name, quoted_summary, quoted_insight, quoted_affected, quoted_impact, quoted_cve, quoted_tag, nvti_category (nvti), quoted_family, quoted_cvss_base, nvti_creation_time (nvti), nvti_modification_time (nvti), nvti_oid (nvti), quoted_solution_type, quoted_solution_method, quoted_solution, quoted_detection, qod, quoted_qod_type); sql ("DELETE FROM vt_refs where vt_oid = '%s';", nvti_oid (nvti)); for (i = 0; i < nvti_vtref_len (nvti); i++) { vtref_t *ref; gchar *quoted_type, *quoted_id, *quoted_text; ref = nvti_vtref (nvti, i); quoted_type = sql_quote (vtref_type (ref)); quoted_id = sql_quote (vtref_id (ref)); quoted_text = sql_quote (vtref_text (ref) ? vtref_text (ref) : ""); sql ("INSERT into vt_refs (vt_oid, type, ref_id, ref_text)" " VALUES ('%s', '%s', '%s', '%s');", nvti_oid (nvti), quoted_type, quoted_id, quoted_text); g_free (quoted_type); g_free (quoted_id); g_free (quoted_text); } sql ("DELETE FROM vt_severities where vt_oid = '%s';", nvti_oid (nvti)); highest = 0; for (i = 0; i < nvti_vtseverities_len (nvti); i++) { vtseverity_t *severity; gchar *quoted_origin, *quoted_value; severity = nvti_vtseverity (nvti, i); quoted_origin = sql_quote (vtseverity_origin (severity) ? vtseverity_origin (severity) : ""); quoted_value = sql_quote (vtseverity_value (severity) ? vtseverity_value (severity) : ""); sql ("INSERT into vt_severities (vt_oid, type, origin, date, score," " value)" " VALUES ('%s', '%s', '%s', %i, %0.1f, '%s');", nvti_oid (nvti), vtseverity_type (severity), quoted_origin, vtseverity_date (severity), vtseverity_score (severity), quoted_value); if (vtseverity_score (severity) > highest) highest = vtseverity_score (severity); g_free (quoted_origin); g_free (quoted_value); } sql ("UPDATE nvts SET cvss_base = %0.1f WHERE oid = '%s';", highest, nvti_oid (nvti)); g_free (quoted_name); g_free (quoted_summary); g_free (quoted_insight); g_free (quoted_affected); g_free (quoted_impact); g_free (quoted_cve); g_free (quoted_tag); g_free (quoted_cvss_base); g_free (quoted_family); g_free (quoted_solution); g_free (quoted_solution_type); g_free (quoted_solution_method); g_free (quoted_detection); g_free (quoted_qod_type); } /** * @brief Initialise an NVT iterator. * * @param[in] iterator Iterator. * @param[in] get GET data. * @param[in] name Name of the info * * @return 0 success, 1 failed to find NVT, 2 failed to find filter, * -1 error. */ int init_nvt_info_iterator (iterator_t* iterator, get_data_t *get, const char *name) { static const char *filter_columns[] = NVT_INFO_ITERATOR_FILTER_COLUMNS; static column_t columns[] = NVT_ITERATOR_COLUMNS; gchar *clause = NULL; int ret; if (get->id) { gchar *quoted = sql_quote (get->id); clause = g_strdup_printf (" AND uuid = '%s'", quoted); g_free (quoted); } else if (name) { gchar *quoted = sql_quote (name); clause = g_strdup_printf (" AND name = '%s'", quoted); g_free (quoted); /* The entry is specified by name, so filtering just gets in the way. */ g_free (get->filter); get->filter = NULL; } ret = init_get_iterator (iterator, "nvt", get, /* Columns. */ columns, /* Columns for trashcan. */ NULL, filter_columns, 0, NULL, clause, 0); g_free (clause); return ret; } /** * @brief Get NVT iterator SELECT columns. * * @return SELECT columns */ static gchar * nvt_iterator_columns () { static column_t select_columns[] = NVT_ITERATOR_COLUMNS; static gchar *columns = NULL; if (columns == NULL) columns = columns_build_select (select_columns); return columns; } /** * @brief Get NVT iterator SELECT columns. * * @return SELECT columns */ static gchar * nvt_iterator_columns_nvts () { static column_t select_columns[] = NVT_ITERATOR_COLUMNS_NVTS; static gchar *columns = NULL; if (columns == NULL) columns = columns_build_select (select_columns); return columns; } /** * @brief Count number of nvt. * * @param[in] get GET params. * * @return Total number of cpes in filtered set. */ int nvt_info_count (const get_data_t *get) { static const char *extra_columns[] = NVT_INFO_ITERATOR_FILTER_COLUMNS; static column_t columns[] = NVT_ITERATOR_COLUMNS; return count ("nvt", get, columns, NULL, extra_columns, 0, 0, 0, FALSE); } /** * @brief Count number of nvts created or modified after a given time. * * @param[in] get GET params. * @param[in] count_time Time NVTs must be created or modified after. * @param[in] get_modified Whether to get the modification time. * * @return Total number of nvts in filtered set. */ int nvt_info_count_after (const get_data_t *get, time_t count_time, gboolean get_modified) { static const char *filter_columns[] = NVT_INFO_ITERATOR_FILTER_COLUMNS; static column_t columns[] = NVT_ITERATOR_COLUMNS; gchar *extra_where; int ret; if (get_modified) extra_where = g_strdup_printf (" AND modification_time > %ld" " AND creation_time <= %ld", count_time, count_time); else extra_where = g_strdup_printf (" AND creation_time > %ld", count_time); ret = count ("nvt", get, columns, NULL, filter_columns, 0, 0, extra_where, FALSE); g_free (extra_where); return ret; } /** * @brief Return SQL for selecting NVT's of a config from one family. * * @param[in] config Config. * @param[in] family Family to limit selection to. * @param[in] ascending Whether to sort ascending or descending. * @param[in] sort_field Field to sort on, or NULL for "nvts.id". * * @return Freshly allocated SELECT statement on success, or NULL on error. */ static gchar * select_config_nvts (const config_t config, const char* family, int ascending, const char* sort_field) { gchar *quoted_selector, *quoted_family, *sql; char *selector; selector = config_nvt_selector (config); if (selector == NULL) /* The config should always have a selector. */ return NULL; quoted_selector = sql_quote (selector); free (selector); quoted_family = sql_quote (family); if (config_nvts_growing (config)) { int constraining; /* The number of NVT's can increase. */ constraining = config_families_growing (config); if (constraining) { /* Constraining the universe. */ if (sql_int ("SELECT COUNT(*) FROM nvt_selectors WHERE name = '%s';", quoted_selector) == 1) /* There is one selector, it should be the all selector. */ sql = g_strdup_printf ("SELECT %s" " FROM nvts WHERE family = '%s'" " ORDER BY %s %s;", nvt_iterator_columns (), quoted_family, sort_field ? sort_field : "name", ascending ? "ASC" : "DESC"); else { /* There are multiple selectors. */ if (sql_int ("SELECT COUNT(*) FROM nvt_selectors" " WHERE name = '%s' AND exclude = 1" " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY) " AND family_or_nvt = '%s'" ";", quoted_selector, quoted_family)) /* The family is excluded, just iterate the NVT includes. */ sql = g_strdup_printf ("SELECT %s" " FROM nvts, nvt_selectors" " WHERE" " nvts.family = '%s'" " AND nvt_selectors.name = '%s'" " AND nvt_selectors.family = '%s'" " AND nvt_selectors.type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT) " AND nvt_selectors.exclude = 0" " AND nvts.oid = nvt_selectors.family_or_nvt" " ORDER BY %s %s;", nvt_iterator_columns_nvts (), quoted_family, quoted_selector, quoted_family, sort_field ? sort_field : "nvts.name", ascending ? "ASC" : "DESC"); else /* The family is included. * * Iterate all NVT's minus excluded NVT's. */ sql = g_strdup_printf ("SELECT %s" " FROM nvts" " WHERE family = '%s'" " EXCEPT" " SELECT %s" " FROM nvt_selectors, nvts" " WHERE" " nvts.family = '%s'" " AND nvt_selectors.name = '%s'" " AND nvt_selectors.family = '%s'" " AND nvt_selectors.type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT) " AND nvt_selectors.exclude = 1" " AND nvts.oid = nvt_selectors.family_or_nvt" " ORDER BY %s %s;", nvt_iterator_columns (), quoted_family, nvt_iterator_columns_nvts (), quoted_family, quoted_selector, quoted_family, /* This works around "ERROR: missing FROM-clause" from * Postgres when using nvts.name. */ sort_field && strcmp (sort_field, "nvts.name") ? sort_field : "3", /* 3 is nvts.name. */ ascending ? "ASC" : "DESC"); } } else { int all; /* Generating from empty. */ all = sql_int ("SELECT COUNT(*) FROM nvt_selectors" " WHERE name = '%s' AND exclude = 0" " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY) " AND family_or_nvt = '%s';", quoted_selector, quoted_family); if (all) /* There is a family include for this family. */ sql = g_strdup_printf ("SELECT %s" " FROM nvts" " WHERE family = '%s'" " EXCEPT" " SELECT %s" " FROM nvt_selectors, nvts" " WHERE" " nvts.family = '%s'" " AND nvt_selectors.name = '%s'" " AND nvt_selectors.family = '%s'" " AND nvt_selectors.type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT) " AND nvt_selectors.exclude = 1" " AND nvts.oid = nvt_selectors.family_or_nvt" " ORDER BY %s %s;", nvt_iterator_columns (), quoted_family, nvt_iterator_columns_nvts (), quoted_family, quoted_selector, quoted_family, /* This works around "ERROR: missing FROM-clause" from * Postgres when using nvts.name. */ sort_field && strcmp (sort_field, "nvts.name") ? sort_field : "3", /* 3 is nvts.name. */ ascending ? "ASC" : "DESC"); else sql = g_strdup_printf (" SELECT %s" " FROM nvt_selectors, nvts" " WHERE" " nvts.family = '%s'" " AND nvt_selectors.name = '%s'" " AND nvt_selectors.family = '%s'" " AND nvt_selectors.type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT) " AND nvt_selectors.exclude = 0" " AND nvts.oid = nvt_selectors.family_or_nvt" " ORDER BY %s %s;", nvt_iterator_columns_nvts (), quoted_family, quoted_selector, quoted_family, sort_field ? sort_field : "nvts.name", ascending ? "ASC" : "DESC"); } } else { /* The number of NVT's is static. Assume a simple list of NVT * includes. */ sql = g_strdup_printf ("SELECT %s" " FROM nvt_selectors, nvts" " WHERE nvts.family = '%s'" " AND nvt_selectors.exclude = 0" " AND nvt_selectors.type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT) " AND nvt_selectors.name = '%s'" " AND nvts.oid = nvt_selectors.family_or_nvt" " ORDER BY %s %s;", nvt_iterator_columns_nvts (), quoted_family, quoted_selector, sort_field ? sort_field : "nvts.id", ascending ? "ASC" : "DESC"); } g_free (quoted_selector); g_free (quoted_family); return sql; } /** * @brief Initialise an NVT iterator. * * @param[in] iterator Iterator. * @param[in] nvt NVT to iterate over, all if 0. * @param[in] config Config to limit selection to. NULL for all NVTs. * Overridden by \arg nvt. * @param[in] family Family to limit selection to. NULL for all NVTs. * Overridden by \arg config. * @param[in] category Category to limit selection to. NULL for all. * @param[in] ascending Whether to sort ascending or descending. * @param[in] sort_field Field to sort on, or NULL for "id". */ void init_nvt_iterator (iterator_t* iterator, nvt_t nvt, config_t config, const char* family, const char *category, int ascending, const char* sort_field) { assert ((nvt && family) == 0); if (nvt) { gchar* sql; sql = g_strdup_printf ("SELECT %s" " FROM nvts WHERE id = %llu;", nvt_iterator_columns (), nvt); init_iterator (iterator, "%s", sql); g_free (sql); } else if (config) { gchar* sql; if (family == NULL) abort (); sql = select_config_nvts (config, family, ascending, sort_field); if (sql) { init_iterator (iterator, "%s", sql); g_free (sql); } else init_iterator (iterator, "SELECT %s" " FROM nvts LIMIT 0;", nvt_iterator_columns ()); } else if (family) { gchar *quoted_family = sql_quote (family); init_iterator (iterator, "SELECT %s" " FROM nvts" " WHERE family = '%s'" " ORDER BY %s %s;", nvt_iterator_columns (), quoted_family, sort_field ? sort_field : "name", ascending ? "ASC" : "DESC"); g_free (quoted_family); } else if (category) { gchar *quoted_category; quoted_category = sql_quote (category); init_iterator (iterator, "SELECT %s" " FROM nvts" " WHERE category = '%s'" " ORDER BY %s %s;", nvt_iterator_columns (), quoted_category, sort_field ? sort_field : "name", ascending ? "ASC" : "DESC"); g_free (quoted_category); } else init_iterator (iterator, "SELECT %s" " FROM nvts" " ORDER BY %s %s;", nvt_iterator_columns (), sort_field ? sort_field : "name", ascending ? "ASC" : "DESC"); } /** * @brief Initialise an NVT iterator, for NVTs of a certain CVE. * * @param[in] iterator Iterator. * @param[in] cve CVE name. * @param[in] ascending Whether to sort ascending or descending. * @param[in] sort_field Field to sort on, or NULL for "id". */ void init_cve_nvt_iterator (iterator_t* iterator, const char *cve, int ascending, const char* sort_field) { init_iterator (iterator, "SELECT %s" " FROM nvts" " WHERE cve %s '%%%s, %%'" " OR cve %s '%%%s'" " ORDER BY %s %s;", nvt_iterator_columns (), sql_ilike_op (), cve ? cve : "", sql_ilike_op (), cve ? cve : "", sort_field ? sort_field : "name", ascending ? "ASC" : "DESC"); } /** * @brief Get the OID from an NVT iterator. * * @param[in] iterator Iterator. * * @return OID, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_oid, GET_ITERATOR_COLUMN_COUNT); /** * @brief Get the name from an NVT iterator. * * @param[in] iterator Iterator. * * @return Name, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_name, GET_ITERATOR_COLUMN_COUNT + 2); /** * @brief Get the tag from an NVT iterator. * * @param[in] iterator Iterator. * * @return Tag, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_tag, GET_ITERATOR_COLUMN_COUNT + 4); /** * @brief Get the category from an NVT iterator. * * @param[in] iterator Iterator. * * @return Category. */ int nvt_iterator_category (iterator_t* iterator) { int ret; if (iterator->done) return -1; ret = iterator_int (iterator, GET_ITERATOR_COLUMN_COUNT + 5); return ret; } /** * @brief Get the family from an NVT iterator. * * @param[in] iterator Iterator. * * @return Family, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_family, GET_ITERATOR_COLUMN_COUNT + 6); /** * @brief Get the cvss_base from an NVT iterator. * * @param[in] iterator Iterator. * * @return Cvss_base, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_cvss_base, GET_ITERATOR_COLUMN_COUNT + 7); /** * @brief Get the qod from an NVT iterator. * * @param[in] iterator Iterator. * * @return QoD, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_qod, GET_ITERATOR_COLUMN_COUNT + 10); /** * @brief Get the qod_type from an NVT iterator. * * @param[in] iterator Iterator. * * @return QoD type, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_qod_type, GET_ITERATOR_COLUMN_COUNT + 11); /** * @brief Get the solution_type from an NVT iterator. * * @param[in] iterator Iterator. * * @return Solution Type, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_solution_type, GET_ITERATOR_COLUMN_COUNT + 12); /** * @brief Get the solution from an NVT iterator. * * @param[in] iterator Iterator. * * @return Solution, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_solution, GET_ITERATOR_COLUMN_COUNT + 14); /** * @brief Get the summary from an NVT iterator. * * @param[in] iterator Iterator. * * @return Summary, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_summary, GET_ITERATOR_COLUMN_COUNT + 15); /** * @brief Get the insight from an NVT iterator. * * @param[in] iterator Iterator. * * @return Insight, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_insight, GET_ITERATOR_COLUMN_COUNT + 16); /** * @brief Get the affected from an NVT iterator. * * @param[in] iterator Iterator. * * @return Affected, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_affected, GET_ITERATOR_COLUMN_COUNT + 17); /** * @brief Get the impact from an NVT iterator. * * @param[in] iterator Iterator. * * @return Impact, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_impact, GET_ITERATOR_COLUMN_COUNT + 18); /** * @brief Get the detection from an NVT iterator. * * @param[in] iterator Iterator. * * @return Detection, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_detection, GET_ITERATOR_COLUMN_COUNT + 19); /** * @brief Get the solution method from an NVT iterator. * * @param[in] iterator Iterator. * * @return Solution method, or NULL if iteration is complete. Freed by * cleanup_iterator. */ DEF_ACCESS (nvt_iterator_solution_method, GET_ITERATOR_COLUMN_COUNT + 20); /** * @brief Get the default timeout of an NVT. * * @param[in] oid The OID of the NVT to get the timeout of. * * @return Newly allocated string of the timeout in seconds or NULL. */ char * nvt_default_timeout (const char* oid) { return sql_string ("SELECT value FROM nvt_preferences" " WHERE name = '%s:0:entry:Timeout'", oid); } /** * @brief Get the family of an NVT. * * @param[in] oid The OID of the NVT. * * @return Newly allocated string of the family, or NULL. */ char * nvt_family (const char *oid) { gchar *quoted_oid; char *ret; quoted_oid = sql_quote (oid); ret = sql_string ("SELECT family FROM nvts WHERE oid = '%s' LIMIT 1;", quoted_oid); g_free (quoted_oid); return ret; } /** * @brief Get the number of NVTs in one or all families. * * @param[in] family Family name. NULL for all families. * * @return Number of NVTs in family, or total number of nvts. */ int family_nvt_count (const char *family) { gchar *quoted_family; if (family == NULL) { static int nvt_count = -1; if (nvt_count == -1) nvt_count = sql_int ("SELECT COUNT(*) FROM nvts" " WHERE family != 'Credentials';"); return nvt_count; } quoted_family = sql_quote (family); int ret = sql_int ("SELECT COUNT(*) FROM nvts WHERE family = '%s';", quoted_family); g_free (quoted_family); return ret; } /** * @brief Get the number of families. * * @return Total number of families. */ int family_count () { return sql_int ("SELECT COUNT(distinct family) FROM nvts" " WHERE family != 'Credentials';"); } /** * @brief Insert a NVT preferences. * * @param[in] nvt_preference Preference. * @param[in] dummy Dummy arg for g_list_foreach. * */ static void insert_nvt_preference (gpointer nvt_preference, gpointer dummy) { preference_t *preference; if (nvt_preference == NULL) return; preference = (preference_t*) nvt_preference; manage_nvt_preference_add (preference->name, preference->value); } /** * @brief Inserts NVT preferences in DB from a list of nvt_preference_t structures. * * @param[in] nvt_preferences_list List of nvts to be inserted. */ static void insert_nvt_preferences_list (GList *nvt_preferences_list) { g_list_foreach (nvt_preferences_list, insert_nvt_preference, NULL); } /** * @brief Set the NVT update check time in the meta table. * * @param[in] count_new Number of new VTs with current update. * @param[in] count_modified Number of modified VTs with current update. */ static void set_nvts_check_time (int count_new, int count_modified) { if (sql_int ("SELECT NOT EXISTS (SELECT * FROM meta" " WHERE name = 'nvts_check_time')")) sql ("INSERT INTO meta (name, value)" " VALUES ('nvts_check_time', m_now ());"); else if (sql_int ("SELECT value = '0' FROM meta" " WHERE name = 'nvts_check_time';")) sql ("UPDATE meta SET value = m_now ()" " WHERE name = 'nvts_check_time';"); else { if (count_new > 0) event (EVENT_NEW_SECINFO, "nvt", 0, 0); if (count_modified > 0) event (EVENT_UPDATED_SECINFO, "nvt", 0, 0); sql ("UPDATE meta SET value = m_now ()" " WHERE name = 'nvts_check_time';"); } } /** * @brief Update NVT from VT XML. * * @param[in] vt OSP GET_VTS VT element. * @param[in] oid OID of NVT. * @param[in] preferences All NVT preferences. * * @return 0 success, -1 error. */ static int update_preferences_from_vt (entity_t vt, const gchar *oid, GList **preferences) { entity_t params, param; entities_t children; assert (preferences); params = entity_child (vt, "params"); if (params == NULL) return 0; children = params->entities; while ((param = first_entity (children))) { if (strcasecmp (entity_name (param), "param") == 0) { const gchar *type, *id; entity_t name, def; type = entity_attribute (param, "type"); id = entity_attribute (param, "id"); name = entity_child (param, "name"); def = entity_child (param, "default"); if (type == NULL) { GString *debug = g_string_new (""); g_warning ("%s: PARAM missing type attribute", __func__); print_entity_to_string (param, debug); g_warning ("%s: PARAM: %s", __func__, debug->str); g_string_free (debug, TRUE); } else if (id == NULL) { GString *debug = g_string_new (""); g_warning ("%s: PARAM missing id attribute", __func__); print_entity_to_string (param, debug); g_warning ("%s: PARAM: %s", __func__, debug->str); g_string_free (debug, TRUE); } else if (name == NULL) { GString *debug = g_string_new (""); g_warning ("%s: PARAM missing NAME", __func__); print_entity_to_string (param, debug); g_warning ("%s: PARAM: %s", __func__, debug->str); g_string_free (debug, TRUE); } else { gchar *full_name; preference_t *preference; full_name = g_strdup_printf ("%s:%s:%s:%s", oid, id, type, entity_text (name)); blank_control_chars (full_name); preference = g_malloc0 (sizeof (preference_t)); preference->name = full_name; if (def) preference->value = g_strdup (entity_text (def)); else preference->value = g_strdup (""); *preferences = g_list_prepend (*preferences, preference); } } children = next_entities (children); } return 0; } /** * @brief Create NVTI structure from VT XML. * * @param[in] vt OSP GET_VTS VT element. * * @return The NVTI object on success (needs to be free'd), NULL on error. */ static nvti_t * nvti_from_vt (entity_t vt) { nvti_t *nvti = nvti_new (); const char *id; entity_t name, summary, insight, affected, impact, detection, solution; entity_t creation_time, modification_time; entity_t refs, ref, custom, family, category, deprecated; entity_t severities, severity; entities_t children; id = entity_attribute (vt, "id"); if (id == NULL) { g_warning ("%s: VT missing id attribute", __func__); nvti_free (nvti); return NULL; } nvti_set_oid (nvti, id); name = entity_child (vt, "name"); if (name == NULL) { g_warning ("%s: VT missing NAME", __func__); nvti_free (nvti); return NULL; } nvti_set_name (nvti, entity_text (name)); summary = entity_child (vt, "summary"); if (summary) nvti_set_summary (nvti, entity_text (summary)); insight = entity_child (vt, "insight"); if (insight) nvti_set_insight (nvti, entity_text (insight)); affected = entity_child (vt, "affected"); if (affected) nvti_set_affected (nvti, entity_text (affected)); impact = entity_child (vt, "impact"); if (impact) nvti_set_impact (nvti, entity_text (impact)); creation_time = entity_child (vt, "creation_time"); if (creation_time) nvti_set_creation_time (nvti, strtol (entity_text (creation_time), NULL, 10)); modification_time = entity_child (vt, "modification_time"); if (modification_time) nvti_set_modification_time (nvti, strtol (entity_text (modification_time), NULL, 10)); detection = entity_child (vt, "detection"); if (detection) { const gchar *qod; nvti_set_detection (nvti, entity_text (detection)); qod = entity_attribute (detection, "qod"); if (qod == NULL) nvti_set_qod_type (nvti, entity_attribute (detection, "qod_type")); else nvti_set_qod (nvti, qod); } solution = entity_child (vt, "solution"); if (solution) { const gchar *type, *method; nvti_set_solution (nvti, entity_text (solution)); type = entity_attribute (solution, "type"); if (type == NULL) g_debug ("%s: SOLUTION missing type", __func__); else nvti_set_solution_type (nvti, type); method = entity_attribute (solution, "method"); if (method) nvti_set_solution_method (nvti, method); } severities = entity_child (vt, "severities"); if (severities == NULL) { g_warning ("%s: VT missing SEVERITIES", __func__); nvti_free (nvti); return NULL; } children = severities->entities; while ((severity = first_entity (children))) { const gchar *severity_type; severity_type = entity_attribute (severity, "type"); if (severity_type == NULL) { GString *debug = g_string_new (""); g_warning ("%s: SEVERITY missing type attribute", __func__); print_entity_to_string (severity, debug); g_warning ("%s: severity: %s", __func__, debug->str); g_string_free (debug, TRUE); } else { entity_t value; value = entity_child (severity, "value"); if (!value) { GString *debug = g_string_new (""); g_warning ("%s: SEVERITY missing value element", __func__); print_entity_to_string (severity, debug); g_warning ("%s: severity: %s", __func__, debug->str); g_string_free (debug, TRUE); } else { entity_t origin, severity_date; double cvss_base_dbl; gchar * cvss_base; time_t parsed_severity_date; cvss_base_dbl = get_cvss_score_from_base_metrics (entity_text (value)); origin = entity_child (severity, "origin"); severity_date = entity_child (severity, "date"); if (severity_date) parsed_severity_date = strtol (entity_text (severity_date), NULL, 10); else parsed_severity_date = nvti_creation_time (nvti); nvti_add_vtseverity (nvti, vtseverity_new (severity_type, origin ? entity_text (origin) : NULL, parsed_severity_date, cvss_base_dbl, entity_text (value))); nvti_add_tag (nvti, "cvss_base_vector", entity_text (value)); cvss_base = g_strdup_printf ("%.1f", get_cvss_score_from_base_metrics (entity_text (value))); nvti_set_cvss_base (nvti, cvss_base); g_free (cvss_base); } } children = next_entities (children); } refs = entity_child (vt, "refs"); if (refs) { children = refs->entities; while ((ref = first_entity (children))) { const gchar *ref_type; ref_type = entity_attribute (ref, "type"); if (ref_type == NULL) { GString *debug = g_string_new (""); g_warning ("%s: REF missing type attribute", __func__); print_entity_to_string (ref, debug); g_warning ("%s: ref: %s", __func__, debug->str); g_string_free (debug, TRUE); } else { const gchar *ref_id; ref_id = entity_attribute (ref, "id"); if (ref_id == NULL) { GString *debug = g_string_new (""); g_warning ("%s: REF missing id attribute", __func__); print_entity_to_string (ref, debug); g_warning ("%s: ref: %s", __func__, debug->str); g_string_free (debug, TRUE); } else { nvti_add_vtref (nvti, vtref_new (ref_type, ref_id, NULL)); } } children = next_entities (children); } } custom = entity_child (vt, "custom"); if (custom == NULL) { g_warning ("%s: VT missing CUSTOM", __func__); nvti_free (nvti); return NULL; } family = entity_child (custom, "family"); if (family == NULL) { g_warning ("%s: VT/CUSTOM missing FAMILY", __func__); nvti_free (nvti); return NULL; } nvti_set_family (nvti, entity_text (family)); category = entity_child (custom, "category"); if (category == NULL) { g_warning ("%s: VT/CUSTOM missing CATEGORY", __func__); nvti_free (nvti); return NULL; } nvti_set_category (nvti, atoi (entity_text (category))); deprecated = entity_child (custom, "deprecated"); if (deprecated) { nvti_add_tag (nvti, "deprecated", entity_text (deprecated)); } return nvti; } /** * @brief Update NVTs from VTs XML. * * @param[in] get_vts_response OSP GET_VTS response. * @param[in] scanner_feed_version Version of feed from scanner. * * @return 0 success, 1 VT integrity check failed, -1 error */ static int update_nvts_from_vts (entity_t *get_vts_response, const gchar *scanner_feed_version) { entity_t vts, vt; entities_t children; GList *preferences; int count_modified_vts, count_new_vts; time_t feed_version_epoch; const char *osp_vt_hash; count_modified_vts = 0; count_new_vts = 0; feed_version_epoch = nvts_feed_version_epoch(); vts = entity_child (*get_vts_response, "vts"); if (vts == NULL) { g_warning ("%s: VTS missing", __func__); return -1; } osp_vt_hash = entity_attribute (vts, "sha256_hash"); sql_begin_immediate (); if (sql_int ("SELECT coalesce ((SELECT CAST (value AS INTEGER)" " FROM meta" " WHERE name = 'checked_preferences')," " 0);") == 0) /* We're in the first NVT sync after migrating preference names. * * If a preference was removed from an NVT then the preference will be in * nvt_preferences in the old format, but we will not get a new version * of the preference name from the sync. For example "Alle Dateien * Auflisten" was removed from 1.3.6.1.4.1.25623.1.0.94023. * * If a preference was not in the migrator then the new version of the * preference would be inserted alongside the old version, resulting in a * duplicate when the name of the old version was corrected. * * To solve both cases, we remove all nvt_preferences. */ sql ("TRUNCATE nvt_preferences;"); children = vts->entities; while ((vt = first_entity (children))) { nvti_t *nvti = nvti_from_vt (vt); if (nvti == NULL) continue; if (nvti_creation_time (nvti) > feed_version_epoch) count_new_vts += 1; else count_modified_vts += 1; insert_nvt (nvti); preferences = NULL; if (update_preferences_from_vt (vt, nvti_oid (nvti), &preferences)) { sql_rollback (); return -1; } sql ("DELETE FROM nvt_preferences WHERE name LIKE '%s:%%';", nvti_oid (nvti)); insert_nvt_preferences_list (preferences); g_list_free_full (preferences, g_free); nvti_free (nvti); children = next_entities (children); } set_nvts_check_time (count_new_vts, count_modified_vts); set_nvts_feed_version (scanner_feed_version); if (check_config_families ()) g_warning ("%s: Error updating config families." " One or more configs refer to an outdated family of an NVT.", __func__); update_all_config_caches (); g_info ("Updating VTs in database ... %i new VTs, %i changed VTs", count_new_vts, count_modified_vts); sql_commit (); if (osp_vt_hash && strcmp (osp_vt_hash, "")) { char *db_vts_hash; /* * The hashed string used for verifying the NVTs generated as follows: * * For each NVT, sorted by OID, concatenate: * - the OID * - the modification time as seconds since epoch * - the preferences sorted as strings(!) and concatenated including: * - the id * - the name * - the default value (including choices for the "radio" type) * * All values are concatenated without a separator. */ db_vts_hash = sql_string ("SELECT encode (" " digest (vts_verification_str (), 'SHA256')," " 'hex'" " );"); if (strcmp (osp_vt_hash, db_vts_hash ? db_vts_hash : "")) { g_warning ("%s: SHA-256 hash of the VTs in the database (%s)" " does not match the one from the scanner (%s).", __func__, db_vts_hash, osp_vt_hash); g_free (db_vts_hash); return 1; } g_free (db_vts_hash); } else g_warning ("%s: No SHA-256 hash received from scanner, skipping check.", __func__); return 0; } /** * @brief Check that preference names are in the new format. * * @param[in] table Table name. */ static void check_old_preference_names (const gchar *table) { /* 1.3.6.1.4.1.25623.1.0.14259:checkbox:Log nmap output * => * 1.3.6.1.4.1.25623.1.0.14259:21:checkbox:Log nmap output */ sql ("UPDATE %s" " SET name = nvt_preferences.name" " FROM nvt_preferences" " WHERE %s.name ~ '.*:.*:.*'" " AND nvt_preferences.name ~ '.*:.*:.*:.*'" " AND %s.name = regexp_replace (nvt_preferences.name," " E'([^:]+):[^:]+:(.*)', '\\1:\\2');", table, table, table, table); } /** * @brief Update config preferences where the name has changed in the NVTs. * * @param[in] trash Whether to update the trash table. * @param[in] modification_time Time NVTs considered must be modified after. */ static void check_preference_names (int trash, time_t modification_time) { iterator_t prefs; sql_begin_immediate (); init_iterator (&prefs, "WITH new_pref_matches AS" " (SELECT substring (nvt_preferences.name," " '^([^:]*:[^:]*)') || ':%%' AS match," " name AS new_name" " FROM nvt_preferences" " WHERE substr (name, 0, position (':' IN name))" " IN (SELECT oid FROM nvts" " WHERE modification_time > %ld))" " SELECT c_prefs.id, c_prefs.name as old_name, new_name," " configs%s.uuid AS config_id" " FROM config_preferences%s AS c_prefs" " JOIN new_pref_matches" " ON c_prefs.name LIKE new_pref_matches.match" " JOIN configs%s ON configs%s.id = c_prefs.config" " WHERE c_prefs.name != new_name;", modification_time, trash ? "_trash" : "", trash ? "_trash" : "", trash ? "_trash" : "", trash ? "_trash" : ""); while (next (&prefs)) { resource_t preference; const char *old_name, *new_name, *config_id; gchar *quoted_new_name; preference = iterator_int64 (&prefs, 0); old_name = iterator_string (&prefs, 1); new_name = iterator_string (&prefs, 2); config_id = iterator_string (&prefs, 3); g_message ("Preference '%s' of %sconfig %s changed to '%s'", old_name, trash ? "trash " : "", config_id, new_name); quoted_new_name = sql_quote (new_name); sql ("UPDATE config_preferences%s" " SET name = '%s'" " WHERE id = %llu", trash ? "_trash " : "", quoted_new_name, preference); g_free (quoted_new_name); } sql_commit (); cleanup_iterator (&prefs); } /** * @brief Initialise an NVT severity iterator. * * @param[in] iterator Iterator. * @param[in] oid OID of NVT. */ void init_nvt_severity_iterator (iterator_t* iterator, const char *oid) { gchar *quoted_oid; quoted_oid = sql_quote (oid ? oid : ""); init_iterator (iterator, "SELECT type, origin, iso_time(date), score, value" " FROM vt_severities" " WHERE vt_oid = '%s'", quoted_oid); g_free (quoted_oid); } /** * @brief Gets the type from an NVT severity iterator. * * @param[in] iterator Iterator. * * @return The type of the severity. */ DEF_ACCESS (nvt_severity_iterator_type, 0) /** * @brief Gets the origin from an NVT severity iterator. * * @param[in] iterator Iterator. * * @return The origin of the severity. */ DEF_ACCESS (nvt_severity_iterator_origin, 1); /** * @brief Gets the date from an NVT severity iterator. * * @param[in] iterator Iterator. * * @return The date of the severity in ISO time format. */ DEF_ACCESS (nvt_severity_iterator_date, 2); /** * @brief Gets the score from an NVT severity iterator. * * @param[in] iterator Iterator. * * @return The score of the severity. */ double nvt_severity_iterator_score (iterator_t *iterator) { return iterator_double (iterator, 3); } /** * @brief Gets the value from an NVT severity iterator. * * @param[in] iterator Iterator. * * @return The value of the severity in ISO time format. */ DEF_ACCESS (nvt_severity_iterator_value, 4); /** * @brief Update VTs via OSP. * * @param[in] update_socket Socket to use to contact scanner. * @param[in] db_feed_version Feed version from meta table. * @param[in] scanner_feed_version Feed version from scanner. * * @return 0 success, 1 VT integrity check failed, -1 error. */ static int update_nvt_cache_osp (const gchar *update_socket, gchar *db_feed_version, gchar *scanner_feed_version) { osp_connection_t *connection; GSList *scanner_prefs; entity_t vts; osp_get_vts_opts_t get_vts_opts; time_t old_nvts_last_modified; int ret; if (db_feed_version == NULL || strcmp (db_feed_version, "") == 0 || strcmp (db_feed_version, "0") == 0) old_nvts_last_modified = 0; else old_nvts_last_modified = (time_t) sql_int64_0 ("SELECT max(modification_time) FROM nvts"); connection = osp_connection_new (update_socket, 0, NULL, NULL, NULL); if (!connection) { g_warning ("%s: failed to connect to %s (2)", __func__, update_socket); return -1; } get_vts_opts = osp_get_vts_opts_default; if (db_feed_version) get_vts_opts.filter = g_strdup_printf ("modification_time>%s", db_feed_version); else get_vts_opts.filter = NULL; if (osp_get_vts_ext (connection, get_vts_opts, &vts)) { g_warning ("%s: failed to get VTs", __func__); g_free (get_vts_opts.filter); return -1; } g_free (get_vts_opts.filter); osp_connection_close (connection); ret = update_nvts_from_vts (&vts, scanner_feed_version); free_entity (vts); if (ret) return ret; /* Update scanner preferences */ connection = osp_connection_new (update_socket, 0, NULL, NULL, NULL); if (!connection) { g_warning ("%s: failed to connect to %s (3)", __func__, update_socket); return -1; } scanner_prefs = NULL; if (osp_get_scanner_details (connection, NULL, &scanner_prefs)) { g_warning ("%s: failed to get scanner preferences", __func__); osp_connection_close (connection); return -1; } else { GString *prefs_sql; GSList *point; int first; point = scanner_prefs; first = 1; osp_connection_close (connection); prefs_sql = g_string_new ("INSERT INTO nvt_preferences (name, value)" " VALUES"); while (point) { osp_param_t *param; gchar *quoted_name, *quoted_value; param = point->data; quoted_name = sql_quote (osp_param_id (param)); quoted_value = sql_quote (osp_param_default (param)); g_string_append_printf (prefs_sql, "%s ('%s', '%s')", first ? "" : ",", quoted_name, quoted_value); first = 0; point = g_slist_next (point); g_free (quoted_name); g_free (quoted_value); } g_string_append (prefs_sql, " ON CONFLICT (name)" " DO UPDATE SET value = EXCLUDED.value;"); if (first == 0) { sql ("%s", prefs_sql->str); } g_string_free (prefs_sql, TRUE); } /* Update the cache of report counts. */ reports_clear_count_cache_dynamic (); /* Tell the main process to update its NVTi cache. */ sql ("UPDATE %s.meta SET value = 1 WHERE name = 'update_nvti_cache';", sql_schema ()); g_info ("Updating VTs in database ... done (%i VTs).", sql_int ("SELECT count (*) FROM nvts;")); if (sql_int ("SELECT coalesce ((SELECT CAST (value AS INTEGER)" " FROM meta" " WHERE name = 'checked_preferences')," " 0);") == 0) { check_old_preference_names ("config_preferences"); check_old_preference_names ("config_preferences_trash"); /* Force update of names in new format in case hard-coded names * used by migrators are outdated */ old_nvts_last_modified = 0; sql ("INSERT INTO meta (name, value)" " VALUES ('checked_preferences', 1)" " ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value;"); } check_preference_names (0, old_nvts_last_modified); check_preference_names (1, old_nvts_last_modified); check_whole_only_in_configs (); return 0; } /** * @brief Get the VTs feed version from an OSP scanner. * * @param[in] update_socket Socket to use to contact ospd-openvas scanner. * * @return The feed version or NULL on error. */ static char * osp_scanner_feed_version (const gchar *update_socket) { osp_connection_t *connection; gchar *error; gchar *scanner_feed_version; scanner_feed_version = NULL; connection = osp_connection_new (update_socket, 0, NULL, NULL, NULL); if (!connection) { g_debug ("%s: failed to connect to %s", __func__, update_socket); return NULL; } error = NULL; if (osp_get_vts_version (connection, &scanner_feed_version, &error)) { g_debug ("%s: failed to get scanner_feed_version. %s", __func__, error ? : ""); g_free (error); osp_connection_close (connection); return NULL; } osp_connection_close (connection); return scanner_feed_version; } /** * @brief Check VTs feed version status via OSP, optionally get versions. * * @param[in] update_socket Socket to use to contact ospd-openvas scanner. * @param[out] db_feed_version_out Output of database feed version. * @param[out] scanner_feed_version_out Output of scanner feed version. * * @return 0 VTs feed current, -1 error, 1 VT update needed. */ static int nvts_feed_version_status_internal (const gchar *update_socket, gchar **db_feed_version_out, gchar **scanner_feed_version_out) { gchar *db_feed_version, *scanner_feed_version; if (db_feed_version_out) *db_feed_version_out = NULL; if (scanner_feed_version_out) *scanner_feed_version_out = NULL; db_feed_version = nvts_feed_version (); g_debug ("%s: db_feed_version: %s", __func__, db_feed_version); if (db_feed_version_out && db_feed_version) *db_feed_version_out = g_strdup (db_feed_version); scanner_feed_version = osp_scanner_feed_version (update_socket); g_debug ("%s: scanner_feed_version: %s", __func__, scanner_feed_version); if (scanner_feed_version == NULL) return -1; if (scanner_feed_version_out && scanner_feed_version) *scanner_feed_version_out = g_strdup (scanner_feed_version); if ((db_feed_version == NULL) || strcmp (scanner_feed_version, db_feed_version)) { g_free (db_feed_version); g_free (scanner_feed_version); return 1; } return 0; } /** * @brief Check VTs feed version status * * @return 0 VTs feed current, 1 VT update needed, -1 error. */ int nvts_feed_version_status () { return nvts_feed_version_status_internal (get_osp_vt_update_socket (), NULL, NULL); } /** * @brief Update VTs via OSP. * * Expect to be called in the child after a fork. * * @param[in] update_socket Socket to use to contact ospd-openvas scanner. * * @return 0 success, -1 error, 1 VT integrity check failed. */ int manage_update_nvt_cache_osp (const gchar *update_socket) { gchar *db_feed_version, *scanner_feed_version; int ret; /* Re-open DB after fork. */ reinit_manage_process (); manage_session_init (current_credentials.uuid); /* Try update VTs. */ ret = nvts_feed_version_status_internal (update_socket, &db_feed_version, &scanner_feed_version); if (ret == 1) { g_info ("OSP service has different VT status (version %s)" " from database (version %s, %i VTs). Starting update ...", scanner_feed_version, db_feed_version, sql_int ("SELECT count (*) FROM nvts;")); ret = update_nvt_cache_osp (update_socket, db_feed_version, scanner_feed_version); g_free (db_feed_version); g_free (scanner_feed_version); return ret; } return ret; } /** * @brief Sync NVTs if newer NVTs are available. * * @param[in] fork_update_nvt_cache Function to do the update. */ void manage_sync_nvts (int (*fork_update_nvt_cache) ()) { fork_update_nvt_cache (); } /** * @brief Update or rebuild NVT db. * * Caller must get the lock. * * @param[in] update 0 rebuild, else update. * * @return 0 success, -1 error, -4 no osp update socket. */ int update_or_rebuild_nvts (int update) { const char *osp_update_socket; gchar *db_feed_version, *scanner_feed_version; osp_connection_t *connection; int ret; gchar *error; if (check_osp_vt_update_socket ()) { printf ("No OSP VT update socket found." " Use --osp-vt-update or change the 'OpenVAS Default'" " scanner to use the main ospd-openvas socket.\n"); return -4; } osp_update_socket = get_osp_vt_update_socket (); if (osp_update_socket == NULL) { printf ("No OSP VT update socket set.\n"); return -4; } db_feed_version = nvts_feed_version (); g_debug ("%s: db_feed_version: %s", __func__, db_feed_version); connection = osp_connection_new (osp_update_socket, 0, NULL, NULL, NULL); if (!connection) { printf ("Failed to connect to %s.\n", osp_update_socket); return -1; } error = NULL; if (osp_get_vts_version (connection, &scanner_feed_version, &error)) { printf ("Failed to get scanner_version. %s\n", error ? : ""); g_free (error); return -1; } g_debug ("%s: scanner_feed_version: %s", __func__, scanner_feed_version); osp_connection_close (connection); if (update == 0) { sql ("TRUNCATE nvts;"); sql ("TRUNCATE nvt_preferences;"); set_nvts_feed_version ("0"); } ret = update_nvt_cache_osp (osp_update_socket, NULL, scanner_feed_version); if (ret) { return -1; } return 0; } /** * @brief Rebuild NVT db. * * @param[in] log_config Log configuration. * @param[in] database Location of manage database. * * @return 0 success, 1 VT integrity check failed, -1 error, * -2 database is wrong version, * -3 database needs to be initialised from server, -5 sync active. */ int manage_rebuild (GSList *log_config, const db_conn_info_t *database) { int ret; static lockfile_t lockfile; g_info (" Rebuilding NVTs."); switch (feed_lockfile_lock_timeout (&lockfile)) { case 1: printf ("A feed sync is already running.\n"); return -5; case -1: printf ("Error getting sync lock.\n"); return -1; } ret = manage_option_setup (log_config, database); if (ret) { feed_lockfile_unlock (&lockfile); return ret; } sql_begin_immediate (); ret = update_or_rebuild_nvts (0); if (ret) sql_rollback (); else sql_commit (); feed_lockfile_unlock (&lockfile); manage_option_cleanup (); return ret; } /** * @brief Dump the string used to calculate the VTs verification hash * to stdout. * * @param[in] log_config Log configuration. * @param[in] database Location of manage database. * * @return 0 success, -1 error, -2 database is wrong version, * -3 database needs to be initialised from server, -5 sync active. */ int manage_dump_vt_verification (GSList *log_config, const db_conn_info_t *database) { int ret; static lockfile_t lockfile; char *verification_str; switch (feed_lockfile_lock_timeout (&lockfile)) { case 1: printf ("A feed sync is already running.\n"); return -5; case -1: printf ("Error getting sync lock.\n"); return -1; } ret = manage_option_setup (log_config, database); if (ret) { feed_lockfile_unlock (&lockfile); return ret; } verification_str = sql_string ("SELECT vts_verification_str ();"); printf ("%s\n", verification_str); feed_lockfile_unlock (&lockfile); manage_option_cleanup (); return 0; }