Annotation of src/usr.bin/ssh/channel-tcpfwd.c, Revision 1.2
1.1 markus 1: /*
2: * Author: Tatu Ylonen <ylo@cs.hut.fi>
3: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4: * All rights reserved
5: *
6: * As far as I am concerned, the code I have written for this software
7: * can be used freely for any purpose. Any derived versions of this
8: * software must be clearly marked as such, and if the derived work is
9: * incompatible with the protocol description in the RFC file, it must be
10: * called by a name other than "ssh" or "Secure Shell".
11: *
12: *
13: * Copyright (c) 2001 Markus Friedl. All rights reserved.
14: *
15: * Redistribution and use in source and binary forms, with or without
16: * modification, are permitted provided that the following conditions
17: * are met:
18: * 1. Redistributions of source code must retain the above copyright
19: * notice, this list of conditions and the following disclaimer.
20: * 2. Redistributions in binary form must reproduce the above copyright
21: * notice, this list of conditions and the following disclaimer in the
22: * documentation and/or other materials provided with the distribution.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include "includes.h"
1.2 ! markus 37: RCSID("$OpenBSD: channel-tcpfwd.c,v 1.1 2001/05/30 12:55:08 markus Exp $");
1.1 markus 38:
39: #include "ssh.h"
40: #include "ssh1.h"
41: #include "ssh2.h"
42: #include "packet.h"
43: #include "xmalloc.h"
44: #include "log.h"
45: #include "channel.h"
46: #include "compat.h"
47:
48: /*
49: * Data structure for storing which hosts are permitted for forward requests.
50: * The local sides of any remote forwards are stored in this array to prevent
51: * a corrupt remote server from accessing arbitrary TCP/IP ports on our local
52: * network (which might be behind a firewall).
53: */
54: typedef struct {
55: char *host_to_connect; /* Connect to 'host'. */
56: u_short port_to_connect; /* Connect to 'port'. */
57: u_short listen_port; /* Remote side should listen port number. */
58: } ForwardPermission;
59:
60: /* List of all permitted host/port pairs to connect. */
61: static ForwardPermission permitted_opens[SSH_MAX_FORWARDS_PER_DIRECTION];
62:
63: /* Number of permitted host/port pairs in the array. */
64: static int num_permitted_opens = 0;
65: /*
66: * If this is true, all opens are permitted. This is the case on the server
67: * on which we have to trust the client anyway, and the user could do
68: * anything after logging in anyway.
69: */
70: static int all_opens_permitted = 0;
71:
72: /* AF_UNSPEC or AF_INET or AF_INET6 */
73: extern int IPv4or6;
74:
75: /*
76: * Initiate forwarding of connections to local port "port" through the secure
77: * channel to host:port from remote side.
78: */
79: int
80: channel_request_local_forwarding(u_short listen_port, const char *host_to_connect,
81: u_short port_to_connect, int gateway_ports)
82: {
83: return channel_request_forwarding(
84: NULL, listen_port,
85: host_to_connect, port_to_connect,
86: gateway_ports, /*remote_fwd*/ 0);
87: }
88:
89: /*
90: * If 'remote_fwd' is true we have a '-R style' listener for protocol 2
91: * (SSH_CHANNEL_RPORT_LISTENER).
92: */
93: int
94: channel_request_forwarding(
95: const char *listen_address, u_short listen_port,
96: const char *host_to_connect, u_short port_to_connect,
97: int gateway_ports, int remote_fwd)
98: {
99: Channel *c;
1.2 ! markus 100: int success, sock, on = 1, type;
1.1 markus 101: struct addrinfo hints, *ai, *aitop;
102: char ntop[NI_MAXHOST], strport[NI_MAXSERV];
103: const char *host;
104: struct linger linger;
105:
106: success = 0;
107:
108: if (remote_fwd) {
109: host = listen_address;
1.2 ! markus 110: type = SSH_CHANNEL_RPORT_LISTENER;
1.1 markus 111: } else {
112: host = host_to_connect;
1.2 ! markus 113: type = SSH_CHANNEL_PORT_LISTENER;
1.1 markus 114: }
115:
116: if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) {
117: error("Forward host name too long.");
118: return success;
119: }
120:
121: /* XXX listen_address is currently ignored */
122: /*
123: * getaddrinfo returns a loopback address if the hostname is
124: * set to NULL and hints.ai_flags is not AI_PASSIVE
125: */
126: memset(&hints, 0, sizeof(hints));
127: hints.ai_family = IPv4or6;
128: hints.ai_flags = gateway_ports ? AI_PASSIVE : 0;
129: hints.ai_socktype = SOCK_STREAM;
130: snprintf(strport, sizeof strport, "%d", listen_port);
131: if (getaddrinfo(NULL, strport, &hints, &aitop) != 0)
132: packet_disconnect("getaddrinfo: fatal error");
133:
134: for (ai = aitop; ai; ai = ai->ai_next) {
135: if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
136: continue;
137: if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
138: strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
139: error("channel_request_forwarding: getnameinfo failed");
140: continue;
141: }
142: /* Create a port to listen for the host. */
143: sock = socket(ai->ai_family, SOCK_STREAM, 0);
144: if (sock < 0) {
145: /* this is no error since kernel may not support ipv6 */
146: verbose("socket: %.100s", strerror(errno));
147: continue;
148: }
149: /*
150: * Set socket options. We would like the socket to disappear
151: * as soon as it has been closed for whatever reason.
152: */
153: setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
154: linger.l_onoff = 1;
155: linger.l_linger = 5;
156: setsockopt(sock, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
157: debug("Local forwarding listening on %s port %s.", ntop, strport);
158:
159: /* Bind the socket to the address. */
160: if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
161: /* address can be in use ipv6 address is already bound */
162: verbose("bind: %.100s", strerror(errno));
163: close(sock);
164: continue;
165: }
166: /* Start listening for connections on the socket. */
167: if (listen(sock, 5) < 0) {
168: error("listen: %.100s", strerror(errno));
169: close(sock);
170: continue;
171: }
172: /* Allocate a channel number for the socket. */
1.2 ! markus 173: c = channel_new("port listener", type, sock, sock, -1,
1.1 markus 174: CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
175: 0, xstrdup("port listener"), 1);
176: if (c == NULL) {
177: error("channel_request_forwarding: channel_new failed");
178: close(sock);
179: continue;
180: }
181: strlcpy(c->path, host, sizeof(c->path));
182: c->host_port = port_to_connect;
183: c->listening_port = listen_port;
184: success = 1;
185: }
186: if (success == 0)
187: error("channel_request_forwarding: cannot listen to port: %d",
188: listen_port);
189: freeaddrinfo(aitop);
190: return success;
191: }
192:
193: /*
194: * Initiate forwarding of connections to port "port" on remote host through
195: * the secure channel to host:port from local side.
196: */
197:
198: void
199: channel_request_remote_forwarding(u_short listen_port,
200: const char *host_to_connect, u_short port_to_connect)
201: {
202: int payload_len, type, success = 0;
203:
204: /* Record locally that connection to this host/port is permitted. */
205: if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
206: fatal("channel_request_remote_forwarding: too many forwards");
207:
208: /* Send the forward request to the remote side. */
209: if (compat20) {
210: const char *address_to_bind = "0.0.0.0";
211: packet_start(SSH2_MSG_GLOBAL_REQUEST);
212: packet_put_cstring("tcpip-forward");
213: packet_put_char(0); /* boolean: want reply */
214: packet_put_cstring(address_to_bind);
215: packet_put_int(listen_port);
216: packet_send();
217: packet_write_wait();
218: /* Assume that server accepts the request */
219: success = 1;
220: } else {
221: packet_start(SSH_CMSG_PORT_FORWARD_REQUEST);
222: packet_put_int(listen_port);
223: packet_put_cstring(host_to_connect);
224: packet_put_int(port_to_connect);
225: packet_send();
226: packet_write_wait();
227:
228: /* Wait for response from the remote side. */
229: type = packet_read(&payload_len);
230: switch (type) {
231: case SSH_SMSG_SUCCESS:
232: success = 1;
233: break;
234: case SSH_SMSG_FAILURE:
235: log("Warning: Server denied remote port forwarding.");
236: break;
237: default:
238: /* Unknown packet */
239: packet_disconnect("Protocol error for port forward request:"
240: "received packet type %d.", type);
241: }
242: }
243: if (success) {
244: permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect);
245: permitted_opens[num_permitted_opens].port_to_connect = port_to_connect;
246: permitted_opens[num_permitted_opens].listen_port = listen_port;
247: num_permitted_opens++;
248: }
249: }
250:
251: /*
252: * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates
253: * listening for the port, and sends back a success reply (or disconnect
254: * message if there was an error). This never returns if there was an error.
255: */
256:
257: void
258: channel_input_port_forward_request(int is_root, int gateway_ports)
259: {
260: u_short port, host_port;
261: char *hostname;
262:
263: /* Get arguments from the packet. */
264: port = packet_get_int();
265: hostname = packet_get_string(NULL);
266: host_port = packet_get_int();
267:
268: /*
269: * Check that an unprivileged user is not trying to forward a
270: * privileged port.
271: */
272: if (port < IPPORT_RESERVED && !is_root)
273: packet_disconnect("Requested forwarding of port %d but user is not root.",
274: port);
275: /* Initiate forwarding */
276: channel_request_local_forwarding(port, hostname, host_port, gateway_ports);
277:
278: /* Free the argument string. */
279: xfree(hostname);
280: }
281:
282: /*
283: * Permits opening to any host/port if permitted_opens[] is empty. This is
284: * usually called by the server, because the user could connect to any port
285: * anyway, and the server has no way to know but to trust the client anyway.
286: */
287: void
288: channel_permit_all_opens()
289: {
290: if (num_permitted_opens == 0)
291: all_opens_permitted = 1;
292: }
293:
294: void
295: channel_add_permitted_opens(char *host, int port)
296: {
297: if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION)
298: fatal("channel_request_remote_forwarding: too many forwards");
299: debug("allow port forwarding to host %s port %d", host, port);
300:
301: permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
302: permitted_opens[num_permitted_opens].port_to_connect = port;
303: num_permitted_opens++;
304:
305: all_opens_permitted = 0;
306: }
307:
308: void
309: channel_clear_permitted_opens(void)
310: {
311: int i;
312:
313: for (i = 0; i < num_permitted_opens; i++)
314: xfree(permitted_opens[i].host_to_connect);
315: num_permitted_opens = 0;
316:
317: }
318:
319:
320: /* return socket to remote host, port */
321: int
322: connect_to(const char *host, u_short port)
323: {
324: struct addrinfo hints, *ai, *aitop;
325: char ntop[NI_MAXHOST], strport[NI_MAXSERV];
326: int gaierr;
327: int sock = -1;
328:
329: memset(&hints, 0, sizeof(hints));
330: hints.ai_family = IPv4or6;
331: hints.ai_socktype = SOCK_STREAM;
332: snprintf(strport, sizeof strport, "%d", port);
333: if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) {
334: error("connect_to %.100s: unknown host (%s)", host,
335: gai_strerror(gaierr));
336: return -1;
337: }
338: for (ai = aitop; ai; ai = ai->ai_next) {
339: if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
340: continue;
341: if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop),
342: strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
343: error("connect_to: getnameinfo failed");
344: continue;
345: }
346: sock = socket(ai->ai_family, SOCK_STREAM, 0);
347: if (sock < 0) {
348: error("socket: %.100s", strerror(errno));
349: continue;
350: }
351: if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0)
352: fatal("connect_to: F_SETFL: %s", strerror(errno));
353: if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 &&
354: errno != EINPROGRESS) {
355: error("connect_to %.100s port %s: %.100s", ntop, strport,
356: strerror(errno));
357: close(sock);
358: continue; /* fail -- try next */
359: }
360: break; /* success */
361:
362: }
363: freeaddrinfo(aitop);
364: if (!ai) {
365: error("connect_to %.100s port %d: failed.", host, port);
366: return -1;
367: }
368: /* success */
369: return sock;
370: }
371:
372: int
373: channel_connect_by_listen_adress(u_short listen_port)
374: {
375: int i;
376:
377: for (i = 0; i < num_permitted_opens; i++)
378: if (permitted_opens[i].listen_port == listen_port)
379: return connect_to(
380: permitted_opens[i].host_to_connect,
381: permitted_opens[i].port_to_connect);
382: error("WARNING: Server requests forwarding for unknown listen_port %d",
383: listen_port);
384: return -1;
385: }
386:
387: /* Check if connecting to that port is permitted and connect. */
388: int
389: channel_connect_to(const char *host, u_short port)
390: {
391: int i, permit;
392:
393: permit = all_opens_permitted;
394: if (!permit) {
395: for (i = 0; i < num_permitted_opens; i++)
396: if (permitted_opens[i].port_to_connect == port &&
397: strcmp(permitted_opens[i].host_to_connect, host) == 0)
398: permit = 1;
399:
400: }
401: if (!permit) {
402: log("Received request to connect to host %.100s port %d, "
403: "but the request was denied.", host, port);
404: return -1;
405: }
406: return connect_to(host, port);
407: }