Comparing version 0.2.19 to 0.2.20
@@ -48,2 +48,3 @@ var inherits = require('util').inherits, | ||
this._callbacks = []; | ||
this._hasX11 = false; | ||
@@ -248,5 +249,4 @@ var onDrain = function() { | ||
if (had_err) | ||
cb(new Error('Unable to request a pseudo-terminal')); | ||
else | ||
cb(); | ||
return cb(new Error('Unable to request a pseudo-terminal')); | ||
cb(); | ||
}); | ||
@@ -388,2 +388,52 @@ | ||
Channel.prototype._sendX11 = function(cfg, cb) { | ||
// Note: CHANNEL_REQUEST does not consume window space | ||
/* | ||
byte SSH_MSG_CHANNEL_REQUEST | ||
uint32 recipient channel | ||
string "x11-req" | ||
boolean want reply | ||
boolean single connection | ||
string x11 authentication protocol | ||
string x11 authentication cookie | ||
uint32 x11 screen number | ||
*/ | ||
this._conn._debug&&this._conn._debug('DEBUG: Channel: Sent CHANNEL_REQUEST (x11)'); | ||
var self = this; | ||
var protolen = Buffer.byteLength(cfg.proto), | ||
cookielen = Buffer.byteLength(cfg.cookie), | ||
buf = new Buffer(1 + 4 + 4 + 7 + 1 + 1 + 4 + protolen + 4 + cookielen + 4); | ||
buf[0] = MESSAGE.CHANNEL_REQUEST; | ||
buf.writeUInt32BE(this.outgoing.id, 1, true); | ||
buf.writeUInt32BE(7, 5, true); | ||
buf.write('x11-req', 9, 7, 'ascii'); | ||
buf[16] = 1; | ||
buf[17] = (cfg.single ? 1 : 0); | ||
buf.writeUInt32BE(protolen, 18, true); | ||
var bp = 22; | ||
if (Buffer.isBuffer(cfg.proto)) | ||
cfg.proto.copy(buf, bp); | ||
else | ||
buf.write(cfg.proto, bp, protolen, 'utf8'); | ||
bp += protolen; | ||
buf.writeUInt32BE(cookielen, bp, true); | ||
bp += 4; | ||
if (Buffer.isBuffer(cfg.cookie)) | ||
cfg.cookie.copy(buf, bp); | ||
else | ||
buf.write(cfg.cookie, bp, cookielen, 'utf8'); | ||
bp += cookielen; | ||
buf.writeUInt32BE((cfg.screen || 0), bp, true); | ||
this._callbacks.push(function(had_err) { | ||
if (had_err) | ||
return cb(new Error('Unable to request X11')); | ||
self._hasX11 = true; | ||
++self._conn._acceptX11; | ||
cb(); | ||
}); | ||
return this._conn._send(buf); | ||
}; | ||
Channel.prototype._sendSubsystem = function(name, cb) { | ||
@@ -708,2 +758,4 @@ // Note: CHANNEL_REQUEST does not consume window space | ||
} | ||
if (this._channel._hasX11) | ||
--this._channel._conn._acceptX11; | ||
this._cleanup(); | ||
@@ -719,2 +771,4 @@ return ret; | ||
if (this._channel) { | ||
if (this._channel._hasX11) | ||
this._channel._hasX11 = false; | ||
this._channel._conn._sock.removeListener('end', this._sockOnEnd); | ||
@@ -721,0 +775,0 @@ this._channel._conn._sock.removeListener('close', this._sockOnEnd); |
@@ -57,2 +57,6 @@ var i = 0, keys, len; | ||
exports.USERAUTH_INFO_RESPONSE = 61; | ||
exports.KEXDH_GEX_REQUEST = 34; | ||
exports.KEXDH_GEX_GROUP = 31; | ||
exports.KEXDH_GEX_INIT = 32; | ||
exports.KEXDH_GEX_REPLY = 33; | ||
@@ -220,2 +224,8 @@ var DISCONNECT_REASON = exports.DISCONNECT_REASON = { | ||
].concat(CIPHER); | ||
KEX = [ | ||
'diffie-hellman-group-exchange-sha256', | ||
'diffie-hellman-group-exchange-sha1' | ||
].concat(KEX); | ||
KEX_LIST = new Buffer(KEX.join(',')); | ||
} | ||
@@ -222,0 +232,0 @@ CIPHER = [ |
@@ -41,3 +41,10 @@ // TODO: * Filter control codes from strings | ||
var i = start, buffer, skipDecrypt = false, buf, self = this, p = i, r; | ||
var i = start, | ||
buffer, | ||
skipDecrypt = false, | ||
buf, | ||
self = this, | ||
p = i, | ||
r, | ||
doDecryptGCM = false; | ||
@@ -153,3 +160,3 @@ while (true) { | ||
this.debug&&this.debug('DEBUG: Parser: STATE_PACKET'); | ||
var doDecryptGCM = (this._decrypt && isGCM(this._decryptType)); | ||
doDecryptGCM = (this._decrypt && isGCM(this._decryptType)); | ||
if (this._decrypt && !isGCM(this._decryptType)) | ||
@@ -187,3 +194,3 @@ buffer = this.decrypt(buffer); | ||
this.debug&&this.debug('DEBUG: Parser: STATE_PACKETDATA'); | ||
var doDecryptGCM = (this._decrypt && isGCM(this._decryptType)); | ||
doDecryptGCM = (this._decrypt && isGCM(this._decryptType)); | ||
if (this._decrypt && !skipDecrypt && !doDecryptGCM) | ||
@@ -236,3 +243,7 @@ buffer = this.decrypt(buffer); | ||
this.debug('DEBUG: Parser: STATE_PACKETDATAAFTER, packet: USERAUTH_PK_OK'); | ||
} else { | ||
} else if (this._payload[0] === 31 && this._kexdh !== 'group') | ||
this.debug('DEBUG: Parser: STATE_PACKETDATAAFTER, packet: KEXDH_GEX_GROUP'); | ||
else if (this._payload[0] === 33 && this._kexdh !== 'group') | ||
this.debug('DEBUG: Parser: STATE_PACKETDATAAFTER, packet: KEXDH_GEX_REPLY'); | ||
else { | ||
this.debug('DEBUG: Parser: STATE_PACKETDATAAFTER, packet: ' | ||
@@ -443,21 +454,18 @@ + MESSAGE[this._payload[0]]); | ||
this.parseKEXInit(); | ||
else if (type === MESSAGE.KEXDH_REPLY) { | ||
/* | ||
byte SSH_MSG_KEXDH_REPLY | ||
string server public host key and certificates (K_S) | ||
mpint f | ||
string signature of H | ||
*/ | ||
info = { | ||
hostkey: readString(payload, 1), | ||
hostkey_format: undefined, | ||
pubkey: readString(payload, payload._pos), | ||
sig: readString(payload, payload._pos), | ||
sig_format: undefined | ||
}; | ||
info.hostkey_format = readString(info.hostkey, 0, 'ascii'); | ||
info.sig_format = readString(info.sig, 0, 'ascii'); | ||
this.emit('KEXDH_REPLY', info); | ||
} else if (type === MESSAGE.NEWKEYS) { | ||
else if (type === 31) { // key exchange method-specific message | ||
if (this._kexdh !== 'group') { | ||
/* | ||
byte SSH_MSG_KEX_DH_GEX_GROUP | ||
mpint p, safe prime | ||
mpint g, generator for subgroup in GF(p) | ||
*/ | ||
var prime = readString(payload, 1), | ||
gen = readString(payload, payload._pos); | ||
this.emit('KEXDH_GEX_GROUP', prime, gen); | ||
} else | ||
this.parseKEXDH_REPLY(); | ||
} else if (type === consts.KEXDH_GEX_REPLY) | ||
this.parseKEXDH_REPLY(); | ||
else if (type === MESSAGE.NEWKEYS) { | ||
/* | ||
byte SSH_MSG_NEW_KEYS | ||
@@ -527,2 +535,21 @@ */ | ||
this.emit('CHANNEL_OPEN', channel); | ||
} else if (chanType === 'x11') { | ||
/* | ||
string originator address (e.g., "192.168.7.38") | ||
uint32 originator port | ||
*/ | ||
var channel = { | ||
type: chanType, | ||
sender: payload.readUInt32BE(payload._pos, true), | ||
window: payload.readUInt32BE(payload._pos += 4, true), | ||
packetSize: payload.readUInt32BE(payload._pos += 4, true), | ||
data: { | ||
srcIP: readString(payload, payload._pos += 4, 'ascii'), | ||
srcPort: payload.readUInt32BE(payload._pos, true) | ||
} | ||
}; | ||
this.emit('CHANNEL_OPEN', channel); | ||
} else { | ||
// allow connection to reject unsupported channel open requests | ||
this.emit('CHANNEL_OPEN', { type: chanType }); | ||
} | ||
@@ -644,2 +671,22 @@ } else if (type === MESSAGE.CHANNEL_OPEN_CONFIRMATION) { | ||
Parser.prototype.parseKEXDH_REPLY = function() { | ||
var payload = this._payload; | ||
/* | ||
byte SSH_MSG_KEXDH_REPLY / SSH_MSG_KEX_DH_GEX_REPLY | ||
string server public host key and certificates (K_S) | ||
mpint f | ||
string signature of H | ||
*/ | ||
var info = { | ||
hostkey: readString(payload, 1), | ||
hostkey_format: undefined, | ||
pubkey: readString(payload, payload._pos), | ||
sig: readString(payload, payload._pos), | ||
sig_format: undefined | ||
}; | ||
info.hostkey_format = readString(info.hostkey, 0, 'ascii'); | ||
info.sig_format = readString(info.sig, 0, 'ascii'); | ||
this.emit('KEXDH_REPLY', info); | ||
}; | ||
Parser.prototype.hmacVerify = function(hmac) { | ||
@@ -716,2 +763,3 @@ this.debug&&this.debug('DEBUG: Parser: Verifying MAC'); | ||
this._kexinit = undefined; | ||
this._kexdh = undefined; | ||
}; | ||
@@ -718,0 +766,0 @@ |
{ "name": "ssh2", | ||
"version": "0.2.19", | ||
"version": "0.2.20", | ||
"author": "Brian White <mscdex@mscdex.net>", | ||
@@ -4,0 +4,0 @@ "description": "An SSH2 client module written in pure JavaScript for node.js", |
@@ -351,2 +351,42 @@ Description | ||
* Forward X11 connections (xeyes): | ||
```javascript | ||
var net = require('net'), | ||
Connection = require('ssh2'); | ||
var conn = new Connection(); | ||
conn.on('x11', function(info, accept, reject) { | ||
var xserversock = new net.Socket(); | ||
xserversock.on('connect', function() { | ||
var xclientsock = accept(); | ||
xclientsock.pipe(xserversock).pipe(xclientsock); | ||
}); | ||
// connects to localhost:0.0 | ||
xserversock.connect(6000, 'localhost'); | ||
}); | ||
conn.on('ready', function() { | ||
conn.exec('xeyes', { x11: true }, function(err, stream) { | ||
if (err) throw err; | ||
var code = 0; | ||
stream.on('end', function() { | ||
if (code !== 0) | ||
console.log('Do you have X11 forwarding enabled on your SSH server?'); | ||
conn.end(); | ||
}); | ||
stream.on('exit', function(exitcode) { | ||
code = exitcode; | ||
}); | ||
}); | ||
}); | ||
conn.connect({ | ||
host: '192.168.1.1', | ||
username: 'foo', | ||
password: 'bar' | ||
}); | ||
``` | ||
* Invoke an arbitrary subsystem (netconf in this example): | ||
@@ -417,2 +457,8 @@ | ||
* **x11**(< _object_ >details, < _function_ >accept, < _function_ >reject) - An incoming X11 connection is being requested. Calling `accept` accepts the connection and returns a `ChannelStream` object. Calling `reject` rejects the connection and no further action is needed. `details` contains: | ||
* **srcIP** - _string_ - The originating IP of the connection. | ||
* **srcPort** - _integer_ - The originating port of the connection. | ||
* **keyboard-interactive**(< _string_ >name, < _string_ >instructions, < _string_ >instructionsLang, < _array_ >prompts, < _function_ >finish) - The server is asking for replies to the given `prompts` for keyboard-interactive user authentication. `name` is generally what you'd use as a window title (for GUI apps). `prompts` is an array of `{ prompt: 'Password: ', echo: false }` style objects (here `echo` indicates whether user input should be displayed on the screen). The answers for all prompts must be provided as an array of strings and passed to `finish` when you are ready to continue. Note: It's possible for the server to come back and ask more questions. | ||
@@ -474,5 +520,11 @@ | ||
* **x11** - < _mixed_ > - Set to true to use defaults below, a number to specify a specific screen number, or an object with the following valid properties: | ||
* **single** - < _boolean_ > - Allow just a single connection? **Default:** false | ||
* **screen** - < _number_ > - Screen number to use **Default:** 0 | ||
`callback` has 2 parameters: < _Error_ >err, < _ChannelStream_ >stream. | ||
* **shell**([< _object_ >window,] < _function_ >callback) - _(void)_ - Starts an interactive shell session on the server, with optional `window` pseudo-tty settings (see 'Pseudo-TTY settings'). `callback` has 2 parameters: < _Error_ >err, < _ChannelStream_ >stream. | ||
* **shell**([[< _object_ >window,] < _object_ >options]< _function_ >callback) - _(void)_ - Starts an interactive shell session on the server, with optional `window` pseudo-tty settings (see 'Pseudo-TTY settings'). `options` supports the 'x11' option as described in exec(). `callback` has 2 parameters: < _Error_ >err, < _ChannelStream_ >stream. | ||
@@ -479,0 +531,0 @@ * **forwardIn**(< _string_ >remoteAddr, < _integer_ >remotePort, < _function_ >callback) - _(void)_ - Bind to `remoteAddr` on `remotePort` on the server and forward incoming connections. `callback` has 2 parameters: < _Error_ >err, < _integer_ >port (`port` is the assigned port number if `remotePort` was 0). Here are some special values for `remoteAddr` and their associated binding behaviors: |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
295414
6115
747