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