#!/bin/sh

#################################################################################
#
#   Lynis
# ------------------
#
# Copyright 2007-2013, Michael Boelen
# Copyright 2007-2017, 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 support automatic updates of Lynis
#
######################################################################
#
# Options:
# ---------
# 1) lynis update info     - Show version information (external)
# 2) lynis update release  - Check and install new release (internal)
#
# How to use:
# ------------
# Run option 1 to know about current and latest release information.
# Run option 2 to query internal server for possible upgrade of Lynis.
#
# Steps for updating to new release:
# 1) Run Lynis with: lynis update release
# 2) Lynis will use this helper and check the profile
# 3) The configured web server will be queried (lynis-latest-version)
# 4) The contents of this file will be compared with a local file
# 5) If there is a difference, download package
# 6) Check paths and extract files
# 7) Quit program
#
# Suggested documentation if you want to use this functionality:
# https://cisofy.com/documentation/lynis/upgrading/
#
######################################################################

LOCAL_VERSION="-"
RUN_UPDATE_CHECK=1
SERVER_VERSION=""
PERFORM_UPGRADE=0
QUIET=0

WGET_EXISTS=`which wget 2> /dev/null`
CURL_EXISTS=`which curl 2> /dev/null`
FETCH_EXISTS=`which fetch 2> /dev/null`

# Update version
if [ "$1" = "release" ]; then

    if [ "${UPDATE_SERVER_PROTOCOL}" = "" ] ; then
        ${ECHOCMD} "Error: Unknown protocol, please specify (http, https) in profile (update_server_protocol)"
        ExitFatal
    fi

    if [ "${UPDATE_SERVER_ADDRESS}" = "" ] ; then
        ${ECHOCMD} "Error: Unknown download address, please specify in profile (update_server_address)"
        ExitFatal
    fi

    if [ "${UPDATE_LATEST_VERSION_DOWNLOAD}" = "" ] ; then
        ${ECHOCMD} "Error: No URL to latest download has been specifiedrsion on the server, please specify in profile (update_latest_version_download)"
        ExitFatal
    fi

    if [ "${UPDATE_LATEST_VERSION_INFO}" = "" ] ; then
        ${ECHOCMD} "Error: No URL has been specified to know the latest version on the server, please specify in profile (update_latest_version_info)"
        ExitFatal
    fi

    if [ "${UPDATE_LOCAL_DIRECTORY}" = "" ] ; then
        ${ECHOCMD} "Error: No local directory has been specified to store Lynis files. Please specify in profile (update_local_directory)"
        ExitFatal
      else
        if [ ! -d ${UPDATE_LOCAL_DIRECTORY} ]; then
            ${ECHOCMD} "Error: Directory ${UPDATE_LOCAL_DIRECTORY} does not exist"
            ExitFatal
        fi
    fi

    if [ "${UPDATE_LOCAL_VERSION_INFO}" = "" ] ; then
        ${ECHOCMD} "Error: No data file has been specified to determine local Lynis version, please specify in profile (update_local_version_info)"
        ExitFatal
    fi

    if [ ! -f ${UPDATE_LOCAL_VERSION_INFO} ]; then
        ${ECHOCMD} "Note: local data file ${UPDATE_LOCAL_VERSION_INFO} does not exist. It will be created after updating. (update_local_version_info)"
      else
        LOCAL_VERSION=`cat ${UPDATE_LOCAL_VERSION_INFO}`
    fi

    # Normal update
    FULLPATH="${UPDATE_SERVER_PROTOCOL}://${UPDATE_SERVER_ADDRESS}${UPDATE_LATEST_VERSION_INFO}"

    # Create temporary file
    CreateTempFile
    TMP_FILE="${TEMP_FILE}"
    if [ "${TMP_FILE}" = "" ]; then ${ECHOCMD} "Could not create a temporary file. Exiting..."; ExitFatal; fi

    ${ECHOCMD} "${CYAN}[Phase 1] Downloading details${NORMAL}"
    if [ ! "${WGET_EXISTS}" = "" ]; then
        LogText "Using wget to download release information"
        LAST_COMMAND_HELP="wget --output-document ${TMP_FILE} ${FULLPATH}"
        wget --output-document ${TMP_FILE} ${FULLPATH} 2> /dev/null
        EXIT_CODE=$?
    elif [ ! "${CURL_EXISTS}" = "" ]; then
        LogText "Using curl to download release information"
        LAST_COMMAND_HELP="curl --fail -o ${TMP_FILE} ${FULLPATH}"
        curl --fail -o ${TMP_FILE} ${FULLPATH} 2> /dev/null
        EXIT_CODE=$?
    else
        ${ECHOCMD} "No download tool available to perform download"
        ExitFatal
    fi

    if [ ! "${TMP_FILE}" = "" ]; then
        if [ -f ${TMP_FILE} ]; then
            SERVER_VERSION=`cat ${TMP_FILE}`
            rm -f ${TMP_FILE}
        fi
      else
        ${ECHOCMD} "Temporary file variable is empty, which is unexpected. Aborting.."
        ExitFatal
    fi

    # Determine if downloading meta data was successful
    if [ ${EXIT_CODE} -eq 0 ]; then
        if [ "${SERVER_VERSION}" = "" ]; then
            ${ECHOCMD} "No version found on the server. Aborting.."
            ExitFatal
          else
            ${ECHOCMD} "Version found on server: ${SERVER_VERSION}"
            ${ECHOCMD} "Local version found: ${LOCAL_VERSION}"
        fi
      else
        ${ECHOCMD} "${RED}Error: ${WHITE}Download utility returned an unexpected error code.${NORMAL} Aborting.."
        ${ECHOCMD} "Error code: ${EXIT_CODE}"
        ${ECHOCMD} "Suggested command: ${LAST_COMMAND_HELP}"
        ExitFatal
    fi

#==========================================================================================================================================

    ${ECHOCMD} " "
    ${ECHOCMD} "${CYAN}[Phase 2] Compare results${NORMAL}"
    if [ ! "${LOCAL_VERSION}" = "${SERVER_VERSION}" ]; then
        ${ECHOCMD} "Different version available, moving to upgrade phase"
        PERFORM_UPGRADE=1
      else
        ${ECHOCMD} "${GREEN}No upgrade needed${NORMAL}"
    fi

    # Go to phase 3 if upgrade is needed
    if [ ${PERFORM_UPGRADE} -eq 1 ]; then
        FULLPATH="${UPDATE_SERVER_PROTOCOL}://${UPDATE_SERVER_ADDRESS}${UPDATE_LATEST_VERSION_DOWNLOAD}"
        ${ECHOCMD} " "
        ${ECHOCMD} "[Phase 3] Downloading latest release"
        ${ECHOCMD} "Download location: ${FULLPATH}"
        if [ ! "${WGET_EXISTS}" = "" ]; then
            LogText "Using wget to download latest release"
            LAST_COMMAND_HELP="wget --output-document ${TMP_FILE} ${FULLPATH}"
            wget --output-document ${TMP_FILE} ${FULLPATH} 2> /dev/null
            EXIT_CODE=$?
        elif [ ! "${CURL_EXISTS}" = "" ]; then
            LogText "Using curl to download latest release"
            LAST_COMMAND_HELP="curl --fail -o ${TMP_FILE} ${FULLPATH}"
            curl --fail -o ${TMP_FILE} ${FULLPATH} 2> /dev/null
            EXIT_CODE=$?
        fi
        if [ ${EXIT_CODE} -eq 0 ]; then
            if [ -f ${TMP_FILE} ]; then
                ${ECHOCMD} "Download successful"
                # Extract the file to the related path, with 'lynis' appended
                # Note: by default the tarball includes 'lynis' as directory
                if [ ! -d ${UPDATE_LOCAL_DIRECTORY} ]; then
                    ${ECHOCMD} "Error: directory ${UPDATE_LOCAL_DIRECTORY} does not exist"
                    ExitFatal
                fi
                ${ECHOCMD} "Extracting latest version to path ${UPDATE_LOCAL_DIRECTORY}"
                if [ ! -d ${UPDATE_LOCAL_DIRECTORY}/lynis ]; then
                    ${ECHOCMD} "Creating 'lynis' directory in ${UPDATE_LOCAL_DIRECTORY}"
                    mkdir ${UPDATE_LOCAL_DIRECTORY}/lynis
                    if [ $? -gt 0 ]; then
                        ${ECHOCMD} "Error: could not create directory ${UPDATE_LOCAL_DIRECTORY}/lynis"
                        ExitFatal
                    fi
                fi
                if [ -d ${UPDATE_LOCAL_DIRECTORY}/lynis ]; then
                    ${ECHOCMD} "Extracting files to ${UPDATE_LOCAL_DIRECTORY}"
                    tar xzf ${TMP_FILE} -C ${UPDATE_LOCAL_DIRECTORY}
                    if [ $? -eq 0 ]; then
                        # Check if we can find the Lynis binary (in the created 'lynis' directory)
                        if [ -f ${UPDATE_LOCAL_DIRECTORY}/lynis/lynis ]; then
                            # If version was downloaded, update local version
                            echo ${SERVER_VERSION} > ${UPDATE_LOCAL_VERSION_INFO}
                          else
                            ${ECHOCMD} "Error: could not find downloaded file on disk"
                        fi
                      else
                        ${ECHOCMD} "Error: File extraction failed"
                        ExitFatal
                    fi
                  else
                    ${ECHOCMD} "Error: could not find lynis directory"
                fi
              else
              ${ECHOCMD} "Error: could not find downloaded file on disk"
              ExitFatal
            fi
          else
            ${ECHOCMD} "Error: could not download latest release"
            ${ECHOCMD} "Suggestion: ${LAST_COMMAND_HELP}"
            ExitFatal
        fi
    fi

    # Removing temp file
    LogText "Action: Removing temporary file ${TMP_FILE}"
    if [ "${TMP_FILE}" = "" ]; then
        if [ -f ${TMP_FILE} ]; then
            rm -f ${TMP_FILE}
        fi
    fi

    ${ECHOCMD} " "
    ${ECHOCMD} "Done"
    ${ECHOCMD} " "

# Update check
elif [ "$1" = "info" ]; then

        # CV - Current Version
        PROGRAM_AC=`echo ${PROGRAM_VERSION} | awk '{ print $1 }' | sed 's/[.]//g'`
        PROGRAM_LV=0

        CheckUpdates

        # Reset everything if we can't determine our current version or the latest
        # available version (due lack of internet connectivity for example)
        if [ "${PROGRAM_AC}" = "" -o "${PROGRAM_LV}" = "" ]; then
            # Set both to safe values
            PROGRAM_AC=0; PROGRAM_LV=0
        fi

        echo ""; echo " == ${WHITE}${PROGRAM_NAME}${NORMAL} =="
        echo ""
        echo "  Version            : ${PROGRAM_VERSION}"
        echo -n "  Status             : "
        if [ ${PROGRAM_LV} -eq 0 ]; then
            echo "${RED}Unknown${NORMAL}";
          elif [ ${PROGRAM_LV} -gt ${PROGRAM_AC} ]; then
            echo "${YELLOW}Outdated${NORMAL}";
            echo "  Installed version  : ${PROGRAM_AC}"
            echo "  Latest version     : ${PROGRAM_LV}"
          else
            echo "${GREEN}Up-to-date${NORMAL}"
        fi
        echo "  Release date       : ${PROGRAM_RELEASE_DATE}"
        echo "  Update location    : ${PROGRAM_WEBSITE}"
        echo ""; echo ""
        echo "${PROGRAM_COPYRIGHT}"
        echo ""

# Check if there is an update, display status on screen and use exit code to tell status as well
elif [ "$1" = "check" ]; then
        # CV - Current Version, LV - Latest Version
        PROGRAM_CV=$(echo ${PROGRAM_VERSION} | awk '{ print $1 }' | sed 's/[.]//g')
        PROGRAM_LV=0
        CheckUpdates
        if [ "${PROGRAM_CV}" = "" -o "${PROGRAM_LV}" = "" ]; then PROGRAM_AC=0; PROGRAM_LV=0; fi
        if [ ${PROGRAM_LV} -eq 0 ]; then
            echo "status=unknown";
            ExitCustom 1
        elif [ ${PROGRAM_LV} -gt ${PROGRAM_CV} ]; then
            echo "status=outdated";
            ExitCustom 1
        else
            echo "status=up-to-date"
            ExitClean
        fi

else
    ${ECHOCMD} "${RED}Error: ${WHITE}Unknown parameter $1.${NORMAL} Aborting.."
    ExitFatal
fi

ExitClean

QUIET=1

# The End
