Home | History | Annotate | Line # | Download | only in telnetd
state.c revision 1.11.4.1
      1  1.11.4.1        he /*	$NetBSD: state.c,v 1.11.4.1 2000/10/10 21:48:19 he Exp $	*/
      2       1.9   thorpej 
      3       1.1       cgd /*
      4       1.5       cgd  * Copyright (c) 1989, 1993
      5       1.5       cgd  *	The Regents of the University of California.  All rights reserved.
      6       1.1       cgd  *
      7       1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8       1.1       cgd  * modification, are permitted provided that the following conditions
      9       1.1       cgd  * are met:
     10       1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11       1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12       1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13       1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14       1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15       1.1       cgd  * 3. All advertising materials mentioning features or use of this software
     16       1.1       cgd  *    must display the following acknowledgement:
     17       1.1       cgd  *	This product includes software developed by the University of
     18       1.1       cgd  *	California, Berkeley and its contributors.
     19       1.1       cgd  * 4. Neither the name of the University nor the names of its contributors
     20       1.1       cgd  *    may be used to endorse or promote products derived from this software
     21       1.1       cgd  *    without specific prior written permission.
     22       1.1       cgd  *
     23       1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24       1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25       1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26       1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27       1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28       1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29       1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30       1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31       1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32       1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33       1.1       cgd  * SUCH DAMAGE.
     34       1.1       cgd  */
     35       1.1       cgd 
     36      1.11       mrg #include <sys/cdefs.h>
     37       1.1       cgd #ifndef lint
     38       1.9   thorpej #if 0
     39       1.9   thorpej static char sccsid[] = "@(#)state.c	8.5 (Berkeley) 5/30/95";
     40       1.9   thorpej #else
     41  1.11.4.1        he __RCSID("$NetBSD: state.c,v 1.11.4.1 2000/10/10 21:48:19 he Exp $");
     42       1.9   thorpej #endif
     43       1.1       cgd #endif /* not lint */
     44       1.1       cgd 
     45       1.1       cgd #include "telnetd.h"
     46       1.5       cgd #if	defined(AUTHENTICATION)
     47       1.1       cgd #include <libtelnet/auth.h>
     48       1.1       cgd #endif
     49       1.1       cgd 
     50      1.11       mrg static int envvarok __P((char *));
     51      1.11       mrg 
     52  1.11.4.1        he unsigned const char	doopt[] = { IAC, DO, '%', 'c', 0 };
     53  1.11.4.1        he unsigned const char	dont[] = { IAC, DONT, '%', 'c', 0 };
     54  1.11.4.1        he unsigned const char	will[] = { IAC, WILL, '%', 'c', 0 };
     55  1.11.4.1        he unsigned const char	wont[] = { IAC, WONT, '%', 'c', 0 };
     56       1.1       cgd int	not42 = 1;
     57       1.1       cgd 
     58       1.1       cgd /*
     59       1.1       cgd  * Buffer for sub-options, and macros
     60       1.1       cgd  * for suboptions buffer manipulations
     61       1.1       cgd  */
     62       1.1       cgd unsigned char subbuffer[512], *subpointer= subbuffer, *subend= subbuffer;
     63       1.1       cgd 
     64       1.5       cgd #define	SB_CLEAR()	subpointer = subbuffer
     65       1.1       cgd #define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
     66       1.1       cgd #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
     67       1.1       cgd 				*subpointer++ = (c); \
     68       1.1       cgd 			}
     69       1.1       cgd #define	SB_GET()	((*subpointer++)&0xff)
     70       1.1       cgd #define	SB_EOF()	(subpointer >= subend)
     71       1.1       cgd #define	SB_LEN()	(subend - subpointer)
     72       1.1       cgd 
     73       1.5       cgd #ifdef	ENV_HACK
     74       1.5       cgd unsigned char *subsave;
     75       1.5       cgd #define SB_SAVE()	subsave = subpointer;
     76       1.5       cgd #define	SB_RESTORE()	subpointer = subsave;
     77       1.5       cgd #endif
     78       1.1       cgd 
     79       1.1       cgd 
     80       1.1       cgd /*
     81       1.1       cgd  * State for recv fsm
     82       1.1       cgd  */
     83       1.1       cgd #define	TS_DATA		0	/* base state */
     84       1.1       cgd #define	TS_IAC		1	/* look for double IAC's */
     85       1.1       cgd #define	TS_CR		2	/* CR-LF ->'s CR */
     86       1.1       cgd #define	TS_SB		3	/* throw away begin's... */
     87       1.1       cgd #define	TS_SE		4	/* ...end's (suboption negotiation) */
     88       1.1       cgd #define	TS_WILL		5	/* will option negotiation */
     89       1.1       cgd #define	TS_WONT		6	/* wont " */
     90       1.1       cgd #define	TS_DO		7	/* do " */
     91       1.1       cgd #define	TS_DONT		8	/* dont " */
     92       1.1       cgd 
     93       1.1       cgd 	void
     94       1.1       cgd telrcv()
     95       1.1       cgd {
     96       1.1       cgd 	register int c;
     97       1.1       cgd 	static int state = TS_DATA;
     98       1.1       cgd #if	defined(CRAY2) && defined(UNICOS5)
     99       1.1       cgd 	char *opfrontp = pfrontp;
    100       1.1       cgd #endif
    101       1.1       cgd 
    102       1.1       cgd 	while (ncc > 0) {
    103       1.1       cgd 		if ((&ptyobuf[BUFSIZ] - pfrontp) < 2)
    104       1.1       cgd 			break;
    105       1.1       cgd 		c = *netip++ & 0377, ncc--;
    106       1.1       cgd 		switch (state) {
    107       1.1       cgd 
    108       1.1       cgd 		case TS_CR:
    109       1.1       cgd 			state = TS_DATA;
    110       1.1       cgd 			/* Strip off \n or \0 after a \r */
    111       1.1       cgd 			if ((c == 0) || (c == '\n')) {
    112       1.1       cgd 				break;
    113       1.1       cgd 			}
    114       1.1       cgd 			/* FALL THROUGH */
    115       1.1       cgd 
    116       1.1       cgd 		case TS_DATA:
    117       1.1       cgd 			if (c == IAC) {
    118       1.1       cgd 				state = TS_IAC;
    119       1.1       cgd 				break;
    120       1.1       cgd 			}
    121       1.1       cgd 			/*
    122       1.1       cgd 			 * We now map \r\n ==> \r for pragmatic reasons.
    123       1.1       cgd 			 * Many client implementations send \r\n when
    124       1.1       cgd 			 * the user hits the CarriageReturn key.
    125       1.1       cgd 			 *
    126       1.1       cgd 			 * We USED to map \r\n ==> \n, since \r\n says
    127       1.1       cgd 			 * that we want to be in column 1 of the next
    128       1.1       cgd 			 * printable line, and \n is the standard
    129       1.1       cgd 			 * unix way of saying that (\r is only good
    130       1.1       cgd 			 * if CRMOD is set, which it normally is).
    131       1.1       cgd 			 */
    132       1.1       cgd 			if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
    133       1.1       cgd 				int nc = *netip;
    134       1.1       cgd #ifdef	LINEMODE
    135       1.1       cgd 				/*
    136       1.1       cgd 				 * If we are operating in linemode,
    137       1.1       cgd 				 * convert to local end-of-line.
    138       1.1       cgd 				 */
    139       1.1       cgd 				if (linemode && (ncc > 0) && (('\n' == nc) ||
    140       1.1       cgd 					 ((0 == nc) && tty_iscrnl())) ) {
    141       1.1       cgd 					netip++; ncc--;
    142       1.1       cgd 					c = '\n';
    143       1.1       cgd 				} else
    144       1.1       cgd #endif
    145       1.1       cgd 				{
    146       1.1       cgd 					state = TS_CR;
    147       1.1       cgd 				}
    148       1.1       cgd 			}
    149       1.1       cgd 			*pfrontp++ = c;
    150       1.1       cgd 			break;
    151       1.1       cgd 
    152       1.1       cgd 		case TS_IAC:
    153       1.1       cgd gotiac:			switch (c) {
    154       1.1       cgd 
    155       1.1       cgd 			/*
    156       1.1       cgd 			 * Send the process on the pty side an
    157       1.1       cgd 			 * interrupt.  Do this with a NULL or
    158       1.1       cgd 			 * interrupt char; depending on the tty mode.
    159       1.1       cgd 			 */
    160       1.1       cgd 			case IP:
    161       1.1       cgd 				DIAG(TD_OPTIONS,
    162       1.1       cgd 					printoption("td: recv IAC", c));
    163       1.1       cgd 				interrupt();
    164       1.1       cgd 				break;
    165       1.1       cgd 
    166       1.1       cgd 			case BREAK:
    167       1.1       cgd 				DIAG(TD_OPTIONS,
    168       1.1       cgd 					printoption("td: recv IAC", c));
    169       1.1       cgd 				sendbrk();
    170       1.1       cgd 				break;
    171       1.1       cgd 
    172       1.1       cgd 			/*
    173       1.1       cgd 			 * Are You There?
    174       1.1       cgd 			 */
    175       1.1       cgd 			case AYT:
    176       1.1       cgd 				DIAG(TD_OPTIONS,
    177       1.1       cgd 					printoption("td: recv IAC", c));
    178       1.1       cgd 				recv_ayt();
    179       1.1       cgd 				break;
    180       1.1       cgd 
    181       1.1       cgd 			/*
    182       1.1       cgd 			 * Abort Output
    183       1.1       cgd 			 */
    184       1.1       cgd 			case AO:
    185       1.1       cgd 			    {
    186       1.1       cgd 				DIAG(TD_OPTIONS,
    187       1.1       cgd 					printoption("td: recv IAC", c));
    188       1.1       cgd 				ptyflush();	/* half-hearted */
    189       1.1       cgd 				init_termbuf();
    190       1.1       cgd 
    191       1.1       cgd 				if (slctab[SLC_AO].sptr &&
    192       1.1       cgd 				    *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
    193       1.1       cgd 				    *pfrontp++ =
    194       1.1       cgd 					(unsigned char)*slctab[SLC_AO].sptr;
    195       1.1       cgd 				}
    196       1.1       cgd 
    197       1.1       cgd 				netclear();	/* clear buffer back */
    198       1.1       cgd 				*nfrontp++ = IAC;
    199       1.1       cgd 				*nfrontp++ = DM;
    200       1.1       cgd 				neturg = nfrontp-1; /* off by one XXX */
    201       1.1       cgd 				DIAG(TD_OPTIONS,
    202       1.1       cgd 					printoption("td: send IAC", DM));
    203       1.1       cgd 				break;
    204       1.1       cgd 			    }
    205       1.1       cgd 
    206       1.1       cgd 			/*
    207       1.1       cgd 			 * Erase Character and
    208       1.1       cgd 			 * Erase Line
    209       1.1       cgd 			 */
    210       1.1       cgd 			case EC:
    211       1.1       cgd 			case EL:
    212       1.1       cgd 			    {
    213       1.1       cgd 				cc_t ch;
    214       1.1       cgd 
    215       1.1       cgd 				DIAG(TD_OPTIONS,
    216       1.1       cgd 					printoption("td: recv IAC", c));
    217       1.1       cgd 				ptyflush();	/* half-hearted */
    218       1.1       cgd 				init_termbuf();
    219       1.1       cgd 				if (c == EC)
    220       1.1       cgd 					ch = *slctab[SLC_EC].sptr;
    221       1.1       cgd 				else
    222       1.1       cgd 					ch = *slctab[SLC_EL].sptr;
    223       1.1       cgd 				if (ch != (cc_t)(_POSIX_VDISABLE))
    224       1.1       cgd 					*pfrontp++ = (unsigned char)ch;
    225       1.1       cgd 				break;
    226       1.1       cgd 			    }
    227       1.1       cgd 
    228       1.1       cgd 			/*
    229       1.1       cgd 			 * Check for urgent data...
    230       1.1       cgd 			 */
    231       1.1       cgd 			case DM:
    232       1.1       cgd 				DIAG(TD_OPTIONS,
    233       1.1       cgd 					printoption("td: recv IAC", c));
    234       1.1       cgd 				SYNCHing = stilloob(net);
    235       1.1       cgd 				settimer(gotDM);
    236       1.1       cgd 				break;
    237       1.1       cgd 
    238       1.1       cgd 
    239       1.1       cgd 			/*
    240       1.1       cgd 			 * Begin option subnegotiation...
    241       1.1       cgd 			 */
    242       1.1       cgd 			case SB:
    243       1.1       cgd 				state = TS_SB;
    244       1.1       cgd 				SB_CLEAR();
    245       1.1       cgd 				continue;
    246       1.1       cgd 
    247       1.1       cgd 			case WILL:
    248       1.1       cgd 				state = TS_WILL;
    249       1.1       cgd 				continue;
    250       1.1       cgd 
    251       1.1       cgd 			case WONT:
    252       1.1       cgd 				state = TS_WONT;
    253       1.1       cgd 				continue;
    254       1.1       cgd 
    255       1.1       cgd 			case DO:
    256       1.1       cgd 				state = TS_DO;
    257       1.1       cgd 				continue;
    258       1.1       cgd 
    259       1.1       cgd 			case DONT:
    260       1.1       cgd 				state = TS_DONT;
    261       1.1       cgd 				continue;
    262       1.1       cgd 			case EOR:
    263       1.1       cgd 				if (his_state_is_will(TELOPT_EOR))
    264       1.1       cgd 					doeof();
    265       1.1       cgd 				break;
    266       1.1       cgd 
    267       1.1       cgd 			/*
    268       1.1       cgd 			 * Handle RFC 10xx Telnet linemode option additions
    269       1.1       cgd 			 * to command stream (EOF, SUSP, ABORT).
    270       1.1       cgd 			 */
    271       1.1       cgd 			case xEOF:
    272       1.1       cgd 				doeof();
    273       1.1       cgd 				break;
    274       1.1       cgd 
    275       1.1       cgd 			case SUSP:
    276       1.1       cgd 				sendsusp();
    277       1.1       cgd 				break;
    278       1.1       cgd 
    279       1.1       cgd 			case ABORT:
    280       1.1       cgd 				sendbrk();
    281       1.1       cgd 				break;
    282       1.1       cgd 
    283       1.1       cgd 			case IAC:
    284       1.1       cgd 				*pfrontp++ = c;
    285       1.1       cgd 				break;
    286       1.1       cgd 			}
    287       1.1       cgd 			state = TS_DATA;
    288       1.1       cgd 			break;
    289       1.1       cgd 
    290       1.1       cgd 		case TS_SB:
    291       1.1       cgd 			if (c == IAC) {
    292       1.1       cgd 				state = TS_SE;
    293       1.1       cgd 			} else {
    294       1.1       cgd 				SB_ACCUM(c);
    295       1.1       cgd 			}
    296       1.1       cgd 			break;
    297       1.1       cgd 
    298       1.1       cgd 		case TS_SE:
    299       1.1       cgd 			if (c != SE) {
    300       1.1       cgd 				if (c != IAC) {
    301       1.1       cgd 					/*
    302       1.1       cgd 					 * bad form of suboption negotiation.
    303       1.1       cgd 					 * handle it in such a way as to avoid
    304       1.1       cgd 					 * damage to local state.  Parse
    305       1.1       cgd 					 * suboption buffer found so far,
    306       1.1       cgd 					 * then treat remaining stream as
    307       1.1       cgd 					 * another command sequence.
    308       1.1       cgd 					 */
    309       1.1       cgd 
    310       1.1       cgd 					/* for DIAGNOSTICS */
    311       1.1       cgd 					SB_ACCUM(IAC);
    312       1.1       cgd 					SB_ACCUM(c);
    313       1.1       cgd 					subpointer -= 2;
    314       1.1       cgd 
    315       1.1       cgd 					SB_TERM();
    316       1.1       cgd 					suboption();
    317       1.1       cgd 					state = TS_IAC;
    318       1.1       cgd 					goto gotiac;
    319       1.1       cgd 				}
    320       1.1       cgd 				SB_ACCUM(c);
    321       1.1       cgd 				state = TS_SB;
    322       1.1       cgd 			} else {
    323       1.1       cgd 				/* for DIAGNOSTICS */
    324       1.1       cgd 				SB_ACCUM(IAC);
    325       1.1       cgd 				SB_ACCUM(SE);
    326       1.1       cgd 				subpointer -= 2;
    327       1.1       cgd 
    328       1.1       cgd 				SB_TERM();
    329       1.1       cgd 				suboption();	/* handle sub-option */
    330       1.1       cgd 				state = TS_DATA;
    331       1.1       cgd 			}
    332       1.1       cgd 			break;
    333       1.1       cgd 
    334       1.1       cgd 		case TS_WILL:
    335       1.1       cgd 			willoption(c);
    336       1.1       cgd 			state = TS_DATA;
    337       1.1       cgd 			continue;
    338       1.1       cgd 
    339       1.1       cgd 		case TS_WONT:
    340       1.1       cgd 			wontoption(c);
    341       1.1       cgd 			state = TS_DATA;
    342       1.1       cgd 			continue;
    343       1.1       cgd 
    344       1.1       cgd 		case TS_DO:
    345       1.1       cgd 			dooption(c);
    346       1.1       cgd 			state = TS_DATA;
    347       1.1       cgd 			continue;
    348       1.1       cgd 
    349       1.1       cgd 		case TS_DONT:
    350       1.1       cgd 			dontoption(c);
    351       1.1       cgd 			state = TS_DATA;
    352       1.1       cgd 			continue;
    353       1.1       cgd 
    354       1.1       cgd 		default:
    355       1.1       cgd 			syslog(LOG_ERR, "telnetd: panic state=%d\n", state);
    356       1.1       cgd 			printf("telnetd: panic state=%d\n", state);
    357       1.1       cgd 			exit(1);
    358       1.1       cgd 		}
    359       1.1       cgd 	}
    360       1.1       cgd #if	defined(CRAY2) && defined(UNICOS5)
    361       1.1       cgd 	if (!linemode) {
    362       1.1       cgd 		char	xptyobuf[BUFSIZ+NETSLOP];
    363       1.1       cgd 		char	xbuf2[BUFSIZ];
    364       1.1       cgd 		register char *cp;
    365       1.1       cgd 		int n = pfrontp - opfrontp, oc;
    366       1.8       jtk 		memmove(xptyobuf, opfrontp, n);
    367       1.1       cgd 		pfrontp = opfrontp;
    368       1.1       cgd 		pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
    369       1.1       cgd 					xbuf2, &oc, BUFSIZ);
    370       1.1       cgd 		for (cp = xbuf2; oc > 0; --oc)
    371       1.1       cgd 			if ((*nfrontp++ = *cp++) == IAC)
    372       1.1       cgd 				*nfrontp++ = IAC;
    373       1.1       cgd 	}
    374       1.1       cgd #endif	/* defined(CRAY2) && defined(UNICOS5) */
    375       1.1       cgd }  /* end of telrcv */
    376       1.1       cgd 
    377       1.1       cgd /*
    378       1.1       cgd  * The will/wont/do/dont state machines are based on Dave Borman's
    379       1.1       cgd  * Telnet option processing state machine.
    380       1.1       cgd  *
    381       1.1       cgd  * These correspond to the following states:
    382       1.1       cgd  *	my_state = the last negotiated state
    383       1.1       cgd  *	want_state = what I want the state to go to
    384       1.1       cgd  *	want_resp = how many requests I have sent
    385       1.1       cgd  * All state defaults are negative, and resp defaults to 0.
    386       1.1       cgd  *
    387       1.1       cgd  * When initiating a request to change state to new_state:
    388       1.8       jtk  *
    389       1.1       cgd  * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
    390       1.1       cgd  *	do nothing;
    391       1.1       cgd  * } else {
    392       1.1       cgd  *	want_state = new_state;
    393       1.1       cgd  *	send new_state;
    394       1.1       cgd  *	want_resp++;
    395       1.1       cgd  * }
    396       1.1       cgd  *
    397       1.1       cgd  * When receiving new_state:
    398       1.1       cgd  *
    399       1.1       cgd  * if (want_resp) {
    400       1.1       cgd  *	want_resp--;
    401       1.1       cgd  *	if (want_resp && (new_state == my_state))
    402       1.1       cgd  *		want_resp--;
    403       1.1       cgd  * }
    404       1.1       cgd  * if ((want_resp == 0) && (new_state != want_state)) {
    405       1.1       cgd  *	if (ok_to_switch_to new_state)
    406       1.1       cgd  *		want_state = new_state;
    407       1.1       cgd  *	else
    408       1.1       cgd  *		want_resp++;
    409       1.1       cgd  *	send want_state;
    410       1.1       cgd  * }
    411       1.1       cgd  * my_state = new_state;
    412       1.1       cgd  *
    413       1.1       cgd  * Note that new_state is implied in these functions by the function itself.
    414       1.1       cgd  * will and do imply positive new_state, wont and dont imply negative.
    415       1.1       cgd  *
    416       1.1       cgd  * Finally, there is one catch.  If we send a negative response to a
    417       1.1       cgd  * positive request, my_state will be the positive while want_state will
    418       1.1       cgd  * remain negative.  my_state will revert to negative when the negative
    419       1.1       cgd  * acknowlegment arrives from the peer.  Thus, my_state generally tells
    420       1.1       cgd  * us not only the last negotiated state, but also tells us what the peer
    421       1.1       cgd  * wants to be doing as well.  It is important to understand this difference
    422       1.1       cgd  * as we may wish to be processing data streams based on our desired state
    423       1.1       cgd  * (want_state) or based on what the peer thinks the state is (my_state).
    424       1.1       cgd  *
    425       1.1       cgd  * This all works fine because if the peer sends a positive request, the data
    426       1.1       cgd  * that we receive prior to negative acknowlegment will probably be affected
    427       1.1       cgd  * by the positive state, and we can process it as such (if we can; if we
    428       1.1       cgd  * can't then it really doesn't matter).  If it is that important, then the
    429       1.1       cgd  * peer probably should be buffering until this option state negotiation
    430       1.1       cgd  * is complete.
    431       1.1       cgd  *
    432       1.1       cgd  */
    433       1.1       cgd 	void
    434       1.1       cgd send_do(option, init)
    435       1.1       cgd 	int option, init;
    436       1.1       cgd {
    437       1.1       cgd 	if (init) {
    438       1.1       cgd 		if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
    439       1.1       cgd 		    his_want_state_is_will(option))
    440       1.1       cgd 			return;
    441       1.1       cgd 		/*
    442       1.1       cgd 		 * Special case for TELOPT_TM:  We send a DO, but pretend
    443       1.1       cgd 		 * that we sent a DONT, so that we can send more DOs if
    444       1.1       cgd 		 * we want to.
    445       1.1       cgd 		 */
    446       1.1       cgd 		if (option == TELOPT_TM)
    447       1.1       cgd 			set_his_want_state_wont(option);
    448       1.1       cgd 		else
    449       1.1       cgd 			set_his_want_state_will(option);
    450       1.1       cgd 		do_dont_resp[option]++;
    451       1.1       cgd 	}
    452       1.5       cgd 	(void) sprintf(nfrontp, (char *)doopt, option);
    453       1.1       cgd 	nfrontp += sizeof (dont) - 2;
    454       1.1       cgd 
    455       1.1       cgd 	DIAG(TD_OPTIONS, printoption("td: send do", option));
    456       1.1       cgd }
    457       1.1       cgd 
    458       1.5       cgd #ifdef	AUTHENTICATION
    459      1.11       mrg extern void auth_request __P((void));	/* libtelnet */
    460       1.1       cgd #endif
    461       1.1       cgd #ifdef	LINEMODE
    462      1.11       mrg extern void doclientstat __P((void));
    463       1.1       cgd #endif
    464       1.1       cgd 
    465       1.1       cgd 	void
    466       1.1       cgd willoption(option)
    467       1.1       cgd 	int option;
    468       1.1       cgd {
    469       1.1       cgd 	int changeok = 0;
    470      1.11       mrg 	void (*func) __P((void)) = 0;
    471       1.1       cgd 
    472       1.1       cgd 	/*
    473       1.1       cgd 	 * process input from peer.
    474       1.1       cgd 	 */
    475       1.1       cgd 
    476       1.1       cgd 	DIAG(TD_OPTIONS, printoption("td: recv will", option));
    477       1.1       cgd 
    478       1.1       cgd 	if (do_dont_resp[option]) {
    479       1.1       cgd 		do_dont_resp[option]--;
    480       1.1       cgd 		if (do_dont_resp[option] && his_state_is_will(option))
    481       1.1       cgd 			do_dont_resp[option]--;
    482       1.1       cgd 	}
    483       1.1       cgd 	if (do_dont_resp[option] == 0) {
    484       1.1       cgd 	    if (his_want_state_is_wont(option)) {
    485       1.1       cgd 		switch (option) {
    486       1.1       cgd 
    487       1.1       cgd 		case TELOPT_BINARY:
    488       1.1       cgd 			init_termbuf();
    489       1.1       cgd 			tty_binaryin(1);
    490       1.1       cgd 			set_termbuf();
    491       1.1       cgd 			changeok++;
    492       1.1       cgd 			break;
    493       1.1       cgd 
    494       1.1       cgd 		case TELOPT_ECHO:
    495       1.1       cgd 			/*
    496       1.1       cgd 			 * See comments below for more info.
    497       1.1       cgd 			 */
    498       1.1       cgd 			not42 = 0;	/* looks like a 4.2 system */
    499       1.1       cgd 			break;
    500       1.1       cgd 
    501       1.1       cgd 		case TELOPT_TM:
    502       1.1       cgd #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
    503       1.1       cgd 			/*
    504       1.1       cgd 			 * This telnetd implementation does not really
    505       1.1       cgd 			 * support timing marks, it just uses them to
    506       1.1       cgd 			 * support the kludge linemode stuff.  If we
    507       1.1       cgd 			 * receive a will or wont TM in response to our
    508       1.1       cgd 			 * do TM request that may have been sent to
    509       1.1       cgd 			 * determine kludge linemode support, process
    510       1.1       cgd 			 * it, otherwise TM should get a negative
    511       1.1       cgd 			 * response back.
    512       1.1       cgd 			 */
    513       1.1       cgd 			/*
    514       1.1       cgd 			 * Handle the linemode kludge stuff.
    515       1.1       cgd 			 * If we are not currently supporting any
    516       1.1       cgd 			 * linemode at all, then we assume that this
    517       1.1       cgd 			 * is the client telling us to use kludge
    518       1.1       cgd 			 * linemode in response to our query.  Set the
    519       1.1       cgd 			 * linemode type that is to be supported, note
    520       1.1       cgd 			 * that the client wishes to use linemode, and
    521       1.1       cgd 			 * eat the will TM as though it never arrived.
    522       1.1       cgd 			 */
    523       1.1       cgd 			if (lmodetype < KLUDGE_LINEMODE) {
    524       1.1       cgd 				lmodetype = KLUDGE_LINEMODE;
    525       1.1       cgd 				clientstat(TELOPT_LINEMODE, WILL, 0);
    526       1.1       cgd 				send_wont(TELOPT_SGA, 1);
    527       1.5       cgd 			} else if (lmodetype == NO_AUTOKLUDGE) {
    528       1.5       cgd 				lmodetype = KLUDGE_OK;
    529       1.1       cgd 			}
    530       1.1       cgd #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
    531       1.1       cgd 			/*
    532       1.1       cgd 			 * We never respond to a WILL TM, and
    533       1.1       cgd 			 * we leave the state WONT.
    534       1.1       cgd 			 */
    535       1.1       cgd 			return;
    536       1.1       cgd 
    537       1.1       cgd 		case TELOPT_LFLOW:
    538       1.1       cgd 			/*
    539       1.1       cgd 			 * If we are going to support flow control
    540       1.1       cgd 			 * option, then don't worry peer that we can't
    541       1.1       cgd 			 * change the flow control characters.
    542       1.1       cgd 			 */
    543       1.1       cgd 			slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
    544       1.1       cgd 			slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
    545       1.1       cgd 			slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
    546       1.1       cgd 			slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
    547       1.1       cgd 		case TELOPT_TTYPE:
    548       1.1       cgd 		case TELOPT_SGA:
    549       1.1       cgd 		case TELOPT_NAWS:
    550       1.1       cgd 		case TELOPT_TSPEED:
    551       1.1       cgd 		case TELOPT_XDISPLOC:
    552       1.5       cgd 		case TELOPT_NEW_ENVIRON:
    553       1.5       cgd 		case TELOPT_OLD_ENVIRON:
    554       1.1       cgd 			changeok++;
    555       1.1       cgd 			break;
    556       1.1       cgd 
    557       1.1       cgd #ifdef	LINEMODE
    558       1.1       cgd 		case TELOPT_LINEMODE:
    559       1.1       cgd # ifdef	KLUDGELINEMODE
    560       1.1       cgd 			/*
    561       1.1       cgd 			 * Note client's desire to use linemode.
    562       1.1       cgd 			 */
    563       1.1       cgd 			lmodetype = REAL_LINEMODE;
    564       1.1       cgd # endif	/* KLUDGELINEMODE */
    565       1.1       cgd 			func = doclientstat;
    566       1.1       cgd 			changeok++;
    567       1.1       cgd 			break;
    568       1.1       cgd #endif	/* LINEMODE */
    569       1.1       cgd 
    570       1.5       cgd #ifdef	AUTHENTICATION
    571       1.1       cgd 		case TELOPT_AUTHENTICATION:
    572       1.1       cgd 			func = auth_request;
    573       1.1       cgd 			changeok++;
    574       1.1       cgd 			break;
    575       1.1       cgd #endif
    576       1.1       cgd 
    577       1.1       cgd 
    578       1.1       cgd 		default:
    579       1.1       cgd 			break;
    580       1.1       cgd 		}
    581       1.1       cgd 		if (changeok) {
    582       1.1       cgd 			set_his_want_state_will(option);
    583       1.1       cgd 			send_do(option, 0);
    584       1.1       cgd 		} else {
    585       1.1       cgd 			do_dont_resp[option]++;
    586       1.1       cgd 			send_dont(option, 0);
    587       1.1       cgd 		}
    588       1.1       cgd 	    } else {
    589       1.1       cgd 		/*
    590       1.1       cgd 		 * Option processing that should happen when
    591       1.1       cgd 		 * we receive conformation of a change in
    592       1.1       cgd 		 * state that we had requested.
    593       1.1       cgd 		 */
    594       1.1       cgd 		switch (option) {
    595       1.1       cgd 		case TELOPT_ECHO:
    596       1.1       cgd 			not42 = 0;	/* looks like a 4.2 system */
    597       1.1       cgd 			/*
    598       1.1       cgd 			 * Egads, he responded "WILL ECHO".  Turn
    599       1.1       cgd 			 * it off right now!
    600       1.1       cgd 			 */
    601       1.1       cgd 			send_dont(option, 1);
    602       1.1       cgd 			/*
    603       1.1       cgd 			 * "WILL ECHO".  Kludge upon kludge!
    604       1.1       cgd 			 * A 4.2 client is now echoing user input at
    605       1.1       cgd 			 * the tty.  This is probably undesireable and
    606       1.1       cgd 			 * it should be stopped.  The client will
    607       1.1       cgd 			 * respond WONT TM to the DO TM that we send to
    608       1.1       cgd 			 * check for kludge linemode.  When the WONT TM
    609       1.1       cgd 			 * arrives, linemode will be turned off and a
    610       1.1       cgd 			 * change propogated to the pty.  This change
    611       1.1       cgd 			 * will cause us to process the new pty state
    612       1.1       cgd 			 * in localstat(), which will notice that
    613       1.1       cgd 			 * linemode is off and send a WILL ECHO
    614       1.1       cgd 			 * so that we are properly in character mode and
    615       1.1       cgd 			 * all is well.
    616       1.1       cgd 			 */
    617       1.1       cgd 			break;
    618       1.1       cgd #ifdef	LINEMODE
    619       1.1       cgd 		case TELOPT_LINEMODE:
    620       1.1       cgd # ifdef	KLUDGELINEMODE
    621       1.1       cgd 			/*
    622       1.1       cgd 			 * Note client's desire to use linemode.
    623       1.1       cgd 			 */
    624       1.1       cgd 			lmodetype = REAL_LINEMODE;
    625       1.1       cgd # endif	/* KLUDGELINEMODE */
    626       1.1       cgd 			func = doclientstat;
    627       1.1       cgd 			break;
    628       1.1       cgd #endif	/* LINEMODE */
    629       1.1       cgd 
    630       1.5       cgd #ifdef	AUTHENTICATION
    631       1.1       cgd 		case TELOPT_AUTHENTICATION:
    632       1.1       cgd 			func = auth_request;
    633       1.1       cgd 			break;
    634       1.1       cgd #endif
    635       1.1       cgd 
    636       1.5       cgd 		case TELOPT_LFLOW:
    637       1.5       cgd 			func = flowstat;
    638       1.1       cgd 			break;
    639       1.1       cgd 		}
    640       1.1       cgd 	    }
    641       1.1       cgd 	}
    642       1.1       cgd 	set_his_state_will(option);
    643       1.1       cgd 	if (func)
    644       1.1       cgd 		(*func)();
    645       1.1       cgd }  /* end of willoption */
    646       1.1       cgd 
    647       1.1       cgd 	void
    648       1.1       cgd send_dont(option, init)
    649       1.1       cgd 	int option, init;
    650       1.1       cgd {
    651       1.1       cgd 	if (init) {
    652       1.1       cgd 		if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
    653       1.1       cgd 		    his_want_state_is_wont(option))
    654       1.1       cgd 			return;
    655       1.1       cgd 		set_his_want_state_wont(option);
    656       1.1       cgd 		do_dont_resp[option]++;
    657       1.1       cgd 	}
    658       1.5       cgd 	(void) sprintf(nfrontp, (char *)dont, option);
    659       1.1       cgd 	nfrontp += sizeof (doopt) - 2;
    660       1.1       cgd 
    661       1.1       cgd 	DIAG(TD_OPTIONS, printoption("td: send dont", option));
    662       1.1       cgd }
    663       1.1       cgd 
    664       1.1       cgd 	void
    665       1.1       cgd wontoption(option)
    666       1.1       cgd 	int option;
    667       1.1       cgd {
    668       1.1       cgd 	/*
    669       1.1       cgd 	 * Process client input.
    670       1.1       cgd 	 */
    671       1.1       cgd 
    672       1.1       cgd 	DIAG(TD_OPTIONS, printoption("td: recv wont", option));
    673       1.1       cgd 
    674       1.1       cgd 	if (do_dont_resp[option]) {
    675       1.1       cgd 		do_dont_resp[option]--;
    676       1.1       cgd 		if (do_dont_resp[option] && his_state_is_wont(option))
    677       1.1       cgd 			do_dont_resp[option]--;
    678       1.1       cgd 	}
    679       1.1       cgd 	if (do_dont_resp[option] == 0) {
    680       1.1       cgd 	    if (his_want_state_is_will(option)) {
    681       1.1       cgd 		/* it is always ok to change to negative state */
    682       1.1       cgd 		switch (option) {
    683       1.1       cgd 		case TELOPT_ECHO:
    684       1.1       cgd 			not42 = 1; /* doesn't seem to be a 4.2 system */
    685       1.1       cgd 			break;
    686       1.1       cgd 
    687       1.1       cgd 		case TELOPT_BINARY:
    688       1.1       cgd 			init_termbuf();
    689       1.1       cgd 			tty_binaryin(0);
    690       1.1       cgd 			set_termbuf();
    691       1.1       cgd 			break;
    692       1.1       cgd 
    693       1.1       cgd #ifdef	LINEMODE
    694       1.1       cgd 		case TELOPT_LINEMODE:
    695       1.1       cgd # ifdef	KLUDGELINEMODE
    696       1.1       cgd 			/*
    697       1.1       cgd 			 * If real linemode is supported, then client is
    698       1.1       cgd 			 * asking to turn linemode off.
    699       1.1       cgd 			 */
    700       1.1       cgd 			if (lmodetype != REAL_LINEMODE)
    701       1.1       cgd 				break;
    702       1.1       cgd # endif	/* KLUDGELINEMODE */
    703       1.1       cgd 			clientstat(TELOPT_LINEMODE, WONT, 0);
    704       1.1       cgd 			break;
    705       1.1       cgd #endif	/* LINEMODE */
    706       1.1       cgd 
    707       1.1       cgd 		case TELOPT_TM:
    708       1.1       cgd 			/*
    709       1.1       cgd 			 * If we get a WONT TM, and had sent a DO TM,
    710       1.1       cgd 			 * don't respond with a DONT TM, just leave it
    711       1.1       cgd 			 * as is.  Short circut the state machine to
    712       1.1       cgd 			 * achive this.
    713       1.1       cgd 			 */
    714       1.1       cgd 			set_his_want_state_wont(TELOPT_TM);
    715       1.1       cgd 			return;
    716       1.1       cgd 
    717       1.1       cgd 		case TELOPT_LFLOW:
    718       1.1       cgd 			/*
    719       1.1       cgd 			 * If we are not going to support flow control
    720       1.1       cgd 			 * option, then let peer know that we can't
    721       1.1       cgd 			 * change the flow control characters.
    722       1.1       cgd 			 */
    723       1.1       cgd 			slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
    724       1.1       cgd 			slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
    725       1.1       cgd 			slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
    726       1.1       cgd 			slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
    727       1.1       cgd 			break;
    728       1.1       cgd 
    729       1.5       cgd #if	defined(AUTHENTICATION)
    730       1.1       cgd 		case TELOPT_AUTHENTICATION:
    731       1.1       cgd 			auth_finished(0, AUTH_REJECT);
    732       1.1       cgd 			break;
    733       1.1       cgd #endif
    734       1.1       cgd 
    735       1.1       cgd 		/*
    736       1.1       cgd 		 * For options that we might spin waiting for
    737       1.1       cgd 		 * sub-negotiation, if the client turns off the
    738       1.1       cgd 		 * option rather than responding to the request,
    739       1.1       cgd 		 * we have to treat it here as if we got a response
    740       1.1       cgd 		 * to the sub-negotiation, (by updating the timers)
    741       1.1       cgd 		 * so that we'll break out of the loop.
    742       1.1       cgd 		 */
    743       1.1       cgd 		case TELOPT_TTYPE:
    744       1.1       cgd 			settimer(ttypesubopt);
    745       1.1       cgd 			break;
    746       1.1       cgd 
    747       1.1       cgd 		case TELOPT_TSPEED:
    748       1.1       cgd 			settimer(tspeedsubopt);
    749       1.1       cgd 			break;
    750       1.1       cgd 
    751       1.1       cgd 		case TELOPT_XDISPLOC:
    752       1.1       cgd 			settimer(xdisplocsubopt);
    753       1.1       cgd 			break;
    754       1.1       cgd 
    755       1.5       cgd 		case TELOPT_OLD_ENVIRON:
    756       1.5       cgd 			settimer(oenvironsubopt);
    757       1.5       cgd 			break;
    758       1.5       cgd 
    759       1.5       cgd 		case TELOPT_NEW_ENVIRON:
    760       1.1       cgd 			settimer(environsubopt);
    761       1.1       cgd 			break;
    762       1.1       cgd 
    763       1.1       cgd 		default:
    764       1.1       cgd 			break;
    765       1.1       cgd 		}
    766       1.1       cgd 		set_his_want_state_wont(option);
    767       1.1       cgd 		if (his_state_is_will(option))
    768       1.1       cgd 			send_dont(option, 0);
    769       1.1       cgd 	    } else {
    770       1.1       cgd 		switch (option) {
    771       1.1       cgd 		case TELOPT_TM:
    772       1.1       cgd #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
    773       1.5       cgd 			if (lmodetype < NO_AUTOKLUDGE) {
    774       1.1       cgd 				lmodetype = NO_LINEMODE;
    775       1.1       cgd 				clientstat(TELOPT_LINEMODE, WONT, 0);
    776       1.1       cgd 				send_will(TELOPT_SGA, 1);
    777       1.1       cgd 				send_will(TELOPT_ECHO, 1);
    778       1.1       cgd 			}
    779       1.1       cgd #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
    780       1.1       cgd 			break;
    781       1.1       cgd 
    782       1.5       cgd #if	defined(AUTHENTICATION)
    783       1.1       cgd 		case TELOPT_AUTHENTICATION:
    784       1.1       cgd 			auth_finished(0, AUTH_REJECT);
    785       1.1       cgd 			break;
    786       1.1       cgd #endif
    787       1.1       cgd 		default:
    788       1.1       cgd 			break;
    789       1.1       cgd 		}
    790       1.1       cgd 	    }
    791       1.1       cgd 	}
    792       1.1       cgd 	set_his_state_wont(option);
    793       1.1       cgd 
    794       1.1       cgd }  /* end of wontoption */
    795       1.1       cgd 
    796       1.1       cgd 	void
    797       1.1       cgd send_will(option, init)
    798       1.1       cgd 	int option, init;
    799       1.1       cgd {
    800       1.1       cgd 	if (init) {
    801       1.1       cgd 		if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
    802       1.1       cgd 		    my_want_state_is_will(option))
    803       1.1       cgd 			return;
    804       1.1       cgd 		set_my_want_state_will(option);
    805       1.1       cgd 		will_wont_resp[option]++;
    806       1.1       cgd 	}
    807       1.5       cgd 	(void) sprintf(nfrontp, (char *)will, option);
    808       1.1       cgd 	nfrontp += sizeof (doopt) - 2;
    809       1.1       cgd 
    810       1.1       cgd 	DIAG(TD_OPTIONS, printoption("td: send will", option));
    811       1.1       cgd }
    812       1.1       cgd 
    813       1.1       cgd #if	!defined(LINEMODE) || !defined(KLUDGELINEMODE)
    814       1.1       cgd /*
    815       1.1       cgd  * When we get a DONT SGA, we will try once to turn it
    816       1.1       cgd  * back on.  If the other side responds DONT SGA, we
    817       1.1       cgd  * leave it at that.  This is so that when we talk to
    818       1.1       cgd  * clients that understand KLUDGELINEMODE but not LINEMODE,
    819       1.1       cgd  * we'll keep them in char-at-a-time mode.
    820       1.1       cgd  */
    821       1.1       cgd int turn_on_sga = 0;
    822       1.1       cgd #endif
    823       1.1       cgd 
    824       1.1       cgd 	void
    825       1.1       cgd dooption(option)
    826       1.1       cgd 	int option;
    827       1.1       cgd {
    828       1.1       cgd 	int changeok = 0;
    829       1.1       cgd 
    830       1.1       cgd 	/*
    831       1.1       cgd 	 * Process client input.
    832       1.1       cgd 	 */
    833       1.1       cgd 
    834       1.1       cgd 	DIAG(TD_OPTIONS, printoption("td: recv do", option));
    835       1.1       cgd 
    836       1.1       cgd 	if (will_wont_resp[option]) {
    837       1.1       cgd 		will_wont_resp[option]--;
    838       1.1       cgd 		if (will_wont_resp[option] && my_state_is_will(option))
    839       1.1       cgd 			will_wont_resp[option]--;
    840       1.1       cgd 	}
    841       1.1       cgd 	if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
    842       1.1       cgd 		switch (option) {
    843       1.1       cgd 		case TELOPT_ECHO:
    844       1.1       cgd #ifdef	LINEMODE
    845       1.1       cgd # ifdef	KLUDGELINEMODE
    846       1.1       cgd 			if (lmodetype == NO_LINEMODE)
    847       1.1       cgd # else
    848       1.1       cgd 			if (his_state_is_wont(TELOPT_LINEMODE))
    849       1.1       cgd # endif
    850       1.1       cgd #endif
    851       1.1       cgd 			{
    852       1.1       cgd 				init_termbuf();
    853       1.1       cgd 				tty_setecho(1);
    854       1.1       cgd 				set_termbuf();
    855       1.1       cgd 			}
    856       1.1       cgd 			changeok++;
    857       1.1       cgd 			break;
    858       1.1       cgd 
    859       1.1       cgd 		case TELOPT_BINARY:
    860       1.1       cgd 			init_termbuf();
    861       1.1       cgd 			tty_binaryout(1);
    862       1.1       cgd 			set_termbuf();
    863       1.1       cgd 			changeok++;
    864       1.1       cgd 			break;
    865       1.1       cgd 
    866       1.1       cgd 		case TELOPT_SGA:
    867       1.1       cgd #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
    868       1.1       cgd 			/*
    869       1.1       cgd 			 * If kludge linemode is in use, then we must
    870       1.1       cgd 			 * process an incoming do SGA for linemode
    871       1.1       cgd 			 * purposes.
    872       1.1       cgd 			 */
    873       1.1       cgd 			if (lmodetype == KLUDGE_LINEMODE) {
    874       1.1       cgd 				/*
    875       1.1       cgd 				 * Receipt of "do SGA" in kludge
    876       1.1       cgd 				 * linemode is the peer asking us to
    877       1.1       cgd 				 * turn off linemode.  Make note of
    878       1.1       cgd 				 * the request.
    879       1.1       cgd 				 */
    880       1.1       cgd 				clientstat(TELOPT_LINEMODE, WONT, 0);
    881       1.1       cgd 				/*
    882       1.1       cgd 				 * If linemode did not get turned off
    883       1.1       cgd 				 * then don't tell peer that we did.
    884       1.1       cgd 				 * Breaking here forces a wont SGA to
    885       1.1       cgd 				 * be returned.
    886       1.1       cgd 				 */
    887       1.1       cgd 				if (linemode)
    888       1.1       cgd 					break;
    889       1.1       cgd 			}
    890       1.1       cgd #else
    891       1.1       cgd 			turn_on_sga = 0;
    892       1.1       cgd #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
    893       1.1       cgd 			changeok++;
    894       1.1       cgd 			break;
    895       1.1       cgd 
    896       1.1       cgd 		case TELOPT_STATUS:
    897       1.1       cgd 			changeok++;
    898       1.1       cgd 			break;
    899       1.1       cgd 
    900       1.1       cgd 		case TELOPT_TM:
    901       1.1       cgd 			/*
    902       1.1       cgd 			 * Special case for TM.  We send a WILL, but
    903       1.1       cgd 			 * pretend we sent a WONT.
    904       1.1       cgd 			 */
    905       1.1       cgd 			send_will(option, 0);
    906       1.1       cgd 			set_my_want_state_wont(option);
    907       1.1       cgd 			set_my_state_wont(option);
    908       1.1       cgd 			return;
    909       1.1       cgd 
    910       1.1       cgd 		case TELOPT_LOGOUT:
    911       1.1       cgd 			/*
    912       1.1       cgd 			 * When we get a LOGOUT option, respond
    913       1.1       cgd 			 * with a WILL LOGOUT, make sure that
    914       1.1       cgd 			 * it gets written out to the network,
    915       1.1       cgd 			 * and then just go away...
    916       1.1       cgd 			 */
    917       1.1       cgd 			set_my_want_state_will(TELOPT_LOGOUT);
    918       1.1       cgd 			send_will(TELOPT_LOGOUT, 0);
    919       1.1       cgd 			set_my_state_will(TELOPT_LOGOUT);
    920       1.1       cgd 			(void)netflush();
    921       1.1       cgd 			cleanup(0);
    922       1.1       cgd 			/* NOT REACHED */
    923       1.1       cgd 			break;
    924       1.1       cgd 
    925       1.1       cgd 		case TELOPT_LINEMODE:
    926       1.1       cgd 		case TELOPT_TTYPE:
    927       1.1       cgd 		case TELOPT_NAWS:
    928       1.1       cgd 		case TELOPT_TSPEED:
    929       1.1       cgd 		case TELOPT_LFLOW:
    930       1.1       cgd 		case TELOPT_XDISPLOC:
    931       1.5       cgd #ifdef	TELOPT_ENVIRON
    932       1.5       cgd 		case TELOPT_NEW_ENVIRON:
    933       1.5       cgd #endif
    934       1.5       cgd 		case TELOPT_OLD_ENVIRON:
    935       1.1       cgd 		default:
    936       1.1       cgd 			break;
    937       1.1       cgd 		}
    938       1.1       cgd 		if (changeok) {
    939       1.1       cgd 			set_my_want_state_will(option);
    940       1.1       cgd 			send_will(option, 0);
    941       1.1       cgd 		} else {
    942       1.1       cgd 			will_wont_resp[option]++;
    943       1.1       cgd 			send_wont(option, 0);
    944       1.1       cgd 		}
    945       1.1       cgd 	}
    946       1.1       cgd 	set_my_state_will(option);
    947       1.1       cgd 
    948       1.1       cgd }  /* end of dooption */
    949       1.1       cgd 
    950       1.1       cgd 	void
    951       1.1       cgd send_wont(option, init)
    952       1.1       cgd 	int option, init;
    953       1.1       cgd {
    954       1.1       cgd 	if (init) {
    955       1.1       cgd 		if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
    956       1.1       cgd 		    my_want_state_is_wont(option))
    957       1.1       cgd 			return;
    958       1.1       cgd 		set_my_want_state_wont(option);
    959       1.1       cgd 		will_wont_resp[option]++;
    960       1.1       cgd 	}
    961       1.5       cgd 	(void) sprintf(nfrontp, (char *)wont, option);
    962       1.1       cgd 	nfrontp += sizeof (wont) - 2;
    963       1.1       cgd 
    964       1.1       cgd 	DIAG(TD_OPTIONS, printoption("td: send wont", option));
    965       1.1       cgd }
    966       1.1       cgd 
    967       1.1       cgd 	void
    968       1.1       cgd dontoption(option)
    969       1.1       cgd 	int option;
    970       1.1       cgd {
    971       1.1       cgd 	/*
    972       1.1       cgd 	 * Process client input.
    973       1.1       cgd 	 */
    974       1.1       cgd 
    975       1.1       cgd 
    976       1.1       cgd 	DIAG(TD_OPTIONS, printoption("td: recv dont", option));
    977       1.1       cgd 
    978       1.1       cgd 	if (will_wont_resp[option]) {
    979       1.1       cgd 		will_wont_resp[option]--;
    980       1.1       cgd 		if (will_wont_resp[option] && my_state_is_wont(option))
    981       1.1       cgd 			will_wont_resp[option]--;
    982       1.1       cgd 	}
    983       1.1       cgd 	if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
    984       1.1       cgd 		switch (option) {
    985       1.1       cgd 		case TELOPT_BINARY:
    986       1.1       cgd 			init_termbuf();
    987       1.1       cgd 			tty_binaryout(0);
    988       1.1       cgd 			set_termbuf();
    989       1.1       cgd 			break;
    990       1.1       cgd 
    991       1.1       cgd 		case TELOPT_ECHO:	/* we should stop echoing */
    992       1.1       cgd #ifdef	LINEMODE
    993       1.1       cgd # ifdef	KLUDGELINEMODE
    994       1.5       cgd 			if ((lmodetype != REAL_LINEMODE) &&
    995       1.5       cgd 			    (lmodetype != KLUDGE_LINEMODE))
    996       1.1       cgd # else
    997       1.1       cgd 			if (his_state_is_wont(TELOPT_LINEMODE))
    998       1.1       cgd # endif
    999       1.1       cgd #endif
   1000       1.1       cgd 			{
   1001       1.1       cgd 				init_termbuf();
   1002       1.1       cgd 				tty_setecho(0);
   1003       1.1       cgd 				set_termbuf();
   1004       1.1       cgd 			}
   1005       1.1       cgd 			break;
   1006       1.1       cgd 
   1007       1.1       cgd 		case TELOPT_SGA:
   1008       1.1       cgd #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
   1009       1.1       cgd 			/*
   1010       1.1       cgd 			 * If kludge linemode is in use, then we
   1011       1.1       cgd 			 * must process an incoming do SGA for
   1012       1.1       cgd 			 * linemode purposes.
   1013       1.1       cgd 			 */
   1014       1.5       cgd 			if ((lmodetype == KLUDGE_LINEMODE) ||
   1015       1.5       cgd 			    (lmodetype == KLUDGE_OK)) {
   1016       1.1       cgd 				/*
   1017       1.1       cgd 				 * The client is asking us to turn
   1018       1.1       cgd 				 * linemode on.
   1019       1.1       cgd 				 */
   1020       1.5       cgd 				lmodetype = KLUDGE_LINEMODE;
   1021       1.1       cgd 				clientstat(TELOPT_LINEMODE, WILL, 0);
   1022       1.1       cgd 				/*
   1023       1.1       cgd 				 * If we did not turn line mode on,
   1024       1.1       cgd 				 * then what do we say?  Will SGA?
   1025       1.1       cgd 				 * This violates design of telnet.
   1026       1.1       cgd 				 * Gross.  Very Gross.
   1027       1.1       cgd 				 */
   1028       1.1       cgd 			}
   1029       1.1       cgd 			break;
   1030       1.1       cgd #else
   1031       1.1       cgd 			set_my_want_state_wont(option);
   1032       1.1       cgd 			if (my_state_is_will(option))
   1033       1.1       cgd 				send_wont(option, 0);
   1034       1.1       cgd 			set_my_state_wont(option);
   1035       1.1       cgd 			if (turn_on_sga ^= 1)
   1036       1.5       cgd 				send_will(option, 1);
   1037       1.1       cgd 			return;
   1038       1.1       cgd #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
   1039       1.1       cgd 
   1040       1.1       cgd 		default:
   1041       1.1       cgd 			break;
   1042       1.1       cgd 		}
   1043       1.1       cgd 
   1044       1.1       cgd 		set_my_want_state_wont(option);
   1045       1.1       cgd 		if (my_state_is_will(option))
   1046       1.1       cgd 			send_wont(option, 0);
   1047       1.1       cgd 	}
   1048       1.1       cgd 	set_my_state_wont(option);
   1049       1.1       cgd 
   1050       1.1       cgd }  /* end of dontoption */
   1051       1.1       cgd 
   1052       1.5       cgd #ifdef	ENV_HACK
   1053       1.5       cgd int env_ovar = -1;
   1054       1.5       cgd int env_ovalue = -1;
   1055       1.5       cgd #else	/* ENV_HACK */
   1056       1.5       cgd # define env_ovar OLD_ENV_VAR
   1057       1.5       cgd # define env_ovalue OLD_ENV_VALUE
   1058       1.5       cgd #endif	/* ENV_HACK */
   1059       1.5       cgd 
   1060       1.7   ghudson /* envvarok(char*) */
   1061       1.7   ghudson /* check that variable is safe to pass to login or shell */
   1062       1.7   ghudson static int
   1063       1.7   ghudson envvarok(varp)
   1064       1.7   ghudson 	char *varp;
   1065       1.7   ghudson {
   1066       1.7   ghudson 	return (strncmp(varp, "LD_", strlen("LD_")) &&
   1067       1.7   ghudson 		strncmp(varp, "_RLD_", strlen("_RLD_")) &&
   1068       1.7   ghudson 		strcmp(varp, "LIBPATH") &&
   1069      1.10  explorer 		strcmp(varp, "ENV") &&
   1070      1.10  explorer 		strcmp(varp, "BASH_ENV") &&
   1071       1.7   ghudson 		strcmp(varp, "IFS"));
   1072       1.7   ghudson }
   1073       1.7   ghudson 
   1074       1.1       cgd /*
   1075       1.1       cgd  * suboption()
   1076       1.1       cgd  *
   1077       1.1       cgd  *	Look at the sub-option buffer, and try to be helpful to the other
   1078       1.1       cgd  * side.
   1079       1.1       cgd  *
   1080       1.1       cgd  *	Currently we recognize:
   1081       1.1       cgd  *
   1082       1.1       cgd  *	Terminal type is
   1083       1.1       cgd  *	Linemode
   1084       1.1       cgd  *	Window size
   1085       1.1       cgd  *	Terminal speed
   1086       1.1       cgd  */
   1087       1.1       cgd 	void
   1088       1.1       cgd suboption()
   1089       1.1       cgd {
   1090       1.1       cgd     register int subchar;
   1091       1.1       cgd 
   1092       1.1       cgd     DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
   1093       1.1       cgd 
   1094       1.1       cgd     subchar = SB_GET();
   1095       1.1       cgd     switch (subchar) {
   1096       1.1       cgd     case TELOPT_TSPEED: {
   1097       1.1       cgd 	register int xspeed, rspeed;
   1098       1.1       cgd 
   1099       1.1       cgd 	if (his_state_is_wont(TELOPT_TSPEED))	/* Ignore if option disabled */
   1100       1.1       cgd 		break;
   1101       1.1       cgd 
   1102       1.1       cgd 	settimer(tspeedsubopt);
   1103       1.1       cgd 
   1104       1.1       cgd 	if (SB_EOF() || SB_GET() != TELQUAL_IS)
   1105       1.1       cgd 		return;
   1106       1.1       cgd 
   1107       1.1       cgd 	xspeed = atoi((char *)subpointer);
   1108       1.1       cgd 
   1109       1.1       cgd 	while (SB_GET() != ',' && !SB_EOF());
   1110       1.1       cgd 	if (SB_EOF())
   1111       1.1       cgd 		return;
   1112       1.1       cgd 
   1113       1.1       cgd 	rspeed = atoi((char *)subpointer);
   1114       1.1       cgd 	clientstat(TELOPT_TSPEED, xspeed, rspeed);
   1115       1.1       cgd 
   1116       1.1       cgd 	break;
   1117       1.1       cgd 
   1118       1.1       cgd     }  /* end of case TELOPT_TSPEED */
   1119       1.1       cgd 
   1120       1.1       cgd     case TELOPT_TTYPE: {		/* Yaaaay! */
   1121       1.1       cgd 	static char terminalname[41];
   1122       1.1       cgd 
   1123       1.1       cgd 	if (his_state_is_wont(TELOPT_TTYPE))	/* Ignore if option disabled */
   1124       1.1       cgd 		break;
   1125       1.1       cgd 	settimer(ttypesubopt);
   1126       1.1       cgd 
   1127       1.1       cgd 	if (SB_EOF() || SB_GET() != TELQUAL_IS) {
   1128       1.1       cgd 	    return;		/* ??? XXX but, this is the most robust */
   1129       1.1       cgd 	}
   1130       1.1       cgd 
   1131       1.1       cgd 	terminaltype = terminalname;
   1132       1.1       cgd 
   1133       1.1       cgd 	while ((terminaltype < (terminalname + sizeof terminalname-1)) &&
   1134       1.1       cgd 								    !SB_EOF()) {
   1135       1.1       cgd 	    register int c;
   1136       1.1       cgd 
   1137       1.1       cgd 	    c = SB_GET();
   1138       1.1       cgd 	    if (isupper(c)) {
   1139       1.1       cgd 		c = tolower(c);
   1140       1.1       cgd 	    }
   1141       1.1       cgd 	    *terminaltype++ = c;    /* accumulate name */
   1142       1.1       cgd 	}
   1143       1.1       cgd 	*terminaltype = 0;
   1144       1.1       cgd 	terminaltype = terminalname;
   1145       1.1       cgd 	break;
   1146       1.1       cgd     }  /* end of case TELOPT_TTYPE */
   1147       1.1       cgd 
   1148       1.1       cgd     case TELOPT_NAWS: {
   1149       1.1       cgd 	register int xwinsize, ywinsize;
   1150       1.1       cgd 
   1151       1.1       cgd 	if (his_state_is_wont(TELOPT_NAWS))	/* Ignore if option disabled */
   1152       1.1       cgd 		break;
   1153       1.1       cgd 
   1154       1.1       cgd 	if (SB_EOF())
   1155       1.1       cgd 		return;
   1156       1.1       cgd 	xwinsize = SB_GET() << 8;
   1157       1.1       cgd 	if (SB_EOF())
   1158       1.1       cgd 		return;
   1159       1.1       cgd 	xwinsize |= SB_GET();
   1160       1.1       cgd 	if (SB_EOF())
   1161       1.1       cgd 		return;
   1162       1.1       cgd 	ywinsize = SB_GET() << 8;
   1163       1.1       cgd 	if (SB_EOF())
   1164       1.1       cgd 		return;
   1165       1.1       cgd 	ywinsize |= SB_GET();
   1166       1.1       cgd 	clientstat(TELOPT_NAWS, xwinsize, ywinsize);
   1167       1.1       cgd 
   1168       1.1       cgd 	break;
   1169       1.1       cgd 
   1170       1.1       cgd     }  /* end of case TELOPT_NAWS */
   1171       1.1       cgd 
   1172       1.1       cgd #ifdef	LINEMODE
   1173       1.1       cgd     case TELOPT_LINEMODE: {
   1174       1.1       cgd 	register int request;
   1175       1.1       cgd 
   1176       1.1       cgd 	if (his_state_is_wont(TELOPT_LINEMODE))	/* Ignore if option disabled */
   1177       1.1       cgd 		break;
   1178       1.1       cgd 	/*
   1179       1.1       cgd 	 * Process linemode suboptions.
   1180       1.1       cgd 	 */
   1181       1.1       cgd 	if (SB_EOF())
   1182       1.1       cgd 	    break;		/* garbage was sent */
   1183       1.1       cgd 	request = SB_GET();	/* get will/wont */
   1184       1.1       cgd 
   1185       1.1       cgd 	if (SB_EOF())
   1186       1.1       cgd 	    break;		/* another garbage check */
   1187       1.1       cgd 
   1188       1.1       cgd 	if (request == LM_SLC) {  /* SLC is not preceeded by WILL or WONT */
   1189       1.1       cgd 		/*
   1190       1.1       cgd 		 * Process suboption buffer of slc's
   1191       1.1       cgd 		 */
   1192       1.1       cgd 		start_slc(1);
   1193       1.1       cgd 		do_opt_slc(subpointer, subend - subpointer);
   1194       1.1       cgd 		(void) end_slc(0);
   1195       1.1       cgd 		break;
   1196       1.1       cgd 	} else if (request == LM_MODE) {
   1197       1.1       cgd 		if (SB_EOF())
   1198       1.1       cgd 		    return;
   1199       1.1       cgd 		useeditmode = SB_GET();  /* get mode flag */
   1200       1.1       cgd 		clientstat(LM_MODE, 0, 0);
   1201       1.1       cgd 		break;
   1202       1.1       cgd 	}
   1203       1.1       cgd 
   1204       1.1       cgd 	if (SB_EOF())
   1205       1.1       cgd 	    break;
   1206       1.1       cgd 	switch (SB_GET()) {  /* what suboption? */
   1207       1.1       cgd 	case LM_FORWARDMASK:
   1208       1.1       cgd 		/*
   1209       1.1       cgd 		 * According to spec, only server can send request for
   1210       1.1       cgd 		 * forwardmask, and client can only return a positive response.
   1211       1.1       cgd 		 * So don't worry about it.
   1212       1.1       cgd 		 */
   1213       1.1       cgd 
   1214       1.1       cgd 	default:
   1215       1.1       cgd 		break;
   1216       1.1       cgd 	}
   1217       1.1       cgd 	break;
   1218       1.1       cgd     }  /* end of case TELOPT_LINEMODE */
   1219       1.1       cgd #endif
   1220       1.1       cgd     case TELOPT_STATUS: {
   1221       1.1       cgd 	int mode;
   1222       1.1       cgd 
   1223       1.1       cgd 	if (SB_EOF())
   1224       1.1       cgd 	    break;
   1225       1.1       cgd 	mode = SB_GET();
   1226       1.1       cgd 	switch (mode) {
   1227       1.1       cgd 	case TELQUAL_SEND:
   1228       1.1       cgd 	    if (my_state_is_will(TELOPT_STATUS))
   1229       1.1       cgd 		send_status();
   1230       1.1       cgd 	    break;
   1231       1.1       cgd 
   1232       1.1       cgd 	case TELQUAL_IS:
   1233       1.1       cgd 	    break;
   1234       1.1       cgd 
   1235       1.1       cgd 	default:
   1236       1.1       cgd 	    break;
   1237       1.1       cgd 	}
   1238       1.1       cgd 	break;
   1239       1.1       cgd     }  /* end of case TELOPT_STATUS */
   1240       1.1       cgd 
   1241       1.1       cgd     case TELOPT_XDISPLOC: {
   1242       1.1       cgd 	if (SB_EOF() || SB_GET() != TELQUAL_IS)
   1243       1.1       cgd 		return;
   1244       1.1       cgd 	settimer(xdisplocsubopt);
   1245       1.1       cgd 	subpointer[SB_LEN()] = '\0';
   1246       1.1       cgd 	(void)setenv("DISPLAY", (char *)subpointer, 1);
   1247       1.1       cgd 	break;
   1248       1.1       cgd     }  /* end of case TELOPT_XDISPLOC */
   1249       1.1       cgd 
   1250       1.5       cgd #ifdef	TELOPT_NEW_ENVIRON
   1251       1.5       cgd     case TELOPT_NEW_ENVIRON:
   1252       1.5       cgd #endif
   1253       1.5       cgd     case TELOPT_OLD_ENVIRON: {
   1254       1.1       cgd 	register int c;
   1255       1.1       cgd 	register char *cp, *varp, *valp;
   1256       1.1       cgd 
   1257       1.1       cgd 	if (SB_EOF())
   1258       1.1       cgd 		return;
   1259       1.1       cgd 	c = SB_GET();
   1260       1.5       cgd 	if (c == TELQUAL_IS) {
   1261       1.5       cgd 		if (subchar == TELOPT_OLD_ENVIRON)
   1262       1.5       cgd 			settimer(oenvironsubopt);
   1263       1.5       cgd 		else
   1264       1.5       cgd 			settimer(environsubopt);
   1265       1.5       cgd 	} else if (c != TELQUAL_INFO) {
   1266       1.1       cgd 		return;
   1267       1.5       cgd 	}
   1268       1.5       cgd 
   1269       1.5       cgd #ifdef	TELOPT_NEW_ENVIRON
   1270       1.5       cgd 	if (subchar == TELOPT_NEW_ENVIRON) {
   1271       1.5       cgd 	    while (!SB_EOF()) {
   1272       1.5       cgd 		c = SB_GET();
   1273       1.5       cgd 		if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
   1274       1.5       cgd 			break;
   1275       1.5       cgd 	    }
   1276       1.5       cgd 	} else
   1277       1.5       cgd #endif
   1278       1.5       cgd 	{
   1279       1.5       cgd #ifdef	ENV_HACK
   1280       1.5       cgd 	    /*
   1281       1.5       cgd 	     * We only want to do this if we haven't already decided
   1282       1.5       cgd 	     * whether or not the other side has its VALUE and VAR
   1283       1.5       cgd 	     * reversed.
   1284       1.5       cgd 	     */
   1285       1.5       cgd 	    if (env_ovar < 0) {
   1286       1.5       cgd 		register int last = -1;		/* invalid value */
   1287       1.5       cgd 		int empty = 0;
   1288       1.5       cgd 		int got_var = 0, got_value = 0, got_uservar = 0;
   1289       1.5       cgd 
   1290       1.5       cgd 		/*
   1291       1.5       cgd 		 * The other side might have its VALUE and VAR values
   1292       1.5       cgd 		 * reversed.  To be interoperable, we need to determine
   1293       1.5       cgd 		 * which way it is.  If the first recognized character
   1294       1.5       cgd 		 * is a VAR or VALUE, then that will tell us what
   1295       1.5       cgd 		 * type of client it is.  If the fist recognized
   1296       1.5       cgd 		 * character is a USERVAR, then we continue scanning
   1297       1.5       cgd 		 * the suboption looking for two consecutive
   1298       1.5       cgd 		 * VAR or VALUE fields.  We should not get two
   1299       1.5       cgd 		 * consecutive VALUE fields, so finding two
   1300       1.5       cgd 		 * consecutive VALUE or VAR fields will tell us
   1301       1.5       cgd 		 * what the client is.
   1302       1.5       cgd 		 */
   1303       1.5       cgd 		SB_SAVE();
   1304       1.5       cgd 		while (!SB_EOF()) {
   1305       1.5       cgd 			c = SB_GET();
   1306       1.5       cgd 			switch(c) {
   1307       1.5       cgd 			case OLD_ENV_VAR:
   1308       1.5       cgd 				if (last < 0 || last == OLD_ENV_VAR
   1309       1.5       cgd 				    || (empty && (last == OLD_ENV_VALUE)))
   1310       1.5       cgd 					goto env_ovar_ok;
   1311       1.5       cgd 				got_var++;
   1312       1.5       cgd 				last = OLD_ENV_VAR;
   1313       1.5       cgd 				break;
   1314       1.5       cgd 			case OLD_ENV_VALUE:
   1315       1.5       cgd 				if (last < 0 || last == OLD_ENV_VALUE
   1316       1.5       cgd 				    || (empty && (last == OLD_ENV_VAR)))
   1317       1.5       cgd 					goto env_ovar_wrong;
   1318       1.5       cgd 				got_value++;
   1319       1.5       cgd 				last = OLD_ENV_VALUE;
   1320       1.5       cgd 				break;
   1321       1.5       cgd 			case ENV_USERVAR:
   1322       1.5       cgd 				/* count strings of USERVAR as one */
   1323       1.5       cgd 				if (last != ENV_USERVAR)
   1324       1.5       cgd 					got_uservar++;
   1325       1.5       cgd 				if (empty) {
   1326       1.5       cgd 					if (last == OLD_ENV_VALUE)
   1327       1.5       cgd 						goto env_ovar_ok;
   1328       1.5       cgd 					if (last == OLD_ENV_VAR)
   1329       1.5       cgd 						goto env_ovar_wrong;
   1330       1.5       cgd 				}
   1331       1.5       cgd 				last = ENV_USERVAR;
   1332       1.5       cgd 				break;
   1333       1.5       cgd 			case ENV_ESC:
   1334       1.5       cgd 				if (!SB_EOF())
   1335       1.5       cgd 					c = SB_GET();
   1336       1.5       cgd 				/* FALL THROUGH */
   1337       1.5       cgd 			default:
   1338       1.5       cgd 				empty = 0;
   1339       1.5       cgd 				continue;
   1340       1.5       cgd 			}
   1341       1.5       cgd 			empty = 1;
   1342       1.5       cgd 		}
   1343       1.5       cgd 		if (empty) {
   1344       1.5       cgd 			if (last == OLD_ENV_VALUE)
   1345       1.5       cgd 				goto env_ovar_ok;
   1346       1.5       cgd 			if (last == OLD_ENV_VAR)
   1347       1.5       cgd 				goto env_ovar_wrong;
   1348       1.5       cgd 		}
   1349       1.5       cgd 		/*
   1350       1.5       cgd 		 * Ok, the first thing was a USERVAR, and there
   1351       1.5       cgd 		 * are not two consecutive VAR or VALUE commands,
   1352       1.5       cgd 		 * and none of the VAR or VALUE commands are empty.
   1353       1.5       cgd 		 * If the client has sent us a well-formed option,
   1354       1.5       cgd 		 * then the number of VALUEs received should always
   1355       1.5       cgd 		 * be less than or equal to the number of VARs and
   1356       1.5       cgd 		 * USERVARs received.
   1357       1.5       cgd 		 *
   1358       1.5       cgd 		 * If we got exactly as many VALUEs as VARs and
   1359       1.5       cgd 		 * USERVARs, the client has the same definitions.
   1360       1.5       cgd 		 *
   1361       1.5       cgd 		 * If we got exactly as many VARs as VALUEs and
   1362       1.5       cgd 		 * USERVARS, the client has reversed definitions.
   1363       1.5       cgd 		 */
   1364       1.5       cgd 		if (got_uservar + got_var == got_value) {
   1365       1.5       cgd 	    env_ovar_ok:
   1366       1.5       cgd 			env_ovar = OLD_ENV_VAR;
   1367       1.5       cgd 			env_ovalue = OLD_ENV_VALUE;
   1368       1.5       cgd 		} else if (got_uservar + got_value == got_var) {
   1369       1.5       cgd 	    env_ovar_wrong:
   1370       1.5       cgd 			env_ovar = OLD_ENV_VALUE;
   1371       1.5       cgd 			env_ovalue = OLD_ENV_VAR;
   1372       1.5       cgd 			DIAG(TD_OPTIONS, {sprintf(nfrontp,
   1373       1.5       cgd 				"ENVIRON VALUE and VAR are reversed!\r\n");
   1374       1.5       cgd 				nfrontp += strlen(nfrontp);});
   1375       1.1       cgd 
   1376       1.5       cgd 		}
   1377       1.5       cgd 	    }
   1378       1.5       cgd 	    SB_RESTORE();
   1379       1.5       cgd #endif
   1380       1.5       cgd 
   1381       1.5       cgd 	    while (!SB_EOF()) {
   1382       1.5       cgd 		c = SB_GET();
   1383       1.5       cgd 		if ((c == env_ovar) || (c == ENV_USERVAR))
   1384       1.5       cgd 			break;
   1385       1.5       cgd 	    }
   1386       1.5       cgd 	}
   1387       1.1       cgd 
   1388       1.1       cgd 	if (SB_EOF())
   1389       1.1       cgd 		return;
   1390       1.1       cgd 
   1391       1.1       cgd 	cp = varp = (char *)subpointer;
   1392       1.1       cgd 	valp = 0;
   1393       1.1       cgd 
   1394       1.1       cgd 	while (!SB_EOF()) {
   1395       1.5       cgd 		c = SB_GET();
   1396       1.5       cgd 		if (subchar == TELOPT_OLD_ENVIRON) {
   1397       1.5       cgd 			if (c == env_ovar)
   1398       1.5       cgd 				c = NEW_ENV_VAR;
   1399       1.5       cgd 			else if (c == env_ovalue)
   1400       1.5       cgd 				c = NEW_ENV_VALUE;
   1401       1.5       cgd 		}
   1402       1.5       cgd 		switch (c) {
   1403       1.5       cgd 
   1404       1.5       cgd 		case NEW_ENV_VALUE:
   1405       1.1       cgd 			*cp = '\0';
   1406       1.1       cgd 			cp = valp = (char *)subpointer;
   1407       1.1       cgd 			break;
   1408       1.1       cgd 
   1409       1.5       cgd 		case NEW_ENV_VAR:
   1410       1.5       cgd 		case ENV_USERVAR:
   1411       1.1       cgd 			*cp = '\0';
   1412       1.7   ghudson 			if (envvarok(varp)) {
   1413       1.6   ghudson 				if (valp)
   1414       1.6   ghudson 					(void)setenv(varp, valp, 1);
   1415       1.6   ghudson 				else
   1416       1.6   ghudson 					unsetenv(varp);
   1417       1.6   ghudson 			}
   1418       1.1       cgd 			cp = varp = (char *)subpointer;
   1419       1.1       cgd 			valp = 0;
   1420       1.1       cgd 			break;
   1421       1.1       cgd 
   1422       1.1       cgd 		case ENV_ESC:
   1423       1.1       cgd 			if (SB_EOF())
   1424       1.1       cgd 				break;
   1425       1.1       cgd 			c = SB_GET();
   1426       1.1       cgd 			/* FALL THROUGH */
   1427       1.1       cgd 		default:
   1428       1.1       cgd 			*cp++ = c;
   1429       1.1       cgd 			break;
   1430       1.1       cgd 		}
   1431       1.1       cgd 	}
   1432       1.1       cgd 	*cp = '\0';
   1433       1.7   ghudson 	if (envvarok(varp)) {
   1434       1.7   ghudson 		if (valp)
   1435       1.7   ghudson 			(void)setenv(varp, valp, 1);
   1436       1.7   ghudson 		else
   1437       1.7   ghudson 			unsetenv(varp);
   1438       1.7   ghudson 	}
   1439       1.1       cgd 	break;
   1440       1.5       cgd     }  /* end of case TELOPT_NEW_ENVIRON */
   1441       1.5       cgd #if	defined(AUTHENTICATION)
   1442       1.1       cgd     case TELOPT_AUTHENTICATION:
   1443       1.1       cgd 	if (SB_EOF())
   1444       1.1       cgd 		break;
   1445       1.1       cgd 	switch(SB_GET()) {
   1446       1.1       cgd 	case TELQUAL_SEND:
   1447       1.1       cgd 	case TELQUAL_REPLY:
   1448       1.1       cgd 		/*
   1449       1.1       cgd 		 * These are sent by us and cannot be sent by
   1450       1.1       cgd 		 * the client.
   1451       1.1       cgd 		 */
   1452       1.1       cgd 		break;
   1453       1.1       cgd 	case TELQUAL_IS:
   1454       1.1       cgd 		auth_is(subpointer, SB_LEN());
   1455       1.1       cgd 		break;
   1456       1.1       cgd 	case TELQUAL_NAME:
   1457       1.1       cgd 		auth_name(subpointer, SB_LEN());
   1458       1.1       cgd 		break;
   1459       1.1       cgd 	}
   1460       1.1       cgd 	break;
   1461       1.1       cgd #endif
   1462       1.1       cgd 
   1463       1.1       cgd     default:
   1464       1.1       cgd 	break;
   1465       1.1       cgd     }  /* end of switch */
   1466       1.1       cgd 
   1467       1.1       cgd }  /* end of suboption */
   1468       1.1       cgd 
   1469       1.1       cgd 	void
   1470       1.1       cgd doclientstat()
   1471       1.1       cgd {
   1472       1.1       cgd 	clientstat(TELOPT_LINEMODE, WILL, 0);
   1473       1.1       cgd }
   1474       1.1       cgd 
   1475       1.8       jtk #define	ADD(c)	 *ncp++ = c
   1476       1.8       jtk #define	ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; }
   1477       1.1       cgd 	void
   1478       1.1       cgd send_status()
   1479       1.1       cgd {
   1480       1.1       cgd 	unsigned char statusbuf[256];
   1481       1.1       cgd 	register unsigned char *ncp;
   1482       1.1       cgd 	register unsigned char i;
   1483       1.1       cgd 
   1484       1.1       cgd 	ncp = statusbuf;
   1485       1.1       cgd 
   1486       1.1       cgd 	netflush();	/* get rid of anything waiting to go out */
   1487       1.1       cgd 
   1488       1.1       cgd 	ADD(IAC);
   1489       1.1       cgd 	ADD(SB);
   1490       1.1       cgd 	ADD(TELOPT_STATUS);
   1491       1.1       cgd 	ADD(TELQUAL_IS);
   1492       1.1       cgd 
   1493       1.1       cgd 	/*
   1494       1.1       cgd 	 * We check the want_state rather than the current state,
   1495       1.1       cgd 	 * because if we received a DO/WILL for an option that we
   1496       1.1       cgd 	 * don't support, and the other side didn't send a DONT/WONT
   1497       1.1       cgd 	 * in response to our WONT/DONT, then the "state" will be
   1498       1.1       cgd 	 * WILL/DO, and the "want_state" will be WONT/DONT.  We
   1499       1.1       cgd 	 * need to go by the latter.
   1500       1.1       cgd 	 */
   1501       1.5       cgd 	for (i = 0; i < (unsigned char)NTELOPTS; i++) {
   1502       1.1       cgd 		if (my_want_state_is_will(i)) {
   1503       1.1       cgd 			ADD(WILL);
   1504       1.1       cgd 			ADD_DATA(i);
   1505       1.1       cgd 		}
   1506       1.1       cgd 		if (his_want_state_is_will(i)) {
   1507       1.1       cgd 			ADD(DO);
   1508       1.1       cgd 			ADD_DATA(i);
   1509       1.1       cgd 		}
   1510       1.1       cgd 	}
   1511       1.1       cgd 
   1512       1.1       cgd 	if (his_want_state_is_will(TELOPT_LFLOW)) {
   1513       1.1       cgd 		ADD(SB);
   1514       1.1       cgd 		ADD(TELOPT_LFLOW);
   1515       1.5       cgd 		if (flowmode) {
   1516       1.5       cgd 			ADD(LFLOW_ON);
   1517       1.5       cgd 		} else {
   1518       1.5       cgd 			ADD(LFLOW_OFF);
   1519       1.5       cgd 		}
   1520       1.1       cgd 		ADD(SE);
   1521       1.5       cgd 
   1522       1.5       cgd 		if (restartany >= 0) {
   1523       1.8       jtk 			ADD(SB);
   1524       1.5       cgd 			ADD(TELOPT_LFLOW);
   1525       1.5       cgd 			if (restartany) {
   1526       1.5       cgd 				ADD(LFLOW_RESTART_ANY);
   1527       1.5       cgd 			} else {
   1528       1.5       cgd 				ADD(LFLOW_RESTART_XON);
   1529       1.5       cgd 			}
   1530       1.8       jtk 			ADD(SE);
   1531       1.5       cgd 		}
   1532       1.1       cgd 	}
   1533       1.1       cgd 
   1534       1.1       cgd #ifdef	LINEMODE
   1535       1.1       cgd 	if (his_want_state_is_will(TELOPT_LINEMODE)) {
   1536       1.1       cgd 		unsigned char *cp, *cpe;
   1537       1.1       cgd 		int len;
   1538       1.1       cgd 
   1539       1.1       cgd 		ADD(SB);
   1540       1.1       cgd 		ADD(TELOPT_LINEMODE);
   1541       1.1       cgd 		ADD(LM_MODE);
   1542       1.1       cgd 		ADD_DATA(editmode);
   1543       1.1       cgd 		ADD(SE);
   1544       1.1       cgd 
   1545       1.1       cgd 		ADD(SB);
   1546       1.1       cgd 		ADD(TELOPT_LINEMODE);
   1547       1.1       cgd 		ADD(LM_SLC);
   1548       1.1       cgd 		start_slc(0);
   1549       1.1       cgd 		send_slc();
   1550       1.1       cgd 		len = end_slc(&cp);
   1551       1.1       cgd 		for (cpe = cp + len; cp < cpe; cp++)
   1552       1.1       cgd 			ADD_DATA(*cp);
   1553       1.1       cgd 		ADD(SE);
   1554       1.1       cgd 	}
   1555       1.1       cgd #endif	/* LINEMODE */
   1556       1.1       cgd 
   1557       1.1       cgd 	ADD(IAC);
   1558       1.1       cgd 	ADD(SE);
   1559       1.1       cgd 
   1560       1.1       cgd 	writenet(statusbuf, ncp - statusbuf);
   1561       1.1       cgd 	netflush();	/* Send it on its way */
   1562       1.1       cgd 
   1563       1.1       cgd 	DIAG(TD_OPTIONS,
   1564       1.1       cgd 		{printsub('>', statusbuf, ncp - statusbuf); netflush();});
   1565       1.1       cgd }
   1566