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