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 ());