blob: 2ad44d4299d08ab74029fa9f3d9e1262733ed1e0 [file] [log] [blame]
Eric Andersen28c70b32000-06-14 20:42:57 +00001/* vi: set sw=4 ts=4: */
Erik Andersenf7c49ef2000-02-22 17:17:45 +00002/*
Eric Andersen28c70b32000-06-14 20:42:57 +00003 * telnet implementation for busybox
Erik Andersenf7c49ef2000-02-22 17:17:45 +00004 *
Eric Andersen28c70b32000-06-14 20:42:57 +00005 * Author: Tomi Ollila <too@iki.fi>
6 * Copyright (C) 1994-2000 by Tomi Ollila
7 *
8 * Created: Thu Apr 7 13:29:41 1994 too
9 * Last modified: Fri Jun 9 14:34:24 2000 too
Erik Andersenf7c49ef2000-02-22 17:17:45 +000010 *
Rob Landley1b751c82005-10-28 09:24:33 +000011 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
Erik Andersenf7c49ef2000-02-22 17:17:45 +000012 *
Eric Andersen28c70b32000-06-14 20:42:57 +000013 * HISTORY
14 * Revision 3.1 1994/04/17 11:31:54 too
15 * initial revision
Eric Andersencb81e642003-07-14 21:21:08 +000016 * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen <andersen@codepoet.org>
Eric Andersen7e1273e2001-05-07 17:57:45 +000017 * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan
18 * <jam@ltsp.org>
Eric Andersen539ffc92004-02-22 12:25:47 +000019 * Modified 2004/02/11 to add ability to pass the USER variable to remote host
20 * by Fernando Silveira <swrh@gmx.net>
Erik Andersenf7c49ef2000-02-22 17:17:45 +000021 *
Erik Andersenf7c49ef2000-02-22 17:17:45 +000022 */
23
Erik Andersenf7c49ef2000-02-22 17:17:45 +000024#include <termios.h>
Eric Andersen28c70b32000-06-14 20:42:57 +000025#include <unistd.h>
26#include <errno.h>
27#include <stdlib.h>
28#include <stdarg.h>
Eric Andersen2276d832002-07-11 11:11:56 +000029#include <string.h>
Eric Andersen28c70b32000-06-14 20:42:57 +000030#include <signal.h>
31#include <arpa/telnet.h>
Erik Andersenf7c49ef2000-02-22 17:17:45 +000032#include <sys/types.h>
33#include <sys/socket.h>
Eric Andersen28c70b32000-06-14 20:42:57 +000034#include <netinet/in.h>
Eric Andersencbe31da2001-02-20 06:14:08 +000035#include "busybox.h"
Erik Andersenf7c49ef2000-02-22 17:17:45 +000036
Eric Andersen28c70b32000-06-14 20:42:57 +000037#if 0
Rob Landleybc68cd12006-03-10 19:22:06 +000038enum { DOTRACE = 1 };
Eric Andersen28c70b32000-06-14 20:42:57 +000039#endif
40
Pavel Roskin616d13b2000-07-28 19:38:27 +000041#ifdef DOTRACE
Eric Andersen28c70b32000-06-14 20:42:57 +000042#include <arpa/inet.h> /* for inet_ntoa()... */
43#define TRACE(x, y) do { if (x) printf y; } while (0)
44#else
Eric Andersenc7bda1c2004-03-15 08:29:22 +000045#define TRACE(x, y)
Eric Andersen28c70b32000-06-14 20:42:57 +000046#endif
47
48#if 0
49#define USE_POLL
50#include <sys/poll.h>
51#else
52#include <sys/time.h>
53#endif
54
Glenn L McGrath78b0e372001-06-26 02:06:08 +000055#define DATABUFSIZE 128
56#define IACBUFSIZE 128
Eric Andersen28c70b32000-06-14 20:42:57 +000057
Mark Whitley59ab0252001-01-23 22:30:04 +000058enum {
Rob Landleybc68cd12006-03-10 19:22:06 +000059 CHM_TRY = 0,
60 CHM_ON = 1,
61 CHM_OFF = 2,
62
63 UF_ECHO = 0x01,
64 UF_SGA = 0x02,
65
Mark Whitley59ab0252001-01-23 22:30:04 +000066 TS_0 = 1,
67 TS_IAC = 2,
68 TS_OPT = 3,
69 TS_SUB1 = 4,
70 TS_SUB2 = 5,
71};
Eric Andersen28c70b32000-06-14 20:42:57 +000072
73#define WriteCS(fd, str) write(fd, str, sizeof str -1)
74
75typedef unsigned char byte;
76
77/* use globals to reduce size ??? */ /* test this hypothesis later */
Eric Andersen92d23242001-03-19 23:49:41 +000078static struct Globalvars {
Eric Andersen28c70b32000-06-14 20:42:57 +000079 int netfd; /* console fd:s are 0 and 1 (and 2) */
80 /* same buffer used both for network and console read/write */
Glenn L McGrath78b0e372001-06-26 02:06:08 +000081 char buf[DATABUFSIZE]; /* allocating so static size is smaller */
Eric Andersen28c70b32000-06-14 20:42:57 +000082 byte telstate; /* telnet negotiation state from network input */
83 byte telwish; /* DO, DONT, WILL, WONT */
84 byte charmode;
85 byte telflags;
86 byte gotsig;
Paul Foxf2ddc052005-07-20 19:55:19 +000087 byte do_termios;
Eric Andersen28c70b32000-06-14 20:42:57 +000088 /* buffer to handle telnet negotiations */
Glenn L McGrath78b0e372001-06-26 02:06:08 +000089 char iacbuf[IACBUFSIZE];
Eric Andersen28c70b32000-06-14 20:42:57 +000090 short iaclen; /* could even use byte */
Eric Andersenc7bda1c2004-03-15 08:29:22 +000091 struct termios termios_def;
92 struct termios termios_raw;
Eric Andersen28c70b32000-06-14 20:42:57 +000093} G;
94
95#define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */
96
97#ifdef USE_GLOBALVAR_PTR
98struct Globalvars * Gptr;
99#define G (*Gptr)
Eric Andersen28c70b32000-06-14 20:42:57 +0000100#endif
101
Eric Andersencd8c4362001-11-10 11:22:46 +0000102static inline void iacflush(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000103{
104 write(G.netfd, G.iacbuf, G.iaclen);
105 G.iaclen = 0;
106}
107
108/* Function prototypes */
Eric Andersencd8c4362001-11-10 11:22:46 +0000109static void rawmode(void);
110static void cookmode(void);
111static void do_linemode(void);
112static void will_charmode(void);
Eric Andersen28c70b32000-06-14 20:42:57 +0000113static void telopt(byte c);
114static int subneg(byte c);
Eric Andersen28c70b32000-06-14 20:42:57 +0000115
116/* Some globals */
117static int one = 1;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000118
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000119#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000120static char *ttype;
121#endif
122
Eric Andersen539ffc92004-02-22 12:25:47 +0000123#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
Glenn L McGrathd4004ee2004-09-14 17:24:59 +0000124static const char *autologin;
Eric Andersen539ffc92004-02-22 12:25:47 +0000125#endif
126
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000127#ifdef CONFIG_FEATURE_AUTOWIDTH
128static int win_width, win_height;
129#endif
130
Eric Andersen28c70b32000-06-14 20:42:57 +0000131static void doexit(int ev)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000132{
Eric Andersen28c70b32000-06-14 20:42:57 +0000133 cookmode();
134 exit(ev);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000135}
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000136
Eric Andersencd8c4362001-11-10 11:22:46 +0000137static void conescape(void)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000138{
Eric Andersen28c70b32000-06-14 20:42:57 +0000139 char b;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000140
Eric Andersen28c70b32000-06-14 20:42:57 +0000141 if (G.gotsig) /* came from line mode... go raw */
142 rawmode();
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000143
Eric Andersen28c70b32000-06-14 20:42:57 +0000144 WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n"
145 " l go to line mode\r\n"
146 " c go to character mode\r\n"
147 " z suspend telnet\r\n"
148 " e exit telnet\r\n");
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000149
Eric Andersen28c70b32000-06-14 20:42:57 +0000150 if (read(0, &b, 1) <= 0)
151 doexit(1);
152
153 switch (b)
154 {
155 case 'l':
156 if (!G.gotsig)
157 {
158 do_linemode();
159 goto rrturn;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000160 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000161 break;
162 case 'c':
163 if (G.gotsig)
164 {
165 will_charmode();
166 goto rrturn;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000167 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000168 break;
169 case 'z':
170 cookmode();
171 kill(0, SIGTSTP);
172 rawmode();
173 break;
174 case 'e':
175 doexit(0);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000176 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000177
178 WriteCS(1, "continuing...\r\n");
179
180 if (G.gotsig)
181 cookmode();
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000182
Eric Andersen28c70b32000-06-14 20:42:57 +0000183 rrturn:
184 G.gotsig = 0;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000185
Eric Andersen28c70b32000-06-14 20:42:57 +0000186}
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000187static void handlenetoutput(int len)
Eric Andersen28c70b32000-06-14 20:42:57 +0000188{
189 /* here we could do smart tricks how to handle 0xFF:s in output
190 * stream like writing twice every sequence of FF:s (thus doing
191 * many write()s. But I think interactive telnet application does
192 * not need to be 100% 8-bit clean, so changing every 0xff:s to
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000193 * 0x7f:s
194 *
195 * 2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com)
196 * I don't agree.
197 * first - I cannot use programs like sz/rz
198 * second - the 0x0D is sent as one character and if the next
199 * char is 0x0A then it's eaten by a server side.
200 * third - whay doy you have to make 'many write()s'?
201 * I don't understand.
202 * So I implemented it. It's realy useful for me. I hope that
203 * others people will find it interesting to.
204 */
Eric Andersen28c70b32000-06-14 20:42:57 +0000205
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000206 int i, j;
Eric Andersen0cb6f352006-01-30 22:30:41 +0000207 byte * p = (byte*)G.buf;
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000208 byte outbuf[4*DATABUFSIZE];
Eric Andersen28c70b32000-06-14 20:42:57 +0000209
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000210 for (i = len, j = 0; i > 0; i--, p++)
Eric Andersen28c70b32000-06-14 20:42:57 +0000211 {
212 if (*p == 0x1d)
213 {
214 conescape();
215 return;
216 }
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000217 outbuf[j++] = *p;
Eric Andersen28c70b32000-06-14 20:42:57 +0000218 if (*p == 0xff)
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000219 outbuf[j++] = 0xff;
220 else if (*p == 0x0d)
221 outbuf[j++] = 0x00;
Eric Andersen28c70b32000-06-14 20:42:57 +0000222 }
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000223 if (j > 0 )
224 write(G.netfd, outbuf, j);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000225}
226
Eric Andersen28c70b32000-06-14 20:42:57 +0000227
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000228static void handlenetinput(int len)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000229{
Eric Andersen28c70b32000-06-14 20:42:57 +0000230 int i;
231 int cstart = 0;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000232
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000233 for (i = 0; i < len; i++)
Eric Andersen28c70b32000-06-14 20:42:57 +0000234 {
235 byte c = G.buf[i];
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000236
Eric Andersen28c70b32000-06-14 20:42:57 +0000237 if (G.telstate == 0) /* most of the time state == 0 */
238 {
239 if (c == IAC)
240 {
241 cstart = i;
242 G.telstate = TS_IAC;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000243 }
244 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000245 else
246 switch (G.telstate)
247 {
248 case TS_0:
249 if (c == IAC)
250 G.telstate = TS_IAC;
251 else
252 G.buf[cstart++] = c;
253 break;
254
255 case TS_IAC:
256 if (c == IAC) /* IAC IAC -> 0xFF */
257 {
258 G.buf[cstart++] = c;
259 G.telstate = TS_0;
260 break;
261 }
262 /* else */
263 switch (c)
264 {
265 case SB:
266 G.telstate = TS_SUB1;
267 break;
268 case DO:
269 case DONT:
270 case WILL:
271 case WONT:
272 G.telwish = c;
273 G.telstate = TS_OPT;
274 break;
275 default:
276 G.telstate = TS_0; /* DATA MARK must be added later */
277 }
278 break;
279 case TS_OPT: /* WILL, WONT, DO, DONT */
280 telopt(c);
281 G.telstate = TS_0;
282 break;
283 case TS_SUB1: /* Subnegotiation */
284 case TS_SUB2: /* Subnegotiation */
Matt Kraai1f0c4362001-12-20 23:13:26 +0000285 if (subneg(c))
Eric Andersen28c70b32000-06-14 20:42:57 +0000286 G.telstate = TS_0;
287 break;
288 }
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000289 }
Eric Andersen28c70b32000-06-14 20:42:57 +0000290 if (G.telstate)
291 {
292 if (G.iaclen) iacflush();
293 if (G.telstate == TS_0) G.telstate = 0;
294
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000295 len = cstart;
Eric Andersen28c70b32000-06-14 20:42:57 +0000296 }
297
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000298 if (len)
299 write(1, G.buf, len);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000300}
301
Eric Andersen28c70b32000-06-14 20:42:57 +0000302
303/* ******************************* */
304
305static inline void putiac(int c)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000306{
Eric Andersen28c70b32000-06-14 20:42:57 +0000307 G.iacbuf[G.iaclen++] = c;
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000308}
309
Eric Andersen28c70b32000-06-14 20:42:57 +0000310
311static void putiac2(byte wwdd, byte c)
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000312{
Eric Andersen28c70b32000-06-14 20:42:57 +0000313 if (G.iaclen + 3 > IACBUFSIZE)
314 iacflush();
315
316 putiac(IAC);
317 putiac(wwdd);
318 putiac(c);
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000319}
320
Eric Andersen28c70b32000-06-14 20:42:57 +0000321#if 0
322static void putiac1(byte c)
323{
324 if (G.iaclen + 2 > IACBUFSIZE)
325 iacflush();
326
327 putiac(IAC);
328 putiac(c);
329}
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000330#endif
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000331
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000332#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000333static void putiac_subopt(byte c, char *str)
334{
335 int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 )
336
337 if (G.iaclen + len > IACBUFSIZE)
338 iacflush();
339
340 putiac(IAC);
341 putiac(SB);
342 putiac(c);
343 putiac(0);
344
345 while(*str)
346 putiac(*str++);
347
348 putiac(IAC);
349 putiac(SE);
350}
351#endif
352
Eric Andersen539ffc92004-02-22 12:25:47 +0000353#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
354static void putiac_subopt_autologin(void)
355{
356 int len = strlen(autologin) + 6; // (2 + 1 + 1 + strlen + 2)
357 char *user = "USER";
358
359 if (G.iaclen + len > IACBUFSIZE)
360 iacflush();
361
362 putiac(IAC);
363 putiac(SB);
364 putiac(TELOPT_NEW_ENVIRON);
365 putiac(TELQUAL_IS);
366 putiac(NEW_ENV_VAR);
367
368 while(*user)
369 putiac(*user++);
370
371 putiac(NEW_ENV_VALUE);
372
373 while(*autologin)
374 putiac(*autologin++);
375
376 putiac(IAC);
377 putiac(SE);
378}
379#endif
380
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000381#ifdef CONFIG_FEATURE_AUTOWIDTH
382static void putiac_naws(byte c, int x, int y)
383{
384 if (G.iaclen + 9 > IACBUFSIZE)
385 iacflush();
386
387 putiac(IAC);
388 putiac(SB);
389 putiac(c);
390
391 putiac((x >> 8) & 0xff);
392 putiac(x & 0xff);
393 putiac((y >> 8) & 0xff);
394 putiac(y & 0xff);
395
396 putiac(IAC);
397 putiac(SE);
398}
399#endif
400
Eric Andersen28c70b32000-06-14 20:42:57 +0000401/* void putiacstring (subneg strings) */
402
403/* ******************************* */
404
Eric Andersen3e6ff902001-03-09 21:24:12 +0000405static char const escapecharis[] = "\r\nEscape character is ";
Eric Andersen28c70b32000-06-14 20:42:57 +0000406
Eric Andersencd8c4362001-11-10 11:22:46 +0000407static void setConMode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000408{
409 if (G.telflags & UF_ECHO)
410 {
411 if (G.charmode == CHM_TRY) {
412 G.charmode = CHM_ON;
Matt Kraai12f417e2001-01-18 02:57:08 +0000413 printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis);
Eric Andersen28c70b32000-06-14 20:42:57 +0000414 rawmode();
415 }
416 }
417 else
418 {
419 if (G.charmode != CHM_OFF) {
420 G.charmode = CHM_OFF;
Matt Kraai12f417e2001-01-18 02:57:08 +0000421 printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis);
Eric Andersen28c70b32000-06-14 20:42:57 +0000422 cookmode();
423 }
424 }
425}
426
427/* ******************************* */
428
Eric Andersencd8c4362001-11-10 11:22:46 +0000429static void will_charmode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000430{
431 G.charmode = CHM_TRY;
432 G.telflags |= (UF_ECHO | UF_SGA);
433 setConMode();
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000434
Eric Andersen28c70b32000-06-14 20:42:57 +0000435 putiac2(DO, TELOPT_ECHO);
436 putiac2(DO, TELOPT_SGA);
437 iacflush();
438}
439
Eric Andersencd8c4362001-11-10 11:22:46 +0000440static void do_linemode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000441{
442 G.charmode = CHM_TRY;
443 G.telflags &= ~(UF_ECHO | UF_SGA);
444 setConMode();
445
446 putiac2(DONT, TELOPT_ECHO);
447 putiac2(DONT, TELOPT_SGA);
448 iacflush();
449}
450
451/* ******************************* */
452
453static inline void to_notsup(char c)
454{
455 if (G.telwish == WILL) putiac2(DONT, c);
456 else if (G.telwish == DO) putiac2(WONT, c);
457}
458
Eric Andersencd8c4362001-11-10 11:22:46 +0000459static inline void to_echo(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000460{
461 /* if server requests ECHO, don't agree */
462 if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; }
463 else if (G.telwish == DONT) return;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000464
Eric Andersen28c70b32000-06-14 20:42:57 +0000465 if (G.telflags & UF_ECHO)
466 {
467 if (G.telwish == WILL)
468 return;
469 }
470 else
471 if (G.telwish == WONT)
472 return;
473
474 if (G.charmode != CHM_OFF)
475 G.telflags ^= UF_ECHO;
476
477 if (G.telflags & UF_ECHO)
478 putiac2(DO, TELOPT_ECHO);
479 else
480 putiac2(DONT, TELOPT_ECHO);
481
482 setConMode();
483 WriteCS(1, "\r\n"); /* sudden modec */
484}
485
Eric Andersencd8c4362001-11-10 11:22:46 +0000486static inline void to_sga(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000487{
488 /* daemon always sends will/wont, client do/dont */
489
490 if (G.telflags & UF_SGA)
491 {
492 if (G.telwish == WILL)
493 return;
494 }
495 else
496 if (G.telwish == WONT)
497 return;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000498
Eric Andersen28c70b32000-06-14 20:42:57 +0000499 if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */
500 putiac2(DO, TELOPT_SGA);
501 else
502 putiac2(DONT, TELOPT_SGA);
503
504 return;
505}
506
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000507#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersencd8c4362001-11-10 11:22:46 +0000508static inline void to_ttype(void)
Eric Andersen7e1273e2001-05-07 17:57:45 +0000509{
510 /* Tell server we will (or won't) do TTYPE */
511
512 if(ttype)
513 putiac2(WILL, TELOPT_TTYPE);
514 else
515 putiac2(WONT, TELOPT_TTYPE);
516
517 return;
518}
519#endif
520
Eric Andersen539ffc92004-02-22 12:25:47 +0000521#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
522static inline void to_new_environ(void)
523{
524 /* Tell server we will (or will not) do AUTOLOGIN */
525
526 if (autologin)
527 putiac2(WILL, TELOPT_NEW_ENVIRON);
528 else
529 putiac2(WONT, TELOPT_NEW_ENVIRON);
530
531 return;
532}
533#endif
534
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000535#ifdef CONFIG_FEATURE_AUTOWIDTH
Tim Rikered8e0362002-04-26 07:53:39 +0000536static inline void to_naws(void)
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000537{
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000538 /* Tell server we will do NAWS */
539 putiac2(WILL, TELOPT_NAWS);
540 return;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000541}
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000542#endif
543
Eric Andersen28c70b32000-06-14 20:42:57 +0000544static void telopt(byte c)
545{
546 switch (c)
547 {
Eric Andersen41634062002-04-26 08:44:17 +0000548 case TELOPT_ECHO: to_echo(); break;
549 case TELOPT_SGA: to_sga(); break;
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000550#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen41634062002-04-26 08:44:17 +0000551 case TELOPT_TTYPE: to_ttype();break;
Eric Andersen7e1273e2001-05-07 17:57:45 +0000552#endif
Eric Andersen539ffc92004-02-22 12:25:47 +0000553#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
554 case TELOPT_NEW_ENVIRON: to_new_environ(); break;
555#endif
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000556#ifdef CONFIG_FEATURE_AUTOWIDTH
Eric Andersen41634062002-04-26 08:44:17 +0000557 case TELOPT_NAWS: to_naws();
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000558 putiac_naws(c, win_width, win_height);
559 break;
560#endif
Eric Andersen8db361b2002-04-26 08:00:33 +0000561 default: to_notsup(c);
562 break;
Eric Andersen28c70b32000-06-14 20:42:57 +0000563 }
564}
565
566
567/* ******************************* */
568
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000569/* subnegotiation -- ignore all (except TTYPE,NAWS) */
Eric Andersen28c70b32000-06-14 20:42:57 +0000570
571static int subneg(byte c)
572{
573 switch (G.telstate)
574 {
575 case TS_SUB1:
576 if (c == IAC)
577 G.telstate = TS_SUB2;
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000578#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000579 else
580 if (c == TELOPT_TTYPE)
581 putiac_subopt(TELOPT_TTYPE,ttype);
582#endif
Eric Andersen539ffc92004-02-22 12:25:47 +0000583#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
584 else
585 if (c == TELOPT_NEW_ENVIRON)
586 putiac_subopt_autologin();
587#endif
Eric Andersen28c70b32000-06-14 20:42:57 +0000588 break;
589 case TS_SUB2:
590 if (c == SE)
591 return TRUE;
592 G.telstate = TS_SUB1;
593 /* break; */
594 }
595 return FALSE;
596}
597
598/* ******************************* */
599
600static void fgotsig(int sig)
601{
602 G.gotsig = sig;
603}
604
605
Eric Andersencd8c4362001-11-10 11:22:46 +0000606static void rawmode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000607{
Paul Foxf2ddc052005-07-20 19:55:19 +0000608 if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_raw);
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000609}
Eric Andersen28c70b32000-06-14 20:42:57 +0000610
Eric Andersencd8c4362001-11-10 11:22:46 +0000611static void cookmode(void)
Eric Andersen28c70b32000-06-14 20:42:57 +0000612{
Paul Foxf2ddc052005-07-20 19:55:19 +0000613 if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_def);
Eric Andersen28c70b32000-06-14 20:42:57 +0000614}
615
Rob Landleydfba7412006-03-06 20:47:33 +0000616int telnet_main(int argc, char** argv)
Eric Andersen28c70b32000-06-14 20:42:57 +0000617{
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000618 int len;
Eric Andersene6dc4392003-10-31 09:31:46 +0000619 struct sockaddr_in s_in;
Eric Andersen28c70b32000-06-14 20:42:57 +0000620#ifdef USE_POLL
621 struct pollfd ufds[2];
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000622#else
Eric Andersen28c70b32000-06-14 20:42:57 +0000623 fd_set readfds;
624 int maxfd;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000625#endif
Eric Andersen28c70b32000-06-14 20:42:57 +0000626
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000627#ifdef CONFIG_FEATURE_AUTOWIDTH
Eric Andersen8efe9672003-09-15 08:33:45 +0000628 get_terminal_width_height(0, &win_width, &win_height);
Eric Andersen0e28e1f2002-04-26 07:20:47 +0000629#endif
630
Eric Andersenbdfd0d72001-10-24 05:00:29 +0000631#ifdef CONFIG_FEATURE_TELNET_TTYPE
Eric Andersen7e1273e2001-05-07 17:57:45 +0000632 ttype = getenv("TERM");
633#endif
Eric Andersen28c70b32000-06-14 20:42:57 +0000634
635 memset(&G, 0, sizeof G);
636
Paul Foxf2ddc052005-07-20 19:55:19 +0000637 if (tcgetattr(0, &G.termios_def) >= 0) {
638 G.do_termios = 1;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000639
Paul Foxf2ddc052005-07-20 19:55:19 +0000640 G.termios_raw = G.termios_def;
641 cfmakeraw(&G.termios_raw);
642 }
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000643
Glenn L McGrathffccf6e2003-12-20 01:47:18 +0000644 if (argc < 2)
645 bb_show_usage();
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000646
Eric Andersen539ffc92004-02-22 12:25:47 +0000647#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN
Paul Fox5a16a892005-11-28 16:29:45 +0000648 if (1 & bb_getopt_ulflags(argc, argv, "al:", &autologin))
Rob Landley1b751c82005-10-28 09:24:33 +0000649 autologin = getenv("USER");
Tim Rikerc1ef7bd2006-01-25 00:08:53 +0000650
Eric Andersen539ffc92004-02-22 12:25:47 +0000651 if (optind < argc) {
652 bb_lookup_host(&s_in, argv[optind++]);
653 s_in.sin_port = bb_lookup_port((optind < argc) ? argv[optind++] :
654 "telnet", "tcp", 23);
655 if (optind < argc)
656 bb_show_usage();
657 } else
658 bb_show_usage();
659#else
Glenn L McGrathffccf6e2003-12-20 01:47:18 +0000660 bb_lookup_host(&s_in, argv[1]);
Glenn L McGrath036dbaa2004-01-17 05:03:31 +0000661 s_in.sin_port = bb_lookup_port((argc == 3) ? argv[2] : "telnet", "tcp", 23);
Eric Andersen539ffc92004-02-22 12:25:47 +0000662#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000663
Eric Andersene6dc4392003-10-31 09:31:46 +0000664 G.netfd = xconnect(&s_in);
Eric Andersen28c70b32000-06-14 20:42:57 +0000665
Eric Andersen0b315862002-07-03 11:51:44 +0000666 setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one);
Eric Andersen28c70b32000-06-14 20:42:57 +0000667
668 signal(SIGINT, fgotsig);
669
670#ifdef USE_POLL
671 ufds[0].fd = 0; ufds[1].fd = G.netfd;
672 ufds[0].events = ufds[1].events = POLLIN;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000673#else
Eric Andersen28c70b32000-06-14 20:42:57 +0000674 FD_ZERO(&readfds);
675 FD_SET(0, &readfds);
676 FD_SET(G.netfd, &readfds);
677 maxfd = G.netfd + 1;
678#endif
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000679
Eric Andersen28c70b32000-06-14 20:42:57 +0000680 while (1)
681 {
682#ifndef USE_POLL
683 fd_set rfds = readfds;
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000684
Eric Andersen28c70b32000-06-14 20:42:57 +0000685 switch (select(maxfd, &rfds, NULL, NULL, NULL))
686#else
687 switch (poll(ufds, 2, -1))
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000688#endif
Eric Andersen28c70b32000-06-14 20:42:57 +0000689 {
690 case 0:
691 /* timeout */
692 case -1:
693 /* error, ignore and/or log something, bay go to loop */
694 if (G.gotsig)
695 conescape();
696 else
697 sleep(1);
698 break;
699 default:
700
701#ifdef USE_POLL
702 if (ufds[0].revents) /* well, should check POLLIN, but ... */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000703#else
Eric Andersen28c70b32000-06-14 20:42:57 +0000704 if (FD_ISSET(0, &rfds))
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000705#endif
Eric Andersen28c70b32000-06-14 20:42:57 +0000706 {
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000707 len = read(0, G.buf, DATABUFSIZE);
Eric Andersen28c70b32000-06-14 20:42:57 +0000708
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000709 if (len <= 0)
Eric Andersen28c70b32000-06-14 20:42:57 +0000710 doexit(0);
711
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000712 TRACE(0, ("Read con: %d\n", len));
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000713
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000714 handlenetoutput(len);
Eric Andersen28c70b32000-06-14 20:42:57 +0000715 }
716
717#ifdef USE_POLL
718 if (ufds[1].revents) /* well, should check POLLIN, but ... */
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000719#else
Eric Andersen28c70b32000-06-14 20:42:57 +0000720 if (FD_ISSET(G.netfd, &rfds))
Eric Andersenc7bda1c2004-03-15 08:29:22 +0000721#endif
Eric Andersen28c70b32000-06-14 20:42:57 +0000722 {
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000723 len = read(G.netfd, G.buf, DATABUFSIZE);
Eric Andersen28c70b32000-06-14 20:42:57 +0000724
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000725 if (len <= 0)
Eric Andersen28c70b32000-06-14 20:42:57 +0000726 {
727 WriteCS(1, "Connection closed by foreign host.\r\n");
728 doexit(1);
729 }
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000730 TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len));
Eric Andersen28c70b32000-06-14 20:42:57 +0000731
Glenn L McGrath78b0e372001-06-26 02:06:08 +0000732 handlenetinput(len);
Eric Andersen28c70b32000-06-14 20:42:57 +0000733 }
734 }
735 }
736}
737
Erik Andersenf7c49ef2000-02-22 17:17:45 +0000738/*
Eric Andersen28c70b32000-06-14 20:42:57 +0000739Local Variables:
740c-file-style: "linux"
741c-basic-offset: 4
742tab-width: 4
743End:
744*/