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