1 /* 2 * Copyright (c) 1988, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * @(#)sys_bsd.c 8.4 (Berkeley) 5/30/95 34 * $FreeBSD: src/crypto/telnet/telnet/sys_bsd.c,v 1.2.8.4 2002/04/13 10:59:08 markm Exp $ 35 * $DragonFly: src/crypto/telnet/telnet/sys_bsd.c,v 1.2 2003/06/17 04:24:37 dillon Exp $ 36 37 */ 38 39 #include <sys/cdefs.h> 40 #include <stdlib.h> 41 #include <err.h> 42 43 /* 44 * The following routines try to encapsulate what is system dependent 45 * (at least between 4.x and dos) which is used in telnet.c. 46 */ 47 48 #include <sys/types.h> 49 #include <sys/socket.h> 50 #include <sys/time.h> 51 #include <errno.h> 52 #include <fcntl.h> 53 #include <signal.h> 54 #include <unistd.h> 55 #include <arpa/telnet.h> 56 57 #include "ring.h" 58 #include "fdset.h" 59 #include "defines.h" 60 #include "externs.h" 61 #include "types.h" 62 63 int 64 tout, /* Output file descriptor */ 65 tin, /* Input file descriptor */ 66 net; 67 68 #ifndef USE_TERMIO 69 struct tchars otc = { 0 }, ntc = { 0 }; 70 struct ltchars oltc = { 0 }, nltc = { 0 }; 71 struct sgttyb ottyb = { 0 }, nttyb = { 0 }; 72 int olmode = 0; 73 # define cfgetispeed(ptr) (ptr)->sg_ispeed 74 # define cfgetospeed(ptr) (ptr)->sg_ospeed 75 # define old_tc ottyb 76 77 #else /* USE_TERMIO */ 78 struct termio old_tc = { 0, 0, 0, 0, {}, 0, 0 }; 79 80 # ifndef TCSANOW 81 # ifdef TCSETS 82 # define TCSANOW TCSETS 83 # define TCSADRAIN TCSETSW 84 # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t) 85 # else 86 # ifdef TCSETA 87 # define TCSANOW TCSETA 88 # define TCSADRAIN TCSETAW 89 # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t) 90 # else 91 # define TCSANOW TIOCSETA 92 # define TCSADRAIN TIOCSETAW 93 # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t) 94 # endif 95 # endif 96 # define tcsetattr(f, a, t) ioctl(f, a, (char *)t) 97 # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD) 98 # ifdef CIBAUD 99 # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT) 100 # else 101 # define cfgetispeed(ptr) cfgetospeed(ptr) 102 # endif 103 # endif /* TCSANOW */ 104 # ifdef sysV88 105 # define TIOCFLUSH TC_PX_DRAIN 106 # endif 107 #endif /* USE_TERMIO */ 108 109 static fd_set *ibitsp, *obitsp, *xbitsp; 110 int fdsn; 111 112 #ifdef SIGINT 113 static SIG_FUNC_RET intr(int); 114 #endif /* SIGINT */ 115 #ifdef SIGQUIT 116 static SIG_FUNC_RET intr2(int); 117 #endif /* SIGQUIT */ 118 #ifdef SIGTSTP 119 static SIG_FUNC_RET susp(int); 120 #endif /* SIGTSTP */ 121 #ifdef SIGINFO 122 static SIG_FUNC_RET ayt(int); 123 #endif 124 125 void 126 init_sys(void) 127 { 128 tout = fileno(stdout); 129 tin = fileno(stdin); 130 errno = 0; 131 } 132 133 int 134 TerminalWrite(char *buf, int n) 135 { 136 return write(tout, buf, n); 137 } 138 139 int 140 TerminalRead(char *buf, int n) 141 { 142 return read(tin, buf, n); 143 } 144 145 /* 146 * 147 */ 148 149 int 150 TerminalAutoFlush(void) 151 { 152 #if defined(LNOFLSH) 153 int flush; 154 155 ioctl(0, TIOCLGET, (char *)&flush); 156 return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */ 157 #else /* LNOFLSH */ 158 return 1; 159 #endif /* LNOFLSH */ 160 } 161 162 #ifdef KLUDGELINEMODE 163 extern int kludgelinemode; 164 #endif 165 /* 166 * TerminalSpecialChars() 167 * 168 * Look at an input character to see if it is a special character 169 * and decide what to do. 170 * 171 * Output: 172 * 173 * 0 Don't add this character. 174 * 1 Do add this character 175 */ 176 177 int 178 TerminalSpecialChars(int c) 179 { 180 if (c == termIntChar) { 181 intp(); 182 return 0; 183 } else if (c == termQuitChar) { 184 #ifdef KLUDGELINEMODE 185 if (kludgelinemode) 186 sendbrk(); 187 else 188 #endif 189 sendabort(); 190 return 0; 191 } else if (c == termEofChar) { 192 if (my_want_state_is_will(TELOPT_LINEMODE)) { 193 sendeof(); 194 return 0; 195 } 196 return 1; 197 } else if (c == termSuspChar) { 198 sendsusp(); 199 return(0); 200 } else if (c == termFlushChar) { 201 xmitAO(); /* Transmit Abort Output */ 202 return 0; 203 } else if (!MODE_LOCAL_CHARS(globalmode)) { 204 if (c == termKillChar) { 205 xmitEL(); 206 return 0; 207 } else if (c == termEraseChar) { 208 xmitEC(); /* Transmit Erase Character */ 209 return 0; 210 } 211 } 212 return 1; 213 } 214 215 216 /* 217 * Flush output to the terminal 218 */ 219 220 void 221 TerminalFlushOutput(void) 222 { 223 #ifdef TIOCFLUSH 224 (void) ioctl(fileno(stdout), TIOCFLUSH, NULL); 225 #else 226 (void) ioctl(fileno(stdout), TCFLSH, NULL); 227 #endif 228 } 229 230 void 231 TerminalSaveState(void) 232 { 233 #ifndef USE_TERMIO 234 ioctl(0, TIOCGETP, (char *)&ottyb); 235 ioctl(0, TIOCGETC, (char *)&otc); 236 ioctl(0, TIOCGLTC, (char *)&oltc); 237 ioctl(0, TIOCLGET, (char *)&olmode); 238 239 ntc = otc; 240 nltc = oltc; 241 nttyb = ottyb; 242 243 #else /* USE_TERMIO */ 244 tcgetattr(0, &old_tc); 245 246 new_tc = old_tc; 247 248 #ifndef VDISCARD 249 termFlushChar = CONTROL('O'); 250 #endif 251 #ifndef VWERASE 252 termWerasChar = CONTROL('W'); 253 #endif 254 #ifndef VREPRINT 255 termRprntChar = CONTROL('R'); 256 #endif 257 #ifndef VLNEXT 258 termLiteralNextChar = CONTROL('V'); 259 #endif 260 #ifndef VSTART 261 termStartChar = CONTROL('Q'); 262 #endif 263 #ifndef VSTOP 264 termStopChar = CONTROL('S'); 265 #endif 266 #ifndef VSTATUS 267 termAytChar = CONTROL('T'); 268 #endif 269 #endif /* USE_TERMIO */ 270 } 271 272 cc_t * 273 tcval(int func) 274 { 275 switch(func) { 276 case SLC_IP: return(&termIntChar); 277 case SLC_ABORT: return(&termQuitChar); 278 case SLC_EOF: return(&termEofChar); 279 case SLC_EC: return(&termEraseChar); 280 case SLC_EL: return(&termKillChar); 281 case SLC_XON: return(&termStartChar); 282 case SLC_XOFF: return(&termStopChar); 283 case SLC_FORW1: return(&termForw1Char); 284 #ifdef USE_TERMIO 285 case SLC_FORW2: return(&termForw2Char); 286 # ifdef VDISCARD 287 case SLC_AO: return(&termFlushChar); 288 # endif 289 # ifdef VSUSP 290 case SLC_SUSP: return(&termSuspChar); 291 # endif 292 # ifdef VWERASE 293 case SLC_EW: return(&termWerasChar); 294 # endif 295 # ifdef VREPRINT 296 case SLC_RP: return(&termRprntChar); 297 # endif 298 # ifdef VLNEXT 299 case SLC_LNEXT: return(&termLiteralNextChar); 300 # endif 301 # ifdef VSTATUS 302 case SLC_AYT: return(&termAytChar); 303 # endif 304 #endif 305 306 case SLC_SYNCH: 307 case SLC_BRK: 308 case SLC_EOR: 309 default: 310 return(NULL); 311 } 312 } 313 314 void 315 TerminalDefaultChars(void) 316 { 317 #ifndef USE_TERMIO 318 ntc = otc; 319 nltc = oltc; 320 nttyb.sg_kill = ottyb.sg_kill; 321 nttyb.sg_erase = ottyb.sg_erase; 322 #else /* USE_TERMIO */ 323 memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc)); 324 # ifndef VDISCARD 325 termFlushChar = CONTROL('O'); 326 # endif 327 # ifndef VWERASE 328 termWerasChar = CONTROL('W'); 329 # endif 330 # ifndef VREPRINT 331 termRprntChar = CONTROL('R'); 332 # endif 333 # ifndef VLNEXT 334 termLiteralNextChar = CONTROL('V'); 335 # endif 336 # ifndef VSTART 337 termStartChar = CONTROL('Q'); 338 # endif 339 # ifndef VSTOP 340 termStopChar = CONTROL('S'); 341 # endif 342 # ifndef VSTATUS 343 termAytChar = CONTROL('T'); 344 # endif 345 #endif /* USE_TERMIO */ 346 } 347 348 /* 349 * TerminalNewMode - set up terminal to a specific mode. 350 * MODE_ECHO: do local terminal echo 351 * MODE_FLOW: do local flow control 352 * MODE_TRAPSIG: do local mapping to TELNET IAC sequences 353 * MODE_EDIT: do local line editing 354 * 355 * Command mode: 356 * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG 357 * local echo 358 * local editing 359 * local xon/xoff 360 * local signal mapping 361 * 362 * Linemode: 363 * local/no editing 364 * Both Linemode and Single Character mode: 365 * local/remote echo 366 * local/no xon/xoff 367 * local/no signal mapping 368 */ 369 370 void 371 TerminalNewMode(int f) 372 { 373 static int prevmode = 0; 374 #ifndef USE_TERMIO 375 struct tchars tc; 376 struct ltchars ltc; 377 struct sgttyb sb; 378 int lmode; 379 #else /* USE_TERMIO */ 380 struct termio tmp_tc; 381 #endif /* USE_TERMIO */ 382 int onoff; 383 int old; 384 cc_t esc; 385 386 globalmode = f&~MODE_FORCE; 387 if (prevmode == f) 388 return; 389 390 /* 391 * Write any outstanding data before switching modes 392 * ttyflush() returns 0 only when there is no more data 393 * left to write out, it returns -1 if it couldn't do 394 * anything at all, otherwise it returns 1 + the number 395 * of characters left to write. 396 #ifndef USE_TERMIO 397 * We would really like ask the kernel to wait for the output 398 * to drain, like we can do with the TCSADRAIN, but we don't have 399 * that option. The only ioctl that waits for the output to 400 * drain, TIOCSETP, also flushes the input queue, which is NOT 401 * what we want (TIOCSETP is like TCSADFLUSH). 402 #endif 403 */ 404 old = ttyflush(SYNCHing|flushout); 405 if (old < 0 || old > 1) { 406 #ifdef USE_TERMIO 407 tcgetattr(tin, &tmp_tc); 408 #endif /* USE_TERMIO */ 409 do { 410 /* 411 * Wait for data to drain, then flush again. 412 */ 413 #ifdef USE_TERMIO 414 tcsetattr(tin, TCSADRAIN, &tmp_tc); 415 #endif /* USE_TERMIO */ 416 old = ttyflush(SYNCHing|flushout); 417 } while (old < 0 || old > 1); 418 } 419 420 old = prevmode; 421 prevmode = f&~MODE_FORCE; 422 #ifndef USE_TERMIO 423 sb = nttyb; 424 tc = ntc; 425 ltc = nltc; 426 lmode = olmode; 427 #else 428 tmp_tc = new_tc; 429 #endif 430 431 if (f&MODE_ECHO) { 432 #ifndef USE_TERMIO 433 sb.sg_flags |= ECHO; 434 #else 435 tmp_tc.c_lflag |= ECHO; 436 tmp_tc.c_oflag |= ONLCR; 437 if (crlf) 438 tmp_tc.c_iflag |= ICRNL; 439 #endif 440 } else { 441 #ifndef USE_TERMIO 442 sb.sg_flags &= ~ECHO; 443 #else 444 tmp_tc.c_lflag &= ~ECHO; 445 tmp_tc.c_oflag &= ~ONLCR; 446 #endif 447 } 448 449 if ((f&MODE_FLOW) == 0) { 450 #ifndef USE_TERMIO 451 tc.t_startc = _POSIX_VDISABLE; 452 tc.t_stopc = _POSIX_VDISABLE; 453 #else 454 tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */ 455 } else { 456 if (restartany < 0) { 457 tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */ 458 } else if (restartany > 0) { 459 tmp_tc.c_iflag |= IXOFF|IXON|IXANY; 460 } else { 461 tmp_tc.c_iflag |= IXOFF|IXON; 462 tmp_tc.c_iflag &= ~IXANY; 463 } 464 #endif 465 } 466 467 if ((f&MODE_TRAPSIG) == 0) { 468 #ifndef USE_TERMIO 469 tc.t_intrc = _POSIX_VDISABLE; 470 tc.t_quitc = _POSIX_VDISABLE; 471 tc.t_eofc = _POSIX_VDISABLE; 472 ltc.t_suspc = _POSIX_VDISABLE; 473 ltc.t_dsuspc = _POSIX_VDISABLE; 474 #else 475 tmp_tc.c_lflag &= ~ISIG; 476 #endif 477 localchars = 0; 478 } else { 479 #ifdef USE_TERMIO 480 tmp_tc.c_lflag |= ISIG; 481 #endif 482 localchars = 1; 483 } 484 485 if (f&MODE_EDIT) { 486 #ifndef USE_TERMIO 487 sb.sg_flags &= ~CBREAK; 488 sb.sg_flags |= CRMOD; 489 #else 490 tmp_tc.c_lflag |= ICANON; 491 #endif 492 } else { 493 #ifndef USE_TERMIO 494 sb.sg_flags |= CBREAK; 495 if (f&MODE_ECHO) 496 sb.sg_flags |= CRMOD; 497 else 498 sb.sg_flags &= ~CRMOD; 499 #else 500 tmp_tc.c_lflag &= ~ICANON; 501 tmp_tc.c_iflag &= ~ICRNL; 502 tmp_tc.c_cc[VMIN] = 1; 503 tmp_tc.c_cc[VTIME] = 0; 504 #endif 505 } 506 507 if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) { 508 #ifndef USE_TERMIO 509 ltc.t_lnextc = _POSIX_VDISABLE; 510 #else 511 # ifdef VLNEXT 512 tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE); 513 # endif 514 #endif 515 } 516 517 if (f&MODE_SOFT_TAB) { 518 #ifndef USE_TERMIO 519 sb.sg_flags |= XTABS; 520 #else 521 # ifdef OXTABS 522 tmp_tc.c_oflag |= OXTABS; 523 # endif 524 # ifdef TABDLY 525 tmp_tc.c_oflag &= ~TABDLY; 526 tmp_tc.c_oflag |= TAB3; 527 # endif 528 #endif 529 } else { 530 #ifndef USE_TERMIO 531 sb.sg_flags &= ~XTABS; 532 #else 533 # ifdef OXTABS 534 tmp_tc.c_oflag &= ~OXTABS; 535 # endif 536 # ifdef TABDLY 537 tmp_tc.c_oflag &= ~TABDLY; 538 # endif 539 #endif 540 } 541 542 if (f&MODE_LIT_ECHO) { 543 #ifndef USE_TERMIO 544 lmode &= ~LCTLECH; 545 #else 546 # ifdef ECHOCTL 547 tmp_tc.c_lflag &= ~ECHOCTL; 548 # endif 549 #endif 550 } else { 551 #ifndef USE_TERMIO 552 lmode |= LCTLECH; 553 #else 554 # ifdef ECHOCTL 555 tmp_tc.c_lflag |= ECHOCTL; 556 # endif 557 #endif 558 } 559 560 if (f == -1) { 561 onoff = 0; 562 } else { 563 #ifndef USE_TERMIO 564 if (f & MODE_OUTBIN) 565 lmode |= LLITOUT; 566 else 567 lmode &= ~LLITOUT; 568 569 if (f & MODE_INBIN) 570 lmode |= LPASS8; 571 else 572 lmode &= ~LPASS8; 573 #else 574 if (f & MODE_INBIN) 575 tmp_tc.c_iflag &= ~ISTRIP; 576 else 577 tmp_tc.c_iflag |= ISTRIP; 578 if (f & MODE_OUTBIN) { 579 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 580 tmp_tc.c_cflag |= CS8; 581 tmp_tc.c_oflag &= ~OPOST; 582 } else { 583 tmp_tc.c_cflag &= ~(CSIZE|PARENB); 584 tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB); 585 tmp_tc.c_oflag |= OPOST; 586 } 587 #endif 588 onoff = 1; 589 } 590 591 if (f != -1) { 592 #ifdef SIGINT 593 (void) signal(SIGINT, intr); 594 #endif 595 #ifdef SIGQUIT 596 (void) signal(SIGQUIT, intr2); 597 #endif 598 #ifdef SIGTSTP 599 (void) signal(SIGTSTP, susp); 600 #endif /* SIGTSTP */ 601 #ifdef SIGINFO 602 (void) signal(SIGINFO, ayt); 603 #endif 604 #if defined(USE_TERMIO) && defined(NOKERNINFO) 605 tmp_tc.c_lflag |= NOKERNINFO; 606 #endif 607 /* 608 * We don't want to process ^Y here. It's just another 609 * character that we'll pass on to the back end. It has 610 * to process it because it will be processed when the 611 * user attempts to read it, not when we send it. 612 */ 613 #ifndef USE_TERMIO 614 ltc.t_dsuspc = _POSIX_VDISABLE; 615 #else 616 # ifdef VDSUSP 617 tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE); 618 # endif 619 #endif 620 #ifdef USE_TERMIO 621 /* 622 * If the VEOL character is already set, then use VEOL2, 623 * otherwise use VEOL. 624 */ 625 esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape; 626 if ((tmp_tc.c_cc[VEOL] != esc) 627 # ifdef VEOL2 628 && (tmp_tc.c_cc[VEOL2] != esc) 629 # endif 630 ) { 631 if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE)) 632 tmp_tc.c_cc[VEOL] = esc; 633 # ifdef VEOL2 634 else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE)) 635 tmp_tc.c_cc[VEOL2] = esc; 636 # endif 637 } 638 #else 639 if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE)) 640 tc.t_brkc = esc; 641 #endif 642 } else { 643 #ifdef SIGINFO 644 (void) signal(SIGINFO, (void (*)(int))ayt_status); 645 #endif 646 #ifdef SIGINT 647 (void) signal(SIGINT, SIG_DFL); 648 #endif 649 #ifdef SIGQUIT 650 (void) signal(SIGQUIT, SIG_DFL); 651 #endif 652 #ifdef SIGTSTP 653 (void) signal(SIGTSTP, SIG_DFL); 654 # ifndef SOLARIS 655 (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1))); 656 # else 657 (void) sigrelse(SIGTSTP); 658 # endif 659 #endif /* SIGTSTP */ 660 #ifndef USE_TERMIO 661 ltc = oltc; 662 tc = otc; 663 sb = ottyb; 664 lmode = olmode; 665 #else 666 tmp_tc = old_tc; 667 #endif 668 } 669 #ifndef USE_TERMIO 670 ioctl(tin, TIOCLSET, (char *)&lmode); 671 ioctl(tin, TIOCSLTC, (char *)<c); 672 ioctl(tin, TIOCSETC, (char *)&tc); 673 ioctl(tin, TIOCSETN, (char *)&sb); 674 #else 675 if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0) 676 tcsetattr(tin, TCSANOW, &tmp_tc); 677 #endif 678 679 ioctl(tin, FIONBIO, (char *)&onoff); 680 ioctl(tout, FIONBIO, (char *)&onoff); 681 682 } 683 684 /* 685 * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD). 686 */ 687 #if B4800 != 4800 688 #define DECODE_BAUD 689 #endif 690 691 #ifdef DECODE_BAUD 692 #ifndef B7200 693 #define B7200 B4800 694 #endif 695 696 #ifndef B14400 697 #define B14400 B9600 698 #endif 699 700 #ifndef B19200 701 # define B19200 B14400 702 #endif 703 704 #ifndef B28800 705 #define B28800 B19200 706 #endif 707 708 #ifndef B38400 709 # define B38400 B28800 710 #endif 711 712 #ifndef B57600 713 #define B57600 B38400 714 #endif 715 716 #ifndef B76800 717 #define B76800 B57600 718 #endif 719 720 #ifndef B115200 721 #define B115200 B76800 722 #endif 723 724 #ifndef B230400 725 #define B230400 B115200 726 #endif 727 728 729 /* 730 * This code assumes that the values B0, B50, B75... 731 * are in ascending order. They do not have to be 732 * contiguous. 733 */ 734 struct termspeeds { 735 long speed; 736 long value; 737 } termspeeds[] = { 738 { 0, B0 }, { 50, B50 }, { 75, B75 }, 739 { 110, B110 }, { 134, B134 }, { 150, B150 }, 740 { 200, B200 }, { 300, B300 }, { 600, B600 }, 741 { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, 742 { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 }, 743 { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 }, 744 { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 }, 745 { 230400, B230400 }, { -1, B230400 } 746 }; 747 #endif /* DECODE_BAUD */ 748 749 void 750 TerminalSpeeds(long *ispeed, long *ospeed) 751 { 752 #ifdef DECODE_BAUD 753 struct termspeeds *tp; 754 #endif /* DECODE_BAUD */ 755 long in, out; 756 757 out = cfgetospeed(&old_tc); 758 in = cfgetispeed(&old_tc); 759 if (in == 0) 760 in = out; 761 762 #ifdef DECODE_BAUD 763 tp = termspeeds; 764 while ((tp->speed != -1) && (tp->value < in)) 765 tp++; 766 *ispeed = tp->speed; 767 768 tp = termspeeds; 769 while ((tp->speed != -1) && (tp->value < out)) 770 tp++; 771 *ospeed = tp->speed; 772 #else /* DECODE_BAUD */ 773 *ispeed = in; 774 *ospeed = out; 775 #endif /* DECODE_BAUD */ 776 } 777 778 int 779 TerminalWindowSize(long *rows, long *cols) 780 { 781 #ifdef TIOCGWINSZ 782 struct winsize ws; 783 784 if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) { 785 *rows = ws.ws_row; 786 *cols = ws.ws_col; 787 return 1; 788 } 789 #endif /* TIOCGWINSZ */ 790 return 0; 791 } 792 793 int 794 NetClose(int fd) 795 { 796 return close(fd); 797 } 798 799 static void 800 NetNonblockingIO(int fd, int onoff) 801 { 802 ioctl(fd, FIONBIO, (char *)&onoff); 803 } 804 805 806 /* 807 * Various signal handling routines. 808 */ 809 810 /* ARGSUSED */ 811 static SIG_FUNC_RET 812 deadpeer(int sig __unused) 813 { 814 setcommandmode(); 815 longjmp(peerdied, -1); 816 } 817 818 /* ARGSUSED */ 819 SIG_FUNC_RET 820 intr(int sig __unused) 821 { 822 if (localchars) { 823 intp(); 824 return; 825 } 826 setcommandmode(); 827 longjmp(toplevel, -1); 828 } 829 830 /* ARGSUSED */ 831 SIG_FUNC_RET 832 intr2(int sig __unused) 833 { 834 if (localchars) { 835 #ifdef KLUDGELINEMODE 836 if (kludgelinemode) 837 sendbrk(); 838 else 839 #endif 840 sendabort(); 841 return; 842 } 843 } 844 845 #ifdef SIGTSTP 846 /* ARGSUSED */ 847 SIG_FUNC_RET 848 susp(int sig __unused) 849 { 850 if ((rlogin != _POSIX_VDISABLE) && rlogin_susp()) 851 return; 852 if (localchars) 853 sendsusp(); 854 } 855 #endif 856 857 #ifdef SIGWINCH 858 /* ARGSUSED */ 859 static SIG_FUNC_RET 860 sendwin(int sig __unused) 861 { 862 if (connected) { 863 sendnaws(); 864 } 865 } 866 #endif 867 868 #ifdef SIGINFO 869 /* ARGSUSED */ 870 SIG_FUNC_RET 871 ayt(int sig __unused) 872 { 873 if (connected) 874 sendayt(); 875 else 876 ayt_status(); 877 } 878 #endif 879 880 881 void 882 sys_telnet_init(void) 883 { 884 (void) signal(SIGINT, intr); 885 (void) signal(SIGQUIT, intr2); 886 (void) signal(SIGPIPE, deadpeer); 887 #ifdef SIGWINCH 888 (void) signal(SIGWINCH, sendwin); 889 #endif 890 #ifdef SIGTSTP 891 (void) signal(SIGTSTP, susp); 892 #endif 893 #ifdef SIGINFO 894 (void) signal(SIGINFO, ayt); 895 #endif 896 897 setconnmode(0); 898 899 NetNonblockingIO(net, 1); 900 901 #if defined(SO_OOBINLINE) 902 if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) { 903 perror("SetSockOpt"); 904 } 905 #endif /* defined(SO_OOBINLINE) */ 906 } 907 908 /* 909 * Process rings - 910 * 911 * This routine tries to fill up/empty our various rings. 912 * 913 * The parameter specifies whether this is a poll operation, 914 * or a block-until-something-happens operation. 915 * 916 * The return value is 1 if something happened, 0 if not. 917 */ 918 919 int 920 process_rings(int netin, int netout, int netex, int ttyin, int ttyout, int poll) 921 { 922 int c; 923 int returnValue = 0; 924 static struct timeval TimeValue = { 0, 0 }; 925 int maxfd = -1; 926 int tmp; 927 928 if ((netout || netin || netex) && net > maxfd) 929 maxfd = net; 930 931 if (ttyout && tout > maxfd) 932 maxfd = tout; 933 if (ttyin && tin > maxfd) 934 maxfd = tin; 935 tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask); 936 if (tmp > fdsn) { 937 if (ibitsp) 938 free(ibitsp); 939 if (obitsp) 940 free(obitsp); 941 if (xbitsp) 942 free(xbitsp); 943 944 fdsn = tmp; 945 if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL) 946 err(1, "malloc"); 947 if ((obitsp = (fd_set *)malloc(fdsn)) == NULL) 948 err(1, "malloc"); 949 if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL) 950 err(1, "malloc"); 951 memset(ibitsp, 0, fdsn); 952 memset(obitsp, 0, fdsn); 953 memset(xbitsp, 0, fdsn); 954 } 955 956 if (netout) 957 FD_SET(net, obitsp); 958 if (ttyout) 959 FD_SET(tout, obitsp); 960 if (ttyin) 961 FD_SET(tin, ibitsp); 962 if (netin) 963 FD_SET(net, ibitsp); 964 if (netex) 965 FD_SET(net, xbitsp); 966 if ((c = select(maxfd + 1, ibitsp, obitsp, xbitsp, 967 (poll == 0)? NULL : &TimeValue)) < 0) { 968 if (c == -1) { 969 /* 970 * we can get EINTR if we are in line mode, 971 * and the user does an escape (TSTP), or 972 * some other signal generator. 973 */ 974 if (errno == EINTR) { 975 return 0; 976 } 977 /* I don't like this, does it ever happen? */ 978 printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno)); 979 sleep(5); 980 } 981 return 0; 982 } 983 984 /* 985 * Any urgent data? 986 */ 987 if (FD_ISSET(net, xbitsp)) { 988 FD_CLR(net, xbitsp); 989 SYNCHing = 1; 990 (void) ttyflush(1); /* flush already enqueued data */ 991 } 992 993 /* 994 * Something to read from the network... 995 */ 996 if (FD_ISSET(net, ibitsp)) { 997 int canread; 998 999 FD_CLR(net, ibitsp); 1000 canread = ring_empty_consecutive(&netiring); 1001 #if !defined(SO_OOBINLINE) 1002 /* 1003 * In 4.2 (and some early 4.3) systems, the 1004 * OOB indication and data handling in the kernel 1005 * is such that if two separate TCP Urgent requests 1006 * come in, one byte of TCP data will be overlaid. 1007 * This is fatal for Telnet, but we try to live 1008 * with it. 1009 * 1010 * In addition, in 4.2 (and...), a special protocol 1011 * is needed to pick up the TCP Urgent data in 1012 * the correct sequence. 1013 * 1014 * What we do is: if we think we are in urgent 1015 * mode, we look to see if we are "at the mark". 1016 * If we are, we do an OOB receive. If we run 1017 * this twice, we will do the OOB receive twice, 1018 * but the second will fail, since the second 1019 * time we were "at the mark", but there wasn't 1020 * any data there (the kernel doesn't reset 1021 * "at the mark" until we do a normal read). 1022 * Once we've read the OOB data, we go ahead 1023 * and do normal reads. 1024 * 1025 * There is also another problem, which is that 1026 * since the OOB byte we read doesn't put us 1027 * out of OOB state, and since that byte is most 1028 * likely the TELNET DM (data mark), we would 1029 * stay in the TELNET SYNCH (SYNCHing) state. 1030 * So, clocks to the rescue. If we've "just" 1031 * received a DM, then we test for the 1032 * presence of OOB data when the receive OOB 1033 * fails (and AFTER we did the normal mode read 1034 * to clear "at the mark"). 1035 */ 1036 if (SYNCHing) { 1037 int atmark; 1038 static int bogus_oob = 0, first = 1; 1039 1040 ioctl(net, SIOCATMARK, (char *)&atmark); 1041 if (atmark) { 1042 c = recv(net, netiring.supply, canread, MSG_OOB); 1043 if ((c == -1) && (errno == EINVAL)) { 1044 c = recv(net, netiring.supply, canread, 0); 1045 if (clocks.didnetreceive < clocks.gotDM) { 1046 SYNCHing = stilloob(net); 1047 } 1048 } else if (first && c > 0) { 1049 /* 1050 * Bogosity check. Systems based on 4.2BSD 1051 * do not return an error if you do a second 1052 * recv(MSG_OOB). So, we do one. If it 1053 * succeeds and returns exactly the same 1054 * data, then assume that we are running 1055 * on a broken system and set the bogus_oob 1056 * flag. (If the data was different, then 1057 * we probably got some valid new data, so 1058 * increment the count...) 1059 */ 1060 int i; 1061 i = recv(net, netiring.supply + c, canread - c, MSG_OOB); 1062 if (i == c && 1063 memcmp(netiring.supply, netiring.supply + c, i) == 0) { 1064 bogus_oob = 1; 1065 first = 0; 1066 } else if (i < 0) { 1067 bogus_oob = 0; 1068 first = 0; 1069 } else 1070 c += i; 1071 } 1072 if (bogus_oob && c > 0) { 1073 int i; 1074 /* 1075 * Bogosity. We have to do the read 1076 * to clear the atmark to get out of 1077 * an infinate loop. 1078 */ 1079 i = read(net, netiring.supply + c, canread - c); 1080 if (i > 0) 1081 c += i; 1082 } 1083 } else { 1084 c = recv(net, netiring.supply, canread, 0); 1085 } 1086 } else { 1087 c = recv(net, netiring.supply, canread, 0); 1088 } 1089 settimer(didnetreceive); 1090 #else /* !defined(SO_OOBINLINE) */ 1091 c = recv(net, (char *)netiring.supply, canread, 0); 1092 #endif /* !defined(SO_OOBINLINE) */ 1093 if (c < 0 && errno == EWOULDBLOCK) { 1094 c = 0; 1095 } else if (c <= 0) { 1096 return -1; 1097 } 1098 if (netdata) { 1099 Dump('<', netiring.supply, c); 1100 } 1101 if (c) 1102 ring_supplied(&netiring, c); 1103 returnValue = 1; 1104 } 1105 1106 /* 1107 * Something to read from the tty... 1108 */ 1109 if (FD_ISSET(tin, ibitsp)) { 1110 FD_CLR(tin, ibitsp); 1111 c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring)); 1112 if (c < 0 && errno == EIO) 1113 c = 0; 1114 if (c < 0 && errno == EWOULDBLOCK) { 1115 c = 0; 1116 } else { 1117 /* EOF detection for line mode!!!! */ 1118 if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) { 1119 /* must be an EOF... */ 1120 *ttyiring.supply = termEofChar; 1121 c = 1; 1122 } 1123 if (c <= 0) { 1124 return -1; 1125 } 1126 if (termdata) { 1127 Dump('<', ttyiring.supply, c); 1128 } 1129 ring_supplied(&ttyiring, c); 1130 } 1131 returnValue = 1; /* did something useful */ 1132 } 1133 1134 if (FD_ISSET(net, obitsp)) { 1135 FD_CLR(net, obitsp); 1136 returnValue |= netflush(); 1137 } 1138 if (FD_ISSET(tout, obitsp)) { 1139 FD_CLR(tout, obitsp); 1140 returnValue |= (ttyflush(SYNCHing|flushout) > 0); 1141 } 1142 1143 return returnValue; 1144 } 1145