From f90f02bfa2d31f56b25238d750c4746d964aea42 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20=C4=8Cern=C3=BD?= <jcerny@redhat.com>
Date: Tue, 26 Nov 2019 13:52:36 +0100
Subject: [PATCH 1/2] Show check identifiers at multi-check rules
Shows OVAL Definition ID and Title when an XCCDF rule uses
multi-check='true'. The multi-check is used in rule
security_patches_up_to_date in SCAP 1.3 datastreams. It wasn't possible
to see which vulnerabilities have been found because all the checks have
the same XCCDF rule ID.
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1771438
Fixes: #1320
---
src/OVAL/oval_agent.c | 35 ++++++++++----
src/XCCDF_POLICY/public/xccdf_policy.h | 18 ++++++-
src/XCCDF_POLICY/xccdf_policy.c | 48 +++++++++++--------
src/XCCDF_POLICY/xccdf_policy_engine.c | 4 +-
src/XCCDF_POLICY/xccdf_policy_engine_priv.h | 2 +-
src/XCCDF_POLICY/xccdf_policy_model_priv.h | 1 +
...eck_content_ref_without_name_attr.oval.xml | 4 +-
.../test_xccdf_check_multi_check2.sh | 6 +++
.../test_xccdf_check_multi_check2.xccdf.xml | 1 +
utils/oscap-xccdf.c | 8 ++++
10 files changed, 92 insertions(+), 35 deletions(-)
diff --git a/src/OVAL/oval_agent.c b/src/OVAL/oval_agent.c
index a962fe379..986295bf6 100644
--- a/src/OVAL/oval_agent.c
+++ b/src/OVAL/oval_agent.c
@@ -593,19 +593,34 @@ _oval_agent_list_definitions(void *usr, xccdf_policy_engine_query_t query_type,
{
__attribute__nonnull__(usr);
struct oval_agent_session *sess = (struct oval_agent_session *) usr;
- if (query_type != POLICY_ENGINE_QUERY_NAMES_FOR_HREF || (query_data != NULL && strcmp(sess->filename, (const char *) query_data)))
+ if (query_data != NULL && strcmp(sess->filename, (const char *) query_data)) {
return NULL;
- struct oval_definition_iterator *iterator = oval_definition_model_get_definitions(sess->def_model);
- struct oscap_stringlist *result = oscap_stringlist_new();
- struct oval_definition *oval_def;
-
- while (oval_definition_iterator_has_more(iterator)) {
- oval_def = oval_definition_iterator_next(iterator);
- oscap_stringlist_add_string(result, oval_definition_get_id(oval_def));
}
+ if (query_type == POLICY_ENGINE_QUERY_NAMES_FOR_HREF) {
+ struct oval_definition_iterator *iterator = oval_definition_model_get_definitions(sess->def_model);
+ struct oscap_stringlist *result = oscap_stringlist_new();
+
+ while (oval_definition_iterator_has_more(iterator)) {
+ struct oval_definition *oval_def = oval_definition_iterator_next(iterator);
+ oscap_stringlist_add_string(result, oval_definition_get_id(oval_def));
+ }
+
+ oval_definition_iterator_free(iterator);
+ return result;
+ } else if (query_type == POLICY_ENGINE_QUERY_OVAL_DEFS_FOR_HREF) {
+ struct oval_definition_iterator *iterator = oval_definition_model_get_definitions(sess->def_model);
+ struct oscap_list *result = oscap_list_new();
- oval_definition_iterator_free(iterator);
- return result;
+ while (oval_definition_iterator_has_more(iterator)) {
+ struct oval_definition *oval_def = oval_definition_iterator_next(iterator);
+ oscap_list_add(result, oval_def);
+ }
+
+ oval_definition_iterator_free(iterator);
+ return result;
+ } else {
+ return NULL;
+ }
}
bool xccdf_policy_model_register_engine_oval(struct xccdf_policy_model * model, struct oval_agent_session * usr)
diff --git a/src/SCE/Makefile.am b/src/SCE/Makefile.am
index 0c90c6da0..5849cf1a0 100644
--- a/src/SCE/Makefile.am
+++ b/src/SCE/Makefile.am
@@ -12,7 +12,8 @@ AM_CPPFLAGS = @xml2_CFLAGS@ \
-I$(top_srcdir)/src/source/public \
-I$(top_srcdir)/src/XCCDF_POLICY/public \
-I$(top_srcdir)/src/XCCDF/public \
- -I$(top_srcdir)/src/CPE/public
+ -I$(top_srcdir)/src/CPE/public \
+ -I$(top_srcdir)/src/OVAL/public
AM_LDFLAGS = @xml2_LIBS@
diff --git a/src/XCCDF_POLICY/public/xccdf_policy.h b/src/XCCDF_POLICY/public/xccdf_policy.h
index aa2525e2b..5e85c476c 100644
--- a/src/XCCDF_POLICY/public/xccdf_policy.h
+++ b/src/XCCDF_POLICY/public/xccdf_policy.h
@@ -35,6 +35,7 @@
#include <stdbool.h>
#include <time.h>
#include <oscap.h>
+#include "oval_definitions.h"
/**
* @struct xccdf_policy_model
@@ -69,6 +70,7 @@ struct xccdf_policy_iterator;
*/
typedef enum {
POLICY_ENGINE_QUERY_NAMES_FOR_HREF = 1, /// Considering xccdf:check-content-ref, what are possible @name attributes for given href?
+ POLICY_ENGINE_QUERY_OVAL_DEFS_FOR_HREF = 2, /// Considering xccdf:check-content-ref, what are OVAL definitions for given href?
} xccdf_policy_engine_query_t;
/**
@@ -80,9 +82,11 @@ typedef enum {
* is always user data as registered. Second argument defines the query. Third argument is
* dependent on query and defined as follows:
* - (const char *)href -- for POLICY_ENGINE_QUERY_NAMES_FOR_HREF
+ * - (const char *)href -- for POLICY_ENGINE_QUERY_OVAL_DEFS_FOR_HREF
*
* Expected return type depends also on query as follows:
- * - (struct oscap_stringlists *) -- for POLICY_ENGINE_QUERY_NAMES_FOR_HREF
+ * - (struct oscap_stringlist *) -- for POLICY_ENGINE_QUERY_NAMES_FOR_HREF
+ * - (struct oscap_list *) -- for POLICY_ENGINE_QUERY_OVAL_DEFS_FOR_HREF
* - NULL shall be returned if the function doesn't understand the query.
*/
typedef void *(*xccdf_policy_engine_query_fn) (void *, xccdf_policy_engine_query_t, void *);
@@ -289,6 +293,19 @@ typedef int (*policy_reporter_start)(struct xccdf_rule *, void *);
*/
bool xccdf_policy_model_register_start_callback(struct xccdf_policy_model * model, policy_reporter_start func, void * usr);
+typedef int (*policy_reporter_multicheck)(struct oval_definition*, void *);
+/**
+ * Function to register callback for checking system that will be called
+ * DURING each rule evaluation if rule sets multi-check="true".
+ * @param model XCCDF Policy Model
+ * @param func Callback - pointer to function called by XCCDF Policy system when rule parsed
+ * @param usr optional parameter for passing user data to callback
+ * @memberof xccdf_policy_model
+ * @return true if callback registered successfully, false otherwise
+ */
+bool xccdf_policy_model_register_multicheck_callback(struct xccdf_policy_model *model, policy_reporter_multicheck func, void *usr);
+
+
/************************************************************/
/**
* @name Getters
diff --git a/src/XCCDF_POLICY/xccdf_policy.c b/src/XCCDF_POLICY/xccdf_policy.c
index b406d7f59..079395c85 100644
--- a/src/XCCDF_POLICY/xccdf_policy.c
+++ b/src/XCCDF_POLICY/xccdf_policy.c
@@ -378,20 +378,19 @@ xccdf_policy_evaluate_cb(struct xccdf_policy * policy, const char * sysname, con
}
/**
- * Find all posible names for given check-content-ref/@href, considering also the check/@system.
- * This is usefull for multi-check="true" feature.
- * @return list of names (even empty) if the given href found, NULL otherwise.
+ * Find all possible names for given check-content-ref/@href, considering also the check/@system.
+ * This is useful for multi-check="true" feature.
+ * @return list of OVAL definitions if the given href found, NULL otherwise.
*/
-static struct oscap_stringlist *
-_xccdf_policy_get_namesfor_href(struct xccdf_policy *policy, const char *sysname, const char *href)
+static struct oscap_list *_xccdf_policy_get_oval_definitions_for_href(struct xccdf_policy *policy, const char *sysname, const char *href)
{
struct oscap_iterator *cb_it = _xccdf_policy_get_engines_by_sysname(policy, sysname);
- struct oscap_stringlist *result = NULL;
+ struct oscap_list *result = NULL;
while (oscap_iterator_has_more(cb_it) && result == NULL) {
struct xccdf_policy_engine *engine = (struct xccdf_policy_engine *) oscap_iterator_next(cb_it);
if (engine == NULL)
break;
- result = xccdf_policy_engine_query(engine, POLICY_ENGINE_QUERY_NAMES_FOR_HREF, (void *) href);
+ result = xccdf_policy_engine_query(engine, POLICY_ENGINE_QUERY_OVAL_DEFS_FOR_HREF, (void *) href);
}
oscap_iterator_free(cb_it);
return result;
@@ -1047,24 +1046,27 @@ _xccdf_policy_rule_evaluate(struct xccdf_policy * policy, const struct xccdf_rul
if (content_name == NULL && xccdf_check_get_multicheck(check)) {
// parent element is Rule, @multi-check is required
- struct oscap_stringlist *names = _xccdf_policy_get_namesfor_href(policy, system_name, href);
- if (names != NULL) {
+ struct oscap_list *oval_definition_list = _xccdf_policy_get_oval_definitions_for_href(policy, system_name, href);
+ if (oval_definition_list != NULL) {
// multi-check is supported by checking-engine
- struct oscap_string_iterator *name_it = oscap_stringlist_get_strings(names);
- if (!oscap_string_iterator_has_more(name_it)) {
+ struct oscap_iterator *oval_definition_iterator = oscap_iterator_new(oval_definition_list);
+ if (!oscap_iterator_has_more(oval_definition_iterator)) {
// Super special case when oval file contains no definitions
// thus multi-check shall yield zero rule-results.
report = _xccdf_policy_report_rule_result(policy, result, rule, check, XCCDF_RESULT_UNKNOWN, "No definitions found for @multi-check.");
- oscap_string_iterator_free(name_it);
- oscap_stringlist_free(names);
+ oscap_iterator_free(oval_definition_iterator);
+ oscap_list_free(oval_definition_list, NULL);
xccdf_check_content_ref_iterator_free(content_it);
oscap_list_free(bindings, (oscap_destruct_func) xccdf_value_binding_free);
return report;
}
- while (oscap_string_iterator_has_more(name_it)) {
- const char *name = oscap_string_iterator_next(name_it);
+ while (oscap_iterator_has_more(oval_definition_iterator)) {
+ struct oval_definition *oval_definition = oscap_iterator_next(oval_definition_iterator);
+ if ((report = xccdf_policy_report_cb(policy, XCCDF_POLICY_OUTCB_MULTICHECK, (void *) oval_definition)) != 0) {
+ break;
+ }
struct xccdf_check *cloned_check = xccdf_check_clone(check);
- xccdf_check_inject_content_ref(cloned_check, content, name);
+ xccdf_check_inject_content_ref(cloned_check, content, oval_definition_get_id(oval_definition));
int inner_ret = xccdf_policy_check_evaluate(policy, cloned_check);
if (inner_ret == -1) {
xccdf_check_free(cloned_check);
@@ -1073,12 +1075,13 @@ _xccdf_policy_rule_evaluate(struct xccdf_policy * policy, const struct xccdf_rul
}
if ((report = _xccdf_policy_report_rule_result(policy, result, rule, cloned_check, inner_ret, NULL)) != 0)
break;
- if (oscap_string_iterator_has_more(name_it))
+ if (oscap_iterator_has_more(oval_definition_iterator)) {
if ((report = xccdf_policy_report_cb(policy, XCCDF_POLICY_OUTCB_START, (void *) rule)) != 0)
break;
+ }
}
- oscap_string_iterator_free(name_it);
- oscap_stringlist_free(names);
+ oscap_iterator_free(oval_definition_iterator);
+ oscap_list_free(oval_definition_list, NULL);
xccdf_check_content_ref_iterator_free(content_it);
oscap_list_free(bindings, (oscap_destruct_func) xccdf_value_binding_free);
xccdf_check_free(check);
@@ -1629,6 +1632,13 @@ bool xccdf_policy_model_register_output_callback(struct xccdf_policy_model * mod
return oscap_list_add(model->callbacks, reporter);
}
+bool xccdf_policy_model_register_multicheck_callback(struct xccdf_policy_model *model, policy_reporter_multicheck func, void *usr)
+{
+ __attribute__nonnull__(model);
+ struct reporter *reporter = reporter_new(XCCDF_POLICY_OUTCB_MULTICHECK, func, usr);
+ return oscap_list_add(model->callbacks, reporter);
+}
+
struct xccdf_result * xccdf_policy_get_result_by_id(struct xccdf_policy * policy, const char * id) {
struct xccdf_result_iterator * result_it;
diff --git a/src/XCCDF_POLICY/xccdf_policy_engine.c b/src/XCCDF_POLICY/xccdf_policy_engine.c
index 5e0a2b6b0..3529dd1b6 100644
--- a/src/XCCDF_POLICY/xccdf_policy_engine.c
+++ b/src/XCCDF_POLICY/xccdf_policy_engine.c
@@ -69,9 +69,9 @@ xccdf_test_result_type_t xccdf_policy_engine_eval(struct xccdf_policy_engine *en
return ret;
}
-struct oscap_stringlist *xccdf_policy_engine_query(struct xccdf_policy_engine *engine, xccdf_policy_engine_query_t query_type, void *query_data)
+struct oscap_list *xccdf_policy_engine_query(struct xccdf_policy_engine *engine, xccdf_policy_engine_query_t query_type, void *query_data)
{
if (engine->query_fn == NULL)
return NULL;
- return (struct oscap_stringlist *) engine->query_fn(engine->usr, query_type, query_data);
+ return (struct oscap_list *) engine->query_fn(engine->usr, query_type, query_data);
}
diff --git a/src/XCCDF_POLICY/xccdf_policy_engine_priv.h b/src/XCCDF_POLICY/xccdf_policy_engine_priv.h
index cdcb49613..bcf758b2e 100644
--- a/src/XCCDF_POLICY/xccdf_policy_engine_priv.h
+++ b/src/XCCDF_POLICY/xccdf_policy_engine_priv.h
@@ -75,7 +75,7 @@ xccdf_test_result_type_t xccdf_policy_engine_eval(struct xccdf_policy_engine *en
* @param query_data Additional data for the checking engine query.
* @returns list of query results
*/
-struct oscap_stringlist *xccdf_policy_engine_query(struct xccdf_policy_engine *engine, xccdf_policy_engine_query_t query_type, void *query_data);
+struct oscap_list *xccdf_policy_engine_query(struct xccdf_policy_engine *engine, xccdf_policy_engine_query_t query_type, void *query_data);
OSCAP_HIDDEN_END;
diff --git a/src/XCCDF_POLICY/xccdf_policy_model_priv.h b/src/XCCDF_POLICY/xccdf_policy_model_priv.h
index c5223a7b8..8f503ef46 100644
--- a/src/XCCDF_POLICY/xccdf_policy_model_priv.h
+++ b/src/XCCDF_POLICY/xccdf_policy_model_priv.h
@@ -33,6 +33,7 @@ OSCAP_HIDDEN_START;
#define XCCDF_POLICY_OUTCB_START "urn:xccdf:system:callback:start"
#define XCCDF_POLICY_OUTCB_END "urn:xccdf:system:callback:output"
+#define XCCDF_POLICY_OUTCB_MULTICHECK "urn:xccdf:system:callback:multicheck"
/**
* Remove checking engines with given system from xccdf_policy_model
diff --git a/tests/API/XCCDF/unittests/test_xccdf_check_content_ref_without_name_attr.oval.xml b/tests/API/XCCDF/unittests/test_xccdf_check_content_ref_without_name_attr.oval.xml
index 6d4868686..6efdb2f1c 100644
--- a/tests/API/XCCDF/unittests/test_xccdf_check_content_ref_without_name_attr.oval.xml
+++ b/tests/API/XCCDF/unittests/test_xccdf_check_content_ref_without_name_attr.oval.xml
@@ -17,11 +17,11 @@
</generator>
<definitions>
<definition class="compliance" id="oval:moc.elpmaxe.www:def:1" version="1">
- <metadata><title>PASS</title><description>Bla.</description></metadata>
+ <metadata><title>DEFINITION_1_TITLE_EXPECTED_PASS</title><description>Bla.</description></metadata>
<criteria><criterion test_ref="oval:moc.elpmaxe.www:tst:1" comment="Is executable"/></criteria>
</definition>
<definition class="compliance" id="oval:moc.elpmaxe.www:def:2" version="1">
- <metadata><title>FAIL</title><description>Bla.</description></metadata>
+ <metadata><title>DEFINITION_2_TITLE_EXPECTED_FAIL</title><description>Bla.</description></metadata>
<criteria><criterion test_ref="oval:moc.elpmaxe.www:tst:2" comment="Is not executable"/></criteria>
</definition>
</definitions>
diff --git a/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.sh b/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.sh
index d5991aa0f..2c45ad0a3 100755
--- a/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.sh
+++ b/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.sh
@@ -17,6 +17,12 @@ echo "Result file = $result"
[ -f $stderr ]; [ ! -s $stderr ]; rm $stderr
grep '^Result.*pass$' $stdout
grep '^Result.*fail$' $stdout
+[ $(grep -c '^Rule.*xccdf_moc.elpmaxe.www_rule_1' $stdout) == 2 ]
+[ $(grep -c '^Title.*The only rule in this benchmark' $stdout) == 2 ]
+grep '^OVAL Definition ID.*oval:moc.elpmaxe.www:def:1$' $stdout
+grep '^OVAL Definition Title.*DEFINITION_1_TITLE_EXPECTED_PASS$' $stdout
+grep '^OVAL Definition ID.*oval:moc.elpmaxe.www:def:2$' $stdout
+grep '^OVAL Definition Title.*DEFINITION_2_TITLE_EXPECTED_FAIL$' $stdout
rm $stdout
$OSCAP xccdf validate-xml $result
diff --git a/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.xccdf.xml b/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.xccdf.xml
index 44dc4de49..1c87b9d51 100644
--- a/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.xccdf.xml
+++ b/tests/API/XCCDF/unittests/test_xccdf_check_multi_check2.xccdf.xml
@@ -3,6 +3,7 @@
<status>incomplete</status>
<version>1.0</version>
<Rule selected="true" id="xccdf_moc.elpmaxe.www_rule_1">
+ <title>The only rule in this benchmark</title>
<check system="http://oval.mitre.org/XMLSchema/oval-definitions-5" multi-check="true">
<check-content-ref href="test_xccdf_check_content_ref_without_name_attr.oval.xml"/>
</check>
diff --git a/utils/oscap-xccdf.c b/utils/oscap-xccdf.c
index 19ffc0859..59cd7bcf2 100644
--- a/utils/oscap-xccdf.c
+++ b/utils/oscap-xccdf.c
@@ -392,6 +392,13 @@ static int callback_scr_result_progress(struct xccdf_rule_result *rule_result, v
return 0;
}
+static int callback_scr_multicheck(struct oval_definition *definition, void *arg)
+{
+ printf("OVAL Definition ID\t%s\n", oval_definition_get_id(definition));
+ printf("OVAL Definition Title\t%s\n", oval_definition_get_title(definition));
+ return 0;
+}
+
/*
* Send XCCDF Rule Results info message to syslog
*
@@ -434,6 +441,7 @@ static void _register_progress_callback(struct xccdf_session *session, bool prog
xccdf_policy_model_register_start_callback(policy_model, callback_scr_rule,
(void *) xccdf_session_get_xccdf_policy(session));
xccdf_policy_model_register_output_callback(policy_model, callback_scr_result, NULL);
+ xccdf_policy_model_register_multicheck_callback(policy_model, callback_scr_multicheck, NULL);
}
/* xccdf_policy_model_register_output_callback(policy_model, callback_syslog_result, NULL); */
}
diff --git a/xsl/xccdf-report-impl.xsl b/xsl/xccdf-report-impl.xsl
index cc76a56cc..ba07b0a90 100644
--- a/xsl/xccdf-report-impl.xsl
+++ b/xsl/xccdf-report-impl.xsl
@@ -346,19 +346,14 @@ Authors:
<xsl:text>}</xsl:text>
</xsl:template>
-<xsl:key name="testresult_ruleresults" match="//cdf:rule-result" use="concat(ancestor::cdf:TestResult/@id, '|', @idref)"/>
-
-<xsl:template name="rule-overview-leaf">
- <xsl:param name="testresult"/>
- <xsl:param name="item"/>
- <xsl:param name="profile"/>
- <xsl:param name="indent"/>
-
- <xsl:variable name="ruleresult" select="key('testresult_ruleresults', concat($testresult/@id, '|', $item/@id))"/>
- <xsl:variable name="result" select="$ruleresult/cdf:result/text()"/>
-
- <xsl:if test="$result != 'notselected'">
- <tr data-tt-id="{$item/@id}" class="rule-overview-leaf rule-overview-leaf-{$result} rule-overview-leaf-id-{$item/@id}" id="rule-overview-leaf-{generate-id($ruleresult)}">
+<xsl:template name="rule-overview-leaf-table-row">
+ <xsl:param name="result" />
+ <xsl:param name="item" />
+ <xsl:param name="indent" />
+ <xsl:param name="testresult" />
+ <xsl:param name="profile" />
+
+ <tr data-tt-id="{$item/@id}" class="rule-overview-leaf rule-overview-leaf-{$result} rule-overview-leaf-id-{$item/@id}" id="rule-overview-leaf-{generate-id(.)}">
<xsl:attribute name="data-tt-parent-id">
<xsl:value-of select="$item/parent::cdf:*/@id"/>
</xsl:attribute>
@@ -371,18 +366,26 @@ Authors:
<xsl:attribute name="class">rule-overview-leaf rule-overview-leaf-<xsl:value-of select="$result"/> rule-overview-needs-attention</xsl:attribute>
</xsl:if>
- <td style="padding-left: {$indent * 19}px"><a href="#rule-detail-{generate-id($ruleresult)}" onclick="return openRuleDetailsDialog('{generate-id($ruleresult)}')">
- <xsl:call-template name="item-title">
- <xsl:with-param name="item" select="$item"/>
- <xsl:with-param name="testresult" select="$testresult"/>
- <xsl:with-param name="profile" select="$profile"/>
- </xsl:call-template>
+ <td style="padding-left: {$indent * 19}px">
+ <a href="#rule-detail-{generate-id(.)}" onclick="return openRuleDetailsDialog('{generate-id(.)}')">
+ <xsl:call-template name="item-title">
+ <xsl:with-param name="item" select="$item"/>
+ <xsl:with-param name="testresult" select="$testresult"/>
+ <xsl:with-param name="profile" select="$profile"/>
+ </xsl:call-template>
</a>
- <xsl:if test="$ruleresult/cdf:override">
+ <xsl:if test="cdf:check[@multi-check='true']">
+ (<xsl:value-of select="cdf:check/cdf:check-content-ref/@name" />)
+ </xsl:if>
+ <xsl:if test="cdf:override">
 <span class="label label-warning">waived</span>
</xsl:if>
</td>
- <td class="rule-severity" style="text-align: center"><xsl:call-template name="item-severity"><xsl:with-param name="item" select="$ruleresult" /></xsl:call-template></td>
+ <td class="rule-severity" style="text-align: center">
+ <xsl:call-template name="item-severity">
+ <xsl:with-param name="item" select="." />
+ </xsl:call-template>
+ </td>
<td class="rule-result rule-result-{$result}">
<xsl:variable name="result_tooltip">
<xsl:call-template name="rule-result-tooltip">
@@ -394,7 +397,31 @@ Authors:
</div>
</td>
</tr>
- </xsl:if>
+</xsl:template>
+
+<xsl:key name="testresult_ruleresults" match="//cdf:rule-result" use="concat(ancestor::cdf:TestResult/@id, '|', @idref)"/>
+
+<xsl:template name="rule-overview-leaf">
+ <xsl:param name="testresult"/>
+ <xsl:param name="item"/>
+ <xsl:param name="profile"/>
+ <xsl:param name="indent"/>
+
+ <xsl:variable name="ruleresult" select="key('testresult_ruleresults', concat($testresult/@id, '|', $item/@id))"/>
+
+ <!-- There can be multiple results for 1 XCCDF rule if multi-check is set -->
+ <xsl:for-each select="$ruleresult">
+ <xsl:variable name="result" select="cdf:result/text()"/>
+ <xsl:if test="$result != 'notselected'">
+ <xsl:call-template name="rule-overview-leaf-table-row">
+ <xsl:with-param name="item" select="$item"/>
+ <xsl:with-param name="result" select="$result"/>
+ <xsl:with-param name="indent" select="$indent"/>
+ <xsl:with-param name="testresult" select="$testresult"/>
+ <xsl:with-param name="profile" select="$profile"/>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:for-each>
</xsl:template>
<xsl:template name="rule-overview-inner-node">
@@ -718,179 +745,212 @@ Authors:
</xsl:template>
-<xsl:template name="result-details-leaf">
- <xsl:param name="testresult"/>
+
+<xsl:template name="result-details-leaf-table">
<xsl:param name="item"/>
+ <xsl:param name="testresult"/>
<xsl:param name="profile"/>
+ <xsl:param name="result"/>
- <xsl:variable name="ruleresult" select="key('testresult_ruleresults', concat($testresult/@id, '|', $item/@id))"/>
- <xsl:variable name="result" select="$ruleresult/cdf:result/text()"/>
-
- <xsl:if test="$result != 'notselected'">
- <div class="panel panel-default rule-detail rule-detail-{$result} rule-detail-id-{$item/@id}" id="rule-detail-{generate-id($ruleresult)}">
- <div class="keywords sr-only">
- <xsl:comment>This allows OpenSCAP JS to search the report rules</xsl:comment>
- <xsl:call-template name="item-title">
- <xsl:with-param name="item" select="$item"/>
- <xsl:with-param name="testresult" select="$testresult"/>
- <xsl:with-param name="profile" select="$profile"/>
- </xsl:call-template>
- <xsl:value-of select="concat($item/@id, ' ')"/>
- <xsl:value-of select="$ruleresult/@severity"/>
- <xsl:for-each select="$ruleresult/cdf:ident">
- <xsl:value-of select="concat(text(), ' ')"/>
- </xsl:for-each>
- <xsl:for-each select="$ruleresult/cdf:reference">
- <xsl:value-of select="concat(text(), ' ')"/>
- </xsl:for-each>
- </div>
- <div class="panel-heading">
- <h3 class="panel-title">
- <xsl:call-template name="item-title">
+ <table class="table table-striped table-bordered">
+ <tbody>
+ <tr><td class="col-md-3">Rule ID</td><td class="rule-id col-md-9"><xsl:value-of select="$item/@id"/></td></tr>
+ <tr><td>Result</td>
+ <td class="rule-result rule-result-{$result}">
+ <xsl:variable name="result_tooltip">
+ <xsl:call-template name="rule-result-tooltip">
+ <xsl:with-param name="ruleresult" select="$result"/>
+ </xsl:call-template>
+ </xsl:variable>
+ <div>
+ <abbr title="{$result_tooltip}"><xsl:value-of select="$result"/></abbr>
+ </div>
+ </td></tr>
+ <tr>
+ <td>Multi-check rule</td>
+ <td>
+ <xsl:choose>
+ <xsl:when test="cdf:check[@multi-check='true']">yes</xsl:when>
+ <xsl:otherwise>no</xsl:otherwise>
+ </xsl:choose>
+ </td>
+ </tr>
+ <xsl:if test="cdf:check[@system='http://oval.mitre.org/XMLSchema/oval-definitions-5']">
+ <tr>
+ <td>OVAL Definition ID</td>
+ <td>
+ <xsl:value-of select="cdf:check/cdf:check-content-ref/@name" />
+ </td>
+ </tr>
+ </xsl:if>
+ <tr><td>Time</td><td><xsl:value-of select="@time"/></td></tr>
+ <tr><td>Severity</td><td><xsl:call-template name="item-severity"><xsl:with-param name="item" select="." /></xsl:call-template></td></tr>
+ <tr><td>Identifiers and References</td><td class="identifiers">
+ <!-- XCCDF 1.2 spec says that idents in rule-result should be copied from
+ the Rule itself. That means that we can just use the same code as guide
+ and just use idents from Rule. -->
+ <xsl:call-template name="item-idents-refs">
<xsl:with-param name="item" select="$item"/>
- <xsl:with-param name="testresult" select="$testresult"/>
- <xsl:with-param name="profile" select="$profile"/>
</xsl:call-template>
- </h3>
- </div>
- <div class="panel-body">
- <table class="table table-striped table-bordered">
- <tbody>
- <tr><td class="col-md-3">Rule ID</td><td class="rule-id col-md-9"><xsl:value-of select="$item/@id"/></td></tr>
- <tr><td>Result</td>
- <td class="rule-result rule-result-{$result}">
- <xsl:variable name="result_tooltip">
- <xsl:call-template name="rule-result-tooltip">
- <xsl:with-param name="ruleresult" select="$result"/>
- </xsl:call-template>
- </xsl:variable>
- <div>
- <abbr title="{$result_tooltip}"><xsl:value-of select="$result"/></abbr>
+ </td></tr>
+ <xsl:if test="cdf:override">
+ <tr><td colspan="2">
+ <xsl:for-each select="cdf:override">
+ <xsl:variable name="old-result" select="cdf:old-result/text()"/>
+
+ <div class="alert alert-warning waiver">
+ This rule has been waived by <strong><xsl:value-of select="@authority"/></strong> at <strong><xsl:value-of select="@date"/></strong>.
+ <blockquote>
+ <xsl:value-of select="cdf:remark/text()"/>
+ </blockquote>
+ <small>
+ The previous result was <span class="rule-result rule-result-{$old-result}"> <xsl:value-of select="$old-result"/> </span>.
+ </small>
</div>
- </td></tr>
- <tr><td>Time</td><td><xsl:value-of select="$ruleresult/@time"/></td></tr>
- <tr><td>Severity</td><td><xsl:call-template name="item-severity"><xsl:with-param name="item" select="$ruleresult" /></xsl:call-template></td></tr>
- <tr><td>Identifiers and References</td><td class="identifiers">
- <!-- XCCDF 1.2 spec says that idents in rule-result should be copied from
- the Rule itself. That means that we can just use the same code as guide
- and just use idents from Rule. -->
- <xsl:call-template name="item-idents-refs">
- <xsl:with-param name="item" select="$item"/>
- </xsl:call-template>
- </td></tr>
- <xsl:if test="$ruleresult/cdf:override">
- <tr><td colspan="2">
- <xsl:for-each select="$ruleresult/cdf:override">
- <xsl:variable name="old-result" select="cdf:old-result/text()"/>
-
- <div class="alert alert-warning waiver">
- This rule has been waived by <strong><xsl:value-of select="@authority"/></strong> at <strong><xsl:value-of select="@date"/></strong>.
- <blockquote>
- <xsl:value-of select="cdf:remark/text()"/>
- </blockquote>
- <small>
- The previous result was <span class="rule-result rule-result-{$old-result}"> <xsl:value-of select="$old-result"/> </span>.
- </small>
- </div>
- </xsl:for-each>
- </td></tr>
- </xsl:if>
- <xsl:if test="$item/cdf:description">
- <tr><td>Description</td><td><div class="description">
- <p>
- <xsl:apply-templates mode="sub-testresult" select="$item/cdf:description">
- <xsl:with-param name="testresult" select="$testresult"/>
+ </xsl:for-each>
+ </td></tr>
+ </xsl:if>
+ <xsl:if test="$item/cdf:description">
+ <tr><td>Description</td><td><div class="description">
+ <p>
+ <xsl:apply-templates mode="sub-testresult" select="$item/cdf:description">
+ <xsl:with-param name="testresult" select="$testresult"/>
+ <xsl:with-param name="benchmark" select="$item/ancestor::cdf:Benchmark"/>
+ <xsl:with-param name="profile" select="$profile"/>
+ </xsl:apply-templates>
+ </p>
+ </div></td></tr>
+ </xsl:if>
+ <xsl:if test="$item/cdf:rationale">
+ <tr><td>Rationale</td><td><div class="rationale">
+ <p>
+ <xsl:apply-templates mode="sub-testresult" select="$item/cdf:rationale">
+ <xsl:with-param name="testresult" select="$testresult"/>
+ <xsl:with-param name="benchmark" select="$item/ancestor::cdf:Benchmark"/>
+ <xsl:with-param name="profile" select="$profile"/>
+ </xsl:apply-templates>
+ </p>
+ </div></td></tr>
+ </xsl:if>
+ <xsl:if test="$item/cdf:warning">
+ <tr><td>Warnings</td><td>
+ <xsl:for-each select="$item/cdf:warning">
+ <div class="panel panel-warning">
+ <div class="panel-heading">
+ <span class="label label-warning">warning</span> 
+ <xsl:apply-templates mode="sub-testresult" select=".">
<xsl:with-param name="benchmark" select="$item/ancestor::cdf:Benchmark"/>
<xsl:with-param name="profile" select="$profile"/>
</xsl:apply-templates>
- </p>
- </div></td></tr>
- </xsl:if>
- <xsl:if test="$item/cdf:rationale">
- <tr><td>Rationale</td><td><div class="rationale">
- <p>
- <xsl:apply-templates mode="sub-testresult" select="$item/cdf:rationale">
- <xsl:with-param name="testresult" select="$testresult"/>
+ </div>
+ </div>
+ </xsl:for-each>
+ </td></tr>
+ </xsl:if>
+ <xsl:variable name="check_system_details_ret">
+ <xsl:call-template name="check-system-details">
+ <xsl:with-param name="check" select="cdf:check"/>
+ <xsl:with-param name="oval-tmpl" select="$oval-tmpl"/>
+ <xsl:with-param name="sce-tmpl" select="$sce-tmpl"/>
+ <xsl:with-param name="result" select="$result"/>
+ </xsl:call-template>
+ </xsl:variable>
+
+ <xsl:if test="normalize-space($check_system_details_ret)">
+ <tr><td colspan="2"><div class="check-system-details">
+ <xsl:copy-of select="$check_system_details_ret"/>
+ </div></td></tr>
+ </xsl:if>
+ <xsl:if test="cdf:message">
+ <tr><td colspan="2"><div class="evaluation-messages">
+ <span class="label label-default"><abbr title="Messages taken from rule-result">Evaluation messages</abbr></span>
+ <div class="panel panel-default">
+ <div class="panel-body">
+ <xsl:for-each select="cdf:message">
+ <xsl:if test="./@severity">
+ <span class="label label-primary"><xsl:value-of select="./@severity"/></span> 
+ </xsl:if>
+ <pre><xsl:apply-templates mode="sub-testresult" select=".">
<xsl:with-param name="benchmark" select="$item/ancestor::cdf:Benchmark"/>
<xsl:with-param name="profile" select="$profile"/>
- </xsl:apply-templates>
- </p>
- </div></td></tr>
- </xsl:if>
- <xsl:if test="$item/cdf:warning">
- <tr><td>Warnings</td><td>
- <xsl:for-each select="$item/cdf:warning">
- <div class="panel panel-warning">
- <div class="panel-heading">
- <span class="label label-warning">warning</span> 
- <xsl:apply-templates mode="sub-testresult" select=".">
- <xsl:with-param name="benchmark" select="$item/ancestor::cdf:Benchmark"/>
- <xsl:with-param name="profile" select="$profile"/>
- </xsl:apply-templates>
- </div>
- </div>
+ </xsl:apply-templates></pre>
</xsl:for-each>
- </td></tr>
- </xsl:if>
- <xsl:variable name="check_system_details_ret">
- <xsl:call-template name="check-system-details">
- <xsl:with-param name="check" select="$ruleresult/cdf:check"/>
- <xsl:with-param name="oval-tmpl" select="$oval-tmpl"/>
- <xsl:with-param name="sce-tmpl" select="$sce-tmpl"/>
- <xsl:with-param name="result" select="$result"/>
+ </div>
+ </div>
+ </div></td></tr>
+ </xsl:if>
+ <xsl:if test="$result = 'fail' or $result = 'error' or $result = 'unknown'">
+ <xsl:for-each select="$item/cdf:fixtext">
+ <tr><td colspan="2"><div class="remediation-description">
+ <xsl:call-template name="show-fixtext">
+ <xsl:with-param name="fixtext" select="."/>
+ <xsl:with-param name="testresult" select="$testresult"/>
+ <xsl:with-param name="benchmark" select="$item/ancestor::cdf:Benchmark"/>
+ <xsl:with-param name="profile" select="$profile"/>
+ </xsl:call-template>
+ </div></td></tr>
+ </xsl:for-each>
+ <xsl:for-each select="$item/cdf:fix">
+ <tr><td colspan="2"><div class="remediation">
+ <xsl:call-template name="show-fix">
+ <xsl:with-param name="fix" select="."/>
+ <xsl:with-param name="testresult" select="$testresult"/>
+ <xsl:with-param name="benchmark" select="$item/ancestor::cdf:Benchmark"/>
+ <xsl:with-param name="profile" select="$profile"/>
</xsl:call-template>
- </xsl:variable>
+ </div></td></tr>
+ </xsl:for-each>
+ </xsl:if>
+ </tbody>
+ </table>
+</xsl:template>
- <xsl:if test="normalize-space($check_system_details_ret)">
- <tr><td colspan="2"><div class="check-system-details">
- <xsl:copy-of select="$check_system_details_ret"/>
- </div></td></tr>
- </xsl:if>
- <xsl:if test="$ruleresult/cdf:message">
- <tr><td colspan="2"><div class="evaluation-messages">
- <span class="label label-default"><abbr title="Messages taken from rule-result">Evaluation messages</abbr></span>
- <div class="panel panel-default">
- <div class="panel-body">
- <xsl:for-each select="$ruleresult/cdf:message">
- <xsl:if test="./@severity">
- <span class="label label-primary"><xsl:value-of select="./@severity"/></span> 
- </xsl:if>
- <pre><xsl:apply-templates mode="sub-testresult" select=".">
- <xsl:with-param name="benchmark" select="$item/ancestor::cdf:Benchmark"/>
- <xsl:with-param name="profile" select="$profile"/>
- </xsl:apply-templates></pre>
- </xsl:for-each>
- </div>
- </div>
- </div></td></tr>
- </xsl:if>
- <xsl:if test="$result = 'fail' or $result = 'error' or $result = 'unknown'">
- <xsl:for-each select="$item/cdf:fixtext">
- <tr><td colspan="2"><div class="remediation-description">
- <xsl:call-template name="show-fixtext">
- <xsl:with-param name="fixtext" select="."/>
- <xsl:with-param name="testresult" select="$testresult"/>
- <xsl:with-param name="benchmark" select="$item/ancestor::cdf:Benchmark"/>
- <xsl:with-param name="profile" select="$profile"/>
- </xsl:call-template>
- </div></td></tr>
- </xsl:for-each>
- <xsl:for-each select="$item/cdf:fix">
- <tr><td colspan="2"><div class="remediation">
- <xsl:call-template name="show-fix">
- <xsl:with-param name="fix" select="."/>
- <xsl:with-param name="testresult" select="$testresult"/>
- <xsl:with-param name="benchmark" select="$item/ancestor::cdf:Benchmark"/>
- <xsl:with-param name="profile" select="$profile"/>
- </xsl:call-template>
- </div></td></tr>
- </xsl:for-each>
- </xsl:if>
- </tbody>
- </table>
- </div>
- </div>
- </xsl:if>
+<xsl:template name="result-details-leaf">
+ <xsl:param name="testresult"/>
+ <xsl:param name="item"/>
+ <xsl:param name="profile"/>
+
+ <xsl:variable name="ruleresult" select="key('testresult_ruleresults', concat($testresult/@id, '|', $item/@id))"/>
+ <xsl:for-each select="$ruleresult">
+ <xsl:variable name="result" select="cdf:result/text()"/>
+ <xsl:if test="$result != 'notselected'">
+ <div class="panel panel-default rule-detail rule-detail-{$result} rule-detail-id-{$item/@id}" id="rule-detail-{generate-id(.)}">
+ <div class="keywords sr-only">
+ <xsl:comment>This allows OpenSCAP JS to search the report rules</xsl:comment>
+ <xsl:call-template name="item-title">
+ <xsl:with-param name="item" select="$item"/>
+ <xsl:with-param name="testresult" select="$testresult"/>
+ <xsl:with-param name="profile" select="$profile"/>
+ </xsl:call-template>
+ <xsl:value-of select="concat($item/@id, ' ')"/>
+ <xsl:value-of select="@severity"/>
+ <xsl:for-each select="cdf:ident">
+ <xsl:value-of select="concat(text(), ' ')"/>
+ </xsl:for-each>
+ <xsl:for-each select="cdf:reference">
+ <xsl:value-of select="concat(text(), ' ')"/>
+ </xsl:for-each>
+ </div>
+ <div class="panel-heading">
+ <h3 class="panel-title">
+ <xsl:call-template name="item-title">
+ <xsl:with-param name="item" select="$item"/>
+ <xsl:with-param name="testresult" select="$testresult"/>
+ <xsl:with-param name="profile" select="$profile"/>
+ </xsl:call-template>
+ </h3>
+ </div>
+ <div class="panel-body">
+ <xsl:call-template name="result-details-leaf-table">
+ <xsl:with-param name="item" select="$item"/>
+ <xsl:with-param name="testresult" select="$testresult"/>
+ <xsl:with-param name="profile" select="$profile"/>
+ <xsl:with-param name="result" select="$result"/>
+ </xsl:call-template>
+ </div>
+ </div>
+ </xsl:if>
+ </xsl:for-each>
</xsl:template>
<xsl:template name="result-details-inner-node">