#!/bin/sh

#################################################################################
#
#   Lynis
# ------------------
#
# Copyright (c) Michael Boelen, CISOfy, and many contributors.
#
# Website  : https://cisofy.com
# Blog     : https://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.
#
#################################################################################
#
    ANSIBLE_ARTIFACT_FOUND=0
    AUTOMATION_TOOL_FOUND=0
    AUTOMATION_TOOL_RUNNING=""
    CFENGINE_AGENT_FOUND=0
    CFENGINE_SERVER_RUNNING=0
    BACKUP_AGENT_FOUND=0
    PUPPET_MASTER_RUNNING=0
    SALT_MASTER_RUNNING=0
    SALT_MINION_RUNNING=0
    IDS_IPS_TOOL_FOUND=0
    FAIL2BAN_FOUND=0
    FAIL2BAN_EMAIL=0
    FAIL2BAN_SILENT=0
    PERFORM_FAIL2BAN_TESTS=0
    SNORT_FOUND=0
    SNORT_RUNNING=0
#
#################################################################################
#
    InsertSection "${SECTION_SYSTEM_TOOLING}"
#
#################################################################################
#
# Automation
#
#################################################################################
#
    # Test        : TOOL-5002
    # Description : Check if automation tools are found
    Register --test-no TOOL-5002 --weight L --network NO --category security --description "Checking for automation tools"
    if [ ${SKIPTEST} -eq 0 ]; then

        Display --indent 2 --text "- Checking automation tooling"

        # Ansible
        FOUND=0
        LIST="${HOME}/.ansible ${ROOTDIR}etc/ansible ${ROOTDIR}root/.ansible ${ROOTDIR}tmp/.ansible"
        for ITEM in ${LIST}; do if DirectoryExists ${ITEM}; then FOUND=1; break; fi; done
        # Test for files (only if no match was found)
        if [ ${FOUND} -eq 0 ]; then
            LIST="${ROOTDIR}var/log/ansible.log ~/.ansible-retry"
            for ITEM in ${LIST}; do if FileExists ${ITEM}; then FOUND=1; break; fi; done
        fi

        if [ ${FOUND} -eq 1 ]; then
            LogText "Result: found a possible trace of Ansible"
            AUTOMATION_TOOL_FOUND=1
            ANSIBLE_ARTIFACT_FOUND=1
            Report "automation_tool_running[]=ansible"
            Display --indent 4 --text "- Ansible artifact" --result "${STATUS_FOUND}" --color GREEN
        fi

        # Cfengine
        if [ -n "${CFAGENTBINARY}" ]; then
            LogText "Result: CFEngine (cfagent) is installed (${CFAGENTBINARY})"
            AUTOMATION_TOOL_FOUND=1
            CFENGINE_AGENT_FOUND=1
            Report "automation_tool_running[]=cf-agent"
            Display --indent 4 --text "- Cfengine (cfagent)" --result "${STATUS_FOUND}" --color GREEN
        fi
        OTHER_CFENGINE_LOCATIONS="/var/cfengine/bin /var/rudder/cfengine-community/bin"
        for I in ${OTHER_CFENGINE_LOCATIONS}; do
            if [ -d ${I} ]; then
                if [ -f ${I}/cf-agent ]; then
                    LogText "Result: found CFEngine agent (cf-agent) in ${I}"
                    AUTOMATION_TOOL_FOUND=1
                    CFENGINE_AGENT_FOUND=1
                    Report "automation_tool_running[]=cf-agent"
                    Display --indent 4 --text "- CFEngine (cf-agent)" --result "${STATUS_FOUND}" --color GREEN
                fi
                if IsRunning "cf-server"; then
                    LogText "Result: found CFEngine server"
                    AUTOMATION_TOOL_FOUND=1
                    CFENGINE_SERVER_RUNNING=1
                    Report "automation_tool_running[]=cf-server"
                    Display --indent 4 --text "- CFEngine (cf-server)" --result "${STATUS_FOUND}" --color GREEN
                fi
            fi
        done

        # Chef
        CHEF_LOCATIONS="/opt/chef/bin /opt/chef-server/sv /opt/chefdk/bin"
        for I in ${CHEF_LOCATIONS}; do
            if [ -d ${I} ]; then
                if [ -f ${I}/chef-client ]; then
                    CHEFCLIENTBINARY="${I}/chef-client"
                    AUTOMATION_TOOL_FOUND=1
                    Report "automation_tool_running[]=chef-client"
                    Display --indent 4 --text "- Chef client (chef-client)" --result "${STATUS_FOUND}" --color GREEN
                    LogText "Result: found chef-client (chef client daemon) in ${I}"
                fi
                if [ -f ${I}/erchef ]; then
                    CHEFSERVERBINARY="${I}/erchef"
                    LogText "Result: Chef Server (erchef) is installed (${CHEFSERVERBINARY})"
                    AUTOMATION_TOOL_FOUND=1
                    Report "automation_tool_running[]=chef-server"
                    Display --indent 4 --text "- Chef Server (erchef)" --result "${STATUS_FOUND}" --color GREEN
                    LogText "Result: found erchef (chef server daemon) in ${I}"
                fi
            fi
        done

        # Puppet

        # Check for Puppet installation provided by Puppetlabs package
        if [ -z "${PUPPETBINARY}" ]; then
            if [ -f ${ROOTDIR}opt/puppetlabs/puppet/bin/puppet ]; then
                PUPPETBINARY="${ROOTDIR}opt/puppetlabs/puppet/bin/puppet"
            fi
        fi

        if [ -n "${PUPPETBINARY}" ]; then
            LogText "Result: Puppet is installed (${PUPPETBINARY})"
            AUTOMATION_TOOL_FOUND=1
            Report "automation_tool_running[]=puppet-agent"
            Display --indent 4 --text "- Puppet (agent)" --result "${STATUS_FOUND}" --color GREEN
        fi

        if IsRunning --full "puppet master"; then
            LogText "Result: found puppet master"
            AUTOMATION_TOOL_FOUND=1
            PUPPET_MASTER_RUNNING=1
            Report "automation_tool_running[]=puppet-master"
            Display --indent 4 --text "- Puppet (master)" --result "${STATUS_FOUND}" --color GREEN
        fi

        # SaltStack
        if [ -n "${SALTMINIONBINARY}" ]; then
            Display --indent 4 --text "- SaltStack minion" --result "${STATUS_FOUND}" --color GREEN
            LogText "Result: SaltStack (salt-minion) is installed (${SALTMINIONBINARY})"
            AUTOMATION_TOOL_FOUND=1
            Report "automation_tool_installed[]=saltstack-minion"

            if IsRunning "salt-minion" --user "root salt"; then
                Display --indent 6 --text "- Minion process" --result "${STATUS_RUNNING}" --color GREEN
                LogText "Result: found SaltStack (master)"
                SALT_MINION_RUNNING=1
                Report "automation_tool_running[]=saltstack-minion"
            else
                Display --indent 6 --text "- Minion process" --result "${STATUS_NOT_RUNNING}" --color YELLOW
            fi

        fi

        if [ -n "${SALTMASTERBINARY}" ]; then
            Display --indent 4 --text "- SaltStack master (salt-master)" --result "${STATUS_FOUND}" --color GREEN
            LogText "Result: SaltStack (salt-master) is installed (${SALTMASTERBINARY})"
            AUTOMATION_TOOL_FOUND=1
            Report "automation_tool_installed[]=saltstack-master"

            if IsRunning "salt-master" --user "root salt"; then
                Display --indent 6 --text "- Master process" --result "${STATUS_RUNNING}" --color GREEN
                LogText "Result: found SaltStack (master)"
                SALT_MASTER_RUNNING=1
                Report "automation_tool_running[]=saltstack-master"
            else
                Display --indent 6 --text "- Master process" --result "${STATUS_NOT_RUNNING}" --color YELLOW
            fi
        fi

        if [ ${AUTOMATION_TOOL_FOUND} -eq 1 ]; then
            Display --indent 2 --text "- Automation tooling" --result "${STATUS_FOUND}" --color GREEN
        else
            Display --indent 2 --text "- Automation tooling" --result "${STATUS_NOT_FOUND}" --color YELLOW
            ReportSuggestion "${TEST_NO}" "Determine if automation tools are present for system management"
        fi
    fi
#
#################################################################################
#
# Intrusion Detection and Prevention tools
#
#################################################################################
#
    # Test        : TOOL-5102
    # Description : Check for Fail2ban
    Register --test-no TOOL-5102 --weight L --network NO --category security --description "Check for presence of Fail2ban"
    if [ ${SKIPTEST} -eq 0 ]; then

        # Fail2ban presence
        if [ -n "${FAIL2BANBINARY}" ]; then
            FAIL2BAN_FOUND=1
            IDS_IPS_TOOL_FOUND=1
            LogText "Result: Fail2ban is installed (${FAIL2BANBINARY})"
            Report "ids_ips_tooling[]=fail2ban"
            Display --indent 2 --text "- Checking presence of Fail2ban" --result "${STATUS_FOUND}" --color GREEN
        else
            LogText "Result: Fail2ban not present (fail2ban-server not found)"
        fi

        # Fail2ban configuration
        LogText "Checking Fail2ban configuration file"
        if [ -f /etc/fail2ban/jail.local ]; then
            FAIL2BAN_CONFIG="/etc/fail2ban/jail.local"
        elif [ -f /etc/fail2ban/jail.conf ]; then
            FAIL2BAN_CONFIG="/etc/fail2ban/jail.conf"
        else
            FAIL2BAN_CONFIG=""
        fi

        # Continue if tooling is available and configuration file found
        if [ ${FAIL2BAN_FOUND} -eq 1 -a -n "${FAIL2BAN_CONFIG}" ]; then
            Report "fail2ban_config=${FAIL2BAN_CONFIG}"
            FAIL2BANCLIENT=$(which fail2ban-client 2> /dev/null | grep -v "no [^ ]* in ")
            if [ -n "${FAIL2BANCLIENT}" ]; then PERFORM_FAIL2BAN_TESTS=1; fi
        fi
    fi
#
#################################################################################
#
    # Test        : TOOL-5104
    # Description : Check for Fail2ban enabled tests
    if [ ${PERFORM_FAIL2BAN_TESTS} -eq 1 ]; then PREQS_MET="YES"; else PREQS_MET="NO"; fi
    Register --test-no TOOL-5104 --weight L --network NO --preqs-met ${PREQS_MET} --category security --description "Enabled tests in Fail2ban"
    if [ ${SKIPTEST} -eq 0 ]; then
        FIND=$(${FAIL2BANCLIENT} -d | ${TRBINARY} -d '[]' | ${TRBINARY} -d "'" | ${AWKBINARY} -F, '{ if ($1=="add") { print $2 }}' | ${TRBINARY} -d ' ')
        if [ -n "${FIND}" ]; then
            for F2BSERVICE in ${FIND}; do
                LogText "Result: service '${F2BSERVICE}' enabled"
                Report "fail2ban_enabled_service[]=${F2BSERVICE}"
            done
            LogText "Result: found at least one enabled jail"
            Display --indent 4 --text "- Checking Fail2ban jails" --result "${STATUS_ENABLED}" --color GREEN
            AddHP 3 3
        else
            LogText "Result: Fail2ban installed but completely disabled"
            Display --indent 4 --text "- Checking Fail2ban jails" --result "${STATUS_DISABLED}" --color RED
            AddHP 0 5
            ReportWarning "${TEST_NO}" "All jails in Fail2ban are disabled" "${FAIL2BAN_CONFIG}"
        fi
    fi
#
#################################################################################
#
    # These tests are temporarily disabled to split them up in different areas to check
    #
    #            LogText "Result: found configuration file (${FAIL2BAN_CONFIG})"
    #
    #            # Check email alert configuration
    #            LogText "Test: checking for email actions within ${FAIL2BAN_CONFIG}"
    #
    #            FIND=$(${GREPBINARY} -E "^action = \%\(action_m.*\)s" ${FAIL2BAN_CONFIG})
    #            FIND2=$(${GREPBINARY} -E "^action = \%\(action_\)s" ${FAIL2BAN_CONFIG})
    #
    #            if [ -n "${FIND}" ]; then
    #                FAIL2BAN_EMAIL=1
    #                LogText "Result: found at least one jail which sends an email alert"
    #            fi
    #
    #            if [ -n "${FIND2}" ]; then
    #                FAIL2BAN_SILENT=1
    #                LogText "Result: found at least one jail which does NOT send an email alert"
    #            fi
    #
    #            if [ ${FAIL2BAN_SILENT} -eq 0 ] && [ ${FAIL2BAN_EMAIL} -eq 0 ]; then
    #                LogText "No registered actions found in ${FAIL2BAN_CONFIG}"
    #                Display --indent 4 --text "- Checking Fail2ban actions" --result "${STATUS_NONE}" --color RED
    #                ReportWarning "${TEST_NO}" "${FAIL2BAN_CONFIG}" "There are no actions configured for Fail2ban."
    #                AddHP 0 3
    #            fi
    #
    #            if [ ${FAIL2BAN_SILENT} -eq 0 ] && [ ${FAIL2BAN_EMAIL} -eq 1 ]; then
    #                LogText "All actions in ${FAIL2BAN_CONFIG} are configured to send email alerts"
    #                Display --indent 4 --text "- Checking Fail2ban actions" --result "${STATUS_OK}" --color GREEN
    #                AddHP 3 3
    #            fi
    #
    #            if [ ${FAIL2BAN_SILENT} -eq 1 ] && [ ${FAIL2BAN_EMAIL} -eq 1 ]; then
    #                LogText "Some actions found in ${FAIL2BAN_CONFIG} are configured to send email alerts"
    #                Display --indent 4 --text "- Checking Fail2ban actions" --result PARTIAL --color YELLOW
    #                ReportSuggestion "${TEST_NO}" "Some Fail2ban jails are configured with non-notified actions.  Consider changing these to emailed alerts."
    #                AddHP 2 3
    #            fi
    #
    #            if [ ${FAIL2BAN_SILENT} -eq 1 ] && [ ${FAIL2BAN_EMAIL} -eq 0 ]; then
    #                LogText "None of the actions found in ${FAIL2BAN_CONFIG} are configured to send email alerts"
    #                Display --indent 4 --text "- Checking Fail2ban actions" --result "${STATUS_NONE}" --color YELLOW
    #                ReportSuggestion "${TEST_NO}" "None of the Fail2ban jails are configured to send email notifications.  Consider changing these to emailed alerts."
    #                AddHP 1 3
    #            fi
    #
    #            # Check at least one enabled jail
    #            LogText "Checking for enabled jails within ${FAIL2BAN_CONFIG}"
    #
    #
    #
    #            # Confirm at least one iptables chain for fail2ban
    #
    #            LogText "Checking for fail2ban iptables chains"
    #
    #            if [ -n "${IPTABLESBINARY}" ]; then
    #                CHECK_CHAINS=$(${IPTABLESBINARY} -L 2>&1 | ${GREPBINARY} fail2ban)
    #                if [ -n "${CHECK_CHAINS}" ]; then
    #                    LogText "Result: found at least one iptables chain for fail2ban"
    #                    Display --indent 4 --text "- Checking for Fail2ban iptables chain" --result "${STATUS_OK}" --color GREEN
    #                else
    #                    LogText "Result: Fail2ban installed but iptables chain not present - fail2ban will not work"
    #                    Display --indent 4 --text "- Checking for Fail2ban iptables chain" --result "${STATUS_WARNING}" --color RED
    #                    AddHP 0 3
    #                    ReportSuggestion "${TEST_NO}" "Check config to see why iptables does not have a fail2ban chain" "${FAIL2BAN_CONFIG}"
    #                fi
    #            else
    #                Display --indent 4 --text "- Checking for Fail2ban iptables chain" --result "${STATUS_WARNING}" --color RED
    #                ReportSuggestion "${TEST_NO}" "iptables doesn't seem to be installed; Fail2ban will not work. Remove Fail2ban or install iptables" "${FAIL2BAN_CONFIG}"
    #            fi
    #        fi
    #    fi
#
#################################################################################
#
    # Test        : TOOL-5120
    # Description : Check for Snort
    Register --test-no TOOL-5120 --weight L --network NO --category security --description "Check for presence of Snort"
    if [ ${SKIPTEST} -eq 0 ]; then

        # Snort presence
        if [ -n "${SNORTBINARY}" ]; then
            SNORT_FOUND=1
            IDS_IPS_TOOL_FOUND=1
            LogText "Result: Snort is installed (${SNORTBINARY})"
            Report "ids_ips_tooling[]=snort"
            Display --indent 2 --text "- Checking presence of Snort" --result "${STATUS_FOUND}" --color GREEN
        fi

        if IsRunning "snort"; then
            SNORT_FOUND=1
            SNORT_RUNNING=1
            SNORT_LOG=$(${PSBINARY} | ${AWKBINARY} -F-.. '/snort/ {print $4}' | ${HEADBINARY} -1)
        else
            LogText "Result: Snort not present (Snort not running)"
        fi
    fi
#
#################################################################################
#
    # Test        : TOOL-5122
    # Description : Check for Snort configuration
    Register --test-no TOOL-5122 --weight L --network NO --category security --description "Check Snort configuration file"
    if [ ${SKIPTEST} -eq 0 ]; then

        # Continue if tooling is available and snort is running
        if [ -n "${SNORT_FOUND}" ] || [ -n "${SNORT_RUNNING}" ]; then
            if [ ${SNORT_FOUND} -eq 1 ] && [ ${SNORT_RUNNING} -eq 1 ]; then
                SNORT_CONFIG=$(${PSBINARY} | ${AWKBINARY} -F-.. '/snort/ {print $3}' | ${HEADBINARY} -1)
                if HasData "${SNORT_CONFIG}"; then
                    LogText "Result: found Snort configuration file: ${SNORT_CONFIG}"
                    Report "snort_config=${SNORT_CONFIG}"
                fi
                SNORT=$(which snort 2> /dev/null)
            fi
        fi
    fi
#
#################################################################################
#
    # Test        : TOOL-5130
    # Description : Check for Suricata
    Register --test-no TOOL-5130 --weight L --network NO --category security --description "Check for active Suricata daemon"
    if [ ${SKIPTEST} -eq 0 ]; then
        # Suricata presence
        if [ -n "${SURICATABINARY}" ]; then
            Report "ids_ips_tooling[]=suricata"
            LogText "Result: Suricata is installed (${SURICATABINARY})"
            # Suricata status
            # Suricata sets its process name to Suricata-Main on Linux, but this might differ on other platforms,
            # so fall back to checking the full commandline instead if the first test fails
            if IsRunning "Suricata-Main" || IsRunning --full "${SURICATABINARY} "; then
                # Only satisfy test TOOL-5190 if Suricata is actually running
                IDS_IPS_TOOL_FOUND=1
                LogText "Result: Suricata daemon is active"
                Display --indent 2 --text "- Checking Suricata status" --result "${STATUS_RUNNING}" --color GREEN
            else
                LogText "Result: Suricata daemon not active"
                Display --indent 2 --text "- Checking Suricata status" --result "${STATUS_NOT_RUNNING}" --color YELLOW
            fi
        else
            LogText "Result: Suricata not installed (suricata not found)"
        fi
    fi
#
#################################################################################
#
    # Test        : TOOL-5126
    # Description : Check for OSSEC
    Register --test-no TOOL-5126 --weight L --network NO --category security --description "Check for active OSSEC daemon"
    if [ ${SKIPTEST} -eq 0 ]; then
        # Server side
        if IsRunning "ossec-analysisd"; then
            IDS_IPS_TOOL_FOUND=1
            Report "ids_ips_tooling[]=ossec"
            Report "ids_ips_tooling[]=ossec-analysisd"
            LogText "Result: OSSEC analysis daemon is active"
            Display --indent 2 --text "- Checking presence of OSSEC (analysis)" --result "${STATUS_FOUND}" --color GREEN
        else
            LogText "Result: OSSEC analysis daemon not active"
        fi

        # Client side
        if IsRunning "ossec-agentd"; then
            IDS_IPS_TOOL_FOUND=1
            Report "ids_ips_tooling[]=ossec"
            Report "ids_ips_tooling[]=ossec-agentd"
            LogText "Result: OSSEC agent daemon is active"
            Display --indent 2 --text "- Checking presence of OSSEC (agent)" --result "${STATUS_FOUND}" --color GREEN
        else
            LogText "Result: OSSEC agent daemon not active"
        fi
    fi
#
#################################################################################
#
    # Test        : TOOL-5128
    # Description : Check for Wazuh daemon
    Register --test-no TOOL-5128 --weight L --network NO --category security --description "Check for active Wazuh daemon"
    if [ ${SKIPTEST} -eq 0 ]; then
        # Server side
        if IsRunning "wazuh-analysisd"; then
            IDS_IPS_TOOL_FOUND=1
            Report "ids_ips_tooling[]=wazuh"
            Report "ids_ips_tooling[]=wazuh-analysisd"
            LogText "Result: Wazuh analysis daemon is active"
            Display --indent 2 --text "- Checking presence of Wazuh (analysis)" --result "${STATUS_FOUND}" --color GREEN
        else
            LogText "Result: Wazuh analysis daemon not active"
        fi

        # Client side
        if IsRunning "wazuh-agentd"; then
            IDS_IPS_TOOL_FOUND=1
            Report "ids_ips_tooling[]=wazuh"
            Report "ids_ips_tooling[]=wazuh-agentd"
            LogText "Result: Wazuh agent daemon is active"
            Display --indent 2 --text "- Checking presence of Wazuh (agent)" --result "${STATUS_FOUND}" --color GREEN
        else
            LogText "Result: Wazuh agent daemon not active"
        fi
    fi
#
#################################################################################
#
    # Test        : TOOL-5190
    # Description : Check for an IDS/IPS tool
    Register --test-no TOOL-5190 --weight L --network NO --category security --description "Check presence of IDS/IPS tool"
    if [ ${SKIPTEST} -eq 0 ]; then

        if [ ${IDS_IPS_TOOL_FOUND} -eq 1 ]; then
            Display --indent 2 --text "- Checking for IDS/IPS tooling" --result "${STATUS_FOUND}" --color GREEN
            AddHP 2 2
        else
            Display --indent 2 --text "- Checking for IDS/IPS tooling" --result "${STATUS_NONE}" --color YELLOW
            #ReportSuggestion "${TEST_NO}" "Install and configure automated intrusion detection/prevention tools"
            AddHP 0 2
        fi
    fi
#
#################################################################################
#
# Backup tools
#
#################################################################################
#
    # Netvault
    # Rsync in cron
#
#################################################################################
#
    Report "automation_tool_present=${AUTOMATION_TOOL_FOUND}"


    WaitForKeyPress
#
#================================================================================
# Lynis - Security Auditing and System Hardening for Linux and UNIX - https://cisofy.com
