338 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			338 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
| /*
 | |
|  * TNET		A server program for MINIX which implements the TCP/IP
 | |
|  *		suite of networking protocols.  It is based on the
 | |
|  *		TCP/IP code written by Phil Karn et al, as found in
 | |
|  *		his NET package for Packet Radio communications.
 | |
|  *
 | |
|  *		This module handles telnet option processing.
 | |
|  *
 | |
|  * Author:	Michael Temari, <temari@temari.ae.ge.com>  01/13/93
 | |
|  *
 | |
|  */
 | |
| #include <sys/types.h>
 | |
| #include <string.h>
 | |
| #include <fcntl.h>
 | |
| #include <errno.h>
 | |
| #include <unistd.h>
 | |
| #include <termios.h>
 | |
| #include "telnetd.h"
 | |
| #include "telnet.h"
 | |
| #include <stdio.h>
 | |
| #include <sys/ioctl.h>
 | |
| 
 | |
| 
 | |
| #define	IN_DATA	0
 | |
| #define	IN_CR	1
 | |
| #define	IN_IAC	2
 | |
| #define	IN_IAC2	3
 | |
| #define IN_SB	4
 | |
| 
 | |
| _PROTOTYPE(static void dowill, (int c));
 | |
| _PROTOTYPE(static void dowont, (int c));
 | |
| _PROTOTYPE(static void dodo, (int c));
 | |
| _PROTOTYPE(static void dodont, (int c));
 | |
| _PROTOTYPE(static void respond, (int ack, int option));
 | |
| _PROTOTYPE(static void respond_really, (int ack, int option));
 | |
| 
 | |
| #define	LASTTELOPT	TELOPT_SGA
 | |
| 
 | |
| static int r_winch = 0;
 | |
| 
 | |
| static int TelROpts[LASTTELOPT+1];
 | |
| static int TelLOpts[LASTTELOPT+1];
 | |
| 
 | |
| static int telfdout;
 | |
| 
 | |
| void tel_init()
 | |
| {
 | |
| int i;
 | |
| 
 | |
|    for(i = 0; i <= LASTTELOPT; i++) {
 | |
| 	TelROpts[i] = 0;
 | |
| 	TelLOpts[i] = 0;
 | |
|    }
 | |
| }
 | |
| 
 | |
| void telopt(fdout, what, option)
 | |
| int fdout;
 | |
| int what;
 | |
| int option;
 | |
| {
 | |
| char buf[3];
 | |
| int len;
 | |
| 
 | |
|    buf[0] = IAC;
 | |
|    buf[1] = what;
 | |
|    buf[2] = option;
 | |
|    len = 0;
 | |
| 
 | |
|    switch(what) {
 | |
| 	case DO:
 | |
| 		if(option <= LASTTELOPT) {
 | |
| 			TelROpts[option] = 1;
 | |
| 			len = 3;
 | |
| 		} else if(option == TELOPT_WINCH && !r_winch) { r_winch = 1; len = 3; } 
 | |
| 		break;
 | |
| 	case DONT:
 | |
| 		if(option <= LASTTELOPT) {
 | |
| 			TelROpts[option] = 1;
 | |
| 			len = 3;
 | |
| 		}
 | |
| 		break;
 | |
| 	case WILL:
 | |
| 		if(option <= LASTTELOPT) {
 | |
| 			TelLOpts[option] = 1;
 | |
| 			len = 3;
 | |
| 		}
 | |
| 		break;
 | |
| 	case WONT:
 | |
| 		if(option <= LASTTELOPT) {
 | |
| 			TelLOpts[option] = 1;
 | |
| 			len = 3;
 | |
| 		}
 | |
| 		break;
 | |
|    }
 | |
|    if(len > 0)
 | |
| 	(void) write(fdout, buf, len);
 | |
| }
 | |
| 
 | |
| int set_winsize(int fd, unsigned int cols, unsigned int rows)
 | |
| {
 | |
| 	struct winsize w;
 | |
| 	memset(&w, 0, sizeof(w));
 | |
| 	w.ws_col = cols;
 | |
| 	w.ws_row = rows;
 | |
| 	ioctl(fd, TIOCSWINSZ, (char *) &w);
 | |
| }
 | |
| 
 | |
| int tel_in(fdout, telout, buffer, len)
 | |
| int fdout;
 | |
| int telout;
 | |
| char *buffer;
 | |
| int len;
 | |
| {
 | |
| static int InState = IN_DATA;
 | |
| static int ThisOpt = 0;
 | |
| char *p;
 | |
| char *p2;
 | |
| int size;
 | |
| int c;
 | |
| 
 | |
|    telfdout = telout;
 | |
|    p = p2 = buffer;
 | |
|    size = 0;
 | |
| 
 | |
|    while(len > 0) {
 | |
|    	c = (unsigned char)*p++; len--;
 | |
| 	switch(InState) {
 | |
|    		case IN_CR:
 | |
|    			InState = IN_DATA;
 | |
|    			if(c == 0 || c == '\n')
 | |
|    				break;
 | |
|    			/* fall through */
 | |
|    		case IN_DATA:
 | |
|    			if(c == IAC) {
 | |
|    				InState = IN_IAC;
 | |
|    				break;
 | |
|    			}
 | |
|    			*p2++ = c; size++;
 | |
|    			if(c == '\r') InState = IN_CR;
 | |
|    			break;
 | |
|    		case IN_IAC:
 | |
|    			switch(c) {
 | |
|    				case IAC:
 | |
| 	   				*p2++ = c; size++;
 | |
|    					InState = IN_DATA;
 | |
|    					break;
 | |
|    				case WILL:
 | |
|    				case WONT:
 | |
|    				case DO:
 | |
|    				case DONT:
 | |
|    					InState = IN_IAC2;
 | |
|    					ThisOpt = c;
 | |
|    					break;
 | |
|    				case SB:
 | |
|    				 	InState = IN_SB; 
 | |
|    					break;
 | |
|    				case EOR:
 | |
|    				case SE:
 | |
|    				case NOP:
 | |
|    				case BREAK:
 | |
|    				case IP:
 | |
|    				case AO:
 | |
|    				case AYT:
 | |
|    				case EC:
 | |
|    				case EL:
 | |
|    				case GA:
 | |
|    					break;
 | |
|    				default:
 | |
|    					break;
 | |
|    			}
 | |
|    			break;
 | |
|    		case IN_IAC2:
 | |
|    			if(size > 0) {
 | |
|    				write(fdout, buffer, size);
 | |
|    				p2 = buffer;
 | |
|    				size = 0;
 | |
|    			}
 | |
|    			InState = IN_DATA;
 | |
|    			switch(ThisOpt) {
 | |
|    				case WILL:	dowill(c);	break;
 | |
|    				case WONT:	dowont(c);	break;
 | |
|    				case DO:	dodo(c);	break;
 | |
|    				case DONT:	dodont(c);	break;
 | |
|    			}
 | |
|    			break;
 | |
|    		case IN_SB:
 | |
|  		{
 | |
| 			static int winchpos = -1;
 | |
|    			/* Subnegotiation. */
 | |
|    			if(winchpos >= 0) {
 | |
| 				static unsigned int winchbuf[5], iacs = 0;
 | |
|    				winchbuf[winchpos] = c;
 | |
|    				/* IAC is escaped - unescape it. */
 | |
|    				if(c == IAC) iacs++; else { iacs = 0; winchpos++; }
 | |
|    				if(iacs == 2) { winchpos++; iacs = 0; }
 | |
|    				if(winchpos >= 4) {
 | |
|    					/* End of WINCH data. */
 | |
|    					set_winsize(fdout,
 | |
|    					(winchbuf[0] << 8) | winchbuf[1],
 | |
|    					(winchbuf[2] << 8) | winchbuf[3]);
 | |
|    					winchpos = -1;
 | |
|    				}
 | |
|    			} else {
 | |
| 				static int lastiac = 0;
 | |
| 	   			switch(c) {
 | |
|    					case TELOPT_WINCH:
 | |
|    						/* Start listening. */
 | |
|    						winchpos = 0;
 | |
|    						break;
 | |
|    					case SE:
 | |
|    						if(lastiac) InState = IN_DATA;
 | |
|    						break;
 | |
|    					default:
 | |
|    						break;
 | |
|    				}
 | |
|    				if(c == IAC) lastiac = 1;
 | |
|    				else lastiac = 0;
 | |
| 
 | |
| 
 | |
|    			}
 | |
|    			break;
 | |
|    		}
 | |
|    	}
 | |
|    }
 | |
| 
 | |
|    if(size > 0)
 | |
|    	write(fdout, buffer, size);
 | |
| }
 | |
| 
 | |
| int tel_out(fdout, buf, size)
 | |
| int fdout;
 | |
| char *buf;
 | |
| int size;
 | |
| {
 | |
| char *p;
 | |
| int got_iac, len;
 | |
| 
 | |
|    p = buf;
 | |
|    while(size > 0) {
 | |
| 	buf = p;
 | |
| 	got_iac = 0;
 | |
| 	if((p = (char *)memchr(buf, IAC, size)) != (char *)NULL) {
 | |
| 		got_iac = 1;
 | |
| 		p++;
 | |
| 	} else
 | |
| 		p = buf + size;
 | |
| 	len = p - buf;
 | |
| 	if(len > 0)
 | |
| 		(void) write(fdout, buf, len);
 | |
| 	if(got_iac)
 | |
| 		(void) write(fdout, p - 1, 1);
 | |
| 	size = size - len;
 | |
|    }
 | |
| }
 | |
| 
 | |
| static void dowill(c)
 | |
| int c;
 | |
| {
 | |
| int ack;
 | |
| 
 | |
|    switch(c) {
 | |
| 	case TELOPT_BINARY:
 | |
| 	case TELOPT_ECHO:
 | |
| 	case TELOPT_SGA:
 | |
| 		if(TelROpts[c] == 1)
 | |
| 			return;
 | |
| 		TelROpts[c] = 1;
 | |
| 		ack = DO;
 | |
| 		break;
 | |
| 	case TELOPT_WINCH:
 | |
| 		if(r_winch) return;
 | |
| 		r_winch = 1;
 | |
| 		ack = DO;
 | |
|  		respond_really(ack, c); 
 | |
| 		return;
 | |
| 	default:
 | |
| 		ack = DONT;
 | |
|    }
 | |
| 
 | |
|    respond(ack, c);
 | |
| }
 | |
| 
 | |
| static void dowont(c)
 | |
| int c;
 | |
| {
 | |
|    if(c <= LASTTELOPT) {
 | |
| 	if(TelROpts[c] == 0)
 | |
| 		return;
 | |
| 	TelROpts[c] = 0;
 | |
|    }
 | |
|    respond(DONT, c);
 | |
| }
 | |
| 
 | |
| static void dodo(c)
 | |
| int c;
 | |
| {
 | |
| int ack;
 | |
| 
 | |
|    switch(c) {
 | |
| 	default:
 | |
| 		ack = WONT;
 | |
|    }
 | |
|    respond(ack, c);
 | |
| }
 | |
| 
 | |
| static void dodont(c)
 | |
| int c;
 | |
| {
 | |
|    if(c <= LASTTELOPT) {
 | |
| 	if(TelLOpts[c] == 0)
 | |
| 		return;
 | |
| 	TelLOpts[c] = 0;
 | |
|    }
 | |
|    respond(WONT, c);
 | |
| }
 | |
| 
 | |
| static void respond(ack, option)
 | |
| int ack, option;
 | |
| {
 | |
| unsigned char c[3];
 | |
| 
 | |
|    c[0] = IAC;
 | |
|    c[1] = ack;
 | |
|    c[2] = option;
 | |
| /*   write(telfdout, c, 3); */
 | |
| }
 | |
| 
 | |
| static void respond_really(ack, option)
 | |
| int ack, option;
 | |
| {
 | |
| unsigned char c[3];
 | |
| 
 | |
|    c[0] = IAC;
 | |
|    c[1] = ack;
 | |
|    c[2] = option;
 | |
|    write(telfdout, c, 3); 
 | |
| }
 | 
