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