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