mirror of https://github.com/wh1te909/rmmagent.git
finish install
This commit is contained in:
parent
04d6e02974
commit
5c30b0e766
|
@ -34,12 +34,14 @@ type WindowsAgent struct {
|
|||
DB
|
||||
Host
|
||||
ProgramDir string
|
||||
EXE string
|
||||
SystemDrive string
|
||||
SaltCall string
|
||||
Nssm string
|
||||
SaltMinion string
|
||||
SaltInstaller string
|
||||
MeshInstaller string
|
||||
MeshSVC string
|
||||
PyBin string
|
||||
Headers map[string]string
|
||||
Logger *logrus.Logger
|
||||
|
@ -52,6 +54,7 @@ func New(logger *logrus.Logger, version string) *WindowsAgent {
|
|||
host, _ := ps.Host()
|
||||
info := host.Info()
|
||||
pd := filepath.Join(os.Getenv("ProgramFiles"), "TacticalAgent")
|
||||
exe := filepath.Join(pd, "tacticalrmm.exe")
|
||||
dbFile := filepath.Join(pd, "agentdb.db")
|
||||
sd := os.Getenv("SystemDrive")
|
||||
pybin := filepath.Join(sd, "\\salt", "bin", "python.exe")
|
||||
|
@ -82,12 +85,14 @@ func New(logger *logrus.Logger, version string) *WindowsAgent {
|
|||
Timezone: info.Timezone,
|
||||
},
|
||||
ProgramDir: pd,
|
||||
EXE: exe,
|
||||
SystemDrive: sd,
|
||||
SaltCall: sc,
|
||||
Nssm: nssm,
|
||||
SaltMinion: saltexe,
|
||||
SaltInstaller: saltinstaller,
|
||||
MeshInstaller: mesh,
|
||||
MeshSVC: "mesh agent",
|
||||
PyBin: pybin,
|
||||
Headers: headers,
|
||||
Logger: logger,
|
||||
|
@ -356,18 +361,24 @@ func (a *WindowsAgent) GetDisks() []Disk {
|
|||
}
|
||||
|
||||
// CMDShell mimics python's `subprocess.run(shell=True)`
|
||||
//
|
||||
// Context timeout won't work here since cmd.exe spawns a child process
|
||||
// and golang's defer will only kill the parent process which will already
|
||||
//
|
||||
// for example, passing `ping 8.8.8.8 -t` here will run forever even with a timeout set
|
||||
//
|
||||
// Passing `detached` will also ensure the function returns immediately and will never hang,
|
||||
// rather continue to run in the background
|
||||
func CMDShell(command string, detached bool) (output [2]string, e error) {
|
||||
var outb, errb bytes.Buffer
|
||||
func CMDShell(cmdArgs []string, command string, timeout int, detached bool) (output [2]string, e error) {
|
||||
var (
|
||||
outb bytes.Buffer
|
||||
errb bytes.Buffer
|
||||
cmd *exec.Cmd
|
||||
timedOut bool = false
|
||||
)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout)*time.Second)
|
||||
defer cancel()
|
||||
|
||||
if len(cmdArgs) > 0 && command == "" {
|
||||
cmdArgs = append([]string{"/C"}, cmdArgs...)
|
||||
cmd = exec.Command("cmd.exe", cmdArgs...)
|
||||
} else {
|
||||
cmd = exec.Command("cmd.exe", "/C", command)
|
||||
}
|
||||
|
||||
cmd := exec.Command("cmd.exe", "/C", command)
|
||||
// https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags
|
||||
if detached {
|
||||
cmd.SysProcAttr = &windows.SysProcAttr{
|
||||
|
@ -376,10 +387,26 @@ func CMDShell(command string, detached bool) (output [2]string, e error) {
|
|||
}
|
||||
cmd.Stdout = &outb
|
||||
cmd.Stderr = &errb
|
||||
err := cmd.Run()
|
||||
err := cmd.Start()
|
||||
|
||||
pid := int32(cmd.Process.Pid)
|
||||
|
||||
go func(p int32) {
|
||||
|
||||
<-ctx.Done()
|
||||
|
||||
_ = KillProc(p)
|
||||
timedOut = true
|
||||
}(pid)
|
||||
|
||||
err = cmd.Wait()
|
||||
|
||||
if timedOut {
|
||||
return [2]string{outb.String(), errb.String()}, ctx.Err()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return [2]string{"", ""}, fmt.Errorf("%s: %s", err, errb.String())
|
||||
return [2]string{outb.String(), errb.String()}, err
|
||||
}
|
||||
|
||||
return [2]string{outb.String(), errb.String()}, nil
|
||||
|
@ -413,9 +440,9 @@ func CMD(exe string, args []string, timeout int, detached bool) (output [2]strin
|
|||
|
||||
// EnablePing enables ping
|
||||
func EnablePing() {
|
||||
fmt.Println("Enabling ping...")
|
||||
args := make([]string, 0)
|
||||
cmd := `netsh advfirewall firewall add rule name="ICMP Allow incoming V4 echo request" protocol=icmpv4:8,any dir=in action=allow`
|
||||
_, err := CMDShell(cmd, false)
|
||||
_, err := CMDShell(args, cmd, 10, false)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
|
@ -423,7 +450,6 @@ func EnablePing() {
|
|||
|
||||
// EnableRDP enables Remote Desktop
|
||||
func EnableRDP() {
|
||||
fmt.Println("Enabling RDP...")
|
||||
k, _, err := registry.CreateKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\Terminal Server`, registry.ALL_ACCESS)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
@ -435,8 +461,9 @@ func EnableRDP() {
|
|||
fmt.Println(err)
|
||||
}
|
||||
|
||||
args := make([]string, 0)
|
||||
cmd := `netsh advfirewall firewall set rule group="remote desktop" new enable=Yes`
|
||||
_, cerr := CMDShell(cmd, false)
|
||||
_, cerr := CMDShell(args, cmd, 10, false)
|
||||
if cerr != nil {
|
||||
fmt.Println(cerr)
|
||||
}
|
||||
|
@ -444,7 +471,6 @@ func EnableRDP() {
|
|||
|
||||
// DisableSleepHibernate disables sleep and hibernate
|
||||
func DisableSleepHibernate() {
|
||||
fmt.Println("Disabling sleep/hibernate...")
|
||||
k, _, err := registry.CreateKey(registry.LOCAL_MACHINE, `SYSTEM\CurrentControlSet\Control\Session Manager\Power`, registry.ALL_ACCESS)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
|
@ -456,21 +482,23 @@ func DisableSleepHibernate() {
|
|||
fmt.Println(err)
|
||||
}
|
||||
|
||||
args := make([]string, 0)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
currents := []string{"ac", "dc"}
|
||||
for _, i := range currents {
|
||||
wg.Add(1)
|
||||
go func(c string) {
|
||||
defer wg.Done()
|
||||
CMDShell(fmt.Sprintf("powercfg /set%svalueindex scheme_current sub_buttons lidaction 0", c), false)
|
||||
CMDShell(fmt.Sprintf("powercfg /x -standby-timeout-%s 0", c), false)
|
||||
CMDShell(fmt.Sprintf("powercfg /x -hibernate-timeout-%s 0", c), false)
|
||||
CMDShell(fmt.Sprintf("powercfg /x -disk-timeout-%s 0", c), false)
|
||||
CMDShell(fmt.Sprintf("powercfg /x -monitor-timeout-%s 0", c), false)
|
||||
_, _ = CMDShell(args, fmt.Sprintf("powercfg /set%svalueindex scheme_current sub_buttons lidaction 0", c), 5, false)
|
||||
_, _ = CMDShell(args, fmt.Sprintf("powercfg /x -standby-timeout-%s 0", c), 5, false)
|
||||
_, _ = CMDShell(args, fmt.Sprintf("powercfg /x -hibernate-timeout-%s 0", c), 5, false)
|
||||
_, _ = CMDShell(args, fmt.Sprintf("powercfg /x -disk-timeout-%s 0", c), 5, false)
|
||||
_, _ = CMDShell(args, fmt.Sprintf("powercfg /x -monitor-timeout-%s 0", c), 5, false)
|
||||
}(i)
|
||||
}
|
||||
wg.Wait()
|
||||
CMDShell("powercfg -S SCHEME_CURRENT", false)
|
||||
_, _ = CMDShell(args, "powercfg -S SCHEME_CURRENT", 5, false)
|
||||
}
|
||||
|
||||
// LoggedOnUser returns active logged on console user
|
||||
|
@ -564,18 +592,7 @@ func (a *WindowsAgent) RecoverSalt() {
|
|||
a.Logger.Debugln("Salt recovery completed on", a.Hostname)
|
||||
}
|
||||
|
||||
//RecoverMesh recovers mesh agent
|
||||
func (a *WindowsAgent) RecoverMesh() {
|
||||
meshSVC := "mesh agent"
|
||||
a.Logger.Debugln("Attempting mesh recovery on", a.Hostname)
|
||||
defer CMD("sc.exe", []string{"start", meshSVC}, 20, false)
|
||||
|
||||
args := []string{"stop", meshSVC}
|
||||
CMD("sc.exe", args, 45, false)
|
||||
WaitForService(meshSVC, "stopped", 5)
|
||||
a.ForceKillMesh()
|
||||
|
||||
var meshexe string
|
||||
func (a *WindowsAgent) getMeshEXE() (meshexe string) {
|
||||
mesh1 := filepath.Join(os.Getenv("ProgramFiles"), "Mesh Agent", "MeshAgent.exe")
|
||||
mesh2 := filepath.Join(a.ProgramDir, a.MeshInstaller)
|
||||
if FileExists(mesh1) {
|
||||
|
@ -583,6 +600,20 @@ func (a *WindowsAgent) RecoverMesh() {
|
|||
} else {
|
||||
meshexe = mesh2
|
||||
}
|
||||
return meshexe
|
||||
}
|
||||
|
||||
//RecoverMesh recovers mesh agent
|
||||
func (a *WindowsAgent) RecoverMesh() {
|
||||
a.Logger.Debugln("Attempting mesh recovery on", a.Hostname)
|
||||
defer CMD("sc.exe", []string{"start", a.MeshSVC}, 20, false)
|
||||
|
||||
args := []string{"stop", a.MeshSVC}
|
||||
CMD("sc.exe", args, 45, false)
|
||||
WaitForService(a.MeshSVC, "stopped", 5)
|
||||
a.ForceKillMesh()
|
||||
|
||||
meshexe := a.getMeshEXE()
|
||||
|
||||
out, err := CMD(meshexe, []string{"-nodeidhex"}, 10, false)
|
||||
if err != nil {
|
||||
|
@ -640,10 +671,7 @@ func (a *WindowsAgent) RecoverMesh() {
|
|||
func (a *WindowsAgent) RecoverCMD(command string) {
|
||||
a.Logger.Debugln("Attempting shell recovery on", a.Hostname)
|
||||
a.Logger.Debugln(command)
|
||||
cmd := exec.Command("cmd.exe", "/C", command)
|
||||
if err := cmd.Run(); err != nil {
|
||||
a.Logger.Debugln(err)
|
||||
}
|
||||
_, _ = CMDShell([]string{}, command, 18000, true)
|
||||
}
|
||||
|
||||
// ShowStatus prints windows service status
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
"github.com/gonutz/w32"
|
||||
)
|
||||
|
||||
type Installer struct {
|
||||
|
@ -32,6 +33,8 @@ type Installer struct {
|
|||
}
|
||||
|
||||
func (a *WindowsAgent) Install(i *Installer) {
|
||||
a.checkExistingAndRemove()
|
||||
|
||||
i.Headers = map[string]string{
|
||||
"content-type": "application/json",
|
||||
"Authorization": fmt.Sprintf("Token %s", i.Token),
|
||||
|
@ -45,14 +48,14 @@ func (a *WindowsAgent) Install(i *Installer) {
|
|||
}
|
||||
|
||||
if u.Scheme != "https" && u.Scheme != "http" {
|
||||
a.installerMsg("Invalid URL (must contain https or http)\nInstallation Failed", "error")
|
||||
a.installerMsg("Invalid URL (must contain https or http)", "error")
|
||||
}
|
||||
|
||||
i.SaltMaster = u.Host
|
||||
a.Logger.Debugln("Salt Master:", i.SaltMaster)
|
||||
|
||||
baseURL := u.Scheme + "://" + u.Host
|
||||
a.Logger.Debugln(baseURL)
|
||||
a.Logger.Debugln("Base URL:", baseURL)
|
||||
|
||||
minion := filepath.Join(a.ProgramDir, a.SaltInstaller)
|
||||
a.Logger.Debugln("Salt Minion:", minion)
|
||||
|
@ -60,7 +63,7 @@ func (a *WindowsAgent) Install(i *Installer) {
|
|||
rClient := resty.New()
|
||||
rClient.SetCloseConnection(true)
|
||||
rClient.SetTimeout(i.Timeout * time.Second)
|
||||
rClient.SetDebug(a.Debug)
|
||||
//rClient.SetDebug(a.Debug)
|
||||
|
||||
// download or copy the salt-minion-setup.exe
|
||||
saltMin := filepath.Join(a.ProgramDir, a.SaltInstaller)
|
||||
|
@ -135,33 +138,41 @@ func (a *WindowsAgent) Install(i *Installer) {
|
|||
|
||||
agentToken := r.Result().(*TokenResp).Token
|
||||
|
||||
// install mesh agent
|
||||
out, err := CMD(mesh, []string{"-fullinstall"}, int(60), false)
|
||||
if err != nil {
|
||||
a.installerMsg(fmt.Sprintf("Failed to install mesh agent: %s", err.Error()), "error")
|
||||
a.Logger.Infoln("Installing mesh agent...")
|
||||
a.Logger.Debugln("Mesh agent:", mesh)
|
||||
meshOut, meshErr := CMD(mesh, []string{"-fullinstall"}, int(60), false)
|
||||
if meshErr != nil {
|
||||
a.installerMsg(fmt.Sprintf("Failed to install mesh agent: %s", meshErr.Error()), "error")
|
||||
}
|
||||
if out[1] != "" {
|
||||
a.installerMsg(fmt.Sprintf("Failed to install mesh agent: %s", out[1]), "error")
|
||||
if meshOut[1] != "" {
|
||||
a.installerMsg(fmt.Sprintf("Failed to install mesh agent: %s", meshOut[1]), "error")
|
||||
}
|
||||
|
||||
WaitForService("mesh agent", "running", 10)
|
||||
fmt.Println(meshOut)
|
||||
|
||||
a.Logger.Debugln("Waiting for mesh service to be running")
|
||||
WaitForService(a.MeshSVC, "running", 15)
|
||||
a.Logger.Debugln("Mesh service is running")
|
||||
a.Logger.Debugln("Sleeping for 10")
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
meshSuccess := false
|
||||
var meshNodeID string
|
||||
for !meshSuccess {
|
||||
pMesh, err := CMD(mesh, []string{"-nodeidhex"}, int(30), false)
|
||||
if err != nil {
|
||||
a.Logger.Errorln(err)
|
||||
a.Logger.Debugln("Getting mesh node id hex")
|
||||
pMesh, pErr := CMD(mesh, []string{"-nodeidhex"}, int(30), false)
|
||||
if pErr != nil {
|
||||
a.Logger.Errorln(pErr)
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
if out[1] != "" {
|
||||
a.Logger.Errorln(out[1])
|
||||
if pMesh[1] != "" {
|
||||
a.Logger.Errorln(pMesh[1])
|
||||
time.Sleep(5 * time.Second)
|
||||
continue
|
||||
}
|
||||
meshNodeID = StripAll(pMesh[0])
|
||||
a.Logger.Debugln("Node id hex:", meshNodeID)
|
||||
if strings.Contains(strings.ToLower(meshNodeID), "not defined") {
|
||||
a.Logger.Errorln(meshNodeID)
|
||||
time.Sleep(5 * time.Second)
|
||||
|
@ -197,7 +208,9 @@ func (a *WindowsAgent) Install(i *Installer) {
|
|||
agentPK := r.Result().(*NewAgentResp).AgentPK
|
||||
saltID := r.Result().(*NewAgentResp).SaltID
|
||||
|
||||
fmt.Println(agentToken, agentPK, saltID)
|
||||
a.Logger.Debugln("Agent token:", agentToken)
|
||||
a.Logger.Debugln("Agent PK:", agentPK)
|
||||
a.Logger.Debugln("Salt ID:", saltID)
|
||||
|
||||
// create the database
|
||||
db, err := sql.Open("sqlite3", filepath.Join(a.ProgramDir, "agentdb.db"))
|
||||
|
@ -240,6 +253,156 @@ func (a *WindowsAgent) Install(i *Installer) {
|
|||
|
||||
// refresh our agent with new values
|
||||
a = New(a.Logger, a.Version)
|
||||
|
||||
// install salt
|
||||
a.Logger.Debugln("changing dir to", a.ProgramDir)
|
||||
cdErr := os.Chdir(a.ProgramDir)
|
||||
if cdErr != nil {
|
||||
a.installerMsg(cdErr.Error(), "error")
|
||||
}
|
||||
|
||||
a.Logger.Infoln("Installing the salt-minion, this might take a while...")
|
||||
saltInstallArgs := []string{
|
||||
a.SaltInstaller,
|
||||
"/S",
|
||||
"/custom-config=saltcustom",
|
||||
fmt.Sprintf("/master=%s", i.SaltMaster),
|
||||
fmt.Sprintf("/minion-name=%s", saltID),
|
||||
"/start-minion=1",
|
||||
}
|
||||
|
||||
a.Logger.Debugln("Installing salt with:", saltInstallArgs)
|
||||
_, saltErr := CMDShell(saltInstallArgs, "", int(i.Timeout), false)
|
||||
if saltErr != nil {
|
||||
a.installerMsg(fmt.Sprintf("Unable to install salt: %s", saltErr.Error()), "error")
|
||||
}
|
||||
|
||||
a.Logger.Debugln("Waiting for salt-minion service enter the running state")
|
||||
WaitForService("salt-minion", "running", 30)
|
||||
a.Logger.Debugln("Salt-minion is running")
|
||||
_, serr := WinServiceGet("salt-minion")
|
||||
if serr != nil {
|
||||
a.installerMsg("Salt installation failed\nCheck the log file in c:\\salt\\var\\log\\salt\\minion", "error")
|
||||
}
|
||||
|
||||
time.Sleep(5 * time.Second)
|
||||
|
||||
// set new headers, no longer knox auth...use agent auth
|
||||
rClient.SetHeaders(a.Headers)
|
||||
|
||||
// accept the salt key on the rmm
|
||||
a.Logger.Debugln("Registering salt with the RMM")
|
||||
acceptPayload := map[string]string{"saltid": saltID, "agent_id": a.AgentID}
|
||||
acceptAttempts := 0
|
||||
acceptRetries := 20
|
||||
for {
|
||||
r, err := rClient.R().SetBody(acceptPayload).Post(fmt.Sprintf("%s/api/v2/saltminion/", baseURL))
|
||||
if err != nil {
|
||||
a.Logger.Debugln(err)
|
||||
acceptAttempts++
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
if r.StatusCode() != 200 {
|
||||
a.Logger.Debugln(r.String())
|
||||
acceptAttempts++
|
||||
time.Sleep(5 * time.Second)
|
||||
} else {
|
||||
acceptAttempts = 0
|
||||
}
|
||||
|
||||
if acceptAttempts == 0 {
|
||||
a.Logger.Debugln(r.String())
|
||||
break
|
||||
} else if acceptAttempts >= acceptRetries {
|
||||
a.installerMsg("Unable to register salt with the RMM\nInstallation failed.", "error")
|
||||
}
|
||||
}
|
||||
|
||||
time.Sleep(10 * time.Second)
|
||||
|
||||
// sync salt modules
|
||||
a.Logger.Debugln("Syncing salt modules")
|
||||
syncPayload := map[string]string{"agent_id": a.AgentID}
|
||||
syncAttempts := 0
|
||||
syncRetries := 20
|
||||
for {
|
||||
r, err := rClient.R().SetBody(syncPayload).Patch(fmt.Sprintf("%s/api/v2/saltminion/", baseURL))
|
||||
if err != nil {
|
||||
a.Logger.Debugln(err)
|
||||
syncAttempts++
|
||||
time.Sleep(5 * time.Second)
|
||||
}
|
||||
|
||||
if r.StatusCode() != 200 {
|
||||
a.Logger.Debugln(r.String())
|
||||
syncAttempts++
|
||||
time.Sleep(5 * time.Second)
|
||||
} else {
|
||||
syncAttempts = 0
|
||||
}
|
||||
|
||||
if syncAttempts == 0 {
|
||||
a.Logger.Debugln(r.String())
|
||||
break
|
||||
} else if syncAttempts >= syncRetries {
|
||||
a.installerMsg("Unable to sync salt modules\nInstallation failed.", "error")
|
||||
}
|
||||
}
|
||||
|
||||
// send wmi sysinfo
|
||||
a.Logger.Debugln("Getting sysinfo with WMI")
|
||||
a.GetWMI()
|
||||
|
||||
// remove existing services if exist
|
||||
services := []string{"tacticalagent", "checkrunner"}
|
||||
for _, svc := range services {
|
||||
_, err := WinServiceGet(svc)
|
||||
if err == nil {
|
||||
a.Logger.Debugln(fmt.Sprintf("Found existing %s service. Removing", svc))
|
||||
_, _ = CMD(a.Nssm, []string{"stop", svc}, 30, false)
|
||||
_, _ = CMD(a.Nssm, []string{"remove", svc, "confirm"}, 30, false)
|
||||
}
|
||||
}
|
||||
|
||||
a.Logger.Infoln("Installing services...")
|
||||
svcCommands := [8][]string{
|
||||
// winagentsvc
|
||||
{"install", "tacticalagent", a.EXE, "-m", "winagentsvc"},
|
||||
{"set", "tacticalagent", "DisplayName", "Tactical RMM Agent"},
|
||||
{"set", "tacticalagent", "Description", "Tactical RMM Agent"},
|
||||
{"start", "tacticalagent"},
|
||||
//checkrunner
|
||||
{"install", "checkrunner", a.EXE, "-m", "checkrunner"},
|
||||
{"set", "checkrunner", "DisplayName", "Tactical RMM Check Runner"},
|
||||
{"set", "checkrunner", "Description", "Tactical RMM Check Runner"},
|
||||
{"start", "checkrunner"},
|
||||
}
|
||||
|
||||
for _, s := range svcCommands {
|
||||
a.Logger.Debugln(s)
|
||||
_, nssmErr := CMD(a.Nssm, s, 15, false)
|
||||
if nssmErr != nil {
|
||||
a.installerMsg(nssmErr.Error(), "error")
|
||||
}
|
||||
}
|
||||
|
||||
if i.Power {
|
||||
a.Logger.Infoln("Disabling sleep/hibernate...")
|
||||
DisableSleepHibernate()
|
||||
}
|
||||
|
||||
if i.Ping {
|
||||
a.Logger.Infoln("Enabling ping...")
|
||||
EnablePing()
|
||||
}
|
||||
|
||||
if i.RDP {
|
||||
a.Logger.Infoln("Enabling RDP...")
|
||||
EnableRDP()
|
||||
}
|
||||
|
||||
a.installerMsg("Installation was successfull!\nAllow a few minutes for the agent to properly display in the RMM", "info")
|
||||
}
|
||||
|
||||
func copyFile(src, dst string) error {
|
||||
|
@ -261,3 +424,29 @@ func copyFile(src, dst string) error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *WindowsAgent) checkExistingAndRemove() {
|
||||
installedMesh := filepath.Join(a.ProgramDir, "Mesh Agent", "MeshAgent.exe")
|
||||
installedSalt := filepath.Join(a.SystemDrive, "\\salt", "uninst.exe")
|
||||
agentDB := filepath.Join(a.ProgramDir, "agentdb.db")
|
||||
if FileExists(installedMesh) || FileExists(installedSalt) || FileExists(agentDB) {
|
||||
tacUninst := filepath.Join(a.ProgramDir, "unins000.exe")
|
||||
tacUninstArgs := []string{tacUninst, "/VERYSILENT", "/SUPPRESSMSGBOXES"}
|
||||
|
||||
window := w32.GetForegroundWindow()
|
||||
if window != 0 {
|
||||
var handle w32.HWND
|
||||
msg := "Existing installation found\nClick OK to remove, then re-run the installer.\nClick Cancel to abort."
|
||||
action := w32.MessageBox(handle, msg, "Tactical RMM", w32.MB_OKCANCEL|w32.MB_ICONWARNING)
|
||||
if action == w32.IDOK {
|
||||
_, _ = CMDShell(tacUninstArgs, "", 60, true)
|
||||
w32.MessageBox(handle, "Uninstall finished", "Tactical RMM", w32.MB_OK|w32.MB_ICONINFORMATION)
|
||||
}
|
||||
} else {
|
||||
fmt.Println("Existing installation found and must be removed before attempting to reinstall.")
|
||||
fmt.Println("Run the following command to uninstall, and then re-run this installer.")
|
||||
fmt.Printf("\"%s\" %s %s", tacUninstArgs[0], tacUninstArgs[1], tacUninstArgs[2])
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,8 +29,8 @@ type HelloPatch struct {
|
|||
BootTime int64 `json:"boot_time"`
|
||||
}
|
||||
|
||||
// RunAsService tacticalagent windows nssm service
|
||||
func (a *WindowsAgent) RunAsService() {
|
||||
// WinAgentSvc tacticalagent windows nssm service
|
||||
func (a *WindowsAgent) WinAgentSvc() {
|
||||
a.Logger.Infoln("Agent service started")
|
||||
var data map[string]interface{}
|
||||
var sleep int
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
|
@ -0,0 +1,9 @@
|
|||
master_tries: -1
|
||||
keysize: 2048
|
||||
multiprocessing: True
|
||||
output: json
|
||||
grains_cache: True
|
||||
grains_refresh_every: 180
|
||||
grains_cache_expiration: 86400
|
||||
enable_fqdn_grains: False
|
||||
log_level: error
|
|
@ -0,0 +1,87 @@
|
|||
#define MyAppName "Tactical RMM Agent"
|
||||
#define MyAppVersion "1.0.0"
|
||||
#define MyAppPublisher "Tactical Techs"
|
||||
#define MyAppURL "https://github.com/wh1te909"
|
||||
#define MyAppExeName "tacticalrmm.exe"
|
||||
#define NSSM "nssm-x86.exe"
|
||||
#define MESHEXE "meshagent-x86.exe"
|
||||
#define SALTUNINSTALL "{sd}\salt\uninst.exe"
|
||||
#define SALTDIR "{sd}\salt"
|
||||
#define MESHDIR "{sd}\Program Files\Mesh Agent"
|
||||
|
||||
[Setup]
|
||||
AppId={{0D34D278-5FAF-4159-A4A0-4E2D2C08139D}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppVerName={#MyAppName}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
AppPublisherURL={#MyAppURL}
|
||||
AppSupportURL={#MyAppURL}
|
||||
AppUpdatesURL={#MyAppURL}
|
||||
DefaultDirName="{sd}\Program Files\TacticalAgent"
|
||||
DisableDirPage=yes
|
||||
DisableProgramGroupPage=yes
|
||||
OutputBaseFilename=winagent-v{#MyAppVersion}-x86
|
||||
SetupIconFile=C:\Users\Public\Documents\rmmagent\build\onit.ico
|
||||
WizardSmallImageFile=C:\Users\Public\Documents\rmmagent\build\onit.bmp
|
||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
|
||||
[Files]
|
||||
Source: "C:\Users\Public\Documents\rmmagent\tacticalrmm.exe"; DestDir: "{app}"; Flags: ignoreversion; BeforeInstall: StopServices;
|
||||
Source: "C:\Users\Public\Documents\rmmagent\build\nssm-x86.exe"; DestDir: "{app}"; Flags: ignoreversion;
|
||||
Source: "C:\Users\Public\Documents\rmmagent\build\saltcustom"; DestDir: "{app}"; Flags: ignoreversion; AfterInstall: StartServices;
|
||||
|
||||
[Icons]
|
||||
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent runascurrentuser
|
||||
|
||||
[UninstallRun]
|
||||
Filename: "{app}\{#NSSM}"; Parameters: "stop tacticalagent"; RunOnceId: "stoptacagent";
|
||||
Filename: "{app}\{#NSSM}"; Parameters: "remove tacticalagent confirm"; RunOnceId: "removetacagent";
|
||||
Filename: "{app}\{#NSSM}"; Parameters: "stop checkrunner"; RunOnceId: "stopcheckrun";
|
||||
Filename: "{app}\{#NSSM}"; Parameters: "remove checkrunner confirm"; RunOnceId: "removecheckrun";
|
||||
;Filename: "{app}\{#MyAppExeName}"; Parameters: "-m cleanup"; RunOnceId: "cleanuprm";
|
||||
Filename: "{#SALTUNINSTALL}"; Parameters: "/S"; RunOnceId: "saltrm";
|
||||
Filename: "{app}\{#MESHEXE}"; Parameters: "-fulluninstall"; RunOnceId: "meshrm";
|
||||
|
||||
[UninstallDelete]
|
||||
Type: filesandordirs; Name: "{app}";
|
||||
Type: filesandordirs; Name: "{#SALTDIR}";
|
||||
Type: filesandordirs; Name: "{#MESHDIR}";
|
||||
|
||||
[Code]
|
||||
procedure StopServices();
|
||||
var
|
||||
ResultCode: Integer;
|
||||
StopTactical: string;
|
||||
StopCheckrunner: string;
|
||||
begin
|
||||
StopTactical := ExpandConstant(' /c "{app}\{#NSSM}"' + ' stop tacticalagent && ping 127.0.0.1 -n 5');
|
||||
StopCheckrunner := ExpandConstant(' /c "{app}\{#NSSM}"' + ' stop checkrunner && ping 127.0.0.1 -n 5');
|
||||
Exec('cmd.exe', StopTactical, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
Exec('cmd.exe', StopCheckrunner, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
end;
|
||||
|
||||
procedure StartServices();
|
||||
var
|
||||
ResultCode: Integer;
|
||||
StartTactical: string;
|
||||
StartCheckrunner: string;
|
||||
begin
|
||||
StartTactical := ExpandConstant(' /c "{app}\{#NSSM}"' + ' start tacticalagent && ping 127.0.0.1 -n 7');
|
||||
StartCheckrunner := ExpandConstant(' /c "{app}\{#NSSM}"' + ' start checkrunner && ping 127.0.0.1 -n 3');
|
||||
Exec('cmd.exe', StartTactical, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
Exec('cmd.exe', StartCheckrunner, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
end;
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
#define MyAppName "Tactical RMM Agent"
|
||||
#define MyAppVersion "1.0.0"
|
||||
#define MyAppPublisher "Tactical Techs"
|
||||
#define MyAppURL "https://github.com/wh1te909"
|
||||
#define MyAppExeName "tacticalrmm.exe"
|
||||
#define NSSM "nssm.exe"
|
||||
#define MESHEXE "meshagent.exe"
|
||||
#define SALTUNINSTALL "{sd}\salt\uninst.exe"
|
||||
#define SALTDIR "{sd}\salt"
|
||||
#define MESHDIR "{sd}\Program Files\Mesh Agent"
|
||||
|
||||
[Setup]
|
||||
AppId={{0D34D278-5FAF-4159-A4A0-4E2D2C08139D}
|
||||
AppName={#MyAppName}
|
||||
AppVersion={#MyAppVersion}
|
||||
AppVerName={#MyAppName}
|
||||
AppPublisher={#MyAppPublisher}
|
||||
AppPublisherURL={#MyAppURL}
|
||||
AppSupportURL={#MyAppURL}
|
||||
AppUpdatesURL={#MyAppURL}
|
||||
DefaultDirName="{sd}\Program Files\TacticalAgent"
|
||||
DisableDirPage=yes
|
||||
DisableProgramGroupPage=yes
|
||||
OutputBaseFilename=winagent-v{#MyAppVersion}
|
||||
SetupIconFile=C:\Users\Public\Documents\rmmagent\build\onit.ico
|
||||
WizardSmallImageFile=C:\Users\Public\Documents\rmmagent\build\onit.bmp
|
||||
UninstallDisplayIcon={app}\{#MyAppExeName}
|
||||
Compression=lzma
|
||||
SolidCompression=yes
|
||||
WizardStyle=modern
|
||||
|
||||
[Languages]
|
||||
Name: "english"; MessagesFile: "compiler:Default.isl"
|
||||
|
||||
[Tasks]
|
||||
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
||||
|
||||
[Files]
|
||||
Source: "C:\Users\Public\Documents\rmmagent\tacticalrmm.exe"; DestDir: "{app}"; Flags: ignoreversion; BeforeInstall: StopServices;
|
||||
Source: "C:\Users\Public\Documents\rmmagent\build\nssm.exe"; DestDir: "{app}"; Flags: ignoreversion;
|
||||
Source: "C:\Users\Public\Documents\rmmagent\build\saltcustom"; DestDir: "{app}"; Flags: ignoreversion; AfterInstall: StartServices;
|
||||
|
||||
[Icons]
|
||||
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
||||
|
||||
[Run]
|
||||
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent runascurrentuser
|
||||
|
||||
[UninstallRun]
|
||||
Filename: "{app}\{#NSSM}"; Parameters: "stop tacticalagent"; RunOnceId: "stoptacagent";
|
||||
Filename: "{app}\{#NSSM}"; Parameters: "remove tacticalagent confirm"; RunOnceId: "removetacagent";
|
||||
Filename: "{app}\{#NSSM}"; Parameters: "stop checkrunner"; RunOnceId: "stopcheckrun";
|
||||
Filename: "{app}\{#NSSM}"; Parameters: "remove checkrunner confirm"; RunOnceId: "removecheckrun";
|
||||
;Filename: "{app}\{#MyAppExeName}"; Parameters: "-m cleanup"; RunOnceId: "cleanuprm";
|
||||
Filename: "{#SALTUNINSTALL}"; Parameters: "/S"; RunOnceId: "saltrm";
|
||||
Filename: "{app}\{#MESHEXE}"; Parameters: "-fulluninstall"; RunOnceId: "meshrm";
|
||||
|
||||
[UninstallDelete]
|
||||
Type: filesandordirs; Name: "{app}";
|
||||
Type: filesandordirs; Name: "{#SALTDIR}";
|
||||
Type: filesandordirs; Name: "{#MESHDIR}";
|
||||
|
||||
[Code]
|
||||
procedure StopServices();
|
||||
var
|
||||
ResultCode: Integer;
|
||||
StopTactical: string;
|
||||
StopCheckrunner: string;
|
||||
begin
|
||||
StopTactical := ExpandConstant(' /c "{app}\{#NSSM}"' + ' stop tacticalagent && ping 127.0.0.1 -n 5');
|
||||
StopCheckrunner := ExpandConstant(' /c "{app}\{#NSSM}"' + ' stop checkrunner && ping 127.0.0.1 -n 5');
|
||||
Exec('cmd.exe', StopTactical, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
Exec('cmd.exe', StopCheckrunner, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
end;
|
||||
|
||||
procedure StartServices();
|
||||
var
|
||||
ResultCode: Integer;
|
||||
StartTactical: string;
|
||||
StartCheckrunner: string;
|
||||
begin
|
||||
StartTactical := ExpandConstant(' /c "{app}\{#NSSM}"' + ' start tacticalagent && ping 127.0.0.1 -n 7');
|
||||
StartCheckrunner := ExpandConstant(' /c "{app}\{#NSSM}"' + ' start checkrunner && ping 127.0.0.1 -n 3');
|
||||
Exec('cmd.exe', StartTactical, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
Exec('cmd.exe', StartCheckrunner, '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
||||
end;
|
||||
|
30
main.go
30
main.go
|
@ -1,18 +1,11 @@
|
|||
//go:generate goversioninfo -64
|
||||
package main
|
||||
|
||||
// cross compile from linux for windows
|
||||
// apt install build-essential gcc-multilib gcc-mingw-w64-x86-64 gcc-mingw-w64-i686
|
||||
// 64 bit: CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc CXX=x86_64-w64-mingw32-g++ GOOS=windows GOARCH=amd64 go build -o tacticalrmm.exe
|
||||
// 32 bit: CGO_ENABLED=1 CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ GOOS=windows GOARCH=386 go build -o tacticalrmm-x86.exe
|
||||
|
||||
// building 32 bit from windows from git bash
|
||||
// env CGO_ENABLED=1 CC=i686-w64-mingw32-gcc CXX=i686-w64-mingw32-g++ GOARCH=386 go build -o tacticalrmm-x86.exe
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/wh1te909/rmmagent/agent"
|
||||
|
@ -35,7 +28,7 @@ func main() {
|
|||
siteID := flag.Int("site-id", 0, "Site ID")
|
||||
timeout := flag.Duration("timeout", 900, "Installer timeout (seconds)")
|
||||
desc := flag.String("desc", hostname, "Agent's Description")
|
||||
atype := flag.String("agent-type", "server", "Server or Workstation")
|
||||
atype := flag.String("agent-type", "server", "server or workstation")
|
||||
token := flag.String("auth", "", "Token")
|
||||
power := flag.Bool("power", false, "Disable sleep/hibernate")
|
||||
rdp := flag.Bool("rdp", false, "Enable RDP")
|
||||
|
@ -64,7 +57,15 @@ func main() {
|
|||
case "checkrunner":
|
||||
a.CheckRunner()
|
||||
case "winagentsvc":
|
||||
a.RunAsService()
|
||||
a.WinAgentSvc()
|
||||
case "runchecks":
|
||||
a.RunChecks()
|
||||
case "sysinfo":
|
||||
a.GetWMI()
|
||||
case "recoversalt":
|
||||
a.RecoverSalt()
|
||||
case "recovermesh":
|
||||
a.RecoverMesh()
|
||||
case "install":
|
||||
log.SetOutput(os.Stdout)
|
||||
if *api == "" || *clientID == 0 || *siteID == 0 || *token == "" {
|
||||
|
@ -108,6 +109,11 @@ func setupLogging(level *string, to *string) {
|
|||
}
|
||||
|
||||
func installUsage() {
|
||||
u := `Usage: tacticalrmm.exe -m install -api <https://api.example.com> -client-id X -site-id X -auth <TOKEN>`
|
||||
fmt.Println(u)
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
u := `Usage: tacticalrmm.exe -m install -api <https://api.example.com> -client-id X -site-id X -auth <TOKEN>`
|
||||
fmt.Println(u)
|
||||
case "linux":
|
||||
// todo
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue