1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
3*0Sstevel@tonic-gate * Use is subject to license terms.
4*0Sstevel@tonic-gate */
5*0Sstevel@tonic-gate
6*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
7*0Sstevel@tonic-gate
8*0Sstevel@tonic-gate /*
9*0Sstevel@tonic-gate * Copyright (c) 1988, 1990, 1993
10*0Sstevel@tonic-gate * The Regents of the University of California. All rights reserved.
11*0Sstevel@tonic-gate *
12*0Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without
13*0Sstevel@tonic-gate * modification, are permitted provided that the following conditions
14*0Sstevel@tonic-gate * are met:
15*0Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright
16*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer.
17*0Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright
18*0Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the
19*0Sstevel@tonic-gate * documentation and/or other materials provided with the distribution.
20*0Sstevel@tonic-gate * 3. All advertising materials mentioning features or use of this software
21*0Sstevel@tonic-gate * must display the following acknowledgement:
22*0Sstevel@tonic-gate * This product includes software developed by the University of
23*0Sstevel@tonic-gate * California, Berkeley and its contributors.
24*0Sstevel@tonic-gate * 4. Neither the name of the University nor the names of its contributors
25*0Sstevel@tonic-gate * may be used to endorse or promote products derived from this software
26*0Sstevel@tonic-gate * without specific prior written permission.
27*0Sstevel@tonic-gate *
28*0Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29*0Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30*0Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31*0Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32*0Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33*0Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34*0Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35*0Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36*0Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37*0Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38*0Sstevel@tonic-gate * SUCH DAMAGE.
39*0Sstevel@tonic-gate */
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate #ifndef lint
42*0Sstevel@tonic-gate static char sccsid[] = "@(#)telnet.c 8.1 (Berkeley) 6/6/93";
43*0Sstevel@tonic-gate #endif /* not lint */
44*0Sstevel@tonic-gate
45*0Sstevel@tonic-gate #include <netdb.h>
46*0Sstevel@tonic-gate #include <sys/types.h>
47*0Sstevel@tonic-gate
48*0Sstevel@tonic-gate #include <curses.h>
49*0Sstevel@tonic-gate #include <signal.h>
50*0Sstevel@tonic-gate /*
51*0Sstevel@tonic-gate * By the way, we need to include curses.h before telnet.h since,
52*0Sstevel@tonic-gate * among other things, telnet.h #defines 'DO', which is a variable
53*0Sstevel@tonic-gate * declared in curses.h.
54*0Sstevel@tonic-gate */
55*0Sstevel@tonic-gate
56*0Sstevel@tonic-gate #include <arpa/telnet.h>
57*0Sstevel@tonic-gate
58*0Sstevel@tonic-gate #include <ctype.h>
59*0Sstevel@tonic-gate
60*0Sstevel@tonic-gate #include "ring.h"
61*0Sstevel@tonic-gate
62*0Sstevel@tonic-gate #include "defines.h"
63*0Sstevel@tonic-gate #include "externs.h"
64*0Sstevel@tonic-gate #include "types.h"
65*0Sstevel@tonic-gate #include "general.h"
66*0Sstevel@tonic-gate
67*0Sstevel@tonic-gate #include "auth.h"
68*0Sstevel@tonic-gate #include "encrypt.h"
69*0Sstevel@tonic-gate
70*0Sstevel@tonic-gate #define strip(x) ((x)&0x7f)
71*0Sstevel@tonic-gate
72*0Sstevel@tonic-gate /* Buffer for sub-options */
73*0Sstevel@tonic-gate static unsigned char subbuffer[SUBBUFSIZE];
74*0Sstevel@tonic-gate static unsigned char *subpointer;
75*0Sstevel@tonic-gate static unsigned char *subend;
76*0Sstevel@tonic-gate
77*0Sstevel@tonic-gate #define SB_CLEAR() subpointer = subbuffer;
78*0Sstevel@tonic-gate #define SB_TERM() { subend = subpointer; SB_CLEAR(); }
79*0Sstevel@tonic-gate #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof (subbuffer))) { \
80*0Sstevel@tonic-gate *subpointer++ = (c); \
81*0Sstevel@tonic-gate }
82*0Sstevel@tonic-gate
83*0Sstevel@tonic-gate #define SB_GET() ((*subpointer++)&0xff)
84*0Sstevel@tonic-gate #define SB_PEEK() ((*subpointer)&0xff)
85*0Sstevel@tonic-gate #define SB_EOF() (subpointer >= subend)
86*0Sstevel@tonic-gate #define SB_LEN() (subend - subpointer)
87*0Sstevel@tonic-gate
88*0Sstevel@tonic-gate char options[SUBBUFSIZE]; /* The combined options */
89*0Sstevel@tonic-gate char do_dont_resp[SUBBUFSIZE];
90*0Sstevel@tonic-gate char will_wont_resp[SUBBUFSIZE];
91*0Sstevel@tonic-gate
92*0Sstevel@tonic-gate int eight = 0;
93*0Sstevel@tonic-gate int autologin = 0; /* Autologin anyone? */
94*0Sstevel@tonic-gate int skiprc = 0;
95*0Sstevel@tonic-gate int connected;
96*0Sstevel@tonic-gate int showoptions;
97*0Sstevel@tonic-gate static int ISend; /* trying to send network data in */
98*0Sstevel@tonic-gate int debug = 0;
99*0Sstevel@tonic-gate int crmod;
100*0Sstevel@tonic-gate int netdata; /* Print out network data flow */
101*0Sstevel@tonic-gate int crlf; /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
102*0Sstevel@tonic-gate int telnetport;
103*0Sstevel@tonic-gate int SYNCHing; /* we are in TELNET SYNCH mode */
104*0Sstevel@tonic-gate int flushout; /* flush output */
105*0Sstevel@tonic-gate int autoflush = 0; /* flush output when interrupting? */
106*0Sstevel@tonic-gate int autosynch; /* send interrupt characters with SYNCH? */
107*0Sstevel@tonic-gate int localflow; /* we handle flow control locally */
108*0Sstevel@tonic-gate int restartany; /* if flow control enabled, restart on any character */
109*0Sstevel@tonic-gate int localchars; /* we recognize interrupt/quit */
110*0Sstevel@tonic-gate int donelclchars; /* the user has set "localchars" */
111*0Sstevel@tonic-gate int donebinarytoggle; /* the user has put us in binary */
112*0Sstevel@tonic-gate int dontlecho; /* do we suppress local echoing right now? */
113*0Sstevel@tonic-gate int eof_pending = 0; /* we received a genuine EOF on input, send IAC-EOF */
114*0Sstevel@tonic-gate int globalmode;
115*0Sstevel@tonic-gate
116*0Sstevel@tonic-gate /* spin while waiting for authentication */
117*0Sstevel@tonic-gate boolean_t scheduler_lockout_tty = B_FALSE;
118*0Sstevel@tonic-gate int encrypt_flag = 0;
119*0Sstevel@tonic-gate int forwardable_flag = 0;
120*0Sstevel@tonic-gate int forward_flag = 0;
121*0Sstevel@tonic-gate boolean_t wantencryption = B_FALSE;
122*0Sstevel@tonic-gate
123*0Sstevel@tonic-gate char *prompt = 0;
124*0Sstevel@tonic-gate
125*0Sstevel@tonic-gate cc_t escape;
126*0Sstevel@tonic-gate cc_t rlogin;
127*0Sstevel@tonic-gate boolean_t escape_valid = B_TRUE;
128*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE
129*0Sstevel@tonic-gate cc_t echoc;
130*0Sstevel@tonic-gate #endif
131*0Sstevel@tonic-gate
132*0Sstevel@tonic-gate /*
133*0Sstevel@tonic-gate * Telnet receiver states for fsm
134*0Sstevel@tonic-gate */
135*0Sstevel@tonic-gate #define TS_DATA 0
136*0Sstevel@tonic-gate #define TS_IAC 1
137*0Sstevel@tonic-gate #define TS_WILL 2
138*0Sstevel@tonic-gate #define TS_WONT 3
139*0Sstevel@tonic-gate #define TS_DO 4
140*0Sstevel@tonic-gate #define TS_DONT 5
141*0Sstevel@tonic-gate #define TS_CR 6
142*0Sstevel@tonic-gate #define TS_SB 7 /* sub-option collection */
143*0Sstevel@tonic-gate #define TS_SE 8 /* looking for sub-option end */
144*0Sstevel@tonic-gate
145*0Sstevel@tonic-gate static int telrcv_state;
146*0Sstevel@tonic-gate #ifdef OLD_ENVIRON
147*0Sstevel@tonic-gate static unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
148*0Sstevel@tonic-gate #else
149*0Sstevel@tonic-gate #define telopt_environ TELOPT_NEW_ENVIRON
150*0Sstevel@tonic-gate #endif
151*0Sstevel@tonic-gate
152*0Sstevel@tonic-gate jmp_buf toplevel = { 0 };
153*0Sstevel@tonic-gate jmp_buf peerdied;
154*0Sstevel@tonic-gate
155*0Sstevel@tonic-gate static int flushline;
156*0Sstevel@tonic-gate int linemode;
157*0Sstevel@tonic-gate
158*0Sstevel@tonic-gate int reqd_linemode = 0; /* Set if either new or old line mode in */
159*0Sstevel@tonic-gate /* effect since before initial negotiations */
160*0Sstevel@tonic-gate
161*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE
162*0Sstevel@tonic-gate int kludgelinemode = 1;
163*0Sstevel@tonic-gate #endif
164*0Sstevel@tonic-gate
165*0Sstevel@tonic-gate /*
166*0Sstevel@tonic-gate * The following are some clocks used to decide how to interpret
167*0Sstevel@tonic-gate * the relationship between various variables.
168*0Sstevel@tonic-gate */
169*0Sstevel@tonic-gate
170*0Sstevel@tonic-gate Clocks clocks;
171*0Sstevel@tonic-gate
172*0Sstevel@tonic-gate #ifdef notdef
173*0Sstevel@tonic-gate Modelist modelist[] = {
174*0Sstevel@tonic-gate { "telnet command mode", COMMAND_LINE },
175*0Sstevel@tonic-gate { "character-at-a-time mode", 0 },
176*0Sstevel@tonic-gate { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
177*0Sstevel@tonic-gate { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
178*0Sstevel@tonic-gate { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
179*0Sstevel@tonic-gate { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
180*0Sstevel@tonic-gate { "3270 mode", 0 },
181*0Sstevel@tonic-gate };
182*0Sstevel@tonic-gate #endif
183*0Sstevel@tonic-gate
184*0Sstevel@tonic-gate static void willoption(int);
185*0Sstevel@tonic-gate static void wontoption(int);
186*0Sstevel@tonic-gate static void lm_will(unsigned char *, int);
187*0Sstevel@tonic-gate static void lm_wont(unsigned char *, int);
188*0Sstevel@tonic-gate static void lm_do(unsigned char *, int);
189*0Sstevel@tonic-gate static void lm_dont(unsigned char *, int);
190*0Sstevel@tonic-gate static void slc_init(void);
191*0Sstevel@tonic-gate static void slc_import(int);
192*0Sstevel@tonic-gate static void slc_export(void);
193*0Sstevel@tonic-gate static void slc_start_reply(size_t);
194*0Sstevel@tonic-gate static void slc_add_reply(unsigned char, unsigned char, cc_t);
195*0Sstevel@tonic-gate static void slc_end_reply(void);
196*0Sstevel@tonic-gate static void slc(unsigned char *, int);
197*0Sstevel@tonic-gate static int slc_update(void);
198*0Sstevel@tonic-gate static void env_opt(unsigned char *, int);
199*0Sstevel@tonic-gate static void env_opt_start(void);
200*0Sstevel@tonic-gate static void sendeof(void);
201*0Sstevel@tonic-gate static int is_unique(register char *, register char **, register char **);
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gate /*
204*0Sstevel@tonic-gate * Initialize telnet environment.
205*0Sstevel@tonic-gate */
206*0Sstevel@tonic-gate
207*0Sstevel@tonic-gate int
init_telnet()208*0Sstevel@tonic-gate init_telnet()
209*0Sstevel@tonic-gate {
210*0Sstevel@tonic-gate if (env_init() == 0)
211*0Sstevel@tonic-gate return (0);
212*0Sstevel@tonic-gate
213*0Sstevel@tonic-gate SB_CLEAR();
214*0Sstevel@tonic-gate ClearArray(options);
215*0Sstevel@tonic-gate
216*0Sstevel@tonic-gate connected = ISend = localflow = donebinarytoggle = 0;
217*0Sstevel@tonic-gate restartany = -1;
218*0Sstevel@tonic-gate
219*0Sstevel@tonic-gate SYNCHing = 0;
220*0Sstevel@tonic-gate
221*0Sstevel@tonic-gate /* Don't change NetTrace */
222*0Sstevel@tonic-gate
223*0Sstevel@tonic-gate escape = CONTROL(']');
224*0Sstevel@tonic-gate rlogin = _POSIX_VDISABLE;
225*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE
226*0Sstevel@tonic-gate echoc = CONTROL('E');
227*0Sstevel@tonic-gate #endif
228*0Sstevel@tonic-gate
229*0Sstevel@tonic-gate flushline = 1;
230*0Sstevel@tonic-gate telrcv_state = TS_DATA;
231*0Sstevel@tonic-gate
232*0Sstevel@tonic-gate return (1);
233*0Sstevel@tonic-gate }
234*0Sstevel@tonic-gate
235*0Sstevel@tonic-gate
236*0Sstevel@tonic-gate #ifdef notdef
237*0Sstevel@tonic-gate #include <varargs.h>
238*0Sstevel@tonic-gate
239*0Sstevel@tonic-gate /*VARARGS*/
240*0Sstevel@tonic-gate static void
printring(va_alist)241*0Sstevel@tonic-gate printring(va_alist)
242*0Sstevel@tonic-gate va_dcl
243*0Sstevel@tonic-gate {
244*0Sstevel@tonic-gate va_list ap;
245*0Sstevel@tonic-gate char buffer[100]; /* where things go */
246*0Sstevel@tonic-gate char *ptr;
247*0Sstevel@tonic-gate char *format;
248*0Sstevel@tonic-gate char *string;
249*0Sstevel@tonic-gate Ring *ring;
250*0Sstevel@tonic-gate int i;
251*0Sstevel@tonic-gate
252*0Sstevel@tonic-gate va_start(ap);
253*0Sstevel@tonic-gate
254*0Sstevel@tonic-gate ring = va_arg(ap, Ring *);
255*0Sstevel@tonic-gate format = va_arg(ap, char *);
256*0Sstevel@tonic-gate ptr = buffer;
257*0Sstevel@tonic-gate
258*0Sstevel@tonic-gate while ((i = *format++) != 0) {
259*0Sstevel@tonic-gate if (i == '%') {
260*0Sstevel@tonic-gate i = *format++;
261*0Sstevel@tonic-gate switch (i) {
262*0Sstevel@tonic-gate case 'c':
263*0Sstevel@tonic-gate *ptr++ = va_arg(ap, int);
264*0Sstevel@tonic-gate break;
265*0Sstevel@tonic-gate case 's':
266*0Sstevel@tonic-gate string = va_arg(ap, char *);
267*0Sstevel@tonic-gate ring_supply_data(ring, buffer, ptr-buffer);
268*0Sstevel@tonic-gate ring_supply_data(ring, string, strlen(string));
269*0Sstevel@tonic-gate ptr = buffer;
270*0Sstevel@tonic-gate break;
271*0Sstevel@tonic-gate case 0:
272*0Sstevel@tonic-gate ExitString("printring: trailing %%.\n",
273*0Sstevel@tonic-gate EXIT_FAILURE);
274*0Sstevel@tonic-gate /*NOTREACHED*/
275*0Sstevel@tonic-gate default:
276*0Sstevel@tonic-gate ExitString("printring: unknown format "
277*0Sstevel@tonic-gate "character.\n", EXIT_FAILURE);
278*0Sstevel@tonic-gate /*NOTREACHED*/
279*0Sstevel@tonic-gate }
280*0Sstevel@tonic-gate } else {
281*0Sstevel@tonic-gate *ptr++ = i;
282*0Sstevel@tonic-gate }
283*0Sstevel@tonic-gate }
284*0Sstevel@tonic-gate ring_supply_data(ring, buffer, ptr-buffer);
285*0Sstevel@tonic-gate }
286*0Sstevel@tonic-gate #endif
287*0Sstevel@tonic-gate
288*0Sstevel@tonic-gate /*
289*0Sstevel@tonic-gate * These routines are in charge of sending option negotiations
290*0Sstevel@tonic-gate * to the other side.
291*0Sstevel@tonic-gate *
292*0Sstevel@tonic-gate * The basic idea is that we send the negotiation if either side
293*0Sstevel@tonic-gate * is in disagreement as to what the current state should be.
294*0Sstevel@tonic-gate */
295*0Sstevel@tonic-gate
296*0Sstevel@tonic-gate void
send_do(c,init)297*0Sstevel@tonic-gate send_do(c, init)
298*0Sstevel@tonic-gate register int c, init;
299*0Sstevel@tonic-gate {
300*0Sstevel@tonic-gate if (init) {
301*0Sstevel@tonic-gate if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
302*0Sstevel@tonic-gate my_want_state_is_do(c))
303*0Sstevel@tonic-gate return;
304*0Sstevel@tonic-gate set_my_want_state_do(c);
305*0Sstevel@tonic-gate do_dont_resp[c]++;
306*0Sstevel@tonic-gate }
307*0Sstevel@tonic-gate NET2ADD(IAC, DO);
308*0Sstevel@tonic-gate NETADD(c);
309*0Sstevel@tonic-gate printoption("SENT", DO, c);
310*0Sstevel@tonic-gate }
311*0Sstevel@tonic-gate
312*0Sstevel@tonic-gate void
send_dont(c,init)313*0Sstevel@tonic-gate send_dont(c, init)
314*0Sstevel@tonic-gate register int c, init;
315*0Sstevel@tonic-gate {
316*0Sstevel@tonic-gate if (init) {
317*0Sstevel@tonic-gate if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
318*0Sstevel@tonic-gate my_want_state_is_dont(c))
319*0Sstevel@tonic-gate return;
320*0Sstevel@tonic-gate set_my_want_state_dont(c);
321*0Sstevel@tonic-gate do_dont_resp[c]++;
322*0Sstevel@tonic-gate }
323*0Sstevel@tonic-gate NET2ADD(IAC, DONT);
324*0Sstevel@tonic-gate NETADD(c);
325*0Sstevel@tonic-gate printoption("SENT", DONT, c);
326*0Sstevel@tonic-gate }
327*0Sstevel@tonic-gate
328*0Sstevel@tonic-gate void
send_will(c,init)329*0Sstevel@tonic-gate send_will(c, init)
330*0Sstevel@tonic-gate register int c, init;
331*0Sstevel@tonic-gate {
332*0Sstevel@tonic-gate if (init) {
333*0Sstevel@tonic-gate if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
334*0Sstevel@tonic-gate my_want_state_is_will(c))
335*0Sstevel@tonic-gate return;
336*0Sstevel@tonic-gate set_my_want_state_will(c);
337*0Sstevel@tonic-gate will_wont_resp[c]++;
338*0Sstevel@tonic-gate }
339*0Sstevel@tonic-gate NET2ADD(IAC, WILL);
340*0Sstevel@tonic-gate NETADD(c);
341*0Sstevel@tonic-gate printoption("SENT", WILL, c);
342*0Sstevel@tonic-gate }
343*0Sstevel@tonic-gate
344*0Sstevel@tonic-gate void
send_wont(c,init)345*0Sstevel@tonic-gate send_wont(c, init)
346*0Sstevel@tonic-gate register int c, init;
347*0Sstevel@tonic-gate {
348*0Sstevel@tonic-gate if (init) {
349*0Sstevel@tonic-gate if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
350*0Sstevel@tonic-gate my_want_state_is_wont(c))
351*0Sstevel@tonic-gate return;
352*0Sstevel@tonic-gate set_my_want_state_wont(c);
353*0Sstevel@tonic-gate will_wont_resp[c]++;
354*0Sstevel@tonic-gate }
355*0Sstevel@tonic-gate NET2ADD(IAC, WONT);
356*0Sstevel@tonic-gate NETADD(c);
357*0Sstevel@tonic-gate printoption("SENT", WONT, c);
358*0Sstevel@tonic-gate }
359*0Sstevel@tonic-gate
360*0Sstevel@tonic-gate
361*0Sstevel@tonic-gate static void
willoption(option)362*0Sstevel@tonic-gate willoption(option)
363*0Sstevel@tonic-gate int option;
364*0Sstevel@tonic-gate {
365*0Sstevel@tonic-gate int new_state_ok = 0;
366*0Sstevel@tonic-gate
367*0Sstevel@tonic-gate if (do_dont_resp[option]) {
368*0Sstevel@tonic-gate --do_dont_resp[option];
369*0Sstevel@tonic-gate if (do_dont_resp[option] && my_state_is_do(option))
370*0Sstevel@tonic-gate --do_dont_resp[option];
371*0Sstevel@tonic-gate }
372*0Sstevel@tonic-gate
373*0Sstevel@tonic-gate if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
374*0Sstevel@tonic-gate
375*0Sstevel@tonic-gate switch (option) {
376*0Sstevel@tonic-gate
377*0Sstevel@tonic-gate case TELOPT_ECHO:
378*0Sstevel@tonic-gate case TELOPT_SGA:
379*0Sstevel@tonic-gate if (reqd_linemode && my_state_is_dont(option)) {
380*0Sstevel@tonic-gate break;
381*0Sstevel@tonic-gate }
382*0Sstevel@tonic-gate /* FALLTHROUGH */
383*0Sstevel@tonic-gate case TELOPT_BINARY:
384*0Sstevel@tonic-gate settimer(modenegotiated);
385*0Sstevel@tonic-gate /* FALLTHROUGH */
386*0Sstevel@tonic-gate case TELOPT_STATUS:
387*0Sstevel@tonic-gate case TELOPT_AUTHENTICATION:
388*0Sstevel@tonic-gate /* FALLTHROUGH */
389*0Sstevel@tonic-gate case TELOPT_ENCRYPT:
390*0Sstevel@tonic-gate new_state_ok = 1;
391*0Sstevel@tonic-gate break;
392*0Sstevel@tonic-gate
393*0Sstevel@tonic-gate case TELOPT_TM:
394*0Sstevel@tonic-gate if (flushout)
395*0Sstevel@tonic-gate flushout = 0;
396*0Sstevel@tonic-gate /*
397*0Sstevel@tonic-gate * Special case for TM. If we get back a WILL,
398*0Sstevel@tonic-gate * pretend we got back a WONT.
399*0Sstevel@tonic-gate */
400*0Sstevel@tonic-gate set_my_want_state_dont(option);
401*0Sstevel@tonic-gate set_my_state_dont(option);
402*0Sstevel@tonic-gate return; /* Never reply to TM will's/wont's */
403*0Sstevel@tonic-gate
404*0Sstevel@tonic-gate case TELOPT_LINEMODE:
405*0Sstevel@tonic-gate default:
406*0Sstevel@tonic-gate break;
407*0Sstevel@tonic-gate }
408*0Sstevel@tonic-gate
409*0Sstevel@tonic-gate if (new_state_ok) {
410*0Sstevel@tonic-gate set_my_want_state_do(option);
411*0Sstevel@tonic-gate send_do(option, 0);
412*0Sstevel@tonic-gate setconnmode(0); /* possibly set new tty mode */
413*0Sstevel@tonic-gate } else {
414*0Sstevel@tonic-gate do_dont_resp[option]++;
415*0Sstevel@tonic-gate send_dont(option, 0);
416*0Sstevel@tonic-gate }
417*0Sstevel@tonic-gate }
418*0Sstevel@tonic-gate set_my_state_do(option);
419*0Sstevel@tonic-gate if (option == TELOPT_ENCRYPT)
420*0Sstevel@tonic-gate encrypt_send_support();
421*0Sstevel@tonic-gate }
422*0Sstevel@tonic-gate
423*0Sstevel@tonic-gate static void
wontoption(option)424*0Sstevel@tonic-gate wontoption(option)
425*0Sstevel@tonic-gate int option;
426*0Sstevel@tonic-gate {
427*0Sstevel@tonic-gate if (do_dont_resp[option]) {
428*0Sstevel@tonic-gate --do_dont_resp[option];
429*0Sstevel@tonic-gate if (do_dont_resp[option] && my_state_is_dont(option))
430*0Sstevel@tonic-gate --do_dont_resp[option];
431*0Sstevel@tonic-gate }
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gate if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
434*0Sstevel@tonic-gate
435*0Sstevel@tonic-gate switch (option) {
436*0Sstevel@tonic-gate
437*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE
438*0Sstevel@tonic-gate case TELOPT_SGA:
439*0Sstevel@tonic-gate if (!kludgelinemode)
440*0Sstevel@tonic-gate break;
441*0Sstevel@tonic-gate /* FALLTHROUGH */
442*0Sstevel@tonic-gate #endif
443*0Sstevel@tonic-gate case TELOPT_ECHO:
444*0Sstevel@tonic-gate settimer(modenegotiated);
445*0Sstevel@tonic-gate break;
446*0Sstevel@tonic-gate
447*0Sstevel@tonic-gate case TELOPT_TM:
448*0Sstevel@tonic-gate if (flushout)
449*0Sstevel@tonic-gate flushout = 0;
450*0Sstevel@tonic-gate set_my_want_state_dont(option);
451*0Sstevel@tonic-gate set_my_state_dont(option);
452*0Sstevel@tonic-gate return; /* Never reply to TM will's/wont's */
453*0Sstevel@tonic-gate
454*0Sstevel@tonic-gate default:
455*0Sstevel@tonic-gate break;
456*0Sstevel@tonic-gate }
457*0Sstevel@tonic-gate set_my_want_state_dont(option);
458*0Sstevel@tonic-gate if (my_state_is_do(option))
459*0Sstevel@tonic-gate send_dont(option, 0);
460*0Sstevel@tonic-gate setconnmode(0); /* Set new tty mode */
461*0Sstevel@tonic-gate } else if (option == TELOPT_TM) {
462*0Sstevel@tonic-gate /*
463*0Sstevel@tonic-gate * Special case for TM.
464*0Sstevel@tonic-gate */
465*0Sstevel@tonic-gate if (flushout)
466*0Sstevel@tonic-gate flushout = 0;
467*0Sstevel@tonic-gate set_my_want_state_dont(option);
468*0Sstevel@tonic-gate }
469*0Sstevel@tonic-gate set_my_state_dont(option);
470*0Sstevel@tonic-gate }
471*0Sstevel@tonic-gate
472*0Sstevel@tonic-gate static void
dooption(option)473*0Sstevel@tonic-gate dooption(option)
474*0Sstevel@tonic-gate int option;
475*0Sstevel@tonic-gate {
476*0Sstevel@tonic-gate int new_state_ok = 0;
477*0Sstevel@tonic-gate
478*0Sstevel@tonic-gate if (will_wont_resp[option]) {
479*0Sstevel@tonic-gate --will_wont_resp[option];
480*0Sstevel@tonic-gate if (will_wont_resp[option] && my_state_is_will(option))
481*0Sstevel@tonic-gate --will_wont_resp[option];
482*0Sstevel@tonic-gate }
483*0Sstevel@tonic-gate
484*0Sstevel@tonic-gate if (will_wont_resp[option] == 0) {
485*0Sstevel@tonic-gate if (my_want_state_is_wont(option)) {
486*0Sstevel@tonic-gate
487*0Sstevel@tonic-gate switch (option) {
488*0Sstevel@tonic-gate
489*0Sstevel@tonic-gate case TELOPT_TM:
490*0Sstevel@tonic-gate /*
491*0Sstevel@tonic-gate * Special case for TM. We send a WILL,
492*0Sstevel@tonic-gate * but pretend we sent WONT.
493*0Sstevel@tonic-gate */
494*0Sstevel@tonic-gate send_will(option, 0);
495*0Sstevel@tonic-gate set_my_want_state_wont(TELOPT_TM);
496*0Sstevel@tonic-gate set_my_state_wont(TELOPT_TM);
497*0Sstevel@tonic-gate return;
498*0Sstevel@tonic-gate
499*0Sstevel@tonic-gate case TELOPT_BINARY: /* binary mode */
500*0Sstevel@tonic-gate case TELOPT_NAWS: /* window size */
501*0Sstevel@tonic-gate case TELOPT_TSPEED: /* terminal speed */
502*0Sstevel@tonic-gate case TELOPT_LFLOW: /* local flow control */
503*0Sstevel@tonic-gate case TELOPT_TTYPE: /* terminal type option */
504*0Sstevel@tonic-gate case TELOPT_SGA: /* no big deal */
505*0Sstevel@tonic-gate case TELOPT_ENCRYPT: /* encryption variable option */
506*0Sstevel@tonic-gate new_state_ok = 1;
507*0Sstevel@tonic-gate break;
508*0Sstevel@tonic-gate
509*0Sstevel@tonic-gate case TELOPT_NEW_ENVIRON:
510*0Sstevel@tonic-gate /* New environment variable option */
511*0Sstevel@tonic-gate #ifdef OLD_ENVIRON
512*0Sstevel@tonic-gate if (my_state_is_will(TELOPT_OLD_ENVIRON))
513*0Sstevel@tonic-gate /* turn off the old */
514*0Sstevel@tonic-gate send_wont(TELOPT_OLD_ENVIRON, 1);
515*0Sstevel@tonic-gate goto env_common;
516*0Sstevel@tonic-gate case TELOPT_OLD_ENVIRON:
517*0Sstevel@tonic-gate /* Old environment variable option */
518*0Sstevel@tonic-gate if (my_state_is_will(TELOPT_NEW_ENVIRON))
519*0Sstevel@tonic-gate /* Don't enable if new one is in use! */
520*0Sstevel@tonic-gate break;
521*0Sstevel@tonic-gate env_common:
522*0Sstevel@tonic-gate telopt_environ = option;
523*0Sstevel@tonic-gate #endif
524*0Sstevel@tonic-gate new_state_ok = 1;
525*0Sstevel@tonic-gate break;
526*0Sstevel@tonic-gate
527*0Sstevel@tonic-gate case TELOPT_AUTHENTICATION:
528*0Sstevel@tonic-gate if (autologin)
529*0Sstevel@tonic-gate new_state_ok = 1;
530*0Sstevel@tonic-gate break;
531*0Sstevel@tonic-gate
532*0Sstevel@tonic-gate case TELOPT_XDISPLOC: /* X Display location */
533*0Sstevel@tonic-gate if (env_getvalue((unsigned char *)"DISPLAY"))
534*0Sstevel@tonic-gate new_state_ok = 1;
535*0Sstevel@tonic-gate break;
536*0Sstevel@tonic-gate
537*0Sstevel@tonic-gate case TELOPT_LINEMODE:
538*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE
539*0Sstevel@tonic-gate kludgelinemode = 0;
540*0Sstevel@tonic-gate send_do(TELOPT_SGA, 1);
541*0Sstevel@tonic-gate #endif
542*0Sstevel@tonic-gate set_my_want_state_will(TELOPT_LINEMODE);
543*0Sstevel@tonic-gate send_will(option, 0);
544*0Sstevel@tonic-gate set_my_state_will(TELOPT_LINEMODE);
545*0Sstevel@tonic-gate slc_init();
546*0Sstevel@tonic-gate return;
547*0Sstevel@tonic-gate
548*0Sstevel@tonic-gate case TELOPT_ECHO: /* We're never going to echo... */
549*0Sstevel@tonic-gate default:
550*0Sstevel@tonic-gate break;
551*0Sstevel@tonic-gate }
552*0Sstevel@tonic-gate
553*0Sstevel@tonic-gate if (new_state_ok) {
554*0Sstevel@tonic-gate set_my_want_state_will(option);
555*0Sstevel@tonic-gate send_will(option, 0);
556*0Sstevel@tonic-gate setconnmode(0); /* Set new tty mode */
557*0Sstevel@tonic-gate } else {
558*0Sstevel@tonic-gate will_wont_resp[option]++;
559*0Sstevel@tonic-gate send_wont(option, 0);
560*0Sstevel@tonic-gate }
561*0Sstevel@tonic-gate } else {
562*0Sstevel@tonic-gate /*
563*0Sstevel@tonic-gate * Handle options that need more things done after the
564*0Sstevel@tonic-gate * other side has acknowledged the option.
565*0Sstevel@tonic-gate */
566*0Sstevel@tonic-gate switch (option) {
567*0Sstevel@tonic-gate case TELOPT_LINEMODE:
568*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE
569*0Sstevel@tonic-gate kludgelinemode = 0;
570*0Sstevel@tonic-gate send_do(TELOPT_SGA, 1);
571*0Sstevel@tonic-gate #endif
572*0Sstevel@tonic-gate set_my_state_will(option);
573*0Sstevel@tonic-gate slc_init();
574*0Sstevel@tonic-gate send_do(TELOPT_SGA, 0);
575*0Sstevel@tonic-gate return;
576*0Sstevel@tonic-gate }
577*0Sstevel@tonic-gate }
578*0Sstevel@tonic-gate }
579*0Sstevel@tonic-gate set_my_state_will(option);
580*0Sstevel@tonic-gate }
581*0Sstevel@tonic-gate
582*0Sstevel@tonic-gate static void
dontoption(option)583*0Sstevel@tonic-gate dontoption(option)
584*0Sstevel@tonic-gate int option;
585*0Sstevel@tonic-gate {
586*0Sstevel@tonic-gate
587*0Sstevel@tonic-gate if (will_wont_resp[option]) {
588*0Sstevel@tonic-gate --will_wont_resp[option];
589*0Sstevel@tonic-gate if (will_wont_resp[option] && my_state_is_wont(option))
590*0Sstevel@tonic-gate --will_wont_resp[option];
591*0Sstevel@tonic-gate }
592*0Sstevel@tonic-gate
593*0Sstevel@tonic-gate if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
594*0Sstevel@tonic-gate switch (option) {
595*0Sstevel@tonic-gate case TELOPT_LINEMODE:
596*0Sstevel@tonic-gate linemode = 0; /* put us back to the default state */
597*0Sstevel@tonic-gate break;
598*0Sstevel@tonic-gate #ifdef OLD_ENVIRON
599*0Sstevel@tonic-gate case TELOPT_NEW_ENVIRON:
600*0Sstevel@tonic-gate /*
601*0Sstevel@tonic-gate * The new environ option wasn't recognized, try
602*0Sstevel@tonic-gate * the old one.
603*0Sstevel@tonic-gate */
604*0Sstevel@tonic-gate send_will(TELOPT_OLD_ENVIRON, 1);
605*0Sstevel@tonic-gate telopt_environ = TELOPT_OLD_ENVIRON;
606*0Sstevel@tonic-gate break;
607*0Sstevel@tonic-gate #endif
608*0Sstevel@tonic-gate }
609*0Sstevel@tonic-gate /* we always accept a DONT */
610*0Sstevel@tonic-gate set_my_want_state_wont(option);
611*0Sstevel@tonic-gate if (my_state_is_will(option))
612*0Sstevel@tonic-gate send_wont(option, 0);
613*0Sstevel@tonic-gate setconnmode(0); /* Set new tty mode */
614*0Sstevel@tonic-gate }
615*0Sstevel@tonic-gate set_my_state_wont(option);
616*0Sstevel@tonic-gate }
617*0Sstevel@tonic-gate
618*0Sstevel@tonic-gate /*
619*0Sstevel@tonic-gate * Given a buffer returned by tgetent(), this routine will turn
620*0Sstevel@tonic-gate * the pipe seperated list of names in the buffer into an array
621*0Sstevel@tonic-gate * of pointers to null terminated names. We toss out any bad,
622*0Sstevel@tonic-gate * duplicate, or verbose names (names with spaces).
623*0Sstevel@tonic-gate */
624*0Sstevel@tonic-gate
625*0Sstevel@tonic-gate static char *name_unknown = "UNKNOWN";
626*0Sstevel@tonic-gate static char *unknown[] = { 0, 0 };
627*0Sstevel@tonic-gate
628*0Sstevel@tonic-gate static char **
mklist(buf,name)629*0Sstevel@tonic-gate mklist(buf, name)
630*0Sstevel@tonic-gate char *buf, *name;
631*0Sstevel@tonic-gate {
632*0Sstevel@tonic-gate register int n;
633*0Sstevel@tonic-gate register char c, *cp, **argvp, *cp2, **argv, **avt;
634*0Sstevel@tonic-gate
635*0Sstevel@tonic-gate if (name) {
636*0Sstevel@tonic-gate if (strlen(name) > 40u) {
637*0Sstevel@tonic-gate name = 0;
638*0Sstevel@tonic-gate unknown[0] = name_unknown;
639*0Sstevel@tonic-gate } else {
640*0Sstevel@tonic-gate unknown[0] = name;
641*0Sstevel@tonic-gate upcase(name);
642*0Sstevel@tonic-gate }
643*0Sstevel@tonic-gate } else
644*0Sstevel@tonic-gate unknown[0] = name_unknown;
645*0Sstevel@tonic-gate /*
646*0Sstevel@tonic-gate * Count up the number of names.
647*0Sstevel@tonic-gate */
648*0Sstevel@tonic-gate for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
649*0Sstevel@tonic-gate if (*cp == '|')
650*0Sstevel@tonic-gate n++;
651*0Sstevel@tonic-gate }
652*0Sstevel@tonic-gate /*
653*0Sstevel@tonic-gate * Allocate an array to put the name pointers into
654*0Sstevel@tonic-gate */
655*0Sstevel@tonic-gate argv = malloc((n+3)*sizeof (char *));
656*0Sstevel@tonic-gate if (argv == 0)
657*0Sstevel@tonic-gate return (unknown);
658*0Sstevel@tonic-gate
659*0Sstevel@tonic-gate /*
660*0Sstevel@tonic-gate * Fill up the array of pointers to names.
661*0Sstevel@tonic-gate */
662*0Sstevel@tonic-gate *argv = 0;
663*0Sstevel@tonic-gate argvp = argv+1;
664*0Sstevel@tonic-gate n = 0;
665*0Sstevel@tonic-gate for (cp = cp2 = buf; (c = *cp) != NULL; cp++) {
666*0Sstevel@tonic-gate if (c == '|' || c == ':') {
667*0Sstevel@tonic-gate *cp++ = '\0';
668*0Sstevel@tonic-gate /*
669*0Sstevel@tonic-gate * Skip entries that have spaces or are over 40
670*0Sstevel@tonic-gate * characters long. If this is our environment
671*0Sstevel@tonic-gate * name, then put it up front. Otherwise, as
672*0Sstevel@tonic-gate * long as this is not a duplicate name (case
673*0Sstevel@tonic-gate * insensitive) add it to the list.
674*0Sstevel@tonic-gate */
675*0Sstevel@tonic-gate if (n || (cp - cp2 > 41))
676*0Sstevel@tonic-gate /* EMPTY */;
677*0Sstevel@tonic-gate else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
678*0Sstevel@tonic-gate *argv = cp2;
679*0Sstevel@tonic-gate else if (is_unique(cp2, argv+1, argvp))
680*0Sstevel@tonic-gate *argvp++ = cp2;
681*0Sstevel@tonic-gate if (c == ':')
682*0Sstevel@tonic-gate break;
683*0Sstevel@tonic-gate /*
684*0Sstevel@tonic-gate * Skip multiple delimiters. Reset cp2 to
685*0Sstevel@tonic-gate * the beginning of the next name. Reset n,
686*0Sstevel@tonic-gate * the flag for names with spaces.
687*0Sstevel@tonic-gate */
688*0Sstevel@tonic-gate while ((c = *cp) == '|')
689*0Sstevel@tonic-gate cp++;
690*0Sstevel@tonic-gate cp2 = cp;
691*0Sstevel@tonic-gate n = 0;
692*0Sstevel@tonic-gate }
693*0Sstevel@tonic-gate /*
694*0Sstevel@tonic-gate * Skip entries with spaces or non-ascii values.
695*0Sstevel@tonic-gate * Convert lower case letters to upper case.
696*0Sstevel@tonic-gate */
697*0Sstevel@tonic-gate if ((c == ' ') || !isascii(c))
698*0Sstevel@tonic-gate n = 1;
699*0Sstevel@tonic-gate else if (islower(c))
700*0Sstevel@tonic-gate *cp = toupper(c);
701*0Sstevel@tonic-gate }
702*0Sstevel@tonic-gate
703*0Sstevel@tonic-gate /*
704*0Sstevel@tonic-gate * Check for an old V6 2 character name. If the second
705*0Sstevel@tonic-gate * name points to the beginning of the buffer, and is
706*0Sstevel@tonic-gate * only 2 characters long, move it to the end of the array.
707*0Sstevel@tonic-gate */
708*0Sstevel@tonic-gate if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
709*0Sstevel@tonic-gate --argvp;
710*0Sstevel@tonic-gate for (avt = &argv[1]; avt < argvp; avt++)
711*0Sstevel@tonic-gate *avt = *(avt+1);
712*0Sstevel@tonic-gate *argvp++ = buf;
713*0Sstevel@tonic-gate }
714*0Sstevel@tonic-gate
715*0Sstevel@tonic-gate /*
716*0Sstevel@tonic-gate * Duplicate last name, for TTYPE option, and null
717*0Sstevel@tonic-gate * terminate the array. If we didn't find a match on
718*0Sstevel@tonic-gate * our terminal name, put that name at the beginning.
719*0Sstevel@tonic-gate */
720*0Sstevel@tonic-gate cp = *(argvp-1);
721*0Sstevel@tonic-gate *argvp++ = cp;
722*0Sstevel@tonic-gate *argvp = 0;
723*0Sstevel@tonic-gate
724*0Sstevel@tonic-gate if (*argv == 0) {
725*0Sstevel@tonic-gate if (name)
726*0Sstevel@tonic-gate *argv = name;
727*0Sstevel@tonic-gate else {
728*0Sstevel@tonic-gate --argvp;
729*0Sstevel@tonic-gate for (avt = argv; avt < argvp; avt++)
730*0Sstevel@tonic-gate *avt = *(avt+1);
731*0Sstevel@tonic-gate }
732*0Sstevel@tonic-gate }
733*0Sstevel@tonic-gate if (*argv)
734*0Sstevel@tonic-gate return (argv);
735*0Sstevel@tonic-gate else
736*0Sstevel@tonic-gate return (unknown);
737*0Sstevel@tonic-gate }
738*0Sstevel@tonic-gate
739*0Sstevel@tonic-gate static int
is_unique(name,as,ae)740*0Sstevel@tonic-gate is_unique(name, as, ae)
741*0Sstevel@tonic-gate register char *name, **as, **ae;
742*0Sstevel@tonic-gate {
743*0Sstevel@tonic-gate register char **ap;
744*0Sstevel@tonic-gate register int n;
745*0Sstevel@tonic-gate
746*0Sstevel@tonic-gate n = strlen(name) + 1;
747*0Sstevel@tonic-gate for (ap = as; ap < ae; ap++)
748*0Sstevel@tonic-gate if (strncasecmp(*ap, name, n) == 0)
749*0Sstevel@tonic-gate return (0);
750*0Sstevel@tonic-gate return (1);
751*0Sstevel@tonic-gate }
752*0Sstevel@tonic-gate
753*0Sstevel@tonic-gate #define termbuf ttytype
754*0Sstevel@tonic-gate extern char ttytype[];
755*0Sstevel@tonic-gate
756*0Sstevel@tonic-gate int resettermname = 1;
757*0Sstevel@tonic-gate
758*0Sstevel@tonic-gate static char *
gettermname(void)759*0Sstevel@tonic-gate gettermname(void)
760*0Sstevel@tonic-gate {
761*0Sstevel@tonic-gate char *tname;
762*0Sstevel@tonic-gate static char **tnamep = 0;
763*0Sstevel@tonic-gate static char **next;
764*0Sstevel@tonic-gate int err;
765*0Sstevel@tonic-gate
766*0Sstevel@tonic-gate if (resettermname) {
767*0Sstevel@tonic-gate resettermname = 0;
768*0Sstevel@tonic-gate if (tnamep && tnamep != unknown)
769*0Sstevel@tonic-gate free(tnamep);
770*0Sstevel@tonic-gate tname = (char *)env_getvalue((unsigned char *)"TERM");
771*0Sstevel@tonic-gate if ((tname != NULL) && (setupterm(tname, 1, &err) == 0)) {
772*0Sstevel@tonic-gate tnamep = mklist(termbuf, tname);
773*0Sstevel@tonic-gate } else {
774*0Sstevel@tonic-gate if (tname && (strlen(tname) <= 40u)) {
775*0Sstevel@tonic-gate unknown[0] = tname;
776*0Sstevel@tonic-gate upcase(tname);
777*0Sstevel@tonic-gate } else
778*0Sstevel@tonic-gate unknown[0] = name_unknown;
779*0Sstevel@tonic-gate tnamep = unknown;
780*0Sstevel@tonic-gate }
781*0Sstevel@tonic-gate next = tnamep;
782*0Sstevel@tonic-gate }
783*0Sstevel@tonic-gate if (*next == 0)
784*0Sstevel@tonic-gate next = tnamep;
785*0Sstevel@tonic-gate return (*next++);
786*0Sstevel@tonic-gate }
787*0Sstevel@tonic-gate /*
788*0Sstevel@tonic-gate * suboption()
789*0Sstevel@tonic-gate *
790*0Sstevel@tonic-gate * Look at the sub-option buffer, and try to be helpful to the other
791*0Sstevel@tonic-gate * side.
792*0Sstevel@tonic-gate *
793*0Sstevel@tonic-gate * Currently we recognize:
794*0Sstevel@tonic-gate *
795*0Sstevel@tonic-gate * Terminal type, send request.
796*0Sstevel@tonic-gate * Terminal speed (send request).
797*0Sstevel@tonic-gate * Local flow control (is request).
798*0Sstevel@tonic-gate * Linemode
799*0Sstevel@tonic-gate */
800*0Sstevel@tonic-gate
801*0Sstevel@tonic-gate static void
suboption()802*0Sstevel@tonic-gate suboption()
803*0Sstevel@tonic-gate {
804*0Sstevel@tonic-gate unsigned char subchar;
805*0Sstevel@tonic-gate
806*0Sstevel@tonic-gate printsub('<', subbuffer, SB_LEN()+2);
807*0Sstevel@tonic-gate switch (subchar = SB_GET()) {
808*0Sstevel@tonic-gate case TELOPT_TTYPE:
809*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_TTYPE))
810*0Sstevel@tonic-gate return;
811*0Sstevel@tonic-gate if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
812*0Sstevel@tonic-gate return;
813*0Sstevel@tonic-gate } else {
814*0Sstevel@tonic-gate char *name;
815*0Sstevel@tonic-gate unsigned char temp[50];
816*0Sstevel@tonic-gate int len, bytes;
817*0Sstevel@tonic-gate
818*0Sstevel@tonic-gate name = gettermname();
819*0Sstevel@tonic-gate len = strlen(name) + 4 + 2;
820*0Sstevel@tonic-gate bytes = snprintf((char *)temp, sizeof (temp),
821*0Sstevel@tonic-gate "%c%c%c%c%s%c%c", IAC, SB,
822*0Sstevel@tonic-gate TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE);
823*0Sstevel@tonic-gate if ((len < NETROOM()) && (bytes < sizeof (temp))) {
824*0Sstevel@tonic-gate ring_supply_data(&netoring, temp, len);
825*0Sstevel@tonic-gate printsub('>', &temp[2], len-2);
826*0Sstevel@tonic-gate } else {
827*0Sstevel@tonic-gate ExitString("No room in buffer for "
828*0Sstevel@tonic-gate "terminal type.\n", EXIT_FAILURE);
829*0Sstevel@tonic-gate /*NOTREACHED*/
830*0Sstevel@tonic-gate }
831*0Sstevel@tonic-gate }
832*0Sstevel@tonic-gate break;
833*0Sstevel@tonic-gate case TELOPT_TSPEED:
834*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_TSPEED))
835*0Sstevel@tonic-gate return;
836*0Sstevel@tonic-gate if (SB_EOF())
837*0Sstevel@tonic-gate return;
838*0Sstevel@tonic-gate if (SB_GET() == TELQUAL_SEND) {
839*0Sstevel@tonic-gate int ospeed, ispeed;
840*0Sstevel@tonic-gate unsigned char temp[50];
841*0Sstevel@tonic-gate int len, bytes;
842*0Sstevel@tonic-gate
843*0Sstevel@tonic-gate TerminalSpeeds(&ispeed, &ospeed);
844*0Sstevel@tonic-gate
845*0Sstevel@tonic-gate bytes = snprintf((char *)temp, sizeof (temp),
846*0Sstevel@tonic-gate "%c%c%c%c%d,%d%c%c", IAC, SB,
847*0Sstevel@tonic-gate TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE);
848*0Sstevel@tonic-gate len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
849*0Sstevel@tonic-gate
850*0Sstevel@tonic-gate if ((len < NETROOM()) && (bytes < sizeof (temp))) {
851*0Sstevel@tonic-gate ring_supply_data(&netoring, temp, len);
852*0Sstevel@tonic-gate printsub('>', temp+2, len - 2);
853*0Sstevel@tonic-gate }
854*0Sstevel@tonic-gate else
855*0Sstevel@tonic-gate (void) printf(
856*0Sstevel@tonic-gate "telnet: not enough room in buffer "
857*0Sstevel@tonic-gate "for terminal speed option reply\n");
858*0Sstevel@tonic-gate }
859*0Sstevel@tonic-gate break;
860*0Sstevel@tonic-gate case TELOPT_LFLOW:
861*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_LFLOW))
862*0Sstevel@tonic-gate return;
863*0Sstevel@tonic-gate if (SB_EOF())
864*0Sstevel@tonic-gate return;
865*0Sstevel@tonic-gate switch (SB_GET()) {
866*0Sstevel@tonic-gate case LFLOW_RESTART_ANY:
867*0Sstevel@tonic-gate restartany = 1;
868*0Sstevel@tonic-gate break;
869*0Sstevel@tonic-gate case LFLOW_RESTART_XON:
870*0Sstevel@tonic-gate restartany = 0;
871*0Sstevel@tonic-gate break;
872*0Sstevel@tonic-gate case LFLOW_ON:
873*0Sstevel@tonic-gate localflow = 1;
874*0Sstevel@tonic-gate break;
875*0Sstevel@tonic-gate case LFLOW_OFF:
876*0Sstevel@tonic-gate localflow = 0;
877*0Sstevel@tonic-gate break;
878*0Sstevel@tonic-gate default:
879*0Sstevel@tonic-gate return;
880*0Sstevel@tonic-gate }
881*0Sstevel@tonic-gate setcommandmode();
882*0Sstevel@tonic-gate setconnmode(0);
883*0Sstevel@tonic-gate break;
884*0Sstevel@tonic-gate
885*0Sstevel@tonic-gate case TELOPT_LINEMODE:
886*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_LINEMODE))
887*0Sstevel@tonic-gate return;
888*0Sstevel@tonic-gate if (SB_EOF())
889*0Sstevel@tonic-gate return;
890*0Sstevel@tonic-gate switch (SB_GET()) {
891*0Sstevel@tonic-gate case WILL:
892*0Sstevel@tonic-gate lm_will(subpointer, SB_LEN());
893*0Sstevel@tonic-gate break;
894*0Sstevel@tonic-gate case WONT:
895*0Sstevel@tonic-gate lm_wont(subpointer, SB_LEN());
896*0Sstevel@tonic-gate break;
897*0Sstevel@tonic-gate case DO:
898*0Sstevel@tonic-gate lm_do(subpointer, SB_LEN());
899*0Sstevel@tonic-gate break;
900*0Sstevel@tonic-gate case DONT:
901*0Sstevel@tonic-gate lm_dont(subpointer, SB_LEN());
902*0Sstevel@tonic-gate break;
903*0Sstevel@tonic-gate case LM_SLC:
904*0Sstevel@tonic-gate slc(subpointer, SB_LEN());
905*0Sstevel@tonic-gate break;
906*0Sstevel@tonic-gate case LM_MODE:
907*0Sstevel@tonic-gate lm_mode(subpointer, SB_LEN(), 0);
908*0Sstevel@tonic-gate break;
909*0Sstevel@tonic-gate default:
910*0Sstevel@tonic-gate break;
911*0Sstevel@tonic-gate }
912*0Sstevel@tonic-gate break;
913*0Sstevel@tonic-gate
914*0Sstevel@tonic-gate #ifdef OLD_ENVIRON
915*0Sstevel@tonic-gate case TELOPT_OLD_ENVIRON:
916*0Sstevel@tonic-gate #endif
917*0Sstevel@tonic-gate case TELOPT_NEW_ENVIRON:
918*0Sstevel@tonic-gate if (SB_EOF())
919*0Sstevel@tonic-gate return;
920*0Sstevel@tonic-gate switch (SB_PEEK()) {
921*0Sstevel@tonic-gate case TELQUAL_IS:
922*0Sstevel@tonic-gate case TELQUAL_INFO:
923*0Sstevel@tonic-gate if (my_want_state_is_dont(subchar))
924*0Sstevel@tonic-gate return;
925*0Sstevel@tonic-gate break;
926*0Sstevel@tonic-gate case TELQUAL_SEND:
927*0Sstevel@tonic-gate if (my_want_state_is_wont(subchar)) {
928*0Sstevel@tonic-gate return;
929*0Sstevel@tonic-gate }
930*0Sstevel@tonic-gate break;
931*0Sstevel@tonic-gate default:
932*0Sstevel@tonic-gate return;
933*0Sstevel@tonic-gate }
934*0Sstevel@tonic-gate env_opt(subpointer, SB_LEN());
935*0Sstevel@tonic-gate break;
936*0Sstevel@tonic-gate
937*0Sstevel@tonic-gate case TELOPT_XDISPLOC:
938*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_XDISPLOC))
939*0Sstevel@tonic-gate return;
940*0Sstevel@tonic-gate if (SB_EOF())
941*0Sstevel@tonic-gate return;
942*0Sstevel@tonic-gate if (SB_GET() == TELQUAL_SEND) {
943*0Sstevel@tonic-gate unsigned char temp[50], *dp;
944*0Sstevel@tonic-gate int len, bytes;
945*0Sstevel@tonic-gate
946*0Sstevel@tonic-gate if ((dp = env_getvalue((unsigned char *)"DISPLAY")) ==
947*0Sstevel@tonic-gate NULL) {
948*0Sstevel@tonic-gate /*
949*0Sstevel@tonic-gate * Something happened, we no longer have a
950*0Sstevel@tonic-gate * DISPLAY variable. So, turn off the option.
951*0Sstevel@tonic-gate */
952*0Sstevel@tonic-gate send_wont(TELOPT_XDISPLOC, 1);
953*0Sstevel@tonic-gate break;
954*0Sstevel@tonic-gate }
955*0Sstevel@tonic-gate bytes = snprintf((char *)temp, sizeof (temp),
956*0Sstevel@tonic-gate "%c%c%c%c%s%c%c", IAC, SB,
957*0Sstevel@tonic-gate TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE);
958*0Sstevel@tonic-gate len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
959*0Sstevel@tonic-gate
960*0Sstevel@tonic-gate if ((len < NETROOM()) && (bytes < sizeof (temp))) {
961*0Sstevel@tonic-gate ring_supply_data(&netoring, temp, len);
962*0Sstevel@tonic-gate printsub('>', temp+2, len - 2);
963*0Sstevel@tonic-gate }
964*0Sstevel@tonic-gate else
965*0Sstevel@tonic-gate (void) printf(
966*0Sstevel@tonic-gate "telnet: not enough room in buffer"
967*0Sstevel@tonic-gate " for display location option reply\n");
968*0Sstevel@tonic-gate }
969*0Sstevel@tonic-gate break;
970*0Sstevel@tonic-gate
971*0Sstevel@tonic-gate case TELOPT_AUTHENTICATION: {
972*0Sstevel@tonic-gate if (!autologin)
973*0Sstevel@tonic-gate break;
974*0Sstevel@tonic-gate if (SB_EOF())
975*0Sstevel@tonic-gate return;
976*0Sstevel@tonic-gate switch (SB_GET()) {
977*0Sstevel@tonic-gate case TELQUAL_SEND:
978*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
979*0Sstevel@tonic-gate return;
980*0Sstevel@tonic-gate auth_send(subpointer, SB_LEN());
981*0Sstevel@tonic-gate break;
982*0Sstevel@tonic-gate case TELQUAL_REPLY:
983*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
984*0Sstevel@tonic-gate return;
985*0Sstevel@tonic-gate auth_reply(subpointer, SB_LEN());
986*0Sstevel@tonic-gate break;
987*0Sstevel@tonic-gate }
988*0Sstevel@tonic-gate }
989*0Sstevel@tonic-gate break;
990*0Sstevel@tonic-gate
991*0Sstevel@tonic-gate case TELOPT_ENCRYPT:
992*0Sstevel@tonic-gate if (SB_EOF())
993*0Sstevel@tonic-gate return;
994*0Sstevel@tonic-gate switch (SB_GET()) {
995*0Sstevel@tonic-gate case ENCRYPT_START:
996*0Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_ENCRYPT))
997*0Sstevel@tonic-gate return;
998*0Sstevel@tonic-gate encrypt_start(subpointer, SB_LEN());
999*0Sstevel@tonic-gate break;
1000*0Sstevel@tonic-gate case ENCRYPT_END:
1001*0Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_ENCRYPT))
1002*0Sstevel@tonic-gate return;
1003*0Sstevel@tonic-gate encrypt_end();
1004*0Sstevel@tonic-gate break;
1005*0Sstevel@tonic-gate case ENCRYPT_SUPPORT:
1006*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_ENCRYPT))
1007*0Sstevel@tonic-gate return;
1008*0Sstevel@tonic-gate encrypt_support(subpointer, SB_LEN());
1009*0Sstevel@tonic-gate break;
1010*0Sstevel@tonic-gate case ENCRYPT_REQSTART:
1011*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_ENCRYPT))
1012*0Sstevel@tonic-gate return;
1013*0Sstevel@tonic-gate encrypt_request_start(subpointer, SB_LEN());
1014*0Sstevel@tonic-gate break;
1015*0Sstevel@tonic-gate case ENCRYPT_REQEND:
1016*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_ENCRYPT))
1017*0Sstevel@tonic-gate return;
1018*0Sstevel@tonic-gate /*
1019*0Sstevel@tonic-gate * We can always send an REQEND so that we cannot
1020*0Sstevel@tonic-gate * get stuck encrypting. We should only get this
1021*0Sstevel@tonic-gate * if we have been able to get in the correct mode
1022*0Sstevel@tonic-gate * anyhow.
1023*0Sstevel@tonic-gate */
1024*0Sstevel@tonic-gate encrypt_request_end();
1025*0Sstevel@tonic-gate break;
1026*0Sstevel@tonic-gate case ENCRYPT_IS:
1027*0Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_ENCRYPT))
1028*0Sstevel@tonic-gate return;
1029*0Sstevel@tonic-gate encrypt_is(subpointer, SB_LEN());
1030*0Sstevel@tonic-gate break;
1031*0Sstevel@tonic-gate case ENCRYPT_REPLY:
1032*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_ENCRYPT))
1033*0Sstevel@tonic-gate return;
1034*0Sstevel@tonic-gate encrypt_reply(subpointer, SB_LEN());
1035*0Sstevel@tonic-gate break;
1036*0Sstevel@tonic-gate case ENCRYPT_ENC_KEYID:
1037*0Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_ENCRYPT))
1038*0Sstevel@tonic-gate return;
1039*0Sstevel@tonic-gate encrypt_enc_keyid(subpointer, SB_LEN());
1040*0Sstevel@tonic-gate break;
1041*0Sstevel@tonic-gate case ENCRYPT_DEC_KEYID:
1042*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_ENCRYPT))
1043*0Sstevel@tonic-gate return;
1044*0Sstevel@tonic-gate encrypt_dec_keyid(subpointer, SB_LEN());
1045*0Sstevel@tonic-gate break;
1046*0Sstevel@tonic-gate default:
1047*0Sstevel@tonic-gate break;
1048*0Sstevel@tonic-gate }
1049*0Sstevel@tonic-gate break;
1050*0Sstevel@tonic-gate default:
1051*0Sstevel@tonic-gate break;
1052*0Sstevel@tonic-gate }
1053*0Sstevel@tonic-gate }
1054*0Sstevel@tonic-gate
1055*0Sstevel@tonic-gate static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
1056*0Sstevel@tonic-gate
1057*0Sstevel@tonic-gate static void
lm_will(cmd,len)1058*0Sstevel@tonic-gate lm_will(cmd, len)
1059*0Sstevel@tonic-gate unsigned char *cmd;
1060*0Sstevel@tonic-gate int len;
1061*0Sstevel@tonic-gate {
1062*0Sstevel@tonic-gate if (len < 1) {
1063*0Sstevel@tonic-gate /* Should not happen... */
1064*0Sstevel@tonic-gate (void) printf(
1065*0Sstevel@tonic-gate "telnet: command missing from linemode WILL request\n");
1066*0Sstevel@tonic-gate return;
1067*0Sstevel@tonic-gate }
1068*0Sstevel@tonic-gate switch (cmd[0]) {
1069*0Sstevel@tonic-gate case LM_FORWARDMASK: /* We shouldn't ever get this... */
1070*0Sstevel@tonic-gate default:
1071*0Sstevel@tonic-gate str_lm[3] = DONT;
1072*0Sstevel@tonic-gate str_lm[4] = cmd[0];
1073*0Sstevel@tonic-gate if (NETROOM() > sizeof (str_lm)) {
1074*0Sstevel@tonic-gate ring_supply_data(&netoring, str_lm, sizeof (str_lm));
1075*0Sstevel@tonic-gate printsub('>', &str_lm[2], sizeof (str_lm)-2);
1076*0Sstevel@tonic-gate }
1077*0Sstevel@tonic-gate else
1078*0Sstevel@tonic-gate (void) printf("telnet: not enough room in buffer for"
1079*0Sstevel@tonic-gate "reply to linemode WILL request\n");
1080*0Sstevel@tonic-gate break;
1081*0Sstevel@tonic-gate }
1082*0Sstevel@tonic-gate }
1083*0Sstevel@tonic-gate
1084*0Sstevel@tonic-gate static void
lm_wont(cmd,len)1085*0Sstevel@tonic-gate lm_wont(cmd, len)
1086*0Sstevel@tonic-gate unsigned char *cmd;
1087*0Sstevel@tonic-gate int len;
1088*0Sstevel@tonic-gate {
1089*0Sstevel@tonic-gate if (len < 1) {
1090*0Sstevel@tonic-gate /* Should not happen... */
1091*0Sstevel@tonic-gate (void) printf(
1092*0Sstevel@tonic-gate "telnet: command missing from linemode WONT request\n");
1093*0Sstevel@tonic-gate return;
1094*0Sstevel@tonic-gate }
1095*0Sstevel@tonic-gate switch (cmd[0]) {
1096*0Sstevel@tonic-gate case LM_FORWARDMASK: /* We shouldn't ever get this... */
1097*0Sstevel@tonic-gate default:
1098*0Sstevel@tonic-gate /* We are always DONT, so don't respond */
1099*0Sstevel@tonic-gate return;
1100*0Sstevel@tonic-gate }
1101*0Sstevel@tonic-gate }
1102*0Sstevel@tonic-gate
1103*0Sstevel@tonic-gate static void
lm_do(cmd,len)1104*0Sstevel@tonic-gate lm_do(cmd, len)
1105*0Sstevel@tonic-gate unsigned char *cmd;
1106*0Sstevel@tonic-gate int len;
1107*0Sstevel@tonic-gate {
1108*0Sstevel@tonic-gate if (len < 1) {
1109*0Sstevel@tonic-gate /* Should not happen... */
1110*0Sstevel@tonic-gate (void) printf(
1111*0Sstevel@tonic-gate "telnet: command missing from linemode DO request\n");
1112*0Sstevel@tonic-gate return;
1113*0Sstevel@tonic-gate }
1114*0Sstevel@tonic-gate switch (cmd[0]) {
1115*0Sstevel@tonic-gate case LM_FORWARDMASK:
1116*0Sstevel@tonic-gate default:
1117*0Sstevel@tonic-gate str_lm[3] = WONT;
1118*0Sstevel@tonic-gate str_lm[4] = cmd[0];
1119*0Sstevel@tonic-gate if (NETROOM() > sizeof (str_lm)) {
1120*0Sstevel@tonic-gate ring_supply_data(&netoring, str_lm, sizeof (str_lm));
1121*0Sstevel@tonic-gate printsub('>', &str_lm[2], sizeof (str_lm)-2);
1122*0Sstevel@tonic-gate }
1123*0Sstevel@tonic-gate else
1124*0Sstevel@tonic-gate (void) printf("telnet: not enough room in buffer for"
1125*0Sstevel@tonic-gate "reply to linemode DO request\n");
1126*0Sstevel@tonic-gate break;
1127*0Sstevel@tonic-gate }
1128*0Sstevel@tonic-gate }
1129*0Sstevel@tonic-gate
1130*0Sstevel@tonic-gate static void
lm_dont(cmd,len)1131*0Sstevel@tonic-gate lm_dont(cmd, len)
1132*0Sstevel@tonic-gate unsigned char *cmd;
1133*0Sstevel@tonic-gate int len;
1134*0Sstevel@tonic-gate {
1135*0Sstevel@tonic-gate if (len < 1) {
1136*0Sstevel@tonic-gate /* Should not happen... */
1137*0Sstevel@tonic-gate (void) printf(
1138*0Sstevel@tonic-gate "telnet: command missing from linemode DONT request\n");
1139*0Sstevel@tonic-gate return;
1140*0Sstevel@tonic-gate }
1141*0Sstevel@tonic-gate switch (cmd[0]) {
1142*0Sstevel@tonic-gate case LM_FORWARDMASK:
1143*0Sstevel@tonic-gate default:
1144*0Sstevel@tonic-gate /* we are always WONT, so don't respond */
1145*0Sstevel@tonic-gate break;
1146*0Sstevel@tonic-gate }
1147*0Sstevel@tonic-gate }
1148*0Sstevel@tonic-gate
1149*0Sstevel@tonic-gate static unsigned char str_lm_mode[] = {
1150*0Sstevel@tonic-gate IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1151*0Sstevel@tonic-gate };
1152*0Sstevel@tonic-gate
1153*0Sstevel@tonic-gate void
lm_mode(cmd,len,init)1154*0Sstevel@tonic-gate lm_mode(cmd, len, init)
1155*0Sstevel@tonic-gate unsigned char *cmd;
1156*0Sstevel@tonic-gate int len, init;
1157*0Sstevel@tonic-gate {
1158*0Sstevel@tonic-gate if (len != 1)
1159*0Sstevel@tonic-gate return;
1160*0Sstevel@tonic-gate if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1161*0Sstevel@tonic-gate return;
1162*0Sstevel@tonic-gate linemode = *cmd&(MODE_MASK&~MODE_ACK);
1163*0Sstevel@tonic-gate str_lm_mode[4] = linemode;
1164*0Sstevel@tonic-gate if (!init)
1165*0Sstevel@tonic-gate str_lm_mode[4] |= MODE_ACK;
1166*0Sstevel@tonic-gate if (NETROOM() > sizeof (str_lm_mode)) {
1167*0Sstevel@tonic-gate ring_supply_data(&netoring, str_lm_mode, sizeof (str_lm_mode));
1168*0Sstevel@tonic-gate printsub('>', &str_lm_mode[2], sizeof (str_lm_mode)-2);
1169*0Sstevel@tonic-gate }
1170*0Sstevel@tonic-gate else
1171*0Sstevel@tonic-gate (void) printf("telnet: not enough room in buffer for"
1172*0Sstevel@tonic-gate "reply to linemode request\n");
1173*0Sstevel@tonic-gate setconnmode(0); /* set changed mode */
1174*0Sstevel@tonic-gate }
1175*0Sstevel@tonic-gate
1176*0Sstevel@tonic-gate
1177*0Sstevel@tonic-gate
1178*0Sstevel@tonic-gate /*
1179*0Sstevel@tonic-gate * slc()
1180*0Sstevel@tonic-gate * Handle special character suboption of LINEMODE.
1181*0Sstevel@tonic-gate */
1182*0Sstevel@tonic-gate
1183*0Sstevel@tonic-gate static struct spc {
1184*0Sstevel@tonic-gate cc_t val;
1185*0Sstevel@tonic-gate cc_t *valp;
1186*0Sstevel@tonic-gate char flags; /* Current flags & level */
1187*0Sstevel@tonic-gate char mylevel; /* Maximum level & flags */
1188*0Sstevel@tonic-gate } spc_data[NSLC+1];
1189*0Sstevel@tonic-gate
1190*0Sstevel@tonic-gate #define SLC_IMPORT 0
1191*0Sstevel@tonic-gate #define SLC_EXPORT 1
1192*0Sstevel@tonic-gate #define SLC_RVALUE 2
1193*0Sstevel@tonic-gate static int slc_mode = SLC_EXPORT;
1194*0Sstevel@tonic-gate
1195*0Sstevel@tonic-gate static void
slc_init()1196*0Sstevel@tonic-gate slc_init()
1197*0Sstevel@tonic-gate {
1198*0Sstevel@tonic-gate register struct spc *spcp;
1199*0Sstevel@tonic-gate
1200*0Sstevel@tonic-gate localchars = 1;
1201*0Sstevel@tonic-gate for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1202*0Sstevel@tonic-gate spcp->val = 0;
1203*0Sstevel@tonic-gate spcp->valp = 0;
1204*0Sstevel@tonic-gate spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1205*0Sstevel@tonic-gate }
1206*0Sstevel@tonic-gate
1207*0Sstevel@tonic-gate #define initfunc(func, flags) { \
1208*0Sstevel@tonic-gate spcp = &spc_data[func]; \
1209*0Sstevel@tonic-gate if (spcp->valp = tcval(func)) { \
1210*0Sstevel@tonic-gate spcp->val = *spcp->valp; \
1211*0Sstevel@tonic-gate spcp->mylevel = SLC_VARIABLE|(flags);\
1212*0Sstevel@tonic-gate } else { \
1213*0Sstevel@tonic-gate spcp->val = 0; \
1214*0Sstevel@tonic-gate spcp->mylevel = SLC_DEFAULT; \
1215*0Sstevel@tonic-gate } \
1216*0Sstevel@tonic-gate }
1217*0Sstevel@tonic-gate
1218*0Sstevel@tonic-gate initfunc(SLC_SYNCH, 0);
1219*0Sstevel@tonic-gate /* No BRK */
1220*0Sstevel@tonic-gate initfunc(SLC_AO, 0);
1221*0Sstevel@tonic-gate initfunc(SLC_AYT, 0);
1222*0Sstevel@tonic-gate /* No EOR */
1223*0Sstevel@tonic-gate initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1224*0Sstevel@tonic-gate initfunc(SLC_EOF, 0);
1225*0Sstevel@tonic-gate initfunc(SLC_SUSP, SLC_FLUSHIN);
1226*0Sstevel@tonic-gate initfunc(SLC_EC, 0);
1227*0Sstevel@tonic-gate initfunc(SLC_EL, 0);
1228*0Sstevel@tonic-gate initfunc(SLC_EW, 0);
1229*0Sstevel@tonic-gate initfunc(SLC_RP, 0);
1230*0Sstevel@tonic-gate initfunc(SLC_LNEXT, 0);
1231*0Sstevel@tonic-gate initfunc(SLC_XON, 0);
1232*0Sstevel@tonic-gate initfunc(SLC_XOFF, 0);
1233*0Sstevel@tonic-gate initfunc(SLC_FORW1, 0);
1234*0Sstevel@tonic-gate #ifdef USE_TERMIO
1235*0Sstevel@tonic-gate initfunc(SLC_FORW2, 0);
1236*0Sstevel@tonic-gate /* No FORW2 */
1237*0Sstevel@tonic-gate #endif
1238*0Sstevel@tonic-gate
1239*0Sstevel@tonic-gate initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1240*0Sstevel@tonic-gate #undef initfunc
1241*0Sstevel@tonic-gate
1242*0Sstevel@tonic-gate if (slc_mode == SLC_EXPORT)
1243*0Sstevel@tonic-gate slc_export();
1244*0Sstevel@tonic-gate else
1245*0Sstevel@tonic-gate slc_import(1);
1246*0Sstevel@tonic-gate
1247*0Sstevel@tonic-gate }
1248*0Sstevel@tonic-gate
1249*0Sstevel@tonic-gate void
slcstate()1250*0Sstevel@tonic-gate slcstate()
1251*0Sstevel@tonic-gate {
1252*0Sstevel@tonic-gate (void) printf("Special characters are %s values\n",
1253*0Sstevel@tonic-gate slc_mode == SLC_IMPORT ? "remote default" :
1254*0Sstevel@tonic-gate slc_mode == SLC_EXPORT ? "local" :
1255*0Sstevel@tonic-gate "remote");
1256*0Sstevel@tonic-gate }
1257*0Sstevel@tonic-gate
1258*0Sstevel@tonic-gate void
slc_mode_export()1259*0Sstevel@tonic-gate slc_mode_export()
1260*0Sstevel@tonic-gate {
1261*0Sstevel@tonic-gate slc_mode = SLC_EXPORT;
1262*0Sstevel@tonic-gate if (my_state_is_will(TELOPT_LINEMODE))
1263*0Sstevel@tonic-gate slc_export();
1264*0Sstevel@tonic-gate }
1265*0Sstevel@tonic-gate
1266*0Sstevel@tonic-gate void
slc_mode_import(def)1267*0Sstevel@tonic-gate slc_mode_import(def)
1268*0Sstevel@tonic-gate int def;
1269*0Sstevel@tonic-gate {
1270*0Sstevel@tonic-gate slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1271*0Sstevel@tonic-gate if (my_state_is_will(TELOPT_LINEMODE))
1272*0Sstevel@tonic-gate slc_import(def);
1273*0Sstevel@tonic-gate }
1274*0Sstevel@tonic-gate
1275*0Sstevel@tonic-gate static unsigned char slc_import_val[] = {
1276*0Sstevel@tonic-gate IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1277*0Sstevel@tonic-gate };
1278*0Sstevel@tonic-gate static unsigned char slc_import_def[] = {
1279*0Sstevel@tonic-gate IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1280*0Sstevel@tonic-gate };
1281*0Sstevel@tonic-gate
1282*0Sstevel@tonic-gate static void
slc_import(def)1283*0Sstevel@tonic-gate slc_import(def)
1284*0Sstevel@tonic-gate int def;
1285*0Sstevel@tonic-gate {
1286*0Sstevel@tonic-gate if (NETROOM() > sizeof (slc_import_val)) {
1287*0Sstevel@tonic-gate if (def) {
1288*0Sstevel@tonic-gate ring_supply_data(&netoring, slc_import_def,
1289*0Sstevel@tonic-gate sizeof (slc_import_def));
1290*0Sstevel@tonic-gate printsub('>', &slc_import_def[2],
1291*0Sstevel@tonic-gate sizeof (slc_import_def)-2);
1292*0Sstevel@tonic-gate } else {
1293*0Sstevel@tonic-gate ring_supply_data(&netoring, slc_import_val,
1294*0Sstevel@tonic-gate sizeof (slc_import_val));
1295*0Sstevel@tonic-gate printsub('>', &slc_import_val[2],
1296*0Sstevel@tonic-gate sizeof (slc_import_val)-2);
1297*0Sstevel@tonic-gate }
1298*0Sstevel@tonic-gate }
1299*0Sstevel@tonic-gate else
1300*0Sstevel@tonic-gate (void) printf(
1301*0Sstevel@tonic-gate "telnet: not enough room in buffer for slc import"
1302*0Sstevel@tonic-gate " request\n");
1303*0Sstevel@tonic-gate }
1304*0Sstevel@tonic-gate
1305*0Sstevel@tonic-gate static uchar_t *slc_reply = NULL;
1306*0Sstevel@tonic-gate static uchar_t *slc_replyp = NULL;
1307*0Sstevel@tonic-gate /*
1308*0Sstevel@tonic-gate * The SLC reply consists of: IAC, SB, TELOPT_LINEMODE, LM_SLC,
1309*0Sstevel@tonic-gate * SLC triplets[], IAC, SE. i.e. it has a 'wrapper' of 6 control characters.
1310*0Sstevel@tonic-gate */
1311*0Sstevel@tonic-gate #define SLC_WRAPPER_SIZE 6
1312*0Sstevel@tonic-gate
1313*0Sstevel@tonic-gate static void
slc_export()1314*0Sstevel@tonic-gate slc_export()
1315*0Sstevel@tonic-gate {
1316*0Sstevel@tonic-gate register struct spc *spcp;
1317*0Sstevel@tonic-gate
1318*0Sstevel@tonic-gate TerminalDefaultChars();
1319*0Sstevel@tonic-gate
1320*0Sstevel@tonic-gate slc_start_reply(NSLC * 3); /* 3 bytes needed per triplet */
1321*0Sstevel@tonic-gate for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1322*0Sstevel@tonic-gate if (spcp->mylevel != SLC_NOSUPPORT) {
1323*0Sstevel@tonic-gate if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1324*0Sstevel@tonic-gate spcp->flags = SLC_NOSUPPORT;
1325*0Sstevel@tonic-gate else
1326*0Sstevel@tonic-gate spcp->flags = spcp->mylevel;
1327*0Sstevel@tonic-gate if (spcp->valp)
1328*0Sstevel@tonic-gate spcp->val = *spcp->valp;
1329*0Sstevel@tonic-gate slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1330*0Sstevel@tonic-gate }
1331*0Sstevel@tonic-gate }
1332*0Sstevel@tonic-gate slc_end_reply();
1333*0Sstevel@tonic-gate (void) slc_update();
1334*0Sstevel@tonic-gate setconnmode(1); /* Make sure the character values are set */
1335*0Sstevel@tonic-gate }
1336*0Sstevel@tonic-gate
1337*0Sstevel@tonic-gate static void
slc(cp,len)1338*0Sstevel@tonic-gate slc(cp, len)
1339*0Sstevel@tonic-gate register unsigned char *cp;
1340*0Sstevel@tonic-gate int len;
1341*0Sstevel@tonic-gate {
1342*0Sstevel@tonic-gate register struct spc *spcp;
1343*0Sstevel@tonic-gate register int func, level;
1344*0Sstevel@tonic-gate
1345*0Sstevel@tonic-gate slc_start_reply(len);
1346*0Sstevel@tonic-gate
1347*0Sstevel@tonic-gate for (; len >= 3; len -= 3, cp += 3) {
1348*0Sstevel@tonic-gate
1349*0Sstevel@tonic-gate func = cp[SLC_FUNC];
1350*0Sstevel@tonic-gate
1351*0Sstevel@tonic-gate if (func == 0) {
1352*0Sstevel@tonic-gate /*
1353*0Sstevel@tonic-gate * Client side: always ignore 0 function.
1354*0Sstevel@tonic-gate */
1355*0Sstevel@tonic-gate continue;
1356*0Sstevel@tonic-gate }
1357*0Sstevel@tonic-gate if (func > NSLC) {
1358*0Sstevel@tonic-gate if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1359*0Sstevel@tonic-gate slc_add_reply(func, SLC_NOSUPPORT, 0);
1360*0Sstevel@tonic-gate continue;
1361*0Sstevel@tonic-gate }
1362*0Sstevel@tonic-gate
1363*0Sstevel@tonic-gate spcp = &spc_data[func];
1364*0Sstevel@tonic-gate
1365*0Sstevel@tonic-gate level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1366*0Sstevel@tonic-gate
1367*0Sstevel@tonic-gate if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1368*0Sstevel@tonic-gate ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1369*0Sstevel@tonic-gate continue;
1370*0Sstevel@tonic-gate }
1371*0Sstevel@tonic-gate
1372*0Sstevel@tonic-gate if (level == (SLC_DEFAULT|SLC_ACK)) {
1373*0Sstevel@tonic-gate /*
1374*0Sstevel@tonic-gate * This is an error condition, the SLC_ACK
1375*0Sstevel@tonic-gate * bit should never be set for the SLC_DEFAULT
1376*0Sstevel@tonic-gate * level. Our best guess to recover is to
1377*0Sstevel@tonic-gate * ignore the SLC_ACK bit.
1378*0Sstevel@tonic-gate */
1379*0Sstevel@tonic-gate cp[SLC_FLAGS] &= ~SLC_ACK;
1380*0Sstevel@tonic-gate }
1381*0Sstevel@tonic-gate
1382*0Sstevel@tonic-gate if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1383*0Sstevel@tonic-gate spcp->val = (cc_t)cp[SLC_VALUE];
1384*0Sstevel@tonic-gate spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
1385*0Sstevel@tonic-gate continue;
1386*0Sstevel@tonic-gate }
1387*0Sstevel@tonic-gate
1388*0Sstevel@tonic-gate level &= ~SLC_ACK;
1389*0Sstevel@tonic-gate
1390*0Sstevel@tonic-gate if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1391*0Sstevel@tonic-gate spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1392*0Sstevel@tonic-gate spcp->val = (cc_t)cp[SLC_VALUE];
1393*0Sstevel@tonic-gate }
1394*0Sstevel@tonic-gate if (level == SLC_DEFAULT) {
1395*0Sstevel@tonic-gate if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1396*0Sstevel@tonic-gate spcp->flags = spcp->mylevel;
1397*0Sstevel@tonic-gate else
1398*0Sstevel@tonic-gate spcp->flags = SLC_NOSUPPORT;
1399*0Sstevel@tonic-gate }
1400*0Sstevel@tonic-gate slc_add_reply(func, spcp->flags, spcp->val);
1401*0Sstevel@tonic-gate }
1402*0Sstevel@tonic-gate slc_end_reply();
1403*0Sstevel@tonic-gate if (slc_update())
1404*0Sstevel@tonic-gate setconnmode(1); /* set the new character values */
1405*0Sstevel@tonic-gate }
1406*0Sstevel@tonic-gate
1407*0Sstevel@tonic-gate void
slc_check()1408*0Sstevel@tonic-gate slc_check()
1409*0Sstevel@tonic-gate {
1410*0Sstevel@tonic-gate register struct spc *spcp;
1411*0Sstevel@tonic-gate
1412*0Sstevel@tonic-gate slc_start_reply(NSLC * 3); /* 3 bytes needed per triplet */
1413*0Sstevel@tonic-gate for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1414*0Sstevel@tonic-gate if (spcp->valp && spcp->val != *spcp->valp) {
1415*0Sstevel@tonic-gate spcp->val = *spcp->valp;
1416*0Sstevel@tonic-gate if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1417*0Sstevel@tonic-gate spcp->flags = SLC_NOSUPPORT;
1418*0Sstevel@tonic-gate else
1419*0Sstevel@tonic-gate spcp->flags = spcp->mylevel;
1420*0Sstevel@tonic-gate slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1421*0Sstevel@tonic-gate }
1422*0Sstevel@tonic-gate }
1423*0Sstevel@tonic-gate slc_end_reply();
1424*0Sstevel@tonic-gate setconnmode(1);
1425*0Sstevel@tonic-gate }
1426*0Sstevel@tonic-gate
1427*0Sstevel@tonic-gate static void
slc_start_reply(size_t len)1428*0Sstevel@tonic-gate slc_start_reply(size_t len)
1429*0Sstevel@tonic-gate {
1430*0Sstevel@tonic-gate /*
1431*0Sstevel@tonic-gate * SLC triplets may contain escaped characters, allow for
1432*0Sstevel@tonic-gate * worst case by allocating 2 bytes for every character.
1433*0Sstevel@tonic-gate */
1434*0Sstevel@tonic-gate slc_reply = realloc(slc_reply, (len * 2) + SLC_WRAPPER_SIZE);
1435*0Sstevel@tonic-gate if (slc_reply == NULL) {
1436*0Sstevel@tonic-gate fprintf(stderr, "telnet: error allocating SLC reply memory\n");
1437*0Sstevel@tonic-gate return;
1438*0Sstevel@tonic-gate }
1439*0Sstevel@tonic-gate slc_replyp = slc_reply;
1440*0Sstevel@tonic-gate *slc_replyp++ = IAC;
1441*0Sstevel@tonic-gate *slc_replyp++ = SB;
1442*0Sstevel@tonic-gate *slc_replyp++ = TELOPT_LINEMODE;
1443*0Sstevel@tonic-gate *slc_replyp++ = LM_SLC;
1444*0Sstevel@tonic-gate }
1445*0Sstevel@tonic-gate
1446*0Sstevel@tonic-gate static void
slc_add_reply(unsigned char func,unsigned char flags,cc_t value)1447*0Sstevel@tonic-gate slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
1448*0Sstevel@tonic-gate {
1449*0Sstevel@tonic-gate if ((*slc_replyp++ = func) == IAC)
1450*0Sstevel@tonic-gate *slc_replyp++ = IAC;
1451*0Sstevel@tonic-gate if ((*slc_replyp++ = flags) == IAC)
1452*0Sstevel@tonic-gate *slc_replyp++ = IAC;
1453*0Sstevel@tonic-gate if ((*slc_replyp++ = (unsigned char)value) == IAC)
1454*0Sstevel@tonic-gate *slc_replyp++ = IAC;
1455*0Sstevel@tonic-gate }
1456*0Sstevel@tonic-gate
1457*0Sstevel@tonic-gate static void
slc_end_reply()1458*0Sstevel@tonic-gate slc_end_reply()
1459*0Sstevel@tonic-gate {
1460*0Sstevel@tonic-gate register int len;
1461*0Sstevel@tonic-gate
1462*0Sstevel@tonic-gate *slc_replyp++ = IAC;
1463*0Sstevel@tonic-gate *slc_replyp++ = SE;
1464*0Sstevel@tonic-gate len = slc_replyp - slc_reply;
1465*0Sstevel@tonic-gate if (len <= SLC_WRAPPER_SIZE)
1466*0Sstevel@tonic-gate return;
1467*0Sstevel@tonic-gate if (NETROOM() > len) {
1468*0Sstevel@tonic-gate ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1469*0Sstevel@tonic-gate printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1470*0Sstevel@tonic-gate }
1471*0Sstevel@tonic-gate else
1472*0Sstevel@tonic-gate (void) printf("telnet: not enough room in buffer for slc end "
1473*0Sstevel@tonic-gate "reply\n");
1474*0Sstevel@tonic-gate }
1475*0Sstevel@tonic-gate
1476*0Sstevel@tonic-gate static int
slc_update()1477*0Sstevel@tonic-gate slc_update()
1478*0Sstevel@tonic-gate {
1479*0Sstevel@tonic-gate register struct spc *spcp;
1480*0Sstevel@tonic-gate int need_update = 0;
1481*0Sstevel@tonic-gate
1482*0Sstevel@tonic-gate for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1483*0Sstevel@tonic-gate if (!(spcp->flags&SLC_ACK))
1484*0Sstevel@tonic-gate continue;
1485*0Sstevel@tonic-gate spcp->flags &= ~SLC_ACK;
1486*0Sstevel@tonic-gate if (spcp->valp && (*spcp->valp != spcp->val)) {
1487*0Sstevel@tonic-gate *spcp->valp = spcp->val;
1488*0Sstevel@tonic-gate need_update = 1;
1489*0Sstevel@tonic-gate }
1490*0Sstevel@tonic-gate }
1491*0Sstevel@tonic-gate return (need_update);
1492*0Sstevel@tonic-gate }
1493*0Sstevel@tonic-gate
1494*0Sstevel@tonic-gate #ifdef OLD_ENVIRON
1495*0Sstevel@tonic-gate #ifdef ENV_HACK
1496*0Sstevel@tonic-gate /*
1497*0Sstevel@tonic-gate * Earlier version of telnet/telnetd from the BSD code had
1498*0Sstevel@tonic-gate * the definitions of VALUE and VAR reversed. To ensure
1499*0Sstevel@tonic-gate * maximum interoperability, we assume that the server is
1500*0Sstevel@tonic-gate * an older BSD server, until proven otherwise. The newer
1501*0Sstevel@tonic-gate * BSD servers should be able to handle either definition,
1502*0Sstevel@tonic-gate * so it is better to use the wrong values if we don't
1503*0Sstevel@tonic-gate * know what type of server it is.
1504*0Sstevel@tonic-gate */
1505*0Sstevel@tonic-gate int env_auto = 1;
1506*0Sstevel@tonic-gate int old_env_var = OLD_ENV_VAR;
1507*0Sstevel@tonic-gate int old_env_value = OLD_ENV_VALUE;
1508*0Sstevel@tonic-gate #else
1509*0Sstevel@tonic-gate #define old_env_var OLD_ENV_VAR
1510*0Sstevel@tonic-gate #define old_env_value OLD_ENV_VALUE
1511*0Sstevel@tonic-gate #endif
1512*0Sstevel@tonic-gate #endif
1513*0Sstevel@tonic-gate
1514*0Sstevel@tonic-gate static void
env_opt(buf,len)1515*0Sstevel@tonic-gate env_opt(buf, len)
1516*0Sstevel@tonic-gate register unsigned char *buf;
1517*0Sstevel@tonic-gate register int len;
1518*0Sstevel@tonic-gate {
1519*0Sstevel@tonic-gate register unsigned char *ep = 0, *epc = 0;
1520*0Sstevel@tonic-gate register int i;
1521*0Sstevel@tonic-gate
1522*0Sstevel@tonic-gate switch (buf[0]&0xff) {
1523*0Sstevel@tonic-gate case TELQUAL_SEND:
1524*0Sstevel@tonic-gate env_opt_start();
1525*0Sstevel@tonic-gate if (len == 1) {
1526*0Sstevel@tonic-gate env_opt_add(NULL);
1527*0Sstevel@tonic-gate } else for (i = 1; i < len; i++) {
1528*0Sstevel@tonic-gate switch (buf[i]&0xff) {
1529*0Sstevel@tonic-gate #ifdef OLD_ENVIRON
1530*0Sstevel@tonic-gate case OLD_ENV_VAR:
1531*0Sstevel@tonic-gate #ifdef ENV_HACK
1532*0Sstevel@tonic-gate if (telopt_environ == TELOPT_OLD_ENVIRON &&
1533*0Sstevel@tonic-gate env_auto) {
1534*0Sstevel@tonic-gate /* Server has the same definitions */
1535*0Sstevel@tonic-gate old_env_var = OLD_ENV_VAR;
1536*0Sstevel@tonic-gate old_env_value = OLD_ENV_VALUE;
1537*0Sstevel@tonic-gate }
1538*0Sstevel@tonic-gate /* FALLTHROUGH */
1539*0Sstevel@tonic-gate #endif
1540*0Sstevel@tonic-gate case OLD_ENV_VALUE:
1541*0Sstevel@tonic-gate /*
1542*0Sstevel@tonic-gate * Although OLD_ENV_VALUE is not legal, we will
1543*0Sstevel@tonic-gate * still recognize it, just in case it is an
1544*0Sstevel@tonic-gate * old server that has VAR & VALUE mixed up...
1545*0Sstevel@tonic-gate */
1546*0Sstevel@tonic-gate /* FALLTHROUGH */
1547*0Sstevel@tonic-gate #else
1548*0Sstevel@tonic-gate case NEW_ENV_VAR:
1549*0Sstevel@tonic-gate #endif
1550*0Sstevel@tonic-gate case ENV_USERVAR:
1551*0Sstevel@tonic-gate if (ep) {
1552*0Sstevel@tonic-gate *epc = 0;
1553*0Sstevel@tonic-gate env_opt_add(ep);
1554*0Sstevel@tonic-gate }
1555*0Sstevel@tonic-gate ep = epc = &buf[i+1];
1556*0Sstevel@tonic-gate break;
1557*0Sstevel@tonic-gate case ENV_ESC:
1558*0Sstevel@tonic-gate i++;
1559*0Sstevel@tonic-gate /*FALLTHROUGH*/
1560*0Sstevel@tonic-gate default:
1561*0Sstevel@tonic-gate if (epc)
1562*0Sstevel@tonic-gate *epc++ = buf[i];
1563*0Sstevel@tonic-gate break;
1564*0Sstevel@tonic-gate }
1565*0Sstevel@tonic-gate }
1566*0Sstevel@tonic-gate if (ep) {
1567*0Sstevel@tonic-gate *epc = 0;
1568*0Sstevel@tonic-gate env_opt_add(ep);
1569*0Sstevel@tonic-gate }
1570*0Sstevel@tonic-gate env_opt_end(1);
1571*0Sstevel@tonic-gate break;
1572*0Sstevel@tonic-gate
1573*0Sstevel@tonic-gate case TELQUAL_IS:
1574*0Sstevel@tonic-gate case TELQUAL_INFO:
1575*0Sstevel@tonic-gate /* Ignore for now. We shouldn't get it anyway. */
1576*0Sstevel@tonic-gate break;
1577*0Sstevel@tonic-gate
1578*0Sstevel@tonic-gate default:
1579*0Sstevel@tonic-gate break;
1580*0Sstevel@tonic-gate }
1581*0Sstevel@tonic-gate }
1582*0Sstevel@tonic-gate
1583*0Sstevel@tonic-gate static unsigned char *opt_reply;
1584*0Sstevel@tonic-gate static unsigned char *opt_replyp;
1585*0Sstevel@tonic-gate static unsigned char *opt_replyend;
1586*0Sstevel@tonic-gate #define OPT_REPLY_INITIAL_SIZE 256
1587*0Sstevel@tonic-gate /*
1588*0Sstevel@tonic-gate * The opt reply consists of: IAC, SB, telopt_environ, TELQUAL_IS,
1589*0Sstevel@tonic-gate * value, IAC, SE. i.e. it has a 'wrapper' of 6 control characters.
1590*0Sstevel@tonic-gate */
1591*0Sstevel@tonic-gate #define OPT_WRAPPER_SIZE 6
1592*0Sstevel@tonic-gate
1593*0Sstevel@tonic-gate static void
env_opt_start()1594*0Sstevel@tonic-gate env_opt_start()
1595*0Sstevel@tonic-gate {
1596*0Sstevel@tonic-gate opt_reply = realloc(opt_reply, OPT_REPLY_INITIAL_SIZE);
1597*0Sstevel@tonic-gate if (opt_reply == NULL) {
1598*0Sstevel@tonic-gate (void) printf(
1599*0Sstevel@tonic-gate "telnet: error allocating environment option memory\n");
1600*0Sstevel@tonic-gate opt_reply = opt_replyp = opt_replyend = NULL;
1601*0Sstevel@tonic-gate return;
1602*0Sstevel@tonic-gate }
1603*0Sstevel@tonic-gate opt_replyp = opt_reply;
1604*0Sstevel@tonic-gate opt_replyend = opt_reply + OPT_REPLY_INITIAL_SIZE;
1605*0Sstevel@tonic-gate *opt_replyp++ = IAC;
1606*0Sstevel@tonic-gate *opt_replyp++ = SB;
1607*0Sstevel@tonic-gate *opt_replyp++ = telopt_environ;
1608*0Sstevel@tonic-gate *opt_replyp++ = TELQUAL_IS;
1609*0Sstevel@tonic-gate }
1610*0Sstevel@tonic-gate
1611*0Sstevel@tonic-gate void
env_opt_start_info()1612*0Sstevel@tonic-gate env_opt_start_info()
1613*0Sstevel@tonic-gate {
1614*0Sstevel@tonic-gate env_opt_start();
1615*0Sstevel@tonic-gate if (opt_replyp)
1616*0Sstevel@tonic-gate opt_replyp[-1] = TELQUAL_INFO;
1617*0Sstevel@tonic-gate }
1618*0Sstevel@tonic-gate
1619*0Sstevel@tonic-gate void
env_opt_add(ep)1620*0Sstevel@tonic-gate env_opt_add(ep)
1621*0Sstevel@tonic-gate register unsigned char *ep;
1622*0Sstevel@tonic-gate {
1623*0Sstevel@tonic-gate register unsigned char *vp, c;
1624*0Sstevel@tonic-gate int opt_reply_size;
1625*0Sstevel@tonic-gate int opt_reply_used;
1626*0Sstevel@tonic-gate
1627*0Sstevel@tonic-gate if (opt_reply == NULL) /* XXX */
1628*0Sstevel@tonic-gate return; /* XXX */
1629*0Sstevel@tonic-gate
1630*0Sstevel@tonic-gate if (ep == NULL || *ep == '\0') {
1631*0Sstevel@tonic-gate /* Send user defined variables first. */
1632*0Sstevel@tonic-gate (void) env_default(1, 0);
1633*0Sstevel@tonic-gate while (ep = env_default(0, 0))
1634*0Sstevel@tonic-gate env_opt_add(ep);
1635*0Sstevel@tonic-gate
1636*0Sstevel@tonic-gate /* Now add the list of well know variables. */
1637*0Sstevel@tonic-gate (void) env_default(1, 1);
1638*0Sstevel@tonic-gate while (ep = env_default(0, 1))
1639*0Sstevel@tonic-gate env_opt_add(ep);
1640*0Sstevel@tonic-gate return;
1641*0Sstevel@tonic-gate }
1642*0Sstevel@tonic-gate vp = env_getvalue(ep);
1643*0Sstevel@tonic-gate
1644*0Sstevel@tonic-gate /*
1645*0Sstevel@tonic-gate * Calculate space required for opt_reply and allocate more if required.
1646*0Sstevel@tonic-gate * Assume worst case that every character is escaped, so needs 2 bytes.
1647*0Sstevel@tonic-gate */
1648*0Sstevel@tonic-gate opt_reply_used = opt_replyp - opt_reply; /* existing contents */
1649*0Sstevel@tonic-gate opt_reply_size = opt_reply_used + OPT_WRAPPER_SIZE +
1650*0Sstevel@tonic-gate (2 * (strlen((char *)ep))) +
1651*0Sstevel@tonic-gate (vp == NULL ? 0 : (2 * strlen((char *)vp)));
1652*0Sstevel@tonic-gate
1653*0Sstevel@tonic-gate if (opt_reply_size > (opt_replyend - opt_reply)) {
1654*0Sstevel@tonic-gate opt_reply = realloc(opt_reply, opt_reply_size);
1655*0Sstevel@tonic-gate if (opt_reply == NULL) {
1656*0Sstevel@tonic-gate (void) printf(
1657*0Sstevel@tonic-gate "telnet: can't allocate environment option "
1658*0Sstevel@tonic-gate "reply\n");
1659*0Sstevel@tonic-gate opt_reply = opt_replyp = opt_replyend = NULL;
1660*0Sstevel@tonic-gate return;
1661*0Sstevel@tonic-gate }
1662*0Sstevel@tonic-gate opt_replyp = opt_reply + opt_reply_used;
1663*0Sstevel@tonic-gate opt_replyend = opt_reply + opt_reply_size;
1664*0Sstevel@tonic-gate }
1665*0Sstevel@tonic-gate
1666*0Sstevel@tonic-gate if (opt_welldefined((char *)ep))
1667*0Sstevel@tonic-gate #ifdef OLD_ENVIRON
1668*0Sstevel@tonic-gate if (telopt_environ == TELOPT_OLD_ENVIRON)
1669*0Sstevel@tonic-gate *opt_replyp++ = old_env_var;
1670*0Sstevel@tonic-gate else
1671*0Sstevel@tonic-gate #endif
1672*0Sstevel@tonic-gate *opt_replyp++ = NEW_ENV_VAR;
1673*0Sstevel@tonic-gate else
1674*0Sstevel@tonic-gate *opt_replyp++ = ENV_USERVAR;
1675*0Sstevel@tonic-gate for (;;) {
1676*0Sstevel@tonic-gate while ((c = *ep++) != NULL) {
1677*0Sstevel@tonic-gate switch (c&0xff) {
1678*0Sstevel@tonic-gate case IAC:
1679*0Sstevel@tonic-gate *opt_replyp++ = IAC;
1680*0Sstevel@tonic-gate break;
1681*0Sstevel@tonic-gate case NEW_ENV_VAR:
1682*0Sstevel@tonic-gate case NEW_ENV_VALUE:
1683*0Sstevel@tonic-gate case ENV_ESC:
1684*0Sstevel@tonic-gate case ENV_USERVAR:
1685*0Sstevel@tonic-gate *opt_replyp++ = ENV_ESC;
1686*0Sstevel@tonic-gate break;
1687*0Sstevel@tonic-gate }
1688*0Sstevel@tonic-gate *opt_replyp++ = c;
1689*0Sstevel@tonic-gate }
1690*0Sstevel@tonic-gate if ((ep = vp) != NULL) {
1691*0Sstevel@tonic-gate #ifdef OLD_ENVIRON
1692*0Sstevel@tonic-gate if (telopt_environ == TELOPT_OLD_ENVIRON)
1693*0Sstevel@tonic-gate *opt_replyp++ = old_env_value;
1694*0Sstevel@tonic-gate else
1695*0Sstevel@tonic-gate #endif
1696*0Sstevel@tonic-gate *opt_replyp++ = NEW_ENV_VALUE;
1697*0Sstevel@tonic-gate vp = NULL;
1698*0Sstevel@tonic-gate } else
1699*0Sstevel@tonic-gate break;
1700*0Sstevel@tonic-gate }
1701*0Sstevel@tonic-gate }
1702*0Sstevel@tonic-gate
1703*0Sstevel@tonic-gate int
opt_welldefined(ep)1704*0Sstevel@tonic-gate opt_welldefined(ep)
1705*0Sstevel@tonic-gate char *ep;
1706*0Sstevel@tonic-gate {
1707*0Sstevel@tonic-gate if ((strcmp(ep, "USER") == 0) ||
1708*0Sstevel@tonic-gate (strcmp(ep, "DISPLAY") == 0) ||
1709*0Sstevel@tonic-gate (strcmp(ep, "PRINTER") == 0) ||
1710*0Sstevel@tonic-gate (strcmp(ep, "SYSTEMTYPE") == 0) ||
1711*0Sstevel@tonic-gate (strcmp(ep, "JOB") == 0) ||
1712*0Sstevel@tonic-gate (strcmp(ep, "ACCT") == 0))
1713*0Sstevel@tonic-gate return (1);
1714*0Sstevel@tonic-gate return (0);
1715*0Sstevel@tonic-gate }
1716*0Sstevel@tonic-gate void
env_opt_end(emptyok)1717*0Sstevel@tonic-gate env_opt_end(emptyok)
1718*0Sstevel@tonic-gate register int emptyok;
1719*0Sstevel@tonic-gate {
1720*0Sstevel@tonic-gate register int len;
1721*0Sstevel@tonic-gate
1722*0Sstevel@tonic-gate len = opt_replyp - opt_reply + 2;
1723*0Sstevel@tonic-gate if (emptyok || len > OPT_WRAPPER_SIZE) {
1724*0Sstevel@tonic-gate *opt_replyp++ = IAC;
1725*0Sstevel@tonic-gate *opt_replyp++ = SE;
1726*0Sstevel@tonic-gate if (NETROOM() > len) {
1727*0Sstevel@tonic-gate ring_supply_data(&netoring, opt_reply, len);
1728*0Sstevel@tonic-gate printsub('>', &opt_reply[2], len - 2);
1729*0Sstevel@tonic-gate }
1730*0Sstevel@tonic-gate else
1731*0Sstevel@tonic-gate (void) printf("telnet: not enough room in buffer for "
1732*0Sstevel@tonic-gate "environment option end reply\n");
1733*0Sstevel@tonic-gate }
1734*0Sstevel@tonic-gate if (opt_reply) {
1735*0Sstevel@tonic-gate free(opt_reply);
1736*0Sstevel@tonic-gate opt_reply = opt_replyp = opt_replyend = NULL;
1737*0Sstevel@tonic-gate }
1738*0Sstevel@tonic-gate }
1739*0Sstevel@tonic-gate
1740*0Sstevel@tonic-gate
1741*0Sstevel@tonic-gate
1742*0Sstevel@tonic-gate int
telrcv()1743*0Sstevel@tonic-gate telrcv()
1744*0Sstevel@tonic-gate {
1745*0Sstevel@tonic-gate register int c;
1746*0Sstevel@tonic-gate register int scc;
1747*0Sstevel@tonic-gate register unsigned char *sbp;
1748*0Sstevel@tonic-gate int count;
1749*0Sstevel@tonic-gate int returnValue = 0;
1750*0Sstevel@tonic-gate int min_room = 0;
1751*0Sstevel@tonic-gate
1752*0Sstevel@tonic-gate scc = 0;
1753*0Sstevel@tonic-gate count = 0;
1754*0Sstevel@tonic-gate while (--min_room > 2 || (min_room = TTYROOM()) > 2) {
1755*0Sstevel@tonic-gate if (scc == 0) {
1756*0Sstevel@tonic-gate if (count) {
1757*0Sstevel@tonic-gate ring_consumed(&netiring, count);
1758*0Sstevel@tonic-gate returnValue = 1;
1759*0Sstevel@tonic-gate count = 0;
1760*0Sstevel@tonic-gate }
1761*0Sstevel@tonic-gate sbp = netiring.consume;
1762*0Sstevel@tonic-gate scc = ring_full_consecutive(&netiring);
1763*0Sstevel@tonic-gate if (scc == 0) {
1764*0Sstevel@tonic-gate /* No more data coming in */
1765*0Sstevel@tonic-gate break;
1766*0Sstevel@tonic-gate }
1767*0Sstevel@tonic-gate }
1768*0Sstevel@tonic-gate
1769*0Sstevel@tonic-gate c = *sbp++ & 0xff, scc--; count++;
1770*0Sstevel@tonic-gate
1771*0Sstevel@tonic-gate if (decrypt_input)
1772*0Sstevel@tonic-gate c = (*decrypt_input)(c);
1773*0Sstevel@tonic-gate
1774*0Sstevel@tonic-gate switch (telrcv_state) {
1775*0Sstevel@tonic-gate
1776*0Sstevel@tonic-gate case TS_CR:
1777*0Sstevel@tonic-gate telrcv_state = TS_DATA;
1778*0Sstevel@tonic-gate if (c == '\0') {
1779*0Sstevel@tonic-gate break; /* Ignore \0 after CR */
1780*0Sstevel@tonic-gate } else if ((c == '\n') &&
1781*0Sstevel@tonic-gate my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1782*0Sstevel@tonic-gate TTYADD(c);
1783*0Sstevel@tonic-gate break;
1784*0Sstevel@tonic-gate }
1785*0Sstevel@tonic-gate /* FALLTHROUGH */
1786*0Sstevel@tonic-gate
1787*0Sstevel@tonic-gate case TS_DATA:
1788*0Sstevel@tonic-gate if (c == IAC) {
1789*0Sstevel@tonic-gate telrcv_state = TS_IAC;
1790*0Sstevel@tonic-gate break;
1791*0Sstevel@tonic-gate }
1792*0Sstevel@tonic-gate /*
1793*0Sstevel@tonic-gate * The 'crmod' hack (see following) is needed
1794*0Sstevel@tonic-gate * since we can't * set CRMOD on output only.
1795*0Sstevel@tonic-gate * Machines like MULTICS like to send \r without
1796*0Sstevel@tonic-gate * \n; since we must turn off CRMOD to get proper
1797*0Sstevel@tonic-gate * input, the mapping is done here (sigh).
1798*0Sstevel@tonic-gate */
1799*0Sstevel@tonic-gate if ((c == '\r') &&
1800*0Sstevel@tonic-gate my_want_state_is_dont(TELOPT_BINARY)) {
1801*0Sstevel@tonic-gate if (scc > 0) {
1802*0Sstevel@tonic-gate c = *sbp&0xff;
1803*0Sstevel@tonic-gate
1804*0Sstevel@tonic-gate if (decrypt_input)
1805*0Sstevel@tonic-gate c = (*decrypt_input)(c);
1806*0Sstevel@tonic-gate
1807*0Sstevel@tonic-gate if (c == 0) {
1808*0Sstevel@tonic-gate sbp++, scc--; count++;
1809*0Sstevel@tonic-gate /* a "true" CR */
1810*0Sstevel@tonic-gate TTYADD('\r');
1811*0Sstevel@tonic-gate } else if (my_want_state_is_dont(
1812*0Sstevel@tonic-gate TELOPT_ECHO) && (c == '\n')) {
1813*0Sstevel@tonic-gate sbp++, scc--; count++;
1814*0Sstevel@tonic-gate TTYADD('\n');
1815*0Sstevel@tonic-gate } else {
1816*0Sstevel@tonic-gate
1817*0Sstevel@tonic-gate if (decrypt_input)
1818*0Sstevel@tonic-gate (*decrypt_input)(-1);
1819*0Sstevel@tonic-gate
1820*0Sstevel@tonic-gate TTYADD('\r');
1821*0Sstevel@tonic-gate if (crmod) {
1822*0Sstevel@tonic-gate TTYADD('\n');
1823*0Sstevel@tonic-gate }
1824*0Sstevel@tonic-gate }
1825*0Sstevel@tonic-gate } else {
1826*0Sstevel@tonic-gate telrcv_state = TS_CR;
1827*0Sstevel@tonic-gate TTYADD('\r');
1828*0Sstevel@tonic-gate if (crmod) {
1829*0Sstevel@tonic-gate TTYADD('\n');
1830*0Sstevel@tonic-gate }
1831*0Sstevel@tonic-gate }
1832*0Sstevel@tonic-gate } else {
1833*0Sstevel@tonic-gate TTYADD(c);
1834*0Sstevel@tonic-gate }
1835*0Sstevel@tonic-gate continue;
1836*0Sstevel@tonic-gate
1837*0Sstevel@tonic-gate case TS_IAC:
1838*0Sstevel@tonic-gate process_iac:
1839*0Sstevel@tonic-gate switch (c) {
1840*0Sstevel@tonic-gate
1841*0Sstevel@tonic-gate case WILL:
1842*0Sstevel@tonic-gate telrcv_state = TS_WILL;
1843*0Sstevel@tonic-gate continue;
1844*0Sstevel@tonic-gate
1845*0Sstevel@tonic-gate case WONT:
1846*0Sstevel@tonic-gate telrcv_state = TS_WONT;
1847*0Sstevel@tonic-gate continue;
1848*0Sstevel@tonic-gate
1849*0Sstevel@tonic-gate case DO:
1850*0Sstevel@tonic-gate telrcv_state = TS_DO;
1851*0Sstevel@tonic-gate continue;
1852*0Sstevel@tonic-gate
1853*0Sstevel@tonic-gate case DONT:
1854*0Sstevel@tonic-gate telrcv_state = TS_DONT;
1855*0Sstevel@tonic-gate continue;
1856*0Sstevel@tonic-gate
1857*0Sstevel@tonic-gate case DM:
1858*0Sstevel@tonic-gate /*
1859*0Sstevel@tonic-gate * We may have missed an urgent notification,
1860*0Sstevel@tonic-gate * so make sure we flush whatever is in the
1861*0Sstevel@tonic-gate * buffer currently.
1862*0Sstevel@tonic-gate */
1863*0Sstevel@tonic-gate printoption("RCVD", IAC, DM);
1864*0Sstevel@tonic-gate SYNCHing = 1;
1865*0Sstevel@tonic-gate if (ttyflush(1) == -2) {
1866*0Sstevel@tonic-gate /* This will not return. */
1867*0Sstevel@tonic-gate fatal_tty_error("write");
1868*0Sstevel@tonic-gate }
1869*0Sstevel@tonic-gate SYNCHing = stilloob();
1870*0Sstevel@tonic-gate settimer(gotDM);
1871*0Sstevel@tonic-gate break;
1872*0Sstevel@tonic-gate
1873*0Sstevel@tonic-gate case SB:
1874*0Sstevel@tonic-gate SB_CLEAR();
1875*0Sstevel@tonic-gate telrcv_state = TS_SB;
1876*0Sstevel@tonic-gate continue;
1877*0Sstevel@tonic-gate
1878*0Sstevel@tonic-gate case IAC:
1879*0Sstevel@tonic-gate TTYADD(IAC);
1880*0Sstevel@tonic-gate break;
1881*0Sstevel@tonic-gate
1882*0Sstevel@tonic-gate case NOP:
1883*0Sstevel@tonic-gate case GA:
1884*0Sstevel@tonic-gate default:
1885*0Sstevel@tonic-gate printoption("RCVD", IAC, c);
1886*0Sstevel@tonic-gate break;
1887*0Sstevel@tonic-gate }
1888*0Sstevel@tonic-gate telrcv_state = TS_DATA;
1889*0Sstevel@tonic-gate continue;
1890*0Sstevel@tonic-gate
1891*0Sstevel@tonic-gate case TS_WILL:
1892*0Sstevel@tonic-gate printoption("RCVD", WILL, c);
1893*0Sstevel@tonic-gate willoption(c);
1894*0Sstevel@tonic-gate telrcv_state = TS_DATA;
1895*0Sstevel@tonic-gate continue;
1896*0Sstevel@tonic-gate
1897*0Sstevel@tonic-gate case TS_WONT:
1898*0Sstevel@tonic-gate printoption("RCVD", WONT, c);
1899*0Sstevel@tonic-gate wontoption(c);
1900*0Sstevel@tonic-gate telrcv_state = TS_DATA;
1901*0Sstevel@tonic-gate continue;
1902*0Sstevel@tonic-gate
1903*0Sstevel@tonic-gate case TS_DO:
1904*0Sstevel@tonic-gate printoption("RCVD", DO, c);
1905*0Sstevel@tonic-gate dooption(c);
1906*0Sstevel@tonic-gate if (c == TELOPT_NAWS) {
1907*0Sstevel@tonic-gate sendnaws();
1908*0Sstevel@tonic-gate } else if (c == TELOPT_LFLOW) {
1909*0Sstevel@tonic-gate localflow = 1;
1910*0Sstevel@tonic-gate setcommandmode();
1911*0Sstevel@tonic-gate setconnmode(0);
1912*0Sstevel@tonic-gate }
1913*0Sstevel@tonic-gate telrcv_state = TS_DATA;
1914*0Sstevel@tonic-gate continue;
1915*0Sstevel@tonic-gate
1916*0Sstevel@tonic-gate case TS_DONT:
1917*0Sstevel@tonic-gate printoption("RCVD", DONT, c);
1918*0Sstevel@tonic-gate dontoption(c);
1919*0Sstevel@tonic-gate flushline = 1;
1920*0Sstevel@tonic-gate setconnmode(0); /* set new tty mode (maybe) */
1921*0Sstevel@tonic-gate telrcv_state = TS_DATA;
1922*0Sstevel@tonic-gate continue;
1923*0Sstevel@tonic-gate
1924*0Sstevel@tonic-gate case TS_SB:
1925*0Sstevel@tonic-gate if (c == IAC) {
1926*0Sstevel@tonic-gate telrcv_state = TS_SE;
1927*0Sstevel@tonic-gate } else {
1928*0Sstevel@tonic-gate SB_ACCUM(c);
1929*0Sstevel@tonic-gate }
1930*0Sstevel@tonic-gate continue;
1931*0Sstevel@tonic-gate
1932*0Sstevel@tonic-gate case TS_SE:
1933*0Sstevel@tonic-gate if (c != SE) {
1934*0Sstevel@tonic-gate if (c != IAC) {
1935*0Sstevel@tonic-gate /*
1936*0Sstevel@tonic-gate * This is an error. We only expect to get
1937*0Sstevel@tonic-gate * "IAC IAC" or "IAC SE". Several things may
1938*0Sstevel@tonic-gate * have happend. An IAC was not doubled, the
1939*0Sstevel@tonic-gate * IAC SE was left off, or another option got
1940*0Sstevel@tonic-gate * inserted into the suboption are all possibilities.
1941*0Sstevel@tonic-gate * If we assume that the IAC was not doubled,
1942*0Sstevel@tonic-gate * and really the IAC SE was left off, we could
1943*0Sstevel@tonic-gate * get into an infinate loop here. So, instead,
1944*0Sstevel@tonic-gate * we terminate the suboption, and process the
1945*0Sstevel@tonic-gate * partial suboption if we can.
1946*0Sstevel@tonic-gate */
1947*0Sstevel@tonic-gate SB_ACCUM(IAC);
1948*0Sstevel@tonic-gate SB_ACCUM(c);
1949*0Sstevel@tonic-gate subpointer -= 2;
1950*0Sstevel@tonic-gate SB_TERM();
1951*0Sstevel@tonic-gate
1952*0Sstevel@tonic-gate printoption("In SUBOPTION processing, "
1953*0Sstevel@tonic-gate "RCVD", IAC, c);
1954*0Sstevel@tonic-gate suboption(); /* handle sub-option */
1955*0Sstevel@tonic-gate telrcv_state = TS_IAC;
1956*0Sstevel@tonic-gate goto process_iac;
1957*0Sstevel@tonic-gate }
1958*0Sstevel@tonic-gate SB_ACCUM(c);
1959*0Sstevel@tonic-gate telrcv_state = TS_SB;
1960*0Sstevel@tonic-gate } else {
1961*0Sstevel@tonic-gate SB_ACCUM(IAC);
1962*0Sstevel@tonic-gate SB_ACCUM(SE);
1963*0Sstevel@tonic-gate subpointer -= 2;
1964*0Sstevel@tonic-gate SB_TERM();
1965*0Sstevel@tonic-gate suboption(); /* handle sub-option */
1966*0Sstevel@tonic-gate telrcv_state = TS_DATA;
1967*0Sstevel@tonic-gate }
1968*0Sstevel@tonic-gate }
1969*0Sstevel@tonic-gate }
1970*0Sstevel@tonic-gate if (count)
1971*0Sstevel@tonic-gate ring_consumed(&netiring, count);
1972*0Sstevel@tonic-gate return (returnValue||count);
1973*0Sstevel@tonic-gate }
1974*0Sstevel@tonic-gate
1975*0Sstevel@tonic-gate static int bol = 1, local = 0;
1976*0Sstevel@tonic-gate
1977*0Sstevel@tonic-gate int
rlogin_susp()1978*0Sstevel@tonic-gate rlogin_susp()
1979*0Sstevel@tonic-gate {
1980*0Sstevel@tonic-gate if (local) {
1981*0Sstevel@tonic-gate local = 0;
1982*0Sstevel@tonic-gate bol = 1;
1983*0Sstevel@tonic-gate command(0, "z\n", 2);
1984*0Sstevel@tonic-gate return (1);
1985*0Sstevel@tonic-gate }
1986*0Sstevel@tonic-gate return (0);
1987*0Sstevel@tonic-gate }
1988*0Sstevel@tonic-gate
1989*0Sstevel@tonic-gate static int
telsnd()1990*0Sstevel@tonic-gate telsnd()
1991*0Sstevel@tonic-gate {
1992*0Sstevel@tonic-gate int tcc;
1993*0Sstevel@tonic-gate int count;
1994*0Sstevel@tonic-gate int returnValue = 0;
1995*0Sstevel@tonic-gate unsigned char *tbp;
1996*0Sstevel@tonic-gate
1997*0Sstevel@tonic-gate tcc = 0;
1998*0Sstevel@tonic-gate count = 0;
1999*0Sstevel@tonic-gate while (NETROOM() > 2) {
2000*0Sstevel@tonic-gate register int sc;
2001*0Sstevel@tonic-gate register int c;
2002*0Sstevel@tonic-gate
2003*0Sstevel@tonic-gate if (tcc == 0) {
2004*0Sstevel@tonic-gate if (count) {
2005*0Sstevel@tonic-gate ring_consumed(&ttyiring, count);
2006*0Sstevel@tonic-gate returnValue = 1;
2007*0Sstevel@tonic-gate count = 0;
2008*0Sstevel@tonic-gate }
2009*0Sstevel@tonic-gate tbp = ttyiring.consume;
2010*0Sstevel@tonic-gate tcc = ring_full_consecutive(&ttyiring);
2011*0Sstevel@tonic-gate if (tcc == 0) {
2012*0Sstevel@tonic-gate break;
2013*0Sstevel@tonic-gate }
2014*0Sstevel@tonic-gate }
2015*0Sstevel@tonic-gate c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
2016*0Sstevel@tonic-gate if (rlogin != _POSIX_VDISABLE) {
2017*0Sstevel@tonic-gate if (bol) {
2018*0Sstevel@tonic-gate bol = 0;
2019*0Sstevel@tonic-gate if (sc == rlogin) {
2020*0Sstevel@tonic-gate local = 1;
2021*0Sstevel@tonic-gate continue;
2022*0Sstevel@tonic-gate }
2023*0Sstevel@tonic-gate } else if (local) {
2024*0Sstevel@tonic-gate local = 0;
2025*0Sstevel@tonic-gate if (sc == '.' || c == termEofChar) {
2026*0Sstevel@tonic-gate bol = 1;
2027*0Sstevel@tonic-gate command(0, "close\n", 6);
2028*0Sstevel@tonic-gate continue;
2029*0Sstevel@tonic-gate }
2030*0Sstevel@tonic-gate if (sc == termSuspChar) {
2031*0Sstevel@tonic-gate bol = 1;
2032*0Sstevel@tonic-gate command(0, "z\n", 2);
2033*0Sstevel@tonic-gate continue;
2034*0Sstevel@tonic-gate }
2035*0Sstevel@tonic-gate if (sc == escape) {
2036*0Sstevel@tonic-gate command(0, (char *)tbp, tcc);
2037*0Sstevel@tonic-gate bol = 1;
2038*0Sstevel@tonic-gate count += tcc;
2039*0Sstevel@tonic-gate tcc = 0;
2040*0Sstevel@tonic-gate flushline = 1;
2041*0Sstevel@tonic-gate break;
2042*0Sstevel@tonic-gate }
2043*0Sstevel@tonic-gate if (sc != rlogin) {
2044*0Sstevel@tonic-gate ++tcc;
2045*0Sstevel@tonic-gate --tbp;
2046*0Sstevel@tonic-gate --count;
2047*0Sstevel@tonic-gate c = sc = rlogin;
2048*0Sstevel@tonic-gate }
2049*0Sstevel@tonic-gate }
2050*0Sstevel@tonic-gate if ((sc == '\n') || (sc == '\r'))
2051*0Sstevel@tonic-gate bol = 1;
2052*0Sstevel@tonic-gate } else if (sc == escape && escape_valid) {
2053*0Sstevel@tonic-gate /*
2054*0Sstevel@tonic-gate * Double escape is a pass through of a single
2055*0Sstevel@tonic-gate * escape character.
2056*0Sstevel@tonic-gate */
2057*0Sstevel@tonic-gate if (tcc && strip(*tbp) == escape) {
2058*0Sstevel@tonic-gate tbp++;
2059*0Sstevel@tonic-gate tcc--;
2060*0Sstevel@tonic-gate count++;
2061*0Sstevel@tonic-gate bol = 0;
2062*0Sstevel@tonic-gate } else {
2063*0Sstevel@tonic-gate command(0, (char *)tbp, tcc);
2064*0Sstevel@tonic-gate bol = 1;
2065*0Sstevel@tonic-gate count += tcc;
2066*0Sstevel@tonic-gate tcc = 0;
2067*0Sstevel@tonic-gate flushline = 1;
2068*0Sstevel@tonic-gate break;
2069*0Sstevel@tonic-gate }
2070*0Sstevel@tonic-gate } else
2071*0Sstevel@tonic-gate bol = 0;
2072*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE
2073*0Sstevel@tonic-gate if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
2074*0Sstevel@tonic-gate if (tcc > 0 && strip(*tbp) == echoc) {
2075*0Sstevel@tonic-gate tcc--; tbp++; count++;
2076*0Sstevel@tonic-gate } else {
2077*0Sstevel@tonic-gate dontlecho = !dontlecho;
2078*0Sstevel@tonic-gate settimer(echotoggle);
2079*0Sstevel@tonic-gate setconnmode(0);
2080*0Sstevel@tonic-gate flushline = 1;
2081*0Sstevel@tonic-gate break;
2082*0Sstevel@tonic-gate }
2083*0Sstevel@tonic-gate }
2084*0Sstevel@tonic-gate #endif
2085*0Sstevel@tonic-gate if (MODE_LOCAL_CHARS(globalmode)) {
2086*0Sstevel@tonic-gate if (TerminalSpecialChars(sc) == 0) {
2087*0Sstevel@tonic-gate bol = 1;
2088*0Sstevel@tonic-gate break;
2089*0Sstevel@tonic-gate }
2090*0Sstevel@tonic-gate }
2091*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_BINARY)) {
2092*0Sstevel@tonic-gate switch (c) {
2093*0Sstevel@tonic-gate case '\n':
2094*0Sstevel@tonic-gate /*
2095*0Sstevel@tonic-gate * If we are in CRMOD mode (\r ==> \n)
2096*0Sstevel@tonic-gate * on our local machine, then probably
2097*0Sstevel@tonic-gate * a newline (unix) is CRLF (TELNET).
2098*0Sstevel@tonic-gate */
2099*0Sstevel@tonic-gate if (MODE_LOCAL_CHARS(globalmode)) {
2100*0Sstevel@tonic-gate NETADD('\r');
2101*0Sstevel@tonic-gate }
2102*0Sstevel@tonic-gate NETADD('\n');
2103*0Sstevel@tonic-gate bol = flushline = 1;
2104*0Sstevel@tonic-gate break;
2105*0Sstevel@tonic-gate case '\r':
2106*0Sstevel@tonic-gate if (!crlf) {
2107*0Sstevel@tonic-gate NET2ADD('\r', '\0');
2108*0Sstevel@tonic-gate } else {
2109*0Sstevel@tonic-gate NET2ADD('\r', '\n');
2110*0Sstevel@tonic-gate }
2111*0Sstevel@tonic-gate bol = flushline = 1;
2112*0Sstevel@tonic-gate break;
2113*0Sstevel@tonic-gate case IAC:
2114*0Sstevel@tonic-gate NET2ADD(IAC, IAC);
2115*0Sstevel@tonic-gate break;
2116*0Sstevel@tonic-gate default:
2117*0Sstevel@tonic-gate NETADD(c);
2118*0Sstevel@tonic-gate break;
2119*0Sstevel@tonic-gate }
2120*0Sstevel@tonic-gate } else if (c == IAC) {
2121*0Sstevel@tonic-gate NET2ADD(IAC, IAC);
2122*0Sstevel@tonic-gate } else {
2123*0Sstevel@tonic-gate NETADD(c);
2124*0Sstevel@tonic-gate }
2125*0Sstevel@tonic-gate }
2126*0Sstevel@tonic-gate if (count)
2127*0Sstevel@tonic-gate ring_consumed(&ttyiring, count);
2128*0Sstevel@tonic-gate return (returnValue||count); /* Non-zero if we did anything */
2129*0Sstevel@tonic-gate }
2130*0Sstevel@tonic-gate
2131*0Sstevel@tonic-gate /*
2132*0Sstevel@tonic-gate * Scheduler()
2133*0Sstevel@tonic-gate *
2134*0Sstevel@tonic-gate * Try to do something.
2135*0Sstevel@tonic-gate *
2136*0Sstevel@tonic-gate * If we do something useful, return 1; else return 0.
2137*0Sstevel@tonic-gate *
2138*0Sstevel@tonic-gate */
2139*0Sstevel@tonic-gate
2140*0Sstevel@tonic-gate
2141*0Sstevel@tonic-gate int
Scheduler(block)2142*0Sstevel@tonic-gate Scheduler(block)
2143*0Sstevel@tonic-gate int block; /* should we block in the select ? */
2144*0Sstevel@tonic-gate {
2145*0Sstevel@tonic-gate /*
2146*0Sstevel@tonic-gate * One wants to be a bit careful about setting returnValue
2147*0Sstevel@tonic-gate * to one, since a one implies we did some useful work,
2148*0Sstevel@tonic-gate * and therefore probably won't be called to block next
2149*0Sstevel@tonic-gate * time (TN3270 mode only).
2150*0Sstevel@tonic-gate */
2151*0Sstevel@tonic-gate int returnValue;
2152*0Sstevel@tonic-gate int netin, netout, netex, ttyin, ttyout;
2153*0Sstevel@tonic-gate
2154*0Sstevel@tonic-gate /* Decide which rings should be processed */
2155*0Sstevel@tonic-gate
2156*0Sstevel@tonic-gate netout = ring_full_count(&netoring) &&
2157*0Sstevel@tonic-gate (flushline ||
2158*0Sstevel@tonic-gate (my_want_state_is_wont(TELOPT_LINEMODE)
2159*0Sstevel@tonic-gate #ifdef KLUDGELINEMODE
2160*0Sstevel@tonic-gate /* X */ && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
2161*0Sstevel@tonic-gate #endif
2162*0Sstevel@tonic-gate /* XXX */) ||
2163*0Sstevel@tonic-gate my_want_state_is_will(TELOPT_BINARY));
2164*0Sstevel@tonic-gate ttyout = ring_full_count(&ttyoring);
2165*0Sstevel@tonic-gate
2166*0Sstevel@tonic-gate ttyin = (ring_empty_count(&ttyiring) && !eof_pending);
2167*0Sstevel@tonic-gate
2168*0Sstevel@tonic-gate netin = !ISend && ring_empty_count(&netiring);
2169*0Sstevel@tonic-gate
2170*0Sstevel@tonic-gate netex = !SYNCHing;
2171*0Sstevel@tonic-gate
2172*0Sstevel@tonic-gate if (scheduler_lockout_tty) {
2173*0Sstevel@tonic-gate ttyin = ttyout = 0;
2174*0Sstevel@tonic-gate }
2175*0Sstevel@tonic-gate
2176*0Sstevel@tonic-gate /* Call to system code to process rings */
2177*0Sstevel@tonic-gate
2178*0Sstevel@tonic-gate returnValue = process_rings(netin, netout, netex, ttyin, ttyout,
2179*0Sstevel@tonic-gate !block);
2180*0Sstevel@tonic-gate
2181*0Sstevel@tonic-gate /* Now, look at the input rings, looking for work to do. */
2182*0Sstevel@tonic-gate
2183*0Sstevel@tonic-gate if (ring_full_count(&ttyiring)) {
2184*0Sstevel@tonic-gate returnValue |= telsnd();
2185*0Sstevel@tonic-gate } else {
2186*0Sstevel@tonic-gate /*
2187*0Sstevel@tonic-gate * If ttyiring is empty, check to see if there is a real EOF
2188*0Sstevel@tonic-gate * pending. If so, we can maybe do the EOF write now.
2189*0Sstevel@tonic-gate */
2190*0Sstevel@tonic-gate if (eof_pending) {
2191*0Sstevel@tonic-gate eof_pending = 0;
2192*0Sstevel@tonic-gate sendeof();
2193*0Sstevel@tonic-gate }
2194*0Sstevel@tonic-gate }
2195*0Sstevel@tonic-gate
2196*0Sstevel@tonic-gate if (ring_full_count(&netiring)) {
2197*0Sstevel@tonic-gate returnValue |= telrcv();
2198*0Sstevel@tonic-gate }
2199*0Sstevel@tonic-gate return (returnValue);
2200*0Sstevel@tonic-gate }
2201*0Sstevel@tonic-gate
2202*0Sstevel@tonic-gate /*
2203*0Sstevel@tonic-gate * Select from tty and network...
2204*0Sstevel@tonic-gate */
2205*0Sstevel@tonic-gate void
telnet(user)2206*0Sstevel@tonic-gate telnet(user)
2207*0Sstevel@tonic-gate char *user;
2208*0Sstevel@tonic-gate {
2209*0Sstevel@tonic-gate sys_telnet_init();
2210*0Sstevel@tonic-gate
2211*0Sstevel@tonic-gate {
2212*0Sstevel@tonic-gate static char local_host[MAXHOSTNAMELEN] = { 0 };
2213*0Sstevel@tonic-gate
2214*0Sstevel@tonic-gate if (!local_host[0]) {
2215*0Sstevel@tonic-gate (void) gethostname(local_host, sizeof (local_host));
2216*0Sstevel@tonic-gate local_host[sizeof (local_host)-1] = 0;
2217*0Sstevel@tonic-gate }
2218*0Sstevel@tonic-gate auth_encrypt_init(local_host, hostname, "TELNET");
2219*0Sstevel@tonic-gate auth_encrypt_user(user);
2220*0Sstevel@tonic-gate }
2221*0Sstevel@tonic-gate
2222*0Sstevel@tonic-gate if (autologin)
2223*0Sstevel@tonic-gate send_will(TELOPT_AUTHENTICATION, 1);
2224*0Sstevel@tonic-gate
2225*0Sstevel@tonic-gate if (telnetport || wantencryption) {
2226*0Sstevel@tonic-gate send_do(TELOPT_ENCRYPT, 1);
2227*0Sstevel@tonic-gate send_will(TELOPT_ENCRYPT, 1);
2228*0Sstevel@tonic-gate }
2229*0Sstevel@tonic-gate
2230*0Sstevel@tonic-gate if (telnetport) {
2231*0Sstevel@tonic-gate if (!reqd_linemode)
2232*0Sstevel@tonic-gate send_do(TELOPT_SGA, 1);
2233*0Sstevel@tonic-gate send_will(TELOPT_TTYPE, 1);
2234*0Sstevel@tonic-gate send_will(TELOPT_NAWS, 1);
2235*0Sstevel@tonic-gate send_will(TELOPT_TSPEED, 1);
2236*0Sstevel@tonic-gate send_will(TELOPT_LFLOW, 1);
2237*0Sstevel@tonic-gate if (!reqd_linemode)
2238*0Sstevel@tonic-gate send_will(TELOPT_LINEMODE, 1);
2239*0Sstevel@tonic-gate send_will(TELOPT_NEW_ENVIRON, 1);
2240*0Sstevel@tonic-gate send_do(TELOPT_STATUS, 1);
2241*0Sstevel@tonic-gate if (env_getvalue((unsigned char *)"DISPLAY"))
2242*0Sstevel@tonic-gate send_will(TELOPT_XDISPLOC, 1);
2243*0Sstevel@tonic-gate if (eight)
2244*0Sstevel@tonic-gate tel_enter_binary(eight);
2245*0Sstevel@tonic-gate }
2246*0Sstevel@tonic-gate
2247*0Sstevel@tonic-gate /*
2248*0Sstevel@tonic-gate * Note: we assume a tie to the authentication option here. This
2249*0Sstevel@tonic-gate * is necessary so that authentication fails, we don't spin
2250*0Sstevel@tonic-gate * forever.
2251*0Sstevel@tonic-gate */
2252*0Sstevel@tonic-gate if (wantencryption) {
2253*0Sstevel@tonic-gate boolean_t printed_encrypt = B_FALSE;
2254*0Sstevel@tonic-gate extern boolean_t auth_has_failed;
2255*0Sstevel@tonic-gate time_t timeout = time(0) + 60;
2256*0Sstevel@tonic-gate
2257*0Sstevel@tonic-gate send_do(TELOPT_ENCRYPT, 1);
2258*0Sstevel@tonic-gate send_will(TELOPT_ENCRYPT, 1);
2259*0Sstevel@tonic-gate for (;;) {
2260*0Sstevel@tonic-gate if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) {
2261*0Sstevel@tonic-gate (void) printf(gettext(
2262*0Sstevel@tonic-gate "\nServer refused to negotiate "
2263*0Sstevel@tonic-gate "authentication, which is required\n"
2264*0Sstevel@tonic-gate "for encryption. Good-bye.\n\r"));
2265*0Sstevel@tonic-gate Exit(EXIT_FAILURE);
2266*0Sstevel@tonic-gate }
2267*0Sstevel@tonic-gate if (auth_has_failed) {
2268*0Sstevel@tonic-gate (void) printf(gettext(
2269*0Sstevel@tonic-gate "\nAuthentication negotation has failed, "
2270*0Sstevel@tonic-gate "which is required for\n"
2271*0Sstevel@tonic-gate "encryption. Good-bye.\n\r"));
2272*0Sstevel@tonic-gate Exit(EXIT_FAILURE);
2273*0Sstevel@tonic-gate }
2274*0Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_ENCRYPT) ||
2275*0Sstevel@tonic-gate my_want_state_is_wont(TELOPT_ENCRYPT)) {
2276*0Sstevel@tonic-gate (void) printf(gettext(
2277*0Sstevel@tonic-gate "\nServer refused to negotiate encryption. "
2278*0Sstevel@tonic-gate "Good-bye.\n\r"));
2279*0Sstevel@tonic-gate Exit(EXIT_FAILURE);
2280*0Sstevel@tonic-gate }
2281*0Sstevel@tonic-gate if (encrypt_is_encrypting())
2282*0Sstevel@tonic-gate break;
2283*0Sstevel@tonic-gate
2284*0Sstevel@tonic-gate if (time(0) > timeout) {
2285*0Sstevel@tonic-gate (void) printf(gettext(
2286*0Sstevel@tonic-gate "\nEncryption could not be enabled. "
2287*0Sstevel@tonic-gate "Good-bye.\n\r"));
2288*0Sstevel@tonic-gate Exit(EXIT_FAILURE);
2289*0Sstevel@tonic-gate }
2290*0Sstevel@tonic-gate if (printed_encrypt == B_FALSE) {
2291*0Sstevel@tonic-gate printed_encrypt = B_TRUE;
2292*0Sstevel@tonic-gate (void) printf(gettext(
2293*0Sstevel@tonic-gate "Waiting for encryption to be negotiated...\n"));
2294*0Sstevel@tonic-gate /*
2295*0Sstevel@tonic-gate * Turn on MODE_TRAPSIG and then turn off localchars
2296*0Sstevel@tonic-gate * so that ^C will cause telnet to exit.
2297*0Sstevel@tonic-gate */
2298*0Sstevel@tonic-gate TerminalNewMode(getconnmode()|MODE_TRAPSIG);
2299*0Sstevel@tonic-gate intr_waiting = 1;
2300*0Sstevel@tonic-gate }
2301*0Sstevel@tonic-gate if (intr_happened) {
2302*0Sstevel@tonic-gate (void) printf(gettext(
2303*0Sstevel@tonic-gate "\nUser requested an interrupt. Good-bye.\n\r"));
2304*0Sstevel@tonic-gate Exit(EXIT_FAILURE);
2305*0Sstevel@tonic-gate }
2306*0Sstevel@tonic-gate telnet_spin();
2307*0Sstevel@tonic-gate }
2308*0Sstevel@tonic-gate if (printed_encrypt) {
2309*0Sstevel@tonic-gate (void) printf(gettext("done.\n"));
2310*0Sstevel@tonic-gate intr_waiting = 0;
2311*0Sstevel@tonic-gate setconnmode(0);
2312*0Sstevel@tonic-gate }
2313*0Sstevel@tonic-gate }
2314*0Sstevel@tonic-gate
2315*0Sstevel@tonic-gate for (;;) {
2316*0Sstevel@tonic-gate int schedValue;
2317*0Sstevel@tonic-gate
2318*0Sstevel@tonic-gate while ((schedValue = Scheduler(0)) != 0) {
2319*0Sstevel@tonic-gate if (schedValue == -1) {
2320*0Sstevel@tonic-gate setcommandmode();
2321*0Sstevel@tonic-gate return;
2322*0Sstevel@tonic-gate }
2323*0Sstevel@tonic-gate }
2324*0Sstevel@tonic-gate
2325*0Sstevel@tonic-gate if (Scheduler(1) == -1) {
2326*0Sstevel@tonic-gate setcommandmode();
2327*0Sstevel@tonic-gate return;
2328*0Sstevel@tonic-gate }
2329*0Sstevel@tonic-gate }
2330*0Sstevel@tonic-gate }
2331*0Sstevel@tonic-gate
2332*0Sstevel@tonic-gate #if 0 /* XXX - this not being in is a bug */
2333*0Sstevel@tonic-gate /*
2334*0Sstevel@tonic-gate * nextitem()
2335*0Sstevel@tonic-gate *
2336*0Sstevel@tonic-gate * Return the address of the next "item" in the TELNET data
2337*0Sstevel@tonic-gate * stream. This will be the address of the next character if
2338*0Sstevel@tonic-gate * the current address is a user data character, or it will
2339*0Sstevel@tonic-gate * be the address of the character following the TELNET command
2340*0Sstevel@tonic-gate * if the current address is a TELNET IAC ("I Am a Command")
2341*0Sstevel@tonic-gate * character.
2342*0Sstevel@tonic-gate */
2343*0Sstevel@tonic-gate
2344*0Sstevel@tonic-gate static char *
2345*0Sstevel@tonic-gate nextitem(current)
2346*0Sstevel@tonic-gate char *current;
2347*0Sstevel@tonic-gate {
2348*0Sstevel@tonic-gate if ((*current&0xff) != IAC) {
2349*0Sstevel@tonic-gate return (current+1);
2350*0Sstevel@tonic-gate }
2351*0Sstevel@tonic-gate switch (*(current+1)&0xff) {
2352*0Sstevel@tonic-gate case DO:
2353*0Sstevel@tonic-gate case DONT:
2354*0Sstevel@tonic-gate case WILL:
2355*0Sstevel@tonic-gate case WONT:
2356*0Sstevel@tonic-gate return (current+3);
2357*0Sstevel@tonic-gate case SB: /* loop forever looking for the SE */
2358*0Sstevel@tonic-gate {
2359*0Sstevel@tonic-gate register char *look = current+2;
2360*0Sstevel@tonic-gate
2361*0Sstevel@tonic-gate for (;;) {
2362*0Sstevel@tonic-gate if ((*look++&0xff) == IAC) {
2363*0Sstevel@tonic-gate if ((*look++&0xff) == SE) {
2364*0Sstevel@tonic-gate return (look);
2365*0Sstevel@tonic-gate }
2366*0Sstevel@tonic-gate }
2367*0Sstevel@tonic-gate }
2368*0Sstevel@tonic-gate }
2369*0Sstevel@tonic-gate default:
2370*0Sstevel@tonic-gate return (current+2);
2371*0Sstevel@tonic-gate }
2372*0Sstevel@tonic-gate }
2373*0Sstevel@tonic-gate #endif /* 0 */
2374*0Sstevel@tonic-gate
2375*0Sstevel@tonic-gate /*
2376*0Sstevel@tonic-gate * netclear()
2377*0Sstevel@tonic-gate *
2378*0Sstevel@tonic-gate * We are about to do a TELNET SYNCH operation. Clear
2379*0Sstevel@tonic-gate * the path to the network.
2380*0Sstevel@tonic-gate *
2381*0Sstevel@tonic-gate * Things are a bit tricky since we may have sent the first
2382*0Sstevel@tonic-gate * byte or so of a previous TELNET command into the network.
2383*0Sstevel@tonic-gate * So, we have to scan the network buffer from the beginning
2384*0Sstevel@tonic-gate * until we are up to where we want to be.
2385*0Sstevel@tonic-gate *
2386*0Sstevel@tonic-gate * A side effect of what we do, just to keep things
2387*0Sstevel@tonic-gate * simple, is to clear the urgent data pointer. The principal
2388*0Sstevel@tonic-gate * caller should be setting the urgent data pointer AFTER calling
2389*0Sstevel@tonic-gate * us in any case.
2390*0Sstevel@tonic-gate */
2391*0Sstevel@tonic-gate
2392*0Sstevel@tonic-gate static void
netclear()2393*0Sstevel@tonic-gate netclear()
2394*0Sstevel@tonic-gate {
2395*0Sstevel@tonic-gate #if 0 /* XXX */
2396*0Sstevel@tonic-gate register char *thisitem, *next;
2397*0Sstevel@tonic-gate char *good;
2398*0Sstevel@tonic-gate #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \
2399*0Sstevel@tonic-gate ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL))
2400*0Sstevel@tonic-gate
2401*0Sstevel@tonic-gate thisitem = netobuf;
2402*0Sstevel@tonic-gate
2403*0Sstevel@tonic-gate while ((next = nextitem(thisitem)) <= netobuf.send) {
2404*0Sstevel@tonic-gate thisitem = next;
2405*0Sstevel@tonic-gate }
2406*0Sstevel@tonic-gate
2407*0Sstevel@tonic-gate /* Now, thisitem is first before/at boundary. */
2408*0Sstevel@tonic-gate
2409*0Sstevel@tonic-gate good = netobuf; /* where the good bytes go */
2410*0Sstevel@tonic-gate
2411*0Sstevel@tonic-gate while (netoring.add > thisitem) {
2412*0Sstevel@tonic-gate if (wewant(thisitem)) {
2413*0Sstevel@tonic-gate int length;
2414*0Sstevel@tonic-gate
2415*0Sstevel@tonic-gate next = thisitem;
2416*0Sstevel@tonic-gate do {
2417*0Sstevel@tonic-gate next = nextitem(next);
2418*0Sstevel@tonic-gate } while (wewant(next) && (nfrontp > next));
2419*0Sstevel@tonic-gate length = next-thisitem;
2420*0Sstevel@tonic-gate memcpy(good, thisitem, length);
2421*0Sstevel@tonic-gate good += length;
2422*0Sstevel@tonic-gate thisitem = next;
2423*0Sstevel@tonic-gate } else {
2424*0Sstevel@tonic-gate thisitem = nextitem(thisitem);
2425*0Sstevel@tonic-gate }
2426*0Sstevel@tonic-gate }
2427*0Sstevel@tonic-gate
2428*0Sstevel@tonic-gate #endif /* 0 */
2429*0Sstevel@tonic-gate }
2430*0Sstevel@tonic-gate
2431*0Sstevel@tonic-gate /*
2432*0Sstevel@tonic-gate * These routines add various telnet commands to the data stream.
2433*0Sstevel@tonic-gate */
2434*0Sstevel@tonic-gate
2435*0Sstevel@tonic-gate /*
2436*0Sstevel@tonic-gate * doflush - Send do timing mark (for network connection flush) & then
2437*0Sstevel@tonic-gate * get rid of anything in the output buffer. Return -1 if there was a
2438*0Sstevel@tonic-gate * non-EWOULDBLOCK error on the tty flush, and otherwise return 0.
2439*0Sstevel@tonic-gate */
2440*0Sstevel@tonic-gate static int
doflush()2441*0Sstevel@tonic-gate doflush()
2442*0Sstevel@tonic-gate {
2443*0Sstevel@tonic-gate NET2ADD(IAC, DO);
2444*0Sstevel@tonic-gate NETADD(TELOPT_TM);
2445*0Sstevel@tonic-gate flushline = 1;
2446*0Sstevel@tonic-gate flushout = 1;
2447*0Sstevel@tonic-gate
2448*0Sstevel@tonic-gate /* Drop pending tty output */
2449*0Sstevel@tonic-gate if (ttyflush(1) == -2)
2450*0Sstevel@tonic-gate return (-1);
2451*0Sstevel@tonic-gate
2452*0Sstevel@tonic-gate /* do printoption AFTER flush, otherwise the output gets tossed... */
2453*0Sstevel@tonic-gate printoption("SENT", DO, TELOPT_TM);
2454*0Sstevel@tonic-gate return (0);
2455*0Sstevel@tonic-gate }
2456*0Sstevel@tonic-gate
2457*0Sstevel@tonic-gate int
xmitAO()2458*0Sstevel@tonic-gate xmitAO()
2459*0Sstevel@tonic-gate {
2460*0Sstevel@tonic-gate NET2ADD(IAC, AO);
2461*0Sstevel@tonic-gate printoption("SENT", IAC, AO);
2462*0Sstevel@tonic-gate if (autoflush) {
2463*0Sstevel@tonic-gate if (doflush() == -1)
2464*0Sstevel@tonic-gate return (-1);
2465*0Sstevel@tonic-gate }
2466*0Sstevel@tonic-gate return (0);
2467*0Sstevel@tonic-gate }
2468*0Sstevel@tonic-gate
2469*0Sstevel@tonic-gate
2470*0Sstevel@tonic-gate void
xmitEL()2471*0Sstevel@tonic-gate xmitEL()
2472*0Sstevel@tonic-gate {
2473*0Sstevel@tonic-gate NET2ADD(IAC, EL);
2474*0Sstevel@tonic-gate printoption("SENT", IAC, EL);
2475*0Sstevel@tonic-gate }
2476*0Sstevel@tonic-gate
2477*0Sstevel@tonic-gate void
xmitEC()2478*0Sstevel@tonic-gate xmitEC()
2479*0Sstevel@tonic-gate {
2480*0Sstevel@tonic-gate NET2ADD(IAC, EC);
2481*0Sstevel@tonic-gate printoption("SENT", IAC, EC);
2482*0Sstevel@tonic-gate }
2483*0Sstevel@tonic-gate
2484*0Sstevel@tonic-gate
2485*0Sstevel@tonic-gate int
dosynch()2486*0Sstevel@tonic-gate dosynch()
2487*0Sstevel@tonic-gate {
2488*0Sstevel@tonic-gate netclear(); /* clear the path to the network */
2489*0Sstevel@tonic-gate NETADD(IAC);
2490*0Sstevel@tonic-gate setneturg();
2491*0Sstevel@tonic-gate NETADD(DM);
2492*0Sstevel@tonic-gate printoption("SENT", IAC, DM);
2493*0Sstevel@tonic-gate return (1);
2494*0Sstevel@tonic-gate }
2495*0Sstevel@tonic-gate
2496*0Sstevel@tonic-gate int want_status_response = 0;
2497*0Sstevel@tonic-gate
2498*0Sstevel@tonic-gate int
get_status()2499*0Sstevel@tonic-gate get_status()
2500*0Sstevel@tonic-gate {
2501*0Sstevel@tonic-gate unsigned char tmp[16];
2502*0Sstevel@tonic-gate register unsigned char *cp;
2503*0Sstevel@tonic-gate
2504*0Sstevel@tonic-gate if (my_want_state_is_dont(TELOPT_STATUS)) {
2505*0Sstevel@tonic-gate (void) printf("Remote side does not support STATUS option\n");
2506*0Sstevel@tonic-gate return (0);
2507*0Sstevel@tonic-gate }
2508*0Sstevel@tonic-gate cp = tmp;
2509*0Sstevel@tonic-gate
2510*0Sstevel@tonic-gate *cp++ = IAC;
2511*0Sstevel@tonic-gate *cp++ = SB;
2512*0Sstevel@tonic-gate *cp++ = TELOPT_STATUS;
2513*0Sstevel@tonic-gate *cp++ = TELQUAL_SEND;
2514*0Sstevel@tonic-gate *cp++ = IAC;
2515*0Sstevel@tonic-gate *cp++ = SE;
2516*0Sstevel@tonic-gate if (NETROOM() >= cp - tmp) {
2517*0Sstevel@tonic-gate ring_supply_data(&netoring, tmp, cp-tmp);
2518*0Sstevel@tonic-gate printsub('>', tmp+2, cp - tmp - 2);
2519*0Sstevel@tonic-gate }
2520*0Sstevel@tonic-gate ++want_status_response;
2521*0Sstevel@tonic-gate return (1);
2522*0Sstevel@tonic-gate }
2523*0Sstevel@tonic-gate
2524*0Sstevel@tonic-gate void
intp()2525*0Sstevel@tonic-gate intp()
2526*0Sstevel@tonic-gate {
2527*0Sstevel@tonic-gate NET2ADD(IAC, IP);
2528*0Sstevel@tonic-gate printoption("SENT", IAC, IP);
2529*0Sstevel@tonic-gate flushline = 1;
2530*0Sstevel@tonic-gate if (autoflush) {
2531*0Sstevel@tonic-gate /* Ignore return as we're ending off anyway. */
2532*0Sstevel@tonic-gate (void) doflush();
2533*0Sstevel@tonic-gate }
2534*0Sstevel@tonic-gate if (autosynch) {
2535*0Sstevel@tonic-gate (void) dosynch();
2536*0Sstevel@tonic-gate }
2537*0Sstevel@tonic-gate }
2538*0Sstevel@tonic-gate
2539*0Sstevel@tonic-gate int
sendbrk()2540*0Sstevel@tonic-gate sendbrk()
2541*0Sstevel@tonic-gate {
2542*0Sstevel@tonic-gate NET2ADD(IAC, BREAK);
2543*0Sstevel@tonic-gate printoption("SENT", IAC, BREAK);
2544*0Sstevel@tonic-gate flushline = 1;
2545*0Sstevel@tonic-gate if (autoflush) {
2546*0Sstevel@tonic-gate if (doflush() == -1)
2547*0Sstevel@tonic-gate return (-1);
2548*0Sstevel@tonic-gate }
2549*0Sstevel@tonic-gate if (autosynch) {
2550*0Sstevel@tonic-gate (void) dosynch();
2551*0Sstevel@tonic-gate }
2552*0Sstevel@tonic-gate return (0);
2553*0Sstevel@tonic-gate }
2554*0Sstevel@tonic-gate
2555*0Sstevel@tonic-gate void
sendabort()2556*0Sstevel@tonic-gate sendabort()
2557*0Sstevel@tonic-gate {
2558*0Sstevel@tonic-gate NET2ADD(IAC, ABORT);
2559*0Sstevel@tonic-gate printoption("SENT", IAC, ABORT);
2560*0Sstevel@tonic-gate flushline = 1;
2561*0Sstevel@tonic-gate if (autoflush) {
2562*0Sstevel@tonic-gate /*
2563*0Sstevel@tonic-gate * Since sendabort() gets called while aborting,
2564*0Sstevel@tonic-gate * ignore the doflush() return
2565*0Sstevel@tonic-gate */
2566*0Sstevel@tonic-gate (void) doflush();
2567*0Sstevel@tonic-gate }
2568*0Sstevel@tonic-gate if (autosynch) {
2569*0Sstevel@tonic-gate (void) dosynch();
2570*0Sstevel@tonic-gate }
2571*0Sstevel@tonic-gate }
2572*0Sstevel@tonic-gate
2573*0Sstevel@tonic-gate void
sendsusp()2574*0Sstevel@tonic-gate sendsusp()
2575*0Sstevel@tonic-gate {
2576*0Sstevel@tonic-gate NET2ADD(IAC, SUSP);
2577*0Sstevel@tonic-gate printoption("SENT", IAC, SUSP);
2578*0Sstevel@tonic-gate flushline = 1;
2579*0Sstevel@tonic-gate if (autoflush) {
2580*0Sstevel@tonic-gate if (doflush() == -1) {
2581*0Sstevel@tonic-gate /* The following will not return. */
2582*0Sstevel@tonic-gate fatal_tty_error("write");
2583*0Sstevel@tonic-gate }
2584*0Sstevel@tonic-gate }
2585*0Sstevel@tonic-gate if (autosynch) {
2586*0Sstevel@tonic-gate (void) dosynch();
2587*0Sstevel@tonic-gate }
2588*0Sstevel@tonic-gate }
2589*0Sstevel@tonic-gate
2590*0Sstevel@tonic-gate static void
sendeof()2591*0Sstevel@tonic-gate sendeof()
2592*0Sstevel@tonic-gate {
2593*0Sstevel@tonic-gate NET2ADD(IAC, xEOF);
2594*0Sstevel@tonic-gate printoption("SENT", IAC, xEOF);
2595*0Sstevel@tonic-gate }
2596*0Sstevel@tonic-gate
2597*0Sstevel@tonic-gate /*
2598*0Sstevel@tonic-gate * Send a window size update to the remote system.
2599*0Sstevel@tonic-gate */
2600*0Sstevel@tonic-gate
2601*0Sstevel@tonic-gate void
sendnaws()2602*0Sstevel@tonic-gate sendnaws()
2603*0Sstevel@tonic-gate {
2604*0Sstevel@tonic-gate unsigned short rows, cols;
2605*0Sstevel@tonic-gate unsigned char tmp[16];
2606*0Sstevel@tonic-gate register unsigned char *cp;
2607*0Sstevel@tonic-gate
2608*0Sstevel@tonic-gate if (my_state_is_wont(TELOPT_NAWS))
2609*0Sstevel@tonic-gate return;
2610*0Sstevel@tonic-gate
2611*0Sstevel@tonic-gate #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2612*0Sstevel@tonic-gate if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2613*0Sstevel@tonic-gate
2614*0Sstevel@tonic-gate if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
2615*0Sstevel@tonic-gate return;
2616*0Sstevel@tonic-gate }
2617*0Sstevel@tonic-gate
2618*0Sstevel@tonic-gate cp = tmp;
2619*0Sstevel@tonic-gate
2620*0Sstevel@tonic-gate *cp++ = IAC;
2621*0Sstevel@tonic-gate *cp++ = SB;
2622*0Sstevel@tonic-gate *cp++ = TELOPT_NAWS;
2623*0Sstevel@tonic-gate PUTSHORT(cp, cols);
2624*0Sstevel@tonic-gate PUTSHORT(cp, rows);
2625*0Sstevel@tonic-gate *cp++ = IAC;
2626*0Sstevel@tonic-gate *cp++ = SE;
2627*0Sstevel@tonic-gate if (NETROOM() >= cp - tmp) {
2628*0Sstevel@tonic-gate ring_supply_data(&netoring, tmp, cp-tmp);
2629*0Sstevel@tonic-gate printsub('>', tmp+2, cp - tmp - 2);
2630*0Sstevel@tonic-gate }
2631*0Sstevel@tonic-gate }
2632*0Sstevel@tonic-gate
2633*0Sstevel@tonic-gate void
tel_enter_binary(rw)2634*0Sstevel@tonic-gate tel_enter_binary(rw)
2635*0Sstevel@tonic-gate int rw;
2636*0Sstevel@tonic-gate {
2637*0Sstevel@tonic-gate if (rw&1)
2638*0Sstevel@tonic-gate send_do(TELOPT_BINARY, 1);
2639*0Sstevel@tonic-gate if (rw&2)
2640*0Sstevel@tonic-gate send_will(TELOPT_BINARY, 1);
2641*0Sstevel@tonic-gate }
2642*0Sstevel@tonic-gate
2643*0Sstevel@tonic-gate void
tel_leave_binary(rw)2644*0Sstevel@tonic-gate tel_leave_binary(rw)
2645*0Sstevel@tonic-gate int rw;
2646*0Sstevel@tonic-gate {
2647*0Sstevel@tonic-gate if (rw&1)
2648*0Sstevel@tonic-gate send_dont(TELOPT_BINARY, 1);
2649*0Sstevel@tonic-gate if (rw&2)
2650*0Sstevel@tonic-gate send_wont(TELOPT_BINARY, 1);
2651*0Sstevel@tonic-gate }
2652