BSD 4_4 release
[unix-history] / usr / src / libexec / telnetd / sys_term.c
index 9aa99d5..55dcd56 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.
  *
  *
- * Redistribution and use in source and binary forms are permitted provided
- * that: (1) source distributions retain this entire copyright notice and
- * comment, and (2) distributions including binaries display the following
- * acknowledgement:  ``This product includes software developed by the
- * University of California, Berkeley and its contributors'' in the
- * documentation or other materials provided with the distribution and in
- * all advertising materials mentioning features or use of this software.
- * 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * 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
-static char sccsid[] = "@(#)sys_term.c 5.10 (Berkeley) 6/30/90";
+static char sccsid[] = "@(#)sys_term.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(AUTHENTICATION)
+#include <libtelnet/auth.h>
+#endif
+
+#if defined(CRAY) || defined(__hpux)
+# define PARENT_DOES_UTMP
+#endif
+
 #ifdef NEWINIT
 #include <initreq.h>
 #ifdef NEWINIT
 #include <initreq.h>
+int    utmp_len = MAXHOSTNAMELEN;      /* sizeof(init_request.host) */
 #else  /* NEWINIT*/
 #else  /* NEWINIT*/
-#include <utmp.h>
+# ifdef        UTMPX
+# include <utmpx.h>
+# else
+# include <utmp.h>
+# endif /* UTMPX */
 struct utmp wtmp;
 
 struct utmp wtmp;
 
-# ifndef CRAY
+int    utmp_len = sizeof(wtmp.ut_host);
+# ifndef PARENT_DOES_UTMP
 char   wtmpf[] = "/usr/adm/wtmp";
 char   utmpf[] = "/etc/utmp";
 char   wtmpf[] = "/usr/adm/wtmp";
 char   utmpf[] = "/etc/utmp";
-# else /* CRAY */
+# else /* PARENT_DOES_UTMP */
 char   wtmpf[] = "/etc/wtmp";
 char   wtmpf[] = "/etc/wtmp";
+# endif /* PARENT_DOES_UTMP */
+
+# ifdef CRAY
+#include <tmpdir.h>
+#include <sys/wait.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/secstat.h>
+extern int secflag;
+extern struct sysv sysv;
+#  endif /* _SC_CRAY_SECURE_SYS */
 # endif        /* CRAY */
 #endif /* NEWINIT */
 
 # endif        /* CRAY */
 #endif /* NEWINIT */
 
+#ifdef STREAMSPTY
+#include <sac.h>
+#include <sys/stropts.h>
+#endif
+
 #define SCPYN(a, b)    (void) strncpy(a, b, sizeof(a))
 #define SCMPN(a, b)    strncmp(a, b, sizeof(a))
 
 #ifdef STREAMS
 #include <sys/stream.h>
 #endif
 #define SCPYN(a, b)    (void) strncpy(a, b, sizeof(a))
 #define SCMPN(a, b)    strncmp(a, b, sizeof(a))
 
 #ifdef STREAMS
 #include <sys/stream.h>
 #endif
+#ifdef __hpux
+#include <sys/resource.h>
+#include <sys/proc.h>
+#endif
 #include <sys/tty.h>
 #ifdef t_erase
 #undef t_erase
 #include <sys/tty.h>
 #ifdef t_erase
 #undef t_erase
@@ -74,20 +131,48 @@ struct termbuf {
        int state;
        int lflags;
 } termbuf, termbuf2;
        int state;
        int lflags;
 } termbuf, termbuf2;
+# define       cfsetospeed(tp, val)    (tp)->sg.sg_ospeed = (val)
+# define       cfsetispeed(tp, val)    (tp)->sg.sg_ispeed = (val)
+# define       cfgetospeed(tp)         (tp)->sg.sg_ospeed
+# define       cfgetispeed(tp)         (tp)->sg.sg_ispeed
 #else  /* USE_TERMIO */
 # ifdef        SYSV_TERMIO
 #      define termios termio
 # endif
 #else  /* USE_TERMIO */
 # ifdef        SYSV_TERMIO
 #      define termios termio
 # endif
-# ifndef TCSETA
+# ifndef       TCSANOW
 #  ifdef TCSETS
 #  ifdef TCSETS
-#   define TCSETA TCSETS
-#   define TCGETA TCGETS
+#   define     TCSANOW         TCSETS
+#   define     TCSADRAIN       TCSETSW
+#   define     tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
+#  else
+#   ifdef TCSETA
+#    define    TCSANOW         TCSETA
+#    define    TCSADRAIN       TCSETAW
+#    define    tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
+#   else
+#    define    TCSANOW         TIOCSETA
+#    define    TCSADRAIN       TIOCSETAW
+#    define    tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
+#   endif
+#  endif
+#  define      tcsetattr(f, a, t)      ioctl(f, a, t)
+#  define      cfsetospeed(tp, val)    (tp)->c_cflag &= ~CBAUD; \
+                                       (tp)->c_cflag |= (val)
+#  define      cfgetospeed(tp)         ((tp)->c_cflag & CBAUD)
+#  ifdef CIBAUD
+#   define     cfsetispeed(tp, val)    (tp)->c_cflag &= ~CIBAUD; \
+                                       (tp)->c_cflag |= ((val)<<IBSHIFT)
+#   define     cfgetispeed(tp)         (((tp)->c_cflag & CIBAUD)>>IBSHIFT)
 #  else
 #  else
-#   define TCSETA TIOCSETAW
-#   define TCGETA TIOCGETA
+#   define     cfsetispeed(tp, val)    (tp)->c_cflag &= ~CBAUD; \
+                                       (tp)->c_cflag |= (val)
+#   define     cfgetispeed(tp)         ((tp)->c_cflag & CBAUD)
 #  endif
 #  endif
-# endif /* 4.4BSD */
+# endif /* TCSANOW */
 struct termios termbuf, termbuf2;      /* pty control structure */
 struct termios termbuf, termbuf2;      /* pty control structure */
+# ifdef  STREAMSPTY
+int ttyfd = -1;
+# endif
 #endif /* USE_TERMIO */
 
 /*
 #endif /* USE_TERMIO */
 
 /*
@@ -101,6 +186,7 @@ struct termios termbuf, termbuf2;   /* pty control structure */
  * set_termbuf() writes the structure into the kernel.
  */
 
  * set_termbuf() writes the structure into the kernel.
  */
 
+       void
 init_termbuf()
 {
 #ifndef        USE_TERMIO
 init_termbuf()
 {
 #ifndef        USE_TERMIO
@@ -111,15 +197,20 @@ init_termbuf()
        (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
 # endif
 #else
        (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
 # endif
 #else
-       (void) ioctl(pty, TCGETA, (char *)&termbuf);
+# ifdef  STREAMSPTY
+       (void) tcgetattr(ttyfd, &termbuf);
+# else
+       (void) tcgetattr(pty, &termbuf);
+# endif
 #endif
        termbuf2 = termbuf;
 }
 
 #if    defined(LINEMODE) && defined(TIOCPKT_IOCTL)
 #endif
        termbuf2 = termbuf;
 }
 
 #if    defined(LINEMODE) && defined(TIOCPKT_IOCTL)
+       void
 copy_termbuf(cp, len)
 copy_termbuf(cp, len)
-char *cp;
-int len;
+       char *cp;
+       int len;
 {
        if (len > sizeof(termbuf))
                len = sizeof(termbuf);
 {
        if (len > sizeof(termbuf))
                len = sizeof(termbuf);
@@ -128,6 +219,7 @@ int len;
 }
 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
 
 }
 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
 
+       void
 set_termbuf()
 {
        /*
 set_termbuf()
 {
        /*
@@ -135,7 +227,7 @@ set_termbuf()
         */
 #ifndef        USE_TERMIO
        if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
         */
 #ifndef        USE_TERMIO
        if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
-               (void) ioctl(pty, TIOCSETP, (char *)&termbuf.sg);
+               (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
        if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
                (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
        if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
        if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
                (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
        if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
@@ -145,8 +237,12 @@ set_termbuf()
                (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
 #else  /* USE_TERMIO */
        if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
                (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
 #else  /* USE_TERMIO */
        if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
-               (void) ioctl(pty, TCSETA, (char *)&termbuf);
-# if   defined(CRAY2) && defined(UNCIOS5)
+# ifdef  STREAMSPTY
+               (void) tcsetattr(ttyfd, TCSANOW, &termbuf);
+# else
+               (void) tcsetattr(pty, TCSANOW, &termbuf);
+# endif
+# if   defined(CRAY2) && defined(UNICOS5)
        needtermstat = 1;
 # endif
 #endif /* USE_TERMIO */
        needtermstat = 1;
 # endif
 #endif /* USE_TERMIO */
@@ -165,10 +261,11 @@ set_termbuf()
  */
 
 #ifndef        USE_TERMIO
  */
 
 #ifndef        USE_TERMIO
+       int
 spcset(func, valp, valpp)
 spcset(func, valp, valpp)
-int func;
-cc_t *valp;
-cc_t **valpp;
+       int func;
+       cc_t *valp;
+       cc_t **valpp;
 {
        switch(func) {
        case SLC_EOF:
 {
        switch(func) {
        case SLC_EOF:
@@ -239,10 +336,11 @@ cc_t **valpp;
 
 #else  /* USE_TERMIO */
 
 
 #else  /* USE_TERMIO */
 
+       int
 spcset(func, valp, valpp)
 spcset(func, valp, valpp)
-int func;
-cc_t *valp;
-cc_t **valpp;
+       int func;
+       cc_t *valp;
+       cc_t **valpp;
 {
 
 #define        setval(a, b)    *valp = termbuf.c_cc[a]; \
 {
 
 #define        setval(a, b)    *valp = termbuf.c_cc[a]; \
@@ -292,8 +390,11 @@ cc_t **valpp;
                defval(0);
 #endif
        case SLC_AO:
                defval(0);
 #endif
        case SLC_AO:
-#ifdef VFLUSHO
-               setval(VFLUSHO, SLC_VARIABLE|SLC_FLUSHOUT);
+#if    !defined(VDISCARD) && defined(VFLUSHO)
+# define VDISCARD VFLUSHO
+#endif
+#ifdef VDISCARD
+               setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
 #else
                defval(0);
 #endif
 #else
                defval(0);
 #endif
@@ -311,10 +412,15 @@ cc_t **valpp;
        case SLC_FORW2:
                setval(VEOL2, SLC_VARIABLE);
 #endif
        case SLC_FORW2:
                setval(VEOL2, SLC_VARIABLE);
 #endif
+       case SLC_AYT:
+#ifdef VSTATUS
+               setval(VSTATUS, SLC_VARIABLE);
+#else
+               defval(0);
+#endif
 
        case SLC_BRK:
        case SLC_SYNCH:
 
        case SLC_BRK:
        case SLC_SYNCH:
-       case SLC_AYT:
        case SLC_EOR:
                defval(0);
 
        case SLC_EOR:
                defval(0);
 
@@ -332,16 +438,21 @@ cc_t **valpp;
  *
  * Return the number of pty's configured into the system.
  */
  *
  * Return the number of pty's configured into the system.
  */
+       int
 getnpty()
 {
 #ifdef _SC_CRAY_NPTY
 getnpty()
 {
 #ifdef _SC_CRAY_NPTY
-       return sysconf(_SC_CRAY_NPTY);
-#else
-       return 128;
+       int numptys;
+
+       if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
+               return numptys;
+       else
 #endif /* _SC_CRAY_NPTY */
 #endif /* _SC_CRAY_NPTY */
+               return 128;
 }
 #endif /* CRAY */
 
 }
 #endif /* CRAY */
 
+#ifndef        convex
 /*
  * getpty()
  *
 /*
  * getpty()
  *
@@ -350,45 +461,117 @@ getnpty()
  *
  * Returns the file descriptor of the opened pty.
  */
  *
  * Returns the file descriptor of the opened pty.
  */
+#ifndef        __GNUC__
 char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
 char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+#else
+static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+char *line = Xline;
+#endif
+#ifdef CRAY
+char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
+#endif /* CRAY */
 
 
-getpty()
+       int
+getpty(ptynum)
+int *ptynum;
 {
        register int p;
 {
        register int p;
+#ifdef STREAMSPTY
+       int t;
+       char *ptsname();
+
+       p = open("/dev/ptmx", 2);
+       if (p > 0) {
+               grantpt(p);
+               unlockpt(p);
+               strcpy(line, ptsname(p));
+               return(p);
+       }
+
+#else  /* ! STREAMSPTY */
 #ifndef CRAY
 #ifndef CRAY
-       register char c, *p1, *p2;
+       register char *cp, *p1, *p2;
        register int i;
        register int i;
+#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
+       int dummy;
+#endif
 
 
+#ifndef        __hpux
        (void) sprintf(line, "/dev/ptyXX");
        p1 = &line[8];
        p2 = &line[9];
        (void) sprintf(line, "/dev/ptyXX");
        p1 = &line[8];
        p2 = &line[9];
+#else
+       (void) sprintf(line, "/dev/ptym/ptyXX");
+       p1 = &line[13];
+       p2 = &line[14];
+#endif
 
 
-       for (c = 'p'; c <= 's'; c++) {
+       for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
                struct stat stb;
 
                struct stat stb;
 
-               *p1 = c;
+               *p1 = *cp;
                *p2 = '0';
                *p2 = '0';
+               /*
+                * This stat() check is just to keep us from
+                * looping through all 256 combinations if there
+                * aren't that many ptys available.
+                */
                if (stat(line, &stb) < 0)
                        break;
                for (i = 0; i < 16; i++) {
                        *p2 = "0123456789abcdef"[i];
                        p = open(line, 2);
                        if (p > 0) {
                if (stat(line, &stb) < 0)
                        break;
                for (i = 0; i < 16; i++) {
                        *p2 = "0123456789abcdef"[i];
                        p = open(line, 2);
                        if (p > 0) {
+#ifndef        __hpux
                                line[5] = 't';
                                line[5] = 't';
-                               return(p);
+#else
+                               for (p1 = &line[8]; *p1; p1++)
+                                       *p1 = *(p1+1);
+                               line[9] = 't';
+#endif
+                               chown(line, 0, 0);
+                               chmod(line, 0600);
+#if defined(sun) && defined(TIOCGPGRP) && BSD < 199207
+                               if (ioctl(p, TIOCGPGRP, &dummy) == 0
+                                   || errno != EIO) {
+                                       chmod(line, 0666);
+                                       close(p);
+                                       line[5] = 'p';
+                               } else
+#endif /* defined(sun) && defined(TIOCGPGRP) && BSD < 199207 */
+                                       return(p);
                        }
                }
        }
 #else  /* CRAY */
                        }
                }
        }
 #else  /* CRAY */
-       register int npty;
        extern lowpty, highpty;
        extern lowpty, highpty;
+       struct stat sb;
 
 
-       for (npty = lowpty; npty <= highpty; npty++) {
-               (void) sprintf(line, "/dev/pty/%03d", npty);
-               p = open(line, 2);
+       for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
+               (void) sprintf(myline, "/dev/pty/%03d", *ptynum);
+               p = open(myline, 2);
                if (p < 0)
                        continue;
                if (p < 0)
                        continue;
-               (void) sprintf(line, "/dev/ttyp%03d", npty);
+               (void) sprintf(line, "/dev/ttyp%03d", *ptynum);
+               /*
+                * Here are some shenanigans to make sure that there
+                * are no listeners lurking on the line.
+                */
+               if(stat(line, &sb) < 0) {
+                       (void) close(p);
+                       continue;
+               }
+               if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
+                       chown(line, 0, 0);
+                       chmod(line, 0600);
+                       (void)close(p);
+                       p = open(myline, 2);
+                       if (p < 0)
+                               continue;
+               }
+               /*
+                * Now it should be safe...check for accessability.
+                */
                if (access(line, 6) == 0)
                        return(p);
                else {
                if (access(line, 6) == 0)
                        return(p);
                else {
@@ -397,8 +580,10 @@ getpty()
                }
        }
 #endif /* CRAY */
                }
        }
 #endif /* CRAY */
+#endif /* STREAMSPTY */
        return(-1);
 }
        return(-1);
 }
+#endif /* convex */
 
 #ifdef LINEMODE
 /*
 
 #ifdef LINEMODE
 /*
@@ -422,40 +607,49 @@ getpty()
  * tty_rspeed(val)     Set receive speed to val.
  */
 
  * tty_rspeed(val)     Set receive speed to val.
  */
 
-tty_flowmode()
-{
-#ifndef USE_TERMIO
-       return((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0);
-#else
-       return(termbuf.c_iflag & IXON ? 1 : 0);
+#ifdef convex
+static int linestate;
 #endif
 #endif
-}
 
 
+       int
 tty_linemode()
 {
 tty_linemode()
 {
+#ifndef convex
 #ifndef        USE_TERMIO
        return(termbuf.state & TS_EXTPROC);
 #else
        return(termbuf.c_lflag & EXTPROC);
 #endif
 #ifndef        USE_TERMIO
        return(termbuf.state & TS_EXTPROC);
 #else
        return(termbuf.c_lflag & EXTPROC);
 #endif
+#else
+       return(linestate);
+#endif
 }
 
 }
 
+       void
 tty_setlinemode(on)
 tty_setlinemode(on)
-int on;
+       int on;
 {
 #ifdef TIOCEXT
 {
 #ifdef TIOCEXT
+# ifndef convex
+       set_termbuf();
+# else
+       linestate = on;
+# endif
        (void) ioctl(pty, TIOCEXT, (char *)&on);
        (void) ioctl(pty, TIOCEXT, (char *)&on);
+# ifndef convex
+       init_termbuf();
+# endif
 #else  /* !TIOCEXT */
 #else  /* !TIOCEXT */
-#ifdef EXTPROC
+# ifdef        EXTPROC
        if (on)
                termbuf.c_lflag |= EXTPROC;
        else
                termbuf.c_lflag &= ~EXTPROC;
        if (on)
                termbuf.c_lflag |= EXTPROC;
        else
                termbuf.c_lflag &= ~EXTPROC;
-#endif
-       set_termbuf();
+# endif
 #endif /* TIOCEXT */
 }
 
 #endif /* TIOCEXT */
 }
 
+       int
 tty_isecho()
 {
 #ifndef USE_TERMIO
 tty_isecho()
 {
 #ifndef USE_TERMIO
@@ -466,7 +660,33 @@ tty_isecho()
 }
 #endif /* LINEMODE */
 
 }
 #endif /* LINEMODE */
 
+       int
+tty_flowmode()
+{
+#ifndef USE_TERMIO
+       return(((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0) ? 1 : 0);
+#else
+       return((termbuf.c_iflag & IXON) ? 1 : 0);
+#endif
+}
+
+       int
+tty_restartany()
+{
+#ifndef USE_TERMIO
+# ifdef        DECCTQ
+       return((termbuf.lflags & DECCTQ) ? 0 : 1);
+# else
+       return(-1);
+# endif
+#else
+       return((termbuf.c_iflag & IXANY) ? 1 : 0);
+#endif
+}
+
+       void
 tty_setecho(on)
 tty_setecho(on)
+       int on;
 {
 #ifndef        USE_TERMIO
        if (on)
 {
 #ifndef        USE_TERMIO
        if (on)
@@ -482,6 +702,7 @@ tty_setecho(on)
 }
 
 #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
 }
 
 #if    defined(LINEMODE) && defined(KLUDGELINEMODE)
+       int
 tty_israw()
 {
 #ifndef USE_TERMIO
 tty_israw()
 {
 #ifndef USE_TERMIO
@@ -492,7 +713,9 @@ tty_israw()
 }
 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
 
 }
 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
 
+       void
 tty_binaryin(on)
 tty_binaryin(on)
+       int on;
 {
 #ifndef        USE_TERMIO
        if (on)
 {
 #ifndef        USE_TERMIO
        if (on)
@@ -501,14 +724,16 @@ tty_binaryin(on)
                termbuf.lflags &= ~LPASS8;
 #else
        if (on) {
                termbuf.lflags &= ~LPASS8;
 #else
        if (on) {
-               termbuf.c_lflag &= ~ISTRIP;
+               termbuf.c_iflag &= ~ISTRIP;
        } else {
        } else {
-               termbuf.c_lflag |= ISTRIP;
+               termbuf.c_iflag |= ISTRIP;
        }
 #endif
 }
 
        }
 #endif
 }
 
+       void
 tty_binaryout(on)
 tty_binaryout(on)
+       int on;
 {
 #ifndef        USE_TERMIO
        if (on)
 {
 #ifndef        USE_TERMIO
        if (on)
@@ -528,6 +753,7 @@ tty_binaryout(on)
 #endif
 }
 
 #endif
 }
 
+       int
 tty_isbinaryin()
 {
 #ifndef        USE_TERMIO
 tty_isbinaryin()
 {
 #ifndef        USE_TERMIO
@@ -537,6 +763,7 @@ tty_isbinaryin()
 #endif
 }
 
 #endif
 }
 
+       int
 tty_isbinaryout()
 {
 #ifndef        USE_TERMIO
 tty_isbinaryout()
 {
 #ifndef        USE_TERMIO
@@ -547,6 +774,7 @@ tty_isbinaryout()
 }
 
 #ifdef LINEMODE
 }
 
 #ifdef LINEMODE
+       int
 tty_isediting()
 {
 #ifndef USE_TERMIO
 tty_isediting()
 {
 #ifndef USE_TERMIO
@@ -556,6 +784,7 @@ tty_isediting()
 #endif
 }
 
 #endif
 }
 
+       int
 tty_istrapsig()
 {
 #ifndef USE_TERMIO
 tty_istrapsig()
 {
 #ifndef USE_TERMIO
@@ -565,8 +794,9 @@ tty_istrapsig()
 #endif
 }
 
 #endif
 }
 
+       void
 tty_setedit(on)
 tty_setedit(on)
-int on;
+       int on;
 {
 #ifndef USE_TERMIO
        if (on)
 {
 #ifndef USE_TERMIO
        if (on)
@@ -581,8 +811,9 @@ int on;
 #endif
 }
 
 #endif
 }
 
+       void
 tty_setsig(on)
 tty_setsig(on)
-int on;
+       int on;
 {
 #ifndef        USE_TERMIO
        if (on)
 {
 #ifndef        USE_TERMIO
        if (on)
@@ -596,6 +827,7 @@ int on;
 }
 #endif /* LINEMODE */
 
 }
 #endif /* LINEMODE */
 
+       int
 tty_issofttab()
 {
 #ifndef        USE_TERMIO
 tty_issofttab()
 {
 #ifndef        USE_TERMIO
@@ -610,8 +842,9 @@ tty_issofttab()
 #endif
 }
 
 #endif
 }
 
+       void
 tty_setsofttab(on)
 tty_setsofttab(on)
-int on;
+       int on;
 {
 #ifndef        USE_TERMIO
        if (on)
 {
 #ifndef        USE_TERMIO
        if (on)
@@ -639,10 +872,11 @@ int on;
 #endif
 }
 
 #endif
 }
 
+       int
 tty_islitecho()
 {
 #ifndef        USE_TERMIO
 tty_islitecho()
 {
 #ifndef        USE_TERMIO
-       return (!(termbuf.sg.sg_flags & CTLECH));
+       return (!(termbuf.lflags & LCTLECH));
 #else
 # ifdef        ECHOCTL
        return (!(termbuf.c_lflag & ECHOCTL));
 #else
 # ifdef        ECHOCTL
        return (!(termbuf.c_lflag & ECHOCTL));
@@ -656,14 +890,15 @@ tty_islitecho()
 #endif
 }
 
 #endif
 }
 
+       void
 tty_setlitecho(on)
 tty_setlitecho(on)
-int on;
+       int on;
 {
 #ifndef        USE_TERMIO
        if (on)
 {
 #ifndef        USE_TERMIO
        if (on)
-               termbuf.sg.sg_flags &= ~CTLECH;
+               termbuf.lflags &= ~LCTLECH;
        else
        else
-               termbuf.sg.sg_flags |= CTLECH;
+               termbuf.lflags |= LCTLECH;
 #else
 # ifdef        ECHOCTL
        if (on)
 #else
 # ifdef        ECHOCTL
        if (on)
@@ -678,6 +913,16 @@ int on;
                termbuf.c_lflag |= TCTLECH;
 # endif
 #endif
                termbuf.c_lflag |= TCTLECH;
 # endif
 #endif
+}
+
+       int
+tty_iscrnl()
+{
+#ifndef        USE_TERMIO
+       return (termbuf.sg.sg_flags & CRMOD);
+#else
+       return (termbuf.c_iflag & ICRNL);
+#endif
 }
 
 /*
 }
 
 /*
@@ -695,43 +940,30 @@ struct termspeeds {
        { 38400, B9600 }, { -1,    B9600 }
 };
 
        { 38400, B9600 }, { -1,    B9600 }
 };
 
+       void
 tty_tspeed(val)
 tty_tspeed(val)
+       int val;
 {
        register struct termspeeds *tp;
 
        for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
                ;
 {
        register struct termspeeds *tp;
 
        for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
                ;
-#ifndef        USE_TERMIO
-       termbuf.sg.sg_ospeed = tp->value;
-#else
-# ifdef        CBAUD
-       termbuf.c_cflag &= ~CBAUD;
-       termbuf.c_cflag |= tp->value;
-# else
-       termbuf.c_ospeed = tp->value;
-# endif
-#endif
+       cfsetospeed(&termbuf, tp->value);
 }
 
 }
 
+       void
 tty_rspeed(val)
 tty_rspeed(val)
+       int val;
 {
        register struct termspeeds *tp;
 
        for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
                ;
 {
        register struct termspeeds *tp;
 
        for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
                ;
-#ifndef        USE_TERMIO
-       termbuf.sg.sg_ispeed = tp->value;
-#else
-# ifdef        CBAUD
-       termbuf.c_cflag &= ~CBAUD;
-       termbuf.c_cflag |= tp->value;
-# else
-       termbuf.c_ispeed = tp->value;
-# endif
-#endif
+       cfsetispeed(&termbuf, tp->value);
 }
 
 #if    defined(CRAY2) && defined(UNICOS5)
 }
 
 #if    defined(CRAY2) && defined(UNICOS5)
+       int
 tty_isnewmap()
 {
        return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
 tty_isnewmap()
 {
        return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
@@ -739,21 +971,31 @@ tty_isnewmap()
 }
 #endif
 
 }
 #endif
 
-#ifdef CRAY
+#ifdef PARENT_DOES_UTMP
 # ifndef NEWINIT
 extern struct utmp wtmp;
 extern char wtmpf[];
 # else /* NEWINIT */
 int    gotalarm;
 # ifndef NEWINIT
 extern struct utmp wtmp;
 extern char wtmpf[];
 # else /* NEWINIT */
 int    gotalarm;
-/* ARGSUSED */
-void
+
+       /* ARGSUSED */
+       void
 nologinproc(sig)
 nologinproc(sig)
-int sig;
+       int sig;
 {
        gotalarm++;
 }
 # endif        /* NEWINIT */
 {
        gotalarm++;
 }
 # endif        /* NEWINIT */
-#endif /* CRAY */
+#endif /* PARENT_DOES_UTMP */
+
+#ifndef        NEWINIT
+# ifdef PARENT_DOES_UTMP
+extern void utmp_sig_init P((void));
+extern void utmp_sig_reset P((void));
+extern void utmp_sig_wait P((void));
+extern void utmp_sig_notify P((int));
+# endif /* PARENT_DOES_UTMP */
+#endif
 
 /*
  * getptyslave()
 
 /*
  * getptyslave()
@@ -762,96 +1004,329 @@ int sig;
  * that is necessary.  The return value is a file descriptor
  * for the slave side.
  */
  * that is necessary.  The return value is a file descriptor
  * for the slave side.
  */
+       int
 getptyslave()
 {
        register int t = -1;
 
 getptyslave()
 {
        register int t = -1;
 
-#ifndef        CRAY
+#if    !defined(CRAY) || !defined(NEWINIT)
+# ifdef        LINEMODE
+       int waslm;
+# endif
+# ifdef        TIOCGWINSZ
+       struct winsize ws;
+       extern int def_row, def_col;
+# endif
+       extern int def_tspeed, def_rspeed;
+       /*
+        * Opening the slave side may cause initilization of the
+        * kernel tty structure.  We need remember the state of
+        *      if linemode was turned on
+        *      terminal window size
+        *      terminal speed
+        * so that we can re-set them if we need to.
+        */
+# ifdef        LINEMODE
+       waslm = tty_linemode();
+# endif
+
+
        /*
        /*
-        * Disassociate self from control terminal and open ttyp side.
-        * Set important flags on ttyp and ptyp.
+        * Make sure that we don't have a controlling tty, and
+        * that we are the session (process group) leader.
         */
         */
+# ifdef        TIOCNOTTY
        t = open(_PATH_TTY, O_RDWR);
        if (t >= 0) {
                (void) ioctl(t, TIOCNOTTY, (char *)0);
                (void) close(t);
        }
        t = open(_PATH_TTY, O_RDWR);
        if (t >= 0) {
                (void) ioctl(t, TIOCNOTTY, (char *)0);
                (void) close(t);
        }
+# endif
 
 
-       t = open(line, O_RDWR);
-       if (t < 0)
-               fatalperror(net, line);
-       if (fchmod(t, 0))
-               fatalperror(net, line);
-#if BSD <= 43
-       (void) signal(SIGHUP, SIG_IGN);
-       vhangup();
-       (void) signal(SIGHUP, SIG_DFL);
-       t = open(line, O_RDWR);
+
+# ifdef PARENT_DOES_UTMP
+       /*
+        * Wait for our parent to get the utmp stuff to get done.
+        */
+       utmp_sig_wait();
+# endif
+
+       t = cleanopen(line);
        if (t < 0)
                fatalperror(net, line);
        if (t < 0)
                fatalperror(net, line);
+
+#ifdef  STREAMSPTY
+#ifdef USE_TERMIO
+       ttyfd = t;
+#endif
+       if (ioctl(t, I_PUSH, "ptem") < 0) 
+               fatal(net, "I_PUSH ptem");
+       if (ioctl(t, I_PUSH, "ldterm") < 0)
+               fatal(net, "I_PUSH ldterm");
+       if (ioctl(t, I_PUSH, "ttcompat") < 0)
+               fatal(net, "I_PUSH ttcompat");
+       if (ioctl(pty, I_PUSH, "pckt") < 0)
+               fatal(net, "I_PUSH pckt");
 #endif
 
 #endif
 
+       /*
+        * set up the tty modes as we like them to be.
+        */
        init_termbuf();
        init_termbuf();
-#ifndef        USE_TERMIO
+# ifdef        TIOCGWINSZ
+       if (def_row || def_col) {
+               bzero((char *)&ws, sizeof(ws));
+               ws.ws_col = def_col;
+               ws.ws_row = def_row;
+               (void)ioctl(t, TIOCSWINSZ, (char *)&ws);
+       }
+# endif
+
+       /*
+        * Settings for sgtty based systems
+        */
+# ifndef       USE_TERMIO
        termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
        termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS;
-       termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600;
-#else
+# endif        /* USE_TERMIO */
+
+       /*
+        * Settings for UNICOS (and HPUX)
+        */
+# if defined(CRAY) || defined(__hpux)
+       termbuf.c_oflag = OPOST|ONLCR|TAB3;
+       termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
+       termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
+       termbuf.c_cflag = EXTB|HUPCL|CS8;
+# endif
+
+       /*
+        * Settings for all other termios/termio based
+        * systems, other than 4.4BSD.  In 4.4BSD the
+        * kernel does the initial terminal setup.
+        */
+# if defined(USE_TERMIO) && !(defined(CRAY) || defined(__hpux)) && (BSD <= 43)
+#  ifndef      OXTABS
+#   define OXTABS      0
+#  endif
        termbuf.c_lflag |= ECHO;
        termbuf.c_lflag |= ECHO;
-#ifndef        OXTABS
-#define OXTABS 0
-#endif
        termbuf.c_oflag |= ONLCR|OXTABS;
        termbuf.c_iflag |= ICRNL;
        termbuf.c_iflag &= ~IXOFF;
        termbuf.c_oflag |= ONLCR|OXTABS;
        termbuf.c_iflag |= ICRNL;
        termbuf.c_iflag &= ~IXOFF;
-# ifdef        CBAUD
-       termbuf.c_cflag &= ~CBAUD;
-       termbuf.c_cflag |= B9600;
-# else /* CBAUD */
-       termbuf.c_ospeed = termbuf.c_ispeed = B9600;
-# endif        /* CBAUD */
-#endif
+# endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */
+       tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
+       tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
+# ifdef        LINEMODE
+       if (waslm)
+               tty_setlinemode(1);
+# endif        /* LINEMODE */
+
+       /*
+        * Set the tty modes, and make this our controlling tty.
+        */
        set_termbuf();
        set_termbuf();
-#else  /* CRAY */
+       if (login_tty(t) == -1)
+               fatalperror(net, "login_tty");
+#endif /* !defined(CRAY) || !defined(NEWINIT) */
+       if (net > 2)
+               (void) close(net);
+       if (pty > 2)
+               (void) close(pty);
+}
+
+#if    !defined(CRAY) || !defined(NEWINIT)
+#ifndef        O_NOCTTY
+#define        O_NOCTTY        0
+#endif
+/*
+ * Open the specified slave side of the pty,
+ * making sure that we have a clean tty.
+ */
+       int
+cleanopen(line)
+       char *line;
+{
+       register int t;
+#if    defined(_SC_CRAY_SECURE_SYS)
+       struct secstat secbuf;
+#endif /* _SC_CRAY_SECURE_SYS */
+
+#ifndef STREAMSPTY
+       /*
+        * Make sure that other people can't open the
+        * slave side of the connection.
+        */
        (void) chown(line, 0, 0);
        (void) chmod(line, 0600);
        (void) chown(line, 0, 0);
        (void) chmod(line, 0600);
-#endif /* CRAY */
+#endif
+
+# if !defined(CRAY) && (BSD > 43)
+       (void) revoke(line);
+# endif
+#if    defined(_SC_CRAY_SECURE_SYS)
+       if (secflag) {
+               if (secstat(line, &secbuf) < 0)
+                       return(-1);
+               if (setulvl(secbuf.st_slevel) < 0)
+                       return(-1);
+               if (setucmp(secbuf.st_compart) < 0)
+                       return(-1);
+       }
+#endif /* _SC_CRAY_SECURE_SYS */
+
+       t = open(line, O_RDWR|O_NOCTTY);
+
+#if    defined(_SC_CRAY_SECURE_SYS)
+       if (secflag) {
+               if (setulvl(sysv.sy_minlvl) < 0)
+                       return(-1);
+               if (setucmp(0) < 0)
+                       return(-1);
+       }
+#endif /* _SC_CRAY_SECURE_SYS */
+
+       if (t < 0)
+               return(-1);
+
+       /*
+        * Hangup anybody else using this ttyp, then reopen it for
+        * ourselves.
+        */
+# if !(defined(CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
+       (void) signal(SIGHUP, SIG_IGN);
+       vhangup();
+       (void) signal(SIGHUP, SIG_DFL);
+       t = open(line, O_RDWR|O_NOCTTY);
+       if (t < 0)
+               return(-1);
+# endif
+# if   defined(CRAY) && defined(TCVHUP)
+       {
+               register int i;
+               (void) signal(SIGHUP, SIG_IGN);
+               (void) ioctl(t, TCVHUP, (char *)0);
+               (void) signal(SIGHUP, SIG_DFL);
+               setpgrp();
+
+#if            defined(_SC_CRAY_SECURE_SYS)
+               if (secflag) {
+                       if (secstat(line, &secbuf) < 0)
+                               return(-1);
+                       if (setulvl(secbuf.st_slevel) < 0)
+                               return(-1);
+                       if (setucmp(secbuf.st_compart) < 0)
+                               return(-1);
+               }
+#endif         /* _SC_CRAY_SECURE_SYS */
+
+               i = open(line, O_RDWR);
+
+#if            defined(_SC_CRAY_SECURE_SYS)
+               if (secflag) {
+                       if (setulvl(sysv.sy_minlvl) < 0)
+                               return(-1);
+                       if (setucmp(0) < 0)
+                               return(-1);
+               }
+#endif         /* _SC_CRAY_SECURE_SYS */
+
+               if (i < 0)
+                       return(-1);
+               (void) close(t);
+               t = i;
+       }
+# endif        /* defined(CRAY) && defined(TCVHUP) */
        return(t);
 }
        return(t);
 }
+#endif /* !defined(CRAY) || !defined(NEWINIT) */
+
+#if BSD <= 43
+       int
+login_tty(t)
+       int t;
+{
+       if (setsid() < 0)
+               fatalperror(net, "setsid()");
+# ifdef        TIOCSCTTY
+       if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
+               fatalperror(net, "ioctl(sctty)");
+#  if defined(CRAY)
+       /*
+        * Close the hard fd to /dev/ttypXXX, and re-open through
+        * the indirect /dev/tty interface.
+        */
+       close(t);
+       if ((t = open("/dev/tty", O_RDWR)) < 0)
+               fatalperror(net, "open(/dev/tty)");
+#  endif
+# else
+       close(open(line, O_RDWR));
+# endif
+       if (t != 0)
+               (void) dup2(t, 0);
+       if (t != 1)
+               (void) dup2(t, 1);
+       if (t != 2)
+               (void) dup2(t, 2);
+       if (t > 2)
+               close(t);
+       return(0);
+}
+#endif /* BSD <= 43 */
 
 #ifdef NEWINIT
 char *gen_id = "fe";
 #endif
 
 /*
 
 #ifdef NEWINIT
 char *gen_id = "fe";
 #endif
 
 /*
- * startslave(t, host)
+ * startslave(host)
  *
  *
- * Given a file descriptor (t) for a tty, and a hostname, do whatever
+ * Given a hostname, do whatever
  * is necessary to startup the login process on the slave side of the pty.
  */
 
 /* ARGSUSED */
  * is necessary to startup the login process on the slave side of the pty.
  */
 
 /* ARGSUSED */
-startslave(t, host)
-int t;
-char *host;
+       void
+startslave(host, autologin, autoname)
+       char *host;
+       int autologin;
+       char *autoname;
 {
        register int i;
        long time();
 {
        register int i;
        long time();
+       char name[256];
+#ifdef NEWINIT
+       extern char *ptyip;
+       struct init_request request;
+       void nologinproc();
+       register int n;
+#endif /* NEWINIT */
+
+#if    defined(AUTHENTICATION)
+       if (!autoname || !autoname[0])
+               autologin = 0;
+
+       if (autologin < auth_level) {
+               fatal(net, "Authorization failed");
+               exit(1);
+       }
+#endif
 
 #ifndef        NEWINIT
 
 #ifndef        NEWINIT
-# ifdef        CRAY
+# ifdef        PARENT_DOES_UTMP
        utmp_sig_init();
        utmp_sig_init();
-# endif        /* CRAY */
+# endif        /* PARENT_DOES_UTMP */
 
        if ((i = fork()) < 0)
                fatalperror(net, "fork");
        if (i) {
 
        if ((i = fork()) < 0)
                fatalperror(net, "fork");
        if (i) {
-# ifdef        CRAY
+# ifdef PARENT_DOES_UTMP
                /*
                 * Cray parent will create utmp entry for child and send
                 * signal to child to tell when done.  Child waits for signal
                 * before doing anything important.
                 */
                register int pid = i;
                /*
                 * Cray parent will create utmp entry for child and send
                 * signal to child to tell when done.  Child waits for signal
                 * before doing anything important.
                 */
                register int pid = i;
+               void sigjob P((int));
 
                setpgrp();
                utmp_sig_reset();               /* reset handler to default */
 
                setpgrp();
                utmp_sig_reset();               /* reset handler to default */
@@ -864,27 +1339,29 @@ char *host;
                SCPYN(wtmp.ut_user, "LOGIN");
                SCPYN(wtmp.ut_host, host);
                SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
                SCPYN(wtmp.ut_user, "LOGIN");
                SCPYN(wtmp.ut_host, host);
                SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
+#ifndef        __hpux
                SCPYN(wtmp.ut_id, wtmp.ut_line+3);
                SCPYN(wtmp.ut_id, wtmp.ut_line+3);
+#else
+               SCPYN(wtmp.ut_id, wtmp.ut_line+7);
+#endif
                pututline(&wtmp);
                endutent();
                if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
                        (void) write(i, (char *)&wtmp, sizeof(struct utmp));
                        (void) close(i);
                }
                pututline(&wtmp);
                endutent();
                if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
                        (void) write(i, (char *)&wtmp, sizeof(struct utmp));
                        (void) close(i);
                }
+#ifdef CRAY
+               (void) signal(WJSIGNAL, sigjob);
+#endif
                utmp_sig_notify(pid);
                utmp_sig_notify(pid);
-# endif        /* CRAY */
-               (void) close(t);
+# endif        /* PARENT_DOES_UTMP */
        } else {
        } else {
-               start_login(t, host);
+               getptyslave();
+               start_login(host, autologin, autoname);
                /*NOTREACHED*/
        }
 #else  /* NEWINIT */
 
                /*NOTREACHED*/
        }
 #else  /* NEWINIT */
 
-       extern char *ptyip;
-       struct init_request request;
-       void nologinproc();
-       register int n;
-
        /*
         * Init will start up login process if we ask nicely.  We only wait
         * for it to start up and begin normal telnet operation.
        /*
         * Init will start up login process if we ask nicely.  We only wait
         * for it to start up and begin normal telnet operation.
@@ -899,7 +1376,7 @@ char *host;
        SCPYN(request.gen_id, gen_id);
        SCPYN(request.tty_id, &line[8]);
        SCPYN(request.host, host);
        SCPYN(request.gen_id, gen_id);
        SCPYN(request.tty_id, &line[8]);
        SCPYN(request.host, host);
-       SCPYN(request.term_type, terminaltype);
+       SCPYN(request.term_type, terminaltype ? terminaltype : "network");
 #if    !defined(UNICOS5)
        request.signal = SIGCLD;
        request.pid = getpid();
 #if    !defined(UNICOS5)
        request.signal = SIGCLD;
        request.pid = getpid();
@@ -942,6 +1419,7 @@ char *host;
 char   *envinit[3];
 extern char **environ;
 
 char   *envinit[3];
 extern char **environ;
 
+       void
 init_env()
 {
        extern char *getenv();
 init_env()
 {
        extern char *getenv();
@@ -950,7 +1428,7 @@ init_env()
        envp = envinit;
        if (*envp = getenv("TZ"))
                *envp++ -= 3;
        envp = envinit;
        if (*envp = getenv("TZ"))
                *envp++ -= 3;
-#ifdef CRAY
+#if    defined(CRAY) || defined(__hpux)
        else
                *envp++ = "TZ=GMT0";
 #endif
        else
                *envp++ = "TZ=GMT0";
 #endif
@@ -958,104 +1436,80 @@ init_env()
        environ = envinit;
 }
 
        environ = envinit;
 }
 
-#ifdef CRAY
-/*
- * These are environment variable that we
- * don't put on the argument line.
- */
-char *invalid[] = {
-       "USER=",        /* Set up by login */
-       "HOME=",        /* Set up by login */
-       "LOGNAME=",     /* Set up by login */
-       "TMPDIR=",      /* Set up by login */
-       "SHELL=",       /* Set up by login */
-       "PATH=",        /* Set up by login */
-       "MAIL=",        /* Set up by login */
-       "TZ=",          /* Login gets it from the environment */
-       "TERM=",        /* Login gets it from the environment */
-       0
-};
-#endif
-
 #ifndef        NEWINIT
 
 /*
 #ifndef        NEWINIT
 
 /*
- * start_login(t, host)
+ * start_login(host)
  *
  * Assuming that we are now running as a child processes, this
  * function will turn us into the login process.
  */
 
  *
  * Assuming that we are now running as a child processes, this
  * function will turn us into the login process.
  */
 
-start_login(t, host)
-int t;
-char *host;
+       void
+start_login(host, autologin, name)
+       char *host;
+       int autologin;
+       char *name;
 {
        register char *cp;
        register char **argv;
        char **addarg();
 {
        register char *cp;
        register char **argv;
        char **addarg();
-#ifdef CRAY
-       register char **cpp, **cpp2;
-       utmp_sig_wait();
-# ifndef TCVHUP
-       setpgrp();
-# endif
-       t = open(line, 2);      /* open ttyp */
-       if (t < 0)
-               fatalperror(net, line);
-# ifdef        TCVHUP
-       /*
-        * Hangup anybody else using this ttyp, then reopen it for
-        * ourselves.
-        */
-       (void) chown(line, 0, 0);
-       (void) chmod(line, 0600);
-       (void) signal(SIGHUP, SIG_IGN);
-       (void) ioctl(t, TCVHUP, (char *)0);
-       (void) signal(SIGHUP, SIG_DFL);
-       setpgrp();
-       i = open(line, 2);
-       if (i < 0)
-               fatalperror(net, line);
-       (void) close(t);
-       t = i;
-# endif        /* TCVHUP */
-       /*
-        * set ttyp modes as we like them to be
-        */
-       init_termbuf();
-       termbuf.c_oflag = OPOST|ONLCR|TAB3;
-       termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
-       termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
-       termbuf.c_cflag = EXTB|HUPCL|CS8;
-       set_termbuf();
-#endif /* CRAY */
+#ifdef UTMPX
+       register int pid = getpid();
+       struct utmpx utmpx;
+#endif
+#ifdef __svr4__
+       char *term;
+       char termbuf[64];
+#endif
 
 
+#ifdef UTMPX
        /*
        /*
-        * set up standard paths before forking to login
+        * Create utmp entry for child
         */
         */
-#if BSD > 43
-       if (login_tty(t) == -1)
-               fatalperror(net, "login_tty");
-#else
-       (void) dup2(t, 0);
-       (void) dup2(t, 1);
-       (void) dup2(t, 2);
-       (void) close(t);
+
+       bzero(&utmpx, sizeof(utmpx));
+       SCPYN(utmpx.ut_user, ".telnet");
+       SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
+       utmpx.ut_pid = pid;
+       utmpx.ut_id[0] = 't';
+       utmpx.ut_id[1] = 'n';
+       utmpx.ut_id[2] = SC_WILDC;
+       utmpx.ut_id[3] = SC_WILDC;
+       utmpx.ut_type = LOGIN_PROCESS;
+       (void) time(&utmpx.ut_tv.tv_sec);
+       if (makeutx(&utmpx) == NULL)
+               fatal(net, "makeutx failed");
 #endif
 #endif
-       if (net > 2)
-               (void) close(net);
-       if (pty > 2)
-               (void) close(pty);
+
        /*
         * -h : pass on name of host.
         *              WARNING:  -h is accepted by login if and only if
         *                      getuid() == 0.
         * -p : don't clobber the environment (so terminal type stays set).
        /*
         * -h : pass on name of host.
         *              WARNING:  -h is accepted by login if and only if
         *                      getuid() == 0.
         * -p : don't clobber the environment (so terminal type stays set).
+        *
+        * -f : force this login, he has already been authenticated
         */
        argv = addarg(0, "login");
         */
        argv = addarg(0, "login");
+#if    !defined(NO_LOGIN_H)
        argv = addarg(argv, "-h");
        argv = addarg(argv, host);
        argv = addarg(argv, "-h");
        argv = addarg(argv, host);
-#if    !defined(CRAY) && !defined(NO_LOGIN_P)
+#endif
+#ifdef __svr4__
+       /*
+        * SVR4 version of -h takes TERM= as second arg, or -
+        */
+       term = getenv("TERM");
+       if (term == NULL || term[0] == 0) {
+               term = "-";
+       } else {
+               strcpy(termbuf, "TERM=");
+               strncat(termbuf, term, sizeof(termbuf) - 6);
+               term = termbuf;
+       }
+       argv = addarg(argv, term);
+#endif
+#if    !defined(NO_LOGIN_P)
        argv = addarg(argv, "-p");
 #endif
 #ifdef BFTPDAEMON
        argv = addarg(argv, "-p");
 #endif
 #ifdef BFTPDAEMON
@@ -1067,21 +1521,45 @@ char *host;
                argv = addarg(argv, "-e");
                argv = addarg(argv, BFTPPATH);
        } else 
                argv = addarg(argv, "-e");
                argv = addarg(argv, BFTPPATH);
        } else 
+#endif
+#if    defined (SecurID)
+       /*
+        * don't worry about the -f that might get sent.
+        * A -s is supposed to override it anyhow.
+        */
+       if (require_SecurID)
+               argv = addarg(argv, "-s");
+#endif
+#if    defined (AUTHENTICATION)
+       if (auth_level >= 0 && autologin == AUTH_VALID) {
+# if   !defined(NO_LOGIN_F)
+               argv = addarg(argv, "-f");
+# endif
+               argv = addarg(argv, name);
+       } else
 #endif
        if (getenv("USER")) {
                argv = addarg(argv, getenv("USER"));
 #endif
        if (getenv("USER")) {
                argv = addarg(argv, getenv("USER"));
-       }
-#ifdef CRAY
-       for (cpp = environ; *cpp; cpp++) {
-               for (cpp2 = invalid; *cpp2; cpp2++)
-                       if (strncmp(*cpp2, *cpp, strlen(*cpp2)) == 0)
-                               break;
-               if (*cpp2)
-                       continue;
-               argv = addarg(argv, *cpp);
-       }
+#if    (defined(CRAY) || defined(__hpux)) && defined(NO_LOGIN_P)
+               {
+                       register char **cpp;
+                       for (cpp = environ; *cpp; cpp++)
+                               argv = addarg(argv, *cpp);
+               }
 #endif
 #endif
-
+               /*
+                * Assume that login will set the USER variable
+                * correctly.  For SysV systems, this means that
+                * USER will no longer be set, just LOGNAME by
+                * login.  (The problem is that if the auto-login
+                * fails, and the user then specifies a different
+                * account name, he can get logged in with both
+                * LOGNAME and USER in his environment, but the
+                * USER value will be wrong.
+                */
+               unsetenv("USER");
+       }
+       closelog();
        execv(_PATH_LOGIN, argv);
 
        syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
        execv(_PATH_LOGIN, argv);
 
        syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
@@ -1089,13 +1567,12 @@ char *host;
        /*NOTREACHED*/
 }
 
        /*NOTREACHED*/
 }
 
-char **
+       char **
 addarg(argv, val)
 addarg(argv, val)
-register char **argv;
-register char *val;
+       register char **argv;
+       register char *val;
 {
        register char **cpp;
 {
        register char **cpp;
-       char *malloc();
 
        if (argv == NULL) {
                /*
 
        if (argv == NULL) {
                /*
@@ -1122,7 +1599,7 @@ register char *val;
        *cpp = 0;
        return(argv);
 }
        *cpp = 0;
        return(argv);
 }
-#endif NEWINIT
+#endif /* NEWINIT */
 
 /*
  * cleanup()
 
 /*
  * cleanup()
@@ -1130,11 +1607,13 @@ register char *val;
  * This is the routine to call when we are all through, to
  * clean up anything that needs to be cleaned up.
  */
  * This is the routine to call when we are all through, to
  * clean up anything that needs to be cleaned up.
  */
-cleanup()
+       /* ARGSUSED */
+       void
+cleanup(sig)
+       int sig;
 {
 {
-
-#ifndef        CRAY
-# if BSD > 43
+#ifndef        PARENT_DOES_UTMP
+# if (BSD > 43) || defined(convex)
        char *p;
 
        p = line + sizeof("/dev/") - 1;
        char *p;
 
        p = line + sizeof("/dev/") - 1;
@@ -1145,24 +1624,70 @@ cleanup()
        *p = 'p';
        (void)chmod(line, 0666);
        (void)chown(line, 0, 0);
        *p = 'p';
        (void)chmod(line, 0666);
        (void)chown(line, 0, 0);
+       (void) shutdown(net, 2);
+       exit(1);
 # else
 # else
+       void rmut();
+
        rmut();
        vhangup();      /* XXX */
        rmut();
        vhangup();      /* XXX */
-# endif
        (void) shutdown(net, 2);
        (void) shutdown(net, 2);
-#else  /* CRAY */
-# ifndef NEWINIT
-       rmut(line);
+       exit(1);
+# endif
+#else  /* PARENT_DOES_UTMP */
+# ifdef        NEWINIT
        (void) shutdown(net, 2);
        (void) shutdown(net, 2);
-       kill(0, SIGHUP);
+       exit(1);
 # else /* NEWINIT */
 # else /* NEWINIT */
+#  ifdef CRAY
+       static int incleanup = 0;
+       register int t;
+
+       /*
+        * 1: Pick up the zombie, if we are being called
+        *    as the signal handler.
+        * 2: If we are a nested cleanup(), return.
+        * 3: Try to clean up TMPDIR.
+        * 4: Fill in utmp with shutdown of process.
+        * 5: Close down the network and pty connections.
+        * 6: Finish up the TMPDIR cleanup, if needed.
+        */
+       if (sig == SIGCHLD)
+               while (waitpid(-1, 0, WNOHANG) > 0)
+                       ;       /* VOID */
+       t = sigblock(sigmask(SIGCHLD));
+       if (incleanup) {
+               sigsetmask(t);
+               return;
+       }
+       incleanup = 1;
+       sigsetmask(t);
+       if (secflag) {
+               /*
+                *      We need to set ourselves back to a null
+                *      label to clean up.
+                */
+
+               setulvl(sysv.sy_minlvl);
+               setucmp((long)0);
+       }
+
+       t = cleantmp(&wtmp);
+       setutent();     /* just to make sure */
+#  endif /* CRAY */
+       rmut(line);
+       close(pty);
        (void) shutdown(net, 2);
        (void) shutdown(net, 2);
-# endif        /* NEWINT */
-#endif /* CRAY */
+#  ifdef CRAY
+       if (t == 0)
+               cleantmp(&wtmp);
+#  endif /* CRAY */
        exit(1);
        exit(1);
+# endif        /* NEWINT */
+#endif /* PARENT_DOES_UTMP */
 }
 
 }
 
-#if    defined(CRAY) && !defined(NEWINIT)
+#if defined(PARENT_DOES_UTMP) && !defined(NEWINIT)
 /*
  * _utmp_sig_rcv
  * utmp_sig_init
 /*
  * _utmp_sig_rcv
  * utmp_sig_init
@@ -1176,14 +1701,15 @@ cleanup()
 static int caught=0;           /* NZ when signal intercepted */
 static void (*func)();         /* address of previous handler */
 
 static int caught=0;           /* NZ when signal intercepted */
 static void (*func)();         /* address of previous handler */
 
-void
+       void
 _utmp_sig_rcv(sig)
 _utmp_sig_rcv(sig)
-int sig;
+       int sig;
 {
        caught = 1;
        (void) signal(SIGUSR1, func);
 }
 
 {
        caught = 1;
        (void) signal(SIGUSR1, func);
 }
 
+       void
 utmp_sig_init()
 {
        /*
 utmp_sig_init()
 {
        /*
@@ -1193,11 +1719,18 @@ utmp_sig_init()
                fatalperror(net, "telnetd/signal");
 }
 
                fatalperror(net, "telnetd/signal");
 }
 
+       void
 utmp_sig_reset()
 {
        (void) signal(SIGUSR1, func);   /* reset handler to default */
 }
 
 utmp_sig_reset()
 {
        (void) signal(SIGUSR1, func);   /* reset handler to default */
 }
 
+# ifdef __hpux
+# define sigoff() /* do nothing */
+# define sigon() /* do nothing */
+# endif
+
+       void
 utmp_sig_wait()
 {
        /*
 utmp_sig_wait()
 {
        /*
@@ -1211,11 +1744,132 @@ utmp_sig_wait()
        sigon();                /* turn on signals again */
 }
 
        sigon();                /* turn on signals again */
 }
 
+       void
 utmp_sig_notify(pid)
 {
        kill(pid, SIGUSR1);
 }
 utmp_sig_notify(pid)
 {
        kill(pid, SIGUSR1);
 }
-#endif /* defined(CRAY) && !defined(NEWINIT) */
+
+# ifdef CRAY
+static int gotsigjob = 0;
+
+       /*ARGSUSED*/
+       void
+sigjob(sig)
+       int sig;
+{
+       register int jid;
+       register struct jobtemp *jp;
+
+       while ((jid = waitjob(NULL)) != -1) {
+               if (jid == 0) {
+                       return;
+               }
+               gotsigjob++;
+               jobend(jid, NULL, NULL);
+       }
+}
+
+/*
+ * Clean up the TMPDIR that login created.
+ * The first time this is called we pick up the info
+ * from the utmp.  If the job has already gone away,
+ * then we'll clean up and be done.  If not, then
+ * when this is called the second time it will wait
+ * for the signal that the job is done.
+ */
+       int
+cleantmp(wtp)
+       register struct utmp *wtp;
+{
+       struct utmp *utp;
+       static int first = 1;
+       register int mask, omask, ret;
+       extern struct utmp *getutid P((struct utmp *));
+
+       mask = sigmask(WJSIGNAL);
+
+       if (first == 0) {
+               omask = sigblock(mask);
+               while (gotsigjob == 0)
+                       sigpause(omask);
+               return(1);
+       }
+       first = 0;
+       setutent();     /* just to make sure */
+
+       utp = getutid(wtp);
+       if (utp == 0) {
+               syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
+               return(-1);
+       }
+       /*
+        * Nothing to clean up if the user shell was never started.
+        */
+       if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
+               return(1);
+
+       /*
+        * Block the WJSIGNAL while we are in jobend().
+        */
+       omask = sigblock(mask);
+       ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
+       sigsetmask(omask);
+       return(ret);
+}
+
+       int
+jobend(jid, path, user)
+       register int jid;
+       register char *path;
+       register char *user;
+{
+       static int saved_jid = 0;
+       static char saved_path[sizeof(wtmp.ut_tpath)+1];
+       static char saved_user[sizeof(wtmp.ut_user)+1];
+
+       if (path) {
+               strncpy(saved_path, path, sizeof(wtmp.ut_tpath));
+               strncpy(saved_user, user, sizeof(wtmp.ut_user));
+               saved_path[sizeof(saved_path)] = '\0';
+               saved_user[sizeof(saved_user)] = '\0';
+       }
+       if (saved_jid == 0) {
+               saved_jid = jid;
+               return(0);
+       }
+       cleantmpdir(jid, saved_path, saved_user);
+       return(1);
+}
+
+/*
+ * Fork a child process to clean up the TMPDIR
+ */
+cleantmpdir(jid, tpath, user)
+       register int jid;
+       register char *tpath;
+       register char *user;
+{
+       switch(fork()) {
+       case -1:
+               syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
+                                                       tpath);
+               break;
+       case 0:
+               execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, 0);
+               syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
+                                                       tpath, CLEANTMPCMD);
+               exit(1);
+       default:
+               /*
+                * Forget about child.  We will exit, and
+                * /etc/init will pick it up.
+                */
+               break;
+       }
+}
+# endif /* CRAY */
+#endif /* defined(PARENT_DOES_UTMP) && !defined(NEWINIT) */
 
 /*
  * rmut()
 
 /*
  * rmut()
@@ -1224,7 +1878,37 @@ utmp_sig_notify(pid)
  * remove the utmp entry for this person.
  */
 
  * remove the utmp entry for this person.
  */
 
-#if    !defined(CRAY) && BSD <= 43
+#ifdef UTMPX
+rmut()
+{
+       register f;
+       int found = 0;
+       struct utmp *u, *utmp;
+       int nutmp;
+       struct stat statbf;
+
+       struct utmpx *utxp, utmpx;
+
+       /*
+        * This updates the utmpx and utmp entries and make a wtmp/x entry
+        */
+
+       SCPYN(utmpx.ut_line, line + sizeof("/dev/") - 1);
+       utxp = getutxline(&utmpx);
+       if (utxp) {
+               utxp->ut_type = DEAD_PROCESS;
+               utxp->ut_exit.e_termination = 0;
+               utxp->ut_exit.e_exit = 0;
+               (void) time(&utmpx.ut_tv.tv_sec);
+               utmpx.ut_tv.tv_usec = 0;
+               modutx(utxp);
+       }
+       endutxent();
+}  /* end of rmut */
+#endif
+
+#if    !defined(UTMPX) && !(defined(CRAY) || defined(__hpux)) && BSD <= 43
+       void
 rmut()
 {
        register f;
 rmut()
 {
        register f;
@@ -1232,9 +1916,6 @@ rmut()
        struct utmp *u, *utmp;
        int nutmp;
        struct stat statbf;
        struct utmp *u, *utmp;
        int nutmp;
        struct stat statbf;
-       char *malloc();
-       long time();
-       off_t lseek();
 
        f = open(utmpf, O_RDWR);
        if (f >= 0) {
 
        f = open(utmpf, O_RDWR);
        if (f >= 0) {
@@ -1278,3 +1959,42 @@ rmut()
        (void) chown(line, 0, 0);
 }  /* end of rmut */
 #endif /* CRAY */
        (void) chown(line, 0, 0);
 }  /* end of rmut */
 #endif /* CRAY */
+
+#ifdef __hpux
+rmut (line)
+char *line;
+{
+       struct utmp utmp;
+       struct utmp *utptr;
+       int fd;                 /* for /etc/wtmp */
+
+       utmp.ut_type = USER_PROCESS;
+       (void) strncpy(utmp.ut_id, line+12, sizeof(utmp.ut_id));
+       (void) setutent();
+       utptr = getutid(&utmp);
+       /* write it out only if it exists */
+       if (utptr) {
+               utptr->ut_type = DEAD_PROCESS;
+               utptr->ut_time = time((long *) 0);
+               (void) pututline(utptr);
+               /* set wtmp entry if wtmp file exists */
+               if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
+                       (void) write(fd, utptr, sizeof(utmp));
+                       (void) close(fd);
+               }
+       }
+       (void) endutent();
+
+       (void) chmod(line, 0666);
+       (void) chown(line, 0, 0);
+       line[14] = line[13];
+       line[13] = line[12];
+       line[8] = 'm';
+       line[9] = '/';
+       line[10] = 'p';
+       line[11] = 't';
+       line[12] = 'y';
+       (void) chmod(line, 0666);
+       (void) chown(line, 0, 0);
+}
+#endif