From 0a81b9fdf82863da19dcf3a5e59b3843e3cb3bd1 Mon Sep 17 00:00:00 2001 From: sidorares Date: Mon, 1 Aug 2011 16:13:44 +1000 Subject: [PATCH] .Xauth-based authorisation --- lib/x11/auth.js | 92 ++++++++++++++++++++++++++++++++++++++--- lib/x11/handshake.js | 4 +- lib/x11/unpackbuffer.js | 5 +++ lib/x11/xcore.js | 41 +++++++++++++----- 4 files changed, 123 insertions(+), 19 deletions(-) diff --git a/lib/x11/auth.js b/lib/x11/auth.js index 6831e15..d12a54b 100644 --- a/lib/x11/auth.js +++ b/lib/x11/auth.js @@ -1,11 +1,91 @@ // TODO: http://en.wikipedia.org/wiki/X_Window_authorization -module.exports = function( cb ) +var fs = require('fs'); +var Buffer = require('buffer').Buffer; +// add 'unpack' method for buffer +require('./unpackbuffer').addUnpack(Buffer); + +function parseXauth( buf ) { - // empty yet - var authType = ''; - var authData = ''; - cb( authType, authData ); + var offset = 0; + var auth = []; + + while (offset < buf.length) + { + var cookie = {}; + var typeToName = { + 256: 'Local', + 65535: 'Wild', + 254: 'Netname', + 253: 'Krb5Principal', + 252: 'LocalHost', + 0: 'Internet', + 1: 'DECnet', + 2: 'Chaos', + 5: 'ServerInterpreted', + 6: 'InternetV6' + }; + cookie.type = buf.unpack('n')[0]; + offset += 2; + console.log(cookie.type); + // TODO: rewrite following using loop (16bits length + string data) + var addressLen = buf.unpack('n', offset)[0]; + offset += 2; + console.log(addressLen); + cookie.address = buf.unpackString(addressLen, offset); + offset += addressLen; + var displayNumLen = buf.unpack('n', offset)[0]; + console.log(displayNumLen); + offset += 2; + cookie.display = buf.unpackString(displayNumLen, offset); + offset += displayNumLen; + var authNameLen = buf.unpack('n', offset)[0]; + offset += 2; + console.log(authNameLen); + cookie.authName = buf.unpackString(authNameLen, offset); + offset += authNameLen; + var authDataLen = buf.unpack('n', offset)[0]; + offset += 2; + console.log(authDataLen); + cookie.authData = buf.unpackString(authDataLen, offset); + offset += authDataLen; + auth.push(cookie); + } + return auth; } -// TODO: rewrite to allow negotiation of auth type with server +module.exports = function( display, host, cb ) +{ + var XAuthorityFile = process.env.XAUTHORITY; + if (!XAuthorityFile) + { + 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'; + } + fs.readFile(XAuthorityFile, function (err, data) { + + if (err) throw err; + + var auth = parseXauth(data); + for (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; + + }); + } +} \ No newline at end of file diff --git a/lib/x11/handshake.js b/lib/x11/handshake.js index 0a56de2..e23e74c 100644 --- a/lib/x11/handshake.js +++ b/lib/x11/handshake.js @@ -180,9 +180,9 @@ bl.unpack('C', function(res) { } -function writeClientHello(stream) +function writeClientHello(stream, displayNum, authHost) { - getAuthString( function( authType, authData ) { + getAuthString( displayNum, authHost, function( authType, authData ) { authType = xutil.padded_string( authType ); authData = xutil.padded_string( authData ); var byte_order = 'l'.charCodeAt(0); // TODO: byteorder!!! diff --git a/lib/x11/unpackbuffer.js b/lib/x11/unpackbuffer.js index 4ed0c49..fbe47b1 100644 --- a/lib/x11/unpackbuffer.js +++ b/lib/x11/unpackbuffer.js @@ -30,6 +30,11 @@ module.exports.addUnpack = function(Buffer) var b2 = this[offset++]; data.push(b2*256+b1); break; + case 'n': + var b1 = this[offset++]; + var b2 = this[offset++]; + data.push(b1*256+b2); + break; case 'L': var b1 = this[offset++]; var b2 = this[offset++]; diff --git a/lib/x11/xcore.js b/lib/x11/xcore.js index 5465558..878b09c 100644 --- a/lib/x11/xcore.js +++ b/lib/x11/xcore.js @@ -13,6 +13,8 @@ var Buffer = require('buffer').Buffer; // add 'unpack' method for buffer require('./unpackbuffer').addUnpack(Buffer); +var os = require('os'); + var xerrors = require('./xerrors'); var coreRequests = require('./corereqs'); var stdatoms = require('./stdatoms'); @@ -281,7 +283,7 @@ XClient.prototype.startHandshake = function() { var client = this; - handshake.writeClientHello(this.pack_stream); + handshake.writeClientHello(this.pack_stream, this.displayNum, this.authHost); handshake.readServerHello(this.pack_stream, function(display) { // TODO: readServerHello can set erro state in display @@ -300,20 +302,37 @@ var platformDefaultTransport = { // TODO: check process.platform on SmartMachine solaris box } -module.exports.createClient = function(initCb) +module.exports.createClient = function(initCb, display) { - // TODO: parse $DISPLAY + if (!display) + display = process.env.DISPLAY; + if (!display) + display = ':0'; + + var displayMatch = display.match(/^(?:[^:]*?\/)?(.*):(\d+)(?:.(\d+))?$/); + var host = displayMatch[1]; + if (!host) + host = '127.0.0.1'; + var displayNum = displayMatch[2]; + if (!displayNum) + displayNum = 0; + var screenNum = displayMatch[3]; + if (!screenNum) + screenNum = 0; - // open stream - var stream; - var defaultTransportName = platformDefaultTransport[process.platform]; - // use tcp if stated explicitly or if not defined at all - if (!defaultTransportName || defaultTransportName == 'tcp') - stream = net.createConnection(6000); - if (defaultTransportName == 'unix') - stream = net.createConnection('/tmp/.X11-unix/X0'); + // open stream + var stream; + var defaultTransportName = platformDefaultTransport[process.platform]; + // use tcp if stated explicitly or if not defined at all + if (!defaultTransportName || defaultTransportName == 'tcp' || host != '127.0.0.1') + stream = net.createConnection(6000 + displayNum, host); + if (defaultTransportName == 'unix' && host == '127.0.0.1') + stream = net.createConnection('/tmp/.X11-unix/X' + displayNum); var client = new XClient(stream); + client.displayNum = displayNum; + client.screenNum = screenNum; + client.authHost = os.hostname(); if (initCb) { client.on('connect', function(display) {