* Packet type contexts, so that ssh2_pkt_type can correctly decode
* the ambiguous type numbers back into the correct type strings.
*/
-#define SSH2_PKTCTX_DHGROUP 0x0001
-#define SSH2_PKTCTX_DHGEX 0x0002
-#define SSH2_PKTCTX_RSAKEX 0x0004
-#define SSH2_PKTCTX_KEX_MASK 0x000F
-#define SSH2_PKTCTX_PUBLICKEY 0x0010
-#define SSH2_PKTCTX_PASSWORD 0x0020
-#define SSH2_PKTCTX_KBDINTER 0x0040
-#define SSH2_PKTCTX_AUTH_MASK 0x00F0
+typedef enum {
+ SSH2_PKTCTX_NOKEX,
+ SSH2_PKTCTX_DHGROUP,
+ SSH2_PKTCTX_DHGEX,
+ SSH2_PKTCTX_RSAKEX
+} Pkt_KCtx;
+typedef enum {
+ SSH2_PKTCTX_NOAUTH,
+ SSH2_PKTCTX_PUBLICKEY,
+ SSH2_PKTCTX_PASSWORD,
+ SSH2_PKTCTX_KBDINTER
+} Pkt_ACtx;
#define SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT 1 /* 0x1 */
#define SSH2_DISCONNECT_PROTOCOL_ERROR 2 /* 0x2 */
}
#define translate(x) if (type == x) return #x
-#define translatec(x,ctx) if (type == x && (pkt_ctx & ctx)) return #x
+#define translatek(x,ctx) if (type == x && (pkt_kctx == ctx)) return #x
+#define translatea(x,ctx) if (type == x && (pkt_actx == ctx)) return #x
static char *ssh1_pkt_type(int type)
{
translate(SSH1_MSG_DISCONNECT);
translate(SSH1_CMSG_AUTH_CCARD_RESPONSE);
return "unknown";
}
-static char *ssh2_pkt_type(int pkt_ctx, int type)
+static char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type)
{
translate(SSH2_MSG_DISCONNECT);
translate(SSH2_MSG_IGNORE);
translate(SSH2_MSG_SERVICE_ACCEPT);
translate(SSH2_MSG_KEXINIT);
translate(SSH2_MSG_NEWKEYS);
- translatec(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP);
- translatec(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP);
- translatec(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX);
- translatec(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX);
- translatec(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX);
- translatec(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX);
- translatec(SSH2_MSG_KEXRSA_PUBKEY, SSH2_PKTCTX_RSAKEX);
- translatec(SSH2_MSG_KEXRSA_SECRET, SSH2_PKTCTX_RSAKEX);
- translatec(SSH2_MSG_KEXRSA_DONE, SSH2_PKTCTX_RSAKEX);
+ translatek(SSH2_MSG_KEXDH_INIT, SSH2_PKTCTX_DHGROUP);
+ translatek(SSH2_MSG_KEXDH_REPLY, SSH2_PKTCTX_DHGROUP);
+ translatek(SSH2_MSG_KEX_DH_GEX_REQUEST, SSH2_PKTCTX_DHGEX);
+ translatek(SSH2_MSG_KEX_DH_GEX_GROUP, SSH2_PKTCTX_DHGEX);
+ translatek(SSH2_MSG_KEX_DH_GEX_INIT, SSH2_PKTCTX_DHGEX);
+ translatek(SSH2_MSG_KEX_DH_GEX_REPLY, SSH2_PKTCTX_DHGEX);
+ translatek(SSH2_MSG_KEXRSA_PUBKEY, SSH2_PKTCTX_RSAKEX);
+ translatek(SSH2_MSG_KEXRSA_SECRET, SSH2_PKTCTX_RSAKEX);
+ translatek(SSH2_MSG_KEXRSA_DONE, SSH2_PKTCTX_RSAKEX);
translate(SSH2_MSG_USERAUTH_REQUEST);
translate(SSH2_MSG_USERAUTH_FAILURE);
translate(SSH2_MSG_USERAUTH_SUCCESS);
translate(SSH2_MSG_USERAUTH_BANNER);
- translatec(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY);
- translatec(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD);
- translatec(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER);
- translatec(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER);
+ translatea(SSH2_MSG_USERAUTH_PK_OK, SSH2_PKTCTX_PUBLICKEY);
+ translatea(SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ, SSH2_PKTCTX_PASSWORD);
+ translatea(SSH2_MSG_USERAUTH_INFO_REQUEST, SSH2_PKTCTX_KBDINTER);
+ translatea(SSH2_MSG_USERAUTH_INFO_RESPONSE, SSH2_PKTCTX_KBDINTER);
translate(SSH2_MSG_GLOBAL_REQUEST);
translate(SSH2_MSG_REQUEST_SUCCESS);
translate(SSH2_MSG_REQUEST_FAILURE);
*
* - OUR_V2_WINSIZE is the maximum window size we present on SSH-2
* channels.
+ *
+ * - OUR_V2_BIGWIN is the window size we advertise for the only
+ * channel in a simple connection.
*/
#define SSH1_BUFFER_LIMIT 32768
#define SSH_MAX_BACKLOG 32768
#define OUR_V2_WINSIZE 16384
+#define OUR_V2_BIGWIN 0x10000000
#define OUR_V2_MAXPKT 0x4000UL
/* Maximum length of passwords/passphrases (arbitrary) */
struct ssh2_data_channel {
bufchain outbuffer;
unsigned remwindow, remmaxpkt;
- unsigned locwindow;
+ /* locwindow is signed so we can cope with excess data. */
+ int locwindow, locmaxwin;
} v2;
} v;
union {
bufchain banner; /* accumulates banners during do_ssh2_authconn */
- int pkt_ctx;
+ Pkt_KCtx pkt_kctx;
+ Pkt_ACtx pkt_actx;
void *x11auth;
/* "Session data" packets - omit the data field */
if ((st->pktin->type == SSH1_SMSG_STDOUT_DATA) ||
(st->pktin->type == SSH1_SMSG_STDERR_DATA)) {
- do_blank = TRUE; blank_prefix = 0;
- } else if (st->pktin->type == SSH1_MSG_CHANNEL_DATA) {
do_blank = TRUE; blank_prefix = 4;
+ } else if (st->pktin->type == SSH1_MSG_CHANNEL_DATA) {
+ do_blank = TRUE; blank_prefix = 8;
}
if (do_blank) {
blank.offset = blank_prefix;
int do_blank = FALSE, blank_prefix = 0;
/* "Session data" packets - omit the data field */
if (st->pktin->type == SSH2_MSG_CHANNEL_DATA) {
- do_blank = TRUE; blank_prefix = 4;
- } else if (st->pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) {
do_blank = TRUE; blank_prefix = 8;
+ } else if (st->pktin->type == SSH2_MSG_CHANNEL_EXTENDED_DATA) {
+ do_blank = TRUE; blank_prefix = 12;
}
if (do_blank) {
blank.offset = blank_prefix;
}
}
log_packet(ssh->logctx, PKT_INCOMING, st->pktin->type,
- ssh2_pkt_type(ssh->pkt_ctx, st->pktin->type),
+ ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx,
+ st->pktin->type),
st->pktin->data+6, st->pktin->length-6,
nblanks, &blank);
}
static int s_write(Ssh ssh, void *data, int len)
{
- log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len, 0, NULL);
+ if (ssh->logctx)
+ log_packet(ssh->logctx, PKT_OUTGOING, -1, NULL, data, len, 0, NULL);
return sk_write(ssh->s, (char *)data, len);
}
if (ssh->logctx)
log_packet(ssh->logctx, PKT_OUTGOING, pkt->data[5],
- ssh2_pkt_type(ssh->pkt_ctx, pkt->data[5]),
+ ssh2_pkt_type(ssh->pkt_kctx, ssh->pkt_actx, pkt->data[5]),
pkt->body, pkt->length - (pkt->body - pkt->data),
pkt->nblanks, pkt->blanks);
sfree(pkt->blanks); pkt->blanks = NULL;
crBegin(ssh->do_ssh_init_crstate);
- /*
- * If the SSH version number's fixed, set it now, and if it's SSH-2,
- * send the version string too.
- *
- * XXX This isn't actually early enough to be useful, since we only
- * get here when the first incoming byte turns up.
- */
- if (ssh->cfg.sshprot == 0)
- ssh->version = 1;
- if (ssh->cfg.sshprot == 3) {
- ssh->version = 2;
- ssh_send_verstring(ssh, NULL);
- }
-
/* Search for a line beginning with the string "SSH-" in the input. */
for (;;) {
if (c != 'S') goto no;
static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen)
{
/* Log raw data, if we're in that mode. */
- log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, datalen, 0, NULL);
+ if (ssh->logctx)
+ log_packet(ssh->logctx, PKT_INCOMING, -1, NULL, data, datalen,
+ 0, NULL);
crBegin(ssh->ssh_gotdata_crstate);
return err;
}
+ /*
+ * If the SSH version number's fixed, set it now, and if it's SSH-2,
+ * send the version string too.
+ */
+ if (ssh->cfg.sshprot == 0)
+ ssh->version = 1;
+ if (ssh->cfg.sshprot == 3) {
+ ssh->version = 2;
+ ssh_send_verstring(ssh, NULL);
+ }
+
return NULL;
}
} else {
send_packet(ssh, SSH1_MSG_CHANNEL_DATA,
PKT_INT, c->remoteid,
- PKTT_DATA,
PKT_INT, replylen,
+ PKTT_DATA,
PKT_DATA, sentreply, replylen,
PKTT_OTHER,
PKT_END);
if (ssh->version == 1) {
send_packet(ssh, SSH1_MSG_CHANNEL_DATA,
PKT_INT, c->remoteid,
- PKTT_DATA,
- PKT_INT, len, PKT_DATA, buf, len,
+ PKT_INT, len, PKTT_DATA, PKT_DATA, buf, len,
PKTT_OTHER, PKT_END);
/*
* In SSH-1 we can return 0 here - implying that forwarded
ssh1_throttle(ssh, -1);
}
} else {
- ssh2_set_window(c, OUR_V2_WINSIZE - bufsize);
+ ssh2_set_window(c, c->v.v2.locmaxwin - bufsize);
}
}
} else {
while (inlen > 0) {
int len = min(inlen, 512);
- send_packet(ssh, SSH1_CMSG_STDIN_DATA, PKTT_DATA,
- PKT_INT, len, PKT_DATA, in, len,
+ send_packet(ssh, SSH1_CMSG_STDIN_DATA,
+ PKT_INT, len, PKTT_DATA, PKT_DATA, in, len,
PKTT_OTHER, PKT_END);
in += len;
inlen -= len;
s->maclist = macs, s->nmacs = lenof(macs);
begin_key_exchange:
- ssh->pkt_ctx &= ~SSH2_PKTCTX_KEX_MASK;
+ ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;
{
int i, j, commalist_started;
*/
if (!ssh->kex->pdata) {
logevent("Doing Diffie-Hellman group exchange");
- ssh->pkt_ctx |= SSH2_PKTCTX_DHGEX;
+ ssh->pkt_kctx = SSH2_PKTCTX_DHGEX;
/*
* Work out how big a DH group we will need to allow that
* much data.
s->kex_init_value = SSH2_MSG_KEX_DH_GEX_INIT;
s->kex_reply_value = SSH2_MSG_KEX_DH_GEX_REPLY;
} else {
- ssh->pkt_ctx |= SSH2_PKTCTX_DHGROUP;
+ ssh->pkt_kctx = SSH2_PKTCTX_DHGROUP;
ssh->kex_ctx = dh_setup_group(ssh->kex);
s->kex_init_value = SSH2_MSG_KEXDH_INIT;
s->kex_reply_value = SSH2_MSG_KEXDH_REPLY;
} else {
logeventf(ssh, "Doing RSA key exchange with hash %s",
ssh->kex->hash->text_name);
- ssh->pkt_ctx |= SSH2_PKTCTX_RSAKEX;
+ ssh->pkt_kctx = SSH2_PKTCTX_RSAKEX;
/*
* RSA key exchange. First expect a KEXRSA_PUBKEY packet
* from the server.
len = c->v.v2.remmaxpkt;
pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_DATA);
ssh2_pkt_adduint32(pktout, c->remoteid);
- dont_log_data(ssh, pktout, PKTLOG_OMIT);
ssh2_pkt_addstring_start(pktout);
+ dont_log_data(ssh, pktout, PKTLOG_OMIT);
ssh2_pkt_addstring_data(pktout, data, len);
end_log_omission(ssh, pktout);
ssh2_pkt_send(ssh, pktout);
*
* "Significant" is arbitrarily defined as half the window size.
*/
- if (newwin > c->v.v2.locwindow * 2) {
+ if (newwin >= c->v.v2.locwindow * 2) {
struct Packet *pktout;
pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_WINDOW_ADJUST);
/*
* If we are not buffering too much data,
* enlarge the window again at the remote side.
+ * If we are buffering too much, we may still
+ * need to adjust the window if the server's
+ * sent excess data.
*/
- if (bufsize < OUR_V2_WINSIZE)
- ssh2_set_window(c, OUR_V2_WINSIZE - bufsize);
+ ssh2_set_window(c, bufsize < c->v.v2.locmaxwin ?
+ c->v.v2.locmaxwin - bufsize : 0);
}
}
} else {
c->localid = alloc_channel_id(ssh);
c->closes = 0;
- c->v.v2.locwindow = OUR_V2_WINSIZE;
+ c->v.v2.locwindow = c->v.v2.locmaxwin = OUR_V2_WINSIZE;
c->v.v2.remwindow = winsize;
c->v.v2.remmaxpkt = pktsize;
bufchain_init(&c->v.v2.outbuffer);
* just in case it succeeds, and (b) so that we know what
* authentication methods we can usefully try next.
*/
- ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
+ ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(s->pktout, s->username);
in_commasep_string("keyboard-interactive", methods, methlen);
}
- ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
+ ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;
if (s->can_pubkey && !s->done_agent && s->nkeys) {
* Attempt public-key authentication using a key from Pageant.
*/
- ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
- ssh->pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
+ ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY;
logeventf(ssh, "Trying Pageant key #%d", s->keyi);
struct ssh2_userkey *key; /* not live over crReturn */
char *passphrase; /* not live over crReturn */
- ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
- ssh->pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
+ ssh->pkt_actx = SSH2_PKTCTX_PUBLICKEY;
s->tried_pubkey_config = TRUE;
s->type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
- ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
- ssh->pkt_ctx |= SSH2_PKTCTX_KBDINTER;
+ ssh->pkt_actx = SSH2_PKTCTX_KBDINTER;
s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
ssh2_pkt_addstring(s->pktout, s->username);
int ret; /* not live over crReturn */
int changereq_first_time; /* not live over crReturn */
- ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
- ssh->pkt_ctx |= SSH2_PKTCTX_PASSWORD;
+ ssh->pkt_actx = SSH2_PKTCTX_PASSWORD;
s->cur_prompt = new_prompts(ssh->frontend);
s->cur_prompt->to_server = TRUE;
s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
ssh2_pkt_addstring(s->pktout, "direct-tcpip");
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid);
- ssh->mainchan->v.v2.locwindow = OUR_V2_WINSIZE;
+ ssh->mainchan->v.v2.locwindow = ssh->mainchan->v.v2.locmaxwin =
+ ssh->cfg.ssh_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE;
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */
ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT); /* our max pkt size */
ssh2_pkt_addstring(s->pktout, ssh->cfg.ssh_nc_host);
s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
ssh2_pkt_addstring(s->pktout, "session");
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid);
- ssh->mainchan->v.v2.locwindow = OUR_V2_WINSIZE;
+ ssh->mainchan->v.v2.locwindow = ssh->mainchan->v.v2.locmaxwin =
+ ssh->cfg.ssh_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE;
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */
ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT); /* our max pkt size */
ssh2_pkt_send(ssh, s->pktout);
ssh->deferred_len = 0;
ssh->deferred_size = 0;
ssh->fallback_cmd = 0;
- ssh->pkt_ctx = 0;
+ ssh->pkt_kctx = SSH2_PKTCTX_NOKEX;
+ ssh->pkt_actx = SSH2_PKTCTX_NOAUTH;
ssh->x11auth = NULL;
ssh->v1_compressing = FALSE;
ssh->v2_outgoing_sequence = 0;
ssh1_throttle(ssh, -1);
}
} else {
- ssh2_set_window(ssh->mainchan, OUR_V2_WINSIZE - bufsize);
+ ssh2_set_window(ssh->mainchan,
+ ssh->mainchan->v.v2.locmaxwin - bufsize);
}
}
pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
ssh2_pkt_addstring(pktout, "direct-tcpip");
ssh2_pkt_adduint32(pktout, c->localid);
- c->v.v2.locwindow = OUR_V2_WINSIZE;
+ c->v.v2.locwindow = c->v.v2.locmaxwin = OUR_V2_WINSIZE;
ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);/* our window size */
ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT); /* our max pkt size */
ssh2_pkt_addstring(pktout, hostname);