- markus@cvs.openbsd.org 2006/07/11 18:50:48
     [clientloop.c ssh.1 ssh.c channels.c ssh_config.5 readconf.h session.c
     channels.h readconf.c]
     add ExitOnForwardFailure: terminate the connection if ssh(1)
     cannot set up all requested dynamic, local, and remote port
     forwardings. ok djm, dtucker, stevesk, jmc
diff --git a/ChangeLog b/ChangeLog
index b5c8498..74bfb0d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -23,6 +23,12 @@
      Only copy the part of environment variable that we actually use.  Prevents
      ssh bailing when SendEnv is used and an environment variable with a really
      long value exists.  ok djm@
+   - markus@cvs.openbsd.org 2006/07/11 18:50:48
+     [clientloop.c ssh.1 ssh.c channels.c ssh_config.5 readconf.h session.c
+     channels.h readconf.c]
+     add ExitOnForwardFailure: terminate the connection if ssh(1)
+     cannot set up all requested dynamic, local, and remote port
+     forwardings. ok djm, dtucker, stevesk, jmc
 
 20060711
  - (dtucker) [configure.ac ssh-keygen.c openbsd-compat/bsd-openpty.c
@@ -4872,4 +4878,4 @@
    - (djm) Trim deprecated options from INSTALL. Mention UsePAM
    - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
 
-$Id: ChangeLog,v 1.4395 2006/07/12 12:16:23 dtucker Exp $
+$Id: ChangeLog,v 1.4396 2006/07/12 12:17:10 dtucker Exp $
diff --git a/channels.c b/channels.c
index cd68efd..5171857 100644
--- a/channels.c
+++ b/channels.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.c,v 1.252 2006/07/10 12:08:08 djm Exp $ */
+/* $OpenBSD: channels.c,v 1.253 2006/07/11 18:50:47 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -2481,7 +2481,7 @@
  * the secure channel to host:port from local side.
  */
 
-void
+int
 channel_request_remote_forwarding(const char *listen_host, u_short listen_port,
     const char *host_to_connect, u_short port_to_connect)
 {
@@ -2525,7 +2525,6 @@
 			success = 1;
 			break;
 		case SSH_SMSG_FAILURE:
-			logit("Warning: Server denied remote port forwarding.");
 			break;
 		default:
 			/* Unknown packet */
@@ -2539,6 +2538,7 @@
 		permitted_opens[num_permitted_opens].listen_port = listen_port;
 		num_permitted_opens++;
 	}
+	return (success ? 0 : -1);
 }
 
 /*
@@ -2578,12 +2578,13 @@
 /*
  * 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.
+ * message if there was an error).
  */
-void
+int
 channel_input_port_forward_request(int is_root, int gateway_ports)
 {
 	u_short port, host_port;
+	int success = 0;
 	char *hostname;
 
 	/* Get arguments from the packet. */
@@ -2605,11 +2606,13 @@
 #endif
 
 	/* Initiate forwarding */
-	channel_setup_local_fwd_listener(NULL, port, hostname,
+	success = channel_setup_local_fwd_listener(NULL, port, hostname,
 	    host_port, gateway_ports);
 
 	/* Free the argument string. */
 	xfree(hostname);
+
+	return (success ? 0 : -1);
 }
 
 /*
@@ -2628,7 +2631,7 @@
 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");
+		fatal("channel_add_permitted_opens: too many forwards");
 	debug("allow port forwarding to host %s port %d", host, port);
 
 	permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host);
diff --git a/channels.h b/channels.h
index ee1d260..d21319a 100644
--- a/channels.h
+++ b/channels.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: channels.h,v 1.84 2006/03/25 22:22:42 djm Exp $ */
+/* $OpenBSD: channels.h,v 1.85 2006/07/11 18:50:47 markus Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -208,10 +208,10 @@
 void     channel_permit_all_opens(void);
 void	 channel_add_permitted_opens(char *, int);
 void	 channel_clear_permitted_opens(void);
-void     channel_input_port_forward_request(int, int);
+int      channel_input_port_forward_request(int, int);
 int	 channel_connect_to(const char *, u_short);
 int	 channel_connect_by_listen_address(u_short);
-void	 channel_request_remote_forwarding(const char *, u_short,
+int	 channel_request_remote_forwarding(const char *, u_short,
 	     const char *, u_short);
 int	 channel_setup_local_fwd_listener(const char *, u_short,
 	     const char *, u_short, int);
diff --git a/clientloop.c b/clientloop.c
index c59d573..6cb2a7a 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.166 2006/07/08 21:47:12 stevesk Exp $ */
+/* $OpenBSD: clientloop.c,v 1.167 2006/07/11 18:50:47 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -996,9 +996,12 @@
 				goto out;
 			}
 		} else {
-			channel_request_remote_forwarding(fwd.listen_host,
+			if (channel_request_remote_forwarding(fwd.listen_host,
 			    fwd.listen_port, fwd.connect_host,
-			    fwd.connect_port);
+			    fwd.connect_port) < 0) {
+				logit("Port forwarding failed.");
+				goto out;
+			}
 		}
 
 		logit("Forwarding port.");
diff --git a/readconf.c b/readconf.c
index df5e566..d25f930 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.152 2006/07/05 02:42:09 stevesk Exp $ */
+/* $OpenBSD: readconf.c,v 1.153 2006/07/11 18:50:48 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -102,6 +102,7 @@
 typedef enum {
 	oBadOption,
 	oForwardAgent, oForwardX11, oForwardX11Trusted, oGatewayPorts,
+	oExitOnForwardFailure,
 	oPasswordAuthentication, oRSAAuthentication,
 	oChallengeResponseAuthentication, oXAuthLocation,
 	oIdentityFile, oHostName, oPort, oCipher, oRemoteForward, oLocalForward,
@@ -132,6 +133,7 @@
 	{ "forwardagent", oForwardAgent },
 	{ "forwardx11", oForwardX11 },
 	{ "forwardx11trusted", oForwardX11Trusted },
+	{ "exitonforwardfailure", oExitOnForwardFailure },
 	{ "xauthlocation", oXAuthLocation },
 	{ "gatewayports", oGatewayPorts },
 	{ "useprivilegedport", oUsePrivilegedPort },
@@ -386,6 +388,10 @@
 		intptr = &options->gateway_ports;
 		goto parse_flag;
 
+	case oExitOnForwardFailure:
+		intptr = &options->exit_on_forward_failure;
+		goto parse_flag;
+
 	case oUsePrivilegedPort:
 		intptr = &options->use_privileged_port;
 		goto parse_flag;
@@ -987,6 +993,7 @@
 	options->forward_agent = -1;
 	options->forward_x11 = -1;
 	options->forward_x11_trusted = -1;
+	options->exit_on_forward_failure = -1;
 	options->xauth_location = NULL;
 	options->gateway_ports = -1;
 	options->use_privileged_port = -1;
@@ -1067,6 +1074,8 @@
 		options->forward_x11 = 0;
 	if (options->forward_x11_trusted == -1)
 		options->forward_x11_trusted = 0;
+	if (options->exit_on_forward_failure == -1)
+		options->exit_on_forward_failure = 0;
 	if (options->xauth_location == NULL)
 		options->xauth_location = _PATH_XAUTH;
 	if (options->gateway_ports == -1)
diff --git a/readconf.h b/readconf.h
index 7fc2ea4..e99b1ff 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.69 2006/03/25 22:22:43 djm Exp $ */
+/* $OpenBSD: readconf.h,v 1.70 2006/07/11 18:50:48 markus Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -34,6 +34,7 @@
 	int     forward_agent;	/* Forward authentication agent. */
 	int     forward_x11;	/* Forward X11 display. */
 	int     forward_x11_trusted;	/* Trust Forward X11 display. */
+	int     exit_on_forward_failure;	/* Exit if bind(2) fails for -L/-R */
 	char   *xauth_location;	/* Location for xauth program */
 	int     gateway_ports;	/* Allow remote connects to forwarded ports. */
 	int     use_privileged_port;	/* Don't use privileged port if false. */
diff --git a/session.c b/session.c
index 0a321be..33be915 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.207 2006/07/08 21:48:53 stevesk Exp $ */
+/* $OpenBSD: session.c,v 1.208 2006/07/11 18:50:48 markus Exp $ */
 /*
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  *                    All rights reserved
@@ -338,7 +338,11 @@
 				break;
 			}
 			debug("Received TCP/IP port forwarding request.");
-			channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports);
+			if (channel_input_port_forward_request(s->pw->pw_uid == 0,
+			    options.gateway_ports) < 0) {
+				debug("Port forwarding failed.");
+				break;
+			}
 			success = 1;
 			break;
 
diff --git a/ssh.1 b/ssh.1
index f44b6f2..6e41bcd 100644
--- a/ssh.1
+++ b/ssh.1
@@ -34,7 +34,7 @@
 .\" (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: ssh.1,v 1.262 2006/07/02 23:01:55 stevesk Exp $
+.\" $OpenBSD: ssh.1,v 1.263 2006/07/11 18:50:48 markus Exp $
 .Dd September 25, 1999
 .Dt SSH 1
 .Os
@@ -449,6 +449,7 @@
 .It ControlPath
 .It DynamicForward
 .It EscapeChar
+.It ExitOnForwardFailure
 .It ForwardAgent
 .It ForwardX11
 .It ForwardX11Trusted
diff --git a/ssh.c b/ssh.c
index bd92206..2e0ef2f 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.282 2006/07/11 10:12:07 dtucker Exp $ */
+/* $OpenBSD: ssh.c,v 1.283 2006/07/11 18:50:48 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -817,6 +817,8 @@
 		    options.local_forwards[i].connect_port,
 		    options.gateway_ports);
 	}
+	if (i > 0 && success != i && options.exit_on_forward_failure)
+		fatal("Could not request local forwarding.");
 	if (i > 0 && success == 0)
 		error("Could not request local forwarding.");
 
@@ -829,11 +831,17 @@
 		    options.remote_forwards[i].listen_port,
 		    options.remote_forwards[i].connect_host,
 		    options.remote_forwards[i].connect_port);
-		channel_request_remote_forwarding(
+		if (channel_request_remote_forwarding(
 		    options.remote_forwards[i].listen_host,
 		    options.remote_forwards[i].listen_port,
 		    options.remote_forwards[i].connect_host,
-		    options.remote_forwards[i].connect_port);
+		    options.remote_forwards[i].connect_port) < 0) {
+			if (options.exit_on_forward_failure)
+				fatal("Could not request remote forwarding.");
+			else
+				logit("Warning: Could not request remote "
+				    "forwarding.");
+		}
 	}
 }
 
@@ -1015,9 +1023,16 @@
 	    options.remote_forwards[i].listen_port,
 	    options.remote_forwards[i].connect_host,
 	    options.remote_forwards[i].connect_port);
-	if (type == SSH2_MSG_REQUEST_FAILURE)
-		logit("Warning: remote port forwarding failed for listen "
-		    "port %d", options.remote_forwards[i].listen_port);
+	if (type == SSH2_MSG_REQUEST_FAILURE) {
+		if (options.exit_on_forward_failure)
+			fatal("Error: remote port forwarding failed for "
+			    "listen port %d",
+			    options.remote_forwards[i].listen_port);
+		else
+			logit("Warning: remote port forwarding failed for "
+			    "listen port %d",
+			    options.remote_forwards[i].listen_port);
+	}
 }
 
 static void
diff --git a/ssh_config.5 b/ssh_config.5
index 68ec311..55ca553 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -34,7 +34,7 @@
 .\" (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: ssh_config.5,v 1.95 2006/07/02 17:12:58 stevesk Exp $
+.\" $OpenBSD: ssh_config.5,v 1.96 2006/07/11 18:50:48 markus Exp $
 .Dd September 25, 1999
 .Dt SSH_CONFIG 5
 .Os
@@ -385,6 +385,17 @@
 to disable the escape
 character entirely (making the connection transparent for binary
 data).
+.It Cm ExitOnForwardFailure
+Specifies whether
+.Xr ssh 1
+should terminate the connection if it cannot set up all requested
+dynamic, local, and remote port forwardings.
+The argument must be
+.Dq yes
+or
+.Dq no .
+The default is
+.Dq no .
 .It Cm ForwardAgent
 Specifies whether the connection to the authentication agent (if any)
 will be forwarded to the remote machine.