Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added reregister flag and additional logging #108

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 201 additions & 33 deletions Bash/InstallHuntress-macOS-bash.sh
Original file line number Diff line number Diff line change
@@ -61,22 +61,172 @@ install_system_extension=false
## Do not modify anything below this line
##############################################################################

scriptVersion="August 15, 2024"
scriptVersion="November 22, 2024"

dd=$(date "+%Y%m%d-%H%M%S")
dd=$(date "+%Y-%m-%d %H:%M:%S")
log_file="/tmp/HuntressInstaller.log"
install_script="/tmp/HuntressMacInstall.sh"
invalid_key="Invalid account secret key"
pattern="[a-f0-9]{32}"
version="1.0"
version="1.1"

## Using logger function to provide helpful logs within RMM tools in addition to log file
# print help message
usage() {
cat <<EOF
Usage: $0 [options...] --account_key=<account_key> --organization_key=<organization_key>

-a, --account_key <account_key> The account key to use for this agent install
-o, --organization_key <organization_key> The org key to use for this agent install
-t, --tags <tags> A comma-separated list of agent tags
-i, --install_system_extension If passed, automatically install the system extension
-r, --reregister Attempt a clean slate install of Huntress (must also pass account and org keys)
-h, --help Print this message

EOF
}

# Using logger function to provide helpful logs within RMM tools in addition to log file
logger() {
echo "$dd -- $*";
echo "$dd -- $*" >> $log_file;
}

logger "Huntress install script last updated $scriptVersion"
# This is for machines where the Huntress install is corrupted, damaged, or missing assets.
# This will try to fully remove Huntress before attempting a reinstall
reregister() {
logger "Starting uninstall, please be aware this can take up to a minute"

countProcesses=$(ps aux | grep "HuntressAgent" -c)
if [ $countProcesses -le 1 ]; then
logger "Huntress process not running, System Extension may hang for a minute on uninstall"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason this message references the system extension specifically? Whether the Go agent (HuntressAgent) is running shouldn't have any effect on the removal of the extension. We'd need to check whether the Swift daemon (aka plain old Huntress) is running, since that's what's responsible for the extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was just something I noticed from testing. If I killed the Huntress processes before trying to remove the System Extension then the SE removal would pause for a period of time. I can adjust this to look for only plain Huntress instead.

fi

# skip trying to stop the services and file deletes if no assets are found to avoid clogging log with errors
installCheck=$(checkForAssets)
if [ $installCheck == 1 ]; then
uninstall_system_extension

cd "/Library/Application Support/Huntress/HuntressAgent"
logger "Stopping services"
/Applications/Huntress.app/Contents/MacOS/HuntressUpdater stop
/Applications/Huntress.app/Contents/MacOS/HuntressAgent stop
/Applications/Huntress.app/Contents/MacOS/Huntress daemonctl stop

logger "Running updater uninstall..."
/Applications/Huntress.app/Contents/MacOS/HuntressUpdater uninstall

logger "Running agent uninstall..."
/Applications/Huntress.app/Contents/MacOS/HuntressAgent uninstall

logger "Uninstalling GRPC daemon..."
/Applications/Huntress.app/Contents/MacOS/Huntress daemonctl uninstall

logger "Removing app directory..."
rm -rf /Applications/Huntress.app

logger "Removing support directory..."
rm -rf "/Library/Application Support/Huntress"
else
logger "Huntress assets not found on disk, no services to stop and no assets to delete. Script continuing..."
fi

pkgCheck=$(checkForPkg)
if [ $pkgCheck == 1 ]; then
logger "Forgetting package id..."
pkgutil --forget com.huntresslabs.pkg.agent 2>/dev/null
else
logger "Huntress pkg not found. Script continuing..."
fi

# wait timer for all components to finish uninstall before proceeding with install
sleep 3
logger "Uninstall complete, beginning reinstall"
}

# Uninstall the Huntress system extension
uninstall_system_extension() {
logger "Uninstalling system extension"
tmp_plist=/tmp/com.apple.system-extensions.admin.plist
tmp_plist_prev=/tmp/com.apple.system-extensions.admin.prev.plist

logger "Toggling system authorization settings..."
security authorizationdb read com.apple.system-extensions.admin > $tmp_plist
cp $tmp_plist $tmp_plist_prev

/usr/libexec/PlistBuddy -c "Set rule:0 is-root" $tmp_plist
security authorizationdb write com.apple.system-extensions.admin < $tmp_plist
evanburkeyhl marked this conversation as resolved.
Show resolved Hide resolved

logger "Uninstalling system extension..."
/Applications/Huntress.app/Contents/MacOS/Huntress extensionctl uninstall || echo "Uninstalling extension failed: error code $!"

logger "Restoring system authorization settings..."
security authorizationdb write com.apple.system-extensions.admin < $tmp_plist_prev
rm $tmp_plist $tmp_plist_prev

logger "Finished uninstalling system extension"
}

# return 1 if an existing Huntress install is detected, otherwise return 0
isHuntressInstalled() {
installCheck=$(checkForAssets)
pkgCheck=$(checkForPkg)
if [ $installCheck == 1 ]; then
echo 1
elif [ $pkgCheck == 1 ]; then
echo 1
else
echo 0
fi
}

# return 1 if Huntress assets are detected on disk, otherwise return 0
checkForAssets() {
if [ -d "/Library/Application Support/Huntress" ] || [ -d "/Applications/Huntress.app" ]; then
echo 1
else
echo 0
fi
}

#return 1 if Huntress pkg is registered, otherwise return 0
checkForPkg() {
pkgCheck=$(pkgutil --pkgs | grep "Huntress" -i)
if [[ -n $pkgCheck ]]; then
echo 1
else
echo 0
fi
}

# logging details about the machine for troubleshooting purposes
getMachineInfo() {
# uptime, free disk space, and OS version
logger "================================================================="
logger "============= Extra logging for troubleshooting ================="
logger $"Uptime: $(uptime)"
dfLines=$(df -H)
for df in dfLines; do
logger "$(df)"
done
logger "$(sw_vers)"

# get network connectivity data
logger "============================================================"
logger "============= Testing network connectivity ================="
for hostn in "update.huntress.io" "huntress.io" "eetee.huntress.io" "huntress-installers.s3.amazonaws.com" "huntress-updates.s3.amazonaws.com" "huntress-uploads.s3.us-west-2.amazonaws.com" "huntress-user-uploads.s3.amazonaws.com" "huntress-rio.s3.amazonaws.com" "huntress-survey-results.s3.amazonaws.com"; do
logger $(nc -z -v $hostn 443 2>&1)
done
}




# ====================================================================================
# =================================== Begin 'main' ===================================
# ====================================================================================

# Logging machine and script info for troubleshooting
getMachineInfo

# Check for root
if [ $EUID -ne 0 ]; then
@@ -86,31 +236,13 @@ fi

# Clean up any old installer scripts.
if [ -f "$install_script" ]; then
logger "Installer file present in /tmp; deleting."
logger "Installer script present in /tmp; deleting to ensure newest version is being used."
rm -f "$install_script"
fi

##
## This section handles the assigning `=` character for options.
## Since most RMMs treat spaces as delimiters in Mac Scripting,
## we have to use `=` to assign the option value, but must remove
## it because, well, bash. https://stackoverflow.com/a/28466267/519360
##

usage() {
cat <<EOF
Usage: $0 [options...] --account_key=<account_key> --organization_key=<organization_key>

-a, --account_key <account_key> The account key to use for this agent install
-o, --organization_key <organization_key> The org key to use for this agent install
-t, --tags <tags> A comma-separated list of agent tags
-i, --install_system_extension If passed, automatically install the system extension
-h, --help Print this message

EOF
}

while getopts a:o:h:t:-:i OPT; do
## This section handles the assigning `=` character for options. Since most RMMs treat spaces as delimiters in Mac Scripting,
## we have to use `=` to assign the option value, but must remove it because, well, bash. https://stackoverflow.com/a/28466267/519360
while getopts a:o:h:t:-:i:r OPT; do
if [ "$OPT" = "-" ]; then
OPT="${OPTARG%%=*}" # extract long option name
OPTARG="${OPTARG#$OPT}" # extract long option argument (may be empty)
@@ -132,6 +264,9 @@ while getopts a:o:h:t:-:i OPT; do
i | install_system_extension)
install_system_extension=true
;;
r | reregister)
reregister=true
;;
h | help)
usage
;;
@@ -146,8 +281,27 @@ while getopts a:o:h:t:-:i OPT; do
done
shift $((OPTIND-1)) # remove parsed options and args from $@ list

logger "=========== INSTALL START AT $dd ==============="
logger "=========== $rmm Deployment Script | Version: $version ==============="
logger "============= INSTALL START AT $dd ================="
logger "============= $rmm | Version: $version ================="
logger "============= Script last updated $scriptVersion ============="

# if the reregister flag is passed perform a full wipe and fresh install
if [ $reregister ]; then
logger "Reregister flag passed, attempting a clean install:"
if [ assetCheck == 1 ]; then
logger "Current contents of Huntress.app folder: $(ls '/Applications/Huntress.app/Contents/MacOS')"
logger "Current contents of Application Support folder: $(ls '/Library/Application Support/Huntress/HuntressAgent')"
fi
reregister
fi

# if Huntress is detected on the machine, exit the script with error
# reregister flag above should fully remove Huntress (for installing on top of an existing install)
assetCheck=$(isHuntressInstalled)
if [ $assetCheck == 1 ]; then
logger "Cannot proceed while Huntress is installed, suggest using the reregister flag"
exit 2
fi

# validate options passed to script, remove all invalid characters except spaces are converted to dash
if [ -z "$organization_key" ]; then
@@ -193,10 +347,12 @@ then
exit 1
fi


logger "Provided Huntress key: $masked"
logger "Provided Organization Key: $organizationKey"

logger "==========================================================="
logger "============= Downloading agent installer ================="

result=$(curl -w "%{http_code}" -L "https://huntress.io/script/darwin/$accountKey" -o "$install_script")

if [ $? != "0" ]; then
@@ -215,13 +371,25 @@ else
install_result="$(/bin/bash "$install_script" -a "$accountKey" -o "$organizationKey" -t "$tags" -v)"
fi

logger "=============== Begin Installer Logs ==============="
logger "========================================================"
logger "================= Begin Installer Logs ================="

if [ $? != "0" ]; then
logger "Installer Error: $install_result"
exit 1
fi

logger "$install_result"
logger "=========== INSTALL FINISHED AT $dd ==============="

registrationStatus=$(sudo cat "/Library/Application Support/Huntress/HuntressAgent/HuntressAgent.log" | head -n 2 | grep "Huntress agent registered" -i)
if [[ -n $registrationStatus ]]; then
echo "Agent successfully registered:"
echo $registrationStatus
else
logger "The agent wasn't able to register. Please check these articles and reach out to support if you get stuck"
logger "https://support.huntress.io/hc/en-us/articles/4411751045267-Network-Connectivity-and-Troubleshooting-Errors-Caused-by-Firewalls"
logger "https://support.huntress.io/hc/en-us/articles/4404005178771-Allow-List-Huntress-in-Third-Party-Security-Software-AV-NGAV-DR"
fi

logger "======================================================="
logger "============= INSTALL FINISHED AT $dd ================="
exit