1 /* 2 * Copyright (c) 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)sys_term.c 5.11 (Berkeley) 09/14/90"; 10 #endif /* not lint */ 11 12 #include "telnetd.h" 13 #include "pathnames.h" 14 15 #ifdef NEWINIT 16 #include <initreq.h> 17 #else /* NEWINIT*/ 18 #include <utmp.h> 19 struct utmp wtmp; 20 21 # ifndef CRAY 22 char wtmpf[] = "/usr/adm/wtmp"; 23 char utmpf[] = "/etc/utmp"; 24 # else /* CRAY */ 25 char wtmpf[] = "/etc/wtmp"; 26 # endif /* CRAY */ 27 #endif /* NEWINIT */ 28 29 #define SCPYN(a, b) (void) strncpy(a, b, sizeof(a)) 30 #define SCMPN(a, b) strncmp(a, b, sizeof(a)) 31 32 #ifdef STREAMS 33 #include <sys/stream.h> 34 #endif 35 #include <sys/tty.h> 36 #ifdef t_erase 37 #undef t_erase 38 #undef t_kill 39 #undef t_intrc 40 #undef t_quitc 41 #undef t_startc 42 #undef t_stopc 43 #undef t_eofc 44 #undef t_brkc 45 #undef t_suspc 46 #undef t_dsuspc 47 #undef t_rprntc 48 #undef t_flushc 49 #undef t_werasc 50 #undef t_lnextc 51 #endif 52 53 #if defined(UNICOS5) && defined(CRAY2) && !defined(EXTPROC) 54 # define EXTPROC 0400 55 #endif 56 57 #ifndef USE_TERMIO 58 struct termbuf { 59 struct sgttyb sg; 60 struct tchars tc; 61 struct ltchars ltc; 62 int state; 63 int lflags; 64 } termbuf, termbuf2; 65 # define cfsetospeed(tp, val) (tp)->sg.sg_ospeed = (val) 66 # define cfsetispeed(tp, val) (tp)->sg.sg_ispeed = (val) 67 #else /* USE_TERMIO */ 68 # ifdef SYSV_TERMIO 69 # define termios termio 70 # endif 71 # ifndef TCSANOW 72 # ifdef TCSETS 73 # define TCSANOW TCSETS 74 # define TCSADRAIN TCSETSW 75 # define tcgetattr(f, t) iotcl(f, TCGETS, t) 76 # else 77 # ifdef TCSETA 78 # define TCSANOW TCSETA 79 # define TCSADRAIN TCSETAW 80 # define tcgetattr(f, t) ioctl(f, TCGETA, t) 81 # else 82 # define TCSANOW TIOCSETA 83 # define TCSADRAIN TIOCSETAW 84 # define tcgetattr(f, t) iotcl(f, TIOCGETA, t) 85 # endif 86 # endif 87 # define tcsetattr(f, a, t) ioctl(f, a, t) 88 # define cfsetospeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 89 (tp)->c_cflag |= (val) 90 # ifdef CIBAUD 91 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CIBAUD; \ 92 (tp)->c_cflag |= ((val)<<IBSHIFT) 93 # else 94 # define cfsetispeed(tp, val) (tp)->c_cflag &= ~CBAUD; \ 95 (tp)->c_cflag |= (val) 96 # endif 97 # endif /* TCSANOW */ 98 struct termios termbuf, termbuf2; /* pty control structure */ 99 #endif /* USE_TERMIO */ 100 101 /* 102 * init_termbuf() 103 * copy_termbuf(cp) 104 * set_termbuf() 105 * 106 * These three routines are used to get and set the "termbuf" structure 107 * to and from the kernel. init_termbuf() gets the current settings. 108 * copy_termbuf() hands in a new "termbuf" to write to the kernel, and 109 * set_termbuf() writes the structure into the kernel. 110 */ 111 112 init_termbuf() 113 { 114 #ifndef USE_TERMIO 115 (void) ioctl(pty, TIOCGETP, (char *)&termbuf.sg); 116 (void) ioctl(pty, TIOCGETC, (char *)&termbuf.tc); 117 (void) ioctl(pty, TIOCGLTC, (char *)&termbuf.ltc); 118 # ifdef TIOCGSTATE 119 (void) ioctl(pty, TIOCGSTATE, (char *)&termbuf.state); 120 # endif 121 #else 122 (void) tcgetattr(pty, (char *)&termbuf); 123 #endif 124 termbuf2 = termbuf; 125 } 126 127 #if defined(LINEMODE) && defined(TIOCPKT_IOCTL) 128 copy_termbuf(cp, len) 129 char *cp; 130 int len; 131 { 132 if (len > sizeof(termbuf)) 133 len = sizeof(termbuf); 134 bcopy(cp, (char *)&termbuf, len); 135 termbuf2 = termbuf; 136 } 137 #endif /* defined(LINEMODE) && defined(TIOCPKT_IOCTL) */ 138 139 set_termbuf() 140 { 141 /* 142 * Only make the necessary changes. 143 */ 144 #ifndef USE_TERMIO 145 if (bcmp((char *)&termbuf.sg, (char *)&termbuf2.sg, sizeof(termbuf.sg))) 146 (void) ioctl(pty, TIOCSETN, (char *)&termbuf.sg); 147 if (bcmp((char *)&termbuf.tc, (char *)&termbuf2.tc, sizeof(termbuf.tc))) 148 (void) ioctl(pty, TIOCSETC, (char *)&termbuf.tc); 149 if (bcmp((char *)&termbuf.ltc, (char *)&termbuf2.ltc, 150 sizeof(termbuf.ltc))) 151 (void) ioctl(pty, TIOCSLTC, (char *)&termbuf.ltc); 152 if (termbuf.lflags != termbuf2.lflags) 153 (void) ioctl(pty, TIOCLSET, (char *)&termbuf.lflags); 154 #else /* USE_TERMIO */ 155 if (bcmp((char *)&termbuf, (char *)&termbuf2, sizeof(termbuf))) 156 (void) tcsetattr(pty, TCSADRAIN, (char *)&termbuf); 157 # if defined(CRAY2) && defined(UNCIOS5) 158 needtermstat = 1; 159 # endif 160 #endif /* USE_TERMIO */ 161 } 162 163 164 /* 165 * spcset(func, valp, valpp) 166 * 167 * This function takes various special characters (func), and 168 * sets *valp to the current value of that character, and 169 * *valpp to point to where in the "termbuf" structure that 170 * value is kept. 171 * 172 * It returns the SLC_ level of support for this function. 173 */ 174 175 #ifndef USE_TERMIO 176 spcset(func, valp, valpp) 177 int func; 178 cc_t *valp; 179 cc_t **valpp; 180 { 181 switch(func) { 182 case SLC_EOF: 183 *valp = termbuf.tc.t_eofc; 184 *valpp = (cc_t *)&termbuf.tc.t_eofc; 185 return(SLC_VARIABLE); 186 case SLC_EC: 187 *valp = termbuf.sg.sg_erase; 188 *valpp = (cc_t *)&termbuf.sg.sg_erase; 189 return(SLC_VARIABLE); 190 case SLC_EL: 191 *valp = termbuf.sg.sg_kill; 192 *valpp = (cc_t *)&termbuf.sg.sg_kill; 193 return(SLC_VARIABLE); 194 case SLC_IP: 195 *valp = termbuf.tc.t_intrc; 196 *valpp = (cc_t *)&termbuf.tc.t_intrc; 197 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 198 case SLC_ABORT: 199 *valp = termbuf.tc.t_quitc; 200 *valpp = (cc_t *)&termbuf.tc.t_quitc; 201 return(SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 202 case SLC_XON: 203 *valp = termbuf.tc.t_startc; 204 *valpp = (cc_t *)&termbuf.tc.t_startc; 205 return(SLC_VARIABLE); 206 case SLC_XOFF: 207 *valp = termbuf.tc.t_stopc; 208 *valpp = (cc_t *)&termbuf.tc.t_stopc; 209 return(SLC_VARIABLE); 210 case SLC_AO: 211 *valp = termbuf.ltc.t_flushc; 212 *valpp = (cc_t *)&termbuf.ltc.t_flushc; 213 return(SLC_VARIABLE); 214 case SLC_SUSP: 215 *valp = termbuf.ltc.t_suspc; 216 *valpp = (cc_t *)&termbuf.ltc.t_suspc; 217 return(SLC_VARIABLE); 218 case SLC_EW: 219 *valp = termbuf.ltc.t_werasc; 220 *valpp = (cc_t *)&termbuf.ltc.t_werasc; 221 return(SLC_VARIABLE); 222 case SLC_RP: 223 *valp = termbuf.ltc.t_rprntc; 224 *valpp = (cc_t *)&termbuf.ltc.t_rprntc; 225 return(SLC_VARIABLE); 226 case SLC_LNEXT: 227 *valp = termbuf.ltc.t_lnextc; 228 *valpp = (cc_t *)&termbuf.ltc.t_lnextc; 229 return(SLC_VARIABLE); 230 case SLC_FORW1: 231 *valp = termbuf.tc.t_brkc; 232 *valpp = (cc_t *)&termbuf.ltc.t_lnextc; 233 return(SLC_VARIABLE); 234 case SLC_BRK: 235 case SLC_SYNCH: 236 case SLC_AYT: 237 case SLC_EOR: 238 *valp = (cc_t)0; 239 *valpp = (cc_t *)0; 240 return(SLC_DEFAULT); 241 default: 242 *valp = (cc_t)0; 243 *valpp = (cc_t *)0; 244 return(SLC_NOSUPPORT); 245 } 246 } 247 248 #else /* USE_TERMIO */ 249 250 spcset(func, valp, valpp) 251 int func; 252 cc_t *valp; 253 cc_t **valpp; 254 { 255 256 #define setval(a, b) *valp = termbuf.c_cc[a]; \ 257 *valpp = &termbuf.c_cc[a]; \ 258 return(b); 259 #define defval(a) *valp = ((cc_t)a); *valpp = (cc_t *)0; return(SLC_DEFAULT); 260 261 switch(func) { 262 case SLC_EOF: 263 setval(VEOF, SLC_VARIABLE); 264 case SLC_EC: 265 setval(VERASE, SLC_VARIABLE); 266 case SLC_EL: 267 setval(VKILL, SLC_VARIABLE); 268 case SLC_IP: 269 setval(VINTR, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 270 case SLC_ABORT: 271 setval(VQUIT, SLC_VARIABLE|SLC_FLUSHIN|SLC_FLUSHOUT); 272 case SLC_XON: 273 #ifdef VSTART 274 setval(VSTART, SLC_VARIABLE); 275 #else 276 defval(0x13); 277 #endif 278 case SLC_XOFF: 279 #ifdef VSTOP 280 setval(VSTOP, SLC_VARIABLE); 281 #else 282 defval(0x11); 283 #endif 284 case SLC_EW: 285 #ifdef VWERASE 286 setval(VWERASE, SLC_VARIABLE); 287 #else 288 defval(0); 289 #endif 290 case SLC_RP: 291 #ifdef VREPRINT 292 setval(VREPRINT, SLC_VARIABLE); 293 #else 294 defval(0); 295 #endif 296 case SLC_LNEXT: 297 #ifdef VLNEXT 298 setval(VLNEXT, SLC_VARIABLE); 299 #else 300 defval(0); 301 #endif 302 case SLC_AO: 303 #if !defined(VDISCARD) && defined(VFLUSHO) 304 # define VDISCARD VFLUSHO 305 #endif 306 #ifdef VDISCARD 307 setval(VDISCARD, SLC_VARIABLE|SLC_FLUSHOUT); 308 #else 309 defval(0); 310 #endif 311 case SLC_SUSP: 312 #ifdef VSUSP 313 setval(VSUSP, SLC_VARIABLE|SLC_FLUSHIN); 314 #else 315 defval(0); 316 #endif 317 #ifdef VEOL 318 case SLC_FORW1: 319 setval(VEOL, SLC_VARIABLE); 320 #endif 321 #ifdef VEOL2 322 case SLC_FORW2: 323 setval(VEOL2, SLC_VARIABLE); 324 #endif 325 case SLC_AYT: 326 #ifdef VSTATUS 327 setval(VSTATUS, SLC_VARIABLE); 328 #else 329 defval(0); 330 #endif 331 332 case SLC_BRK: 333 case SLC_SYNCH: 334 case SLC_EOR: 335 defval(0); 336 337 default: 338 *valp = 0; 339 *valpp = 0; 340 return(SLC_NOSUPPORT); 341 } 342 } 343 #endif /* USE_TERMIO */ 344 345 #ifdef CRAY 346 /* 347 * getnpty() 348 * 349 * Return the number of pty's configured into the system. 350 */ 351 getnpty() 352 { 353 #ifdef _SC_CRAY_NPTY 354 return sysconf(_SC_CRAY_NPTY); 355 #else 356 return 128; 357 #endif /* _SC_CRAY_NPTY */ 358 } 359 #endif /* CRAY */ 360 361 #ifndef convex 362 /* 363 * getpty() 364 * 365 * Allocate a pty. As a side effect, the external character 366 * array "line" contains the name of the slave side. 367 * 368 * Returns the file descriptor of the opened pty. 369 */ 370 #ifndef __GNUC__ 371 char *line = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 372 #else 373 static char Xline[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 374 char *line = Xline; 375 #endif 376 #ifdef CRAY 377 char *myline = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"; 378 #endif /* CRAY */ 379 380 getpty() 381 { 382 register int p; 383 #ifndef CRAY 384 register char c, *p1, *p2; 385 register int i; 386 387 (void) sprintf(line, "/dev/ptyXX"); 388 p1 = &line[8]; 389 p2 = &line[9]; 390 391 for (c = 'p'; c <= 's'; c++) { 392 struct stat stb; 393 394 *p1 = c; 395 *p2 = '0'; 396 if (stat(line, &stb) < 0) 397 break; 398 for (i = 0; i < 16; i++) { 399 *p2 = "0123456789abcdef"[i]; 400 p = open(line, 2); 401 if (p > 0) { 402 line[5] = 't'; 403 return(p); 404 } 405 } 406 } 407 #else /* CRAY */ 408 register int npty; 409 extern lowpty, highpty; 410 struct stat sb; 411 412 for (npty = lowpty; npty <= highpty; npty++) { 413 (void) sprintf(myline, "/dev/pty/%03d", npty); 414 p = open(myline, 2); 415 if (p < 0) 416 continue; 417 (void) sprintf(line, "/dev/ttyp%03d", npty); 418 /* 419 * Here are some shenanigans to make sure that there 420 * are no listeners lurking on the line. 421 */ 422 if(stat(line, &sb) < 0) { 423 (void) close(p); 424 continue; 425 } 426 if(sb.st_uid || sb.st_gid || sb.st_mode != 0600) { 427 chown(line, 0, 0); 428 chmod(line, 0600); 429 (void)close(p); 430 p = open(myline, 2); 431 if (p < 0) 432 continue; 433 } 434 /* 435 * Now it should be safe...check for accessability. 436 */ 437 if (access(line, 6) == 0) 438 return(p); 439 else { 440 /* no tty side to pty so skip it */ 441 (void) close(p); 442 } 443 } 444 #endif /* CRAY */ 445 return(-1); 446 } 447 #endif /* convex */ 448 449 #ifdef LINEMODE 450 /* 451 * tty_flowmode() Find out if flow control is enabled or disabled. 452 * tty_linemode() Find out if linemode (external processing) is enabled. 453 * tty_setlinemod(on) Turn on/off linemode. 454 * tty_isecho() Find out if echoing is turned on. 455 * tty_setecho(on) Enable/disable character echoing. 456 * tty_israw() Find out if terminal is in RAW mode. 457 * tty_binaryin(on) Turn on/off BINARY on input. 458 * tty_binaryout(on) Turn on/off BINARY on output. 459 * tty_isediting() Find out if line editing is enabled. 460 * tty_istrapsig() Find out if signal trapping is enabled. 461 * tty_setedit(on) Turn on/off line editing. 462 * tty_setsig(on) Turn on/off signal trapping. 463 * tty_issofttab() Find out if tab expansion is enabled. 464 * tty_setsofttab(on) Turn on/off soft tab expansion. 465 * tty_islitecho() Find out if typed control chars are echoed literally 466 * tty_setlitecho() Turn on/off literal echo of control chars 467 * tty_tspeed(val) Set transmit speed to val. 468 * tty_rspeed(val) Set receive speed to val. 469 */ 470 471 tty_flowmode() 472 { 473 #ifndef USE_TERMIO 474 return((termbuf.tc.t_startc) > 0 && (termbuf.tc.t_stopc) > 0); 475 #else 476 return(termbuf.c_iflag & IXON ? 1 : 0); 477 #endif 478 } 479 480 #ifdef convex 481 static int linestate; 482 #endif 483 484 tty_linemode() 485 { 486 #ifndef convex 487 #ifndef USE_TERMIO 488 return(termbuf.state & TS_EXTPROC); 489 #else 490 return(termbuf.c_lflag & EXTPROC); 491 #endif 492 #else 493 return(linestate); 494 #endif 495 } 496 497 tty_setlinemode(on) 498 int on; 499 { 500 #ifdef TIOCEXT 501 # ifndef convex 502 set_termbuf(); 503 # else 504 linestate = on; 505 # endif 506 (void) ioctl(pty, TIOCEXT, (char *)&on); 507 # ifndef convex 508 init_termbuf(); 509 # endif 510 #else /* !TIOCEXT */ 511 # ifdef EXTPROC 512 if (on) 513 termbuf.c_lflag |= EXTPROC; 514 else 515 termbuf.c_lflag &= ~EXTPROC; 516 # endif 517 #endif /* TIOCEXT */ 518 } 519 520 tty_isecho() 521 { 522 #ifndef USE_TERMIO 523 return (termbuf.sg.sg_flags & ECHO); 524 #else 525 return (termbuf.c_lflag & ECHO); 526 #endif 527 } 528 #endif /* LINEMODE */ 529 530 tty_setecho(on) 531 { 532 #ifndef USE_TERMIO 533 if (on) 534 termbuf.sg.sg_flags |= ECHO|CRMOD; 535 else 536 termbuf.sg.sg_flags &= ~(ECHO|CRMOD); 537 #else 538 if (on) 539 termbuf.c_lflag |= ECHO; 540 else 541 termbuf.c_lflag &= ~ECHO; 542 #endif 543 } 544 545 #if defined(LINEMODE) && defined(KLUDGELINEMODE) 546 tty_israw() 547 { 548 #ifndef USE_TERMIO 549 return(termbuf.sg.sg_flags & RAW); 550 #else 551 return(!(termbuf.c_lflag & ICANON)); 552 #endif 553 } 554 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 555 556 tty_binaryin(on) 557 { 558 #ifndef USE_TERMIO 559 if (on) 560 termbuf.lflags |= LPASS8; 561 else 562 termbuf.lflags &= ~LPASS8; 563 #else 564 if (on) { 565 termbuf.c_lflag &= ~ISTRIP; 566 } else { 567 termbuf.c_lflag |= ISTRIP; 568 } 569 #endif 570 } 571 572 tty_binaryout(on) 573 { 574 #ifndef USE_TERMIO 575 if (on) 576 termbuf.lflags |= LLITOUT; 577 else 578 termbuf.lflags &= ~LLITOUT; 579 #else 580 if (on) { 581 termbuf.c_cflag &= ~(CSIZE|PARENB); 582 termbuf.c_cflag |= CS8; 583 termbuf.c_oflag &= ~OPOST; 584 } else { 585 termbuf.c_cflag &= ~CSIZE; 586 termbuf.c_cflag |= CS7|PARENB; 587 termbuf.c_oflag |= OPOST; 588 } 589 #endif 590 } 591 592 tty_isbinaryin() 593 { 594 #ifndef USE_TERMIO 595 return(termbuf.lflags & LPASS8); 596 #else 597 return(!(termbuf.c_iflag & ISTRIP)); 598 #endif 599 } 600 601 tty_isbinaryout() 602 { 603 #ifndef USE_TERMIO 604 return(termbuf.lflags & LLITOUT); 605 #else 606 return(!(termbuf.c_oflag&OPOST)); 607 #endif 608 } 609 610 #ifdef LINEMODE 611 tty_isediting() 612 { 613 #ifndef USE_TERMIO 614 return(!(termbuf.sg.sg_flags & (CBREAK|RAW))); 615 #else 616 return(termbuf.c_lflag & ICANON); 617 #endif 618 } 619 620 tty_istrapsig() 621 { 622 #ifndef USE_TERMIO 623 return(!(termbuf.sg.sg_flags&RAW)); 624 #else 625 return(termbuf.c_lflag & ISIG); 626 #endif 627 } 628 629 tty_setedit(on) 630 int on; 631 { 632 #ifndef USE_TERMIO 633 if (on) 634 termbuf.sg.sg_flags &= ~CBREAK; 635 else 636 termbuf.sg.sg_flags |= CBREAK; 637 #else 638 if (on) 639 termbuf.c_lflag |= ICANON; 640 else 641 termbuf.c_lflag &= ~ICANON; 642 #endif 643 } 644 645 tty_setsig(on) 646 int on; 647 { 648 #ifndef USE_TERMIO 649 if (on) 650 ; 651 #else 652 if (on) 653 termbuf.c_lflag |= ISIG; 654 else 655 termbuf.c_lflag &= ~ISIG; 656 #endif 657 } 658 #endif /* LINEMODE */ 659 660 tty_issofttab() 661 { 662 #ifndef USE_TERMIO 663 return (termbuf.sg.sg_flags & XTABS); 664 #else 665 # ifdef OXTABS 666 return (termbuf.c_oflag & OXTABS); 667 # endif 668 # ifdef TABDLY 669 return ((termbuf.c_oflag & TABDLY) == TAB3); 670 # endif 671 #endif 672 } 673 674 tty_setsofttab(on) 675 int on; 676 { 677 #ifndef USE_TERMIO 678 if (on) 679 termbuf.sg.sg_flags |= XTABS; 680 else 681 termbuf.sg.sg_flags &= ~XTABS; 682 #else 683 if (on) { 684 # ifdef OXTABS 685 termbuf.c_oflag |= OXTABS; 686 # endif 687 # ifdef TABDLY 688 termbuf.c_oflag &= ~TABDLY; 689 termbuf.c_oflag |= TAB3; 690 # endif 691 } else { 692 # ifdef OXTABS 693 termbuf.c_oflag &= ~OXTABS; 694 # endif 695 # ifdef TABDLY 696 termbuf.c_oflag &= ~TABDLY; 697 termbuf.c_oflag |= TAB0; 698 # endif 699 } 700 #endif 701 } 702 703 tty_islitecho() 704 { 705 #ifndef USE_TERMIO 706 return (!(termbuf.sg.sg_flags & CTLECH)); 707 #else 708 # ifdef ECHOCTL 709 return (!(termbuf.c_lflag & ECHOCTL)); 710 # endif 711 # ifdef TCTLECH 712 return (!(termbuf.c_lflag & TCTLECH)); 713 # endif 714 # if !defined(ECHOCTL) && !defined(TCTLECH) 715 return (0); /* assumes ctl chars are echoed '^x' */ 716 # endif 717 #endif 718 } 719 720 tty_setlitecho(on) 721 int on; 722 { 723 #ifndef USE_TERMIO 724 if (on) 725 termbuf.sg.sg_flags &= ~CTLECH; 726 else 727 termbuf.sg.sg_flags |= CTLECH; 728 #else 729 # ifdef ECHOCTL 730 if (on) 731 termbuf.c_lflag &= ~ECHOCTL; 732 else 733 termbuf.c_lflag |= ECHOCTL; 734 # endif 735 # ifdef TCTLECH 736 if (on) 737 termbuf.c_lflag &= ~TCTLECH; 738 else 739 termbuf.c_lflag |= TCTLECH; 740 # endif 741 #endif 742 } 743 744 /* 745 * A table of available terminal speeds 746 */ 747 struct termspeeds { 748 int speed; 749 int value; 750 } termspeeds[] = { 751 { 0, B0 }, { 50, B50 }, { 75, B75 }, 752 { 110, B110 }, { 134, B134 }, { 150, B150 }, 753 { 200, B200 }, { 300, B300 }, { 600, B600 }, 754 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 755 { 4800, B4800 }, { 9600, B9600 }, { 19200, B9600 }, 756 { 38400, B9600 }, { -1, B9600 } 757 }; 758 759 tty_tspeed(val) 760 { 761 register struct termspeeds *tp; 762 763 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 764 ; 765 cfsetospeed(&termbuf, tp->value); 766 } 767 768 tty_rspeed(val) 769 { 770 register struct termspeeds *tp; 771 772 for (tp = termspeeds; (tp->speed != -1) && (val > tp->speed); tp++) 773 ; 774 cfsetispeed(&termbuf, tp->value); 775 } 776 777 #if defined(CRAY2) && defined(UNICOS5) 778 tty_isnewmap() 779 { 780 return((termbuf.c_oflag & OPOST) && (termbuf.c_oflag & ONLCR) && 781 !(termbuf.c_oflag & ONLRET)); 782 } 783 #endif 784 785 #ifdef CRAY 786 # ifndef NEWINIT 787 extern struct utmp wtmp; 788 extern char wtmpf[]; 789 # else /* NEWINIT */ 790 int gotalarm; 791 /* ARGSUSED */ 792 void 793 nologinproc(sig) 794 int sig; 795 { 796 gotalarm++; 797 } 798 # endif /* NEWINIT */ 799 #endif /* CRAY */ 800 801 /* 802 * getptyslave() 803 * 804 * Open the slave side of the pty, and do any initialization 805 * that is necessary. The return value is a file descriptor 806 * for the slave side. 807 */ 808 getptyslave() 809 { 810 register int t = -1; 811 812 #if !defined(CRAY) || !defined(NEWINIT) 813 # ifdef LINEMODE 814 /* 815 * Opening the slave side may cause initilization of the 816 * kernel tty structure. We need remember whether or not 817 * linemode was turned on, so that we can re-set it if we 818 * need to. 819 */ 820 int waslm = tty_linemode(); 821 # endif 822 823 824 /* 825 * Make sure that we don't have a controlling tty, and 826 * that we are the session (process group) leader. 827 */ 828 # ifdef TIOCNOTTY 829 t = open(_PATH_TTY, O_RDWR); 830 if (t >= 0) { 831 (void) ioctl(t, TIOCNOTTY, (char *)0); 832 (void) close(t); 833 } 834 # endif 835 836 837 # ifdef CRAY 838 /* 839 * Wait for our parent to get the utmp stuff to get done. 840 */ 841 utmp_sig_wait(); 842 # endif 843 844 t = cleanopen(line); 845 if (t < 0) 846 fatalperror(net, line); 847 848 /* 849 * set up the tty modes as we like them to be. 850 */ 851 init_termbuf(); 852 # ifdef LINEMODE 853 if (waslm) 854 tty_setlinemode(); 855 # endif LINEMODE 856 857 /* 858 * Settings for sgtty based systems 859 */ 860 # ifndef USE_TERMIO 861 termbuf.sg.sg_flags |= CRMOD|ANYP|ECHO|XTABS; 862 termbuf.sg.sg_ospeed = termbuf.sg.sg_ispeed = B9600; 863 # endif /* USE_TERMIO */ 864 865 /* 866 * Settings for UNICOS 867 */ 868 # ifdef CRAY 869 termbuf.c_oflag = OPOST|ONLCR|TAB3; 870 termbuf.c_iflag = IGNPAR|ISTRIP|ICRNL|IXON; 871 termbuf.c_lflag = ISIG|ICANON|ECHO|ECHOE|ECHOK; 872 termbuf.c_cflag = EXTB|HUPCL|CS8; 873 # endif 874 875 /* 876 * Settings for all other termios/termio based 877 * systems, other than 4.4BSD. In 4.4BSD the 878 * kernel does the initial terminal setup. 879 */ 880 # if defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) 881 # ifndef OXTABS 882 # define OXTABS 0 883 # endif 884 termbuf.c_lflag |= ECHO; 885 termbuf.c_oflag |= ONLCR|OXTABS; 886 termbuf.c_iflag |= ICRNL; 887 termbuf.c_iflag &= ~IXOFF; 888 cfsetospeed(&termbuf, B9600); 889 cfsetispeed(&termbuf, B9600); 890 # endif /* defined(USE_TERMIO) && !defined(CRAY) && (BSD <= 43) */ 891 892 /* 893 * Set the tty modes, and make this our controlling tty. 894 */ 895 set_termbuf(); 896 if (login_tty(t) == -1) 897 fatalperror(net, "login_tty"); 898 #endif /* !defined(CRAY) || !defined(NEWINIT) */ 899 if (net > 2) 900 (void) close(net); 901 if (pty > 2) 902 (void) close(pty); 903 } 904 905 #if !defined(CRAY) || !defined(NEWINIT) 906 #ifndef O_NOCTTY 907 #define O_NOCTTY 0 908 #endif 909 /* 910 * Open the specified slave side of the pty, 911 * making sure that we have a clean tty. 912 */ 913 cleanopen(line) 914 char *line; 915 { 916 register int t; 917 918 /* 919 * Make sure that other people can't open the 920 * slave side of the connection. 921 */ 922 (void) chown(line, 0, 0); 923 (void) chmod(line, 0600); 924 925 # if !defined(CRAY) && (BSD > 43) 926 (void) revoke(line); 927 # endif 928 t = open(line, O_RDWR|O_NOCTTY); 929 if (t < 0) 930 return(-1); 931 932 /* 933 * Hangup anybody else using this ttyp, then reopen it for 934 * ourselves. 935 */ 936 # if !defined(CRAY) && (BSD <= 43) 937 (void) signal(SIGHUP, SIG_IGN); 938 vhangup(); 939 (void) signal(SIGHUP, SIG_DFL); 940 t = open(line, O_RDWR|O_NOCTTY); 941 if (t < 0) 942 return(-1); 943 # endif 944 # if defined(CRAY) && defined(TCVHUP) 945 { 946 register int i; 947 (void) signal(SIGHUP, SIG_IGN); 948 (void) ioctl(t, TCVHUP, (char *)0); 949 (void) signal(SIGHUP, SIG_DFL); 950 setpgrp(); 951 i = open(line, O_RDWR); 952 if (i < 0) 953 return(-1) 954 (void) close(t); 955 t = i; 956 } 957 # endif /* defined(CRAY) && defined(TCVHUP) */ 958 return(t); 959 } 960 #endif /* !defined(CRAY) || !defined(NEWINIT) */ 961 962 #if BSD <= 43 963 login_tty(t) 964 int t; 965 { 966 # ifndef NO_SETSID 967 if (setsid() < 0) 968 fatalperror(net, "setsid()"); 969 # else 970 # ifndef convex 971 if (setpgrp(0,0) < 0) 972 fatalperror(net, "setpgrp()"); 973 # endif 974 # endif 975 # ifdef TIOCSCTTY 976 if (ioctl(t, TIOCSCTTY, (char *)0) < 0) 977 fatalperror(net, "ioctl(sctty)"); 978 # else 979 close(open(line, O_RDWR)); 980 # endif 981 (void) dup2(t, 0); 982 (void) dup2(t, 1); 983 (void) dup2(t, 2); 984 close(t); 985 } 986 #endif /* BSD <= 43 */ 987 988 #ifdef NEWINIT 989 char *gen_id = "fe"; 990 #endif 991 992 /* 993 * startslave(host) 994 * 995 * Given a hostname, do whatever 996 * is necessary to startup the login process on the slave side of the pty. 997 */ 998 999 /* ARGSUSED */ 1000 startslave(host) 1001 char *host; 1002 { 1003 register int i; 1004 long time(); 1005 1006 #ifndef NEWINIT 1007 # ifdef CRAY 1008 utmp_sig_init(); 1009 # endif /* CRAY */ 1010 1011 if ((i = fork()) < 0) 1012 fatalperror(net, "fork"); 1013 if (i) { 1014 # ifdef CRAY 1015 /* 1016 * Cray parent will create utmp entry for child and send 1017 * signal to child to tell when done. Child waits for signal 1018 * before doing anything important. 1019 */ 1020 register int pid = i; 1021 1022 setpgrp(); 1023 utmp_sig_reset(); /* reset handler to default */ 1024 /* 1025 * Create utmp entry for child 1026 */ 1027 (void) time(&wtmp.ut_time); 1028 wtmp.ut_type = LOGIN_PROCESS; 1029 wtmp.ut_pid = pid; 1030 SCPYN(wtmp.ut_user, "LOGIN"); 1031 SCPYN(wtmp.ut_host, host); 1032 SCPYN(wtmp.ut_line, line + sizeof("/dev/") - 1); 1033 SCPYN(wtmp.ut_id, wtmp.ut_line+3); 1034 pututline(&wtmp); 1035 endutent(); 1036 if ((i = open(wtmpf, O_WRONLY|O_APPEND)) >= 0) { 1037 (void) write(i, (char *)&wtmp, sizeof(struct utmp)); 1038 (void) close(i); 1039 } 1040 utmp_sig_notify(pid); 1041 # endif /* CRAY */ 1042 } else { 1043 getptyslave(); 1044 start_login(host); 1045 /*NOTREACHED*/ 1046 } 1047 #else /* NEWINIT */ 1048 1049 extern char *ptyip; 1050 struct init_request request; 1051 void nologinproc(); 1052 register int n; 1053 1054 /* 1055 * Init will start up login process if we ask nicely. We only wait 1056 * for it to start up and begin normal telnet operation. 1057 */ 1058 if ((i = open(INIT_FIFO, O_WRONLY)) < 0) { 1059 char tbuf[128]; 1060 (void) sprintf(tbuf, "Can't open %s\n", INIT_FIFO); 1061 fatalperror(net, tbuf); 1062 } 1063 memset((char *)&request, 0, sizeof(request)); 1064 request.magic = INIT_MAGIC; 1065 SCPYN(request.gen_id, gen_id); 1066 SCPYN(request.tty_id, &line[8]); 1067 SCPYN(request.host, host); 1068 SCPYN(request.term_type, terminaltype); 1069 #if !defined(UNICOS5) 1070 request.signal = SIGCLD; 1071 request.pid = getpid(); 1072 #endif 1073 #ifdef BFTPDAEMON 1074 /* 1075 * Are we working as the bftp daemon? 1076 */ 1077 if (bftpd) { 1078 SCPYN(request.exec_name, BFTPPATH); 1079 } 1080 #endif /* BFTPDAEMON */ 1081 if (write(i, (char *)&request, sizeof(request)) < 0) { 1082 char tbuf[128]; 1083 (void) sprintf(tbuf, "Can't write to %s\n", INIT_FIFO); 1084 fatalperror(net, tbuf); 1085 } 1086 (void) close(i); 1087 (void) signal(SIGALRM, nologinproc); 1088 for (i = 0; ; i++) { 1089 char tbuf[128]; 1090 alarm(15); 1091 n = read(pty, ptyip, BUFSIZ); 1092 if (i == 3 || n >= 0 || !gotalarm) 1093 break; 1094 gotalarm = 0; 1095 sprintf(tbuf, "telnetd: waiting for /etc/init to start login process on %s\r\n", line); 1096 (void) write(net, tbuf, strlen(tbuf)); 1097 } 1098 if (n < 0 && gotalarm) 1099 fatal(net, "/etc/init didn't start login process"); 1100 pcc += n; 1101 alarm(0); 1102 (void) signal(SIGALRM, SIG_DFL); 1103 1104 return; 1105 #endif /* NEWINIT */ 1106 } 1107 1108 char *envinit[3]; 1109 extern char **environ; 1110 1111 init_env() 1112 { 1113 extern char *getenv(); 1114 char **envp; 1115 1116 envp = envinit; 1117 if (*envp = getenv("TZ")) 1118 *envp++ -= 3; 1119 #ifdef CRAY 1120 else 1121 *envp++ = "TZ=GMT0"; 1122 #endif 1123 *envp = 0; 1124 environ = envinit; 1125 } 1126 1127 #ifdef CRAY 1128 /* 1129 * These are environment variable that we 1130 * don't put on the argument line. 1131 */ 1132 char *invalid[] = { 1133 "USER=", /* Set up by login */ 1134 "HOME=", /* Set up by login */ 1135 "LOGNAME=", /* Set up by login */ 1136 "TMPDIR=", /* Set up by login */ 1137 "SHELL=", /* Set up by login */ 1138 "PATH=", /* Set up by login */ 1139 "MAIL=", /* Set up by login */ 1140 "TZ=", /* Login gets it from the environment */ 1141 "TERM=", /* Login gets it from the environment */ 1142 0 1143 }; 1144 #endif 1145 1146 #ifndef NEWINIT 1147 1148 /* 1149 * start_login(host) 1150 * 1151 * Assuming that we are now running as a child processes, this 1152 * function will turn us into the login process. 1153 */ 1154 1155 start_login(host) 1156 char *host; 1157 { 1158 register char *cp; 1159 register char **argv; 1160 char **addarg(); 1161 #ifdef CRAY 1162 register char **cpp, **cpp2; 1163 #endif /* CRAY */ 1164 1165 /* 1166 * -h : pass on name of host. 1167 * WARNING: -h is accepted by login if and only if 1168 * getuid() == 0. 1169 * -p : don't clobber the environment (so terminal type stays set). 1170 */ 1171 argv = addarg(0, "login"); 1172 argv = addarg(argv, "-h"); 1173 argv = addarg(argv, host); 1174 #if !defined(CRAY) && !defined(NO_LOGIN_P) 1175 argv = addarg(argv, "-p"); 1176 #endif 1177 #ifdef BFTPDAEMON 1178 /* 1179 * Are we working as the bftp daemon? If so, then ask login 1180 * to start bftp instead of shell. 1181 */ 1182 if (bftpd) { 1183 argv = addarg(argv, "-e"); 1184 argv = addarg(argv, BFTPPATH); 1185 } else 1186 #endif 1187 if (getenv("USER")) { 1188 argv = addarg(argv, getenv("USER")); 1189 } 1190 #ifdef CRAY 1191 for (cpp = environ; *cpp; cpp++) { 1192 for (cpp2 = invalid; *cpp2; cpp2++) 1193 if (strncmp(*cpp2, *cpp, strlen(*cpp2)) == 0) 1194 break; 1195 if (*cpp2) 1196 continue; 1197 argv = addarg(argv, *cpp); 1198 } 1199 #endif 1200 1201 execv(_PATH_LOGIN, argv); 1202 1203 syslog(LOG_ERR, "%s: %m\n", _PATH_LOGIN); 1204 fatalperror(net, _PATH_LOGIN); 1205 /*NOTREACHED*/ 1206 } 1207 1208 char ** 1209 addarg(argv, val) 1210 register char **argv; 1211 register char *val; 1212 { 1213 register char **cpp; 1214 char *malloc(); 1215 1216 if (argv == NULL) { 1217 /* 1218 * 10 entries, a leading length, and a null 1219 */ 1220 argv = (char **)malloc(sizeof(*argv) * 12); 1221 if (argv == NULL) 1222 return(NULL); 1223 *argv++ = (char *)10; 1224 *argv = (char *)0; 1225 } 1226 for (cpp = argv; *cpp; cpp++) 1227 ; 1228 if (cpp == &argv[(int)argv[-1]]) { 1229 --argv; 1230 *argv = (char *)((int)(*argv) + 10); 1231 argv = (char **)realloc(argv, (int)(*argv) + 2); 1232 if (argv == NULL) 1233 return(NULL); 1234 argv++; 1235 cpp = &argv[(int)argv[-1] - 10]; 1236 } 1237 *cpp++ = val; 1238 *cpp = 0; 1239 return(argv); 1240 } 1241 #endif NEWINIT 1242 1243 /* 1244 * cleanup() 1245 * 1246 * This is the routine to call when we are all through, to 1247 * clean up anything that needs to be cleaned up. 1248 */ 1249 void 1250 cleanup() 1251 { 1252 1253 #ifndef CRAY 1254 # if (BSD > 43) || defined(convex) 1255 char *p; 1256 1257 p = line + sizeof("/dev/") - 1; 1258 if (logout(p)) 1259 logwtmp(p, "", ""); 1260 (void)chmod(line, 0666); 1261 (void)chown(line, 0, 0); 1262 *p = 'p'; 1263 (void)chmod(line, 0666); 1264 (void)chown(line, 0, 0); 1265 # else 1266 rmut(); 1267 vhangup(); /* XXX */ 1268 # endif 1269 (void) shutdown(net, 2); 1270 #else /* CRAY */ 1271 # ifndef NEWINIT 1272 rmut(line); 1273 (void) shutdown(net, 2); 1274 kill(0, SIGHUP); 1275 # else /* NEWINIT */ 1276 (void) shutdown(net, 2); 1277 # endif /* NEWINT */ 1278 #endif /* CRAY */ 1279 exit(1); 1280 } 1281 1282 #if defined(CRAY) && !defined(NEWINIT) 1283 /* 1284 * _utmp_sig_rcv 1285 * utmp_sig_init 1286 * utmp_sig_wait 1287 * These three functions are used to coordinate the handling of 1288 * the utmp file between the server and the soon-to-be-login shell. 1289 * The server actually creates the utmp structure, the child calls 1290 * utmp_sig_wait(), until the server calls utmp_sig_notify() and 1291 * signals the future-login shell to proceed. 1292 */ 1293 static int caught=0; /* NZ when signal intercepted */ 1294 static void (*func)(); /* address of previous handler */ 1295 1296 void 1297 _utmp_sig_rcv(sig) 1298 int sig; 1299 { 1300 caught = 1; 1301 (void) signal(SIGUSR1, func); 1302 } 1303 1304 utmp_sig_init() 1305 { 1306 /* 1307 * register signal handler for UTMP creation 1308 */ 1309 if ((int)(func = signal(SIGUSR1, _utmp_sig_rcv)) == -1) 1310 fatalperror(net, "telnetd/signal"); 1311 } 1312 1313 utmp_sig_reset() 1314 { 1315 (void) signal(SIGUSR1, func); /* reset handler to default */ 1316 } 1317 1318 utmp_sig_wait() 1319 { 1320 /* 1321 * Wait for parent to write our utmp entry. 1322 */ 1323 sigoff(); 1324 while (caught == 0) { 1325 pause(); /* wait until we get a signal (sigon) */ 1326 sigoff(); /* turn off signals while we check caught */ 1327 } 1328 sigon(); /* turn on signals again */ 1329 } 1330 1331 utmp_sig_notify(pid) 1332 { 1333 kill(pid, SIGUSR1); 1334 } 1335 #endif /* defined(CRAY) && !defined(NEWINIT) */ 1336 1337 /* 1338 * rmut() 1339 * 1340 * This is the function called by cleanup() to 1341 * remove the utmp entry for this person. 1342 */ 1343 1344 #if !defined(CRAY) && BSD <= 43 1345 rmut() 1346 { 1347 register f; 1348 int found = 0; 1349 struct utmp *u, *utmp; 1350 int nutmp; 1351 struct stat statbf; 1352 char *malloc(); 1353 long time(); 1354 off_t lseek(); 1355 1356 f = open(utmpf, O_RDWR); 1357 if (f >= 0) { 1358 (void) fstat(f, &statbf); 1359 utmp = (struct utmp *)malloc((unsigned)statbf.st_size); 1360 if (!utmp) 1361 syslog(LOG_ERR, "utmp malloc failed"); 1362 if (statbf.st_size && utmp) { 1363 nutmp = read(f, (char *)utmp, (int)statbf.st_size); 1364 nutmp /= sizeof(struct utmp); 1365 1366 for (u = utmp ; u < &utmp[nutmp] ; u++) { 1367 if (SCMPN(u->ut_line, line+5) || 1368 u->ut_name[0]==0) 1369 continue; 1370 (void) lseek(f, ((long)u)-((long)utmp), L_SET); 1371 SCPYN(u->ut_name, ""); 1372 SCPYN(u->ut_host, ""); 1373 (void) time(&u->ut_time); 1374 (void) write(f, (char *)u, sizeof(wtmp)); 1375 found++; 1376 } 1377 } 1378 (void) close(f); 1379 } 1380 if (found) { 1381 f = open(wtmpf, O_WRONLY|O_APPEND); 1382 if (f >= 0) { 1383 SCPYN(wtmp.ut_line, line+5); 1384 SCPYN(wtmp.ut_name, ""); 1385 SCPYN(wtmp.ut_host, ""); 1386 (void) time(&wtmp.ut_time); 1387 (void) write(f, (char *)&wtmp, sizeof(wtmp)); 1388 (void) close(f); 1389 } 1390 } 1391 (void) chmod(line, 0666); 1392 (void) chown(line, 0, 0); 1393 line[strlen("/dev/")] = 'p'; 1394 (void) chmod(line, 0666); 1395 (void) chown(line, 0, 0); 1396 } /* end of rmut */ 1397 #endif /* CRAY */ 1398