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