Mesh agents can now connect and skip server cert check to boost speed

This commit is contained in:
Ylian Saint-Hilaire 2018-08-21 15:08:15 -07:00
parent d3db0e4ef6
commit 82801f4069
9 changed files with 226 additions and 225 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -185,6 +185,10 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Use our server private key to sign the ServerHash + AgentNonce + ServerNonce // Use our server private key to sign the ServerHash + AgentNonce + ServerNonce
obj.agentnonce = msg.substring(50); obj.agentnonce = msg.substring(50);
// Check if we got the agent auth confirmation
if ((obj.receivedCommands & 8) == 0) {
// If we did not get an indication that the agent already validated this server, send the server signature.
if (obj.useSwarmCert == true) { if (obj.useSwarmCert == true) {
// Perform the hash signature using older swarm server certificate // Perform the hash signature using older swarm server certificate
obj.parent.parent.certificateOperations.acceleratorPerformSignature(1, msg.substring(2) + obj.nonce, obj, function (obj2, signature) { obj.parent.parent.certificateOperations.acceleratorPerformSignature(1, msg.substring(2) + obj.nonce, obj, function (obj2, signature) {
@ -198,6 +202,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
obj2.send(obj2.common.ShortToStr(2) + obj.common.ShortToStr(obj2.parent.agentCertificateAsn1.length) + obj2.parent.agentCertificateAsn1 + signature); // Command 2, certificate + signature obj2.send(obj2.common.ShortToStr(2) + obj.common.ShortToStr(obj2.parent.agentCertificateAsn1.length) + obj2.parent.agentCertificateAsn1 + signature); // Command 2, certificate + signature
}); });
} }
}
// Check the agent signature if we can // Check the agent signature if we can
if (obj.unauthsign != null) { if (obj.unauthsign != null) {
@ -242,6 +247,10 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
obj.agentInfo.computerName = msg.substring(72, 72 + computerNameLen); obj.agentInfo.computerName = msg.substring(72, 72 + computerNameLen);
obj.dbMeshKey = 'mesh/' + obj.domain.id + '/' + obj.meshid; obj.dbMeshKey = 'mesh/' + obj.domain.id + '/' + obj.meshid;
completeAgentConnection(); completeAgentConnection();
} else if (cmd == 4) {
if ((msg.length < 2) || ((obj.receivedCommands & 8) != 0)) return;
obj.receivedCommands += 8; // Agent can't send the same command twice on the same connection ever. Block DOS attack path.
// Agent already authenticated the server, wants to skip the server signature - which is great for server performance.
} else if (cmd == 5) { } else if (cmd == 5) {
// ServerID. Agent is telling us what serverid it expects. Useful if we have many server certificates. // ServerID. Agent is telling us what serverid it expects. Useful if we have many server certificates.
if ((msg.substring(2, 34) == obj.parent.swarmCertificateHash256) || (msg.substring(2, 50) == obj.parent.swarmCertificateHash384)) { obj.useSwarmCert = true; } if ((msg.substring(2, 34) == obj.parent.swarmCertificateHash256) || (msg.substring(2, 50) == obj.parent.swarmCertificateHash384)) { obj.useSwarmCert = true; }
@ -263,13 +272,12 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
// Once we get all the information about an agent, run this to hook everything up to the server // Once we get all the information about an agent, run this to hook everything up to the server
function completeAgentConnection() { function completeAgentConnection() {
if (obj.authenticated = !1 || obj.meshid == null || obj.pendingCompleteAgentConnection) return; if ((obj.authenticated != 1) || (obj.meshid == null) || obj.pendingCompleteAgentConnection) return;
obj.pendingCompleteAgentConnection = true; obj.pendingCompleteAgentConnection = true;
// Check that the mesh exists // Check that the mesh exists
obj.db.Get(obj.dbMeshKey, function (err, meshes) { var mesh = obj.parent.meshes[obj.dbMeshKey];
if (meshes.length == 0) { console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddr + ', ' + obj.dbMeshKey + ').'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours. if (mesh == null) { console.log('Agent connected with invalid domain/mesh, holding connection (' + obj.remoteaddr + ', ' + obj.dbMeshKey + ').'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours.
var mesh = meshes[0];
if (mesh.mtype != 2) { console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddr + ').'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours. if (mesh.mtype != 2) { console.log('Agent connected with invalid mesh type, holding connection (' + obj.remoteaddr + ').'); return; } // If we disconnect, the agnet will just reconnect. We need to log this or tell agent to connect in a few hours.
// Check that the node exists // Check that the node exists
@ -385,7 +393,6 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
} }
}); });
}); });
});
} }
// Get the web certificate hash for the speficied domain // Get the web certificate hash for the speficied domain
@ -566,9 +573,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
if (command.caps == null || command.caps == null) { command.caps = 0; } else { if (typeof command.caps != 'number') command.caps = 0; } if (command.caps == null || command.caps == null) { command.caps = 0; } else { if (typeof command.caps != 'number') command.caps = 0; }
// Check that the mesh exists // Check that the mesh exists
obj.db.Get(obj.dbMeshKey, function (err, meshes) { var mesh = obj.parent.meshes[obj.dbMeshKey];
if (meshes.length != 1) return; if (mesh == null) return;
var mesh = meshes[0];
// Get the node and change it if needed // Get the node and change it if needed
obj.db.Get(obj.dbNodeKey, function (err, nodes) { obj.db.Get(obj.dbNodeKey, function (err, nodes) {
if (nodes.length != 1) return; if (nodes.length != 1) return;
@ -607,20 +614,19 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
} }
} }
}); });
});
} }
// Change the current core information string and event it // Change the current core information string and event it
function ChangeAgentLocationInfo(command) { function ChangeAgentLocationInfo(command) {
if ((command == null) || (command == null)) return; // Safety, should never happen. if ((command == null) || (command == null)) { return; } // Safety, should never happen.
// Check that the mesh exists // Check that the mesh exists
obj.db.Get(obj.dbMeshKey, function (err, meshes) { var mesh = obj.parent.meshes[obj.dbMeshKey];
if (meshes.length != 1) return; if (mesh == null) return;
var mesh = meshes[0];
// Get the node and change it if needed // Get the node and change it if needed
obj.db.Get(obj.dbNodeKey, function (err, nodes) { obj.db.Get(obj.dbNodeKey, function (err, nodes) {
if (nodes.length != 1) return; if (nodes.length != 1) { return; }
var device = nodes[0]; var device = nodes[0];
if (device.agent) { if (device.agent) {
var changes = [], change = 0; var changes = [], change = 0;
@ -637,13 +643,12 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ') }; var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ') };
if (obj.agentInfo.capabilities & 0x20) { event.nolog = 1; } // If this is a temporary device, don't log changes if (obj.agentInfo.capabilities & 0x20) { event.nolog = 1; } // If this is a temporary device, don't log changes
var device2 = obj.common.Clone(device); var device2 = obj.common.Clone(device);
if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this. if (device2.intelamt && device2.intelamt.pass) { delete device2.intelamt.pass; } // Remove the Intel AMT password before eventing this.
event.node = device; event.node = device;
obj.parent.parent.DispatchEvent(['*', device.meshid], obj, event); obj.parent.parent.DispatchEvent(['*', device.meshid], obj, event);
} }
} }
}); });
});
} }
// Update the mesh agent tab in the database // Update the mesh agent tab in the database

View File

@ -1,6 +1,6 @@
{ {
"name": "meshcentral", "name": "meshcentral",
"version": "0.1.9-j", "version": "0.1.9-k",
"keywords": [ "keywords": [
"Remote Management", "Remote Management",
"Intel AMT", "Intel AMT",

View File

@ -1468,10 +1468,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
res.sendFile(argentInfo.path); res.sendFile(argentInfo.path);
} else { } else {
// We are going to embed the .msh file into the Windows executable (signed or not). // We are going to embed the .msh file into the Windows executable (signed or not).
// First, query the meshid to build the .msh file // First, fetch the mesh object to build the .msh file
obj.db.Get('mesh/' + domain.id + '/' + req.query.meshid, function (err, meshes) { var mesh = obj.meshes['mesh/' + domain.id + '/' + req.query.meshid];
if (meshes.length != 1) { res.sendStatus(401); return; } if (mesh == null) { res.sendStatus(401); return; }
var mesh = meshes[0];
// If required, check if this user has rights to do this // If required, check if this user has rights to do this
if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true)) { if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true)) {
@ -1493,7 +1492,6 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
if (req.query.tag != null) { meshsettings += "Tag=" + req.query.tag + "\r\n"; } if (req.query.tag != null) { meshsettings += "Tag=" + req.query.tag + "\r\n"; }
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=' + argentInfo.rname }); res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=' + argentInfo.rname });
obj.parent.exeHandler.streamExeWithMeshPolicy({ platform: 'win32', sourceFileName: obj.parent.meshAgentBinaries[req.query.id].path, destinationStream: res, msh: meshsettings, peinfo: obj.parent.meshAgentBinaries[req.query.id].pe }); obj.parent.exeHandler.streamExeWithMeshPolicy({ platform: 'win32', sourceFileName: obj.parent.meshAgentBinaries[req.query.id].path, destinationStream: res, msh: meshsettings, peinfo: obj.parent.meshAgentBinaries[req.query.id].pe });
});
} }
} else if (req.query.script != null) { } else if (req.query.script != null) {
// Send a specific mesh install script back // Send a specific mesh install script back
@ -1602,10 +1600,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
// If required, check if this user has rights to do this // If required, check if this user has rights to do this
if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true) && (req.session.userid == null)) { res.sendStatus(401); return; } if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true) && (req.session.userid == null)) { res.sendStatus(401); return; }
// Query the meshid // Fetch the mesh object
obj.db.Get('mesh/' + domain.id + '/' + req.query.id, function (err, meshes) { var mesh = obj.meshes['mesh/' + domain.id + '/' + req.query.id];
if (meshes.length != 1) { res.sendStatus(401); return; } if (mesh == null) { res.sendStatus(401); return; }
var mesh = meshes[0];
// If needed, check if this user has rights to do this // If needed, check if this user has rights to do this
if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true)) { if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true)) {
@ -1627,7 +1624,6 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=meshagent.msh' }); res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=meshagent.msh' });
res.send(meshsettings); res.send(meshsettings);
});
} }
// Add HTTP security headers to all responses // Add HTTP security headers to all responses