Remove the special hooks in ssh.c for pscp. pscp now uses the standard
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index ff6e837..cdb12bf 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -2,12 +2,17 @@
 #include <stdlib.h>
 #include <stdarg.h>
 #include <assert.h>
+#ifndef AUTO_WINSOCK
+#ifdef WINSOCK_TWO
+#include <winsock2.h>
+#else
 #include <winsock.h>
+#endif
+#endif
 
 #include "putty.h"
 #include "tree234.h"
 #include "ssh.h"
-#include "scp.h"
 
 #ifndef FALSE
 #define FALSE 0
 #endif
 
 #define logevent(s) { logevent(s); \
-                      if (!(flags & FLAG_CONNECTION) && (flags & FLAG_VERBOSE)) \
+                      if ((flags & FLAG_STDERR) && (flags & FLAG_VERBOSE)) \
                       fprintf(stderr, "%s\n", s); }
 
+#define bombout(msg) ( ssh_state == SSH_STATE_CLOSED, closesocket(s), \
+                       s = INVALID_SOCKET, connection_fatal msg )
+
 #define SSH1_MSG_DISCONNECT                       1    /* 0x1 */
 #define SSH1_SMSG_PUBLIC_KEY                      2    /* 0x2 */
 #define SSH1_CMSG_SESSION_KEY                     3    /* 0x3 */
@@ -248,8 +256,10 @@ static void s_write (char *buf, int len) {
     while (len > 0) {
        int i = send (s, buf, len, 0);
         noise_ultralight(i);
-        if (i <= 0)
-            fatalbox("Lost connection while sending");
+        if (i <= 0) {
+            bombout(("Lost connection while sending"));
+            return;
+        }
        if (i > 0)
            len -= i, buf += i;
     }
@@ -269,7 +279,7 @@ static int s_read (char *buf, int len) {
 }
 
 static void c_write (char *buf, int len) {
-    if (!(flags & FLAG_CONNECTION)) {
+    if ((flags & FLAG_STDERR)) {
         int i;
         for (i = 0; i < len; i++)
             if (buf[i] != '\r')
@@ -280,6 +290,11 @@ static void c_write (char *buf, int len) {
         c_write1(*buf++);
 }
 
+static void c_writedata (char *buf, int len) {
+    while (len--)
+        c_write1(*buf++);
+}
+
 struct Packet {
     long length;
     int type;
@@ -372,7 +387,8 @@ next_packet:
     realcrc = crc32(pktin.data, biglen-4);
     gotcrc = GET_32BIT(pktin.data+biglen-4);
     if (gotcrc != realcrc) {
-       fatalbox("Incorrect CRC received on packet");
+       bombout(("Incorrect CRC received on packet"));
+        crReturn(0);
     }
 
     if (pktin.type == SSH1_SMSG_STDOUT_DATA ||
@@ -381,8 +397,10 @@ next_packet:
         pktin.type == SSH1_SMSG_AUTH_TIS_CHALLENGE ||
         pktin.type == SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
        long strlen = GET_32BIT(pktin.body);
-       if (strlen + 4 != pktin.length)
-           fatalbox("Received data packet with bogus string length");
+       if (strlen + 4 != pktin.length) {
+           bombout(("Received data packet with bogus string length"));
+            crReturn(0);
+        }
     }
 
     if (pktin.type == SSH1_MSG_DEBUG) {
@@ -503,8 +521,10 @@ next_packet:
     /*
      * Check the MAC.
      */
-    if (scmac && !scmac->verify(pktin.data, len+4, incoming_sequence))
-       fatalbox("Incorrect MAC received on packet");
+    if (scmac && !scmac->verify(pktin.data, len+4, incoming_sequence)) {
+       bombout(("Incorrect MAC received on packet"));
+        crReturn(0);
+    }
     incoming_sequence++;               /* whether or not we MACed */
 
     pktin.savedpos = 6;
@@ -950,8 +970,10 @@ Bignum ssh2_pkt_getmp(void) {
     ssh2_pkt_getstring(&p, &length);
     if (!p)
         return NULL;
-    if (p[0] & 0x80)
-        fatalbox("internal error: Can't handle negative mpints");
+    if (p[0] & 0x80) {
+        bombout(("internal error: Can't handle negative mpints"));
+        return NULL;
+    }
     b = newbn((length+1)/2);
     for (i = 0; i < length; i++) {
         j = length - 1 - i;
@@ -1069,8 +1091,10 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
 
     if (!ispkt) crWaitUntil(ispkt);
 
-    if (pktin.type != SSH1_SMSG_PUBLIC_KEY)
-       fatalbox("Public key packet not received");
+    if (pktin.type != SSH1_SMSG_PUBLIC_KEY) {
+       bombout(("Public key packet not received"));
+        crReturn(0);
+    }
 
     logevent("Received public keys");
 
@@ -1080,21 +1104,15 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
     j = makekey(pktin.body+8+i, &hostkey, &keystr2, 0);
 
     /*
-     * Hash the host key and print the hash in the log box. Just as
-     * a last resort in case the registry's host key checking is
-     * compromised, we'll allow the user some ability to verify
-     * host keys by eye.
+     * Log the host key fingerprint.
      */
-    MD5Init(&md5c);
-    MD5Update(&md5c, keystr2, hostkey.bytes);
-    MD5Final(session_id, &md5c);
     {
        char logmsg[80];
-       int i;
-       logevent("Host key MD5 is:");
+       logevent("Host key fingerprint is:");
        strcpy(logmsg, "      ");
-       for (i = 0; i < 16; i++)
-           sprintf(logmsg+strlen(logmsg), "%02x", session_id[i]);
+        hostkey.comment = NULL;
+        rsa_fingerprint(logmsg+strlen(logmsg), sizeof(logmsg)-strlen(logmsg),
+                        &hostkey);
        logevent(logmsg);
     }
 
@@ -1180,8 +1198,10 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
 
     crWaitUntil(ispkt);
 
-    if (pktin.type != SSH1_SMSG_SUCCESS)
-       fatalbox("Encryption not successfully enabled");
+    if (pktin.type != SSH1_SMSG_SUCCESS) {
+       bombout(("Encryption not successfully enabled"));
+        crReturn(0);
+    }
 
     logevent("Successfully started encryption");
 
@@ -1190,8 +1210,9 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
        static char username[100];
        static int pos = 0;
        static char c;
-       if ((flags & FLAG_CONNECTION) && !*cfg.username) {
+       if ((flags & FLAG_INTERACTIVE) && !*cfg.username) {
            c_write("login as: ", 10);
+            ssh_send_ok = 1;
            while (pos >= 0) {
                crWaitUntil(!ispkt);
                while (inlen--) switch (c = *in++) {
@@ -1230,7 +1251,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
            char stuff[200];
            strncpy(username, cfg.username, 99);
            username[99] = '\0';
-            if (flags & FLAG_VERBOSE) {
+            if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
                sprintf(stuff, "Sent username \"%s\".\r\n", username);
                 c_write(stuff, strlen(stuff));
            }
@@ -1250,6 +1271,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
 
     while (pktin.type == SSH1_SMSG_FAILURE) {
        static char password[100];
+       static char prompt[200];
        static int pos;
        static char c;
         static int pwpkt_type;
@@ -1334,10 +1356,12 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
                                 crWaitUntil(ispkt);
                                 if (pktin.type == SSH1_SMSG_SUCCESS) {
                                     logevent("Pageant's response accepted");
-                                    c_write("Authenticated using RSA key \"",
-                                            29);
-                                    c_write(commentp, commentlen);
-                                    c_write("\" from agent\r\n", 14);
+                                    if (flags & FLAG_VERBOSE) {
+                                        c_write("Authenticated using RSA key \"",
+                                                29);
+                                        c_write(commentp, commentlen);
+                                        c_write("\" from agent\r\n", 14);
+                                    }
                                     authed = TRUE;
                                 } else
                                     logevent("Pageant's response not accepted");
@@ -1362,9 +1386,71 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
         if (*cfg.keyfile && !tried_publickey)
             pwpkt_type = SSH1_CMSG_AUTH_RSA;
 
-       if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD && !FLAG_WINDOWED) {
-           char prompt[200];
-           sprintf(prompt, "%s@%s's password: ", cfg.username, savedhost);
+        if (pktin.type == SSH1_SMSG_FAILURE &&
+            cfg.try_tis_auth &&
+            (supported_auths_mask & (1<<SSH1_AUTH_TIS))) {
+            pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
+            logevent("Requested TIS authentication");
+            send_packet(SSH1_CMSG_AUTH_TIS, PKT_END);
+            crWaitUntil(ispkt);
+            if (pktin.type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
+                logevent("TIS authentication declined");
+                if (flags & FLAG_INTERACTIVE)
+                    c_write("TIS authentication refused.\r\n", 29);
+            } else {
+                int challengelen = ((pktin.body[0] << 24) |
+                                    (pktin.body[1] << 16) |
+                                    (pktin.body[2] << 8) |
+                                    (pktin.body[3]));
+                logevent("Received TIS challenge");
+                if (challengelen > sizeof(prompt)-1)
+                    challengelen = sizeof(prompt)-1;   /* prevent overrun */
+                memcpy(prompt, pktin.body+4, challengelen);
+                prompt[challengelen] = '\0';
+            }
+        }
+        if (pktin.type == SSH1_SMSG_FAILURE &&
+            cfg.try_tis_auth &&
+            (supported_auths_mask & (1<<SSH1_AUTH_CCARD))) {
+            pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
+            logevent("Requested CryptoCard authentication");
+            send_packet(SSH1_CMSG_AUTH_CCARD, PKT_END);
+            crWaitUntil(ispkt);
+            if (pktin.type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
+                logevent("CryptoCard authentication declined");
+                c_write("CryptoCard authentication refused.\r\n", 29);
+            } else {
+                int challengelen = ((pktin.body[0] << 24) |
+                                    (pktin.body[1] << 16) |
+                                    (pktin.body[2] << 8) |
+                                    (pktin.body[3]));
+                logevent("Received CryptoCard challenge");
+                if (challengelen > sizeof(prompt)-1)
+                    challengelen = sizeof(prompt)-1;   /* prevent overrun */
+                memcpy(prompt, pktin.body+4, challengelen);
+                strncpy(prompt + challengelen, "\r\nResponse : ",
+                        sizeof(prompt)-challengelen);
+                prompt[sizeof(prompt)-1] = '\0';
+            }
+        }
+        if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD) {
+            sprintf(prompt, "%.90s@%.90s's password: ",
+                    cfg.username, savedhost);
+        }
+        if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
+            char *comment = NULL;
+            if (flags & FLAG_VERBOSE)
+                c_write("Trying public key authentication.\r\n", 35);
+            if (!rsakey_encrypted(cfg.keyfile, &comment)) {
+                if (flags & FLAG_VERBOSE)
+                    c_write("No passphrase required.\r\n", 25);
+                goto tryauth;
+            }
+            sprintf(prompt, "Passphrase for key \"%.100s\": ", comment);
+            free(comment);
+        }
+
+       if (!(flags & FLAG_INTERACTIVE)) {
            if (!ssh_get_password(prompt, password, sizeof(password))) {
                 /*
                  * get_password failed to get a password (for
@@ -1377,60 +1463,9 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
                 crReturn(1);
             }
        } else {
-
-            if (pktin.type == SSH1_SMSG_FAILURE &&
-                cfg.try_tis_auth &&
-                (supported_auths_mask & (1<<SSH1_AUTH_TIS))) {
-                pwpkt_type = SSH1_CMSG_AUTH_TIS_RESPONSE;
-                logevent("Requested TIS authentication");
-                send_packet(SSH1_CMSG_AUTH_TIS, PKT_END);
-                crWaitUntil(ispkt);
-                if (pktin.type != SSH1_SMSG_AUTH_TIS_CHALLENGE) {
-                    logevent("TIS authentication declined");
-                    c_write("TIS authentication refused.\r\n", 29);
-                } else {
-                    int challengelen = ((pktin.body[0] << 24) |
-                                        (pktin.body[1] << 16) |
-                                        (pktin.body[2] << 8) |
-                                        (pktin.body[3]));
-                    logevent("Received TIS challenge");
-                    c_write(pktin.body+4, challengelen);
-                }
-            }
-            if (pktin.type == SSH1_SMSG_FAILURE &&
-                cfg.try_tis_auth &&
-                (supported_auths_mask & (1<<SSH1_AUTH_CCARD))) {
-                pwpkt_type = SSH1_CMSG_AUTH_CCARD_RESPONSE;
-                logevent("Requested CryptoCard authentication");
-                send_packet(SSH1_CMSG_AUTH_CCARD, PKT_END);
-                crWaitUntil(ispkt);
-                if (pktin.type != SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
-                    logevent("CryptoCard authentication declined");
-                    c_write("CryptoCard authentication refused.\r\n", 29);
-                } else {
-                    int challengelen = ((pktin.body[0] << 24) |
-                                        (pktin.body[1] << 16) |
-                                        (pktin.body[2] << 8) |
-                                        (pktin.body[3]));
-                    logevent("Received CryptoCard challenge");
-                    c_write(pktin.body+4, challengelen);
-                    c_write("\r\nResponse : ", 13);
-                }
-            }
-            if (pwpkt_type == SSH1_CMSG_AUTH_PASSWORD)
-                c_write("password: ", 10);
-            if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
-                if (flags & FLAG_VERBOSE)
-                    c_write("Trying public key authentication.\r\n", 35);
-                if (!rsakey_encrypted(cfg.keyfile)) {
-                    if (flags & FLAG_VERBOSE)
-                        c_write("No passphrase required.\r\n", 25);
-                    goto tryauth;
-                }
-                c_write("passphrase: ", 12);
-            }
-
+            c_write(prompt, strlen(prompt));
             pos = 0;
+            ssh_send_ok = 1;
             while (pos >= 0) {
                 crWaitUntil(!ispkt);
                 while (inlen--) switch (c = *in++) {
@@ -1457,8 +1492,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
                 }
             }
             c_write("\r\n", 2);
-
-       }
+        }
 
         tryauth:
        if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
@@ -1493,12 +1527,13 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
 
             crWaitUntil(ispkt);
             if (pktin.type == SSH1_SMSG_FAILURE) {
-                if (flags & FLAG_VERBOSE)
-                    c_write("Server refused our public key.\r\n", 32);
+                c_write("Server refused our public key.\r\n", 32);
                 continue;              /* go and try password */
             }
-            if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE)
-                fatalbox("Bizarre response to offer of public key");
+            if (pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) {
+                bombout(("Bizarre response to offer of public key"));
+                crReturn(0);
+            }
             ssh1_read_bignum(pktin.body, &challenge);
             response = rsadecrypt(challenge, &pubkey);
             freebn(pubkey.private_exponent);   /* burn the evidence */
@@ -1523,7 +1558,8 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
                             45);
                 continue;              /* go and try password */
             } else if (pktin.type != SSH1_SMSG_SUCCESS) {
-                fatalbox("Bizarre response to RSA authentication response");
+                bombout(("Bizarre response to RSA authentication response"));
+                crReturn(0);
             }
 
             break;                     /* we're through! */
@@ -1542,7 +1578,8 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
             ssh_state = SSH_STATE_CLOSED;
            crReturn(1);
        } else if (pktin.type != SSH1_SMSG_SUCCESS) {
-           fatalbox("Strange packet received, type %d", pktin.type);
+           bombout(("Strange packet received, type %d", pktin.type));
+            crReturn(0);
        }
     }
 
@@ -1567,7 +1604,8 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
         send_packet(SSH1_CMSG_AGENT_REQUEST_FORWARDING, PKT_END);
         do { crReturnV; } while (!ispkt);
         if (pktin.type != SSH1_SMSG_SUCCESS && pktin.type != SSH1_SMSG_FAILURE) {
-            fatalbox("Protocol confusion");
+            bombout(("Protocol confusion"));
+            crReturnV;
         } else if (pktin.type == SSH1_SMSG_FAILURE) {
             logevent("Agent forwarding refused");
         } else
@@ -1584,7 +1622,8 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
         ssh_state = SSH_STATE_INTERMED;
         do { crReturnV; } while (!ispkt);
         if (pktin.type != SSH1_SMSG_SUCCESS && pktin.type != SSH1_SMSG_FAILURE) {
-            fatalbox("Protocol confusion");
+            bombout(("Protocol confusion"));
+            crReturnV;
         } else if (pktin.type == SSH1_SMSG_FAILURE) {
             c_write("Server refused to allocate pty\r\n", 32);
         }
@@ -1603,13 +1642,14 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
 
     ssh_send_ok = 1;
     ssh_channels = newtree234(ssh_channelcmp);
+    begin_session();
     while (1) {
        crReturnV;
        if (ispkt) {
            if (pktin.type == SSH1_SMSG_STDOUT_DATA ||
                 pktin.type == SSH1_SMSG_STDERR_DATA) {
                long len = GET_32BIT(pktin.body);
-               c_write(pktin.body+4, len);
+               c_writedata(pktin.body+4, len);
            } else if (pktin.type == SSH1_MSG_DISCONNECT) {
                 ssh_state = SSH_STATE_CLOSED;
                logevent("Received disconnect request");
@@ -1629,6 +1669,7 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
                 c->localid = i;
                 c->closes = 0;
                 c->type = SSH1_SMSG_AGENT_OPEN;   /* identify channel type */
+                c->u.a.lensofar = 0;
                 add234(ssh_channels, c);
                 send_packet(SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
                             PKT_INT, c->remoteid, PKT_INT, c->localid,
@@ -1710,7 +1751,8 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt) {
            } else if (pktin.type == SSH1_SMSG_EXIT_STATUS) {
                send_packet(SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);
            } else {
-               fatalbox("Strange packet received: type %d", pktin.type);
+               bombout(("Strange packet received: type %d", pktin.type));
+                crReturnV;
            }
        } else {
            send_packet(SSH1_CMSG_STDIN_DATA,
@@ -1887,7 +1929,8 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
      * to.
      */
     if (pktin.type != SSH2_MSG_KEXINIT) {
-        fatalbox("expected key exchange packet from server");
+        bombout(("expected key exchange packet from server"));
+        crReturn(0);
     }
     kex = NULL; hostkey = NULL; cscipher_tobe = NULL; sccipher_tobe = NULL;
     csmac_tobe = NULL; scmac_tobe = NULL; cscomp_tobe = NULL; sccomp_tobe = NULL;
@@ -1953,8 +1996,10 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
      * Currently we only support Diffie-Hellman and DSS, so let's
      * bomb out if those aren't selected.
      */
-    if (kex != &ssh_diffiehellman || hostkey != &ssh_dss)
-        fatalbox("internal fault: chaos in SSH 2 transport layer");
+    if (kex != &ssh_diffiehellman || hostkey != &ssh_dss) {
+        bombout(("internal fault: chaos in SSH 2 transport layer"));
+        crReturn(0);
+    }
 
     /*
      * Now we begin the fun. Generate and send e for Diffie-Hellman.
@@ -1966,7 +2011,8 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
 
     crWaitUntil(ispkt);
     if (pktin.type != SSH2_MSG_KEXDH_REPLY) {
-        fatalbox("expected key exchange packet from server");
+        bombout(("expected key exchange packet from server"));
+        crReturn(0);
     }
     ssh2_pkt_getstring(&hostkeydata, &hostkeylen);
     f = ssh2_pkt_getmp();
@@ -1988,15 +2034,19 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
 #endif
 
     hostkey->setkey(hostkeydata, hostkeylen);
-    if (!hostkey->verifysig(sigdata, siglen, exchange_hash, 20))
-        fatalbox("Server failed host key check");
+    if (!hostkey->verifysig(sigdata, siglen, exchange_hash, 20)) {
+        bombout(("Server failed host key check"));
+        crReturn(0);
+    }
 
     /*
      * Expect SSH2_MSG_NEWKEYS from server.
      */
     crWaitUntil(ispkt);
-    if (pktin.type != SSH2_MSG_NEWKEYS)
-        fatalbox("expected new-keys packet from server");
+    if (pktin.type != SSH2_MSG_NEWKEYS) {
+        bombout(("expected new-keys packet from server"));
+        crReturn(0);
+    }
 
     /*
      * Authenticate remote host: verify host key. (We've already
@@ -2062,8 +2112,10 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
     ssh2_pkt_addstring("ssh-userauth");
     ssh2_pkt_send();
     crWaitUntilV(ispkt);
-    if (pktin.type != SSH2_MSG_SERVICE_ACCEPT)
-        fatalbox("Server refused user authentication protocol");
+    if (pktin.type != SSH2_MSG_SERVICE_ACCEPT) {
+        bombout(("Server refused user authentication protocol"));
+        crReturnV;
+    }
 
     /*
      * FIXME: currently we support only password authentication.
@@ -2079,8 +2131,9 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
        static int pos = 0;
        static char c;
 
-       if ((flags & FLAG_CONNECTION) && !*cfg.username) {
+       if ((flags & FLAG_INTERACTIVE) && !*cfg.username) {
            c_write("login as: ", 10);
+            ssh_send_ok = 1;
            while (pos >= 0) {
                crWaitUntilV(!ispkt);
                while (inlen--) switch (c = *in++) {
@@ -2119,15 +2172,15 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
            char stuff[200];
            strncpy(username, cfg.username, 99);
            username[99] = '\0';
-           if (flags & FLAG_VERBOSE) {
+            if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
                sprintf(stuff, "Using username \"%s\".\r\n", username);
                c_write(stuff, strlen(stuff));
            }
        }
 
-       if (!(flags & FLAG_WINDOWED)) {
+       if (!(flags & FLAG_INTERACTIVE)) {
            char prompt[200];
-           sprintf(prompt, "%s@%s's password: ", cfg.username, savedhost);
+           sprintf(prompt, "%.90s@%.90s's password: ", cfg.username, savedhost);
            if (!ssh_get_password(prompt, password, sizeof(password))) {
                 /*
                  * get_password failed to get a password (for
@@ -2141,6 +2194,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
             }
        } else {
             c_write("password: ", 10);
+            ssh_send_ok = 1;
 
             pos = 0;
             while (pos >= 0) {
@@ -2206,11 +2260,13 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
     ssh2_pkt_send();
     crWaitUntilV(ispkt);
     if (pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
-        fatalbox("Server refused to open a session");
+        bombout(("Server refused to open a session"));
+        crReturnV;
         /* FIXME: error data comes back in FAILURE packet */
     }
     if (ssh2_pkt_getuint32() != mainchan->localid) {
-        fatalbox("Server's channel confirmation cited wrong channel");
+        bombout(("Server's channel confirmation cited wrong channel"));
+        crReturnV;
     }
     mainchan->remoteid = ssh2_pkt_getuint32();
     mainchan->u.v2.remwindow = ssh2_pkt_getuint32();
@@ -2222,39 +2278,54 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
     /*
      * Now allocate a pty for the session.
      */
-    ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
-    ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */
-    ssh2_pkt_addstring("pty-req");
-    ssh2_pkt_addbool(1);               /* want reply */
-    ssh2_pkt_addstring(cfg.termtype);
-    ssh2_pkt_adduint32(cols);
-    ssh2_pkt_adduint32(rows);
-    ssh2_pkt_adduint32(0);             /* pixel width */
-    ssh2_pkt_adduint32(0);             /* pixel height */
-    ssh2_pkt_addstring_start();
-    ssh2_pkt_addstring_data("\0", 1);  /* TTY_OP_END, no special options */
-    ssh2_pkt_send();
+    if (!cfg.nopty) {
+        ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
+        ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */
+        ssh2_pkt_addstring("pty-req");
+        ssh2_pkt_addbool(1);           /* want reply */
+        ssh2_pkt_addstring(cfg.termtype);
+        ssh2_pkt_adduint32(cols);
+        ssh2_pkt_adduint32(rows);
+        ssh2_pkt_adduint32(0);         /* pixel width */
+        ssh2_pkt_adduint32(0);         /* pixel height */
+        ssh2_pkt_addstring_start();
+        ssh2_pkt_addstring_data("\0", 1);/* TTY_OP_END, no special options */
+        ssh2_pkt_send();
 
-    do {                               /* FIXME: pay attention to these */
-        crWaitUntilV(ispkt);
-    } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
+        do {
+            crWaitUntilV(ispkt);
+            if (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
+                /* FIXME: be able to handle other channels here */
+                if (ssh2_pkt_getuint32() != mainchan->localid)
+                    continue;          /* wrong channel */
+                mainchan->u.v2.remwindow += ssh2_pkt_getuint32();
+            }
+        } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
 
-    if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
-        if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
-            fatalbox("Server got confused by pty request");
+        if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
+            if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
+                bombout(("Server got confused by pty request"));
+                crReturnV;
+            }
+            c_write("Server refused to allocate pty\r\n", 32);
+        } else {
+            logevent("Allocated pty");
         }
-        c_write("Server refused to allocate pty\r\n", 32);
-    } else {
-        logevent("Allocated pty");
     }
 
     /*
-     * Start a shell.
+     * Start a shell or a remote command.
      */
     ssh2_pkt_init(SSH2_MSG_CHANNEL_REQUEST);
     ssh2_pkt_adduint32(mainchan->remoteid); /* recipient channel */
-    ssh2_pkt_addstring("shell");
-    ssh2_pkt_addbool(1);               /* want reply */
+    if (*cfg.remote_cmd) {
+        ssh2_pkt_addstring("exec");
+        ssh2_pkt_addbool(1);           /* want reply */
+        ssh2_pkt_addstring(cfg.remote_cmd);
+    } else {
+        ssh2_pkt_addstring("shell");
+        ssh2_pkt_addbool(1);           /* want reply */
+    }
     ssh2_pkt_send();
     do {
         crWaitUntilV(ispkt);
@@ -2267,17 +2338,20 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
     } while (pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
     if (pktin.type != SSH2_MSG_CHANNEL_SUCCESS) {
         if (pktin.type != SSH2_MSG_CHANNEL_FAILURE) {
-            fatalbox("Server got confused by shell request");
+            bombout(("Server got confused by shell/command request"));
+            crReturnV;
         }
-        fatalbox("Server refused to start a shell");
+        bombout(("Server refused to start a shell/command"));
+        crReturnV;
     } else {
-        logevent("Started a shell");
+        logevent("Started a shell/command");
     }
 
     /*
      * Transfer data!
      */
     ssh_send_ok = 1;
+    begin_session();
     while (1) {
         static int try_send;
        crReturnV;
@@ -2295,7 +2369,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                     continue;          /* extended but not stderr */
                 ssh2_pkt_getstring(&data, &length);
                 if (data) {
-                    c_write(data, length);
+                    c_writedata(data, length);
                     /*
                      * Enlarge the window again at the remote side,
                      * just in case it ever runs down and they fail
@@ -2334,7 +2408,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                 mainchan->u.v2.remwindow += ssh2_pkt_getuint32();
                 try_send = TRUE;
            } else {
-               fatalbox("Strange packet received: type %d", pktin.type);
+               bombout(("Strange packet received: type %d", pktin.type));
+                crReturnV;
            }
        } else {
             /*
@@ -2439,8 +2514,11 @@ static int ssh_msg (WPARAM wParam, LPARAM lParam) {
     if (s == INVALID_SOCKET)
        return 1;
 
-    if (WSAGETSELECTERROR(lParam) != 0)
+    if (WSAGETSELECTERROR(lParam) != 0) {
+        closesocket(s);
+        s = INVALID_SOCKET;
        return -WSAGETSELECTERROR(lParam);
+    }
 
     switch (WSAGETSELECTEVENT(lParam)) {
       case FD_READ:
@@ -2448,8 +2526,11 @@ static int ssh_msg (WPARAM wParam, LPARAM lParam) {
        ret = recv(s, buf, sizeof(buf), 0);
        if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK)
            return 1;
-       if (ret < 0)                   /* any _other_ error */
+       if (ret < 0) {                 /* any _other_ error */
+            closesocket(s);
+            s = INVALID_SOCKET;
            return -10000-WSAGetLastError();
+        }
        if (ret == 0) {
            s = INVALID_SOCKET;
            return 0;
@@ -2502,182 +2583,19 @@ static void ssh_size(void) {
  */
 static void ssh_special (Telnet_Special code) {
     if (code == TS_EOF) {
-        if (ssh_version = 1) {
+        if (ssh_version == 1) {
             send_packet(SSH1_CMSG_EOF, PKT_END);
         } else {
             ssh2_pkt_init(SSH2_MSG_CHANNEL_EOF);
             ssh2_pkt_adduint32(mainchan->remoteid);
             ssh2_pkt_send();
         }
+        logevent("Sent EOF message");
     } else {
         /* do nothing */
     }
 }
 
-
-/*
- * Read and decrypt one incoming SSH packet.
- * (only used by pSCP)
- */
-static void get_packet(void)
-{
-    unsigned char buf[4096], *p;
-    long to_read;
-    int len;
-
-    p = NULL;
-    len = 0;
-
-    while ((to_read = s_rdpkt(&p, &len)) > 0) {
-       if (to_read > sizeof(buf)) to_read = sizeof(buf);
-       len = s_read(buf, to_read);
-       if (len != to_read) {
-           closesocket(s);
-           s = INVALID_SOCKET;
-           return;
-       }
-       p = buf;
-    }
-
-    assert(len == 0);
-}
-
-/*
- * Receive a block of data over the SSH link. Block until
- * all data is available. Return nr of bytes read (0 if lost connection).
- * (only used by pSCP)
- */
-int ssh_scp_recv(unsigned char *buf, int len)
-{
-    static int pending_input_len = 0;
-    static unsigned char *pending_input_ptr;
-    int to_read = len;
-
-    if (pending_input_len >= to_read) {
-       memcpy(buf, pending_input_ptr, to_read);
-       pending_input_ptr += to_read;
-       pending_input_len -= to_read;
-       return len;
-    }
-    
-    if (pending_input_len > 0) {
-       memcpy(buf, pending_input_ptr, pending_input_len);
-       buf += pending_input_len;
-       to_read -= pending_input_len;
-       pending_input_len = 0;
-    }
-
-    if (s == INVALID_SOCKET)
-       return 0;
-    while (to_read > 0) {
-       get_packet();
-       if (s == INVALID_SOCKET)
-           return 0;
-       if (pktin.type == SSH1_SMSG_STDOUT_DATA) {
-           int plen = GET_32BIT(pktin.body);
-           if (plen <= to_read) {
-               memcpy(buf, pktin.body + 4, plen);
-               buf += plen;
-               to_read -= plen;
-           } else {
-               memcpy(buf, pktin.body + 4, to_read);
-               pending_input_len = plen - to_read;
-               pending_input_ptr = pktin.body + 4 + to_read;
-               to_read = 0;
-           }
-       } else if (pktin.type == SSH1_SMSG_STDERR_DATA) {
-           int plen = GET_32BIT(pktin.body);
-           fwrite(pktin.body + 4, plen, 1, stderr);
-       } else if (pktin.type == SSH1_MSG_DISCONNECT) {
-               logevent("Received disconnect request");
-       } else if (pktin.type == SSH1_SMSG_SUCCESS ||
-                  pktin.type == SSH1_SMSG_FAILURE) {
-               /* ignore */
-       } else if (pktin.type == SSH1_SMSG_EXIT_STATUS) {
-           char logbuf[100];
-           sprintf(logbuf, "Remote exit status: %d", GET_32BIT(pktin.body));
-           logevent(logbuf);
-           send_packet(SSH1_CMSG_EXIT_CONFIRMATION, PKT_END);
-           logevent("Closing connection");
-           closesocket(s);
-           s = INVALID_SOCKET;
-       } else {
-           fatalbox("Strange packet received: type %d", pktin.type);
-       }
-    }
-
-    return len;
-}
-
-/*
- * Send a block of data over the SSH link.
- * Block until all data is sent.
- * (only used by pSCP)
- */
-void ssh_scp_send(unsigned char *buf, int len)
-{
-    if (s == INVALID_SOCKET)
-       return;
-    send_packet(SSH1_CMSG_STDIN_DATA,
-                PKT_INT, len, PKT_DATA, buf, len, PKT_END);
-}
-
-/*
- * Send an EOF notification to the server.
- * (only used by pSCP)
- */
-void ssh_scp_send_eof(void)
-{
-    if (s == INVALID_SOCKET)
-       return;
-    send_packet(SSH1_CMSG_EOF, PKT_END);
-}
-
-/*
- * Set up the connection, login on the remote host and
- * start execution of a command.
- * Returns an error message, or NULL on success.
- * (only used by pSCP)
- */
-char *ssh_scp_init(char *host, int port, char *cmd, char **realhost)
-{
-    char buf[160], *p;
-
-#ifdef MSCRYPTOAPI
-    if (crypto_startup() == 0)
-       return "Microsoft high encryption pack not installed!";
-#endif
-
-    p = connect_to_host(host, port, realhost);
-    if (p != NULL)
-       return p;
-
-    random_init();
-
-    if (!do_ssh_init())
-       return "Protocol initialisation error";
-
-    /* Exchange keys and login */
-    do {
-       get_packet();
-       if (s == INVALID_SOCKET)
-           return "Connection closed by remote host";
-    } while (!do_ssh1_login(NULL, 0, 1));
-
-    if (ssh_state == SSH_STATE_CLOSED) {
-        closesocket(s);
-        s = INVALID_SOCKET;
-        return "Session initialisation error";
-    }
-
-    /* Execute command */
-    sprintf(buf, "Sending command: %.100s", cmd);
-    logevent(buf);
-    send_packet(SSH1_CMSG_EXEC_CMD, PKT_STR, cmd, PKT_END);
-
-    return NULL;
-}
-
 static SOCKET ssh_socket(void) { return s; }
 
 static int ssh_sendok(void) { return ssh_send_ok; }