<def-group>
  <definition class="compliance" id="accounts_passwords_pam_faillock_deny" version="4">
    <metadata>
      <title>Lock out account after failed login attempts</title>
      <affected family="unix">
        <platform>multi_platform_all</platform>
      </affected>
      <description>The number of allowed failed logins should be set correctly.</description>
      <reference source="JL" ref_id="RHEL6_20150122" ref_url="test_attestation" />
      <reference source="JL" ref_id="RHEL7_20150122" ref_url="test_attestation" />
      <reference source="JL" ref_id="FEDORA20_20150122" ref_url="test_attestation" />
    </metadata>
    <criteria>

      <criterion test_ref="test_accounts_passwords_pam_faillock_preauth_silent_system-auth"
      comment="pam_faillock.so preauth silent set in system-auth" />
      <criterion test_ref="test_accounts_passwords_pam_faillock_authfail_deny_system-auth"
      comment="pam_faillock.so authfail deny value set in system-auth" />
      <criterion test_ref="test_accounts_passwords_pam_faillock_account_phase_system-auth"
      comment="pam_faillock.so set in account phase of system-auth" />
      <criterion test_ref="test_accounts_passwords_pam_faillock_preauth_silent_password-auth"
      comment="pam_faillock.so preauth silent set in password-auth" />
      <criterion test_ref="test_accounts_passwords_pam_faillock_authfail_deny_password-auth"
      comment="pam_faillock.so authfail deny value set in password-auth" />
      <criterion test_ref="test_accounts_passwords_pam_faillock_account_phase_password-auth"
      comment="pam_faillock.so set in account phase of password-auth" />

    </criteria>
  </definition>

  <!-- Specify required external variable & create corresponding state from it -->
  <external_variable id="var_accounts_passwords_pam_faillock_deny" datatype="int"
  comment="number of failed login attempts allowed" version="1" />

  <ind:textfilecontent54_state id="state_var_accounts_passwords_pam_faillock_deny_value" version="1">
    <ind:subexpression datatype="int" operation="less than or equal" var_ref="var_accounts_passwords_pam_faillock_deny" />
  </ind:textfilecontent54_state>

  <!-- Check for preauth silent in /etc/pam.d/system-auth -->
  <!-- Also check the 'deny' option value matches the number of failed login attempts allowed -->
  <ind:textfilecontent54_test id="test_accounts_passwords_pam_faillock_preauth_silent_system-auth"
  check="all" check_existence="all_exist"
  comment="Check pam_faillock.so preauth silent present in /etc/pam.d/system-auth" version="1">
    <ind:object object_ref="object_accounts_passwords_pam_faillock_preauth_silent_system-auth" />
    <ind:state state_ref="state_var_accounts_passwords_pam_faillock_deny_value" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_accounts_passwords_pam_faillock_preauth_silent_system-auth" version="1">
    <!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
    <ind:behaviors singleline="true" />
    <ind:filepath>/etc/pam.d/system-auth</ind:filepath>
    <!-- Since order of PAM modules matters ensure pam_faillock.so preauth silent in auth section is listed before
         pam_unix.so module in auth section -->
    <ind:pattern operation="pattern match">[\n][\s]*auth[\s]+required[\s]+pam_faillock\.so[\s]+preauth[\s]+silent[\s]+[^\n]*deny=([0-9]+)[\s]*[^\n]*[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
    <!-- Check only the first instance -->
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

  <!-- Check for authfail deny in /etc/pam.d/system-auth -->
  <ind:textfilecontent54_test id="test_accounts_passwords_pam_faillock_authfail_deny_system-auth"
  check="all" check_existence="all_exist"
  comment="Check maximum failed login attempts allowed in /etc/pam.d/system-auth (authfail)" version="1">
    <ind:object object_ref="object_accounts_passwords_pam_faillock_authfail_deny_system-auth" />
    <ind:state state_ref="state_var_accounts_passwords_pam_faillock_deny_value" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_accounts_passwords_pam_faillock_authfail_deny_system-auth" version="1">
    <!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
    <ind:behaviors singleline="true" />
    <ind:filepath>/etc/pam.d/system-auth</ind:filepath>
    <!-- Since order of PAM modules matters ensure pam_faillock.so in auth section is listed right after pam_unix.so auth row -->
    <ind:pattern operation="pattern match">[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]+[\n][\s]*auth[\s]+\[default=die\][\s]+pam_faillock\.so[\s]+authfail[\s]+[^\n]*deny=([0-9]+)[^\n]*[\n]</ind:pattern>
    <!-- Check only the first instance -->
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

  <!-- Check for pam_faillock.so present in account phase of /etc/pam.d/system-auth -->
  <ind:textfilecontent54_test id="test_accounts_passwords_pam_faillock_account_phase_system-auth"
  check="all" check_existence="all_exist"
  comment="Check if pam_faillock_so is called in account phase of /etc/pam.d/system-auth" version="1" >
    <ind:object object_ref="object_accounts_passwords_pam_faillock_account_phase_system-auth" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_accounts_passwords_pam_faillock_account_phase_system-auth" version="1">
    <!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
    <ind:behaviors singleline="true" />
    <ind:filepath>/etc/pam.d/system-auth</ind:filepath>
    <!-- Since order of PAM modules matters ensure pam_faillock.so in account section is listed right before pam_unix.so account row -->
    <ind:pattern operation="pattern match">[\n][\s]*account[\s]+required[\s]+pam_faillock\.so[^\n]*[\n][\s]*account[\s]+required[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
    <!-- Check only the first instance -->
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

  <!-- Check for preauth silent in /etc/pam.d/password-auth -->
  <!-- Also check the 'deny' option value matches the number of failed login attempts allowed -->
  <ind:textfilecontent54_test id="test_accounts_passwords_pam_faillock_preauth_silent_password-auth"
  check="all" check_existence="all_exist"
  comment="Check pam_faillock.so preauth silent present in /etc/pam.d/password-auth" version="1">
    <ind:object object_ref="object_accounts_passwords_pam_faillock_preauth_silent_password-auth" />
    <ind:state state_ref="state_var_accounts_passwords_pam_faillock_deny_value" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_accounts_passwords_pam_faillock_preauth_silent_password-auth" version="1">
    <!-- Read whole /etc/pam.d/password-auth content as single line so we can verify existing order of PAM modules -->
    <ind:behaviors singleline="true" />
    <ind:filepath>/etc/pam.d/password-auth</ind:filepath>
    <!-- Since order of PAM modules matters ensure pam_faillock.so preauth silent in auth section is listed before
         pam_unix.so module in auth section -->
    <ind:pattern operation="pattern match">[\n][\s]*auth[\s]+required[\s]+pam_faillock\.so[\s]+preauth[\s]+silent[\s]+[^\n]*deny=([0-9]+)[\s]*[^\n]*[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
    <!-- Check only the first instance -->
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

  <!-- Check for authfail deny in /etc/pam.d/password-auth -->
  <ind:textfilecontent54_test id="test_accounts_passwords_pam_faillock_authfail_deny_password-auth"
  check="all" check_existence="all_exist"
  comment="Check maximum failed login attempts allowed in /etc/pam.d/password-auth (authfail)" version="1">
    <ind:object object_ref="object_accounts_passwords_pam_faillock_authfail_deny_password-auth" />
    <ind:state state_ref="state_var_accounts_passwords_pam_faillock_deny_value" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_accounts_passwords_pam_faillock_authfail_deny_password-auth" version="1">
    <!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
    <ind:behaviors singleline="true" />
    <ind:filepath>/etc/pam.d/password-auth</ind:filepath>
    <!-- Since order of PAM modules matters ensure pam_faillock.so in auth section is listed right after pam_unix.so auth row -->
    <ind:pattern operation="pattern match">[\n][\s]*auth[\s]+sufficient[\s]+pam_unix\.so[^\n]+[\n][\s]*auth[\s]+\[default=die\][\s]+pam_faillock\.so[\s]+authfail[\s]+[^\n]*deny=([0-9]+)[^\n]*[\n]</ind:pattern>
    <!-- Check only the first instance -->
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

  <!-- Check for pam_faillock.so present in account phase of /etc/pam.d/password-auth -->
  <ind:textfilecontent54_test id="test_accounts_passwords_pam_faillock_account_phase_password-auth"
  check="all" check_existence="all_exist"
  comment="Check if pam_faillock_so is called in account phase of /etc/pam.d/password-auth" version="1" >
    <ind:object object_ref="object_accounts_passwords_pam_faillock_account_phase_password-auth" />
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object id="object_accounts_passwords_pam_faillock_account_phase_password-auth" version="1">
    <!-- Read whole /etc/pam.d/system-auth content as single line so we can verify existing order of PAM modules -->
    <ind:behaviors singleline="true" />
    <ind:filepath>/etc/pam.d/password-auth</ind:filepath>
    <!-- Since order of PAM modules matters ensure pam_faillock.so in account section is listed right before pam_unix.so account row -->
    <ind:pattern operation="pattern match">[\n][\s]*account[\s]+required[\s]+pam_faillock\.so[^\n]*[\n][\s]*account[\s]+required[\s]+pam_unix\.so[^\n]*[\n]</ind:pattern>
    <!-- Check only the first instance -->
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

</def-group>
