Removed meshcmd actions: amtacm, amtscript, amtdiscover.

This commit is contained in:
Ylian Saint-Hilaire 2020-10-29 12:59:55 -07:00
parent 6a18705ec7
commit 06f0f8cb43
4 changed files with 33 additions and 742 deletions

Binary file not shown.

Binary file not shown.

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', 'AMTSCRIPT', 'AMTUUID', 'AMTCCM', 'AMTACM', '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'];
// Load the action file
var actionfile = null;
@ -133,7 +133,6 @@ function run(argv) {
if ((typeof args.username) == 'string') { settings.username = args.username; }
if ((typeof args.password) == 'string') { settings.password = args.password; }
if ((typeof args.url) == 'string') { settings.url = args.url; }
if ((typeof args.profile) == 'string') { settings.profile = args.profile; }
if ((typeof args.type) == 'string') { settings.type = args.type; }
if ((typeof args.user) == 'string') { settings.username = args.user; }
if ((typeof args.pass) == 'string') { settings.password = args.pass; }
@ -184,7 +183,6 @@ function run(argv) {
console.log(' AmtVersions - Show all Intel ME version information.');
console.log(' AmtHashes - Show all Intel AMT trusted activation hashes.');
console.log(' AmtCCM - Activate Intel AMT into Client Control Mode.');
console.log(' AmtACM - Activate Intel AMT into Admin Control Mode.');
console.log(' AmtDeactivate - Deactivate Intel AMT if activated in Client Control mode.');
console.log(' AmtAcmDeactivate - Deactivate Intel AMT if activated in Admin Control mode.');
console.log('\r\nValid local or remote actions:');
@ -198,7 +196,6 @@ function run(argv) {
console.log(' AmtSaveState - Save all Intel AMT WSMAN object to file.');
console.log(' AmtPresence - Heartbeat a local Intel AMT watchdog agent.');
console.log(' AmtPower - Perform remote Intel AMT power operation.');
console.log(' AmtScript - Run .mescript on Intel AMT.');
console.log(' AmtIDER - Mount local disk image to remote computer.');
console.log(' AmtFeatures - Intel AMT features & user consent.');
console.log(' AmtNetwork - Intel AMT network interface settings.');
@ -242,24 +239,12 @@ function run(argv) {
console.log('AmtCCM will attempt to activate Intel AMT on this computer into client control mode (CCM). The command must be run on a computer with Intel AMT, must run as administrator and the Intel management driver must be installed. Intel AMT must be in "pre-provisioning" state for this command to work and a administrator password must be provided.');
console.log('\r\nPossible arguments:\r\n');
console.log(' --password [password] Admin password used to activate Intel AMT.');
console.log('\r\nor:\r\n');
console.log(' --url [wss://server] Url to the activation server.');
console.log(' --tag [string] Optional string sent to the server during activation.');
console.log(' --serverhttpshash [hash] Optional TLS server certificate hash.');
console.log(' --profile [string] Optional profile used for server activation.');
} else if (action == 'amtconfig') {
console.log('AmtConfig will attempt to activate and configure Intel AMT on this computer. The command must be run on a computer with Intel AMT, must run as administrator and the Intel management driver must be installed. Example usage:\r\n\r\n meshcmd amtconfig --url [url]');
console.log('\r\nPossible arguments:\r\n');
console.log(' --url [wss://server] The address of the MeshCentral server.');
console.log(' --id [groupid] The device group identifier.');
console.log(' --serverhttpshash [hash] Optional TLS server certificate hash.');
} else if (action == 'amtacm') {
console.log('AmtACM will attempt to activate Intel AMT on this computer into admin control mode (ACM). The command must be run on a computer with Intel AMT, must run as administrator and the Intel management driver must be installed. Intel AMT must be in "pre-provisioning" state for this command to work. Example usage:\r\n\r\n meshcmd amtacm --url [url]');
console.log('\r\nPossible arguments:\r\n');
console.log(' --url [wss://server] The address of the Intel AMT activation server.');
console.log(' --tag [string] Optional string sent to the server during activation.');
console.log(' --serverhttpshash [hash] Optional TLS server certificate hash.');
console.log(' --profile [string] Optional profile used for server activation.');
} else if (action == 'amtdeactivate') {
console.log('AmtDeactivate will attempt to deactivate Intel AMT on this computer when in client control mode (CCM). The command must be run on a computer with Intel AMT, must run as administrator and the Intel management driver must be installed. Intel AMT must be activated in client control mode for this command to work. Example usage:\r\n\r\n meshcmd amtdeactivate');
} else if (action == 'amtacmdeactivate') {
@ -310,14 +295,6 @@ function run(argv) {
console.log(' --user [username] The Intel AMT login username, admin is default.');
console.log(' --pass [password] The Intel AMT login password.');
console.log(' --agent [uuid] The unique identifier of the watchdog agent.');
} else if (action == 'amtscript') {
console.log('AmtScript will run a .mescript file on the local or remote Intel AMT. Script files can be built using the MeshCommander script editor and be used to setup or perform actions on Intel AMT. Example usage:\r\n\r\n meshcmd amtscript --script myscript.mescript --host 1.2.3.4 --user admin --pass mypassword --tls');
console.log('\r\nPossible arguments:\r\n');
console.log(' --script [filename] The script file to run on Intel AMT.');
console.log(' --host [hostname] The IP address or DNS name of Intel AMT, 127.0.0.1 is default.');
console.log(' --user [username] The Intel AMT login username, admin is default.');
console.log(' --pass [password] The Intel AMT login password.');
console.log(' --tls Specifies that TLS must be used.');
} else if (action == 'amtpower') {
console.log('AmtPower will get current pwoer state or send a reboot command to a remote Intel AMT device. Example usage:\r\n\r\n meshcmd amtpower --reset --host 1.2.3.4 --user admin --pass mypassword --tls');
console.log('\r\nRequired arguments:\r\n');
@ -622,14 +599,6 @@ function run(argv) {
if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; }
if ((settings.agent == null) || (typeof settings.agent != 'string') || (settings.agent == '')) { console.log('No or invalid \"agent\" specified, use --agent [agent].'); exit(1); return; }
performAmtAgentPresence();
} else if (settings.action == 'amtscript') {
// Start running a MEScript
if ((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) { console.log('No or invalid \"password\" specified, use --password [password].'); exit(1); return; }
if ((settings.hostname == null) || (typeof settings.hostname != 'string') || (settings.hostname == '')) { settings.hostname = '127.0.0.1'; }
if ((settings.username == null) || (typeof settings.username != 'string') || (settings.username == '')) { settings.username = 'admin'; }
//if ((settings.script == null) || (typeof settings.script != 'string') || (settings.script == '')) { if (mescriptJSON != '') { settings.scriptjson = mescriptJSON; } else { console.log('No or invalid \"script\" file specified, use --script [filename].'); exit(1); return; } }
if ((settings.script == null) || (typeof settings.script != 'string') || (settings.script == '')) { console.log('No or invalid \"script\" file specified, use --script [filename].'); exit(1); return; }
startMeScript();
} else if (settings.action == 'amtuuid') {
// Start running
if (settings.hostname != null) {
@ -648,23 +617,11 @@ function run(argv) {
configureAmt();
} else if (settings.action == 'amtccm') {
// Start activation to CCM
if (((settings.password == null) || (typeof settings.password != 'string') || (settings.password == '')) && ((settings.url == null) || (typeof settings.url != 'string') || (settings.url == ''))) { console.log('No or invalid parameters specified, use --password [password] or --url [url].'); exit(1); return; }
if ((typeof settings.profile != 'string') || (settings.profile == '')) { settings.profile = null; }
if (((settings.password == null) || (typeof settings.password != 'string') || (settings.password == ''))) { console.log('No or invalid parameters specified, use --password [password] or --url [url].'); exit(1); return; }
settings.protocol = 'http:';
settings.localport = 16992;
debug(1, "Settings: " + JSON.stringify(settings));
if (settings.password != null) { activeToCCM(); } else { activeToACM(); }
} else if (settings.action == 'amtacm') {
// Start activation to ACM
if ((settings.url == null) || (typeof settings.url != 'string') || (settings.url == '')) { console.log('No activation server URL specified, use --url [url].'); exit(1); return; }
if ((typeof settings.profile != 'string') || (settings.profile == '')) { settings.profile = null; }
debug(1, "Settings: " + JSON.stringify(settings));
activeToACM();
} else if (settings.action == 'amtdiscover') {
// Intel AMT server discovery, tell the server the state of Intel AMT.
if ((settings.url == null) || (typeof settings.url != 'string') || (settings.url == '')) { console.log('No activation server URL specified, use --url [url].'); exit(1); return; }
debug(1, "Settings: " + JSON.stringify(settings));
activeToACM();
activeToCCM();
} else if (settings.action == 'amtdeactivate') {
// Deactivate CCM
debug(1, "Settings: " + JSON.stringify(settings));
@ -739,7 +696,7 @@ function run(argv) {
if ((args.ssid == null) || (typeof args.ssid != 'string') || args.ssid == '') { console.log("Wifi SSID is required."); exit(1); return; }
if ((args.psk == null) || (typeof args.psk != 'string') || args.psk == '') { console.log("Wifi password is required."); exit(1); return; }
}
if (args.del !=null) {
if (args.del != null) {
if ((settings.name == null) || (typeof settings.name != 'string') || settings.name == '') { console.log("Wifi profile name is required."); exit(1); return; }
}
performAmtWifiConfig(args);
@ -938,7 +895,7 @@ function readAmtEventLogEx2(stack, messages) {
} exit(1);
});
}
else{
else {
console.log('Invalid action, usage:\r\n\r\n meshcmd help amtauditlog');
exit(1);
}
@ -1017,7 +974,7 @@ function readAmtAuditLogEx2(stack, response, status) {
} exit(1);
});
}
else{
else {
console.log('Invalid action, usage:\r\n\r\n meshcmd help amtauditlog');
exit(1);
}
@ -1238,7 +1195,6 @@ function activeToCCMEx3(stack, name, responses, status) {
//
// Deactivate Intel AMT ACM
//
@ -1304,229 +1260,6 @@ function getTrustedHashes(amtMei, func, tag) {
});
}
//
// Activate Intel AMT to with server (ACM or CCM)
//
function activeToACM() {
console.log('Starting Intel AMT activation attempt...');
settings.noconsole = true;
// Display Intel AMT version and activation state
mestate = {};
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; });
try {
amtMei.getProvisioningState(function (result) { if (result) { mestate.ProvisioningState = result; } });
amtMei.getVersion(function (val) { mestate.vers = {}; if (val != null) { for (var version in val.Versions) { mestate.vers[val.Versions[version].Description] = val.Versions[version].Version; } } });
amtMei.getLanInterfaceSettings(0, function (result) { if (result) { mestate.net0 = result; } });
amtMei.getUuid(function (result) { if ((result != null) && (result.uuid != null)) { mestate.uuid = result.uuid; } });
amtMei.getControlMode(function (result) { if (result != null) { mestate.controlMode = result.controlMode; } }); // controlMode: 0 = NoActivated, 1 = CCM, 2 = ACM
amtMei.getDnsSuffix(function (result) {
if ((mestate.vers == null) || (mestate.vers['AMT'] == null)) { console.log("Unable to get Intel AMT version."); exit(100); return; }
if (mestate.ProvisioningState == null) { console.log("Unable to read Intel AMT activation state."); exit(100); return; }
if ((settings.action != 'amtdiscover') && (mestate.controlMode == 2)) { console.log("Intel AMT already activation in admin control mode."); exit(100); return; }
if (mestate.uuid == null) { console.log("Unable to get Intel AMT UUID."); exit(100); return; }
var fqdn = null;
if ((mestate.net0 == null) && (meinfo.net0.enabled != 0)) { console.log("No Intel AMT wired interface, can't perform ACM activation."); exit(100); return; }
if (result) { fqdn = result; } // If Intel AMT has a trusted DNS suffix set, use that one.
else {
// Look for the DNS suffix for the Intel AMT Ethernet interface
var interfaces = require('os').networkInterfaces();
for (var i in interfaces) {
for (var j in interfaces[i]) {
if ((interfaces[i][j].mac == mestate.net0.mac) && (interfaces[i][j].fqdn != null) && (interfaces[i][j].fqdn != '')) { fqdn = interfaces[i][j].fqdn; }
}
}
}
if (fqdn != null) {
settings.fqdn = fqdn;
settings.uuid = mestate.uuid;
getTrustedHashes(amtMei, function () { startLms(getFwNonce, amtMei); });
} else {
console.log("Trusted DNS suffix not set, can't perform ACM activation."); exit(100); return;
}
});
} catch (ex) { console.log("Unable to perform MEI operations, try running as administrator."); exit(1); return; }
}
// Gets the FWNonce from AMT and saves it to a file.
function getFwNonce() {
osamtstack.BatchEnum(null, ['*AMT_GeneralSettings', '*IPS_HostBasedSetupService'], function (stack, name, responses, status) {
if (status != 200) { console.log("Unable to get firmware activation nonce, status=" + status); exit(100); return; }
var fwNonce = responses['IPS_HostBasedSetupService'].response['ConfigurationNonce'];
var digestRealm = responses['AMT_GeneralSettings'].response['DigestRealm'];
var allowedModes = responses['IPS_HostBasedSetupService'].response['AllowedControlModes']; // 1 = CCM, 2 = ACM
activeToACMEx(fwNonce, settings.fqdn, digestRealm, settings.uuid, allowedModes);
});
}
// Connect to the activation server and perform ACM activation
function activeToACMEx(fwNonce, dnsSuffix, digestRealm, uuid, allowedModes) {
console.log('FQDN: ' + dnsSuffix);
console.log('UUID: ' + uuid);
console.log('Realm: ' + digestRealm);
console.log('Nonce: ' + fwNonce);
console.log('Connecting to ' + settings.url);
// Establish WebSocket connection to activation server
var options = http.parseUri(settings.url);
options.checkServerIdentity = onVerifyServer;
options.rejectUnauthorized = false;
var connection = http.request(options);
connection.on('upgrade', function (response, socket) {
settings.xxsocket = socket;
if (settings.action == 'amtdiscover') { console.log('Connected, performing discovery...'); } else { console.log('Connected, requesting activation...'); }
socket.on('end', function () { console.log('Connection closed'); exit(0); });
socket.on('error', function () { console.log('Connection error'); exit(100); });
socket.on('data', function (data) {
// Parse and check the response
var cmd = null;
try { cmd = JSON.parse(data); } catch (ex) { console.log('Unable to parse server response: ' + data); exit(100); return; }
if (typeof cmd != 'object') { console.log('Invalid server response: ' + cmd); exit(100); return; }
if (typeof cmd.errorText == 'string') { console.log('Server error: ' + cmd.errorText); exit(100); return; }
if (typeof cmd.messageText == 'string') { console.log('Server: ' + cmd.messageText); return; }
switch (cmd.action) {
case 'acmactivate': {
// Server responded with ACM activation response
if (typeof cmd.signature != 'string') { console.log('Invalid server signature'); exit(100); return; }
if (typeof cmd.password != 'string') { console.log('Invalid server password'); exit(100); return; }
if (typeof cmd.nonce != 'string') { console.log('Invalid server nonce'); exit(100); return; }
if (typeof cmd.certs != 'object') { console.log('Invalid server certificates'); exit(100); return; }
settings.xxprofileScript = cmd.profileScript;
settings.xxrawpassword = cmd.rawpassword;
cmd.index = 0;
// If we are in CCM mode, deactivate.
if (mestate.controlMode == 1) {
amtMei.unprovision(1, function (status) {
if (status == 0) {
console.log('Intel AMT CCM deactivated, holding 10 seconds...');
// We are ready to go, perform ACM activation.
settings.xxTimer = setTimeout(function () { performAcmActivation(cmd, AcmActivationCompleted); }, 10000);
} else {
console.log('Intel AMT CCM deactivation error ' + status); exit(1); return;
}
});
} else {
// We are ready to go, perform ACM activation.
performAcmActivation(cmd, AcmActivationCompleted);
}
break;
}
case 'ccmactivate': {
// Server responded with CCM activation response
if (typeof cmd.password != 'string') { console.log('Invalid server password'); exit(100); return; }
settings.xxprofileScript = cmd.profileScript;
settings.xxrawpassword = cmd.rawpassword;
// If we are already in CCM mode, deactivate.
if (mestate.controlMode == 1) {
amtMei.unprovision(1, function (status) {
if (status == 0) {
console.log('Intel AMT CCM deactivated, holding 10 seconds...');
// We are ready to go, perform CCM activation.
settings.xxTimer = setTimeout(function () { osamtstack.IPS_HostBasedSetupService_Setup(2, cmd.password, null, null, null, null, performCcmActivation); }, 10000);
} else {
console.log('Intel AMT CCM deactivation error ' + status); exit(1); return;
}
});
} else {
// We are ready to go, perform CCM activation.
osamtstack.IPS_HostBasedSetupService_Setup(2, cmd.password, null, null, null, null, performCcmActivation);
}
break;
}
case 'amtdiscover': {
console.log('Done.');
exit(0);
break;
}
default: {
console.log('Invalid server response, command: ' + cmd.action); exit(100);
break;
}
}
});
var action = 'acmactivate';
if (settings.action == 'amtccm') { action = 'ccmactivate'; }
if (settings.action == 'amtdiscover') { action = 'amtdiscover'; }
socket.write({ client: 'meshcmd', version: 1, action: action, fqdn: dnsSuffix, realm: digestRealm, nonce: fwNonce, uuid: uuid, profile: settings.profile, hashes: trustedHashes, tag: settings.tag, name: settings.name, ver: mestate.vers['AMT'], build: mestate.vers['Build Number'], sku: parseInt(mestate.vers['Sku']), modes: allowedModes, currentMode: mestate.controlMode, hostname: require('os').hostname() });
});
connection.end();
}
function performCcmActivation(stack, name, responses, status) {
if (status != 200) {
settings.xxsocket.write({ client: 'meshcmd', version: 1, action: 'ccmactivate-failed', uuid: mestate.uuid });
console.log('Failed to activate, status ' + status);
} else if (responses.Body.ReturnValue != 0) {
settings.xxsocket.write({ client: 'meshcmd', version: 1, action: 'ccmactivate-failed', uuid: mestate.uuid });
console.log('Intel AMT CCM activation failed: ' + responses.Body.ReturnValueStr);
} else {
settings.xxsocket.write({ client: 'meshcmd', version: 1, action: 'ccmactivate-success', uuid: mestate.uuid });
if ((settings.xxprofileScript !== null) && (settings.xxrawpassword != null)) {
console.log("Intel AMT CCM activation success, applying profile...");
settings.scriptjson = settings.xxprofileScript;
settings.password = settings.xxrawpassword; // This is only going to work if the server sends the raw password
settings.username = 'admin';
startMeScriptEx(function () { console.log('Intel AMT profile applied.'); socket.end(); exit(0); }, stack);
return;
} else {
console.log('Intel AMT CCM activation success.');
settings.xxsocket.end();
exit(0);
return;
}
}
settings.xxsocket.end();
exit(1);
}
function AcmActivationCompleted(result) {
if (result == false) {
console.log('Intel AMT ACM activation failed.');
settings.xxsocket.write({ client: 'meshcmd', version: 1, action: 'acmactivate-failed', uuid: mestate.uuid });
settings.xxsocket.end();
exit(1);
} else {
if ((settings.xxprofileScript !== null) && (settings.xxrawpassword != null)) {
console.log('Intel AMT ACM activation success, applying profile...');
settings.scriptjson = settings.xxprofileScript;
settings.password = settings.xxrawpassword; // This is only going to work if the server sends the raw password
settings.username = 'admin';
startMeScriptEx(function () { console.log('Intel AMT profile applied.'); settings.xxsocket.end(); exit(0); }, stack);
} else {
console.log('Intel AMT ACM activation success.');
settings.xxsocket.write({ client: 'meshcmd', version: 1, action: 'acmactivate-success', uuid: mestate.uuid });
settings.xxsocket.end();
exit(0);
}
}
}
// Recursive function to inject the provisioning certificates into AMT in the proper order and completes ACM activation
function performAcmActivation(acmdata, func) {
var leaf = (acmdata.index == 0), root = (acmdata.index == (acmdata.certs.length - 1));
if ((acmdata.index < acmdata.certs.length) && (acmdata.certs[acmdata.index] != null)) {
osamtstack.IPS_HostBasedSetupService_AddNextCertInChain(acmdata.certs[acmdata.index], leaf, root, function (stack, name, responses, status) {
if (status !== 200) { console.log('AddNextCertInChain error, status=' + status); exit(1); return; }
else if (responses['Body']['ReturnValue'] !== 0) { console.log('AddNextCertInChain error: ' + responses['Body']['ReturnValue']); exit(1); return; }
else { acmdata.index++; performAcmActivation(acmdata, func); }
});
} else {
//console.log(acmdata.password, acmdata.nonce, acmdata.signature);
osamtstack.IPS_HostBasedSetupService_AdminSetup(2, acmdata.password, acmdata.nonce, 2, acmdata.signature,
function (stack, name, responses, status) {
if (status !== 200) { console.log('Error, AdminSetup status: ' + status); }
else if (responses['Body']['ReturnValue'] != 0) { console.log('Error, AdminSetup return value: ' + responses['Body']['ReturnValue']); }
func((status == 200) && (responses['Body']['ReturnValue'] == 0));
}
);
}
}
//
// Get AMT UUID
@ -1557,45 +1290,6 @@ function getAmtUuidEx() {
}
//
// Run MESCRIPT
//
// Run a .mescript targeting local or remote Intel AMT.
function startMeScript() {
// See if MicroLMS needs to be started
if ((settings.hostname == '127.0.0.1') || (settings.hostname.toLowerCase() == 'localhost')) { settings.noconsole = true; startLms(startMeScriptEx); return; } else { startMeScriptEx(); }
}
function startMeScriptEx(callback, amtstack) {
//console.log('Running script...');
var transport = require('amt-wsman-duk');
var wsman = require('amt-wsman');
var amt = require('amt');
if (!wsstack) { wsstack = new wsman(transport, settings.hostname, settings.tls ? 16993 : 16992, settings.username, settings.password, settings.tls); }
if (!amtstack) { amtstack = new amt(wsstack); }
//IntelAmtEntireStateProgress = 101;
//amtstack.onProcessChanged = onWsmanProcessChanged;
var scriptData = null;
if (settings.script != null) {
try { scriptData = fs.readFileSync(settings.script); } catch (e) { console.log('Unable to read script file (1): ' + settings.script + '.'); exit(1); return; }
} else {
scriptData = settings.scriptjson;
}
if (scriptData == null) { console.log('Unable to read script file (2): ' + settings.script + '.'); exit(1); return; }
try { scriptData = JSON.parse(scriptData); } catch (e) { console.log('Unable to read script file (3): ' + settings.script + '.'); exit(1); return; }
if (scriptData.mescript == null) { console.log('Unable to read script file (4): ' + settings.script + '.'); exit(1); return; }
var scriptData = Buffer.from(scriptData.mescript, 'base64');
var scriptModule = require('amt-script');
var script = scriptModule.setup(scriptData, {})
script.amtstack = amtstack;
script.start();
script.onCompleted = function () { if (callback) { callback(); } exit(1); }
}
//
// FETCH ALL INTEL AMT STATE
//
@ -1616,7 +1310,6 @@ function saveEntireAmtState2() {
amtstack.BatchEnum(null, AllWsman, saveEntireAmtStateOk2, null, true);
amtstack.GetAuditLog(saveEntireAmtStateOk3);
amtstack.GetMessageLog(saveEntireAmtStateOk4);
}
// Save the entire Intel AMT state
@ -1625,8 +1318,7 @@ function saveEntireAmtState() {
if ((settings.hostname == '127.0.0.1') || (settings.hostname.toLowerCase() == 'localhost')) {
settings.noconsole = true;
startLms().then(saveEntireAmtState2);
}
else {
} else {
saveEntireAmtState2();
}
}
@ -2633,31 +2325,31 @@ function performAmtWifiConfig0(state, args) {
}
function performAmtWifiConfig1(stack, name, response, status, args) {
if ( status == 200 ) {
var wifiAuthMethod = {1: "Other", 2: "Open", 3: "Shared Key", 4: "WPA PSK", 5: "WPA 802.1x", 6: "WPA2 PSK", 7: "WPA2 802.1x", 32768 : "WPA3 802.1x"};
var wifiEncMethod = {1: "Other", 2: "WEP", 3: "TKIP", 4: "CCMP", 5: "None"}
if (status == 200) {
var wifiAuthMethod = { 1: "Other", 2: "Open", 3: "Shared Key", 4: "WPA PSK", 5: "WPA 802.1x", 6: "WPA2 PSK", 7: "WPA2 802.1x", 32768: "WPA3 802.1x" };
var wifiEncMethod = { 1: "Other", 2: "WEP", 3: "TKIP", 4: "CCMP", 5: "None" }
var wifiProfiles = {};
for (var y in response['CIM_WiFiEndpointSettings'].responses) {
var z = response['CIM_WiFiEndpointSettings'].responses[y];
var n = z['ElementName'];
wifiProfiles[n]= {'Priority': z['Priority'], 'SSID':z['SSID'],'AuthenticationMethod': z['AuthenticationMethod'], 'EncryptionMethod': z['EncryptionMethod']};
wifiProfiles[n] = { 'Priority': z['Priority'], 'SSID': z['SSID'], 'AuthenticationMethod': z['AuthenticationMethod'], 'EncryptionMethod': z['EncryptionMethod'] };
}
if (args) {
if (args.list) {
console.log('List of Intel AMT Wifi profiles:');
if (wifiProfiles.length==0) {
if (wifiProfiles.length == 0) {
console.log('No Wifi profiles is stored.');
}
for (var t in wifiProfiles) {
var w = wifiProfiles[t];
console.log('Profile Name: '+t+'; Priority: '+w['Priority']+ '; SSID: '+w['SSID']+'; Security: '+wifiAuthMethod[w['AuthenticationMethod']]+'/'+wifiEncMethod[w['EncryptionMethod']]);
console.log('Profile Name: ' + t + '; Priority: ' + w['Priority'] + '; SSID: ' + w['SSID'] + '; Security: ' + wifiAuthMethod[w['AuthenticationMethod']] + '/' + wifiEncMethod[w['EncryptionMethod']]);
}
process.exit(0);
} else if (args.add) {
if (args.auth==null) {args.auth=6}//if not set, default to WPA2 PSK
if (args.enc==null) {args.enc=3}//if not set, default to TKIP
if (args.priority==null) {args.priority=0}//if not set, default to 0
if (args.auth == null) { args.auth = 6; } // if not set, default to WPA2 PSK
if (args.enc == null) { args.enc = 3; } // if not set, default to TKIP
if (args.priority == null) { args.priority = 0; } // if not set, default to 0
var wifiep = {
__parameterType: 'reference',
@ -2677,8 +2369,8 @@ function performAmtWifiConfig1(stack, name, response, status, args) {
PSKPassPhrase: args.psk
}
stack.AMT_WiFiPortConfigurationService_AddWiFiSettings(wifiep, wifiepsettinginput, null, null, null,
function(stck, nm, resp, sts) {
if (sts==200) {
function (stck, nm, resp, sts) {
if (sts == 200) {
console.log("Wifi profile " + args.name + " successfully added.");
} else {
console.log("Failed to add wifi profile " + args.name + ".");
@ -2686,20 +2378,20 @@ function performAmtWifiConfig1(stack, name, response, status, args) {
process.exit(0);
});
} else if (args.del) {
if (wifiProfiles[args.name]==null) {
console.log("Profile "+args.name+" could not be found.");
if (wifiProfiles[args.name] == null) {
console.log("Profile " + args.name + " could not be found.");
process.exit(0);
}
stack.Delete('CIM_WiFiEndpointSettings', { InstanceID : 'Intel(r) AMT:WiFi Endpoint Settings ' + args.name },
function(stck, nm, resp, sts){
if (sts==200) {
stack.Delete('CIM_WiFiEndpointSettings', { InstanceID: 'Intel(r) AMT:WiFi Endpoint Settings ' + args.name },
function (stck, nm, resp, sts) {
if (sts == 200) {
console.log("Wifi profile " + args.name + " successfully deleted.");
} else {
console.log("Failed to delete wifi profile " + args.name + ".");
}
process.exit(0);
},
0, 1);
0, 1);
}
} else {
process.exit(0);
@ -2787,7 +2479,7 @@ function performAmtWakeConfig1(stack, name, response, status, args) {
if (sts == 200) { console.log("Done."); } else { console.log("Failed to delete wake alarm " + args.del + "."); }
process.exit(0);
},
0, 1);
0, 1);
} else if (args.add) {
// Add a wake alarm
var alarmFound = false;

View File

@ -1,401 +0,0 @@
/*
Copyright 2018-2020 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.
*/
/**
* @fileoverview Script Compiler / Decompiler / Runner
* @author Ylian Saint-Hilaire
* @version v0.1.0e
*/
// Core functions
script_functionTable1 = ['nop', 'jump', 'set', 'print', 'dialog', 'getitem', 'substr', 'indexof', 'split', 'join', 'length', 'jsonparse', 'jsonstr', 'add', 'substract', 'parseint', 'wsbatchenum', 'wsput', 'wscreate', 'wsdelete', 'wsexec', 'scriptspeed', 'wssubscribe', 'wsunsubscribe', 'readchar', 'signwithdummyca'];
// functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6)
script_functionTable2 = ['encodeuri', 'decodeuri', 'passwordcheck', 'atob', 'btoa', 'hex2str', 'str2hex', 'random', 'md5', 'maketoarray', 'readshort', 'readshortx', 'readint', 'readsint', 'readintx', 'shorttostr', 'shorttostrx', 'inttostr', 'inttostrx'];
// functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6)
script_functionTableX2 = [encodeURI, decodeURI, passwordcheck, atob, btoa, hex2rstr, rstr2hex, random, rstr_md5, MakeToArray, ReadShort, ReadShortX, ReadInt, ReadSInt, ReadIntX, ShortToStr, ShortToStrX, IntToStr, IntToStrX];
function MakeToArray(v) { if (!v || v == null || typeof v == 'object') return v; return [v]; }
function ReadShort(v, p) { return (v[p] << 8) + v[p + 1]; }
function ReadShortX(v, p) { return (v[p + 1] << 8) + v[p]; }
function ReadInt(v, p) { return (v[p] * 0x1000000) + (v[p + 1] << 16) + (v[p + 2] << 8) + v[p + 3]; } // We use "*0x1000000" instead of "<<24" because the shift converts the number to signed int32.
function ReadSInt(v, p) { return (v[p] << 24) + (v[p + 1] << 16) + (v[p + 2] << 8) + v[p + 3]; }
function ReadIntX(v, p) { return (v[p + 3] * 0x1000000) + (v[p + 2] << 16) + (v[p + 1] << 8) + v[p]; }
function ShortToStr(v) { return String.fromCharCode((v >> 8) & 0xFF, v & 0xFF); }
function ShortToStrX(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF); }
function IntToStr(v) { return String.fromCharCode((v >> 24) & 0xFF, (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); }
function IntToStrX(v) { return String.fromCharCode(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF, (v >> 24) & 0xFF); }
//function ShortToStr(v) { var b = Buffer.alloc(2); b.writeInt16BE(v); return b; }
//function ShortToStrX(v) { var b = Buffer.alloc(2); b.writeInt16LE(v); return b; }
//function IntToStr(v) { var b = Buffer.alloc(4); b.writeInt32BE(v); return b; }
//function IntToStrX(v) { var b = Buffer.alloc(4); b.writeInt32LE(v); return b; }
function btoa(x) { return Buffer.from(x).toString('base64');}
function atob(x) { var z = null; try { z = Buffer.from(x, 'base64').toString(); } catch (e) { console.log(e); } return z; }
function passwordcheck(p) { if (p.length < 8) return false; var upper = 0, lower = 0, number = 0, nonalpha = 0; for (var i in p) { var c = p.charCodeAt(i); if ((c > 64) && (c < 91)) { upper = 1; } else if ((c > 96) && (c < 123)) { lower = 1; } else if ((c > 47) && (c < 58)) { number = 1; } else { nonalpha = 1; } } return ((upper + lower + number + nonalpha) == 4); }
function hex2rstr(x) { Buffer.from(x, 'hex').toString(); }
function rstr2hex(x) { Buffer.from(x).toString('hex'); }
function random() { return Math.floor(Math.random()*max); }
function rstr_md5(str) { return hex2rstr(hex_md5(str)); }
function getItem(x, y, z) { for (var i in x) { if (x[i][y] == z) return x[i]; } return null; }
var httpErrorTable = {
200: 'OK',
401: 'Authentication Error',
408: 'Timeout Error',
601: 'WSMAN Parsing Error',
602: 'Unable to parse HTTP response header',
603: 'Unexpected HTTP enum response',
604: 'Unexpected HTTP pull response',
998: 'Invalid TLS certificate'
}
// Setup the script state
module.exports.setup = function(binary, startvars) {
var obj = { startvars: startvars, onCompleted: null };
if (binary.length < 6) { console.error('Invalid script length'); return null; } // Script must have at least 6 byte header
if (ReadInt(binary, 0) != 0x247D2945) { console.error('Invalid binary script'); return null; } // Check the script magic header
if (ReadShort(binary, 4) > 1) { console.error('Unsupported script version'); return null; } // Check the script version
obj.script = binary.slice(6);
// Reset the script to the start
obj.reset = function (stepspeed) {
obj.stop();
obj.ip = 0;
obj.variables = startvars;
obj.state = 1;
}
// Start the script
obj.start = function (stepspeed) {
obj.stop();
if (stepspeed == null) { obj.stepspeed = 10; } else { obj.stepspeed = stepspeed; }
if (obj.stepspeed > 0) { obj.timer = setInterval(function () { obj.step() }, obj.stepspeed); }
}
// Stop the script
obj.stop = function () {
if (obj.timer != null) { clearInterval(obj.timer); }
obj.timer = null;
obj.stepspeed = 0;
}
// function used to load and store variable values
obj.getVar = function (name) { if (name == undefined) return undefined; return obj.getVarEx(name.split('.'), obj.variables); }
obj.getVarEx = function (name, val) { try { if (name == undefined) return undefined; if (name.length == 0) return val; return obj.getVarEx(name.slice(1), val[name[0]]); } catch (e) { return null; } }
obj.setVar = function (name, val) { obj.setVarEx(name.split('.'), obj.variables, val); }
obj.setVarEx = function (name, vars, val) { if (name.length == 1) { vars[name[0]] = val; } else { obj.setVarEx(name.slice(1), vars[name[0]], val); } }
// Run the script one step forward
obj.step = function () {
if (obj.state != 1) return;
if (obj.ip < obj.script.length) {
var cmdid = ReadShort(obj.script, obj.ip);
var cmdlen = ReadShort(obj.script, obj.ip + 2);
var argcount = ReadShort(obj.script, obj.ip + 4);
var argptr = obj.ip + 6;
var args = [];
// Clear all temp variables (This is optional)
for (var i in obj.variables) { if (i.startsWith('__')) { delete obj.variables[i]; } }
// Loop on each argument, moving forward by the argument length each time
for (var i = 0; i < argcount; i++) {
var arglen = ReadShort(obj.script, argptr);
var argval = obj.script.slice(argptr + 2, argptr + 2 + arglen);
var argtyp = argval[0];
argval = argval.slice(1);
if (argtyp < 2) {
// Get the value and replace all {var} with variable values
argval = argval.toString();
if (argval != null) { while (argval.split("{").length > 1) { var t = argval.split("{").pop().split("}").shift(); argval = argval.replace('{' + t + '}', obj.getVar(t)); } }
if (argtyp == 1) { obj.variables['__' + i] = decodeURI(argval); argval = '__' + i; } // If argtyp is 1, this is a literal. Store in temp variable.
args.push(argval);
}
if (argtyp == 2 || argtyp == 3) {
obj.variables['__' + i] = ReadSInt(argval, 0);
args.push('__' + i);
}
argptr += (2 + arglen);
}
// Move instruction pointer forward by command size
obj.ip += cmdlen;
// Get all variable values
var argsval = [];
for (var i = 0; i < 10; i++) { argsval.push(obj.getVar(args[i])); }
var storeInArg0;
try {
if (cmdid < 10000) {
// Lets run the actual command
switch (cmdid) {
case 0: // nop
break;
case 1: // jump(label) or jump(label, a, compare, b)
if (argsval[2]) {
if (
(argsval[2] == '<' && argsval[1] < argsval[3]) ||
(argsval[2] == '<=' && argsval[1] <= argsval[3]) ||
(argsval[2] == '!=' && argsval[1] != argsval[3]) ||
(argsval[2] == '=' && argsval[1] == argsval[3]) ||
(argsval[2] == '>=' && argsval[1] >= argsval[3]) ||
(argsval[2] == '>' && argsval[1] > argsval[3])
) {
obj.ip = argsval[0];
}
} else {
obj.ip = argsval[0]; // Set the instruction pointer to the new location in the script
}
break;
case 2: // set(variable, value)
if (args[1] == undefined) delete obj.variables[args[0]]; else obj.setVar(args[0], argsval[1]);
break;
case 3: // print(message)
var v = obj.toString(argsval[0]);
if (v.indexOf('INFO: ') == 0) { v = v.substring(6); }
if (v.indexOf('SUCCESS: ') == 0) { v = v.substring(9); }
if (obj.onConsole) { obj.onConsole(v, obj); } else { console.log(v); }
// Q(obj.consoleid).value += () + '\n'); Q(obj.console).scrollTop = Q(obj.console).scrollHeight;
break;
case 4: // dialog(title, content, buttons)
obj.state = 2;
obj.dialog = true;
setDialogMode(11, argsval[0], argsval[2], obj.xxStepDialogOk, argsval[1], obj);
break;
case 5: // getitem(a, b, c)
for (var i in argsval[1]) { if (argsval[1][i][argsval[2]] == argsval[3]) { storeInArg0 = i; } };
break;
case 6: // substr(variable_dest, variable_src, index, len)
storeInArg0 = argsval[1].substr(argsval[2], argsval[3]);
break;
case 7: // indexOf(variable_dest, variable_src, index, len)
storeInArg0 = argsval[1].indexOf(argsval[2]);
break;
case 8: // split(variable_dest, variable_src, separator)
storeInArg0 = argsval[1].split(argsval[2]);
break;
case 9: // join(variable_dest, variable_src, separator)
storeInArg0 = argsval[1].join(argsval[2]);
break;
case 10: // length(variable_dest, variable_src)
if (argsval[1] == null) { storeInArg0 = 0; } else { storeInArg0 = argsval[1].length; }
break;
case 11: // jsonparse(variable_dest, json)
storeInArg0 = JSON.parse(argsval[1]);
break;
case 12: // jsonstr(variable_dest, variable_src)
storeInArg0 = JSON.stringify(argsval[1]);
break;
case 13: // add(variable_dest, variable_src, value)
storeInArg0 = (argsval[1] + argsval[2]);
break;
case 14: // substract(variable_dest, variable_src, value)
storeInArg0 = (argsval[1] - argsval[2]);
break;
case 15: // parseInt(variable_dest, variable_src)
storeInArg0 = parseInt(argsval[1]);
break;
case 16: // wsbatchenum(name, objectList)
obj.state = 2;
obj.amtstack.BatchEnum(argsval[0], argsval[1], obj.xxWsmanReturn, obj);
break;
case 17: // wsput(name, args)
obj.state = 2;
obj.amtstack.Put(argsval[0], argsval[1], obj.xxWsmanReturn, obj);
break;
case 18: // wscreate(name, args)
obj.state = 2;
obj.amtstack.Create(argsval[0], argsval[1], obj.xxWsmanReturn, obj);
break;
case 19: // wsdelete(name, args)
obj.state = 2;
obj.amtstack.Delete(argsval[0], argsval[1], obj.xxWsmanReturn, obj);
break;
case 20: // wsexec(name, method, args, selectors)
obj.state = 2;
obj.amtstack.Exec(argsval[0], argsval[1], argsval[2], obj.xxWsmanReturn, obj, 0, argsval[3]);
break;
case 21: // Script Speed
obj.stepspeed = argsval[0];
if (obj.timer != null) { clearInterval(obj.timer); obj.timer = setInterval(function () { obj.step() }, obj.stepspeed); }
break;
case 22: // wssubscribe(name, delivery, url, selectors, opaque, user, pass)
obj.state = 2;
obj.amtstack.Subscribe(argsval[0], argsval[1], argsval[2], obj.xxWsmanReturn, obj, 0, argsval[3], argsval[4], argsval[5], argsval[6]);
break;
case 23: // wsunsubscribe(name, selectors)
obj.state = 2;
obj.amtstack.UnSubscribe(argsval[0], obj.xxWsmanReturn, obj, 0, argsval[1]);
break;
case 24: // readchar(str, pos)
console.log(argsval[1], argsval[2], argsval[1].charCodeAt(argsval[2]));
storeInArg0 = argsval[1].charCodeAt(argsval[2]);
break;
case 25: // signWithDummyCa
// Not supported
break;
default: {
obj.state = 9;
console.error("Script Error, unknown command: " + cmdid);
}
}
} else {
if (cmdid < 20000) {
// functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6)
storeInArg0 = script_functionTableX2[cmdid - 10000](argsval[1], argsval[2], argsval[3], argsval[4], argsval[5], argsval[6]);
} else {
// Optional functions of type ARG1 = func(ARG2, ARG3, ARG4, ARG5, ARG6)
//if (script_functionTableX3 && script_functionTableX3[cmdid - 20000]) {
// storeInArg0 = script_functionTableX3[cmdid - 20000](obj, argsval[1], argsval[2], argsval[3], argsval[4], argsval[5], argsval[6]); // Note that optional calls start with "obj" as first argument.
//}
}
}
if (storeInArg0 != undefined) obj.setVar(args[0], storeInArg0);
} catch (e) {
if (typeof e == 'object') { e = e.message; }
obj.setVar('_exception', e);
}
}
if (obj.state == 1 && obj.ip >= obj.script.length) { obj.state = 0; obj.stop(); if (obj.onCompleted) { obj.onCompleted(); } }
if (obj.onStep) obj.onStep(obj);
return obj;
}
obj.xxStepDialogOk = function (button) {
obj.variables['DialogSelect'] = button;
obj.state = 1;
obj.dialog = false;
if (obj.onStep) obj.onStep(obj);
}
obj.xxWsmanReturn = function (stack, name, responses, status) {
obj.setVar(name, responses);
obj.setVar('wsman_result', status);
obj.setVar('wsman_result_str', ((httpErrorTable[status]) ? (httpErrorTable[status]) : ('Error #' + status)));
obj.state = 1;
if (obj.onStep) obj.onStep(obj);
}
obj.toString = function (x) { if (typeof x == 'object') return JSON.stringify(x); return x; }
obj.reset();
return obj;
}
// Argument types: 0 = Variable, 1 = String, 2 = Integer, 3 = Label
module.exports.compile = function(script, onmsg) {
var r = '', scriptlines = script.split('\n'), labels = {}, labelswap = [], swaps = [];
// Go thru each script line and encode it
for (var i in scriptlines) {
var scriptline = scriptlines[i];
if (scriptline.startsWith('##SWAP ')) { var x = scriptline.split(' '); if (x.length == 3) { swaps[x[1]] = x[2]; } } // Add a swap instance
if (scriptline[0] == '#' || scriptline.length == 0) continue; // Skip comments & blank lines
for (var x in swaps) { scriptline = scriptline.split(x).join(swaps[x]); } // Apply all swaps
var keywords = scriptline.match(/"[^"]*"|[^\s"]+/g);
if (keywords.length == 0) continue; // Skip blank lines
if (scriptline[0] == ':') { labels[keywords[0].toUpperCase()] = r.length; continue; } // Mark a label position
var funcIndex = script_functionTable1.indexOf(keywords[0].toLowerCase());
if (funcIndex == -1) { funcIndex = script_functionTable2.indexOf(keywords[0].toLowerCase()); if (funcIndex >= 0) funcIndex += 10000; }
if (funcIndex == -1) { if (onmsg) { onmsg("Unabled to compile, unknown command: " + keywords[0]); } return ''; }
// Encode CommandId, CmdSize, ArgCount, Arg1Len, Arg1, Arg2Len, Arg2...
var cmd = ShortToStr(keywords.length - 1);
for (var j in keywords) {
if (j == 0) continue;
if (keywords[j][0] == ':') {
labelswap.push([keywords[j], r.length + cmd.length + 7]); // Add a label swap
cmd += ShortToStr(5) + String.fromCharCode(3) + IntToStr(0xFFFFFFFF); // Put an empty label
} else {
var argint = parseInt(keywords[j]);
if (argint == keywords[j]) {
cmd += ShortToStr(5) + String.fromCharCode(2) + IntToStr(argint);
} else {
if (keywords[j][0] == '"' && keywords[j][keywords[j].length - 1] == '"') {
cmd += ShortToStr(keywords[j].length - 1) + String.fromCharCode(1) + keywords[j].substring(1, keywords[j].length - 1);
} else {
cmd += ShortToStr(keywords[j].length + 1) + String.fromCharCode(0) + keywords[j];
}
}
}
}
cmd = ShortToStr(funcIndex) + ShortToStr(cmd.length + 4) + cmd;
r += cmd;
}
// Perform all the needed label swaps
for (i in labelswap) {
var label = labelswap[i][0].toUpperCase(), position = labelswap[i][1], target = labels[label];
if (target == undefined) { if (onmsg) { onmsg("Unabled to compile, unknown label: " + label); } return ''; }
r = r.substr(0, position) + IntToStr(target) + r.substr(position + 4);
}
return IntToStr(0x247D2945) + ShortToStr(1) + r;
}
// Decompile the script, intended for debugging only
module.exports.decompile = function(binary, onecmd) {
var r = '', ptr = 6, labelcount = 0, labels = {};
if (onecmd >= 0) {
ptr = onecmd; // If we are decompiling just one command, set the ptr to that command.
} else {
if (binary.length < 6) { return '# Invalid script length'; }
var magic = ReadInt(binary, 0);
var version = ReadShort(binary, 4);
if (magic != 0x247D2945) { return '# Invalid binary script: ' + magic; }
if (version != 1) { return '# Invalid script version'; }
}
// Loop on each command, moving forward by the command length each time.
while (ptr < binary.length) {
var cmdid = ReadShort(binary, ptr);
var cmdlen = ReadShort(binary, ptr + 2);
var argcount = ReadShort(binary, ptr + 4);
var argptr = ptr + 6;
var argstr = '';
if (!(onecmd >= 0)) r += ":label" + (ptr - 6) + "\n";
// Loop on each argument, moving forward by the argument length each time
for (var i = 0; i < argcount; i++) {
var arglen = ReadShort(binary, argptr);
var argval = binary.substring(argptr + 2, argptr + 2 + arglen);
var argtyp = argval.charCodeAt(0);
if (argtyp == 0) { argstr += ' ' + argval.substring(1); } // Variable
else if (argtyp == 1) { argstr += ' \"' + argval.substring(1) + '\"'; } // String
else if (argtyp == 2) { argstr += ' ' + ReadInt(argval, 1); } // Integer
else if (argtyp == 3) { // Label
var target = ReadInt(argval, 1);
var label = labels[target];
if (!label) { label = ":label" + target; labels[label] = target; }
argstr += ' ' + label;
}
argptr += (2 + arglen);
}
// Go in the script function table to decode the function
if (cmdid < 10000) {
r += script_functionTable1[cmdid] + argstr + "\n";
} else {
if ((cmdid >= 10000) && (cmdid < 10000)) { r += script_functionTable2[cmdid - 10000] + argstr + "\n"; }
}
ptr += cmdlen;
if (onecmd >= 0) return r; // If we are decompiling just one command, exit now
}
// Remove all unused labels
var scriptlines = r.split('\n');
r = '';
for (var i in scriptlines) {
var line = scriptlines[i];
if (line[0] != ':') { r += line + '\n'; } else { if (labels[line]) { r += line + '\n'; } }
}
return r;
}