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