Socket
Socket
Sign inDemoInstall

ssh2

Package Overview
Dependencies
Maintainers
1
Versions
105
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ssh2 - npm Package Compare versions

Comparing version 0.2.5 to 0.2.6

39

lib/Channel.js

@@ -15,2 +15,13 @@ var inherits = require('util').inherits,

var CUSTOM_EVENTS = [
'CHANNEL_EOF',
'CHANNEL_CLOSE',
'CHANNEL_DATA',
'CHANNEL_EXTENDED_DATA',
'CHANNEL_WINDOW_ADJUST',
'CHANNEL_SUCCESS',
'CHANNEL_FAILURE',
'CHANNEL_REQUEST'
], CUSTOM_EVENTS_LEN = CUSTOM_EVENTS.length;
function Channel(info, conn) {

@@ -67,3 +78,10 @@ EventEmitter.call(this);

conn.removeListener('drain', onDrain);
stream._cleanup();
}
for (var i = 0; i < CUSTOM_EVENTS_LEN; ++i) {
// Since EventEmitters do not actually *delete* event names in the
// emitter's event array, we must do this manually so as not to leak
// our custom, channel-specific event names.
delete conn._parser._events[CUSTOM_EVENTS[i] + ':' + self.incoming.id];
}
});

@@ -499,10 +517,10 @@

this._decoder = undefined;
channel._conn._sock.once('end', function() {
this._sockOnEnd = function() {
self.writable = false;
self.readable = false;
});
channel._conn._sock.once('close', function() {
self.writable = false;
self.readable = false;
});
channel._conn._sock.removeListener('end', this._sockOnEnd);
channel._conn._sock.removeListener('close', this._sockOnEnd);
};
channel._conn._sock.once('end', this._sockOnEnd);
channel._conn._sock.once('close', this._sockOnEnd);
}

@@ -672,2 +690,7 @@ inherits(ChannelStream, Stream);

ret = this._channel.close();
this._cleanup();
return ret;
};
ChannelStream.prototype._cleanup = function() {
if (this._outbuffer.length)

@@ -677,2 +700,4 @@ this._outbuffer = [];

this._inbuffer = [];
this._channel._conn._sock.removeListener('end', this._sockOnEnd);
this._channel._conn._sock.removeListener('close', this._sockOnEnd);
this.writable = false;

@@ -683,3 +708,3 @@ this.readable = false;

this._decoder = undefined;
return ret;
this._channel = undefined;
};

@@ -686,0 +711,0 @@

984

lib/Parser.js

@@ -5,2 +5,3 @@ // TODO: * Filter control codes from strings

var crypto = require('crypto');
var StreamSearch = require('streamsearch');
var consts = require('./Parser.constants');

@@ -28,12 +29,9 @@ var inherits = require('util').inherits,

// common byte arrays for matching purposes
var EXP_BYTES_CRLF = bytes('\n'),
EXP_BYTES_SSHHEADER = bytes('SSH-');
var EXP_TYPE_HEADER = 0,
EXP_TYPE_LF = 1,
EXP_TYPE_BYTES = 2; // waits until n bytes have been seen
var EXP_TYPE_MATCH = 0, // waits for byte array match
EXP_TYPE_BYTES = 1; // waits until n bytes have been seen
function Parser() {
this.debug = undefined;
this._hmacBuf = new Buffer(9);
this._hmacBufCompute = new Buffer(9);
this.reset();

@@ -47,21 +45,16 @@ }

var i = start, buffer, skipDecrypt = false, j, info, buf, lang, message;
var i = start, buffer, skipDecrypt = false, j, info, buf, lang, message,
self = this, p = i;
while (true) {
// begin expecting bytes handlers
if (this._expectLen) {
if (this._expectType !== undefined) {
if (i >= end)
break;
// simple case: just counting n bytes
if (this._expectType === EXP_TYPE_BYTES) {
if (this._expectBuf) {
this._expectBuf[this._expectPtr++] = b[i++];
if (this._expectPtr === this._expectLen) {
if (this._expectPtr === this._expect) {
buffer = this._expectBuf;
this._expectBuf = undefined;
this._expectBufLen = 0;
this._expectPtr = 0;
this._expectLen = undefined;
this._expect = undefined;
this._expectType = undefined;
start = i;
}

@@ -71,90 +64,62 @@ } else

continue;
}
// complex case: searching for byte array match
if (b[i] === this._expect[this._expectPtr])
++this._expectPtr;
else {
if (this._expectPtr > 0) {
if (i - start > 0) {
buf = new Buffer(i - start);
b.copy(buf, 0, start, start + (i - start));
} else {
buf = new Buffer(this._expectPtr);
for (j = 0; j < this._expectPtr; ++j)
buf[j] = this._expect[j];
} else if (this._expectType === EXP_TYPE_HEADER) {
this._ss.push(b);
if (this._expectType !== undefined)
continue;
} else if (this._expectType === EXP_TYPE_LF) {
if (b[i] === 0x0A) {
this._expectType = undefined;
if (p < i) {
if (this._expectBuf === undefined)
this._expectBuf = b.toString('ascii', p, i);
else
this._expectBuf += b.toString('ascii', p, i);
}
if (this._expectBuf !== undefined) {
this._expectBuf.push(buf);
this._expectBufLen += buf.length;
}
start = i;
}
this._expectPtr = 0;
if (b[i] === this._expect[this._expectPtr])
++this._expectPtr;
}
++i;
if (this._expectPtr < this._expectLen) {
if (this._expectPtr === 0 && i === end) {
if (this._expectBuf !== undefined) {
buf = (start === 0 ? b : b.slice(start));
this._expectBuf.push(buf);
this._expectBufLen += buf.length;
}
}
continue;
} else {
var leftovers = i - this._expectLen - start;
if (leftovers < 0)
leftovers = 0;
if (this._expectBuf !== undefined) {
var expbuflen = this._expectBuf.length;
if (expbuflen === 0) {
if (leftovers)
this._expectBuf = b.slice(start, start + leftovers);
buffer = this._expectBuf;
this._expectBuf = undefined;
++i;
} else {
if (++i === end && p < i) {
if (this._expectBuf === undefined)
this._expectBuf = b.toString('ascii', p, i);
else
this._expectBuf = null;
} else if (expbuflen === 1 && leftovers === 0)
this._expectBuf = this._expectBuf[0];
else {
buf = new Buffer(this._expectBufLen + leftovers);
var pos = 0, len = this._expectBuf.length;
for (j = 0; j < len; ++j) {
this._expectBuf[j].copy(buf, pos);
pos += this._expectBuf[j].length;
}
if (leftovers)
b.copy(buf, pos, start, start + leftovers);
this._expectBuf = buf;
this._expectBuf += b.toString('ascii', p, i);
}
continue;
}
buffer = this._expectBuf;
this._expectBuf = undefined;
this._expectBufLen = 0;
this._expectPtr = 0;
this._expectLen = undefined;
this._expect = undefined;
this._expectType = undefined;
start = i;
}
}
// end expecting bytes handlers
switch (this._state) {
case STATE_INIT:
if (this._state === STATE_INIT) {
this.debug&&this.debug('DEBUG: Parser: STATE_INIT');
// retrieve all bytes that may come before the header
this.expect(EXP_BYTES_SSHHEADER);
this.expect(EXP_TYPE_HEADER);
this._ss = new StreamSearch(new Buffer('SSH-'));
this._ss.on('info', function onInfo(matched, data, start, end) {
if (data) {
if (this._greeting === undefined)
this._greeting = data.toString('binary', start, end);
else
this._greeting += data.toString('binary', start, end);
}
if (matched) {
if (end !== undefined)
i = end;
else
i += 4;
self._expectType = undefined;
self._ss.removeListener('info', onInfo);
}
});
this._state = STATE_GREETING;
break;
case STATE_GREETING:
} else if (this._state === STATE_GREETING) {
this.debug&&this.debug('DEBUG: Parser: STATE_GREETING');
if (buffer && buffer.length)
this._greeting = buffer;
this._ss = undefined;
// retrieve the identification bytes after the "SSH-" header
this.expect(EXP_BYTES_CRLF);
p = i;
this.expect(EXP_TYPE_LF);
this._state = STATE_HEADER;
break;
case STATE_HEADER:
} else if (this._state === STATE_HEADER) {
this.debug&&this.debug('DEBUG: Parser: STATE_HEADER');
buffer = buffer.toString('ascii').trim();
buffer = buffer.trim();
var idxDash = buffer.indexOf('-'),

@@ -164,3 +129,3 @@ idxSpace = buffer.indexOf(' ');

// RFC says greeting SHOULD be utf8
greeting: (this._greeting ? this._greeting.toString('utf8') : null),
greeting: this._greeting,//(this._greeting ? this._greeting.toString('utf8') : null),
ident_raw: 'SSH-' + buffer,

@@ -183,11 +148,9 @@ versions: {

this._state = STATE_PACKETBEFORE;
break;
case STATE_PACKETBEFORE:
} else if (this._state === STATE_PACKETBEFORE) {
this.debug&&this.debug('DEBUG: Parser: STATE_PACKETBEFORE (expecting ' + this._decryptSize + ')');
// wait for the right number of bytes so we can determine the incoming
// packet length
this.expect(this._decryptSize);
this.expect(EXP_TYPE_BYTES, this._decryptSize, '_decryptBuf');
this._state = STATE_PACKET;
break;
case STATE_PACKET:
} else if (this._state === STATE_PACKET) {
this.debug&&this.debug('DEBUG: Parser: STATE_PACKET');

@@ -203,3 +166,3 @@ if (this._decrypt)

// grab the rest of the packet
this.expect(remainLen);
this.expect(EXP_TYPE_BYTES, remainLen);
this._state = STATE_PACKETDATA;

@@ -214,4 +177,3 @@ } else if (remainLen < 0)

}
break;
case STATE_PACKETDATA:
} else if (this._state === STATE_PACKETDATA) {
this.debug&&this.debug('DEBUG: Parser: STATE_PACKETDATA');

@@ -236,3 +198,3 @@ if (this._decrypt && !skipDecrypt)

this.debug&&this.debug('DEBUG: Parser: hmacSize === ' + this._hmacSize);
this.expect(this._hmacSize);
this.expect(EXP_TYPE_BYTES, this._hmacSize, '_hmacBuf');
this._state = STATE_PACKETDATAVERIFY;

@@ -244,4 +206,3 @@ this._packet = buf;

buf = undefined;
break;
case STATE_PACKETDATAVERIFY:
} else if (this._state === STATE_PACKETDATAVERIFY) {
this.debug&&this.debug('DEBUG: Parser: STATE_PACKETDATAVERIFY');

@@ -256,4 +217,3 @@ // verify packet data integrity

}
break;
case STATE_PACKETDATAAFTER:
} else if (this._state === STATE_PACKETDATAAFTER) {
if (this.debug) {

@@ -272,391 +232,3 @@ if (this._payload[0] === 60) {

}
var payload = this._payload;
if (++this._seqno > MAX_SEQNO)
this._seqno = 0;
// payload[0] === packet type
switch (payload[0]) {
case MESSAGE.IGNORE:
/*
byte SSH_MSG_IGNORE
string data
*/
break;
case MESSAGE.DISCONNECT:
/*
byte SSH_MSG_DISCONNECT
uint32 reason code
string description in ISO-10646 UTF-8 encoding
string language tag
*/
var reason = payload.readUInt32BE(1, true),
description = readString(payload, 5, 'utf8');
lang = readString(payload, payload._pos, 'ascii');
this.emit('DISCONNECT', DISCONNECT_REASON[reason],
reason, description, lang);
break;
case MESSAGE.DEBUG:
/*
byte SSH_MSG_DEBUG
boolean always_display
string message in ISO-10646 UTF-8 encoding
string language tag
*/
message = readString(payload, 2, 'utf8');
lang = readString(payload, payload._pos, 'ascii');
this.emit('DEBUG', message, lang);
break;
case MESSAGE.KEXINIT:
/*
byte SSH_MSG_KEXINIT
byte[16] cookie (random bytes)
name-list kex_algorithms
name-list server_host_key_algorithms
name-list encryption_algorithms_client_to_server
name-list encryption_algorithms_server_to_client
name-list mac_algorithms_client_to_server
name-list mac_algorithms_server_to_client
name-list compression_algorithms_client_to_server
name-list compression_algorithms_server_to_client
name-list languages_client_to_server
name-list languages_server_to_client
boolean first_kex_packet_follows
uint32 0 (reserved for future extension)
*/
var init = this._kexinit_info = {
algorithms: {
kex: undefined,
srvHostKey: undefined,
cs: {
encrypt: undefined,
mac: undefined,
compress: undefined
},
sc: {
encrypt: undefined,
mac: undefined,
compress: undefined
}
},
languages: {
cs: undefined,
sc: undefined
}
};
init.algorithms.kex = readList(payload, 17);
init.algorithms.srvHostKey = readList(payload, payload._pos);
init.algorithms.cs.encrypt = readList(payload, payload._pos);
init.algorithms.sc.encrypt = readList(payload, payload._pos);
init.algorithms.cs.mac = readList(payload, payload._pos);
init.algorithms.sc.mac = readList(payload, payload._pos);
init.algorithms.cs.compress = readList(payload, payload._pos);
init.algorithms.sc.compress = readList(payload, payload._pos);
init.languages.cs = readList(payload, payload._pos);
init.languages.sc = readList(payload, payload._pos);
this._kexinit = payload;
this.emit('KEXINIT', init);
break;
case 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);
break;
case MESSAGE.NEWKEYS:
/*
byte SSH_MSG_NEW_KEYS
*/
this.emit('NEWKEYS');
break;
case MESSAGE.SERVICE_ACCEPT:
/*
byte SSH_MSG_NEW_KEYS
*/
var serviceName = readString(payload, 1, 'ascii');
this.emit('SERVICE_ACCEPT', serviceName);
break;
case MESSAGE.USERAUTH_SUCCESS:
/*
byte SSH_MSG_USERAUTH_SUCCESS
*/
this.emit('USERAUTH_SUCCESS');
break;
case MESSAGE.USERAUTH_FAILURE:
/*
byte SSH_MSG_USERAUTH_FAILURE
name-list authentications that can continue
boolean partial success
*/
var auths = readString(payload, 1, 'ascii').split(','),
partSuccess = (payload[payload._pos] !== 0);
this.emit('USERAUTH_FAILURE', auths, partSuccess);
break;
case MESSAGE.USERAUTH_BANNER:
/*
byte SSH_MSG_USERAUTH_BANNER
string message in ISO-10646 UTF-8 encoding
string language tag
*/
message = readString(payload, 1, 'utf8');
lang = readString(payload, payload._pos, 'utf8');
this.emit('USERAUTH_BANNER', message, lang);
break;
case 60: // user auth context-specific messages
if (this._authMethod === 'password') {
/*
byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
string prompt in ISO-10646 UTF-8 encoding
string language tag
*/
message = readString(payload, 1, 'utf8');
lang = readString(payload, payload._pos, 'utf8');
this.emit('USERAUTH_PASSWD_CHANGEREQ', message, lang);
} else if (this._authMethod === 'keyboard-interactive') {
/*
byte SSH_MSG_USERAUTH_INFO_REQUEST
string name (ISO-10646 UTF-8)
string instruction (ISO-10646 UTF-8)
string language tag -- MAY be empty
int num-prompts
string prompt[1] (ISO-10646 UTF-8)
boolean echo[1]
...
string prompt[num-prompts] (ISO-10646 UTF-8)
boolean echo[num-prompts]
*/
var name, instr, nprompts;
name = readString(payload, 1, 'utf8');
instr = readString(payload, payload._pos, 'utf8');
lang = readString(payload, payload._pos, 'utf8');
nprompts = payload.readUInt32BE(payload._pos, true);
payload._pos += 4;
if (nprompts > 0) {
var prompts = new Array(nprompts);
for (var prompt = 0; prompt < nprompts; ++prompt) {
prompts.push({
prompt: readString(payload, payload._pos, 'utf8'),
echo: (payload[payload._pos++] !== 0)
});
}
this.emit('USERAUTH_INFO_REQUEST', name, instr, lang, prompts);
} else
this.emit('USERAUTH_INFO_REQUEST', name, instr, lang);
} else if (this._authMethod === 'pubkey') {
/*
byte SSH_MSG_USERAUTH_PK_OK
string public key algorithm name from the request
string public key blob from the request
*/
this.emit('USERAUTH_PK_OK');
}
break;
case MESSAGE.CHANNEL_OPEN:
/*
byte SSH_MSG_CHANNEL_OPEN
string channel type in US-ASCII only
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
.... channel type specific data follows
*/
var chanType = readString(payload, 1, 'ascii');
if (chanType === 'forwarded-tcpip') {
/*
string address that was connected
uint32 port that was connected
string originator IP address
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: {
destIP: readString(payload, payload._pos += 4, 'ascii'),
destPort: payload.readUInt32BE(payload._pos, true),
srcIP: readString(payload, payload._pos += 4, 'ascii'),
srcPort: payload.readUInt32BE(payload._pos, true)
}
};
this.emit('CHANNEL_OPEN', channel);
}
break;
case MESSAGE.CHANNEL_OPEN_CONFIRMATION:
/*
byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION
uint32 recipient channel
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
.... channel type specific data follows
*/
// "The 'recipient channel' is the channel number given in the
// original open request, and 'sender channel' is the channel number
// allocated by the other side."
info = {
recipient: payload.readUInt32BE(1, true),
sender: payload.readUInt32BE(5, true),
window: payload.readUInt32BE(9, true),
packetSize: payload.readUInt32BE(13, true),
data: undefined
};
if (payload.length > 17)
info.data = payload.slice(17);
this.emit('CHANNEL_OPEN_CONFIRMATION:' + info.recipient, info);
break;
case MESSAGE.CHANNEL_OPEN_FAILURE:
/*
byte SSH_MSG_CHANNEL_OPEN_FAILURE
uint32 recipient channel
uint32 reason code
string description in ISO-10646 UTF-8 encoding
string language tag
*/
payload._pos = 9;
info = {
recipient: payload.readUInt32BE(1, true),
reasonCode: payload.readUInt32BE(5, true),
reason: undefined,
description: readString(payload, payload._pos, 'utf8'),
lang: readString(payload, payload._pos, 'utf8')
};
info.reason = CHANNEL_OPEN_FAILURE[info.reasonCode];
this.emit('CHANNEL_OPEN_FAILURE:' + info.recipient, info);
break;
case MESSAGE.CHANNEL_DATA:
/*
byte SSH_MSG_CHANNEL_DATA
uint32 recipient channel
string data
*/
this.emit('CHANNEL_DATA:' + payload.readUInt32BE(1, true),
readString(payload, 5));
break;
case MESSAGE.CHANNEL_EXTENDED_DATA:
/*
byte SSH_MSG_CHANNEL_EXTENDED_DATA
uint32 recipient channel
uint32 data_type_code
string data
*/
this.emit('CHANNEL_EXTENDED_DATA:' + payload.readUInt32BE(1, true),
payload.readUInt32BE(5, true),
readString(payload, 9));
break;
case MESSAGE.CHANNEL_WINDOW_ADJUST:
/*
byte SSH_MSG_CHANNEL_WINDOW_ADJUST
uint32 recipient channel
uint32 bytes to add
*/
this.emit('CHANNEL_WINDOW_ADJUST:' + payload.readUInt32BE(1, true),
payload.readUInt32BE(5, true));
break;
case MESSAGE.CHANNEL_SUCCESS:
/*
byte SSH_MSG_CHANNEL_SUCCESS
uint32 recipient channel
*/
this.emit('CHANNEL_SUCCESS:' + payload.readUInt32BE(1, true));
break;
case MESSAGE.CHANNEL_FAILURE:
/*
byte SSH_MSG_CHANNEL_FAILURE
uint32 recipient channel
*/
this.emit('CHANNEL_FAILURE:' + payload.readUInt32BE(1, true));
break;
case MESSAGE.CHANNEL_EOF:
/*
byte SSH_MSG_CHANNEL_EOF
uint32 recipient channel
*/
this.emit('CHANNEL_EOF:' + payload.readUInt32BE(1, true));
break;
case MESSAGE.CHANNEL_CLOSE:
/*
byte SSH_MSG_CHANNEL_CLOSE
uint32 recipient channel
*/
this.emit('CHANNEL_CLOSE:' + payload.readUInt32BE(1, true));
break;
case MESSAGE.CHANNEL_REQUEST:
var recipient = payload.readUInt32BE(1, true),
request = readString(payload, 5, 'ascii');
if (request === 'exit-status') {
/*
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "exit-status"
boolean FALSE
uint32 exit_status
*/
info = {
recipient: recipient,
request: request,
code: payload.readUInt32BE(1 + payload._pos, true)
};
this.emit('CHANNEL_REQUEST:' + recipient, info);
} else if (request === 'exit-signal') {
/*
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "exit-signal"
boolean FALSE
string signal name (without the "SIG" prefix)
boolean core dumped
string error message in ISO-10646 UTF-8 encoding
string language tag
*/
info = {
recipient: recipient,
request: request,
signal: readString(payload, 1 + payload._pos, 'ascii'),
coredump: (payload[payload._pos] !== 0),
description: readString(payload, ++payload._pos, 'utf8'),
lang: readString(payload, payload._pos, 'utf8')
};
this.emit('CHANNEL_REQUEST:' + recipient, info);
}
break;
case MESSAGE.REQUEST_SUCCESS:
/*
byte SSH_MSG_REQUEST_SUCCESS
.... response specific data
*/
if (payload.length > 1)
this.emit('REQUEST_SUCCESS', payload.slice(1));
else
this.emit('REQUEST_SUCCESS');
break;
case MESSAGE.REQUEST_FAILURE:
/*
byte SSH_MSG_REQUEST_FAILURE
*/
this.emit('REQUEST_FAILURE');
break;
case MESSAGE.UNIMPLEMENTED:
/*
byte SSH_MSG_UNIMPLEMENTED
uint32 packet sequence number of rejected message
*/
// TODO
break;
default:
}
this.parsePacket();
if (this._state === STATE_INIT) {

@@ -668,3 +240,2 @@ // we were reset due to some error/disagreement ?

this._payload = undefined;
break;
}

@@ -676,10 +247,394 @@ if (buffer !== undefined)

Parser.prototype.parseKEXInit = function() {
var payload = this._payload;
/*
byte SSH_MSG_KEXINIT
byte[16] cookie (random bytes)
name-list kex_algorithms
name-list server_host_key_algorithms
name-list encryption_algorithms_client_to_server
name-list encryption_algorithms_server_to_client
name-list mac_algorithms_client_to_server
name-list mac_algorithms_server_to_client
name-list compression_algorithms_client_to_server
name-list compression_algorithms_server_to_client
name-list languages_client_to_server
name-list languages_server_to_client
boolean first_kex_packet_follows
uint32 0 (reserved for future extension)
*/
var init = this._kexinit_info = {
algorithms: {
kex: undefined,
srvHostKey: undefined,
cs: {
encrypt: undefined,
mac: undefined,
compress: undefined
},
sc: {
encrypt: undefined,
mac: undefined,
compress: undefined
}
},
languages: {
cs: undefined,
sc: undefined
}
};
init.algorithms.kex = readList(payload, 17);
init.algorithms.srvHostKey = readList(payload, payload._pos);
init.algorithms.cs.encrypt = readList(payload, payload._pos);
init.algorithms.sc.encrypt = readList(payload, payload._pos);
init.algorithms.cs.mac = readList(payload, payload._pos);
init.algorithms.sc.mac = readList(payload, payload._pos);
init.algorithms.cs.compress = readList(payload, payload._pos);
init.algorithms.sc.compress = readList(payload, payload._pos);
init.languages.cs = readList(payload, payload._pos);
init.languages.sc = readList(payload, payload._pos);
this._kexinit = payload;
this.emit('KEXINIT', init);
};
Parser.prototype.parseUserAuthMisc = function() {
var payload = this._payload;
if (this._authMethod === 'password') {
/*
byte SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
string prompt in ISO-10646 UTF-8 encoding
string language tag
*/
message = readString(payload, 1, 'utf8');
lang = readString(payload, payload._pos, 'utf8');
this.emit('USERAUTH_PASSWD_CHANGEREQ', message, lang);
} else if (this._authMethod === 'keyboard-interactive') {
/*
byte SSH_MSG_USERAUTH_INFO_REQUEST
string name (ISO-10646 UTF-8)
string instruction (ISO-10646 UTF-8)
string language tag -- MAY be empty
int num-prompts
string prompt[1] (ISO-10646 UTF-8)
boolean echo[1]
...
string prompt[num-prompts] (ISO-10646 UTF-8)
boolean echo[num-prompts]
*/
var name, instr, nprompts;
name = readString(payload, 1, 'utf8');
instr = readString(payload, payload._pos, 'utf8');
lang = readString(payload, payload._pos, 'utf8');
nprompts = payload.readUInt32BE(payload._pos, true);
payload._pos += 4;
if (nprompts > 0) {
var prompts = new Array(nprompts);
for (var prompt = 0; prompt < nprompts; ++prompt) {
prompts.push({
prompt: readString(payload, payload._pos, 'utf8'),
echo: (payload[payload._pos++] !== 0)
});
}
this.emit('USERAUTH_INFO_REQUEST', name, instr, lang, prompts);
} else
this.emit('USERAUTH_INFO_REQUEST', name, instr, lang);
} else if (this._authMethod === 'pubkey') {
/*
byte SSH_MSG_USERAUTH_PK_OK
string public key algorithm name from the request
string public key blob from the request
*/
this.emit('USERAUTH_PK_OK');
}
};
Parser.prototype.parseChRequest = function() {
var payload = this._payload;
var recipient = payload.readUInt32BE(1, true),
request = readString(payload, 5, 'ascii');
if (request === 'exit-status') {
/*
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "exit-status"
boolean FALSE
uint32 exit_status
*/
info = {
recipient: recipient,
request: request,
code: payload.readUInt32BE(1 + payload._pos, true)
};
this.emit('CHANNEL_REQUEST:' + recipient, info);
} else if (request === 'exit-signal') {
/*
byte SSH_MSG_CHANNEL_REQUEST
uint32 recipient channel
string "exit-signal"
boolean FALSE
string signal name (without the "SIG" prefix)
boolean core dumped
string error message in ISO-10646 UTF-8 encoding
string language tag
*/
info = {
recipient: recipient,
request: request,
signal: readString(payload, 1 + payload._pos, 'ascii'),
coredump: (payload[payload._pos] !== 0),
description: readString(payload, ++payload._pos, 'utf8'),
lang: readString(payload, payload._pos, 'utf8')
};
this.emit('CHANNEL_REQUEST:' + recipient, info);
}
};
Parser.prototype.parsePacket = function() {
var payload = this._payload;
if (++this._seqno > MAX_SEQNO)
this._seqno = 0;
// payload[0] === packet type
var type = payload[0];
if (type === MESSAGE.IGNORE) {
/*
byte SSH_MSG_IGNORE
string data
*/
} else if (type === MESSAGE.DISCONNECT) {
/*
byte SSH_MSG_DISCONNECT
uint32 reason code
string description in ISO-10646 UTF-8 encoding
string language tag
*/
var reason = payload.readUInt32BE(1, true),
description = readString(payload, 5, 'utf8');
lang = readString(payload, payload._pos, 'ascii');
this.emit('DISCONNECT', DISCONNECT_REASON[reason],
reason, description, lang);
} else if (type === MESSAGE.DEBUG) {
/*
byte SSH_MSG_DEBUG
boolean always_display
string message in ISO-10646 UTF-8 encoding
string language tag
*/
message = readString(payload, 2, 'utf8');
lang = readString(payload, payload._pos, 'ascii');
this.emit('DEBUG', message, lang);
} else if (type === MESSAGE.KEXINIT)
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) {
/*
byte SSH_MSG_NEW_KEYS
*/
this.emit('NEWKEYS');
} else if (type === MESSAGE.SERVICE_ACCEPT) {
/*
byte SSH_MSG_NEW_KEYS
*/
var serviceName = readString(payload, 1, 'ascii');
this.emit('SERVICE_ACCEPT', serviceName);
} else if (type === MESSAGE.USERAUTH_SUCCESS) {
/*
byte SSH_MSG_USERAUTH_SUCCESS
*/
this.emit('USERAUTH_SUCCESS');
} else if (type === MESSAGE.USERAUTH_FAILURE) {
/*
byte SSH_MSG_USERAUTH_FAILURE
name-list authentications that can continue
boolean partial success
*/
var auths = readString(payload, 1, 'ascii').split(','),
partSuccess = (payload[payload._pos] !== 0);
this.emit('USERAUTH_FAILURE', auths, partSuccess);
} else if (type === MESSAGE.USERAUTH_BANNER) {
/*
byte SSH_MSG_USERAUTH_BANNER
string message in ISO-10646 UTF-8 encoding
string language tag
*/
message = readString(payload, 1, 'utf8');
lang = readString(payload, payload._pos, 'utf8');
this.emit('USERAUTH_BANNER', message, lang);
} else if (type === 60) // user auth context-specific messages
this.parseUserAuthMisc();
else if (type === MESSAGE.CHANNEL_OPEN) {
/*
byte SSH_MSG_CHANNEL_OPEN
string channel type in US-ASCII only
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
.... channel type specific data follows
*/
var chanType = readString(payload, 1, 'ascii');
if (chanType === 'forwarded-tcpip') {
/*
string address that was connected
uint32 port that was connected
string originator IP address
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: {
destIP: readString(payload, payload._pos += 4, 'ascii'),
destPort: payload.readUInt32BE(payload._pos, true),
srcIP: readString(payload, payload._pos += 4, 'ascii'),
srcPort: payload.readUInt32BE(payload._pos, true)
}
};
this.emit('CHANNEL_OPEN', channel);
}
} else if (type === MESSAGE.CHANNEL_OPEN_CONFIRMATION) {
/*
byte SSH_MSG_CHANNEL_OPEN_CONFIRMATION
uint32 recipient channel
uint32 sender channel
uint32 initial window size
uint32 maximum packet size
.... channel type specific data follows
*/
// "The 'recipient channel' is the channel number given in the
// original open request, and 'sender channel' is the channel number
// allocated by the other side."
info = {
recipient: payload.readUInt32BE(1, true),
sender: payload.readUInt32BE(5, true),
window: payload.readUInt32BE(9, true),
packetSize: payload.readUInt32BE(13, true),
data: undefined
};
if (payload.length > 17)
info.data = payload.slice(17);
this.emit('CHANNEL_OPEN_CONFIRMATION:' + info.recipient, info);
} else if (type === MESSAGE.CHANNEL_OPEN_FAILURE) {
/*
byte SSH_MSG_CHANNEL_OPEN_FAILURE
uint32 recipient channel
uint32 reason code
string description in ISO-10646 UTF-8 encoding
string language tag
*/
payload._pos = 9;
info = {
recipient: payload.readUInt32BE(1, true),
reasonCode: payload.readUInt32BE(5, true),
reason: undefined,
description: readString(payload, payload._pos, 'utf8'),
lang: readString(payload, payload._pos, 'utf8')
};
info.reason = CHANNEL_OPEN_FAILURE[info.reasonCode];
this.emit('CHANNEL_OPEN_FAILURE:' + info.recipient, info);
} else if (type === MESSAGE.CHANNEL_DATA) {
/*
byte SSH_MSG_CHANNEL_DATA
uint32 recipient channel
string data
*/
this.emit('CHANNEL_DATA:' + payload.readUInt32BE(1, true),
readString(payload, 5));
} else if (type === MESSAGE.CHANNEL_EXTENDED_DATA) {
/*
byte SSH_MSG_CHANNEL_EXTENDED_DATA
uint32 recipient channel
uint32 data_type_code
string data
*/
this.emit('CHANNEL_EXTENDED_DATA:' + payload.readUInt32BE(1, true),
payload.readUInt32BE(5, true),
readString(payload, 9));
} else if (type === MESSAGE.CHANNEL_WINDOW_ADJUST) {
/*
byte SSH_MSG_CHANNEL_WINDOW_ADJUST
uint32 recipient channel
uint32 bytes to add
*/
this.emit('CHANNEL_WINDOW_ADJUST:' + payload.readUInt32BE(1, true),
payload.readUInt32BE(5, true));
} else if (type === MESSAGE.CHANNEL_SUCCESS) {
/*
byte SSH_MSG_CHANNEL_SUCCESS
uint32 recipient channel
*/
this.emit('CHANNEL_SUCCESS:' + payload.readUInt32BE(1, true));
} else if (type === MESSAGE.CHANNEL_FAILURE) {
/*
byte SSH_MSG_CHANNEL_FAILURE
uint32 recipient channel
*/
this.emit('CHANNEL_FAILURE:' + payload.readUInt32BE(1, true));
} else if (type === MESSAGE.CHANNEL_EOF) {
/*
byte SSH_MSG_CHANNEL_EOF
uint32 recipient channel
*/
this.emit('CHANNEL_EOF:' + payload.readUInt32BE(1, true));
} else if (type === MESSAGE.CHANNEL_CLOSE) {
/*
byte SSH_MSG_CHANNEL_CLOSE
uint32 recipient channel
*/
this.emit('CHANNEL_CLOSE:' + payload.readUInt32BE(1, true));
} else if (type === MESSAGE.CHANNEL_REQUEST)
this.parseChRequest();
else if (type === MESSAGE.REQUEST_SUCCESS) {
/*
byte SSH_MSG_REQUEST_SUCCESS
.... response specific data
*/
if (payload.length > 1)
this.emit('REQUEST_SUCCESS', payload.slice(1));
else
this.emit('REQUEST_SUCCESS');
} else if (type === MESSAGE.REQUEST_FAILURE) {
/*
byte SSH_MSG_REQUEST_FAILURE
*/
this.emit('REQUEST_FAILURE');
} else if (type === MESSAGE.UNIMPLEMENTED) {
/*
byte SSH_MSG_UNIMPLEMENTED
uint32 packet sequence number of rejected message
*/
// TODO
}
};
Parser.prototype.hmacVerify = function(hmac) {
var calcHmac = crypto.createHmac(SSH_TO_OPENSSL[this._hmac], this._hmacKey);
this._hmacBuf.writeUInt32BE(this._seqno, 0, true);
this._hmacBuf.writeUInt32BE(this._pktLen, 4, true);
this._hmacBuf[8] = this._padLen;
this._hmacBufCompute.writeUInt32BE(this._seqno, 0, true);
this._hmacBufCompute.writeUInt32BE(this._pktLen, 4, true);
this._hmacBufCompute[8] = this._padLen;
calcHmac.update(this._hmacBuf);
calcHmac.update(this._hmacBufCompute);
calcHmac.update(this._packet);

@@ -691,16 +646,13 @@

Parser.prototype.decrypt = function(data) {
var ret = new Buffer(this._decrypt.update(data, 'binary', 'binary'), 'binary');
return ret;
return new Buffer(this._decrypt.update(data, 'binary', 'binary'), 'binary');
};
Parser.prototype.expect = function(what) {
this._expect = what;
this._expectType = (Array.isArray(what) ? EXP_TYPE_MATCH : EXP_TYPE_BYTES);
this._expectLen = (Array.isArray(what) ? what.length : what);
Parser.prototype.expect = function(type, amount, bufferKey) {
this._expect = amount;
this._expectType = type;
this._expectPtr = 0;
if (Array.isArray(what))
this._expectBuf = [];
else
this._expectBuf = new Buffer(what);
this._expectBufLen = 0;
if (bufferKey && this[bufferKey])
this._expectBuf = this[bufferKey];
else if (amount)
this._expectBuf = new Buffer(amount);
};

@@ -712,10 +664,10 @@

this._expectType = undefined;
this._expectLen = undefined;
this._expectPtr = 0;
this._expectBuf = undefined;
this._expectBufLen = 0;
this._ss = undefined;
this._greeting = undefined;
this._decryptSize = 8;
this._decrypt = false;
this._decryptBuf = undefined;
this._authMethod = undefined;

@@ -727,2 +679,3 @@

this._payload = undefined;
this._hmacBuf = undefined;
this._hmacSize = undefined;

@@ -735,9 +688,2 @@ this._packet = undefined;

function bytes(str) {
var ret = new Array(str.length);
for (var i = 0, len = ret.length; i < len; ++i)
ret[i] = str.charCodeAt(i);
return ret;
}
function readString(buffer, start, encoding) {

@@ -744,0 +690,0 @@ start || (start = 0);

@@ -202,3 +202,3 @@ var EventEmitter = require('events').EventEmitter,

throw new Error('buffer is not a Buffer');
else if (offset >= buffer.length)
else if (offset > buffer.length)
throw new Error('offset is out of bounds');

@@ -748,3 +748,3 @@ else if (offset + length > buffer.length)

return this.fsetstat(handle, {
permissions: mode
mode: mode
}, cb);

@@ -755,3 +755,3 @@ };

return this.setstat(path, {
permissions: mode
mode: mode
}, cb);

@@ -758,0 +758,0 @@ };

@@ -17,3 +17,3 @@

Stats.prototype._checkModeProperty = function(property) {
return ((this.permissions & constants.S_IFMT) === property);
return ((this.mode & constants.S_IFMT) === property);
};

@@ -20,0 +20,0 @@

{ "name": "ssh2",
"version": "0.2.5",
"version": "0.2.6",
"author": "Brian White <mscdex@mscdex.net>",

@@ -7,5 +7,8 @@ "description": "An SSH2 client module written in pure JavaScript for node.js",

"engines": { "node": ">=0.8.7" },
"keywords": [ "ssh", "ssh2", "sftp", "secure", "shell", "ftp", "exec", "remote", "client" ],
"dependencies": {
"streamsearch": "*"
},
"keywords": [ "ssh", "ssh2", "sftp", "secure", "shell", "exec", "remote", "client" ],
"licenses": [ { "type": "MIT", "url": "http://github.com/mscdex/ssh2/raw/master/LICENSE" } ],
"repository" : { "type": "git", "url": "http://github.com/mscdex/ssh2.git" }
}

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc