From 70519cbb381f92457e6126b789a06f2a55d99d0a Mon Sep 17 00:00:00 2001 From: Andrey Sidorov Date: Fri, 15 Jan 2016 16:01:54 +1100 Subject: [PATCH] handle Internet cookie addresses correctly. Fixes #121 --- lib/auth.js | 101 ++++++++++++++++++++++------------------------- lib/handshake.js | 73 +++++++++++++++++----------------- lib/xcore.js | 3 +- 3 files changed, 85 insertions(+), 92 deletions(-) diff --git a/lib/auth.js b/lib/auth.js index e62e910..aa044f8 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -11,81 +11,74 @@ function parseXauth( buf ) var auth = []; var cookieProperties = ['address', 'display', 'authName', 'authData']; - function handleCookieProperty(property) { - var length = buf.unpack('n', offset)[0]; - offset += 2; - cookie[property] = buf.unpackString(length, offset); - offset += length; - } - while (offset < buf.length) { - var cookie = {}; + var cookie = {}; var typeToName = { 256: 'Local', 65535: 'Wild', 254: 'Netname', - 253: 'Krb5Principal', + 253: 'Krb5Principal', 252: 'LocalHost', - 0: 'Internet', - 1: 'DECnet', + 0: 'Internet', + 1: 'DECnet', 2: 'Chaos', - 5: 'ServerInterpreted', + 5: 'ServerInterpreted', 6: 'InternetV6' }; - cookie.type = buf.unpack('n')[0]; + cookie.type = buf.readUInt16LE(offset); + console.log('Cookie type: '); if (!typeToName[cookie.type]) { console.warn('Unknown address type'); } offset += 2; - //JSHint becomes angry when handleCookieProperty is declared inside loop - cookieProperties.forEach(handleCookieProperty); + cookieProperties.forEach(function(property) { + var length = buf.unpack('n', offset)[0]; + offset += 2; + if (cookie.type === 0 && property == 'address') { // Internet + // 4 bytes of ip addess, convert to w.x.y.z string + cookie.address = [ buf[offset], buf[offset+1], buf[offset+2], buf[offset+3]] + .map(function(octet) { return octet.toString(10) }).join('.'); + } else { + cookie[property] = buf.unpackString(length, offset); + } + offset += length; + }); auth.push(cookie); } return auth; } +var os = require('os'); +var path = require('path'); + +function readXauthority(cb) { + var filename = process.env.XAUTHORITY || path.join(os.homedir(), '.Xauthority'); + fs.readFile(filename, function(err, data) { + if (!err) + return cb(null, data); + if(err.code == 'ENOENT') { + // Xming/windows uses %HOME%/Xauthority ( .Xauthority with no dot ) - try with this name + filename = process.env.XAUTHORITY || path.join(os.homedir(), 'Xauthority'); + return fs.readFile(filename, cb); + } else { + cb(err); + } + }); +} + module.exports = function( display, host, cb ) { - var XAuthorityFile = process.env.XAUTHORITY; - if (!XAuthorityFile) + readXauthority(function(err, data) { + if(err) return cb(err); + + var auth = parseXauth(data); + for (var cookieNum in auth) { - if ( process.platform.match(/win/) ) { - // http://www.straightrunning.com/XmingNotes/trouble.php - // - // The Xming magic cookie program, xauth (user-based), uses an - // Xauthority file (not the traditional .Xauthority file) in - // the %HOME% directory. To use xauth from Command Processor - // e.g. on Windows machine 192.168.0.2 with user colin... - XAuthorityFile = process.env.USERPROFILE + '\\Xauthority'; - } else { - XAuthorityFile = process.env.HOME + '/.Xauthority'; - } + var cookie = auth[cookieNum]; + if (cookie.display === display && cookie.address === host) + return cb( null, cookie ); } - - fs.readFile(XAuthorityFile, function (err, data) { - - if (err) - { - if (err.code == 'ENOENT') - { - cb('',''); - return; - } - throw err; - } - - var auth = parseXauth(data); - for (var cookieNum in auth) - { - var cookie = auth[cookieNum]; - if (cookie.display == display && cookie.address == host) - { - cb( cookie.authName, cookie.authData ); - return; - } - } - // throw 'No auth cookie matching display=' + display + ' and host=' + host; - cb( '', '' ); - }); + cb(new Error('No auth cookie matching display=' + display + ' and host=' + host)); + }); }; diff --git a/lib/handshake.js b/lib/handshake.js index e791cae..7dda277 100644 --- a/lib/handshake.js +++ b/lib/handshake.js @@ -12,15 +12,15 @@ function readVisuals(bl, visuals, n_visuals, cb) var visual = {}; bl.unpackTo( visual, [ - 'L vid', - 'C class', - 'C bits_per_rgb', + 'L vid', + 'C class', + 'C bits_per_rgb', 'S map_ent', 'L red_mask', 'L green_mask', 'L blue_mask', 'xxxx' - ], + ], function() { var vid = visual.vid; // delete visual.vid; @@ -28,7 +28,7 @@ function readVisuals(bl, visuals, n_visuals, cb) if (Object.keys(visuals).length == n_visuals) cb() else - readVisuals(bl, visuals, n_visuals, cb); + readVisuals(bl, visuals, n_visuals, cb); }); } @@ -51,7 +51,7 @@ function readDepths(bl, display, depths, n_depths, cb) cb(); else readDepths(bl, display, depths, n_depths, cb); - }); + }); }); } @@ -62,23 +62,23 @@ function readScreens(bl, display, cbDisplayReady) var scr = {}; bl.unpackTo( scr, [ - 'L root', + 'L root', 'L default_colormap', - 'L white_pixel', + 'L white_pixel', 'L black_pixel', - 'L input_masks', - 'S pixel_width', - 'S pixel_height', - 'S mm_width', - 'S mm_height', - 'S min_installed_maps', + 'L input_masks', + 'S pixel_width', + 'S pixel_height', + 'S mm_width', + 'S mm_height', + 'S min_installed_maps', 'S max_installed_maps', - 'L root_visual', + 'L root_visual', 'C root_depth', 'C backing_stores', 'C root_depth', 'C num_depths' - ], + ], function () { var depths = {}; readDepths(bl, display, depths, scr.num_depths, function() { @@ -86,7 +86,7 @@ function readScreens(bl, display, cbDisplayReady) scr.depths = depths; delete scr.num_depths; display.screen.push(scr); - + if (display.screen.length == display.screen_num) { delete display.screen_num; @@ -96,7 +96,7 @@ function readScreens(bl, display, cbDisplayReady) readScreens(bl, display, cbDisplayReady); } }); - }); + }); } } @@ -104,7 +104,7 @@ function readServerHello(bl, cb) { bl.unpack('C', function(res) { - + if (res[0] == 0) { // conection time error @@ -124,10 +124,10 @@ bl.unpack('C', function(res) { 'S major', 'S minor', 'S xlen', - 'L release', - 'L resource_base', - 'L resource_mask', - 'L motion_buffer_size', + 'L release', + 'L resource_base', + 'L resource_mask', + 'L motion_buffer_size', 'S vlen', 'S max_request_length', 'C screen_num', @@ -139,8 +139,8 @@ bl.unpack('C', function(res) { 'C min_keycode', 'C max_keycode', 'xxxx' - ], - + ], + function() { var pvlen = xutil.padded_length(display.vlen); @@ -148,12 +148,12 @@ bl.unpack('C', function(res) { // setup data to generate resource id // TODO: cleaunup code here var mask = display.resource_mask; - display.rsrc_shift = 0; + display.rsrc_shift = 0; while (!( (mask >> display.rsrc_shift) & 1) ) display.rsrc_shift++; display.rsrc_id = 0; - bl.get(pvlen, function(vendor) + bl.get(pvlen, function(vendor) { display.vendor = vendor.toString().substr(0, display.vlen); // utf8 by default? @@ -172,7 +172,7 @@ bl.unpack('C', function(res) { readScreens(bl, display, cb); } }); - } + } }); } ); @@ -191,23 +191,24 @@ function getByteOrder() { function writeClientHello(stream, displayNum, authHost) { - getAuthString( displayNum, authHost, function( authType, authData ) { + getAuthString( displayNum, authHost, function( err, cookie ) { + debugger; var byte_order = getByteOrder(); var protocol_major = 11; // TODO: config? env? var protocol_minor = 0; stream.pack( - 'CxSSSSxxpp', - [ + 'CxSSSSxxpp', + [ byte_order, protocol_major, protocol_minor, - authType.length, - authData.length, - authType, - authData + cookie.authName.length, + cookie.authData.length, + cookie.authName, + cookie.authData ] ); - stream.flush(); + stream.flush(); }); } diff --git a/lib/xcore.js b/lib/xcore.js index 569a747..350b270 100644 --- a/lib/xcore.js +++ b/lib/xcore.js @@ -520,8 +520,7 @@ XClient.prototype.expectReplyHeader = function() ); } -XClient.prototype.startHandshake = function() -{ +XClient.prototype.startHandshake = function() { var client = this; handshake.writeClientHello(this.pack_stream, this.displayNum, this.authHost);