VNC authentication works, although there is no UI for adding passwords

yet. Direct database manipulation is required for now.
This commit is contained in:
Simo Kinnunen
2015-10-13 03:14:18 +09:00
parent a902c66131
commit 5b5520b705
8 changed files with 332 additions and 32 deletions

View File

@@ -1,10 +1,13 @@
var util = require('util')
var os = require('os')
var crypto = require('crypto')
var EventEmitter = require('eventemitter3').EventEmitter
var debug = require('debug')('vnc:connection')
var Promise = require('bluebird')
var PixelFormat = require('./pixelformat')
var vncauth = require('../../../../../util/vncauth')
function VncConnection(conn, options) {
this.options = options
@@ -21,7 +24,15 @@ function VncConnection(conn, options) {
this._changeState(VncConnection.STATE_NEED_CLIENT_VERSION)
this._serverVersion = VncConnection.V3_008
this._serverSupportedSecurity = [VncConnection.SECURITY_NONE]
this._serverSupportedSecurity = this.options.security
this._serverSupportedSecurityByType =
this.options.security.reduce(
function(map, method) {
map[method.type] = method
return map
}
, Object.create(null)
)
this._serverWidth = this.options.width
this._serverHeight = this.options.height
this._serverPixelFormat = new PixelFormat({
@@ -45,12 +56,16 @@ function VncConnection(conn, options) {
this._clientEncodings = []
this._clientCutTextLength = 0
this._authChallenge = this.options.challenge || crypto.randomBytes(16)
this.conn = conn
.on('error', this._bound._errorListener)
.on('readable', this._bound._readableListener)
.on('end', this._bound._endListener)
.on('close', this._bound._closeListener)
this._blockingOps = []
this._writeServerVersion()
this._read()
}
@@ -80,6 +95,7 @@ var StateReverse = Object.create(null), State = {
STATE_NEED_CLIENT_VERSION: 10
, STATE_NEED_CLIENT_SECURITY: 20
, STATE_NEED_CLIENT_INIT: 30
, STATE_NEED_CLIENT_VNC_AUTH: 31
, STATE_NEED_CLIENT_MESSAGE: 40
, STATE_NEED_CLIENT_MESSAGE_SETPIXELFORMAT: 50
, STATE_NEED_CLIENT_MESSAGE_SETENCODINGS: 60
@@ -171,18 +187,12 @@ VncConnection.prototype._writeSupportedSecurity = function() {
chunk[0] = this._serverSupportedSecurity.length
this._serverSupportedSecurity.forEach(function(security, i) {
chunk[1 + i] = security
chunk[1 + i] = security.type
})
this._write(chunk)
}
VncConnection.prototype._writeSelectedSecurity = function() {
var chunk = new Buffer(4)
chunk.writeUInt32BE(VncConnection.SECURITY_NONE, 0)
this._write(chunk)
}
VncConnection.prototype._writeSecurityResult = function(result, reason) {
var chunk
switch (result) {
@@ -224,11 +234,40 @@ VncConnection.prototype._writeServerInit = function() {
this._write(chunk)
}
VncConnection.prototype._writeVncAuthChallenge = function() {
var vncSec = this._serverSupportedSecurityByType[VncConnection.SECURITY_VNC]
debug('vnc auth challenge', vncSec.challenge)
this._write(vncSec.challenge)
}
VncConnection.prototype._readableListener = function() {
this._read()
}
VncConnection.prototype._read = function() {
Promise.all(this._blockingOps).bind(this)
.then(this._unguardedRead)
}
VncConnection.prototype._auth = function(type, data) {
var security = this._serverSupportedSecurityByType[type]
this._blockingOps.push(
security.auth(data).bind(this)
.then(function() {
this._changeState(VncConnection.STATE_NEED_CLIENT_INIT)
this._writeSecurityResult(VncConnection.SECURITYRESULT_OK)
this.emit('authenticated')
this._read()
})
.catch(function() {
this._writeSecurityResult(
VncConnection.SECURITYRESULT_FAIL, 'Authentication failure')
this.end()
})
)
}
VncConnection.prototype._unguardedRead = function() {
var chunk, lo, hi
while (this._append(this.conn.read())) {
do {
@@ -250,14 +289,35 @@ VncConnection.prototype._read = function() {
if ((chunk = this._consume(1))) {
if ((this._clientSecurity = this._parseSecurity(chunk)) === null) {
this._writeSecurityResult(
VncConnection.SECURITYRESULT_FAIL, 'Unsupported security type')
VncConnection.SECURITYRESULT_FAIL, 'Unimplemented security type')
this.end()
return
}
debug('client security', this._clientSecurity)
this._writeSecurityResult(VncConnection.SECURITYRESULT_OK)
this.emit('authenticated')
this._changeState(VncConnection.STATE_NEED_CLIENT_INIT)
if (!(this._clientSecurity in this._serverSupportedSecurityByType)) {
this._writeSecurityResult(
VncConnection.SECURITYRESULT_FAIL, 'Unsupported security type')
this.end()
return
}
switch (this._clientSecurity) {
case VncConnection.SECURITY_NONE:
this._auth(VncConnection.SECURITY_NONE)
return
case VncConnection.SECURITY_VNC:
this._writeVncAuthChallenge()
this._changeState(VncConnection.STATE_NEED_CLIENT_VNC_AUTH)
break
}
}
break
case VncConnection.STATE_NEED_CLIENT_VNC_AUTH:
if ((chunk = this._consume(16))) {
this._auth(VncConnection.SECURITY_VNC, {
response: chunk
, fingerprint: vncauth.format(chunk)
})
return
}
break
case VncConnection.STATE_NEED_CLIENT_INIT:
@@ -284,14 +344,17 @@ VncConnection.prototype._read = function() {
VncConnection.STATE_NEED_CLIENT_MESSAGE_FBUPDATEREQUEST)
break
case VncConnection.CLIENT_MESSAGE_KEYEVENT:
this.emit('userActivity')
this._changeState(
VncConnection.STATE_NEED_CLIENT_MESSAGE_KEYEVENT)
break
case VncConnection.CLIENT_MESSAGE_POINTEREVENT:
this.emit('userActivity')
this._changeState(
VncConnection.STATE_NEED_CLIENT_MESSAGE_POINTEREVENT)
break
case VncConnection.CLIENT_MESSAGE_CLIENTCUTTEXT:
this.emit('userActivity')
this._changeState(
VncConnection.STATE_NEED_CLIENT_MESSAGE_CLIENTCUTTEXT)
break