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