1 /* 2 * Copyright (c) 1989, 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 34 #include "telnetd.h" 35 36 RCSID("$Id: state.c,v 1.14 2000/10/02 05:06:02 assar Exp $"); 37 38 unsigned char doopt[] = { IAC, DO, '%', 'c', 0 }; 39 unsigned char dont[] = { IAC, DONT, '%', 'c', 0 }; 40 unsigned char will[] = { IAC, WILL, '%', 'c', 0 }; 41 unsigned char wont[] = { IAC, WONT, '%', 'c', 0 }; 42 int not42 = 1; 43 44 /* 45 * Buffer for sub-options, and macros 46 * for suboptions buffer manipulations 47 */ 48 unsigned char subbuffer[2048], *subpointer= subbuffer, *subend= subbuffer; 49 50 #define SB_CLEAR() subpointer = subbuffer 51 #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 52 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 53 *subpointer++ = (c); \ 54 } 55 #define SB_GET() ((*subpointer++)&0xff) 56 #define SB_EOF() (subpointer >= subend) 57 #define SB_LEN() (subend - subpointer) 58 59 #ifdef ENV_HACK 60 unsigned char *subsave; 61 #define SB_SAVE() subsave = subpointer; 62 #define SB_RESTORE() subpointer = subsave; 63 #endif 64 65 66 /* 67 * State for recv fsm 68 */ 69 #define TS_DATA 0 /* base state */ 70 #define TS_IAC 1 /* look for double IAC's */ 71 #define TS_CR 2 /* CR-LF ->'s CR */ 72 #define TS_SB 3 /* throw away begin's... */ 73 #define TS_SE 4 /* ...end's (suboption negotiation) */ 74 #define TS_WILL 5 /* will option negotiation */ 75 #define TS_WONT 6 /* wont -''- */ 76 #define TS_DO 7 /* do -''- */ 77 #define TS_DONT 8 /* dont -''- */ 78 79 void 80 telrcv(void) 81 { 82 int c; 83 static int state = TS_DATA; 84 85 while (ncc > 0) { 86 if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) 87 break; 88 c = *netip++ & 0377, ncc--; 89 #ifdef ENCRYPTION 90 if (decrypt_input) 91 c = (*decrypt_input)(c); 92 #endif 93 switch (state) { 94 95 case TS_CR: 96 state = TS_DATA; 97 /* Strip off \n or \0 after a \r */ 98 if ((c == 0) || (c == '\n')) { 99 break; 100 } 101 /* FALL THROUGH */ 102 103 case TS_DATA: 104 if (c == IAC) { 105 state = TS_IAC; 106 break; 107 } 108 /* 109 * We now map \r\n ==> \r for pragmatic reasons. 110 * Many client implementations send \r\n when 111 * the user hits the CarriageReturn key. 112 * 113 * We USED to map \r\n ==> \n, since \r\n says 114 * that we want to be in column 1 of the next 115 * printable line, and \n is the standard 116 * unix way of saying that (\r is only good 117 * if CRMOD is set, which it normally is). 118 */ 119 if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) { 120 int nc = *netip; 121 #ifdef ENCRYPTION 122 if (decrypt_input) 123 nc = (*decrypt_input)(nc & 0xff); 124 #endif 125 { 126 #ifdef ENCRYPTION 127 if (decrypt_input) 128 (void)(*decrypt_input)(-1); 129 #endif 130 state = TS_CR; 131 } 132 } 133 *pfrontp++ = c; 134 break; 135 136 case TS_IAC: 137 gotiac: switch (c) { 138 139 /* 140 * Send the process on the pty side an 141 * interrupt. Do this with a NULL or 142 * interrupt char; depending on the tty mode. 143 */ 144 case IP: 145 DIAG(TD_OPTIONS, 146 printoption("td: recv IAC", c)); 147 interrupt(); 148 break; 149 150 case BREAK: 151 DIAG(TD_OPTIONS, 152 printoption("td: recv IAC", c)); 153 sendbrk(); 154 break; 155 156 /* 157 * Are You There? 158 */ 159 case AYT: 160 DIAG(TD_OPTIONS, 161 printoption("td: recv IAC", c)); 162 recv_ayt(); 163 break; 164 165 /* 166 * Abort Output 167 */ 168 case AO: 169 { 170 DIAG(TD_OPTIONS, 171 printoption("td: recv IAC", c)); 172 ptyflush(); /* half-hearted */ 173 init_termbuf(); 174 175 if (slctab[SLC_AO].sptr && 176 *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) { 177 *pfrontp++ = 178 (unsigned char)*slctab[SLC_AO].sptr; 179 } 180 181 netclear(); /* clear buffer back */ 182 output_data ("%c%c", IAC, DM); 183 neturg = nfrontp-1; /* off by one XXX */ 184 DIAG(TD_OPTIONS, 185 printoption("td: send IAC", DM)); 186 break; 187 } 188 189 /* 190 * Erase Character and 191 * Erase Line 192 */ 193 case EC: 194 case EL: 195 { 196 cc_t ch; 197 198 DIAG(TD_OPTIONS, 199 printoption("td: recv IAC", c)); 200 ptyflush(); /* half-hearted */ 201 init_termbuf(); 202 if (c == EC) 203 ch = *slctab[SLC_EC].sptr; 204 else 205 ch = *slctab[SLC_EL].sptr; 206 if (ch != (cc_t)(_POSIX_VDISABLE)) 207 *pfrontp++ = (unsigned char)ch; 208 break; 209 } 210 211 /* 212 * Check for urgent data... 213 */ 214 case DM: 215 DIAG(TD_OPTIONS, 216 printoption("td: recv IAC", c)); 217 SYNCHing = stilloob(net); 218 settimer(gotDM); 219 break; 220 221 222 /* 223 * Begin option subnegotiation... 224 */ 225 case SB: 226 state = TS_SB; 227 SB_CLEAR(); 228 continue; 229 230 case WILL: 231 state = TS_WILL; 232 continue; 233 234 case WONT: 235 state = TS_WONT; 236 continue; 237 238 case DO: 239 state = TS_DO; 240 continue; 241 242 case DONT: 243 state = TS_DONT; 244 continue; 245 case EOR: 246 if (his_state_is_will(TELOPT_EOR)) 247 doeof(); 248 break; 249 250 /* 251 * Handle RFC 10xx Telnet linemode option additions 252 * to command stream (EOF, SUSP, ABORT). 253 */ 254 case xEOF: 255 doeof(); 256 break; 257 258 case SUSP: 259 sendsusp(); 260 break; 261 262 case ABORT: 263 sendbrk(); 264 break; 265 266 case IAC: 267 *pfrontp++ = c; 268 break; 269 } 270 state = TS_DATA; 271 break; 272 273 case TS_SB: 274 if (c == IAC) { 275 state = TS_SE; 276 } else { 277 SB_ACCUM(c); 278 } 279 break; 280 281 case TS_SE: 282 if (c != SE) { 283 if (c != IAC) { 284 /* 285 * bad form of suboption negotiation. 286 * handle it in such a way as to avoid 287 * damage to local state. Parse 288 * suboption buffer found so far, 289 * then treat remaining stream as 290 * another command sequence. 291 */ 292 293 /* for DIAGNOSTICS */ 294 SB_ACCUM(IAC); 295 SB_ACCUM(c); 296 subpointer -= 2; 297 298 SB_TERM(); 299 suboption(); 300 state = TS_IAC; 301 goto gotiac; 302 } 303 SB_ACCUM(c); 304 state = TS_SB; 305 } else { 306 /* for DIAGNOSTICS */ 307 SB_ACCUM(IAC); 308 SB_ACCUM(SE); 309 subpointer -= 2; 310 311 SB_TERM(); 312 suboption(); /* handle sub-option */ 313 state = TS_DATA; 314 } 315 break; 316 317 case TS_WILL: 318 willoption(c); 319 state = TS_DATA; 320 continue; 321 322 case TS_WONT: 323 wontoption(c); 324 if (c==TELOPT_ENCRYPT && his_do_dont_is_changing(TELOPT_ENCRYPT) ) 325 dontoption(c); 326 state = TS_DATA; 327 continue; 328 329 case TS_DO: 330 dooption(c); 331 state = TS_DATA; 332 continue; 333 334 case TS_DONT: 335 dontoption(c); 336 state = TS_DATA; 337 continue; 338 339 default: 340 syslog(LOG_ERR, "telnetd: panic state=%d\n", state); 341 printf("telnetd: panic state=%d\n", state); 342 exit(1); 343 } 344 } 345 } /* end of telrcv */ 346 347 /* 348 * The will/wont/do/dont state machines are based on Dave Borman's 349 * Telnet option processing state machine. 350 * 351 * These correspond to the following states: 352 * my_state = the last negotiated state 353 * want_state = what I want the state to go to 354 * want_resp = how many requests I have sent 355 * All state defaults are negative, and resp defaults to 0. 356 * 357 * When initiating a request to change state to new_state: 358 * 359 * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { 360 * do nothing; 361 * } else { 362 * want_state = new_state; 363 * send new_state; 364 * want_resp++; 365 * } 366 * 367 * When receiving new_state: 368 * 369 * if (want_resp) { 370 * want_resp--; 371 * if (want_resp && (new_state == my_state)) 372 * want_resp--; 373 * } 374 * if ((want_resp == 0) && (new_state != want_state)) { 375 * if (ok_to_switch_to new_state) 376 * want_state = new_state; 377 * else 378 * want_resp++; 379 * send want_state; 380 * } 381 * my_state = new_state; 382 * 383 * Note that new_state is implied in these functions by the function itself. 384 * will and do imply positive new_state, wont and dont imply negative. 385 * 386 * Finally, there is one catch. If we send a negative response to a 387 * positive request, my_state will be the positive while want_state will 388 * remain negative. my_state will revert to negative when the negative 389 * acknowlegment arrives from the peer. Thus, my_state generally tells 390 * us not only the last negotiated state, but also tells us what the peer 391 * wants to be doing as well. It is important to understand this difference 392 * as we may wish to be processing data streams based on our desired state 393 * (want_state) or based on what the peer thinks the state is (my_state). 394 * 395 * This all works fine because if the peer sends a positive request, the data 396 * that we receive prior to negative acknowlegment will probably be affected 397 * by the positive state, and we can process it as such (if we can; if we 398 * can't then it really doesn't matter). If it is that important, then the 399 * peer probably should be buffering until this option state negotiation 400 * is complete. 401 * 402 */ 403 void 404 send_do(int option, int init) 405 { 406 if (init) { 407 if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || 408 his_want_state_is_will(option)) 409 return; 410 /* 411 * Special case for TELOPT_TM: We send a DO, but pretend 412 * that we sent a DONT, so that we can send more DOs if 413 * we want to. 414 */ 415 if (option == TELOPT_TM) 416 set_his_want_state_wont(option); 417 else 418 set_his_want_state_will(option); 419 do_dont_resp[option]++; 420 } 421 output_data((const char *)doopt, option); 422 423 DIAG(TD_OPTIONS, printoption("td: send do", option)); 424 } 425 426 #ifdef AUTHENTICATION 427 extern void auth_request(void); 428 #endif 429 #ifdef ENCRYPTION 430 extern void encrypt_send_support(); 431 #endif 432 433 void 434 willoption(int option) 435 { 436 int changeok = 0; 437 void (*func)() = 0; 438 439 /* 440 * process input from peer. 441 */ 442 443 DIAG(TD_OPTIONS, printoption("td: recv will", option)); 444 445 if (do_dont_resp[option]) { 446 do_dont_resp[option]--; 447 if (do_dont_resp[option] && his_state_is_will(option)) 448 do_dont_resp[option]--; 449 } 450 if (do_dont_resp[option] == 0) { 451 if (his_want_state_is_wont(option)) { 452 switch (option) { 453 454 case TELOPT_BINARY: 455 init_termbuf(); 456 tty_binaryin(1); 457 set_termbuf(); 458 changeok++; 459 break; 460 461 case TELOPT_ECHO: 462 /* 463 * See comments below for more info. 464 */ 465 not42 = 0; /* looks like a 4.2 system */ 466 break; 467 468 case TELOPT_TM: 469 /* 470 * We never respond to a WILL TM, and 471 * we leave the state WONT. 472 */ 473 return; 474 475 case TELOPT_LFLOW: 476 /* 477 * If we are going to support flow control 478 * option, then don't worry peer that we can't 479 * change the flow control characters. 480 */ 481 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 482 slctab[SLC_XON].defset.flag |= SLC_DEFAULT; 483 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 484 slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; 485 case TELOPT_TTYPE: 486 case TELOPT_SGA: 487 case TELOPT_NAWS: 488 case TELOPT_TSPEED: 489 case TELOPT_XDISPLOC: 490 case TELOPT_NEW_ENVIRON: 491 case TELOPT_OLD_ENVIRON: 492 changeok++; 493 break; 494 495 496 #ifdef AUTHENTICATION 497 case TELOPT_AUTHENTICATION: 498 func = auth_request; 499 changeok++; 500 break; 501 #endif 502 503 #ifdef ENCRYPTION 504 case TELOPT_ENCRYPT: 505 func = encrypt_send_support; 506 changeok++; 507 break; 508 #endif 509 510 default: 511 break; 512 } 513 if (changeok) { 514 set_his_want_state_will(option); 515 send_do(option, 0); 516 } else { 517 do_dont_resp[option]++; 518 send_dont(option, 0); 519 } 520 } else { 521 /* 522 * Option processing that should happen when 523 * we receive conformation of a change in 524 * state that we had requested. 525 */ 526 switch (option) { 527 case TELOPT_ECHO: 528 not42 = 0; /* looks like a 4.2 system */ 529 /* 530 * Egads, he responded "WILL ECHO". Turn 531 * it off right now! 532 */ 533 send_dont(option, 1); 534 /* 535 * "WILL ECHO". Kludge upon kludge! 536 * A 4.2 client is now echoing user input at 537 * the tty. This is probably undesireable and 538 * it should be stopped. The client will 539 * respond WONT TM to the DO TM that we send to 540 * check for kludge linemode. When the WONT TM 541 * arrives, linemode will be turned off and a 542 * change propogated to the pty. This change 543 * will cause us to process the new pty state 544 * in localstat(), which will notice that 545 * linemode is off and send a WILL ECHO 546 * so that we are properly in character mode and 547 * all is well. 548 */ 549 break; 550 551 #ifdef AUTHENTICATION 552 case TELOPT_AUTHENTICATION: 553 func = auth_request; 554 break; 555 #endif 556 557 #ifdef ENCRYPTION 558 case TELOPT_ENCRYPT: 559 func = encrypt_send_support; 560 break; 561 #endif 562 563 case TELOPT_LFLOW: 564 func = flowstat; 565 break; 566 } 567 } 568 } 569 set_his_state_will(option); 570 if (func) 571 (*func)(); 572 } /* end of willoption */ 573 574 void 575 send_dont(int option, int init) 576 { 577 if (init) { 578 if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || 579 his_want_state_is_wont(option)) 580 return; 581 set_his_want_state_wont(option); 582 do_dont_resp[option]++; 583 } 584 output_data((const char *)dont, option); 585 586 DIAG(TD_OPTIONS, printoption("td: send dont", option)); 587 } 588 589 void 590 wontoption(int option) 591 { 592 /* 593 * Process client input. 594 */ 595 596 DIAG(TD_OPTIONS, printoption("td: recv wont", option)); 597 598 if (do_dont_resp[option]) { 599 do_dont_resp[option]--; 600 if (do_dont_resp[option] && his_state_is_wont(option)) 601 do_dont_resp[option]--; 602 } 603 if (do_dont_resp[option] == 0) { 604 if (his_want_state_is_will(option)) { 605 /* it is always ok to change to negative state */ 606 switch (option) { 607 case TELOPT_ECHO: 608 not42 = 1; /* doesn't seem to be a 4.2 system */ 609 break; 610 611 case TELOPT_BINARY: 612 init_termbuf(); 613 tty_binaryin(0); 614 set_termbuf(); 615 break; 616 617 case TELOPT_TM: 618 /* 619 * If we get a WONT TM, and had sent a DO TM, 620 * don't respond with a DONT TM, just leave it 621 * as is. Short circut the state machine to 622 * achive this. 623 */ 624 set_his_want_state_wont(TELOPT_TM); 625 return; 626 627 case TELOPT_LFLOW: 628 /* 629 * If we are not going to support flow control 630 * option, then let peer know that we can't 631 * change the flow control characters. 632 */ 633 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 634 slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; 635 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 636 slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; 637 break; 638 639 #ifdef AUTHENTICATION 640 case TELOPT_AUTHENTICATION: 641 auth_finished(0, AUTH_REJECT); 642 break; 643 #endif 644 645 /* 646 * For options that we might spin waiting for 647 * sub-negotiation, if the client turns off the 648 * option rather than responding to the request, 649 * we have to treat it here as if we got a response 650 * to the sub-negotiation, (by updating the timers) 651 * so that we'll break out of the loop. 652 */ 653 case TELOPT_TTYPE: 654 settimer(ttypesubopt); 655 break; 656 657 case TELOPT_TSPEED: 658 settimer(tspeedsubopt); 659 break; 660 661 case TELOPT_XDISPLOC: 662 settimer(xdisplocsubopt); 663 break; 664 665 case TELOPT_OLD_ENVIRON: 666 settimer(oenvironsubopt); 667 break; 668 669 case TELOPT_NEW_ENVIRON: 670 settimer(environsubopt); 671 break; 672 673 default: 674 break; 675 } 676 set_his_want_state_wont(option); 677 if (his_state_is_will(option)) 678 send_dont(option, 0); 679 } else { 680 switch (option) { 681 case TELOPT_TM: 682 break; 683 684 #ifdef AUTHENTICATION 685 case TELOPT_AUTHENTICATION: 686 auth_finished(0, AUTH_REJECT); 687 break; 688 #endif 689 default: 690 break; 691 } 692 } 693 } 694 set_his_state_wont(option); 695 696 } /* end of wontoption */ 697 698 void 699 send_will(int option, int init) 700 { 701 if (init) { 702 if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| 703 my_want_state_is_will(option)) 704 return; 705 set_my_want_state_will(option); 706 will_wont_resp[option]++; 707 } 708 output_data ((const char *)will, option); 709 710 DIAG(TD_OPTIONS, printoption("td: send will", option)); 711 } 712 713 /* 714 * When we get a DONT SGA, we will try once to turn it 715 * back on. If the other side responds DONT SGA, we 716 * leave it at that. This is so that when we talk to 717 * clients that understand KLUDGELINEMODE but not LINEMODE, 718 * we'll keep them in char-at-a-time mode. 719 */ 720 int turn_on_sga = 0; 721 722 void 723 dooption(int option) 724 { 725 int changeok = 0; 726 727 /* 728 * Process client input. 729 */ 730 731 DIAG(TD_OPTIONS, printoption("td: recv do", option)); 732 733 if (will_wont_resp[option]) { 734 will_wont_resp[option]--; 735 if (will_wont_resp[option] && my_state_is_will(option)) 736 will_wont_resp[option]--; 737 } 738 if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { 739 switch (option) { 740 case TELOPT_ECHO: 741 { 742 init_termbuf(); 743 tty_setecho(1); 744 set_termbuf(); 745 } 746 changeok++; 747 break; 748 749 case TELOPT_BINARY: 750 init_termbuf(); 751 tty_binaryout(1); 752 set_termbuf(); 753 changeok++; 754 break; 755 756 case TELOPT_SGA: 757 turn_on_sga = 0; 758 changeok++; 759 break; 760 761 case TELOPT_STATUS: 762 changeok++; 763 break; 764 765 case TELOPT_TM: 766 /* 767 * Special case for TM. We send a WILL, but 768 * pretend we sent a WONT. 769 */ 770 send_will(option, 0); 771 set_my_want_state_wont(option); 772 set_my_state_wont(option); 773 return; 774 775 case TELOPT_LOGOUT: 776 /* 777 * When we get a LOGOUT option, respond 778 * with a WILL LOGOUT, make sure that 779 * it gets written out to the network, 780 * and then just go away... 781 */ 782 set_my_want_state_will(TELOPT_LOGOUT); 783 send_will(TELOPT_LOGOUT, 0); 784 set_my_state_will(TELOPT_LOGOUT); 785 netflush(); 786 cleanup(0); 787 /* NOT REACHED */ 788 break; 789 790 #ifdef ENCRYPTION 791 case TELOPT_ENCRYPT: 792 changeok++; 793 break; 794 #endif 795 case TELOPT_LINEMODE: 796 case TELOPT_TTYPE: 797 case TELOPT_NAWS: 798 case TELOPT_TSPEED: 799 case TELOPT_LFLOW: 800 case TELOPT_XDISPLOC: 801 #ifdef TELOPT_ENVIRON 802 case TELOPT_NEW_ENVIRON: 803 #endif 804 case TELOPT_OLD_ENVIRON: 805 default: 806 break; 807 } 808 if (changeok) { 809 set_my_want_state_will(option); 810 send_will(option, 0); 811 } else { 812 will_wont_resp[option]++; 813 send_wont(option, 0); 814 } 815 } 816 set_my_state_will(option); 817 818 } /* end of dooption */ 819 820 void 821 send_wont(int option, int init) 822 { 823 if (init) { 824 if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || 825 my_want_state_is_wont(option)) 826 return; 827 set_my_want_state_wont(option); 828 will_wont_resp[option]++; 829 } 830 output_data ((const char *)wont, option); 831 832 DIAG(TD_OPTIONS, printoption("td: send wont", option)); 833 } 834 835 void 836 dontoption(int option) 837 { 838 /* 839 * Process client input. 840 */ 841 842 843 DIAG(TD_OPTIONS, printoption("td: recv dont", option)); 844 845 if (will_wont_resp[option]) { 846 will_wont_resp[option]--; 847 if (will_wont_resp[option] && my_state_is_wont(option)) 848 will_wont_resp[option]--; 849 } 850 if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { 851 switch (option) { 852 case TELOPT_BINARY: 853 init_termbuf(); 854 tty_binaryout(0); 855 set_termbuf(); 856 break; 857 858 case TELOPT_ECHO: /* we should stop echoing */ 859 { 860 init_termbuf(); 861 tty_setecho(0); 862 set_termbuf(); 863 } 864 break; 865 866 case TELOPT_SGA: 867 set_my_want_state_wont(option); 868 if (my_state_is_will(option)) 869 send_wont(option, 0); 870 set_my_state_wont(option); 871 if (turn_on_sga ^= 1) 872 send_will(option, 1); 873 return; 874 875 default: 876 break; 877 } 878 879 set_my_want_state_wont(option); 880 if (my_state_is_will(option)) 881 send_wont(option, 0); 882 } 883 set_my_state_wont(option); 884 885 } /* end of dontoption */ 886 887 #ifdef ENV_HACK 888 int env_ovar = -1; 889 int env_ovalue = -1; 890 #else /* ENV_HACK */ 891 # define env_ovar OLD_ENV_VAR 892 # define env_ovalue OLD_ENV_VALUE 893 #endif /* ENV_HACK */ 894 895 /* 896 * suboption() 897 * 898 * Look at the sub-option buffer, and try to be helpful to the other 899 * side. 900 * 901 * Currently we recognize: 902 * 903 * Terminal type is 904 * Linemode 905 * Window size 906 * Terminal speed 907 */ 908 void 909 suboption(void) 910 { 911 int subchar; 912 913 DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); 914 915 subchar = SB_GET(); 916 switch (subchar) { 917 case TELOPT_TSPEED: { 918 int xspeed, rspeed; 919 920 if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ 921 break; 922 923 settimer(tspeedsubopt); 924 925 if (SB_EOF() || SB_GET() != TELQUAL_IS) 926 return; 927 928 xspeed = atoi((char *)subpointer); 929 930 while (SB_GET() != ',' && !SB_EOF()); 931 if (SB_EOF()) 932 return; 933 934 rspeed = atoi((char *)subpointer); 935 clientstat(TELOPT_TSPEED, xspeed, rspeed); 936 937 break; 938 939 } /* end of case TELOPT_TSPEED */ 940 941 case TELOPT_TTYPE: { /* Yaaaay! */ 942 static char terminalname[41]; 943 944 if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ 945 break; 946 settimer(ttypesubopt); 947 948 if (SB_EOF() || SB_GET() != TELQUAL_IS) { 949 return; /* ??? XXX but, this is the most robust */ 950 } 951 952 terminaltype = terminalname; 953 954 while ((terminaltype < (terminalname + sizeof terminalname-1)) && 955 !SB_EOF()) { 956 int c; 957 958 c = SB_GET(); 959 if (isupper(c)) { 960 c = tolower(c); 961 } 962 *terminaltype++ = c; /* accumulate name */ 963 } 964 *terminaltype = 0; 965 terminaltype = terminalname; 966 break; 967 } /* end of case TELOPT_TTYPE */ 968 969 case TELOPT_NAWS: { 970 int xwinsize, ywinsize; 971 972 if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ 973 break; 974 975 if (SB_EOF()) 976 return; 977 xwinsize = SB_GET() << 8; 978 if (SB_EOF()) 979 return; 980 xwinsize |= SB_GET(); 981 if (SB_EOF()) 982 return; 983 ywinsize = SB_GET() << 8; 984 if (SB_EOF()) 985 return; 986 ywinsize |= SB_GET(); 987 clientstat(TELOPT_NAWS, xwinsize, ywinsize); 988 989 break; 990 991 } /* end of case TELOPT_NAWS */ 992 993 case TELOPT_STATUS: { 994 int mode; 995 996 if (SB_EOF()) 997 break; 998 mode = SB_GET(); 999 switch (mode) { 1000 case TELQUAL_SEND: 1001 if (my_state_is_will(TELOPT_STATUS)) 1002 send_status(); 1003 break; 1004 1005 case TELQUAL_IS: 1006 break; 1007 1008 default: 1009 break; 1010 } 1011 break; 1012 } /* end of case TELOPT_STATUS */ 1013 1014 case TELOPT_XDISPLOC: { 1015 if (SB_EOF() || SB_GET() != TELQUAL_IS) 1016 return; 1017 settimer(xdisplocsubopt); 1018 subpointer[SB_LEN()] = '\0'; 1019 esetenv("DISPLAY", (char *)subpointer, 1); 1020 break; 1021 } /* end of case TELOPT_XDISPLOC */ 1022 1023 #ifdef TELOPT_NEW_ENVIRON 1024 case TELOPT_NEW_ENVIRON: 1025 #endif 1026 case TELOPT_OLD_ENVIRON: { 1027 int c; 1028 char *cp, *varp, *valp; 1029 1030 if (SB_EOF()) 1031 return; 1032 c = SB_GET(); 1033 if (c == TELQUAL_IS) { 1034 if (subchar == TELOPT_OLD_ENVIRON) 1035 settimer(oenvironsubopt); 1036 else 1037 settimer(environsubopt); 1038 } else if (c != TELQUAL_INFO) { 1039 return; 1040 } 1041 1042 #ifdef TELOPT_NEW_ENVIRON 1043 if (subchar == TELOPT_NEW_ENVIRON) { 1044 while (!SB_EOF()) { 1045 c = SB_GET(); 1046 if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) 1047 break; 1048 } 1049 } else 1050 #endif 1051 { 1052 #ifdef ENV_HACK 1053 /* 1054 * We only want to do this if we haven't already decided 1055 * whether or not the other side has its VALUE and VAR 1056 * reversed. 1057 */ 1058 if (env_ovar < 0) { 1059 int last = -1; /* invalid value */ 1060 int empty = 0; 1061 int got_var = 0, got_value = 0, got_uservar = 0; 1062 1063 /* 1064 * The other side might have its VALUE and VAR values 1065 * reversed. To be interoperable, we need to determine 1066 * which way it is. If the first recognized character 1067 * is a VAR or VALUE, then that will tell us what 1068 * type of client it is. If the fist recognized 1069 * character is a USERVAR, then we continue scanning 1070 * the suboption looking for two consecutive 1071 * VAR or VALUE fields. We should not get two 1072 * consecutive VALUE fields, so finding two 1073 * consecutive VALUE or VAR fields will tell us 1074 * what the client is. 1075 */ 1076 SB_SAVE(); 1077 while (!SB_EOF()) { 1078 c = SB_GET(); 1079 switch(c) { 1080 case OLD_ENV_VAR: 1081 if (last < 0 || last == OLD_ENV_VAR 1082 || (empty && (last == OLD_ENV_VALUE))) 1083 goto env_ovar_ok; 1084 got_var++; 1085 last = OLD_ENV_VAR; 1086 break; 1087 case OLD_ENV_VALUE: 1088 if (last < 0 || last == OLD_ENV_VALUE 1089 || (empty && (last == OLD_ENV_VAR))) 1090 goto env_ovar_wrong; 1091 got_value++; 1092 last = OLD_ENV_VALUE; 1093 break; 1094 case ENV_USERVAR: 1095 /* count strings of USERVAR as one */ 1096 if (last != ENV_USERVAR) 1097 got_uservar++; 1098 if (empty) { 1099 if (last == OLD_ENV_VALUE) 1100 goto env_ovar_ok; 1101 if (last == OLD_ENV_VAR) 1102 goto env_ovar_wrong; 1103 } 1104 last = ENV_USERVAR; 1105 break; 1106 case ENV_ESC: 1107 if (!SB_EOF()) 1108 c = SB_GET(); 1109 /* FALL THROUGH */ 1110 default: 1111 empty = 0; 1112 continue; 1113 } 1114 empty = 1; 1115 } 1116 if (empty) { 1117 if (last == OLD_ENV_VALUE) 1118 goto env_ovar_ok; 1119 if (last == OLD_ENV_VAR) 1120 goto env_ovar_wrong; 1121 } 1122 /* 1123 * Ok, the first thing was a USERVAR, and there 1124 * are not two consecutive VAR or VALUE commands, 1125 * and none of the VAR or VALUE commands are empty. 1126 * If the client has sent us a well-formed option, 1127 * then the number of VALUEs received should always 1128 * be less than or equal to the number of VARs and 1129 * USERVARs received. 1130 * 1131 * If we got exactly as many VALUEs as VARs and 1132 * USERVARs, the client has the same definitions. 1133 * 1134 * If we got exactly as many VARs as VALUEs and 1135 * USERVARS, the client has reversed definitions. 1136 */ 1137 if (got_uservar + got_var == got_value) { 1138 env_ovar_ok: 1139 env_ovar = OLD_ENV_VAR; 1140 env_ovalue = OLD_ENV_VALUE; 1141 } else if (got_uservar + got_value == got_var) { 1142 env_ovar_wrong: 1143 env_ovar = OLD_ENV_VALUE; 1144 env_ovalue = OLD_ENV_VAR; 1145 DIAG(TD_OPTIONS, { 1146 output_data("ENVIRON VALUE and VAR are reversed!\r\n"); 1147 }); 1148 1149 } 1150 } 1151 SB_RESTORE(); 1152 #endif 1153 1154 while (!SB_EOF()) { 1155 c = SB_GET(); 1156 if ((c == env_ovar) || (c == ENV_USERVAR)) 1157 break; 1158 } 1159 } 1160 1161 if (SB_EOF()) 1162 return; 1163 1164 cp = varp = (char *)subpointer; 1165 valp = 0; 1166 1167 while (!SB_EOF()) { 1168 c = SB_GET(); 1169 if (subchar == TELOPT_OLD_ENVIRON) { 1170 if (c == env_ovar) 1171 c = NEW_ENV_VAR; 1172 else if (c == env_ovalue) 1173 c = NEW_ENV_VALUE; 1174 } 1175 switch (c) { 1176 1177 case NEW_ENV_VALUE: 1178 *cp = '\0'; 1179 cp = valp = (char *)subpointer; 1180 break; 1181 1182 case NEW_ENV_VAR: 1183 case ENV_USERVAR: 1184 *cp = '\0'; 1185 if (valp) 1186 esetenv(varp, valp, 1); 1187 else 1188 unsetenv(varp); 1189 cp = varp = (char *)subpointer; 1190 valp = 0; 1191 break; 1192 1193 case ENV_ESC: 1194 if (SB_EOF()) 1195 break; 1196 c = SB_GET(); 1197 /* FALL THROUGH */ 1198 default: 1199 *cp++ = c; 1200 break; 1201 } 1202 } 1203 *cp = '\0'; 1204 if (valp) 1205 esetenv(varp, valp, 1); 1206 else 1207 unsetenv(varp); 1208 break; 1209 } /* end of case TELOPT_NEW_ENVIRON */ 1210 #ifdef AUTHENTICATION 1211 case TELOPT_AUTHENTICATION: 1212 if (SB_EOF()) 1213 break; 1214 switch(SB_GET()) { 1215 case TELQUAL_SEND: 1216 case TELQUAL_REPLY: 1217 /* 1218 * These are sent by us and cannot be sent by 1219 * the client. 1220 */ 1221 break; 1222 case TELQUAL_IS: 1223 auth_is(subpointer, SB_LEN()); 1224 break; 1225 case TELQUAL_NAME: 1226 auth_name(subpointer, SB_LEN()); 1227 break; 1228 } 1229 break; 1230 #endif 1231 #ifdef ENCRYPTION 1232 case TELOPT_ENCRYPT: 1233 if (SB_EOF()) 1234 break; 1235 switch(SB_GET()) { 1236 case ENCRYPT_SUPPORT: 1237 encrypt_support(subpointer, SB_LEN()); 1238 break; 1239 case ENCRYPT_IS: 1240 encrypt_is(subpointer, SB_LEN()); 1241 break; 1242 case ENCRYPT_REPLY: 1243 encrypt_reply(subpointer, SB_LEN()); 1244 break; 1245 case ENCRYPT_START: 1246 encrypt_start(subpointer, SB_LEN()); 1247 break; 1248 case ENCRYPT_END: 1249 encrypt_end(); 1250 break; 1251 case ENCRYPT_REQSTART: 1252 encrypt_request_start(subpointer, SB_LEN()); 1253 break; 1254 case ENCRYPT_REQEND: 1255 /* 1256 * We can always send an REQEND so that we cannot 1257 * get stuck encrypting. We should only get this 1258 * if we have been able to get in the correct mode 1259 * anyhow. 1260 */ 1261 encrypt_request_end(); 1262 break; 1263 case ENCRYPT_ENC_KEYID: 1264 encrypt_enc_keyid(subpointer, SB_LEN()); 1265 break; 1266 case ENCRYPT_DEC_KEYID: 1267 encrypt_dec_keyid(subpointer, SB_LEN()); 1268 break; 1269 default: 1270 break; 1271 } 1272 break; 1273 #endif 1274 1275 default: 1276 break; 1277 } /* end of switch */ 1278 1279 } /* end of suboption */ 1280 1281 void 1282 doclientstat(void) 1283 { 1284 clientstat(TELOPT_LINEMODE, WILL, 0); 1285 } 1286 1287 #define ADD(c) *ncp++ = c 1288 #define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; } 1289 1290 void 1291 send_status(void) 1292 { 1293 unsigned char statusbuf[256]; 1294 unsigned char *ncp; 1295 unsigned char i; 1296 1297 ncp = statusbuf; 1298 1299 netflush(); /* get rid of anything waiting to go out */ 1300 1301 ADD(IAC); 1302 ADD(SB); 1303 ADD(TELOPT_STATUS); 1304 ADD(TELQUAL_IS); 1305 1306 /* 1307 * We check the want_state rather than the current state, 1308 * because if we received a DO/WILL for an option that we 1309 * don't support, and the other side didn't send a DONT/WONT 1310 * in response to our WONT/DONT, then the "state" will be 1311 * WILL/DO, and the "want_state" will be WONT/DONT. We 1312 * need to go by the latter. 1313 */ 1314 for (i = 0; i < (unsigned char)NTELOPTS; i++) { 1315 if (my_want_state_is_will(i)) { 1316 ADD(WILL); 1317 ADD_DATA(i); 1318 } 1319 if (his_want_state_is_will(i)) { 1320 ADD(DO); 1321 ADD_DATA(i); 1322 } 1323 } 1324 1325 if (his_want_state_is_will(TELOPT_LFLOW)) { 1326 ADD(SB); 1327 ADD(TELOPT_LFLOW); 1328 if (flowmode) { 1329 ADD(LFLOW_ON); 1330 } else { 1331 ADD(LFLOW_OFF); 1332 } 1333 ADD(SE); 1334 1335 if (restartany >= 0) { 1336 ADD(SB); 1337 ADD(TELOPT_LFLOW); 1338 if (restartany) { 1339 ADD(LFLOW_RESTART_ANY); 1340 } else { 1341 ADD(LFLOW_RESTART_XON); 1342 } 1343 ADD(SE); 1344 } 1345 } 1346 1347 1348 ADD(IAC); 1349 ADD(SE); 1350 1351 writenet(statusbuf, ncp - statusbuf); 1352 netflush(); /* Send it on its way */ 1353 1354 DIAG(TD_OPTIONS, 1355 {printsub('>', statusbuf, ncp - statusbuf); netflush();}); 1356 } 1357