|
|
1.1 ! root 1: #ifndef lint ! 2: static char sccsid[] = "@(#)telnet.c 4.24 (Berkeley) 7/20/83"; ! 3: #endif ! 4: ! 5: /* ! 6: * User telnet program. ! 7: */ ! 8: #include <sys/param.h> ! 9: #include <sys/ttyio.h> ! 10: #include <sys/nttyio.h> ! 11: ! 12: #define TELOPTS ! 13: #include "telnet.h" ! 14: ! 15: #include <stdio.h> ! 16: #include <ctype.h> ! 17: #include <errno.h> ! 18: #include <signal.h> ! 19: #include <setjmp.h> ! 20: #include <ipc.h> ! 21: #include <libc.h> ! 22: ! 23: #define strip(x) ((x)&0177) ! 24: ! 25: char ttyobuf[BUFSIZ], *tfrontp = ttyobuf, *tbackp = ttyobuf; ! 26: char netobuf[BUFSIZ], *nfrontp = netobuf, *nbackp = netobuf; ! 27: ! 28: char hisopts[256]; ! 29: char myopts[256]; ! 30: ! 31: char doopt[] = { IAC, DO, '%', 'c', 0 }; ! 32: char dont[] = { IAC, DONT, '%', 'c', 0 }; ! 33: char will[] = { IAC, WILL, '%', 'c', 0 }; ! 34: char wont[] = { IAC, WONT, '%', 'c', 0 }; ! 35: ! 36: int connected; ! 37: int net; ! 38: int showoptions = 0; ! 39: int options; ! 40: int debug = 0; ! 41: int crmod = 0; ! 42: char *prompt; ! 43: char escape = 035; ! 44: ! 45: char line[200]; ! 46: int margc; ! 47: char *margv[20]; ! 48: ! 49: jmp_buf toplevel; ! 50: ! 51: extern int errno; ! 52: ! 53: int tn(), quit(), bye(), help(); ! 54: int setescape(), status(), toggle(), setoptions(); ! 55: int setcrmod(), setdebug(); ! 56: ! 57: #define HELPINDENT (sizeof ("connect")) ! 58: ! 59: struct cmd { ! 60: char *name; /* command name */ ! 61: char *help; /* help string */ ! 62: int (*handler)(); /* routine which executes command */ ! 63: }; ! 64: ! 65: char openhelp[] = "open connection to a site"; ! 66: char closehelp[] = "close current connection"; ! 67: char quithelp[] = "exit telnet"; ! 68: char debughelp[] = "toggle debugging"; ! 69: char escapehelp[] = "set escape character"; ! 70: char statushelp[] = "print status information"; ! 71: char helphelp[] = "print help information"; ! 72: char optionshelp[] = "toggle viewing of options processing"; ! 73: char crmodhelp[] = "toggle mapping of received carriage returns"; ! 74: ! 75: struct cmd cmdtab[] = { ! 76: { "open", openhelp, tn }, ! 77: { "close", closehelp, bye }, ! 78: { "quit", quithelp, quit }, ! 79: { "escape", escapehelp, setescape }, ! 80: { "status", statushelp, status }, ! 81: { "options", optionshelp, setoptions }, ! 82: { "crmod", crmodhelp, setcrmod }, ! 83: { "debug", debughelp, setdebug }, ! 84: { "?", helphelp, help }, ! 85: 0 ! 86: }; ! 87: ! 88: int intr(), deadpeer(); ! 89: char *control(); ! 90: struct cmd *getcmd(); ! 91: ! 92: struct tchars otc; ! 93: struct ltchars oltc; ! 94: struct sgttyb ottyb; ! 95: ! 96: char *fgets(); ! 97: ! 98: main(argc, argv) ! 99: int argc; ! 100: char *argv[]; ! 101: { ! 102: ioctl(0, TIOCGETP, (char *)&ottyb); ! 103: ioctl(0, TIOCGETC, (char *)&otc); ! 104: ioctl(0, TIOCGLTC, (char *)&oltc); ! 105: setbuf(stdin, (char *)0); ! 106: setbuf(stdout, (char *)0); ! 107: prompt = argv[0]; ! 108: if (argc > 1 && !strcmp(argv[1], "-d")) ! 109: debug++, argv++, argc--; ! 110: if (argc != 1) { ! 111: if (setjmp(toplevel) != 0) ! 112: exit(0); ! 113: tn(argc, argv); ! 114: } ! 115: setjmp(toplevel); ! 116: for (;;) ! 117: command(1); ! 118: } ! 119: ! 120: char *hostname; ! 121: ! 122: tn(argc, argv) ! 123: int argc; ! 124: char *argv[]; ! 125: { ! 126: register int c; ! 127: char *serv; ! 128: char *tcptofs(); ! 129: ! 130: if (connected) { ! 131: printf("?Already connected to %s\n", hostname); ! 132: return; ! 133: } ! 134: if (argc < 2) { ! 135: strcpy(line, "Connect "); ! 136: printf("(to) "); ! 137: fgets(&line[strlen(line)], sizeof(line)-strlen(line)-1, stdin); ! 138: makeargv(); ! 139: argc = margc; ! 140: argv = margv; ! 141: } ! 142: if (argc > 3) { ! 143: printf("usage: %s host-name [port]\n", argv[0]); ! 144: return; ! 145: } ! 146: hostname = argv[1]; ! 147: if (argc == 3) ! 148: serv = tcptofs(atoi(argv[2])); ! 149: else ! 150: serv = tcptofs(23); ! 151: signal(SIGINT, intr); ! 152: signal(SIGPIPE, SIG_IGN); ! 153: signal(SIGHUP, SIG_IGN); ! 154: printf("Trying...\n"); ! 155: net = ipcopen(ipcpath(hostname, "tcp", serv), "light hup"); ! 156: if(net < 0){ ! 157: perror("telnet: connect"); ! 158: signal(SIGINT, SIG_DFL); ! 159: return; ! 160: } ! 161: connected++; ! 162: call(status, (int)"status", 0); ! 163: telnet(net); ! 164: fprintf(stderr, "Connection closed by foreign host.\n"); ! 165: exit(1); ! 166: } ! 167: ! 168: /* ! 169: * Print status about the connection. ! 170: */ ! 171: /*VARARGS*/ ! 172: status() ! 173: { ! 174: if (connected) ! 175: printf("Connected to %s.\n", hostname); ! 176: else ! 177: printf("No connection.\n"); ! 178: printf("Escape character is '%s'.\n", control(escape)); ! 179: fflush(stdout); ! 180: } ! 181: ! 182: makeargv() ! 183: { ! 184: register char *cp; ! 185: register char **argp = margv; ! 186: ! 187: margc = 0; ! 188: for (cp = line; *cp;) { ! 189: while (isspace(*cp)) ! 190: cp++; ! 191: if (*cp == '\0') ! 192: break; ! 193: *argp++ = cp; ! 194: margc += 1; ! 195: while (*cp != '\0' && !isspace(*cp)) ! 196: cp++; ! 197: if (*cp == '\0') ! 198: break; ! 199: *cp++ = '\0'; ! 200: } ! 201: *argp++ = 0; ! 202: } ! 203: ! 204: /*VARARGS*/ ! 205: bye() ! 206: { ! 207: register char *op; ! 208: ! 209: (void) mode(0); ! 210: if (connected) { ! 211: printf("Connection closed.\n"); ! 212: close(net); ! 213: connected = 0; ! 214: /* reset his options */ ! 215: for (op = hisopts; op < &hisopts[256]; op++) ! 216: *op = 0; ! 217: } ! 218: } ! 219: ! 220: /*VARARGS*/ ! 221: quit() ! 222: { ! 223: call(bye, (int)"bye", 0); ! 224: exit(0); ! 225: } ! 226: ! 227: /* ! 228: * Help command. ! 229: */ ! 230: help(argc, argv) ! 231: int argc; ! 232: char *argv[]; ! 233: { ! 234: register struct cmd *c; ! 235: ! 236: if (argc == 1) { ! 237: printf("Commands may be abbreviated. Commands are:\n\n"); ! 238: for (c = cmdtab; c->name; c++) ! 239: printf("%-*s\t%s\n", HELPINDENT, c->name, c->help); ! 240: return; ! 241: } ! 242: while (--argc > 0) { ! 243: register char *arg; ! 244: arg = *++argv; ! 245: c = getcmd(arg); ! 246: if (c == (struct cmd *)-1) ! 247: printf("?Ambiguous help command %s\n", arg); ! 248: else if (c == (struct cmd *)0) ! 249: printf("?Invalid help command %s\n", arg); ! 250: else ! 251: printf("%s\n", c->help); ! 252: } ! 253: } ! 254: ! 255: /* ! 256: * Call routine with argc, argv set from args (terminated by 0). ! 257: * VARARGS2 ! 258: */ ! 259: call(routine, args) ! 260: int (*routine)(); ! 261: int args; ! 262: { ! 263: register int *argp; ! 264: register int argc; ! 265: ! 266: for (argc = 0, argp = &args; *argp++ != 0; argc++) ! 267: ; ! 268: (*routine)(argc, &args); ! 269: } ! 270: ! 271: struct tchars notc = { -1, -1, -1, -1, -1, -1 }; ! 272: struct ltchars noltc = { -1, -1, -1, -1, -1, -1 }; ! 273: ! 274: mode(f) ! 275: register int f; ! 276: { ! 277: static int prevmode = 0; ! 278: struct tchars *tc; ! 279: struct ltchars *ltc; ! 280: struct sgttyb sb; ! 281: int onoff, old; ! 282: ! 283: if (prevmode == f) ! 284: return (f); ! 285: old = prevmode; ! 286: prevmode = f; ! 287: sb = ottyb; ! 288: switch (f) { ! 289: ! 290: case 0: ! 291: onoff = 0; ! 292: tc = &otc; ! 293: ltc = &oltc; ! 294: break; ! 295: ! 296: case 1: ! 297: case 2: ! 298: sb.sg_flags |= CBREAK; ! 299: if (f == 1) ! 300: sb.sg_flags &= ~(ECHO|CRMOD); ! 301: else ! 302: sb.sg_flags |= ECHO|CRMOD; ! 303: sb.sg_erase = sb.sg_kill = -1; ! 304: tc = ¬c; ! 305: ltc = &noltc; ! 306: onoff = 1; ! 307: break; ! 308: ! 309: default: ! 310: return; ! 311: } ! 312: ioctl(fileno(stdin), TIOCSLTC, (char *)ltc); ! 313: ioctl(fileno(stdin), TIOCSETC, (char *)tc); ! 314: ioctl(fileno(stdin), TIOCSETP, (char *)&sb); ! 315: return (old); ! 316: } ! 317: ! 318: char sibuf[BUFSIZ], *sbp; ! 319: char tibuf[BUFSIZ], *tbp; ! 320: int scc, tcc; ! 321: int hungup; ! 322: ! 323: catchhup() ! 324: { ! 325: hungup = 1; ! 326: signal(SIGHUP, SIG_IGN); ! 327: } ! 328: ! 329: /* ! 330: * Select from tty and network... ! 331: */ ! 332: telnet(s) ! 333: int s; ! 334: { ! 335: register int c; ! 336: int tin = fileno(stdin), tout = fileno(stdout); ! 337: int on = 1; ! 338: ! 339: hungup = 0; ! 340: (void) mode(2); ! 341: signal(SIGHUP, catchhup); ! 342: while(!hungup) { ! 343: fd_set ibits, obits; ! 344: int nfds; ! 345: ! 346: FD_ZERO(ibits); ! 347: FD_ZERO(obits); ! 348: if (nfrontp - nbackp) ! 349: FD_SET(s, obits); ! 350: else ! 351: FD_SET(tin, ibits); ! 352: if (tfrontp - tbackp) ! 353: FD_SET(tout, obits); ! 354: else ! 355: FD_SET(s, ibits); ! 356: if (scc < 0 && tcc < 0) ! 357: break; ! 358: nfds = select(NOFILE, &ibits, &obits, 1000); ! 359: if (nfds==0) ! 360: continue; ! 361: else if (nfds<0) ! 362: break; ! 363: ! 364: /* ! 365: * Something to read from the network... ! 366: */ ! 367: if (FD_ISSET(s, ibits)) { ! 368: scc = read(s, sibuf, sizeof (sibuf)); ! 369: if (scc <= 0) ! 370: break; ! 371: sbp = sibuf; ! 372: } ! 373: ! 374: /* ! 375: * Something to read from the tty... ! 376: */ ! 377: if (FD_ISSET(tin, ibits)) { ! 378: tcc = read(tin, tibuf, sizeof (tibuf)); ! 379: if (tcc < 0) ! 380: break; ! 381: tbp = tibuf; ! 382: } ! 383: ! 384: while (tcc > 0) { ! 385: register int c; ! 386: ! 387: if ((&netobuf[BUFSIZ] - nfrontp) < 2) ! 388: break; ! 389: c = *tbp++ & 0377, tcc--; ! 390: if (strip(c) == escape) { ! 391: command(0); ! 392: tcc = 0; ! 393: break; ! 394: } ! 395: if (c == IAC) ! 396: *nfrontp++ = c; ! 397: *nfrontp++ = c; ! 398: } ! 399: if (FD_ISSET(s, obits) && (nfrontp - nbackp) > 0) ! 400: netflush(s); ! 401: if (scc > 0) ! 402: telrcv(); ! 403: if (FD_ISSET(tout, obits) && (tfrontp - tbackp) > 0) ! 404: ttyflush(tout); ! 405: } ! 406: signal(SIGHUP, SIG_IGN); ! 407: (void) mode(0); ! 408: } ! 409: ! 410: command(top) ! 411: int top; ! 412: { ! 413: register struct cmd *c; ! 414: int oldmode, wasopen; ! 415: ! 416: oldmode = mode(0); ! 417: if (!top) ! 418: putchar('\n'); ! 419: else ! 420: signal(SIGINT, SIG_DFL); ! 421: for (;;) { ! 422: printf("%s> ", prompt); ! 423: if (fgets(line, sizeof(line), stdin) == 0) { ! 424: if (feof(stdin)) { ! 425: clearerr(stdin); ! 426: putchar('\n'); ! 427: } ! 428: break; ! 429: } ! 430: if (line[0] == 0) ! 431: break; ! 432: makeargv(); ! 433: c = getcmd(margv[0]); ! 434: if (c == (struct cmd *)-1) { ! 435: printf("?Ambiguous command\n"); ! 436: continue; ! 437: } ! 438: if (c == 0) { ! 439: printf("?Invalid command\n"); ! 440: continue; ! 441: } ! 442: (*c->handler)(margc, margv); ! 443: if (c->handler != help) ! 444: break; ! 445: } ! 446: if (!top) { ! 447: if (!connected) ! 448: longjmp(toplevel, 1); ! 449: (void) mode(oldmode); ! 450: } ! 451: } ! 452: ! 453: /* ! 454: * Telnet receiver states for fsm ! 455: */ ! 456: #define TS_DATA 0 ! 457: #define TS_IAC 1 ! 458: #define TS_WILL 2 ! 459: #define TS_WONT 3 ! 460: #define TS_DO 4 ! 461: #define TS_DONT 5 ! 462: ! 463: telrcv() ! 464: { ! 465: register int c; ! 466: static int state = TS_DATA; ! 467: ! 468: while (scc > 0) { ! 469: c = *sbp++ & 0377, scc--; ! 470: switch (state) { ! 471: ! 472: case TS_DATA: ! 473: if (c == IAC) { ! 474: state = TS_IAC; ! 475: continue; ! 476: } ! 477: *tfrontp++ = c; ! 478: /* ! 479: * This hack is needed since we can't set ! 480: * CRMOD on output only. Machines like MULTICS ! 481: * like to send \r without \n; since we must ! 482: * turn off CRMOD to get proper input, the mapping ! 483: * is done here (sigh). ! 484: */ ! 485: if (c == '\r' && crmod) ! 486: *tfrontp++ = '\n'; ! 487: continue; ! 488: ! 489: case TS_IAC: ! 490: switch (c) { ! 491: ! 492: case WILL: ! 493: state = TS_WILL; ! 494: continue; ! 495: ! 496: case WONT: ! 497: state = TS_WONT; ! 498: continue; ! 499: ! 500: case DO: ! 501: state = TS_DO; ! 502: continue; ! 503: ! 504: case DONT: ! 505: state = TS_DONT; ! 506: continue; ! 507: ! 508: case DM: ! 509: ioctl(fileno(stdout), TIOCFLUSH, 0); ! 510: break; ! 511: ! 512: case NOP: ! 513: case GA: ! 514: break; ! 515: ! 516: default: ! 517: break; ! 518: } ! 519: state = TS_DATA; ! 520: continue; ! 521: ! 522: case TS_WILL: ! 523: printoption("RCVD", will, c, !hisopts[c]); ! 524: if (!hisopts[c]) ! 525: willoption(c); ! 526: state = TS_DATA; ! 527: continue; ! 528: ! 529: case TS_WONT: ! 530: printoption("RCVD", wont, c, hisopts[c]); ! 531: if (hisopts[c]) ! 532: wontoption(c); ! 533: state = TS_DATA; ! 534: continue; ! 535: ! 536: case TS_DO: ! 537: printoption("RCVD", doopt, c, !myopts[c]); ! 538: if (!myopts[c]) ! 539: dooption(c); ! 540: state = TS_DATA; ! 541: continue; ! 542: ! 543: case TS_DONT: ! 544: printoption("RCVD", dont, c, myopts[c]); ! 545: if (myopts[c]) { ! 546: myopts[c] = 0; ! 547: sprintf(nfrontp, wont, c); ! 548: nfrontp += sizeof (wont) - 2; ! 549: printoption("SENT", wont, c, 0); ! 550: } ! 551: state = TS_DATA; ! 552: continue; ! 553: } ! 554: } ! 555: } ! 556: ! 557: willoption(option) ! 558: int option; ! 559: { ! 560: char *fmt; ! 561: ! 562: switch (option) { ! 563: ! 564: case TELOPT_ECHO: ! 565: (void) mode(1); ! 566: ! 567: case TELOPT_SGA: ! 568: hisopts[option] = 1; ! 569: fmt = doopt; ! 570: break; ! 571: ! 572: case TELOPT_TM: ! 573: fmt = dont; ! 574: break; ! 575: ! 576: default: ! 577: fmt = dont; ! 578: break; ! 579: } ! 580: sprintf(nfrontp, fmt, option); ! 581: nfrontp += sizeof (dont) - 2; ! 582: printoption("SENT", fmt, option, 0); ! 583: } ! 584: ! 585: wontoption(option) ! 586: int option; ! 587: { ! 588: char *fmt; ! 589: ! 590: switch (option) { ! 591: ! 592: case TELOPT_ECHO: ! 593: (void) mode(2); ! 594: ! 595: case TELOPT_SGA: ! 596: hisopts[option] = 0; ! 597: fmt = dont; ! 598: break; ! 599: ! 600: default: ! 601: fmt = dont; ! 602: } ! 603: sprintf(nfrontp, fmt, option); ! 604: nfrontp += sizeof (doopt) - 2; ! 605: printoption("SENT", fmt, option, 0); ! 606: } ! 607: ! 608: dooption(option) ! 609: int option; ! 610: { ! 611: char *fmt; ! 612: ! 613: switch (option) { ! 614: ! 615: case TELOPT_TM: ! 616: fmt = wont; ! 617: break; ! 618: ! 619: case TELOPT_ECHO: ! 620: (void) mode(2); ! 621: fmt = will; ! 622: hisopts[option] = 0; ! 623: break; ! 624: ! 625: case TELOPT_SGA: ! 626: fmt = will; ! 627: break; ! 628: ! 629: default: ! 630: fmt = wont; ! 631: break; ! 632: } ! 633: sprintf(nfrontp, fmt, option); ! 634: nfrontp += sizeof (doopt) - 2; ! 635: printoption("SENT", fmt, option, 0); ! 636: } ! 637: ! 638: /* ! 639: * Set the escape character. ! 640: */ ! 641: setescape(argc, argv) ! 642: int argc; ! 643: char *argv[]; ! 644: { ! 645: register char *arg; ! 646: char buf[50]; ! 647: ! 648: if (argc > 2) ! 649: arg = argv[1]; ! 650: else { ! 651: printf("new escape character: "); ! 652: fgets(buf, sizeof(buf), stdin); ! 653: arg = buf; ! 654: } ! 655: if (arg[0] != '\0') ! 656: escape = arg[0]; ! 657: printf("Escape character is '%s'.\n", control(escape)); ! 658: fflush(stdout); ! 659: } ! 660: ! 661: /*VARARGS*/ ! 662: setoptions() ! 663: { ! 664: ! 665: showoptions = !showoptions; ! 666: printf("%s show option processing.\n", showoptions ? "Will" : "Wont"); ! 667: fflush(stdout); ! 668: } ! 669: ! 670: /*VARARGS*/ ! 671: setcrmod() ! 672: { ! 673: ! 674: crmod = !crmod; ! 675: printf("%s map carriage return on output.\n", crmod ? "Will" : "Wont"); ! 676: fflush(stdout); ! 677: } ! 678: ! 679: /*VARARGS*/ ! 680: setdebug() ! 681: { ! 682: ! 683: debug = !debug; ! 684: printf("%s turn on socket level debugging.\n", ! 685: debug ? "Will" : "Wont"); ! 686: fflush(stdout); ! 687: } ! 688: ! 689: /* ! 690: * Construct a control character sequence ! 691: * for a special character. ! 692: */ ! 693: char * ! 694: control(c) ! 695: register int c; ! 696: { ! 697: static char buf[3]; ! 698: ! 699: if (c == 0177) ! 700: return ("^?"); ! 701: if (c >= 040) { ! 702: buf[0] = c; ! 703: buf[1] = 0; ! 704: } else { ! 705: buf[0] = '^'; ! 706: buf[1] = '@'+c; ! 707: buf[2] = 0; ! 708: } ! 709: return (buf); ! 710: } ! 711: ! 712: struct cmd * ! 713: getcmd(name) ! 714: register char *name; ! 715: { ! 716: register char *p, *q; ! 717: register struct cmd *c, *found; ! 718: register int nmatches, longest; ! 719: ! 720: longest = 0; ! 721: nmatches = 0; ! 722: found = 0; ! 723: for (c = cmdtab; p = c->name; c++) { ! 724: for (q = name; *q == *p++; q++) ! 725: if (*q == 0) /* exact match? */ ! 726: return (c); ! 727: if (!*q) { /* the name was a prefix */ ! 728: if (q - name > longest) { ! 729: longest = q - name; ! 730: nmatches = 1; ! 731: found = c; ! 732: } else if (q - name == longest) ! 733: nmatches++; ! 734: } ! 735: } ! 736: if (nmatches > 1) ! 737: return ((struct cmd *)-1); ! 738: return (found); ! 739: } ! 740: ! 741: intr() ! 742: { ! 743: (void) mode(0); ! 744: longjmp(toplevel, -1); ! 745: } ! 746: ! 747: ttyflush(fd) ! 748: { ! 749: int n; ! 750: ! 751: if ((n = tfrontp - tbackp) > 0) ! 752: n = write(fd, tbackp, n); ! 753: if (n < 0) ! 754: return; ! 755: tbackp += n; ! 756: if (tbackp == tfrontp) ! 757: tbackp = tfrontp = ttyobuf; ! 758: } ! 759: ! 760: netflush(fd) ! 761: { ! 762: int n; ! 763: ! 764: if ((n = nfrontp - nbackp) > 0) ! 765: n = write(fd, nbackp, n); ! 766: if (n > 0) ! 767: nbackp += n; ! 768: if (nbackp == nfrontp) ! 769: nbackp = nfrontp = netobuf; ! 770: } ! 771: ! 772: /*VARARGS*/ ! 773: printoption(direction, fmt, option, what) ! 774: char *direction, *fmt; ! 775: int option, what; ! 776: { ! 777: if (!showoptions) ! 778: return; ! 779: printf("%s ", direction); ! 780: if (fmt == doopt) ! 781: fmt = "do"; ! 782: else if (fmt == dont) ! 783: fmt = "dont"; ! 784: else if (fmt == will) ! 785: fmt = "will"; ! 786: else if (fmt == wont) ! 787: fmt = "wont"; ! 788: else ! 789: fmt = "???"; ! 790: if (option < TELOPT_SUPDUP) ! 791: printf("%s %s", fmt, telopts[option]); ! 792: else ! 793: printf("%s %d", fmt, option); ! 794: if (*direction == '<') { ! 795: printf("\r\n"); ! 796: return; ! 797: } ! 798: printf(" (%s)\r\n", what ? "reply" : "don't reply"); ! 799: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.