diff --git a/ChangeLog b/ChangeLog index 12b8f00f1..8bc9e0c1b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -58,6 +58,10 @@ [sshbuf.c] unblock SIGSEGV before raising it ok djm + - markus@cvs.openbsd.org 2014/06/27 16:41:56 + [channels.c channels.h clientloop.c ssh.c] + fix remote fwding with same listen port but different listen address + with gerhard@, ok djm@ 20140618 - (tim) [openssh/session.c] Work around to get chroot sftp working on UnixWare diff --git a/channels.c b/channels.c index 1020071ff..7d0439e68 100644 --- a/channels.c +++ b/channels.c @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.c,v 1.332 2014/04/28 03:09:18 djm Exp $ */ +/* $OpenBSD: channels.c,v 1.333 2014/06/27 16:41:56 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -110,7 +110,8 @@ static int channel_max_fd = 0; typedef struct { char *host_to_connect; /* Connect to 'host'. */ u_short port_to_connect; /* Connect to 'port'. */ - u_short listen_port; /* Remote side should listen port number. */ + char *listen_host; /* Remote side should listen address. */ + u_short listen_port; /* Remote side should listen port. */ } ForwardPermission; /* List of all permitted host/port pairs to connect by the user. */ @@ -3032,11 +3033,52 @@ channel_request_remote_forwarding(const char *listen_host, u_short listen_port, idx = num_permitted_opens++; permitted_opens[idx].host_to_connect = xstrdup(host_to_connect); permitted_opens[idx].port_to_connect = port_to_connect; + permitted_opens[idx].listen_host = listen_host ? + xstrdup(listen_host) : NULL; permitted_opens[idx].listen_port = listen_port; } return (idx); } +static int +open_match(ForwardPermission *allowed_open, const char *requestedhost, + u_short requestedport) +{ + if (allowed_open->host_to_connect == NULL) + return 0; + if (allowed_open->port_to_connect != FWD_PERMIT_ANY_PORT && + allowed_open->port_to_connect != requestedport) + return 0; + if (strcmp(allowed_open->host_to_connect, requestedhost) != 0) + return 0; + return 1; +} + +/* + * Note that in he listen host/port case + * we don't support FWD_PERMIT_ANY_PORT and + * need to translate between the configured-host (listen_host) + * and what we've sent to the remote server (channel_rfwd_bind_host) + */ +static int +open_listen_match(ForwardPermission *allowed_open, const char *requestedhost, + u_short requestedport, int translate) +{ + const char *allowed_host; + + if (allowed_open->host_to_connect == NULL) + return 0; + if (allowed_open->listen_port != requestedport) + return 0; + allowed_host = translate ? + channel_rfwd_bind_host(allowed_open->listen_host) : + allowed_open->listen_host; + if (allowed_host == NULL || + strcmp(allowed_host, requestedhost) != 0) + return 0; + return 1; +} + /* * Request cancellation of remote forwarding of connection host:port from * local side. @@ -3050,8 +3092,7 @@ channel_request_rforward_cancel(const char *host, u_short port) return -1; for (i = 0; i < num_permitted_opens; i++) { - if (permitted_opens[i].host_to_connect != NULL && - permitted_opens[i].listen_port == port) + if (open_listen_match(&permitted_opens[i], host, port, 0)) break; } if (i >= num_permitted_opens) { @@ -3065,10 +3106,12 @@ channel_request_rforward_cancel(const char *host, u_short port) packet_put_int(port); packet_send(); - permitted_opens[i].listen_port = 0; permitted_opens[i].port_to_connect = 0; + permitted_opens[i].listen_port = 0; free(permitted_opens[i].host_to_connect); permitted_opens[i].host_to_connect = NULL; + free(permitted_opens[i].listen_host); + permitted_opens[i].listen_host = NULL; return 0; } @@ -3134,6 +3177,8 @@ channel_add_permitted_opens(char *host, int port) num_permitted_opens + 1, sizeof(*permitted_opens)); permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); permitted_opens[num_permitted_opens].port_to_connect = port; + permitted_opens[num_permitted_opens].listen_host = NULL; + permitted_opens[num_permitted_opens].listen_port = 0; num_permitted_opens++; all_opens_permitted = 0; @@ -3165,6 +3210,8 @@ channel_update_permitted_opens(int idx, int newport) permitted_opens[idx].port_to_connect = 0; free(permitted_opens[idx].host_to_connect); permitted_opens[idx].host_to_connect = NULL; + free(permitted_opens[idx].listen_host); + permitted_opens[idx].listen_host = NULL; } } @@ -3178,6 +3225,8 @@ channel_add_adm_permitted_opens(char *host, int port) permitted_adm_opens[num_adm_permitted_opens].host_to_connect = xstrdup(host); permitted_adm_opens[num_adm_permitted_opens].port_to_connect = port; + permitted_adm_opens[num_adm_permitted_opens].listen_host = NULL; + permitted_adm_opens[num_adm_permitted_opens].listen_port = 0; return ++num_adm_permitted_opens; } @@ -3195,8 +3244,10 @@ channel_clear_permitted_opens(void) { int i; - for (i = 0; i < num_permitted_opens; i++) + for (i = 0; i < num_permitted_opens; i++) { free(permitted_opens[i].host_to_connect); + free(permitted_opens[i].listen_host); + } free(permitted_opens); permitted_opens = NULL; num_permitted_opens = 0; @@ -3207,8 +3258,10 @@ channel_clear_adm_permitted_opens(void) { int i; - for (i = 0; i < num_adm_permitted_opens; i++) + for (i = 0; i < num_adm_permitted_opens; i++) { free(permitted_adm_opens[i].host_to_connect); + free(permitted_adm_opens[i].listen_host); + } free(permitted_adm_opens); permitted_adm_opens = NULL; num_adm_permitted_opens = 0; @@ -3246,15 +3299,6 @@ permitopen_port(const char *p) return -1; } -static int -port_match(u_short allowedport, u_short requestedport) -{ - if (allowedport == FWD_PERMIT_ANY_PORT || - allowedport == requestedport) - return 1; - return 0; -} - /* Try to start non-blocking connect to next host in cctx list */ static int connect_next(struct channel_connect *cctx) @@ -3349,13 +3393,14 @@ connect_to(const char *host, u_short port, char *ctype, char *rname) } Channel * -channel_connect_by_listen_address(u_short listen_port, char *ctype, char *rname) +channel_connect_by_listen_address(const char *listen_host, + u_short listen_port, char *ctype, char *rname) { int i; for (i = 0; i < num_permitted_opens; i++) { - if (permitted_opens[i].host_to_connect != NULL && - port_match(permitted_opens[i].listen_port, listen_port)) { + if (open_listen_match(&permitted_opens[i], listen_host, + listen_port, 1)) { return connect_to( permitted_opens[i].host_to_connect, permitted_opens[i].port_to_connect, ctype, rname); @@ -3375,20 +3420,19 @@ channel_connect_to(const char *host, u_short port, char *ctype, char *rname) permit = all_opens_permitted; if (!permit) { for (i = 0; i < num_permitted_opens; i++) - if (permitted_opens[i].host_to_connect != NULL && - port_match(permitted_opens[i].port_to_connect, port) && - strcmp(permitted_opens[i].host_to_connect, host) == 0) + if (open_match(&permitted_opens[i], host, port)) { permit = 1; + break; + } } if (num_adm_permitted_opens > 0) { permit_adm = 0; for (i = 0; i < num_adm_permitted_opens; i++) - if (permitted_adm_opens[i].host_to_connect != NULL && - port_match(permitted_adm_opens[i].port_to_connect, port) && - strcmp(permitted_adm_opens[i].host_to_connect, host) - == 0) + if (open_match(&permitted_adm_opens[i], host, port)) { permit_adm = 1; + break; + } } if (!permit || !permit_adm) { diff --git a/channels.h b/channels.h index 4fab9d7c4..4745b9a7d 100644 --- a/channels.h +++ b/channels.h @@ -1,4 +1,4 @@ -/* $OpenBSD: channels.h,v 1.113 2013/06/07 15:37:52 dtucker Exp $ */ +/* $OpenBSD: channels.h,v 1.114 2014/06/27 16:41:56 markus Exp $ */ /* * Author: Tatu Ylonen @@ -266,7 +266,8 @@ void channel_print_adm_permitted_opens(void); int channel_input_port_forward_request(int, int); Channel *channel_connect_to(const char *, u_short, char *, char *); Channel *channel_connect_stdio_fwd(const char*, u_short, int, int); -Channel *channel_connect_by_listen_address(u_short, char *, char *); +Channel *channel_connect_by_listen_address(const char *, u_short, + char *, char *); int channel_request_remote_forwarding(const char *, u_short, const char *, u_short); int channel_setup_local_fwd_listener(const char *, u_short, diff --git a/clientloop.c b/clientloop.c index 203151ea8..02510e26d 100644 --- a/clientloop.c +++ b/clientloop.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clientloop.c,v 1.259 2014/04/29 13:10:30 djm Exp $ */ +/* $OpenBSD: clientloop.c,v 1.260 2014/06/27 16:41:56 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1849,7 +1849,7 @@ client_request_forwarded_tcpip(const char *request_type, int rchan) "originator %s port %d", listen_address, listen_port, originator_address, originator_port); - c = channel_connect_by_listen_address(listen_port, + c = channel_connect_by_listen_address(listen_address, listen_port, "forwarded-tcpip", originator_address); free(originator_address); diff --git a/ssh.c b/ssh.c index 35fc7ddf9..6625557bd 100644 --- a/ssh.c +++ b/ssh.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ssh.c,v 1.403 2014/06/24 02:19:48 djm Exp $ */ +/* $OpenBSD: ssh.c,v 1.404 2014/06/27 16:41:56 markus Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland @@ -1279,8 +1279,10 @@ ssh_confirm_remote_forward(int type, u_int32_t seq, void *ctxt) Forward *rfwd = (Forward *)ctxt; /* XXX verbose() on failure? */ - debug("remote forward %s for: listen %d, connect %s:%d", + debug("remote forward %s for: listen %s%s%d, connect %s:%d", type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure", + rfwd->listen_host == NULL ? "" : rfwd->listen_host, + rfwd->listen_host == NULL ? "" : ":", rfwd->listen_port, rfwd->connect_host, rfwd->connect_port); if (rfwd->listen_port == 0) { if (type == SSH2_MSG_REQUEST_SUCCESS) {