2001-08-26  Simon Josefsson  <sjosefsson@rsasecurity.com>

	* telnet/*: Port '-x' fix from MIT Kerberos.

Mon Mar 18 20:56:37 1996  Theodore Y. Ts'o  <tytso@dcl>

	* encrypt.c (encrypt_is_encrypting): New function which returns
	true only if both sides of the telnet stream is encrypted.

Mon Mar 18 20:31:44 1996  Theodore Y. Ts'o  <tytso@dcl>

	* telnet/authenc.c (telnet_spin): Implemented the telnet spin
	function, which works by calling the Scheduler with the
	tty_lockout flag set.

	* main.c (main): If the -x option is given, set the autologin,
	wantencryption, and auth_enable_encrypt flag.  They enable
	authentication, enforcement of the encryption option, and a flag
	to the auth layer to negotiate authentication with mandatory
	encryption option.

	* telnet.c (telnet): If the wantencryption flag is set (because
	the user has given the -x option, then we enforce that encryption
	must be turned on.  The user will not be able to type to the
	network stream until encryption is enabled, and if encryption is
	refused, the client will print an error message.
	(Scheduler): If the tty_lockout flag is set, then don't process
	keyboard read events.  This prevents the user from typing over the
	network until encryption is enabled.

diff -ur heimdal-0.4d.orig/appl/telnet/libtelnet/auth.c heimdal-0.4d/appl/telnet/libtelnet/auth.c
--- heimdal-0.4d.orig/appl/telnet/libtelnet/auth.c	Mon Jun 18 21:49:59 2001
+++ heimdal-0.4d/appl/telnet/libtelnet/auth.c	Sun Aug 26 21:56:06 2001
@@ -100,6 +100,8 @@
 #endif
 
 int auth_debug_mode = 0;
+int auth_has_failed = 0;
+int auth_enable_encrypt = 0;
 static 	const	char	*Name = "Noname";
 static	int	Server = 0;
 static	Authenticator	*authenticated = 0;
@@ -468,6 +470,7 @@
     if (auth_debug_mode)
 	printf(">>>%s: Sent failure message\r\n", Name);
     auth_finished(0, AUTH_REJECT);
+    auth_has_failed = 1;
 #ifdef KANNAN
     /*
      *  We requested strong authentication, however no mechanisms worked.
diff -ur heimdal-0.4d.orig/appl/telnet/libtelnet/enc-proto.h heimdal-0.4d/appl/telnet/libtelnet/enc-proto.h
--- heimdal-0.4d.orig/appl/telnet/libtelnet/enc-proto.h	Tue Jan 18 04:09:56 2000
+++ heimdal-0.4d/appl/telnet/libtelnet/enc-proto.h	Sun Aug 26 22:01:03 2001
@@ -94,6 +94,7 @@
 void encrypt_send_keyid(int, unsigned char*, int, int);
 void encrypt_send_request_end(void);
 void encrypt_send_request_start(void);
+int encrypt_is_encrypting(void);
 void encrypt_send_support(void);
 void encrypt_session_key(Session_Key*, int);
 void encrypt_start(unsigned char*, int);
diff -ur heimdal-0.4d.orig/appl/telnet/libtelnet/encrypt.c heimdal-0.4d/appl/telnet/libtelnet/encrypt.c
--- heimdal-0.4d.orig/appl/telnet/libtelnet/encrypt.c	Tue Jan 18 04:10:35 2000
+++ heimdal-0.4d/appl/telnet/libtelnet/encrypt.c	Sun Aug 26 22:01:21 2001
@@ -952,6 +952,13 @@
     return 0;
 }
 
+int encrypt_is_encrypting()
+{
+    if (encrypt_output && decrypt_input)
+	return 1;
+    return 0;
+}
+
 void
 encrypt_debug(int mode)
 {
diff -ur heimdal-0.4d.orig/appl/telnet/telnet/authenc.c heimdal-0.4d/appl/telnet/telnet/authenc.c
--- heimdal-0.4d.orig/appl/telnet/telnet/authenc.c	Thu Nov 16 00:00:58 2000
+++ heimdal-0.4d/appl/telnet/telnet/authenc.c	Sun Aug 26 22:12:00 2001
@@ -62,7 +62,14 @@
 int
 telnet_spin(void)
 {
-	return(-1);
+    extern int scheduler_lockout_tty;
+
+    scheduler_lockout_tty = 1;
+    Scheduler(0);
+    scheduler_lockout_tty = 0;
+    
+    return 0;
+
 }
 
 char *
diff -ur heimdal-0.4d.orig/appl/telnet/telnet/externs.h heimdal-0.4d/appl/telnet/telnet/externs.h
--- heimdal-0.4d.orig/appl/telnet/telnet/externs.h	Fri Jul  6 17:39:25 2001
+++ heimdal-0.4d/appl/telnet/telnet/externs.h	Sun Aug 26 22:02:52 2001
@@ -66,6 +66,7 @@
     localchars,		/* we recognize interrupt/quit */
     donelclchars,	/* the user has set "localchars" */
     showoptions,
+    wantencryption,	/* User has requested encryption */
     net,		/* Network file descriptor */
     tin,		/* Terminal input file descriptor */
     tout,		/* Terminal output file descriptor */
@@ -80,6 +81,8 @@
     prettydump,		/* Print "netdata" output in user readable format */
     termdata,		/* Print out terminal data flow */
     debug;		/* Debug level */
+
+extern int intr_happened, intr_waiting;	/* for interrupt handling */
 
 extern cc_t escape;	/* Escape to command mode */
 extern cc_t rlogin;	/* Rlogin mode escape character */
diff -ur heimdal-0.4d.orig/appl/telnet/telnet/main.c heimdal-0.4d/appl/telnet/telnet/main.c
--- heimdal-0.4d.orig/appl/telnet/telnet/main.c	Mon Jun 18 21:52:22 2001
+++ heimdal-0.4d/appl/telnet/telnet/main.c	Sun Aug 26 22:02:20 2001
@@ -126,6 +126,7 @@
         "libdefaults", "encrypt", NULL)) {
           encrypt_auto(1);
           decrypt_auto(1); 
+	  wantencryption = 1;
           EncryptVerbose(1);
         }
 #endif
@@ -292,6 +293,7 @@
 #ifdef	ENCRYPTION
 			encrypt_auto(1);
 			decrypt_auto(1);
+			wantencryption = 1;
 			EncryptVerbose(1);
 #else
 			fprintf(stderr,
diff -ur heimdal-0.4d.orig/appl/telnet/telnet/sys_bsd.c heimdal-0.4d/appl/telnet/telnet/sys_bsd.c
--- heimdal-0.4d.orig/appl/telnet/telnet/sys_bsd.c	Tue Mar  6 21:10:14 2001
+++ heimdal-0.4d/appl/telnet/telnet/sys_bsd.c	Sun Aug 26 22:04:29 2001
@@ -652,10 +652,17 @@
 	longjmp(peerdied, -1);
 }
 
+int intr_happened = 0;
+int intr_waiting = 0;
+
     /* ARGSUSED */
 static RETSIGTYPE
 intr(int sig)
 {
+    if (intr_waiting) {
+	intr_happened = 1;
+	return;
+    }
     if (localchars) {
 	intp();
 	return;
diff -ur heimdal-0.4d.orig/appl/telnet/telnet/telnet.1 heimdal-0.4d/appl/telnet/telnet/telnet.1
--- heimdal-0.4d.orig/appl/telnet/telnet/telnet.1	Fri May 11 10:23:40 2001
+++ heimdal-0.4d/appl/telnet/telnet/telnet.1	Sun Aug 26 22:26:14 2001
@@ -177,8 +177,10 @@
 mode, the escape character is set to the tilde (~) character,
 unless modified by the -e option.
 .It Fl x
-Turns on encryption of the data stream if possible. This is 
-currently the default and when it fails a warning is issued.
+Turn on encryption of the data stream.  When this option is turned on,
+.B telnet
+will exit with an error if authentication cannot be negotiated or if
+encryption cannot be turned on.
 .It Ar host
 Indicates the official name, an alias, or the Internet address
 of a remote host.
diff -ur heimdal-0.4d.orig/appl/telnet/telnet/telnet.c heimdal-0.4d/appl/telnet/telnet/telnet.c
--- heimdal-0.4d.orig/appl/telnet/telnet/telnet.c	Wed Nov  8 18:32:43 2000
+++ heimdal-0.4d/appl/telnet/telnet/telnet.c	Sun Aug 26 22:15:00 2001
@@ -70,6 +70,7 @@
 	netdata,	/* Print out network data flow */
 	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
 	telnetport,
+        wantencryption = 0,
 	SYNCHing,	/* we are in TELNET SYNCH mode */
 	flushout,	/* flush output */
 	autoflush = 0,	/* flush output when interrupting? */
@@ -84,6 +85,8 @@
 
 char *prompt = 0;
 
+int scheduler_lockout_tty = 0;
+
 cc_t escape;
 cc_t rlogin;
 #ifdef	KLUDGELINEMODE
@@ -1957,7 +1960,7 @@
  */
 
 
-static int
+    int
 Scheduler(int block) /* should we block in the select ? */
 {
 		/* One wants to be a bit careful about setting returnValue
@@ -1988,6 +1991,10 @@
 
     /* If we have seen a signal recently, reset things */
 
+    if (scheduler_lockout_tty) {
+        ttyin = ttyout = 0;
+    }
+
     /* Call to system code to process rings */
 
     returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
@@ -2010,6 +2017,8 @@
 void
 my_telnet(char *user)
 {
+    int printed_encrypt = 0;
+    
     sys_telnet_init();
 
 #if	defined(AUTHENTICATION) || defined(ENCRYPTION)
@@ -2047,6 +2056,64 @@
 	if (binary)
 	    tel_enter_binary(binary);
     }
+
+#ifdef ENCRYPTION
+    /*
+     * Note: we assume a tie to the authentication option here.  This
+     * is necessary so that authentication fails, we don't spin
+     * forever. 
+     */
+    if (wantencryption) {
+	extern int auth_has_failed;
+	time_t timeout = time(0) + 60;
+
+	send_do(TELOPT_ENCRYPT, 1);
+	send_will(TELOPT_ENCRYPT, 1);
+	while (1) {
+	    if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
+		printf("\nServer refused to negotiate authentication, which is required\n");
+		printf("for encryption.  Good bye.\n\r");
+		Exit(1);
+	    }
+	    if (auth_has_failed) {
+		printf("\nAuthentication negotation has failed, which is required for\n");
+		printf("encryption.  Good bye.\n\r");
+		Exit(1);
+	    }
+	    if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
+		my_want_state_is_wont(TELOPT_ENCRYPT)) {
+		printf("\nServer refused to negotiate encryption.  Good bye.\n\r");
+		Exit(1);
+	    }
+	    if (encrypt_is_encrypting())
+		break;
+	    if (time(0) > timeout) {
+		printf("\nEncryption could not be enabled.  Goodbye.\n\r");
+		Exit(1);
+	    }
+	    if (printed_encrypt == 0) {
+		    printed_encrypt = 1;
+		    printf("Waiting for encryption to be negotiated...\n");
+		    /*
+		     * Turn on MODE_TRAPSIG and then turn off localchars 
+		     * so that ^C will cause telnet to exit.
+		     */
+		    TerminalNewMode(getconnmode()|MODE_TRAPSIG);
+		    intr_waiting = 1;
+	    }
+	    if (intr_happened) {
+		    printf("\nUser requested an interrupt.  Goodbye.\n\r");
+		    Exit(1);
+	    }
+	    telnet_spin();
+	}
+	if (printed_encrypt) {
+		printf("done.\n");
+		intr_waiting = 0;
+		setconnmode(0);
+	}
+    }
+#endif
 
     for (;;) {
 	int schedValue;

