1 /* $NetBSD: state.c,v 1.24 2003/08/07 09:46:51 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95"; 36 #else 37 __RCSID("$NetBSD: state.c,v 1.24 2003/08/07 09:46:51 agc Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <stdarg.h> 42 43 #include "telnetd.h" 44 45 static int envvarok __P((char *)); 46 47 unsigned const char doopt[] = { IAC, DO, '%', 'c', 0 }; 48 unsigned const char dont[] = { IAC, DONT, '%', 'c', 0 }; 49 unsigned const char will[] = { IAC, WILL, '%', 'c', 0 }; 50 unsigned const char wont[] = { IAC, WONT, '%', 'c', 0 }; 51 int not42 = 1; 52 53 /* 54 * Buffer for sub-options, and macros 55 * for suboptions buffer manipulations 56 */ 57 unsigned char subbuffer[4096], *subpointer= subbuffer, *subend= subbuffer; 58 59 #define SB_CLEAR() subpointer = subbuffer 60 #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 61 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 62 *subpointer++ = (c); \ 63 } 64 #define SB_GET() ((*subpointer++)&0xff) 65 #define SB_EOF() (subpointer >= subend) 66 #define SB_LEN() (subend - subpointer) 67 68 #ifdef ENV_HACK 69 unsigned char *subsave; 70 #define SB_SAVE() subsave = subpointer; 71 #define SB_RESTORE() subpointer = subsave; 72 #endif 73 74 75 /* 76 * State for recv fsm 77 */ 78 #define TS_DATA 0 /* base state */ 79 #define TS_IAC 1 /* look for double IAC's */ 80 #define TS_CR 2 /* CR-LF ->'s CR */ 81 #define TS_SB 3 /* throw away begin's... */ 82 #define TS_SE 4 /* ...end's (suboption negotiation) */ 83 #define TS_WILL 5 /* will option negotiation */ 84 #define TS_WONT 6 /* wont " */ 85 #define TS_DO 7 /* do " */ 86 #define TS_DONT 8 /* dont " */ 87 88 void 89 telrcv() 90 { 91 register int c; 92 static int state = TS_DATA; 93 94 while (ncc > 0) { 95 if ((&ptyobuf[BUFSIZ] - pfrontp) < 2) 96 break; 97 c = *netip++ & 0377, ncc--; 98 #ifdef ENCRYPTION 99 if (decrypt_input) 100 c = (*decrypt_input)(c); 101 #endif /* ENCRYPTION */ 102 switch (state) { 103 104 case TS_CR: 105 state = TS_DATA; 106 /* Strip off \n or \0 after a \r */ 107 if ((c == 0) || (c == '\n')) { 108 break; 109 } 110 /* FALL THROUGH */ 111 112 case TS_DATA: 113 if (c == IAC) { 114 state = TS_IAC; 115 break; 116 } 117 /* 118 * We now map \r\n ==> \r for pragmatic reasons. 119 * Many client implementations send \r\n when 120 * the user hits the CarriageReturn key. 121 * 122 * We USED to map \r\n ==> \n, since \r\n says 123 * that we want to be in column 1 of the next 124 * printable line, and \n is the standard 125 * unix way of saying that (\r is only good 126 * if CRMOD is set, which it normally is). 127 */ 128 if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) { 129 int nc = *netip; 130 #ifdef ENCRYPTION 131 if (decrypt_input) 132 nc = (*decrypt_input)(nc & 0xff); 133 #endif /* ENCRYPTION */ 134 #ifdef LINEMODE 135 /* 136 * If we are operating in linemode, 137 * convert to local end-of-line. 138 */ 139 if (linemode && (ncc > 0) && (('\n' == nc) || 140 ((0 == nc) && tty_iscrnl())) ) { 141 netip++; ncc--; 142 c = '\n'; 143 } else 144 #endif 145 { 146 #ifdef ENCRYPTION 147 if (decrypt_input) 148 (void)(*decrypt_input)(-1); 149 #endif /* ENCRYPTION */ 150 state = TS_CR; 151 } 152 } 153 *pfrontp++ = c; 154 break; 155 156 case TS_IAC: 157 gotiac: switch (c) { 158 159 /* 160 * Send the process on the pty side an 161 * interrupt. Do this with a NULL or 162 * interrupt char; depending on the tty mode. 163 */ 164 case IP: 165 DIAG(TD_OPTIONS, 166 printoption("td: recv IAC", c)); 167 interrupt(); 168 break; 169 170 case BREAK: 171 DIAG(TD_OPTIONS, 172 printoption("td: recv IAC", c)); 173 sendbrk(); 174 break; 175 176 /* 177 * Are You There? 178 */ 179 case AYT: 180 DIAG(TD_OPTIONS, 181 printoption("td: recv IAC", c)); 182 recv_ayt(); 183 break; 184 185 /* 186 * Abort Output 187 */ 188 case AO: 189 { 190 DIAG(TD_OPTIONS, 191 printoption("td: recv IAC", c)); 192 ptyflush(); /* half-hearted */ 193 init_termbuf(); 194 195 if (slctab[SLC_AO].sptr && 196 *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) { 197 *pfrontp++ = 198 (unsigned char)*slctab[SLC_AO].sptr; 199 } 200 201 netclear(); /* clear buffer back */ 202 output_data("%c%c", IAC, DM); 203 neturg = nfrontp - 1; /* off by one XXX */ 204 DIAG(TD_OPTIONS, 205 printoption("td: send IAC", DM)); 206 break; 207 } 208 209 /* 210 * Erase Character and 211 * Erase Line 212 */ 213 case EC: 214 case EL: 215 { 216 cc_t ch; 217 218 DIAG(TD_OPTIONS, 219 printoption("td: recv IAC", c)); 220 ptyflush(); /* half-hearted */ 221 init_termbuf(); 222 if (c == EC) 223 ch = *slctab[SLC_EC].sptr; 224 else 225 ch = *slctab[SLC_EL].sptr; 226 if (ch != (cc_t)(_POSIX_VDISABLE)) 227 *pfrontp++ = (unsigned char)ch; 228 break; 229 } 230 231 /* 232 * Check for urgent data... 233 */ 234 case DM: 235 DIAG(TD_OPTIONS, 236 printoption("td: recv IAC", c)); 237 SYNCHing = stilloob(net); 238 settimer(gotDM); 239 break; 240 241 242 /* 243 * Begin option subnegotiation... 244 */ 245 case SB: 246 state = TS_SB; 247 SB_CLEAR(); 248 continue; 249 250 case WILL: 251 state = TS_WILL; 252 continue; 253 254 case WONT: 255 state = TS_WONT; 256 continue; 257 258 case DO: 259 state = TS_DO; 260 continue; 261 262 case DONT: 263 state = TS_DONT; 264 continue; 265 case EOR: 266 if (his_state_is_will(TELOPT_EOR)) 267 doeof(); 268 break; 269 270 /* 271 * Handle RFC 10xx Telnet linemode option additions 272 * to command stream (EOF, SUSP, ABORT). 273 */ 274 case xEOF: 275 doeof(); 276 break; 277 278 case SUSP: 279 sendsusp(); 280 break; 281 282 case ABORT: 283 sendbrk(); 284 break; 285 286 case IAC: 287 *pfrontp++ = c; 288 break; 289 } 290 state = TS_DATA; 291 break; 292 293 case TS_SB: 294 if (c == IAC) { 295 state = TS_SE; 296 } else { 297 SB_ACCUM(c); 298 } 299 break; 300 301 case TS_SE: 302 if (c != SE) { 303 if (c != IAC) { 304 /* 305 * bad form of suboption negotiation. 306 * handle it in such a way as to avoid 307 * damage to local state. Parse 308 * suboption buffer found so far, 309 * then treat remaining stream as 310 * another command sequence. 311 */ 312 313 /* for DIAGNOSTICS */ 314 SB_ACCUM(IAC); 315 SB_ACCUM(c); 316 subpointer -= 2; 317 318 SB_TERM(); 319 suboption(); 320 state = TS_IAC; 321 goto gotiac; 322 } 323 SB_ACCUM(c); 324 state = TS_SB; 325 } else { 326 /* for DIAGNOSTICS */ 327 SB_ACCUM(IAC); 328 SB_ACCUM(SE); 329 subpointer -= 2; 330 331 SB_TERM(); 332 suboption(); /* handle sub-option */ 333 state = TS_DATA; 334 } 335 break; 336 337 case TS_WILL: 338 willoption(c); 339 state = TS_DATA; 340 continue; 341 342 case TS_WONT: 343 wontoption(c); 344 state = TS_DATA; 345 continue; 346 347 case TS_DO: 348 dooption(c); 349 state = TS_DATA; 350 continue; 351 352 case TS_DONT: 353 dontoption(c); 354 state = TS_DATA; 355 continue; 356 357 default: 358 syslog(LOG_ERR, "panic state=%d", state); 359 printf("telnetd: panic state=%d\n", state); 360 exit(1); 361 } 362 } 363 } /* end of telrcv */ 364 365 /* 366 * The will/wont/do/dont state machines are based on Dave Borman's 367 * Telnet option processing state machine. 368 * 369 * These correspond to the following states: 370 * my_state = the last negotiated state 371 * want_state = what I want the state to go to 372 * want_resp = how many requests I have sent 373 * All state defaults are negative, and resp defaults to 0. 374 * 375 * When initiating a request to change state to new_state: 376 * 377 * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { 378 * do nothing; 379 * } else { 380 * want_state = new_state; 381 * send new_state; 382 * want_resp++; 383 * } 384 * 385 * When receiving new_state: 386 * 387 * if (want_resp) { 388 * want_resp--; 389 * if (want_resp && (new_state == my_state)) 390 * want_resp--; 391 * } 392 * if ((want_resp == 0) && (new_state != want_state)) { 393 * if (ok_to_switch_to new_state) 394 * want_state = new_state; 395 * else 396 * want_resp++; 397 * send want_state; 398 * } 399 * my_state = new_state; 400 * 401 * Note that new_state is implied in these functions by the function itself. 402 * will and do imply positive new_state, wont and dont imply negative. 403 * 404 * Finally, there is one catch. If we send a negative response to a 405 * positive request, my_state will be the positive while want_state will 406 * remain negative. my_state will revert to negative when the negative 407 * acknowlegment arrives from the peer. Thus, my_state generally tells 408 * us not only the last negotiated state, but also tells us what the peer 409 * wants to be doing as well. It is important to understand this difference 410 * as we may wish to be processing data streams based on our desired state 411 * (want_state) or based on what the peer thinks the state is (my_state). 412 * 413 * This all works fine because if the peer sends a positive request, the data 414 * that we receive prior to negative acknowlegment will probably be affected 415 * by the positive state, and we can process it as such (if we can; if we 416 * can't then it really doesn't matter). If it is that important, then the 417 * peer probably should be buffering until this option state negotiation 418 * is complete. 419 * 420 */ 421 void 422 send_do(option, init) 423 int option, init; 424 { 425 if (init) { 426 if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || 427 his_want_state_is_will(option)) 428 return; 429 /* 430 * Special case for TELOPT_TM: We send a DO, but pretend 431 * that we sent a DONT, so that we can send more DOs if 432 * we want to. 433 */ 434 if (option == TELOPT_TM) 435 set_his_want_state_wont(option); 436 else 437 set_his_want_state_will(option); 438 do_dont_resp[option]++; 439 } 440 (void) output_data((const char *)doopt, option); 441 442 DIAG(TD_OPTIONS, printoption("td: send do", option)); 443 } 444 445 #ifdef LINEMODE 446 extern void doclientstat __P((void)); 447 #endif 448 #if 0 449 #ifdef AUTHENTICATION 450 extern void auth_request __P((void)); /* libtelnet */ 451 #endif 452 #ifdef ENCRYPTION 453 extern void encrypt_send_support __P((void)); 454 #endif /* ENCRYPTION */ 455 #endif 456 457 void 458 willoption(option) 459 int option; 460 { 461 int changeok = 0; 462 void (*func) __P((void)) = 0; 463 464 /* 465 * process input from peer. 466 */ 467 468 DIAG(TD_OPTIONS, printoption("td: recv will", option)); 469 470 if (do_dont_resp[option]) { 471 do_dont_resp[option]--; 472 if (do_dont_resp[option] && his_state_is_will(option)) 473 do_dont_resp[option]--; 474 } 475 if (do_dont_resp[option] == 0) { 476 if (his_want_state_is_wont(option)) { 477 switch (option) { 478 479 case TELOPT_BINARY: 480 init_termbuf(); 481 tty_binaryin(1); 482 set_termbuf(); 483 changeok++; 484 break; 485 486 case TELOPT_ECHO: 487 /* 488 * See comments below for more info. 489 */ 490 not42 = 0; /* looks like a 4.2 system */ 491 break; 492 493 case TELOPT_TM: 494 #if defined(LINEMODE) && defined(KLUDGELINEMODE) 495 /* 496 * This telnetd implementation does not really 497 * support timing marks, it just uses them to 498 * support the kludge linemode stuff. If we 499 * receive a will or wont TM in response to our 500 * do TM request that may have been sent to 501 * determine kludge linemode support, process 502 * it, otherwise TM should get a negative 503 * response back. 504 */ 505 /* 506 * Handle the linemode kludge stuff. 507 * If we are not currently supporting any 508 * linemode at all, then we assume that this 509 * is the client telling us to use kludge 510 * linemode in response to our query. Set the 511 * linemode type that is to be supported, note 512 * that the client wishes to use linemode, and 513 * eat the will TM as though it never arrived. 514 */ 515 if (lmodetype < KLUDGE_LINEMODE) { 516 lmodetype = KLUDGE_LINEMODE; 517 clientstat(TELOPT_LINEMODE, WILL, 0); 518 send_wont(TELOPT_SGA, 1); 519 } else if (lmodetype == NO_AUTOKLUDGE) { 520 lmodetype = KLUDGE_OK; 521 } 522 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 523 /* 524 * We never respond to a WILL TM, and 525 * we leave the state WONT. 526 */ 527 return; 528 529 case TELOPT_LFLOW: 530 /* 531 * If we are going to support flow control 532 * option, then don't worry peer that we can't 533 * change the flow control characters. 534 */ 535 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 536 slctab[SLC_XON].defset.flag |= SLC_DEFAULT; 537 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 538 slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; 539 case TELOPT_TTYPE: 540 case TELOPT_SGA: 541 case TELOPT_NAWS: 542 case TELOPT_TSPEED: 543 case TELOPT_XDISPLOC: 544 case TELOPT_NEW_ENVIRON: 545 case TELOPT_OLD_ENVIRON: 546 changeok++; 547 break; 548 549 #ifdef LINEMODE 550 case TELOPT_LINEMODE: 551 # ifdef KLUDGELINEMODE 552 /* 553 * Note client's desire to use linemode. 554 */ 555 lmodetype = REAL_LINEMODE; 556 # endif /* KLUDGELINEMODE */ 557 func = doclientstat; 558 changeok++; 559 break; 560 #endif /* LINEMODE */ 561 562 #ifdef AUTHENTICATION 563 case TELOPT_AUTHENTICATION: 564 func = auth_request; 565 changeok++; 566 break; 567 #endif 568 569 #ifdef ENCRYPTION 570 case TELOPT_ENCRYPT: 571 func = encrypt_send_support; 572 changeok++; 573 break; 574 #endif /* ENCRYPTION */ 575 576 default: 577 break; 578 } 579 if (changeok) { 580 set_his_want_state_will(option); 581 send_do(option, 0); 582 } else { 583 do_dont_resp[option]++; 584 send_dont(option, 0); 585 } 586 } else { 587 /* 588 * Option processing that should happen when 589 * we receive conformation of a change in 590 * state that we had requested. 591 */ 592 switch (option) { 593 case TELOPT_ECHO: 594 not42 = 0; /* looks like a 4.2 system */ 595 /* 596 * Egads, he responded "WILL ECHO". Turn 597 * it off right now! 598 */ 599 send_dont(option, 1); 600 /* 601 * "WILL ECHO". Kludge upon kludge! 602 * A 4.2 client is now echoing user input at 603 * the tty. This is probably undesireable and 604 * it should be stopped. The client will 605 * respond WONT TM to the DO TM that we send to 606 * check for kludge linemode. When the WONT TM 607 * arrives, linemode will be turned off and a 608 * change propogated to the pty. This change 609 * will cause us to process the new pty state 610 * in localstat(), which will notice that 611 * linemode is off and send a WILL ECHO 612 * so that we are properly in character mode and 613 * all is well. 614 */ 615 break; 616 #ifdef LINEMODE 617 case TELOPT_LINEMODE: 618 # ifdef KLUDGELINEMODE 619 /* 620 * Note client's desire to use linemode. 621 */ 622 lmodetype = REAL_LINEMODE; 623 # endif /* KLUDGELINEMODE */ 624 func = doclientstat; 625 break; 626 #endif /* LINEMODE */ 627 628 #ifdef AUTHENTICATION 629 case TELOPT_AUTHENTICATION: 630 func = auth_request; 631 break; 632 #endif 633 634 #ifdef ENCRYPTION 635 case TELOPT_ENCRYPT: 636 func = encrypt_send_support; 637 break; 638 #endif /* ENCRYPTION */ 639 640 case TELOPT_LFLOW: 641 func = flowstat; 642 break; 643 } 644 } 645 } 646 set_his_state_will(option); 647 if (func) 648 (*func)(); 649 } /* end of willoption */ 650 651 void 652 send_dont(option, init) 653 int option, init; 654 { 655 if (init) { 656 if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || 657 his_want_state_is_wont(option)) 658 return; 659 set_his_want_state_wont(option); 660 do_dont_resp[option]++; 661 } 662 (void) output_data((const char *)dont, option); 663 664 DIAG(TD_OPTIONS, printoption("td: send dont", option)); 665 } 666 667 void 668 wontoption(option) 669 int option; 670 { 671 /* 672 * Process client input. 673 */ 674 675 DIAG(TD_OPTIONS, printoption("td: recv wont", option)); 676 677 if (do_dont_resp[option]) { 678 do_dont_resp[option]--; 679 if (do_dont_resp[option] && his_state_is_wont(option)) 680 do_dont_resp[option]--; 681 } 682 if (do_dont_resp[option] == 0) { 683 if (his_want_state_is_will(option)) { 684 /* it is always ok to change to negative state */ 685 switch (option) { 686 case TELOPT_ECHO: 687 not42 = 1; /* doesn't seem to be a 4.2 system */ 688 break; 689 690 case TELOPT_BINARY: 691 init_termbuf(); 692 tty_binaryin(0); 693 set_termbuf(); 694 break; 695 696 #ifdef LINEMODE 697 case TELOPT_LINEMODE: 698 # ifdef KLUDGELINEMODE 699 /* 700 * If real linemode is supported, then client is 701 * asking to turn linemode off. 702 */ 703 if (lmodetype != REAL_LINEMODE) 704 break; 705 /* XXX double-check this --thorpej */ 706 lmodetype = KLUDGE_LINEMODE; 707 # endif /* KLUDGELINEMODE */ 708 clientstat(TELOPT_LINEMODE, WONT, 0); 709 break; 710 #endif /* LINEMODE */ 711 712 case TELOPT_TM: 713 /* 714 * If we get a WONT TM, and had sent a DO TM, 715 * don't respond with a DONT TM, just leave it 716 * as is. Short circut the state machine to 717 * achieve this. 718 */ 719 set_his_want_state_wont(TELOPT_TM); 720 return; 721 722 case TELOPT_LFLOW: 723 /* 724 * If we are not going to support flow control 725 * option, then let peer know that we can't 726 * change the flow control characters. 727 */ 728 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 729 slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; 730 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 731 slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; 732 break; 733 734 #ifdef AUTHENTICATION 735 case TELOPT_AUTHENTICATION: 736 auth_finished(0, AUTH_REJECT); 737 break; 738 #endif 739 740 /* 741 * For options that we might spin waiting for 742 * sub-negotiation, if the client turns off the 743 * option rather than responding to the request, 744 * we have to treat it here as if we got a response 745 * to the sub-negotiation, (by updating the timers) 746 * so that we'll break out of the loop. 747 */ 748 case TELOPT_TTYPE: 749 settimer(ttypesubopt); 750 break; 751 752 case TELOPT_TSPEED: 753 settimer(tspeedsubopt); 754 break; 755 756 case TELOPT_XDISPLOC: 757 settimer(xdisplocsubopt); 758 break; 759 760 case TELOPT_OLD_ENVIRON: 761 settimer(oenvironsubopt); 762 break; 763 764 case TELOPT_NEW_ENVIRON: 765 settimer(environsubopt); 766 break; 767 768 default: 769 break; 770 } 771 set_his_want_state_wont(option); 772 if (his_state_is_will(option)) 773 send_dont(option, 0); 774 } else { 775 switch (option) { 776 case TELOPT_TM: 777 #if defined(LINEMODE) && defined(KLUDGELINEMODE) 778 if (lmodetype < NO_AUTOKLUDGE) { 779 lmodetype = NO_LINEMODE; 780 clientstat(TELOPT_LINEMODE, WONT, 0); 781 send_will(TELOPT_SGA, 1); 782 send_will(TELOPT_ECHO, 1); 783 } 784 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 785 break; 786 787 #ifdef AUTHENTICATION 788 case TELOPT_AUTHENTICATION: 789 auth_finished(0, AUTH_REJECT); 790 break; 791 #endif 792 default: 793 break; 794 } 795 } 796 } 797 set_his_state_wont(option); 798 799 } /* end of wontoption */ 800 801 void 802 send_will(option, init) 803 int option, init; 804 { 805 if (init) { 806 if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| 807 my_want_state_is_will(option)) 808 return; 809 set_my_want_state_will(option); 810 will_wont_resp[option]++; 811 } 812 (void) output_data((const char *)will, option); 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 #ifdef ENCRYPTION 930 case TELOPT_ENCRYPT: 931 changeok++; 932 break; 933 #endif /* ENCRYPTION */ 934 935 case TELOPT_LINEMODE: 936 case TELOPT_TTYPE: 937 case TELOPT_NAWS: 938 case TELOPT_TSPEED: 939 case TELOPT_LFLOW: 940 case TELOPT_XDISPLOC: 941 case TELOPT_OLD_ENVIRON: 942 default: 943 break; 944 } 945 if (changeok) { 946 set_my_want_state_will(option); 947 send_will(option, 0); 948 } else { 949 will_wont_resp[option]++; 950 send_wont(option, 0); 951 } 952 } 953 set_my_state_will(option); 954 955 } /* end of dooption */ 956 957 void 958 send_wont(option, init) 959 int option, init; 960 { 961 if (init) { 962 if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || 963 my_want_state_is_wont(option)) 964 return; 965 set_my_want_state_wont(option); 966 will_wont_resp[option]++; 967 } 968 (void) output_data((const char *)wont, option); 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 != REAL_LINEMODE) && 1001 (lmodetype != KLUDGE_LINEMODE)) 1002 # else 1003 if (his_state_is_wont(TELOPT_LINEMODE)) 1004 # endif 1005 #endif 1006 { 1007 init_termbuf(); 1008 tty_setecho(0); 1009 set_termbuf(); 1010 } 1011 break; 1012 1013 case TELOPT_SGA: 1014 #if defined(LINEMODE) && defined(KLUDGELINEMODE) 1015 /* 1016 * If kludge linemode is in use, then we 1017 * must process an incoming do SGA for 1018 * linemode purposes. 1019 */ 1020 if ((lmodetype == KLUDGE_LINEMODE) || 1021 (lmodetype == KLUDGE_OK)) { 1022 /* 1023 * The client is asking us to turn 1024 * linemode on. 1025 */ 1026 lmodetype = KLUDGE_LINEMODE; 1027 clientstat(TELOPT_LINEMODE, WILL, 0); 1028 /* 1029 * If we did not turn line mode on, 1030 * then what do we say? Will SGA? 1031 * This violates design of telnet. 1032 * Gross. Very Gross. 1033 */ 1034 } 1035 break; 1036 #else 1037 set_my_want_state_wont(option); 1038 if (my_state_is_will(option)) 1039 send_wont(option, 0); 1040 set_my_state_wont(option); 1041 if (turn_on_sga ^= 1) 1042 send_will(option, 1); 1043 return; 1044 #endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 1045 1046 default: 1047 break; 1048 } 1049 1050 set_my_want_state_wont(option); 1051 if (my_state_is_will(option)) 1052 send_wont(option, 0); 1053 } 1054 set_my_state_wont(option); 1055 1056 } /* end of dontoption */ 1057 1058 #ifdef ENV_HACK 1059 int env_ovar = -1; 1060 int env_ovalue = -1; 1061 #else /* ENV_HACK */ 1062 # define env_ovar OLD_ENV_VAR 1063 # define env_ovalue OLD_ENV_VALUE 1064 #endif /* ENV_HACK */ 1065 1066 /* envvarok(char*) */ 1067 /* check that variable is safe to pass to login or shell */ 1068 static int 1069 envvarok(varp) 1070 char *varp; 1071 { 1072 1073 if (strcmp(varp, "TERMCAP") && /* to prevent a security hole */ 1074 strcmp(varp, "TERMINFO") && /* with tgetent */ 1075 strcmp(varp, "TERMPATH") && 1076 strcmp(varp, "HOME") && /* to prevent the tegetent bug */ 1077 strncmp(varp, "LD_", strlen("LD_")) && /* most systems */ 1078 strncmp(varp, "_RLD_", strlen("_RLD_")) && /* IRIX */ 1079 strcmp(varp, "LIBPATH") && /* AIX */ 1080 strcmp(varp, "ENV") && 1081 strcmp(varp, "BASH_ENV") && 1082 strcmp(varp, "IFS") && 1083 strncmp(varp, "KRB5", strlen("KRB5")) && /* Krb5 */ 1084 /* 1085 * The above case is a catch-all for now. Here are some of 1086 * the specific ones we must avoid passing, at least until 1087 * we can prove it can be done safely. Keep this list 1088 * around un case someone wants to remove the catch-all. 1089 */ 1090 strcmp(varp, "KRB5_CONFIG") && /* Krb5 */ 1091 strcmp(varp, "KRB5CCNAME") && /* Krb5 */ 1092 strcmp(varp, "KRB5_KTNAME") && /* Krb5 */ 1093 strcmp(varp, "KRBTKFILE") && /* Krb4 */ 1094 strcmp(varp, "KRB_CONF") && /* CNS 4 */ 1095 strcmp(varp, "KRB_REALMS") && /* CNS 4 */ 1096 strcmp(varp, "RESOLV_HOST_CONF")) /* Linux */ 1097 return (1); 1098 else { 1099 syslog(LOG_INFO, "Rejected the attempt to modify the " 1100 "environment variable \"%s\"", varp); 1101 return (0); 1102 } 1103 } 1104 1105 /* 1106 * suboption() 1107 * 1108 * Look at the sub-option buffer, and try to be helpful to the other 1109 * side. 1110 * 1111 * Currently we recognize: 1112 * 1113 * Terminal type is 1114 * Linemode 1115 * Window size 1116 * Terminal speed 1117 */ 1118 void 1119 suboption() 1120 { 1121 register int subchar; 1122 1123 DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); 1124 1125 subchar = SB_GET(); 1126 switch (subchar) { 1127 case TELOPT_TSPEED: { 1128 register int xspeed, rspeed; 1129 1130 if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ 1131 break; 1132 1133 settimer(tspeedsubopt); 1134 1135 if (SB_EOF() || SB_GET() != TELQUAL_IS) 1136 return; 1137 1138 xspeed = atoi((char *)subpointer); 1139 1140 while (SB_GET() != ',' && !SB_EOF()); 1141 if (SB_EOF()) 1142 return; 1143 1144 rspeed = atoi((char *)subpointer); 1145 clientstat(TELOPT_TSPEED, xspeed, rspeed); 1146 1147 break; 1148 1149 } /* end of case TELOPT_TSPEED */ 1150 1151 case TELOPT_TTYPE: { /* Yaaaay! */ 1152 static char terminalname[41]; 1153 1154 if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ 1155 break; 1156 settimer(ttypesubopt); 1157 1158 if (SB_EOF() || SB_GET() != TELQUAL_IS) { 1159 return; /* ??? XXX but, this is the most robust */ 1160 } 1161 1162 terminaltype = terminalname; 1163 1164 while ((terminaltype < (terminalname + sizeof terminalname-1)) && 1165 !SB_EOF()) { 1166 register int c; 1167 1168 c = SB_GET(); 1169 if (isupper(c)) { 1170 c = tolower(c); 1171 } 1172 *terminaltype++ = c; /* accumulate name */ 1173 } 1174 *terminaltype = 0; 1175 terminaltype = terminalname; 1176 break; 1177 } /* end of case TELOPT_TTYPE */ 1178 1179 case TELOPT_NAWS: { 1180 register int xwinsize, ywinsize; 1181 1182 if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ 1183 break; 1184 1185 if (SB_EOF()) 1186 return; 1187 xwinsize = SB_GET() << 8; 1188 if (SB_EOF()) 1189 return; 1190 xwinsize |= SB_GET(); 1191 if (SB_EOF()) 1192 return; 1193 ywinsize = SB_GET() << 8; 1194 if (SB_EOF()) 1195 return; 1196 ywinsize |= SB_GET(); 1197 clientstat(TELOPT_NAWS, xwinsize, ywinsize); 1198 1199 break; 1200 1201 } /* end of case TELOPT_NAWS */ 1202 1203 #ifdef LINEMODE 1204 case TELOPT_LINEMODE: { 1205 register int request; 1206 1207 if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */ 1208 break; 1209 /* 1210 * Process linemode suboptions. 1211 */ 1212 if (SB_EOF()) 1213 break; /* garbage was sent */ 1214 request = SB_GET(); /* get will/wont */ 1215 1216 if (SB_EOF()) 1217 break; /* another garbage check */ 1218 1219 if (request == LM_SLC) { /* SLC is not preceded by WILL or WONT */ 1220 /* 1221 * Process suboption buffer of slc's 1222 */ 1223 start_slc(1); 1224 do_opt_slc(subpointer, subend - subpointer); 1225 (void) end_slc(0); 1226 break; 1227 } else if (request == LM_MODE) { 1228 if (SB_EOF()) 1229 return; 1230 useeditmode = SB_GET(); /* get mode flag */ 1231 clientstat(LM_MODE, 0, 0); 1232 break; 1233 } 1234 1235 if (SB_EOF()) 1236 break; 1237 switch (SB_GET()) { /* what suboption? */ 1238 case LM_FORWARDMASK: 1239 /* 1240 * According to spec, only server can send request for 1241 * forwardmask, and client can only return a positive response. 1242 * So don't worry about it. 1243 */ 1244 1245 default: 1246 break; 1247 } 1248 break; 1249 } /* end of case TELOPT_LINEMODE */ 1250 #endif 1251 case TELOPT_STATUS: { 1252 int mode; 1253 1254 if (SB_EOF()) 1255 break; 1256 mode = SB_GET(); 1257 switch (mode) { 1258 case TELQUAL_SEND: 1259 if (my_state_is_will(TELOPT_STATUS)) 1260 send_status(); 1261 break; 1262 1263 case TELQUAL_IS: 1264 break; 1265 1266 default: 1267 break; 1268 } 1269 break; 1270 } /* end of case TELOPT_STATUS */ 1271 1272 case TELOPT_XDISPLOC: { 1273 if (SB_EOF() || SB_GET() != TELQUAL_IS) 1274 return; 1275 settimer(xdisplocsubopt); 1276 subpointer[SB_LEN()] = '\0'; 1277 (void)setenv("DISPLAY", (char *)subpointer, 1); 1278 break; 1279 } /* end of case TELOPT_XDISPLOC */ 1280 1281 case TELOPT_NEW_ENVIRON: 1282 case TELOPT_OLD_ENVIRON: { 1283 register int c; 1284 register char *cp, *varp, *valp; 1285 1286 if (SB_EOF()) 1287 return; 1288 c = SB_GET(); 1289 if (c == TELQUAL_IS) { 1290 if (subchar == TELOPT_OLD_ENVIRON) 1291 settimer(oenvironsubopt); 1292 else 1293 settimer(environsubopt); 1294 } else if (c != TELQUAL_INFO) { 1295 return; 1296 } 1297 1298 if (subchar == TELOPT_NEW_ENVIRON) { 1299 while (!SB_EOF()) { 1300 c = SB_GET(); 1301 if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) 1302 break; 1303 } 1304 } else 1305 { 1306 #ifdef ENV_HACK 1307 /* 1308 * We only want to do this if we haven't already decided 1309 * whether or not the other side has its VALUE and VAR 1310 * reversed. 1311 */ 1312 if (env_ovar < 0) { 1313 register int last = -1; /* invalid value */ 1314 int empty = 0; 1315 int got_var = 0, got_value = 0, got_uservar = 0; 1316 1317 /* 1318 * The other side might have its VALUE and VAR values 1319 * reversed. To be interoperable, we need to determine 1320 * which way it is. If the first recognized character 1321 * is a VAR or VALUE, then that will tell us what 1322 * type of client it is. If the fist recognized 1323 * character is a USERVAR, then we continue scanning 1324 * the suboption looking for two consecutive 1325 * VAR or VALUE fields. We should not get two 1326 * consecutive VALUE fields, so finding two 1327 * consecutive VALUE or VAR fields will tell us 1328 * what the client is. 1329 */ 1330 SB_SAVE(); 1331 while (!SB_EOF()) { 1332 c = SB_GET(); 1333 switch(c) { 1334 case OLD_ENV_VAR: 1335 if (last < 0 || last == OLD_ENV_VAR 1336 || (empty && (last == OLD_ENV_VALUE))) 1337 goto env_ovar_ok; 1338 got_var++; 1339 last = OLD_ENV_VAR; 1340 break; 1341 case OLD_ENV_VALUE: 1342 if (last < 0 || last == OLD_ENV_VALUE 1343 || (empty && (last == OLD_ENV_VAR))) 1344 goto env_ovar_wrong; 1345 got_value++; 1346 last = OLD_ENV_VALUE; 1347 break; 1348 case ENV_USERVAR: 1349 /* count strings of USERVAR as one */ 1350 if (last != ENV_USERVAR) 1351 got_uservar++; 1352 if (empty) { 1353 if (last == OLD_ENV_VALUE) 1354 goto env_ovar_ok; 1355 if (last == OLD_ENV_VAR) 1356 goto env_ovar_wrong; 1357 } 1358 last = ENV_USERVAR; 1359 break; 1360 case ENV_ESC: 1361 if (!SB_EOF()) 1362 c = SB_GET(); 1363 /* FALL THROUGH */ 1364 default: 1365 empty = 0; 1366 continue; 1367 } 1368 empty = 1; 1369 } 1370 if (empty) { 1371 if (last == OLD_ENV_VALUE) 1372 goto env_ovar_ok; 1373 if (last == OLD_ENV_VAR) 1374 goto env_ovar_wrong; 1375 } 1376 /* 1377 * Ok, the first thing was a USERVAR, and there 1378 * are not two consecutive VAR or VALUE commands, 1379 * and none of the VAR or VALUE commands are empty. 1380 * If the client has sent us a well-formed option, 1381 * then the number of VALUEs received should always 1382 * be less than or equal to the number of VARs and 1383 * USERVARs received. 1384 * 1385 * If we got exactly as many VALUEs as VARs and 1386 * USERVARs, the client has the same definitions. 1387 * 1388 * If we got exactly as many VARs as VALUEs and 1389 * USERVARS, the client has reversed definitions. 1390 */ 1391 if (got_uservar + got_var == got_value) { 1392 env_ovar_ok: 1393 env_ovar = OLD_ENV_VAR; 1394 env_ovalue = OLD_ENV_VALUE; 1395 } else if (got_uservar + got_value == got_var) { 1396 env_ovar_wrong: 1397 env_ovar = OLD_ENV_VALUE; 1398 env_ovalue = OLD_ENV_VAR; 1399 DIAG(TD_OPTIONS, {output_data( 1400 "ENVIRON VALUE and VAR are reversed!\r\n");}); 1401 1402 } 1403 } 1404 SB_RESTORE(); 1405 #endif 1406 1407 while (!SB_EOF()) { 1408 c = SB_GET(); 1409 if ((c == env_ovar) || (c == ENV_USERVAR)) 1410 break; 1411 } 1412 } 1413 1414 if (SB_EOF()) 1415 return; 1416 1417 cp = varp = (char *)subpointer; 1418 valp = 0; 1419 1420 while (!SB_EOF()) { 1421 c = SB_GET(); 1422 if (subchar == TELOPT_OLD_ENVIRON) { 1423 if (c == env_ovar) 1424 c = NEW_ENV_VAR; 1425 else if (c == env_ovalue) 1426 c = NEW_ENV_VALUE; 1427 } 1428 switch (c) { 1429 1430 case NEW_ENV_VALUE: 1431 *cp = '\0'; 1432 cp = valp = (char *)subpointer; 1433 break; 1434 1435 case NEW_ENV_VAR: 1436 case ENV_USERVAR: 1437 *cp = '\0'; 1438 if (envvarok(varp)) { 1439 if (valp) 1440 (void)setenv(varp, valp, 1); 1441 else 1442 unsetenv(varp); 1443 } 1444 cp = varp = (char *)subpointer; 1445 valp = 0; 1446 break; 1447 1448 case ENV_ESC: 1449 if (SB_EOF()) 1450 break; 1451 c = SB_GET(); 1452 /* FALL THROUGH */ 1453 default: 1454 *cp++ = c; 1455 break; 1456 } 1457 } 1458 *cp = '\0'; 1459 if (envvarok(varp)) { 1460 if (valp) 1461 (void)setenv(varp, valp, 1); 1462 else 1463 unsetenv(varp); 1464 } 1465 break; 1466 } /* end of case TELOPT_NEW_ENVIRON */ 1467 #ifdef AUTHENTICATION 1468 case TELOPT_AUTHENTICATION: 1469 if (SB_EOF()) 1470 break; 1471 switch(SB_GET()) { 1472 case TELQUAL_SEND: 1473 case TELQUAL_REPLY: 1474 /* 1475 * These are sent by us and cannot be sent by 1476 * the client. 1477 */ 1478 break; 1479 case TELQUAL_IS: 1480 auth_is(subpointer, SB_LEN()); 1481 break; 1482 case TELQUAL_NAME: 1483 auth_name(subpointer, SB_LEN()); 1484 break; 1485 } 1486 break; 1487 #endif 1488 #ifdef ENCRYPTION 1489 case TELOPT_ENCRYPT: 1490 if (SB_EOF()) 1491 break; 1492 switch(SB_GET()) { 1493 case ENCRYPT_SUPPORT: 1494 encrypt_support(subpointer, SB_LEN()); 1495 break; 1496 case ENCRYPT_IS: 1497 encrypt_is(subpointer, SB_LEN()); 1498 break; 1499 case ENCRYPT_REPLY: 1500 encrypt_reply(subpointer, SB_LEN()); 1501 break; 1502 case ENCRYPT_START: 1503 encrypt_start(subpointer, SB_LEN()); 1504 break; 1505 case ENCRYPT_END: 1506 encrypt_end(); 1507 break; 1508 case ENCRYPT_REQSTART: 1509 encrypt_request_start(subpointer, SB_LEN()); 1510 break; 1511 case ENCRYPT_REQEND: 1512 /* 1513 * We can always send an REQEND so that we cannot 1514 * get stuck encrypting. We should only get this 1515 * if we have been able to get in the correct mode 1516 * anyhow. 1517 */ 1518 encrypt_request_end(); 1519 break; 1520 case ENCRYPT_ENC_KEYID: 1521 encrypt_enc_keyid(subpointer, SB_LEN()); 1522 break; 1523 case ENCRYPT_DEC_KEYID: 1524 encrypt_dec_keyid(subpointer, SB_LEN()); 1525 break; 1526 default: 1527 break; 1528 } 1529 break; 1530 #endif /* ENCRYPTION */ 1531 1532 default: 1533 break; 1534 } /* end of switch */ 1535 1536 } /* end of suboption */ 1537 1538 #ifdef LINEMODE 1539 void 1540 doclientstat() 1541 { 1542 clientstat(TELOPT_LINEMODE, WILL, 0); 1543 } 1544 #endif /* LINEMODE */ 1545 1546 void 1547 send_status() 1548 { 1549 #define ADD(c) \ 1550 do { \ 1551 if (ep > ncp) \ 1552 *ncp++ = c; \ 1553 else \ 1554 goto trunc; \ 1555 } while (0) 1556 #define ADD_DATA(c) \ 1557 do { \ 1558 ADD(c); if (c == SE || c == IAC) ADD(c); \ 1559 } while (0) 1560 1561 unsigned char statusbuf[256]; 1562 unsigned char *ep; 1563 register unsigned char *ncp; 1564 register unsigned char i; 1565 1566 ncp = statusbuf; 1567 ep = statusbuf + sizeof(statusbuf); 1568 1569 netflush(); /* get rid of anything waiting to go out */ 1570 1571 ADD(IAC); 1572 ADD(SB); 1573 ADD(TELOPT_STATUS); 1574 ADD(TELQUAL_IS); 1575 1576 /* 1577 * We check the want_state rather than the current state, 1578 * because if we received a DO/WILL for an option that we 1579 * don't support, and the other side didn't send a DONT/WONT 1580 * in response to our WONT/DONT, then the "state" will be 1581 * WILL/DO, and the "want_state" will be WONT/DONT. We 1582 * need to go by the latter. 1583 */ 1584 for (i = 0; i < (unsigned char)NTELOPTS; i++) { 1585 if (my_want_state_is_will(i)) { 1586 ADD(WILL); 1587 ADD_DATA(i); 1588 } 1589 if (his_want_state_is_will(i)) { 1590 ADD(DO); 1591 ADD_DATA(i); 1592 } 1593 } 1594 1595 if (his_want_state_is_will(TELOPT_LFLOW)) { 1596 ADD(SB); 1597 ADD(TELOPT_LFLOW); 1598 if (flowmode) { 1599 ADD(LFLOW_ON); 1600 } else { 1601 ADD(LFLOW_OFF); 1602 } 1603 ADD(SE); 1604 1605 if (restartany >= 0) { 1606 ADD(SB); 1607 ADD(TELOPT_LFLOW); 1608 if (restartany) { 1609 ADD(LFLOW_RESTART_ANY); 1610 } else { 1611 ADD(LFLOW_RESTART_XON); 1612 } 1613 ADD(SE); 1614 } 1615 } 1616 1617 #ifdef LINEMODE 1618 if (his_want_state_is_will(TELOPT_LINEMODE)) { 1619 unsigned char *cp, *cpe; 1620 int len; 1621 1622 ADD(SB); 1623 ADD(TELOPT_LINEMODE); 1624 ADD(LM_MODE); 1625 ADD_DATA(editmode); 1626 ADD(SE); 1627 1628 ADD(SB); 1629 ADD(TELOPT_LINEMODE); 1630 ADD(LM_SLC); 1631 start_slc(0); 1632 send_slc(); 1633 len = end_slc(&cp); 1634 for (cpe = cp + len; cp < cpe; cp++) 1635 ADD_DATA(*cp); 1636 ADD(SE); 1637 } 1638 #endif /* LINEMODE */ 1639 1640 ADD(IAC); 1641 ADD(SE); 1642 1643 writenet(statusbuf, ncp - statusbuf); 1644 netflush(); /* Send it on its way */ 1645 1646 DIAG(TD_OPTIONS, 1647 {printsub('>', statusbuf, ncp - statusbuf); netflush();}); 1648 return; 1649 1650 trunc: 1651 /* XXX bark? */ 1652 return; 1653 #undef ADD 1654 #undef ADD_DATA 1655 } 1656 1657 int 1658 output_data(const char *format, ...) 1659 { 1660 va_list args; 1661 size_t remaining, ret; 1662 1663 va_start(args, format); 1664 remaining = BUFSIZ - (nfrontp - netobuf); 1665 /* try a netflush() if the room is too low */ 1666 if (strlen(format) > remaining || BUFSIZ / 4 > remaining) { 1667 netflush(); 1668 remaining = BUFSIZ - (nfrontp - netobuf); 1669 } 1670 ret = vsnprintf(nfrontp, remaining, format, args); 1671 nfrontp += ((ret < remaining - 1) ? ret : remaining - 1); 1672 va_end(args); 1673 return ret; 1674 } 1675 1676 int 1677 output_datalen(const char *buf, size_t l) 1678 { 1679 size_t remaining; 1680 1681 remaining = BUFSIZ - (nfrontp - netobuf); 1682 if (remaining < l) { 1683 netflush(); 1684 remaining = BUFSIZ - (nfrontp - netobuf); 1685 } 1686 if (remaining < l) 1687 return -1; 1688 memmove(nfrontp, buf, l); 1689 nfrontp += l; 1690 return (int)l; 1691 } 1692