commit 26f72c842ec184ed517fbf0d3224c421ad7cc9c6
Author: Gabriel Becker <ggasparb@redhat.com>
Date: Thu Feb 24 18:33:50 2022 +0100
Manual edited patch scap-security-guide-0.1.59-multifile_templates-PR_7405.patch.
diff --git a/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/ansible/shared.yml b/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/ansible/shared.yml
deleted file mode 100644
index f6f2ab4..0000000
--- a/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/ansible/shared.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-# platform = multi_platform_sle,Red Hat Enterprise Linux 8,multi_platform_fedora
-# reboot = false
-# strategy = restrict
-# complexity = medium
-# disruption = medium
-- name: "Read list libraries without root ownership"
- find:
- paths:
- - "/usr/lib"
- - "/usr/lib64"
- - "/lib"
- - "/lib64"
- file_type: "directory"
- register: library_dirs_not_group_owned_by_root
-
-- name: "Set group ownership of system library dirs to root"
- file:
- path: "{{ item.path }}"
- group: "root"
- state: "directory"
- mode: "{{ item.mode }}"
- with_items: "{{ library_dirs_not_group_owned_by_root.files }}"
- when:
- - library_dirs_not_group_owned_by_root.matched > 0
- - item.gid != 0
diff --git a/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/bash/shared.sh b/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/bash/shared.sh
deleted file mode 100644
index 365b983..0000000
--- a/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/bash/shared.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-# platform = multi_platform_sle,Red Hat Enterprise Linux 8,multi_platform_fedora
-
-find /lib \
-/lib64 \
-/usr/lib \
-/usr/lib64 \
-\! -group root -type d -exec chgrp root '{}' \;
diff --git a/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/oval/shared.xml b/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/oval/shared.xml
deleted file mode 100644
index 3af60ff..0000000
--- a/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/oval/shared.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<def-group>
- <definition class="compliance" id="dir_group_ownership_library_dirs" version="1">
- {{{ oval_metadata("
- Checks that /lib, /lib64, /usr/lib, /usr/lib64, /lib/modules, and
- directories therein, are group-owned by root.
- ") }}}
- <criteria operator="AND">
- <criterion test_ref="test_dir_group_ownership_lib_dir" />
- </criteria>
- </definition>
-
- <unix:file_test check="all" check_existence="none_exist" comment="library directories gid root" id="test_dir_group_ownership_lib_dir" version="1">
- <unix:object object_ref="object_dir_group_ownership_lib_dir" />
- </unix:file_test>
-
- <unix:file_object comment="library directories" id="object_dir_group_ownership_lib_dir" version="1">
- <!-- Check that /lib, /lib64, /usr/lib, and /usr/lib64 directories belong to group with gid 0 (root) -->
- <unix:path operation="pattern match">(^\/lib(|64)\/|^\/usr\/lib(|64)\/)</unix:path>
- <unix:filename xsi:nil="true" />
- <filter action="include">state_group_owner_library_dirs_not_root</filter>
- </unix:file_object>
-
- <unix:file_state id="state_group_owner_library_dirs_not_root" version="1">
- <unix:group_id datatype="int" operation="not equal">0</unix:group_id>
- </unix:file_state>
-
-</def-group>
diff --git a/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/rule.yml b/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/rule.yml
index 8c0acc0..10203c9 100644
--- a/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/rule.yml
+++ b/linux_os/guide/system/permissions/files/permissions_within_important_dirs/dir_group_ownership_library_dirs/rule.yml
@@ -1,6 +1,6 @@
documentation_complete: true
-prodtype: sle12,sle15,rhel8,fedora
+prodtype: fedora,rhel8,sle12,sle15,ubuntu2004
title: 'Verify that Shared Library Directories Have Root Group Ownership'
@@ -40,6 +40,7 @@ references:
stigid@rhel8: RHEL-08-010350
stigid@sle12: SLES-12-010876
stigid@sle15: SLES-15-010356
+ stigid@ubuntu2004: UBTU-20-010431
ocil_clause: 'any of these directories are not group-owned by root'
@@ -52,3 +53,14 @@ ocil: |-
For each of these directories, run the following command to find files not
owned by root:
<pre>$ sudo find -L <i>$DIR</i> ! -user root -type d -exec chgrp root {} \;</pre>
+
+template:
+ name: file_groupowner
+ vars:
+ filepath:
+ - /lib/
+ - /lib64/
+ - /usr/lib/
+ - /usr/lib64/
+ recursive: 'true'
+ filegid: '0'
diff --git a/products/ubuntu2004/profiles/stig.profile b/products/ubuntu2004/profiles/stig.profile
index ac96858..4c76824 100644
--- a/products/ubuntu2004/profiles/stig.profile
+++ b/products/ubuntu2004/profiles/stig.profile
@@ -470,6 +470,7 @@ selections:
# UBTU-20-010430 The Ubuntu operating system library files must be group-owned by root.
# UBTU-20-010431 The Ubuntu operating system library directories must be group-owned by root.
+ - dir_group_ownership_library_dirs
# UBTU-20-010432 The Ubuntu operating system must be configured to preserve log records from failure events.
- service_rsyslog_enabled
diff --git a/shared/templates/file_groupowner/ansible.template b/shared/templates/file_groupowner/ansible.template
index 073d356..68fc2e1 100644
--- a/shared/templates/file_groupowner/ansible.template
+++ b/shared/templates/file_groupowner/ansible.template
@@ -4,33 +4,44 @@
# complexity = low
# disruption = low
+{{% for path in FILEPATH %}}
{{% if IS_DIRECTORY and FILE_REGEX %}}
-- name: Find {{{ FILEPATH }}} file(s) matching {{{ FILE_REGEX }}}
+- name: Find {{{ path }}} file(s) matching {{{ FILE_REGEX[loop.index0] }}}
find:
- paths: "{{{ FILEPATH }}}"
- patterns: "{{{ FILE_REGEX }}}"
+ paths: "{{{ path }}}"
+ patterns: {{{ FILE_REGEX[loop.index0] }}}
use_regex: yes
register: files_found
-- name: Ensure group owner on {{{ FILEPATH }}} file(s) matching {{{ FILE_REGEX }}}
+- name: Ensure group owner on {{{ path }}} file(s) matching {{{ FILE_REGEX[loop.index0] }}}
file:
path: "{{ item.path }}"
group: "{{{ FILEGID }}}"
with_items:
- "{{ files_found.files }}"
+{{% elif IS_DIRECTORY and RECURSIVE %}}
+
+- name: Ensure group owner on {{{ path }}} recursively
+ file:
+ path: "{{{ path }}}"
+ state: directory
+ recurse: yes
+ group: "{{{ FILEGID }}}"
+
{{% else %}}
-- name: Test for existence {{{ FILEPATH }}}
+- name: Test for existence {{{ path }}}
stat:
- path: "{{{ FILEPATH }}}"
+ path: "{{{ path }}}"
register: file_exists
-- name: Ensure group owner {{{ FILEGID }}} on {{{ FILEPATH }}}
+- name: Ensure group owner {{{ FILEGID }}} on {{{ path }}}
file:
- path: "{{{ FILEPATH }}}"
+ path: "{{{ path }}}"
group: "{{{ FILEGID }}}"
when: file_exists.stat is defined and file_exists.stat.exists
{{% endif %}}
+{{% endfor %}}
diff --git a/shared/templates/file_groupowner/bash.template b/shared/templates/file_groupowner/bash.template
index 442e015..982d2f3 100644
--- a/shared/templates/file_groupowner/bash.template
+++ b/shared/templates/file_groupowner/bash.template
@@ -4,13 +4,17 @@
# complexity = low
# disruption = low
+{{% for path in FILEPATH %}}
{{% if IS_DIRECTORY and FILE_REGEX %}}
-readarray -t files < <(find {{{ FILEPATH }}})
+readarray -t files < <(find {{{ path }}})
for file in "${files[@]}"; do
- if basename $file | grep -q '{{{ FILE_REGEX }}}'; then
+ if basename $file | grep -qE '{{{ FILE_REGEX[loop.index0] }}}'; then
chgrp {{{ FILEGID }}} $file
fi
done
+{{% elif IS_DIRECTORY and RECURSIVE %}}
+find -L {{{ path }}} -type d -exec chgrp {{{ FILEGID }}} {} \;
{{% else %}}
-chgrp {{{ FILEGID }}} {{{ FILEPATH }}}
+chgrp {{{ FILEGID }}} {{{ path }}}
{{% endif %}}
+{{% endfor %}}
diff --git a/shared/templates/file_groupowner/oval.template b/shared/templates/file_groupowner/oval.template
index 1b637a6..fd2e5db 100644
--- a/shared/templates/file_groupowner/oval.template
+++ b/shared/templates/file_groupowner/oval.template
@@ -1,8 +1,16 @@
<def-group>
<definition class="compliance" id="{{{ _RULE_ID }}}" version="1">
+ {{% if FILEPATH is not string %}}
+ {{{ oval_metadata("This test makes sure that FILEPATH is group owned by " + FILEGID + ".") }}}
+ <criteria>
+ {{% for filepath in FILEPATH %}}
+ <criterion comment="Check file group ownership of {{{ filepath }}}" test_ref="test_file_groupowner{{{ FILEID }}}_{{{ loop.index0 }}}" />
+ {{% endfor %}}
+ {{% else %}}
{{{ oval_metadata("This test makes sure that " + FILEPATH + " is group owned by " + FILEGID + ".") }}}
<criteria>
<criterion comment="Check file group ownership of {{{ FILEPATH }}}" test_ref="test_file_groupowner{{{ FILEID }}}" />
+ {{% endif %}}
</criteria>
</definition>
{{%- if MISSING_FILE_PASS -%}}
@@ -12,23 +20,31 @@
{{# All defined files must exist. When using regex, at least one file must match #}}
{{% set FILE_EXISTENCE = "all_exist" %}}
{{%- endif -%}}
- <unix:file_test check="all" check_existence="{{{ FILE_EXISTENCE }}}" comment="Testing group ownership of {{{ FILEPATH }}}" id="test_file_groupowner{{{ FILEID }}}" version="1">
- <unix:object object_ref="object_file_groupowner{{{ FILEID }}}" />
- <unix:state state_ref="state_file_groupowner{{{ FILEID }}}_gid_{{{ FILEGID }}}" />
+
+
+ {{% for filepath in FILEPATH %}}
+ <unix:file_test check="all" check_existence="{{{ FILE_EXISTENCE }}}" comment="Testing group ownership of {{{ filepath }}}" id="test_file_groupowner{{{ FILEID }}}_{{{ loop.index0 }}}" version="1">
+ <unix:object object_ref="object_file_groupowner{{{ FILEID }}}_{{{ loop.index0 }}}" />
+ <unix:state state_ref="state_file_groupowner{{{ FILEID }}}_gid_{{{ FILEGID }}}_{{{ loop.index0 }}}" />
</unix:file_test>
- <unix:file_state id="state_file_groupowner{{{ FILEID }}}_gid_{{{ FILEGID }}}" version="1">
+ <unix:file_state id="state_file_groupowner{{{ FILEID }}}_gid_{{{ FILEGID }}}_{{{ loop.index0 }}}" version="1">
<unix:group_id datatype="int">{{{ FILEGID }}}</unix:group_id>
</unix:file_state>
- <unix:file_object comment="{{{ FILEPATH }}}" id="object_file_groupowner{{{ FILEID }}}" version="1">
+ <unix:file_object comment="{{{ filepath }}}" id="object_file_groupowner{{{ FILEID }}}_{{{ loop.index0 }}}" version="1">
{{%- if IS_DIRECTORY -%}}
- <unix:path>{{{ FILEPATH }}}</unix:path>
- {{%- if FILE_REGEX -%}}
- <unix:filename operation="pattern match">{{{ FILE_REGEX }}}</unix:filename>
- {{%- else -%}}
- <unix:filename xsi:nil="true" />
- {{%- endif -%}}
- {{%- else -%}}
- <unix:filepath{{% if FILEPATH_IS_REGEX %}} operation="pattern match"{{% endif %}}>{{{ FILEPATH }}}</unix:filepath>
- {{%- endif -%}}
+ {{%- if FILE_REGEX %}}
+ <unix:path>{{{ filepath[:-1] }}}</unix:path>
+ <unix:filename operation="pattern match">{{{ FILE_REGEX[loop.index0] }}}</unix:filename>
+ {{%- elif RECURSIVE %}}
+ <unix:path operation="pattern match">{{{ filepath[:-1] }}}</unix:path>
+ <unix:filename xsi:nil="true" />
+ {{%- else %}}
+ <unix:path>{{{ filepath[:-1] }}}</unix:path>
+ <unix:filename xsi:nil="true" />
+ {{%- endif %}}
+ {{%- else %}}
+ <unix:filepath{{% if FILEPATH_IS_REGEX %}} operation="pattern match"{{% endif %}}>{{{ filepath }}}</unix:filepath>
+ {{%- endif %}}
</unix:file_object>
+ {{% endfor %}}
</def-group>
diff --git a/shared/templates/file_groupowner/template.py b/shared/templates/file_groupowner/template.py
index 2263ae8..10baed9 100644
--- a/shared/templates/file_groupowner/template.py
+++ b/shared/templates/file_groupowner/template.py
@@ -1,12 +1,25 @@
-from ssg.utils import parse_template_boolean_value
+from ssg.utils import parse_template_boolean_value, check_conflict_regex_directory
def _file_owner_groupowner_permissions_regex(data):
- data["is_directory"] = data["filepath"].endswith("/")
- if "file_regex" in data and not data["is_directory"]:
- raise ValueError(
- "Used 'file_regex' key in rule '{0}' but filepath '{1}' does not "
- "specify a directory. Append '/' to the filepath or remove the "
- "'file_regex' key.".format(data["_rule_id"], data["filepath"]))
+ # this avoids code duplicates
+ if isinstance(data["filepath"], str):
+ data["filepath"] = [data["filepath"]]
+
+ if "file_regex" in data:
+ # we can have a list of filepaths, but only one regex
+ # instead of declaring the same regex multiple times
+ if isinstance(data["file_regex"], str):
+ data["file_regex"] = [data["file_regex"]] * len(data["filepath"])
+
+ # if the length of filepaths and file_regex are not the same, then error.
+ # in case we have multiple regexes for just one filepath, than we need
+ # to declare that filepath multiple times
+ if len(data["filepath"]) != len(data["file_regex"]):
+ raise ValueError(
+ "You should have one file_path per file_regex. Please check "
+ "rule '{0}'".format(data["_rule_id"]))
+
+ check_conflict_regex_directory(data)
def preprocess(data, lang):
@@ -14,6 +27,10 @@ def preprocess(data, lang):
data["missing_file_pass"] = parse_template_boolean_value(data, parameter="missing_file_pass", default_value=False)
+ data["recursive"] = parse_template_boolean_value(data,
+ parameter="recursive",
+ default_value=False)
+
if lang == "oval":
data["fileid"] = data["_rule_id"].replace("file_groupowner", "")
return data
diff --git a/shared/templates/file_owner/ansible.template b/shared/templates/file_owner/ansible.template
index 6083fbe..80eaae8 100644
--- a/shared/templates/file_owner/ansible.template
+++ b/shared/templates/file_owner/ansible.template
@@ -4,33 +4,44 @@
# complexity = low
# disruption = low
+{{% for path in FILEPATH %}}
{{% if IS_DIRECTORY and FILE_REGEX %}}
-- name: Find {{{ FILEPATH }}} file(s) matching {{{ FILE_REGEX }}}
+- name: Find {{{ path }}} file(s) matching {{{ FILE_REGEX[loop.index0] }}}
find:
- paths: "{{{ FILEPATH }}}"
- patterns: "{{{ FILE_REGEX }}}"
+ paths: "{{{ path }}}"
+ patterns: {{{ FILE_REGEX[loop.index0] }}}
use_regex: yes
register: files_found
-- name: Ensure group owner on {{{ FILEPATH }}} file(s) matching {{{ FILE_REGEX }}}
+- name: Ensure group owner on {{{ path }}} file(s) matching {{{ FILE_REGEX[loop.index0] }}}
file:
path: "{{ item.path }}"
owner: "{{{ FILEUID }}}"
with_items:
- "{{ files_found.files }}"
+{{% elif IS_DIRECTORY and RECURSIVE %}}
+
+- name: Ensure owner on {{{ path }}} recursively
+ file:
+ paths "{{{ path }}}"
+ state: directory
+ recurse: yes
+ owner: "{{{ FILEUID }}}"
+
{{% else %}}
-- name: Test for existence {{{ FILEPATH }}}
+- name: Test for existence {{{ path }}}
stat:
- path: "{{{ FILEPATH }}}"
+ path: "{{{ path }}}"
register: file_exists
-- name: Ensure owner {{{ FILEUID }}} on {{{ FILEPATH }}}
+- name: Ensure owner {{{ FILEUID }}} on {{{ path }}}
file:
- path: "{{{ FILEPATH }}}"
+ path: "{{{ path }}}"
owner: "{{{ FILEUID }}}"
when: file_exists.stat is defined and file_exists.stat.exists
{{% endif %}}
+{{% endfor %}}
diff --git a/shared/templates/file_owner/bash.template b/shared/templates/file_owner/bash.template
index 16025b7..27b5a2a 100644
--- a/shared/templates/file_owner/bash.template
+++ b/shared/templates/file_owner/bash.template
@@ -4,13 +4,17 @@
# complexity = low
# disruption = low
+{{% for path in FILEPATH %}}
{{% if IS_DIRECTORY and FILE_REGEX %}}
-readarray -t files < <(find {{{ FILEPATH }}})
+readarray -t files < <(find {{{ path }}})
for file in "${files[@]}"; do
- if basename $file | grep -q '{{{ FILE_REGEX }}}'; then
+ if basename $file | grep -qE '{{{ FILE_REGEX[loop.index0] }}}'; then
chown {{{ FILEUID }}} $file
fi
done
+{{% elif IS_DIRECTORY and RECURSIVE %}}
+find -L {{{ path }}} -type d -exec chown {{{ FILEUID }}} {} \;
{{% else %}}
-chown {{{ FILEUID }}} {{{ FILEPATH }}}
+chown {{{ FILEUID }}} {{{ path }}}
{{% endif %}}
+{{% endfor %}}
diff --git a/shared/templates/file_owner/oval.template b/shared/templates/file_owner/oval.template
index 23ac161..105e29c 100644
--- a/shared/templates/file_owner/oval.template
+++ b/shared/templates/file_owner/oval.template
@@ -1,8 +1,16 @@
<def-group>
<definition class="compliance" id="{{{ _RULE_ID }}}" version="1">
+ {{% if FILEPATH is not string %}}
+ {{{ oval_metadata("This test makes sure that FILEPATH is owned by " + FILEUID + ".") }}}
+ <criteria>
+ {{% for filepath in FILEPATH %}}
+ <criterion comment="Check file ownership of {{{ filepath }}}" test_ref="test_file_owner{{{ FILEID }}}_{{{ loop.index0 }}}" />
+ {{% endfor %}}
+ {{% else %}}
{{{ oval_metadata("This test makes sure that " + FILEPATH + " is owned by " + FILEUID + ".") }}}
<criteria>
<criterion comment="Check file ownership of {{{ FILEPATH }}}" test_ref="test_file_owner{{{ FILEID }}}" />
+ {{% endif %}}
</criteria>
</definition>
{{%- if MISSING_FILE_PASS -%}}
@@ -12,23 +20,30 @@
{{# All defined files must exist. When using regex, at least one file must match #}}
{{% set FILE_EXISTENCE = "all_exist" %}}
{{%- endif -%}}
- <unix:file_test check="all" check_existence="{{{ FILE_EXISTENCE }}}" comment="Testing user ownership of {{{ FILEPATH }}}" id="test_file_owner{{{ FILEID }}}" version="1">
- <unix:object object_ref="object_file_owner{{{ FILEID }}}" />
- <unix:state state_ref="state_file_owner{{{ FILEID }}}_uid_{{{ FILEUID }}}" />
+
+ {{% for filepath in FILEPATH %}}
+ <unix:file_test check="all" check_existence="{{{ FILE_EXISTENCE }}}" comment="Testing user ownership of {{{ filepath }}}" id="test_file_owner{{{ FILEID }}}_{{{ loop.index0 }}}" version="1">
+ <unix:object object_ref="object_file_owner{{{ FILEID }}}_{{{ loop.index0 }}}" />
+ <unix:state state_ref="state_file_owner{{{ FILEID }}}_uid_{{{ FILEUID }}}_{{{ loop.index0 }}}" />
</unix:file_test>
- <unix:file_state id="state_file_owner{{{ FILEID }}}_uid_{{{ FILEUID }}}" version="1">
+ <unix:file_state id="state_file_owner{{{ FILEID }}}_uid_{{{ FILEUID }}}_{{{ loop.index0 }}}" version="1">
<unix:user_id datatype="int">{{{ FILEUID }}}</unix:user_id>
</unix:file_state>
- <unix:file_object comment="{{{ FILEPATH }}}" id="object_file_owner{{{ FILEID }}}" version="1">
+ <unix:file_object comment="{{{ filepath }}}" id="object_file_owner{{{ FILEID }}}_{{{ loop.index0 }}}" version="1">
{{%- if IS_DIRECTORY -%}}
- <unix:path>{{{ FILEPATH }}}</unix:path>
- {{%- if FILE_REGEX -%}}
- <unix:filename operation="pattern match">{{{ FILE_REGEX }}}</unix:filename>
- {{%- else -%}}
- <unix:filename xsi:nil="true" />
- {{%- endif -%}}
- {{%- else -%}}
- <unix:filepath{{% if FILEPATH_IS_REGEX %}} operation="pattern match"{{% endif %}}>{{{ FILEPATH }}}</unix:filepath>
- {{%- endif -%}}
+ {{%- if FILE_REGEX %}}
+ <unix:path>{{{ filepath[:-1] }}}</unix:path>
+ <unix:filename operation="pattern match">{{{ FILE_REGEX[loop.index0] }}}</unix:filename>
+ {{%- elif RECURSIVE %}}
+ <unix:path operation="pattern match">{{{ filepath[:-1] }}}</unix:path>
+ <unix:filename xsi:nil="true" />
+ {{%- else %}}
+ <unix:path>{{{ filepath[:-1] }}}</unix:path>
+ <unix:filename xsi:nil="true" />
+ {{%- endif %}}
+ {{%- else %}}
+ <unix:filepath{{% if FILEPATH_IS_REGEX %}} operation="pattern match"{{% endif %}}>{{{ filepath }}}</unix:filepath>
+ {{%- endif %}}
</unix:file_object>
+ {{% endfor %}}
</def-group>
diff --git a/shared/templates/file_owner/template.py b/shared/templates/file_owner/template.py
index 0dd0008..1391dcf 100644
--- a/shared/templates/file_owner/template.py
+++ b/shared/templates/file_owner/template.py
@@ -1,12 +1,25 @@
-from ssg.utils import parse_template_boolean_value
+from ssg.utils import parse_template_boolean_value, check_conflict_regex_directory
def _file_owner_groupowner_permissions_regex(data):
- data["is_directory"] = data["filepath"].endswith("/")
- if "file_regex" in data and not data["is_directory"]:
- raise ValueError(
- "Used 'file_regex' key in rule '{0}' but filepath '{1}' does not "
- "specify a directory. Append '/' to the filepath or remove the "
- "'file_regex' key.".format(data["_rule_id"], data["filepath"]))
+ # this avoids code duplicates
+ if isinstance(data["filepath"], str):
+ data["filepath"] = [data["filepath"]]
+
+ if "file_regex" in data:
+ # we can have a list of filepaths, but only one regex
+ # instead of declaring the same regex multiple times
+ if isinstance(data["file_regex"], str):
+ data["file_regex"] = [data["file_regex"]] * len(data["filepath"])
+
+ # if the length of filepaths and file_regex are not the same, then error.
+ # in case we have multiple regexes for just one filepath, than we need
+ # to declare that filepath multiple times
+ if len(data["filepath"]) != len(data["file_regex"]):
+ raise ValueError(
+ "You should have one file_path per file_regex. Please check "
+ "rule '{0}'".format(data["_rule_id"]))
+
+ check_conflict_regex_directory(data)
def preprocess(data, lang):
@@ -14,6 +27,10 @@ def preprocess(data, lang):
data["missing_file_pass"] = parse_template_boolean_value(data, parameter="missing_file_pass", default_value=False)
+ data["recursive"] = parse_template_boolean_value(data,
+ parameter="recursive",
+ default_value=False)
+
if lang == "oval":
data["fileid"] = data["_rule_id"].replace("file_owner", "")
return data
diff --git a/shared/templates/file_permissions/ansible.template b/shared/templates/file_permissions/ansible.template
index 029d03f..fc211bd 100644
--- a/shared/templates/file_permissions/ansible.template
+++ b/shared/templates/file_permissions/ansible.template
@@ -3,33 +3,45 @@
# strategy = configure
# complexity = low
# disruption = low
+
+{{% for path in FILEPATH %}}
{{% if IS_DIRECTORY and FILE_REGEX %}}
-- name: Find {{{ FILEPATH }}} file(s)
+- name: Find {{{ path }}} file(s)
find:
- paths: "{{{ FILEPATH }}}"
- patterns: "{{{ FILE_REGEX }}}"
+ paths: "{{{ path }}}"
+ patterns: {{{ FILE_REGEX[loop.index0] }}}
use_regex: yes
register: files_found
-- name: Set permissions for {{{ FILEPATH }}} file(s)
+- name: Set permissions for {{{ path }}} file(s)
file:
path: "{{ item.path }}"
mode: "{{{ FILEMODE }}}"
with_items:
- "{{ files_found.files }}"
+{{% elif IS_DIRECTORY and RECURSIVE %}}
+
+- name: Set permissions for {{{ path }}} recursively
+ file:
+ path: "{{{ path }}}"
+ state: directory
+ recurse: yes
+ mode: "{{{ FILEMODE }}}"
+
{{% else %}}
-- name: Test for existence {{{ FILEPATH }}}
+- name: Test for existence {{{ path }}}
stat:
- path: "{{{ FILEPATH }}}"
+ path: "{{{ path }}}"
register: file_exists
-- name: Ensure permission {{{ FILEMODE }}} on {{{ FILEPATH }}}
+- name: Ensure permission {{{ FILEMODE }}} on {{{ path }}}
file:
- path: "{{{ FILEPATH }}}"
+ path: "{{{ path }}}"
mode: "{{{ FILEMODE }}}"
when: file_exists.stat is defined and file_exists.stat.exists
{{% endif %}}
+{{% endfor %}}
diff --git a/shared/templates/file_permissions/bash.template b/shared/templates/file_permissions/bash.template
index af9cf4e..e0d8fe9 100644
--- a/shared/templates/file_permissions/bash.template
+++ b/shared/templates/file_permissions/bash.template
@@ -4,13 +4,17 @@
# complexity = low
# disruption = low
+{{% for path in FILEPATH %}}
{{% if IS_DIRECTORY and FILE_REGEX %}}
-readarray -t files < <(find {{{ FILEPATH }}})
+readarray -t files < <(find {{{ path }}})
for file in "${files[@]}"; do
- if basename $file | grep -q '{{{ FILE_REGEX }}}'; then
+ if basename $file | grep -qE '{{{ FILE_REGEX[loop.index0] }}}'; then
chmod {{{ FILEMODE }}} $file
fi
done
+{{% elif IS_DIRECTORY and RECURSIVE %}}
+find -L {{{ path }}} -type d -exec chmod {{{ FILEMODE }}} {} \;
{{% else %}}
-chmod {{{ FILEMODE }}} {{{ FILEPATH }}}
+chmod {{{ FILEMODE }}} {{{ path }}}
{{% endif %}}
+{{% endfor %}}
diff --git a/shared/templates/file_permissions/oval.template b/shared/templates/file_permissions/oval.template
index f570ff8..89083e8 100644
--- a/shared/templates/file_permissions/oval.template
+++ b/shared/templates/file_permissions/oval.template
@@ -16,31 +16,47 @@
{{%- endif -%}}
<def-group>
<definition class="compliance" id="{{{ _RULE_ID }}}" version="1">
- {{{ oval_metadata("This test makes sure that " + FILEPATH + " has mode " + FILEMODE + ".
+ {{% if FILEPATH is not string %}}
+ {{{ oval_metadata("This test makes sure that FILEPATH has mode " + FILEMODE + ".
+ If the target file or directory has an extended ACL, then it will fail the mode check.
+ ") }}}
+ <criteria>
+ {{% for filepath in FILEPATH %}}
+ <criterion comment="Check file mode of {{{ filepath }}}" test_ref="test_file_permissions{{{ FILEID }}}_{{{ loop.index0 }}}"{{{ ' negate="true"' if ALLOW_STRICTER_PERMISSIONS }}}/>
+ {{% endfor %}}
+ {{% else %}}
+ {{{ oval_metadata("This test makes sure that " + FILEPATH + " has mode " + FILEMODE + ".
If the target file or directory has an extended ACL, then it will fail the mode check.
") }}}
<criteria>
<criterion comment="Check file mode of {{{ FILEPATH }}}" test_ref="test_file_permissions{{{ FILEID }}}"{{{ ' negate="true"' if ALLOW_STRICTER_PERMISSIONS }}}/>
+ {{% endif %}}
</criteria>
</definition>
- <unix:file_test check="all" check_existence="{{{ FILE_EXISTENCE }}}" comment="Testing mode of {{{ FILEPATH }}}" id="test_file_permissions{{{ FILEID }}}" version="2">
- <unix:object object_ref="object_file_permissions{{{ FILEID }}}" />
- <unix:state state_ref="state_file_permissions{{{ FILEID }}}_mode_{{{ 'not_' if ALLOW_STRICTER_PERMISSIONS }}}{{{ FILEMODE }}}" />
- </unix:file_test>
- <unix:file_state id="state_file_permissions{{{ FILEID }}}_mode_{{{ 'not_' if ALLOW_STRICTER_PERMISSIONS }}}{{{ FILEMODE }}}"{{{ ' operator="OR"' if ALLOW_STRICTER_PERMISSIONS }}} version="2">
+
+ {{% for filepath in FILEPATH %}}
+ <unix:file_test check="all" check_existence="{{{ FILE_EXISTENCE }}}" comment="Testing mode of {{{ filepath }}}" id="test_file_permissions{{{ FILEID }}}_{{{ loop.index0 }}}" version="2">
+ <unix:object object_ref="object_file_permissions{{{ FILEID }}}_{{{ loop.index0 }}}" />
+ <unix:state state_ref="state_file_permissions{{{ FILEID }}}_{{{ loop.index0 }}}_mode_{{{ 'not_' if ALLOW_STRICTER_PERMISSIONS }}}{{{ FILEMODE }}}" />
+ </unix:file_test>
+ <unix:file_state id="state_file_permissions{{{ FILEID }}}_{{{ loop.index0 }}}_mode_{{{ 'not_' if ALLOW_STRICTER_PERMISSIONS }}}{{{ FILEMODE }}}"{{{ ' operator="OR"' if ALLOW_STRICTER_PERMISSIONS }}} version="2">
{{{ STATEMODE | indent(6) }}}
- </unix:file_state>
- <unix:file_object comment="{{{ FILEPATH }}}" id="object_file_permissions{{{ FILEID }}}" version="1">
+ </unix:file_state>
+ <unix:file_object comment="{{{ filepath }}}" id="object_file_permissions{{{ FILEID }}}_{{{ loop.index0 }}}" version="1">
{{%- if IS_DIRECTORY %}}
- <unix:path>{{{ FILEPATH }}}</unix:path>
{{%- if FILE_REGEX %}}
- <unix:filename operation="pattern match">{{{ FILE_REGEX }}}</unix:filename>
+ <unix:path>{{{ filepath[:-1] }}}</unix:path>
+ <unix:filename operation="pattern match">{{{ FILE_REGEX[loop.index0] }}}</unix:filename>
+ {{%- elif RECURSIVE %}}
+ <unix:path operation="pattern match">{{{ filepath[:-1] }}}</unix:path>
+ <unix:filename xsi:nil="true" />
{{%- else %}}
+ <unix:path>{{{ filepath[:-1] }}}</unix:path>
<unix:filename xsi:nil="true" />
{{%- endif %}}
{{%- else %}}
- <unix:filepath{{% if FILEPATH_IS_REGEX %}} operation="pattern match"{{% endif %}}>{{{ FILEPATH }}}</unix:filepath>
+ <unix:filepath{{% if FILEPATH_IS_REGEX %}} operation="pattern match"{{% endif %}}>{{{ filepath }}}</unix:filepath>
{{%- endif %}}
{{%- if ALLOW_STRICTER_PERMISSIONS %}}
@@ -49,8 +65,8 @@
https://github.com/OpenSCAP/openscap/pull/1709 but this line should be kept until the
fix is widely available. The fix is expected to be part of OpenSCAP >= 1.3.5.
#}}
- <filter action="include">state_file_permissions{{{ FILEID }}}_mode_not_{{{ FILEMODE }}}</filter>
+ <filter action="include">state_file_permissions{{{ FILEID }}}_{{{ loop.index0 }}}_mode_not_{{{ FILEMODE }}}</filter>
{{%- endif %}}
-
- </unix:file_object>
+ </unix:file_object>
+ {{% endfor %}}
</def-group>
diff --git a/shared/templates/file_permissions/template.py b/shared/templates/file_permissions/template.py
index 677e083..6e20a62 100644
--- a/shared/templates/file_permissions/template.py
+++ b/shared/templates/file_permissions/template.py
@@ -1,12 +1,25 @@
-from ssg.utils import parse_template_boolean_value
+from ssg.utils import parse_template_boolean_value, check_conflict_regex_directory
def _file_owner_groupowner_permissions_regex(data):
- data["is_directory"] = data["filepath"].endswith("/")
- if "file_regex" in data and not data["is_directory"]:
- raise ValueError(
- "Used 'file_regex' key in rule '{0}' but filepath '{1}' does not "
- "specify a directory. Append '/' to the filepath or remove the "
- "'file_regex' key.".format(data["_rule_id"], data["filepath"]))
+ # this avoids code duplicates
+ if isinstance(data["filepath"], str):
+ data["filepath"] = [data["filepath"]]
+
+ if "file_regex" in data:
+ # we can have a list of filepaths, but only one regex
+ # instead of declaring the same regex multiple times
+ if isinstance(data["file_regex"], str):
+ data["file_regex"] = [data["file_regex"]] * len(data["filepath"])
+
+ # if the length of filepaths and file_regex are not the same, then error.
+ # in case we have multiple regexes for just one filepath, than we need
+ # to declare that filepath multiple times
+ if len(data["filepath"]) != len(data["file_regex"]):
+ raise ValueError(
+ "You should have one file_path per file_regex. Please check "
+ "rule '{0}'".format(data["_rule_id"]))
+
+ check_conflict_regex_directory(data)
def preprocess(data, lang):
@@ -16,6 +29,10 @@ def preprocess(data, lang):
data["missing_file_pass"] = parse_template_boolean_value(data, parameter="missing_file_pass", default_value=False)
+ data["recursive"] = parse_template_boolean_value(data,
+ parameter="recursive",
+ default_value=False)
+
if lang == "oval":
data["fileid"] = data["_rule_id"].replace("file_permissions", "")
# build the state that describes our mode
diff --git a/ssg/utils.py b/ssg/utils.py
index b0ded09..2248b1e 100644
--- a/ssg/utils.py
+++ b/ssg/utils.py
@@ -303,3 +303,25 @@ def parse_template_boolean_value(data, parameter, default_value):
raise ValueError(
"Template parameter {} used in rule {} cannot accept the "
"value {}".format(parameter, data["_rule_id"], value))
+
+
+def check_conflict_regex_directory(data):
+ """
+ Validate that either all path are directories OR file_regex exists.
+
+ Throws ValueError.
+ """
+ for f in data["filepath"]:
+ if "is_directory" in data and data["is_directory"] != f.endswith("/"):
+ raise ValueError(
+ "If passing a list of filepaths, all of them need to be "
+ "either directories or files. Mixing is not possible. "
+ "Please fix rules '{0}' filepath '{1}'".format(data["_rule_id"], f))
+
+ data["is_directory"] = f.endswith("/")
+
+ if "file_regex" in data and not data["is_directory"]:
+ raise ValueError(
+ "Used 'file_regex' key in rule '{0}' but filepath '{1}' does not "
+ "specify a directory. Append '/' to the filepath or remove the "
+ "'file_regex' key.".format(data["_rule_id"], f))