summaryrefslogtreecommitdiff
path: root/channels.c
diff options
context:
space:
mode:
Diffstat (limited to 'channels.c')
-rw-r--r--channels.c252
1 files changed, 187 insertions, 65 deletions
diff --git a/channels.c b/channels.c
index 24d4a9f42..f6e9b4d8c 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.315 2011/09/23 07:45:05 markus 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
@@ -125,6 +125,9 @@ static int num_permitted_opens = 0;
125/* Number of permitted host/port pair in the array permitted by the admin. */ 125/* Number of permitted host/port pair in the array permitted by the admin. */
126static int num_adm_permitted_opens = 0; 126static int num_adm_permitted_opens = 0;
127 127
128/* special-case port number meaning allow any port */
129#define FWD_PERMIT_ANY_PORT 0
130
128/* 131/*
129 * If this is true, all opens are permitted. This is the case on the server 132 * If this is true, all opens are permitted. This is the case on the server
130 * on which we have to trust the client anyway, and the user could do 133 * on which we have to trust the client anyway, and the user could do
@@ -302,6 +305,8 @@ channel_new(char *ctype, int type, int rfd, int wfd, int efd,
302 buffer_init(&c->output); 305 buffer_init(&c->output);
303 buffer_init(&c->extended); 306 buffer_init(&c->extended);
304 c->path = NULL; 307 c->path = NULL;
308 c->listening_addr = NULL;
309 c->listening_port = 0;
305 c->ostate = CHAN_OUTPUT_OPEN; 310 c->ostate = CHAN_OUTPUT_OPEN;
306 c->istate = CHAN_INPUT_OPEN; 311 c->istate = CHAN_INPUT_OPEN;
307 c->flags = 0; 312 c->flags = 0;
@@ -411,6 +416,10 @@ channel_free(Channel *c)
411 xfree(c->path); 416 xfree(c->path);
412 c->path = NULL; 417 c->path = NULL;
413 } 418 }
419 if (c->listening_addr) {
420 xfree(c->listening_addr);
421 c->listening_addr = NULL;
422 }
414 while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) { 423 while ((cc = TAILQ_FIRST(&c->status_confirms)) != NULL) {
415 if (cc->abandon_cb != NULL) 424 if (cc->abandon_cb != NULL)
416 cc->abandon_cb(c, cc->ctx); 425 cc->abandon_cb(c, cc->ctx);
@@ -2634,6 +2643,46 @@ channel_set_af(int af)
2634 IPv4or6 = af; 2643 IPv4or6 = af;
2635} 2644}
2636 2645
2646
2647/*
2648 * Determine whether or not a port forward listens to loopback, the
2649 * specified address or wildcard. On the client, a specified bind
2650 * address will always override gateway_ports. On the server, a
2651 * gateway_ports of 1 (``yes'') will override the client's specification
2652 * and force a wildcard bind, whereas a value of 2 (``clientspecified'')
2653 * will bind to whatever address the client asked for.
2654 *
2655 * Special-case listen_addrs are:
2656 *
2657 * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR
2658 * "" (empty string), "*" -> wildcard v4/v6
2659 * "localhost" -> loopback v4/v6
2660 */
2661static const char *
2662channel_fwd_bind_addr(const char *listen_addr, int *wildcardp,
2663 int is_client, int gateway_ports)
2664{
2665 const char *addr = NULL;
2666 int wildcard = 0;
2667
2668 if (listen_addr == NULL) {
2669 /* No address specified: default to gateway_ports setting */
2670 if (gateway_ports)
2671 wildcard = 1;
2672 } else if (gateway_ports || is_client) {
2673 if (((datafellows & SSH_OLD_FORWARD_ADDR) &&
2674 strcmp(listen_addr, "0.0.0.0") == 0 && is_client == 0) ||
2675 *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 ||
2676 (!is_client && gateway_ports == 1))
2677 wildcard = 1;
2678 else if (strcmp(listen_addr, "localhost") != 0)
2679 addr = listen_addr;
2680 }
2681 if (wildcardp != NULL)
2682 *wildcardp = wildcard;
2683 return addr;
2684}
2685
2637static int 2686static int
2638channel_setup_fwd_listener(int type, const char *listen_addr, 2687channel_setup_fwd_listener(int type, const char *listen_addr,
2639 u_short listen_port, int *allocated_listen_port, 2688 u_short listen_port, int *allocated_listen_port,
@@ -2659,36 +2708,9 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2659 return 0; 2708 return 0;
2660 } 2709 }
2661 2710
2662 /* 2711 /* Determine the bind address, cf. channel_fwd_bind_addr() comment */
2663 * Determine whether or not a port forward listens to loopback, 2712 addr = channel_fwd_bind_addr(listen_addr, &wildcard,
2664 * specified address or wildcard. On the client, a specified bind 2713 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", 2714 debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s",
2693 type, wildcard, (addr == NULL) ? "NULL" : addr); 2715 type, wildcard, (addr == NULL) ? "NULL" : addr);
2694 2716
@@ -2792,7 +2814,12 @@ channel_setup_fwd_listener(int type, const char *listen_addr,
2792 0, "port listener", 1); 2814 0, "port listener", 1);
2793 c->path = xstrdup(host); 2815 c->path = xstrdup(host);
2794 c->host_port = port_to_connect; 2816 c->host_port = port_to_connect;
2795 c->listening_port = listen_port; 2817 c->listening_addr = addr == NULL ? NULL : xstrdup(addr);
2818 if (listen_port == 0 && allocated_listen_port != NULL &&
2819 !(datafellows & SSH_BUG_DYNAMIC_RPORT))
2820 c->listening_port = *allocated_listen_port;
2821 else
2822 c->listening_port = listen_port;
2796 success = 1; 2823 success = 1;
2797 } 2824 }
2798 if (success == 0) 2825 if (success == 0)
@@ -2810,9 +2837,44 @@ channel_cancel_rport_listener(const char *host, u_short port)
2810 2837
2811 for (i = 0; i < channels_alloc; i++) { 2838 for (i = 0; i < channels_alloc; i++) {
2812 Channel *c = channels[i]; 2839 Channel *c = channels[i];
2840 if (c == NULL || c->type != SSH_CHANNEL_RPORT_LISTENER)
2841 continue;
2842 if (strcmp(c->path, host) == 0 && c->listening_port == port) {
2843 debug2("%s: close channel %d", __func__, i);
2844 channel_free(c);
2845 found = 1;
2846 }
2847 }
2848
2849 return (found);
2850}
2851
2852int
2853channel_cancel_lport_listener(const char *lhost, u_short lport,
2854 int cport, int gateway_ports)
2855{
2856 u_int i;
2857 int found = 0;
2858 const char *addr = channel_fwd_bind_addr(lhost, NULL, 1, gateway_ports);
2813 2859
2814 if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && 2860 for (i = 0; i < channels_alloc; i++) {
2815 strcmp(c->path, host) == 0 && c->listening_port == port) { 2861 Channel *c = channels[i];
2862 if (c == NULL || c->type != SSH_CHANNEL_PORT_LISTENER)
2863 continue;
2864 if (c->listening_port != lport)
2865 continue;
2866 if (cport == CHANNEL_CANCEL_PORT_STATIC) {
2867 /* skip dynamic forwardings */
2868 if (c->host_port == 0)
2869 continue;
2870 } else {
2871 if (c->host_port != cport)
2872 continue;
2873 }
2874 if ((c->listening_addr == NULL && addr != NULL) ||
2875 (c->listening_addr != NULL && addr == NULL))
2876 continue;
2877 if (addr == NULL || strcmp(c->listening_addr, addr) == 0) {
2816 debug2("%s: close channel %d", __func__, i); 2878 debug2("%s: close channel %d", __func__, i);
2817 channel_free(c); 2879 channel_free(c);
2818 found = 1; 2880 found = 1;
@@ -2843,37 +2905,44 @@ channel_setup_remote_fwd_listener(const char *listen_address,
2843} 2905}
2844 2906
2845/* 2907/*
2908 * Translate the requested rfwd listen host to something usable for
2909 * this server.
2910 */
2911static const char *
2912channel_rfwd_bind_host(const char *listen_host)
2913{
2914 if (listen_host == NULL) {
2915 if (datafellows & SSH_BUG_RFWD_ADDR)
2916 return "127.0.0.1";
2917 else
2918 return "localhost";
2919 } else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0) {
2920 if (datafellows & SSH_BUG_RFWD_ADDR)
2921 return "0.0.0.0";
2922 else
2923 return "";
2924 } else
2925 return listen_host;
2926}
2927
2928/*
2846 * Initiate forwarding of connections to port "port" on remote host through 2929 * Initiate forwarding of connections to port "port" on remote host through
2847 * the secure channel to host:port from local side. 2930 * the secure channel to host:port from local side.
2931 * Returns handle (index) for updating the dynamic listen port with
2932 * channel_update_permitted_opens().
2848 */ 2933 */
2849
2850int 2934int
2851channel_request_remote_forwarding(const char *listen_host, u_short listen_port, 2935channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
2852 const char *host_to_connect, u_short port_to_connect) 2936 const char *host_to_connect, u_short port_to_connect)
2853{ 2937{
2854 int type, success = 0; 2938 int type, success = 0, idx = -1;
2855 2939
2856 /* Send the forward request to the remote side. */ 2940 /* Send the forward request to the remote side. */
2857 if (compat20) { 2941 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); 2942 packet_start(SSH2_MSG_GLOBAL_REQUEST);
2874 packet_put_cstring("tcpip-forward"); 2943 packet_put_cstring("tcpip-forward");
2875 packet_put_char(1); /* boolean: want reply */ 2944 packet_put_char(1); /* boolean: want reply */
2876 packet_put_cstring(address_to_bind); 2945 packet_put_cstring(channel_rfwd_bind_host(listen_host));
2877 packet_put_int(listen_port); 2946 packet_put_int(listen_port);
2878 packet_send(); 2947 packet_send();
2879 packet_write_wait(); 2948 packet_write_wait();
@@ -2905,25 +2974,25 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
2905 /* Record that connection to this host/port is permitted. */ 2974 /* Record that connection to this host/port is permitted. */
2906 permitted_opens = xrealloc(permitted_opens, 2975 permitted_opens = xrealloc(permitted_opens,
2907 num_permitted_opens + 1, sizeof(*permitted_opens)); 2976 num_permitted_opens + 1, sizeof(*permitted_opens));
2908 permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); 2977 idx = num_permitted_opens++;
2909 permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; 2978 permitted_opens[idx].host_to_connect = xstrdup(host_to_connect);
2910 permitted_opens[num_permitted_opens].listen_port = listen_port; 2979 permitted_opens[idx].port_to_connect = port_to_connect;
2911 num_permitted_opens++; 2980 permitted_opens[idx].listen_port = listen_port;
2912 } 2981 }
2913 return (success ? 0 : -1); 2982 return (idx);
2914} 2983}
2915 2984
2916/* 2985/*
2917 * Request cancellation of remote forwarding of connection host:port from 2986 * Request cancellation of remote forwarding of connection host:port from
2918 * local side. 2987 * local side.
2919 */ 2988 */
2920void 2989int
2921channel_request_rforward_cancel(const char *host, u_short port) 2990channel_request_rforward_cancel(const char *host, u_short port)
2922{ 2991{
2923 int i; 2992 int i;
2924 2993
2925 if (!compat20) 2994 if (!compat20)
2926 return; 2995 return -1;
2927 2996
2928 for (i = 0; i < num_permitted_opens; i++) { 2997 for (i = 0; i < num_permitted_opens; i++) {
2929 if (permitted_opens[i].host_to_connect != NULL && 2998 if (permitted_opens[i].host_to_connect != NULL &&
@@ -2932,12 +3001,12 @@ channel_request_rforward_cancel(const char *host, u_short port)
2932 } 3001 }
2933 if (i >= num_permitted_opens) { 3002 if (i >= num_permitted_opens) {
2934 debug("%s: requested forward not found", __func__); 3003 debug("%s: requested forward not found", __func__);
2935 return; 3004 return -1;
2936 } 3005 }
2937 packet_start(SSH2_MSG_GLOBAL_REQUEST); 3006 packet_start(SSH2_MSG_GLOBAL_REQUEST);
2938 packet_put_cstring("cancel-tcpip-forward"); 3007 packet_put_cstring("cancel-tcpip-forward");
2939 packet_put_char(0); 3008 packet_put_char(0);
2940 packet_put_cstring(host == NULL ? "" : host); 3009 packet_put_cstring(channel_rfwd_bind_host(host));
2941 packet_put_int(port); 3010 packet_put_int(port);
2942 packet_send(); 3011 packet_send();
2943 3012
@@ -2945,6 +3014,8 @@ channel_request_rforward_cancel(const char *host, u_short port)
2945 permitted_opens[i].port_to_connect = 0; 3014 permitted_opens[i].port_to_connect = 0;
2946 xfree(permitted_opens[i].host_to_connect); 3015 xfree(permitted_opens[i].host_to_connect);
2947 permitted_opens[i].host_to_connect = NULL; 3016 permitted_opens[i].host_to_connect = NULL;
3017
3018 return 0;
2948} 3019}
2949 3020
2950/* 3021/*
@@ -3013,6 +3084,35 @@ channel_add_permitted_opens(char *host, int port)
3013 all_opens_permitted = 0; 3084 all_opens_permitted = 0;
3014} 3085}
3015 3086
3087/*
3088 * Update the listen port for a dynamic remote forward, after
3089 * the actual 'newport' has been allocated. If 'newport' < 0 is
3090 * passed then they entry will be invalidated.
3091 */
3092void
3093channel_update_permitted_opens(int idx, int newport)
3094{
3095 if (idx < 0 || idx >= num_permitted_opens) {
3096 debug("channel_update_permitted_opens: index out of range:"
3097 " %d num_permitted_opens %d", idx, num_permitted_opens);
3098 return;
3099 }
3100 debug("%s allowed port %d for forwarding to host %s port %d",
3101 newport > 0 ? "Updating" : "Removing",
3102 newport,
3103 permitted_opens[idx].host_to_connect,
3104 permitted_opens[idx].port_to_connect);
3105 if (newport >= 0) {
3106 permitted_opens[idx].listen_port =
3107 (datafellows & SSH_BUG_DYNAMIC_RPORT) ? 0 : newport;
3108 } else {
3109 permitted_opens[idx].listen_port = 0;
3110 permitted_opens[idx].port_to_connect = 0;
3111 xfree(permitted_opens[idx].host_to_connect);
3112 permitted_opens[idx].host_to_connect = NULL;
3113 }
3114}
3115
3016int 3116int
3017channel_add_adm_permitted_opens(char *host, int port) 3117channel_add_adm_permitted_opens(char *host, int port)
3018{ 3118{
@@ -3073,6 +3173,28 @@ channel_print_adm_permitted_opens(void)
3073 printf("\n"); 3173 printf("\n");
3074} 3174}
3075 3175
3176/* returns port number, FWD_PERMIT_ANY_PORT or -1 on error */
3177int
3178permitopen_port(const char *p)
3179{
3180 int port;
3181
3182 if (strcmp(p, "*") == 0)
3183 return FWD_PERMIT_ANY_PORT;
3184 if ((port = a2port(p)) > 0)
3185 return port;
3186 return -1;
3187}
3188
3189static int
3190port_match(u_short allowedport, u_short requestedport)
3191{
3192 if (allowedport == FWD_PERMIT_ANY_PORT ||
3193 allowedport == requestedport)
3194 return 1;
3195 return 0;
3196}
3197
3076/* Try to start non-blocking connect to next host in cctx list */ 3198/* Try to start non-blocking connect to next host in cctx list */
3077static int 3199static int
3078connect_next(struct channel_connect *cctx) 3200connect_next(struct channel_connect *cctx)
@@ -3175,7 +3297,7 @@ channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname)
3175 3297
3176 for (i = 0; i < num_permitted_opens; i++) { 3298 for (i = 0; i < num_permitted_opens; i++) {
3177 if (permitted_opens[i].host_to_connect != NULL && 3299 if (permitted_opens[i].host_to_connect != NULL &&
3178 permitted_opens[i].listen_port == listen_port) { 3300 port_match(permitted_opens[i].listen_port, listen_port)) {
3179 return connect_to( 3301 return connect_to(
3180 permitted_opens[i].host_to_connect, 3302 permitted_opens[i].host_to_connect,
3181 permitted_opens[i].port_to_connect, ctype, rname); 3303 permitted_opens[i].port_to_connect, ctype, rname);
@@ -3196,7 +3318,7 @@ channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
3196 if (!permit) { 3318 if (!permit) {
3197 for (i = 0; i < num_permitted_opens; i++) 3319 for (i = 0; i < num_permitted_opens; i++)
3198 if (permitted_opens[i].host_to_connect != NULL && 3320 if (permitted_opens[i].host_to_connect != NULL &&
3199 permitted_opens[i].port_to_connect == port && 3321 port_match(permitted_opens[i].port_to_connect, port) &&
3200 strcmp(permitted_opens[i].host_to_connect, host) == 0) 3322 strcmp(permitted_opens[i].host_to_connect, host) == 0)
3201 permit = 1; 3323 permit = 1;
3202 } 3324 }
@@ -3205,7 +3327,7 @@ channel_connect_to(const char *host, u_short port, char *ctype, char *rname)
3205 permit_adm = 0; 3327 permit_adm = 0;
3206 for (i = 0; i < num_adm_permitted_opens; i++) 3328 for (i = 0; i < num_adm_permitted_opens; i++)
3207 if (permitted_adm_opens[i].host_to_connect != NULL && 3329 if (permitted_adm_opens[i].host_to_connect != NULL &&
3208 permitted_adm_opens[i].port_to_connect == port && 3330 port_match(permitted_adm_opens[i].port_to_connect, port) &&
3209 strcmp(permitted_adm_opens[i].host_to_connect, host) 3331 strcmp(permitted_adm_opens[i].host_to_connect, host)
3210 == 0) 3332 == 0)
3211 permit_adm = 1; 3333 permit_adm = 1;