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