From 852dfee29fdf8d3ae36695b3e7233a8bcf1414a2 Mon Sep 17 00:00:00 2001 From: wh1te909 Date: Fri, 23 Sep 2022 16:05:17 -0700 Subject: [PATCH] mac agent --- agent/agent.go | 29 ++++++++------ agent/agent_unix.go | 39 ++++++++++++++---- agent/install.go | 92 ++++++++++++++++++++++++++++++++++++------- agent/install_unix.go | 36 ++++++++++++++--- agent/svc.go | 17 +++++--- main.go | 2 +- 6 files changed, 170 insertions(+), 45 deletions(-) diff --git a/agent/agent.go b/agent/agent.go index 9b3cf8f..2fb9fd7 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -76,6 +76,12 @@ const ( winExeName = "tacticalrmm.exe" winSvcName = "tacticalrmm" meshSvcName = "mesh agent" + etcConfig = "/etc/tacticalagent" + nixAgentDir = "/opt/tacticalagent" + nixAgentBin = nixAgentDir + "/tacticalagent" + macPlistPath = "/Library/LaunchDaemons/tacticalagent.plist" + macPlistName = "tacticalagent" + macMeshSvcDir = "/usr/local/mesh_services" ) var winTempDir = filepath.Join(os.Getenv("PROGRAMDATA"), "TacticalRMM") @@ -120,18 +126,19 @@ func New(logger *logrus.Logger, version string) *Agent { } var MeshSysExe string - if len(ac.CustomMeshDir) > 0 { - MeshSysExe = filepath.Join(ac.CustomMeshDir, "MeshAgent.exe") - } else { - MeshSysExe = filepath.Join(os.Getenv("ProgramFiles"), "Mesh Agent", "MeshAgent.exe") - } - - if runtime.GOOS == "linux" { + switch runtime.GOOS { + case "windows": + if len(ac.CustomMeshDir) > 0 { + MeshSysExe = filepath.Join(ac.CustomMeshDir, "MeshAgent.exe") + } else { + MeshSysExe = filepath.Join(os.Getenv("ProgramFiles"), "Mesh Agent", "MeshAgent.exe") + } + case "linux": + MeshSysExe = "/opt/tacticalmesh/meshagent" + case "darwin": + MeshSysExe = "/usr/local/mesh_services/meshagent/meshagent" + default: MeshSysExe = "/opt/tacticalmesh/meshagent" - } - - if runtime.GOOS == "darwin" { - MeshSysExe = "/usr/local/mesh_services/meshagent/meshagent_osx64" } svcConf := &service.Config{ diff --git a/agent/agent_unix.go b/agent/agent_unix.go index 9d23590..f33a307 100644 --- a/agent/agent_unix.go +++ b/agent/agent_unix.go @@ -50,7 +50,7 @@ func (a *Agent) GetDisks() []trmm.Disk { } for _, p := range partitions { - if strings.Contains(p.Device, "dev/loop") { + if strings.Contains(p.Device, "dev/loop") || strings.Contains(p.Device, "devfs") { continue } usage, err := disk.Usage(p.Mountpoint) @@ -283,7 +283,7 @@ func (a *Agent) AgentUpdate(url, inno, version string) { } } - if a.seEnforcing() { + if runtime.GOOS == "linux" && a.seEnforcing() { se := a.NewCMDOpts() se.Command = fmt.Sprintf("restorecon -rv %s", self) out := a.CmdV2(se) @@ -292,7 +292,15 @@ func (a *Agent) AgentUpdate(url, inno, version string) { opts := a.NewCMDOpts() opts.Detached = true - opts.Command = "systemctl restart tacticalagent.service" + switch runtime.GOOS { + case "linux": + opts.Command = "systemctl restart tacticalagent.service" + case "darwin": + opts.Command = "launchctl kickstart -k system/tacticalagent" + default: + return + } + a.CmdV2(opts) } @@ -310,7 +318,9 @@ func (a *Agent) AgentUninstall(code string) { opts := a.NewCMDOpts() opts.IsScript = true opts.Shell = f.Name() - opts.Args = []string{"uninstall"} + if runtime.GOOS == "linux" { + opts.Args = []string{"uninstall"} + } opts.Detached = true a.CmdV2(opts) } @@ -354,7 +364,15 @@ func (a *Agent) getMeshNodeID() (string, error) { func (a *Agent) RecoverMesh() { a.Logger.Infoln("Attempting mesh recovery") opts := a.NewCMDOpts() - opts.Command = "systemctl restart meshagent.service" + def := "systemctl restart meshagent.service" + switch runtime.GOOS { + case "linux": + opts.Command = def + case "darwin": + opts.Command = "launchctl kickstart -k system/meshagent" + default: + opts.Command = def + } a.CmdV2(opts) a.SyncMeshNodeID() } @@ -413,18 +431,25 @@ func (a *Agent) GetWMIInfo() map[string]interface{} { wmiInfo["make_model"] = "" chassis, err := ghw.Chassis(ghw.WithDisableWarnings()) if err != nil { - a.Logger.Errorln("ghw.Chassis()", err) + a.Logger.Debugln("ghw.Chassis()", err) } else { if chassis.Vendor != "" || chassis.Version != "" { wmiInfo["make_model"] = fmt.Sprintf("%s %s", chassis.Vendor, chassis.Version) } } + if runtime.GOOS == "darwin" { + opts := a.NewCMDOpts() + opts.Command = "sysctl hw.model" + out := a.CmdV2(opts) + wmiInfo["make_model"] = strings.ReplaceAll(out.Stdout, "hw.model: ", "") + } + // gfx cards gpu, err := ghw.GPU(ghw.WithDisableWarnings()) if err != nil { - a.Logger.Errorln("ghw.GPU()", err) + a.Logger.Debugln("ghw.GPU()", err) } else { for _, i := range gpu.GraphicsCards { if i.DeviceInfo != nil { diff --git a/agent/install.go b/agent/install.go index 228aa3b..1cd45e4 100644 --- a/agent/install.go +++ b/agent/install.go @@ -140,34 +140,57 @@ func (a *Agent) Install(i *Installer) { installerMeshSystemEXE = a.MeshSystemEXE } - var meshNodeID string + var meshNodeID, meshOutput string - if runtime.GOOS == "windows" && !i.NoMesh { - mesh := filepath.Join(a.ProgramDir, a.MeshInstaller) - if i.LocalMesh == "" { + if !i.NoMesh && runtime.GOOS != "linux" { + switch runtime.GOOS { + case "windows": + meshOutput = filepath.Join(a.ProgramDir, a.MeshInstaller) + case "darwin": + tmp, err := createTmpFile() + if err != nil { + a.Logger.Fatalln("Failed to create mesh temp file", err) + } + meshOutput = tmp.Name() + os.Chmod(meshOutput, 0755) + defer os.Remove(meshOutput) + defer os.Remove(meshOutput + ".msh") + } + + if runtime.GOOS == "windows" && i.LocalMesh != "" { + err := copyFile(i.LocalMesh, meshOutput) + if err != nil { + a.installerMsg(err.Error(), "error", i.Silent) + } + } else { a.Logger.Infoln("Downloading mesh agent...") payload := map[string]string{"goarch": a.GoArch, "plat": a.Platform} - r, err := rClient.R().SetBody(payload).SetOutput(mesh).Post(fmt.Sprintf("%s/api/v3/meshexe/", baseURL)) + r, err := rClient.R().SetBody(payload).SetOutput(meshOutput).Post(fmt.Sprintf("%s/api/v3/meshexe/", baseURL)) if err != nil { a.installerMsg(fmt.Sprintf("Failed to download mesh agent: %s", err.Error()), "error", i.Silent) } if r.StatusCode() != 200 { a.installerMsg(fmt.Sprintf("Unable to download the mesh agent from the RMM. %s", r.String()), "error", i.Silent) } - } else { - err := copyFile(i.LocalMesh, mesh) - if err != nil { - a.installerMsg(err.Error(), "error", i.Silent) - } } a.Logger.Infoln("Installing mesh agent...") - a.Logger.Debugln("Mesh agent:", mesh) + a.Logger.Debugln("Mesh agent:", meshOutput) time.Sleep(1 * time.Second) - meshNodeID, err = a.installMesh(mesh, installerMeshSystemEXE, i.Proxy) - if err != nil { - a.installerMsg(fmt.Sprintf("Failed to install mesh agent: %s", err.Error()), "error", i.Silent) + if runtime.GOOS == "windows" { + meshNodeID, err = a.installMesh(meshOutput, installerMeshSystemEXE, i.Proxy) + if err != nil { + a.installerMsg(fmt.Sprintf("Failed to install mesh agent: %s", err.Error()), "error", i.Silent) + } + } else { + opts := a.NewCMDOpts() + opts.Command = fmt.Sprintf("%s -install", meshOutput) + out := a.CmdV2(opts) + if out.Status.Exit != 0 { + a.Logger.Fatalln("Error installing mesh agent:", out.Stderr) + } + fmt.Println(out.Stdout) } } @@ -219,6 +242,47 @@ func (a *Agent) Install(i *Installer) { // check in once a.DoNatsCheckIn() + if runtime.GOOS == "darwin" { + os.MkdirAll(nixAgentDir, 0755) + self, _ := os.Executable() + copyFile(self, nixAgentBin) + os.Chmod(nixAgentBin, 0755) + svc := fmt.Sprintf(` + + + + + Label + %s + + ServiceDescription + TacticalAgent Service + + ProgramArguments + + %s + -m + svc + + + WorkingDirectory + %s/ + + RunAtLoad + + + KeepAlive + + + +`, macPlistName, nixAgentBin, nixAgentDir) + + os.WriteFile(macPlistPath, []byte(svc), 0644) + opts := a.NewCMDOpts() + opts.Command = fmt.Sprintf("launchctl bootstrap system %s", macPlistPath) + a.CmdV2(opts) + } + if runtime.GOOS == "windows" { // send software api a.SendSoftware() diff --git a/agent/install_unix.go b/agent/install_unix.go index 60cb7f1..56f5f8f 100644 --- a/agent/install_unix.go +++ b/agent/install_unix.go @@ -15,17 +15,16 @@ https://license.tacticalrmm.com package agent import ( + "fmt" "log" + "os" + "runtime" + "time" "github.com/spf13/viper" + trmm "github.com/wh1te909/trmm-shared" ) -const ( - etcConfig = "/etc/tacticalagent" -) - -func (a *Agent) checkExistingAndRemove(silent bool) {} - func (a *Agent) installerMsg(msg, alert string, silent bool) { if alert == "error" { a.Logger.Fatalln(msg) @@ -51,6 +50,31 @@ func createAgentConfig(baseurl, agentid, apiurl, token, agentpk, cert, proxy, me } } +func (a *Agent) checkExistingAndRemove(silent bool) { + if runtime.GOOS == "darwin" { + if trmm.FileExists(a.MeshSystemEXE) { + a.Logger.Infoln("Existing meshagent found, attempting to remove...") + uopts := a.NewCMDOpts() + uopts.Command = fmt.Sprintf("%s -fulluninstall", a.MeshSystemEXE) + uout := a.CmdV2(uopts) + fmt.Println(uout.Stdout) + time.Sleep(1 * time.Second) + } + + if trmm.FileExists(macPlistPath) { + a.Logger.Infoln("Existing tacticalagent plist found, attempting to remove...") + opts := a.NewCMDOpts() + opts.Command = fmt.Sprintf("launchctl bootout system %s", macPlistPath) + a.CmdV2(opts) + } + + os.RemoveAll(macMeshSvcDir) + os.Remove(etcConfig) + os.RemoveAll(nixAgentDir) + os.Remove(macPlistPath) + } +} + func DisableSleepHibernate() {} func EnablePing() {} diff --git a/agent/svc.go b/agent/svc.go index 4ca85c2..e695ffd 100644 --- a/agent/svc.go +++ b/agent/svc.go @@ -12,6 +12,7 @@ https://license.tacticalrmm.com package agent import ( + "runtime" "sync" "time" @@ -27,11 +28,13 @@ func (a *Agent) RunAsService() { } func (a *Agent) AgentSvc() { - go a.GetPython(false) + if runtime.GOOS == "windows" { + go a.GetPython(false) - err := createWinTempDir() - if err != nil { - a.Logger.Errorln("AgentSvc() createWinTempDir():", err) + err := createWinTempDir() + if err != nil { + a.Logger.Errorln("AgentSvc() createWinTempDir():", err) + } } a.RunMigrations() @@ -53,8 +56,10 @@ func (a *Agent) AgentSvc() { go a.SyncMeshNodeID() time.Sleep(time.Duration(randRange(1, 3)) * time.Second) - a.AgentStartup() - a.SendSoftware() + if runtime.GOOS == "windows" { + a.AgentStartup() + a.SendSoftware() + } checkInHelloTicker := time.NewTicker(time.Duration(randRange(30, 60)) * time.Second) checkInAgentInfoTicker := time.NewTicker(time.Duration(randRange(200, 400)) * time.Second) diff --git a/main.go b/main.go index eea4af3..ea597e7 100644 --- a/main.go +++ b/main.go @@ -185,7 +185,7 @@ func setupLogging(level, to *string) { switch runtime.GOOS { case "windows": logFile, _ = os.OpenFile(filepath.Join(os.Getenv("ProgramFiles"), "TacticalAgent", "agent.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664) - case "linux": + default: logFile, _ = os.OpenFile(filepath.Join("/var/log/", "tacticalagent.log"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0664) } log.SetOutput(logFile)