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*40242Sborman static char sccsid[] = "@(#)sys_term.c 5.5 (Berkeley) 02/28/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 7539974Ssklower # ifndef TCSETA 7639974Ssklower # define TCSETA TIOCSETA 7739974Ssklower # define TCGETA TIOCGETA 7839974Ssklower # 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); 138*40242Sborman # if defined(CRAY2) && defined(UNCIOS5) 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; 159*40242Sborman cc_t *valp; 160*40242Sborman cc_t **valpp; 16138905Sborman { 16238905Sborman switch(func) { 16338905Sborman case SLC_EOF: 16438905Sborman *valp = termbuf.tc.t_eofc; 165*40242Sborman *valpp = (cc_t *)&termbuf.tc.t_eofc; 16638905Sborman return(SLC_VARIABLE); 16738905Sborman case SLC_EC: 16838905Sborman *valp = termbuf.sg.sg_erase; 169*40242Sborman *valpp = (cc_t *)&termbuf.sg.sg_erase; 17038905Sborman return(SLC_VARIABLE); 17138905Sborman case SLC_EL: 17238905Sborman *valp = termbuf.sg.sg_kill; 173*40242Sborman *valpp = (cc_t *)&termbuf.sg.sg_kill; 17438905Sborman return(SLC_VARIABLE); 17538905Sborman case SLC_IP: 17638905Sborman *valp = termbuf.tc.t_intrc; 177*40242Sborman *valpp = (cc_t *)&termbuf.tc.t_intrc; 17838905Sborman return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 17938905Sborman case SLC_ABORT: 18038905Sborman *valp = termbuf.tc.t_quitc; 181*40242Sborman *valpp = (cc_t *)&termbuf.tc.t_quitc; 18238905Sborman return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 18338905Sborman case SLC_XON: 18438905Sborman *valp = termbuf.tc.t_startc; 185*40242Sborman *valpp = (cc_t *)&termbuf.tc.t_startc; 18638905Sborman return(SLC_VARIABLE); 18738905Sborman case SLC_XOFF: 18838905Sborman *valp = termbuf.tc.t_stopc; 189*40242Sborman *valpp = (cc_t *)&termbuf.tc.t_stopc; 19038905Sborman return(SLC_VARIABLE); 19138905Sborman case SLC_AO: 19238905Sborman *valp = termbuf.ltc.t_flushc; 193*40242Sborman *valpp = (cc_t *)&termbuf.ltc.t_flushc; 19438905Sborman return(SLC_VARIABLE); 19538905Sborman case SLC_SUSP: 19638905Sborman *valp = termbuf.ltc.t_suspc; 197*40242Sborman *valpp = (cc_t *)&termbuf.ltc.t_suspc; 19838905Sborman return(SLC_VARIABLE); 19938905Sborman case SLC_EW: 20038905Sborman *valp = termbuf.ltc.t_werasc; 201*40242Sborman *valpp = (cc_t *)&termbuf.ltc.t_werasc; 20238905Sborman return(SLC_VARIABLE); 20338905Sborman case SLC_RP: 20438905Sborman *valp = termbuf.ltc.t_rprntc; 205*40242Sborman *valpp = (cc_t *)&termbuf.ltc.t_rprntc; 20638905Sborman return(SLC_VARIABLE); 20738905Sborman case SLC_LNEXT: 20838905Sborman *valp = termbuf.ltc.t_lnextc; 209*40242Sborman *valpp = (cc_t *)&termbuf.ltc.t_lnextc; 21038905Sborman return(SLC_VARIABLE); 211*40242Sborman case SLC_FORW1: 212*40242Sborman *valp = termbuf.tc.t_brkc; 213*40242Sborman *valpp = (cc_t *)&termbuf.ltc.t_lnextc; 214*40242Sborman return(SLC_VARIABLE); 21538905Sborman case SLC_BRK: 21638905Sborman case SLC_SYNCH: 21738905Sborman case SLC_AYT: 21838905Sborman case SLC_EOR: 219*40242Sborman *valp = (cc_t)0; 220*40242Sborman *valpp = (cc_t *)0; 22138905Sborman return(SLC_DEFAULT); 22238905Sborman default: 223*40242Sborman *valp = (cc_t)0; 224*40242Sborman *valpp = (cc_t *)0; 22538905Sborman return(SLC_NOSUPPORT); 22638905Sborman } 22738905Sborman } 22838905Sborman 22938905Sborman #else /* USE_TERMIO */ 23038905Sborman 23138905Sborman spcset(func, valp, valpp) 23238905Sborman int func; 233*40242Sborman cc_t *valp; 234*40242Sborman cc_t **valpp; 23538905Sborman { 23639503Sborman 23739503Sborman #define setval(a, b) *valp = termbuf.c_cc[a]; \ 23839503Sborman *valpp = &termbuf.c_cc[a]; \ 23939503Sborman return(b); 240*40242Sborman #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); 24139503Sborman 24238905Sborman switch(func) { 24338905Sborman case SLC_EOF: 24439503Sborman setval(VEOF, SLC_VARIABLE); 24538905Sborman case SLC_EC: 24639503Sborman setval(VERASE, SLC_VARIABLE); 24738905Sborman case SLC_EL: 24839503Sborman setval(VKILL, SLC_VARIABLE); 24938905Sborman case SLC_IP: 25039503Sborman setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 25138905Sborman case SLC_ABORT: 25239503Sborman setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 25338905Sborman case SLC_XON: 25439503Sborman #ifdef VSTART 25539503Sborman setval(VSTART, SLC_VARIABLE); 25639503Sborman #else 25739503Sborman defval(0x13); 25839503Sborman #endif 25938905Sborman case SLC_XOFF: 26039503Sborman #ifdef VSTOP 26139503Sborman setval(VSTOP, SLC_VARIABLE); 26239503Sborman #else 26339503Sborman defval(0x11); 26439503Sborman #endif 26538905Sborman case SLC_EW: 26639503Sborman #ifdef VWERASE 26739503Sborman setval(VWERASE, SLC_VARIABLE); 26839503Sborman #else 26939503Sborman defval(0); 27039503Sborman #endif 27138905Sborman case SLC_RP: 27239503Sborman #ifdef VREPRINT 27339503Sborman setval(VREPRINT, SLC_VARIABLE); 27439503Sborman #else 27539503Sborman defval(0); 27639503Sborman #endif 27738905Sborman case SLC_LNEXT: 27839503Sborman #ifdef VLNEXT 27939503Sborman setval(VLNEXT, SLC_VARIABLE); 28039503Sborman #else 28139503Sborman defval(0); 28239503Sborman #endif 28339503Sborman case SLC_AO: 28439503Sborman #ifdef VFLUSHO 28539503Sborman setval(VFLUSHO, SLC_VARIABLE|SLC_FLUSHOUT); 28639503Sborman #else 28739503Sborman defval(0); 28839503Sborman #endif 28939503Sborman case SLC_SUSP: 29039503Sborman #ifdef VSUSP 29139503Sborman setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); 29239503Sborman #else 29339503Sborman defval(0); 29439503Sborman #endif 295*40242Sborman #ifdef VEOL 296*40242Sborman case SLC_FORW1: 297*40242Sborman setval(VEOL, SLC_VARIABLE); 298*40242Sborman #endif 299*40242Sborman #ifdef VEOL2 300*40242Sborman case SLC_FORW2: 301*40242Sborman setval(VEOL2, SLC_VARIABLE); 302*40242Sborman #endif 30339503Sborman 30438905Sborman case SLC_BRK: 30538905Sborman case SLC_SYNCH: 30638905Sborman case SLC_AYT: 30738905Sborman case SLC_EOR: 30839503Sborman defval(0); 30939503Sborman 31038905Sborman default: 31138905Sborman *valp = 0; 31238905Sborman *valpp = 0; 31338905Sborman return(SLC_NOSUPPORT); 31438905Sborman } 31538905Sborman } 31638905Sborman #endif /* USE_TERMIO */ 31738905Sborman 318*40242Sborman #ifdef CRAY 31938905Sborman /* 320*40242Sborman * getnpty() 321*40242Sborman * 322*40242Sborman * Return the number of pty's configured into the system. 323*40242Sborman */ 324*40242Sborman getnpty() 325*40242Sborman { 326*40242Sborman #ifdef _SC_CRAY_NPTY 327*40242Sborman return sysconf(_SC_CRAY_NPTY); 328*40242Sborman #else 329*40242Sborman return 128; 330*40242Sborman #endif /* _SC_CRAY_NPTY */ 331*40242Sborman } 332*40242Sborman #endif /* CRAY */ 333*40242Sborman 334*40242Sborman /* 33538905Sborman * getpty() 33638905Sborman * 33738905Sborman * Allocate a pty. As a side effect, the external character 33838905Sborman * array "line" contains the name of the slave side. 33938905Sborman * 34038905Sborman * Returns the file descriptor of the opened pty. 34138905Sborman */ 34238905Sborman char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 34338905Sborman 34438905Sborman getpty() 34538905Sborman { 34638905Sborman register int p; 34738905Sborman #ifndef CRAY 34838905Sborman register char c, *p1, *p2; 34938905Sborman register int i; 35038905Sborman 35138905Sborman (void) sprintf(line, "/dev/ptyXX"); 35238905Sborman p1 = &line[8]; 35338905Sborman p2 = &line[9]; 35438905Sborman 35538905Sborman for (c = 'p'; c <= 's'; c++) { 35638905Sborman struct stat stb; 35738905Sborman 35838905Sborman *p1 = c; 35938905Sborman *p2 = '0'; 36038905Sborman if (stat(line, &stb) < 0) 36138905Sborman break; 36238905Sborman for (i = 0; i < 16; i++) { 36338905Sborman *p2 = "0123456789abcdef"[i]; 36438905Sborman p = open(line, 2); 36538905Sborman if (p > 0) { 36638905Sborman line[5] = 't'; 36738905Sborman return(p); 36838905Sborman } 36938905Sborman } 37038905Sborman } 37138905Sborman #else /* CRAY */ 37238905Sborman register int npty; 37338905Sborman extern lowpty, highpty; 37438905Sborman 37538905Sborman for (npty = lowpty; npty <= highpty; npty++) { 37638905Sborman (void) sprintf(line, "/dev/pty/%03d", npty); 37738905Sborman p = open(line, 2); 37838905Sborman if (p < 0) 37938905Sborman continue; 38038905Sborman (void) sprintf(line, "/dev/ttyp%03d", npty); 38138905Sborman if (access(line, 6) == 0) 38238905Sborman return(p); 38338905Sborman else { 38438905Sborman /* no tty side to pty so skip it */ 38538905Sborman (void) close(p); 38638905Sborman } 38738905Sborman } 38838905Sborman #endif /* CRAY */ 38938905Sborman return(-1); 39038905Sborman } 39138905Sborman 39238905Sborman #ifdef LINEMODE 39338905Sborman /* 39438905Sborman * tty_flowmode() Find out if flow control is enabled or disabled. 39538905Sborman * tty_linemode() Find out if linemode (external processing) is enabled. 39638905Sborman * tty_setlinemod(on) Turn on/off linemode. 39738905Sborman * tty_isecho() Find out if echoing is turned on. 39838905Sborman * tty_setecho(on) Enable/disable character echoing. 39938905Sborman * tty_israw() Find out if terminal is in RAW mode. 40038905Sborman * tty_binaryin(on) Turn on/off BINARY on input. 40138905Sborman * tty_binaryout(on) Turn on/off BINARY on output. 40238905Sborman * tty_isediting() Find out if line editing is enabled. 40338905Sborman * tty_istrapsig() Find out if signal trapping is enabled. 40438905Sborman * tty_setedit(on) Turn on/off line editing. 40538905Sborman * tty_setsig(on) Turn on/off signal trapping. 40638905Sborman * tty_tspeed(val) Set transmit speed to val. 40738905Sborman * tty_rspeed(val) Set receive speed to val. 40838905Sborman */ 40938905Sborman 41038905Sborman tty_flowmode() 41138905Sborman { 41238905Sborman #ifndef USE_TERMIO 41338905Sborman return((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0); 41438905Sborman #else 41538905Sborman return(termbuf.c_iflag & IXON ? 1 : 0); 41638905Sborman #endif 41738905Sborman } 41838905Sborman 41938905Sborman tty_linemode() 42038905Sborman { 42138905Sborman #ifndef USE_TERMIO 42238905Sborman return(termbuf.state & TS_EXTPROC); 42338905Sborman #else 42438905Sborman return(termbuf.c_lflag & EXTPROC); 42538905Sborman #endif 42638905Sborman } 42738905Sborman 42838905Sborman tty_setlinemode(on) 42938905Sborman int on; 43038905Sborman { 43138905Sborman #ifdef TIOCEXT 43238905Sborman (void) ioctl(pty, TIOCEXT, (char *)&on); 43338905Sborman #else /* !TIOCEXT */ 43438905Sborman #ifdef EXTPROC 43538905Sborman if (on) 43638905Sborman termbuf.c_lflag |= EXTPROC; 43738905Sborman else 43838905Sborman termbuf.c_lflag &= ~EXTPROC; 43938905Sborman #endif 44038905Sborman set_termbuf(); 44138905Sborman #endif /* TIOCEXT */ 44238905Sborman } 44338905Sborman 44438905Sborman tty_isecho() 44538905Sborman { 44638905Sborman #ifndef USE_TERMIO 44738905Sborman return (termbuf.sg.sg_flags & ECHO); 44838905Sborman #else 44938905Sborman return (termbuf.c_lflag & ECHO); 45038905Sborman #endif 45138905Sborman } 45238905Sborman #endif /* LINEMODE */ 45338905Sborman 45438905Sborman tty_setecho(on) 45538905Sborman { 45638905Sborman #ifndef USE_TERMIO 45738905Sborman if (on) 45838905Sborman termbuf.sg.sg_flags |= ECHO|CRMOD; 45938905Sborman else 46038905Sborman termbuf.sg.sg_flags &= ~(ECHO|CRMOD); 46138905Sborman #else 46238905Sborman if (on) 46338905Sborman termbuf.c_lflag |= ECHO; 46438905Sborman else 46538905Sborman termbuf.c_lflag &= ~ECHO; 46638905Sborman #endif 46738905Sborman } 46838905Sborman 46938905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 47038905Sborman tty_israw() 47138905Sborman { 47238905Sborman #ifndef USE_TERMIO 47338905Sborman return(termbuf.sg.sg_flags & RAW); 47438905Sborman #else 47538905Sborman return(!(termbuf.c_lflag & ICANON)); 47638905Sborman #endif 47738905Sborman } 47838905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 47938905Sborman 48038905Sborman tty_binaryin(on) 48138905Sborman { 48238905Sborman #ifndef USE_TERMIO 48338905Sborman if (on) 48438905Sborman termbuf.lflags |= LPASS8; 48538905Sborman else 48638905Sborman termbuf.lflags &= ~LPASS8; 48738905Sborman #else 48838905Sborman if (on) { 48938905Sborman termbuf.c_lflag &= ~ISTRIP; 49038905Sborman } else { 49138905Sborman termbuf.c_lflag |= ISTRIP; 49238905Sborman } 49338905Sborman #endif 49438905Sborman } 49538905Sborman 49638905Sborman tty_binaryout(on) 49738905Sborman { 49838905Sborman #ifndef USE_TERMIO 49938905Sborman if (on) 50038905Sborman termbuf.lflags |= LLITOUT; 50138905Sborman else 50238905Sborman termbuf.lflags &= ~LLITOUT; 50338905Sborman #else 50438905Sborman if (on) { 50538905Sborman termbuf.c_cflag &= ~(CSIZE|PARENB); 50638905Sborman termbuf.c_cflag |= CS8; 50738905Sborman termbuf.c_oflag &= ~OPOST; 50838905Sborman } else { 50938905Sborman termbuf.c_cflag &= ~CSIZE; 51038905Sborman termbuf.c_cflag |= CS7|PARENB; 51138905Sborman termbuf.c_oflag |= OPOST; 51238905Sborman } 51338905Sborman #endif 51438905Sborman } 51538905Sborman 51638905Sborman tty_isbinaryin() 51738905Sborman { 51838905Sborman #ifndef USE_TERMIO 51938905Sborman return(termbuf.lflags & LPASS8); 52038905Sborman #else 52139503Sborman return(!(termbuf.c_iflag & ISTRIP)); 52238905Sborman #endif 52338905Sborman } 52438905Sborman 52538905Sborman tty_isbinaryout() 52638905Sborman { 52738905Sborman #ifndef USE_TERMIO 52838905Sborman return(termbuf.lflags & LLITOUT); 52938905Sborman #else 53039503Sborman return(!(termbuf.c_oflag&OPOST)); 53138905Sborman #endif 53238905Sborman } 53338905Sborman 53438905Sborman #ifdef LINEMODE 53538905Sborman tty_isediting() 53638905Sborman { 53738905Sborman #ifndef USE_TERMIO 53838905Sborman return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); 53938905Sborman #else 54038905Sborman return(termbuf.c_lflag & ICANON); 54138905Sborman #endif 54238905Sborman } 54338905Sborman 54438905Sborman tty_istrapsig() 54538905Sborman { 54638905Sborman #ifndef USE_TERMIO 54738905Sborman return(!(termbuf.sg.sg_flags&RAW)); 54838905Sborman #else 54938905Sborman return(termbuf.c_lflag & ISIG); 55038905Sborman #endif 55138905Sborman } 55238905Sborman 55338905Sborman tty_setedit(on) 55438905Sborman int on; 55538905Sborman { 55638905Sborman #ifndef USE_TERMIO 55738905Sborman if (on) 55838905Sborman termbuf.sg.sg_flags &= ~CBREAK; 55938905Sborman else 56038905Sborman termbuf.sg.sg_flags |= CBREAK; 56138905Sborman #else 56238905Sborman if (on) 56338905Sborman termbuf.c_lflag |= ICANON; 56438905Sborman else 56538905Sborman termbuf.c_lflag &= ~ICANON; 56638905Sborman #endif 56738905Sborman } 56838905Sborman 56938905Sborman tty_setsig(on) 57038905Sborman int on; 57138905Sborman { 57238905Sborman #ifndef USE_TERMIO 57338905Sborman if (on) 57438905Sborman ; 57538905Sborman #else 57638905Sborman if (on) 57738905Sborman termbuf.c_lflag |= ISIG; 57838905Sborman else 57938905Sborman termbuf.c_lflag &= ~ISIG; 58038905Sborman #endif 58138905Sborman } 58238905Sborman #endif /* LINEMODE */ 58338905Sborman 58438905Sborman /* 58538905Sborman * A table of available terminal speeds 58638905Sborman */ 58738905Sborman struct termspeeds { 58838905Sborman int speed; 58938905Sborman int value; 59038905Sborman } termspeeds[] = { 59138905Sborman { 0, B0 }, { 50, B50 }, { 75, B75 }, 59238905Sborman { 110, B110 }, { 134, B134 }, { 150, B150 }, 59338905Sborman { 200, B200 }, { 300, B300 }, { 600, B600 }, 59438905Sborman { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 59538905Sborman { 4800, B4800 }, { 9600, B9600 }, { 19200, B9600 }, 59638905Sborman { 38400, B9600 }, { -1, B9600 } 59738905Sborman }; 59838905Sborman 59938905Sborman tty_tspeed(val) 60038905Sborman { 60138905Sborman register struct termspeeds *tp; 60238905Sborman 60338905Sborman for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 60438905Sborman ; 60538905Sborman #ifndef USE_TERMIO 60638905Sborman termbuf.sg.sg_ospeed = tp->value; 60738905Sborman #else 60838905Sborman # ifdef SYSV_TERMIO 60938905Sborman termbuf.c_cflag &= ~CBAUD; 61038905Sborman termbuf.c_cflag |= tp->value; 61138905Sborman # else 61238905Sborman termbuf.c_ospeed = tp->value; 61338905Sborman # endif 61438905Sborman #endif 61538905Sborman } 61638905Sborman 61738905Sborman tty_rspeed(val) 61838905Sborman { 61938905Sborman register struct termspeeds *tp; 62038905Sborman 62138905Sborman for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 62238905Sborman ; 62338905Sborman #ifndef USE_TERMIO 62438905Sborman termbuf.sg.sg_ispeed = tp->value; 62538905Sborman #else 62638905Sborman # ifdef SYSV_TERMIO 62738905Sborman termbuf.c_cflag &= ~CBAUD; 62838905Sborman termbuf.c_cflag |= tp->value; 62938905Sborman # else 63038905Sborman termbuf.c_ispeed = tp->value; 63138905Sborman # endif 63238905Sborman #endif 63338905Sborman } 63438905Sborman 635*40242Sborman #if defined(CRAY2) && defined(UNICOS5) 63638905Sborman tty_isnewmap() 63738905Sborman { 63838905Sborman return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) && 63938905Sborman !(termbuf.c_oflag & ONLRET)); 64038905Sborman } 64138905Sborman #endif 64238905Sborman 64338905Sborman #ifdef CRAY 64438905Sborman # ifndef NEWINIT 64538905Sborman extern struct utmp wtmp; 64638905Sborman extern char wtmpf[]; 64738905Sborman # else /* NEWINIT */ 64838905Sborman int gotalarm; 649*40242Sborman /* ARGSUSED */ 650*40242Sborman void 651*40242Sborman nologinproc(sig) 652*40242Sborman int sig; 65338905Sborman { 65438905Sborman gotalarm++; 65538905Sborman } 65638905Sborman # endif /* NEWINIT */ 65738905Sborman #endif /* CRAY */ 65838905Sborman 65938905Sborman /* 66038905Sborman * getptyslave() 66138905Sborman * 66238905Sborman * Open the slave side of the pty, and do any initialization 66338905Sborman * that is necessary. The return value is a file descriptor 66438905Sborman * for the slave side. 66538905Sborman */ 66638905Sborman getptyslave() 66738905Sborman { 66838905Sborman register int t = -1; 66938905Sborman 67038905Sborman #ifndef CRAY 67138905Sborman /* 67238905Sborman * Disassociate self from control terminal and open ttyp side. 67338905Sborman * Set important flags on ttyp and ptyp. 67438905Sborman */ 67538905Sborman t = open(_PATH_TTY, O_RDWR); 67638905Sborman if (t >= 0) { 67738905Sborman (void) ioctl(t, TIOCNOTTY, (char *)0); 67838905Sborman (void) close(t); 67938905Sborman } 68038905Sborman 68138905Sborman t = open(line, O_RDWR); 68238905Sborman if (t < 0) 68338905Sborman fatalperror(net, line); 68438905Sborman if (fchmod(t, 0)) 68538905Sborman fatalperror(net, line); 68638905Sborman (void) signal(SIGHUP, SIG_IGN); 68738905Sborman vhangup(); 68838905Sborman (void) signal(SIGHUP, SIG_DFL); 68938905Sborman t = open(line, O_RDWR); 69038905Sborman if (t < 0) 69138905Sborman fatalperror(net, line); 69238905Sborman 69338905Sborman init_termbuf(); 69438905Sborman #ifndef USE_TERMIO 695*40242Sborman termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS; 69638905Sborman termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600; 69738905Sborman #else 69838905Sborman termbuf.c_lflag |= ECHO; 69938905Sborman termbuf.c_oflag |= ONLCR|OXTABS; 70038905Sborman termbuf.c_iflag |= ICRNL; 70138905Sborman termbuf.c_iflag &= ~IXOFF; 70238905Sborman # ifdef SYSV_TERMIO 70338905Sborman termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600; 70438905Sborman # else SYSV_TERMIO 70538905Sborman termbuf.c_ospeed = termbuf.c_ispeed = B9600; 70638905Sborman # endif 70738905Sborman #endif 70838905Sborman set_termbuf(); 70938905Sborman #else /* CRAY */ 71038905Sborman (void) chown(line, 0, 0); 71138905Sborman (void) chmod(line, 0600); 71238905Sborman #endif /* CRAY */ 71338905Sborman return(t); 71438905Sborman } 71538905Sborman 71638905Sborman #ifdef NEWINIT 71738905Sborman char *gen_id = "fe"; 71838905Sborman #endif 71938905Sborman 72038905Sborman /* 72138905Sborman * startslave(t, host) 72238905Sborman * 72338905Sborman * Given a file descriptor (t) for a tty, and a hostname, do whatever 72438905Sborman * is necessary to startup the login process on the slave side of the pty. 72538905Sborman */ 72638905Sborman 72738905Sborman /* ARGSUSED */ 72838905Sborman startslave(t, host) 72938905Sborman int t; 73038905Sborman char *host; 73138905Sborman { 73238905Sborman register int i; 73338905Sborman long time(); 73438905Sborman 73538905Sborman #ifndef NEWINIT 73638905Sborman # ifdef CRAY 73738905Sborman utmp_sig_init(); 73838905Sborman # endif /* CRAY */ 73938905Sborman 74038905Sborman if ((i = fork()) < 0) 74138905Sborman fatalperror(net, "fork"); 74238905Sborman if (i) { 74338905Sborman # ifdef CRAY 74438905Sborman /* 74538905Sborman * Cray parent will create utmp entry for child and send 74638905Sborman * signal to child to tell when done. Child waits for signal 74738905Sborman * before doing anything important. 74838905Sborman */ 74938905Sborman register int pid = i; 75038905Sborman 75138905Sborman setpgrp(); 75238905Sborman (void) signal(SIGUSR1, func); /* reset handler to default */ 75338905Sborman /* 75438905Sborman * Create utmp entry for child 75538905Sborman */ 75638905Sborman (void) time(&wtmp.ut_time); 75738905Sborman wtmp.ut_type = LOGIN_PROCESS; 75838905Sborman wtmp.ut_pid = pid; 75938905Sborman SCPYN(wtmp.ut_user, "LOGIN"); 76038905Sborman SCPYN(wtmp.ut_host, host); 76138905Sborman SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1); 76238905Sborman SCPYN(wtmp.ut_id, wtmp.ut_line+3); 76338905Sborman pututline(&wtmp); 76438905Sborman endutent(); 76538905Sborman if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { 76638905Sborman (void) write(i, (char *)&wtmp, sizeof(struct utmp)); 76738905Sborman (void) close(i); 76838905Sborman } 76938905Sborman utmp_sig_notify(pid); 77038905Sborman # endif /* CRAY */ 77138905Sborman (void) close(t); 77238905Sborman } else { 77338905Sborman start_login(t, host); 77438905Sborman /*NOTREACHED*/ 77538905Sborman } 77638905Sborman #else /* NEWINIT */ 77738905Sborman 77838905Sborman extern char *ptyip; 77938905Sborman struct init_request request; 780*40242Sborman void nologinproc(); 78138905Sborman register int n; 78238905Sborman 78338905Sborman /* 78438905Sborman * Init will start up login process if we ask nicely. We only wait 78538905Sborman * for it to start up and begin normal telnet operation. 78638905Sborman */ 78738905Sborman if ((i = open(INIT_FIFO, O_WRONLY)) < 0) { 78838905Sborman char tbuf[128]; 78938905Sborman (void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO); 79038905Sborman fatalperror(net, tbuf); 79138905Sborman } 79238905Sborman memset((char *)&request, 0, sizeof(request)); 79338905Sborman request.magic = INIT_MAGIC; 79438905Sborman SCPYN(request.gen_id, gen_id); 79538905Sborman SCPYN(request.tty_id, &line[8]); 79638905Sborman SCPYN(request.host, host); 79738905Sborman SCPYN(request.term_type, &terminaltype[5]); 798*40242Sborman #if defined(UNICOS5) 799*40242Sborman request.signal = SIGCLD; 800*40242Sborman request.pid = getpid(); 801*40242Sborman #endif 80238905Sborman if (write(i, (char *)&request, sizeof(request)) < 0) { 80338905Sborman char tbuf[128]; 80438905Sborman (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO); 80538905Sborman fatalperror(net, tbuf); 80638905Sborman } 80738905Sborman (void) close(i); 80838905Sborman (void) signal(SIGALRM, nologinproc); 80938905Sborman for (i = 0; ; i++) { 810*40242Sborman char tbuf[128]; 81138905Sborman alarm(15); 81238905Sborman n = read(pty, ptyip, BUFSIZ); 81338905Sborman if (i == 3 || n >= 0 || !gotalarm) 81438905Sborman break; 81538905Sborman gotalarm = 0; 816*40242Sborman sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line); 817*40242Sborman (void) write(net, tbuf, strlen(tbuf)); 81838905Sborman } 81938905Sborman if (n < 0 && gotalarm) 82038905Sborman fatal(net, "/etc/init didn't start login process"); 82138905Sborman pcc += n; 82238905Sborman alarm(0); 82338905Sborman (void) signal(SIGALRM, SIG_DFL); 82438905Sborman 82538905Sborman return; 82638905Sborman #endif /* NEWINIT */ 82738905Sborman } 82838905Sborman 82938905Sborman #ifndef NEWINIT 83038905Sborman char *envinit[3]; 83138905Sborman 83238905Sborman /* 83338905Sborman * start_login(t, host) 83438905Sborman * 83538905Sborman * Assuming that we are now running as a child processes, this 83638905Sborman * function will turn us into the login process. 83738905Sborman */ 83838905Sborman 83938905Sborman start_login(t, host) 84038905Sborman int t; 84138905Sborman char *host; 84238905Sborman { 84338905Sborman extern char *getenv(); 84438905Sborman char **envp; 84538905Sborman 84638905Sborman #ifdef CRAY 84738905Sborman utmp_sig_wait(); 84838905Sborman # ifndef TCVHUP 84938905Sborman setpgrp(); 85038905Sborman # endif 85138905Sborman t = open(line, 2); /* open ttyp */ 85238905Sborman if (t < 0) 85338905Sborman fatalperror(net, line); 85438905Sborman # ifdef TCVHUP 85538905Sborman /* 85638905Sborman * Hangup anybody else using this ttyp, then reopen it for 85738905Sborman * ourselves. 85838905Sborman */ 85938905Sborman (void) chown(line, 0, 0); 86038905Sborman (void) chmod(line, 0600); 86138905Sborman (void) signal(SIGHUP, SIG_IGN); 86238905Sborman (void) ioctl(t, TCVHUP, (char *)0); 86338905Sborman (void) signal(SIGHUP, SIG_DFL); 86438905Sborman setpgrp(); 86538905Sborman i = open(line, 2); 86638905Sborman if (i < 0) 86738905Sborman fatalperror(net, line); 86838905Sborman (void) close(t); 86938905Sborman t = i; 87038905Sborman # endif /* TCVHUP */ 87138905Sborman /* 87238905Sborman * set ttyp modes as we like them to be 87338905Sborman */ 87438905Sborman init_termbuf(); 875*40242Sborman termbuf.c_oflag = OPOST|ONLCR|TAB3; 87638905Sborman termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; 87738905Sborman termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; 87838905Sborman termbuf.c_cflag = EXTB|HUPCL|CS8; 87938905Sborman set_termbuf(); 88038905Sborman #endif /* CRAY */ 88138905Sborman 88238905Sborman /* 88338905Sborman * set up standard paths before forking to login 88438905Sborman */ 88538999Sborman #if BSD >43 88638905Sborman if (setsid() < 0) 88738905Sborman fatalperror(net, "setsid"); 88838905Sborman if (ioctl(t, TIOCSCTTY, (char *)0) < 0) 88938905Sborman fatalperror(net, "ioctl(sctty)"); 89038905Sborman #endif 89138905Sborman (void) close(net); 89238905Sborman (void) close(pty); 89338905Sborman (void) dup2(t, 0); 89438905Sborman (void) dup2(t, 1); 89538905Sborman (void) dup2(t, 2); 89638905Sborman (void) close(t); 89738905Sborman envp = envinit; 89838905Sborman *envp++ = terminaltype; 89938905Sborman if (*envp = getenv("TZ")) 90038905Sborman *envp++ -= 3; 90138905Sborman #ifdef CRAY 90238905Sborman else 90338905Sborman *envp++ = "TZ=GMT0"; 90438905Sborman #endif 90538905Sborman *envp = 0; 90638905Sborman environ = envinit; 90738905Sborman /* 90838905Sborman * -h : pass on name of host. 90938905Sborman * WARNING: -h is accepted by login if and only if 91038905Sborman * getuid() == 0. 91138905Sborman * -p : don't clobber the environment (so terminal type stays set). 91238905Sborman */ 91338905Sborman execl(_PATH_LOGIN, "login", "-h", host, 91438905Sborman #ifndef CRAY 91538905Sborman terminaltype ? "-p" : 0, 91638905Sborman #endif 91738905Sborman 0); 91838905Sborman syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN); 91938905Sborman fatalperror(net, _PATH_LOGIN); 92038905Sborman /*NOTREACHED*/ 92138905Sborman } 92238905Sborman #endif NEWINIT 92338905Sborman 92438905Sborman /* 92538905Sborman * cleanup() 92638905Sborman * 92738905Sborman * This is the routine to call when we are all through, to 92838905Sborman * clean up anything that needs to be cleaned up. 92938905Sborman */ 93038905Sborman cleanup() 93138905Sborman { 93238905Sborman 93338905Sborman #ifndef CRAY 93438905Sborman # if BSD > 43 93538905Sborman char *p; 93638905Sborman 93738905Sborman p = line + sizeof("/dev/") - 1; 93838905Sborman if (logout(p)) 93938905Sborman logwtmp(p, "", ""); 94038905Sborman (void)chmod(line, 0666); 94138905Sborman (void)chown(line, 0, 0); 94238905Sborman *p = 'p'; 94338905Sborman (void)chmod(line, 0666); 94438905Sborman (void)chown(line, 0, 0); 94538905Sborman # else 94638905Sborman rmut(); 94738905Sborman vhangup(); /* XXX */ 94838905Sborman # endif 94938905Sborman (void) shutdown(net, 2); 95038905Sborman #else /* CRAY */ 95138905Sborman # ifndef NEWINIT 95238905Sborman rmut(line); 95338905Sborman (void) shutdown(net, 2); 95438905Sborman kill(0, SIGHUP); 95538905Sborman # else /* NEWINIT */ 95638905Sborman (void) shutdown(net, 2); 957*40242Sborman sleep(2); 95838905Sborman # endif /* NEWINT */ 95938905Sborman #endif /* CRAY */ 96038905Sborman exit(1); 96138905Sborman } 96238905Sborman 96338905Sborman #if defined(CRAY) && !defined(NEWINIT) 96438905Sborman /* 96538905Sborman * _utmp_sig_rcv 96638905Sborman * utmp_sig_init 96738905Sborman * utmp_sig_wait 96838905Sborman * These three functions are used to coordinate the handling of 96938905Sborman * the utmp file between the server and the soon-to-be-login shell. 97038905Sborman * The server actually creates the utmp structure, the child calls 97138905Sborman * utmp_sig_wait(), until the server calls utmp_sig_notify() and 97238905Sborman * signals the future-login shell to proceed. 97338905Sborman */ 97438905Sborman static int caught=0; /* NZ when signal intercepted */ 97538905Sborman static void (*func)(); /* address of previous handler */ 97638905Sborman 97738905Sborman void 97838905Sborman _utmp_sig_rcv(sig) 97938905Sborman int sig; 98038905Sborman { 98138905Sborman caught = 1; 98238905Sborman (void) signal(SIGUSR1, func); 98338905Sborman } 98438905Sborman 98538905Sborman utmp_sig_init() 98638905Sborman { 98738905Sborman /* 98838905Sborman * register signal handler for UTMP creation 98938905Sborman */ 99038905Sborman if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) 99138905Sborman fatalperror(net, "telnetd/signal"); 99238905Sborman } 99338905Sborman 99438905Sborman utmp_sig_wait() 99538905Sborman { 99638905Sborman /* 99738905Sborman * Wait for parent to write our utmp entry. 99838905Sborman */ 99938905Sborman sigoff(); 100038905Sborman while (caught == 0) { 100138905Sborman pause(); /* wait until we get a signal (sigon) */ 100238905Sborman sigoff(); /* turn off signals while we check caught */ 100338905Sborman } 100438905Sborman sigon(); /* turn on signals again */ 100538905Sborman } 100638905Sborman 100738905Sborman utmp_sig_notify(pid) 100838905Sborman { 100938905Sborman kill(pid, SIGUSR1); 101038905Sborman } 101138905Sborman #endif /* defined(CRAY) && !defined(NEWINIT) */ 101238905Sborman 101338905Sborman /* 101438905Sborman * rmut() 101538905Sborman * 101638905Sborman * This is the function called by cleanup() to 101738905Sborman * remove the utmp entry for this person. 101838905Sborman */ 101938905Sborman 102038905Sborman #if !defined(CRAY) && BSD <= 43 102138905Sborman rmut() 102238905Sborman { 102338905Sborman register f; 102438905Sborman int found = 0; 102538905Sborman struct utmp *u, *utmp; 102638905Sborman int nutmp; 102738905Sborman struct stat statbf; 102838905Sborman char *malloc(); 102938905Sborman long time(); 103038905Sborman off_t lseek(); 103138905Sborman 103238905Sborman f = open(utmpf, O_RDWR); 103338905Sborman if (f >= 0) { 103438905Sborman (void) fstat(f, &statbf); 103538905Sborman utmp = (struct utmp *)malloc((unsigned)statbf.st_size); 103638905Sborman if (!utmp) 103738905Sborman syslog(LOG_ERR, "utmp malloc failed"); 103838905Sborman if (statbf.st_size && utmp) { 103938905Sborman nutmp = read(f, (char *)utmp, (int)statbf.st_size); 104038905Sborman nutmp /= sizeof(struct utmp); 104138905Sborman 104238905Sborman for (u = utmp ; u < &utmp[nutmp] ; u++) { 104338905Sborman if (SCMPN(u->ut_line, line+5) || 104438905Sborman u->ut_name[0]==0) 104538905Sborman continue; 104638905Sborman (void) lseek(f, ((long)u)-((long)utmp), L_SET); 104738905Sborman SCPYN(u->ut_name, ""); 104838905Sborman SCPYN(u->ut_host, ""); 104938905Sborman (void) time(&u->ut_time); 105038905Sborman (void) write(f, (char *)u, sizeof(wtmp)); 105138905Sborman found++; 105238905Sborman } 105338905Sborman } 105438905Sborman (void) close(f); 105538905Sborman } 105638905Sborman if (found) { 105738905Sborman f = open(wtmpf, O_WRONLY|O_APPEND); 105838905Sborman if (f >= 0) { 105938905Sborman SCPYN(wtmp.ut_line, line+5); 106038905Sborman SCPYN(wtmp.ut_name, ""); 106138905Sborman SCPYN(wtmp.ut_host, ""); 106238905Sborman (void) time(&wtmp.ut_time); 106338905Sborman (void) write(f, (char *)&wtmp, sizeof(wtmp)); 106438905Sborman (void) close(f); 106538905Sborman } 106638905Sborman } 106738905Sborman (void) chmod(line, 0666); 106838905Sborman (void) chown(line, 0, 0); 106938905Sborman line[strlen("/dev/")] = 'p'; 107038905Sborman (void) chmod(line, 0666); 107138905Sborman (void) chown(line, 0, 0); 107238905Sborman } /* end of rmut */ 107338905Sborman #endif /* CRAY */ 1074