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