#undef translate
#undef translatec
-#define GET_32BIT(cp) \
- (((unsigned long)(unsigned char)(cp)[0] << 24) | \
- ((unsigned long)(unsigned char)(cp)[1] << 16) | \
- ((unsigned long)(unsigned char)(cp)[2] << 8) | \
- ((unsigned long)(unsigned char)(cp)[3]))
-
-#define PUT_32BIT(cp, value) { \
- (cp)[0] = (unsigned char)((value) >> 24); \
- (cp)[1] = (unsigned char)((value) >> 16); \
- (cp)[2] = (unsigned char)((value) >> 8); \
- (cp)[3] = (unsigned char)(value); }
-
/* Enumeration values for fields in SSH-1 packets */
enum {
PKT_END, PKT_INT, PKT_CHAR, PKT_DATA, PKT_STR, PKT_BIGNUM,
typedef struct ssh_tag *Ssh;
struct Packet;
+static struct Packet *ssh1_pkt_init(int pkt_type);
static struct Packet *ssh2_pkt_init(int pkt_type);
+static void ssh_pkt_ensure(struct Packet *, int length);
+static void ssh_pkt_adddata(struct Packet *, void *data, int len);
+static void ssh_pkt_addbyte(struct Packet *, unsigned char value);
static void ssh2_pkt_addbool(struct Packet *, unsigned char value);
-static void ssh2_pkt_adduint32(struct Packet *, unsigned long value);
-static void ssh2_pkt_addstring_start(struct Packet *);
-static void ssh2_pkt_addstring_str(struct Packet *, char *data);
-static void ssh2_pkt_addstring_data(struct Packet *, char *data, int len);
-static void ssh2_pkt_addstring(struct Packet *, char *data);
+static void ssh_pkt_adduint32(struct Packet *, unsigned long value);
+static void ssh_pkt_addstring_start(struct Packet *);
+static void ssh_pkt_addstring_str(struct Packet *, char *data);
+static void ssh_pkt_addstring_data(struct Packet *, char *data, int len);
+static void ssh_pkt_addstring(struct Packet *, char *data);
static unsigned char *ssh2_mpint_fmt(Bignum b, int *len);
+static void ssh1_pkt_addmp(struct Packet *, Bignum b);
static void ssh2_pkt_addmp(struct Packet *, Bignum b);
static int ssh2_pkt_construct(Ssh, struct Packet *);
static void ssh2_pkt_send(Ssh, struct Packet *);
const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };
-static void *nullmac_make_context(void)
-{
- return NULL;
-}
-static void nullmac_free_context(void *handle)
-{
-}
-static void nullmac_key(void *handle, unsigned char *key)
-{
-}
-static void nullmac_generate(void *handle, unsigned char *blk, int len,
- unsigned long seq)
-{
-}
-static int nullmac_verify(void *handle, unsigned char *blk, int len,
- unsigned long seq)
-{
- return 1;
-}
-const static struct ssh_mac ssh_mac_none = {
- nullmac_make_context, nullmac_free_context, nullmac_key,
- nullmac_generate, nullmac_verify, "none", 0
-};
const static struct ssh_mac *macs[] = {
- &ssh_sha1, &ssh_md5, &ssh_mac_none
+ &ssh_sha1, &ssh_md5
};
const static struct ssh_mac *buggymacs[] = {
- &ssh_sha1_buggy, &ssh_md5, &ssh_mac_none
+ &ssh_sha1_buggy, &ssh_md5
};
static void *ssh_comp_none_init(void)
sfree((pf)->sserv), sfree((pf)->dserv)) : (void)0 ), sfree(pf) )
struct Packet {
- long length;
- long forcepad; /* Force padding to at least this length */
- int type;
- unsigned long sequence;
- unsigned char *data;
- unsigned char *body;
- long savedpos;
- long maxlen;
- long encrypted_len; /* for SSH-2 total-size counting */
+ long length; /* length of `data' actually used */
+ long forcepad; /* SSH-2: force padding to at least this length */
+ int type; /* only used for incoming packets */
+ unsigned long sequence; /* SSH-2 incoming sequence number */
+ unsigned char *data; /* allocated storage */
+ unsigned char *body; /* offset of payload within `data' */
+ long savedpos; /* temporary index into `data' (for strings) */
+ long maxlen; /* amount of storage allocated for `data' */
+ long encrypted_len; /* for SSH-2 total-size counting */
/*
* State associated with packet logging
{
struct Packet *pkt = snew(struct Packet);
- pkt->data = NULL;
+ pkt->body = pkt->data = NULL;
pkt->maxlen = 0;
pkt->logmode = PKTLOG_EMIT;
pkt->nblanks = 0;
crFinish(st->pktin);
}
-static void ssh1_pktout_size(struct Packet *pkt, int len)
-{
- int pad, biglen;
-
- len += 5; /* type and CRC */
- pad = 8 - (len % 8);
- biglen = len + pad;
-
- pkt->length = len - 5;
- if (pkt->maxlen < biglen) {
- pkt->maxlen = biglen;
- pkt->data = sresize(pkt->data, biglen + 4 + APIEXTRA, unsigned char);
- }
- pkt->body = pkt->data + 4 + pad + 1;
-}
-
-static struct Packet *s_wrpkt_start(int type, int len)
+static int s_wrpkt_prepare(Ssh ssh, struct Packet *pkt, int *offset_p)
{
- struct Packet *pkt = ssh_new_packet();
- ssh1_pktout_size(pkt, len);
- pkt->type = type;
- /* Initialise log omission state */
- pkt->nblanks = 0;
- pkt->blanks = NULL;
- return pkt;
-}
-
-static int s_wrpkt_prepare(Ssh ssh, struct Packet *pkt)
-{
- int pad, biglen, i;
+ int pad, biglen, i, pktoffs;
unsigned long crc;
#ifdef __SC__
/*
#endif
int len;
- pkt->body[-1] = pkt->type;
-
if (ssh->logctx)
- log_packet(ssh->logctx, PKT_OUTGOING, pkt->type,
- ssh1_pkt_type(pkt->type),
- pkt->body, pkt->length,
+ log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[12],
+ ssh1_pkt_type(pkt->data[12]),
+ pkt->body, pkt->length - (pkt->body - pkt->data),
pkt->nblanks, pkt->blanks);
sfree(pkt->blanks); pkt->blanks = NULL;
pkt->nblanks = 0;
unsigned char *compblk;
int complen;
zlib_compress_block(ssh->cs_comp_ctx,
- pkt->body - 1, pkt->length + 1,
+ pkt->data + 12, pkt->length - 12,
&compblk, &complen);
- ssh1_pktout_size(pkt, complen - 1);
- memcpy(pkt->body - 1, compblk, complen);
+ memcpy(pkt->data + 12, compblk, complen);
sfree(compblk);
+ pkt->length = complen + 12;
}
- len = pkt->length + 5; /* type and CRC */
+ ssh_pkt_ensure(pkt, pkt->length + 4); /* space for CRC */
+ pkt->length += 4;
+ len = pkt->length - 4 - 8; /* len(type+data+CRC) */
pad = 8 - (len % 8);
- biglen = len + pad;
+ pktoffs = 8 - pad;
+ biglen = len + pad; /* len(padding+type+data+CRC) */
- for (i = 0; i < pad; i++)
- pkt->data[i + 4] = random_byte();
- crc = crc32_compute(pkt->data + 4, biglen - 4);
- PUT_32BIT(pkt->data + biglen, crc);
- PUT_32BIT(pkt->data, len);
+ for (i = pktoffs; i < 4+8; i++)
+ pkt->data[i] = random_byte();
+ crc = crc32_compute(pkt->data + pktoffs + 4, biglen - 4); /* all ex len */
+ PUT_32BIT(pkt->data + pktoffs + 4 + biglen - 4, crc);
+ PUT_32BIT(pkt->data + pktoffs, len);
if (ssh->cipher)
- ssh->cipher->encrypt(ssh->v1_cipher_ctx, pkt->data + 4, biglen);
+ ssh->cipher->encrypt(ssh->v1_cipher_ctx,
+ pkt->data + pktoffs + 4, biglen);
- return biglen + 4;
+ if (offset_p) *offset_p = pktoffs;
+ return biglen + 4; /* len(length+padding+type+data+CRC) */
}
static void s_wrpkt(Ssh ssh, struct Packet *pkt)
{
- int len, backlog;
- len = s_wrpkt_prepare(ssh, pkt);
- backlog = sk_write(ssh->s, (char *)pkt->data, len);
+ int len, backlog, offset;
+ len = s_wrpkt_prepare(ssh, pkt, &offset);
+ backlog = sk_write(ssh->s, (char *)pkt->data + offset, len);
if (backlog > SSH_MAX_BACKLOG)
ssh_throttle_all(ssh, 1, backlog);
+ ssh_free_packet(pkt);
}
static void s_wrpkt_defer(Ssh ssh, struct Packet *pkt)
{
- int len;
- len = s_wrpkt_prepare(ssh, pkt);
+ int len, offset;
+ len = s_wrpkt_prepare(ssh, pkt, &offset);
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, pkt->data, len);
+ memcpy(ssh->deferred_send_data + ssh->deferred_len,
+ pkt->data + offset, len);
ssh->deferred_len += len;
+ ssh_free_packet(pkt);
}
/*
- * Construct a packet with the specified contents.
+ * Construct a SSH-1 packet with the specified contents.
+ * (This all-at-once interface used to be the only one, but now SSH-1
+ * packets can also be constructed incrementally.)
*/
-static struct Packet *construct_packet(Ssh ssh, int pkttype,
- va_list ap1, va_list ap2)
+static struct Packet *construct_packet(Ssh ssh, int pkttype, va_list ap)
{
- unsigned char *p, *argp, argchar;
- unsigned long argint;
- int pktlen, argtype, arglen;
+ int argtype;
Bignum bn;
struct Packet *pkt;
- 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;
- case PKTT_PASSWORD:
- case PKTT_DATA:
- case PKTT_OTHER:
- /* ignore this pass */
- break;
- default:
- assert(0);
- }
- }
-
- pkt = s_wrpkt_start(pkttype, pktlen);
- p = pkt->body;
+ pkt = ssh1_pkt_init(pkttype);
- while ((argtype = va_arg(ap2, int)) != PKT_END) {
- int offset = p - pkt->body, len = 0;
+ while ((argtype = va_arg(ap, int)) != PKT_END) {
+ unsigned char *argp, argchar;
+ unsigned long argint;
+ int arglen;
switch (argtype) {
/* Actual fields in the packet */
case PKT_INT:
- argint = va_arg(ap2, int);
- PUT_32BIT(p, argint);
- len = 4;
+ argint = va_arg(ap, int);
+ ssh_pkt_adduint32(pkt, argint);
break;
case PKT_CHAR:
- argchar = (unsigned char) va_arg(ap2, int);
- *p = argchar;
- len = 1;
+ argchar = (unsigned char) va_arg(ap, int);
+ ssh_pkt_addbyte(pkt, argchar);
break;
case PKT_DATA:
- argp = va_arg(ap2, unsigned char *);
- arglen = va_arg(ap2, int);
- memcpy(p, argp, arglen);
- len = arglen;
+ argp = va_arg(ap, unsigned char *);
+ arglen = va_arg(ap, int);
+ ssh_pkt_adddata(pkt, argp, arglen);
break;
case PKT_STR:
- argp = va_arg(ap2, unsigned char *);
- arglen = strlen((char *)argp);
- PUT_32BIT(p, arglen);
- memcpy(p + 4, argp, arglen);
- len = arglen + 4;
+ argp = va_arg(ap, unsigned char *);
+ ssh_pkt_addstring(pkt, argp);
break;
case PKT_BIGNUM:
- bn = va_arg(ap2, Bignum);
- len = ssh1_write_bignum(p, bn);
+ bn = va_arg(ap, Bignum);
+ ssh1_pkt_addmp(pkt, bn);
break;
/* Tokens for modifications to packet logging */
case PKTT_PASSWORD:
end_log_omission(ssh, pkt);
break;
}
- p += len;
- /* Deal with logfile omission, if required. */
- if (len && (pkt->logmode != PKTLOG_EMIT)) {
- pkt->nblanks++;
- pkt->blanks = sresize(pkt->blanks, pkt->nblanks,
- struct logblank_t);
- pkt->blanks[pkt->nblanks-1].offset = offset;
- pkt->blanks[pkt->nblanks-1].len = len;
- pkt->blanks[pkt->nblanks-1].type = pkt->logmode;
- }
}
return pkt;
static void send_packet(Ssh ssh, int pkttype, ...)
{
struct Packet *pkt;
- va_list ap1, ap2;
- va_start(ap1, pkttype);
- va_start(ap2, pkttype);
- pkt = construct_packet(ssh, pkttype, ap1, ap2);
- va_end(ap2);
- va_end(ap1);
+ va_list ap;
+ va_start(ap, pkttype);
+ pkt = construct_packet(ssh, pkttype, ap);
+ va_end(ap);
s_wrpkt(ssh, pkt);
- ssh_free_packet(pkt);
}
static void defer_packet(Ssh ssh, int pkttype, ...)
{
struct Packet *pkt;
- va_list ap1, ap2;
- va_start(ap1, pkttype);
- va_start(ap2, pkttype);
- pkt = construct_packet(ssh, pkttype, ap1, ap2);
- va_end(ap2);
- va_end(ap1);
+ va_list ap;
+ va_start(ap, pkttype);
+ pkt = construct_packet(ssh, pkttype, ap);
+ va_end(ap);
s_wrpkt_defer(ssh, pkt);
- ssh_free_packet(pkt);
}
static int ssh_versioncmp(char *a, char *b)
* 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];
}
/*
- * SSH-2 packet construction functions.
+ * Packet construction functions. Mostly shared between SSH-1 and SSH-2.
*/
-static void ssh2_pkt_ensure(struct Packet *pkt, int length)
+static void ssh_pkt_ensure(struct Packet *pkt, int length)
{
if (pkt->maxlen < length) {
+ unsigned char *body = pkt->body;
+ int offset = body ? pkt->data - body : 0;
pkt->maxlen = length + 256;
pkt->data = sresize(pkt->data, pkt->maxlen + APIEXTRA, unsigned char);
+ if (body) pkt->body = pkt->data + offset;
}
}
-static void ssh2_pkt_adddata(struct Packet *pkt, void *data, int len)
+static void ssh_pkt_adddata(struct Packet *pkt, void *data, int len)
{
if (pkt->logmode != PKTLOG_EMIT) {
pkt->nblanks++;
pkt->blanks = sresize(pkt->blanks, pkt->nblanks, struct logblank_t);
- pkt->blanks[pkt->nblanks-1].offset = pkt->length - 6;
+ assert(pkt->body);
+ pkt->blanks[pkt->nblanks-1].offset = pkt->length -
+ (pkt->body - pkt->data);
pkt->blanks[pkt->nblanks-1].len = len;
pkt->blanks[pkt->nblanks-1].type = pkt->logmode;
}
pkt->length += len;
- ssh2_pkt_ensure(pkt, pkt->length);
+ ssh_pkt_ensure(pkt, pkt->length);
memcpy(pkt->data + pkt->length - len, data, len);
}
-static void ssh2_pkt_addbyte(struct Packet *pkt, unsigned char byte)
+static void ssh_pkt_addbyte(struct Packet *pkt, unsigned char byte)
{
- ssh2_pkt_adddata(pkt, &byte, 1);
-}
-static struct Packet *ssh2_pkt_init(int pkt_type)
-{
- struct Packet *pkt = ssh_new_packet();
- pkt->length = 5;
- pkt->forcepad = 0;
- ssh2_pkt_addbyte(pkt, (unsigned char) pkt_type);
- return pkt;
+ ssh_pkt_adddata(pkt, &byte, 1);
}
static void ssh2_pkt_addbool(struct Packet *pkt, unsigned char value)
{
- ssh2_pkt_adddata(pkt, &value, 1);
+ ssh_pkt_adddata(pkt, &value, 1);
}
-static void ssh2_pkt_adduint32(struct Packet *pkt, unsigned long value)
+static void ssh_pkt_adduint32(struct Packet *pkt, unsigned long value)
{
unsigned char x[4];
PUT_32BIT(x, value);
- ssh2_pkt_adddata(pkt, x, 4);
+ ssh_pkt_adddata(pkt, x, 4);
}
-static void ssh2_pkt_addstring_start(struct Packet *pkt)
+static void ssh_pkt_addstring_start(struct Packet *pkt)
{
- ssh2_pkt_adduint32(pkt, 0);
+ ssh_pkt_adduint32(pkt, 0);
pkt->savedpos = pkt->length;
}
-static void ssh2_pkt_addstring_str(struct Packet *pkt, char *data)
+static void ssh_pkt_addstring_str(struct Packet *pkt, char *data)
{
- ssh2_pkt_adddata(pkt, data, strlen(data));
+ ssh_pkt_adddata(pkt, data, strlen(data));
PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);
}
-static void ssh2_pkt_addstring_data(struct Packet *pkt, char *data, int len)
+static void ssh_pkt_addstring_data(struct Packet *pkt, char *data, int len)
{
- ssh2_pkt_adddata(pkt, data, len);
+ ssh_pkt_adddata(pkt, data, len);
PUT_32BIT(pkt->data + pkt->savedpos - 4, pkt->length - pkt->savedpos);
}
-static void ssh2_pkt_addstring(struct Packet *pkt, char *data)
+static void ssh_pkt_addstring(struct Packet *pkt, char *data)
{
- ssh2_pkt_addstring_start(pkt);
- ssh2_pkt_addstring_str(pkt, data);
+ ssh_pkt_addstring_start(pkt);
+ ssh_pkt_addstring_str(pkt, data);
+}
+static void ssh1_pkt_addmp(struct Packet *pkt, Bignum b)
+{
+ int len = ssh1_bignum_length(b);
+ unsigned char *data = snewn(len, char);
+ (void) ssh1_write_bignum(data, b);
+ ssh_pkt_adddata(pkt, data, len);
+ sfree(data);
}
static unsigned char *ssh2_mpint_fmt(Bignum b, int *len)
{
unsigned char *p;
int len;
p = ssh2_mpint_fmt(b, &len);
- ssh2_pkt_addstring_start(pkt);
- ssh2_pkt_addstring_data(pkt, (char *)p, len);
+ ssh_pkt_addstring_start(pkt);
+ ssh_pkt_addstring_data(pkt, (char *)p, len);
sfree(p);
}
+static struct Packet *ssh1_pkt_init(int pkt_type)
+{
+ struct Packet *pkt = ssh_new_packet();
+ pkt->length = 4 + 8; /* space for length + max padding */
+ ssh_pkt_addbyte(pkt, pkt_type);
+ pkt->body = pkt->data + pkt->length;
+ return pkt;
+}
+
+/* For legacy code (SSH-1 and -2 packet construction used to be separate) */
+#define ssh2_pkt_ensure(pkt, length) ssh_pkt_ensure(pkt, length)
+#define ssh2_pkt_adddata(pkt, data, len) ssh_pkt_adddata(pkt, data, len)
+#define ssh2_pkt_addbyte(pkt, byte) ssh_pkt_addbyte(pkt, byte)
+#define ssh2_pkt_adduint32(pkt, value) ssh_pkt_adduint32(pkt, value)
+#define ssh2_pkt_addstring_start(pkt) ssh_pkt_addstring_start(pkt)
+#define ssh2_pkt_addstring_str(pkt, data) ssh_pkt_addstring_str(pkt, data)
+#define ssh2_pkt_addstring_data(pkt, data, len) ssh_pkt_addstring_data(pkt, data, len)
+#define ssh2_pkt_addstring(pkt, data) ssh_pkt_addstring(pkt, data)
+
+static struct Packet *ssh2_pkt_init(int pkt_type)
+{
+ struct Packet *pkt = ssh_new_packet();
+ pkt->length = 5;
+ pkt->forcepad = 0;
+ ssh_pkt_addbyte(pkt, (unsigned char) pkt_type);
+ pkt->body = pkt->data + pkt->length;
+ return pkt;
+}
+
/*
* Construct an SSH-2 final-form packet: compress it, encrypt it,
* put the MAC on it. Final packet, ready to be sent, is stored in
if (ssh->logctx)
log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[5],
ssh2_pkt_type(ssh->pkt_ctx, pkt->data[5]),
- pkt->data + 6, pkt->length - 6,
+ pkt->body, pkt->length - (pkt->body - pkt->data),
pkt->nblanks, pkt->blanks);
sfree(pkt->blanks); pkt->blanks = NULL;
pkt->nblanks = 0;
struct ssh_channel *c;
ssh->state = SSH_STATE_CLOSED;
+ expire_timer_context(ssh);
if (ssh->s) {
sk_close(ssh->s);
ssh->s = NULL;
case CIPHER_AES:
s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_aes;
break;
+ case CIPHER_ARCFOUR:
+ s->preferred_ciphers[s->n_preferred_ciphers++] = &ssh2_arcfour;
+ break;
case CIPHER_WARN:
/* Flag for later. Don't bother if it's the last in
* the list. */
{
Ssh ssh = (Ssh)ctx;
+ if (ssh->state == SSH_STATE_CLOSED)
+ return;
+
if (!ssh->kex_in_progress && ssh->cfg.ssh_rekey_time != 0 &&
now - ssh->next_rekey >= 0) {
do_ssh2_transport(ssh, "timeout", -1, NULL);