Updated Windows agents, meshcore we better pipe support.

This commit is contained in:
Ylian Saint-Hilaire 2020-10-11 22:24:30 -07:00
parent fe2496e75b
commit 80980f7089
8 changed files with 259 additions and 3915 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -138,7 +138,8 @@ function createMeshCore(agent) {
obj.DAIPC = require('net').createServer(); obj.DAIPC = require('net').createServer();
if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (e) { } } if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd() + '/DAIPC'); } catch (e) { } }
obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC'); obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH, writableAll: true }); } catch (e) { } try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH, writableAll: true, maxConnections: 5 }); } catch (e) { }
obj.DAIPC._daipc = [];
obj.DAIPC.on('connection', function (c) { obj.DAIPC.on('connection', function (c) {
c._send = function (j) { c._send = function (j) {
var data = JSON.stringify(j); var data = JSON.stringify(j);
@ -147,17 +148,13 @@ function createMeshCore(agent) {
Buffer.from(data).copy(packet, 4); Buffer.from(data).copy(packet, 4);
this.write(packet); this.write(packet);
}; };
this._daipc = c; this._daipc.push(c);
c.parent = this; c.parent = this;
c.on('end', function () { c.on('end', function () { removeRegisteredApp(this); });
this.end(); // TODO: Must call end() on self to close the named pipe correctly.
this.parent._daipc = null;
if (this._registered != null) { try { mesh.SendCommand({ action: 'sessions', type: 'app', value: {} }); } catch (e) { } }
});
c.on('data', function (chunk) { c.on('data', function (chunk) {
if (chunk.length < 4) { this.unshift(chunk); return; } if (chunk.length < 4) { this.unshift(chunk); return; }
var len = chunk.readUInt32LE(0); var len = chunk.readUInt32LE(0);
if (len > 8192) { this.parent._daipc = null; this.end(); return; } if (len > 8192) { removeRegisteredApp(this); this.end(); return; }
if (chunk.length < len) { this.unshift(chunk); return; } if (chunk.length < len) { this.unshift(chunk); return; }
var data = chunk.slice(4, len); var data = chunk.slice(4, len);
@ -195,18 +192,48 @@ function createMeshCore(agent) {
this._send(data); this._send(data);
break; break;
case 'descriptors': case 'descriptors':
require('ChainViewer').getSnapshot().then(function (f) { require('ChainViewer').getSnapshot().then(function (f)
{
this.tag.payload.result = f; this.tag.payload.result = f;
this.tag.ipc._send(this.tag.payload); this.tag.ipc._send(this.tag.payload);
}).parentPromise.tag = { ipc: this, payload: data }; }).parentPromise.tag = { ipc: this, payload: data };
break; break;
} }
break; break;
case 'sessions':
this._send({ cmd: 'sessions', sessions: tunnelUserCount });
break;
} }
} }
catch (e) { this.parent._daipc = null; this.end(); return; } catch (e) { removeRegisteredApp(this); this.end(); return; }
}); });
}); });
// Send current sessions to registered apps
function broadcastSessionsToRegisteredApps(x) {
broadcastToRegisteredApps({ cmd: 'sessions', sessions: tunnelUserCount });
}
// 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 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 (e) { }
}
// 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() { function diagnosticAgent_uninstall() {
require('service-manager').manager.uninstallService('meshagentDiagnostic'); require('service-manager').manager.uninstallService('meshagentDiagnostic');
require('task-scheduler').delete('meshagentDiagnostic/periodicStart'); require('task-scheduler').delete('meshagentDiagnostic/periodicStart');
@ -405,12 +432,16 @@ function createMeshCore(agent) {
childProcess = require('child_process'); childProcess = require('child_process');
if (mesh.hasKVM == 1) { // if the agent is compiled with KVM support if (mesh.hasKVM == 1) { // if the agent is compiled with KVM support
// Check if this computer supports a desktop // Check if this computer supports a desktop
try { try
if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support)) { {
if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support))
{
meshCoreObj.caps |= 1; meshCoreObj.caps |= 1;
} }
else if (process.platform == 'linux' || process.platform == 'freebsd') { else if(process.platform == 'linux' || process.platform == 'freebsd')
require('monitor-info').on('kvmSupportDetected', function (value) { {
require('monitor-info').on('kvmSupportDetected', function (value)
{
meshCoreObj.caps |= 1; meshCoreObj.caps |= 1;
mesh.SendCommand(meshCoreObj); mesh.SendCommand(meshCoreObj);
}); });
@ -473,16 +504,20 @@ function createMeshCore(agent) {
if (mesh.isControlChannelConnected) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); } if (mesh.isControlChannelConnected) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
// If SMBios tables say that Intel AMT is present, try to connect MEI // If SMBios tables say that Intel AMT is present, try to connect MEI
if (SMBiosTables.amtInfo && (SMBiosTables.amtInfo.AMT == true)) { if (SMBiosTables.amtInfo && (SMBiosTables.amtInfo.AMT == true))
{
var amtmodule = require('amt-manage'); var amtmodule = require('amt-manage');
amt = new amtmodule(mesh, db, false); amt = new amtmodule(mesh, db, false);
amt.on('portBinding_LMS', function (map) { amt.on('portBinding_LMS', function (map)
{
var j = { action: 'lmsinfo', value: { ports: map.keys() } }; var j = { action: 'lmsinfo', value: { ports: map.keys() } };
mesh.SendCommand(j); mesh.SendCommand(j);
}); });
amt.on('stateChange_LMS', function (v) { amt.on('stateChange_LMS', function (v)
{
if (!meshCoreObj.intelamt) { meshCoreObj.intelamt = {}; } if (!meshCoreObj.intelamt) { meshCoreObj.intelamt = {}; }
switch (v) { switch(v)
{
case 0: case 0:
meshCoreObj.intelamt.microlms = 'DISABLED'; meshCoreObj.intelamt.microlms = 'DISABLED';
break; break;
@ -1189,9 +1224,11 @@ function createMeshCore(agent) {
s.tunnel = this; s.tunnel = this;
s.descriptorMetadata = "MeshAgent_relayTunnel"; s.descriptorMetadata = "MeshAgent_relayTunnel";
if (require('MeshAgent').idleTimeout != null) { if (require('MeshAgent').idleTimeout != null)
{
s.setTimeout(require('MeshAgent').idleTimeout * 1000); s.setTimeout(require('MeshAgent').idleTimeout * 1000);
s.on('timeout', function () { s.on('timeout', function ()
{
this.ping(); this.ping();
this.setTimeout(require('MeshAgent').idleTimeout * 1000); this.setTimeout(require('MeshAgent').idleTimeout * 1000);
}); });
@ -1212,6 +1249,7 @@ function createMeshCore(agent) {
if (s.httprequest.userid != null) { if (s.httprequest.userid != null) {
if (tunnelUserCount.tcp[s.httprequest.userid] == null) { tunnelUserCount.tcp[s.httprequest.userid] = 1; } else { tunnelUserCount.tcp[s.httprequest.userid]++; } if (tunnelUserCount.tcp[s.httprequest.userid] == null) { tunnelUserCount.tcp[s.httprequest.userid] = 1; } else { tunnelUserCount.tcp[s.httprequest.userid]++; }
try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
broadcastSessionsToRegisteredApps();
} }
} if (this.udpport != null) { } if (this.udpport != null) {
// This is a UDP relay connection, get the UDP socket setup. // TODO: *************** // This is a UDP relay connection, get the UDP socket setup. // TODO: ***************
@ -1228,6 +1266,7 @@ function createMeshCore(agent) {
if (s.httprequest.userid != null) { if (s.httprequest.userid != null) {
if (tunnelUserCount.udp[s.httprequest.userid] == null) { tunnelUserCount.udp[s.httprequest.userid] = 1; } else { tunnelUserCount.udp[s.httprequest.userid]++; } if (tunnelUserCount.udp[s.httprequest.userid] == null) { tunnelUserCount.udp[s.httprequest.userid] = 1; } else { tunnelUserCount.udp[s.httprequest.userid]++; }
try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.tcp }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.tcp }); } catch (e) { }
broadcastSessionsToRegisteredApps();
} }
} else { } else {
// This is a normal connect for KVM/Terminal/Files // This is a normal connect for KVM/Terminal/Files
@ -1275,9 +1314,11 @@ function createMeshCore(agent) {
if (this.httprequest.tcpport != null) { if (this.httprequest.tcpport != null) {
if (tunnelUserCount.tcp[this.httprequest.userid] != null) { tunnelUserCount.tcp[this.httprequest.userid]--; if (tunnelUserCount.tcp[this.httprequest.userid] <= 0) { delete tunnelUserCount.tcp[this.httprequest.userid]; } } if (tunnelUserCount.tcp[this.httprequest.userid] != null) { tunnelUserCount.tcp[this.httprequest.userid]--; if (tunnelUserCount.tcp[this.httprequest.userid] <= 0) { delete tunnelUserCount.tcp[this.httprequest.userid]; } }
try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
broadcastSessionsToRegisteredApps();
} else if (this.httprequest.udpport != null) { } else if (this.httprequest.udpport != null) {
if (tunnelUserCount.udp[this.httprequest.userid] != null) { tunnelUserCount.udp[this.httprequest.userid]--; if (tunnelUserCount.udp[this.httprequest.userid] <= 0) { delete tunnelUserCount.udp[this.httprequest.userid]; } } if (tunnelUserCount.udp[this.httprequest.userid] != null) { tunnelUserCount.udp[this.httprequest.userid]--; if (tunnelUserCount.udp[this.httprequest.userid] <= 0) { delete tunnelUserCount.udp[this.httprequest.userid]; } }
try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.udp }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.udp }); } catch (e) { }
broadcastSessionsToRegisteredApps();
} }
} }
@ -1351,7 +1392,8 @@ function createMeshCore(agent) {
// Check if this is a relay connection // Check if this is a relay connection
if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ } if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
} }
else { else
{
// Handle tunnel data // Handle tunnel data
if (this.httprequest.protocol == 0) { // 1 = Terminal (admin), 2 = Desktop, 5 = Files, 6 = PowerShell (admin), 7 = Plugin Data Exchange, 8 = Terminal (user), 9 = PowerShell (user), 10 = FileTransfer if (this.httprequest.protocol == 0) { // 1 = Terminal (admin), 2 = Desktop, 5 = Files, 6 = PowerShell (admin), 7 = Plugin Data Exchange, 8 = Terminal (user), 9 = PowerShell (user), 10 = FileTransfer
// Take a look at the protocol // Take a look at the protocol
@ -1376,7 +1418,8 @@ function createMeshCore(agent) {
this.write(JSON.stringify({ op: 'cancel' })); this.write(JSON.stringify({ op: 'cancel' }));
} }
} }
else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9)) { else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9))
{
// //
// Remote Terminal // Remote Terminal
// //
@ -1392,8 +1435,10 @@ function createMeshCore(agent) {
this.descriptorMetadata = "Remote Terminal"; this.descriptorMetadata = "Remote Terminal";
if (process.platform == 'win32') { if (process.platform == 'win32')
if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9)) { {
if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9))
{
this.httprequest.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'PowerShell is not supported on this version of windows', msgid: 1 })); this.httprequest.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'PowerShell is not supported on this version of windows', msgid: 1 }));
this.httprequest.s.end(); this.httprequest.s.end();
return; return;
@ -1405,23 +1450,28 @@ function createMeshCore(agent) {
this.httprequest.tpromise.that = this; this.httprequest.tpromise.that = this;
this.httprequest.tpromise.httprequest = this.httprequest; this.httprequest.tpromise.httprequest = this.httprequest;
this.end = function () { this.end = function ()
{
if (this.httprequest.tpromise._consent) { this.httprequest.tpromise._consent.close(); } if (this.httprequest.tpromise._consent) { this.httprequest.tpromise._consent.close(); }
if (this.httprequest.connectionPromise) { this.httprequest.connectionPromise._rej('Closed'); } if (this.httprequest.connectionPromise) { this.httprequest.connectionPromise._rej('Closed'); }
// Remove the terminal session to the count to update the server // Remove the terminal session to the count to update the server
if (this.httprequest.userid != null) { if (this.httprequest.userid != null)
{
if (tunnelUserCount.terminal[this.httprequest.userid] != null) { tunnelUserCount.terminal[this.httprequest.userid]--; if (tunnelUserCount.terminal[this.httprequest.userid] <= 0) { delete tunnelUserCount.terminal[this.httprequest.userid]; } } if (tunnelUserCount.terminal[this.httprequest.userid] != null) { tunnelUserCount.terminal[this.httprequest.userid]--; if (tunnelUserCount.terminal[this.httprequest.userid] <= 0) { delete tunnelUserCount.terminal[this.httprequest.userid]; } }
try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
broadcastSessionsToRegisteredApps();
} }
if (process.platform == 'win32') { if (process.platform == 'win32')
{
// Unpipe the web socket // Unpipe the web socket
this.unpipe(this.httprequest._term); this.unpipe(this.httprequest._term);
if (this.httprequest._term) { this.httprequest._term.unpipe(this); } if (this.httprequest._term) { this.httprequest._term.unpipe(this); }
// Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends). // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
if (this.rtcchannel) { if (this.rtcchannel)
{
this.rtcchannel.unpipe(this.httprequest._term); this.rtcchannel.unpipe(this.httprequest._term);
if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); } if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); }
} }
@ -1433,7 +1483,8 @@ function createMeshCore(agent) {
}; };
// Perform User-Consent if needed. // Perform User-Consent if needed.
if (this.httprequest.consent && (this.httprequest.consent & 16)) { if (this.httprequest.consent && (this.httprequest.consent & 16))
{
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 })); this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
var consentMessage = this.httprequest.username + " requesting remote terminal access. Grant access?", consentTitle = 'MeshCentral'; var consentMessage = this.httprequest.username + " requesting remote terminal access. Grant access?", consentTitle = 'MeshCentral';
if (this.httprequest.soptions != null) { if (this.httprequest.soptions != null) {
@ -1443,85 +1494,106 @@ function createMeshCore(agent) {
this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, 30); this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, 30);
this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise; this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise;
this.httprequest.tpromise._consent.then( this.httprequest.tpromise._consent.then(
function () { function ()
{
// Success // Success
MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest); MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 })); this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
this.retPromise._consent = null; this.retPromise._consent = null;
this.retPromise._res(); this.retPromise._res();
}, },
function (e) { function (e)
{
// Denied // Denied
MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest); MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 })); this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
this.retPromise._rej(e.toString()); this.retPromise._rej(e.toString());
}); });
} }
else { else
{
// User-Consent is not required, so just resolve this promise // User-Consent is not required, so just resolve this promise
this.httprequest.tpromise._res(); this.httprequest.tpromise._res();
} }
this.httprequest.tpromise.then( this.httprequest.tpromise.then(
function () { function ()
{
this.httprequest.connectionPromise = new prom(function (res, rej) { this._res = res; this._rej = rej; }); this.httprequest.connectionPromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
this.httprequest.connectionPromise.ws = this.that; this.httprequest.connectionPromise.ws = this.that;
// Start Terminal // Start Terminal
if (process.platform == 'win32') { if(process.platform == 'win32')
try { {
try
{
var cols = 80, rows = 25; var cols = 80, rows = 25;
if (this.httprequest.xoptions) { if (this.httprequest.xoptions)
{
if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; } if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; }
if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; } if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; }
} }
if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6)) { if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6))
{
// Admin Terminal // Admin Terminal
if (require('win-virtual-terminal').supported) { if (require('win-virtual-terminal').supported)
{
// ConPTY PseudoTerminal // ConPTY PseudoTerminal
// this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25); // this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25);
// The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround
this.httprequest._dispatcher = require('win-dispatcher').dispatch({ modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } }); this.httprequest._dispatcher = require('win-dispatcher').dispatch({ modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
this.httprequest._dispatcher.httprequest = this.httprequest; this.httprequest._dispatcher.httprequest = this.httprequest;
this.httprequest._dispatcher.on('connection', function (c) { this.httprequest._dispatcher.on('connection', function (c)
if (this.httprequest.connectionPromise.completed) { {
if (this.httprequest.connectionPromise.completed)
{
c.end(); c.end();
} }
else { else
{
this.httprequest.connectionPromise._res(c); this.httprequest.connectionPromise._res(c);
} }
}); });
} }
else { else
{
// Legacy Terminal // Legacy Terminal
this.httprequest.connectionPromise._res(require('win-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](cols, rows)); this.httprequest.connectionPromise._res(require('win-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](cols, rows));
} }
} }
else { else
{
// Logged in user // Logged in user
var userPromise = require('user-sessions').enumerateUsers(); var userPromise = require('user-sessions').enumerateUsers();
userPromise.that = this; userPromise.that = this;
userPromise.then(function (u) { userPromise.then(function (u)
{
var that = this.that; var that = this.that;
if (u.Active.length > 0) { if (u.Active.length > 0)
{
var username = u.Active[0].Username; var username = u.Active[0].Username;
if (require('win-virtual-terminal').supported) { if (require('win-virtual-terminal').supported)
{
// ConPTY PseudoTerminal // ConPTY PseudoTerminal
that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } }); that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
} }
else { else
{
// Legacy Terminal // Legacy Terminal
that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-terminal', script: getJSModule('win-terminal') }], launch: { module: 'win-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } }); that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-terminal', script: getJSModule('win-terminal') }], launch: { module: 'win-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
} }
that.httprequest._dispatcher.ws = that; that.httprequest._dispatcher.ws = that;
that.httprequest._dispatcher.on('connection', function (c) { that.httprequest._dispatcher.on('connection', function (c)
if (this.ws.httprequest.connectionPromise.completed) { {
if (this.ws.httprequest.connectionPromise.completed)
{
c.end(); c.end();
} }
else { else
{
this.ws.httprequest.connectionPromise._res(c); this.ws.httprequest.connectionPromise._res(c);
} }
}); });
@ -1529,58 +1601,70 @@ function createMeshCore(agent) {
}); });
} }
} }
catch (e) { catch (e)
{
this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString()); this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
} }
} }
else { else
try { {
try
{
var bash = fs.existsSync('/bin/bash') ? '/bin/bash' : false; var bash = fs.existsSync('/bin/bash') ? '/bin/bash' : false;
var sh = fs.existsSync('/bin/sh') ? '/bin/sh' : false; var sh = fs.existsSync('/bin/sh') ? '/bin/sh' : false;
var login = process.platform == 'linux' ? '/bin/login' : '/usr/bin/login'; var login = process.platform == 'linux' ? '/bin/login' : '/usr/bin/login';
var env = { HISTCONTROL: 'ignoreboth' }; var env = { HISTCONTROL: 'ignoreboth' };
if (this.httprequest.xoptions) { if (this.httprequest.xoptions)
{
if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); } if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); } if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
} }
var options = { type: childProcess.SpawnTypes.TERM, uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env }; var options = { type: childProcess.SpawnTypes.TERM, uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env };
if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin) { if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin)
{
if (!require('fs').existsSync(login)) { throw ('Unable to spawn login process'); } if (!require('fs').existsSync(login)) { throw ('Unable to spawn login process'); }
this.httprequest.connectionPromise._res(childProcess.execFile(login, ['login'], options)); // Start login shell this.httprequest.connectionPromise._res(childProcess.execFile(login, ['login'], options)); // Start login shell
} }
else if (bash) { else if (bash)
{
var p = childProcess.execFile(bash, ['bash'], options); // Start bash var p = childProcess.execFile(bash, ['bash'], options); // Start bash
// Spaces at the beginning of lines are needed to hide commands from the command history // Spaces at the beginning of lines are needed to hide commands from the command history
if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); } if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
this.httprequest.connectionPromise._res(p); this.httprequest.connectionPromise._res(p);
} }
else if (sh) { else if (sh)
{
var p = childProcess.execFile(sh, ['sh'], options); // Start sh var p = childProcess.execFile(sh, ['sh'], options); // Start sh
// Spaces at the beginning of lines are needed to hide commands from the command history // Spaces at the beginning of lines are needed to hide commands from the command history
if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); } if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
this.httprequest.connectionPromise._res(p); this.httprequest.connectionPromise._res(p);
} }
else { else
{
this.httprequest.connectionPromise._rej('Failed to start remote terminal session, no shell found'); this.httprequest.connectionPromise._rej('Failed to start remote terminal session, no shell found');
} }
} }
catch (e) { catch (e)
{
this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString()); this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
} }
} }
this.httprequest.connectionPromise.then( this.httprequest.connectionPromise.then(
function (term) { function (term)
{
// SUCCESS // SUCCESS
var stdoutstream; var stdoutstream;
var stdinstream; var stdinstream;
if (process.platform == 'win32') { if (process.platform == 'win32')
{
this.ws.httprequest._term = term; this.ws.httprequest._term = term;
this.ws.httprequest._term.tunnel = this.ws; this.ws.httprequest._term.tunnel = this.ws;
stdoutstream = stdinstream = term; stdoutstream = stdinstream = term;
} }
else { else
{
term.descriptorMetadata = 'Remote Terminal'; term.descriptorMetadata = 'Remote Terminal';
this.ws.httprequest.process = term; this.ws.httprequest.process = term;
this.ws.httprequest.process.tunnel = this.ws; this.ws.httprequest.process.tunnel = this.ws;
@ -1599,13 +1683,16 @@ function createMeshCore(agent) {
this.ws.pipe(stdinstream, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text. this.ws.pipe(stdinstream, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
// Add the terminal session to the count to update the server // Add the terminal session to the count to update the server
if (this.ws.httprequest.userid != null) { if (this.ws.httprequest.userid != null)
{
if (tunnelUserCount.terminal[this.ws.httprequest.userid] == null) { tunnelUserCount.terminal[this.ws.httprequest.userid] = 1; } else { tunnelUserCount.terminal[this.ws.httprequest.userid]++; } if (tunnelUserCount.terminal[this.ws.httprequest.userid] == null) { tunnelUserCount.terminal[this.ws.httprequest.userid] = 1; } else { tunnelUserCount.terminal[this.ws.httprequest.userid]++; }
try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
broadcastSessionsToRegisteredApps();
} }
// Toast Notification, if required // Toast Notification, if required
if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2)) { if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2))
{
// User Notifications is required // User Notifications is required
var notifyMessage = this.ws.httprequest.username + " started a remote terminal session.", notifyTitle = "MeshCentral"; var notifyMessage = this.ws.httprequest.username + " started a remote terminal session.", notifyTitle = "MeshCentral";
if (this.ws.httprequest.soptions != null) { if (this.ws.httprequest.soptions != null) {
@ -1615,19 +1702,22 @@ function createMeshCore(agent) {
try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { } try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
} }
}, },
function (e) { function (e)
{
// FAILED to connect terminal // FAILED to connect terminal
this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 })); this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
this.ws.end(); this.ws.end();
}); });
}, },
function (e) { function (e)
{
// DO NOT start terminal // DO NOT start terminal
this.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 })); this.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
this.that.end(); this.that.end();
}); });
} }
else if (this.httprequest.protocol == 2) { else if (this.httprequest.protocol == 2)
{
// //
// Remote KVM // Remote KVM
// //
@ -1662,7 +1752,9 @@ function createMeshCore(agent) {
if (this.httprequest.desktop.kvm.tunnels != null) { if (this.httprequest.desktop.kvm.tunnels != null) {
for (var i in this.httprequest.desktop.kvm.tunnels) { try { var userid = this.httprequest.desktop.kvm.tunnels[i].httprequest.userid; if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; } } catch (e) { } } for (var i in this.httprequest.desktop.kvm.tunnels) { try { var userid = this.httprequest.desktop.kvm.tunnels[i].httprequest.userid; if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; } } catch (e) { } }
for (var i in this.httprequest.desktop.kvm.tunnels) { try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { } } for (var i in this.httprequest.desktop.kvm.tunnels) { try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { } }
tunnelUserCount.desktop = users;
try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { }
broadcastSessionsToRegisteredApps();
} }
this.end = function () { this.end = function () {
@ -1677,23 +1769,28 @@ function createMeshCore(agent) {
if (this.httprequest.desktop.kvm.tunnels != null) { if (this.httprequest.desktop.kvm.tunnels != null) {
for (var i in this.httprequest.desktop.kvm.tunnels) { try { var userid = this.httprequest.desktop.kvm.tunnels[i].httprequest.userid; if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; } } catch (e) { } } for (var i in this.httprequest.desktop.kvm.tunnels) { try { var userid = this.httprequest.desktop.kvm.tunnels[i].httprequest.userid; if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; } } catch (e) { } }
for (var i in this.httprequest.desktop.kvm.tunnels) { try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { } } for (var i in this.httprequest.desktop.kvm.tunnels) { try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { } }
tunnelUserCount.desktop = users;
try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'kvm', value: users }); } catch (e) { }
broadcastSessionsToRegisteredApps();
} }
// Unpipe the web socket // Unpipe the web socket
try { try
{
this.unpipe(this.httprequest.desktop.kvm); this.unpipe(this.httprequest.desktop.kvm);
this.httprequest.desktop.kvm.unpipe(this); this.httprequest.desktop.kvm.unpipe(this);
} }
catch (e) { } catch(e) { }
// Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends). // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
if (this.rtcchannel) { if (this.rtcchannel)
try { {
try
{
this.rtcchannel.unpipe(this.httprequest.desktop.kvm); this.rtcchannel.unpipe(this.httprequest.desktop.kvm);
this.httprequest.desktop.kvm.unpipe(this.rtcchannel); this.httprequest.desktop.kvm.unpipe(this.rtcchannel);
} }
catch (e) { } catch(e) { }
} }
// Place wallpaper back if needed // Place wallpaper back if needed
@ -1752,7 +1849,8 @@ function createMeshCore(agent) {
} }
// Perform notification if needed. Toast messages may not be supported on all platforms. // Perform notification if needed. Toast messages may not be supported on all platforms.
if (this.httprequest.consent && (this.httprequest.consent & 8)) { if (this.httprequest.consent && (this.httprequest.consent & 8))
{
// User Consent Prompt is required // User Consent Prompt is required
// Send a console message back using the console channel, "\n" is supported. // Send a console message back using the console channel, "\n" is supported.
this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 })); this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
@ -1765,9 +1863,10 @@ function createMeshCore(agent) {
pr.ws = this; pr.ws = this;
this.pause(); this.pause();
this._consentpromise = pr; this._consentpromise = pr;
this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } }); this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); }});
pr.then( pr.then(
function () { function ()
{
// Success // Success
this.ws._consentpromise = null; this.ws._consentpromise = null;
MeshServerLogEx(30, null, "Starting remote desktop after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); MeshServerLogEx(30, null, "Starting remote desktop after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
@ -1810,7 +1909,8 @@ function createMeshCore(agent) {
this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 }); this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
this.ws.resume(); this.ws.resume();
}, },
function (e) { function (e)
{
// User Consent Denied/Failed // User Consent Denied/Failed
this.ws._consentpromise = null; this.ws._consentpromise = null;
MeshServerLogEx(34, null, "Failed to start remote desktop after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); MeshServerLogEx(34, null, "Failed to start remote desktop after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
@ -1881,6 +1981,7 @@ function createMeshCore(agent) {
if (this.httprequest.userid != null) { if (this.httprequest.userid != null) {
if (tunnelUserCount.files[this.httprequest.userid] == null) { tunnelUserCount.files[this.httprequest.userid] = 1; } else { tunnelUserCount.files[this.httprequest.userid]++; } if (tunnelUserCount.files[this.httprequest.userid] == null) { tunnelUserCount.files[this.httprequest.userid] = 1; } else { tunnelUserCount.files[this.httprequest.userid]++; }
try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
broadcastSessionsToRegisteredApps();
} }
this.end = function () { this.end = function () {
@ -1888,6 +1989,7 @@ function createMeshCore(agent) {
if (this.httprequest.userid != null) { if (this.httprequest.userid != null) {
if (tunnelUserCount.files[this.httprequest.userid] != null) { tunnelUserCount.files[this.httprequest.userid]--; if (tunnelUserCount.files[this.httprequest.userid] <= 0) { delete tunnelUserCount.files[this.httprequest.userid]; } } if (tunnelUserCount.files[this.httprequest.userid] != null) { tunnelUserCount.files[this.httprequest.userid]--; if (tunnelUserCount.files[this.httprequest.userid] <= 0) { delete tunnelUserCount.files[this.httprequest.userid]; } }
try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
broadcastSessionsToRegisteredApps();
} }
}; };
@ -1907,7 +2009,8 @@ function createMeshCore(agent) {
this._consentpromise = pr; this._consentpromise = pr;
this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } }); this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
pr.then( pr.then(
function () { function ()
{
// Success // Success
this.ws._consentpromise = null; this.ws._consentpromise = null;
MeshServerLogEx(40, null, "Starting remote files after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); MeshServerLogEx(40, null, "Starting remote files after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
@ -1923,7 +2026,8 @@ function createMeshCore(agent) {
} }
this.ws.resume(); this.ws.resume();
}, },
function (e) { function (e)
{
// User Consent Denied/Failed // User Consent Denied/Failed
this.ws._consentpromise = null; this.ws._consentpromise = null;
MeshServerLogEx(41, null, "Failed to start remote files after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest); MeshServerLogEx(41, null, "Failed to start remote files after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
@ -2289,11 +2393,13 @@ function createMeshCore(agent) {
} }
case 'termsize': { case 'termsize': {
// Indicates a change in terminal size // Indicates a change in terminal size
if (process.platform == 'win32') { if (process.platform == 'win32')
{
if (ws.httprequest._dispatcher == null) return; if (ws.httprequest._dispatcher == null) return;
//sendConsoleText('Win32-TermSize: ' + obj.cols + 'x' + obj.rows); //sendConsoleText('Win32-TermSize: ' + obj.cols + 'x' + obj.rows);
if (ws.httprequest._dispatcher.invoke) { ws.httprequest._dispatcher.invoke('resizeTerminal', [obj.cols, obj.rows]); } if (ws.httprequest._dispatcher.invoke) { ws.httprequest._dispatcher.invoke('resizeTerminal', [obj.cols, obj.rows]); }
} else { } else
{
if (ws.httprequest.process == null || ws.httprequest.process.pty == 0) return; if (ws.httprequest.process == null || ws.httprequest.process.pty == 0) return;
//sendConsoleText('Linux Resize: ' + obj.cols + 'x' + obj.rows); //sendConsoleText('Linux Resize: ' + obj.cols + 'x' + obj.rows);
@ -2374,8 +2480,10 @@ function createMeshCore(agent) {
this.websocket.rtcchannel.on('end', function () { this.websocket.rtcchannel.on('end', function () {
// The WebRTC channel closed, unpipe the KVM now. This is also done when the web socket closes. // The WebRTC channel closed, unpipe the KVM now. This is also done when the web socket closes.
//sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed'); //sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed');
if (this.websocket.desktop && this.websocket.desktop.kvm) { if (this.websocket.desktop && this.websocket.desktop.kvm)
try { {
try
{
this.unpipe(this.websocket.desktop.kvm); this.unpipe(this.websocket.desktop.kvm);
this.websocket.httprequest.desktop.kvm.unpipe(this); this.websocket.httprequest.desktop.kvm.unpipe(this);
} }
@ -2452,7 +2560,7 @@ function createMeshCore(agent) {
case 'help': { // Displays available commands case 'help': { // Displays available commands
var fin = '', f = '', availcommands = 'coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,amtreset,amtccm,amtacm,amtdeactivate,amtpolicy,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt,wallpaper,agentmsg'; var fin = '', f = '', availcommands = 'coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,amt,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,sendcaps,openurl,amtreset,amtccm,amtacm,amtdeactivate,amtpolicy,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,scanamt,wallpaper,agentmsg';
if (process.platform == 'win32') { availcommands += ',safemode,wpfhwacceleration,uac'; } if (process.platform == 'win32') { availcommands += ',safemode,wpfhwacceleration,uac'; }
if (process.platform != 'freebsd') { availcommands += ',vm'; } if (process.platform != 'freebsd') { availcommands += ',vm';}
if (require('MeshAgent').maxKvmTileSize != null) { availcommands += ',kvmmode'; } if (require('MeshAgent').maxKvmTileSize != null) { availcommands += ',kvmmode'; }
try { require('zip-reader'); availcommands += ',zip,unzip'; } catch (e) { } try { require('zip-reader'); availcommands += ',zip,unzip'; } catch (e) { }
@ -2484,19 +2592,22 @@ function createMeshCore(agent) {
response = JSON.stringify(tunnelUserCount.msg, null, 2); response = JSON.stringify(tunnelUserCount.msg, null, 2);
} }
try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (x) { } try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (x) { }
broadcastSessionsToRegisteredApps();
} }
break; break;
} }
case 'clearagentmsg': { case 'clearagentmsg': {
tunnelUserCount.msg = {}; tunnelUserCount.msg = {};
try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (x) { } try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (x) { }
broadcastSessionsToRegisteredApps();
break; break;
} }
case 'coredump': case 'coredump':
if (args['_'].length != 1) { if (args['_'].length != 1) {
response = "Proper usage: coredump on|off|status|clear"; // Display usage response = "Proper usage: coredump on|off|status|clear"; // Display usage
} else { } else {
switch (args['_'][0].toLowerCase()) { switch (args['_'][0].toLowerCase())
{
case 'on': case 'on':
process.coreDumpLocation = (process.platform == 'win32') ? (process.execPath.replace('.exe', '.dmp')) : (process.execPath + '.dmp'); process.coreDumpLocation = (process.platform == 'win32') ? (process.execPath.replace('.exe', '.dmp')) : (process.execPath + '.dmp');
response = 'coredump is now on'; response = 'coredump is now on';
@ -2526,20 +2637,25 @@ function createMeshCore(agent) {
} }
break; break;
case 'service': case 'service':
if (args['_'].length != 1) { if (args['_'].length != 1)
{
response = "Proper usage: service status|restart"; // Display usage response = "Proper usage: service status|restart"; // Display usage
} }
else { else
{
var s = require('service-manager').manager.getService(process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'); var s = require('service-manager').manager.getService(process.platform == 'win32' ? 'Mesh Agent' : 'meshagent');
switch (args['_'][0].toLowerCase()) { switch(args['_'][0].toLowerCase())
{
case 'status': case 'status':
response = 'Service ' + (s.isRunning() ? (s.isMe() ? '[SELF]' : '[RUNNING]') : ('[NOT RUNNING]')); response = 'Service ' + (s.isRunning() ? (s.isMe() ? '[SELF]' : '[RUNNING]') : ('[NOT RUNNING]'));
break; break;
case 'restart': case 'restart':
if (s.isMe()) { if (s.isMe())
{
s.restart(); s.restart();
} }
else { else
{
response = 'Restarting another agent instance is not allowed'; response = 'Restarting another agent instance is not allowed';
} }
break; break;
@ -2596,41 +2712,51 @@ function createMeshCore(agent) {
break; break;
case 'fdcount': case 'fdcount':
require('DescriptorEvents').getDescriptorCount().then( require('DescriptorEvents').getDescriptorCount().then(
function (c) { function (c)
{
sendConsoleText('Descriptor Count: ' + c, this.sessionid); sendConsoleText('Descriptor Count: ' + c, this.sessionid);
}, function (e) { }, function (e)
{
sendConsoleText('Error fetching descriptor count: ' + e, this.sessionid); sendConsoleText('Error fetching descriptor count: ' + e, this.sessionid);
}).parentPromise.sessionid = sessionid; }).parentPromise.sessionid = sessionid;
break; break;
case 'uac': case 'uac':
if (process.platform != 'win32') { if (process.platform != 'win32')
{
response = 'Unknown command "uac", type "help" for list of avaialble commands.'; response = 'Unknown command "uac", type "help" for list of avaialble commands.';
break; break;
} }
if (args['_'].length != 1) { if (args['_'].length != 1)
{
response = 'Proper usage: uac [get|interactive|secure]'; response = 'Proper usage: uac [get|interactive|secure]';
} }
else { else
switch (args['_'][0].toUpperCase()) { {
switch(args['_'][0].toUpperCase())
{
case 'GET': case 'GET':
var secd = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop'); var secd = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop');
response = "UAC mode: " + (secd == 0 ? "Interactive Desktop" : "Secure Desktop"); response = "UAC mode: " + (secd == 0 ? "Interactive Desktop" : "Secure Desktop");
break; break;
case 'INTERACTIVE': case 'INTERACTIVE':
try { try
{
require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 0); require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 0);
response = 'UAC mode changed to: Interactive Desktop'; response = 'UAC mode changed to: Interactive Desktop';
} }
catch (e) { catch (e)
{
response = "Unable to change UAC Mode"; response = "Unable to change UAC Mode";
} }
break; break;
case 'SECURE': case 'SECURE':
try { try
{
require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 1); require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 1);
response = 'UAC mode changed to: Secure Desktop'; response = 'UAC mode changed to: Secure Desktop';
} }
catch (e) { catch(e)
{
response = "Unable to change UAC Mode"; response = "Unable to change UAC Mode";
} }
break; break;
@ -2647,30 +2773,38 @@ function createMeshCore(agent) {
response = JSON.stringify(require('MeshAgent').getStartupOptions()); response = JSON.stringify(require('MeshAgent').getStartupOptions());
break; break;
case 'kvmmode': case 'kvmmode':
if (require('MeshAgent').maxKvmTileSize == null) { if (require('MeshAgent').maxKvmTileSize == null)
{
response = "Unknown command \"kvmmode\", type \"help\" for list of avaialble commands."; response = "Unknown command \"kvmmode\", type \"help\" for list of avaialble commands.";
} }
else { else
if (require('MeshAgent').maxKvmTileSize == 0) { {
if(require('MeshAgent').maxKvmTileSize == 0)
{
response = 'KVM Mode: Full JUMBO'; response = 'KVM Mode: Full JUMBO';
} }
else { else
{
response = 'KVM Mode: ' + (require('MeshAgent').maxKvmTileSize <= 65500 ? 'NO JUMBO' : 'Partial JUMBO'); response = 'KVM Mode: ' + (require('MeshAgent').maxKvmTileSize <= 65500 ? 'NO JUMBO' : 'Partial JUMBO');
response += (', TileLimit: ' + (require('MeshAgent').maxKvmTileSize < 1024 ? (require('MeshAgent').maxKvmTileSize + ' bytes') : (Math.round(require('MeshAgent').maxKvmTileSize / 1024) + ' Kbytes'))); response += (', TileLimit: ' + (require('MeshAgent').maxKvmTileSize < 1024 ? (require('MeshAgent').maxKvmTileSize + ' bytes') : (Math.round(require('MeshAgent').maxKvmTileSize/1024) + ' Kbytes')));
} }
} }
break; break;
case 'alert': case 'alert':
if (args['_'].length == 0) { if (args['_'].length == 0)
{
response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
} }
else { else
{
var p = args['_'].join(' ').split(','); var p = args['_'].join(' ').split(',');
if (p.length < 2) { if(p.length<2)
{
response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
} }
else { else
this._alert = require('message-box').create(p[0], p[1], p.length == 3 ? parseInt(p[2]) : 9999, 1); {
this._alert = require('message-box').create(p[0], p[1], p.length==3?parseInt(p[2]):9999,1);
} }
} }
break; break;
@ -3507,18 +3641,15 @@ function createMeshCore(agent) {
// Send any state messages // Send any state messages
if (Object.keys(tunnelUserCount.msg).length > 0) { if (Object.keys(tunnelUserCount.msg).length > 0) {
try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (e) { } try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (e) { }
} broadcastSessionsToRegisteredApps();
} }
// Send update to the registered application // Send update of registered applications to the server
if ((obj.DAIPC._daipc != null) && (obj.DAIPC._daipc._registered != null)) { updateRegisteredAppsToServer();
if (state == 1) {
var apps = {};
apps[obj.DAIPC._daipc._registered] = 1;
try { mesh.SendCommand({ action: 'sessions', type: 'app', value: apps }); } catch (e) { }
}
obj.DAIPC._daipc._send({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer });
} }
// Send server state update to registered applications
broadcastToRegisteredApps({ cmd: 'serverstate', value: meshServerConnectionState, url: require('MeshAgent').ConnectedServer });
} }
// Update the server with the latest network interface information // Update the server with the latest network interface information
@ -3547,8 +3678,10 @@ function createMeshCore(agent) {
try { try {
if (meinfo == null) return; if (meinfo == null) return;
var intelamt = {}; var intelamt = {};
if (amt != null) { if (amt != null)
switch (amt.lmsstate) { {
switch(amt.lmsstate)
{
case 0: intelamt.microlms = 'DISABLED'; break; case 0: intelamt.microlms = 'DISABLED'; break;
case 1: intelamt.microlms = 'CONNECTING'; break; case 1: intelamt.microlms = 'CONNECTING'; break;
case 2: intelamt.microlms = 'CONNECTED'; break; case 2: intelamt.microlms = 'CONNECTED'; break;