BSD 4_4_Lite2 release
[unix-history] / usr / src / libexec / telnetd / sys_term.c
index 9aa99d5..58d2e98 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.4 (Berkeley) 5/30/95";
 #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>
+struct utmpx wtmp;
+# else
+# include <utmp.h>
 struct utmp wtmp;
 struct utmp wtmp;
+# endif /* UTMPX */
 
 
-# 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 (UNICOS_LVL == '7.0') || (UNICOS_LVL == '7.1')
+#   define UNICOS7x
+#  endif
+
+#  ifdef UNICOS7x
+#include <sys/sysv.h>
+#include <sys/secstat.h>
+extern int secflag;
+extern struct sysv sysv;
+#  endif /* UNICOS7x */
 # 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 +127,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
 #  else
-#   define TCSETA TIOCSETAW
-#   define TCGETA TIOCGETA
+#   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
 #  endif
-# endif /* 4.4BSD */
+#  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
+#   define     cfsetispeed(tp, val)    (tp)->c_cflag &= ~CBAUD; \
+                                       (tp)->c_cflag |= (val)
+#   define     cfgetispeed(tp)         ((tp)->c_cflag & CBAUD)
+#  endif
+# 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 +182,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,42 +193,54 @@ 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);
-       bcopy(cp, (char *)&termbuf, len);
+       memmove((char *)&termbuf, cp, len);
        termbuf2 = termbuf;
 }
 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
 
        termbuf2 = termbuf;
 }
 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
 
+       void
 set_termbuf()
 {
        /*
         * Only make the necessary changes.
         */
 #ifndef        USE_TERMIO
 set_termbuf()
 {
        /*
         * Only make the necessary changes.
         */
 #ifndef        USE_TERMIO
-       if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
-               (void) ioctl(pty, TIOCSETP, (char *)&termbuf.sg);
-       if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
+       if (memcmp((char *)&termbuf.sg, (char *)&termbuf2.sg,
+                                                       sizeof(termbuf.sg)))
+               (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg);
+       if (memcmp((char *)&termbuf.tc, (char *)&termbuf2.tc,
+                                                       sizeof(termbuf.tc)))
                (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
                (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
-       if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
+       if (memcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
                                                        sizeof(termbuf.ltc)))
                (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
        if (termbuf.lflags != termbuf2.lflags)
                (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
 #else  /* USE_TERMIO */
                                                        sizeof(termbuf.ltc)))
                (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
        if (termbuf.lflags != termbuf2.lflags)
                (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)
+       if (memcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
+# 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 +259,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 +334,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 +388,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 +410,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 +436,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 +459,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 +578,10 @@ getpty()
                }
        }
 #endif /* CRAY */
                }
        }
 #endif /* CRAY */
+#endif /* STREAMSPTY */
        return(-1);
 }
        return(-1);
 }
+#endif /* convex */
 
 #ifdef LINEMODE
 /*
 
 #ifdef LINEMODE
 /*
@@ -422,40 +605,50 @@ 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 */
 }
+#endif /* LINEMODE */
 
 
+       int
 tty_isecho()
 {
 #ifndef USE_TERMIO
 tty_isecho()
 {
 #ifndef USE_TERMIO
@@ -464,9 +657,34 @@ tty_isecho()
        return (termbuf.c_lflag & ECHO);
 #endif
 }
        return (termbuf.c_lflag & ECHO);
 #endif
 }
-#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)
@@ -481,7 +699,7 @@ tty_setecho(on)
 #endif
 }
 
 #endif
 }
 
-#if    defined(LINEMODE) && defined(KLUDGELINEMODE)
+       int
 tty_israw()
 {
 #ifndef USE_TERMIO
 tty_israw()
 {
 #ifndef USE_TERMIO
@@ -490,9 +708,28 @@ tty_israw()
        return(!(termbuf.c_lflag & ICANON));
 #endif
 }
        return(!(termbuf.c_lflag & ICANON));
 #endif
 }
-#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */
 
 
+#if    defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
+       int
+tty_setraw(on)
+{
+#  ifndef USE_TERMIO
+       if (on)
+               termbuf.sg.sg_flags |= RAW;
+       else
+               termbuf.sg.sg_flags &= ~RAW;
+#  else
+       if (on)
+               termbuf.c_lflag &= ~ICANON;
+       else
+               termbuf.c_lflag |= ICANON;
+#  endif
+}
+#endif
+
+       void
 tty_binaryin(on)
 tty_binaryin(on)
+       int on;
 {
 #ifndef        USE_TERMIO
        if (on)
 {
 #ifndef        USE_TERMIO
        if (on)
@@ -501,14 +738,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 +767,7 @@ tty_binaryout(on)
 #endif
 }
 
 #endif
 }
 
+       int
 tty_isbinaryin()
 {
 #ifndef        USE_TERMIO
 tty_isbinaryin()
 {
 #ifndef        USE_TERMIO
@@ -537,6 +777,7 @@ tty_isbinaryin()
 #endif
 }
 
 #endif
 }
 
+       int
 tty_isbinaryout()
 {
 #ifndef        USE_TERMIO
 tty_isbinaryout()
 {
 #ifndef        USE_TERMIO
@@ -547,6 +788,7 @@ tty_isbinaryout()
 }
 
 #ifdef LINEMODE
 }
 
 #ifdef LINEMODE
+       int
 tty_isediting()
 {
 #ifndef USE_TERMIO
 tty_isediting()
 {
 #ifndef USE_TERMIO
@@ -556,6 +798,7 @@ tty_isediting()
 #endif
 }
 
 #endif
 }
 
+       int
 tty_istrapsig()
 {
 #ifndef USE_TERMIO
 tty_istrapsig()
 {
 #ifndef USE_TERMIO
@@ -565,8 +808,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 +825,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 +841,7 @@ int on;
 }
 #endif /* LINEMODE */
 
 }
 #endif /* LINEMODE */
 
+       int
 tty_issofttab()
 {
 #ifndef        USE_TERMIO
 tty_issofttab()
 {
 #ifndef        USE_TERMIO
@@ -610,8 +856,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 +886,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 +904,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)
@@ -680,6 +929,25 @@ int on;
 #endif
 }
 
 #endif
 }
 
+       int
+tty_iscrnl()
+{
+#ifndef        USE_TERMIO
+       return (termbuf.sg.sg_flags & CRMOD);
+#else
+       return (termbuf.c_iflag & ICRNL);
+#endif
+}
+
+/*
+ * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
+ */
+#if B4800 != 4800
+#define        DECODE_BAUD
+#endif
+
+#ifdef DECODE_BAUD
+
 /*
  * A table of available terminal speeds
  */
 /*
  * A table of available terminal speeds
  */
@@ -687,51 +955,76 @@ struct termspeeds {
        int     speed;
        int     value;
 } termspeeds[] = {
        int     speed;
        int     value;
 } termspeeds[] = {
-       { 0,     B0 },    { 50,    B50 },   { 75,    B75 },
-       { 110,   B110 },  { 134,   B134 },  { 150,   B150 },
-       { 200,   B200 },  { 300,   B300 },  { 600,   B600 },
-       { 1200,  B1200 }, { 1800,  B1800 }, { 2400,  B2400 },
-       { 4800,  B4800 }, { 9600,  B9600 }, { 19200, B9600 },
-       { 38400, B9600 }, { -1,    B9600 }
+       { 0,      B0 },      { 50,    B50 },    { 75,     B75 },
+       { 110,    B110 },    { 134,   B134 },   { 150,    B150 },
+       { 200,    B200 },    { 300,   B300 },   { 600,    B600 },
+       { 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
+       { 4800,   B4800 },
+#ifdef B7200
+       { 7200,  B7200 },
+#endif
+       { 9600,   B9600 },
+#ifdef B14400
+       { 14400,  B14400 },
+#endif
+#ifdef B19200
+       { 19200,  B19200 },
+#endif
+#ifdef B28800
+       { 28800,  B28800 },
+#endif
+#ifdef B38400
+       { 38400,  B38400 },
+#endif
+#ifdef B57600
+       { 57600,  B57600 },
+#endif
+#ifdef B115200
+       { 115200, B115200 },
+#endif
+#ifdef B230400
+       { 230400, B230400 },
+#endif
+       { -1,     0 }
 };
 };
+#endif /* DECODE_BUAD */
 
 
+       void
 tty_tspeed(val)
 tty_tspeed(val)
+       int val;
 {
 {
+#ifdef DECODE_BAUD
        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
+       if (tp->speed == -1)    /* back up to last valid value */
+               --tp;
+       cfsetospeed(&termbuf, tp->value);
+#else  /* DECODE_BUAD */
+       cfsetospeed(&termbuf, val);
+#endif /* DECODE_BUAD */
 }
 
 }
 
+       void
 tty_rspeed(val)
 tty_rspeed(val)
+       int val;
 {
 {
+#ifdef DECODE_BAUD
        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
+       if (tp->speed == -1)    /* back up to last valid value */
+               --tp;
+       cfsetispeed(&termbuf, tp->value);
+#else  /* DECODE_BAUD */
+       cfsetispeed(&termbuf, val);
+#endif /* DECODE_BAUD */
 }
 
 #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 +1032,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 +1065,359 @@ 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) {
+               memset((char *)&ws, 0, 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    defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
+       /*
+        * Leave the pty open so that we can write out the rlogin
+        * protocol for /bin/login, if the authentication works.
+        */
+#else
+       if (pty > 2) {
+               (void) close(pty);
+               pty = -1;
+       }
+#endif
+}
+
+#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;
+#ifdef UNICOS7x
+       struct secstat secbuf;
+#endif /* UNICOS7x */
+
+#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
+#ifdef UNICOS7x
+       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 /* UNICOS7x */
+
+       t = open(line, O_RDWR|O_NOCTTY);
+
+#ifdef UNICOS7x
+       if (secflag) {
+               if (setulvl(sysv.sy_minlvl) < 0)
+                       return(-1);
+               if (setucmp(0) < 0)
+                       return(-1);
+       }
+#endif /* UNICOS7x */
+
+       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);
+
+#ifdef UNICOS7x
+               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 /* UNICOS7x */
+
+               i = open(line, O_RDWR);
+
+#ifdef UNICOS7x
+               if (secflag) {
+                       if (setulvl(sysv.sy_minlvl) < 0)
+                               return(-1);
+                       if (setucmp(0) < 0)
+                               return(-1);
+               }
+#endif /* UNICOS7x */
+
+               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) {
+#ifdef ultrix
+               /*
+                * The setsid() may have failed because we
+                * already have a pgrp == pid.  Zero out
+                * our pgrp and try again...
+                */
+               if ((setpgrp(0, 0) < 0) || (setsid() < 0))
+#endif
+                       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
+       /*
+        * We get our controlling tty assigned as a side-effect
+        * of opening up a tty device.  But on BSD based systems,
+        * this only happens if our process group is zero.  The
+        * setsid() call above may have set our pgrp, so clear
+        * it out before opening the tty...
+        */
+#  ifndef SOLARIS
+       (void) setpgrp(0, 0);
+#  else
+       (void) setpgrp();
+#  endif
+       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 +1430,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(autologin);
+               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 +1467,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 +1510,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 +1519,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,106 +1527,107 @@ 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 */
+       extern char *getenv();
+#ifdef UTMPX
+       register int pid = getpid();
+       struct utmpx utmpx;
+#endif
+#ifdef SOLARIS
+       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);
+
+       memset(&utmpx, 0, 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 (pututxline(&utmpx) == NULL)
+               fatal(net, "pututxline 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");
-       argv = addarg(argv, "-h");
-       argv = addarg(argv, host);
-#if    !defined(CRAY) && !defined(NO_LOGIN_P)
+
+#if    !defined(NO_LOGIN_H)
+
+# if   defined (AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
+       /*
+        * Don't add the "-h host" option if we are going
+        * to be adding the "-r host" option down below...
+        */
+       if ((auth_level < 0) || (autologin != AUTH_VALID))
+# endif
+       {
+               argv = addarg(argv, "-h");
+               argv = addarg(argv, host);
+#ifdef SOLARIS
+               /*
+                * 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
+       }
+#endif
+#if    !defined(NO_LOGIN_P)
        argv = addarg(argv, "-p");
 #endif
        argv = addarg(argv, "-p");
 #endif
+#ifdef LINEMODE
+       /*
+        * Set the environment variable "LINEMODE" to either
+        * "real" or "kludge" if we are operating in either
+        * real or kludge linemode.
+        */
+       if (lmodetype == REAL_LINEMODE)
+               setenv("LINEMODE", "real", 1);
+# ifdef KLUDGELINEMODE
+       else if (lmodetype == KLUDGE_LINEMODE || lmodetype == KLUDGE_OK)
+               setenv("LINEMODE", "kludge", 1);
+# endif
+#endif
 #ifdef BFTPDAEMON
        /*
         * Are we working as the bftp daemon?  If so, then ask login
 #ifdef BFTPDAEMON
        /*
         * Are we working as the bftp daemon?  If so, then ask login
@@ -1066,22 +1636,139 @@ char *host;
        if (bftpd) {
                argv = addarg(argv, "-e");
                argv = addarg(argv, BFTPPATH);
        if (bftpd) {
                argv = addarg(argv, "-e");
                argv = addarg(argv, BFTPPATH);
-       } else 
+       } 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");
+               argv = addarg(argv, name);
+# else
+#  if defined(LOGIN_R)
+               /*
+                * We don't have support for "login -f", but we
+                * can fool /bin/login into thinking that we are
+                * rlogind, and allow us to log in without a
+                * password.  The rlogin protocol expects
+                *      local-user\0remote-user\0term/speed\0
+                */
+
+               if (pty > 2) {
+                       register char *cp;
+                       char speed[128];
+                       int isecho, israw, xpty, len;
+                       extern int def_rspeed;
+#  ifndef LOGIN_HOST
+                       /*
+                        * Tell login that we are coming from "localhost".
+                        * If we passed in the real host name, then the
+                        * user would have to allow .rhost access from
+                        * every machine that they want authenticated
+                        * access to work from, which sort of defeats
+                        * the purpose of an authenticated login...
+                        * So, we tell login that the session is coming
+                        * from "localhost", and the user will only have
+                        * to have "localhost" in their .rhost file.
+                        */
+#                      define LOGIN_HOST "localhost"
+#  endif
+                       argv = addarg(argv, "-r");
+                       argv = addarg(argv, LOGIN_HOST);
+
+                       xpty = pty;
+# ifndef  STREAMSPTY
+                       pty = 0;
+# else
+                       ttyfd = 0;
+# endif
+                       init_termbuf();
+                       isecho = tty_isecho();
+                       israw = tty_israw();
+                       if (isecho || !israw) {
+                               tty_setecho(0);         /* Turn off echo */
+                               tty_setraw(1);          /* Turn on raw */
+                               set_termbuf();
+                       }
+                       len = strlen(name)+1;
+                       write(xpty, name, len);
+                       write(xpty, name, len);
+                       sprintf(speed, "%s/%d", (cp = getenv("TERM")) ? cp : "",
+                               (def_rspeed > 0) ? def_rspeed : 9600);
+                       len = strlen(speed)+1;
+                       write(xpty, speed, len);
+
+                       if (isecho || !israw) {
+                               init_termbuf();
+                               tty_setecho(isecho);
+                               tty_setraw(israw);
+                               set_termbuf();
+                               if (!israw) {
+                                       /*
+                                        * Write a newline to ensure
+                                        * that login will be able to
+                                        * read the line...
+                                        */
+                                       write(xpty, "\n", 1);
+                               }
+                       }
+                       pty = xpty;
+               }
+#  else
+               argv = addarg(argv, name);
+#  endif
+# endif
+       } else
 #endif
        if (getenv("USER")) {
                argv = addarg(argv, getenv("USER"));
 #endif
        if (getenv("USER")) {
                argv = addarg(argv, getenv("USER"));
+#if    defined(LOGIN_ARGS) && defined(NO_LOGIN_P)
+               {
+                       register char **cpp;
+                       for (cpp = environ; *cpp; cpp++)
+                               argv = addarg(argv, *cpp);
+               }
+#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");
        }
        }
-#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);
+#ifdef SOLARIS
+       else {
+               char **p;
+
+               argv = addarg(argv, "");        /* no login name */
+               for (p = environ; *p; p++) {
+                       argv = addarg(argv, *p);
+               }
        }
        }
+#endif /* SOLARIS */
+#if    defined(AUTHENTICATION) && defined(NO_LOGIN_F) && defined(LOGIN_R)
+       if (pty > 2)
+               close(pty);
 #endif
 #endif
-
+       closelog();
+       /*
+        * This sleep(1) is in here so that telnetd can
+        * finish up with the tty.  There's a race condition
+        * the login banner message gets lost...
+        */
+       sleep(1);
        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 +1776,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) {
                /*
@@ -1112,7 +1798,7 @@ register char *val;
        if (cpp == &argv[(int)argv[-1]]) {
                --argv;
                *argv = (char *)((int)(*argv) + 10);
        if (cpp == &argv[(int)argv[-1]]) {
                --argv;
                *argv = (char *)((int)(*argv) + 10);
-               argv = (char **)realloc(argv, (int)(*argv) + 2);
+               argv = (char **)realloc(argv, sizeof(*argv)*((int)(*argv) + 2));
                if (argv == NULL)
                        return(NULL);
                argv++;
                if (argv == NULL)
                        return(NULL);
                argv++;
@@ -1122,7 +1808,7 @@ register char *val;
        *cpp = 0;
        return(argv);
 }
        *cpp = 0;
        return(argv);
 }
-#endif NEWINIT
+#endif /* NEWINIT */
 
 /*
  * cleanup()
 
 /*
  * cleanup()
@@ -1130,11 +1816,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 +1833,82 @@ 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;
+       int child_status; /* status of child process as returned by waitpid */
+       int flags = WNOHANG|WUNTRACED;
+
+       /*
+        * 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, &child_status, flags) > 0)
+                       ;       /* VOID */
+               /* Check if the child process was stopped
+                * rather than exited.  We want cleanup only if
+                * the child has died.
+                */
+               if (WIFSTOPPED(child_status)) {
+                       return;
+               }
+       }
+       t = sigblock(sigmask(SIGCHLD));
+       if (incleanup) {
+               sigsetmask(t);
+               return;
+       }
+       incleanup = 1;
+       sigsetmask(t);
+#ifdef UNICOS7x
+       if (secflag) {
+               /*
+                *      We need to set ourselves back to a null
+                *      label to clean up.
+                */
+
+               setulvl(sysv.sy_minlvl);
+               setucmp((long)0);
+       }
+#endif /* UNICOS7x */
+
+       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 +1922,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 +1940,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 +1965,191 @@ 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);
+       }
+}
+
+/*
+ *     jid_getutid:
+ *             called by jobend() before calling cleantmp()
+ *             to find the correct $TMPDIR to cleanup.
+ */
+
+       struct utmp *
+jid_getutid(jid)
+       int jid;
+{
+       struct utmp *cur = NULL;
+
+       setutent();     /* just to make sure */
+       while (cur = getutent()) {
+               if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
+                       return(cur);
+               }
+       }
+
+       return(0);
+}
+
+/*
+ * 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((const struct utmp *_Id));
+
+
+       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 int pty_saved_jid = 0;
+       static char saved_path[sizeof(wtmp.ut_tpath)+1];
+       static char saved_user[sizeof(wtmp.ut_user)+1];
+
+       /*
+        * this little piece of code comes into play
+        * only when ptyreconnect is used to reconnect
+        * to an previous session.
+        *
+        * this is the only time when the
+        * "saved_jid != jid" code is executed.
+        */
+
+       if ( saved_jid && saved_jid != jid ) {
+               if (!path) {    /* called from signal handler */
+                       pty_saved_jid = jid;
+               } else {
+                       pty_saved_jid = saved_jid;
+               }
+       }
+
+       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);
+       }
+
+       /* if the jid has changed, get the correct entry from the utmp file */
+
+       if ( saved_jid != jid ) {
+               struct utmp *utp = NULL;
+               struct utmp *jid_getutid();
+
+               utp = jid_getutid(pty_saved_jid);
+
+               if (utp == 0) {
+                       syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
+                       return(-1);
+               }
+
+               cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
+               return(1);
+       }
+
+       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 +2158,38 @@ 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
+       void
+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 +2197,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) {
@@ -1245,7 +2207,7 @@ rmut()
                if (statbf.st_size && utmp) {
                        nutmp = read(f, (char *)utmp, (int)statbf.st_size);
                        nutmp /= sizeof(struct utmp);
                if (statbf.st_size && utmp) {
                        nutmp = read(f, (char *)utmp, (int)statbf.st_size);
                        nutmp /= sizeof(struct utmp);
-               
+
                        for (u = utmp ; u < &utmp[nutmp] ; u++) {
                                if (SCMPN(u->ut_line, line+5) ||
                                    u->ut_name[0]==0)
                        for (u = utmp ; u < &utmp[nutmp] ; u++) {
                                if (SCMPN(u->ut_line, line+5) ||
                                    u->ut_name[0]==0)
@@ -1278,3 +2240,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