=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/channels.c,v retrieving revision 1.332 retrieving revision 1.333 diff -u -r1.332 -r1.333 --- src/usr.bin/ssh/channels.c 2014/04/28 03:09:18 1.332 +++ src/usr.bin/ssh/channels.c 2014/06/27 16:41:56 1.333 @@ -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 @@ -106,7 +106,8 @@ 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. */ @@ -3001,12 +3002,53 @@ 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. */ @@ -3019,8 +3061,7 @@ 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) { @@ -3034,10 +3075,12 @@ 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; } @@ -3101,6 +3144,8 @@ 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; @@ -3132,6 +3177,8 @@ 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; } } @@ -3145,6 +3192,8 @@ 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; } @@ -3162,8 +3211,10 @@ { 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; @@ -3174,8 +3225,10 @@ { 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; @@ -3213,15 +3266,6 @@ 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) @@ -3316,13 +3360,14 @@ } 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); @@ -3342,20 +3387,19 @@ 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) {