From 9b40767967e533bdb340ca4c91f2fd1192694820 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Wed, 2 Dec 2020 16:45:42 +0100
Subject: [PATCH] Fix TestResult/benchmark/@href attribute
Make the href attribute an URI according to SCAP specification Section
4.5. This should fix SCAPVAL error RES-253-2 which occured when
validating ARFs by SCAPVAL. See #1629 for the problem description.
Also, it fixes a problem that xccdf_benchmark_item_clone didn't create
the clusters_dict hash table.
The existing tests are extended to test this property, the
function test_sds_external_xccdf has been splitted into 2 functions.
Fixes: #1629
---
src/DS/ds_sds_session.c | 18 ++++++++++++++++++
src/DS/ds_sds_session_priv.h | 1 +
src/DS/public/ds_sds_session.h | 8 ++++++++
src/DS/sds.c | 3 +++
src/XCCDF/item.c | 1 +
src/XCCDF/xccdf_session.c | 25 ++++++++++++++++++++-----
tests/DS/test_ds_misc.sh | 30 +++++++++++++++++++++++-------
7 files changed, 74 insertions(+), 12 deletions(-)
diff --git a/src/DS/ds_sds_session.c b/src/DS/ds_sds_session.c
index c03d3d593e..9120ee3243 100644
--- a/src/DS/ds_sds_session.c
+++ b/src/DS/ds_sds_session.c
@@ -50,7 +50,9 @@ struct ds_sds_session {
const char *target_dir; ///< Target directory for current split
const char *datastream_id; ///< ID of selected datastream
const char *checklist_id; ///< ID of selected checklist
+ const char *checklist_uri; ///< URI of selected checklist
struct oscap_htable *component_sources; ///< oscap_source for parsed components
+ struct oscap_htable *component_uris; ///< maps component refs to component URIs
bool fetch_remote_resources; ///< Allows loading of external components;
download_progress_calllback_t progress; ///< Callback to report progress of download.
};
@@ -72,6 +74,7 @@ struct ds_sds_session *ds_sds_session_new_from_source(struct oscap_source *sourc
struct ds_sds_session *sds_session = (struct ds_sds_session *) calloc(1, sizeof(struct ds_sds_session));
sds_session->source = source;
sds_session->component_sources = oscap_htable_new();
+ sds_session->component_uris = oscap_htable_new();
sds_session->progress = download_progress_empty_calllback;
return sds_session;
}
@@ -84,6 +87,7 @@ void ds_sds_session_free(struct ds_sds_session *sds_session)
oscap_acquire_cleanup_dir(&(sds_session->temp_dir));
}
oscap_htable_free(sds_session->component_sources, (oscap_destruct_func) oscap_source_free);
+ oscap_htable_free(sds_session->component_uris, (oscap_destruct_func) free);
free(sds_session);
}
}
@@ -91,10 +95,13 @@ void ds_sds_session_free(struct ds_sds_session *sds_session)
void ds_sds_session_reset(struct ds_sds_session *session)
{
session->checklist_id = NULL;
+ session->checklist_uri = NULL;
session->datastream_id = NULL;
session->target_dir = NULL;
oscap_htable_free(session->component_sources, (oscap_destruct_func) oscap_source_free);
session->component_sources = oscap_htable_new();
+ oscap_htable_free(session->component_uris, (oscap_destruct_func) free);
+ session->component_uris = oscap_htable_new();
}
struct ds_sds_index *ds_sds_session_get_sds_idx(struct ds_sds_session *session)
@@ -163,11 +170,21 @@ const char *ds_sds_session_get_checklist_id(const struct ds_sds_session *session
return session->checklist_id;
}
+const char *ds_sds_session_get_checklist_uri(const struct ds_sds_session *session)
+{
+ return session->checklist_uri;
+}
+
struct oscap_htable *ds_sds_session_get_component_sources(struct ds_sds_session *session)
{
return session->component_sources;
}
+struct oscap_htable *ds_sds_session_get_component_uris(struct ds_sds_session *session)
+{
+ return session->component_uris;
+}
+
const char *ds_sds_session_get_readable_origin(const struct ds_sds_session *session)
{
if (session->source == NULL)
@@ -210,6 +227,7 @@ struct oscap_source *ds_sds_session_select_checklist(struct ds_sds_session *sess
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Could not extract %s with all dependencies from datastream.", session->checklist_id);
return NULL;
}
+ session->checklist_uri = oscap_htable_get(session->component_uris, session->checklist_id);
struct oscap_source *xccdf = oscap_htable_get(session->component_sources, session->checklist_id);
if (xccdf == NULL) {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Internal error: Could not acquire handle to '%s' source.", session->checklist_id);
diff --git a/src/DS/ds_sds_session_priv.h b/src/DS/ds_sds_session_priv.h
index 4aa559ebb4..f58231dc48 100644
--- a/src/DS/ds_sds_session_priv.h
+++ b/src/DS/ds_sds_session_priv.h
@@ -37,6 +37,7 @@ xmlDoc *ds_sds_session_get_xmlDoc(struct ds_sds_session *session);
int ds_sds_session_register_component_source(struct ds_sds_session *session, const char *relative_filepath, struct oscap_source *component);
const char *ds_sds_session_get_target_dir(struct ds_sds_session *session);
struct oscap_htable *ds_sds_session_get_component_sources(struct ds_sds_session *session);
+struct oscap_htable *ds_sds_session_get_component_uris(struct ds_sds_session *session);
const char *ds_sds_session_get_readable_origin(const struct ds_sds_session *session);
bool ds_sds_session_fetch_remote_resources(struct ds_sds_session *session);
download_progress_calllback_t ds_sds_session_remote_resources_progress(struct ds_sds_session *session);
diff --git a/src/DS/public/ds_sds_session.h b/src/DS/public/ds_sds_session.h
index 1ce692ce21..20a85146cc 100644
--- a/src/DS/public/ds_sds_session.h
+++ b/src/DS/public/ds_sds_session.h
@@ -119,6 +119,14 @@ const char *ds_sds_session_get_datastream_id(const struct ds_sds_sessi
*/
const char *ds_sds_session_get_checklist_id(const struct ds_sds_session *session);
+/**
+ * Return URI of currently selected component representing XCCDF within the DataStream
+ * @memberof ds_sds_session
+ * @param session The Source DataStream session
+ * @returns URI of selected component or NULL
+ */
+const char *ds_sds_session_get_checklist_uri(const struct ds_sds_session *session);
+
/**
* Get component from Source DataStream by its href. This assumes that the component
* has been already cached by the session. You can cache component or its dependencies
diff --git a/src/DS/sds.c b/src/DS/sds.c
index b546ed3e65..20c683a7aa 100644
--- a/src/DS/sds.c
+++ b/src/DS/sds.c
@@ -450,7 +450,10 @@ int ds_sds_dump_component_ref_as(const xmlNodePtr component_ref, struct ds_sds_s
char* component_id = NULL;
+ // make a copy of xlink_href because ds_sds_dump_component_by_href modifies its second argument
+ char *xlink_href_copy = oscap_strdup(xlink_href);
int ret = ds_sds_dump_component_by_href(session, xlink_href, target_filename_dirname, relative_filepath, cref_id, &component_id);
+ oscap_htable_add(ds_sds_session_get_component_uris(session), cref_id, xlink_href_copy);
xmlFree(xlink_href);
xmlFree(cref_id);
diff --git a/src/XCCDF/item.c b/src/XCCDF/item.c
index 3657fb461a..295e4a7f00 100644
--- a/src/XCCDF/item.c
+++ b/src/XCCDF/item.c
@@ -1155,6 +1155,7 @@ struct xccdf_benchmark_item * xccdf_benchmark_item_clone(struct xccdf_item *pare
clone->items_dict = oscap_htable_new();
clone->profiles_dict = oscap_htable_new();
clone->results_dict = oscap_htable_new();
+ clone->clusters_dict = oscap_htable_new();
clone->notices = oscap_list_clone(item->notices, (oscap_clone_func) xccdf_notice_clone);
clone->plain_texts = oscap_list_clone(item->plain_texts, (oscap_clone_func) xccdf_plain_text_clone);
diff --git a/src/XCCDF/xccdf_session.c b/src/XCCDF/xccdf_session.c
index f1b8379591..c88d90be05 100644
--- a/src/XCCDF/xccdf_session.c
+++ b/src/XCCDF/xccdf_session.c
@@ -1374,21 +1374,28 @@ static int _build_xccdf_result_source(struct xccdf_session *session)
oscap_seterr(OSCAP_EFAMILY_OSCAP, "No XCCDF results to export.");
return 1;
}
- struct xccdf_result* cloned_result = xccdf_result_clone(session->xccdf.result);
- xccdf_benchmark_add_result(benchmark, cloned_result);
- session->xccdf.result_source = xccdf_benchmark_export_source(benchmark, session->export.xccdf_file);
if (session->export.xccdf_file != NULL) {
+ struct xccdf_benchmark *cloned_benchmark = xccdf_benchmark_clone(benchmark);
+ struct xccdf_result *cloned_result = xccdf_result_clone(session->xccdf.result);
+ xccdf_benchmark_add_result(cloned_benchmark, cloned_result);
+ struct oscap_source *xccdf_result_source = xccdf_benchmark_export_source(cloned_benchmark, session->export.xccdf_file);
+ // cloned_result is freed during xccdf_benchmark_free
+ xccdf_benchmark_free(cloned_benchmark);
// Export XCCDF result file only when explicitly requested
- if (oscap_source_save_as(session->xccdf.result_source, NULL) != 0) {
+ if (oscap_source_save_as(xccdf_result_source, NULL) != 0) {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Could not save file: %s",
- oscap_source_readable_origin(session->xccdf.result_source));
+ oscap_source_readable_origin(xccdf_result_source));
+ oscap_source_free(xccdf_result_source);
return -1;
}
+ oscap_source_free(xccdf_result_source);
}
if (session->export.xccdf_stig_viewer_file != NULL) {
+ struct xccdf_result *cloned_result = xccdf_result_clone(session->xccdf.result);
struct oscap_source * stig_result = xccdf_result_stig_viewer_export_source(cloned_result, session->export.xccdf_stig_viewer_file);
+ xccdf_result_free(cloned_result);
if (oscap_source_save_as(stig_result, NULL) != 0) {
oscap_seterr(OSCAP_EFAMILY_OSCAP, "Could not save file: %s",
oscap_source_readable_origin(stig_result));
@@ -1398,6 +1405,14 @@ static int _build_xccdf_result_source(struct xccdf_session *session)
oscap_source_free(stig_result);
}
+ struct xccdf_result *cloned_result = xccdf_result_clone(session->xccdf.result);
+ if (xccdf_session_is_sds(session)) {
+ struct ds_sds_session *sds_session = xccdf_session_get_ds_sds_session(session);
+ const char *benchmark_uri = ds_sds_session_get_checklist_uri(sds_session);
+ xccdf_result_set_benchmark_uri(cloned_result, benchmark_uri);
+ }
+ xccdf_benchmark_add_result(benchmark, cloned_result);
+ session->xccdf.result_source = xccdf_benchmark_export_source(benchmark, session->export.xccdf_file);
/* validate XCCDF Results */
if (session->validate && session->full_validation) {
if (oscap_source_validate(session->xccdf.result_source, _reporter, NULL)) {