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