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