diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 164 |
1 files changed, 109 insertions, 55 deletions
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 | /* |