diff --git a/CMakeLists.txt b/CMakeLists.txt index dbcd70aa0..9c810c609 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -113,7 +113,7 @@ include (CPack) ## Variables -set (GVMD_DATABASE_VERSION 215) +set (GVMD_DATABASE_VERSION 216) set (GVMD_SCAP_DATABASE_VERSION 15) diff --git a/src/gmp.c b/src/gmp.c index 0c3b35a99..d199c4928 100644 --- a/src/gmp.c +++ b/src/gmp.c @@ -10170,10 +10170,30 @@ results_xml_append_nvt (iterator_t *results, GString *buffer, int cert_loaded) else { const char *cvss_base = result_iterator_nvt_cvss_base (results); + GString *tags = g_string_new (result_iterator_nvt_tag (results)); if (!cvss_base && !strcmp (oid, "0")) cvss_base = "0.0"; + /* Add the elements that are expected as part of the pipe-separated tag list + * via API although internally already explicitely stored. Once the API is + * extended to have these elements explicitely, they do not need to be + * added to this string anymore. */ + if (result_iterator_nvt_solution (results)) + { + if (tags->str) + g_string_append_printf (tags, "|solution=%s", result_iterator_nvt_solution (results)); + else + g_string_append_printf (tags, "solution=%s", result_iterator_nvt_solution (results)); + } + if (result_iterator_nvt_solution_type (results)) + { + if (tags->str) + g_string_append_printf (tags, "|solution_type=%s", result_iterator_nvt_solution_type (results)); + else + g_string_append_printf (tags, "solution_type=%s", result_iterator_nvt_solution_type (results)); + } + buffer_xml_append_printf (buffer, "" "nvt" @@ -10185,7 +10205,7 @@ results_xml_append_nvt (iterator_t *results, GString *buffer, int cert_loaded) result_iterator_nvt_name (results) ?: oid, result_iterator_nvt_family (results) ?: "", cvss_base ?: "", - result_iterator_nvt_tag (results) ?: ""); + tags->str ?: ""); buffer_xml_append_printf (buffer, ""); result_iterator_nvt_refs_append (buffer, results); @@ -10193,6 +10213,8 @@ results_xml_append_nvt (iterator_t *results, GString *buffer, int cert_loaded) result_iterator_has_cert_bunds (results), result_iterator_has_dfn_certs (results)); buffer_xml_append_printf (buffer, ""); + + g_string_free (tags, TRUE); } } diff --git a/src/manage.c b/src/manage.c index b699f8156..c844d16b8 100644 --- a/src/manage.c +++ b/src/manage.c @@ -7374,7 +7374,7 @@ get_nvti_xml (iterator_t *nvts, int details, int pref_count, if (details) { int tag_count; - GString *refs_str, *tags_str, *buffer; + GString *refs_str, *tags_str, *buffer, *nvt_tags; iterator_t cert_refs_iterator, tags; gchar *tag_name_esc, *tag_value_esc, *tag_comment_esc; char *default_timeout = nvt_default_timeout (oid); @@ -7384,6 +7384,28 @@ get_nvti_xml (iterator_t *nvts, int details, int pref_count, #undef DEF + nvt_tags = g_string_new (tag_text); + g_free (tag_text); + + /* Add the elements that are expected as part of the pipe-separated tag list + * via API although internally already explicitely stored. Once the API is + * extended to have these elements explicitely, they do not need to be + * added to this string anymore. */ + if (nvt_iterator_solution (nvts)) + { + if (nvt_tags->str) + g_string_append_printf (nvt_tags, "|solution=%s", nvt_iterator_solution (nvts)); + else + g_string_append_printf (nvt_tags, "solution=%s", result_iterator_nvt_solution (nvts)); + } + if (nvt_iterator_solution_type (nvts)) + { + if (nvt_tags->str) + g_string_append_printf (nvt_tags, "|solution_type=%s", nvt_iterator_solution_type (nvts)); + else + g_string_append_printf (nvt_tags, "solution_type=%s", nvt_iterator_solution_type (nvts)); + } + refs_str = g_string_new (""); if (manage_cert_loaded()) @@ -7495,12 +7517,12 @@ get_nvti_xml (iterator_t *nvts, int details, int pref_count, nvt_iterator_qod (nvts), nvt_iterator_qod_type (nvts), refs_str->str, - tag_text, + nvt_tags->str, pref_count, timeout ? timeout : "", default_timeout ? default_timeout : ""); g_free (family_text); - g_free (tag_text); + g_string_free(nvt_tags, 1); g_string_free(refs_str, 1); g_string_free(tags_str, 1); diff --git a/src/manage.h b/src/manage.h index 4086e209f..885b1cbd1 100644 --- a/src/manage.h +++ b/src/manage.h @@ -1444,6 +1444,12 @@ result_iterator_nvt_oid (iterator_t*); const char* result_iterator_nvt_name (iterator_t *); +const char* +result_iterator_nvt_solution (iterator_t *); + +const char* +result_iterator_nvt_solution_type (iterator_t *); + const char* result_iterator_nvt_family (iterator_t *); @@ -2008,6 +2014,9 @@ nvt_iterator_qod (iterator_t*); const char* nvt_iterator_qod_type ( iterator_t *iterator ); +const char* +nvt_iterator_solution (iterator_t*); + const char* nvt_iterator_solution_type (iterator_t*); diff --git a/src/manage_migrators.c b/src/manage_migrators.c index 870778a46..31483c2af 100644 --- a/src/manage_migrators.c +++ b/src/manage_migrators.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2013-2018 Greenbone Networks GmbH +/* Copyright (C) 2013-2019 Greenbone Networks GmbH * * SPDX-License-Identifier: GPL-2.0-or-later * @@ -1162,8 +1162,6 @@ migrate_213_to_214 () return 0; } -#undef UPDATE_DASHBOARD_SETTINGS - /** * @brief Migrate the database from version 214 to version 215. * @@ -1196,6 +1194,40 @@ migrate_214_to_215 () return 0; } +/** + * @brief Migrate the database from version 215 to version 216. + * + * @return 0 success, -1 error. + */ +int +migrate_215_to_216 () +{ + sql_begin_immediate (); + + /* Ensure that the database is currently version 215. */ + + if (manage_db_version () != 215) + { + sql_rollback (); + return -1; + } + + /* Update the database. */ + + /* Extend table "nvts" with additional column "solution" */ + sql ("ALTER TABLE IF EXISTS nvts ADD COLUMN solution text;"); + + /* Set the database version to 216. */ + + set_db_version (216); + + sql_commit (); + + return 0; +} + +#undef UPDATE_DASHBOARD_SETTINGS + /** * @brief The oldest version for which migration is supported */ @@ -1215,6 +1247,7 @@ static migrator_t database_migrators[] = { {213, migrate_212_to_213}, {214, migrate_213_to_214}, {215, migrate_214_to_215}, + {216, migrate_215_to_216}, /* End marker. */ {-1, NULL}}; diff --git a/src/manage_sql.c b/src/manage_sql.c index ce1b62361..6c50dc43a 100644 --- a/src/manage_sql.c +++ b/src/manage_sql.c @@ -15550,7 +15550,7 @@ update_nvti_cache () nvti_cache = nvtis_new (); init_iterator (&nvts, - "SELECT oid, name, family, cvss_base, tag FROM nvts;"); + "SELECT oid, name, family, cvss_base, tag, solution, solution_type FROM nvts;"); while (next (&nvts)) { iterator_t refs; @@ -15561,6 +15561,8 @@ update_nvti_cache () nvti_set_family (nvti, iterator_string (&nvts, 2)); nvti_set_cvss_base (nvti, iterator_string (&nvts, 3)); nvti_set_tag (nvti, iterator_string (&nvts, 4)); + nvti_set_solution (nvti, iterator_string (&nvts, 5)); + nvti_set_solution_type (nvti, iterator_string (&nvts, 6)); init_iterator (&refs, "SELECT type, ref_id, ref_text" @@ -24300,6 +24302,43 @@ result_iterator_nvt_name (iterator_t *iterator) return NULL; } +/** + * @brief Get the NVT solution from a result iterator. + * + * @param[in] iterator Iterator. + * + * @return The solution of the NVT that produced the result, or NULL on error. + */ +const char* +result_iterator_nvt_solution (iterator_t *iterator) +{ + nvti_t *nvti; + if (iterator->done) return NULL; + nvti = lookup_nvti (result_iterator_nvt_oid (iterator)); + if (nvti) + return nvti_solution (nvti); + return NULL; +} + +/** + * @brief Get the NVT solution_type from a result iterator. + * + * @param[in] iterator Iterator. + * + * @return The solution_type of the NVT that produced the result, + * or NULL on error. + */ +const char* +result_iterator_nvt_solution_type (iterator_t *iterator) +{ + nvti_t *nvti; + if (iterator->done) return NULL; + nvti = lookup_nvti (result_iterator_nvt_oid (iterator)); + if (nvti) + return nvti_solution_type (nvti); + return NULL; +} + /** * @brief Get the NVT family from a result iterator. * diff --git a/src/manage_sql_nvts.c b/src/manage_sql_nvts.c index a7c3ed1ba..1f928c207 100644 --- a/src/manage_sql_nvts.c +++ b/src/manage_sql_nvts.c @@ -186,7 +186,7 @@ insert_nvt (const nvti_t *nvti) gchar *qod_str, *qod_type, *cve; gchar *quoted_name, *quoted_cve, *quoted_tag; gchar *quoted_cvss_base, *quoted_qod_type, *quoted_family, *value; - gchar *quoted_solution_type; + gchar *quoted_solution, *quoted_solution_type; int creation_time, modification_time, qod, i; cve = nvti_refs (nvti, "cve", "", 0); @@ -196,6 +196,11 @@ insert_nvt (const nvti_t *nvti) 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) : ""); + if (nvti_tag (nvti)) { gchar **split, **point; @@ -305,15 +310,6 @@ insert_nvt (const nvti_t *nvti) } g_free (value); - value = tag_value (nvti_tag (nvti), "solution_type"); - if (value) - { - quoted_solution_type = sql_quote (value); - g_free (value); - } - else - quoted_solution_type = g_strdup (""); - if (sql_int ("SELECT EXISTS (SELECT * FROM nvts WHERE oid = '%s');", nvti_oid (nvti))) sql ("DELETE FROM nvts WHERE oid = '%s';", nvti_oid (nvti)); @@ -321,12 +317,12 @@ insert_nvt (const nvti_t *nvti) sql ("INSERT into nvts (oid, name," " cve, tag, category, family, cvss_base," " creation_time, modification_time, uuid, solution_type," - " qod, qod_type)" + " solution, qod, qod_type)" " VALUES ('%s', '%s', '%s'," - " '%s', %i, '%s', '%s', %i, %i, '%s', '%s', %d, '%s');", + " '%s', %i, '%s', '%s', %i, %i, '%s', '%s', '%s', %d, '%s');", nvti_oid (nvti), quoted_name, quoted_cve, quoted_tag, nvti_category (nvti), quoted_family, quoted_cvss_base, creation_time, - modification_time, nvti_oid (nvti), quoted_solution_type, + modification_time, nvti_oid (nvti), quoted_solution_type, quoted_solution, qod, quoted_qod_type); sql ("DELETE FROM vt_refs where vt_oid = '%s';", nvti_oid (nvti)); @@ -353,6 +349,7 @@ insert_nvt (const nvti_t *nvti) 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_qod_type); } @@ -854,6 +851,26 @@ DEF_ACCESS (nvt_iterator_qod, GET_ITERATOR_COLUMN_COUNT + 10); */ 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 default timeout of an NVT. * @@ -1025,24 +1042,6 @@ get_tag (entity_t vt) first = 0; } - child = entity_child (vt, "solution"); - if (child) - { - const gchar *type; - - g_string_append_printf (tag, - "%ssolution=%s", - first ? "" : "|", - entity_text (child)); - first = 0; - - type = entity_attribute (child, "type"); - if (type == NULL) - g_debug ("%s: SOLUTION missing type", __FUNCTION__); - else - g_string_append_printf (tag, "|solution_type=%s", type); - } - child = entity_child (vt, "severities"); if (child) { @@ -1208,7 +1207,7 @@ nvti_from_vt (entity_t vt) { nvti_t *nvti = nvti_new (); const char *id; - entity_t name, detection, refs, ref, custom, family, category; + entity_t name, detection, solution, refs, ref, custom, family, category; entities_t children; gchar *tag, *cvss_base, *parsed_tags; @@ -1236,6 +1235,20 @@ nvti_from_vt (entity_t vt) nvti_set_qod_type (nvti, entity_attribute (detection, "qod_type")); } + solution = entity_child (vt, "solution"); + if (solution) + { + const gchar *type; + + nvti_set_solution (nvti, entity_text (solution)); + + type = entity_attribute (solution, "type"); + if (type == NULL) + g_debug ("%s: SOLUTION missing type", __FUNCTION__); + else + nvti_set_solution_type (nvti, type); + } + refs = entity_child (vt, "refs"); if (refs == NULL) { diff --git a/src/manage_sql_nvts.h b/src/manage_sql_nvts.h index d152b2fe0..0f503ccc1 100644 --- a/src/manage_sql_nvts.h +++ b/src/manage_sql_nvts.h @@ -55,6 +55,7 @@ { "qod_type", NULL, KEYWORD_TYPE_STRING }, \ { "solution_type", NULL, KEYWORD_TYPE_STRING }, \ { "tag", "script_tags", KEYWORD_TYPE_STRING}, \ + { "solution", NULL, KEYWORD_TYPE_STRING}, \ { NULL, NULL, KEYWORD_TYPE_UNKNOWN } \ }