Removed task support from agent (for now).

Ylian Saint-Hilaire committed Aug 21, 2021 at 23:07 UTC fbe37b294e9a55d73560486da1e192a55aa11d77
2 files changed +2 -455
agents/meshcore.js
+2 -1
@@ -640,7 +640,8 @@ function getIpLocationDataEx(func) {
640 }
641
642 // Setup script task. Allows running scripts at scheduled intervals
643 -var scriptTask = require('scripttask');
643 +var scriptTask = null;
644 +try { scriptTask = require('scripttask'); } catch (ex) { }
645
646 // Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
647 function clearGatewayMac(str) {
agents/modules_meshcore/scripttask.js deleted
-454
@@ -1,454 +0,0 @@
1 -/**
2 -* @description MeshCentral ScriptTask plugin
3 -* @author Ryan Blenis
4 -* @copyright
5 -* @license Apache-2.0
6 -*/
7 -
8 -'use strict';
9 -var mesh = require('MeshAgent');
10 -var db = require('SimpleDataStore').Shared();
11 -var pendingDownload = [];
12 -var debug_flag = false;
13 -var runningJobs = [];
14 -var runningJobPIDs = {};
15 -
16 -var dbg = function (str, sessionid) {
17 - if (debug_flag || sessionid) { sendConsoleText(str, sessionid); } sendConsoleText
18 - if (debug_flag !== true) return;
19 - var logStream = require('fs').createWriteStream('scripttask.txt', { 'flags': 'a' });
20 - // use {'flags': 'a'} to append and {'flags': 'w'} to erase and write a new file
21 - logStream.write(new Date().toLocaleString() + ': ' + str + '\n');
22 - logStream.end('\n');
23 -}
24 -
25 -Array.prototype.remove = function (from, to) {
26 - var rest = this.slice((to || from) + 1 || this.length);
27 - this.length = (from < 0) ? this.length + from : from;
28 - return this.push.apply(this, rest);
29 -};
30 -
31 -function processCommand(args, rights, sessionid) {
32 - switch (args.cmd) {
33 - case 'trigger':
34 - var jObj = {
35 - jobId: args.jobId,
36 - scriptId: args.scriptId,
37 - replaceVars: args.replaceVars,
38 - scriptHash: args.scriptHash,
39 - dispatchTime: args.dispatchTime
40 - };
41 - //dbg('jObj args is ' + JSON.stringify(jObj), sessionid);
42 - var sObj = getScriptFromCache(jObj.scriptId);
43 - //dbg('sobj = ' + JSON.stringify(sObj) + ', shash = ' + jObj.scriptHash, sessionid);
44 - if ((sObj == null) ||( sObj.contentHash != jObj.scriptHash)) {
45 - // Get from the server, then run
46 - //dbg('Getting and caching script '+ jObj.scriptId, sessionid);
47 - mesh.SendCommand({ 'action': 'scripttask', 'task': 'get', 'scriptId': jObj.scriptId, 'sessionid': sessionid });
48 - pendingDownload.push(jObj);
49 - } else {
50 - // Ready to run
51 - runScript(sObj, jObj, sessionid);
52 - }
53 - break;
54 - case 'set':
55 - var sObj = args.script;
56 - cacheScript(sObj);
57 - var setRun = [];
58 - if (pendingDownload.length) {
59 - pendingDownload.forEach(function (pd, k) {
60 - if ((pd.scriptId == sObj._id) && (pd.scriptHash == sObj.contentHash)) {
61 - if (setRun.indexOf(pd) === -1) {
62 - runScript(sObj, pd, sessionid);
63 - setRun.push(pd);
64 - }
65 - pendingDownload.remove(k);
66 - }
67 - });
68 - }
69 - break;
70 - case 'clear':
71 - clearScriptCache();
72 - mesh.SendCommand({ 'action': 'scripttask', 'task': 'clear', 'sessionid': sessionid });
73 - return 'Cache cleared. All pending tasks cleared.';
74 - case 'clearcache':
75 - clearScriptCache();
76 - return 'The script cache has been cleared';
77 - case 'debug':
78 - debug_flag = (debug_flag) ? false : true;
79 - var str = (debug_flag) ? 'on' : 'off';
80 - return 'Debugging is now ' + str;
81 - case 'pending':
82 - var ret = '';
83 - if (pendingDownload.length == 0) return "No jobs pending script download";
84 - pendingDownload.forEach(function (pd, k) {
85 - ret += 'Task ' + k + ': ' + 'TaskID: ' + pd.jobId + ' ScriptID: ' + pd.scriptId;
86 - });
87 - return ret;
88 - default:
89 - if (sessionid == null) return;
90 - if (args['_'][0] == null) { return 'Supported task commands: pending, trigger, clear, clearcache, debug'; }
91 - return 'Unknown action: ' + args['_'][0] + ' with data ' + JSON.stringify(args);
92 - }
93 -}
94 -
95 -function finalizeJob(job, retVal, errVal, sessionid) {
96 - if (errVal != null && errVal.stack != null) errVal = errVal.stack;
97 - runningJobs.remove(runningJobs.indexOf(job.jobId));
98 - if (typeof runningJobPIDs[job.jobId] != 'undefined') delete runningJobPIDs[job.jobId];
99 - mesh.SendCommand({
100 - 'action': 'scripttask',
101 - 'task': 'complete',
102 - 'jobId': job.jobId,
103 - 'scriptId': job.scriptId,
104 - 'retVal': retVal,
105 - 'errVal': errVal,
106 - 'dispatchTime': job.dispatchTime, // Include original run time (long running tasks could have tried a re-send)
107 - 'sessionid': sessionid
108 - });
109 -}
110 -
111 -//@TODO Test powershell on *nix devices with and without powershell installed
112 -function runPowerShell(sObj, jObj, sessionid) {
113 - if (process.platform != 'win32') return runPowerShellNonWin(sObj, jObj);
114 - const fs = require('fs');
115 - var rand = Math.random().toString(32).replace('0.', '');
116 -
117 - var oName = 'st' + rand + '.txt';
118 - var pName = 'st' + rand + '.ps1';
119 - var pwshout = '', pwsherr = '', cancontinue = false;
120 - try {
121 - fs.writeFileSync(pName, sObj.content);
122 - var outstr = '', errstr = '';
123 - var child = require('child_process').execFile(process.env['windir'] + '\\system32\\WindowsPowerShell\\v1.0\\powershell.exe', ['-NoLogo']);
124 - child.xxsessionid = sessionid;
125 - child.stderr.on('data', function (chunk) { errstr += chunk; });
126 - child.stdout.on('data', function (chunk) { });
127 - runningJobPIDs[jObj.jobId] = child.pid;
128 - child.stdin.write('.\\' + pName + ' | Out-File ' + oName + ' -Encoding UTF8\r\n');
129 - child.on('exit', function (procRetVal, procRetSignal) {
130 - dbg('Exiting with ' + procRetVal + ', Signal: ' + procRetSignal);
131 - if (errstr != '') {
132 - finalizeJob(jObj, null, errstr, this.xxsessionid);
133 - try {
134 - fs.unlinkSync(oName);
135 - fs.unlinkSync(pName);
136 - } catch (e) { dbg('Could not unlink files, error was: ' + e, this.xxsessionid); }
137 - return;
138 - }
139 - if (procRetVal == 1) {
140 - finalizeJob(jObj, null, 'Process terminated unexpectedly.', this.xxsessionid);
141 - try {
142 - fs.unlinkSync(oName);
143 - fs.unlinkSync(pName);
144 - } catch (e) { dbg('Could not unlink files, error was: ' + e, this.xxsessionid); }
145 - return;
146 - }
147 - try {
148 - outstr = fs.readFileSync(oName, 'utf8').toString();
149 - } catch (e) { outstr = (procRetVal) ? 'Failure' : 'Success'; }
150 - if (outstr) {
151 - //outstr = outstr.replace(/[^\x20-\x7E]/g, '');
152 - try { outstr = outstr.trim(); } catch (e) { }
153 - } else {
154 - outstr = (procRetVal) ? 'Failure' : 'Success';
155 - }
156 - dbg('Output is: ' + outstr, this.xxsessionid);
157 - finalizeJob(jObj, outstr, this.xxsessionid);
158 - try {
159 - fs.unlinkSync(oName);
160 - fs.unlinkSync(pName);
161 - } catch (e) { }
162 - });
163 - child.stdin.write('exit\r\n');
164 - //child.waitExit(); // this was causing the event loop to stall on long-running scripts, switched to '.on exit'
165 - } catch (e) {
166 - dbg('Error block was (PowerShell): ' + e, sessionid);
167 - finalizeJob(jObj, null, e, sessionid);
168 - }
169 -}
170 -
171 -function runPowerShellNonWin(sObj, jObj, sessionid) {
172 - const fs = require('fs');
173 - var rand = Math.random().toString(32).replace('0.', '');
174 - var path = '';
175 - var pathTests = [
176 - '/usr/local/mesh',
177 - '/tmp',
178 - '/usr/local/mesh_services/meshagent',
179 - '/var/tmp'
180 - ];
181 - pathTests.forEach(function (p) {
182 - if (path == '' && fs.existsSync(p)) { path = p; }
183 - });
184 - dbg('Path chosen is: ' + path, sessionid);
185 - path = path + '/';
186 -
187 - var oName = 'st' + rand + '.txt';
188 - var pName = 'st' + rand + '.ps1';
189 - var pwshout = '', pwsherr = '', cancontinue = false;
190 - try {
191 - var childp = require('child_process').execFile('/bin/sh', ['sh']);
192 - childp.stderr.on('data', function (chunk) { pwsherr += chunk; });
193 - childp.stdout.on('data', function (chunk) { pwshout += chunk; });
194 - childp.stdin.write('which pwsh' + '\n');
195 - childp.stdin.write('exit\n');
196 - childp.waitExit();
197 - } catch (e) { finalizeJob(jObj, null, "Couldn't determine pwsh in env: " + e, sessionid); }
198 - if (pwsherr != '') {
199 - finalizeJob(jObj, null, "PowerShell env determination error: " + pwsherr, sessionid);
200 - return;
201 - }
202 - if (pwshout.trim() != '') {
203 - cancontinue = true;
204 - }
205 - if (cancontinue === false) { finalizeJob(jObj, null, "PowerShell is not installed"); return; }
206 - try {
207 - fs.writeFileSync(path + pName, '#!' + pwshout + '\n' + sObj.content.split('\r\n').join('\n').split('\r').join('\n'));
208 - var outstr = '', errstr = '';
209 - var child = require('child_process').execFile('/bin/sh', ['sh']);
210 - child.xxsessionid = sessionid;
211 - child.stderr.on('data', function (chunk) { errstr += chunk; });
212 - child.stdout.on('data', function (chunk) { });
213 - runningJobPIDs[jObj.jobId] = child.pid;
214 - child.stdin.write('cd ' + path + '\n');
215 - child.stdin.write('chmod a+x ' + pName + '\n');
216 - child.stdin.write('./' + pName + ' > ' + oName + '\n');
217 - child.on('exit', function (procRetVal, procRetSignal) {
218 - if (errstr != '') {
219 - finalizeJob(jObj, null, errstr);
220 - try {
221 - fs.unlinkSync(path + oName);
222 - fs.unlinkSync(path + pName);
223 - } catch (e) { dbg('Could not unlink files, error was: ' + e + ' for path ' + path, this.xxsessionid); }
224 - return;
225 - }
226 - if (procRetVal == 1) {
227 - finalizeJob(jObj, null, 'Process terminated unexpectedly.');
228 - try {
229 - fs.unlinkSync(path + oName);
230 - fs.unlinkSync(path + pName);
231 - } catch (e) { dbg('Could not unlink files1, error was: ' + e + ' for path ' + path, this.xxsessionid); }
232 - return;
233 - }
234 - try {
235 - outstr = fs.readFileSync(path + oName, 'utf8').toString();
236 - } catch (e) { outstr = (procRetVal) ? 'Failure' : 'Success'; }
237 - if (outstr) {
238 - //outstr = outstr.replace(/[^\x20-\x7E]/g, '');
239 - try { outstr = outstr.trim(); } catch (e) { }
240 - } else {
241 - outstr = (procRetVal) ? 'Failure' : 'Success';
242 - }
243 - dbg('Output is: ' + outstr);
244 - finalizeJob(jObj, outstr);
245 - try {
246 - fs.unlinkSync(path + oName);
247 - fs.unlinkSync(path + pName);
248 - } catch (e) { dbg('Could not unlink files2, error was: ' + e + ' for path ' + path, this.xxsessionid); }
249 - });
250 - child.stdin.write('exit\n');
251 - } catch (e) {
252 - dbg('Error block was (PowerShellNonWin): ' + e, sessionid);
253 - finalizeJob(jObj, null, e, sessionid);
254 - }
255 -}
256 -
257 -function runBat(sObj, jObj, sessionid) {
258 - if (process.platform != 'win32') { finalizeJob(jObj, null, 'Platform not supported.', sessionid); return; }
259 - const fs = require('fs');
260 - var rand = Math.random().toString(32).replace('0.', '');
261 - var oName = 'st' + rand + '.txt';
262 - var pName = 'st' + rand + '.bat';
263 - try {
264 - fs.writeFileSync(pName, sObj.content);
265 - var outstr = '', errstr = '';
266 - var child = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe');
267 - child.xxsessionid = sessionid;
268 - child.stderr.on('data', function (chunk) { errstr += chunk; });
269 - child.stdout.on('data', function (chunk) { });
270 - runningJobPIDs[jObj.jobId] = child.pid;
271 - child.stdin.write(pName + ' > ' + oName + '\r\n');
272 - child.stdin.write('exit\r\n');
273 - child.on('exit', function (procRetVal, procRetSignal) {
274 - if (errstr != '') {
275 - try {
276 - fs.unlinkSync(oName);
277 - fs.unlinkSync(pName);
278 - } catch (e) { dbg('Could not unlink files, error was: ' + e, this.xxsessionid); }
279 - finalizeJob(jObj, null, errstr, this.xxsessionid);
280 - return;
281 - }
282 - if (procRetVal == 1) {
283 - try {
284 - fs.unlinkSync(oName);
285 - fs.unlinkSync(pName);
286 - } catch (e) { dbg('Could not unlink files, error was: ' + e, this.xxsessionid); }
287 - finalizeJob(jObj, null, 'Process terminated unexpectedly.', this.xxsessionid);
288 - return;
289 - }
290 - try {
291 - outstr = fs.readFileSync(oName, 'utf8').toString();
292 - } catch (e) { outstr = (procRetVal) ? 'Failure' : 'Success'; }
293 - if (outstr) {
294 - //outstr = outstr.replace(/[^\x20-\x7E]/g, '');
295 - try { outstr = outstr.trim(); } catch (e) { }
296 - } else {
297 - outstr = (procRetVal) ? 'Failure' : 'Success';
298 - }
299 - dbg('Output is: ' + outstr);
300 - try {
301 - fs.unlinkSync(oName);
302 - fs.unlinkSync(pName);
303 - } catch (e) { dbg('Could not unlink files, error was: ' + e, this.xxsessionid); }
304 - finalizeJob(jObj, outstr, null, this.xxsessionid);
305 - });
306 - } catch (e) {
307 - dbg('Error block was (BAT): ' + e, sessionid);
308 - finalizeJob(jObj, null, e, sessionid);
309 - }
310 -}
311 -
312 -function runBash(sObj, jObj, sessionid) {
313 - if (process.platform == 'win32') {
314 - finalizeJob(jObj, null, 'Platform not supported.', sessionid);
315 - return;
316 - }
317 - //dbg('proc is ' + JSON.stringify(process));
318 - const fs = require('fs');
319 - var path = '';
320 - var pathTests = [
321 - '/usr/local/mesh',
322 - '/tmp',
323 - '/usr/local/mesh_services/meshagent',
324 - '/var/tmp'
325 - ];
326 - pathTests.forEach(function (p) {
327 - if (path == '' && fs.existsSync(p)) { path = p; }
328 - });
329 - dbg('Path chosen is: ' + path, sessionid);
330 - path = path + '/';
331 - //var child = require('child_process');
332 - //child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 });
333 -
334 - var rand = Math.random().toString(32).replace('0.', '');
335 - var oName = 'st' + rand + '.txt';
336 - var pName = 'st' + rand + '.sh';
337 - try {
338 - fs.writeFileSync(path + pName, sObj.content);
339 - var outstr = '', errstr = '';
340 - var child = require('child_process').execFile('/bin/sh', ['sh']);
341 - child.xxsessionid = sessionid;
342 - child.stderr.on('data', function (chunk) { errstr += chunk; });
343 - child.stdout.on('data', function (chunk) { });
344 - runningJobPIDs[jObj.jobId] = child.pid;
345 - child.stdin.write('cd ' + path + '\n');
346 - child.stdin.write('chmod a+x ' + pName + '\n');
347 - child.stdin.write('./' + pName + ' > ' + oName + '\n');
348 - child.stdin.write('exit\n');
349 - child.on('exit', function (procRetVal, procRetSignal) {
350 - if (errstr != '') {
351 - try {
352 - fs.unlinkSync(path + oName);
353 - fs.unlinkSync(path + pName);
354 - } catch (e) { dbg('Could not unlink files, error was: ' + e + ' for path ' + path, this.xxsessionid); }
355 - finalizeJob(jObj, null, errstr, this.xxsessionid);
356 - return;
357 - }
358 - if (procRetVal == 1) {
359 - try {
360 - fs.unlinkSync(path + oName);
361 - fs.unlinkSync(path + pName);
362 - } catch (e) { dbg('Could not unlink files1, error was: ' + e + ' for path ' + path, this.xxsessionid); }
363 - finalizeJob(jObj, null, 'Process terminated unexpectedly.', this.xxsessionid);
364 - return;
365 - }
366 - try {
367 - outstr = fs.readFileSync(path + oName, 'utf8').toString();
368 - } catch (e) { outstr = (procRetVal) ? 'Failure' : 'Success'; }
369 - if (outstr) {
370 - //outstr = outstr.replace(/[^\x20-\x7E]/g, '');
371 - try { outstr = outstr.trim(); } catch (e) { }
372 - } else {
373 - outstr = (procRetVal) ? 'Failure' : 'Success';
374 - }
375 - dbg('Output is: ' + outstr);
376 - try {
377 - fs.unlinkSync(path + oName);
378 - fs.unlinkSync(path + pName);
379 - } catch (e) { dbg('Could not unlink files2, error was: ' + e + ' for path ' + path, this.xxsessionid); }
380 - finalizeJob(jObj, outstr, null, this.xxsessionid);
381 - });
382 - } catch (e) {
383 - dbg('Error block was (bash): ' + e, sessionid);
384 - finalizeJob(jObj, null, e, sessionid);
385 - }
386 -}
387 -
388 -function jobIsRunning(jObj) {
389 - if (runningJobs.indexOf(jObj.jobId) === -1) return false;
390 - return true;
391 -}
392 -
393 -function runScript(sObj, jObj, sessionid) {
394 - // get current processes and clean running jobs if they are no longer running (computer fell asleep, user caused process to stop, etc.)
395 - if ((process.platform != 'linux') && runningJobs.length) { // linux throws errors here in the meshagent for some reason
396 - require('process-manager').getProcesses(function (plist) {
397 - dbg('Got process list', sessionid);
398 - dbg('There are currently ' + runningJobs.length + ' running jobs.', sessionid);
399 - if (runningJobs.length) {
400 - runningJobs.forEach(function (jobId, idx) {
401 - dbg('Checking for running job: ' + jobId + ' with PID ' + runningJobPIDs[jobId], sessionid);
402 - if (typeof plist[runningJobPIDs[jobId]] == 'undefined' || typeof plist[runningJobPIDs[jobId]].cmd != 'string') {
403 - dbg('Found job with no process. Removing running status.', sessionid);
404 - delete runningJobPIDs[jobId];
405 - runningJobs.remove(runningJobs.indexOf(idx));
406 - //dbg('RunningJobs: ' + JSON.stringify(runningJobs));
407 - //dbg('RunningJobsPIDs: ' + JSON.stringify(runningJobPIDs));
408 - }
409 - });
410 - }
411 - });
412 - }
413 - if (jobIsRunning(jObj)) { dbg('Job already running job id [' + jObj.jobId + ']. Skipping.', sessionid); return; }
414 - if (jObj.replaceVars != null) {
415 - Object.getOwnPropertyNames(jObj.replaceVars).forEach(function (key) {
416 - var val = jObj.replaceVars[key];
417 - sObj.content = sObj.content.replace(new RegExp('#' + key + '#', 'g'), val);
418 - dbg('replacing var ' + key + ' with ' + val, sessionid);
419 - });
420 - sObj.content = sObj.content.replace(new RegExp('#(.*?)#', 'g'), 'VAR_NOT_FOUND');
421 - }
422 - runningJobs.push(jObj.jobId);
423 - dbg('Running Script ' + sObj._id, sessionid);
424 - switch (sObj.filetype) {
425 - case 'ps1': runPowerShell(sObj, jObj, sessionid); break;
426 - case 'bat': runBat(sObj, jObj, sessionid); break;
427 - case 'bash': runBash(sObj, jObj, sessionid); break;
428 - default: dbg('Unknown filetype: ' + sObj.filetype, sessionid);
429 - break;
430 - }
431 -}
432 -function getScriptFromCache(id) {
433 - var script = db.Get('scriptTask_script_' + id);
434 - if (script == '' || script == null) return null;
435 - try { script = JSON.parse(script); } catch (e) { return null; }
436 - return script;
437 -}
438 -function cacheScript(sObj) {
439 - db.Put('scriptTask_script_' + sObj._id, sObj);
440 -}
441 -function clearScriptCache() {
442 - db.Keys.forEach(function (k) {
443 - if (k.indexOf('scriptTask_script_') === 0) {
444 - db.Put(k, null);
445 - db.Delete(k);
446 - }
447 - });
448 -}
449 -
450 -function sendConsoleText(text, sessionid) {
451 - require('MeshAgent').SendCommand({ 'action': 'msg', 'type': 'console', 'value': (typeof text == 'string') ? text : JSON.stringify(text), 'sessionid': sessionid });
452 -}
453 -
454 -module.exports = { processCommand: processCommand };
\ No newline at end of file