From ef764d3b9baa8f5385f3ce218a2590d663d4781c Mon Sep 17 00:00:00 2001 From: Joel Martin Date: Sun, 2 May 2010 14:19:13 -0500 Subject: [PATCH] Support for RFB 3.8 handshake. --- include/base64.js | 2 +- vnc.js | 85 ++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 70 insertions(+), 17 deletions(-) diff --git a/include/base64.js b/include/base64.js index e556b2be..6d62b30b 100644 --- a/include/base64.js +++ b/include/base64.js @@ -101,7 +101,7 @@ decode: function (data, offset) { var data_length = data.indexOf('=') - offset; if (data_length < 0) data_length = data.length - offset; - var result_length = (data_length >> 2) * 3 + ((data.length - offset) % 4 - 1); + var result_length = (data_length >> 2) * 3 + Math.floor((data_length%4)/1.5); var result = new Array(result_length); // Convert one by one. diff --git a/vnc.js b/vnc.js index cc0692d7..b3ae88be 100644 --- a/vnc.js +++ b/vnc.js @@ -21,6 +21,12 @@ Array.prototype.shift32 = function () { (this.shift() << 8) + (this.shift() ); } +Array.prototype.get32 = function (off) { + return (this[off ] << 24) + + (this[off + 1] << 16) + + (this[off + 2] << 8) + + (this[off + 3] ); +} Array.prototype.push32 = function (num) { this.push((num >> 24) & 0xFF, (num >> 16) & 0xFF, @@ -85,7 +91,9 @@ ws : null, // Web Socket object sendID : null, use_seq : false, -version : "RFB 003.003\n", +max_version : 3.8, +version : 0, +auth_scheme : '', state : 'disconnected', cuttext : 'none', // ServerCutText wait state ct_length : 0, @@ -115,28 +123,68 @@ rre_chunk : 100, init_msg: function () { console.log(">> init_msg"); + //console.log("RQ (" + RQ.length + ") " + RQ); + switch (RFB.state) { case 'ProtocolVersion' : - if (RQ.length != 12) { - updateStatus('failed', "Disconnected: invalid RFB protocol version received"); + if (RQ.length < 12) { + RFB.updateState('failed', "Disconnected: invalid RFB protocol version received"); + return; + } + var server_version = RQ.shiftStr(12).substr(0,11); + console.log("Server ProtocolVersion: " + server_version); + if ((server_version == "RFB 003.003") || (RFB.max_version == 3.3)) { + RFB.version = 3.3; + var verstr = "RFB 003.003"; + RFB.send_string(verstr + "\n"); + RFB.updateState('Security', "Sent ProtocolVersion: " + verstr); + } else if (server_version == "RFB 003.008") { + RFB.version = 3.8; + var verstr = "RFB 003.008"; + RFB.send_string(verstr + "\n"); + RFB.updateState('Security', "Sent ProtocolVersion: " + verstr); + } else { + RFB.updateState('failed', "Invalid server version " + server_version); return; } - var server_version = RQ.shiftStr(12); - console.log("Server ProtocolVersion: " + server_version.substr(0,11)); - RFB.send_string(RFB.version); - RFB.updateState('Authentication', "Sent ProtocolVersion: " + RFB.version.substr(0,11)); break; - case 'Authentication' : - if (RQ.length < 4) { - RFB.updateState('reset', "Invalid auth frame"); - return; + case 'Security' : + if (RFB.version == 3.3) { + if (RQ.length < 4) { + RFB.updateState('reset', "Invalid security frame"); + return; + } + RFB.auth_scheme = RQ.shift32(); + console.log("auth_scheme: " + RFB.auth_scheme); + } else if (RFB.version == 3.8) { + var num_types = RQ.shift8(); + if (num_types == 0) { + var strlen = RQ.shift32(); + var reason = RQ.shiftStr(strlen); + RFB.updateState('failed', "Disconnected: security failure: " + reason); + return; + } + var types = RQ.shiftBytes(num_types); + if ((types[0] != 1) && (types[0] != 2)) { + RFB.updateState('failed', "Disconnected: invalid security type list: " + types); + return; + } + RFB.auth_scheme = types[0]; + RFB.send_array([RFB.auth_scheme]); } - var scheme = RQ.shift32(); - console.log("Auth scheme: " + scheme); - switch (scheme) { + RFB.updateState('Authentication', "Authenticating using scheme: " + RFB.auth_scheme); + // Fall through + + case 'Authentication' : + console.log("Security auth scheme: " + RFB.auth_scheme); + switch (RFB.auth_scheme) { case 0: // connection failed + if (RQ.length < 4) { + console.log(" waiting for auth reason bytes"); + return; + } var strlen = RQ.shift32(); var reason = RQ.shiftStr(strlen); RFB.updateState('failed', "Disconnected: auth failure: " + reason); @@ -146,17 +194,22 @@ init_msg: function () { RFB.updateState('ServerInitialisation'); break; case 2: // VNC authentication + if (RQ.length < 16) { + console.log(" waiting for auth challenge bytes"); + return; + } var challenge = RQ.shiftBytes(16); console.log("Password: " + RFB.password); - console.log("Challenge: " + challenge + "(" + challenge.length + ")"); + console.log("Challenge: " + challenge + " (" + challenge.length + ")"); passwd = RFB.passwdTwiddle(RFB.password); response = des(passwd, challenge, 1); + console.log("Response: " + response + " (" + response.length + ")"); RFB.send_array(response); RFB.updateState('SecurityResult'); break; default: - RFB.updateState('failed', "Disconnected: unsupported auth scheme " + scheme); + RFB.updateState('failed', "Disconnected: unsupported auth scheme: " + RFB.auth_scheme); return; } break;