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