diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..37122af
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,21 @@
+---
+name: Bug report
+about: Create a report to help us improve
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**Version**
+ - Distribution [e.g. Ubuntu 18.04]
+ - Lynis version [e.g. 2.7.0]
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Output**
+If applicable, add output that you get from the tool or the related section of lynis.log
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..91466f2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,17 @@
+---
+name: Feature request
+about: Suggest an idea for this project
+
+---
+
+**Is your feature request related to a problem? Please describe.**
+A clear and concise description of what the problem is. How would it help you to make things easier? Ex. I'm always frustrated when [...]
+
+**Describe the solution you'd like**
+A clear and concise description of what you want to happen.
+
+**Required changes**
+What needs to be changed in Lynis?
+
+**Additional context**
+Add anything else that you consider to be relevant about the feature request here.
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e53091c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+.bzr
+.bzrignore
+custom.prf
+*.swp
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..ab00fa6
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,14 @@
+language: bash
+
+before_script:
+    - sh extras/travis-ci/before_script.sh
+
+script:
+    - cd .. && cd ./lynis-sdk && sh lynis-devkit run unit-tests
+
+notifications:
+  email:
+    recipients:
+      - lynis-dev@cisofy.com
+    on_success: change
+    on_failure: always
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3d43492..83d058b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,27 @@
 # Lynis Changelog
 
+## Lynis 3.0.8 (not released yet)
+
+### Added
+- MALW-3274 - Detect McAfee VirusScan Command Line Scanner
+- PKGS-7346 Check Alpine Package Keeper (apk)
+- PKGS-7395 Check Alpine upgradeable packages
+- EOL for Alpine Linux 3.14 and 3.15
+
+### Changed
+- AUTH-9408 - Check for pam_faillock as well (replacement for pam_tally2)
+- FILE-7524 - Test enhanced to support symlinks
+- HTTP-6643 - Support ModSecurity version 2 and 3
+- KRNL-5788 - Only run relevant tests and improved logging
+- KRNL-5820 - Additional path for security/limits.conf
+- KRNL-5830 - Check for /var/run/needs_restarting (Slackware)
+- KRNL-5830 - Add a presence check for /boot/vmlinuz
+- PRNT-2308 - Bugfix that prevented test from storing values correctly
+- Extended location of PAM files for AARCH64
+- Some messages in log improved
+
+---------------------------------------------------------------------------------
+
 ## Lynis 3.0.7 (2022-01-18)
 
 ### Added
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4fa3900
--- /dev/null
+++ b/README.md
@@ -0,0 +1,125 @@
+
+
+[![Linux Security Expert badge](https://badges.linuxsecurity.expert/tools/ranking/lynis.svg)](https://linuxsecurity.expert/tools/lynis/)
+[![Build Status](https://travis-ci.org/CISOfy/lynis.svg?branch=master)](https://travis-ci.org/CISOfy/lynis)
+[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/96/badge)](https://bestpractices.coreinfrastructure.org/projects/96)
+[Documentation]
+
+[Documentation]: https://cisofy.com/documentation/lynis/
+
+Do you like this software? **Star the project** and become a [stargazer](https://github.com/CISOfy/lynis/stargazers).
+
+----
+
+# lynis
+
+> Lynis - Security auditing and hardening tool, for UNIX-based systems.
+
+Lynis is a security auditing tool for systems based on UNIX like Linux, macOS, BSD, and others. It performs an **in-depth security scan** and runs on the system itself. The primary goal is to test security defenses and **provide tips for further system hardening**. It will also scan for general system information, vulnerable software packages, and possible configuration issues. Lynis was commonly used by system administrators and auditors to assess the security defenses of their systems. Besides the "blue team," nowadays penetration testers also have Lynis in their toolkit.
+
+We believe software should be **simple**, **updated on a regular basis**, and **open**. You should be able to trust, understand, and have the option to change the software. Many agree with us, as the software is being used by thousands every day to protect their systems.
+
+## Goals
+
+The main goals are:
+- Automated security auditing
+- Compliance testing (e.g. ISO27001, PCI-DSS, HIPAA)
+- Vulnerability detection
+
+The software (also) assists with:
+- Configuration and asset management
+- Software patch management
+- System hardening
+- Penetration testing (privilege escalation)
+- Intrusion detection
+
+### Audience
+
+Typical users of the software:
+- System administrators
+- Auditors
+- Security officers
+- Penetration testers
+- Security professionals
+
+## Installation
+
+There are multiple options available to install Lynis.
+
+### Software Package
+
+For systems running Linux, BSD, and macOS, there is typically a package available. This is the preferred method of obtaining Lynis, as it is quick to install and easy to update. The Lynis project itself also provides [packages](https://packages.cisofy.com/) in RPM or DEB format suitable for systems systems running:
+`CentOS`, `Debian`, `Fedora`, `OEL`, `openSUSE`, `RHEL`, `Ubuntu`, and others.
+
+Some distributions may also have Lynis in their software repository: [![Repology](https://repology.org/badge/tiny-repos/lynis.svg)](https://repology.org/project/lynis/versions)
+
+Note: Some distributions don't provide an up-to-date version. In that case it is better to use the CISOfy software repository, download the tarball from the website, or download the latest GitHub release.
+
+### Git
+
+The very latest developments can be obtained via git.
+
+1. Clone or download the project files (**no compilation nor installation** is required) ;
+
+        git clone https://github.com/CISOfy/lynis
+
+2. Execute:
+
+        cd lynis && ./lynis audit system
+
+If you want to run the software as `root` (or sudo), we suggest changing the ownership of the files. Use `chown -R 0:0` to recursively alter the owner and group and set it to user ID `0` (`root`). Otherwise Lynis will warn you about the file permissions. After all, you are executing files owned by a non-privileged user.
+
+
+### Enterprise Version
+
+This software component is also part of an enterprise solution. Same quality, yet with more functionality.
+
+Focus areas include compliance (`PCI DSS`, `HIPAA`, `ISO27001`, and others). The Enterprise version comes with:
+* a web interface;
+* dashboard and reporting;
+* hardening snippets;
+* improvement plan (based on risk);
+* commercial support.
+
+## Documentation
+Full documentation: https://cisofy.com/documentation/lynis/.
+
+## Customization
+If you want to create your own tests, have a look at the [Lynis software development kit](https://github.com/CISOfy/lynis-sdk).
+
+## Security
+We participate in the [CII best practices](https://bestpractices.coreinfrastructure.org/projects/96) badge program of the Linux Foundation.
+
+## Media and Awards
+Lynis is collecting some awards along the way and we are proud of that.
+
+* 2016
+  * [Best of Open Source Software Awards 2016](http://www.infoworld.com/article/3121251/open-source-tools/bossie-awards-2016-the-best-open-source-networking-and-security-software.html#slide13).
+  * Article by TechRepublic, considering Lynis a "must-have" tool: [How to quickly audit a Linux system from the command line](http://www.techrepublic.com/article/how-to-quickly-audit-a-linux-system-from-the-command-line/)
+  * [![ToolsWatch Best Tools (top 10)](https://www.toolswatch.org/badges/toptools/2016.svg)](https://www.toolswatch.org/2017/02/2016-top-security-tools-as-voted-by-toolswatch-org-readers/)
+
+* 2015
+  * [![ToolsWatch Best Tools (second place)](https://www.toolswatch.org/badges/toptools/2015.svg)](https://www.toolswatch.org/2016/02/2015-top-security-tools-as-voted-by-toolswatch-org-readers/)
+  * [Best of Open Source Software Awards 2015](http://www.idgenterprise.com/news/press-release/infoworld-announces-the-2015-best-of-open-source-software-awards/).
+
+* 2014
+  * [![ToolsWatch Best Tools (third place)](https://www.toolswatch.org/badges/toptools/2014.svg)](https://www.toolswatch.org/2015/01/2014-top-security-tools-as-voted-by-toolswatch-org-readers/)
+
+* 2013
+  * [![ToolsWatch Best Tools (sixth place)](https://www.toolswatch.org/badges/toptools/2013.svg)](https://www.toolswatch.org/2013/12/2013-top-security-tools-as-voted-by-toolswatch-org-readers/)
+
+## Contribute
+
+> We love contributors.
+
+Do you have something to share? Want to help out with translating Lynis into your own language? Create an issue or pull request on GitHub, or send us an e-mail: lynis-dev@cisofy.com.
+
+More details can be found in the [Contributors Guide](https://github.com/CISOfy/lynis/blob/master/CONTRIBUTING.md).
+
+You can also simply contribute to the project by _starring_ the project and show your appreciation that way.
+
+Thanks!
+
+### License
+
+> GPLv3
diff --git a/db/software-eol.db b/db/software-eol.db
index bebd4de..f8242d3 100644
--- a/db/software-eol.db
+++ b/db/software-eol.db
@@ -16,6 +16,8 @@
 #
 # Alpine - https://alpinelinux.org/releases/
 #
+os:Alpine 3.15:2023-11-01:1698793200
+os:Alpine 3.14:2023-05-01:1682899200
 os:Alpine 3.13:2022-11-01:1667275200
 os:Alpine 3.12:2022-05-01:1651377600
 os:Alpine 3.11:2021-11-01:1635739200
diff --git a/db/tests.db b/db/tests.db
index c9c4797..fe16ef9 100644
--- a/db/tests.db
+++ b/db/tests.db
@@ -265,6 +265,7 @@ MAIL-8838:test:security:mail_messaging::Check dovecot process:
 MAIL-8860:test:security:mail_messaging::Check Qmail status:
 MAIL-8880:test:security:mail_messaging::Check Sendmail status:
 MAIL-8920:test:security:mail_messaging::Check OpenSMTPD status:
+MALW-3274:test:security:malware::Check for McAfee VirusScan Command Line Scanner:
 MALW-3275:test:security:malware::Check for chkrootkit:
 MALW-3276:test:security:malware::Check for Rootkit Hunter:
 MALW-3278:test:security:malware::Check for LMD:
@@ -322,6 +323,7 @@ PHP-2376:test:security:php::Check PHP allow_url_fopen option:
 PHP-2378:test:security:php::Check PHP allow_url_include option:
 PHP-2379:test:security:php::Check PHP suhosin extension status:
 PHP-2382:test:security:php::Check PHP listen option:
+PKGS-7200:test:security:ports_packages:Linux:Check Alpine Package Keeper (apk):
 PKGS-7301:test:security:ports_packages::Query NetBSD pkg:
 PKGS-7302:test:security:ports_packages::Query FreeBSD/NetBSD pkg_info:
 PKGS-7303:test:security:ports_packages::Query brew package manager:
@@ -358,6 +360,7 @@ PKGS-7390:test:security:ports_packages:Linux:Check Ubuntu database consistency:
 PKGS-7392:test:security:ports_packages:Linux:Check for Debian/Ubuntu security updates:
 PKGS-7393:test:security:ports_packages::Check for Gentoo vulnerable packages:
 PKGS-7394:test:security:ports_packages:Linux:Check for Ubuntu updates:
+PKGS-7395:test:security:ports_packages:Linux:Check Alpine upgradeable packages:
 PKGS-7398:test:security:ports_packages::Check for package audit tool:
 PKGS-7410:test:security:ports_packages::Count installed kernel packages:
 PKGS-7420:test:security:ports_packages::Detect toolkit to automatically download and apply upgrades:
diff --git a/debian/changelog b/debian/changelog
index 6e3bb55..2c4c265 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+lynis (3.0.7+git20220314.1.6475821-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Thu, 31 Mar 2022 14:49:28 -0000
+
 lynis (3.0.7-1) unstable; urgency=medium
 
   * NUR.
diff --git a/debian/patches/debian_plugin_diff b/debian/patches/debian_plugin_diff
index d28736e..286019d 100644
--- a/debian/patches/debian_plugin_diff
+++ b/debian/patches/debian_plugin_diff
@@ -1,9 +1,11 @@
 # Description: Added Debian plugin by default
 # Author: Francisco M. Garcia Claramonte <francisco@debian.org>
 # Last-Update: 26-05-2017
---- a/default.prf
-+++ b/default.prf
-@@ -144,6 +144,7 @@
+Index: lynis/default.prf
+===================================================================
+--- lynis.orig/default.prf
++++ lynis/default.prf
+@@ -144,6 +144,7 @@ plugin=software
  plugin=system-integrity
  plugin=systemd
  plugin=users
diff --git a/debian/patches/disable_version_check.patch b/debian/patches/disable_version_check.patch
index f441751..1d1f05b 100644
--- a/debian/patches/disable_version_check.patch
+++ b/debian/patches/disable_version_check.patch
@@ -2,9 +2,11 @@ Description: this version check is considered a privacy issue and disabled by de
 Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
 Forwarded: not-needed
 
---- a/default.prf
-+++ b/default.prf
-@@ -90,7 +90,7 @@
+Index: lynis/default.prf
+===================================================================
+--- lynis.orig/default.prf
++++ lynis/default.prf
+@@ -90,7 +90,7 @@ skip-plugins=no
  #skip-test=SSH-7408:permitrootlogin
  
  # Skip Lynis upgrade availability test (default: no)
diff --git a/include/binaries b/include/binaries
index fb8147c..7aabba4 100644
--- a/include/binaries
+++ b/include/binaries
@@ -134,6 +134,7 @@
                             aide)                   AIDEBINARY=${BINARY};              LogText "  Found known binary: aide (file integrity checker) - ${BINARY}" ;;
                             apache2)                HTTPDBINARY=${BINARY};             LogText "  Found known binary: apache2 (web server) - ${BINARY}" ;;
                             apt)                    APTBINARY=${BINARY};               LogText "  Found known binary: apt (package manager) - ${BINARY}" ;;
+                            apk)                    APKBINARY=${BINARY};               LogText "  Found known binary: apk (package manager) - ${BINARY}" ;;
                             arch-audit)             ARCH_AUDIT_BINARY="${BINARY}";     LogText "  Found known binary: arch-audit (auditing utility to test for vulnerable packages) - ${BINARY}" ;;
                             auditd)                 AUDITDBINARY=${BINARY};            LogText "  Found known binary: auditd (audit framework) - ${BINARY}" ;;
                             awk)                    AWKBINARY=${BINARY};               LogText "  Found known binary: awk (string tool) - ${BINARY}" ;;
diff --git a/include/consts b/include/consts
index 1dc3f89..5d61842 100644
--- a/include/consts
+++ b/include/consts
@@ -43,6 +43,7 @@ ETC_PATHS="/etc /usr/local/etc"
 # == Variable initializing ==
 #
     APTBINARY=""
+    APKBINARY=""
     ARCH_AUDIT_BINARY=""
     AUDITORNAME=""
     AUDITCTLBINARY=""
diff --git a/include/functions b/include/functions
index 6c4d76c..5b21170 100644
--- a/include/functions
+++ b/include/functions
@@ -1306,6 +1306,11 @@
         if [ $# -ne 2 ]; then Fatal "Incorrect usage of HasCorrectFilePermissions"; fi
         CHECKFILE="$1"
         CHECKPERMISSION_FULL="$2"
+        # Check for symlink
+        if [ -L ${CHECKFILE} ]; then
+            ShowSymlinkPath ${CHECKFILE}
+            if [ ! "${SYMLINK}" = "" ]; then CHECKFILE="${SYMLINK}"; fi
+        fi
         if [ ! -d ${CHECKFILE} -a ! -f ${CHECKFILE} ]; then
             return 2
         else
@@ -1320,9 +1325,8 @@
                 CHECK_PERMISSION=$(echo "${CHECK_PERMISSION}" | ${AWKBINARY} '{printf "%03d",$1}')
 
                 # First try stat command
-                LogText "Test: checking if file ${CHECKFILE} has the permissions set to ${CHECK_PERMISSION} or more restrictive"
+                LogText "Test: checking if file ${CHECKFILE} has the permissions set to ${CHECK_PERMISSION} (${CHECKPERMISSION_FULL}) or more restrictive"
                 if [ -n "${STATBINARY}" ]; then
-
                     case ${OS} in
                         *BSD | "macOS")
                             # BSD and macOS have no --format, only short notation
@@ -1388,7 +1392,7 @@
                 fi
             done
 
-            LogText "Outcome: permissions of file ${CHECKFILE} are not matching expected value (${DATA} != ${CHECKPERMISSION_FULL})"
+            LogText "Outcome: permissions of file ${CHECKFILE} are not matching expected value (${DATA} != ${CHECK_PERMISSION})"
             # No match, return exit code 1
             return 1
         fi
@@ -2002,7 +2006,11 @@
         if [ $# -eq 0 ]; then ExitFatal "Missing parameter when calling IsWorldWritable function"; fi
         sFILE=$1
         FileIsWorldWritable=""
-
+        # Check for symlink
+        if [ -L ${sFILE} ]; then
+            ShowSymlinkPath ${sFILE}
+            if [ ! "${SYMLINK}" = "" ]; then sFILE="${SYMLINK}"; fi
+        fi
         # Only check if target is a file or directory
         if [ -f ${sFILE} -o -d ${sFILE} ]; then
             FINDVAL=$(ls -ld ${sFILE} | cut -c 9)
@@ -2090,6 +2098,9 @@
         elif [ -n "${XBPSBINARY}" ]; then
             output=$(${XBPSBINARY} ${package} 2> /dev/null | ${GREPBINARY} "^ii")
             exit_code=$?
+        elif [ -n "${APKBINARY}" ]; then
+            output=$(${APKBINARY} search ${package} 2> /dev/null | ${GREPBINARY} ${package})
+            exit_code=$?
         else
             if [ "${package}" != "__dummy__" ]; then
                 ReportException "PackageIsInstalled:01 (test=${TEST_NO:-unknown})"
diff --git a/include/osdetection b/include/osdetection
index c91c69e..d9b8a41 100644
--- a/include/osdetection
+++ b/include/osdetection
@@ -678,7 +678,7 @@
                         ReportException "OS Detection" "Unknown OS found in /etc/os-release - Please create issue on GitHub project page: ${PROGRAM_SOURCE}"
                         ;;
                 esac
-            elif [ "$(uname -o 2> /dev/null)" == "illumos" ]; then
+            elif [ "$(uname -o 2> /dev/null)" = "illumos" ]; then
                 OPENSOLARIS=1
         
                 # Solaris has a free form text file with release information
diff --git a/include/tests_authentication b/include/tests_authentication
index 1718f99..0552d64 100644
--- a/include/tests_authentication
+++ b/include/tests_authentication
@@ -25,7 +25,7 @@
     LDAP_AUTH_ENABLED=0
     LDAP_PAM_ENABLED=0
     LDAP_CONF_LOCATIONS="${ROOTDIR}etc/ldap.conf ${ROOTDIR}etc/ldap/ldap.conf ${ROOTDIR}etc/openldap/ldap.conf ${ROOTDIR}usr/local/etc/ldap.conf ${ROOTDIR}usr/local/etc/openldap/ldap.conf"
-    PAM_FILE_LOCATIONS="${ROOTDIR}lib/arm-linux-gnueabihf/security ${ROOTDIR}lib/i386-linux-gnu/security ${ROOTDIR}lib/security ${ROOTDIR}lib/x86_64-linux-gnu/security ${ROOTDIR}lib64/security ${ROOTDIR}usr/lib /usr/lib/security"
+    PAM_FILE_LOCATIONS="${ROOTDIR}usr/lib/aarch64-linux-gnu/security ${ROOTDIR}lib/arm-linux-gnueabihf/security ${ROOTDIR}lib/i386-linux-gnu/security ${ROOTDIR}lib/security ${ROOTDIR}lib/x86_64-linux-gnu/security ${ROOTDIR}lib64/security ${ROOTDIR}usr/lib /usr/lib/security"
     SUDOERS_LOCATIONS="${ROOTDIR}etc/sudoers ${ROOTDIR}usr/local/etc/sudoers ${ROOTDIR}usr/pkg/etc/sudoers"
     SUDOERS_FILE=""
 #
@@ -607,7 +607,7 @@
                     Display --indent 4 --text "- Permissions for directory: ${SUDOERS_D}" --result "${STATUS_WARNING}" --color RED
                     ;;
             esac
-            SUDO_CONFIG_FILES="${SUDO_CONFIG_FILES} $(${FINDBINARY} ${SUDOERS_D} -type f -print)"
+            SUDO_CONFIG_FILES="${SUDO_CONFIG_FILES} $(${FINDBINARY} -L ${SUDOERS_D} -type f -print)"
         fi
         for f in ${SUDO_CONFIG_FILES}; do
             LogText "Test: checking file (${f})"
@@ -764,7 +764,7 @@
             LogText "Result: directory /etc/pam.d exists"
             Display --indent 2 --text "- PAM configuration files (pam.d)" --result "${STATUS_FOUND}" --color GREEN
             LogText "Test: searching PAM configuration files"
-            FIND=$(${FINDBINARY} ${ROOTDIR}etc/pam.d \! -name "*.pam-old" -type f -print | sort)
+            FIND=$(${FINDBINARY} -L ${ROOTDIR}etc/pam.d \! -name "*.pam-old" -type f -print | sort)
             for FILE in ${FIND}; do
                 LogText "Found file: ${FILE}"
             done
@@ -1533,31 +1533,49 @@
     # Description : Logging of failed login attempts
     Register --test-no AUTH-9408 --weight L --network NO --category security --description "Logging of failed login attempts"
     if [ ${SKIPTEST} -eq 0 ]; then
-        if [ -f "${ROOTDIR}etc/pam.conf" ]; then
+        if [ -f "${ROOTDIR}etc/pam.conf" -o -d "${ROOTDIR}etc/pam.d" ]; then
             FOUND_PAM_TALLY2=0
             FOUND_TALLYLOG=0
-            if [ -s "${ROOTDIR}var/log/tallylog" ]; then
+            FOUND_PAM_FAILLOCK=0
+            FOUND_FAILLOCKDIR=0
+            if [ -d "${ROOTDIR}var/run/faillock" ]; then
+                FOUND_FAILLOCKDIR=1
+                LogText "Result: found ${ROOTDIR}var/run/faillock directory"
+            elif [ -s "${ROOTDIR}var/log/tallylog" ]; then
                 FOUND_TALLYLOG=1
                 LogText "Result: found ${ROOTDIR}var/log/tallylog with a size bigger than zero"
             else
-                LogText "Result: did not find ${ROOTDIR}var/log/tallylog on disk or its file size is zero bytes"
+                LogText "Result: did not find ${ROOTDIR}var/run/faillock directory or ${ROOTDIR}var/log/tallylog file on disk or its file size is zero bytes"
             fi
-            # Determine if pam_tally2 is available
+            # Determine if pam_faillock is available
             for D in $(GetReportData --key "pam_module\\\[\\\]"); do
-                if ContainsString "pam_tally2" "${D}"; then
-                    LogText "Result: found pam_tally2 module on disk"
-                    FOUND_PAM_TALLY2=1
+                if ContainsString "pam_faillock" "${D}"; then
+                    LogText "Result: found pam_faillock module on disk"
+                    FOUND_PAM_FAILLOCK=1
                 fi
             done
-            if [ ${FOUND_PAM_TALLY2} -eq 1 -a ${FOUND_TALLYLOG} -eq 1 ]; then
+            if [ ${FOUND_PAM_FAILLOCK} -eq 0 ]; then
+                # Determine if pam_tally2 is available
+                for D in $(GetReportData --key "pam_module\\\[\\\]"); do
+                    if ContainsString "pam_tally2" "${D}"; then
+                        LogText "Result: found pam_tally2 module on disk"
+                        FOUND_PAM_TALLY2=1
+                    fi
+                done
+            fi
+            if [ ${FOUND_PAM_FAILLOCK} -eq 1 -a ${FOUND_FAILLOCKDIR} -eq 1 ]; then
+                LogText "Outcome: authentication failures are logged using pam_faillock"
+                AUTH_FAILED_LOGINS_LOGGED=1
+                Report "auth_failed_logins_tooling[]=pam_faillock"
+            elif [ ${FOUND_PAM_TALLY2} -eq 1 -a ${FOUND_TALLYLOG} -eq 1 ]; then
                 LogText "Outcome: authentication failures are logged using pam_tally2"
                 AUTH_FAILED_LOGINS_LOGGED=1
                 Report "auth_failed_logins_tooling[]=pam_tally2"
             else
-                LogText "Outcome: it looks like pam_tally2 is not configured to log failed login attempts"
+                LogText "Outcome: it looks like pam_faillock or pam_tally2 is not configured to log failed login attempts"
             fi
 
-            unset FOUND_PAM_TALLY2 FOUND_TALLYLOG
+            unset FOUND_PAM_TALLY2 FOUND_TALLYLOG FOUND_PAM_FAILLOCK FOUND_FAILLOCKDIR
         fi
         # Also check /etc/logins.defs, although its usage decreased over the years
         if [ -f ${ROOTDIR}etc/login.defs ]; then
diff --git a/include/tests_boot_services b/include/tests_boot_services
index 4a5fb3d..5901cd7 100644
--- a/include/tests_boot_services
+++ b/include/tests_boot_services
@@ -347,7 +347,7 @@
         FOUND=0
 
         if [ -d "${ROOTDIR}etc/grub.d" ]; then
-            CONF_FILES=$(${FINDBINARY} "${ROOTDIR}etc/grub.d" -type f -name "[0-9][0-9]*" -print0 | ${TRBINARY} '\0' ' ' | ${TRBINARY} -d '[:cntrl:]')
+            CONF_FILES=$(${FINDBINARY} -L "${ROOTDIR}etc/grub.d" -type f -name "[0-9][0-9]*" -print0 | ${TRBINARY} '\0' ' ' | ${TRBINARY} -d '[:cntrl:]')
             CONF_FILES="${GRUBCONFFILE} ${ROOTDIR}boot/grub/custom.cfg ${CONF_FILES}"
         else
             CONF_FILES="${GRUBCONFFILE} ${ROOTDIR}boot/grub/custom.cfg"
@@ -785,7 +785,7 @@
             if [ -d ${DIR} ]; then
                 LogText "Result: directory ${DIR} found"
                 LogText "Test: checking for available files in directory"
-                FIND=$(${FINDBINARY} ${DIR} -type f -print | ${SORTBINARY})
+                FIND=$(${FINDBINARY} -L ${DIR} -type f -print | ${SORTBINARY})
                 if [ -n "${FIND}" ]; then
                     LogText "Result: found files in directory, checking permissions now"
                     for FILE in ${FIND}; do
@@ -809,7 +809,7 @@
         for NO in 0 1 2 3 4 5 6; do
             LogText "Test: Checking ${ROOTDIR}etc/rc${NO}.d scripts for writable bit"
             if [ -d ${ROOTDIR}etc/rc${NO}.d ]; then
-                FIND=$(${FINDBINARY} ${ROOTDIR}etc/rc${NO}.d -type f -print | ${SORTBINARY})
+                FIND=$(${FINDBINARY} -L ${ROOTDIR}etc/rc${NO}.d -type f -print | ${SORTBINARY})
                 for I in ${FIND}; do
                     if IsWorldWritable ${I}; then
                         FOUND=1
@@ -1017,7 +1017,7 @@
             LogText "Result: directory ${DIR} found"
             LogText "Test: checking for available files in directory"
             # OpenBSD uses symlinks to create another instance of daemons
-            FIND=$(${FINDBINARY} ${CHECKDIR} \( -type f -o -type l \) -print | ${SORTBINARY})
+            FIND=$(${FINDBINARY} -L ${CHECKDIR} -type f -print | ${SORTBINARY})
             if [ -n "${FIND}" ]; then
                 LogText "Result: found files in directory, checking permissions now"
                 for FILE in ${FIND}; do
diff --git a/include/tests_databases b/include/tests_databases
index 9a8755b..f5bc22a 100644
--- a/include/tests_databases
+++ b/include/tests_databases
@@ -204,7 +204,7 @@
     Register --test-no DBS-1828 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Test PostgreSQL configuration"
     if [ ${SKIPTEST} -eq 0 ]; then
         FIND_PATHS="${ROOTDIR}etc/postgres ${ROOTDIR}var/lib/postgres/data ${ROOTDIR}usr/local/pgsql/data"
-        CONFIG_FILES=$(${FINDBINARY} ${FIND_PATHS} -type f -name "*.conf" -print0 2> /dev/null | ${TRBINARY} -cd '[:print:]\0' | ${TRBINARY} -d '\n' | ${TRBINARY} '\0' '\n' | xargs -i sh -c 'test -r "{}" && echo "{}"' | ${SEDBINARY} "s/ /:space:/g")
+        CONFIG_FILES=$(${FINDBINARY} -L ${FIND_PATHS} -type f -name "*.conf" -print0 2> /dev/null | ${TRBINARY} -cd '[:print:]\0' | ${TRBINARY} -d '\n' | ${TRBINARY} '\0' '\n' | xargs -i sh -c 'test -r "{}" && echo "{}"' | ${SEDBINARY} "s/ /:space:/g")
         for CF in ${CONFIG_FILES}; do
             Report "postgresql_config_file[]=${CF}"
             LogText "Found configuration file (${CF})"
diff --git a/include/tests_kernel b/include/tests_kernel
index 610fd32..ad914bf 100644
--- a/include/tests_kernel
+++ b/include/tests_kernel
@@ -368,14 +368,14 @@
 #
     # Test        : KRNL-5788
     # Description : Checking availability new kernel
-    if [ "${LINUX_VERSION}" = "Debian" ] || [ "${LINUX_VERSION}" = "Ubuntu" ] ||
-           [ "${LINUX_VERSION_LIKE}" = "Debian" ] || [ "${LINUX_VERSION_LIKE}" = "Ubuntu" ]; then
+    if [ "${LINUX_VERSION}" = "Debian" ] || [ "${LINUX_VERSION}" = "Ubuntu" ] || [ "${LINUX_VERSION_LIKE}" = "Debian" ] || [ "${LINUX_VERSION_LIKE}" = "Ubuntu" ]; then
         PREQS_MET="YES"
     else
         PREQS_MET="NO"
     fi
     Register --test-no KRNL-5788 --os Linux --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Checking availability new Linux kernel"
     if [ ${SKIPTEST} -eq 0 ]; then
+        FINDKERNEL=""
         HAS_VMLINUZ=0
         LogText "Test: Searching apt-cache, to determine if a newer kernel is available"
         if [ -x ${ROOTDIR}usr/bin/apt-cache ]; then
@@ -384,62 +384,69 @@
             if [ -f ${ROOTDIR}vmlinuz -o -f ${ROOTDIR}boot/vmlinuz ]; then
                 HAS_VMLINUZ=1
                 if [ -f ${ROOTDIR}vmlinuz ]; then
-                    FINDVMLINUZ=${ROOTDIR}vmlinuz
+                    FINDVMLINUZ="${ROOTDIR}vmlinuz"
                 else
-                    FINDVMLINUZ=${ROOTDIR}boot/vmlinuz
+                    FINDVMLINUZ="${ROOTDIR}boot/vmlinuz"
                 fi
                 LogText "Result: found ${FINDVMLINUZ}"
                 LogText "Test: checking readlink location of ${FINDVMLINUZ}"
                 FINDKERNFILE=$(readlink -f ${FINDVMLINUZ})
                 LogText "Output: readlink reported file ${FINDKERNFILE}"
-                LogText "Test: checking package from dpkg -S"
+                LogText "Test: checking relevant package using output from dpkg -S"
                 FINDKERNEL=$(dpkg -S ${FINDKERNFILE} 2> /dev/null | ${AWKBINARY} -F : '{print $1}')
                 LogText "Output: dpkg -S reported package ${FINDKERNEL}"
             elif [ -e ${ROOTDIR}dev/grsec ]; then
-                FINDKERNEL=linux-image-$(uname -r)
+                FINDKERNEL="linux-image-$(uname -r)"
                 LogText "Result: ${ROOTDIR}vmlinuz missing due to grsecurity; assuming ${FINDKERNEL}"
             elif [ -e ${ROOTDIR}etc/rpi-issue ]; then
-                FINDKERNEL=raspberrypi-kernel
+                FINDKERNEL="raspberrypi-kernel"
                 LogText "Result: ${ROOTDIR}vmlinuz missing due to Raspbian"
-            elif `${EGREPBINARY} -q 'do_symlinks.*=.*No' ${ROOTDIR}etc/kernel-img.conf`; then
-                FINDKERNEL=linux-image-$(uname -r)
+            elif $(${EGREPBINARY} -q 'do_symlinks.*=.*No' ${ROOTDIR}etc/kernel-img.conf); then
+                FINDKERNEL="linux-image-$(uname -r)"
                 LogText "Result: ${ROOTDIR}vmlinuz missing due to /etc/kernel-img.conf item do_symlinks = No"
             else
-                LogText "This system is missing ${ROOTDIR}vmlinuz or ${ROOTDIR}boot/vmlinuz.  Unable to check whether kernel is up-to-date."
+                LogText "This system is missing ${ROOTDIR}vmlinuz or ${ROOTDIR}boot/vmlinuz. Unable to check whether kernel is up-to-date."
                 ReportSuggestion "${TEST_NO}" "Determine why ${ROOTDIR}vmlinuz or ${ROOTDIR}boot/vmlinuz is missing on this Debian/Ubuntu system." "/vmlinuz or /boot/vmlinuz"
             fi
-            LogText "Test: Using apt-cache policy to determine if there is an update available"
-            FINDINST=$(apt-cache policy ${FINDKERNEL} | ${EGREPBINARY} 'Installed' | ${CUTBINARY} -d ':' -f2 | ${TRBINARY} -d ' ')
-            FINDCAND=$(apt-cache policy ${FINDKERNEL} | ${EGREPBINARY} 'Candidate' | ${CUTBINARY} -d ':' -f2 | ${TRBINARY} -d ' ')
-            LogText "Kernel installed: ${FINDINST}"
-            LogText "Kernel candidate: ${FINDCAND}"
-            if IsEmpty "${FINDINST}"; then
-                Display --indent 2 --text "- Checking for available kernel update" --result "${STATUS_UNKNOWN}" --color YELLOW
-                LogText "Result: Exception occurred, no output from apt-cache policy"
-                if [ ${HAS_VMLINUZ} -eq 1 ]; then
-                    ReportException "${TEST_NO}:01"
-                    ReportSuggestion "${TEST_NO}" "Check the output of apt-cache policy to determine why its output is empty"
-                fi
-                LogText "Result: apt-cache policy did not return an installed kernel version"
+
+            if IsEmpty "${FINDKERNEL}"; then
+                LogText "Result: could not check kernel update status as kernel is unknown"
             else
-                if [ "${FINDINST}" = "${FINDCAND}" ]; then
-                    if [ -e /dev/grsec ]; then
-                        Display --indent 2 --text "- Checking for available kernel update" --result GRSEC --color GREEN
-                        LogText "Result: Grsecurity is installed; unable to determine if there's a newer kernel available"
-                        ReportManual "Manually check to confirm you're using a recent kernel and grsecurity patch"
-                    else
-                        Display --indent 2 --text "- Checking for available kernel update" --result "${STATUS_OK}" --color GREEN
-                        LogText "Result: no kernel update available"
+                LogText "Result: found kernel '${FINDKERNEL}' which will be used for further testing"
+                LogText "Test: Using apt-cache policy to determine if there is an update available"
+                FINDINSTALLED=$(apt-cache policy ${FINDKERNEL} | ${EGREPBINARY} 'Installed' | ${CUTBINARY} -d ':' -f2 | ${TRBINARY} -d ' ')
+                FINDCANDIDATE=$(apt-cache policy ${FINDKERNEL} | ${EGREPBINARY} 'Candidate' | ${CUTBINARY} -d ':' -f2 | ${TRBINARY} -d ' ')
+                LogText "Kernel installed: ${FINDINSTALLED}"
+                LogText "Kernel candidate: ${FINDCANDIDATE}"
+                if IsEmpty "${FINDINSTALLED}"; then
+                    Display --indent 2 --text "- Checking for available kernel update" --result "${STATUS_UNKNOWN}" --color YELLOW
+                    LogText "Result: Exception occurred, no output from apt-cache policy"
+                    if [ ${HAS_VMLINUZ} -eq 1 ]; then
+                        ReportException "${TEST_NO}:01" "Found vmlinuz (${FINDVMLINUZ}) but could not determine the installed kernel using apt-cache policy"
+                        ReportSuggestion "${TEST_NO}" "Check the output of apt-cache policy to determine why its output is empty"
                     fi
+                    LogText "Result: apt-cache policy did not return an installed kernel version"
                 else
-                    Display --indent 2 --text "- Checking for available kernel update" --result "UPDATE AVAILABLE" --color YELLOW
-                    LogText "Result: kernel update available according 'apt-cache policy'."
-                    ReportSuggestion "${TEST_NO}" "Determine priority for available kernel update"
+                    if [ "${FINDINSTALLED}" = "${FINDCANDIDATE}" ]; then
+                        if [ -e /dev/grsec ]; then
+                            Display --indent 2 --text "- Checking for available kernel update" --result GRSEC --color GREEN
+                            LogText "Result: Grsecurity is installed; unable to determine if there's a newer kernel available"
+                            ReportManual "Manually check to confirm you're using a recent kernel and grsecurity patch"
+                        else
+                            Display --indent 2 --text "- Checking for available kernel update" --result "${STATUS_OK}" --color GREEN
+                            LogText "Result: no kernel update available"
+                        fi
+                    else
+                        Display --indent 2 --text "- Checking for available kernel update" --result "UPDATE AVAILABLE" --color YELLOW
+                        LogText "Result: kernel update available according 'apt-cache policy'."
+                        ReportSuggestion "${TEST_NO}" "Determine priority for available kernel update"
+                    fi
                 fi
             fi
         else
-            LogText "Result: could NOT find /usr/bin/apt-cache, skipped other tests."
+            LogText "Result: could NOT find ${ROOTDIR}usr/bin/apt-cache, skipped other tests."
         fi
+        unset FINDCANDIDATE FINDINSTALLED FINDKERNEL HAS_VMLINUZ
     fi
 #
 #################################################################################
@@ -463,9 +470,9 @@
             # check conf files in possibly existing coredump.conf.d folders 
             # using find instead of grep -r to stay POSIX compliant. On AIX and HPUX grep -r is not available.
             # while there could be multiple files overwriting each other, we are checking the number of occurrences
-            SYSD_CORED_SUB_PROCSIZEMAX_NR_DISABLED=$(${FINDBINARY} /etc/systemd/coredump.conf.d/ /run/systemd/coredump.conf.d/ /usr/lib/systemd/coredump.conf.d/ -type f -iname "*.conf" -exec ${SEDBINARY} 's/^ *//g' {} \; 2> /dev/null | ${GREPBINARY} -i "^ProcessSizeMax=" | ${CUTBINARY} -d'=' -f2 | ${SEDBINARY} 's/ .*$//g ; s/\([A-Z][a-z]*\)*$//g' | ${GREPBINARY} "^0 *$" | ${WCBINARY} -l)
-            SYSD_CORED_SUB_PROCSIZEMAX_NR_ENABLED=$(${FINDBINARY} /etc/systemd/coredump.conf.d/ /run/systemd/coredump.conf.d/ /usr/lib/systemd/coredump.conf.d/ -type f -iname "*.conf" -exec ${SEDBINARY} 's/^ *//g' {} \; 2> /dev/null | ${GREPBINARY} -i "^ProcessSizeMax=" | ${CUTBINARY} -d'=' -f2 | ${SEDBINARY} 's/ .*$//g ; s/\([A-Z][a-z]*\)*$//g' | ${GREPBINARY} -v "^0 *$" | ${WCBINARY} -l)
-            SYSD_CORED_SUB_STORAGE_FOUND=$(${FINDBINARY} /etc/systemd/coredump.conf.d/ /run/systemd/coredump.conf.d/ /usr/lib/systemd/coredump.conf.d/ -type f -iname "*.conf" -exec ${SEDBINARY} 's/^ *//g' {} \; 2> /dev/null | ${GREPBINARY} -i "^Storage=" | ${CUTBINARY} -d'=' -f2 | ${SEDBINARY} 's/ .*$//g')
+            SYSD_CORED_SUB_PROCSIZEMAX_NR_DISABLED=$(${FINDBINARY} -L /etc/systemd/coredump.conf.d/ /run/systemd/coredump.conf.d/ /usr/lib/systemd/coredump.conf.d/ -type f -iname "*.conf" -exec ${SEDBINARY} 's/^ *//g' {} \; 2> /dev/null | ${GREPBINARY} -i "^ProcessSizeMax=" | ${CUTBINARY} -d'=' -f2 | ${SEDBINARY} 's/ .*$//g ; s/\([A-Z][a-z]*\)*$//g' | ${GREPBINARY} "^0 *$" | ${WCBINARY} -l)
+            SYSD_CORED_SUB_PROCSIZEMAX_NR_ENABLED=$(${FINDBINARY} -L /etc/systemd/coredump.conf.d/ /run/systemd/coredump.conf.d/ /usr/lib/systemd/coredump.conf.d/ -type f -iname "*.conf" -exec ${SEDBINARY} 's/^ *//g' {} \; 2> /dev/null | ${GREPBINARY} -i "^ProcessSizeMax=" | ${CUTBINARY} -d'=' -f2 | ${SEDBINARY} 's/ .*$//g ; s/\([A-Z][a-z]*\)*$//g' | ${GREPBINARY} -v "^0 *$" | ${WCBINARY} -l)
+            SYSD_CORED_SUB_STORAGE_FOUND=$(${FINDBINARY} -L /etc/systemd/coredump.conf.d/ /run/systemd/coredump.conf.d/ /usr/lib/systemd/coredump.conf.d/ -type f -iname "*.conf" -exec ${SEDBINARY} 's/^ *//g' {} \; 2> /dev/null | ${GREPBINARY} -i "^Storage=" | ${CUTBINARY} -d'=' -f2 | ${SEDBINARY} 's/ .*$//g')
             SYSD_CORED_SUB_STORAGE_NR_ENABLED=$(${ECHOCMD} "${SYSD_CORED_SUB_STORAGE_FOUND}" | ${SEDBINARY} 's/none//g' | ${WCBINARY} | ${AWKBINARY} '{print $2}')
             SYSD_CORED_SUB_STORAGE_NR_DISABLED=$(${ECHOCMD} "${SYSD_CORED_SUB_STORAGE_FOUND}" | ${GREPBINARY} -o "none" | ${WCBINARY} | ${AWKBINARY} '{print $2}')
             if ( [ ${SYSD_CORED_BASE_PROCSIZEMAX_NR_DISABLED} -ge 1 ] && [ ${SYSD_CORED_BASE_STORAGE_NR_DISABLED} -ge 1 ] && [ ${SYSD_CORED_SUB_PROCSIZEMAX_NR_ENABLED} -eq 0 ] && [ ${SYSD_CORED_SUB_STORAGE_NR_ENABLED} -eq 0 ] ) || \
@@ -506,81 +513,84 @@
             LogText "Test: Checking if 'ulimit -c 0' exists in ${ROOTDIR}etc/profile or ${ROOTDIR}etc/profile.d/*.sh"
             # use tail -1 in the following commands to get the last entry, which is the one that counts (in case of profile.d/ probably counts)
             ULIMIT_C_VALUE="$(${GREPBINARY} "ulimit -c " ${ROOTDIR}etc/profile 2> /dev/null | ${SEDBINARY} 's/^ *//g' | ${GREPBINARY} -v "^#" | ${TAILBINARY} -1 | ${CUTBINARY} -d' ' -f3 | ${SEDBINARY} 's/ .*$//g ; s/\([A-Z][a-z]*\)*$//g')"
-            ULIMIT_C_VALUE_SUB="$(${FINDBINARY} ${ROOTDIR}etc/profile.d -name "*.sh" -type f -exec ${CAT_BINARY} {} \; 2> /dev/null | ${GREPBINARY} "ulimit -c " | ${SEDBINARY} 's/^ *//g' | ${GREPBINARY} -v "^#" | ${TAILBINARY} -1 | ${CUTBINARY} -d' ' -f3 | ${SEDBINARY} 's/ .*$//g ; s/\([A-Z][a-z]*\)*$//g')"
+            ULIMIT_C_VALUE_SUB="$(${FINDBINARY} -L ${ROOTDIR}etc/profile.d -name "*.sh" -type f -exec ${CAT_BINARY} {} \; 2> /dev/null | ${GREPBINARY} "ulimit -c " | ${SEDBINARY} 's/^ *//g' | ${GREPBINARY} -v "^#" | ${TAILBINARY} -1 | ${CUTBINARY} -d' ' -f3 | ${SEDBINARY} 's/ .*$//g ; s/\([A-Z][a-z]*\)*$//g')"
             if ( [ -n "${ULIMIT_C_VALUE_SUB}" ] && [ "${ULIMIT_C_VALUE_SUB}" = "0" ] ) || ( [ -n "${ULIMIT_C_VALUE}" ] && [ -z "${ULIMIT_C_VALUE_SUB}" ] && [ "${ULIMIT_C_VALUE}" = "0" ] ); then
                 LogText "Result: core dumps are disabled by 'ulimit -c 0' in ${ROOTDIR}etc/profile or ${ROOTDIR}etc/profile.d/*.sh"
                 Display --indent 4 --text "- configuration in etc/profile" --result "${STATUS_DISABLED}" --color GREEN
                 AddHP 1 1
             elif [ -z "${ULIMIT_C_VALUE_SUB}" ] && [ -z "${ULIMIT_C_VALUE}" ]; then
                 LogText "Result: core dumps are not disabled in ${ROOTDIR}etc/profile or ${ROOTDIR}etc/profile.d/*.sh config files. Didn't find setting 'ulimit -c 0'"
-                Display --indent 4 --text "- configuration in etc/profile" --result "${STATUS_DEFAULT}" --color WHITE
+                Display --indent 4 --text "- configuration in ${ROOTDIR}etc/profile" --result "${STATUS_DEFAULT}" --color WHITE
                 AddHP 0 1
             elif ( [ -n "${ULIMIT_C_VALUE_SUB}" ] && ( [ "${ULIMIT_C_VALUE_SUB}" = "unlimited" ] || [ "${ULIMIT_C_VALUE_SUB}" != "0" ] ) ) || ( [ -n "${ULIMIT_C_VALUE}" ] && [ -z "${ULIMIT_C_VALUE_SUB}" ] && ( [ "${ULIMIT_C_VALUE}" = "unlimited" ] || [ "${ULIMIT_C_VALUE}" != "0" ] ) ); then
                 LogText "Result: core dumps are enabled in ${ROOTDIR}etc/profile or ${ROOTDIR}etc/profile.d/*.sh config files. A value higher than 0 is configured for 'ulimit -c'"
-                Display --indent 4 --text "- configuration in etc/profile" --result "${STATUS_ENABLED}" --color RED
+                Display --indent 4 --text "- configuration in ${ROOTDIR}etc/profile" --result "${STATUS_ENABLED}" --color RED
                 AddHP 0 1
             else
                 LogText "Result: ERROR - something went wrong. Unexpected result during check of ${ROOTDIR}etc/profile and ${ROOTDIR}etc/profile.d/*.sh config files. Please report on Github!"
-                Display --indent 4 --text "- configuration in etc/profile" --result "${STATUS_ERROR}" --color YELLOW
+                Display --indent 4 --text "- configuration in ${ROOTDIR}etc/profile" --result "${STATUS_ERROR}" --color YELLOW
             fi
         fi
-        # Limits option
-        LogText "Test: Checking presence ${ROOTDIR}etc/security/limits.conf"
-        if [ -f "${ROOTDIR}etc/security/limits.conf" ]; then
-            LogText "Result: file ${ROOTDIR}etc/security/limits.conf exists"
-            LogText "Test: Checking if core dumps are disabled in ${ROOTDIR}etc/security/limits.conf and ${LIMITS_DIRECTORY}/*"
-            # using find instead of grep -r to stay POSIX compliant. On AIX and HPUX grep -r is not available.
-            FIND1=$(${FINDBINARY} "${ROOTDIR}etc/security/limits.conf" "${LIMITS_DIRECTORY}" -type f -exec ${CAT_BINARY} {} \; 2> /dev/null | ${GREPBINARY} -v "^$" | ${AWKBINARY} '{ if ($1=="*" && $2=="soft" && $3=="core" && $4=="0") { print "soft core disabled" } else if ($1=="*" && $2=="soft" && $3=="core" && $4!="0") { print "soft core enabled" } }' | ${TAILBINARY} -1)
-            FIND2=$(${FINDBINARY} "${ROOTDIR}etc/security/limits.conf" "${LIMITS_DIRECTORY}" -type f -exec ${CAT_BINARY} {} \; 2> /dev/null | ${GREPBINARY} -v "^$" | ${AWKBINARY} '{ if ($1=="*" && $2=="hard" && $3=="core" && $4=="0") { print "hard core disabled" } else if ($1=="*" && $2=="hard" && $3=="core" && $4!="0") { print "hard core enabled" } }' | ${TAILBINARY} -1)
-            FIND3=$(${FINDBINARY} "${ROOTDIR}etc/security/limits.conf" "${LIMITS_DIRECTORY}" -type f -exec ${CAT_BINARY} {} \; 2> /dev/null | ${GREPBINARY} -v "^$" | ${AWKBINARY} '{ if ($1=="*" && $2=="-" && $3=="core" && $4=="0") { print "core dumps disabled" } else if ($1=="*" && $2=="-" && $3=="core" && $4!="0") { print "core dumps enabled" } }' | ${TAILBINARY} -1)
+        
+        # Limits options
+        for DIR in "/" "/usr/"; do
+            LogText "Test: Checking presence ${DIR}etc/security/limits.conf"
+            if [ -f "${DIR}etc/security/limits.conf" ]; then
+                LogText "Result: file ${DIR}etc/security/limits.conf exists"
+                LogText "Test: Checking if core dumps are disabled in ${DIR}etc/security/limits.conf and ${LIMITS_DIRECTORY}/*"
+                # using find instead of grep -r to stay POSIX compliant. On AIX and HPUX grep -r is not available.
+                FIND1=$(${FINDBINARY} -L "${DIR}etc/security/limits.conf" "${LIMITS_DIRECTORY}" -type f -exec ${CAT_BINARY} {} \; 2> /dev/null | ${GREPBINARY} -v "^$" | ${AWKBINARY} '{ if ($1=="*" && $2=="soft" && $3=="core" && $4=="0") { print "soft core disabled" } else if ($1=="*" && $2=="soft" && $3=="core" && $4!="0") { print "soft core enabled" } }' | ${TAILBINARY} -1)
+                FIND2=$(${FINDBINARY} -L "${DIR}etc/security/limits.conf" "${LIMITS_DIRECTORY}" -type f -exec ${CAT_BINARY} {} \; 2> /dev/null | ${GREPBINARY} -v "^$" | ${AWKBINARY} '{ if ($1=="*" && $2=="hard" && $3=="core" && $4=="0") { print "hard core disabled" } else if ($1=="*" && $2=="hard" && $3=="core" && $4!="0") { print "hard core enabled" } }' | ${TAILBINARY} -1)
+                FIND3=$(${FINDBINARY} -L "${DIR}etc/security/limits.conf" "${LIMITS_DIRECTORY}" -type f -exec ${CAT_BINARY} {} \; 2> /dev/null | ${GREPBINARY} -v "^$" | ${AWKBINARY} '{ if ($1=="*" && $2=="-" && $3=="core" && $4=="0") { print "core dumps disabled" } else if ($1=="*" && $2=="-" && $3=="core" && $4!="0") { print "core dumps enabled" } }' | ${TAILBINARY} -1)
 
-            # When "* - core [value]" is used, then this sets both soft and core. In that case we set the values, as they the type 'hard' and 'soft' will not be present in the configuration file.
-            if [ "${FIND3}" = "core dumps disabled" ]; then
-                FIND1="soft core disabled"
-                FIND2="hard core disabled"
-            elif [ "${FIND3}" = "core dumps enabled" ]; then
-                FIND1="soft core enabled"
-                FIND2="hard core enabled"
-            fi
+                # When "* - core [value]" is used, then this sets both soft and core. In that case we set the values, as they the type 'hard' and 'soft' will not be present in the configuration file.
+                if [ "${FIND3}" = "core dumps disabled" ]; then
+                    FIND1="soft core disabled"
+                    FIND2="hard core disabled"
+                elif [ "${FIND3}" = "core dumps enabled" ]; then
+                    FIND1="soft core enabled"
+                    FIND2="hard core enabled"
+                fi
 
-            IS_SOFTCORE_DISABLED="$(if [ "${FIND1}" = "soft core disabled" ]; then ${ECHOCMD} DISABLED; elif [ "${FIND1}" = "soft core enabled" ]; then ${ECHOCMD} ENABLED; else ${ECHOCMD} ${STATUS_DEFAULT}; fi)"
-            IS_HARDCORE_DISABLED="$(if [ "${FIND2}" = "hard core disabled" ]; then ${ECHOCMD} DISABLED; elif [ "${FIND2}" = "hard core enabled" ]; then ${ECHOCMD} ENABLED; else ${ECHOCMD} ${STATUS_DEFAULT}; fi)"
+                IS_SOFTCORE_DISABLED="$(if [ "${FIND1}" = "soft core disabled" ]; then ${ECHOCMD} DISABLED; elif [ "${FIND1}" = "soft core enabled" ]; then ${ECHOCMD} ENABLED; else ${ECHOCMD} ${STATUS_DEFAULT}; fi)"
+                IS_HARDCORE_DISABLED="$(if [ "${FIND2}" = "hard core disabled" ]; then ${ECHOCMD} DISABLED; elif [ "${FIND2}" = "hard core enabled" ]; then ${ECHOCMD} ENABLED; else ${ECHOCMD} ${STATUS_DEFAULT}; fi)"
 
-            if [ "${FIND2}" = "hard core disabled" ]; then
-                LogText "Result: core dumps are hard disabled"
-                Display --indent 4 --text "- 'hard' configuration in security/limits.conf" --result "${IS_HARDCORE_DISABLED}" --color "GREEN"
-                if [ "${FIND1}" = "soft core disabled" ]; then
-                    Display --indent 4 --text "- 'soft' configuration in security/limits.conf" --result "${IS_SOFTCORE_DISABLED}" --color "GREEN"
+                if [ "${FIND2}" = "hard core disabled" ]; then
+                    LogText "Result: core dumps are hard disabled"
+                    Display --indent 4 --text "- 'hard' configuration in ${DIR}etc/security/limits.conf" --result "${IS_HARDCORE_DISABLED}" --color "GREEN"
+                    if [ "${FIND1}" = "soft core disabled" ]; then
+                        Display --indent 4 --text "- 'soft' configuration in ${DIR}etc/security/limits.conf" --result "${IS_SOFTCORE_DISABLED}" --color "GREEN"
+                    else
+                        Display --indent 4 --text "- 'soft' config in ${DIR}etc/security/limits.conf (implicit)" --result "${STATUS_DISABLED}" --color "GREEN"
+                    fi
+                    AddHP 3 3
+                elif [ "${FIND1}" = "soft core enabled" ] && [ "${FIND2}" = "hard core enabled" ]; then
+                    LogText "Result: core dumps (soft and hard) are enabled"
+                    Display --indent 4 --text "- 'hard' configuration in ${DIR}etc/security/limits.conf" --result "${STATUS_ENABLED}" --color "RED"
+                    Display --indent 4 --text "- 'soft' configuration in ${DIR}etc/security/limits.conf" --result "${STATUS_ENABLED}" --color "RED"
+                    ReportSuggestion "${TEST_NO}" "If not required, consider explicit disabling of core dump in /etc/security/limits.conf file"
+                    AddHP 0 3
+                elif [ "${FIND1}" = "soft core disabled" ]; then
+                    LogText "Result: core dumps are disabled for 'soft' ('hard'=${IS_HARDCORE_DISABLED})"
+                    Display --indent 4 --text "- 'hard' configuration in ${DIR}etc/security/limits.conf" --result "${IS_HARDCORE_DISABLED}" --color "$(if [ "${IS_HARDCORE_DISABLED}" = "ENABLED" ]; then ${ECHOCMD} RED; elif [ "${IS_HARDCORE_DISABLED}" = "DISABLED" ]; then ${ECHOCMD} GREEN; else ${ECHOCMD} WHITE; fi)"
+                    Display --indent 4 --text "- 'soft' configuration in ${DIR}etc/security/limits.conf" --result "${IS_SOFTCORE_DISABLED}" --color "GREEN"
+                    AddHP 2 3
+                elif [ "${FIND1}" = "soft core enabled" ] || [ "${FIND2}" = "hard core enabled" ]; then
+                    LogText "Result: core dumps are partially enabled ('hard'=${IS_HARDCORE_DISABLED}, 'soft'=${IS_SOFTCORE_DISABLED})"
+                    Display --indent 4 --text "- 'hard' configuration in ${DIR}etc/security/limits.conf" --result "${IS_HARDCORE_DISABLED}" --color "$(if [ "${IS_HARDCORE_DISABLED}" = "ENABLED" ]; then ${ECHOCMD} RED; elif [ "${IS_HARDCORE_DISABLED}" = "DISABLED" ]; then ${ECHOCMD} GREEN; else ${ECHOCMD} WHITE; fi)"
+                    Display --indent 4 --text "- 'soft' configuration in ${DIR}etc/security/limits.conf" --result "${IS_SOFTCORE_DISABLED}" --color "$(if [ "${IS_SOFTCORE_DISABLED}" = "ENABLED" ]; then ${ECHOCMD} RED; elif [ "${IS_SOFTCORE_DISABLED}" = "DISABLED" ]; then ${ECHOCMD} GREEN; else ${ECHOCMD} WHITE; fi)"
+                    AddHP 0 3
                 else
-                    Display --indent 4 --text "- 'soft' config in security/limits.conf (implicit)" --result "${STATUS_DISABLED}" --color "GREEN"
+                    LogText "Result: core dumps are not explicitly disabled"
+                    Display --indent 4 --text "- 'hard' configuration in ${DIR}etc/security/limits.conf" --result "${IS_HARDCORE_DISABLED}" --color "WHITE"
+                    Display --indent 4 --text "- 'soft' configuration in ${DIR}etc/security/limits.conf" --result "${IS_HARDCORE_DISABLED}" --color "WHITE"
+                    ReportSuggestion "${TEST_NO}" "If not required, consider explicit disabling of core dump in ${DIR}etc/security/limits.conf file"
+                    AddHP 1 3
                 fi
-                AddHP 3 3
-            elif [ "${FIND1}" = "soft core enabled" ] && [ "${FIND2}" = "hard core enabled" ]; then
-                LogText "Result: core dumps (soft and hard) are enabled"
-                Display --indent 4 --text "- 'hard' configuration in security/limits.conf" --result "${STATUS_ENABLED}" --color "RED"
-                Display --indent 4 --text "- 'soft' configuration in security/limits.conf" --result "${STATUS_ENABLED}" --color "RED"
-                ReportSuggestion "${TEST_NO}" "If not required, consider explicit disabling of core dump in /etc/security/limits.conf file"
-                AddHP 0 3
-            elif [ "${FIND1}" = "soft core disabled" ]; then
-                LogText "Result: core dumps are disabled for 'soft' ('hard'=${IS_HARDCORE_DISABLED})"
-                Display --indent 4 --text "- 'hard' configuration in security/limits.conf" --result "${IS_HARDCORE_DISABLED}" --color "$(if [ "${IS_HARDCORE_DISABLED}" = "ENABLED" ]; then ${ECHOCMD} RED; elif [ "${IS_HARDCORE_DISABLED}" = "DISABLED" ]; then ${ECHOCMD} GREEN; else ${ECHOCMD} WHITE; fi)"
-                Display --indent 4 --text "- 'soft' configuration in security/limits.conf" --result "${IS_SOFTCORE_DISABLED}" --color "GREEN"
-                AddHP 2 3
-            elif [ "${FIND1}" = "soft core enabled" ] || [ "${FIND2}" = "hard core enabled" ]; then
-                LogText "Result: core dumps are partially enabled ('hard'=${IS_HARDCORE_DISABLED}, 'soft'=${IS_SOFTCORE_DISABLED})"
-                Display --indent 4 --text "- 'hard' configuration in security/limits.conf" --result "${IS_HARDCORE_DISABLED}" --color "$(if [ "${IS_HARDCORE_DISABLED}" = "ENABLED" ]; then ${ECHOCMD} RED; elif [ "${IS_HARDCORE_DISABLED}" = "DISABLED" ]; then ${ECHOCMD} GREEN; else ${ECHOCMD} WHITE; fi)"
-                Display --indent 4 --text "- 'soft' configuration in security/limits.conf" --result "${IS_SOFTCORE_DISABLED}" --color "$(if [ "${IS_SOFTCORE_DISABLED}" = "ENABLED" ]; then ${ECHOCMD} RED; elif [ "${IS_SOFTCORE_DISABLED}" = "DISABLED" ]; then ${ECHOCMD} GREEN; else ${ECHOCMD} WHITE; fi)"
-                AddHP 0 3
             else
-                LogText "Result: core dumps are not explicitly disabled"
-                Display --indent 4 --text "- 'hard' configuration in security/limits.conf" --result "${IS_HARDCORE_DISABLED}" --color "WHITE"
-                Display --indent 4 --text "- 'soft' configuration in security/limits.conf" --result "${IS_HARDCORE_DISABLED}" --color "WHITE"
-                ReportSuggestion "${TEST_NO}" "If not required, consider explicit disabling of core dump in ${ROOTDIR}etc/security/limits.conf file"
-                AddHP 1 3
+                LogText "Result: file ${DIR}etc/security/limits.conf does not exist, skipping test for this file"
             fi
-        else
-            LogText "Result: file ${ROOTDIR}etc/security/limits.conf does not exist, skipping test"
-        fi
+        done
 
         # Sysctl option
         LogText "Test: Checking sysctl value of fs.suid_dumpable"
@@ -615,25 +625,29 @@
     Register --test-no KRNL-5830 --os Linux --weight L --network NO --category security --description "Checking if system is running on the latest installed kernel"
     if [ ${SKIPTEST} -eq 0 ]; then
         REBOOT_NEEDED=2
-        FILE="${ROOTDIR}var/run/reboot-required.pkgs"
-        LogText "Test: Checking presence ${FILE}"
-        if [ -f ${FILE} ]; then
-            LogText "Result: file ${FILE} exists"
-            FIND=$(${WCBINARY} -l < ${FILE})
-            if [ "${FIND}" = "0" ]; then
-                LogText "Result: No reboot needed (file empty)"
-                REBOOT_NEEDED=0
+        for FILE in "${ROOTDIR}var/run/reboot-required.pkgs" "${ROOTDIR}var/run/needs_restarting"
+        do
+            LogText "Test: Checking presence ${FILE}"
+            if [ -f ${FILE} ]; then
+                LogText "Result: file ${FILE} exists"
+                FIND=$(${WCBINARY} -l < ${FILE})
+                if [ "${FIND}" = "0" ]; then
+                    LogText "Result: No reboot needed (file empty)"
+                    REBOOT_NEEDED=0
+                    break
+                else
+                    PKGSCOUNT=$(${WCBINARY} -l < ${FILE})
+                    LogText "Result: reboot is needed, related to ${PKGSCOUNT} packages"
+                    for I in ${FIND}; do
+                        LogText "Package: ${I}"
+                    done
+                    REBOOT_NEEDED=1
+                    break
+                fi
             else
-                PKGSCOUNT=$(${WCBINARY} -l < ${FILE})
-                LogText "Result: reboot is needed, related to ${PKGSCOUNT} packages"
-                for I in ${FIND}; do
-                    LogText "Package: ${I}"
-                done
-                REBOOT_NEEDED=1
+                LogText "Result: file ${FILE} not found"
             fi
-        else
-            LogText "Result: file ${FILE} not found"
-        fi
+        done
 
         # Check if /boot exists
         if [ -d "${ROOTDIR}boot" ]; then
@@ -663,7 +677,10 @@
                         ReportException "${TEST_NO}:1" "Can't determine kernel version on disk, need debug data"
                     fi
                 elif [ -f ${ROOTDIR}boot/vmlinuz-linux ] || [ -f ${ROOTDIR}boot/vmlinuz-linux-lts ] || [ -f "$(${LSBINARY} -t ${ROOTDIR}boot/vm[l0-9]* 2> /dev/null | ${HEADBINARY} -1)" ]; then
-                    if [ -f ${ROOTDIR}boot/vmlinuz-linux ]; then
+                    if [ -f ${ROOTDIR}boot/vmlinuz ]; then
+                          LogText "Result: found ${ROOTDIR}boot/vmlinuz"
+                          FOUND_VMLINUZ=${ROOTDIR}boot/vmlinuz
+                    elif [ -f ${ROOTDIR}boot/vmlinuz-linux ]; then
                         LogText "Result: found ${ROOTDIR}boot/vmlinuz-linux"
                         FOUND_VMLINUZ=${ROOTDIR}boot/vmlinuz-linux
                     elif [ -f ${ROOTDIR}boot/vmlinuz-linux-lts ]; then
diff --git a/include/tests_logging b/include/tests_logging
index 7b3c203..b6acdbe 100644
--- a/include/tests_logging
+++ b/include/tests_logging
@@ -387,7 +387,7 @@
             fi
             TARGET="${ROOTDIR}etc/rsyslog.d"
             if [ -d ${TARGET} ]; then
-                FILES=$(${FINDBINARY} ${TARGET} -type f -print0 | ${TRBINARY} -cd '[:print:]\0' | ${SEDBINARY} 's/[[:blank:]]/:space:/g' | ${TRBINARY} '\0' ' ')
+                FILES=$(${FINDBINARY} -L ${TARGET} -type f -print0 | ${TRBINARY} -cd '[:print:]\0' | ${SEDBINARY} 's/[[:blank:]]/:space:/g' | ${TRBINARY} '\0' ' ')
                 for F in ${FILES}; do
                     F=$(echo ${F} | ${SEDBINARY} 's/:space:/ /g')
                     LogText "Test: analyzing file ${F} for remote target"
diff --git a/include/tests_malware b/include/tests_malware
index cb13ca9..40336fa 100644
--- a/include/tests_malware
+++ b/include/tests_malware
@@ -45,6 +45,24 @@
     TRENDMICRO_DSA_DAEMON_RUNNING=0
 #
 #################################################################################
+#
+    # Test        : MALW-3274
+    # Description : Check for installed tool (McAfee VirusScan for Command Line)
+    Register --test-no MALW-3274 --weight L --network NO --category security --description "Check for McAfee VirusScan Command Line"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        LogText "Test: checking presence McAfee VirusScan for Command Line"
+        if [ -x /usr/local/uvscan/uvscan ]; then
+            Display --indent 2 --text "- ${GEN_CHECKING} McAfee VirusScan for Command Line" --result "${STATUS_FOUND}" --color GREEN
+            LogText "Result: Found ${MCAFEECLBINARY}"
+            MALWARE_SCANNER_INSTALLED=1
+            AddHP 2 2
+            Report "malware_scanner[]=mcafeecl"
+        else
+            LogText "Result: McAfee VirusScan for Command Line not found"
+        fi
+    fi
+#
+#################################################################################
 #
     # Test        : MALW-3275
     # Description : Check for installed tool (chkrootkit)
diff --git a/include/tests_ports_packages b/include/tests_ports_packages
index e757bd0..9ca1948 100644
--- a/include/tests_ports_packages
+++ b/include/tests_ports_packages
@@ -34,6 +34,34 @@
     Display --indent 2 --text "- Searching package managers"
 #
 #################################################################################
+#
+    # Test        : PKGS-7200
+    # Description : Check Alpine Package Keeper (apk)
+    if [ -x ${ROOTDIR}/sbin/apk ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PKGS-7200 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Querying apk"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        COUNT=0
+        Display --indent 4 --text "- Searching apk package manager" --result "${STATUS_FOUND}" --color GREEN
+        LogText "Result: Found apk binary"
+        Report "package_manager[]=apk"
+        PACKAGE_MGR_PKG=1
+        LogText "Test: Querying apk info -v to get package list"
+        Display --indent 6 --text "- Querying package manager"
+        LogText "Output:"
+        SPACKAGES=$(apk info -v | ${SEDBINARY} -r -e 's/([a-z,A-Z,0-9,_,-,.]{1,250})-([a-z,A-Z,0-9,.]+-r[a-z,A-Z,0-9]+)/\1,\2/' | sort)
+        for J in ${SPACKAGES}; do
+            COUNT=$((COUNT + 1))
+            PACKAGE_NAME=$(echo ${J} | ${CUTBINARY} -d ',' -f1)
+            PACKAGE_VERSION=$(echo ${J} | ${CUTBINARY} -d ',' -f2)
+            LogText "Found package: ${PACKAGE_NAME} (version: ${PACKAGE_VERSION})"
+            INSTALLED_PACKAGES="${INSTALLED_PACKAGES}|${PACKAGE_NAME},${PACKAGE_VERSION}"
+        done
+        Report "installed_packages=${COUNT}"
+    else
+        LogText "Result: apk "${STATUS_NOT_FOUND}", test skipped"
+    fi
+#
+#################################################################################
 #
     # Test        : PKGS-7301
     # Description : Query FreeBSD pkg
@@ -1235,6 +1263,41 @@
 
 #
 #################################################################################
+#
+    # Test        : PKGS-7395
+    # Description : Check Alpine upgradeable packages
+    if [ "${LINUX_VERSION}" = "Alpine Linux" ]  && [ -x "${ROOTDIR}sbin/apk" ]; then
+        PREQS_MET="YES"
+    else
+        PREQS_MET="NO"
+    fi
+
+    Register --test-no PKGS-7395 --os Linux --preqs-met ${PREQS_MET} --weight L --network YES --category security --description "Check for Alpine updates"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        if [ ${REFRESH_REPOSITORIES} -eq 1 ]; then
+            LogText "Action: updating package repository with apk"
+            ${ROOTDIR}sbin/apk update
+            LogText "Result: apk finished"
+        else
+            LogText "Result: using a possibly outdated repository, as updating is disabled via configuration"
+        fi
+        LogText "Test: Checking packages which can be upgraded via apk version -l '<'"
+        FIND=$(${ROOTDIR}sbin/apk version -l '<' | ${GREPBINARY} '<' | ${SEDBINARY} 's/\s\+<\s/</g')
+        if [ -z "${FIND}" ]; then
+            LogText "Result: no packages found which can be upgraded"
+            Display --indent 2 --text "- Checking upgradeable packages" --result "${STATUS_NONE}" --color GREEN
+            AddHP 3 3
+        else
+            LogText "Result: found one or more packages which can be upgraded"
+            Display --indent 2 --text "- Checking upgradeable packages" --result "${STATUS_FOUND}" --color YELLOW
+            for ITEM in ${FIND}; do
+                ITEM=$(echo ${ITEM} | ${SEDBINARY}  -r -e 's/([a-z,A-Z,0-9,_,-,.]{1,250})-([a-z,A-Z,0-9,.]+-r[a-z,A-Z,0-9]+)<([a-z,A-Z,0-9,-,.]+)/\1 from \2 to \3/')
+                LogText "${ITEM}"
+            done
+        fi
+    fi
+#
+#################################################################################
 #
     # Test        : PKGS-7398
     # Description : Check package audit tool
diff --git a/include/tests_printers_spoolers b/include/tests_printers_spoolers
index 18b88c0..851b0ed 100644
--- a/include/tests_printers_spoolers
+++ b/include/tests_printers_spoolers
@@ -139,8 +139,18 @@
     Register --test-no PRNT-2308 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check CUPSd network configuration"
     if [ ${SKIPTEST} -eq 0 ]; then
         FOUND=0
-        # Checking network addresses
+        PORT_FOUND=0
+
         LogText "Test: Checking CUPS daemon listening network addresses"
+
+        # Search for Port statement
+        FIND=$(${EGREPBINARY} "^Port 631" ${CUPSD_CONFIG_FILE})
+        if [ -n "${FIND}" ]; then
+            LogText "Result: found CUPS listening on port 631 (most likely all interfaces)"
+            PORT_FOUND=1
+        fi
+
+        # Checking network addresses
         FIND=$(${EGREPBINARY} "^(SSL)?Listen" ${CUPSD_CONFIG_FILE} | ${GREPBINARY} -v "/" | ${AWKBINARY} '{ print $2 }')
         COUNT=0
         for ITEM in ${FIND}; do
@@ -149,17 +159,10 @@
             FOUND=1
         done
 
-        # Search for Port statement
-        FIND=$(${EGREPBINARY} "^Port 631" ${CUPSD_CONFIG_FILE})
-        if [ -n "${FIND}" ]; then
-            LogText "Result: found CUPS listening on port 631 (most likely all interfaces)"
-            FOUND=1
-        fi
-
         # Check if daemon might be running on localhost
-        if [ ${FOUND} -eq 0 ]; then
+        if [ ${FOUND} -eq 0 -a ${PORT_FOUND} -eq 0 ]; then
             LogText "Result: CUPS does not look to be listening on a network port"
-        elif [ ${COUNT} -eq 1 ]; then
+        elif [ ${COUNT} -eq 1 -a ${PORT_FOUND} -eq 0 ]; then
             if [ "${FIND}" = "localhost:631" -o "${FIND}" = "127.0.0.1:631" ]; then
                 LogText "Result: CUPS daemon only running on localhost"
                 AddHP 2 2
diff --git a/include/tests_scheduling b/include/tests_scheduling
index 196a2e7..3aa004c 100644
--- a/include/tests_scheduling
+++ b/include/tests_scheduling
@@ -77,7 +77,7 @@
                 if FileIsReadable ${DIR}; then
                     LogText "Result: found directory ${DIR}"
                     LogText "Test: searching files in ${DIR}"
-                    FIND=$(${FINDBINARY} ${DIR} -type f -print | ${GREPBINARY} -v ".placeholder")
+                    FIND=$(${FINDBINARY} -L ${DIR} -type f -print | ${GREPBINARY} -v ".placeholder")
                     if IsEmpty "${FIND}"; then
                         LogText "Result: no files found in ${DIR}"
                     else
@@ -112,7 +112,7 @@
                 LogText "Result: found directory ${I}"
                 if FileIsReadable ${I}; then
                     LogText "Test: searching files in ${I}"
-                    FIND=$(${FINDBINARY} ${I} -type f -print 2> /dev/null | ${GREPBINARY} -v ".placeholder")
+                    FIND=$(${FINDBINARY} -L ${I} -type f -print 2> /dev/null | ${GREPBINARY} -v ".placeholder")
                     if [ -z "${FIND}" ]; then
                         LogText "Result: no files found in ${I}"
                     else
diff --git a/include/tests_shells b/include/tests_shells
index 9598cfb..8ecbde2 100644
--- a/include/tests_shells
+++ b/include/tests_shells
@@ -167,9 +167,9 @@
             FIND=$(${LSBINARY} ${ROOTDIR}etc/profile.d/*.sh 2> /dev/null)
             if [ -n "${FIND}" ]; then
                 # Determine if we can find a TMOUT value
-                FIND=$(${FINDBINARY} ${ROOTDIR}etc/profile.d -name "*.sh" -type f -exec cat {} \; 2> /dev/null | ${GREPBINARY} 'TMOUT=' | ${TRBINARY} -d ' ' | ${TRBINARY} -d '\t' | ${GREPBINARY} -v "^#" | ${SEDBINARY} 's/export//' | ${SEDBINARY} 's/#.*//' | ${AWKBINARY} -F= '{ print $2 }')
+                FIND=$(${FINDBINARY} -L ${ROOTDIR}etc/profile.d -name "*.sh" -type f -exec cat {} \; 2> /dev/null | ${GREPBINARY} 'TMOUT=' | ${TRBINARY} -d ' ' | ${TRBINARY} -d '\t' | ${GREPBINARY} -v "^#" | ${SEDBINARY} 's/export//' | ${SEDBINARY} 's/#.*//' | ${AWKBINARY} -F= '{ print $2 }')
                 # Determine if the value is exported (with export, readonly, or typeset)
-                FIND2=$(${FINDBINARY} ${ROOTDIR}etc/profile.d -name "*.sh" -type f -exec cat {} \; 2> /dev/null | ${GREPBINARY} '\(export\|readonly\|typeset -r\)[ \t]*TMOUT' | ${GREPBINARY} -v "^#" | ${SEDBINARY} 's/#.*//' | ${AWKBINARY} '{ print $1 }')
+                FIND2=$(${FINDBINARY} -L ${ROOTDIR}etc/profile.d -name "*.sh" -type f -exec cat {} \; 2> /dev/null | ${GREPBINARY} '\(export\|readonly\|typeset -r\)[ \t]*TMOUT' | ${GREPBINARY} -v "^#" | ${SEDBINARY} 's/#.*//' | ${AWKBINARY} '{ print $1 }')
                 if [ -n "${FIND}" ]; then
                     N=0; IDLE_TIMEOUT=1
                     for I in ${FIND}; do
diff --git a/include/tests_squid b/include/tests_squid
index c6b5174..c486108 100644
--- a/include/tests_squid
+++ b/include/tests_squid
@@ -131,7 +131,7 @@
     Register --test-no SQD-3613 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check Squid file permissions"
     if [ ${SKIPTEST} -eq 0 ]; then
         LogText "Test: Checking file permissions of ${SQUID_DAEMON_CONFIG}"
-        FIND=$(find ${SQUID_DAEMON_CONFIG} -type f -a \( -perm -004 -o -perm -002 -o -perm -001 \))
+        FIND=$(find -L ${SQUID_DAEMON_CONFIG} -type f -a \( -perm -004 -o -perm -002 -o -perm -001 \))
         if [ -n "${FIND}" ]; then
             LogText "Result: file ${SQUID_DAEMON_CONFIG} is world readable, writable or executable and could leak information or passwords"
             Display --indent 4 --text "- Checking Squid configuration file permissions" --result "${STATUS_WARNING}" --color RED
diff --git a/include/tests_ssh b/include/tests_ssh
index 7f31c34..de3209e 100644
--- a/include/tests_ssh
+++ b/include/tests_ssh
@@ -74,7 +74,7 @@
                 LogText "Result: ${I}/sshd_config exists"
                 if [ ${FOUND} -eq 1 ]; then
                     ReportException "${TEST_NO}:01"
-                    LogText "Result: we already had found another sshd_config file. Using this new file then."
+                    LogText "Result: we already found another sshd_config file. Using this new file instead of the previous one."
                 fi
                 FileIsReadable ${I}/sshd_config
                 if [ ${CANREAD} -eq 1 ]; then
diff --git a/include/tests_webservers b/include/tests_webservers
index 6e0a3b3..e0ca573 100644
--- a/include/tests_webservers
+++ b/include/tests_webservers
@@ -288,7 +288,7 @@
     Register --test-no HTTP-6643 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Determining existence of specific Apache modules"
     if [ ${SKIPTEST} -eq 0 ]; then
         # Check modules, module
-        if CheckItem "apache_module" "/mod_security2.so"; then
+        if CheckItem "apache_module" "/mod_security(2|3).so" ; then
             Display --indent 10 --text "ModSecurity: web application firewall" --result "${STATUS_FOUND}" --color GREEN
             AddHP 3 3
         else
diff --git a/lynis b/lynis
index a9bef80..c15a78c 100755
--- a/lynis
+++ b/lynis
@@ -43,10 +43,10 @@
     PROGRAM_WEBSITE="https://cisofy.com/lynis/"
 
     # Version details
-    PROGRAM_RELEASE_DATE="2022-01-18"
-    PROGRAM_RELEASE_TIMESTAMP=1642512096
-    PROGRAM_RELEASE_TYPE="release" # pre-release or release
-    PROGRAM_VERSION="3.0.7"
+    PROGRAM_RELEASE_DATE="2022-01-31"
+    PROGRAM_RELEASE_TIMESTAMP=1643632222
+    PROGRAM_RELEASE_TYPE="pre-release" # pre-release or release
+    PROGRAM_VERSION="3.0.8"
 
     # Source, documentation and license
     PROGRAM_SOURCE="https://github.com/CISOfy/lynis"
diff --git a/plugins/plugin_pam_phase1 b/plugins/plugin_pam_phase1
new file mode 100644
index 0000000..9aada62
--- /dev/null
+++ b/plugins/plugin_pam_phase1
@@ -0,0 +1,535 @@
+#!/bin/sh
+
+#########################################################################
+#
+#    * DO NOT REMOVE *
+#-----------------------------------------------------
+# PLUGIN_AUTHOR=Michael Boelen <michael.boelen@cisofy.com>
+# PLUGIN_CATEGORY=authentication
+# PLUGIN_DATE=2020-03-21
+# PLUGIN_DESC=PAM
+# PLUGIN_NAME=pam
+# PLUGIN_PACKAGE=all
+# PLUGIN_REQUIRED_TESTS=
+# PLUGIN_VERSION=1.0.5
+#-----------------------------------------------------
+#########################################################################
+#
+    # Variables
+    CREDITS_D_PASSWORD=""
+    CREDITS_L_PASSWORD=""
+    CREDITS_O_PASSWORD=""
+    CREDITS_U_PASSWORD=""
+    MAX_PASSWORD_RETRY=""
+    MIN_PASSWORD_CLASS=""
+    PAM_DIRECTORY="${ROOTDIR}etc/pam.d"
+#
+#########################################################################
+#
+    # Test        : PLGN-0008
+    # Description : Check PAM configuration
+    FILE="${ROOTDIR}etc/security/pwquality.conf"
+    if [ -f ${FILE} ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-0008 --preqs-met ${PREQS_MET} --weight L --network NO --description "Check PAM configuration (pwquality.conf)" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        for LINE in $(${GREPBINARY} -v "^#" ${FILE} | ${TRBINARY} -d " "); do
+            for I in ${LINE}; do
+                OPTION=$(echo ${I} | ${AWKBINARY} -F= '{ print $1 }')
+                VALUE=$(echo ${I} | ${AWKBINARY} -F= '{ print $2 }')
+                case ${OPTION} in
+                    minlen)
+                        DigitsOnly ${VALUE}
+                        MIN_PASSWORD_LENGTH=${VALUE}
+                    ;;
+                    retry)
+                        DigitsOnly ${VALUE}
+                        MAX_PASSWORD_RETRY=${VALUE}
+                    ;;
+                    minclass)
+                        MIN_PASSWORD_CLASS=${VALUE}
+                    ;;
+                    dcredit)
+                        CREDITS_D_PASSWORD=${VALUE}
+                    ;;
+                    lcredit)
+                        CREDITS_L_PASSWORD=${VALUE}
+                    ;;
+                    ocredit)
+                        CREDITS_O_PASSWORD=${VALUE}
+                    ;;
+                    ucredit)
+                        CREDITS_U_PASSWORD=${VALUE}
+                    ;;
+                esac
+            done
+        done
+    fi
+#
+#########################################################################
+#
+    # Test        : PLGN-0010
+    # Description : Check PAM configuration
+    if [ -f ${ROOTDIR}etc/pam.conf -o -d ${PAM_DIRECTORY} ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-0010 --preqs-met ${PREQS_MET} --weight L --network NO --description "Check PAM configuration" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FOUNDPROBLEM=0
+        # Check if the PAM directory structure exists
+        if [ -d ${PAM_DIRECTORY} ]; then
+            LogText "Result: ${PAM_DIRECTORY} exists"
+            if [ ! "${OS}" = "FreeBSD" -a ! "${OS}" = "NetBSD" ]; then
+                FIND_FILES=$(find ${PAM_DIRECTORY} \! -name "*.pam-old" -type f -print)
+            else
+                if [ -f ${PAM_DIRECTORY}/README ]; then
+                    LogText "Skipped checking ${OS} ${PAM_DIRECTORY}/README as a PAM file"
+                fi
+                FIND_FILES=$(find ${PAM_DIRECTORY} \! -name "README" \! -name "*.pam-old" -type f -print)
+            fi
+
+            for PAM_FILE in ${FIND_FILES}; do
+                LogText "Now checking PAM file ${PAM_FILE}"
+                while read line; do
+                    # Strip empty lines, commented lines, tabs, line breaks (\), then finally remove all double spaces
+                    LINE=$(echo $line | grep -v "^#" | grep -v "^$" | tr '\011' ' ' | sed 's/\\\n/ /' | sed 's/  / /g' | sed 's/ #\(.*\)$//')
+                    if [ ! "${LINE}" = "" ]; then
+                        PAM_SERVICE=$(echo ${PAM_FILE} | awk -F/ '{ print $NF }')
+                        PAM_CONTROL_FLAG="-"
+                        PAM_CONTROL_OPTIONS="-"
+                        PAM_MODULE="-"
+                        PAM_MODULE_OPTIONS="-"
+                        PAM_TYPE=$(echo ${LINE} | awk '{ print $1 }' | sed 's/^ *-//g')
+                        PARSELINE=0
+                        case ${PAM_TYPE} in
+                            "@include")
+                                FILE=$(echo ${LINE} | awk '{ print $2 }')
+                                Debug "Result: Found @include in ${PAM_FILE}. Does include PAM settings from file ${FILE} (which is individually processed)"
+                            ;;
+                            "account")
+                                PARSELINE=1
+                            ;;
+                            "auth")
+                                PARSELINE=1
+                            ;;
+                            "password")
+                                PARSELINE=1
+                            ;;
+                            "session")
+                                PARSELINE=1
+                            ;;
+                            *)
+                                LogText "Exception: Unknown PAM type found (${PAM_TYPE})"
+                            ;;
+                        esac
+                        if [ ${PARSELINE} -eq 1 ]; then
+                            MULTIPLE_OPTIONS=$(echo ${LINE} | awk '$2 ~ /^\[/')
+                            if [ ! "${MULTIPLE_OPTIONS}" = "" ]; then
+                                # Needs more parsing, depending on the options found
+                                PAM_CONTROL_OPTIONS=$(echo ${LINE} | sed "s/^.*\[//" | sed "s/\].*$//")
+                                LogText "Result: Found brackets in line, indicating multiple options for control flags: ${PAM_CONTROL_OPTIONS}"
+                                LINE=$(echo ${LINE} | sed "s/ \[.*\] / other /")
+                            fi
+                            PAM_MODULE=$(echo ${LINE} | awk '{ print $3 }')
+                            PAM_MODULE_OPTIONS=$(echo ${LINE} | cut -d ' ' -f 4-)
+                            PAM_CONTROL_FLAG=$(echo ${LINE} | awk '{ print $2 }')
+                            if [ ${PAM_CONTROL_FLAG} = "include" ]; then
+                                FILE=$(echo ${LINE} | awk '{ print $3 }')
+                                Debug "Result: Found include in ${PAM_FILE}. Does include PAM settings from file ${FILE} (which is individually processed)"
+                                PARSELINE=0
+                            fi
+                        fi
+                        if [ ${PARSELINE} -eq 1 ]; then
+                            case ${PAM_CONTROL_FLAG} in
+                                    "optional"|"required"|"requisite"|"sufficient")
+                                        #Debug "Found a common control flag: ${PAM_CONTROL_FLAG} for ${PAM_MODULE}"
+                                        X=0 # do nothing
+                                    ;;
+                                    "other")
+                                        LogText "Result: brackets used, ignoring control flags"
+                                    ;;
+                                    *)
+                                        LogText "Unknown control flag found (${PAM_CONTROL_FLAG})"
+                                    ;;
+                            esac
+                            if [ ! "${PAM_MODULE_OPTIONS}" = "" ]; then
+                                LogText "Result: using module ${PAM_MODULE} (${PAM_CONTROL_FLAG}) with options ${PAM_MODULE_OPTIONS}"
+                              else
+                                PAM_MODULE_OPTIONS="-"
+                                LogText "Result: using module ${PAM_MODULE} (${PAM_CONTROL_FLAG}) without options configured"
+                            fi
+
+                            PAM_MODULE_NAME=$(echo ${PAM_MODULE} | sed 's/.so$//')
+                            #
+                            # Specific PAMs are commonly seen on these platforms:
+                            #
+                            #                     FreeBSD  Linux  macOS  NetBSD
+                            # pam_access                     v
+                            # pam_afpmount                          v
+                            # pam_afslog                                   v
+                            # pam_deny               v       v      v      v
+                            # pam_env                               v
+                            # pam_chroot             v                     v
+                            # pam_echo               v       ?             v
+                            # pam_exec               v       ?             v
+                            # pam_ftpusers                                 v
+                            # pam_group              v              v      v
+                            # pam_guest                                    v
+                            # pam_krb5               v              v      v
+                            # pam_ksu                v                     v
+                            # pam_lastlog            v                     v
+                            # pam_launchd                           v
+                            # pam_login_access       v                     v
+                            # pam_mount                             v
+                            # pam_nologin            v              v      v
+                            # pam_ntlm                              v
+                            # pam_opendirectory                     v
+                            # pam_opie               v
+                            # pam_opieaccess         v
+                            # pam_passwdqc           v
+                            # pam_permit             v              v      v
+                            # pam_radius             v                     v
+                            # pam_rhosts             v                     v
+                            # pam_rootok             v              v      v
+                            # pam_sacl                              v
+                            # pam_securetty          v              v      v
+                            # pam_securityserver                    v
+                            # pam_self               v                     v
+                            # pam_skey                                     v
+                            # pam_ssh                v                     v
+                            # pam_tacplus            v
+                            # pam_unix               v              v      v
+                            # pam_uwtmp                             v
+                            # pam_wheel                             v
+                            # pam_winbind                           v
+
+                            case ${PAM_MODULE_NAME} in
+                                pam_access) ;;
+                                pam_afpmount | pam_afslog) ;;
+                                pam_cap) ;;
+                                pam_debug | pam_deny) ;;
+                                pam_echo| pam_env | pam_exec |  pam_faildelay) ;;
+                                pam_filter | pam_ftp | pam_ftpusers) ;;
+                                # Google Authenticator / YubiKey
+                                # Common to find it only enabled for SSH
+                                pam_google_authenticator | pam_yubico)
+                                    LogText "Result: found pam_google_authenticator"
+                                    if [ "${PAM_CONTROL_FLAG}" = "required" ]; then
+                                        PAM_2F_AUTH_ENABLED=1
+                                        PAM_2F_AUTH_REQUIRED=1
+                                        Report "authentication_2f_provider[]=${PAM_MODULE_NAME}"
+                                        Report "authentication_2f_service[]=${PAM_SERVICE}"
+                                    elif [ "${PAM_CONTROL_FLAG}" = "sufficient" ]; then
+                                        PAM_2F_AUTH_ENABLED=1
+                                        Report "authentication_2f_provider[]=${PAM_MODULE_NAME}"
+                                        Report "authentication_2f_service[]=${PAM_SERVICE}"
+                                      else
+                                        LogText "exception: found 2F authenticator enabled with uncommon control flag: ${PAM_CONTROL_FLAG}"
+                                    fi
+                                ;;
+                                pam_group) ;;
+                                pam_guest) ;;
+                                pam_issue) ;;
+                                pam_keyinit | pam_krb5 | pam_ksu) ;;
+                                pam_launchd) ;;
+                                pam_lastlog | pam_limits) ;;
+                                pam_login_access) ;;
+                                # Log UID for auditd
+                                pam_loginuid)
+                                    PAM_LOGINUID_FOUND=1
+                                ;;
+                                pam_listfile | pam_localuser) ;;
+                                pam_mail | pam_mkhomedir | pam_motd) ;;
+                                pam_namespace | pam_nologin | pam_ntlm) ;;
+                                pam_opendirectory) ;;
+                                pam_permit) ;;
+
+                                # Password history - Can be configured via pam_unix or pam_pwhistory
+                                pam_pwhistory)
+                                    LogText "Result: found ${PAM_MODULE} module (password history)"
+                                    # set default for having pam_pwhistory enabled
+                                    PAM_PASSWORD_PWHISTORY_ENABLED=1
+                                    if [ "${PAM_PASSWORD_PWHISTORY_AMOUNT}" = "" ]; then PAM_PASSWORD_PWHISTORY_AMOUNT=10; fi
+                                    if [ ! "${PAM_MODULE_OPTIONS}" = "" ]; then
+                                        for I in ${PAM_MODULE_OPTIONS}; do
+                                            OPTION=$(echo ${I} | awk -F= '{ print $1 }')
+                                            VALUE=$(echo ${I} | awk -F= '{ print $2 }')
+                                            CREDITS_CONFIGURED=0
+                                            case ${OPTION} in
+                                                remember)
+                                                    LogText "Result: password history (remember) configured for pam_pwhistory"
+                                                    DigitsOnly ${VALUE}
+                                                    PAM_PASSWORD_PWHISTORY_AMOUNT=${VALUE}
+                                                    Debug "Found password history enabled with module ${PAM_MODULE_NAME} and password amount ${PAM_PASSWORD_PWHISTORY_AMOUNT}"
+                                                ;;
+                                            esac
+                                        done
+                                    fi
+                                ;;
+
+                                pam_radius) ;;
+                                pam_rhosts) ;;
+                                pam_rootok) ;;
+                                pam_sacl) ;;
+                                pam_securetty) ;;
+                                pam_securityserver) ;;
+                                pam_self) ;;
+                                pam_selinux) ;;
+                                pam_shells) ;;
+                                pam_skey) ;;
+                                pam_ssh)
+                                    LogText "Result: found ${PAM_MODULE} module (SSH authentication/session management)"
+                                    ReportWarning ${TEST_NO} "Potential security risks using of pam_ssh(8) module."
+                                ;;
+                                pam_stress | pam_succeed_if | pam_systemd) ;;
+                                pam_time | pam_timestamp) ;;
+                                pam_umask) ;;
+
+                                # Password history - Can be configured via pam_unix or pam_pwhistory
+                                pam_unix)
+                                    LogText "Result: found ${PAM_MODULE} module (generic)"
+                                    if [ ! "${PAM_MODULE_OPTIONS}" = "" ]; then
+                                        for I in ${PAM_MODULE_OPTIONS}; do
+                                            OPTION=$(echo ${I} | awk -F= '{ print $1 }')
+                                            VALUE=$(echo ${I} | awk -F= '{ print $2 }')
+                                            CREDITS_CONFIGURED=0
+                                            case ${OPTION} in
+                                                remember)
+                                                    LogText "Result: password history configured for pam_unix"
+                                                    DigitsOnly ${VALUE}
+                                                    PAM_PASSWORD_UXHISTORY_AMOUNT=${VALUE}
+                                                    PAM_PASSWORD_UXHISTORY_ENABLED=1
+                                                    Debug "Found password history enabled with module ${PAM_MODULE_NAME} and password amount ${PAM_PASSWORD_UXHISTORY_AMOUNT}"
+                                                ;;
+                                            esac
+                                        done
+                                    fi
+                                ;;
+
+                                pam_unix_acct| pam_unix_auth | pam_unix_passwd | pam_unix_session | pam_unix2) ;;
+                                pam_uwtmp) ;;
+                                pam_vbox) ;;
+                                pam_warn | pam_wheel) ;;
+                                pam_winbind) ;;
+                                pam_xauth) ;;
+
+                                # Password strength testing
+                                pam_cracklib | pam_pwquality)
+                                    LogText "Result: found module ${PAM_MODULE} for password strength testing"
+
+                                    # Set default values
+                                    if [ "${CREDITS_D_PASSWORD}" = "" ]; then CREDITS_D_PASSWORD=1; fi
+                                    if [ "${CREDITS_L_PASSWORD}" = "" ]; then CREDITS_L_PASSWORD=1; fi
+                                    if [ "${CREDITS_O_PASSWORD}" = "" ]; then CREDITS_O_PASSWORD=1; fi
+                                    if [ "${CREDITS_U_PASSWORD}" = "" ]; then CREDITS_U_PASSWORD=1; fi
+                                    if [ "${MIN_PASSWORD_CLASS}" = "" ]; then MIN_PASSWORD_CLASS=0; fi
+                                    if [ "${MIN_PASSWORD_LENGTH}" = "" ]; then MIN_PASSWORD_LENGTH=6; fi
+
+                                    PAM_PASSWORD_STRENGTH_TESTED=1
+                                    if [ ! "${PAM_MODULE_OPTIONS}" = "" ]; then
+                                        Debug "Module options configured"
+                                        for I in ${PAM_MODULE_OPTIONS}; do
+                                            OPTION=$(echo ${I} | awk -F= '{ print $1 }')
+                                            Debug ${OPTION}
+                                            VALUE=$(echo ${I} | awk -F= '{ print $2 }')
+                                            CREDITS_CONFIGURED=0
+                                            case ${OPTION} in
+                                                minlen)
+                                                    # Minimum length (remove 1 if credits are configured, at later stage in function)
+                                                    LogText "Result: minlen configured"
+                                                    DigitsOnly ${VALUE}
+                                                    MIN_PASSWORD_LENGTH=${VALUE}
+                                                ;;
+                                                retry)
+                                                    # Maximum password retry
+                                                    LogText "Result: Max password Retry configured"
+                                                    DigitsOnly ${VALUE}
+                                                    MAX_PASSWORD_RETRY=${VALUE}
+                                                ;;
+                                                minclass)
+                                                    # Minimum number of class required out of upper, lower, digit and others
+                                                    LogText "Result: Min number of password class is configured"
+                                                    MIN_PASSWORD_CLASS=${VALUE}
+                                                ;;
+                                                dcredit)
+                                                    CREDITS_D_PASSWORD=${VALUE}
+                                                ;;
+                                                lcredit)
+                                                    CREDITS_L_PASSWORD=${VALUE}
+                                                ;;
+                                                ocredit)
+                                                    CREDITS_O_PASSWORD=${VALUE}
+                                                ;;
+                                                ucredit)
+                                                    CREDITS_U_PASSWORD=${VALUE}
+                                                ;;
+                                                *)
+                                                    LogText "Result: unknown option found: ${OPTION} with value ${VALUE}"
+                                                ;;
+                                            esac
+                                        done
+                                    fi
+                                ;;
+
+                                pam_tally | pam_tally2)
+                                    if [ "${PAM_CONTROL_FLAG}" = "required" ]; then
+                                        LogText "Result: found a required module for countering brute force cracking attempts"
+                                        Report "pam_auth_brute_force_protection_module[]=${PAM_MODULE_NAME}"
+                                        PAM_AUTH_BRUTE_FORCE_PROTECTION=1
+                                    fi
+                                    if [ ! "${PAM_MODULE_OPTIONS}" = "" ]; then
+                                        for I in ${PAM_MODULE_OPTIONS}; do
+                                            OPTION=$(echo ${I} | awk -F= '{ print $1 }')
+                                            VALUE=$(echo ${I} | awk -F= '{ print $2 }')
+                                            case ${OPTION} in
+                                                deny)
+                                                    AUTH_BLOCK_BAD_LOGIN_ATTEMPTS="${VALUE}"
+                                                ;;
+                                                unlock_time)
+                                                    AUTH_UNLOCK_TIME="${VALUE}"
+                                                ;;
+                                            esac
+                                        done
+                                    fi
+                                ;;
+                                "-")
+                                    LogText "NOTE: this module is not parsed, as it uses an unknown control flag or type"
+                                ;;
+                                *)
+                                    LogText "Result: found pluggable authentication module ${PAM_MODULE}, which is unknown"
+                                ;;
+                            esac
+                        fi
+                        #Debug "Service:          ${PAM_SERVICE}"
+                        #Debug "Type:             ${PAM_TYPE}"
+                        #Debug "Control:          ${PAM_CONTROL_FLAG}"
+                        #Debug "Control options:  ${PAM_CONTROL_OPTIONS}"
+                        #Debug "Module:           ${PAM_MODULE_NAME}"
+                        #Debug "Module options:   ${PAM_MODULE_OPTIONS}"
+                    fi
+                done < ${PAM_FILE}
+                #ParsePAMLine ${J}
+                #StoreSetting "pam" "
+            done
+        fi
+    fi
+#
+#################################################################################
+#
+
+# /etc/security/opasswd should exist when:
+# password history is enabled via pam_unix
+# pam_cracklib or pam_pwquality is used
+# In that case, the file should be owned by root, with 440/640/660 permissions
+
+LogText "[PAM] PAM 2F authentication enabled: ${PAM_2F_AUTH_ENABLED}"
+Report "authentication_two_factor_enabled=${PAM_2F_AUTH_ENABLED}"
+
+LogText "[PAM] PAM 2F authentication required: ${PAM_2F_AUTH_REQUIRED}"
+Report "authentication_two_factor_required=${PAM_2F_AUTH_REQUIRED}"
+
+if [ ! "${AUTH_UNLOCK_TIME}" = "-1" ]; then
+    LogText "[PAM] Authentication unlock time: ${AUTH_UNLOCK_TIME}"
+    Report "authentication_unlock_time=${AUTH_UNLOCK_TIME}"
+else
+    LogText "[PAM] Authentication unlock time: not configured"
+fi
+
+LogText "[PAM] Password brute force protection: ${PAM_AUTH_BRUTE_FORCE_PROTECTION}"
+
+if [ ${PAM_AUTH_BRUTE_FORCE_PROTECTION} -eq 1 ]; then
+    Report "authentication_brute_force_protection=1"
+fi
+
+if [ ! "${MIN_PASSWORD_LENGTH}" = "-1" ]; then
+    LogText "[PAM] Minimum password length: ${MIN_PASSWORD_LENGTH}"
+    Report "minimum_password_length=${MIN_PASSWORD_LENGTH}"
+else
+    LogText "[PAM] Minimum password length: not configured"
+fi
+
+LogText "[PAM] Password strength testing enabled: ${PAM_PASSWORD_STRENGTH_TESTED}"
+if [ ${PAM_PASSWORD_STRENGTH_TESTED} -eq 1 ]; then
+    Report "password_strength_tested=1"
+
+    if [ ${CREDITS_D_PASSWORD} -ge 1 -a ${CREDITS_L_PASSWORD} -ge 1 -a ${CREDITS_O_PASSWORD} -ge 1 -a ${CREDITS_U_PASSWORD} -ge 1 ]; then
+        # Show how many password class are required out of 4
+        LogText "[PAM] Minimum password class out of 4: ${MIN_PASSWORD_CLASS}"
+        Report "min_password_class=${MIN_PASSWORD_CLASS}"
+    else
+        LogText "[PAM] Minimum password class setting of ${MIN_PASSWORD_CLASS} out of 4 is ignored since at least 1 class are forced"
+        Report "min_password_class=ignored"
+    fi
+
+    # Digits
+    if [ ${CREDITS_D_PASSWORD} -lt 0 ]; then
+        CREDITS_D_PASSWORD=$(echo ${CREDITS_D_PASSWORD} | cut -b 2-)
+        LogText "[PAM] Minimum number of Digital characters required: ${CREDITS_D_PASSWORD}"
+        Report "password_min_digital_required=${CREDITS_D_PASSWORD}"
+    elif [ ${CREDITS_D_PASSWORD} -ge 0 ]; then
+        LogText "[PAM] Maximum credit for Digital characters: ${CREDITS_D_PASSWORD}"
+        Report "password_max_digital_credit=${CREDITS_D_PASSWORD}"
+    fi
+
+    # Lowercase
+    if [ ${CREDITS_L_PASSWORD} -lt 0 ]; then
+        CREDITS_L_PASSWORD=$(echo ${CREDITS_L_PASSWORD} | cut -b 2-)
+        LogText "[PAM] Minimum number of Lowercase characters required: ${CREDITS_L_PASSWORD}"
+        Report "password_min_l_required=${CREDITS_L_PASSWORD}"
+    elif [ ${CREDITS_L_PASSWORD} -ge 0 ]; then
+        LogText "[PAM] Maximum credit for Lowercase characters: ${CREDITS_L_PASSWORD}"
+        Report "password_max_l_credit=${CREDITS_L_PASSWORD}"
+    fi
+
+    # Other characters
+    if [ ${CREDITS_O_PASSWORD} -lt 0 ]; then
+        CREDITS_O_PASSWORD=$(echo ${CREDITS_O_PASSWORD} | cut -b 2-)
+        LogText "[PAM] Minimum number of Other characters required: ${CREDITS_O_PASSWORD}"
+        Report "password_min_other_required=${CREDITS_O_PASSWORD}"
+    elif [ ${CREDITS_O_PASSWORD} -ge 0 ]; then
+        LogText "[PAM] Maximum credit for Other characters: ${CREDITS_O_PASSWORD}"
+        Report "password_max_other_credit=${CREDITS_O_PASSWORD}"
+    fi
+
+    # Uppercase
+    if [ ${CREDITS_U_PASSWORD} -lt 0 ]; then
+        CREDITS_U_PASSWORD=$(echo ${CREDITS_U_PASSWORD} | cut -b 2-)
+        LogText "[PAM] Minimum number of Uppercase characters required: ${CREDITS_U_PASSWORD}"
+        Report "password_min_u_required=${CREDITS_U_PASSWORD}"
+    elif [ ${CREDITS_U_PASSWORD} -ge 0 ]; then
+        LogText "[PAM] Maximum credit for Uppercase characters: ${CREDITS_U_PASSWORD}"
+        Report "password_max_u_credit=${CREDITS_U_PASSWORD}"
+    fi
+fi
+
+# Show how many retries are allowed to change password
+if [ ! -z "${MAX_PASSWORD_RETRY}" ]; then
+    LogText "[PAM] Password maximum retry: ${MAX_PASSWORD_RETRY}"
+    Report "max_password_retry=${MAX_PASSWORD_RETRY}"
+else
+    LogText "[PAM] Password maximum retry: Not configured"
+fi
+
+# If auditd is running, but pam_loginuid not, events might not be properly logged
+if [ ${AUDITD_RUNNING} -eq 1 ]; then
+    if [ ${PAM_LOGINUID_FOUND} -eq 0 ]; then
+        Report "pam_issue[]=pam_loginuid is missing"
+    fi
+fi
+
+if [ ${PAM_PASSWORD_PWHISTORY_ENABLED} -eq 1 ]; then
+    LogText "[PAM] Password history with pam_pwhistory enabled: ${PAM_PASSWORD_PWHISTORY_ENABLED}"
+    LogText "[PAM] Password history with pam_pwhistory amount: ${PAM_PASSWORD_PWHISTORY_AMOUNT}"
+    Report "password_history_amount=${PAM_PASSWORD_PWHISTORY_AMOUNT}"
+else
+    LogText "[PAM] Password history with pam_pwhistory IS NOT enabled"
+fi
+
+if [ ${PAM_PASSWORD_UXHISTORY_ENABLED} -eq 1 ]; then
+    LogText "[PAM] Password history with pam_unix enabled: ${PAM_PASSWORD_UXHISTORY_ENABLED}"
+    LogText "[PAM] Password history with pam_unix amount: ${PAM_PASSWORD_UXHISTORY_AMOUNT}"
+    Report "password_history_amount=${PAM_PASSWORD_UXHISTORY_AMOUNT}"
+else
+    LogText "[PAM] Password history with pam_unix IS NOT enabled"
+fi
+
+
+
+#EOF
diff --git a/plugins/plugin_systemd_phase1 b/plugins/plugin_systemd_phase1
new file mode 100644
index 0000000..4e183f8
--- /dev/null
+++ b/plugins/plugin_systemd_phase1
@@ -0,0 +1,295 @@
+#!/bin/sh
+
+#########################################################################
+#
+#    * DO NOT REMOVE *
+#-----------------------------------------------------
+# PLUGIN_AUTHOR=Michael Boelen <michael.boelen@cisofy.com>
+# PLUGIN_CATEGORY=essentials
+# PLUGIN_DATE=2020-03-23
+# PLUGIN_DESC=Tests related to systemd tooling
+# PLUGIN_NAME=systemd
+# PLUGIN_PACKAGE=community
+# PLUGIN_REQUIRED_TESTS=
+# PLUGIN_VERSION=1.0.4
+#-----------------------------------------------------
+#
+#########################################################################
+#
+    SYSTEMD_COREDUMP_USED=0
+    SYSTEMD_FSS_FILE=""
+    SYSTEMD_MACHINEID=""
+    SYSTEMD_RUNNING=0
+    SYSTEMD_VERSION=0
+#
+#########################################################################
+#
+    # Test        : PLGN-3800
+    # Description : Gather systemctl exit code
+    if [ -n "${SYSTEMCTLBINARY}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3800 --preqs-met ${PREQS_MET} --weight L --network NO --description "Gather systemctl exit code" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${SYSTEMCTLBINARY} > /dev/null)
+        if [ $? -gt 0 ]; then
+            Report "systemctl_error_message=${FIND}"
+        else
+            SYSTEMD_RUNNING=1
+        fi
+        Report "systemctl_exit_code=$?"
+    fi
+#
+#########################################################################
+#
+    # Test        : PLGN-3802
+    # Description : Query systemd version and options
+    # Notes       : version can also be gathered with systemctl show | grep ^Version=
+    #               features with systemctl show | grep ^Features=
+    if [ -n "${SYSTEMCTLBINARY}" -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3802 --preqs-met ${PREQS_MET} --weight L --network NO --description "Query systemd version and options" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${SYSTEMCTLBINARY} --version 2> /dev/null | ${AWKBINARY} '{ if ($1=="systemd") { print $2 } }' | grep "^[1-9][0-9][0-9]$" | head -1)
+        if [ -n "${FIND}" ]; then
+            SYSTEMD_VERSION=${FIND}
+            Report "systemd_version=${FIND}"
+            LogText "Result: found systemd version ${FIND}"
+        fi
+        FIND=$(${SYSTEMCTLBINARY} --version 2> /dev/null | grep "^[-+]" | sed 's/[[:space:]]/,/g' | head -1)
+        if [ -n "${FIND}" ]; then
+            Report "systemd_builtin_components=${FIND}"
+            LogText "Result: found builtin components list"
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3804
+    # Description : Gather all systemd unit files
+    if [ -n "${SYSTEMCTLBINARY}" -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3804 --preqs-met ${PREQS_MET} --weight L --network NO --description "Gather systemd unit files and their status" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${SYSTEMCTLBINARY} --no-legend list-unit-files 2> /dev/null | ${AWKBINARY} '{ print $1"|"$2"|" }')
+        if [ -n "${FIND}" ]; then
+            LogText "Result: found systemd unit files via systemctl list-unit-files"
+            for I in ${FIND}; do
+                LogText "Output: ${I}"
+                Report "systemd_unit_file[]=${I}"
+            done
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3806
+    # Description : Gather all failed systemd units
+    if [ -n "${SYSTEMCTLBINARY}" -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3806 --preqs-met ${PREQS_MET} --weight L --network NO --description "Gather failed systemd units" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${SYSTEMCTLBINARY} --no-legend --state=failed 2> /dev/null | ${AWKBINARY} '{ if ($4=="failed" && $5=="failed") { print $2 } }')
+        if [ -n "${FIND}" ]; then
+            LogText "Result: found systemd unit files via systemctl list-unit-files"
+            for I in ${FIND}; do
+                LogText "Output: ${I}"
+                Report "systemd_unit_file[]=${I}"
+            done
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3808
+    # Description : Gather machine ID
+    if [ -f ${ROOTDIR}etc/machine-id -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3808 --preqs-met ${PREQS_MET} --weight L --network NO --description "Gather systemd machine ID" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(cat ${ROOTDIR}etc/machine-id | head -1)
+        if [ -n "${FIND}" ]; then
+            SYSTEMD_MACHINEID="${FIND}"
+            LogText "Result: found machine ID: ${SYSTEMD_MACHINEID}"
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3810
+    # Description : Query main systemd binaries
+    if [ -n "${FINDBINARY}" -a -d /usr/lib/systemd -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3810 --preqs-met ${PREQS_MET} --weight L --network NO --description "Query main systemd binaries" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${FINDBINARY} ${ROOTDIR}usr/lib/systemd -maxdepth 1 -type f -name "systemd-*" -printf "%f|")
+        if [ -n "${FIND}" ]; then
+            Report "systemd_binaries=${FIND}"
+            LogText "Result: found systemd binaries in /usr/lib/systemd"
+        else
+            LogText "Result: no binaries found in /usr/lib/systemd"
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3812
+    # Description : Query journal for boot related information
+    if [ -n "${JOURNALCTLBINARY}" -a ${SYSTEMD_RUNNING} -eq 1 -a ${SYSTEMD_VERSION} -ge 209 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3812 --preqs-met ${PREQS_MET} --weight L --network NO --description "Query journal for boot related information" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${JOURNALCTLBINARY} --list-boots | wc -l)
+        LogText "Output: number of boots listed in journal is ${FIND}"
+        if [ -n "${FIND}" ]; then Report "journal_bootlogs=${FIND}"; fi
+        FIND=$(${JOURNALCTLBINARY} --list-boots | head -1 | awk '{ print $4 }')
+        LogText "Output: oldest boot date in journal is ${FIND}"
+        if [ -n "${FIND}" ]; then Report "journal_oldest_bootdate=${FIND}"; fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3814
+    # Description : Journal integrity
+    if [ -n "${JOURNALCTLBINARY}" -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3814 --preqs-met ${PREQS_MET} --weight L --network NO --description "Verify journal integrity" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${JOURNALCTLBINARY} --verify 2>&1 | grep FAIL | sed 's/[[:space:]]/:space:/g')
+        if [ -n "${FIND}" ]; then
+            Report "journal_contains_errors=1"
+            for I in ${FIND}; do
+                LINE=$(echo ${I} | sed 's/:space:/ /g')
+                LogText "Output (fails): ${LINE}"
+            done
+          else
+            Report "journal_contains_errors=0"
+            LogText "Result: systemd journal has no errors"
+       fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3816
+    # Description : Journal sizing
+    if [ -n "${JOURNALCTLBINARY}" -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3816 --preqs-met ${PREQS_MET} --weight L --network NO --description "Query journal for boot related information" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${JOURNALCTLBINARY} --disk-usage | awk '{ if ($1=="Journals") { print $4 } else if ($1=="Archived") { print $7 }}')
+        Report "journal_disk_size=${FIND}"
+        LogText "Result: journals are ${FIND} in size"
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3818
+    # Description : Journal meta data
+    if [ -n "${JOURNALCTLBINARY}" -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3818 --preqs-met ${PREQS_MET} --weight L --network NO --description "Query journal meta data" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${JOURNALCTLBINARY} --header | sed 's/^$/|/g' | tr '\n' ',' | sed 's/[[:space:]]//g')
+        Report "journal_meta_data=${FIND}"
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3820
+    # Description : Journal FSS (Forward Secure Sealing) configuration
+    if [ -n "${JOURNALCTLBINARY}" -a -n "${SYSTEMD_MACHINEID}" -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3820 --preqs-met ${PREQS_MET} --weight L --network NO --description "Check for journal FSS configuration" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FILE="/var/log/journal/${SYSTEMD_MACHINEID}/fss"
+        if [ -f ${FILE} ]; then
+            SYSTEMD_FSS_FILE="${FILE}"
+            Report "journal_fss=1"
+            Report "journal_fss_file=${SYSTEMD_FSS_FILE}"
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3830
+    # Description : Query systemd status
+    if [ -n "${SYSTEMCTLBINARY}" -a ${SYSTEMD_RUNNING} -eq 1 -a ${SYSTEMD_VERSION} -ge 215 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3830 --preqs-met ${PREQS_MET} --weight L --network NO --description "Query systemd status" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${SYSTEMCTLBINARY} is-system-running 2> /dev/null | head -1)
+        if [ -n "${FIND}" ]; then
+            Report "systemd_status=${FIND}"
+            LogText "Result: found systemd status = ${FIND}"
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3832
+    # Description : Query processes which can not be found
+    if [ ! "${SYSTEMCTLBINARY}" = "" -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3832 --preqs-met ${PREQS_MET} --weight L --network NO --description "Query systemd status for processes which can not be found" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${SYSTEMCTLBINARY} --no-legend --all --state=not-found 2> /dev/null | awk '{ print $1 }')
+        if [ -n "${FIND}" ]; then
+            for I in ${FIND}; do
+                Report "systemd_unit_not_found[]=${I}"
+            done
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3834
+    # Description : Gather units from systemd which can not be found
+    if [ -n "${SYSTEMCTLBINARY}" -a -n "${AWKBINARY}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3834 --preqs-met ${PREQS_MET} --weight L --network NO --description "Collect service units which can not be found in systemd" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${SYSTEMCTLBINARY} list-units -t service --all | ${AWKBINARY} '{ if ($3=="not-found") { print $2 }}')
+        if [ -n "${FIND}" ]; then
+            LogText "Result: found one or more services with faulty state"
+            for I in ${FIND}; do
+                LogText "Result: service seems to be faulty (not-found) ${I}"
+                Report "systemd_service_not_found[]=$I"
+            done
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3856
+    # Description : Check if systemd-coredump is used
+    if [ -f /proc/sys/kernel/core_pattern -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3856 --preqs-met ${PREQS_MET} --weight L --network NO --description "Check if systemd-coredump is used" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        SYSTEMD_COREDUMP_USED=1
+        FIND=$(cat /proc/sys/kernel/core_pattern | grep systemd-coredump)
+        if [ -n "${FIND}" ]; then
+            LogText "Result: systemd uses systemd-coredump to handle coredumps"
+            Report "systemd_coredump_used=1"
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : PLGN-3858
+    # Description : Check if coredumps are placed on disk or in the journal
+    # Notes       : systemd 215+
+#
+#################################################################################
+#
+    # Test        : PLGN-3860
+    # Description : Query coredumps from journalctl since Yesterday
+    if [ -n "${JOURNALCTLBINARY}" -a ${SYSTEMD_COREDUMP_USED} -eq 1 -a ${SYSTEMD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no PLGN-3860 --preqs-met ${PREQS_MET} --weight L --network NO --description "Query coredumps from journals since Yesterday" --progress
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FIND=$(${JOURNALCTLBINARY} SYSLOG_IDENTIFIER=systemd-coredump --since=yesterday -o cat 2> /dev/null)
+        if [ -n "${FIND}" ]; then
+            Report "journal_coredumps_lastday=1"
+            LogText "Result: found recent coredumps"
+        else
+            Report "journal_coredumps_lastday=0"
+            LogText "Result: found no coredumps"
+        fi
+    fi
+#
+#################################################################################
+#
+
+# coredumpctl info (systemd 215+)
+# coredumpctl -1 (systemd 215+)
+# systemd-timesyncd (systemd 213+)
+# systemctl list-machines (systemd 212+)
+# systemd-journal-remote (systemd 212+)
+# systemctl list-timers (systemd 209+)
+# systemctl cat (systemd 209+)
+
+#EOF