diff options
Diffstat (limited to 'usr.bin/ssh/channel-tcpfwd.c')
-rw-r--r-- | usr.bin/ssh/channel-tcpfwd.c | 407 |
1 files changed, 0 insertions, 407 deletions
diff --git a/usr.bin/ssh/channel-tcpfwd.c b/usr.bin/ssh/channel-tcpfwd.c deleted file mode 100644 index 71d9b6e9461..00000000000 --- a/usr.bin/ssh/channel-tcpfwd.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - * Author: Tatu Ylonen <ylo@cs.hut.fi> - * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland - * All rights reserved - * - * As far as I am concerned, the code I have written for this software - * can be used freely for any purpose. Any derived versions of this - * software must be clearly marked as such, and if the derived work is - * incompatible with the protocol description in the RFC file, it must be - * called by a name other than "ssh" or "Secure Shell". - * - * - * Copyright (c) 2001 Markus Friedl. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "includes.h" -RCSID("$OpenBSD: channel-tcpfwd.c,v 1.2 2001/05/30 16:22:46 markus Exp $"); - -#include "ssh.h" -#include "ssh1.h" -#include "ssh2.h" -#include "packet.h" -#include "xmalloc.h" -#include "log.h" -#include "channel.h" -#include "compat.h" - -/* - * Data structure for storing which hosts are permitted for forward requests. - * The local sides of any remote forwards are stored in this array to prevent - * a corrupt remote server from accessing arbitrary TCP/IP ports on our local - * network (which might be behind a firewall). - */ -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. */ -} ForwardPermission; - -/* List of all permitted host/port pairs to connect. */ -static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION]; - -/* Number of permitted host/port pairs in the array. */ -static int num_permitted_opens = 0; -/* - * If this is true, all opens are permitted. This is the case on the server - * on which we have to trust the client anyway, and the user could do - * anything after logging in anyway. - */ -static int all_opens_permitted = 0; - -/* AF_UNSPEC or AF_INET or AF_INET6 */ -extern int IPv4or6; - -/* - * Initiate forwarding of connections to local port "port" through the secure - * channel to host:port from remote side. - */ -int -channel_request_local_forwarding(u_short listen_port, const char *host_to_connect, - u_short port_to_connect, int gateway_ports) -{ - return channel_request_forwarding( - NULL, listen_port, - host_to_connect, port_to_connect, - gateway_ports, /*remote_fwd*/ 0); -} - -/* - * If 'remote_fwd' is true we have a '-R style' listener for protocol 2 - * (SSH_CHANNEL_RPORT_LISTENER). - */ -int -channel_request_forwarding( - const char *listen_address, u_short listen_port, - const char *host_to_connect, u_short port_to_connect, - int gateway_ports, int remote_fwd) -{ - Channel *c; - int success, sock, on = 1, type; - struct addrinfo hints, *ai, *aitop; - char ntop[NI_MAXHOST], strport[NI_MAXSERV]; - const char *host; - struct linger linger; - - success = 0; - - if (remote_fwd) { - host = listen_address; - type = SSH_CHANNEL_RPORT_LISTENER; - } else { - host = host_to_connect; - type = SSH_CHANNEL_PORT_LISTENER; - } - - if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) { - error("Forward host name too long."); - return success; - } - - /* XXX listen_address is currently ignored */ - /* - * getaddrinfo returns a loopback address if the hostname is - * set to NULL and hints.ai_flags is not AI_PASSIVE - */ - memset(&hints, 0, sizeof(hints)); - hints.ai_family = IPv4or6; - hints.ai_flags = gateway_ports ? AI_PASSIVE : 0; - hints.ai_socktype = SOCK_STREAM; - snprintf(strport, sizeof strport, "%d", listen_port); - if (getaddrinfo(NULL, strport, &hints, &aitop) != 0) - packet_disconnect("getaddrinfo: fatal error"); - - for (ai = aitop; ai; ai = ai->ai_next) { - if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) - continue; - if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), - strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { - error("channel_request_forwarding: getnameinfo failed"); - continue; - } - /* Create a port to listen for the host. */ - sock = socket(ai->ai_family, SOCK_STREAM, 0); - if (sock < 0) { - /* this is no error since kernel may not support ipv6 */ - verbose("socket: %.100s", strerror(errno)); - continue; - } - /* - * Set socket options. We would like the socket to disappear - * as soon as it has been closed for whatever reason. - */ - setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); - linger.l_onoff = 1; - linger.l_linger = 5; - setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger)); - debug("Local forwarding listening on %s port %s.", ntop, strport); - - /* Bind the socket to the address. */ - if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { - /* address can be in use ipv6 address is already bound */ - verbose("bind: %.100s", strerror(errno)); - close(sock); - continue; - } - /* Start listening for connections on the socket. */ - if (listen(sock, 5) < 0) { - error("listen: %.100s", strerror(errno)); - close(sock); - continue; - } - /* Allocate a channel number for the socket. */ - c = channel_new("port listener", type, sock, sock, -1, - CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, - 0, xstrdup("port listener"), 1); - if (c == NULL) { - error("channel_request_forwarding: channel_new failed"); - close(sock); - continue; - } - strlcpy(c->path, host, sizeof(c->path)); - c->host_port = port_to_connect; - c->listening_port = listen_port; - success = 1; - } - if (success == 0) - error("channel_request_forwarding: cannot listen to port: %d", - listen_port); - freeaddrinfo(aitop); - return success; -} - -/* - * Initiate forwarding of connections to port "port" on remote host through - * the secure channel to host:port from local side. - */ - -void -channel_request_remote_forwarding(u_short listen_port, - const char *host_to_connect, u_short port_to_connect) -{ - int payload_len, type, success = 0; - - /* Record locally that connection to this host/port is permitted. */ - if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) - fatal("channel_request_remote_forwarding: too many forwards"); - - /* Send the forward request to the remote side. */ - if (compat20) { - const char *address_to_bind = "0.0.0.0"; - packet_start(SSH2_MSG_GLOBAL_REQUEST); - packet_put_cstring("tcpip-forward"); - packet_put_char(0); /* boolean: want reply */ - packet_put_cstring(address_to_bind); - packet_put_int(listen_port); - packet_send(); - packet_write_wait(); - /* Assume that server accepts the request */ - success = 1; - } else { - packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); - packet_put_int(listen_port); - packet_put_cstring(host_to_connect); - packet_put_int(port_to_connect); - packet_send(); - packet_write_wait(); - - /* Wait for response from the remote side. */ - type = packet_read(&payload_len); - switch (type) { - case SSH_SMSG_SUCCESS: - success = 1; - break; - case SSH_SMSG_FAILURE: - log("Warning: Server denied remote port forwarding."); - break; - default: - /* Unknown packet */ - packet_disconnect("Protocol error for port forward request:" - "received packet type %d.", type); - } - } - if (success) { - permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); - permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; - permitted_opens[num_permitted_opens].listen_port = listen_port; - num_permitted_opens++; - } -} - -/* - * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates - * listening for the port, and sends back a success reply (or disconnect - * message if there was an error). This never returns if there was an error. - */ - -void -channel_input_port_forward_request(int is_root, int gateway_ports) -{ - u_short port, host_port; - char *hostname; - - /* Get arguments from the packet. */ - port = packet_get_int(); - hostname = packet_get_string(NULL); - host_port = packet_get_int(); - - /* - * Check that an unprivileged user is not trying to forward a - * privileged port. - */ - if (port < IPPORT_RESERVED && !is_root) - packet_disconnect("Requested forwarding of port %d but user is not root.", - port); - /* Initiate forwarding */ - channel_request_local_forwarding(port, hostname, host_port, gateway_ports); - - /* Free the argument string. */ - xfree(hostname); -} - -/* - * Permits opening to any host/port if permitted_opens[] is empty. This is - * usually called by the server, because the user could connect to any port - * anyway, and the server has no way to know but to trust the client anyway. - */ -void -channel_permit_all_opens() -{ - if (num_permitted_opens == 0) - all_opens_permitted = 1; -} - -void -channel_add_permitted_opens(char *host, int port) -{ - if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) - fatal("channel_request_remote_forwarding: too many forwards"); - debug("allow port forwarding to host %s port %d", host, port); - - permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); - permitted_opens[num_permitted_opens].port_to_connect = port; - num_permitted_opens++; - - all_opens_permitted = 0; -} - -void -channel_clear_permitted_opens(void) -{ - int i; - - for (i = 0; i < num_permitted_opens; i++) - xfree(permitted_opens[i].host_to_connect); - num_permitted_opens = 0; - -} - - -/* return socket to remote host, port */ -int -connect_to(const char *host, u_short port) -{ - struct addrinfo hints, *ai, *aitop; - char ntop[NI_MAXHOST], strport[NI_MAXSERV]; - int gaierr; - int sock = -1; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = IPv4or6; - hints.ai_socktype = SOCK_STREAM; - snprintf(strport, sizeof strport, "%d", port); - if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { - error("connect_to %.100s: unknown host (%s)", host, - gai_strerror(gaierr)); - return -1; - } - for (ai = aitop; ai; ai = ai->ai_next) { - if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) - continue; - if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), - strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { - error("connect_to: getnameinfo failed"); - continue; - } - sock = socket(ai->ai_family, SOCK_STREAM, 0); - if (sock < 0) { - error("socket: %.100s", strerror(errno)); - continue; - } - if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) - fatal("connect_to: F_SETFL: %s", strerror(errno)); - if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && - errno != EINPROGRESS) { - error("connect_to %.100s port %s: %.100s", ntop, strport, - strerror(errno)); - close(sock); - continue; /* fail -- try next */ - } - break; /* success */ - - } - freeaddrinfo(aitop); - if (!ai) { - error("connect_to %.100s port %d: failed.", host, port); - return -1; - } - /* success */ - return sock; -} - -int -channel_connect_by_listen_adress(u_short listen_port) -{ - int i; - - for (i = 0; i < num_permitted_opens; i++) - if (permitted_opens[i].listen_port == listen_port) - return connect_to( - permitted_opens[i].host_to_connect, - permitted_opens[i].port_to_connect); - error("WARNING: Server requests forwarding for unknown listen_port %d", - listen_port); - return -1; -} - -/* Check if connecting to that port is permitted and connect. */ -int -channel_connect_to(const char *host, u_short port) -{ - int i, permit; - - permit = all_opens_permitted; - if (!permit) { - for (i = 0; i < num_permitted_opens; i++) - if (permitted_opens[i].port_to_connect == port && - strcmp(permitted_opens[i].host_to_connect, host) == 0) - permit = 1; - - } - if (!permit) { - log("Received request to connect to host %.100s port %d, " - "but the request was denied.", host, port); - return -1; - } - return connect_to(host, port); -} |