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