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