Blob Blame History Raw
commit dc273bb872cc53f2d52af4396f4d3bba0acc178f
Author: Gabriel Becker <ggasparb@redhat.com>
Date:   Thu Feb 24 17:30:42 2022 +0100

    Manual edited patch scap-security-guide-0.1.59-BZ1884687C-PR_7824.patch.

diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/ansible/shared.yml b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/ansible/shared.yml
new file mode 100644
index 0000000..ff41e19
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/ansible/shared.yml
@@ -0,0 +1,32 @@
+# platform = multi_platform_all
+# reboot = false
+# strategy = restrict
+# complexity = low
+# disruption = low
+
+- name: Get all local users from /etc/passwd
+  ansible.builtin.getent:
+    database: passwd
+    split: ':'
+
+- name: Create local_users variable from the getent output
+  ansible.builtin.set_fact:
+    local_users: '{{ ansible_facts.getent_passwd|dict2items }}'
+
+- name: Test for existence home directories to avoid creating them, but only fixing ownership
+  ansible.builtin.stat:
+    path: '{{ item.value[4] }}'
+  register: path_exists
+  loop: '{{ local_users }}'
+  when:
+    - item.value[2]|int >= {{{ gid_min }}}
+    - item.value[2]|int != 65534
+
+- name: Ensure interactive local users are the owners of their respective home directories
+  ansible.builtin.file:
+    path: '{{ item.0.value[4] }}'
+    group: '{{ item.0.value[2] }}'
+    recurse: yes
+  loop: '{{ local_users|zip(path_exists.results)|list }}'
+  when:
+    - item.1.stat is defined and item.1.stat.exists
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/bash/shared.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/bash/shared.sh
new file mode 100644
index 0000000..e392d2f
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/bash/shared.sh
@@ -0,0 +1,14 @@
+# platform = multi_platform_all
+# reboot = false
+# strategy = restrict
+# complexity = low
+# disruption = low
+
+for user in $(awk -F':' '{ if ($4 >= {{{ gid_min }}} && $4 != 65534) print $1 }' /etc/passwd); do
+    home_dir=$(getent passwd $user | cut -d: -f6)
+    group=$(getent passwd $user | cut -d: -f4)
+    # Only update the group-ownership when necessary. This will avoid changing the inode timestamp
+    # when the group is already defined as expected, therefore not impacting in possible integrity
+    # check systems that also check inodes timestamps.
+    find $home_dir -not -group $group -exec chgrp -f $group {} \;
+done
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/oval/shared.xml b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/oval/shared.xml
new file mode 100644
index 0000000..1fd016a
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/oval/shared.xml
@@ -0,0 +1,52 @@
+<def-group>
+  <definition class="compliance" id="{{{ rule_id }}}" version="1">
+    {{{ oval_metadata("All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary User") }}}
+    <criteria>
+      <criterion test_ref="test_accounts_users_home_files_groupownership"
+                 comment="All User Files and Directories In The Home Directory Must Be Group-Owned By The Primary User"/>
+    </criteria>
+  </definition>
+
+  <unix:password_object id="object_accounts_users_home_files_groupownership_objects" version="1">
+    <unix:username datatype="string" operation="not equal">nobody</unix:username>
+    <filter action="include">state_accounts_users_home_files_groupownership_interactive_gids</filter>
+  </unix:password_object>
+
+  <unix:password_state id="state_accounts_users_home_files_groupownership_interactive_gids" version="1">
+    <unix:user_id datatype="int" operation="greater than or equal">{{{ gid_min }}}</unix:user_id>
+  </unix:password_state>
+
+  <local_variable id="var_accounts_users_home_files_groupownership_dirs" datatype="string" version="1"
+                  comment="Variable including all home dirs from interactive users">
+    <object_component item_field="home_dir"
+                      object_ref="object_accounts_users_home_files_groupownership_objects"/>
+  </local_variable>
+
+  <local_variable id="var_accounts_users_home_files_groupownership_gids" datatype="int" version="1"
+                  comment="List of interactive users gids">
+    <object_component item_field="group_id"
+                      object_ref="object_accounts_users_home_files_groupownership_objects"/>
+  </local_variable>
+
+  <!-- #### creation of object #### -->
+  <unix:file_object id="object_accounts_users_home_files_groupownership_dirs" version="1">
+    <unix:behaviors recurse="directories" recurse_direction="down" max_depth="-1"
+                    recurse_file_system="local"/>
+    <unix:path var_ref="var_accounts_users_home_files_groupownership_dirs" var_check="at least one"/>
+    <unix:filename operation="pattern match">.*</unix:filename>
+  </unix:file_object>
+
+  <!-- #### creation of state #### -->
+  <unix:file_state id="state_accounts_users_home_files_groupownership_gids" version="1">
+    <unix:group_id datatype="int" var_check="only one"
+                  var_ref="var_accounts_users_home_files_groupownership_gids"/>
+  </unix:file_state>
+
+  <!-- #### creation of test #### -->
+  <unix:file_test id="test_accounts_users_home_files_groupownership" check="all"
+                  check_existence="any_exist" version="1"
+                  comment="All home directories files are group-owned by a local interactive user">
+    <unix:object object_ref="object_accounts_users_home_files_groupownership_dirs"/>
+    <unix:state state_ref="state_accounts_users_home_files_groupownership_gids"/>
+  </unix:file_test>
+</def-group>
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/rule.yml b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/rule.yml
index 1c0f93a..31a0f1d 100644
--- a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/rule.yml
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/rule.yml
@@ -10,6 +10,9 @@ description: |-
     local interactive users files and directories, use the following command:
     <pre>$ sudo chgrp <i>USER_GROUP</i> /home/<i>USER</i>/<i>FILE_DIR</i></pre>
 
+    This rule ensures every file or directory under the home directory related
+    to an interactive user is group-owned by an interactive user.
+
 rationale: |-
     If a local interactive users files are group-owned by a group of which the
     user is not a member, unintended users may be able to access them.
@@ -33,3 +36,9 @@ ocil: |-
     group-owned by a group the user is a member of, run the
     following command:
     <pre>$ sudo ls -lLR /home/<i>USER</i></pre>
+
+warnings:
+    - general: |-
+       Due to OVAL limitation, this rule can report a false negative in a
+       specific situation where two interactive users swap the group-ownership
+       of folders or files in their respective home directories.
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/expected_groupowner.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/expected_groupowner.pass.sh
new file mode 100644
index 0000000..8538430
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/expected_groupowner.pass.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -m $USER
+echo "$USER" > /home/$USER/$USER.txt
+chgrp -f $USER /home/$USER/$USER.txt
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/home_dirs_all_absent.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/home_dirs_all_absent.pass.sh
new file mode 100644
index 0000000..af24025
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/home_dirs_all_absent.pass.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -M $USER
+# This make sure home dirs related to test environment users are also removed.
+rm -Rf /home/*
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/home_dirs_one_absent.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/home_dirs_one_absent.pass.sh
new file mode 100644
index 0000000..5bce517
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/home_dirs_one_absent.pass.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+USER1="cac_user1"
+USER2="cac_user2"
+
+useradd -m $USER1
+useradd -M $USER2
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/interactive_users_absent.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/interactive_users_absent.pass.sh
new file mode 100644
index 0000000..ed34f09
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/interactive_users_absent.pass.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+# remove all interactive users (ID >= 1000) from /etc/passwd
+sed -i '/.*:[0-9]\{4,\}:/d' /etc/passwd
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/unexpected_groupowner_system_gid.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/unexpected_groupowner_system_gid.fail.sh
new file mode 100644
index 0000000..f105723
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/unexpected_groupowner_system_gid.fail.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -m $USER
+echo "$USER" > /home/$USER/$USER.txt
+chgrp 2 /home/$USER/$USER.txt
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/unexpected_groupowner_unknown_gid.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/unexpected_groupowner_unknown_gid.fail.sh
new file mode 100644
index 0000000..00fa481
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/unexpected_groupowner_unknown_gid.fail.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -m $USER
+echo "$USER" > /home/$USER/$USER.txt
+chgrp 10005 /home/$USER/$USER.txt
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/warning_home_dirs_swapped_groupowner.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/warning_home_dirs_swapped_groupowner.pass.sh
new file mode 100644
index 0000000..052aa7c
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_groupownership/tests/warning_home_dirs_swapped_groupowner.pass.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+USER1="cac_user1"
+USER2="cac_user2"
+
+useradd -m $USER1
+useradd -m $USER2
+echo "$USER1" > /home/$USER1/$USER1.txt
+echo "$USER2" > /home/$USER2/$USER2.txt
+# Swap the ownership of files in two home directories
+# WARNING: This test scenario will report a false negative, as explained in the
+# warning section of this rule.
+chgrp -f $USER2 /home/$USER1/$USER1.txt
+chgrp -f $USER1 /home/$USER2/$USER2.txt
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/ansible/shared.yml b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/ansible/shared.yml
new file mode 100644
index 0000000..40a0579
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/ansible/shared.yml
@@ -0,0 +1,32 @@
+# platform = multi_platform_all
+# reboot = false
+# strategy = restrict
+# complexity = low
+# disruption = low
+
+- name: Get all local users from /etc/passwd
+  ansible.builtin.getent:
+    database: passwd
+    split: ':'
+
+- name: Create local_users variable from the getent output
+  ansible.builtin.set_fact:
+    local_users: '{{ ansible_facts.getent_passwd|dict2items }}'
+
+- name: Test for existence home directories to avoid creating them, but only fixing ownership
+  ansible.builtin.stat:
+    path: '{{ item.value[4] }}'
+  register: path_exists
+  loop: '{{ local_users }}'
+  when:
+    - item.value[1]|int >= {{{ uid_min }}}
+    - item.value[1]|int != 65534
+
+- name: Ensure interactive local users are the owners of their respective home directories
+  ansible.builtin.file:
+    path: '{{ item.0.value[4] }}'
+    owner: '{{ item.0.value[1] }}'
+    recurse: yes
+  loop: '{{ local_users|zip(path_exists.results)|list }}'
+  when:
+    - item.1.stat is defined and item.1.stat.exists
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/bash/shared.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/bash/shared.sh
new file mode 100644
index 0000000..236c800
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/bash/shared.sh
@@ -0,0 +1,13 @@
+# platform = multi_platform_all
+# reboot = false
+# strategy = restrict
+# complexity = low
+# disruption = low
+
+for user in $(awk -F':' '{ if ($3 >= {{{ uid_min }}} && $3 != 65534) print $1 }' /etc/passwd); do
+    home_dir=$(getent passwd $user | cut -d: -f6)
+    # Only update the ownership when necessary. This will avoid changing the inode timestamp
+    # when the owner is already defined as expected, therefore not impacting in possible integrity
+    # check systems that also check inodes timestamps.
+    find $home_dir -not -user $user -exec chown -f $user {} \;
+done
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/oval/shared.xml b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/oval/shared.xml
new file mode 100644
index 0000000..1850cfb
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/oval/shared.xml
@@ -0,0 +1,52 @@
+<def-group>
+  <definition class="compliance" id="{{{ rule_id }}}" version="1">
+    {{{ oval_metadata("All User Files and Directories In The Home Directory Must Have a Valid Owner") }}}
+    <criteria>
+      <criterion test_ref="test_accounts_users_home_files_ownership"
+                 comment="All User Files and Directories In The Home Directory Must Have a Valid Owner"/>
+    </criteria>
+  </definition>
+
+  <unix:password_object id="object_accounts_users_home_files_ownership_objects" version="1">
+    <unix:username datatype="string" operation="not equal">nobody</unix:username>
+    <filter action="include">state_accounts_users_home_files_ownership_interactive_uids</filter>
+  </unix:password_object>
+
+  <unix:password_state id="state_accounts_users_home_files_ownership_interactive_uids" version="1">
+    <unix:user_id datatype="int" operation="greater than or equal">{{{ uid_min }}}</unix:user_id>
+  </unix:password_state>
+
+  <local_variable id="var_accounts_users_home_files_ownership_dirs" datatype="string" version="1"
+                  comment="Variable including all home dirs from interactive users">
+    <object_component item_field="home_dir"
+                      object_ref="object_accounts_users_home_files_ownership_objects"/>
+  </local_variable>
+
+  <local_variable id="var_accounts_users_home_files_ownership_uids" datatype="int" version="1"
+                  comment="List of interactive users uids">
+    <object_component item_field="user_id"
+                      object_ref="object_accounts_users_home_files_ownership_objects"/>
+  </local_variable>
+
+  <!-- #### creation of object #### -->
+  <unix:file_object id="object_accounts_users_home_files_ownership_dirs" version="1">
+    <unix:behaviors recurse="directories" recurse_direction="down" max_depth="-1"
+                    recurse_file_system="local"/>
+    <unix:path var_ref="var_accounts_users_home_files_ownership_dirs" var_check="at least one"/>
+    <unix:filename operation="pattern match">.*</unix:filename>
+  </unix:file_object>
+
+  <!-- #### creation of state #### -->
+  <unix:file_state id="state_accounts_users_home_files_ownership_uids" version="1">
+    <unix:user_id datatype="int" var_check="only one"
+                  var_ref="var_accounts_users_home_files_ownership_uids"/>
+  </unix:file_state>
+
+  <!-- #### creation of test #### -->
+  <unix:file_test id="test_accounts_users_home_files_ownership" check="all"
+                  check_existence="any_exist" version="1"
+                  comment="All home directories files are owned by a local interactive user">
+    <unix:object object_ref="object_accounts_users_home_files_ownership_dirs"/>
+    <unix:state state_ref="state_accounts_users_home_files_ownership_uids"/>
+  </unix:file_test>
+</def-group>
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/rule.yml b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/rule.yml
index 13f6bfe..5bfb388 100644
--- a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/rule.yml
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/rule.yml
@@ -10,6 +10,9 @@ description: |-
     directories, use the following command:
     <pre>$ sudo chown -R <i>USER</i> /home/<i>USER</i></pre>
 
+    This rule ensures every file or directory under the home directory related
+    to an interactive user is owned by an interactive user.
+
 rationale: |-
     If local interactive users do not own the files in their directories,
     unauthorized users may be able to access them. Additionally, if files are not
@@ -34,3 +37,9 @@ ocil: |-
     To verify all files and directories in interactive users home directory
     are owned by the user, run the following command:
     <pre>$ sudo ls -lLR /home/<i>USER</i></pre>
+
+warnings:
+    - general: |-
+       Due to OVAL limitation, this rule can report a false negative in a
+       specific situation where two interactive users swap the ownership of
+       folders or files in their respective home directories.
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/expected_owner.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/expected_owner.pass.sh
new file mode 100644
index 0000000..da68cb4
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/expected_owner.pass.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -m $USER
+echo "$USER" > /home/$USER/$USER.txt
+chown $USER /home/$USER/$USER.txt
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/home_dirs_all_absent.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/home_dirs_all_absent.pass.sh
new file mode 100644
index 0000000..af24025
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/home_dirs_all_absent.pass.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -M $USER
+# This make sure home dirs related to test environment users are also removed.
+rm -Rf /home/*
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/home_dirs_one_absent.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/home_dirs_one_absent.pass.sh
new file mode 100644
index 0000000..5bce517
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/home_dirs_one_absent.pass.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+USER1="cac_user1"
+USER2="cac_user2"
+
+useradd -m $USER1
+useradd -M $USER2
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/interactive_users_absent.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/interactive_users_absent.pass.sh
new file mode 100644
index 0000000..ed34f09
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/interactive_users_absent.pass.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+# remove all interactive users (ID >= 1000) from /etc/passwd
+sed -i '/.*:[0-9]\{4,\}:/d' /etc/passwd
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/unexpected_owner_system_id.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/unexpected_owner_system_id.fail.sh
new file mode 100644
index 0000000..59c46a9
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/unexpected_owner_system_id.fail.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -m $USER
+echo "$USER" > /home/$USER/$USER.txt
+chown 2 /home/$USER/$USER.txt
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/unexpected_owner_unknown_id.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/unexpected_owner_unknown_id.fail.sh
new file mode 100644
index 0000000..e0f5514
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/unexpected_owner_unknown_id.fail.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -m $USER
+echo "$USER" > /home/$USER/$USER.txt
+chown 10005 /home/$USER/$USER.txt
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/warning_home_dirs_swapped_owner.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/warning_home_dirs_swapped_owner.pass.sh
new file mode 100644
index 0000000..1174ec6
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_ownership/tests/warning_home_dirs_swapped_owner.pass.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+USER1="cac_user1"
+USER2="cac_user2"
+
+useradd -m $USER1
+useradd -m $USER2
+echo "$USER1" > /home/$USER1/$USER1.txt
+echo "$USER2" > /home/$USER2/$USER2.txt
+# Swap the ownership of files in two home directories
+# WARNING: This test scenario will report a false negative, as explained in the
+# warning section of this rule.
+chown -f $USER2 /home/$USER1/$USER1.txt
+chown -f $USER1 /home/$USER2/$USER2.txt
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/ansible/shared.yml b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/ansible/shared.yml
new file mode 100644
index 0000000..9473710
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/ansible/shared.yml
@@ -0,0 +1,33 @@
+# platform = multi_platform_all
+# reboot = false
+# strategy = restrict
+# complexity = low
+# disruption = low
+
+- name: Get all local users from /etc/passwd
+  ansible.builtin.getent:
+    database: passwd
+    split: ':'
+
+- name: Create local_users variable from the getent output
+  ansible.builtin.set_fact:
+    local_users: '{{ ansible_facts.getent_passwd|dict2items }}'
+
+- name: Test for existence home directories to avoid creating them, but only fixing group ownership
+  ansible.builtin.stat:
+    path: '{{ item.value[4] }}'
+  register: path_exists
+  loop: '{{ local_users }}'
+  when:
+    - item.value[2]|int >= {{{ uid_min }}}
+    - item.value[2]|int != 65534
+
+- name: Ensure interactive local users are the group-owners of their respective home directories
+  ansible.builtin.file:
+    path: '{{ item.0.value[4] }}'
+    mode: 'g-w,o=-'
+    follow: no
+    recurse: yes
+  loop: '{{ local_users|zip(path_exists.results)|list }}'
+  when:
+    - item.1.stat is defined and item.1.stat.exists
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/bash/shared.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/bash/shared.sh
new file mode 100644
index 0000000..186d55d
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/bash/shared.sh
@@ -0,0 +1,12 @@
+# platform = multi_platform_all
+# reboot = false
+# strategy = restrict
+# complexity = low
+# disruption = low
+
+for home_dir in $(awk -F':' '{ if ($4 >= {{{ uid_min }}} && $4 != 65534) print $6 }' /etc/passwd); do
+    # Only update the permissions when necessary. This will avoid changing the inode timestamp when
+    # the permission is already defined as expected, therefore not impacting in possible integrity
+    # check systems that also check inodes timestamps.
+    find $home_dir -perm /027 -exec chmod g-w,o=- {} \;
+done
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/oval/shared.xml b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/oval/shared.xml
new file mode 100644
index 0000000..d3db46d
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/oval/shared.xml
@@ -0,0 +1,52 @@
+<def-group>
+  <definition class="compliance" id="{{{ rule_id }}}" version="1">
+    {{{ oval_metadata("All User Files and Directories In The Home Directory Must Have Mode 0750 Or Less Permissive") }}}
+    <criteria>
+      <criterion test_ref="test_accounts_users_home_files_permissions"
+                 comment="All files under interactive user's Home Directories must have proper permissions"/>
+    </criteria>
+  </definition>
+
+  <!-- For detailed comments about logic used in this OVAL, check the
+       "file_ownership_home_directories" rule. -->
+  <unix:password_object id="object_accounts_users_home_files_permissions_objects" version="1">
+    <unix:username datatype="string" operation="not equal">nobody</unix:username>
+    <filter action="include">state_accounts_users_home_files_permissions_interactive_uids</filter>
+  </unix:password_object>
+
+  <unix:password_state id="state_accounts_users_home_files_permissions_interactive_uids" version="1">
+    <unix:user_id datatype="int" operation="greater than or equal">{{{ uid_min }}}</unix:user_id>
+  </unix:password_state>
+
+  <!-- #### prepare for test_file_permissions_home_directories #### -->
+  <local_variable id="var_accounts_users_home_files_permissions_dirs" datatype="string" version="1"
+                  comment="Variable including all home dirs from interactive users">
+    <object_component item_field="home_dir" object_ref="object_accounts_users_home_files_permissions_objects"/>
+  </local_variable>
+
+  <!-- #### creation of object #### -->
+  <unix:file_object id="object_accounts_users_home_files_permissions_dirs" version="1">
+    <unix:behaviors recurse="directories" recurse_direction="down" max_depth="-1"
+                    recurse_file_system="local"/>
+    <unix:path var_ref="var_accounts_users_home_files_permissions_dirs" var_check="at least one"/>
+    <unix:filename operation="pattern match">.*</unix:filename>
+  </unix:file_object>
+
+  <!-- #### creation of state #### -->
+  <unix:file_state id="state_accounts_users_home_files_permissions_dirs" version="1" operator='AND'>
+    <unix:suid datatype="boolean">false</unix:suid>
+    <unix:sgid datatype="boolean">false</unix:sgid>
+    <unix:sticky datatype="boolean">false</unix:sticky>
+    <unix:gwrite datatype="boolean">false</unix:gwrite>
+    <unix:oread datatype="boolean">false</unix:oread>
+    <unix:owrite datatype="boolean">false</unix:owrite>
+    <unix:oexec datatype="boolean">false</unix:oexec>
+  </unix:file_state>
+
+  <!-- #### creation of test #### -->
+  <unix:file_test id="test_accounts_users_home_files_permissions" check="all" check_existence="any_exist"
+                  version="1" comment="All home directories have proper permissions">
+    <unix:object object_ref="object_accounts_users_home_files_permissions_dirs"/>
+    <unix:state state_ref="state_accounts_users_home_files_permissions_dirs"/>
+  </unix:file_test>
+</def-group>
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/acceptable_permission.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/acceptable_permission.pass.sh
new file mode 100644
index 0000000..3561847
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/acceptable_permission.pass.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -m $USER
+echo "$USER" > /home/$USER/$USER.txt
+chmod -Rf 750 /home/$USER/.*
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/expected_permissions.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/expected_permissions.pass.sh
new file mode 100644
index 0000000..8ed7fa2
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/expected_permissions.pass.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -m $USER
+echo "$USER" > /home/$USER/$USER.txt
+chmod -Rf 700 /home/$USER/.*
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/home_dirs_absent.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/home_dirs_absent.pass.sh
new file mode 100644
index 0000000..af24025
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/home_dirs_absent.pass.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -M $USER
+# This make sure home dirs related to test environment users are also removed.
+rm -Rf /home/*
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/interactive_users_absent.pass.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/interactive_users_absent.pass.sh
new file mode 100644
index 0000000..ed34f09
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/interactive_users_absent.pass.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+# remove all interactive users (ID >= 1000) from /etc/passwd
+sed -i '/.*:[0-9]\{4,\}:/d' /etc/passwd
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/lenient_permission.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/lenient_permission.fail.sh
new file mode 100644
index 0000000..b561671
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/lenient_permission.fail.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -m $USER
+echo "$USER" > /home/$USER/$USER.txt
+chmod -Rf 700 /home/$USER/.*
+chmod -f o+r /home/$USER/$USER.txt
diff --git a/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/lenient_permission_hidden_files.fail.sh b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/lenient_permission_hidden_files.fail.sh
new file mode 100644
index 0000000..d7811bc
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-session/accounts_users_home_files_permissions/tests/lenient_permission_hidden_files.fail.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+USER="cac_user"
+useradd -m $USER
+echo "$USER" > /home/$USER/.init_file
+chmod -Rf 700 /home/$USER/.*
+chmod -f o+r /home/$USER/.init_file
diff --git a/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/tests/unexpected_groupowner_system_id.fail.sh b/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/tests/unexpected_groupowner_system_uid.fail.sh
similarity index 100%
rename from linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/tests/unexpected_groupowner_system_id.fail.sh
rename to linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/tests/unexpected_groupowner_system_uid.fail.sh
diff --git a/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/tests/unexpected_groupowner_unknown_id.fail.sh b/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/tests/unexpected_groupowner_unknown_uid.fail.sh
similarity index 100%
rename from linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/tests/unexpected_groupowner_unknown_id.fail.sh
rename to linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/tests/unexpected_groupowner_unknown_uid.fail.sh