Hiroshi Oota points out that PuTTY's agent forwarding sockets can get
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 8 Sep 2012 10:40:36 +0000 (10:40 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 8 Sep 2012 10:40:36 +0000 (10:40 +0000)
confused if they receive a request followed by immediate EOF, since we
currently send outgoing EOF as soon as we see the incoming one - and
then, when the response comes back from the real SSH agent, we send it
along anyway as channel data in spite of having sent EOF.

To fix this, I introduce a new field for each agent channel which
counts the number of calls to ssh_agentf_callback that are currently
expected, and we don't send EOF on an agent channel until we've both
received EOF and that value drops to zero.

git-svn-id: svn://svn.tartarus.org/sgt/putty@9651 cda61777-01e9-0310-a592-d414129be87e

ssh.c

diff --git a/ssh.c b/ssh.c
index b4d3884..e09ce73 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -666,6 +666,7 @@ struct ssh_channel {
            unsigned char *message;
            unsigned char msglen[4];
            unsigned lensofar, totallen;
+            int outstanding_requests;
        } a;
        struct ssh_x11_channel {
            Socket s;
@@ -3201,6 +3202,7 @@ static void ssh_agentf_callback(void *cv, void *reply, int replylen)
     Ssh ssh = c->ssh;
     void *sentreply = reply;
 
+    c->u.a.outstanding_requests--;
     if (!sentreply) {
        /* Fake SSH_AGENT_FAILURE. */
        sentreply = "\0\0\0\1\5";
@@ -3220,6 +3222,12 @@ static void ssh_agentf_callback(void *cv, void *reply, int replylen)
     }
     if (reply)
        sfree(reply);
+    /*
+     * If we've already seen an incoming EOF but haven't sent an
+     * outgoing one, this may be the moment to send it.
+     */
+    if (c->u.a.outstanding_requests == 0 && (c->closes & CLOSES_RCVD_EOF))
+        sshfwd_write_eof(c);
 }
 
 /*
@@ -4827,6 +4835,7 @@ static void ssh1_smsg_agent_open(Ssh ssh, struct Packet *pktin)
        c->type = CHAN_AGENT;   /* identify channel type */
        c->u.a.lensofar = 0;
        c->u.a.message = NULL;
+       c->u.a.outstanding_requests = 0;
        add234(ssh->channels, c);
        send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
                    PKT_INT, c->remoteid, PKT_INT, c->localid,
@@ -5052,6 +5061,7 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin)
                if (c->u.a.lensofar == c->u.a.totallen) {
                    void *reply;
                    int replylen;
+                    c->u.a.outstanding_requests++;
                    if (agent_query(c->u.a.message,
                                    c->u.a.totallen,
                                    &reply, &replylen,
@@ -6847,6 +6857,7 @@ static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin)
                if (c->u.a.lensofar == c->u.a.totallen) {
                    void *reply;
                    int replylen;
+                    c->u.a.outstanding_requests++;
                    if (agent_query(c->u.a.message,
                                    c->u.a.totallen,
                                    &reply, &replylen,
@@ -6985,8 +6996,10 @@ static void ssh2_channel_got_eof(struct ssh_channel *c)
     if (c->type == CHAN_X11) {
        x11_send_eof(c->u.x11.s);
     } else if (c->type == CHAN_AGENT) {
-        /* Manufacture an outgoing EOF in response to the incoming one. */
-        sshfwd_write_eof(c);
+        if (c->u.a.outstanding_requests == 0) {
+            /* Manufacture an outgoing EOF in response to the incoming one. */
+            sshfwd_write_eof(c);
+        }
     } else if (c->type == CHAN_SOCKDATA) {
        pfd_send_eof(c->u.pfd.s);
     } else if (c->type == CHAN_MAINSESSION) {
@@ -7408,6 +7421,7 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)
        else {
            c->type = CHAN_AGENT;       /* identify channel type */
            c->u.a.lensofar = 0;
+            c->u.a.outstanding_requests = 0;
        }
     } else {
        error = "Unsupported channel type requested";