#!/bin/sh

echo "KIS for Mac 20.0 - Patch C"

KAV_DIR="/Library/Application Support/Kaspersky Lab/KAV"
KAV_BINARIES_DIR="$KAV_DIR/Binaries"
KAV_DATA_DIR="$KAV_DIR/Data"
KAV_APP_PKG="$KAV_DATA_DIR/kav_app.tar.gz"
KAV_AGENT_PKG="$KAV_DATA_DIR/kav_agent.tar.gz"
KAV_UPDATE_PKG="$KAV_DATA_DIR/kav_update.tar.gz"
KAV_UNINSTALLER_PKG="$KAV_DATA_DIR/kav_uninstaller.tar.gz"
DRIVERS_PKG_DIR="$KAV_DATA_DIR"
DRIVERS_CACHE_DIR="$KAV_DIR/Bases/Cache"
BASES_KLAVA_DIR="$KAV_DIR/Bases/KLAVA"
KAV_AGENT_APP_PATH="$KAV_DIR/Applications/Kaspersky Anti-Virus Agent.app"
KAV_UPDATE_APP_PATH="$KAV_DIR/Applications/Kaspersky Anti-Virus Update.app"
KAV_UNINSTALLER_APP_PATH="$KAV_DIR/Applications/Kaspersky Uninstaller.app"
KAV_AGENT_WATCHPATH="$KAV_DIR/kickstart_gui"
LAUNCHAGENT_KAV_PLIST="/Library/LaunchAgents/com.kaspersky.kav.gui.plist"
DEFAULT_KAVAPP_PATH="/Applications/Kaspersky Anti-Virus For Mac.app"
LOC_TGZ="$KAV_DATA_DIR/loc.tar.gz"
LOC_DIR="$KAV_DIR/Loc"
DOC_TGZ="$KAV_DATA_DIR/doc.tar.gz"
DOC_DIR="$KAV_DIR/Doc"
CONFIG_XML_CHANGES_TMP="/tmp/kav_config_xml_changes"

UPDATE_CFG_SCRIPT="$KAV_BINARIES_DIR/update_cfg.pl"
UPDATE_CFG_TARGET="$KAV_BINARIES_DIR/config.xml"
UPDATE_CFGPDKESM_TARGET="$KAV_BINARIES_DIR/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
}

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
}

if [ "$1" != "OnHotfixInstalled" ]; then
    PRODUCT_TYPE=$(get_environment_key "ProductType")
    echo "ProductType:      $PRODUCT_TYPE"
    REGION_TYPE=$(get_environment_key "ProductRegion")
    echo "ProductRegion:    $REGION_TYPE"
    MATCHED_ARCHIVE="${PRODUCT_TYPE}_${REGION_TYPE}".tar.gz
    echo "Matched archive:  $MATCHED_ARCHIVE"

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

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

    if [ "$KAV_APP_PKG" != "" ]
    then
        LAST_PATCH_DEPLOYMENT_TIMESTAMP=$(get_last_patch_deployment)
        KAV_APP_PKG_TIMESTAMP=$(stat -f "%m" "$KAV_APP_PKG")
        echo "kav app pkg timestamp: $KAV_APP_PKG_TIMESTAMP, last path deployment timestamp: $LAST_PATCH_DEPLOYMENT_TIMESTAMP"

        if [[ (-e "$KAV_APP_PKG") && ($KAV_APP_PKG_TIMESTAMP > $LAST_PATCH_DEPLOYMENT_TIMESTAMP) ]]; then
            KAV_APP_EXTRACTION_TEMP_PATH=$(mktemp -d)
            echo ""
            echo "Extracting $KAV_APP_PKG into $KAV_APP_EXTRACTION_TEMP_PATH"
            tar -xzvf "$KAV_APP_PKG" -C "$KAV_APP_EXTRACTION_TEMP_PATH"
            echo "Extracted: "
            ls -la "$KAV_APP_EXTRACTION_TEMP_PATH"

    		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 ""

                if [ -f "$KAV_APP_EXTRACTION_TEMP_PATH/$MATCHED_ARCHIVE" ]; then
                    CURRENT_KAV_APP_EXTRACTION_TEMP_PATH=$(mktemp -d)
                    echo "Extracting application resources from $MATCHED_ARCHIVE to $CURRENT_KAV_APP_EXTRACTION_TEMP_PATH..."
                    tar -xzvf "$KAV_APP_EXTRACTION_TEMP_PATH/$MATCHED_ARCHIVE" -C "$CURRENT_KAV_APP_EXTRACTION_TEMP_PATH"
                    cp -Rfv "$CURRENT_KAV_APP_EXTRACTION_TEMP_PATH"/ "$KAVAPP_PATH"
                    touch "$KAVAPP_PATH"
                else
                    echo "No matched archive in $KAV_APP_EXTRACTION_TEMP_PATH, do not apply patch for $KAVAPP_PATH"
                fi
    		done
    		IFS="$OLD_IFS"

    		echo ""
    		echo "Stopping application..."
    		stop_kav_app
    	fi
    else
        echo ""
        echo "KAV app pkg path is empty"
    fi

    if [ "$KAV_AGENT_PKG" != "" ]
    then
        LAST_PATCH_DEPLOYMENT_TIMESTAMP=$(get_last_patch_deployment)
        KAV_AGENT_PKG_TIMESTAMP=$(stat -f "%m" "$KAV_AGENT_PKG")
        echo "kav app pkg timestamp: $KAV_AGENT_PKG_TIMESTAMP, last path deployment timestamp: $LAST_PATCH_DEPLOYMENT_TIMESTAMP"

        if [[ (-e "$KAV_AGENT_PKG") && ($KAV_AGENT_PKG_TIMESTAMP > $LAST_PATCH_DEPLOYMENT_TIMESTAMP) ]];
    	then
            KAV_AGENT_EXTRACTION_TEMP_PATH=$(mktemp -d)
    		echo ""
    		echo "Extracting agent resources to $KAV_AGENT_EXTRACTION_TEMP_PATH..."
    		tar -xzvf "$KAV_AGENT_PKG" -C "$KAV_AGENT_EXTRACTION_TEMP_PATH"
            echo "Extracted: "
            ls -la "$KAV_AGENT_EXTRACTION_TEMP_PATH"

            echo ""
            echo "Deploying agent resources..."

            if [ -f "$KAV_AGENT_EXTRACTION_TEMP_PATH/$MATCHED_ARCHIVE" ]; then
                CURRENT_KAV_AGENT_EXTRACTION_TEMP_PATH=$(mktemp -d)
                echo "Extracting application resources from $MATCHED_ARCHIVE to $CURRENT_KAV_AGENT_EXTRACTION_TEMP_PATH..."
                tar -xzvf "$KAV_AGENT_EXTRACTION_TEMP_PATH/$MATCHED_ARCHIVE" -C "$CURRENT_KAV_AGENT_EXTRACTION_TEMP_PATH"
                cp -Rfv "$CURRENT_KAV_AGENT_EXTRACTION_TEMP_PATH"/ "$KAV_AGENT_APP_PATH"
                touch "$KAV_AGENT_APP_PATH"
            else
                echo "No matched archive in $KAV_AGENT_EXTRACTION_TEMP_PATH, do not apply patch for $KAV_AGENT_APP_PATH"
            fi

    		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
    else
        echo ""
        echo "KAV agent pkg path is empty"
    fi

    echo ""
    echo "Updating config.xml"

    SEARCH_RESULT=$(grep "WebVisitorId" "$UPDATE_CFG_TARGET")
    if [ ! -z "$SEARCH_RESULT" ];
    then
        echo "Found WebVisitorId, skip adding"
    else
        echo "Adding WebVisitorId field with 0 value"
        touch "$CONFIG_XML_CHANGES_TMP"
        echo "environment WebVisitorId 0" >> "$CONFIG_XML_CHANGES_TMP"
    fi

    SEARCH_RESULT=$(grep "VirusLink.*viruslist" "$UPDATE_CFG_TARGET")
    if [ ! -z "$SEARCH_RESULT" ];
    then
        echo "Found old virus link, updating it"
        touch "$CONFIG_XML_CHANGES_TMP"
        echo "environment VirusLink https://click.kaspersky.com/?hl=[Localization]&amp;customization=[RebrandingCode]&amp;link=VirusLink&amp;syst=[OsVersion]&amp;pid=kismac&amp;version=[ApplicationVersion]&amp;hotfix=[GlobalProductHotfix]" >> "$CONFIG_XML_CHANGES_TMP"
    else
        echo "No changes in VirusLink"
    fi

    echo "printing $CONFIG_XML_CHANGES_TMP"
    cat "$CONFIG_XML_CHANGES_TMP"

    echo ""
    echo "Updating configpdk.esm"

    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=\"libbl.dylib\">\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

else
    LAST_PATCH_DEPLOYMENT_TIMESTAMP=$(get_last_patch_deployment)
    
    echo ""
    echo "Last path deployment timestamp: $LAST_PATCH_DEPLOYMENT_TIMESTAMP"
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"
}

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

chmod -R o+r "/Library/Application Support/Kaspersky Lab/KAV/Bases/"

rm -rfv /Library/Caches/com.kaspersky.kav/PersonalCertificates/*

echo "Deleting Cert directory..."
rm -rfv "/Library/Application Support/Kaspersky Lab/KAV/Data/Cert"

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*
