📄 ssh.c
字号:
crReturn(st->to_read);
if (st->chunk > (*datalen))
st->chunk = (*datalen);
memcpy(st->p, *data, st->chunk);
*data += st->chunk;
*datalen -= st->chunk;
st->p += st->chunk;
st->to_read -= st->chunk;
}
if (ssh->cipher && detect_attack(ssh->crcda_ctx, ssh->pktin.data,
st->biglen, NULL)) {
bombout(("Network attack (CRC compensation) detected!"));
crStop(0);
}
if (ssh->cipher)
ssh->cipher->decrypt(ssh->v1_cipher_ctx, ssh->pktin.data, st->biglen);
st->realcrc = crc32_compute(ssh->pktin.data, st->biglen - 4);
st->gotcrc = GET_32BIT(ssh->pktin.data + st->biglen - 4);
if (st->gotcrc != st->realcrc) {
bombout(("Incorrect CRC received on packet"));
crStop(0);
}
ssh->pktin.body = ssh->pktin.data + st->pad + 1;
ssh->pktin.savedpos = 0;
if (ssh->v1_compressing) {
unsigned char *decompblk;
int decomplen;
if (!zlib_decompress_block(ssh->sc_comp_ctx,
ssh->pktin.body - 1, ssh->pktin.length + 1,
&decompblk, &decomplen)) {
bombout(("Zlib decompression encountered invalid data"));
crStop(0);
}
if (ssh->pktin.maxlen < st->pad + decomplen) {
ssh->pktin.maxlen = st->pad + decomplen;
ssh->pktin.data = sresize(ssh->pktin.data,
ssh->pktin.maxlen + APIEXTRA,
unsigned char);
ssh->pktin.body = ssh->pktin.data + st->pad + 1;
}
memcpy(ssh->pktin.body - 1, decompblk, decomplen);
sfree(decompblk);
ssh->pktin.length = decomplen - 1;
}
ssh->pktin.type = ssh->pktin.body[-1];
if (ssh->logctx)
log_packet(ssh->logctx,
PKT_INCOMING, ssh->pktin.type,
ssh1_pkt_type(ssh->pktin.type),
ssh->pktin.body, ssh->pktin.length);
if (ssh->pktin.type == SSH1_SMSG_STDOUT_DATA ||
ssh->pktin.type == SSH1_SMSG_STDERR_DATA ||
ssh->pktin.type == SSH1_MSG_DEBUG ||
ssh->pktin.type == SSH1_SMSG_AUTH_TIS_CHALLENGE ||
ssh->pktin.type == SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
long stringlen = GET_32BIT(ssh->pktin.body);
if (stringlen + 4 != ssh->pktin.length) {
bombout(("Received data packet with bogus string length"));
crStop(0);
}
}
if (ssh->pktin.type == SSH1_MSG_DEBUG) {
/* log debug message */
char buf[512];
int stringlen = GET_32BIT(ssh->pktin.body);
strcpy(buf, "Remote debug message: ");
if (stringlen > 480)
stringlen = 480;
memcpy(buf + 8, ssh->pktin.body + 4, stringlen);
buf[8 + stringlen] = '\0';
logevent(buf);
goto next_packet;
} else if (ssh->pktin.type == SSH1_MSG_IGNORE) {
/* do nothing */
goto next_packet;
}
if (ssh->pktin.type == SSH1_MSG_DISCONNECT) {
/* log reason code in disconnect message */
char buf[256];
unsigned msglen = GET_32BIT(ssh->pktin.body);
unsigned nowlen;
strcpy(buf, "Remote sent disconnect: ");
nowlen = strlen(buf);
if (msglen > sizeof(buf) - nowlen - 1)
msglen = sizeof(buf) - nowlen - 1;
memcpy(buf + nowlen, ssh->pktin.body + 4, msglen);
buf[nowlen + msglen] = '\0';
/* logevent(buf); (this is now done within the bombout macro) */
bombout(("Server sent disconnect message:\n\"%s\"", buf+nowlen));
crStop(0);
}
crFinish(0);
}
static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
{
struct rdpkt2_state_tag *st = &ssh->rdpkt2_state;
crBegin(ssh->ssh2_rdpkt_crstate);
next_packet:
ssh->pktin.type = 0;
ssh->pktin.length = 0;
if (ssh->sccipher)
st->cipherblk = ssh->sccipher->blksize;
else
st->cipherblk = 8;
if (st->cipherblk < 8)
st->cipherblk = 8;
if (ssh->pktin.maxlen < st->cipherblk) {
ssh->pktin.maxlen = st->cipherblk;
ssh->pktin.data = sresize(ssh->pktin.data, st->cipherblk + APIEXTRA,
unsigned char);
}
/*
* Acquire and decrypt the first block of the packet. This will
* contain the length and padding details.
*/
for (st->i = st->len = 0; st->i < st->cipherblk; st->i++) {
while ((*datalen) == 0)
crReturn(st->cipherblk - st->i);
ssh->pktin.data[st->i] = *(*data)++;
(*datalen)--;
}
if (ssh->sccipher)
ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
ssh->pktin.data, st->cipherblk);
/*
* Now get the length and padding figures.
*/
st->len = GET_32BIT(ssh->pktin.data);
st->pad = ssh->pktin.data[4];
/*
* _Completely_ silly lengths should be stomped on before they
* do us any more damage.
*/
if (st->len < 0 || st->pad < 0 || st->len + st->pad < 0) {
bombout(("Incoming packet was garbled on decryption"));
crStop(0);
}
/*
* This enables us to deduce the payload length.
*/
st->payload = st->len - st->pad - 1;
ssh->pktin.length = st->payload + 5;
/*
* So now we can work out the total packet length.
*/
st->packetlen = st->len + 4;
st->maclen = ssh->scmac ? ssh->scmac->len : 0;
/*
* Adjust memory allocation if packet is too big.
*/
if (ssh->pktin.maxlen < st->packetlen + st->maclen) {
ssh->pktin.maxlen = st->packetlen + st->maclen;
ssh->pktin.data = sresize(ssh->pktin.data,
ssh->pktin.maxlen + APIEXTRA,
unsigned char);
}
/*
* Read and decrypt the remainder of the packet.
*/
for (st->i = st->cipherblk; st->i < st->packetlen + st->maclen;
st->i++) {
while ((*datalen) == 0)
crReturn(st->packetlen + st->maclen - st->i);
ssh->pktin.data[st->i] = *(*data)++;
(*datalen)--;
}
/* Decrypt everything _except_ the MAC. */
if (ssh->sccipher)
ssh->sccipher->decrypt(ssh->sc_cipher_ctx,
ssh->pktin.data + st->cipherblk,
st->packetlen - st->cipherblk);
/*
* Check the MAC.
*/
if (ssh->scmac
&& !ssh->scmac->verify(ssh->sc_mac_ctx, ssh->pktin.data, st->len + 4,
st->incoming_sequence)) {
bombout(("Incorrect MAC received on packet"));
crStop(0);
}
st->incoming_sequence++; /* whether or not we MACed */
/*
* Decompress packet payload.
*/
{
unsigned char *newpayload;
int newlen;
if (ssh->sccomp &&
ssh->sccomp->decompress(ssh->sc_comp_ctx,
ssh->pktin.data + 5, ssh->pktin.length - 5,
&newpayload, &newlen)) {
if (ssh->pktin.maxlen < newlen + 5) {
ssh->pktin.maxlen = newlen + 5;
ssh->pktin.data = sresize(ssh->pktin.data,
ssh->pktin.maxlen + APIEXTRA,
unsigned char);
}
ssh->pktin.length = 5 + newlen;
memcpy(ssh->pktin.data + 5, newpayload, newlen);
sfree(newpayload);
}
}
ssh->pktin.savedpos = 6;
ssh->pktin.body = ssh->pktin.data;
ssh->pktin.type = ssh->pktin.data[5];
if (ssh->logctx)
log_packet(ssh->logctx, PKT_INCOMING, ssh->pktin.type,
ssh2_pkt_type(ssh->pkt_ctx, ssh->pktin.type),
ssh->pktin.data+6, ssh->pktin.length-6);
switch (ssh->pktin.type) {
/*
* These packets we must handle instantly.
*/
case SSH2_MSG_DISCONNECT:
{
/* log reason code in disconnect message */
char *buf;
int nowlen;
int reason = GET_32BIT(ssh->pktin.data + 6);
unsigned msglen = GET_32BIT(ssh->pktin.data + 10);
if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {
buf = dupprintf("Received disconnect message (%s)",
ssh2_disconnect_reasons[reason]);
} else {
buf = dupprintf("Received disconnect message (unknown"
" type %d)", reason);
}
logevent(buf);
sfree(buf);
buf = dupprintf("Disconnection message text: %n%.*s",
&nowlen, msglen, ssh->pktin.data + 14);
logevent(buf);
bombout(("Server sent disconnect message\ntype %d (%s):\n\"%s\"",
reason,
(reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ?
ssh2_disconnect_reasons[reason] : "unknown",
buf+nowlen));
sfree(buf);
crStop(0);
}
break;
case SSH2_MSG_IGNORE:
goto next_packet;
case SSH2_MSG_DEBUG:
{
/* log the debug message */
char buf[512];
/* int display = ssh->pktin.body[6]; */
int stringlen = GET_32BIT(ssh->pktin.data+7);
int prefix;
strcpy(buf, "Remote debug message: ");
prefix = strlen(buf);
if (stringlen > (int)(sizeof(buf)-prefix-1))
stringlen = sizeof(buf)-prefix-1;
memcpy(buf + prefix, ssh->pktin.data + 11, stringlen);
buf[prefix + stringlen] = '\0';
logevent(buf);
}
goto next_packet; /* FIXME: print the debug message */
/*
* These packets we need do nothing about here.
*/
case SSH2_MSG_UNIMPLEMENTED:
case SSH2_MSG_SERVICE_REQUEST:
case SSH2_MSG_SERVICE_ACCEPT:
case SSH2_MSG_KEXINIT:
case SSH2_MSG_NEWKEYS:
case SSH2_MSG_KEXDH_INIT:
case SSH2_MSG_KEXDH_REPLY:
/* case SSH2_MSG_KEX_DH_GEX_REQUEST: duplicate case value */
/* case SSH2_MSG_KEX_DH_GEX_GROUP: duplicate case value */
case SSH2_MSG_KEX_DH_GEX_INIT:
case SSH2_MSG_KEX_DH_GEX_REPLY:
case SSH2_MSG_USERAUTH_REQUEST:
case SSH2_MSG_USERAUTH_FAILURE:
case SSH2_MSG_USERAUTH_SUCCESS:
case SSH2_MSG_USERAUTH_BANNER:
case SSH2_MSG_USERAUTH_PK_OK:
/* case SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: duplicate case value */
/* case SSH2_MSG_USERAUTH_INFO_REQUEST: duplicate case value */
case SSH2_MSG_USERAUTH_INFO_RESPONSE:
case SSH2_MSG_GLOBAL_REQUEST:
case SSH2_MSG_REQUEST_SUCCESS:
case SSH2_MSG_REQUEST_FAILURE:
case SSH2_MSG_CHANNEL_OPEN:
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
case SSH2_MSG_CHANNEL_OPEN_FAILURE:
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
case SSH2_MSG_CHANNEL_DATA:
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
case SSH2_MSG_CHANNEL_EOF:
case SSH2_MSG_CHANNEL_CLOSE:
case SSH2_MSG_CHANNEL_REQUEST:
case SSH2_MSG_CHANNEL_SUCCESS:
case SSH2_MSG_CHANNEL_FAILURE:
break;
/*
* For anything else we send SSH2_MSG_UNIMPLEMENTED.
*/
default:
ssh2_pkt_init(ssh, SSH2_MSG_UNIMPLEMENTED);
ssh2_pkt_adduint32(ssh, st->incoming_sequence - 1);
ssh2_pkt_send(ssh);
break;
}
crFinish(0);
}
static void ssh1_pktout_size(Ssh ssh, int len)
{
int pad, biglen;
len += 5; /* type and CRC */
pad = 8 - (len % 8);
biglen = len + pad;
ssh->pktout.length = len - 5;
if (ssh->pktout.maxlen < biglen) {
ssh->pktout.maxlen = biglen;
#ifdef MSCRYPTOAPI
/* Allocate enough buffer space for extra block
* for MS CryptEncrypt() */
ssh->pktout.data = sresize(ssh->pktout.data, biglen + 12,
unsigned char);
#else
ssh->pktout.data = sresize(ssh->pktout.data, biglen + 4,
unsigned char);
#endif
}
ssh->pktout.body = ssh->pktout.data + 4 + pad + 1;
}
static void s_wrpkt_start(Ssh ssh, int type, int len)
{
ssh1_pktout_size(ssh, len);
ssh->pktout.type = type;
}
static int s_wrpkt_prepare(Ssh ssh)
{
int pad, biglen, i;
unsigned long crc;
#ifdef __SC__
/*
* XXX various versions of SC (including 8.8.4) screw up the
* register allocation in this function and use the same register
* (D6) for len and as a temporary, with predictable results. The
* following sledgehammer prevents this.
*/
volatile
#endif
int len;
ssh->pktout.body[-1] = ssh->pktout.type;
if (ssh->logctx)
log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.type,
ssh1_pkt_type(ssh->pktout.type),
ssh->pktout.body, ssh->pktout.length);
if (ssh->v1_compressing) {
unsigned char *compblk;
int complen;
zlib_compress_block(ssh->cs_comp_ctx,
ssh->pktout.body - 1, ssh->pktout.length + 1,
&compblk, &complen);
ssh1_pktout_size(ssh, complen - 1);
memcpy(ssh->pktout.body - 1, compblk, complen);
sfree(compblk);
}
len = ssh->pktout.length + 5; /* type and CRC */
pad = 8 - (len % 8);
biglen = len + pad;
for (i = 0; i < pad; i++)
ssh->pktout.data[i + 4] = random_byte();
crc = crc32_compute(ssh->pktout.data + 4, biglen - 4);
PUT_32BIT(ssh->pktout.data + biglen, crc);
PUT_32BIT(ssh->pktout.data, len);
if (ssh->cipher)
ssh->cipher->encrypt(ssh->v1_cipher_ctx, ssh->pktout.data + 4, biglen);
return biglen + 4;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -