From 83d24a875ec613ae28b8efa18ddb50fb2d0c92c1 Mon Sep 17 00:00:00 2001
From: ozgen
Date: Thu, 2 Apr 2026 10:02:01 +0200
Subject: [PATCH 01/15] change: extract report hosts logic into dedicated
management files
Extract report host related SQL and XML generation logic from the
existing report handling code into dedicated report hosts modules.
Keep the existing behavior unchanged and prepare the codebase for a
separate get_report_hosts GMP command.
---
src/CMakeLists.txt | 3 +
src/manage_sql.c | 1059 +++------------------------------
src/manage_sql.h | 67 +++
src/manage_sql_report_hosts.c | 1044 ++++++++++++++++++++++++++++++++
src/manage_sql_report_hosts.h | 39 ++
5 files changed, 1250 insertions(+), 962 deletions(-)
create mode 100644 src/manage_sql_report_hosts.c
create mode 100644 src/manage_sql_report_hosts.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1e479ed20..05111d852 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -188,6 +188,7 @@ set(
manage_resources.c
manage_report_configs.c
manage_report_formats.c
+ manage_report_hosts.c
manage_roles.c
manage_runtime_flags.c
manage_authentication.c
@@ -244,6 +245,7 @@ set(
manage_sql_report_configs.c
manage_sql_report_formats.c
manage_sql_resources.c
+ manage_sql_report_hosts.c
manage_sql_roles.c
manage_sql_settings.c
manage_sql_tags.c
@@ -287,6 +289,7 @@ set(
gmp_tls_certificates.c
gmp_oci_image_targets.c
gmp_integration_configs.c
+ gmp_report_hosts.c
)
if(ENABLE_AGENTS)
diff --git a/src/manage_sql.c b/src/manage_sql.c
index cec12fb15..0babef986 100644
--- a/src/manage_sql.c
+++ b/src/manage_sql.c
@@ -114,6 +114,7 @@
#include "manage_sql_agents.h"
#include "manage_sql_agent_groups.h"
#include "manage_sql_agent_installers.h"
+#include "manage_sql_report_hosts.h"
#undef G_LOG_DOMAIN
/**
@@ -12986,198 +12987,6 @@ cleanup_result_nvts ()
return 0;
}
-/**
- * @brief Initialise a host iterator.
- *
- * @param[in] iterator Iterator.
- * @param[in] report Report whose hosts the iterator loops over.
- * @param[in] host Single host to iterate over. All hosts if NULL.
- * @param[in] report_host Single report host to iterate over. All if 0.
- */
-void
-init_report_host_iterator (iterator_t* iterator, report_t report, const char *host,
- report_host_t report_host)
-{
- if (report)
- {
- init_ps_iterator (iterator,
- "SELECT id, host, iso_time (start_time),"
- " iso_time (end_time), current_port,"
- " max_port, hostname, report,"
- " (SELECT uuid FROM reports WHERE id = report),"
- " (SELECT uuid FROM hosts"
- " WHERE id = (SELECT host FROM host_identifiers"
- " WHERE source_type = 'Report Host'"
- " AND name = 'ip'"
- " AND source_id = (SELECT uuid"
- " FROM reports"
- " WHERE id = report)"
- " AND value = report_hosts.host"
- " LIMIT 1))"
- " FROM report_hosts"
- " WHERE ($1 = 0 OR id = $1)"
- " AND report = $2"
- " AND ($3::text IS NULL OR host = $3)"
- " ORDER BY order_inet (host);",
- SQL_RESOURCE_PARAM (report_host),
- SQL_RESOURCE_PARAM (report),
- host ? SQL_STR_PARAM (host) : SQL_NULL_PARAM,
- NULL);
- }
- else
- {
- init_ps_iterator (iterator,
- "SELECT id, host, iso_time (start_time),"
- " iso_time (end_time), current_port, max_port,"
- " hostname, report,"
- " (SELECT uuid FROM reports WHERE id = report),"
- " ''"
- " FROM report_hosts"
- " WHERE ($1 = 0 OR id = $1)"
- " AND ($2::text IS NULL OR host = $2)"
- " ORDER BY order_inet (host);",
- SQL_RESOURCE_PARAM (report_host),
- host ? SQL_STR_PARAM (host) : SQL_NULL_PARAM,
- NULL);
- }
-}
-
-/**
- * @brief Initialise a host iterator.
- *
- * @param[in] iterator Iterator.
- * @param[in] report Report whose hosts the iterator loops over.
- * @param[in] host Host to iterate over.
- * @param[in] hostname Hostname.
- */
-void
-init_report_host_iterator_hostname (iterator_t* iterator,
- report_t report,
- const char *host,
- const char *hostname)
-{
- init_ps_iterator (iterator,
- "SELECT id, host, iso_time (start_time),"
- " iso_time (end_time), current_port, max_port,"
- " hostname, report,"
- " (SELECT uuid FROM reports WHERE id = report),"
- " (SELECT uuid FROM hosts"
- " WHERE id = (SELECT host FROM host_identifiers"
- " WHERE source_type = 'Report Host'"
- " AND name = 'ip'"
- " AND source_id = (SELECT uuid"
- " FROM reports"
- " WHERE id = report)"
- " AND value = report_hosts.host"
- " LIMIT 1))"
- " FROM report_hosts"
- " WHERE report = $1"
- " AND host = $2"
- " AND hostname = $3"
- " ORDER BY order_inet (host);",
- SQL_RESOURCE_PARAM (report),
- SQL_STR_PARAM (host),
- SQL_STR_PARAM (hostname),
- NULL);
-}
-
-
-/**
- * @brief Get the report host from a host iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return Report host.
- */
-report_host_t
-host_iterator_report_host (iterator_t* iterator)
-{
- if (iterator->done) return 0;
- return (report_host_t) iterator_int64 (iterator, 0);
-}
-
-/**
- * @brief Get the host from a host iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return The host of the host. Caller must use only before calling
- * cleanup_iterator.
- */
-DEF_ACCESS (host_iterator_host, 1);
-
-/**
- * @brief Get the start time from a host iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return The start time of the host. Caller must use only before calling
- * cleanup_iterator.
- */
-DEF_ACCESS (host_iterator_start_time, 2);
-
-/**
- * @brief Get the end time from a host iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return The end time of the host. Caller must use only before calling
- * cleanup_iterator.
- */
-DEF_ACCESS (host_iterator_end_time, 3);
-
-/**
- * @brief Get the current port from a host iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return Current port.
- */
-int
-host_iterator_current_port (iterator_t* iterator)
-{
- int ret;
- if (iterator->done) return -1;
- ret = iterator_int (iterator, 4);
- return ret;
-}
-
-/**
- * @brief Get the max port from a host iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return Current port.
- */
-int
-host_iterator_max_port (iterator_t* iterator)
-{
- int ret;
- if (iterator->done) return -1;
- ret = iterator_int (iterator, 5);
- return ret;
-}
-
-/**
- * @brief Get the hostname from a host iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return The hostname of the host.
- */
-DEF_ACCESS (host_iterator_hostname, 6);
-
-/**
- * @brief Get the asset UUID from a host iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return The UUID of the assset associate with the host. Caller must use
- * only before calling cleanup_iterator.
- */
-static
-DEF_ACCESS (host_iterator_asset_uuid, 9);
-
/**
* @brief Initialise a report errors iterator.
*
@@ -13336,69 +13145,6 @@ init_report_host_details_iterator (iterator_t* iterator,
report_host, report_host);
}
-/**
- * @brief Get the name from a report host details iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return The name of the report host detail. Caller must use only before
- * calling cleanup_iterator.
- */
-DEF_ACCESS (report_host_details_iterator_name, 1);
-
-/**
- * @brief Get the value from a report host details iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return The value of the report host detail. Caller must use only before
- * calling cleanup_iterator.
- */
-DEF_ACCESS (report_host_details_iterator_value, 2);
-
-/**
- * @brief Get the source type from a report host details iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return The source type of the report host detail. Caller must use only
- * before calling cleanup_iterator.
- */
-static
-DEF_ACCESS (report_host_details_iterator_source_type, 3);
-
-/**
- * @brief Get the source name from a report host details iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return The source name of the report host detail. Caller must use only
- * before calling cleanup_iterator.
- */
-DEF_ACCESS (report_host_details_iterator_source_name, 4);
-
-/**
- * @brief Get the source description from a report host details iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return The source description of the report host detail. Caller must use
- * only before calling cleanup_iterator.
- */
-static
-DEF_ACCESS (report_host_details_iterator_source_desc, 5);
-
-/**
- * @brief Get the extra info from a report host details iterator.
- *
- * @param[in] iterator Iterator.
- *
- * @return Extra info of the report host detail. Caller must use
- * only before calling cleanup_iterator.
- */
-static
-DEF_ACCESS (report_host_details_iterator_extra, 6);
-
/**
* @brief Set the end time of a task.
*
@@ -15486,49 +15232,6 @@ report_finished_container_images_str (report_t report)
return ret;
}
-/**
- * @brief Context info for print_report_xml_start.
- */
-struct print_report_context
-{
- gchar *compliance_levels; ///< Compliance levels.
- int count_filtered; ///< Whether to count filtered results.
- report_t delta; ///< Report to compare with.
- int filtered_result_count; ///< Filtered result count.
- const get_data_t *get; ///< GET command data.
- gchar *tz; ///< TZ.
- gchar *zone; ///< Zone.
- char *old_tz_override; ///< Old TZ.
- report_t report; ///< Report.
- gchar *tsk_usage_type; ///< Usage type of task, like "audit"
- // Counts.
- int criticals; ///< Number of criticals.
- int holes; ///< Number of holes.
- int infos; ///< Number of infos.
- int logs; ///< Number of logs.
- int warnings; ///< Number of warnings.
- int false_positives; ///< Number of false positives.
- int total_result_count; ///< Total number of results.
- // Filtered counts.
- GHashTable *f_host_criticals; ///< Criticals per host.
- GHashTable *f_host_false_positives; ///< False positives per host.
- GHashTable *f_host_holes; ///< Holes per host.
- GHashTable *f_host_infos; ///< Infos per host.
- GHashTable *f_host_logs; ///< Logs per hosts.
- GHashTable *f_host_ports; ///< Ports per host.
- GHashTable *f_host_warnings; ///< Warnings per hosts.
- // Filtered counts: audit.
- GHashTable *f_host_compliant; ///< Compliants per host.
- GHashTable *f_host_incomplete; ///< Incompletes per host.
- GHashTable *f_host_notcompliant; ///< Notcompliants per host.
- GHashTable *f_host_undefined; ///< Undefineds per host.
-};
-
-/**
- * @brief Context type for print_report_xml_start.
- */
-typedef struct print_report_context print_report_context_t;
-
/**
* @brief Free f_hosts_ field for print_report_context_cleanup.
*
@@ -15541,145 +15244,6 @@ free_f_host (GHashTable *table)
g_hash_table_destroy (table);
}
-/**
- * @brief Free the members of a context.
- *
- * @param[in] ctx Printing context.
- */
-static void
-print_report_context_cleanup (print_report_context_t *ctx)
-{
- g_free (ctx->compliance_levels);
- g_free (ctx->tsk_usage_type);
- g_free (ctx->tz);
- g_free (ctx->zone);
- free (ctx->old_tz_override);
- // Filtered counts.
- free_f_host (ctx->f_host_false_positives);
- free_f_host (ctx->f_host_holes);
- free_f_host (ctx->f_host_infos);
- free_f_host (ctx->f_host_logs);
- free_f_host (ctx->f_host_ports);
- free_f_host (ctx->f_host_warnings);
- // Filtered counts: audit.
- free_f_host (ctx->f_host_compliant);
- free_f_host (ctx->f_host_criticals);
- free_f_host (ctx->f_host_incomplete);
- free_f_host (ctx->f_host_notcompliant);
- free_f_host (ctx->f_host_undefined);
-}
-
-/**
- * @brief Write report host detail to file stream.
- *
- * On error close stream.
- *
- * @param[in] stream Stream to write to.
- * @param[in] details Report host details iterator.
- * @param[in] lean Whether to return reduced info.
- *
- * @return 0 success, -1 error.
- */
-static int
-print_report_host_detail (FILE *stream, iterator_t *details, int lean)
-{
- const char *name, *value;
-
- name = report_host_details_iterator_name (details);
- value = report_host_details_iterator_value (details);
-
- if (lean)
- {
- /* Skip certain host details. */
-
- if (strcmp (name, "EXIT_CODE") == 0
- && strcmp (value, "EXIT_NOTVULN") == 0)
- return 0;
-
- if (strcmp (name, "scanned_with_scanner") == 0)
- return 0;
-
- if (strcmp (name, "scanned_with_feedtype") == 0)
- return 0;
-
- if (strcmp (name, "scanned_with_feedversion") == 0)
- return 0;
-
- if (strcmp (name, "OS") == 0)
- return 0;
-
- if (strcmp (name, "traceroute") == 0)
- return 0;
- }
-
- PRINT (stream,
- ""
- "%s "
- "%s "
- "",
- name,
- value);
-
- if (lean == 0)
- PRINT (stream,
- "%s ",
- report_host_details_iterator_source_type (details));
-
- PRINT (stream,
- "%s ",
- report_host_details_iterator_source_name (details));
-
- if (report_host_details_iterator_source_desc (details)
- && strlen (report_host_details_iterator_source_desc (details)))
- PRINT (stream,
- "%s ",
- report_host_details_iterator_source_desc (details));
- else if (lean == 0)
- PRINT (stream,
- " ");
-
- PRINT (stream,
- " ");
-
- if (report_host_details_iterator_extra (details)
- && strlen (report_host_details_iterator_extra (details)))
- PRINT (stream,
- "%s ",
- report_host_details_iterator_extra (details));
- else if (lean == 0)
- PRINT (stream,
- " ");
-
- PRINT (stream,
- " ");
-
- return 0;
-}
-
-/**
- * @brief Print the XML for a report's host details to a file stream.
- * @param[in] report_host The report host.
- * @param[in] stream File stream to write to.
- * @param[in] lean Report host details iterator.
- *
- * @return 0 on success, -1 error.
- */
-static int
-print_report_host_details_xml (report_host_t report_host, FILE *stream,
- int lean)
-{
- iterator_t details;
-
- init_report_host_details_iterator
- (&details, report_host);
- while (next (&details))
- if (print_report_host_detail (stream, &details, lean))
- return -1;
- cleanup_iterator (&details);
-
- return 0;
-}
-
/**
* @brief Print the XML for a report host's TLS certificates to a file stream.
* @param[in] report_host The report host to get certificates from.
@@ -16100,6 +15664,72 @@ print_report_port_xml (print_report_context_t *ctx, report_t report, FILE *out,
return 0;
}
+/**
+ * @brief Free the members of a context.
+ *
+ * @param[in] ctx Printing context.
+ */
+void
+print_report_context_cleanup (print_report_context_t *ctx)
+{
+ g_free (ctx->compliance_levels);
+ g_free (ctx->tsk_usage_type);
+ g_free (ctx->tz);
+ g_free (ctx->zone);
+ free (ctx->old_tz_override);
+ // Filtered counts.
+ free_f_host (ctx->f_host_false_positives);
+ free_f_host (ctx->f_host_holes);
+ free_f_host (ctx->f_host_infos);
+ free_f_host (ctx->f_host_logs);
+ free_f_host (ctx->f_host_ports);
+ free_f_host (ctx->f_host_warnings);
+ // Filtered counts: audit.
+ free_f_host (ctx->f_host_compliant);
+ free_f_host (ctx->f_host_criticals);
+ free_f_host (ctx->f_host_incomplete);
+ free_f_host (ctx->f_host_notcompliant);
+ free_f_host (ctx->f_host_undefined);
+}
+
+
+/**
+ * @brief Init the f_hosts_* hashtables.
+ *
+ * @param[in] ctx Printing context.
+ */
+void
+print_report_init_f_hosts (print_report_context_t *ctx)
+{
+ if (strcmp (ctx->tsk_usage_type, "audit") == 0)
+ {
+ ctx->f_host_compliant = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ ctx->f_host_notcompliant = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ ctx->f_host_incomplete = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ ctx->f_host_undefined = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ }
+ else
+ {
+ ctx->f_host_criticals = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ ctx->f_host_holes = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ ctx->f_host_warnings = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ ctx->f_host_infos = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ ctx->f_host_logs = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+ ctx->f_host_false_positives = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free, NULL);
+ }
+}
+
/**
* @brief Calculate the progress of a report.
*
@@ -16152,397 +15782,6 @@ tz_revert (gchar *zone, char *tz, char *old_tz_override)
return 0;
}
-/**
- * @brief Print the XML for a report to a file.
- *
- * @param[in] host_summary_buffer Summary.
- * @param[in] host Host.
- * @param[in] start_iso Start time, in ISO format.
- * @param[in] end_iso End time, in ISO format.
- */
-static void
-host_summary_append (GString *host_summary_buffer, const char *host,
- const char *start_iso, const char *end_iso)
-{
- if (host_summary_buffer)
- {
- char start[200], end[200];
-
- if (start_iso)
- {
- struct tm start_tm;
-
- memset (&start_tm, 0, sizeof (struct tm));
- #if !defined(__GLIBC__)
- if (strptime (start_iso, "%Y-%m-%dT%H:%M:%S", &start_tm) == NULL)
- #else
- if (strptime (start_iso, "%FT%H:%M:%S", &start_tm) == NULL)
- #endif
- {
- g_warning ("%s: Failed to parse start", __func__);
- return;
- }
-
- if (strftime (start, 200, "%b %d, %H:%M:%S", &start_tm) == 0)
- {
- g_warning ("%s: Failed to format start", __func__);
- return;
- }
- }
- else
- strcpy (start, "(not started)");
-
- if (end_iso)
- {
- struct tm end_tm;
-
- memset (&end_tm, 0, sizeof (struct tm));
- #if !defined(__GLIBC__)
- if (strptime (end_iso, "%Y-%m-%dT%H:%M:%S", &end_tm) == NULL)
- #else
- if (strptime (end_iso, "%FT%H:%M:%S", &end_tm) == NULL)
- #endif
- {
- g_warning ("%s: Failed to parse end", __func__);
- return;
- }
-
- if (strftime (end, 200, "%b %d, %H:%M:%S", &end_tm) == 0)
- {
- g_warning ("%s: Failed to format end", __func__);
- return;
- }
- }
- else
- strcpy (end, "(not finished)");
-
- g_string_append_printf (host_summary_buffer,
- " %-15s %-16s %s\n",
- host,
- start,
- end);
- }
-}
-
-/**
- * @brief Print the XML for a report's host to a file stream.
- *
- * @param[in] ctx Printing context.
- * @param[in] stream File stream to write to.
- * @param[in] hosts Host iterator.
- * @param[in] host Single host to iterate over.
- * All hosts if NULL.
- * @param[in] usage_type Report usage type.
- * @param[in] lean Whether to return lean report.
- * @param[in] host_summary_buffer Host sumary buffer.
- *
- * @return 0 on success, -1 error.
- */
-static int
-print_report_host_xml (print_report_context_t *ctx,
- FILE *stream,
- iterator_t *hosts,
- const char *host,
- gchar *usage_type,
- int lean,
- GString *host_summary_buffer)
-{
- const char *current_host;
- int ports_count;
-
- current_host = host_iterator_host (hosts);
-
- ports_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_ports, current_host));
-
- host_summary_append (host_summary_buffer,
- host ? host : host_iterator_host (hosts),
- host_iterator_start_time (hosts),
- host_iterator_end_time (hosts));
- PRINT (stream,
- ""
- "%s ",
- host ? host : host_iterator_host (hosts));
-
- if (host_iterator_asset_uuid (hosts)
- && strlen (host_iterator_asset_uuid (hosts)))
- PRINT (stream,
- "",
- host_iterator_asset_uuid (hosts));
- else if (lean == 0)
- PRINT (stream,
- "");
-
- if (strcmp (usage_type, "audit") == 0)
- {
- int yes_count, no_count, incomplete_count, undefined_count;
-
- yes_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_compliant, current_host));
- no_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_notcompliant, current_host));
- incomplete_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_incomplete, current_host));
- undefined_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_undefined, current_host));
-
- PRINT (stream,
- "%s "
- "%s "
- "%d "
- ""
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- " "
- "%s ",
- host_iterator_start_time (hosts),
- host_iterator_end_time (hosts)
- ? host_iterator_end_time (hosts)
- : "",
- ports_count,
- (yes_count + no_count + incomplete_count + undefined_count),
- yes_count,
- no_count,
- incomplete_count,
- undefined_count,
- report_compliance_from_counts (&yes_count,
- &no_count,
- &incomplete_count,
- &undefined_count));
- }
- else
- {
- int holes_count, warnings_count, infos_count;
- int logs_count, false_positives_count;
- int criticals_count = 0;
-
- criticals_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_criticals, current_host));
- holes_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_holes, current_host));
- warnings_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_warnings, current_host));
- infos_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_infos, current_host));
- logs_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_logs, current_host));
- false_positives_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_false_positives,
- current_host));
-
- PRINT (stream,
- "%s "
- "%s "
- "%d "
- ""
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- " ",
- host_iterator_start_time (hosts),
- host_iterator_end_time (hosts)
- ? host_iterator_end_time (hosts)
- : "",
- ports_count,
- (criticals_count + holes_count + warnings_count + infos_count
- + logs_count + false_positives_count),
- criticals_count,
- holes_count,
- holes_count,
- warnings_count,
- warnings_count,
- infos_count,
- infos_count,
- logs_count,
- false_positives_count);
- }
-
- if (print_report_host_details_xml
- (host_iterator_report_host (hosts), stream, lean))
- {
- return -1;
- }
-
- PRINT (stream,
- " ");
-
- return 0;
-}
-
-#if ENABLE_CONTAINER_SCANNING
-/**
- * @brief Print the XML for a report's host to a file stream.
- * @param[in] ctx Printing context.
- * @param[in] stream File stream to write to.
- * @param[in] hosts Host iterator.
- * @param[in] lean Whether to return lean report.
- * @param[in] host_summary_buffer Host sumary buffer.
- *
- * @return 0 on success, -1 error.
- */
-static int
-print_container_scan_report_host_xml (print_report_context_t *ctx,
- FILE *stream,
- iterator_t *hosts,
- int lean,
- GString *host_summary_buffer)
-{
- int ports_count;
-
- const char* host = host_iterator_host (hosts);
- const char* hostname = host_iterator_hostname (hosts);
-
- gchar *host_key = create_host_key (host,
- hostname,
- CONTAINER_SCANNER_HOST_KEY_SEPARATOR);
-
- ports_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_ports, host_key));
-
- host_summary_append (host_summary_buffer,
- host,
- host_iterator_start_time (hosts),
- host_iterator_end_time (hosts));
- PRINT (stream,
- ""
- "%s ",
- host);
-
- if (host_iterator_asset_uuid (hosts)
- && strlen (host_iterator_asset_uuid (hosts)))
- PRINT (stream,
- "",
- host_iterator_asset_uuid (hosts));
- else if (lean == 0)
- PRINT (stream,
- "");
-
- int holes_count, warnings_count, infos_count;
- int logs_count, false_positives_count;
- int criticals_count = 0;
-
- criticals_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_criticals, host_key));
- holes_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_holes, host_key));
- warnings_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_warnings, host_key));
- infos_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_infos, host_key));
- logs_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_logs, host_key));
- false_positives_count
- = GPOINTER_TO_INT
- (g_hash_table_lookup (ctx->f_host_false_positives,
- host_key));
-
- PRINT (stream,
- "%s "
- "%s "
- "%d "
- ""
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- "%d "
- " ",
- host_iterator_start_time (hosts),
- host_iterator_end_time (hosts)
- ? host_iterator_end_time (hosts)
- : "",
- ports_count,
- (criticals_count + holes_count + warnings_count + infos_count
- + logs_count + false_positives_count),
- criticals_count,
- holes_count,
- holes_count,
- warnings_count,
- warnings_count,
- infos_count,
- infos_count,
- logs_count,
- false_positives_count);
-
- g_free (host_key);
-
- if (print_report_host_details_xml
- (host_iterator_report_host (hosts), stream, lean))
- {
- return -1;
- }
-
- PRINT (stream,
- " ");
-
- return 0;
-}
-
-/**
- * @brief Print report hosts for an XML report
- *
- * @param[in] ctx Printing context.
- * @param[in] stream File stream to write to.
- * @param[in] hosts Host iterator.
- * @param[in] lean Whether to return lean report.
- * @param[in] host_summary_buffer Buffer to append host summary to.
- */
-static int
-print_container_scan_report_hosts_xml (print_report_context_t *ctx,
- FILE *stream,
- iterator_t *hosts,
- int lean,
- GString *host_summary_buffer)
-{
- while (next (hosts))
- {
- if (print_container_scan_report_host_xml (ctx,
- stream,
- hosts,
- lean,
- host_summary_buffer))
- {
- g_warning ("%s: Failed to print host XML", __func__);
- return -1;
- }
- }
- return 0;
-}
-
-#endif // ENABLE_CONTAINER_SCANNING
-
/**
* @brief Init delta iterator for print_report_xml.
*
@@ -17062,42 +16301,6 @@ print_report_init_zone (print_report_context_t *ctx)
return 0;
}
-/**
- * @brief Init the f_hosts_* hashtables.
- *
- * @param[in] ctx Printing context.
- */
-static void
-print_report_init_f_hosts (print_report_context_t *ctx)
-{
- if (strcmp (ctx->tsk_usage_type, "audit") == 0)
- {
- ctx->f_host_compliant = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
- ctx->f_host_notcompliant = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
- ctx->f_host_incomplete = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
- ctx->f_host_undefined = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
- }
- else
- {
- ctx->f_host_criticals = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
- ctx->f_host_holes = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
- ctx->f_host_warnings = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
- ctx->f_host_infos = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
- ctx->f_host_logs = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
- ctx->f_host_false_positives = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free, NULL);
- }
-}
/**
* @brief Get result count totals for print_report_xml_start.
@@ -18219,101 +17422,43 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
if (get->details && result_hosts_only)
{
- gchar *result_host;
- int index = 0;
- array_terminate (result_hosts);
- iterator_t hosts;
-
-#if ENABLE_CONTAINER_SCANNING
- if (is_container_scanning_report)
+ if (print_report_hosts_xml (&ctx,
+ out,
+ report,
+ get,
+ ctx.tsk_usage_type,
+ lean,
+ #if ENABLE_CONTAINER_SCANNING
+ is_container_scanning_report,
+ #else
+ FALSE,
+ #endif
+ TRUE, /* result_hosts_only */
+ result_hosts, /* result_hosts */
+ host_summary_buffer))
{
- while ((result_host = g_ptr_array_index (result_hosts, index++)))
- {
- gchar *host, *hostname;
- if (parse_host_key (result_host,
- CONTAINER_SCANNER_HOST_KEY_SEPARATOR,
- &host,
- &hostname) < 0)
- {
- goto failed_print_report_host;
- }
- init_report_host_iterator_hostname (&hosts, report, host, hostname);
- g_free (host);
- g_free (hostname);
-
- if (print_container_scan_report_hosts_xml (&ctx,
- out,
- &hosts,
- lean,
- host_summary_buffer))
- {
- cleanup_iterator (&hosts);
- goto failed_print_report_host;
- }
- }
+ goto failed_print_report_host;
}
- else
-#endif /* ENABLE_CONTAINER_SCANNING */
- {
- while ((result_host = g_ptr_array_index (result_hosts, index++)))
- {
- gboolean present;
- init_report_host_iterator (&hosts, report, result_host, 0);
- present = next (&hosts);
- if (present)
- {
- if (print_report_host_xml (&ctx,
- out,
- &hosts,
- result_host,
- ctx.tsk_usage_type,
- lean,
- host_summary_buffer))
- {
- cleanup_iterator (&hosts);
- goto failed_print_report_host;
- }
- }
- }
- }
- cleanup_iterator (&hosts);
}
else if (get->details)
{
- iterator_t hosts;
- init_report_host_iterator (&hosts, report, NULL, 0);
-#if ENABLE_CONTAINER_SCANNING
- if (is_container_scanning_report)
- {
- if (print_container_scan_report_hosts_xml (&ctx,
- out,
- &hosts,
- lean,
- host_summary_buffer))
- {
- cleanup_iterator (&hosts);
- goto failed_print_report_host;
- }
- }
- else
-#endif /* ENABLE_CONTAINER_SCANNING */
+ if (print_report_hosts_xml (&ctx,
+ out,
+ report,
+ get,
+ ctx.tsk_usage_type,
+ lean,
+ #if ENABLE_CONTAINER_SCANNING
+ is_container_scanning_report,
+ #else
+ FALSE,
+ #endif
+ FALSE, /* result_hosts_only */
+ NULL, /* result_hosts */
+ host_summary_buffer))
{
- while (next (&hosts))
- {
- if (print_report_host_xml (&ctx,
- out,
- &hosts,
- NULL,
- ctx.tsk_usage_type,
- lean,
- host_summary_buffer))
- {
- cleanup_iterator (&hosts);
- goto failed_print_report_host;
- }
- }
+ goto failed_print_report_host;
}
- cleanup_iterator (&hosts);
}
/* Print TLS certificates */
@@ -18585,16 +17730,6 @@ manage_report (report_t report, report_t delta_report, const get_data_t *get,
return output;
}
-/**
- * @brief Size of base64 chunk in manage_send_report.
- */
-#define MANAGE_SEND_REPORT_CHUNK64_SIZE 262144
-
-/**
- * @brief Size of file chunk in manage_send_report.
- */
-#define MANAGE_SEND_REPORT_CHUNK_SIZE (MANAGE_SEND_REPORT_CHUNK64_SIZE * 3 / 4)
-
/**
* @brief Generate a report.
*
diff --git a/src/manage_sql.h b/src/manage_sql.h
index 46ce84654..3534cb8d9 100644
--- a/src/manage_sql.h
+++ b/src/manage_sql.h
@@ -165,6 +165,61 @@ struct report_aux {
/* Variables */
+
+
+/**
+ * @brief Size of base64 chunk in manage_send_report.
+ */
+#define MANAGE_SEND_REPORT_CHUNK64_SIZE 262144
+
+/**
+ * @brief Size of file chunk in manage_send_report.
+ */
+#define MANAGE_SEND_REPORT_CHUNK_SIZE (MANAGE_SEND_REPORT_CHUNK64_SIZE * 3 / 4)
+
+/**
+ * @brief Context info for print_report_xml_start.
+ */
+struct print_report_context
+{
+ gchar *compliance_levels; ///< Compliance levels.
+ int count_filtered; ///< Whether to count filtered results.
+ report_t delta; ///< Report to compare with.
+ int filtered_result_count; ///< Filtered result count.
+ const get_data_t *get; ///< GET command data.
+ gchar *tz; ///< TZ.
+ gchar *zone; ///< Zone.
+ char *old_tz_override; ///< Old TZ.
+ report_t report; ///< Report.
+ gchar *tsk_usage_type; ///< Usage type of task, like "audit"
+ // Counts.
+ int criticals; ///< Number of criticals.
+ int holes; ///< Number of holes.
+ int infos; ///< Number of infos.
+ int logs; ///< Number of logs.
+ int warnings; ///< Number of warnings.
+ int false_positives; ///< Number of false positives.
+ int total_result_count; ///< Total number of results.
+ // Filtered counts.
+ GHashTable *f_host_criticals; ///< Criticals per host.
+ GHashTable *f_host_false_positives; ///< False positives per host.
+ GHashTable *f_host_holes; ///< Holes per host.
+ GHashTable *f_host_infos; ///< Infos per host.
+ GHashTable *f_host_logs; ///< Logs per hosts.
+ GHashTable *f_host_ports; ///< Ports per host.
+ GHashTable *f_host_warnings; ///< Warnings per hosts.
+ // Filtered counts: audit.
+ GHashTable *f_host_compliant; ///< Compliants per host.
+ GHashTable *f_host_incomplete; ///< Incompletes per host.
+ GHashTable *f_host_notcompliant; ///< Notcompliants per host.
+ GHashTable *f_host_undefined; ///< Undefineds per host.
+};
+
+/**
+ * @brief Context type for print_report_xml_start.
+ */
+typedef struct print_report_context print_report_context_t;
+
extern db_conn_info_t gvmd_db_conn_info;
/**
@@ -553,4 +608,16 @@ type_build_select (const char *, const char *, const get_data_t *, gboolean,
gboolean, const char *, const char *, const char *,
gchar **);
+void
+print_report_init_f_hosts (print_report_context_t *);
+
+void
+print_report_context_cleanup (print_report_context_t *);
+
+const char *
+report_compliance_from_counts (const int*,
+ const int*,
+ const int*,
+ const int*);
+
#endif /* not _GVMD_MANAGE_SQL_H */
diff --git a/src/manage_sql_report_hosts.c b/src/manage_sql_report_hosts.c
new file mode 100644
index 000000000..666e9c865
--- /dev/null
+++ b/src/manage_sql_report_hosts.c
@@ -0,0 +1,1044 @@
+/* Copyright (C) 2026 Greenbone AG
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+/**
+ * @file
+ * @brief GVM SQL layer: Report hosts.
+ *
+ * SQL handlers for report host XML.
+ */
+
+#undef _XOPEN_SOURCE
+/**
+ * @brief Enable extra functions.
+ *
+ * For strptime in time.h.
+ */
+#define _XOPEN_SOURCE
+
+#include "manage_sql_report_hosts.h"
+
+#undef G_LOG_DOMAIN
+/**
+ * @brief GLib log domain.
+ */
+#define G_LOG_DOMAIN "md manage"
+
+/**
+ * @brief Get the name from a report host details iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The name of the report host detail. Caller must use only before
+ * calling cleanup_iterator.
+ */
+DEF_ACCESS (report_host_details_iterator_name, 1);
+
+/**
+ * @brief Get the value from a report host details iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The value of the report host detail. Caller must use only before
+ * calling cleanup_iterator.
+ */
+DEF_ACCESS (report_host_details_iterator_value, 2);
+
+/**
+ * @brief Get the source type from a report host details iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The source type of the report host detail. Caller must use only
+ * before calling cleanup_iterator.
+ */
+static
+DEF_ACCESS (report_host_details_iterator_source_type, 3);
+
+/**
+ * @brief Get the source name from a report host details iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The source name of the report host detail. Caller must use only
+ * before calling cleanup_iterator.
+ */
+DEF_ACCESS (report_host_details_iterator_source_name, 4);
+
+/**
+ * @brief Get the source description from a report host details iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The source description of the report host detail. Caller must use
+ * only before calling cleanup_iterator.
+ */
+static
+DEF_ACCESS (report_host_details_iterator_source_desc, 5);
+
+/**
+ * @brief Get the extra info from a report host details iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Extra info of the report host detail. Caller must use only before
+ * calling cleanup_iterator.
+ */
+static
+DEF_ACCESS (report_host_details_iterator_extra, 6);
+
+/**
+ * @brief Get the hostname from a host iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The hostname of the host.
+ */
+DEF_ACCESS (host_iterator_hostname, 6);
+
+/**
+ * @brief Get the asset UUID from a host iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The UUID of the asset associated with the host. Caller must use
+ * only before calling cleanup_iterator.
+ */
+static
+DEF_ACCESS (host_iterator_asset_uuid, 9);
+
+/**
+ * @brief Write report host detail to file stream.
+ *
+ * @param[in] stream Stream to write to.
+ * @param[in] details Report host details iterator.
+ * @param[in] lean Whether to return reduced info.
+ *
+ * @return 0 success, -1 error.
+ */
+static int
+print_report_host_detail (FILE *stream, iterator_t *details, int lean)
+{
+ const char *name, *value;
+
+ name = report_host_details_iterator_name (details);
+ value = report_host_details_iterator_value (details);
+
+ if (lean)
+ {
+ if (strcmp (name, "EXIT_CODE") == 0
+ && strcmp (value, "EXIT_NOTVULN") == 0)
+ return 0;
+
+ if (strcmp (name, "scanned_with_scanner") == 0)
+ return 0;
+
+ if (strcmp (name, "scanned_with_feedtype") == 0)
+ return 0;
+
+ if (strcmp (name, "scanned_with_feedversion") == 0)
+ return 0;
+
+ if (strcmp (name, "OS") == 0)
+ return 0;
+
+ if (strcmp (name, "traceroute") == 0)
+ return 0;
+ }
+
+ PRINT (stream,
+ ""
+ "%s "
+ "%s "
+ "",
+ name,
+ value);
+
+ if (lean == 0)
+ PRINT (stream,
+ "%s ",
+ report_host_details_iterator_source_type (details));
+
+ PRINT (stream,
+ "%s ",
+ report_host_details_iterator_source_name (details));
+
+ if (report_host_details_iterator_source_desc (details)
+ && strlen (report_host_details_iterator_source_desc (details)))
+ PRINT (stream,
+ "%s ",
+ report_host_details_iterator_source_desc (details));
+ else if (lean == 0)
+ PRINT (stream,
+ " ");
+
+ PRINT (stream, " ");
+
+ if (report_host_details_iterator_extra (details)
+ && strlen (report_host_details_iterator_extra (details)))
+ PRINT (stream,
+ "%s ",
+ report_host_details_iterator_extra (details));
+ else if (lean == 0)
+ PRINT (stream,
+ " ");
+
+ PRINT (stream, " ");
+
+ return 0;
+}
+
+/**
+ * @brief Print the XML for a report host's details to a file stream.
+ *
+ * @param[in] report_host The report host.
+ * @param[in] stream File stream to write to.
+ * @param[in] lean Whether to return reduced info.
+ *
+ * @return 0 on success, -1 error.
+ */
+static int
+print_report_host_details_xml (report_host_t report_host, FILE *stream,
+ int lean)
+{
+ iterator_t details;
+
+ init_report_host_details_iterator (&details, report_host);
+ while (next (&details))
+ {
+ if (print_report_host_detail (stream, &details, lean))
+ {
+ cleanup_iterator (&details);
+ return -1;
+ }
+ }
+ cleanup_iterator (&details);
+
+ return 0;
+}
+
+/**
+ * @brief Append one host summary line.
+ *
+ * @param[in] host_summary_buffer Summary buffer.
+ * @param[in] host Host.
+ * @param[in] start_iso Start time in ISO format.
+ * @param[in] end_iso End time in ISO format.
+ */
+static void
+host_summary_append (GString *host_summary_buffer, const char *host,
+ const char *start_iso, const char *end_iso)
+{
+ if (host_summary_buffer)
+ {
+ char start[200], end[200];
+
+ if (start_iso)
+ {
+ struct tm start_tm;
+
+ memset (&start_tm, 0, sizeof (struct tm));
+#if !defined(__GLIBC__)
+ if (strptime (start_iso, "%Y-%m-%dT%H:%M:%S", &start_tm) == NULL)
+#else
+ if (strptime (start_iso, "%FT%H:%M:%S", &start_tm) == NULL)
+#endif
+ {
+ g_warning ("%s: Failed to parse start", __func__);
+ return;
+ }
+
+ if (strftime (start, sizeof (start), "%b %d, %H:%M:%S",
+ &start_tm) == 0)
+ {
+ g_warning ("%s: Failed to format start", __func__);
+ return;
+ }
+ }
+ else
+ strcpy (start, "(not started)");
+
+ if (end_iso)
+ {
+ struct tm end_tm;
+
+ memset (&end_tm, 0, sizeof (struct tm));
+#if !defined(__GLIBC__)
+ if (strptime (end_iso, "%Y-%m-%dT%H:%M:%S", &end_tm) == NULL)
+#else
+ if (strptime (end_iso, "%FT%H:%M:%S", &end_tm) == NULL)
+#endif
+ {
+ g_warning ("%s: Failed to parse end", __func__);
+ return;
+ }
+
+ if (strftime (end, sizeof (end), "%b %d, %H:%M:%S", &end_tm) == 0)
+ {
+ g_warning ("%s: Failed to format end", __func__);
+ return;
+ }
+ }
+ else
+ strcpy (end, "(not finished)");
+
+ g_string_append_printf (host_summary_buffer,
+ " %-15s %-16s %s\n",
+ host,
+ start,
+ end);
+ }
+}
+
+/**
+ * @brief Print the XML for a report's host to a file stream.
+ *
+ * @param[in] ctx Printing context.
+ * @param[in] stream File stream to write to.
+ * @param[in] hosts Host iterator.
+ * @param[in] host Single host override, or NULL.
+ * @param[in] usage_type Report usage type.
+ * @param[in] lean Whether to return lean report.
+ * @param[in] host_summary_buffer Host summary buffer.
+ *
+ * @return 0 on success, -1 error.
+ */
+static int
+print_report_host_xml (print_report_context_t *ctx,
+ FILE *stream,
+ iterator_t *hosts,
+ const char *host,
+ gchar *usage_type,
+ int lean,
+ GString *host_summary_buffer)
+{
+ const char *current_host;
+ int ports_count;
+
+ current_host = host_iterator_host (hosts);
+
+ ports_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_ports, current_host));
+
+ host_summary_append (host_summary_buffer,
+ host ? host : host_iterator_host (hosts),
+ host_iterator_start_time (hosts),
+ host_iterator_end_time (hosts));
+
+ PRINT (stream,
+ ""
+ "%s ",
+ host ? host : host_iterator_host (hosts));
+
+ if (host_iterator_asset_uuid (hosts)
+ && strlen (host_iterator_asset_uuid (hosts)))
+ PRINT (stream,
+ "",
+ host_iterator_asset_uuid (hosts));
+ else if (lean == 0)
+ PRINT (stream,
+ "");
+
+ if (strcmp (usage_type, "audit") == 0)
+ {
+ int yes_count, no_count, incomplete_count, undefined_count;
+
+ yes_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_compliant, current_host));
+ no_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_notcompliant, current_host));
+ incomplete_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_incomplete, current_host));
+ undefined_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_undefined, current_host));
+
+ PRINT (stream,
+ "%s "
+ "%s "
+ "%d "
+ ""
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ " "
+ "%s ",
+ host_iterator_start_time (hosts),
+ host_iterator_end_time (hosts)
+ ? host_iterator_end_time (hosts)
+ : "",
+ ports_count,
+ (yes_count + no_count + incomplete_count + undefined_count),
+ yes_count,
+ no_count,
+ incomplete_count,
+ undefined_count,
+ report_compliance_from_counts (&yes_count,
+ &no_count,
+ &incomplete_count,
+ &undefined_count));
+ }
+ else
+ {
+ int holes_count, warnings_count, infos_count;
+ int logs_count, false_positives_count;
+ int criticals_count = 0;
+
+ criticals_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_criticals, current_host));
+ holes_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_holes, current_host));
+ warnings_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_warnings, current_host));
+ infos_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_infos, current_host));
+ logs_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_logs, current_host));
+ false_positives_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_false_positives,
+ current_host));
+
+ PRINT (stream,
+ "%s "
+ "%s "
+ "%d "
+ ""
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ " ",
+ host_iterator_start_time (hosts),
+ host_iterator_end_time (hosts)
+ ? host_iterator_end_time (hosts)
+ : "",
+ ports_count,
+ (criticals_count + holes_count + warnings_count + infos_count
+ + logs_count + false_positives_count),
+ criticals_count,
+ holes_count,
+ holes_count,
+ warnings_count,
+ warnings_count,
+ infos_count,
+ infos_count,
+ logs_count,
+ false_positives_count);
+ }
+
+ if (print_report_host_details_xml (host_iterator_report_host (hosts),
+ stream,
+ lean))
+ return -1;
+
+ PRINT (stream, " ");
+
+ return 0;
+}
+
+#if ENABLE_CONTAINER_SCANNING
+/**
+ * @brief Print the XML for a container scan report host to a file stream.
+ *
+ * @param[in] ctx Printing context.
+ * @param[in] stream File stream to write to.
+ * @param[in] hosts Host iterator.
+ * @param[in] lean Whether to return lean report.
+ * @param[in] host_summary_buffer Host summary buffer.
+ *
+ * @return 0 on success, -1 error.
+ */
+static int
+print_container_scan_report_host_xml (print_report_context_t *ctx,
+ FILE *stream,
+ iterator_t *hosts,
+ int lean,
+ GString *host_summary_buffer)
+{
+ int ports_count;
+ const char *host;
+ const char *hostname;
+ gchar *host_key;
+
+ int holes_count, warnings_count, infos_count;
+ int logs_count, false_positives_count;
+ int criticals_count = 0;
+
+ host = host_iterator_host (hosts);
+ hostname = host_iterator_hostname (hosts);
+
+ host_key = create_host_key (host,
+ hostname,
+ CONTAINER_SCANNER_HOST_KEY_SEPARATOR);
+
+ ports_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_ports, host_key));
+
+ host_summary_append (host_summary_buffer,
+ host,
+ host_iterator_start_time (hosts),
+ host_iterator_end_time (hosts));
+
+ PRINT (stream,
+ ""
+ "%s ",
+ host);
+
+ if (host_iterator_asset_uuid (hosts)
+ && strlen (host_iterator_asset_uuid (hosts)))
+ PRINT (stream,
+ "",
+ host_iterator_asset_uuid (hosts));
+ else if (lean == 0)
+ PRINT (stream,
+ "");
+
+ criticals_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_criticals, host_key));
+ holes_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_holes, host_key));
+ warnings_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_warnings, host_key));
+ infos_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_infos, host_key));
+ logs_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_logs, host_key));
+ false_positives_count
+ = GPOINTER_TO_INT
+ (g_hash_table_lookup (ctx->f_host_false_positives, host_key));
+
+ PRINT (stream,
+ "%s "
+ "%s "
+ "%d "
+ ""
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ "%d "
+ " ",
+ host_iterator_start_time (hosts),
+ host_iterator_end_time (hosts)
+ ? host_iterator_end_time (hosts)
+ : "",
+ ports_count,
+ (criticals_count + holes_count + warnings_count + infos_count
+ + logs_count + false_positives_count),
+ criticals_count,
+ holes_count,
+ holes_count,
+ warnings_count,
+ warnings_count,
+ infos_count,
+ infos_count,
+ logs_count,
+ false_positives_count);
+
+ g_free (host_key);
+
+ if (print_report_host_details_xml (host_iterator_report_host (hosts),
+ stream,
+ lean))
+ return -1;
+
+ PRINT (stream, " ");
+
+ return 0;
+}
+
+/**
+ * @brief Print all hosts from a container scan host iterator.
+ *
+ * @param[in] ctx Printing context.
+ * @param[in] stream File stream to write to.
+ * @param[in] hosts Host iterator.
+ * @param[in] lean Whether to return lean report.
+ * @param[in] host_summary_buffer Host summary buffer.
+ *
+ * @return 0 on success, -1 error.
+ */
+static int
+print_container_scan_report_hosts_xml (print_report_context_t *ctx,
+ FILE *stream,
+ iterator_t *hosts,
+ int lean,
+ GString *host_summary_buffer)
+{
+ while (next (hosts))
+ {
+ if (print_container_scan_report_host_xml (ctx,
+ stream,
+ hosts,
+ lean,
+ host_summary_buffer))
+ {
+ g_warning ("%s: Failed to print host XML", __func__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+#endif /* ENABLE_CONTAINER_SCANNING */
+
+/**
+ * @brief Print report hosts XML.
+ *
+ * @param[in] ctx Printing context.
+ * @param[in] stream File stream to write to.
+ * @param[in] report Report.
+ * @param[in] get GET data.
+ * @param[in] usage_type Report usage type.
+ * @param[in] lean Whether to return lean report.
+ * @param[in] is_container_scan Whether this is a container scan report.
+ * @param[in] result_hosts_only Whether to print only hosts with results.
+ * @param[in] result_hosts Result hosts array, used when result_hosts_only is set.
+ * @param[in] host_summary_buffer Host summary buffer.
+ *
+ * @return 0 on success, -1 error.
+ */
+int
+print_report_hosts_xml (print_report_context_t *ctx,
+ FILE *stream,
+ report_t report,
+ const get_data_t *get,
+ const gchar *usage_type,
+ int lean,
+ gboolean is_container_scan,
+ gboolean result_hosts_only,
+ array_t *result_hosts,
+ GString *host_summary_buffer)
+{
+ if (get == NULL)
+ {
+ g_warning ("%s: get is NULL", __func__);
+ return -1;
+ }
+
+ if (get->details == 0)
+ {
+ PRINT (stream,
+ "%i ",
+ report_host_count (report));
+ return 0;
+ }
+
+#if ENABLE_CONTAINER_SCANNING
+ if (is_container_scan)
+ {
+ if (result_hosts_only)
+ {
+ gchar *result_host;
+ int index = 0;
+
+ if (result_hosts == NULL)
+ {
+ g_warning ("%s: result_hosts_only set but result_hosts is NULL",
+ __func__);
+ return -1;
+ }
+
+ array_terminate (result_hosts);
+
+ while ((result_host = g_ptr_array_index (result_hosts, index++)))
+ {
+ iterator_t hosts;
+ gchar *host = NULL;
+ gchar *hostname = NULL;
+
+ if (parse_host_key (result_host,
+ CONTAINER_SCANNER_HOST_KEY_SEPARATOR,
+ &host,
+ &hostname) < 0)
+ {
+ g_warning ("%s: Failed to parse host key", __func__);
+ return -1;
+ }
+
+ init_report_host_iterator_hostname (
+ &hosts, report, host, hostname);
+
+ g_free (host);
+ g_free (hostname);
+
+ if (print_container_scan_report_hosts_xml (ctx,
+ stream,
+ &hosts,
+ lean,
+ host_summary_buffer))
+ {
+ cleanup_iterator (&hosts);
+ return -1;
+ }
+
+ cleanup_iterator (&hosts);
+ }
+
+ return 0;
+ }
+ else
+ {
+ iterator_t hosts;
+
+ init_report_host_iterator (&hosts, report, NULL, 0);
+
+ if (print_container_scan_report_hosts_xml (ctx,
+ stream,
+ &hosts,
+ lean,
+ host_summary_buffer))
+ {
+ cleanup_iterator (&hosts);
+ return -1;
+ }
+
+ cleanup_iterator (&hosts);
+ return 0;
+ }
+ }
+#endif /* ENABLE_CONTAINER_SCANNING */
+
+ if (result_hosts_only)
+ {
+ gchar *result_host;
+ int index = 0;
+
+ if (result_hosts == NULL)
+ {
+ g_warning ("%s: result_hosts_only set but result_hosts is NULL",
+ __func__);
+ return -1;
+ }
+
+ array_terminate (result_hosts);
+
+ while ((result_host = g_ptr_array_index (result_hosts, index++)))
+ {
+ iterator_t hosts;
+ gboolean present;
+
+ init_report_host_iterator (&hosts, report, result_host, 0);
+ present = next (&hosts);
+
+ if (present)
+ {
+ if (print_report_host_xml (ctx,
+ stream,
+ &hosts,
+ result_host,
+ (gchar *) usage_type,
+ lean,
+ host_summary_buffer))
+ {
+ cleanup_iterator (&hosts);
+ return -1;
+ }
+ }
+
+ cleanup_iterator (&hosts);
+ }
+
+ return 0;
+ }
+ else
+ {
+ iterator_t hosts;
+
+ init_report_host_iterator (&hosts, report, NULL, 0);
+
+ while (next (&hosts))
+ {
+ if (print_report_host_xml (ctx,
+ stream,
+ &hosts,
+ NULL,
+ (gchar *) usage_type,
+ lean,
+ host_summary_buffer))
+ {
+ cleanup_iterator (&hosts);
+ return -1;
+ }
+ }
+
+ cleanup_iterator (&hosts);
+ return 0;
+ }
+}
+
+/**
+ * @brief Initialize the result iterator and collect all result hosts.
+ *
+ * @param result_hosts Array to be filled with host keys (must be initialized).
+ * @param results Result iterator to use.
+ * @param get Request data used for iterator initialization.
+ * @param report Report identifier.
+ * @param is_container_scanning_report Whether to generate container-aware host keys.
+ *
+ * @return 0 on success, non-zero on failure.
+ */
+int
+fill_filtered_result_hosts (array_t **result_hosts,
+ const get_data_t *get,
+ report_t report,
+ iterator_t *results,
+ gboolean is_container_scanning_report)
+{
+ int ret;
+
+ if (result_hosts == NULL)
+ return -1;
+
+ *result_hosts = make_array ();
+
+ ret = init_result_get_iterator (results, get, report, NULL, NULL);
+ if (ret)
+ return ret;
+
+ while (next (results))
+ {
+ gchar *host_key;
+
+#if ENABLE_CONTAINER_SCANNING
+ if (is_container_scanning_report)
+ host_key = create_host_key (result_iterator_host (results),
+ result_iterator_hostname (results),
+ CONTAINER_SCANNER_HOST_KEY_SEPARATOR);
+ else
+#endif
+ host_key = g_strdup (result_iterator_host (results));
+
+ array_add_new_string (*result_hosts, host_key);
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Initialise a host iterator.
+ *
+ * @param[in] iterator Iterator.
+ * @param[in] report Report whose hosts the iterator loops over.
+ * @param[in] host Single host to iterate over. All hosts if NULL.
+ * @param[in] report_host Single report host to iterate over. All if 0.
+ */
+void
+init_report_host_iterator (iterator_t *iterator, report_t report,
+ const char *host,
+ report_host_t report_host)
+{
+ if (report)
+ {
+ init_ps_iterator (iterator,
+ "SELECT id, host, iso_time (start_time),"
+ " iso_time (end_time), current_port,"
+ " max_port, hostname, report,"
+ " (SELECT uuid FROM reports WHERE id = report),"
+ " (SELECT uuid FROM hosts"
+ " WHERE id = (SELECT host FROM host_identifiers"
+ " WHERE source_type = 'Report Host'"
+ " AND name = 'ip'"
+ " AND source_id = (SELECT uuid"
+ " FROM reports"
+ " WHERE id = report)"
+ " AND value = report_hosts.host"
+ " LIMIT 1))"
+ " FROM report_hosts"
+ " WHERE ($1 = 0 OR id = $1)"
+ " AND report = $2"
+ " AND ($3::text IS NULL OR host = $3)"
+ " ORDER BY order_inet (host);",
+ SQL_RESOURCE_PARAM (report_host),
+ SQL_RESOURCE_PARAM (report),
+ host ? SQL_STR_PARAM (host) : SQL_NULL_PARAM,
+ NULL);
+ }
+ else
+ {
+ init_ps_iterator (iterator,
+ "SELECT id, host, iso_time (start_time),"
+ " iso_time (end_time), current_port, max_port,"
+ " hostname, report,"
+ " (SELECT uuid FROM reports WHERE id = report),"
+ " ''"
+ " FROM report_hosts"
+ " WHERE ($1 = 0 OR id = $1)"
+ " AND ($2::text IS NULL OR host = $2)"
+ " ORDER BY order_inet (host);",
+ SQL_RESOURCE_PARAM (report_host),
+ host ? SQL_STR_PARAM (host) : SQL_NULL_PARAM,
+ NULL);
+ }
+}
+
+/**
+ * @brief Initialise a host iterator.
+ *
+ * @param[in] iterator Iterator.
+ * @param[in] report Report whose hosts the iterator loops over.
+ * @param[in] host Host to iterate over.
+ * @param[in] hostname Hostname.
+ */
+void
+init_report_host_iterator_hostname (iterator_t *iterator,
+ report_t report,
+ const char *host,
+ const char *hostname)
+{
+ init_ps_iterator (iterator,
+ "SELECT id, host, iso_time (start_time),"
+ " iso_time (end_time), current_port, max_port,"
+ " hostname, report,"
+ " (SELECT uuid FROM reports WHERE id = report),"
+ " (SELECT uuid FROM hosts"
+ " WHERE id = (SELECT host FROM host_identifiers"
+ " WHERE source_type = 'Report Host'"
+ " AND name = 'ip'"
+ " AND source_id = (SELECT uuid"
+ " FROM reports"
+ " WHERE id = report)"
+ " AND value = report_hosts.host"
+ " LIMIT 1))"
+ " FROM report_hosts"
+ " WHERE report = $1"
+ " AND host = $2"
+ " AND hostname = $3"
+ " ORDER BY order_inet (host);",
+ SQL_RESOURCE_PARAM (report),
+ SQL_STR_PARAM (host),
+ SQL_STR_PARAM (hostname),
+ NULL);
+}
+
+/**
+ * @brief Get the report host from a host iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Report host.
+ */
+report_host_t
+host_iterator_report_host (iterator_t *iterator)
+{
+ if (iterator->done)
+ return 0;
+ return (report_host_t) iterator_int64 (iterator, 0);
+}
+
+/**
+ * @brief Get the host from a host iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The host of the host. Caller must use only before calling
+ * cleanup_iterator.
+ */
+DEF_ACCESS (host_iterator_host, 1);
+
+/**
+ * @brief Get the start time from a host iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The start time of the host. Caller must use only before calling
+ * cleanup_iterator.
+ */
+DEF_ACCESS (host_iterator_start_time, 2);
+
+/**
+ * @brief Get the end time from a host iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return The end time of the host. Caller must use only before calling
+ * cleanup_iterator.
+ */
+DEF_ACCESS (host_iterator_end_time, 3);
+
+/**
+ * @brief Get the current port from a host iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Current port.
+ */
+int
+host_iterator_current_port (iterator_t *iterator)
+{
+ int ret;
+ if (iterator->done)
+ return -1;
+ ret = iterator_int (iterator, 4);
+ return ret;
+}
+
+/**
+ * @brief Get the max port from a host iterator.
+ *
+ * @param[in] iterator Iterator.
+ *
+ * @return Current port.
+ */
+int
+host_iterator_max_port (iterator_t *iterator)
+{
+ int ret;
+ if (iterator->done)
+ return -1;
+ ret = iterator_int (iterator, 5);
+ return ret;
+}
+
+/**
+ * @brief Generates extra where condition for report hosts
+ *
+ * @param report_uuid Report uuid for Where condition
+ *
+ * @return Newly allocated where clause string.
+ */
+gchar *
+report_hosts_extra_where (const gchar *report_uuid)
+{
+ gchar *extra_where;
+ gchar *quoted_report_uuid = sql_quote (report_uuid);
+
+ extra_where = g_strdup_printf (
+ " AND report = (SELECT id from reports WHERE uuid = '%s')",
+ quoted_report_uuid);
+
+ g_free (quoted_report_uuid);
+
+ return extra_where;
+}
\ No newline at end of file
diff --git a/src/manage_sql_report_hosts.h b/src/manage_sql_report_hosts.h
new file mode 100644
index 000000000..9abf35d45
--- /dev/null
+++ b/src/manage_sql_report_hosts.h
@@ -0,0 +1,39 @@
+/* Copyright (C) 2026 Greenbone AG
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+/**
+ * @file
+ * @brief GVM SQL layer: Report hosts.
+ *
+ * Headers for SQL handlers for report host XML.
+ */
+
+#ifndef _GVM_MANAGE_SQL_REPORT_HOSTS_H
+#define _GVM_MANAGE_SQL_REPORT_HOSTS_H
+
+#include "manage_report_hosts.h"
+#include "manage_sql.h"
+
+
+int
+print_report_hosts_xml(print_report_context_t*,
+ FILE*,
+ report_t,
+ const get_data_t*,
+ const gchar*,
+ int lean,
+ gboolean,
+ gboolean,
+ array_t*,
+ GString*);
+
+int
+fill_filtered_result_hosts(array_t**,
+ const get_data_t*,
+ report_t,
+ iterator_t*,
+ gboolean);
+
+#endif /* _GVM_MANAGE_SQL_REPORT_HOSTS_H */
From 68cbd16e28a1e8f8d5cd0b81bd0adc63c8c87027 Mon Sep 17 00:00:00 2001
From: ozgen
Date: Thu, 2 Apr 2026 10:04:12 +0200
Subject: [PATCH 02/15] Add management-layer support for report hosts responses
Add management-layer handling for sending report host XML separately
from get_reports.
Reuse the existing filtering and host selection logic, including
result_hosts_only and container scan handling, so host-only responses
can be generated without changing the existing report output.
---
src/manage.c | 1 +
src/manage.h | 23 +--
src/manage_report_hosts.c | 309 ++++++++++++++++++++++++++++++++++++++
src/manage_report_hosts.h | 59 ++++++++
src/manage_sql_assets.c | 1 +
5 files changed, 371 insertions(+), 22 deletions(-)
create mode 100644 src/manage_report_hosts.c
create mode 100644 src/manage_report_hosts.h
diff --git a/src/manage.c b/src/manage.c
index 4ddd2122e..9ed00c302 100644
--- a/src/manage.c
+++ b/src/manage.c
@@ -49,6 +49,7 @@
#include "manage_settings.h"
#include "manage_oci_image_targets.h"
#include "manage_http_scanner.h"
+#include "manage_report_hosts.h"
#include "manage_runtime_flags.h"
#include "manage_sql.h"
#include "manage_sql_assets.h"
diff --git a/src/manage.h b/src/manage.h
index 65ee70362..c2fbd7610 100644
--- a/src/manage.h
+++ b/src/manage.h
@@ -21,6 +21,7 @@
#include "manage_events.h"
#include "manage_get.h"
#include "manage_integration_configs.h"
+#include "manage_report_hosts.h"
#include "manage_tasks.h"
#include "sql.h"
#include "utils.h"
@@ -1446,28 +1447,6 @@ result_iterator_delta_hostname (iterator_t*);
int
cleanup_result_nvts ();
-void
-init_report_host_iterator (iterator_t*, report_t, const char *, report_host_t);
-
-void
-init_report_host_iterator_hostname (iterator_t*, report_t, const char *,
- const char *);
-
-const char*
-host_iterator_host (iterator_t*);
-
-const char*
-host_iterator_start_time (iterator_t*);
-
-const char*
-host_iterator_end_time (iterator_t*);
-
-int
-host_iterator_current_port (iterator_t*);
-
-int
-host_iterator_max_port (iterator_t*);
-
int
collate_message_type (void* data, int, const void*, int, const void*);
diff --git a/src/manage_report_hosts.c b/src/manage_report_hosts.c
new file mode 100644
index 000000000..ee2bc03fd
--- /dev/null
+++ b/src/manage_report_hosts.c
@@ -0,0 +1,309 @@
+/* Copyright (C) 2026 Greenbone AG
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+/**
+ * @file
+ * @brief GVM management layer: Report hosts.
+ *
+ * Non-SQL report hosts code for the GVM management layer.
+ */
+
+#include "manage_filters.h"
+#include "manage_report_hosts.h"
+
+#include "manage_settings.h"
+#include "manage_sql_report_hosts.h"
+
+#include
+
+#undef G_LOG_DOMAIN
+/**
+ * @brief GLib log domain.
+ */
+#define G_LOG_DOMAIN "md manage"
+
+/**
+ * @brief Send report hosts XML to the client.
+ *
+ * @param[in] report Report.
+ * @param[in] get GET command data.
+ * @param[in] usage_type Task usage type.
+ * @param[in] is_container_scanning_report Whether this is a container scan report.
+ * @param[in] lean Whether to send lean host data.
+ * @param[in] send Function to write to client.
+ * @param[in] send_data_1 Second argument to @p send.
+ * @param[in] send_data_2 Third argument to @p send.
+ *
+ * @return 0 on success, -1 on error, 2 if filter was not found.
+ */
+int
+manage_send_report_hosts (report_t report,
+ const get_data_t *get,
+ const gchar *usage_type,
+ gboolean is_container_scanning_report,
+ int lean,
+ gboolean (*send) (const char *,
+ int (*) (const char *, void *),
+ void *),
+ int (*send_data_1) (const char *, void *),
+ void *send_data_2)
+{
+ print_report_context_t ctx;
+ gchar *xml_file;
+ gchar *term;
+ gchar *sort_field;
+ gchar *levels;
+ gchar *delta_states;
+ gchar *search_phrase;
+ char xml_dir[] = "/tmp/gvmd_XXXXXX";
+ char chunk[MANAGE_SEND_REPORT_CHUNK_SIZE + 1];
+ FILE *stream;
+ int ret;
+ int first_result;
+ int max_results;
+ int sort_order;
+ gchar *min_qod;
+ int apply_overrides;
+ int search_phrase_exact;
+ int notes;
+ int overrides;
+ int result_hosts_only;
+ array_t *result_hosts;
+ iterator_t results;
+ GString *host_summary_buffer;
+ int results_initialized;
+
+ memset (&ctx, 0, sizeof (ctx));
+ term = NULL;
+ sort_field = NULL;
+ levels = NULL;
+ delta_states = NULL;
+ search_phrase = NULL;
+ xml_file = NULL;
+ stream = NULL;
+ result_hosts = NULL;
+ host_summary_buffer = NULL;
+ results_initialized = 0;
+ result_hosts_only = 0;
+
+
+ if (get == NULL)
+ {
+ g_warning ("%s: get is NULL", __func__);
+ return -1;
+ }
+
+ ctx.get = get;
+ ctx.report = report;
+ ctx.tsk_usage_type = g_strdup (usage_type);
+
+ print_report_init_f_hosts (&ctx);
+
+ /* Derive filter controls, including whether only hosts with results
+ * should be included.
+ */
+ if ((get->filt_id && strlen (get->filt_id)
+ && strcmp (get->filt_id, FILT_ID_NONE))
+ || (get->filter && strlen (get->filter)))
+ {
+ if (get->filt_id && strlen (get->filt_id)
+ && strcmp (get->filt_id, FILT_ID_NONE))
+ {
+ term = filter_term (get->filt_id);
+ if (term == NULL)
+ return 2;
+ }
+
+ manage_report_filter_controls (term ? term : get->filter,
+ &first_result,
+ &max_results,
+ &sort_field,
+ &sort_order,
+ &result_hosts_only,
+ &min_qod,
+ &levels,
+ &ctx.compliance_levels,
+ &delta_states,
+ &search_phrase,
+ &search_phrase_exact,
+ ¬es,
+ &overrides,
+ &apply_overrides,
+ &ctx.zone);
+ }
+ else
+ {
+ term = g_strdup ("");
+
+ manage_report_filter_controls (term,
+ &first_result,
+ &max_results,
+ &sort_field,
+ &sort_order,
+ &result_hosts_only,
+ &min_qod,
+ &levels,
+ &ctx.compliance_levels,
+ &delta_states,
+ &search_phrase,
+ &search_phrase_exact,
+ ¬es,
+ &overrides,
+ &apply_overrides,
+ &ctx.zone);
+ }
+
+ max_results = manage_max_rows (max_results, get->ignore_max_rows_per_page);
+ (void) first_result;
+ (void) max_results;
+ (void) sort_order;
+ (void) min_qod;
+ (void) search_phrase_exact;
+ (void) notes;
+ (void) overrides;
+ (void) apply_overrides;
+
+ if (mkdtemp (xml_dir) == NULL)
+ {
+ g_warning ("%s: mkdtemp failed", __func__);
+ ret = -1;
+ goto cleanup;
+ }
+
+ if (get->details && result_hosts_only)
+ {
+ ret = fill_filtered_result_hosts (&result_hosts,
+ get,
+ report,
+ &results,
+ is_container_scanning_report);
+ if (ret)
+ {
+ ret = -1;
+ goto cleanup;
+ }
+
+ results_initialized = 1;
+ }
+
+ xml_file = g_strdup_printf ("%s/report-hosts.xml", xml_dir);
+ stream = fopen (xml_file, "w");
+ if (stream == NULL)
+ {
+ g_warning ("%s: %s", __func__, strerror (errno));
+ ret = -1;
+ goto cleanup;
+ }
+
+ host_summary_buffer = g_string_new ("");
+
+ ret = print_report_hosts_xml (&ctx,
+ stream,
+ report,
+ get,
+ usage_type,
+ lean,
+ is_container_scanning_report,
+ result_hosts_only,
+ result_hosts,
+ host_summary_buffer);
+
+ if (host_summary_buffer)
+ {
+ g_string_free (host_summary_buffer, TRUE);
+ host_summary_buffer = NULL;
+ }
+
+ if (fclose (stream))
+ {
+ stream = NULL;
+ ret = -1;
+ goto cleanup;
+ }
+ stream = NULL;
+
+ if (ret)
+ {
+ ret = -1;
+ goto cleanup;
+ }
+
+ stream = fopen (xml_file, "r");
+ if (stream == NULL)
+ {
+ g_warning ("%s: %s", __func__, strerror (errno));
+ ret = -1;
+ goto cleanup;
+ }
+
+ while (1)
+ {
+ int left;
+ char *dest;
+
+ left = MANAGE_SEND_REPORT_CHUNK_SIZE;
+ dest = chunk;
+
+ while (1)
+ {
+ ret = fread (dest, 1, left, stream);
+ if (ferror (stream))
+ {
+ g_warning ("%s: error after fread", __func__);
+ ret = -1;
+ goto cleanup;
+ }
+
+ left -= ret;
+ if (left == 0 || feof (stream))
+ break;
+ dest += ret;
+ }
+
+ if (left < MANAGE_SEND_REPORT_CHUNK_SIZE)
+ {
+ chunk[MANAGE_SEND_REPORT_CHUNK_SIZE - left] = '\0';
+ if (send (chunk, send_data_1, send_data_2))
+ {
+ g_warning ("%s: send error", __func__);
+ ret = -1;
+ goto cleanup;
+ }
+ }
+
+ if (feof (stream))
+ break;
+ }
+
+ ret = 0;
+
+cleanup:
+ if (stream)
+ fclose (stream);
+
+ if (host_summary_buffer)
+ g_string_free (host_summary_buffer, TRUE);
+
+ if (results_initialized)
+ cleanup_iterator (&results);
+
+ if (result_hosts)
+ array_free (result_hosts);
+
+ g_free (xml_file);
+ g_free (term);
+ g_free (sort_field);
+ g_free (levels);
+ g_free (delta_states);
+ g_free (search_phrase);
+ g_free (min_qod);
+
+ print_report_context_cleanup (&ctx);
+
+ if (xml_dir[0] != '\0')
+ gvm_file_remove_recurse (xml_dir);
+
+ return ret;
+}
\ No newline at end of file
diff --git a/src/manage_report_hosts.h b/src/manage_report_hosts.h
new file mode 100644
index 000000000..dd9bb696f
--- /dev/null
+++ b/src/manage_report_hosts.h
@@ -0,0 +1,59 @@
+/* Copyright (C) 2026 Greenbone AG
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+/**
+ * @file
+ * @brief GVM management layer: Report hosts.
+ *
+ * Non-SQL report hosts code for the GVM management layer.
+ */
+
+#ifndef _GVM_MANAGE_REPORT_HOSTS_H
+#define _GVM_MANAGE_REPORT_HOSTS_H
+
+#include "iterator.h"
+#include "manage_resources.h"
+
+#include
+#include
+
+void
+init_report_host_iterator (iterator_t*, report_t, const char *, report_host_t);
+
+void
+init_report_host_iterator_hostname (iterator_t*, report_t, const char *,
+ const char *);
+
+const char*
+host_iterator_host (iterator_t*);
+
+const char*
+host_iterator_start_time (iterator_t*);
+
+const char*
+host_iterator_end_time (iterator_t*);
+
+int
+host_iterator_current_port (iterator_t*);
+
+int
+host_iterator_max_port (iterator_t*);
+
+int
+manage_send_report_hosts (report_t ,
+ const get_data_t *,
+ const gchar *,
+ gboolean,
+ int,
+ gboolean (*) (const char *,
+ int (*) (const char *, void *),
+ void *),
+ int (*) (const char *, void *),
+ void *);
+
+gchar *
+report_hosts_extra_where (const gchar *);
+
+#endif //_GVM_MANAGE_REPORT_HOSTS_H
diff --git a/src/manage_sql_assets.c b/src/manage_sql_assets.c
index c1b7e37c2..9a7d769c1 100644
--- a/src/manage_sql_assets.c
+++ b/src/manage_sql_assets.c
@@ -14,6 +14,7 @@
#include "manage_sql_oci_image_targets.h"
#endif
#include "manage_asset_keys.h"
+#include "manage_report_hosts.h"
#include "manage_sql_permissions.h"
#include "manage_sql_resources.h"
#include "manage_sql_settings.h"
From eb14c637113007bf368f7e16d2a4dbe6bdffd006 Mon Sep 17 00:00:00 2001
From: ozgen
Date: Thu, 2 Apr 2026 10:05:35 +0200
Subject: [PATCH 03/15] Add: add get_report_hosts GMP command
Introduce the get_report_hosts GMP command for retrieving host data
from a single report.
Support report_id, filter parsing and lean mode, and route the command
through the new management-layer report hosts handling.
---
src/gmp.c | 7 ++
src/gmp_get.c | 3 +
src/gmp_report_hosts.c | 202 +++++++++++++++++++++++++++++++++++++
src/gmp_report_hosts.h | 23 +++++
src/manage_commands.c | 1 +
src/manage_resources.c | 3 +-
src/manage_sql_resources.c | 8 ++
7 files changed, 246 insertions(+), 1 deletion(-)
create mode 100644 src/gmp_report_hosts.c
create mode 100644 src/gmp_report_hosts.h
diff --git a/src/gmp.c b/src/gmp.c
index e09e825b5..5363e5556 100644
--- a/src/gmp.c
+++ b/src/gmp.c
@@ -91,6 +91,7 @@
#include "gmp_port_lists.h"
#include "gmp_report_configs.h"
#include "gmp_report_formats.h"
+#include "gmp_report_hosts.h"
#include "gmp_tickets.h"
#include "gmp_tls_certificates.h"
#include "manage.h"
@@ -4549,6 +4550,7 @@ typedef enum
CLIENT_GET_REPORTS,
CLIENT_GET_REPORT_CONFIGS,
CLIENT_GET_REPORT_FORMATS,
+ CLIENT_GET_REPORT_HOSTS,
CLIENT_GET_RESOURCE_NAMES,
CLIENT_GET_RESULTS,
CLIENT_GET_ROLES,
@@ -5876,6 +5878,9 @@ gmp_xml_handle_start_element (/* unused */ GMarkupParseContext* context,
set_client_state (CLIENT_GET_REPORT_FORMATS);
}
+
+ ELSE_GET_START (report_hosts, REPORT_HOSTS)
+
else if (strcasecmp ("GET_RESOURCE_NAMES", element_name) == 0)
{
const gchar* typebuf;
@@ -22111,6 +22116,8 @@ gmp_xml_handle_end_element (/* unused */ GMarkupParseContext* context,
handle_get_report_formats (gmp_parser, error);
break;
+ CASE_GET_END (REPORT_HOSTS, report_hosts);
+
case CLIENT_GET_RESOURCE_NAMES:
handle_get_resource_names (gmp_parser, error);
break;
diff --git a/src/gmp_get.c b/src/gmp_get.c
index 68a4a14de..cd7242af6 100644
--- a/src/gmp_get.c
+++ b/src/gmp_get.c
@@ -600,6 +600,7 @@ send_get_end_internal (const char *type, get_data_t *get, int get_counts,
g_free (filter);
if ((strcmp (type, "task") == 0)
|| (strcmp (type, "report") == 0)
+ || (strcmp (type, "report_host") == 0)
|| (strcmp (type, "result") == 0)
|| (strcmp (type, "vuln") == 0))
{
@@ -618,6 +619,7 @@ send_get_end_internal (const char *type, get_data_t *get, int get_counts,
if ((strcmp (type, "task") == 0)
|| (strcmp (type, "report") == 0)
+ || (strcmp (type, "report_host") == 0)
|| (strcmp (type, "result") == 0))
{
value = filter_term_value (new_filter, "apply_overrides");
@@ -638,6 +640,7 @@ send_get_end_internal (const char *type, get_data_t *get, int get_counts,
{
if ((strcmp (type, "task") == 0)
|| (strcmp (type, "report") == 0)
+ || (strcmp (type, "report_host") == 0)
|| (strcmp (type, "result") == 0))
filter = manage_clean_filter("apply_overrides="
G_STRINGIFY (APPLY_OVERRIDES_DEFAULT)
diff --git a/src/gmp_report_hosts.c b/src/gmp_report_hosts.c
new file mode 100644
index 000000000..992a71560
--- /dev/null
+++ b/src/gmp_report_hosts.c
@@ -0,0 +1,202 @@
+/* Copyright (C) 2026 Greenbone AG
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include "gmp_report_hosts.h"
+
+#include "gmp_get.h"
+#include "manage.h"
+#include "manage_acl.h"
+
+
+/**
+ * @brief Command data for the get_report_hosts command.
+ */
+typedef struct
+{
+ get_data_t get; ///< Get args with host/result filtering.
+ char *report_id; ///< ID of single report to get.
+ int lean; ///< Boolean. Whether to return lean host data.
+} get_report_hosts_data_t;
+
+/**
+ * @brief Parser callback data.
+ *
+ * This is initially 0 because it's a global variable.
+ */
+static get_report_hosts_data_t get_report_hosts_data;
+
+
+/**
+ * @brief Reset the internal state of the command.
+ */
+static void
+get_report_hosts_reset ()
+{
+ get_data_reset (&get_report_hosts_data.get);
+ g_free (get_report_hosts_data.report_id);
+ memset (&get_report_hosts_data, 0, sizeof (get_report_hosts_data));
+}
+
+/**
+ * @brief Initialize the GMP command by parsing attributes.
+ *
+ * @param[in] attribute_names Null-terminated array of attribute names.
+ * @param[in] attribute_values Null-terminated array of corresponding attribute values.
+ */
+void
+get_report_hosts_start (const gchar **attribute_names,
+ const gchar **attribute_values)
+{
+ const gchar *attribute;
+
+ get_data_parse_attributes (&get_report_hosts_data.get,
+ "report_host",
+ attribute_names,
+ attribute_values);
+
+ if (find_attribute (attribute_names, attribute_values,
+ "report_id", &attribute))
+ {
+ get_report_hosts_data.report_id = g_strdup (attribute);
+
+ get_data_set_extra (&get_report_hosts_data.get, "report_id",
+ g_strdup (attribute));
+ }
+ if (find_attribute (attribute_names, attribute_values,
+ "lean", &attribute))
+ get_report_hosts_data.lean = strcmp (attribute, "0");
+ else
+ get_report_hosts_data.lean = 0;
+}
+
+/**
+ * @brief Execute the GMP command.
+ *
+ * @param[in] gmp_parser Pointer to the GMP parser handling the current session.
+ * @param[in] error Location to store error information, if any occurs.
+ */
+void
+get_report_hosts_run (gmp_parser_t *gmp_parser, GError **error)
+{
+ report_t report;
+ task_t task;
+ gchar *usage_type;
+ gboolean is_container_scanning_report = FALSE;
+ int ret, filtered, count;
+
+ count = 0;
+ usage_type = NULL;
+ is_container_scanning_report = FALSE;
+
+ if (get_report_hosts_data.report_id == NULL)
+ {
+ SEND_TO_CLIENT_OR_FAIL
+ (XML_ERROR_SYNTAX ("get_report_hosts",
+ "Missing report_id attribute"));
+ get_report_hosts_reset ();
+ return;
+ }
+
+ ret = init_get ("get_report_hosts",
+ &get_report_hosts_data.get,
+ "Report Hosts",
+ NULL);
+ if (ret)
+ {
+ switch (ret)
+ {
+ case 99:
+ SEND_TO_CLIENT_OR_FAIL
+ (XML_ERROR_SYNTAX ("get_report_hosts",
+ "Permission denied"));
+ break;
+ default:
+ internal_error_send_to_client (error);
+ get_report_hosts_reset ();
+ return;
+ }
+ get_report_hosts_reset ();
+ return;
+ }
+
+ if (find_report_with_permission (get_report_hosts_data.report_id,
+ &report,
+ "get_reports"))
+ {
+ internal_error_send_to_client (error);
+ get_report_hosts_reset ();
+ return;
+ }
+
+ if (report == 0)
+ {
+ if (send_find_error_to_client ("get_report_hosts",
+ "report",
+ get_report_hosts_data.report_id,
+ gmp_parser))
+ error_send_to_client (error);
+ get_report_hosts_reset ();
+ return;
+ }
+
+ if (report_task (report, &task))
+ {
+ internal_error_send_to_client (error);
+ get_report_hosts_reset ();
+ return;
+ }
+
+ task_usage_type (task, &usage_type);
+ if (usage_type == NULL)
+ usage_type = g_strdup ("");
+
+#if ENABLE_CONTAINER_SCANNING
+ oci_image_target_t oci_image_target = task_oci_image_target (task);
+ if (oci_image_target)
+ {
+ is_container_scanning_report = TRUE;
+ }
+#endif
+
+ SEND_GET_START ("report_host");
+
+ ret = manage_send_report_hosts (
+ report,
+ &get_report_hosts_data.get,
+ usage_type,
+ is_container_scanning_report,
+ get_report_hosts_data.lean,
+ send_to_client,
+ gmp_parser->client_writer,
+ gmp_parser->client_writer_data);
+
+ g_free (usage_type);
+
+ if (ret)
+ {
+ switch (ret)
+ {
+ case 2:
+ if (send_find_error_to_client ("get_report_hosts",
+ "filter",
+ get_report_hosts_data.get.filt_id,
+ gmp_parser))
+ error_send_to_client (error);
+ break;
+ default:
+ internal_error_send_to_client (error);
+ break;
+ }
+ get_report_hosts_reset ();
+ return;
+ }
+
+ filtered = get_report_hosts_data.get.id
+ ? 1
+ : report_host_count (report);
+ SEND_GET_END ("report_host", &get_report_hosts_data.get, count, filtered);
+
+ get_report_hosts_reset ();
+}
\ No newline at end of file
diff --git a/src/gmp_report_hosts.h b/src/gmp_report_hosts.h
new file mode 100644
index 000000000..e8e0d2ad5
--- /dev/null
+++ b/src/gmp_report_hosts.h
@@ -0,0 +1,23 @@
+/* Copyright (C) 2026 Greenbone AG
+ *
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#ifndef _GVM_GMP_REPORT_HOSTS_H
+#define _GVM_GMP_REPORT_HOSTS_H
+
+#include "gmp_base.h"
+
+#include
+#include
+
+/* GET_REPORT_HOSTS. */
+
+void
+get_report_hosts_start (const gchar **,
+ const gchar **);
+
+void
+get_report_hosts_run (gmp_parser_t *gmp_parser, GError **error);
+
+#endif //_GVM_GMP_REPORT_HOSTS_H
diff --git a/src/manage_commands.c b/src/manage_commands.c
index f743b9b4e..962b3b583 100644
--- a/src/manage_commands.c
+++ b/src/manage_commands.c
@@ -125,6 +125,7 @@ command_t gmp_commands[]
{"GET_REPORTS", "Get all reports."},
{"GET_REPORT_CONFIGS", "Get all report configs."},
{"GET_REPORT_FORMATS", "Get all report formats."},
+ {"GET_REPORT_HOSTS", "Get all report hosts for specific report."},
{"GET_RESULTS", "Get results."},
{"GET_ROLES", "Get all roles."},
{"GET_SCANNERS", "Get all scanners."},
diff --git a/src/manage_resources.c b/src/manage_resources.c
index 173158db0..4fa4f6d92 100644
--- a/src/manage_resources.c
+++ b/src/manage_resources.c
@@ -311,7 +311,8 @@ type_owned (const char* type)
{
return strcasecmp (type, "info")
&& type_is_info_subtype (type) == 0
- && strcasecmp (type, "vuln");
+ && strcasecmp (type, "vuln")
+ && strcasecmp (type, "report_host");
}
/**
diff --git a/src/manage_sql_resources.c b/src/manage_sql_resources.c
index 2a63e0862..5d41a60aa 100644
--- a/src/manage_sql_resources.c
+++ b/src/manage_sql_resources.c
@@ -771,6 +771,14 @@ resource_count (const char *type, const get_data_t *get)
const gchar *usage_type = get_data_get_extra (get, "usage_type");
extra_where = reports_extra_where (0, NULL, usage_type);
}
+ else if (strcmp (type, "report_host") == 0)
+ {
+ const gchar *report_uuid = get_data_get_extra (get, "report_id");
+ if (!str_blank (report_uuid))
+ {
+ extra_where = report_hosts_extra_where (report_uuid);
+ }
+ }
else if (strcmp (type, "result") == 0)
{
extra_where
From 2f4f5d5d643f25b541f184e3dc1f90c8f922b834 Mon Sep 17 00:00:00 2001
From: ozgen
Date: Thu, 2 Apr 2026 10:05:56 +0200
Subject: [PATCH 04/15] docs: add GMP documentation for get_report_hosts
---
src/schema_formats/XML/GMP.xml.in | 567 ++++++++++++++++++++++++++++++
1 file changed, 567 insertions(+)
diff --git a/src/schema_formats/XML/GMP.xml.in b/src/schema_formats/XML/GMP.xml.in
index 6a0752bb1..bb03a5c65 100644
--- a/src/schema_formats/XML/GMP.xml.in
+++ b/src/schema_formats/XML/GMP.xml.in
@@ -21486,6 +21486,573 @@ END:VCALENDAR
+
+ get_report_hosts
+ Get hosts from a report
+
+
+ The client uses the get_report_hosts command to get host information
+ from a single report.
+
+
+ This command is a host-focused subset of get_reports intended to support
+ pagination and reduced response sizes when only host data is needed.
+
+
+ If the "details" attribute is set, the response includes host entries.
+ Otherwise only filter, sort and count information is returned.
+
+
+
+
+ report_id
+ ID of the report to get hosts from
+ uuid
+ 1
+
+
+ filter
+ Filter term to use to filter report hosts
+ text
+
+
+ first
+ integer
+
+ Index of the first item returned, starting at 1 (e.g. first=5
+ starts at the 5th item)
+
+
+
+ rows
+ integer
+ Number of items to return
+
+
+ sort
+ text
+ Column to sort by in ascending order
+
+
+ sort-reverse
+ text
+ Column to sort by in descending order
+
+
+ apply_overrides
+ boolean
+ Whether to apply Overrides
+
+
+ min_qod
+ integer
+ Minimum QoD of the results
+
+
+ levels
+ levels
+ Severity levels to select
+
+
+ result_hosts_only
+ boolean
+
+ Whether to limit the response to hosts having results matching the
+ filter
+
+
+
+ uuid
+ uuid
+ Unique ID
+
+
+ ip
+ text
+ IP address of the host
+
+
+ asset_id
+ uuid
+ UUID of the associated asset
+
+
+ start
+ iso_time
+ Host scan start time
+
+
+ end
+ iso_time
+ Host scan end time
+
+
+ severity
+ severity
+ Highest severity of matching results for the host
+
+
+
+
+ filt_id
+ ID of filter to use to filter report hosts
+ uuid
+
+
+ details
+ Whether to include host details
+ boolean
+
+
+
+
+
+ status
+ status
+ 1
+
+
+ status_text
+ text
+ 1
+
+ host
+ filters
+ sort
+ report_hosts
+ report_host_count
+
+
+ host
+ A host from the selected report
+
+ ip
+ asset
+ start
+ end
+ port_count
+ result_count
+ detail
+
+
+ ip
+ IP address of the host
+ text
+
+
+ asset
+ Asset associated with the host
+
+
+ asset_id
+ uuid
+ 1
+
+
+
+
+ start
+ Host scan start time
+ iso_time
+
+
+ end
+ Host scan end time
+ iso_time
+
+
+ port_count
+ Count of ports on the current page
+
+ page
+
+
+ page
+ Number of ports on the current page
+ integer
+
+
+
+ result_count
+ Counts of results for the host on the current page
+
+ page
+ critical
+ hole
+ high
+ warning
+ medium
+ info
+ low
+ log
+ false_positive
+
+
+ page
+ Number of results on the current page
+ integer
+
+
+ critical
+ page
+
+ page
+ integer
+
+
+
+ hole
+
+
+ deprecated
+ boolean
+
+ page
+
+
+ page
+ integer
+
+
+
+ high
+ page
+
+ page
+ integer
+
+
+
+ warning
+
+
+ deprecated
+ boolean
+
+ page
+
+
+ page
+ integer
+
+
+
+ medium
+ page
+
+ page
+ integer
+
+
+
+ info
+
+
+ deprecated
+ boolean
+
+ page
+
+
+ page
+ integer
+
+
+
+ low
+ page
+
+ page
+ integer
+
+
+
+ log
+ page
+
+ page
+ integer
+
+
+
+ false_positive
+ page
+
+ page
+ integer
+
+
+
+
+ detail
+ A detail of the host
+
+ name
+ value
+ source
+ extra
+
+
+ name
+ Name of the host detail
+ text
+
+
+ value
+ Value of the host detail
+ text
+
+
+ source
+ Source of the host detail
+
+ type
+ name
+ description
+
+
+ type
+ Type of source
+ text
+
+
+ name
+ Name of source
+ text
+
+
+ description
+ Description of source
+ text
+
+
+
+ extra
+ Extra information for the detail
+ text
+
+
+
+
+ filters
+
+
+ id
+ UUID of filter if any, else empty or 0
+ uuid
+
+ term
+ keywords
+
+
+ term
+ Filter term
+ text
+
+
+ keywords
+ Filter broken down into keywords
+ keyword
+
+ keyword
+
+ column
+ relation
+ value
+
+
+ column
+ Column prefix
+ text
+
+
+ relation
+ Relation operator
+
+
+ =
+ :
+ ~
+ >
+ <
+
+
+
+
+ value
+ The filter text
+ text
+
+
+
+
+
+ sort
+
+ text
+ field
+
+
+ field
+
+ text
+ order
+
+
+ order
+
+
+ ascending
+ descending
+
+
+
+
+
+
+ report_hosts
+
+
+ start
+ First report host
+ integer
+ 1
+
+
+ max
+ Maximum number of report hosts
+ integer
+ 1
+
+
+
+
+ report_host_count
+
+ text
+ filtered
+ page
+
+
+ filtered
+ Number of report hosts after filtering
+ integer
+
+
+ page
+ Number of report hosts on current page
+ integer
+
+
+
+
+ Get hosts of a report with details
+
+
+
+
+
+
+
+ 192.168.178.87
+
+ 2026-03-30T06:44:34Z
+ 2026-03-30T06:45:44Z
+
+ 0
+
+
+ 0
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+
+ hostname
+ levoit-purifier.fritz.box
+
+ nvt
+ 1.3.6.1.4.1.25623.1.0.103997
+ Host Details
+
+
+
+
+
+ apply_overrides=0 levels=chml rows=100 min_qod=70 first=1 sort-reverse=severity result_hosts_only=0
+
+
+ apply_overrides
+ =
+ 0
+
+
+ levels
+ =
+ chml
+
+
+ rows
+ =
+ 100
+
+
+ min_qod
+ =
+ 70
+
+
+ first
+ =
+ 1
+
+
+ sort-reverse
+ =
+ severity
+
+
+ result_hosts_only
+ =
+ 0
+
+
+
+
+ severitydescending
+
+
+ 11 0
+
+
+
+
get_reports
Get one or many reports
From 0407b08af94d9c91ed314198dc8f0cc65bfffb98 Mon Sep 17 00:00:00 2001
From: ozgen
Date: Thu, 2 Apr 2026 10:20:44 +0200
Subject: [PATCH 05/15] fix: initialize host ports table for report host output
in manage_send_report_hosts
---
src/manage_report_hosts.c | 5 ++++-
src/manage_sql.c | 1 -
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/src/manage_report_hosts.c b/src/manage_report_hosts.c
index ee2bc03fd..ccb4aa7b1 100644
--- a/src/manage_report_hosts.c
+++ b/src/manage_report_hosts.c
@@ -88,7 +88,6 @@ manage_send_report_hosts (report_t report,
results_initialized = 0;
result_hosts_only = 0;
-
if (get == NULL)
{
g_warning ("%s: get is NULL", __func__);
@@ -101,6 +100,10 @@ manage_send_report_hosts (report_t report,
print_report_init_f_hosts (&ctx);
+ // Initialize host_ports
+ ctx.f_host_ports = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+
/* Derive filter controls, including whether only hosts with results
* should be included.
*/
diff --git a/src/manage_sql.c b/src/manage_sql.c
index 0babef986..77d13bfa7 100644
--- a/src/manage_sql.c
+++ b/src/manage_sql.c
@@ -15692,7 +15692,6 @@ print_report_context_cleanup (print_report_context_t *ctx)
free_f_host (ctx->f_host_undefined);
}
-
/**
* @brief Init the f_hosts_* hashtables.
*
From d9d904939f43c0f8b845aeab8361cc771f5c7f35 Mon Sep 17 00:00:00 2001
From: ozgen
Date: Thu, 2 Apr 2026 10:24:33 +0200
Subject: [PATCH 06/15] add missing log context in gmp_report_hosts.c
---
src/gmp_report_hosts.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/gmp_report_hosts.c b/src/gmp_report_hosts.c
index 992a71560..b3fab34fa 100644
--- a/src/gmp_report_hosts.c
+++ b/src/gmp_report_hosts.c
@@ -9,6 +9,11 @@
#include "manage.h"
#include "manage_acl.h"
+#undef G_LOG_DOMAIN
+/**
+ * @brief GLib log domain.
+ */
+#define G_LOG_DOMAIN "md gmp"
/**
* @brief Command data for the get_report_hosts command.
From 55d8c58cac274db94425c3d59b718e2a641a941a Mon Sep 17 00:00:00 2001
From: ozgen
Date: Thu, 2 Apr 2026 11:36:47 +0200
Subject: [PATCH 07/15] Simplify manage_send_report_hosts function arguments
---
src/gmp_report_hosts.c | 4 +---
src/manage_report_hosts.c | 13 ++++---------
src/manage_report_hosts.h | 8 +++-----
3 files changed, 8 insertions(+), 17 deletions(-)
diff --git a/src/gmp_report_hosts.c b/src/gmp_report_hosts.c
index b3fab34fa..68be0620c 100644
--- a/src/gmp_report_hosts.c
+++ b/src/gmp_report_hosts.c
@@ -173,9 +173,7 @@ get_report_hosts_run (gmp_parser_t *gmp_parser, GError **error)
usage_type,
is_container_scanning_report,
get_report_hosts_data.lean,
- send_to_client,
- gmp_parser->client_writer,
- gmp_parser->client_writer_data);
+ gmp_parser);
g_free (usage_type);
diff --git a/src/manage_report_hosts.c b/src/manage_report_hosts.c
index ccb4aa7b1..e63f1536e 100644
--- a/src/manage_report_hosts.c
+++ b/src/manage_report_hosts.c
@@ -32,9 +32,7 @@
* @param[in] usage_type Task usage type.
* @param[in] is_container_scanning_report Whether this is a container scan report.
* @param[in] lean Whether to send lean host data.
- * @param[in] send Function to write to client.
- * @param[in] send_data_1 Second argument to @p send.
- * @param[in] send_data_2 Third argument to @p send.
+ * @param[in] parser gmp_parser_t to write to client.
*
* @return 0 on success, -1 on error, 2 if filter was not found.
*/
@@ -44,11 +42,7 @@ manage_send_report_hosts (report_t report,
const gchar *usage_type,
gboolean is_container_scanning_report,
int lean,
- gboolean (*send) (const char *,
- int (*) (const char *, void *),
- void *),
- int (*send_data_1) (const char *, void *),
- void *send_data_2)
+ gmp_parser_t *parser)
{
print_report_context_t ctx;
gchar *xml_file;
@@ -268,7 +262,8 @@ manage_send_report_hosts (report_t report,
if (left < MANAGE_SEND_REPORT_CHUNK_SIZE)
{
chunk[MANAGE_SEND_REPORT_CHUNK_SIZE - left] = '\0';
- if (send (chunk, send_data_1, send_data_2))
+ if (send_to_client (chunk, parser->client_writer,
+ parser->client_writer_data))
{
g_warning ("%s: send error", __func__);
ret = -1;
diff --git a/src/manage_report_hosts.h b/src/manage_report_hosts.h
index dd9bb696f..6a4263480 100644
--- a/src/manage_report_hosts.h
+++ b/src/manage_report_hosts.h
@@ -19,6 +19,8 @@
#include
#include
+#include "gmp_base.h"
+
void
init_report_host_iterator (iterator_t*, report_t, const char *, report_host_t);
@@ -47,11 +49,7 @@ manage_send_report_hosts (report_t ,
const gchar *,
gboolean,
int,
- gboolean (*) (const char *,
- int (*) (const char *, void *),
- void *),
- int (*) (const char *, void *),
- void *);
+ gmp_parser_t *);
gchar *
report_hosts_extra_where (const gchar *);
From 45d7914b356f7a09fc704671e21f95d339319c8c Mon Sep 17 00:00:00 2001
From: ozgen
Date: Thu, 2 Apr 2026 13:11:27 +0200
Subject: [PATCH 08/15] fix formatting and sort C source files alphabetically
in CMakeLists.txt
---
src/CMakeLists.txt | 6 +++---
src/gmp_get.c | 2 +-
src/gmp_report_hosts.h | 5 ++---
src/manage_report_hosts.h | 14 +++++++-------
src/manage_sql.h | 8 ++++----
src/manage_sql_report_hosts.h | 31 +++++++++++++++----------------
6 files changed, 32 insertions(+), 34 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 05111d852..845c1d984 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -280,16 +280,16 @@ set(
gmp_configs.c
gmp_delete.c
gmp_get.c
+ gmp_integration_configs.c
gmp_license.c
gmp_logout.c
+ gmp_oci_image_targets.c
gmp_port_lists.c
gmp_report_configs.c
gmp_report_formats.c
+ gmp_report_hosts.c
gmp_tickets.c
gmp_tls_certificates.c
- gmp_oci_image_targets.c
- gmp_integration_configs.c
- gmp_report_hosts.c
)
if(ENABLE_AGENTS)
diff --git a/src/gmp_get.c b/src/gmp_get.c
index cd7242af6..903062181 100644
--- a/src/gmp_get.c
+++ b/src/gmp_get.c
@@ -619,7 +619,7 @@ send_get_end_internal (const char *type, get_data_t *get, int get_counts,
if ((strcmp (type, "task") == 0)
|| (strcmp (type, "report") == 0)
- || (strcmp (type, "report_host") == 0)
+ || (strcmp (type, "report_host") == 0)
|| (strcmp (type, "result") == 0))
{
value = filter_term_value (new_filter, "apply_overrides");
diff --git a/src/gmp_report_hosts.h b/src/gmp_report_hosts.h
index e8e0d2ad5..88c6c0b60 100644
--- a/src/gmp_report_hosts.h
+++ b/src/gmp_report_hosts.h
@@ -14,10 +14,9 @@
/* GET_REPORT_HOSTS. */
void
-get_report_hosts_start (const gchar **,
- const gchar **);
+get_report_hosts_start (const gchar **, const gchar **);
void
-get_report_hosts_run (gmp_parser_t *gmp_parser, GError **error);
+get_report_hosts_run (gmp_parser_t *, GError **);
#endif //_GVM_GMP_REPORT_HOSTS_H
diff --git a/src/manage_report_hosts.h b/src/manage_report_hosts.h
index 6a4263480..77bd5bae3 100644
--- a/src/manage_report_hosts.h
+++ b/src/manage_report_hosts.h
@@ -22,26 +22,26 @@
#include "gmp_base.h"
void
-init_report_host_iterator (iterator_t*, report_t, const char *, report_host_t);
+init_report_host_iterator (iterator_t *, report_t, const char *, report_host_t);
void
-init_report_host_iterator_hostname (iterator_t*, report_t, const char *,
+init_report_host_iterator_hostname (iterator_t *, report_t, const char *,
const char *);
const char*
-host_iterator_host (iterator_t*);
+host_iterator_host (iterator_t *);
const char*
-host_iterator_start_time (iterator_t*);
+host_iterator_start_time (iterator_t *);
const char*
-host_iterator_end_time (iterator_t*);
+host_iterator_end_time (iterator_t *);
int
-host_iterator_current_port (iterator_t*);
+host_iterator_current_port (iterator_t *);
int
-host_iterator_max_port (iterator_t*);
+host_iterator_max_port (iterator_t *);
int
manage_send_report_hosts (report_t ,
diff --git a/src/manage_sql.h b/src/manage_sql.h
index 3534cb8d9..a2f080da0 100644
--- a/src/manage_sql.h
+++ b/src/manage_sql.h
@@ -615,9 +615,9 @@ void
print_report_context_cleanup (print_report_context_t *);
const char *
-report_compliance_from_counts (const int*,
- const int*,
- const int*,
- const int*);
+report_compliance_from_counts (const int *,
+ const int *,
+ const int *,
+ const int *);
#endif /* not _GVMD_MANAGE_SQL_H */
diff --git a/src/manage_sql_report_hosts.h b/src/manage_sql_report_hosts.h
index 9abf35d45..d484804c6 100644
--- a/src/manage_sql_report_hosts.h
+++ b/src/manage_sql_report_hosts.h
@@ -16,24 +16,23 @@
#include "manage_report_hosts.h"
#include "manage_sql.h"
-
int
-print_report_hosts_xml(print_report_context_t*,
- FILE*,
- report_t,
- const get_data_t*,
- const gchar*,
- int lean,
- gboolean,
- gboolean,
- array_t*,
- GString*);
+print_report_hosts_xml (print_report_context_t *,
+ FILE *,
+ report_t,
+ const get_data_t *,
+ const gchar *,
+ int lean,
+ gboolean,
+ gboolean,
+ array_t *,
+ GString *);
int
-fill_filtered_result_hosts(array_t**,
- const get_data_t*,
- report_t,
- iterator_t*,
- gboolean);
+fill_filtered_result_hosts (array_t **,
+ const get_data_t *,
+ report_t,
+ iterator_t *,
+ gboolean);
#endif /* _GVM_MANAGE_SQL_REPORT_HOSTS_H */
From 36fa26d9ef917db62a53d9097dfe3b1e29ab8a9b Mon Sep 17 00:00:00 2001
From: ozgen
Date: Thu, 2 Apr 2026 23:38:09 +0200
Subject: [PATCH 09/15] simplify report host XML flow and container flag
handling
---
src/manage_sql.c | 32 +++-----------------------------
1 file changed, 3 insertions(+), 29 deletions(-)
diff --git a/src/manage_sql.c b/src/manage_sql.c
index 1dfdafb39..93177618b 100644
--- a/src/manage_sql.c
+++ b/src/manage_sql.c
@@ -16408,9 +16408,7 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
int f_compliance_count;
print_report_context_t ctx = {0};
- #if ENABLE_CONTAINER_SCANNING
gboolean is_container_scanning_report = FALSE;
- #endif
/* Init some vars to prevent warnings from older compilers. */
max_results = -1;
@@ -17421,27 +17419,7 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
else
host_summary_buffer = NULL;
- if (get->details && result_hosts_only)
- {
- if (print_report_hosts_xml (&ctx,
- out,
- report,
- get,
- ctx.tsk_usage_type,
- lean,
- #if ENABLE_CONTAINER_SCANNING
- is_container_scanning_report,
- #else
- FALSE,
- #endif
- TRUE, /* result_hosts_only */
- result_hosts, /* result_hosts */
- host_summary_buffer))
- {
- goto failed_print_report_host;
- }
- }
- else if (get->details)
+ if (get->details)
{
if (print_report_hosts_xml (&ctx,
out,
@@ -17449,13 +17427,9 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
get,
ctx.tsk_usage_type,
lean,
- #if ENABLE_CONTAINER_SCANNING
is_container_scanning_report,
- #else
- FALSE,
- #endif
- FALSE, /* result_hosts_only */
- NULL, /* result_hosts */
+ result_hosts_only,
+ result_hosts,
host_summary_buffer))
{
goto failed_print_report_host;
From f5c2980f1005dfd0f484a053530638544e70f027 Mon Sep 17 00:00:00 2001
From: ozgen mehmet
Date: Fri, 3 Apr 2026 13:21:40 +0200
Subject: [PATCH 10/15] Update manage_report_hosts.c
Co-authored-by: Matt Mundell <32057441+mattmundell@users.noreply.github.com>
---
src/manage_report_hosts.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/manage_report_hosts.c b/src/manage_report_hosts.c
index e63f1536e..e30ef5b25 100644
--- a/src/manage_report_hosts.c
+++ b/src/manage_report_hosts.c
@@ -10,9 +10,8 @@
* Non-SQL report hosts code for the GVM management layer.
*/
-#include "manage_filters.h"
#include "manage_report_hosts.h"
-
+#include "manage_filters.h"
#include "manage_settings.h"
#include "manage_sql_report_hosts.h"
From 2c9c7f4033ccc9052ba08b41708beda655970b70 Mon Sep 17 00:00:00 2001
From: ozgen
Date: Fri, 3 Apr 2026 14:40:56 +0200
Subject: [PATCH 11/15] change: share filter setup and clean up temp dir
handling
Extract duplicated report filter control setup into a shared helper
and use it in manage_report_hosts and manage_sql_report_hosts.
Remove duplicate initialization in gmp_report_hosts.c and guard
temporary directory cleanup with a dedicated mkdtemp success flag.
---
src/gmp_report_hosts.c | 5 +-
src/manage_filters.h | 5 ++
src/manage_report_hosts.c | 116 ++++++++++++--------------------------
src/manage_report_hosts.h | 8 ++-
src/manage_sql.c | 55 +++++++-----------
src/manage_sql_filters.c | 111 ++++++++++++++++++++++++++++++++++++
6 files changed, 181 insertions(+), 119 deletions(-)
diff --git a/src/gmp_report_hosts.c b/src/gmp_report_hosts.c
index 68be0620c..684e46a1a 100644
--- a/src/gmp_report_hosts.c
+++ b/src/gmp_report_hosts.c
@@ -93,7 +93,6 @@ get_report_hosts_run (gmp_parser_t *gmp_parser, GError **error)
count = 0;
usage_type = NULL;
- is_container_scanning_report = FALSE;
if (get_report_hosts_data.report_id == NULL)
{
@@ -173,7 +172,9 @@ get_report_hosts_run (gmp_parser_t *gmp_parser, GError **error)
usage_type,
is_container_scanning_report,
get_report_hosts_data.lean,
- gmp_parser);
+ send_to_client,
+ gmp_parser->client_writer,
+ gmp_parser->client_writer_data);
g_free (usage_type);
diff --git a/src/manage_filters.h b/src/manage_filters.h
index 63ac36095..98658c621 100644
--- a/src/manage_filters.h
+++ b/src/manage_filters.h
@@ -26,6 +26,11 @@ void
manage_report_filter_controls (const gchar *, int *, int *, gchar **, int *,
int *, gchar **, gchar **, gchar **, gchar **,
gchar **, int *, int *, int *, int *, gchar **);
+int
+manage_report_filter_controls_from_get (const get_data_t *, gchar **, int *,
+ int *, gchar **, int *, int *, gchar **,
+ gchar **, gchar **, gchar **, gchar **,
+ int *, int *, int *, int *, gchar **);
gchar *
manage_clean_filter (const gchar *, int);
diff --git a/src/manage_report_hosts.c b/src/manage_report_hosts.c
index e30ef5b25..558eadb27 100644
--- a/src/manage_report_hosts.c
+++ b/src/manage_report_hosts.c
@@ -15,7 +15,7 @@
#include "manage_settings.h"
#include "manage_sql_report_hosts.h"
-#include
+#include
#undef G_LOG_DOMAIN
/**
@@ -31,7 +31,9 @@
* @param[in] usage_type Task usage type.
* @param[in] is_container_scanning_report Whether this is a container scan report.
* @param[in] lean Whether to send lean host data.
- * @param[in] parser gmp_parser_t to write to client.
+ * @param[in] send Function to write to client.
+ * @param[in] send_data_1 Second argument to @p send.
+ * @param[in] send_data_2 Third argument to @p send.
*
* @return 0 on success, -1 on error, 2 if filter was not found.
*/
@@ -41,7 +43,11 @@ manage_send_report_hosts (report_t report,
const gchar *usage_type,
gboolean is_container_scanning_report,
int lean,
- gmp_parser_t *parser)
+ gboolean (*send) (const char *,
+ int (*) (const char *, void *),
+ void *),
+ int (*send_data_1) (const char *, void *),
+ void *send_data_2)
{
print_report_context_t ctx;
gchar *xml_file;
@@ -51,17 +57,10 @@ manage_send_report_hosts (report_t report,
gchar *delta_states;
gchar *search_phrase;
char xml_dir[] = "/tmp/gvmd_XXXXXX";
+ gboolean xml_dir_created = FALSE;
char chunk[MANAGE_SEND_REPORT_CHUNK_SIZE + 1];
FILE *stream;
int ret;
- int first_result;
- int max_results;
- int sort_order;
- gchar *min_qod;
- int apply_overrides;
- int search_phrase_exact;
- int notes;
- int overrides;
int result_hosts_only;
array_t *result_hosts;
iterator_t results;
@@ -91,75 +90,34 @@ manage_send_report_hosts (report_t report,
ctx.report = report;
ctx.tsk_usage_type = g_strdup (usage_type);
- print_report_init_f_hosts (&ctx);
-
- // Initialize host_ports
- ctx.f_host_ports = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, NULL);
-
/* Derive filter controls, including whether only hosts with results
* should be included.
*/
- if ((get->filt_id && strlen (get->filt_id)
- && strcmp (get->filt_id, FILT_ID_NONE))
- || (get->filter && strlen (get->filter)))
- {
- if (get->filt_id && strlen (get->filt_id)
- && strcmp (get->filt_id, FILT_ID_NONE))
- {
- term = filter_term (get->filt_id);
- if (term == NULL)
- return 2;
- }
+ ret = manage_report_filter_controls_from_get (get,
+ &term,
+ NULL,
+ NULL,
+ &sort_field,
+ NULL,
+ &result_hosts_only,
+ NULL,
+ &levels,
+ &ctx.compliance_levels,
+ &delta_states,
+ &search_phrase,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &ctx.zone);
+ if (ret)
+ goto cleanup;
- manage_report_filter_controls (term ? term : get->filter,
- &first_result,
- &max_results,
- &sort_field,
- &sort_order,
- &result_hosts_only,
- &min_qod,
- &levels,
- &ctx.compliance_levels,
- &delta_states,
- &search_phrase,
- &search_phrase_exact,
- ¬es,
- &overrides,
- &apply_overrides,
- &ctx.zone);
- }
- else
- {
- term = g_strdup ("");
-
- manage_report_filter_controls (term,
- &first_result,
- &max_results,
- &sort_field,
- &sort_order,
- &result_hosts_only,
- &min_qod,
- &levels,
- &ctx.compliance_levels,
- &delta_states,
- &search_phrase,
- &search_phrase_exact,
- ¬es,
- &overrides,
- &apply_overrides,
- &ctx.zone);
- }
+ print_report_init_f_hosts (&ctx);
- max_results = manage_max_rows (max_results, get->ignore_max_rows_per_page);
- (void) first_result;
- (void) max_results;
- (void) sort_order;
- (void) min_qod;
- (void) search_phrase_exact;
- (void) notes;
- (void) overrides;
- (void) apply_overrides;
+ // Initialize host_ports
+ ctx.f_host_ports = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
if (mkdtemp (xml_dir) == NULL)
{
@@ -168,6 +126,8 @@ manage_send_report_hosts (report_t report,
goto cleanup;
}
+ xml_dir_created = TRUE;
+
if (get->details && result_hosts_only)
{
ret = fill_filtered_result_hosts (&result_hosts,
@@ -261,8 +221,7 @@ manage_send_report_hosts (report_t report,
if (left < MANAGE_SEND_REPORT_CHUNK_SIZE)
{
chunk[MANAGE_SEND_REPORT_CHUNK_SIZE - left] = '\0';
- if (send_to_client (chunk, parser->client_writer,
- parser->client_writer_data))
+ if (send (chunk, send_data_1, send_data_2))
{
g_warning ("%s: send error", __func__);
ret = -1;
@@ -295,11 +254,10 @@ manage_send_report_hosts (report_t report,
g_free (levels);
g_free (delta_states);
g_free (search_phrase);
- g_free (min_qod);
print_report_context_cleanup (&ctx);
- if (xml_dir[0] != '\0')
+ if (xml_dir_created)
gvm_file_remove_recurse (xml_dir);
return ret;
diff --git a/src/manage_report_hosts.h b/src/manage_report_hosts.h
index 77bd5bae3..c16032b1b 100644
--- a/src/manage_report_hosts.h
+++ b/src/manage_report_hosts.h
@@ -19,8 +19,6 @@
#include
#include
-#include "gmp_base.h"
-
void
init_report_host_iterator (iterator_t *, report_t, const char *, report_host_t);
@@ -49,7 +47,11 @@ manage_send_report_hosts (report_t ,
const gchar *,
gboolean,
int,
- gmp_parser_t *);
+ gboolean (*)(const char*,
+ int (*)(const char*, void*),
+ void*),
+ int (*) (const char *, void *),
+ void *);
gchar *
report_hosts_extra_where (const gchar *);
diff --git a/src/manage_sql.c b/src/manage_sql.c
index 93177618b..6627bd2b1 100644
--- a/src/manage_sql.c
+++ b/src/manage_sql.c
@@ -16455,42 +16455,27 @@ print_report_xml_start (report_t report, report_t delta, task_t task,
assert (get);
- if ((get->filt_id && strlen (get->filt_id)
- && strcmp (get->filt_id, FILT_ID_NONE))
- || (get->filter && strlen (get->filter)))
- {
- term = NULL;
- if (get->filt_id && strlen (get->filt_id)
- && strcmp (get->filt_id, FILT_ID_NONE))
- {
- term = filter_term (get->filt_id);
- if (term == NULL)
- {
- fclose (out);
- return 2;
- }
- }
-
- /* Set the filter parameters from the filter term. */
- manage_report_filter_controls (term ? term : get->filter,
- &first_result, &max_results, &sort_field,
- &sort_order, &result_hosts_only,
- &min_qod, &levels, &ctx.compliance_levels,
- &delta_states, &search_phrase,
- &search_phrase_exact, ¬es,
- &overrides, &apply_overrides, &ctx.zone);
- }
- else
+ int ret = manage_report_filter_controls_from_get (get,
+ &term,
+ &first_result,
+ &max_results,
+ &sort_field,
+ &sort_order,
+ &result_hosts_only,
+ &min_qod,
+ &levels,
+ &ctx.compliance_levels,
+ &delta_states,
+ &search_phrase,
+ &search_phrase_exact,
+ ¬es,
+ &overrides,
+ &apply_overrides,
+ &ctx.zone);
+ if (ret)
{
- term = g_strdup ("");
- /* Set the filter parameters to defaults */
- manage_report_filter_controls (term,
- &first_result, &max_results, &sort_field,
- &sort_order, &result_hosts_only,
- &min_qod, &levels, &ctx.compliance_levels,
- &delta_states, &search_phrase,
- &search_phrase_exact, ¬es, &overrides,
- &apply_overrides, &ctx.zone);
+ fclose (out);
+ return ret;
}
max_results = manage_max_rows (max_results, get->ignore_max_rows_per_page);
diff --git a/src/manage_sql_filters.c b/src/manage_sql_filters.c
index c23e534e0..262d193a4 100644
--- a/src/manage_sql_filters.c
+++ b/src/manage_sql_filters.c
@@ -450,6 +450,117 @@ manage_report_filter_controls (const gchar *filter, int *first, int *max,
return;
}
+/**
+ * @brief Derive report filter control values from GET filter input.
+ *
+ * The caller owns any allocated output strings and must free them.
+ *
+ * @param[in] get GET command data.
+ * @param[out] term Resolved filter term.
+ * @param[out] first_result First result offset.
+ * @param[out] max_results Maximum number of results.
+ * @param[out] sort_field Sort field.
+ * @param[out] sort_order Sort order.
+ * @param[out] result_hosts_only Whether only hosts with matching results
+ * should be included.
+ * @param[out] min_qod Minimum QoD.
+ * @param[out] levels Severity levels filter.
+ * @param[out] compliance_levels Compliance levels filter.
+ * @param[out] delta_states Delta states filter.
+ * @param[out] search_phrase Search phrase.
+ * @param[out] search_phrase_exact Whether search phrase must match exactly.
+ * @param[out] notes Whether notes are enabled.
+ * @param[out] overrides Whether overrides are enabled.
+ * @param[out] apply_overrides Whether overrides should be applied.
+ * @param[out] zone Timezone.
+ *
+ * @return 0 on success, 2 if the referenced filter was not found, -1 on error.
+ */
+int
+manage_report_filter_controls_from_get (const get_data_t *get,
+ gchar **term,
+ int *first_result,
+ int *max_results,
+ gchar **sort_field,
+ int *sort_order,
+ int *result_hosts_only,
+ gchar **min_qod,
+ gchar **levels,
+ gchar **compliance_levels,
+ gchar **delta_states,
+ gchar **search_phrase,
+ int *search_phrase_exact,
+ int *notes,
+ int *overrides,
+ int *apply_overrides,
+ gchar **zone)
+{
+ gchar *local_term;
+
+ if (get == NULL || term == NULL)
+ {
+ g_warning ("%s: invalid argument", __func__);
+ return -1;
+ }
+
+ *term = NULL;
+ local_term = NULL;
+
+ if ((get->filt_id && strlen (get->filt_id)
+ && strcmp (get->filt_id, FILT_ID_NONE))
+ || (get->filter && strlen (get->filter)))
+ {
+ if (get->filt_id && strlen (get->filt_id)
+ && strcmp (get->filt_id, FILT_ID_NONE))
+ {
+ local_term = filter_term (get->filt_id);
+ if (local_term == NULL)
+ return 2;
+ }
+
+ manage_report_filter_controls (local_term ? local_term : get->filter,
+ first_result,
+ max_results,
+ sort_field,
+ sort_order,
+ result_hosts_only,
+ min_qod,
+ levels,
+ compliance_levels,
+ delta_states,
+ search_phrase,
+ search_phrase_exact,
+ notes,
+ overrides,
+ apply_overrides,
+ zone);
+ }
+ else
+ {
+ local_term = g_strdup ("");
+
+ manage_report_filter_controls (local_term,
+ first_result,
+ max_results,
+ sort_field,
+ sort_order,
+ result_hosts_only,
+ min_qod,
+ levels,
+ compliance_levels,
+ delta_states,
+ search_phrase,
+ search_phrase_exact,
+ notes,
+ overrides,
+ apply_overrides,
+ zone);
+ }
+
+ *term = local_term;
+ return 0;
+}
+
/**
* @brief Append relation to filter.
*
From d3dc449ba99486fe5c4c1d492254f349a60f0e3c Mon Sep 17 00:00:00 2001
From: ozgen
Date: Fri, 3 Apr 2026 14:46:20 +0200
Subject: [PATCH 12/15] docs: add lean option and remove unimplemented
GET_REPORT_HOSTS options
Document the lean parameter for report hosts and remove options that are
not currently implemented to keep the GMP documentation aligned with
actual behavior.
---
src/schema_formats/XML/GMP.xml.in | 24 +++++++++---------------
1 file changed, 9 insertions(+), 15 deletions(-)
diff --git a/src/schema_formats/XML/GMP.xml.in b/src/schema_formats/XML/GMP.xml.in
index bb03a5c65..453136e96 100644
--- a/src/schema_formats/XML/GMP.xml.in
+++ b/src/schema_formats/XML/GMP.xml.in
@@ -21502,6 +21502,10 @@ END:VCALENDAR
If the "details" attribute is set, the response includes host entries.
Otherwise only filter, sort and count information is returned.
+
+ Currently "lean" omits selected optional or redundant XML elements from the
+ report hosts output to reduce response size.
+
@@ -21523,11 +21527,6 @@ END:VCALENDAR
starts at the 5th item)
-
- rows
- integer
- Number of items to return
-
sort
text
@@ -21538,16 +21537,6 @@ END:VCALENDAR
text
Column to sort by in descending order
-
- apply_overrides
- boolean
- Whether to apply Overrides
-
-
- min_qod
- integer
- Minimum QoD of the results
-
levels
levels
@@ -21598,6 +21587,11 @@ END:VCALENDAR
ID of filter to use to filter report hosts
uuid
+
+ lean
+ Whether to return a streamlined response
+ boolean
+
details
Whether to include host details
From 51c7b6c6f4536a3bf922989bea44f49c0578b609 Mon Sep 17 00:00:00 2001
From: ozgen
Date: Fri, 3 Apr 2026 14:55:01 +0200
Subject: [PATCH 13/15] remove unused host summary buffer allocation
---
src/manage_report_hosts.c | 14 +-------------
1 file changed, 1 insertion(+), 13 deletions(-)
diff --git a/src/manage_report_hosts.c b/src/manage_report_hosts.c
index 558eadb27..53d30af8a 100644
--- a/src/manage_report_hosts.c
+++ b/src/manage_report_hosts.c
@@ -64,7 +64,6 @@ manage_send_report_hosts (report_t report,
int result_hosts_only;
array_t *result_hosts;
iterator_t results;
- GString *host_summary_buffer;
int results_initialized;
memset (&ctx, 0, sizeof (ctx));
@@ -76,7 +75,6 @@ manage_send_report_hosts (report_t report,
xml_file = NULL;
stream = NULL;
result_hosts = NULL;
- host_summary_buffer = NULL;
results_initialized = 0;
result_hosts_only = 0;
@@ -153,8 +151,6 @@ manage_send_report_hosts (report_t report,
goto cleanup;
}
- host_summary_buffer = g_string_new ("");
-
ret = print_report_hosts_xml (&ctx,
stream,
report,
@@ -164,13 +160,8 @@ manage_send_report_hosts (report_t report,
is_container_scanning_report,
result_hosts_only,
result_hosts,
- host_summary_buffer);
+ NULL);
- if (host_summary_buffer)
- {
- g_string_free (host_summary_buffer, TRUE);
- host_summary_buffer = NULL;
- }
if (fclose (stream))
{
@@ -239,9 +230,6 @@ manage_send_report_hosts (report_t report,
if (stream)
fclose (stream);
- if (host_summary_buffer)
- g_string_free (host_summary_buffer, TRUE);
-
if (results_initialized)
cleanup_iterator (&results);
From 3bf13fa05645baa084f8eef2e9205c67e29da628 Mon Sep 17 00:00:00 2001
From: ozgen
Date: Mon, 6 Apr 2026 12:47:00 +0200
Subject: [PATCH 14/15] pass only required filter control outputs
---
src/manage_report_hosts.c | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/src/manage_report_hosts.c b/src/manage_report_hosts.c
index 53d30af8a..b367db003 100644
--- a/src/manage_report_hosts.c
+++ b/src/manage_report_hosts.c
@@ -95,19 +95,19 @@ manage_send_report_hosts (report_t report,
&term,
NULL,
NULL,
- &sort_field,
+ NULL,
NULL,
&result_hosts_only,
NULL,
- &levels,
- &ctx.compliance_levels,
- &delta_states,
- &search_phrase,
NULL,
NULL,
NULL,
NULL,
- &ctx.zone);
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL);
if (ret)
goto cleanup;
From d5df5b912130dc9238d71962c531dd0b7749ca75 Mon Sep 17 00:00:00 2001
From: ozgen
Date: Mon, 6 Apr 2026 12:47:15 +0200
Subject: [PATCH 15/15] clarify result-driven filtering in GET_REPORT_HOSTS
---
src/schema_formats/XML/GMP.xml.in | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/src/schema_formats/XML/GMP.xml.in b/src/schema_formats/XML/GMP.xml.in
index 453136e96..203cd02a5 100644
--- a/src/schema_formats/XML/GMP.xml.in
+++ b/src/schema_formats/XML/GMP.xml.in
@@ -21506,6 +21506,11 @@ END:VCALENDAR
Currently "lean" omits selected optional or redundant XML elements from the
report hosts output to reduce response size.
+
+ The filter affects the selection of matching results and the derived host
+ information returned by the command. When "result_hosts_only" is set, only
+ hosts with matching results are included.
+
@@ -21516,7 +21521,7 @@ END:VCALENDAR
filter
- Filter term to use to filter report hosts
+ Filter term to use for report host retrieval
text