diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 1997-03-27 03:07:27 +0000 | 
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 1997-03-27 03:07:27 +0000 | 
| commit | 1784d64eb85eb63599204bb31b826970b6661e65 (patch) | |
| tree | 31089dd6c9e4a7feeac25f24574e6269b75f5db0 /eBones/libexec/telnetd/state.c | |
| parent | fe49c1266233ddc2306072aefb4e1c1d045060fe (diff) | |
Diffstat (limited to 'eBones/libexec/telnetd/state.c')
| -rw-r--r-- | eBones/libexec/telnetd/state.c | 1615 | 
1 files changed, 0 insertions, 1615 deletions
| diff --git a/eBones/libexec/telnetd/state.c b/eBones/libexec/telnetd/state.c deleted file mode 100644 index faf4088b537f..000000000000 --- a/eBones/libexec/telnetd/state.c +++ /dev/null @@ -1,1615 +0,0 @@ -/* - * Copyright (c) 1989, 1993 - *	The Regents of the University of California.  All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - *    notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - *    notice, this list of conditions and the following disclaimer in the - *    documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - *    must display the following acknowledgement: - *	This product includes software developed by the University of - *	California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - *    may be used to endorse or promote products derived from this software - *    without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -static const char sccsid[] = "@(#)state.c	8.5 (Berkeley) 5/30/95"; -#endif /* not lint */ - -#include "telnetd.h" -#if	defined(AUTHENTICATION) -#include <libtelnet/auth.h> -#endif -#if	defined(ENCRYPTION) -#include <libtelnet/encrypt.h> -#endif - -unsigned char	doopt[] = { IAC, DO, '%', 'c', 0 }; -unsigned char	dont[] = { IAC, DONT, '%', 'c', 0 }; -unsigned char	will[] = { IAC, WILL, '%', 'c', 0 }; -unsigned char	wont[] = { IAC, WONT, '%', 'c', 0 }; -int	not42 = 1; - -/* - * Buffer for sub-options, and macros - * for suboptions buffer manipulations - */ -unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer; - -#define	SB_CLEAR()	subpointer = subbuffer -#define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); } -#define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \ -				*subpointer++ = (c); \ -			} -#define	SB_GET()	((*subpointer++)&0xff) -#define	SB_EOF()	(subpointer >= subend) -#define	SB_LEN()	(subend - subpointer) - -#ifdef	ENV_HACK -unsigned char *subsave; -#define SB_SAVE()	subsave = subpointer; -#define	SB_RESTORE()	subpointer = subsave; -#endif - - -/* - * State for recv fsm - */ -#define	TS_DATA		0	/* base state */ -#define	TS_IAC		1	/* look for double IAC's */ -#define	TS_CR		2	/* CR-LF ->'s CR */ -#define	TS_SB		3	/* throw away begin's... */ -#define	TS_SE		4	/* ...end's (suboption negotiation) */ -#define	TS_WILL		5	/* will option negotiation */ -#define	TS_WONT		6	/* wont " */ -#define	TS_DO		7	/* do " */ -#define	TS_DONT		8	/* dont " */ - -	void -telrcv() -{ -	register int c; -	static int state = TS_DATA; -#if	defined(CRAY2) && defined(UNICOS5) -	char *opfrontp = pfrontp; -#endif - -	while (ncc > 0) { -		if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) -			break; -		c = *netip++ & 0377, ncc--; -#ifdef	ENCRYPTION -		if (decrypt_input) -			c = (*decrypt_input)(c); -#endif	/* ENCRYPTION */ -		switch (state) { - -		case TS_CR: -			state = TS_DATA; -			/* Strip off \n or \0 after a \r */ -			if ((c == 0) || (c == '\n')) { -				break; -			} -			/* FALL THROUGH */ - -		case TS_DATA: -			if (c == IAC) { -				state = TS_IAC; -				break; -			} -			/* -			 * We now map \r\n ==> \r for pragmatic reasons. -			 * Many client implementations send \r\n when -			 * the user hits the CarriageReturn key. -			 * -			 * We USED to map \r\n ==> \n, since \r\n says -			 * that we want to be in column 1 of the next -			 * printable line, and \n is the standard -			 * unix way of saying that (\r is only good -			 * if CRMOD is set, which it normally is). -			 */ -			if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) { -				int nc = *netip; -#ifdef	ENCRYPTION -				if (decrypt_input) -					nc = (*decrypt_input)(nc & 0xff); -#endif	/* ENCRYPTION */ -#ifdef	LINEMODE -				/* -				 * If we are operating in linemode, -				 * convert to local end-of-line. -				 */ -				if (linemode && (ncc > 0) && (('\n' == nc) || -					 ((0 == nc) && tty_iscrnl())) ) { -					netip++; ncc--; -					c = '\n'; -				} else -#endif -				{ -#ifdef	ENCRYPTION -					if (decrypt_input) -						(void)(*decrypt_input)(-1); -#endif	/* ENCRYPTION */ -					state = TS_CR; -				} -			} -			*pfrontp++ = c; -			break; - -		case TS_IAC: -gotiac:			switch (c) { - -			/* -			 * Send the process on the pty side an -			 * interrupt.  Do this with a NULL or -			 * interrupt char; depending on the tty mode. -			 */ -			case IP: -				DIAG(TD_OPTIONS, -					printoption("td: recv IAC", c)); -				interrupt(); -				break; - -			case BREAK: -				DIAG(TD_OPTIONS, -					printoption("td: recv IAC", c)); -				sendbrk(); -				break; - -			/* -			 * Are You There? -			 */ -			case AYT: -				DIAG(TD_OPTIONS, -					printoption("td: recv IAC", c)); -				recv_ayt(); -				break; - -			/* -			 * Abort Output -			 */ -			case AO: -			    { -				DIAG(TD_OPTIONS, -					printoption("td: recv IAC", c)); -				ptyflush();	/* half-hearted */ -				init_termbuf(); - -				if (slctab[SLC_AO].sptr && -				    *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) { -				    *pfrontp++ = -					(unsigned char)*slctab[SLC_AO].sptr; -				} - -				netclear();	/* clear buffer back */ -				*nfrontp++ = IAC; -				*nfrontp++ = DM; -				neturg = nfrontp-1; /* off by one XXX */ -				DIAG(TD_OPTIONS, -					printoption("td: send IAC", DM)); -				break; -			    } - -			/* -			 * Erase Character and -			 * Erase Line -			 */ -			case EC: -			case EL: -			    { -				cc_t ch; - -				DIAG(TD_OPTIONS, -					printoption("td: recv IAC", c)); -				ptyflush();	/* half-hearted */ -				init_termbuf(); -				if (c == EC) -					ch = *slctab[SLC_EC].sptr; -				else -					ch = *slctab[SLC_EL].sptr; -				if (ch != (cc_t)(_POSIX_VDISABLE)) -					*pfrontp++ = (unsigned char)ch; -				break; -			    } - -			/* -			 * Check for urgent data... -			 */ -			case DM: -				DIAG(TD_OPTIONS, -					printoption("td: recv IAC", c)); -				SYNCHing = stilloob(net); -				settimer(gotDM); -				break; - - -			/* -			 * Begin option subnegotiation... -			 */ -			case SB: -				state = TS_SB; -				SB_CLEAR(); -				continue; - -			case WILL: -				state = TS_WILL; -				continue; - -			case WONT: -				state = TS_WONT; -				continue; - -			case DO: -				state = TS_DO; -				continue; - -			case DONT: -				state = TS_DONT; -				continue; -			case EOR: -				if (his_state_is_will(TELOPT_EOR)) -					doeof(); -				break; - -			/* -			 * Handle RFC 10xx Telnet linemode option additions -			 * to command stream (EOF, SUSP, ABORT). -			 */ -			case xEOF: -				doeof(); -				break; - -			case SUSP: -				sendsusp(); -				break; - -			case ABORT: -				sendbrk(); -				break; - -			case IAC: -				*pfrontp++ = c; -				break; -			} -			state = TS_DATA; -			break; - -		case TS_SB: -			if (c == IAC) { -				state = TS_SE; -			} else { -				SB_ACCUM(c); -			} -			break; - -		case TS_SE: -			if (c != SE) { -				if (c != IAC) { -					/* -					 * bad form of suboption negotiation. -					 * handle it in such a way as to avoid -					 * damage to local state.  Parse -					 * suboption buffer found so far, -					 * then treat remaining stream as -					 * another command sequence. -					 */ - -					/* for DIAGNOSTICS */ -					SB_ACCUM(IAC); -					SB_ACCUM(c); -					subpointer -= 2; - -					SB_TERM(); -					suboption(); -					state = TS_IAC; -					goto gotiac; -				} -				SB_ACCUM(c); -				state = TS_SB; -			} else { -				/* for DIAGNOSTICS */ -				SB_ACCUM(IAC); -				SB_ACCUM(SE); -				subpointer -= 2; - -				SB_TERM(); -				suboption();	/* handle sub-option */ -				state = TS_DATA; -			} -			break; - -		case TS_WILL: -			willoption(c); -			state = TS_DATA; -			continue; - -		case TS_WONT: -			wontoption(c); -			state = TS_DATA; -			continue; - -		case TS_DO: -			dooption(c); -			state = TS_DATA; -			continue; - -		case TS_DONT: -			dontoption(c); -			state = TS_DATA; -			continue; - -		default: -			syslog(LOG_ERR, "telnetd: panic state=%d\n", state); -			printf("telnetd: panic state=%d\n", state); -			exit(1); -		} -	} -#if	defined(CRAY2) && defined(UNICOS5) -	if (!linemode) { -		char	xptyobuf[BUFSIZ+NETSLOP]; -		char	xbuf2[BUFSIZ]; -		register char *cp; -		int n = pfrontp - opfrontp, oc; -		memmove(xptyobuf, opfrontp, n); -		pfrontp = opfrontp; -		pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP, -					xbuf2, &oc, BUFSIZ); -		for (cp = xbuf2; oc > 0; --oc) -			if ((*nfrontp++ = *cp++) == IAC) -				*nfrontp++ = IAC; -	} -#endif	/* defined(CRAY2) && defined(UNICOS5) */ -}  /* end of telrcv */ - -/* - * The will/wont/do/dont state machines are based on Dave Borman's - * Telnet option processing state machine. - * - * These correspond to the following states: - *	my_state = the last negotiated state - *	want_state = what I want the state to go to - *	want_resp = how many requests I have sent - * All state defaults are negative, and resp defaults to 0. - * - * When initiating a request to change state to new_state: - * - * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { - *	do nothing; - * } else { - *	want_state = new_state; - *	send new_state; - *	want_resp++; - * } - * - * When receiving new_state: - * - * if (want_resp) { - *	want_resp--; - *	if (want_resp && (new_state == my_state)) - *		want_resp--; - * } - * if ((want_resp == 0) && (new_state != want_state)) { - *	if (ok_to_switch_to new_state) - *		want_state = new_state; - *	else - *		want_resp++; - *	send want_state; - * } - * my_state = new_state; - * - * Note that new_state is implied in these functions by the function itself. - * will and do imply positive new_state, wont and dont imply negative. - * - * Finally, there is one catch.  If we send a negative response to a - * positive request, my_state will be the positive while want_state will - * remain negative.  my_state will revert to negative when the negative - * acknowlegment arrives from the peer.  Thus, my_state generally tells - * us not only the last negotiated state, but also tells us what the peer - * wants to be doing as well.  It is important to understand this difference - * as we may wish to be processing data streams based on our desired state - * (want_state) or based on what the peer thinks the state is (my_state). - * - * This all works fine because if the peer sends a positive request, the data - * that we receive prior to negative acknowlegment will probably be affected - * by the positive state, and we can process it as such (if we can; if we - * can't then it really doesn't matter).  If it is that important, then the - * peer probably should be buffering until this option state negotiation - * is complete. - * - */ -	void -send_do(option, init) -	int option, init; -{ -	if (init) { -		if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || -		    his_want_state_is_will(option)) -			return; -		/* -		 * Special case for TELOPT_TM:  We send a DO, but pretend -		 * that we sent a DONT, so that we can send more DOs if -		 * we want to. -		 */ -		if (option == TELOPT_TM) -			set_his_want_state_wont(option); -		else -			set_his_want_state_will(option); -		do_dont_resp[option]++; -	} -	(void) sprintf(nfrontp, (char *)doopt, option); -	nfrontp += sizeof (dont) - 2; - -	DIAG(TD_OPTIONS, printoption("td: send do", option)); -} - -#ifdef	AUTHENTICATION -extern void auth_request(); -#endif -#ifdef	LINEMODE -extern void doclientstat(); -#endif -#ifdef	ENCRYPTION -extern void encrypt_send_support(); -#endif	/* ENCRYPTION */ - -	void -willoption(option) -	int option; -{ -	int changeok = 0; -	void (*func)() = 0; - -	/* -	 * process input from peer. -	 */ - -	DIAG(TD_OPTIONS, printoption("td: recv will", option)); - -	if (do_dont_resp[option]) { -		do_dont_resp[option]--; -		if (do_dont_resp[option] && his_state_is_will(option)) -			do_dont_resp[option]--; -	} -	if (do_dont_resp[option] == 0) { -	    if (his_want_state_is_wont(option)) { -		switch (option) { - -		case TELOPT_BINARY: -			init_termbuf(); -			tty_binaryin(1); -			set_termbuf(); -			changeok++; -			break; - -		case TELOPT_ECHO: -			/* -			 * See comments below for more info. -			 */ -			not42 = 0;	/* looks like a 4.2 system */ -			break; - -		case TELOPT_TM: -#if	defined(LINEMODE) && defined(KLUDGELINEMODE) -			/* -			 * This telnetd implementation does not really -			 * support timing marks, it just uses them to -			 * support the kludge linemode stuff.  If we -			 * receive a will or wont TM in response to our -			 * do TM request that may have been sent to -			 * determine kludge linemode support, process -			 * it, otherwise TM should get a negative -			 * response back. -			 */ -			/* -			 * Handle the linemode kludge stuff. -			 * If we are not currently supporting any -			 * linemode at all, then we assume that this -			 * is the client telling us to use kludge -			 * linemode in response to our query.  Set the -			 * linemode type that is to be supported, note -			 * that the client wishes to use linemode, and -			 * eat the will TM as though it never arrived. -			 */ -			if (lmodetype < KLUDGE_LINEMODE) { -				lmodetype = KLUDGE_LINEMODE; -				clientstat(TELOPT_LINEMODE, WILL, 0); -				send_wont(TELOPT_SGA, 1); -			} else if (lmodetype == NO_AUTOKLUDGE) { -				lmodetype = KLUDGE_OK; -			} -#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */ -			/* -			 * We never respond to a WILL TM, and -			 * we leave the state WONT. -			 */ -			return; - -		case TELOPT_LFLOW: -			/* -			 * If we are going to support flow control -			 * option, then don't worry peer that we can't -			 * change the flow control characters. -			 */ -			slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; -			slctab[SLC_XON].defset.flag |= SLC_DEFAULT; -			slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; -			slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; -		case TELOPT_TTYPE: -		case TELOPT_SGA: -		case TELOPT_NAWS: -		case TELOPT_TSPEED: -		case TELOPT_XDISPLOC: -		case TELOPT_NEW_ENVIRON: -		case TELOPT_OLD_ENVIRON: -			changeok++; -			break; - -#ifdef	LINEMODE -		case TELOPT_LINEMODE: -# ifdef	KLUDGELINEMODE -			/* -			 * Note client's desire to use linemode. -			 */ -			lmodetype = REAL_LINEMODE; -# endif	/* KLUDGELINEMODE */ -			func = doclientstat; -			changeok++; -			break; -#endif	/* LINEMODE */ - -#ifdef	AUTHENTICATION -		case TELOPT_AUTHENTICATION: -			func = auth_request; -			changeok++; -			break; -#endif - -#ifdef	ENCRYPTION -		case TELOPT_ENCRYPT: -			func = encrypt_send_support; -			changeok++; -			break; -#endif	/* ENCRYPTION */ - -		default: -			break; -		} -		if (changeok) { -			set_his_want_state_will(option); -			send_do(option, 0); -		} else { -			do_dont_resp[option]++; -			send_dont(option, 0); -		} -	    } else { -		/* -		 * Option processing that should happen when -		 * we receive conformation of a change in -		 * state that we had requested. -		 */ -		switch (option) { -		case TELOPT_ECHO: -			not42 = 0;	/* looks like a 4.2 system */ -			/* -			 * Egads, he responded "WILL ECHO".  Turn -			 * it off right now! -			 */ -			send_dont(option, 1); -			/* -			 * "WILL ECHO".  Kludge upon kludge! -			 * A 4.2 client is now echoing user input at -			 * the tty.  This is probably undesireable and -			 * it should be stopped.  The client will -			 * respond WONT TM to the DO TM that we send to -			 * check for kludge linemode.  When the WONT TM -			 * arrives, linemode will be turned off and a -			 * change propogated to the pty.  This change -			 * will cause us to process the new pty state -			 * in localstat(), which will notice that -			 * linemode is off and send a WILL ECHO -			 * so that we are properly in character mode and -			 * all is well. -			 */ -			break; -#ifdef	LINEMODE -		case TELOPT_LINEMODE: -# ifdef	KLUDGELINEMODE -			/* -			 * Note client's desire to use linemode. -			 */ -			lmodetype = REAL_LINEMODE; -# endif	/* KLUDGELINEMODE */ -			func = doclientstat; -			break; -#endif	/* LINEMODE */ - -#ifdef	AUTHENTICATION -		case TELOPT_AUTHENTICATION: -			func = auth_request; -			break; -#endif - -#ifdef	ENCRYPTION -		case TELOPT_ENCRYPT: -			func = encrypt_send_support; -			break; -#endif	/* ENCRYPTION */ -		case TELOPT_LFLOW: -			func = flowstat; -			break; -		} -	    } -	} -	set_his_state_will(option); -	if (func) -		(*func)(); -}  /* end of willoption */ - -	void -send_dont(option, init) -	int option, init; -{ -	if (init) { -		if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || -		    his_want_state_is_wont(option)) -			return; -		set_his_want_state_wont(option); -		do_dont_resp[option]++; -	} -	(void) sprintf(nfrontp, (char *)dont, option); -	nfrontp += sizeof (doopt) - 2; - -	DIAG(TD_OPTIONS, printoption("td: send dont", option)); -} - -	void -wontoption(option) -	int option; -{ -	/* -	 * Process client input. -	 */ - -	DIAG(TD_OPTIONS, printoption("td: recv wont", option)); - -	if (do_dont_resp[option]) { -		do_dont_resp[option]--; -		if (do_dont_resp[option] && his_state_is_wont(option)) -			do_dont_resp[option]--; -	} -	if (do_dont_resp[option] == 0) { -	    if (his_want_state_is_will(option)) { -		/* it is always ok to change to negative state */ -		switch (option) { -		case TELOPT_ECHO: -			not42 = 1; /* doesn't seem to be a 4.2 system */ -			break; - -		case TELOPT_BINARY: -			init_termbuf(); -			tty_binaryin(0); -			set_termbuf(); -			break; - -#ifdef	LINEMODE -		case TELOPT_LINEMODE: -# ifdef	KLUDGELINEMODE -			/* -			 * If real linemode is supported, then client is -			 * asking to turn linemode off. -			 */ -			if (lmodetype != REAL_LINEMODE) -				break; -# endif	/* KLUDGELINEMODE */ -			clientstat(TELOPT_LINEMODE, WONT, 0); -			break; -#endif	/* LINEMODE */ - -		case TELOPT_TM: -			/* -			 * If we get a WONT TM, and had sent a DO TM, -			 * don't respond with a DONT TM, just leave it -			 * as is.  Short circut the state machine to -			 * achive this. -			 */ -			set_his_want_state_wont(TELOPT_TM); -			return; - -		case TELOPT_LFLOW: -			/* -			 * If we are not going to support flow control -			 * option, then let peer know that we can't -			 * change the flow control characters. -			 */ -			slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; -			slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; -			slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; -			slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; -			break; - -#if	defined(AUTHENTICATION) -		case TELOPT_AUTHENTICATION: -			auth_finished(0, AUTH_REJECT); -			break; -#endif - -		/* -		 * For options that we might spin waiting for -		 * sub-negotiation, if the client turns off the -		 * option rather than responding to the request, -		 * we have to treat it here as if we got a response -		 * to the sub-negotiation, (by updating the timers) -		 * so that we'll break out of the loop. -		 */ -		case TELOPT_TTYPE: -			settimer(ttypesubopt); -			break; - -		case TELOPT_TSPEED: -			settimer(tspeedsubopt); -			break; - -		case TELOPT_XDISPLOC: -			settimer(xdisplocsubopt); -			break; - -		case TELOPT_OLD_ENVIRON: -			settimer(oenvironsubopt); -			break; - -		case TELOPT_NEW_ENVIRON: -			settimer(environsubopt); -			break; - -		default: -			break; -		} -		set_his_want_state_wont(option); -		if (his_state_is_will(option)) -			send_dont(option, 0); -	    } else { -		switch (option) { -		case TELOPT_TM: -#if	defined(LINEMODE) && defined(KLUDGELINEMODE) -			if (lmodetype < NO_AUTOKLUDGE) { -				lmodetype = NO_LINEMODE; -				clientstat(TELOPT_LINEMODE, WONT, 0); -				send_will(TELOPT_SGA, 1); -				send_will(TELOPT_ECHO, 1); -			} -#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */ -			break; - -#if	defined(AUTHENTICATION) -		case TELOPT_AUTHENTICATION: -			auth_finished(0, AUTH_REJECT); -			break; -#endif -		default: -			break; -		} -	    } -	} -	set_his_state_wont(option); - -}  /* end of wontoption */ - -	void -send_will(option, init) -	int option, init; -{ -	if (init) { -		if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| -		    my_want_state_is_will(option)) -			return; -		set_my_want_state_will(option); -		will_wont_resp[option]++; -	} -	(void) sprintf(nfrontp, (char *)will, option); -	nfrontp += sizeof (doopt) - 2; - -	DIAG(TD_OPTIONS, printoption("td: send will", option)); -} - -#if	!defined(LINEMODE) || !defined(KLUDGELINEMODE) -/* - * When we get a DONT SGA, we will try once to turn it - * back on.  If the other side responds DONT SGA, we - * leave it at that.  This is so that when we talk to - * clients that understand KLUDGELINEMODE but not LINEMODE, - * we'll keep them in char-at-a-time mode. - */ -int turn_on_sga = 0; -#endif - -	void -dooption(option) -	int option; -{ -	int changeok = 0; - -	/* -	 * Process client input. -	 */ - -	DIAG(TD_OPTIONS, printoption("td: recv do", option)); - -	if (will_wont_resp[option]) { -		will_wont_resp[option]--; -		if (will_wont_resp[option] && my_state_is_will(option)) -			will_wont_resp[option]--; -	} -	if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { -		switch (option) { -		case TELOPT_ECHO: -#ifdef	LINEMODE -# ifdef	KLUDGELINEMODE -			if (lmodetype == NO_LINEMODE) -# else -			if (his_state_is_wont(TELOPT_LINEMODE)) -# endif -#endif -			{ -				init_termbuf(); -				tty_setecho(1); -				set_termbuf(); -			} -			changeok++; -			break; - -		case TELOPT_BINARY: -			init_termbuf(); -			tty_binaryout(1); -			set_termbuf(); -			changeok++; -			break; - -		case TELOPT_SGA: -#if	defined(LINEMODE) && defined(KLUDGELINEMODE) -			/* -			 * If kludge linemode is in use, then we must -			 * process an incoming do SGA for linemode -			 * purposes. -			 */ -			if (lmodetype == KLUDGE_LINEMODE) { -				/* -				 * Receipt of "do SGA" in kludge -				 * linemode is the peer asking us to -				 * turn off linemode.  Make note of -				 * the request. -				 */ -				clientstat(TELOPT_LINEMODE, WONT, 0); -				/* -				 * If linemode did not get turned off -				 * then don't tell peer that we did. -				 * Breaking here forces a wont SGA to -				 * be returned. -				 */ -				if (linemode) -					break; -			} -#else -			turn_on_sga = 0; -#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */ -			changeok++; -			break; - -		case TELOPT_STATUS: -			changeok++; -			break; - -		case TELOPT_TM: -			/* -			 * Special case for TM.  We send a WILL, but -			 * pretend we sent a WONT. -			 */ -			send_will(option, 0); -			set_my_want_state_wont(option); -			set_my_state_wont(option); -			return; - -		case TELOPT_LOGOUT: -			/* -			 * When we get a LOGOUT option, respond -			 * with a WILL LOGOUT, make sure that -			 * it gets written out to the network, -			 * and then just go away... -			 */ -			set_my_want_state_will(TELOPT_LOGOUT); -			send_will(TELOPT_LOGOUT, 0); -			set_my_state_will(TELOPT_LOGOUT); -			(void)netflush(); -			cleanup(0); -			/* NOT REACHED */ -			break; - -#ifdef	ENCRYPTION -		case TELOPT_ENCRYPT: -			changeok++; -			break; -#endif	/* ENCRYPTION */ -		case TELOPT_LINEMODE: -		case TELOPT_TTYPE: -		case TELOPT_NAWS: -		case TELOPT_TSPEED: -		case TELOPT_LFLOW: -		case TELOPT_XDISPLOC: -#ifdef	TELOPT_ENVIRON -		case TELOPT_NEW_ENVIRON: -#endif -		case TELOPT_OLD_ENVIRON: -		default: -			break; -		} -		if (changeok) { -			set_my_want_state_will(option); -			send_will(option, 0); -		} else { -			will_wont_resp[option]++; -			send_wont(option, 0); -		} -	} -	set_my_state_will(option); - -}  /* end of dooption */ - -	void -send_wont(option, init) -	int option, init; -{ -	if (init) { -		if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || -		    my_want_state_is_wont(option)) -			return; -		set_my_want_state_wont(option); -		will_wont_resp[option]++; -	} -	(void) sprintf(nfrontp, (char *)wont, option); -	nfrontp += sizeof (wont) - 2; - -	DIAG(TD_OPTIONS, printoption("td: send wont", option)); -} - -	void -dontoption(option) -	int option; -{ -	/* -	 * Process client input. -	 */ - - -	DIAG(TD_OPTIONS, printoption("td: recv dont", option)); - -	if (will_wont_resp[option]) { -		will_wont_resp[option]--; -		if (will_wont_resp[option] && my_state_is_wont(option)) -			will_wont_resp[option]--; -	} -	if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { -		switch (option) { -		case TELOPT_BINARY: -			init_termbuf(); -			tty_binaryout(0); -			set_termbuf(); -			break; - -		case TELOPT_ECHO:	/* we should stop echoing */ -#ifdef	LINEMODE -# ifdef	KLUDGELINEMODE -			if ((lmodetype != REAL_LINEMODE) && -			    (lmodetype != KLUDGE_LINEMODE)) -# else -			if (his_state_is_wont(TELOPT_LINEMODE)) -# endif -#endif -			{ -				init_termbuf(); -				tty_setecho(0); -				set_termbuf(); -			} -			break; - -		case TELOPT_SGA: -#if	defined(LINEMODE) && defined(KLUDGELINEMODE) -			/* -			 * If kludge linemode is in use, then we -			 * must process an incoming do SGA for -			 * linemode purposes. -			 */ -			if ((lmodetype == KLUDGE_LINEMODE) || -			    (lmodetype == KLUDGE_OK)) { -				/* -				 * The client is asking us to turn -				 * linemode on. -				 */ -				lmodetype = KLUDGE_LINEMODE; -				clientstat(TELOPT_LINEMODE, WILL, 0); -				/* -				 * If we did not turn line mode on, -				 * then what do we say?  Will SGA? -				 * This violates design of telnet. -				 * Gross.  Very Gross. -				 */ -			} -			break; -#else -			set_my_want_state_wont(option); -			if (my_state_is_will(option)) -				send_wont(option, 0); -			set_my_state_wont(option); -			if (turn_on_sga ^= 1) -				send_will(option, 1); -			return; -#endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */ - -		default: -			break; -		} - -		set_my_want_state_wont(option); -		if (my_state_is_will(option)) -			send_wont(option, 0); -	} -	set_my_state_wont(option); - -}  /* end of dontoption */ - -#ifdef	ENV_HACK -int env_ovar = -1; -int env_ovalue = -1; -#else	/* ENV_HACK */ -# define env_ovar OLD_ENV_VAR -# define env_ovalue OLD_ENV_VALUE -#endif	/* ENV_HACK */ - -/* - * suboption() - * - *	Look at the sub-option buffer, and try to be helpful to the other - * side. - * - *	Currently we recognize: - * - *	Terminal type is - *	Linemode - *	Window size - *	Terminal speed - */ -	void -suboption() -{ -    register int subchar; - -    DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); - -    subchar = SB_GET(); -    switch (subchar) { -    case TELOPT_TSPEED: { -	register int xspeed, rspeed; - -	if (his_state_is_wont(TELOPT_TSPEED))	/* Ignore if option disabled */ -		break; - -	settimer(tspeedsubopt); - -	if (SB_EOF() || SB_GET() != TELQUAL_IS) -		return; - -	xspeed = atoi((char *)subpointer); - -	while (SB_GET() != ',' && !SB_EOF()); -	if (SB_EOF()) -		return; - -	rspeed = atoi((char *)subpointer); -	clientstat(TELOPT_TSPEED, xspeed, rspeed); - -	break; - -    }  /* end of case TELOPT_TSPEED */ - -    case TELOPT_TTYPE: {		/* Yaaaay! */ -	static char terminalname[41]; - -	if (his_state_is_wont(TELOPT_TTYPE))	/* Ignore if option disabled */ -		break; -	settimer(ttypesubopt); - -	if (SB_EOF() || SB_GET() != TELQUAL_IS) { -	    return;		/* ??? XXX but, this is the most robust */ -	} - -	terminaltype = terminalname; - -	while ((terminaltype < (terminalname + sizeof terminalname-1)) && -								    !SB_EOF()) { -	    register int c; - -	    c = SB_GET(); -	    if (isupper(c)) { -		c = tolower(c); -	    } -	    *terminaltype++ = c;    /* accumulate name */ -	} -	*terminaltype = 0; -	terminaltype = terminalname; -	break; -    }  /* end of case TELOPT_TTYPE */ - -    case TELOPT_NAWS: { -	register int xwinsize, ywinsize; - -	if (his_state_is_wont(TELOPT_NAWS))	/* Ignore if option disabled */ -		break; - -	if (SB_EOF()) -		return; -	xwinsize = SB_GET() << 8; -	if (SB_EOF()) -		return; -	xwinsize |= SB_GET(); -	if (SB_EOF()) -		return; -	ywinsize = SB_GET() << 8; -	if (SB_EOF()) -		return; -	ywinsize |= SB_GET(); -	clientstat(TELOPT_NAWS, xwinsize, ywinsize); - -	break; - -    }  /* end of case TELOPT_NAWS */ - -#ifdef	LINEMODE -    case TELOPT_LINEMODE: { -	register int request; - -	if (his_state_is_wont(TELOPT_LINEMODE))	/* Ignore if option disabled */ -		break; -	/* -	 * Process linemode suboptions. -	 */ -	if (SB_EOF()) -	    break;		/* garbage was sent */ -	request = SB_GET();	/* get will/wont */ - -	if (SB_EOF()) -	    break;		/* another garbage check */ - -	if (request == LM_SLC) {  /* SLC is not preceeded by WILL or WONT */ -		/* -		 * Process suboption buffer of slc's -		 */ -		start_slc(1); -		do_opt_slc(subpointer, subend - subpointer); -		(void) end_slc(0); -		break; -	} else if (request == LM_MODE) { -		if (SB_EOF()) -		    return; -		useeditmode = SB_GET();  /* get mode flag */ -		clientstat(LM_MODE, 0, 0); -		break; -	} - -	if (SB_EOF()) -	    break; -	switch (SB_GET()) {  /* what suboption? */ -	case LM_FORWARDMASK: -		/* -		 * According to spec, only server can send request for -		 * forwardmask, and client can only return a positive response. -		 * So don't worry about it. -		 */ - -	default: -		break; -	} -	break; -    }  /* end of case TELOPT_LINEMODE */ -#endif -    case TELOPT_STATUS: { -	int mode; - -	if (SB_EOF()) -	    break; -	mode = SB_GET(); -	switch (mode) { -	case TELQUAL_SEND: -	    if (my_state_is_will(TELOPT_STATUS)) -		send_status(); -	    break; - -	case TELQUAL_IS: -	    break; - -	default: -	    break; -	} -	break; -    }  /* end of case TELOPT_STATUS */ - -    case TELOPT_XDISPLOC: { -	if (SB_EOF() || SB_GET() != TELQUAL_IS) -		return; -	settimer(xdisplocsubopt); -	subpointer[SB_LEN()] = '\0'; -	(void)setenv("DISPLAY", (char *)subpointer, 1); -	break; -    }  /* end of case TELOPT_XDISPLOC */ - -#ifdef	TELOPT_NEW_ENVIRON -    case TELOPT_NEW_ENVIRON: -#endif -    case TELOPT_OLD_ENVIRON: { -	register int c; -	register char *cp, *varp, *valp; - -	if (SB_EOF()) -		return; -	c = SB_GET(); -	if (c == TELQUAL_IS) { -		if (subchar == TELOPT_OLD_ENVIRON) -			settimer(oenvironsubopt); -		else -			settimer(environsubopt); -	} else if (c != TELQUAL_INFO) { -		return; -	} - -#ifdef	TELOPT_NEW_ENVIRON -	if (subchar == TELOPT_NEW_ENVIRON) { -	    while (!SB_EOF()) { -		c = SB_GET(); -		if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) -			break; -	    } -	} else -#endif -	{ -#ifdef	ENV_HACK -	    /* -	     * We only want to do this if we haven't already decided -	     * whether or not the other side has its VALUE and VAR -	     * reversed. -	     */ -	    if (env_ovar < 0) { -		register int last = -1;		/* invalid value */ -		int empty = 0; -		int got_var = 0, got_value = 0, got_uservar = 0; - -		/* -		 * The other side might have its VALUE and VAR values -		 * reversed.  To be interoperable, we need to determine -		 * which way it is.  If the first recognized character -		 * is a VAR or VALUE, then that will tell us what -		 * type of client it is.  If the fist recognized -		 * character is a USERVAR, then we continue scanning -		 * the suboption looking for two consecutive -		 * VAR or VALUE fields.  We should not get two -		 * consecutive VALUE fields, so finding two -		 * consecutive VALUE or VAR fields will tell us -		 * what the client is. -		 */ -		SB_SAVE(); -		while (!SB_EOF()) { -			c = SB_GET(); -			switch(c) { -			case OLD_ENV_VAR: -				if (last < 0 || last == OLD_ENV_VAR -				    || (empty && (last == OLD_ENV_VALUE))) -					goto env_ovar_ok; -				got_var++; -				last = OLD_ENV_VAR; -				break; -			case OLD_ENV_VALUE: -				if (last < 0 || last == OLD_ENV_VALUE -				    || (empty && (last == OLD_ENV_VAR))) -					goto env_ovar_wrong; -				got_value++; -				last = OLD_ENV_VALUE; -				break; -			case ENV_USERVAR: -				/* count strings of USERVAR as one */ -				if (last != ENV_USERVAR) -					got_uservar++; -				if (empty) { -					if (last == OLD_ENV_VALUE) -						goto env_ovar_ok; -					if (last == OLD_ENV_VAR) -						goto env_ovar_wrong; -				} -				last = ENV_USERVAR; -				break; -			case ENV_ESC: -				if (!SB_EOF()) -					c = SB_GET(); -				/* FALL THROUGH */ -			default: -				empty = 0; -				continue; -			} -			empty = 1; -		} -		if (empty) { -			if (last == OLD_ENV_VALUE) -				goto env_ovar_ok; -			if (last == OLD_ENV_VAR) -				goto env_ovar_wrong; -		} -		/* -		 * Ok, the first thing was a USERVAR, and there -		 * are not two consecutive VAR or VALUE commands, -		 * and none of the VAR or VALUE commands are empty. -		 * If the client has sent us a well-formed option, -		 * then the number of VALUEs received should always -		 * be less than or equal to the number of VARs and -		 * USERVARs received. -		 * -		 * If we got exactly as many VALUEs as VARs and -		 * USERVARs, the client has the same definitions. -		 * -		 * If we got exactly as many VARs as VALUEs and -		 * USERVARS, the client has reversed definitions. -		 */ -		if (got_uservar + got_var == got_value) { -	    env_ovar_ok: -			env_ovar = OLD_ENV_VAR; -			env_ovalue = OLD_ENV_VALUE; -		} else if (got_uservar + got_value == got_var) { -	    env_ovar_wrong: -			env_ovar = OLD_ENV_VALUE; -			env_ovalue = OLD_ENV_VAR; -			DIAG(TD_OPTIONS, {sprintf(nfrontp, -				"ENVIRON VALUE and VAR are reversed!\r\n"); -				nfrontp += strlen(nfrontp);}); - -		} -	    } -	    SB_RESTORE(); -#endif - -	    while (!SB_EOF()) { -		c = SB_GET(); -		if ((c == env_ovar) || (c == ENV_USERVAR)) -			break; -	    } -	} - -	if (SB_EOF()) -		return; - -	cp = varp = (char *)subpointer; -	valp = 0; - -	while (!SB_EOF()) { -		c = SB_GET(); -		if (subchar == TELOPT_OLD_ENVIRON) { -			if (c == env_ovar) -				c = NEW_ENV_VAR; -			else if (c == env_ovalue) -				c = NEW_ENV_VALUE; -		} -		switch (c) { - -		case NEW_ENV_VALUE: -			*cp = '\0'; -			cp = valp = (char *)subpointer; -			break; - -		case NEW_ENV_VAR: -		case ENV_USERVAR: -			*cp = '\0'; -			if (valp) -				(void)setenv(varp, valp, 1); -			else -				unsetenv(varp); -			cp = varp = (char *)subpointer; -			valp = 0; -			break; - -		case ENV_ESC: -			if (SB_EOF()) -				break; -			c = SB_GET(); -			/* FALL THROUGH */ -		default: -			*cp++ = c; -			break; -		} -	} -	*cp = '\0'; -	if (valp) -		(void)setenv(varp, valp, 1); -	else -		unsetenv(varp); -	break; -    }  /* end of case TELOPT_NEW_ENVIRON */ -#if	defined(AUTHENTICATION) -    case TELOPT_AUTHENTICATION: -	if (SB_EOF()) -		break; -	switch(SB_GET()) { -	case TELQUAL_SEND: -	case TELQUAL_REPLY: -		/* -		 * These are sent by us and cannot be sent by -		 * the client. -		 */ -		break; -	case TELQUAL_IS: -		auth_is(subpointer, SB_LEN()); -		break; -	case TELQUAL_NAME: -		auth_name(subpointer, SB_LEN()); -		break; -	} -	break; -#endif -#ifdef	ENCRYPTION -    case TELOPT_ENCRYPT: -	if (SB_EOF()) -		break; -	switch(SB_GET()) { -	case ENCRYPT_SUPPORT: -		encrypt_support(subpointer, SB_LEN()); -		break; -	case ENCRYPT_IS: -		encrypt_is(subpointer, SB_LEN()); -		break; -	case ENCRYPT_REPLY: -		encrypt_reply(subpointer, SB_LEN()); -		break; -	case ENCRYPT_START: -		encrypt_start(subpointer, SB_LEN()); -		break; -	case ENCRYPT_END: -		encrypt_end(); -		break; -	case ENCRYPT_REQSTART: -		encrypt_request_start(subpointer, SB_LEN()); -		break; -	case ENCRYPT_REQEND: -		/* -		 * We can always send an REQEND so that we cannot -		 * get stuck encrypting.  We should only get this -		 * if we have been able to get in the correct mode -		 * anyhow. -		 */ -		encrypt_request_end(); -		break; -	case ENCRYPT_ENC_KEYID: -		encrypt_enc_keyid(subpointer, SB_LEN()); -		break; -	case ENCRYPT_DEC_KEYID: -		encrypt_dec_keyid(subpointer, SB_LEN()); -		break; -	default: -		break; -	} -	break; -#endif	/* ENCRYPTION */ - -    default: -	break; -    }  /* end of switch */ - -}  /* end of suboption */ - -	void -doclientstat() -{ -	clientstat(TELOPT_LINEMODE, WILL, 0); -} - -#define	ADD(c)	 *ncp++ = c -#define	ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; } -	void -send_status() -{ -	unsigned char statusbuf[256]; -	register unsigned char *ncp; -	register unsigned char i; - -	ncp = statusbuf; - -	netflush();	/* get rid of anything waiting to go out */ - -	ADD(IAC); -	ADD(SB); -	ADD(TELOPT_STATUS); -	ADD(TELQUAL_IS); - -	/* -	 * We check the want_state rather than the current state, -	 * because if we received a DO/WILL for an option that we -	 * don't support, and the other side didn't send a DONT/WONT -	 * in response to our WONT/DONT, then the "state" will be -	 * WILL/DO, and the "want_state" will be WONT/DONT.  We -	 * need to go by the latter. -	 */ -	for (i = 0; i < (unsigned char)NTELOPTS; i++) { -		if (my_want_state_is_will(i)) { -			ADD(WILL); -			ADD_DATA(i); -		} -		if (his_want_state_is_will(i)) { -			ADD(DO); -			ADD_DATA(i); -		} -	} - -	if (his_want_state_is_will(TELOPT_LFLOW)) { -		ADD(SB); -		ADD(TELOPT_LFLOW); -		if (flowmode) { -			ADD(LFLOW_ON); -		} else { -			ADD(LFLOW_OFF); -		} -		ADD(SE); - -		if (restartany >= 0) { -			ADD(SB); -			ADD(TELOPT_LFLOW); -			if (restartany) { -				ADD(LFLOW_RESTART_ANY); -			} else { -				ADD(LFLOW_RESTART_XON); -			} -			ADD(SE); -		} -	} - -#ifdef	LINEMODE -	if (his_want_state_is_will(TELOPT_LINEMODE)) { -		unsigned char *cp, *cpe; -		int len; - -		ADD(SB); -		ADD(TELOPT_LINEMODE); -		ADD(LM_MODE); -		ADD_DATA(editmode); -		ADD(SE); - -		ADD(SB); -		ADD(TELOPT_LINEMODE); -		ADD(LM_SLC); -		start_slc(0); -		send_slc(); -		len = end_slc(&cp); -		for (cpe = cp + len; cp < cpe; cp++) -			ADD_DATA(*cp); -		ADD(SE); -	} -#endif	/* LINEMODE */ - -	ADD(IAC); -	ADD(SE); - -	writenet(statusbuf, ncp - statusbuf); -	netflush();	/* Send it on its way */ - -	DIAG(TD_OPTIONS, -		{printsub('>', statusbuf, ncp - statusbuf); netflush();}); -} | 
