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