From 3ab9f6a87167fc7d50f9690e00d3870f7a766082 Mon Sep 17 00:00:00 2001 From: Soarinferret Date: Sat, 12 Nov 2022 19:39:18 -0600 Subject: [PATCH 1/3] add code for bash oneliner --- api/tacticalrmm/agents/urls.py | 1 + api/tacticalrmm/agents/utils.py | 81 +++++++++++++++++++++-------- api/tacticalrmm/agents/views.py | 27 ++++++++-- api/tacticalrmm/core/agent_linux.sh | 16 ++++++ 4 files changed, 99 insertions(+), 26 deletions(-) diff --git a/api/tacticalrmm/agents/urls.py b/api/tacticalrmm/agents/urls.py index 73ffd2ba3d..221e04cda0 100644 --- a/api/tacticalrmm/agents/urls.py +++ b/api/tacticalrmm/agents/urls.py @@ -42,4 +42,5 @@ path("update/", views.update_agents), path("installer/", views.install_agent), path("bulkrecovery/", views.bulk_agent_recovery), + path("installer/linux", views.install_agent_linux), ] diff --git a/api/tacticalrmm/agents/utils.py b/api/tacticalrmm/agents/utils.py index c9fdc2943b..f8cc8e375d 100644 --- a/api/tacticalrmm/agents/utils.py +++ b/api/tacticalrmm/agents/utils.py @@ -33,8 +33,62 @@ def generate_linux_install( token: str, api: str, download_url: str, + download_only: bool=False, ) -> FileResponse: + text = Path(settings.LINUX_AGENT_SCRIPT).read_text() + + # replace contents + if not download_only: + match arch: + case "amd64": + arch_id = MeshAgentIdent.LINUX64 + case "386": + arch_id = MeshAgentIdent.LINUX32 + case "arm64": + arch_id = MeshAgentIdent.LINUX_ARM_64 + case "arm": + arch_id = MeshAgentIdent.LINUX_ARM_HF + case _: + arch_id = "not_found" + + core = get_core_settings() + + uri = get_mesh_ws_url() + mesh_id = asyncio.run(get_mesh_device_id(uri, core.mesh_device_group)) + mesh_dl = ( + f"{core.mesh_site}/meshagents?id={mesh_id}&installflags=2&meshinstall={arch_id}" + ) + + replace = { + "agentDLChange": download_url, + "meshDLChange": mesh_dl, + "clientIDChange": client, + "siteIDChange": site, + "agentTypeChange": agent_type, + "tokenChange": token, + "apiURLChange": api, + } + + for i, j in replace.items(): + text = text.replace(i, j) + + with tempfile.NamedTemporaryFile() as fp: + with open(fp.name, "w") as f: + f.write(text) + f.write("\n") + + return FileResponse( + open(fp.name, "rb"), as_attachment=True, filename="linux_agent_install.sh" + ) + + +def generate_linux_install_command( + install_flags: list, + arch: str, + curl_url: str, + download_url: str, +): match arch: case "amd64": arch_id = MeshAgentIdent.LINUX64 @@ -55,26 +109,7 @@ def generate_linux_install( f"{core.mesh_site}/meshagents?id={mesh_id}&installflags=2&meshinstall={arch_id}" ) - text = Path(settings.LINUX_AGENT_SCRIPT).read_text() - - replace = { - "agentDLChange": download_url, - "meshDLChange": mesh_dl, - "clientIDChange": client, - "siteIDChange": site, - "agentTypeChange": agent_type, - "tokenChange": token, - "apiURLChange": api, - } - - for i, j in replace.items(): - text = text.replace(i, j) - - with tempfile.NamedTemporaryFile() as fp: - with open(fp.name, "w") as f: - f.write(text) - f.write("\n") - - return FileResponse( - open(fp.name, "rb"), as_attachment=True, filename="linux_agent_install.sh" - ) + install_flags.extend(["--meshdl", f"'{mesh_dl}'", "--agentdl", f"'{download_url}'"]) + return ( + f"curl -FL '{curl_url}' | sudo bash -s -- " + " ".join(str(i) for i in install_flags) + ) \ No newline at end of file diff --git a/api/tacticalrmm/agents/views.py b/api/tacticalrmm/agents/views.py index 1a076fe35c..3f183e54f6 100644 --- a/api/tacticalrmm/agents/views.py +++ b/api/tacticalrmm/agents/views.py @@ -11,12 +11,14 @@ from django.http import HttpResponse from django.shortcuts import get_object_or_404 from django.utils import timezone as djangotime +from django.urls import reverse +from agents.utils import generate_linux_install, generate_linux_install_command from meshctrl.utils import get_login_token from packaging import version as pyver from rest_framework import serializers from rest_framework.decorators import api_view, permission_classes from rest_framework.exceptions import PermissionDenied -from rest_framework.permissions import IsAuthenticated +from rest_framework.permissions import IsAuthenticated, AllowAny from rest_framework.response import Response from rest_framework.views import APIView @@ -547,7 +549,7 @@ def install_agent(request): codesign_token, is_valid = token_is_valid() - if request.data["installMethod"] in {"bash", "mac"} and not is_valid: + if request.data["installMethod"] in {"bash", "mac"} and is_valid: return notify_error( "Missing code signing token, or token is no longer valid. Please read the docs for more info." ) @@ -609,7 +611,7 @@ def install_agent(request): download_url=download_url, ) - elif request.data["installMethod"] in {"manual", "mac"}: + elif request.data["installMethod"] in {"manual", "mac", "bash-manual"}: resp = {} if request.data["installMethod"] == "manual": cmd = [ @@ -633,6 +635,12 @@ def install_agent(request): cmd.append("--power") resp["cmd"] = " ".join(str(i) for i in cmd) + elif request.data["installMethod"] == "bash-manual": + curl_url = request.build_absolute_uri(reverse(install_agent_linux)) + cmd = install_flags.copy() + cmd.remove('-m') + cmd.remove('install') + resp["cmd"] = generate_linux_install_command(cmd, goarch, curl_url, download_url) else: install_flags.insert(0, f"sudo ./{inno}") cmd = install_flags.copy() @@ -687,6 +695,19 @@ def install_agent(request): response["X-Accel-Redirect"] = f"/private/exe/{file_name}" return response +@api_view(["GET"]) +@permission_classes([AllowAny]) +def install_agent_linux(request): + return generate_linux_install( + download_only=True, + client="", + site="", + agent_type="", + arch="", + token="", + api="", + download_url="", + ) @api_view(["POST"]) @permission_classes([IsAuthenticated, RecoverAgentPerms]) diff --git a/api/tacticalrmm/core/agent_linux.sh b/api/tacticalrmm/core/agent_linux.sh index ef995cf920..09c3a55324 100755 --- a/api/tacticalrmm/core/agent_linux.sh +++ b/api/tacticalrmm/core/agent_linux.sh @@ -33,6 +33,22 @@ meshSystemBin="${meshDir}/meshagent" meshSvcName='meshagent.service' meshSysD="/lib/systemd/system/${meshSvcName}" +# Simple Bash Argument Handler +while [[ "$#" -gt 0 ]]; do + case $1 in + -t|--token|--auth) token="$2"; shift ;; + -c|--client-id) clientID="$2"; shift ;; + -s|--site-id) siteID="$2"; shift ;; + -a|--agent-type) agentType="$2"; shift;; + --proxy) proxy="$2"; shift;; + --api) apiURL="$2"; shift;; + --agentdl) agentDL="$2"; shift;; + --meshdl) meshDL="$2"; shift;; + *) echo "Unknown parameter passed: $1"; exit 1 ;; + esac + shift +done + deb=(ubuntu debian raspbian kali linuxmint) rhe=(fedora rocky centos rhel amzn arch opensuse) From d63efea03999f2f25845dbff29f9f82074f1c24d Mon Sep 17 00:00:00 2001 From: Soarinferret Date: Sat, 12 Nov 2022 19:42:03 -0600 Subject: [PATCH 2/3] fix token code --- api/tacticalrmm/agents/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/api/tacticalrmm/agents/views.py b/api/tacticalrmm/agents/views.py index 3f183e54f6..3a4f264703 100644 --- a/api/tacticalrmm/agents/views.py +++ b/api/tacticalrmm/agents/views.py @@ -549,7 +549,7 @@ def install_agent(request): codesign_token, is_valid = token_is_valid() - if request.data["installMethod"] in {"bash", "mac"} and is_valid: + if request.data["installMethod"] in {"bash", "mac"} and not is_valid: return notify_error( "Missing code signing token, or token is no longer valid. Please read the docs for more info." ) From 2d6d07437532ba62bae23545cf0712195a12c475 Mon Sep 17 00:00:00 2001 From: Soarinferret Date: Tue, 15 Nov 2022 21:02:30 -0600 Subject: [PATCH 3/3] fix black formatting --- api/tacticalrmm/agents/utils.py | 12 +++++------- api/tacticalrmm/agents/views.py | 10 +++++++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/api/tacticalrmm/agents/utils.py b/api/tacticalrmm/agents/utils.py index f8cc8e375d..0bebd7cbbb 100644 --- a/api/tacticalrmm/agents/utils.py +++ b/api/tacticalrmm/agents/utils.py @@ -33,7 +33,7 @@ def generate_linux_install( token: str, api: str, download_url: str, - download_only: bool=False, + download_only: bool = False, ) -> FileResponse: text = Path(settings.LINUX_AGENT_SCRIPT).read_text() @@ -56,9 +56,7 @@ def generate_linux_install( uri = get_mesh_ws_url() mesh_id = asyncio.run(get_mesh_device_id(uri, core.mesh_device_group)) - mesh_dl = ( - f"{core.mesh_site}/meshagents?id={mesh_id}&installflags=2&meshinstall={arch_id}" - ) + mesh_dl = f"{core.mesh_site}/meshagents?id={mesh_id}&installflags=2&meshinstall={arch_id}" replace = { "agentDLChange": download_url, @@ -110,6 +108,6 @@ def generate_linux_install_command( ) install_flags.extend(["--meshdl", f"'{mesh_dl}'", "--agentdl", f"'{download_url}'"]) - return ( - f"curl -FL '{curl_url}' | sudo bash -s -- " + " ".join(str(i) for i in install_flags) - ) \ No newline at end of file + return f"curl -FL '{curl_url}' | sudo bash -s -- " + " ".join( + str(i) for i in install_flags + ) diff --git a/api/tacticalrmm/agents/views.py b/api/tacticalrmm/agents/views.py index 3a4f264703..ec0713e369 100644 --- a/api/tacticalrmm/agents/views.py +++ b/api/tacticalrmm/agents/views.py @@ -638,9 +638,11 @@ def install_agent(request): elif request.data["installMethod"] == "bash-manual": curl_url = request.build_absolute_uri(reverse(install_agent_linux)) cmd = install_flags.copy() - cmd.remove('-m') - cmd.remove('install') - resp["cmd"] = generate_linux_install_command(cmd, goarch, curl_url, download_url) + cmd.remove("-m") + cmd.remove("install") + resp["cmd"] = generate_linux_install_command( + cmd, goarch, curl_url, download_url + ) else: install_flags.insert(0, f"sudo ./{inno}") cmd = install_flags.copy() @@ -695,6 +697,7 @@ def install_agent(request): response["X-Accel-Redirect"] = f"/private/exe/{file_name}" return response + @api_view(["GET"]) @permission_classes([AllowAny]) def install_agent_linux(request): @@ -709,6 +712,7 @@ def install_agent_linux(request): download_url="", ) + @api_view(["POST"]) @permission_classes([IsAuthenticated, RecoverAgentPerms]) def recover(request, agent_id: str) -> Response: