diff --git a/docs/manual/developer_guide.adoc b/docs/manual/developer_guide.adoc
index 6edabaaf7a1c..a642146de44d 100644
--- a/docs/manual/developer_guide.adoc
+++ b/docs/manual/developer_guide.adoc
@@ -1600,11 +1600,14 @@ audit_rules_usergroup_modification::
** *path* - path that should be part of the audit rule as a value of `-w` argument, eg. `/etc/group`.
* Languages: Ansible, Bash, OVAL
-bls_bootloader_option::
-* Checks kernel command line arguments in BLS-compatible (Boot Loader Specification) boot loader configuration.
+argument_value_in_line::
+* Checks that `argument=value` pair is present in (optionally) the line started with line_prefix (and, optionally, ending with line_suffix) in the file(s) defined by filepath.
* Parameters:
-** *arg_name* - argument name, eg. `audit`
-** *arg_value* - argument value, eg. `'1'`
+** *filepath* - File(s) to be checked. The value would be treated as a regular expression pattern.
+** *arg_name* - Argument name, eg. `audit`
+** *arg_value* - Argument value, eg. `'1'`
+** *line_prefix* - The prefix of the line in which argument-value pair should be present, optional.
+** *line_suffix* - The suffix of the line in which argument-value pair should be present, optional.
* Languages: OVAL
file_groupowner::
@@ -1812,8 +1815,6 @@ an OVAL template file called _template_OVAL_package_installed_:
----
-Notice that you can use Jinja macros and Jinja filters in the template code.
-
And here is the Ansible template file called _template_ANSIBLE_package_installed_:
----
@@ -1887,6 +1888,18 @@ def mount_option(data, lang):
return data
----
+==== Filters
+
+You can use Jinja macros and Jinja filters in the template code. ComplianceAsCode support all built-in Jinja link:https://jinja.palletsprojects.com/en/2.11.x/templates/#builtin-filters[filters].
+
+There are also some custom filters useful for content authoring defined in the project:
+
+escape_id::
+* Replaces all non-word (regex *\W*) characters with underscore. Useful for sanitizing ID strings as it is compatible with OVAL IDs `oval:[A-Za-z0-9_\-\.]+:ste:[1-9][0-9]*`.
+
+escape_regex::
+* Escapes characters in the string for it to be usable as a part of some regular expression, behaves similar to the Python 3's link:https://docs.python.org/3/library/re.html#re.escape[*re.escape*].
+
=== Tests (ctest)
diff --git a/linux_os/guide/system/bootloader-grub2/grub2_admin_username/oval/shared.xml b/linux_os/guide/system/bootloader-grub2/grub2_admin_username/oval/shared.xml
index c93ad9b88884..5857e7ad9ef9 100644
--- a/linux_os/guide/system/bootloader-grub2/grub2_admin_username/oval/shared.xml
+++ b/linux_os/guide/system/bootloader-grub2/grub2_admin_username/oval/shared.xml
@@ -3,12 +3,12 @@
{{{ oval_metadata("The grub2 boot loader superuser should have a username that is hard to guess.") }}}
- {{{ oval_file_absent_criterion("/boot/grub2/grub.cfg", rule_id + "_grub_cfg") }}}
+ {{{ oval_file_absent_criterion("/boot/grub2/grub.cfg") }}}
- {{{ oval_file_absent("/boot/grub2/grub.cfg", rule_id + "_grub_cfg") }}}
+ {{{ oval_file_absent("/boot/grub2/grub.cfg") }}}
diff --git a/linux_os/guide/system/bootloader-grub2/grub2_password/oval/shared.xml b/linux_os/guide/system/bootloader-grub2/grub2_password/oval/shared.xml
index 657f259c0f42..05f72fb76f21 100644
--- a/linux_os/guide/system/bootloader-grub2/grub2_password/oval/shared.xml
+++ b/linux_os/guide/system/bootloader-grub2/grub2_password/oval/shared.xml
@@ -4,7 +4,7 @@
{{{ oval_metadata("The grub2 boot loader should have password protection enabled.") }}}
- {{{ oval_file_absent_criterion(grub_cfg_prefix + "/grub.cfg", rule_id + "_grub_cfg") }}}
+ {{{ oval_file_absent_criterion(grub_cfg_prefix + "/grub.cfg") }}}
@@ -15,7 +15,7 @@
- {{{ oval_file_absent(grub_cfg_prefix + "/grub.cfg", rule_id + "_grub_cfg") }}}
+ {{{ oval_file_absent(grub_cfg_prefix + "/grub.cfg") }}}
diff --git a/linux_os/guide/system/bootloader-grub2/grub2_uefi_admin_username/oval/shared.xml b/linux_os/guide/system/bootloader-grub2/grub2_uefi_admin_username/oval/shared.xml
index 6142c8cdc33d..2062201eb6cb 100644
--- a/linux_os/guide/system/bootloader-grub2/grub2_uefi_admin_username/oval/shared.xml
+++ b/linux_os/guide/system/bootloader-grub2/grub2_uefi_admin_username/oval/shared.xml
@@ -3,12 +3,12 @@
{{{ oval_metadata("The grub2 boot loader superuser should have a username that is hard to guess.") }}}
- {{{ oval_file_absent_criterion("/boot/efi/EFI/redhat/grub.cfg", rule_id + "_grub_cfg") }}}
+ {{{ oval_file_absent_criterion("/boot/efi/EFI/redhat/grub.cfg") }}}
- {{{ oval_file_absent("/boot/efi/EFI/redhat/grub.cfg", rule_id + "_grub_cfg") }}}
+ {{{ oval_file_absent("/boot/efi/EFI/redhat/grub.cfg") }}}
diff --git a/linux_os/guide/system/bootloader-grub2/grub2_uefi_password/oval/shared.xml b/linux_os/guide/system/bootloader-grub2/grub2_uefi_password/oval/shared.xml
index 6d2a69d2ca31..74214da219f6 100644
--- a/linux_os/guide/system/bootloader-grub2/grub2_uefi_password/oval/shared.xml
+++ b/linux_os/guide/system/bootloader-grub2/grub2_uefi_password/oval/shared.xml
@@ -9,7 +9,7 @@
{{{ oval_metadata("The UEFI grub2 boot loader should have password protection enabled.") }}}
- {{{ oval_file_absent_criterion(grub_cfg_prefix + "/grub.cfg", rule_id + "_grub_cfg") }}}
+ {{{ oval_file_absent_criterion(grub_cfg_prefix + "/grub.cfg") }}}
@@ -20,7 +20,7 @@
- {{{ oval_file_absent(grub_cfg_prefix + "/grub.cfg", rule_id + "_grub_cfg") }}}
+ {{{ oval_file_absent(grub_cfg_prefix + "/grub.cfg") }}}
diff --git a/shared/macros-bash.jinja b/shared/macros-bash.jinja
index f4ef85942089..ee48bec12d3e 100644
--- a/shared/macros-bash.jinja
+++ b/shared/macros-bash.jinja
@@ -614,3 +614,28 @@ for f in $( ls /etc/sudoers /etc/sudoers.d/* 2> /dev/null ) ; do
fi
done
{{%- endmacro -%}}
+
+{{% macro bash_sssd_ldap_config(parameter, value) -%}}
+SSSD_CONF="/etc/sssd/sssd.conf"
+LDAP_REGEX='[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*{{{ parameter }}}'
+AD_REGEX='[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$'
+DOMAIN_REGEX="[[:space:]]*\[domain\/[^]]*]"
+
+# Check if id_provider is not set to ad (Active Directory) which makes start_tls not applicable, note the -v option to invert the grep.
+# Try to find [domain/..] and {{{ parameter }}} in sssd.conf, if it exists, set to '{{{ value }}}'
+# if {{{ parameter }}} isn't here, add it
+# if [domain/..] doesn't exist, add it here for default domain
+if grep -qvzosP $AD_REGEX $SSSD_CONF; then
+ if grep -qzosP $LDAP_REGEX $SSSD_CONF; then
+ sed -i "s#{{{ parameter }}}[^(\n)]*#{{{ parameter }}} = {{{ value }}}#" $SSSD_CONF
+ elif grep -qs $DOMAIN_REGEX $SSSD_CONF; then
+ sed -i "/$DOMAIN_REGEX/a {{{ parameter }}} = {{{ value }}}" $SSSD_CONF
+ else
+ if test -f "$SSSD_CONF"; then
+ echo -e "[domain/default]\n{{{ parameter }}} = {{{ value }}}" >> $SSSD_CONF
+ else
+ echo "Config file '$SSSD_CONF' doesnt exist, not remediating, assuming non-applicability." >&2
+ fi
+ fi
+fi
+{{%- endmacro %}}
diff --git a/shared/macros-oval.jinja b/shared/macros-oval.jinja
index 0e077cd8948f..f730b3c61df7 100644
--- a/shared/macros-oval.jinja
+++ b/shared/macros-oval.jinja
@@ -220,8 +220,8 @@
- filepath (String): Path to the file to be checked.
- id of the test name - the test will be named test_
#}}
-{{%- macro oval_file_absent_criterion(filepath, id) -%}}
-
+{{%- macro oval_file_absent_criterion(filepath) -%}}
+
{{%- endmacro %}}
{{#
@@ -230,12 +230,13 @@
- filepath (String): Path to the configuration file to be checked.
- id of the test name - the test will be named test_, the respective object object_ etc.
#}}
-{{%- macro oval_file_absent(filepath, id) -%}}
-
-
+{{%- macro oval_file_absent(filepath) -%}}
+
+
-
- {{{ filepath }}}
+
+ ^{{{ filepath }}}
{{%- endmacro %}}
@@ -250,6 +251,69 @@
{{%- endmacro %}}
+{{#
+ Macro to define the OVAL test to check if there is a line in file with a pair of argument=value (Criterion definition).
+ Parameters:
+ - filepath (String): Path to the file to be checked.
+ - name (String): Argument name
+ - value (String): Argument value
+ - application (String): The application which the configuration file is being checked. Can be any value and does not affect the actual OVAL check.
+#}}
+{{%- macro oval_argument_value_in_line_criterion(filepath, name, value, application='') -%}}
+{{%- set name_value = name+"="+value -%}}
+
+{{%- endmacro -%}}
+
+{{#
+ Macro to define the OVAL test to check if there is a line in file with a pair of argument=value (Test definition).
+ Parameters:
+ - filepath (String): Path to the configuration file to be checked. The operation is "pattern match"
+ - name (String): Argument name
+ - value (String): Argument value
+ - line_prefix (String): The starting part of the line with the list of arguments, default is empty
+ - line_suffix (String): The ending part of the line with the list of arguments, default is empty
+#}}
+{{%- macro oval_argument_value_in_line_test(filepath, name, value, line_prefix='', line_suffix='') -%}}
+{{%- set name_value = name+"="+value -%}}
+
+
+
+
+
+ ^{{{ filepath }}}
+ ^{{{ line_prefix|escape_regex }}}(.*){{{ line_suffix|escape_regex }}}$
+ 1
+
+
+ ^(?:.*\s)?{{{ name_value|escape_regex }}}(?:\s.*)?$
+
+{{%- endmacro -%}}
+
+{{#
+ Hight level macro to define the OVAL test to check if there is a line in file with a pair of argument=value.
+ Parameters:
+ - filepath (String): Path to the configuration file to be checked.
+ - name (String): Argument name
+ - value (String): Argument value
+ - line_prefix (String): The starting part of the line with the list of arguments, default is empty
+ - line_suffix (String): The ending part of the line with the list of arguments, default is empty
+ - application (String): The application which the configuration file is being checked. Can be any value and does not affect the actual OVAL check.
+#}}
+{{%- macro oval_argument_value_in_line(filepath, name, value, line_prefix='', line_suffix='') -%}}
+
+
+ {{{ oval_metadata("Ensure argument " + name + "=" + value + " is present"+ (" in the line starting with '" + line_prefix + "'" if line_prefix else "") + " in file(s) '" + filepath + "'") }}}
+
+ {{{- oval_argument_value_in_line_criterion(filepath, name, value, application) }}}
+
+
+ {{{- oval_argument_value_in_line_test(filepath, name, value, line_prefix, line_suffix) }}}
+
+{{%- endmacro -%}}
+
{{#
High level macro to check if a particular combination of parameter and value in the ssh daemon configuration file is set.
This macro can take five parameters:
@@ -534,29 +598,3 @@
{{{ description }}}
{{%- endmacro %}}
-
-
-{{% macro bash_sssd_ldap_config(parameter, value) -%}}
-SSSD_CONF="/etc/sssd/sssd.conf"
-LDAP_REGEX='[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*{{{ parameter }}}'
-AD_REGEX='[[:space:]]*\[domain\/[^]]*]([^(\n)]*(\n)+)+?[[:space:]]*id_provider[[:space:]]*=[[:space:]]*((?i)ad)[[:space:]]*$'
-DOMAIN_REGEX="[[:space:]]*\[domain\/[^]]*]"
-
-# Check if id_provider is not set to ad (Active Directory) which makes start_tls not applicable, note the -v option to invert the grep.
-# Try to find [domain/..] and {{{ parameter }}} in sssd.conf, if it exists, set to '{{{ value }}}'
-# if {{{ parameter }}} isn't here, add it
-# if [domain/..] doesn't exist, add it here for default domain
-if grep -qvzosP $AD_REGEX $SSSD_CONF; then
- if grep -qzosP $LDAP_REGEX $SSSD_CONF; then
- sed -i "s#{{{ parameter }}}[^(\n)]*#{{{ parameter }}} = {{{ value }}}#" $SSSD_CONF
- elif grep -qs $DOMAIN_REGEX $SSSD_CONF; then
- sed -i "/$DOMAIN_REGEX/a {{{ parameter }}} = {{{ value }}}" $SSSD_CONF
- else
- if test -f "$SSSD_CONF"; then
- echo -e "[domain/default]\n{{{ parameter }}} = {{{ value }}}" >> $SSSD_CONF
- else
- echo "Config file '$SSSD_CONF' doesnt exist, not remediating, assuming non-applicability." >&2
- fi
- fi
-fi
-{{%- endmacro %}}
diff --git a/shared/templates/template_ANSIBLE_zipl_bls_entries_option b/shared/templates/template_ANSIBLE_zipl_bls_entries_option
index bccad2267c11..7e73d391deba 100644
--- a/shared/templates/template_ANSIBLE_zipl_bls_entries_option
+++ b/shared/templates/template_ANSIBLE_zipl_bls_entries_option
@@ -4,7 +4,7 @@
# complexity = medium
# disruption = low
-- name: "Ensure BLS boot entries options contain {{{ ARG_NAME_VALUE }}}"
+- name: "Ensure BLS boot entries options contain {{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
block:
- name: "Check how many boot entries exist "
find:
@@ -12,15 +12,15 @@
patterns: "*.conf"
register: n_entries
- - name: "Check how many boot entries set {{{ ARG_NAME_VALUE }}}"
+ - name: "Check how many boot entries set {{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
find:
paths: "/boot/loader/entries/"
- contains: "^options .*{{{ ARG_NAME_VALUE }}}.*$"
+ contains: "^options .*{{{ ARG_NAME }}}={{{ ARG_VALUE }}}.*$"
patterns: "*.conf"
register: n_entries_options
- name: "Update boot entries options"
- command: grubby --update-kernel=ALL --args="{{{ ARG_NAME_VALUE }}}"
+ command: grubby --update-kernel=ALL --args="{{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
when: n_entries is defined and n_entries_options is defined and n_entries.matched != n_entries_options.matched
- name: "Check if /etc/kernel/cmdline exists"
@@ -28,25 +28,25 @@
path: /etc/kernel/cmdline
register: cmdline_stat
- - name: "Check if /etc/kernel/cmdline contains {{{ ARG_NAME_VALUE }}}"
+ - name: "Check if /etc/kernel/cmdline contains {{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
find:
paths: "/etc/kernel/"
patterns: "cmdline"
- contains: "^.*{{{ ARG_NAME_VALUE }}}.*$"
+ contains: "^.*{{{ ARG_NAME }}}={{{ ARG_VALUE }}}.*$"
register: cmdline_find
- - name: "Add /etc/kernel/cmdline contains {{{ ARG_NAME_VALUE }}}"
+ - name: "Add /etc/kernel/cmdline contains {{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
lineinfile:
create: yes
path: "/etc/kernel/cmdline"
- line: '{{{ ARG_NAME_VALUE }}}'
+ line: '{{{ ARG_NAME }}}={{{ ARG_VALUE }}}'
when: cmdline_stat is defined and not cmdline_stat.stat.exists
- - name: "Append /etc/kernel/cmdline contains {{{ ARG_NAME_VALUE }}}"
+ - name: "Append /etc/kernel/cmdline contains {{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
lineinfile:
path: "/etc/kernel/cmdline"
backrefs: yes
regexp: "^(.*)$"
- line: '\1 {{{ ARG_NAME_VALUE }}}'
+ line: '\1 {{{ ARG_NAME }}}={{{ ARG_VALUE }}}'
when: cmdline_stat is defined and cmdline_stat.stat.exists and cmdline_find is defined and cmdline_find.matched == 0
diff --git a/shared/templates/template_BASH_zipl_bls_entries_option b/shared/templates/template_BASH_zipl_bls_entries_option
index dde8c948f7a9..d0faeb805f55 100644
--- a/shared/templates/template_BASH_zipl_bls_entries_option
+++ b/shared/templates/template_BASH_zipl_bls_entries_option
@@ -1,11 +1,11 @@
# platform = Red Hat Enterprise Linux 8
# Correct BLS option using grubby, which is a thin wrapper around BLS operations
-grubby --update-kernel=ALL --args="{{{ ARG_NAME_VALUE }}}"
+grubby --update-kernel=ALL --args="{{{ ARG_NAME }}}={{{ ARG_VALUE }}}"
# Ensure new kernels and boot entries retain the boot option
if [ ! -f /etc/kernel/cmdline ]; then
- echo "{{{ ARG_NAME_VALUE }}}" >> /etc/kernel/cmdline
-elif ! grep -q '^(.*\s)?{{{ ARG_NAME_VALUE }}}(\s.*)?$' /etc/kernel/cmdline; then
- sed -Ei 's/^(.*)$/\1 {{{ ARG_NAME_VALUE }}}/' /etc/kernel/cmdline
+ echo "{{{ ARG_NAME }}}={{{ ARG_VALUE }}}" > /etc/kernel/cmdline
+elif ! grep -q '^(.*\s)?{{{ ARG_NAME }}}={{{ ARG_VALUE }}}(\s.*)?$' /etc/kernel/cmdline; then
+ sed -Ei 's/^(.*)$/\1 {{{ ARG_NAME }}}={{{ ARG_VALUE }}}/' /etc/kernel/cmdline
fi
diff --git a/shared/templates/template_OVAL_argument_in_file b/shared/templates/template_OVAL_argument_in_file
new file mode 100644
index 000000000000..14cf33e7c8cd
--- /dev/null
+++ b/shared/templates/template_OVAL_argument_in_file
@@ -0,0 +1,9 @@
+{{{
+ oval_argument_value_in_line(
+ filepath=FILEPATH,
+ name=ARG_NAME,
+ value=ARG_VALUE,
+ line_prefix=LINE_PREFIX,
+ line_suffix=LINE_SUFFIX
+ )
+}}}
diff --git a/shared/templates/template_OVAL_bls_entries_option b/shared/templates/template_OVAL_bls_entries_option
deleted file mode 100644
index d60f13c8f9c1..000000000000
--- a/shared/templates/template_OVAL_bls_entries_option
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
- {{{ oval_metadata("Ensure " + ARG_NAME_VALUE + " option is configured in the 'options' line in /boot/loader/entries/*.conf.") }}}
-
-
-
-
-
-
-
-
-
-
-
- ^/boot/loader/entries/.*\.conf$
- ^options (.*)$
- 1
-
-
-
- ^(?:.*\s)?{{{ ESCAPED_ARG_NAME_VALUE }}}(?:\s.*)?$
-
-
diff --git a/shared/templates/template_OVAL_coreos_kernel_option b/shared/templates/template_OVAL_coreos_kernel_option
index 9a161ba17368..63fbd7a490fe 100644
--- a/shared/templates/template_OVAL_coreos_kernel_option
+++ b/shared/templates/template_OVAL_coreos_kernel_option
@@ -1,71 +1,26 @@
-
- Ensure that the most recent (default) CoreOS boot loader entry is configured to run Linux operating system with argument {{{ ARG_NAME_VALUE }}}
- {{{- oval_affected(products) }}}
- Ensure {{{ ARG_NAME_VALUE }}} option is configured in the 'options' line in /boot/loader/entries/ostree-2-*.conf (or ostree-1-*.conf if the second version does not exists).
-
-
+ {{{ oval_metadata("Ensure " + ARG_NAME + "=" + ARG_VALUE +" argument is present in the 'options' line of /boot/loader/entries/ostree-2-*.conf (or ostree-1-*.conf if there is no ostree-2-*.conf as ostree has only two enries at the most, with *-2-*.conf entry always being the most recent). Also, ensure that kernel is currently running with this argument by checking /proc/cmdline.") }}}
+
+
-
+ {{{- oval_file_absent_criterion('/boot/loader/entries/ostree-2-.*.conf')}}}
+ {{{- oval_argument_value_in_line_criterion('/boot/loader/entries/ostree-1-.*.conf', ARG_NAME, ARG_VALUE, 'Linux kernel') }}}
-
-
+ {{{- oval_argument_value_in_line_criterion('/boot/loader/entries/ostree-2-.*.conf', ARG_NAME, ARG_VALUE, 'Linux kernel') }}}
-
+
+
+ {{{- oval_argument_value_in_line_criterion('/proc/cmdline', ARG_NAME, ARG_VALUE, 'Linux kernel') }}}
+
+
-
-
-
-
+ {{{- oval_file_absent('/boot/loader/entries/ostree-2-.*.conf') }}}
+ {{{- oval_argument_value_in_line_test('/boot/loader/entries/ostree-1-.*.conf', ARG_NAME, ARG_VALUE, 'options ') }}}
-
- ^/boot/loader/entries/ostree-2-*\.conf$
- ^options (.*)$
- 1
-
-
-
- ^(?:.*\s)?{{{ ESCAPED_ARG_NAME_VALUE }}}(?:\s.*)?$
-
-
-
-
-
-
-
-
- ^/boot/loader/entries/ostree-1-*\.conf$
- ^options (.*)$
- 1
-
-
-
- ^(?:.*\s)?{{{ ESCAPED_ARG_NAME_VALUE }}}(?:\s.*)?$
-
-
-
-
-
-
-
- ^/boot/loader/entries/ostree-2-*\.conf
-
+ {{{- oval_argument_value_in_line_test('/boot/loader/entries/ostree-2-.*.conf', ARG_NAME, ARG_VALUE, 'options ') }}}
+ {{{- oval_argument_value_in_line_test('/proc/cmdline', ARG_NAME, ARG_VALUE, 'BOOT_IMAGE') }}}
diff --git a/shared/templates/template_OVAL_zipl_bls_entries_option b/shared/templates/template_OVAL_zipl_bls_entries_option
index 8b786450f093..905078e28efd 100644
--- a/shared/templates/template_OVAL_zipl_bls_entries_option
+++ b/shared/templates/template_OVAL_zipl_bls_entries_option
@@ -1,43 +1,12 @@
- {{{ oval_metadata("Ensure " + ARG_NAME_VALUE + " option is configured in the 'options' line in /boot/loader/entries/*.conf.") }}}
+ {{{ oval_metadata("Ensure " + ARG_NAME + "=" + ARG_VALUE + " option is configured in the 'options' line in /boot/loader/entries/*.conf. Make sure that newly installed kernels will retain this option, it should be configured in /etc/kernel/cmdline as well.") }}}
-
-
+ {{{- oval_argument_value_in_line_criterion('/boot/loader/entries/.*.conf', ARG_NAME, ARG_VALUE, 'Linux kernel') }}}
+ {{{- oval_argument_value_in_line_criterion('/etc/kernel/cmdline', ARG_NAME, ARG_VALUE, 'Linux kernel') }}}
-
-
-
-
-
-
- ^/boot/loader/entries/.*\.conf$
- ^options (.*)$
- 1
-
-
-
-
-
-
-
- /etc/kernel/cmdline
- ^(.*)$
- 1
-
-
-
- ^(?:.*\s)?{{{ ESCAPED_ARG_NAME_VALUE }}}(?:\s.*)?$
-
+ {{{- oval_argument_value_in_line_test('/boot/loader/entries/.*.conf', ARG_NAME, ARG_VALUE, 'options ') }}}
+ {{{- oval_argument_value_in_line_test('/etc/kernel/cmdline', ARG_NAME, ARG_VALUE) }}}
diff --git a/ssg/jinja.py b/ssg/jinja.py
index e81ee4ce5232..a514f91c9a6f 100644
--- a/ssg/jinja.py
+++ b/ssg/jinja.py
@@ -23,7 +23,9 @@
name_to_platform,
prodtype_to_platform,
banner_regexify,
- banner_anchor_wrap
+ banner_anchor_wrap,
+ escape_id,
+ escape_regex
)
@@ -87,6 +89,8 @@ def _get_jinja_environment(substitutions_dict):
)
_get_jinja_environment.env.filters['banner_regexify'] = banner_regexify
_get_jinja_environment.env.filters['banner_anchor_wrap'] = banner_anchor_wrap
+ _get_jinja_environment.env.filters['escape_regex'] = escape_regex
+ _get_jinja_environment.env.filters['escape_id'] = escape_id
return _get_jinja_environment.env
diff --git a/ssg/templates.py b/ssg/templates.py
index e238ed76a09c..5543fcadaac1 100644
--- a/ssg/templates.py
+++ b/ssg/templates.py
@@ -7,6 +7,7 @@
from xml.sax.saxutils import unescape
import ssg.build_yaml
+import ssg.utils
try:
from urllib.parse import quote
@@ -25,8 +26,6 @@
"kubernetes": ".yml"
}
-def sanitize_input(string):
- return re.sub(r'[\W_]', '_', string)
templates = dict()
@@ -73,7 +72,7 @@ def audit_rules_file_deletion_events(data, lang):
@template(["ansible", "bash", "oval", "kubernetes"])
def audit_rules_login_events(data, lang):
path = data["path"]
- name = re.sub(r'[-\./]', '_', os.path.basename(os.path.normpath(path)))
+ name = ssg.utils.escape_id(os.path.basename(os.path.normpath(path)))
data["name"] = name
if lang == "oval":
data["path"] = path.replace("/", "\\/")
@@ -83,7 +82,7 @@ def audit_rules_login_events(data, lang):
@template(["ansible", "bash", "oval"])
def audit_rules_path_syscall(data, lang):
if lang == "oval":
- pathid = re.sub(r'[-\./]', '_', data["path"])
+ pathid = ssg.utils.escape_id(data["path"])
# remove root slash made into '_'
pathid = pathid[1:]
data["pathid"] = pathid
@@ -93,7 +92,7 @@ def audit_rules_path_syscall(data, lang):
@template(["ansible", "bash", "oval", "kubernetes"])
def audit_rules_privileged_commands(data, lang):
path = data["path"]
- name = re.sub(r"[-\./]", "_", os.path.basename(path))
+ name = ssg.utils.escape_id(os.path.basename(path))
data["name"] = name
if lang == "oval":
data["id"] = data["_rule_id"]
@@ -134,7 +133,7 @@ def audit_rules_unsuccessful_file_modification_rule_order(data, lang):
@template(["ansible", "bash", "oval"])
def audit_rules_usergroup_modification(data, lang):
path = data["path"]
- name = re.sub(r'[-\./]', '_', os.path.basename(path))
+ name = ssg.utils.escape_id(os.path.basename(path))
data["name"] = name
if lang == "oval":
data["path"] = path.replace("/", "\\/")
@@ -144,7 +143,7 @@ def audit_rules_usergroup_modification(data, lang):
@template(["ansible", "bash", "oval"])
def audit_file_contents(data, lang):
if lang == "oval":
- pathid = re.sub(r'[-\./]', '_', data["filepath"])
+ pathid = ssg.utils.escape_id(data["filepath"])
# remove root slash made into '_'
pathid = pathid[1:]
data["filepath_id"] = pathid
@@ -216,7 +215,7 @@ def grub2_bootloader_argument(data, lang):
# escape dot, this is used in oval regex
data["escaped_arg_name_value"] = data["arg_name_value"].replace(".", "\\.")
# replace . with _, this is used in test / object / state ids
- data["sanitized_arg_name"] = data["arg_name"].replace(".", "_")
+ data["sanitized_arg_name"] = ssg.utils.escape_id(data["arg_name"])
return data
@@ -227,13 +226,13 @@ def kernel_module_disabled(data, lang):
@template(["anaconda", "oval"])
def mount(data, lang):
- data["pointid"] = re.sub(r'[-\./]', '_', data["mountpoint"])
+ data["pointid"] = ssg.utils.escape_id(data["mountpoint"])
return data
def _mount_option(data, lang):
if lang == "oval":
- data["pointid"] = re.sub(r"[-\./]", "_", data["mountpoint"]).lstrip("_")
+ data["pointid"] = ssg.utils.escape_id(data["mountpoint"])
else:
data["mountoption"] = re.sub(" ", ",", data["mountoption"])
return data
@@ -247,7 +246,7 @@ def mount_option(data, lang):
@template(["ansible", "bash", "oval"])
def mount_option_remote_filesystems(data, lang):
if lang == "oval":
- data["mountoptionid"] = sanitize_input(data["mountoption"])
+ data["mountoptionid"] = ssg.utils.escape_id(data["mountoption"])
return _mount_option(data, lang)
@@ -270,7 +269,7 @@ def package_installed(data, lang):
@template(["ansible", "bash", "oval"])
def sysctl(data, lang):
- data["sysctlid"] = re.sub(r'[-\.]', '_', data["sysctlvar"])
+ data["sysctlid"] = ssg.utils.escape_id(data["sysctlvar"])
if not data.get("sysctlval"):
data["sysctlval"] = ""
ipv6_flag = "P"
@@ -365,24 +364,18 @@ def yamlfile_value(data, lang):
@template(["oval"])
-def bls_entries_option(data, lang):
- data["arg_name_value"] = data["arg_name"] + "=" + data["arg_value"]
- if lang == "oval":
- # escape dot, this is used in oval regex
- data["escaped_arg_name_value"] = data["arg_name_value"].replace(".", "\\.")
- # replace . with _, this is used in test / object / state ids
- data["sanitized_arg_name"] = data["arg_name"].replace(".", "_")
+def argument_value_in_line(data, lang):
return data
@template(["ansible", "bash", "oval"])
def zipl_bls_entries_option(data, lang):
- return bls_entries_option(data, lang)
+ return data
@template(["oval"])
def coreos_kernel_option(data, lang):
- return bls_entries_option(data, lang)
+ return data
class Builder(object):
diff --git a/ssg/utils.py b/ssg/utils.py
index f59445b327a4..a347c1b94104 100644
--- a/ssg/utils.py
+++ b/ssg/utils.py
@@ -252,15 +252,27 @@ def mkdir_p(path):
raise
-def banner_regexify(banner_text):
+def escape_regex(text):
# We could use re.escape(), but it escapes too many characters, including plain white space.
# In python 3.7 the set of charaters escaped by re.escape is reasonable, so lets mimic it.
# See https://docs.python.org/3/library/re.html#re.sub
# '!', '"', '%', "'", ',', '/', ':', ';', '<', '=', '>', '@', and "`" are not escaped.
- banner_text = re.sub(r"([#$&*+-.^`|~:()])", r"\\\1", banner_text)
- banner_text = banner_text.replace("\n", "BFLMPSVZ")
- banner_text = banner_text.replace(" ", "[\\s\\n]+")
- return banner_text.replace("BFLMPSVZ", "(?:[\\n]+|(?:\\\\n)+)")
+ return re.sub(r"([#$&*+-.^`|~:()])", r"\\\1", text)
+
+
+def escape_id(text):
+ # Make a string used as an Id for OSCAP/XCCDF/OVAL entities more readable
+ # and compatible with:
+ # OVAL: r'oval:[A-Za-z0-9_\-\.]+:ste:[1-9][0-9]*'
+ return re.sub(r"[^\w]+", "_", text).strip("_")
+
+
+def banner_regexify(banner_text):
+ return escape_regex(banner_text) \
+ .replace("\n", "BFLMPSVZ") \
+ .replace(" ", "[\\s\\n]+") \
+ .replace("BFLMPSVZ", "(?:[\\n]+|(?:\\\\n)+)")
+
def banner_anchor_wrap(banner_text):
return "^" + banner_text + "$"