xref: /csrg-svn/libexec/telnetd/sys_term.c (revision 38999)
138905Sborman /*
238905Sborman  * Copyright (c) 1989 Regents of the University of California.
338905Sborman  * All rights reserved.
438905Sborman  *
538905Sborman  * Redistribution and use in source and binary forms are permitted
638905Sborman  * provided that the above copyright notice and this paragraph are
738905Sborman  * duplicated in all such forms and that any documentation,
838905Sborman  * advertising materials, and other materials related to such
938905Sborman  * distribution and use acknowledge that the software was developed
1038905Sborman  * by the University of California, Berkeley.  The name of the
1138905Sborman  * University may not be used to endorse or promote products derived
1238905Sborman  * from this software without specific prior written permission.
1338905Sborman  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1438905Sborman  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1538905Sborman  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1638905Sborman  */
1738905Sborman 
1838905Sborman #ifndef lint
19*38999Sborman static char sccsid[] = "@(#)sys_term.c	5.2 (Berkeley) 09/05/89";
2038905Sborman #endif /* not lint */
2138905Sborman 
2238905Sborman #include "telnetd.h"
2338905Sborman #include "pathnames.h"
2438905Sborman 
2538905Sborman #ifdef	NEWINIT
2638905Sborman #include <initreq.h>
2738905Sborman #else	/* NEWINIT*/
2838905Sborman #include <utmp.h>
2938905Sborman struct	utmp wtmp;
3038905Sborman 
3138905Sborman # ifndef CRAY
3238905Sborman char	wtmpf[]	= "/usr/adm/wtmp";
3338905Sborman char	utmpf[] = "/etc/utmp";
3438905Sborman # else	/* CRAY */
3538905Sborman char	wtmpf[]	= "/etc/wtmp";
3638905Sborman # endif	/* CRAY */
3738905Sborman #endif	/* NEWINIT */
3838905Sborman 
3938905Sborman #define SCPYN(a, b)	(void) strncpy(a, b, sizeof(a))
4038905Sborman #define SCMPN(a, b)	strncmp(a, b, sizeof(a))
4138905Sborman 
4238905Sborman #include <sys/tty.h>
4338905Sborman #ifdef	t_erase
4438905Sborman #undef	t_erase
4538905Sborman #undef	t_kill
4638905Sborman #undef	t_intrc
4738905Sborman #undef	t_quitc
4838905Sborman #undef	t_startc
4938905Sborman #undef	t_stopc
5038905Sborman #undef	t_eofc
5138905Sborman #undef	t_brkc
5238905Sborman #undef	t_suspc
5338905Sborman #undef	t_dsuspc
5438905Sborman #undef	t_rprntc
5538905Sborman #undef	t_flushc
5638905Sborman #undef	t_werasc
5738905Sborman #undef	t_lnextc
5838905Sborman #endif
5938905Sborman 
6038905Sborman #ifndef	USE_TERMIO
6138905Sborman struct termbuf {
6238905Sborman 	struct sgttyb sg;
6338905Sborman 	struct tchars tc;
6438905Sborman 	struct ltchars ltc;
6538905Sborman 	int state;
6638905Sborman 	int lflags;
6738905Sborman } termbuf, termbuf2;
6838905Sborman #else	/* USE_TERMIO */
6938905Sborman # ifndef EXTPROC
7038905Sborman # define EXTPROC 0400
7138905Sborman # endif
7238905Sborman # ifdef	SYSV_TERMIO
7338905Sborman #	define termios termio
7438905Sborman # endif
7538905Sborman struct termios termbuf, termbuf2;	/* pty control structure */
7638905Sborman #endif	/* USE_TERMIO */
7738905Sborman 
7838905Sborman /*
7938905Sborman  * init_termbuf()
8038905Sborman  * copy_termbuf(cp)
8138905Sborman  * set_termbuf()
8238905Sborman  *
8338905Sborman  * These three routines are used to get and set the "termbuf" structure
8438905Sborman  * to and from the kernel.  init_termbuf() gets the current settings.
8538905Sborman  * copy_termbuf() hands in a new "termbuf" to write to the kernel, and
8638905Sborman  * set_termbuf() writes the structure into the kernel.
8738905Sborman  */
8838905Sborman 
8938905Sborman init_termbuf()
9038905Sborman {
9138905Sborman #ifndef	USE_TERMIO
9238905Sborman 	(void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg);
9338905Sborman 	(void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc);
9438905Sborman 	(void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc);
9538905Sborman # ifdef	TIOCGSTATE
9638905Sborman 	(void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state);
9738905Sborman # endif
9838905Sborman #else
9938905Sborman 	(void) ioctl(pty, TCGETA, (char *)&termbuf);
10038905Sborman #endif
10138905Sborman 	termbuf2 = termbuf;
10238905Sborman }
10338905Sborman 
10438905Sborman #if	defined(LINEMODE) && defined(TIOCPKT_IOCTL)
10538905Sborman copy_termbuf(cp, len)
10638905Sborman char *cp;
10738905Sborman int len;
10838905Sborman {
10938905Sborman 	if (len > sizeof(termbuf))
11038905Sborman 		len = sizeof(termbuf);
11138905Sborman 	bcopy(cp, (char *)&termbuf, len);
11238905Sborman 	termbuf2 = termbuf;
11338905Sborman }
11438905Sborman #endif	/* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */
11538905Sborman 
11638905Sborman set_termbuf()
11738905Sborman {
11838905Sborman 	/*
11938905Sborman 	 * Only make the necessary changes.
12038905Sborman 	 */
12138905Sborman #ifndef	USE_TERMIO
12238905Sborman 	if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg)))
12338905Sborman 		(void) ioctl(pty, TIOCSETP, (char *)&termbuf.sg);
12438905Sborman 	if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc)))
12538905Sborman 		(void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc);
12638905Sborman 	if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc,
12738905Sborman 							sizeof(termbuf.ltc)))
12838905Sborman 		(void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc);
12938905Sborman 	if (termbuf.lflags != termbuf2.lflags)
13038905Sborman 		(void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags);
13138905Sborman #else	/* USE_TERMIO */
13238905Sborman 	if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf)))
13338905Sborman 		(void) ioctl(pty, TCSETA, (char *)&termbuf);
13438905Sborman # ifdef	CRAY2
13538905Sborman 	needtermstat = 1;
13638905Sborman # endif
13738905Sborman #endif	/* USE_TERMIO */
13838905Sborman }
13938905Sborman 
14038905Sborman 
14138905Sborman /*
14238905Sborman  * spcset(func, valp, valpp)
14338905Sborman  *
14438905Sborman  * This function takes various special characters (func), and
14538905Sborman  * sets *valp to the current value of that character, and
14638905Sborman  * *valpp to point to where in the "termbuf" structure that
14738905Sborman  * value is kept.
14838905Sborman  *
14938905Sborman  * It returns the SLC_ level of support for this function.
15038905Sborman  */
15138905Sborman 
15238905Sborman #ifndef	USE_TERMIO
15338905Sborman spcset(func, valp, valpp)
15438905Sborman int func;
15538905Sborman unsigned char *valp;
15638905Sborman unsigned char **valpp;
15738905Sborman {
15838905Sborman 	switch(func) {
15938905Sborman 	case SLC_EOF:
16038905Sborman 		*valp = termbuf.tc.t_eofc;
16138905Sborman 		*valpp = (unsigned char *)&termbuf.tc.t_eofc;
16238905Sborman 		return(SLC_VARIABLE);
16338905Sborman 	case SLC_EC:
16438905Sborman 		*valp = termbuf.sg.sg_erase;
16538905Sborman 		*valpp = (unsigned char *)&termbuf.sg.sg_erase;
16638905Sborman 		return(SLC_VARIABLE);
16738905Sborman 	case SLC_EL:
16838905Sborman 		*valp = termbuf.sg.sg_kill;
16938905Sborman 		*valpp = (unsigned char *)&termbuf.sg.sg_kill;
17038905Sborman 		return(SLC_VARIABLE);
17138905Sborman 	case SLC_IP:
17238905Sborman 		*valp = termbuf.tc.t_intrc;
17338905Sborman 		*valpp = (unsigned char *)&termbuf.tc.t_intrc;
17438905Sborman 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
17538905Sborman 	case SLC_ABORT:
17638905Sborman 		*valp = termbuf.tc.t_quitc;
17738905Sborman 		*valpp = (unsigned char *)&termbuf.tc.t_quitc;
17838905Sborman 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
17938905Sborman 	case SLC_XON:
18038905Sborman 		*valp = termbuf.tc.t_startc;
18138905Sborman 		*valpp = (unsigned char *)&termbuf.tc.t_startc;
18238905Sborman 		return(SLC_VARIABLE);
18338905Sborman 	case SLC_XOFF:
18438905Sborman 		*valp = termbuf.tc.t_stopc;
18538905Sborman 		*valpp = (unsigned char *)&termbuf.tc.t_stopc;
18638905Sborman 		return(SLC_VARIABLE);
18738905Sborman 	case SLC_AO:
18838905Sborman 		*valp = termbuf.ltc.t_flushc;
18938905Sborman 		*valpp = (unsigned char *)&termbuf.ltc.t_flushc;
19038905Sborman 		return(SLC_VARIABLE);
19138905Sborman 	case SLC_SUSP:
19238905Sborman 		*valp = termbuf.ltc.t_suspc;
19338905Sborman 		*valpp = (unsigned char *)&termbuf.ltc.t_suspc;
19438905Sborman 		return(SLC_VARIABLE);
19538905Sborman 	case SLC_EW:
19638905Sborman 		*valp = termbuf.ltc.t_werasc;
19738905Sborman 		*valpp = (unsigned char *)&termbuf.ltc.t_werasc;
19838905Sborman 		return(SLC_VARIABLE);
19938905Sborman 	case SLC_RP:
20038905Sborman 		*valp = termbuf.ltc.t_rprntc;
20138905Sborman 		*valpp = (unsigned char *)&termbuf.ltc.t_rprntc;
20238905Sborman 		return(SLC_VARIABLE);
20338905Sborman 	case SLC_LNEXT:
20438905Sborman 		*valp = termbuf.ltc.t_lnextc;
20538905Sborman 		*valpp = (unsigned char *)&termbuf.ltc.t_lnextc;
20638905Sborman 		return(SLC_VARIABLE);
20738905Sborman 	case SLC_BRK:
20838905Sborman 	case SLC_SYNCH:
20938905Sborman 	case SLC_AYT:
21038905Sborman 	case SLC_EOR:
21138905Sborman 		*valp = 0;
21238905Sborman 		*valpp = 0;
21338905Sborman 		return(SLC_DEFAULT);
21438905Sborman 	default:
21538905Sborman 		*valp = 0;
21638905Sborman 		*valpp = 0;
21738905Sborman 		return(SLC_NOSUPPORT);
21838905Sborman 	}
21938905Sborman }
22038905Sborman 
22138905Sborman #else	/* USE_TERMIO */
22238905Sborman 
22338905Sborman spcset(func, valp, valpp)
22438905Sborman int func;
22538905Sborman unsigned char *valp;
22638905Sborman unsigned char **valpp;
22738905Sborman {
22838905Sborman 	switch(func) {
22938905Sborman 	case SLC_EOF:
23038905Sborman 		*valp = termbuf.c_cc[VEOF];
23138905Sborman 		*valpp = &termbuf.c_cc[VEOF];
23238905Sborman 		return(SLC_VARIABLE);
23338905Sborman 	case SLC_EC:
23438905Sborman 		*valp = termbuf.c_cc[VERASE];
23538905Sborman 		*valpp = &termbuf.c_cc[VERASE];
23638905Sborman 		return(SLC_VARIABLE);
23738905Sborman 	case SLC_EL:
23838905Sborman 		*valp = termbuf.c_cc[VKILL];
23938905Sborman 		*valpp = &termbuf.c_cc[VKILL];
24038905Sborman 		return(SLC_VARIABLE);
24138905Sborman 	case SLC_IP:
24238905Sborman 		*valp = termbuf.c_cc[VINTR];
24338905Sborman 		*valpp = &termbuf.c_cc[VINTR];
24438905Sborman 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
24538905Sborman 	case SLC_ABORT:
24638905Sborman 		*valp = termbuf.c_cc[VQUIT];
24738905Sborman 		*valpp = &termbuf.c_cc[VQUIT];
24838905Sborman 		return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT);
24938905Sborman 	case SLC_XON:
25038905Sborman 		*valp = 0x13;
25138905Sborman 		*valpp = 0;
25238905Sborman 		return(SLC_DEFAULT);
25338905Sborman 	case SLC_XOFF:
25438905Sborman 		*valp = 0x11;
25538905Sborman 		*valpp = 0;
25638905Sborman 		return(SLC_DEFAULT);
25738905Sborman 	case SLC_EW:
25838905Sborman 	case SLC_RP:
25938905Sborman 	case SLC_LNEXT:
26038905Sborman 	case SLC_BRK:
26138905Sborman 	case SLC_SYNCH:
26238905Sborman 	case SLC_AYT:
26338905Sborman 	case SLC_EOR:
26438905Sborman 		*valp = 0;
26538905Sborman 		*valpp = 0;
26638905Sborman 		return(SLC_DEFAULT);
26738905Sborman 	case SLC_AO:
26838905Sborman 	case SLC_SUSP:
26938905Sborman 	default:
27038905Sborman 		*valp = 0;
27138905Sborman 		*valpp = 0;
27238905Sborman 		return(SLC_NOSUPPORT);
27338905Sborman 	}
27438905Sborman }
27538905Sborman #endif	/* USE_TERMIO */
27638905Sborman 
27738905Sborman /*
27838905Sborman  * getpty()
27938905Sborman  *
28038905Sborman  * Allocate a pty.  As a side effect, the external character
28138905Sborman  * array "line" contains the name of the slave side.
28238905Sborman  *
28338905Sborman  * Returns the file descriptor of the opened pty.
28438905Sborman  */
28538905Sborman char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
28638905Sborman 
28738905Sborman getpty()
28838905Sborman {
28938905Sborman 	register int p;
29038905Sborman #ifndef CRAY
29138905Sborman 	register char c, *p1, *p2;
29238905Sborman 	register int i;
29338905Sborman 
29438905Sborman 	(void) sprintf(line, "/dev/ptyXX");
29538905Sborman 	p1 = &line[8];
29638905Sborman 	p2 = &line[9];
29738905Sborman 
29838905Sborman 	for (c = 'p'; c <= 's'; c++) {
29938905Sborman 		struct stat stb;
30038905Sborman 
30138905Sborman 		*p1 = c;
30238905Sborman 		*p2 = '0';
30338905Sborman 		if (stat(line, &stb) < 0)
30438905Sborman 			break;
30538905Sborman 		for (i = 0; i < 16; i++) {
30638905Sborman 			*p2 = "0123456789abcdef"[i];
30738905Sborman 			p = open(line, 2);
30838905Sborman 			if (p > 0) {
30938905Sborman 				line[5] = 't';
31038905Sborman 				return(p);
31138905Sborman 			}
31238905Sborman 		}
31338905Sborman 	}
31438905Sborman #else	/* CRAY */
31538905Sborman 	register int npty;
31638905Sborman 	extern lowpty, highpty;
31738905Sborman 
31838905Sborman 	for (npty = lowpty; npty <= highpty; npty++) {
31938905Sborman 		(void) sprintf(line, "/dev/pty/%03d", npty);
32038905Sborman 		p = open(line, 2);
32138905Sborman 		if (p < 0)
32238905Sborman 			continue;
32338905Sborman 		(void) sprintf(line, "/dev/ttyp%03d", npty);
32438905Sborman 		if (access(line, 6) == 0)
32538905Sborman 			return(p);
32638905Sborman 		else {
32738905Sborman 			/* no tty side to pty so skip it */
32838905Sborman 			(void) close(p);
32938905Sborman 		}
33038905Sborman 	}
33138905Sborman #endif	/* CRAY */
33238905Sborman 	return(-1);
33338905Sborman }
33438905Sborman 
33538905Sborman #ifdef	LINEMODE
33638905Sborman /*
33738905Sborman  * tty_flowmode()	Find out if flow control is enabled or disabled.
33838905Sborman  * tty_linemode()	Find out if linemode (external processing) is enabled.
33938905Sborman  * tty_setlinemod(on)	Turn on/off linemode.
34038905Sborman  * tty_isecho()		Find out if echoing is turned on.
34138905Sborman  * tty_setecho(on)	Enable/disable character echoing.
34238905Sborman  * tty_israw()		Find out if terminal is in RAW mode.
34338905Sborman  * tty_binaryin(on)	Turn on/off BINARY on input.
34438905Sborman  * tty_binaryout(on)	Turn on/off BINARY on output.
34538905Sborman  * tty_isediting()	Find out if line editing is enabled.
34638905Sborman  * tty_istrapsig()	Find out if signal trapping is enabled.
34738905Sborman  * tty_setedit(on)	Turn on/off line editing.
34838905Sborman  * tty_setsig(on)	Turn on/off signal trapping.
34938905Sborman  * tty_tspeed(val)	Set transmit speed to val.
35038905Sborman  * tty_rspeed(val)	Set receive speed to val.
35138905Sborman  */
35238905Sborman 
35338905Sborman tty_flowmode()
35438905Sborman {
35538905Sborman #ifndef USE_TERMIO
35638905Sborman 	return((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0);
35738905Sborman #else
35838905Sborman 	return(termbuf.c_iflag & IXON ? 1 : 0);
35938905Sborman #endif
36038905Sborman }
36138905Sborman 
36238905Sborman tty_linemode()
36338905Sborman {
36438905Sborman #ifndef	USE_TERMIO
36538905Sborman 	return(termbuf.state & TS_EXTPROC);
36638905Sborman #else
36738905Sborman 	return(termbuf.c_lflag & EXTPROC);
36838905Sborman #endif
36938905Sborman }
37038905Sborman 
37138905Sborman tty_setlinemode(on)
37238905Sborman int on;
37338905Sborman {
37438905Sborman #ifdef	TIOCEXT
37538905Sborman 	(void) ioctl(pty, TIOCEXT, (char *)&on);
37638905Sborman #else	/* !TIOCEXT */
37738905Sborman #ifdef	EXTPROC
37838905Sborman 	if (on)
37938905Sborman 		termbuf.c_lflag |= EXTPROC;
38038905Sborman 	else
38138905Sborman 		termbuf.c_lflag &= ~EXTPROC;
38238905Sborman #endif
38338905Sborman 	set_termbuf();
38438905Sborman #endif	/* TIOCEXT */
38538905Sborman }
38638905Sborman 
38738905Sborman tty_isecho()
38838905Sborman {
38938905Sborman #ifndef USE_TERMIO
39038905Sborman 	return (termbuf.sg.sg_flags & ECHO);
39138905Sborman #else
39238905Sborman 	return (termbuf.c_lflag & ECHO);
39338905Sborman #endif
39438905Sborman }
39538905Sborman #endif	/* LINEMODE */
39638905Sborman 
39738905Sborman tty_setecho(on)
39838905Sborman {
39938905Sborman #ifndef	USE_TERMIO
40038905Sborman 	if (on)
40138905Sborman 		termbuf.sg.sg_flags |= ECHO|CRMOD;
40238905Sborman 	else
40338905Sborman 		termbuf.sg.sg_flags &= ~(ECHO|CRMOD);
40438905Sborman #else
40538905Sborman 	if (on)
40638905Sborman 		termbuf.c_lflag |= ECHO;
40738905Sborman 	else
40838905Sborman 		termbuf.c_lflag &= ~ECHO;
40938905Sborman #endif
41038905Sborman }
41138905Sborman 
41238905Sborman #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
41338905Sborman tty_israw()
41438905Sborman {
41538905Sborman #ifndef USE_TERMIO
41638905Sborman 	return(termbuf.sg.sg_flags & RAW);
41738905Sborman #else
41838905Sborman 	return(!(termbuf.c_lflag & ICANON));
41938905Sborman #endif
42038905Sborman }
42138905Sborman #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
42238905Sborman 
42338905Sborman tty_binaryin(on)
42438905Sborman {
42538905Sborman #ifndef	USE_TERMIO
42638905Sborman 	if (on)
42738905Sborman 		termbuf.lflags |= LPASS8;
42838905Sborman 	else
42938905Sborman 		termbuf.lflags &= ~LPASS8;
43038905Sborman #else
43138905Sborman 	if (on) {
43238905Sborman 		termbuf.c_lflag &= ~ISTRIP;
43338905Sborman 	} else {
43438905Sborman 		termbuf.c_lflag |= ISTRIP;
43538905Sborman 	}
43638905Sborman #endif
43738905Sborman }
43838905Sborman 
43938905Sborman tty_binaryout(on)
44038905Sborman {
44138905Sborman #ifndef	USE_TERMIO
44238905Sborman 	if (on)
44338905Sborman 		termbuf.lflags |= LLITOUT;
44438905Sborman 	else
44538905Sborman 		termbuf.lflags &= ~LLITOUT;
44638905Sborman #else
44738905Sborman 	if (on) {
44838905Sborman 		termbuf.c_cflag &= ~(CSIZE|PARENB);
44938905Sborman 		termbuf.c_cflag |= CS8;
45038905Sborman 		termbuf.c_oflag &= ~OPOST;
45138905Sborman 	} else {
45238905Sborman 		termbuf.c_cflag &= ~CSIZE;
45338905Sborman 		termbuf.c_cflag |= CS7|PARENB;
45438905Sborman 		termbuf.c_oflag |= OPOST;
45538905Sborman 	}
45638905Sborman #endif
45738905Sborman }
45838905Sborman 
45938905Sborman tty_isbinaryin()
46038905Sborman {
46138905Sborman #ifndef	USE_TERMIO
46238905Sborman 	return(termbuf.lflags & LPASS8);
46338905Sborman #else
46438905Sborman 	return(!(termbuf.c_lflag & ISTRIP));
46538905Sborman #endif
46638905Sborman }
46738905Sborman 
46838905Sborman tty_isbinaryout()
46938905Sborman {
47038905Sborman #ifndef	USE_TERMIO
47138905Sborman 	return(termbuf.lflags & LLITOUT);
47238905Sborman #else
47338905Sborman 	return(mywants[TELOPT_BINARY] == OPT_YES);
47438905Sborman #endif
47538905Sborman }
47638905Sborman 
47738905Sborman #ifdef	LINEMODE
47838905Sborman tty_isediting()
47938905Sborman {
48038905Sborman #ifndef USE_TERMIO
48138905Sborman 	return(!(termbuf.sg.sg_flags & (CBREAK|RAW)));
48238905Sborman #else
48338905Sborman 	return(termbuf.c_lflag & ICANON);
48438905Sborman #endif
48538905Sborman }
48638905Sborman 
48738905Sborman tty_istrapsig()
48838905Sborman {
48938905Sborman #ifndef USE_TERMIO
49038905Sborman 	return(!(termbuf.sg.sg_flags&RAW));
49138905Sborman #else
49238905Sborman 	return(termbuf.c_lflag & ISIG);
49338905Sborman #endif
49438905Sborman }
49538905Sborman 
49638905Sborman tty_setedit(on)
49738905Sborman int on;
49838905Sborman {
49938905Sborman #ifndef USE_TERMIO
50038905Sborman 	if (on)
50138905Sborman 		termbuf.sg.sg_flags &= ~CBREAK;
50238905Sborman 	else
50338905Sborman 		termbuf.sg.sg_flags |= CBREAK;
50438905Sborman #else
50538905Sborman 	if (on)
50638905Sborman 		termbuf.c_lflag |= ICANON;
50738905Sborman 	else
50838905Sborman 		termbuf.c_lflag &= ~ICANON;
50938905Sborman #endif
51038905Sborman }
51138905Sborman 
51238905Sborman tty_setsig(on)
51338905Sborman int on;
51438905Sborman {
51538905Sborman #ifndef	USE_TERMIO
51638905Sborman 	if (on)
51738905Sborman 		;
51838905Sborman #else
51938905Sborman 	if (on)
52038905Sborman 		termbuf.c_lflag |= ISIG;
52138905Sborman 	else
52238905Sborman 		termbuf.c_lflag &= ~ISIG;
52338905Sborman #endif
52438905Sborman }
52538905Sborman #endif	/* LINEMODE */
52638905Sborman 
52738905Sborman /*
52838905Sborman  * A table of available terminal speeds
52938905Sborman  */
53038905Sborman struct termspeeds {
53138905Sborman 	int	speed;
53238905Sborman 	int	value;
53338905Sborman } termspeeds[] = {
53438905Sborman 	{ 0,     B0 },    { 50,    B50 },   { 75,    B75 },
53538905Sborman 	{ 110,   B110 },  { 134,   B134 },  { 150,   B150 },
53638905Sborman 	{ 200,   B200 },  { 300,   B300 },  { 600,   B600 },
53738905Sborman 	{ 1200,  B1200 }, { 1800,  B1800 }, { 2400,  B2400 },
53838905Sborman 	{ 4800,  B4800 }, { 9600,  B9600 }, { 19200, B9600 },
53938905Sborman 	{ 38400, B9600 }, { -1,    B9600 }
54038905Sborman };
54138905Sborman 
54238905Sborman tty_tspeed(val)
54338905Sborman {
54438905Sborman 	register struct termspeeds *tp;
54538905Sborman 
54638905Sborman 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
54738905Sborman 		;
54838905Sborman #ifndef	USE_TERMIO
54938905Sborman 	termbuf.sg.sg_ospeed = tp->value;
55038905Sborman #else
55138905Sborman # ifdef	SYSV_TERMIO
55238905Sborman 	termbuf.c_cflag &= ~CBAUD;
55338905Sborman 	termbuf.c_cflag |= tp->value;
55438905Sborman # else
55538905Sborman 	termbuf.c_ospeed = tp->value;
55638905Sborman # endif
55738905Sborman #endif
55838905Sborman }
55938905Sborman 
56038905Sborman tty_rspeed(val)
56138905Sborman {
56238905Sborman 	register struct termspeeds *tp;
56338905Sborman 
56438905Sborman 	for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++)
56538905Sborman 		;
56638905Sborman #ifndef	USE_TERMIO
56738905Sborman 	termbuf.sg.sg_ispeed = tp->value;
56838905Sborman #else
56938905Sborman # ifdef	SYSV_TERMIO
57038905Sborman 	termbuf.c_cflag &= ~CBAUD;
57138905Sborman 	termbuf.c_cflag |= tp->value;
57238905Sborman # else
57338905Sborman 	termbuf.c_ispeed = tp->value;
57438905Sborman # endif
57538905Sborman #endif
57638905Sborman }
57738905Sborman 
57838905Sborman #ifdef	CRAY2
57938905Sborman tty_isnewmap()
58038905Sborman {
58138905Sborman 	return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) &&
58238905Sborman 			!(termbuf.c_oflag & ONLRET));
58338905Sborman }
58438905Sborman #endif
58538905Sborman 
58638905Sborman #ifdef	CRAY
58738905Sborman # ifndef NEWINIT
58838905Sborman extern	struct utmp wtmp;
58938905Sborman extern char wtmpf[];
59038905Sborman # else	/* NEWINIT */
59138905Sborman int	gotalarm;
59238905Sborman nologinproc()
59338905Sborman {
59438905Sborman 	gotalarm++;
59538905Sborman }
59638905Sborman # endif	/* NEWINIT */
59738905Sborman #endif /* CRAY */
59838905Sborman 
59938905Sborman /*
60038905Sborman  * getptyslave()
60138905Sborman  *
60238905Sborman  * Open the slave side of the pty, and do any initialization
60338905Sborman  * that is necessary.  The return value is a file descriptor
60438905Sborman  * for the slave side.
60538905Sborman  */
60638905Sborman getptyslave()
60738905Sborman {
60838905Sborman 	register int t = -1;
60938905Sborman 
61038905Sborman #ifndef	CRAY
61138905Sborman 	/*
61238905Sborman 	 * Disassociate self from control terminal and open ttyp side.
61338905Sborman 	 * Set important flags on ttyp and ptyp.
61438905Sborman 	 */
61538905Sborman 	t = open(_PATH_TTY, O_RDWR);
61638905Sborman 	if (t >= 0) {
61738905Sborman 		(void) ioctl(t, TIOCNOTTY, (char *)0);
61838905Sborman 		(void) close(t);
61938905Sborman 	}
62038905Sborman 
62138905Sborman 	t = open(line, O_RDWR);
62238905Sborman 	if (t < 0)
62338905Sborman 		fatalperror(net, line);
62438905Sborman 	if (fchmod(t, 0))
62538905Sborman 		fatalperror(net, line);
62638905Sborman 	(void) signal(SIGHUP, SIG_IGN);
62738905Sborman 	vhangup();
62838905Sborman 	(void) signal(SIGHUP, SIG_DFL);
62938905Sborman 	t = open(line, O_RDWR);
63038905Sborman 	if (t < 0)
63138905Sborman 		fatalperror(net, line);
63238905Sborman 
63338905Sborman 	init_termbuf();
63438905Sborman #ifndef	USE_TERMIO
63538905Sborman 	termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO;
63638905Sborman 	termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600;
63738905Sborman #else
63838905Sborman 	termbuf.c_lflag |= ECHO;
63938905Sborman 	termbuf.c_oflag |= ONLCR|OXTABS;
64038905Sborman 	termbuf.c_iflag |= ICRNL;
64138905Sborman 	termbuf.c_iflag &= ~IXOFF;
64238905Sborman # ifdef	SYSV_TERMIO
64338905Sborman 	termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600;
64438905Sborman # else SYSV_TERMIO
64538905Sborman 	termbuf.c_ospeed = termbuf.c_ispeed = B9600;
64638905Sborman # endif
64738905Sborman #endif
64838905Sborman 	set_termbuf();
64938905Sborman #else	/* CRAY */
65038905Sborman 	(void) chown(line, 0, 0);
65138905Sborman 	(void) chmod(line, 0600);
65238905Sborman #endif	/* CRAY */
65338905Sborman 	return(t);
65438905Sborman }
65538905Sborman 
65638905Sborman #ifdef	NEWINIT
65738905Sborman char *gen_id = "fe";
65838905Sborman #endif
65938905Sborman 
66038905Sborman /*
66138905Sborman  * startslave(t, host)
66238905Sborman  *
66338905Sborman  * Given a file descriptor (t) for a tty, and a hostname, do whatever
66438905Sborman  * is necessary to startup the login process on the slave side of the pty.
66538905Sborman  */
66638905Sborman 
66738905Sborman /* ARGSUSED */
66838905Sborman startslave(t, host)
66938905Sborman int t;
67038905Sborman char *host;
67138905Sborman {
67238905Sborman 	register int i;
67338905Sborman 	long time();
67438905Sborman 
67538905Sborman #ifndef	NEWINIT
67638905Sborman # ifdef	CRAY
67738905Sborman 	utmp_sig_init();
67838905Sborman # endif	/* CRAY */
67938905Sborman 
68038905Sborman 	if ((i = fork()) < 0)
68138905Sborman 		fatalperror(net, "fork");
68238905Sborman 	if (i) {
68338905Sborman # ifdef	CRAY
68438905Sborman 		/*
68538905Sborman 		 * Cray parent will create utmp entry for child and send
68638905Sborman 		 * signal to child to tell when done.  Child waits for signal
68738905Sborman 		 * before doing anything important.
68838905Sborman 		 */
68938905Sborman 		register int pid = i;
69038905Sborman 
69138905Sborman 		setpgrp();
69238905Sborman 		(void) signal(SIGUSR1, func);	/* reset handler to default */
69338905Sborman 		/*
69438905Sborman 		 * Create utmp entry for child
69538905Sborman 		 */
69638905Sborman 		(void) time(&wtmp.ut_time);
69738905Sborman 		wtmp.ut_type = LOGIN_PROCESS;
69838905Sborman 		wtmp.ut_pid = pid;
69938905Sborman 		SCPYN(wtmp.ut_user, "LOGIN");
70038905Sborman 		SCPYN(wtmp.ut_host, host);
70138905Sborman 		SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1);
70238905Sborman 		SCPYN(wtmp.ut_id, wtmp.ut_line+3);
70338905Sborman 		pututline(&wtmp);
70438905Sborman 		endutent();
70538905Sborman 		if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) {
70638905Sborman 			(void) write(i, (char *)&wtmp, sizeof(struct utmp));
70738905Sborman 			(void) close(i);
70838905Sborman 		}
70938905Sborman 		utmp_sig_notify(pid);
71038905Sborman # endif	/* CRAY */
71138905Sborman 		(void) close(t);
71238905Sborman 	} else {
71338905Sborman 		start_login(t, host);
71438905Sborman 		/*NOTREACHED*/
71538905Sborman 	}
71638905Sborman #else	/* NEWINIT */
71738905Sborman 
71838905Sborman 	extern char *ptyip;
71938905Sborman 	struct init_request request;
72038905Sborman 	int nologinproc();
72138905Sborman 	register int n;
72238905Sborman 
72338905Sborman 	/*
72438905Sborman 	 * Init will start up login process if we ask nicely.  We only wait
72538905Sborman 	 * for it to start up and begin normal telnet operation.
72638905Sborman 	 */
72738905Sborman 	if ((i = open(INIT_FIFO, O_WRONLY)) < 0) {
72838905Sborman 		char tbuf[128];
72938905Sborman 		(void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO);
73038905Sborman 		fatalperror(net, tbuf);
73138905Sborman 	}
73238905Sborman 	memset((char *)&request, 0, sizeof(request));
73338905Sborman 	request.magic = INIT_MAGIC;
73438905Sborman 	SCPYN(request.gen_id, gen_id);
73538905Sborman 	SCPYN(request.tty_id, &line[8]);
73638905Sborman 	SCPYN(request.host, host);
73738905Sborman 	SCPYN(request.term_type, &terminaltype[5]);
73838905Sborman 	if (write(i, (char *)&request, sizeof(request)) < 0) {
73938905Sborman 		char tbuf[128];
74038905Sborman 		(void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO);
74138905Sborman 		fatalperror(net, tbuf);
74238905Sborman 	}
74338905Sborman 	(void) close(i);
74438905Sborman 	(void) signal(SIGALRM, nologinproc);
74538905Sborman 	for (i = 0; ; i++) {
74638905Sborman 		alarm(15);
74738905Sborman 		n = read(pty, ptyip, BUFSIZ);
74838905Sborman 		if (i == 3 || n >= 0 || !gotalarm)
74938905Sborman 			break;
75038905Sborman 		gotalarm = 0;
75138905Sborman 		(void) write(net, "telnetd: waiting for /etc/init to start login process.\r\n", 56);
75238905Sborman 	}
75338905Sborman 	if (n < 0 && gotalarm)
75438905Sborman 		fatal(net, "/etc/init didn't start login process");
75538905Sborman 	pcc += n;
75638905Sborman 	alarm(0);
75738905Sborman 	(void) signal(SIGALRM, SIG_DFL);
75838905Sborman 
75938905Sborman 	/*
76038905Sborman 	 * Set tab expansion the way we like, in case init did something
76138905Sborman 	 * different.
76238905Sborman 	 */
76338905Sborman 	init_termbuf();
76438905Sborman 	termbuf.c_oflag &= ~TABDLY;
76538905Sborman 	termbuf.c_oflag |= TAB0;
76638905Sborman 	set_termbuf();
76738905Sborman 	return;
76838905Sborman #endif	/* NEWINIT */
76938905Sborman }
77038905Sborman 
77138905Sborman #ifndef	NEWINIT
77238905Sborman char	*envinit[3];
77338905Sborman 
77438905Sborman /*
77538905Sborman  * start_login(t, host)
77638905Sborman  *
77738905Sborman  * Assuming that we are now running as a child processes, this
77838905Sborman  * function will turn us into the login process.
77938905Sborman  */
78038905Sborman 
78138905Sborman start_login(t, host)
78238905Sborman int t;
78338905Sborman char *host;
78438905Sborman {
78538905Sborman 	extern char *getenv();
78638905Sborman 	char **envp;
78738905Sborman 
78838905Sborman #ifdef	CRAY
78938905Sborman 	utmp_sig_wait();
79038905Sborman # ifndef TCVHUP
79138905Sborman 	setpgrp();
79238905Sborman # endif
79338905Sborman 	t = open(line, 2);	/* open ttyp */
79438905Sborman 	if (t < 0)
79538905Sborman 		fatalperror(net, line);
79638905Sborman # ifdef	TCVHUP
79738905Sborman 	/*
79838905Sborman 	 * Hangup anybody else using this ttyp, then reopen it for
79938905Sborman 	 * ourselves.
80038905Sborman 	 */
80138905Sborman 	(void) chown(line, 0, 0);
80238905Sborman 	(void) chmod(line, 0600);
80338905Sborman 	(void) signal(SIGHUP, SIG_IGN);
80438905Sborman 	(void) ioctl(t, TCVHUP, (char *)0);
80538905Sborman 	(void) signal(SIGHUP, SIG_DFL);
80638905Sborman 	setpgrp();
80738905Sborman 	i = open(line, 2);
80838905Sborman 	if (i < 0)
80938905Sborman 		fatalperror(net, line);
81038905Sborman 	(void) close(t);
81138905Sborman 	t = i;
81238905Sborman # endif	/* TCVHUP */
81338905Sborman 	/*
81438905Sborman 	 * set ttyp modes as we like them to be
81538905Sborman 	 */
81638905Sborman 	init_termbuf();
81738905Sborman 	termbuf.c_oflag = OPOST|ONLCR;
81838905Sborman 	termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON;
81938905Sborman 	termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK;
82038905Sborman 	termbuf.c_cflag = EXTB|HUPCL|CS8;
82138905Sborman 	set_termbuf();
82238905Sborman #endif	/* CRAY */
82338905Sborman 
82438905Sborman 	/*
82538905Sborman 	 * set up standard paths before forking to login
82638905Sborman 	 */
827*38999Sborman #if	BSD >43
82838905Sborman 	if (setsid() < 0)
82938905Sborman 		fatalperror(net, "setsid");
83038905Sborman 	if (ioctl(t, TIOCSCTTY, (char *)0) < 0)
83138905Sborman 		fatalperror(net, "ioctl(sctty)");
83238905Sborman #endif
83338905Sborman 	(void) close(net);
83438905Sborman 	(void) close(pty);
83538905Sborman 	(void) dup2(t, 0);
83638905Sborman 	(void) dup2(t, 1);
83738905Sborman 	(void) dup2(t, 2);
83838905Sborman 	(void) close(t);
83938905Sborman 	envp = envinit;
84038905Sborman 	*envp++ = terminaltype;
84138905Sborman 	if (*envp = getenv("TZ"))
84238905Sborman 		*envp++ -= 3;
84338905Sborman #ifdef	CRAY
84438905Sborman 	else
84538905Sborman 		*envp++ = "TZ=GMT0";
84638905Sborman #endif
84738905Sborman 	*envp = 0;
84838905Sborman 	environ = envinit;
84938905Sborman 	/*
85038905Sborman 	 * -h : pass on name of host.
85138905Sborman 	 *		WARNING:  -h is accepted by login if and only if
85238905Sborman 	 *			getuid() == 0.
85338905Sborman 	 * -p : don't clobber the environment (so terminal type stays set).
85438905Sborman 	 */
85538905Sborman 	execl(_PATH_LOGIN, "login", "-h", host,
85638905Sborman #ifndef CRAY
85738905Sborman 					terminaltype ? "-p" : 0,
85838905Sborman #endif
85938905Sborman 								0);
86038905Sborman 	syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN);
86138905Sborman 	fatalperror(net, _PATH_LOGIN);
86238905Sborman 	/*NOTREACHED*/
86338905Sborman }
86438905Sborman #endif	NEWINIT
86538905Sborman 
86638905Sborman /*
86738905Sborman  * cleanup()
86838905Sborman  *
86938905Sborman  * This is the routine to call when we are all through, to
87038905Sborman  * clean up anything that needs to be cleaned up.
87138905Sborman  */
87238905Sborman cleanup()
87338905Sborman {
87438905Sborman 
87538905Sborman #ifndef	CRAY
87638905Sborman # if BSD > 43
87738905Sborman 	char *p;
87838905Sborman 
87938905Sborman 	p = line + sizeof("/dev/") - 1;
88038905Sborman 	if (logout(p))
88138905Sborman 		logwtmp(p, "", "");
88238905Sborman 	(void)chmod(line, 0666);
88338905Sborman 	(void)chown(line, 0, 0);
88438905Sborman 	*p = 'p';
88538905Sborman 	(void)chmod(line, 0666);
88638905Sborman 	(void)chown(line, 0, 0);
88738905Sborman # else
88838905Sborman 	rmut();
88938905Sborman 	vhangup();	/* XXX */
89038905Sborman # endif
89138905Sborman 	(void) shutdown(net, 2);
89238905Sborman #else	/* CRAY */
89338905Sborman # ifndef NEWINIT
89438905Sborman 	rmut(line);
89538905Sborman 	(void) shutdown(net, 2);
89638905Sborman 	kill(0, SIGHUP);
89738905Sborman # else	/* NEWINIT */
89838905Sborman 	(void) shutdown(net, 2);
89938905Sborman 	sleep(5);
90038905Sborman # endif	/* NEWINT */
90138905Sborman #endif	/* CRAY */
90238905Sborman 	exit(1);
90338905Sborman }
90438905Sborman 
90538905Sborman #if	defined(CRAY) && !defined(NEWINIT)
90638905Sborman /*
90738905Sborman  * _utmp_sig_rcv
90838905Sborman  * utmp_sig_init
90938905Sborman  * utmp_sig_wait
91038905Sborman  *	These three functions are used to coordinate the handling of
91138905Sborman  *	the utmp file between the server and the soon-to-be-login shell.
91238905Sborman  *	The server actually creates the utmp structure, the child calls
91338905Sborman  *	utmp_sig_wait(), until the server calls utmp_sig_notify() and
91438905Sborman  *	signals the future-login shell to proceed.
91538905Sborman  */
91638905Sborman static int caught=0;		/* NZ when signal intercepted */
91738905Sborman static void (*func)();		/* address of previous handler */
91838905Sborman 
91938905Sborman void
92038905Sborman _utmp_sig_rcv(sig)
92138905Sborman int sig;
92238905Sborman {
92338905Sborman 	caught = 1;
92438905Sborman 	(void) signal(SIGUSR1, func);
92538905Sborman }
92638905Sborman 
92738905Sborman utmp_sig_init()
92838905Sborman {
92938905Sborman 	/*
93038905Sborman 	 * register signal handler for UTMP creation
93138905Sborman 	 */
93238905Sborman 	if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1)
93338905Sborman 		fatalperror(net, "telnetd/signal");
93438905Sborman }
93538905Sborman 
93638905Sborman utmp_sig_wait()
93738905Sborman {
93838905Sborman 	/*
93938905Sborman 	 * Wait for parent to write our utmp entry.
94038905Sborman 	 */
94138905Sborman 	sigoff();
94238905Sborman 	while (caught == 0) {
94338905Sborman 		pause();	/* wait until we get a signal (sigon) */
94438905Sborman 		sigoff();	/* turn off signals while we check caught */
94538905Sborman 	}
94638905Sborman 	sigon();		/* turn on signals again */
94738905Sborman }
94838905Sborman 
94938905Sborman utmp_sig_notify(pid)
95038905Sborman {
95138905Sborman 	kill(pid, SIGUSR1);
95238905Sborman }
95338905Sborman #endif	/* defined(CRAY) && !defined(NEWINIT) */
95438905Sborman 
95538905Sborman /*
95638905Sborman  * rmut()
95738905Sborman  *
95838905Sborman  * This is the function called by cleanup() to
95938905Sborman  * remove the utmp entry for this person.
96038905Sborman  */
96138905Sborman 
96238905Sborman #if	!defined(CRAY) && BSD <= 43
96338905Sborman rmut()
96438905Sborman {
96538905Sborman 	register f;
96638905Sborman 	int found = 0;
96738905Sborman 	struct utmp *u, *utmp;
96838905Sborman 	int nutmp;
96938905Sborman 	struct stat statbf;
97038905Sborman 	char *malloc();
97138905Sborman 	long time();
97238905Sborman 	off_t lseek();
97338905Sborman 
97438905Sborman 	f = open(utmpf, O_RDWR);
97538905Sborman 	if (f >= 0) {
97638905Sborman 		(void) fstat(f, &statbf);
97738905Sborman 		utmp = (struct utmp *)malloc((unsigned)statbf.st_size);
97838905Sborman 		if (!utmp)
97938905Sborman 			syslog(LOG_ERR, "utmp malloc failed");
98038905Sborman 		if (statbf.st_size && utmp) {
98138905Sborman 			nutmp = read(f, (char *)utmp, (int)statbf.st_size);
98238905Sborman 			nutmp /= sizeof(struct utmp);
98338905Sborman 
98438905Sborman 			for (u = utmp ; u < &utmp[nutmp] ; u++) {
98538905Sborman 				if (SCMPN(u->ut_line, line+5) ||
98638905Sborman 				    u->ut_name[0]==0)
98738905Sborman 					continue;
98838905Sborman 				(void) lseek(f, ((long)u)-((long)utmp), L_SET);
98938905Sborman 				SCPYN(u->ut_name, "");
99038905Sborman 				SCPYN(u->ut_host, "");
99138905Sborman 				(void) time(&u->ut_time);
99238905Sborman 				(void) write(f, (char *)u, sizeof(wtmp));
99338905Sborman 				found++;
99438905Sborman 			}
99538905Sborman 		}
99638905Sborman 		(void) close(f);
99738905Sborman 	}
99838905Sborman 	if (found) {
99938905Sborman 		f = open(wtmpf, O_WRONLY|O_APPEND);
100038905Sborman 		if (f >= 0) {
100138905Sborman 			SCPYN(wtmp.ut_line, line+5);
100238905Sborman 			SCPYN(wtmp.ut_name, "");
100338905Sborman 			SCPYN(wtmp.ut_host, "");
100438905Sborman 			(void) time(&wtmp.ut_time);
100538905Sborman 			(void) write(f, (char *)&wtmp, sizeof(wtmp));
100638905Sborman 			(void) close(f);
100738905Sborman 		}
100838905Sborman 	}
100938905Sborman 	(void) chmod(line, 0666);
101038905Sborman 	(void) chown(line, 0, 0);
101138905Sborman 	line[strlen("/dev/")] = 'p';
101238905Sborman 	(void) chmod(line, 0666);
101338905Sborman 	(void) chown(line, 0, 0);
101438905Sborman }  /* end of rmut */
101538905Sborman #endif	/* CRAY */
1016