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