#!/bin/bash
# @file      falcon-kernel-check
# @brief     Check if the host kernel supports CrowdStrike sensor.
#            Exit status:
#            0      if supported.
#            1      if not supported.
#            2      if error occurred.
# @version   13003
# @copyright CrowdStrike, Inc. CONFIDENTIAL AND PROPRIETARY
# @copyright CrowdStrike, Inc. Copyright (c) 2021. All rights reserved.

kernels="4.14.77-86.82.amzn2.aarch64\n4.14.88-88.73.amzn2.aarch64\n4.14.88-88.76.amzn2.aarch64\n4.14.94-89.73.amzn2.aarch64\n4.14.97-90.72.amzn2.aarch64\n4.14.101-91.76.amzn2.aarch64\n4.14.104-95.84.amzn2.aarch64\n4.14.106-97.85.amzn2.aarch64\n4.14.109-99.92.amzn2.aarch64\n4.14.114-103.97.amzn2.aarch64\n4.14.114-105.126.amzn2.aarch64\n4.14.121-109.96.amzn2.aarch64\n4.14.123-111.109.amzn2.aarch64\n4.14.128-112.105.amzn2.aarch64\n4.14.133-113.105.amzn2.aarch64\n4.14.133-113.112.amzn2.aarch64\n4.14.138-114.102.amzn2.aarch64\n4.14.143-118.123.amzn2.aarch64\n4.14.146-119.123.amzn2.aarch64\n4.14.146-120.181.amzn2.aarch64\n4.14.152-124.171.amzn2.aarch64\n4.14.152-127.182.amzn2.aarch64\n4.14.154-128.181.amzn2.aarch64\n4.14.158-129.185.amzn2.aarch64\n4.14.165-131.185.amzn2.aarch64\n4.14.165-133.209.amzn2.aarch64\n4.14.171-136.231.amzn2.aarch64\n4.14.173-137.228.amzn2.aarch64\n4.14.173-137.229.amzn2.aarch64\n4.14.177-139.253.amzn2.aarch64\n4.14.177-139.254.amzn2.aarch64\n4.14.181-140.257.amzn2.aarch64\n4.14.181-142.260.amzn2.aarch64\n4.14.186-146.268.amzn2.aarch64\n4.14.192-147.314.amzn2.aarch64\n4.14.193-149.317.amzn2.aarch64\n4.14.198-152.320.amzn2.aarch64\n4.14.200-155.322.amzn2.aarch64\n4.14.203-156.332.amzn2.aarch64\n4.14.209-160.335.amzn2.aarch64\n4.14.209-160.339.amzn2.aarch64\n4.14.214-160.339.amzn2.aarch64\n4.14.219-161.340.amzn2.aarch64\n4.14.219-164.354.amzn2.aarch64\n4.14.225-168.357.amzn2.aarch64\n4.14.225-169.362.amzn2.aarch64\n4.14.231-173.360.amzn2.aarch64\n4.14.231-173.361.amzn2.aarch64\n4.14.232-176.381.amzn2.aarch64\n4.14.238-182.421.amzn2.aarch64\n4.14.238-182.422.amzn2.aarch64\n4.19.58-21.57.amzn2.aarch64\n4.19.58-21.64.amzn2.aarch64\n4.19.66-22.57.amzn2.aarch64\n4.19.72-25.58.amzn2.aarch64\n4.19.75-27.58.amzn2.aarch64\n4.19.75-28.73.amzn2.aarch64\n4.19.82-30.69.amzn2.aarch64\n4.19.84-33.70.amzn2.aarch64\n5.4.20-12.75.amzn2.aarch64\n5.4.38-17.76.amzn2.aarch64\n5.4.46-19.75.amzn2.aarch64\n5.4.46-23.77.amzn2.aarch64\n5.4.50-25.83.amzn2.aarch64\n5.4.58-27.104.amzn2.aarch64\n5.4.58-32.125.amzn2.aarch64\n5.4.68-34.125.amzn2.aarch64\n5.4.74-36.135.amzn2.aarch64\n5.4.80-40.140.amzn2.aarch64\n5.4.91-41.139.amzn2.aarch64\n5.4.95-42.163.amzn2.aarch64\n5.4.105-48.177.amzn2.aarch64\n5.4.110-54.182.amzn2.aarch64\n5.4.110-54.189.amzn2.aarch64\n5.4.117-58.216.amzn2.aarch64\n5.4.129-62.227.amzn2.aarch64\n5.4.129-63.229.amzn2.aarch64\n"
sensor_version_number=13003

fuzzy_matching=0
matched=0
user_input=0
quiet=0

echo_stdout()
{
    msg=$1

    test $quiet -eq 0 && echo $msg
}

exit_usage()
{
    retval=$1

    echo "Usage: $(basename $0) [options]"
    echo "    -h print usage."
    echo "    -v print version."
    echo "    -k input kernel release to see if it is supported."
    echo "    -q quiet output."

    exit $retval
}

exit_supported()
{
    case $fuzzy_matching in
    0)
        echo_stdout "Host OS $uname is supported by Sensor version $sensor_version_number."
        ;;
    1)
        echo_stdout "Host OS $(uname -r) is supported (fuzzy matching $uname) by Sensor version $sensor_version_number."
        ;;
    *)
        echo "Internal error happened $fuzzy_matching" >&2
        exit 2
    esac
    exit 0
}

exit_nonsupported()
{
    echo "Host OS $(uname -srv) is not supported by Sensor version $sensor_version_number." >&2
    exit 1
}

exit_matched()
{
    _uname=$1

    if [ $quiet -eq 0 ]; then
        echo -n "$_uname matches:"
        test "$fuzzy_matching" -eq 1 && echo -n " (fuzzy kernel matching enabled)"
        echo
        echo -e "$kernels" | grep -E "^$_uname"
    fi

    exit 0
}

adjust_fuzzy_kernel_uname()
{
    _uname=$1

    if [ "$fuzzy_matching" -eq 1 ]; then
        while true; do
            _ver=$(echo $_uname | grep -oE 'el[678](_[[:digit:]]*)?')
            test -z $_ver && break
            _uname=$(echo $_uname | sed -e "s/${_ver}.*\.x86_64/${_ver}.x86_64/")
            break
        done
    fi

    echo $_uname
}

user_input_kernel()
{
    test -z "$1" && exit_usage 2

    _orig_uname=$1
    _uname=$(adjust_fuzzy_kernel_uname $1)
    _count=$(echo -e "$kernels" | grep -E "^$_uname" | wc -l)

    if [ $_count -eq 1 ]; then
        _matched=$(echo -e "$kernels" | grep -E "^$_uname")
        if [ "$_uname" = "$_matched" ]; then
            if [ "$_orig_uname" = "$_uname" ]; then
                echo_stdout "$_uname is supported by Sensor version $sensor_version_number."
            else
                echo_stdout "$_orig_uname is supported (fuzzy matching $_uname) by Sensor version $sensor_version_number."
            fi
            exit 0
        else
            exit_matched $_uname
        fi
    elif [ $_count -eq 0 ]; then
        echo "$_uname is not supported by Sensor version $sensor_version_number." >&2
        exit 1
    else
        exit_matched $_uname
    fi
}


for bin in "uname" "sed" "awk" "wc" "grep" "test" "[" "echo"; do
    if ! which $bin >/dev/null 2>&1; then
        echo "$bin does not exist."
        exit 2
    fi
done

while getopts mvhqk: opt; do
    case $opt in
        m)
            fuzzy_matching=1
            ;;
        v)
            echo $(basename $0) $sensor_version_number
            echo
            echo "CrowdStrike, Inc. Copyright (c) 2021. All rights reserved."
            exit 0
            ;;
        k)
            uname=$OPTARG
            user_input=1
            ;;
        h)
            exit_usage 0
            ;;
        q)
            quiet=1
            ;;
        *)
            exit_usage 2
            ;;
    esac
done

shift $(expr $OPTIND - 1)
test $# -eq 0 || exit_usage 2

test "$user_input" -eq 1 && user_input_kernel $uname

uname=$(uname -rv)
echo -e "$kernels" | grep -q "$uname" && exit_supported

uname="$(uname -r)"
test $(echo -e "$kernels" | grep "$uname" | wc -l) -gt 1 && exit_nonsupported

matched="$(echo -e "$kernels" | grep "$uname")"

test -n "$(echo "$matched" | awk '{print $2}')" && exit_nonsupported

test "$uname" = "$matched" && exit_supported

uname=$(adjust_fuzzy_kernel_uname $uname)
echo -e "$kernels" | grep -q $uname && exit_supported

exit_nonsupported
