BSD 4_4 release
[unix-history] / usr / src / libexec / telnetd / telnetd.c
index 940a6bc..1649a7c 100644 (file)
 /*
 /*
- * Copyright (c) 1989 Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
  *
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1989 Regents of the University of California.\n\
- All rights reserved.\n";
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
      The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
 #endif /* not lint */
 
 #ifndef lint
-static char sccsid[] = "@(#)telnetd.c  5.47 (Berkeley) %G%";
+static char sccsid[] = "@(#)telnetd.c  8.1 (Berkeley) 6/4/93";
 #endif /* not lint */
 
 #include "telnetd.h"
 #include "pathnames.h"
 
 #endif /* not lint */
 
 #include "telnetd.h"
 #include "pathnames.h"
 
+#if    defined(_SC_CRAY_SECURE_SYS) && !defined(SCM_SECURITY)
+/*
+ * UNICOS 6.0/6.1 do not have SCM_SECURITY defined, so we can
+ * use it to tell us to turn off all the socket security code,
+ * since that is only used in UNICOS 7.0 and later.
+ */
+# undef _SC_CRAY_SECURE_SYS
+#endif
+
+#if    defined(_SC_CRAY_SECURE_SYS)
+#include <sys/sysv.h>
+#include <sys/secdev.h>
+# ifdef SO_SEC_MULTI           /* 8.0 code */
+#include <sys/secparm.h>
+#include <sys/usrv.h>
+# endif /* SO_SEC_MULTI */
+int    secflag;
+char   tty_dev[16];
+struct secdev dv;
+struct sysv sysv;
+# ifdef SO_SEC_MULTI           /* 8.0 code */
+struct socksec ss;
+# else /* SO_SEC_MULTI */      /* 7.0 code */
+struct socket_security ss;
+# endif /* SO_SEC_MULTI */
+#endif /* _SC_CRAY_SECURE_SYS */
+
+#if    defined(AUTHENTICATION)
+#include <libtelnet/auth.h>
+int    auth_level = 0;
+#endif
+#if    defined(SecurID)
+int    require_SecurID = 0;
+#endif
+
+extern int utmp_len;
+int    registerd_host_only = 0;
+
+#ifdef STREAMSPTY
+# include <stropts.h>
+# include <termio.h>
+/* make sure we don't get the bsd version */
+# include "/usr/include/sys/tty.h"
+# include <sys/ptyvar.h>
+
+/*
+ * Because of the way ptyibuf is used with streams messages, we need
+ * ptyibuf+1 to be on a full-word boundary.  The following wierdness
+ * is simply to make that happen.
+ */
+char   ptyibufbuf[BUFSIZ+4];
+char   *ptyibuf = ptyibufbuf+3;
+char   *ptyip = ptyibufbuf+3;
+char   ptyibuf2[BUFSIZ];
+unsigned char ctlbuf[BUFSIZ];
+struct strbuf strbufc, strbufd;
+
+int readstream();
+
+#else  /* ! STREAMPTY */
+
 /*
  * I/O data buffers,
  * pointers, and counters.
 /*
  * I/O data buffers,
  * pointers, and counters.
@@ -25,6 +112,8 @@ static char sccsid[] = "@(#)telnetd.c        5.47 (Berkeley) %G%";
 char   ptyibuf[BUFSIZ], *ptyip = ptyibuf;
 char   ptyibuf2[BUFSIZ];
 
 char   ptyibuf[BUFSIZ], *ptyip = ptyibuf;
 char   ptyibuf2[BUFSIZ];
 
+#endif /* ! STREAMPTY */
+
 int    hostinfo = 1;                   /* do we print login banner? */
 
 #ifdef CRAY
 int    hostinfo = 1;                   /* do we print login banner? */
 
 #ifdef CRAY
@@ -33,43 +122,63 @@ int        lowpty = 0, highpty;    /* low, high pty numbers */
 #endif /* CRAY */
 
 int debug = 0;
 #endif /* CRAY */
 
 int debug = 0;
+int keepalive = 1;
 char *progname;
 
 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 */
-};
+extern void usage P((void));
 
 
-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);
-}
+/*
+ * The string to pass to getopt().  We do it this way so
+ * that only the actual options that we support will be
+ * passed off to getopt().
+ */
+char valid_opts[] = {
+       'd', ':', 'h', 'k', 'n', 'S', ':', 'u', ':', 'U',
+#ifdef AUTHENTICATION
+       'a', ':', 'X', ':',
+#endif
+#ifdef BFTPDAEMON
+       'B',
+#endif
+#ifdef DIAGNOSTICS
+       'D', ':',
+#endif
+#ifdef ENCRYPTION
+       'e', ':',
+#endif
+#if    defined(CRAY) && defined(NEWINIT)
+       'I', ':',
+#endif
+#ifdef LINEMODE
+       'l',
+#endif
+#ifdef CRAY
+       'r', ':',
 #endif
 #endif
+#ifdef SecurID
+       's',
+#endif
+       '\0'
+};
 
 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) */
+       register int ch;
+       extern char *optarg;
+       extern int optind;
+#if    defined(IPPROTO_IP) && defined(IP_TOS)
+       int tos = -1;
+#endif
 
        pfrontp = pbackp = ptyobuf;
        netip = netibuf;
        nfrontp = nbackp = netobuf;
 
        pfrontp = pbackp = ptyobuf;
        netip = netibuf;
        nfrontp = nbackp = netobuf;
+#ifdef ENCRYPTION
+       nclearto = 0;
+#endif /* ENCRYPTION */
 
        progname = *argv;
 
 
        progname = *argv;
 
@@ -81,128 +190,191 @@ main(argc, argv)
        highpty = getnpty();
 #endif /* CRAY */
 
        highpty = getnpty();
 #endif /* CRAY */
 
-top:
-       argc--, argv++;
-#ifdef convex
-       if (argc == 1 && !debug)
-               argc--;                 /* ignore the host/port name */
-#endif
-
-       if (argc > 0 && strcmp(*argv, "-debug") == 0) {
-               debug++;
-               goto top;
-       }
-
-#ifdef LINEMODE
-       if (argc > 0 && !strcmp(*argv, "-l")) {
-               alwayslinemode = 1;
-               goto top;
-       }
-#endif /* LINEMODE */
+       while ((ch = getopt(argc, argv, valid_opts)) != EOF) {
+               switch(ch) {
 
 
-       if (argc > 0 && !strcmp(*argv, "-h")) {
-               hostinfo = 0;
-               goto top;
-       }
+#ifdef AUTHENTICATION
+               case 'a':
+                       /*
+                        * Check for required authentication level
+                        */
+                       if (strcmp(optarg, "debug") == 0) {
+                               extern int auth_debug_mode;
+                               auth_debug_mode = 1;
+                       } else if (strcasecmp(optarg, "none") == 0) {
+                               auth_level = 0;
+                       } else if (strcasecmp(optarg, "other") == 0) {
+                               auth_level = AUTH_OTHER;
+                       } else if (strcasecmp(optarg, "user") == 0) {
+                               auth_level = AUTH_USER;
+                       } else if (strcasecmp(optarg, "valid") == 0) {
+                               auth_level = AUTH_VALID;
+                       } else if (strcasecmp(optarg, "off") == 0) {
+                               /*
+                                * This hack turns off authentication
+                                */
+                               auth_level = -1;
+                       } else {
+                               fprintf(stderr,
+                           "telnetd: unknown authorization level for -a\n");
+                       }
+                       break;
+#endif /* AUTHENTICATION */
 
 
-#ifdef CRAY
-       if (argc > 0 && !strncmp(*argv, "-r", 2)) {
-               char *strchr();
-               char *c;
+#ifdef BFTPDAEMON
+               case 'B':
+                       bftpd++;
+                       break;
+#endif /* BFTPDAEMON */
 
 
-               /*
-                * 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--;
-               c = strchr(*argv, '-');
-               if (c) {
-                       *c++ = '\0';
-                       highpty = atoi(c);
-               }
-               if (**argv != '\0')
-                       lowpty = atoi(*argv);
-               if ((lowpty > highpty) || (lowpty < 0) || (highpty > 32767)) {
+               case 'd':
+                       if (strcmp(optarg, "ebug") == 0) {
+                               debug++;
+                               break;
+                       }
                        usage();
                        usage();
-                       /* NOT REACHED */
-               }
-               goto top;
-       }
-# ifdef        NEWINIT
-       if (argc > 0 && !strncmp(*argv, "-I", 2)) {
-               extern char *gen_id;
+                       /* NOTREACHED */
+                       break;
 
 
-               *argv += 2;
-               if (**argv == '\0') {
-                       if (argc < 2) {
+#ifdef DIAGNOSTICS
+               case 'D':
+                       /*
+                        * Check for desired diagnostics capabilities.
+                        */
+                       if (!strcmp(optarg, "report")) {
+                               diagnostic |= TD_REPORT|TD_OPTIONS;
+                       } else if (!strcmp(optarg, "exercise")) {
+                               diagnostic |= TD_EXERCISE;
+                       } else if (!strcmp(optarg, "netdata")) {
+                               diagnostic |= TD_NETDATA;
+                       } else if (!strcmp(optarg, "ptydata")) {
+                               diagnostic |= TD_PTYDATA;
+                       } else if (!strcmp(optarg, "options")) {
+                               diagnostic |= TD_OPTIONS;
+                       } else {
                                usage();
                                /* NOT REACHED */
                        }
                                usage();
                                /* NOT REACHED */
                        }
-                       argv++, argc--;
-                       if (**argv == '\0') {
-                               usage();
-                               /* NOT REACHED */
+                       break;
+#endif /* DIAGNOSTICS */
+
+#ifdef ENCRYPTION
+               case 'e':
+                       if (strcmp(optarg, "debug") == 0) {
+                               extern int encrypt_debug_mode;
+                               encrypt_debug_mode = 1;
+                               break;
                        }
                        }
-               }
-               gen_id = *argv;
-               goto top;
-       }
-# endif        /* NEWINIT */
-#endif /* CRAY */
+                       usage();
+                       /* NOTREACHED */
+                       break;
+#endif /* ENCRYPTION */
 
 
-#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 */
+               case 'h':
+                       hostinfo = 0;
+                       break;
+
+#if    defined(CRAY) && defined(NEWINIT)
+               case 'I':
+                   {
+                       extern char *gen_id;
+                       gen_id = optarg;
+                       break;
+                   }
+#endif /* defined(CRAY) && defined(NEWINIT) */
+
+#ifdef LINEMODE
+               case 'l':
+                       alwayslinemode = 1;
+                       break;
+#endif /* LINEMODE */
+
+               case 'k':
+#if    defined(LINEMODE) && defined(KLUDGELINEMODE)
+                       lmodetype = NO_AUTOKLUDGE;
+#else
+                       /* ignore -k option if built without kludge linemode */
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
+                       break;
+
+               case 'n':
+                       keepalive = 0;
+                       break;
+
+#ifdef CRAY
+               case 'r':
+                   {
+                       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.
+                        */
+                       c = strchr(optarg, '-');
+                       if (c) {
+                               *c++ = '\0';
+                               highpty = atoi(c);
                        }
                        }
-                       argv++, argc--;
-                       if (**argv == '\0') {
+                       if (*optarg != '\0')
+                               lowpty = atoi(optarg);
+                       if ((lowpty > highpty) || (lowpty < 0) ||
+                                                       (highpty > 32767)) {
                                usage();
                                /* NOT REACHED */
                        }
                                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 {
+                       break;
+                   }
+#endif /* CRAY */
+
+#ifdef SecurID
+               case 's':
+                       /* SecurID required */
+                       require_SecurID = 1;
+                       break;
+#endif /* SecurID */
+               case 'S':
+#ifdef HAS_GETTOS
+                       if ((tos = parsetos(optarg, "tcp")) < 0)
+                               fprintf(stderr, "%s%s%s\n",
+                                       "telnetd: Bad TOS argument '", optarg,
+                                       "'; will try to use default TOS");
+#else
+                       fprintf(stderr, "%s%s\n", "TOS option unavailable; ",
+                                               "-S flag not supported\n");
+#endif
+                       break;
+
+               case 'u':
+                       utmp_len = atoi(optarg);
+                       break;
+
+               case 'U':
+                       registerd_host_only = 1;
+                       break;
+
+#ifdef AUTHENTICATION
+               case 'X':
+                       /*
+                        * Check for invalid authentication types
+                        */
+                       auth_disable_name(optarg);
+                       break;
+#endif /* AUTHENTICATION */
+
+               default:
+                       fprintf(stderr, "telnetd: %c: unknown option\n", ch);
+                       /* FALLTHROUGH */
+               case '?':
                        usage();
                        usage();
-                       /* NOT REACHED */
+                       /* NOTREACHED */
                }
                }
-               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 */
-       }
+       argc -= optind;
+       argv += optind;
 
        if (debug) {
            int s, ns, foo;
 
        if (debug) {
            int s, ns, foo;
@@ -238,7 +410,8 @@ top:
                    perror("telnetd: socket");;
                    exit(1);
            }
                    perror("telnetd: socket");;
                    exit(1);
            }
-           (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+           (void) setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
+                               (char *)&on, sizeof(on));
            if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
                perror("bind");
                exit(1);
            if (bind(s, (struct sockaddr *)&sin, sizeof sin) < 0) {
                perror("bind");
                exit(1);
@@ -256,11 +429,72 @@ top:
            (void) dup2(ns, 0);
            (void) close(ns);
            (void) close(s);
            (void) dup2(ns, 0);
            (void) close(ns);
            (void) close(s);
+#ifdef convex
+       } else if (argc == 1) {
+               ; /* VOID*/             /* Just ignore the host/port name */
+#endif
        } else if (argc > 0) {
                usage();
                /* NOT REACHED */
        }
 
        } else if (argc > 0) {
                usage();
                /* NOT REACHED */
        }
 
+#if    defined(_SC_CRAY_SECURE_SYS)
+       secflag = sysconf(_SC_CRAY_SECURE_SYS);
+
+       /*
+        *      Get socket's security label
+        */
+       if (secflag)  {
+               int szss = sizeof(ss);
+#ifdef SO_SEC_MULTI                    /* 8.0 code */
+               int sock_multi;
+               int szi = sizeof(int);
+#endif /* SO_SEC_MULTI */
+
+               bzero((char *)&dv, sizeof(dv));
+
+               if (getsysv(&sysv, sizeof(struct sysv)) != 0) {
+                       perror("getsysv");
+                       exit(1);
+               }
+
+               /*
+                *      Get socket security label and set device values
+                *         {security label to be set on ttyp device}
+                */
+#ifdef SO_SEC_MULTI                    /* 8.0 code */
+               if ((getsockopt(0, SOL_SOCKET, SO_SECURITY,
+                              (char *)&ss, &szss) < 0) ||
+                   (getsockopt(0, SOL_SOCKET, SO_SEC_MULTI,
+                               (char *)&sock_multi, &szi) < 0)) {
+                       perror("getsockopt");
+                       exit(1);
+               } else {
+                       dv.dv_actlvl = ss.ss_actlabel.lt_level;
+                       dv.dv_actcmp = ss.ss_actlabel.lt_compart;
+                       if (!sock_multi) {
+                               dv.dv_minlvl = dv.dv_maxlvl = dv.dv_actlvl;
+                               dv.dv_valcmp = dv.dv_actcmp;
+                       } else {
+                               dv.dv_minlvl = ss.ss_minlabel.lt_level;
+                               dv.dv_maxlvl = ss.ss_maxlabel.lt_level;
+                               dv.dv_valcmp = ss.ss_maxlabel.lt_compart;
+                       }
+                       dv.dv_devflg = 0;
+               }
+#else /* SO_SEC_MULTI */               /* 7.0 code */
+               if (getsockopt(0, SOL_SOCKET, SO_SECURITY,
+                               (char *)&ss, &szss) >= 0) {
+                       dv.dv_actlvl = ss.ss_slevel;
+                       dv.dv_actcmp = ss.ss_compart;
+                       dv.dv_minlvl = ss.ss_minlvl;
+                       dv.dv_maxlvl = ss.ss_maxlvl;
+                       dv.dv_valcmp = ss.ss_maxcmp;
+               }
+#endif /* SO_SEC_MULTI */
+       }
+#endif /* _SC_CRAY_SECURE_SYS */
+
        openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
        fromlen = sizeof (from);
        if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
        openlog("telnetd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
        fromlen = sizeof (from);
        if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
@@ -268,44 +502,79 @@ top:
                perror("getpeername");
                _exit(1);
        }
                perror("getpeername");
                _exit(1);
        }
-       if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof (on)) < 0) {
+       if (keepalive &&
+           setsockopt(0, SOL_SOCKET, SO_KEEPALIVE,
+                       (char *)&on, sizeof (on)) < 0) {
                syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
        }
 
                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) */
+#if    defined(IPPROTO_IP) && defined(IP_TOS)
+       {
+# if   defined(HAS_GETTOS)
+               struct tosent *tp;
+               if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
+                       tos = tp->t_tos;
+# endif
+               if (tos < 0)
+                       tos = 020;      /* Low Delay bit */
+               if (tos
+                  && (setsockopt(0, IPPROTO_IP, IP_TOS,
+                                 (char *)&tos, sizeof(tos)) < 0)
+                  && (errno != ENOPROTOOPT) )
+                       syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
+       }
+#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
        net = 0;
        doit(&from);
        /* NOTREACHED */
 }  /* end of main */
 
        net = 0;
        doit(&from);
        /* NOTREACHED */
 }  /* end of main */
 
+       void
 usage()
 {
 usage()
 {
-       fprintf(stderr, "Usage: telnetd [-debug] [-h]");
-#ifdef NEWINIT
-       fprintf(stderr, " [-Iinitid]");
-#endif /* NEWINIT */
+       fprintf(stderr, "Usage: telnetd");
+#ifdef AUTHENTICATION
+       fprintf(stderr, " [-a (debug|other|user|valid|off|none)]\n\t");
+#endif
+#ifdef BFTPDAEMON
+       fprintf(stderr, " [-B]");
+#endif
+       fprintf(stderr, " [-debug]");
 #ifdef DIAGNOSTICS
 #ifdef DIAGNOSTICS
-       fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]");
-#endif /* DIAGNOSTICS */
+       fprintf(stderr, " [-D (options|report|exercise|netdata|ptydata)]\n\t");
+#endif
+#ifdef AUTHENTICATION
+       fprintf(stderr, " [-edebug]");
+#endif
+       fprintf(stderr, " [-h]");
+#if    defined(CRAY) && defined(NEWINIT)
+       fprintf(stderr, " [-Iinitid]");
+#endif
+#if    defined(LINEMODE) && defined(KLUDGELINEMODE)
+       fprintf(stderr, " [-k]");
+#endif
 #ifdef LINEMODE
        fprintf(stderr, " [-l]");
 #endif
 #ifdef LINEMODE
        fprintf(stderr, " [-l]");
 #endif
+       fprintf(stderr, " [-n]");
 #ifdef CRAY
        fprintf(stderr, " [-r[lowpty]-[highpty]]");
 #endif
 #ifdef CRAY
        fprintf(stderr, " [-r[lowpty]-[highpty]]");
 #endif
-#ifdef BFTPDAEMON
-       fprintf(stderr, " [-B]");
-#endif /* BFTPDAEMON */
+       fprintf(stderr, "\n\t");
+#ifdef SecurID
+       fprintf(stderr, " [-s]");
+#endif
+#ifdef HAS_GETTOS
+       fprintf(stderr, " [-S tos]");
+#endif
+#ifdef AUTHENTICATION
+       fprintf(stderr, " [-X auth-type]");
+#endif
+       fprintf(stderr, " [-u utmp_hostname_length] [-U]");
        fprintf(stderr, " [port]\n");
        exit(1);
 }
 
        fprintf(stderr, " [port]\n");
        exit(1);
 }
 
-void   cleanup();
-
 /*
  * getterminaltype
  *
 /*
  * getterminaltype
  *
@@ -313,22 +582,53 @@ void      cleanup();
  * Output is the variable terminaltype filled in.
  */
 static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
  * Output is the variable terminaltype filled in.
  */
 static char ttytype_sbbuf[] = { IAC, SB, TELOPT_TTYPE, TELQUAL_SEND, IAC, SE };
-void
-getterminaltype()
+
+    int
+getterminaltype(name)
+    char *name;
 {
 {
-    void ttloop();
+    int retval = -1;
+    void _gettermname();
 
     settimer(baseline);
 
     settimer(baseline);
+#if    defined(AUTHENTICATION)
+    /*
+     * Handle the Authentication option before we do anything else.
+     */
+    send_do(TELOPT_AUTHENTICATION, 1);
+    while (his_will_wont_is_changing(TELOPT_AUTHENTICATION))
+       ttloop();
+    if (his_state_is_will(TELOPT_AUTHENTICATION)) {
+       retval = auth_wait(name);
+    }
+#endif
+
+#ifdef ENCRYPTION
+    send_will(TELOPT_ENCRYPT, 1);
+#endif /* ENCRYPTION */
     send_do(TELOPT_TTYPE, 1);
     send_do(TELOPT_TSPEED, 1);
     send_do(TELOPT_XDISPLOC, 1);
     send_do(TELOPT_ENVIRON, 1);
     send_do(TELOPT_TTYPE, 1);
     send_do(TELOPT_TSPEED, 1);
     send_do(TELOPT_XDISPLOC, 1);
     send_do(TELOPT_ENVIRON, 1);
-    while (his_will_wont_is_changing(TELOPT_TTYPE) ||
+    while (
+#ifdef ENCRYPTION
+          his_do_dont_is_changing(TELOPT_ENCRYPT) ||
+#endif /* ENCRYPTION */
+          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();
     }
           his_will_wont_is_changing(TELOPT_TSPEED) ||
           his_will_wont_is_changing(TELOPT_XDISPLOC) ||
           his_will_wont_is_changing(TELOPT_ENVIRON)) {
        ttloop();
     }
+#ifdef ENCRYPTION
+    /*
+     * Wait for the negotiation of what type of encryption we can
+     * send with.  If autoencrypt is not set, this will just return.
+     */
+    if (his_state_is_will(TELOPT_ENCRYPT)) {
+       encrypt_wait();
+    }
+#endif /* ENCRYPTION */
     if (his_state_is_will(TELOPT_TSPEED)) {
        static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
 
     if (his_state_is_will(TELOPT_TSPEED)) {
        static char sbbuf[] = { IAC, SB, TELOPT_TSPEED, TELQUAL_SEND, IAC, SE };
 
@@ -405,8 +705,10 @@ getterminaltype()
            }
        }
     }
            }
        }
     }
+    return(retval);
 }  /* end of getterminaltype */
 
 }  /* end of getterminaltype */
 
+    void
 _gettermname()
 {
     /*
 _gettermname()
 {
     /*
@@ -423,8 +725,9 @@ _gettermname()
        ttloop();
 }
 
        ttloop();
 }
 
+    int
 terminaltypeok(s)
 terminaltypeok(s)
-char *s;
+    char *s;
 {
     char buf[1024];
 
 {
     char buf[1024];
 
@@ -443,6 +746,20 @@ char *s;
     return(1);
 }
 
     return(1);
 }
 
+#ifndef        MAXHOSTNAMELEN
+#define        MAXHOSTNAMELEN 64
+#endif /* MAXHOSTNAMELEN */
+
+char *hostname;
+char host_name[MAXHOSTNAMELEN];
+char remote_host_name[MAXHOSTNAMELEN];
+
+#ifndef        convex
+extern void telnet P((int, int));
+#else
+extern void telnet P((int, int, char *));
+#endif
+
 /*
  * Get a pty, scan input lines.
  */
 /*
  * Get a pty, scan input lines.
  */
@@ -452,12 +769,15 @@ doit(who)
        char *host, *inet_ntoa();
        int t;
        struct hostent *hp;
        char *host, *inet_ntoa();
        int t;
        struct hostent *hp;
+       int level;
+       int ptynum;
+       char user_name[256];
 
        /*
         * Find an available pty to use.
         */
 #ifndef        convex
 
        /*
         * Find an available pty to use.
         */
 #ifndef        convex
-       pty = getpty();
+       pty = getpty(&ptynum);
        if (pty < 0)
                fatal(net, "All network ports in use");
 #else
        if (pty < 0)
                fatal(net, "All network ports in use");
 #else
@@ -476,26 +796,72 @@ doit(who)
        }
 #endif
 
        }
 #endif
 
+#if    defined(_SC_CRAY_SECURE_SYS)
+       /*
+        *      set ttyp line security label 
+        */
+       if (secflag) {
+               char slave_dev[16];
+
+               sprintf(tty_dev, "/dev/pty/%03d", ptynum);
+               if (setdevs(tty_dev, &dv) < 0)
+                       fatal(net, "cannot set pty security");
+               sprintf(slave_dev, "/dev/ttyp%03d", ptynum);
+               if (setdevs(slave_dev, &dv) < 0)
+                       fatal(net, "cannot set tty security");
+       }
+#endif /* _SC_CRAY_SECURE_SYS */
+
        /* get name of connected client */
        hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
                who->sin_family);
        /* get name of connected client */
        hp = gethostbyaddr((char *)&who->sin_addr, sizeof (struct in_addr),
                who->sin_family);
-       if (hp)
+
+       if (hp == NULL && registerd_host_only) {
+               fatal(net, "Couldn't resolve your address into a host name.\r\n\
+         Please contact your net administrator");
+       } else if (hp &&
+           (strlen(hp->h_name) <= ((utmp_len < 0) ? -utmp_len : utmp_len))) {
                host = hp->h_name;
                host = hp->h_name;
-       else
+       } else {
                host = inet_ntoa(who->sin_addr);
                host = inet_ntoa(who->sin_addr);
+       }
+       /*
+        * We must make a copy because Kerberos is probably going
+        * to also do a gethost* and overwrite the static data...
+        */
+       strncpy(remote_host_name, host, sizeof(remote_host_name)-1);
+       remote_host_name[sizeof(remote_host_name)-1] = 0;
+       host = remote_host_name;
+
+       (void) gethostname(host_name, sizeof (host_name));
+       hostname = host_name;
+
+#if    defined(AUTHENTICATION) || defined(ENCRYPTION)
+       auth_encrypt_init(hostname, host, "TELNETD", 1);
+#endif
 
        init_env();
        /*
         * get terminal type.
         */
 
        init_env();
        /*
         * get terminal type.
         */
-       getterminaltype();
+       *user_name = 0;
+       level = getterminaltype(user_name);
        setenv("TERM", terminaltype ? terminaltype : "network", 1);
 
        /*
         * Start up the login process on the slave side of the terminal
         */
 #ifndef        convex
        setenv("TERM", terminaltype ? terminaltype : "network", 1);
 
        /*
         * Start up the login process on the slave side of the terminal
         */
 #ifndef        convex
-       startslave(host);
+       startslave(host, level, user_name);
+
+#if    defined(_SC_CRAY_SECURE_SYS)
+       if (secflag) {
+               if (setulvl(dv.dv_actlvl) < 0)
+                       fatal(net,"cannot setulvl()");
+               if (setucmp(dv.dv_actcmp) < 0)
+                       fatal(net, "cannot setucmp()");
+       }
+#endif /* _SC_CRAY_SECURE_SYS */
 
        telnet(net, pty);  /* begin server processing */
 #else
 
        telnet(net, pty);  /* begin server processing */
 #else
@@ -504,29 +870,37 @@ doit(who)
        /*NOTREACHED*/
 }  /* end of doit */
 
        /*NOTREACHED*/
 }  /* end of doit */
 
-#ifndef        MAXHOSTNAMELEN
-#define        MAXHOSTNAMELEN 64
-#endif MAXHOSTNAMELEN
+#if    defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50)
+       int
+Xterm_output(ibufp, obuf, icountp, ocount)
+       char **ibufp, *obuf;
+       int *icountp, ocount;
+{
+       int ret;
+       ret = term_output(*ibufp, obuf, *icountp, ocount);
+       *ibufp += *icountp;
+       *icountp = 0;
+       return(ret);
+}
+#define        term_output     Xterm_output
+#endif /* defined(CRAY2) && defined(UNICOS5) && defined(UNICOS50) */
+
 /*
  * Main loop.  Select from pty and network, and
  * hand data to telnet receiver finite state machine.
  */
 /*
  * Main loop.  Select from pty and network, and
  * hand data to telnet receiver finite state machine.
  */
+       void
 #ifndef        convex
 telnet(f, p)
 #else
 telnet(f, p, host)
 #endif
 #ifndef        convex
 telnet(f, p)
 #else
 telnet(f, p, host)
 #endif
-int f, p;
+       int f, p;
 #ifdef convex
 #ifdef convex
-char *host;
+       char *host;
 #endif
 {
        int on = 1;
 #endif
 {
        int on = 1;
-       char hostname[MAXHOSTNAMELEN];
-#if    defined(CRAY2) && defined(UNICOS5)
-       int termstat();
-       int interrupt(), sendbrk();
-#endif
 #define        TABBUFSIZ       512
        char    defent[TABBUFSIZ];
        char    defstrs[TABBUFSIZ];
 #define        TABBUFSIZ       512
        char    defent[TABBUFSIZ];
        char    defstrs[TABBUFSIZ];
@@ -535,7 +909,7 @@ char *host;
        char *HN;
        char *IM;
        void netflush();
        char *HN;
        char *IM;
        void netflush();
-       
+
        /*
         * Initialize the slc mapping table.
         */
        /*
         * Initialize the slc mapping table.
         */
@@ -576,7 +950,8 @@ char *host;
         */
        send_do(TELOPT_NAWS, 1);
        send_will(TELOPT_STATUS, 1);
         */
        send_do(TELOPT_NAWS, 1);
        send_will(TELOPT_STATUS, 1);
-       flowmode = 1;  /* default flow control state */
+       flowmode = 1;           /* default flow control state */
+       restartany = -1;        /* uninitialized... */
        send_do(TELOPT_LFLOW, 1);
 
        /*
        send_do(TELOPT_LFLOW, 1);
 
        /*
@@ -618,12 +993,9 @@ char *host;
         * mode, which we do not want.
         */
        if (his_want_state_is_will(TELOPT_ECHO)) {
         * mode, which we do not want.
         */
        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 */
+               DIAG(TD_OPTIONS,
+                       {sprintf(nfrontp, "td: simulating recv\r\n");
+                        nfrontp += strlen(nfrontp);});
                willoption(TELOPT_ECHO);
        }
 
                willoption(TELOPT_ECHO);
        }
 
@@ -635,11 +1007,14 @@ char *host;
        if (my_state_is_wont(TELOPT_ECHO))
                send_will(TELOPT_ECHO, 1);
 
        if (my_state_is_wont(TELOPT_ECHO))
                send_will(TELOPT_ECHO, 1);
 
+#ifndef        STREAMSPTY
        /*
         * Turn on packet mode
         */
        (void) ioctl(p, TIOCPKT, (char *)&on);
        /*
         * Turn on packet mode
         */
        (void) ioctl(p, TIOCPKT, (char *)&on);
-#ifdef KLUDGELINEMODE
+#endif
+
+#if    defined(LINEMODE) && defined(KLUDGELINEMODE)
        /*
         * Continuing line mode support.  If client does not support
         * real linemode, attempt to negotiate kludge linemode by sending
        /*
         * Continuing line mode support.  If client does not support
         * real linemode, attempt to negotiate kludge linemode by sending
@@ -647,7 +1022,7 @@ char *host;
         */
        if (lmodetype < REAL_LINEMODE)
                send_do(TELOPT_TM, 1);
         */
        if (lmodetype < REAL_LINEMODE)
                send_do(TELOPT_TM, 1);
-#endif /* KLUDGELINEMODE */
+#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
 
        /*
         * Call telrcv() once to pick up anything received during
 
        /*
         * Call telrcv() once to pick up anything received during
@@ -663,7 +1038,8 @@ char *host;
 #endif
 
 #if    defined(SO_OOBINLINE)
 #endif
 
 #if    defined(SO_OOBINLINE)
-       (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE, &on, sizeof on);
+       (void) setsockopt(net, SOL_SOCKET, SO_OOBINLINE,
+                               (char *)&on, sizeof on);
 #endif /* defined(SO_OOBINLINE) */
 
 #ifdef SIGTSTP
 #endif /* defined(SO_OOBINLINE) */
 
 #ifdef SIGTSTP
@@ -705,7 +1081,7 @@ char *host;
        }
 #endif
 
        }
 #endif
 
-#if    defined(TIOCSCTTY) && defined(CRAY)
+#if    defined(CRAY) && defined(NEWINIT) && defined(TIOCSCTTY)
        (void) setsid();
        ioctl(p, TIOCSCTTY, 0);
 #endif
        (void) setsid();
        ioctl(p, TIOCSCTTY, 0);
 #endif
@@ -722,7 +1098,6 @@ char *host;
        if (getenv("USER"))
                hostinfo = 0;
 #endif
        if (getenv("USER"))
                hostinfo = 0;
 #endif
-       (void) gethostname(hostname, sizeof (hostname));
 
        if (getent(defent, "default") == 1) {
                char *getstr();
 
        if (getent(defent, "default") == 1) {
                char *getstr();
@@ -732,14 +1107,14 @@ char *host;
                HN = getstr("hn", &cp);
                IM = getstr("im", &cp);
                if (HN && *HN)
                HN = getstr("hn", &cp);
                IM = getstr("im", &cp);
                if (HN && *HN)
-                       (void) strcpy(hostname, HN);
+                       (void) strcpy(host_name, HN);
                if (IM == 0)
                        IM = "";
        } else {
                IM = DEFAULT_IM;
                HE = 0;
        }
                if (IM == 0)
                        IM = "";
        } else {
                IM = DEFAULT_IM;
                HE = 0;
        }
-       edithost(HE, hostname);
+       edithost(HE, host_name);
        if (hostinfo && *IM)
                putf(IM, ptyibuf2);
 
        if (hostinfo && *IM)
                putf(IM, ptyibuf2);
 
@@ -755,12 +1130,9 @@ char *host;
        localstat();
 #endif /* LINEMODE */
 
        localstat();
 #endif /* LINEMODE */
 
-#ifdef DIAGNOSTICS
-       if (diagnostic & TD_REPORT) {
-               sprintf(nfrontp, "td: Entering processing loop\r\n");
-               nfrontp += strlen(nfrontp);
-       }
-#endif /* DIAGNOSTICS */
+       DIAG(TD_REPORT,
+               {sprintf(nfrontp, "td: Entering processing loop\r\n");
+                nfrontp += strlen(nfrontp);});
 
 #ifdef convex
        startslave(host);
 
 #ifdef convex
        startslave(host);
@@ -884,25 +1256,33 @@ char *host;
                        }
                        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 */
+                   DIAG((TD_REPORT | TD_NETDATA),
+                           {sprintf(nfrontp, "td: netread %d chars\r\n", ncc);
+                            nfrontp += strlen(nfrontp);});
+                   DIAG(TD_NETDATA, printdata("nd", netip, ncc));
                }
 
                /*
                 * Something to read from the pty...
                 */
                if (FD_ISSET(p, &ibits)) {
                }
 
                /*
                 * Something to read from the pty...
                 */
                if (FD_ISSET(p, &ibits)) {
+#ifndef        STREAMSPTY
                        pcc = read(p, ptyibuf, BUFSIZ);
                        pcc = read(p, ptyibuf, BUFSIZ);
-                       if (pcc < 0 && errno == EWOULDBLOCK)
+#else
+                       pcc = readstream(p, ptyibuf, BUFSIZ);
+#endif
+                       /*
+                        * On some systems, if we try to read something
+                        * off the master side before the slave side is
+                        * opened, we get EIO.
+                        */
+                       if (pcc < 0 && (errno == EWOULDBLOCK ||
+#ifdef EAGAIN
+                                       errno == EAGAIN ||
+#endif
+                                       errno == EIO)) {
                                pcc = 0;
                                pcc = 0;
-                       else {
+                       else {
                                if (pcc <= 0)
                                        break;
 #if    !defined(CRAY2) || !defined(UNICOS5)
                                if (pcc <= 0)
                                        break;
 #if    !defined(CRAY2) || !defined(UNICOS5)
@@ -915,7 +1295,7 @@ char *host;
                                        localstat();
                                        pcc = 1;
                                }
                                        localstat();
                                        pcc = 1;
                                }
-#endif LINEMODE
+#endif /* LINEMODE */
                                if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
                                        netclear();     /* clear buffer back */
 #ifndef        NO_URGENT
                                if (ptyibuf[0] & TIOCPKT_FLUSHWRITE) {
                                        netclear();     /* clear buffer back */
 #ifndef        NO_URGENT
@@ -933,11 +1313,18 @@ char *host;
                                if (his_state_is_will(TELOPT_LFLOW) &&
                                    (ptyibuf[0] &
                                     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
                                if (his_state_is_will(TELOPT_LFLOW) &&
                                    (ptyibuf[0] &
                                     (TIOCPKT_NOSTOP|TIOCPKT_DOSTOP))) {
-                                       (void) sprintf(nfrontp, "%c%c%c%c%c%c",
-                                           IAC, SB, TELOPT_LFLOW,
-                                           ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0,
-                                           IAC, SE);
-                                       nfrontp += 6;
+                                       int newflow =
+                                           ptyibuf[0] & TIOCPKT_DOSTOP ? 1 : 0;
+                                       if (newflow != flowmode) {
+                                               flowmode = newflow;
+                                               (void) sprintf(nfrontp,
+                                                       "%c%c%c%c%c%c",
+                                                       IAC, SB, TELOPT_LFLOW,
+                                                       flowmode ? LFLOW_ON
+                                                                : LFLOW_OFF,
+                                                       IAC, SE);
+                                               nfrontp += 6;
+                                       }
                                }
                                pcc--;
                                ptyip = ptyibuf+1;
                                }
                                pcc--;
                                ptyip = ptyibuf+1;
@@ -979,7 +1366,7 @@ char *host;
                 * If chars were left over from the terminal driver,
                 * note their existence.
                 */
                 * If chars were left over from the terminal driver,
                 * note their existence.
                 */
-                if (!uselinemode && unpcc) {
+               if (!uselinemode && unpcc) {
                        pcc = unpcc;
                        unpcc = 0;
                        ptyip = unptyip;
                        pcc = unpcc;
                        unpcc = 0;
                        ptyip = unptyip;
@@ -993,7 +1380,7 @@ char *host;
                if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
                        ptyflush();
        }
                if (FD_ISSET(p, &obits) && (pfrontp - pbackp) > 0)
                        ptyflush();
        }
-       cleanup();
+       cleanup(0);
 }  /* end of telnet */
        
 #ifndef        TCSIG
 }  /* end of telnet */
        
 #ifndef        TCSIG
@@ -1002,11 +1389,102 @@ char *host;
 # endif
 #endif
 
 # endif
 #endif
 
+#ifdef STREAMSPTY
+
+int flowison = -1;  /* current state of flow: -1 is unknown */
+
+int readstream(p, ibuf, bufsize)
+       int p;
+       char *ibuf;
+       int bufsize;
+{
+       int flags = 0;
+       int ret = 0;
+       struct termios *tsp;
+       struct termio *tp;
+       struct iocblk *ip;
+       char vstop, vstart;
+       int ixon;
+       int newflow;
+
+       strbufc.maxlen = BUFSIZ;
+       strbufc.buf = ctlbuf;
+       strbufd.maxlen = bufsize-1;
+       strbufd.len = 0;
+       strbufd.buf = ibuf+1;
+       ibuf[0] = 0;
+
+       ret = getmsg(p, &strbufc, &strbufd, &flags);
+       if (ret < 0)  /* error of some sort -- probably EAGAIN */
+               return(-1);
+
+       if (strbufc.len <= 0 || ctlbuf[0] == M_DATA) {
+               /* data message */
+               if (strbufd.len > 0) {                  /* real data */
+                       return(strbufd.len + 1);        /* count header char */
+               } else {
+                       /* nothing there */
+                       errno = EAGAIN;
+                       return(-1);
+               }
+       }
+
+       /*
+        * It's a control message.  Return 1, to look at the flag we set
+        */
+
+       switch (ctlbuf[0]) {
+       case M_FLUSH:
+               if (ibuf[1] & FLUSHW)
+                       ibuf[0] = TIOCPKT_FLUSHWRITE;
+               return(1);
+
+       case M_IOCTL:
+               ip = (struct iocblk *) (ibuf+1);
+
+               switch (ip->ioc_cmd) {
+               case TCSETS:
+               case TCSETSW:
+               case TCSETSF:
+                       tsp = (struct termios *)
+                                       (ibuf+1 + sizeof(struct iocblk));
+                       vstop = tsp->c_cc[VSTOP];
+                       vstart = tsp->c_cc[VSTART];
+                       ixon = tsp->c_iflag & IXON;
+                       break;
+               case TCSETA:
+               case TCSETAW:
+               case TCSETAF:
+                       tp = (struct termio *) (ibuf+1 + sizeof(struct iocblk));
+                       vstop = tp->c_cc[VSTOP];
+                       vstart = tp->c_cc[VSTART];
+                       ixon = tp->c_iflag & IXON;      
+                       break;
+               default:
+                       errno = EAGAIN;
+                       return(-1);
+               }
+
+               newflow =  (ixon && (vstart == 021) && (vstop == 023)) ? 1 : 0;
+               if (newflow != flowison) {  /* it's a change */
+                       flowison = newflow;
+                       ibuf[0] = newflow ? TIOCPKT_DOSTOP : TIOCPKT_NOSTOP;
+                       return(1);
+               }
+       }
+
+       /* nothing worth doing anything about */
+       errno = EAGAIN;
+       return(-1);
+}
+#endif /* STREAMSPTY */
+
 /*
  * Send interrupt to process on other side of pty.
  * If it is in raw mode, just write NULL;
  * otherwise, write intr char.
  */
 /*
  * Send interrupt to process on other side of pty.
  * If it is in raw mode, just write NULL;
  * otherwise, write intr char.
  */
+       void
 interrupt()
 {
        ptyflush();     /* half-hearted */
 interrupt()
 {
        ptyflush();     /* half-hearted */
@@ -1025,6 +1503,7 @@ interrupt()
  * If it is in raw mode, just write NULL;
  * otherwise, write quit char.
  */
  * If it is in raw mode, just write NULL;
  * otherwise, write quit char.
  */
+       void
 sendbrk()
 {
        ptyflush();     /* half-hearted */
 sendbrk()
 {
        ptyflush();     /* half-hearted */
@@ -1037,6 +1516,7 @@ sendbrk()
 #endif /* TCSIG */
 }
 
 #endif /* TCSIG */
 }
 
+       void
 sendsusp()
 {
 #ifdef SIGTSTP
 sendsusp()
 {
 #ifdef SIGTSTP
@@ -1054,6 +1534,7 @@ sendsusp()
  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
  * just send back "[Yes]".
  */
  * When we get an AYT, if ^T is enabled, use that.  Otherwise,
  * just send back "[Yes]".
  */
+       void
 recv_ayt()
 {
 #if    defined(SIGINFO) && defined(TCSIG)
 recv_ayt()
 {
 #if    defined(SIGINFO) && defined(TCSIG)
@@ -1066,15 +1547,14 @@ recv_ayt()
        nfrontp += 9;
 }
 
        nfrontp += 9;
 }
 
+       void
 doeof()
 {
 doeof()
 {
-#if    defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
-       extern char oldeofc;
-#endif
        init_termbuf();
 
 #if    defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
        if (!tty_isediting()) {
        init_termbuf();
 
 #if    defined(LINEMODE) && defined(USE_TERMIO) && (VEOF == VMIN)
        if (!tty_isediting()) {
+               extern char oldeofc;
                *pfrontp++ = oldeofc;
                return;
        }
                *pfrontp++ = oldeofc;
                return;
        }