Hack to work around the rootshell.com xterm DoS problem. A better
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index 93a1280..295d0e6 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -101,6 +101,9 @@ static void c_write (char *buf, int len) {
        if (new_head != inbuf_reap) {
            inbuf[inbuf_head] = *buf++;
            inbuf_head = new_head;
+       } else {
+            term_out();
+            if( inbuf_head == inbuf_reap ) len++; else break;
        }
     }
 }
@@ -124,6 +127,7 @@ static void ssh_gotdata(unsigned char *data, int datalen) {
     static long len, biglen, to_read;
     static unsigned char *p;
     static int i, pad;
+    static unsigned long realcrc, gotcrc;
 
     crBegin;
     while (1) {
@@ -149,8 +153,15 @@ static void ssh_gotdata(unsigned char *data, int datalen) {
        pktin.length = len;
        if (pktin.maxlen < biglen) {
            pktin.maxlen = biglen;
+#ifdef MSCRYPTOAPI
+           /* Allocate enough buffer space for extra block
+            * for MS CryptEncrypt() */
+           pktin.data = (pktin.data == NULL ? malloc(biglen+8) :
+                         realloc(pktin.data, biglen+8));
+#else
            pktin.data = (pktin.data == NULL ? malloc(biglen) :
-                       realloc(pktin.data, biglen));
+                         realloc(pktin.data, biglen));
+#endif
            if (!pktin.data)
                fatalbox("Out of memory");
        }
@@ -176,6 +187,15 @@ static void ssh_gotdata(unsigned char *data, int datalen) {
        pktin.type = pktin.data[pad];
        pktin.body = pktin.data+pad+1;
 
+       realcrc = crc32(pktin.data, biglen-4);
+       gotcrc = (pktin.data[biglen-4] << 24);
+       gotcrc |= (pktin.data[biglen-3] << 16);
+       gotcrc |= (pktin.data[biglen-2] <<  8);
+       gotcrc |= (pktin.data[biglen-1] <<  0);
+       if (gotcrc != realcrc) {
+           fatalbox("Incorrect CRC received on packet");
+       }
+
        if (pktin.type == SSH_MSG_DEBUG) {
            /* FIXME: log it */
        } else if (pktin.type == SSH_MSG_IGNORE) {
@@ -196,8 +216,15 @@ static void s_wrpkt_start(int type, int len) {
     pktout.length = len-5;
     if (pktout.maxlen < biglen) {
        pktout.maxlen = biglen;
+#ifdef MSCRYPTOAPI
+       /* Allocate enough buffer space for extra block 
+        * for MS CryptEncrypt() */
+       pktout.data = (pktout.data == NULL ? malloc(biglen+8) :
+                      realloc(pktout.data, biglen+8));
+#else
        pktout.data = (pktout.data == NULL ? malloc(biglen+4) :
                       realloc(pktout.data, biglen+4));
+#endif
        if (!pktout.data)
            fatalbox("Out of memory");
     }
@@ -382,7 +409,21 @@ static void ssh_protocol(unsigned char *in, int inlen, int ispkt) {
     if (!rsabuf)
        fatalbox("Out of memory");
 
-    verify_ssh_host_key(savedhost, &hostkey);
+    /*
+     * Verify the host key.
+     */
+    {
+        /*
+         * First format the key into a string.
+         */
+        int len = rsastr_len(&hostkey);
+        char *keystr = malloc(len);
+        if (!keystr)
+            fatalbox("Out of memory");
+        rsastr_fmt(keystr, &hostkey);
+        verify_ssh_host_key(savedhost, keystr);
+        free(keystr);
+    }
 
     for (i=0; i<32; i++) {
        rsabuf[i] = session_key[i];
@@ -469,7 +510,8 @@ static void ssh_protocol(unsigned char *in, int inlen, int ispkt) {
                    exit(0);
                    break;
                  default:
-                   if (c >= ' ' && c <= '~' && pos < 40) {
+                   if (((c >= ' ' && c <= '~') ||
+                         ((unsigned char)c >= 160)) && pos < 40) {
                        username[pos++] = c;
                        c_write(&c, 1);
                    }
@@ -553,7 +595,8 @@ static void ssh_protocol(unsigned char *in, int inlen, int ispkt) {
                exit(0);
                break;
              default:
-               if (c >= ' ' && c <= '~' && pos < 40)
+               if (((c >= ' ' && c <= '~') ||
+                     ((unsigned char)c >= 160)) && pos < 40)
                    password[pos++] = c;
                break;
            }
@@ -668,6 +711,11 @@ static char *ssh_init (HWND hwnd, char *host, int port, char **realhost) {
     char *FWhost;
     int FWport;
 #endif
+       
+#ifdef MSCRYPTOAPI
+    if(crypto_startup() == 0)
+       return "Microsoft high encryption pack not installed!";
+#endif
 
     savedhost = malloc(1+strlen(host));
     if (!savedhost)
@@ -772,14 +820,22 @@ static int ssh_msg (WPARAM wParam, LPARAM lParam) {
     int ret;
     char buf[256];
 
-    if (s == INVALID_SOCKET)          /* how the hell did we get here?! */
-       return -5000;
+    /*
+     * Because reading less than the whole of the available pending
+     * data can generate an FD_READ event, we need to allow for the
+     * possibility that FD_READ may arrive with FD_CLOSE already in
+     * the queue; so it's possible that we can get here even with s
+     * invalid. If so, we return 1 and don't worry about it.
+     */
+    if (s == INVALID_SOCKET)
+       return 1;
 
     if (WSAGETSELECTERROR(lParam) != 0)
        return -WSAGETSELECTERROR(lParam);
 
     switch (WSAGETSELECTEVENT(lParam)) {
       case FD_READ:
+      case FD_CLOSE:
        ret = recv(s, buf, sizeof(buf), 0);
        if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
            return 1;
@@ -787,14 +843,10 @@ static int ssh_msg (WPARAM wParam, LPARAM lParam) {
            return -10000-WSAGetLastError();
        if (ret == 0) {
            s = INVALID_SOCKET;
-           return 0;                  /* can't happen, in theory */
+           return 0;
        }
        ssh_gotdata (buf, ret);
        return 1;
-      case FD_CLOSE:
-       s = INVALID_SOCKET;
-        ssh_state = SSH_STATE_CLOSED;
-       return 0;
     }
     return 1;                         /* shouldn't happen, but WTF */
 }