📄 ssh.c
字号:
}
static void s_wrpkt(Ssh ssh)
{
int len, backlog;
len = s_wrpkt_prepare(ssh);
backlog = sk_write(ssh->s, (char *)ssh->pktout.data, len);
if (backlog > SSH_MAX_BACKLOG)
ssh_throttle_all(ssh, 1, backlog);
}
static void s_wrpkt_defer(Ssh ssh)
{
int len;
len = s_wrpkt_prepare(ssh);
if (ssh->deferred_len + len > ssh->deferred_size) {
ssh->deferred_size = ssh->deferred_len + len + 128;
ssh->deferred_send_data = sresize(ssh->deferred_send_data,
ssh->deferred_size,
unsigned char);
}
memcpy(ssh->deferred_send_data + ssh->deferred_len, ssh->pktout.data, len);
ssh->deferred_len += len;
}
/*
* Construct a packet with the specified contents.
*/
static void construct_packet(Ssh ssh, int pkttype, va_list ap1, va_list ap2)
{
unsigned char *p, *argp, argchar;
unsigned long argint;
int pktlen, argtype, arglen;
Bignum bn;
pktlen = 0;
while ((argtype = va_arg(ap1, int)) != PKT_END) {
switch (argtype) {
case PKT_INT:
(void) va_arg(ap1, int);
pktlen += 4;
break;
case PKT_CHAR:
(void) va_arg(ap1, int);
pktlen++;
break;
case PKT_DATA:
(void) va_arg(ap1, unsigned char *);
arglen = va_arg(ap1, int);
pktlen += arglen;
break;
case PKT_STR:
argp = va_arg(ap1, unsigned char *);
arglen = strlen((char *)argp);
pktlen += 4 + arglen;
break;
case PKT_BIGNUM:
bn = va_arg(ap1, Bignum);
pktlen += ssh1_bignum_length(bn);
break;
default:
assert(0);
}
}
s_wrpkt_start(ssh, pkttype, pktlen);
p = ssh->pktout.body;
while ((argtype = va_arg(ap2, int)) != PKT_END) {
switch (argtype) {
case PKT_INT:
argint = va_arg(ap2, int);
PUT_32BIT(p, argint);
p += 4;
break;
case PKT_CHAR:
argchar = (unsigned char) va_arg(ap2, int);
*p = argchar;
p++;
break;
case PKT_DATA:
argp = va_arg(ap2, unsigned char *);
arglen = va_arg(ap2, int);
memcpy(p, argp, arglen);
p += arglen;
break;
case PKT_STR:
argp = va_arg(ap2, unsigned char *);
arglen = strlen((char *)argp);
PUT_32BIT(p, arglen);
memcpy(p + 4, argp, arglen);
p += 4 + arglen;
break;
case PKT_BIGNUM:
bn = va_arg(ap2, Bignum);
p += ssh1_write_bignum(p, bn);
break;
}
}
}
static void send_packet(Ssh ssh, int pkttype, ...)
{
va_list ap1, ap2;
va_start(ap1, pkttype);
va_start(ap2, pkttype);
construct_packet(ssh, pkttype, ap1, ap2);
s_wrpkt(ssh);
}
static void defer_packet(Ssh ssh, int pkttype, ...)
{
va_list ap1, ap2;
va_start(ap1, pkttype);
va_start(ap2, pkttype);
construct_packet(ssh, pkttype, ap1, ap2);
s_wrpkt_defer(ssh);
}
static int ssh_versioncmp(char *a, char *b)
{
char *ae, *be;
unsigned long av, bv;
av = strtoul(a, &ae, 10);
bv = strtoul(b, &be, 10);
if (av != bv)
return (av < bv ? -1 : +1);
if (*ae == '.')
ae++;
if (*be == '.')
be++;
av = strtoul(ae, &ae, 10);
bv = strtoul(be, &be, 10);
if (av != bv)
return (av < bv ? -1 : +1);
return 0;
}
/*
* Utility routines for putting an SSH-protocol `string' and
* `uint32' into a SHA state.
*/
#include <stdio.h>
static void sha_string(SHA_State * s, void *str, int len)
{
unsigned char lenblk[4];
PUT_32BIT(lenblk, len);
SHA_Bytes(s, lenblk, 4);
SHA_Bytes(s, str, len);
}
static void sha_uint32(SHA_State * s, unsigned i)
{
unsigned char intblk[4];
PUT_32BIT(intblk, i);
SHA_Bytes(s, intblk, 4);
}
/*
* SSH2 packet construction functions.
*/
static void ssh2_pkt_ensure(Ssh ssh, int length)
{
if (ssh->pktout.maxlen < length) {
ssh->pktout.maxlen = length + 256;
ssh->pktout.data = sresize(ssh->pktout.data,
ssh->pktout.maxlen + APIEXTRA,
unsigned char);
if (!ssh->pktout.data)
fatalbox("Out of memory");
}
}
static void ssh2_pkt_adddata(Ssh ssh, void *data, int len)
{
ssh->pktout.length += len;
ssh2_pkt_ensure(ssh, ssh->pktout.length);
memcpy(ssh->pktout.data + ssh->pktout.length - len, data, len);
}
static void ssh2_pkt_addbyte(Ssh ssh, unsigned char byte)
{
ssh2_pkt_adddata(ssh, &byte, 1);
}
static void ssh2_pkt_init(Ssh ssh, int pkt_type)
{
ssh->pktout.length = 5;
ssh2_pkt_addbyte(ssh, (unsigned char) pkt_type);
}
static void ssh2_pkt_addbool(Ssh ssh, unsigned char value)
{
ssh2_pkt_adddata(ssh, &value, 1);
}
static void ssh2_pkt_adduint32(Ssh ssh, unsigned long value)
{
unsigned char x[4];
PUT_32BIT(x, value);
ssh2_pkt_adddata(ssh, x, 4);
}
static void ssh2_pkt_addstring_start(Ssh ssh)
{
ssh2_pkt_adduint32(ssh, 0);
ssh->pktout.savedpos = ssh->pktout.length;
}
static void ssh2_pkt_addstring_str(Ssh ssh, char *data)
{
ssh2_pkt_adddata(ssh, data, strlen(data));
PUT_32BIT(ssh->pktout.data + ssh->pktout.savedpos - 4,
ssh->pktout.length - ssh->pktout.savedpos);
}
static void ssh2_pkt_addstring_data(Ssh ssh, char *data, int len)
{
ssh2_pkt_adddata(ssh, data, len);
PUT_32BIT(ssh->pktout.data + ssh->pktout.savedpos - 4,
ssh->pktout.length - ssh->pktout.savedpos);
}
static void ssh2_pkt_addstring(Ssh ssh, char *data)
{
ssh2_pkt_addstring_start(ssh);
ssh2_pkt_addstring_str(ssh, data);
}
static unsigned char *ssh2_mpint_fmt(Bignum b, int *len)
{
unsigned char *p;
int i, n = (bignum_bitcount(b) + 7) / 8;
p = snewn(n + 1, unsigned char);
if (!p)
fatalbox("out of memory");
p[0] = 0;
for (i = 1; i <= n; i++)
p[i] = bignum_byte(b, n - i);
i = 0;
while (i <= n && p[i] == 0 && (p[i + 1] & 0x80) == 0)
i++;
memmove(p, p + i, n + 1 - i);
*len = n + 1 - i;
return p;
}
static void ssh2_pkt_addmp(Ssh ssh, Bignum b)
{
unsigned char *p;
int len;
p = ssh2_mpint_fmt(b, &len);
ssh2_pkt_addstring_start(ssh);
ssh2_pkt_addstring_data(ssh, (char *)p, len);
sfree(p);
}
/*
* Construct an SSH2 final-form packet: compress it, encrypt it,
* put the MAC on it. Final packet, ready to be sent, is stored in
* ssh->pktout.data. Total length is returned.
*/
static int ssh2_pkt_construct(Ssh ssh)
{
int cipherblk, maclen, padding, i;
if (ssh->logctx)
log_packet(ssh->logctx, PKT_OUTGOING, ssh->pktout.data[5],
ssh2_pkt_type(ssh->pkt_ctx, ssh->pktout.data[5]),
ssh->pktout.data + 6, ssh->pktout.length - 6);
/*
* Compress packet payload.
*/
{
unsigned char *newpayload;
int newlen;
if (ssh->cscomp &&
ssh->cscomp->compress(ssh->cs_comp_ctx, ssh->pktout.data + 5,
ssh->pktout.length - 5,
&newpayload, &newlen)) {
ssh->pktout.length = 5;
ssh2_pkt_adddata(ssh, newpayload, newlen);
sfree(newpayload);
}
}
/*
* Add padding. At least four bytes, and must also bring total
* length (minus MAC) up to a multiple of the block size.
*/
cipherblk = ssh->cscipher ? ssh->cscipher->blksize : 8; /* block size */
cipherblk = cipherblk < 8 ? 8 : cipherblk; /* or 8 if blksize < 8 */
padding = 4;
padding +=
(cipherblk - (ssh->pktout.length + padding) % cipherblk) % cipherblk;
maclen = ssh->csmac ? ssh->csmac->len : 0;
ssh2_pkt_ensure(ssh, ssh->pktout.length + padding + maclen);
ssh->pktout.data[4] = padding;
for (i = 0; i < padding; i++)
ssh->pktout.data[ssh->pktout.length + i] = random_byte();
PUT_32BIT(ssh->pktout.data, ssh->pktout.length + padding - 4);
if (ssh->csmac)
ssh->csmac->generate(ssh->cs_mac_ctx, ssh->pktout.data,
ssh->pktout.length + padding,
ssh->v2_outgoing_sequence);
ssh->v2_outgoing_sequence++; /* whether or not we MACed */
if (ssh->cscipher)
ssh->cscipher->encrypt(ssh->cs_cipher_ctx,
ssh->pktout.data, ssh->pktout.length + padding);
/* Ready-to-send packet starts at ssh->pktout.data. We return length. */
return ssh->pktout.length + padding + maclen;
}
/*
* Construct and send an SSH2 packet immediately.
*/
static void ssh2_pkt_send(Ssh ssh)
{
int len;
int backlog;
len = ssh2_pkt_construct(ssh);
backlog = sk_write(ssh->s, (char *)ssh->pktout.data, len);
if (backlog > SSH_MAX_BACKLOG)
ssh_throttle_all(ssh, 1, backlog);
}
/*
* Construct an SSH2 packet and add it to a deferred data block.
* Useful for sending multiple packets in a single sk_write() call,
* to prevent a traffic-analysing listener from being able to work
* out the length of any particular packet (such as the password
* packet).
*
* Note that because SSH2 sequence-numbers its packets, this can
* NOT be used as an m4-style `defer' allowing packets to be
* constructed in one order and sent in another.
*/
static void ssh2_pkt_defer(Ssh ssh)
{
int len = ssh2_pkt_construct(ssh);
if (ssh->deferred_len + len > ssh->deferred_size) {
ssh->deferred_size = ssh->deferred_len + len + 128;
ssh->deferred_send_data = sresize(ssh->deferred_send_data,
ssh->deferred_size,
unsigned char);
}
memcpy(ssh->deferred_send_data + ssh->deferred_len, ssh->pktout.data, len);
ssh->deferred_len += len;
}
/*
* Send the whole deferred data block constructed by
* ssh2_pkt_defer() or SSH1's defer_packet().
*/
static void ssh_pkt_defersend(Ssh ssh)
{
int backlog;
backlog = sk_write(ssh->s, (char *)ssh->deferred_send_data,
ssh->deferred_len);
ssh->deferred_len = ssh->deferred_size = 0;
sfree(ssh->deferred_send_data);
ssh->deferred_send_data = NULL;
if (backlog > SSH_MAX_BACKLOG)
ssh_throttle_all(ssh, 1, backlog);
}
#if 0
void bndebug(char *string, Bignum b)
{
unsigned char *p;
int i, len;
p = ssh2_mpint_fmt(b, &len);
debug(("%s", string));
for (i = 0; i < len; i++)
debug((" %02x", p[i]));
debug(("\n"));
sfree(p);
}
#endif
static void sha_mpint(SHA_State * s, Bignum b)
{
unsigned char *p;
int len;
p = ssh2_mpint_fmt(b, &len);
sha_string(s, p, len);
sfree(p);
}
/*
* Packet decode functions for both SSH1 and SSH2.
*/
static unsigned long ssh_pkt_getuint32(Ssh ssh)
{
unsigned long value;
if (ssh->pktin.length - ssh->pktin.savedpos < 4)
return 0; /* arrgh, no way to decline (FIXME?) */
value = GET_32BIT(ssh->pktin.body + ssh->pktin.savedpos);
ssh->pktin.savedpos += 4;
return value;
}
static int ssh2_pkt_getbool(Ssh ssh)
{
unsigned long value;
if (ssh->pktin.length - ssh->pktin.savedpos < 1)
return 0; /* arrgh, no way to decline (FIXME?) */
value = ssh->pktin.body[ssh->pktin.savedpos] != 0;
ssh->pktin.savedpos++;
return value;
}
static void ssh_pkt_getstring(Ssh ssh, char **p, int *length)
{
int len;
*p = NULL;
*length = 0;
if (ssh->pktin.length - ssh->pktin.savedpos < 4)
return;
len = GET_32BIT(ssh->pktin.body + ssh->pktin.savedpos);
if (len < 0)
return;
*length = len;
ssh->pktin.savedpos += 4;
if (ssh->pktin.length - ssh->pktin.savedpos < *length)
return;
*p = (char *)(ssh->pktin.body + ssh->pktin.savedpos);
ssh->pktin.savedpos += *length;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -