summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--channels.c164
-rw-r--r--channels.h6
-rw-r--r--clientloop.h3
-rw-r--r--mux.c104
-rw-r--r--ssh.c4
6 files changed, 206 insertions, 80 deletions
diff --git a/ChangeLog b/ChangeLog
index dfce82822..b31ee81cd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -51,6 +51,11 @@
51 [sshd.c] 51 [sshd.c]
52 kill the preauth privsep child on fatal errors in the monitor; 52 kill the preauth privsep child on fatal errors in the monitor;
53 ok markus@ 53 ok markus@
54 - djm@cvs.openbsd.org 2011/09/09 22:46:44
55 [channels.c channels.h clientloop.h mux.c ssh.c]
56 support for cancelling local and remote port forwards via the multiplex
57 socket. Use ssh -O cancel -L xx:xx:xx -R yy:yy:yy user@host" to request
58 the cancellation of the specified forwardings; ok markus@
54 59
5520110909 6020110909
56 - (dtucker) [entropy.h] Bug #1932: remove old definition of init_rng. From 61 - (dtucker) [entropy.h] Bug #1932: remove old definition of init_rng. From
diff --git a/channels.c b/channels.c
index 24d4a9f42..0f7e1a872 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.c,v 1.311 2011/06/22 22:08:42 djm Exp $ */ 1/* $OpenBSD: channels.c,v 1.312 2011/09/09 22:46:44 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -302,6 +302,8 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
302 buffer_init(&c->output); 302 buffer_init(&c->output);
303 buffer_init(&c->extended); 303 buffer_init(&c->extended);
304 c->path = NULL; 304 c->path = NULL;
305 c->listening_addr = NULL;
306 c->listening_port = 0;
305 c->ostate = CHAN_OUTPUT_OPEN; 307 c->ostate = CHAN_OUTPUT_OPEN;
306 c->istate = CHAN_INPUT_OPEN; 308 c->istate = CHAN_INPUT_OPEN;
307 c->flags = 0; 309 c->flags = 0;
@@ -411,6 +413,10 @@ channel_free(Channel *c)
411 xfree(c->path); 413 xfree(c->path);
412 c->path = NULL; 414 c->path = NULL;
413 } 415 }
416 if (c->listening_addr) {
417 xfree(c->listening_addr);
418 c->listening_addr = NULL;
419 }
414 while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { 420 while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
415 if (cc->abandon_cb != NULL) 421 if (cc->abandon_cb != NULL)
416 cc->abandon_cb(c, cc->ctx); 422 cc->abandon_cb(c, cc->ctx);
@@ -2634,6 +2640,46 @@ channel_set_af(int af)
2634 IPv4or6 = af; 2640 IPv4or6 = af;
2635} 2641}
2636 2642
2643
2644/*
2645 * Determine whether or not a port forward listens to loopback, the
2646 * specified address or wildcard. On the client, a specified bind
2647 * address will always override gateway_ports. On the server, a
2648 * gateway_ports of 1 (``yes'') will override the client's specification
2649 * and force a wildcard bind, whereas a value of 2 (``clientspecified'')
2650 * will bind to whatever address the client asked for.
2651 *
2652 * Special-case listen_addrs are:
2653 *
2654 * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
2655 * "" (empty string), "*" -> wildcard v4/v6
2656 * "localhost" -> loopback v4/v6
2657 */
2658static const char *
2659channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
2660 int is_client, int gateway_ports)
2661{
2662 const char *addr = NULL;
2663 int wildcard = 0;
2664
2665 if (listen_addr == NULL) {
2666 /* No address specified: default to gateway_ports setting */
2667 if (gateway_ports)
2668 wildcard = 1;
2669 } else if (gateway_ports || is_client) {
2670 if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2671 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2672 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2673 (!is_client && gateway_ports == 1))
2674 wildcard = 1;
2675 else if (strcmp(listen_addr, "localhost") != 0)
2676 addr = listen_addr;
2677 }
2678 if (wildcardp != NULL)
2679 *wildcardp = wildcard;
2680 return addr;
2681}
2682
2637static int 2683static int
2638channel_setup_fwd_listener(int type, const char *listen_addr, 2684channel_setup_fwd_listener(int type, const char *listen_addr,
2639 u_short listen_port, int *allocated_listen_port, 2685 u_short listen_port, int *allocated_listen_port,
@@ -2659,36 +2705,9 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2659 return 0; 2705 return 0;
2660 } 2706 }
2661 2707
2662 /* 2708 /* Determine the bind address, cf. channel_fwd_bind_addr() comment */
2663 * Determine whether or not a port forward listens to loopback, 2709 addr = channel_fwd_bind_addr(listen_addr, &wildcard,
2664 * specified address or wildcard. On the client, a specified bind 2710 is_client, gateway_ports);
2665 * address will always override gateway_ports. On the server, a
2666 * gateway_ports of 1 (``yes'') will override the client's
2667 * specification and force a wildcard bind, whereas a value of 2
2668 * (``clientspecified'') will bind to whatever address the client
2669 * asked for.
2670 *
2671 * Special-case listen_addrs are:
2672 *
2673 * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
2674 * "" (empty string), "*" -> wildcard v4/v6
2675 * "localhost" -> loopback v4/v6
2676 */
2677 addr = NULL;
2678 if (listen_addr == NULL) {
2679 /* No address specified: default to gateway_ports setting */
2680 if (gateway_ports)
2681 wildcard = 1;
2682 } else if (gateway_ports || is_client) {
2683 if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2684 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2685 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2686 (!is_client && gateway_ports == 1))
2687 wildcard = 1;
2688 else if (strcmp(listen_addr, "localhost") != 0)
2689 addr = listen_addr;
2690 }
2691
2692 debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s", 2711 debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
2693 type, wildcard, (addr == NULL) ? "NULL" : addr); 2712 type, wildcard, (addr == NULL) ? "NULL" : addr);
2694 2713
@@ -2793,6 +2812,7 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2793 c->path = xstrdup(host); 2812 c->path = xstrdup(host);
2794 c->host_port = port_to_connect; 2813 c->host_port = port_to_connect;
2795 c->listening_port = listen_port; 2814 c->listening_port = listen_port;
2815 c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
2796 success = 1; 2816 success = 1;
2797 } 2817 }
2798 if (success == 0) 2818 if (success == 0)
@@ -2810,9 +2830,36 @@ channel_cancel_rport_listener(const char *host, u_short port)
2810 2830
2811 for (i = 0; i < channels_alloc; i++) { 2831 for (i = 0; i < channels_alloc; i++) {
2812 Channel *c = channels[i]; 2832 Channel *c = channels[i];
2833 if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER)
2834 continue;
2835 if (strcmp(c->path, host) == 0 && c->listening_port == port) {
2836 debug2("%s: close channel %d", __func__, i);
2837 channel_free(c);
2838 found = 1;
2839 }
2840 }
2841
2842 return (found);
2843}
2844
2845int
2846channel_cancel_lport_listener(const char *lhost, u_short lport,
2847 u_short cport, int gateway_ports)
2848{
2849 u_int i;
2850 int found = 0;
2851 const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, gateway_ports);
2813 2852
2814 if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && 2853 for (i = 0; i < channels_alloc; i++) {
2815 strcmp(c->path, host) == 0 && c->listening_port == port) { 2854 Channel *c = channels[i];
2855 if (c == NULL || c->type != SSH_CHANNEL_PORT_LISTENER)
2856 continue;
2857 if (c->listening_port != lport || c->host_port != cport)
2858 continue;
2859 if ((c->listening_addr == NULL && addr != NULL) ||
2860 (c->listening_addr != NULL && addr == NULL))
2861 continue;
2862 if (addr == NULL || strcmp(c->listening_addr, addr) == 0) {
2816 debug2("%s: close channel %d", __func__, i); 2863 debug2("%s: close channel %d", __func__, i);
2817 channel_free(c); 2864 channel_free(c);
2818 found = 1; 2865 found = 1;
@@ -2843,10 +2890,30 @@ channel_setup_remote_fwd_listener(const char *listen_address,
2843} 2890}
2844 2891
2845/* 2892/*
2893 * Translate the requested rfwd listen host to something usable for
2894 * this server.
2895 */
2896static const char *
2897channel_rfwd_bind_host(const char *listen_host)
2898{
2899 if (listen_host == NULL) {
2900 if (datafellows & SSH_BUG_RFWD_ADDR)
2901 return "127.0.0.1";
2902 else
2903 return "localhost";
2904 } else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0) {
2905 if (datafellows & SSH_BUG_RFWD_ADDR)
2906 return "0.0.0.0";
2907 else
2908 return "";
2909 } else
2910 return listen_host;
2911}
2912
2913/*
2846 * Initiate forwarding of connections to port "port" on remote host through 2914 * Initiate forwarding of connections to port "port" on remote host through
2847 * the secure channel to host:port from local side. 2915 * the secure channel to host:port from local side.
2848 */ 2916 */
2849
2850int 2917int
2851channel_request_remote_forwarding(const char *listen_host, u_short listen_port, 2918channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
2852 const char *host_to_connect, u_short port_to_connect) 2919 const char *host_to_connect, u_short port_to_connect)
@@ -2855,25 +2922,10 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
2855 2922
2856 /* Send the forward request to the remote side. */ 2923 /* Send the forward request to the remote side. */
2857 if (compat20) { 2924 if (compat20) {
2858 const char *address_to_bind;
2859 if (listen_host == NULL) {
2860 if (datafellows & SSH_BUG_RFWD_ADDR)
2861 address_to_bind = "127.0.0.1";
2862 else
2863 address_to_bind = "localhost";
2864 } else if (*listen_host == '\0' ||
2865 strcmp(listen_host, "*") == 0) {
2866 if (datafellows & SSH_BUG_RFWD_ADDR)
2867 address_to_bind = "0.0.0.0";
2868 else
2869 address_to_bind = "";
2870 } else
2871 address_to_bind = listen_host;
2872
2873 packet_start(SSH2_MSG_GLOBAL_REQUEST); 2925 packet_start(SSH2_MSG_GLOBAL_REQUEST);
2874 packet_put_cstring("tcpip-forward"); 2926 packet_put_cstring("tcpip-forward");
2875 packet_put_char(1); /* boolean: want reply */ 2927 packet_put_char(1); /* boolean: want reply */
2876 packet_put_cstring(address_to_bind); 2928 packet_put_cstring(channel_rfwd_bind_host(listen_host));
2877 packet_put_int(listen_port); 2929 packet_put_int(listen_port);
2878 packet_send(); 2930 packet_send();
2879 packet_write_wait(); 2931 packet_write_wait();
@@ -2917,13 +2969,13 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
2917 * Request cancellation of remote forwarding of connection host:port from 2969 * Request cancellation of remote forwarding of connection host:port from
2918 * local side. 2970 * local side.
2919 */ 2971 */
2920void 2972int
2921channel_request_rforward_cancel(const char *host, u_short port) 2973channel_request_rforward_cancel(const char *host, u_short port)
2922{ 2974{
2923 int i; 2975 int i;
2924 2976
2925 if (!compat20) 2977 if (!compat20)
2926 return; 2978 return -1;
2927 2979
2928 for (i = 0; i < num_permitted_opens; i++) { 2980 for (i = 0; i < num_permitted_opens; i++) {
2929 if (permitted_opens[i].host_to_connect != NULL && 2981 if (permitted_opens[i].host_to_connect != NULL &&
@@ -2932,12 +2984,12 @@ channel_request_rforward_cancel(const char *host, u_short port)
2932 } 2984 }
2933 if (i >= num_permitted_opens) { 2985 if (i >= num_permitted_opens) {
2934 debug("%s: requested forward not found", __func__); 2986 debug("%s: requested forward not found", __func__);
2935 return; 2987 return -1;
2936 } 2988 }
2937 packet_start(SSH2_MSG_GLOBAL_REQUEST); 2989 packet_start(SSH2_MSG_GLOBAL_REQUEST);
2938 packet_put_cstring("cancel-tcpip-forward"); 2990 packet_put_cstring("cancel-tcpip-forward");
2939 packet_put_char(0); 2991 packet_put_char(0);
2940 packet_put_cstring(host == NULL ? "" : host); 2992 packet_put_cstring(channel_rfwd_bind_host(host));
2941 packet_put_int(port); 2993 packet_put_int(port);
2942 packet_send(); 2994 packet_send();
2943 2995
@@ -2945,6 +2997,8 @@ channel_request_rforward_cancel(const char *host, u_short port)
2945 permitted_opens[i].port_to_connect = 0; 2997 permitted_opens[i].port_to_connect = 0;
2946 xfree(permitted_opens[i].host_to_connect); 2998 xfree(permitted_opens[i].host_to_connect);
2947 permitted_opens[i].host_to_connect = NULL; 2999 permitted_opens[i].host_to_connect = NULL;
3000
3001 return 0;
2948} 3002}
2949 3003
2950/* 3004/*
diff --git a/channels.h b/channels.h
index e2941c85a..37af32289 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: channels.h,v 1.105 2011/06/22 22:08:42 djm Exp $ */ 1/* $OpenBSD: channels.h,v 1.106 2011/09/09 22:46:44 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -116,6 +116,7 @@ struct Channel {
116 char *path; 116 char *path;
117 /* path for unix domain sockets, or host name for forwards */ 117 /* path for unix domain sockets, or host name for forwards */
118 int listening_port; /* port being listened for forwards */ 118 int listening_port; /* port being listened for forwards */
119 char *listening_addr; /* addr being listened for forwards */
119 int host_port; /* remote port to connect for forwards */ 120 int host_port; /* remote port to connect for forwards */
120 char *remote_name; /* remote hostname */ 121 char *remote_name; /* remote hostname */
121 122
@@ -261,9 +262,10 @@ int channel_request_remote_forwarding(const char *, u_short,
261 const char *, u_short); 262 const char *, u_short);
262int channel_setup_local_fwd_listener(const char *, u_short, 263int channel_setup_local_fwd_listener(const char *, u_short,
263 const char *, u_short, int); 264 const char *, u_short, int);
264void channel_request_rforward_cancel(const char *host, u_short port); 265int channel_request_rforward_cancel(const char *host, u_short port);
265int channel_setup_remote_fwd_listener(const char *, u_short, int *, int); 266int channel_setup_remote_fwd_listener(const char *, u_short, int *, int);
266int channel_cancel_rport_listener(const char *, u_short); 267int channel_cancel_rport_listener(const char *, u_short);
268int channel_cancel_lport_listener(const char *, u_short, u_short, int);
267 269
268/* x11 forwarding */ 270/* x11 forwarding */
269 271
diff --git a/clientloop.h b/clientloop.h
index a259b5e14..3bb794879 100644
--- a/clientloop.h
+++ b/clientloop.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: clientloop.h,v 1.28 2011/06/22 22:08:42 djm Exp $ */ 1/* $OpenBSD: clientloop.h,v 1.29 2011/09/09 22:46:44 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -70,6 +70,7 @@ void client_expect_confirm(int, const char *, enum confirm_action);
70#define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */ 70#define SSHMUX_COMMAND_STDIO_FWD 4 /* Open stdio fwd (ssh -W) */
71#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */ 71#define SSHMUX_COMMAND_FORWARD 5 /* Forward only, no command */
72#define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */ 72#define SSHMUX_COMMAND_STOP 6 /* Disable mux but not conn */
73#define SSHMUX_COMMAND_CANCEL_FWD 7 /* Cancel forwarding(s) */
73 74
74void muxserver_listen(void); 75void muxserver_listen(void);
75void muxclient(const char *); 76void muxclient(const char *);
diff --git a/mux.c b/mux.c
index add0e26b1..6b63d813b 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: mux.c,v 1.29 2011/06/22 22:08:42 djm Exp $ */ 1/* $OpenBSD: mux.c,v 1.30 2011/09/09 22:46:44 djm Exp $ */
2/* 2/*
3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org> 3 * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
4 * 4 *
@@ -777,10 +777,11 @@ process_mux_open_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
777static int 777static int
778process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) 778process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
779{ 779{
780 Forward fwd; 780 Forward fwd, *found_fwd;
781 char *fwd_desc = NULL; 781 char *fwd_desc = NULL;
782 const char *error_reason = NULL;
782 u_int ftype; 783 u_int ftype;
783 int ret = 0; 784 int i, ret = 0;
784 785
785 fwd.listen_host = fwd.connect_host = NULL; 786 fwd.listen_host = fwd.connect_host = NULL;
786 if (buffer_get_int_ret(&ftype, m) != 0 || 787 if (buffer_get_int_ret(&ftype, m) != 0 ||
@@ -802,14 +803,66 @@ process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r)
802 fwd.connect_host = NULL; 803 fwd.connect_host = NULL;
803 } 804 }
804 805
805 debug2("%s: channel %d: request %s", __func__, c->self, 806 debug2("%s: channel %d: request cancel %s", __func__, c->self,
806 (fwd_desc = format_forward(ftype, &fwd))); 807 (fwd_desc = format_forward(ftype, &fwd)));
807 808
808 /* XXX implement this */ 809 /* make sure this has been requested */
809 buffer_put_int(r, MUX_S_FAILURE); 810 found_fwd = NULL;
810 buffer_put_int(r, rid); 811 switch (ftype) {
811 buffer_put_cstring(r, "unimplemented"); 812 case MUX_FWD_LOCAL:
813 case MUX_FWD_DYNAMIC:
814 for (i = 0; i < options.num_local_forwards; i++) {
815 if (compare_forward(&fwd,
816 options.local_forwards + i)) {
817 found_fwd = options.local_forwards + i;
818 break;
819 }
820 }
821 break;
822 case MUX_FWD_REMOTE:
823 for (i = 0; i < options.num_remote_forwards; i++) {
824 if (compare_forward(&fwd,
825 options.remote_forwards + i)) {
826 found_fwd = options.remote_forwards + i;
827 break;
828 }
829 }
830 break;
831 }
812 832
833 if (found_fwd == NULL)
834 error_reason = "port not forwarded";
835 else if (ftype == MUX_FWD_REMOTE) {
836 /*
837 * This shouldn't fail unless we confused the host/port
838 * between options.remote_forwards and permitted_opens.
839 */
840 if (channel_request_rforward_cancel(fwd.listen_host,
841 fwd.listen_port) == -1)
842 error_reason = "port not in permitted opens";
843 } else { /* local and dynamic forwards */
844 /* Ditto */
845 if (channel_cancel_lport_listener(fwd.listen_host,
846 fwd.listen_port, fwd.connect_port,
847 options.gateway_ports) == -1)
848 error_reason = "port not found";
849 }
850
851 if (error_reason == NULL) {
852 buffer_put_int(r, MUX_S_OK);
853 buffer_put_int(r, rid);
854
855 if (found_fwd->listen_host != NULL)
856 xfree(found_fwd->listen_host);
857 if (found_fwd->connect_host != NULL)
858 xfree(found_fwd->connect_host);
859 found_fwd->listen_host = found_fwd->connect_host = NULL;
860 found_fwd->listen_port = found_fwd->connect_port = 0;
861 } else {
862 buffer_put_int(r, MUX_S_FAILURE);
863 buffer_put_int(r, rid);
864 buffer_put_cstring(r, error_reason);
865 }
813 out: 866 out:
814 if (fwd_desc != NULL) 867 if (fwd_desc != NULL)
815 xfree(fwd_desc); 868 xfree(fwd_desc);
@@ -1537,18 +1590,19 @@ mux_client_request_terminate(int fd)
1537} 1590}
1538 1591
1539static int 1592static int
1540mux_client_request_forward(int fd, u_int ftype, Forward *fwd) 1593mux_client_forward(int fd, int cancel_flag, u_int ftype, Forward *fwd)
1541{ 1594{
1542 Buffer m; 1595 Buffer m;
1543 char *e, *fwd_desc; 1596 char *e, *fwd_desc;
1544 u_int type, rid; 1597 u_int type, rid;
1545 1598
1546 fwd_desc = format_forward(ftype, fwd); 1599 fwd_desc = format_forward(ftype, fwd);
1547 debug("Requesting %s", fwd_desc); 1600 debug("Requesting %s %s",
1601 cancel_flag ? "cancellation of" : "forwarding of", fwd_desc);
1548 xfree(fwd_desc); 1602 xfree(fwd_desc);
1549 1603
1550 buffer_init(&m); 1604 buffer_init(&m);
1551 buffer_put_int(&m, MUX_C_OPEN_FWD); 1605 buffer_put_int(&m, cancel_flag ? MUX_C_CLOSE_FWD : MUX_C_OPEN_FWD);
1552 buffer_put_int(&m, muxclient_request_id); 1606 buffer_put_int(&m, muxclient_request_id);
1553 buffer_put_int(&m, ftype); 1607 buffer_put_int(&m, ftype);
1554 buffer_put_cstring(&m, 1608 buffer_put_cstring(&m,
@@ -1577,6 +1631,8 @@ mux_client_request_forward(int fd, u_int ftype, Forward *fwd)
1577 case MUX_S_OK: 1631 case MUX_S_OK:
1578 break; 1632 break;
1579 case MUX_S_REMOTE_PORT: 1633 case MUX_S_REMOTE_PORT:
1634 if (cancel_flag)
1635 fatal("%s: got MUX_S_REMOTE_PORT for cancel", __func__);
1580 fwd->allocated_port = buffer_get_int(&m); 1636 fwd->allocated_port = buffer_get_int(&m);
1581 logit("Allocated port %u for remote forward to %s:%d", 1637 logit("Allocated port %u for remote forward to %s:%d",
1582 fwd->allocated_port, 1638 fwd->allocated_port,
@@ -1606,27 +1662,28 @@ mux_client_request_forward(int fd, u_int ftype, Forward *fwd)
1606} 1662}
1607 1663
1608static int 1664static int
1609mux_client_request_forwards(int fd) 1665mux_client_forwards(int fd, int cancel_flag)
1610{ 1666{
1611 int i; 1667 int i, ret = 0;
1612 1668
1613 debug3("%s: requesting forwardings: %d local, %d remote", __func__, 1669 debug3("%s: %s forwardings: %d local, %d remote", __func__,
1670 cancel_flag ? "cancel" : "request",
1614 options.num_local_forwards, options.num_remote_forwards); 1671 options.num_local_forwards, options.num_remote_forwards);
1615 1672
1616 /* XXX ExitOnForwardingFailure */ 1673 /* XXX ExitOnForwardingFailure */
1617 for (i = 0; i < options.num_local_forwards; i++) { 1674 for (i = 0; i < options.num_local_forwards; i++) {
1618 if (mux_client_request_forward(fd, 1675 if (mux_client_forward(fd, cancel_flag,
1619 options.local_forwards[i].connect_port == 0 ? 1676 options.local_forwards[i].connect_port == 0 ?
1620 MUX_FWD_DYNAMIC : MUX_FWD_LOCAL, 1677 MUX_FWD_DYNAMIC : MUX_FWD_LOCAL,
1621 options.local_forwards + i) != 0) 1678 options.local_forwards + i) != 0)
1622 return -1; 1679 ret = -1;
1623 } 1680 }
1624 for (i = 0; i < options.num_remote_forwards; i++) { 1681 for (i = 0; i < options.num_remote_forwards; i++) {
1625 if (mux_client_request_forward(fd, MUX_FWD_REMOTE, 1682 if (mux_client_forward(fd, cancel_flag, MUX_FWD_REMOTE,
1626 options.remote_forwards + i) != 0) 1683 options.remote_forwards + i) != 0)
1627 return -1; 1684 ret = -1;
1628 } 1685 }
1629 return 0; 1686 return ret;
1630} 1687}
1631 1688
1632static int 1689static int
@@ -2014,11 +2071,11 @@ muxclient(const char *path)
2014 fprintf(stderr, "Exit request sent.\r\n"); 2071 fprintf(stderr, "Exit request sent.\r\n");
2015 exit(0); 2072 exit(0);
2016 case SSHMUX_COMMAND_FORWARD: 2073 case SSHMUX_COMMAND_FORWARD:
2017 if (mux_client_request_forwards(sock) != 0) 2074 if (mux_client_forwards(sock, 0) != 0)
2018 fatal("%s: master forward request failed", __func__); 2075 fatal("%s: master forward request failed", __func__);
2019 exit(0); 2076 exit(0);
2020 case SSHMUX_COMMAND_OPEN: 2077 case SSHMUX_COMMAND_OPEN:
2021 if (mux_client_request_forwards(sock) != 0) { 2078 if (mux_client_forwards(sock, 0) != 0) {
2022 error("%s: master forward request failed", __func__); 2079 error("%s: master forward request failed", __func__);
2023 return; 2080 return;
2024 } 2081 }
@@ -2031,6 +2088,11 @@ muxclient(const char *path)
2031 mux_client_request_stop_listening(sock); 2088 mux_client_request_stop_listening(sock);
2032 fprintf(stderr, "Stop listening request sent.\r\n"); 2089 fprintf(stderr, "Stop listening request sent.\r\n");
2033 exit(0); 2090 exit(0);
2091 case SSHMUX_COMMAND_CANCEL_FWD:
2092 if (mux_client_forwards(sock, 1) != 0)
2093 error("%s: master cancel forward request failed",
2094 __func__);
2095 exit(0);
2034 default: 2096 default:
2035 fatal("unrecognised muxclient_command %d", muxclient_command); 2097 fatal("unrecognised muxclient_command %d", muxclient_command);
2036 } 2098 }
diff --git a/ssh.c b/ssh.c
index c717dcf1d..f437dec1c 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssh.c,v 1.364 2011/08/02 23:15:03 djm Exp $ */ 1/* $OpenBSD: ssh.c,v 1.365 2011/09/09 22:46:44 djm Exp $ */
2/* 2/*
3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -377,6 +377,8 @@ main(int ac, char **av)
377 muxclient_command = SSHMUX_COMMAND_TERMINATE; 377 muxclient_command = SSHMUX_COMMAND_TERMINATE;
378 else if (strcmp(optarg, "stop") == 0) 378 else if (strcmp(optarg, "stop") == 0)
379 muxclient_command = SSHMUX_COMMAND_STOP; 379 muxclient_command = SSHMUX_COMMAND_STOP;
380 else if (strcmp(optarg, "cancel") == 0)
381 muxclient_command = SSHMUX_COMMAND_CANCEL_FWD;
380 else 382 else
381 fatal("Invalid multiplex command."); 383 fatal("Invalid multiplex command.");
382 break; 384 break;