Blame SOURCES/openscap-1.3.1-improve_stig-viewer_output-PR_1319.patch

8b65ee
From 97ea3d5dd72e11996fac63bfdcf9691e1515f09a Mon Sep 17 00:00:00 2001
8b65ee
From: Malte Kraus <malte.kraus@suse.com>
8b65ee
Date: Fri, 29 Mar 2019 16:12:22 +0100
8b65ee
Subject: [PATCH] improve --stig-viewer output when there is no 1:1 connection
8b65ee
 between rules
8b65ee
8b65ee
There can both be rules covering multiple STIG IDs (easy to handle: just
8b65ee
output the same result multiple times), and STIG IDs covered by more
8b65ee
than one rule. The DISA Stig Viewer seems to only consider the last
8b65ee
result for a given rule when it imports results, so when that last rule
8b65ee
happens to pass, that means the whole STIG will be marked as 'not a
8b65ee
finding'. To counteract that, this commit attempts to merge the results
8b65ee
in a sensible way - only if all tests passed, the STIG should be
8b65ee
marked as 'not a finding' in the way.
8b65ee
---
8b65ee
 src/XCCDF/result.c     | 92 +++++++++++++++++++++++++++++++++---------
8b65ee
 src/XCCDF/xccdf_impl.h |  3 +-
8b65ee
 2 files changed, 76 insertions(+), 19 deletions(-)
8b65ee
8b65ee
diff --git a/src/XCCDF/result.c b/src/XCCDF/result.c
8b65ee
index f389813d5..f0fa647b2 100644
8b65ee
--- a/src/XCCDF/result.c
8b65ee
+++ b/src/XCCDF/result.c
8b65ee
@@ -924,13 +924,68 @@ void xccdf_result_to_dom(struct xccdf_result *result, xmlNode *result_node, xmlD
8b65ee
 	}
8b65ee
 	xccdf_setvalue_iterator_free(setvalues);
8b65ee
 
8b65ee
+	struct oscap_htable *nodes_by_rule_id = oscap_htable_new();
8b65ee
+
8b65ee
 	struct xccdf_rule_result_iterator *rule_results = xccdf_result_get_rule_results(result);
8b65ee
+		if (use_stig_rule_id) {
8b65ee
+		while (xccdf_rule_result_iterator_has_more(rule_results)) {
8b65ee
+			struct xccdf_rule_result *rule_result = xccdf_rule_result_iterator_next(rule_results);
8b65ee
+
8b65ee
+			const char *idref = xccdf_rule_result_get_idref(rule_result);
8b65ee
+			if (!idref)
8b65ee
+				continue;
8b65ee
+
8b65ee
+			xccdf_test_result_type_t test_res = xccdf_rule_result_get_result(rule_result);
8b65ee
+
8b65ee
+			const struct xccdf_item *item = xccdf_benchmark_get_member(associated_benchmark, XCCDF_RULE, idref);
8b65ee
+			if (!item)
8b65ee
+				continue;
8b65ee
+
8b65ee
+			struct oscap_reference_iterator *references = xccdf_item_get_references(item);
8b65ee
+			while (oscap_reference_iterator_has_more(references)) {
8b65ee
+				struct oscap_reference *ref = oscap_reference_iterator_next(references);
8b65ee
+				if (strcmp(oscap_reference_get_href(ref), DISA_STIG_VIEWER_HREF) == 0) {
8b65ee
+					const char *stig_rule_id = oscap_reference_get_title(ref);
8b65ee
+
8b65ee
+					xccdf_test_result_type_t other_res = (xccdf_test_result_type_t)oscap_htable_detach(nodes_by_rule_id, stig_rule_id);
8b65ee
+					xccdf_test_result_type_t wanted_res;
8b65ee
+					if (other_res == 0) {
8b65ee
+						wanted_res = test_res;
8b65ee
+					} else {
8b65ee
+						// if one test passed, and the other didn't, the other one should win
8b65ee
+						if (test_res == XCCDF_RESULT_PASS) {
8b65ee
+							wanted_res = other_res;
8b65ee
+						} else if (other_res == XCCDF_RESULT_PASS) {
8b65ee
+							wanted_res = test_res;
8b65ee
+						// if one had an error, that should win
8b65ee
+						} else if (test_res == XCCDF_RESULT_ERROR || other_res == XCCDF_RESULT_ERROR) {
8b65ee
+							wanted_res = XCCDF_RESULT_ERROR;
8b65ee
+						// next prio: failures
8b65ee
+						} else if (test_res == XCCDF_RESULT_FAIL || other_res == XCCDF_RESULT_FAIL) {
8b65ee
+							wanted_res = XCCDF_RESULT_FAIL;
8b65ee
+						// next prio: unknown
8b65ee
+						} else if (test_res == XCCDF_RESULT_UNKNOWN || other_res == XCCDF_RESULT_UNKNOWN) {
8b65ee
+							wanted_res = XCCDF_RESULT_UNKNOWN;
8b65ee
+						// otherwise, just pick the lower one (more or less arbitrarily)
8b65ee
+						} else {
8b65ee
+							wanted_res = (test_res < other_res) ? test_res : other_res;
8b65ee
+						}
8b65ee
+					}
8b65ee
+					oscap_htable_add(nodes_by_rule_id, stig_rule_id, (void*)wanted_res);
8b65ee
+				}
8b65ee
+			}
8b65ee
+			oscap_reference_iterator_free(references);
8b65ee
+		}
8b65ee
+		xccdf_rule_result_iterator_reset(rule_results);
8b65ee
+	}
8b65ee
 	while (xccdf_rule_result_iterator_has_more(rule_results)) {
8b65ee
 		struct xccdf_rule_result *rule_result = xccdf_rule_result_iterator_next(rule_results);
8b65ee
-		xccdf_rule_result_to_dom(rule_result, doc, result_node, version_info, associated_benchmark, use_stig_rule_id);
8b65ee
+		xccdf_rule_result_to_dom(rule_result, doc, result_node, version_info, associated_benchmark, use_stig_rule_id, nodes_by_rule_id);
8b65ee
 	}
8b65ee
 	xccdf_rule_result_iterator_free(rule_results);
8b65ee
 
8b65ee
+	oscap_htable_free0(nodes_by_rule_id);
8b65ee
+
8b65ee
 	struct xccdf_score_iterator *scores = xccdf_result_get_scores(result);
8b65ee
 	while (xccdf_score_iterator_has_more(scores)) {
8b65ee
 		struct xccdf_score *score = xccdf_score_iterator_next(scores);
8b65ee
@@ -1081,36 +1136,40 @@ xmlNode *xccdf_target_identifier_to_dom(const struct xccdf_target_identifier *ti
8b65ee
 	}
8b65ee
 }
8b65ee
 
8b65ee
-xmlNode *xccdf_rule_result_to_dom(struct xccdf_rule_result *result, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info* version_info, struct xccdf_benchmark *benchmark, bool use_stig_rule_id)
8b65ee
+static void _xccdf_rule_result_to_dom_idref(struct xccdf_rule_result *result, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info* version_info, struct xccdf_benchmark *benchmark, const char *idref);
8b65ee
+void xccdf_rule_result_to_dom(struct xccdf_rule_result *result, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info* version_info, struct xccdf_benchmark *benchmark, bool use_stig_rule_id, struct oscap_htable *nodes_by_rule_id)
8b65ee
 {
8b65ee
 	const char *idref = xccdf_rule_result_get_idref(result);
8b65ee
 	if (use_stig_rule_id) {
8b65ee
 		// Don't output rules with no stig ids
8b65ee
 		if (!idref || !benchmark)
8b65ee
-			return NULL;
8b65ee
+			return;
8b65ee
 
8b65ee
-		struct xccdf_item *item = xccdf_benchmark_get_member(benchmark, XCCDF_RULE, idref);
8b65ee
+		const struct xccdf_item *item = xccdf_benchmark_get_member(benchmark, XCCDF_RULE, idref);
8b65ee
 		if (!item)
8b65ee
-			return NULL;
8b65ee
+			return;
8b65ee
 
8b65ee
-		const char *stig_rule_id = NULL;		
8b65ee
-		struct oscap_reference_iterator *references = xccdf_item_get_references(XRULE(item));
8b65ee
+		struct oscap_reference_iterator *references = xccdf_item_get_references(item);
8b65ee
 		while (oscap_reference_iterator_has_more(references)) {
8b65ee
 			struct oscap_reference *ref = oscap_reference_iterator_next(references);
8b65ee
 			if (strcmp(oscap_reference_get_href(ref), DISA_STIG_VIEWER_HREF[0]) == 0 ||
8b65ee
 			    strcmp(oscap_reference_get_href(ref), DISA_STIG_VIEWER_HREF[1]) == 0) {
8b65ee
-				stig_rule_id = oscap_reference_get_title(ref);
8b65ee
-				break;
8b65ee
+				const char *stig_rule_id = oscap_reference_get_title(ref);
8b65ee
+
8b65ee
+				xccdf_test_result_type_t expected_res = (xccdf_test_result_type_t)oscap_htable_get(nodes_by_rule_id, stig_rule_id);
8b65ee
+				xccdf_test_result_type_t test_res = xccdf_rule_result_get_result(result);
8b65ee
+				if (expected_res == test_res) {
8b65ee
+					oscap_htable_detach(nodes_by_rule_id, stig_rule_id);
8b65ee
+					_xccdf_rule_result_to_dom_idref(result, doc, parent, version_info, benchmark, stig_rule_id);
8b65ee
+				}
8b65ee
 			}
8b65ee
 		}
8b65ee
 		oscap_reference_iterator_free(references);
8b65ee
-
8b65ee
-		if (!stig_rule_id)
8b65ee
-			return NULL;
8b65ee
-
8b65ee
-		idref = stig_rule_id;
8b65ee
+	} else {
8b65ee
+		_xccdf_rule_result_to_dom_idref(result, doc, parent, version_info, benchmark, idref);
8b65ee
 	}
8b65ee
-
8b65ee
+}
8b65ee
+static void _xccdf_rule_result_to_dom_idref(struct xccdf_rule_result *result, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info* version_info, struct xccdf_benchmark *benchmark, const char *idref) {
8b65ee
 	xmlNs *ns_xccdf = lookup_xccdf_ns(doc, parent, version_info);
8b65ee
 
8b65ee
 	xmlNode *result_node = xmlNewTextChild(parent, ns_xccdf, BAD_CAST "rule-result", NULL);
8b65ee
@@ -1203,8 +1262,6 @@ xmlNode *xccdf_rule_result_to_dom(struct xccdf_rule_result *result, xmlDoc *doc,
8b65ee
 		xccdf_check_to_dom(check, doc, result_node, version_info);
8b65ee
 	}
8b65ee
 	xccdf_check_iterator_free(checks);
8b65ee
-
8b65ee
-	return result_node;
8b65ee
 }
8b65ee
 
8b65ee
 bool xccdf_rule_result_override(struct xccdf_rule_result *rule_result, xccdf_test_result_type_t new_result, const char *waiver_time, const char *authority, struct oscap_text *remark)
8b65ee
diff --git a/src/XCCDF/xccdf_impl.h b/src/XCCDF/xccdf_impl.h
8b65ee
index b87e7f170..05e0edd85 100644
8b65ee
--- a/src/XCCDF/xccdf_impl.h
8b65ee
+++ b/src/XCCDF/xccdf_impl.h
8b65ee
@@ -27,6 +27,7 @@
8b65ee
 #include <public/xccdf_benchmark.h>
8b65ee
 #include <common/util.h>
8b65ee
 #include <libxml/xmlreader.h>
8b65ee
+#include <common/list.h>
8b65ee
 
8b65ee
 OSCAP_HIDDEN_START;
8b65ee
 
8b65ee
@@ -49,7 +50,7 @@ void xccdf_group_to_dom(struct xccdf_group *group, xmlNode *group_node, xmlDoc *
8b65ee
 void xccdf_profile_to_dom(struct xccdf_profile *profile, xmlNode *profile_node, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info *version_info);
8b65ee
 void xccdf_result_to_dom(struct xccdf_result *result, xmlNode *result_node, xmlDoc *doc, xmlNode *parent, bool use_stig_rule_id);
8b65ee
 xmlNode *xccdf_target_identifier_to_dom(const struct xccdf_target_identifier *ti, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info* version_info);
8b65ee
-xmlNode *xccdf_rule_result_to_dom(struct xccdf_rule_result *result, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info* version_info, struct xccdf_benchmark *benchmark, bool use_stig_rule_id);
8b65ee
+void xccdf_rule_result_to_dom(struct xccdf_rule_result *result, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info* version_info, struct xccdf_benchmark *benchmark, bool use_stig_rule_id, struct oscap_htable *nodes_by_rule_id);
8b65ee
 xmlNode *xccdf_ident_to_dom(struct xccdf_ident *ident, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info* version_info);
8b65ee
 xmlNode *xccdf_setvalue_to_dom(struct xccdf_setvalue *setvalue, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info* version_info);
8b65ee
 xmlNode *xccdf_override_to_dom(struct xccdf_override *override, xmlDoc *doc, xmlNode *parent, const struct xccdf_version_info* version_info);