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