# platform = multi_platform_all
# reboot = false
# strategy = restrict
# complexity = low
# disruption = low
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
  - DISA-STIG-UBTU-22-411045
  - accounts_passwords_pam_faillock_silent
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy

- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
    if system relies on pam-auth-update tool
  ansible.builtin.stat:
    path: /usr/sbin/pam-auth-update
  register: result_pam_auth_update_present
  when:
  - '"linux-base" in ansible_facts.packages'
  - '"libpam-runtime" in ansible_facts.packages'
  tags:
  - DISA-STIG-UBTU-22-411045
  - accounts_passwords_pam_faillock_silent
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy

- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Remediation
    where pam-auth-update tool is present
  block:

  - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
      the presence of cac_faillock file
    ansible.builtin.stat:
      path: /usr/share/pam-configs/cac_faillock
    register: faillock_file_stat

  - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
      the presence of cac_faillock_notify file
    ansible.builtin.stat:
      path: /usr/share/pam-configs/cac_faillock_notify
    register: faillock_notify_file_stat

  - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Put
      the content into cac_faillock if it does not exist
    ansible.builtin.copy:
      dest: /usr/share/pam-configs/cac_faillock
      content: |
        Name: Enable pam_faillock to deny access
        Default: yes
        Priority: 0
        Conflicts: faillock
        Auth-Type: Primary
        Auth:
          [default=die]                   pam_faillock.so authfail
          sufficient                      pam_faillock.so authsucc
      force: true
    when: not faillock_file_stat.stat.exists

  - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Put
      the content into cac_faillock_notify if it does not exist
    ansible.builtin.copy:
      dest: /usr/share/pam-configs/cac_faillock_notify
      content: |
        Name: Notify of failed login attempts and reset count upon success
        Default: yes
        Priority: 1025
        Conflicts: faillock_notify
        Auth-Type: Primary
        Auth:
          requisite                       pam_faillock.so preauth
        Account-Type: Primary
        Account:
          required                        pam_faillock.so
      force: true
    when: not faillock_notify_file_stat.stat.exists

  - name: None - Ensure pam-auth-update profile changes are applied
    ansible.builtin.command:
      cmd: pam-auth-update --enable cac_faillock

  - name: None - Ensure pam-auth-update profile changes are applied
    ansible.builtin.command:
      cmd: pam-auth-update --enable cac_faillock_notify
  when:
  - '"linux-base" in ansible_facts.packages'
  - '"libpam-runtime" in ansible_facts.packages'
  - result_pam_auth_update_present.stat.exists
  tags:
  - DISA-STIG-UBTU-22-411045
  - accounts_passwords_pam_faillock_silent
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy

- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
    the presence of /etc/security/faillock.conf file
  ansible.builtin.stat:
    path: /etc/security/faillock.conf
  register: result_faillock_conf_check
  when:
  - '"linux-base" in ansible_facts.packages'
  - '"libpam-runtime" in ansible_facts.packages'
  tags:
  - DISA-STIG-UBTU-22-411045
  - accounts_passwords_pam_faillock_silent
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy

- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
    the pam_faillock.so silent parameter in /etc/security/faillock.conf
  ansible.builtin.lineinfile:
    path: /etc/security/faillock.conf
    regexp: ^\s*silent
    line: silent
    state: present
  when:
  - '"linux-base" in ansible_facts.packages'
  - '"libpam-runtime" in ansible_facts.packages'
  - result_faillock_conf_check.stat.exists
  tags:
  - DISA-STIG-UBTU-22-411045
  - accounts_passwords_pam_faillock_silent
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy

- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
    the pam_faillock.so silent parameter not in PAM files
  block:

  - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
      if /etc/pam.d/system-auth file is present
    ansible.builtin.stat:
      path: /etc/pam.d/system-auth
    register: result_pam_file_present

  - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
      the proper remediation for the system
    block:

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Define
        the PAM file to be edited as a local fact
      ansible.builtin.set_fact:
        pam_file_path: /etc/pam.d/system-auth

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
        if system relies on authselect tool
      ansible.builtin.stat:
        path: /usr/bin/authselect
      register: result_authselect_present

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
        authselect custom profile is used if authselect is present
      block:

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          Check integrity of authselect current profile
        ansible.builtin.command:
          cmd: authselect check
        register: result_authselect_check_cmd
        changed_when: false
        check_mode: false
        failed_when: false

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          Informative message based on the authselect integrity check result
        ansible.builtin.assert:
          that:
          - ansible_check_mode or 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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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
        check_mode: false
        when:
        - result_authselect_profile is not skipped
        - authselect_current_profile is not match("custom/")

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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:
        - result_authselect_profile is not skipped
        - authselect_current_profile is not match("custom/")

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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_profile is not skipped
        - result_authselect_check_cmd is success
        - authselect_current_profile is not match("^(custom/|local)")
        - not result_authselect_custom_profile_present.stat.exists

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          Create an authselect custom profile based on sssd profile
        ansible.builtin.command:
          cmd: authselect create-profile hardening -b sssd
        when:
        - result_authselect_profile is not skipped
        - result_authselect_check_cmd is success
        - authselect_current_profile is match("local")
        - not result_authselect_custom_profile_present.stat.exists

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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:
        - authselect_custom_profile is defined
      when:
      - result_authselect_present.stat.exists

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Define
        a fact for control already filtered in case filters are used
      ansible.builtin.set_fact:
        pam_module_control: ''

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
        if {{ pam_file_path }} file is present
      ansible.builtin.stat:
        path: '{{ pam_file_path }}'
      register: result_pam_file_present

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
        the "silent" option from "pam_faillock.so" is not present in {{ pam_file_path
        }}
      ansible.builtin.replace:
        dest: '{{ pam_file_path }}'
        regexp: (.*auth.*pam_faillock.so.*)\bsilent\b=?[0-9a-zA-Z]*(.*)
        replace: \1\2
      register: result_pam_option_removal
      when: result_pam_file_present.stat.exists

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - 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:
    - result_pam_file_present.stat.exists

  - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
      if /etc/pam.d/password-auth file is present
    ansible.builtin.stat:
      path: /etc/pam.d/password-auth
    register: result_pam_file_present

  - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
      the proper remediation for the system
    block:

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Define
        the PAM file to be edited as a local fact
      ansible.builtin.set_fact:
        pam_file_path: /etc/pam.d/password-auth

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
        if system relies on authselect tool
      ansible.builtin.stat:
        path: /usr/bin/authselect
      register: result_authselect_present

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
        authselect custom profile is used if authselect is present
      block:

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          Check integrity of authselect current profile
        ansible.builtin.command:
          cmd: authselect check
        register: result_authselect_check_cmd
        changed_when: false
        check_mode: false
        failed_when: false

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          Informative message based on the authselect integrity check result
        ansible.builtin.assert:
          that:
          - ansible_check_mode or 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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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
        check_mode: false
        when:
        - result_authselect_profile is not skipped
        - authselect_current_profile is not match("custom/")

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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:
        - result_authselect_profile is not skipped
        - authselect_current_profile is not match("custom/")

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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_profile is not skipped
        - result_authselect_check_cmd is success
        - authselect_current_profile is not match("^(custom/|local)")
        - not result_authselect_custom_profile_present.stat.exists

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          Create an authselect custom profile based on sssd profile
        ansible.builtin.command:
          cmd: authselect create-profile hardening -b sssd
        when:
        - result_authselect_profile is not skipped
        - result_authselect_check_cmd is success
        - authselect_current_profile is match("local")
        - not result_authselect_custom_profile_present.stat.exists

      - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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: Do Not Show System Messages When Unsuccessful Logon Attempts Occur -
          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:
        - authselect_custom_profile is defined
      when:
      - result_authselect_present.stat.exists

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Define
        a fact for control already filtered in case filters are used
      ansible.builtin.set_fact:
        pam_module_control: ''

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Check
        if {{ pam_file_path }} file is present
      ansible.builtin.stat:
        path: '{{ pam_file_path }}'
      register: result_pam_file_present

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
        the "silent" option from "pam_faillock.so" is not present in {{ pam_file_path
        }}
      ansible.builtin.replace:
        dest: '{{ pam_file_path }}'
        regexp: (.*auth.*pam_faillock.so.*)\bsilent\b=?[0-9a-zA-Z]*(.*)
        replace: \1\2
      register: result_pam_option_removal
      when: result_pam_file_present.stat.exists

    - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - 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:
    - result_pam_file_present.stat.exists
  when:
  - '"linux-base" in ansible_facts.packages'
  - '"libpam-runtime" in ansible_facts.packages'
  - result_faillock_conf_check.stat.exists
  tags:
  - DISA-STIG-UBTU-22-411045
  - accounts_passwords_pam_faillock_silent
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy

- name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
    the pam_faillock.so silent parameter in PAM files
  block:

  - name: Do Not Show System Messages When Unsuccessful Logon Attempts Occur - Ensure
      the inclusion of pam_faillock.so preauth silent parameter in auth section
    ansible.builtin.lineinfile:
      path: '{{ item }}'
      backrefs: true
      regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth(:?(?!silent).)*)
      line: \1required\3 silent
      state: present
    loop:
    - /etc/pam.d/system-auth
    - /etc/pam.d/password-auth
  when:
  - '"linux-base" in ansible_facts.packages'
  - '"libpam-runtime" in ansible_facts.packages'
  - not result_faillock_conf_check.stat.exists
  tags:
  - DISA-STIG-UBTU-22-411045
  - accounts_passwords_pam_faillock_silent
  - low_complexity
  - low_disruption
  - medium_severity
  - no_reboot_needed
  - restrict_strategy
