Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/networking/telnet.c
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/networking/telnet.c
r821 r1770 23 23 24 24 #include <termios.h> 25 #include <unistd.h>26 #include <errno.h>27 #include <stdlib.h>28 #include <stdarg.h>29 #include <string.h>30 #include <signal.h>31 25 #include <arpa/telnet.h> 32 #include <sys/types.h>33 #include <sys/socket.h>34 26 #include <netinet/in.h> 35 #include "busybox.h" 36 37 #if 0 38 enum { DOTRACE = 1 }; 39 #endif 27 #include "libbb.h" 40 28 41 29 #ifdef DOTRACE 42 #include <arpa/inet.h> /* for inet_ntoa()... */43 30 #define TRACE(x, y) do { if (x) printf y; } while (0) 44 31 #else … … 46 33 #endif 47 34 48 #define DATABUFSIZE 12849 #define IACBUFSIZE 12850 51 35 enum { 36 DATABUFSIZE = 128, 37 IACBUFSIZE = 128, 38 52 39 CHM_TRY = 0, 53 40 CHM_ON = 1, … … 64 51 }; 65 52 66 #define WriteCS(fd, str) write(fd, str, sizeof str -1)67 68 53 typedef unsigned char byte; 69 54 70 /* use globals to reduce size ??? */ /* test this hypothesis later */ 71 static struct Globalvars { 72 int netfd; /* console fd:s are 0 and 1 (and 2) */ 73 /* same buffer used both for network and console read/write */ 74 char buf[DATABUFSIZE]; /* allocating so static size is smaller */ 55 struct globals { 56 int netfd; /* console fd:s are 0 and 1 (and 2) */ 57 short iaclen; /* could even use byte */ 75 58 byte telstate; /* telnet negotiation state from network input */ 76 59 byte telwish; /* DO, DONT, WILL, WONT */ … … 79 62 byte gotsig; 80 63 byte do_termios; 64 #if ENABLE_FEATURE_TELNET_TTYPE 65 char *ttype; 66 #endif 67 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 68 const char *autologin; 69 #endif 70 #if ENABLE_FEATURE_AUTOWIDTH 71 int win_width, win_height; 72 #endif 73 /* same buffer used both for network and console read/write */ 74 char buf[DATABUFSIZE]; 81 75 /* buffer to handle telnet negotiations */ 82 76 char iacbuf[IACBUFSIZE]; 83 short iaclen; /* could even use byte */84 77 struct termios termios_def; 85 78 struct termios termios_raw; 86 } G; 87 88 #define xUSE_GLOBALVAR_PTR /* xUSE... -> don't use :D (makes smaller code) */ 89 90 #ifdef USE_GLOBALVAR_PTR 91 struct Globalvars * Gptr; 92 #define G (*Gptr) 93 #endif 94 95 static inline void iacflush(void) 96 { 97 write(G.netfd, G.iacbuf, G.iaclen); 98 G.iaclen = 0; 99 } 79 }; 80 #define G (*(struct globals*)&bb_common_bufsiz1) 81 void BUG_telnet_globals_too_big(void); 82 #define INIT_G() do { \ 83 if (sizeof(G) > COMMON_BUFSIZE) \ 84 BUG_telnet_globals_too_big(); \ 85 /* memset(&G, 0, sizeof G); - already is */ \ 86 } while (0) 100 87 101 88 /* Function prototypes */ … … 107 94 static int subneg(byte c); 108 95 109 /* Some globals */ 110 static int one = 1; 111 112 #ifdef CONFIG_FEATURE_TELNET_TTYPE 113 static char *ttype; 114 #endif 115 116 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN 117 static const char *autologin; 118 #endif 119 120 #ifdef CONFIG_FEATURE_AUTOWIDTH 121 static int win_width, win_height; 122 #endif 96 static void iacflush(void) 97 { 98 write(G.netfd, G.iacbuf, G.iaclen); 99 G.iaclen = 0; 100 } 101 102 #define write_str(fd, str) write(fd, str, sizeof(str) - 1) 123 103 124 104 static void doexit(int ev) … … 135 115 rawmode(); 136 116 137 WriteCS(1, "\r\nConsole escape. Commands are:\r\n\n"117 write_str(1, "\r\nConsole escape. Commands are:\r\n\n" 138 118 " l go to line mode\r\n" 139 119 " c go to character mode\r\n" … … 144 124 doexit(1); 145 125 146 switch (b) 147 { 126 switch (b) { 148 127 case 'l': 149 if (!G.gotsig) 150 { 128 if (!G.gotsig) { 151 129 do_linemode(); 152 130 goto rrturn; … … 154 132 break; 155 133 case 'c': 156 if (G.gotsig) 157 { 134 if (G.gotsig) { 158 135 will_charmode(); 159 136 goto rrturn; … … 169 146 } 170 147 171 WriteCS(1, "continuing...\r\n");148 write_str(1, "continuing...\r\n"); 172 149 173 150 if (G.gotsig) … … 178 155 179 156 } 157 180 158 static void handlenetoutput(int len) 181 159 { … … 190 168 * first - I cannot use programs like sz/rz 191 169 * second - the 0x0D is sent as one character and if the next 192 * 170 * char is 0x0A then it's eaten by a server side. 193 171 * third - whay doy you have to make 'many write()s'? 194 * 172 * I don't understand. 195 173 * So I implemented it. It's realy useful for me. I hope that 196 174 * others people will find it interesting to. … … 210 188 outbuf[j++] = *p; 211 189 if (*p == 0xff) 212 190 outbuf[j++] = 0xff; 213 191 else if (*p == 0x0d) 214 outbuf[j++] = 0x00; 215 } 216 if (j > 0 ) 217 write(G.netfd, outbuf, j); 218 } 219 192 outbuf[j++] = 0x00; 193 } 194 if (j > 0) 195 write(G.netfd, outbuf, j); 196 } 220 197 221 198 static void handlenetinput(int len) … … 293 270 } 294 271 295 296 /* ******************************* */ 297 298 static inline void putiac(int c) 272 static void putiac(int c) 299 273 { 300 274 G.iacbuf[G.iaclen++] = c; 301 275 } 302 303 276 304 277 static void putiac2(byte wwdd, byte c) … … 312 285 } 313 286 314 #if 0 315 static void putiac1(byte c) 316 { 317 if (G.iaclen + 2 > IACBUFSIZE) 318 iacflush(); 319 320 putiac(IAC); 321 putiac(c); 322 } 323 #endif 324 325 #ifdef CONFIG_FEATURE_TELNET_TTYPE 287 #if ENABLE_FEATURE_TELNET_TTYPE 326 288 static void putiac_subopt(byte c, char *str) 327 289 { … … 336 298 putiac(0); 337 299 338 while (*str)300 while (*str) 339 301 putiac(*str++); 340 302 … … 344 306 #endif 345 307 346 #if def CONFIG_FEATURE_TELNET_AUTOLOGIN308 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 347 309 static void putiac_subopt_autologin(void) 348 310 { 349 int len = strlen( autologin) + 6; // (2 + 1 + 1 + strlen + 2)350 c har *user = "USER";311 int len = strlen(G.autologin) + 6; // (2 + 1 + 1 + strlen + 2) 312 const char *user = "USER"; 351 313 352 314 if (G.iaclen + len > IACBUFSIZE) … … 359 321 putiac(NEW_ENV_VAR); 360 322 361 while (*user)323 while (*user) 362 324 putiac(*user++); 363 325 364 326 putiac(NEW_ENV_VALUE); 365 327 366 while (*autologin)367 putiac(* autologin++);328 while (*G.autologin) 329 putiac(*G.autologin++); 368 330 369 331 putiac(IAC); … … 372 334 #endif 373 335 374 #if def CONFIG_FEATURE_AUTOWIDTH336 #if ENABLE_FEATURE_AUTOWIDTH 375 337 static void putiac_naws(byte c, int x, int y) 376 338 { … … 392 354 #endif 393 355 394 /* void putiacstring (subneg strings) */ 395 396 /* ******************************* */ 397 398 static char const escapecharis[] = "\r\nEscape character is "; 356 static char const escapecharis[] ALIGN1 = "\r\nEscape character is "; 399 357 400 358 static void setConMode(void) 401 359 { 402 if (G.telflags & UF_ECHO) 403 { 360 if (G.telflags & UF_ECHO) { 404 361 if (G.charmode == CHM_TRY) { 405 362 G.charmode = CHM_ON; … … 407 364 rawmode(); 408 365 } 409 } 410 else 411 { 366 } else { 412 367 if (G.charmode != CHM_OFF) { 413 368 G.charmode = CHM_OFF; … … 418 373 } 419 374 420 /* ******************************* */421 422 375 static void will_charmode(void) 423 376 { … … 442 395 } 443 396 444 /* ******************************* */ 445 446 static inline void to_notsup(char c)447 { 448 if (G.telwish == WILL) putiac2(DONT, c);449 else if (G.telwish == DO)putiac2(WONT, c);450 } 451 452 static inlinevoid to_echo(void)397 static void to_notsup(char c) 398 { 399 if (G.telwish == WILL) 400 putiac2(DONT, c); 401 else if (G.telwish == DO) 402 putiac2(WONT, c); 403 } 404 405 static void to_echo(void) 453 406 { 454 407 /* if server requests ECHO, don't agree */ 455 if (G.telwish == DO) { putiac2(WONT, TELOPT_ECHO); return; } 456 else if (G.telwish == DONT) return; 457 458 if (G.telflags & UF_ECHO) 459 { 408 if (G.telwish == DO) { 409 putiac2(WONT, TELOPT_ECHO); 410 return; 411 } 412 if (G.telwish == DONT) 413 return; 414 415 if (G.telflags & UF_ECHO) { 460 416 if (G.telwish == WILL) 461 417 return; 462 } 463 else 464 if (G.telwish == WONT) 465 return; 418 } else if (G.telwish == WONT) 419 return; 466 420 467 421 if (G.charmode != CHM_OFF) … … 474 428 475 429 setConMode(); 476 WriteCS(1, "\r\n"); /* sudden modec */477 } 478 479 static inlinevoid to_sga(void)430 write_str(1, "\r\n"); /* sudden modec */ 431 } 432 433 static void to_sga(void) 480 434 { 481 435 /* daemon always sends will/wont, client do/dont */ 482 436 483 if (G.telflags & UF_SGA) 484 { 437 if (G.telflags & UF_SGA) { 485 438 if (G.telwish == WILL) 486 439 return; 487 } 488 else 489 if (G.telwish == WONT) 490 return; 440 } else if (G.telwish == WONT) 441 return; 491 442 492 443 if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */ … … 494 445 else 495 446 putiac2(DONT, TELOPT_SGA); 496 497 return; 498 } 499 500 #ifdef CONFIG_FEATURE_TELNET_TTYPE 501 static inline void to_ttype(void) 447 } 448 449 #if ENABLE_FEATURE_TELNET_TTYPE 450 static void to_ttype(void) 502 451 { 503 452 /* Tell server we will (or won't) do TTYPE */ 504 453 505 if (ttype)454 if (G.ttype) 506 455 putiac2(WILL, TELOPT_TTYPE); 507 456 else 508 457 putiac2(WONT, TELOPT_TTYPE); 509 510 return; 511 } 512 #endif 513 514 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN 515 static inline void to_new_environ(void) 458 } 459 #endif 460 461 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 462 static void to_new_environ(void) 516 463 { 517 464 /* Tell server we will (or will not) do AUTOLOGIN */ 518 465 519 if ( autologin)466 if (G.autologin) 520 467 putiac2(WILL, TELOPT_NEW_ENVIRON); 521 468 else 522 469 putiac2(WONT, TELOPT_NEW_ENVIRON); 523 524 return; 525 } 526 #endif 527 528 #ifdef CONFIG_FEATURE_AUTOWIDTH 529 static inline void to_naws(void) 470 } 471 #endif 472 473 #if ENABLE_FEATURE_AUTOWIDTH 474 static void to_naws(void) 530 475 { 531 476 /* Tell server we will do NAWS */ 532 477 putiac2(WILL, TELOPT_NAWS); 533 return;534 478 } 535 479 #endif … … 537 481 static void telopt(byte c) 538 482 { 539 switch (c) 540 { 541 case TELOPT_ECHO: to_echo(); break; 542 case TELOPT_SGA: to_sga(); break; 543 #ifdef CONFIG_FEATURE_TELNET_TTYPE 544 case TELOPT_TTYPE: to_ttype();break; 545 #endif 546 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN 547 case TELOPT_NEW_ENVIRON: to_new_environ(); break; 548 #endif 549 #ifdef CONFIG_FEATURE_AUTOWIDTH 550 case TELOPT_NAWS: to_naws(); 551 putiac_naws(c, win_width, win_height); 552 break; 553 #endif 554 default: to_notsup(c); 555 break; 556 } 557 } 558 559 560 /* ******************************* */ 483 switch (c) { 484 case TELOPT_ECHO: 485 to_echo(); break; 486 case TELOPT_SGA: 487 to_sga(); break; 488 #if ENABLE_FEATURE_TELNET_TTYPE 489 case TELOPT_TTYPE: 490 to_ttype(); break; 491 #endif 492 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 493 case TELOPT_NEW_ENVIRON: 494 to_new_environ(); break; 495 #endif 496 #if ENABLE_FEATURE_AUTOWIDTH 497 case TELOPT_NAWS: 498 to_naws(); 499 putiac_naws(c, G.win_width, G.win_height); 500 break; 501 #endif 502 default: 503 to_notsup(c); 504 break; 505 } 506 } 561 507 562 508 /* subnegotiation -- ignore all (except TTYPE,NAWS) */ 563 564 509 static int subneg(byte c) 565 510 { 566 switch (G.telstate) 567 { 511 switch (G.telstate) { 568 512 case TS_SUB1: 569 513 if (c == IAC) 570 514 G.telstate = TS_SUB2; 571 #if def CONFIG_FEATURE_TELNET_TTYPE515 #if ENABLE_FEATURE_TELNET_TTYPE 572 516 else 573 517 if (c == TELOPT_TTYPE) 574 putiac_subopt(TELOPT_TTYPE, ttype);575 #endif 576 #if def CONFIG_FEATURE_TELNET_AUTOLOGIN518 putiac_subopt(TELOPT_TTYPE, G.ttype); 519 #endif 520 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 577 521 else 578 522 if (c == TELOPT_NEW_ENVIRON) … … 589 533 } 590 534 591 /* ******************************* */592 593 535 static void fgotsig(int sig) 594 536 { … … 599 541 static void rawmode(void) 600 542 { 601 if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_raw); 543 if (G.do_termios) 544 tcsetattr(0, TCSADRAIN, &G.termios_raw); 602 545 } 603 546 604 547 static void cookmode(void) 605 548 { 606 if (G.do_termios) tcsetattr(0, TCSADRAIN, &G.termios_def); 607 } 608 549 if (G.do_termios) 550 tcsetattr(0, TCSADRAIN, &G.termios_def); 551 } 552 553 int telnet_main(int argc, char** argv); 609 554 int telnet_main(int argc, char** argv) 610 555 { 556 char *host; 557 int port; 611 558 int len; 612 struct sockaddr_in s_in;613 559 #ifdef USE_POLL 614 560 struct pollfd ufds[2]; … … 618 564 #endif 619 565 620 #ifdef CONFIG_FEATURE_AUTOWIDTH 621 get_terminal_width_height(0, &win_width, &win_height); 622 # endif623 624 # ifdef CONFIG_FEATURE_TELNET_TTYPE625 ttype = getenv("TERM"); 626 # endif627 628 memset(&G, 0, sizeof G); 566 INIT_G(); 567 568 #if ENABLE_FEATURE_AUTOWIDTH 569 get_terminal_width_height(0, &G.win_width, &G.win_height); 570 #endif 571 572 #if ENABLE_FEATURE_TELNET_TTYPE 573 G.ttype = getenv("TERM"); 574 #endif 629 575 630 576 if (tcgetattr(0, &G.termios_def) >= 0) { 631 577 G.do_termios = 1; 632 633 578 G.termios_raw = G.termios_def; 634 579 cfmakeraw(&G.termios_raw); … … 638 583 bb_show_usage(); 639 584 640 #ifdef CONFIG_FEATURE_TELNET_AUTOLOGIN 641 if (1 & bb_getopt_ulflags(argc, argv, "al:", &autologin)) 642 autologin = getenv("USER"); 643 644 if (optind < argc) { 645 bb_lookup_host(&s_in, argv[optind++]); 646 s_in.sin_port = bb_lookup_port((optind < argc) ? argv[optind++] : 647 "telnet", "tcp", 23); 648 if (optind < argc) 649 bb_show_usage(); 650 } else 585 #if ENABLE_FEATURE_TELNET_AUTOLOGIN 586 if (1 & getopt32(argv, "al:", &G.autologin)) 587 G.autologin = getenv("USER"); 588 argv += optind; 589 #else 590 argv++; 591 #endif 592 if (!*argv) 651 593 bb_show_usage(); 652 #else 653 bb_lookup_host(&s_in, argv[1]);654 s_in.sin_port = bb_lookup_port((argc == 3) ? argv[2] : "telnet", "tcp", 23);655 #endif 656 657 G.netfd = xconnect(&s_in);658 659 setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, & one, sizeof one);594 host = *argv++; 595 port = bb_lookup_port(*argv ? *argv++ : "telnet", "tcp", 23); 596 if (*argv) /* extra params?? */ 597 bb_show_usage(); 598 599 G.netfd = create_and_connect_stream_or_die(host, port); 600 601 setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); 660 602 661 603 signal(SIGINT, fgotsig); … … 671 613 #endif 672 614 673 while (1) 674 { 615 while (1) { 675 616 #ifndef USE_POLL 676 617 fd_set rfds = readfds; … … 699 640 { 700 641 len = read(0, G.buf, DATABUFSIZE); 701 702 642 if (len <= 0) 703 643 doexit(0); 704 705 644 TRACE(0, ("Read con: %d\n", len)); 706 707 645 handlenetoutput(len); 708 646 } … … 715 653 { 716 654 len = read(G.netfd, G.buf, DATABUFSIZE); 717 718 if (len <= 0) 719 { 720 WriteCS(1, "Connection closed by foreign host.\r\n"); 655 if (len <= 0) { 656 write_str(1, "Connection closed by foreign host\r\n"); 721 657 doexit(1); 722 658 } 723 659 TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len)); 724 725 660 handlenetinput(len); 726 661 }
Note:
See TracChangeset
for help on using the changeset viewer.