pty library
[unix-history] / usr / src / libexec / telnetd / telnetd.c
index 0f199b5..b6a70d5 100644 (file)
@@ -2,17 +2,7 @@
  * Copyright (c) 1989 Regents of the University of California.
  * All rights reserved.
  *
  * Copyright (c) 1989 Regents of the University of California.
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  */
 
 #ifndef lint
  */
 
 #ifndef lint
@@ -22,7 +12,7 @@ char copyright[] =
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)telnetd.c  5.40 (Berkeley) %G%";
+static char sccsid[] = "@(#)telnetd.c  5.46 (Berkeley) %G%";
 #endif /* not lint */
 
 #include "telnetd.h"
 #endif /* not lint */
 
 #include "telnetd.h"
@@ -40,23 +30,58 @@ int hostinfo = 1;                   /* do we print login banner? */
 
 #ifdef CRAY
 extern int      newmap; /* nonzero if \n maps to ^M^J */
 
 #ifdef CRAY
 extern int      newmap; /* nonzero if \n maps to ^M^J */
-int    lowpty = 0, highpty = 128;      /* low, high pty numbers */
+int    lowpty = 0, highpty;    /* low, high pty numbers */
 #endif /* CRAY */
 
 int debug = 0;
 char *progname;
 
 #endif /* CRAY */
 
 int debug = 0;
 char *progname;
 
+#if    defined(NEED_GETTOS)
+struct tosent {
+       char    *t_name;        /* name */
+       char    **t_aliases;    /* alias list */
+       char    *t_proto;       /* protocol */
+       int     t_tos;          /* Type Of Service bits */
+};
+
+struct tosent *
+gettosbyname(name, proto)
+char *name, *proto;
+{
+       static struct tosent te;
+       static char *aliasp = 0;
+
+       te.t_name = name;
+       te.t_aliases = &aliasp;
+       te.t_proto = proto;
+       te.t_tos = 020; /* Low Delay bit */
+       return(&te);
+}
+#endif
+
 main(argc, argv)
        char *argv[];
 {
        struct sockaddr_in from;
        int on = 1, fromlen;
 main(argc, argv)
        char *argv[];
 {
        struct sockaddr_in from;
        int on = 1, fromlen;
+#if    defined(HAS_IP_TOS) || defined(NEED_GETTOS)
+       struct tosent *tp;
+#endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
 
        pfrontp = pbackp = ptyobuf;
        netip = netibuf;
        nfrontp = nbackp = netobuf;
 
        progname = *argv;
 
        pfrontp = pbackp = ptyobuf;
        netip = netibuf;
        nfrontp = nbackp = netobuf;
 
        progname = *argv;
+
+#ifdef CRAY
+       /*
+        * Get number of pty's before trying to process options,
+        * which may include changing pty range.
+        */
+       highpty = getnpty();
+#endif /* CRAY */
+
 top:
        argc--, argv++;
 
 top:
        argc--, argv++;
 
@@ -82,6 +107,11 @@ top:
                char *strchr();
                char *c;
 
                char *strchr();
                char *c;
 
+               /*
+                * Allow the specification of alterations to the pty search
+                * range.  It is legal to specify only one, and not change the
+                * other from its default.
+                */
                *argv += 2;
                if (**argv == '\0' && argc)
                        argv++, argc--;
                *argv += 2;
                if (**argv == '\0' && argc)
                        argv++, argc--;
@@ -89,17 +119,12 @@ top:
                if (c) {
                        *c++ = '\0';
                        highpty = atoi(c);
                if (c) {
                        *c++ = '\0';
                        highpty = atoi(c);
-               } else
-                       highpty = -1;
-               lowpty = atoi(*argv);
-               if ((lowpty > highpty) || (lowpty < 0) || (highpty > 999)) {
-       usage:
-                       fprintf(stderr, "Usage: telnetd [-debug] [-h] ");
-# ifdef        NEWINIT
-                       fprintf(stderr, "[-Iinitid] ");
-# endif        /* NEWINIT */
-                       fprintf(stderr, "[-l] [-rlowpty-highpty] [port]\n");
-                       exit(1);
+               }
+               if (**argv != '\0')
+                       lowpty = atoi(*argv);
+               if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) {
+                       usage();
+                       /* NOT REACHED */
                }
                goto top;
        }
                }
                goto top;
        }
@@ -109,11 +134,15 @@ top:
 
                *argv += 2;
                if (**argv == '\0') {
 
                *argv += 2;
                if (**argv == '\0') {
-                       if (argc < 2)
-                               goto usage;
+                       if (argc < 2) {
+                               usage();
+                               /* NOT REACHED */
+                       }
                        argv++, argc--;
                        argv++, argc--;
-                       if (**argv == '\0')
-                               goto usage;
+                       if (**argv == '\0') {
+                               usage();
+                               /* NOT REACHED */
+                       }
                }
                gen_id = *argv;
                goto top;
                }
                gen_id = *argv;
                goto top;
@@ -121,27 +150,81 @@ top:
 # endif        /* NEWINIT */
 #endif /* CRAY */
 
 # endif        /* NEWINIT */
 #endif /* CRAY */
 
+#ifdef DIAGNOSTICS
+       /*
+        * Check for desired diagnostics capabilities.
+        */
+       if (argc > 0 && !strncmp(*argv, "-D", 2)) {
+               *argv += 2;
+               if (**argv == '\0') {
+                       if (argc < 2) {
+                               usage();
+                               /* NOT REACHED */
+                       }
+                       argv++, argc--;
+                       if (**argv == '\0') {
+                               usage();
+                               /* NOT REACHED */
+                       }
+               }
+               if (!strcmp(*argv, "report")) {
+                       diagnostic |= TD_REPORT|TD_OPTIONS;
+               } else if (!strcmp(*argv, "exercise")) {
+                       diagnostic |= TD_EXERCISE;
+               } else if (!strcmp(*argv, "netdata")) {
+                       diagnostic |= TD_NETDATA;
+               } else if (!strcmp(*argv, "ptydata")) {
+                       diagnostic |= TD_PTYDATA;
+               } else if (!strcmp(*argv, "options")) {
+                       diagnostic |= TD_OPTIONS;
+               } else {
+                       usage();
+                       /* NOT REACHED */
+               }
+               goto top;
+       }
+#endif /* DIAGNOSTICS */
+
+#ifdef BFTPDAEMON
+       /*
+        * Check for bftp daemon
+        */
+       if (argc > 0 && !strncmp(*argv, "-B", 2)) {
+               bftpd++;
+               goto top;
+       }
+#endif /* BFTPDAEMON */
+
+       if (argc > 0 && **argv == '-') {
+               fprintf(stderr, "telnetd: %s: unknown option\n", *argv+1);
+               usage();
+               /* NOT REACHED */
+       }
+
        if (debug) {
            int s, ns, foo;
            struct servent *sp;
            static struct sockaddr_in sin = { AF_INET };
 
        if (debug) {
            int s, ns, foo;
            struct servent *sp;
            static struct sockaddr_in sin = { AF_INET };
 
-           if (argc > 0) {
+           if (argc > 1) {
+               usage();
+               /* NOT REACHED */
+           } else if (argc == 1) {
                    if (sp = getservbyname(*argv, "tcp")) {
                        sin.sin_port = sp->s_port;
                    } else {
                        sin.sin_port = atoi(*argv);
                        if ((int)sin.sin_port <= 0) {
                            fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
                    if (sp = getservbyname(*argv, "tcp")) {
                        sin.sin_port = sp->s_port;
                    } else {
                        sin.sin_port = atoi(*argv);
                        if ((int)sin.sin_port <= 0) {
                            fprintf(stderr, "telnetd: %s: bad port #\n", *argv);
-                           exit(1);
+                           usage();
+                           /* NOT REACHED */
                        }
                        sin.sin_port = htons((u_short)sin.sin_port);
                   }
            } else {
                sp = getservbyname("telnet", "tcp");
                if (sp == 0) {
                        }
                        sin.sin_port = htons((u_short)sin.sin_port);
                   }
            } else {
                sp = getservbyname("telnet", "tcp");
                if (sp == 0) {
-                       fprintf(stderr,
-                               "telnetd: tcp/telnet: unknown service\n");
+                   fprintf(stderr, "telnetd: tcp/telnet: unknown service\n");
                    exit(1);
                }
                sin.sin_port = sp->s_port;
                    exit(1);
                }
                sin.sin_port = sp->s_port;
@@ -170,6 +253,9 @@ top:
            (void) dup2(ns, 0);
            (void) close(ns);
            (void) close(s);
            (void) dup2(ns, 0);
            (void) close(ns);
            (void) close(s);
+       } else if (argc > 0) {
+               usage();
+               /* NOT REACHED */
        }
 
        openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
        }
 
        openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
@@ -182,12 +268,40 @@ top:
        if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
                syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
        }
        if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
                syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
        }
+
+#if    defined(HAS_IP_TOS) || defined(NEED_GETTOS)
+       if ((tp = gettosbyname("telnet", "tcp")) &&
+           (setsockopt(0, IPPROTO_IP, IP_TOS, &tp->t_tos, sizeof(int)) < 0))
+               syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+#endif /* defined(HAS_IP_TOS) || defined(NEED_GETTOS) */
        net = 0;
        doit(&from);
        /* NOTREACHED */
 }  /* end of main */
 
        net = 0;
        doit(&from);
        /* NOTREACHED */
 }  /* end of main */
 
-int    cleanup();
+usage()
+{
+       fprintf(stderr, "Usage: telnetd [-debug] [-h]");
+#ifdef NEWINIT
+       fprintf(stderr, " [-Iinitid]");
+#endif /* NEWINIT */
+#ifdef DIAGNOSTICS
+       fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]");
+#endif /* DIAGNOSTICS */
+#ifdef LINEMODE
+       fprintf(stderr, " [-l]");
+#endif
+#ifdef CRAY
+       fprintf(stderr, " [-r[lowpty]-[highpty]]");
+#endif
+#ifdef BFTPDAEMON
+       fprintf(stderr, " [-B]");
+#endif /* BFTPDAEMON */
+       fprintf(stderr, " [port]\n");
+       exit(1);
+}
+
+void   cleanup();
 
 /*
  * getterminaltype
 
 /*
  * getterminaltype
@@ -204,32 +318,60 @@ getterminaltype()
     settimer(baseline);
     send_do(TELOPT_TTYPE, 1);
     send_do(TELOPT_TSPEED, 1);
     settimer(baseline);
     send_do(TELOPT_TTYPE, 1);
     send_do(TELOPT_TSPEED, 1);
-    while ((hiswants[TELOPT_TTYPE] != hisopts[TELOPT_TTYPE]) ||
-          (hiswants[TELOPT_TSPEED] != hisopts[TELOPT_TSPEED])) {
+    send_do(TELOPT_XDISPLOC, 1);
+    send_do(TELOPT_ENVIRON, 1);
+    while (his_will_wont_is_changing(TELOPT_TTYPE) ||
+          his_will_wont_is_changing(TELOPT_TSPEED) ||
+          his_will_wont_is_changing(TELOPT_XDISPLOC) ||
+          his_will_wont_is_changing(TELOPT_ENVIRON)) {
        ttloop();
     }
        ttloop();
     }
-    if (hisopts[TELOPT_TSPEED] == OPT_YES) {
+    if (his_state_is_will(TELOPT_TSPEED)) {
        static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
 
        bcopy(sbbuf, nfrontp, sizeof sbbuf);
        nfrontp += sizeof sbbuf;
     }
        static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
 
        bcopy(sbbuf, nfrontp, sizeof sbbuf);
        nfrontp += sizeof sbbuf;
     }
-    if (hisopts[TELOPT_TTYPE] == OPT_YES) {
+    if (his_state_is_will(TELOPT_XDISPLOC)) {
+       static char sbbuf[] = { IAC, SB, TELOPT_XDISPLOC, TELQUAL_SEND, IAC, SE };
+
+       bcopy(sbbuf, nfrontp, sizeof sbbuf);
+       nfrontp += sizeof sbbuf;
+    }
+    if (his_state_is_will(TELOPT_ENVIRON)) {
+       static char sbbuf[] = { IAC, SB, TELOPT_ENVIRON, TELQUAL_SEND, IAC, SE };
+
+       bcopy(sbbuf, nfrontp, sizeof sbbuf);
+       nfrontp += sizeof sbbuf;
+    }
+    if (his_state_is_will(TELOPT_TTYPE)) {
 
        bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
        nfrontp += sizeof ttytype_sbbuf;
     }
 
        bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
        nfrontp += sizeof ttytype_sbbuf;
     }
-    if (hisopts[TELOPT_TSPEED] == OPT_YES) {
+    if (his_state_is_will(TELOPT_TSPEED)) {
        while (sequenceIs(tspeedsubopt, baseline))
            ttloop();
     }
        while (sequenceIs(tspeedsubopt, baseline))
            ttloop();
     }
-    if (hisopts[TELOPT_TTYPE] == OPT_YES) {
+    if (his_state_is_will(TELOPT_XDISPLOC)) {
+       while (sequenceIs(xdisplocsubopt, baseline))
+           ttloop();
+    }
+    if (his_state_is_will(TELOPT_ENVIRON)) {
+       while (sequenceIs(environsubopt, baseline))
+           ttloop();
+    }
+    if (his_state_is_will(TELOPT_TTYPE)) {
        char first[256], last[256];
 
        while (sequenceIs(ttypesubopt, baseline))
            ttloop();
 
        char first[256], last[256];
 
        while (sequenceIs(ttypesubopt, baseline))
            ttloop();
 
-       if (!terminaltypeok(&terminaltype[5])) {
+       /*
+        * If the other side has already disabled the option, then
+        * we have to just go with what we (might) have already gotten.
+        */
+       if (his_state_is_will(TELOPT_TTYPE) && !terminaltypeok(terminaltype)) {
            (void) strncpy(first, terminaltype, sizeof(first));
            for(;;) {
                /*
            (void) strncpy(first, terminaltype, sizeof(first));
            for(;;) {
                /*
@@ -237,9 +379,10 @@ getterminaltype()
                 */
                (void) strncpy(last, terminaltype, sizeof(last));
                _gettermname();
                 */
                (void) strncpy(last, terminaltype, sizeof(last));
                _gettermname();
-               if (terminaltypeok(&terminaltype[5]))
+               if (terminaltypeok(terminaltype))
                    break;
                    break;
-               if (strncmp(last, terminaltype, sizeof(last)) == 0) {
+               if ((strncmp(last, terminaltype, sizeof(last)) == 0) ||
+                   his_state_is_wont(TELOPT_TTYPE)) {
                    /*
                     * We've hit the end.  If this is the same as
                     * the first name, just go with it.
                    /*
                     * We've hit the end.  If this is the same as
                     * the first name, just go with it.
@@ -247,11 +390,11 @@ getterminaltype()
                    if (strncmp(first, terminaltype, sizeof(first) == 0))
                        break;
                    /*
                    if (strncmp(first, terminaltype, sizeof(first) == 0))
                        break;
                    /*
-                    * Get the terminal name one more type, so that
+                    * Get the terminal name one more time, so that
                     * RFC1091 compliant telnets will cycle back to
                     * the start of the list.
                     */
                     * RFC1091 compliant telnets will cycle back to
                     * the start of the list.
                     */
-                   _gettermname();
+                    _gettermname();
                    if (strncmp(first, terminaltype, sizeof(first) != 0))
                        (void) strncpy(terminaltype, first, sizeof(first));
                    break;
                    if (strncmp(first, terminaltype, sizeof(first) != 0))
                        (void) strncpy(terminaltype, first, sizeof(first));
                    break;
@@ -263,6 +406,13 @@ getterminaltype()
 
 _gettermname()
 {
 
 _gettermname()
 {
+    /*
+     * If the client turned off the option,
+     * we can't send another request, so we
+     * just return.
+     */
+    if (his_state_is_wont(TELOPT_TTYPE))
+       return;
     settimer(baseline);
     bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
     nfrontp += sizeof ttytype_sbbuf;
     settimer(baseline);
     bcopy(ttytype_sbbuf, nfrontp, sizeof ttytype_sbbuf);
     nfrontp += sizeof ttytype_sbbuf;
@@ -299,7 +449,14 @@ doit(who)
        char *host, *inet_ntoa();
        int t;
        struct hostent *hp;
        char *host, *inet_ntoa();
        int t;
        struct hostent *hp;
+#if BSD > 43
+       extern char *line;
 
 
+       if (openpty(&pty, &t, line, NULL, NULL) == -1)
+               fatal(net, "All network ports in use");
+       init_termbuf();
+#else
+       
        /*
         * Find an available pty to use.
         */
        /*
         * Find an available pty to use.
         */
@@ -308,6 +465,7 @@ doit(who)
                fatal(net, "All network ports in use");
 
        t = getptyslave();
                fatal(net, "All network ports in use");
 
        t = getptyslave();
+#endif
 
        /* get name of connected client */
        hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
 
        /* get name of connected client */
        hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
@@ -317,12 +475,12 @@ doit(who)
        else
                host = inet_ntoa(who->sin_addr);
 
        else
                host = inet_ntoa(who->sin_addr);
 
+       init_env();
        /*
         * get terminal type.
         */
        getterminaltype();
        /*
         * get terminal type.
         */
        getterminaltype();
-       if (terminaltype == NULL)
-               terminaltype = "TERM=network";
+       setenv("TERM", terminaltype ? terminaltype : "network", 1);
 
        /*
         * Start up the login process on the slave side of the terminal
 
        /*
         * Start up the login process on the slave side of the terminal
@@ -345,7 +503,7 @@ int f, p;
 {
        int on = 1;
        char hostname[MAXHOSTNAMELEN];
 {
        int on = 1;
        char hostname[MAXHOSTNAMELEN];
-#ifdef CRAY2
+#if    defined(CRAY2) && defined(UNICOS5)
        int termstat();
        int interrupt(), sendbrk();
 #endif
        int termstat();
        int interrupt(), sendbrk();
 #endif
@@ -368,7 +526,7 @@ int f, p;
         * Rather than doing them slowly, one at a time, do them all
         * at once.
         */
         * Rather than doing them slowly, one at a time, do them all
         * at once.
         */
-       if (!myopts[TELOPT_SGA])
+       if (my_state_is_wont(TELOPT_SGA))
                send_will(TELOPT_SGA, 1);
        /*
         * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
                send_will(TELOPT_SGA, 1);
        /*
         * Is the client side a 4.2 (NOT 4.3) system?  We need to know this
@@ -383,11 +541,11 @@ int f, p;
        send_do(TELOPT_ECHO, 1);
 
 #ifdef LINEMODE
        send_do(TELOPT_ECHO, 1);
 
 #ifdef LINEMODE
-       if (hisopts[TELOPT_LINEMODE] == OPT_NO) {
+       if (his_state_is_wont(TELOPT_LINEMODE)) {
                /* Query the peer for linemode support by trying to negotiate
                 * the linemode option.
                 */
                /* Query the peer for linemode support by trying to negotiate
                 * the linemode option.
                 */
-               linemode = 1;
+               linemode = 0;
                editmode = 0;
                send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
        }
                editmode = 0;
                send_do(TELOPT_LINEMODE, 1);  /* send do linemode */
        }
@@ -410,9 +568,25 @@ int f, p;
         * response, it will already have processed the DO ECHO.
         * Kludge upon kludge.
         */
         * response, it will already have processed the DO ECHO.
         * Kludge upon kludge.
         */
-       while (hiswants[TELOPT_NAWS] != hisopts[TELOPT_NAWS])
+       while (his_will_wont_is_changing(TELOPT_NAWS))
                ttloop();
 
                ttloop();
 
+       /*
+        * But...
+        * The client might have sent a WILL NAWS as part of its
+        * startup code; if so, we'll be here before we get the
+        * response to the DO ECHO.  We'll make the assumption
+        * that any implementation that understands about NAWS
+        * is a modern enough implementation that it will respond
+        * to our DO ECHO request; hence we'll do another spin
+        * waiting for the ECHO option to settle down, which is
+        * what we wanted to do in the first place...
+        */
+       if (his_want_state_is_will(TELOPT_ECHO) &&
+           his_state_is_will(TELOPT_NAWS)) {
+               while (his_will_wont_is_changing(TELOPT_ECHO))
+                       ttloop();
+       }
        /*
         * On the off chance that the telnet client is broken and does not
         * respond to the DO ECHO we sent, (after all, we did send the
        /*
         * On the off chance that the telnet client is broken and does not
         * respond to the DO ECHO we sent, (after all, we did send the
@@ -423,15 +597,22 @@ int f, p;
         * respond because it believes that it is already in DO ECHO
         * mode, which we do not want.
         */
         * respond because it believes that it is already in DO ECHO
         * mode, which we do not want.
         */
-       if (hiswants[TELOPT_ECHO] == OPT_YES)
+       if (his_want_state_is_will(TELOPT_ECHO)) {
+#ifdef DIAGNOSTICS
+               if (diagnostic & TD_OPTIONS) {
+                       sprintf(nfrontp, "td: simulating recv\r\n");
+                       nfrontp += strlen(nfrontp);
+               }
+#endif /* DIAGNOSTICS */
                willoption(TELOPT_ECHO);
                willoption(TELOPT_ECHO);
+       }
 
        /*
         * Finally, to clean things up, we turn on our echo.  This
         * will break stupid 4.2 telnets out of local terminal echo.
         */
 
 
        /*
         * Finally, to clean things up, we turn on our echo.  This
         * will break stupid 4.2 telnets out of local terminal echo.
         */
 
-       if (!myopts[TELOPT_ECHO])
+       if (my_state_is_wont(TELOPT_ECHO))
                send_will(TELOPT_ECHO, 1);
 
        /*
                send_will(TELOPT_ECHO, 1);
 
        /*
@@ -461,7 +642,7 @@ int f, p;
 
        (void) ioctl(f, FIONBIO, (char *)&on);
        (void) ioctl(p, FIONBIO, (char *)&on);
 
        (void) ioctl(f, FIONBIO, (char *)&on);
        (void) ioctl(p, FIONBIO, (char *)&on);
-#ifdef CRAY2
+#if    defined(CRAY2) && defined(UNICOS5)
        init_termdriver(f, p, interrupt, sendbrk);
 #endif
 
        init_termdriver(f, p, interrupt, sendbrk);
 #endif
 
@@ -482,7 +663,7 @@ int f, p;
 
        (void) signal(SIGCHLD, cleanup);
 
 
        (void) signal(SIGCHLD, cleanup);
 
-#if    defined(CRAY2)
+#if    defined(CRAY2) && defined(UNICOS5)
        /*
         * Cray-2 will send a signal when pty modes are changed by slave
         * side.  Set up signal handler now.
        /*
         * Cray-2 will send a signal when pty modes are changed by slave
         * side.  Set up signal handler now.
@@ -497,7 +678,14 @@ int f, p;
        termstat();
 #endif
 
        termstat();
 #endif
 
+#ifdef NO_SETSID
        (void) setpgrp(0, 0);
        (void) setpgrp(0, 0);
+#else
+       (void) setsid();
+#endif
+#if    defined(TIOCSCTTY) && defined(CRAY)
+       ioctl(p, TIOCSCTTY, 0);
+#endif
 
        /*
         * Show banner that getty never gave.
 
        /*
         * Show banner that getty never gave.
@@ -537,6 +725,20 @@ int f, p;
                (void) strncat(ptyibuf2, ptyip, pcc+1);
        ptyip = ptyibuf2;
        pcc = strlen(ptyip);
                (void) strncat(ptyibuf2, ptyip, pcc+1);
        ptyip = ptyibuf2;
        pcc = strlen(ptyip);
+#ifdef LINEMODE
+       /*
+        * Last check to make sure all our states are correct.
+        */
+       init_termbuf();
+       localstat();
+#endif /* LINEMODE */
+
+#ifdef DIAGNOSTICS
+       if (diagnostic & TD_REPORT) {
+               sprintf(nfrontp, "td: Entering processing loop\r\n");
+               nfrontp += strlen(nfrontp);
+       }
+#endif /* DIAGNOSTICS */
 
        for (;;) {
                fd_set ibits, obits, xbits;
 
        for (;;) {
                fd_set ibits, obits, xbits;
@@ -545,10 +747,10 @@ int f, p;
                if (ncc < 0 && pcc < 0)
                        break;
 
                if (ncc < 0 && pcc < 0)
                        break;
 
-#ifdef CRAY2
+#if    defined(CRAY2) && defined(UNICOS5)
                if (needtermstat)
                        _termstat();
                if (needtermstat)
                        _termstat();
-#endif /* CRAY2 */
+#endif /* defined(CRAY2) && defined(UNICOS5) */
                FD_ZERO(&ibits);
                FD_ZERO(&obits);
                FD_ZERO(&xbits);
                FD_ZERO(&ibits);
                FD_ZERO(&obits);
                FD_ZERO(&xbits);
@@ -656,6 +858,15 @@ int f, p;
                        }
                        netip = netibuf;
                    }
                        }
                        netip = netibuf;
                    }
+#ifdef DIAGNOSTICS
+                   if (diagnostic & (TD_REPORT | TD_NETDATA)) {
+                           sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
+                           nfrontp += strlen(nfrontp);
+                   }
+                   if (diagnostic & TD_NETDATA) {
+                           printdata("nd", netip, ncc);
+                   }
+#endif /* DIAGNOSTICS */
                }
 
                /*
                }
 
                /*
@@ -668,7 +879,7 @@ int f, p;
                        else {
                                if (pcc <= 0)
                                        break;
                        else {
                                if (pcc <= 0)
                                        break;
-#ifndef        CRAY2
+#if    !defined(CRAY2) || !defined(UNICOS5)
 #ifdef LINEMODE
                                /*
                                 * If ioctl from pty, pass it through net
 #ifdef LINEMODE
                                /*
                                 * If ioctl from pty, pass it through net
@@ -681,11 +892,21 @@ int f, p;
 #endif LINEMODE
                                if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
                                        netclear();     /* clear buffer back */
 #endif LINEMODE
                                if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
                                        netclear();     /* clear buffer back */
+#ifdef notdef
+                                       /*
+                                        * We really should have this in, but
+                                        * there are client telnets on some
+                                        * operating systems get screwed up
+                                        * royally if we send them urgent
+                                        * mode data.  So, for now, we'll not
+                                        * do this...
+                                        */
                                        *nfrontp++ = IAC;
                                        *nfrontp++ = DM;
                                        neturg = nfrontp-1; /* off by one XXX */
                                        *nfrontp++ = IAC;
                                        *nfrontp++ = DM;
                                        neturg = nfrontp-1; /* off by one XXX */
+#endif
                                }
                                }
-                               if (hisopts[TELOPT_LFLOW] &&
+                               if (his_state_is_will(TELOPT_LFLOW) &&
                                    (ptyibuf[0] &
                                     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
                                        (void) sprintf(nfrontp, "%c%c%c%c%c%c",
                                    (ptyibuf[0] &
                                     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
                                        (void) sprintf(nfrontp, "%c%c%c%c%c%c",
@@ -696,14 +917,16 @@ int f, p;
                                }
                                pcc--;
                                ptyip = ptyibuf+1;
                                }
                                pcc--;
                                ptyip = ptyibuf+1;
-#else  /* CRAY2 */
+#else  /* defined(CRAY2) && defined(UNICOS5) */
                                if (!uselinemode) {
                                if (!uselinemode) {
-                                       pcc = term_output(ptyibuf, ptyibuf2,
-                                                               pcc, BUFSIZ);
+                                       unpcc = pcc;
+                                       unptyip = ptyibuf;
+                                       pcc = term_output(&unptyip, ptyibuf2,
+                                                               &unpcc, BUFSIZ);
                                        ptyip = ptyibuf2;
                                } else
                                        ptyip = ptyibuf;
                                        ptyip = ptyibuf2;
                                } else
                                        ptyip = ptyibuf;
-#endif /* CRAY2 */
+#endif /* defined(CRAY2) && defined(UNICOS5) */
                        }
                }
 
                        }
                }
 
@@ -713,13 +936,13 @@ int f, p;
                        c = *ptyip++ & 0377, pcc--;
                        if (c == IAC)
                                *nfrontp++ = c;
                        c = *ptyip++ & 0377, pcc--;
                        if (c == IAC)
                                *nfrontp++ = c;
-#ifdef CRAY2
+#if    defined(CRAY2) && defined(UNICOS5)
                        else if (c == '\n' &&
                        else if (c == '\n' &&
-                                    myopts[TELOPT_BINARY] == OPT_NO && newmap)
+                                    my_state_is_wont(TELOPT_BINARY) && newmap)
                                *nfrontp++ = '\r';
                                *nfrontp++ = '\r';
-#endif /* CRAY2 */
+#endif /* defined(CRAY2) && defined(UNICOS5) */
                        *nfrontp++ = c;
                        *nfrontp++ = c;
-                       if ((c == '\r') && (myopts[TELOPT_BINARY] == OPT_NO)) {
+                       if ((c == '\r') && (my_state_is_wont(TELOPT_BINARY))) {
                                if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
                                        *nfrontp++ = *ptyip++ & 0377;
                                        pcc--;
                                if (pcc > 0 && ((*ptyip & 0377) == '\n')) {
                                        *nfrontp++ = *ptyip++ & 0377;
                                        pcc--;
@@ -727,6 +950,18 @@ int f, p;
                                        *nfrontp++ = '\0';
                        }
                }
                                        *nfrontp++ = '\0';
                        }
                }
+#if    defined(CRAY2) && defined(UNICOS5)
+               /*
+                * If chars were left over from the terminal driver,
+                * note their existence.
+                */
+                if (!uselinemode && unpcc) {
+                       pcc = unpcc;
+                       unpcc = 0;
+                       ptyip = unptyip;
+               }
+#endif /* defined(CRAY2) && defined(UNICOS5) */
+
                if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
                        netflush();
                if (ncc > 0)
                if (FD_ISSET(f, &obits) && (nfrontp - nbackp) > 0)
                        netflush();
                if (ncc > 0)
@@ -756,7 +991,8 @@ interrupt()
        (void) ioctl(pty, TCSIG, (char *)SIGINT);
 #else  /* TCSIG */
        init_termbuf();
        (void) ioctl(pty, TCSIG, (char *)SIGINT);
 #else  /* TCSIG */
        init_termbuf();
-       *pfrontp++ = slctab[SLC_IP].sptr ? *slctab[SLC_IP].sptr : '\177';
+       *pfrontp++ = slctab[SLC_IP].sptr ?
+                       (unsigned char)*slctab[SLC_IP].sptr : '\177';
 #endif /* TCSIG */
 }
 
 #endif /* TCSIG */
 }
 
@@ -772,7 +1008,8 @@ sendbrk()
        (void) ioctl(pty, TCSIG, (char *)SIGQUIT);
 #else  /* TCSIG */
        init_termbuf();
        (void) ioctl(pty, TCSIG, (char *)SIGQUIT);
 #else  /* TCSIG */
        init_termbuf();
-       *pfrontp++ = slctab[SLC_ABORT].sptr ? *slctab[SLC_ABORT].sptr : '\034';
+       *pfrontp++ = slctab[SLC_ABORT].sptr ?
+                       (unsigned char)*slctab[SLC_ABORT].sptr : '\034';
 #endif /* TCSIG */
 }
 
 #endif /* TCSIG */
 }
 
@@ -783,14 +1020,25 @@ sendsusp()
 # ifdef        TCSIG
        (void) ioctl(pty, TCSIG, (char *)SIGTSTP);
 # else /* TCSIG */
 # ifdef        TCSIG
        (void) ioctl(pty, TCSIG, (char *)SIGTSTP);
 # else /* TCSIG */
-       *pfrontp++ = slctab[SLC_SUSP].sptr ? *slctab[SLC_SUSP].sptr : '\032';
+       *pfrontp++ = slctab[SLC_SUSP].sptr ?
+                       (unsigned char)*slctab[SLC_SUSP].sptr : '\032';
 # endif        /* TCSIG */
 #endif /* SIGTSTP */
 }
 
 doeof()
 {
 # endif        /* TCSIG */
 #endif /* SIGTSTP */
 }
 
 doeof()
 {
+#if    defined(USE_TERMIO) && defined(SYSV_TERMIO)
+       extern char oldeofc;
+#endif
        init_termbuf();
 
        init_termbuf();
 
-       *pfrontp++ = slctab[SLC_EOF].sptr ? *slctab[SLC_EOF].sptr : '\004';
+#if    defined(USE_TERMIO) && defined(SYSV_TERMIO)
+       if (!tty_isediting()) {
+               *pfrontp++ = oldeofc;
+               return;
+       }
+#endif
+       *pfrontp++ = slctab[SLC_EOF].sptr ?
+                       (unsigned char)*slctab[SLC_EOF].sptr : '\004';
 }
 }