diff --git a/agents/meshcore.js b/agents/meshcore.js index d811af12..e96f77b7 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -905,7 +905,7 @@ function createMeshCore(agent) switch (data.action) { case 'agentupdate': - agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash }); + agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash, sessionid: data.sessionid }); break; case 'msg': { switch (data.type) @@ -3053,11 +3053,11 @@ function createMeshCore(agent) break; } case 'agentupdate': - require('MeshAgent').SendCommand({ action: 'agentupdate' }); + require('MeshAgent').SendCommand({ action: 'agentupdate', sessionid: sessionid }); break; case 'agentupdateex': // Perform an direct agent update without requesting any information from the server, this should not typically be used. - agentUpdate_Start(null, { session: sessionid }); + agentUpdate_Start(null, { sessionid: sessionid }); break; case 'msh': response = JSON.stringify(_MSH(), null, 2); @@ -4343,7 +4343,7 @@ function createMeshCore(agent) function agentUpdate_Start(updateurl, updateoptions) { // If this value is null - var sessionid = updateoptions != null ? updateoptions.session : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted + var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted if (this._selfupdate != null) { @@ -4380,7 +4380,7 @@ function createMeshCore(agent) return; } - sendConsoleText('Downloading update...', sessionid); + if (sessionid != null) { sendConsoleText('Downloading update...', sessionid); } var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl); options.protocol = 'https:'; if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); } @@ -4422,7 +4422,7 @@ function createMeshCore(agent) { if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase()) { - sendConsoleText('Download complete. HASH verified.', sessionid); + if (sessionid != null) { sendConsoleText('Download complete. HASH verified.', sessionid); } } else { @@ -4433,10 +4433,13 @@ function createMeshCore(agent) } else { - sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid); + if (sessionid != null) { sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid); } } - sendConsoleText('Updating and restarting agent...', sessionid); + // Send an indication to the server that we got the update download correctly. + try { mesh.SendCommand({ action: 'agentupdatedownloaded' }); } catch (e) { } + + if (sessionid != null) { sendConsoleText('Updating and restarting agent...', sessionid); } if (process.platform == 'win32') { // Use _wexecve() equivalent to perform the update @@ -4458,7 +4461,7 @@ function createMeshCore(agent) m |= (require('fs').CHMOD_MODES.S_IXUSR | require('fs').CHMOD_MODES.S_IXGRP | require('fs').CHMOD_MODES.S_IXOTH); require('fs').chmodSync(process.execPath, m); - sendConsoleText('Restarting service...', sessionid); + if (sessionid != null) { sendConsoleText('Restarting service...', sessionid); } try { // restart service diff --git a/agents/recoverycore.js b/agents/recoverycore.js index 20e367be..2ad7e99f 100644 --- a/agents/recoverycore.js +++ b/agents/recoverycore.js @@ -86,7 +86,7 @@ function windows_execve(name, agentfilename, sessionid) function agentUpdate_Start(updateurl, updateoptions) { // If this value is null - var sessionid = updateoptions != null ? updateoptions.session : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted + var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted if (this._selfupdate != null) { @@ -123,7 +123,7 @@ function agentUpdate_Start(updateurl, updateoptions) return; } - sendConsoleText('Downloading update...', sessionid); + if (sessionid != null) { sendConsoleText('Downloading update...', sessionid); } var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl); options.protocol = 'https:'; if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); } @@ -165,7 +165,7 @@ function agentUpdate_Start(updateurl, updateoptions) { if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase()) { - sendConsoleText('Download complete. HASH verified.', sessionid); + if (sessionid != null) { sendConsoleText('Download complete. HASH verified.', sessionid); } } else { @@ -179,7 +179,10 @@ function agentUpdate_Start(updateurl, updateoptions) sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid); } - sendConsoleText('Updating and restarting agent...', sessionid); + // Send an indication to the server that we got the update download correctly. + try { mesh.SendCommand({ action: 'agentupdatedownloaded' }); } catch (e) { } + + if (sessionid != null) { sendConsoleText('Updating and restarting agent...', sessionid); } if (process.platform == 'win32') { // Use _wexecve() equivalent to perform the update @@ -201,7 +204,7 @@ function agentUpdate_Start(updateurl, updateoptions) m |= (require('fs').CHMOD_MODES.S_IXUSR | require('fs').CHMOD_MODES.S_IXGRP | require('fs').CHMOD_MODES.S_IXOTH); require('fs').chmodSync(process.execPath, m); - sendConsoleText('Restarting service...', sessionid); + if (sessionid != null) { sendConsoleText('Restarting service...', sessionid); } try { // restart service @@ -406,7 +409,7 @@ require('MeshAgent').AddCommandHandler(function (data) switch (data.action) { case 'agentupdate': - agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash }); + agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash, sessionid: data.sessionid }); break; case 'msg': { @@ -662,11 +665,11 @@ function processConsoleCommand(cmd, args, rights, sessionid) { break; case 'agentupdate': // Request that the server send a agent update command - require('MeshAgent').SendCommand({ action: 'agentupdate' }); + require('MeshAgent').SendCommand({ action: 'agentupdate', sessionid: sessionid }); break; case 'agentupdateex': // Perform an direct agent update without requesting any information from the server, this should not typically be used. - agentUpdate_Start(null, { session: sessionid }); + agentUpdate_Start(null, { sessionid: sessionid }); break; case 'osinfo': { // Return the operating system information var i = 1; diff --git a/meshagent.js b/meshagent.js index f9a59a96..f0482007 100644 --- a/meshagent.js +++ b/meshagent.js @@ -89,7 +89,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { // Set this agent as no longer authenticated obj.authenticated = -1; - // If we where updating the agent, clean that up. + // If we where updating the agent using native method, clean that up. if (obj.agentUpdate != null) { if (obj.agentUpdate.fd) { try { parent.fs.close(obj.agentUpdate.fd); } catch (ex) { } } parent.parent.taskLimiter.completed(obj.agentUpdate.taskid); // Indicate this task complete @@ -97,6 +97,12 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { delete obj.agentUpdate; } + // If we where updating the agent meshcore method, clean that up. + if (obj.agentCoreUpdateTaskId != null) { + parent.parent.taskLimiter.completed(obj.agentCoreUpdateTaskId); + delete obj.agentCoreUpdateTaskId; + } + // Perform timer cleanup if (obj.pingtimer) { clearInterval(obj.pingtimer); delete obj.pingtimer; } if (obj.pongtimer) { clearInterval(obj.pongtimer); delete obj.pongtimer; } @@ -238,7 +244,6 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { if (agentUpdateMethod === 2) { // Use meshcore agent update system // Send the recovery core to the agent, if the agent is capable of running one if (((obj.agentInfo.capabilities & 16) != 0) && (parent.parent.meshAgentsArchitectureNumbers[obj.agentInfo.agentId].core != null)) { - //obj.agentCoreCheck = 1001; obj.agentCoreUpdate = true; obj.sendBinary(common.ShortToStr(11) + common.ShortToStr(0)); } @@ -1152,17 +1157,26 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { { if ((obj.agentCoreUpdate === true) && (obj.agentExeInfo != null)) { // Agent update. The recovery core was loaded in the agent, send a command to update the agent - var cmd = { action: 'agentupdate', url: obj.agentExeInfo.url, hash: obj.agentExeInfo.hashhex }; - // Add the hash - if (obj.agentExeInfo.fileHash != null) { cmd.hash = obj.agentExeInfo.fileHashHex; } else { cmd.hash = obj.agentExeInfo.hashhex; } - // Add server TLS cert hash - if (parent.parent.args.ignoreagenthashcheck !== true) { - const tlsCertHash = parent.webCertificateFullHashs[domain.id]; - if (tlsCertHash != null) { cmd.servertlshash = Buffer.from(tlsCertHash, 'binary').toString('hex'); } - } - // Send the agent update command - obj.send(JSON.stringify(cmd)); - //delete obj.agentCoreUpdate; + parent.parent.taskLimiter.launch(function (argument, taskid, taskLimiterQueue) { // Medium priority task + // If agent disconnection, complete and exit now. + if (obj.authenticated != 2) { parent.parent.taskLimiter.completed(taskid); return; } + + // Agent update. The recovery core was loaded in the agent, send a command to update the agent + obj.agentCoreUpdateTaskId = taskid; + var cmd = { action: 'agentupdate', url: obj.agentExeInfo.url, hash: obj.agentExeInfo.hashhex }; + + // Add the hash + if (obj.agentExeInfo.fileHash != null) { cmd.hash = obj.agentExeInfo.fileHashHex; } else { cmd.hash = obj.agentExeInfo.hashhex; } + + // Add server TLS cert hash + if (parent.parent.args.ignoreagenthashcheck !== true) { + const tlsCertHash = parent.webCertificateFullHashs[domain.id]; + if (tlsCertHash != null) { cmd.servertlshash = Buffer.from(tlsCertHash, 'binary').toString('hex'); } + } + + // Send the agent update command + obj.send(JSON.stringify(cmd)); + }, null, 1); } else { // Sent by the agent to update agent information ChangeAgentCoreInfo(command); @@ -1456,17 +1470,38 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { break; } case 'agentupdate': { - // Agent is requesting an agent update - var cmd = { action: 'agentupdate', url: obj.agentExeInfo.url, hash: obj.agentExeInfo.hashhex }; - // Add the hash - if (obj.agentExeInfo.fileHash != null) { cmd.hash = obj.agentExeInfo.fileHashHex; } else { cmd.hash = obj.agentExeInfo.hashhex; } - // Add server TLS cert hash - if (parent.parent.args.ignoreagenthashcheck !== true) { - const tlsCertHash = parent.webCertificateFullHashs[domain.id]; - if (tlsCertHash != null) { cmd.servertlshash = Buffer.from(tlsCertHash, 'binary').toString('hex'); } + var func = function agentUpdateFunc(argument, taskid, taskLimiterQueue) { // Medium priority task + // If agent disconnection, complete and exit now. + if (obj.authenticated != 2) { parent.parent.taskLimiter.completed(taskid); return; } + + // Agent is requesting an agent update + obj.agentCoreUpdateTaskId = taskid; + var cmd = { action: 'agentupdate', url: obj.agentExeInfo.url, hash: obj.agentExeInfo.hashhex, sessionid: agentUpdateFunc.sessionid }; + + // Add the hash + if (obj.agentExeInfo.fileHash != null) { cmd.hash = obj.agentExeInfo.fileHashHex; } else { cmd.hash = obj.agentExeInfo.hashhex; } + + // Add server TLS cert hash + if (parent.parent.args.ignoreagenthashcheck !== true) { + const tlsCertHash = parent.webCertificateFullHashs[domain.id]; + if (tlsCertHash != null) { cmd.servertlshash = Buffer.from(tlsCertHash, 'binary').toString('hex'); } + } + + // Send the agent update command + obj.send(JSON.stringify(cmd)); + } + func.sessionid = command.sessionid; + + // Agent update. The recovery core was loaded in the agent, send a command to update the agent + parent.parent.taskLimiter.launch(func, null, 1); + break; + } + case 'agentupdatedownloaded': { + if (obj.agentCoreUpdateTaskId != null) { + // Indicate this udpate task is complete + parent.parent.taskLimiter.completed(obj.agentCoreUpdateTaskId); + delete obj.agentCoreUpdateTaskId; } - // Send the agent update command - obj.send(JSON.stringify(cmd)); break; } default: {