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