Added polyfill for Array.find() when missing, needed for Windows/Temp self update
Bryan Roe committed
Jun 4, 2021 at 11:46 UTC
ab8b3095dd0f79ae9b3d291adda84befd9ed7244
1 file changed
+218
-31
agents/recoverycore.js
+218
-31
@@ -6,9 +6,104 @@ var nextTunnelIndex = 1;
6
var tunnels = {};
7
var fs = require('fs');
8
9
-if (require('MeshAgent').ARCHID == null) {
9
+try
10
+{
11
+ Object.defineProperty(Array.prototype, 'find', {
12
+ value: function (func)
13
+ {
14
+ var i = 0;
15
+ for(i=0;i<this.length;++i)
16
+ {
17
+ if(func(this[i]))
18
+ {
19
+ return (this[i]);
20
+ }
21
+ }
22
+ return (null);
23
+ }
24
+ });
25
+}
26
+catch(x)
27
+{
28
+
29
+}
30
+
31
+function _getPotentialServiceNames()
32
+{
33
+ var registry = require('win-registry');
34
+ var ret = [];
35
+ var K = registry.QueryKey(registry.HKEY.LocalMachine, 'SYSTEM\\CurrentControlSet\\Services');
36
+ var service, s;
37
+ while (K.subkeys.length > 0)
38
+ {
39
+ service = K.subkeys.shift();
40
+ try
41
+ {
42
+ s = registry.QueryKey(registry.HKEY.LocalMachine, 'SYSTEM\\CurrentControlSet\\Services\\' + service, 'ImagePath');
43
+ if (s.startsWith(process.execPath) || s.startsWith('"' + process.execPath + '"'))
44
+ {
45
+ ret.push(service);
46
+ }
47
+ }
48
+ catch (x)
49
+ {
50
+ }
51
+ }
52
+ return (ret);
53
+}
54
+function _verifyServiceName(names)
55
+{
56
+ var i;
57
+ var s;
58
+ var ret = null;
59
+ for (i = 0; i < names.length; ++i)
60
+ {
61
+ try
62
+ {
63
+ s = require('service-manager').manager.getService(names[i]);
64
+ if (s.isMe())
65
+ {
66
+ ret = names[i];
67
+ s.close();
68
+ break;
69
+ }
70
+ s.close();
71
+ }
72
+ catch (z) { }
73
+ }
74
+ return (ret);
75
+}
76
+
77
+function windows_getCommandLine()
78
+{
79
+ var parms = [];
80
+ var GM = require('_GenericMarshal');
81
+ var k32 = GM.CreateNativeProxy('kernel32.dll');
82
+ var s32 = GM.CreateNativeProxy('shell32.dll');
83
+ k32.CreateMethod('GetCommandLineW');
84
+ k32.CreateMethod('LocalFree');
85
+ s32.CreateMethod('CommandLineToArgvW');
86
+ var v = k32.GetCommandLineW();
87
+ var i;
88
+ var len = GM.CreateVariable(4);
89
+ var val = s32.CommandLineToArgvW(v, len);
90
+ len = len.toBuffer().readInt32LE(0);
91
+ if (len > 0)
92
+ {
93
+ for (i = 0; i < len; ++i)
94
+ {
95
+ parms.push(val.Deref(i * GM.PointerSize, GM.PointerSize).Deref().Wide2UTF8);
96
+ }
97
+ }
98
+ k32.LocalFree(val);
99
+ return (parms);
100
+}
101
+
102
+if (require('MeshAgent').ARCHID == null)
103
+{
104
var id = null;
11
- switch (process.platform) {
105
+ switch (process.platform)
106
+ {
107
case 'win32':
108
id = require('_GenericMarshal').PointerSize == 4 ? 3 : 4;
109
break;
@@ -16,10 +111,12 @@ if (require('MeshAgent').ARCHID == null) {
111
id = require('_GenericMarshal').PointerSize == 4 ? 31 : 30;
112
break;
113
case 'darwin':
19
- try {
114
+ try
115
+ {
116
id = require('os').arch() == 'x64' ? 16 : 29;
117
}
22
- catch (xx) {
118
+ catch (xx)
119
+ {
120
id = 16;
121
}
122
break;
@@ -29,17 +126,22 @@ if (require('MeshAgent').ARCHID == null) {
126
127
//attachDebugger({ webport: 9994, wait: 1 }).then(function (p) { console.log('Debug on port: ' + p); });
128
32
-function sendConsoleText(msg, sessionid) {
33
- if (sessionid != null) {
129
+function sendConsoleText(msg, sessionid)
130
+{
131
+ if (sessionid != null)
132
+ {
133
require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: msg, sessionid: sessionid });
134
}
36
- else {
135
+ else
136
+ {
137
require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: msg });
138
}
139
}
140
41
-function sendAgentMessage(msg, icon) {
42
- if (sendAgentMessage.messages == null) {
141
+function sendAgentMessage(msg, icon)
142
+{
143
+ if (sendAgentMessage.messages == null)
144
+ {
145
sendAgentMessage.messages = {};
146
sendAgentMessage.nextid = 1;
147
}
@@ -48,9 +150,11 @@ function sendAgentMessage(msg, icon) {
150
}
151
152
// Add to the server event log
51
-function MeshServerLog(msg, state) {
153
+function MeshServerLog(msg, state)
154
+{
155
if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
53
- if (state) {
156
+ if (state)
157
+ {
158
if (state.userid) { msg.userid = state.userid; }
159
if (state.username) { msg.username = state.username; }
160
if (state.sessionid) { msg.sessionid = state.sessionid; }
@@ -60,9 +164,11 @@ function MeshServerLog(msg, state) {
164
}
165
166
// Add to the server event log, use internationalized events
63
-function MeshServerLogEx(id, args, msg, state) {
167
+function MeshServerLogEx(id, args, msg, state)
168
+{
169
var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
65
- if (state) {
170
+ if (state)
171
+ {
172
if (state.userid) { msg.userid = state.userid; }
173
if (state.username) { msg.username = state.username; }
174
if (state.sessionid) { msg.sessionid = state.sessionid; }
@@ -346,6 +452,34 @@ function windows_execve(name, agentfilename, sessionid) {
452
var arg2 = require('_GenericMarshal').CreateVariable('/C wmic service "' + name + '" call stopservice & "' + cwd + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCk7CiAgICByZXF1aXJlKCdwcm9jZXNzLW1hbmFnZXInKS5lbnVtZXJhdGVQcm9jZXNzZXMoKS50aGVuKGZ1bmN0aW9uIChwcm9jKQogICAgewogICAgICAgIGZvciAodmFyIHAgaW4gcHJvYykKICAgICAgICB7CiAgICAgICAgICAgIGlmIChwcm9jW3BdLnBhdGggPT0gc2VydmljZUxvY2F0aW9uKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBwcm9jZXNzLmtpbGwocHJvY1twXS5waWQpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHByb2Nlc3MuZXhpdCgpOwogICAgfSk7Cn0KY2F0Y2goZSkKewogICAgcHJvY2Vzcy5leGl0KCk7Cn0=' +
453
' "' + process.execPath + '" & copy "' + cwd + agentfilename + '.update.exe" "' + process.execPath + '" & wmic service "' + name + '" call startservice & erase "' + cwd + agentfilename + '.update.exe"', { wide: true });
454
455
+ if (name == null)
456
+ {
457
+ // We can continue with self update for Temp/Console Mode on Windows
458
+ var db = null;
459
+ var update = cwd + agentfilename + '.update.exe';
460
+ var updatedb = cwd + agentfilename + '.update.db';
461
+ var parms = windows_getCommandLine(); parms.shift();
462
+
463
+ var updatesource = parms.find(function (v) { return (v.startsWith('--updateSourcePath=')); });
464
+ if (updatesource == null)
465
+ {
466
+ parms.push('--updateSourcePath="' + cwd + agentfilename + '"');
467
+ updatesource = (cwd + agentfilename).split('.exe'); updatesource.pop(); updatesource = updatesource.join('.exe');
468
+ db = updatesource + '.db';
469
+ updatesource = (' & move "' + updatedb + '" "' + db + '"') + (' & erase "' + updatedb + '"');
470
+ }
471
+ else
472
+ {
473
+ updatesource = updatesource.substring(19).split('.exe');
474
+ updatesource.pop(); updatesource = updatesource.join('.exe');
475
+ db = updatesource + '.db';
476
+ updatesource = (' & move "' + update + '" "' + updatesource + '.exe" & move "' + updatedb + '" "' + db + '" & erase "' + updatedb + '"') + (' & echo move "' + update + '" "' + updatesource + '.exe" & echo move "' + updatedb + '" "' + db + '"');
477
+ }
478
+
479
+ var tmp = '/C echo copy "' + db + '" "' + updatedb + '" & copy "' + db + '" "' + updatedb + '"' + ' & "' + update + '" ' + parms.join(' ') + updatesource + ' & erase "' + update + '" & echo ERASE "' + update + '"';
480
+ arg2 = require('_GenericMarshal').CreateVariable(tmp, { wide: true });
481
+ }
482
+
483
arg1.pointerBuffer().copy(args.toBuffer());
484
arg2.pointerBuffer().copy(args.toBuffer(), require('_GenericMarshal').PointerSize);
485
@@ -363,7 +497,8 @@ function agentUpdate_Start(updateurl, updateoptions) {
497
if (updateurl.startsWith("wss://")) { updateurl = "https://" + updateurl.substring(6); }
498
}
499
366
- if (agentUpdate_Start._selfupdate != null) {
500
+ if (agentUpdate_Start._selfupdate != null)
501
+ {
502
// We were already called, so we will ignore this duplicate request
503
if (sessionid != null) { sendConsoleText('Self update already in progress...', sessionid); }
504
}
@@ -373,25 +508,58 @@ function agentUpdate_Start(updateurl, updateoptions) {
508
// This agent doesn't have the ability to tell us which ARCHID it is, so we don't know which agent to pull
509
sendConsoleText('Unable to initiate update, agent ARCHID is not defined', sessionid);
510
}
376
- else {
511
+ else
512
+ {
513
var agentfilename = process.execPath.split(process.platform == 'win32' ? '\\' : '/').pop(); // Local File Name, ie: MeshAgent.exe
514
var name = require('MeshAgent').serviceName;
379
- if (name == null) { name = (process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'); } // This is an older agent that doesn't expose the service name, so use the default
380
- try {
381
- var s = require('service-manager').manager.getService(name);
382
- if (!s.isMe()) {
515
+ if (name == null) { name = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'; }
516
+ if (process.platform == 'win32')
517
+ {
518
+ // Special Processing for Temporary/Console Mode Agents on Windows
519
+ var parms = windows_getCommandLine();
520
+ if (parms.findIndex(function (val) { return (val.toUpperCase() == 'RUN' || val.toUpperCase() == 'CONNECT');})>=0)
521
+ {
522
+ // This is a Temporary/Console Mode Agent
523
+ sendConsoleText('This is a temporary/console agent, checking for conflicts with background services...');
524
+
525
+ // Check to see if our binary conflicts with an installed agent
526
+ var agents = _getPotentialServiceNames();
527
+ if(_getPotentialServiceNames().length>0)
528
+ {
529
+ sendConsoleText('Self update cannot continue because the installed agent (' + agents[0] + ') conflicts with the currently running Temp/Console agent...', sessionid);
530
+ return;
531
+ }
532
+
533
+
534
+ sendConsoleText('No conflicts detected...');
535
+ name = null;
536
+ }
537
+ else
538
+ {
539
+ // Not running in Temp/Console Mode... No Op here....
540
+ }
541
+ }
542
+ else
543
+ {
544
+ // Non Windows Self Update
545
+ try
546
+ {
547
+ var s = require('service-manager').manager.getService(name);
548
+ if (!s.isMe())
549
+ {
550
+ if (process.platform == 'win32') { s.close(); }
551
+ sendConsoleText('Self Update cannot continue, this agent is not an instance of background service (' + name + ')', sessionid);
552
+ return;
553
+ }
554
if (process.platform == 'win32') { s.close(); }
384
- sendConsoleText('Self Update cannot continue, this agent is not an instance of (' + name + ')', sessionid);
555
+ }
556
+ catch (zz)
557
+ {
558
+ sendConsoleText('Self Update Failed because this agent is not an instance of (' + name + ')', sessionid);
559
+ sendAgentMessage('Self Update Failed because this agent is not an instance of (' + name + ')', 3);
560
return;
561
}
387
- if (process.platform == 'win32') { s.close(); }
388
- }
389
- catch (zz) {
390
- sendConsoleText('Self Update Failed because this agent is not an instance of (' + name + ')', sessionid);
391
- sendAgentMessage('Self Update Failed because this agent is not an instance of (' + name + ')', 3);
392
- return;
562
}
394
-
563
if ((sessionid != null) && (updateurl != null)) { sendConsoleText('Downloading update from: ' + updateurl, sessionid); }
564
var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl);
565
options.protocol = 'https:';
@@ -1007,7 +1175,25 @@ require('MeshAgent').AddCommandHandler(function (data) {
1175
function processConsoleCommand(cmd, args, rights, sessionid) {
1176
try {
1177
var response = null;
1010
- switch (cmd) {
1178
+ switch (cmd)
1179
+ {
1180
+ default:
1181
+ { // This is an unknown command, return an error message
1182
+ response = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.';
1183
+ break;
1184
+ }
1185
+ case 'commandline':
1186
+ {
1187
+ if (process.platform == 'win32')
1188
+ {
1189
+ response = JSON.stringify(windows_getCommandLine(), null, 1);
1190
+ }
1191
+ else
1192
+ {
1193
+ response = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.';
1194
+ }
1195
+ }
1196
+ break;
1197
case 'help':
1198
response = "Available commands are: agentupdate, agentupdateex, dbkeys, dbget, dbset, dbcompact, eval, netinfo, osinfo, setdebug, versions.";
1199
break;
@@ -1097,10 +1283,11 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
1283
response = objToString(interfaces, 0, ' ', true);
1284
break;
1285
}
1100
- default: { // This is an unknown command, return an error message
1101
- response = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.';
1286
+ case 'name':
1287
+ {
1288
+ response = 'Service Name = ' + require('MeshAgent').serviceName;
1289
+ }
1290
break;
1103
- }
1291
}
1292
} catch (e) { response = "Command returned an exception error: " + e; console.log(e); }
1293
if (response != null) { sendConsoleText(response, sessionid); }