760 lines
33 KiB
Diff
760 lines
33 KiB
Diff
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))
|