#!/bin/sh

KAV_APP_PKG="/Library/Application Support/Kaspersky Lab/KAV/Data/kav_app.tar.gz"
DRIVERS_PKG_DIR="/Library/Application Support/Kaspersky Lab/KAV/Data"
DRIVERS_CACHE_DIR="/Library/Application Support/Kaspersky Lab/KAV/Bases/Cache"
BASES_KLAVA_DIR="/Library/Application Support/Kaspersky Lab/KAV/Bases/KLAVA"
KAV_DATA_DIR="/Library/Application Support/Kaspersky Lab/KAV/Data"
KAV_AGENT_PKG="/Library/Application Support/Kaspersky Lab/KAV/Data/kav_agent.tar.gz"
KAV_AGENT_APP_PATH="/Library/Application Support/Kaspersky Lab/KAV/Applications/Kaspersky Anti-Virus Agent.app"
KAV_AGENT_WATCHPATH="/Library/Application Support/Kaspersky Lab/KAV/kickstart_gui"
LAUNCHAGENT_KAV_PLIST="/Library/LaunchAgents/com.kaspersky.kav.gui.plist"
DEFAULT_KAVAPP_PATH="/Applications/Kaspersky Anti-Virus For Mac.app"
LOC_TGZ="/Library/Application Support/Kaspersky Lab/KAV/Data/loc.tar.gz"
LOC_DIR="/Library/Application Support/Kaspersky Lab/KAV/Loc"

UPDATE_CFG_SCRIPT="/Library/Application Support/Kaspersky Lab/KAV/Binaries/update_cfg.pl"
UPDATE_CFG_TARGET="/Library/Application Support/Kaspersky Lab/KAV/Binaries/config.xml"
UPDATE_CFGPDKESM_TARGET="/Library/Application Support/Kaspersky Lab/KAV/Binaries/configpdk.esm"


get_environment_key()
{
    python -c """
import xml.etree.ElementTree as ET
tree = ET.parse('$UPDATE_CFG_TARGET')
root = tree.getroot()
for node in root.findall(\".//key[@name='environment']\"):
    for childNode in node.findall(\".//tSTRING[@name='$1']\"):
        print(childNode.text)
    """
}

get_last_patch_deployment()
{
    python -c """
import xml.etree.ElementTree as ET
tree = ET.parse('$UPDATE_CFG_TARGET')
root = tree.getroot()
for node in root.findall(\".//key[@name='Timestamps']\"):
    for childNode in node.findall(\".//tDWORD[@name='LastPatchDeployment']\"):
        print(childNode.text)
    """
}

stop_kav_app()
{
	local KAVAPP_RECORD=$(ps -axwo pid,command | grep -v grep | grep "Contents/MacOS/kav_app")
	local KAVPID=$(/bin/echo -n "$KAVAPP_RECORD" | awk '{print $1}')
	if [ "$KAVPID" != "" ]
	then
		RELAUNCH_KAVAPP_PATH=$(/bin/echo -n "$KAVAPP_RECORD" | sed 's/[ ]*'"$KAVPID"'[ ]*\(.*\.app\).*/\1/')
		kill -s KILL "$KAVPID"
	fi
}

update_configxml()
{
    UPDATE_CFG_TARGET_copy="/tmp/config.xml.tmp1"

    echo "Updating Virus link value"
    awk '/\<tSTRING name=\"VirusLink\"\>/{print "        <tSTRING name=\"VirusLink\">https://click.kaspersky.com/?hl=[localization]&amp;customization=[RebrandingCode]&amp;link=VirusLink&amp;syst=[OsVersion]&amp;pid=[productType]mac&amp;version=[ApplicationVersion]&amp;hotfix=[GlobalProductHotfix]</tSTRING>";next}{print}' "$UPDATE_CFG_TARGET" > "$UPDATE_CFG_TARGET_copy"

    echo "Moving $UPDATE_CFG_TARGET_copy to $UPDATE_CFG_TARGET"
    mv -vf "$UPDATE_CFG_TARGET_copy" "$UPDATE_CFG_TARGET"
    rm -rfv "$UPDATE_CFG_TARGET_copy"
}

update_locs()
{
    if [ -e "$LOC_TGZ" ]
    then
        LOC_EXTRACTION_TEMP_PATH=$(mktemp -d)
        echo ""
        echo "Extracting $LOC_TGZ into $LOC_EXTRACTION_TEMP_PATH"
        tar -xzvf "$LOC_TGZ" -C "$LOC_EXTRACTION_TEMP_PATH"
        echo "Extracted: "
        ls -la "$LOC_EXTRACTION_TEMP_PATH"

        echo ""
        echo "Deploying localizations..."
        for LOC in $(ls "$LOC_EXTRACTION_TEMP_PATH")
        do
            if [ -d "$LOC_DIR"/"$LOC" ]
            then
                cp -Rfv "$LOC_EXTRACTION_TEMP_PATH"/"$LOC"/ "$LOC_DIR"/"$LOC"
            fi
        done
    fi
}

update_kavapp()
{
    LAST_PATCH_DEPLOYMENT_TIMESTAMP=$(get_last_patch_deployment)
    KAV_APP_PKG_TIMESTAMP=$(stat -f "%m" "$KAV_APP_PKG")

    if [[ (-e "$KAV_APP_PKG") && ($KAV_APP_PKG_TIMESTAMP > $LAST_PATCH_DEPLOYMENT_TIMESTAMP) ]]; then
    	echo ""
    	echo "Deploying application resources..."

    	KAVAPP_PATHS=$(mdfind "kMDItemCFBundleIdentifier == 'com.kaspersky.kav'" | grep -v "^/Volumes/")
    	if [ "$KAVAPP_PATHS" == "" ]
    	then
    		KAVAPP_PATHS="$DEFAULT_KAVAPP_PATH"
    	fi

    	OLD_IFS="$IFS"
    	IFS=$'\n'
    	for KAVAPP_PATH in $KAVAPP_PATHS
    	do
            echo ""
    		echo "Extracting application resources to $KAVAPP_PATH..."
    		tar -xzvf "$KAV_APP_PKG" -C "$KAVAPP_PATH"
    		touch "$KAVAPP_PATH"
    	done
    	IFS="$OLD_IFS"

    	echo ""
    	echo "Stopping application..."
    	stop_kav_app
    fi
}

update_agent()
{
    LAST_PATCH_DEPLOYMENT_TIMESTAMP=$(get_last_patch_deployment)
    KAV_AGENT_PKG_TIMESTAMP=$(stat -f "%m" "$KAV_AGENT_PKG")

    if [[ (-e "$KAV_AGENT_PKG") && ($KAV_AGENT_PKG_TIMESTAMP > $LAST_PATCH_DEPLOYMENT_TIMESTAMP) ]];
    then
    	echo ""
    	echo "Extracting agent resources to $KAV_AGENT_APP_PATH..."
    	tar -xzvf "$KAV_AGENT_PKG" -C "$KAV_AGENT_APP_PATH"
    	touch "$KAV_AGENT_APP_PATH"

    	echo ""
    	echo "Stopping agent..."
    	stop_kav_agent

    	if [ "$RESTART_KAVAGENT" == "1" ]
    	then
    		AGENTPID=$(ps -axwo pid,command | grep -v grep | grep "Contents/MacOS/kav_agent" | awk '{print $1}')
    		if [ "$AGENTPID" == "" ]
    		then
    			echo ""
    			echo "Restarting agent..."
    			LOGINWINDOW_RECORDS=$(ps -axwo pid,uid,command | grep -v grep | grep loginwindow)
    			for RECORD in "$LOGINWINDOW_RECORDS"
    			do
    				LOGINWINDOW_PID=$(/bin/echo -n "$RECORD" | awk '{print $1}')
    				LOGINWINDOW_UID=$(/bin/echo -n "$RECORD" | awk '{print $2}')
    				echo "Loading launch agent for uid $LOGINWINDOW_UID..."
    				launchctl asuser "$LOGINWINDOW_UID" launchctl load "$LAUNCHAGENT_KAV_PLIST"
    			done
    			echo "Kickstarting agent..."
    			touch "$KAV_AGENT_WATCHPATH"
    		fi
    	fi
    fi
}

update_configpdkesm()
{
    SEARCH_RESULT=$(grep "FullDiskAccessState" "$UPDATE_CFGPDKESM_TARGET")
    if [ ! -z "$SEARCH_RESULT" ];
    then
        echo "Found FullDiskAccessState in configpdk.esm, skip adding"
    else
        echo ""
        echo "Updating configpdk.esm"
        UPDATE_CFGPDKESM_TARGET_copy="/tmp/configpdk.esm.tmp"

        awk '/<\/root>/{print "    <component name=\"bl.FullDiskAccessState\" service_key=\"0x0e11a78a\" clsid=\"0x0e11a78a\" module=\"bl.ppl\">\n        <interface iid=\"0x2bf692ed\" name=\"bl.IFullDiskAccessState\" \/>\n        <interface iid=\"0x67b773e7\" name=\"bl.IFullDiskAccessStateEventsSubscription\" \/>\n    <\/component>"}1' "$UPDATE_CFGPDKESM_TARGET" > "$UPDATE_CFGPDKESM_TARGET_copy"

        echo "Moving $UPDATE_CFGPDKESM_TARGET_copy to $UPDATE_CFGPDKESM_TARGET"
        mv -vf "$UPDATE_CFGPDKESM_TARGET_copy" "$UPDATE_CFGPDKESM_TARGET"
    fi
}

stop_kav_agent()
{
	local KAVPID=$(ps -axwo pid,command | grep -v grep | grep "Contents/MacOS/kav_agent" | awk '{print $1}')
	if [ "$KAVPID" != "" ]
	then
		kill -s KILL $KAVPID
		RESTART_KAVAGENT=1
	fi
}

split_driver_version()
{
    local MAJOR=$(echo $1 | sed -n "s/\([0-9]*\).*/\1/p")
    local MINOR=$(echo $1 | sed -n "s/\([0-9]*\)\.\([0-9]*\).*/\2/p")
    local BUGFIX=$(echo $1 | sed -n "s/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\).*/\3/p")
    local STAGE=$(echo $1 | sed -n "s/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)\([a-z]*\).*/\4/p")
    local BUILD=$(echo $1 | sed -n "s/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)\([a-z]*\)\([0-9]*\)/\5/p")
    echo "$MAJOR $MINOR $BUGFIX $STAGE $BUILD"
}

get_driver_version_component()
{
    echo "$1" | cut -f $2 -d " "
}

get_driver_version_stage_priority()
{
    local PRIORITIZED_LIST=$(echo ":d"; echo ":a"; echo ":b"; echo ":fc"; echo ":")
    echo "$PRIORITIZED_LIST" | grep -n "^:$1" | sed "s/\([0-9]*\).*/\1/"
}

compare_driver_versions()
{
    V1=$(split_driver_version $1)
    V2=$(split_driver_version $3)

    N1=$(echo "$V1" | awk '{ print NF }')
    N2=$(echo "$V2" | awk '{ print NF }')

    local N
    if [ $N1 -gt $N2 ]; then
        N=$N1
    else
        N=$N2
    fi

    for i in `seq 1 $N`; do
	local NUMBER1=$(get_driver_version_component "$V1" $i);
	local NUMBER2=$(get_driver_version_component "$V2" $i);

	if [ $i -eq 4 ]; then
	    NUMBER1=$(get_driver_version_stage_priority ${NUMBER1})
	    NUMBER2=$(get_driver_version_stage_priority ${NUMBER2})
        fi

	if [ ${NUMBER1:=0} -ne ${NUMBER2:=0} ]; then
	    [ ${NUMBER1:=0} $2 ${NUMBER2:=0} ]
	    return
	fi
    done

    [ 0 $2 0 ]
}

update_driver()
{
    [ ! -f "$5/$3" ] && return 1

    DRIVER_REFERENCES_PATH="/Library/Application Support/Kaspersky Lab/Shared/$1.references"
    DRIVER_REFERENCES_LEGACY_PATH="$4/$1.kext/Contents/.References.plist"
    if [ "$4" == "/Library/Extensions" ] && [ -f "$DRIVER_REFERENCES_LEGACY_PATH" ] && [ ! -f "$DRIVER_REFERENCES_PATH" ]; then
	DRIVER_REFERENCES_DIR=$(dirname "$DRIVER_REFERENCES_PATH")
	mkdir -p "$DRIVER_REFERENCES_DIR"
	mv "$DRIVER_REFERENCES_LEGACY_PATH" "$DRIVER_REFERENCES_PATH" || return 1
    fi

    if [ "$4" == "/System/Library/Extensions" ] && [ -f "$DRIVER_REFERENCES_LEGACY_PATH" ]; then
	rm -rvf "$DRIVER_REFERENCES_LEGACY_PATH"
    fi

    DRIVER_PATH="$4/$1.kext"
    if [ -d "$DRIVER_PATH" ]; then
	INSTALLED_DRIVER_VERSION=$(/usr/libexec/PlistBuddy -c "Print :CFBundleVersion" "$DRIVER_PATH/Contents/Info.plist")
	compare_driver_versions $2 -gt $INSTALLED_DRIVER_VERSION || return 1
    fi

    rm -rvf "$DRIVER_PATH"
    tar -xzvf "$5/$3" -C "$4"
    chown -R root:wheel "$DRIVER_PATH"
    echo "Driver $1 updated to version $2"
}

update_drivers()
{
    echo "Updating drivers..."

    SHOULD_RESET_DRIVER_CACHE=0
    update_driver klif 3.6.15a55 klif.notarized.tar.gz /Library/Extensions "$DRIVERS_PKG_DIR" && SHOULD_RESET_DRIVER_CACHE=1
    update_driver klnke 2.4.7d10 klnke.notarized.tar.gz /Library/Extensions "$DRIVERS_PKG_DIR" && SHOULD_RESET_DRIVER_CACHE=1

    if [ "$SHOULD_RESET_DRIVER_CACHE" == "1" ]; then
        echo "Reseting driver cache..."
        touch "/Library/Extensions"
        /usr/sbin/kextcache -update-volume / -Installer -verbose 4 || (/usr/sbin/kextcache -system-prelinked-kernel && /usr/sbin/kextcache -invalidate /)
    fi
}

finishing_and_housekeeping()
{
    echo "Deleting Cert directory..."
    rm -rfv "/Library/Application Support/Kaspersky Lab/KAV/Data/Cert"
    
    chmod -R o+r "/Library/Application Support/Kaspersky Lab/KAV/Bases/"

    echo "Deleting kav crash logs"
    rm -rfv /Library/Logs/DiagnosticReports/kav_*
    echo "Deleting kav_app crash logs"
    rm -rfv ~/Library/Logs/DiagnosticReports/kav_app*
    echo "Deleting kav_agent crash logs"
    rm -rfv ~/Library/Logs/DiagnosticReports/kav_agent*
    echo "Deleting appex crash logs"
    rm -rfv ~/Library/Logs/DiagnosticReports/KasperskySecurity*
}

if [ "$1" != "OnHotfixInstalled" ]; then
    PRODUCT_TYPE=$(get_environment_key "ProductType")
    echo "ProductType = $PRODUCT_TYPE"

    if [ -f "$UPDATE_CFG_SCRIPT" ]
    then
    	echo ""
    	echo "Stopping application..."
    	stop_kav_app

    	echo ""
    	echo "Stopping possibly respawned application..."
    	stop_kav_app
    fi

    if [ "$LOC_TGZ" != "" ]
    then
        update_locs
    fi

    if [ "$KAV_APP_PKG" != "" ]
    then
        update_kavapp
    fi

    if [ "$KAV_AGENT_PKG" != "" ]
    then
        update_agent
    fi
else
    echo ""
    echo "Updating config.xml"
    update_configxml

    echo ""
    echo "Updating configpdk.esm"
    update_configpdkesm
fi

update_drivers
finishing_and_housekeeping
