From 314c8f5270a8a880faaf30bb11ad3130350e6f55 Mon Sep 17 00:00:00 2001 From: Simon Tatham Date: Sun, 3 Jun 2018 07:37:45 +0100 Subject: [PATCH] Connection sharing: handle reply to cancel-tcpip-forward. This is another bug that must have been around since connection sharing was introduced, and nobody noticed until I did some unusually thorough testing yesterday. When a sharing downstream asks to set up a remote port forwarding, we pass through the "tcpip-forward" global request, and we also intercept the reply so that we know that the forwarding has been set up (and hence that we should be passing "forwarded-tcpip" channel opens for that port to this downstream). To do that, we set the want-reply flag in the version of the packet we pass to the server, even if it was clear in downstream's version; and we also put an item on a queue local to sshshare.c which reminds us what to do about the reply when it comes back. But when the downstream _cancels_ one of those forwardings, I wrote the code for all parts of that process except adding that queue item. I even wrote the code to _consume_ the queue item, but somehow I completely forgot to generate one in the first place! So the enum value GLOBREQ_CANCEL_TCPIP_FORWARD was declared, tested for, but never actually assigned to anything. --- sshshare.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/sshshare.c b/sshshare.c index 5f0c01a1..75b6940c 100644 --- a/sshshare.c +++ b/sshshare.c @@ -1146,6 +1146,7 @@ void share_got_pkt_from_server(void *csv, int type, case SSH2_MSG_REQUEST_SUCCESS: case SSH2_MSG_REQUEST_FAILURE: globreq = cs->globreq_head; + assert(globreq); /* should match the queue in ssh.c */ if (globreq->type == GLOBREQ_TCPIP_FORWARD) { if (type == SSH2_MSG_REQUEST_FAILURE) { share_remove_forwarding(cs, globreq->fwd); @@ -1402,6 +1403,20 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs, (cs->parent->ssh, cs->id, type, pkt, pktlen, orig_wantreply ? NULL : "upstream added want_reply flag"); ssh_sharing_queue_global_request(cs->parent->ssh, cs); + + /* + * And queue a globreq so that when the reply comes + * back we know to cancel it. + */ + globreq = snew(struct share_globreq); + globreq->next = NULL; + if (cs->globreq_tail) + cs->globreq_tail->next = globreq; + else + cs->globreq_head = globreq; + globreq->fwd = fwd; + globreq->want_reply = orig_wantreply; + globreq->type = GLOBREQ_CANCEL_TCPIP_FORWARD; } sfree(host);