X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=networking%2Ftelnet.c;h=e65b6918d8d9f8eb9df0a2b2142050d8f2a43bf7;hb=52933d47bd86d6d992f7290fad93d63b53f7a15f;hp=86d672c2d5fd6ec81971fcc2baa39c57df4508f3;hpb=0b31586c7113b9b26ca0aeee9247a831b55b308c;p=oweals%2Fbusybox.git diff --git a/networking/telnet.c b/networking/telnet.c index 86d672c2d..e65b6918d 100644 --- a/networking/telnet.c +++ b/networking/telnet.c @@ -8,26 +8,16 @@ * Created: Thu Apr 7 13:29:41 1994 too * Last modified: Fri Jun 9 14:34:24 2000 too * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. * * HISTORY * Revision 3.1 1994/04/17 11:31:54 too * initial revision - * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen + * Modified 2000/06/13 for inclusion into BusyBox by Erik Andersen * Modified 2001/05/07 to add ability to pass TTYPE to remote host by Jim McQuillan * + * Modified 2004/02/11 to add ability to pass the USER variable to remote host + * by Fernando Silveira * */ @@ -36,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -43,39 +34,24 @@ #include #include "busybox.h" -#ifdef CONFIG_FEATURE_AUTOWIDTH -# include -#endif - -#if 0 -static const int DOTRACE = 1; -#endif - #ifdef DOTRACE #include /* for inet_ntoa()... */ #define TRACE(x, y) do { if (x) printf y; } while (0) #else -#define TRACE(x, y) -#endif - -#if 0 -#define USE_POLL -#include -#else -#include +#define TRACE(x, y) #endif #define DATABUFSIZE 128 #define IACBUFSIZE 128 -static const int CHM_TRY = 0; -static const int CHM_ON = 1; -static const int CHM_OFF = 2; +enum { + CHM_TRY = 0, + CHM_ON = 1, + CHM_OFF = 2, -static const int UF_ECHO = 0x01; -static const int UF_SGA = 0x02; + UF_ECHO = 0x01, + UF_SGA = 0x02, -enum { TS_0 = 1, TS_IAC = 2, TS_OPT = 3, @@ -97,11 +73,12 @@ static struct Globalvars { byte charmode; byte telflags; byte gotsig; + byte do_termios; /* buffer to handle telnet negotiations */ char iacbuf[IACBUFSIZE]; short iaclen; /* could even use byte */ - struct termios termios_def; - struct termios termios_raw; + struct termios termios_def; + struct termios termios_raw; } G; #define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */ @@ -109,11 +86,9 @@ static struct Globalvars { #ifdef USE_GLOBALVAR_PTR struct Globalvars * Gptr; #define G (*Gptr) -#else -static struct Globalvars G; #endif -static inline void iacflush(void) +static void iacflush(void) { write(G.netfd, G.iacbuf, G.iaclen); G.iaclen = 0; @@ -128,12 +103,16 @@ static void telopt(byte c); static int subneg(byte c); /* Some globals */ -static int one = 1; +static const int one = 1; #ifdef CONFIG_FEATURE_TELNET_TTYPE static char *ttype; #endif +#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN +static const char *autologin; +#endif + #ifdef CONFIG_FEATURE_AUTOWIDTH static int win_width, win_height; #endif @@ -142,7 +121,7 @@ static void doexit(int ev) { cookmode(); exit(ev); -} +} static void conescape(void) { @@ -189,10 +168,10 @@ static void conescape(void) if (G.gotsig) cookmode(); - + rrturn: G.gotsig = 0; - + } static void handlenetoutput(int len) { @@ -206,15 +185,15 @@ static void handlenetoutput(int len) * I don't agree. * first - I cannot use programs like sz/rz * second - the 0x0D is sent as one character and if the next - * char is 0x0A then it's eaten by a server side. + * char is 0x0A then it's eaten by a server side. * third - whay doy you have to make 'many write()s'? - * I don't understand. + * I don't understand. * So I implemented it. It's realy useful for me. I hope that * others people will find it interesting to. */ int i, j; - byte * p = G.buf; + byte * p = (byte*)G.buf; byte outbuf[4*DATABUFSIZE]; for (i = len, j = 0; i > 0; i--, p++) @@ -226,12 +205,12 @@ static void handlenetoutput(int len) } outbuf[j++] = *p; if (*p == 0xff) - outbuf[j++] = 0xff; + outbuf[j++] = 0xff; else if (*p == 0x0d) - outbuf[j++] = 0x00; + outbuf[j++] = 0x00; } if (j > 0 ) - write(G.netfd, outbuf, j); + write(G.netfd, outbuf, j); } @@ -312,7 +291,7 @@ static void handlenetinput(int len) /* ******************************* */ -static inline void putiac(int c) +static void putiac(int c) { G.iacbuf[G.iaclen++] = c; } @@ -328,32 +307,49 @@ static void putiac2(byte wwdd, byte c) putiac(c); } -#if 0 -static void putiac1(byte c) +#ifdef CONFIG_FEATURE_TELNET_TTYPE +static void putiac_subopt(byte c, char *str) { - if (G.iaclen + 2 > IACBUFSIZE) + int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) + + if (G.iaclen + len > IACBUFSIZE) iacflush(); putiac(IAC); + putiac(SB); putiac(c); + putiac(0); + + while (*str) + putiac(*str++); + + putiac(IAC); + putiac(SE); } #endif -#ifdef CONFIG_FEATURE_TELNET_TTYPE -static void putiac_subopt(byte c, char *str) +#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN +static void putiac_subopt_autologin(void) { - int len = strlen(str) + 6; // ( 2 + 1 + 1 + strlen + 2 ) + int len = strlen(autologin) + 6; // (2 + 1 + 1 + strlen + 2) + char *user = "USER"; if (G.iaclen + len > IACBUFSIZE) iacflush(); putiac(IAC); putiac(SB); - putiac(c); - putiac(0); + putiac(TELOPT_NEW_ENVIRON); + putiac(TELQUAL_IS); + putiac(NEW_ENV_VAR); - while(*str) - putiac(*str++); + while (*user) + putiac(*user++); + + putiac(NEW_ENV_VALUE); + + while (*autologin) + putiac(*autologin++); putiac(IAC); putiac(SE); @@ -413,7 +409,7 @@ static void will_charmode(void) G.charmode = CHM_TRY; G.telflags |= (UF_ECHO | UF_SGA); setConMode(); - + putiac2(DO, TELOPT_ECHO); putiac2(DO, TELOPT_SGA); iacflush(); @@ -432,18 +428,18 @@ static void do_linemode(void) /* ******************************* */ -static inline void to_notsup(char c) +static void to_notsup(char c) { if (G.telwish == WILL) putiac2(DONT, c); else if (G.telwish == DO) putiac2(WONT, c); } -static inline void to_echo(void) +static void to_echo(void) { /* if server requests ECHO, don't agree */ if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; } else if (G.telwish == DONT) return; - + if (G.telflags & UF_ECHO) { if (G.telwish == WILL) @@ -465,7 +461,7 @@ static inline void to_echo(void) WriteCS(1, "\r\n"); /* sudden modec */ } -static inline void to_sga(void) +static void to_sga(void) { /* daemon always sends will/wont, client do/dont */ @@ -477,7 +473,7 @@ static inline void to_sga(void) else if (G.telwish == WONT) return; - + if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */ putiac2(DO, TELOPT_SGA); else @@ -487,7 +483,7 @@ static inline void to_sga(void) } #ifdef CONFIG_FEATURE_TELNET_TTYPE -static inline void to_ttype(void) +static void to_ttype(void) { /* Tell server we will (or won't) do TTYPE */ @@ -500,13 +496,27 @@ static inline void to_ttype(void) } #endif +#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN +static void to_new_environ(void) +{ + /* Tell server we will (or will not) do AUTOLOGIN */ + + if (autologin) + putiac2(WILL, TELOPT_NEW_ENVIRON); + else + putiac2(WONT, TELOPT_NEW_ENVIRON); + + return; +} +#endif + #ifdef CONFIG_FEATURE_AUTOWIDTH -static inline void to_naws(void) -{ +static void to_naws(void) +{ /* Tell server we will do NAWS */ putiac2(WILL, TELOPT_NAWS); return; -} +} #endif static void telopt(byte c) @@ -518,6 +528,9 @@ static void telopt(byte c) #ifdef CONFIG_FEATURE_TELNET_TTYPE case TELOPT_TTYPE: to_ttype();break; #endif +#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN + case TELOPT_NEW_ENVIRON: to_new_environ(); break; +#endif #ifdef CONFIG_FEATURE_AUTOWIDTH case TELOPT_NAWS: to_naws(); putiac_naws(c, win_width, win_height); @@ -544,6 +557,11 @@ static int subneg(byte c) else if (c == TELOPT_TTYPE) putiac_subopt(TELOPT_TTYPE,ttype); +#endif +#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN + else + if (c == TELOPT_NEW_ENVIRON) + putiac_subopt_autologin(); #endif break; case TS_SUB2: @@ -565,52 +583,63 @@ static void fgotsig(int sig) static void rawmode(void) { - tcsetattr(0, TCSADRAIN, &G.termios_raw); -} + if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_raw); +} static void cookmode(void) { - tcsetattr(0, TCSADRAIN, &G.termios_def); + if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_def); } -extern int telnet_main(int argc, char** argv) +int telnet_main(int argc, char** argv) { - char *host; - char *port; int len; + struct sockaddr_in s_in; #ifdef USE_POLL struct pollfd ufds[2]; -#else +#else fd_set readfds; int maxfd; -#endif +#endif #ifdef CONFIG_FEATURE_AUTOWIDTH - struct winsize winp; - if( ioctl(0, TIOCGWINSZ, &winp) == 0 ) { - win_width = winp.ws_col; - win_height = winp.ws_row; - } + get_terminal_width_height(0, &win_width, &win_height); #endif #ifdef CONFIG_FEATURE_TELNET_TTYPE - ttype = getenv("TERM"); + ttype = getenv("TERM"); #endif memset(&G, 0, sizeof G); - if (tcgetattr(0, &G.termios_def) < 0) - exit(1); - - G.termios_raw = G.termios_def; - cfmakeraw(&G.termios_raw); - - if (argc < 2) show_usage(); - port = (argc > 2)? argv[2] : "23"; - - host = argv[1]; - - G.netfd = xconnect(host, port); + if (tcgetattr(0, &G.termios_def) >= 0) { + G.do_termios = 1; + + G.termios_raw = G.termios_def; + cfmakeraw(&G.termios_raw); + } + + if (argc < 2) + bb_show_usage(); + +#ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN + if (1 & getopt32(argc, argv, "al:", &autologin)) + autologin = getenv("USER"); + + if (optind < argc) { + bb_lookup_host(&s_in, argv[optind++]); + s_in.sin_port = bb_lookup_port((optind < argc) ? argv[optind++] : + "telnet", "tcp", 23); + if (optind < argc) + bb_show_usage(); + } else + bb_show_usage(); +#else + bb_lookup_host(&s_in, argv[1]); + s_in.sin_port = bb_lookup_port((argc == 3) ? argv[2] : "telnet", "tcp", 23); +#endif + + G.netfd = xconnect_tcp_v4(&s_in); setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &one, sizeof one); @@ -619,22 +648,22 @@ extern int telnet_main(int argc, char** argv) #ifdef USE_POLL ufds[0].fd = 0; ufds[1].fd = G.netfd; ufds[0].events = ufds[1].events = POLLIN; -#else +#else FD_ZERO(&readfds); FD_SET(0, &readfds); FD_SET(G.netfd, &readfds); maxfd = G.netfd + 1; #endif - + while (1) { #ifndef USE_POLL fd_set rfds = readfds; - + switch (select(maxfd, &rfds, NULL, NULL, NULL)) #else switch (poll(ufds, 2, -1)) -#endif +#endif { case 0: /* timeout */ @@ -649,9 +678,9 @@ extern int telnet_main(int argc, char** argv) #ifdef USE_POLL if (ufds[0].revents) /* well, should check POLLIN, but ... */ -#else +#else if (FD_ISSET(0, &rfds)) -#endif +#endif { len = read(0, G.buf, DATABUFSIZE); @@ -659,15 +688,15 @@ extern int telnet_main(int argc, char** argv) doexit(0); TRACE(0, ("Read con: %d\n", len)); - + handlenetoutput(len); } #ifdef USE_POLL if (ufds[1].revents) /* well, should check POLLIN, but ... */ -#else +#else if (FD_ISSET(G.netfd, &rfds)) -#endif +#endif { len = read(G.netfd, G.buf, DATABUFSIZE); @@ -683,11 +712,3 @@ extern int telnet_main(int argc, char** argv) } } } - -/* -Local Variables: -c-file-style: "linux" -c-basic-offset: 4 -tab-width: 4 -End: -*/