Fix auth for remote hosts and handle different auth families

- Use the remote address to find the auth cookie instead of the local
  hostname
- Read family type as big endian in Xauthority file
- Don't upgrade 127.0.0.1 TCP connections to unix domain socket (libX11
  and xcb don't do this)
- Don't error if no auth cookie is found; continue without auth
This commit is contained in:
Ian Scott 2016-03-21 16:00:52 -07:00
parent edbe678f84
commit e8883275bf
3 changed files with 30 additions and 15 deletions

View file

@ -1,4 +1,5 @@
// TODO: http://en.wikipedia.org/wiki/X_Window_authorization // TODO: differentiate between auth types (i.e., MIT-MAGIC-COOKIE-1 and XDM-AUTHORIZATION-1)
// and choose the best based on the algorithm in libXau's XauGetBestAuthByAddr
var fs = require('fs'); var fs = require('fs');
var Buffer = require('buffer').Buffer; var Buffer = require('buffer').Buffer;
@ -15,7 +16,7 @@ var typeToName = {
1: 'DECnet', 1: 'DECnet',
2: 'Chaos', 2: 'Chaos',
5: 'ServerInterpreted', 5: 'ServerInterpreted',
6: 'InternetV6' 6: 'Internet6'
}; };
function parseXauth( buf ) function parseXauth( buf )
@ -27,7 +28,7 @@ function parseXauth( buf )
while (offset < buf.length) while (offset < buf.length)
{ {
var cookie = {}; var cookie = {};
cookie.type = buf.readUInt16LE(offset); cookie.type = buf.readUInt16BE(offset);
if (!typeToName[cookie.type]) { if (!typeToName[cookie.type]) {
console.warn('Unknown address type'); console.warn('Unknown address type');
} }
@ -73,8 +74,16 @@ function readXauthority(cb) {
}); });
} }
module.exports = function( display, host, cb ) module.exports = function( display, host, socketFamily, cb )
{ {
var family;
if (socketFamily === 'IPv4') {
family = 0; // Internet
} else if (socketFamily === 'IPv6') {
family = 6; // Internet6
} else {
family = 256; // Local
}
readXauthority(function(err, data) { readXauthority(function(err, data) {
if(err) return cb(err); if(err) return cb(err);
@ -84,15 +93,18 @@ module.exports = function( display, host, cb )
authData: '' authData: ''
}); });
} }
var auth = parseXauth(data); var auth = parseXauth(data);
for (var cookieNum in auth) for (var cookieNum in auth)
{ {
var cookie = auth[cookieNum]; var cookie = auth[cookieNum];
if ((typeToName[cookie.family] === 'Wild' || cookie.address === host) && if ((typeToName[cookie.family] === 'Wild' || (cookie.type === family && cookie.address === host)) &&
(cookie.display.length === 0 || cookie.display === display)) (cookie.display.length === 0 || cookie.display === display))
return cb( null, cookie ); return cb( null, cookie );
} }
cb(new Error('No auth cookie matching display=' + display + ' and host=' + host)); // If no cookie is found, proceed without authentication
cb(null, {
authName: '',
authData: ''
});
}); });
}; };

View file

@ -189,9 +189,9 @@ function getByteOrder() {
} }
} }
function writeClientHello(stream, displayNum, authHost) function writeClientHello(stream, displayNum, authHost, authFamily)
{ {
getAuthString( displayNum, authHost, function( err, cookie ) { getAuthString( displayNum, authHost, authFamily, function( err, cookie ) {
if (err) { if (err) {
throw err; throw err;
} }

View file

@ -31,7 +31,6 @@ function XClient(displayNum, screenNum, options)
this.displayNum = displayNum; this.displayNum = displayNum;
this.screenNum = screenNum; this.screenNum = screenNum;
this.authHost = os.hostname();
} }
util.inherits(XClient, EventEmitter); util.inherits(XClient, EventEmitter);
@ -39,6 +38,13 @@ XClient.prototype.init = function(stream)
{ {
this.stream = stream; this.stream = stream;
this.authHost = stream.remoteAddress;
this.authFamily = stream.remoteFamily;
if (!this.authHost || this.authHost === '127.0.0.1' || this.authHost === '::1') {
this.authHost = os.hostname();
this.authFamily = null;
}
var pack_stream = new PackStream(); var pack_stream = new PackStream();
// data received from stream is dispached to // data received from stream is dispached to
@ -524,7 +530,7 @@ XClient.prototype.expectReplyHeader = function()
XClient.prototype.startHandshake = function() { XClient.prototype.startHandshake = function() {
var client = this; var client = this;
handshake.writeClientHello(this.pack_stream, this.displayNum, this.authHost); handshake.writeClientHello(this.pack_stream, this.displayNum, this.authHost, this.authFamily);
handshake.readServerHello(this.pack_stream, function(display) handshake.readServerHello(this.pack_stream, function(display)
{ {
// TODO: readServerHello can set error state in display // TODO: readServerHello can set error state in display
@ -560,8 +566,6 @@ module.exports.createClient = function(options, initCb)
throw new Error("Cannot parse display"); throw new Error("Cannot parse display");
var host = displayMatch[1]; var host = displayMatch[1];
if (!host)
host = '127.0.0.1';
var displayNum = displayMatch[2]; var displayNum = displayMatch[2];
if (!displayNum) if (!displayNum)
@ -586,10 +590,9 @@ module.exports.createClient = function(options, initCb)
{ {
socketPath = display; socketPath = display;
} }
} else if(host == '127.0.0.1') //TODO check if it's consistent with xlib (DISPLAY=127.0.0.1:0 -> local unix socket or port 6000?) } else if(!host)
socketPath = '/tmp/.X11-unix/X' + displayNum; socketPath = '/tmp/.X11-unix/X' + displayNum;
} }
//socketPath = '/tmp/.X11-unix/X' + displayNum;
var client = new XClient(displayNum, screenNum, options); var client = new XClient(displayNum, screenNum, options);
var connectStream = function() { var connectStream = function() {