From: qpliu@phoenix.princeton.edu (q.p.liu)
Subject: ka9q telunix (incoming telnet server) patches
Originator: news@nimaster
Keywords: ka9q, telunix, telnet
Reply-To: qpliu@princeton.edu
Organization: Princeton University
Date: Tue, 18 Aug 1992 07:52:32 GMT


These are some minor patches to ka9q that will provide the minimal
incoming telnet (telunix server) capability for those who want it
now.  THE SECURITY CONSCIOUS SHOULD READ THE CAVEATS.

First, if it gets EAGAIN from reading the pty, it won't shut down
the connection.

Second, it acknowledges DO ECHO and DO SGA with WILL.  (Don't know what
SGA is, it's required for character mode.  Ask a telnetd wizard.)

Third, it initially sends WILL ECHO and DONT ECHO.  (And a few other
things, just in case.)

Fourth, it sets the pty to -icanon.

Fifth, it does cr-nl and cr-nul to cr conversion.

Sixth, it responds to AYT (as part of learning how telnetd works.)

Limitations and caveats:
It assumes that there is already a process connected to the other end of
the pty.  (A more complete server would fork a login on a connection, and
close the connection when it dies, and kill it when the connection dies,
and clean up utmp and ... be a real telnetd.)  I have init putting a getty
there.  This means connecting/disconnecting does not affect anything on
the other end of the pty.  If the connection shuts down in the shell, the
next connection will resume in the shell.  THE SECURITY CONSCIOUS SHOULD
BE AWARE OF THIS.

Opening a pty that is already open doesn't seem to give an error, (at least
with 0.95c, this may not be a problem with later versions of the kernel.)
This means all incoming telnets get connected to the same pty.  There is
probably a simple fix, but a simpler hack is to limit the number of telnet
clients to 1 (the current default is 3.)  AGAIN, THE SECURITY CONSCIOUS
SHOULD BE AWARE OF THIS.

qpliu@princeton.edu

-cut here-
*** sys5_io.c.orig	Mon Aug 17 00:59:18 1992
--- sys5_io.c	Mon Aug 17 01:11:42 1992
***************
*** 486,491 ****
--- 486,492 ----
  	extern int	errno;
  	int		pty;
  	int		letcnt=0, numcnt=0;
+ 	struct termio	tio;
  
  	static char	*letters = "pqrs",
  			*numbers = "0123456789abcdef";
***************
*** 512,517 ****
--- 513,522 ----
  			numcnt = 0;
  		} 
  	} while ((pty=open(master, O_RDWR | O_NDELAY)) < 0);
+ 
+ 	ioctl (pty, TCGETA, &tio);
+ 	tio.c_lflag &= ~(ICANON);
+ 	ioctl (pty, TCSETA, &tio);
  
  	return(pty);
  }
*** telnet.c.orig	Sun Aug 16 20:53:16 1992
--- telnet.c	Sun Aug 16 23:55:55 1992
***************
*** 622,627 ****
--- 622,639 ----
  		tel_setterm(tn);  /* enable flow */
  		ack = WILL;
  		break;
+ 	case TN_ECHO:
+ 		if(tn->local[uchar(opt)] == 1)
+ 			return;		/* Already set, ignore to prevent loop */
+ 		tn->local[uchar(opt)] = 1;
+ 		ack = WILL;
+ 		break;
+ 	case TN_SUPPRESS_GA:
+ 		if(tn->local[uchar(opt)] == 1)
+ 			return;		/* Already set, ignore to prevent loop */
+ 		tn->local[uchar(opt)] = 1;
+ 		ack = WILL;
+ 		break;
  	default:
  		ack = WONT;	/* Don't know what it is */
  	}
*** telnet.h.orig	Sun Aug 16 23:38:34 1992
--- telnet.h	Sun Aug 16 23:38:43 1992
***************
*** 7,12 ****
--- 7,13 ----
  #define	WONT		252
  #define	DO		253
  #define	DONT		254
+ #define	AYT		246
  #define	TN_DM		242		/* data mark--for connect. cleaning */
  #define	SB		250		/* interpret as subnegotiation */
  #define	SE		240		/* end sub negotiation */
***************
*** 35,40 ****
--- 36,42 ----
  #define	TS_DONT	5	/* Received IAC-DONT */
  #define	TS_SB	7		/* sub-option collection */
  #define	TS_SE	8		/* looking for sub-option end */
+ #define	TS_CR	9		/* stripping out nul with cr-nul */
  
  #define SUBBUFSIZE 64
  
*** telunix.c.orig	Sun Aug 16 17:58:43 1992
--- telunix.c	Mon Aug 17 01:20:38 1992
***************
*** 1,4 ****
--- 1,5 ----
  #include <stdio.h>
+ #include <errno.h>
  #include "global.h"
  #include "config.h"
  #include "mbuf.h"
***************
*** 102,107 ****
--- 103,117 ----
  		selmask |= (1 << tn->fd);
  #endif
  		log(tcb,"open Telunix - (%d %x %d %d)",tn->fd,tcb,old,new);
+ 
+ 		{
+ 			char data[] = { IAC, WILL, TN_ECHO, IAC, WILL,
+ 				TN_SUPPRESS_GA, IAC, WILL, TN_TRANSMIT_BINARY,
+ 				IAC, WILL, TN_STATUS, IAC, DO, TN_LFLOW, IAC,
+ 				DONT, ECHO};
+ 			send_tcp (tcb, qdata (data, 18));
+ 		}
+ 
  		break;
  
  	case FINWAIT1:
***************
*** 199,204 ****
--- 209,215 ----
  		if(tn->outbuf->cnt < TURQSIZ) {
  			if((i = read(tn->fd, tn->outbuf->data + tn->outbuf->cnt,
  				(int)(TURQSIZ - tn->outbuf->cnt))) == -1) {
+ 				if (errno == EAGAIN) return;
  				log(tcb,"error Telunix - read (%d %d %d)",
  					errno, tn->fd,
  					TURQSIZ - tn->outbuf->cnt);
***************
*** 240,246 ****
  	/* Optimization for very common special case -- no special chars */
  	if(tn->state == TS_DATA){
  		while(bp != NULLBUF &&
! 		      memchr(bp->data,IAC,(int)bp->cnt) == NULLCHAR) {
  			if((i = write(tn->fd, bp->data, (int)bp->cnt)) == bp->cnt) {
  				tn->inbuf = bp = free_mbuf(bp);
  			} else if(i == -1) {
--- 251,258 ----
  	/* Optimization for very common special case -- no special chars */
  	if(tn->state == TS_DATA){
  		while(bp != NULLBUF &&
! 		      memchr(bp->data,IAC,(int)bp->cnt) == NULLCHAR &&
! 		      memchr(bp->data,'\r',(int)bp->cnt) == NULLCHAR) {
  			if((i = write(tn->fd, bp->data, (int)bp->cnt)) == bp->cnt) {
  				tn->inbuf = bp = free_mbuf(bp);
  			} else if(i == -1) {
***************
*** 260,268 ****
--- 272,290 ----
  	while(pullup(&(tn->inbuf),&c,1) == 1){
  		bp = tn->inbuf;
  		switch(tn->state){
+ 		case TS_CR:
+ 			tn->state = TS_DATA;
+ 			/* strip from cr-nl and cr-nul */
+ 			if (c == 0 || c == '\n') break;
  		case TS_DATA:
  			if(uchar(c) == IAC){
  				tn->state = TS_IAC;
+ 			} else if (uchar (c) == '\r') {
+ 				tn->state = TS_CR;
+ 				if(write(tn->fd, &c, 1) != 1) {
+ 					/* we drop a character here */
+ 					return;
+ 				}
  			} else {
  				if(!tn->remote[TN_TRANSMIT_BINARY])
  					c &= 0x7f;
***************
*** 285,290 ****
--- 307,316 ----
  				break;
  			case DONT:
  				tn->state = TS_DONT;
+ 				break;
+ 			case AYT:
+ 				tn->state = TS_DATA;
+ 				sndmsg (tn->tcb,"\r\n[Um...Yeah!]\r\n");
  				break;
  			case IAC:
  				if(write(tn->fd, &c, 1) != 1) {
-- 
qpliu@princeton.edu           Standard opinion: Opinions are delta-correlated.