# HG changeset patch
# Parent  bf6de09b9a5d04dbf3c2b0c0ff042de709484934
Date:   Sat Jun 26 10:02:24 2010 +1000

upstream commit 1bf477d3cdf1a864646d59820878783d42357a1d
Author: djm@openbsd.org <djm@openbsd.org>
    upstream commit

    better refuse ForwardX11Trusted=no connections attempted
     after ForwardX11Timeout expires; reported by Jann Horn

    Upstream-ID: bf0fddadc1b46a0334e26c080038313b4b6dea21

diff --git a/openssh-5.1p1/channels.c b/openssh-5.1p1/channels.c
--- a/openssh-5.1p1/channels.c
+++ b/openssh-5.1p1/channels.c
@@ -142,16 +142,19 @@ static char *x11_saved_display = NULL;
 
 /* Saved X11 authentication protocol name. */
 static char *x11_saved_proto = NULL;
 
 /* Saved X11 authentication data.  This is the real data. */
 static char *x11_saved_data = NULL;
 static u_int x11_saved_data_len = 0;
 
+/* Deadline after which all X11 connections are refused */
+static u_int x11_refuse_time;
+
 /*
  * Fake X11 authentication data.  This is what the server will be sending us;
  * we should replace any occurrences of this by the real data.
  */
 static u_char *x11_fake_data = NULL;
 static u_int x11_fake_data_len;
 
 
@@ -865,16 +868,23 @@ channel_pre_output_draining(Channel *c, 
  * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok
  */
 static int
 x11_open_helper(Buffer *b)
 {
 	u_char *ucp;
 	u_int proto_len, data_len;
 
+	/* Is this being called after the refusal deadline? */
+	if (x11_refuse_time != 0 && (u_int)time(NULL) >= x11_refuse_time) {
+		verbose("Rejected X11 connection after ForwardX11Timeout "
+		    "expired");
+		return -1;
+	}
+
 	/* Check if the fixed size part of the packet is in buffer. */
 	if (buffer_len(b) < 12)
 		return 0;
 
 	/* Parse the lengths of variable-length fields. */
 	ucp = buffer_ptr(b);
 	if (ucp[0] == 0x42) {	/* Byte order MSB first. */
 		proto_len = 256 * ucp[6] + ucp[7];
@@ -1323,16 +1333,22 @@ channel_set_reuseaddr(int fd)
 	/*
 	 * Set socket options.
 	 * Allow local port reuse in TIME_WAIT.
 	 */
 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1)
 		error("setsockopt SO_REUSEADDR fd %d: %s", fd, strerror(errno));
 }
 
+void
+channel_set_x11_refuse_time(u_int refuse_time)
+{
+	x11_refuse_time = refuse_time;
+}
+
 /*
  * This socket is listening for connections to a forwarded TCP/IP port.
  */
 /* ARGSUSED */
 static void
 channel_post_port_listener(Channel *c, fd_set *readset, fd_set *writeset)
 {
 	Channel *nc;
diff --git a/openssh-5.1p1/channels.h b/openssh-5.1p1/channels.h
--- a/openssh-5.1p1/channels.h
+++ b/openssh-5.1p1/channels.h
@@ -247,16 +247,17 @@ int	 channel_request_remote_forwarding(c
 int	 channel_setup_local_fwd_listener(const char *, u_short,
 	     const char *, u_short, int);
 void	 channel_request_rforward_cancel(const char *host, u_short port);
 int	 channel_setup_remote_fwd_listener(const char *, u_short, int);
 int	 channel_cancel_rport_listener(const char *, u_short);
 
 /* x11 forwarding */
 
+void	 channel_set_x11_refuse_time(u_int);
 int	 x11_connect_display(void);
 int	 x11_create_display_inet(int, int, int, u_int *, int **);
 void     x11_input_open(int, u_int32_t, void *);
 void	 x11_request_forwarding_with_spoofing(int, const char *, const char *,
 	     const char *);
 void	 deny_input_open(int, u_int32_t, void *);
 
 /* agent forwarding */
diff --git a/openssh-5.1p1/clientloop.c b/openssh-5.1p1/clientloop.c
--- a/openssh-5.1p1/clientloop.c
+++ b/openssh-5.1p1/clientloop.c
@@ -152,17 +152,17 @@ static int stdin_eof;		/* EOF has been e
 static Buffer stdin_buffer;	/* Buffer for stdin data. */
 static Buffer stdout_buffer;	/* Buffer for stdout data. */
 static Buffer stderr_buffer;	/* Buffer for stderr data. */
 static u_int buffer_high;	/* Soft max buffer size. */
 static int connection_in;	/* Connection to server (input). */
 static int connection_out;	/* Connection to server (output). */
 static int need_rekeying;	/* Set to non-zero if rekeying is requested. */
 static int session_closed;	/* In SSH2: login session closed. */
-static int x11_refuse_time;	/* If >0, refuse x11 opens after this time. */
+static u_int x11_refuse_time;	/* If >0, refuse x11 opens after this time. */
 
 static void client_init_dispatch(void);
 int	session_ident = -1;
 
 /* Track escape per proto2 channel */
 struct escape_filter_ctx {
 	int escape_pending;
 	int escape_char;
@@ -242,30 +242,31 @@ signal_handler(int sig)
 static double
 get_current_time(void)
 {
 	struct timeval tv;
 	gettimeofday(&tv, NULL);
 	return (double) tv.tv_sec + (double) tv.tv_usec / 1000000.0;
 }
 
-#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
+#define SSH_X11_PROTO		"MIT-MAGIC-COOKIE-1"
+#define X11_TIMEOUT_SLACK	60
 void
 client_x11_get_proto(const char *display, const char *xauth_path,
     u_int trusted, u_int timeout, char **_proto, char **_data)
 {
 	char cmd[1024];
 	char line[512];
 	char xdisplay[512];
 	static char proto[512], data[512];
 	FILE *f;
 	int got_data = 0, generated = 0, do_unlink = 0, i;
 	char *xauthdir, *xauthfile;
 	struct stat st;
-	u_int now;
+	u_int now, x11_timeout_real;
 
 	xauthdir = xauthfile = NULL;
 	*_proto = proto;
 	*_data = data;
 	proto[0] = data[0] = '\0';
 
 	if (xauth_path == NULL ||(stat(xauth_path, &st) == -1)) {
 		debug("No xauth program.");
@@ -284,35 +285,47 @@ client_x11_get_proto(const char *display
 		if (strncmp(display, "localhost:", 10) == 0) {
 			snprintf(xdisplay, sizeof(xdisplay), "unix:%s",
 			    display + 10);
 			display = xdisplay;
 		}
 		if (trusted == 0) {
 			xauthdir = xmalloc(MAXPATHLEN);
 			xauthfile = xmalloc(MAXPATHLEN);
+			/*
+			 * The authentication cookie should briefly outlive
+			 * ssh's willingness to forward X11 connections to
+			 * avoid nasty fail-open behaviour in the X server.
+			 */
+			if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK)
+				x11_timeout_real = UINT_MAX;
+			else
+				x11_timeout_real = timeout + X11_TIMEOUT_SLACK;
 			strlcpy(xauthdir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);
 			if (mkdtemp(xauthdir) != NULL) {
 				do_unlink = 1;
 				snprintf(xauthfile, MAXPATHLEN, "%s/xauthfile",
 				    xauthdir);
 				snprintf(cmd, sizeof(cmd),
 				    "%s -f %s generate %s " SSH_X11_PROTO
 				    " untrusted timeout %u 2>" _PATH_DEVNULL,
-				    xauth_path, xauthfile, display, timeout);
+				    xauth_path, xauthfile, display,
+				    x11_timeout_real);
 				debug2("x11_get_proto: %s", cmd);
-				if (system(cmd) == 0)
-					generated = 1;
 				if (x11_refuse_time == 0) {
 					now = time(NULL) + 1;
 					if (UINT_MAX - timeout < now)
 						x11_refuse_time = UINT_MAX;
 					else
 						x11_refuse_time = now + timeout;
+					channel_set_x11_refuse_time(
+					    x11_refuse_time);
 				}
+				if (system(cmd) == 0)
+					generated = 1;
 			}
 		}
 
 		/*
 		 * When in untrusted mode, we read the cookie only if it was
 		 * successfully generated as an untrusted one in the step
 		 * above.
 		 */
