X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/37508af4ab231b1fde58345f5237f3ee82803829..96b9dc0a7fbf77afadc5b83e4431425d234b55cc:/ssh.c diff --git a/ssh.c b/ssh.c index 8092c985..0d53ddbf 100644 --- a/ssh.c +++ b/ssh.c @@ -47,7 +47,8 @@ static char *savedhost; static enum { SSH_STATE_BEFORE_SIZE, SSH_STATE_INTERMED, - SSH_STATE_SESSION + SSH_STATE_SESSION, + SSH_STATE_CLOSED } ssh_state = SSH_STATE_BEFORE_SIZE; static int size_needed = FALSE; @@ -75,7 +76,6 @@ static int s_read (char *buf, int len) { static void c_write (char *buf, int len) { while (len--) { int new_head = (inbuf_head + 1) & INBUF_MASK; - int c = (unsigned char) *buf; if (new_head != inbuf_reap) { inbuf[inbuf_head] = *buf++; inbuf_head = new_head; @@ -100,10 +100,8 @@ static void ssh_size(void); static void ssh_gotdata(unsigned char *data, int datalen) { static long len, biglen, to_read; - static unsigned char c, *p; + static unsigned char *p; static int i, pad; - static char padding[8]; - static unsigned char word[4]; crBegin; while (1) { @@ -158,6 +156,8 @@ static void ssh_gotdata(unsigned char *data, int datalen) { if (pktin.type == 36) { /* SSH_MSG_DEBUG */ /* FIXME: log it */ + } else if (pktin.type == 32) { /* SSH_MSG_IGNORE */ + /* do nothing */; } else ssh_protocol(NULL, 0, 1); } @@ -174,8 +174,8 @@ static void s_wrpkt_start(int type, int len) { pktout.length = len-5; if (pktout.maxlen < biglen) { pktout.maxlen = biglen; - pktout.data = (pktout.data == NULL ? malloc(biglen) : - realloc(pktout.data, biglen)); + pktout.data = (pktout.data == NULL ? malloc(biglen+4) : + realloc(pktout.data, biglen+4)); if (!pktout.data) fatalbox("Out of memory"); } @@ -251,6 +251,7 @@ static int do_ssh_init(void) { sprintf(vstring, "SSH-%s-7.7.7\n", (strcmp(version, "1.5") <= 0 ? version : "1.5")); s_write(vstring, strlen(vstring)); + return 1; } static void ssh_protocol(unsigned char *in, int inlen, int ispkt) { @@ -260,8 +261,11 @@ static void ssh_protocol(unsigned char *in, int inlen, int ispkt) { unsigned char cookie[8]; struct RSAKey servkey, hostkey; struct MD5Context md5c; + unsigned long supported_ciphers_mask; + int cipher_type; extern struct ssh_cipher ssh_3des; + extern struct ssh_cipher ssh_blowfish; crBegin; @@ -281,6 +285,11 @@ static void ssh_protocol(unsigned char *in, int inlen, int ispkt) { j = makekey(pktin.body+8+i, &hostkey, &keystr2); + supported_ciphers_mask = (pktin.body[12+i+j] << 24) | + (pktin.body[13+i+j] << 16) | + (pktin.body[14+i+j] << 8) | + (pktin.body[15+i+j]); + MD5Update(&md5c, keystr2, hostkey.bytes); MD5Update(&md5c, keystr1, servkey.bytes); MD5Update(&md5c, pktin.body, 8); @@ -312,8 +321,15 @@ static void ssh_protocol(unsigned char *in, int inlen, int ispkt) { rsaencrypt(rsabuf, hostkey.bytes, &servkey); } + cipher_type = cfg.cipher == CIPHER_BLOWFISH ? SSH_CIPHER_BLOWFISH : + SSH_CIPHER_3DES; + if ((supported_ciphers_mask & (1 << cipher_type)) == 0) { + c_write("Selected cipher not supported, falling back to 3DES\r\n", 53); + cipher_type = SSH_CIPHER_3DES; + } + s_wrpkt_start(3, len+15); - pktout.body[0] = 3; /* SSH_CIPHER_3DES */ + pktout.body[0] = cipher_type; memcpy(pktout.body+1, cookie, 8); pktout.body[9] = (len*8) >> 8; pktout.body[10] = (len*8) & 0xFF; @@ -324,7 +340,8 @@ static void ssh_protocol(unsigned char *in, int inlen, int ispkt) { free(rsabuf); - cipher = &ssh_3des; + cipher = cipher_type == SSH_CIPHER_BLOWFISH ? &ssh_blowfish : + &ssh_3des; cipher->sesskey(session_key); do { crReturnV; } while (!ispkt); @@ -433,30 +450,32 @@ static void ssh_protocol(unsigned char *in, int inlen, int ispkt) { } } - i = strlen(cfg.termtype); - s_wrpkt_start(10, i+5*4+1); - pktout.body[0] = (i >> 24) & 0xFF; - pktout.body[1] = (i >> 16) & 0xFF; - pktout.body[2] = (i >> 8) & 0xFF; - pktout.body[3] = i & 0xFF; - memcpy(pktout.body+4, cfg.termtype, i); - i += 4; - pktout.body[i++] = (rows >> 24) & 0xFF; - pktout.body[i++] = (rows >> 16) & 0xFF; - pktout.body[i++] = (rows >> 8) & 0xFF; - pktout.body[i++] = rows & 0xFF; - pktout.body[i++] = (cols >> 24) & 0xFF; - pktout.body[i++] = (cols >> 16) & 0xFF; - pktout.body[i++] = (cols >> 8) & 0xFF; - pktout.body[i++] = cols & 0xFF; - memset(pktout.body+i, 0, 9); /* 0 pixwidth, 0 pixheight, 0.b endofopt */ - s_wrpkt(); - ssh_state = SSH_STATE_INTERMED; - do { crReturnV; } while (!ispkt); - if (pktin.type != 14 && pktin.type != 15) { - fatalbox("Protocol confusion"); - } else if (pktin.type == 15) { - c_write("Server refused to allocate pty\r\n", 32); + if (!cfg.nopty) { + i = strlen(cfg.termtype); + s_wrpkt_start(10, i+5*4+1); + pktout.body[0] = (i >> 24) & 0xFF; + pktout.body[1] = (i >> 16) & 0xFF; + pktout.body[2] = (i >> 8) & 0xFF; + pktout.body[3] = i & 0xFF; + memcpy(pktout.body+4, cfg.termtype, i); + i += 4; + pktout.body[i++] = (rows >> 24) & 0xFF; + pktout.body[i++] = (rows >> 16) & 0xFF; + pktout.body[i++] = (rows >> 8) & 0xFF; + pktout.body[i++] = rows & 0xFF; + pktout.body[i++] = (cols >> 24) & 0xFF; + pktout.body[i++] = (cols >> 16) & 0xFF; + pktout.body[i++] = (cols >> 8) & 0xFF; + pktout.body[i++] = cols & 0xFF; + memset(pktout.body+i, 0, 9); /* 0 pixwidth, 0 pixheight, 0.b endofopt */ + s_wrpkt(); + ssh_state = SSH_STATE_INTERMED; + do { crReturnV; } while (!ispkt); + if (pktin.type != 14 && pktin.type != 15) { + fatalbox("Protocol confusion"); + } else if (pktin.type == 15) { + c_write("Server refused to allocate pty\r\n", 32); + } } s_wrpkt_start(12, 0); @@ -475,7 +494,8 @@ static void ssh_protocol(unsigned char *in, int inlen, int ispkt) { len = (len << 8) + pktin.body[i]; c_write(pktin.body+4, len); } else if (pktin.type == 1) { - /* SSH_MSG_DISCONNECT: do nothing */ + /* SSH_MSG_DISCONNECT */ + ssh_state = SSH_STATE_CLOSED; } else if (pktin.type == 14) { /* SSH_MSG_SUCCESS: may be from EXEC_SHELL on some servers */ } else if (pktin.type == 15) { @@ -644,6 +664,7 @@ static int ssh_msg (WPARAM wParam, LPARAM lParam) { return 1; case FD_CLOSE: s = INVALID_SOCKET; + ssh_state = SSH_STATE_CLOSED; return 0; } return 1; /* shouldn't happen, but WTF */ @@ -665,22 +686,25 @@ static void ssh_send (char *buf, int len) { static void ssh_size(void) { switch (ssh_state) { case SSH_STATE_BEFORE_SIZE: + case SSH_STATE_CLOSED: break; /* do nothing */ case SSH_STATE_INTERMED: size_needed = TRUE; /* buffer for later */ break; case SSH_STATE_SESSION: - s_wrpkt_start(11, 16); - pktout.body[0] = (rows >> 24) & 0xFF; - pktout.body[1] = (rows >> 16) & 0xFF; - pktout.body[2] = (rows >> 8) & 0xFF; - pktout.body[3] = rows & 0xFF; - pktout.body[4] = (cols >> 24) & 0xFF; - pktout.body[5] = (cols >> 16) & 0xFF; - pktout.body[6] = (cols >> 8) & 0xFF; - pktout.body[7] = cols & 0xFF; - memset(pktout.body+8, 0, 8); - s_wrpkt(); + if (!cfg.nopty) { + s_wrpkt_start(11, 16); + pktout.body[0] = (rows >> 24) & 0xFF; + pktout.body[1] = (rows >> 16) & 0xFF; + pktout.body[2] = (rows >> 8) & 0xFF; + pktout.body[3] = rows & 0xFF; + pktout.body[4] = (cols >> 24) & 0xFF; + pktout.body[5] = (cols >> 16) & 0xFF; + pktout.body[6] = (cols >> 8) & 0xFF; + pktout.body[7] = cols & 0xFF; + memset(pktout.body+8, 0, 8); + s_wrpkt(); + } } }