From b324d31273d5f6e3cc0555c7f756f656111fe43d Mon Sep 17 00:00:00 2001 From: David Schroeder Date: Sat, 25 Jul 2026 16:39:46 -0500 Subject: [PATCH] update --- defaults.inc | 2 +- proxmenu-scripts.sh | 363 +++++++++++++++++++++++++++++++++++++------- 2 files changed, 306 insertions(+), 59 deletions(-) diff --git a/defaults.inc b/defaults.inc index 2897e59..5b8ec01 100755 --- a/defaults.inc +++ b/defaults.inc @@ -3,7 +3,7 @@ action="${1:-}" FOLDER='/opt/idssys/ta-proxmenu' -VERS='2026.7.25-28' +VERS='2026.7.25-29' noupdate=' ' diff --git a/proxmenu-scripts.sh b/proxmenu-scripts.sh index 1001d90..7ec57bb 100755 --- a/proxmenu-scripts.sh +++ b/proxmenu-scripts.sh @@ -14,6 +14,101 @@ FINISH_ACTION() { ENTER2CONTINUE } +FINISH_FAILED_ACTION() { + (( ACTION_REQUESTED == 1 )) && exit 1 + ENTER2CONTINUE +} + +declare -a TAPM_TEMP_DIRS=() +TAPM_TEMP_DIR='' + +TAPM_CLEAN_TEMP_DIR() { + local temp_dir="${1:-}" + + if [[ "$temp_dir" == /tmp/ta-proxmenu-* && -d "$temp_dir" ]]; then + rm -rf -- "$temp_dir" + fi +} + +TAPM_CLEAN_ALL_TEMP_DIRS() { + local temp_dir + + for temp_dir in "${TAPM_TEMP_DIRS[@]}"; do + TAPM_CLEAN_TEMP_DIR "$temp_dir" + done +} + +TAPM_CREATE_TEMP_DIR() { + local label="${1:-installer}" + + TAPM_TEMP_DIR="$(mktemp -d "/tmp/ta-proxmenu-${label}.XXXXXX")" || { + echo -e "${idsCL[LightRed]}Unable to create a temporary installer directory.${idsCL[Default]}" + return 1 + } + if ! chmod 0700 "$TAPM_TEMP_DIR"; then + TAPM_CLEAN_TEMP_DIR "$TAPM_TEMP_DIR" + echo -e "${idsCL[LightRed]}Unable to secure the temporary installer directory.${idsCL[Default]}" + return 1 + fi + TAPM_TEMP_DIRS+=("$TAPM_TEMP_DIR") +} + +TAPM_VALID_HTTPS_URL() { + local url="${1:-}" + + [[ "$url" == https://* && + "$url" != *$'\n'* && + "$url" != *$'\r'* && + "$url" != *'"'* && + "$url" != *\\* && + "$url" != *[[:space:]]* ]] +} + +TAPM_DOWNLOAD_HTTPS() { + local url="$1" + local destination="$2" + local label="${3:-Installer}" + + if ! TAPM_VALID_HTTPS_URL "$url"; then + echo -e "${idsCL[LightRed]}${label} requires a valid HTTPS URL.${idsCL[Default]}" + return 1 + fi + + if ! printf 'url = "%s"\n' "$url" | + curl --fail --location --silent --show-error \ + --proto '=https' --proto-redir '=https' \ + --output "$destination" --config -; then + echo -e "${idsCL[LightRed]}${label} download failed.${idsCL[Default]}" + return 1 + fi + + if [[ ! -s "$destination" ]]; then + echo -e "${idsCL[LightRed]}${label} download was empty.${idsCL[Default]}" + return 1 + fi +} + +TAPM_PACKAGE_INSTALLED() { + dpkg-query -W -f='${Status}' "$1" 2>/dev/null | + grep -q '^install ok installed$' +} + +TAPM_WAIT_FOR_SERVICE() { + local service="$1" + local attempts="${2:-30}" + local attempt=0 + + while (( attempt < attempts )); do + systemctl is-active --quiet "$service" && return 0 + sleep 1 + ((attempt++)) + done + + return 1 +} + +trap TAPM_CLEAN_ALL_TEMP_DIRS EXIT + TAPM_CLEAR_AUTHORIZATION() { unset TAPM_SESSION_TOKEN TAPM_PACKAGE_URL TAPM_PACKAGE_SHA256 TAPM_PACKAGE_VERSION } @@ -79,7 +174,8 @@ print(package.get("version", "") if package else "") ) || true unset exchange_response - if [[ ${#access[@]} -ne 4 || -z "${access[0]}" ]]; then + if [[ ${#access[@]} -ne 4 || + ! "${access[0]}" =~ ^[A-Za-z0-9._~-]+$ ]]; then unset access echo -e "${idsCL[LightRed]}This deployment code does not authorize ${authorization_label}.${idsCL[Default]}" return 1 @@ -100,34 +196,92 @@ print(package.get("version", "") if package else "") } INSTALL_PULSE() { + local installer + local temp_dir + echo - bash <(curl -fsSL https://github.com/rcourtman/Pulse/releases/latest/download/install.sh) + if ! TAPM_CREATE_TEMP_DIR pulse; then + FINISH_FAILED_ACTION + return + fi + temp_dir="$TAPM_TEMP_DIR" + installer="${temp_dir}/install.sh" + + if ! TAPM_DOWNLOAD_HTTPS \ + 'https://github.com/rcourtman/Pulse/releases/latest/download/install.sh' \ + "$installer" 'Pulse installer' || + ! bash "$installer"; then + TAPM_CLEAN_TEMP_DIR "$temp_dir" + echo -e "${idsCL[LightRed]}Pulse installation failed.${idsCL[Default]}" + FINISH_FAILED_ACTION + return + fi + + TAPM_CLEAN_TEMP_DIR "$temp_dir" echo - echo -e "\n${idsCL[Green]}Pulse has been installed${idsCL[Default]}" + echo -e "\n${idsCL[Green]}Pulse installer completed successfully.${idsCL[Default]}" FINISH_ACTION } INSTALL_ACRONIS() { + local installer + local temp_dir + local url='https://us5-cloud.acronis.com/bc/api/ams/links/agents/redirect?language=multi&channel=CURRENT&system=linux&architecture=64&productType=enterprise&login=010180ae-63c4-4495-bed0-4ec934c25af9&white_labeled=0' + echo if ! TAPM_AUTHORIZE "install-acronis" "" "Acronis installation"; then - FINISH_ACTION + FINISH_FAILED_ACTION return fi TAPM_CLEAR_AUTHORIZATION - cd /tmp || return 1 - wget "https://us5-cloud.acronis.com/bc/api/ams/links/agents/redirect?language=multi&channel=CURRENT&system=linux&architecture=64&productType=enterprise&login=010180ae-63c4-4495-bed0-4ec934c25af9&white_labeled=0" -O ./acronisinstall - chmod +x ./acronisinstall - ./acronisinstall - rm -f ./acronisinstall + + if ! TAPM_CREATE_TEMP_DIR acronis; then + FINISH_FAILED_ACTION + return + fi + temp_dir="$TAPM_TEMP_DIR" + installer="${temp_dir}/acronisinstall" + + if ! TAPM_DOWNLOAD_HTTPS "$url" "$installer" 'Acronis installer' || + ! chmod 0700 "$installer" || + ! (cd "$temp_dir" && ./acronisinstall) || + ! TAPM_PACKAGE_INSTALLED cyberprotect; then + TAPM_CLEAN_TEMP_DIR "$temp_dir" + echo -e "${idsCL[LightRed]}Acronis installation failed or could not be verified.${idsCL[Default]}" + FINISH_FAILED_ACTION + return + fi + + TAPM_CLEAN_TEMP_DIR "$temp_dir" echo - echo -e "\n${idsCL[Green]}Acronis has been installed${idsCL[Default]}" + echo -e "\n${idsCL[Green]}Acronis has been installed and verified.${idsCL[Default]}" FINISH_ACTION } INSTALL_PROXMENUX() { - bash -c "$(wget -qLO - https://raw.githubusercontent.com/MacRimi/ProxMenux/main/install_proxmenux.sh)" - # systemctl disable --now proxmenux-monitor - menu + local installer + local temp_dir + + if ! TAPM_CREATE_TEMP_DIR proxmenux; then + FINISH_FAILED_ACTION + return + fi + temp_dir="$TAPM_TEMP_DIR" + installer="${temp_dir}/install.sh" + + if ! TAPM_DOWNLOAD_HTTPS \ + 'https://raw.githubusercontent.com/MacRimi/ProxMenux/main/install_proxmenux.sh' \ + "$installer" 'ProxMenux installer' || + ! bash "$installer" || + [[ ! -x /usr/local/bin/menu ]]; then + TAPM_CLEAN_TEMP_DIR "$temp_dir" + echo -e "${idsCL[LightRed]}ProxMenux installation failed or could not be verified.${idsCL[Default]}" + FINISH_FAILED_ACTION + return + fi + + TAPM_CLEAN_TEMP_DIR "$temp_dir" + /usr/local/bin/menu } PROXMENUX_POST_INSTALL() { @@ -142,38 +296,79 @@ PROXMENUX_POST_INSTALL() { INSTALL_GLANCES() { echo - apt install glances -y - echo -e "\n${idsCL[Green]}Glances has been installed${idsCL[Default]}" + if ! DEBIAN_FRONTEND=noninteractive apt-get install glances -y || + ! TAPM_PACKAGE_INSTALLED glances; then + echo -e "\n${idsCL[LightRed]}Glances installation failed or could not be verified.${idsCL[Default]}" + FINISH_FAILED_ACTION + return + fi + echo -e "\n${idsCL[Green]}Glances has been installed and verified.${idsCL[Default]}" FINISH_ACTION } INSTALL_SCREENCONNECT() { + local SCURL='' + local installer + local temp_dir + echo if ! TAPM_AUTHORIZE "install-screenconnect" "" "ScreenConnect installation"; then - FINISH_ACTION + FINISH_FAILED_ACTION return fi TAPM_CLEAR_AUTHORIZATION echo -en "\n${idsCL[LightYellow]}Paste the URL provided from the Build Installer: ${idsCL[Default]}" read -r -s SCURL echo - [[ -n "$SCURL" ]] || { echo "No URL supplied."; FINISH_ACTION; return; } - wget "${SCURL}" -O /tmp/scinstall + [[ -n "$SCURL" ]] || { echo "No URL supplied."; FINISH_FAILED_ACTION; return; } + if ! TAPM_CREATE_TEMP_DIR screenconnect; then + unset SCURL + FINISH_FAILED_ACTION + return + fi + temp_dir="$TAPM_TEMP_DIR" + installer="${temp_dir}/screenconnect.deb" + + if ! TAPM_DOWNLOAD_HTTPS "$SCURL" "$installer" 'ScreenConnect installer'; then + unset SCURL + TAPM_CLEAN_TEMP_DIR "$temp_dir" + FINISH_FAILED_ACTION + return + fi unset SCURL - dpkg -i /tmp/scinstall - apt install --fix-broken -y - apt remove "connectwis*" -y > /dev/null 2>&1 - dpkg -i /tmp/scinstall - rm -f /tmp/scinstall - systemctl disable --now proxmenux-monitor - echo -e "\n${idsCL[Green]}ScreenConnect has been installed${idsCL[Default]}" + + if ! dpkg -i "$installer"; then + if ! DEBIAN_FRONTEND=noninteractive apt-get install --fix-broken -y; then + TAPM_CLEAN_TEMP_DIR "$temp_dir" + echo -e "${idsCL[LightRed]}ScreenConnect dependency installation failed.${idsCL[Default]}" + FINISH_FAILED_ACTION + return + fi + fi + DEBIAN_FRONTEND=noninteractive apt-get remove 'connectwis*' -y >/dev/null 2>&1 || true + if ! dpkg -i "$installer" || + ! TAPM_WAIT_FOR_SERVICE 'connectwise*'; then + TAPM_CLEAN_TEMP_DIR "$temp_dir" + echo -e "${idsCL[LightRed]}ScreenConnect installation failed or its service is not active.${idsCL[Default]}" + FINISH_FAILED_ACTION + return + fi + + TAPM_CLEAN_TEMP_DIR "$temp_dir" + systemctl disable --now proxmenux-monitor >/dev/null 2>&1 || true + echo -e "\n${idsCL[Green]}ScreenConnect has been installed and verified.${idsCL[Default]}" FINISH_ACTION } INSTALL_RMM() { + local RMMURL='' + local TOKEN='' + local installer + local temp_dir + echo if ! TAPM_AUTHORIZE "install-rmm" "" "RMM installation"; then - FINISH_ACTION + FINISH_FAILED_ACTION return fi TAPM_CLEAR_AUTHORIZATION @@ -181,48 +376,100 @@ INSTALL_RMM() { echo -en "\n${idsCL[LightYellow]}Paste the Linux Server URL provided from the Download Agent screen: ${idsCL[Default]}" read -r -s RMMURL echo - [[ -n "$RMMURL" ]] || { echo "No URL supplied."; FINISH_ACTION; return; } - wget "${RMMURL}" -O /tmp/rmminstall + [[ -n "$RMMURL" ]] || { echo "No URL supplied."; FINISH_FAILED_ACTION; return; } if [[ "$RMMURL" != *TKN* || "$RMMURL" != */RUN* ]]; then echo "Unable to extract the RMM token from the URL." unset RMMURL - FINISH_ACTION + FINISH_FAILED_ACTION return fi TOKEN="${RMMURL#*TKN}" TOKEN="${TOKEN%%/RUN*}" - unset RMMURL - [[ -n "$TOKEN" ]] || { echo "The RMM token is empty."; FINISH_ACTION; return; } - TOKEN="$TOKEN" bash /tmp/rmminstall - unset TOKEN - systemctl restart ITSPlatform - # rm -f /tmp/rmminstall + if [[ -z "$TOKEN" ]]; then + unset RMMURL TOKEN + echo "The RMM token is empty." + FINISH_FAILED_ACTION + return + fi - echo -e "\n${idsCL[Green]}RMM has been installed${idsCL[Default]}" + if ! TAPM_CREATE_TEMP_DIR rmm; then + unset RMMURL TOKEN + FINISH_FAILED_ACTION + return + fi + temp_dir="$TAPM_TEMP_DIR" + installer="${temp_dir}/rmminstall" + if ! TAPM_DOWNLOAD_HTTPS "$RMMURL" "$installer" 'RMM installer'; then + unset RMMURL TOKEN + TAPM_CLEAN_TEMP_DIR "$temp_dir" + FINISH_FAILED_ACTION + return + fi + unset RMMURL + + if ! TOKEN="$TOKEN" bash "$installer"; then + unset TOKEN + TAPM_CLEAN_TEMP_DIR "$temp_dir" + echo -e "${idsCL[LightRed]}RMM installation failed.${idsCL[Default]}" + FINISH_FAILED_ACTION + return + fi + unset TOKEN + TAPM_CLEAN_TEMP_DIR "$temp_dir" + + if ! systemctl restart ITSPlatform || + ! TAPM_WAIT_FOR_SERVICE ITSPlatform; then + echo -e "${idsCL[LightRed]}RMM installed, but the ITSPlatform service is not active.${idsCL[Default]}" + FINISH_FAILED_ACTION + return + fi + + echo -e "\n${idsCL[Green]}RMM has been installed and verified.${idsCL[Default]}" FINISH_ACTION } INSTALL_S1() { + local installer + local s1token='' + local temp_dir + if ! TAPM_AUTHORIZE "" "$S1_BROKER_PACKAGE" "SentinelOne installation"; then - FINISH_ACTION + FINISH_FAILED_ACTION return fi - rm -f "/tmp/${S1_PACKAGE}" - if ! printf 'header = "Authorization: Bearer %s"\n' "$TAPM_SESSION_TOKEN" | - curl --fail --location --show-error --config - \ - --output "/tmp/${S1_PACKAGE}" "$TAPM_PACKAGE_URL"; then + if ! TAPM_CREATE_TEMP_DIR sentinelone; then TAPM_CLEAR_AUTHORIZATION - rm -f "/tmp/${S1_PACKAGE}" - echo -e "${idsCL[LightRed]}The SentinelOne installer download failed.${idsCL[Default]}" - FINISH_ACTION + FINISH_FAILED_ACTION return fi - if [[ "$(sha256sum "/tmp/${S1_PACKAGE}" | cut -d' ' -f1)" != "$TAPM_PACKAGE_SHA256" ]]; then + temp_dir="$TAPM_TEMP_DIR" + installer="${temp_dir}/${S1_PACKAGE}" + + if ! TAPM_VALID_HTTPS_URL "$TAPM_PACKAGE_URL"; then TAPM_CLEAR_AUTHORIZATION - rm -f "/tmp/${S1_PACKAGE}" + TAPM_CLEAN_TEMP_DIR "$temp_dir" + echo -e "${idsCL[LightRed]}The authorized SentinelOne package URL is not valid HTTPS.${idsCL[Default]}" + FINISH_FAILED_ACTION + return + fi + if ! printf 'header = "Authorization: Bearer %s"\nurl = "%s"\n' \ + "$TAPM_SESSION_TOKEN" "$TAPM_PACKAGE_URL" | + curl --fail --location --silent --show-error --config - \ + --proto '=https' --proto-redir '=https' \ + --output "$installer"; then + TAPM_CLEAR_AUTHORIZATION + TAPM_CLEAN_TEMP_DIR "$temp_dir" + echo -e "${idsCL[LightRed]}The SentinelOne installer download failed.${idsCL[Default]}" + FINISH_FAILED_ACTION + return + fi + if [[ ! -s "$installer" || + "$(sha256sum "$installer" | cut -d' ' -f1)" != "$TAPM_PACKAGE_SHA256" ]]; then + TAPM_CLEAR_AUTHORIZATION + TAPM_CLEAN_TEMP_DIR "$temp_dir" echo -e "${idsCL[LightRed]}The SentinelOne installer checksum did not match. The file was removed.${idsCL[Default]}" - FINISH_ACTION + FINISH_FAILED_ACTION return fi TAPM_CLEAR_AUTHORIZATION @@ -231,25 +478,25 @@ INSTALL_S1() { read -r -s s1token echo [[ -n "$s1token" ]] || { - rm -f "/tmp/${S1_PACKAGE}" + TAPM_CLEAN_TEMP_DIR "$temp_dir" echo "No SentinelOne site token supplied." - FINISH_ACTION + FINISH_FAILED_ACTION return } - cd /tmp || return 1 - if ! dpkg -i "/tmp/${S1_PACKAGE}"; then + if ! dpkg -i "$installer" || + ! /opt/sentinelone/bin/sentinelctl management token set "$s1token" || + ! /opt/sentinelone/bin/sentinelctl control start || + ! TAPM_PACKAGE_INSTALLED sentinelagent; then unset s1token - rm -f "/tmp/${S1_PACKAGE}" - echo -e "${idsCL[LightRed]}SentinelOne installation failed.${idsCL[Default]}" - FINISH_ACTION + TAPM_CLEAN_TEMP_DIR "$temp_dir" + echo -e "${idsCL[LightRed]}SentinelOne installation failed or could not be verified.${idsCL[Default]}" + FINISH_FAILED_ACTION return fi - /opt/sentinelone/bin/sentinelctl management token set "$s1token" unset s1token - /opt/sentinelone/bin/sentinelctl control start - rm -f "/tmp/${S1_PACKAGE}" + TAPM_CLEAN_TEMP_DIR "$temp_dir" - echo -e "\n${idsCL[Green]}SentinelOne Agent has been installed. Make sure its added to a \"DETECT ONLY\" policy${idsCL[Default]}" + echo -e "\n${idsCL[Green]}SentinelOne Agent has been installed and verified. Make sure it is added to a \"DETECT ONLY\" policy.${idsCL[Default]}" FINISH_ACTION }