mirror of https://github.com/CISOfy/lynis.git
1135 lines
48 KiB
Bash
Executable File
1135 lines
48 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
#################################################################################
|
|
#
|
|
# Lynis
|
|
# ------------------
|
|
#
|
|
# Copyright 2007-2013, Michael Boelen
|
|
# 2013-now, CISOfy
|
|
#
|
|
# Web site: https://cisofy.com
|
|
#
|
|
# 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.
|
|
#
|
|
# Lynis is licensed under GPLv3, Plugins are licensed differently (see plugins)
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Lynis is an automated auditing tool for Unix based operating systems.
|
|
#
|
|
#################################################################################
|
|
#
|
|
# 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.
|
|
if [ "$(uname)" = "SunOS" ]; then
|
|
test "$_" != "/usr/xpg4/bin/sh" && test -f /usr/xpg4/bin/sh && exec /usr/xpg4/bin/sh "$0" "$@"
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Code quality: don't allow using undefined variables
|
|
# Notes: $_ may be empty on FreeBSD
|
|
set -o nounset
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Program information
|
|
PROGRAM_NAME="Lynis"
|
|
PROGRAM_AUTHOR="CISOfy"
|
|
PROGRAM_AUTHOR_CONTACT="lynis-dev@cisofy.com"
|
|
PROGRAM_WEBSITE="https://cisofy.com/lynis/"
|
|
|
|
# Version details
|
|
PROGRAM_RELEASE_DATE="2019-07-14"
|
|
PROGRAM_RELEASE_TIMESTAMP=1563094548
|
|
PROGRAM_RELEASE_TYPE="pre-release" # pre-release or release
|
|
PROGRAM_VERSION="3.0.0"
|
|
|
|
# Source, documentation and license
|
|
PROGRAM_SOURCE="https://github.com/CISOfy/lynis"
|
|
PROGRAM_PACKAGE="https://packages.cisofy.com/"
|
|
PROGRAM_DOCUMENTATION="https://cisofy.com/docs/"
|
|
PROGRAM_COPYRIGHT="2007-2019, ${PROGRAM_AUTHOR} - ${PROGRAM_WEBSITE}"
|
|
PROGRAM_LICENSE="${PROGRAM_NAME} 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 the LICENSE file for details about using this software."
|
|
PROGRAM_EXTRAINFO="Enterprise support available (compliance, plugins, interface and tools)"
|
|
|
|
# Version number of report files (when format changes in future)
|
|
REPORT_version_major="1"; REPORT_version_minor="0"
|
|
REPORT_version="${REPORT_version_major}.${REPORT_version_minor}"
|
|
|
|
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Configure Include path and files
|
|
#
|
|
#################################################################################
|
|
#
|
|
# 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)
|
|
|
|
# Test from which directories we can use all functions and tests
|
|
USE_CWD=0
|
|
if case "$@" in *--usecwd*) true;; *) false;; esac; then
|
|
USE_CWD=1
|
|
INCLUDEDIR="./include"
|
|
else
|
|
INCLUDEDIR=""
|
|
tINCLUDE_TARGETS="/usr/local/include/lynis /usr/local/lynis/include /usr/share/lynis/include ./include" # Default paths to check (CWD as last option, in case we run from standalone)
|
|
for I in ${tINCLUDE_TARGETS}; do
|
|
if [ "${I}" = "./include" ]; then
|
|
if [ -d "${WORKDIR}/include" ]; then INCLUDEDIR="${WORKDIR}/include"; fi
|
|
elif [ -d ${I} -a -z "${INCLUDEDIR}" ]; then
|
|
INCLUDEDIR=${I}
|
|
fi
|
|
done
|
|
fi
|
|
|
|
# Drop out if our include directory can't be found
|
|
if [ -z "${INCLUDEDIR}" ]; then
|
|
printf "%s" "\nFatal error: can't find include directory\nMake sure to execute ${PROGRAM_NAME} from untarred directory or check your installation."
|
|
exit 1
|
|
fi
|
|
|
|
# Test for database directory
|
|
if [ ${USE_CWD} -eq 1 ]; then
|
|
DBDIR="./db"
|
|
else
|
|
DBDIR=""; tDB_TARGETS="/usr/local/share/lynis/db /usr/local/lynis/db /usr/share/lynis/db ./db"
|
|
for I in ${tDB_TARGETS}; do
|
|
if [ "${I}" = "./db" ]; then
|
|
if [ -d "${WORKDIR}/db" ]; then DBDIR="${WORKDIR}/db"; fi
|
|
elif [ -d ${I} -a -z "${DBDIR}" ]; then
|
|
DBDIR="${I}"
|
|
fi
|
|
done
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
MYID=""
|
|
# Check user to determine file permissions later on. If we encounter Solaris, use related id binary instead
|
|
if [ -x /usr/xpg4/bin/id ]; then
|
|
MYID=$(/usr/xpg4/bin/id -u 2> /dev/null)
|
|
elif [ "$(uname)" = "SunOS" ]; then
|
|
MYID=$(id | tr '=' ' ' | tr '(' ' ' | awk '{ print $2 }' 2> /dev/null)
|
|
else
|
|
MYID=$(id -u 2> /dev/null)
|
|
fi
|
|
if [ -z "${MYID}" ]; then Display "Could not find user ID with id command. Want to help improve Lynis? Raise a ticket at ${PROGRAM_SOURCE}"; ExitFatal; fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Set basic values and test permissions of the files to include, such as:
|
|
# - consts: bin paths, text strings, colors
|
|
# - functions: function library
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Determine if we are root (UID = 0)
|
|
if [ ${MYID} -eq 0 ]; then
|
|
PRIVILEGED=1
|
|
PENTESTINGMODE=0
|
|
else
|
|
PRIVILEGED=0
|
|
# Set to pentesting mode if scan is without root privileges
|
|
PENTESTINGMODE=1
|
|
fi
|
|
|
|
# Perform a basic check for permissions. After including functions, using SafePerms()
|
|
IGNORE_FILE_PERMISSION_ISSUES=0
|
|
|
|
FILES_TO_CHECK="consts functions"
|
|
|
|
ISSUE=0
|
|
ISSUE_TYPE=""
|
|
SHOWPERMERROR=0
|
|
|
|
for FILE in ${FILES_TO_CHECK}; do
|
|
PERMS=$(ls -l ${INCLUDEDIR}/${FILE} | cut -c 2-10)
|
|
GROUPPERMS=$(ls -l ${INCLUDEDIR}/${FILE} | cut -c 5-7)
|
|
GROUPOWNERID=$(ls -n ${INCLUDEDIR}/${FILE} | awk '{ print $4 }')
|
|
OWNER=$(ls -l ${INCLUDEDIR}/${FILE} | awk -F" " '{ print $3 }')
|
|
OWNERID=$(ls -n ${INCLUDEDIR}/${FILE} | awk -F" " '{ print $3 }')
|
|
|
|
# Check permissions of include/X file (400, 600, 640, 644)
|
|
if [ "${PERMS}" = "rwxrwxrwx" ]; then
|
|
ISSUE=1; ISSUE_TYPE="perms"; echo "[!] Change file permissions of ${INCLUDEDIR}/${FILE} to 640."; echo " Command: chmod 640 ${INCLUDEDIR}/${FILE}"
|
|
elif [ ! "${PERMS}" = "r--------" -a ! "${PERMS}" = "rw-------" -a ! "${PERMS}" = "rw-r-----" -a ! "${PERMS}" = "rw-r--r--" ]; then
|
|
# If group ID equals user ID, we consider permissions to be fine (probably default umask)
|
|
if [ ! "${GROUPOWNERID}" = "${OWNERID}" ]; then
|
|
ISSUE=1; ISSUE_TYPE="perms"; echo "[!] Change file permissions of ${INCLUDEDIR}/${FILE} to 640."; echo " Command: chmod 640 ${INCLUDEDIR}/${FILE}"
|
|
fi
|
|
fi
|
|
|
|
# Check if owner of both files is root user, or the same user which is running Lynis (for pentester mode)
|
|
if [ ! "${OWNER}" = "root" -a ! "${OWNERID}" = "0" ]; then
|
|
if [ ! "${MYID}" = "${OWNERID}" ]; then
|
|
ISSUE=1; ISSUE_TYPE="owner"; SHOWPERMERROR=1; ISSUE_FILE="${FILE}"; ISSUE_OWNER="${OWNER}"; ISSUE_OWNERID="${OWNERID}"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
if [ ${SHOWPERMERROR} -eq 1 ]; then
|
|
printf "%s" "
|
|
|
|
[!] Change ownership of ${INCLUDEDIR}/${ISSUE_FILE} to 'root' or similar (found: ${ISSUE_OWNER} with UID ${ISSUE_OWNERID}).
|
|
|
|
Command:
|
|
# chown 0:0 ${INCLUDEDIR}/${ISSUE_FILE}
|
|
"
|
|
fi
|
|
|
|
# Now if there is an issue with permissions, show it to the user and let them decide how to continue.
|
|
if [ ${ISSUE} -eq 1 ]; then
|
|
printf "\n[X] Security check failed\n\n Why do I see this error?\n -------------------------------\n This is a protection mechanism to prevent the root user from executing user created files. The files may be altered, or including malicious pieces of script.\n\n What can I do?\n ---------------------\n Option 1) Check if a trusted user created the files (e.g. due to using Git, Homebrew or similar).\n If you trust these files, you can decide to continue this run by pressing ENTER.\n"
|
|
if [ "${ISSUE_TYPE}" = "perms" ]; then
|
|
printf "\n Option 2) Change permissions of the related files.\n\n Commands (full directory):\n # chmod 640 include/*\n # ./lynis audit system"
|
|
elif [ "${ISSUE_TYPE}" = "owner" ]; then
|
|
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 ]"
|
|
IGNORE_FILE_PERMISSION_ISSUES=1
|
|
read -r void
|
|
fi
|
|
|
|
# Now include files if permissions are correct, or user decided to continue
|
|
. ${INCLUDEDIR}/consts
|
|
. ${INCLUDEDIR}/functions
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Language settings
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Auto detection of language based on shell LANG variable. This is required by the Display() function to deal with multi-bytes characters.
|
|
DISPLAY_LANG="${LANG:-}"
|
|
|
|
# Extract the short notation of the language (first two characters).
|
|
if [ -x "$(command -v locale 2> /dev/null)" ]; then
|
|
LANGUAGE=$(locale | egrep "^LANG=" | cut -d= -f2 | cut -d_ -f1 | egrep "^[a-z]{2}$")
|
|
# Try locale command if shell variable had no value
|
|
if [ -z "${DISPLAY_LANG}" ]; then
|
|
DISPLAY_LANG=$(locale | egrep "^LANG=" | cut -d= -f2)
|
|
fi
|
|
else
|
|
LANGUAGE="en"
|
|
fi
|
|
|
|
# Set default language: 'en' (English) if no value is set
|
|
if [ -z "${LANGUAGE}" ]; then
|
|
LANGUAGE="en"
|
|
fi
|
|
|
|
# Import translations. First import English to prefill all texts
|
|
if [ -f ${DBDIR}/languages/en ]; then
|
|
if SafeFile "${DBDIR}/languages/en"; then
|
|
. ${DBDIR}/languages/en
|
|
else
|
|
ExitFatal "Incorrect ownership or permissions of language file (${DBDIR}/languages/en)"
|
|
fi
|
|
else
|
|
echo "Could not find languages directory (file: ${DBDIR}/languages/en)"
|
|
exit 1
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Traps
|
|
#
|
|
#################################################################################
|
|
#
|
|
trap CleanUp INT
|
|
|
|
# Use safe umask for the files we create
|
|
umask 027
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Parameter checks
|
|
#
|
|
#################################################################################
|
|
#
|
|
SafePerms ${INCLUDEDIR}/parameters
|
|
. ${INCLUDEDIR}/parameters
|
|
|
|
|
|
# Disable logging if no alternative was provided
|
|
if [ ${PRIVILEGED} -eq 0 ]; then
|
|
if [ -z "${LOGFILE}" ]; then
|
|
# Try creating a log file in temporary directory
|
|
if [ ! -f /tmp/lynis.log ]; then
|
|
if [ -L /tmp/lynis.log ]; then echo "Log file is symlinked, which can introduce the risk of a symlink attack."; exit 1; fi
|
|
touch /tmp/lynis.log
|
|
if [ $? -eq 0 ]; then LOGFILE="/tmp/lynis.log"; else LOGFILE="/dev/null"; fi
|
|
else
|
|
LOGFILE="/tmp/lynis.log"
|
|
fi
|
|
else
|
|
if [ -L "${LOGFILE}" ]; then echo "Log file is symlinked, which can introduce the risk of a symlink attack."; exit 1; fi
|
|
fi
|
|
if [ -z "${REPORTFILE}" ]; then
|
|
touch /tmp/lynis-report.dat
|
|
if [ -L /tmp/lynis-report.dat ]; then echo "Report file is symlinked, which can introduce the risk of a symlink attack."; exit 1; fi
|
|
if [ $? -eq 0 ]; then REPORTFILE="/tmp/lynis-report.dat"; else REPORTFILE="/dev/null"; fi
|
|
else
|
|
if [ -L "${REPORTFILE}" ]; then echo "Report file is symlinked, which can introduce the risk of a symlink attack."; exit 1; fi
|
|
fi
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Program information
|
|
#
|
|
#################################################################################
|
|
#
|
|
# CV - Current Version
|
|
PROGRAM_AC=$(echo ${PROGRAM_VERSION} | awk '{ print $1 }' | sed 's/[.]//g')
|
|
PROGRAM_LV=0
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Initialize and default settings
|
|
#
|
|
#################################################################################
|
|
#
|
|
|
|
if [ ${QUIET} -eq 0 ]; then
|
|
printf "\n${WHITE}[ ${PROGRAM_NAME} ${PROGRAM_VERSION} ]${NORMAL}\n\n################################################################################\n ${PROGRAM_LICENSE}\n\n ${PROGRAM_COPYRIGHT}\n ${PROGRAM_EXTRAINFO}\n################################################################################\n\n"
|
|
fi
|
|
|
|
if [ "${PROGRAM_RELEASE_TYPE}" = "beta" ]; then
|
|
printf "%s" "
|
|
${WHITE}
|
|
#########################################################
|
|
# ${YELLOW}BETA VERSION${WHITE} #
|
|
#########################################################
|
|
|
|
Thank you for testing a beta release. Make sure to read
|
|
all available documentation before proceeding and/or
|
|
requesting support. Due the nature of beta releases, it
|
|
is possible new features give unexpected warnings.
|
|
|
|
|
|
#########################################################
|
|
${NORMAL}
|
|
"
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
InsertSection "${GEN_INITIALIZE_PROGRAM}"
|
|
|
|
# Discover any profiles
|
|
DiscoverProfiles
|
|
|
|
# Initialize and check profile file, auditor name, log file and report file
|
|
if [ -z "${LOGDIR}" ]; then LOGDIR="/var/log"; fi
|
|
if [ -z "${AUDITORNAME}" ]; then AUDITORNAME="[Not Specified]"; fi
|
|
if [ -z "${LOGFILE}" ]; then LOGFILE="${LOGDIR}/lynis.log"; fi
|
|
if [ -z "${REPORTFILE}" ]; then REPORTFILE="${LOGDIR}/lynis-report.dat"; fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# PID :: Check PID file, to avoid multiple instances running at the same time.
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Decide where to write our PID file. For unprivileged users this will be in their home directory, or /tmp if their
|
|
# home directory isn't set. For root it will be /var/run, or the current working directory if /var/run doesn't exist.
|
|
MYHOMEDIR=$(echo ~ 2> /dev/null)
|
|
if [ -z "${MYHOMEDIR}" ]; then MYHOMEDIR="/tmp"; fi
|
|
|
|
if [ ${PRIVILEGED} -eq 0 ]; then
|
|
PIDFILE="${MYHOMEDIR}/lynis.pid"
|
|
elif [ -d /var/run ]; then
|
|
PIDFILE="/var/run/lynis.pid"
|
|
else
|
|
PIDFILE="./lynis.pid"
|
|
fi
|
|
|
|
# Check if there is already a PID file in any of the locations (incorrect termination of previous instance)
|
|
if [ -f "${MYHOMEDIR}/lynis.pid" -o -f "./lynis.pid" -o -f "/var/run/lynis.pid" ]; then
|
|
printf "%s" "
|
|
|
|
${WARNING}Warning${NORMAL}: ${WHITE}PID file exists, probably another Lynis process is running.${NORMAL}
|
|
------------------------------------------------------------------------------
|
|
If you are unsure if another Lynis process is running currently, you are advised
|
|
to stop the current process and check the process list first. If you cancelled
|
|
a previous instance (by using CTRL+C), you can ignore this message.
|
|
|
|
You are advised to check for temporary files after program completion.
|
|
------------------------------------------------------------------------------
|
|
|
|
${YELLOW}Note: ${WHITE}Cancelling the program can leave temporary files behind${NORMAL}
|
|
"
|
|
|
|
# Quit directly for cron jobs.
|
|
if [ ${CRONJOB} -eq 1 ]; then
|
|
echo "Quitting, to prevent multiple cron jobs running at the same time"
|
|
exit 1 # Manually exit, no cleanups to prevent deleting an active PID file
|
|
else
|
|
WaitForKeyPress
|
|
fi
|
|
|
|
# Deleting any stale PID files that might exist. Note: Display function does not work yet at this point
|
|
if [ -f "${MYHOMEDIR}/lynis.pid" ]; then rm -f "${MYHOMEDIR}/lynis.pid"; fi
|
|
if [ -f "./lynis.pid" ]; then rm -f "./lynis.pid"; fi
|
|
if [ -f "/var/run/lynis.pid" ]; then rm -f "/var/run/lynis.pid"; fi
|
|
fi
|
|
|
|
# Ensure symlink attack is not possible, by confirming there is no symlink of the file already
|
|
OURPID=$(echo $$)
|
|
if [ -L ${PIDFILE} ]; then
|
|
echo "Found symlinked PID file (${PIDFILE}), quitting"
|
|
ExitFatal
|
|
else
|
|
# Create new PID file writable only by owner
|
|
echo "${OURPID}" > ${PIDFILE}
|
|
chmod 600 ${PIDFILE}
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Check program parameters
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Bail out if we didn't get any parameter, or incorrect ones
|
|
if [ ${PARAMCOUNT} -eq 0 -o ${WRONGOPTION} -eq 1 -o ${VIEWHELP} -eq 1 ]; then
|
|
printf "%s" "
|
|
|
|
${GREEN}Usage:${NORMAL} lynis ${CYAN}command ${GRAY}[options]${NORMAL}
|
|
|
|
|
|
${WHITE}Command:${NORMAL}
|
|
|
|
${CYAN}audit${NORMAL}
|
|
audit system : Perform local security scan
|
|
audit system remote <host> : Remote security scan
|
|
audit dockerfile <file> : Analyze Dockerfile
|
|
|
|
${CYAN}show${NORMAL}
|
|
show : Show all commands
|
|
show version : Show ${PROGRAM_NAME} version
|
|
show help : Show help
|
|
|
|
${CYAN}update${NORMAL}
|
|
update info : Show update details
|
|
|
|
|
|
${WHITE}Options:${NORMAL}
|
|
|
|
${WHITE}Alternative system audit modes${NORMAL}
|
|
${GRAY}--forensics${NORMAL} : Perform forensics on a running or mounted system
|
|
${GRAY}--pentest${NORMAL} : Non-privileged, show points of interest for pentesting
|
|
|
|
${WHITE}Layout options${NORMAL}
|
|
${GRAY}--no-colors${NORMAL} : Don't use colors in output
|
|
${GRAY}--quiet (-q)${NORMAL} : No output
|
|
${GRAY}--reverse-colors${NORMAL} : Optimize color display for light backgrounds
|
|
|
|
${WHITE}Misc options${NORMAL}
|
|
${GRAY}--debug${NORMAL} : Debug logging to screen
|
|
${GRAY}--no-log${NORMAL} : Don't create a log file
|
|
${GRAY}--profile ${BROWN}<profile>${NORMAL} : Scan the system with the given profile file
|
|
${GRAY}--view-manpage (--man)${NORMAL} : View man page
|
|
${GRAY}--verbose${NORMAL} : Show more details on screen
|
|
${GRAY}--version (-V)${NORMAL} : Display version number and quit
|
|
${GRAY}--wait${NORMAL} : Wait between a set of tests
|
|
|
|
${WHITE}Enterprise options${NORMAL}
|
|
${GRAY}--plugindir ${BROWN}<path>${NORMAL} : Define path of available plugins
|
|
${GRAY}--upload${NORMAL} : Upload data to central node
|
|
|
|
More options available. Run '$0 show options', or use the man page.
|
|
|
|
|
|
"
|
|
|
|
if [ ${WRONGOPTION} -eq 1 ]; then
|
|
echo " ${RED}Error${NORMAL}: ${WHITE}Invalid option '${WRONGOPTION_value}'${NORMAL}"
|
|
else
|
|
if [ ${VIEWHELP} -eq 0 ]; then
|
|
echo " ${RED}No command provided.${WHITE} Exiting..${NORMAL}"
|
|
echo ""
|
|
fi
|
|
fi
|
|
echo ""
|
|
# Cleanup PID file if we drop out earlier
|
|
RemovePIDFile
|
|
# Exit with exit code 1
|
|
exit 64
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
if [ ${PRIVILEGED} -eq 0 -a ${CHECK} -eq 1 -a ${QUIET} -eq 0 ]; then
|
|
printf "%s" "${WHITE}
|
|
###################################################################
|
|
# #
|
|
# ${PURPLE}NON-PRIVILEGED SCAN MODE${WHITE} #
|
|
# #
|
|
###################################################################
|
|
${NORMAL}
|
|
${YELLOW}NOTES:${NORMAL}
|
|
--------------
|
|
${WHITE}*${NORMAL} Some tests will be skipped (as they require root permissions)
|
|
${WHITE}*${NORMAL} Some tests might fail silently or give different results
|
|
|
|
"
|
|
sleep 3
|
|
if [ -z "${LOGFILE}" -o "${LOGFILE}" = "/dev/null" ]; then
|
|
printf "%s" "
|
|
${RED}WARNING:${NORMAL}
|
|
${WHITE}*${NORMAL} No suggestions or warnings will be displayed in report (due to missing log file)"
|
|
fi
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# OS Detection
|
|
#
|
|
#################################################################################
|
|
#
|
|
SafePerms ${INCLUDEDIR}/osdetection
|
|
. ${INCLUDEDIR}/osdetection
|
|
Display --indent 2 --text "- Detecting OS... " --result DONE --color GREEN
|
|
|
|
# Check hostname
|
|
case ${OS} in
|
|
HP-UX)
|
|
HOSTNAME=$(hostname) ;;
|
|
Solaris)
|
|
HOSTNAME=$(uname -n) ;;
|
|
*)
|
|
HOSTNAME=$(hostname -s 2> /dev/null) ;;
|
|
esac
|
|
if [ -z "${HOSTNAME}" ]; then
|
|
HOSTNAME=$(hostname 2> /dev/null)
|
|
if [ -z "${HOSTNAME}" ]; then HOSTNAME="no-hostname"; fi
|
|
fi
|
|
FQDN=$(hostname 2> /dev/null)
|
|
if [ "${OS}" = "Linux" -a "${HOSTNAME}" = "${FQDN}" ]; then
|
|
FQDN=$(hostname -f 2> /dev/null)
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Clear log and report files
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Clear log file and test if it's writable
|
|
CDATE=$(date "+%Y-%m-%d %H:%M:%S")
|
|
if [ ${LOGTEXT} -eq 1 ]; then echo "${CDATE} Starting ${PROGRAM_NAME} ${PROGRAM_VERSION} with PID ${OURPID}, build date ${PROGRAM_RELEASE_DATE}" > ${LOGFILE}; fi
|
|
if [ $? -gt 0 ]; then
|
|
Display --indent 2 --text "- Clearing log file (${LOGFILE})... " --result WARNING --color RED
|
|
echo "${WARNING}Fatal error${NORMAL}: problem while writing to log file. Check location and permissions."
|
|
RemovePIDFile
|
|
exit 1
|
|
fi
|
|
LogTextBreak
|
|
LogText "### ${PROGRAM_COPYRIGHT} ###"
|
|
|
|
# Clear report file (to avoid appending to an existing file)
|
|
if [ ${CREATE_REPORT_FILE} -eq 1 ]; then echo "# ${PROGRAM_NAME} Report" > ${REPORTFILE}; fi
|
|
Report "report_version_major=${REPORT_version_major}"
|
|
Report "report_version_minor=${REPORT_version_minor}"
|
|
CDATE=$(date "+%F %H:%M:%S")
|
|
Report "report_datetime_start=${CDATE}"
|
|
Report "auditor=${AUDITORNAME}"
|
|
Report "lynis_version=${PROGRAM_VERSION}"
|
|
Report "os=${OS}"
|
|
Report "os_name=${OS_NAME}"
|
|
Report "os_fullname=${OS_FULLNAME}"
|
|
Report "os_version=${OS_VERSION}"
|
|
if [ "${OS}" = "Linux" ]; then Report "linux_version=${LINUX_VERSION}"; fi
|
|
if [ -n "${OS_KERNELVERSION}" ]; then Report "os_kernel_version=${OS_KERNELVERSION}"; fi
|
|
if [ -n "${OS_KERNELVERSION_FULL}" ]; then Report "os_kernel_version_full=${OS_KERNELVERSION_FULL}"; fi
|
|
|
|
Report "hostname=${HOSTNAME}"
|
|
|
|
if [ -z "${HOSTNAME}" ]; then
|
|
HOSTNAME="no-hostname"
|
|
LogText "Info: could not find a hostname, using 'no-hostname' instead"
|
|
ReportSuggestion "LYNIS" "Check your hostname configuration" "hostname -s"
|
|
fi
|
|
Report "test_category=${TEST_CATEGORY_TO_CHECK}"
|
|
Report "test_group=${TEST_GROUP_TO_CHECK}"
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Read profile, set code checks, define language
|
|
#
|
|
#################################################################################
|
|
#
|
|
ParseProfiles
|
|
|
|
# Define if we keep working in strict mode (development)
|
|
if [ ${SET_STRICT} -eq 0 ]; then
|
|
set +u # Allow uninitialized variables
|
|
else
|
|
set -u # Do not allow unitialized variables
|
|
fi
|
|
|
|
# Import a different language when configured
|
|
if [ ! "${LANGUAGE}" = "en" ]; then
|
|
LogText "Language is set to ${LANGUAGE}"
|
|
Display --indent 2 --text "- Detecting language and localization" --result "${LANGUAGE}" --color WHITE
|
|
if [ ! -f ${DBDIR}/languages/${LANGUAGE} ]; then
|
|
Display --indent 4 --text "${YELLOW}Notice:${NORMAL} no language file found for '${LANGUAGE}' (tried: ${DBDIR}/languages/${LANGUAGE})"
|
|
if IsDeveloperVersion; then Display --indent 4 --text "See https://github.com/CISOfy/lynis-sdk/documentation/10-translations.md for more details to help translate Lynis"; fi
|
|
sleep 5
|
|
else
|
|
LogText "Importing language file (${DBDIR}/languages/${LANGUAGE})"
|
|
. ${DBDIR}/languages/${LANGUAGE}
|
|
fi
|
|
fi
|
|
LogTextBreak
|
|
|
|
# Pre-execution tests
|
|
if [ ${UPLOAD_DATA} -eq 1 -a -z "${LICENSE_KEY}" ]; then DisplayError "${ERROR_NO_LICENSE}" 64; fi
|
|
if [ ${UPLOAD_DATA} -eq 1 -a -z "${UPLOAD_SERVER}" ]; then DisplayError "${ERROR_NO_UPLOAD_SERVER}" 64; fi
|
|
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Plugins
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Plugin directory test
|
|
if [ -z "${PLUGINDIR}" ]; then
|
|
#LogText "Result: Searching for plugindir"
|
|
tPLUGIN_TARGETS="/usr/local/lynis/plugins /usr/local/share/lynis/plugins /usr/share/lynis/plugins /etc/lynis/plugins ./plugins"
|
|
for DIR in ${tPLUGIN_TARGETS}; do
|
|
if [ -d ${DIR} -a -z "${PLUGINDIR}" ]; then
|
|
PLUGINDIR=${DIR}
|
|
Debug "Result: found plugindir ${PLUGINDIR}"
|
|
fi
|
|
done
|
|
else
|
|
Debug "Plugin was already set before to ${PLUGINDIR} (most likely via program argument or profile)"
|
|
fi
|
|
|
|
# Drop out if our plugin directory can't be found
|
|
if [ -z "${PLUGINDIR}" -o ! -d ${PLUGINDIR} ]; then
|
|
echo "Fatal error: can't find plugin directory ${PLUGINDIR}"
|
|
echo "Make sure to execute ${PROGRAM_NAME} from untarred directory or check your installation."
|
|
exit 1
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Show program information to display
|
|
#
|
|
#################################################################################
|
|
#
|
|
if [ ${QUIET} -eq 0 -a ${SHOW_PROGRAM_DETAILS} -eq 1 ]; then
|
|
echo ""
|
|
echo " ---------------------------------------------------"
|
|
echo " Program version: ${PROGRAM_VERSION}"
|
|
echo " Operating system: ${OS}"
|
|
echo " Operating system name: ${OS_NAME}"
|
|
echo " Operating system version: ${OS_VERSION}"
|
|
LogText "EOL check: ${EOL}"
|
|
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 [ -n "${OS_MODE}" ]; then echo " Operating system mode: ${OS_MODE}"; fi
|
|
echo " Kernel version: ${OS_KERNELVERSION}"
|
|
echo " Hardware platform: ${HARDWARE}"
|
|
echo " Hostname: ${HOSTNAME}"
|
|
echo " ---------------------------------------------------"
|
|
echo " Profiles: ${PROFILES}"
|
|
echo " Log file: ${LOGFILE}"
|
|
echo " Report file: ${REPORTFILE}"
|
|
echo " Report version: ${REPORT_version}"
|
|
echo " Plugin directory: ${PLUGINDIR}"
|
|
echo " ---------------------------------------------------"
|
|
echo " Auditor: ${AUDITORNAME}"
|
|
echo " Language: ${LANGUAGE}"
|
|
echo " Test category: ${TEST_CATEGORY_TO_CHECK}"
|
|
echo " Test group: ${TEST_GROUP_TO_CHECK}"
|
|
if [ ! "${ROOTDIR}" = "/" ]; then echo " Root directory (custom): ${ROOTDIR}"; fi
|
|
echo " ---------------------------------------------------"
|
|
fi
|
|
|
|
LogText "Program version: ${PROGRAM_VERSION}"
|
|
LogText "Operating system: ${OS}"
|
|
LogText "Operating system name: ${OS_NAME}"
|
|
LogText "Operating system version: ${OS_VERSION}"
|
|
if [ -n "${OS_MODE}" ]; then LogText "Operating system mode: ${OS_MODE}"; fi
|
|
LogText "Kernel version: ${OS_KERNELVERSION}"
|
|
if [ -n "${OS_KERNELVERSION_FULL}" ]; then
|
|
LogText "Kernel version (full): ${OS_KERNELVERSION_FULL}"
|
|
fi
|
|
LogText "Hardware platform: ${HARDWARE}"
|
|
LogText "-----------------------------------------------------"
|
|
LogText "Hostname: ${HOSTNAME}"
|
|
LogText "Auditor: ${AUDITORNAME}"
|
|
LogText "Profiles: ${PROFILES}"
|
|
LogText "Work directory: ${WORKDIR}"
|
|
LogText "Include directory: ${INCLUDEDIR}"
|
|
LogText "Plugin directory: ${PLUGINDIR}"
|
|
LogText "-----------------------------------------------------"
|
|
LogText "Log file: ${LOGFILE}"
|
|
LogText "Report file: ${REPORTFILE}"
|
|
LogText "Report version: ${REPORT_version}"
|
|
LogText "-----------------------------------------------------"
|
|
LogText "Test category: ${TEST_CATEGORY_TO_CHECK}"
|
|
LogText "Test group: ${TEST_GROUP_TO_CHECK}"
|
|
LogText "BusyBox used: ${SHELL_IS_BUSYBOX}"
|
|
|
|
Report "plugin_directory=${PLUGINDIR}"
|
|
|
|
LogTextBreak
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Check for program update (and friendly force people to upgrade)
|
|
#
|
|
#################################################################################
|
|
#
|
|
LogText "Test: Checking for program update..."
|
|
UPDATE_AVAILABLE=0
|
|
|
|
if [ ${SKIP_UPGRADE_TEST} -eq 1 ]; then
|
|
LogText "Upgrade test skipped due profile option set (skip_upgrade_test)"
|
|
PROGRAM_LV="${PROGRAM_AC}"
|
|
else
|
|
CheckUpdates
|
|
fi
|
|
|
|
if [ -z "${PROGRAM_AC}" -o -z "${PROGRAM_LV}" ]; then
|
|
Display --indent 2 --text "- Program update status... " --result UNKNOWN --color YELLOW
|
|
LogText "Result: Update check failed. No network connection?"
|
|
LogText "Info: to perform an automatic update check, outbound DNS connections should be allowed (TXT record)."
|
|
# Set both to safe values
|
|
PROGRAM_AC=0; PROGRAM_LV=0
|
|
else
|
|
LogText "Current installed version : ${PROGRAM_AC}"
|
|
LogText "Latest stable version : ${PROGRAM_LV}"
|
|
if [ ${PROGRAM_LV} -gt ${PROGRAM_AC} ]; then
|
|
# Check if current version is REALLY outdated (10 versions ago)
|
|
PROGRAM_MINVERSION=$((PROGRAM_LV - 10))
|
|
LogText "Minimum required version : ${PROGRAM_MINVERSION}"
|
|
if [ ${PROGRAM_MINVERSION} -gt ${PROGRAM_AC} ]; then
|
|
Display --indent 2 --text "- Program update status... " --result "WARNING" --color RED
|
|
LogText "Result: This version is VERY outdated. Newer ${PROGRAM_NAME} release available!"
|
|
ReportWarning "LYNIS" "Version of Lynis is very old and should be updated"
|
|
Report "lynis_update_available=1"
|
|
UPDATE_AVAILABLE=1
|
|
else
|
|
Display --indent 2 --text "- Program update status... " --result "UPDATE AVAILABLE" --color YELLOW
|
|
LogText "Result: newer ${PROGRAM_NAME} release available!"
|
|
ReportSuggestion "LYNIS" "Version of Lynis outdated, consider upgrading to the latest version"
|
|
Report "lynis_update_available=1"
|
|
UPDATE_AVAILABLE=1
|
|
fi
|
|
else
|
|
if [ ${UPDATE_CHECK_SKIPPED} -eq 0 ]; then
|
|
Display --indent 2 --text "- Program update status... " --result "NO UPDATE" --color GREEN
|
|
LogText "No ${PROGRAM_NAME} update available."
|
|
Report "lynis_update_available=0"
|
|
else
|
|
Display --indent 2 --text "- Program update status... " --result "SKIPPED" --color YELLOW
|
|
LogText "Update check skipped due to constraints (e.g. missing dig binary)"
|
|
Report "lynis_update_available=-1"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Test for older releases, without testing via update mechanism
|
|
if [ "${OS}" = "Solaris" ]; then
|
|
NOW=$(nawk 'BEGIN{print srand()}')
|
|
else
|
|
NOW=$(date "+%s")
|
|
fi
|
|
|
|
OLD_RELEASE=0
|
|
TIME_DIFFERENCE_CHECK=10368000 # 4 months
|
|
RELEASE_PLUS_TIMEDIFF=$((PROGRAM_RELEASE_TIMESTAMP + TIME_DIFFERENCE_CHECK))
|
|
if [ ${NOW} -gt ${RELEASE_PLUS_TIMEDIFF} ]; then
|
|
# Show if release is old, only if we didn't show it with normal update check
|
|
if [ ${UPDATE_AVAILABLE} -eq 0 ]; then
|
|
ReportSuggestion "LYNIS" "This release is more than 4 months old. Consider upgrading"
|
|
fi
|
|
UPDATE_AVAILABLE=1
|
|
OLD_RELEASE=1
|
|
fi
|
|
|
|
# Show on screen message if release is very outdated (unless --quiet/--silent is used)
|
|
if [ ${UPDATE_AVAILABLE} -eq 1 -a ${QUIET} -eq 0 ]; then
|
|
echo ""
|
|
echo " ==============================================================================="
|
|
echo " ${CYAN}${PROGRAM_NAME} ${TEXT_UPDATE_AVAILABLE}${NORMAL}"
|
|
echo " ==============================================================================="
|
|
echo ""
|
|
if [ ${OLD_RELEASE} -eq 1 ]; then
|
|
echo " ${YELLOW}Current version is more than 4 months old${NORMAL}"
|
|
echo ""
|
|
fi
|
|
if [ ${PROGRAM_LV} -gt 0 ]; then
|
|
echo " Current version : ${YELLOW}${PROGRAM_AC}${NORMAL} Latest version : ${GREEN}${PROGRAM_LV}${NORMAL}"
|
|
echo ""
|
|
fi
|
|
echo " ${WHITE}Please update to the latest version.${NORMAL}"
|
|
echo " New releases include additional features, bug fixes, tests, and baselines.${NORMAL}"
|
|
echo ""
|
|
echo " Download the latest version:"
|
|
echo ""
|
|
echo " Packages (DEB/RPM) - https://packages.cisofy.com"
|
|
echo " Website (TAR) - https://cisofy.com/downloads/"
|
|
echo " GitHub (source) - https://github.com/CISOfy/lynis"
|
|
echo ""
|
|
echo " ==============================================================================="
|
|
echo ""
|
|
sleep 5
|
|
fi
|
|
|
|
LogTextBreak
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Check which binaries are available to the scanning process
|
|
if [ -f ${INCLUDEDIR}/binaries ]; then
|
|
SafePerms ${INCLUDEDIR}/binaries
|
|
. ${INCLUDEDIR}/binaries
|
|
fi
|
|
LogTextBreak
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Use hardware detection capabilities
|
|
IsVirtualMachine
|
|
if IsContainer; then
|
|
LogText "Result: ${PROGRAM_NAME} is running in container (${CONTAINER_TYPE})"
|
|
Report "container=1"
|
|
Report "container_type=${CONTAINER_TYPE}"
|
|
else
|
|
LogText "Result: ${PROGRAM_NAME} is not running in container"
|
|
Report "container=0"
|
|
fi
|
|
IsNotebook
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Check for systemd active
|
|
if [ -d /run/systemd/system ]; then
|
|
LogText "Result: system is using systemd"
|
|
HAS_SYSTEMD=1
|
|
Report "systemd=1"
|
|
else
|
|
LogText "Result: systemd not found"
|
|
HAS_SYSTEMD=0
|
|
Report "systemd=0"
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
if IsVerbose; then
|
|
InsertSection "Program Details"
|
|
Display --indent 2 --text "- ${GEN_VERBOSE_MODE}" --result "YES" --color GREEN
|
|
if IsDebug; then
|
|
Display --indent 2 --text "- ${GEN_DEBUG_MODE}" --result "YES" --color GREEN
|
|
else
|
|
Display --indent 2 --text "- ${GEN_DEBUG_MODE}" --result "NO" --color RED
|
|
fi
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Plugins
|
|
if [ ${SKIP_PLUGINS} -eq 0 ]; then
|
|
|
|
N_PLUGIN=0
|
|
N_PLUGIN_ENABLED=0
|
|
|
|
# Plugins function
|
|
RunPlugins() {
|
|
if [ $# -eq 0 ]; then echo "RunPlugins should be started with phase number"; ExitFatal; fi
|
|
PLUGIN_PHASE=$1
|
|
if [ ${PLUGIN_PHASE} -eq 0 -o ${PLUGIN_PHASE} -gt 2 ]; then echo "Incorrect phase number when calling RunPlugins"; ExitFatal; fi
|
|
LogTextBreak
|
|
InsertPluginSection "Plugins (${GEN_PHASE} ${PLUGIN_PHASE})"
|
|
if [ ${PLUGIN_PHASE} -eq 1 ]; then
|
|
Display --text "${NOTE_PLUGINS_TAKE_TIME}"
|
|
Display --text " "
|
|
LogText "Searching plugins..."
|
|
fi
|
|
|
|
# Search plugins
|
|
FIND_PLUGINS=$(find ${PLUGINDIR} -type f -name "plugin_[a-z]*_phase${PLUGIN_PHASE}" | sort)
|
|
for PLUGIN_FILE in ${FIND_PLUGINS}; do
|
|
LogText "Found plugin file: ${PLUGIN_FILE}"
|
|
# Double check if output is a valid file name
|
|
if [ -f ${PLUGIN_FILE} ]; then
|
|
FIND2=$(grep "^# PLUGIN_NAME=" ${PLUGIN_FILE} | awk -F= '{ print $2 }')
|
|
if [ ! "${FIND2}" = "" -a ! "${FIND2}" = "[plugin_name]" ]; then
|
|
if [ ${PLUGIN_PHASE} -eq 1 ]; then N_PLUGIN=$((N_PLUGIN + 1)); fi
|
|
# Check if the plugin is enabled in any of the profiles
|
|
PLUGIN_ENABLED_STATE=0
|
|
for PROFILE in ${PROFILES}; do
|
|
LogText "Action: checking plugin status in profile: ${PROFILE}"
|
|
FIND3=$(grep "^plugin=${FIND2}" ${PROFILE})
|
|
if [ -n "${FIND3}" ]; then
|
|
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
|
|
LogText "Result: plugin ${FIND2} is enabled"
|
|
PLUGINFILE="${PLUGINDIR}/plugin_${FIND2}_phase${PLUGIN_PHASE}"
|
|
if [ -f ${PLUGINFILE} ]; then
|
|
PLUGIN_VERSION=$(grep "^# PLUGIN_VERSION=" ${PLUGIN_FILE} | awk -F= '{ print $2 }')
|
|
PLUGIN_VERSION_NODOTS=$(echo ${PLUGIN_VERSION} | sed 's/.//g')
|
|
if SafePerms ${PLUGINFILE}; then
|
|
LogText "Including plugin file: ${PLUGINFILE} (version: ${PLUGIN_VERSION})"
|
|
Report "plugin_enabled_phase${PLUGIN_PHASE}[]=${FIND2}|${PLUGIN_VERSION}|"
|
|
if [ ${PLUGIN_PHASE} -eq 1 ]; then N_PLUGIN_ENABLED=$((N_PLUGIN_ENABLED + 1)); fi
|
|
Display --indent 2 --text "- ${CYAN}Plugin${NORMAL}: ${WHITE}${FIND2}${NORMAL}"
|
|
if [ ${PLUGIN_PHASE} -eq 1 ]; then Progress " ["; fi
|
|
. ${PLUGINFILE}
|
|
if [ ${PLUGIN_PHASE} -eq 1 ]; then Progress "]"; Progress --finish; fi
|
|
LogTextBreak
|
|
LogText "Result: ${FIND2} plugin (phase ${PLUGIN_PHASE}) finished"
|
|
else
|
|
LogText "Plugin ${FIND2}: Skipped (bad file permissions, should be 644, 640, 600 or 400)"
|
|
fi
|
|
else
|
|
LogText "Plugin ${FIND2}: Skipped for phase ${PLUGIN_PHASE} (no file found: ${PLUGINFILE})"
|
|
fi
|
|
else
|
|
LogText "Plugin ${FIND2}: Skipped (not enabled)"
|
|
fi
|
|
else
|
|
LogText "Skipping plugin file ${PLUGIN_FILE} (no valid plugin name found)"
|
|
fi
|
|
fi
|
|
LogText "--"
|
|
done
|
|
LogText "Result: Found ${N_PLUGIN} plugins of which ${N_PLUGIN_ENABLED} are enabled"
|
|
LogText "Result: Plugins phase ${PLUGIN_PHASE} finished"
|
|
}
|
|
RunPlugins 1
|
|
|
|
if [ ${N_PLUGIN_ENABLED} -eq 0 ]; then
|
|
Display --indent 2 --text "- ${GEN_PLUGINS_ENABLED}" --result "NONE" --color WHITE
|
|
Report "plugins_enabled=0"
|
|
else
|
|
Report "plugins_enabled=1"
|
|
fi
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Get host ID
|
|
LogTextBreak
|
|
GetHostID
|
|
# Check if result is not empty (no blank, or hash of blank value, or minus, or zeros)
|
|
if [ ! "${HOSTID}" = "-" -a ! "${HOSTID}" = "" -a ! "${HOSTID}" = "adc83b19e793491b1c6ea0fd8b46cd9f32e592fc" -a ! "${HOSTID}" = "6ef1338f520d075957424741d7ed35ab5966ae97" ]; then
|
|
LogText "Info: found valid HostID ${HOSTID}"
|
|
Report "hostid=${HOSTID}"
|
|
else
|
|
LogText "Info: no HostID found or invalid one"
|
|
fi
|
|
if [ ! "${HOSTID2}" = "" ]; then
|
|
Report "hostid2=${HOSTID2}"
|
|
fi
|
|
if [ ! "${MACHINEID}" = "" ]; then
|
|
LogText "Info: found a machine ID ${MACHINEID}"
|
|
Report "machineid=${MACHINEID}"
|
|
else
|
|
LogText "Info: no machine ID found"
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
|
|
if [ ${RUN_TESTS} -eq 1 ]; then
|
|
|
|
LogTextBreak
|
|
# Test sections
|
|
if [ "${TEST_GROUP_TO_CHECK}" = "all" ]; then
|
|
LogText "Info: perform tests from all categories"
|
|
|
|
INCLUDE_TESTS="boot_services kernel memory_processes authentication shells \
|
|
filesystems usb storage storage_nfs nameservices dns ports_packages networking printers_spools \
|
|
mail_messaging firewalls webservers ssh snmp databases ldap php squid logging \
|
|
insecure_services banners scheduling accounting time crypto virtualization containers \
|
|
mac_frameworks file_integrity tooling malware file_permissions homedirs \
|
|
kernel_hardening hardening"
|
|
else
|
|
INCLUDE_TESTS="${TEST_GROUP_TO_CHECK}"
|
|
LogText "Info: only performing tests from groups: ${TEST_GROUP_TO_CHECK}"
|
|
fi
|
|
|
|
# Include available tests
|
|
for INCLUDE_TEST in ${INCLUDE_TESTS}; do
|
|
INCLUDE_FILE="${INCLUDEDIR}/tests_${INCLUDE_TEST}"
|
|
if [ -f ${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)"
|
|
ReportWarning "NONE" "Invalid permissions on tests file tests_${INCLUDE_TEST}"
|
|
# Insert a section and warn user also on screen
|
|
InsertSection "General"
|
|
Display --indent 2 --text "- Running test category ${INCLUDE_TEST}... " --result "SKIPPED" --color RED
|
|
fi
|
|
else
|
|
echo "Error: Can't find file (category: ${INCLUDE_TEST})"
|
|
fi
|
|
done
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
|
|
if [ ${RUN_TESTS} -eq 1 ]; then
|
|
|
|
InsertSection "${SECTION_CUSTOM_TESTS}"
|
|
LogText "Test: Checking for tests_custom file"
|
|
# Custom tests
|
|
if [ -f ${INCLUDEDIR}/tests_custom ]; then
|
|
LogText "Result: tests_custom file found in include directory"
|
|
if SafePerms ${INCLUDEDIR}/tests_custom; then
|
|
Display --indent 2 --text "- Start custom tests... "
|
|
LogText "Result: file permissions fine, running custom tests"
|
|
. ${INCLUDEDIR}/tests_custom
|
|
else
|
|
LogText "Exception: skipping custom tests, file has bad permissions (should be 640, 600 or 400)"
|
|
ReportWarning "NONE" "Invalid permissions on custom tests file"
|
|
Display --indent 2 --text "- Running custom tests... " --result "WARNING" --color RED
|
|
fi
|
|
else
|
|
Display --indent 2 --text "- Running custom tests... " --result "NONE" --color WHITE
|
|
fi
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Run helpers
|
|
#
|
|
#################################################################################
|
|
#
|
|
if [ ${RUN_HELPERS} -eq 1 ]; then
|
|
if [ ! "${HELPER}" = "" ]; then
|
|
LogText "Helper tool is $HELPER"
|
|
if [ -f ${INCLUDEDIR}/helper_${HELPER} ]; then
|
|
SafePerms ${INCLUDEDIR}/helper_${HELPER}
|
|
LogText "Running helper tool ${HELPER} with params: ${HELPER_PARAMS}"
|
|
InsertPluginSection "Helper: ${HELPER}"
|
|
. ${INCLUDEDIR}/helper_${HELPER} ${HELPER_PARAMS}
|
|
else
|
|
echo "Error, could not find helper"
|
|
fi
|
|
fi
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Run phase 2 of plugins
|
|
#
|
|
#################################################################################
|
|
#
|
|
if [ ${SKIP_PLUGINS} -eq 0 ]; then
|
|
RunPlugins 2
|
|
if [ ${N_PLUGIN_ENABLED} -gt 1 ]; then
|
|
Display --indent 2 --text "- Plugins (phase 2)" --result "DONE" --color GREEN
|
|
fi
|
|
fi
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Show test results overview
|
|
#
|
|
#################################################################################
|
|
#
|
|
# Store total performed tests
|
|
Report "lynis_tests_done=${CTESTS_PERFORMED}"
|
|
CDATE=$(date "+%F %H:%M:%S")
|
|
Report "report_datetime_end=${CDATE}"
|
|
|
|
# Show report
|
|
if [ -f ${INCLUDEDIR}/report ]; then SafePerms ${INCLUDEDIR}/report; . ${INCLUDEDIR}/report; fi
|
|
|
|
# Show tool tips
|
|
if [ -f ${INCLUDEDIR}/tool_tips ]; then SafePerms ${INCLUDEDIR}/tool_tips; . ${INCLUDEDIR}/tool_tips; fi
|
|
|
|
LogText "================================================================================"
|
|
LogText "Tests performed: ${CTESTS_PERFORMED}"
|
|
LogText "Total tests: ${TOTAL_TESTS}"
|
|
LogText "Active plugins: ${N_PLUGIN_ENABLED}"
|
|
LogText "Total plugins: ${N_PLUGIN}"
|
|
LogText "================================================================================"
|
|
Report "tests_executed=${TESTS_EXECUTED}"
|
|
Report "tests_skipped=${TESTS_SKIPPED}"
|
|
Report "finish=true"
|
|
|
|
# Upload data
|
|
if [ ${UPLOAD_DATA} -eq 1 ]; then
|
|
if [ -f ${INCLUDEDIR}/data_upload ]; then
|
|
SafePerms ${INCLUDEDIR}/data_upload
|
|
. ${INCLUDEDIR}/data_upload
|
|
else
|
|
echo "Fatal error: can't find upload_data script"
|
|
fi
|
|
fi
|
|
|
|
LogText "${PROGRAM_NAME} ${PROGRAM_VERSION}"
|
|
LogText "${PROGRAM_COPYRIGHT}"
|
|
LogText "${PROGRAM_EXTRAINFO}"
|
|
LogText "Program ended successfully"
|
|
LogText "================================================================================"
|
|
|
|
# Tool tips
|
|
|
|
if [ ${QUIET} -eq 0 ]; then
|
|
|
|
if [ -z "${CUSTOM_PROFILE}" ]; then DisplayToolTip "Enhance ${PROGRAM_NAME} audits by adding your settings to custom.prf (see ${DEFAULT_PROFILE} for all settings)"; fi
|
|
fi
|
|
|
|
# Clean exit (Delete PID file)
|
|
if [ ${TOTAL_WARNINGS} -gt 0 ]; then
|
|
# Use exit code 78 if we found any warnings (and enabled)
|
|
if [ ${ERROR_ON_WARNINGS} -eq 1 ]; then
|
|
ExitCustom 78
|
|
else
|
|
ExitClean
|
|
fi
|
|
else
|
|
ExitClean
|
|
fi
|
|
|
|
# The End
|
|
|
|
#
|
|
#================================================================================
|
|
# Lynis - Copyright 2007-2019, Michael Boelen, CISOfy - https://cisofy.com
|