Protocol 2 remote forwarding patch

Jarno Huuskonen jhuuskon at messi.uku.fi
Wed Aug 23 17:48:37 EST 2000


Hi !

Here's a patch to add remote port forwarding support (protocol 2) for
openssh. I have tried to test that it works like it should but a more
thorough testing is needed. This patch adds both client/server support.
The patch should be applied to openssh-2.1.1p4 source tree.

Also included is a PortForwarding sshd_config option, new ./configure
option --disable-forwarding that should make it possible to disable
port forwarding in server altogether and some earlier patch to make
ssh client fork with -f (when using protocol 2).

Please test the patch and give me feedback.

-Jarno

-- 
Jarno Huuskonen - System Administrator   |  Jarno.Huuskonen at uku.fi
University of Kuopio - Computer Center   |  Work:   +358 17 162822
PO BOX 1627, 70211 Kuopio, Finland       |  Mobile: +358 40 5388169
-------------- next part --------------
diff -u -r openssh-2.1.1p4/auth2.c openssh-2.1.1p4-jhchanges/auth2.c
--- openssh-2.1.1p4/auth2.c	Tue Jul 11 10:31:38 2000
+++ openssh-2.1.1p4-jhchanges/auth2.c	Tue Aug 22 19:43:09 2000
@@ -65,6 +65,7 @@
 extern ServerOptions options;
 extern unsigned char *session_id2;
 extern int session_id2_len;
+extern int user_authenticated_as_root; /* Jarno: From channels.c */
 
 /* protocol */
 
@@ -239,6 +240,14 @@
 		packet_put_char(0);				/* XXX partial success, unused */
 		packet_send();
 		packet_write_wait();
+	}
+	
+	/* Jarno: Set the user_authenticated_as_root flag */
+	if ( authenticated && pw && pw->pw_uid == (uid_t)0 ) {
+		user_authenticated_as_root = 1;
+	}
+	else {
+		user_authenticated_as_root = 0;
 	}
 
 	xfree(service);
diff -u -r openssh-2.1.1p4/channels.c openssh-2.1.1p4-jhchanges/channels.c
--- openssh-2.1.1p4/channels.c	Mon Jun 26 03:22:53 2000
+++ openssh-2.1.1p4-jhchanges/channels.c	Wed Aug 23 09:27:47 2000
@@ -59,6 +59,12 @@
  */
 static int channels_alloc = 0;
 
+/* Jarno: Needed to check if port_forwarding is allowed */
+int allow_port_forwarding;
+int user_authenticated_as_root; /* This could be uid so we could log who
+																 * tried to forward ports.
+																 */
+
 /*
  * Maximum file descriptor value used in any of the channels.  This is
  * updated in channel_allocate.
@@ -581,13 +587,20 @@
 		    "connect from %.200s port %d",
 		    c->listening_port, c->path, c->host_port,
 		    remote_hostname, remote_port);
-		newch = channel_new("direct-tcpip",
+		/* Jarno: If the channel is SSH2 port listener (server) then send
+		 * forwarded-tcpip message.
+		 */
+		newch = channel_new( (c->type == SSH2_CHANNEL_PORT_LISTENER) ?
+												 "forwarded-tcpip" : "direct-tcpip",
 		    SSH_CHANNEL_OPENING, newsock, newsock, -1,
 		    c->local_window_max, c->local_maxpacket,
 		    0, xstrdup(buf));
 		if (compat20) {
 			packet_start(SSH2_MSG_CHANNEL_OPEN);
-			packet_put_cstring("direct-tcpip");
+			if (c->type == SSH2_CHANNEL_PORT_LISTENER)
+				packet_put_cstring("forwarded-tcpip");
+			else
+				packet_put_cstring("direct-tcpip");
 			packet_put_int(newch);
 			packet_put_int(c->local_window_max);
 			packet_put_int(c->local_maxpacket);
@@ -786,10 +799,12 @@
 	channel_pre[SSH_CHANNEL_OPEN] =			&channel_pre_open_20;
 	channel_pre[SSH_CHANNEL_X11_OPEN] =		&channel_pre_x11_open;
 	channel_pre[SSH_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
+	channel_pre[SSH2_CHANNEL_PORT_LISTENER] =	&channel_pre_listener;
 	channel_pre[SSH_CHANNEL_X11_LISTENER] =		&channel_pre_listener;
 
 	channel_post[SSH_CHANNEL_OPEN] =		&channel_post_open_2;
 	channel_post[SSH_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
+	channel_post[SSH2_CHANNEL_PORT_LISTENER] =	&channel_post_port_listener;
 	channel_post[SSH_CHANNEL_X11_LISTENER] =	&channel_post_x11_listener;
 }
 
@@ -1275,6 +1290,122 @@
 	c->remote_window += adjust;
 }
 
+/* Jarno Huuskonen: Checks if the server allows port forwarding.
+ * Logs all failed attempts.
+ * Return 1 if the forwarding is allowed or 0 for failure.
+ */
+int allow_remote_forwarding(const char *address_to_listen, int port)
+{
+#ifdef DISABLE_FORWARDING
+	return 0;
+#endif /* DISABLE_FORWARDING */
+
+	/* Only root can forward privileged ports */
+	if ( port < IPPORT_RESERVED && !user_authenticated_as_root ) {
+		debug("Non-root user tries to forward privileged port %d", port);
+		/* Commercial ssh2 doesn't disconnect so same behaviour here */
+		packet_send_debug("Requested forwarding of port %d but user is not root.",
+											port);
+		return 0;
+	}
+
+	/* Is forwarding disabled in configuration */
+	if ( allow_port_forwarding ) {
+		return 1;
+	}
+	/* TODO: Better logging of refused forwards:
+	 * log("Refused port forward request from %.100s port %d."); 
+	 */
+	return 0;
+}
+
+/* Jarno Huuskonen: This is called when server receives 
+ * SSH2_MSG_GLOBAL_REQUEST. Handles both "tcpip-forward" and
+ * "cancel-tcpip-forward" requests.
+ */
+void 
+channel_server_global_request(int type, int plen)
+{
+	char *rtype;
+	char want_reply;
+	int success = 0;
+
+	rtype = packet_get_string(NULL);
+	want_reply = packet_get_char();
+	debug("server received: %.100s request (reply=%d)",rtype, 
+				(int)want_reply);
+	
+	if ( strcmp(rtype, "tcpip-forward") == 0 ) {
+		char *address_to_bind;
+		int port_to_bind;
+		address_to_bind = packet_get_string(NULL);
+		port_to_bind = packet_get_int();
+
+		/* Check if the client is allowed to forward (this port) */
+		if ( allow_remote_forwarding(address_to_bind, port_to_bind) ) {
+			/* Start listening on the port */
+			channel_request_local_forwarding( port_to_bind, address_to_bind,
+																				port_to_bind, 1, 1 );
+			/* NOT REACHED if error (disconnects). 
+			 * Note: if error xfree not called
+			 * for address_to_bind
+			 */
+			success = 1;
+		}
+		else {
+			success = 0;
+			packet_send_debug("Server has disabled port forwarding.");
+		}
+
+		xfree( address_to_bind );
+	}
+
+	/* TODO: This is untested !!! create some test code !!!*/
+	if ( strcmp(rtype, "cancel-tcpip-forward") == 0 ) {
+		char *address_to_bind;
+		int port_to_bind;
+		int chan;
+
+		address_to_bind = packet_get_string(NULL);
+		port_to_bind = packet_get_int();
+
+		/* Lookup the channel listening for this port:
+			 First see if the channel type is SSH2_CHANNEL_PORT_LISTENER and then 
+			 compare port/addr.
+			 TODO: Is it safe to use strcmp ?
+		 */
+		for (chan = 0; chan < channels_alloc; chan++) {
+			if ( channels[chan].type == SSH2_CHANNEL_PORT_LISTENER ) {
+				if ( channels[chan].listening_port == port_to_bind &&
+						 (strcmp(address_to_bind, channels[chan].path) == 0) )
+					break;
+			}
+		}
+		
+		if ( chan < channels_alloc ) {
+			/* We have a winner --> close the channel*/
+			channel_free( channels[chan].self );
+			success = 1;
+		}
+		xfree( address_to_bind );
+	}
+
+	/* Client requested a reply */
+	if ( want_reply ) {
+		if ( success ) {
+			packet_start(SSH2_MSG_REQUEST_SUCCESS);
+		}
+		else {
+			packet_start(SSH2_MSG_REQUEST_FAILURE);
+		}
+		/* Now send the SUCCESS/FAILURE */
+		packet_send();
+		packet_write_wait();
+	}
+	xfree(rtype);
+}
+
+
 /*
  * Stops listening for channels, and removes any unix domain sockets that we
  * might have.
@@ -1292,6 +1423,7 @@
 			channel_free(i);
 			break;
 		case SSH_CHANNEL_PORT_LISTENER:
+		case SSH2_CHANNEL_PORT_LISTENER: /* Jarno */
 		case SSH_CHANNEL_X11_LISTENER:
 			close(channels[i].sock);
 			channel_free(i);
@@ -1335,6 +1467,7 @@
 		case SSH_CHANNEL_FREE:
 		case SSH_CHANNEL_X11_LISTENER:
 		case SSH_CHANNEL_PORT_LISTENER:
+		case SSH2_CHANNEL_PORT_LISTENER: /* Jarno */
 		case SSH_CHANNEL_CLOSED:
 		case SSH_CHANNEL_AUTH_SOCKET:
 			continue;
@@ -1380,6 +1513,7 @@
 		case SSH_CHANNEL_FREE:
 		case SSH_CHANNEL_X11_LISTENER:
 		case SSH_CHANNEL_PORT_LISTENER:
+		case SSH2_CHANNEL_PORT_LISTENER: /* Jarno */
 		case SSH_CHANNEL_CLOSED:
 		case SSH_CHANNEL_AUTH_SOCKET:
 			continue;
@@ -1412,10 +1546,14 @@
  * Initiate forwarding of connections to local port "port" through the secure
  * channel to host:port from remote side.
  */
-
+/* Jarno: If ssh2_remote_fwd is true then protocol 2 server called this
+ * and we need to use channel type SSH2_CHANNEL_PORT_LISTENER (when someone
+ * connects to the listening socket we know to send "forwarded-tcpip" message
+ * instead of "direct-tcpip").
+ */
 void
 channel_request_local_forwarding(u_short port, const char *host,
-				 u_short host_port, int gateway_ports)
+				 u_short host_port, int gateway_ports, int ssh2_remote_fwd)
 {
 	int success, ch, sock, on = 1;
 	struct addrinfo hints, *ai, *aitop;
@@ -1482,7 +1620,8 @@
 		}
 		/* Allocate a channel number for the socket. */
 		ch = channel_new(
-		    "port listener", SSH_CHANNEL_PORT_LISTENER,
+		    "port listener", 
+				ssh2_remote_fwd ? SSH2_CHANNEL_PORT_LISTENER : SSH_CHANNEL_PORT_LISTENER,
 		    sock, sock, -1,
 		    CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT,
 		    0, xstrdup("port listener"));
@@ -1506,38 +1645,149 @@
 				  u_short port_to_connect)
 {
 	int payload_len;
+	int type;
+	int 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");
 
-	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++;
-
 	/* 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 */
+
+		/* Don't ask for a reply because: while waiting for a reply server can
+			 send rekey-msg and handling that correctly might be messy.
+			 Not requesting a reply is not the best solution: We have no way of  
+			 know if the server doesn't allow port forwarding.
+		*/
+		packet_put_char(0); /* Boolean 1 asks for reply */
 		packet_put_cstring(address_to_bind);
 		packet_put_int(listen_port);
-	} else {
+		packet_send();
+		packet_write_wait();
+		success = 1;   /* Assume that server accepts the request and put the
+											forward request to permitted_opens */
+ 
+		/*
+		type = packet_read(&payload_len);
+		switch (type) {
+		case SSH2_MSG_REQUEST_SUCCESS:
+			success = 1;
+			break;
+		case SSH2_MSG_REQUEST_FAILURE:
+			log("Warning: Server doesn't do port forwarding.");
+			break;
+		default:
+				packet_disconnect("Protocol error for port forward request: received packet type %d.", type);
+		}
+		*/
+	} 
+	else {
+		/* Protocol 1 */
 		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.  It will send a disconnect
-		 * message on failure, and we will never see it here.
+
+		/* Jarno: Server can send SSH_SMSG_FAILURE if it won't do port 
+		 *	 forwardings. Read the server reply.
 		 */
-		packet_read_expect(&payload_len, SSH_SMSG_SUCCESS);
+		type = packet_read(&payload_len); /* Expect reply from server */
+		switch (type) {
+		case SSH_SMSG_SUCCESS:
+			success = 1;
+			break;
+		case SSH_SMSG_FAILURE:
+			log("Warning: Server doesn't do 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++;
 	}
 }
 
+/* Jarno Huuskonen:
+ * This gets called after ssh client has received 
+ * SSH2_MSG_GLOBAL_REQUEST type "forwarded-tcpip".
+ *
+ * returns new channel if OK or NULL for failure.
+ */
+Channel*
+client_forwarded_tcpip_request(const char *request_type, int rchan,
+															 int rwindow, int rmaxpack)
+{
+	Channel* c = NULL;
+	int sock;
+	char *listen_address;       /* Remote (server) address that is listening 
+																 for the connection */
+	int listen_port;
+	char* originator_address;   /* Address of the client connecting to 
+																 listen_address */
+	int originator_port;        /* Client port */
+
+	unsigned int client_len, connected_len;
+
+	int newch;
+	int i;
+
+	debug("ssh2 server tries to open forwarded-tcpip channel.");
+
+	/* Get rest of the packet */
+	listen_address = packet_get_string(&connected_len);
+	listen_port = packet_get_int();
+	originator_address = packet_get_string(&client_len);
+	originator_port = packet_get_int();
+	packet_done();
+
+	/* Check if we have requested this remote forwarding 
+	 * Note: this is not fool proof, because we don't ask the server to
+	 * acknowledge our remote forward request.
+	 */
+	for (i = 0; i<num_permitted_opens; i++) {
+		if ( permitted_opens[i].listen_port == listen_port ) {
+			break;
+		}
+	}
+
+	/* We haven't requested the connection to be forwarded ! */
+	if ( i >= num_permitted_opens ) {
+		log("Received request to open remote forwarded channel (%d) but the request was denied", rchan);
+		return NULL;
+	}
+
+	/* TODO: Somekind of access control ??
+	 * Maybe tcp_wrappers/username/group based access control ??
+	 */
+
+	/* Open socket and allocate a channel for it */
+	sock = channel_connect_to(permitted_opens[i].host_to_connect, 
+														permitted_opens[i].port_to_connect);
+
+	if ( sock >= 0 ) {
+		newch = channel_new("forwarded-tcpip", SSH_CHANNEL_OPEN,
+												sock, sock, -1, 4*1024, 32*1024, 0, 
+												xstrdup(originator_address));
+		c = channel_lookup( newch );
+	}
+	/* client_input_channel_open calls xfree(request_type) Don't call it here */
+	xfree(originator_address);
+	xfree(listen_address);
+	return c;
+}
+
 /*
  * This is called after receiving CHANNEL_FORWARDING_REQUEST.  This initates
  * listening for the port, and sends back a success reply (or disconnect
@@ -1565,7 +1815,10 @@
 	/*
 	 * Initiate forwarding,
 	 */
-	channel_request_local_forwarding(port, hostname, host_port, gateway_ports);
+	/* Jarno: The last parameter is used to signal if this is protocol 2 
+		 server listening for remote forward --> false */
+	channel_request_local_forwarding(port, hostname, host_port, 
+																	 gateway_ports, 0);
 
 	/* Free the argument string. */
 	xfree(hostname);
@@ -1621,22 +1874,49 @@
 	return sock;
 }
 
+/* Jarno: This is only a wrapper for channel_input_port_open that 
+ * server calls after receiving PORT_OPEN. The only purpose for this is to
+ * make it possible to refuse forwarding requests (in server).
+ */
+void server_channel_input_port_open(int type, int plen)
+{
+	int remote_channel = packet_get_int();
+
+#ifndef DISABLE_FORWARDING
+	if (!allow_port_forwarding) {
+#endif
+		debug("Refused port forward request.");
+		packet_send_debug("Server configuration rejects port forwardings.");
+		packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);
+		packet_put_int(remote_channel);
+		packet_send();
+		return;
+#ifndef DISABLE_FORWARDING
+	}
+#endif
+	channel_input_port_open(type, plen, remote_channel);
+}
+
+/* Jarno: This is only a client wrapper for channel_input_port_open */
+void client_channel_input_port_open(int type, int plen)
+{
+	int remote_channel = packet_get_int();
+	channel_input_port_open(type, plen, remote_channel);
+}
+
+
 /*
  * This is called after receiving PORT_OPEN message.  This attempts to
  * connect to the given host:port, and sends back CHANNEL_OPEN_CONFIRMATION
  * or CHANNEL_OPEN_FAILURE.
  */
-
 void
-channel_input_port_open(int type, int plen)
+channel_input_port_open(int type, int plen, int remote_channel)
 {
 	u_short host_port;
 	char *host, *originator_string;
-	int remote_channel, sock = -1, newch, i, denied;
+	int sock = -1, newch, i, denied;
 	unsigned int host_len, originator_len;
-
-	/* Get remote channel number. */
-	remote_channel = packet_get_int();
 
 	/* Get host name to connect to. */
 	host = packet_get_string(&host_len);
diff -u -r openssh-2.1.1p4/channels.h openssh-2.1.1p4-jhchanges/channels.h
--- openssh-2.1.1p4/channels.h	Thu Jun 22 14:32:31 2000
+++ openssh-2.1.1p4-jhchanges/channels.h	Tue Aug 22 21:36:16 2000
@@ -15,7 +15,13 @@
 #define SSH_CHANNEL_INPUT_DRAINING	8	/* sending remaining data to conn */
 #define SSH_CHANNEL_OUTPUT_DRAINING	9	/* sending remaining data to app */
 #define SSH_CHANNEL_LARVAL		10	/* larval session */
-#define SSH_CHANNEL_MAX_TYPE		11
+#define SSH2_CHANNEL_PORT_LISTENER	11	/* Jarno: protocol 2 remote port 
+																				 * listener. (needs different type 
+																				 * because with protocol 2 remote
+																				 * forward the server sends
+																				 * forwarded-tcpip (not direct-tcpip)
+																				 */
+#define SSH_CHANNEL_MAX_TYPE		12
 
 /*
  * Data structure for channel data.  This is iniailized in channel_allocate
@@ -89,10 +95,27 @@
 void	channel_input_oclose(int type, int plen);
 void	channel_input_open_confirmation(int type, int plen);
 void	channel_input_open_failure(int type, int plen);
-void	channel_input_port_open(int type, int plen);
+/* Jarno: This is only a wrapper for channel_input_port_open that the
+ * server calls after receiving PORT_OPEN. The only purpose of this is to
+ * make it possible to refuse forwarding requests.
+ */
+void server_channel_input_port_open(int type, int plen);
+/* Jarno: This is only a client wrapper for channel_input_port_open */
+void client_channel_input_port_open(int type, int plen);
+void	channel_input_port_open(int type, int plen, int remote_channel);
 void	channel_input_window_adjust(int type, int plen);
+
+/* Jarno Huuskonen: Checks if the server allows port forwarding.
+ * Logs all failed attempts.
+ * Return 1 if the forwarding is allowed or 0 for failure.
+ */
+int allow_remote_forwarding(const char *address_to_listen, int port);
+
 void	channel_input_open(int type, int plen);
 
+/* Jarno Huuskonen: */
+void channel_server_global_request(int type, int plen);
+
 /* Sets specific protocol options. */
 void    channel_set_options(int hostname_in_open);
 
@@ -149,9 +172,12 @@
  * channel to host:port from remote side.  This never returns if there was an
  * error.
  */
+/* Jarno: Added ssh2_remote_fwd flag. Used when protocol2 server gets 
+ * tcpip-forward request
+ */
 void
 channel_request_local_forwarding(u_short port, const char *host,
-    u_short remote_port, int gateway_ports);
+    u_short remote_port, int gateway_ports, int ssh2_remote_fwd);
 
 /*
  * Initiate forwarding of connections to port "port" on remote host through
@@ -162,6 +188,12 @@
 void
 channel_request_remote_forwarding(u_short port, const char *host,
     u_short remote_port);
+
+/* Jarno Huuskonen: 
+ */
+Channel *
+client_forwarded_tcpip_request(const char *request_type, int rchan,
+															 int rwindow, int rmaxpack);
 
 /*
  * Permits opening to any host/port in SSH_MSG_PORT_OPEN.  This is usually
diff -u -r openssh-2.1.1p4/clientloop.c openssh-2.1.1p4-jhchanges/clientloop.c
--- openssh-2.1.1p4/clientloop.c	Sat Jul 15 07:14:17 2000
+++ openssh-2.1.1p4-jhchanges/clientloop.c	Tue Aug 22 21:37:57 2000
@@ -974,6 +974,12 @@
 	debug("client_input_channel_open: ctype %s rchan %d win %d max %d",
 	    ctype, rchan, rwindow, rmaxpack);
 
+	/* Jarno: Check if ssh2 server tries to open remote forward channel 
+	 */
+	if (strcmp(ctype, "forwarded-tcpip") == 0) {
+		c = client_forwarded_tcpip_request( ctype, rchan, rwindow, rmaxpack );
+	}
+
 	if (strcmp(ctype, "x11") == 0) {
 		int sock;
 		char *originator;
@@ -1015,7 +1021,8 @@
 		packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);
 		packet_put_int(rchan);
 		packet_put_int(SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED);
-		packet_put_cstring("bla bla");
+		packet_put_cstring("bla bla"); /* TODO: Perhaps a little better 
+																			explanation */
 		packet_put_cstring("");
 		packet_send();
 	}
@@ -1045,7 +1052,7 @@
 	dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
 	dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
 	dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
-	dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
+	dispatch_set(SSH_MSG_PORT_OPEN, &client_channel_input_port_open); /* Jarno */
 	dispatch_set(SSH_SMSG_AGENT_OPEN, &auth_input_open_request);
 	dispatch_set(SSH_SMSG_EXITSTATUS, &client_input_exit_status);
 	dispatch_set(SSH_SMSG_STDERR_DATA, &client_input_stderr_data);
diff -u -r openssh-2.1.1p4/configure.in openssh-2.1.1p4-jhchanges/configure.in
--- openssh-2.1.1p4/configure.in	Sat Jul 15 07:59:14 2000
+++ openssh-2.1.1p4-jhchanges/configure.in	Fri Aug 18 20:02:20 2000
@@ -1094,6 +1094,12 @@
 AC_DEFINE_UNQUOTED(PIDDIR, "$piddir")
 AC_SUBST(piddir)
 
+# Disable server port forwarding
+AC_ARG_ENABLE(forwarding,
+	[  --disable-forwarding    disable port forwarding in server [no]],
+	[ AC_DEFINE(DISABLE_FORWARDING) ]
+)
+
 dnl allow user to disable some login recording features
 AC_ARG_ENABLE(lastlog,
 	[  --disable-lastlog       disable use of lastlog even if detected [no]],
@@ -1370,7 +1376,6 @@
 echo "   IP address in \$DISPLAY hack: $DISPLAY_HACK_MSG"
 echo "      Use IPv4 by default hack: $IPV4_HACK_MSG"
 echo "       Translate v4 in v6 hack: $IPV4_IN6_HACK_MSG"
-
 echo ""
 
 echo "Compiler flags: ${CFLAGS}"
diff -u -r openssh-2.1.1p4/config.h.in openssh-2.1.1p4-jhchanges/config.h.in
--- openssh-2.1.1p4/config.h.in	Sun Jul 16 06:26:46 2000
+++ openssh-2.1.1p4-jhchanges/config.h.in	Fri Aug 18 19:58:58 2000
@@ -73,6 +73,9 @@
 #undef HAVE_TIME_IN_UTMP
 #undef HAVE_TIME_IN_UTMPX
 
+/* Define if you want to disable port forwarding in server */
+#undef DISABLE_FORWARDING
+
 /* Define if you don't want to use your system's login() call */
 #undef DISABLE_LOGIN
 
diff -u -r openssh-2.1.1p4/servconf.c openssh-2.1.1p4-jhchanges/servconf.c
--- openssh-2.1.1p4/servconf.c	Sat Jul 15 07:14:17 2000
+++ openssh-2.1.1p4-jhchanges/servconf.c	Mon Aug 21 20:48:09 2000
@@ -19,6 +19,9 @@
 #include "xmalloc.h"
 #include "compat.h"
 
+/* Jarno: import */
+extern int allow_port_forwarding;
+
 /* add listen address */
 void add_listen_addr(ServerOptions *options, char *addr);
 
@@ -45,6 +48,7 @@
 	options->x11_forwarding = -1;
 	options->x11_display_offset = -1;
 	options->xauth_location = NULL;
+	allow_port_forwarding = -1;
 	options->strict_modes = -1;
 	options->keepalives = -1;
 	options->log_facility = (SyslogFacility) - 1;
@@ -116,6 +120,8 @@
 	if (options->xauth_location == NULL)
 		options->xauth_location = XAUTH_PATH;
 #endif /* XAUTH_PATH */
+	if (allow_port_forwarding == -1)
+		allow_port_forwarding = 1;     /* Allow forwarding */
 	if (options->strict_modes == -1)
 		options->strict_modes = 1;
 	if (options->keepalives == -1)
@@ -180,9 +186,9 @@
 	sSkeyAuthentication,
 #endif
 	sPasswordAuthentication, sListenAddress,
-	sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset,
-	sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, sCheckMail,
-	sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
+	sPrintMotd, sIgnoreRhosts, sX11Forwarding, sX11DisplayOffset, 
+	sPortForwarding, sStrictModes, sEmptyPasswd, sRandomSeedFile, sKeepAlives, 
+	sCheckMail, sUseLogin, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
 	sIgnoreUserKnownHosts, sHostDSAKeyFile, sCiphers, sProtocol, sPidFile,
 	sGatewayPorts, sDSAAuthentication, sXAuthLocation, sSubsystem, sMaxStartups
 } ServerOpCodes;
@@ -227,6 +233,7 @@
 	{ "x11forwarding", sX11Forwarding },
 	{ "x11displayoffset", sX11DisplayOffset },
 	{ "xauthlocation", sXAuthLocation },
+	{ "portforwarding", sPortForwarding },
 	{ "strictmodes", sStrictModes },
 	{ "permitemptypasswords", sEmptyPasswd },
 	{ "uselogin", sUseLogin },
@@ -518,7 +525,11 @@
 		case sXAuthLocation:
 			charptr = &options->xauth_location;
 			goto parse_filename;
-			
+
+		case sPortForwarding:
+			intptr = &allow_port_forwarding;
+			goto parse_flag;
+
 		case sStrictModes:
 			intptr = &options->strict_modes;
 			goto parse_flag;
diff -u -r openssh-2.1.1p4/serverloop.c openssh-2.1.1p4-jhchanges/serverloop.c
--- openssh-2.1.1p4/serverloop.c	Tue Jul 11 10:31:38 2000
+++ openssh-2.1.1p4-jhchanges/serverloop.c	Tue Aug 22 21:26:20 2000
@@ -44,6 +44,9 @@
 static unsigned int buffer_high;/* "Soft" max buffer size. */
 static int max_fd;		/* Max file descriptor number for select(). */
 
+/* Jarno: import */
+extern int allow_port_forwarding;
+
 /*
  * This SIGCHLD kludge is used to detect when the child exits.  The server
  * will exit after that, as soon as forwarded connections have terminated.
@@ -722,11 +725,19 @@
 	   originator, originator_port, target, target_port);
 
 	/* XXX check permission */
-	if (no_port_forwarding_flag) {
+	/* Jarno: TODO: call function to check forwarding+better logging */
+#ifndef DISABLE_FORWARDING
+	if (no_port_forwarding_flag || !allow_port_forwarding) {
+#endif /* DISABLE_FORWARDING */
+		packet_send_debug("Server configuration rejects port forwardings.");
+		debug("Port forwarding disabled in server configuration.");
 		xfree(target);
 		xfree(originator);
 		return -1;
+#ifndef DISABLE_FORWARDING
 	}
+#endif /* DISABLE_FORWARDING */
+
 	sock = channel_connect_to(target, target_port);
 	xfree(target);
 	xfree(originator);
@@ -819,6 +830,7 @@
 	dispatch_set(SSH2_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
 	dispatch_set(SSH2_MSG_CHANNEL_REQUEST, &channel_input_channel_request);
 	dispatch_set(SSH2_MSG_CHANNEL_WINDOW_ADJUST, &channel_input_window_adjust);
+	dispatch_set(SSH2_MSG_GLOBAL_REQUEST, &channel_server_global_request);
 }
 void
 server_init_dispatch_13()
@@ -833,7 +845,7 @@
 	dispatch_set(SSH_MSG_CHANNEL_DATA, &channel_input_data);
 	dispatch_set(SSH_MSG_CHANNEL_OPEN_CONFIRMATION, &channel_input_open_confirmation);
 	dispatch_set(SSH_MSG_CHANNEL_OPEN_FAILURE, &channel_input_open_failure);
-	dispatch_set(SSH_MSG_PORT_OPEN, &channel_input_port_open);
+	dispatch_set(SSH_MSG_PORT_OPEN, &server_channel_input_port_open); /* Jarno */
 }
 void
 server_init_dispatch_15()
diff -u -r openssh-2.1.1p4/session.c openssh-2.1.1p4-jhchanges/session.c
--- openssh-2.1.1p4/session.c	Wed Jul 12 02:45:27 2000
+++ openssh-2.1.1p4-jhchanges/session.c	Wed Aug 23 10:25:53 2000
@@ -82,6 +82,9 @@
 
 /* import */
 extern ServerOptions options;
+/* Jarno */
+extern int allow_port_forwarding;
+
 #ifdef HAVE___PROGNAME
 extern char *__progname;
 #else /* HAVE___PROGNAME */
@@ -324,6 +327,19 @@
 				debug("Port forwarding not permitted for this authentication.");
 				break;
 			}
+
+			/* JARNO: Todo: Better logging */
+#ifndef DISABLE_FORWARDING
+		 if ( !allow_port_forwarding ) {
+#endif /* DISABLE_FORWARDING */
+				debug("Port forwarding disabled in server configuration.");
+				packet_send_debug("Server has disabled port forwarding.");
+				success = 0;
+				break;
+#ifndef DISABLE_FORWARDING
+			}
+#endif /* DISABLE_FORWARDING */
+
 			debug("Received TCP/IP port forwarding request.");
 			channel_input_port_forward_request(pw->pw_uid == 0, options.gateway_ports);
 			success = 1;
diff -u -r openssh-2.1.1p4/ssh.c openssh-2.1.1p4-jhchanges/ssh.c
--- openssh-2.1.1p4/ssh.c	Sat Jul 15 07:14:17 2000
+++ openssh-2.1.1p4-jhchanges/ssh.c	Mon Aug 21 18:37:31 2000
@@ -460,10 +460,6 @@
 		}
 	}
 
-	/* Cannot fork to background if no command. */
-	if (fork_after_authentication_flag && buffer_len(&command) == 0)
-		fatal("Cannot fork into background without a command to execute.");
-
 	/* Allocate a tty by default if no command specified. */
 	if (buffer_len(&command) == 0)
 		tty_flag = 1;
@@ -511,6 +507,29 @@
 	/* reinit */
 	log_init(av[0], options.log_level, SYSLOG_FACILITY_USER, 0);
 
+	/* -N option only makes sense with protocol 2. It doesn't make sense
+		 without port forwarding ??????
+	*/
+	if ( options.num_local_forwards == 0 && options.num_remote_forwards == 0 &&
+			 no_shell_flag ) {
+		fprintf(stderr, "-N makes sense only with port forwardings\n");
+		usage();
+		/* NOT REACHED */
+	}
+	if ((options.protocol & SSH_PROTO_2) && no_shell_flag && 
+			buffer_len(&command) > 0) {
+		fprintf(stderr,"-N option works only with protocol version 2 and w/out a command\n");
+		usage();
+		/* NOT REACHED */
+	}
+
+	/* Cannot fork to background if no command.
+		 Command not needed for protocol 2 & -N
+	*/
+	if ((options.protocol & SSH_PROTO_1) && !(options.protocol & SSH_PROTO_2) && 
+			fork_after_authentication_flag && buffer_len(&command) == 0)
+			fatal("Cannot fork into background without a command to execute.");
+
 	/* check if RSA support exists */
 	if ((options.protocol & SSH_PROTO_1) &&
 	    rsa_alive() == 0) {
@@ -831,7 +850,7 @@
 		channel_request_local_forwarding(options.local_forwards[i].port,
 						 options.local_forwards[i].host,
 						 options.local_forwards[i].host_port,
-						 options.gateway_ports);
+						 options.gateway_ports, 0);
 	}
 
 	/* Initiate remote TCP/IP port forwardings. */
@@ -887,7 +906,25 @@
 		channel_request_local_forwarding(options.local_forwards[i].port,
 						 options.local_forwards[i].host,
 						 options.local_forwards[i].host_port,
-						 options.gateway_ports);
+						 options.gateway_ports, 0);
+	}
+}
+
+/* Jarno Huuskonen: ssh2 client calls this to initiate remote port forwarding
+ * requests.
+ */
+void
+init_remote_fwd(void)
+{
+	int i;
+	for (i = 0; i < options.num_remote_forwards; i++) {
+		debug("Connections to remote port %d forwarded to local address %.200s:%d",
+		      options.remote_forwards[i].port,
+		      options.remote_forwards[i].host,
+		      options.remote_forwards[i].host_port);
+		channel_request_remote_forwarding(options.remote_forwards[i].port,
+						  options.remote_forwards[i].host,
+						  options.remote_forwards[i].host_port);
 	}
 }
 
@@ -963,7 +1000,9 @@
 
 	/* should be pre-session */
 	init_local_fwd();
-	
+	/* Jarno */
+	init_remote_fwd();
+
 	window = 32*1024;
 	if (tty_flag) {
 		packetmax = window/8;
@@ -979,6 +1018,12 @@
 
 	channel_open(id);
 	channel_register_callback(id, SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, client_init, (void *)0);
+
+	/* Jarno: User wants us to fork */
+	if (fork_after_authentication_flag) {
+		if (daemon(1, 1) < 0)
+			fatal("daemon() failed: %.200s", strerror(errno));
+	}
 
 	return client_loop(tty_flag, tty_flag ? options.escape_char : -1);
 }
diff -u -r openssh-2.1.1p4/sshd.8 openssh-2.1.1p4-jhchanges/sshd.8
--- openssh-2.1.1p4/sshd.8	Tue Jul 11 10:31:39 2000
+++ openssh-2.1.1p4-jhchanges/sshd.8	Sun Aug 13 13:47:46 2000
@@ -485,6 +485,10 @@
 listens on.
 The default is 22.
 Multiple options of this type are permitted.
+.It Cm PortForwarding
+Specifies whether TCP/IP port forwarding is permitted.
+The default is
+.Dq yes .
 .It Cm PrintMotd
 Specifies whether
 .Nm


More information about the openssh-unix-dev mailing list