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