diff --git a/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/ansible/shared.yml b/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/ansible/shared.yml index 14ebb3662f27..a9c23013c91b 100644 --- a/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/ansible/shared.yml +++ b/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/ansible/shared.yml @@ -4,32 +4,32 @@ # complexity = low # disruption = low -- name: Get all local users from /etc/passwd +- name: Get all users from getent to support remote users (LDAP, SSSD, etc.) ansible.builtin.getent: database: passwd split: ':' -- name: Create local_users variable from the getent output +- name: Create interactive_users variable filtering out non-interactive shells ansible.builtin.set_fact: - local_users: '{{ ansible_facts.getent_passwd|dict2items }}' - # Creates a dictionary where the key is the first field of the /etc/passwd file, the username. - # The list of values are the next 6 fields from /etc/passwd. Example for the root entry: - # The "root" key would have these values: ["x", "0", "0", "root", "/root", "/bin/bash"] + interactive_users: '{{ ansible_facts.getent_passwd|dict2items|rejectattr("value.5", "match", ".*/sbin/nologin$")|rejectattr("value.5", "match", ".*/usr/sbin/nologin$")|rejectattr("value.5", "match", ".*/bin/false$")|rejectattr("value.5", "match", ".*/usr/bin/false$")|list }}' + # Creates a dictionary where the key is the username and values are fields from getent passwd. + # Filters out users with non-interactive shells: nologin and false. + # Example for the admin entry: ["x", "1000", "1000", "", "/home/admin", "/bin/bash"] - name: Test for existence of home directories to avoid creating them, but only fixing group ownership ansible.builtin.stat: path: '{{ item.value[4] }}' register: path_exists - loop: '{{ local_users }}' + loop: '{{ interactive_users }}' when: - item.value[1]|int >= {{{ uid_min }}} - item.value[1]|int != {{{ nobody_uid }}} - item.value[4] != "/" -- name: Ensure interactive local users are the group-owners of their respective home directories +- name: Ensure interactive users are the group-owners of their respective home directories ansible.builtin.file: path: '{{ item.0.value[4] }}' group: '{{ item.0.value[2] }}' - loop: '{{ local_users|zip(path_exists.results)|list }}' + loop: '{{ interactive_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/file_groupownership_home_directories/bash/shared.sh b/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/bash/shared.sh index a6c7b07bd586..4f8d83d7ca5e 100644 --- a/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/bash/shared.sh +++ b/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/bash/shared.sh @@ -4,4 +4,14 @@ # complexity = low # disruption = low -awk -F':' '{ if ($3 >= {{{ uid_min }}} && $3 != {{{ nobody_uid }}} && $6 != "/") system("chgrp -f " $4" "$6) }' /etc/passwd +# Get interactive users using getent to support remote users (LDAP, SSSD, etc.) +while IFS=: read -r _ _ uid gid _ home shell; do + # Filter interactive users: UID >= {{{ uid_min }}}, not nobody, has valid home dir, not nologin/false shell + if [ "$uid" -ge {{{ uid_min }}} ] && [ "$uid" -ne {{{ nobody_uid }}} ] && \ + [ "$home" != "/" ] && \ + [ "$shell" != "/sbin/nologin" ] && [ "$shell" != "/usr/sbin/nologin" ] && \ + [ "$shell" != "/bin/false" ] && [ "$shell" != "/usr/bin/false" ]; then + # Arguments are properly quoted to prevent command injection + chgrp -f -- "$gid" "$home" + fi +done < <(getent passwd) diff --git a/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/oval/shared.xml b/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/oval/shared.xml index 79a5f7dec0d3..2dbf49b051c1 100644 --- a/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/oval/shared.xml +++ b/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/oval/shared.xml @@ -7,21 +7,20 @@ - {{%- set interactive_users_home_dirs_object = "object_" ~ rule_id ~ "_home_dirs" -%}} - {{{ create_local_interactive_users_home_dirs_list_object(interactive_users_home_dirs_object) }}} - {{%- set interactive_users_gids_object = "object_" ~ rule_id ~ "_gids" -%}} - {{{ create_local_interactive_users_gids_list_object(interactive_users_gids_object) }}} + {{%- set interactive_users_object = "object_" ~ rule_id ~ "_interactive_users" -%}} + {{{ create_interactive_users_list_object(interactive_users_object, rule_id=rule_id) }}} - + - + comment="Home directories of interactive users (local and remote)"> + + + comment="Primary group IDs of interactive users (local and remote)"> - + @@ -37,9 +36,8 @@ - + version="1" comment="All home directories are group-owned by an interactive user's primary group"> diff --git a/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/rule.yml b/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/rule.yml index 9fff2eddbf2a..c39884622b5b 100644 --- a/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/rule.yml +++ b/linux_os/guide/system/accounts/accounts-session/file_groupownership_home_directories/rule.yml @@ -4,15 +4,19 @@ documentation_complete: true title: 'All Interactive User Home Directories Must Be Group-Owned By The Primary Group' description: |- - Change the group owner of interactive users home directory to the - group found in /etc/passwd. To change the group owner of - interactive users home directory, use the following command: + Change the group owner of interactive user home directories to the + group found in getent passwd. To change the group owner of + an interactive user's home directory, use the following command:
$ sudo chgrp USER_GROUP /home/USER
This rule ensures every home directory related to an interactive user is - group-owned by an interactive user. It also ensures that interactive users + group-owned by that user's primary group. It also ensures that interactive users are group-owners of one and only one home directory. + Interactive users are those with a UID greater than or equal to {{{ uid_min }}} + and a valid interactive shell (not /sbin/nologin, /usr/sbin/nologin, + /bin/false, or /usr/bin/false). + rationale: |- If the Group Identifier (GID) of a local interactive users home directory is not the same as the primary GID of the user, this would allow unauthorized @@ -43,15 +47,27 @@ ocil_clause: 'the group ownership is incorrect' ocil: |- To verify the assigned home directory of all interactive users is group- - owned by that users primary GID, run the following command: -
# ls -ld $(awk -F: '($3>={{{ uid_min }}})&&($7 !~ /nologin/){print $6}' /etc/passwd)
+ owned by that user's primary GID, run the following command: +
# ls -ld $(getent passwd | awk -F: '($3>={{{ uid_min }}})&&($7 !~ /nologin/)&&($7 !~ /\/false$/){print $6}')
+ + This should return a list of home directories with group ownership matching each user's primary group. + Using getent passwd instead of reading /etc/passwd directly ensures that remote users + (LDAP, SSSD, NIS, etc.) are also checked. fixtext: |- - Change the group owner of a local interactive user’s home directory to the group found in "/etc/passwd". To change the group owner of a local interactive user’s home directory, use the following command: + Change the group owner of an interactive user’s home directory to the group found in the system user database. + + Identify the user’s primary group: +
$ getent passwd smithj
+    smithj:x:1000:1000:John Smith:/home/smithj:/bin/bash
+ + The fourth field (1000) is the primary group ID (GID). Change the home directory group ownership: +
$ sudo chgrp 1000 /home/smithj
- Note: The example will be for the user "smithj", who has a home directory of "/home/smithj", and has a primary group of users. + Or use the group name: +
$ sudo chgrp users /home/smithj
- $ sudo chgrp users /home/smithj + Note: This applies to all interactive users, including those in remote directories (LDAP, SSSD, NIS, etc.). srg_requirement: 'All {{{ full_name }}} local interactive user home directories must be group-owned by the home directory owner’s primary group.' diff --git a/shared/macros/10-oval.jinja b/shared/macros/10-oval.jinja index 22082d69d395..3f69afb6f012 100644 --- a/shared/macros/10-oval.jinja +++ b/shared/macros/10-oval.jinja @@ -1276,7 +1276,7 @@ Generates the :code:`` tag for OVAL check using correct product platfo - ^(?:/usr)?/sbin/nologin$ + ^(?:/usr)?(?:/sbin/nologin|/bin/false)$ {{%- endmacro %}}