Add: Server variables are opt-out by default

- Pull the Nushell and Deno versions from the server.
- Support downloading Nushell and Deno from a url (not GitHUb).
- Add support for nu config.nu and env.nu files.
- Add support for default Deno permissions.
This commit is contained in:
David Randall 2023-12-03 23:14:27 -05:00
parent 87e1b29ef6
commit 2afdfd7ab8
11 changed files with 610 additions and 387 deletions

View File

@ -89,12 +89,11 @@ const (
nixMeshDir = "/opt/tacticalmesh" nixMeshDir = "/opt/tacticalmesh"
nixAgentBin = nixAgentDir + "/tacticalagent" nixAgentBin = nixAgentDir + "/tacticalagent"
nixAgentBinDir = nixAgentDir + "/bin" nixAgentBinDir = nixAgentDir + "/bin"
nixAgentEtcDir = nixAgentDir + "/etc"
nixMeshAgentBin = nixMeshDir + "/meshagent" nixMeshAgentBin = nixMeshDir + "/meshagent"
macPlistPath = "/Library/LaunchDaemons/tacticalagent.plist" macPlistPath = "/Library/LaunchDaemons/tacticalagent.plist"
macPlistName = "tacticalagent" macPlistName = "tacticalagent"
defaultMacMeshSvcDir = "/usr/local/mesh_services" defaultMacMeshSvcDir = "/usr/local/mesh_services"
nuVersion = "0.87.0"
denoVersion = "v1.38.2"
) )
var defaultWinTmpDir = filepath.Join(os.Getenv("PROGRAMDATA"), "TacticalRMM") var defaultWinTmpDir = filepath.Join(os.Getenv("PROGRAMDATA"), "TacticalRMM")

View File

@ -167,7 +167,7 @@ func NewAgentConfig() *rmm.AgentConfig {
return ret return ret
} }
func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string) (stdout, stderr string, exitcode int, e error) { func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string, nushellEnableConfig bool, denoDefaultPermissions string) (stdout, stderr string, exitcode int, e error) {
code = removeWinNewLines(code) code = removeWinNewLines(code)
content := []byte(code) content := []byte(code)
@ -197,12 +197,21 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int,
opts.IsScript = true opts.IsScript = true
switch shell { switch shell {
case "nushell": case "nushell":
var nushellArgs []string
if nushellEnableConfig {
nushellArgs = []string{
"--config",
path.Join(nixAgentEtcDir, "nushell", "config.nu"),
"--env-config",
path.Join(nixAgentEtcDir, "nushell", "env.nu"),
}
} else {
nushellArgs = []string{"--no-config-file"}
}
opts.Shell = a.NuBin opts.Shell = a.NuBin
opts.Args = append([]string{ opts.Args = nushellArgs
"--no-config-file", opts.Args = append(opts.Args, f.Name())
f.Name(), opts.Args = append(opts.Args, args...)
},
args...)
if !trmm.FileExists(a.NuBin) { if !trmm.FileExists(a.NuBin) {
a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin) a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin)
err := errors.New("File Not Found: " + a.NuBin) err := errors.New("File Not Found: " + a.NuBin)
@ -225,6 +234,8 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int,
// https://docs.deno.com/runtime/manual/basics/permissions#permissions-list // https://docs.deno.com/runtime/manual/basics/permissions#permissions-list
// DENO_PERMISSIONS is not an official environment variable. // DENO_PERMISSIONS is not an official environment variable.
// https://docs.deno.com/runtime/manual/basics/env_variables // https://docs.deno.com/runtime/manual/basics/env_variables
// DENO_DEFAULT_PERMISSIONS is used if not found in the environment variables.
found := false
for i, v := range envVars { for i, v := range envVars {
if strings.HasPrefix(v, "DENO_PERMISSIONS=") { if strings.HasPrefix(v, "DENO_PERMISSIONS=") {
permissions := strings.Split(v, "=")[1] permissions := strings.Split(v, "=")[1]
@ -232,9 +243,13 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int,
// Remove the DENO_PERMISSIONS variable from the environment variables slice. // Remove the DENO_PERMISSIONS variable from the environment variables slice.
// It's possible more variables may exist with the same prefix. // It's possible more variables may exist with the same prefix.
envVars = append(envVars[:i], envVars[i+1:]...) envVars = append(envVars[:i], envVars[i+1:]...)
found = true
break break
} }
} }
if !found && denoDefaultPermissions != "" {
opts.Args = append(opts.Args, strings.Split(denoDefaultPermissions, " ")...)
}
// Can't append a variadic slice after a string arg. // Can't append a variadic slice after a string arg.
// https://pkg.go.dev/builtin#append // https://pkg.go.dev/builtin#append
@ -536,11 +551,321 @@ func (a *Agent) GetWMIInfo() map[string]interface{} {
return wmiInfo return wmiInfo
} }
// windows only below TODO add into stub file // InstallNushell will download nushell from GitHub and install (copy) it to nixAgentBinDir
func (a *Agent) InstallNushell(force bool) {
conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI())
if !conf.InstallNushell {
return
}
if trmm.FileExists(a.NuBin) {
if force {
a.Logger.Debugln(a.NuBin, "InstallNushell(): Forced install. Removing nu binary.")
err := os.Remove(a.NuBin)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error removing nu binary:", err)
return
}
} else {
return
}
}
if !trmm.FileExists(nixAgentBinDir) {
err := os.MkdirAll(nixAgentBinDir, 0755)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error creating nixAgentBinDir:", err)
return
}
}
if conf.NushellEnableConfig {
// Create 0-byte config files for Nushell
nushellPath := path.Join(nixAgentEtcDir, "nushell")
nushellConfig := path.Join(nushellPath, "config.nu")
nushellEnv := path.Join(nushellPath, "env.nu")
if !trmm.FileExists(nushellPath) {
err := os.MkdirAll(nushellPath, 0755)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error creating nixAgentEtcDir/nushell:", err)
return
}
}
if !trmm.FileExists(nushellConfig) {
_, err := os.Create(nushellConfig)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error creating nushell config.nu:", err)
return
}
err = os.Chmod(nushellConfig, 0744)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell config.nu:", err)
return
}
}
if !trmm.FileExists(nushellEnv) {
_, err := os.Create(nushellEnv)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error creating nushell env.nu:", err)
return
}
err = os.Chmod(nushellEnv, 0744)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell env.nu:", err)
return
}
}
}
var (
assetName string
url string
targzDirName string
)
if conf.InstallNushellUrl != "" {
url = conf.InstallNushellUrl
url = strings.Replace(url, "{OS}", runtime.GOOS, -1)
url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1)
url = strings.Replace(url, "{VERSION}", conf.InstallNushellVersion, -1)
} else {
switch runtime.GOOS {
case "darwin":
switch runtime.GOARCH {
case "arm64":
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-darwin-full.tar.gz
assetName = fmt.Sprintf("nu-%s-aarch64-darwin-full.tar.gz", conf.InstallNushellVersion)
default:
a.Logger.Debugln("InstallNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
return
}
case "linux":
switch runtime.GOARCH {
case "amd64":
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-linux-musl-full.tar.gz
assetName = fmt.Sprintf("nu-%s-x86_64-linux-musl-full.tar.gz", conf.InstallNushellVersion)
case "arm64":
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-linux-gnu-full.tar.gz
assetName = fmt.Sprintf("nu-%s-aarch64-linux-gnu-full.tar.gz", conf.InstallNushellVersion)
default:
a.Logger.Debugln("InstallNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
return
}
default:
a.Logger.Debugln("InstallNushell(): Unsupported OS:", runtime.GOOS)
return
}
url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", conf.InstallNushellVersion, assetName)
}
a.Logger.Debugln("InstallNushell(): Nu download url:", url)
tmpDir, err := os.MkdirTemp("", "trmm")
if err != nil {
a.Logger.Errorln("InstallNushell(): Error creating temp directory:", err)
return
}
defer func(path string) {
err := os.RemoveAll(path)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error removing temp directory:", err)
}
}(tmpDir)
tmpAssetName := filepath.Join(tmpDir, assetName)
a.Logger.Debugln("InstallNushell(): tmpAssetName:", tmpAssetName)
rClient := resty.New()
rClient.SetTimeout(20 * time.Minute)
rClient.SetRetryCount(10)
rClient.SetRetryWaitTime(1 * time.Minute)
rClient.SetRetryMaxWaitTime(15 * time.Minute)
if len(a.Proxy) > 0 {
rClient.SetProxy(a.Proxy)
}
r, err := rClient.R().SetOutput(tmpAssetName).Get(url)
if err != nil {
a.Logger.Errorln("InstallNushell(): Unable to download nu:", err)
return
}
if r.IsError() {
a.Logger.Errorln("InstallNushell(): Unable to download nu. Status code:", r.StatusCode())
return
}
if conf.InstallNushellUrl != "" {
// InstallNushellUrl is not compressed.
err = copyFile(path.Join(tmpDir, tmpAssetName), a.NuBin)
if err != nil {
a.Logger.Errorln("InstallNushell(): Failed to copy nu file to install dir:", err)
return
}
} else {
// GitHub asset is tar.gz compressed.
targzDirName, err = a.ExtractTarGz(tmpAssetName, tmpDir)
if err != nil {
a.Logger.Errorln("InstallNushell(): Failed to extract downloaded tar.gz file:", err)
return
}
err = copyFile(path.Join(tmpDir, targzDirName, "nu"), a.NuBin)
if err != nil {
a.Logger.Errorln("InstallNushell(): Failed to copy nu file to install dir:", err)
return
}
}
err = os.Chmod(a.NuBin, 0755)
if err != nil {
a.Logger.Errorln("InstallNushell(): Failed to chmod nu binary:", err)
return
}
}
// InstallDeno will download deno from GitHub and install (copy) it to nixAgentBinDir
func (a *Agent) InstallDeno(force bool) {
conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI())
if !conf.InstallDeno {
return
}
if trmm.FileExists(a.DenoBin) {
if force {
a.Logger.Debugln(a.NuBin, "InstallDeno(): Forced install. Removing deno binary.")
err := os.Remove(a.DenoBin)
if err != nil {
a.Logger.Errorln("InstallDeno(): Error removing deno binary:", err)
return
}
} else {
return
}
}
if !trmm.FileExists(nixAgentBinDir) {
err := os.MkdirAll(nixAgentBinDir, 0755)
if err != nil {
a.Logger.Errorln("InstallDeno(): Error creating nixAgentBinDir:", err)
return
}
}
var (
assetName string
url string
)
if conf.InstallDenoUrl != "" {
url = conf.InstallDenoUrl
url = strings.Replace(url, "{OS}", runtime.GOOS, -1)
url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1)
url = strings.Replace(url, "{VERSION}", conf.InstallDenoVersion, -1)
} else {
switch runtime.GOOS {
case "darwin":
switch runtime.GOARCH {
case "arm64":
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-aarch64-apple-darwin.zip
assetName = fmt.Sprintf("deno-aarch64-apple-darwin.zip")
case "amd64":
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-apple-darwin.zip
assetName = fmt.Sprintf("deno-x86_64-apple-darwin.zip")
default:
a.Logger.Debugln("InstallDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
return
}
case "linux":
switch runtime.GOARCH {
case "amd64":
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-unknown-linux-gnu.zip
assetName = fmt.Sprintf("deno-x86_64-unknown-linux-gnu.zip")
default:
a.Logger.Debugln("InstallDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
return
}
default:
a.Logger.Debugln("InstallDeno(): Unsupported OS:", runtime.GOOS)
return
}
url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", conf.InstallDenoVersion, assetName)
}
a.Logger.Debugln("InstallDeno(): Deno download url:", url)
tmpDir, err := os.MkdirTemp("", "trmm")
if err != nil {
a.Logger.Errorln("InstallDeno(): Error creating temp directory:", err)
return
}
defer func(path string) {
err := os.RemoveAll(path)
if err != nil {
a.Logger.Errorln("InstallDeno(): Error removing temp directory:", err)
}
}(tmpDir)
tmpAssetName := filepath.Join(tmpDir, assetName)
a.Logger.Debugln("InstallDeno(): tmpAssetName:", tmpAssetName)
rClient := resty.New()
rClient.SetTimeout(20 * time.Minute)
rClient.SetRetryCount(10)
rClient.SetRetryWaitTime(1 * time.Minute)
rClient.SetRetryMaxWaitTime(15 * time.Minute)
if len(a.Proxy) > 0 {
rClient.SetProxy(a.Proxy)
}
r, err := rClient.R().SetOutput(tmpAssetName).Get(url)
if err != nil {
a.Logger.Errorln("InstallDeno(): Unable to download deno:", err)
return
}
if r.IsError() {
a.Logger.Errorln("InstallDeno(): Unable to download deno. Status code:", r.StatusCode())
return
}
if conf.InstallDenoUrl != "" {
// InstallDenoUrl is not compressed.
err = copyFile(path.Join(tmpDir, tmpAssetName), a.DenoBin)
if err != nil {
a.Logger.Errorln("InstallDeno(): Failed to copy deno file to install dir:", err)
return
}
} else {
// GitHub asset is zip compressed.
err = Unzip(tmpAssetName, tmpDir)
if err != nil {
a.Logger.Errorln("InstallDeno(): Failed to unzip downloaded zip file:", err)
return
}
err = copyFile(path.Join(tmpDir, "deno"), a.DenoBin)
if err != nil {
a.Logger.Errorln("InstallDeno(): Failed to copy deno file to install dir:", err)
return
}
}
err = os.Chmod(a.DenoBin, 0755)
if err != nil {
a.Logger.Errorln("InstallDeno(): Failed to chmod deno binary:", err)
return
}
}
// GetAgentCheckInConfig will get the agent configuration from the server.
// The Windows agent stores the configuration in the registry. The UNIX agent does not store the config.
// @return AgentCheckInConfig
func (a *Agent) GetAgentCheckInConfig(ret AgentCheckInConfig) AgentCheckInConfig { func (a *Agent) GetAgentCheckInConfig(ret AgentCheckInConfig) AgentCheckInConfig {
// TODO: Persist the config to disk.
return ret return ret
} }
// windows only below TODO add into stub file
func (a *Agent) PlatVer() (string, error) { return "", nil } func (a *Agent) PlatVer() (string, error) { return "", nil }
func (a *Agent) SendSoftware() {} func (a *Agent) SendSoftware() {}
@ -553,235 +878,6 @@ func GetServiceStatus(name string) (string, error) { return "", nil }
func (a *Agent) GetPython(force bool) {} func (a *Agent) GetPython(force bool) {}
// GetNushell will download nushell from GitHub and install (copy) it to nixAgentBinDir
func (a *Agent) GetNushell(force bool) {
if trmm.FileExists(a.NuBin) {
if force {
err := os.Remove(a.NuBin)
if err != nil {
a.Logger.Errorln("GetNushell(): Error removing nu binary:", err)
return
}
} else {
return
}
}
if !trmm.FileExists(nixAgentBinDir) {
err := os.MkdirAll(nixAgentBinDir, 0755)
if err != nil {
a.Logger.Errorln("GetNushell(): Error creating nixAgentBinDir:", err)
return
}
}
var (
assetName string
url string
targzDirName string
)
switch runtime.GOOS {
case "darwin":
switch runtime.GOARCH {
case "arm64":
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-darwin-full.tar.gz
assetName = fmt.Sprintf("nu-%s-aarch64-darwin-full.tar.gz", nuVersion)
default:
a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
return
}
case "linux":
switch runtime.GOARCH {
case "amd64":
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-linux-musl-full.tar.gz
assetName = fmt.Sprintf("nu-%s-x86_64-linux-musl-full.tar.gz", nuVersion)
case "arm64":
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-linux-gnu-full.tar.gz
assetName = fmt.Sprintf("nu-%s-aarch64-linux-gnu-full.tar.gz", nuVersion)
default:
a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
return
}
default:
a.Logger.Debugln("GetNushell(): Unsupported OS:", runtime.GOOS)
return
}
url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", nuVersion, assetName)
a.Logger.Debugln("GetNushell(): Nu download url:", url)
tmpDir, err := os.MkdirTemp("", "trmm")
if err != nil {
a.Logger.Errorln("GetNushell(): Error creating temp directory:", err)
return
}
defer func(path string) {
err := os.RemoveAll(path)
if err != nil {
a.Logger.Errorln("GetNushell(): Error removing temp directory:", err)
}
}(tmpDir)
tmpAssetName := filepath.Join(tmpDir, assetName)
a.Logger.Debugln("GetNushell(): tmpAssetName:", tmpAssetName)
rClient := resty.New()
rClient.SetTimeout(20 * time.Minute)
rClient.SetRetryCount(10)
rClient.SetRetryWaitTime(1 * time.Minute)
rClient.SetRetryMaxWaitTime(15 * time.Minute)
if len(a.Proxy) > 0 {
rClient.SetProxy(a.Proxy)
}
r, err := rClient.R().SetOutput(tmpAssetName).Get(url)
if err != nil {
a.Logger.Errorln("GetNushell(): Unable to download nu from github.", err)
return
}
if r.IsError() {
a.Logger.Errorln("GetNushell(): Unable to download nu from github. Status code", r.StatusCode())
return
}
targzDirName, err = a.ExtractTarGz(tmpAssetName, tmpDir)
if err != nil {
a.Logger.Errorln("GetNushell(): Failed to extract downloaded tar.gz file:", err)
return
}
err = copyFile(path.Join(tmpDir, targzDirName, "nu"), a.NuBin)
if err != nil {
a.Logger.Errorln("GetNushell(): Failed to copy nu file to install dir:", err)
return
}
err = os.Chmod(a.NuBin, 0755)
if err != nil {
a.Logger.Errorln("GetNushell(): Failed to chmod nu binary:", err)
return
}
}
// GetDeno will download deno from GitHub and install (copy) it to nixAgentBinDir
func (a *Agent) GetDeno(force bool) {
if trmm.FileExists(a.DenoBin) {
if force {
err := os.Remove(a.DenoBin)
if err != nil {
a.Logger.Errorln("GetDeno(): Error removing deno binary:", err)
return
}
} else {
return
}
}
if !trmm.FileExists(nixAgentBinDir) {
err := os.MkdirAll(nixAgentBinDir, 0755)
if err != nil {
a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err)
return
}
}
var (
assetName string
url string
)
switch runtime.GOOS {
case "darwin":
switch runtime.GOARCH {
case "arm64":
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-aarch64-apple-darwin.zip
assetName = fmt.Sprintf("deno-aarch64-apple-darwin.zip")
case "amd64":
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-apple-darwin.zip
assetName = fmt.Sprintf("deno-x86_64-apple-darwin.zip")
default:
a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
return
}
case "linux":
switch runtime.GOARCH {
case "amd64":
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-unknown-linux-gnu.zip
assetName = fmt.Sprintf("deno-x86_64-unknown-linux-gnu.zip")
default:
a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
return
}
default:
a.Logger.Debugln("GetDeno(): Unsupported OS:", runtime.GOOS)
return
}
url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", denoVersion, assetName)
a.Logger.Debugln("GetDeno(): Deno download url:", url)
tmpDir, err := os.MkdirTemp("", "trmm")
if err != nil {
a.Logger.Errorln("GetDeno(): Error creating temp directory:", err)
return
}
defer func(path string) {
err := os.RemoveAll(path)
if err != nil {
a.Logger.Errorln("GetDeno(): Error removing temp directory:", err)
}
}(tmpDir)
tmpAssetName := filepath.Join(tmpDir, assetName)
a.Logger.Debugln("GetDeno(): tmpAssetName:", tmpAssetName)
if !trmm.FileExists(nixAgentBinDir) {
err = os.MkdirAll(nixAgentBinDir, 0755)
if err != nil {
a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err)
return
}
}
rClient := resty.New()
rClient.SetTimeout(20 * time.Minute)
rClient.SetRetryCount(10)
rClient.SetRetryWaitTime(1 * time.Minute)
rClient.SetRetryMaxWaitTime(15 * time.Minute)
if len(a.Proxy) > 0 {
rClient.SetProxy(a.Proxy)
}
r, err := rClient.R().SetOutput(tmpAssetName).Get(url)
if err != nil {
a.Logger.Errorln("GetDeno(): Unable to download deno from github.", err)
return
}
if r.IsError() {
a.Logger.Errorln("GetDeno(): Unable to download deno from github. Status code", r.StatusCode())
return
}
err = Unzip(tmpAssetName, tmpDir)
if err != nil {
a.Logger.Errorln("GetDeno(): Failed to unzip downloaded zip file:", err)
return
}
err = copyFile(path.Join(tmpDir, "deno"), a.DenoBin)
if err != nil {
a.Logger.Errorln("GetDeno(): Failed to copy deno file to install dir:", err)
return
}
err = os.Chmod(a.DenoBin, 0755)
if err != nil {
a.Logger.Errorln("GetDeno(): Failed to chmod deno binary:", err)
return
}
}
type SchedTask struct{ Name string } type SchedTask struct{ Name string }
func (a *Agent) PatchMgmnt(enable bool) error { return nil } func (a *Agent) PatchMgmnt(enable bool) error { return nil }

View File

@ -92,7 +92,7 @@ func NewAgentConfig() *rmm.AgentConfig {
} }
} }
func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string) (stdout, stderr string, exitcode int, e error) { func (a *Agent) RunScript(code string, shell string, args []string, timeout int, runasuser bool, envVars []string, nushellEnableConfig bool, denoDefaultPermissions string) (stdout, stderr string, exitcode int, e error) {
content := []byte(code) content := []byte(code)
@ -158,7 +158,18 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int,
exe = tmpfn.Name() exe = tmpfn.Name()
case "nushell": case "nushell":
exe = a.NuBin exe = a.NuBin
cmdArgs = []string{"--no-config-file", tmpfn.Name()} var nushellArgs []string
if nushellEnableConfig {
nushellArgs = []string{
"--config",
path.Join(a.ProgramDir, "etc", "nushell", "config.nu"),
"--env-config",
path.Join(a.ProgramDir, "etc", "nushell", "env.nu"),
}
} else {
nushellArgs = []string{"--no-config-file"}
}
cmdArgs = append(nushellArgs, tmpfn.Name())
if !trmm.FileExists(a.NuBin) { if !trmm.FileExists(a.NuBin) {
a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin) a.Logger.Errorln("RunScript(): Executable does not exist. Install Nu and try again:", a.NuBin)
err := errors.New("File Not Found: " + a.NuBin) err := errors.New("File Not Found: " + a.NuBin)
@ -177,6 +188,8 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int,
// https://docs.deno.com/runtime/manual/basics/permissions#permissions-list // https://docs.deno.com/runtime/manual/basics/permissions#permissions-list
// DENO_PERMISSIONS is not an official environment variable. // DENO_PERMISSIONS is not an official environment variable.
// https://docs.deno.com/runtime/manual/basics/env_variables // https://docs.deno.com/runtime/manual/basics/env_variables
// DENO_DEFAULT_PERMISSIONS is used if not found in the environment variables.
found := false
for i, v := range envVars { for i, v := range envVars {
if strings.HasPrefix(v, "DENO_PERMISSIONS=") { if strings.HasPrefix(v, "DENO_PERMISSIONS=") {
permissions := strings.Split(v, "=")[1] permissions := strings.Split(v, "=")[1]
@ -184,12 +197,13 @@ func (a *Agent) RunScript(code string, shell string, args []string, timeout int,
// Remove the DENO_PERMISSIONS variable from the environment variables slice. // Remove the DENO_PERMISSIONS variable from the environment variables slice.
// It's possible more variables may exist with the same prefix. // It's possible more variables may exist with the same prefix.
envVars = append(envVars[:i], envVars[i+1:]...) envVars = append(envVars[:i], envVars[i+1:]...)
found = true
break break
} }
} }
if !found && denoDefaultPermissions != "" {
// Can't append a variadic slice after a string arg. cmdArgs = append(cmdArgs, strings.Split(denoDefaultPermissions, " ")...)
// https://pkg.go.dev/builtin#append }
cmdArgs = append(cmdArgs, tmpfn.Name()) cmdArgs = append(cmdArgs, tmpfn.Name())
} }
@ -879,14 +893,20 @@ func (a *Agent) GetPython(force bool) {
} }
} }
// GetNushell will download nushell from GitHub and install (copy) it to ProgramDir\bin, where ProgramDir is // InstallNushell will download nushell from GitHub and install (copy) it to ProgramDir\bin, where ProgramDir is
// initialized to C:\Program Files\TacticalAgent // initialized to C:\Program Files\TacticalAgent
func (a *Agent) GetNushell(force bool) { func (a *Agent) InstallNushell(force bool) {
conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI())
if !conf.InstallNushell {
return
}
if trmm.FileExists(a.NuBin) { if trmm.FileExists(a.NuBin) {
if force { if force {
a.Logger.Debugln(a.NuBin, "InstallNushell(): Forced install. Removing nu.exe binary.")
err := os.Remove(a.NuBin) err := os.Remove(a.NuBin)
if err != nil { if err != nil {
a.Logger.Errorln("GetNushell(): Error removing nu binary:", err) a.Logger.Errorln("InstallNushell(): Error removing nu.exe binary:", err)
return return
} }
} else { } else {
@ -898,50 +918,96 @@ func (a *Agent) GetNushell(force bool) {
if !trmm.FileExists(programBinDir) { if !trmm.FileExists(programBinDir) {
err := os.MkdirAll(programBinDir, 0755) err := os.MkdirAll(programBinDir, 0755)
if err != nil { if err != nil {
a.Logger.Errorln("GetNushell(): Error creating Program Files bin folder:", err) a.Logger.Errorln("InstallNushell(): Error creating Program Files bin folder:", err)
return return
} }
} }
if conf.NushellEnableConfig {
// Create 0-byte config files for Nushell
nushellPath := path.Join(a.ProgramDir, "etc", "nushell")
nushellConfig := path.Join(nushellPath, "config.nu")
nushellEnv := path.Join(nushellPath, "env.nu")
if !trmm.FileExists(nushellPath) {
err := os.MkdirAll(nushellPath, 0755)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error creating Program Files/nushell:", err)
return
}
}
if !trmm.FileExists(nushellConfig) {
_, err := os.Create(nushellConfig)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error creating nushell config.nu:", err)
return
}
err = os.Chmod(nushellConfig, 0744)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell config.nu:", err)
return
}
}
if !trmm.FileExists(nushellEnv) {
_, err := os.Create(nushellEnv)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error creating nushell env.nu:", err)
return
}
err = os.Chmod(nushellEnv, 0744)
if err != nil {
a.Logger.Errorln("InstallNushell(): Error changing permissions for nushell env.nu:", err)
return
}
}
}
var ( var (
assetName string assetName string
url string url string
) )
switch runtime.GOOS { if conf.InstallNushellUrl != "" {
case "windows": url = conf.InstallNushellUrl
switch runtime.GOARCH { url = strings.Replace(url, "{OS}", runtime.GOOS, -1)
case "amd64": url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1)
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-windows-msvc-full.zip url = strings.Replace(url, "{VERSION}", conf.InstallNushellVersion, -1)
assetName = fmt.Sprintf("nu-%s-x86_64-windows-msvc-full.zip", nuVersion) } else {
case "arm64": switch runtime.GOOS {
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-windows-msvc-full.zip case "windows":
assetName = fmt.Sprintf("nu-%s-aarch64-windows-msvc-full.zip", nuVersion) switch runtime.GOARCH {
case "amd64":
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-x86_64-windows-msvc-full.zip
assetName = fmt.Sprintf("nu-%s-x86_64-windows-msvc-full.zip", conf.InstallNushellVersion)
case "arm64":
// https://github.com/nushell/nushell/releases/download/0.87.0/nu-0.87.0-aarch64-windows-msvc-full.zip
assetName = fmt.Sprintf("nu-%s-aarch64-windows-msvc-full.zip", conf.InstallNushellVersion)
default:
a.Logger.Debugln("InstallNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
return
}
default: default:
a.Logger.Debugln("GetNushell(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) a.Logger.Debugln("InstallNushell(): Unsupported OS:", runtime.GOOS)
return return
} }
default: url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", conf.InstallNushellVersion, assetName)
a.Logger.Debugln("GetNushell(): Unsupported OS:", runtime.GOOS)
return
} }
url = fmt.Sprintf("https://github.com/nushell/nushell/releases/download/%s/%s", nuVersion, assetName) a.Logger.Debugln("InstallNushell(): Nu download url:", url)
a.Logger.Debugln("GetNushell(): Nu download url:", url)
tmpDir, err := os.MkdirTemp("", "trmm") tmpDir, err := os.MkdirTemp("", "trmm")
if err != nil { if err != nil {
a.Logger.Errorln("GetNushell(): Error creating temp directory:", err) a.Logger.Errorln("InstallNushell(): Error creating temp directory:", err)
return return
} }
defer func(path string) { defer func(path string) {
err := os.RemoveAll(path) err := os.RemoveAll(path)
if err != nil { if err != nil {
a.Logger.Errorln("GetNushell(): Error removing temp directory:", err) a.Logger.Errorln("InstallNushell(): Error removing temp directory:", err)
} }
}(tmpDir) }(tmpDir)
tmpAssetName := filepath.Join(tmpDir, assetName) tmpAssetName := filepath.Join(tmpDir, assetName)
a.Logger.Debugln("GetNushell(): tmpAssetName:", tmpAssetName) a.Logger.Debugln("InstallNushell(): tmpAssetName:", tmpAssetName)
rClient := resty.New() rClient := resty.New()
rClient.SetTimeout(20 * time.Minute) rClient.SetTimeout(20 * time.Minute)
@ -954,35 +1020,50 @@ func (a *Agent) GetNushell(force bool) {
r, err := rClient.R().SetOutput(tmpAssetName).Get(url) r, err := rClient.R().SetOutput(tmpAssetName).Get(url)
if err != nil { if err != nil {
a.Logger.Errorln("GetNushell(): Unable to download nu from github.", err) a.Logger.Errorln("InstallNushell(): Unable to download nu:", err)
return return
} }
if r.IsError() { if r.IsError() {
a.Logger.Errorln("GetNushell(): Unable to download nu from github. Status code", r.StatusCode()) a.Logger.Errorln("InstallNushell(): Unable to download nu. Status code:", r.StatusCode())
return return
} }
err = Unzip(tmpAssetName, tmpDir) if conf.InstallNushellUrl != "" {
if err != nil { // InstallNushellUrl is not compressed.
a.Logger.Errorln("GetNushell(): Failed to unzip downloaded zip file:", err) err = copyFile(path.Join(tmpDir, tmpAssetName), a.NuBin)
return if err != nil {
} a.Logger.Errorln("InstallNushell(): Failed to copy nu file to install dir:", err)
return
}
} else {
err = Unzip(tmpAssetName, tmpDir)
if err != nil {
a.Logger.Errorln("InstallNushell(): Failed to unzip downloaded zip file:", err)
return
}
err = copyFile(path.Join(tmpDir, "nu.exe"), a.NuBin) err = copyFile(path.Join(tmpDir, "nu.exe"), a.NuBin)
if err != nil { if err != nil {
a.Logger.Errorln("GetNushell(): Failed to copy nu.exe file to install dir:", err) a.Logger.Errorln("InstallNushell(): Failed to copy nu.exe file to install dir:", err)
return return
}
} }
} }
// GetDeno will download deno from GitHub and install (copy) it to nixAgentBinDir // InstallDeno will download deno from GitHub and install (copy) it to ProgramDir\bin, where ProgramDir is
func (a *Agent) GetDeno(force bool) { // initialized to C:\Program Files\TacticalAgent
func (a *Agent) InstallDeno(force bool) {
conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI())
if !conf.InstallDeno {
return
}
if trmm.FileExists(a.DenoBin) { if trmm.FileExists(a.DenoBin) {
if force { if force {
err := os.Remove(a.DenoBin) err := os.Remove(a.DenoBin)
if err != nil { if err != nil {
a.Logger.Errorln("GetDeno(): Error removing deno binary:", err) a.Logger.Errorln("InstallDeno(): Error removing deno binary:", err)
return return
} }
} else { } else {
@ -994,7 +1075,7 @@ func (a *Agent) GetDeno(force bool) {
if !trmm.FileExists(programBinDir) { if !trmm.FileExists(programBinDir) {
err := os.MkdirAll(programBinDir, 0755) err := os.MkdirAll(programBinDir, 0755)
if err != nil { if err != nil {
a.Logger.Errorln("GetDeno(): Error creating Program Files bin folder:", err) a.Logger.Errorln("InstallDeno(): Error creating Program Files bin folder:", err)
return return
} }
} }
@ -1004,45 +1085,44 @@ func (a *Agent) GetDeno(force bool) {
url string url string
) )
switch runtime.GOOS { if conf.InstallDenoUrl != "" {
case "windows": url = conf.InstallDenoUrl
switch runtime.GOARCH { url = strings.Replace(url, "{OS}", runtime.GOOS, -1)
case "amd64": url = strings.Replace(url, "{ARCH}", runtime.GOARCH, -1)
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-pc-windows-msvc.zip url = strings.Replace(url, "{VERSION}", conf.InstallDenoVersion, -1)
assetName = fmt.Sprintf("deno-x86_64-pc-windows-msvc.zip") } else {
switch runtime.GOOS {
case "windows":
switch runtime.GOARCH {
case "amd64":
// https://github.com/denoland/deno/releases/download/v1.38.2/deno-x86_64-pc-windows-msvc.zip
assetName = fmt.Sprintf("deno-x86_64-pc-windows-msvc.zip")
default:
a.Logger.Debugln("InstallDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS)
return
}
default: default:
a.Logger.Debugln("GetDeno(): Unsupported architecture and OS:", runtime.GOARCH, runtime.GOOS) a.Logger.Debugln("InstallDeno(): Unsupported OS:", runtime.GOOS)
return return
} }
default: url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", conf.InstallDenoVersion, assetName)
a.Logger.Debugln("GetDeno(): Unsupported OS:", runtime.GOOS)
return
} }
url = fmt.Sprintf("https://github.com/denoland/deno/releases/download/%s/%s", denoVersion, assetName) a.Logger.Debugln("InstallDeno(): Deno download url:", url)
a.Logger.Debugln("GetDeno(): Deno download url:", url)
tmpDir, err := os.MkdirTemp("", "trmm") tmpDir, err := os.MkdirTemp("", "trmm")
if err != nil { if err != nil {
a.Logger.Errorln("GetDeno(): Error creating temp directory:", err) a.Logger.Errorln("InstallDeno(): Error creating temp directory:", err)
return return
} }
defer func(path string) { defer func(path string) {
err := os.RemoveAll(path) err := os.RemoveAll(path)
if err != nil { if err != nil {
a.Logger.Errorln("GetDeno(): Error removing temp directory:", err) a.Logger.Errorln("InstallDeno(): Error removing temp directory:", err)
} }
}(tmpDir) }(tmpDir)
tmpAssetName := filepath.Join(tmpDir, assetName) tmpAssetName := filepath.Join(tmpDir, assetName)
a.Logger.Debugln("GetDeno(): tmpAssetName:", tmpAssetName) a.Logger.Debugln("InstallDeno(): tmpAssetName:", tmpAssetName)
if !trmm.FileExists(nixAgentBinDir) {
err = os.MkdirAll(nixAgentBinDir, 0755)
if err != nil {
a.Logger.Errorln("GetDeno(): Error creating nixAgentBinDir:", err)
return
}
}
rClient := resty.New() rClient := resty.New()
rClient.SetTimeout(20 * time.Minute) rClient.SetTimeout(20 * time.Minute)
@ -1055,24 +1135,34 @@ func (a *Agent) GetDeno(force bool) {
r, err := rClient.R().SetOutput(tmpAssetName).Get(url) r, err := rClient.R().SetOutput(tmpAssetName).Get(url)
if err != nil { if err != nil {
a.Logger.Errorln("GetDeno(): Unable to download deno from github.", err) a.Logger.Errorln("InstallDeno(): Unable to download deno:", err)
return return
} }
if r.IsError() { if r.IsError() {
a.Logger.Errorln("GetDeno(): Unable to download deno from github. Status code", r.StatusCode()) a.Logger.Errorln("InstallDeno(): Unable to download deno. Status code:", r.StatusCode())
return return
} }
err = Unzip(tmpAssetName, tmpDir) if conf.InstallDenoUrl != "" {
if err != nil { // InstallDenoUrl is not compressed.
a.Logger.Errorln("GetDeno(): Failed to unzip downloaded zip file:", err) err = copyFile(path.Join(tmpDir, tmpAssetName), a.DenoBin)
return if err != nil {
} a.Logger.Errorln("InstallDeno(): Failed to copy deno file to install dir:", err)
return
}
} else {
// GitHub asset is zip compressed.
err = Unzip(tmpAssetName, tmpDir)
if err != nil {
a.Logger.Errorln("InstallDeno(): Failed to unzip downloaded zip file:", err)
return
}
err = copyFile(path.Join(tmpDir, "deno.exe"), a.DenoBin) err = copyFile(path.Join(tmpDir, "deno.exe"), a.DenoBin)
if err != nil { if err != nil {
a.Logger.Errorln("GetDeno(): Failed to copy deno.exe file to install dir:", err) a.Logger.Errorln("InstallDeno(): Failed to copy deno.exe file to install dir:", err)
return return
}
} }
} }

View File

@ -169,7 +169,7 @@ type ScriptCheckResult struct {
// ScriptCheck runs either bat, powershell or python script // ScriptCheck runs either bat, powershell or python script
func (a *Agent) ScriptCheck(data rmm.Check, r *resty.Client) { func (a *Agent) ScriptCheck(data rmm.Check, r *resty.Client) {
start := time.Now() start := time.Now()
stdout, stderr, retcode, _ := a.RunScript(data.Script.Code, data.Script.Shell, data.ScriptArgs, data.Timeout, data.Script.RunAsUser, data.EnvVars) stdout, stderr, retcode, _ := a.RunScript(data.Script.Code, data.Script.Shell, data.ScriptArgs, data.Timeout, data.Script.RunAsUser, data.EnvVars, data.NushellEnableConfig, data.DenoDefaultPermissions)
payload := ScriptCheckResult{ payload := ScriptCheckResult{
ID: data.CheckPK, ID: data.CheckPK,

View File

@ -45,7 +45,7 @@ func (a *Agent) InstallChoco() {
return return
} }
_, _, exitcode, err := a.RunScript(string(r.Body()), "powershell", []string{}, 900, false, []string{}) _, _, exitcode, err := a.RunScript(string(r.Body()), "powershell", []string{}, 900, false, []string{}, false, "")
if err != nil { if err != nil {
a.Logger.Debugln(err) a.Logger.Debugln(err)
a.rClient.R().SetBody(result).Post(url) a.rClient.R().SetBody(result).Post(url)

View File

@ -20,5 +20,5 @@ import _ "embed"
var ventura_mesh_fix string var ventura_mesh_fix string
func (a *Agent) FixVenturaMesh() { func (a *Agent) FixVenturaMesh() {
a.RunScript(ventura_mesh_fix, "foo", []string{}, 45, false, []string{}) a.RunScript(ventura_mesh_fix, "foo", []string{}, 45, false, []string{}, false, "")
} }

View File

@ -26,22 +26,24 @@ import (
) )
type NatsMsg struct { type NatsMsg struct {
Func string `json:"func"` Func string `json:"func"`
Timeout int `json:"timeout"` Timeout int `json:"timeout"`
Data map[string]string `json:"payload"` Data map[string]string `json:"payload"`
ScriptArgs []string `json:"script_args"` ScriptArgs []string `json:"script_args"`
ProcPID int32 `json:"procpid"` ProcPID int32 `json:"procpid"`
TaskPK int `json:"taskpk"` TaskPK int `json:"taskpk"`
ScheduledTask SchedTask `json:"schedtaskpayload"` ScheduledTask SchedTask `json:"schedtaskpayload"`
RecoveryCommand string `json:"recoverycommand"` RecoveryCommand string `json:"recoverycommand"`
UpdateGUIDs []string `json:"guids"` UpdateGUIDs []string `json:"guids"`
ChocoProgName string `json:"choco_prog_name"` ChocoProgName string `json:"choco_prog_name"`
PendingActionPK int `json:"pending_action_pk"` PendingActionPK int `json:"pending_action_pk"`
PatchMgmt bool `json:"patch_mgmt"` PatchMgmt bool `json:"patch_mgmt"`
ID int `json:"id"` ID int `json:"id"`
Code string `json:"code"` Code string `json:"code"`
RunAsUser bool `json:"run_as_user"` RunAsUser bool `json:"run_as_user"`
EnvVars []string `json:"env_vars"` EnvVars []string `json:"env_vars"`
NushellEnableConfig bool `json:"nushell_enable_config"`
DenoDefaultPermissions string `json:"deno_default_permissions"`
} }
var ( var (
@ -264,7 +266,7 @@ func (a *Agent) RunRPC() {
var resultData rmm.RunScriptResp var resultData rmm.RunScriptResp
ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle)) ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle))
start := time.Now() start := time.Now()
stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars) stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars, p.NushellEnableConfig, p.DenoDefaultPermissions)
resultData.ExecTime = time.Since(start).Seconds() resultData.ExecTime = time.Since(start).Seconds()
resultData.ID = p.ID resultData.ID = p.ID
@ -294,7 +296,7 @@ func (a *Agent) RunRPC() {
var retData rmm.RunScriptResp var retData rmm.RunScriptResp
ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle)) ret := codec.NewEncoderBytes(&resp, new(codec.MsgpackHandle))
start := time.Now() start := time.Now()
stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars) stdout, stderr, retcode, err := a.RunScript(p.Data["code"], p.Data["shell"], p.ScriptArgs, p.Timeout, p.RunAsUser, p.EnvVars, p.NushellEnableConfig, p.DenoDefaultPermissions)
retData.ExecTime = time.Since(start).Seconds() retData.ExecTime = time.Since(start).Seconds()
if err != nil { if err != nil {
@ -438,9 +440,9 @@ func (a *Agent) RunRPC() {
case "installpython": case "installpython":
go a.GetPython(true) go a.GetPython(true)
case "installnushell": case "installnushell":
go a.GetNushell(true) go a.InstallNushell(true)
case "installdeno": case "installdeno":
go a.GetDeno(true) go a.InstallDeno(true)
case "installchoco": case "installchoco":
go a.InstallChoco() go a.InstallChoco()
case "installwithchoco": case "installwithchoco":

View File

@ -29,15 +29,23 @@ func (a *Agent) RunAsService(nc *nats.Conn) {
} }
type AgentCheckInConfig struct { type AgentCheckInConfig struct {
Hello int `json:"checkin_hello"` Hello int `json:"checkin_hello"`
AgentInfo int `json:"checkin_agentinfo"` AgentInfo int `json:"checkin_agentinfo"`
WinSvc int `json:"checkin_winsvc"` WinSvc int `json:"checkin_winsvc"`
PubIP int `json:"checkin_pubip"` PubIP int `json:"checkin_pubip"`
Disks int `json:"checkin_disks"` Disks int `json:"checkin_disks"`
SW int `json:"checkin_sw"` SW int `json:"checkin_sw"`
WMI int `json:"checkin_wmi"` WMI int `json:"checkin_wmi"`
SyncMesh int `json:"checkin_syncmesh"` SyncMesh int `json:"checkin_syncmesh"`
LimitData bool `json:"limit_data"` LimitData bool `json:"limit_data"`
InstallNushell bool `json:"install_nushell"`
InstallNushellVersion string `json:"install_nushell_version"`
InstallNushellUrl string `json:"install_nushell_url"`
NushellEnableConfig bool `json:"nushell_enable_config"`
InstallDeno bool `json:"install_deno"`
InstallDenoVersion string `json:"install_deno_version"`
InstallDenoUrl string `json:"install_deno_url"`
DenoDefaultPermissions string `json:"deno_default_permissions"`
} }
func (a *Agent) AgentSvc(nc *nats.Conn) { func (a *Agent) AgentSvc(nc *nats.Conn) {
@ -49,8 +57,6 @@ func (a *Agent) AgentSvc(nc *nats.Conn) {
a.Logger.Errorln("AgentSvc() createWinTempDir():", err) a.Logger.Errorln("AgentSvc() createWinTempDir():", err)
} }
} }
a.GetNushell(false)
a.GetDeno(false)
a.RunMigrations() a.RunMigrations()
@ -64,8 +70,9 @@ func (a *Agent) AgentSvc(nc *nats.Conn) {
a.CleanupAgentUpdates() a.CleanupAgentUpdates()
} }
// Windows has GetAgentCheckInConfig() while unix has a stub GetAgentCheckInConfig()
conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI()) conf := a.GetAgentCheckInConfig(a.GetCheckInConfFromAPI())
a.Logger.Debugf("+%v\n", conf) a.Logger.Debugf("AgentCheckInConf: %+v\n", conf)
for _, s := range natsCheckin { for _, s := range natsCheckin {
if conf.LimitData && stringInSlice(s, limitNatsData) { if conf.LimitData && stringInSlice(s, limitNatsData) {
continue continue
@ -75,6 +82,15 @@ func (a *Agent) AgentSvc(nc *nats.Conn) {
} }
} }
// The server conf check is also done in the functions to keep the parameters the same.
// Don't force a download when restarting the service.
if conf.InstallNushell {
a.InstallNushell(false)
}
if conf.InstallDeno {
a.InstallDeno(false)
}
go a.SyncMeshNodeID() go a.SyncMeshNodeID()
time.Sleep(time.Duration(randRange(1, 3)) * time.Second) time.Sleep(time.Duration(randRange(1, 3)) * time.Second)
@ -142,6 +158,14 @@ func (a *Agent) GetCheckInConfFromAPI() AgentCheckInConfig {
ret.WMI = randRange(3000, 4000) ret.WMI = randRange(3000, 4000)
ret.SyncMesh = randRange(800, 1200) ret.SyncMesh = randRange(800, 1200)
ret.LimitData = false ret.LimitData = false
ret.InstallNushell = false
ret.InstallNushellVersion = ""
ret.InstallNushellUrl = ""
ret.NushellEnableConfig = false
ret.InstallDeno = false
ret.InstallDenoVersion = ""
ret.InstallDenoUrl = ""
ret.DenoDefaultPermissions = ""
} else { } else {
ret.Hello = r.Result().(*AgentCheckInConfig).Hello ret.Hello = r.Result().(*AgentCheckInConfig).Hello
ret.AgentInfo = r.Result().(*AgentCheckInConfig).AgentInfo ret.AgentInfo = r.Result().(*AgentCheckInConfig).AgentInfo
@ -152,6 +176,14 @@ func (a *Agent) GetCheckInConfFromAPI() AgentCheckInConfig {
ret.WMI = r.Result().(*AgentCheckInConfig).WMI ret.WMI = r.Result().(*AgentCheckInConfig).WMI
ret.SyncMesh = r.Result().(*AgentCheckInConfig).SyncMesh ret.SyncMesh = r.Result().(*AgentCheckInConfig).SyncMesh
ret.LimitData = r.Result().(*AgentCheckInConfig).LimitData ret.LimitData = r.Result().(*AgentCheckInConfig).LimitData
ret.InstallNushell = r.Result().(*AgentCheckInConfig).InstallNushell
ret.InstallNushellVersion = r.Result().(*AgentCheckInConfig).InstallNushellVersion
ret.InstallNushellUrl = r.Result().(*AgentCheckInConfig).InstallNushellUrl
ret.NushellEnableConfig = r.Result().(*AgentCheckInConfig).NushellEnableConfig
ret.InstallDeno = r.Result().(*AgentCheckInConfig).InstallDeno
ret.InstallDenoVersion = r.Result().(*AgentCheckInConfig).InstallDenoVersion
ret.InstallDenoUrl = r.Result().(*AgentCheckInConfig).InstallDenoUrl
ret.DenoDefaultPermissions = r.Result().(*AgentCheckInConfig).DenoDefaultPermissions
} }
return ret return ret
} }

View File

@ -14,13 +14,13 @@ package agent
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/amidaware/taskmaster"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
rmm "github.com/amidaware/rmmagent/shared" rmm "github.com/amidaware/rmmagent/shared"
"github.com/amidaware/taskmaster"
"github.com/rickb777/date/period" "github.com/rickb777/date/period"
) )
@ -59,7 +59,7 @@ func (a *Agent) RunTask(id int) error {
action_start := time.Now() action_start := time.Now()
if action.ActionType == "script" { if action.ActionType == "script" {
stdout, stderr, retcode, err := a.RunScript(action.Code, action.Shell, action.Args, action.Timeout, action.RunAsUser, action.EnvVars) stdout, stderr, retcode, err := a.RunScript(action.Code, action.Shell, action.Args, action.Timeout, action.RunAsUser, action.EnvVars, action.NushellEnableConfig, action.DenoDefaultPermissions)
if err != nil { if err != nil {
a.Logger.Debugln(err) a.Logger.Debugln(err)

View File

@ -117,10 +117,10 @@ func main() {
fmt.Println(a.PublicIP()) fmt.Println(a.PublicIP())
case "getpython": case "getpython":
a.GetPython(true) a.GetPython(true)
case "getdeno": case "installdeno":
a.GetDeno(true) a.InstallDeno(true)
case "getnushell": case "installnushell":
a.GetNushell(true) a.InstallNushell(true)
case "runmigrations": case "runmigrations":
a.RunMigrations() a.RunMigrations()
case "recovermesh": case "recovermesh":

View File

@ -157,29 +157,31 @@ type CheckInfo struct {
} }
type Check struct { type Check struct {
Script Script `json:"script"` Script Script `json:"script"`
AssignedTasks []AssignedTask `json:"assigned_tasks"` AssignedTasks []AssignedTask `json:"assigned_tasks"`
CheckPK int `json:"id"` CheckPK int `json:"id"`
CheckType string `json:"check_type"` CheckType string `json:"check_type"`
Status string `json:"status"` Status string `json:"status"`
Threshold int `json:"threshold"` Threshold int `json:"threshold"`
Disk string `json:"disk"` Disk string `json:"disk"`
IP string `json:"ip"` IP string `json:"ip"`
ScriptArgs []string `json:"script_args"` ScriptArgs []string `json:"script_args"`
EnvVars []string `json:"env_vars"` EnvVars []string `json:"env_vars"`
Timeout int `json:"timeout"` NushellEnableConfig bool `json:"nushell_enable_config"`
ServiceName string `json:"svc_name"` DenoDefaultPermissions string `json:"deno_default_permissions"`
PassStartPending bool `json:"pass_if_start_pending"` Timeout int `json:"timeout"`
PassNotExist bool `json:"pass_if_svc_not_exist"` ServiceName string `json:"svc_name"`
RestartIfStopped bool `json:"restart_if_stopped"` PassStartPending bool `json:"pass_if_start_pending"`
LogName string `json:"log_name"` PassNotExist bool `json:"pass_if_svc_not_exist"`
EventID int `json:"event_id"` RestartIfStopped bool `json:"restart_if_stopped"`
EventIDWildcard bool `json:"event_id_is_wildcard"` LogName string `json:"log_name"`
EventType string `json:"event_type"` EventID int `json:"event_id"`
EventSource string `json:"event_source"` EventIDWildcard bool `json:"event_id_is_wildcard"`
EventMessage string `json:"event_message"` EventType string `json:"event_type"`
FailWhen string `json:"fail_when"` EventSource string `json:"event_source"`
SearchLastDays int `json:"search_last_days"` EventMessage string `json:"event_message"`
FailWhen string `json:"fail_when"`
SearchLastDays int `json:"search_last_days"`
} }
type AllChecks struct { type AllChecks struct {
@ -188,15 +190,17 @@ type AllChecks struct {
} }
type TaskAction struct { type TaskAction struct {
ActionType string `json:"type"` ActionType string `json:"type"`
Command string `json:"command"` Command string `json:"command"`
Shell string `json:"shell"` Shell string `json:"shell"`
ScriptName string `json:"script_name"` ScriptName string `json:"script_name"`
Code string `json:"code"` Code string `json:"code"`
Args []string `json:"script_args"` Args []string `json:"script_args"`
Timeout int `json:"timeout"` Timeout int `json:"timeout"`
RunAsUser bool `json:"run_as_user"` RunAsUser bool `json:"run_as_user"`
EnvVars []string `json:"env_vars"` EnvVars []string `json:"env_vars"`
NushellEnableConfig bool `json:"nushell_enable_config"`
DenoDefaultPermissions string `json:"deno_default_permissions"`
} }
type AutomatedTask struct { type AutomatedTask struct {