Revamp of command-line handling. Most command line options should
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index 51bbf44..1885088 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -181,6 +181,7 @@ static const char *const ssh2_disconnect_reasons[] = {
 #define BUG_SSH2_HMAC                             2
 #define BUG_NEEDS_SSH1_PLAIN_PASSWORD            4
 #define BUG_CHOKES_ON_RSA                        8
+#define BUG_SSH2_RSA_PADDING                    16
 
 static int ssh_pkt_ctx = 0;
 
@@ -514,8 +515,6 @@ static const struct ssh_compress *sccomp = NULL;
 static const struct ssh_kex *kex = NULL;
 static const struct ssh_signkey *hostkey = NULL;
 static unsigned char ssh2_session_id[20];
-int (*ssh_get_line) (const char *prompt, char *str, int maxlen,
-                    int is_pw) = NULL;
 
 static char *savedhost;
 static int savedport;
@@ -1540,6 +1539,7 @@ static int ssh2_pkt_getbool(void)
 static void ssh2_pkt_getstring(char **p, int *length)
 {
     *p = NULL;
+    *length = 0;
     if (pktin.length - pktin.savedpos < 4)
        return;
     *length = GET_32BIT(pktin.data + pktin.savedpos);
@@ -1567,6 +1567,75 @@ static Bignum ssh2_pkt_getmp(void)
 }
 
 /*
+ * Helper function to add an SSH2 signature blob to a packet.
+ * Expects to be shown the public key blob as well as the signature
+ * blob. Normally works just like ssh2_pkt_addstring, but will
+ * fiddle with the signature packet if necessary for
+ * BUG_SSH2_RSA_PADDING.
+ */
+static void ssh2_add_sigblob(void *pkblob_v, int pkblob_len,
+                            void *sigblob_v, int sigblob_len)
+{
+    unsigned char *pkblob = (unsigned char *)pkblob_v;
+    unsigned char *sigblob = (unsigned char *)sigblob_v;
+
+    /* dmemdump(pkblob, pkblob_len); */
+    /* dmemdump(sigblob, sigblob_len); */
+
+    /*
+     * See if this is in fact an ssh-rsa signature and a buggy
+     * server; otherwise we can just do this the easy way.
+     */
+    if ((ssh_remote_bugs & BUG_SSH2_RSA_PADDING) &&
+       (GET_32BIT(pkblob) == 7 && !memcmp(pkblob+4, "ssh-rsa", 7))) {
+       int pos, len, siglen;
+
+       /*
+        * Find the byte length of the modulus.
+        */
+
+       pos = 4+7;                     /* skip over "ssh-rsa" */
+       pos += 4 + GET_32BIT(pkblob+pos);   /* skip over exponent */
+       len = GET_32BIT(pkblob+pos);   /* find length of modulus */
+       pos += 4;                      /* find modulus itself */
+       while (len > 0 && pkblob[pos] == 0)
+           len--, pos++;
+       /* debug(("modulus length is %d\n", len)); */
+
+       /*
+        * Now find the signature integer.
+        */
+       pos = 4+7;                     /* skip over "ssh-rsa" */
+       siglen = GET_32BIT(sigblob+pos);
+       /* debug(("signature length is %d\n", siglen)); */
+
+       if (len != siglen) {
+           unsigned char newlen[4];
+           ssh2_pkt_addstring_start();
+           ssh2_pkt_addstring_data(sigblob, pos);
+           /* dmemdump(sigblob, pos); */
+           pos += 4;                  /* point to start of actual sig */
+           PUT_32BIT(newlen, len);
+           ssh2_pkt_addstring_data(newlen, 4);
+           /* dmemdump(newlen, 4); */
+           newlen[0] = 0;
+           while (len-- > siglen) {
+               ssh2_pkt_addstring_data(newlen, 1);
+               /* dmemdump(newlen, 1); */
+           }
+           ssh2_pkt_addstring_data(sigblob+pos, siglen);
+           /* dmemdump(sigblob+pos, siglen); */
+           return;
+       }
+
+       /* Otherwise fall through and do it the easy way. */
+    }
+
+    ssh2_pkt_addstring_start();
+    ssh2_pkt_addstring_data(sigblob, sigblob_len);
+}
+
+/*
  * Examine the remote side's version string and compare it against
  * a list of known buggy implementations.
  */
@@ -1622,6 +1691,15 @@ static void ssh_detect_bugs(char *vstring)
        ssh_remote_bugs |= BUG_SSH2_HMAC;
        logevent("We believe remote version has SSH2 HMAC bug");
     }
+
+    if ((!strncmp(imp, "OpenSSH_2.", 10) && imp[10]>='5' && imp[10]<='9') ||
+       (!strncmp(imp, "OpenSSH_3.", 10) && imp[10]>='0' && imp[10]<='2')) {
+       /*
+        * These versions have the SSH2 RSA padding bug.
+        */
+       ssh_remote_bugs |= BUG_SSH2_RSA_PADDING;
+       logevent("We believe remote version has SSH2 RSA padding bug");
+    }
 }
 
 static int do_ssh_init(unsigned char c)
@@ -1722,6 +1800,12 @@ static int do_ssh_init(unsigned char c)
        sprintf(vlog, "We claim version: %s", verstring);
        logevent(vlog);
        strcat(verstring, "\n");
+       
+       if (cfg.sshprot == 3) {
+           bombout(("SSH protocol version 2 required by user but not provided by server"));
+           crReturn(0);
+       }
+
        logevent("Using SSH protocol version 1");
        sk_write(s, verstring, strlen(verstring));
        ssh_protocol = ssh1_protocol;
@@ -2142,7 +2226,7 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
        static int pos = 0;
        static char c;
        if ((flags & FLAG_INTERACTIVE) && !*cfg.username) {
-           if (ssh_get_line) {
+           if (ssh_get_line && !ssh_getline_pw_only) {
                if (!ssh_get_line("login as: ",
                                  username, sizeof(username), FALSE)) {
                    /*
@@ -2430,8 +2514,22 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
        }
        if (pwpkt_type == SSH1_CMSG_AUTH_RSA) {
            char *comment = NULL;
+           int type;
+           char msgbuf[256];
            if (flags & FLAG_VERBOSE)
                c_write_str("Trying public key authentication.\r\n");
+           sprintf(msgbuf, "Trying public key \"%.200s\"", cfg.keyfile);
+           logevent(msgbuf);
+           type = key_type(cfg.keyfile);
+           if (type != SSH_KEYTYPE_SSH1) {
+               sprintf(msgbuf, "Key is of wrong type (%s)",
+                       key_type_to_str(type));
+               logevent(msgbuf);
+               c_write_str(msgbuf);
+               c_write_str("\r\n");
+               tried_publickey = 1;
+               continue;
+           }
            if (!rsakey_encrypted(cfg.keyfile, &comment)) {
                if (flags & FLAG_VERBOSE)
                    c_write_str("No passphrase required.\r\n");
@@ -2719,7 +2817,7 @@ void sshfwd_close(struct ssh_channel *c)
         * on it now, and then when the server acks the channel
         * open, we can close it then.
         */
-       if (c->remoteid != -1) {
+       if (((int)c->remoteid) != -1) {
            if (ssh_version == 1) {
                send_packet(SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,
                            PKT_END);
@@ -2831,11 +2929,13 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt)
     }
 
     {
-       char type, *e;
+       char type;
+       static char *e;
        int n;
-       int sport,dport;
+       int sport,dport,sserv,dserv;
        char sports[256], dports[256], host[256];
        char buf[1024];
+       struct servent *se;
 
        ssh_rportfwds = newtree234(ssh_rportcmp_ssh1);
         /* Add port forwardings. */
@@ -2860,12 +2960,43 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt)
            dports[n] = 0;
            e++;
            dport = atoi(dports);
+           dserv = 0;
+           if (dport == 0) {
+               dserv = 1;
+               se = getservbyname(dports, NULL);
+               if (se != NULL) {
+                   dport = ntohs(se->s_port);
+               } else {
+                   sprintf(buf,
+                           "Service lookup failed for destination port \"%s\"",
+                           dports);
+                   logevent(buf);
+               }
+           }
            sport = atoi(sports);
+           sserv = 0;
+           if (sport == 0) {
+               sserv = 1;
+               se = getservbyname(sports, NULL);
+               if (se != NULL) {
+                   sport = ntohs(se->s_port);
+               } else {
+                   sprintf(buf,
+                           "Service lookup failed for source port \"%s\"",
+                           sports);
+                   logevent(buf);
+               }
+           }
            if (sport && dport) {
                if (type == 'L') {
                    pfd_addforward(host, dport, sport);
-                   sprintf(buf, "Local port %d forwarding to %s:%d",
-                           sport, host, dport);
+                   sprintf(buf, "Local port %.*s%.*s%d%.*s forwarding to"
+                           " %s:%.*s%.*s%d%.*s",
+                           sserv ? strlen(sports) : 0, sports,
+                           sserv, "(", sport, sserv, ")",
+                           host,
+                           dserv ? strlen(dports) : 0, dports,
+                           dserv, "(", dport, dserv, ")");
                    logevent(buf);
                } else {
                    struct ssh_rportfwd *pf;
@@ -2879,14 +3010,31 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt)
                        logevent(buf);
                        sfree(pf);
                    } else {
-                       sprintf(buf, "Requesting remote port %d forward to %s:%d",
-                               sport, host, dport);
+                       sprintf(buf, "Requesting remote port %.*s%.*s%d%.*s"
+                               " forward to %s:%.*s%.*s%d%.*s",
+                           sserv ? strlen(sports) : 0, sports,
+                           sserv, "(", sport, sserv, ")",
+                           host,
+                           dserv ? strlen(dports) : 0, dports,
+                           dserv, "(", dport, dserv, ")");
                        logevent(buf);
                        send_packet(SSH1_CMSG_PORT_FORWARD_REQUEST,
                                    PKT_INT, sport,
                                    PKT_STR, host,
                                    PKT_INT, dport,
                                    PKT_END);
+                       do {
+                           crReturnV;
+                       } while (!ispkt);
+                       if (pktin.type != SSH1_SMSG_SUCCESS
+                           && pktin.type != SSH1_SMSG_FAILURE) {
+                           bombout(("Protocol confusion"));
+                           crReturnV;
+                       } else if (pktin.type == SSH1_SMSG_FAILURE) {
+                           c_write_str("Server refused port forwarding\r\n");
+                           ssh_editing = ssh_echoing = 1;
+                       }
+                       logevent("Remote port forwarding enabled");
                    }
                }
            }
@@ -3885,7 +4033,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
     static int tried_pubkey_config, tried_agent, tried_keyb_inter;
     static int kbd_inter_running;
     static int we_are_in;
-    static int num_prompts, echo;
+    static int num_prompts, curr_prompt, echo;
     static char username[100];
     static int got_username;
     static char pwprompt[200];
@@ -3948,7 +4096,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
             * it again.
             */
        } else if ((flags & FLAG_INTERACTIVE) && !*cfg.username) {
-           if (ssh_get_line) {
+           if (ssh_get_line && !ssh_getline_pw_only) {
                if (!ssh_get_line("login as: ",
                                  username, sizeof(username), FALSE)) {
                    /*
@@ -4035,8 +4183,21 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
        kbd_inter_running = FALSE;
        /* Load the pub half of cfg.keyfile so we notice if it's in Pageant */
        if (*cfg.keyfile) {
-           publickey_blob = ssh2_userkey_loadpub(cfg.keyfile, NULL,
-                                                 &publickey_bloblen);
+           int keytype;
+           logeventf("Reading private key file \"%.150s\"", cfg.keyfile);
+           keytype = key_type(cfg.keyfile);
+           if (keytype == SSH_KEYTYPE_SSH2)
+               publickey_blob = ssh2_userkey_loadpub(cfg.keyfile, NULL,
+                                                     &publickey_bloblen);
+           else {
+               char msgbuf[256];
+               logeventf("Unable to use this key file (%s)",
+                       key_type_to_str(keytype));
+               sprintf(msgbuf, "Unable to use key file \"%.150s\" (%s)\r\n",
+                       cfg.keyfile, key_type_to_str(keytype));
+               c_write_str(msgbuf);
+               publickey_blob = NULL;
+           }
        } else
            publickey_blob = NULL;
 
@@ -4073,9 +4234,14 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
            if (kbd_inter_running &&
                pktin.type == SSH2_MSG_USERAUTH_INFO_REQUEST) {
                /*
-                * This is a further prompt in keyboard-interactive
-                * authentication. Do nothing.
+                * This is either a further set-of-prompts packet
+                * in keyboard-interactive authentication, or it's
+                * the same one and we came back here with `gotit'
+                * set. In the former case, we must reset the
+                * curr_prompt variable.
                 */
+               if (!gotit)
+                   curr_prompt = 0;
            } else if (pktin.type != SSH2_MSG_USERAUTH_FAILURE) {
                bombout(("Strange packet received during authentication: type %d",
                         pktin.type));
@@ -4159,6 +4325,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                static int authed = FALSE;
                void *r;
 
+               ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
                ssh_pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
 
                tried_agent = TRUE;
@@ -4276,10 +4443,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                        if (ret) {
                            if (ret[4] == SSH2_AGENT_SIGN_RESPONSE) {
                                logevent("Sending Pageant's response");
-                               ssh2_pkt_addstring_start();
-                               ssh2_pkt_addstring_data(ret + 9,
-                                                       GET_32BIT(ret +
-                                                                 5));
+                               ssh2_add_sigblob(pkblob, pklen,
+                                                ret + 9, GET_32BIT(ret + 5));
                                ssh2_pkt_send();
                                authed = TRUE;
                                break;
@@ -4295,7 +4460,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                }
            }
 
-           if (!method && can_pubkey && *cfg.keyfile
+           if (!method && can_pubkey && publickey_blob
                && !tried_pubkey_config) {
                unsigned char *pub_blob;
                char *algorithm, *comment;
@@ -4303,6 +4468,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
 
                tried_pubkey_config = TRUE;
 
+               ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
                ssh_pkt_ctx |= SSH2_PKTCTX_PUBLICKEY;
 
                /*
@@ -4357,6 +4523,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
                tried_keyb_inter = TRUE;
 
+               ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
                ssh_pkt_ctx |= SSH2_PKTCTX_KBDINTER;
 
                ssh2_pkt_init(SSH2_MSG_USERAUTH_REQUEST);
@@ -4377,6 +4544,7 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                }
 
                kbd_inter_running = TRUE;
+               curr_prompt = 0;
            }
 
            if (kbd_inter_running) {
@@ -4384,34 +4552,58 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
                tried_keyb_inter = TRUE;
 
+               ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
                ssh_pkt_ctx |= SSH2_PKTCTX_KBDINTER;
 
-               /* We've got packet with that "interactive" info
-                  dump banners, and set its prompt as ours */
-               {
-                   char *name, *inst, *lang, *prompt;
-                   int name_len, inst_len, lang_len, prompt_len;
+               if (curr_prompt == 0) {
+                   /*
+                    * We've got a fresh USERAUTH_INFO_REQUEST.
+                    * Display header data, and start going through
+                    * the prompts.
+                    */
+                   char *name, *inst, *lang;
+                   int name_len, inst_len, lang_len;
+
                    ssh2_pkt_getstring(&name, &name_len);
                    ssh2_pkt_getstring(&inst, &inst_len);
                    ssh2_pkt_getstring(&lang, &lang_len);
-                   if (name_len > 0)
+                   if (name_len > 0) {
                        c_write_untrusted(name, name_len);
-                   if (inst_len > 0)
+                       c_write_str("\n");
+                   }
+                   if (inst_len > 0) {
                        c_write_untrusted(inst, inst_len);
+                       c_write_str("\n");
+                   }
                    num_prompts = ssh2_pkt_getuint32();
+               }
 
-                   ssh2_pkt_getstring(&prompt, &prompt_len);
-                   strncpy(pwprompt, prompt, sizeof(pwprompt));
-                   pwprompt[prompt_len < sizeof(pwprompt) ?
-                            prompt_len : sizeof(pwprompt)-1] = '\0';
-                   need_pw = TRUE;
+               /*
+                * If there are prompts remaining in the packet,
+                * display one and get a response.
+                */
+               if (curr_prompt < num_prompts) {
+                   char *prompt;
+                   int prompt_len;
 
+                   ssh2_pkt_getstring(&prompt, &prompt_len);
+                   if (prompt_len > 0) {
+                       strncpy(pwprompt, prompt, sizeof(pwprompt));
+                       pwprompt[prompt_len < sizeof(pwprompt) ?
+                                prompt_len : sizeof(pwprompt)-1] = '\0';
+                   } else {
+                       strcpy(pwprompt,
+                              "<server failed to send prompt>: ");
+                   }
                    echo = ssh2_pkt_getbool();
-               }
+                   need_pw = TRUE;
+               } else
+                   need_pw = FALSE;
            }
 
            if (!method && can_passwd) {
                method = AUTH_PASSWORD;
+               ssh_pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK;
                ssh_pkt_ctx |= SSH2_PKTCTX_PASSWORD;
                sprintf(pwprompt, "%.90s@%.90s's password: ", username,
                        savedhost);
@@ -4502,8 +4694,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                    ssh2_pkt_send();
                    type = AUTH_TYPE_NONE;
                } else {
-                   unsigned char *blob, *sigdata;
-                   int blob_len, sigdata_len;
+                   unsigned char *pkblob, *sigblob, *sigdata;
+                   int pkblob_len, sigblob_len, sigdata_len;
 
                    /*
                     * We have loaded the private key and the server
@@ -4516,10 +4708,9 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                    ssh2_pkt_addstring("publickey");    /* method */
                    ssh2_pkt_addbool(TRUE);
                    ssh2_pkt_addstring(key->alg->name);
-                   blob = key->alg->public_blob(key->data, &blob_len);
+                   pkblob = key->alg->public_blob(key->data, &pkblob_len);
                    ssh2_pkt_addstring_start();
-                   ssh2_pkt_addstring_data(blob, blob_len);
-                   sfree(blob);
+                   ssh2_pkt_addstring_data(pkblob, pkblob_len);
 
                    /*
                     * The data to be signed is:
@@ -4535,12 +4726,12 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                    memcpy(sigdata + 4, ssh2_session_id, 20);
                    memcpy(sigdata + 24, pktout.data + 5,
                           pktout.length - 5);
-                   blob =
-                       key->alg->sign(key->data, sigdata, sigdata_len,
-                                      &blob_len);
-                   ssh2_pkt_addstring_start();
-                   ssh2_pkt_addstring_data(blob, blob_len);
-                   sfree(blob);
+                   sigblob = key->alg->sign(key->data, sigdata,
+                                            sigdata_len, &sigblob_len);
+                   ssh2_add_sigblob(pkblob, pkblob_len,
+                                    sigblob, sigblob_len);
+                   sfree(pkblob);
+                   sfree(sigblob);
                    sfree(sigdata);
 
                    ssh2_pkt_send();
@@ -4604,11 +4795,28 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                logevent("Sent password");
                type = AUTH_TYPE_PASSWORD;
            } else if (method == AUTH_KEYBOARD_INTERACTIVE) {
-                ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
-                ssh2_pkt_adduint32(num_prompts);
-                ssh2_pkt_addstring(password);
-                memset(password, 0, sizeof(password));
-                ssh2_pkt_send();
+               if (curr_prompt == 0) {
+                   ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
+                   ssh2_pkt_adduint32(num_prompts);
+               }
+               if (need_pw) {         /* only add pw if we just got one! */
+                   ssh2_pkt_addstring(password);
+                   memset(password, 0, sizeof(password));
+                   curr_prompt++;
+               }
+               if (curr_prompt >= num_prompts) {
+                   ssh2_pkt_send();
+               } else {
+                   /*
+                    * If there are prompts remaining, we set
+                    * `gotit' so that we won't attempt to get
+                    * another packet. Then we go back round the
+                    * loop and will end up retrieving another
+                    * prompt out of the existing packet. Funky or
+                    * what?
+                    */
+                   gotit = TRUE;
+               }
                type = AUTH_TYPE_KEYBOARD_INTERACTIVE;
            } else {
                c_write_str
@@ -4714,9 +4922,10 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
        static char *e;                /* preserve across crReturn */
        char type;
        int n;
-       int sport,dport;
+       int sport,dport,sserv,dserv;
        char sports[256], dports[256], host[256];
        char buf[1024];
+       struct servent *se;
 
        ssh_rportfwds = newtree234(ssh_rportcmp_ssh2);
         /* Add port forwardings. */
@@ -4741,12 +4950,43 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
            dports[n] = 0;
            e++;
            dport = atoi(dports);
+           dserv = 0;
+           if (dport == 0) {
+               dserv = 1;
+               se = getservbyname(dports, NULL);
+               if (se != NULL) {
+                   dport = ntohs(se->s_port);
+               } else {
+                   sprintf(buf,
+                           "Service lookup failed for destination port \"%s\"",
+                           dports);
+                   logevent(buf);
+               }
+           }
            sport = atoi(sports);
+           sserv = 0;
+           if (sport == 0) {
+               sserv = 1;
+               se = getservbyname(sports, NULL);
+               if (se != NULL) {
+                   sport = ntohs(se->s_port);
+               } else {
+                   sprintf(buf,
+                           "Service lookup failed for source port \"%s\"",
+                           sports);
+                   logevent(buf);
+               }
+           }
            if (sport && dport) {
                if (type == 'L') {
                    pfd_addforward(host, dport, sport);
-                   sprintf(buf, "Local port %d forwarding to %s:%d",
-                           sport, host, dport);
+                   sprintf(buf, "Local port %.*s%.*s%d%.*s forwarding to"
+                           " %s:%.*s%.*s%d%.*s",
+                           sserv ? strlen(sports) : 0, sports,
+                           sserv, "(", sport, sserv, ")",
+                           host,
+                           dserv ? strlen(dports) : 0, dports,
+                           dserv, "(", dport, dserv, ")");
                    logevent(buf);
                } else {
                    struct ssh_rportfwd *pf;
@@ -4761,8 +5001,13 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                        logevent(buf);
                        sfree(pf);
                    } else {
-                       sprintf(buf, "Requesting remote port %d (forwarded to %s:%d)",
-                               sport, host, dport);
+                       sprintf(buf, "Requesting remote port %.*s%.*s%d%.*s"
+                               " forward to %s:%.*s%.*s%d%.*s",
+                           sserv ? strlen(sports) : 0, sports,
+                           sserv, "(", sport, sserv, ")",
+                           host,
+                           dserv ? strlen(dports) : 0, dports,
+                           dserv, "(", dport, dserv, ")");
                        logevent(buf);
                        ssh2_pkt_init(SSH2_MSG_GLOBAL_REQUEST);
                        ssh2_pkt_addstring("tcpip-forward");
@@ -5161,7 +5406,6 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                c->type = CHAN_SOCKDATA;
                c->v.v2.remwindow = ssh2_pkt_getuint32();
                c->v.v2.remmaxpkt = ssh2_pkt_getuint32();
-               bufchain_init(&c->v.v2.outbuffer);
                if (c->u.pfd.s)
                    pfd_confirm(c->u.pfd.s);
                if (c->closes) {
@@ -5563,6 +5807,7 @@ void *new_sock_channel(Socket s)
        c->closes = 0;
        c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */
        c->u.pfd.s = s;
+       bufchain_init(&c->v.v2.outbuffer);
        add234(ssh_channels, c);
     }
     return c;