Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor display_login_attempts rule for simplicity and avoid noise #10979

Merged

Conversation

marcusburghardt
Copy link
Member

@marcusburghardt marcusburghardt commented Aug 10, 2023

Description:

The pam_lastlog.so module is used in the /etc/pam.d/postlogin file (or login file depending on the distro) to display Last login information for certain programs. Although this module is only explicitly mentioned in the postlogin file, it is indirectly used by various other PAM configuration files, such as those for login, ssh, passwd, and others. The reason for this is to ensure that the Last login information is shown for programs like gdm and su, while avoiding redundancy for programs that already display this information without needing pam_lastlog.so. Despite the usage of silent option in one line, the default configuration of /etc/pam.d/postlogin ensures consistent display of Last login information for specific programs.

In short we only need to check if at least one line contains am_lastlog.so, showfailed and not silent.

Rationale:

Review Hints:

The commits were organized in a sequence to facilitate the review.
The most import is actually to understand the reasons behind the changes, which are better contextualized in #9031
Finally, the automatus should work fine with to validate the technical aspects of the check and remediation

This rule demands the pam_lastlog.so module to be properly configured
in order to show the previous successfull logins. This is already
implicit in login program and configurable in ssh and other programs
which uses PAM, but it is not ensured in other programs such as gdm*
and su*. To complement program whitout a native option to show the last
login, the pam_lastlog.so module is used. This is extensively
documented in ComplianceAsCode#9031
One one line of pam_lastlog.so without the silent option is enough.
In general the pam_lastlog.so is used to complement tools without the
native capability to show the "Last login" information but is used
without conditionals the information will be duplicated. This commit
simplify the OVAL in alignment to this expected behavior.
In the context of pam_lastlog and postlogin or login files, the control
is not so relevant and don't need to be tested since it can depend on
other lines, such as conditionals. In fact, it is important to check if
the "showfailed" is present without the "silent" in the same line.
@marcusburghardt marcusburghardt added refactoring Improvement which, once completed, will enable the project to progress faster. Update Rule Issues or pull requests related to Rules updates. labels Aug 10, 2023
@github-actions
Copy link

Start a new ephemeral environment with changes proposed in this pull request:

rhel8 (from CTF) Environment (using Fedora as testing environment)
Open in Gitpod

Fedora Testing Environment
Open in Gitpod

Oracle Linux 8 Environment
Open in Gitpod

@marcusburghardt marcusburghardt requested review from a team August 10, 2023 14:55
@github-actions
Copy link

github-actions bot commented Aug 10, 2023

This datastream diff is auto generated by the check Compare DS/Generate Diff

Click here to see the full diff
New content has different text for rule 'xccdf_org.ssgproject.content_rule_display_login_attempts'.
--- xccdf_org.ssgproject.content_rule_display_login_attempts
+++ xccdf_org.ssgproject.content_rule_display_login_attempts
@@ -3,13 +3,25 @@
 Ensure PAM Displays Last Logon/Access Notification
 
 [description]:
-To configure the system to notify users of last logon/access
-using pam_lastlog, add or correct the pam_lastlog
-settings in
-/etc/pam.d/postlogin to read as follows:
-session     required pam_lastlog.so showfailed
-And make sure that the silent option is not set for
-pam_lastlog module.
+To configure the system to notify users of last logon/access using pam_lastlog,
+add or correct the pam_lastlog settings in /etc/pam.d/postlogin
+to include showfailed option, such as:
+session     [default=1]    pam_lastlog.so showfailed
+And make sure that the silent option is not set for this specific line.
+
+[warning]:
+If the system relies on authselect tool to manage PAM settings, the remediation
+will also use authselect tool. However, if any manual modification was made in
+PAM files, the authselect integrity check will fail and the remediation will be
+aborted in order to preserve intentional changes. In this case, an informative message will
+be shown in the remediation report.
+
+[warning]:
+authselect contains an authselect feature to easily and properly enable Last Logon
+notifications with pam_lastlog.so module. If a custom profile was created and used
+in the system before this authselect feature was available, the new feature can't be used
+with this custom profile and the remediation will fail. In this case, the custom profile
+should be recreated or manually updated.
 
 [reference]:
 1
@@ -147,11 +159,10 @@
 SV-230381r858726_rule
 
 [rationale]:
-Users need to be aware of activity that occurs regarding
-their account. Providing users with information regarding the number
-of unsuccessful attempts that were made to login to their account
-allows the user to determine if any unauthorized activity has occurred
-and gives them an opportunity to notify administrators.
+Users need to be aware of activity that occurs regarding their account. Providing users with
+information regarding the number of unsuccessful attempts that were made to login to their
+account allows the user to determine if any unauthorized activity has occurred and gives them
+an opportunity to notify administrators.
 
 [ident]:
 CCE-80788-3

OVAL for rule 'xccdf_org.ssgproject.content_rule_display_login_attempts' differs.
--- oval:ssg-display_login_attempts:def:1
+++ oval:ssg-display_login_attempts:def:1
@@ -1,3 +1,2 @@
-criteria AND
+criteria None
 criterion oval:ssg-test_display_login_attempts:tst:1
-criterion oval:ssg-test_display_login_attempts_silent:tst:1

OCIL for rule 'xccdf_org.ssgproject.content_rule_display_login_attempts' differs.
--- ocil:ssg-display_login_attempts_ocil:questionnaire:1
+++ ocil:ssg-display_login_attempts_ocil:questionnaire:1
@@ -2,6 +2,6 @@
 
 $ sudo grep pam_lastlog /etc/pam.d/postlogin
 
-session required pam_lastlog.so showfailed
-      Is it the case that "pam_lastlog" is missing from "/etc/pam.d/postlogin" file, or the silent option is present?
+session [default=1] pam_lastlog.so showfailed
+      Is it the case that "pam_lastlog.so" is not properly configured in "/etc/pam.d/postlogin" file?
       
bash remediation for rule 'xccdf_org.ssgproject.content_rule_display_login_attempts' differs.
--- xccdf_org.ssgproject.content_rule_display_login_attempts
+++ xccdf_org.ssgproject.content_rule_display_login_attempts
@@ -1,9 +1,20 @@
 # Remediation is applicable only in certain platforms
 if rpm --quiet -q pam; then
 
-if [ -e "/etc/pam.d/postlogin" ] ; then
-    PAM_FILE_PATH="/etc/pam.d/postlogin"
-    if [ -f /usr/bin/authselect ]; then
+if [ -f /usr/bin/authselect ]; then
+    if authselect list-features minimal | grep -q with-silent-lastlog; then
+        if ! authselect check; then
+        echo "
+        authselect integrity check failed. Remediation aborted!
+        This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
+        It is not recommended to manually edit the PAM files when authselect tool is available.
+        In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
+        exit 1
+        fi
+        authselect disable-feature with-silent-lastlog
+
+        authselect apply-changes -b
+    else
         
         if ! authselect check; then
         echo "
@@ -33,70 +44,212 @@
         PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
 
         authselect apply-changes -b
-    fi
-    if ! grep -qP '^\s*session\s+'"required"'\s+pam_lastlog.so\s*.*' "$PAM_FILE_PATH"; then
-            # Line matching group + control + module was not found. Check group + module.
-            if [ "$(grep -cP '^\s*session\s+.*\s+pam_lastlog.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
-                # The control is updated only if one single line matches.
-                sed -i -E --follow-symlinks 's/^(\s*session\s+).*(\bpam_lastlog.so.*)/\1'"required"' \2/' "$PAM_FILE_PATH"
-            else
-                sed -i --follow-symlinks '1i session     '"required"'    pam_lastlog.so' "$PAM_FILE_PATH"
-            fi
-        fi
-        # Check the option
-        if ! grep -qP '^\s*session\s+'"required"'\s+pam_lastlog.so\s*.*\sshowfailed\b' "$PAM_FILE_PATH"; then
-            sed -i -E --follow-symlinks '/\s*session\s+'"required"'\s+pam_lastlog.so.*/ s/$/ showfailed/' "$PAM_FILE_PATH"
-        fi
-    if [ -f /usr/bin/authselect ]; then
-        
-        authselect apply-changes -b
+        if [ -e "$PAM_FILE_PATH" ] ; then
+            PAM_FILE_PATH="$PAM_FILE_PATH"
+            if [ -f /usr/bin/authselect ]; then
+                
+                if ! authselect check; then
+                echo "
+                authselect integrity check failed. Remediation aborted!
+                This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
+                It is not recommended to manually edit the PAM files when authselect tool is available.
+                In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
+                exit 1
+                fi
+
+                CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
+                # If not already in use, a custom profile is created preserving the enabled features.
+                if [[ ! $CURRENT_PROFILE == custom/* ]]; then
+                    ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
+                    authselect create-profile hardening -b $CURRENT_PROFILE
+                    CURRENT_PROFILE="custom/hardening"
+                    
+                    authselect apply-changes -b --backup=before-hardening-custom-profile
+                    authselect select $CURRENT_PROFILE
+                    for feature in $ENABLED_FEATURES; do
+                        authselect enable-feature $feature;
+                    done
+                    
+                    authselect apply-changes -b --backup=after-hardening-custom-profile
+                fi
+                PAM_FILE_NAME=$(basename "$PAM_FILE_PATH")
+                PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+
+                authselect apply-changes -b
+            fi
+            if ! grep -qP '^\s*session\s+'"\[default=1\]"'\s+pam_lastlog.so\s*.*' "$PAM_FILE_PATH"; then
+                    # Line matching group + control + module was not found. Check group + module.
+                    if [ "$(grep -cP '^\s*session\s+.*\s+pam_lastlog.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
+                        # The control is updated only if one single line matches.
+                        sed -i -E --follow-symlinks 's/^(\s*session\s+).*(\bpam_lastlog.so.*)/\1'"\[default=1\]"' \2/' "$PAM_FILE_PATH"
+                    else
+                        LAST_MATCH_LINE=$(grep -nP "^\s*session\s+.*pam_succeed_if\.so.*" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1)
+                        if [ ! -z $LAST_MATCH_LINE ]; then
+                            sed -i --follow-symlinks $LAST_MATCH_LINE' a session     '"\[default=1\]"'    pam_lastlog.so' "$PAM_FILE_PATH"
+                        else
+                            echo 'session    '"\[default=1\]"'    pam_lastlog.so' >> "$PAM_FILE_PATH"
+                        fi
+                    fi
+                fi
+                # Check the option
+                if ! grep -qP '^\s*session\s+'"\[default=1\]"'\s+pam_lastlog.so\s*.*\sshowfailed\b' "$PAM_FILE_PATH"; then
+                    sed -i -E --follow-symlinks '/\s*session\s+'"\[default=1\]"'\s+pam_lastlog.so.*/ s/$/ showfailed/' "$PAM_FILE_PATH"
+                fi
+            if [ -f /usr/bin/authselect ]; then
+                
+                authselect apply-changes -b
+            fi
+        else
+            echo "$PAM_FILE_PATH was not found" >&2
+        fi
+        if [ -e "$PAM_FILE_PATH" ] ; then
+            PAM_FILE_PATH="$PAM_FILE_PATH"
+            if [ -f /usr/bin/authselect ]; then
+                
+                if ! authselect check; then
+                echo "
+                authselect integrity check failed. Remediation aborted!
+                This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
+                It is not recommended to manually edit the PAM files when authselect tool is available.
+                In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
+                exit 1
+                fi
+
+                CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
+                # If not already in use, a custom profile is created preserving the enabled features.
+                if [[ ! $CURRENT_PROFILE == custom/* ]]; then
+                    ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
+                    authselect create-profile hardening -b $CURRENT_PROFILE
+                    CURRENT_PROFILE="custom/hardening"
+                    
+                    authselect apply-changes -b --backup=before-hardening-custom-profile
+                    authselect select $CURRENT_PROFILE
+                    for feature in $ENABLED_FEATURES; do
+                        authselect enable-feature $feature;
+                    done
+                    
+                    authselect apply-changes -b --backup=after-hardening-custom-profile
+                fi
+                PAM_FILE_NAME=$(basename "$PAM_FILE_PATH")
+                PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+
+                authselect apply-changes -b
+            fi
+            
+        if grep -qP '^\s*session\s+'"\[default=1\]"'\s+pam_lastlog.so\s.*\bsilent\b' "$PAM_FILE_PATH"; then
+            sed -i -E --follow-symlinks 's/(.*session.*'"\[default=1\]"'.*pam_lastlog.so.*)\ssilent=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
+        fi
+            if [ -f /usr/bin/authselect ]; then
+                
+                authselect apply-changes -b
+            fi
+        else
+            echo "$PAM_FILE_PATH was not found" >&2
+        fi
     fi
 else
-    echo "/etc/pam.d/postlogin was not found" >&2
-fi
-if [ -e "/etc/pam.d/postlogin" ] ; then
-    PAM_FILE_PATH="/etc/pam.d/postlogin"
-    if [ -f /usr/bin/authselect ]; then
-        
-        if ! authselect check; then
-        echo "
-        authselect integrity check failed. Remediation aborted!
-        This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
-        It is not recommended to manually edit the PAM files when authselect tool is available.
-        In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
-        exit 1
-        fi
-
-        CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
-        # If not already in use, a custom profile is created preserving the enabled features.
-        if [[ ! $CURRENT_PROFILE == custom/* ]]; then
-            ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
-            authselect create-profile hardening -b $CURRENT_PROFILE
-            CURRENT_PROFILE="custom/hardening"
-            
-            authselect apply-changes -b --backup=before-hardening-custom-profile
-            authselect select $CURRENT_PROFILE
-            for feature in $ENABLED_FEATURES; do
-                authselect enable-feature $feature;
-            done
-            
-            authselect apply-changes -b --backup=after-hardening-custom-profile
-        fi
-        PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin")
-        PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
-
-        authselect apply-changes -b
-    fi
-    
-if grep -qP '^\s*session\s.*\bpam_lastlog.so\s.*\bsilent\b' "$PAM_FILE_PATH"; then
-    sed -i -E --follow-symlinks 's/(.*session.*pam_lastlog.so.*)\bsilent\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
-fi
-    if [ -f /usr/bin/authselect ]; then
-        
-        authselect apply-changes -b
-    fi
-else
-    echo "/etc/pam.d/postlogin was not found" >&2
+    if [ -e "/etc/pam.d/postlogin" ] ; then
+            PAM_FILE_PATH="/etc/pam.d/postlogin"
+            if [ -f /usr/bin/authselect ]; then
+                
+                if ! authselect check; then
+                echo "
+                authselect integrity check failed. Remediation aborted!
+                This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
+                It is not recommended to manually edit the PAM files when authselect tool is available.
+                In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
+                exit 1
+                fi
+
+                CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
+                # If not already in use, a custom profile is created preserving the enabled features.
+                if [[ ! $CURRENT_PROFILE == custom/* ]]; then
+                    ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
+                    authselect create-profile hardening -b $CURRENT_PROFILE
+                    CURRENT_PROFILE="custom/hardening"
+                    
+                    authselect apply-changes -b --backup=before-hardening-custom-profile
+                    authselect select $CURRENT_PROFILE
+                    for feature in $ENABLED_FEATURES; do
+                        authselect enable-feature $feature;
+                    done
+                    
+                    authselect apply-changes -b --backup=after-hardening-custom-profile
+                fi
+                PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin")
+                PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+
+                authselect apply-changes -b
+            fi
+            if ! grep -qP '^\s*session\s+'"\[default=1\]"'\s+pam_lastlog.so\s*.*' "$PAM_FILE_PATH"; then
+                    # Line matching group + control + module was not found. Check group + module.
+                    if [ "$(grep -cP '^\s*session\s+.*\s+pam_lastlog.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
+                        # The control is updated only if one single line matches.
+                        sed -i -E --follow-symlinks 's/^(\s*session\s+).*(\bpam_lastlog.so.*)/\1'"\[default=1\]"' \2/' "$PAM_FILE_PATH"
+                    else
+                        LAST_MATCH_LINE=$(grep -nP "^\s*session\s+.*pam_succeed_if\.so.*" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1)
+                        if [ ! -z $LAST_MATCH_LINE ]; then
+                            sed -i --follow-symlinks $LAST_MATCH_LINE' a session     '"\[default=1\]"'    pam_lastlog.so' "$PAM_FILE_PATH"
+                        else
+                            echo 'session    '"\[default=1\]"'    pam_lastlog.so' >> "$PAM_FILE_PATH"
+                        fi
+                    fi
+                fi
+                # Check the option
+                if ! grep -qP '^\s*session\s+'"\[default=1\]"'\s+pam_lastlog.so\s*.*\sshowfailed\b' "$PAM_FILE_PATH"; then
+                    sed -i -E --follow-symlinks '/\s*session\s+'"\[default=1\]"'\s+pam_lastlog.so.*/ s/$/ showfailed/' "$PAM_FILE_PATH"
+                fi
+            if [ -f /usr/bin/authselect ]; then
+                
+                authselect apply-changes -b
+            fi
+        else
+            echo "/etc/pam.d/postlogin was not found" >&2
+        fi
+    if [ -e "/etc/pam.d/postlogin" ] ; then
+            PAM_FILE_PATH="/etc/pam.d/postlogin"
+            if [ -f /usr/bin/authselect ]; then
+                
+                if ! authselect check; then
+                echo "
+                authselect integrity check failed. Remediation aborted!
+                This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
+                It is not recommended to manually edit the PAM files when authselect tool is available.
+                In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
+                exit 1
+                fi
+
+                CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
+                # If not already in use, a custom profile is created preserving the enabled features.
+                if [[ ! $CURRENT_PROFILE == custom/* ]]; then
+                    ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
+                    authselect create-profile hardening -b $CURRENT_PROFILE
+                    CURRENT_PROFILE="custom/hardening"
+                    
+                    authselect apply-changes -b --backup=before-hardening-custom-profile
+                    authselect select $CURRENT_PROFILE
+                    for feature in $ENABLED_FEATURES; do
+                        authselect enable-feature $feature;
+                    done
+                    
+                    authselect apply-changes -b --backup=after-hardening-custom-profile
+                fi
+                PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin")
+                PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+
+                authselect apply-changes -b
+            fi
+            
+        if grep -qP '^\s*session\s+'"\[default=1\]"'\s+pam_lastlog.so\s.*\bsilent\b' "$PAM_FILE_PATH"; then
+            sed -i -E --follow-symlinks 's/(.*session.*'"\[default=1\]"'.*pam_lastlog.so.*)\ssilent=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
+        fi
+            if [ -f /usr/bin/authselect ]; then
+                
+                authselect apply-changes -b
+            fi
+        else
+            echo "/etc/pam.d/postlogin was not found" >&2
+        fi
 fi
 
 else

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_display_login_attempts' differs.
--- xccdf_org.ssgproject.content_rule_display_login_attempts
+++ xccdf_org.ssgproject.content_rule_display_login_attempts
@@ -16,11 +16,11 @@
   - low_severity
   - no_reboot_needed
 
-- name: Ensure PAM Displays Last Logon/Access Notification - Check if /etc/pam.d/postlogin
-    file is present
+- name: Ensure PAM Displays Last Logon/Access Notification - Check if system relies
+    on authselect tool
   ansible.builtin.stat:
-    path: /etc/pam.d/postlogin
-  register: result_pam_file_present
+    path: /usr/bin/authselect
+  register: result_authselect_present
   when: '"pam" in ansible_facts.packages'
   tags:
   - CCE-80788-3
@@ -37,8 +37,104 @@
   - low_severity
   - no_reboot_needed
 
-- name: Ensure PAM Displays Last Logon/Access Notification - Check the proper remediation
-    for the system
+- name: Ensure PAM Displays Last Logon/Access Notification - Collect the Available
+    authselect Features
+  ansible.builtin.command:
+    cmd: authselect list-features minimal
+  register: result_authselect_available_features
+  changed_when: false
+  when:
+  - '"pam" in ansible_facts.packages'
+  - result_authselect_present.stat.exists
+  tags:
+  - CCE-80788-3
+  - CJIS-5.5.2
+  - DISA-STIG-RHEL-08-020340
+  - NIST-800-53-AC-9
+  - NIST-800-53-AC-9(1)
+  - PCI-DSS-Req-10.2.4
+  - PCI-DSSv4-10.2.1.4
+  - configure_strategy
+  - display_login_attempts
+  - low_complexity
+  - low_disruption
+  - low_severity
+  - no_reboot_needed
+
+- name: Ensure PAM Displays Last Logon/Access Notification - Configure pam_lastlog.so
+    Using authselect Feature
+  block:
+
+  - name: Ensure PAM Displays Last Logon/Access Notification - Check integrity of
+      authselect current profile
+    ansible.builtin.command:
+      cmd: authselect check
+    register: result_authselect_check_cmd
+    changed_when: false
+    failed_when: false
+
+  - name: Ensure PAM Displays Last Logon/Access Notification - Informative message
+      based on the authselect integrity check result
+    ansible.builtin.assert:
+      that:
+      - result_authselect_check_cmd.rc == 0
+      fail_msg:
+      - authselect integrity check failed. Remediation aborted!
+      - This remediation could not be applied because an authselect profile was not
+        selected or the selected profile is not intact.
+      - It is not recommended to manually edit the PAM files when authselect tool
+        is available.
+      - In cases where the default authselect profile does not cover a specific demand,
+        a custom authselect profile is recommended.
+      success_msg:
+      - authselect integrity check passed
+
+  - name: Ensure PAM Displays Last Logon/Access Notification - Get authselect Features
+      Currently Enabled
+    ansible.builtin.shell:
+      cmd: authselect current | tail -n+3 | awk '{ print $2 }'
+    register: result_authselect_features
+    changed_when: false
+    when:
+    - result_authselect_check_cmd is success
+
+  - name: Ensure PAM Displays Last Logon/Access Notification - Ensure "with-silent-lastlog"
+      Feature is Disabled Using authselect Tool
+    ansible.builtin.command:
+      cmd: authselect disable-feature with-silent-lastlog
+    register: result_authselect_disable_feature_cmd
+    when:
+    - result_authselect_check_cmd is success
+    - result_authselect_features.stdout is search("with-silent-lastlog")
+
+  - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect changes
+      are applied
+    ansible.builtin.command:
+      cmd: authselect apply-changes -b
+    when:
+    - result_authselect_disable_feature_cmd is not skipped
+    - result_authselect_disable_feature_cmd is success
+  when:
+  - '"pam" in ansible_facts.packages'
+  - result_authselect_present.stat.exists
+  - result_authselect_available_features.stdout is search("with-silent-lastlog")
+  tags:
+  - CCE-80788-3
+  - CJIS-5.5.2
+  - DISA-STIG-RHEL-08-020340
+  - NIST-800-53-AC-9
+  - NIST-800-53-AC-9(1)
+  - PCI-DSS-Req-10.2.4
+  - PCI-DSSv4-10.2.1.4
+  - configure_strategy
+  - display_login_attempts
+  - low_complexity
+  - low_disruption
+  - low_severity
+  - no_reboot_needed
+
+- name: Ensure PAM Displays Last Logon/Access Notification - Configure pam_lastlog.so
+    in appropriate PAM files
   block:
 
   - name: Ensure PAM Displays Last Logon/Access Notification - Define the PAM file
@@ -189,7 +285,7 @@
       module line is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*session\s+required\s+pam_lastlog.so\s*.*
+      regexp: ^\s*session\s+{{ '[default=1]' | regex_escape() }}\s+pam_lastlog.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -214,7 +310,7 @@
       ansible.builtin.replace:
         dest: '{{ pam_file_path }}'
         regexp: ^(\s*session\s+).*(\bpam_lastlog.so.*)
-        replace: \1required \2
+        replace: \1[default=1] \2
       register: result_pam_module_edit
       when:
       - result_pam_line_other_control_present.found == 1
@@ -223,8 +319,8 @@
         PAM module line is included in {{ pam_file_path }}
       ansible.builtin.lineinfile:
         dest: '{{ pam_file_path }}'
-        insertafter: BOF
-        line: session    required    pam_lastlog.so
+        insertafter: ^\s*session\s+.*pam_succeed_if\.so.*
+        line: session    [default=1]    pam_lastlog.so
       register: result_pam_module_add
       when:
       - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found
@@ -248,7 +344,7 @@
       PAM module option is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*session\s+required\s+pam_lastlog.so\s*.*\sshowfailed\b
+      regexp: ^\s*session\s+{{ '[default=1]' | regex_escape() }}\s+pam_lastlog.so\s*.*\sshowfailed\b
       state: absent
     check_mode: true
     changed_when: false
@@ -259,238 +355,32 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*session\s+required\s+pam_lastlog.so.*)
+      regexp: ^(\s*session\s+{{ '[default=1]' | regex_escape() }}\s+pam_lastlog.so.*)
       line: \1 showfailed
       state: present
     register: result_pam_showfailed_add
     when:
     - result_pam_module_showfailed_option_present.found == 0
-
-  - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect changes
-      are applied
-    ansible.builtin.command:
-      cmd: authselect apply-changes -b
-    when:
-    - result_authselect_present.stat.exists
-    - |-
-      (result_pam_showfailed_add is defined and result_pam_showfailed_add.changed)
-       or (result_pam_showfailed_edit is defined and result_pam_showfailed_edit.changed)
-  when:
-  - '"pam" in ansible_facts.packages'
-  - result_pam_file_present.stat.exists
-  tags:
-  - CCE-80788-3
-  - CJIS-5.5.2
-  - DISA-STIG-RHEL-08-020340
-  - NIST-800-53-AC-9
-  - NIST-800-53-AC-9(1)
-  - PCI-DSS-Req-10.2.4
-  - PCI-DSSv4-10.2.1.4
-  - configure_strategy
-  - display_login_attempts
-  - low_complexity
-  - low_disruption
-  - low_severity
-  - no_reboot_needed
-
-- name: Ensure PAM Displays Last Logon/Access Notification - Check if /etc/pam.d/postlogin
-    file is present
-  ansible.builtin.stat:
-    path: /etc/pam.d/postlogin
-  register: result_pam_file_present
-  when: '"pam" in ansible_facts.packages'
-  tags:
-  - CCE-80788-3
-  - CJIS-5.5.2
-  - DISA-STIG-RHEL-08-020340
-  - NIST-800-53-AC-9
-  - NIST-800-53-AC-9(1)
-  - PCI-DSS-Req-10.2.4
-  - PCI-DSSv4-10.2.1.4
-  - configure_strategy
-  - display_login_attempts
-  - low_complexity
-  - low_disruption
-  - low_severity
-  - no_reboot_needed
-
-- name: Ensure PAM Displays Last Logon/Access Notification - Check the proper remediation
-    for the system
-  block:
-
-  - name: Ensure PAM Displays Last Logon/Access Notification - Define the PAM file
-      to be edited as a local fact
-    ansible.builtin.set_fact:
-      pam_file_path: /etc/pam.d/postlogin
-
-  - name: Ensure PAM Displays Last Logon/Access Notification - Check if system relies
-      on authselect tool
-    ansible.builtin.stat:
-      path: /usr/bin/authselect
-    register: result_authselect_present
-
-  - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect custom
-      profile is used if authselect is present
-    block:
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Check integrity of
-        authselect current profile
-      ansible.builtin.command:
-        cmd: authselect check
-      register: result_authselect_check_cmd
-      changed_when: false
-      failed_when: false
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Informative message
-        based on the authselect integrity check result
-      ansible.builtin.assert:
-        that:
-        - result_authselect_check_cmd.rc == 0
-        fail_msg:
-        - authselect integrity check failed. Remediation aborted!
-        - This remediation could not be applied because an authselect profile was
-          not selected or the selected profile is not intact.
-        - It is not recommended to manually edit the PAM files when authselect tool
-          is available.
-        - In cases where the default authselect profile does not cover a specific
-          demand, a custom authselect profile is recommended.
-        success_msg:
-        - authselect integrity check passed
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Get authselect current
-        profile
-      ansible.builtin.shell:
-        cmd: authselect current -r | awk '{ print $1 }'
-      register: result_authselect_profile
-      changed_when: false
-      when:
-      - result_authselect_check_cmd is success
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Define the current
-        authselect profile as a local fact
-      ansible.builtin.set_fact:
-        authselect_current_profile: '{{ result_authselect_profile.stdout }}'
-        authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
-      when:
-      - result_authselect_profile is not skipped
-      - result_authselect_profile.stdout is match("custom/")
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Define the new authselect
-        custom profile as a local fact
-      ansible.builtin.set_fact:
-        authselect_current_profile: '{{ result_authselect_profile.stdout }}'
-        authselect_custom_profile: custom/hardening
-      when:
-      - result_authselect_profile is not skipped
-      - result_authselect_profile.stdout is not match("custom/")
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Get authselect current
-        features to also enable them in the custom profile
-      ansible.builtin.shell:
-        cmd: authselect current | tail -n+3 | awk '{ print $2 }'
-      register: result_authselect_features
-      changed_when: false
-      when:
-      - result_authselect_profile is not skipped
-      - authselect_current_profile is not match("custom/")
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Check if any custom
-        profile with the same name was already created
-      ansible.builtin.stat:
-        path: /etc/authselect/{{ authselect_custom_profile }}
-      register: result_authselect_custom_profile_present
-      changed_when: false
-      when:
-      - authselect_current_profile is not match("custom/")
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Create an authselect
-        custom profile based on the current profile
-      ansible.builtin.command:
-        cmd: authselect create-profile hardening -b {{ authselect_current_profile
-          }}
-      when:
-      - result_authselect_check_cmd is success
-      - authselect_current_profile is not match("custom/")
-      - not result_authselect_custom_profile_present.stat.exists
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect
-        changes are applied
-      ansible.builtin.command:
-        cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
-      when:
-      - result_authselect_check_cmd is success
-      - result_authselect_profile is not skipped
-      - authselect_current_profile is not match("custom/")
-      - authselect_custom_profile is not match(authselect_current_profile)
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Ensure the authselect
-        custom profile is selected
-      ansible.builtin.command:
-        cmd: authselect select {{ authselect_custom_profile }}
-      register: result_pam_authselect_select_profile
-      when:
-      - result_authselect_check_cmd is success
-      - result_authselect_profile is not skipped
-      - authselect_current_profile is not match("custom/")
-      - authselect_custom_profile is not match(authselect_current_profile)
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Restore the authselect
-        features in the custom profile
-      ansible.builtin.command:
-        cmd: authselect enable-feature {{ item }}
-      loop: '{{ result_authselect_features.stdout_lines }}'
-      register: result_pam_authselect_restore_features
-      when:
-      - result_authselect_profile is not skipped
-      - result_authselect_features is not skipped
-      - result_pam_authselect_select_profile is not skipped
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect
-        changes are applied
-      ansible.builtin.command:
-        cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
-      when:
-      - result_authselect_check_cmd is success
-      - result_authselect_profile is not skipped
-      - result_pam_authselect_restore_features is not skipped
-
-    - name: Ensure PAM Displays Last Logon/Access Notification - Change the PAM file
-        to be edited according to the custom authselect profile
-      ansible.builtin.set_fact:
-        pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
-          | basename }}
-    when:
-    - result_authselect_present.stat.exists
 
   - name: Ensure PAM Displays Last Logon/Access Notification - Ensure the "silent"
       option from "pam_lastlog.so" is not present in {{ pam_file_path }}
     ansible.builtin.replace:
       dest: '{{ pam_file_path }}'
-      regexp: (.*session.*pam_lastlog.so.*)\bsilent\b=?[0-9a-zA-Z]*(.*)
+      regexp: (.*session.*{{ '[default=1]' | regex_escape() }}.*pam_lastlog.so.*)\bsilent\b=?[0-9a-zA-Z]*(.*)
       replace: \1\2
     register: result_pam_option_removal
-
-  - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect changes
-      are applied
-    ansible.builtin.command:
-      cmd: authselect apply-changes -b
-    when:
-    - result_authselect_present.stat.exists
-    - result_pam_option_removal is changed
-  when:
-  - '"pam" in ansible_facts.packages'
-  - result_pam_file_present.stat.exists
-  tags:
-  - CCE-80788-3
-  - CJIS-5.5.2
-  - DISA-STIG-RHEL-08-020340
-  - NIST-800-53-AC-9
-  - NIST-800-53-AC-9(1)
-  - PCI-DSS-Req-10.2.4
-  - PCI-DSSv4-10.2.1.4
-  - configure_strategy
-  - display_login_attempts
-  - low_complexity
-  - low_disruption
-  - low_severity
-  - no_reboot_needed
+  when: '"pam" in ansible_facts.packages'
+  tags:
+  - CCE-80788-3
+  - CJIS-5.5.2
+  - DISA-STIG-RHEL-08-020340
+  - NIST-800-53-AC-9
+  - NIST-800-53-AC-9(1)
+  - PCI-DSS-Req-10.2.4
+  - PCI-DSSv4-10.2.1.4
+  - configure_strategy
+  - display_login_attempts
+  - low_complexity
+  - low_disruption
+  - low_severity
+  - no_reboot_needed

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth
@@ -289,8 +289,8 @@
       is present in {{ pam_file_path }}'
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+{{ var_password_pam_remember_control_flag.split(",")[0]
-        }}\s+pam_pwhistory.so\s*.*
+      regexp: ^\s*password\s+{{ '{{ var_password_pam_remember_control_flag.split(",")[0]
+        }}' | regex_escape() }}\s+pam_pwhistory.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -737,7 +737,7 @@
       is present in {{ pam_file_path }}'
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*
+      regexp: ^\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -794,7 +794,7 @@
       option is present in {{ pam_file_path }}'
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b
+      regexp: ^\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so\s*.*\sremember\b
       state: absent
     check_mode: true
     changed_when: false
@@ -805,7 +805,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so.*)
+      regexp: ^(\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so.*)
       line: \1 remember={{ var_password_pam_remember }}
       state: present
     register: result_pam_remember_add
@@ -817,7 +817,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*)
+      regexp: ^(\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*)
       line: \1\2={{ var_password_pam_remember }} \3
     register: result_pam_remember_edit
     when:

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth
@@ -289,8 +289,8 @@
       present in {{ pam_file_path }}'
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+{{ var_password_pam_remember_control_flag.split(",")[0]
-        }}\s+pam_pwhistory.so\s*.*
+      regexp: ^\s*password\s+{{ '{{ var_password_pam_remember_control_flag.split(",")[0]
+        }}' | regex_escape() }}\s+pam_pwhistory.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -736,7 +736,7 @@
       present in {{ pam_file_path }}'
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*
+      regexp: ^\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -793,7 +793,7 @@
       is present in {{ pam_file_path }}'
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b
+      regexp: ^\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so\s*.*\sremember\b
       state: absent
     check_mode: true
     changed_when: false
@@ -804,7 +804,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so.*)
+      regexp: ^(\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so.*)
       line: \1 remember={{ var_password_pam_remember }}
       state: present
     register: result_pam_remember_add
@@ -816,7 +816,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*)
+      regexp: ^(\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*)
       line: \1\2={{ var_password_pam_remember }} \3
     register: result_pam_remember_edit
     when:

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_remember' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_remember
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_remember
@@ -275,7 +275,7 @@
       pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*
+      regexp: ^\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -706,7 +706,7 @@
       pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*
+      regexp: ^\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -763,7 +763,7 @@
       in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b
+      regexp: ^\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so\s*.*\sremember\b
       state: absent
     check_mode: true
     changed_when: false
@@ -774,7 +774,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so.*)
+      regexp: ^(\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so.*)
       line: \1 remember={{ var_password_pam_unix_remember }}
       state: present
     register: result_pam_remember_add
@@ -786,7 +786,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*)
+      regexp: ^(\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*)
       line: \1\2={{ var_password_pam_unix_remember }} \3
     register: result_pam_remember_edit
     when:

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwquality_password_auth' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_pwquality_password_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_pwquality_password_auth
@@ -179,7 +179,7 @@
       if expected PAM module line is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+requisite\s+pam_pwquality.so\s*.*
+      regexp: ^\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwquality.so\s*.*
       state: absent
     check_mode: true
     changed_when: false

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwquality_system_auth' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_pwquality_system_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_pwquality_system_auth
@@ -179,7 +179,7 @@
       if expected PAM module line is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+requisite\s+pam_pwquality.so\s*.*
+      regexp: ^\s*password\s+{{ 'requisite' | regex_escape() }}\s+pam_pwquality.so\s*.*
       state: absent
     check_mode: true
     changed_when: false

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_retry' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_retry
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_retry
@@ -221,7 +221,7 @@
       not present in {{ pam_file_path }}
     ansible.builtin.replace:
       dest: '{{ pam_file_path }}'
-      regexp: (.*password.*.*.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*)
+      regexp: (.*password.*{{ '.*' | regex_escape() }}.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*)
       replace: \1\2
     register: result_pam_option_removal
 
@@ -429,7 +429,7 @@
       not present in {{ pam_file_path }}
     ansible.builtin.replace:
       dest: '{{ pam_file_path }}'
-      regexp: (.*password.*.*.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*)
+      regexp: (.*password.*{{ '.*' | regex_escape() }}.*pam_pwquality.so.*)\bretry\b=?[0-9a-zA-Z]*(.*)
       replace: \1\2
     register: result_pam_option_removal
 

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_passwordauth' differs.
--- xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_passwordauth
+++ xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_passwordauth
@@ -191,7 +191,7 @@
       PAM module line is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*
+      regexp: ^\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -249,7 +249,7 @@
       PAM module option is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\ssha512\b
+      regexp: ^\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so\s*.*\ssha512\b
       state: absent
     check_mode: true
     changed_when: false
@@ -260,7 +260,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*)
+      regexp: ^(\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so.*)
       line: \1 sha512
       state: present
     register: result_pam_sha512_add

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_systemauth' differs.
--- xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_systemauth
+++ xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_systemauth
@@ -190,7 +190,7 @@
       is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*
+      regexp: ^\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -247,7 +247,7 @@
       option is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\ssha512\b
+      regexp: ^\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so\s*.*\ssha512\b
       state: absent
     check_mode: true
     changed_when: false
@@ -258,7 +258,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*)
+      regexp: ^(\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so.*)
       line: \1 sha512
       state: present
     register: result_pam_sha512_add

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_rounds_password_auth' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_rounds_password_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_rounds_password_auth
@@ -182,7 +182,7 @@
       PAM module line is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*
+      regexp: ^\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -240,7 +240,7 @@
       PAM module option is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\srounds\b
+      regexp: ^\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so\s*.*\srounds\b
       state: absent
     check_mode: true
     changed_when: false
@@ -251,7 +251,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*)
+      regexp: ^(\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so.*)
       line: \1 rounds={{ var_password_pam_unix_rounds }}
       state: present
     register: result_pam_rounds_add
@@ -263,7 +263,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*)
+      regexp: ^(\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*)
       line: \1\2={{ var_password_pam_unix_rounds }} \3
     register: result_pam_rounds_edit
     when:

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_rounds_system_auth' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_rounds_system_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_rounds_system_auth
@@ -182,7 +182,7 @@
       PAM module line is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*
+      regexp: ^\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -240,7 +240,7 @@
       PAM module option is present in {{ pam_file_path }}
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
-      regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\srounds\b
+      regexp: ^\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so\s*.*\srounds\b
       state: absent
     check_mode: true
     changed_when: false
@@ -251,7 +251,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*)
+      regexp: ^(\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so.*)
       line: \1 rounds={{ var_password_pam_unix_rounds }}
       state: present
     register: result_pam_rounds_add
@@ -263,7 +263,7 @@
     ansible.builtin.lineinfile:
       path: '{{ pam_file_path }}'
       backrefs: true
-      regexp: ^(\s*password\s+sufficient\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*)
+      regexp: ^(\s*password\s+{{ 'sufficient' | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]+\s*(.*)
       line: \1\2={{ var_password_pam_unix_rounds }} \3
     register: result_pam_rounds_edit
     when:

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_sssd_enable_smartcards' differs.
--- xccdf_org.ssgproject.content_rule_sssd_enable_smartcards
+++ xccdf_org.ssgproject.content_rule_sssd_enable_smartcards
@@ -180,7 +180,7 @@
       in /etc/pam.d/smartcard-auth
     ansible.builtin.lineinfile:
       path: /etc/pam.d/smartcard-auth
-      regexp: ^\s*auth\s+sufficient\s+pam_sss.so\s*.*
+      regexp: ^\s*auth\s+{{ 'sufficient' | regex_escape() }}\s+pam_sss.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -236,7 +236,7 @@
       in /etc/pam.d/smartcard-auth
     ansible.builtin.lineinfile:
       path: /etc/pam.d/smartcard-auth
-      regexp: ^\s*auth\s+sufficient\s+pam_sss.so\s*.*\sallow_missing_name\b
+      regexp: ^\s*auth\s+{{ 'sufficient' | regex_escape() }}\s+pam_sss.so\s*.*\sallow_missing_name\b
       state: absent
     check_mode: true
     changed_when: false
@@ -247,7 +247,7 @@
     ansible.builtin.lineinfile:
       path: /etc/pam.d/smartcard-auth
       backrefs: true
-      regexp: ^(\s*auth\s+sufficient\s+pam_sss.so.*)
+      regexp: ^(\s*auth\s+{{ 'sufficient' | regex_escape() }}\s+pam_sss.so.*)
       line: \1 allow_missing_name
       state: present
     register: result_pam_allow_missing_name_add
@@ -258,7 +258,8 @@
       in /etc/pam.d/system-auth
     ansible.builtin.lineinfile:
       path: /etc/pam.d/system-auth
-      regexp: ^\s*auth\s+\[success=done authinfo_unavail=ignore ignore=ignore default=die\]\s+pam_sss.so\s*.*
+      regexp: ^\s*auth\s+{{ '\[success=done authinfo_unavail=ignore ignore=ignore
+        default=die\]' | regex_escape() }}\s+pam_sss.so\s*.*
       state: absent
     check_mode: true
     changed_when: false
@@ -315,7 +316,8 @@
       in /etc/pam.d/system-auth
     ansible.builtin.lineinfile:
       path: /etc/pam.d/system-auth
-      regexp: ^\s*auth\s+\[success=done authinfo_unavail=ignore ignore=ignore default=die\]\s+pam_sss.so\s*.*\stry_cert_auth\b
+      regexp: ^\s*auth\s+{{ '\[success=done authinfo_unavail=ignore ignore=ignore
+        default=die\]' | regex_escape() }}\s+pam_sss.so\s*.*\stry_cert_auth\b
       state: absent
     check_mode: true
     changed_when: false
@@ -326,7 +328,8 @@
     ansible.builtin.lineinfile:
       path: /etc/pam.d/system-auth
       backrefs: true
-      regexp: ^(\s*auth\s+\[success=done authinfo_unavail=ignore ignore=ignore default=die\]\s+pam_sss.so.*)
+      regexp: ^(\s*auth\s+{{ '\[success=done authinfo_unavail=ignore ignore=ignore
+        default=die\]' | regex_escape() }}\s+pam_sss.so.*)
       line: \1 try_cert_auth
       state: present
     register: result_pam_try_cert_auth_add

@marcusburghardt
Copy link
Member Author

@dodys , @freddieRv and @teacup-on-rockingchair , it took me some time to investigate the #9031 and come with this PR. Initially it was affecting the user experience but after some investigation much more was involved. I think the changes proposed in this PR also make sense for other distros and your feedback on this would be appreciated. Much more context and detailed information is found in #9031 Thanks

Copy link
Contributor

@teacup-on-rockingchair teacup-on-rockingchair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Beside the ansible issue saw no other definately looks better 👍

@ggbecker
Copy link
Member

/packit retest-failed

Instead of using BOF (beginning of file), it was included a Jinja2
variable to make the regex more flexible among different distros. In
case the regex does not match, the line is inserted at the end of the
file.
Instead of using a literal control, it was included a Jinja2 variable
to make the control more flexible among different distros.
Copy link
Contributor

@teacup-on-rockingchair teacup-on-rockingchair left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice stuff 🙇

PAM files can use advanced syntax for controls, such as [default=1].
In Ansible macros, the control value is used both to assemble the
desired line and to assemble the regexp. For regexp, the square
brackets must be escaped.
In systems using authselect, there is a feature to properly configure
the pam_lastlog.so module in order to be silent or to show the failed
logins. It was created a macro to use this authselect feature whenever
available. The Bash remediation was also updated to use this new macro.
The bash remediation is now capable to use the authselect feature to
configure pam_lastlog.so so the test scenario scripts were aligned to
this new feature. Some tests were simplified and unnecessary tests were
removed.
It is aligned to the equivalent Bash macro. Remediation was also updated
to use this new Ansible macro.
Systems which were already remediated with this rule before this
refactoring might demand manual actions from the administrator in order
to properly restore the original settings.
@Mab879 Mab879 self-assigned this Aug 25, 2023
@Mab879 Mab879 added this to the 0.1.70 milestone Aug 25, 2023
Copy link
Member

@Mab879 Mab879 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Automatus tests locally in RHEL7-RHEL9 VMs.

@Mab879
Copy link
Member

Mab879 commented Aug 25, 2023

/packit retest-failed

@marcusburghardt
Copy link
Member Author

@dodys and @freddieRv could you also take a look on this PR, please?

Copy link
Contributor

@dodys dodys left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some small details regarding ubuntu specifically

Although the control is not critical for the OVAL check, it is relevant
for remediation so distros can use their own preferences.
Aligned the platforms among all test scenario scripts, ensuring the
tests become applicable to main products. Also ensured two pass test
scripts with different control in order to confirm the control is not
considered during the OVAL assessment.
@codeclimate
Copy link

codeclimate bot commented Aug 29, 2023

Code Climate has analyzed commit 21ae1e1 and detected 0 issues on this pull request.

The test coverage on the diff in this pull request is 100.0% (50% is the threshold).

This pull request will bring the total coverage in the repository to 53.3% (0.0% change).

View more on Code Climate.

Copy link
Contributor

@dodys dodys left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks for addressing the comments!

Copy link
Contributor

@freddieRv freddieRv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes LGTM. Thanks for addressing my comment @marcusburghardt

@Mab879
Copy link
Member

Mab879 commented Aug 29, 2023

/packit retest-failed

@Mab879
Copy link
Member

Mab879 commented Aug 29, 2023

Thanks all for your reviews!

@Mab879 Mab879 merged commit ac68625 into ComplianceAsCode:master Aug 29, 2023
33 of 38 checks passed
@marcusburghardt marcusburghardt deleted the display_login_attempts_fix branch August 29, 2023 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugfix Fixes to reported bugs. refactoring Improvement which, once completed, will enable the project to progress faster. Update Rule Issues or pull requests related to Rules updates.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Improve the description of display_login_attempts rule and respective remediation
6 participants