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