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