From 9b40767967e533bdb340ca4c91f2fd1192694820 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= 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)) {