diff --git a/CMakeLists.txt b/CMakeLists.txt index cf44b15e4..8aa2c55a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,7 +20,7 @@ cmake_minimum_required (VERSION 3.0) message ("-- Configuring Greenbone Vulnerability Manager...") project (gvm - VERSION 23.7.1 + VERSION 23.9.1 LANGUAGES C) if (POLICY CMP0005) @@ -247,6 +247,10 @@ if (NOT CVSS3_RATINGS) endif (NOT CVSS3_RATINGS) add_definitions (-DCVSS3_RATINGS=${CVSS3_RATINGS}) +if (NOT COMPLIANCE_REPORTS) + set (COMPLIANCE_REPORTS 0) +endif (NOT COMPLIANCE_REPORTS) +add_definitions (-DCOMPLIANCE_REPORTS=${COMPLIANCE_REPORTS}) message ("-- Install prefix: ${CMAKE_INSTALL_PREFIX}") @@ -254,6 +258,14 @@ message ("-- Install prefix: ${CMAKE_INSTALL_PREFIX}") set (GVMD_VERSION "${PROJECT_VERSION_STRING}") +if (COMPLIANCE_REPORTS EQUAL 1) + set(IF_COMPLIANCE_REPORTS "") + set(ENDIF_COMPLIANCE_REPORTS "") +elseif (COMPLIANCE_REPORTS EQUAL 0) + set(IF_COMPLIANCE_REPORTS "") +endif() + # Configure Doxyfile with version number configure_file (doc/Doxyfile.in doc/Doxyfile) configure_file (doc/Doxyfile_full.in doc/Doxyfile_full) @@ -402,7 +414,7 @@ install (FILES src/alert_methods/vFire/alert DESTINATION ${GVMD_DATA_DIR}/global_alert_methods/159f79a5-fce8-4ec5-aa49-7d17a77739a3/ PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE) - install (CODE "file (MAKE_DIRECTORY \$ENV{DESTDIR}${GVMD_DATA_DIR}/wizards)") +install (CODE "file (MAKE_DIRECTORY \$ENV{DESTDIR}${GVMD_DATA_DIR}/wizards)") install (FILES src/wizards/quick_first_scan.xml src/wizards/get_tasks_deep.xml diff --git a/doc/gvmd.8 b/doc/gvmd.8 index 7972955c6..1460e997e 100644 --- a/doc/gvmd.8 +++ b/doc/gvmd.8 @@ -109,6 +109,9 @@ File mode of the unix socket \fB--listen-owner=\fISTRING\fB\f1 Owner of the unix socket .TP +\fB--max-concurrent-scan-updates=\fINUMBER\fB\f1 +Maximum number of scan updates that can run at the same time. Default: 0 (unlimited). +.TP \fB--max-email-attachment-size=\fINUMBER\fB\f1 Maximum size of alert email attachments, in bytes. .TP @@ -121,9 +124,15 @@ Maximum size of user-defined message text in alert emails, in bytes. \fB--max-ips-per-target=\fINUMBER\fB\f1 Maximum number of IPs per target. .TP +\fB--mem-wait-retries=\fINUMBER\fB\f1 +How often to try waiting for available memory. Default: 30. Each retry will wait for 10 seconds. +.TP \fB-m, --migrate\f1 Migrate the database and exit. .TP +\fB--min-mem-feed-update=\fINUMBER\fB\f1 +Minimum memory in MiB for feed updates. Default: 0. Feed updates are skipped if less physical memory is available. +.TP \fB--modify-scanner=\fISCANNER-UUID\fB\f1 Modify scanner SCANNER-UUID and exit. .TP diff --git a/doc/gvmd.8.xml b/doc/gvmd.8.xml index 7c2165808..49bed2b70 100644 --- a/doc/gvmd.8.xml +++ b/doc/gvmd.8.xml @@ -262,6 +262,15 @@ along with this program. If not, see .

Owner of the unix socket

+ + + + @IF_COMPLIANCE_REPORTS@ + + @ENDIF_COMPLIANCE_REPORTS@ tag text @@ -18072,6 +18310,28 @@ END:VCALENDAR iso_time Scan end time + @IF_COMPLIANCE_REPORTS@ + + compliance_yes + integer + Number of compliance yes results + + + compliance_no + integer + Number of compliance no results + + + compliance_incomplete + integer + Number of compliance incomplete results + + + compliant + compliance_status + Compliance state of the report. Can be yes, no, incomplete or undefined + + @ENDIF_COMPLIANCE_REPORTS@ @@ -18141,6 +18401,19 @@ END:VCALENDAR boolean + @IF_COMPLIANCE_REPORTS@ + + usage_type + Optional usage type to limit the reports to. Affects total count unlike filter + + + scan + audit + + + + + @ENDIF_COMPLIANCE_REPORTS@ @@ -22919,8 +23192,15 @@ END:VCALENDAR timestamp scan_end + @IF_COMPLIANCE_REPORTS@ + + @ENDIF_COMPLIANCE_REPORTS@ result_count severity + @IF_COMPLIANCE_REPORTS@ + + compliance_count + @ENDIF_COMPLIANCE_REPORTS@ timestamp @@ -22966,6 +23246,34 @@ END:VCALENDAR severity Maximum severity of the report + @IF_COMPLIANCE_REPORTS@ + + compliance_count + Complaince counts. Only for audit tasks + + yes + no + incomplete + undefined + + + yes + integer + + + no + integer + + + incomplete + integer + + + undefined + integer + + + @ENDIF_COMPLIANCE_REPORTS@ diff --git a/src/sql.c b/src/sql.c index 0f08b56e1..33b0de1ca 100644 --- a/src/sql.c +++ b/src/sql.c @@ -150,38 +150,30 @@ sql_quote (const char* string) } /** - * @brief Quotes a string for use in SQL statements, also ASCII escaping it - * if it is not valid UTF-8. + * @brief Quotes a string for use in SQL statements, also ASCII escaping it. * - * @param[in] string String to quote, has to be \\0 terminated. + * The ASCII escaping excludes characters 0x80 - 0xFF for valid UTF-8 strings + * and includes them otherwise. + * + * @param[in] string String to quote, has to be \\0 terminated. + * @param[in] exceptions Optional exceptions for the escaping. * * @return Freshly allocated, quoted string. Free with g_free. */ gchar* -sql_ascii_escape_and_quote (const char* string) +sql_ascii_escape_and_quote (const char* string, const char* exceptions) { + gchar *escaped_string; gchar *quoted_string; assert (string); if (string == NULL) - { - return NULL; - } - else if (g_utf8_validate (string, -1, NULL)) - { - // Quote valid UTF-8 without ASCII escaping - quoted_string = sql_quote (string); - } - else - { - // Assume invalid UTF-8 uses a different, unknown encoding and - // ASCII-escape it. - gchar *escaped_string; - escaped_string = g_strescape (string, ""); - quoted_string = sql_quote (escaped_string); - g_free (escaped_string); - } + return NULL; + + escaped_string = strescape_check_utf8 (string, exceptions); + quoted_string = sql_quote (escaped_string); + g_free (escaped_string); return quoted_string; } @@ -216,7 +208,7 @@ sql_insert (const char *string) * * @return 0 success, 1 gave up (even when retry given), * 2 reserved (lock unavailable), 3 unique constraint violation, - * -1 error. + * 4 deadlock, -1 error. */ int sqlv (int retry, char* sql, va_list args) @@ -282,13 +274,14 @@ sql (char* sql, ...) continue; else if (ret == 4) { - if (deadlock_amount++ > DEADLOCK_THRESHOLD) - { - g_warning("%s: %d deadlocks detected, waiting and retrying %s", __func__, deadlock_amount, sql); - } - gvm_usleep (DEADLOCK_SLEEP); - continue; - } + if (deadlock_amount++ > DEADLOCK_THRESHOLD) + { + g_warning("%s: %d deadlocks detected, waiting and retrying %s", + __func__, deadlock_amount, sql); + } + gvm_usleep (DEADLOCK_SLEEP); + continue; + } else if (ret) abort(); break; @@ -363,6 +356,7 @@ int sql_x (char* sql, va_list args, sql_stmt_t** stmt_return) { int ret; + unsigned int deadlock_amount = 0; assert (stmt_return); @@ -400,6 +394,16 @@ sql_x (char* sql, va_list args, sql_stmt_t** stmt_return) sql_finalize (*stmt_return); continue; } + if (ret == -5) + { + if (deadlock_amount++ > DEADLOCK_THRESHOLD) + { + g_warning("%s: %d deadlocks detected, waiting and retrying %s", + __func__, deadlock_amount, sql); + } + gvm_usleep (DEADLOCK_SLEEP); + continue; + } break; } assert (ret == 1); diff --git a/src/sql.h b/src/sql.h index b0a225eff..08103a959 100644 --- a/src/sql.h +++ b/src/sql.h @@ -80,7 +80,7 @@ gchar * sql_quote (const char *); gchar * -sql_ascii_escape_and_quote (const char *); +sql_ascii_escape_and_quote (const char *, const char *); gchar * sql_insert (const char *); diff --git a/src/utils.c b/src/utils.c index 9c7ceb7cc..5db841129 100644 --- a/src/utils.c +++ b/src/utils.c @@ -770,6 +770,73 @@ is_uuid (const char *uuid) return 1; } + +/* Strings. */ + +/** + * @brief Escape a string with exceptions for UTF-8 if it is valid UTF-8. + * + * If the string is valid UTF-8, characters in the range 0x80 - 0xFF + * are excluded so non-ASCII UTF-8 characters and any characters in the + * extra_exceptions are not escaped. + * This leaves the characters 0x01 - 0x1F and 0x7F to be escaped if they are + * not in the given extra_exceptions. + * + * For strings that are not valid UTF-8 all characters in the ranges + * + * @param[in] str The string to escape. + * @param[in] extra_exceptions Extra exc. + * + * @return Newly allocated escaped copy of the string. + */ +gchar * +strescape_check_utf8 (const char *str, const char *extra_exceptions) +{ + if (g_utf8_validate (str, -1, NULL)) + return strescape_without_utf8 (str, extra_exceptions); + else + return g_strescape (str, extra_exceptions); +} + +/** + * @brief Escape control characters in a string with exceptions for UTF-8. + * + * Characters in the range 0x80 - 0xFF are excluded so non-ASCII UTF-8 + * characters are not escaped. + * This leaves the characters 0x01 - 0x1F and 0x7F to be escaped if they are + * not in the given extra_exceptions. + * + * @param[in] str The string to escape. + * @param[in] extra_exceptions Extra exceptions to the escaping. + * + * @return Newly allocated escaped copy of the string. + */ +gchar * +strescape_without_utf8 (const char *str, const char *extra_exceptions) +{ + static const char *base_exceptions = + "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377"; + gchar *exceptions = NULL; + gchar *escaped; + + if (extra_exceptions && strcmp (extra_exceptions, "")) + { + exceptions = g_strconcat (base_exceptions, + extra_exceptions ? extra_exceptions : "", + NULL); + } + escaped = g_strescape (str, exceptions ? exceptions : base_exceptions); + g_free (exceptions); + return escaped; +} + /* XML. */ @@ -959,3 +1026,26 @@ wait_for_pid (pid_t pid, const char *context) } } } + +/** + * @brief Get the available physical memory in bytes. + * + * @return The available memory + */ +guint64 +phys_mem_available () +{ + return (unsigned long long)(sysconf(_SC_AVPHYS_PAGES)) + * sysconf(_SC_PAGESIZE); +} + +/** + * @brief Get the total physical memory in bytes. + * + * @return The total memory + */ +guint64 +phys_mem_total () +{ + return sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE); +} diff --git a/src/utils.h b/src/utils.h index 1054dc0ca..10fcf59d8 100644 --- a/src/utils.h +++ b/src/utils.h @@ -88,6 +88,12 @@ lockfile_locked (const gchar *); int is_uuid (const char *); +gchar * +strescape_check_utf8 (const char *, const char *); + +gchar * +strescape_without_utf8 (const char *, const char *); + int parse_xml_file (const gchar *, entity_t *); @@ -103,4 +109,10 @@ fork_with_handlers (); void wait_for_pid (pid_t, const char *); +guint64 +phys_mem_available (); + +guint64 +phys_mem_total (); + #endif /* not _GVMD_UTILS_H */ diff --git a/src/utils_tests.c b/src/utils_tests.c index 2a252a19d..ad6b8aa3f 100644 --- a/src/utils_tests.c +++ b/src/utils_tests.c @@ -109,6 +109,42 @@ Ensure (utils, gvm_sleep_sleep_for_1) assert_that (timespec_subtract (&end, &start), is_greater_than (NANOSECONDS - 1)); } +Ensure (utils, strescape_check_utf_8_no_exceptions) +{ + const char *utf8_input = "Äöü\n123\\UTF-8\x04"; + const char *utf8_expected = "Äöü\\n123\\\\UTF-8\\004"; + const char *cp850_input = "\x8E\x94\x81\n123\\CP850\x04"; + const char *cp850_expected = "\\216\\224\\201\\n123\\\\CP850\\004"; + + assert_that (g_utf8_validate (utf8_input, -1, NULL), is_true); + gchar *output = strescape_check_utf8 (utf8_input, NULL); + assert_that (output, is_equal_to_string (utf8_expected)); + g_free (output); + + assert_that (g_utf8_validate (cp850_input, -1, NULL), is_false); + output = strescape_check_utf8 (cp850_input, NULL); + assert_that (output, is_equal_to_string (cp850_expected)); + g_free (output); +} + +Ensure (utils, strescape_check_utf_8_with_exceptions) +{ + const char *utf8_input = "Äöü\n123\\UTF-8\x04"; + const char *utf8_expected = "Äöü\n123\\\\UTF-8\\004"; + const char *cp850_input = "\x8E\x94\x81\n123\\CP850\x04"; + const char *cp850_expected = "\\216\\224\\201\n123\\\\CP850\\004"; + + assert_that (g_utf8_validate (utf8_input, -1, NULL), is_true); + gchar *output = strescape_check_utf8 (utf8_input, "\t\n\r"); + assert_that (output, is_equal_to_string (utf8_expected)); + g_free (output); + + assert_that (g_utf8_validate (cp850_input, -1, NULL), is_false); + output = strescape_check_utf8 (cp850_input, "\t\n\r"); + assert_that (output, is_equal_to_string (cp850_expected)); + g_free (output); +} + /* Test suite. */ int @@ -128,6 +164,9 @@ main (int argc, char **argv) add_test_with_context (suite, utils, parse_iso_time_tz_with_z); add_test_with_context (suite, utils, parse_iso_time_tz_with_fallback_tz); add_test_with_context (suite, utils, parse_iso_time_tz_variants); + + add_test_with_context (suite, utils, strescape_check_utf_8_no_exceptions); + add_test_with_context (suite, utils, strescape_check_utf_8_with_exceptions); if (argc > 1) return run_single_test (suite, argv[1], create_text_reporter ());