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