- djm@cvs.openbsd.org 2012/12/02 20:46:11
     [auth-options.c channels.c servconf.c servconf.h serverloop.c session.c]
     [sshd_config.5]
     make AllowTcpForwarding accept "local" and "remote" in addition to its
     current "yes"/"no" to allow the server to specify whether just local or
     remote TCP forwarding is enabled. ok markus@
diff --git a/ChangeLog b/ChangeLog
index 7cea00c..cee0387 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -12,6 +12,12 @@
      make deleting explicit keys "ssh-add -d" symmetric with adding keys -
      try to delete the corresponding certificate too and respect the -k option
      to allow deleting of the key only; feedback and ok markus@
+   - djm@cvs.openbsd.org 2012/12/02 20:46:11
+     [auth-options.c channels.c servconf.c servconf.h serverloop.c session.c]
+     [sshd_config.5]
+     make AllowTcpForwarding accept "local" and "remote" in addition to its
+     current "yes"/"no" to allow the server to specify whether just local or
+     remote TCP forwarding is enabled. ok markus@
 
 20121114
  - (djm) OpenBSD CVS Sync
diff --git a/auth-options.c b/auth-options.c
index 0e67bd8..23d0423 100644
--- a/auth-options.c
+++ b/auth-options.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: auth-options.c,v 1.56 2011/10/18 04:58:26 djm Exp $ */
+/* $OpenBSD: auth-options.c,v 1.57 2012/12/02 20:46:11 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -349,7 +349,7 @@
 				xfree(patterns);
 				goto bad_option;
 			}
-			if (options.allow_tcp_forwarding)
+			if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0)
 				channel_add_permitted_opens(host, port);
 			xfree(patterns);
 			goto next_option;
diff --git a/channels.c b/channels.c
index 7791feb..9cf85a3 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.318 2012/04/23 08:18:17 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.319 2012/12/02 20:46:11 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -3165,12 +3165,10 @@
 void
 channel_disable_adm_local_opens(void)
 {
-	if (num_adm_permitted_opens == 0) {
-		permitted_adm_opens = xmalloc(sizeof(*permitted_adm_opens));
-		permitted_adm_opens[num_adm_permitted_opens].host_to_connect
-		   = NULL;
-		num_adm_permitted_opens = 1;
-	}
+	channel_clear_adm_permitted_opens();
+	permitted_adm_opens = xmalloc(sizeof(*permitted_adm_opens));
+	permitted_adm_opens[num_adm_permitted_opens].host_to_connect = NULL;
+	num_adm_permitted_opens = 1;
 }
 
 void
diff --git a/servconf.c b/servconf.c
index b90dba6..21b371c 100644
--- a/servconf.c
+++ b/servconf.c
@@ -1,5 +1,5 @@
 
-/* $OpenBSD: servconf.c,v 1.232 2012/11/04 11:09:15 djm Exp $ */
+/* $OpenBSD: servconf.c,v 1.233 2012/12/02 20:46:11 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -250,7 +250,7 @@
 	if (options->compression == -1)
 		options->compression = COMP_DELAYED;
 	if (options->allow_tcp_forwarding == -1)
-		options->allow_tcp_forwarding = 1;
+		options->allow_tcp_forwarding = FORWARD_ALLOW;
 	if (options->allow_agent_forwarding == -1)
 		options->allow_agent_forwarding = 1;
 	if (options->gateway_ports == -1)
@@ -786,6 +786,14 @@
 	{ "no",				PRIVSEP_OFF },
 	{ NULL, -1 }
 };
+static const struct multistate multistate_tcpfwd[] = {
+	{ "yes",			FORWARD_ALLOW },
+	{ "all",			FORWARD_ALLOW },
+	{ "no",				FORWARD_DENY },
+	{ "remote",			FORWARD_REMOTE },
+	{ "local",			FORWARD_LOCAL },
+	{ NULL, -1 }
+};
 
 int
 process_server_config_line(ServerOptions *options, char *line,
@@ -1143,7 +1151,8 @@
 
 	case sAllowTcpForwarding:
 		intptr = &options->allow_tcp_forwarding;
-		goto parse_flag;
+		multistate_ptr = multistate_tcpfwd;
+		goto parse_multistate;
 
 	case sAllowAgentForwarding:
 		intptr = &options->allow_agent_forwarding;
@@ -1423,7 +1432,6 @@
 		}
 		if (strcmp(arg, "none") == 0) {
 			if (*activep && n == -1) {
-				channel_clear_adm_permitted_opens();
 				options->num_permitted_opens = 1;
 				channel_disable_adm_local_opens();
 			}
@@ -1780,6 +1788,8 @@
 		return fmt_multistate_int(val, multistate_compression);
 	case sUsePrivilegeSeparation:
 		return fmt_multistate_int(val, multistate_privsep);
+	case sAllowTcpForwarding:
+		return fmt_multistate_int(val, multistate_tcpfwd);
 	case sProtocol:
 		switch (val) {
 		case SSH_PROTO_1:
diff --git a/servconf.h b/servconf.h
index 68fcdb7..a23ef7f 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: servconf.h,v 1.105 2012/11/04 11:09:15 djm Exp $ */
+/* $OpenBSD: servconf.h,v 1.106 2012/12/02 20:46:11 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -42,6 +42,12 @@
 #define PRIVSEP_ON		1
 #define PRIVSEP_NOSANDBOX	2
 
+/* AllowTCPForwarding */
+#define FORWARD_DENY		0
+#define FORWARD_REMOTE		(1)
+#define FORWARD_LOCAL		(1<<1)
+#define FORWARD_ALLOW		(FORWARD_REMOTE|FORWARD_LOCAL)
+
 #define DEFAULT_AUTH_FAIL_MAX	6	/* Default for MaxAuthTries */
 #define DEFAULT_SESSIONS_MAX	10	/* Default for MaxSessions */
 
@@ -116,7 +122,7 @@
 	int     permit_user_env;	/* If true, read ~/.ssh/environment */
 	int     use_login;	/* If true, login(1) is used */
 	int     compression;	/* If true, compression is allowed */
-	int	allow_tcp_forwarding;
+	int	allow_tcp_forwarding; /* One of FORWARD_* */
 	int	allow_agent_forwarding;
 	u_int num_allow_users;
 	char   *allow_users[MAX_ALLOW_USERS];
diff --git a/serverloop.c b/serverloop.c
index 741c5be..14e60c6 100644
--- a/serverloop.c
+++ b/serverloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: serverloop.c,v 1.162 2012/06/20 04:42:58 djm Exp $ */
+/* $OpenBSD: serverloop.c,v 1.163 2012/12/02 20:46:11 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -950,7 +950,7 @@
 static Channel *
 server_request_direct_tcpip(void)
 {
-	Channel *c;
+	Channel *c = NULL;
 	char *target, *originator;
 	u_short target_port, originator_port;
 
@@ -963,9 +963,16 @@
 	debug("server_request_direct_tcpip: originator %s port %d, target %s "
 	    "port %d", originator, originator_port, target, target_port);
 
-	/* XXX check permission */
-	c = channel_connect_to(target, target_port,
-	    "direct-tcpip", "direct-tcpip");
+	/* XXX fine grained permissions */
+	if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0 &&
+	    !no_port_forwarding_flag) {
+		c = channel_connect_to(target, target_port,
+		    "direct-tcpip", "direct-tcpip");
+	} else {
+		logit("refused local port forward: "
+		    "originator %s port %d, target %s port %d",
+		    originator, originator_port, target, target_port);
+	}
 
 	xfree(originator);
 	xfree(target);
@@ -1126,7 +1133,7 @@
 		    listen_address, listen_port);
 
 		/* check permissions */
-		if (!options.allow_tcp_forwarding ||
+		if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0 ||
 		    no_port_forwarding_flag ||
 		    (!want_reply && listen_port == 0)
 #ifndef NO_IPPORT_RESERVED_CONCEPT
diff --git a/session.c b/session.c
index 65bf287..643e7fc 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.260 2012/03/15 03:10:27 guenther Exp $ */
+/* $OpenBSD: session.c,v 1.261 2012/12/02 20:46:11 djm Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -273,7 +273,10 @@
 	setproctitle("%s", authctxt->pw->pw_name);
 
 	/* setup the channel layer */
-	if (!no_port_forwarding_flag && options.allow_tcp_forwarding)
+	if (no_port_forwarding_flag ||
+	    (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
+		channel_disable_adm_local_opens();
+	else
 		channel_permit_all_opens();
 
 	auth_debug_send();
@@ -383,7 +386,7 @@
 				debug("Port forwarding not permitted for this authentication.");
 				break;
 			}
-			if (!options.allow_tcp_forwarding) {
+			if (!(options.allow_tcp_forwarding & FORWARD_REMOTE)) {
 				debug("Port forwarding not permitted.");
 				break;
 			}
diff --git a/sshd_config.5 b/sshd_config.5
index 05f3374..d2c4db5 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -33,8 +33,8 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.\" $OpenBSD: sshd_config.5,v 1.149 2012/11/04 11:09:15 djm Exp $
-.Dd $Mdocdate: November 4 2012 $
+.\" $OpenBSD: sshd_config.5,v 1.150 2012/12/02 20:46:11 djm Exp $
+.Dd $Mdocdate: December 2 2012 $
 .Dt SSHD_CONFIG 5
 .Os
 .Sh NAME
@@ -124,6 +124,18 @@
 for more information on patterns.
 .It Cm AllowTcpForwarding
 Specifies whether TCP forwarding is permitted.
+The available options are
+.Dq yes
+or
+.Dq all
+to allow TCP forwarding,
+.Dq no
+to prevent all TCP forwarding,
+.Dq local
+to allow local (from the perspective of
+.Xr ssh 1 ) forwarding only or
+.Dq remote
+to allow remote forwarding only.
 The default is
 .Dq yes .
 Note that disabling TCP forwarding does not improve security unless