#!/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.
#
#################################################################################
#
# Report
#
#################################################################################
#
    # Add additional data fields to the report file at the end of the scan
    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 [ -n "${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
    #
    # 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.

    # 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

    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
    if [ ${QUIET} -eq 0 ]; then
        echo ""; echo "================================================================================"
        echo ""; echo "  -[ ${WHITE}${PROGRAM_NAME} ${PROGRAM_VERSION} Results${NORMAL} ]-"
        echo "";


    if [ ${SHOW_REPORT} -eq 1 ]; then

        LogTextBreak

        # Show test results overview

            if [ -z "${CONTROL_URL_PROTOCOL}" ]; then CONTROL_URL_PROTOCOL="https"; fi
            if [ -z "${CONTROL_URL_PREPEND}" ]; then CONTROL_URL_PREPEND="cisofy.com/lynis/controls/"; fi
            if [ -z "${CONTROL_URL_APPEND}" ]; then CONTROL_URL_APPEND="/"; fi
            if [ -z "${CUSTOM_URL_PROTOCOL}" ]; then CUSTOM_URL_PROTOCOL="https"; fi
            if [ -z "${CUSTOM_URL_PREPEND}" ]; then CUSTOM_URL_PREPEND="your-domain.example.org/controls/"; fi
            if [ -z "${CUSTOM_URL_APPEND}" ]; then CUSTOM_URL_APPEND="/"; fi

            # Show warnings from logfile
            SWARNINGS=$(${GREPBINARY} 'Warning: ' ${LOGFILE} | sed 's/ /!space!/g')
            if [ -z "${SWARNINGS}" ]; then
                echo "  ${OK}Great, no warnings${NORMAL}"; echo ""
            else
                echo "  ${WARNING}Warnings${NORMAL} (${TOTAL_WARNINGS}):"
                echo "  ${WHITE}----------------------------${NORMAL}"
                for WARNING in ${SWARNINGS}; do
                    SOLUTION=""
                    SHOWWARNING=$(echo ${WARNING} | sed 's/!space!/ /g' | sed 's/^.* Warning: //' | sed 's/\[details:\(.*\)\] \[solution:\(.*\)\]//' | sed 's/test://')
                    ADDLINK=$(echo ${WARNING} | sed 's/!space!/ /g' | sed 's/^.* Warning: \(.*\)\[test://' | sed 's/\]\(.*\)]//' | ${AWKBINARY} -F: '{print $1}')
                    DETAILS=$(echo ${WARNING} | sed 's/!space!/ /g' | sed 's/^.* Warning: \(.*\)\[details://' | sed 's/\]\(.*\)]//')
                    SUGGESTION_PIECES=$(echo ${WARNING} | sed 's/\[/ [/g')
                    for PIECE in ${SUGGESTION_PIECES}; do
                        if [ -z "${SOLUTION}" ]; then
                            SEARCH=$(echo ${PIECE} | grep "^\[solution:")
                            if [ $? -eq 0 ]; then SOLUTION=$(echo ${SEARCH} | sed 's/!space!/ /g' | sed 's/solution://' | sed 's/text://' | tr -d '[]'); fi
                        fi
                    done
                    IS_CUSTOM=$(echo ${ADDLINK} | grep "^CUST")
                    echo "  ${RED}!${NORMAL} ${SHOWWARNING}"
                    if [ ! "${DETAILS}" = "-" -a -n "${DETAILS}" ]; then echo "    - Details  : ${CYAN}${DETAILS}${NORMAL}"; fi
                    if [ ${SHOW_REPORT_SOLUTION} -eq 1 -a ! "${SOLUTION}" = "-" ]; then echo "    - Solution : ${SOLUTION}"; fi
                    if [ -z "${IS_CUSTOM}" ]; then
                        echo "      ${CONTROL_URL_PROTOCOL}://${CONTROL_URL_PREPEND}${ADDLINK}${CONTROL_URL_APPEND}"
                    else
                        echo "      ${CUSTOM_URL_PROTOCOL}://${CUSTOM_URL_PREPEND}${ADDLINK}${CUSTOM_URL_APPEND}"
                    fi
                    echo ""
                done
            fi

            # Show suggestions from logfile
            SUGGESTIONS=$(${GREPBINARY} 'Suggestion: ' ${LOGFILE} | sed 's/ /!space!/g')

            if [ -z "${SUGGESTIONS}" ]; then
                echo "  ${OK}No suggestions${NORMAL}"; echo ""
            else
                echo "  ${YELLOW}Suggestions${NORMAL} (${TOTAL_SUGGESTIONS}):"
                echo "  ${WHITE}----------------------------${NORMAL}"
                for SUGGESTION in ${SUGGESTIONS}; do
                    SOLUTION=""
                    SHOWSUGGESTION=$(echo ${SUGGESTION} | sed 's/!space!/ /g' | sed 's/^.* Suggestion: //' | sed 's/\[details:\(.*\)\] \[solution:\(.*\)\]//' | sed 's/test://')
                    RELATED_CONTROL=$(echo ${SUGGESTION} | sed 's/!space!/ /g' | sed 's/^.* Suggestion: \(.*\)\[test://' | sed 's/\]\(.*\)]//' | ${AWKBINARY} -F: '{print $1}')
                    ADDLINK="${RELATED_CONTROL}"
                    DETAILS=$(echo ${SUGGESTION} | sed 's/!space!/ /g' | sed 's/^.* Suggestion: \(.*\)\[details://' | sed 's/\]\(.*\)]//')
                    SUGGESTION_PIECES=$(echo ${SUGGESTION} | sed 's/\[/ [/g')
                    for PIECE in ${SUGGESTION_PIECES}; do
                        if [ -z "${SOLUTION}" ]; then
                            SEARCH=$(echo ${PIECE} | grep "^\[solution:")
                            if [ $? -eq 0 ]; then SOLUTION=$(echo ${SEARCH} | sed 's/!space!/ /g' | sed 's/solution://' | sed 's/text://' | tr -d '[]'); fi
                        fi
                    done
                    IS_CUSTOM=$(echo ${ADDLINK} | grep "^CUST")
                    echo "  ${YELLOW}*${NORMAL} ${SHOWSUGGESTION}"
                    if [ ! "${DETAILS}" = "-" -a -n "${DETAILS}" ]; then echo "    - Details  : ${CYAN}${DETAILS}${NORMAL}"; fi
                    if [ ${SHOW_REPORT_SOLUTION} -eq 1 -a ! "${SOLUTION}" = "-" ]; then echo "    - Solution : ${SOLUTION}"; fi
                    # Show relevant articles if the database is available
                    if [ -f ${DBDIR}/control-links.db ]; then
                        echo "    - Related resources"
                        ARTICLES=$($AWKBINARY -F \; -v control=${RELATED_CONTROL} '{if($1==control && $2=="blog"){print $2";"$3";"$4";"}}' "${DBDIR}/control-links.db" | sed 's/ /!space!/g')
                        if [ -n "${ARTICLES}" ]; then
                            for ITEM in ${ARTICLES}; do
                                ITEM=$(echo ${ITEM} | sed 's/!space!/ /g')
                                ARTICLE=$(echo ${ITEM} | awk -F\; '{print $2}')
                                ARTICLE_LINK=$(echo ${ITEM} | awk -F\; '{print $3}')
                                echo "      * Article: ${CYAN}${ARTICLE}${NORMAL}: ${ARTICLE_LINK}"
                            done
                        fi
                    fi
                    if [ -z "${IS_CUSTOM}" ]; then
                        echo "      * Website: ${GRAY}${CONTROL_URL_PROTOCOL}://${CONTROL_URL_PREPEND}${ADDLINK}${CONTROL_URL_APPEND}${NORMAL}"
                    else
                        echo "      * Details: ${GRAY}${CUSTOM_URL_PROTOCOL}://${CUSTOM_URL_PREPEND}${ADDLINK}${CUSTOM_URL_APPEND}${NORMAL}"
                    fi
                    echo ""
                done
            fi
            # Show tip on how to continue (next steps)
            if [ ! "${SWARNINGS}" = "" -o ! "${SUGGESTIONS}" = "" ]; then
                echo "  ${CYAN}Follow-up${NORMAL}:"
                echo "  ${WHITE}----------------------------${NORMAL}"
                echo "  ${WHITE}-${NORMAL} Show details of a test (lynis show details TEST-ID)"
                echo "  ${WHITE}-${NORMAL} Check the logfile for all details (less ${LOGFILE})"
                echo "  ${WHITE}-${NORMAL} Read security controls texts (https://cisofy.com)"
                if [ ${UPLOAD_DATA} -eq 0 ]; then echo "  ${WHITE}-${NORMAL} Use --upload to upload data to central system (Lynis Enterprise users)"; fi
                echo ""
            fi
            echo "================================================================================"
            echo ""
            echo "  ${WHITE}Lynis security scan details${NORMAL}:"
            echo ""
            echo "  ${SECTION}Scan mode${NORMAL}:"
            if [ ${DEVOPS_MODE} -eq 1 ]; then
                echo "  Normal [ ]  Forensics [ ]  Integration [▆]  Pentest [ ]"
            elif [ ${FORENSICS_MODE} -eq 1 ]; then
                echo "  Normal [ ]  Forensics [▆]  Integration [ ]  Pentest [ ]"
            elif [ ${PENTESTINGMODE} -eq 1 ]; then
                if [ ${PRIVILEGED} -eq 0 ]; then
                    echo "  Normal [ ]  Forensics [ ]  Integration [ ]  Pentest [▆] (running non-privileged)"
                else
                    echo "  Normal [ ]  Forensics [ ]  Integration [ ]  Pentest [▆] (running privileged)"
                fi
            else
                echo "  Normal [▆]  Forensics [ ]  Integration [ ]  Pentest [ ]"
            fi
            echo ""

            echo "  ${SECTION}Lynis modules${NORMAL}:"
            if [ ${COMPLIANCE_TESTS_PERFORMED} -eq 1 ]; then
                if [ ${COMPLIANCE_FINDINGS_FOUND} -eq 0 ]; then COMPLIANCE="${GREEN}V"; else COMPLIANCE="${RED}X"; fi
            else
                COMPLIANCE="${YELLOW}?"
            fi
            echo "  - Compliance status      [${COMPLIANCE}${NORMAL}]"
            echo "  - Security audit         [${GREEN}V${NORMAL}]"
            echo "  - Vulnerability scan     [${GREEN}V${NORMAL}]"
            echo ""
            echo "  ${SECTION}Details${NORMAL}:"
            echo "  ${CYAN}Hardening index${NORMAL} : ${WHITE}${HPINDEX}${NORMAL} ${HPGRAPH}"
            echo "  ${CYAN}Tests performed${NORMAL} : ${WHITE}${CTESTS_PERFORMED}${NORMAL}"
            if [ ${SKIP_PLUGINS} -eq 0 ]; then
                echo "  ${CYAN}Plugins enabled${NORMAL} : ${WHITE}${N_PLUGIN_ENABLED}${NORMAL}"
            else
                echo "  ${CYAN}Plugins enabled${NORMAL} : ${WHITE}Skipped${NORMAL}"
            fi
            echo ""
            echo "  ${SECTION}Software components${NORMAL}:"
            if [ ${FIREWALL_ACTIVE} -eq 1 ]; then FIREWALL="${GREEN}V"; else FIREWALL="${RED}X"; fi
            if [ ${MALWARE_SCANNER_INSTALLED} -eq 1 ]; then MALWARE="${GREEN}V"; else MALWARE="${RED}X"; fi
            if [ ${IDS_IPS_TOOL_FOUND} -eq 1 ]; then IDSIPS="${GREEN}V"; else IDSIPS="${RED}X"; fi

            echo "  - Firewall               [${FIREWALL}${NORMAL}]"
            #echo "  - Integrity monitoring   [${IDSIPS}${NORMAL}]"
            echo "  - Intrusion software     [${IDSIPS}${NORMAL}]"
            echo "  - Malware scanner        [${MALWARE}${NORMAL}]"

            echo ""
            echo "  ${SECTION}Files${NORMAL}:"
            echo "  - Test and debug information      : ${WHITE}${LOGFILE}${NORMAL}"
            echo "  - Report data                     : ${WHITE}${REPORTFILE}${NORMAL}"
            echo ""
            echo "================================================================================"
            if [ ${PROGRAM_LV} -gt ${PROGRAM_AC} ]; then
                echo "  ${NOTICE}Notice: ${WHITE}${PROGRAM_NAME} ${GEN_UPDATE_AVAILABLE}${NORMAL}"
                echo "  ${GEN_CURRENT_VERSION} : ${WHITE}${PROGRAM_AC}${NORMAL}    ${GEN_LATEST_VERSION} : ${WHITE}${PROGRAM_LV}${NORMAL}"
                echo "================================================================================"
            else
                if [ ${OLD_RELEASE} -eq 1 ]; then
                    echo ""
                    echo "  ${NOTICE}Notice: ${WHITE}This version of ${PROGRAM_NAME} is older than 6 months and might be outdated. Check the project page if a newer version is available.${NORMAL}"
                    echo ""
                echo "================================================================================"
                fi 
                ###########################################################################################
                #
                # Software quality program
                # Only provide this hint when the tool is at the latest version
                #
                ###########################################################################################

                if [ ! "${PROGRAM_LV}" = "0" -a ! "${REPORTFILE}" = "" -a ! "${REPORTFILE}" = "/dev/null" ]; then

                    # Determine if the quality of the program can be increased by filtering out the exceptions
                    FIND=$(${GREPBINARY} "^exception" ${REPORTFILE})
                    if [ -n "${FIND}" ]; then
                        echo ""
                        echo "  ${RED}${NOTE_EXCEPTIONS_FOUND}${NORMAL}"
                        echo "  ${WHITE}${NOTE_EXCEPTIONS_FOUND_DETAILED}!${NORMAL}"
                        echo ""
                        echo "  ${CYAN}${GEN_WHAT_TO_DO}:${NORMAL}"
                        echo "  ${TEXT_YOU_CAN_HELP_LOGFILE} (${LOGFILE})."
                        echo "  Go to https://cisofy.com/contact/ and send your file to the e-mail address listed"
                        echo ""
                        echo "================================================================================"
                    fi
                fi

                # If end-of-life check failed, ask to submit
                if [ ! "${PROGRAM_LV}" = "0" -a ${EOL} -eq 255 ]; then
                    echo ""
                    echo "  ${SECTION}Notice: ${WHITE}No OS entry was found in the end-of-life database${NORMAL}"
                    echo ""
                    echo "  ${CYAN}${GEN_WHAT_TO_DO}:${NORMAL}"
                    echo "  Please submit a pull request on GitHub to include your OS version and the end date of this OS version is being supported"
                    echo "  URL: ${PROGRAM_SOURCE}"
                    echo ""
                    echo "================================================================================"
                fi 
            fi

            # Display what tests are skipped in non-privileged scan for awareness
            if [ ${PENTESTINGMODE} -eq 1 -a ! "${SKIPPED_TESTS_ROOTONLY}" = "" ]; then
                echo ""
                echo "  ${PURPLE}${NOTE_SKIPPED_TESTS_NON_PRIVILEGED}:${NORMAL}"
                echo ""
                FIND=$(echo ${SKIPPED_TESTS_ROOTONLY} | sed 's/ /:space:/g')
                # Split entries
                FIND=$(echo ${FIND} | sed 's/====/ /g')
                # Display found entries
                for ITEM in ${FIND}; do
                    OUTPUT=$(echo ${ITEM} | sed 's/:space:/ /g')
                    echo "    ${OUTPUT}"
                done
                echo ""
                echo "================================================================================"
            fi

            echo ""
        fi

    fi

    # Report data, even if it is not displayed on screen
    Report "hardening_index=${HPINDEX}"

    if [ ${QUIET} -eq 0 ]; then
        echo "  ${WHITE}${PROGRAM_NAME}${NORMAL} ${PROGRAM_VERSION}"
        echo ""
        echo "  Auditing, system hardening, and compliance for UNIX-based systems"
        echo "  (Linux, macOS, BSD, and others)"
        echo ""
        echo "  ${PROGRAM_COPYRIGHT}"
        echo "  ${WHITE}${PROGRAM_EXTRAINFO}${NORMAL}"
        echo ""
        echo "================================================================================"
    fi

# EOF
