<def-group>
  <definition class="compliance" id="{{{ rule_id }}}" version="5">
    {{{ oval_metadata("Enforce pam_faillock for Local Accounts Only") }}}
    <criteria operator="AND" comment="Check the proper configuration of pam_faillock.so">
      <criteria operator="AND" comment="Check if pam_faillock.so is properly enabled">
        <!-- pam_unix.so is a control module present in all realistic scenarios and also used
             as reference for the correct position of pam_faillock.so in auth section. If the
             system is properly configured, it must appear only once in auth section. -->
        <criteria operator="AND"
                  comment="Count occurrences of pam_unix.so in system-auth and password-auth">
          <criterion
              test_ref="test_accounts_passwords_pam_faillock_enforce_local_system_pam_unix_auth"
              comment="pam_unix.so appears only once in auth section of system-auth"/>
          <criterion
              test_ref="test_accounts_passwords_pam_faillock_enforce_local_password_pam_unix_auth"
              comment="pam_unix.so appears only once in auth section of password-auth"/>
        </criteria>

        <!-- pam_faillock.so parameters can be defined directly in pam files or, in newer
             versions, in /etc/security/faillock.conf. The last is the recommended option when
             available. Also, is the option used by auselect tool. However, regardless the
             approach, a minimal declaration is common in pam files. -->
        <criteria operator="AND" comment="Check common definition of pam_faillock.so">
          <criterion
            test_ref="test_accounts_passwords_pam_faillock_enforce_local_system_pam_faillock_auth"
            comment="pam_faillock.so is properly defined in auth section of system-auth"/>
          <criterion
            test_ref="test_accounts_passwords_pam_faillock_enforce_local_system_pam_faillock_account"
            comment="pam_faillock.so is properly defined in account section of system-auth"/>
          <criterion
            test_ref="test_accounts_passwords_pam_faillock_enforce_local_password_pam_faillock_auth"
            comment="pam_faillock.so is properly defined in auth section of password-auth"/>
          <criterion
            test_ref="test_accounts_passwords_pam_faillock_enforce_local_password_pam_faillock_account"
            comment="pam_faillock.so is properly defined in account section of password-auth"/>
        </criteria>
      </criteria>

      <criterion
        test_ref="test_accounts_passwords_pam_faillock_enforce_local_parameter_faillock_conf"
        comment="Ensure the local_users_only parameter is present in /etc/security/faillock.conf"/>
    </criteria>
  </definition>

  <!-- The following tests demand complex regex which are necessary more than once.
       These variables make simpler the usage of regex patterns. -->
  <constant_variable id="var_accounts_passwords_pam_faillock_enforce_local_pam_unix_regex"
                datatype="string" version="1"
                comment="regex to identify pam_unix.so in auth section of pam files">
    <value>^[\s]*auth\N+pam_unix\.so</value>
  </constant_variable>

  <constant_variable id="var_accounts_passwords_pam_faillock_enforce_local_pam_faillock_auth_regex"
                datatype="string" version="1"
                comment="regex to identify pam_faillock.so entries in auth section of pam files">
    <value>^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+preauth[\s\S]*^[\s]*auth[\s]+(sufficient|\[(?=.*\bsuccess=done\b)(?=.*?\bnew_authtok_reqd=done\b)(?=.*?\bdefault=ignore\b).*\])[\s]+pam_unix\.so[\s\S]*^[\s]*auth[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\w\d=]+authfail</value>
  </constant_variable>

  <constant_variable id="var_accounts_passwords_pam_faillock_enforce_local_pam_faillock_account_regex"
                datatype="string" version="1"
                comment="regex to identify pam_faillock.so entry in account section of pam files">
    <value>^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_faillock\.so[\s\S]*^[\s]*account[\s]+(required|\[(?=.*?\bsuccess=ok\b)(?=.*?\bnew_authtok_reqd=ok\b)(?=.*?\bignore=ignore\b)(?=.*?\bdefault=bad\b).*\])[\s]+pam_unix\.so</value>
  </constant_variable>

  <constant_variable
              id="var_accounts_passwords_pam_faillock_enforce_local_faillock_conf_parameter_regex"
              datatype="string" version="1"
              comment="regex to identify deny entry in /etc/security/faillock.conf">
    <value>^[\s]*local_users_only</value>
  </constant_variable>

  <!-- Check occurrences of pam_unix.so in auth section of system-auth file -->
  <ind:textfilecontent54_object version="1"
        id="object_accounts_passwords_pam_faillock_enforce_local_system_pam_unix_auth"
        comment="Get the second and subsequent occurrences of pam_unix.so in auth section of system-auth">
    <ind:filepath operation="pattern match">^/etc/pam.d/system-auth$</ind:filepath>
    <ind:pattern operation="pattern match"
                 var_ref="var_accounts_passwords_pam_faillock_enforce_local_pam_unix_regex"/>
    <!-- It is not expected to find a second instance of this pattern -->
    <ind:instance datatype="int" operation="greater than">1</ind:instance>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_test check="all" check_existence="none_exist" version="1"
        id="test_accounts_passwords_pam_faillock_enforce_local_system_pam_unix_auth"
        comment="No more than one pam_unix.so is expected in auth section of system-auth">
    <ind:object object_ref="object_accounts_passwords_pam_faillock_enforce_local_system_pam_unix_auth"/>
  </ind:textfilecontent54_test>

  <!-- Check occurrences of pam_unix.so in auth section in password-auth -->
  <ind:textfilecontent54_object version="1"
        id="object_accounts_passwords_pam_faillock_enforce_local_password_pam_unix_auth"
        comment="Get the second and subsequent occurrences of pam_unix.so in auth section of password-auth">
    <ind:filepath operation="pattern match">^/etc/pam.d/password-auth$</ind:filepath>
    <ind:pattern operation="pattern match"
                 var_ref="var_accounts_passwords_pam_faillock_enforce_local_pam_unix_regex"/>
    <ind:instance datatype="int" operation="greater than">1</ind:instance>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_test check="all" check_existence="none_exist" version="1"
        id="test_accounts_passwords_pam_faillock_enforce_local_password_pam_unix_auth"
        comment="No more than one pam_unix.so is expected in auth section of password-auth">
    <ind:object object_ref="object_accounts_passwords_pam_faillock_enforce_local_password_pam_unix_auth"/>
  </ind:textfilecontent54_test>

  <!-- Check common definition of pam_faillock.so in system-auth -->
  <ind:textfilecontent54_object version="1"
        id="object_accounts_passwords_pam_faillock_enforce_local_system_pam_faillock_auth"
        comment="Check common definition of pam_faillock.so in auth section of system-auth">
    <ind:filepath operation="pattern match">^/etc/pam.d/system-auth$</ind:filepath>
    <ind:pattern operation="pattern match"
                 var_ref="var_accounts_passwords_pam_faillock_enforce_local_pam_faillock_auth_regex"/>
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_test check="all" check_existence="all_exist" version="1"
        id="test_accounts_passwords_pam_faillock_enforce_local_system_pam_faillock_auth"
        comment="One and only one pattern occurrence is expected in auth section of system-auth">
    <ind:object
        object_ref="object_accounts_passwords_pam_faillock_enforce_local_system_pam_faillock_auth"/>
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object version="1"
        id="object_accounts_passwords_pam_faillock_enforce_local_system_pam_faillock_account"
        comment="Check common definition of pam_faillock.so in account section of system-auth">
    <ind:filepath operation="pattern match">^/etc/pam.d/system-auth$</ind:filepath>
    <ind:pattern operation="pattern match"
              var_ref="var_accounts_passwords_pam_faillock_enforce_local_pam_faillock_account_regex"/>
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_test check="all" check_existence="all_exist" version="1"
      id="test_accounts_passwords_pam_faillock_enforce_local_system_pam_faillock_account"
      comment="One and only one pattern occurrence is expected in account section of system-auth">
    <ind:object
      object_ref="object_accounts_passwords_pam_faillock_enforce_local_system_pam_faillock_account"/>
  </ind:textfilecontent54_test>

  <!-- Check common definition of pam_faillock.so in password-auth -->
  <ind:textfilecontent54_object version="1"
        id="object_accounts_passwords_pam_faillock_enforce_local_password_pam_faillock_auth"
        comment="Check common definition of pam_faillock.so in auth section of password-auth">
    <ind:filepath operation="pattern match">^/etc/pam.d/password-auth$</ind:filepath>
    <ind:pattern operation="pattern match"
                 var_ref="var_accounts_passwords_pam_faillock_enforce_local_pam_faillock_auth_regex"/>
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_test check="all" check_existence="all_exist" version="1"
        id="test_accounts_passwords_pam_faillock_enforce_local_password_pam_faillock_auth"
        comment="One and only one pattern occurrence is expected in auth section of system-auth">
    <ind:object
        object_ref="object_accounts_passwords_pam_faillock_enforce_local_password_pam_faillock_auth"/>
  </ind:textfilecontent54_test>

  <ind:textfilecontent54_object version="1"
        id="object_accounts_passwords_pam_faillock_enforce_local_password_pam_faillock_account"
        comment="Check common definition of pam_faillock.so in account section of password-auth">
    <ind:filepath operation="pattern match">^/etc/pam.d/password-auth$</ind:filepath>
    <ind:pattern operation="pattern match"
              var_ref="var_accounts_passwords_pam_faillock_enforce_local_pam_faillock_account_regex"/>
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_test check="all" check_existence="all_exist" version="1"
        id="test_accounts_passwords_pam_faillock_enforce_local_password_pam_faillock_account"
    comment="One and only one pattern occurrence is expected in account section of password-auth">
    <ind:object
    object_ref="object_accounts_passwords_pam_faillock_enforce_local_password_pam_faillock_account"/>
  </ind:textfilecontent54_test>

  <!-- Check pam_faillock.so local_users_only parameter in /etc/security/faillock.conf -->
  <ind:textfilecontent54_object version="1"
      id="object_accounts_passwords_pam_faillock_enforce_local_parameter_faillock_conf"
      comment="Try to get the local_users_only parameter from /etc/security/faillock.conf">
    <ind:filepath operation="pattern match">^/etc/security/faillock.conf$</ind:filepath>
    <ind:pattern operation="pattern match"
          var_ref="var_accounts_passwords_pam_faillock_enforce_local_faillock_conf_parameter_regex"/>
    <ind:instance datatype="int" operation="equals">1</ind:instance>
  </ind:textfilecontent54_object>

  <ind:textfilecontent54_test check="all" check_existence="all_exist" version="1"
        id="test_accounts_passwords_pam_faillock_enforce_local_parameter_faillock_conf"
        comment="Check the expected local_users_only parameter in /etc/security/faillock.conf">
    <ind:object
         object_ref="object_accounts_passwords_pam_faillock_enforce_local_parameter_faillock_conf"/>
  </ind:textfilecontent54_test>
</def-group>
