diff --git a/CHANGELOG.md b/CHANGELOG.md
index a3522551..2d4d7ad8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,115 @@
 # Lynis Changelog
 
+## Lynis 3.0.0 (not released yet)
+
+This is a major release of Lynis and includes several big changes.
+Some of these changes may break your current usage of the tool, so test before
+deployment!
+
+### Breaking changes
+- Some commands or switches are deprecated or removed
+- Format of all profile options converted (from key:value to key=value)
+- Non-interactive by default (use --wait option to pause between groups of tests)
+
+### Security
+An important focus area for this release is on security. We added several
+measures to further tighten any possible misuse.
+
+### Added
+- Security: test PATH and warn or exit on discovery of dangerous location
+- Security: additional safeguard by testing if common system tools are available
+- Security: test parameters and arguments for presence of control characters
+- Security: filtering out unexpected characters from profiles
+- Security: test if setuid bit is set on Lynis binary
+- New function: DisplayWarning - show a warning on the screen
+- New function: Equals - compare two strings
+- New function: Readonly - mark variable read-only (security)
+- New function: SafeFile - test file type and call permission check
+- New function: SafeInput - check for safe input (security)
+- New profile option: disable-plugin - disables a single plugin
+- New profile option: ssl-certificate-paths-to-ignore - ignore a path
+- New test: CRYP-7930 - disk or file system encryption testing
+- New test: PROC-3802 - Check presence of prelink tooling
+- New report key: openssh_daemon_running
+- New command: lynis generate systemd-units
+- Measure timing of tests and report slow tests (10+ seconds)
+
+### Changed
+- Function: CheckItem - returns only exit code (ITEM_FOUND value is dropped)
+- Profiles: unused options removed
+- Profiles: message is displayed when old format "key:value" is used
+- Security: the 'nounset' (set -u) parameter is now activated by default
+- Use only locations from PATH environment variable, unless it is not defined
+- Show 'lynis generate hostids' when they are missing
+- NAME-4408 - corrected Report function call
+- NETW-3032 - small rewrite of test and extended with addrwatch
+- PROC-3602 - allow different root directory
+- PROC-3612 - show 'Not found' instead of 'OK'
+- PROC-3614 - show 'Not found' instead of 'OK'
+- SSH-7402 - detect other SSH daemons like dropbear
+- Whow changelog works again for newer versions
+- systemd service file adjusted
+- bash completion script extended
+
+---------------------------------------------------------------------------------
+
+## Lynis 2.7.5 (2019-06-24)
+
+### Added
+- Danish translation
+- Slackware end-of-life information
+- Detect BSD-style (rc.d) init in Linux systems
+- Detection of Bro and Suricata (IDS)
+
+### Changed
+- Corrected end-of-life entries for CentOS 5 and 6
+- AUTH-9204 - change name to check in /etc/passwd file for QNAP devices
+- AUTH-9268 - AIX enhancement to use correct find statement
+- FILE-6310 - Filter on correct field for AIX
+- NETW-3012 - set ss command as preferred option for Linux and changed output format
+- List of PHP ini file locations has been extended
+- Removed several pieces of the code as part of cleanup and code health
+- Extended help
+
+---------------------------------------------------------------------------------
+
+
+## Lynis 2.7.4 (2019-04-21)
+
+This is a bigger release than usual, including several new tests created by
+Capashenn (GitHub). It is a coincidence that it is released exactly one month
+after the previous version and on Easter. No easter eggs, only improvements!
+
+### Added
+- FILE-6324 - Discover XFS mount points
+- INSE-8000 - Installed inetd package
+- INSE-8100 - Installed xinetd package
+- INSE-8102 - Status of xinet daemon
+- INSE-8104 - xinetd configuration file
+- INSE-8106 - xinetd configuration for inactive daemon
+- INSE-8200 - Usage of TCP wrappers
+- INSE-8300 - Presence of rsh client
+- INSE-8302 - Presence of rsh server
+- Detect equery binary detection
+- New 'generate' command
+
+### Changed
+- AUTH-9278 - Test LDAP in all PAM components on Red Hat and other systems
+- PKGS-7410 - Add support for DPKG-based systems to gather installed kernel packages
+- PKGS-7420 - Detect toolkit to automatically download and apply upgrades
+- PKGS-7328 - Added global Zypper option --non-interactive
+- PKGS-7330 - Added global Zypper option --non-interactive
+- PKGS-7386 - Only show warning when vulnerable packages were discovered
+- PKGS-7392 - Skip test for Zypper-based systems
+- Minor changes to improve text output, test descriptions, and logging
+- Changed CentOS identifiers in end-of-life database
+- AIX enhancement for IsRunning function
+- Extended PackageIsInstalled function
+- Improve text output on AIX systems
+- Corrected lsvg binary detection
+
+---------------------------------------------------------------------------------
+
 ## Lynis 2.7.3 (2019-03-21)
 
 ### Added
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000..7f5895cd
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,27 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported          |
+| ------- | ------------------ |
+| 3.x.x   | :white_check_mark: |
+| 2.x.x   | :white_check_mark: |
+| < 2.x   | :x:                |
+
+## Reporting a Vulnerability
+
+To report a vulnerability, use security@cisofy.com
+
+See our [security page](https://cisofy.com/security/) for more details.
+
+## Preferred language
+
+English
+
+## Acknowledgments
+
+https://cisofy.com/security/#thanks
+
+## Other
+
+See the latest 'security.txt' at https://cisofy.com/.well-known/security.txt
diff --git a/db/languages/da b/db/languages/da
new file mode 100644
index 00000000..d26c1220
--- /dev/null
+++ b/db/languages/da
@@ -0,0 +1,41 @@
+ERROR_NO_LICENSE="Ingen licensnøgle konfigureret"
+ERROR_NO_UPLOAD_SERVER="Ingen upload server konfigureret"
+GEN_CHECKING="Tjekker"
+GEN_CURRENT_VERSION="Nuværende version"
+GEN_DEBUG_MODE="Fejlfindingstilstand"
+GEN_INITIALIZE_PROGRAM="Initialiserer program"
+GEN_LATEST_VERSION="Seneste version"
+GEN_PHASE="Fase"
+GEN_PLUGINS_ENABLED="Plugins aktiverede"
+GEN_UPDATE_AVAILABLE="opdatering tilgængelig"
+GEN_VERBOSE_MODE="Detaljeret tilstand"
+GEN_WHAT_TO_DO="At gøre"
+NOTE_EXCEPTIONS_FOUND="Undtagelser fundet"
+NOTE_EXCEPTIONS_FOUND_DETAILED="Nogle usædvanlige hændelser eller information var fundet"
+NOTE_PLUGINS_TAKE_TIME="Bemærk: plugins har mere omfattende tests og kan tage flere minutter at fuldføre"
+NOTE_SKIPPED_TESTS_NON_PRIVILEGED="Sprang over tests på grund af ikke-privilegeret tilstand"
+SECTION_CUSTOM_TESTS="Brugerdefinerede Tests"
+SECTION_MALWARE="Malware"
+SECTION_MEMORY_AND_PROCESSES="Hukommelse og Processer"
+STATUS_DISABLED="DEAKTIVERET"
+STATUS_DONE="FÆRDIG"
+STATUS_ENABLED="AKTIVERET"
+STATUS_NOT_ENABLED="IKKE AKTIVERET"
+STATUS_ERROR="FEJL"
+STATUS_FOUND="FUNDET"
+STATUS_YES="JA"
+STATUS_NO="NEJ"
+STATUS_OFF="FRA"
+STATUS_OK="OK"
+STATUS_ON="TIL"
+STATUS_NONE="INGEN"
+STATUS_NOT_FOUND="IKKE FUNDET"
+STATUS_NOT_RUNNING="KØRER IKKE"
+STATUS_RUNNING="KØRER"
+STATUS_SKIPPED="SPRUNGET OVER"
+STATUS_SUGGESTION="FORSLAG"
+STATUS_UNKNOWN="UKENDT"
+STATUS_WARNING="ADVARSEL"
+STATUS_WEAK="SVAG"
+TEXT_YOU_CAN_HELP_LOGFILE="Du kan hjælpe ved at bidrage med din logfil"
+TEXT_UPDATE_AVAILABLE="opdatering tilgængelig"
diff --git a/db/software-eol.db b/db/software-eol.db
index 39edb2da..7b511237 100644
--- a/db/software-eol.db
+++ b/db/software-eol.db
@@ -11,9 +11,9 @@
 #
 # CentOS
 #
-os:CentOS 5:2017-03-31:1490911200:
-os:CentOS 6:2020-11-30:1606690800:
-os:CentOS 7:2024-06-30:1719698400:
+os:CentOS release 5:2017-03-31:1490911200:
+os:CentOS release 6:2020-11-30:1606690800:
+os:CentOS Linux release 7:2024-06-30:1719698400:
 #
 # FreeBSD - https://www.freebsd.org/security/unsupported.html
 #
@@ -42,5 +42,21 @@ os:Ubuntu 16.10:2017-07-01:1498860000:
 os:Ubuntu 17.04:2018-01-01:1514761200:
 os:Ubuntu 17.10:2018-07-01:1530396000:
 os:Ubuntu 18.04:2023-05-01:1682892000:
-os:Ubuntu 18.10:2019-07-01:1561932000:
-os:Ubuntu 19.04:2020-01-01:1577833200:
\ No newline at end of file
+os:Ubuntu 18.10:2019-07-18:1563400800:
+os:Ubuntu 19.04:2020-01-01:1577833200:
+#
+# Slackware - https://en.wikipedia.org/wiki/Slackware#Releases
+#
+os:Slackware Linux 8.1:2012-08-01:1343768400:
+os:Slackware Linux 9.0:2012-08-01:1343768400:
+os:Slackware Linux 9.1:2012-08-01:1343768400:
+os:Slackware Linux 10.0:2012-08-01:1343768400:
+os:Slackware Linux 10.1:2012-08-01:1343768400:
+os:Slackware Linux 10.2:2012-08-01:1343768400:
+os:Slackware Linux 11.0:2012-08-01:1343768400:
+os:Slackware Linux 12.0:2012-08-01:1343768400:
+os:Slackware Linux 12.1:2013-12-09:1386540000:
+os:Slackware Linux 12.2:2013-12-09:1386540000:
+os:Slackware Linux 13.0:2018-07-05:1530738000:
+os:Slackware Linux 13.1:2018-07-05:1530738000:
+os:Slackware Linux 13.37:2018-07-05:1530738000:
diff --git a/db/tests.db b/db/tests.db
index 641ea927..cd978c50 100644
--- a/db/tests.db
+++ b/db/tests.db
@@ -84,6 +84,7 @@ CONT-8107:test:performance:containers::Check number of unused Docker containers:
 CONT-8108:test:security:containers::Check file permissions for Docker files:
 CORE-1000:test:performance:system_integrity::Check all system binaries:
 CRYP-7902:test:security:crypto::Check expire date of SSL certificates:
+CRYP-7930:test:security:crypto::Determine if system uses disk or file encryption:
 DNS-1600:test:security:dns::Validating that the DNSSEC signatures are checked:
 DBS-1804:test:security:databases::Checking active MySQL process:
 DBS-1816:test:security:databases::Checking MySQL root password:
@@ -169,11 +170,17 @@ HTTP-6712:test:security:webservers::Check nginx access logging:
 HTTP-6714:test:security:webservers::Check for missing error logs in nginx:
 HTTP-6716:test:security:webservers::Check for debug mode on error log in nginx:
 HTTP-6720:test:security:webservers::Check Nginx log files:
-INSE-8002:test:security:insecure_services::Check for enabled inet daemon:
-INSE-8004:test:security:insecure_services::Check for enabled inet daemon:
-INSE-8006:test:security:insecure_services::Check configuration of inetd when disabled:
+INSE-8000:test:security:insecure_services::Installed inetd package:
+INSE-8002:test:security:insecure_services::Status of inet daemon:
+INSE-8004:test:security:insecure_services::Presence of inetd configuration file:
+INSE-8006:test:security:insecure_services::Check configuration of inetd when it is disabled:
 INSE-8016:test:security:insecure_services::Check for telnet via inetd:
 INSE-8050:test:security:insecure_services:MacOS:Check for insecure services on macOS systems:
+INSE-8100:test:security:insecure_services::Installed xinetd package:
+INSE-8116:test:security:insecure_services::Insecure services enabled via xinetd:
+INSE-8200:test:security:insecure_services::Usage of TCP wrappers:
+INSE-8300:test:security:insecure_services::Presence of rsh client:
+INSE-8302:test:security:insecure_services::Presence of rsh server:
 KRNL-5622:test:security:kernel:Linux:Determine Linux default run level:
 KRNL-5677:test:security:kernel:Linux:Check CPU options and support:
 KRNL-5695:test:security:kernel:Linux:Determine Linux kernel version and release number:
@@ -319,6 +326,7 @@ PKGS-7393:test:security:ports_packages::Check for Gentoo vulnerable packages:
 PKGS-7394:test:security:ports_packages:Linux:Check for Ubuntu updates:
 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:
 PRNT-2302:test:security:printers_spools:FreeBSD:Check for printcap consistency:
 PRNT-2304:test:security:printers_spools::Check cupsd status:
 PRNT-2306:test:security:printers_spools::Check CUPSd configuration file:
@@ -332,6 +340,7 @@ PROC-3602:test:security:memory_processes:Linux:Checking /proc/meminfo for memory
 PROC-3604:test:security:memory_processes:Solaris:Query prtconf for memory details:
 PROC-3612:test:security:memory_processes::Check dead or zombie processes:
 PROC-3614:test:security:memory_processes::Check heavy IO waiting based processes:
+PROC-3802:test:security:memory_processes::Check presence of prelink tooling:
 RBAC-6272:test:security:mac_frameworks::Check grsecurity presence:
 SCHD-7702:test:security:scheduling::Check status of cron daemon:
 SCHD-7704:test:security:scheduling::Check crontab/cronjobs:
diff --git a/default.prf b/default.prf
index ef474b1f..1431beb6 100644
--- a/default.prf
+++ b/default.prf
@@ -1,30 +1,33 @@
 #################################################################################
 #
 #
-# Lynis - Scan Profile (default)
-#
-# This is the default profile and contains default values.
+# Lynis - Default scan profile
 #
 #
 #################################################################################
 #
 #
-# SUGGESTION
+# This profile provides Lynis with most of its initial values to perform a
+# system audit.
+#
+#
+# WARNINGS
 # ----------
 #
-# Do NOT make changes to this file, instead copy your preferred settings to
-# custom.prf and put it in the same directory as default.prf
+# Do NOT make changes to this file. Instead, copy only your changes into
+# the file custom.prf and put it in the same directory as default.prf
 #
 # To discover where your profiles are located: lynis show profiles
 #
 #
+# Lynis performs a strict check on profiles to avoid the inclusion of
+# possibly harmful injections. See include/profiles for details.
+#
+#
 #################################################################################
 #
 # All empty lines or with the # prefix will be skipped
 #
-# More information about this plugin can be found in the documentation:
-# https://cisofy.com/documentation/lynis/
-#
 #################################################################################
 
 # Use colored output
@@ -33,6 +36,9 @@ colors=yes
 # Compressed uploads (set to zero when errors with uploading occur)
 compressed-uploads=yes
 
+# Amount of connections in WAIT state before reporting it as a suggestion
+#connections-max-wait-state=5000
+
 # Debug mode (for debugging purposes, extra data logged to screen)
 #debug=yes
 
@@ -42,20 +48,27 @@ error-on-warnings=no
 # Use Lynis in your own language (by default auto-detected)
 language=
 
-# Lynis Enterprise license key
-license-key=
+# Log tests from another guest operating system (default: yes)
+#log-tests-incorrect-os=yes
+
+# Define if available NTP daemon is configured as a server or client on the network
+# values: server or client (default: client)
+#ntpd-role=client
 
 # Defines the role of the system (personal, workstation or server)
 machine-role=server
 
+# Ignore some stratum 16 hosts (for example when running as time source itself)
+#ntp-ignore-stratum-16-peer=127.0.0.1
+
 # Profile name, will be used as title/description
 profile-name=Default Audit Template
 
 # Number of seconds to pause between every test (0 is no pause)
 pause-between-tests=0
 
-# Enable quick mode (no waiting for keypresses, same as --quick option)
-quick=no
+# Quick mode (do not wait for keypresses)
+quick=yes
 
 # Refresh software repositories to help detecting vulnerable packages
 refresh-repositories=yes
@@ -76,39 +89,20 @@ skip-plugins=no
 #skip-test=SSH-7408:loglevel
 #skip-test=SSH-7408:permitrootlogin
 
+# Skip Lynis upgrade availability test (default: no)
+#skip-upgrade-test=yes
+
+# Locations where to search for SSL certificates (separate paths with a colon)
+ssl-certificate-paths=/etc/apache2:/etc/dovecot:/etc/httpd:/etc/letsencrypt:/etc/pki:/etc/postfix:/etc/ssl:/opt/psa/var/certificates:/usr/local/psa/var/certificates:/usr/local/share/ca-certificates:/var/www:/srv/www
+ssl-certificate-paths-to-ignore=/etc/letsencrypt/archive:
+
 # Scan type - how deep the audit should be (light, normal or full)
 test-scan-mode=full
 
-# Upload data to central server
-upload=no
-
-# The hostname/IP address to receive the data
-upload-server=
-
-# Provide options to cURL (or other upload tool) when uploading data.
-# upload-options=--insecure   --> use HTTPS, but skip certificate check (e.g. self-signed)
-upload-options=
-
 # Verbose output
 verbose=no
 
 
-#################################################################################
-#
-# Upgrade and updating
-# --------------------
-#
-# The old settings to do automatic updating are deprecated. It is suggested to
-# use a package or deploy your the tarball via a custom script.
-#
-# The latest packages can be found at: https://packages.cisofy.com
-#
-#################################################################################
-
-# Skip Lynis upgrade availability test (default: no)
-#skip-upgrade-test=yes
-
-
 #################################################################################
 #
 # Plugins
@@ -119,10 +113,11 @@ verbose=no
 # - Nothing happens if plugin isn't available
 # - There is no order in execution of plugins
 # - See documentation about how to use plugins and phases
+# - Some are for Lynis Enterprise users only
 #
 #################################################################################
 
-# Lynis Plugins (some are for Lynis Enterprise users only)
+# Lynis plugins to enable
 plugin=authentication
 plugin=compliance
 plugin=configuration
@@ -149,17 +144,22 @@ plugin=system-integrity
 plugin=systemd
 plugin=users
 
+# Disable a particular plugin (will overrule an enabled plugin)
+#disable-plugin=authentication
 
 #################################################################################
 #
 # Kernel options
 # ---------------
-# sysctl:<sysctl Key>:<Expected Value>:<Hardening Points>:<Description>:
+# configdate=, followed by:
 #
-# Sysctl key       = name
-# Expected value   = value of sysctl key
-# Hardening points = Number of hardening points. For most keys 1 HP will be suitable
-# Description      = Text description of key
+# - Type                     = Set to 'sysctl'
+# - Setting                  = value of sysctl key (e.g. kernel.sysrq)
+# - Expected value           = Preferred value for key (e.g. 0)
+# - Hardening Points         = Number of hardening points (typically 1 point per key) (1)
+# - Description              = Textual description about the sysctl key(Disable magic SysRQ)
+# - Related file or command  = For example, sysctl -a to retrieve more details
+# - Solution field           = Specifies more details or where to find them (url:URL, text:TEXT, or -)
 #
 #################################################################################
 
@@ -269,86 +269,58 @@ config-data=sysctl;security.bsd.hardlink_check_gid;1;1;Unprivileged processes ar
 config-data=sysctl;security.bsd.hardlink_check_uid;1;1;Unprivileged processes are not allowed to create hard links to files which are owned by other users;-;category:security;
 
 
-#################################################################################
-#
-# Apache options
-# columns: (1)apache : (2)option : (3)value
-#
-#################################################################################
-
-apache:ServerTokens:Prod:
-
-
-#################################################################################
-#
-# OpenLDAP options
-# columns: (1)openldap : (2)file : (3)option : (4)expected value(s)
-#
-#################################################################################
-
-openldap:slapd.conf:permissions:640-600:
-openldap:slapd.conf:owner:ldap-root:
-
-
-
-
-#################################################################################
-#
-# NTP options
-#
-#################################################################################
-
-# Ignore some stratum 16 hosts (for example when running as time source itself)
-#ntp-ignore-stratum-16-peer=127.0.0.1
-
-
-#################################################################################
-#
-# File/directories permissions (currently not used yet)
-#
-#################################################################################
-
-# Scan for exact file name match
-#[scanfiles]
-#scanfile:/etc/rc.conf:FreeBSD configuration:
-
-# Scan for exact directory name match
-#[scandirs]
-#scandir:/etc:/etc directory:
-
-
 #################################################################################
 #
 # permfile
 # ---------------
-# permfile:file name:file permissions:owner:group:action:
+# permfile=file name:file permissions:owner:group:action:
 # Action = NOTICE or WARN
 # Examples:
-# permfile:/etc/test1.dat:600:root:wheel:NOTICE:
-# permfile:/etc/test1.dat:640:root:-:WARN:
+# permfile=/etc/test1.dat:600:root:wheel:NOTICE:
+# permfile=/etc/test1.dat:640:root:-:WARN:
 #
 #################################################################################
 
-#permfile:/etc/inetd.conf:rw-------:root:-:WARN:
-#permfile:/etc/fstab:rw-r--r--:root:-:WARN:
-permfile:/etc/lilo.conf:rw-------:root:-:WARN:
-
+#permfile=/etc/inetd.conf:rw-------:root:-:WARN:
+#permfile=/etc/fstab:rw-r--r--:root:-:WARN:
+permfile=/boot/grub2/grub.cfg:rw-------:root:root:WARN:
+permfile=/boot/grub/grub.cfg:rw-------:root:root:WARN:
+permfile=/boot/grub2/user.cfg:rw-------:root:root:WARN:
+permfile=/etc/at.allow:rw-------:root:-:WARN:
+permfile=/etc/at.deny:rw-------:root:-:WARN:
+permfile=/etc/cron.allow:rw-------:root:-:WARN:
+permfile=/etc/cron.deny:rw-------:root:-:WARN:
+permfile=/etc/crontab:rw-------:root:-:WARN:
+permfile=/etc/group:rw-r--r--:root:-:WARN:
+permfile=/etc/group-:rw-r--r--:root:-:WARN:
+permfile=/etc/gshadow:---------:root:-:WARN:
+permfile=/etc/gshadow-:---------:root:-:WARN:
+permfile=/etc/hosts.allow:rw-r--r--:root:root:WARN:
+permfile=/etc/hosts.deny:rw-r--r--:root:root:WARN:
+permfile=/etc/issue:rw-r--r--:root:root:WARN:
+permfile=/etc/issue.net:rw-r--r--:root:root:WARN:
+permfile=/etc/lilo.conf:rw-------:root:-:WARN:
+permfile=/etc/motd:rw-r--r--:root:root:WARN:
+permfile=/etc/passwd:rw-r--r--:root:-:WARN:
+permfile=/etc/passwd-:rw-r--r--:root:-:WARN:
+permfile=/etc/shadow:---------:root:-:WARN:
+permfile=/etc/shadow-:---------:root:-:WARN:
+permfile=/etc/ssh/sshd_config:rw-------:root:-:WARN:
 
 #################################################################################
 #
 # permdir
 # ---------------
-# permdir:directory name:file permissions:owner:group:action when permissions are different:
+# permdir=directory name:file permissions:owner:group:action when permissions are different:
 #
 #################################################################################
 
-permdir:/root/.ssh:rwx------:root:-:WARN:
-
-# Scan for a program/binary in BINPATHs
-#scanbinary:Rootkit Hunter:rkhunter:
-
-# Amount of connections in WAIT state before reporting it as a suggestion
-#connections-max-wait-state=5000
+permdir=/root/.ssh:rwx------:root:-:WARN:
+permdir=/etc/cron.d:rwx------:root:root:WARN:
+permdir=/etc/cron.daily:rwx------:root:root:WARN:
+permdir=/etc/cron.hourly:rwx------:root:root:WARN:
+permdir=/etc/cron.weekly:rwx------:root:root:WARN:
+permdir=/etc/cron.monthly:rwx------:root:root:WARN:
 
 
 # Ignore some specific home directories
@@ -356,12 +328,6 @@ permdir:/root/.ssh:rwx------:root:-:WARN:
 # checks, like file permissions, SSH and other configuration files
 #ignore-home-dir=/home/user
 
-# Do not log tests with another guest operating system (default: yes)
-#log-tests-incorrect-os=no
-
-# Define if available NTP daemon is configured as a server or client on the network
-# values: server or client (default: client)
-#ntpd-role=client
 
 # Allow promiscuous interfaces
 #   <option>:<promiscuous interface name>:<description>:
@@ -395,21 +361,10 @@ permdir:/root/.ssh:rwx------:root:-:WARN:
 
 
 
-#################################################################################
-#
-# SSL certificates
-#
-#################################################################################
-
-# Locations where to search for SSL certificates
-ssl-certificate-paths=/etc/apache2:/etc/dovecot:/etc/httpd:/etc/letsencrypt:/etc/pki:/etc/postfix:/etc/ssl:/opt/psa/var/certificates:/usr/local/psa/var/certificates:/usr/local/share/ca-certificates:/var/www:/srv/www
-
-
-
 #################################################################################
 #
 # Lynis Enterprise options
-# -----------------
+# ------------------------
 #
 #################################################################################
 
@@ -423,6 +378,9 @@ ssl-certificate-paths=/etc/apache2:/etc/dovecot:/etc/httpd:/etc/letsencrypt:/etc
 #hostid=40-char-hash
 #hostid2=64-char-hash
 
+# Lynis Enterprise license key
+license-key=
+
 # Proxy settings
 # Protocol (http, https, socks5)
 #proxy-protocol=https
@@ -443,9 +401,18 @@ compliance-standards=cis,hipaa,iso27001,pci-dss
 # Provide the name of the customer/client
 #system-customer-name=mycustomer
 
+# Upload data to central server
+upload=no
+
+# The hostname/IP address to receive the data
+upload-server=
+
+# Provide options to cURL (or other upload tool) when uploading data.
+# upload-options=--insecure (use HTTPS, but skip certificate check for self-signed certificates)
+upload-options=
+
 # Link one or more tags to a system
 #tags=db,production,ssn-1304
 
 
-
 #EOF
diff --git a/developer.prf b/developer.prf
index 856596a8..624e06e6 100644
--- a/developer.prf
+++ b/developer.prf
@@ -3,6 +3,5 @@
 
 debug=yes
 developer-mode=yes
-quick=yes
 strict=yes
 verbose=yes
diff --git a/extras/bash_completion.d/lynis b/extras/bash_completion.d/lynis
index 235a848a..8732ede3 100644
--- a/extras/bash_completion.d/lynis
+++ b/extras/bash_completion.d/lynis
@@ -1,6 +1,6 @@
 # bash completion for lynis
 
-# version 1.0.0 (22 September 2014)
+# version 1.0.1 (2019-07-13)
 # Michael Boelen <michael.boelen@cisofy.com>
 
 # lynis(8) completion
@@ -10,7 +10,7 @@ _lynis()
     # opts nodig nosig
 
     COMPREPLY=()
-    _get_comp_words_by_ref cur prev
+    _get_comp_words_by_ref cur prev words
 
     if [ $COMP_CWORD -eq 1 ]; then
         # first parameter on line
@@ -19,24 +19,134 @@ _lynis()
                 COMPREPLY=( $( compgen -W '--help --info --version' -- "$cur" ) )
                 ;;
             *)
-                COMPREPLY=( $( compgen -W 'audit --help --info --version' -- "$cur" ) )
+                COMPREPLY=( $( compgen -W 'audit generate show' -- "$cur" ) )
                 ;;
         esac
-
-    return 0
+        return 0
+    elif [ $COMP_CWORD -eq 4 ]; then
+        # Stop after some specifics
+        if [ "${COMP_WORDS[1]}" = "show" -a "${COMP_WORDS[2]}" = "details" ]; then
+            return 0
+        fi
     fi
 
+    # Check previous argument to share the available options
     case $prev in
         audit)
             COMPREPLY=( $( compgen -W 'dockerfile system ' -- "$cur" ) )
             ;;
+
         show)
-            COMPREPLY=( $( compgen -W 'help version ' -- "$cur" ) )
+            COMPREPLY=( $( compgen -W 'categories changelog commands dbdir details environment eol groups help hostids includedir language license logfile man options os pidfile plugindir profiles release releasedate report settings tests  version workdir ' -- "$cur" ) )
             ;;
 
+        # Related items to show (lynis show XYZ)
+        categories)
+            return 0
+            ;;
+        changelog)
+            return 0
+            ;;
+        commands)
+            return 0
+            ;;
+        dbdir)
+            return 0
+            ;;
+        details)
+            local dbfile=""
+            local dirs="/data/development/lynis /usr/local/lynis /usr/share/lynis"
+            for d in ${dirs}; do
+                if [ -f "${d}/db/tests.db" ]; then
+                    local dbfile="/data/development/lynis/db/tests.db"
+                fi
+            done
+            if [ -f "${dbfile}" ]; then
+                local suggestions=($(compgen -W "$(awk -F: '$1 ~ /^[A-Z]/ {print $1}' ${dbfile})" -- "${cur}"))
+                COMPREPLY=("${suggestions[@]}")
+            else
+                COMPREPLY=($(compgen -W "TEST-1234" -- "$cur"))
+            fi
+            ;;
+        environment)
+            return 0
+            ;;
+        eol)
+            return 0
+            ;;
+        groups)
+            return 0
+            ;;
+        help)
+            return 0
+            ;;
+        hostids)
+            if [ "${COMP_WORDS[1]}" = "generate" -a "${COMP_WORDS[2]}" = "hostids" ]; then
+                COMPREPLY=($(compgen -W "save" -- "$cur"))
+            else
+                return 0
+            fi
+            ;;
+        includedir)
+            return 0
+            ;;
+        language)
+            return 0
+            ;;
+        license)
+            return 0
+            ;;
+        logfile)
+            return 0
+            ;;
+        man)
+            return 0
+            ;;
+        options)
+            return 0
+            ;;
+        os)
+            return 0
+            ;;
+        pidfile)
+            return 0
+            ;;
+        plugindir)
+            return 0
+            ;;
+        profiles)
+            return 0
+            ;;
+        release)
+            return 0
+            ;;
+        releasedate)
+            return 0
+            ;;
+        report)
+            return 0
+            ;;
+        settiings)
+            return 0
+            ;;
+        tests)
+            return 0
+            ;;
+        version)
+            return 0
+            ;;
+        workdir)
+            return 0
+            ;;
+
+        generate)
+            COMPREPLY=( $( compgen -W 'hostids ' -- "$cur" ) )
+            ;;
+
+        # Options
         --auditor)
             COMPREPLY=( '"Mr. Auditor"' )
-            return 0
+            #return 0
             ;;
         --check-update|--help|--info|--version)
             # all other options are noop with this command
diff --git a/extras/systemd/lynis.service b/extras/systemd/lynis.service
index 7ecc36ad..21432c22 100644
--- a/extras/systemd/lynis.service
+++ b/extras/systemd/lynis.service
@@ -5,19 +5,26 @@
 #################################################################################
 #
 # - Adjust path to link to location where Lynis binary is installed
-# - Place this file together with the timer file in systemd directory
-# - Run: systemctl enable lynis.service
+#
+# - Place this file together with the lynis.timer file in the related
+#   systemd directory (e.g. /etc/systemd/system/)
+#
+# - See details in lynis.timer file
 #
 #################################################################################
 
 [Unit]
-Description=Lynis security audit and vulnerability scan
+Description=Security audit and vulnerability scanner
+Documentation=https://cisofy.com/docs/
 
 [Service]
 Nice=19
 IOSchedulingClass=best-effort
 IOSchedulingPriority=7
 Type=simple
-ExecStart=/path/to/lynis -c --cronjob
+ExecStart=/path/to/lynis audit system --cronjob
+
+[Install]
+WantedBy=multi-user.target
 
 #EOF
diff --git a/extras/systemd/lynis.timer b/extras/systemd/lynis.timer
index 169b3c17..83f5c144 100644
--- a/extras/systemd/lynis.timer
+++ b/extras/systemd/lynis.timer
@@ -4,17 +4,23 @@
 #
 #################################################################################
 #
-# - Place this file together with the service file in systemd directory
-# - Run: systemctl enable lynis.timer
-#        systemctl start lynis.service
+# - Place this file together with the lynis.service file in the related
+#   systemd directory (e.g. /etc/systemd/system)
+#
+# - Tell systemd you made changes
+#   systemctl daemon-reload
+#
+# - Enable and start the timer (so no reboot is needed):
+#   systemctl enable --now lynis.timer
 #
 #################################################################################
 
 [Unit]
-Description=Daily run for Lynis security audit and vulnerability scan
+Description=Daily timer for the Lynis security audit and vulnerability scanner
 
 [Timer]
 OnCalendar=daily
+RandomizedDelaySec=1800
 Persistent=false
 
 [Install]
diff --git a/include/binaries b/include/binaries
index 18b54b2a..d894caf9 100644
--- a/include/binaries
+++ b/include/binaries
@@ -42,18 +42,39 @@
         Display --indent 2 --text "- Checking system binaries..."
         LogText "Status: Starting binary scan..."
 
-        # Test if our PATH variable provides a set of paths
-        # If so, reverse the order. If we discover the same binary multiple times, the one first in PATH
-        # should be used.
-        # If PATH is empty, we use the predefined list in include/consts. Common paths first, then followed
-        # by more specific paths. This helps on the slightly ancient UNIX derivatives.
+        # Notes:
+        # - If PATH is empty, we use the predefined list in include/consts
+        # - Common paths first, then followed by more specific paths. This helps on the slightly ancient UNIX derivatives.
+        # - Avoid sorting the path list, as this might result in incorrect order of finding binaries (e.g. awk binary)
+
+        # Test if our PATH variable provides a set of paths. If so, reverse the order. If we discover the same binary
+        # multiple times, the one first in PATH should be used.
         if [ ! -z "${PATH}" ]; then
             PATH_REVERSED=$(echo ${PATH} | awk -F: '{ for (i=NF; i>1; i--) printf("%s ",$i); print $1; }')
-            BIN_PATHS=$(echo "${PATH_REVERSED} ${BIN_PATHS}" | tr ':' ' ')
+            BIN_PATHS=$(echo "${PATH_REVERSED}" | tr ':' ' ')
         fi
 
-        # Avoid sorting, as this might result in incorrect order of finding binaries (e.g. awk binary)
-        #SORTED_BIN_PATHS=$(echo ${BIN_PATHS} | tr ' ' '\n' | sort | uniq | tr '\n' ' ')
+        # First test available locations that may be suspicious or dangerous
+        for SCANDIR in ${BIN_PATHS}; do
+            FOUND=0
+            if [ "${SCANDIR}" = "." ]; then FOUND=1; MSG="Found single dot (.) in PATH"
+            elif [ "${SCANDIR}" = ".." ]; then FOUND=1; MSG="Found double dot (..) in PATH"
+            elif echo ${SCANDIR} | grep '^\.\.' > /dev/null; then FOUND=1; MSG="Found path starting with double dot (..) in PATH"
+            elif echo ${SCANDIR} | grep '^[a-zA-Z]' > /dev/null; then FOUND=1; MSG="Found relative path in PATH"
+            fi
+            if [ ${FOUND} -eq 1 ]; then
+                # Stop execution if privileged, otherwise continue but warn user
+                if [ ${PRIVILEGED} -eq 1 ]; then
+                    ExitFatal "Possible riskful location (${SCANDIR}) in PATH discovered. Quitting..."
+                else
+                    Display --indent 4 --text "Warning: suspicious location (${SCANDIR}) in PATH"
+                    ReportWarning "${TEST_NO}" "Possible riskful location in PATH discovered" "text:${MSG}"
+                    sleep 1
+                fi
+            fi
+        done
+
+        # Now perform binary detection
         for SCANDIR in ${BIN_PATHS}; do
             LogText "Test: Checking binaries in directory ${SCANDIR}"
             ORGPATH=""
@@ -99,6 +120,7 @@
                             afick.pl)               AFICKBINARY=${BINARY};             LogText "  Found known binary: afick (file integrity checker) - ${BINARY}" ;;
                             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}" ;;
                             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}" ;;
@@ -109,6 +131,7 @@
                             base64)                 BASE64BINARY="${BINARY}";          LogText "  Found known binary: base64 (encoding tool) - ${BINARY}" ;;
                             blkid)                  BLKIDBINARY="${BINARY}";           LogText "  Found known binary: blkid (information about block devices) - ${BINARY}" ;;
                             bootctl)                BOOTCTLBINARY="${BINARY}";         LogText "  Found known binary: bootctl (systemd-boot manager utility) - ${BINARY}" ;;
+                            bro)                    BROBINARY="${BINARY}";             LogText "  Found known binary: bro (IDS) - ${BINARY}" ;;
                             cat)                    CAT_BINARY="${BINARY}";            LogText "  Found known binary: cat (generic file handling) - ${BINARY}" ;;
                             cc)                     CCBINARY="${BINARY}";              COMPILER_INSTALLED=1;  LogText "  Found known binary: cc (compiler) - ${BINARY}" ;;
                             chkconfig)              CHKCONFIGBINARY=${BINARY};         LogText "  Found known binary: chkconfig (administration tool) - ${BINARY}" ;;
@@ -131,7 +154,8 @@
                             domainname)             DOMAINNAMEBINARY="${BINARY}";      LogText "  Found known binary: domainname (NIS domain) - ${BINARY}" ;;
                             dpkg)                   DPKGBINARY="${BINARY}";            LogText "  Found known binary: dpkg (package management) - ${BINARY}" ;;
                             egrep)                  EGREPBINARY=${BINARY};             LogText "  Found known binary: egrep (text search) - ${BINARY}" ;;
-                            exim)                   EXIMBINARY="${BINARY}";            EXIMVERSION=$(${BINARY} -bV | grep 'Exim version' | awk '{ print $3 }' | xargs); LogText "Found ${BINARY} (version ${EXIMVERSION})" ;;
+                            equery)                 EQUERYBINARY="${BINARY}";          LogText "  Found known binary: query (package manager) - ${BINARY}" ;;
+                            exim)                   EXIMBINARY="${BINARY}";            EXIMVERSION=$(${BINARY} -bV | grep 'Exim version' | awk '{ print $3 }' | xargs); LogText "  Found known binary ${BINARY} (version ${EXIMVERSION})" ;;
                             fail2ban-server)        FAIL2BANBINARY="${BINARY}";        LogText "  Found known binary: fail2ban (IPS tool) - ${BINARY}" ;;
                             file)                   FILEBINARY="${BINARY}";            LogText "  Found known binary: file (file type detection) - ${BINARY}" ;;
                             find)                   FINDBINARY="${BINARY}";            LogText "  Found known binary: find (search tool) - ${BINARY}" ;;
@@ -164,7 +188,7 @@
                             lsattr)                 LSATTRBINARY="${BINARY}";          LogText "  Found known binary: lsattr (file attributes) - ${BINARY}" ;;
                             lsmod)                  LSMODBINARY="${BINARY}";           LogText "  Found known binary: lsmod (kernel modules) - ${BINARY}" ;;
                             lsof)                   LSOFBINARY="${BINARY}";            LogText "  Found known binary: lsof (open files) - ${BINARY}" ;;
-                            lsvg)                   LVSGBINARY=${BINARY};              LogText "  Found known binary: lsvg (volume manager) - ${BINARY}" ;;
+                            lsvg)                   LSVGBINARY=${BINARY};              LogText "  Found known binary: lsvg (volume manager) - ${BINARY}" ;;
                             lvdisplay)              LVDISPLAYBINARY="${BINARY}";       LogText "  Found known binary: lvdisplay (LVM tool) - ${BINARY}" ;;
                             lynx)                   LYNXBINARY="${BINARY}";            LYNXVERSION=$(${BINARY} -version | grep "^Lynx Version" | cut -d ' ' -f3); LogText "Found known binary: lynx (browser) - ${BINARY} (version ${LYNXVERSION})" ;;
                             maldet)                 LMDBINARY="${BINARY}";             MALWARE_SCANNER_INSTALLED=1;           LogText "  Found known binary: maldet (Linux Malware Detect, malware scanner) - ${BINARY}" ;;
@@ -225,6 +249,7 @@
                             sha1|sha1sum|shasum)    SHA1SUMBINARY="${BINARY}";         LogText "  Found known binary: sha1/sha1sum/shasum (crypto hashing) - ${BINARY}" ;;
                             sha256|sha256sum)       SHA256SUMBINARY="${BINARY}";       LogText "  Found known binary: sha256/sha256sum (crypto hashing) - ${BINARY}" ;;
                             ssh-keyscan)            SSHKEYSCANBINARY="${BINARY}";      LogText "  Found known binary: ssh-keyscan (scanner for SSH keys) - ${BINARY}" ;;
+                            suricata)               SURICATABINARY="${BINARY}";        LogText "  Found known binary: suricata (IDS) - ${BINARY}" ;;
                             sysctl)                 SYSCTLBINARY="${BINARY}";          LogText "  Found known binary: sysctl (kernel parameters) - ${BINARY}" ;;
                             syslog-ng)              SYSLOGNGBINARY="${BINARY}";        SYSLOGNGVERSION=$(${BINARY} -V 2>&1 | grep "^syslog-ng" | awk '{ print $2 }'); LogText "Found ${BINARY} (version ${SYSLOGNGVERSION})" ;;
                             systemctl)              SYSTEMCTLBINARY="${BINARY}";       LogText "  Found known binary: systemctl (client to systemd) - ${BINARY}" ;;
@@ -254,6 +279,7 @@
                 LogText "Result: Directory ${SCANDIR} does NOT exist"
             fi
         done
+
         # unset SORTED_BIN_PATHS
         BINARY_SCAN_FINISHED=1
         BINARY_PATHS_FOUND=$(echo ${BINARY_PATHS_FOUND} | sed 's/^, //g' | sed 's/ //g')
@@ -261,10 +287,35 @@
         LogText "Result: found ${COUNT} binaries"
         Report "binaries_count=${COUNT}"
         Report "binary_paths=${BINARY_PATHS_FOUND}"
+
+        # Test if the basic system tools are defined. These will be used during the audit.
+        [ "${AWKBINARY:-}" ] || ExitFatal "awk binary not found"
+        [ "${CUTBINARY:-}" ] || ExitFatal "cut binary not found"
+        [ "${EGREPBINARY:-}" ] || ExitFatal "grep binary not found"
+        [ "${FINDBINARY:-}" ] || ExitFatal "find binary not found"
+        [ "${GREPBINARY:-}" ] || ExitFatal "grep binary not found"
+        [ "${HEADBINARY:-}" ] || ExitFatal "head binary not found"
+        [ "${LSBINARY:-}" ] || ExitFatal "ls binary not found"
+        [ "${PSBINARY:-}" ] || ExitFatal "ps binary not found"
+        [ "${SEDBINARY:-}" ] || ExitFatal "sed binary not found"
+        [ "${SORTBINARY:-}" ] || ExitFatal "sort binary not found"
+        [ "${TRBINARY:-}" ] || ExitFatal "tr binary not found"
+        [ "${UNIQBINARY:-}" ] || ExitFatal "uniq binary not found"
+        [ "${WCBINARY:-}" ] || ExitFatal "wc binary not found"
+
+        # Test a few other tools that we did not specifically define (yet)
+        TOOLS="xxd"
+        for T in ${TOOLS}; do
+            DATA=$(type ${T})
+            if [ $? -gt 0 ]; then ExitFatal "${T} binary not found"; fi
+        done
+
+
     else
         LogText "Result: checking of binaries skipped in this mode"
     fi
 
+
 #
 #================================================================================
 # Lynis - Security Auditing and System Hardening for Linux and UNIX - https://cisofy.com
diff --git a/include/consts b/include/consts
index 671ed1ca..67a18733 100644
--- a/include/consts
+++ b/include/consts
@@ -46,6 +46,7 @@ unset LANG
 #
 # == Variable initializing ==
 #
+    APTBINARY=""
     ARCH_AUDIT_BINARY=""
     AUDITORNAME=""
     AUDITCTLBINARY=""
@@ -70,6 +71,7 @@ unset LANG
     CHKCONFIGBINARY=""
     CLAMCONF_BINARY=""
     CLAMSCANBINARY=""
+    CLANGBINARY=""
     COLORS=1
     COMPLIANCE_ENABLE_CIS=0
     COMPLIANCE_ENABLE_HIPAA=0
@@ -84,6 +86,7 @@ unset LANG
     CONTAINER_TYPE=""
     CREATE_REPORT_FILE=1
     CSUMBINARY=""
+    CURRENT_TS=0
     CUSTOM_URL_APPEND=""
     CUSTOM_URL_PREPEND=""
     CUSTOM_URL_PROTOCOL=""
@@ -94,13 +97,17 @@ unset LANG
     DEBSECANBINARY=""
     DEBSUMSBINARY=""
     DEVELOPER_MODE=0
+    DISABLED_PLUGINS=""
     DISCOVERED_BINARIES=""
     DMIDECODEBINARY=""
     DNFBINARY=""
     DOCKERBINARY=""
     DOCKER_DAEMON_RUNNING=0
+    DPKGBINARY=""
     ECHOCMD=""
     ERROR_ON_WARNINGS=0
+    EQUERYBINARY=""
+    EXIMBINARY=""
     FAIL2BANBINARY=""
     FILEBINARY=""
     FILEVALUE=""
@@ -210,6 +217,8 @@ unset LANG
     PLUGIN_PHASE=0
     POSTFIXBINARY=""
     POSTGRES_RUNNING=0
+    PREVIOUS_TEST="No test ID"
+    PREVIOUS_TS=0
     PRIVILEGED=0
     PROFILES=""
     PROFILEVALUE=""
@@ -248,8 +257,10 @@ unset LANG
     SHOW_REPORT_SOLUTION=1
     SHOW_TOOL_TIPS=1                    # Show inline tool tips (default true)
     SHOW_WARNINGS_ONLY=0
+    SKIP_GETHOSTID=0
     SKIP_PLUGINS=0
     SKIP_TESTS=""
+    SKIP_VM_DETECTION=0
     SKIPREASON=""
     SKIPPED_TESTS_ROOTONLY=""
     SMTPCTLBINARY=""
@@ -257,6 +268,7 @@ unset LANG
     SSHKEYSCANBINARY=""
     SSHKEYSCANFOUND=0
     SSL_CERTIFICATE_PATHS=""
+    SSL_CERTIFICATE_PATHS_TO_IGNORE=""
     STUNNELBINARY=""
     SYSLOGNGBINARY=""
     SYSTEMCTLBINARY=""
@@ -270,6 +282,7 @@ unset LANG
     TESTS_EXECUTED=""
     TESTS_SKIPPED=""
     TMPFILE=""
+    TOMOYOINITBINARY=""
     TOOLTIP_SHOWED=0
     TOTAL_SUGGESTIONS=0
     TOTAL_WARNINGS=0
@@ -340,7 +353,8 @@ unset LANG
 #################################################################################
 #
 
-    # Normal color names
+    # Normal color names (BG will color background)
+    BG_BLUE="$(printf '\033[0;44m')"
     CYAN="$(printf '\033[0;36m')"
     BLUE="$(printf '\033[0;34m')"
     BROWN="$(printf '\033[0;33m')"
@@ -354,15 +368,13 @@ unset LANG
     YELLOW="$(printf '\033[1;33m')"
     WHITE="$(printf '\033[1;37m')"
 
-    # Markup
+    # Special markup
     BOLD="${WHITE}"
-
-    # With background
-    BG_BLUE="$(printf '\033[0;44m')"
+    NORMAL="$(printf '\033[0m')"
 
     # Semantic names
+    BG_WARNING="$(printf '\033[30;43m')"  # Yellow background with grey text
     HEADER="${WHITE}"
-    NORMAL="$(printf '\033[0m')"
     WARNING="${RED}"
     SECTION="${YELLOW}"
     NOTICE="${YELLOW}"
diff --git a/include/data_upload b/include/data_upload
index 5bc8e839..7698d13a 100644
--- a/include/data_upload
+++ b/include/data_upload
@@ -242,13 +242,9 @@
             fi
         else
             echo "${RED}Error${NORMAL}: No hostid and/or hostid2 found. Can not upload report file."
-            echo "Suggested command: lynis show hostids"
+            echo "Suggested command: lynis generate hostids --save"
             echo ""
-            echo "If hostid2 is the only ID that is missing, use the following step:"
-            echo "Create hash and add it to custom.prf"
-            echo "echo \"hostid2=\$(cat /dev/urandom | tr -dc 'a-f0-9' | fold -w 64 | head -n 1)\" >> /etc/lynis/custom.prf" 
-            echo ""
-            echo "Note: do not replicate this ID to other systems, as it needs to be unique per system"
+            echo "Note: do not replicate the values to other systems, as it needs to be unique per system"
 
             # Quit
             ExitFatal
diff --git a/include/functions b/include/functions
index 95083600..16cef804 100644
--- a/include/functions
+++ b/include/functions
@@ -42,6 +42,8 @@
 #    DisplayError               Show an error on screen
 #    DisplayManual              Output text to screen without any layout
 #    DisplayToolTip             Show a tip for improving usage of the tool
+#    DisplayWarning             Show a clear warning on screen
+#    Equals                     Compares two strings
 #    ExitClean                  Stop the program (cleanly), with exit code 0
 #    ExitCustom                 Stop the program (cleanly), with custom exit code
 #    ExitFatal                  Stop the program (cleanly), with exit code 1
@@ -74,6 +76,7 @@
 #    ParseTestValues            Parse a set of values
 #    PortIsListening            Check if machine is listening on specified protocol and port
 #    Progress                   Show progress on screen
+#    Readonly                   Mark a variable as read-only data
 #    Register                   Register a test (for logging and execution)
 #    RandomString               Show a random string
 #    RemoveColors               Reset all colors
@@ -85,7 +88,9 @@
 #    ReportManual               Log manual actions to report file
 #    ReportSuggestion           Add a suggestion to report file
 #    ReportWarning              Add a warning and priority to report file
+#    SafeFile                   Security tests to perform on a file before using it
 #    SafePerms                  Check if a file has safe permissions
+#    SafeInput                  Test provided string to see if it contains unwanted characters
 #    SearchItem                 Search a string in a file
 #    ShowComplianceFinding      Display a particular finding regarding compliance or a security standard
 #    ShowSymlinkPath            Show a path behind a symlink
@@ -114,7 +119,8 @@
     # Name        : AddHP()
     # Description : Add hardening points and count them
     #
-    # Input       : $1 = points to add, $2 = maximum points for this item
+    # Parameters  : $1 = points to add (0 or higher)
+    #               $2 = maximum points (at least value of $1 or higher)
     # Returns     : <nothing>
     # Usage       : AddHP 1 3
     ################################################################################
@@ -135,7 +141,9 @@
     # Name        : AddSetting()
     # Description : Addition of a setting for display with 'lynis show settings'
     #
-    # Input       : $1 = setting, $2 = value, $3 description
+    # Parameters  : $1 = setting
+    #               $2 = value
+    #               $3 = description
     # Returns     : <nothing>
     # Usage       : AddSetting debug 1 'Debug mode'
     ################################################################################
@@ -159,7 +167,7 @@
                 TEMP_SETTINGS_FILE="${TEMP_FILE}"
                 cat ${SETTINGS_FILE} > ${TEMP_SETTINGS_FILE}
                 sed -e '/^'"${SETTING}"';/d' ${TEMP_SETTINGS_FILE} > ${SETTINGS_FILE}
-                rm ${TEMP_SETTINGS_FILE}
+                rm "${TEMP_SETTINGS_FILE}"
                 echo "${SETTING};${VALUE};${DESCRIPTION};" >> ${SETTINGS_FILE}
             fi
         else
@@ -172,7 +180,7 @@
     # Name        : AddSystemGroup()
     # Description : Adds a system to a group, which can be used for categorizing
     #
-    # Input       : Group name
+    # Parameters  : $1 = group name
     # Returns     : <nothing>
     # Usage       : AddSystemGroup "test"
     ################################################################################
@@ -186,13 +194,13 @@
     # Name        : CheckFilePermissions()
     # Description : Check file permissions
     #
-    # Input       : full path to file or directory
+    # Parameters  : Full path to file or directory
     # Returns     : PERMS (FILE_NOT_FOUND | OK | BAD)
     # Notes       : This function might be replaced in future
     ################################################################################
 
     CheckFilePermissions() {
-        CHECKFILE=$1
+        CHECKFILE="$1"
         if [ ! -d ${CHECKFILE} -a ! -f ${CHECKFILE} ]; then
             PERMS="FILE_NOT_FOUND"
         else
@@ -213,13 +221,13 @@
     # Name        : CheckItem()
     # Description : Check if a specific item exists in the report
     #
-    # Input       : $1 = key, $2 = value
-    # Returns     : ITEM_FOUND
-    # Usage       : CheckItem "key" "value"
+    # Parameters  : $1 = key
+    #               $2 = value
+    # Returns     : True (0) or False (1)
+    # Usage       : if CheckItem "key" "value"; then ....; fi
     ################################################################################
 
     CheckItem() {
-        ITEM_FOUND=0
         RETVAL=255
         if [ $# -eq 2 ]; then
             # Don't search in /dev/null, it's too empty there
@@ -228,7 +236,6 @@
                 LogText "Test: search string $2 in earlier discovered results"
                 FIND=$(egrep "^$1(\[\])?=" ${REPORTFILE} | egrep "$2")
                 if HasData "${FIND}"; then
-                    ITEM_FOUND=1
                     RETVAL=0
                     LogText "Result: found search string (result: $FIND)"
                 else
@@ -248,6 +255,7 @@
     ################################################################################
     # Name        : CheckUpdates()
     # Description : Determine if there is an update available
+    #
     # Returns     : <nothing>
     # Usage       : CheckUpdates
     #               Use PROGRAM_LV (latest version) and compare it with actual version (PROGRAM_AC)
@@ -282,8 +290,9 @@
 
     ################################################################################
     # Name        : CleanUp()
-    # Description : Cleanup service
-    # Returns     : <nothing>
+    # Description : Delete PID and temporary files, stop execution (exit code 1)
+    #
+    # Usage       : this function is triggered by a manual break by user
     ################################################################################
 
     CleanUp() {
@@ -298,7 +307,8 @@
     ################################################################################
     # Name        : ContainsString()
     # Description : Search a specific string (or regular expression) in another
-    # Returns     : (0 - True, 1 - False)
+    #
+    # Returns     : True (0) or False (1)
     # Usage       : if ContainsString "needle" "there is a needle in the haystack"; echo "Found"; else "Not found"; fi
     ################################################################################
 
@@ -313,11 +323,9 @@
 
     ################################################################################
     # Name        : CountTests()
-    # Description : Count the number of tests performed
+    # Description : Counter for the number of tests performed
     #
-    # Input       : <nothing>
-    # Returns     : <nothing>
-    # Usage       : CountTests
+    # Usage       : Call CountTests to increase number by 1
     ################################################################################
 
     CountTests() {
@@ -329,7 +337,6 @@
     # Name        : CreateTempFile()
     # Description : Creates a temporary file
     #
-    # Input       : <nothing>
     # Returns     : TEMP_FILE (variable)
     # Usage       : CreateTempFile
     #               if [ ! "${TEMP_FILE}" = "" ]; then
@@ -361,7 +368,7 @@
     # Name        : DirectoryExists()
     # Description : Check if a directory exists
     #
-    # Returns     : 0 (directory exists), 1 (directory does not exist)
+    # Returns     : True (0) or False (1)
     # Usage       : if DirectoryExists; then echo "it exists"; else echo "It does not exist"; fi
     ################################################################################
 
@@ -605,6 +612,46 @@
     }
 
 
+    ################################################################################
+    # Name        : DisplayWarning
+    # Description : Show a warning on the screen
+    #
+    # Input       : $1 = text
+    # Returns     : <nothing>
+    ################################################################################
+
+    DisplayWarning() {
+        if [ ${CRONJOB} -eq 0 ]; then
+            printf "\n"
+            ${ECHOCMD:-echo} "  ${BG_WARNING}[WARNING]${NORMAL}: $1${NORMAL}"
+            printf "\n"
+        else
+            ${ECHOCMD} "  [WARNING]: $1"
+        fi
+    }
+
+
+    ################################################################################
+    # Name        : Equals()
+    # Description : Compare two strings
+    #
+    # Returns     : (0 - True, 1 - False)
+    # Usage       : if Equals "${MYDIR}" "/etc"; then echo "Found"; else "Not found"; fi
+    ################################################################################
+
+    Equals() {
+        RETVAL=1
+        if [ $# -ne 2 ]; then ReportException "Equals" "Incorrect number of arguments for $0 function"; fi
+
+        # Strip any strange control characters
+        INPUT1=$(echo $1 | tr -d '[:cntrl:]<>' | ${SEDBINARY} 's/__space__/ /g' | ${SEDBINARY} 's/:space:/ /g')
+        INPUT2=$(echo $2 | tr -d '[:cntrl:]<>' | ${SEDBINARY} 's/__space__/ /g' | ${SEDBINARY} 's/:space:/ /g')
+        if [ "${INPUT1}" = "${INPUT2}" ]; then RETVAL=0; fi
+
+        return ${RETVAL}
+    }
+
+
     ################################################################################
     # Name        : ExitClean()
     # Description : Perform a normal exit of the program, and clean up resources
@@ -659,9 +706,9 @@
         RemoveTempFiles
         LogText "${PROGRAM_NAME} ended with exit code 1."
         if [ $# -eq 1 ]; then
-            ${ECHOCMD} ""
-            ${ECHOCMD} "${RED}Fatal error${NORMAL}: ${WHITE}$1${NORMAL}"
-            ${ECHOCMD} ""
+            ${ECHOCMD:-echo} ""
+            ${ECHOCMD:-echo} "${RED}Fatal error${NORMAL}: ${WHITE}$1${NORMAL}"
+            ${ECHOCMD:-echo} ""
         fi
         exit 1
     }
@@ -805,15 +852,26 @@
     # Name        : GetHostID()
     # Description : Create an unique id for the system
     #
-    # Returns     : optional value
+    # Returns     : 0 = fetched or created IDs, 1 = failed, 2 = skipped
     # Usage       : GetHostID
     ################################################################################
 
     GetHostID() {
 
+        if [ ${SKIP_GETHOSTID} -eq 1 ]; then
+            return 2
+        fi
+
         if [ ! -z "${HOSTID}" -a ! -z "${HOSTID2}" ]; then
             Debug "Skipping creation of host identifiers, as they are already configured (via profile)"
-            return 1
+            return 2
+        fi
+
+        if [ -f "${ROOTDIR}etc/lynis/hostids" ]; then
+            Debug "Used hostids file to fetch values"
+            HOSTID=$(grep "^hostid=" ${ROOTDIR}etc/lynis/hostids | awk -F= '{print $2}')
+            HOSTID2=$(grep "^hostid2=" ${ROOTDIR}etc/lynis/hostids | awk -F= '{print $2}')
+            return 0
         fi
 
         FIND=""
@@ -1110,8 +1168,9 @@
         fi
 
         # Show an exception if no HostID could be created, to ensure each system (and scan) has one
-        if [ "${HOSTID}" = "" ]; then
+        if [ -z "${HOSTID}" ]; then
             ReportException "GetHostID" "No unique host identifier could be created."
+            return 1
         elif [ ! -z "${HOSTID2}" ]; then
             return 0
         fi
@@ -1284,7 +1343,8 @@
 
         if [ -z "${search}" ]; then ExitFatal "Missing process to search for when using IsRunning function"; fi
         RUNNING=0
-        if [ ! -z "${PGREPBINARY}" ]; then
+        # AIX does not fully support pgrep options, so using ps instead
+        if [ ! -z "${PGREPBINARY}" -a ! "${OS}" = "AIX" ]; then
             FIND=$(${PGREPBINARY} ${pgrep_options} "${search}" | ${TRBINARY} '\n' ' ')
         else
             if [ -z "${PSOPTIONS}" ]; then
@@ -1392,6 +1452,10 @@
         ISVIRTUALMACHINE=2; VMTYPE="unknown"; VMFULLTYPE="Unknown"
         SHORT=""
 
+        if [ ${SKIP_VM_DETECTION} -eq 1 ]; then
+            return 2
+        fi
+
         # lxc environ detection
         if [ -z "${SHORT}" ]; then
             if [ -f /proc/1/environ ]; then
@@ -1699,7 +1763,7 @@
 
     ################################################################################
     # Name        : PackageIsInstalled()
-    # Description : Add a separator to log file between sections, tests etc
+    # Description : Determines if a package is installed
     # Returns     : exit code
     # Notes       : this function is not used yet, but created in advance to allow
     #               the addition of support for all operating systems
@@ -1714,11 +1778,20 @@
             Fatal "Incorrect usage of PackageIsInstalled function"
         fi
 
-        if [ ! -z "${RPMBINARY}" ]; then
-            output=$(${RPMBINARY} --quiet -q ${package} 2> /dev/null)
+        if [ ! -z "${DNFBINARY}" ]; then
+            output=$(${DNFBINARY} --quiet --cacheonly --noplugins --assumeno info --installed ${package} > /dev/null 2>&1)
             exit_code=$?
-        elif ! -z "${DPKGBINARY}" ]; then
-            output=$(${DPKGBINARY} -l ${package} 2> /dev/null)
+        elif [ ! -z "${DPKGBINARY}" ]; then
+            output=$(${DPKGBINARY} -l ${package} 2> /dev/null | ${GREPBINARY} "^ii")
+            exit_code=$?
+        elif [ ! -z "${EQUERYBINARY}" ]; then
+            output=$(${EQUERYBINARY} --quiet ${package} > /dev/null 2>&1)
+            exit_code=$?  # 0=package installed, 3=package not installed
+        elif [ ! -z "${PKG_BINARY}" ]; then
+            output=$(${PKG_BINARY} -N info ${package} >/dev/null 2>&1)
+            exit_code=$?  # 0=package installed, 70=invalid package
+        elif [ ! -z "${RPMBINARY}" ]; then
+            output=$(${RPMBINARY} --quiet -q ${package} > /dev/null 2>&1)
             exit_code=$?
         elif [ ! -z "${ZYPPERBINARY}" ]; then
             output=$(${ZYPPERBINARY} --quiet --non-interactive search --installed -i ${PACKAGE} 2> /dev/null | grep "^i")
@@ -1983,7 +2056,7 @@
                     for ITEM in ${VALUE}; do
                         LogText "Result: found protocol ${ITEM}"
                         case ${ITEM} in
-                            "sslv2" | "sslv3")
+                            "sslv2" | "sslv3" | "tlsv1")
                                 NGINX_WEAK_SSL_PROTOCOL_FOUND=1
                             ;;
                         esac
@@ -2089,6 +2162,24 @@
     }
 
 
+    ################################################################################
+    # Name        : Readonly()
+    # Description : Mark a variable as read-only data
+    # Returns     : nothing
+    ################################################################################
+
+    Readonly() {
+        if [ $# -eq 1 ]; then
+            if type -t typeset; then
+                typeset -r $1
+            else
+                Debug "No typeset available to mark variable '$1' as read-only variable"
+            fi
+        else
+            ExitFatal "Expected 1 parameter, received none or multiple"
+        fi
+    }
+
 
     ################################################################################
     # Name        : Register()
@@ -2096,6 +2187,19 @@
     # Returns     : SKIPTEST (0 or 1)
     ################################################################################
 
+    GetTimestamp() {
+        ts=0
+        case "${OS}" in
+            "Linux")
+                ts=$(date "+%s%N")
+            ;;
+            *)
+                ts=$(date "+%s")
+            ;;
+        esac
+        echo $ts
+    }
+
     Register() {
         # Do not insert a log break, if previous test was not logged
         if [ ${SKIPLOGTEST} -eq 0 ]; then LogTextBreak; fi
@@ -2163,6 +2267,35 @@
             shift
         done
 
+        # Measure timing
+        CURRENT_TS=$(GetTimestamp)
+        if [ ${PREVIOUS_TS} -gt 0 ]; then
+            SLOW_TEST=0
+            TIME_THRESHOLD=10  # seconds
+
+            # Calculate timing and determine if we use seconds or nanoseconds (more precise)
+            TIME_DIFF=$((${CURRENT_TS} - ${PREVIOUS_TS}))
+            if [ ${CURRENT_TS} -gt 1000000000000000000 ]; then
+                TIME_DIFF_FORMAT="nanoseconds"
+                TIME_THRESHOLD=$((${TIME_THRESHOLD} * 1000000000))
+                if [ ${TIME_DIFF} -gt ${TIME_THRESHOLD} ]; then
+                    SLOW_TEST=1
+                    # Convert back to seconds for readability
+                    TIME_DIFF_FORMAT="seconds"
+                    TIME_DIFF=$(echo ${TIME_DIFF} | ${AWKBINARY} '{printf "%f",$1/1000000000}')
+                fi
+            else
+                TIME_DIFF_FORMAT="seconds"
+                if [ ${TIME_DIFF} -gt ${TIME_THRESHOLD} ]; then
+                    SLOW_TEST=1
+                fi
+            fi
+            if [ ${SLOW_TEST} -eq 1 ]; then
+                DisplayWarning "Test ${PREVIOUS_TEST} had a long execution: ${TIME_DIFF} ${TIME_DIFF_FORMAT}"
+                Report "slow_test[]=${PREVIOUS_TEST},${TIME_DIFF}"
+            fi
+        fi
+
         # Skip test if it's configured in profile (old style)
         if [ ${SKIPTEST} -eq 0 ]; then
             FIND=$(echo "${TEST_SKIP_ALWAYS}" | grep "${TEST_NO}" | tr '[:lower:]' '[:upper:]')
@@ -2235,6 +2368,10 @@
             TESTS_SKIPPED="${TEST_NO}|${TESTS_SKIPPED}"
         fi
         unset SKIPREASON
+
+        # Save timestamp for next time the Register function is called
+        PREVIOUS_TEST="${TEST_NO}"
+        PREVIOUS_TS="${CURRENT_TS}"
     }
 
 
@@ -2262,6 +2399,7 @@
 
         # Colors with background
         BG_BLUE=""
+        BG_WARNING=""
 
         # Semantic names
         BAD=""
@@ -2276,14 +2414,15 @@
 
     ################################################################################
     # Name        : RemovePIDFile()
+    # Description : When defined, remove the file storing the process ID
     ################################################################################
 
     # Remove PID file
     RemovePIDFile() {
         # Test if PIDFILE is defined, before checking file presence
-        if [ ! "${PIDFILE}" = "" ]; then
-            if [ -f ${PIDFILE} ]; then
-                rm -f $PIDFILE;
+        if [ ! -z "${PIDFILE}" ]; then
+            if [ -f "${PIDFILE}" ]; then
+                rm -f "${PIDFILE}"
                 LogText "PID file removed (${PIDFILE})"
             else
                 LogText "PID file not found (${PIDFILE})"
@@ -2294,6 +2433,7 @@
 
     ################################################################################
     # Name        : RemoveTempFiles()
+    # Description : When created, delete any temporary file
     ################################################################################
 
     # Remove any temporary files
@@ -2304,10 +2444,10 @@
             for FILE in ${TEMP_FILES}; do
                 # Temporary files should be in /tmp
                 TMPFILE=$(echo ${FILE} | egrep "^/tmp/lynis" | grep -v "\.\.")
-                if [ ! "${TMPFILE}" = "" ]; then
-                    if [ -f ${TMPFILE} ]; then
+                if [ ! -z "${TMPFILE}" ]; then
+                    if [ -f "${TMPFILE}" ]; then
                         LogText "Action: removing temporary file ${TMPFILE}"
-                        rm -f ${TMPFILE}
+                        rm -f "${TMPFILE}"
                     else
                         LogText "Info: temporary file ${TMPFILE} was already removed"
                     fi
@@ -2323,6 +2463,7 @@
 
     ################################################################################
     # Name        : Report()
+    # Description : Store data in the report file
     ################################################################################
 
     Report() {
@@ -2397,12 +2538,14 @@
 
     ################################################################################
     # Name        : ReportException()
+    # Description : Store an exceptional event in the report
+    #
+    # Parameters  : $1 = test ID + colon + 2 numeric characters (TEST-1234:01)
+    #               $2 = string (text)
     ################################################################################
 
     # Log exceptions
     ReportException() {
-        # 1 parameters
-        # <ID>:<2 char numeric>|text|
         Report "exception_event[]=$1|$2|"
         LogText "Exception: test has an exceptional event ($1) with text $2"
     }
@@ -2410,11 +2553,12 @@
 
     ################################################################################
     # Name        : ReportManual()
+    # Description : Add an item to the report that requires manual intervention
+    #
+    # Parameters  : $1 = string (text)
     ################################################################################
 
-    # Log manual actions to report file
     ReportManual() {
-        # 1 parameter: Text
         Report "manual_event[]=$1"
         LogText "Manual: one or more manual actions are required for further testing of this control/plugin"
     }
@@ -2422,20 +2566,20 @@
 
     ################################################################################
     # Name        : ReportSuggestion()
+    # Description : Log a suggestion to the report file
+    #
+    # Parameters  : <ID> <Suggestion> <Details> <Solution>
+    #               $1 = Test ID - Lynis ID (use CUST-.... for your own tests)
+    #               $2 = Suggestion - Suggestion text to be displayed
+    #               $3 = Details - Specific item or details
+    #               $4 = Solution - Optional link for additional information:
+    #                    * url:https://example.org/how-to-solve-link
+    #                    * text:Additional explanation
+    #                    * - (dash) for none
     ################################################################################
 
-    # Log suggestions to report file
     ReportSuggestion() {
         TOTAL_SUGGESTIONS=$((TOTAL_SUGGESTIONS + 1))
-        # 4 parameters
-        # <ID> <Suggestion> <Details> <Solution>
-        # <ID>         Lynis ID (use CUST-.... for your own tests)
-        # <Suggestion> Suggestion text to be displayed
-        # <Details>    Specific item or details
-        # <Solution>   Optional link for additional information:
-        #              * url:http://site/link
-        #              * text:Additional explanation
-        #              * - for none
         if [ $# -eq 0 ]; then echo "Not enough arguments provided for function ReportSuggestion"; ExitFatal; fi
         if [ $# -ge 1 ]; then TEST="$1"; else TEST="UNKNOWN"; fi
         if [ $# -ge 2 ]; then MESSAGE="$2"; else MESSAGE="UNKNOWN"; fi
@@ -2449,9 +2593,9 @@
 
     ################################################################################
     # Name        : ReportWarning()
+    # Description : Log a warning to the report file
     ################################################################################
 
-    # Log warning to report file
     ReportWarning() {
         TOTAL_WARNINGS=$((TOTAL_WARNINGS + 1))
         # Old style
@@ -2484,76 +2628,180 @@
     }
 
 
+    ################################################################################
+    # Name        : SafeInput()
+    # Description : Test provided string to see if it contains unwanted characters
+    #
+    # Input       : string + optional class (parameter 2)
+    # Returns     : 0 (input considered to be safe) or 1 (validation failed)
+    ################################################################################
+
+    SafeInput() {
+        exitcode=1
+        # By default remove only control characters
+        if [ $# -eq 1 ]; then
+            input="$1"
+            cleaned=$(echo ${input} | tr -d '[:cntrl:]')
+        # If know what to test against, then see if input matches the specified class
+        elif [ $# -eq 2 ]; then
+            input="$1"
+            testchars="$2"
+            cleaned=$(echo $1 | tr -cd "${testchars}")
+        else
+            ExitFatal "No argument or too many arguments provided to SafeInput()"
+        fi
+
+        if [ "${cleaned}" = "${input}" ]; then
+            exitcode=0
+        fi
+        return ${exitcode}
+    }
+
+
+    ################################################################################
+    # Name        : SafeFile()
+    # Description : Check if a file is safe to use
+    #
+    ################################################################################
+
+    SafeFile() {
+        unsafe=0
+        if [ $# -ne 1 ]; then
+            ExitFatal "No argument or too many arguments provided to SafeFile()"
+        else
+            FILE="$1"
+
+            # Generic checks
+            if [ -g "${FILE}" ]; then
+                LogText "Security alert: file has setgid attribute"
+                unsafe=1
+            # sticky bit
+            elif [ -k "${FILE}" ]; then
+                LogText "Security alert: file has sticky bit"
+                unsafe=1
+            # symbolic link
+            elif [ -L "${FILE}" ]; then
+                LogText "Security alert: file is a symbolic link"
+                unsafe=1
+            elif [ -f "${FILE}" ]; then
+                LogText "Security check: file is normal"
+            else
+                unsafe=1
+            fi
+
+            # Perform additional checks based on privilege level
+            if [ ${PRIVILEGED} -eq 0 ]; then
+                # File is not owned by active user, but still able to write
+                if [ ! -O "${FILE}" -a -w "${FILE}" ]; then
+                    unsafe=1
+                    LogText "Security alert: file is not owned by active user, but can write to it"
+                fi
+            fi
+
+            # Check file permissions
+            if ! SafePerms "${FILE}"; then
+                unsafe=1
+            fi
+
+        fi
+
+        return ${unsafe}
+    }
+
+
     ################################################################################
     # Name        : SafePerms()
-    # Return      : 0 (file OK) or break
+    # Description : Check if a file has safe permissions to be used
+    #
+    # Returns     : 0 (file permissions OK) or break
     ################################################################################
 
     SafePerms() {
-        if [ ${WARN_ON_FILE_ISSUES} -eq 1 ]; then
+        exitcode=1
+        IS_PARAMETERS=0
+        IS_PROFILE=0
+
+        if [ ${IGNORE_FILE_PERMISSION_ISSUES} -eq 0 ]; then
             PERMS_OK=0
             LogText "Checking permissions of $1"
-            if [ $# -eq 1 ]; then
-                IS_PARAMETERS_FILE=$(echo $1 | grep "/parameters")
+
+            if [ $# -gt 0 ]; then
+
+                if [ $# -eq 2 ]; then
+                    case "$2" in
+                        "parameters")
+                            IS_PARAMETERS=1
+                        ;;
+                        "profile")
+                            IS_PROFILE=1
+                        ;;
+                    esac
+                else
+                    FIND=$(echo $1 | grep "/parameters")
+                    if [ $? -eq 0 ]; then IS_PARAMETERS=1; fi
+                fi
                 # Check file permissions
-                  if [ ! -f "$1" ]; then
-                      LogText "Fatal error: file $1 does not exist. Quitting."
-                      echo "Fatal error: file $1 does not exist"
-                      ExitFatal
-                    else
-                      PERMS=$(ls -l $1)
-                      # Owner permissions
-                      OWNER=$(echo ${PERMS} | awk -F" " '{ print $3 }')
-                      OWNERID=$(ls -n $1 | awk -F" " '{ print $3 }')
-                      if [ ${PENTESTINGMODE} -eq 0 -a "${IS_PARAMETERS_FILE}" = "" ]; then
-                          if [ ! "${OWNER}" = "root" -a ! "${OWNERID}" = "0" ]; then
-                              echo "Fatal error: file $1 should be owned by user 'root' when running it as root (found: ${OWNER})."
-                              ExitFatal
-                          fi
-                      fi
-                      # Group permissions
-                      GROUP=$(echo ${PERMS} | awk -F" " '{ print $4 }')
-                      GROUPID=$(ls -n $1 | awk -F" " '{ print $4 }')
+                if [ ! -f "$1" ]; then
+                    LogText "Fatal error: file $1 does not exist. Quitting."
+                    echo "Fatal error: file $1 does not exist"
+                    ExitFatal
+                else
+                    PERMS=$(ls -l $1)
 
-                      if [ ${PENTESTINGMODE} -eq 0 -a "${IS_PARAMETERS_FILE}" = "" ]; then
-                          if [ ! "${GROUP}" = "root" -a ! "${GROUP}" = "wheel" -a ! "${GROUPID}" = "0" ]; then
-                              echo "Fatal error: group owner of directory $1 should be owned by root user, wheel or similar (found: ${GROUP})."
-                              ExitFatal
-                          fi
-                      fi
+                    # Owner permissions
+                    OWNER=$(echo ${PERMS} | awk -F" " '{ print $3 }')
+                    OWNERID=$(ls -n $1 | awk -F" " '{ print $3 }')
+                    if [ ${PENTESTINGMODE} -eq 0 -a ${IS_PARAMETERS} -eq 0 ]; then
+                        if [ ! "${OWNER}" = "root" -a ! "${OWNERID}" = "0" ]; then
+                            echo "Fatal error: file $1 should be owned by user 'root' when running it as root (found: ${OWNER})."
+                            ExitFatal
+                        fi
+                    fi
+                    # Group permissions
+                    GROUP=$(echo ${PERMS} | awk -F" " '{ print $4 }')
+                    GROUPID=$(ls -n $1 | awk -F" " '{ print $4 }')
 
-                      # Owner permissions
-                      OWNER_PERMS=$(echo ${PERMS} | cut -c2-4)
-                      if [ ! "${OWNER_PERMS}" = "rw-" -a ! "${OWNER_PERMS}" = "r--" ]; then
-                          echo "Fatal error: permissions of file $1 are not strict enough. Access to 'owner' should be read-write, or read. Change with: chmod 600 $1"
-                          ExitFatal
-                      fi
+                    if [ ${PENTESTINGMODE} -eq 0 -a ${IS_PARAMETERS} -eq 0 ]; then
+                        if [ ! "${GROUP}" = "root" -a ! "${GROUP}" = "wheel" -a ! "${GROUPID}" = "0" ]; then
+                            echo "Fatal error: group owner of directory $1 should be owned by root user, wheel or similar (found: ${GROUP})."
+                            ExitFatal
+                        fi
+                    fi
 
-                      # Owner permissions
-                      GROUP_PERMS=$(echo ${PERMS} | cut -c5-7)
-                      if [ ! "${GROUP_PERMS}" = "rw-" -a ! "${GROUP_PERMS}" = "r--" -a ! "${GROUP_PERMS}" = "---" ]; then
-                          echo "Fatal error: permissions of file $1 are not strict enough. Access to 'group' should be read-write, read, or none. Change with: chmod 600 $1"
-                          ExitFatal
-                      fi
+                    # Owner permissions
+                    OWNER_PERMS=$(echo ${PERMS} | cut -c2-4)
+                    if [ ! "${OWNER_PERMS}" = "rw-" -a ! "${OWNER_PERMS}" = "r--" ]; then
+                        echo "Fatal error: permissions of file $1 are not strict enough. Access to 'owner' should be read-write, or read. Change with: chmod 600 $1"
+                        ExitFatal
+                    fi
 
-                      # Other permissions
-                      OTHER_PERMS=$(echo ${PERMS} | cut -c8-10)
-                      if [ ! "${OTHER_PERMS}" = "---" -a ! "${OTHER_PERMS}" = "r--" ]; then
-                          echo "Fatal error: permissions of file $1 are not strict enough. Access to 'other' should be denied or read-only. Change with: chmod 600 $1"
-                          ExitFatal
-                      fi
-                      # Set PERMS_OK to 1 if no fatal errors occurred
-                      PERMS_OK=1
-                      LogText "File permissions are OK"
-                      return 0
-                  fi
+                    # Owner permissions
+                    GROUP_PERMS=$(echo ${PERMS} | cut -c5-7)
+                    if [ ! "${GROUP_PERMS}" = "rw-" -a ! "${GROUP_PERMS}" = "r--" -a ! "${GROUP_PERMS}" = "---" ]; then
+                        echo "Fatal error: permissions of file $1 are not strict enough. Access to 'group' should be read-write, read, or none. Change with: chmod 600 $1"
+                        ExitFatal
+                    fi
+
+                    # Other permissions
+                    OTHER_PERMS=$(echo ${PERMS} | cut -c8-10)
+                    if [ ! "${OTHER_PERMS}" = "---" -a ! "${OTHER_PERMS}" = "r--" ]; then
+                        echo "Fatal error: permissions of file $1 are not strict enough. Access to 'other' should be denied or read-only. Change with: chmod 600 $1"
+                        ExitFatal
+                    fi
+                    # Set PERMS_OK to 1 if no fatal errors occurred
+                    PERMS_OK=1
+                    LogText "File permissions are OK"
+                    exitcode=0
+                fi
             else
                 ReportException "SafePerms()" "Invalid number of arguments for function"
             fi
         else
             PERMS_OK=1
-            return 0
+            exitcode=0
         fi
+        return ${exitcode}
+
     }
 
 
@@ -2561,14 +2809,15 @@
     # Name        : SearchItem()
     # Description : Search if a specific string exists in in a file
     #
-    # Input       : $1 = search key (string), $2 = file (string), $3 and later
-    #               are optional arguments
+    # Parameters  : $1 = search key (string)
+    #               $2 = file (string)
+    #               $3 = optional arguments:
+    #                    --sensitive - don't store results in log
     # Returns     : True (0) or False (1)
     ################################################################################
 
     SearchItem()  {
         PERFORM_SCAN=0
-        ITEM_FOUND=0
         MASK_LOG=0
         RETVAL=1
         if [ $# -lt 2 ]; then
@@ -2596,8 +2845,7 @@
                 # Check if we can find the main type (with or without brackets)
                 LogText "Test: search string ${STRING} in file ${FILE}"
                 FIND=$(egrep "${STRING}" ${FILE})
-                if [ ! "${FIND}" = "" ]; then
-                    ITEM_FOUND=1
+                if [ ! -z "${FIND}" ]; then
                     LogText "Result: found search string '${STRING}'"
                     if [ ${MASK_LOG} -eq 0 ]; then LogText "Full string returned: ${FIND}"; fi
                     RETVAL=0
@@ -2616,21 +2864,6 @@
     }
 
 
-    # Show result code (to be removed)
-    ShowResult() {
-        case $1 in
-        OK)
-            echo "[ ${OK}OK${NORMAL} ]"
-        ;;
-        WARNING)
-            echo "[ ${WARNING}WARNING${NORMAL} ]"
-            # log the warning to our log file
-            #LogText "Warning: $2"
-            # add the warning to our report file
-            #Report "warning=$2"
-        ;;
-        esac
-    }
 
 
     ################################################################################
@@ -3191,35 +3424,44 @@
     #
     ################################################################################
     # For compatibility reasons they are listed here, but will be phased out in
-    # steps. If they still get used, they will trigger an alert when using the
-    # developer mode. In a later phase they will trigger errors on screen.
+    # steps. If they still get used, they will trigger errors on screen.
     ################################################################################
 
     counttests() {
+        DisplayWarning "Deprecated function used (counttests)"
         if IsDeveloperMode; then Debug "Warning: old counttests function is used. Please replace any reference with CountTests."; fi
         CountTests
     }
 
     logtext() {
+        DisplayWarning "Deprecated function used (logtext)"
         if IsDeveloperMode; then Debug "Warning: old logtext function is used. Please replace any reference with LogText."; fi
         LogText "$1"
     }
 
     logtextbreak() {
+        DisplayWarning "Deprecated function used (logtextbreak)"
         if IsDeveloperMode; then Debug "Warning: old logtextbreak function is used. Please replace any reference with LogTextBreak."; fi
         LogTextBreak "$1"
     }
 
     report() {
+        DisplayWarning "Deprecated function used (report)"
         if IsDeveloperMode; then Debug "Warning: old report function is used. Please replace any reference with Report."; fi
         Report "$1"
     }
 
     wait_for_keypress() {
+        DisplayWarning "Deprecated function used (wait_for_keypress)"
         if IsDeveloperMode; then Debug "Warning: old wait_for_keypress function is used. Please replace any reference with WaitForKeyPress."; fi
         WaitForKeyPress
     }
 
+    ShowResult() {
+        DisplayWarning "Deprecated function used (ShowResult)"
+        if IsDeveloperMode; then Debug "Warning: old ShowResult() function is used. Please replace any reference with WaitForKeyPress."; fi
+    }
+
 
 
 #================================================================================
diff --git a/include/helper_audit_dockerfile b/include/helper_audit_dockerfile
index efe73d28..3d18556f 100644
--- a/include/helper_audit_dockerfile
+++ b/include/helper_audit_dockerfile
@@ -19,25 +19,14 @@
 #################################################################################
 
 if [ $# -eq 0 ]; then
-    Display --indent 2 --text "${RED}Error: ${WHITE}Provide URL or file${NORMAL}"
+    Display --indent 2 --text "${RED}Error: ${WHITE}Provide a file${NORMAL}"
     Display --text " "; Display --text " "
     ExitFatal
 else
     FILE=$(echo $1 | egrep "^http|https")
     if HasData "${FILE}"; then
-        CreateTempFile
-        TMP_FILE="${TEMP_FILE}"
-        Display --indent 2 --text "Downloading URL ${FILE} with wget"
-        wget -o ${TMP_FILE} ${FILE}
-        if [ $? -gt 0 ]; then
-            AUDIT_FILE="${TMP_FILE}"
-        else
-            if [ -f ${TMP_FILE} ]; then
-                rm -f ${TMP_FILE}
-            fi
-            Display --indent 2 --text "${RED}Error: ${WHITE}can not download file${NORMAL}"
-            ExitFatal
-        fi
+        echo "Provide a file (not a URL)"
+        ExitFatal
     else
         if [ -f $1 ]; then
             AUDIT_FILE="$1"
@@ -70,13 +59,12 @@ fi
         IS_ALPINE=$(echo ${IMAGE} | grep -i alpine)
         IS_LATEST=$(echo ${TAG} | grep -i latest)
 
-        if [ ! "${IS_DEBIAN}" = "" ]; then IMAGE="debian"; fi
-        if [ ! "${IS_FEDORA}" = "" ]; then IMAGE="fedora"; fi
-        if [ ! "${IS_UBUNTU}" = "" ]; then IMAGE="ubuntu"; fi
-        if [ ! "${IS_ALPINE}" = "" ]; then IMAGE="alpine"; fi
-        
-        if [ ! "${IS_LATEST}" = "" ]; then 
-            ReportWarning "dockerfile" "latest TAG used. Specifying the version is better."
+        if [ ! -z "${IS_DEBIAN}" ]; then IMAGE="debian"; fi
+        if [ ! -z "${IS_FEDORA}" ]; then IMAGE="fedora"; fi
+        if [ ! -z "${IS_UBUNTU}" ]; then IMAGE="ubuntu"; fi
+        if [ ! -z "${IS_ALPINE}" ]; then IMAGE="alpine"; fi
+        if [ ! -z "${IS_LATEST}" ]; then
+            ReportWarning "dockerfile" "latest TAG used. Specifying a targeted OS image and version is better for reproducible results."
         fi
 
         case ${IMAGE} in
@@ -110,14 +98,14 @@ InsertSection "Basics"
 
     #FIND=$(egrep "^MAINTAINER" ${AUDIT_FILE} | sed 's/ /:space:/g')
     FIND=$(egrep -i "*MAINTAINER" ${AUDIT_FILE}  |  sed 's/=/ /g' | cut -d'"' -f 2)
-    if [ "${FIND}" = "" ]; then
+    if [ -z "${FIND}" ]; then
         ReportWarning "dockerfile" "No maintainer found. Unclear who created this file."
     else
         #MAINTAINER=$(echo ${FIND} | sed 's/:space:/ /g' | awk '{ if($1=="MAINTAINER") { print }}')
         MAINTAINER=$(echo ${FIND})
         Display --indent 2 --text "Maintainer" --result "${MAINTAINER}"
     fi
-    
+
     FIND=$(grep "^ENTRYPOINT" ${AUDIT_FILE} | cut -d' ' -f2 )
     if [ "${FIND}" = "" ]; then
         ReportWarning "dockerfile" "No ENTRYPOINT defined in Dockerfile."
@@ -127,7 +115,7 @@ InsertSection "Basics"
     fi
 
     FIND=$(grep "^CMD" ${AUDIT_FILE} | cut -d' ' -f2 )
-    if [ "${FIND}" = "" ]; then
+    if [ -z "${FIND}" ]; then
         ReportWarning "dockerfile" "No CMD defines in Dockerfile."
     else
         CMD=$(echo ${FIND})
@@ -135,7 +123,7 @@ InsertSection "Basics"
     fi
 
     FIND=$(grep "^USER" ${AUDIT_FILE} | cut -d' ' -f2 )
-    if [ "${FIND}" = "" ]; then
+    if [ -z "${FIND}" ]; then
         ReportWarning "dockerfile" "No user declared in Dockerfile. Container will execute command as root"
     else
         USER=$(echo ${FIND})
diff --git a/include/helper_generate b/include/helper_generate
new file mode 100644
index 00000000..31dba7ec
--- /dev/null
+++ b/include/helper_generate
@@ -0,0 +1,180 @@
+#!/bin/sh
+
+#################################################################################
+#
+#   Lynis
+# ------------------
+#
+# Copyright 2007-2013, Michael Boelen
+# Copyright 2007-2019, CISOfy
+#
+# Website  : https://cisofy.com
+# Blog     : http://linux-audit.com
+# GitHub   : https://github.com/CISOfy/lynis
+#
+# Lynis comes with ABSOLUTELY NO WARRANTY. This is free software, and you are
+# welcome to redistribute it under the terms of the GNU General Public License.
+# See LICENSE file for usage of this software.
+#
+######################################################################
+#
+# Helper program to generate specific details such as host IDs
+#
+######################################################################
+#
+# How to use:
+# ------------
+# Run: lynis generate <option>
+#
+######################################################################
+
+SAVEFILE=0
+GENERATE_ARGS="hostids systemd-units"
+
+if [ $# -gt 0 ]; then
+    case $1 in
+        "hostids")
+
+            if [ $# -gt 1 ]; then
+                shift
+                if [ $1 = "--save" ]; then
+                    SAVEFILE=1
+                fi
+            fi
+
+            # Generate random host IDs
+            HOSTID=$(head -c20 < /dev/urandom | xxd -c 20 -p)
+            HOSTID2=$(head -c32 < /dev/urandom | xxd -c 32 -p)
+
+            ${ECHOCMD} "Generated host identifiers"
+            ${ECHOCMD} "- hostid: ${HOSTID}"
+            ${ECHOCMD} "- hostid2: ${HOSTID2}"
+
+            if [ ${SAVEFILE} -eq 1 ]; then
+                FILE="${ROOTDIR}etc/lynis/hostids"
+                if [ -f ${FILE} ]; then
+                    ${ECHOCMD} "Error: hostids file already exists (${FILE})"
+                    ${ECHOCMD} "Remove the file first and rerun command"
+                    ExitFatal
+                else
+                    OUTPUT=$(touch ${FILE} 2> /dev/null)
+                    if [ $? -eq 0 ]; then
+                        ${ECHOCMD} "Created hostids file (${FILE})"
+                        echo "# generated using 'lynis generate hostids --save'" > ${FILE}
+                        echo "hostid=${HOSTID}" >> ${FILE}
+                        echo "hostid2=${HOSTID2}" >> ${FILE}
+                    else
+                        ExitFatal "Error: could not created hostids file (${FILE}). Issue with permissions?"
+                    fi
+                fi
+            fi
+
+            ExitClean
+            ;;
+
+        "cronjob")
+            ${ECHOCMD} "Not implemented yet"
+            ;;
+
+        "systemd-units")
+
+            ${ECHOCMD} ""
+
+            ${ECHOCMD} "${BG_BLUE}Step 1: create service unit (/etc/systemd/system/lynis.service)${NORMAL}"
+
+            ${ECHOCMD} ""
+            ${ECHOCMD} "#################################################################################"
+            ${ECHOCMD} "#"
+            ${ECHOCMD} "# Lynis service file for systemd"
+            ${ECHOCMD} "#"
+            ${ECHOCMD} "#################################################################################"
+            ${ECHOCMD} "# Do not remove, so Lynis can provide a hint when a newer unit is available"
+            ${ECHOCMD} "# Generator=lynis"
+            ${ECHOCMD} "# Version=1"
+            ${ECHOCMD} "#################################################################################"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "[Unit]"
+            ${ECHOCMD} "Description=Security audit and vulnerability scanner"
+            ${ECHOCMD} "Documentation=https://cisofy.com/docs/"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "[Service]"
+            ${ECHOCMD} "Nice=19"
+            ${ECHOCMD} "IOSchedulingClass=best-effort"
+            ${ECHOCMD} "IOSchedulingPriority=7"
+            ${ECHOCMD} "Type=simple"
+            MYBINARY=$(which lynis 2>/dev/null)
+            MOREOPTIONS=""
+            if [ -n "${LICENSE_KEY}" ]; then
+                MOREOPTIONS=" --upload"
+            fi
+            ${ECHOCMD} "ExecStart=${MYBINARY:-/path/to/lynis} audit system --cronjob${MOREOPTIONS}"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "[Install]"
+            ${ECHOCMD} "WantedBy=multi-user.target"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "#################################################################################"
+            ${ECHOCMD} ""
+            ${ECHOCMD} ""
+
+            ${ECHOCMD} "${BG_BLUE}Step 2: create timer unit (/etc/systemd/system/lynis.timer)${NORMAL}"
+            ${ECHOCMD} ""
+
+            ${ECHOCMD} "#################################################################################"
+            ${ECHOCMD} "#"
+            ${ECHOCMD} "# Lynis timer file for systemd"
+            ${ECHOCMD} "#"
+            ${ECHOCMD} "#################################################################################"
+            ${ECHOCMD} "# Do not remove, so Lynis can provide a hint when a newer unit is available"
+            ${ECHOCMD} "# Generator=lynis"
+            ${ECHOCMD} "# Version=1"
+            ${ECHOCMD} "#################################################################################"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "[Unit]"
+            ${ECHOCMD} "Description=Daily timer for the Lynis security audit and vulnerability scanner"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "[Timer]"
+            ${ECHOCMD} "OnCalendar=daily"
+            ${ECHOCMD} "RandomizedDelaySec=1800"
+            ${ECHOCMD} "Persistent=false"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "[Install]"
+            ${ECHOCMD} "WantedBy=timers.target"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "#################################################################################"
+            ${ECHOCMD} ""
+            ${ECHOCMD} ""
+
+            ${ECHOCMD} "${BG_BLUE}Step 3 - Enable the timer${NORMAL}"
+
+            ${ECHOCMD} ""
+            ${ECHOCMD} "Tell systemd you made changes: systemctl daemon-reload"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "Enable and start the timer (so no reboot is needed): systemctl enable --now lynis.timer"
+            ${ECHOCMD} ""
+            ${ECHOCMD} ""
+            ${ECHOCMD} "${BG_BLUE}Optional - Customize${NORMAL}"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "Want to override the timer? Run: systemctl edit lynis.timer"
+            ${ECHOCMD} "Note: set the timer by first resetting it, then set the preferred value"
+            ${ECHOCMD} ""
+            ${ECHOCMD} "[Timer]"
+            ${ECHOCMD} "OnCalendar="
+            ${ECHOCMD} "OnCalendar=*-*-* 03:00:00"
+            ${ECHOCMD} ""
+            ;;
+        *)                      ${ECHOCMD} "Unknown argument '${RED}$1${NORMAL}' for lynis generate" ;;
+    esac
+else
+    ${ECHOCMD} "\n  ${WHITE}Provide an additional argument${NORMAL}\n\n"
+    for ITEM in ${GENERATE_ARGS}; do
+        ${ECHOCMD} "    lynis generate ${BROWN}${ITEM}${NORMAL}"
+    done
+    ${ECHOCMD} "\n"
+    ${ECHOCMD} ""
+    ${ECHOCMD} "Extended help about the generate command can be provided with: $0 show commands generate"
+fi
+
+
+ExitClean
+
+# The End
diff --git a/include/helper_show b/include/helper_show
index 6e0738e6..94d839be 100644
--- a/include/helper_show
+++ b/include/helper_show
@@ -28,7 +28,7 @@
 #
 ######################################################################
 
-COMMANDS="audit configure show update upload-only"
+COMMANDS="audit configure generate show update upload-only"
 HELPERS="audit configure show update"
 OPTIONS="--auditor\n--cronjob (--cron)\n--debug\n--developer\n--help (-h)\n--license-key\n--log-file\n--manpage (--man)\n--no-colors\n--no-log\n--pentest\n--profile\n--plugin-dir\n--quick (-Q)\n--quiet (-q)\n--report-file\n--reverse-colors\n--skip-plugins\n--tests\n--tests-from-category\n--tests-from-group\n--upload\n--verbose\n--version (-V)\n--wait\n--warnings-only"
 
@@ -94,6 +94,20 @@ AUDIT_HELP="
 
 "
 
+GENERATE_ARGS="( --save )"
+GENERATE_HELP="
+  Generate random value for hostid and hostid2
+  ${WHITE}lynis generate hostids${NORMAL}
+
+  Generate and save values
+  ${WHITE}lynis generate hostids --save${NORMAL}
+
+  Generate systemd units to run Lynis on a schedule (e.g. daily)
+  ${WHITE}lynis generate systemd-units${NORMAL}
+
+"
+
+
 UPDATE_ARGS="check info"
 UPDATE_HELP="
   ${CYAN}update info${NORMAL}
@@ -149,15 +163,15 @@ if [ $# -gt 0 ]; then
                 if [ ! -z "${CHANGELOG}" ]; then LogText "Result: found changelog file: ${CHANGELOG}"; break; fi
             done
             if [ ! -z "${CHANGELOG}" ]; then
-                SEARCH=$(egrep "^${PROGRAM_NAME} ${SEARCH_VERSION}" ${CHANGELOG})
+                SEARCH=$(sed 's/^## //' ${CHANGELOG} | grep -E "^${PROGRAM_NAME} ${SEARCH_VERSION}")
                 if [ $? -eq 0 ]; then
                     while read -r LINE; do
                         if [ ${STARTED} -eq 0 ]; then
-                            SEARCH=$(echo ${LINE} | egrep "^${PROGRAM_NAME} ${SEARCH_VERSION}")
+                            SEARCH=$(echo ${LINE} | sed 's/^## //' | grep -E "^${PROGRAM_NAME} ${SEARCH_VERSION}")
                             if [ $? -eq 0 ]; then STARTED=1; ${ECHOCMD} "${BOLD}${LINE}${NORMAL}"; fi
                         else
                             # Stop if we find the next Lynis version
-                            SEARCH=$(echo ${LINE} | egrep "^${PROGRAM_NAME} [0-9]\.[0-9]\.[0-9]")
+                            SEARCH=$(echo ${LINE} | sed 's/^## //' | grep -E "^${PROGRAM_NAME} [0-9]\.[0-9]\.[0-9]")
                             if [ $? -eq 0 ]; then
                                 break
                             else
@@ -172,7 +186,7 @@ if [ $# -gt 0 ]; then
                     ${ECHOCMD} "$0 lynis show changelog [version]"
                     ${ECHOCMD} ""
                     ${ECHOCMD} "${HEADER}${PROGRAM_NAME} versions:${NORMAL}"
-                    SEARCH=$(egrep "^Lynis [0-9]\.[0-9]\.[0-9] " ${CHANGELOG} | awk '{print $2}' | sort -n)
+                    SEARCH=$(sed 's/^## //' ${CHANGELOG} | grep -E "^Lynis [0-9]\.[0-9]\.[0-9] " | awk '{print $2}' | sort -n)
                     ${ECHOCMD} ${SEARCH}
                     ExitFatal
                 fi
@@ -274,6 +288,7 @@ if [ $# -gt 0 ]; then
                 shift
                 case $1 in
                    "audit") ${ECHOCMD} "${AUDIT_HELP}" ;;
+                   "generate") ${ECHOCMD} "${GENERATE_HELP}" ;;
                    "show") ${ECHOCMD} "${SHOW_HELP}" ;;
                    "update") ${ECHOCMD} "${UPDATE_HELP}" ;;
                    "upload-only") ${ECHOCMD} "${UPLOAD_ONLY_HELP}" ;;
diff --git a/include/osdetection b/include/osdetection
index 5ab80293..a6c18bb5 100644
--- a/include/osdetection
+++ b/include/osdetection
@@ -477,7 +477,7 @@
     ECHONB=""
 
     case ${OS} in
-        "AIX")                           ECHOCMD="echo" ;;
+        "AIX")                           ECHOCMD="echo"; ECHONB="printf" ;;
         "DragonFly"|"FreeBSD"|"NetBSD")  ECHOCMD="echo -e"; ECHONB="echo -n" ;;
         "macOS" | "Mac OS X")                         ECHOCMD="echo"; ECHONB="/bin/echo -n" ;;
         "Solaris")                       ECHOCMD="echo" ; test -f /usr/ucb/echo && ECHONB="/usr/ucb/echo -n" ;;
diff --git a/include/parameters b/include/parameters
index 96d63524..001044a5 100644
--- a/include/parameters
+++ b/include/parameters
@@ -22,8 +22,21 @@
 #
 #################################################################################
 #
-    # Check number of parameters submitted (at least one is needed)
     PARAMCOUNT=$#
+
+
+    # Input validation on provided parameters and their arguments
+    COUNT=0
+    for I in "$@"; do
+        COUNT=$((COUNT + 1))
+        if ! SafeInput "${I}"; then
+            echo "Execution of ${PROGRAM_NAME} stopped as we found unexpected input or invalid characters in argument ${COUNT}"
+            echo "Do you believe this is in error? Let us know: ${PROGRAM_AUTHOR_CONTACT}"
+            ExitFatal "Program execution stopped due to security measure"
+        fi
+    done
+
+    # Parse arguments
     while [ $# -ge 1 ]; do
         case $1 in
             # Helpers first
@@ -36,12 +49,13 @@
                 if [ $# -gt 1 ]; then
                     case $2 in
                         "dockerfile")
-                            if [ "$3" = "" ]; then
+                            if [ $# = 2 ]; then
                                 echo "${RED}Error: ${WHITE}Missing file name or URL${NORMAL}"
-                                echo "Example: $0 audit dockerfile /root/Dockerfile"
+                                echo "Example: $0 audit dockerfile /path/to/Dockerfile"
                                 ExitFatal
                             else
                                 shift; shift
+                                CHECK_BINARIES=1
                                 HELPER_PARAMS="$1"
                                 HELPER="audit_dockerfile"
                                 break
@@ -111,6 +125,24 @@
                 break
             ;;
 
+            # Generate data
+            generate)
+                CHECK_BINARIES=0
+                HELPER="generate"
+                LOGTEXT=0
+                QUIET=1
+                RUN_HELPERS=1
+                RUN_TESTS=0
+                RUN_UPDATE_CHECK=0
+                SKIP_GETHOSTID=1
+                SKIP_PLUGINS=1
+                SKIP_VM_DETECTION=1
+                SHOW_PROGRAM_DETAILS=0
+                SHOW_TOOL_TIPS=0
+                shift; HELPER_PARAMS="$@"
+                break
+            ;;
+
             # Show Lynis details
             show)
                 CHECK_BINARIES=0
@@ -201,7 +233,7 @@
             # Cronjob support
             --cron-job | --cronjob | --cron)
                 CRONJOB=1
-                CHECK=1; QUICKMODE=1; COLORS=0; NEVERBREAK=1 # Use some defaults (-c, -Q, no colors)
+                CHECK=1; COLORS=0; NEVERBREAK=1 # Use some defaults ('audit system', -Q, no colors)
                 RemoveColors
             ;;
 
@@ -313,7 +345,6 @@
             # Quiet mode
             --quiet | -q | --silent)
                 QUIET=1
-                QUICKMODE=1 # Run non-interactive
             ;;
 
             # Non-interactive mode
@@ -412,7 +443,6 @@
             # Warnings
             --warnings-only | --show-warnings-only)
                 SHOW_WARNINGS_ONLY=1
-                QUICKMODE=1
                 QUIET=1
             ;;
 
@@ -433,5 +463,15 @@
 
     done
 
+    # Ensure non-interactive mode when running quietly or as cronjob
+    if [ ${CRONJOB} -eq 1 -o ${QUIET} -eq 1 ]; then
+        if [ ${QUICKMODE} -eq 0 ]; then
+            if [ ${QUIET} -eq 0 ]; then
+                echo "Switched back to quick mode (cron/non-interactive/quiet)"
+            fi
+            QUICKMODE=1
+        fi
+    fi
+
 #================================================================================
 # Lynis - Security Auditing and System Hardening for Linux and UNIX - https://cisofy.com
diff --git a/include/profiles b/include/profiles
index eba67427..f8935ece 100644
--- a/include/profiles
+++ b/include/profiles
@@ -32,9 +32,38 @@
     for PROFILE in ${PROFILES}; do
 
         LogText "Reading profile/configuration ${PROFILE}"
-        FIND=$(egrep "^config:|^[a-z-].*=" ${PROFILE} | sed 's/ /!space!/g')
-        for CONFIGOPTION in ${FIND}; do
-            if ContainsString "config:" "${CONFIGOPTION}"; then
+
+        # Show deprecation message for old config entries
+        FOUND=0
+        #DATA=$(egrep "^config:" ${PROFILE} | od --address-radix=none -t a | sed 's/ /!space!/g')
+        #if ! IsEmpty "${DATA}"; then FOUND=1; fi
+        # Items such as 'apache:'
+        DATA=$(egrep "^[a-z-]{1,}:" ${PROFILE} | od --address-radix=none -t a | sed 's/ /!space!/g')
+        if ! IsEmpty "${DATA}"; then FOUND=1; fi
+
+        if [ ${FOUND} -eq 1 ]; then
+            DisplayWarning "Your profile contains old-style configuration entries. See log file for more details and how to convert these entries"
+            LogText "Your profile has one or more configuration items that are in an old format (lines starting with key:value). They need to be converted into the new format (key=value)."
+            LogText "Tip: Use egrep to see the relevant matches (egrep \"^[a-z-]{1,}:\" custom.prf)"
+            sleep 30
+        fi
+
+        # Security check for unexpected and possibly harmful escape characters
+        DATA=$(grep -v '^$\|^ \|^#\|^config:'  ${PROFILE} | tr -d '[:alnum:]/\[\]\(\)\-_\|,\.:;= \n\r' | od --address-radix=none -t a | sed 's/ /!space!/g')
+        if ! IsEmpty "${DATA}"; then
+            DisplayWarning "Your profile '${PROFILE}' contains unexpected characters. See the log file for more information."
+            LogText "Found unexpected or possibly harmful characters in the profile. See output below."
+            for I in "${DATA}"; do
+                I=$(echo ${I} | sed 's/!space!/ /g')
+                LogText "Output: ${I}"
+            done
+            sleep 30
+        fi
+
+        # Now parse the profile and filter out unwanted characters
+        DATA=$(egrep "^config:|^[a-z-].*=" ${PROFILE} | tr -dc '[:alnum:]/\[\]\(\)\-_\|,\.:;= \n\r' | sed 's/ /!space!/g')
+        for CONFIGOPTION in ${DATA}; do
+            if ContainsString "^config:" "${CONFIGOPTION}"; then
                 # Old style configuration
                 OPTION=$(echo ${CONFIGOPTION} | cut -d ':' -f2)
                 VALUE=$(echo ${CONFIGOPTION} | cut -d ':' -f3 | sed 's/!space!/ /g')
@@ -90,7 +119,7 @@
                 ;;
 
                 # Ignore configuration data
-                config-data)
+                config-data | permdir | permfile)
                     Debug "Ignoring configuration option, as it will be used by a specific test"
                 ;;
 
@@ -239,6 +268,11 @@
                     LogText "Plugin '${VALUE}' enabled according profile (${PROFILE})"
                 ;;
 
+                disable-plugin)
+                    LogText "Plugin '${VALUE}' disabled according profile (${PROFILE})"
+                    DISABLED_PLUGINS="${DISABLED_PLUGINS} ${VALUE}"
+                ;;
+
                 # Plugin directory
                 plugindir | plugin-dir)
                     if IsEmpty "${PLUGINDIR}"; then
@@ -256,9 +290,9 @@
 
                 # Quick (no waiting for keypresses)
                 quick)
-                    # Quick mode (SKIP_PLUGINS) might already be set outside profile, so store in different variable
-                    SETTING_QUICK_MODE=0 # default is no
-                    FIND=$(echo "${VALUE}" | egrep "^(1|true|yes)$") && QUICKMODE=1
+                    # Quick mode might already be set outside profile, so store in different variable
+                    SETTING_QUICK_MODE=1 # default is yes
+                    FIND=$(echo "${VALUE}" | egrep "^(0|false|no)$") && QUICKMODE=0
                     if [ ! -z "${FIND}" ]; then SETTING_QUICK_MODE=1; fi
                     Debug "Quickmode set to ${SETTING_QUICK_MODE}"
                     AddSetting "quick" "${SETTING_QUICK_MODE}" "Quick mode (non-interactive)"
@@ -328,6 +362,13 @@
                     AddSetting "ssl-certificate-paths" "${SSL_CERTIFICATE_PATHS}" "Paths for SSL certificates"
                 ;;
 
+                ssl-certificate-paths-to-ignore)
+                    # Retrieve paths to ignore when searching for certificates. Strip special characters, replace possible spaces
+                    SSL_CERTIFICATE_PATHS_TO_IGNORE=$(echo ${VALUE} | tr -d '[:cntrl:]' | sed 's/ /__space__/g' | tr ':' ' ')
+                    Debug "SSL paths to ignore: ${SSL_CERTIFICATE_PATHS_TO_IGNORE}"
+                    AddSetting "ssl-certificate-paths-to-ignore" "${SSL_CERTIFICATE_PATHS_TO_IGNORE}" "Paths that should be ignored for SSL certificates"
+                ;;
+
                 # Set strict mode for development and quality purposes
                 strict)
                     FIND=$(echo "${VALUE}" | egrep "^(1|true|yes)") && SET_STRICT=1
@@ -441,10 +482,14 @@
                 # Catch all bad options and bail out
                 *)
                     LogText "Unknown option ${OPTION} (with value: ${VALUE})"
-                    ${ECHOCMD} ""
-                    ${ECHOCMD} "${RED}Error${NORMAL}: found one or more errors in profile ${PROFILE}"
-                    ${ECHOCMD} "${WHITE}Details${NORMAL}: Unknown option '${YELLOW}${OPTION}${NORMAL}' found (with value: ${VALUE})"
-                    ${ECHOCMD} ""
+
+                    ${ECHOCMD:-echo} ""
+                    ${ECHOCMD:-echo} "${RED}Error${NORMAL}: found one or more errors in profile ${PROFILE}"
+                    ${ECHOCMD:-echo} ""
+                    ${ECHOCMD:-echo} ""
+                    ${ECHOCMD:-echo} "Full line: ${CONFIGOPTION}"
+                    ${ECHOCMD:-echo} "${WHITE}Details${NORMAL}: Unknown option '${YELLOW}${OPTION}${NORMAL}' found (with value: ${VALUE})"
+                    ${ECHOCMD:-echo} ""
                     ExitFatal
                 ;;
 
diff --git a/include/report b/include/report
index b200f6be..2df666e4 100644
--- a/include/report
+++ b/include/report
@@ -22,55 +22,79 @@
 #
 #################################################################################
 #
+
+    # Add data fields to report file
+    Report "dhcp_client_running=${DHCP_CLIENT_RUNNING}"
+    Report "arpwatch_running=${ARPWATCH_RUNNING}"
+
+    # Report firewall installed for now, if we found one active. Next step would be determining binaries first and apply additional checks.
+    Report "firewall_active=${FIREWALL_ACTIVE}"
+    Report "firewall_empty_ruleset=${FIREWALL_EMPTY_RULESET}"
+    Report "firewall_installed=${FIREWALL_ACTIVE}"
+
+    if [ ! -z "${INSTALLED_PACKAGES}" ]; then Report "installed_packages_array=${INSTALLED_PACKAGES}"; fi
+
+    Report "package_audit_tool=${PACKAGE_AUDIT_TOOL}"
+    Report "package_audit_tool_found=${PACKAGE_AUDIT_TOOL_FOUND}"
+    Report "vulnerable_packages_found=${VULNERABLE_PACKAGES_FOUND}"
+
+
     # Hardening Index
-    # Define approximately how strong a machine has been hardened
 
-        # If no hardening has been found, set value to 1
-        if [ ${HPPOINTS} -eq 0 ]; then HPPOINTS=1; HPTOTAL=100; fi
-        HPINDEX=$((HPPOINTS * 100 / HPTOTAL))
-        HPAOBLOCKS=$((HPPOINTS * 20 / HPTOTAL))
-        # Set color related to rating
-        if [ ${HPINDEX} -lt 50 ]; then
-            HPCOLOR="${RED}"
-            HIDESCRIPTION="System has not or a low amount been hardened"
-        elif [ ${HPINDEX} -gt 49 -a ${HPINDEX} -lt 80 ]; then
-            HPCOLOR="${YELLOW}"
-            HIDESCRIPTION="System has been hardened, but could use additional hardening"
-        elif [ ${HPINDEX} -gt 79 -a ${HPINDEX} -lt 90 ]; then
-            HPCOLOR="${GREEN}"
-            HIDESCRIPTION="System seem to be decent hardened"
-        elif [ ${HPINDEX} -gt 89 ]; then
-            HPCOLOR="${GREEN}"
-            HIDESCRIPTION="System seem to be well hardened"
-        fi
+    # Goal:
+    # Provide a visual way to show how much the system is hardened
+    #
+    # Important:
+    # The index gives a simplified version of the measures taken on the system.
+    # It should be used to get a first impression about the state of the system or to compare similar systems.
+    # Getting the maximum score (100 or full bar) does not indicate that the system is fully secured.
 
-        case ${HPAOBLOCKS} in
-            0)  HPBLOCKS="#"; HPEMPTY="                   " ;;
-            1)  HPBLOCKS="#"; HPEMPTY="                   " ;;
-            2)  HPBLOCKS="##"; HPEMPTY="                  " ;;
-            3)  HPBLOCKS="###"; HPEMPTY="                 " ;;
-            4)  HPBLOCKS="####"; HPEMPTY="                " ;;
-            5)  HPBLOCKS="#####"; HPEMPTY="               " ;;
-            6)  HPBLOCKS="######"; HPEMPTY="              " ;;
-            7)  HPBLOCKS="#######"; HPEMPTY="             " ;;
-            8)  HPBLOCKS="########"; HPEMPTY="            " ;;
-            9)  HPBLOCKS="#########"; HPEMPTY="           " ;;
-            10) HPBLOCKS="##########"; HPEMPTY="          " ;;
-            11) HPBLOCKS="###########"; HPEMPTY="         " ;;
-            12) HPBLOCKS="############"; HPEMPTY="        " ;;
-            13) HPBLOCKS="#############"; HPEMPTY="       " ;;
-            14) HPBLOCKS="##############"; HPEMPTY="      " ;;
-            15) HPBLOCKS="###############"; HPEMPTY="     " ;;
-            16) HPBLOCKS="################"; HPEMPTY="    " ;;
-            17) HPBLOCKS="#################"; HPEMPTY="   " ;;
-            18) HPBLOCKS="##################"; HPEMPTY="  " ;;
-            19) HPBLOCKS="###################"; HPEMPTY=" " ;;
-            20) HPBLOCKS="####################"; HPEMPTY="" ;;
-        esac
+    # If no hardening has been found, set value to 1
+    if [ ${HPPOINTS} -eq 0 ]; then HPPOINTS=1; HPTOTAL=100; fi
+    HPINDEX=$((HPPOINTS * 100 / HPTOTAL))
+    HPAOBLOCKS=$((HPPOINTS * 20 / HPTOTAL))
+    # Set color related to rating
+    if [ ${HPINDEX} -lt 50 ]; then
+        HPCOLOR="${RED}"
+        HIDESCRIPTION="System has not or a low amount been hardened"
+    elif [ ${HPINDEX} -gt 49 -a ${HPINDEX} -lt 80 ]; then
+        HPCOLOR="${YELLOW}"
+        HIDESCRIPTION="System has been hardened, but could use additional hardening"
+    elif [ ${HPINDEX} -gt 79 -a ${HPINDEX} -lt 90 ]; then
+        HPCOLOR="${GREEN}"
+        HIDESCRIPTION="System seem to be decent hardened"
+    elif [ ${HPINDEX} -gt 89 ]; then
+        HPCOLOR="${GREEN}"
+        HIDESCRIPTION="System seem to be well hardened"
+    fi
 
-        HPGRAPH="[${HPCOLOR}${HPBLOCKS}${NORMAL}${HPEMPTY}]"
-        LogText "Hardening index : [${HPINDEX}] [${HPBLOCKS}${HPEMPTY}]"
-        LogText "Hardening strength: ${HIDESCRIPTION}"
+    case ${HPAOBLOCKS} in
+        0)  HPBLOCKS="#"; HPEMPTY="                   " ;;
+        1)  HPBLOCKS="#"; HPEMPTY="                   " ;;
+        2)  HPBLOCKS="##"; HPEMPTY="                  " ;;
+        3)  HPBLOCKS="###"; HPEMPTY="                 " ;;
+        4)  HPBLOCKS="####"; HPEMPTY="                " ;;
+        5)  HPBLOCKS="#####"; HPEMPTY="               " ;;
+        6)  HPBLOCKS="######"; HPEMPTY="              " ;;
+        7)  HPBLOCKS="#######"; HPEMPTY="             " ;;
+        8)  HPBLOCKS="########"; HPEMPTY="            " ;;
+        9)  HPBLOCKS="#########"; HPEMPTY="           " ;;
+        10) HPBLOCKS="##########"; HPEMPTY="          " ;;
+        11) HPBLOCKS="###########"; HPEMPTY="         " ;;
+        12) HPBLOCKS="############"; HPEMPTY="        " ;;
+        13) HPBLOCKS="#############"; HPEMPTY="       " ;;
+        14) HPBLOCKS="##############"; HPEMPTY="      " ;;
+        15) HPBLOCKS="###############"; HPEMPTY="     " ;;
+        16) HPBLOCKS="################"; HPEMPTY="    " ;;
+        17) HPBLOCKS="#################"; HPEMPTY="   " ;;
+        18) HPBLOCKS="##################"; HPEMPTY="  " ;;
+        19) HPBLOCKS="###################"; HPEMPTY=" " ;;
+        20) HPBLOCKS="####################"; HPEMPTY="" ;;
+    esac
+
+    HPGRAPH="[${HPCOLOR}${HPBLOCKS}${NORMAL}${HPEMPTY}]"
+    LogText "Hardening index : [${HPINDEX}] [${HPBLOCKS}${HPEMPTY}]"
+    LogText "Hardening strength: ${HIDESCRIPTION}"
 
 
     # Only show overview if not running in quiet mode
diff --git a/include/tests_authentication b/include/tests_authentication
index fe8ece41..6c867da6 100644
--- a/include/tests_authentication
+++ b/include/tests_authentication
@@ -40,7 +40,12 @@
     if [ ${SKIPTEST} -eq 0 ]; then
         # Search accounts with UID 0
         LogText "Test: Searching accounts with UID 0"
-        FIND=$(${GREPBINARY} ':0:' ${ROOTDIR}etc/passwd | ${EGREPBINARY} -v '^#|^root:|^(\+:\*)?:0:0:::' | ${CUTBINARY} -d ":" -f1,3 | ${GREPBINARY} ':0')
+        # Check if device is a QNAP, as the root user is called admin, and not root
+        if [ ${QNAP_DEVICE} -eq 1 ]; then
+            FIND=$(${GREPBINARY} ':0:' ${ROOTDIR}etc/passwd | ${EGREPBINARY} -v '^#|^admin:|^(\+:\*)?:0:0:::' | ${CUTBINARY} -d ":" -f1,3 | ${GREPBINARY} ':0')
+        else
+            FIND=$(${GREPBINARY} ':0:' ${ROOTDIR}etc/passwd | ${EGREPBINARY} -v '^#|^root:|^(\+:\*)?:0:0:::' | ${CUTBINARY} -d ":" -f1,3 | ${GREPBINARY} ':0')
+        fi
         if [ ! -z "${FIND}" ]; then
             Display --indent 2 --text "- Administrator accounts" --result "${STATUS_WARNING}" --color RED
             LogText "Result: Found more than one administrator accounts"
@@ -669,8 +674,8 @@
             if [ -d ${DIR} -a ! -L ${DIR} ]; then
                 LogText "Result: directory ${DIR} exists"
                 # Search in the specified directory
-                if [ "${OS}" = "Solaris" ]; then
-                    # Solaris does not support -maxdepth
+                if [ "${OS}" = "AIX" -o "${OS}" = "Solaris" ]; then
+                    # AIX/Solaris does not support -maxdepth
                     FIND=$(find ${DIR} -type f -name "pam_*.so" -print | sort)
                 else
                     FIND=$(find ${DIR} -maxdepth 1 -type f -name "pam_*.so" -print | sort)
@@ -698,25 +703,32 @@
 #
     # Test        : AUTH-9278
     # Description : Search LDAP support in PAM files
-    Register --test-no AUTH-9278 --weight L --network NO --category security --description "Checking LDAP pam status"
+    Register --test-no AUTH-9278 --weight L --network NO --category security --description "Determine LDAP support in PAM files"
     if [ ${SKIPTEST} -eq 0 ]; then
-        LogText "Test: checking presence /etc/pam.d/common-auth"
-        if [ -f /etc/pam.d/common-auth ]; then
-            LogText "Result: file /etc/pam.d/common-auth exists"
-            LogText "Test: checking presence LDAP module"
-            FIND=$(${GREPBINARY} "^auth.*ldap" /etc/pam.d/common-auth)
-            if [ ! "${FIND}" = "" ]; then
-                LogText "Result: LDAP module present"
-                LogText "Output: ${FIND}"
-                Display --indent 2 --text "- LDAP module in PAM" --result "${STATUS_FOUND}" --color GREEN
-                LDAP_AUTH_ENABLED=1
-                LDAP_PAM_ENABLED=1
+        AUTH_FILES="${ROOTDIR}etc/pam.d/common-auth ${ROOTDIR}etc/pam.d/system-auth"
+        for FILE in ${AUTH_FILES}; do
+            LogText "Test: checking presence ${FILE}"
+            if [ -f ${FILE} ]; then
+                LogText "Result: file ${FILE} exists"
+                LogText "Test: checking presence LDAP module"
+                FIND=$(${GREPBINARY} "^auth.*ldap" ${FILE})
+                if [ ! -z "${FIND}" ]; then
+                    LogText "Result: LDAP module present"
+                    LogText "Output: ${FIND}"
+                    LDAP_AUTH_ENABLED=1
+                    LDAP_PAM_ENABLED=1
+                else
+                    LogText "Result: LDAP module not found"
+                fi
             else
-                LogText "Result: LDAP module not found"
-                Display --indent 2 --text "- LDAP module in PAM" --result "${STATUS_NOT_FOUND}" --color WHITE
+                LogText "Result: file ${FILE} not found, skipping test"
             fi
+        done
+
+        if [ ${LDAP_PAM_ENABLED} -eq 1 ]; then
+            Display --indent 2 --text "- LDAP module in PAM" --result "${STATUS_FOUND}" --color GREEN
         else
-            LogText "Result: file /etc/pam.d/common-auth not found, skipping test"
+            Display --indent 2 --text "- LDAP module in PAM" --result "${STATUS_NOT_FOUND}" --color WHITE
         fi
     fi
 #
diff --git a/include/tests_boot_services b/include/tests_boot_services
index 5495938c..42b8dab1 100644
--- a/include/tests_boot_services
+++ b/include/tests_boot_services
@@ -96,7 +96,11 @@
                                 ;;
 
                                 "init" | "initsplash")
-                                    SERVICE_MANAGER="SysV Init"
+                                    if [ -d ${ROOTDIR}etc/rc.d ]; then
+                                        SERVICE_MANAGER="bsdrc.d"
+                                    else
+                                        SERVICE_MANAGER="SysV Init"
+                                    fi
                                 ;;
                                 systemd)
                                     SERVICE_MANAGER="systemd"
diff --git a/include/tests_crypto b/include/tests_crypto
index 4188dea9..6d0d5384 100644
--- a/include/tests_crypto
+++ b/include/tests_crypto
@@ -34,55 +34,78 @@
         COUNT_EXPIRED=0
         COUNT_TOTAL=0
         FOUNDPROBLEM=0
-        sSSL_PATHS=$(echo ${SSL_CERTIFICATE_PATHS} | ${SEDBINARY} 's/:/ /g')
-        sSSL_PATHS=$(echo ${sSSL_PATHS} | ${SEDBINARY} 's/^ //' | ${TRBINARY} " " "\n" | ${SORTBINARY} | uniq | ${TRBINARY} "\n" " ")
+        SKIP=0
+        sSSL_PATHS=$(echo ${SSL_CERTIFICATE_PATHS} | ${SEDBINARY} 's/:space:/__space__/g' | ${SEDBINARY} 's/:/ /g')
+        sSSL_PATHS=$(echo ${sSSL_PATHS} | ${SEDBINARY} 's/^ //' | ${SORTBINARY} | ${UNIQBINARY})
         LogText "Paths to scan: ${sSSL_PATHS}"
 
+        IGNORE_PATHS_PRINT=$(echo ${SSL_CERTIFICATE_PATHS_TO_IGNORE} | ${SEDBINARY} 's/:/, /g' | ${SEDBINARY} 's/__space__/ /g' | ${SEDBINARY} 's/^ //' | ${SORTBINARY} | ${UNIQBINARY})
+        LogText "Paths to ignore: ${IGNORE_PATHS_PRINT}"
+
         for DIR in ${sSSL_PATHS}; do
             COUNT_DIR=0
             if [ -d ${DIR} ]; then
                 FileIsReadable ${DIR}
                 if [ ${CANREAD} -eq 1 ]; then
+                    LASTSUBDIR=""
                     LogText "Result: found directory ${DIR}"
                     # Search for certificate files
-                    FILES=$(${FINDBINARY} ${DIR} -type f 2> /dev/null | ${EGREPBINARY} ".crt$|.pem$|^cert" | ${SORTBINARY} | ${SEDBINARY} 's/ /:space:/g')
+                    FILES=$(${FINDBINARY} ${DIR} -type f 2> /dev/null | ${EGREPBINARY} ".crt$|.pem$|^cert" | ${SORTBINARY} | ${SEDBINARY} 's/ /__space__/g')
                     for FILE in ${FILES}; do
-                        FILE=$(echo ${FILE} |${SEDBINARY} 's/:space:/ /g')
-                        COUNT_DIR=$((COUNT_DIR + 1))
-                        FileIsReadable "${FILE}"
-                        if [ ${CANREAD} -eq 1 ]; then
-                            # Only check the files that are not installed by a package
-                            if ! FileInstalledByPackage "${FILE}"; then
-                                LogText "Test: test if file is a certificate"
-                                OUTPUT=$(${GREPBINARY} -q 'BEGIN CERT' "${FILE}")
-                                if [ $? -eq 0 ]; then
-                                    LogText "Result: file is a certificate"
-                                    LogText "Test: checking certificate details"
-                                    FIND=$(${OPENSSLBINARY} x509 -noout -in "${FILE}" -enddate 2> /dev/null | ${GREPBINARY} "^notAfter")
+                        FILE=$(echo ${FILE} | ${SEDBINARY} 's/__space__/ /g')
+                        # See if we need to skip this path
+                        SUBDIR=$(echo ${FILE} | ${AWKBINARY} -F/ 'sub(FS $NF,x)' | ${SEDBINARY} 's/__space__/ /g')
+                        # If we discover a new directory, do evaluation
+                        #Debug "File   : ${FILE}"
+                        #Debug "Lastdir: ${LASTSUBDIR}"
+                        #Debug "Curdir : ${SUBDIR}"
+                        if [ ! "${SUBDIR}" = "${LASTSUBDIR}" ]; then
+                            SKIP=0
+                            # Now check if this path is on the to-be-ignored list
+                            for D in ${SSL_CERTIFICATE_PATHS_TO_IGNORE}; do
+                                if Equals "${D}" "${SUBDIR}"; then
+                                    SKIP=1
+                                    LogText "Result: skipping directory (${SUBDIR}) as it is on ignore list"
+                                fi
+                            done
+                        fi
+                        if [ ${SKIP} -eq 0 ]; then
+                            #Debug "Testing ${FILE} in path: $SUBDIR"
+                            COUNT_DIR=$((COUNT_DIR + 1))
+                            FileIsReadable "${FILE}"
+                            if [ ${CANREAD} -eq 1 ]; then
+                                # Only check the files that are not installed by a package
+                                if ! FileInstalledByPackage "${FILE}"; then
+                                    OUTPUT=$(${GREPBINARY} -q 'BEGIN CERT' "${FILE}")
                                     if [ $? -eq 0 ]; then
-                                        # Check certificate where 'end date' has been expired
-                                        FIND=$(${OPENSSLBINARY} x509 -noout -checkend 0 -in "${FILE}" -enddate 2> /dev/null)
-                                        EXIT_CODE=$?
-                                        CERT_CN=$(${OPENSSLBINARY} x509 -noout -subject -in "${FILE}" 2> /dev/null | ${SEDBINARY} -e 's/^subject.*CN=\([a-zA-Z0-9\.\-\*]*\).*$/\1/')
-                                        CERT_NOTAFTER=$(${OPENSSLBINARY} x509 -noout -enddate -in "${FILE}" 2> /dev/null | ${AWKBINARY} -F= '{if ($1=="notAfter") { print $2 }}')
-                                        Report "certificate[]=${FILE}|${EXIT_CODE}|cn:${CERT_CN};notafter:${CERT_NOTAFTER};|"
-                                        if [ ${EXIT_CODE} -eq 0 ]; then 
-                                            LogText "Result: certificate ${FILE} seems to be correct and still valid"
+                                        LogText "Result: file is a certificate file"
+                                        FIND=$(${OPENSSLBINARY} x509 -noout -in "${FILE}" -enddate 2> /dev/null | ${GREPBINARY} "^notAfter")
+                                        if [ $? -eq 0 ]; then
+                                            # Check certificate where 'end date' has been expired
+                                            FIND=$(${OPENSSLBINARY} x509 -noout -checkend 0 -in "${FILE}" -enddate 2> /dev/null)
+                                            EXIT_CODE=$?
+                                            CERT_CN=$(${OPENSSLBINARY} x509 -noout -subject -in "${FILE}" 2> /dev/null | ${SEDBINARY} -e 's/^subject.*CN=\([a-zA-Z0-9\.\-\*]*\).*$/\1/')
+                                            CERT_NOTAFTER=$(${OPENSSLBINARY} x509 -noout -enddate -in "${FILE}" 2> /dev/null | ${AWKBINARY} -F= '{if ($1=="notAfter") { print $2 }}')
+                                            Report "certificate[]=${FILE}|${EXIT_CODE}|cn:${CERT_CN};notafter:${CERT_NOTAFTER};|"
+                                            if [ ${EXIT_CODE} -eq 0 ]; then 
+                                                LogText "Result: certificate ${FILE} seems to be correct and still valid"
+                                            else
+                                                FOUNDPROBLEM=1
+                                                COUNT_EXPIRED=$((COUNT_EXPIRED + 1))
+                                                LogText "Result: certificate ${FILE} has been expired"
+                                            fi
                                         else
-                                            FOUNDPROBLEM=1
-                                            COUNT_EXPIRED=$((COUNT_EXPIRED + 1))
-                                            LogText "Result: certificate ${FILE} has been expired"
+                                            LogText "Result: skipping tests for this file (${FILE}) as it is most likely not a certificate (is it a key file?)"
                                         fi
                                     else
-                                        LogText "Result: skipping tests for this file (${FILE}) as it is most likely not a certificate (a key file?)"
+                                        LogText "Result: skipping test for this file (${FILE}) as we could not find 'BEGIN CERT'"
                                     fi
-                                else
-                                    LogText "Result: skipping test for this file (${FILE}) as we could not find 'BEGIN CERT'"
                                 fi
+                            else
+                                LogText "Result: can not read file ${FILE} (no permission)"
                             fi
-                        else
-                            LogText "Result: can not read file ${FILE} (no permission)"
                         fi
+                        LASTSUBDIR="${SUBDIR}"
                     done
                     COUNT_TOTAL=$((COUNT_TOTAL + COUNT_DIR))
                     LogText "Result: found ${COUNT_DIR} certificates in ${DIR}"
@@ -105,6 +128,30 @@
     fi
 #
 #################################################################################
+#
+    # Test        : CRYP-7930
+    # Description : Determine if system uses disk or file encryption
+    Register --test-no CRYP-7930 --weight L --network NO --category security --description "Determine if system uses disk or file encryption"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        FILE="${ROOTDIR}etc/crypttab"
+        if [ -f ${FILE} ]; then
+            LogText "Result: crypttab file (${FILE}) exists"
+            DATA=$(${GREPBINARY} "^[a-z]" ${FILE} | ${TRBINARY} -cd '[:alnum:]_\-=,\n\t ' | ${SEDBINARY} 's/[[:blank:]]/__space__/g')
+            for LINE in ${DATA}; do
+                LINE=$(echo ${LINE} | ${SEDBINARY} 's/__space__/ /g')
+                if ContainsString "luks," "${LINE}"; then
+                    PARTITION=$(echo ${LINE} | ${AWKBINARY} '{print $1}' | ${AWKBINARY} -F_ '{print $1}')
+                    LogText "Result: Found LUKS encryption on partition ${PARTITION}"
+                    Report "encryption[]=luks,partition,${PARTITION}"
+                fi
+            done
+            unset DATA LINE PARTITION
+        else
+            LogText "Result: crypttab file (${FILE}) does not exist"
+        fi
+    fi
+#
+#################################################################################
 #
 
 WaitForKeyPress
diff --git a/include/tests_file_permissions b/include/tests_file_permissions
index 20136488..2c43fc0e 100644
--- a/include/tests_file_permissions
+++ b/include/tests_file_permissions
@@ -34,10 +34,10 @@
         LogText "Test: Checking file permissions"
         for PROFILE in ${PROFILES}; do
             LogText "Using profile ${PROFILE} for baseline."
-            FIND=$(${EGREPBINARY} '^permfile:|^permdir:' ${PROFILE} | ${CUTBINARY} -d: -f2)
+            FIND=$(${EGREPBINARY} '^permfile=|^permdir=' ${PROFILE} | ${CUTBINARY} -d= -f2)
             for I in ${FIND}; do
                 LogText "Checking ${I}"
-                CheckFilePermissions ${I}
+                CheckFilePermissions "${I}"
                 LogText "  Expected permissions: ${PROFILEVALUE}"
                 LogText "  Actual permissions: ${FILEVALUE}"
                 LogText "  Result: $PERMS"
diff --git a/include/tests_filesystems b/include/tests_filesystems
index a52bb66b..4e52ea5e 100644
--- a/include/tests_filesystems
+++ b/include/tests_filesystems
@@ -48,7 +48,11 @@
                 Display --indent 4 --text "- Checking ${I} mount point" --result SYMLINK --color WHITE
             elif [ -d ${I} ]; then
                 LogText "Result: directory ${I} exists"
-                FIND=$(${MOUNTBINARY} | ${AWKBINARY} -v MP=${I} '{ if ($3==MP) { print $3 }}')
+                case "${OS}" in
+                    "AIX") FIND=$(${MOUNTBINARY} | ${AWKBINARY} -v MP=${I} '{ if ($2==MP) { print $2 }}') ;;
+                    *) FIND=$(${MOUNTBINARY} | ${AWKBINARY} -v MP=${I} '{ if ($3==MP) { print $3 }}') ;;
+                esac
+
                 if IsEmpty "${FIND}"; then
                     LogText "Result: ${I} not found in mount list. Directory most likely stored on / file system"
                     Display --indent 4 --text "- Checking ${I} mount point" --result "${STATUS_SUGGESTION}" --color YELLOW
@@ -158,7 +162,27 @@
             done
         else
             LogText "Result: no EXT file systems found"
-            Report "file_systems_ext[]=none"
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : FILE-6324
+    # Description : Checking Linux XFS file systems
+    Register --test-no FILE-6324 --os Linux --weight L --network NO --category security --description "Checking XFS file systems"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        LogText "Test: Checking for Linux XFS file systems"
+        FIND=$(${MOUNTBINARY} -t xfs | ${AWKBINARY} '{ print $3","$5 }')
+        if [ ! -z "${FIND}" ]; then
+            LogText "Result: found one or more XFS file systems"
+            for I in ${FIND}; do
+                FILESYSTEM=$(echo ${I} | ${CUTBINARY} -d ',' -f1)
+                FILETYPE=$(echo ${I} | ${CUTBINARY} -d ',' -f2)
+                LogText "File system: ${FILESYSTEM} (type: ${FILETYPE})"
+                Report "file_systems_xfs[]=${FILESYSTEM}|${FILETYPE}|"
+            done
+        else
+            LogText "Result: no XFS file systems found"
         fi
     fi
 #
@@ -540,13 +564,13 @@
     #            ---------------------------------------------------------
 
     FILESYSTEMS_TO_CHECK="/boot:nodev,noexec,nosuid /dev/shm:nosuid,nodev,noexec /home:nodev,nosuid /tmp:nodev,noexec,nosuid /var:nosuid /var/log:nodev,noexec,nosuid /var/log/audit:nodev,noexec,nosuid /var/tmp:nodev,noexec,nosuid"
-    Register --test-no FILE-6374 --os Linux --weight L --network NO --category security --description "Checking /boot mount options"
+    Register --test-no FILE-6374 --os Linux --weight L --network NO --category security --description "Checking partitions mount options"
     if [ ${SKIPTEST} -eq 0 ]; then
         if [ -f /etc/fstab ]; then
             for I in ${FILESYSTEMS_TO_CHECK}; do
                 FILESYSTEM=$(echo ${I} | ${CUTBINARY} -d: -f1)
                 EXPECTED_FLAGS=$(echo ${I} | ${CUTBINARY} -d: -f2 | ${SEDBINARY} 's/,/ /g')
-                FS_FSTAB=$(${AWKBINARY} -v fs=${FILESYSTEM} '{ if ($2==fs) { print $3 } }' /etc/fstab)
+                FS_FSTAB=$(${AWKBINARY} -v fs=${FILESYSTEM} '{ if ($2==fs) { print $3 } }' ${ROOTDIR}etc/fstab)
                 if [ "${FS_FSTAB}" = "glusterfs" ]; then
                     EXPECTED_FLAGS=$(echo ${EXPECTED_FLAGS} | ${SEDBINARY} 's/\<\(nodev\|nosuid\)\> *//g')
                     if [ -z "${EXPECTED_FLAGS}" ]; then
@@ -554,7 +578,7 @@
                     fi
                 fi
                 if [ ! -z "${FS_FSTAB}" ]; then
-                    FOUND_FLAGS=$(${AWKBINARY} -v fs=${FILESYSTEM} '{ if ($2==fs) { print $4 } }' /etc/fstab | ${SEDBINARY} 's/,/ /g' | ${TRBINARY} '\n' ' ')
+                    FOUND_FLAGS=$(${AWKBINARY} -v fs=${FILESYSTEM} '{ if ($2==fs) { print $4 } }' ${ROOTDIR}etc/fstab | ${SEDBINARY} 's/,/ /g' | ${TRBINARY} '\n' ' ')
                     LogText "File system:    ${FILESYSTEM}"
                     LogText "Expected flags: ${EXPECTED_FLAGS}"
                     LogText "Found flags:    ${FOUND_FLAGS}"
@@ -562,7 +586,7 @@
                     FULLY_HARDENED=1
                     for FLAG in ${EXPECTED_FLAGS}; do
                         FLAG_AVAILABLE=$(echo ${FOUND_FLAGS} | ${GREPBINARY} ${FLAG})
-                        if [ "${FLAG_AVAILABLE}" = "" ]; then
+                        if [ -z "${FLAG_AVAILABLE}" ]; then
                             LogText "Result: Could not find mount option ${FLAG} on file system ${FILESYSTEM}"
                             FULLY_HARDENED=0
                         else
diff --git a/include/tests_firewalls b/include/tests_firewalls
index 85f2b150..735059fe 100644
--- a/include/tests_firewalls
+++ b/include/tests_firewalls
@@ -596,11 +596,6 @@
 #################################################################################
 #
 
-# Report firewall installed for now, if we found one active. Next step would be determining binaries first and apply additional checks.
-Report "firewall_active=${FIREWALL_ACTIVE}"
-Report "firewall_empty_ruleset=${FIREWALL_EMPTY_RULESET}"
-Report "firewall_installed=${FIREWALL_ACTIVE}"
-
 WaitForKeyPress
 
 #
diff --git a/include/tests_insecure_services b/include/tests_insecure_services
index 277791d9..841189d8 100644
--- a/include/tests_insecure_services
+++ b/include/tests_insecure_services
@@ -18,7 +18,7 @@
 #
 #################################################################################
 #
-# Unsecure services
+# Insecure services
 #
 #################################################################################
 #
@@ -28,32 +28,55 @@
 #
     INETD_ACTIVE=0
     INETD_CONFIG_FILE="${ROOTDIR}etc/inetd.conf"
+    INETD_PACKAGE_INSTALLED=0
+    XINETD_ACTIVE=0
+    XINETD_CONFIG_FILE="${ROOTDIR}etc/xinetd.conf"
+    XINETD_CONFIG_DIR="${ROOTDIR}etc/xinetd.d"
+#
+#################################################################################
+#
+    # Test        : INSE-8000
+    # Description : Check for installed inetd package
+    Register --test-no INSE-8000 --weight L --network NO --category security --description "Installed inetd package"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        # Check for installed inetd daemon
+        LogText "Test: Checking if inetd is installed"
+        if PackageIsInstalled "inetd"; then
+            INETD_PACKAGE_INSTALLED=1
+            LogText "Result: inetd is installed"
+            Display --indent 2 --text "- Installed inetd package" --result "${STATUS_FOUND}" --color YELLOW
+            #ReportSuggestion ${TEST_NO} "If there are no inetd services required, it is recommended that the daemon be removed"
+        else
+            LogText "Result: inetd is NOT installed"
+            Display --indent 2 --text "- Installed inetd package" --result "${STATUS_NOT_FOUND}" --color GREEN
+        fi
+    fi
 #
 #################################################################################
 #
     # Test        : INSE-8002
     # Description : Check for inetd status
-    Register --test-no INSE-8002 --weight L --network NO --category security --description "Check for enabled inet daemon"
+    if [ ${INETD_PACKAGE_INSTALLED} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no INSE-8002 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check for enabled inet daemon"
     if [ ${SKIPTEST} -eq 0 ]; then
         # Check running processes
         LogText "Test: Searching for active inet daemon"
-        IsRunning inetd
-        if [ ${RUNNING} -eq 1 ]; then
+        if IsRunning "inetd"; then
             LogText "Result: inetd is running"
-            Display --indent 2 --text "- Checking inetd status" --result "ACTIVE" --color GREEN
+            Display --indent 4 --text "- inetd status" --result "ACTIVE" --color GREEN
             INETD_ACTIVE=1
         else
             LogText "Result: inetd is NOT running"
-            Display --indent 2 --text "- Checking inetd status" --result "NOT ACTIVE" --color GREEN
+            Display --indent 4 --text "- inetd status" --result "NOT ACTIVE" --color GREEN
         fi
     fi
 #
 #################################################################################
 #
     # Test        : INSE-8004
-    # Description : Check for inetd configuration file
+    # Description : Check for inetd configuration file (inetd)
     if [ ${INETD_ACTIVE} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
-    Register --test-no INSE-8004 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check for enabled inet daemon"
+    Register --test-no INSE-8004 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Presence of inetd configuration file"
     if [ ${SKIPTEST} -eq 0 ]; then
         # Check configuration file
         LogText "Test: Searching for file ${INETD_CONFIG_FILE}"
@@ -73,15 +96,15 @@
     if [ ${INETD_ACTIVE} -eq 0 -a -f ${INETD_CONFIG_FILE} ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
     Register --test-no INSE-8006 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check configuration of inetd when disabled"
     if [ ${SKIPTEST} -eq 0 ]; then
-        # Check if any service is enabled in /etc/inetd.conf (inetd is not active, see test 8002)
-        LogText "Test: check if all services are disabled if inetd is disabled"
+        # Check if any service is enabled in /etc/inetd.conf (inetd is not active, see test INSE-8002)
+        LogText "Test: check if all services are disabled when inetd is disabled"
         FIND=$(${GREPBINARY} -v "^#" ${INETD_CONFIG_FILE} | ${GREPBINARY} -v "^$")
         if [ -z "${FIND}" ]; then
             LogText "Result: no services found in ${INETD_CONFIG_FILE}"
-            Display --indent 4 --text "- Checking inetd.conf services" --result "${STATUS_OK}" --color GREEN
+            Display --indent 4 --text "- Checking enabled inetd services" --result "${STATUS_OK}" --color GREEN
         else
             LogText "Result: found services in inetd, even though inetd is not running"
-            Display --indent 4 --text "- Checking inetd.conf services" --result "${STATUS_SUGGESTION}" --color YELLOW
+            Display --indent 4 --text "- Checking enabled inetd services" --result "${STATUS_SUGGESTION}" --color YELLOW
             ReportSuggestion ${TEST_NO} "Although inetd is not running, make sure no services are enabled in ${INETD_CONFIG_FILE}, or remove inetd service"
         fi
     fi
@@ -95,7 +118,7 @@
     if [ ${SKIPTEST} -eq 0 ]; then
         LogText "Test: checking telnet presence in inetd configuration"
         FIND=$(${GREPBINARY} "^telnet" ${INETD_CONFIG_FILE})
-        if [ "${FIND}" = "" ]; then
+        if [ -z "${FIND}" ]; then
             LogText "Result: telnet not enabled in ${INETD_CONFIG_FILE}"
             Display --indent 2 --text "- Checking inetd (telnet)" --result "${STATUS_NOT_FOUND}" --color GREEN
             AddHP 3 3
@@ -108,6 +131,289 @@
     fi
 #
 #################################################################################
+#
+    # Test        : INSE-8100
+    # Description : Check for installed xinetd daemon
+    Register --test-no INSE-8100 --weight L --network NO --category security --description "Check for installed xinetd daemon"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        # Check for installed xinetd daemon
+        LogText "Test: Checking for installed xinetd daemon"
+        if PackageIsInstalled "xinetd"; then
+            LogText "Result: xinetd is installed"
+            Display --indent 2 --text "- Installed xinetd package" --result "${STATUS_FOUND}" --color YELLOW
+            ReportSuggestion ${TEST_NO} "If there are no xinetd services required, it is recommended that the daemon be removed"
+        else
+            LogText "Result: xinetd is NOT installed"
+            Display --indent 2 --text "- Installed xinetd package" --result "${STATUS_OK}" --color GREEN
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : INSE-8102
+    # Description : Check for xinetd status
+    Register --test-no INSE-8102 --weight L --network NO --category security --description "Check for active xinet daemon"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        # Check running processes
+        LogText "Test: Searching for active extended internet services daemon (xinetd)"
+        if IsRunning "xinetd"; then
+            LogText "Result: xinetd is running"
+            Display --indent 4 --text "- xinetd status" --result "ACTIVE" --color GREEN
+            XINETD_ACTIVE=1
+        else
+            LogText "Result: xinetd is NOT running"
+            Display --indent 4 --text "- xinetd status" --result "NOT ACTIVE" --color GREEN
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : INSE-8104
+    # Description : Check for xinetd configuration file
+    if [ ${XINETD_ACTIVE} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no INSE-8104 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check for enabled xinet daemon"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        # Check configuration file
+        LogText "Test: Searching for file ${XINETD_CONFIG_FILE}"
+        if [ -f "${XINETD_CONFIG_FILE}" ]; then
+            LogText "Result: ${XINETD_CONFIG_FILE} exists"
+            Display --indent 6 --text "- Configuration file (xinetd.conf)" --result "${STATUS_FOUND}" --color WHITE
+        else
+            LogText "Result: ${XINETD_CONFIG_FILE} does not exist"
+            Display --indent 6 --text "- Configuration file (xinetd.conf)" --result "${STATUS_NOT_FOUND}" --color WHITE
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : INSE-8106
+    # Description : Check for xinetd configuration file contents if xinetd is NOT active
+    if [ ${XINETD_ACTIVE} -eq 0 -a -f ${XINETD_CONFIG_FILE} ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no INSE-8106 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check configuration of xinetd when disabled"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        # Check if any service is enabled in /etc/xinetd.d (xinetd is not active, see test INSE-8102)
+        LogText "Test: check if all services are disabled if xinetd is disabled"
+        FIND=$(${GREPBINARY} -r "disable\s*=\s*no" ${XINETD_CONFIG_DIR})
+        if [ -z "${FIND}" ]; then
+            LogText "Result: no services found in ${XINETD_CONFIG_DIR}"
+            Display --indent 6 --text "- Enabled xinetd.d services" --result "${STATUS_NOT_FOUND}" --color GREEN
+        else
+            LogText "Result: found services in ${XINETD_CONFIG_DIR}, even though xinetd is not running"
+            Display --indent 6 --text "- Enabled xinetd.d services" --result "${STATUS_FOUND}" --color YELLOW
+            ReportSuggestion ${TEST_NO} "Although xinetd is not running, make sure no services are enabled in ${XINETD_CONFIG_DIR}, or remove xinetd service"
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : INSE-8116
+    # Description : Check for insecure services enabled via xinetd
+    if [ ${XINETD_ACTIVE} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no INSE-8116 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Insecure services enabled via xinetd"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        XINETD_INSECURE_SERVICE_FOUND=0
+
+        ITEMS="chargen chargen-dgram chargen-stream daytime daytime-dgram daytime-stream discard discard-dgram discard-stream echo echo-dgram echo-stream time time-dgram time-stream ntalk rexec rlogin rsh talk telnet tftp"
+
+        for SERVICE in ${ITEMS}; do
+            LogText "Test: checking service ${SERVICE}"
+            if ! SkipAtomicTest "${TEST_NO}:${SERVICE}"; then
+                FILE="${XINETD_CONFIG_DIR}/${SERVICE}"
+                if [ -f "${FILE}" ]; then
+                    LogText "Test: checking status in xinetd configuration file (${FILE})"
+                    FIND=$(${GREPBINARY} "disable\s*=\s*no" ${FILE})
+                    if [ ! -z "${FIND}" ]; then
+                        LogText "Result: found insecure service enabled: ${SERVICE}"
+                        XINETD_INSECURE_SERVICE_FOUND=1
+                        ReportSuggestion "${TEST_NO}" "Disable or remove any insecure services in the xinetd configuration" "${SERVICE}" "text:See log file for more details"
+                        Report "insecure_service[]=${SERVICE}"
+                    fi
+                fi
+            else
+                LogText "Result: skipped, as this item is excluded using the profile"
+            fi
+        done
+
+        if [ ${XINETD_INSECURE_SERVICE_FOUND} -eq 0 ]; then
+            LogText "Result: no insecure services found in xinetd configuration"
+            Display --indent 6 --text "- Checking xinetd (insecure services)" --result "${STATUS_OK}" --color GREEN
+            AddHP 3 3
+        else
+            LogText "Result: one ore more insecure services discovered in xinetd configuration"
+            Display --indent 6 --text "- Checking xinetd (insecure services)" --result "${STATUS_WARNING}" --color RED
+            AddHP 0 3
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : INSE-8150
+    # Description : Check for rsync enabled via xinetd
+    #RSYNC_XINETD_CONFIG_FILE="${XINETD_CONFIG_DIR}/rsync"
+    #if [ ${XINETD_ACTIVE} -eq 1 -a -f ${RSYNC_XINETD_CONFIG_FILE} ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    #Register --test-no INSE-8150 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check for rsync via xinetd"
+    #if [ ${SKIPTEST} -eq 0 ]; then
+    #    LogText "Test: checking rsync presence in xinetd configuration"
+    #    FIND=$(${GREPBINARY} "disable\s*=\s*no" ${RSYNC_XINETD_CONFIG_FILE})
+    #    if [ "${FIND}" = "" ]; then
+    #        LogText "Result: rsync not enabled in ${RSYNC_XINETD_CONFIG_FILE}"
+    #        Display --indent 6 --text "- Checking xinetd (rsync)" --result "${STATUS_DISABLED}" --color GREEN
+    #    else
+    #        LogText "Result: rsync enabled in ${RSYNC_XINETD_CONFIG_FILE}"
+    #        Display --indent 6 --text "- Checking xinetd (rsync)" --result "${STATUS_ENABLED}" --color RED
+    #        ReportSuggestion "${TEST_NO}" "Disable rsync in xinetd configuration"
+    #    fi
+    #fi
+#
+#################################################################################
+#
+    # Test        : INSE-8200
+    # Description : Check if tcp_wrappers is installed when inetd/xinetd is active
+    if [ ${INETD_ACTIVE} -eq 1 -o ${XINETD_ACTIVE} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no INSE-8200 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check if tcp_wrappers is installed when inetd/xinetd is active"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        LogText "Test: Checking if tcp_wrappers is installed"
+        FOUND=0
+        PACKAGES="tcp_wrappers tcpd"
+        for PACKAGE in ${PACKAGES}; do
+            if PackageIsInstalled "${PACKAGE}"; then LogText "Package '${PACKAGE}' is installed"; FOUND=1; fi
+        done
+        if [ ${FOUND} -eq 1 ]; then
+            LogText "Result: tcp_wrappers is installed"
+            Display --indent 2 --text "- Checking tcp_wrappers installation" --result "${STATUS_OK}" --color GREEN
+        else
+            LogText "Result: tcp_wrappers is NOT installed"
+            Display --indent 2 --text "- Checking tcp_wrappers installation" --result "${STATUS_SUGGESTION}" --color YELLOW
+            #ReportSuggestion ${TEST_NO} "When network services are using the inetd/xinetd service, the tcp_wrappers package should be installed"
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : INSE-8300
+    # Description : Check if rsh client is installed
+    Register --test-no INSE-8300 --weight L --network NO --category security --description "Check if rsh client is installed"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        LogText "Test: Checking if rsh client is installed"
+        FOUND=0
+        PACKAGES="rsh rsh-client rsh-redone-client"
+        for PACKAGE in ${PACKAGES}; do
+            if PackageIsInstalled "${PACKAGE}"; then LogText "Package '${PACKAGE}' is installed"; FOUND=1; fi
+        done
+        if [ ${FOUND} -eq 1 ]; then
+            LogText "Result: rsh client is installed"
+            Display --indent 2 --text "- Installed rsh client package" --result "${STATUS_SUGGESTION}" --color YELLOW
+            ReportSuggestion ${TEST_NO} "Remove rsh client when it is not in use or replace with the more secure SSH package"
+        else
+            LogText "Result: rsh client is NOT installed"
+            Display --indent 2 --text "- Installed rsh client package" --result "${STATUS_OK}" --color GREEN
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : INSE-8302
+    # Description : Check presence of rsh Trust Files
+    #Register --test-no INSE-8302 --weight L --network NO --category security --description "Check presence of rsh Trust Files"
+    #if [ ${SKIPTEST} -eq 0 ]; then
+    #    # Check presence of Rsh Trust Files
+    #    FOUND=0
+    #    for LINE in $(${CAT_BINARY} /etc/passwd | ${EGREPBINARY} -v '^(root|halt|sync|shutdown)' | ${AWKBINARY} -F: '($7 !="/sbin/nologin" && $7 != "/bin/false") { print }'); do
+    #        USER=$(echo ${LINE} | ${CUTBINARY} -d: -f1)
+    #        DIR=$(echo ${LINE} | ${CUTBINARY} -d: -f6)
+    #            if [ -d ${DIR} ]; then
+    #                for RHOSTS in ${DIR}/.rhosts; do
+    #                    if [ ! -h ${RHOSTS} -a -f ${RHOSTS} ]; then
+    #                        LogText "FOUND .rhosts file in home directory ${DIR} of ${USER}"
+    #                        FOUND=1
+    #                    fi
+    #                done
+    #            fi
+    #    done
+    #    if [ -f /etc/hosts.equiv ];then
+    #        LogText "FOUND /etc/hosts.equiv"
+    #        FOUND=1
+    #    fi
+    #    if [ ${FOUND} -eq 1 ]; then
+    #        LogText "Result: found one or more Rsh Trust Files"
+    #        Display --indent 4 --text "- Checking presence of Rsh Trust Files" --result "${STATUS_SUGGESTION}" --color YELLOW
+    #        ReportSuggestion ${TEST_NO} "Remove every Rsh Trust Files as they can allow unauthenticated access to a system"
+    #    else
+    #        LogText "Result: no Rsh Trust Files found"
+    #        Display --indent 4 --text "- Checking presence of Rsh Trust Files" --result "${STATUS_OK}" --color GREEN
+    #    fi
+    #fi
+#
+#################################################################################
+#
+    # Test        : INSE-8304
+    # Description : Check if rsh server is installed
+    Register --test-no INSE-8342 --weight L --network NO --category security --description "Check if rsh server is installed"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        # Check if rsh server is installed
+        LogText "Test: Checking if rsh server is installed"
+        FOUND=0
+        PACKAGES="rsh-server rsh-redone-server"
+        for PACKAGE in ${PACKAGES}; do
+            if PackageIsInstalled "${PACKAGE}"; then LogText "Package '${PACKAGE}' is installed"; FOUND=1; fi
+        done
+        if [ ${FOUND} -eq 1 ]; then
+            LogText "Result: rsh server is installed"
+            Display --indent 2 --text "- Installed rsh server package" --result "${STATUS_SUGGESTION}" --color YELLOW
+            ReportSuggestion ${TEST_NO} "Remove the rsh-server package and replace with a more secure alternative like SSH"
+            Report "insecure_service[]=rsh-server"
+        else
+            LogText "Result: rsh server is NOT installed"
+            Display --indent 2 --text "- Installed rsh server package" --result "${STATUS_OK}" --color GREEN
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : INSE-8310
+    # Description : Check if telnet client is installed
+    Register --test-no INSE-8310 --weight L --network NO --category security --description "Check if telnet client is installed"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        # Check if telnet client is installed
+        LogText "Test: Checking if telnet client is installed"
+        if PackageIsInstalled "${PACKAGE}"; then LogText "Package '${PACKAGE}' is installed"; FOUND=1; fi
+
+        if [ ${FOUND} -eq 1 ]; then
+            LogText "Result: telnet client is installed"
+            Display --indent 2 --text "- Installed telnet client package" --result "${STATUS_FOUND}" --color YELLOW
+            # Telnet client usage might be used for troubleshooting instead of system administration
+            #ReportSuggestion ${TEST_NO} "telnet client contain numerous security exposures and have been replaced with the more secure SSH package"
+        else
+            LogText "Result: telnet client is NOT installed"
+            Display --indent 2 --text "- Installed telnet client package" --result "${STATUS_OK}" --color GREEN
+        fi
+    fi
+#
+#################################################################################
+#
+    # Test        : INSE-8312
+    # Description : Check if telnet server is installed
+    Register --test-no INSE-8322 --weight L --network NO --category security --description "Check if telnet server is installed"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        # Check if TFTP server is installed
+        LogText "Test: Checking if telnet server is installed"
+        FOUND=0
+        PACKAGES="telnetd telnet-server"
+        for PACKAGE in ${PACKAGES}; do
+            if PackageIsInstalled "${PACKAGE}"; then LogText "Package '${PACKAGE}' is installed"; FOUND=1; fi
+        done
+        if [ ${FOUND} -eq 1 ]; then
+            LogText "Result: telnet server is installed"
+            Display --indent 2 --text "- Installed telnet server package" --result "${STATUS_FOUND}" --color YELLOW
+            ReportSuggestion ${TEST_NO} "Removing the ${FOUND} package and replace with SSH when possible"
+            Report "insecure_service[]=telnet-server"
+        else
+            LogText "Result: telnet server is NOT installed"
+            Display --indent 2 --text "- Installed telnet server package" --result "${STATUS_NOT_FOUND}" --color GREEN
+        fi
+    fi
+#
+#################################################################################
 #
     if [ ! -z "${LAUNCHCTL_BINARY}" ]; then PREQS_MET="YES"; SKIPREASON=""; else PREQS_MET="NO"; SKIPREASON="No launchctl binary on this system"; fi
     Register --test-no INSE-8050 --os "macOS" --preqs-met ${PREQS_MET} --skip-reason "${SKIPREASON}" --weight M --network NO --category security --description "Check for insecure services on macOS"
diff --git a/include/tests_memory_processes b/include/tests_memory_processes
index 71c0fc42..fc1789dc 100644
--- a/include/tests_memory_processes
+++ b/include/tests_memory_processes
@@ -30,17 +30,17 @@
     # Description : Query /proc/meminfo
     Register --test-no PROC-3602 --os Linux --weight L --network NO --category security --description "Checking /proc/meminfo for memory details"
     if [ ${SKIPTEST} -eq 0 ]; then
-        if [ -f /proc/meminfo ]; then
-            LogText "Result: found /proc/meminfo"
-            Display --indent 2 --text "- Checking /proc/meminfo" --result "${STATUS_FOUND}" --color GREEN
-            FIND=$(${AWKBINARY} '/^MemTotal/ { print $2, $3 }' /proc/meminfo)
+        if [ -f ${ROOTDIR}proc/meminfo ]; then
+            LogText "Result: found ${ROOTDIR}proc/meminfo"
+            Display --indent 2 --text "- Checking ${ROOTDIR}proc/meminfo" --result "${STATUS_FOUND}" --color GREEN
+            FIND=$(${AWKBINARY} '/^MemTotal/ { print $2, $3 }' ${ROOTDIR}proc/meminfo)
             MEMORY_SIZE=$(echo ${FIND} | ${AWKBINARY} '{ print $1 }')
             MEMORY_UNITS=$(echo ${FIND} | ${AWKBINARY} '{ print $2 }')
             LogText "Result: Found ${MEMORY_SIZE} ${MEMORY_UNITS} memory"
             Report "memory_size=${MEMORY_SIZE}"
             Report "memory_units=${MEMORY_UNITS}"
         else
-            LogText "Result: /proc/meminfo file not found on this system"
+            LogText "Result: ${ROOTDIR}proc/meminfo file not found on this system"
         fi
     fi
 #
@@ -80,7 +80,7 @@
         fi
         if [ -z "${FIND}" ]; then
             LogText "Result: no zombie processes found"
-            Display --indent 2 --text "- Searching for dead/zombie processes" --result "${STATUS_OK}" --color GREEN
+            Display --indent 2 --text "- Searching for dead/zombie processes" --result "${STATUS_NOT_FOUND}" --color GREEN
         else
             LogText "Result: found one or more dead or zombie processes"
             LogText "Output: PIDs ${FIND}"
@@ -104,7 +104,7 @@
         fi
         if [ -z "${FIND}" ]; then
             LogText "Result: No processes were waiting for IO requests to be handled first"
-            Display --indent 2 --text "- Searching for IO waiting processes" --result "${STATUS_OK}" --color GREEN
+            Display --indent 2 --text "- Searching for IO waiting processes" --result "${STATUS_NOT_FOUND}" --color GREEN
         else
             LogText "Result: found one or more processes which were waiting to get IO requests handled first"
             LogText "More info: processes which show up with the status flag 'D' are often stuck, until a disk IO event finished. This can happen for example with network storage, where the connection or protocol settings are not logtext well configured."
@@ -116,6 +116,27 @@
 #
 #################################################################################
 #
+    # Test        : PROC-3802
+    # Description : Check presence of prelink tooling
+    Register --test-no PROC-3802 --weight L --network NO --category security --description "Check presence of prelink tooling"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        if PackageIsInstalled "prelink"; then
+            LogText "Result: prelink packages is installed"
+            # TODO
+            # - Add item to website with rationale
+            #ReportSuggestion "${TEST_NO}" "Disable and remove prelinking of binaries"
+            AddHP 1 3
+            Display --indent 2 --text "- Search prelink tooling" --result "${STATUS_FOUND}" --color YELLOW
+        else
+            Display --indent 2 --text "- Search prelink tooling" --result "${STATUS_NOT_FOUND}" --color GREEN
+            LogText "Result: prelink package is NOT installed"
+            AddHP 3 3
+        fi
+    fi
+#
+#################################################################################
+#
+
 
 WaitForKeyPress
 
diff --git a/include/tests_nameservices b/include/tests_nameservices
index 19189898..2ae503e3 100644
--- a/include/tests_nameservices
+++ b/include/tests_nameservices
@@ -644,15 +644,15 @@
         if [ "${FIND}" = "127.0.0.1" ]; then
             LogText "Result: localhost mapped to 127.0.0.1"
             Display --indent 4 --text "- Checking /etc/hosts (localhost to IP)" --result "${STATUS_OK}" --color GREEN
-            report "localhost-mapped-to=${FIND}"
+            Report "localhost-mapped-to=${FIND}"
         elif [ "${FIND}" = "::1" ]; then
             LogText "Result: localhost mapped to ::1"
             Display --indent 4 --text "- Checking /etc/hosts (localhost to IP)" --result "${STATUS_OK}" --color GREEN
-            report "localhost-mapped-to=${FIND}"
+            Report "localhost-mapped-to=${FIND}"
         elif [ "${FIND}" = "127.0.0.1::1" ]; then
             LogText "Result: localhost mapped to 127.0.0.1 and ::1"
             Display --indent 4 --text "- Checking /etc/hosts (localhost to IP)" --result "${STATUS_OK}" --color GREEN
-            report "localhost-mapped-to=${FIND}"
+            Report "localhost-mapped-to=${FIND}"
         else
             LogText "Output: ${FIND}"
             LogText "Result: this server hostname is not mapped to a local address"
diff --git a/include/tests_networking b/include/tests_networking
index 3986220b..8c895c4e 100644
--- a/include/tests_networking
+++ b/include/tests_networking
@@ -370,6 +370,7 @@
     # Description : Check listening ports
     Register --test-no NETW-3012 --weight L --network NO --category security --description "Check listening ports"
     if [ ${SKIPTEST} -eq 0 ]; then
+        DATA=""
         FIND=""; FIND2=""
         COUNT=0
         case ${OS} in
@@ -381,24 +382,19 @@
                     FIND=""
                 fi
                 FIND2=""
-                ;;
+            ;;
             Linux)
-                if [ ! -z "${NETSTATBINARY}" ]; then
+                if [ -n "${SSBINARY}" ]; then
+                    DATA=$(${SSBINARY} --query=udp,tcp -plnt | awk '{ if ($1!="Netid") { print "raw,ss,v1|"$1"|"$5"|"$7"|" }}' | sed 's/pid=[0-9]\{1,\},fd=[0-9]\{1,\}//g' | sed 's/users://' | sed 's/,)//g' | tr -d '()"')
+                elif [ -n "${NETSTATBINARY}" ]; then
                     # UDP
                     FIND=$(${NETSTATBINARY} -nlp 2> /dev/null | ${GREPBINARY} "^udp" | ${AWKBINARY} '{ print $4"|"$1"|"$6"|" }' | ${SEDBINARY} 's:|[0-9]*/:|:')
                     # TCP
                     FIND2=$(${NETSTATBINARY} -nlp 2> /dev/null  | ${GREPBINARY} "^tcp" | ${AWKBINARY} '{ if($6=="LISTEN") { print $4"|"$1"|"$7"|" }}' | ${SEDBINARY} 's:|[0-9]*/:|:')
                 else
-                    if [ ! "${SSBINARY}" = "" ]; then
-                        # UDP
-                        FIND=$(${SSBINARY} -u -a -n 2> /dev/null | ${AWKBINARY} '{ print $4 }' | ${GREPBINARY} -v Local)
-                        # TCP
-                        FIND2=$(${SSBINARY} -t -a -n 2> /dev/null | ${AWKBINARY} '{ print $4 }' | ${GREPBINARY} -v Local)
-                    else
-                        ReportException "${TEST_NO}:1" "netstat and ss binary missing to gather listening ports"
-                    fi
+                    ReportException "${TEST_NO}:1" "netstat and ss binary missing to gather listening ports"
                 fi
-                ;;
+            ;;
 
             macOS)
                 if [ ! "${LSOFBINARY}" = "" ]; then
@@ -409,9 +405,7 @@
                 fi
                 # Not needed as we have a combined test
                 FIND2=""
-                ;;
-
-
+            ;;
             NetBSD)
                 if [ ! "${SOCKSTATBINARY}" = "" ]; then
                     FIND=$(${SOCKSTATBINARY} 2> /dev/null | ${AWKBINARY} '{ if ($7 ~ /\*.\*/) print $5"|"$6"|"$2"|" }' | ${SORTBINARY} -u)
@@ -419,7 +413,7 @@
                     FIND=""
                 fi
                 FIND2=""
-                ;;
+            ;;
             OpenBSD)
                 if [ ! "${NETSTATBINARY}" = "" ]; then
                     # UDP
@@ -429,13 +423,20 @@
                 else
                     ReportException "${TEST_NO}:3" "netstat missing to gather listening ports"
                 fi
-                ;;
+            ;;
             *)
                 # Got this exception? Provide your details and output of netstat or any other tool to determine this information.
                 ReportException "${TEST_NO}:2" "Unclear what method to use, to determine listening port information"
-                ;;
+            ;;
         esac
 
+        if HasData "${DATA}"; then
+            for ITEM in ${DATA}; do
+                COUNT=$((COUNT + 1))
+                Report "network_listen[]=${ITEM}"
+            done
+        fi
+
         # Retrieve information from sockstat, when available
         LogText "Test: Retrieving sockstat information to find listening ports"
         if HasData "${FIND}"; then
@@ -453,11 +454,10 @@
                 Report "network_listen_port[]=${ITEM}"
             done
         fi
-        if [ "${FIND}" = "" -a "${FIND2}" = "" ]; then
+        if [ -z "${DATA}" -a -z "${FIND}" ]; then
             Display --indent 2 --text "- Getting listening ports (TCP/UDP)" --result "${STATUS_SKIPPED}" --color YELLOW
         else
             Display --indent 2 --text "- Getting listening ports (TCP/UDP)" --result "${STATUS_DONE}" --color GREEN
-            Display --indent 6 --text "* Found ${COUNT} ports"
         fi
     fi
 #
@@ -610,33 +610,34 @@
     if [ ${SKIPTEST} -eq 0 ]; then
         FOUND=0
 
+        # addrwatch
+        if IsRunning "addrwatch"; then
+            FOUND=1
+        fi
+
         # arpwatch
-        IsRunning arpwatch
-        if [ ${RUNNING} -eq 1 ]; then
+        if IsRunning "arpwatch"; then
             FOUND=1
             ARPWATCH_RUNNING=1
-            Display --indent 2 --text "- Checking for ARP monitoring software" --result "${STATUS_RUNNING}" --color GREEN
         fi
 
         # arpon
-        IsRunning arpon
-        if [ ${RUNNING} -eq 1 ]; then
+        if IsRunning "arpon"; then
             FOUND=1
             ARPON_RUNNING=1
-            Display --indent 2 --text "- Checking for ARP monitoring software" --result "${STATUS_RUNNING}" --color GREEN
         fi
-        if [ ${FOUND} -eq 0 ]; then
+
+        if [ ${FOUND} -eq 1 ]; then
+            Display --indent 2 --text "- Checking for ARP monitoring software" --result "${STATUS_RUNNING}" --color GREEN
+        else
             Display --indent 2 --text "- Checking for ARP monitoring software" --result "${STATUS_NOT_FOUND}" --color YELLOW
-            ReportSuggestion ${TEST_NO} "Consider running ARP monitoring software (arpwatch,arpon)"
+            ReportSuggestion "${TEST_NO}" "Consider running ARP monitoring software (addrwatch,arpwatch,arpon)"
         fi
     fi
 #
 #################################################################################
 #
 
-Report "dhcp_client_running=${DHCP_CLIENT_RUNNING}"
-Report "arpwatch_running=${ARPWATCH_RUNNING}"
-
 WaitForKeyPress
 
 #
diff --git a/include/tests_php b/include/tests_php
index 363321cf..76606c64 100644
--- a/include/tests_php
+++ b/include/tests_php
@@ -42,6 +42,9 @@
                 ${ROOTDIR}etc/php5/apache2/php.ini \
                 ${ROOTDIR}etc/php5/fpm/php.ini \
                 ${ROOTDIR}private/etc/php.ini \
+                ${ROOTDIR}etc/php/7.2/apache2/php.ini \
+                ${ROOTDIR}etc/php/7.1/apache2/php.ini \
+                ${ROOTDIR}etc/php/7.0/apache2/php.ini \
                 ${ROOTDIR}etc/php/7.2/cli/php.ini ${ROOTDIR}etc/php/7.2/fpm/php.ini \
                 ${ROOTDIR}etc/php/7.1/cli/php.ini ${ROOTDIR}etc/php/7.1/fpm/php.ini \
                 ${ROOTDIR}etc/php/7.0/cli/php.ini ${ROOTDIR}etc/php/7.0/fpm/php.ini \
diff --git a/include/tests_ports_packages b/include/tests_ports_packages
index 1426a068..6b6b2ed9 100644
--- a/include/tests_ports_packages
+++ b/include/tests_ports_packages
@@ -344,7 +344,7 @@
         COUNT=0
         PACKAGE_AUDIT_TOOL_FOUND=1
         PACKAGE_AUDIT_TOOL="zypper"
-        FIND=$(${ZYPPERBINARY} -n se -t package -i | ${AWKBINARY} '{ if ($1=="i") { print $3 } }')
+        FIND=$(${ZYPPERBINARY} --non-interactive -n se -t package -i | ${AWKBINARY} '{ if ($1=="i") { print $3 } }')
         if [ ! -z "${FIND}" ]; then
             for PKG in ${FIND}; do
                 COUNT=$((COUNT + 1))
@@ -365,7 +365,7 @@
     if [ ! -z "${ZYPPERBINARY}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
     Register --test-no PKGS-7330 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Querying Zypper for vulnerable packages"
     if [ ${SKIPTEST} -eq 0 ]; then
-        FIND=$(${ZYPPERBINARY} -n pchk | ${GREPBINARY} "(0 security patches)")
+        FIND=$(${ZYPPERBINARY} --non-interactive pchk | ${GREPBINARY} "(0 security patches)")
         if [ ! -z "${FIND}" ]; then
             LogText "Result: No security updates found with Zypper"
             Display --indent 2 --text "- Using Zypper to find vulnerable packages" --result "${STATUS_NONE}" --color GREEN
@@ -374,7 +374,7 @@
             LogText "Result: Zypper found one or more installed packages which are vulnerable."
             ReportWarning ${TEST_NO} "Found one or more vulnerable packages installed"
             # Unfortunately zypper does not properly give back which package it is. Usually best guess is last word on the line
-            FIND=$(${ZYPPERBINARY} -n lp | ${AWKBINARY} '{ if ($5=="security" || $7=="security") { print $NF }}' | ${SEDBINARY} 's/:$//' | ${GREPBINARY} -v "^$" | ${SORTBINARY} -u)
+            FIND=$(${ZYPPERBINARY} --non-interactive lp | ${AWKBINARY} '{ if ($5=="security" || $7=="security") { print $NF }}' | ${SEDBINARY} 's/:$//' | ${GREPBINARY} -v "^$" | ${SORTBINARY} -u)
             LogText "List of vulnerable packages/version:"
             for PKG in ${FIND}; do
                 VULNERABLE_PACKAGES_FOUND=1
@@ -879,8 +879,7 @@
         if [ ${DO_TEST} -eq 0 ]; then
             FileExists ${ROOTDIR}usr/share/yum-cli/cli.py
             if [ ${FILE_FOUND} -eq 1 ]; then
-                SearchItem "\-\-security" "${ROOTDIR}usr/share/yum-cli/cli.py"
-                if [ ${ITEM_FOUND} -eq 1 ]; then
+                if SearchItem "\-\-security" "${ROOTDIR}usr/share/yum-cli/cli.py"; then
                     DO_TEST=1
                     LogText "Result: found built-in security in yum"
                 else
@@ -892,8 +891,7 @@
         if [ ${DO_TEST} -eq 0 ]; then
             FileExists ${ROOTDIR}etc/yum/pluginconf.d/security.conf
             if [ ${FILE_FOUND} -eq 1 ]; then
-                SearchItem "^enabled=1$" "${ROOTDIR}etc/yum/pluginconf.d/security.conf"
-                if [ ${ITEM_FOUND} -eq 1 ]; then
+                if SearchItem "^enabled=1$" "${ROOTDIR}etc/yum/pluginconf.d/security.conf"; then
                     DO_TEST=1
                     LogText "Result: found enabled plugin"
                 else
@@ -930,7 +928,6 @@
                     AddHP 1 2
                 done
                 ReportWarning ${TEST_NO} "Found one or more vulnerable packages."
-                ReportSuggestion ${TEST_NO} "Use 'yum --security update' to update your system"
             fi
         else
             LogText "Result: yum-security package not found"
@@ -968,8 +965,8 @@
         FOUND=0
         FileExists ${ROOTDIR}etc/yum.conf
         if [ ${FILE_FOUND} -eq 1 ]; then
-            SearchItem "^gpgenabled\s*=\s*1$" "${ROOTDIR}etc/yum.conf"; if [ ${ITEM_FOUND} -eq 1 ]; then FOUND=1; fi
-            SearchItem "^gpgcheck\s*=\s*1$" "${ROOTDIR}etc/yum.conf"; if [ ${ITEM_FOUND} -eq 1 ]; then FOUND=1; fi
+            if SearchItem "^gpgenabled\s*=\s*1$" "${ROOTDIR}etc/yum.conf"; then FOUND=1; fi
+            if SearchItem "^gpgcheck\s*=\s*1$" "${ROOTDIR}etc/yum.conf"; then FOUND=1; fi
             if [ ${FOUND} -eq 1 ]; then
                 LogText "Result: GPG check is enabled"
                 Display --indent 2 --text "- Checking GPG checks (yum.conf)" --result "${STATUS_OK}" --color GREEN
@@ -1055,7 +1052,8 @@
 #
     # Test        : PKGS-7392
     # Description : Check Debian/Ubuntu vulnerable packages
-    if [ -x ${ROOTDIR}usr/bin/apt-get ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    # Note        : Skip for zypper-based systems
+    if [ -x ${ROOTDIR}usr/bin/apt-get -a -z "${ZYPPERBINARY}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
     Register --test-no PKGS-7392 --os Linux --preqs-met ${PREQS_MET} --root-only YES --weight L --network YES --category security --description "Check for Debian/Ubuntu security updates"
     if [ ${SKIPTEST} -eq 0 ]; then
         VULNERABLE_PACKAGES_FOUND=0
@@ -1247,8 +1245,20 @@
     Register --test-no PKGS-7410 --weight L --network NO --category security --description "Count installed kernel packages"
     if [ ${SKIPTEST} -eq 0 ]; then
         KERNELS=0
-        if [ ! -z "${RPMBINARY}" ]; then
-            LogText "Test: Checking how many kernel packages are installed"
+        LogText "Test: Checking how many kernel packages are installed"
+
+        if [ ! -z "${DPKGBINARY}" ]; then
+            KERNELS=$(${DPKGBINARY} -l 2> /dev/null | ${GREPBINARY} "linux-image-[0-9]" | ${WCBINARY} -l)
+            if [ ${KERNELS} -eq 0 ]; then
+                LogText "Result: found no kernels from dpkg -l output, which is unexpected"
+                ReportException "KRNL-5840:2" "Could not find any kernel packages from DPKG output"
+            elif [ ${KERNELS} -gt 5 ]; then
+                LogText "Result: found more than 5 kernel packages on the system, which might indicate lack of regular cleanups"
+                ReportSuggestion "${TEST_NO}" "Remove any unneeded kernel packages" "${KERNELS} kernels" "text:validate dpkg -l output and perform cleanup with apt autoremove"
+            else
+                LogText "Result: found ${KERNELS} kernel packages on the system, which is fine"
+            fi
+        elif [ ! -z "${RPMBINARY}" ]; then
             KERNELS=$(${RPMBINARY} -q kernel 2> /dev/null | ${WCBINARY} -l)
             if [ ${KERNELS} -eq 0 ]; then
                 LogText "Result: found no kernels from rpm -q kernel output, which is unexpected"
@@ -1256,22 +1266,77 @@
             elif [ ${KERNELS} -gt 5 ]; then
                 LogText "Result: found more than 5 kernel packages on the system, which might indicate lack of regular cleanups"
                 ReportSuggestion "${TEST_NO}" "Remove any unneeded kernel packages with package-cleanup utility (--old-kernels)"
-                AddHP 4 5
             else
-                LogText "Result: found ${KERNELS} on the system, which is fine"
-                AddHP 1 1
+                LogText "Result: found ${KERNELS} kernel packages on the system, which is fine"
             fi
         fi
+
+        Report "installed_kernel_packages=${KERNELS}"
     fi
 #
 #################################################################################
 #
+    # Test        : PKGS-7420
+    # Description : Detect toolkit to automatically download and apply upgrades
+    Register --test-no PKGS-7420 --weight L --network NO --category security --description "Detect toolkit to automatically download and apply upgrades"
+    if [ ${SKIPTEST} -eq 0 ]; then
+        UNATTENDED_UPGRADES_TOOLKIT=0
+        UNATTENDED_UPGRADES_TOOL=""
+        UNATTENDED_UPGRADES_OPTION_AVAILABLE=0
 
-if [ ! -z "${INSTALLED_PACKAGES}" ]; then Report "installed_packages_array=${INSTALLED_PACKAGES}"; fi
+        case "${OS}" in
+            "Linux")
+                case "${LINUX_VERSION}" in
+                    "CentOS" | "Debian" | "Fedora" | "RHEL" | "Ubuntu")
 
-Report "package_audit_tool=${PACKAGE_AUDIT_TOOL}"
-Report "package_audit_tool_found=${PACKAGE_AUDIT_TOOL_FOUND}"
-Report "vulnerable_packages_found=${VULNERABLE_PACKAGES_FOUND}"
+                        UNATTENDED_UPGRADES_OPTION_AVAILABLE=1
+                        # Test available tools for Linux
+                        if [ -f "${ROOTDIR}bin/auter" ]; then
+                            UNATTENDED_UPGRADES_TOOL="auter"
+                            UNATTENDED_UPGRADES_TOOLKIT=1
+                            LogText "Result: found ${UNATTENDED_UPGRADES_TOOL}"
+                            Report "unattended_upgrade_tool[]=${UNATTENDED_UPGRADES_TOOL}"
+                        fi
+                        if [ -f "${ROOTDIR}sbin/yum-cron" ]; then
+                            UNATTENDED_UPGRADES_TOOL="yum-cron"
+                            UNATTENDED_UPGRADES_TOOLKIT=1
+                            LogText "Result: found ${UNATTENDED_UPGRADES_TOOL}"
+                            Report "unattended_upgrade_tool[]=${UNATTENDED_UPGRADES_TOOL}"
+                        fi
+                        if [ -f "${ROOTDIR}usr/bin/dnf-automatic" ]; then
+                            UNATTENDED_UPGRADES_TOOL="dnf-automatic"
+                            UNATTENDED_UPGRADES_TOOLKIT=1
+                            LogText "Result: found ${UNATTENDED_UPGRADES_TOOL}"
+                            Report "unattended_upgrade_tool[]=${UNATTENDED_UPGRADES_TOOL}"
+                        fi
+                        if [ -f "${ROOTDIR}usr/bin/unattended-upgrade" ]; then
+                            UNATTENDED_UPGRADES_TOOL="unattended-upgrade"
+                            UNATTENDED_UPGRADES_TOOLKIT=1
+                            LogText "Result: found ${UNATTENDED_UPGRADES_TOOL}"
+                            Report "unattended_upgrade_tool[]=${UNATTENDED_UPGRADES_TOOL}"
+                        fi
+                    ;;
+                esac
+            ;;
+        esac
+
+        if [ ${UNATTENDED_UPGRADES_OPTION_AVAILABLE} -eq 1 ]; then
+            if [ ${UNATTENDED_UPGRADES_TOOLKIT} -eq 1 ]; then
+                AddHP 5 5
+                Display --indent 2 --text "- Toolkit for automatic upgrades (${UNATTENDED_UPGRADES_TOOL})" --result "${STATUS_FOUND}" --color GREEN
+            else
+                AddHP 1 5
+                Display --indent 2 --text "- Toolkit for automatic upgrades" --result "${STATUS_NOTFOUND}" --color YELLOW
+                LogText "Result: no toolkit for automatic updates discovered"
+                ReportSuggestion "${TEST_NO}" "Consider using a tool to automatically apply upgrades"
+            fi
+        fi
+
+        Report "unattended_upgrade_option_available=${UNATTENDED_UPGRADES_OPTION_AVAILABLE}"
+    fi
+#
+#################################################################################
+#
 
 WaitForKeyPress
 
diff --git a/include/tests_shells b/include/tests_shells
index 8f9763b4..3a094ad8 100644
--- a/include/tests_shells
+++ b/include/tests_shells
@@ -31,9 +31,10 @@
     # Files (interactive login shells):     /etc/profile $HOME/.bash_profile
     #                                       $HOME/.bash_login $HOME/.profile
     # Files (interactive non-login shells): $HOME/.bash_rc
-
+    #
     # csh/tcsh
     # Files: /etc/csh.cshrc /etc/csh.login
+    #
     # zsh
     # Files: /etc/zshenv /etc/zsh/zshenv $HOME/.zshenv /etc/zprofile
     #        /etc/zsh/zprofile $HOME/.zprofile /etc/zshrc /etc/zsh/zshrc
@@ -68,8 +69,8 @@
 #################################################################################
 #
     # Test        : SHLL-6211
-    # Description : which shells are available according /etc/shells
-    Register --test-no SHLL-6211 --weight L --network NO --category security --description "Checking available and valid shells"
+    # Description : Determine available shell according /etc/shells
+    Register --test-no SHLL-6211 --weight L --network NO --category security --description "Available and valid shells"
     if [ ${SKIPTEST} -eq 0 ]; then
         LogText "Test: Searching for ${ROOTDIR}etc/shells"
         if [ -f ${ROOTDIR}etc/shells ]; then
@@ -98,8 +99,8 @@
 #################################################################################
 #
     # Test        : SHLL-6220
-    # Description : check for idle session killing tools or settings
-    Register --test-no SHLL-6220 --weight L --network NO --category security --description "Checking available and valid shells"
+    # Description : Check for idle session killing tools or settings
+    Register --test-no SHLL-6220 --weight L --network NO --category security --description "Idle session killing tools or settings"
     if [ ${SKIPTEST} -eq 0 ]; then
 
         IDLE_TIMEOUT_METHOD=""
diff --git a/include/tests_ssh b/include/tests_ssh
index e811e069..852e2db5 100644
--- a/include/tests_ssh
+++ b/include/tests_ssh
@@ -27,6 +27,7 @@
     SSH_DAEMON_PORT=""
     SSH_DAEMON_RUNNING=0
     SSH_DAEMON_OPTIONS_FILE=""
+    OPENSSHD_RUNNING=0
     OPENSSHD_VERSION=0
     OPENSSHD_VERSION_MAJOR=0
     OPENSSHD_VERSION_MINOR=0
@@ -42,8 +43,8 @@
     Register --test-no SSH-7402 --weight L --network NO --category security --description "Check for running SSH daemon"
     if [ ${SKIPTEST} -eq 0 ]; then
         LogText "Test: Searching for a SSH daemon"
-        IsRunning sshd
-        if [ ${RUNNING} -eq 1 ] || PortIsListening "TCP" 22; then
+        if IsRunning "sshd"; then
+            OPENSSHD_RUNNING=1
             SSH_DAEMON_RUNNING=1
             Display --indent 2 --text "- Checking running SSH daemon" --result "${STATUS_FOUND}" --color GREEN
             # Store settings in a temporary file
@@ -51,6 +52,9 @@
             SSH_DAEMON_OPTIONS_FILE="${TEMP_FILE}"
             # Use a non-existing user, to ensure that systems that have a Match block configured, will be evaluated as well
             ${SSHDBINARY} -T -C user=doesnotexist,host=none,addr=none 2> /dev/null > ${SSH_DAEMON_OPTIONS_FILE}
+        elif PortIsListening "TCP" 22; then
+            Display --indent 2 --text "- Checking running SSH daemon" --result "${STATUS_FOUND}" --color GREEN
+            SSH_DAEMON_RUNNING=1
         else
             Display --indent 2 --text "- Checking running SSH daemon" --result "${STATUS_NOT_FOUND}" --color WHITE
         fi
@@ -60,7 +64,7 @@
 #
     # Test        : SSH-7404
     # Description : Determine SSH daemon configuration file location
-    if [ ${SSH_DAEMON_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    if [ ${OPENSSHD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
     Register --test-no SSH-7404 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check SSH daemon file location"
     if [ ${SKIPTEST} -eq 0 ]; then
         FOUND=0
@@ -95,7 +99,7 @@
 #
     # Test        : SSH-7406
     # Description : Check OpenSSH version
-    if [ ${SSH_DAEMON_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    if [ ${OPENSSHD_RUNNING} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
     Register --test-no SSH-7406 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Determine OpenSSH version"
     if [ ${SKIPTEST} -eq 0 ]; then
         OPENSSHD_VERSION=$(${SSHDBINARY} -t -d 2>&1 | ${GREPBINARY} 'sshd version' | ${AWKBINARY} '{if($4~OpenSSH_){print $4}}' | ${AWKBINARY} -F_ '{print $2}' | ${TRBINARY} -d ',' | ${TRBINARY} -d '\r')
@@ -113,7 +117,7 @@
     # Test        : SSH-7408
     # Description : Check SSH specific defined options
     # Notes       : Instead of parsing the configuration file, we query the SSH daemon itself
-    if [ ${SSH_DAEMON_RUNNING} -eq 1 -a ! -z "${SSH_DAEMON_OPTIONS_FILE}" -a ${OPENSSHD_VERSION_MAJOR} -ge 5 -a ${OPENSSHD_VERSION_MINOR} -ge 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    if [ ${OPENSSHD_RUNNING} -eq 1 -a ! -z "${SSH_DAEMON_OPTIONS_FILE}" -a ${OPENSSHD_VERSION_MAJOR} -ge 5 -a ${OPENSSHD_VERSION_MINOR} -ge 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
     Register --test-no SSH-7408 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check SSH specific defined options"
     if [ ${SKIPTEST} -eq 0 ]; then
         LogText "Test: Checking specific defined options in ${SSH_DAEMON_OPTIONS_FILE}"
@@ -258,31 +262,31 @@
                 fi
 
                 if [ "${RESULT}" = "GOOD" ]; then
-                    LogText "Result: SSH option ${OPTIONNAME} is configured very well"
-                    Display --indent 4 --text "- SSH option: ${OPTIONNAME}" --result "${STATUS_OK}" --color GREEN
+                    LogText "Result: OpenSSH option ${OPTIONNAME} is configured very well"
+                    Display --indent 4 --text "- OpenSSH option: ${OPTIONNAME}" --result "${STATUS_OK}" --color GREEN
                     AddHP 3 3
                 elif [ "${RESULT}" = "MIDSCORED" ]; then
-                    LogText "Result: SSH option ${OPTIONNAME} is configured reasonably"
+                    LogText "Result: OpenSSH option ${OPTIONNAME} is configured reasonably"
                     ReportSuggestion ${TEST_NO} "Consider hardening SSH configuration" "${OPTIONNAME} (${FOUNDVALUE} --> ${EXPECTEDVALUE})" "-"
                     ReportDetails --test "${TEST_NO}" --service "sshd" --field "${OPTIONNAME}" --value "${FOUNDVALUE}" --preferredvalue "${EXPECTEDVALUE}" --description "sshd option ${OPTIONNAME}"
-                    Display --indent 4 --text "- SSH option: ${OPTIONNAME}" --result "${STATUS_SUGGESTION}" --color YELLOW
+                    Display --indent 4 --text "- OpenSSH option: ${OPTIONNAME}" --result "${STATUS_SUGGESTION}" --color YELLOW
                     AddHP 1 3
                 elif [ "${RESULT}" = "WEAK" ]; then
-                    LogText "Result: SSH option ${OPTIONNAME} is in a weak configuration state and should be fixed"
+                    LogText "Result: OpenSSH option ${OPTIONNAME} is in a weak configuration state and should be fixed"
                     ReportSuggestion ${TEST_NO} "Consider hardening SSH configuration" "${OPTIONNAME} (${FOUNDVALUE} --> ${EXPECTEDVALUE})" "-"
                     ReportDetails --test "${TEST_NO}" --service "sshd" --field "${OPTIONNAME}" --value "${FOUNDVALUE}" --preferredvalue "${EXPECTEDVALUE}" --description "sshd option ${OPTIONNAME}"
-                    Display --indent 4 --text "- SSH option: ${OPTIONNAME}" --result "${STATUS_SUGGESTION}" --color YELLOW
+                    Display --indent 4 --text "- OpenSSH option: ${OPTIONNAME}" --result "${STATUS_SUGGESTION}" --color YELLOW
                     AddHP 0 3
                 elif [ "${RESULT}" = "UNKNOWN" ]; then
-                    LogText "Result: Value of SSH option ${OPTIONNAME} is unknown (not defined)"
-                    Display --indent 4 --text "- SSH option: ${OPTIONNAME}" --result DEFAULT --color WHITE
+                    LogText "Result: Value of OpenSSH option ${OPTIONNAME} is unknown (not defined)"
+                    Display --indent 4 --text "- OpenSSH option: ${OPTIONNAME}" --result DEFAULT --color WHITE
                     Report "unknown_config_option[]=ssh|$SSH_DAEMON_CONFIG}|${OPTIONNAME}|"
                 else
                     LogText "Result: Option ${OPTIONNAME} not found in output"
-                    Display --indent 4 --text "- SSH option: ${OPTIONNAME}" --result "${STATUS_NOT_FOUND}" --color WHITE
+                    Display --indent 4 --text "- OpenSSH option: ${OPTIONNAME}" --result "${STATUS_NOT_FOUND}" --color WHITE
                 fi
             else
-                if IsVerbose; then Display --indent 4 --text "- SSH option: ${OPTIONNAME}" --result "SKIPPED (via config)" --color WHITE; fi
+                if IsVerbose; then Display --indent 4 --text "- OpenSSH option: ${OPTIONNAME}" --result "SKIPPED (via config)" --color WHITE; fi
             fi
         done
     fi
@@ -290,32 +294,32 @@
 #################################################################################
 #
     # Test        : SSH-7440
-    # Description : AllowUsers / AllowGroups
+    # Description : OpenSSH - AllowUsers / AllowGroups
     # Goal        : Check if only a specific amount of users/groups can log in to the system
-    if [ ${SSH_DAEMON_RUNNING} -eq 1 -a ! -z "${SSH_DAEMON_OPTIONS_FILE}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
-    Register --test-no SSH-7440 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check SSH option: AllowUsers and AllowGroups"
+    if [ ${OPENSSHD_RUNNING} -eq 1 -a ! -z "${SSH_DAEMON_OPTIONS_FILE}" ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
+    Register --test-no SSH-7440 --preqs-met ${PREQS_MET} --weight L --network NO --category security --description "Check OpenSSH option: AllowUsers and AllowGroups"
     if [ ${SKIPTEST} -eq 0 ]; then
         FOUND=0
         # AllowUsers
         FIND=$(${EGREPBINARY} -i "^AllowUsers" ${SSH_DAEMON_OPTIONS_FILE} | ${AWKBINARY} '{ print $2 }')
         if [ ! -z "${FIND}" ]; then
             LogText "Result: AllowUsers set, with value ${FIND}"
-            Display --indent 4 --text "- SSH option: AllowUsers" --result "${STATUS_FOUND}" --color GREEN
+            Display --indent 4 --text "- OpenSSH option: AllowUsers" --result "${STATUS_FOUND}" --color GREEN
             FOUND=1
         else
             LogText "Result: AllowUsers is not set"
-            Display --indent 4 --text "- SSH option: AllowUsers" --result "${STATUS_NOT_FOUND}" --color WHITE
+            Display --indent 4 --text "- OpenSSH option: AllowUsers" --result "${STATUS_NOT_FOUND}" --color WHITE
         fi
 
         # AllowGroups
         FIND=$(${EGREPBINARY} -i "^AllowGroups" ${SSH_DAEMON_OPTIONS_FILE} | ${AWKBINARY} '{ print $2 }')
         if [ ! -z "${FIND}" ]; then
             LogText "Result: AllowUsers set ${FIND}"
-            Display --indent 4 --text "- SSH option: AllowGroups" --result "${STATUS_FOUND}" --color GREEN
+            Display --indent 4 --text "- OpenSSH option: AllowGroups" --result "${STATUS_FOUND}" --color GREEN
             FOUND=1
         else
             LogText "Result: AllowGroups is not set"
-            Display --indent 4 --text "- SSH option: AllowGroups" --result "${STATUS_NOT_FOUND}" --color WHITE
+            Display --indent 4 --text "- OpenSSH option: AllowGroups" --result "${STATUS_NOT_FOUND}" --color WHITE
         fi
 
         if [ ${FOUND} -eq 1 ]; then
@@ -331,6 +335,7 @@
 #
 
 Report "ssh_daemon_running=${SSH_DAEMON_RUNNING}"
+Report "openssh_daemon_running=${OPENSSHD_RUNNING}"
 
 WaitForKeyPress
 
diff --git a/include/tests_webservers b/include/tests_webservers
index 5d0907b9..dfe8aabc 100644
--- a/include/tests_webservers
+++ b/include/tests_webservers
@@ -251,8 +251,7 @@
     Register --test-no HTTP-6640 --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
-        CheckItem "apache_module" "/mod_evasive([0-9][0-9])?.so"
-        if [ ${ITEM_FOUND} -eq 1 ]; then
+        if CheckItem "apache_module" "/mod_evasive([0-9][0-9])?.so"; then
             Display --indent 10 --text "mod_evasive: anti-DoS/brute force" --result "${STATUS_FOUND}" --color GREEN
             AddHP 3 3
         else
@@ -271,8 +270,7 @@
     Register --test-no HTTP-6641 --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
-        CheckItem "apache_module" "/mod_(reqtimeout|qos).so"
-        if [ ${ITEM_FOUND} -eq 1 ]; then
+        if CheckItem "apache_module" "/mod_(reqtimeout|qos).so"; then
             Display --indent 10 --text "mod_reqtimeout/mod_qos" --result "${STATUS_FOUND}" --color GREEN
             AddHP 3 3
         else
@@ -290,8 +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
-        CheckItem "apache_module" "/mod_security2.so"
-        if [ ${ITEM_FOUND} -eq 1 ]; then
+        if CheckItem "apache_module" "/mod_security2.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 15d509ea..0914f9c4 100755
--- a/lynis
+++ b/lynis
@@ -21,6 +21,11 @@
 # Lynis is an automated auditing tool for Unix based operating systems.
 #
 #################################################################################
+#
+    # Code quality: don't allow using undefined variables
+    set -o nounset
+#
+#################################################################################
 #
     # In Solaris /bin/sh is not POSIX, but /usr/xpg4/bin/sh is.
     # Switch to /usr/xpg4/bin/sh if it exists and we are not already running it.
@@ -35,10 +40,10 @@
     PROGRAM_AUTHOR_CONTACT="lynis-dev@cisofy.com"
 
     # Version details
-    PROGRAM_RELEASE_DATE="2019-03-21"
-    PROGRAM_RELEASE_TIMESTAMP=1553157295
-    PROGRAM_RELEASE_TYPE="final" # dev or final
-    PROGRAM_VERSION="2.7.3"
+    PROGRAM_RELEASE_DATE="2019-06-29"
+    PROGRAM_RELEASE_TIMESTAMP=1561383761
+    PROGRAM_RELEASE_TYPE="dev" # dev or final
+    PROGRAM_VERSION="3.0.0"
 
     # Source, documentation and license
     PROGRAM_SOURCE="https://github.com/CISOfy/lynis"
@@ -55,11 +60,6 @@
 
     DISPLAY_LANG="${LANG}"  # required by function Display to deal with multi-bytes characters.
 
-    # Code quality:
-    # Set strict checking for development version for first part of code. After
-    # initialization this is checked with strict profile option.
-    if [ ${PROGRAM_RELEASE_TYPE} = "dev" ]; then set -u; fi
-
 #
 #################################################################################
 #
@@ -67,6 +67,9 @@
 #
 #################################################################################
 #
+    # Check setuid bit
+    if [ -u "$0" ]; then echo "The called binary has the set-user-id bit - As this is unusual, execution will be stopped."; exit 1; fi
+
     # Work directory
     WORKDIR=$(pwd)
 
@@ -139,8 +142,7 @@ Make sure to execute ${PROGRAM_NAME} from untarred directory or check your insta
 #################################################################################
 #
     # Perform a basic check for permissions. After including functions, using SafePerms()
-    WARN_ON_FILE_ISSUES=1
-    WARN_ON_FILE_ISSUES_ASKED=0
+    IGNORE_FILE_PERMISSION_ISSUES=0
 
     FILES_TO_CHECK="consts functions"
 
@@ -192,14 +194,10 @@ Make sure to execute ${PROGRAM_NAME} from untarred directory or check your insta
             printf "\n    Option 2) Change ownership of the related files (or full directory).\n\n       Commands (full directory):\n         # cd ..\n         # chown -R 0:0 lynis\n         # cd lynis\n         # ./lynis audit system"
         fi
         printf "\n\n[ Press ENTER to continue, or CTRL+C to cancel ]"
-        WARN_ON_FILE_ISSUES_ASKED=1
+        IGNORE_FILE_PERMISSION_ISSUES=1
         read DUMMY
     fi
 
-    if [ ${WARN_ON_FILE_ISSUES_ASKED} -eq 1 ]; then
-        WARN_ON_FILE_ISSUES=0
-    fi
-
     # Now include files if permissions are correct, or user decided to continue
     . ${INCLUDEDIR}/consts
     . ${INCLUDEDIR}/functions
@@ -613,6 +611,9 @@ ${NORMAL}
         if [ ${EOL} -eq 1 ]; then
             echo "  End-of-life:               ${WARNING}YES${NORMAL}"
             ReportWarning "GEN-0010" "This version ${OS_VERSION} is marked end-of-life as of ${EOL_DATE}"
+        elif [ ${EOL} -eq 255 ]; then
+            # TODO - mark as item where community can provide help
+            LogText "Note: the end-of-life of '${OS_FULLNAME}' could not be checked. Entry missing in software-eol.db?"
         fi
 
         if [ ! -z "${OS_MODE}" ]; then echo "  Operating system mode:     ${OS_MODE}"; fi
@@ -853,8 +854,17 @@ ${NORMAL}
                             LogText "Action: checking plugin status in profile: ${PROFILE}"
                             FIND3=$(grep "^plugin=${FIND2}" ${PROFILE})
                             if [ ! -z "${FIND3}" ]; then
-                                LogText "Result: plugin enabled in profile (${PROFILE})"
-                                PLUGIN_ENABLED_STATE=1
+                                FOUND=0
+                                for I in ${DISABLED_PLUGINS}; do
+                                    if [ "${I}" = "${FIND2}" ]; then
+                                        FOUND=1
+                                        LogText "Result: plugin ${FIND2} is specifically disabled"
+                                    fi
+                                done
+                                if [ ${FOUND} -eq 0 ]; then
+                                    LogText "Result: plugin enabled in profile (${PROFILE})"
+                                    PLUGIN_ENABLED_STATE=1
+                                fi
                             fi
                         done
                         if [ ${PLUGIN_ENABLED_STATE} -eq 1 ]; then
@@ -948,7 +958,7 @@ ${NORMAL}
         for INCLUDE_TEST in ${INCLUDE_TESTS}; do
             INCLUDE_FILE="${INCLUDEDIR}/tests_${INCLUDE_TEST}"
             if [ -f ${INCLUDE_FILE} ]; then
-                if SafePerms ${INCLUDE_FILE}; then
+                if SafeFile ${INCLUDE_FILE}; then
                     . ${INCLUDE_FILE}
                 else
                     LogText "Exception: skipping test category ${INCLUDE_TEST}, file ${INCLUDE_FILE} has bad permissions (should be 640, 600 or 400)"