mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
Mesh agents can now connect and skip server cert check to boost speed
This commit is contained in:
parent
d3db0e4ef6
commit
82801f4069
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
363
meshagent.js
363
meshagent.js
@ -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);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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",
|
||||||
|
86
webserver.js
86
webserver.js
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user