diff --git a/agents/MeshCmd-signed.exe b/agents/MeshCmd-signed.exe index 87b59507..4a12333f 100644 Binary files a/agents/MeshCmd-signed.exe and b/agents/MeshCmd-signed.exe differ diff --git a/agents/MeshCmd64-signed.exe b/agents/MeshCmd64-signed.exe index a5a725f4..671f5194 100644 Binary files a/agents/MeshCmd64-signed.exe and b/agents/MeshCmd64-signed.exe differ diff --git a/agents/MeshService-signed.exe b/agents/MeshService-signed.exe index 4753574b..bbfca414 100644 Binary files a/agents/MeshService-signed.exe and b/agents/MeshService-signed.exe differ diff --git a/agents/MeshService.exe b/agents/MeshService.exe index 7b782f59..729f17ba 100644 Binary files a/agents/MeshService.exe and b/agents/MeshService.exe differ diff --git a/agents/MeshService64-signed.exe b/agents/MeshService64-signed.exe index 54925ffc..c9a4a96a 100644 Binary files a/agents/MeshService64-signed.exe and b/agents/MeshService64-signed.exe differ diff --git a/agents/MeshService64.exe b/agents/MeshService64.exe index e2a86e3a..ed0ef15d 100644 Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ diff --git a/meshagent.js b/meshagent.js index 533929fd..ea04a556 100644 --- a/meshagent.js +++ b/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 obj.agentnonce = msg.substring(50); - if (obj.useSwarmCert == true) { - // Perform the hash signature using older swarm server certificate - obj.parent.parent.certificateOperations.acceleratorPerformSignature(1, msg.substring(2) + obj.nonce, obj, function (obj2, signature) { - // Send back our certificate + signature - obj2.send(obj2.common.ShortToStr(2) + obj2.common.ShortToStr(obj2.parent.swarmCertificateAsn1.length) + obj2.parent.swarmCertificateAsn1 + 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 if we got the agent auth confirmation + if ((obj.receivedCommands & 8) == 0) { + // If we did not get an indication that the agent already validated this server, send the server signature. + if (obj.useSwarmCert == true) { + // Perform the hash signature using older swarm server certificate + obj.parent.parent.certificateOperations.acceleratorPerformSignature(1, msg.substring(2) + obj.nonce, obj, function (obj2, signature) { + // Send back our certificate + signature + obj2.send(obj2.common.ShortToStr(2) + obj2.common.ShortToStr(obj2.parent.swarmCertificateAsn1.length) + obj2.parent.swarmCertificateAsn1 + 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 @@ -242,6 +247,10 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { obj.agentInfo.computerName = msg.substring(72, 72 + computerNameLen); obj.dbMeshKey = 'mesh/' + obj.domain.id + '/' + obj.meshid; 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) { // 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; } @@ -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 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; // Check that the mesh exists - obj.db.Get(obj.dbMeshKey, function (err, meshes) { - 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. - 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. + var mesh = obj.parent.meshes[obj.dbMeshKey]; + 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. + 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 - obj.db.Get(obj.dbNodeKey, function (err, nodes) { - var device; + // Check that the node exists + obj.db.Get(obj.dbNodeKey, function (err, nodes) { + var device; - // Mark when we connected to this agent - obj.connectTime = Date.now(); - if (nodes.length == 0) { - // 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 }; - obj.db.Set(device); + // Mark when we connected to this agent + obj.connectTime = Date.now(); + if (nodes.length == 0) { + // 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 }; + obj.db.Set(device); - // Event the new node - if (obj.agentInfo.capabilities & 0x20) { - // 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 }) - } 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 }) - } + // Event the new node + if (obj.agentInfo.capabilities & 0x20) { + // 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 }) } else { - // Device already exists, look if changes has occured - device = nodes[0]; - if (device.agent == null) { - device.agent = { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }; change = 1; - } else { - var changes = [], change = 0, log = 0; - if (device.rname != obj.agentInfo.computerName) { device.rname = obj.agentInfo.computerName; change = 1; changes.push('computer name'); } - if (device.agent.ver != obj.agentInfo.agentVersion) { device.agent.ver = obj.agentInfo.agentVersion; change = 1; changes.push('agent version'); } - 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); + 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 { + // Device already exists, look if changes has occured + device = nodes[0]; + if (device.agent == null) { + device.agent = { ver: obj.agentInfo.agentVersion, id: obj.agentInfo.agentId, caps: obj.agentInfo.capabilities }; change = 1; + } else { + var changes = [], change = 0, log = 0; + if (device.rname != obj.agentInfo.computerName) { device.rname = obj.agentInfo.computerName; change = 1; changes.push('computer name'); } + if (device.agent.ver != obj.agentInfo.agentVersion) { device.agent.ver = obj.agentInfo.agentVersion; change = 1; changes.push('agent version'); } + 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 (obj.agentInfo.capabilities & 0x20) { log = 0; } + // If this is a temporary device, don't log changes + if (obj.agentInfo.capabilities & 0x20) { log = 0; } - // Event the node change - 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(', '); } - 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); - } + // Event the node change + 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(', '); } + 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); } } + } - // Check if this agent is already connected - var dupAgent = obj.parent.wsagents[obj.dbNodeKey]; - obj.parent.wsagents[obj.dbNodeKey] = obj; - if (dupAgent) { - // Close the duplicate agent - if (obj.nodeid != null) { obj.parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); } - dupAgent.close(3); + // Check if this agent is already connected + var dupAgent = obj.parent.wsagents[obj.dbNodeKey]; + obj.parent.wsagents[obj.dbNodeKey] = obj; + if (dupAgent) { + // Close the duplicate agent + if (obj.nodeid != null) { obj.parent.parent.debug(1, 'Duplicate agent ' + obj.nodeid + ' (' + obj.remoteaddr + ')'); } + 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 { - // 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); - } + // Check if we need to ask for the IP location + var doIpLocation = 0; + if (device.iploc == null) { + doIpLocation = 1; } else { - // Check if we need to ask for the IP location - var doIpLocation = 0; - if (device.iploc == null) { - doIpLocation = 1; + var loc = device.iploc.split(','); + if (loc.length < 3) { + doIpLocation = 2; } else { - var loc = device.iploc.split(','); - if (loc.length < 3) { - doIpLocation = 2; - } 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' })); - } - }); + 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' })); + } + }); + } + } }); }); } @@ -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; } // Check that the mesh exists - obj.db.Get(obj.dbMeshKey, function (err, meshes) { - if (meshes.length != 1) 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; + var mesh = obj.parent.meshes[obj.dbMeshKey]; + if (mesh == null) return; - // Check if anything changes - if (command.name && (command.name != device.name)) { change = 1; device.name = command.name; changes.push('name'); } - 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 - if (command.intelamt) { - if (!device.intelamt) { device.intelamt = {}; } - 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. - } + // 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; - // 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); - } + // Check if anything changes + if (command.name && (command.name != device.name)) { change = 1; device.name = command.name; changes.push('name'); } + 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 + if (command.intelamt) { + if (!device.intelamt) { device.intelamt = {}; } + 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 + 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 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 - obj.db.Get(obj.dbMeshKey, function (err, meshes) { - if (meshes.length != 1) 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; + var mesh = obj.parent.meshes[obj.dbMeshKey]; + if (mesh == null) return; - // Check if anything changes - if ((command.publicip) && (device.publicip != command.publicip)) { device.publicip = command.publicip; change = 1; changes.push('public ip'); } - if ((command.iploc) && (device.iploc != command.iploc)) { device.iploc = command.iploc; change = 1; changes.push('ip location'); } + // 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; - // If there are changes, save and event - if (change == 1) { - obj.db.Set(device); + // Check if anything changes + if ((command.publicip) && (device.publicip != command.publicip)) { device.publicip = command.publicip; change = 1; changes.push('public ip'); } + if ((command.iploc) && (device.iploc != command.iploc)) { device.iploc = command.iploc; change = 1; changes.push('ip location'); } - // 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); - } + // 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); } - }); + } }); } diff --git a/package.json b/package.json index 4bf43c1b..b7f74bf3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.1.9-j", + "version": "0.1.9-k", "keywords": [ "Remote Management", "Intel AMT", diff --git a/webserver.js b/webserver.js index 2a345f9c..3df919d0 100644 --- a/webserver.js +++ b/webserver.js @@ -1468,32 +1468,30 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate res.sendFile(argentInfo.path); } else { // We are going to embed the .msh file into the Windows executable (signed or not). - // First, query the meshid to build the .msh file - obj.db.Get('mesh/' + domain.id + '/' + req.query.meshid, function (err, meshes) { - if (meshes.length != 1) { res.sendStatus(401); return; } - var mesh = meshes[0]; + // First, fetch the mesh object to build the .msh file + var mesh = obj.meshes['mesh/' + domain.id + '/' + req.query.meshid]; + if (mesh == null) { res.sendStatus(401); return; } - // If required, check if this user has rights to do this - if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true)) { - var user = obj.users[req.session.userid]; - 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 (domain.id != mesh.domain) { res.sendStatus(401); return; } - } + // If required, check if this user has rights to do this + if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true)) { + var user = obj.users[req.session.userid]; + 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 (domain.id != mesh.domain) { res.sendStatus(401); return; } + } - 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 httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified + 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 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. - var xdomain = (domain.dns == null) ? domain.id : ''; - if (xdomain != '') xdomain += "/"; - 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 (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 }); - 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 }); - }); + // 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 : ''; + if (xdomain != '') xdomain += "/"; + 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 (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 }); + 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) { // 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 ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true) && (req.session.userid == null)) { res.sendStatus(401); return; } - // Query the meshid - obj.db.Get('mesh/' + domain.id + '/' + req.query.id, function (err, meshes) { - if (meshes.length != 1) { res.sendStatus(401); return; } - var mesh = meshes[0]; + // Fetch the mesh object + var mesh = obj.meshes['mesh/' + domain.id + '/' + req.query.id]; + if (mesh == null) { res.sendStatus(401); return; } - // If needed, check if this user has rights to do this - if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true)) { - var user = obj.users[req.session.userid]; - 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 (domain.id != mesh.domain) { res.sendStatus(401); return; } - } + // If needed, check if this user has rights to do this + if ((obj.parent.config.settings != null) && (obj.parent.config.settings.lockagentdownload == true)) { + var user = obj.users[req.session.userid]; + 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 (domain.id != mesh.domain) { res.sendStatus(401); return; } + } - 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 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(); - // 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 : ''; - if (xdomain != '') xdomain += "/"; - 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 - if (obj.args.lanonly != true) { meshsettings += "MeshServer=ws" + (obj.args.notls ? '' : 's') + "://" + getWebServerName(domain) + ":" + httpsPort + "/" + xdomain + "agent.ashx\r\n"; } else { meshsettings += "MeshServer=local"; } + // 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 : ''; + if (xdomain != '') xdomain += "/"; + 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 + 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.send(meshsettings); - }); + 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); } // Add HTTP security headers to all responses