157416Smarkm/*
257416Smarkm * Copyright (c) 1989, 1993
357416Smarkm *	The Regents of the University of California.  All rights reserved.
457416Smarkm *
557416Smarkm * Redistribution and use in source and binary forms, with or without
657416Smarkm * modification, are permitted provided that the following conditions
757416Smarkm * are met:
857416Smarkm * 1. Redistributions of source code must retain the above copyright
957416Smarkm *    notice, this list of conditions and the following disclaimer.
1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1157416Smarkm *    notice, this list of conditions and the following disclaimer in the
1257416Smarkm *    documentation and/or other materials provided with the distribution.
1357416Smarkm * 3. All advertising materials mentioning features or use of this software
1457416Smarkm *    must display the following acknowledgement:
1557416Smarkm *	This product includes software developed by the University of
1657416Smarkm *	California, Berkeley and its contributors.
1757416Smarkm * 4. Neither the name of the University nor the names of its contributors
1857416Smarkm *    may be used to endorse or promote products derived from this software
1957416Smarkm *    without specific prior written permission.
2057416Smarkm *
2157416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2257416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2357416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2457416Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2557416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2657416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2757416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2857416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2957416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3057416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3157416Smarkm * SUCH DAMAGE.
3257416Smarkm */
3357416Smarkm
3457416Smarkm#include "telnetd.h"
3557416Smarkm
36233294SstasRCSID("$Id$");
3757416Smarkm
3857416Smarkm#if defined(_CRAY) || (defined(__hpux) && !defined(HAVE_UTMPX_H))
3957416Smarkm# define PARENT_DOES_UTMP
4057416Smarkm#endif
4157416Smarkm
4257416Smarkm#ifdef HAVE_UTMP_H
4357416Smarkm#include <utmp.h>
4457416Smarkm#endif
4557416Smarkm
4657416Smarkm#ifdef HAVE_UTMPX_H
4757416Smarkm#include <utmpx.h>
4857416Smarkm#endif
4957416Smarkm
5057416Smarkm#ifdef HAVE_UTMPX_H
5157416Smarkmstruct	utmpx wtmp;
5257416Smarkm#elif defined(HAVE_UTMP_H)
5357416Smarkmstruct	utmp wtmp;
5457416Smarkm#endif /* HAVE_UTMPX_H */
5557416Smarkm
5657416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_HOST
5757416Smarkmint	utmp_len = sizeof(wtmp.ut_host);
5857416Smarkm#else
5957416Smarkmint	utmp_len = MaxHostNameLen;
6057416Smarkm#endif
6157416Smarkm
6257416Smarkm#ifndef UTMP_FILE
6357416Smarkm#ifdef _PATH_UTMP
6457416Smarkm#define UTMP_FILE _PATH_UTMP
6557416Smarkm#else
6657416Smarkm#define UTMP_FILE "/etc/utmp"
6757416Smarkm#endif
6857416Smarkm#endif
6957416Smarkm
70233294Sstas/* really, mac os uses wtmpx (or asl) */
71233294Sstas#ifdef __APPLE__
72233294Sstas#undef _PATH_WTMP
73233294Sstas#endif
74233294Sstas
7557416Smarkm#if !defined(WTMP_FILE) && defined(_PATH_WTMP)
7657416Smarkm#define WTMP_FILE _PATH_WTMP
7757416Smarkm#endif
7857416Smarkm
7957416Smarkm#ifndef PARENT_DOES_UTMP
8057416Smarkm#ifdef WTMP_FILE
8157416Smarkmchar	wtmpf[] = WTMP_FILE;
8257416Smarkm#else
8357416Smarkmchar	wtmpf[]	= "/usr/adm/wtmp";
8457416Smarkm#endif
8557416Smarkmchar	utmpf[] = UTMP_FILE;
8657416Smarkm#else /* PARENT_DOES_UTMP */
8757416Smarkm#ifdef WTMP_FILE
8857416Smarkmchar	wtmpf[] = WTMP_FILE;
8957416Smarkm#else
9057416Smarkmchar	wtmpf[]	= "/etc/wtmp";
9157416Smarkm#endif
9257416Smarkm#endif /* PARENT_DOES_UTMP */
9357416Smarkm
9457416Smarkm#ifdef HAVE_TMPDIR_H
9557416Smarkm#include <tmpdir.h>
9657416Smarkm#endif	/* CRAY */
9757416Smarkm
9857416Smarkm#if !(defined(__sgi) || defined(__linux) || defined(_AIX)) && defined(HAVE_SYS_TTY)
9957416Smarkm#include <sys/tty.h>
10057416Smarkm#endif
10157416Smarkm#ifdef	t_erase
10257416Smarkm#undef	t_erase
10357416Smarkm#undef	t_kill
10457416Smarkm#undef	t_intrc
10557416Smarkm#undef	t_quitc
10657416Smarkm#undef	t_startc
10757416Smarkm#undef	t_stopc
10857416Smarkm#undef	t_eofc
10957416Smarkm#undef	t_brkc
11057416Smarkm#undef	t_suspc
11157416Smarkm#undef	t_dsuspc
11257416Smarkm#undef	t_rprntc
11357416Smarkm#undef	t_flushc
11457416Smarkm#undef	t_werasc
11557416Smarkm#undef	t_lnextc
11657416Smarkm#endif
11757416Smarkm
11857416Smarkm#ifdef HAVE_TERMIOS_H
11957416Smarkm#include <termios.h>
12057416Smarkm#else
12157416Smarkm#ifdef HAVE_TERMIO_H
12257416Smarkm#include <termio.h>
12357416Smarkm#endif
12457416Smarkm#endif
12557416Smarkm
12657416Smarkm#ifdef HAVE_UTIL_H
12757416Smarkm#include <util.h>
12857416Smarkm#endif
12990926Snectar#ifdef HAVE_LIBUTIL_H
13090926Snectar#include <libutil.h>
13190926Snectar#endif
13257416Smarkm
13357416Smarkm# ifndef	TCSANOW
13457416Smarkm#  ifdef TCSETS
13557416Smarkm#   define	TCSANOW		TCSETS
13657416Smarkm#   define	TCSADRAIN	TCSETSW
13757416Smarkm#   define	tcgetattr(f, t)	ioctl(f, TCGETS, (char *)t)
13857416Smarkm#  else
13957416Smarkm#   ifdef TCSETA
14057416Smarkm#    define	TCSANOW		TCSETA
14157416Smarkm#    define	TCSADRAIN	TCSETAW
14257416Smarkm#    define	tcgetattr(f, t)	ioctl(f, TCGETA, (char *)t)
14357416Smarkm#   else
14457416Smarkm#    define	TCSANOW		TIOCSETA
14557416Smarkm#    define	TCSADRAIN	TIOCSETAW
14657416Smarkm#    define	tcgetattr(f, t)	ioctl(f, TIOCGETA, (char *)t)
14757416Smarkm#   endif
14857416Smarkm#  endif
14957416Smarkm#  define	tcsetattr(f, a, t)	ioctl(f, a, t)
15057416Smarkm#  define	cfsetospeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
15157416Smarkm(tp)->c_cflag |= (val)
15257416Smarkm#  define	cfgetospeed(tp)		((tp)->c_cflag & CBAUD)
15357416Smarkm#  ifdef CIBAUD
15457416Smarkm#   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CIBAUD; \
15557416Smarkm     (tp)->c_cflag |= ((val)<<IBSHIFT)
15657416Smarkm#   define	cfgetispeed(tp)		(((tp)->c_cflag & CIBAUD)>>IBSHIFT)
15757416Smarkm#  else
15857416Smarkm#   define	cfsetispeed(tp, val)	(tp)->c_cflag &= ~CBAUD; \
15957416Smarkm     (tp)->c_cflag |= (val)
16057416Smarkm#   define	cfgetispeed(tp)		((tp)->c_cflag & CBAUD)
16157416Smarkm#  endif
16257416Smarkm# endif /* TCSANOW */
16357416Smarkm     struct termios termbuf, termbuf2;	/* pty control structure */
16457416Smarkm# ifdef  STREAMSPTY
16557416Smarkm     static int ttyfd = -1;
16657416Smarkm     int really_stream = 0;
167233294Sstas# else
168233294Sstas#define really_stream 0
16957416Smarkm# endif
17057416Smarkm
17157416Smarkm     const char *new_login = _PATH_LOGIN;
17257416Smarkm
17357416Smarkm/*
17457416Smarkm * init_termbuf()
17557416Smarkm * copy_termbuf(cp)
17657416Smarkm * set_termbuf()
17757416Smarkm *
17857416Smarkm * These three routines are used to get and set the "termbuf" structure
17957416Smarkm * to and from the kernel.  init_termbuf() gets the current settings.
18057416Smarkm * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
18157416Smarkm * set_termbuf() writes the structure into the kernel.
18257416Smarkm */
18357416Smarkm
18457416Smarkm     void
18557416Smarkm     init_termbuf(void)
18657416Smarkm{
18757416Smarkm# ifdef  STREAMSPTY
18857416Smarkm    if (really_stream)
18957416Smarkm	tcgetattr(ttyfd, &termbuf);
19057416Smarkm    else
19157416Smarkm# endif
19257416Smarkm	tcgetattr(ourpty, &termbuf);
19357416Smarkm    termbuf2 = termbuf;
19457416Smarkm}
19557416Smarkm
19657416Smarkmvoid
19757416Smarkmset_termbuf(void)
19857416Smarkm{
19957416Smarkm    /*
20057416Smarkm     * Only make the necessary changes.
20157416Smarkm	 */
202178825Sdfr    if (memcmp(&termbuf, &termbuf2, sizeof(termbuf))) {
20357416Smarkm# ifdef  STREAMSPTY
20457416Smarkm	if (really_stream)
20557416Smarkm	    tcsetattr(ttyfd, TCSANOW, &termbuf);
20657416Smarkm	else
20757416Smarkm# endif
20857416Smarkm	    tcsetattr(ourpty, TCSANOW, &termbuf);
209178825Sdfr    }
21057416Smarkm}
21157416Smarkm
21257416Smarkm
21357416Smarkm/*
21457416Smarkm * spcset(func, valp, valpp)
21557416Smarkm *
21657416Smarkm * This function takes various special characters (func), and
21757416Smarkm * sets *valp to the current value of that character, and
21857416Smarkm * *valpp to point to where in the "termbuf" structure that
21957416Smarkm * value is kept.
22057416Smarkm *
22157416Smarkm * It returns the SLC_ level of support for this function.
22257416Smarkm */
22357416Smarkm
22457416Smarkm
22557416Smarkmint
22657416Smarkmspcset(int func, cc_t *valp, cc_t **valpp)
22757416Smarkm{
22857416Smarkm
22957416Smarkm#define	setval(a, b)	*valp = termbuf.c_cc[a]; \
23057416Smarkm    *valpp = &termbuf.c_cc[a]; \
23157416Smarkm				   return(b);
23257416Smarkm#define	defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT);
23357416Smarkm
23457416Smarkm    switch(func) {
23557416Smarkm    case SLC_EOF:
23657416Smarkm	setval(VEOF, SLC_VARIABLE);
23757416Smarkm    case SLC_EC:
23857416Smarkm	setval(VERASE, SLC_VARIABLE);
23957416Smarkm    case SLC_EL:
24057416Smarkm	setval(VKILL, SLC_VARIABLE);
24157416Smarkm    case SLC_IP:
24257416Smarkm	setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
24357416Smarkm    case SLC_ABORT:
24457416Smarkm	setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
24557416Smarkm    case SLC_XON:
24657416Smarkm#ifdef	VSTART
24757416Smarkm	setval(VSTART, SLC_VARIABLE);
24857416Smarkm#else
24957416Smarkm	defval(0x13);
25057416Smarkm#endif
25157416Smarkm    case SLC_XOFF:
25257416Smarkm#ifdef	VSTOP
25357416Smarkm	setval(VSTOP, SLC_VARIABLE);
25457416Smarkm#else
25557416Smarkm	defval(0x11);
25657416Smarkm#endif
25757416Smarkm    case SLC_EW:
25857416Smarkm#ifdef	VWERASE
25957416Smarkm	setval(VWERASE, SLC_VARIABLE);
26057416Smarkm#else
26157416Smarkm	defval(0);
26257416Smarkm#endif
26357416Smarkm    case SLC_RP:
26457416Smarkm#ifdef	VREPRINT
26557416Smarkm	setval(VREPRINT, SLC_VARIABLE);
26657416Smarkm#else
26757416Smarkm	defval(0);
26857416Smarkm#endif
26957416Smarkm    case SLC_LNEXT:
27057416Smarkm#ifdef	VLNEXT
27157416Smarkm	setval(VLNEXT, SLC_VARIABLE);
27257416Smarkm#else
27357416Smarkm	defval(0);
27457416Smarkm#endif
27557416Smarkm    case SLC_AO:
27657416Smarkm#if	!defined(VDISCARD) && defined(VFLUSHO)
27757416Smarkm# define VDISCARD VFLUSHO
27857416Smarkm#endif
27957416Smarkm#ifdef	VDISCARD
28057416Smarkm	setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT);
28157416Smarkm#else
28257416Smarkm	defval(0);
28357416Smarkm#endif
28457416Smarkm    case SLC_SUSP:
28557416Smarkm#ifdef	VSUSP
28657416Smarkm	setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN);
28757416Smarkm#else
28857416Smarkm	defval(0);
28957416Smarkm#endif
29057416Smarkm#ifdef	VEOL
29157416Smarkm    case SLC_FORW1:
29257416Smarkm	setval(VEOL, SLC_VARIABLE);
29357416Smarkm#endif
29457416Smarkm#ifdef	VEOL2
29557416Smarkm    case SLC_FORW2:
29657416Smarkm	setval(VEOL2, SLC_VARIABLE);
29757416Smarkm#endif
29857416Smarkm    case SLC_AYT:
29957416Smarkm#ifdef	VSTATUS
30057416Smarkm	setval(VSTATUS, SLC_VARIABLE);
30157416Smarkm#else
30257416Smarkm	defval(0);
30357416Smarkm#endif
30457416Smarkm
30557416Smarkm    case SLC_BRK:
30657416Smarkm    case SLC_SYNCH:
30757416Smarkm    case SLC_EOR:
30857416Smarkm	defval(0);
30957416Smarkm
31057416Smarkm    default:
31157416Smarkm	*valp = 0;
31257416Smarkm	*valpp = 0;
31357416Smarkm	return(SLC_NOSUPPORT);
31457416Smarkm    }
31557416Smarkm}
31657416Smarkm
31757416Smarkm#ifdef _CRAY
31857416Smarkm/*
31957416Smarkm * getnpty()
32057416Smarkm *
32157416Smarkm * Return the number of pty's configured into the system.
32257416Smarkm */
32357416Smarkmint
32457416Smarkmgetnpty()
32557416Smarkm{
32657416Smarkm#ifdef _SC_CRAY_NPTY
32757416Smarkm    int numptys;
32857416Smarkm
32957416Smarkm    if ((numptys = sysconf(_SC_CRAY_NPTY)) != -1)
33057416Smarkm	return numptys;
33157416Smarkm    else
33257416Smarkm#endif /* _SC_CRAY_NPTY */
33357416Smarkm	return 128;
33457416Smarkm}
33557416Smarkm#endif /* CRAY */
33657416Smarkm
33757416Smarkm/*
33857416Smarkm * getpty()
33957416Smarkm *
34057416Smarkm * Allocate a pty.  As a side effect, the external character
34157416Smarkm * array "line" contains the name of the slave side.
34257416Smarkm *
34357416Smarkm * Returns the file descriptor of the opened pty.
34457416Smarkm */
34557416Smarkm
346178825Sdfrstatic int ptyslavefd = -1;
347178825Sdfr
34857416Smarkmstatic char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
34957416Smarkmchar *line = Xline;
35057416Smarkm
35157416Smarkm#ifdef	_CRAY
35257416Smarkmchar myline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
35357416Smarkm#endif	/* CRAY */
35457416Smarkm
35557416Smarkm#if !defined(HAVE_PTSNAME) && defined(STREAMSPTY)
35657416Smarkmstatic char *ptsname(int fd)
35757416Smarkm{
35857416Smarkm#ifdef HAVE_TTYNAME
35957416Smarkm    return ttyname(fd);
36057416Smarkm#else
36157416Smarkm    return NULL;
36257416Smarkm#endif
36357416Smarkm}
36457416Smarkm#endif
36557416Smarkm
36657416Smarkmint getpty(int *ptynum)
36757416Smarkm{
368178825Sdfr#if defined(HAVE_OPENPTY) || defined(__linux) || defined(__osf__) /* XXX */
369178825Sdfr    {
370178825Sdfr	int master;
371178825Sdfr	int slave;
372178825Sdfr	if(openpty(&master, &slave, line, 0, 0) == 0){
373178825Sdfr	    ptyslavefd = slave;
374178825Sdfr	    return master;
375178825Sdfr	}
37657416Smarkm    }
377178825Sdfr#endif /* HAVE_OPENPTY .... */
37857416Smarkm#ifdef HAVE__GETPTY
379178825Sdfr    {
380178825Sdfr	int master;
381178825Sdfr	char *p;
382178825Sdfr	p = _getpty(&master, O_RDWR, 0600, 1);
383178825Sdfr	if(p == NULL)
384178825Sdfr	    return -1;
385178825Sdfr	strlcpy(line, p, sizeof(Xline));
38657416Smarkm	return master;
38757416Smarkm    }
388178825Sdfr#endif
389233294Sstas
39057416Smarkm#ifdef	STREAMSPTY
391178825Sdfr    {
392233294Sstas	char *clone[] = { "/dev/ptc", "/dev/ptmx", "/dev/ptm",
393178825Sdfr			  "/dev/ptym/clone", 0 };
394233294Sstas
395178825Sdfr	char **q;
396178825Sdfr	int p;
397178825Sdfr	for(q=clone; *q; q++){
398178825Sdfr	    p=open(*q, O_RDWR);
399178825Sdfr	    if(p >= 0){
40057416Smarkm#ifdef HAVE_GRANTPT
401178825Sdfr		grantpt(p);
40257416Smarkm#endif
40357416Smarkm#ifdef HAVE_UNLOCKPT
404178825Sdfr		unlockpt(p);
40557416Smarkm#endif
406178825Sdfr		strlcpy(line, ptsname(p), sizeof(Xline));
407178825Sdfr		really_stream = 1;
408178825Sdfr		return p;
409178825Sdfr	    }
41057416Smarkm	}
41157416Smarkm    }
41257416Smarkm#endif /* STREAMSPTY */
41357416Smarkm#ifndef _CRAY
414178825Sdfr    {
415178825Sdfr	int p;
416178825Sdfr	char *cp, *p1, *p2;
417178825Sdfr	int i;
418233294Sstas
41957416Smarkm#ifndef	__hpux
420178825Sdfr	snprintf(line, sizeof(Xline), "/dev/ptyXX");
421178825Sdfr	p1 = &line[8];
422178825Sdfr	p2 = &line[9];
42357416Smarkm#else
424178825Sdfr	snprintf(line, sizeof(Xline), "/dev/ptym/ptyXX");
425178825Sdfr	p1 = &line[13];
426178825Sdfr	p2 = &line[14];
42757416Smarkm#endif
428233294Sstas
429233294Sstas
430178825Sdfr	for (cp = "pqrstuvwxyzPQRST"; *cp; cp++) {
431178825Sdfr	    struct stat stb;
432233294Sstas
433178825Sdfr	    *p1 = *cp;
434178825Sdfr	    *p2 = '0';
435178825Sdfr	    /*
436178825Sdfr	     * This stat() check is just to keep us from
437178825Sdfr	     * looping through all 256 combinations if there
438178825Sdfr	     * aren't that many ptys available.
439178825Sdfr	     */
440178825Sdfr	    if (stat(line, &stb) < 0)
441178825Sdfr		break;
442178825Sdfr	    for (i = 0; i < 16; i++) {
443178825Sdfr		*p2 = "0123456789abcdef"[i];
444178825Sdfr		p = open(line, O_RDWR);
445178825Sdfr		if (p > 0) {
446178825Sdfr#if SunOS == 40
447178825Sdfr		    int dummy;
448178825Sdfr#endif
449233294Sstas
45057416Smarkm#ifndef	__hpux
451178825Sdfr		    line[5] = 't';
45257416Smarkm#else
453178825Sdfr		    for (p1 = &line[8]; *p1; p1++)
454178825Sdfr			*p1 = *(p1+1);
455178825Sdfr		    line[9] = 't';
45657416Smarkm#endif
457178825Sdfr		    chown(line, 0, 0);
458178825Sdfr		    chmod(line, 0600);
45957416Smarkm#if SunOS == 40
460178825Sdfr		    if (ioctl(p, TIOCGPGRP, &dummy) == 0
461178825Sdfr			|| errno != EIO) {
462178825Sdfr			chmod(line, 0666);
463178825Sdfr			close(p);
464178825Sdfr			line[5] = 'p';
465178825Sdfr		    } else
46657416Smarkm#endif /* SunOS == 40 */
467178825Sdfr			return(p);
468178825Sdfr		}
46957416Smarkm	    }
47057416Smarkm	}
47157416Smarkm    }
47257416Smarkm#else	/* CRAY */
473178825Sdfr    {
474178825Sdfr	extern lowpty, highpty;
475178825Sdfr	struct stat sb;
476178825Sdfr	int p;
477233294Sstas
478178825Sdfr	for (*ptynum = lowpty; *ptynum <= highpty; (*ptynum)++) {
479178825Sdfr	    snprintf(myline, sizeof(myline), "/dev/pty/%03d", *ptynum);
48057416Smarkm	    p = open(myline, 2);
48157416Smarkm	    if (p < 0)
48257416Smarkm		continue;
483178825Sdfr	    snprintf(line, sizeof(Xline), "/dev/ttyp%03d", *ptynum);
484178825Sdfr	    /*
485178825Sdfr	     * Here are some shenanigans to make sure that there
486178825Sdfr	     * are no listeners lurking on the line.
487178825Sdfr	     */
488178825Sdfr	    if(stat(line, &sb) < 0) {
489178825Sdfr		close(p);
490178825Sdfr		continue;
491178825Sdfr	    }
492178825Sdfr	    if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) {
493178825Sdfr		chown(line, 0, 0);
494178825Sdfr		chmod(line, 0600);
495178825Sdfr		close(p);
496178825Sdfr		p = open(myline, 2);
497178825Sdfr		if (p < 0)
498178825Sdfr		    continue;
499178825Sdfr	    }
500178825Sdfr	    /*
501178825Sdfr	     * Now it should be safe...check for accessability.
502178825Sdfr	     */
503178825Sdfr	    if (access(line, 6) == 0)
504178825Sdfr		return(p);
505178825Sdfr	    else {
506178825Sdfr		/* no tty side to pty so skip it */
507178825Sdfr		close(p);
508178825Sdfr	    }
50957416Smarkm	}
51057416Smarkm    }
51157416Smarkm#endif	/* CRAY */
51257416Smarkm    return(-1);
51357416Smarkm}
51457416Smarkm
51557416Smarkm
51657416Smarkmint
51757416Smarkmtty_isecho(void)
51857416Smarkm{
51957416Smarkm    return (termbuf.c_lflag & ECHO);
52057416Smarkm}
52157416Smarkm
52257416Smarkmint
52357416Smarkmtty_flowmode(void)
52457416Smarkm{
52557416Smarkm    return((termbuf.c_iflag & IXON) ? 1 : 0);
52657416Smarkm}
52757416Smarkm
52857416Smarkmint
52957416Smarkmtty_restartany(void)
53057416Smarkm{
53157416Smarkm    return((termbuf.c_iflag & IXANY) ? 1 : 0);
53257416Smarkm}
53357416Smarkm
53457416Smarkmvoid
53557416Smarkmtty_setecho(int on)
53657416Smarkm{
53757416Smarkm    if (on)
53857416Smarkm	termbuf.c_lflag |= ECHO;
53957416Smarkm    else
54057416Smarkm	termbuf.c_lflag &= ~ECHO;
54157416Smarkm}
54257416Smarkm
54357416Smarkmint
54457416Smarkmtty_israw(void)
54557416Smarkm{
54657416Smarkm    return(!(termbuf.c_lflag & ICANON));
54757416Smarkm}
54857416Smarkm
54957416Smarkmvoid
55057416Smarkmtty_binaryin(int on)
55157416Smarkm{
55257416Smarkm    if (on) {
55357416Smarkm	termbuf.c_iflag &= ~ISTRIP;
55457416Smarkm    } else {
55557416Smarkm	termbuf.c_iflag |= ISTRIP;
55657416Smarkm    }
55757416Smarkm}
55857416Smarkm
55957416Smarkmvoid
56057416Smarkmtty_binaryout(int on)
56157416Smarkm{
56257416Smarkm    if (on) {
56357416Smarkm	termbuf.c_cflag &= ~(CSIZE|PARENB);
56457416Smarkm	termbuf.c_cflag |= CS8;
56557416Smarkm	termbuf.c_oflag &= ~OPOST;
56657416Smarkm    } else {
56757416Smarkm	termbuf.c_cflag &= ~CSIZE;
56857416Smarkm	termbuf.c_cflag |= CS7|PARENB;
56957416Smarkm	termbuf.c_oflag |= OPOST;
57057416Smarkm    }
57157416Smarkm}
57257416Smarkm
57357416Smarkmint
57457416Smarkmtty_isbinaryin(void)
57557416Smarkm{
57657416Smarkm    return(!(termbuf.c_iflag & ISTRIP));
57757416Smarkm}
57857416Smarkm
57957416Smarkmint
58057416Smarkmtty_isbinaryout(void)
58157416Smarkm{
58257416Smarkm    return(!(termbuf.c_oflag&OPOST));
58357416Smarkm}
58457416Smarkm
58557416Smarkm
58657416Smarkmint
58757416Smarkmtty_issofttab(void)
58857416Smarkm{
58957416Smarkm# ifdef	OXTABS
59057416Smarkm    return (termbuf.c_oflag & OXTABS);
59157416Smarkm# endif
59257416Smarkm# ifdef	TABDLY
59357416Smarkm    return ((termbuf.c_oflag & TABDLY) == TAB3);
59457416Smarkm# endif
59557416Smarkm}
59657416Smarkm
59757416Smarkmvoid
59857416Smarkmtty_setsofttab(int on)
59957416Smarkm{
60057416Smarkm    if (on) {
60157416Smarkm# ifdef	OXTABS
60257416Smarkm	termbuf.c_oflag |= OXTABS;
60357416Smarkm# endif
60457416Smarkm# ifdef	TABDLY
60557416Smarkm	termbuf.c_oflag &= ~TABDLY;
60657416Smarkm	termbuf.c_oflag |= TAB3;
60757416Smarkm# endif
60857416Smarkm    } else {
60957416Smarkm# ifdef	OXTABS
61057416Smarkm	termbuf.c_oflag &= ~OXTABS;
61157416Smarkm# endif
61257416Smarkm# ifdef	TABDLY
61357416Smarkm	termbuf.c_oflag &= ~TABDLY;
61457416Smarkm	termbuf.c_oflag |= TAB0;
61557416Smarkm# endif
61657416Smarkm    }
61757416Smarkm}
61857416Smarkm
61957416Smarkmint
62057416Smarkmtty_islitecho(void)
62157416Smarkm{
62257416Smarkm# ifdef	ECHOCTL
62357416Smarkm    return (!(termbuf.c_lflag & ECHOCTL));
62457416Smarkm# endif
62557416Smarkm# ifdef	TCTLECH
62657416Smarkm    return (!(termbuf.c_lflag & TCTLECH));
62757416Smarkm# endif
62857416Smarkm# if	!defined(ECHOCTL) && !defined(TCTLECH)
62957416Smarkm    return (0);	/* assumes ctl chars are echoed '^x' */
63057416Smarkm# endif
63157416Smarkm}
63257416Smarkm
63357416Smarkmvoid
63457416Smarkmtty_setlitecho(int on)
63557416Smarkm{
63657416Smarkm# ifdef	ECHOCTL
63757416Smarkm    if (on)
63857416Smarkm	termbuf.c_lflag &= ~ECHOCTL;
63957416Smarkm    else
64057416Smarkm	termbuf.c_lflag |= ECHOCTL;
64157416Smarkm# endif
64257416Smarkm# ifdef	TCTLECH
64357416Smarkm    if (on)
64457416Smarkm	termbuf.c_lflag &= ~TCTLECH;
64557416Smarkm    else
64657416Smarkm	termbuf.c_lflag |= TCTLECH;
64757416Smarkm# endif
64857416Smarkm}
64957416Smarkm
65057416Smarkmint
65157416Smarkmtty_iscrnl(void)
65257416Smarkm{
65357416Smarkm    return (termbuf.c_iflag & ICRNL);
65457416Smarkm}
65557416Smarkm
65657416Smarkm/*
65757416Smarkm * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
65857416Smarkm */
65957416Smarkm#if B4800 != 4800
66057416Smarkm#define	DECODE_BAUD
66157416Smarkm#endif
66257416Smarkm
66357416Smarkm#ifdef	DECODE_BAUD
66457416Smarkm
66557416Smarkm/*
66657416Smarkm * A table of available terminal speeds
66757416Smarkm */
66857416Smarkmstruct termspeeds {
66957416Smarkm    int	speed;
67057416Smarkm    int	value;
67157416Smarkm} termspeeds[] = {
67257416Smarkm    { 0,      B0 },      { 50,    B50 },    { 75,     B75 },
67357416Smarkm    { 110,    B110 },    { 134,   B134 },   { 150,    B150 },
67457416Smarkm    { 200,    B200 },    { 300,   B300 },   { 600,    B600 },
67557416Smarkm    { 1200,   B1200 },   { 1800,  B1800 },  { 2400,   B2400 },
67657416Smarkm    { 4800,   B4800 },
67757416Smarkm#ifdef	B7200
67857416Smarkm    { 7200,  B7200 },
67957416Smarkm#endif
68057416Smarkm    { 9600,   B9600 },
68157416Smarkm#ifdef	B14400
68257416Smarkm    { 14400,  B14400 },
68357416Smarkm#endif
68457416Smarkm#ifdef	B19200
68557416Smarkm    { 19200,  B19200 },
68657416Smarkm#endif
68757416Smarkm#ifdef	B28800
68857416Smarkm    { 28800,  B28800 },
68957416Smarkm#endif
69057416Smarkm#ifdef	B38400
69157416Smarkm    { 38400,  B38400 },
69257416Smarkm#endif
69357416Smarkm#ifdef	B57600
69457416Smarkm    { 57600,  B57600 },
69557416Smarkm#endif
69657416Smarkm#ifdef	B115200
69757416Smarkm    { 115200, B115200 },
69857416Smarkm#endif
69957416Smarkm#ifdef	B230400
70057416Smarkm    { 230400, B230400 },
70157416Smarkm#endif
70257416Smarkm    { -1,     0 }
70357416Smarkm};
70457416Smarkm#endif	/* DECODE_BUAD */
70557416Smarkm
70657416Smarkmvoid
70757416Smarkmtty_tspeed(int val)
70857416Smarkm{
70957416Smarkm#ifdef	DECODE_BAUD
71057416Smarkm    struct termspeeds *tp;
71157416Smarkm
71257416Smarkm    for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
71357416Smarkm	;
71457416Smarkm    if (tp->speed == -1)	/* back up to last valid value */
71557416Smarkm	--tp;
71657416Smarkm    cfsetospeed(&termbuf, tp->value);
71757416Smarkm#else	/* DECODE_BUAD */
71857416Smarkm    cfsetospeed(&termbuf, val);
71957416Smarkm#endif	/* DECODE_BUAD */
72057416Smarkm}
72157416Smarkm
72257416Smarkmvoid
72357416Smarkmtty_rspeed(int val)
72457416Smarkm{
72557416Smarkm#ifdef	DECODE_BAUD
72657416Smarkm    struct termspeeds *tp;
72757416Smarkm
72857416Smarkm    for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
72957416Smarkm	;
73057416Smarkm    if (tp->speed == -1)	/* back up to last valid value */
73157416Smarkm	--tp;
73257416Smarkm    cfsetispeed(&termbuf, tp->value);
73357416Smarkm#else	/* DECODE_BAUD */
73457416Smarkm    cfsetispeed(&termbuf, val);
73557416Smarkm#endif	/* DECODE_BAUD */
73657416Smarkm}
73757416Smarkm
73857416Smarkm#ifdef PARENT_DOES_UTMP
73957416Smarkmextern	struct utmp wtmp;
74057416Smarkmextern char wtmpf[];
74157416Smarkm
74257416Smarkmextern void utmp_sig_init (void);
74357416Smarkmextern void utmp_sig_reset (void);
74457416Smarkmextern void utmp_sig_wait (void);
74557416Smarkmextern void utmp_sig_notify (int);
74657416Smarkm# endif /* PARENT_DOES_UTMP */
74757416Smarkm
74857416Smarkm#ifdef STREAMSPTY
74957416Smarkm
75057416Smarkm/* I_FIND seems to live a life of its own */
75157416Smarkmstatic int my_find(int fd, char *module)
75257416Smarkm{
75357416Smarkm#if defined(I_FIND) && defined(I_LIST)
75457416Smarkm    static int flag;
75557416Smarkm    static struct str_list sl;
75657416Smarkm    int n;
75757416Smarkm    int i;
758233294Sstas
75957416Smarkm    if(!flag){
76057416Smarkm	n = ioctl(fd, I_LIST, 0);
76157416Smarkm	if(n < 0){
76257416Smarkm	    perror("ioctl(fd, I_LIST, 0)");
76357416Smarkm	    return -1;
76457416Smarkm	}
76557416Smarkm	sl.sl_modlist=(struct str_mlist*)malloc(n * sizeof(struct str_mlist));
76657416Smarkm	sl.sl_nmods = n;
76757416Smarkm	n = ioctl(fd, I_LIST, &sl);
76857416Smarkm	if(n < 0){
76957416Smarkm	    perror("ioctl(fd, I_LIST, n)");
77057416Smarkm	    return -1;
77157416Smarkm	}
77257416Smarkm	flag = 1;
77357416Smarkm    }
774233294Sstas
77557416Smarkm    for(i=0; i<sl.sl_nmods; i++)
77657416Smarkm	if(!strcmp(sl.sl_modlist[i].l_name, module))
77757416Smarkm	    return 1;
77857416Smarkm#endif
77957416Smarkm    return 0;
78057416Smarkm}
78157416Smarkm
78257416Smarkmstatic void maybe_push_modules(int fd, char **modules)
78357416Smarkm{
78457416Smarkm    char **p;
78557416Smarkm    int err;
78657416Smarkm
78757416Smarkm    for(p=modules; *p; p++){
78857416Smarkm	err = my_find(fd, *p);
78957416Smarkm	if(err == 1)
79057416Smarkm	    break;
79157416Smarkm	if(err < 0 && errno != EINVAL)
79257416Smarkm	    fatalperror(net, "my_find()");
79357416Smarkm	/* module not pushed or does not exist */
79457416Smarkm    }
79557416Smarkm    /* p points to null or to an already pushed module, now push all
79657416Smarkm       modules before this one */
797233294Sstas
79857416Smarkm    for(p--; p >= modules; p--){
79957416Smarkm	err = ioctl(fd, I_PUSH, *p);
80057416Smarkm	if(err < 0 && errno != EINVAL)
80157416Smarkm	    fatalperror(net, "I_PUSH");
80257416Smarkm    }
80357416Smarkm}
80457416Smarkm#endif
80557416Smarkm
80657416Smarkm/*
80757416Smarkm * getptyslave()
80857416Smarkm *
80957416Smarkm * Open the slave side of the pty, and do any initialization
81057416Smarkm * that is necessary.  The return value is a file descriptor
81157416Smarkm * for the slave side.
81257416Smarkm */
81357416Smarkmvoid getptyslave(void)
81457416Smarkm{
81557416Smarkm    int t = -1;
81657416Smarkm
81757416Smarkm    struct winsize ws;
81857416Smarkm    /*
81957416Smarkm     * Opening the slave side may cause initilization of the
82057416Smarkm     * kernel tty structure.  We need remember the state of
82157416Smarkm     * 	if linemode was turned on
82257416Smarkm     *	terminal window size
82357416Smarkm     *	terminal speed
82457416Smarkm     * so that we can re-set them if we need to.
82557416Smarkm     */
82657416Smarkm
82757416Smarkm
82857416Smarkm    /*
82957416Smarkm     * Make sure that we don't have a controlling tty, and
83057416Smarkm     * that we are the session (process group) leader.
83157416Smarkm     */
83257416Smarkm
83357416Smarkm#ifdef HAVE_SETSID
83457416Smarkm    if(setsid()<0)
83557416Smarkm	fatalperror(net, "setsid()");
83657416Smarkm#else
83757416Smarkm# ifdef	TIOCNOTTY
83857416Smarkm    t = open(_PATH_TTY, O_RDWR);
83957416Smarkm    if (t >= 0) {
84057416Smarkm	ioctl(t, TIOCNOTTY, (char *)0);
84157416Smarkm	close(t);
84257416Smarkm    }
84357416Smarkm# endif
84457416Smarkm#endif
84557416Smarkm
84657416Smarkm# ifdef PARENT_DOES_UTMP
84757416Smarkm    /*
84857416Smarkm     * Wait for our parent to get the utmp stuff to get done.
84957416Smarkm     */
85057416Smarkm    utmp_sig_wait();
85157416Smarkm# endif
85257416Smarkm
85357416Smarkm    t = cleanopen(line);
85457416Smarkm    if (t < 0)
85557416Smarkm	fatalperror(net, line);
85657416Smarkm
85757416Smarkm#ifdef  STREAMSPTY
85857416Smarkm    ttyfd = t;
85957416Smarkm
860233294Sstas
86157416Smarkm    /*
86257416Smarkm     * Not all systems have (or need) modules ttcompat and pckt so
86357416Smarkm     * don't flag it as a fatal error if they don't exist.
86457416Smarkm     */
86557416Smarkm
86657416Smarkm    if (really_stream)
86757416Smarkm	{
86857416Smarkm	    /* these are the streams modules that we want pushed. note
86957416Smarkm	       that they are in reverse order, ptem will be pushed
87057416Smarkm	       first. maybe_push_modules() will try to push all modules
87157416Smarkm	       before the first one that isn't already pushed. i.e if
87257416Smarkm	       ldterm is pushed, only ttcompat will be attempted.
87357416Smarkm
87457416Smarkm	       all this is because we don't know which modules are
87557416Smarkm	       available, and we don't know which modules are already
87657416Smarkm	       pushed (via autopush, for instance).
87757416Smarkm
87857416Smarkm	       */
879233294Sstas
88057416Smarkm	    char *ttymodules[] = { "ttcompat", "ldterm", "ptem", NULL };
88157416Smarkm	    char *ptymodules[] = { "pckt", NULL };
88257416Smarkm
88357416Smarkm	    maybe_push_modules(t, ttymodules);
88457416Smarkm	    maybe_push_modules(ourpty, ptymodules);
88557416Smarkm	}
88657416Smarkm#endif
88757416Smarkm    /*
88857416Smarkm     * set up the tty modes as we like them to be.
88957416Smarkm     */
89057416Smarkm    init_termbuf();
89157416Smarkm# ifdef	TIOCSWINSZ
89257416Smarkm    if (def_row || def_col) {
89357416Smarkm	memset(&ws, 0, sizeof(ws));
89457416Smarkm	ws.ws_col = def_col;
89557416Smarkm	ws.ws_row = def_row;
89657416Smarkm	ioctl(t, TIOCSWINSZ, (char *)&ws);
89757416Smarkm    }
89857416Smarkm# endif
89957416Smarkm
90057416Smarkm    /*
90157416Smarkm     * Settings for sgtty based systems
90257416Smarkm     */
90357416Smarkm
90457416Smarkm    /*
90557416Smarkm     * Settings for UNICOS (and HPUX)
90657416Smarkm     */
90757416Smarkm# if defined(_CRAY) || defined(__hpux)
90857416Smarkm    termbuf.c_oflag = OPOST|ONLCR|TAB3;
90957416Smarkm    termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
91057416Smarkm    termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
91157416Smarkm    termbuf.c_cflag = EXTB|HUPCL|CS8;
91257416Smarkm# endif
91357416Smarkm
91457416Smarkm    /*
91557416Smarkm     * Settings for all other termios/termio based
91657416Smarkm     * systems, other than 4.4BSD.  In 4.4BSD the
91757416Smarkm     * kernel does the initial terminal setup.
91857416Smarkm     */
91957416Smarkm# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43)
92057416Smarkm#  ifndef	OXTABS
92157416Smarkm#   define OXTABS	0
92257416Smarkm#  endif
92357416Smarkm    termbuf.c_lflag |= ECHO;
92457416Smarkm    termbuf.c_oflag |= ONLCR|OXTABS;
92557416Smarkm    termbuf.c_iflag |= ICRNL;
92657416Smarkm    termbuf.c_iflag &= ~IXOFF;
92757416Smarkm# endif
92857416Smarkm    tty_rspeed((def_rspeed > 0) ? def_rspeed : 9600);
92957416Smarkm    tty_tspeed((def_tspeed > 0) ? def_tspeed : 9600);
93057416Smarkm
93157416Smarkm    /*
93257416Smarkm     * Set the tty modes, and make this our controlling tty.
93357416Smarkm     */
93457416Smarkm    set_termbuf();
93557416Smarkm    if (login_tty(t) == -1)
93657416Smarkm	fatalperror(net, "login_tty");
93757416Smarkm    if (net > 2)
93857416Smarkm	close(net);
93957416Smarkm    if (ourpty > 2) {
94057416Smarkm	close(ourpty);
94157416Smarkm	ourpty = -1;
94257416Smarkm    }
94357416Smarkm}
94457416Smarkm
94557416Smarkm#ifndef	O_NOCTTY
94657416Smarkm#define	O_NOCTTY	0
94757416Smarkm#endif
94857416Smarkm/*
94957416Smarkm * Open the specified slave side of the pty,
95057416Smarkm * making sure that we have a clean tty.
95157416Smarkm */
95257416Smarkm
95357416Smarkmint cleanopen(char *line)
95457416Smarkm{
95557416Smarkm    int t;
95657416Smarkm
957178825Sdfr    if (ptyslavefd != -1)
958178825Sdfr	return ptyslavefd;
959178825Sdfr
96057416Smarkm#ifdef STREAMSPTY
96157416Smarkm    if (!really_stream)
96257416Smarkm#endif
96357416Smarkm	{
96457416Smarkm	    /*
96557416Smarkm	     * Make sure that other people can't open the
96657416Smarkm	     * slave side of the connection.
96757416Smarkm	     */
96857416Smarkm	    chown(line, 0, 0);
96957416Smarkm	    chmod(line, 0600);
97057416Smarkm	}
97157416Smarkm
97257416Smarkm#ifdef HAVE_REVOKE
97357416Smarkm    revoke(line);
97457416Smarkm#endif
97557416Smarkm
97657416Smarkm    t = open(line, O_RDWR|O_NOCTTY);
97757416Smarkm
97857416Smarkm    if (t < 0)
97957416Smarkm	return(-1);
98057416Smarkm
98157416Smarkm    /*
98257416Smarkm     * Hangup anybody else using this ttyp, then reopen it for
98357416Smarkm     * ourselves.
98457416Smarkm     */
98557416Smarkm# if !(defined(_CRAY) || defined(__hpux)) && (BSD <= 43) && !defined(STREAMSPTY)
98657416Smarkm    signal(SIGHUP, SIG_IGN);
98757416Smarkm#ifdef HAVE_VHANGUP
98857416Smarkm    vhangup();
98957416Smarkm#else
99057416Smarkm#endif
99157416Smarkm    signal(SIGHUP, SIG_DFL);
99257416Smarkm    t = open(line, O_RDWR|O_NOCTTY);
99357416Smarkm    if (t < 0)
99457416Smarkm	return(-1);
99557416Smarkm# endif
99657416Smarkm# if	defined(_CRAY) && defined(TCVHUP)
99757416Smarkm    {
99857416Smarkm	int i;
99957416Smarkm	signal(SIGHUP, SIG_IGN);
100057416Smarkm	ioctl(t, TCVHUP, (char *)0);
100157416Smarkm	signal(SIGHUP, SIG_DFL);
100257416Smarkm
100357416Smarkm	i = open(line, O_RDWR);
100457416Smarkm
100557416Smarkm	if (i < 0)
100657416Smarkm	    return(-1);
100757416Smarkm	close(t);
100857416Smarkm	t = i;
100957416Smarkm    }
101057416Smarkm# endif	/* defined(CRAY) && defined(TCVHUP) */
101157416Smarkm    return(t);
101257416Smarkm}
101357416Smarkm
101457416Smarkm#if !defined(BSD4_4)
101557416Smarkm
101657416Smarkmint login_tty(int t)
101757416Smarkm{
1018233294Sstas    /* Dont need to set this as the controlling PTY on steams sockets,
1019233294Sstas     * don't abort on failure. */
102057416Smarkm# if defined(TIOCSCTTY) && !defined(__hpux)
1021233294Sstas    if (ioctl(t, TIOCSCTTY, (char *)0) < 0 && !really_stream)
102257416Smarkm	fatalperror(net, "ioctl(sctty)");
102357416Smarkm#  ifdef _CRAY
102457416Smarkm    /*
102557416Smarkm     * Close the hard fd to /dev/ttypXXX, and re-open through
102657416Smarkm     * the indirect /dev/tty interface.
102757416Smarkm     */
102857416Smarkm    close(t);
102957416Smarkm    if ((t = open("/dev/tty", O_RDWR)) < 0)
103057416Smarkm	fatalperror(net, "open(/dev/tty)");
103157416Smarkm#  endif
103257416Smarkm# else
103357416Smarkm    /*
103457416Smarkm     * We get our controlling tty assigned as a side-effect
103557416Smarkm     * of opening up a tty device.  But on BSD based systems,
103657416Smarkm     * this only happens if our process group is zero.  The
103757416Smarkm     * setsid() call above may have set our pgrp, so clear
103857416Smarkm     * it out before opening the tty...
103957416Smarkm     */
104057416Smarkm#ifdef HAVE_SETPGID
104157416Smarkm    setpgid(0, 0);
104257416Smarkm#else
104357416Smarkm    setpgrp(0, 0); /* if setpgid isn't available, setpgrp
104457416Smarkm		      probably takes arguments */
104557416Smarkm#endif
104657416Smarkm    close(open(line, O_RDWR));
104757416Smarkm# endif
104857416Smarkm    if (t != 0)
104957416Smarkm	dup2(t, 0);
105057416Smarkm    if (t != 1)
105157416Smarkm	dup2(t, 1);
105257416Smarkm    if (t != 2)
105357416Smarkm	dup2(t, 2);
105457416Smarkm    if (t > 2)
105557416Smarkm	close(t);
105657416Smarkm    return(0);
105757416Smarkm}
105857416Smarkm#endif	/* BSD <= 43 */
105957416Smarkm
106057416Smarkm/*
106157416Smarkm * This comes from ../../bsd/tty.c and should not really be here.
106257416Smarkm */
106357416Smarkm
106457416Smarkm/*
106557416Smarkm * Clean the tty name.  Return a pointer to the cleaned version.
106657416Smarkm */
106757416Smarkm
1068178825Sdfrstatic char * clean_ttyname (char *) __attribute__((unused));
1069178825Sdfr
107057416Smarkmstatic char *
107157416Smarkmclean_ttyname (char *tty)
107257416Smarkm{
107357416Smarkm  char *res = tty;
107457416Smarkm
107557416Smarkm  if (strncmp (res, _PATH_DEV, strlen(_PATH_DEV)) == 0)
107657416Smarkm    res += strlen(_PATH_DEV);
107757416Smarkm  if (strncmp (res, "pty/", 4) == 0)
107857416Smarkm    res += 4;
107957416Smarkm  if (strncmp (res, "ptym/", 5) == 0)
108057416Smarkm    res += 5;
108157416Smarkm  return res;
108257416Smarkm}
108357416Smarkm
108457416Smarkm/*
108557416Smarkm * Generate a name usable as an `ut_id', typically without `tty'.
108657416Smarkm */
108757416Smarkm
108857416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_ID
108957416Smarkmstatic char *
109057416Smarkmmake_id (char *tty)
109157416Smarkm{
109257416Smarkm  char *res = tty;
1093233294Sstas
109457416Smarkm  if (strncmp (res, "pts/", 4) == 0)
109557416Smarkm    res += 4;
109657416Smarkm  if (strncmp (res, "tty", 3) == 0)
109757416Smarkm    res += 3;
109857416Smarkm  return res;
109957416Smarkm}
110057416Smarkm#endif
110157416Smarkm
110257416Smarkm/*
110357416Smarkm * startslave(host)
110457416Smarkm *
110557416Smarkm * Given a hostname, do whatever
110657416Smarkm * is necessary to startup the login process on the slave side of the pty.
110757416Smarkm */
110857416Smarkm
110957416Smarkm/* ARGSUSED */
111057416Smarkmvoid
111178527Sassarstartslave(const char *host, const char *utmp_host,
111278527Sassar	   int autologin, char *autoname)
111357416Smarkm{
111457416Smarkm    int i;
111557416Smarkm
111657416Smarkm#ifdef AUTHENTICATION
111757416Smarkm    if (!autoname || !autoname[0])
111857416Smarkm	autologin = 0;
111957416Smarkm
112057416Smarkm    if (autologin < auth_level) {
112157416Smarkm	fatal(net, "Authorization failed");
112257416Smarkm	exit(1);
112357416Smarkm    }
112457416Smarkm#endif
112557416Smarkm
112657416Smarkm    {
112757416Smarkm	char *tbuf =
112857416Smarkm	    "\r\n*** Connection not encrypted! "
112957416Smarkm	    "Communication may be eavesdropped. ***\r\n";
113057416Smarkm#ifdef ENCRYPTION
113157416Smarkm	if (!no_warn && (encrypt_output == 0 || decrypt_input == 0))
113257416Smarkm#endif
1133178825Sdfr	    writenet(tbuf, strlen(tbuf));
113457416Smarkm    }
113557416Smarkm# ifdef	PARENT_DOES_UTMP
113657416Smarkm    utmp_sig_init();
113757416Smarkm# endif	/* PARENT_DOES_UTMP */
113857416Smarkm
113957416Smarkm    if ((i = fork()) < 0)
114057416Smarkm	fatalperror(net, "fork");
114157416Smarkm    if (i) {
114257416Smarkm# ifdef PARENT_DOES_UTMP
114357416Smarkm	/*
114457416Smarkm	 * Cray parent will create utmp entry for child and send
114557416Smarkm	 * signal to child to tell when done.  Child waits for signal
114657416Smarkm	 * before doing anything important.
114757416Smarkm	 */
114857416Smarkm	int pid = i;
114957416Smarkm	void sigjob (int);
115057416Smarkm
115157416Smarkm	setpgrp();
115257416Smarkm	utmp_sig_reset();		/* reset handler to default */
115357416Smarkm	/*
115457416Smarkm	 * Create utmp entry for child
115557416Smarkm	 */
115672445Sassar	wtmp.ut_time = time(NULL);
115757416Smarkm	wtmp.ut_type = LOGIN_PROCESS;
115857416Smarkm	wtmp.ut_pid = pid;
115957416Smarkm	strncpy(wtmp.ut_user,  "LOGIN", sizeof(wtmp.ut_user));
116078527Sassar	strncpy(wtmp.ut_host,  utmp_host, sizeof(wtmp.ut_host));
116157416Smarkm	strncpy(wtmp.ut_line,  clean_ttyname(line), sizeof(wtmp.ut_line));
116257416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_ID
116357416Smarkm	strncpy(wtmp.ut_id, wtmp.ut_line + 3, sizeof(wtmp.ut_id));
116457416Smarkm#endif
116557416Smarkm
116657416Smarkm	pututline(&wtmp);
116757416Smarkm	endutent();
116857416Smarkm	if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
116957416Smarkm	    write(i, &wtmp, sizeof(struct utmp));
117057416Smarkm	    close(i);
117157416Smarkm	}
117257416Smarkm#ifdef	_CRAY
117357416Smarkm	signal(WJSIGNAL, sigjob);
117457416Smarkm#endif
117557416Smarkm	utmp_sig_notify(pid);
117657416Smarkm# endif	/* PARENT_DOES_UTMP */
117757416Smarkm    } else {
117857416Smarkm	getptyslave();
117972445Sassar#if defined(DCE)
118072445Sassar	/* if we authenticated via K5, try and join the PAG */
118172445Sassar	kerberos5_dfspag();
118272445Sassar#endif
118357416Smarkm	start_login(host, autologin, autoname);
118457416Smarkm	/*NOTREACHED*/
118557416Smarkm    }
118657416Smarkm}
118757416Smarkm
118857416Smarkmchar	*envinit[3];
1189233294Sstas#if !HAVE_DECL_ENVIRON
119057416Smarkmextern char **environ;
1191233294Sstas#endif
119257416Smarkm
119357416Smarkmvoid
119457416Smarkminit_env(void)
119557416Smarkm{
119657416Smarkm    char **envp;
119757416Smarkm
119857416Smarkm    envp = envinit;
119957416Smarkm    if ((*envp = getenv("TZ")))
120057416Smarkm	*envp++ -= 3;
120157416Smarkm#if defined(_CRAY) || defined(__hpux)
120257416Smarkm    else
120357416Smarkm	*envp++ = "TZ=GMT0";
120457416Smarkm#endif
120557416Smarkm    *envp = 0;
120657416Smarkm    environ = envinit;
120757416Smarkm}
120857416Smarkm
120957416Smarkm/*
121057416Smarkm * scrub_env()
121157416Smarkm *
121272445Sassar * We only accept the environment variables listed below.
121357416Smarkm */
121457416Smarkm
121572445Sassarstatic void
121672445Sassarscrub_env(void)
121757416Smarkm{
121872445Sassar    static const char *reject[] = {
121972445Sassar	"TERMCAP=/",
122072445Sassar	NULL
122172445Sassar    };
122257416Smarkm
122372445Sassar    static const char *accept[] = {
122472445Sassar	"XAUTH=", "XAUTHORITY=", "DISPLAY=",
122572445Sassar	"TERM=",
122672445Sassar	"EDITOR=",
122772445Sassar	"PAGER=",
122872445Sassar	"PRINTER=",
122972445Sassar	"LOGNAME=",
123072445Sassar	"POSIXLY_CORRECT=",
123172445Sassar	"TERMCAP=",
123272445Sassar	NULL
123372445Sassar    };
123472445Sassar
123557416Smarkm    char **cpp, **cpp2;
123672445Sassar    const char **p;
1237233294Sstas
123857416Smarkm    for (cpp2 = cpp = environ; *cpp; cpp++) {
123972445Sassar	int reject_it = 0;
124072445Sassar
124172445Sassar	for(p = reject; *p; p++)
124272445Sassar	    if(strncmp(*cpp, *p, strlen(*p)) == 0) {
124372445Sassar		reject_it = 1;
124472445Sassar		break;
124572445Sassar	    }
124672445Sassar	if (reject_it)
124772445Sassar	    continue;
124872445Sassar
124972445Sassar	for(p = accept; *p; p++)
125057416Smarkm	    if(strncmp(*cpp, *p, strlen(*p)) == 0)
125157416Smarkm		break;
125272445Sassar	if(*p != NULL)
125357416Smarkm	    *cpp2++ = *cpp;
125457416Smarkm    }
125572445Sassar    *cpp2 = NULL;
125657416Smarkm}
125757416Smarkm
125857416Smarkm
125957416Smarkmstruct arg_val {
126057416Smarkm    int size;
126157416Smarkm    int argc;
1262178825Sdfr    char **argv;
126357416Smarkm};
126457416Smarkm
126578527Sassarstatic void addarg(struct arg_val*, const char*);
126657416Smarkm
126757416Smarkm/*
126857416Smarkm * start_login(host)
126957416Smarkm *
127057416Smarkm * Assuming that we are now running as a child processes, this
127157416Smarkm * function will turn us into the login process.
127257416Smarkm */
127357416Smarkm
127457416Smarkmvoid
127578527Sassarstart_login(const char *host, int autologin, char *name)
127657416Smarkm{
127757416Smarkm    struct arg_val argv;
127857416Smarkm    char *user;
127978527Sassar    int save_errno;
128057416Smarkm
1281178825Sdfr#ifdef ENCRYPTION
1282178825Sdfr    encrypt_output = NULL;
1283178825Sdfr    decrypt_input = NULL;
1284178825Sdfr#endif
1285233294Sstas
128657416Smarkm#ifdef HAVE_UTMPX_H
1287178825Sdfr    {
1288178825Sdfr	int pid = getpid();
1289178825Sdfr	struct utmpx utmpx;
1290178825Sdfr	struct timeval tv;
1291178825Sdfr	char *clean_tty;
1292233294Sstas
1293178825Sdfr	/*
1294178825Sdfr	 * Create utmp entry for child
1295178825Sdfr	 */
1296233294Sstas
1297178825Sdfr	clean_tty = clean_ttyname(line);
1298178825Sdfr	memset(&utmpx, 0, sizeof(utmpx));
1299178825Sdfr	strncpy(utmpx.ut_user,  ".telnet", sizeof(utmpx.ut_user));
1300178825Sdfr	strncpy(utmpx.ut_line,  clean_tty, sizeof(utmpx.ut_line));
130157416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_ID
1302178825Sdfr	strncpy(utmpx.ut_id, make_id(clean_tty), sizeof(utmpx.ut_id));
130357416Smarkm#endif
1304178825Sdfr	utmpx.ut_pid = pid;
1305233294Sstas
1306178825Sdfr	utmpx.ut_type = LOGIN_PROCESS;
1307233294Sstas
1308178825Sdfr	gettimeofday (&tv, NULL);
1309178825Sdfr	utmpx.ut_tv.tv_sec = tv.tv_sec;
1310178825Sdfr	utmpx.ut_tv.tv_usec = tv.tv_usec;
131157416Smarkm
1312178825Sdfr	if (pututxline(&utmpx) == NULL)
1313178825Sdfr	    fatal(net, "pututxline failed");
1314178825Sdfr    }
131557416Smarkm#endif
131657416Smarkm
131757416Smarkm    scrub_env();
1318233294Sstas
131957416Smarkm    /*
132057416Smarkm     * -h : pass on name of host.
132157416Smarkm     *		WARNING:  -h is accepted by login if and only if
132257416Smarkm     *			getuid() == 0.
132357416Smarkm     * -p : don't clobber the environment (so terminal type stays set).
132457416Smarkm     *
132557416Smarkm     * -f : force this login, he has already been authenticated
132657416Smarkm     */
132757416Smarkm
1328233294Sstas    /* init argv structure */
132957416Smarkm    argv.size=0;
133057416Smarkm    argv.argc=0;
133178527Sassar    argv.argv=malloc(0); /*so we can call realloc later */
133257416Smarkm    addarg(&argv, "login");
133357416Smarkm    addarg(&argv, "-h");
133457416Smarkm    addarg(&argv, host);
133557416Smarkm    addarg(&argv, "-p");
1336233294Sstas    if(name && name[0])
133757416Smarkm	user = name;
133857416Smarkm    else
133957416Smarkm	user = getenv("USER");
134057416Smarkm#ifdef AUTHENTICATION
134157416Smarkm    if (auth_level < 0 || autologin != AUTH_VALID) {
134257416Smarkm	if(!no_warn) {
134357416Smarkm	    printf("User not authenticated. ");
134457416Smarkm	    if (require_otp)
134557416Smarkm		printf("Using one-time password\r\n");
134657416Smarkm	    else
134757416Smarkm		printf("Using plaintext username and password\r\n");
134857416Smarkm	}
134957416Smarkm	if (require_otp) {
135057416Smarkm	    addarg(&argv, "-a");
135157416Smarkm	    addarg(&argv, "otp");
135257416Smarkm	}
1353233294Sstas	if(log_unauth)
1354233294Sstas	    syslog(LOG_INFO, "unauthenticated access from %s (%s)",
135557416Smarkm		   host, user ? user : "unknown user");
135657416Smarkm    }
135757416Smarkm    if (auth_level >= 0 && autologin == AUTH_VALID)
135857416Smarkm	addarg(&argv, "-f");
135957416Smarkm#endif
136057416Smarkm    if(user){
136157416Smarkm	addarg(&argv, "--");
136257416Smarkm	addarg(&argv, strdup(user));
136357416Smarkm    }
136457416Smarkm    if (getenv("USER")) {
136557416Smarkm	/*
136657416Smarkm	 * Assume that login will set the USER variable
136757416Smarkm	 * correctly.  For SysV systems, this means that
136857416Smarkm	 * USER will no longer be set, just LOGNAME by
136957416Smarkm	 * login.  (The problem is that if the auto-login
137057416Smarkm	 * fails, and the user then specifies a different
137157416Smarkm	 * account name, he can get logged in with both
137257416Smarkm	 * LOGNAME and USER in his environment, but the
137357416Smarkm	 * USER value will be wrong.
137457416Smarkm	 */
137557416Smarkm	unsetenv("USER");
137657416Smarkm    }
137757416Smarkm    closelog();
137857416Smarkm    /*
137957416Smarkm     * This sleep(1) is in here so that telnetd can
138057416Smarkm     * finish up with the tty.  There's a race condition
138157416Smarkm     * the login banner message gets lost...
138257416Smarkm     */
138357416Smarkm    sleep(1);
138457416Smarkm
138557416Smarkm    execv(new_login, argv.argv);
138678527Sassar    save_errno = errno;
1387178825Sdfr    syslog(LOG_ERR, "%s: %m", new_login);
138878527Sassar    fatalperror_errno(net, new_login, save_errno);
138957416Smarkm    /*NOTREACHED*/
139057416Smarkm}
139157416Smarkm
139257416Smarkmstatic void
139378527Sassaraddarg(struct arg_val *argv, const char *val)
139457416Smarkm{
139557416Smarkm    if(argv->size <= argv->argc+1) {
139657416Smarkm	argv->argv = realloc(argv->argv, sizeof(char*) * (argv->size + 10));
139757416Smarkm	if (argv->argv == NULL)
139857416Smarkm	    fatal (net, "realloc: out of memory");
139957416Smarkm	argv->size+=10;
140057416Smarkm    }
1401178825Sdfr    if((argv->argv[argv->argc++] = strdup(val)) == NULL)
1402178825Sdfr	fatal (net, "strdup: out of memory");
140357416Smarkm    argv->argv[argv->argc]   = NULL;
140457416Smarkm}
140557416Smarkm
140657416Smarkm
140757416Smarkm/*
140857416Smarkm * rmut()
140957416Smarkm *
141057416Smarkm * This is the function called by cleanup() to
141157416Smarkm * remove the utmp entry for this person.
141257416Smarkm */
141357416Smarkm
141457416Smarkm#ifdef HAVE_UTMPX_H
141557416Smarkmstatic void
141657416Smarkmrmut(void)
141757416Smarkm{
141857416Smarkm    struct utmpx utmpx, *non_save_utxp;
141957416Smarkm    char *clean_tty = clean_ttyname(line);
142057416Smarkm
142157416Smarkm    /*
142257416Smarkm     * This updates the utmpx and utmp entries and make a wtmp/x entry
142357416Smarkm     */
142457416Smarkm
142557416Smarkm    setutxent();
142657416Smarkm    memset(&utmpx, 0, sizeof(utmpx));
142757416Smarkm    strncpy(utmpx.ut_line, clean_tty, sizeof(utmpx.ut_line));
142857416Smarkm    utmpx.ut_type = LOGIN_PROCESS;
142957416Smarkm    non_save_utxp = getutxline(&utmpx);
143057416Smarkm    if (non_save_utxp) {
143157416Smarkm	struct utmpx *utxp;
1432178825Sdfr	struct timeval tv;
143357416Smarkm	char user0;
143457416Smarkm
143557416Smarkm	utxp = malloc(sizeof(struct utmpx));
143657416Smarkm	*utxp = *non_save_utxp;
143757416Smarkm	user0 = utxp->ut_user[0];
143857416Smarkm	utxp->ut_user[0] = '\0';
143957416Smarkm	utxp->ut_type = DEAD_PROCESS;
144057416Smarkm#ifdef HAVE_STRUCT_UTMPX_UT_EXIT
144157416Smarkm#ifdef _STRUCT___EXIT_STATUS
144257416Smarkm	utxp->ut_exit.__e_termination = 0;
144357416Smarkm	utxp->ut_exit.__e_exit = 0;
144457416Smarkm#elif defined(__osf__) /* XXX */
144557416Smarkm	utxp->ut_exit.ut_termination = 0;
144657416Smarkm	utxp->ut_exit.ut_exit = 0;
1447233294Sstas#else
144857416Smarkm	utxp->ut_exit.e_termination = 0;
144957416Smarkm	utxp->ut_exit.e_exit = 0;
145057416Smarkm#endif
145157416Smarkm#endif
1452178825Sdfr	gettimeofday (&tv, NULL);
1453178825Sdfr	utxp->ut_tv.tv_sec = tv.tv_sec;
1454178825Sdfr	utxp->ut_tv.tv_usec = tv.tv_usec;
1455178825Sdfr
145657416Smarkm	pututxline(utxp);
145757416Smarkm#ifdef WTMPX_FILE
145857416Smarkm	utxp->ut_user[0] = user0;
145957416Smarkm	updwtmpx(WTMPX_FILE, utxp);
146057416Smarkm#elif defined(WTMP_FILE)
146157416Smarkm	/* This is a strange system with a utmpx and a wtmp! */
146257416Smarkm	{
146357416Smarkm	  int f = open(wtmpf, O_WRONLY|O_APPEND);
146457416Smarkm	  struct utmp wtmp;
146557416Smarkm	  if (f >= 0) {
146657416Smarkm	    strncpy(wtmp.ut_line,  clean_tty, sizeof(wtmp.ut_line));
146757416Smarkm	    strncpy(wtmp.ut_name,  "", sizeof(wtmp.ut_name));
146857416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_HOST
146957416Smarkm	    strncpy(wtmp.ut_host,  "", sizeof(wtmp.ut_host));
147057416Smarkm#endif
147172445Sassar	    wtmp.ut_time = time(NULL);
147257416Smarkm	    write(f, &wtmp, sizeof(wtmp));
147357416Smarkm	    close(f);
147457416Smarkm	  }
147557416Smarkm	}
147657416Smarkm#endif
147757416Smarkm	free (utxp);
147857416Smarkm    }
147957416Smarkm    endutxent();
148057416Smarkm}  /* end of rmut */
148157416Smarkm#endif
148257416Smarkm
148357416Smarkm#if !defined(HAVE_UTMPX_H) && !(defined(_CRAY) || defined(__hpux)) && BSD <= 43
148457416Smarkmstatic void
148557416Smarkmrmut(void)
148657416Smarkm{
148757416Smarkm    int f;
148857416Smarkm    int found = 0;
148957416Smarkm    struct utmp *u, *utmp;
149057416Smarkm    int nutmp;
149157416Smarkm    struct stat statbf;
149257416Smarkm    char *clean_tty = clean_ttyname(line);
149357416Smarkm
149457416Smarkm    f = open(utmpf, O_RDWR);
149557416Smarkm    if (f >= 0) {
149657416Smarkm	fstat(f, &statbf);
149757416Smarkm	utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
149857416Smarkm	if (!utmp)
149957416Smarkm	    syslog(LOG_ERR, "utmp malloc failed");
150057416Smarkm	if (statbf.st_size && utmp) {
150157416Smarkm	    nutmp = read(f, utmp, (int)statbf.st_size);
150257416Smarkm	    nutmp /= sizeof(struct utmp);
150357416Smarkm
150457416Smarkm	    for (u = utmp ; u < &utmp[nutmp] ; u++) {
150557416Smarkm		if (strncmp(u->ut_line,
150657416Smarkm			    clean_tty,
150757416Smarkm			    sizeof(u->ut_line)) ||
150857416Smarkm		    u->ut_name[0]==0)
150957416Smarkm		    continue;
151057416Smarkm		lseek(f, ((long)u)-((long)utmp), L_SET);
151157416Smarkm		strncpy(u->ut_name,  "", sizeof(u->ut_name));
151257416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_HOST
151357416Smarkm		strncpy(u->ut_host,  "", sizeof(u->ut_host));
151457416Smarkm#endif
151572445Sassar		u->ut_time = time(NULL);
151657416Smarkm		write(f, u, sizeof(wtmp));
151757416Smarkm		found++;
151857416Smarkm	    }
151957416Smarkm	}
152057416Smarkm	close(f);
152157416Smarkm    }
152257416Smarkm    if (found) {
152357416Smarkm	f = open(wtmpf, O_WRONLY|O_APPEND);
152457416Smarkm	if (f >= 0) {
152557416Smarkm	    strncpy(wtmp.ut_line,  clean_tty, sizeof(wtmp.ut_line));
152657416Smarkm	    strncpy(wtmp.ut_name,  "", sizeof(wtmp.ut_name));
152757416Smarkm#ifdef HAVE_STRUCT_UTMP_UT_HOST
152857416Smarkm	    strncpy(wtmp.ut_host,  "", sizeof(wtmp.ut_host));
152957416Smarkm#endif
153072445Sassar	    wtmp.ut_time = time(NULL);
153157416Smarkm	    write(f, &wtmp, sizeof(wtmp));
153257416Smarkm	    close(f);
153357416Smarkm	}
153457416Smarkm    }
153557416Smarkm    chmod(line, 0666);
153657416Smarkm    chown(line, 0, 0);
153757416Smarkm    line[strlen("/dev/")] = 'p';
153857416Smarkm    chmod(line, 0666);
153957416Smarkm    chown(line, 0, 0);
154057416Smarkm}  /* end of rmut */
154157416Smarkm#endif	/* CRAY */
154257416Smarkm
154357416Smarkm#if defined(__hpux) && !defined(HAVE_UTMPX_H)
154457416Smarkmstatic void
154557416Smarkmrmut (char *line)
154657416Smarkm{
154757416Smarkm    struct utmp utmp;
154857416Smarkm    struct utmp *utptr;
154957416Smarkm    int fd;			/* for /etc/wtmp */
155057416Smarkm
155157416Smarkm    utmp.ut_type = USER_PROCESS;
155257416Smarkm    strncpy(utmp.ut_line, clean_ttyname(line), sizeof(utmp.ut_line));
155357416Smarkm    setutent();
155457416Smarkm    utptr = getutline(&utmp);
155557416Smarkm    /* write it out only if it exists */
155657416Smarkm    if (utptr) {
155757416Smarkm	utptr->ut_type = DEAD_PROCESS;
155857416Smarkm	utptr->ut_time = time(NULL);
155957416Smarkm	pututline(utptr);
156057416Smarkm	/* set wtmp entry if wtmp file exists */
156157416Smarkm	if ((fd = open(wtmpf, O_WRONLY | O_APPEND)) >= 0) {
156257416Smarkm	    write(fd, utptr, sizeof(utmp));
156357416Smarkm	    close(fd);
156457416Smarkm	}
156557416Smarkm    }
156657416Smarkm    endutent();
156757416Smarkm
156857416Smarkm    chmod(line, 0666);
156957416Smarkm    chown(line, 0, 0);
157057416Smarkm    line[14] = line[13];
157157416Smarkm    line[13] = line[12];
157257416Smarkm    line[8] = 'm';
157357416Smarkm    line[9] = '/';
157457416Smarkm    line[10] = 'p';
157557416Smarkm    line[11] = 't';
157657416Smarkm    line[12] = 'y';
157757416Smarkm    chmod(line, 0666);
157857416Smarkm    chown(line, 0, 0);
157957416Smarkm}
158057416Smarkm#endif
158157416Smarkm
158257416Smarkm/*
158357416Smarkm * cleanup()
158457416Smarkm *
158557416Smarkm * This is the routine to call when we are all through, to
158657416Smarkm * clean up anything that needs to be cleaned up.
158757416Smarkm */
158857416Smarkm
158957416Smarkm#ifdef PARENT_DOES_UTMP
159057416Smarkm
159157416Smarkmvoid
159257416Smarkmcleanup(int sig)
159357416Smarkm{
159457416Smarkm#ifdef _CRAY
159557416Smarkm    static int incleanup = 0;
159657416Smarkm    int t;
159757416Smarkm    int child_status; /* status of child process as returned by waitpid */
159857416Smarkm    int flags = WNOHANG|WUNTRACED;
1599233294Sstas
160057416Smarkm    /*
160157416Smarkm     * 1: Pick up the zombie, if we are being called
160257416Smarkm     *    as the signal handler.
160357416Smarkm     * 2: If we are a nested cleanup(), return.
160457416Smarkm     * 3: Try to clean up TMPDIR.
160557416Smarkm     * 4: Fill in utmp with shutdown of process.
160657416Smarkm     * 5: Close down the network and pty connections.
160757416Smarkm     * 6: Finish up the TMPDIR cleanup, if needed.
160857416Smarkm     */
160957416Smarkm    if (sig == SIGCHLD) {
161057416Smarkm	while (waitpid(-1, &child_status, flags) > 0)
161157416Smarkm	    ;	/* VOID */
161257416Smarkm	/* Check if the child process was stopped
161357416Smarkm	 * rather than exited.  We want cleanup only if
161457416Smarkm	 * the child has died.
161557416Smarkm	 */
161657416Smarkm	if (WIFSTOPPED(child_status)) {
161757416Smarkm	    return;
161857416Smarkm	}
161957416Smarkm    }
162057416Smarkm    t = sigblock(sigmask(SIGCHLD));
162157416Smarkm    if (incleanup) {
162257416Smarkm	sigsetmask(t);
162357416Smarkm	return;
162457416Smarkm    }
162557416Smarkm    incleanup = 1;
162657416Smarkm    sigsetmask(t);
1627233294Sstas
162857416Smarkm    t = cleantmp(&wtmp);
162957416Smarkm    setutent();	/* just to make sure */
163057416Smarkm#endif /* CRAY */
163157416Smarkm    rmut(line);
163257416Smarkm    close(ourpty);
163357416Smarkm    shutdown(net, 2);
163457416Smarkm#ifdef _CRAY
163557416Smarkm    if (t == 0)
163657416Smarkm	cleantmp(&wtmp);
163757416Smarkm#endif /* CRAY */
163857416Smarkm    exit(1);
163957416Smarkm}
164057416Smarkm
164157416Smarkm#else /* PARENT_DOES_UTMP */
164257416Smarkm
164357416Smarkmvoid
164457416Smarkmcleanup(int sig)
164557416Smarkm{
164657416Smarkm#if defined(HAVE_UTMPX_H) || !defined(HAVE_LOGWTMP)
164757416Smarkm    rmut();
164857416Smarkm#ifdef HAVE_VHANGUP
164957416Smarkm#ifndef __sgi
165057416Smarkm    vhangup(); /* XXX */
165157416Smarkm#endif
165257416Smarkm#endif
165357416Smarkm#else
165457416Smarkm    char *p;
1655233294Sstas
165657416Smarkm    p = line + sizeof("/dev/") - 1;
165757416Smarkm    if (logout(p))
165857416Smarkm	logwtmp(p, "", "");
165957416Smarkm    chmod(line, 0666);
166057416Smarkm    chown(line, 0, 0);
166157416Smarkm    *p = 'p';
166257416Smarkm    chmod(line, 0666);
166357416Smarkm    chown(line, 0, 0);
166457416Smarkm#endif
166557416Smarkm    shutdown(net, 2);
166657416Smarkm    exit(1);
166757416Smarkm}
166857416Smarkm
166957416Smarkm#endif /* PARENT_DOES_UTMP */
167057416Smarkm
167157416Smarkm#ifdef PARENT_DOES_UTMP
167257416Smarkm/*
167357416Smarkm * _utmp_sig_rcv
167457416Smarkm * utmp_sig_init
167557416Smarkm * utmp_sig_wait
167657416Smarkm *	These three functions are used to coordinate the handling of
167757416Smarkm *	the utmp file between the server and the soon-to-be-login shell.
167857416Smarkm *	The server actually creates the utmp structure, the child calls
167957416Smarkm *	utmp_sig_wait(), until the server calls utmp_sig_notify() and
168057416Smarkm *	signals the future-login shell to proceed.
168157416Smarkm */
168257416Smarkmstatic int caught=0;		/* NZ when signal intercepted */
168357416Smarkmstatic void (*func)();		/* address of previous handler */
168457416Smarkm
168557416Smarkmvoid
168657416Smarkm_utmp_sig_rcv(sig)
168757416Smarkm     int sig;
168857416Smarkm{
168957416Smarkm    caught = 1;
169057416Smarkm    signal(SIGUSR1, func);
169157416Smarkm}
169257416Smarkm
169357416Smarkmvoid
169457416Smarkmutmp_sig_init()
169557416Smarkm{
169657416Smarkm    /*
169757416Smarkm     * register signal handler for UTMP creation
169857416Smarkm     */
169957416Smarkm    if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
170057416Smarkm	fatalperror(net, "telnetd/signal");
170157416Smarkm}
170257416Smarkm
170357416Smarkmvoid
170457416Smarkmutmp_sig_reset()
170557416Smarkm{
170657416Smarkm    signal(SIGUSR1, func);	/* reset handler to default */
170757416Smarkm}
170857416Smarkm
170957416Smarkm# ifdef __hpux
171057416Smarkm# define sigoff() /* do nothing */
171157416Smarkm# define sigon() /* do nothing */
171257416Smarkm# endif
171357416Smarkm
171457416Smarkmvoid
171557416Smarkmutmp_sig_wait()
171657416Smarkm{
171757416Smarkm    /*
171857416Smarkm     * Wait for parent to write our utmp entry.
171957416Smarkm	 */
172057416Smarkm    sigoff();
172157416Smarkm    while (caught == 0) {
172257416Smarkm	pause();	/* wait until we get a signal (sigon) */
172357416Smarkm	sigoff();	/* turn off signals while we check caught */
172457416Smarkm    }
172557416Smarkm    sigon();		/* turn on signals again */
172657416Smarkm}
172757416Smarkm
172857416Smarkmvoid
172957416Smarkmutmp_sig_notify(pid)
173057416Smarkm{
173157416Smarkm    kill(pid, SIGUSR1);
173257416Smarkm}
173357416Smarkm
173457416Smarkm#ifdef _CRAY
173557416Smarkmstatic int gotsigjob = 0;
173657416Smarkm
173757416Smarkm	/*ARGSUSED*/
173857416Smarkmvoid
173957416Smarkmsigjob(sig)
174057416Smarkm     int sig;
174157416Smarkm{
174257416Smarkm    int jid;
174357416Smarkm    struct jobtemp *jp;
174457416Smarkm
174557416Smarkm    while ((jid = waitjob(NULL)) != -1) {
174657416Smarkm	if (jid == 0) {
174757416Smarkm	    return;
174857416Smarkm	}
174957416Smarkm	gotsigjob++;
175057416Smarkm	jobend(jid, NULL, NULL);
175157416Smarkm    }
175257416Smarkm}
175357416Smarkm
175457416Smarkm/*
175557416Smarkm *	jid_getutid:
175657416Smarkm *		called by jobend() before calling cleantmp()
175757416Smarkm *		to find the correct $TMPDIR to cleanup.
175857416Smarkm */
175957416Smarkm
176057416Smarkmstruct utmp *
176157416Smarkmjid_getutid(jid)
176257416Smarkm     int jid;
176357416Smarkm{
176457416Smarkm    struct utmp *cur = NULL;
176557416Smarkm
176657416Smarkm    setutent();	/* just to make sure */
176757416Smarkm    while (cur = getutent()) {
176857416Smarkm	if ( (cur->ut_type != NULL) && (jid == cur->ut_jid) ) {
176957416Smarkm	    return(cur);
177057416Smarkm	}
177157416Smarkm    }
177257416Smarkm
177357416Smarkm    return(0);
177457416Smarkm}
177557416Smarkm
177657416Smarkm/*
177757416Smarkm * Clean up the TMPDIR that login created.
177857416Smarkm * The first time this is called we pick up the info
177957416Smarkm * from the utmp.  If the job has already gone away,
178057416Smarkm * then we'll clean up and be done.  If not, then
178157416Smarkm * when this is called the second time it will wait
178257416Smarkm * for the signal that the job is done.
178357416Smarkm */
178457416Smarkmint
178557416Smarkmcleantmp(wtp)
178657416Smarkm     struct utmp *wtp;
178757416Smarkm{
178857416Smarkm    struct utmp *utp;
178957416Smarkm    static int first = 1;
179057416Smarkm    int mask, omask, ret;
179157416Smarkm    extern struct utmp *getutid (const struct utmp *_Id);
179257416Smarkm
179357416Smarkm
179457416Smarkm    mask = sigmask(WJSIGNAL);
179557416Smarkm
179657416Smarkm    if (first == 0) {
179757416Smarkm	omask = sigblock(mask);
179857416Smarkm	while (gotsigjob == 0)
179957416Smarkm	    sigpause(omask);
180057416Smarkm	return(1);
180157416Smarkm    }
180257416Smarkm    first = 0;
180357416Smarkm    setutent();	/* just to make sure */
180457416Smarkm
180557416Smarkm    utp = getutid(wtp);
180657416Smarkm    if (utp == 0) {
180757416Smarkm	syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
180857416Smarkm	return(-1);
180957416Smarkm    }
181057416Smarkm    /*
181157416Smarkm     * Nothing to clean up if the user shell was never started.
181257416Smarkm     */
181357416Smarkm    if (utp->ut_type != USER_PROCESS || utp->ut_jid == 0)
181457416Smarkm	return(1);
181557416Smarkm
181657416Smarkm    /*
181757416Smarkm     * Block the WJSIGNAL while we are in jobend().
181857416Smarkm     */
181957416Smarkm    omask = sigblock(mask);
182057416Smarkm    ret = jobend(utp->ut_jid, utp->ut_tpath, utp->ut_user);
182157416Smarkm    sigsetmask(omask);
182257416Smarkm    return(ret);
182357416Smarkm}
182457416Smarkm
182557416Smarkmint
182657416Smarkmjobend(jid, path, user)
182757416Smarkm     int jid;
182857416Smarkm     char *path;
182957416Smarkm     char *user;
183057416Smarkm{
183157416Smarkm    static int saved_jid = 0;
183257416Smarkm    static int pty_saved_jid = 0;
183357416Smarkm    static char saved_path[sizeof(wtmp.ut_tpath)+1];
183457416Smarkm    static char saved_user[sizeof(wtmp.ut_user)+1];
183557416Smarkm
183657416Smarkm    /*
183757416Smarkm     * this little piece of code comes into play
183857416Smarkm     * only when ptyreconnect is used to reconnect
183957416Smarkm     * to an previous session.
184057416Smarkm     *
184157416Smarkm     * this is the only time when the
184257416Smarkm     * "saved_jid != jid" code is executed.
184357416Smarkm     */
184457416Smarkm
184557416Smarkm    if ( saved_jid && saved_jid != jid ) {
184657416Smarkm	if (!path) {	/* called from signal handler */
184757416Smarkm	    pty_saved_jid = jid;
184857416Smarkm	} else {
184957416Smarkm	    pty_saved_jid = saved_jid;
185057416Smarkm	}
185157416Smarkm    }
185257416Smarkm
185357416Smarkm    if (path) {
1854178825Sdfr	strlcpy(saved_path, path, sizeof(saved_path));
1855178825Sdfr	strlcpy(saved_user, user, sizeof(saved_user));
185657416Smarkm    }
185757416Smarkm    if (saved_jid == 0) {
185857416Smarkm	saved_jid = jid;
185957416Smarkm	return(0);
186057416Smarkm    }
186157416Smarkm
186257416Smarkm    /* if the jid has changed, get the correct entry from the utmp file */
186357416Smarkm
186457416Smarkm    if ( saved_jid != jid ) {
186557416Smarkm	struct utmp *utp = NULL;
186657416Smarkm	struct utmp *jid_getutid();
186757416Smarkm
186857416Smarkm	utp = jid_getutid(pty_saved_jid);
186957416Smarkm
187057416Smarkm	if (utp == 0) {
187157416Smarkm	    syslog(LOG_ERR, "Can't get /etc/utmp entry to clean TMPDIR");
187257416Smarkm	    return(-1);
187357416Smarkm	}
187457416Smarkm
187557416Smarkm	cleantmpdir(jid, utp->ut_tpath, utp->ut_user);
187657416Smarkm	return(1);
187757416Smarkm    }
187857416Smarkm
187957416Smarkm    cleantmpdir(jid, saved_path, saved_user);
188057416Smarkm    return(1);
188157416Smarkm}
188257416Smarkm
188357416Smarkm/*
188457416Smarkm * Fork a child process to clean up the TMPDIR
188557416Smarkm */
188657416Smarkmcleantmpdir(jid, tpath, user)
188757416Smarkm     int jid;
188857416Smarkm     char *tpath;
188957416Smarkm     char *user;
189057416Smarkm{
189157416Smarkm    switch(fork()) {
189257416Smarkm    case -1:
189357416Smarkm	syslog(LOG_ERR, "TMPDIR cleanup(%s): fork() failed: %m\n",
189457416Smarkm	       tpath);
189557416Smarkm	break;
189657416Smarkm    case 0:
1897178825Sdfr	execl(CLEANTMPCMD, CLEANTMPCMD, user, tpath, NULL);
189857416Smarkm	syslog(LOG_ERR, "TMPDIR cleanup(%s): execl(%s) failed: %m\n",
189957416Smarkm	       tpath, CLEANTMPCMD);
190057416Smarkm	exit(1);
190157416Smarkm    default:
190257416Smarkm	/*
190357416Smarkm	 * Forget about child.  We will exit, and
190457416Smarkm	 * /etc/init will pick it up.
190557416Smarkm	 */
190657416Smarkm	break;
190757416Smarkm    }
190857416Smarkm}
190957416Smarkm#endif /* CRAY */
191057416Smarkm#endif	/* defined(PARENT_DOES_UTMP) */
1911