meshcentral
Version:
Web based remote computer management server
1,016 lines (918 loc) • 425 kB
JavaScript
/*
Copyright 2018-2022 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.
*/
process.on('uncaughtException', function (ex) {
require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "uncaughtException1: " + ex });
});
if (process.platform == 'win32' && require('user-sessions').getDomain == null) {
require('user-sessions').getDomain = function getDomain(uid) {
return (this.getSessionAttribute(uid, this.InfoClass.WTSDomainName));
};
}
var promise = require('promise');
// Mesh Rights
var MNG_ERROR = 65;
var MESHRIGHT_EDITMESH = 1;
var MESHRIGHT_MANAGEUSERS = 2;
var MESHRIGHT_MANAGECOMPUTERS = 4;
var MESHRIGHT_REMOTECONTROL = 8;
var MESHRIGHT_AGENTCONSOLE = 16;
var MESHRIGHT_SERVERFILES = 32;
var MESHRIGHT_WAKEDEVICE = 64;
var MESHRIGHT_SETNOTES = 128;
var MESHRIGHT_REMOTEVIEW = 256; // Remote View Only
var MESHRIGHT_NOTERMINAL = 512;
var MESHRIGHT_NOFILES = 1024;
var MESHRIGHT_NOAMT = 2048;
var MESHRIGHT_LIMITEDINPUT = 4096;
var MESHRIGHT_LIMITEVENTS = 8192;
var MESHRIGHT_CHATNOTIFY = 16384;
var MESHRIGHT_UNINSTALL = 32768;
var MESHRIGHT_NODESKTOP = 65536;
var MESHRIGHT_ADMIN = 0xFFFFFFFF;
var pendingSetClip = false; // This is a temporary hack to prevent multiple setclips at the same time to stop the agent from crashing.
//
// This is a helper function used by the 32 bit Windows Agent, when running on 64 bit windows. It will check if the agent is already patched for this
// and will use this helper if it is not. This helper will inject 'sysnative' into the results when calling readdirSync() on %windir%.
//
function __readdirSync_fix(path)
{
var sysnative = false;
pathstr = require('fs')._fixwinpath(path);
if (pathstr.split('\\*').join('').toLowerCase() == process.env['windir'].toLowerCase()) { sysnative = true; }
var ret = require('fs').__readdirSync_old(path);
if (sysnative) { ret.push('sysnative'); }
return (ret);
}
if (process.platform == 'win32' && require('_GenericMarshal').PointerSize == 4 && require('os').arch() == 'x64')
{
if (require('fs').readdirSync.version == null)
{
//
// 32 Bit Windows Agent on 64 bit Windows has not been patched for sysnative issue, so lets use our own solution
//
require('fs').__readdirSync_old = require('fs').readdirSync;
require('fs').readdirSync = __readdirSync_fix;
}
}
function bcdOK() {
if (process.platform != 'win32') { return (false); }
if (require('os').arch() == 'x64') {
return (require('_GenericMarshal').PointerSize == 8);
}
return (true);
}
function getDomainInfo() {
var hostname = require('os').hostname();
var ret = { Name: hostname, Domain: "", PartOfDomain: false };
switch (process.platform) {
case 'win32':
try {
ret = require('win-wmi-fixed').query('ROOT\\CIMV2', 'SELECT * FROM Win32_ComputerSystem', ['Name', 'Domain', 'PartOfDomain'])[0];
}
catch (x) {
}
break;
case 'linux':
var hasrealm = false;
try {
hasrealm = require('lib-finder').hasBinary('realm');
}
catch (x) {
}
if (hasrealm) {
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
child.stdin.write("realm list | grep domain-name: | tr '\\n' '`' | ");
child.stdin.write("awk -F'`' '{ ");
child.stdin.write(' printf("[");');
child.stdin.write(' ST="";');
child.stdin.write(' for(i=1;i<NF;++i)');
child.stdin.write(' {');
child.stdin.write(' match($i,/domain-name: /);');
child.stdin.write(' printf("%s\\"%s\\"", ST, substr($i, RSTART+RLENGTH));');
child.stdin.write(' ST=",";');
child.stdin.write(' }');
child.stdin.write(' printf("]");');
child.stdin.write(" }'");
child.stdin.write('\nexit\n');
child.waitExit();
var names = [];
try {
names = JSON.parse(child.stdout.str);
}
catch (e) {
}
while (names.length > 0) {
if (hostname.endsWith('.' + names.peek())) {
ret = { Name: hostname.substring(0, hostname.length - names.peek().length - 1), Domain: names.peek(), PartOfDomain: true };
break;
}
names.pop();
}
}
break;
}
return (ret);
}
function getLoggedOnUserBySessionId(sessionId) {
try {
const result = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine,
("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Authentication\\LogonUI\\SessionData\\" + sessionId), 'LoggedOnUser'
);
if (result) {
return result.replace(/^[^\\]+\\/, '');
}
return null;
} catch (err) {
return null;
}
}
function getLogonCacheKeys() {
var registry = require('win-registry');
var HKLM = registry.HKEY.LocalMachine;
var userObj = [];
function readSubKeys(path) {
var vals = registry.QueryKey(HKLM, path);
if (!vals) return;
// Extract IdentityName, SAMName, SID if they exist
var identityName = null, samName = null, sid = null;
for (var i = 0; i in vals.values; i++) {
if (vals.values[i].toLowerCase() === 'identityname' && identityName === null) {
identityName = registry.QueryKey(HKLM, path, vals.values[i]);
}
if (vals.values[i].toLowerCase() === 'samname' && samName === null) {
samName = registry.QueryKey(HKLM, path, vals.values[i]);
}
if (vals.values[i].toLowerCase() === 'sid' && sid === null) {
sid = registry.QueryKey(HKLM, path, vals.values[i]);
}
}
// If IdentityName exists, add to userObj
if (identityName) {
userObj.push({
UPN: identityName,
SAM: samName,
SID: sid
});
}
// Recurse into subkeys if any
if (vals.subkeys && vals.subkeys.length > 0) {
for (var j = 0; j < vals.subkeys.length; j++) {
readSubKeys(path + '\\' + vals.subkeys[j]);
}
}
}
// Start recursion from the LogonCache root
readSubKeys('SOFTWARE\\Microsoft\\IdentityStore\\LogonCache');
var grouped = {};
function pushUnique(arr, val) {
if (val && arr.indexOf(val) === -1) arr.push(val);
}
// Group by UPN and merge values
for (var i = 0; i < userObj.length; i++) {
var u = userObj[i];
if (!grouped[u.UPN]) grouped[u.UPN] = {UPN: u.UPN, SID: [], SAM: []};
pushUnique(grouped[u.UPN].SID, u.SID);
pushUnique(grouped[u.UPN].SAM, u.SAM);
}
userObj = [];
// Convert grouped object to array
for (var k in grouped) if (grouped.hasOwnProperty(k)) userObj.push(grouped[k]);
return userObj;
}
function getJoinState() {
if (process.platform != 'win32') { return -1; }
var isAzureAD = false;
var isOnPrem = false;
var isHybrid = false;
var isMicrosoft = false;
// 1 Azure AD / Entra ID
try {
const joinInfo = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'SYSTEM\\CurrentControlSet\\Control\\CloudDomainJoin\\JoinInfo');
isAzureAD = Array.isArray(joinInfo.subkeys) && joinInfo.subkeys.length > 0;
} catch (e) {}
// 2 On-prem AD
try {
const tcpip = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters','Domain');
isOnPrem = !!(tcpip !== "" || null);
} catch (e) {}
// 3 Hybrid AD
isHybrid = isAzureAD && isOnPrem;
// 4 Microsoft Account
try {
const userAccounts = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'SOFTWARE\\Microsoft\\IdentityStore\\LogonCache\\D7F9888F-E3FC-49b0-9EA6-A85B5F392A4F');
isMicrosoft = Array.isArray(userAccounts.subkeys) && userAccounts.subkeys.length > 0;
} catch (e) {}
if (isMicrosoft) return 4;
if (isHybrid) return 3;
if (isOnPrem) return 2;
if (isAzureAD) return 1;
return 0;
}
try {
Object.defineProperty(Array.prototype, 'findIndex', {
value: function (func) {
var i = 0;
for (i = 0; i < this.length; ++i) {
if (func(this[i], i, this)) {
return (i);
}
}
return (-1);
}
});
} catch (ex) { }
if (require('MeshAgent').ARCHID == null) {
var id = null;
switch (process.platform) {
case 'win32':
id = require('_GenericMarshal').PointerSize == 4 ? 3 : 4;
break;
case 'freebsd':
id = require('_GenericMarshal').PointerSize == 4 ? 31 : 30;
break;
case 'darwin':
try {
id = require('os').arch() == 'x64' ? 16 : 29;
} catch (ex) { id = 16; }
break;
}
if (id != null) { Object.defineProperty(require('MeshAgent'), 'ARCHID', { value: id }); }
}
function setDefaultCoreTranslation(obj, field, value) {
if (obj[field] == null || obj[field] == '') { obj[field] = value; }
}
function getCoreTranslation() {
var ret = {};
if (global.coretranslations != null) {
try {
var lang = require('util-language').current;
if (coretranslations[lang] == null) { lang = lang.split('-')[0]; }
if (coretranslations[lang] == null) { lang = 'en'; }
if (coretranslations[lang] != null) { ret = coretranslations[lang]; }
}
catch (ex) { }
}
setDefaultCoreTranslation(ret, 'allow', 'Allow');
setDefaultCoreTranslation(ret, 'deny', 'Deny');
setDefaultCoreTranslation(ret, 'autoAllowForFive', 'Auto accept all connections for next 5 minutes');
setDefaultCoreTranslation(ret, 'terminalConsent', '{0} requesting remote terminal access. Grant access?');
setDefaultCoreTranslation(ret, 'desktopConsent', '{0} requesting remote desktop access. Grant access?');
setDefaultCoreTranslation(ret, 'fileConsent', '{0} requesting remote file Access. Grant access?');
setDefaultCoreTranslation(ret, 'terminalNotify', '{0} started a remote terminal session.');
setDefaultCoreTranslation(ret, 'desktopNotify', '{0} started a remote desktop session.');
setDefaultCoreTranslation(ret, 'fileNotify', '{0} started a remote file session.');
setDefaultCoreTranslation(ret, 'privacyBar', 'Sharing desktop with: {0}');
return (ret);
}
var currentTranslation = getCoreTranslation();
try {
require('kvm-helper');
}
catch (e) {
var j =
{
users: function () {
var r = {};
require('user-sessions').Current(function (c) { r = c; });
if (process.platform != 'win32') {
for (var i in r) {
r[i].SessionId = r[i].uid;
}
}
return (r);
}
};
addModuleObject('kvm-helper', j);
}
function lockDesktop(uid) {
switch (process.platform) {
case 'linux':
if (uid != null) {
var name = require('user-sessions').getUsername(uid);
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stderr.str = ''; child.stderr.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('loginctl show-user -p Sessions ' + name + " | awk '{");
child.stdin.write('gsub(/^Sessions=/,"",$0);');
child.stdin.write('cmd = sprintf("loginctl lock-session %s",$0);');
child.stdin.write('system(cmd);');
child.stdin.write("}'\nexit\n");
child.waitExit();
}
else {
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = ''; child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stderr.str = ''; child.stderr.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write('loginctl lock-sessions\nexit\n');
child.waitExit();
}
break;
case 'win32':
{
var options = { type: 1, uid: uid };
var child = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], options);
child.waitExit();
}
break;
default:
break;
}
}
var writable = require('stream').Writable;
function destopLockHelper_pipe(httprequest) {
if (process.platform != 'linux' && process.platform != 'freebsd') { return; }
if (httprequest.unlockerHelper == null && httprequest.desktop != null && httprequest.desktop.kvm != null) {
httprequest.unlockerHelper = new writable(
{
'write': function (chunk, flush) {
if (chunk.readUInt16BE(0) == 65) {
delete this.request.autolock;
}
flush();
return (true);
},
'final': function (flush) {
flush();
}
});
httprequest.unlockerHelper.request = httprequest;
httprequest.desktop.kvm.pipe(httprequest.unlockerHelper);
}
}
var obj = { serverInfo: {} };
var agentFileHttpRequests = {}; // Currently active agent HTTPS GET requests from the server.
var agentFileHttpPendingRequests = []; // Pending HTTPS GET requests from the server.
var debugConsole = (global._MSH && (_MSH().debugConsole == 1));
var color_options =
{
background: (global._MSH != null) ? global._MSH().background : '0,54,105',
foreground: (global._MSH != null) ? global._MSH().foreground : '255,255,255'
};
if (process.platform == 'win32' && require('user-sessions').isRoot()) {
// Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
try {
var writtenSize = 0, actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
var serviceName = (_MSH().serviceName ? _MSH().serviceName : (require('_agentNodeId').serviceName() ? require('_agentNodeId').serviceName() : 'Mesh Agent'));
try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'EstimatedSize'); } catch (ex) { }
if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'EstimatedSize', actualSize); } catch (ex) { } }
} catch (ex) { }
// Check to see if we are the Installed Mesh Agent Service, if we are, make sure we can run in Safe Mode
var svcname = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
try {
svcname = require('MeshAgent').serviceName;
} catch (ex) { }
try {
var meshCheck = false;
try { meshCheck = require('service-manager').manager.getService(svcname).isMe(); } catch (ex) { }
if (meshCheck && require('win-bcd').isSafeModeService && !require('win-bcd').isSafeModeService(svcname)) { require('win-bcd').enableSafeModeService(svcname); }
} catch (ex) { }
// Check the Agent Uninstall MetaData for DisplayVersion and update if not the same and only on windows
if (process.platform == 'win32') {
try {
var writtenDisplayVersion = 0, actualDisplayVersion = process.versions.commitDate.toString();
var serviceName = (_MSH().serviceName ? _MSH().serviceName : (require('_agentNodeId').serviceName() ? require('_agentNodeId').serviceName() : 'Mesh Agent'));
try { writtenDisplayVersion = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'DisplayVersion'); } catch (ex) { }
if (writtenDisplayVersion != actualDisplayVersion) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + serviceName, 'DisplayVersion', actualDisplayVersion); } catch (ex) { } }
} catch (ex) { }
}
}
if (process.platform != 'win32') {
var ch = require('child_process');
ch._execFile = ch.execFile;
ch.execFile = function execFile(path, args, options) {
if (options && options.type && options.type == ch.SpawnTypes.TERM && options.env) {
options.env['TERM'] = 'xterm-256color';
}
return (this._execFile(path, args, options));
};
}
if (process.platform == 'darwin' && !process.versions) {
// This is an older MacOS Agent, so we'll need to check the service definition so that Auto-Update will function correctly
var child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write("cat /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist | tr '\n' '\.' | awk '{split($0, a, \"<key>KeepAlive</key>\"); split(a[2], b, \"<\"); split(b[2], c, \">\"); ");
child.stdin.write(" if(c[1]==\"dict\"){ split(a[2], d, \"</dict>\"); if(split(d[1], truval, \"<true/>\")>1) { split(truval[1], kn1, \"<key>\"); split(kn1[2], kn2, \"</key>\"); print kn2[1]; } }");
child.stdin.write(" else { split(c[1], ka, \"/\"); if(ka[1]==\"true\") {print \"ALWAYS\";} } }'\nexit\n");
child.waitExit();
if (child.stdout.str.trim() == 'Crashed') {
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write("launchctl list | grep 'meshagent' | awk '{ if($3==\"meshagent\"){print $1;}}'\nexit\n");
child.waitExit();
if (parseInt(child.stdout.str.trim()) == process.pid) {
// The currently running MeshAgent is us, so we can continue with the update
var plist = require('fs').readFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist').toString();
var tokens = plist.split('<key>KeepAlive</key>');
if (tokens[1].split('>')[0].split('<')[1] == 'dict') {
var tmp = tokens[1].split('</dict>');
tmp.shift();
tokens[1] = '\n <true/>' + tmp.join('</dict>');
tokens = tokens.join('<key>KeepAlive</key>');
require('fs').writeFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist', tokens);
var fix = '';
fix += ("function macosRepair()\n");
fix += ("{\n");
fix += (" var child = require('child_process').execFile('/bin/sh', ['sh']);\n");
fix += (" child.stdout.str = '';\n");
fix += (" child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });\n");
fix += (" child.stderr.on('data', function (chunk) { });\n");
fix += (" child.stdin.write('launchctl unload /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
fix += (" child.stdin.write('launchctl load /Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist\\n');\n");
fix += (" child.stdin.write('rm /Library/LaunchDaemons/meshagentRepair.plist\\n');\n");
fix += (" child.stdin.write('rm " + process.cwd() + "/macosRepair.js\\n');\n");
fix += (" child.stdin.write('launchctl stop meshagentRepair\\nexit\\n');\n");
fix += (" child.waitExit();\n");
fix += ("}\n");
fix += ("macosRepair();\n");
fix += ("process.exit();\n");
require('fs').writeFileSync(process.cwd() + '/macosRepair.js', fix);
var plist = '<?xml version="1.0" encoding="UTF-8"?>\n';
plist += '<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n';
plist += '<plist version="1.0">\n';
plist += ' <dict>\n';
plist += ' <key>Label</key>\n';
plist += (' <string>meshagentRepair</string>\n');
plist += ' <key>ProgramArguments</key>\n';
plist += ' <array>\n';
plist += (' <string>' + process.execPath + '</string>\n');
plist += ' <string>macosRepair.js</string>\n';
plist += ' </array>\n';
plist += ' <key>WorkingDirectory</key>\n';
plist += (' <string>' + process.cwd() + '</string>\n');
plist += ' <key>RunAtLoad</key>\n';
plist += ' <true/>\n';
plist += ' </dict>\n';
plist += '</plist>';
require('fs').writeFileSync('/Library/LaunchDaemons/meshagentRepair.plist', plist);
child = require('child_process').execFile('/bin/sh', ['sh']);
child.stdout.str = '';
child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
child.stdin.write("launchctl load /Library/LaunchDaemons/meshagentRepair.plist\nexit\n");
child.waitExit();
}
}
}
}
// Add an Intel AMT event to the log
function addAmtEvent(msg) {
if (obj.amtevents == null) { obj.amtevents = []; }
var d = new Date(), e = zeroPad(d.getHours(), 2) + ':' + zeroPad(d.getMinutes(), 2) + ':' + zeroPad(d.getSeconds(), 2) + ', ' + msg;
obj.amtevents.push(e);
if (obj.amtevents.length > 100) { obj.amtevents.splice(0, obj.amtevents.length - 100); }
if (obj.showamtevent) { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: e }); }
}
function zeroPad(num, size) { var s = '000000000' + num; return s.substr(s.length - size); }
function trimResults(val) {
var i, x;
for (i = 0; i < val.length; ++i) {
for (x in val[i]) {
if (x.startsWith('_')) {
delete val[i][x];
} else {
if (val[i][x] == null || val[i][x] == 0) { delete val[i][x]; }
}
}
}
}
// Create Secure IPC for Diagnostic Agent Communications
obj.DAIPC = require('net').createServer();
if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (ex) { } }
obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH, writableAll: true, maxConnections: 5 }); } catch (ex) { }
obj.DAIPC._daipc = [];
obj.DAIPC.on('connection', function (c) {
c._send = function (j) {
var data = JSON.stringify(j);
var packet = Buffer.alloc(data.length + 4);
packet.writeUInt32LE(data.length + 4, 0);
Buffer.from(data).copy(packet, 4);
this.write(packet);
};
this._daipc.push(c);
c.parent = this;
c.on('end', function () { removeRegisteredApp(this); });
c.on('data', function (chunk) {
if (chunk.length < 4) { this.unshift(chunk); return; }
var len = chunk.readUInt32LE(0);
if (len > 8192) { removeRegisteredApp(this); this.end(); return; }
if (chunk.length < len) { this.unshift(chunk); return; }
var data = chunk.slice(4, len);
try { data = JSON.parse(data.toString()); } catch (ex) { }
if ((data == null) || (typeof data.cmd != 'string')) return;
try {
switch (data.cmd) {
case 'requesthelp':
if (this._registered == null) return;
sendConsoleText('Request Help (' + this._registered + '): ' + data.value);
var help = {};
help[this._registered] = data.value;
try { mesh.SendCommand({ action: 'sessions', type: 'help', value: help }); } catch (ex) { }
MeshServerLogEx(98, [this._registered, data.value], "Help Requested, user: " + this._registered + ", details: " + data.value, null);
break;
case 'cancelhelp':
if (this._registered == null) return;
sendConsoleText('Cancel Help (' + this._registered + ')');
try { mesh.SendCommand({ action: 'sessions', type: 'help', value: {} }); } catch (ex) { }
break;
case 'register':
if (typeof data.value == 'string') {
this._registered = data.value;
var apps = {};
apps[data.value] = 1;
try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (ex) { }
this._send({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer, amt: (amt != null) });
}
break;
case 'query':
switch (data.value) {
case 'connection':
data.result = require('MeshAgent').ConnectedServer;
this._send(data);
break;
case 'descriptors':
require('ChainViewer').getSnapshot().then(function (f) {
this.tag.payload.result = f;
this.tag.ipc._send(this.tag.payload);
}).parentPromise.tag = { ipc: this, payload: data };
break;
case 'timerinfo':
data.result = require('ChainViewer').getTimerInfo();
this._send(data);
break;
}
break;
case 'amtstate':
if (amt == null) return;
var func = function amtStateFunc(state) { if (state != null) { amtStateFunc.pipe._send({ cmd: 'amtstate', value: state }); } }
func.pipe = this;
amt.getMeiState(11, func);
break;
case 'sessions':
this._send({ cmd: 'sessions', sessions: tunnelUserCount });
break;
case 'meshToolInfo':
try { mesh.SendCommand({ action: 'meshToolInfo', name: data.name, hash: data.hash, cookie: data.cookie ? true : false, pipe: true }); } catch (ex) { }
break;
case 'getUserImage':
try { mesh.SendCommand({ action: 'getUserImage', userid: data.userid, pipe: true }); } catch (ex) { }
break;
case 'console':
if (debugConsole) {
var args = splitArgs(data.value);
processConsoleCommand(args[0].toLowerCase(), parseArgs(args), 0, 'pipe');
}
break;
}
}
catch (ex) { removeRegisteredApp(this); this.end(); return; }
});
});
// Send current sessions to registered apps
function broadcastSessionsToRegisteredApps(x) {
var p = {}, i;
for (i = 0; sendAgentMessage.messages != null && i < sendAgentMessage.messages.length; ++i) {
p[i] = sendAgentMessage.messages[i];
}
tunnelUserCount.msg = p;
broadcastToRegisteredApps({ cmd: 'sessions', sessions: tunnelUserCount });
tunnelUserCount.msg = {};
}
// Send this object to all registered local applications
function broadcastToRegisteredApps(x) {
if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
for (var i in obj.DAIPC._daipc) {
if (obj.DAIPC._daipc[i]._registered != null) { obj.DAIPC._daipc[i]._send(x); }
}
}
// Send this object to a specific registered local applications
function sendToRegisteredApp(appid, x) {
if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
for (var i in obj.DAIPC._daipc) { if (obj.DAIPC._daipc[i]._registered == appid) { obj.DAIPC._daipc[i]._send(x); } }
}
// Send list of registered apps to the server
function updateRegisteredAppsToServer() {
if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
var apps = {};
for (var i in obj.DAIPC._daipc) { if (apps[obj.DAIPC._daipc[i]._registered] == null) { apps[obj.DAIPC._daipc[i]._registered] = 1; } else { apps[obj.DAIPC._daipc[i]._registered]++; } }
try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (ex) { }
}
// Remove a registered app
function removeRegisteredApp(pipe) {
for (var i = obj.DAIPC._daipc.length - 1; i >= 0; i--) { if (obj.DAIPC._daipc[i] === pipe) { obj.DAIPC._daipc.splice(i, 1); } }
if (pipe._registered != null) updateRegisteredAppsToServer();
}
function diagnosticAgent_uninstall() {
require('service-manager').manager.uninstallService('meshagentDiagnostic');
require('task-scheduler').delete('meshagentDiagnostic/periodicStart'); // TODO: Using "delete" here breaks the minifier since this is a reserved keyword
}
function diagnosticAgent_installCheck(install) {
try {
var diag = require('service-manager').manager.getService('meshagentDiagnostic');
return (diag);
} catch (ex) { }
if (!install) { return null; }
var svc = null;
try {
require('service-manager').manager.installService(
{
name: 'meshagentDiagnostic',
displayName: "Mesh Agent Diagnostic Service",
description: "Mesh Agent Diagnostic Service",
servicePath: process.execPath,
parameters: ['-recovery']
//files: [{ newName: 'diagnostic.js', _buffer: Buffer.from('LyoNCkNvcHlyaWdodCAyMDE5IEludGVsIENvcnBvcmF0aW9uDQoNCkxpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSAiTGljZW5zZSIpOw0KeW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLg0KWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0DQoNCiAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjANCg0KVW5sZXNzIHJlcXVpcmVkIGJ5IGFwcGxpY2FibGUgbGF3IG9yIGFncmVlZCB0byBpbiB3cml0aW5nLCBzb2Z0d2FyZQ0KZGlzdHJpYnV0ZWQgdW5kZXIgdGhlIExpY2Vuc2UgaXMgZGlzdHJpYnV0ZWQgb24gYW4gIkFTIElTIiBCQVNJUywNCldJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLg0KU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZA0KbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuDQoqLw0KDQp2YXIgaG9zdCA9IHJlcXVpcmUoJ3NlcnZpY2UtaG9zdCcpLmNyZWF0ZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpOw0KdmFyIFJlY292ZXJ5QWdlbnQgPSByZXF1aXJlKCdNZXNoQWdlbnQnKTsNCg0KaG9zdC5vbignc2VydmljZVN0YXJ0JywgZnVuY3Rpb24gKCkNCnsNCiAgICBjb25zb2xlLnNldERlc3RpbmF0aW9uKGNvbnNvbGUuRGVzdGluYXRpb25zLkxPR0ZJTEUpOw0KICAgIGhvc3Quc3RvcCA9IGZ1bmN0aW9uKCkNCiAgICB7DQogICAgICAgIHJlcXVpcmUoJ3NlcnZpY2UtbWFuYWdlcicpLm1hbmFnZXIuZ2V0U2VydmljZSgnbWVzaGFnZW50RGlhZ25vc3RpYycpLnN0b3AoKTsNCiAgICB9DQogICAgUmVjb3ZlcnlBZ2VudC5vbignQ29ubmVjdGVkJywgZnVuY3Rpb24gKHN0YXR1cykNCiAgICB7DQogICAgICAgIGlmIChzdGF0dXMgPT0gMCkNCiAgICAgICAgew0KICAgICAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IFNlcnZlciBjb25uZWN0aW9uIGxvc3QuLi4nKTsNCiAgICAgICAgICAgIHJldHVybjsNCiAgICAgICAgfQ0KICAgICAgICBjb25zb2xlLmxvZygnRGlhZ25vc3RpYyBBZ2VudDogQ29ubmVjdGlvbiBFc3RhYmxpc2hlZCB3aXRoIFNlcnZlcicpOw0KICAgICAgICBzdGFydCgpOw0KICAgIH0pOw0KfSk7DQpob3N0Lm9uKCdub3JtYWxTdGFydCcsIGZ1bmN0aW9uICgpDQp7DQogICAgaG9zdC5zdG9wID0gZnVuY3Rpb24gKCkNCiAgICB7DQogICAgICAgIHByb2Nlc3MuZXhpdCgpOw0KICAgIH0NCiAgICBjb25zb2xlLmxvZygnTm9uIFNlcnZpY2UgTW9kZScpOw0KICAgIFJlY292ZXJ5QWdlbnQub24oJ0Nvbm5lY3RlZCcsIGZ1bmN0aW9uIChzdGF0dXMpDQogICAgew0KICAgICAgICBpZiAoc3RhdHVzID09IDApDQogICAgICAgIHsNCiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdEaWFnbm9zdGljIEFnZW50OiBTZXJ2ZXIgY29ubmVjdGlvbiBsb3N0Li4uJyk7DQogICAgICAgICAgICByZXR1cm47DQogICAgICAgIH0NCiAgICAgICAgY29uc29sZS5sb2coJ0RpYWdub3N0aWMgQWdlbnQ6IENvbm5lY3Rpb24gRXN0YWJsaXNoZWQgd2l0aCBTZXJ2ZXInKTsNCiAgICAgICAgc3RhcnQoKTsNCiAgICB9KTsNCn0pOw0KaG9zdC5vbignc2VydmljZVN0b3AnLCBmdW5jdGlvbiAoKSB7IHByb2Nlc3MuZXhpdCgpOyB9KTsNCmhvc3QucnVuKCk7DQoNCg0KZnVuY3Rpb24gc3RhcnQoKQ0Kew0KDQp9Ow0K', 'base64') }]
});
svc = require('service-manager').manager.getService('meshagentDiagnostic');
}
catch (ex) { return null; }
var proxyConfig = require('global-tunnel').proxyConfig;
var cert = require('MeshAgent').GenerateAgentCertificate('CN=MeshNodeDiagnosticCertificate');
var nodeid = require('tls').loadCertificate(cert.root).getKeyHash().toString('base64');
ddb = require('SimpleDataStore').Create(svc.appWorkingDirectory().replace('\\', '/') + '/meshagentDiagnostic.db');
ddb.Put('disableUpdate', '1');
ddb.Put('MeshID', Buffer.from(require('MeshAgent').ServerInfo.MeshID, 'hex'));
ddb.Put('ServerID', require('MeshAgent').ServerInfo.ServerID);
ddb.Put('MeshServer', require('MeshAgent').ServerInfo.ServerUri);
if (cert.root.pfx) { ddb.Put('SelfNodeCert', cert.root.pfx); }
if (cert.tls) { ddb.Put('SelfNodeTlsCert', cert.tls.pfx); }
if (proxyConfig) {
ddb.Put('WebProxy', proxyConfig.host + ':' + proxyConfig.port);
} else {
ddb.Put('ignoreProxyFile', '1');
}
require('MeshAgent').SendCommand({ action: 'diagnostic', value: { command: 'register', value: nodeid } });
require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "Diagnostic Agent Registered [" + nodeid.length + "/" + nodeid + "]" });
delete ddb;
// Set a recurrent task, to run the Diagnostic Agent every 2 days
require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: 2, time: require('tls').generateRandomInteger('0', '23') + ':' + require('tls').generateRandomInteger('0', '59').padStart(2, '0'), service: 'meshagentDiagnostic' });
//require('task-scheduler').create({ name: 'meshagentDiagnostic/periodicStart', daily: '1', time: '17:16', service: 'meshagentDiagnostic' });
return (svc);
}
// Monitor the file 'batterystate.txt' in the agent's folder and sends battery update when this file is changed.
if ((require('fs').existsSync(process.cwd() + 'batterystate.txt')) && (require('fs').watch != null)) {
// Setup manual battery monitoring
require('MeshAgent')._batteryFileWatcher = require('fs').watch(process.cwd(), function () {
if (require('MeshAgent')._batteryFileTimer != null) return;
require('MeshAgent')._batteryFileTimer = setTimeout(function () {
try {
require('MeshAgent')._batteryFileTimer = null;
var data = null;
try { data = require('fs').readFileSync(process.cwd() + 'batterystate.txt').toString(); } catch (ex) { }
if ((data != null) && (data.length < 10)) {
data = data.split(',');
if ((data.length == 2) && ((data[0] == 'ac') || (data[0] == 'dc'))) {
var level = parseInt(data[1]);
if ((level >= 0) && (level <= 100)) { require('MeshAgent').SendCommand({ action: 'battery', state: data[0], level: level }); }
}
}
} catch (ex) { }
}, 1000);
});
}
else {
try {
// Setup normal battery monitoring
if (require('computer-identifiers').isBatteryPowered && require('computer-identifiers').isBatteryPowered()) {
require('MeshAgent')._battLevelChanged = function _battLevelChanged(val) {
_battLevelChanged.self._currentBatteryLevel = val;
_battLevelChanged.self.SendCommand({ action: 'battery', state: _battLevelChanged.self._currentPowerState, level: val });
};
require('MeshAgent')._battLevelChanged.self = require('MeshAgent');
require('MeshAgent')._powerChanged = function _powerChanged(val) {
_powerChanged.self._currentPowerState = (val == 'AC' ? 'ac' : 'dc');
_powerChanged.self.SendCommand({ action: 'battery', state: (val == 'AC' ? 'ac' : 'dc'), level: _powerChanged.self._currentBatteryLevel });
};
require('MeshAgent')._powerChanged.self = require('MeshAgent');
require('MeshAgent').on('Connected', function (status) {
if (status == 0) {
require('power-monitor').removeListener('acdc', this._powerChanged);
require('power-monitor').removeListener('batteryLevel', this._battLevelChanged);
} else {
require('power-monitor').on('acdc', this._powerChanged);
require('power-monitor').on('batteryLevel', this._battLevelChanged);
}
});
}
}
catch (ex) { }
}
// MeshAgent JavaScript Core Module. This code is sent to and running on the mesh agent.
var meshCoreObj = { action: 'coreinfo', value: (require('MeshAgent').coreHash ? ((process.versions.compileTime ? process.versions.compileTime : '').split(', ')[1].replace(' ', ' ') + ', ' + crc32c(require('MeshAgent').coreHash)) : ('MeshCore v6')), caps: 14, root: require('user-sessions').isRoot() }; // Capability bitmask: 1 = Desktop, 2 = Terminal, 4 = Files, 8 = Console, 16 = JavaScript, 32 = Temporary Agent, 64 = Recovery Agent
// Get the operating system description string
try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; meshCoreObjChanged(); }); } catch (ex) { }
// Setup logged in user monitoring (THIS IS BROKEN IN WIN7)
function onUserSessionChanged(user, locked) {
userSession.enumerateUsers().then(function (users) {
if (process.platform == 'linux') {
if (userSession._startTime == null) {
userSession._startTime = Date.now();
userSession._count = users.length;
}
else if (Date.now() - userSession._startTime < 10000 && users.length == userSession._count) {
userSession.removeAllListeners('changed');
return;
}
}
var u = [], a = users.Active;
if(meshCoreObj.lusers == null) { meshCoreObj.lusers = []; }
if(meshCoreObj.upnusers == null) { meshCoreObj.upnusers = []; }
var ret = getDomainInfo();
for (var i = 0; i < a.length; i++) {
var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username);
if (user && locked && (JSON.stringify(a[i]) === JSON.stringify(user))) { if (meshCoreObj.lusers.indexOf(un) == -1) { meshCoreObj.lusers.push(un); } }
else if (user && !locked && (JSON.stringify(a[i]) === JSON.stringify(user))) { meshCoreObj.lusers.splice(meshCoreObj.lusers.indexOf(un), 1); }
if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once.
if ((a[i].Domain != null && a[i].Domain == 'AzureAD') || getJoinState() == 1 ){
var userobj = getLogonCacheKeys();
if(userobj && userobj.length > 0){
for (var j = 0; j < userobj.length; j++) {
if (userobj[j] && userobj[j].SAM && userobj[j].SAM[0].trim() === a[i].Username) {
meshCoreObj.upnusers.push(userobj[j].UPN);
break;
}
}
}
} else if (a[i].Domain != null) {
if (ret != null && ret.PartOfDomain === true) {
var loggedOnUser = getLoggedOnUserBySessionId(a[i].SessionId);
if(loggedOnUser == null || (/^[^@]+@[^@]+\.[^@]+$/.test(loggedOnUser) == false)){
loggedOnUser = a[i].Username + '@' + ret.Domain;
}
meshCoreObj.upnusers.push(loggedOnUser);
} else if (getJoinState() == 4) { // One account with Microsoft Account
var userobj = getLogonCacheKeys();
if(userobj && userobj.length > 0){
for (var j = 0; j < userobj.length; j++) {
if (userobj[j] && userobj[j].SAM && userobj[j].SAM.length == 0 && userobj[j].UPN && userobj[j].UPN != '') {
meshCoreObj.upnusers.push(userobj[j].UPN);
break;
}
}
}
}
}
}
meshCoreObj.lusers = meshCoreObj.lusers;
meshCoreObj.users = u;
meshCoreObjChanged();
});
}
try {
var userSession = require('user-sessions');
userSession.on('changed', function () { onUserSessionChanged(null, false); });
userSession.emit('changed');
userSession.on('locked', function (user) { if(user != undefined && user != null) { onUserSessionChanged(user, true); } });
userSession.on('unlocked', function (user) { if(user != undefined && user != null) { onUserSessionChanged(user, false); } });
} catch (ex) { }
var meshServerConnectionState = 0;
var tunnels = {};
var lastNetworkInfo = null;
var lastPublicLocationInfo = null;
var selfInfoUpdateTimer = null;
var http = require('http');
var net = require('net');
var fs = require('fs');
var rtc = require('ILibWebRTC');
var amt = null;
var processManager = require('process-manager');
var wifiScannerLib = null;
var wifiScanner = null;
var networkMonitor = null;
var nextTunnelIndex = 1;
var apftunnel = null;
var tunnelUserCount = { terminal: {}, files: {}, tcp: {}, udp: {}, msg: {} }; // List of userid->count sessions for terminal, files and TCP/UDP routing
// Add to the server event log
function MeshServerLog(msg, state) {
if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
if (state) {
if (state.userid) { msg.userid = state.userid; }
if (state.username) { msg.username = state.username; }
if (state.sessionid) { msg.sessionid = state.sessionid; }
if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
if (state.guestname) { msg.guestname = state.guestname; }
}
mesh.SendCommand(msg);
}
// Add to the server event log, use internationalized events
function MeshServerLogEx(id, args, msg, state) {
var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
if (state) {
if (state.userid) { msg.userid = state.userid; }
if (state.xuserid) { msg.xuserid = state.xuserid; }
if (state.username) { msg.username = state.username; }
if (state.sessionid) { msg.sessionid = state.sessionid; }
if (state.remoteaddr) { msg.remoteaddr = state.remoteaddr; }
if (state.guestname) { msg.guestname = state.guestname; }
}
mesh.SendCommand(msg);
}
// Import libraries
db = require('SimpleDataStore').Shared();
sha = require('SHA256Stream');
mesh = require('MeshAgent');
childProcess = require('child_process');
if (mesh.hasKVM == 1) { // if the agent is compiled with KVM support
// Check if this computer supports a desktop
try {
if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support)) {
meshCoreObj.caps |= 1; meshCoreObjChanged();
} else if (process.platform == 'linux' || process.platform == 'freebsd') {
require('monitor-info').on('kvmSupportDetected', function (value) { meshCoreObj.caps |= 1; meshCoreObjChanged(); });
}
} catch (ex) { }
}
mesh.DAIPC = obj.DAIPC;
/*
// Try to load up the network monitor
try {
networkMonitor = require('NetworkMonitor');
networkMonitor.on('change', function () { sendNetworkUpdateNagle(); });
networkMonitor.on('add', function (addr) { sendNetworkUpdateNagle(); });
networkMonitor.on('remove', function (addr) { sendNetworkUpdateNagle(); });
} catch (ex) { networkMonitor = null; }
*/
// Fetch the SMBios Tables
var SMBiosTables = null;
var SMBiosTablesRaw = null;
try {
var SMBiosModule = null;
try { SMBiosModule = require('smbios'); } catch (ex) { }
if (SMBiosModule != null) {
SMBiosModule.get(function (data) {
if (data != null) {
SMBiosTablesRaw = data;
SMBiosTables = require('smbios').parse(data)
if (mesh.isControlChannelConnected) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
// If SMBios tables say that Intel AMT is present, try to connect MEI
if (SMBiosTables.amtInfo && (SMBiosTables.amtInfo.AMT == true)) {
var amtmodule = require('amt-manage');
amt = new amtmodule(mesh, db, false);
amt.on('portBinding_LMS', function (map) { mesh.SendCommand({ action: 'lmsinfo', value: { ports: map.keys() } }); });
amt.on('stateChange_LMS', function (v) { if (!meshCoreObj.intelamt) { meshCoreObj.intelamt = {}; } meshCoreObj.intelamt.microlms = v; meshCoreObjChanged(); }); // 0 = Disabled, 1 = Connecting, 2 = Connected
amt.onStateChange = function (state) { if (state == 2) { sendPeriodicServerUpdate(1); } } // MEI State
amt.reset();
}
}
});
}
} catch (ex) { sendConsoleText("ex1: " + ex); }
// Try to load up the WIFI scanner
try {
var wifiScannerLib = require('wifi-scanner');
wifiScanner = new wifiScannerLib();
wifiScanner.on('accessPoint', function (data) { sendConsoleText("wifiScanner: " + data); });
} catch (ex) { wifiScannerLib = null; wifiScanner = null; }
// Get our location (lat/long) using our public IP address
var getIpLocationDataExInProgress = false;
var getIpLocationDataExCounts = [0, 0];
function getIpLocationDataEx(func) {
if (getIpLocationDataExInProgress == true) { return false; }
getIpLocationDataExInProgress = true;
getIpLocationDataExCounts[0]++;
function tryEndpoint(url, fallback) {
var options = http.parseUri(url);
options.method = 'GET';
http.request(options, function (resp) {
var geoData = '';
resp.data = function (chunk) { geoData += chunk; };
resp.end = function () {
try {
var result = JSON.parse(geoData);
if (result.ip && result.loc) {
getIpLocationDataExInProgress = false;
getIpLocationDataExCounts[1]++;
func(result);
return;
}
} catch (ex) { }
if (fallback) { fallback(); } else { done(null); }
};
if (resp.statusCode != 200) { if (fallback) { fallback(); } else { done(null); } }
}).on('error', function () {
if (fallback) { fallback(); } else { done(null); }
}).end();
}
function done(result) {
getIpLocationDataExInProgress = false;
if (func) { func(result); }
}
tryEndpoint('http://v6.ipinfo.io/json', function () {
tryEndpoint('http://ipinfo.io/json', null);
});
return true;
}
// Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
funct