1*38905Sborman /* 2*38905Sborman * Copyright (c) 1989 Regents of the University of California. 3*38905Sborman * All rights reserved. 4*38905Sborman * 5*38905Sborman * Redistribution and use in source and binary forms are permitted 6*38905Sborman * provided that the above copyright notice and this paragraph are 7*38905Sborman * duplicated in all such forms and that any documentation, 8*38905Sborman * advertising materials, and other materials related to such 9*38905Sborman * distribution and use acknowledge that the software was developed 10*38905Sborman * by the University of California, Berkeley. The name of the 11*38905Sborman * University may not be used to endorse or promote products derived 12*38905Sborman * from this software without specific prior written permission. 13*38905Sborman * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*38905Sborman * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*38905Sborman * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16*38905Sborman */ 17*38905Sborman 18*38905Sborman #ifndef lint 19*38905Sborman static char sccsid[] = "@(#)sys_term.c 5.1 (Berkeley) 09/01/89"; 20*38905Sborman #endif /* not lint */ 21*38905Sborman 22*38905Sborman #include "telnetd.h" 23*38905Sborman #include "pathnames.h" 24*38905Sborman 25*38905Sborman #ifdef NEWINIT 26*38905Sborman #include <initreq.h> 27*38905Sborman #else /* NEWINIT*/ 28*38905Sborman #include <utmp.h> 29*38905Sborman struct utmp wtmp; 30*38905Sborman 31*38905Sborman # ifndef CRAY 32*38905Sborman char wtmpf[] = "/usr/adm/wtmp"; 33*38905Sborman char utmpf[] = "/etc/utmp"; 34*38905Sborman # else /* CRAY */ 35*38905Sborman char wtmpf[] = "/etc/wtmp"; 36*38905Sborman # endif /* CRAY */ 37*38905Sborman #endif /* NEWINIT */ 38*38905Sborman 39*38905Sborman #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a)) 40*38905Sborman #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 41*38905Sborman 42*38905Sborman #include <sys/tty.h> 43*38905Sborman #ifdef t_erase 44*38905Sborman #undef t_erase 45*38905Sborman #undef t_kill 46*38905Sborman #undef t_intrc 47*38905Sborman #undef t_quitc 48*38905Sborman #undef t_startc 49*38905Sborman #undef t_stopc 50*38905Sborman #undef t_eofc 51*38905Sborman #undef t_brkc 52*38905Sborman #undef t_suspc 53*38905Sborman #undef t_dsuspc 54*38905Sborman #undef t_rprntc 55*38905Sborman #undef t_flushc 56*38905Sborman #undef t_werasc 57*38905Sborman #undef t_lnextc 58*38905Sborman #endif 59*38905Sborman 60*38905Sborman #ifndef USE_TERMIO 61*38905Sborman struct termbuf { 62*38905Sborman struct sgttyb sg; 63*38905Sborman struct tchars tc; 64*38905Sborman struct ltchars ltc; 65*38905Sborman int state; 66*38905Sborman int lflags; 67*38905Sborman } termbuf, termbuf2; 68*38905Sborman #else /* USE_TERMIO */ 69*38905Sborman # ifndef EXTPROC 70*38905Sborman # define EXTPROC 0400 71*38905Sborman # endif 72*38905Sborman # ifdef SYSV_TERMIO 73*38905Sborman # define termios termio 74*38905Sborman # endif 75*38905Sborman struct termios termbuf, termbuf2; /* pty control structure */ 76*38905Sborman #endif /* USE_TERMIO */ 77*38905Sborman 78*38905Sborman /* 79*38905Sborman * init_termbuf() 80*38905Sborman * copy_termbuf(cp) 81*38905Sborman * set_termbuf() 82*38905Sborman * 83*38905Sborman * These three routines are used to get and set the "termbuf" structure 84*38905Sborman * to and from the kernel. init_termbuf() gets the current settings. 85*38905Sborman * copy_termbuf() hands in a new "termbuf" to write to the kernel, and 86*38905Sborman * set_termbuf() writes the structure into the kernel. 87*38905Sborman */ 88*38905Sborman 89*38905Sborman init_termbuf() 90*38905Sborman { 91*38905Sborman #ifndef USE_TERMIO 92*38905Sborman (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg); 93*38905Sborman (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc); 94*38905Sborman (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc); 95*38905Sborman # ifdef TIOCGSTATE 96*38905Sborman (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state); 97*38905Sborman # endif 98*38905Sborman #else 99*38905Sborman (void) ioctl(pty, TCGETA, (char *)&termbuf); 100*38905Sborman #endif 101*38905Sborman termbuf2 = termbuf; 102*38905Sborman } 103*38905Sborman 104*38905Sborman #if defined(LINEMODE) && defined(TIOCPKT_IOCTL) 105*38905Sborman copy_termbuf(cp, len) 106*38905Sborman char *cp; 107*38905Sborman int len; 108*38905Sborman { 109*38905Sborman if (len > sizeof(termbuf)) 110*38905Sborman len = sizeof(termbuf); 111*38905Sborman bcopy(cp, (char *)&termbuf, len); 112*38905Sborman termbuf2 = termbuf; 113*38905Sborman } 114*38905Sborman #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ 115*38905Sborman 116*38905Sborman set_termbuf() 117*38905Sborman { 118*38905Sborman /* 119*38905Sborman * Only make the necessary changes. 120*38905Sborman */ 121*38905Sborman #ifndef USE_TERMIO 122*38905Sborman if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg))) 123*38905Sborman (void) ioctl(pty, TIOCSETP, (char *)&termbuf.sg); 124*38905Sborman if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc))) 125*38905Sborman (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc); 126*38905Sborman if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc, 127*38905Sborman sizeof(termbuf.ltc))) 128*38905Sborman (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc); 129*38905Sborman if (termbuf.lflags != termbuf2.lflags) 130*38905Sborman (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags); 131*38905Sborman #else /* USE_TERMIO */ 132*38905Sborman if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) 133*38905Sborman (void) ioctl(pty, TCSETA, (char *)&termbuf); 134*38905Sborman # ifdef CRAY2 135*38905Sborman needtermstat = 1; 136*38905Sborman # endif 137*38905Sborman #endif /* USE_TERMIO */ 138*38905Sborman } 139*38905Sborman 140*38905Sborman 141*38905Sborman /* 142*38905Sborman * spcset(func, valp, valpp) 143*38905Sborman * 144*38905Sborman * This function takes various special characters (func), and 145*38905Sborman * sets *valp to the current value of that character, and 146*38905Sborman * *valpp to point to where in the "termbuf" structure that 147*38905Sborman * value is kept. 148*38905Sborman * 149*38905Sborman * It returns the SLC_ level of support for this function. 150*38905Sborman */ 151*38905Sborman 152*38905Sborman #ifndef USE_TERMIO 153*38905Sborman spcset(func, valp, valpp) 154*38905Sborman int func; 155*38905Sborman unsigned char *valp; 156*38905Sborman unsigned char **valpp; 157*38905Sborman { 158*38905Sborman switch(func) { 159*38905Sborman case SLC_EOF: 160*38905Sborman *valp = termbuf.tc.t_eofc; 161*38905Sborman *valpp = (unsigned char *)&termbuf.tc.t_eofc; 162*38905Sborman return(SLC_VARIABLE); 163*38905Sborman case SLC_EC: 164*38905Sborman *valp = termbuf.sg.sg_erase; 165*38905Sborman *valpp = (unsigned char *)&termbuf.sg.sg_erase; 166*38905Sborman return(SLC_VARIABLE); 167*38905Sborman case SLC_EL: 168*38905Sborman *valp = termbuf.sg.sg_kill; 169*38905Sborman *valpp = (unsigned char *)&termbuf.sg.sg_kill; 170*38905Sborman return(SLC_VARIABLE); 171*38905Sborman case SLC_IP: 172*38905Sborman *valp = termbuf.tc.t_intrc; 173*38905Sborman *valpp = (unsigned char *)&termbuf.tc.t_intrc; 174*38905Sborman return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 175*38905Sborman case SLC_ABORT: 176*38905Sborman *valp = termbuf.tc.t_quitc; 177*38905Sborman *valpp = (unsigned char *)&termbuf.tc.t_quitc; 178*38905Sborman return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 179*38905Sborman case SLC_XON: 180*38905Sborman *valp = termbuf.tc.t_startc; 181*38905Sborman *valpp = (unsigned char *)&termbuf.tc.t_startc; 182*38905Sborman return(SLC_VARIABLE); 183*38905Sborman case SLC_XOFF: 184*38905Sborman *valp = termbuf.tc.t_stopc; 185*38905Sborman *valpp = (unsigned char *)&termbuf.tc.t_stopc; 186*38905Sborman return(SLC_VARIABLE); 187*38905Sborman case SLC_AO: 188*38905Sborman *valp = termbuf.ltc.t_flushc; 189*38905Sborman *valpp = (unsigned char *)&termbuf.ltc.t_flushc; 190*38905Sborman return(SLC_VARIABLE); 191*38905Sborman case SLC_SUSP: 192*38905Sborman *valp = termbuf.ltc.t_suspc; 193*38905Sborman *valpp = (unsigned char *)&termbuf.ltc.t_suspc; 194*38905Sborman return(SLC_VARIABLE); 195*38905Sborman case SLC_EW: 196*38905Sborman *valp = termbuf.ltc.t_werasc; 197*38905Sborman *valpp = (unsigned char *)&termbuf.ltc.t_werasc; 198*38905Sborman return(SLC_VARIABLE); 199*38905Sborman case SLC_RP: 200*38905Sborman *valp = termbuf.ltc.t_rprntc; 201*38905Sborman *valpp = (unsigned char *)&termbuf.ltc.t_rprntc; 202*38905Sborman return(SLC_VARIABLE); 203*38905Sborman case SLC_LNEXT: 204*38905Sborman *valp = termbuf.ltc.t_lnextc; 205*38905Sborman *valpp = (unsigned char *)&termbuf.ltc.t_lnextc; 206*38905Sborman return(SLC_VARIABLE); 207*38905Sborman case SLC_BRK: 208*38905Sborman case SLC_SYNCH: 209*38905Sborman case SLC_AYT: 210*38905Sborman case SLC_EOR: 211*38905Sborman *valp = 0; 212*38905Sborman *valpp = 0; 213*38905Sborman return(SLC_DEFAULT); 214*38905Sborman default: 215*38905Sborman *valp = 0; 216*38905Sborman *valpp = 0; 217*38905Sborman return(SLC_NOSUPPORT); 218*38905Sborman } 219*38905Sborman } 220*38905Sborman 221*38905Sborman #else /* USE_TERMIO */ 222*38905Sborman 223*38905Sborman spcset(func, valp, valpp) 224*38905Sborman int func; 225*38905Sborman unsigned char *valp; 226*38905Sborman unsigned char **valpp; 227*38905Sborman { 228*38905Sborman switch(func) { 229*38905Sborman case SLC_EOF: 230*38905Sborman *valp = termbuf.c_cc[VEOF]; 231*38905Sborman *valpp = &termbuf.c_cc[VEOF]; 232*38905Sborman return(SLC_VARIABLE); 233*38905Sborman case SLC_EC: 234*38905Sborman *valp = termbuf.c_cc[VERASE]; 235*38905Sborman *valpp = &termbuf.c_cc[VERASE]; 236*38905Sborman return(SLC_VARIABLE); 237*38905Sborman case SLC_EL: 238*38905Sborman *valp = termbuf.c_cc[VKILL]; 239*38905Sborman *valpp = &termbuf.c_cc[VKILL]; 240*38905Sborman return(SLC_VARIABLE); 241*38905Sborman case SLC_IP: 242*38905Sborman *valp = termbuf.c_cc[VINTR]; 243*38905Sborman *valpp = &termbuf.c_cc[VINTR]; 244*38905Sborman return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 245*38905Sborman case SLC_ABORT: 246*38905Sborman *valp = termbuf.c_cc[VQUIT]; 247*38905Sborman *valpp = &termbuf.c_cc[VQUIT]; 248*38905Sborman return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 249*38905Sborman case SLC_XON: 250*38905Sborman *valp = 0x13; 251*38905Sborman *valpp = 0; 252*38905Sborman return(SLC_DEFAULT); 253*38905Sborman case SLC_XOFF: 254*38905Sborman *valp = 0x11; 255*38905Sborman *valpp = 0; 256*38905Sborman return(SLC_DEFAULT); 257*38905Sborman case SLC_EW: 258*38905Sborman case SLC_RP: 259*38905Sborman case SLC_LNEXT: 260*38905Sborman case SLC_BRK: 261*38905Sborman case SLC_SYNCH: 262*38905Sborman case SLC_AYT: 263*38905Sborman case SLC_EOR: 264*38905Sborman *valp = 0; 265*38905Sborman *valpp = 0; 266*38905Sborman return(SLC_DEFAULT); 267*38905Sborman case SLC_AO: 268*38905Sborman case SLC_SUSP: 269*38905Sborman default: 270*38905Sborman *valp = 0; 271*38905Sborman *valpp = 0; 272*38905Sborman return(SLC_NOSUPPORT); 273*38905Sborman } 274*38905Sborman } 275*38905Sborman #endif /* USE_TERMIO */ 276*38905Sborman 277*38905Sborman /* 278*38905Sborman * getpty() 279*38905Sborman * 280*38905Sborman * Allocate a pty. As a side effect, the external character 281*38905Sborman * array "line" contains the name of the slave side. 282*38905Sborman * 283*38905Sborman * Returns the file descriptor of the opened pty. 284*38905Sborman */ 285*38905Sborman char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 286*38905Sborman 287*38905Sborman getpty() 288*38905Sborman { 289*38905Sborman register int p; 290*38905Sborman #ifndef CRAY 291*38905Sborman register char c, *p1, *p2; 292*38905Sborman register int i; 293*38905Sborman 294*38905Sborman (void) sprintf(line, "/dev/ptyXX"); 295*38905Sborman p1 = &line[8]; 296*38905Sborman p2 = &line[9]; 297*38905Sborman 298*38905Sborman for (c = 'p'; c <= 's'; c++) { 299*38905Sborman struct stat stb; 300*38905Sborman 301*38905Sborman *p1 = c; 302*38905Sborman *p2 = '0'; 303*38905Sborman if (stat(line, &stb) < 0) 304*38905Sborman break; 305*38905Sborman for (i = 0; i < 16; i++) { 306*38905Sborman *p2 = "0123456789abcdef"[i]; 307*38905Sborman p = open(line, 2); 308*38905Sborman if (p > 0) { 309*38905Sborman line[5] = 't'; 310*38905Sborman return(p); 311*38905Sborman } 312*38905Sborman } 313*38905Sborman } 314*38905Sborman #else /* CRAY */ 315*38905Sborman register int npty; 316*38905Sborman extern lowpty, highpty; 317*38905Sborman 318*38905Sborman for (npty = lowpty; npty <= highpty; npty++) { 319*38905Sborman (void) sprintf(line, "/dev/pty/%03d", npty); 320*38905Sborman p = open(line, 2); 321*38905Sborman if (p < 0) 322*38905Sborman continue; 323*38905Sborman (void) sprintf(line, "/dev/ttyp%03d", npty); 324*38905Sborman if (access(line, 6) == 0) 325*38905Sborman return(p); 326*38905Sborman else { 327*38905Sborman /* no tty side to pty so skip it */ 328*38905Sborman (void) close(p); 329*38905Sborman } 330*38905Sborman } 331*38905Sborman #endif /* CRAY */ 332*38905Sborman return(-1); 333*38905Sborman } 334*38905Sborman 335*38905Sborman #ifdef LINEMODE 336*38905Sborman /* 337*38905Sborman * tty_flowmode() Find out if flow control is enabled or disabled. 338*38905Sborman * tty_linemode() Find out if linemode (external processing) is enabled. 339*38905Sborman * tty_setlinemod(on) Turn on/off linemode. 340*38905Sborman * tty_isecho() Find out if echoing is turned on. 341*38905Sborman * tty_setecho(on) Enable/disable character echoing. 342*38905Sborman * tty_israw() Find out if terminal is in RAW mode. 343*38905Sborman * tty_binaryin(on) Turn on/off BINARY on input. 344*38905Sborman * tty_binaryout(on) Turn on/off BINARY on output. 345*38905Sborman * tty_isediting() Find out if line editing is enabled. 346*38905Sborman * tty_istrapsig() Find out if signal trapping is enabled. 347*38905Sborman * tty_setedit(on) Turn on/off line editing. 348*38905Sborman * tty_setsig(on) Turn on/off signal trapping. 349*38905Sborman * tty_tspeed(val) Set transmit speed to val. 350*38905Sborman * tty_rspeed(val) Set receive speed to val. 351*38905Sborman */ 352*38905Sborman 353*38905Sborman tty_flowmode() 354*38905Sborman { 355*38905Sborman #ifndef USE_TERMIO 356*38905Sborman return((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0); 357*38905Sborman #else 358*38905Sborman return(termbuf.c_iflag & IXON ? 1 : 0); 359*38905Sborman #endif 360*38905Sborman } 361*38905Sborman 362*38905Sborman tty_linemode() 363*38905Sborman { 364*38905Sborman #ifndef USE_TERMIO 365*38905Sborman return(termbuf.state & TS_EXTPROC); 366*38905Sborman #else 367*38905Sborman return(termbuf.c_lflag & EXTPROC); 368*38905Sborman #endif 369*38905Sborman } 370*38905Sborman 371*38905Sborman tty_setlinemode(on) 372*38905Sborman int on; 373*38905Sborman { 374*38905Sborman #ifdef TIOCEXT 375*38905Sborman (void) ioctl(pty, TIOCEXT, (char *)&on); 376*38905Sborman #else /* !TIOCEXT */ 377*38905Sborman #ifdef EXTPROC 378*38905Sborman if (on) 379*38905Sborman termbuf.c_lflag |= EXTPROC; 380*38905Sborman else 381*38905Sborman termbuf.c_lflag &= ~EXTPROC; 382*38905Sborman #endif 383*38905Sborman set_termbuf(); 384*38905Sborman #endif /* TIOCEXT */ 385*38905Sborman } 386*38905Sborman 387*38905Sborman tty_isecho() 388*38905Sborman { 389*38905Sborman #ifndef USE_TERMIO 390*38905Sborman return (termbuf.sg.sg_flags & ECHO); 391*38905Sborman #else 392*38905Sborman return (termbuf.c_lflag & ECHO); 393*38905Sborman #endif 394*38905Sborman } 395*38905Sborman #endif /* LINEMODE */ 396*38905Sborman 397*38905Sborman tty_setecho(on) 398*38905Sborman { 399*38905Sborman #ifndef USE_TERMIO 400*38905Sborman if (on) 401*38905Sborman termbuf.sg.sg_flags |= ECHO|CRMOD; 402*38905Sborman else 403*38905Sborman termbuf.sg.sg_flags &= ~(ECHO|CRMOD); 404*38905Sborman #else 405*38905Sborman if (on) 406*38905Sborman termbuf.c_lflag |= ECHO; 407*38905Sborman else 408*38905Sborman termbuf.c_lflag &= ~ECHO; 409*38905Sborman #endif 410*38905Sborman } 411*38905Sborman 412*38905Sborman #if defined(LINEMODE) && defined(KLUDGELINEMODE) 413*38905Sborman tty_israw() 414*38905Sborman { 415*38905Sborman #ifndef USE_TERMIO 416*38905Sborman return(termbuf.sg.sg_flags & RAW); 417*38905Sborman #else 418*38905Sborman return(!(termbuf.c_lflag & ICANON)); 419*38905Sborman #endif 420*38905Sborman } 421*38905Sborman #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 422*38905Sborman 423*38905Sborman tty_binaryin(on) 424*38905Sborman { 425*38905Sborman #ifndef USE_TERMIO 426*38905Sborman if (on) 427*38905Sborman termbuf.lflags |= LPASS8; 428*38905Sborman else 429*38905Sborman termbuf.lflags &= ~LPASS8; 430*38905Sborman #else 431*38905Sborman if (on) { 432*38905Sborman termbuf.c_lflag &= ~ISTRIP; 433*38905Sborman } else { 434*38905Sborman termbuf.c_lflag |= ISTRIP; 435*38905Sborman } 436*38905Sborman #endif 437*38905Sborman } 438*38905Sborman 439*38905Sborman tty_binaryout(on) 440*38905Sborman { 441*38905Sborman #ifndef USE_TERMIO 442*38905Sborman if (on) 443*38905Sborman termbuf.lflags |= LLITOUT; 444*38905Sborman else 445*38905Sborman termbuf.lflags &= ~LLITOUT; 446*38905Sborman #else 447*38905Sborman if (on) { 448*38905Sborman termbuf.c_cflag &= ~(CSIZE|PARENB); 449*38905Sborman termbuf.c_cflag |= CS8; 450*38905Sborman termbuf.c_oflag &= ~OPOST; 451*38905Sborman } else { 452*38905Sborman termbuf.c_cflag &= ~CSIZE; 453*38905Sborman termbuf.c_cflag |= CS7|PARENB; 454*38905Sborman termbuf.c_oflag |= OPOST; 455*38905Sborman } 456*38905Sborman #endif 457*38905Sborman } 458*38905Sborman 459*38905Sborman tty_isbinaryin() 460*38905Sborman { 461*38905Sborman #ifndef USE_TERMIO 462*38905Sborman return(termbuf.lflags & LPASS8); 463*38905Sborman #else 464*38905Sborman return(!(termbuf.c_lflag & ISTRIP)); 465*38905Sborman #endif 466*38905Sborman } 467*38905Sborman 468*38905Sborman tty_isbinaryout() 469*38905Sborman { 470*38905Sborman #ifndef USE_TERMIO 471*38905Sborman return(termbuf.lflags & LLITOUT); 472*38905Sborman #else 473*38905Sborman return(mywants[TELOPT_BINARY] == OPT_YES); 474*38905Sborman #endif 475*38905Sborman } 476*38905Sborman 477*38905Sborman #ifdef LINEMODE 478*38905Sborman tty_isediting() 479*38905Sborman { 480*38905Sborman #ifndef USE_TERMIO 481*38905Sborman return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); 482*38905Sborman #else 483*38905Sborman return(termbuf.c_lflag & ICANON); 484*38905Sborman #endif 485*38905Sborman } 486*38905Sborman 487*38905Sborman tty_istrapsig() 488*38905Sborman { 489*38905Sborman #ifndef USE_TERMIO 490*38905Sborman return(!(termbuf.sg.sg_flags&RAW)); 491*38905Sborman #else 492*38905Sborman return(termbuf.c_lflag & ISIG); 493*38905Sborman #endif 494*38905Sborman } 495*38905Sborman 496*38905Sborman tty_setedit(on) 497*38905Sborman int on; 498*38905Sborman { 499*38905Sborman #ifndef USE_TERMIO 500*38905Sborman if (on) 501*38905Sborman termbuf.sg.sg_flags &= ~CBREAK; 502*38905Sborman else 503*38905Sborman termbuf.sg.sg_flags |= CBREAK; 504*38905Sborman #else 505*38905Sborman if (on) 506*38905Sborman termbuf.c_lflag |= ICANON; 507*38905Sborman else 508*38905Sborman termbuf.c_lflag &= ~ICANON; 509*38905Sborman #endif 510*38905Sborman } 511*38905Sborman 512*38905Sborman tty_setsig(on) 513*38905Sborman int on; 514*38905Sborman { 515*38905Sborman #ifndef USE_TERMIO 516*38905Sborman if (on) 517*38905Sborman ; 518*38905Sborman #else 519*38905Sborman if (on) 520*38905Sborman termbuf.c_lflag |= ISIG; 521*38905Sborman else 522*38905Sborman termbuf.c_lflag &= ~ISIG; 523*38905Sborman #endif 524*38905Sborman } 525*38905Sborman #endif /* LINEMODE */ 526*38905Sborman 527*38905Sborman /* 528*38905Sborman * A table of available terminal speeds 529*38905Sborman */ 530*38905Sborman struct termspeeds { 531*38905Sborman int speed; 532*38905Sborman int value; 533*38905Sborman } termspeeds[] = { 534*38905Sborman { 0, B0 }, { 50, B50 }, { 75, B75 }, 535*38905Sborman { 110, B110 }, { 134, B134 }, { 150, B150 }, 536*38905Sborman { 200, B200 }, { 300, B300 }, { 600, B600 }, 537*38905Sborman { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 538*38905Sborman { 4800, B4800 }, { 9600, B9600 }, { 19200, B9600 }, 539*38905Sborman { 38400, B9600 }, { -1, B9600 } 540*38905Sborman }; 541*38905Sborman 542*38905Sborman tty_tspeed(val) 543*38905Sborman { 544*38905Sborman register struct termspeeds *tp; 545*38905Sborman 546*38905Sborman for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 547*38905Sborman ; 548*38905Sborman #ifndef USE_TERMIO 549*38905Sborman termbuf.sg.sg_ospeed = tp->value; 550*38905Sborman #else 551*38905Sborman # ifdef SYSV_TERMIO 552*38905Sborman termbuf.c_cflag &= ~CBAUD; 553*38905Sborman termbuf.c_cflag |= tp->value; 554*38905Sborman # else 555*38905Sborman termbuf.c_ospeed = tp->value; 556*38905Sborman # endif 557*38905Sborman #endif 558*38905Sborman } 559*38905Sborman 560*38905Sborman tty_rspeed(val) 561*38905Sborman { 562*38905Sborman register struct termspeeds *tp; 563*38905Sborman 564*38905Sborman for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 565*38905Sborman ; 566*38905Sborman #ifndef USE_TERMIO 567*38905Sborman termbuf.sg.sg_ispeed = tp->value; 568*38905Sborman #else 569*38905Sborman # ifdef SYSV_TERMIO 570*38905Sborman termbuf.c_cflag &= ~CBAUD; 571*38905Sborman termbuf.c_cflag |= tp->value; 572*38905Sborman # else 573*38905Sborman termbuf.c_ispeed = tp->value; 574*38905Sborman # endif 575*38905Sborman #endif 576*38905Sborman } 577*38905Sborman 578*38905Sborman #ifdef CRAY2 579*38905Sborman tty_isnewmap() 580*38905Sborman { 581*38905Sborman return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) && 582*38905Sborman !(termbuf.c_oflag & ONLRET)); 583*38905Sborman } 584*38905Sborman #endif 585*38905Sborman 586*38905Sborman #ifdef CRAY 587*38905Sborman # ifndef NEWINIT 588*38905Sborman extern struct utmp wtmp; 589*38905Sborman extern char wtmpf[]; 590*38905Sborman # else /* NEWINIT */ 591*38905Sborman int gotalarm; 592*38905Sborman nologinproc() 593*38905Sborman { 594*38905Sborman gotalarm++; 595*38905Sborman } 596*38905Sborman # endif /* NEWINIT */ 597*38905Sborman #endif /* CRAY */ 598*38905Sborman 599*38905Sborman /* 600*38905Sborman * getptyslave() 601*38905Sborman * 602*38905Sborman * Open the slave side of the pty, and do any initialization 603*38905Sborman * that is necessary. The return value is a file descriptor 604*38905Sborman * for the slave side. 605*38905Sborman */ 606*38905Sborman getptyslave() 607*38905Sborman { 608*38905Sborman register int t = -1; 609*38905Sborman 610*38905Sborman #ifndef CRAY 611*38905Sborman /* 612*38905Sborman * Disassociate self from control terminal and open ttyp side. 613*38905Sborman * Set important flags on ttyp and ptyp. 614*38905Sborman */ 615*38905Sborman t = open(_PATH_TTY, O_RDWR); 616*38905Sborman if (t >= 0) { 617*38905Sborman (void) ioctl(t, TIOCNOTTY, (char *)0); 618*38905Sborman (void) close(t); 619*38905Sborman } 620*38905Sborman 621*38905Sborman t = open(line, O_RDWR); 622*38905Sborman if (t < 0) 623*38905Sborman fatalperror(net, line); 624*38905Sborman if (fchmod(t, 0)) 625*38905Sborman fatalperror(net, line); 626*38905Sborman (void) signal(SIGHUP, SIG_IGN); 627*38905Sborman vhangup(); 628*38905Sborman (void) signal(SIGHUP, SIG_DFL); 629*38905Sborman t = open(line, O_RDWR); 630*38905Sborman if (t < 0) 631*38905Sborman fatalperror(net, line); 632*38905Sborman 633*38905Sborman init_termbuf(); 634*38905Sborman #ifndef USE_TERMIO 635*38905Sborman termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO; 636*38905Sborman termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600; 637*38905Sborman #else 638*38905Sborman termbuf.c_lflag |= ECHO; 639*38905Sborman termbuf.c_oflag |= ONLCR|OXTABS; 640*38905Sborman termbuf.c_iflag |= ICRNL; 641*38905Sborman termbuf.c_iflag &= ~IXOFF; 642*38905Sborman # ifdef SYSV_TERMIO 643*38905Sborman termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600; 644*38905Sborman # else SYSV_TERMIO 645*38905Sborman termbuf.c_ospeed = termbuf.c_ispeed = B9600; 646*38905Sborman # endif 647*38905Sborman #endif 648*38905Sborman set_termbuf(); 649*38905Sborman #else /* CRAY */ 650*38905Sborman (void) chown(line, 0, 0); 651*38905Sborman (void) chmod(line, 0600); 652*38905Sborman #endif /* CRAY */ 653*38905Sborman return(t); 654*38905Sborman } 655*38905Sborman 656*38905Sborman #ifdef NEWINIT 657*38905Sborman char *gen_id = "fe"; 658*38905Sborman #endif 659*38905Sborman 660*38905Sborman /* 661*38905Sborman * startslave(t, host) 662*38905Sborman * 663*38905Sborman * Given a file descriptor (t) for a tty, and a hostname, do whatever 664*38905Sborman * is necessary to startup the login process on the slave side of the pty. 665*38905Sborman */ 666*38905Sborman 667*38905Sborman /* ARGSUSED */ 668*38905Sborman startslave(t, host) 669*38905Sborman int t; 670*38905Sborman char *host; 671*38905Sborman { 672*38905Sborman register int i; 673*38905Sborman long time(); 674*38905Sborman 675*38905Sborman #ifndef NEWINIT 676*38905Sborman # ifdef CRAY 677*38905Sborman utmp_sig_init(); 678*38905Sborman # endif /* CRAY */ 679*38905Sborman 680*38905Sborman if ((i = fork()) < 0) 681*38905Sborman fatalperror(net, "fork"); 682*38905Sborman if (i) { 683*38905Sborman # ifdef CRAY 684*38905Sborman /* 685*38905Sborman * Cray parent will create utmp entry for child and send 686*38905Sborman * signal to child to tell when done. Child waits for signal 687*38905Sborman * before doing anything important. 688*38905Sborman */ 689*38905Sborman register int pid = i; 690*38905Sborman 691*38905Sborman setpgrp(); 692*38905Sborman (void) signal(SIGUSR1, func); /* reset handler to default */ 693*38905Sborman /* 694*38905Sborman * Create utmp entry for child 695*38905Sborman */ 696*38905Sborman (void) time(&wtmp.ut_time); 697*38905Sborman wtmp.ut_type = LOGIN_PROCESS; 698*38905Sborman wtmp.ut_pid = pid; 699*38905Sborman SCPYN(wtmp.ut_user, "LOGIN"); 700*38905Sborman SCPYN(wtmp.ut_host, host); 701*38905Sborman SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1); 702*38905Sborman SCPYN(wtmp.ut_id, wtmp.ut_line+3); 703*38905Sborman pututline(&wtmp); 704*38905Sborman endutent(); 705*38905Sborman if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { 706*38905Sborman (void) write(i, (char *)&wtmp, sizeof(struct utmp)); 707*38905Sborman (void) close(i); 708*38905Sborman } 709*38905Sborman utmp_sig_notify(pid); 710*38905Sborman # endif /* CRAY */ 711*38905Sborman (void) close(t); 712*38905Sborman } else { 713*38905Sborman start_login(t, host); 714*38905Sborman /*NOTREACHED*/ 715*38905Sborman } 716*38905Sborman #else /* NEWINIT */ 717*38905Sborman 718*38905Sborman extern char *ptyip; 719*38905Sborman struct init_request request; 720*38905Sborman int nologinproc(); 721*38905Sborman register int n; 722*38905Sborman 723*38905Sborman /* 724*38905Sborman * Init will start up login process if we ask nicely. We only wait 725*38905Sborman * for it to start up and begin normal telnet operation. 726*38905Sborman */ 727*38905Sborman if ((i = open(INIT_FIFO, O_WRONLY)) < 0) { 728*38905Sborman char tbuf[128]; 729*38905Sborman (void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO); 730*38905Sborman fatalperror(net, tbuf); 731*38905Sborman } 732*38905Sborman memset((char *)&request, 0, sizeof(request)); 733*38905Sborman request.magic = INIT_MAGIC; 734*38905Sborman SCPYN(request.gen_id, gen_id); 735*38905Sborman SCPYN(request.tty_id, &line[8]); 736*38905Sborman SCPYN(request.host, host); 737*38905Sborman SCPYN(request.term_type, &terminaltype[5]); 738*38905Sborman if (write(i, (char *)&request, sizeof(request)) < 0) { 739*38905Sborman char tbuf[128]; 740*38905Sborman (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO); 741*38905Sborman fatalperror(net, tbuf); 742*38905Sborman } 743*38905Sborman (void) close(i); 744*38905Sborman (void) signal(SIGALRM, nologinproc); 745*38905Sborman for (i = 0; ; i++) { 746*38905Sborman alarm(15); 747*38905Sborman n = read(pty, ptyip, BUFSIZ); 748*38905Sborman if (i == 3 || n >= 0 || !gotalarm) 749*38905Sborman break; 750*38905Sborman gotalarm = 0; 751*38905Sborman (void) write(net, "telnetd: waiting for /etc/init to start login process.\r\n", 56); 752*38905Sborman } 753*38905Sborman if (n < 0 && gotalarm) 754*38905Sborman fatal(net, "/etc/init didn't start login process"); 755*38905Sborman pcc += n; 756*38905Sborman alarm(0); 757*38905Sborman (void) signal(SIGALRM, SIG_DFL); 758*38905Sborman 759*38905Sborman /* 760*38905Sborman * Set tab expansion the way we like, in case init did something 761*38905Sborman * different. 762*38905Sborman */ 763*38905Sborman init_termbuf(); 764*38905Sborman termbuf.c_oflag &= ~TABDLY; 765*38905Sborman termbuf.c_oflag |= TAB0; 766*38905Sborman set_termbuf(); 767*38905Sborman return; 768*38905Sborman #endif /* NEWINIT */ 769*38905Sborman } 770*38905Sborman 771*38905Sborman #ifndef NEWINIT 772*38905Sborman char *envinit[3]; 773*38905Sborman 774*38905Sborman /* 775*38905Sborman * start_login(t, host) 776*38905Sborman * 777*38905Sborman * Assuming that we are now running as a child processes, this 778*38905Sborman * function will turn us into the login process. 779*38905Sborman */ 780*38905Sborman 781*38905Sborman start_login(t, host) 782*38905Sborman int t; 783*38905Sborman char *host; 784*38905Sborman { 785*38905Sborman extern char *getenv(); 786*38905Sborman char **envp; 787*38905Sborman 788*38905Sborman #ifdef CRAY 789*38905Sborman utmp_sig_wait(); 790*38905Sborman # ifndef TCVHUP 791*38905Sborman setpgrp(); 792*38905Sborman # endif 793*38905Sborman t = open(line, 2); /* open ttyp */ 794*38905Sborman if (t < 0) 795*38905Sborman fatalperror(net, line); 796*38905Sborman # ifdef TCVHUP 797*38905Sborman /* 798*38905Sborman * Hangup anybody else using this ttyp, then reopen it for 799*38905Sborman * ourselves. 800*38905Sborman */ 801*38905Sborman (void) chown(line, 0, 0); 802*38905Sborman (void) chmod(line, 0600); 803*38905Sborman (void) signal(SIGHUP, SIG_IGN); 804*38905Sborman (void) ioctl(t, TCVHUP, (char *)0); 805*38905Sborman (void) signal(SIGHUP, SIG_DFL); 806*38905Sborman setpgrp(); 807*38905Sborman i = open(line, 2); 808*38905Sborman if (i < 0) 809*38905Sborman fatalperror(net, line); 810*38905Sborman (void) close(t); 811*38905Sborman t = i; 812*38905Sborman # endif /* TCVHUP */ 813*38905Sborman /* 814*38905Sborman * set ttyp modes as we like them to be 815*38905Sborman */ 816*38905Sborman init_termbuf(); 817*38905Sborman termbuf.c_oflag = OPOST|ONLCR; 818*38905Sborman termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; 819*38905Sborman termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; 820*38905Sborman termbuf.c_cflag = EXTB|HUPCL|CS8; 821*38905Sborman set_termbuf(); 822*38905Sborman #endif /* CRAY */ 823*38905Sborman 824*38905Sborman /* 825*38905Sborman * set up standard paths before forking to login 826*38905Sborman */ 827*38905Sborman #ifdef BSD >43 828*38905Sborman if (setsid() < 0) 829*38905Sborman fatalperror(net, "setsid"); 830*38905Sborman if (ioctl(t, TIOCSCTTY, (char *)0) < 0) 831*38905Sborman fatalperror(net, "ioctl(sctty)"); 832*38905Sborman #endif 833*38905Sborman (void) close(net); 834*38905Sborman (void) close(pty); 835*38905Sborman (void) dup2(t, 0); 836*38905Sborman (void) dup2(t, 1); 837*38905Sborman (void) dup2(t, 2); 838*38905Sborman (void) close(t); 839*38905Sborman envp = envinit; 840*38905Sborman *envp++ = terminaltype; 841*38905Sborman if (*envp = getenv("TZ")) 842*38905Sborman *envp++ -= 3; 843*38905Sborman #ifdef CRAY 844*38905Sborman else 845*38905Sborman *envp++ = "TZ=GMT0"; 846*38905Sborman #endif 847*38905Sborman *envp = 0; 848*38905Sborman environ = envinit; 849*38905Sborman /* 850*38905Sborman * -h : pass on name of host. 851*38905Sborman * WARNING: -h is accepted by login if and only if 852*38905Sborman * getuid() == 0. 853*38905Sborman * -p : don't clobber the environment (so terminal type stays set). 854*38905Sborman */ 855*38905Sborman execl(_PATH_LOGIN, "login", "-h", host, 856*38905Sborman #ifndef CRAY 857*38905Sborman terminaltype ? "-p" : 0, 858*38905Sborman #endif 859*38905Sborman 0); 860*38905Sborman syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN); 861*38905Sborman fatalperror(net, _PATH_LOGIN); 862*38905Sborman /*NOTREACHED*/ 863*38905Sborman } 864*38905Sborman #endif NEWINIT 865*38905Sborman 866*38905Sborman /* 867*38905Sborman * cleanup() 868*38905Sborman * 869*38905Sborman * This is the routine to call when we are all through, to 870*38905Sborman * clean up anything that needs to be cleaned up. 871*38905Sborman */ 872*38905Sborman cleanup() 873*38905Sborman { 874*38905Sborman 875*38905Sborman #ifndef CRAY 876*38905Sborman # if BSD > 43 877*38905Sborman char *p; 878*38905Sborman 879*38905Sborman p = line + sizeof("/dev/") - 1; 880*38905Sborman if (logout(p)) 881*38905Sborman logwtmp(p, "", ""); 882*38905Sborman (void)chmod(line, 0666); 883*38905Sborman (void)chown(line, 0, 0); 884*38905Sborman *p = 'p'; 885*38905Sborman (void)chmod(line, 0666); 886*38905Sborman (void)chown(line, 0, 0); 887*38905Sborman # else 888*38905Sborman rmut(); 889*38905Sborman vhangup(); /* XXX */ 890*38905Sborman # endif 891*38905Sborman (void) shutdown(net, 2); 892*38905Sborman #else /* CRAY */ 893*38905Sborman # ifndef NEWINIT 894*38905Sborman rmut(line); 895*38905Sborman (void) shutdown(net, 2); 896*38905Sborman kill(0, SIGHUP); 897*38905Sborman # else /* NEWINIT */ 898*38905Sborman (void) shutdown(net, 2); 899*38905Sborman sleep(5); 900*38905Sborman # endif /* NEWINT */ 901*38905Sborman #endif /* CRAY */ 902*38905Sborman exit(1); 903*38905Sborman } 904*38905Sborman 905*38905Sborman #if defined(CRAY) && !defined(NEWINIT) 906*38905Sborman /* 907*38905Sborman * _utmp_sig_rcv 908*38905Sborman * utmp_sig_init 909*38905Sborman * utmp_sig_wait 910*38905Sborman * These three functions are used to coordinate the handling of 911*38905Sborman * the utmp file between the server and the soon-to-be-login shell. 912*38905Sborman * The server actually creates the utmp structure, the child calls 913*38905Sborman * utmp_sig_wait(), until the server calls utmp_sig_notify() and 914*38905Sborman * signals the future-login shell to proceed. 915*38905Sborman */ 916*38905Sborman static int caught=0; /* NZ when signal intercepted */ 917*38905Sborman static void (*func)(); /* address of previous handler */ 918*38905Sborman 919*38905Sborman void 920*38905Sborman _utmp_sig_rcv(sig) 921*38905Sborman int sig; 922*38905Sborman { 923*38905Sborman caught = 1; 924*38905Sborman (void) signal(SIGUSR1, func); 925*38905Sborman } 926*38905Sborman 927*38905Sborman utmp_sig_init() 928*38905Sborman { 929*38905Sborman /* 930*38905Sborman * register signal handler for UTMP creation 931*38905Sborman */ 932*38905Sborman if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) 933*38905Sborman fatalperror(net, "telnetd/signal"); 934*38905Sborman } 935*38905Sborman 936*38905Sborman utmp_sig_wait() 937*38905Sborman { 938*38905Sborman /* 939*38905Sborman * Wait for parent to write our utmp entry. 940*38905Sborman */ 941*38905Sborman sigoff(); 942*38905Sborman while (caught == 0) { 943*38905Sborman pause(); /* wait until we get a signal (sigon) */ 944*38905Sborman sigoff(); /* turn off signals while we check caught */ 945*38905Sborman } 946*38905Sborman sigon(); /* turn on signals again */ 947*38905Sborman } 948*38905Sborman 949*38905Sborman utmp_sig_notify(pid) 950*38905Sborman { 951*38905Sborman kill(pid, SIGUSR1); 952*38905Sborman } 953*38905Sborman #endif /* defined(CRAY) && !defined(NEWINIT) */ 954*38905Sborman 955*38905Sborman /* 956*38905Sborman * rmut() 957*38905Sborman * 958*38905Sborman * This is the function called by cleanup() to 959*38905Sborman * remove the utmp entry for this person. 960*38905Sborman */ 961*38905Sborman 962*38905Sborman #if !defined(CRAY) && BSD <= 43 963*38905Sborman rmut() 964*38905Sborman { 965*38905Sborman register f; 966*38905Sborman int found = 0; 967*38905Sborman struct utmp *u, *utmp; 968*38905Sborman int nutmp; 969*38905Sborman struct stat statbf; 970*38905Sborman char *malloc(); 971*38905Sborman long time(); 972*38905Sborman off_t lseek(); 973*38905Sborman 974*38905Sborman f = open(utmpf, O_RDWR); 975*38905Sborman if (f >= 0) { 976*38905Sborman (void) fstat(f, &statbf); 977*38905Sborman utmp = (struct utmp *)malloc((unsigned)statbf.st_size); 978*38905Sborman if (!utmp) 979*38905Sborman syslog(LOG_ERR, "utmp malloc failed"); 980*38905Sborman if (statbf.st_size && utmp) { 981*38905Sborman nutmp = read(f, (char *)utmp, (int)statbf.st_size); 982*38905Sborman nutmp /= sizeof(struct utmp); 983*38905Sborman 984*38905Sborman for (u = utmp ; u < &utmp[nutmp] ; u++) { 985*38905Sborman if (SCMPN(u->ut_line, line+5) || 986*38905Sborman u->ut_name[0]==0) 987*38905Sborman continue; 988*38905Sborman (void) lseek(f, ((long)u)-((long)utmp), L_SET); 989*38905Sborman SCPYN(u->ut_name, ""); 990*38905Sborman SCPYN(u->ut_host, ""); 991*38905Sborman (void) time(&u->ut_time); 992*38905Sborman (void) write(f, (char *)u, sizeof(wtmp)); 993*38905Sborman found++; 994*38905Sborman } 995*38905Sborman } 996*38905Sborman (void) close(f); 997*38905Sborman } 998*38905Sborman if (found) { 999*38905Sborman f = open(wtmpf, O_WRONLY|O_APPEND); 1000*38905Sborman if (f >= 0) { 1001*38905Sborman SCPYN(wtmp.ut_line, line+5); 1002*38905Sborman SCPYN(wtmp.ut_name, ""); 1003*38905Sborman SCPYN(wtmp.ut_host, ""); 1004*38905Sborman (void) time(&wtmp.ut_time); 1005*38905Sborman (void) write(f, (char *)&wtmp, sizeof(wtmp)); 1006*38905Sborman (void) close(f); 1007*38905Sborman } 1008*38905Sborman } 1009*38905Sborman (void) chmod(line, 0666); 1010*38905Sborman (void) chown(line, 0, 0); 1011*38905Sborman line[strlen("/dev/")] = 'p'; 1012*38905Sborman (void) chmod(line, 0666); 1013*38905Sborman (void) chown(line, 0, 0); 1014*38905Sborman } /* end of rmut */ 1015*38905Sborman #endif /* CRAY */ 1016