From 783ff4be0c10f5cfeb29b610989c158aa934debc Mon Sep 17 00:00:00 2001 From: Ylian Saint-Hilaire Date: Fri, 20 May 2022 21:52:03 -0700 Subject: [PATCH] Improved RDP error handling, #4022 --- apprelays.js | 3 +- public/scripts/agent-rdp-0.0.1.js | 25 +- rdp/protocol/pdu/cliprdr.js | 536 +++++++++++++++--------------- rdp/protocol/rdp.js | 7 +- rdp/protocol/x224.js | 9 +- views/default.handlebars | 12 +- 6 files changed, 311 insertions(+), 281 deletions(-) diff --git a/apprelays.js b/apprelays.js index fb8e59c2..43a4e66c 100644 --- a/apprelays.js +++ b/apprelays.js @@ -207,7 +207,8 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { }).on('close', function () { send(['rdp-close']); }).on('error', function (err) { - send(['rdp-error', err]); + if (typeof err == 'string') { send(['rdp-error', err]); } + if ((typeof err == 'object') && (err.err) && (err.code)) { send(['rdp-error', err.err, err.code]); } }).connect('localhost', obj.tcpServerPort); } catch (ex) { console.log('startRdpException', ex); diff --git a/public/scripts/agent-rdp-0.0.1.js b/public/scripts/agent-rdp-0.0.1.js index 2c4f61b6..41412436 100644 --- a/public/scripts/agent-rdp-0.0.1.js +++ b/public/scripts/agent-rdp-0.0.1.js @@ -16,6 +16,7 @@ var CreateRDPDesktop = function (canvasid) { obj.ScreenWidth = obj.width = 1280; obj.ScreenHeight = obj.height = 1024; obj.m.onClipboardChanged = null; + obj.onConsoleMessageChange = null; function mouseButtonMap(button) { // Swap mouse buttons if needed @@ -79,8 +80,28 @@ var CreateRDPDesktop = function (canvasid) { break; } case 'rdp-error': { - var err = msg[1]; - console.log('[mstsc.js] error : ' + err.code + '(' + err.message + ')'); + obj.consoleMessageTimeout = 5; // Seconds + obj.consoleMessage = msg[1]; + delete obj.consoleMessageArgs; + if (msg.length > 2) { obj.consoleMessageArgs = [ msg[2] ]; } + switch (msg[1]) { + case 'NODE_RDP_PROTOCOL_X224_NEG_FAILURE': + if (msg[2] == 1) { obj.consoleMessageId = 9; } // "SSL required by server"; + else if (msg[2] == 2) { obj.consoleMessageId = 10; } // "SSL not allowed by server"; + else if (msg[2] == 3) { obj.consoleMessageId = 11; } // "SSL certificate not on server"; + else if (msg[2] == 4) { obj.consoleMessageId = 12; } // "Inconsistent flags"; + else if (msg[2] == 5) { obj.consoleMessageId = 13; } // "Hybrid required by server"; + else if (msg[2] == 6) { obj.consoleMessageId = 14; } // "SSL with user auth required by server"; + else obj.consoleMessageId = 7; // "Protocol negotiation failed"; + break; + case 'NODE_RDP_PROTOCOL_X224_NLA_NOT_SUPPORTED': + obj.consoleMessageId = 8; // "NLA not supported"; + break; + default: + obj.consoleMessageId = null; + break; + } + if (obj.onConsoleMessageChange) { obj.onConsoleMessageChange(); } obj.Stop(); break; } diff --git a/rdp/protocol/pdu/cliprdr.js b/rdp/protocol/pdu/cliprdr.js index 15e3b86f..614a8bd8 100644 --- a/rdp/protocol/pdu/cliprdr.js +++ b/rdp/protocol/pdu/cliprdr.js @@ -12,14 +12,14 @@ const data = require('./data'); */ class Cliprdr extends EventEmitter { - constructor(transport) { - super(); - this.transport = transport; - // must be init via connect event - this.userId = 0; - this.serverCapabilities = []; - this.clientCapabilities = []; - } + constructor(transport) { + super(); + this.transport = transport; + // must be init via connect event + this.userId = 0; + this.serverCapabilities = []; + this.clientCapabilities = []; + } } @@ -30,298 +30,298 @@ class Cliprdr extends EventEmitter { */ class Client extends Cliprdr { - constructor(transport, fastPathTransport) { + constructor(transport, fastPathTransport) { - super(transport, fastPathTransport); + super(transport, fastPathTransport); - this.transport.once('connect', (gccCore, userId, channelId) => { - this.connect(gccCore, userId, channelId); - }).on('close', () => { - this.emit('close'); - }).on('error', (err) => { - this.emit('error', err); - }); + this.transport.once('connect', (gccCore, userId, channelId) => { + this.connect(gccCore, userId, channelId); + }).on('close', function () { + //this.emit('close'); + }).on('error', function (err) { + //this.emit('error', err); + }); - this.content = ''; - - } + this.content = ''; - /** - * connect function - * @param gccCore {type.Component(clientCoreData)} - */ - connect(gccCore, userId, channelId) { - this.gccCore = gccCore; - this.userId = userId; - this.channelId = channelId; - this.transport.once('cliprdr', (s) => { - this.recv(s); - }); - } - - - send(message) { - this.transport.send('cliprdr', new type.Component([ - // Channel PDU Header - new type.UInt32Le(message.size()), - // CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST | CHANNEL_FLAG_SHOW_PROTOCOL - new type.UInt32Le(0x13), - message - ])); - }; - - recv(s) { - s.offset = 18; - const pdu = data.clipPDU().read(s), type = data.ClipPDUMsgType; - - switch (pdu.obj.header.obj.msgType.value) { - case type.CB_MONITOR_READY: - this.recvMonitorReadyPDU(s); - break; - case type.CB_FORMAT_LIST: - this.recvFormatListPDU(s); - break; - case type.CB_FORMAT_LIST_RESPONSE: - this.recvFormatListResponsePDU(s); - break; - case type.CB_FORMAT_DATA_REQUEST: - this.recvFormatDataRequestPDU(s); - break; - case type.CB_FORMAT_DATA_RESPONSE: - this.recvFormatDataResponsePDU(s); - break; - case type.CB_TEMP_DIRECTORY: - break; - case type.CB_CLIP_CAPS: - this.recvClipboardCapsPDU(s); - break; - case type.CB_FILECONTENTS_REQUEST: } - this.transport.once('cliprdr', (s) => { - this.recv(s); - }); - } - - /** - * Receive capabilities from server - * @param s {type.Stream} - */ - recvClipboardCapsPDU(s) { - // Start at 18 - s.offset = 18; - // const pdu = data.clipPDU().read(s); - // console.log('recvClipboardCapsPDU', s); - } + /** + * connect function + * @param gccCore {type.Component(clientCoreData)} + */ + connect(gccCore, userId, channelId) { + this.gccCore = gccCore; + this.userId = userId; + this.channelId = channelId; + this.transport.once('cliprdr', (s) => { + this.recv(s); + }); + } - /** - * Receive monitor ready from server - * @param s {type.Stream} - */ - recvMonitorReadyPDU(s) { - s.offset = 18; - // const pdu = data.clipPDU().read(s); - // console.log('recvMonitorReadyPDU', s); + send(message) { + this.transport.send('cliprdr', new type.Component([ + // Channel PDU Header + new type.UInt32Le(message.size()), + // CHANNEL_FLAG_FIRST | CHANNEL_FLAG_LAST | CHANNEL_FLAG_SHOW_PROTOCOL + new type.UInt32Le(0x13), + message + ])); + }; - this.sendClipboardCapsPDU(); - // this.sendClientTemporaryDirectoryPDU(); - this.sendFormatListPDU(); - } + recv(s) { + s.offset = 18; + const pdu = data.clipPDU().read(s), type = data.ClipPDUMsgType; + + switch (pdu.obj.header.obj.msgType.value) { + case type.CB_MONITOR_READY: + this.recvMonitorReadyPDU(s); + break; + case type.CB_FORMAT_LIST: + this.recvFormatListPDU(s); + break; + case type.CB_FORMAT_LIST_RESPONSE: + this.recvFormatListResponsePDU(s); + break; + case type.CB_FORMAT_DATA_REQUEST: + this.recvFormatDataRequestPDU(s); + break; + case type.CB_FORMAT_DATA_RESPONSE: + this.recvFormatDataResponsePDU(s); + break; + case type.CB_TEMP_DIRECTORY: + break; + case type.CB_CLIP_CAPS: + this.recvClipboardCapsPDU(s); + break; + case type.CB_FILECONTENTS_REQUEST: + } + + this.transport.once('cliprdr', (s) => { + this.recv(s); + }); + } + + /** + * Receive capabilities from server + * @param s {type.Stream} + */ + recvClipboardCapsPDU(s) { + // Start at 18 + s.offset = 18; + // const pdu = data.clipPDU().read(s); + // console.log('recvClipboardCapsPDU', s); + } - /** - * Send clipboard capabilities PDU - */ - sendClipboardCapsPDU() { - this.send(new type.Component({ - msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_CLIP_CAPS), - msgFlags: new type.UInt16Le(0x00), - dataLen: new type.UInt32Le(0x10), - cCapabilitiesSets: new type.UInt16Le(0x01), - pad1: new type.UInt16Le(0x00), - capabilitySetType: new type.UInt16Le(0x01), - lengthCapability: new type.UInt16Le(0x0c), - version: new type.UInt32Le(0x02), - capabilityFlags: new type.UInt32Le(0x02) - })); - } + /** + * Receive monitor ready from server + * @param s {type.Stream} + */ + recvMonitorReadyPDU(s) { + s.offset = 18; + // const pdu = data.clipPDU().read(s); + // console.log('recvMonitorReadyPDU', s); + + this.sendClipboardCapsPDU(); + // this.sendClientTemporaryDirectoryPDU(); + this.sendFormatListPDU(); + } - /** - * Send client temporary directory PDU - */ - sendClientTemporaryDirectoryPDU(path = '') { - // TODO - this.send(new type.Component({ - msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_TEMP_DIRECTORY), - msgFlags: new type.UInt16Le(0x00), - dataLen: new type.UInt32Le(0x0208), - wszTempDir: new type.BinaryString(Buffer.from('D:\\Vectors' + Array(251).join('\x00'), 'ucs2'), { readLength : new type.CallableValue(520)}) - })); - } + /** + * Send clipboard capabilities PDU + */ + sendClipboardCapsPDU() { + this.send(new type.Component({ + msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_CLIP_CAPS), + msgFlags: new type.UInt16Le(0x00), + dataLen: new type.UInt32Le(0x10), + cCapabilitiesSets: new type.UInt16Le(0x01), + pad1: new type.UInt16Le(0x00), + capabilitySetType: new type.UInt16Le(0x01), + lengthCapability: new type.UInt16Le(0x0c), + version: new type.UInt32Le(0x02), + capabilityFlags: new type.UInt32Le(0x02) + })); + } - /** - * Send format list PDU - */ - sendFormatListPDU() { - this.send(new type.Component({ - msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST), - msgFlags: new type.UInt16Le(0x00), - - dataLen: new type.UInt32Le(0x24), - - formatId6: new type.UInt32Le(0xc004), - formatName6: new type.BinaryString(Buffer.from('Native\x00' , 'ucs2'), { readLength : new type.CallableValue(14)}), - - formatId8: new type.UInt32Le(0x0d), - formatName8: new type.UInt16Le(0x00), - - formatId9: new type.UInt32Le(0x10), - formatName9: new type.UInt16Le(0x00), - - formatId0: new type.UInt32Le(0x01), - formatName0: new type.UInt16Le(0x00), - - // dataLen: new type.UInt32Le(0xe0), - - // formatId1: new type.UInt32Le(0xc08a), - // formatName1: new type.BinaryString(Buffer.from('Rich Text Format\x00' , 'ucs2'), { readLength : new type.CallableValue(34)}), - - // formatId2: new type.UInt32Le(0xc145), - // formatName2: new type.BinaryString(Buffer.from('Rich Text Format Without Objects\x00' , 'ucs2'), { readLength : new type.CallableValue(66)}), - - // formatId3: new type.UInt32Le(0xc143), - // formatName3: new type.BinaryString(Buffer.from('RTF As Text\x00' , 'ucs2'), { readLength : new type.CallableValue(24)}), - - // formatId4: new type.UInt32Le(0x01), - // formatName4: new type.BinaryString(0x00), - - formatId5: new type.UInt32Le(0x07), - formatName5: new type.UInt16Le(0x00), - - // formatId6: new type.UInt32Le(0xc004), - // formatName6: new type.BinaryString(Buffer.from('Native\x00' , 'ucs2'), { readLength : new type.CallableValue(14)}), - - // formatId7: new type.UInt32Le(0xc00e), - // formatName7: new type.BinaryString(Buffer.from('Object Descriptor\x00' , 'ucs2'), { readLength : new type.CallableValue(36)}), - - // formatId8: new type.UInt32Le(0x03), - // formatName8: new type.UInt16Le(0x00), - - // formatId9: new type.UInt32Le(0x10), - // formatName9: new type.UInt16Le(0x00), - - // formatId0: new type.UInt32Le(0x07), - // formatName0: new type.UInt16Le(0x00), - })); - - } - - /** - * Recvie format list PDU from server - * @param {type.Stream} s - */ - recvFormatListPDU(s) { - s.offset = 18; - // const pdu = data.clipPDU().read(s); - // console.log('recvFormatListPDU', s); - this.sendFormatListResponsePDU(); - } + /** + * Send client temporary directory PDU + */ + sendClientTemporaryDirectoryPDU(path = '') { + // TODO + this.send(new type.Component({ + msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_TEMP_DIRECTORY), + msgFlags: new type.UInt16Le(0x00), + dataLen: new type.UInt32Le(0x0208), + wszTempDir: new type.BinaryString(Buffer.from('D:\\Vectors' + Array(251).join('\x00'), 'ucs2'), { readLength: new type.CallableValue(520) }) + })); + } - /** - * Send format list reesponse - */ - sendFormatListResponsePDU() { - this.send(new type.Component({ - msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST_RESPONSE), - msgFlags: new type.UInt16Le(0x01), - dataLen: new type.UInt32Le(0x00), - })); + /** + * Send format list PDU + */ + sendFormatListPDU() { + this.send(new type.Component({ + msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST), + msgFlags: new type.UInt16Le(0x00), - this.sendFormatDataRequestPDU(); - } + dataLen: new type.UInt32Le(0x24), + + formatId6: new type.UInt32Le(0xc004), + formatName6: new type.BinaryString(Buffer.from('Native\x00', 'ucs2'), { readLength: new type.CallableValue(14) }), + + formatId8: new type.UInt32Le(0x0d), + formatName8: new type.UInt16Le(0x00), + + formatId9: new type.UInt32Le(0x10), + formatName9: new type.UInt16Le(0x00), + + formatId0: new type.UInt32Le(0x01), + formatName0: new type.UInt16Le(0x00), + + // dataLen: new type.UInt32Le(0xe0), + + // formatId1: new type.UInt32Le(0xc08a), + // formatName1: new type.BinaryString(Buffer.from('Rich Text Format\x00' , 'ucs2'), { readLength : new type.CallableValue(34)}), + + // formatId2: new type.UInt32Le(0xc145), + // formatName2: new type.BinaryString(Buffer.from('Rich Text Format Without Objects\x00' , 'ucs2'), { readLength : new type.CallableValue(66)}), + + // formatId3: new type.UInt32Le(0xc143), + // formatName3: new type.BinaryString(Buffer.from('RTF As Text\x00' , 'ucs2'), { readLength : new type.CallableValue(24)}), + + // formatId4: new type.UInt32Le(0x01), + // formatName4: new type.BinaryString(0x00), + + formatId5: new type.UInt32Le(0x07), + formatName5: new type.UInt16Le(0x00), + + // formatId6: new type.UInt32Le(0xc004), + // formatName6: new type.BinaryString(Buffer.from('Native\x00' , 'ucs2'), { readLength : new type.CallableValue(14)}), + + // formatId7: new type.UInt32Le(0xc00e), + // formatName7: new type.BinaryString(Buffer.from('Object Descriptor\x00' , 'ucs2'), { readLength : new type.CallableValue(36)}), + + // formatId8: new type.UInt32Le(0x03), + // formatName8: new type.UInt16Le(0x00), + + // formatId9: new type.UInt32Le(0x10), + // formatName9: new type.UInt16Le(0x00), + + // formatId0: new type.UInt32Le(0x07), + // formatName0: new type.UInt16Le(0x00), + })); + + } + + /** + * Recvie format list PDU from server + * @param {type.Stream} s + */ + recvFormatListPDU(s) { + s.offset = 18; + // const pdu = data.clipPDU().read(s); + // console.log('recvFormatListPDU', s); + this.sendFormatListResponsePDU(); + } - /** - * Receive format list response from server - * @param s {type.Stream} - */ - recvFormatListResponsePDU(s) { - s.offset = 18; - // const pdu = data.clipPDU().read(s); - // console.log('recvFormatListResponsePDU', s); - // this.sendFormatDataRequestPDU(); - } + /** + * Send format list reesponse + */ + sendFormatListResponsePDU() { + this.send(new type.Component({ + msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_LIST_RESPONSE), + msgFlags: new type.UInt16Le(0x01), + dataLen: new type.UInt32Le(0x00), + })); + + this.sendFormatDataRequestPDU(); + } - /** - * Send format data request PDU - */ - sendFormatDataRequestPDU(formartId = 0x0d) { - this.send(new type.Component({ - msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_REQUEST), - msgFlags: new type.UInt16Le(0x00), - dataLen: new type.UInt32Le(0x04), - requestedFormatId: new type.UInt32Le(formartId), - })); - } + /** + * Receive format list response from server + * @param s {type.Stream} + */ + recvFormatListResponsePDU(s) { + s.offset = 18; + // const pdu = data.clipPDU().read(s); + // console.log('recvFormatListResponsePDU', s); + // this.sendFormatDataRequestPDU(); + } - /** - * Receive format data request PDU from server - * @param s {type.Stream} - */ - recvFormatDataRequestPDU(s) { - s.offset = 18; - // const pdu = data.clipPDU().read(s); - // console.log('recvFormatDataRequestPDU', s); - this.sendFormatDataResponsePDU(); - } + /** + * Send format data request PDU + */ + sendFormatDataRequestPDU(formartId = 0x0d) { + this.send(new type.Component({ + msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_REQUEST), + msgFlags: new type.UInt16Le(0x00), + dataLen: new type.UInt32Le(0x04), + requestedFormatId: new type.UInt32Le(formartId), + })); + } - /** - * Send format data reesponse PDU - */ - sendFormatDataResponsePDU() { - - const bufs = Buffer.from(this.content + '\x00' , 'ucs2'); - - this.send(new type.Component({ - msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_RESPONSE), - msgFlags: new type.UInt16Le(0x01), - dataLen: new type.UInt32Le(bufs.length), - requestedFormatData: new type.BinaryString(bufs, { readLength : new type.CallableValue(bufs.length)}) - })); - - } + /** + * Receive format data request PDU from server + * @param s {type.Stream} + */ + recvFormatDataRequestPDU(s) { + s.offset = 18; + // const pdu = data.clipPDU().read(s); + // console.log('recvFormatDataRequestPDU', s); + this.sendFormatDataResponsePDU(); + } - /** - * Receive format data response PDU from server - * @param s {type.Stream} - */ - recvFormatDataResponsePDU(s) { - s.offset = 18; - // const pdu = data.clipPDU().read(s); - const str = s.buffer.toString('ucs2', 26, s.buffer.length-2); - // console.log('recvFormatDataResponsePDU', str); - this.content = str; - this.emit('clipboard', str) - } + /** + * Send format data reesponse PDU + */ + sendFormatDataResponsePDU() { + + const bufs = Buffer.from(this.content + '\x00', 'ucs2'); + + this.send(new type.Component({ + msgType: new type.UInt16Le(data.ClipPDUMsgType.CB_FORMAT_DATA_RESPONSE), + msgFlags: new type.UInt16Le(0x01), + dataLen: new type.UInt32Le(bufs.length), + requestedFormatData: new type.BinaryString(bufs, { readLength: new type.CallableValue(bufs.length) }) + })); + + } -// ===================================================================================== - setClipboardData(content) { - this.content = content; - this.sendFormatListPDU(); - } + /** + * Receive format data response PDU from server + * @param s {type.Stream} + */ + recvFormatDataResponsePDU(s) { + s.offset = 18; + // const pdu = data.clipPDU().read(s); + const str = s.buffer.toString('ucs2', 26, s.buffer.length - 2); + // console.log('recvFormatDataResponsePDU', str); + this.content = str; + this.emit('clipboard', str) + } + + + // ===================================================================================== + setClipboardData(content) { + this.content = content; + this.sendFormatListPDU(); + } } - + module.exports = { - Client + Client } diff --git a/rdp/protocol/rdp.js b/rdp/protocol/rdp.js index 97cb25a6..c58e2e1c 100644 --- a/rdp/protocol/rdp.js +++ b/rdp/protocol/rdp.js @@ -184,12 +184,7 @@ function RdpClient(config) { } }).on('error', function (err) { log.warn(err.code + '(' + err.message + ')\n' + err.stack); - if (err instanceof error.FatalError) { - throw err; - } - else { - self.emit('error', err); - } + if (err instanceof error.FatalError) { throw err; } else { self.emit('error', err); } }); } diff --git a/rdp/protocol/x224.js b/rdp/protocol/x224.js index 1054efd6..c99e65af 100644 --- a/rdp/protocol/x224.js +++ b/rdp/protocol/x224.js @@ -218,8 +218,9 @@ Client.prototype.recvConnectionConfirm = function(s) { var message = serverConnectionConfirm().read(s); if (message.obj.protocolNeg.obj.type.value == NegotiationType.TYPE_RDP_NEG_FAILURE) { - throw new error.ProtocolError('NODE_RDP_PROTOCOL_X224_NEG_FAILURE', - 'Failure code:' + message.obj.protocolNeg.obj.result.value + " (see https://msdn.microsoft.com/en-us/library/cc240507.aspx)"); + this.emit('error', { err: 'NODE_RDP_PROTOCOL_X224_NEG_FAILURE', code: message.obj.protocolNeg.obj.result.value }); + return; + //throw new error.ProtocolError('NODE_RDP_PROTOCOL_X224_NEG_FAILURE', 'Failure code:' + message.obj.protocolNeg.obj.result.value + " (see https://msdn.microsoft.com/en-us/library/cc240507.aspx)"); } if (message.obj.protocolNeg.obj.type.value == NegotiationType.TYPE_RDP_NEG_RSP) { @@ -227,7 +228,9 @@ Client.prototype.recvConnectionConfirm = function(s) { } if ([Protocols.PROTOCOL_HYBRID_EX].indexOf(this.selectedProtocol) !== -1) { - throw new error.ProtocolError('NODE_RDP_PROTOCOL_X224_NLA_NOT_SUPPORTED'); + this.emit('error', 'NODE_RDP_PROTOCOL_X224_NLA_NOT_SUPPORTED'); + return; + //throw new error.ProtocolError('NODE_RDP_PROTOCOL_X224_NLA_NOT_SUPPORTED'); } if (this.selectedProtocol == Protocols.PROTOCOL_RDP) { diff --git a/views/default.handlebars b/views/default.handlebars index 28706dfe..1116e4e4 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -8414,7 +8414,7 @@ function autoConnectDesktop(e) { if (autoConnectDesktopTimer == null) { autoConnectDesktopTimer = setInterval(function() { connectDesktop(null, 1) }, 1000); } else { clearInterval(autoConnectDesktopTimer); autoConnectDesktopTimer = null; } } // Used to translate incoming agent console messages - var agentConsoleMessages = [ '', "Waiting for user to grant access...", "Denied", "Failed to start remote terminal session, {0} ({1})", "Timeout", "Received invalid network data", "Unable to capture display" ]; + var agentConsoleMessages = [ '', "Waiting for user to grant access...", "Denied", "Failed to start remote terminal session, {0} ({1})", "Timeout", "Received invalid network data", "Unable to capture display", "Protocol negotiation failed ({0})", "NLA not supported", "SSL required by server", "SSL not allowed by server", "SSL certificate not on server", "Inconsistent flags", "Hybrid required by server", "SSL with user auth required by server" ]; function formatAgentConsoleMessage(msg, msgid, msgargs) { var r; if (msgargs == null) { msgargs = []; } @@ -8569,6 +8569,16 @@ if (desktopsettings.rdpsmb) { desktop.m.SwapMouse = desktopsettings.rdpsmb; } desktop.Start(desktopNode._id, currentNode.rdpport ? currentNode.rdpport : 3389, tsid); desktop.contype = 4; + desktop.onConsoleMessageChange = function () { + if (desktop.consoleMessage) { + Q('p11DeskConsoleMsg').innerHTML += formatAgentConsoleMessage(desktop.consoleMessage, desktop.consoleMessageId, desktop.consoleMessageArgs); + QV('p11DeskConsoleMsg', true); + if (p11DeskConsoleMsgTimer != null) { clearTimeout(p11DeskConsoleMsgTimer); } + if (desktop.consoleMessageTimeout) { p11DeskConsoleMsgTimer = setTimeout(p11clearConsoleMsg, desktop.consoleMessageTimeout * 1000); } + } else { + p11clearConsoleMsg(); + } + } } } else { // Disconnect and clean up the remote desktop