diff options
author | Damien Miller <djm@mindrot.org> | 2011-09-22 21:38:52 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2011-09-22 21:38:52 +1000 |
commit | f6dff7cd2ff5eba5cd63e3a9c7bf6ccf183cb056 (patch) | |
tree | ca2f37e390f5f26598341a09435dabed25648d46 | |
parent | 9ee2c606c1d03ecb955aa8a2624b9db4aa9752a2 (diff) |
- djm@cvs.openbsd.org 2011/09/09 22:46:44
[channels.c channels.h clientloop.h mux.c ssh.c]
support for cancelling local and remote port forwards via the multiplex
socket. Use ssh -O cancel -L xx:xx:xx -R yy:yy:yy user@host" to request
the cancellation of the specified forwardings; ok markus@
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | channels.c | 164 | ||||
-rw-r--r-- | channels.h | 6 | ||||
-rw-r--r-- | clientloop.h | 3 | ||||
-rw-r--r-- | mux.c | 104 | ||||
-rw-r--r-- | ssh.c | 4 |
6 files changed, 206 insertions, 80 deletions
@@ -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 | ||
55 | 20110909 | 60 | 20110909 |
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 | */ | ||
2658 | static const char * | ||
2659 | channel_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 | |||
2637 | static int | 2683 | static int |
2638 | channel_setup_fwd_listener(int type, const char *listen_addr, | 2684 | channel_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 | |||
2845 | int | ||
2846 | channel_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 | */ | ||
2896 | static const char * | ||
2897 | channel_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 | |||
2850 | int | 2917 | int |
2851 | channel_request_remote_forwarding(const char *listen_host, u_short listen_port, | 2918 | channel_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 | */ |
2920 | void | 2972 | int |
2921 | channel_request_rforward_cancel(const char *host, u_short port) | 2973 | channel_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); |
262 | int channel_setup_local_fwd_listener(const char *, u_short, | 263 | int channel_setup_local_fwd_listener(const char *, u_short, |
263 | const char *, u_short, int); | 264 | const char *, u_short, int); |
264 | void channel_request_rforward_cancel(const char *host, u_short port); | 265 | int channel_request_rforward_cancel(const char *host, u_short port); |
265 | int channel_setup_remote_fwd_listener(const char *, u_short, int *, int); | 266 | int channel_setup_remote_fwd_listener(const char *, u_short, int *, int); |
266 | int channel_cancel_rport_listener(const char *, u_short); | 267 | int channel_cancel_rport_listener(const char *, u_short); |
268 | int 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 | ||
74 | void muxserver_listen(void); | 75 | void muxserver_listen(void); |
75 | void muxclient(const char *); | 76 | void muxclient(const char *); |
@@ -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) | |||
777 | static int | 777 | static int |
778 | process_mux_close_fwd(u_int rid, Channel *c, Buffer *m, Buffer *r) | 778 | process_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 | ||
1539 | static int | 1592 | static int |
1540 | mux_client_request_forward(int fd, u_int ftype, Forward *fwd) | 1593 | mux_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 | ||
1608 | static int | 1664 | static int |
1609 | mux_client_request_forwards(int fd) | 1665 | mux_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 | ||
1632 | static int | 1689 | static 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 | } |
@@ -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; |