From fbe37b294e9a55d73560486da1e192a55aa11d77 Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Sat, 21 Aug 2021 23:07:55 -0700 Subject: [PATCH] Removed task support from agent (for now). --- agents/meshcore.js | 3 +- agents/modules_meshcore/scripttask.js | 454 -------------------------- 2 files changed, 2 insertions(+), 455 deletions(-) delete mode 100644 agents/modules_meshcore/scripttask.js diff --git a/agents/meshcore.js b/agents/meshcore.js index ea684ca7..448d698a 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -640,7 +640,8 @@ function getIpLocationDataEx(func) { } // Setup script task. Allows running scripts at scheduled intervals -var scriptTask = require('scripttask'); +var scriptTask = null; +try { scriptTask = require('scripttask'); } catch (ex) { } // Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably. function clearGatewayMac(str) { diff --git a/agents/modules_meshcore/scripttask.js b/agents/modules_meshcore/scripttask.js deleted file mode 100644 index d28c16f6..00000000 --- a/agents/modules_meshcore/scripttask.js +++ /dev/null @@ -1,454 +0,0 @@ -/** -* @description MeshCentral ScriptTask plugin -* @author Ryan Blenis -* @copyright -* @license Apache-2.0 -*/ - -'use strict'; -var mesh = require('MeshAgent'); -var db = require('SimpleDataStore').Shared(); -var pendingDownload = []; -var debug_flag = false; -var runningJobs = []; -var runningJobPIDs = {}; - -var dbg = function (str, sessionid) { - if (debug_flag || sessionid) { sendConsoleText(str, sessionid); } sendConsoleText - if (debug_flag !== true) return; - var logStream = require('fs').createWriteStream('scripttask.txt', { 'flags': 'a' }); - // use {'flags': 'a'} to append and {'flags': 'w'} to erase and write a new file - logStream.write(new Date().toLocaleString() + ': ' + str + '\n'); - logStream.end('\n'); -} - -Array.prototype.remove = function (from, to) { - var rest = this.slice((to || from) + 1 || this.length); - this.length = (from < 0) ? this.length + from : from; - return this.push.apply(this, rest); -}; - -function processCommand(args, rights, sessionid) { - switch (args.cmd) { - case 'trigger': - var jObj = { - jobId: args.jobId, - scriptId: args.scriptId, - replaceVars: args.replaceVars, - scriptHash: args.scriptHash, - dispatchTime: args.dispatchTime - }; - //dbg('jObj args is ' + JSON.stringify(jObj), sessionid); - var sObj = getScriptFromCache(jObj.scriptId); - //dbg('sobj = ' + JSON.stringify(sObj) + ', shash = ' + jObj.scriptHash, sessionid); - if ((sObj == null) ||( sObj.contentHash != jObj.scriptHash)) { - // Get from the server, then run - //dbg('Getting and caching script '+ jObj.scriptId, sessionid); - mesh.SendCommand({ 'action': 'scripttask', 'task': 'get', 'scriptId': jObj.scriptId, 'sessionid': sessionid }); - pendingDownload.push(jObj); - } else { - // Ready to run - runScript(sObj, jObj, sessionid); - } - break; - case 'set': - var sObj = args.script; - cacheScript(sObj); - var setRun = []; - if (pendingDownload.length) { - pendingDownload.forEach(function (pd, k) { - if ((pd.scriptId == sObj._id) && (pd.scriptHash == sObj.contentHash)) { - if (setRun.indexOf(pd) === -1) { - runScript(sObj, pd, sessionid); - setRun.push(pd); - } - pendingDownload.remove(k); - } - }); - } - break; - case 'clear': - clearScriptCache(); - mesh.SendCommand({ 'action': 'scripttask', 'task': 'clear', 'sessionid': sessionid }); - return 'Cache cleared. All pending tasks cleared.'; - case 'clearcache': - clearScriptCache(); - return 'The script cache has been cleared'; - case 'debug': - debug_flag = (debug_flag) ? false : true; - var str = (debug_flag) ? 'on' : 'off'; - return 'Debugging is now ' + str; - case 'pending': - var ret = ''; - if (pendingDownload.length == 0) return "No jobs pending script download"; - pendingDownload.forEach(function (pd, k) { - ret += 'Task ' + k + ': ' + 'TaskID: ' + pd.jobId + ' ScriptID: ' + pd.scriptId; - }); - return ret; - default: - if (sessionid == null) return; - if (args['_'][0] == null) { return 'Supported task commands: pending, trigger, clear, clearcache, debug'; } - return 'Unknown action: ' + args['_'][0] + ' with data ' + JSON.stringify(args); - } -} - -function finalizeJob(job, retVal, errVal, sessionid) { - if (errVal != null && errVal.stack != null) errVal = errVal.stack; - runningJobs.remove(runningJobs.indexOf(job.jobId)); - if (typeof runningJobPIDs[job.jobId] != 'undefined') delete runningJobPIDs[job.jobId]; - mesh.SendCommand({ - 'action': 'scripttask', - 'task': 'complete', - 'jobId': job.jobId, - 'scriptId': job.scriptId, - 'retVal': retVal, - 'errVal': errVal, - 'dispatchTime': job.dispatchTime, // Include original run time (long running tasks could have tried a re-send) - 'sessionid': sessionid - }); -} - -//@TODO Test powershell on *nix devices with and without powershell installed -function runPowerShell(sObj, jObj, sessionid) { - if (process.platform != 'win32') return runPowerShellNonWin(sObj, jObj); - const fs = require('fs'); - var rand = Math.random().toString(32).replace('0.', ''); - - var oName = 'st' + rand + '.txt'; - var pName = 'st' + rand + '.ps1'; - var pwshout = '', pwsherr = '', cancontinue = false; - try { - fs.writeFileSync(pName, sObj.content); - var outstr = '', errstr = ''; - var child = require('child_process').execFile(process.env['windir'] + '\\system32\\WindowsPowerShell\\v1.0\\powershell.exe', ['-NoLogo']); - child.xxsessionid = sessionid; - child.stderr.on('data', function (chunk) { errstr += chunk; }); - child.stdout.on('data', function (chunk) { }); - runningJobPIDs[jObj.jobId] = child.pid; - child.stdin.write('.\\' + pName + ' | Out-File ' + oName + ' -Encoding UTF8\r\n'); - child.on('exit', function (procRetVal, procRetSignal) { - dbg('Exiting with ' + procRetVal + ', Signal: ' + procRetSignal); - if (errstr != '') { - finalizeJob(jObj, null, errstr, this.xxsessionid); - try { - fs.unlinkSync(oName); - fs.unlinkSync(pName); - } catch (e) { dbg('Could not unlink files, error was: ' + e, this.xxsessionid); } - return; - } - if (procRetVal == 1) { - finalizeJob(jObj, null, 'Process terminated unexpectedly.', this.xxsessionid); - try { - fs.unlinkSync(oName); - fs.unlinkSync(pName); - } catch (e) { dbg('Could not unlink files, error was: ' + e, this.xxsessionid); } - return; - } - try { - outstr = fs.readFileSync(oName, 'utf8').toString(); - } catch (e) { outstr = (procRetVal) ? 'Failure' : 'Success'; } - if (outstr) { - //outstr = outstr.replace(/[^\x20-\x7E]/g, ''); - try { outstr = outstr.trim(); } catch (e) { } - } else { - outstr = (procRetVal) ? 'Failure' : 'Success'; - } - dbg('Output is: ' + outstr, this.xxsessionid); - finalizeJob(jObj, outstr, this.xxsessionid); - try { - fs.unlinkSync(oName); - fs.unlinkSync(pName); - } catch (e) { } - }); - child.stdin.write('exit\r\n'); - //child.waitExit(); // this was causing the event loop to stall on long-running scripts, switched to '.on exit' - } catch (e) { - dbg('Error block was (PowerShell): ' + e, sessionid); - finalizeJob(jObj, null, e, sessionid); - } -} - -function runPowerShellNonWin(sObj, jObj, sessionid) { - const fs = require('fs'); - var rand = Math.random().toString(32).replace('0.', ''); - var path = ''; - var pathTests = [ - '/usr/local/mesh', - '/tmp', - '/usr/local/mesh_services/meshagent', - '/var/tmp' - ]; - pathTests.forEach(function (p) { - if (path == '' && fs.existsSync(p)) { path = p; } - }); - dbg('Path chosen is: ' + path, sessionid); - path = path + '/'; - - var oName = 'st' + rand + '.txt'; - var pName = 'st' + rand + '.ps1'; - var pwshout = '', pwsherr = '', cancontinue = false; - try { - var childp = require('child_process').execFile('/bin/sh', ['sh']); - childp.stderr.on('data', function (chunk) { pwsherr += chunk; }); - childp.stdout.on('data', function (chunk) { pwshout += chunk; }); - childp.stdin.write('which pwsh' + '\n'); - childp.stdin.write('exit\n'); - childp.waitExit(); - } catch (e) { finalizeJob(jObj, null, "Couldn't determine pwsh in env: " + e, sessionid); } - if (pwsherr != '') { - finalizeJob(jObj, null, "PowerShell env determination error: " + pwsherr, sessionid); - return; - } - if (pwshout.trim() != '') { - cancontinue = true; - } - if (cancontinue === false) { finalizeJob(jObj, null, "PowerShell is not installed"); return; } - try { - fs.writeFileSync(path + pName, '#!' + pwshout + '\n' + sObj.content.split('\r\n').join('\n').split('\r').join('\n')); - var outstr = '', errstr = ''; - var child = require('child_process').execFile('/bin/sh', ['sh']); - child.xxsessionid = sessionid; - child.stderr.on('data', function (chunk) { errstr += chunk; }); - child.stdout.on('data', function (chunk) { }); - runningJobPIDs[jObj.jobId] = child.pid; - child.stdin.write('cd ' + path + '\n'); - child.stdin.write('chmod a+x ' + pName + '\n'); - child.stdin.write('./' + pName + ' > ' + oName + '\n'); - child.on('exit', function (procRetVal, procRetSignal) { - if (errstr != '') { - finalizeJob(jObj, null, errstr); - try { - fs.unlinkSync(path + oName); - fs.unlinkSync(path + pName); - } catch (e) { dbg('Could not unlink files, error was: ' + e + ' for path ' + path, this.xxsessionid); } - return; - } - if (procRetVal == 1) { - finalizeJob(jObj, null, 'Process terminated unexpectedly.'); - try { - fs.unlinkSync(path + oName); - fs.unlinkSync(path + pName); - } catch (e) { dbg('Could not unlink files1, error was: ' + e + ' for path ' + path, this.xxsessionid); } - return; - } - try { - outstr = fs.readFileSync(path + oName, 'utf8').toString(); - } catch (e) { outstr = (procRetVal) ? 'Failure' : 'Success'; } - if (outstr) { - //outstr = outstr.replace(/[^\x20-\x7E]/g, ''); - try { outstr = outstr.trim(); } catch (e) { } - } else { - outstr = (procRetVal) ? 'Failure' : 'Success'; - } - dbg('Output is: ' + outstr); - finalizeJob(jObj, outstr); - try { - fs.unlinkSync(path + oName); - fs.unlinkSync(path + pName); - } catch (e) { dbg('Could not unlink files2, error was: ' + e + ' for path ' + path, this.xxsessionid); } - }); - child.stdin.write('exit\n'); - } catch (e) { - dbg('Error block was (PowerShellNonWin): ' + e, sessionid); - finalizeJob(jObj, null, e, sessionid); - } -} - -function runBat(sObj, jObj, sessionid) { - if (process.platform != 'win32') { finalizeJob(jObj, null, 'Platform not supported.', sessionid); return; } - const fs = require('fs'); - var rand = Math.random().toString(32).replace('0.', ''); - var oName = 'st' + rand + '.txt'; - var pName = 'st' + rand + '.bat'; - try { - fs.writeFileSync(pName, sObj.content); - var outstr = '', errstr = ''; - var child = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe'); - child.xxsessionid = sessionid; - child.stderr.on('data', function (chunk) { errstr += chunk; }); - child.stdout.on('data', function (chunk) { }); - runningJobPIDs[jObj.jobId] = child.pid; - child.stdin.write(pName + ' > ' + oName + '\r\n'); - child.stdin.write('exit\r\n'); - child.on('exit', function (procRetVal, procRetSignal) { - if (errstr != '') { - try { - fs.unlinkSync(oName); - fs.unlinkSync(pName); - } catch (e) { dbg('Could not unlink files, error was: ' + e, this.xxsessionid); } - finalizeJob(jObj, null, errstr, this.xxsessionid); - return; - } - if (procRetVal == 1) { - try { - fs.unlinkSync(oName); - fs.unlinkSync(pName); - } catch (e) { dbg('Could not unlink files, error was: ' + e, this.xxsessionid); } - finalizeJob(jObj, null, 'Process terminated unexpectedly.', this.xxsessionid); - return; - } - try { - outstr = fs.readFileSync(oName, 'utf8').toString(); - } catch (e) { outstr = (procRetVal) ? 'Failure' : 'Success'; } - if (outstr) { - //outstr = outstr.replace(/[^\x20-\x7E]/g, ''); - try { outstr = outstr.trim(); } catch (e) { } - } else { - outstr = (procRetVal) ? 'Failure' : 'Success'; - } - dbg('Output is: ' + outstr); - try { - fs.unlinkSync(oName); - fs.unlinkSync(pName); - } catch (e) { dbg('Could not unlink files, error was: ' + e, this.xxsessionid); } - finalizeJob(jObj, outstr, null, this.xxsessionid); - }); - } catch (e) { - dbg('Error block was (BAT): ' + e, sessionid); - finalizeJob(jObj, null, e, sessionid); - } -} - -function runBash(sObj, jObj, sessionid) { - if (process.platform == 'win32') { - finalizeJob(jObj, null, 'Platform not supported.', sessionid); - return; - } - //dbg('proc is ' + JSON.stringify(process)); - const fs = require('fs'); - var path = ''; - var pathTests = [ - '/usr/local/mesh', - '/tmp', - '/usr/local/mesh_services/meshagent', - '/var/tmp' - ]; - pathTests.forEach(function (p) { - if (path == '' && fs.existsSync(p)) { path = p; } - }); - dbg('Path chosen is: ' + path, sessionid); - path = path + '/'; - //var child = require('child_process'); - //child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 }); - - var rand = Math.random().toString(32).replace('0.', ''); - var oName = 'st' + rand + '.txt'; - var pName = 'st' + rand + '.sh'; - try { - fs.writeFileSync(path + pName, sObj.content); - var outstr = '', errstr = ''; - var child = require('child_process').execFile('/bin/sh', ['sh']); - child.xxsessionid = sessionid; - child.stderr.on('data', function (chunk) { errstr += chunk; }); - child.stdout.on('data', function (chunk) { }); - runningJobPIDs[jObj.jobId] = child.pid; - child.stdin.write('cd ' + path + '\n'); - child.stdin.write('chmod a+x ' + pName + '\n'); - child.stdin.write('./' + pName + ' > ' + oName + '\n'); - child.stdin.write('exit\n'); - child.on('exit', function (procRetVal, procRetSignal) { - if (errstr != '') { - try { - fs.unlinkSync(path + oName); - fs.unlinkSync(path + pName); - } catch (e) { dbg('Could not unlink files, error was: ' + e + ' for path ' + path, this.xxsessionid); } - finalizeJob(jObj, null, errstr, this.xxsessionid); - return; - } - if (procRetVal == 1) { - try { - fs.unlinkSync(path + oName); - fs.unlinkSync(path + pName); - } catch (e) { dbg('Could not unlink files1, error was: ' + e + ' for path ' + path, this.xxsessionid); } - finalizeJob(jObj, null, 'Process terminated unexpectedly.', this.xxsessionid); - return; - } - try { - outstr = fs.readFileSync(path + oName, 'utf8').toString(); - } catch (e) { outstr = (procRetVal) ? 'Failure' : 'Success'; } - if (outstr) { - //outstr = outstr.replace(/[^\x20-\x7E]/g, ''); - try { outstr = outstr.trim(); } catch (e) { } - } else { - outstr = (procRetVal) ? 'Failure' : 'Success'; - } - dbg('Output is: ' + outstr); - try { - fs.unlinkSync(path + oName); - fs.unlinkSync(path + pName); - } catch (e) { dbg('Could not unlink files2, error was: ' + e + ' for path ' + path, this.xxsessionid); } - finalizeJob(jObj, outstr, null, this.xxsessionid); - }); - } catch (e) { - dbg('Error block was (bash): ' + e, sessionid); - finalizeJob(jObj, null, e, sessionid); - } -} - -function jobIsRunning(jObj) { - if (runningJobs.indexOf(jObj.jobId) === -1) return false; - return true; -} - -function runScript(sObj, jObj, sessionid) { - // get current processes and clean running jobs if they are no longer running (computer fell asleep, user caused process to stop, etc.) - if ((process.platform != 'linux') && runningJobs.length) { // linux throws errors here in the meshagent for some reason - require('process-manager').getProcesses(function (plist) { - dbg('Got process list', sessionid); - dbg('There are currently ' + runningJobs.length + ' running jobs.', sessionid); - if (runningJobs.length) { - runningJobs.forEach(function (jobId, idx) { - dbg('Checking for running job: ' + jobId + ' with PID ' + runningJobPIDs[jobId], sessionid); - if (typeof plist[runningJobPIDs[jobId]] == 'undefined' || typeof plist[runningJobPIDs[jobId]].cmd != 'string') { - dbg('Found job with no process. Removing running status.', sessionid); - delete runningJobPIDs[jobId]; - runningJobs.remove(runningJobs.indexOf(idx)); - //dbg('RunningJobs: ' + JSON.stringify(runningJobs)); - //dbg('RunningJobsPIDs: ' + JSON.stringify(runningJobPIDs)); - } - }); - } - }); - } - if (jobIsRunning(jObj)) { dbg('Job already running job id [' + jObj.jobId + ']. Skipping.', sessionid); return; } - if (jObj.replaceVars != null) { - Object.getOwnPropertyNames(jObj.replaceVars).forEach(function (key) { - var val = jObj.replaceVars[key]; - sObj.content = sObj.content.replace(new RegExp('#' + key + '#', 'g'), val); - dbg('replacing var ' + key + ' with ' + val, sessionid); - }); - sObj.content = sObj.content.replace(new RegExp('#(.*?)#', 'g'), 'VAR_NOT_FOUND'); - } - runningJobs.push(jObj.jobId); - dbg('Running Script ' + sObj._id, sessionid); - switch (sObj.filetype) { - case 'ps1': runPowerShell(sObj, jObj, sessionid); break; - case 'bat': runBat(sObj, jObj, sessionid); break; - case 'bash': runBash(sObj, jObj, sessionid); break; - default: dbg('Unknown filetype: ' + sObj.filetype, sessionid); - break; - } -} -function getScriptFromCache(id) { - var script = db.Get('scriptTask_script_' + id); - if (script == '' || script == null) return null; - try { script = JSON.parse(script); } catch (e) { return null; } - return script; -} -function cacheScript(sObj) { - db.Put('scriptTask_script_' + sObj._id, sObj); -} -function clearScriptCache() { - db.Keys.forEach(function (k) { - if (k.indexOf('scriptTask_script_') === 0) { - db.Put(k, null); - db.Delete(k); - } - }); -} - -function sendConsoleText(text, sessionid) { - require('MeshAgent').SendCommand({ 'action': 'msg', 'type': 'console', 'value': (typeof text == 'string') ? text : JSON.stringify(text), 'sessionid': sessionid }); -} - -module.exports = { processCommand: processCommand }; \ No newline at end of file