diff --git a/agents/MeshCmd-signed.exe b/agents/MeshCmd-signed.exe index 57a0d89d..2efb5bbe 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 0745e070..ada4dd5d 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 fcdda123..b27ab9fa 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 ee628130..ce61f6a4 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 094d7b75..5a0e9060 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 8b5d94fb..8e275fb8 100644 Binary files a/agents/MeshService64.exe and b/agents/MeshService64.exe differ diff --git a/agents/meshagent_osx-x86-64 b/agents/meshagent_osx-x86-64 new file mode 100644 index 00000000..0659568c Binary files /dev/null and b/agents/meshagent_osx-x86-64 differ diff --git a/agents/meshcore.js b/agents/meshcore.js index 91786322..13863db7 100644 --- a/agents/meshcore.js +++ b/agents/meshcore.js @@ -29,9 +29,12 @@ function createMeshCore(agent) { this.Start = function Start(user) { if (this.container == null) { if (process.platform == 'win32') { - this.container = require('ScriptContainer').Create({ processIsolation: 1, sessionId: user.SessionId }); - } - else { + try { + this.container = require('ScriptContainer').Create({ processIsolation: 1, sessionId: user.SessionId }); + } catch (ex) { + this.container = require('ScriptContainer').Create({ processIsolation: 1 }); + } + } else { this.container = require('ScriptContainer').Create({ processIsolation: 1, sessionId: user.uid }); } this.container.parent = this; @@ -47,33 +50,21 @@ function createMeshCore(agent) { this._container = this.container; this._container.parent = this; this.container = null; - this._container.exit(); } } } + obj.borderManager = new borderController(); */ - - require('events').EventEmitter.call(obj, true).createEvent('loggedInUsers_Updated'); - obj.on('loggedInUsers_Updated', function () - { - var users = [] - for(var i = 0; i < obj.loggedInUsers.length; ++i) - { - users.push((obj.loggedInUsers[i].Domain ? (obj.loggedInUsers[i].Domain + '\\') : '') + obj.loggedInUsers[i].Username); - } - sendConsoleText('LogOn Status Changed. Active Users => [' + users.join(', ') + ']'); - }); - //obj.borderManager = new borderController(); // MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent. obj.meshCoreInfo = "MeshCore v6"; obj.meshCoreCapabilities = 14; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript - obj.loggedInUsers = []; + obj.loggedInUsers = null; var meshServerConnectionState = 0; var tunnels = {}; - var lastSelfInfo = null; + var lastMeInfo = null; var lastNetworkInfo = null; var lastPublicLocationInfo = null; var selfInfoUpdateTimer = null; @@ -92,10 +83,8 @@ function createMeshCore(agent) { var nextTunnelIndex = 1; // Get the operating system description string - // *** THIS CAUSES AGENT TO BE UNSTABLE!!! - //obj.osDesc = null; - //try { require('os').name().then(function (v) { obj.osDesc = v; }); } catch (ex) { } - // *** THIS CAUSES AGENT TO BE UNSTABLE!!! + var osDesc = null; + try { require('os').name().then(function (v) { osDesc = v; if (mesh.isControlChannelConnected) { mesh.SendCommand({ "action": "coreinfo", "value": obj.meshCoreInfo, "osdesc": osDesc }); } }); } catch (ex) { } /* var AMTScanner = require("AMTScanner"); @@ -128,23 +117,23 @@ function createMeshCore(agent) { var AMTScannerModule = require('amt-scanner'); amtscanner = new AMTScannerModule(); //amtscanner.on('found', function (data) { if (typeof data != 'string') { data = JSON.stringify(data, null, " "); } sendConsoleText(data); }); - } catch (e) { amtscanner = null; } + } catch (ex) { amtscanner = null; } // Try to load up the MEI module try { var amtMeiLib = require('amt-mei'); amtMei = new amtMeiLib(); - amtMei.on('error', function (e) { amtMeiLib = null; amtMei = null; amtMeiConnected = -1; sendPeriodicServerUpdate(); }); + amtMei.on('error', function (e) { amtMeiLib = null; amtMei = null; amtMeiConnected = -1; }); amtMeiConnected = 2; - //amtMei.on('connect', function () { amtMeiConnected = 2; sendPeriodicServerUpdate(); }); - } catch (e) { amtMeiLib = null; amtMei = null; amtMeiConnected = -1; } + sendPeriodicServerUpdate(1); + } catch (ex) { amtMeiLib = null; amtMei = null; amtMeiConnected = -1; } // Try to load up the WIFI scanner try { var wifiScannerLib = require('wifi-scanner'); wifiScanner = new wifiScannerLib(); wifiScanner.on('accessPoint', function (data) { sendConsoleText(JSON.stringify(data)); }); - } catch (e) { wifiScannerLib = null; wifiScanner = null; } + } catch (ex) { wifiScannerLib = null; wifiScanner = null; } // If we are running in Duktape, agent will be null if (agent == null) { @@ -923,7 +912,7 @@ function createMeshCore(agent) { var response = null; switch (cmd) { case 'help': { // Displays available commands - response = 'Available commands: help, info, osinfo, args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, ps, kill, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios, toast, lock, users, sendinfo, sendcaps.'; + response = 'Available commands: help, info, osinfo, args, print, type, dbget, dbset, dbcompact, eval, parseuri, httpget,\r\nwslist, wsconnect, wssend, wsclose, notify, ls, ps, kill, amt, netinfo, location, power, wakeonlan, scanwifi,\r\nscanamt, setdebug, smbios, rawsmbios, toast, lock, users, sendcaps.'; break; } /* @@ -947,12 +936,7 @@ function createMeshCore(agent) { */ case 'users': { - var retList = []; - for(var i = 0; i < obj.loggedInUsers.length; ++i) - { - retList.push((obj.loggedInUsers[i].Domain ? (obj.loggedInUsers[i].Domain + '\\') : '') + obj.loggedInUsers[i].Username); - } - response = 'Active Users => [' + retList.join(', ') + ']'; + if (obj.loggedInUsers == null) { response = 'Active users are unknown.'; } else { response = 'Active Users: ' + obj.loggedInUsers.join(', ') + '.'; } } break; case 'toast': { @@ -1038,10 +1022,10 @@ function createMeshCore(agent) { case 'info': { // Return information about the agent and agent core module response = 'Current Core: ' + obj.meshCoreInfo + '.\r\nAgent Time: ' + Date() + '.\r\nUser Rights: 0x' + rights.toString(16) + '.\r\nPlatform: ' + process.platform + '.\r\nCapabilities: ' + obj.meshCoreCapabilities + '.\r\nServer URL: ' + mesh.ServerUrl + '.'; if (amtLmsState >= 0) { response += '\r\nBuilt-in LMS: ' + ['Disabled', 'Connecting..', 'Connected'][amtLmsState] + '.'; } - //if (obj.osDesc) { response += '\r\nOS: ' + obj.osDesc + '.'; } + if (osDesc) { response += '\r\nOS: ' + osDesc + '.'; } response += '\r\nModules: ' + addedModules.join(', ') + '.'; response += '\r\nServer Connection: ' + mesh.isControlChannelConnected + ', State: ' + meshServerConnectionState + '.'; - response += '\r\nLastInfo: ' + lastSelfInfo + '.'; + response += '\r\lastMeInfo: ' + lastMeInfo + '.'; var oldNodeId = db.Get('OldNodeId'); if (oldNodeId != null) { response += '\r\nOldNodeID: ' + oldNodeId + '.'; } if (process.platform != 'win32') { response += '\r\nX11 support: ' + require('monitor-info').kvm_x11_support + '.'; } @@ -1049,7 +1033,7 @@ function createMeshCore(agent) { } case 'osinfo': { // Return the operating system information var i = 1; - if (args['_'].length > 0) { i = parseInt(args['_'][0]); response = 'Calling ' + i + ' times.'; } + if (args['_'].length > 0) { i = parseInt(args['_'][0]); if (i > 8) { i = 8; } response = 'Calling ' + i + ' times.'; } for (var j = 0; j < i; j++) { var pr = require('os').name(); pr.sessionid = sessionid; @@ -1057,30 +1041,24 @@ function createMeshCore(agent) { } break; } - case 'selfinfo': { // Return self information block - buildSelfInfo(function (info) { sendConsoleText(objToString(info, 0, ' ', true), sessionid); }); - break; - } - case 'sendinfo': { // Send our information to the server - buildSelfInfo(function (selfInfo) { - lastSelfInfo = JSON.stringify(selfInfo); - sendConsoleText('Sent: ' + lastSelfInfo); - mesh.SendCommand(lastSelfInfo); - }); - break; - } case 'sendcaps': { // Send capability flags to the server if (args['_'].length == 0) { response = 'Proper usage: sendcaps (number)'; // Display correct command usage } else { - var flags = 0; - response = JSON.stringify(args); - flags = { "action": "coreinfo", "value": obj.meshCoreInfo, "caps": parseInt(args['_'][0]) }; + var flags = { "action": "coreinfo", "value": obj.meshCoreInfo, "caps": parseInt(args['_'][0]) }; mesh.SendCommand(flags); response = JSON.stringify(flags); } break; } + case 'sendosdesc': { // Send OS description + var os = osDesc; + if (args['_'].length > 0) { os = args['_'][0]; } + var flags = { "action": "coreinfo", "value": obj.meshCoreInfo, "osdesc": os }; + mesh.SendCommand(flags); + response = JSON.stringify(flags); + break; + } case 'args': { // Displays parsed command arguments response = 'args ' + objToString(args, 0, ' ', true); break; @@ -1380,31 +1358,22 @@ function createMeshCore(agent) { // Server connected, send mesh core information var oldNodeId = db.Get('OldNodeId'); if (oldNodeId != null) { mesh.SendCommand({ action: 'mc1migration', oldnodeid: oldNodeId }); } - sendPeriodicServerUpdate(true); - //if (selfInfoUpdateTimer == null) { selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 60000); } // Should be a long time, like 20 minutes. For now, 1 minute. + + // Update the server wtih basic info + var r = { "action": "coreinfo", "value": obj.meshCoreInfo, "caps": obj.meshCoreCapabilities }; + if (osDesc != null) { r.osdesc = osDesc; } + mesh.SendCommand(r); + + // Update list of logged in users + if (obj.loggedInUsers != null) { mesh.SendCommand({ "action": "coreinfo", "v": { "users": obj.loggedInUsers } }); } + + // Update the server on more advanced stuff, like Intel ME and Network Settings + meInfoStr = null; + sendPeriodicServerUpdate(); + //if (selfInfoUpdateTimer == null) { selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 1200000); } // 20 minutes } } - - // Build a bunch a self information data that will be sent to the server - // We need to do this periodically and if anything changes, send the update to the server. - function buildSelfInfo(func) { - getAmtInfo(function (meinfo) { - var r = { "action": "coreinfo", "value": obj.meshCoreInfo, "caps": obj.meshCoreCapabilities }; - try { - if (meinfo != null) { - var intelamt = {}, p = false; - if (meinfo.Versions && meinfo.Versions.AMT) { intelamt.ver = meinfo.Versions.AMT; p = true; } - if (meinfo.ProvisioningState) { intelamt.state = meinfo.ProvisioningState; p = true; } - if (meinfo.Flags) { intelamt.flags = meinfo.Flags; p = true; } - if (meinfo.OsHostname) { intelamt.host = meinfo.OsHostname; p = true; } - if (meinfo.UUID) { intelamt.uuid = meinfo.UUID; p = true; } - if (p == true) { r.intelamt = intelamt } - } - } catch (ex) { } - func(r); - }); - } - + // Update the server with the latest network interface information var sendNetworkUpdateNagleTimer = null; function sendNetworkUpdateNagle() { if (sendNetworkUpdateNagleTimer != null) { clearTimeout(sendNetworkUpdateNagleTimer); sendNetworkUpdateNagleTimer = null; } sendNetworkUpdateNagleTimer = setTimeout(sendNetworkUpdate, 5000); } @@ -1419,18 +1388,33 @@ function createMeshCore(agent) { } // Called periodically to check if we need to send updates to the server - function sendPeriodicServerUpdate(force) { - if ((amtMeiConnected != 1) || (force == true)) { // If we are pending MEI connection, hold off on updating the server on self-info - if (force == true) { lastSelfInfo = null; } - // Update the self information data - buildSelfInfo(function (selfInfo) { - selfInfoStr = JSON.stringify(selfInfo); - if (selfInfoStr != lastSelfInfo) { mesh.SendCommand(selfInfo); lastSelfInfo = selfInfoStr; } + function sendPeriodicServerUpdate(flags) { + if (meshServerConnectionState == 0) return; // Not connected to server, do nothing. + if (!flags) { flags = 0xFFFFFFFF; } + + if (flags & 1) { + // If we have a connected MEI, get Intel ME information + getAmtInfo(function (meinfo) { + try { + if (meinfo == null) return; + var intelamt = {}, p = false; + if (meinfo.Versions && meinfo.Versions.AMT) { intelamt.ver = meinfo.Versions.AMT; p = true; } + if (meinfo.ProvisioningState) { intelamt.state = meinfo.ProvisioningState; p = true; } + if (meinfo.Flags) { intelamt.flags = meinfo.Flags; p = true; } + if (meinfo.OsHostname) { intelamt.host = meinfo.OsHostname; p = true; } + if (meinfo.UUID) { intelamt.uuid = meinfo.UUID; p = true; } + if (p == true) { + var meInfoStr = JSON.stringify({ "action": "coreinfo", "value": obj.meshCoreInfo, "intelamt": intelamt }); + if (meInfoStr != lastMeInfo) { mesh.SendCommand(meInfoStr); lastMeInfo = meInfoStr; } + } + } catch (ex) { } }); } - - // Update network information - sendNetworkUpdateNagle(force); + + if (flags & 2) { + // Update network information + sendNetworkUpdateNagle(false); + } } // Get Intel AMT information using MEI @@ -1492,25 +1476,23 @@ function createMeshCore(agent) { }); } catch (e) { amtLmsState = -1; amtLms = null; } - // Check if the control channel is connected - if (mesh.isControlChannelConnected) { handleServerConnection(1); } - + // Setup logged in user monitoring /* - require('user-sessions').on('changed', function onUserSessionChanged() - { - require('user-sessions').enumerateUsers().then(function (users) - { - obj.loggedInUsers = users.Active; - obj.emit('loggedInUsers_Updated'); + try { + var userSession = require('user-sessions'); + userSession.on('changed', function onUserSessionChanged() { + userSession.enumerateUsers().then(function (users) { + var u = [], a = users.Active; + for (var i in a) { if (a[i].Domain) { u.push(a[i].Domain + '\\' + a[i].Username); } else { u.push(a[i].Username); } } + obj.loggedInUsers = u; + if (mesh.isControlChannelConnected) { mesh.SendCommand({ "action": "coreinfo", "users": u }); } + }); }); - }); - - require('user-sessions').emit('changed'); - require('user-sessions').on('locked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has LOCKED the desktop'); }); - require('user-sessions').on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); }); + userSession.emit('changed'); + //userSession.on('locked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has LOCKED the desktop'); }); + //userSession.on('unlocked', function (user) { sendConsoleText('[' + (user.Domain ? user.Domain + '\\' : '') + user.Username + '] has UNLOCKED the desktop'); }); + } catch (ex) { } */ - //console.log('Stopping.'); - //process.exit(); } obj.stop = function () { @@ -1535,7 +1517,8 @@ function createMeshCore(agent) { // KVM Data Channel // - obj.setupMeiOsAdmin = function(func, state) { + obj.setupMeiOsAdmin = function (func, state) { + if ((amtMei == null) || (amtMeiConnected != 2)) { return; } // If there is no MEI, don't bother with this. amtMei.getLocalSystemAccount(function (x) { var transport = require('amt-wsman-duk'); var wsman = require('amt-wsman'); diff --git a/agents/modules_meshcmd/amt-mei.js b/agents/modules_meshcmd/amt-mei.js index a6f0b17b..eb86b3c2 100644 --- a/agents/modules_meshcmd/amt-mei.js +++ b/agents/modules_meshcmd/amt-mei.js @@ -30,7 +30,28 @@ function amt_heci() { this._amt.UnicodeStringLen = 20; this._amt.Parent = this; - this._amt.on('error', function _amtOnError(e) { this.Parent.emit('error', e); }); + this._amt.on('error', function _amtOnError(e) + { + if(this.Parent._rq.isEmpty()) + { + this.Parent.emit('error', e); // No pending requests, so propagate the error up + } + else + { + // There is a pending request, so fail the pending request + var user = this.Parent._rq.deQueue(); + var params = user.optional; + var callback = user.func; + params.unshift({ Status: -1 }); // Relay an error + callback.apply(this.Parent, params); + + if(!this.Parent._rq.isEmpty()) + { + // There are still more pending requests, so try to re-helpconnect MEI + this.connect(heci.GUIDS.AMT, { noPipeline: 1 }); + } + } + }); this._amt.on('connect', function _amtOnConnect() { this.on('data', function _amtOnData(chunk) @@ -70,7 +91,8 @@ function amt_heci() { return (ret); }; - this.sendCommand = function sendCommand() { + this.sendCommand = function sendCommand() + { if (arguments.length < 3 || typeof (arguments[0]) != 'number' || typeof (arguments[1]) != 'object' || typeof (arguments[2]) != 'function') { throw ('invalid parameters'); } var args = []; for (var i = 3; i < arguments.length; ++i) { args.push(arguments[i]); } @@ -278,8 +300,16 @@ function amt_heci() { this.getLocalSystemAccount = function getLocalSystemAccount(callback) { var optional = []; for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } - this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) { - if (header.Data.length == 68) { opt.unshift({ user: trim(header.Data.slice(0, 33).toString()), pass: trim(header.Data.slice(33, 67).toString()), raw: header.Data }); } else { opt.unshift(null); } + this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) + { + if (header.Status == 0 && header.Data.length == 68) + { + opt.unshift({ user: trim(header.Data.slice(0, 33).toString()), pass: trim(header.Data.slice(33, 67).toString()), raw: header.Data }); + } + else + { + opt.unshift(null); + } fn.apply(this, opt); }, callback, optional); } diff --git a/agents/modules_meshcmd/user-sessions.js b/agents/modules_meshcmd/user-sessions.js index 6ca26278..877d4b30 100644 --- a/agents/modules_meshcmd/user-sessions.js +++ b/agents/modules_meshcmd/user-sessions.js @@ -197,11 +197,18 @@ function UserSessions() { this.parent.hwnd = h; - // Now that we have a window handle, we can register it to receive Windows Messages - this.parent._wts.WTSRegisterSessionNotification(this.parent.hwnd, NOTIFY_FOR_ALL_SESSIONS); - //this.parent._user32.ACDC_H = this.parent._user32.RegisterPowerSettingNotification(this.parent.hwnd, GUID_ACDC_POWER_SOURCE, 0); - //this.parent._user32.BATT_H = this.parent._user32.RegisterPowerSettingNotification(this.parent.hwnd, GUID_BATTERY_PERCENTAGE_REMAINING, 0); - //this.parent._user32.DISP_H = this.parent._user32.RegisterPowerSettingNotification(this.parent.hwnd, GUID_CONSOLE_DISPLAY_STATE, 0); // Windows 8+ only, THIS WILL BLOCK ON WIN7 + // We need to yield, and do this in the next event loop pass, becuase we don't want to call 'RegisterPowerSettingNotification' + // from the messagepump 'thread', because we are actually on the microstack thread, such that the message pump thread, is holding + // on a semaphore for us to return. If we call now, we may deadlock on Windows 7, becuase it will try to notify immediately + this.immediate = setImmediate(function (self) + { + // Now that we have a window handle, we can register it to receive Windows Messages + self.parent._wts.WTSRegisterSessionNotification(self.parent.hwnd, NOTIFY_FOR_ALL_SESSIONS); + self.parent._user32.ACDC_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_ACDC_POWER_SOURCE, 0); + self.parent._user32.BATT_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_BATTERY_PERCENTAGE_REMAINING, 0); + self.parent._user32.DISP_H = self.parent._user32.RegisterPowerSettingNotification(self.parent.hwnd, GUID_CONSOLE_DISPLAY_STATE, 0); + console.log(self.parent._user32.ACDC_H.Val, self.parent._user32.BATT_H.Val, self.parent._user32.DISP_H.Val); + }, this); }); this._messagepump.on('message', function (msg) { diff --git a/agents/modules_meshcore/amt-mei.js b/agents/modules_meshcore/amt-mei.js index a6f0b17b..eb86b3c2 100644 --- a/agents/modules_meshcore/amt-mei.js +++ b/agents/modules_meshcore/amt-mei.js @@ -30,7 +30,28 @@ function amt_heci() { this._amt.UnicodeStringLen = 20; this._amt.Parent = this; - this._amt.on('error', function _amtOnError(e) { this.Parent.emit('error', e); }); + this._amt.on('error', function _amtOnError(e) + { + if(this.Parent._rq.isEmpty()) + { + this.Parent.emit('error', e); // No pending requests, so propagate the error up + } + else + { + // There is a pending request, so fail the pending request + var user = this.Parent._rq.deQueue(); + var params = user.optional; + var callback = user.func; + params.unshift({ Status: -1 }); // Relay an error + callback.apply(this.Parent, params); + + if(!this.Parent._rq.isEmpty()) + { + // There are still more pending requests, so try to re-helpconnect MEI + this.connect(heci.GUIDS.AMT, { noPipeline: 1 }); + } + } + }); this._amt.on('connect', function _amtOnConnect() { this.on('data', function _amtOnData(chunk) @@ -70,7 +91,8 @@ function amt_heci() { return (ret); }; - this.sendCommand = function sendCommand() { + this.sendCommand = function sendCommand() + { if (arguments.length < 3 || typeof (arguments[0]) != 'number' || typeof (arguments[1]) != 'object' || typeof (arguments[2]) != 'function') { throw ('invalid parameters'); } var args = []; for (var i = 3; i < arguments.length; ++i) { args.push(arguments[i]); } @@ -278,8 +300,16 @@ function amt_heci() { this.getLocalSystemAccount = function getLocalSystemAccount(callback) { var optional = []; for (var i = 1; i < arguments.length; ++i) { optional.push(arguments[i]); } - this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) { - if (header.Data.length == 68) { opt.unshift({ user: trim(header.Data.slice(0, 33).toString()), pass: trim(header.Data.slice(33, 67).toString()), raw: header.Data }); } else { opt.unshift(null); } + this.sendCommand(103, Buffer.alloc(40), function (header, fn, opt) + { + if (header.Status == 0 && header.Data.length == 68) + { + opt.unshift({ user: trim(header.Data.slice(0, 33).toString()), pass: trim(header.Data.slice(33, 67).toString()), raw: header.Data }); + } + else + { + opt.unshift(null); + } fn.apply(this, opt); }, callback, optional); } diff --git a/agents/modules_meshcore/linux-dbus.js b/agents/modules_meshcore/linux-dbus.js new file mode 100644 index 00000000..390bbfea --- /dev/null +++ b/agents/modules_meshcore/linux-dbus.js @@ -0,0 +1,128 @@ +/* +Copyright 2018 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +try { Object.defineProperty(Array.prototype, "peek", { value: function () { return (this.length > 0 ? this[this.length - 1] : undefined); } }); } catch (e) { } + + + +function dbus(address, uid) +{ + this._ObjectID = 'linux-dbus'; + require('events').EventEmitter.call(this, true) + .createEvent('signal'); + Object.defineProperty(this, "uid", { value: uid }); + this._child = require('child_process').execFile("/bin/sh", ["sh"], { type: require('child_process').SpawnTypes.TERM, uid: uid == null ? -1 : uid }); + this._child.stdin.write('dbus-monitor --session "type=\'signal\', interface=\'' + address + '\'" | ( while true; do read X; echo "$X"; done )\n'); + this._child.stdout.dbus = this; + this._child.stdout.on('data', function (chunk) + { + // Parse DBUS Data + if (!this.ready) { this.ready = true; return; } + + var lines = []; + var tokens = chunk.toString().split('\r\n'); + for (var i in tokens) + { + if (tokens[i] == '') + { + // End of record + this.dbus.preParseRecords(lines); + lines = []; + } + else + { + lines.push(tokens[i]); + } + } + }); + this.preParseRecords = function (lines) + { + var record = []; + for (var i in lines) + { + if(lines[i].startsWith('signal ')) + { + if(record.length>0) + { + this.parseRecords(record); + } + record = []; + } + record.push(lines[i]); + } + if (record.length > 0) + { + this.parseRecords(record); + } + } + this.parseRecords = function (lines) + { + if (lines[0].startsWith('signal ')) + { + var signal = {}; + var sigtokens = lines[0].split(' '); + sigtokens.shift(); + + for (var i in sigtokens) { + var sigitems = sigtokens[i].split('='); + if (sigitems.length == 2) { + signal[sigitems[0]] = sigitems[1]; + } + } + + lines.shift(); + signal.data = lines; + + this.parseSignal(signal); + } + } + this.parseSignal = function(signal) + { + var data = signal.data; + signal.data = []; + + for(var i=0; i ' + command.intelamt.flags + ')'); } else { changes.push('AMT flags (' + command.intelamt.flags + ')'); } + device.intelamt.flags = command.intelamt.flags; change = 1; + } + if ((command.intelamt.host != null) && (device.intelamt.host != command.intelamt.host)) { changes.push('AMT host'); device.intelamt.host = command.intelamt.host; change = 1; } + if ((command.intelamt.uuid != null) && (device.intelamt.uuid != command.intelamt.uuid)) { changes.push('AMT uuid'); device.intelamt.uuid = command.intelamt.uuid; change = 1; } } + if ((command.users != null) && (device.users != command.users)) { device.users = command.users; change = 1; } // Would be nice not to save this to the db. 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 there are changes, event the new device if (change == 1) { + // Save to the database 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 event = { etype: 'node', action: 'changenode', nodeid: obj.dbNodeKey, domain: domain.id }; + if (changes.length > 0) { event.msg = 'Changed device ' + device.name + ' from mesh ' + mesh.name + ': ' + changes.join(', '); } + if ((obj.agentInfo.capabilities & 0x20) || (changes.length == 0)) { 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; diff --git a/meshcentral.js b/meshcentral.js index e5c72010..e919973a 100644 --- a/meshcentral.js +++ b/meshcentral.js @@ -946,12 +946,12 @@ function CreateMeshCentralServer(config, args) { 8: { id: 8, localname: 'MeshAgent-Linux-XEN-x86-32', rname: 'meshagent', desc: 'XEN x86-64', update: true, amt: false, platform: 'linux' }, 9: { id: 9, localname: 'meshagent_arm', rname: 'meshagent', desc: 'Linux ARM5', update: true, amt: false, platform: 'linux' }, 10: { id: 10, localname: 'MeshAgent-Linux-ARM-PlugPC', rname: 'meshagent', desc: 'Linux ARM PlugPC', update: true, amt: false, platform: 'linux' }, - 11: { id: 11, localname: 'MeshAgent-OSX-x86-32', rname: 'meshosx', desc: 'Apple OSX x86-32', update: true, amt: false, platform: 'linux' }, + 11: { id: 11, localname: 'meshagent_osx-x86-32', rname: 'meshosx', desc: 'Apple OSX x86-32', update: true, amt: false, platform: 'linux' }, 12: { id: 12, localname: 'MeshAgent-Android-x86', rname: 'meshandroid', desc: 'Android x86-32', update: true, amt: false, platform: 'linux' }, 13: { id: 13, localname: 'meshagent_pogo', rname: 'meshagent', desc: 'Linux ARM PogoPlug', update: true, amt: false, platform: 'linux' }, 14: { id: 14, localname: 'MeshAgent-Android-APK', rname: 'meshandroid', desc: 'Android Market', update: false, amt: false, platform: 'android' }, // Get this one from Google Play 15: { id: 15, localname: 'meshagent_poky', rname: 'meshagent', desc: 'Linux Poky x86-32', update: true, amt: false, platform: 'linux' }, - 16: { id: 16, localname: 'MeshAgent-OSX-x86-64', rname: 'meshagent', desc: 'Apple OSX x86-64', update: true, amt: false, platform: 'osx' }, + 16: { id: 16, localname: 'meshagent_osx-x86-64', rname: 'meshagent', desc: 'Apple OSX x86-64', update: true, amt: false, platform: 'osx' }, 17: { id: 17, localname: 'MeshAgent-ChromeOS', rname: 'meshagent', desc: 'Google ChromeOS', update: false, amt: false, platform: 'chromeos' }, // Get this one from Chrome store 18: { id: 18, localname: 'meshagent_poky64', rname: 'meshagent', desc: 'Linux Poky x86-64', update: true, amt: false, platform: 'linux' }, 19: { id: 19, localname: 'meshagent_x86_nokvm', rname: 'meshagent', desc: 'Linux x86-32 NoKVM', update: true, amt: true, platform: 'linux' }, diff --git a/package.json b/package.json index f3c030e6..a447505e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "meshcentral", - "version": "0.2.0-w", + "version": "0.2.0-y", "keywords": [ "Remote Management", "Intel AMT", diff --git a/public/scripts/amt-desktop-0.0.2.js b/public/scripts/amt-desktop-0.0.2.js index 9bde9169..3a2aee86 100644 --- a/public/scripts/amt-desktop-0.0.2.js +++ b/public/scripts/amt-desktop-0.0.2.js @@ -39,6 +39,14 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) { obj.noMouseRotate = false; obj.rotation = 0; // ###END###{DesktopRotation} + // ###BEGIN###{DesktopInband} + obj.kvmDataSupported = false; + obj.onKvmData = null; + obj.onKvmDataPending = []; + obj.onKvmDataAck = -1; + obj.holding = false; + obj.lastKeepAlive = Date.now(); + // ###END###{DesktopInband} // ###BEGIN###{DesktopFocus} obj.mx = 0; // Last mouse x position @@ -138,6 +146,9 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) { var supportedEncodings = ''; if (obj.useZRLE) supportedEncodings += IntToStr(16); supportedEncodings += IntToStr(0); + // ###BEGIN###{DesktopInband} + supportedEncodings += IntToStr(1092); + // ###END###{DesktopInband} obj.send(String.fromCharCode(2, 0) + ShortToStr((supportedEncodings.length / 4) + 1) + supportedEncodings + IntToStr(-223)); // Supported Encodings + Desktop Size @@ -157,13 +168,21 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) { if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight); } } else if (obj.state == 4) { - var c = obj.acc.charCodeAt(0); - if (c == 2) { - cmdsize = 1; // This is the bell, do nothing. - } else if (c == 0) { - if (obj.acc.length < 4) return; - obj.state = 100 + ReadShort(obj.acc, 2); // Read the number of tiles that are going to be sent, add 100 and use that as our protocol state. - cmdsize = 4; + switch (obj.acc.charCodeAt(0)) { + case 0: // FramebufferUpdate + if (obj.acc.length < 4) return; + obj.state = 100 + ReadShort(obj.acc, 2); // Read the number of tiles that are going to be sent, add 100 and use that as our protocol state. + cmdsize = 4; + break; + case 2: // This is the bell, do nothing. + cmdsize = 1; + break; + case 3: // This is ServerCutText + if (obj.acc.length < 8) return; + var len = ReadInt(obj.acc, 4) + 8; + if (obj.acc.length < len) return; + cmdsize = handleServerCutText(obj.acc); + break; } } else if (obj.state > 100 && obj.acc.length >= 12) { @@ -319,7 +338,31 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) { } } + // ###BEGIN###{DesktopInband} + obj.hold = function (holding) { + if (obj.holding == holding) return; + obj.holding = holding; + obj.canvas.fillStyle = '#000000'; + obj.canvas.fillRect(0, 0, obj.width, obj.height); // Paint black + if (obj.holding == false) { + // Go back to normal operations + // Set canvas size and ask for full screen refresh + if ((obj.canvas.canvas.width != obj.width) || (obj.canvas.canvas.height != obj.height)) { + obj.canvas.canvas.width = obj.width; obj.canvas.canvas.height = obj.height; + if (obj.onScreenSizeChange != null) { obj.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight); } // ??? + } + obj.Send(String.fromCharCode(3, 0, 0, 0, 0, 0) + ShortToStr(obj.width) + ShortToStr(obj.height)); // FramebufferUpdateRequest + } else { + obj.UnGrabMouseInput(); + obj.UnGrabKeyInput(); + } + } + // ###END###{DesktopInband} + function _putImage(i, x, y) { + // ###BEGIN###{DesktopInband} + if (obj.holding == true) return; + // ###END###{DesktopInband} // ###BEGIN###{DesktopRotation} var xx = _arotX(x, y); y = _arotY(x, y); @@ -416,6 +459,11 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) { obj.setRotation = function (x) { while (x < 0) { x += 4; } var newrotation = x % 4; + //console.log('hard-rot: ' + newrotation); + // ###BEGIN###{DesktopInband} + if (obj.holding == true) { obj.rotation = newrotation; return; } + // ###END###{DesktopInband} + if (newrotation == obj.rotation) return true; var rw = obj.canvas.canvas.width; var rh = obj.canvas.canvas.height; @@ -451,6 +499,9 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) { function _fixColor(c) { return (c > 127) ? (c + 32) : c; } function _SendRefresh() { + // ###BEGIN###{DesktopInband} + if (obj.holding == true) return; + // ###END###{DesktopInband} // ###BEGIN###{DesktopFocus} if (obj.focusmode > 0) { // Request only pixels around the last mouse position @@ -477,6 +528,11 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) { // ###BEGIN###{Inflate} obj.inflate.inflateReset(); // ###END###{Inflate} + // ###BEGIN###{DesktopInband} + obj.onKvmDataPending = []; + obj.onKvmDataAck = -1; + obj.kvmDataSupported = false; + // ###END###{DesktopInband} for (var i in obj.sparecache) { delete obj.sparecache[i]; } } @@ -555,6 +611,43 @@ var CreateAmtRemoteDesktop = function (divid, scrolldiv) { else { obj.send(String.fromCharCode(4, d, 0, 0) + IntToStr(k)); } } + function handleServerCutText(acc) { + if (acc.length < 8) return 0; + var len = ReadInt(obj.acc, 4) + 8; + if (acc.length < len) return 0; + // ###BEGIN###{DesktopInband} + if (obj.onKvmData != null) { + var d = acc.substring(8, len); + if ((d.length >= 16) && (d.substring(0, 15) == '\0KvmDataChannel')) { + if (obj.kvmDataSupported == false) { obj.kvmDataSupported = true; console.log('KVM Data Channel Supported.'); } + if (((obj.onKvmDataAck == -1) && (d.length == 16)) || (d.charCodeAt(15) != 0)) { obj.onKvmDataAck = true; } + //if (urlvars && urlvars['kvmdatatrace']) { console.log('KVM-Recv(' + (d.length - 16) + '): ' + d.substring(16)); } + if (d.length > 16) { obj.onKvmData(d.substring(16)); } // Event the data and ack + if ((obj.onKvmDataAck == true) && (obj.onKvmDataPending.length > 0)) { obj.sendKvmData(obj.onKvmDataPending.shift()); } // Send pending data + } + } + // ###END###{DesktopInband} + return len; + } + + // ###BEGIN###{DesktopInband} + obj.sendKvmData = function (x) { + if (obj.onKvmDataAck !== true) { + obj.onKvmDataPending.push(x); + } else { + if (urlvars && urlvars['kvmdatatrace']) { console.log('KVM-Send(' + x.length + '): ' + x); } + x = '\0KvmDataChannel\0' + x; + obj.Send(String.fromCharCode(6, 0, 0, 0) + IntToStr(x.length) + x); + obj.onKvmDataAck = false; + } + } + + // Send a HWKVM keep alive if it's not been sent in the last 5 seconds. + obj.sendKeepAlive = function () { + if (obj.lastKeepAlive < Date.now() - 5000) { obj.lastKeepAlive = Date.now(); obj.Send(String.fromCharCode(6, 0, 0, 0) + IntToStr(16) + '\0KvmDataChannel\0'); } + } + // ###END###{DesktopInband} + obj.SendCtrlAltDelMsg = function () { obj.sendcad(); } obj.sendcad = function () { obj.sendkey([[0xFFE3, 1], [0xFFE9, 1], [0xFFFF, 1], [0xFFFF, 0], [0xFFE9, 0], [0xFFE3, 0]]); } // Control down, Alt down, Delete down, Delete up , Alt up , Control up diff --git a/views/default-min.handlebars b/views/default-min.handlebars index a9632845..9c967173 100644 --- a/views/default-min.handlebars +++ b/views/default-min.handlebars @@ -1 +1 @@ - MeshCentral
{{{title}}}
{{{title2}}}

{{{logoutControl}}}


\ No newline at end of file + MeshCentral
{{{title}}}
{{{title2}}}

{{{logoutControl}}}


\ No newline at end of file diff --git a/views/default-mobile-min.handlebars b/views/default-mobile-min.handlebars index 1f86e485..d377c55c 100644 --- a/views/default-mobile-min.handlebars +++ b/views/default-mobile-min.handlebars @@ -1 +1 @@ - MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file + MeshCentral - Login
{{{title}}}
{{{title2}}}
\ No newline at end of file diff --git a/views/default.handlebars b/views/default.handlebars index 8c955960..028bf7b1 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -144,8 +144,8 @@