1
0
Fork 0
mirror of https://github.com/Ylianst/MeshCentral.git synced 2025-03-09 15:40:18 +00:00

Merge branch 'master' of https://github.com/Ylianst/MeshCentral into master

This commit is contained in:
Bryan Roe 2021-03-05 17:31:00 -08:00
commit dea0d96add
113 changed files with 96567 additions and 2432 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -73,7 +73,7 @@
"meshId": "Netzkennung",
"serverId": "Server-ID",
"setup": "Konfiguration",
"update": "Aktualisieren",
"update": "Updates",
"pressok": "Drücken Sie OK, um die Verbindung zu trennen",
"elevation": "Für die Installation / Deinstallation des Agenten sind erhöhte Berechtigungen erforderlich.",
"sudo": "Bitte versuchen Sie es erneut mit sudo.",

View file

@ -113,7 +113,7 @@ function run(argv) {
//console.log('addedModules = ' + JSON.stringify(addedModules));
var actionpath = 'meshaction.txt';
if (args.actionfile != null) { actionpath = args.actionfile; }
var actions = ['HELP', 'ROUTE', 'MICROLMS', 'AMTCONFIG', 'AMTSCAN', 'AMTPOWER', 'AMTFEATURES', 'AMTNETWORK', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'AMTINFO', 'AMTINFODEBUG', 'AMTVERSIONS', 'AMTHASHES', 'AMTSAVESTATE', 'AMTUUID', 'AMTCCM', 'AMTDEACTIVATE', 'AMTACMDEACTIVATE', 'SMBIOS', 'RAWSMBIOS', 'MESHCOMMANDER', 'AMTAUDITLOG', 'AMTEVENTLOG', 'AMTPRESENCE', 'AMTWIFI', 'AMTWAKE'];
var actions = ['HELP', 'ROUTE', 'MICROLMS', 'AMTCONFIG', 'AMTSCAN', 'AMTPOWER', 'AMTFEATURES', 'AMTNETWORK', 'AMTLOADWEBAPP', 'AMTLOADSMALLWEBAPP', 'AMTLOADLARGEWEBAPP', 'AMTCLEARWEBAPP', 'AMTSTORAGESTATE', 'AMTINFO', 'AMTINFODEBUG', 'AMTVERSIONS', 'AMTHASHES', 'AMTSAVESTATE', 'AMTUUID', 'AMTCCM', 'AMTDEACTIVATE', 'AMTACMDEACTIVATE', 'SMBIOS', 'RAWSMBIOS', 'MESHCOMMANDER', 'AMTAUDITLOG', 'AMTEVENTLOG', 'AMTPRESENCE', 'AMTWIFI', 'AMTWAKE', 'AMTSTOPCONFIGURATION'];
// Load the action file
var actionfile = null;
@ -428,7 +428,19 @@ function run(argv) {
console.log('Proxy set to ' + proxy[0] + ':' + proxyport);
}
if (settings.action == 'smbios') {
if (settings.action == 'amtstopconfiguration') {
// Stop Intel AMT configuration
var amtMeiModule, amtMei;
try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { console.log(ex); exit(1); return; }
amtMei.on('error', function (e) { console.log('ERROR: ' + e); exit(1); return; });
amtMei.stopConfiguration(function (state) {
if (state == 3) { console.log("Intel AMT is not in in-provisionning mode."); }
else if (state == 1) { console.log("Intel AMT internal error."); }
else if (state == 0) { console.log("Success."); }
else { console.log("Unknown state: " + state); }
exit(1);
});
} else if (settings.action == 'smbios') {
// Display SM BIOS tables in raw form
SMBiosTables = require('smbios');
SMBiosTables.get(function (data) {
@ -1174,9 +1186,28 @@ function configureJsonControl(data) {
amtMei.on('error', function (e) { settings.apftunnel.sendMeiDeactivationState(1); });
amtMei.unprovision(1, function (status) { settings.apftunnel.sendMeiDeactivationState(status); }); // 0 = Success
break;
case 'startTlsHostConfig': // Request start of host based TLS ACM activation
var amtMeiModule, amtMei;
try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { settings.apftunnel.sendStartTlsHostConfigResponse({ state: -103 }); break; }
amtMei.on('error', function (e) { settings.apftunnel.sendStartTlsHostConfigResponse({ state: -104 }); });
amtMei.startConfigurationHBased(Buffer.from(data.hash, 'hex'), data.hostVpn, data.dnsSuffixList, function (response) {
settings.apftunnel.sendStartTlsHostConfigResponse(response);
});
break;
case 'stopConfiguration': // Request Intel AMT stop configuration.
var amtMeiModule, amtMei;
try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { settings.apftunnel.sendStartTlsHostConfigResponse({ state: -103 }); break; }
amtMei.on('error', function (e) { settings.apftunnel.sendStartTlsHostConfigResponse({ state: -104 }); });
amtMei.stopConfiguration(function (status) {
settings.apftunnel.sendStopConfigurationResponse(status);
});
break;
case 'close': // Close the CIRA-LMS connection
exit(0);
break;
default:
console.log("MeshCmd update may be needed, unknown JSON control action: " + data.action);
break;
}
}
@ -2691,7 +2722,7 @@ function getMeiState(flags, func) {
try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { func(null); return; }
amtMei.on('error', function (e) { func(null); return; });
try {
var amtMeiTmpState = { OsHostname: require('os').hostname(), Flags: 0 }; // Flags: 1=EHBC, 2=CCM, 4=ACM
var amtMeiTmpState = { 'core-ver': 1, OsHostname: require('os').hostname(), Flags: 0 }; // Flags: 1=EHBC, 2=CCM, 4=ACM
amtMei.getProtocolVersion(function (result) { if (result != null) { amtMeiTmpState.MeiVersion = result; } });
if ((flags & 1) != 0) { amtMei.getVersion(function (result) { if (result) { amtMeiTmpState.Versions = {}; for (var version in result.Versions) { amtMeiTmpState.Versions[result.Versions[version].Description] = result.Versions[version].Version; } } }); }
amtMei.getProvisioningMode(function (result) { if (result) { amtMeiTmpState.ProvisioningMode = result.mode; } });

View file

@ -1197,6 +1197,18 @@ function handleServerCommand(data) {
amtMei.unprovision(1, function (status) { if (apftunnel) apftunnel.sendMeiDeactivationState(status); }); // 0 = Success
}
if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; } // Close the CIRA-LMS connection
if (data.action == 'startTlsHostConfig') { // Request start of host based TLS ACM activation
var amtMeiModule, amtMei;
try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { if (apftunnel) apftunnel.sendMeiDeactivationState(1); return; }
amtMei.on('error', function (e) { if (apftunnel) apftunnel.sendStartTlsHostConfigResponse({ state: -104 }); });
amtMei.startConfigurationHBased(Buffer.from(data.hash, 'hex'), data.hostVpn, data.dnsSuffixList, function (response) { apftunnel.sendStartTlsHostConfigResponse(response); });
}
if (data.action == 'stopConfiguration') { // Request Intel AMT stop configuration.
var amtMeiModule, amtMei;
try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { if (apftunnel) apftunnel.sendMeiDeactivationState(1); return; }
amtMei.on('error', function (e) { if (apftunnel) apftunnel.sendStopConfigurationResponse({ state: -104 }); });
amtMei.stopConfiguration(function (status) { apftunnel.sendStopConfigurationResponse(status); });
}
}
apftunnel.onChannelClosed = function () { addAmtEvent('LMS tunnel closed.'); apftunnel = null; }
try { apftunnel.connect(); } catch (ex) { }
@ -1222,7 +1234,7 @@ function handleServerCommand(data) {
break;
}
case 'coredump':
// Set the current agent coredump situation.
// Set the current agent coredump situation.s
if (data.value === true) {
if (process.platform == 'win32') {
// TODO: This replace() below is not ideal, would be better to remove the .exe at the end instead of replace.
@ -2746,7 +2758,11 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
break;
case 'agentupdateex':
// Perform an direct agent update without requesting any information from the server, this should not typically be used.
agentUpdate_Start(null, { sessionid: sessionid });
if (args['_'].length == 1) {
if (args['_'][0].startsWith('https://')) { agentUpdate_Start(args['_'][0], { sessionid: sessionid }); } else { response = "Usage: agentupdateex https://server/path"; }
} else {
agentUpdate_Start(null, { sessionid: sessionid });
}
break;
case 'msh':
response = JSON.stringify(_MSH(), null, 2);
@ -4134,8 +4150,10 @@ function agentUpdate_Start(updateurl, updateoptions) {
var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
// If the url starts with *, switch it to use the same protoco, host and port as the control channel.
updateurl = getServerTargetUrlEx(updateurl);
if (updateurl.startsWith("wss://")) { updateurl = "https://" + updateurl.substring(6); }
if (updateurl != null) {
updateurl = getServerTargetUrlEx(updateurl);
if (updateurl.startsWith("wss://")) { updateurl = "https://" + updateurl.substring(6); }
}
if (agentUpdate_Start._selfupdate != null) {
// We were already called, so we will ignore this duplicate request
@ -4166,10 +4184,10 @@ function agentUpdate_Start(updateurl, updateoptions) {
return;
}
if (sessionid != null) { sendConsoleText('Downloading update from: ' + updateurl, sessionid); }
if ((sessionid != null) && (updateurl != null)) { sendConsoleText('Downloading update from: ' + updateurl, sessionid); }
var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl);
options.protocol = 'https:';
if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); }
if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); sendConsoleText('Downloading update from: ' + options.path, sessionid); }
options.rejectUnauthorized = false;
options.checkServerIdentity = function checkServerIdentity(certs) {
// If the tunnel certificate matches the control channel certificate, accept the connection

View file

@ -183,6 +183,8 @@ function CreateAPFClient(parent, args) {
obj.updateMeiState = function (state) { SendJsonControl(obj.forwardClient.ws, { action: 'meiState', value: state }); }
obj.sendMeiDeactivationState = function (state) { SendJsonControl(obj.forwardClient.ws, { action: 'deactivate', value: state }); }
obj.sendStartTlsHostConfigResponse = function (state) { SendJsonControl(obj.forwardClient.ws, { action: 'startTlsHostConfig', value: state }); }
obj.sendStopConfigurationResponse = function (state) { SendJsonControl(obj.forwardClient.ws, { action: 'stopConfiguration', value: state }); }
function SendJsonControl(socket, o) {
var data = JSON.stringify(o)

View file

@ -24,22 +24,18 @@ function amt_heci() {
this._ObjectID = "pthi";
this._rq = new Q();
this._setupPTHI = function _setupPTHI()
{
this._setupPTHI = function _setupPTHI() {
this._amt = heci.create();
this._amt.descriptorMetadata = "amt-pthi";
this._amt.BiosVersionLen = 65;
this._amt.UnicodeStringLen = 20;
this._amt.Parent = this;
this._amt.on('error', function _amtOnError(e)
{
if(this.Parent._rq.isEmpty())
{
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
{
else {
// There is a pending request, so fail the pending request
var user = this.Parent._rq.deQueue();
var params = user.optional;
@ -47,17 +43,14 @@ function amt_heci() {
params.unshift({ Status: -1 }); // Relay an error
callback.apply(this.Parent, params);
if(!this.Parent._rq.isEmpty())
{
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)
{
this._amt.on('connect', function _amtOnConnect() {
this.on('data', function _amtOnData(chunk) {
//console.log("Received: " + chunk.length + " bytes");
var header = this.Parent.getCommand(chunk);
//console.log("CMD = " + header.Command + " (Status: " + header.Status + ") Response = " + header.IsResponse);
@ -69,14 +62,12 @@ function amt_heci() {
params.unshift(header);
callback.apply(this.Parent, params);
if(this.Parent._rq.isEmpty())
{
if (this.Parent._rq.isEmpty()) {
// No More Requests, we can close PTHI
this.Parent._amt.disconnect();
this.Parent._amt = null;
}
else
{
else {
// Send the next request
this.write(this.Parent._rq.peekQueue().send);
}
@ -93,8 +84,7 @@ 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]); }
@ -102,10 +92,9 @@ function amt_heci() {
var header = Buffer.from('010100000000000000000000', 'hex');
header.writeUInt32LE(arguments[0] | 0x04000000, 4);
header.writeUInt32LE(arguments[1] == null ? 0 : arguments[1].length, 8);
this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args , send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]]))});
this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args, send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]])) });
if(!this._amt)
{
if (!this._amt) {
this._setupPTHI();
this._amt.connect(heci.GUIDS.AMT, { noPipeline: 1 });
}
@ -117,7 +106,7 @@ function amt_heci() {
this.sendCommand(26, null, function (header, fn, opt) {
if (header.Status == 0) {
var i, CodeVersion = header.Data, val = { BiosVersion: CodeVersion.slice(0, this._amt.BiosVersionLen).toString(), Versions: [] }, v = CodeVersion.slice(this._amt.BiosVersionLen + 4);
for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen) ; ++i) {
for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen); ++i) {
val.Versions[i] = { Description: v.slice(2, v.readUInt16LE(0) + 2).toString(), Version: v.slice(4 + this._amt.UnicodeStringLen, 4 + this._amt.UnicodeStringLen + v.readUInt16LE(2 + this._amt.UnicodeStringLen)).toString() };
v = v.slice(4 + (2 * this._amt.UnicodeStringLen));
}
@ -302,34 +291,27 @@ 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.Status == 0 && header.Data.length == 68)
{
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
{
else {
opt.unshift(null);
}
fn.apply(this, opt);
}, callback, optional);
}
this.getLanInterfaceSettings = function getLanInterfaceSettings(index, callback)
{
this.getLanInterfaceSettings = function getLanInterfaceSettings(index, callback) {
var optional = [];
for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
var ifx = Buffer.alloc(4);
ifx.writeUInt32LE(index);
this.sendCommand(0x48, ifx, function onGetLanInterfaceSettings(header, fn, opt)
{
if(header.Status == 0)
{
this.sendCommand(0x48, ifx, function onGetLanInterfaceSettings(header, fn, opt) {
if (header.Status == 0) {
var info = {};
info.enabled = header.Data.readUInt32LE(0);
info.dhcpEnabled = header.Data.readUInt32LE(8);
switch(header.Data[12])
{
switch (header.Data[12]) {
case 1:
info.dhcpMode = 'ACTIVE'
break;
@ -341,14 +323,13 @@ function amt_heci() {
break;
}
info.mac = header.Data.slice(14).toString('hex:');
var addr = header.Data.readUInt32LE(4);
info.address = ((addr >> 24) & 255) + '.' + ((addr >> 16) & 255) + '.' + ((addr >> 8) & 255) + '.' + (addr & 255);
opt.unshift(info);
fn.apply(this, opt);
}
else
{
else {
opt.unshift(null);
fn.apply(this, opt);
}
@ -398,27 +379,81 @@ function amt_heci() {
fn.apply(this, opt);
}, callback, optional);
}
this.getProtocolVersion = function getProtocolVersion(callback)
{
this.getProtocolVersion = function getProtocolVersion(callback) {
var optional = [];
for (var i = 1; i < arguments.length; ++i) { opt.push(arguments[i]); }
if (!this._tmpSession) { this._tmpSession = heci.create(); this._tmpSession.parent = this;}
this._tmpSession.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt)
{
if (!this._tmpSession) { this._tmpSession = heci.create(); this._tmpSession.parent = this; }
this._tmpSession.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt) {
if (status == 0) {
var result = buffer.readUInt8(0).toString() + '.' + buffer.readUInt8(1).toString() + '.' + buffer.readUInt8(2).toString() + '.' + buffer.readUInt16BE(3).toString();
opt.unshift(result);
fn.apply(self, opt);
}
else
{
else {
opt.unshift(null);
fn.apply(self, opt);
}
}, this, callback, optional);
}
this.startConfigurationHBased = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) {
if ((certHash == null) || ((certHash.length != 32) && (certHash.length != 48))) { func({ status: -101 }); }
this.stopConfiguration(function (status) {
if (status == 0) {
// We stopped the configuration, wait 20 seconds before starting up again.
var f = function tf() { delete tf.parent.xtimeout; tf.parent.startConfigurationHBasedEx(certHash, hostVpn, dnsSuffixList, func); }
f.parent = this;
this.xtimeout = setTimeout(f, 20000);
} else {
// We are not in the connect mode, this is good, start configuration right away.
this.startConfigurationHBasedEx(certHash, hostVpn, dnsSuffixList, func);
}
})
}
this.startConfigurationHBasedEx = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) {
var optional = [];
for (var i = 4; i < arguments.length; ++i) { optional.push(arguments[i]); }
// Format the command
var data = Buffer.alloc(4 + 64 + 4 + 4 + 320);
data.writeUInt32LE((certHash.length == 48) ? 3 : 2, 0); // Write certificate hash type: SHA256 = 2, SHA384 = 3
certHash.copy(data, 4); // Write the hash
data.writeUInt32LE(hostVpn ? 1 : 0, 68); // Write is HostVPN is enabled
if (dnsSuffixList != null) {
data.writeUInt32LE(dnsSuffixList.length, 72); // Write the number of DNS Suffix, from 0 to 4
var ptr = 76;
for (var i = 0; i < dnsSuffixList.length; i++) { ptr += data.write(dnsSuffixList[i], ptr) + 1; } // Write up to 4 DNS Suffix with null seperation.
}
// Send the command
this.sendCommand(139, data, function (header, fn, opt) {
if (header.Status == 0) {
var amtHash = null;
if (header.Data[0] == 2) { amtHash = header.Data.slice(1, 33); } // SHA256
if (header.Data[0] == 3) { amtHash = header.Data.slice(1, 49); } // SHA384
opt.unshift({ status: header.Status, hash: amtHash.toString('hex') });
} else {
opt.unshift({ status: header.Status });
}
fn.apply(this, opt);
}, func, optional);
}
}
module.exports = amt_heci;
module.exports = amt_heci;
/*
AMT_STATUS_SUCCESS = 0,
AMT_STATUS_INTERNAL_ERROR = 1,
AMT_STATUS_INVALID_AMT_MODE = 3,
AMT_STATUS_INVALID_MESSAGE_LENGTH = 4,
AMT_STATUS_MAX_LIMIT_REACHED = 23,
AMT_STATUS_INVALID_PARAMETER = 36,
AMT_STATUS_RNG_GENERATION_IN_PROGRESS = 47,
AMT_STATUS_RNG_NOT_READY = 48,
AMT_STATUS_CERTIFICATE_NOT_READY = 49,
AMT_STATUS_INVALID_HANDLE = 2053
AMT_STATUS_NOT_FOUND = 2068,
*/

View file

@ -183,6 +183,8 @@ function CreateAPFClient(parent, args) {
obj.updateMeiState = function (state) { SendJsonControl(obj.forwardClient.ws, { action: 'meiState', value: state }); }
obj.sendMeiDeactivationState = function (state) { SendJsonControl(obj.forwardClient.ws, { action: 'deactivate', value: state }); }
obj.sendStartTlsHostConfigResponse = function (state) { SendJsonControl(obj.forwardClient.ws, { action: 'startTlsHostConfig', value: state }); }
obj.sendStopConfigurationResponse = function (state) { SendJsonControl(obj.forwardClient.ws, { action: 'stopConfiguration', value: state }); }
function SendJsonControl(socket, o) {
var data = JSON.stringify(o)

View file

@ -87,7 +87,7 @@ function AmtManager(agent, db, isdebug) {
obj.getMeiState = function(flags, func) {
if ((amtMei == null) || (amtMeiState < 2)) { if (func != null) { func(null); } return; }
try {
var amtMeiTmpState = { OsHostname: require('os').hostname(), Flags: 0 }; // Flags: 1=EHBC, 2=CCM, 4=ACM
var amtMeiTmpState = { 'core-ver': 1, OsHostname: require('os').hostname(), Flags: 0 }; // Flags: 1=EHBC, 2=CCM, 4=ACM
if (getMeiStateCache.MeiVersion != null) { amtMeiTmpState.MeiVersion = getMeiStateCache.MeiVersion; } else { amtMei.getProtocolVersion(function (result) { if (result != null) { getMeiStateCache.MeiVersion = amtMeiTmpState.MeiVersion = result; } }); }
if ((flags & 1) != 0) {
if (getMeiStateCache.Versions != null) {
@ -157,6 +157,12 @@ function AmtManager(agent, db, isdebug) {
}
}
// Start host based ACM activation with TLS
obj.startConfigurationHBased = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) {
if ((amtMei == null) || (amtMeiState < 2)) { if (func != null) { func({ status: -100 }); } return; }
amtMei.startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func);
}
}
module.exports = AmtManager;

View file

@ -24,22 +24,18 @@ function amt_heci() {
this._ObjectID = "pthi";
this._rq = new Q();
this._setupPTHI = function _setupPTHI()
{
this._setupPTHI = function _setupPTHI() {
this._amt = heci.create();
this._amt.descriptorMetadata = "amt-pthi";
this._amt.BiosVersionLen = 65;
this._amt.UnicodeStringLen = 20;
this._amt.Parent = this;
this._amt.on('error', function _amtOnError(e)
{
if(this.Parent._rq.isEmpty())
{
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
{
else {
// There is a pending request, so fail the pending request
var user = this.Parent._rq.deQueue();
var params = user.optional;
@ -47,17 +43,14 @@ function amt_heci() {
params.unshift({ Status: -1 }); // Relay an error
callback.apply(this.Parent, params);
if(!this.Parent._rq.isEmpty())
{
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)
{
this._amt.on('connect', function _amtOnConnect() {
this.on('data', function _amtOnData(chunk) {
//console.log("Received: " + chunk.length + " bytes");
var header = this.Parent.getCommand(chunk);
//console.log("CMD = " + header.Command + " (Status: " + header.Status + ") Response = " + header.IsResponse);
@ -69,14 +62,12 @@ function amt_heci() {
params.unshift(header);
callback.apply(this.Parent, params);
if(this.Parent._rq.isEmpty())
{
if (this.Parent._rq.isEmpty()) {
// No More Requests, we can close PTHI
this.Parent._amt.disconnect();
this.Parent._amt = null;
}
else
{
else {
// Send the next request
this.write(this.Parent._rq.peekQueue().send);
}
@ -93,8 +84,7 @@ 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]); }
@ -102,10 +92,9 @@ function amt_heci() {
var header = Buffer.from('010100000000000000000000', 'hex');
header.writeUInt32LE(arguments[0] | 0x04000000, 4);
header.writeUInt32LE(arguments[1] == null ? 0 : arguments[1].length, 8);
this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args , send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]]))});
this._rq.enQueue({ cmd: arguments[0], func: arguments[2], optional: args, send: (arguments[1] == null ? header : Buffer.concat([header, arguments[1]])) });
if(!this._amt)
{
if (!this._amt) {
this._setupPTHI();
this._amt.connect(heci.GUIDS.AMT, { noPipeline: 1 });
}
@ -117,7 +106,7 @@ function amt_heci() {
this.sendCommand(26, null, function (header, fn, opt) {
if (header.Status == 0) {
var i, CodeVersion = header.Data, val = { BiosVersion: CodeVersion.slice(0, this._amt.BiosVersionLen).toString(), Versions: [] }, v = CodeVersion.slice(this._amt.BiosVersionLen + 4);
for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen) ; ++i) {
for (i = 0; i < CodeVersion.readUInt32LE(this._amt.BiosVersionLen); ++i) {
val.Versions[i] = { Description: v.slice(2, v.readUInt16LE(0) + 2).toString(), Version: v.slice(4 + this._amt.UnicodeStringLen, 4 + this._amt.UnicodeStringLen + v.readUInt16LE(2 + this._amt.UnicodeStringLen)).toString() };
v = v.slice(4 + (2 * this._amt.UnicodeStringLen));
}
@ -302,34 +291,27 @@ 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.Status == 0 && header.Data.length == 68)
{
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
{
else {
opt.unshift(null);
}
fn.apply(this, opt);
}, callback, optional);
}
this.getLanInterfaceSettings = function getLanInterfaceSettings(index, callback)
{
this.getLanInterfaceSettings = function getLanInterfaceSettings(index, callback) {
var optional = [];
for (var i = 2; i < arguments.length; ++i) { optional.push(arguments[i]); }
var ifx = Buffer.alloc(4);
ifx.writeUInt32LE(index);
this.sendCommand(0x48, ifx, function onGetLanInterfaceSettings(header, fn, opt)
{
if(header.Status == 0)
{
this.sendCommand(0x48, ifx, function onGetLanInterfaceSettings(header, fn, opt) {
if (header.Status == 0) {
var info = {};
info.enabled = header.Data.readUInt32LE(0);
info.dhcpEnabled = header.Data.readUInt32LE(8);
switch(header.Data[12])
{
switch (header.Data[12]) {
case 1:
info.dhcpMode = 'ACTIVE'
break;
@ -341,14 +323,13 @@ function amt_heci() {
break;
}
info.mac = header.Data.slice(14).toString('hex:');
var addr = header.Data.readUInt32LE(4);
info.address = ((addr >> 24) & 255) + '.' + ((addr >> 16) & 255) + '.' + ((addr >> 8) & 255) + '.' + (addr & 255);
opt.unshift(info);
fn.apply(this, opt);
}
else
{
else {
opt.unshift(null);
fn.apply(this, opt);
}
@ -398,27 +379,81 @@ function amt_heci() {
fn.apply(this, opt);
}, callback, optional);
}
this.getProtocolVersion = function getProtocolVersion(callback)
{
this.getProtocolVersion = function getProtocolVersion(callback) {
var optional = [];
for (var i = 1; i < arguments.length; ++i) { opt.push(arguments[i]); }
if (!this._tmpSession) { this._tmpSession = heci.create(); this._tmpSession.parent = this;}
this._tmpSession.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt)
{
if (!this._tmpSession) { this._tmpSession = heci.create(); this._tmpSession.parent = this; }
this._tmpSession.doIoctl(heci.IOCTL.HECI_VERSION, Buffer.alloc(5), Buffer.alloc(5), function (status, buffer, self, fn, opt) {
if (status == 0) {
var result = buffer.readUInt8(0).toString() + '.' + buffer.readUInt8(1).toString() + '.' + buffer.readUInt8(2).toString() + '.' + buffer.readUInt16BE(3).toString();
opt.unshift(result);
fn.apply(self, opt);
}
else
{
else {
opt.unshift(null);
fn.apply(self, opt);
}
}, this, callback, optional);
}
this.startConfigurationHBased = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) {
if ((certHash == null) || ((certHash.length != 32) && (certHash.length != 48))) { func({ status: -101 }); }
this.stopConfiguration(function (status) {
if (status == 0) {
// We stopped the configuration, wait 20 seconds before starting up again.
var f = function tf() { delete tf.parent.xtimeout; tf.parent.startConfigurationHBasedEx(certHash, hostVpn, dnsSuffixList, func); }
f.parent = this;
this.xtimeout = setTimeout(f, 20000);
} else {
// We are not in the connect mode, this is good, start configuration right away.
this.startConfigurationHBasedEx(certHash, hostVpn, dnsSuffixList, func);
}
})
}
this.startConfigurationHBasedEx = function startConfigurationHBased(certHash, hostVpn, dnsSuffixList, func) {
var optional = [];
for (var i = 4; i < arguments.length; ++i) { optional.push(arguments[i]); }
// Format the command
var data = Buffer.alloc(4 + 64 + 4 + 4 + 320);
data.writeUInt32LE((certHash.length == 48) ? 3 : 2, 0); // Write certificate hash type: SHA256 = 2, SHA384 = 3
certHash.copy(data, 4); // Write the hash
data.writeUInt32LE(hostVpn ? 1 : 0, 68); // Write is HostVPN is enabled
if (dnsSuffixList != null) {
data.writeUInt32LE(dnsSuffixList.length, 72); // Write the number of DNS Suffix, from 0 to 4
var ptr = 76;
for (var i = 0; i < dnsSuffixList.length; i++) { ptr += data.write(dnsSuffixList[i], ptr) + 1; } // Write up to 4 DNS Suffix with null seperation.
}
// Send the command
this.sendCommand(139, data, function (header, fn, opt) {
if (header.Status == 0) {
var amtHash = null;
if (header.Data[0] == 2) { amtHash = header.Data.slice(1, 33); } // SHA256
if (header.Data[0] == 3) { amtHash = header.Data.slice(1, 49); } // SHA384
opt.unshift({ status: header.Status, hash: amtHash.toString('hex') });
} else {
opt.unshift({ status: header.Status });
}
fn.apply(this, opt);
}, func, optional);
}
}
module.exports = amt_heci;
module.exports = amt_heci;
/*
AMT_STATUS_SUCCESS = 0,
AMT_STATUS_INTERNAL_ERROR = 1,
AMT_STATUS_INVALID_AMT_MODE = 3,
AMT_STATUS_INVALID_MESSAGE_LENGTH = 4,
AMT_STATUS_MAX_LIMIT_REACHED = 23,
AMT_STATUS_INVALID_PARAMETER = 36,
AMT_STATUS_RNG_GENERATION_IN_PROGRESS = 47,
AMT_STATUS_RNG_NOT_READY = 48,
AMT_STATUS_CERTIFICATE_NOT_READY = 49,
AMT_STATUS_INVALID_HANDLE = 2053
AMT_STATUS_NOT_FOUND = 2068,
*/

View file

@ -358,8 +358,10 @@ function agentUpdate_Start(updateurl, updateoptions) {
var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
// If the url starts with *, switch it to use the same protoco, host and port as the control channel.
updateurl = getServerTargetUrlEx(updateurl);
if (updateurl.startsWith("wss://")) { updateurl = "https://" + updateurl.substring(6); }
if (updateurl != null) {
updateurl = getServerTargetUrlEx(updateurl);
if (updateurl.startsWith("wss://")) { updateurl = "https://" + updateurl.substring(6); }
}
if (agentUpdate_Start._selfupdate != null) {
// We were already called, so we will ignore this duplicate request
@ -390,10 +392,10 @@ function agentUpdate_Start(updateurl, updateoptions) {
return;
}
if (sessionid != null) { sendConsoleText('Downloading update from: ' + updateurl, sessionid); }
if ((sessionid != null) && (updateurl != null)) { sendConsoleText('Downloading update from: ' + updateurl, sessionid); }
var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl);
options.protocol = 'https:';
if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); }
if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); sendConsoleText('Downloading update from: ' + options.path, sessionid); }
options.rejectUnauthorized = false;
options.checkServerIdentity = function checkServerIdentity(certs) {
// If the tunnel certificate matches the control channel certificate, accept the connection
@ -1007,7 +1009,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
var response = null;
switch (cmd) {
case 'help':
response = "Available commands are: agentupdate, dbkeys, dbget, dbset, dbcompact, eval, netinfo, osinfo, setdebug, versions.";
response = "Available commands are: agentupdate, agentupdateex, dbkeys, dbget, dbset, dbcompact, eval, netinfo, osinfo, setdebug, versions.";
break;
case '_descriptors':
response = 'Open Descriptors: ' + JSON.stringify(getOpenDescriptors());
@ -1021,7 +1023,11 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
break;
case 'agentupdateex':
// Perform an direct agent update without requesting any information from the server, this should not typically be used.
agentUpdate_Start(null, { sessionid: sessionid });
if (args['_'].length == 1) {
if (args['_'][0].startsWith('https://')) { agentUpdate_Start(args['_'][0], { sessionid: sessionid }); } else { response = "Usage: agentupdateex https://server/path"; }
} else {
agentUpdate_Start(null, { sessionid: sessionid });
}
break;
case 'eval':
{ // Eval JavaScript