mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2025-11-09 13:39:42 -05:00
Mesh agents can now connect and skip server cert check to boost speed
This commit is contained in:
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
|
||||||
|
|||||||
Reference in New Issue
Block a user