diff --git a/amtmanager.js b/amtmanager.js index fb73bb27..ec69ecd4 100644 --- a/amtmanager.js +++ b/amtmanager.js @@ -183,7 +183,7 @@ module.exports.CreateAmtManager = function (parent) { parent.debug('amt', "Start Management", nodeid, connType); addAmtDevice(dev); - // Start the device manager the task limiter so not to flood the server. Low priority task + // Start the device manager in the task limiter so not to flood the server. Low priority task obj.parent.taskLimiter.launch(function (dev, taskid, taskLimiterQueue) { if (isAmtDeviceValid(dev)) { // Start managing this device @@ -255,34 +255,41 @@ module.exports.CreateAmtManager = function (parent) { // Handle server events // Make sure to only manage devices with connections to this server. In a multi-server setup, we don't want multiple managers talking to the same device. obj.HandleEvent = function (source, event, ids, id) { - if (event.noact == 1) return; // Take no action on these events. We are likely in peering mode and need to only act when the database signals the change in state. switch (event.action) { case 'removenode': { // React to node being removed + if (event.noact == 1) return; // Take no action on these events. We are likely in peering mode and need to only act when the database signals the change in state. removeDevice(event.nodeid); break; } case 'wakedevices': { // React to node wakeup command, perform Intel AMT wake if possible + if (event.noact == 1) return; // Take no action on these events. We are likely in peering mode and need to only act when the database signals the change in state. if (Array.isArray(event.nodeids)) { for (var i in event.nodeids) { performPowerAction(event.nodeids[i], 2); } } break; } case 'changenode': { // React to changes in a device - var devices = obj.amtDevices[event.nodeid]; - if (devices == null) break; // We are not managing this device - for (var i in devices) { - var dev = devices[i]; - if (dev.name != event.node.name) { - //console.log('device name change'); + var devices = obj.amtDevices[event.nodeid], rescan = false; + if (devices != null) { + for (var i in devices) { + var dev = devices[i]; dev.name = event.node.name; + if (event.node.intelamt != null) { dev.intelamt = event.node.intelamt; } + if ((dev.connType == 3) && (dev.host != event.node.host)) { + dev.host = event.node.host; // The host has changed, if we are connected to this device locally, we need to reset. + removeAmtDevice(dev); // We are going to wait for the AMT scanned to find this device again. + rescan = true; + } } - if (event.node.intelamt != null) { - dev.intelamt = event.node.intelamt; - } - if ((dev.connType == 3) && (dev.host != event.node.host)) { - //console.log('device host change', dev.host, event.node.host); - dev.host = event.node.host; // The host has changed, if we are connected to this device locally, we need to reset. - removeAmtDevice(dev); // We are going to wait for the AMT scanned to find this device again. - } + } else { + // If this event provides a hint that something changed with AMT and we are not managing this device, let's rescan the local network now. + if (event.amtchange == 1) { rescan = true; } } + + // If there is a significant change to the device AMT settings and this server manages local devices, perform a re-scan of the device now. + if (rescan && (parent.amtScanner != null)) { parent.amtScanner.performSpecificScan(event.node); } + break; + } + case 'meshchange': { + // TODO break; } } @@ -581,7 +588,7 @@ module.exports.CreateAmtManager = function (parent) { // Set an error that we can't login to this device if (dev.aquired == null) { dev.aquired = {}; } - dev.aquired.warn = 1; // Intel AMT Warning Flags: 1 = Unknown credentials, 2 = Realm Mismatch, 4 = TLS Cert Mismatch + dev.aquired.warn = 1; // Intel AMT Warning Flags: 1 = Unknown credentials, 2 = Realm Mismatch, 4 = TLS Cert Mismatch, 8 = Trying credentials UpdateDevice(dev); } //console.log(dev.nodeid, dev.name, dev.host, status, 'Bad response'); @@ -620,7 +627,7 @@ module.exports.CreateAmtManager = function (parent) { if ((typeof dev.aquired.tls == 'number') && (dev.aquired.tls != device.intelamt.tls)) { change = 1; log = 1; device.intelamt.tls = dev.aquired.tls; changes.push('AMT TLS'); } if ((typeof dev.aquired.state == 'number') && (dev.aquired.state != device.intelamt.state)) { change = 1; log = 1; device.intelamt.state = dev.aquired.state; changes.push('AMT state'); } - // Intel AMT Warning Flags: 1 = Unknown credentials, 2 = Realm Mismatch, 4 = TLS Cert Mismatch + // Intel AMT Warning Flags: 1 = Unknown credentials, 2 = Realm Mismatch, 4 = TLS Cert Mismatch, 8 = Trying credentials if ((typeof dev.aquired.warn == 'number')) { if ((dev.aquired.warn == 0) && (device.intelamt.warn != null)) { delete device.intelamt.warn; change = 1; } else if (dev.aquired.warn != device.intelamt.warn) { device.intelamt.warn = dev.aquired.warn; change = 1; } } // Update Intel AMT flags if needed @@ -737,8 +744,8 @@ module.exports.CreateAmtManager = function (parent) { if (devices == null) return; for (var i in devices) { var dev = devices[i]; - if (dev.amtstack != null) { - // TODO: Check if the device passed initial connection + // If not LMS, has a AMT stack present and is in connected state, perform power operation. + if ((dev.connType != 2) && (dev.state == 1) && (dev.amtstack != null)) { try { dev.amtstack.RequestPowerStateChange(action, performPowerActionResponse); } catch (ex) { } } } diff --git a/amtscanner.js b/amtscanner.js index cc4541d9..9807061e 100644 --- a/amtscanner.js +++ b/amtscanner.js @@ -167,7 +167,7 @@ module.exports.CreateAmtScanner = function (parent) { const ciraConnections = obj.parent.mpsserver ? obj.parent.mpsserver.GetConnectionToNode(doc._id, null, true) : null; // See if any OOB connections are present if ((host != '127.0.0.1') && (host != '::1') && (host.toLowerCase() != 'localhost') && (ciraConnections == null)) { var scaninfo = obj.scanTable[doc._id]; - if (scaninfo == undefined) { + if (scaninfo == null) { var tag = obj.nextTag++; obj.scanTableTags[tag] = obj.scanTable[doc._id] = scaninfo = { nodeinfo: doc, present: true, tag: tag, state: 0 }; //console.log('Scan ' + host + ', state=' + scaninfo.state + ', delta=' + delta); @@ -212,6 +212,17 @@ module.exports.CreateAmtScanner = function (parent) { return true; }; + // Look for all Intel AMT computers that may be locally reachable and poll their presence + obj.performSpecificScan = function (node) { + var host = node.host.toLowerCase(); + const ciraConnections = obj.parent.mpsserver ? obj.parent.mpsserver.GetConnectionToNode(node._id, null, true) : null; // See if any OOB connections are present + if ((host != '127.0.0.1') && (host != '::1') && (host.toLowerCase() != 'localhost') && (ciraConnections == null)) { + obj.checkTcpPresence(host, (node.intelamt.tls == 1) ? 16993 : 16992, { nodeinfo: node }, function (tag, result, version) { + if ((result == true) && (obj.parent.amtManager != null)) { obj.parent.amtManager.startAmtManagement(tag.nodeinfo._id, 3, tag.nodeinfo.host); } + }); + } + }; + // Check the presense of a specific Intel AMT computer using RMCP obj.checkAmtPresence = function (host, tag) { obj.ResolveName(host, function (hostname, ip) { obj.checkAmtPresenceEx(ip, tag); }); }; diff --git a/meshagent.js b/meshagent.js index 5a5136ac..1040ceea 100644 --- a/meshagent.js +++ b/meshagent.js @@ -439,6 +439,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { parent.parent.debug('agent', 'Agent reported web cert hash:' + (Buffer.from(msg.substring(2, 50), 'binary').toString('hex')) + '.'); console.log('Agent bad web cert hash (Agent:' + (Buffer.from(msg.substring(2, 50), 'binary').toString('hex').substring(0, 10)) + ' != Server:' + (Buffer.from(getWebCertHash(domain), 'binary').toString('hex').substring(0, 10)) + ' or ' + (Buffer.from(getWebCertFullHash(domain), 'binary').toString('hex').substring(0, 10)) + '), holding connection (' + obj.remoteaddrport + ').'); console.log('Agent reported web cert hash:' + (Buffer.from(msg.substring(2, 50), 'binary').toString('hex')) + '.'); + delete obj.agentSeenCerthash; return; } else { // The hash matched one of the acceptable values, send the agent web hash back to the agent @@ -1078,6 +1079,9 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { if (isIgnoreHashCheck() == false) { var verified = false; + // This agent did not report a valid TLS certificate hash, fail now. + if (obj.agentSeenCerthash == null) return false; + // Raw RSA signatures have an exact length of 256 or 384. PKCS7 is larger. if ((msg.length != 384) && (msg.length != 256)) { // Verify a PKCS7 signature. diff --git a/meshuser.js b/meshuser.js index 428ae120..5b640d33 100644 --- a/meshuser.js +++ b/meshuser.js @@ -4047,12 +4047,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use } if (command.desc != null && (command.desc != node.desc)) { change = 1; node.desc = command.desc; changes.push('description'); } if (command.intelamt != null) { - if ((parent.parent.amtManager == null) || (node.intelamt.user == null) || (node.intelamt.user == '') || ((node.intelamt.warn != null) && ((node.intelamt.warn) & 3 != 0))) { // Only allow changes to Intel AMT credentials if AMT manager is not running, or manager warned of unknown/trying credentials. + if ((parent.parent.amtManager == null) || (node.intelamt.user == null) || (node.intelamt.user == '') || ((node.intelamt.warn != null) && (((node.intelamt.warn) & 9) != 0))) { // Only allow changes to Intel AMT credentials if AMT manager is not running, or manager warned of unknown/trying credentials. if ((command.intelamt.user != null) && (command.intelamt.pass != null) && ((command.intelamt.user != node.intelamt.user) || (command.intelamt.pass != node.intelamt.pass))) { change = 1; node.intelamt.user = command.intelamt.user; node.intelamt.pass = command.intelamt.pass; - node.intelamt.warn = 2; // Change warning to "Trying". Bit flags: 0 = Valid credentials, 1 = Invalid credentials, 2 = Trying new credentials. + node.intelamt.warn |= 8; // Change warning to "Trying". Bit flags: 1 = Unknown credentials, 2 = Realm Mismatch, 4 = TLS Cert Mismatch, 8 = Trying credentials changes.push('Intel AMT credentials'); amtchange = 1; } diff --git a/views/default-mobile.handlebars b/views/default-mobile.handlebars index 49de7955..2089ab76 100644 --- a/views/default-mobile.handlebars +++ b/views/default-mobile.handlebars @@ -3128,7 +3128,7 @@ } else if (((features2 & 1) != 0) && (node.intelamt.warn != null)) { // If AMT manager is running and warned of invalid credentials, allow setting them. var warn = null; if ((node.intelamt.warn & 1) != 0) { warn = "Invalid Credentials"; } - if ((node.intelamt.warn & 2) != 0) { warn = "Trying Credentials"; } + if ((node.intelamt.warn & 8) != 0) { warn = "Trying Credentials"; } if (warn != null) { if ((meshrights & 4) != 0) { str += ', ' + warn + ''; diff --git a/views/default.handlebars b/views/default.handlebars index e6d2d279..1309a16b 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -2772,7 +2772,7 @@ meshserver.send({ action: 'nodes' }); // Request a refresh of all nodes (TODO: We could optimize this to only request nodes for the new mesh). } } else { - // This is an existing mesh + // This is an existing device group if (message.event.name != null) { meshes[message.event.meshid].name = message.event.name; for (var i in nodes) { if (nodes[i].meshid == message.event.meshid) { nodes[i].meshnamel = message.event.name.toLowerCase(); } } @@ -5927,7 +5927,7 @@ } else if (((features2 & 1) != 0) && (node.intelamt.warn != null)) { // If AMT manager is running and warned of invalid credentials, allow setting them. var warn = null; if ((node.intelamt.warn & 1) != 0) { warn = "Invalid Credentials"; } - if ((node.intelamt.warn & 2) != 0) { warn = "Trying Credentials"; } + if ((node.intelamt.warn & 8) != 0) { warn = "Trying Credentials"; } if (warn != null) { if ((meshrights & 4) != 0) { str += ', ' + warn + '';