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