113e3f4d6SMark Murray /*
213e3f4d6SMark Murray  * Copyright (c) 1989, 1993
313e3f4d6SMark Murray  *	The Regents of the University of California.  All rights reserved.
413e3f4d6SMark Murray  *
513e3f4d6SMark Murray  * Redistribution and use in source and binary forms, with or without
613e3f4d6SMark Murray  * modification, are permitted provided that the following conditions
713e3f4d6SMark Murray  * are met:
813e3f4d6SMark Murray  * 1. Redistributions of source code must retain the above copyright
913e3f4d6SMark Murray  *    notice, this list of conditions and the following disclaimer.
1013e3f4d6SMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
1113e3f4d6SMark Murray  *    notice, this list of conditions and the following disclaimer in the
1213e3f4d6SMark Murray  *    documentation and/or other materials provided with the distribution.
1313e3f4d6SMark Murray  * 3. All advertising materials mentioning features or use of this software
1413e3f4d6SMark Murray  *    must display the following acknowledgement:
1513e3f4d6SMark Murray  *	This product includes software developed by the University of
1613e3f4d6SMark Murray  *	California, Berkeley and its contributors.
1713e3f4d6SMark Murray  * 4. Neither the name of the University nor the names of its contributors
1813e3f4d6SMark Murray  *    may be used to endorse or promote products derived from this software
1913e3f4d6SMark Murray  *    without specific prior written permission.
2013e3f4d6SMark Murray  *
2113e3f4d6SMark Murray  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2213e3f4d6SMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2313e3f4d6SMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2413e3f4d6SMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2513e3f4d6SMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2613e3f4d6SMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2713e3f4d6SMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2813e3f4d6SMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2913e3f4d6SMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3013e3f4d6SMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3113e3f4d6SMark Murray  * SUCH DAMAGE.
3213e3f4d6SMark Murray  */
3313e3f4d6SMark Murray 
3413e3f4d6SMark Murray #include "telnetd.h"
3513e3f4d6SMark Murray 
36c19800e8SDoug Rabson RCSID("$Id$");
3713e3f4d6SMark Murray 
3813e3f4d6SMark Murray #if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H))
3913e3f4d6SMark Murray # define PARENT_DOES_UTMP
4013e3f4d6SMark Murray #endif
4113e3f4d6SMark Murray 
4213e3f4d6SMark Murray #ifdef HAVE_UTMP_H
4313e3f4d6SMark Murray #include <utmp.h>
4413e3f4d6SMark Murray #endif
4513e3f4d6SMark Murray 
4613e3f4d6SMark Murray #ifdef HAVE_UTMPX_H
4713e3f4d6SMark Murray #include <utmpx.h>
4813e3f4d6SMark Murray #endif
4913e3f4d6SMark Murray 
5013e3f4d6SMark Murray #ifdef HAVE_UTMPX_H
5113e3f4d6SMark Murray struct	utmpx wtmp;
5213e3f4d6SMark Murray #elif defined(HAVE_UTMP_H)
5313e3f4d6SMark Murray struct	utmp wtmp;
5413e3f4d6SMark Murray #endif /* HAVE_UTMPX_H */
5513e3f4d6SMark Murray 
5613e3f4d6SMark Murray #ifdef HAVE_STRUCT_UTMP_UT_HOST
5713e3f4d6SMark Murray int	utmp_len = sizeof(wtmp.ut_host);
5813e3f4d6SMark Murray #else
5913e3f4d6SMark Murray int	utmp_len = MaxHostNameLen;
6013e3f4d6SMark Murray #endif
6113e3f4d6SMark Murray 
6213e3f4d6SMark Murray #ifndef UTMP_FILE
6313e3f4d6SMark Murray #ifdef _PATH_UTMP
6413e3f4d6SMark Murray #define UTMP_FILE _PATH_UTMP
6513e3f4d6SMark Murray #else
6613e3f4d6SMark Murray #define UTMP_FILE "/etc/utmp"
6713e3f4d6SMark Murray #endif
6813e3f4d6SMark Murray #endif
6913e3f4d6SMark Murray 
7013e3f4d6SMark Murray /* really, mac os uses wtmpx (or asl) */
7113e3f4d6SMark Murray #ifdef __APPLE__
7213e3f4d6SMark Murray #undef _PATH_WTMP
7313e3f4d6SMark Murray #endif
7413e3f4d6SMark Murray 
7513e3f4d6SMark Murray #if !defined(WTMP_FILE) && defined(_PATH_WTMP)
7613e3f4d6SMark Murray #define WTMP_FILE _PATH_WTMP
7713e3f4d6SMark Murray #endif
7813e3f4d6SMark Murray 
7913e3f4d6SMark Murray #ifndef PARENT_DOES_UTMP
8013e3f4d6SMark Murray #ifdef WTMP_FILE
8113e3f4d6SMark Murray char	wtmpf[] = WTMP_FILE;
8213e3f4d6SMark Murray #else
8313e3f4d6SMark Murray char	wtmpf[]	= "/usr/adm/wtmp";
8413e3f4d6SMark Murray #endif
8513e3f4d6SMark Murray char	utmpf[] = UTMP_FILE;
8613e3f4d6SMark Murray #else /* PARENT_DOES_UTMP */
8713e3f4d6SMark Murray #ifdef WTMP_FILE
8813e3f4d6SMark Murray char	wtmpf[] = WTMP_FILE;
8913e3f4d6SMark Murray #else
9013e3f4d6SMark Murray char	wtmpf[]	= "/etc/wtmp";
9113e3f4d6SMark Murray #endif
9213e3f4d6SMark Murray #endif /* PARENT_DOES_UTMP */
9313e3f4d6SMark Murray 
9413e3f4d6SMark Murray #ifdef HAVE_TMPDIR_H
9513e3f4d6SMark Murray #include <tmpdir.h>
9613e3f4d6SMark Murray #endif	/* CRAY */
9713e3f4d6SMark Murray 
9813e3f4d6SMark Murray #if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
9913e3f4d6SMark Murray #include <sys/tty.h>
10013e3f4d6SMark Murray #endif
10113e3f4d6SMark Murray #ifdef	t_erase
10213e3f4d6SMark Murray #undef	t_erase
10313e3f4d6SMark Murray #undef	t_kill
10413e3f4d6SMark Murray #undef	t_intrc
10513e3f4d6SMark Murray #undef	t_quitc
10613e3f4d6SMark Murray #undef	t_startc
10713e3f4d6SMark Murray #undef	t_stopc
10813e3f4d6SMark Murray #undef	t_eofc
10913e3f4d6SMark Murray #undef	t_brkc
11013e3f4d6SMark Murray #undef	t_suspc
11113e3f4d6SMark Murray #undef	t_dsuspc
11213e3f4d6SMark Murray #undef	t_rprntc
11313e3f4d6SMark Murray #undef	t_flushc
11413e3f4d6SMark Murray #undef	t_werasc
11513e3f4d6SMark Murray #undef	t_lnextc
11613e3f4d6SMark Murray #endif
11713e3f4d6SMark Murray 
11813e3f4d6SMark Murray #ifdef HAVE_TERMIOS_H
11913e3f4d6SMark Murray #include <termios.h>
12013e3f4d6SMark Murray #else
12113e3f4d6SMark Murray #ifdef HAVE_TERMIO_H
12213e3f4d6SMark Murray #include <termio.h>
12313e3f4d6SMark Murray #endif
1244137ff4cSJacques Vidrine #endif
1254137ff4cSJacques Vidrine 
1264137ff4cSJacques Vidrine #ifdef HAVE_UTIL_H
12713e3f4d6SMark Murray #include <util.h>
12813e3f4d6SMark Murray #endif
12913e3f4d6SMark Murray #ifdef HAVE_LIBUTIL_H
13013e3f4d6SMark Murray #include <libutil.h>
13113e3f4d6SMark Murray #endif
13213e3f4d6SMark Murray 
13313e3f4d6SMark Murray # ifndef	TCSANOW
13413e3f4d6SMark Murray #  ifdef TCSETS
13513e3f4d6SMark Murray #   define	TCSANOW		TCSETS
13613e3f4d6SMark Murray #   define	TCSADRAIN	TCSETSW
13713e3f4d6SMark Murray #   define	tcgetattr(f, t)	ioctl(f, TCGETS, (char *)t)
13813e3f4d6SMark Murray #  else
13913e3f4d6SMark Murray #   ifdef TCSETA
14013e3f4d6SMark Murray #    define	TCSANOW		TCSETA
14113e3f4d6SMark Murray #    define	TCSADRAIN	TCSETAW
14213e3f4d6SMark Murray #    define	tcgetattr(f, t)	ioctl(f, TCGETA, (char *)t)
14313e3f4d6SMark Murray #   else
14413e3f4d6SMark Murray #    define	TCSANOW		TIOCSETA
14513e3f4d6SMark Murray #    define	TCSADRAIN	TIOCSETAW
14613e3f4d6SMark Murray #    define	tcgetattr(f, t)	ioctl(f, TIOCGETA, (char *)t)
14713e3f4d6SMark Murray #   endif
14813e3f4d6SMark Murray #  endif
14913e3f4d6SMark Murray #  define	tcsetattr(f, a, t)	ioctl(f, a, t)
15013e3f4d6SMark Murray #  define	cfsetospeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
15113e3f4d6SMark Murray (tp)->c_cflag |= (val)
15213e3f4d6SMark Murray #  define	cfgetospeed(tp)		((tp)->c_cflag & CBAUD)
15313e3f4d6SMark Murray #  ifdef CIBAUD
15413e3f4d6SMark Murray #   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CIBAUD; \
15513e3f4d6SMark Murray      (tp)->c_cflag |= ((val)<<IBSHIFT)
15613e3f4d6SMark Murray #   define	cfgetispeed(tp)		(((tp)->c_cflag & CIBAUD)>>IBSHIFT)
15713e3f4d6SMark Murray #  else
15813e3f4d6SMark Murray #   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
15913e3f4d6SMark Murray      (tp)->c_cflag |= (val)
16013e3f4d6SMark Murray #   define	cfgetispeed(tp)		((tp)->c_cflag & CBAUD)
16113e3f4d6SMark Murray #  endif
16213e3f4d6SMark Murray # endif /* TCSANOW */
16313e3f4d6SMark Murray      struct termios termbuf, termbuf2;	/* pty control structure */
16413e3f4d6SMark Murray # ifdef  STREAMSPTY
16513e3f4d6SMark Murray      static int ttyfd = -1;
16613e3f4d6SMark Murray      int really_stream = 0;
16713e3f4d6SMark Murray # else
16813e3f4d6SMark Murray #define really_stream 0
16913e3f4d6SMark Murray # endif
17013e3f4d6SMark Murray 
17113e3f4d6SMark Murray      const char *new_login = _PATH_LOGIN;
17213e3f4d6SMark Murray 
17313e3f4d6SMark Murray /*
17413e3f4d6SMark Murray  * init_termbuf()
17513e3f4d6SMark Murray  * copy_termbuf(cp)
17613e3f4d6SMark Murray  * set_termbuf()
17713e3f4d6SMark Murray  *
17813e3f4d6SMark Murray  * These three routines are used to get and set the "termbuf" structure
17913e3f4d6SMark Murray  * to and from the kernel.  init_termbuf() gets the current settings.
18013e3f4d6SMark Murray  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
18113e3f4d6SMark Murray  * set_termbuf() writes the structure into the kernel.
18213e3f4d6SMark Murray  */
18313e3f4d6SMark Murray 
18413e3f4d6SMark Murray      void
init_termbuf(void)18513e3f4d6SMark Murray      init_termbuf(void)
18613e3f4d6SMark Murray {
18713e3f4d6SMark Murray # ifdef  STREAMSPTY
18813e3f4d6SMark Murray     if (really_stream)
18913e3f4d6SMark Murray 	tcgetattr(ttyfd, &termbuf);
19013e3f4d6SMark Murray     else
19113e3f4d6SMark Murray # endif
19213e3f4d6SMark Murray 	tcgetattr(ourpty, &termbuf);
19313e3f4d6SMark Murray     termbuf2 = termbuf;
19413e3f4d6SMark Murray }
195c19800e8SDoug Rabson 
19613e3f4d6SMark Murray void
set_termbuf(void)19713e3f4d6SMark Murray set_termbuf(void)
19813e3f4d6SMark Murray {
19913e3f4d6SMark Murray     /*
20013e3f4d6SMark Murray      * Only make the necessary changes.
20113e3f4d6SMark Murray 	 */
20213e3f4d6SMark Murray     if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) {
203c19800e8SDoug Rabson # ifdef  STREAMSPTY
20413e3f4d6SMark Murray 	if (really_stream)
20513e3f4d6SMark Murray 	    tcsetattr(ttyfd, TCSANOW, &termbuf);
20613e3f4d6SMark Murray 	else
20713e3f4d6SMark Murray # endif
20813e3f4d6SMark Murray 	    tcsetattr(ourpty, TCSANOW, &termbuf);
20913e3f4d6SMark Murray     }
21013e3f4d6SMark Murray }
21113e3f4d6SMark Murray 
21213e3f4d6SMark Murray 
21313e3f4d6SMark Murray /*
21413e3f4d6SMark Murray  * spcset(func, valp, valpp)
21513e3f4d6SMark Murray  *
21613e3f4d6SMark Murray  * This function takes various special characters (func), and
21713e3f4d6SMark Murray  * sets *valp to the current value of that character, and
21813e3f4d6SMark Murray  * *valpp to point to where in the "termbuf" structure that
21913e3f4d6SMark Murray  * value is kept.
22013e3f4d6SMark Murray  *
22113e3f4d6SMark Murray  * It returns the SLC_ level of support for this function.
22213e3f4d6SMark Murray  */
22313e3f4d6SMark Murray 
22413e3f4d6SMark Murray 
22513e3f4d6SMark Murray int
spcset(int func,cc_t * valp,cc_t ** valpp)22613e3f4d6SMark Murray spcset(int func, cc_t *valp, cc_t **valpp)
22713e3f4d6SMark Murray {
22813e3f4d6SMark Murray 
22913e3f4d6SMark Murray #define	setval(a, b)	*valp = termbuf.c_cc[a]; \
23013e3f4d6SMark Murray     *valpp = &termbuf.c_cc[a]; \
23113e3f4d6SMark Murray 				   return(b);
23213e3f4d6SMark Murray #define	defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
23313e3f4d6SMark Murray 
23413e3f4d6SMark Murray     switch(func) {
23513e3f4d6SMark Murray     case SLC_EOF:
23613e3f4d6SMark Murray 	setval(VEOF, SLC_VARIABLE);
23713e3f4d6SMark Murray     case SLC_EC:
23813e3f4d6SMark Murray 	setval(VERASE, SLC_VARIABLE);
23913e3f4d6SMark Murray     case SLC_EL:
24013e3f4d6SMark Murray 	setval(VKILL, SLC_VARIABLE);
24113e3f4d6SMark Murray     case SLC_IP:
24213e3f4d6SMark Murray 	setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
24313e3f4d6SMark Murray     case SLC_ABORT:
24413e3f4d6SMark Murray 	setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
24513e3f4d6SMark Murray     case SLC_XON:
24613e3f4d6SMark Murray #ifdef	VSTART
24713e3f4d6SMark Murray 	setval(VSTART, SLC_VARIABLE);
24813e3f4d6SMark Murray #else
24913e3f4d6SMark Murray 	defval(0x13);
25013e3f4d6SMark Murray #endif
25113e3f4d6SMark Murray     case SLC_XOFF:
25213e3f4d6SMark Murray #ifdef	VSTOP
25313e3f4d6SMark Murray 	setval(VSTOP, SLC_VARIABLE);
25413e3f4d6SMark Murray #else
25513e3f4d6SMark Murray 	defval(0x11);
25613e3f4d6SMark Murray #endif
25713e3f4d6SMark Murray     case SLC_EW:
25813e3f4d6SMark Murray #ifdef	VWERASE
25913e3f4d6SMark Murray 	setval(VWERASE, SLC_VARIABLE);
26013e3f4d6SMark Murray #else
26113e3f4d6SMark Murray 	defval(0);
26213e3f4d6SMark Murray #endif
26313e3f4d6SMark Murray     case SLC_RP:
26413e3f4d6SMark Murray #ifdef	VREPRINT
26513e3f4d6SMark Murray 	setval(VREPRINT, SLC_VARIABLE);
26613e3f4d6SMark Murray #else
26713e3f4d6SMark Murray 	defval(0);
26813e3f4d6SMark Murray #endif
26913e3f4d6SMark Murray     case SLC_LNEXT:
27013e3f4d6SMark Murray #ifdef	VLNEXT
27113e3f4d6SMark Murray 	setval(VLNEXT, SLC_VARIABLE);
27213e3f4d6SMark Murray #else
27313e3f4d6SMark Murray 	defval(0);
27413e3f4d6SMark Murray #endif
27513e3f4d6SMark Murray     case SLC_AO:
27613e3f4d6SMark Murray #if	!defined(VDISCARD) && defined(VFLUSHO)
27713e3f4d6SMark Murray # define VDISCARD VFLUSHO
27813e3f4d6SMark Murray #endif
27913e3f4d6SMark Murray #ifdef	VDISCARD
28013e3f4d6SMark Murray 	setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
28113e3f4d6SMark Murray #else
28213e3f4d6SMark Murray 	defval(0);
28313e3f4d6SMark Murray #endif
28413e3f4d6SMark Murray     case SLC_SUSP:
28513e3f4d6SMark Murray #ifdef	VSUSP
28613e3f4d6SMark Murray 	setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
28713e3f4d6SMark Murray #else
28813e3f4d6SMark Murray 	defval(0);
28913e3f4d6SMark Murray #endif
29013e3f4d6SMark Murray #ifdef	VEOL
29113e3f4d6SMark Murray     case SLC_FORW1:
29213e3f4d6SMark Murray 	setval(VEOL, SLC_VARIABLE);
29313e3f4d6SMark Murray #endif
29413e3f4d6SMark Murray #ifdef	VEOL2
29513e3f4d6SMark Murray     case SLC_FORW2:
29613e3f4d6SMark Murray 	setval(VEOL2, SLC_VARIABLE);
29713e3f4d6SMark Murray #endif
29813e3f4d6SMark Murray     case SLC_AYT:
29913e3f4d6SMark Murray #ifdef	VSTATUS
30013e3f4d6SMark Murray 	setval(VSTATUS, SLC_VARIABLE);
30113e3f4d6SMark Murray #else
30213e3f4d6SMark Murray 	defval(0);
30313e3f4d6SMark Murray #endif
30413e3f4d6SMark Murray 
30513e3f4d6SMark Murray     case SLC_BRK:
30613e3f4d6SMark Murray     case SLC_SYNCH:
30713e3f4d6SMark Murray     case SLC_EOR:
30813e3f4d6SMark Murray 	defval(0);
30913e3f4d6SMark Murray 
31013e3f4d6SMark Murray     default:
31113e3f4d6SMark Murray 	*valp = 0;
31213e3f4d6SMark Murray 	*valpp = 0;
31313e3f4d6SMark Murray 	return(SLC_NOSUPPORT);
31413e3f4d6SMark Murray     }
31513e3f4d6SMark Murray }
31613e3f4d6SMark Murray 
31713e3f4d6SMark Murray #ifdef _CRAY
31813e3f4d6SMark Murray /*
31913e3f4d6SMark Murray  * getnpty()
32013e3f4d6SMark Murray  *
32113e3f4d6SMark Murray  * Return the number of pty's configured into the system.
32213e3f4d6SMark Murray  */
32313e3f4d6SMark Murray int
getnpty()32413e3f4d6SMark Murray getnpty()
32513e3f4d6SMark Murray {
32613e3f4d6SMark Murray #ifdef _SC_CRAY_NPTY
32713e3f4d6SMark Murray     int numptys;
32813e3f4d6SMark Murray 
32913e3f4d6SMark Murray     if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
33013e3f4d6SMark Murray 	return numptys;
33113e3f4d6SMark Murray     else
33213e3f4d6SMark Murray #endif /* _SC_CRAY_NPTY */
33313e3f4d6SMark Murray 	return 128;
33413e3f4d6SMark Murray }
33513e3f4d6SMark Murray #endif /* CRAY */
33613e3f4d6SMark Murray 
33713e3f4d6SMark Murray /*
33813e3f4d6SMark Murray  * getpty()
339c19800e8SDoug Rabson  *
340c19800e8SDoug Rabson  * Allocate a pty.  As a side effect, the external character
34113e3f4d6SMark Murray  * array "line" contains the name of the slave side.
34213e3f4d6SMark Murray  *
34313e3f4d6SMark Murray  * Returns the file descriptor of the opened pty.
34413e3f4d6SMark Murray  */
34513e3f4d6SMark Murray 
34613e3f4d6SMark Murray static int ptyslavefd = -1;
34713e3f4d6SMark Murray 
34813e3f4d6SMark Murray static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
34913e3f4d6SMark Murray char *line = Xline;
35013e3f4d6SMark Murray 
35113e3f4d6SMark Murray #ifdef	_CRAY
35213e3f4d6SMark Murray char myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
35313e3f4d6SMark Murray #endif	/* CRAY */
35413e3f4d6SMark Murray 
35513e3f4d6SMark Murray #if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
ptsname(int fd)35613e3f4d6SMark Murray static char *ptsname(int fd)
35713e3f4d6SMark Murray {
35813e3f4d6SMark Murray #ifdef HAVE_TTYNAME
35913e3f4d6SMark Murray     return ttyname(fd);
36013e3f4d6SMark Murray #else
361c19800e8SDoug Rabson     return NULL;
362c19800e8SDoug Rabson #endif
36313e3f4d6SMark Murray }
36413e3f4d6SMark Murray #endif
36513e3f4d6SMark Murray 
getpty(int * ptynum)366c19800e8SDoug Rabson int getpty(int *ptynum)
36713e3f4d6SMark Murray {
36813e3f4d6SMark Murray #if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */
369c19800e8SDoug Rabson     {
370c19800e8SDoug Rabson 	int master;
37113e3f4d6SMark Murray 	int slave;
372c19800e8SDoug Rabson 	if(openpty(&master, &slave, line, 0, 0) == 0){
373c19800e8SDoug Rabson 	    ptyslavefd = slave;
37413e3f4d6SMark Murray 	    return master;
37513e3f4d6SMark Murray 	}
37613e3f4d6SMark Murray     }
37713e3f4d6SMark Murray #endif /* HAVE_OPENPTY .... */
37813e3f4d6SMark Murray #ifdef HAVE__GETPTY
37913e3f4d6SMark Murray     {
38013e3f4d6SMark Murray 	int master;
381c19800e8SDoug Rabson 	char *p;
382c19800e8SDoug Rabson 	p = _getpty(&master, O_RDWR, 0600, 1);
38313e3f4d6SMark Murray 	if(p == NULL)
384c19800e8SDoug Rabson 	    return -1;
38513e3f4d6SMark Murray 	strlcpy(line, p, sizeof(Xline));
38613e3f4d6SMark Murray 	return master;
38713e3f4d6SMark Murray     }
38813e3f4d6SMark Murray #endif
389c19800e8SDoug Rabson 
39013e3f4d6SMark Murray #ifdef	STREAMSPTY
39113e3f4d6SMark Murray     {
39213e3f4d6SMark Murray 	char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
39313e3f4d6SMark Murray 			  "/dev/ptym/clone", 0 };
39413e3f4d6SMark Murray 
39513e3f4d6SMark Murray 	char **q;
39613e3f4d6SMark Murray 	int p;
39713e3f4d6SMark Murray 	for(q=clone; *q; q++){
39813e3f4d6SMark Murray 	    p=open(*q, O_RDWR);
39913e3f4d6SMark Murray 	    if(p >= 0){
40013e3f4d6SMark Murray #ifdef HAVE_GRANTPT
40113e3f4d6SMark Murray 		grantpt(p);
40213e3f4d6SMark Murray #endif
40313e3f4d6SMark Murray #ifdef HAVE_UNLOCKPT
404c19800e8SDoug Rabson 		unlockpt(p);
40513e3f4d6SMark Murray #endif
40613e3f4d6SMark Murray 		strlcpy(line, ptsname(p), sizeof(Xline));
407c19800e8SDoug Rabson 		really_stream = 1;
408c19800e8SDoug Rabson 		return p;
409c19800e8SDoug Rabson 	    }
410c19800e8SDoug Rabson 	}
41113e3f4d6SMark Murray     }
41213e3f4d6SMark Murray #endif /* STREAMSPTY */
41313e3f4d6SMark Murray #ifndef _CRAY
41413e3f4d6SMark Murray     {
41513e3f4d6SMark Murray 	int p;
41613e3f4d6SMark Murray 	char *cp, *p1, *p2;
41713e3f4d6SMark Murray 	int i;
41813e3f4d6SMark Murray 
41913e3f4d6SMark Murray #ifndef	__hpux
42013e3f4d6SMark Murray 	snprintf(line, sizeof(Xline), "/dev/ptyXX");
42113e3f4d6SMark Murray 	p1 = &line[8];
42213e3f4d6SMark Murray 	p2 = &line[9];
42313e3f4d6SMark Murray #else
42413e3f4d6SMark Murray 	snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX");
42513e3f4d6SMark Murray 	p1 = &line[13];
42613e3f4d6SMark Murray 	p2 = &line[14];
42713e3f4d6SMark Murray #endif
42813e3f4d6SMark Murray 
42913e3f4d6SMark Murray 
43013e3f4d6SMark Murray 	for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
43113e3f4d6SMark Murray 	    struct stat stb;
43213e3f4d6SMark Murray 
43313e3f4d6SMark Murray 	    *p1 = *cp;
43413e3f4d6SMark Murray 	    *p2 = '0';
43513e3f4d6SMark Murray 	    /*
43613e3f4d6SMark Murray 	     * This stat() check is just to keep us from
43713e3f4d6SMark Murray 	     * looping through all 256 combinations if there
43813e3f4d6SMark Murray 	     * aren't that many ptys available.
439c19800e8SDoug Rabson 	     */
440c19800e8SDoug Rabson 	    if (stat(line, &stb) < 0)
441c19800e8SDoug Rabson 		break;
442c19800e8SDoug Rabson 	    for (i = 0; i < 16; i++) {
44313e3f4d6SMark Murray 		*p2 = "0123456789abcdef"[i];
44413e3f4d6SMark Murray 		p = open(line, O_RDWR);
44513e3f4d6SMark Murray 		if (p > 0) {
44613e3f4d6SMark Murray #if SunOS == 40
44713e3f4d6SMark Murray 		    int dummy;
44813e3f4d6SMark Murray #endif
44913e3f4d6SMark Murray 
45013e3f4d6SMark Murray #ifndef	__hpux
45113e3f4d6SMark Murray 		    line[5] = 't';
45213e3f4d6SMark Murray #else
45313e3f4d6SMark Murray 		    for (p1 = &line[8]; *p1; p1++)
45413e3f4d6SMark Murray 			*p1 = *(p1+1);
45513e3f4d6SMark Murray 		    line[9] = 't';
45613e3f4d6SMark Murray #endif
45713e3f4d6SMark Murray 		    chown(line, 0, 0);
45813e3f4d6SMark Murray 		    chmod(line, 0600);
45913e3f4d6SMark Murray #if SunOS == 40
46013e3f4d6SMark Murray 		    if (ioctl(p, TIOCGPGRP, &dummy) == 0
46113e3f4d6SMark Murray 			|| errno != EIO) {
46213e3f4d6SMark Murray 			chmod(line, 0666);
46313e3f4d6SMark Murray 			close(p);
464c19800e8SDoug Rabson 			line[5] = 'p';
46513e3f4d6SMark Murray 		    } else
466c19800e8SDoug Rabson #endif /* SunOS == 40 */
46713e3f4d6SMark Murray 			return(p);
46813e3f4d6SMark Murray 		}
469c19800e8SDoug Rabson 	    }
47013e3f4d6SMark Murray 	}
47113e3f4d6SMark Murray     }
47213e3f4d6SMark Murray #else	/* CRAY */
47313e3f4d6SMark Murray     {
47413e3f4d6SMark Murray 	extern lowpty, highpty;
47513e3f4d6SMark Murray 	struct stat sb;
47613e3f4d6SMark Murray 	int p;
47713e3f4d6SMark Murray 
47813e3f4d6SMark Murray 	for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
47913e3f4d6SMark Murray 	    snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum);
48013e3f4d6SMark Murray 	    p = open(myline, 2);
48113e3f4d6SMark Murray 	    if (p < 0)
48213e3f4d6SMark Murray 		continue;
48313e3f4d6SMark Murray 	    snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum);
48413e3f4d6SMark Murray 	    /*
48513e3f4d6SMark Murray 	     * Here are some shenanigans to make sure that there
48613e3f4d6SMark Murray 	     * are no listeners lurking on the line.
48713e3f4d6SMark Murray 	     */
48813e3f4d6SMark Murray 	    if(stat(line, &sb) < 0) {
48913e3f4d6SMark Murray 		close(p);
49013e3f4d6SMark Murray 		continue;
49113e3f4d6SMark Murray 	    }
49213e3f4d6SMark Murray 	    if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
49313e3f4d6SMark Murray 		chown(line, 0, 0);
49413e3f4d6SMark Murray 		chmod(line, 0600);
49513e3f4d6SMark Murray 		close(p);
49613e3f4d6SMark Murray 		p = open(myline, 2);
49713e3f4d6SMark Murray 		if (p < 0)
49813e3f4d6SMark Murray 		    continue;
49913e3f4d6SMark Murray 	    }
50013e3f4d6SMark Murray 	    /*
50113e3f4d6SMark Murray 	     * Now it should be safe...check for accessability.
50213e3f4d6SMark Murray 	     */
503c19800e8SDoug Rabson 	    if (access(line, 6) == 0)
50413e3f4d6SMark Murray 		return(p);
50513e3f4d6SMark Murray 	    else {
50613e3f4d6SMark Murray 		/* no tty side to pty so skip it */
50713e3f4d6SMark Murray 		close(p);
50813e3f4d6SMark Murray 	    }
50913e3f4d6SMark Murray 	}
51013e3f4d6SMark Murray     }
51113e3f4d6SMark Murray #endif	/* CRAY */
51213e3f4d6SMark Murray     return(-1);
51313e3f4d6SMark Murray }
51413e3f4d6SMark Murray 
51513e3f4d6SMark Murray 
51613e3f4d6SMark Murray int
tty_isecho(void)51713e3f4d6SMark Murray tty_isecho(void)
51813e3f4d6SMark Murray {
51913e3f4d6SMark Murray     return (termbuf.c_lflag & ECHO);
52013e3f4d6SMark Murray }
52113e3f4d6SMark Murray 
52213e3f4d6SMark Murray int
tty_flowmode(void)52313e3f4d6SMark Murray tty_flowmode(void)
52413e3f4d6SMark Murray {
52513e3f4d6SMark Murray     return((termbuf.c_iflag & IXON) ? 1 : 0);
52613e3f4d6SMark Murray }
52713e3f4d6SMark Murray 
52813e3f4d6SMark Murray int
tty_restartany(void)52913e3f4d6SMark Murray tty_restartany(void)
53013e3f4d6SMark Murray {
53113e3f4d6SMark Murray     return((termbuf.c_iflag & IXANY) ? 1 : 0);
53213e3f4d6SMark Murray }
53313e3f4d6SMark Murray 
53413e3f4d6SMark Murray void
tty_setecho(int on)53513e3f4d6SMark Murray tty_setecho(int on)
53613e3f4d6SMark Murray {
53713e3f4d6SMark Murray     if (on)
53813e3f4d6SMark Murray 	termbuf.c_lflag |= ECHO;
53913e3f4d6SMark Murray     else
54013e3f4d6SMark Murray 	termbuf.c_lflag &= ~ECHO;
54113e3f4d6SMark Murray }
54213e3f4d6SMark Murray 
54313e3f4d6SMark Murray int
tty_israw(void)54413e3f4d6SMark Murray tty_israw(void)
54513e3f4d6SMark Murray {
54613e3f4d6SMark Murray     return(!(termbuf.c_lflag & ICANON));
54713e3f4d6SMark Murray }
54813e3f4d6SMark Murray 
54913e3f4d6SMark Murray void
tty_binaryin(int on)55013e3f4d6SMark Murray tty_binaryin(int on)
55113e3f4d6SMark Murray {
55213e3f4d6SMark Murray     if (on) {
55313e3f4d6SMark Murray 	termbuf.c_iflag &= ~ISTRIP;
55413e3f4d6SMark Murray     } else {
55513e3f4d6SMark Murray 	termbuf.c_iflag |= ISTRIP;
55613e3f4d6SMark Murray     }
55713e3f4d6SMark Murray }
55813e3f4d6SMark Murray 
55913e3f4d6SMark Murray void
tty_binaryout(int on)56013e3f4d6SMark Murray tty_binaryout(int on)
56113e3f4d6SMark Murray {
56213e3f4d6SMark Murray     if (on) {
56313e3f4d6SMark Murray 	termbuf.c_cflag &= ~(CSIZE|PARENB);
56413e3f4d6SMark Murray 	termbuf.c_cflag |= CS8;
56513e3f4d6SMark Murray 	termbuf.c_oflag &= ~OPOST;
56613e3f4d6SMark Murray     } else {
56713e3f4d6SMark Murray 	termbuf.c_cflag &= ~CSIZE;
56813e3f4d6SMark Murray 	termbuf.c_cflag |= CS7|PARENB;
56913e3f4d6SMark Murray 	termbuf.c_oflag |= OPOST;
57013e3f4d6SMark Murray     }
57113e3f4d6SMark Murray }
57213e3f4d6SMark Murray 
57313e3f4d6SMark Murray int
tty_isbinaryin(void)57413e3f4d6SMark Murray tty_isbinaryin(void)
57513e3f4d6SMark Murray {
57613e3f4d6SMark Murray     return(!(termbuf.c_iflag & ISTRIP));
57713e3f4d6SMark Murray }
57813e3f4d6SMark Murray 
57913e3f4d6SMark Murray int
tty_isbinaryout(void)58013e3f4d6SMark Murray tty_isbinaryout(void)
58113e3f4d6SMark Murray {
58213e3f4d6SMark Murray     return(!(termbuf.c_oflag&OPOST));
58313e3f4d6SMark Murray }
58413e3f4d6SMark Murray 
58513e3f4d6SMark Murray 
58613e3f4d6SMark Murray int
tty_issofttab(void)58713e3f4d6SMark Murray tty_issofttab(void)
58813e3f4d6SMark Murray {
58913e3f4d6SMark Murray # ifdef	OXTABS
59013e3f4d6SMark Murray     return (termbuf.c_oflag & OXTABS);
59113e3f4d6SMark Murray # endif
59213e3f4d6SMark Murray # ifdef	TABDLY
59313e3f4d6SMark Murray     return ((termbuf.c_oflag & TABDLY) == TAB3);
59413e3f4d6SMark Murray # endif
59513e3f4d6SMark Murray }
59613e3f4d6SMark Murray 
59713e3f4d6SMark Murray void
tty_setsofttab(int on)59813e3f4d6SMark Murray tty_setsofttab(int on)
59913e3f4d6SMark Murray {
60013e3f4d6SMark Murray     if (on) {
60113e3f4d6SMark Murray # ifdef	OXTABS
60213e3f4d6SMark Murray 	termbuf.c_oflag |= OXTABS;
60313e3f4d6SMark Murray # endif
60413e3f4d6SMark Murray # ifdef	TABDLY
60513e3f4d6SMark Murray 	termbuf.c_oflag &= ~TABDLY;
60613e3f4d6SMark Murray 	termbuf.c_oflag |= TAB3;
60713e3f4d6SMark Murray # endif
60813e3f4d6SMark Murray     } else {
60913e3f4d6SMark Murray # ifdef	OXTABS
61013e3f4d6SMark Murray 	termbuf.c_oflag &= ~OXTABS;
61113e3f4d6SMark Murray # endif
61213e3f4d6SMark Murray # ifdef	TABDLY
61313e3f4d6SMark Murray 	termbuf.c_oflag &= ~TABDLY;
61413e3f4d6SMark Murray 	termbuf.c_oflag |= TAB0;
61513e3f4d6SMark Murray # endif
61613e3f4d6SMark Murray     }
61713e3f4d6SMark Murray }
61813e3f4d6SMark Murray 
61913e3f4d6SMark Murray int
tty_islitecho(void)62013e3f4d6SMark Murray tty_islitecho(void)
62113e3f4d6SMark Murray {
62213e3f4d6SMark Murray # ifdef	ECHOCTL
62313e3f4d6SMark Murray     return (!(termbuf.c_lflag & ECHOCTL));
62413e3f4d6SMark Murray # endif
62513e3f4d6SMark Murray # ifdef	TCTLECH
62613e3f4d6SMark Murray     return (!(termbuf.c_lflag & TCTLECH));
62713e3f4d6SMark Murray # endif
62813e3f4d6SMark Murray # if	!defined(ECHOCTL) && !defined(TCTLECH)
62913e3f4d6SMark Murray     return (0);	/* assumes ctl chars are echoed '^x' */
63013e3f4d6SMark Murray # endif
63113e3f4d6SMark Murray }
63213e3f4d6SMark Murray 
63313e3f4d6SMark Murray void
tty_setlitecho(int on)63413e3f4d6SMark Murray tty_setlitecho(int on)
63513e3f4d6SMark Murray {
63613e3f4d6SMark Murray # ifdef	ECHOCTL
63713e3f4d6SMark Murray     if (on)
63813e3f4d6SMark Murray 	termbuf.c_lflag &= ~ECHOCTL;
63913e3f4d6SMark Murray     else
64013e3f4d6SMark Murray 	termbuf.c_lflag |= ECHOCTL;
64113e3f4d6SMark Murray # endif
64213e3f4d6SMark Murray # ifdef	TCTLECH
64313e3f4d6SMark Murray     if (on)
64413e3f4d6SMark Murray 	termbuf.c_lflag &= ~TCTLECH;
64513e3f4d6SMark Murray     else
64613e3f4d6SMark Murray 	termbuf.c_lflag |= TCTLECH;
64713e3f4d6SMark Murray # endif
64813e3f4d6SMark Murray }
64913e3f4d6SMark Murray 
65013e3f4d6SMark Murray int
tty_iscrnl(void)65113e3f4d6SMark Murray tty_iscrnl(void)
65213e3f4d6SMark Murray {
65313e3f4d6SMark Murray     return (termbuf.c_iflag & ICRNL);
65413e3f4d6SMark Murray }
65513e3f4d6SMark Murray 
65613e3f4d6SMark Murray /*
65713e3f4d6SMark Murray  * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
65813e3f4d6SMark Murray  */
65913e3f4d6SMark Murray #if B4800 != 4800
66013e3f4d6SMark Murray #define	DECODE_BAUD
66113e3f4d6SMark Murray #endif
66213e3f4d6SMark Murray 
66313e3f4d6SMark Murray #ifdef	DECODE_BAUD
66413e3f4d6SMark Murray 
66513e3f4d6SMark Murray /*
66613e3f4d6SMark Murray  * A table of available terminal speeds
66713e3f4d6SMark Murray  */
66813e3f4d6SMark Murray struct termspeeds {
66913e3f4d6SMark Murray     int	speed;
67013e3f4d6SMark Murray     int	value;
67113e3f4d6SMark Murray } termspeeds[] = {
67213e3f4d6SMark Murray     { 0,      B0 },      { 50,    B50 },    { 75,     B75 },
67313e3f4d6SMark Murray     { 110,    B110 },    { 134,   B134 },   { 150,    B150 },
67413e3f4d6SMark Murray     { 200,    B200 },    { 300,   B300 },   { 600,    B600 },
67513e3f4d6SMark Murray     { 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
67613e3f4d6SMark Murray     { 4800,   B4800 },
67713e3f4d6SMark Murray #ifdef	B7200
67813e3f4d6SMark Murray     { 7200,  B7200 },
67913e3f4d6SMark Murray #endif
68013e3f4d6SMark Murray     { 9600,   B9600 },
68113e3f4d6SMark Murray #ifdef	B14400
68213e3f4d6SMark Murray     { 14400,  B14400 },
68313e3f4d6SMark Murray #endif
68413e3f4d6SMark Murray #ifdef	B19200
68513e3f4d6SMark Murray     { 19200,  B19200 },
68613e3f4d6SMark Murray #endif
68713e3f4d6SMark Murray #ifdef	B28800
68813e3f4d6SMark Murray     { 28800,  B28800 },
68913e3f4d6SMark Murray #endif
69013e3f4d6SMark Murray #ifdef	B38400
69113e3f4d6SMark Murray     { 38400,  B38400 },
69213e3f4d6SMark Murray #endif
69313e3f4d6SMark Murray #ifdef	B57600
69413e3f4d6SMark Murray     { 57600,  B57600 },
69513e3f4d6SMark Murray #endif
69613e3f4d6SMark Murray #ifdef	B115200
69713e3f4d6SMark Murray     { 115200, B115200 },
69813e3f4d6SMark Murray #endif
69913e3f4d6SMark Murray #ifdef	B230400
70013e3f4d6SMark Murray     { 230400, B230400 },
70113e3f4d6SMark Murray #endif
70213e3f4d6SMark Murray     { -1,     0 }
70313e3f4d6SMark Murray };
70413e3f4d6SMark Murray #endif	/* DECODE_BUAD */
70513e3f4d6SMark Murray 
70613e3f4d6SMark Murray void
tty_tspeed(int val)70713e3f4d6SMark Murray tty_tspeed(int val)
70813e3f4d6SMark Murray {
70913e3f4d6SMark Murray #ifdef	DECODE_BAUD
71013e3f4d6SMark Murray     struct termspeeds *tp;
71113e3f4d6SMark Murray 
71213e3f4d6SMark Murray     for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
71313e3f4d6SMark Murray 	;
71413e3f4d6SMark Murray     if (tp->speed == -1)	/* back up to last valid value */
71513e3f4d6SMark Murray 	--tp;
71613e3f4d6SMark Murray     cfsetospeed(&termbuf, tp->value);
71713e3f4d6SMark Murray #else	/* DECODE_BUAD */
71813e3f4d6SMark Murray     cfsetospeed(&termbuf, val);
71913e3f4d6SMark Murray #endif	/* DECODE_BUAD */
72013e3f4d6SMark Murray }
72113e3f4d6SMark Murray 
72213e3f4d6SMark Murray void
tty_rspeed(int val)72313e3f4d6SMark Murray tty_rspeed(int val)
72413e3f4d6SMark Murray {
72513e3f4d6SMark Murray #ifdef	DECODE_BAUD
72613e3f4d6SMark Murray     struct termspeeds *tp;
72713e3f4d6SMark Murray 
72813e3f4d6SMark Murray     for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
72913e3f4d6SMark Murray 	;
73013e3f4d6SMark Murray     if (tp->speed == -1)	/* back up to last valid value */
73113e3f4d6SMark Murray 	--tp;
73213e3f4d6SMark Murray     cfsetispeed(&termbuf, tp->value);
73313e3f4d6SMark Murray #else	/* DECODE_BAUD */
73413e3f4d6SMark Murray     cfsetispeed(&termbuf, val);
73513e3f4d6SMark Murray #endif	/* DECODE_BAUD */
73613e3f4d6SMark Murray }
73713e3f4d6SMark Murray 
73813e3f4d6SMark Murray #ifdef PARENT_DOES_UTMP
73913e3f4d6SMark Murray extern	struct utmp wtmp;
74013e3f4d6SMark Murray extern char wtmpf[];
74113e3f4d6SMark Murray 
74213e3f4d6SMark Murray extern void utmp_sig_init (void);
74313e3f4d6SMark Murray extern void utmp_sig_reset (void);
74413e3f4d6SMark Murray extern void utmp_sig_wait (void);
74513e3f4d6SMark Murray extern void utmp_sig_notify (int);
74613e3f4d6SMark Murray # endif /* PARENT_DOES_UTMP */
74713e3f4d6SMark Murray 
74813e3f4d6SMark Murray #ifdef STREAMSPTY
74913e3f4d6SMark Murray 
75013e3f4d6SMark Murray /* I_FIND seems to live a life of its own */
my_find(int fd,char * module)75113e3f4d6SMark Murray static int my_find(int fd, char *module)
75213e3f4d6SMark Murray {
75313e3f4d6SMark Murray #if defined(I_FIND) && defined(I_LIST)
75413e3f4d6SMark Murray     static int flag;
75513e3f4d6SMark Murray     static struct str_list sl;
75613e3f4d6SMark Murray     int n;
75713e3f4d6SMark Murray     int i;
75813e3f4d6SMark Murray 
75913e3f4d6SMark Murray     if(!flag){
76013e3f4d6SMark Murray 	n = ioctl(fd, I_LIST, 0);
76113e3f4d6SMark Murray 	if(n < 0){
76213e3f4d6SMark Murray 	    perror("ioctl(fd, I_LIST, 0)");
76313e3f4d6SMark Murray 	    return -1;
76413e3f4d6SMark Murray 	}
76513e3f4d6SMark Murray 	sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist));
76613e3f4d6SMark Murray 	sl.sl_nmods = n;
76713e3f4d6SMark Murray 	n = ioctl(fd, I_LIST, &sl);
76813e3f4d6SMark Murray 	if(n < 0){
76913e3f4d6SMark Murray 	    perror("ioctl(fd, I_LIST, n)");
77013e3f4d6SMark Murray 	    return -1;
77113e3f4d6SMark Murray 	}
77213e3f4d6SMark Murray 	flag = 1;
77313e3f4d6SMark Murray     }
77413e3f4d6SMark Murray 
77513e3f4d6SMark Murray     for(i=0; i<sl.sl_nmods; i++)
77613e3f4d6SMark Murray 	if(!strcmp(sl.sl_modlist[i].l_name, module))
77713e3f4d6SMark Murray 	    return 1;
77813e3f4d6SMark Murray #endif
77913e3f4d6SMark Murray     return 0;
78013e3f4d6SMark Murray }
78113e3f4d6SMark Murray 
maybe_push_modules(int fd,char ** modules)78213e3f4d6SMark Murray static void maybe_push_modules(int fd, char **modules)
78313e3f4d6SMark Murray {
78413e3f4d6SMark Murray     char **p;
78513e3f4d6SMark Murray     int err;
78613e3f4d6SMark Murray 
78713e3f4d6SMark Murray     for(p=modules; *p; p++){
78813e3f4d6SMark Murray 	err = my_find(fd, *p);
78913e3f4d6SMark Murray 	if(err == 1)
79013e3f4d6SMark Murray 	    break;
79113e3f4d6SMark Murray 	if(err < 0 && errno != EINVAL)
79213e3f4d6SMark Murray 	    fatalperror(net, "my_find()");
79313e3f4d6SMark Murray 	/* module not pushed or does not exist */
79413e3f4d6SMark Murray     }
79513e3f4d6SMark Murray     /* p points to null or to an already pushed module, now push all
79613e3f4d6SMark Murray        modules before this one */
79713e3f4d6SMark Murray 
79813e3f4d6SMark Murray     for(p--; p >= modules; p--){
79913e3f4d6SMark Murray 	err = ioctl(fd, I_PUSH, *p);
80013e3f4d6SMark Murray 	if(err < 0 && errno != EINVAL)
80113e3f4d6SMark Murray 	    fatalperror(net, "I_PUSH");
80213e3f4d6SMark Murray     }
80313e3f4d6SMark Murray }
80413e3f4d6SMark Murray #endif
80513e3f4d6SMark Murray 
80613e3f4d6SMark Murray /*
80713e3f4d6SMark Murray  * getptyslave()
80813e3f4d6SMark Murray  *
80913e3f4d6SMark Murray  * Open the slave side of the pty, and do any initialization
81013e3f4d6SMark Murray  * that is necessary.  The return value is a file descriptor
81113e3f4d6SMark Murray  * for the slave side.
81213e3f4d6SMark Murray  */
getptyslave(void)81313e3f4d6SMark Murray void getptyslave(void)
81413e3f4d6SMark Murray {
81513e3f4d6SMark Murray     int t = -1;
81613e3f4d6SMark Murray 
81713e3f4d6SMark Murray     struct winsize ws;
81813e3f4d6SMark Murray     /*
81913e3f4d6SMark Murray      * Opening the slave side may cause initilization of the
82013e3f4d6SMark Murray      * kernel tty structure.  We need remember the state of
82113e3f4d6SMark Murray      * 	if linemode was turned on
82213e3f4d6SMark Murray      *	terminal window size
82313e3f4d6SMark Murray      *	terminal speed
82413e3f4d6SMark Murray      * so that we can re-set them if we need to.
82513e3f4d6SMark Murray      */
82613e3f4d6SMark Murray 
82713e3f4d6SMark Murray 
82813e3f4d6SMark Murray     /*
82913e3f4d6SMark Murray      * Make sure that we don't have a controlling tty, and
83013e3f4d6SMark Murray      * that we are the session (process group) leader.
83113e3f4d6SMark Murray      */
83213e3f4d6SMark Murray 
83313e3f4d6SMark Murray #ifdef HAVE_SETSID
83413e3f4d6SMark Murray     if(setsid()<0)
83513e3f4d6SMark Murray 	fatalperror(net, "setsid()");
83613e3f4d6SMark Murray #else
83713e3f4d6SMark Murray # ifdef	TIOCNOTTY
83813e3f4d6SMark Murray     t = open(_PATH_TTY, O_RDWR);
83913e3f4d6SMark Murray     if (t >= 0) {
84013e3f4d6SMark Murray 	ioctl(t, TIOCNOTTY, (char *)0);
84113e3f4d6SMark Murray 	close(t);
84213e3f4d6SMark Murray     }
84313e3f4d6SMark Murray # endif
84413e3f4d6SMark Murray #endif
84513e3f4d6SMark Murray 
84613e3f4d6SMark Murray # ifdef PARENT_DOES_UTMP
84713e3f4d6SMark Murray     /*
84813e3f4d6SMark Murray      * Wait for our parent to get the utmp stuff to get done.
84913e3f4d6SMark Murray      */
85013e3f4d6SMark Murray     utmp_sig_wait();
85113e3f4d6SMark Murray # endif
85213e3f4d6SMark Murray 
85313e3f4d6SMark Murray     t = cleanopen(line);
85413e3f4d6SMark Murray     if (t < 0)
85513e3f4d6SMark Murray 	fatalperror(net, line);
85613e3f4d6SMark Murray 
85713e3f4d6SMark Murray #ifdef  STREAMSPTY
85813e3f4d6SMark Murray     ttyfd = t;
85913e3f4d6SMark Murray 
86013e3f4d6SMark Murray 
86113e3f4d6SMark Murray     /*
86213e3f4d6SMark Murray      * Not all systems have (or need) modules ttcompat and pckt so
86313e3f4d6SMark Murray      * don't flag it as a fatal error if they don't exist.
86413e3f4d6SMark Murray      */
86513e3f4d6SMark Murray 
86613e3f4d6SMark Murray     if (really_stream)
86713e3f4d6SMark Murray 	{
86813e3f4d6SMark Murray 	    /* these are the streams modules that we want pushed. note
86913e3f4d6SMark Murray 	       that they are in reverse order, ptem will be pushed
87013e3f4d6SMark Murray 	       first. maybe_push_modules() will try to push all modules
87113e3f4d6SMark Murray 	       before the first one that isn't already pushed. i.e if
87213e3f4d6SMark Murray 	       ldterm is pushed, only ttcompat will be attempted.
87313e3f4d6SMark Murray 
87413e3f4d6SMark Murray 	       all this is because we don't know which modules are
87513e3f4d6SMark Murray 	       available, and we don't know which modules are already
87613e3f4d6SMark Murray 	       pushed (via autopush, for instance).
87713e3f4d6SMark Murray 
87813e3f4d6SMark Murray 	       */
87913e3f4d6SMark Murray 
88013e3f4d6SMark Murray 	    char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
88113e3f4d6SMark Murray 	    char *ptymodules[] = { "pckt", NULL };
88213e3f4d6SMark Murray 
88313e3f4d6SMark Murray 	    maybe_push_modules(t, ttymodules);
88413e3f4d6SMark Murray 	    maybe_push_modules(ourpty, ptymodules);
88513e3f4d6SMark Murray 	}
88613e3f4d6SMark Murray #endif
88713e3f4d6SMark Murray     /*
88813e3f4d6SMark Murray      * set up the tty modes as we like them to be.
88913e3f4d6SMark Murray      */
89013e3f4d6SMark Murray     init_termbuf();
89113e3f4d6SMark Murray # ifdef	TIOCSWINSZ
89213e3f4d6SMark Murray     if (def_row || def_col) {
89313e3f4d6SMark Murray 	memset(&ws, 0, sizeof(ws));
89413e3f4d6SMark Murray 	ws.ws_col = def_col;
89513e3f4d6SMark Murray 	ws.ws_row = def_row;
89613e3f4d6SMark Murray 	ioctl(t, TIOCSWINSZ, (char *)&ws);
89713e3f4d6SMark Murray     }
89813e3f4d6SMark Murray # endif
89913e3f4d6SMark Murray 
90013e3f4d6SMark Murray     /*
90113e3f4d6SMark Murray      * Settings for sgtty based systems
90213e3f4d6SMark Murray      */
90313e3f4d6SMark Murray 
90413e3f4d6SMark Murray     /*
90513e3f4d6SMark Murray      * Settings for UNICOS (and HPUX)
90613e3f4d6SMark Murray      */
90713e3f4d6SMark Murray # if defined(_CRAY) || defined(__hpux)
90813e3f4d6SMark Murray     termbuf.c_oflag = OPOST|ONLCR|TAB3;
90913e3f4d6SMark Murray     termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
91013e3f4d6SMark Murray     termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
91113e3f4d6SMark Murray     termbuf.c_cflag = EXTB|HUPCL|CS8;
91213e3f4d6SMark Murray # endif
91313e3f4d6SMark Murray 
91413e3f4d6SMark Murray     /*
91513e3f4d6SMark Murray      * Settings for all other termios/termio based
91613e3f4d6SMark Murray      * systems, other than 4.4BSD.  In 4.4BSD the
91713e3f4d6SMark Murray      * kernel does the initial terminal setup.
91813e3f4d6SMark Murray      */
91913e3f4d6SMark Murray # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
92013e3f4d6SMark Murray #  ifndef	OXTABS
92113e3f4d6SMark Murray #   define OXTABS	0
92213e3f4d6SMark Murray #  endif
92313e3f4d6SMark Murray     termbuf.c_lflag |= ECHO;
92413e3f4d6SMark Murray     termbuf.c_oflag |= ONLCR|OXTABS;
92513e3f4d6SMark Murray     termbuf.c_iflag |= ICRNL;
92613e3f4d6SMark Murray     termbuf.c_iflag &= ~IXOFF;
92713e3f4d6SMark Murray # endif
92813e3f4d6SMark Murray     tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
92913e3f4d6SMark Murray     tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
93013e3f4d6SMark Murray 
93113e3f4d6SMark Murray     /*
93213e3f4d6SMark Murray      * Set the tty modes, and make this our controlling tty.
93313e3f4d6SMark Murray      */
93413e3f4d6SMark Murray     set_termbuf();
93513e3f4d6SMark Murray     if (login_tty(t) == -1)
93613e3f4d6SMark Murray 	fatalperror(net, "login_tty");
93713e3f4d6SMark Murray     if (net > 2)
93813e3f4d6SMark Murray 	close(net);
93913e3f4d6SMark Murray     if (ourpty > 2) {
94013e3f4d6SMark Murray 	close(ourpty);
94113e3f4d6SMark Murray 	ourpty = -1;
94213e3f4d6SMark Murray     }
94313e3f4d6SMark Murray }
94413e3f4d6SMark Murray 
94513e3f4d6SMark Murray #ifndef	O_NOCTTY
94613e3f4d6SMark Murray #define	O_NOCTTY	0
94713e3f4d6SMark Murray #endif
94813e3f4d6SMark Murray /*
94913e3f4d6SMark Murray  * Open the specified slave side of the pty,
950c19800e8SDoug Rabson  * making sure that we have a clean tty.
951c19800e8SDoug Rabson  */
952c19800e8SDoug Rabson 
cleanopen(char * line)95313e3f4d6SMark Murray int cleanopen(char *line)
95413e3f4d6SMark Murray {
95513e3f4d6SMark Murray     int t;
95613e3f4d6SMark Murray 
95713e3f4d6SMark Murray     if (ptyslavefd != -1)
95813e3f4d6SMark Murray 	return ptyslavefd;
95913e3f4d6SMark Murray 
96013e3f4d6SMark Murray #ifdef STREAMSPTY
96113e3f4d6SMark Murray     if (!really_stream)
96213e3f4d6SMark Murray #endif
96313e3f4d6SMark Murray 	{
96413e3f4d6SMark Murray 	    /*
96513e3f4d6SMark Murray 	     * Make sure that other people can't open the
96613e3f4d6SMark Murray 	     * slave side of the connection.
96713e3f4d6SMark Murray 	     */
96813e3f4d6SMark Murray 	    chown(line, 0, 0);
96913e3f4d6SMark Murray 	    chmod(line, 0600);
97013e3f4d6SMark Murray 	}
97113e3f4d6SMark Murray 
97213e3f4d6SMark Murray #ifdef HAVE_REVOKE
97313e3f4d6SMark Murray     revoke(line);
97413e3f4d6SMark Murray #endif
97513e3f4d6SMark Murray 
97613e3f4d6SMark Murray     t = open(line, O_RDWR|O_NOCTTY);
97713e3f4d6SMark Murray 
97813e3f4d6SMark Murray     if (t < 0)
97913e3f4d6SMark Murray 	return(-1);
98013e3f4d6SMark Murray 
98113e3f4d6SMark Murray     /*
98213e3f4d6SMark Murray      * Hangup anybody else using this ttyp, then reopen it for
98313e3f4d6SMark Murray      * ourselves.
98413e3f4d6SMark Murray      */
98513e3f4d6SMark Murray # if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
98613e3f4d6SMark Murray     signal(SIGHUP, SIG_IGN);
98713e3f4d6SMark Murray #ifdef HAVE_VHANGUP
98813e3f4d6SMark Murray     vhangup();
98913e3f4d6SMark Murray #else
99013e3f4d6SMark Murray #endif
99113e3f4d6SMark Murray     signal(SIGHUP, SIG_DFL);
99213e3f4d6SMark Murray     t = open(line, O_RDWR|O_NOCTTY);
99313e3f4d6SMark Murray     if (t < 0)
99413e3f4d6SMark Murray 	return(-1);
99513e3f4d6SMark Murray # endif
99613e3f4d6SMark Murray # if	defined(_CRAY) && defined(TCVHUP)
99713e3f4d6SMark Murray     {
99813e3f4d6SMark Murray 	int i;
99913e3f4d6SMark Murray 	signal(SIGHUP, SIG_IGN);
100013e3f4d6SMark Murray 	ioctl(t, TCVHUP, (char *)0);
100113e3f4d6SMark Murray 	signal(SIGHUP, SIG_DFL);
100213e3f4d6SMark Murray 
100313e3f4d6SMark Murray 	i = open(line, O_RDWR);
100413e3f4d6SMark Murray 
100513e3f4d6SMark Murray 	if (i < 0)
100613e3f4d6SMark Murray 	    return(-1);
100713e3f4d6SMark Murray 	close(t);
100813e3f4d6SMark Murray 	t = i;
100913e3f4d6SMark Murray     }
101013e3f4d6SMark Murray # endif	/* defined(CRAY) && defined(TCVHUP) */
101113e3f4d6SMark Murray     return(t);
101213e3f4d6SMark Murray }
101313e3f4d6SMark Murray 
101413e3f4d6SMark Murray #if !defined(BSD4_4)
101513e3f4d6SMark Murray 
login_tty(int t)101613e3f4d6SMark Murray int login_tty(int t)
101713e3f4d6SMark Murray {
101813e3f4d6SMark Murray     /* Dont need to set this as the controlling PTY on steams sockets,
101913e3f4d6SMark Murray      * don't abort on failure. */
102013e3f4d6SMark Murray # if defined(TIOCSCTTY) && !defined(__hpux)
102113e3f4d6SMark Murray     if (ioctl(t, TIOCSCTTY, (char *)0) < 0 && !really_stream)
102213e3f4d6SMark Murray 	fatalperror(net, "ioctl(sctty)");
102313e3f4d6SMark Murray #  ifdef _CRAY
102413e3f4d6SMark Murray     /*
102513e3f4d6SMark Murray      * Close the hard fd to /dev/ttypXXX, and re-open through
102613e3f4d6SMark Murray      * the indirect /dev/tty interface.
102713e3f4d6SMark Murray      */
102813e3f4d6SMark Murray     close(t);
102913e3f4d6SMark Murray     if ((t = open("/dev/tty", O_RDWR)) < 0)
103013e3f4d6SMark Murray 	fatalperror(net, "open(/dev/tty)");
103113e3f4d6SMark Murray #  endif
103213e3f4d6SMark Murray # else
103313e3f4d6SMark Murray     /*
103413e3f4d6SMark Murray      * We get our controlling tty assigned as a side-effect
103513e3f4d6SMark Murray      * of opening up a tty device.  But on BSD based systems,
103613e3f4d6SMark Murray      * this only happens if our process group is zero.  The
103713e3f4d6SMark Murray      * setsid() call above may have set our pgrp, so clear
103813e3f4d6SMark Murray      * it out before opening the tty...
103913e3f4d6SMark Murray      */
104013e3f4d6SMark Murray #ifdef HAVE_SETPGID
104113e3f4d6SMark Murray     setpgid(0, 0);
104213e3f4d6SMark Murray #else
104313e3f4d6SMark Murray     setpgrp(0, 0); /* if setpgid isn't available, setpgrp
104413e3f4d6SMark Murray 		      probably takes arguments */
104513e3f4d6SMark Murray #endif
104613e3f4d6SMark Murray     close(open(line, O_RDWR));
104713e3f4d6SMark Murray # endif
104813e3f4d6SMark Murray     if (t != 0)
104913e3f4d6SMark Murray 	dup2(t, 0);
105013e3f4d6SMark Murray     if (t != 1)
105113e3f4d6SMark Murray 	dup2(t, 1);
105213e3f4d6SMark Murray     if (t != 2)
105313e3f4d6SMark Murray 	dup2(t, 2);
105413e3f4d6SMark Murray     if (t > 2)
105513e3f4d6SMark Murray 	close(t);
105613e3f4d6SMark Murray     return(0);
105713e3f4d6SMark Murray }
105813e3f4d6SMark Murray #endif	/* BSD <= 43 */
1059c19800e8SDoug Rabson 
1060c19800e8SDoug Rabson /*
106113e3f4d6SMark Murray  * This comes from ../../bsd/tty.c and should not really be here.
106213e3f4d6SMark Murray  */
106313e3f4d6SMark Murray 
106413e3f4d6SMark Murray /*
106513e3f4d6SMark Murray  * Clean the tty name.  Return a pointer to the cleaned version.
106613e3f4d6SMark Murray  */
106713e3f4d6SMark Murray 
106813e3f4d6SMark Murray static char * clean_ttyname (char *) __attribute__((unused));
106913e3f4d6SMark Murray 
107013e3f4d6SMark Murray static char *
clean_ttyname(char * tty)107113e3f4d6SMark Murray clean_ttyname (char *tty)
107213e3f4d6SMark Murray {
107313e3f4d6SMark Murray   char *res = tty;
107413e3f4d6SMark Murray 
107513e3f4d6SMark Murray   if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0)
107613e3f4d6SMark Murray     res += strlen(_PATH_DEV);
107713e3f4d6SMark Murray   if (strncmp (res, "pty/", 4) == 0)
107813e3f4d6SMark Murray     res += 4;
107913e3f4d6SMark Murray   if (strncmp (res, "ptym/", 5) == 0)
108013e3f4d6SMark Murray     res += 5;
108113e3f4d6SMark Murray   return res;
108213e3f4d6SMark Murray }
108313e3f4d6SMark Murray 
108413e3f4d6SMark Murray /*
108513e3f4d6SMark Murray  * Generate a name usable as an `ut_id', typically without `tty'.
108613e3f4d6SMark Murray  */
108713e3f4d6SMark Murray 
108813e3f4d6SMark Murray #ifdef HAVE_STRUCT_UTMP_UT_ID
108913e3f4d6SMark Murray static char *
make_id(char * tty)109013e3f4d6SMark Murray make_id (char *tty)
109113e3f4d6SMark Murray {
109213e3f4d6SMark Murray   char *res = tty;
109313e3f4d6SMark Murray 
109413e3f4d6SMark Murray   if (strncmp (res, "pts/", 4) == 0)
109513e3f4d6SMark Murray     res += 4;
109613e3f4d6SMark Murray   if (strncmp (res, "tty", 3) == 0)
109713e3f4d6SMark Murray     res += 3;
109813e3f4d6SMark Murray   return res;
109913e3f4d6SMark Murray }
110013e3f4d6SMark Murray #endif
110113e3f4d6SMark Murray 
1102adb0ddaeSAssar Westerlund /*
1103adb0ddaeSAssar Westerlund  * startslave(host)
110413e3f4d6SMark Murray  *
110513e3f4d6SMark Murray  * Given a hostname, do whatever
110613e3f4d6SMark Murray  * is necessary to startup the login process on the slave side of the pty.
110713e3f4d6SMark Murray  */
110813e3f4d6SMark Murray 
110913e3f4d6SMark Murray /* ARGSUSED */
111013e3f4d6SMark Murray void
startslave(const char * host,const char * utmp_host,int autologin,char * autoname)111113e3f4d6SMark Murray startslave(const char *host, const char *utmp_host,
111213e3f4d6SMark Murray 	   int autologin, char *autoname)
111313e3f4d6SMark Murray {
111413e3f4d6SMark Murray     int i;
111513e3f4d6SMark Murray 
111613e3f4d6SMark Murray #ifdef AUTHENTICATION
111713e3f4d6SMark Murray     if (!autoname || !autoname[0])
111813e3f4d6SMark Murray 	autologin = 0;
111913e3f4d6SMark Murray 
112013e3f4d6SMark Murray     if (autologin < auth_level) {
112113e3f4d6SMark Murray 	fatal(net, "Authorization failed");
112213e3f4d6SMark Murray 	exit(1);
112313e3f4d6SMark Murray     }
1124c19800e8SDoug Rabson #endif
112513e3f4d6SMark Murray 
112613e3f4d6SMark Murray     {
112713e3f4d6SMark Murray 	char *tbuf =
112813e3f4d6SMark Murray 	    "\r\n*** Connection not encrypted! "
112913e3f4d6SMark Murray 	    "Communication may be eavesdropped. ***\r\n";
113013e3f4d6SMark Murray #ifdef ENCRYPTION
113113e3f4d6SMark Murray 	if (!no_warn && (encrypt_output == 0 || decrypt_input == 0))
113213e3f4d6SMark Murray #endif
113313e3f4d6SMark Murray 	    writenet(tbuf, strlen(tbuf));
113413e3f4d6SMark Murray     }
113513e3f4d6SMark Murray # ifdef	PARENT_DOES_UTMP
113613e3f4d6SMark Murray     utmp_sig_init();
113713e3f4d6SMark Murray # endif	/* PARENT_DOES_UTMP */
113813e3f4d6SMark Murray 
113913e3f4d6SMark Murray     if ((i = fork()) < 0)
114013e3f4d6SMark Murray 	fatalperror(net, "fork");
114113e3f4d6SMark Murray     if (i) {
114213e3f4d6SMark Murray # ifdef PARENT_DOES_UTMP
114313e3f4d6SMark Murray 	/*
114413e3f4d6SMark Murray 	 * Cray parent will create utmp entry for child and send
114513e3f4d6SMark Murray 	 * signal to child to tell when done.  Child waits for signal
114613e3f4d6SMark Murray 	 * before doing anything important.
11475e9cd1aeSAssar Westerlund 	 */
114813e3f4d6SMark Murray 	int pid = i;
114913e3f4d6SMark Murray 	void sigjob (int);
115013e3f4d6SMark Murray 
1151adb0ddaeSAssar Westerlund 	setpgrp();
115213e3f4d6SMark Murray 	utmp_sig_reset();		/* reset handler to default */
115313e3f4d6SMark Murray 	/*
115413e3f4d6SMark Murray 	 * Create utmp entry for child
115513e3f4d6SMark Murray 	 */
115613e3f4d6SMark Murray 	wtmp.ut_time = time(NULL);
115713e3f4d6SMark Murray 	wtmp.ut_type = LOGIN_PROCESS;
115813e3f4d6SMark Murray 	wtmp.ut_pid = pid;
115913e3f4d6SMark Murray 	strncpy(wtmp.ut_user,  "LOGIN", sizeof(wtmp.ut_user));
116013e3f4d6SMark Murray 	strncpy(wtmp.ut_host,  utmp_host, sizeof(wtmp.ut_host));
116113e3f4d6SMark Murray 	strncpy(wtmp.ut_line,  clean_ttyname(line), sizeof(wtmp.ut_line));
116213e3f4d6SMark Murray #ifdef HAVE_STRUCT_UTMP_UT_ID
116313e3f4d6SMark Murray 	strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id));
116413e3f4d6SMark Murray #endif
116513e3f4d6SMark Murray 
116613e3f4d6SMark Murray 	pututline(&wtmp);
116713e3f4d6SMark Murray 	endutent();
116813e3f4d6SMark Murray 	if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
116913e3f4d6SMark Murray 	    write(i, &wtmp, sizeof(struct utmp));
11705e9cd1aeSAssar Westerlund 	    close(i);
11715e9cd1aeSAssar Westerlund 	}
11725e9cd1aeSAssar Westerlund #ifdef	_CRAY
11735e9cd1aeSAssar Westerlund 	signal(WJSIGNAL, sigjob);
117413e3f4d6SMark Murray #endif
117513e3f4d6SMark Murray 	utmp_sig_notify(pid);
117613e3f4d6SMark Murray # endif	/* PARENT_DOES_UTMP */
117713e3f4d6SMark Murray     } else {
117813e3f4d6SMark Murray 	getptyslave();
117913e3f4d6SMark Murray #if defined(DCE)
118013e3f4d6SMark Murray 	/* if we authenticated via K5, try and join the PAG */
118113e3f4d6SMark Murray 	kerberos5_dfspag();
118213e3f4d6SMark Murray #endif
118313e3f4d6SMark Murray 	start_login(host, autologin, autoname);
118413e3f4d6SMark Murray 	/*NOTREACHED*/
118513e3f4d6SMark Murray     }
118613e3f4d6SMark Murray }
118713e3f4d6SMark Murray 
118813e3f4d6SMark Murray char	*envinit[3];
118913e3f4d6SMark Murray #if !HAVE_DECL_ENVIRON
119013e3f4d6SMark Murray extern char **environ;
119113e3f4d6SMark Murray #endif
119213e3f4d6SMark Murray 
119313e3f4d6SMark Murray void
init_env(void)119413e3f4d6SMark Murray init_env(void)
119513e3f4d6SMark Murray {
119613e3f4d6SMark Murray     char **envp;
119713e3f4d6SMark Murray 
119813e3f4d6SMark Murray     envp = envinit;
119913e3f4d6SMark Murray     if ((*envp = getenv("TZ")))
120013e3f4d6SMark Murray 	*envp++ -= 3;
12015e9cd1aeSAssar Westerlund #if defined(_CRAY) || defined(__hpux)
120213e3f4d6SMark Murray     else
120313e3f4d6SMark Murray 	*envp++ = "TZ=GMT0";
12045e9cd1aeSAssar Westerlund #endif
12055e9cd1aeSAssar Westerlund     *envp = 0;
120613e3f4d6SMark Murray     environ = envinit;
12075e9cd1aeSAssar Westerlund }
12085e9cd1aeSAssar Westerlund 
12095e9cd1aeSAssar Westerlund /*
12105e9cd1aeSAssar Westerlund  * scrub_env()
12115e9cd1aeSAssar Westerlund  *
12125e9cd1aeSAssar Westerlund  * We only accept the environment variables listed below.
12135e9cd1aeSAssar Westerlund  */
12145e9cd1aeSAssar Westerlund 
12155e9cd1aeSAssar Westerlund static void
scrub_env(void)12165e9cd1aeSAssar Westerlund scrub_env(void)
12175e9cd1aeSAssar Westerlund {
12185e9cd1aeSAssar Westerlund     static const char *reject[] = {
12195e9cd1aeSAssar Westerlund 	"TERMCAP=/",
12205e9cd1aeSAssar Westerlund 	NULL
12215e9cd1aeSAssar Westerlund     };
12225e9cd1aeSAssar Westerlund 
122313e3f4d6SMark Murray     static const char *accept[] = {
122413e3f4d6SMark Murray 	"XAUTH=", "XAUTHORITY=", "DISPLAY=",
12255e9cd1aeSAssar Westerlund 	"TERM=",
122613e3f4d6SMark Murray 	"EDITOR=",
122713e3f4d6SMark Murray 	"PAGER=",
12285e9cd1aeSAssar Westerlund 	"PRINTER=",
12295e9cd1aeSAssar Westerlund 	"LOGNAME=",
12305e9cd1aeSAssar Westerlund 	"POSIXLY_CORRECT=",
12315e9cd1aeSAssar Westerlund 	"TERMCAP=",
12325e9cd1aeSAssar Westerlund 	NULL
12335e9cd1aeSAssar Westerlund     };
12345e9cd1aeSAssar Westerlund 
12355e9cd1aeSAssar Westerlund     char **cpp, **cpp2;
12365e9cd1aeSAssar Westerlund     const char **p;
12375e9cd1aeSAssar Westerlund 
12385e9cd1aeSAssar Westerlund     for (cpp2 = cpp = environ; *cpp; cpp++) {
123913e3f4d6SMark Murray 	int reject_it = 0;
124013e3f4d6SMark Murray 
12415e9cd1aeSAssar Westerlund 	for(p = reject; *p; p++)
124213e3f4d6SMark Murray 	    if(strncmp(*cpp, *p, strlen(*p)) == 0) {
124313e3f4d6SMark Murray 		reject_it = 1;
12445e9cd1aeSAssar Westerlund 		break;
124513e3f4d6SMark Murray 	    }
124613e3f4d6SMark Murray 	if (reject_it)
124713e3f4d6SMark Murray 	    continue;
124813e3f4d6SMark Murray 
124913e3f4d6SMark Murray 	for(p = accept; *p; p++)
125013e3f4d6SMark Murray 	    if(strncmp(*cpp, *p, strlen(*p)) == 0)
1251c19800e8SDoug Rabson 		break;
125213e3f4d6SMark Murray 	if(*p != NULL)
125313e3f4d6SMark Murray 	    *cpp2++ = *cpp;
1254adb0ddaeSAssar Westerlund     }
125513e3f4d6SMark Murray     *cpp2 = NULL;
125613e3f4d6SMark Murray }
125713e3f4d6SMark Murray 
125813e3f4d6SMark Murray 
125913e3f4d6SMark Murray struct arg_val {
126013e3f4d6SMark Murray     int size;
126113e3f4d6SMark Murray     int argc;
126213e3f4d6SMark Murray     char **argv;
126313e3f4d6SMark Murray };
1264adb0ddaeSAssar Westerlund 
126513e3f4d6SMark Murray static void addarg(struct arg_val*, const char*);
126613e3f4d6SMark Murray 
126713e3f4d6SMark Murray /*
1268adb0ddaeSAssar Westerlund  * start_login(host)
126913e3f4d6SMark Murray  *
1270c19800e8SDoug Rabson  * Assuming that we are now running as a child processes, this
1271c19800e8SDoug Rabson  * function will turn us into the login process.
1272c19800e8SDoug Rabson  */
1273c19800e8SDoug Rabson 
1274c19800e8SDoug Rabson void
start_login(const char * host,int autologin,char * name)127513e3f4d6SMark Murray start_login(const char *host, int autologin, char *name)
1276c19800e8SDoug Rabson {
127713e3f4d6SMark Murray     struct arg_val argv;
127813e3f4d6SMark Murray     char *user;
1279c19800e8SDoug Rabson     int save_errno;
128013e3f4d6SMark Murray 
128113e3f4d6SMark Murray #ifdef ENCRYPTION
128213e3f4d6SMark Murray     encrypt_output = NULL;
128313e3f4d6SMark Murray     decrypt_input = NULL;
128413e3f4d6SMark Murray #endif
128513e3f4d6SMark Murray 
128613e3f4d6SMark Murray #ifdef HAVE_UTMPX_H
128713e3f4d6SMark Murray     {
128813e3f4d6SMark Murray 	int pid = getpid();
128913e3f4d6SMark Murray 	struct utmpx utmpx;
129013e3f4d6SMark Murray 	struct timeval tv;
129113e3f4d6SMark Murray 	char *clean_tty;
129213e3f4d6SMark Murray 
129313e3f4d6SMark Murray 	/*
129413e3f4d6SMark Murray 	 * Create utmp entry for child
129513e3f4d6SMark Murray 	 */
129613e3f4d6SMark Murray 
1297c19800e8SDoug Rabson 	clean_tty = clean_ttyname(line);
1298c19800e8SDoug Rabson 	memset(&utmpx, 0, sizeof(utmpx));
1299c19800e8SDoug Rabson 	strncpy(utmpx.ut_user,  ".telnet", sizeof(utmpx.ut_user));
1300c19800e8SDoug Rabson 	strncpy(utmpx.ut_line,  clean_tty, sizeof(utmpx.ut_line));
130113e3f4d6SMark Murray #ifdef HAVE_STRUCT_UTMP_UT_ID
130213e3f4d6SMark Murray 	strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));
1303c19800e8SDoug Rabson #endif
130413e3f4d6SMark Murray 	utmpx.ut_pid = pid;
130513e3f4d6SMark Murray 
130613e3f4d6SMark Murray 	utmpx.ut_type = LOGIN_PROCESS;
130713e3f4d6SMark Murray 
130813e3f4d6SMark Murray 	gettimeofday (&tv, NULL);
130913e3f4d6SMark Murray 	utmpx.ut_tv.tv_sec = tv.tv_sec;
131013e3f4d6SMark Murray 	utmpx.ut_tv.tv_usec = tv.tv_usec;
131113e3f4d6SMark Murray 
131213e3f4d6SMark Murray 	if (pututxline(&utmpx) == NULL)
131313e3f4d6SMark Murray 	    fatal(net, "pututxline failed");
131413e3f4d6SMark Murray     }
131513e3f4d6SMark Murray #endif
131613e3f4d6SMark Murray 
131713e3f4d6SMark Murray     scrub_env();
131813e3f4d6SMark Murray 
131913e3f4d6SMark Murray     /*
1320adb0ddaeSAssar Westerlund      * -h : pass on name of host.
132113e3f4d6SMark Murray      *		WARNING:  -h is accepted by login if and only if
132213e3f4d6SMark Murray      *			getuid() == 0.
132313e3f4d6SMark Murray      * -p : don't clobber the environment (so terminal type stays set).
132413e3f4d6SMark Murray      *
132513e3f4d6SMark Murray      * -f : force this login, he has already been authenticated
132613e3f4d6SMark Murray      */
132713e3f4d6SMark Murray 
132813e3f4d6SMark Murray     /* init argv structure */
132913e3f4d6SMark Murray     argv.size=0;
133013e3f4d6SMark Murray     argv.argc=0;
133113e3f4d6SMark Murray     argv.argv=malloc(0); /*so we can call realloc later */
133213e3f4d6SMark Murray     addarg(&argv, "login");
133313e3f4d6SMark Murray     addarg(&argv, "-h");
133413e3f4d6SMark Murray     addarg(&argv, host);
133513e3f4d6SMark Murray     addarg(&argv, "-p");
133613e3f4d6SMark Murray     if(name && name[0])
133713e3f4d6SMark Murray 	user = name;
133813e3f4d6SMark Murray     else
133913e3f4d6SMark Murray 	user = getenv("USER");
134013e3f4d6SMark Murray #ifdef AUTHENTICATION
134113e3f4d6SMark Murray     if (auth_level < 0 || autologin != AUTH_VALID) {
134213e3f4d6SMark Murray 	if(!no_warn) {
134313e3f4d6SMark Murray 	    printf("User not authenticated. ");
134413e3f4d6SMark Murray 	    if (require_otp)
134513e3f4d6SMark Murray 		printf("Using one-time password\r\n");
134613e3f4d6SMark Murray 	    else
134713e3f4d6SMark Murray 		printf("Using plaintext username and password\r\n");
134813e3f4d6SMark Murray 	}
134913e3f4d6SMark Murray 	if (require_otp) {
135013e3f4d6SMark Murray 	    addarg(&argv, "-a");
135113e3f4d6SMark Murray 	    addarg(&argv, "otp");
135213e3f4d6SMark Murray 	}
135313e3f4d6SMark Murray 	if(log_unauth)
135413e3f4d6SMark Murray 	    syslog(LOG_INFO, "unauthenticated access from %s (%s)",
135513e3f4d6SMark Murray 		   host, user ? user : "unknown user");
135613e3f4d6SMark Murray     }
135713e3f4d6SMark Murray     if (auth_level >= 0 && autologin == AUTH_VALID)
135813e3f4d6SMark Murray 	addarg(&argv, "-f");
135913e3f4d6SMark Murray #endif
136013e3f4d6SMark Murray     if(user){
136113e3f4d6SMark Murray 	addarg(&argv, "--");
136213e3f4d6SMark Murray 	addarg(&argv, strdup(user));
136313e3f4d6SMark Murray     }
136413e3f4d6SMark Murray     if (getenv("USER")) {
136513e3f4d6SMark Murray 	/*
136613e3f4d6SMark Murray 	 * Assume that login will set the USER variable
136713e3f4d6SMark Murray 	 * correctly.  For SysV systems, this means that
136813e3f4d6SMark Murray 	 * USER will no longer be set, just LOGNAME by
136913e3f4d6SMark Murray 	 * login.  (The problem is that if the auto-login
137013e3f4d6SMark Murray 	 * fails, and the user then specifies a different
137113e3f4d6SMark Murray 	 * account name, he can get logged in with both
137213e3f4d6SMark Murray 	 * LOGNAME and USER in his environment, but the
137313e3f4d6SMark Murray 	 * USER value will be wrong.
137413e3f4d6SMark Murray 	 */
1375adb0ddaeSAssar Westerlund 	unsetenv("USER");
1376c19800e8SDoug Rabson     }
1377adb0ddaeSAssar Westerlund     closelog();
137813e3f4d6SMark Murray     /*
137913e3f4d6SMark Murray      * This sleep(1) is in here so that telnetd can
138013e3f4d6SMark Murray      * finish up with the tty.  There's a race condition
138113e3f4d6SMark Murray      * the login banner message gets lost...
1382adb0ddaeSAssar Westerlund      */
138313e3f4d6SMark Murray     sleep(1);
138413e3f4d6SMark Murray 
138513e3f4d6SMark Murray     execv(new_login, argv.argv);
138613e3f4d6SMark Murray     save_errno = errno;
138713e3f4d6SMark Murray     syslog(LOG_ERR, "%s: %m", new_login);
138813e3f4d6SMark Murray     fatalperror_errno(net, new_login, save_errno);
138913e3f4d6SMark Murray     /*NOTREACHED*/
1390c19800e8SDoug Rabson }
1391c19800e8SDoug Rabson 
139213e3f4d6SMark Murray static void
addarg(struct arg_val * argv,const char * val)139313e3f4d6SMark Murray addarg(struct arg_val *argv, const char *val)
139413e3f4d6SMark Murray {
139513e3f4d6SMark Murray     if(argv->size <= argv->argc+1) {
139613e3f4d6SMark Murray 	argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10));
139713e3f4d6SMark Murray 	if (argv->argv == NULL)
139813e3f4d6SMark Murray 	    fatal (net, "realloc: out of memory");
139913e3f4d6SMark Murray 	argv->size+=10;
140013e3f4d6SMark Murray     }
140113e3f4d6SMark Murray     if((argv->argv[argv->argc++] = strdup(val)) == NULL)
140213e3f4d6SMark Murray 	fatal (net, "strdup: out of memory");
140313e3f4d6SMark Murray     argv->argv[argv->argc]   = NULL;
140413e3f4d6SMark Murray }
140513e3f4d6SMark Murray 
140613e3f4d6SMark Murray 
140713e3f4d6SMark Murray /*
140813e3f4d6SMark Murray  * rmut()
140913e3f4d6SMark Murray  *
141013e3f4d6SMark Murray  * This is the function called by cleanup() to
141113e3f4d6SMark Murray  * remove the utmp entry for this person.
141213e3f4d6SMark Murray  */
141313e3f4d6SMark Murray 
141413e3f4d6SMark Murray #ifdef HAVE_UTMPX_H
141513e3f4d6SMark Murray static void
rmut(void)141613e3f4d6SMark Murray rmut(void)
141713e3f4d6SMark Murray {
141813e3f4d6SMark Murray     struct utmpx utmpx, *non_save_utxp;
141913e3f4d6SMark Murray     char *clean_tty = clean_ttyname(line);
142013e3f4d6SMark Murray 
1421c19800e8SDoug Rabson     /*
142213e3f4d6SMark Murray      * This updates the utmpx and utmp entries and make a wtmp/x entry
142313e3f4d6SMark Murray      */
142413e3f4d6SMark Murray 
142513e3f4d6SMark Murray     setutxent();
142613e3f4d6SMark Murray     memset(&utmpx, 0, sizeof(utmpx));
142713e3f4d6SMark Murray     strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
142813e3f4d6SMark Murray     utmpx.ut_type = LOGIN_PROCESS;
142913e3f4d6SMark Murray     non_save_utxp = getutxline(&utmpx);
143013e3f4d6SMark Murray     if (non_save_utxp) {
143113e3f4d6SMark Murray 	struct utmpx *utxp;
143213e3f4d6SMark Murray 	struct timeval tv;
143313e3f4d6SMark Murray 	char user0;
143413e3f4d6SMark Murray 
143513e3f4d6SMark Murray 	utxp = malloc(sizeof(struct utmpx));
143613e3f4d6SMark Murray 	*utxp = *non_save_utxp;
143713e3f4d6SMark Murray 	user0 = utxp->ut_user[0];
143813e3f4d6SMark Murray 	utxp->ut_user[0] = '\0';
143913e3f4d6SMark Murray 	utxp->ut_type = DEAD_PROCESS;
144013e3f4d6SMark Murray #ifdef HAVE_STRUCT_UTMPX_UT_EXIT
1441c19800e8SDoug Rabson #ifdef _STRUCT___EXIT_STATUS
1442c19800e8SDoug Rabson 	utxp->ut_exit.__e_termination = 0;
1443c19800e8SDoug Rabson 	utxp->ut_exit.__e_exit = 0;
1444c19800e8SDoug Rabson #elif defined(__osf__) /* XXX */
144513e3f4d6SMark Murray 	utxp->ut_exit.ut_termination = 0;
144613e3f4d6SMark Murray 	utxp->ut_exit.ut_exit = 0;
144713e3f4d6SMark Murray #else
144813e3f4d6SMark Murray 	utxp->ut_exit.e_termination = 0;
144913e3f4d6SMark Murray 	utxp->ut_exit.e_exit = 0;
145013e3f4d6SMark Murray #endif
145113e3f4d6SMark Murray #endif
145213e3f4d6SMark Murray 	gettimeofday (&tv, NULL);
145313e3f4d6SMark Murray 	utxp->ut_tv.tv_sec = tv.tv_sec;
145413e3f4d6SMark Murray 	utxp->ut_tv.tv_usec = tv.tv_usec;
145513e3f4d6SMark Murray 
145613e3f4d6SMark Murray 	pututxline(utxp);
145713e3f4d6SMark Murray #ifdef WTMPX_FILE
145813e3f4d6SMark Murray 	utxp->ut_user[0] = user0;
145913e3f4d6SMark Murray 	updwtmpx(WTMPX_FILE, utxp);
14605e9cd1aeSAssar Westerlund #elif defined(WTMP_FILE)
146113e3f4d6SMark Murray 	/* This is a strange system with a utmpx and a wtmp! */
146213e3f4d6SMark Murray 	{
146313e3f4d6SMark Murray 	  int f = open(wtmpf, O_WRONLY|O_APPEND);
146413e3f4d6SMark Murray 	  struct utmp wtmp;
146513e3f4d6SMark Murray 	  if (f >= 0) {
146613e3f4d6SMark Murray 	    strncpy(wtmp.ut_line,  clean_tty, sizeof(wtmp.ut_line));
146713e3f4d6SMark Murray 	    strncpy(wtmp.ut_name,  "", sizeof(wtmp.ut_name));
146813e3f4d6SMark Murray #ifdef HAVE_STRUCT_UTMP_UT_HOST
146913e3f4d6SMark Murray 	    strncpy(wtmp.ut_host,  "", sizeof(wtmp.ut_host));
147013e3f4d6SMark Murray #endif
147113e3f4d6SMark Murray 	    wtmp.ut_time = time(NULL);
147213e3f4d6SMark Murray 	    write(f, &wtmp, sizeof(wtmp));
147313e3f4d6SMark Murray 	    close(f);
147413e3f4d6SMark Murray 	  }
147513e3f4d6SMark Murray 	}
147613e3f4d6SMark Murray #endif
147713e3f4d6SMark Murray 	free (utxp);
147813e3f4d6SMark Murray     }
147913e3f4d6SMark Murray     endutxent();
148013e3f4d6SMark Murray }  /* end of rmut */
148113e3f4d6SMark Murray #endif
148213e3f4d6SMark Murray 
148313e3f4d6SMark Murray #if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
148413e3f4d6SMark Murray static void
rmut(void)148513e3f4d6SMark Murray rmut(void)
148613e3f4d6SMark Murray {
148713e3f4d6SMark Murray     int f;
148813e3f4d6SMark Murray     int found = 0;
148913e3f4d6SMark Murray     struct utmp *u, *utmp;
149013e3f4d6SMark Murray     int nutmp;
149113e3f4d6SMark Murray     struct stat statbf;
149213e3f4d6SMark Murray     char *clean_tty = clean_ttyname(line);
149313e3f4d6SMark Murray 
149413e3f4d6SMark Murray     f = open(utmpf, O_RDWR);
149513e3f4d6SMark Murray     if (f >= 0) {
149613e3f4d6SMark Murray 	fstat(f, &statbf);
149713e3f4d6SMark Murray 	utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
149813e3f4d6SMark Murray 	if (!utmp)
149913e3f4d6SMark Murray 	    syslog(LOG_ERR, "utmp malloc failed");
150013e3f4d6SMark Murray 	if (statbf.st_size && utmp) {
150113e3f4d6SMark Murray 	    nutmp = read(f, utmp, (int)statbf.st_size);
150213e3f4d6SMark Murray 	    nutmp /= sizeof(struct utmp);
150313e3f4d6SMark Murray 
15045e9cd1aeSAssar Westerlund 	    for (u = utmp ; u < &utmp[nutmp] ; u++) {
150513e3f4d6SMark Murray 		if (strncmp(u->ut_line,
150613e3f4d6SMark Murray 			    clean_tty,
150713e3f4d6SMark Murray 			    sizeof(u->ut_line)) ||
150813e3f4d6SMark Murray 		    u->ut_name[0]==0)
150913e3f4d6SMark Murray 		    continue;
151013e3f4d6SMark Murray 		lseek(f, ((long)u)-((long)utmp), L_SET);
151113e3f4d6SMark Murray 		strncpy(u->ut_name,  "", sizeof(u->ut_name));
151213e3f4d6SMark Murray #ifdef HAVE_STRUCT_UTMP_UT_HOST
151313e3f4d6SMark Murray 		strncpy(u->ut_host,  "", sizeof(u->ut_host));
151413e3f4d6SMark Murray #endif
151513e3f4d6SMark Murray 		u->ut_time = time(NULL);
151613e3f4d6SMark Murray 		write(f, u, sizeof(wtmp));
151713e3f4d6SMark Murray 		found++;
151813e3f4d6SMark Murray 	    }
15195e9cd1aeSAssar Westerlund 	}
152013e3f4d6SMark Murray 	close(f);
152113e3f4d6SMark Murray     }
152213e3f4d6SMark Murray     if (found) {
152313e3f4d6SMark Murray 	f = open(wtmpf, O_WRONLY|O_APPEND);
152413e3f4d6SMark Murray 	if (f >= 0) {
152513e3f4d6SMark Murray 	    strncpy(wtmp.ut_line,  clean_tty, sizeof(wtmp.ut_line));
152613e3f4d6SMark Murray 	    strncpy(wtmp.ut_name,  "", sizeof(wtmp.ut_name));
152713e3f4d6SMark Murray #ifdef HAVE_STRUCT_UTMP_UT_HOST
152813e3f4d6SMark Murray 	    strncpy(wtmp.ut_host,  "", sizeof(wtmp.ut_host));
152913e3f4d6SMark Murray #endif
153013e3f4d6SMark Murray 	    wtmp.ut_time = time(NULL);
153113e3f4d6SMark Murray 	    write(f, &wtmp, sizeof(wtmp));
153213e3f4d6SMark Murray 	    close(f);
153313e3f4d6SMark Murray 	}
153413e3f4d6SMark Murray     }
153513e3f4d6SMark Murray     chmod(line, 0666);
153613e3f4d6SMark Murray     chown(line, 0, 0);
153713e3f4d6SMark Murray     line[strlen("/dev/")] = 'p';
153813e3f4d6SMark Murray     chmod(line, 0666);
153913e3f4d6SMark Murray     chown(line, 0, 0);
154013e3f4d6SMark Murray }  /* end of rmut */
154113e3f4d6SMark Murray #endif	/* CRAY */
154213e3f4d6SMark Murray 
154313e3f4d6SMark Murray #if defined(__hpux) && !defined(HAVE_UTMPX_H)
154413e3f4d6SMark Murray static void
rmut(char * line)154513e3f4d6SMark Murray rmut (char *line)
154613e3f4d6SMark Murray {
154713e3f4d6SMark Murray     struct utmp utmp;
154813e3f4d6SMark Murray     struct utmp *utptr;
154913e3f4d6SMark Murray     int fd;			/* for /etc/wtmp */
155013e3f4d6SMark Murray 
155113e3f4d6SMark Murray     utmp.ut_type = USER_PROCESS;
155213e3f4d6SMark Murray     strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
155313e3f4d6SMark Murray     setutent();
155413e3f4d6SMark Murray     utptr = getutline(&utmp);
155513e3f4d6SMark Murray     /* write it out only if it exists */
155613e3f4d6SMark Murray     if (utptr) {
155713e3f4d6SMark Murray 	utptr->ut_type = DEAD_PROCESS;
155813e3f4d6SMark Murray 	utptr->ut_time = time(NULL);
155913e3f4d6SMark Murray 	pututline(utptr);
156013e3f4d6SMark Murray 	/* set wtmp entry if wtmp file exists */
156113e3f4d6SMark Murray 	if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
156213e3f4d6SMark Murray 	    write(fd, utptr, sizeof(utmp));
156313e3f4d6SMark Murray 	    close(fd);
156413e3f4d6SMark Murray 	}
156513e3f4d6SMark Murray     }
156613e3f4d6SMark Murray     endutent();
156713e3f4d6SMark Murray 
156813e3f4d6SMark Murray     chmod(line, 0666);
156913e3f4d6SMark Murray     chown(line, 0, 0);
157013e3f4d6SMark Murray     line[14] = line[13];
157113e3f4d6SMark Murray     line[13] = line[12];
157213e3f4d6SMark Murray     line[8] = 'm';
157313e3f4d6SMark Murray     line[9] = '/';
157413e3f4d6SMark Murray     line[10] = 'p';
157513e3f4d6SMark Murray     line[11] = 't';
157613e3f4d6SMark Murray     line[12] = 'y';
157713e3f4d6SMark Murray     chmod(line, 0666);
157813e3f4d6SMark Murray     chown(line, 0, 0);
157913e3f4d6SMark Murray }
158013e3f4d6SMark Murray #endif
158113e3f4d6SMark Murray 
158213e3f4d6SMark Murray /*
158313e3f4d6SMark Murray  * cleanup()
158413e3f4d6SMark Murray  *
158513e3f4d6SMark Murray  * This is the routine to call when we are all through, to
158613e3f4d6SMark Murray  * clean up anything that needs to be cleaned up.
158713e3f4d6SMark Murray  */
158813e3f4d6SMark Murray 
158913e3f4d6SMark Murray #ifdef PARENT_DOES_UTMP
159013e3f4d6SMark Murray 
159113e3f4d6SMark Murray void
cleanup(int sig)159213e3f4d6SMark Murray cleanup(int sig)
159313e3f4d6SMark Murray {
159413e3f4d6SMark Murray #ifdef _CRAY
159513e3f4d6SMark Murray     static int incleanup = 0;
159613e3f4d6SMark Murray     int t;
159713e3f4d6SMark Murray     int child_status; /* status of child process as returned by waitpid */
159813e3f4d6SMark Murray     int flags = WNOHANG|WUNTRACED;
159913e3f4d6SMark Murray 
160013e3f4d6SMark Murray     /*
160113e3f4d6SMark Murray      * 1: Pick up the zombie, if we are being called
160213e3f4d6SMark Murray      *    as the signal handler.
160313e3f4d6SMark Murray      * 2: If we are a nested cleanup(), return.
160413e3f4d6SMark Murray      * 3: Try to clean up TMPDIR.
160513e3f4d6SMark Murray      * 4: Fill in utmp with shutdown of process.
160613e3f4d6SMark Murray      * 5: Close down the network and pty connections.
160713e3f4d6SMark Murray      * 6: Finish up the TMPDIR cleanup, if needed.
160813e3f4d6SMark Murray      */
160913e3f4d6SMark Murray     if (sig == SIGCHLD) {
161013e3f4d6SMark Murray 	while (waitpid(-1, &child_status, flags) > 0)
161113e3f4d6SMark Murray 	    ;	/* VOID */
161213e3f4d6SMark Murray 	/* Check if the child process was stopped
161313e3f4d6SMark Murray 	 * rather than exited.  We want cleanup only if
161413e3f4d6SMark Murray 	 * the child has died.
161513e3f4d6SMark Murray 	 */
161613e3f4d6SMark Murray 	if (WIFSTOPPED(child_status)) {
161713e3f4d6SMark Murray 	    return;
161813e3f4d6SMark Murray 	}
161913e3f4d6SMark Murray     }
162013e3f4d6SMark Murray     t = sigblock(sigmask(SIGCHLD));
162113e3f4d6SMark Murray     if (incleanup) {
162213e3f4d6SMark Murray 	sigsetmask(t);
162313e3f4d6SMark Murray 	return;
162413e3f4d6SMark Murray     }
162513e3f4d6SMark Murray     incleanup = 1;
162613e3f4d6SMark Murray     sigsetmask(t);
162713e3f4d6SMark Murray 
162813e3f4d6SMark Murray     t = cleantmp(&wtmp);
162913e3f4d6SMark Murray     setutent();	/* just to make sure */
163013e3f4d6SMark Murray #endif /* CRAY */
163113e3f4d6SMark Murray     rmut(line);
163213e3f4d6SMark Murray     close(ourpty);
163313e3f4d6SMark Murray     shutdown(net, 2);
163413e3f4d6SMark Murray #ifdef _CRAY
163513e3f4d6SMark Murray     if (t == 0)
163613e3f4d6SMark Murray 	cleantmp(&wtmp);
163713e3f4d6SMark Murray #endif /* CRAY */
163813e3f4d6SMark Murray     exit(1);
163913e3f4d6SMark Murray }
164013e3f4d6SMark Murray 
164113e3f4d6SMark Murray #else /* PARENT_DOES_UTMP */
164213e3f4d6SMark Murray 
164313e3f4d6SMark Murray void
cleanup(int sig)164413e3f4d6SMark Murray cleanup(int sig)
164513e3f4d6SMark Murray {
164613e3f4d6SMark Murray #if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
164713e3f4d6SMark Murray     rmut();
164813e3f4d6SMark Murray #ifdef HAVE_VHANGUP
164913e3f4d6SMark Murray #ifndef __sgi
165013e3f4d6SMark Murray     vhangup(); /* XXX */
165113e3f4d6SMark Murray #endif
165213e3f4d6SMark Murray #endif
165313e3f4d6SMark Murray #else
165413e3f4d6SMark Murray     char *p;
165513e3f4d6SMark Murray 
165613e3f4d6SMark Murray     p = line + sizeof("/dev/") - 1;
165713e3f4d6SMark Murray     if (logout(p))
165813e3f4d6SMark Murray 	logwtmp(p, "", "");
165913e3f4d6SMark Murray     chmod(line, 0666);
166013e3f4d6SMark Murray     chown(line, 0, 0);
166113e3f4d6SMark Murray     *p = 'p';
166213e3f4d6SMark Murray     chmod(line, 0666);
166313e3f4d6SMark Murray     chown(line, 0, 0);
166413e3f4d6SMark Murray #endif
166513e3f4d6SMark Murray     shutdown(net, 2);
166613e3f4d6SMark Murray     exit(1);
166713e3f4d6SMark Murray }
166813e3f4d6SMark Murray 
166913e3f4d6SMark Murray #endif /* PARENT_DOES_UTMP */
167013e3f4d6SMark Murray 
167113e3f4d6SMark Murray #ifdef PARENT_DOES_UTMP
167213e3f4d6SMark Murray /*
167313e3f4d6SMark Murray  * _utmp_sig_rcv
167413e3f4d6SMark Murray  * utmp_sig_init
167513e3f4d6SMark Murray  * utmp_sig_wait
167613e3f4d6SMark Murray  *	These three functions are used to coordinate the handling of
167713e3f4d6SMark Murray  *	the utmp file between the server and the soon-to-be-login shell.
167813e3f4d6SMark Murray  *	The server actually creates the utmp structure, the child calls
167913e3f4d6SMark Murray  *	utmp_sig_wait(), until the server calls utmp_sig_notify() and
168013e3f4d6SMark Murray  *	signals the future-login shell to proceed.
168113e3f4d6SMark Murray  */
168213e3f4d6SMark Murray static int caught=0;		/* NZ when signal intercepted */
168313e3f4d6SMark Murray static void (*func)();		/* address of previous handler */
168413e3f4d6SMark Murray 
168513e3f4d6SMark Murray void
_utmp_sig_rcv(sig)168613e3f4d6SMark Murray _utmp_sig_rcv(sig)
168713e3f4d6SMark Murray      int sig;
168813e3f4d6SMark Murray {
168913e3f4d6SMark Murray     caught = 1;
169013e3f4d6SMark Murray     signal(SIGUSR1, func);
169113e3f4d6SMark Murray }
169213e3f4d6SMark Murray 
169313e3f4d6SMark Murray void
utmp_sig_init()169413e3f4d6SMark Murray utmp_sig_init()
169513e3f4d6SMark Murray {
169613e3f4d6SMark Murray     /*
169713e3f4d6SMark Murray      * register signal handler for UTMP creation
169813e3f4d6SMark Murray      */
169913e3f4d6SMark Murray     if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
170013e3f4d6SMark Murray 	fatalperror(net, "telnetd/signal");
170113e3f4d6SMark Murray }
170213e3f4d6SMark Murray 
170313e3f4d6SMark Murray void
utmp_sig_reset()170413e3f4d6SMark Murray utmp_sig_reset()
170513e3f4d6SMark Murray {
170613e3f4d6SMark Murray     signal(SIGUSR1, func);	/* reset handler to default */
170713e3f4d6SMark Murray }
170813e3f4d6SMark Murray 
170913e3f4d6SMark Murray # ifdef __hpux
171013e3f4d6SMark Murray # define sigoff() /* do nothing */
171113e3f4d6SMark Murray # define sigon() /* do nothing */
171213e3f4d6SMark Murray # endif
171313e3f4d6SMark Murray 
171413e3f4d6SMark Murray void
utmp_sig_wait()171513e3f4d6SMark Murray utmp_sig_wait()
171613e3f4d6SMark Murray {
171713e3f4d6SMark Murray     /*
171813e3f4d6SMark Murray      * Wait for parent to write our utmp entry.
171913e3f4d6SMark Murray 	 */
172013e3f4d6SMark Murray     sigoff();
172113e3f4d6SMark Murray     while (caught == 0) {
172213e3f4d6SMark Murray 	pause();	/* wait until we get a signal (sigon) */
172313e3f4d6SMark Murray 	sigoff();	/* turn off signals while we check caught */
172413e3f4d6SMark Murray     }
172513e3f4d6SMark Murray     sigon();		/* turn on signals again */
172613e3f4d6SMark Murray }
172713e3f4d6SMark Murray 
172813e3f4d6SMark Murray void
utmp_sig_notify(pid)172913e3f4d6SMark Murray utmp_sig_notify(pid)
173013e3f4d6SMark Murray {
173113e3f4d6SMark Murray     kill(pid, SIGUSR1);
173213e3f4d6SMark Murray }
173313e3f4d6SMark Murray 
173413e3f4d6SMark Murray #ifdef _CRAY
173513e3f4d6SMark Murray static int gotsigjob = 0;
173613e3f4d6SMark Murray 
173713e3f4d6SMark Murray 	/*ARGSUSED*/
173813e3f4d6SMark Murray void
sigjob(sig)173913e3f4d6SMark Murray sigjob(sig)
174013e3f4d6SMark Murray      int sig;
174113e3f4d6SMark Murray {
174213e3f4d6SMark Murray     int jid;
174313e3f4d6SMark Murray     struct jobtemp *jp;
174413e3f4d6SMark Murray 
174513e3f4d6SMark Murray     while ((jid = waitjob(NULL)) != -1) {
174613e3f4d6SMark Murray 	if (jid == 0) {
174713e3f4d6SMark Murray 	    return;
174813e3f4d6SMark Murray 	}
174913e3f4d6SMark Murray 	gotsigjob++;
175013e3f4d6SMark Murray 	jobend(jid, NULL, NULL);
175113e3f4d6SMark Murray     }
175213e3f4d6SMark Murray }
175313e3f4d6SMark Murray 
175413e3f4d6SMark Murray /*
175513e3f4d6SMark Murray  *	jid_getutid:
175613e3f4d6SMark Murray  *		called by jobend() before calling cleantmp()
175713e3f4d6SMark Murray  *		to find the correct $TMPDIR to cleanup.
175813e3f4d6SMark Murray  */
175913e3f4d6SMark Murray 
176013e3f4d6SMark Murray struct utmp *
jid_getutid(jid)176113e3f4d6SMark Murray jid_getutid(jid)
176213e3f4d6SMark Murray      int jid;
176313e3f4d6SMark Murray {
176413e3f4d6SMark Murray     struct utmp *cur = NULL;
176513e3f4d6SMark Murray 
176613e3f4d6SMark Murray     setutent();	/* just to make sure */
176713e3f4d6SMark Murray     while (cur = getutent()) {
176813e3f4d6SMark Murray 	if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
176913e3f4d6SMark Murray 	    return(cur);
177013e3f4d6SMark Murray 	}
177113e3f4d6SMark Murray     }
177213e3f4d6SMark Murray 
177313e3f4d6SMark Murray     return(0);
177413e3f4d6SMark Murray }
177513e3f4d6SMark Murray 
177613e3f4d6SMark Murray /*
177713e3f4d6SMark Murray  * Clean up the TMPDIR that login created.
177813e3f4d6SMark Murray  * The first time this is called we pick up the info
177913e3f4d6SMark Murray  * from the utmp.  If the job has already gone away,
178013e3f4d6SMark Murray  * then we'll clean up and be done.  If not, then
178113e3f4d6SMark Murray  * when this is called the second time it will wait
178213e3f4d6SMark Murray  * for the signal that the job is done.
178313e3f4d6SMark Murray  */
178413e3f4d6SMark Murray int
cleantmp(wtp)178513e3f4d6SMark Murray cleantmp(wtp)
178613e3f4d6SMark Murray      struct utmp *wtp;
178713e3f4d6SMark Murray {
178813e3f4d6SMark Murray     struct utmp *utp;
178913e3f4d6SMark Murray     static int first = 1;
179013e3f4d6SMark Murray     int mask, omask, ret;
179113e3f4d6SMark Murray     extern struct utmp *getutid (const struct utmp *_Id);
179213e3f4d6SMark Murray 
179313e3f4d6SMark Murray 
179413e3f4d6SMark Murray     mask = sigmask(WJSIGNAL);
179513e3f4d6SMark Murray 
179613e3f4d6SMark Murray     if (first == 0) {
179713e3f4d6SMark Murray 	omask = sigblock(mask);
179813e3f4d6SMark Murray 	while (gotsigjob == 0)
179913e3f4d6SMark Murray 	    sigpause(omask);
180013e3f4d6SMark Murray 	return(1);
180113e3f4d6SMark Murray     }
180213e3f4d6SMark Murray     first = 0;
180313e3f4d6SMark Murray     setutent();	/* just to make sure */
180413e3f4d6SMark Murray 
180513e3f4d6SMark Murray     utp = getutid(wtp);
180613e3f4d6SMark Murray     if (utp == 0) {
180713e3f4d6SMark Murray 	syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
180813e3f4d6SMark Murray 	return(-1);
180913e3f4d6SMark Murray     }
181013e3f4d6SMark Murray     /*
181113e3f4d6SMark Murray      * Nothing to clean up if the user shell was never started.
181213e3f4d6SMark Murray      */
181313e3f4d6SMark Murray     if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
181413e3f4d6SMark Murray 	return(1);
181513e3f4d6SMark Murray 
181613e3f4d6SMark Murray     /*
181713e3f4d6SMark Murray      * Block the WJSIGNAL while we are in jobend().
181813e3f4d6SMark Murray      */
181913e3f4d6SMark Murray     omask = sigblock(mask);
182013e3f4d6SMark Murray     ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
182113e3f4d6SMark Murray     sigsetmask(omask);
182213e3f4d6SMark Murray     return(ret);
182313e3f4d6SMark Murray }
182413e3f4d6SMark Murray 
182513e3f4d6SMark Murray int
jobend(jid,path,user)182613e3f4d6SMark Murray jobend(jid, path, user)
182713e3f4d6SMark Murray      int jid;
182813e3f4d6SMark Murray      char *path;
182913e3f4d6SMark Murray      char *user;
183013e3f4d6SMark Murray {
183113e3f4d6SMark Murray     static int saved_jid = 0;
183213e3f4d6SMark Murray     static int pty_saved_jid = 0;
183313e3f4d6SMark Murray     static char saved_path[sizeof(wtmp.ut_tpath)+1];
183413e3f4d6SMark Murray     static char saved_user[sizeof(wtmp.ut_user)+1];
183513e3f4d6SMark Murray 
183613e3f4d6SMark Murray     /*
183713e3f4d6SMark Murray      * this little piece of code comes into play
183813e3f4d6SMark Murray      * only when ptyreconnect is used to reconnect
183913e3f4d6SMark Murray      * to an previous session.
184013e3f4d6SMark Murray      *
184113e3f4d6SMark Murray      * this is the only time when the
184213e3f4d6SMark Murray      * "saved_jid != jid" code is executed.
1843c19800e8SDoug Rabson      */
1844c19800e8SDoug Rabson 
184513e3f4d6SMark Murray     if ( saved_jid && saved_jid != jid ) {
184613e3f4d6SMark Murray 	if (!path) {	/* called from signal handler */
184713e3f4d6SMark Murray 	    pty_saved_jid = jid;
184813e3f4d6SMark Murray 	} else {
184913e3f4d6SMark Murray 	    pty_saved_jid = saved_jid;
185013e3f4d6SMark Murray 	}
185113e3f4d6SMark Murray     }
185213e3f4d6SMark Murray 
185313e3f4d6SMark Murray     if (path) {
185413e3f4d6SMark Murray 	strlcpy(saved_path, path, sizeof(saved_path));
185513e3f4d6SMark Murray 	strlcpy(saved_user, user, sizeof(saved_user));
185613e3f4d6SMark Murray     }
185713e3f4d6SMark Murray     if (saved_jid == 0) {
185813e3f4d6SMark Murray 	saved_jid = jid;
185913e3f4d6SMark Murray 	return(0);
186013e3f4d6SMark Murray     }
186113e3f4d6SMark Murray 
186213e3f4d6SMark Murray     /* if the jid has changed, get the correct entry from the utmp file */
186313e3f4d6SMark Murray 
186413e3f4d6SMark Murray     if ( saved_jid != jid ) {
186513e3f4d6SMark Murray 	struct utmp *utp = NULL;
186613e3f4d6SMark Murray 	struct utmp *jid_getutid();
186713e3f4d6SMark Murray 
186813e3f4d6SMark Murray 	utp = jid_getutid(pty_saved_jid);
186913e3f4d6SMark Murray 
187013e3f4d6SMark Murray 	if (utp == 0) {
187113e3f4d6SMark Murray 	    syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
187213e3f4d6SMark Murray 	    return(-1);
187313e3f4d6SMark Murray 	}
187413e3f4d6SMark Murray 
187513e3f4d6SMark Murray 	cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
187613e3f4d6SMark Murray 	return(1);
187713e3f4d6SMark Murray     }
187813e3f4d6SMark Murray 
187913e3f4d6SMark Murray     cleantmpdir(jid, saved_path, saved_user);
188013e3f4d6SMark Murray     return(1);
188113e3f4d6SMark Murray }
188213e3f4d6SMark Murray 
188313e3f4d6SMark Murray /*
188413e3f4d6SMark Murray  * Fork a child process to clean up the TMPDIR
188513e3f4d6SMark Murray  */
cleantmpdir(jid,tpath,user)1886c19800e8SDoug Rabson cleantmpdir(jid, tpath, user)
188713e3f4d6SMark Murray      int jid;
188813e3f4d6SMark Murray      char *tpath;
188913e3f4d6SMark Murray      char *user;
189013e3f4d6SMark Murray {
189113e3f4d6SMark Murray     switch(fork()) {
189213e3f4d6SMark Murray     case -1:
189313e3f4d6SMark Murray 	syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
189413e3f4d6SMark Murray 	       tpath);
189513e3f4d6SMark Murray 	break;
189613e3f4d6SMark Murray     case 0:
189713e3f4d6SMark Murray 	execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, NULL);
189813e3f4d6SMark Murray 	syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
189913e3f4d6SMark Murray 	       tpath, CLEANTMPCMD);
1900 	exit(1);
1901     default:
1902 	/*
1903 	 * Forget about child.  We will exit, and
1904 	 * /etc/init will pick it up.
1905 	 */
1906 	break;
1907     }
1908 }
1909 #endif /* CRAY */
1910 #endif	/* defined(PARENT_DOES_UTMP) */
1911