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