diff --git a/.docker/build.Dockerfile b/.docker/build.Dockerfile
index a3fcbb304..885201235 100644
--- a/.docker/build.Dockerfile
+++ b/.docker/build.Dockerfile
@@ -2,7 +2,7 @@
ARG GVM_LIBS_VERSION=oldstable
# We want gvm-libs to be ready so we use the build docker image of gvm-libs
-FROM greenbone/gvm-libs:$GVM_LIBS_VERSION
+FROM registry.community.greenbone.net/community/gvm-libs:${GVM_LIBS_VERSION}
# This will make apt-get install without question
ARG DEBIAN_FRONTEND=noninteractive
diff --git a/.docker/prod.Dockerfile b/.docker/prod.Dockerfile
index 204d14036..1872962b8 100644
--- a/.docker/prod.Dockerfile
+++ b/.docker/prod.Dockerfile
@@ -20,7 +20,7 @@ RUN mkdir /build && \
cmake -DCMAKE_BUILD_TYPE=Release $FEATURE_TOGGLE /source && \
make DESTDIR=/install install
-FROM greenbone/gvm-libs:${GVM_LIBS_VERSION}
+FROM registry.community.greenbone.net/community/gvm-libs:${GVM_LIBS_VERSION}
ARG DEBIAN_FRONTEND=noninteractive
diff --git a/.docker/start-gvmd.sh b/.docker/start-gvmd.sh
index 7083b8f81..a05ca0824 100644
--- a/.docker/start-gvmd.sh
+++ b/.docker/start-gvmd.sh
@@ -18,7 +18,7 @@
[ -z "$USER" ] && USER="admin"
[ -z "$PASSWORD" ] && PASSWORD="admin"
-[ -z "$GVMD_ARGS" ] && GVMD_ARGS="--listen-mode=666"
+[ -z "$GVMD_ARGS" ] && GVMD_ARGS="-f --listen-mode=666"
[ -z "$GVMD_USER" ] && GVMD_USER="gvmd"
[ -z "$PGRES_DATA" ] && PGRES_DATA="/var/lib/postgresql"
@@ -49,6 +49,4 @@ gvmd --modify-setting 78eceaec-3385-11ea-b237-28d24461215b --value "$uid"
echo "starting gvmd"
gvmd $GVMD_ARGS ||
- (cat /var/log/gvm/gvmd.log && exit 1)
-
-tail -f /var/log/gvm/gvmd.log
+ (echo "Starting gvmd failed" && exit 1)
\ No newline at end of file
diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml
index 470a23bb2..c74217b0c 100644
--- a/.github/workflows/build-and-test.yml
+++ b/.github/workflows/build-and-test.yml
@@ -64,7 +64,7 @@ jobs:
- name: Configure and run tests
run: CTEST_OUTPUT_ON_FAILURE=1 cmake --build build -- tests test
- name: Upload test coverage to Codecov
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
with:
file: build/coverage/coverage.xml
token: ${{ secrets.CODECOV_TOKEN }}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cf44b15e4..a279ac168 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 24.0.1
LANGUAGES C)
if (POLICY CMP0005)
@@ -103,7 +103,7 @@ include (CPack)
set (GVMD_DATABASE_VERSION 256)
-set (GVMD_SCAP_DATABASE_VERSION 21)
+set (GVMD_SCAP_DATABASE_VERSION 22)
set (GVMD_CERT_DATABASE_VERSION 8)
@@ -163,11 +163,13 @@ if (NOT GVMD_STATE_DIR)
set (GVMD_STATE_DIR "${GVM_STATE_DIR}/gvmd")
endif (NOT GVMD_STATE_DIR)
-if (NOT GVM_LOG_DIR)
- set (GVM_LOG_DIR "${LOCALSTATEDIR}/log/gvm")
-else (NOT GVM_LOG_DIR)
- set (GVM_LOG_DIR "${GVM_LOG_DIR}")
-endif (NOT GVM_LOG_DIR)
+if (NOT GVMD_LOG_FILE)
+ if (GVM_LOG_DIR)
+ set (GVMD_LOG_FILE "${GVM_LOG_DIR}/gvmd.log")
+ else (GVM_LOG_DIR)
+ set (GVMD_LOG_FILE "-")
+ endif (GVM_LOG_DIR)
+endif (NOT GVMD_LOG_FILE)
set (GVM_SCAP_RES_DIR "${GVM_DATA_DIR}/scap")
set (GVM_CERT_RES_DIR "${GVM_DATA_DIR}/cert")
@@ -247,8 +249,8 @@ if (NOT CVSS3_RATINGS)
endif (NOT CVSS3_RATINGS)
add_definitions (-DCVSS3_RATINGS=${CVSS3_RATINGS})
-
message ("-- Install prefix: ${CMAKE_INSTALL_PREFIX}")
+message ("-- Log file: ${GVMD_LOG_FILE}")
## Version
@@ -402,7 +404,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/INSTALL.md b/INSTALL.md
index ff9f1b144..a7b36c2bf 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -21,7 +21,7 @@ Prerequisites:
Install these prerequisites on Debian GNU/Linux 'Buster' 10:
- apt-get install gcc cmake libglib2.0-dev libgnutls28-dev libpq-dev postgresql-server-dev-11 pkg-config libical-dev xsltproc libgpgme-dev
+ apt-get install gcc cmake libcjson-dev libglib2.0-dev libgnutls28-dev libpq-dev postgresql-server-dev-11 pkg-config libical-dev xsltproc libgpgme-dev
Prerequisites for building documentation:
* Doxygen
diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt
index a9c1ce686..5756751d5 100644
--- a/config/CMakeLists.txt
+++ b/config/CMakeLists.txt
@@ -15,9 +15,8 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
-
if (NOT SYSTEMD_SERVICE_DIR)
- set (SYSTEMD_SERVICE_DIR "/lib/systemd/system")
+ set (SYSTEMD_SERVICE_DIR "${LIBDIR}/systemd/system")
endif (NOT SYSTEMD_SERVICE_DIR)
if (NOT LOGROTATE_DIR)
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
+
+
+
+
tag
text
@@ -18060,6 +18357,26 @@ END:VCALENDAR
iso_time
Scan end time
+
+ 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
+
@@ -18081,7 +18398,7 @@ END:VCALENDAR
uuid
- format_id
+ config_id
ID of requested report config
uuid
@@ -18129,6 +18446,17 @@ END:VCALENDAR
boolean
+
+ usage_type
+ Optional usage type to limit the reports to. Affects total count unlike filter
+
+
+ scan
+ audit
+
+
+
+
@@ -18168,9 +18496,6 @@ END:VCALENDAR
term
name
- filter
- host
- delta
keywords
@@ -18183,61 +18508,6 @@ END:VCALENDAR
Filter name, if applicable
text
-
- filter
- A severity level that is included in the report
-
-
- High
- Medium
- Low
- Log
-
-
-
-
- host
- Single host selected for delta report
-
- ip
-
-
- ip
- IP address of the host
- text
-
-
-
- delta
- Delta states
-
- text
- changed
- gone
- new
- same
-
-
- changed
- Whether changed results are included
- boolean
-
-
- gone
- Whether results that have vanished are included
- boolean
-
-
- new
- Whether new results are included
- boolean
-
-
- same
- Whether results that are equal are included
- boolean
-
-
keywords
Filter broken down into keywords
@@ -22907,8 +23177,11 @@ END:VCALENDAR
timestamp
scan_end
+
result_count
severity
+
+ compliance_count
timestamp
@@ -22954,6 +23227,32 @@ END:VCALENDAR
severity
Maximum severity of the report
+
+ compliance_count
+ Complaince counts. Only for audit tasks
+
+ yes
+ no
+ incomplete
+ undefined
+
+
+ yes
+ integer
+
+
+ no
+ integer
+
+
+ incomplete
+ integer
+
+
+ undefined
+ integer
+
+
@@ -26474,12 +26773,14 @@ END:VCALENDAR
name
allow_insecure
certificate
+ kdc
key
login
password
community
auth_algorithm
privacy
+ realm
name
@@ -26507,6 +26808,11 @@ END:VCALENDAR
text
+
+ kdc
+ text
+ The Kerberos KDC (key distribution center(s))
+
key
@@ -26593,6 +26899,11 @@ END:VCALENDAR
+
+ realm
+ text
+ The Kerberos realm
+
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/sql_pg.c b/src/sql_pg.c
index cf8ed82c8..7f87cc1c9 100644
--- a/src/sql_pg.c
+++ b/src/sql_pg.c
@@ -607,7 +607,7 @@ sql_rollback ()
*
* @param[in] table The table to lock.
* @param[in] lock_timeout The lock timeout in milliseconds, 0 for unlimited.
- *
+ *
* @return 1 if locked, 0 if failed / timed out.
*/
int
@@ -615,10 +615,10 @@ sql_table_lock_wait (const char *table, int lock_timeout)
{
int old_lock_timeout = sql_int ("SHOW lock_timeout;");
sql ("SET LOCAL lock_timeout = %d;", lock_timeout);
-
+
// This requires the gvmd functions to be defined first.
int ret = sql_int ("SELECT try_exclusive_lock_wait ('%s');", table);
-
+
sql ("SET LOCAL lock_timeout = %d;", old_lock_timeout);
return ret;
}
diff --git a/src/utils.c b/src/utils.c
index 9c7ceb7cc..32588497b 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..46ff41bb4 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
@@ -129,6 +165,9 @@ main (int argc, char **argv)
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 ());