|
|
1.1 root 1: /*
2: * Copyright (c) 1989 Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution and use in source and binary forms are permitted provided
6: * that: (1) source distributions retain this entire copyright notice and
7: * comment, and (2) distributions including binaries display the following
8: * acknowledgement: ``This product includes software developed by the
9: * University of California, Berkeley and its contributors'' in the
10: * documentation or other materials provided with the distribution and in
11: * all advertising materials mentioning features or use of this software.
12: * Neither the name of the University nor the names of its contributors may
13: * be used to endorse or promote products derived from this software without
14: * specific prior written permission.
15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18: */
19:
20: #ifndef lint
21: char copyright[] =
22: "@(#) Copyright (c) 1989 Regents of the University of California.\n\
23: All rights reserved.\n";
24: #endif /* not lint */
25:
26: #ifndef lint
27: static char sccsid[] = "@(#)telnetd.c 5.46 (Berkeley) 6/28/90";
28: #endif /* not lint */
29:
30: #include "telnetd.h"
31:
32: /*
33: * I/O data buffers,
34: * pointers, and counters.
35: */
36: char ptyibuf[BUFSIZ], *ptyip = ptyibuf;
37: char ptyibuf2[BUFSIZ];
38:
39: #ifdef CRAY
40: int hostinfo = 1; /* do we print login banner? */
41: #endif
42:
43: #ifdef CRAY
44: extern int newmap; /* nonzero if \n maps to ^M^J */
45: int lowpty = 0, highpty; /* low, high pty numbers */
46: #endif /* CRAY */
47:
48: int debug = 0;
49: char *progname;
50:
51: #if defined(NEED_GETTOS)
52: struct tosent {
53: char *t_name; /* name */
54: char **t_aliases; /* alias list */
55: char *t_proto; /* protocol */
56: int t_tos; /* Type Of Service bits */
57: };
58:
59: struct tosent *
60: gettosbyname(name, proto)
61: char *name, *proto;
62: {
63: static struct tosent te;
64: static char *aliasp = 0;
65:
66: te.t_name = name;
67: te.t_aliases = &aliasp;
68: te.t_proto = proto;
69: te.t_tos = 020; /* Low Delay bit */
70: return(&te);
71: }
72: #endif
73:
74: main(argc, argv)
75: char *argv[];
76: {
77: struct sockaddr_in from;
78: int on = 1, fromlen;
79: #if defined(HAS_IP_TOS) || defined(NEED_GETTOS)
80: struct tosent *tp;
81: #endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
82:
83: pfrontp = pbackp = ptyobuf;
84: netip = netibuf;
85: nfrontp = nbackp = netobuf;
86:
87: progname = *argv;
88:
89: #ifdef CRAY
90: /*
91: * Get number of pty's before trying to process options,
92: * which may include changing pty range.
93: */
94: highpty = getnpty();
95: #endif /* CRAY */
96:
97: top:
98: argc--, argv++;
99:
100: if (argc > 0 && strcmp(*argv, "-debug") == 0) {
101: debug++;
102: goto top;
103: }
104:
105: #ifdef LINEMODE
106: if (argc > 0 && !strcmp(*argv, "-l")) {
107: alwayslinemode = 1;
108: goto top;
109: }
110: #endif /* LINEMODE */
111:
112: #ifdef CRAY
113: if (argc > 0 && !strcmp(*argv, "-h")) {
114: hostinfo = 0;
115: goto top;
116: }
117:
118: if (argc > 0 && !strncmp(*argv, "-r", 2)) {
119: char *strchr();
120: char *c;
121:
122: /*
123: * Allow the specification of alterations to the pty search
124: * range. It is legal to specify only one, and not change the
125: * other from its default.
126: */
127: *argv += 2;
128: if (**argv == '\0' && argc)
129: argv++, argc--;
130: c = strchr(*argv, '-');
131: if (c) {
132: *c++ = '\0';
133: highpty = atoi(c);
134: }
135: if (**argv != '\0')
136: lowpty = atoi(*argv);
137: if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) {
138: usage();
139: /* NOT REACHED */
140: }
141: goto top;
142: }
143: # ifdef NEWINIT
144: if (argc > 0 && !strncmp(*argv, "-I", 2)) {
145: extern char *gen_id;
146:
147: *argv += 2;
148: if (**argv == '\0') {
149: if (argc < 2) {
150: usage();
151: /* NOT REACHED */
152: }
153: argv++, argc--;
154: if (**argv == '\0') {
155: usage();
156: /* NOT REACHED */
157: }
158: }
159: gen_id = *argv;
160: goto top;
161: }
162: # endif /* NEWINIT */
163: #endif /* CRAY */
164:
165: #ifdef DIAGNOSTICS
166: /*
167: * Check for desired diagnostics capabilities.
168: */
169: if (argc > 0 && !strncmp(*argv, "-D", 2)) {
170: *argv += 2;
171: if (**argv == '\0') {
172: if (argc < 2) {
173: usage();
174: /* NOT REACHED */
175: }
176: argv++, argc--;
177: if (**argv == '\0') {
178: usage();
179: /* NOT REACHED */
180: }
181: }
182: if (!strcmp(*argv, "report")) {
183: diagnostic |= TD_REPORT|TD_OPTIONS;
184: } else if (!strcmp(*argv, "exercise")) {
185: diagnostic |= TD_EXERCISE;
186: } else if (!strcmp(*argv, "netdata")) {
187: diagnostic |= TD_NETDATA;
188: } else if (!strcmp(*argv, "ptydata")) {
189: diagnostic |= TD_PTYDATA;
190: } else if (!strcmp(*argv, "options")) {
191: diagnostic |= TD_OPTIONS;
192: } else {
193: usage();
194: /* NOT REACHED */
195: }
196: goto top;
197: }
198: #endif /* DIAGNOSTICS */
199:
200: #ifdef BFTPDAEMON
201: /*
202: * Check for bftp daemon
203: */
204: if (argc > 0 && !strncmp(*argv, "-B", 2)) {
205: bftpd++;
206: goto top;
207: }
208: #endif /* BFTPDAEMON */
209:
210: if (argc > 0 && **argv == '-') {
211: fprintf(stderr, "telnetd: %s: unknown option\n", *argv+1);
212: usage();
213: /* NOT REACHED */
214: }
215:
216: if (debug) {
217: int s, ns, foo;
218: struct servent *sp;
219: static struct sockaddr_in sin = { AF_INET };
220:
221: if (argc > 1) {
222: usage();
223: /* NOT REACHED */
224: } else if (argc == 1) {
225: if (sp = getservbyname(*argv, "tcp")) {
226: sin.sin_port = sp->s_port;
227: } else {
228: sin.sin_port = atoi(*argv);
229: if ((int)sin.sin_port <= 0) {
230: fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
231: usage();
232: /* NOT REACHED */
233: }
234: sin.sin_port = htons((u_short)sin.sin_port);
235: }
236: } else {
237: sp = getservbyname("telnet", "tcp");
238: if (sp == 0) {
239: fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
240: exit(1);
241: }
242: sin.sin_port = sp->s_port;
243: }
244:
245: s = socket(AF_INET, SOCK_STREAM, 0);
246: if (s < 0) {
247: perror("telnetd: socket");;
248: exit(1);
249: }
250: (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
251: if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
252: perror("bind");
253: exit(1);
254: }
255: if (listen(s, 1) < 0) {
256: perror("listen");
257: exit(1);
258: }
259: foo = sizeof sin;
260: ns = accept(s, (struct sockaddr *)&sin, &foo);
261: if (ns < 0) {
262: perror("accept");
263: exit(1);
264: }
265: (void) dup2(ns, 0);
266: (void) close(ns);
267: (void) close(s);
268: } else if (argc > 0) {
269: usage();
270: /* NOT REACHED */
271: }
272:
273: openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
274: fromlen = sizeof (from);
275: if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
276: fprintf(stderr, "%s: ", progname);
277: perror("getpeername");
278: _exit(1);
279: }
280: if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
281: syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
282: }
283:
284: #if defined(HAS_IP_TOS) || defined(NEED_GETTOS)
285: if ((tp = gettosbyname("telnet", "tcp")) &&
286: (setsockopt(0, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
287: syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
288: #endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
289: net = 0;
290: doit(&from);
291: /* NOTREACHED */
292: } /* end of main */
293:
294: usage()
295: {
296: fprintf(stderr, "Usage: telnetd [-debug] [-h]");
297: #ifdef NEWINIT
298: fprintf(stderr, " [-Iinitid]");
299: #endif /* NEWINIT */
300: #ifdef DIAGNOSTICS
301: fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]");
302: #endif /* DIAGNOSTICS */
303: #ifdef LINEMODE
304: fprintf(stderr, " [-l]");
305: #endif
306: #ifdef CRAY
307: fprintf(stderr, " [-r[lowpty]-[highpty]]");
308: #endif
309: #ifdef BFTPDAEMON
310: fprintf(stderr, " [-B]");
311: #endif /* BFTPDAEMON */
312: fprintf(stderr, " [port]\n");
313: exit(1);
314: }
315:
316: void cleanup();
317:
318: /*
319: * getterminaltype
320: *
321: * Ask the other end to send along its terminal type and speed.
322: * Output is the variable terminaltype filled in.
323: */
324: static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
325: void
326: getterminaltype()
327: {
328: void ttloop();
329:
330: settimer(baseline);
331: send_do(TELOPT_TTYPE, 1);
332: send_do(TELOPT_TSPEED, 1);
333: send_do(TELOPT_XDISPLOC, 1);
334: send_do(TELOPT_ENVIRON, 1);
335: while (his_will_wont_is_changing(TELOPT_TTYPE) ||
336: his_will_wont_is_changing(TELOPT_TSPEED) ||
337: his_will_wont_is_changing(TELOPT_XDISPLOC) ||
338: his_will_wont_is_changing(TELOPT_ENVIRON)) {
339: ttloop();
340: }
341: if (his_state_is_will(TELOPT_TSPEED)) {
342: static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
343:
344: bcopy(sbbuf, nfrontp, sizeof sbbuf);
345: nfrontp += sizeof sbbuf;
346: }
347: if (his_state_is_will(TELOPT_XDISPLOC)) {
348: static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
349:
350: bcopy(sbbuf, nfrontp, sizeof sbbuf);
351: nfrontp += sizeof sbbuf;
352: }
353: if (his_state_is_will(TELOPT_ENVIRON)) {
354: static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE };
355:
356: bcopy(sbbuf, nfrontp, sizeof sbbuf);
357: nfrontp += sizeof sbbuf;
358: }
359: if (his_state_is_will(TELOPT_TTYPE)) {
360:
361: bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
362: nfrontp += sizeof ttytype_sbbuf;
363: }
364: if (his_state_is_will(TELOPT_TSPEED)) {
365: while (sequenceIs(tspeedsubopt, baseline))
366: ttloop();
367: }
368: if (his_state_is_will(TELOPT_XDISPLOC)) {
369: while (sequenceIs(xdisplocsubopt, baseline))
370: ttloop();
371: }
372: if (his_state_is_will(TELOPT_ENVIRON)) {
373: while (sequenceIs(environsubopt, baseline))
374: ttloop();
375: }
376: if (his_state_is_will(TELOPT_TTYPE)) {
377: char first[256], last[256];
378:
379: while (sequenceIs(ttypesubopt, baseline))
380: ttloop();
381:
382: /*
383: * If the other side has already disabled the option, then
384: * we have to just go with what we (might) have already gotten.
385: */
386: if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
387: (void) strncpy(first, terminaltype, sizeof(first));
388: for(;;) {
389: /*
390: * Save the unknown name, and request the next name.
391: */
392: (void) strncpy(last, terminaltype, sizeof(last));
393: _gettermname();
394: if (terminaltypeok(terminaltype))
395: break;
396: if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
397: his_state_is_wont(TELOPT_TTYPE)) {
398: /*
399: * We've hit the end. If this is the same as
400: * the first name, just go with it.
401: */
402: if (strncmp(first, terminaltype, sizeof(first) == 0))
403: break;
404: /*
405: * Get the terminal name one more time, so that
406: * RFC1091 compliant telnets will cycle back to
407: * the start of the list.
408: */
409: _gettermname();
410: if (strncmp(first, terminaltype, sizeof(first) != 0))
411: (void) strncpy(terminaltype, first, sizeof(first));
412: break;
413: }
414: }
415: }
416: }
417: } /* end of getterminaltype */
418:
419: _gettermname()
420: {
421: /*
422: * If the client turned off the option,
423: * we can't send another request, so we
424: * just return.
425: */
426: if (his_state_is_wont(TELOPT_TTYPE))
427: return;
428: settimer(baseline);
429: bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
430: nfrontp += sizeof ttytype_sbbuf;
431: while (sequenceIs(ttypesubopt, baseline))
432: ttloop();
433: }
434:
435: terminaltypeok(s)
436: char *s;
437: {
438: char buf[1024];
439:
440: if (terminaltype == NULL)
441: return(1);
442:
443: /*
444: * tgetent() will return 1 if the type is known, and
445: * 0 if it is not known. If it returns -1, it couldn't
446: * open the database. But if we can't open the database,
447: * it won't help to say we failed, because we won't be
448: * able to verify anything else. So, we treat -1 like 1.
449: */
450: if (tgetent(buf, s) == 0)
451: return(0);
452: return(1);
453: }
454:
455: /*
456: * Get a pty, scan input lines.
457: */
458: doit(who)
459: struct sockaddr_in *who;
460: {
461: char *host, *inet_ntoa();
462: int t;
463: struct hostent *hp;
464: #if BSD > 43
465: extern char *line;
466:
467: if (openpty(&pty, &t, line, NULL, NULL) == -1)
468: fatal(net, "All network ports in use");
469: init_termbuf();
470: #else
471:
472: /*
473: * Find an available pty to use.
474: */
475: pty = getpty();
476: if (pty < 0)
477: fatal(net, "All network ports in use");
478:
479: t = getptyslave();
480: #endif
481:
482: /* get name of connected client */
483: hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
484: who->sin_family);
485: if (hp)
486: host = hp->h_name;
487: else
488: host = inet_ntoa(who->sin_addr);
489:
490: init_env();
491: /*
492: * get terminal type.
493: */
494: getterminaltype();
495: setenv("TERM", terminaltype ? terminaltype : "network", 1);
496:
497: /*
498: * Start up the login process on the slave side of the terminal
499: */
500: startslave(t, host);
501:
502: telnet(net, pty); /* begin server processing */
503: /*NOTREACHED*/
504: } /* end of doit */
505:
506: #ifndef MAXHOSTNAMELEN
507: #define MAXHOSTNAMELEN 64
508: #endif MAXHOSTNAMELEN
509: /*
510: * Main loop. Select from pty and network, and
511: * hand data to telnet receiver finite state machine.
512: */
513: telnet(f, p)
514: int f, p;
515: {
516: int on = 1;
517: char hostname[MAXHOSTNAMELEN];
518: #if defined(CRAY2) && defined(UNICOS5)
519: int termstat();
520: int interrupt(), sendbrk();
521: #endif
522: #define TABBUFSIZ 512
523: char defent[TABBUFSIZ];
524: char defstrs[TABBUFSIZ];
525: #undef TABBUFSIZ
526: char *HE;
527: char *HN;
528: char *IM;
529: void netflush();
530:
531: /*
532: * Initialize the slc mapping table.
533: */
534: get_slc_defaults();
535:
536: /*
537: * Do some tests where it is desireable to wait for a response.
538: * Rather than doing them slowly, one at a time, do them all
539: * at once.
540: */
541: if (my_state_is_wont(TELOPT_SGA))
542: send_will(TELOPT_SGA, 1);
543: /*
544: * Is the client side a 4.2 (NOT 4.3) system? We need to know this
545: * because 4.2 clients are unable to deal with TCP urgent data.
546: *
547: * To find out, we send out a "DO ECHO". If the remote system
548: * answers "WILL ECHO" it is probably a 4.2 client, and we note
549: * that fact ("WILL ECHO" ==> that the client will echo what
550: * WE, the server, sends it; it does NOT mean that the client will
551: * echo the terminal input).
552: */
553: send_do(TELOPT_ECHO, 1);
554:
555: #ifdef LINEMODE
556: if (his_state_is_wont(TELOPT_LINEMODE)) {
557: /* Query the peer for linemode support by trying to negotiate
558: * the linemode option.
559: */
560: linemode = 0;
561: editmode = 0;
562: send_do(TELOPT_LINEMODE, 1); /* send do linemode */
563: }
564: #endif /* LINEMODE */
565:
566: /*
567: * Send along a couple of other options that we wish to negotiate.
568: */
569: send_do(TELOPT_NAWS, 1);
570: send_will(TELOPT_STATUS, 1);
571: flowmode = 1; /* default flow control state */
572: send_do(TELOPT_LFLOW, 1);
573:
574: /*
575: * Spin, waiting for a response from the DO ECHO. However,
576: * some REALLY DUMB telnets out there might not respond
577: * to the DO ECHO. So, we spin looking for NAWS, (most dumb
578: * telnets so far seem to respond with WONT for a DO that
579: * they don't understand...) because by the time we get the
580: * response, it will already have processed the DO ECHO.
581: * Kludge upon kludge.
582: */
583: while (his_will_wont_is_changing(TELOPT_NAWS))
584: ttloop();
585:
586: /*
587: * But...
588: * The client might have sent a WILL NAWS as part of its
589: * startup code; if so, we'll be here before we get the
590: * response to the DO ECHO. We'll make the assumption
591: * that any implementation that understands about NAWS
592: * is a modern enough implementation that it will respond
593: * to our DO ECHO request; hence we'll do another spin
594: * waiting for the ECHO option to settle down, which is
595: * what we wanted to do in the first place...
596: */
597: if (his_want_state_is_will(TELOPT_ECHO) &&
598: his_state_is_will(TELOPT_NAWS)) {
599: while (his_will_wont_is_changing(TELOPT_ECHO))
600: ttloop();
601: }
602: /*
603: * On the off chance that the telnet client is broken and does not
604: * respond to the DO ECHO we sent, (after all, we did send the
605: * DO NAWS negotiation after the DO ECHO, and we won't get here
606: * until a response to the DO NAWS comes back) simulate the
607: * receipt of a will echo. This will also send a WONT ECHO
608: * to the client, since we assume that the client failed to
609: * respond because it believes that it is already in DO ECHO
610: * mode, which we do not want.
611: */
612: if (his_want_state_is_will(TELOPT_ECHO)) {
613: #ifdef DIAGNOSTICS
614: if (diagnostic & TD_OPTIONS) {
615: sprintf(nfrontp, "td: simulating recv\r\n");
616: nfrontp += strlen(nfrontp);
617: }
618: #endif /* DIAGNOSTICS */
619: willoption(TELOPT_ECHO);
620: }
621:
622: /*
623: * Finally, to clean things up, we turn on our echo. This
624: * will break stupid 4.2 telnets out of local terminal echo.
625: */
626:
627: if (my_state_is_wont(TELOPT_ECHO))
628: send_will(TELOPT_ECHO, 1);
629:
630: /*
631: * Turn on packet mode, and default to line at at time mode.
632: */
633: (void) ioctl(p, TIOCPKT, (char *)&on);
634: #ifdef LINEMODE
635: tty_setlinemode(1);
636:
637: # ifdef KLUDGELINEMODE
638: /*
639: * Continuing line mode support. If client does not support
640: * real linemode, attempt to negotiate kludge linemode by sending
641: * the do timing mark sequence.
642: */
643: if (lmodetype < REAL_LINEMODE)
644: send_do(TELOPT_TM, 1);
645: # endif /* KLUDGELINEMODE */
646: #endif /* LINEMODE */
647:
648: /*
649: * Call telrcv() once to pick up anything received during
650: * terminal type negotiation, 4.2/4.3 determination, and
651: * linemode negotiation.
652: */
653: telrcv();
654:
655: (void) ioctl(f, FIONBIO, (char *)&on);
656: (void) ioctl(p, FIONBIO, (char *)&on);
657: #if defined(CRAY2) && defined(UNICOS5)
658: init_termdriver(f, p, interrupt, sendbrk);
659: #endif
660:
661: #if defined(SO_OOBINLINE)
662: (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
663: #endif /* defined(SO_OOBINLINE) */
664:
665: #ifdef SIGTSTP
666: (void) signal(SIGTSTP, SIG_IGN);
667: #endif
668: #ifdef SIGTTOU
669: /*
670: * Ignoring SIGTTOU keeps the kernel from blocking us
671: * in ttioct() in /sys/tty.c.
672: */
673: (void) signal(SIGTTOU, SIG_IGN);
674: #endif
675:
676: (void) signal(SIGCHLD, cleanup);
677:
678: #if defined(CRAY2) && defined(UNICOS5)
679: /*
680: * Cray-2 will send a signal when pty modes are changed by slave
681: * side. Set up signal handler now.
682: */
683: if ((int)signal(SIGUSR1, termstat) < 0)
684: perror("signal");
685: else if (ioctl(p, TCSIGME, (char *)SIGUSR1) < 0)
686: perror("ioctl:TCSIGME");
687: /*
688: * Make processing loop check terminal characteristics early on.
689: */
690: termstat();
691: #endif
692:
693: #ifdef NO_SETSID
694: (void) setpgrp(0, 0);
695: #else
696: (void) setsid();
697: #endif
698: #if defined(TIOCSCTTY) && defined(CRAY)
699: ioctl(p, TIOCSCTTY, 0);
700: #endif
701:
702: /*
703: * Show banner that getty never gave.
704: *
705: * We put the banner in the pty input buffer. This way, it
706: * gets carriage return null processing, etc., just like all
707: * other pty --> client data.
708: */
709:
710: (void) gethostname(hostname, sizeof (hostname));
711:
712: if (getent(defent, "default") == 1) {
713: char *getstr();
714: char *cp=defstrs;
715:
716: HE = getstr("he", &cp);
717: HN = getstr("hn", &cp);
718: IM = getstr("im", &cp);
719: if (HN && *HN)
720: (void) strcpy(hostname, HN);
721: if (IM == 0)
722: IM = "";
723: } else {
724: #ifdef CRAY
725: if (hostinfo == 0)
726: IM = 0;
727: else
728: #endif
729: IM = DEFAULT_IM;
730: HE = 0;
731: }
732: edithost(HE, hostname);
733: if (IM && *IM)
734: putf(IM, ptyibuf2);
735:
736: if (pcc)
737: (void) strncat(ptyibuf2, ptyip, pcc+1);
738: ptyip = ptyibuf2;
739: pcc = strlen(ptyip);
740: #ifdef LINEMODE
741: /*
742: * Last check to make sure all our states are correct.
743: */
744: init_termbuf();
745: localstat();
746: #endif /* LINEMODE */
747:
748: #ifdef DIAGNOSTICS
749: if (diagnostic & TD_REPORT) {
750: sprintf(nfrontp, "td: Entering processing loop\r\n");
751: nfrontp += strlen(nfrontp);
752: }
753: #endif /* DIAGNOSTICS */
754:
755: for (;;) {
756: fd_set ibits, obits, xbits;
757: register int c;
758:
759: if (ncc < 0 && pcc < 0)
760: break;
761:
762: #if defined(CRAY2) && defined(UNICOS5)
763: if (needtermstat)
764: _termstat();
765: #endif /* defined(CRAY2) && defined(UNICOS5) */
766: FD_ZERO(&ibits);
767: FD_ZERO(&obits);
768: FD_ZERO(&xbits);
769: /*
770: * Never look for input if there's still
771: * stuff in the corresponding output buffer
772: */
773: if (nfrontp - nbackp || pcc > 0) {
774: FD_SET(f, &obits);
775: } else {
776: FD_SET(p, &ibits);
777: }
778: if (pfrontp - pbackp || ncc > 0) {
779: FD_SET(p, &obits);
780: } else {
781: FD_SET(f, &ibits);
782: }
783: if (!SYNCHing) {
784: FD_SET(f, &xbits);
785: }
786: if ((c = select(16, &ibits, &obits, &xbits,
787: (struct timeval *)0)) < 1) {
788: if (c == -1) {
789: if (errno == EINTR) {
790: continue;
791: }
792: }
793: sleep(5);
794: continue;
795: }
796:
797: /*
798: * Any urgent data?
799: */
800: if (FD_ISSET(net, &xbits)) {
801: SYNCHing = 1;
802: }
803:
804: /*
805: * Something to read from the network...
806: */
807: if (FD_ISSET(net, &ibits)) {
808: #if !defined(SO_OOBINLINE)
809: /*
810: * In 4.2 (and 4.3 beta) systems, the
811: * OOB indication and data handling in the kernel
812: * is such that if two separate TCP Urgent requests
813: * come in, one byte of TCP data will be overlaid.
814: * This is fatal for Telnet, but we try to live
815: * with it.
816: *
817: * In addition, in 4.2 (and...), a special protocol
818: * is needed to pick up the TCP Urgent data in
819: * the correct sequence.
820: *
821: * What we do is: if we think we are in urgent
822: * mode, we look to see if we are "at the mark".
823: * If we are, we do an OOB receive. If we run
824: * this twice, we will do the OOB receive twice,
825: * but the second will fail, since the second
826: * time we were "at the mark", but there wasn't
827: * any data there (the kernel doesn't reset
828: * "at the mark" until we do a normal read).
829: * Once we've read the OOB data, we go ahead
830: * and do normal reads.
831: *
832: * There is also another problem, which is that
833: * since the OOB byte we read doesn't put us
834: * out of OOB state, and since that byte is most
835: * likely the TELNET DM (data mark), we would
836: * stay in the TELNET SYNCH (SYNCHing) state.
837: * So, clocks to the rescue. If we've "just"
838: * received a DM, then we test for the
839: * presence of OOB data when the receive OOB
840: * fails (and AFTER we did the normal mode read
841: * to clear "at the mark").
842: */
843: if (SYNCHing) {
844: int atmark;
845:
846: (void) ioctl(net, SIOCATMARK, (char *)&atmark);
847: if (atmark) {
848: ncc = recv(net, netibuf, sizeof (netibuf), MSG_OOB);
849: if ((ncc == -1) && (errno == EINVAL)) {
850: ncc = read(net, netibuf, sizeof (netibuf));
851: if (sequenceIs(didnetreceive, gotDM)) {
852: SYNCHing = stilloob(net);
853: }
854: }
855: } else {
856: ncc = read(net, netibuf, sizeof (netibuf));
857: }
858: } else {
859: ncc = read(net, netibuf, sizeof (netibuf));
860: }
861: settimer(didnetreceive);
862: #else /* !defined(SO_OOBINLINE)) */
863: ncc = read(net, netibuf, sizeof (netibuf));
864: #endif /* !defined(SO_OOBINLINE)) */
865: if (ncc < 0 && errno == EWOULDBLOCK)
866: ncc = 0;
867: else {
868: if (ncc <= 0) {
869: break;
870: }
871: netip = netibuf;
872: }
873: #ifdef DIAGNOSTICS
874: if (diagnostic & (TD_REPORT | TD_NETDATA)) {
875: sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
876: nfrontp += strlen(nfrontp);
877: }
878: if (diagnostic & TD_NETDATA) {
879: printdata("nd", netip, ncc);
880: }
881: #endif /* DIAGNOSTICS */
882: }
883:
884: /*
885: * Something to read from the pty...
886: */
887: if (FD_ISSET(p, &ibits)) {
888: pcc = read(p, ptyibuf, BUFSIZ);
889: if (pcc < 0 && errno == EWOULDBLOCK)
890: pcc = 0;
891: else {
892: if (pcc <= 0)
893: break;
894: #if !defined(CRAY2) || !defined(UNICOS5)
895: #ifdef LINEMODE
896: /*
897: * If ioctl from pty, pass it through net
898: */
899: if (ptyibuf[0] & TIOCPKT_IOCTL) {
900: copy_termbuf(ptyibuf+1, pcc-1);
901: localstat();
902: pcc = 1;
903: }
904: #endif LINEMODE
905: if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
906: netclear(); /* clear buffer back */
907: #ifdef notdef
908: /*
909: * We really should have this in, but
910: * there are client telnets on some
911: * operating systems get screwed up
912: * royally if we send them urgent
913: * mode data. So, for now, we'll not
914: * do this...
915: */
916: *nfrontp++ = IAC;
917: *nfrontp++ = DM;
918: neturg = nfrontp-1; /* off by one XXX */
919: #endif
920: }
921: if (his_state_is_will(TELOPT_LFLOW) &&
922: (ptyibuf[0] &
923: (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
924: (void) sprintf(nfrontp, "%c%c%c%c%c%c",
925: IAC, SB, TELOPT_LFLOW,
926: ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0,
927: IAC, SE);
928: nfrontp += 6;
929: }
930: pcc--;
931: ptyip = ptyibuf+1;
932: #else /* defined(CRAY2) && defined(UNICOS5) */
933: if (!uselinemode) {
934: unpcc = pcc;
935: unptyip = ptyibuf;
936: pcc = term_output(&unptyip, ptyibuf2,
937: &unpcc, BUFSIZ);
938: ptyip = ptyibuf2;
939: } else
940: ptyip = ptyibuf;
941: #endif /* defined(CRAY2) && defined(UNICOS5) */
942: }
943: }
944:
945: while (pcc > 0) {
946: if ((&netobuf[BUFSIZ] - nfrontp) < 2)
947: break;
948: c = *ptyip++ & 0377, pcc--;
949: if (c == IAC)
950: *nfrontp++ = c;
951: #if defined(CRAY2) && defined(UNICOS5)
952: else if (c == '\n' &&
953: my_state_is_wont(TELOPT_BINARY) && newmap)
954: *nfrontp++ = '\r';
955: #endif /* defined(CRAY2) && defined(UNICOS5) */
956: *nfrontp++ = c;
957: if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
958: if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
959: *nfrontp++ = *ptyip++ & 0377;
960: pcc--;
961: } else
962: *nfrontp++ = '\0';
963: }
964: }
965: #if defined(CRAY2) && defined(UNICOS5)
966: /*
967: * If chars were left over from the terminal driver,
968: * note their existence.
969: */
970: if (!uselinemode && unpcc) {
971: pcc = unpcc;
972: unpcc = 0;
973: ptyip = unptyip;
974: }
975: #endif /* defined(CRAY2) && defined(UNICOS5) */
976:
977: if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
978: netflush();
979: if (ncc > 0)
980: telrcv();
981: if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
982: ptyflush();
983: }
984: cleanup();
985: } /* end of telnet */
986:
987: #ifndef TCSIG
988: # ifdef TIOCSIG
989: # define TCSIG TIOCSIG
990: # endif
991: #endif
992:
993: /*
994: * Send interrupt to process on other side of pty.
995: * If it is in raw mode, just write NULL;
996: * otherwise, write intr char.
997: */
998: interrupt()
999: {
1000: ptyflush(); /* half-hearted */
1001:
1002: #ifdef TCSIG
1003: (void) ioctl(pty, TCSIG, (char *)SIGINT);
1004: #else /* TCSIG */
1005: init_termbuf();
1006: *pfrontp++ = slctab[SLC_IP].sptr ?
1007: (unsigned char)*slctab[SLC_IP].sptr : '\177';
1008: #endif /* TCSIG */
1009: }
1010:
1011: /*
1012: * Send quit to process on other side of pty.
1013: * If it is in raw mode, just write NULL;
1014: * otherwise, write quit char.
1015: */
1016: sendbrk()
1017: {
1018: ptyflush(); /* half-hearted */
1019: #ifdef TCSIG
1020: (void) ioctl(pty, TCSIG, (char *)SIGQUIT);
1021: #else /* TCSIG */
1022: init_termbuf();
1023: *pfrontp++ = slctab[SLC_ABORT].sptr ?
1024: (unsigned char)*slctab[SLC_ABORT].sptr : '\034';
1025: #endif /* TCSIG */
1026: }
1027:
1028: sendsusp()
1029: {
1030: #ifdef SIGTSTP
1031: ptyflush(); /* half-hearted */
1032: # ifdef TCSIG
1033: (void) ioctl(pty, TCSIG, (char *)SIGTSTP);
1034: # else /* TCSIG */
1035: *pfrontp++ = slctab[SLC_SUSP].sptr ?
1036: (unsigned char)*slctab[SLC_SUSP].sptr : '\032';
1037: # endif /* TCSIG */
1038: #endif /* SIGTSTP */
1039: }
1040:
1041: doeof()
1042: {
1043: #if defined(USE_TERMIO) && defined(SYSV_TERMIO)
1044: extern char oldeofc;
1045: #endif
1046: init_termbuf();
1047:
1048: #if defined(USE_TERMIO) && defined(SYSV_TERMIO)
1049: if (!tty_isediting()) {
1050: *pfrontp++ = oldeofc;
1051: return;
1052: }
1053: #endif
1054: *pfrontp++ = slctab[SLC_EOF].sptr ?
1055: (unsigned char)*slctab[SLC_EOF].sptr : '\004';
1056: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.