Complete rewite

This commit is contained in:
mattchis
2025-06-20 14:27:04 -06:00
parent 6f583a5d63
commit 94c012ef05
2 changed files with 149 additions and 106 deletions

View File

@@ -2,11 +2,13 @@
This script is designed to assist users in adding Mac agents to Tactical RMM without the need for upfront payment for code-signed agents. If you find this solution beneficial, please consider contributing to the Tactical RMM project! This script is designed to assist users in adding Mac agents to Tactical RMM without the need for upfront payment for code-signed agents. If you find this solution beneficial, please consider contributing to the Tactical RMM project!
> This script had a complete rewrite and now only supports MacOS 14 (Sonoma) and above.
# rmmagent-script # rmmagent-script
Script for one-line installation and updating of the tacticalRMM agent. Script for one-line installation and updating of the tacticalRMM agent.
> Currently, both amd64 and arm64 scripts are available; however, only the amd64 version has been tested on macOS 13 (Ventura). > Currently, both amd64 and arm64 scripts are available and has been tested with MacOS 14 (Sonoma) and MacOS 15 (Sequoia); however, only the amd64 version has been tested on macOS 13 (Ventura).
Scripts for additional platforms will be developed and released as they are adapted. You are welcome to modify the script and contribute your improvements back to the project. Scripts for additional platforms will be developed and released as they are adapted. You are welcome to modify the script and contribute your improvements back to the project.
@@ -21,23 +23,13 @@ Download script with this url: `https://raw.githubusercontent.com/mattchis/MacRM
To install agent launch the script with this argument: To install agent launch the script with this argument:
```bash ```bash
./rmmagent-mac.sh install 'System type' 'Mesh agent' 'API URL' 'Client ID' 'Site ID' 'Auth Key' 'Agent Type' ./rmmagent-mac.sh install 'API URL' 'Client ID' 'Site ID' 'Auth Key' 'Agent Type'
``` ```
The compiling can be quite long, don't panic and wait few minutes... USE THE 'SINGLE QUOTES' IN ALL FIELDS! The compiling can be quite long, don't panic and wait few minutes... USE THE 'SINGLE QUOTES' IN ALL FIELDS!
The argument are: The argument are:
2. System type 2. API URL
Type of system. Can be 'amd64' 'arm64'
3. Mesh agent
The url given by mesh for installing new agent.
Go to mesh.fqdn.com > Add agent > Installation Executable Linux / BSD / macOS > **Select the good system type**
Copy **ONLY** the URL with the quote.
4. API URL
Your api URL for agent communication usually https://api.fqdn.com. Your api URL for agent communication usually https://api.fqdn.com.
@@ -62,7 +54,7 @@ The argument are:
### Example ### Example
```bash ```bash
./rmmagent-mac.sh install amd64 "https://mesh.fqdn.com/meshagents?id=XXXXX&installflags=X&meshinstall=X" "https://api.fqdn.com" 3 1 "XXXXX" server ./rmmagent-mac.sh install "https://api.fqdn.com" 3 1 "XXXXX" server
``` ```
## Update ## Update
@@ -71,6 +63,17 @@ Simply launch the script that match your system with *update* as argument.
```bash ```bash
./rmmagent-mac.sh update ./rmmagent-mac.sh update
``` ```
## Enable Permissions
This sets up all the permissions for screenrecording, file, and disk access for the meshagent.
```bash
./rmmagent-mac.sh enablepermissions
```
## Seqouia Fix
This will fix issues with "Take Control" from the dashboard not displaying the screen. Credit goes to PeetMcK and si458 for the solution (https://github.com/Ylianst/MeshCentral/issues/6402)
```bash
./rmmagent-mac.sh sequoiafix
```
## Uninstall ## Uninstall
To uninstall the agent, execute the script with the following argument: To uninstall the agent, execute the script with the following argument:

View File

@@ -10,100 +10,87 @@ if [[ $1 == "help" ]]; then
echo "" echo ""
echo "List of INSTALL/UPDATE argument (no argument name):" echo "List of INSTALL/UPDATE argument (no argument name):"
echo "Arg 1: 'install' or 'update'" echo "Arg 1: 'install' or 'update'"
echo "Arg 2: System type 'amd64' 'arm64'" echo "Arg 2: API URL"
echo "Arg 3: Mesh agent URL" echo "Arg 3: Client ID"
echo "Arg 4: API URL" echo "Arg 4: Site ID"
echo "Arg 5: Client ID" echo "Arg 5: Auth Key"
echo "Arg 6: Site ID" echo "Arg 6: Agent Type 'server' or 'workstation'"
echo "Arg 7: Auth Key"
echo "Arg 8: Agent Type 'server' or 'workstation'"
echo "" echo ""
echo "List of UNINSTALL argument (no argument name):" echo "List of UNINSTALL argument (no argument name):"
echo "Arg 1: 'uninstall'" echo "Arg 1: 'uninstall'"
echo "Arg 2: Mesh agent FQDN (i.e. mesh.domain.com)"
echo "Arg 3: Mesh agent id (The id needs to have single quotes around it)"
echo "" echo ""
echo "Only argument 1 is needed for update" echo "List of ENABLEPERMISSIONS argument (no argument name):"
echo "Arg 1: 'enablepermissions'"
echo ""
echo "List of SEQUOIAFIX argument (no argument name):"
echo "Arg 1: 'SEQUOIAFIX'"
echo ""
echo "Only argument 1 is needed for update and sequoiafix"
echo "" echo ""
exit 0 exit 0
fi fi
if [[ $1 != "install" && $1 != "update" && $1 != "uninstall" ]]; then if [[ $1 != "install" && $1 != "update" && $1 != "uninstall" && $1 != "enablepermissions" && $1 != "sequoiafix" ]]; then
echo "First argument can only be 'install' or 'update' or 'uninstall' !" echo "First argument can only be 'install' or 'update' or 'uninstall' !"
echo "Type help for more information" echo "Type help for more information"
exit 1 exit 1
fi fi
if [[ $1 == "install" && $2 == "" ]]; then if [[ $1 == "install" && $2 == "" ]]; then
echo "Argument 2 (System type) is empty !" echo "Argument 2 (API URL) is empty !"
echo "Type help for more information"
exit 1
fi
if [[ $1 == "install" && $2 != "amd64" && $2 != "arm64" ]]; then
echo "This argument can only be 'amd64' 'arm64' !"
echo "Type help for more information" echo "Type help for more information"
exit 1 exit 1
fi fi
if [[ $1 == "install" && $3 == "" ]]; then if [[ $1 == "install" && $3 == "" ]]; then
echo "Argument 3 (Mesh agent URL) is empty !" echo "Argument 3 (Client ID) is empty !"
echo "Type help for more information" echo "Type help for more information"
exit 1 exit 1
fi fi
if [[ $1 == "install" && $4 == "" ]]; then if [[ $1 == "install" && $4 == "" ]]; then
echo "Argument 4 (API URL) is empty !" echo "Argument 4 (Site ID) is empty !"
echo "Type help for more information" echo "Type help for more information"
exit 1 exit 1
fi fi
if [[ $1 == "install" && $5 == "" ]]; then if [[ $1 == "install" && $5 == "" ]]; then
echo "Argument 5 (Client ID) is empty !" echo "Argument 5 (Auth Key) is empty !"
echo "Type help for more information" echo "Type help for more information"
exit 1 exit 1
fi fi
if [[ $1 == "install" && $6 == "" ]]; then if [[ $1 == "install" && $6 == "" ]]; then
echo "Argument 6 (Site ID) is empty !" echo "Argument 6 (Agent Type) is empty !"
echo "Type help for more information" echo "Type help for more information"
exit 1 exit 1
fi fi
if [[ $1 == "install" && $7 == "" ]]; then if [[ $1 == "install" && $6 != "server" && $6 != "workstation" ]]; then
echo "Argument 7 (Auth Key) is empty !"
echo "Type help for more information"
exit 1
fi
if [[ $1 == "install" && $8 == "" ]]; then
echo "Argument 8 (Agent Type) is empty !"
echo "Type help for more information"
exit 1
fi
if [[ $1 == "install" && $8 != "server" && $8 != "workstation" ]]; then
echo "First argument can only be 'server' or 'workstation' !" echo "First argument can only be 'server' or 'workstation' !"
echo "Type help for more information" echo "Type help for more information"
exit 1 exit 1
fi fi
## Setting var for easy scription ## Setting var for easy scription
system=$2 #system=$2
mesh_url=$3 #mesh_url=$2
rmm_url=$4 rmm_url=$2
rmm_client_id=$5 rmm_client_id=$3
rmm_site_id=$6 rmm_site_id=$4
rmm_auth=$7 rmm_auth=$5
rmm_agent_type=$8 rmm_agent_type=$6
go_url_amd64="https://go.dev/dl/go1.20.2.darwin-amd64.pkg" go_url_amd64="https://go.dev/dl/go1.24.4.darwin-amd64.pkg"
go_url_arm64="https://go.dev/dl/go1.20.2.darwin-arm64.pkg" go_url_arm64="https://go.dev/dl/go1.24.4.darwin-arm64.pkg"
function go_install() { function go_install() {
## Installing golang ## Installing golang
case $system in echo "###########################"
amd64) echo "# Installing/Upgrading Go #"
echo "###########################"
case $(uname -m) in
x86_64)
sudo curl -L -o /tmp/golang.pkg $go_url_amd64 sudo curl -L -o /tmp/golang.pkg $go_url_amd64
;; ;;
arm64) arm64)
@@ -112,7 +99,7 @@ function go_install() {
esac esac
sudo mkdir /usr/local/go sudo mkdir /usr/local/go
sudo installer -pkg /tmp/golang.pkg -target /usr/local/go sudo installer -pkg /tmp/golang.pkg -target /usr/local/go
sudo rm /tmp/golang.pkg sudo rm /tmp/golang.pkg
source /etc/profile source /etc/profile
@@ -120,44 +107,36 @@ function go_install() {
echo "Golang Install Done !" echo "Golang Install Done !"
} }
function install_mesh() {
## Installing mesh agent
sudo curl -L -o /tmp/meshagent $mesh_url
sudo chmod +x /tmp/meshagent
sudo mkdir /opt/tacticalmesh
sudo /tmp/meshagent -install --installPath="/opt/tacticalmesh"
sudo rm /tmp/meshagent
sudo rm /tmp/meshagent.msh
}
function getCSREQBlob(){ function getCSREQBlob(){
# Sign the app # Sign the app
sudo codesign --detached /opt/tacticalmesh/meshagent.sig -s - /opt/tacticalmesh/meshagent sudo codesign --detached /opt/tacticalmesh/meshagent.sig -s - /opt/tacticalmesh/meshagent
# Get the requirement string from codesign # Get the requirement string from codesign
req_str=$(sudo codesign -d -r- --detached /opt/tacticalmesh/meshagent.sig /opt/tacticalmesh/meshagent 2>&1 | awk -F ' => ' '/designated/{print $2}') req_str=$(sudo codesign -d -r- --detached /opt/tacticalmesh/meshagent.sig /opt/tacticalmesh/meshagent 2>&1 | awk -F ' => ' '/designated/{print $2}')
# Convert the requirements string into it's binary representation
# csreq requires the output to be a file so we just throw it in /tmp
echo "$req_str" | sudo csreq -r- -b /tmp/csreq.bin >/dev/null 2>&1
# Convert the binary form to hex, and print it nicely for use in sqlite
req_hex="X'$(sudo xxd -p /tmp/csreq.bin | tr -d '\n')'"
echo "$req_hex"
# Convert the requirements string into it's binary representation # Remove csqeq.bin
# csreq requires the output to be a file so we just throw it in /tmp sudo rm -f "/tmp/csreq.bin"
echo "$req_str" | sudo csreq -r- -b /tmp/csreq.bin
# Convert the binary form to hex, and print it nicely for use in sqlite
req_hex="X'$(sudo xxd -p /tmp/csreq.bin | tr -d '\n')'"
echo "$req_hex"
# Remove csqeq.bin
sudo rm -f "/tmp/csreq.bin"
} }
function agent_compile() { function agent_compile() {
## Compiling and installing tactical agent from github ## Compiling and installing tactical agent from github
echo "Agent Compile begin" echo "########################"
echo "# Compiling TRMM Agent #"
echo "########################"
sudo curl -L -o /tmp/rmmagent.zip https://github.com/amidaware/rmmagent/archive/refs/heads/master.zip sudo curl -L -o /tmp/rmmagent.zip https://github.com/amidaware/rmmagent/archive/refs/heads/master.zip
sudo unzip /tmp/rmmagent.zip -d /tmp/ sudo unzip /tmp/rmmagent.zip -d /tmp/
sudo rm /tmp/rmmagent.zip sudo rm /tmp/rmmagent.zip
case $system in case $(uname -m) in
amd64) x86_64)
sudo /bin/sh -c 'cd /tmp/rmmagent-master && env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w" -o /tmp/temp_rmmagent' sudo /bin/sh -c 'cd /tmp/rmmagent-master && env CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -w" -o /tmp/temp_rmmagent'
;; ;;
arm64) arm64)
@@ -170,63 +149,124 @@ function agent_compile() {
} }
function install_agent() { function install_agent() {
echo "#########################"
echo "# Installing TRMM Agent #"
echo "#########################"
sudo cp /tmp/temp_rmmagent /usr/local/bin/rmmagent sudo cp /tmp/temp_rmmagent /usr/local/bin/rmmagent
sudo /tmp/temp_rmmagent -m install -meshdir /opt/tacticalmesh -api $rmm_url -client-id $rmm_client_id -site-id $rmm_site_id -agent-type $rmm_agent_type -auth $rmm_auth sudo /tmp/temp_rmmagent -m install -meshdir /opt/tacticalmesh -api $rmm_url -client-id $rmm_client_id -site-id $rmm_site_id -agent-type $rmm_agent_type -auth $rmm_auth
sudo rm /tmp/temp_rmmagent sudo rm /tmp/temp_rmmagent
sudo xattr -r -d com.apple.quarantine /opt/tacticalmesh/meshagent
} }
function update_agent() { function update_agent() {
sudo launchctl unload /Library/LaunchDaemons/tacticalagent.plist echo "#######################"
echo "# Updating TRMM Agent #"
echo "#######################"
sudo launchctl bootout system /Library/LaunchDaemons/tacticalagent.plist
sudo cp /tmp/temp_rmmagent /opt/tacticalagent/tacticalagent sudo cp /tmp/temp_rmmagent /opt/tacticalagent/tacticalagent
sudo rm /tmp/temp_rmmagent sudo rm /tmp/temp_rmmagent
sudo launchctl load -w /Library/LaunchDaemons/tacticalagent.plist sudo launchctl load -w /Library/LaunchDaemons/tacticalagent.plist
sudo xattr -r -d com.apple.quarantine /opt/tacticalmesh/meshagent
} }
function config_securityandprivacy () { function config_securityandprivacy () {
# Adding permissions to macOS to allow Accessibility, Screen Capture, and All File Access to the meshagent # Adding permissions to macOS to allow Accessibility, Screen Capture, and All File Access to the meshagent
echo "Applying Security and Privacy Exceptions" echo "############################################"
echo "# Applying Security and Privacy Exceptions #"
echo "############################################"
req_hex="$(getCSREQBlob)" req_hex="$(getCSREQBlob)"
sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "REPLACE INTO access VALUES('kTCCServiceAccessibility','/opt/tacticalmesh/meshagent',1,2,4,1,$req_hex,NULL,0,NULL,NULL,0,NULL);" echo "Hex value = $req_hex"
sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "REPLACE INTO access VALUES('kTCCServiceScreenCapture','/opt/tacticalmesh/meshagent',1,2,4,1,$req_hex,NULL,0,NULL,NULL,0,NULL);" sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "REPLACE INTO access VALUES('kTCCServiceAccessibility','/opt/tacticalmesh/meshagent',1,2,4,1,$req_hex,NULL,0,'UNUSED',NULL,0,NULL,NULL,NULL,NULL,NULL);"
sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "REPLACE INTO access VALUES('kTCCServiceSystemPolicyAllFiles','/opt/tacticalmesh/meshagent',1,2,4,1,$req_hex,NULL,0,NULL,NULL,0,NULL);" sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "REPLACE INTO access VALUES('kTCCServiceScreenCapture','/opt/tacticalmesh/meshagent',1,2,4,1,$req_hex,NULL,0,NULL,NULL,0,NULL,NULL,NULL,NULL,NULL);"
sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "REPLACE INTO access VALUES('kTCCServiceSystemPolicyAllFiles','/opt/tacticalmesh/meshagent',1,2,4,1,$req_hex,NULL,0,NULL,NULL,0,NULL,NULL,NULL,NULL,NULL);"
} }
function uninstall_agent() { function uninstall_agent() {
sudo launchctl unload /Library/LaunchDaemons/tacticalagent.plist echo "###########################"
sudo rm /Library/LaunchDaemons/tacticalagent.plist echo "# Uninstalling TRMM Agent #"
sudo rm -Rf /opt/tacticalagent/ echo "###########################"
sudo rm /etc/tacticalagent if [ -e "/Library/LaunchDaemons/tacticalagent.plist" ]; then
sudo launchctl bootout system /Library/LaunchDaemons/tacticalagent.plist
sudo rm /Library/LaunchDaemons/tacticalagent.plist
fi
if [ -d "/opt/tacticalagent" ]; then
sudo rm -Rf /opt/tacticalagent/
fi
if [ -e "/etc/tacticalagent" ]; then
sudo rm /etc/tacticalagent
fi
sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "delete from access where client='/opt/tacticalagent/tacticalagent';"
} }
function uninstall_mesh() { function uninstall_mesh() {
sudo launchctl unload /Library/LaunchDaemons/meshagent.plist echo "###########################"
sudo /opt/tacticalmesh/meshagent -fulluninstall echo "# Uninstalling Mesh Agent #"
rm -Rf /opt/tacticalmesh echo "###########################"
if [ -e "/Library/LaunchDaemons/meshagent.plist" ]; then
sudo launchctl bootout system /Library/LaunchDaemons/meshagent.plist
fi
if [ -e "/Library/LaunchAgents/meshagent-agent.plist" ]; then
sudo rm /Library/LaunchAgents/meshagent-agent.plist
fi
if [ -e "/Library/LaunchAgents/meshagent.plist" ]; then
sudo rm /Library/LaunchAgents/meshagent.plist
fi
if [ -e "/opt/tacticalmesh/meshagent" ]; then
sudo /opt/tacticalmesh/meshagent -fulluninstall
fi
if [ -d "/opt/tacticalmesh" ]; then
rm -Rf /opt/tacticalmesh
fi
sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "delete from access where client='/opt/tacticalmesh/meshagent';" sudo sqlite3 /Library/Application\ Support/com.apple.TCC/TCC.db "delete from access where client='/opt/tacticalmesh/meshagent';"
} }
function sequoia_fix() {
echo "########################"
echo "# Applying Sequoia Fix #"
echo "########################"
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -e "/Library/LaunchAgents/meshagent-agent.plist" ]; then
sudo rm /Library/LaunchAgents/meshagent-agent.plist
fi
if [ -e "/Library/LaunchDaemons/meshagent.plist" ]; then
sudo rm /Library/LaunchDaemons/meshagent.plist
fi
sudo cp "${script_dir}/meshagent.plist" /Library/LaunchAgents/meshagent.plist
sudo chown root:wheel /Library/LaunchAgents/meshagent.plist
sudo chmod 666 /opt/tacticalmesh/meshagent.msh
sudo chmod 666 /opt/tacticalmesh/meshagent.db
}
case $1 in case $1 in
install) install)
go_install go_install
install_mesh
agent_compile agent_compile
install_agent install_agent
config_securityandprivacy
echo "Tactical Agent Install is done" echo "Tactical Agent Install is done"
echo "Please wait about 5 min then run 'rmmagent-mac.sh enablepermissions'"
exit 0;; exit 0;;
enablepermissions)
config_securityandprivacy
echo "Security and Privacy configuration is done"
echo "If the Mac is running Sequoia then run 'rmmagent-mac.sh sequoiafix'"
exit 0;;
sequoiafix)
sequoia_fix
echo "Sequoia Fix has been applied. Please reboot Mac for changes to take effect"
exit 0;;
update) update)
go_install go_install
agent_compile agent_compile
update_agent update_agent
config_securityandprivacy
echo "Tactical Agent Update is done" echo "Tactical Agent Update is done"
echo "Please wait about 5 min then run 'rmmagent-mac.sh enablepermissions'"
exit 0;; exit 0;;
uninstall) uninstall)
uninstall_agent uninstall_agent
uninstall_mesh uninstall_mesh
echo "Tactical Agent Uninstall is done" echo "TacticalRMM/Mesh Agent Uninstall is complete"
echo "You may need to manually remove the agents orphaned connections on TacticalRMM and MeshCentral" echo "You may need to manually remove the agents orphaned connections on TacticalRMM and MeshCentral"
exit 0;; exit 0;;
esac esac