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