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