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