- djm@cvs.openbsd.org 2011/05/06 21:34:32
     [clientloop.c mux.c readconf.c readconf.h ssh.c ssh_config.5]
     Add a RequestTTY ssh_config option to allow configuration-based
     control over tty allocation (like -t/-T); ok markus@
diff --git a/ChangeLog b/ChangeLog
index caec1dd..67e6513 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -32,6 +32,10 @@
      
      Will match "a.example.org", "b.example.org", but not "c.example.org"
      ok markus@
+   - djm@cvs.openbsd.org 2011/05/06 21:34:32
+     [clientloop.c mux.c readconf.c readconf.h ssh.c ssh_config.5]
+     Add a RequestTTY ssh_config option to allow configuration-based
+     control over tty allocation (like -t/-T); ok markus@
 
 20110510
  - (dtucker) [openbsd-compat/openssl-compat.{c,h}] Bug #1882: fix
diff --git a/clientloop.c b/clientloop.c
index 502dd98..5bd757d 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.232 2011/04/17 22:42:41 djm Exp $ */
+/* $OpenBSD: clientloop.c,v 1.233 2011/05/06 21:34:32 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -130,9 +130,6 @@
  */
 extern char *host;
 
-/* Force TTY allocation */
-extern int force_tty_flag;
-
 /*
  * Flag to indicate that we have received a window change signal which has
  * not yet been processed.  This will cause a message indicating the new
@@ -662,7 +659,7 @@
 		atomicio(vwrite, fileno(stderr), buffer_ptr(berr),
 		    buffer_len(berr));
 
-	leave_raw_mode(force_tty_flag);
+	leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
 
 	/*
 	 * Free (and clear) the buffer to reduce the amount of data that gets
@@ -683,7 +680,7 @@
 	buffer_init(bout);
 	buffer_init(berr);
 
-	enter_raw_mode(force_tty_flag);
+	enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
 }
 
 static void
@@ -826,7 +823,7 @@
 	bzero(&fwd, sizeof(fwd));
 	fwd.listen_host = fwd.connect_host = NULL;
 
-	leave_raw_mode(force_tty_flag);
+	leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
 	handler = signal(SIGINT, SIG_IGN);
 	cmd = s = read_passphrase("\r\nssh> ", RP_ECHO);
 	if (s == NULL)
@@ -930,7 +927,7 @@
 
 out:
 	signal(SIGINT, handler);
-	enter_raw_mode(force_tty_flag);
+	enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
 	if (cmd)
 		xfree(cmd);
 	if (fwd.listen_host != NULL)
@@ -1049,7 +1046,8 @@
 				 * more new connections).
 				 */
 				/* Restore tty modes. */
-				leave_raw_mode(force_tty_flag);
+				leave_raw_mode(
+				    options.request_tty == REQUEST_TTY_FORCE);
 
 				/* Stop listening for new connections. */
 				channel_stop_listening();
@@ -1344,7 +1342,7 @@
 {
 	channel_cancel_cleanup(id);
 	session_closed = 1;
-	leave_raw_mode(force_tty_flag);
+	leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
 }
 
 /*
@@ -1415,7 +1413,7 @@
 	signal(SIGWINCH, window_change_handler);
 
 	if (have_pty)
-		enter_raw_mode(force_tty_flag);
+		enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
 
 	if (compat20) {
 		session_ident = ssh2_chan_id;
@@ -1559,7 +1557,7 @@
 	channel_free_all();
 
 	if (have_pty)
-		leave_raw_mode(force_tty_flag);
+		leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
 
 	/* restore blocking io */
 	if (!isatty(fileno(stdin)))
@@ -2142,7 +2140,7 @@
 void
 cleanup_exit(int i)
 {
-	leave_raw_mode(force_tty_flag);
+	leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
 	leave_non_blocking();
 	if (options.control_path != NULL && muxserver_sock != -1)
 		unlink(options.control_path);
diff --git a/mux.c b/mux.c
index fb24c0f..1afd1bd 100644
--- a/mux.c
+++ b/mux.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: mux.c,v 1.26 2011/05/05 05:12:08 djm Exp $ */
+/* $OpenBSD: mux.c,v 1.27 2011/05/06 21:34:32 djm Exp $ */
 /*
  * Copyright (c) 2002-2008 Damien Miller <djm@openbsd.org>
  *
@@ -87,7 +87,6 @@
 
 /* from ssh.c */
 extern int tty_flag;
-extern int force_tty_flag;
 extern Options options;
 extern int stdin_null_flag;
 extern char *host;
@@ -1710,7 +1709,7 @@
 	signal(SIGWINCH, control_client_sigrelay);
 
 	if (tty_flag)
-		enter_raw_mode(force_tty_flag);
+		enter_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
 
 	/*
 	 * Stick around until the controlee closes the client_fd.
@@ -1739,7 +1738,7 @@
 	}
 
 	close(fd);
-	leave_raw_mode(force_tty_flag);
+	leave_raw_mode(options.request_tty == REQUEST_TTY_FORCE);
 
 	if (muxclient_terminate) {
 		debug2("Exiting on signal %d", muxclient_terminate);
diff --git a/readconf.c b/readconf.c
index 927e7fe..4780ae2 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.c,v 1.191 2011/05/06 21:31:38 djm Exp $ */
+/* $OpenBSD: readconf.c,v 1.192 2011/05/06 21:34:32 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -134,7 +134,7 @@
 	oHashKnownHosts,
 	oTunnel, oTunnelDevice, oLocalCommand, oPermitLocalCommand,
 	oVisualHostKey, oUseRoaming, oZeroKnowledgePasswordAuthentication,
-	oKexAlgorithms, oIPQoS,
+	oKexAlgorithms, oIPQoS, oRequestTTY,
 	oDeprecated, oUnsupported
 } OpCodes;
 
@@ -245,6 +245,7 @@
 #endif
 	{ "kexalgorithms", oKexAlgorithms },
 	{ "ipqos", oIPQoS },
+	{ "requesttty", oRequestTTY },
 
 	{ NULL, oBadOption }
 };
@@ -1013,6 +1014,26 @@
 		intptr = &options->use_roaming;
 		goto parse_flag;
 
+	case oRequestTTY:
+		arg = strdelim(&s);
+		if (!arg || *arg == '\0')
+			fatal("%s line %d: missing argument.",
+			    filename, linenum);
+		intptr = &options->request_tty;
+		if (strcasecmp(arg, "yes") == 0)
+			value = REQUEST_TTY_YES;
+		else if (strcasecmp(arg, "no") == 0)
+			value = REQUEST_TTY_NO;
+		else if (strcasecmp(arg, "force") == 0)
+			value = REQUEST_TTY_FORCE;
+		else if (strcasecmp(arg, "auto") == 0)
+			value = REQUEST_TTY_AUTO;
+		else
+			fatal("Unsupported RequestTTY \"%s\"", arg);
+		if (*activep && *intptr == -1)
+			*intptr = value;
+		break;
+
 	case oDeprecated:
 		debug("%s line %d: Deprecated option \"%s\"",
 		    filename, linenum, keyword);
@@ -1173,6 +1194,7 @@
 	options->zero_knowledge_password_authentication = -1;
 	options->ip_qos_interactive = -1;
 	options->ip_qos_bulk = -1;
+	options->request_tty = -1;
 }
 
 /*
@@ -1331,6 +1353,8 @@
 		options->ip_qos_interactive = IPTOS_LOWDELAY;
 	if (options->ip_qos_bulk == -1)
 		options->ip_qos_bulk = IPTOS_THROUGHPUT;
+	if (options->request_tty == -1)
+		options->request_tty = REQUEST_TTY_AUTO;
 	/* options->local_command should not be set by default */
 	/* options->proxy_command should not be set by default */
 	/* options->user will be set in the main program if appropriate */
diff --git a/readconf.h b/readconf.h
index ee160df..bc3e8c1 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: readconf.h,v 1.88 2010/11/13 23:27:50 djm Exp $ */
+/* $OpenBSD: readconf.h,v 1.89 2011/05/06 21:34:32 djm Exp $ */
 
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -132,6 +132,7 @@
 
 	int	use_roaming;
 
+	int	request_tty;
 }       Options;
 
 #define SSHCTL_MASTER_NO	0
@@ -140,6 +141,11 @@
 #define SSHCTL_MASTER_ASK	3
 #define SSHCTL_MASTER_AUTO_ASK	4
 
+#define REQUEST_TTY_AUTO	0
+#define REQUEST_TTY_NO		1
+#define REQUEST_TTY_YES		2
+#define REQUEST_TTY_FORCE	3
+
 void     initialize_options(Options *);
 void     fill_default_options(Options *);
 int	 read_config_file(const char *, const char *, Options *, int);
diff --git a/ssh.c b/ssh.c
index 549dd5c..7243fa2 100644
--- a/ssh.c
+++ b/ssh.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ssh.c,v 1.358 2011/05/06 21:18:02 djm Exp $ */
+/* $OpenBSD: ssh.c,v 1.359 2011/05/06 21:34:32 djm Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -114,10 +114,8 @@
 /* Flag indicating whether debug mode is on.  May be set on the command line. */
 int debug_flag = 0;
 
-/* Flag indicating whether a tty should be allocated */
+/* Flag indicating whether a tty should be requested */
 int tty_flag = 0;
-int no_tty_flag = 0;
-int force_tty_flag = 0;
 
 /* don't exec a shell */
 int no_shell_flag = 0;
@@ -135,7 +133,7 @@
 int need_controlpersist_detach = 0;
 
 /* Copies of flags for ControlPersist foreground slave */
-int ostdin_null_flag, ono_shell_flag, ono_tty_flag, otty_flag;
+int ostdin_null_flag, ono_shell_flag, otty_flag, orequest_tty;
 
 /*
  * Flag indicating that ssh should fork after authentication.  This is useful
@@ -389,9 +387,10 @@
 #endif
 			break;
 		case 't':
-			if (tty_flag)
-				force_tty_flag = 1;
-			tty_flag = 1;
+			if (options.request_tty == REQUEST_TTY_YES)
+				options.request_tty = REQUEST_TTY_FORCE;
+			else
+				options.request_tty = REQUEST_TTY_YES;
 			break;
 		case 'v':
 			if (debug_flag == 0) {
@@ -434,7 +433,7 @@
 				    optarg);
 				exit(255);
 			}
-			no_tty_flag = 1;
+			options.request_tty = REQUEST_TTY_NO;
 			no_shell_flag = 1;
 			options.clear_forwardings = 1;
 			options.exit_on_forward_failure = 1;
@@ -543,10 +542,10 @@
 			break;
 		case 'N':
 			no_shell_flag = 1;
-			no_tty_flag = 1;
+			options.request_tty = REQUEST_TTY_NO;
 			break;
 		case 'T':
-			no_tty_flag = 1;
+			options.request_tty = REQUEST_TTY_NO;
 			break;
 		case 'o':
 			dummy = 1;
@@ -606,6 +605,10 @@
 	/* Initialize the command to execute on remote host. */
 	buffer_init(&command);
 
+	if (options.request_tty == REQUEST_TTY_YES ||
+	    options.request_tty == REQUEST_TTY_FORCE)
+		tty_flag = 1;
+
 	/*
 	 * Save the command to execute on the remote host in a buffer. There
 	 * is no limit on the length of the command, except by the maximum
@@ -613,7 +616,7 @@
 	 */
 	if (!ac) {
 		/* No command specified - execute shell on a tty. */
-		tty_flag = 1;
+		tty_flag = options.request_tty != REQUEST_TTY_NO;
 		if (subsystem_flag) {
 			fprintf(stderr,
 			    "You must specify a subsystem to invoke.\n");
@@ -636,13 +639,14 @@
 
 	/* Allocate a tty by default if no command specified. */
 	if (buffer_len(&command) == 0)
-		tty_flag = 1;
+		tty_flag = options.request_tty != REQUEST_TTY_NO;
 
 	/* Force no tty */
-	if (no_tty_flag || muxclient_command != 0)
+	if (options.request_tty == REQUEST_TTY_NO || muxclient_command != 0)
 		tty_flag = 0;
 	/* Do not allocate a tty if stdin is not a tty. */
-	if ((!isatty(fileno(stdin)) || stdin_null_flag) && !force_tty_flag) {
+	if ((!isatty(fileno(stdin)) || stdin_null_flag) &&
+	    options.request_tty != REQUEST_TTY_FORCE) {
 		if (tty_flag)
 			logit("Pseudo-terminal will not be allocated because "
 			    "stdin is not a terminal.");
@@ -946,8 +950,7 @@
 		/* Parent: set up mux slave to connect to backgrounded master */
 		debug2("%s: background process is %ld", __func__, (long)pid);
 		stdin_null_flag = ostdin_null_flag;
-		no_shell_flag = ono_shell_flag;
-		no_tty_flag = ono_tty_flag;
+		options.request_tty = orequest_tty;
 		tty_flag = otty_flag;
  		close(muxserver_sock);
  		muxserver_sock = -1;
@@ -1394,11 +1397,11 @@
  	if (options.control_persist && muxserver_sock != -1) {
 		ostdin_null_flag = stdin_null_flag;
 		ono_shell_flag = no_shell_flag;
-		ono_tty_flag = no_tty_flag;
+		orequest_tty = options.request_tty;
 		otty_flag = tty_flag;
  		stdin_null_flag = 1;
  		no_shell_flag = 1;
- 		no_tty_flag = 1;
+ 		options.request_tty == REQUEST_TTY_NO;
  		tty_flag = 0;
 		if (!fork_after_authentication_flag)
 			need_controlpersist_detach = 1;
diff --git a/ssh_config.5 b/ssh_config.5
index 5bdc7fe..83baa82 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -33,7 +33,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.148 2011/05/06 21:31:38 djm Exp $
+.\" $OpenBSD: ssh_config.5,v 1.149 2011/05/06 21:34:32 djm Exp $
 .Dd $Mdocdate: May 6 2011 $
 .Dt SSH_CONFIG 5
 .Os
@@ -959,6 +959,23 @@
 .Cm GatewayPorts
 option is enabled (see
 .Xr sshd_config 5 ) .
+.It Cm RequestTTY
+Specifies whether to request a pseudo-tty for the session.
+The argument may be one of:
+.Dq no
+(never request a TTY),
+.Dq yes
+(always request a TTY when standard input is a TTY),
+.Dq force
+(always request a TTY) or
+.Dq auto
+(request a TTY when opening a login session).
+This option mirrors the
+.Fl t
+and
+.Fl T
+flags for
+.Xr ssh 1 .
 .It Cm RhostsRSAAuthentication
 Specifies whether to try rhosts based authentication with RSA host
 authentication.