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,18 +185,23 @@ 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);
if (obj.useSwarmCert == true) {
// Perform the hash signature using older swarm server certificate // Check if we got the agent auth confirmation
obj.parent.parent.certificateOperations.acceleratorPerformSignature(1, msg.substring(2) + obj.nonce, obj, function (obj2, signature) { if ((obj.receivedCommands & 8) == 0) {
// Send back our certificate + signature // If we did not get an indication that the agent already validated this server, send the server signature.
obj2.send(obj2.common.ShortToStr(2) + obj2.common.ShortToStr(obj2.parent.swarmCertificateAsn1.length) + obj2.parent.swarmCertificateAsn1 + signature); // Command 2, certificate + signature if (obj.useSwarmCert == true) {
}); // Perform the hash signature using older swarm server certificate
} else { obj.parent.parent.certificateOperations.acceleratorPerformSignature(1, msg.substring(2) + obj.nonce, obj, function (obj2, signature) {
// Perform the hash signature using the server agent certificate // Send back our certificate + signature
obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, obj, function (obj2, signature) { obj2.send(obj2.common.ShortToStr(2) + obj2.common.ShortToStr(obj2.parent.swarmCertificateAsn1.length) + obj2.parent.swarmCertificateAsn1 + signature); // Command 2, certificate + signature
// Send back our certificate + signature });
obj2.send(obj2.common.ShortToStr(2) + obj.common.ShortToStr(obj2.parent.agentCertificateAsn1.length) + obj2.parent.agentCertificateAsn1 + signature); // Command 2, certificate + signature } else {
}); // Perform the hash signature using the server agent certificate
obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, obj, function (obj2, signature) {
// Send back our 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
@ -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,127 +272,125 @@ 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
obj.db.Get(obj.dbNodeKey, function (err, nodes) { obj.db.Get(obj.dbNodeKey, function (err, nodes) {
var device; var device;
// Mark when we connected to this agent // Mark when we connected to this agent
obj.connectTime = Date.now(); obj.connectTime = Date.now();
if (nodes.length == 0) { if (nodes.length == 0) {
// This node does not exist, create it. // This node does not exist, create it.
device = { type: 'node', mtype: mesh.mtype, _id: obj.dbNodeKey, icon: obj.agentInfo.platformType, meshid: obj.dbMeshKey, name: obj.agentInfo.computerName, rname: obj.agentInfo.computerName, domain: domain.id, agent: { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }, host: null }; device = { type: 'node', mtype: mesh.mtype, _id: obj.dbNodeKey, icon: obj.agentInfo.platformType, meshid: obj.dbMeshKey, name: obj.agentInfo.computerName, rname: obj.agentInfo.computerName, domain: domain.id, agent: { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }, host: null };
obj.db.Set(device); obj.db.Set(device);
// Event the new node // Event the new node
if (obj.agentInfo.capabilities & 0x20) { if (obj.agentInfo.capabilities & 0x20) {
// This is a temporary agent, don't log. // This is a temporary agent, don't log.
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 }) obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, domain: domain.id, nolog: 1 })
} else {
var change = 'Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name;
obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, msg: change, domain: domain.id })
}
} else { } else {
// Device already exists, look if changes has occured var change = 'Added device ' + obj.agentInfo.computerName + ' to mesh ' + mesh.name;
device = nodes[0]; obj.parent.parent.DispatchEvent(['*', obj.dbMeshKey], obj, { etype: 'node', action: 'addnode', node: device, msg: change, domain: domain.id })
if (device.agent == null) { }
device.agent = { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }; change = 1; } else {
} else { // Device already exists, look if changes has occured
var changes = [], change = 0, log = 0; device = nodes[0];
if (device.rname != obj.agentInfo.computerName) { device.rname = obj.agentInfo.computerName; change = 1; changes.push('computer name'); } if (device.agent == null) {
if (device.agent.ver != obj.agentInfo.agentVersion) { device.agent.ver = obj.agentInfo.agentVersion; change = 1; changes.push('agent version'); } device.agent = { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }; change = 1;
if (device.agent.id != obj.agentInfo.agentId) { device.agent.id = obj.agentInfo.agentId; change = 1; changes.push('agent type'); } } else {
if ((device.agent.caps & 24) != (obj.agentInfo.capabilities & 24)) { device.agent.caps = obj.agentInfo.capabilities; change = 1; changes.push('agent capabilities'); } // If agent console or javascript support changes, update capabilities var changes = [], change = 0, log = 0;
if (device.meshid != obj.dbMeshKey) { device.meshid = obj.dbMeshKey; change = 1; log = 1; changes.push('agent meshid'); } // TODO: If the meshid changes, we need to event a device add/remove on both meshes if (device.rname != obj.agentInfo.computerName) { device.rname = obj.agentInfo.computerName; change = 1; changes.push('computer name'); }
if (change == 1) { if (device.agent.ver != obj.agentInfo.agentVersion) { device.agent.ver = obj.agentInfo.agentVersion; change = 1; changes.push('agent version'); }
obj.db.Set(device); if (device.agent.id != obj.agentInfo.agentId) { device.agent.id = obj.agentInfo.agentId; change = 1; changes.push('agent type'); }
if ((device.agent.caps & 24) != (obj.agentInfo.capabilities & 24)) { device.agent.caps = obj.agentInfo.capabilities; change = 1; changes.push('agent capabilities'); } // If agent console or javascript support changes, update capabilities
if (device.meshid != obj.dbMeshKey) { device.meshid = obj.dbMeshKey; change = 1; log = 1; changes.push('agent meshid'); } // TODO: If the meshid changes, we need to event a device add/remove on both meshes
if (change == 1) {
obj.db.Set(device);
// If this is a temporary device, don't log changes // If this is a temporary device, don't log changes
if (obj.agentInfo.capabilities & 0x20) { log = 0; } if (obj.agentInfo.capabilities & 0x20) { log = 0; }
// Event the node change // Event the node change
var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id }; var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id };
if (log == 0) { event.nolog = 1; } else { event.msg = 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', '); } if (log == 0) { event.nolog = 1; } else { event.msg = 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', '); }
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);
}
} }
} }
}
// Check if this agent is already connected // Check if this agent is already connected
var dupAgent = obj.parent.wsagents[obj.dbNodeKey]; var dupAgent = obj.parent.wsagents[obj.dbNodeKey];
obj.parent.wsagents[obj.dbNodeKey] = obj; obj.parent.wsagents[obj.dbNodeKey] = obj;
if (dupAgent) { if (dupAgent) {
// Close the duplicate agent // Close the duplicate agent
if (obj.nodeid != null) { obj.parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); } if (obj.nodeid != null) { obj.parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); }
dupAgent.close(3); dupAgent.close(3);
} else {
// Indicate the agent is connected
obj.parent.parent.SetConnectivityState(obj.dbMeshKey, obj.dbNodeKey, obj.connectTime, 1, 1);
}
// We are done, ready to communicate with this agent
delete obj.pendingCompleteAgentConnection;
obj.authenticated = 2;
// Command 4, inform mesh agent that it's authenticated.
obj.send(obj.common.ShortToStr(4));
// Check the mesh core, if the agent is capable of running one
if ((obj.agentInfo.capabilities & 16) != 0) { obj.send(obj.common.ShortToStr(11) + obj.common.ShortToStr(0)); } // Command 11, ask for mesh core hash.
// Check if we need to make an native update check
obj.agentExeInfo = obj.parent.parent.meshAgentBinaries[obj.agentInfo.agentId];
if ((obj.agentExeInfo != null) && (obj.agentExeInfo.update == true)) { obj.send(obj.common.ShortToStr(12) + obj.common.ShortToStr(0)); } // Ask the agent for it's executable binary hash
// Check if we already have IP location information for this node
obj.db.Get('iploc_' + obj.remoteaddr, function (err, iplocs) {
if (iplocs.length == 1) {
// We have a location in the database for this remote IP
var iploc = nodes[0], x = {};
if ((iploc != null) && (iploc.ip != null) && (iploc.loc != null)) {
x.publicip = iploc.ip;
x.iploc = iploc.loc + ',' + (Math.floor((new Date(iploc.date)) / 1000));
ChangeAgentLocationInfo(x);
}
} else { } else {
// Indicate the agent is connected // Check if we need to ask for the IP location
obj.parent.parent.SetConnectivityState(obj.dbMeshKey, obj.dbNodeKey, obj.connectTime, 1, 1); var doIpLocation = 0;
} if (device.iploc == null) {
doIpLocation = 1;
// We are done, ready to communicate with this agent
delete obj.pendingCompleteAgentConnection;
obj.authenticated = 2;
// Command 4, inform mesh agent that it's authenticated.
obj.send(obj.common.ShortToStr(4));
// Check the mesh core, if the agent is capable of running one
if ((obj.agentInfo.capabilities & 16) != 0) { obj.send(obj.common.ShortToStr(11) + obj.common.ShortToStr(0)); } // Command 11, ask for mesh core hash.
// Check if we need to make an native update check
obj.agentExeInfo = obj.parent.parent.meshAgentBinaries[obj.agentInfo.agentId];
if ((obj.agentExeInfo != null) && (obj.agentExeInfo.update == true)) { obj.send(obj.common.ShortToStr(12) + obj.common.ShortToStr(0)); } // Ask the agent for it's executable binary hash
// Check if we already have IP location information for this node
obj.db.Get('iploc_' + obj.remoteaddr, function (err, iplocs) {
if (iplocs.length == 1) {
// We have a location in the database for this remote IP
var iploc = nodes[0], x = {};
if ((iploc != null) && (iploc.ip != null) && (iploc.loc != null)) {
x.publicip = iploc.ip;
x.iploc = iploc.loc + ',' + (Math.floor((new Date(iploc.date)) / 1000));
ChangeAgentLocationInfo(x);
}
} else { } else {
// Check if we need to ask for the IP location var loc = device.iploc.split(',');
var doIpLocation = 0; if (loc.length < 3) {
if (device.iploc == null) { doIpLocation = 2;
doIpLocation = 1;
} else { } else {
var loc = device.iploc.split(','); var t = new Date((parseFloat(loc[2]) * 1000)), now = Date.now();
if (loc.length < 3) { t.setDate(t.getDate() + 20);
doIpLocation = 2; if (t < now) { doIpLocation = 3; }
} else {
var t = new Date((parseFloat(loc[2]) * 1000)), now = Date.now();
t.setDate(t.getDate() + 20);
if (t < now) { doIpLocation = 3; }
}
}
// If we need to ask for IP location, see if we have the quota to do it.
if (doIpLocation > 0) {
obj.db.getValueOfTheDay('ipLocationRequestLimitor', 10, function (ipLocationLimitor) {
if (ipLocationLimitor.value > 0) {
ipLocationLimitor.value--;
obj.db.Set(ipLocationLimitor);
obj.send(JSON.stringify({ action: 'iplocation' }));
}
});
} }
} }
});
// If we need to ask for IP location, see if we have the quota to do it.
if (doIpLocation > 0) {
obj.db.getValueOfTheDay('ipLocationRequestLimitor', 10, function (ipLocationLimitor) {
if (ipLocationLimitor.value > 0) {
ipLocationLimitor.value--;
obj.db.Set(ipLocationLimitor);
obj.send(JSON.stringify({ action: 'iplocation' }));
}
});
}
}
}); });
}); });
} }
@ -566,83 +573,81 @@ 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
obj.db.Get(obj.dbNodeKey, function (err, nodes) {
if (nodes.length != 1) return;
var device = nodes[0];
if (device.agent) {
var changes = [], change = 0;
// Check if anything changes // Get the node and change it if needed
if (command.name && (command.name != device.name)) { change = 1; device.name = command.name; changes.push('name'); } obj.db.Get(obj.dbNodeKey, function (err, nodes) {
if (device.agent.core != command.value) { if ((command.value == null) && (device.agent.core != null)) { delete device.agent.core; } else { device.agent.core = command.value; } change = 1; changes.push('agent core'); } if (nodes.length != 1) return;
if ((device.agent.caps & 0xFFFFFFE7) != (command.caps & 0xFFFFFFE7)) { device.agent.caps = ((device.agent.caps & 24) + (command.caps & 0xFFFFFFE7)); change = 1; changes.push('agent capabilities'); } // Allow Javascript on the agent to change all capabilities except console and javascript support var device = nodes[0];
if (command.intelamt) { if (device.agent) {
if (!device.intelamt) { device.intelamt = {}; } var changes = [], change = 0;
if ((command.intelamt.ver != null) && (device.intelamt.ver != command.intelamt.ver)) { device.intelamt.ver = command.intelamt.ver; change = 1; changes.push('AMT version'); }
if ((command.intelamt.state != null) && (device.intelamt.state != command.intelamt.state)) { device.intelamt.state = command.intelamt.state; change = 1; changes.push('AMT state'); }
if ((command.intelamt.flags != null) && (device.intelamt.flags != command.intelamt.flags)) { device.intelamt.flags = command.intelamt.flags; change = 1; changes.push('AMT flags'); }
if ((command.intelamt.host != null) && (device.intelamt.host != command.intelamt.host)) { device.intelamt.host = command.intelamt.host; change = 1; changes.push('AMT host'); }
if ((command.intelamt.uuid != null) && (device.intelamt.uuid != command.intelamt.uuid)) { device.intelamt.uuid = command.intelamt.uuid; change = 1; changes.push('AMT uuid'); }
}
if (mesh.mtype == 2) {
if (device.host != obj.remoteaddr) { device.host = obj.remoteaddr; change = 1; changes.push('host'); }
// TODO: Check that the agent has an interface that is the same as the one we got this websocket connection on. Only set if we have a match.
}
// If there are changes, save and event // Check if anything changes
if (change == 1) { if (command.name && (command.name != device.name)) { change = 1; device.name = command.name; changes.push('name'); }
obj.db.Set(device); if (device.agent.core != command.value) { if ((command.value == null) && (device.agent.core != null)) { delete device.agent.core; } else { device.agent.core = command.value; } change = 1; changes.push('agent core'); }
if ((device.agent.caps & 0xFFFFFFE7) != (command.caps & 0xFFFFFFE7)) { device.agent.caps = ((device.agent.caps & 24) + (command.caps & 0xFFFFFFE7)); change = 1; changes.push('agent capabilities'); } // Allow Javascript on the agent to change all capabilities except console and javascript support
// Event the node change if (command.intelamt) {
var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ') }; if (!device.intelamt) { device.intelamt = {}; }
if (obj.agentInfo.capabilities & 0x20) { event.nolog = 1; } // If this is a temporary device, don't log changes if ((command.intelamt.ver != null) && (device.intelamt.ver != command.intelamt.ver)) { device.intelamt.ver = command.intelamt.ver; change = 1; changes.push('AMT version'); }
var device2 = obj.common.Clone(device); if ((command.intelamt.state != null) && (device.intelamt.state != command.intelamt.state)) { device.intelamt.state = command.intelamt.state; change = 1; changes.push('AMT state'); }
if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this. if ((command.intelamt.flags != null) && (device.intelamt.flags != command.intelamt.flags)) { device.intelamt.flags = command.intelamt.flags; change = 1; changes.push('AMT flags'); }
event.node = device; if ((command.intelamt.host != null) && (device.intelamt.host != command.intelamt.host)) { device.intelamt.host = command.intelamt.host; change = 1; changes.push('AMT host'); }
obj.parent.parent.DispatchEvent(['*', device.meshid], obj, event); if ((command.intelamt.uuid != null) && (device.intelamt.uuid != command.intelamt.uuid)) { device.intelamt.uuid = command.intelamt.uuid; change = 1; changes.push('AMT uuid'); }
}
} }
}); if (mesh.mtype == 2) {
if (device.host != obj.remoteaddr) { device.host = obj.remoteaddr; change = 1; changes.push('host'); }
// TODO: Check that the agent has an interface that is the same as the one we got this websocket connection on. Only set if we have a match.
}
// If there are changes, save and event
if (change == 1) {
obj.db.Set(device);
// Event the node change
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
var device2 = obj.common.Clone(device);
if (device2.intelamt && device2.intelamt.pass) delete device2.intelamt.pass; // Remove the Intel AMT password before eventing this.
event.node = device;
obj.parent.parent.DispatchEvent(['*', device.meshid], obj, event);
}
}
}); });
} }
// 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
obj.db.Get(obj.dbNodeKey, function (err, nodes) {
if (nodes.length != 1) return;
var device = nodes[0];
if (device.agent) {
var changes = [], change = 0;
// Check if anything changes // Get the node and change it if needed
if ((command.publicip) && (device.publicip != command.publicip)) { device.publicip = command.publicip; change = 1; changes.push('public ip'); } obj.db.Get(obj.dbNodeKey, function (err, nodes) {
if ((command.iploc) && (device.iploc != command.iploc)) { device.iploc = command.iploc; change = 1; changes.push('ip location'); } if (nodes.length != 1) { return; }
var device = nodes[0];
if (device.agent) {
var changes = [], change = 0;
// If there are changes, save and event // Check if anything changes
if (change == 1) { if ((command.publicip) && (device.publicip != command.publicip)) { device.publicip = command.publicip; change = 1; changes.push('public ip'); }
obj.db.Set(device); if ((command.iploc) && (device.iploc != command.iploc)) { device.iploc = command.iploc; change = 1; changes.push('ip location'); }
// Event the node change // If there are changes, save and event
var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ') }; if (change == 1) {
if (obj.agentInfo.capabilities & 0x20) { event.nolog = 1; } // If this is a temporary device, don't log changes obj.db.Set(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. // Event the node change
event.node = device; var event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id, msg: 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', ') };
obj.parent.parent.DispatchEvent(['*', device.meshid], obj, event); if (obj.agentInfo.capabilities & 0x20) { event.nolog = 1; } // If this is a temporary device, don't log changes
} var device2 = obj.common.Clone(device);
if (device2.intelamt && device2.intelamt.pass) { delete device2.intelamt.pass; } // Remove the Intel AMT password before eventing this.
event.node = device;
obj.parent.parent.DispatchEvent(['*', device.meshid], obj, event);
} }
}); }
}); });
} }

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,32 +1468,30 @@ 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)) {
var user = obj.users[req.session.userid]; var user = obj.users[req.session.userid];
var escUserId = obj.common.escapeFieldName(user._id); var escUserId = obj.common.escapeFieldName(user._id);
if ((user == null) || (mesh.links[escUserId] == null) || ((mesh.links[escUserId].rights & 1) == 0)) { res.sendStatus(401); return; } if ((user == null) || (mesh.links[escUserId] == null) || ((mesh.links[escUserId].rights & 1) == 0)) { res.sendStatus(401); return; }
if (domain.id != mesh.domain) { res.sendStatus(401); return; } if (domain.id != mesh.domain) { res.sendStatus(401); return; }
} }
var meshidhex = new Buffer(req.query.meshid.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase(); var meshidhex = new Buffer(req.query.meshid.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
var serveridhex = new Buffer(obj.agentCertificateHashBase64.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase(); var serveridhex = new Buffer(obj.agentCertificateHashBase64.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
// Build the agent connection URL. If we are using a sub-domain or one with a DNS, we need to craft the URL correctly. // Build the agent connection URL. If we are using a sub-domain or one with a DNS, we need to craft the URL correctly.
var xdomain = (domain.dns == null) ? domain.id : ''; var xdomain = (domain.dns == null) ? domain.id : '';
if (xdomain != '') xdomain += "/"; if (xdomain != '') xdomain += "/";
var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n"; var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; } if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
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,32 +1600,30 @@ 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)) {
var user = obj.users[req.session.userid]; var user = obj.users[req.session.userid];
var escUserId = obj.common.escapeFieldName(user._id); var escUserId = obj.common.escapeFieldName(user._id);
if ((user == null) || (mesh.links[escUserId] == null) || ((mesh.links[escUserId].rights & 1) == 0)) { res.sendStatus(401); return; } if ((user == null) || (mesh.links[escUserId] == null) || ((mesh.links[escUserId].rights & 1) == 0)) { res.sendStatus(401); return; }
if (domain.id != mesh.domain) { res.sendStatus(401); return; } if (domain.id != mesh.domain) { res.sendStatus(401); return; }
} }
var meshidhex = new Buffer(req.query.id.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase(); var meshidhex = new Buffer(req.query.id.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
var serveridhex = new Buffer(obj.agentCertificateHashBase64.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase(); var serveridhex = new Buffer(obj.agentCertificateHashBase64.replace(/\@/g, '+').replace(/\$/g, '/'), 'base64').toString('hex').toUpperCase();
// Build the agent connection URL. If we are using a sub-domain or one with a DNS, we need to craft the URL correctly. // Build the agent connection URL. If we are using a sub-domain or one with a DNS, we need to craft the URL correctly.
var xdomain = (domain.dns == null) ? domain.id : ''; var xdomain = (domain.dns == null) ? domain.id : '';
if (xdomain != '') xdomain += "/"; if (xdomain != '') xdomain += "/";
var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n"; var meshsettings = "MeshName=" + mesh.name + "\r\nMeshType=" + mesh.mtype + "\r\nMeshID=0x" + meshidhex + "\r\nServerID=" + serveridhex + "\r\n";
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; } if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; }
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