1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35#if 0 36static const char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95"; 37#endif 38static const char rcsid[] =
| 1/* 2 * Copyright (c) 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#ifndef lint 35#if 0 36static const char sccsid[] = "@(#)state.c 8.5 (Berkeley) 5/30/95"; 37#endif 38static const char rcsid[] =
|
39 "$FreeBSD: head/contrib/telnet/telnetd/state.c 80224 2001-07-23 21:52:26Z kris $";
| 39 "$FreeBSD: head/contrib/telnet/telnetd/state.c 81965 2001-08-20 12:28:40Z markm $";
|
40#endif /* not lint */ 41 42#include <stdarg.h> 43#include "telnetd.h" 44#if defined(AUTHENTICATION) 45#include <libtelnet/auth.h> 46#endif 47#if defined(ENCRYPTION) 48#include <libtelnet/encrypt.h> 49#endif 50 51unsigned char doopt[] = { IAC, DO, '%', 'c', 0 }; 52unsigned char dont[] = { IAC, DONT, '%', 'c', 0 }; 53unsigned char will[] = { IAC, WILL, '%', 'c', 0 }; 54unsigned char wont[] = { IAC, WONT, '%', 'c', 0 }; 55int not42 = 1; 56 57/* 58 * Buffer for sub-options, and macros 59 * for suboptions buffer manipulations 60 */ 61unsigned char subbuffer[512], *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 73unsigned 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 93telrcv() 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: 164gotiac: 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, "panic state=%d", 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 if ((*nfrontp++ = *cp++) == IAC) 382 *nfrontp++ = IAC; 383 } 384#endif /* defined(CRAY2) && defined(UNICOS5) */ 385} /* end of telrcv */ 386 387/* 388 * The will/wont/do/dont state machines are based on Dave Borman's 389 * Telnet option processing state machine. 390 * 391 * These correspond to the following states: 392 * my_state = the last negotiated state 393 * want_state = what I want the state to go to 394 * want_resp = how many requests I have sent 395 * All state defaults are negative, and resp defaults to 0. 396 * 397 * When initiating a request to change state to new_state: 398 * 399 * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { 400 * do nothing; 401 * } else { 402 * want_state = new_state; 403 * send new_state; 404 * want_resp++; 405 * } 406 * 407 * When receiving new_state: 408 * 409 * if (want_resp) { 410 * want_resp--; 411 * if (want_resp && (new_state == my_state)) 412 * want_resp--; 413 * } 414 * if ((want_resp == 0) && (new_state != want_state)) { 415 * if (ok_to_switch_to new_state) 416 * want_state = new_state; 417 * else 418 * want_resp++; 419 * send want_state; 420 * } 421 * my_state = new_state; 422 * 423 * Note that new_state is implied in these functions by the function itself. 424 * will and do imply positive new_state, wont and dont imply negative. 425 * 426 * Finally, there is one catch. If we send a negative response to a 427 * positive request, my_state will be the positive while want_state will 428 * remain negative. my_state will revert to negative when the negative 429 * acknowlegment arrives from the peer. Thus, my_state generally tells 430 * us not only the last negotiated state, but also tells us what the peer 431 * wants to be doing as well. It is important to understand this difference 432 * as we may wish to be processing data streams based on our desired state 433 * (want_state) or based on what the peer thinks the state is (my_state). 434 * 435 * This all works fine because if the peer sends a positive request, the data 436 * that we receive prior to negative acknowlegment will probably be affected 437 * by the positive state, and we can process it as such (if we can; if we 438 * can't then it really doesn't matter). If it is that important, then the 439 * peer probably should be buffering until this option state negotiation 440 * is complete. 441 * 442 */ 443 void 444send_do(option, init) 445 int option, init; 446{ 447 if (init) { 448 if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || 449 his_want_state_is_will(option)) 450 return; 451 /* 452 * Special case for TELOPT_TM: We send a DO, but pretend 453 * that we sent a DONT, so that we can send more DOs if 454 * we want to. 455 */ 456 if (option == TELOPT_TM) 457 set_his_want_state_wont(option); 458 else 459 set_his_want_state_will(option); 460 do_dont_resp[option]++; 461 } 462 output_data((const char *)doopt, option); 463 464 DIAG(TD_OPTIONS, printoption("td: send do", option)); 465} 466 467#ifdef AUTHENTICATION 468extern void auth_request(); 469#endif 470#ifdef LINEMODE 471extern void doclientstat(); 472#endif 473#ifdef ENCRYPTION 474extern void encrypt_send_support(); 475#endif /* ENCRYPTION */ 476 477 void 478willoption(option) 479 int option; 480{ 481 int changeok = 0; 482 void (*func)() = 0; 483 484 /* 485 * process input from peer. 486 */ 487 488 DIAG(TD_OPTIONS, printoption("td: recv will", option)); 489 490 if (do_dont_resp[option]) { 491 do_dont_resp[option]--; 492 if (do_dont_resp[option] && his_state_is_will(option)) 493 do_dont_resp[option]--; 494 } 495 if (do_dont_resp[option] == 0) { 496 if (his_want_state_is_wont(option)) { 497 switch (option) { 498 499 case TELOPT_BINARY: 500 init_termbuf(); 501 tty_binaryin(1); 502 set_termbuf(); 503 changeok++; 504 break; 505 506 case TELOPT_ECHO: 507 /* 508 * See comments below for more info. 509 */ 510 not42 = 0; /* looks like a 4.2 system */ 511 break; 512 513 case TELOPT_TM: 514#if defined(LINEMODE) && defined(KLUDGELINEMODE) 515 /* 516 * This telnetd implementation does not really 517 * support timing marks, it just uses them to 518 * support the kludge linemode stuff. If we 519 * receive a will or wont TM in response to our 520 * do TM request that may have been sent to 521 * determine kludge linemode support, process 522 * it, otherwise TM should get a negative 523 * response back. 524 */ 525 /* 526 * Handle the linemode kludge stuff. 527 * If we are not currently supporting any 528 * linemode at all, then we assume that this 529 * is the client telling us to use kludge 530 * linemode in response to our query. Set the 531 * linemode type that is to be supported, note 532 * that the client wishes to use linemode, and 533 * eat the will TM as though it never arrived. 534 */ 535 if (lmodetype < KLUDGE_LINEMODE) { 536 lmodetype = KLUDGE_LINEMODE; 537 clientstat(TELOPT_LINEMODE, WILL, 0); 538 send_wont(TELOPT_SGA, 1); 539 } else if (lmodetype == NO_AUTOKLUDGE) { 540 lmodetype = KLUDGE_OK; 541 } 542#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 543 /* 544 * We never respond to a WILL TM, and 545 * we leave the state WONT. 546 */ 547 return; 548 549 case TELOPT_LFLOW: 550 /* 551 * If we are going to support flow control 552 * option, then don't worry peer that we can't 553 * change the flow control characters. 554 */ 555 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 556 slctab[SLC_XON].defset.flag |= SLC_DEFAULT; 557 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 558 slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; 559 case TELOPT_TTYPE: 560 case TELOPT_SGA: 561 case TELOPT_NAWS: 562 case TELOPT_TSPEED: 563 case TELOPT_XDISPLOC: 564 case TELOPT_NEW_ENVIRON: 565 case TELOPT_OLD_ENVIRON: 566 changeok++; 567 break; 568 569#ifdef LINEMODE 570 case TELOPT_LINEMODE: 571# ifdef KLUDGELINEMODE 572 /* 573 * Note client's desire to use linemode. 574 */ 575 lmodetype = REAL_LINEMODE; 576# endif /* KLUDGELINEMODE */ 577 func = doclientstat; 578 changeok++; 579 break; 580#endif /* LINEMODE */ 581 582#ifdef AUTHENTICATION 583 case TELOPT_AUTHENTICATION: 584 func = auth_request; 585 changeok++; 586 break; 587#endif 588 589#ifdef ENCRYPTION 590 case TELOPT_ENCRYPT: 591 func = encrypt_send_support; 592 changeok++; 593 break; 594#endif /* ENCRYPTION */ 595 596 default: 597 break; 598 } 599 if (changeok) { 600 set_his_want_state_will(option); 601 send_do(option, 0); 602 } else { 603 do_dont_resp[option]++; 604 send_dont(option, 0); 605 } 606 } else { 607 /* 608 * Option processing that should happen when 609 * we receive conformation of a change in 610 * state that we had requested. 611 */ 612 switch (option) { 613 case TELOPT_ECHO: 614 not42 = 0; /* looks like a 4.2 system */ 615 /* 616 * Egads, he responded "WILL ECHO". Turn 617 * it off right now! 618 */ 619 send_dont(option, 1); 620 /* 621 * "WILL ECHO". Kludge upon kludge! 622 * A 4.2 client is now echoing user input at 623 * the tty. This is probably undesireable and 624 * it should be stopped. The client will 625 * respond WONT TM to the DO TM that we send to 626 * check for kludge linemode. When the WONT TM 627 * arrives, linemode will be turned off and a 628 * change propogated to the pty. This change 629 * will cause us to process the new pty state 630 * in localstat(), which will notice that 631 * linemode is off and send a WILL ECHO 632 * so that we are properly in character mode and 633 * all is well. 634 */ 635 break; 636#ifdef LINEMODE 637 case TELOPT_LINEMODE: 638# ifdef KLUDGELINEMODE 639 /* 640 * Note client's desire to use linemode. 641 */ 642 lmodetype = REAL_LINEMODE; 643# endif /* KLUDGELINEMODE */ 644 func = doclientstat; 645 break; 646#endif /* LINEMODE */ 647 648#ifdef AUTHENTICATION 649 case TELOPT_AUTHENTICATION: 650 func = auth_request; 651 break; 652#endif 653 654#ifdef ENCRYPTION 655 case TELOPT_ENCRYPT: 656 func = encrypt_send_support; 657 break; 658#endif /* ENCRYPTION */ 659 case TELOPT_LFLOW: 660 func = flowstat; 661 break; 662 } 663 } 664 } 665 set_his_state_will(option); 666 if (func) 667 (*func)(); 668} /* end of willoption */ 669 670 void 671send_dont(option, init) 672 int option, init; 673{ 674 if (init) { 675 if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || 676 his_want_state_is_wont(option)) 677 return; 678 set_his_want_state_wont(option); 679 do_dont_resp[option]++; 680 } 681 output_data((const char *)dont, option); 682 683 DIAG(TD_OPTIONS, printoption("td: send dont", option)); 684} 685 686 void 687wontoption(option) 688 int option; 689{ 690 /* 691 * Process client input. 692 */ 693 694 DIAG(TD_OPTIONS, printoption("td: recv wont", option)); 695 696 if (do_dont_resp[option]) { 697 do_dont_resp[option]--; 698 if (do_dont_resp[option] && his_state_is_wont(option)) 699 do_dont_resp[option]--; 700 } 701 if (do_dont_resp[option] == 0) { 702 if (his_want_state_is_will(option)) { 703 /* it is always ok to change to negative state */ 704 switch (option) { 705 case TELOPT_ECHO: 706 not42 = 1; /* doesn't seem to be a 4.2 system */ 707 break; 708 709 case TELOPT_BINARY: 710 init_termbuf(); 711 tty_binaryin(0); 712 set_termbuf(); 713 break; 714 715#ifdef LINEMODE 716 case TELOPT_LINEMODE: 717# ifdef KLUDGELINEMODE 718 /* 719 * If real linemode is supported, then client is 720 * asking to turn linemode off. 721 */ 722 if (lmodetype != REAL_LINEMODE) 723 break;
| 40#endif /* not lint */ 41 42#include <stdarg.h> 43#include "telnetd.h" 44#if defined(AUTHENTICATION) 45#include <libtelnet/auth.h> 46#endif 47#if defined(ENCRYPTION) 48#include <libtelnet/encrypt.h> 49#endif 50 51unsigned char doopt[] = { IAC, DO, '%', 'c', 0 }; 52unsigned char dont[] = { IAC, DONT, '%', 'c', 0 }; 53unsigned char will[] = { IAC, WILL, '%', 'c', 0 }; 54unsigned char wont[] = { IAC, WONT, '%', 'c', 0 }; 55int not42 = 1; 56 57/* 58 * Buffer for sub-options, and macros 59 * for suboptions buffer manipulations 60 */ 61unsigned char subbuffer[512], *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 73unsigned 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 93telrcv() 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: 164gotiac: 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, "panic state=%d", 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 if ((*nfrontp++ = *cp++) == IAC) 382 *nfrontp++ = IAC; 383 } 384#endif /* defined(CRAY2) && defined(UNICOS5) */ 385} /* end of telrcv */ 386 387/* 388 * The will/wont/do/dont state machines are based on Dave Borman's 389 * Telnet option processing state machine. 390 * 391 * These correspond to the following states: 392 * my_state = the last negotiated state 393 * want_state = what I want the state to go to 394 * want_resp = how many requests I have sent 395 * All state defaults are negative, and resp defaults to 0. 396 * 397 * When initiating a request to change state to new_state: 398 * 399 * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) { 400 * do nothing; 401 * } else { 402 * want_state = new_state; 403 * send new_state; 404 * want_resp++; 405 * } 406 * 407 * When receiving new_state: 408 * 409 * if (want_resp) { 410 * want_resp--; 411 * if (want_resp && (new_state == my_state)) 412 * want_resp--; 413 * } 414 * if ((want_resp == 0) && (new_state != want_state)) { 415 * if (ok_to_switch_to new_state) 416 * want_state = new_state; 417 * else 418 * want_resp++; 419 * send want_state; 420 * } 421 * my_state = new_state; 422 * 423 * Note that new_state is implied in these functions by the function itself. 424 * will and do imply positive new_state, wont and dont imply negative. 425 * 426 * Finally, there is one catch. If we send a negative response to a 427 * positive request, my_state will be the positive while want_state will 428 * remain negative. my_state will revert to negative when the negative 429 * acknowlegment arrives from the peer. Thus, my_state generally tells 430 * us not only the last negotiated state, but also tells us what the peer 431 * wants to be doing as well. It is important to understand this difference 432 * as we may wish to be processing data streams based on our desired state 433 * (want_state) or based on what the peer thinks the state is (my_state). 434 * 435 * This all works fine because if the peer sends a positive request, the data 436 * that we receive prior to negative acknowlegment will probably be affected 437 * by the positive state, and we can process it as such (if we can; if we 438 * can't then it really doesn't matter). If it is that important, then the 439 * peer probably should be buffering until this option state negotiation 440 * is complete. 441 * 442 */ 443 void 444send_do(option, init) 445 int option, init; 446{ 447 if (init) { 448 if ((do_dont_resp[option] == 0 && his_state_is_will(option)) || 449 his_want_state_is_will(option)) 450 return; 451 /* 452 * Special case for TELOPT_TM: We send a DO, but pretend 453 * that we sent a DONT, so that we can send more DOs if 454 * we want to. 455 */ 456 if (option == TELOPT_TM) 457 set_his_want_state_wont(option); 458 else 459 set_his_want_state_will(option); 460 do_dont_resp[option]++; 461 } 462 output_data((const char *)doopt, option); 463 464 DIAG(TD_OPTIONS, printoption("td: send do", option)); 465} 466 467#ifdef AUTHENTICATION 468extern void auth_request(); 469#endif 470#ifdef LINEMODE 471extern void doclientstat(); 472#endif 473#ifdef ENCRYPTION 474extern void encrypt_send_support(); 475#endif /* ENCRYPTION */ 476 477 void 478willoption(option) 479 int option; 480{ 481 int changeok = 0; 482 void (*func)() = 0; 483 484 /* 485 * process input from peer. 486 */ 487 488 DIAG(TD_OPTIONS, printoption("td: recv will", option)); 489 490 if (do_dont_resp[option]) { 491 do_dont_resp[option]--; 492 if (do_dont_resp[option] && his_state_is_will(option)) 493 do_dont_resp[option]--; 494 } 495 if (do_dont_resp[option] == 0) { 496 if (his_want_state_is_wont(option)) { 497 switch (option) { 498 499 case TELOPT_BINARY: 500 init_termbuf(); 501 tty_binaryin(1); 502 set_termbuf(); 503 changeok++; 504 break; 505 506 case TELOPT_ECHO: 507 /* 508 * See comments below for more info. 509 */ 510 not42 = 0; /* looks like a 4.2 system */ 511 break; 512 513 case TELOPT_TM: 514#if defined(LINEMODE) && defined(KLUDGELINEMODE) 515 /* 516 * This telnetd implementation does not really 517 * support timing marks, it just uses them to 518 * support the kludge linemode stuff. If we 519 * receive a will or wont TM in response to our 520 * do TM request that may have been sent to 521 * determine kludge linemode support, process 522 * it, otherwise TM should get a negative 523 * response back. 524 */ 525 /* 526 * Handle the linemode kludge stuff. 527 * If we are not currently supporting any 528 * linemode at all, then we assume that this 529 * is the client telling us to use kludge 530 * linemode in response to our query. Set the 531 * linemode type that is to be supported, note 532 * that the client wishes to use linemode, and 533 * eat the will TM as though it never arrived. 534 */ 535 if (lmodetype < KLUDGE_LINEMODE) { 536 lmodetype = KLUDGE_LINEMODE; 537 clientstat(TELOPT_LINEMODE, WILL, 0); 538 send_wont(TELOPT_SGA, 1); 539 } else if (lmodetype == NO_AUTOKLUDGE) { 540 lmodetype = KLUDGE_OK; 541 } 542#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 543 /* 544 * We never respond to a WILL TM, and 545 * we leave the state WONT. 546 */ 547 return; 548 549 case TELOPT_LFLOW: 550 /* 551 * If we are going to support flow control 552 * option, then don't worry peer that we can't 553 * change the flow control characters. 554 */ 555 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 556 slctab[SLC_XON].defset.flag |= SLC_DEFAULT; 557 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 558 slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT; 559 case TELOPT_TTYPE: 560 case TELOPT_SGA: 561 case TELOPT_NAWS: 562 case TELOPT_TSPEED: 563 case TELOPT_XDISPLOC: 564 case TELOPT_NEW_ENVIRON: 565 case TELOPT_OLD_ENVIRON: 566 changeok++; 567 break; 568 569#ifdef LINEMODE 570 case TELOPT_LINEMODE: 571# ifdef KLUDGELINEMODE 572 /* 573 * Note client's desire to use linemode. 574 */ 575 lmodetype = REAL_LINEMODE; 576# endif /* KLUDGELINEMODE */ 577 func = doclientstat; 578 changeok++; 579 break; 580#endif /* LINEMODE */ 581 582#ifdef AUTHENTICATION 583 case TELOPT_AUTHENTICATION: 584 func = auth_request; 585 changeok++; 586 break; 587#endif 588 589#ifdef ENCRYPTION 590 case TELOPT_ENCRYPT: 591 func = encrypt_send_support; 592 changeok++; 593 break; 594#endif /* ENCRYPTION */ 595 596 default: 597 break; 598 } 599 if (changeok) { 600 set_his_want_state_will(option); 601 send_do(option, 0); 602 } else { 603 do_dont_resp[option]++; 604 send_dont(option, 0); 605 } 606 } else { 607 /* 608 * Option processing that should happen when 609 * we receive conformation of a change in 610 * state that we had requested. 611 */ 612 switch (option) { 613 case TELOPT_ECHO: 614 not42 = 0; /* looks like a 4.2 system */ 615 /* 616 * Egads, he responded "WILL ECHO". Turn 617 * it off right now! 618 */ 619 send_dont(option, 1); 620 /* 621 * "WILL ECHO". Kludge upon kludge! 622 * A 4.2 client is now echoing user input at 623 * the tty. This is probably undesireable and 624 * it should be stopped. The client will 625 * respond WONT TM to the DO TM that we send to 626 * check for kludge linemode. When the WONT TM 627 * arrives, linemode will be turned off and a 628 * change propogated to the pty. This change 629 * will cause us to process the new pty state 630 * in localstat(), which will notice that 631 * linemode is off and send a WILL ECHO 632 * so that we are properly in character mode and 633 * all is well. 634 */ 635 break; 636#ifdef LINEMODE 637 case TELOPT_LINEMODE: 638# ifdef KLUDGELINEMODE 639 /* 640 * Note client's desire to use linemode. 641 */ 642 lmodetype = REAL_LINEMODE; 643# endif /* KLUDGELINEMODE */ 644 func = doclientstat; 645 break; 646#endif /* LINEMODE */ 647 648#ifdef AUTHENTICATION 649 case TELOPT_AUTHENTICATION: 650 func = auth_request; 651 break; 652#endif 653 654#ifdef ENCRYPTION 655 case TELOPT_ENCRYPT: 656 func = encrypt_send_support; 657 break; 658#endif /* ENCRYPTION */ 659 case TELOPT_LFLOW: 660 func = flowstat; 661 break; 662 } 663 } 664 } 665 set_his_state_will(option); 666 if (func) 667 (*func)(); 668} /* end of willoption */ 669 670 void 671send_dont(option, init) 672 int option, init; 673{ 674 if (init) { 675 if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) || 676 his_want_state_is_wont(option)) 677 return; 678 set_his_want_state_wont(option); 679 do_dont_resp[option]++; 680 } 681 output_data((const char *)dont, option); 682 683 DIAG(TD_OPTIONS, printoption("td: send dont", option)); 684} 685 686 void 687wontoption(option) 688 int option; 689{ 690 /* 691 * Process client input. 692 */ 693 694 DIAG(TD_OPTIONS, printoption("td: recv wont", option)); 695 696 if (do_dont_resp[option]) { 697 do_dont_resp[option]--; 698 if (do_dont_resp[option] && his_state_is_wont(option)) 699 do_dont_resp[option]--; 700 } 701 if (do_dont_resp[option] == 0) { 702 if (his_want_state_is_will(option)) { 703 /* it is always ok to change to negative state */ 704 switch (option) { 705 case TELOPT_ECHO: 706 not42 = 1; /* doesn't seem to be a 4.2 system */ 707 break; 708 709 case TELOPT_BINARY: 710 init_termbuf(); 711 tty_binaryin(0); 712 set_termbuf(); 713 break; 714 715#ifdef LINEMODE 716 case TELOPT_LINEMODE: 717# ifdef KLUDGELINEMODE 718 /* 719 * If real linemode is supported, then client is 720 * asking to turn linemode off. 721 */ 722 if (lmodetype != REAL_LINEMODE) 723 break;
|
| 724 lmodetype = KLUDGE_LINEMODE;
|
724# endif /* KLUDGELINEMODE */ 725 clientstat(TELOPT_LINEMODE, WONT, 0); 726 break; 727#endif /* LINEMODE */ 728 729 case TELOPT_TM: 730 /* 731 * If we get a WONT TM, and had sent a DO TM, 732 * don't respond with a DONT TM, just leave it 733 * as is. Short circut the state machine to 734 * achive this. 735 */ 736 set_his_want_state_wont(TELOPT_TM); 737 return; 738 739 case TELOPT_LFLOW: 740 /* 741 * If we are not going to support flow control 742 * option, then let peer know that we can't 743 * change the flow control characters. 744 */ 745 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 746 slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; 747 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 748 slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; 749 break; 750 751#if defined(AUTHENTICATION) 752 case TELOPT_AUTHENTICATION: 753 auth_finished(0, AUTH_REJECT); 754 break; 755#endif 756 757 /* 758 * For options that we might spin waiting for 759 * sub-negotiation, if the client turns off the 760 * option rather than responding to the request, 761 * we have to treat it here as if we got a response 762 * to the sub-negotiation, (by updating the timers) 763 * so that we'll break out of the loop. 764 */ 765 case TELOPT_TTYPE: 766 settimer(ttypesubopt); 767 break; 768 769 case TELOPT_TSPEED: 770 settimer(tspeedsubopt); 771 break; 772 773 case TELOPT_XDISPLOC: 774 settimer(xdisplocsubopt); 775 break; 776 777 case TELOPT_OLD_ENVIRON: 778 settimer(oenvironsubopt); 779 break; 780 781 case TELOPT_NEW_ENVIRON: 782 settimer(environsubopt); 783 break; 784 785 default: 786 break; 787 } 788 set_his_want_state_wont(option); 789 if (his_state_is_will(option)) 790 send_dont(option, 0); 791 } else { 792 switch (option) { 793 case TELOPT_TM: 794#if defined(LINEMODE) && defined(KLUDGELINEMODE) 795 if (lmodetype < NO_AUTOKLUDGE) { 796 lmodetype = NO_LINEMODE; 797 clientstat(TELOPT_LINEMODE, WONT, 0); 798 send_will(TELOPT_SGA, 1); 799 send_will(TELOPT_ECHO, 1); 800 } 801#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 802 break; 803 804#if defined(AUTHENTICATION) 805 case TELOPT_AUTHENTICATION: 806 auth_finished(0, AUTH_REJECT); 807 break; 808#endif 809 default: 810 break; 811 } 812 } 813 } 814 set_his_state_wont(option); 815 816} /* end of wontoption */ 817 818 void 819send_will(option, init) 820 int option, init; 821{ 822 if (init) { 823 if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| 824 my_want_state_is_will(option)) 825 return; 826 set_my_want_state_will(option); 827 will_wont_resp[option]++; 828 } 829 output_data((const char *)will, option); 830 831 DIAG(TD_OPTIONS, printoption("td: send will", option)); 832} 833 834#if !defined(LINEMODE) || !defined(KLUDGELINEMODE) 835/* 836 * When we get a DONT SGA, we will try once to turn it 837 * back on. If the other side responds DONT SGA, we 838 * leave it at that. This is so that when we talk to 839 * clients that understand KLUDGELINEMODE but not LINEMODE, 840 * we'll keep them in char-at-a-time mode. 841 */ 842int turn_on_sga = 0; 843#endif 844 845 void 846dooption(option) 847 int option; 848{ 849 int changeok = 0; 850 851 /* 852 * Process client input. 853 */ 854 855 DIAG(TD_OPTIONS, printoption("td: recv do", option)); 856 857 if (will_wont_resp[option]) { 858 will_wont_resp[option]--; 859 if (will_wont_resp[option] && my_state_is_will(option)) 860 will_wont_resp[option]--; 861 } 862 if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { 863 switch (option) { 864 case TELOPT_ECHO: 865#ifdef LINEMODE 866# ifdef KLUDGELINEMODE 867 if (lmodetype == NO_LINEMODE) 868# else 869 if (his_state_is_wont(TELOPT_LINEMODE)) 870# endif 871#endif 872 { 873 init_termbuf(); 874 tty_setecho(1); 875 set_termbuf(); 876 } 877 changeok++; 878 break; 879 880 case TELOPT_BINARY: 881 init_termbuf(); 882 tty_binaryout(1); 883 set_termbuf(); 884 changeok++; 885 break; 886 887 case TELOPT_SGA: 888#if defined(LINEMODE) && defined(KLUDGELINEMODE) 889 /* 890 * If kludge linemode is in use, then we must 891 * process an incoming do SGA for linemode 892 * purposes. 893 */ 894 if (lmodetype == KLUDGE_LINEMODE) { 895 /* 896 * Receipt of "do SGA" in kludge 897 * linemode is the peer asking us to 898 * turn off linemode. Make note of 899 * the request. 900 */ 901 clientstat(TELOPT_LINEMODE, WONT, 0); 902 /* 903 * If linemode did not get turned off 904 * then don't tell peer that we did. 905 * Breaking here forces a wont SGA to 906 * be returned. 907 */ 908 if (linemode) 909 break; 910 } 911#else 912 turn_on_sga = 0; 913#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 914 changeok++; 915 break; 916 917 case TELOPT_STATUS: 918 changeok++; 919 break; 920 921 case TELOPT_TM: 922 /* 923 * Special case for TM. We send a WILL, but 924 * pretend we sent a WONT. 925 */ 926 send_will(option, 0); 927 set_my_want_state_wont(option); 928 set_my_state_wont(option); 929 return; 930 931 case TELOPT_LOGOUT: 932 /* 933 * When we get a LOGOUT option, respond 934 * with a WILL LOGOUT, make sure that 935 * it gets written out to the network, 936 * and then just go away... 937 */ 938 set_my_want_state_will(TELOPT_LOGOUT); 939 send_will(TELOPT_LOGOUT, 0); 940 set_my_state_will(TELOPT_LOGOUT); 941 (void)netflush(); 942 cleanup(0); 943 /* NOT REACHED */ 944 break; 945 946#ifdef ENCRYPTION 947 case TELOPT_ENCRYPT: 948 changeok++; 949 break; 950#endif /* ENCRYPTION */ 951 case TELOPT_LINEMODE: 952 case TELOPT_TTYPE: 953 case TELOPT_NAWS: 954 case TELOPT_TSPEED: 955 case TELOPT_LFLOW: 956 case TELOPT_XDISPLOC: 957#ifdef TELOPT_ENVIRON 958 case TELOPT_NEW_ENVIRON: 959#endif 960 case TELOPT_OLD_ENVIRON: 961 default: 962 break; 963 } 964 if (changeok) { 965 set_my_want_state_will(option); 966 send_will(option, 0); 967 } else { 968 will_wont_resp[option]++; 969 send_wont(option, 0); 970 } 971 } 972 set_my_state_will(option); 973 974} /* end of dooption */ 975 976 void 977send_wont(option, init) 978 int option, init; 979{ 980 if (init) { 981 if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || 982 my_want_state_is_wont(option)) 983 return; 984 set_my_want_state_wont(option); 985 will_wont_resp[option]++; 986 } 987 output_data((const char *)wont, option); 988 989 DIAG(TD_OPTIONS, printoption("td: send wont", option)); 990} 991 992 void 993dontoption(option) 994 int option; 995{ 996 /* 997 * Process client input. 998 */ 999 1000 1001 DIAG(TD_OPTIONS, printoption("td: recv dont", option)); 1002 1003 if (will_wont_resp[option]) { 1004 will_wont_resp[option]--; 1005 if (will_wont_resp[option] && my_state_is_wont(option)) 1006 will_wont_resp[option]--; 1007 } 1008 if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { 1009 switch (option) { 1010 case TELOPT_BINARY: 1011 init_termbuf(); 1012 tty_binaryout(0); 1013 set_termbuf(); 1014 break; 1015 1016 case TELOPT_ECHO: /* we should stop echoing */ 1017#ifdef LINEMODE 1018# ifdef KLUDGELINEMODE 1019 if ((lmodetype != REAL_LINEMODE) && 1020 (lmodetype != KLUDGE_LINEMODE)) 1021# else 1022 if (his_state_is_wont(TELOPT_LINEMODE)) 1023# endif 1024#endif 1025 { 1026 init_termbuf(); 1027 tty_setecho(0); 1028 set_termbuf(); 1029 } 1030 break; 1031 1032 case TELOPT_SGA: 1033#if defined(LINEMODE) && defined(KLUDGELINEMODE) 1034 /* 1035 * If kludge linemode is in use, then we 1036 * must process an incoming do SGA for 1037 * linemode purposes. 1038 */ 1039 if ((lmodetype == KLUDGE_LINEMODE) || 1040 (lmodetype == KLUDGE_OK)) { 1041 /* 1042 * The client is asking us to turn 1043 * linemode on. 1044 */ 1045 lmodetype = KLUDGE_LINEMODE; 1046 clientstat(TELOPT_LINEMODE, WILL, 0); 1047 /* 1048 * If we did not turn line mode on, 1049 * then what do we say? Will SGA? 1050 * This violates design of telnet. 1051 * Gross. Very Gross. 1052 */ 1053 } 1054 break; 1055#else 1056 set_my_want_state_wont(option); 1057 if (my_state_is_will(option)) 1058 send_wont(option, 0); 1059 set_my_state_wont(option); 1060 if (turn_on_sga ^= 1) 1061 send_will(option, 1); 1062 return; 1063#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 1064 1065 default: 1066 break; 1067 } 1068 1069 set_my_want_state_wont(option); 1070 if (my_state_is_will(option)) 1071 send_wont(option, 0); 1072 } 1073 set_my_state_wont(option); 1074 1075} /* end of dontoption */ 1076 1077#ifdef ENV_HACK 1078int env_ovar = -1; 1079int env_ovalue = -1; 1080#else /* ENV_HACK */ 1081# define env_ovar OLD_ENV_VAR 1082# define env_ovalue OLD_ENV_VALUE 1083#endif /* ENV_HACK */ 1084 1085/* 1086 * suboption() 1087 * 1088 * Look at the sub-option buffer, and try to be helpful to the other 1089 * side. 1090 * 1091 * Currently we recognize: 1092 * 1093 * Terminal type is 1094 * Linemode 1095 * Window size 1096 * Terminal speed 1097 */ 1098 void 1099suboption() 1100{ 1101 register int subchar; 1102 1103 DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); 1104 1105 subchar = SB_GET(); 1106 switch (subchar) { 1107 case TELOPT_TSPEED: { 1108 register int xspeed, rspeed; 1109 1110 if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ 1111 break; 1112 1113 settimer(tspeedsubopt); 1114 1115 if (SB_EOF() || SB_GET() != TELQUAL_IS) 1116 return; 1117 1118 xspeed = atoi((char *)subpointer); 1119 1120 while (SB_GET() != ',' && !SB_EOF()); 1121 if (SB_EOF()) 1122 return; 1123 1124 rspeed = atoi((char *)subpointer); 1125 clientstat(TELOPT_TSPEED, xspeed, rspeed); 1126 1127 break; 1128 1129 } /* end of case TELOPT_TSPEED */ 1130 1131 case TELOPT_TTYPE: { /* Yaaaay! */ 1132 static char terminalname[41]; 1133 1134 if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ 1135 break; 1136 settimer(ttypesubopt); 1137 1138 if (SB_EOF() || SB_GET() != TELQUAL_IS) { 1139 return; /* ??? XXX but, this is the most robust */ 1140 } 1141 1142 terminaltype = terminalname; 1143 1144 while ((terminaltype < (terminalname + sizeof terminalname-1)) && 1145 !SB_EOF()) { 1146 register int c; 1147 1148 c = SB_GET(); 1149 if (isupper(c)) { 1150 c = tolower(c); 1151 } 1152 *terminaltype++ = c; /* accumulate name */ 1153 } 1154 *terminaltype = 0; 1155 terminaltype = terminalname; 1156 break; 1157 } /* end of case TELOPT_TTYPE */ 1158 1159 case TELOPT_NAWS: { 1160 register int xwinsize, ywinsize; 1161 1162 if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ 1163 break; 1164 1165 if (SB_EOF()) 1166 return; 1167 xwinsize = SB_GET() << 8; 1168 if (SB_EOF()) 1169 return; 1170 xwinsize |= SB_GET(); 1171 if (SB_EOF()) 1172 return; 1173 ywinsize = SB_GET() << 8; 1174 if (SB_EOF()) 1175 return; 1176 ywinsize |= SB_GET(); 1177 clientstat(TELOPT_NAWS, xwinsize, ywinsize); 1178 1179 break; 1180 1181 } /* end of case TELOPT_NAWS */ 1182 1183#ifdef LINEMODE 1184 case TELOPT_LINEMODE: { 1185 register int request; 1186 1187 if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */ 1188 break; 1189 /* 1190 * Process linemode suboptions. 1191 */ 1192 if (SB_EOF()) 1193 break; /* garbage was sent */ 1194 request = SB_GET(); /* get will/wont */ 1195 1196 if (SB_EOF()) 1197 break; /* another garbage check */ 1198 1199 if (request == LM_SLC) { /* SLC is not preceeded by WILL or WONT */ 1200 /* 1201 * Process suboption buffer of slc's 1202 */ 1203 start_slc(1); 1204 do_opt_slc(subpointer, subend - subpointer); 1205 (void) end_slc(0); 1206 break; 1207 } else if (request == LM_MODE) { 1208 if (SB_EOF()) 1209 return; 1210 useeditmode = SB_GET(); /* get mode flag */ 1211 clientstat(LM_MODE, 0, 0); 1212 break; 1213 } 1214 1215 if (SB_EOF()) 1216 break; 1217 switch (SB_GET()) { /* what suboption? */ 1218 case LM_FORWARDMASK: 1219 /* 1220 * According to spec, only server can send request for 1221 * forwardmask, and client can only return a positive response. 1222 * So don't worry about it. 1223 */ 1224 1225 default: 1226 break; 1227 } 1228 break; 1229 } /* end of case TELOPT_LINEMODE */ 1230#endif 1231 case TELOPT_STATUS: { 1232 int mode; 1233 1234 if (SB_EOF()) 1235 break; 1236 mode = SB_GET(); 1237 switch (mode) { 1238 case TELQUAL_SEND: 1239 if (my_state_is_will(TELOPT_STATUS)) 1240 send_status(); 1241 break; 1242 1243 case TELQUAL_IS: 1244 break; 1245 1246 default: 1247 break; 1248 } 1249 break; 1250 } /* end of case TELOPT_STATUS */ 1251 1252 case TELOPT_XDISPLOC: { 1253 if (SB_EOF() || SB_GET() != TELQUAL_IS) 1254 return; 1255 settimer(xdisplocsubopt); 1256 subpointer[SB_LEN()] = '\0'; 1257 (void)setenv("DISPLAY", (char *)subpointer, 1); 1258 break; 1259 } /* end of case TELOPT_XDISPLOC */ 1260 1261#ifdef TELOPT_NEW_ENVIRON 1262 case TELOPT_NEW_ENVIRON: 1263#endif 1264 case TELOPT_OLD_ENVIRON: { 1265 register int c; 1266 register char *cp, *varp, *valp; 1267 1268 if (SB_EOF()) 1269 return; 1270 c = SB_GET(); 1271 if (c == TELQUAL_IS) { 1272 if (subchar == TELOPT_OLD_ENVIRON) 1273 settimer(oenvironsubopt); 1274 else 1275 settimer(environsubopt); 1276 } else if (c != TELQUAL_INFO) { 1277 return; 1278 } 1279 1280#ifdef TELOPT_NEW_ENVIRON 1281 if (subchar == TELOPT_NEW_ENVIRON) { 1282 while (!SB_EOF()) { 1283 c = SB_GET(); 1284 if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) 1285 break; 1286 } 1287 } else 1288#endif 1289 { 1290#ifdef ENV_HACK 1291 /* 1292 * We only want to do this if we haven't already decided 1293 * whether or not the other side has its VALUE and VAR 1294 * reversed. 1295 */ 1296 if (env_ovar < 0) { 1297 register int last = -1; /* invalid value */ 1298 int empty = 0; 1299 int got_var = 0, got_value = 0, got_uservar = 0; 1300 1301 /* 1302 * The other side might have its VALUE and VAR values 1303 * reversed. To be interoperable, we need to determine 1304 * which way it is. If the first recognized character 1305 * is a VAR or VALUE, then that will tell us what 1306 * type of client it is. If the fist recognized 1307 * character is a USERVAR, then we continue scanning 1308 * the suboption looking for two consecutive 1309 * VAR or VALUE fields. We should not get two 1310 * consecutive VALUE fields, so finding two 1311 * consecutive VALUE or VAR fields will tell us 1312 * what the client is. 1313 */ 1314 SB_SAVE(); 1315 while (!SB_EOF()) { 1316 c = SB_GET(); 1317 switch(c) { 1318 case OLD_ENV_VAR: 1319 if (last < 0 || last == OLD_ENV_VAR 1320 || (empty && (last == OLD_ENV_VALUE))) 1321 goto env_ovar_ok; 1322 got_var++; 1323 last = OLD_ENV_VAR; 1324 break; 1325 case OLD_ENV_VALUE: 1326 if (last < 0 || last == OLD_ENV_VALUE 1327 || (empty && (last == OLD_ENV_VAR))) 1328 goto env_ovar_wrong; 1329 got_value++; 1330 last = OLD_ENV_VALUE; 1331 break; 1332 case ENV_USERVAR: 1333 /* count strings of USERVAR as one */ 1334 if (last != ENV_USERVAR) 1335 got_uservar++; 1336 if (empty) { 1337 if (last == OLD_ENV_VALUE) 1338 goto env_ovar_ok; 1339 if (last == OLD_ENV_VAR) 1340 goto env_ovar_wrong; 1341 } 1342 last = ENV_USERVAR; 1343 break; 1344 case ENV_ESC: 1345 if (!SB_EOF()) 1346 c = SB_GET(); 1347 /* FALL THROUGH */ 1348 default: 1349 empty = 0; 1350 continue; 1351 } 1352 empty = 1; 1353 } 1354 if (empty) { 1355 if (last == OLD_ENV_VALUE) 1356 goto env_ovar_ok; 1357 if (last == OLD_ENV_VAR) 1358 goto env_ovar_wrong; 1359 } 1360 /* 1361 * Ok, the first thing was a USERVAR, and there 1362 * are not two consecutive VAR or VALUE commands, 1363 * and none of the VAR or VALUE commands are empty. 1364 * If the client has sent us a well-formed option, 1365 * then the number of VALUEs received should always 1366 * be less than or equal to the number of VARs and 1367 * USERVARs received. 1368 * 1369 * If we got exactly as many VALUEs as VARs and 1370 * USERVARs, the client has the same definitions. 1371 * 1372 * If we got exactly as many VARs as VALUEs and 1373 * USERVARS, the client has reversed definitions. 1374 */ 1375 if (got_uservar + got_var == got_value) { 1376 env_ovar_ok: 1377 env_ovar = OLD_ENV_VAR; 1378 env_ovalue = OLD_ENV_VALUE; 1379 } else if (got_uservar + got_value == got_var) { 1380 env_ovar_wrong: 1381 env_ovar = OLD_ENV_VALUE; 1382 env_ovalue = OLD_ENV_VAR; 1383 DIAG(TD_OPTIONS, 1384 output_data("ENVIRON VALUE and VAR are reversed!\r\n")); 1385 1386 } 1387 } 1388 SB_RESTORE(); 1389#endif 1390 1391 while (!SB_EOF()) { 1392 c = SB_GET(); 1393 if ((c == env_ovar) || (c == ENV_USERVAR)) 1394 break; 1395 } 1396 } 1397 1398 if (SB_EOF()) 1399 return; 1400 1401 cp = varp = (char *)subpointer; 1402 valp = 0; 1403 1404 while (!SB_EOF()) { 1405 c = SB_GET(); 1406 if (subchar == TELOPT_OLD_ENVIRON) { 1407 if (c == env_ovar) 1408 c = NEW_ENV_VAR; 1409 else if (c == env_ovalue) 1410 c = NEW_ENV_VALUE; 1411 } 1412 switch (c) { 1413 1414 case NEW_ENV_VALUE: 1415 *cp = '\0'; 1416 cp = valp = (char *)subpointer; 1417 break; 1418 1419 case NEW_ENV_VAR: 1420 case ENV_USERVAR: 1421 *cp = '\0'; 1422 if (valp) 1423 (void)setenv(varp, valp, 1); 1424 else 1425 unsetenv(varp); 1426 cp = varp = (char *)subpointer; 1427 valp = 0; 1428 break; 1429 1430 case ENV_ESC: 1431 if (SB_EOF()) 1432 break; 1433 c = SB_GET(); 1434 /* FALL THROUGH */ 1435 default: 1436 *cp++ = c; 1437 break; 1438 } 1439 } 1440 *cp = '\0'; 1441 if (valp) 1442 (void)setenv(varp, valp, 1); 1443 else 1444 unsetenv(varp); 1445 break; 1446 } /* end of case TELOPT_NEW_ENVIRON */ 1447#if defined(AUTHENTICATION) 1448 case TELOPT_AUTHENTICATION: 1449 if (SB_EOF()) 1450 break; 1451 switch(SB_GET()) { 1452 case TELQUAL_SEND: 1453 case TELQUAL_REPLY: 1454 /* 1455 * These are sent by us and cannot be sent by 1456 * the client. 1457 */ 1458 break; 1459 case TELQUAL_IS: 1460 auth_is(subpointer, SB_LEN()); 1461 break; 1462 case TELQUAL_NAME: 1463 auth_name(subpointer, SB_LEN()); 1464 break; 1465 } 1466 break; 1467#endif 1468#ifdef ENCRYPTION 1469 case TELOPT_ENCRYPT: 1470 if (SB_EOF()) 1471 break; 1472 switch(SB_GET()) { 1473 case ENCRYPT_SUPPORT: 1474 encrypt_support(subpointer, SB_LEN()); 1475 break; 1476 case ENCRYPT_IS: 1477 encrypt_is(subpointer, SB_LEN()); 1478 break; 1479 case ENCRYPT_REPLY: 1480 encrypt_reply(subpointer, SB_LEN()); 1481 break; 1482 case ENCRYPT_START: 1483 encrypt_start(subpointer, SB_LEN()); 1484 break; 1485 case ENCRYPT_END: 1486 encrypt_end(); 1487 break; 1488 case ENCRYPT_REQSTART: 1489 encrypt_request_start(subpointer, SB_LEN()); 1490 break; 1491 case ENCRYPT_REQEND: 1492 /* 1493 * We can always send an REQEND so that we cannot 1494 * get stuck encrypting. We should only get this 1495 * if we have been able to get in the correct mode 1496 * anyhow. 1497 */ 1498 encrypt_request_end(); 1499 break; 1500 case ENCRYPT_ENC_KEYID: 1501 encrypt_enc_keyid(subpointer, SB_LEN()); 1502 break; 1503 case ENCRYPT_DEC_KEYID: 1504 encrypt_dec_keyid(subpointer, SB_LEN()); 1505 break; 1506 default: 1507 break; 1508 } 1509 break; 1510#endif /* ENCRYPTION */ 1511 1512 default: 1513 break; 1514 } /* end of switch */ 1515 1516} /* end of suboption */ 1517 1518 void 1519doclientstat() 1520{ 1521 clientstat(TELOPT_LINEMODE, WILL, 0); 1522} 1523 1524#define ADD(c) *ncp++ = c 1525#define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; } 1526 void 1527send_status() 1528{ 1529 unsigned char statusbuf[256]; 1530 register unsigned char *ncp; 1531 register unsigned char i; 1532 1533 ncp = statusbuf; 1534 1535 netflush(); /* get rid of anything waiting to go out */ 1536 1537 ADD(IAC); 1538 ADD(SB); 1539 ADD(TELOPT_STATUS); 1540 ADD(TELQUAL_IS); 1541 1542 /* 1543 * We check the want_state rather than the current state, 1544 * because if we received a DO/WILL for an option that we 1545 * don't support, and the other side didn't send a DONT/WONT 1546 * in response to our WONT/DONT, then the "state" will be 1547 * WILL/DO, and the "want_state" will be WONT/DONT. We 1548 * need to go by the latter. 1549 */ 1550 for (i = 0; i < (unsigned char)NTELOPTS; i++) { 1551 if (my_want_state_is_will(i)) { 1552 ADD(WILL); 1553 ADD_DATA(i);
| 725# endif /* KLUDGELINEMODE */ 726 clientstat(TELOPT_LINEMODE, WONT, 0); 727 break; 728#endif /* LINEMODE */ 729 730 case TELOPT_TM: 731 /* 732 * If we get a WONT TM, and had sent a DO TM, 733 * don't respond with a DONT TM, just leave it 734 * as is. Short circut the state machine to 735 * achive this. 736 */ 737 set_his_want_state_wont(TELOPT_TM); 738 return; 739 740 case TELOPT_LFLOW: 741 /* 742 * If we are not going to support flow control 743 * option, then let peer know that we can't 744 * change the flow control characters. 745 */ 746 slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS; 747 slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE; 748 slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS; 749 slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE; 750 break; 751 752#if defined(AUTHENTICATION) 753 case TELOPT_AUTHENTICATION: 754 auth_finished(0, AUTH_REJECT); 755 break; 756#endif 757 758 /* 759 * For options that we might spin waiting for 760 * sub-negotiation, if the client turns off the 761 * option rather than responding to the request, 762 * we have to treat it here as if we got a response 763 * to the sub-negotiation, (by updating the timers) 764 * so that we'll break out of the loop. 765 */ 766 case TELOPT_TTYPE: 767 settimer(ttypesubopt); 768 break; 769 770 case TELOPT_TSPEED: 771 settimer(tspeedsubopt); 772 break; 773 774 case TELOPT_XDISPLOC: 775 settimer(xdisplocsubopt); 776 break; 777 778 case TELOPT_OLD_ENVIRON: 779 settimer(oenvironsubopt); 780 break; 781 782 case TELOPT_NEW_ENVIRON: 783 settimer(environsubopt); 784 break; 785 786 default: 787 break; 788 } 789 set_his_want_state_wont(option); 790 if (his_state_is_will(option)) 791 send_dont(option, 0); 792 } else { 793 switch (option) { 794 case TELOPT_TM: 795#if defined(LINEMODE) && defined(KLUDGELINEMODE) 796 if (lmodetype < NO_AUTOKLUDGE) { 797 lmodetype = NO_LINEMODE; 798 clientstat(TELOPT_LINEMODE, WONT, 0); 799 send_will(TELOPT_SGA, 1); 800 send_will(TELOPT_ECHO, 1); 801 } 802#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 803 break; 804 805#if defined(AUTHENTICATION) 806 case TELOPT_AUTHENTICATION: 807 auth_finished(0, AUTH_REJECT); 808 break; 809#endif 810 default: 811 break; 812 } 813 } 814 } 815 set_his_state_wont(option); 816 817} /* end of wontoption */ 818 819 void 820send_will(option, init) 821 int option, init; 822{ 823 if (init) { 824 if ((will_wont_resp[option] == 0 && my_state_is_will(option))|| 825 my_want_state_is_will(option)) 826 return; 827 set_my_want_state_will(option); 828 will_wont_resp[option]++; 829 } 830 output_data((const char *)will, option); 831 832 DIAG(TD_OPTIONS, printoption("td: send will", option)); 833} 834 835#if !defined(LINEMODE) || !defined(KLUDGELINEMODE) 836/* 837 * When we get a DONT SGA, we will try once to turn it 838 * back on. If the other side responds DONT SGA, we 839 * leave it at that. This is so that when we talk to 840 * clients that understand KLUDGELINEMODE but not LINEMODE, 841 * we'll keep them in char-at-a-time mode. 842 */ 843int turn_on_sga = 0; 844#endif 845 846 void 847dooption(option) 848 int option; 849{ 850 int changeok = 0; 851 852 /* 853 * Process client input. 854 */ 855 856 DIAG(TD_OPTIONS, printoption("td: recv do", option)); 857 858 if (will_wont_resp[option]) { 859 will_wont_resp[option]--; 860 if (will_wont_resp[option] && my_state_is_will(option)) 861 will_wont_resp[option]--; 862 } 863 if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) { 864 switch (option) { 865 case TELOPT_ECHO: 866#ifdef LINEMODE 867# ifdef KLUDGELINEMODE 868 if (lmodetype == NO_LINEMODE) 869# else 870 if (his_state_is_wont(TELOPT_LINEMODE)) 871# endif 872#endif 873 { 874 init_termbuf(); 875 tty_setecho(1); 876 set_termbuf(); 877 } 878 changeok++; 879 break; 880 881 case TELOPT_BINARY: 882 init_termbuf(); 883 tty_binaryout(1); 884 set_termbuf(); 885 changeok++; 886 break; 887 888 case TELOPT_SGA: 889#if defined(LINEMODE) && defined(KLUDGELINEMODE) 890 /* 891 * If kludge linemode is in use, then we must 892 * process an incoming do SGA for linemode 893 * purposes. 894 */ 895 if (lmodetype == KLUDGE_LINEMODE) { 896 /* 897 * Receipt of "do SGA" in kludge 898 * linemode is the peer asking us to 899 * turn off linemode. Make note of 900 * the request. 901 */ 902 clientstat(TELOPT_LINEMODE, WONT, 0); 903 /* 904 * If linemode did not get turned off 905 * then don't tell peer that we did. 906 * Breaking here forces a wont SGA to 907 * be returned. 908 */ 909 if (linemode) 910 break; 911 } 912#else 913 turn_on_sga = 0; 914#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 915 changeok++; 916 break; 917 918 case TELOPT_STATUS: 919 changeok++; 920 break; 921 922 case TELOPT_TM: 923 /* 924 * Special case for TM. We send a WILL, but 925 * pretend we sent a WONT. 926 */ 927 send_will(option, 0); 928 set_my_want_state_wont(option); 929 set_my_state_wont(option); 930 return; 931 932 case TELOPT_LOGOUT: 933 /* 934 * When we get a LOGOUT option, respond 935 * with a WILL LOGOUT, make sure that 936 * it gets written out to the network, 937 * and then just go away... 938 */ 939 set_my_want_state_will(TELOPT_LOGOUT); 940 send_will(TELOPT_LOGOUT, 0); 941 set_my_state_will(TELOPT_LOGOUT); 942 (void)netflush(); 943 cleanup(0); 944 /* NOT REACHED */ 945 break; 946 947#ifdef ENCRYPTION 948 case TELOPT_ENCRYPT: 949 changeok++; 950 break; 951#endif /* ENCRYPTION */ 952 case TELOPT_LINEMODE: 953 case TELOPT_TTYPE: 954 case TELOPT_NAWS: 955 case TELOPT_TSPEED: 956 case TELOPT_LFLOW: 957 case TELOPT_XDISPLOC: 958#ifdef TELOPT_ENVIRON 959 case TELOPT_NEW_ENVIRON: 960#endif 961 case TELOPT_OLD_ENVIRON: 962 default: 963 break; 964 } 965 if (changeok) { 966 set_my_want_state_will(option); 967 send_will(option, 0); 968 } else { 969 will_wont_resp[option]++; 970 send_wont(option, 0); 971 } 972 } 973 set_my_state_will(option); 974 975} /* end of dooption */ 976 977 void 978send_wont(option, init) 979 int option, init; 980{ 981 if (init) { 982 if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) || 983 my_want_state_is_wont(option)) 984 return; 985 set_my_want_state_wont(option); 986 will_wont_resp[option]++; 987 } 988 output_data((const char *)wont, option); 989 990 DIAG(TD_OPTIONS, printoption("td: send wont", option)); 991} 992 993 void 994dontoption(option) 995 int option; 996{ 997 /* 998 * Process client input. 999 */ 1000 1001 1002 DIAG(TD_OPTIONS, printoption("td: recv dont", option)); 1003 1004 if (will_wont_resp[option]) { 1005 will_wont_resp[option]--; 1006 if (will_wont_resp[option] && my_state_is_wont(option)) 1007 will_wont_resp[option]--; 1008 } 1009 if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) { 1010 switch (option) { 1011 case TELOPT_BINARY: 1012 init_termbuf(); 1013 tty_binaryout(0); 1014 set_termbuf(); 1015 break; 1016 1017 case TELOPT_ECHO: /* we should stop echoing */ 1018#ifdef LINEMODE 1019# ifdef KLUDGELINEMODE 1020 if ((lmodetype != REAL_LINEMODE) && 1021 (lmodetype != KLUDGE_LINEMODE)) 1022# else 1023 if (his_state_is_wont(TELOPT_LINEMODE)) 1024# endif 1025#endif 1026 { 1027 init_termbuf(); 1028 tty_setecho(0); 1029 set_termbuf(); 1030 } 1031 break; 1032 1033 case TELOPT_SGA: 1034#if defined(LINEMODE) && defined(KLUDGELINEMODE) 1035 /* 1036 * If kludge linemode is in use, then we 1037 * must process an incoming do SGA for 1038 * linemode purposes. 1039 */ 1040 if ((lmodetype == KLUDGE_LINEMODE) || 1041 (lmodetype == KLUDGE_OK)) { 1042 /* 1043 * The client is asking us to turn 1044 * linemode on. 1045 */ 1046 lmodetype = KLUDGE_LINEMODE; 1047 clientstat(TELOPT_LINEMODE, WILL, 0); 1048 /* 1049 * If we did not turn line mode on, 1050 * then what do we say? Will SGA? 1051 * This violates design of telnet. 1052 * Gross. Very Gross. 1053 */ 1054 } 1055 break; 1056#else 1057 set_my_want_state_wont(option); 1058 if (my_state_is_will(option)) 1059 send_wont(option, 0); 1060 set_my_state_wont(option); 1061 if (turn_on_sga ^= 1) 1062 send_will(option, 1); 1063 return; 1064#endif /* defined(LINEMODE) && defined(KLUDGELINEMODE) */ 1065 1066 default: 1067 break; 1068 } 1069 1070 set_my_want_state_wont(option); 1071 if (my_state_is_will(option)) 1072 send_wont(option, 0); 1073 } 1074 set_my_state_wont(option); 1075 1076} /* end of dontoption */ 1077 1078#ifdef ENV_HACK 1079int env_ovar = -1; 1080int env_ovalue = -1; 1081#else /* ENV_HACK */ 1082# define env_ovar OLD_ENV_VAR 1083# define env_ovalue OLD_ENV_VALUE 1084#endif /* ENV_HACK */ 1085 1086/* 1087 * suboption() 1088 * 1089 * Look at the sub-option buffer, and try to be helpful to the other 1090 * side. 1091 * 1092 * Currently we recognize: 1093 * 1094 * Terminal type is 1095 * Linemode 1096 * Window size 1097 * Terminal speed 1098 */ 1099 void 1100suboption() 1101{ 1102 register int subchar; 1103 1104 DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);}); 1105 1106 subchar = SB_GET(); 1107 switch (subchar) { 1108 case TELOPT_TSPEED: { 1109 register int xspeed, rspeed; 1110 1111 if (his_state_is_wont(TELOPT_TSPEED)) /* Ignore if option disabled */ 1112 break; 1113 1114 settimer(tspeedsubopt); 1115 1116 if (SB_EOF() || SB_GET() != TELQUAL_IS) 1117 return; 1118 1119 xspeed = atoi((char *)subpointer); 1120 1121 while (SB_GET() != ',' && !SB_EOF()); 1122 if (SB_EOF()) 1123 return; 1124 1125 rspeed = atoi((char *)subpointer); 1126 clientstat(TELOPT_TSPEED, xspeed, rspeed); 1127 1128 break; 1129 1130 } /* end of case TELOPT_TSPEED */ 1131 1132 case TELOPT_TTYPE: { /* Yaaaay! */ 1133 static char terminalname[41]; 1134 1135 if (his_state_is_wont(TELOPT_TTYPE)) /* Ignore if option disabled */ 1136 break; 1137 settimer(ttypesubopt); 1138 1139 if (SB_EOF() || SB_GET() != TELQUAL_IS) { 1140 return; /* ??? XXX but, this is the most robust */ 1141 } 1142 1143 terminaltype = terminalname; 1144 1145 while ((terminaltype < (terminalname + sizeof terminalname-1)) && 1146 !SB_EOF()) { 1147 register int c; 1148 1149 c = SB_GET(); 1150 if (isupper(c)) { 1151 c = tolower(c); 1152 } 1153 *terminaltype++ = c; /* accumulate name */ 1154 } 1155 *terminaltype = 0; 1156 terminaltype = terminalname; 1157 break; 1158 } /* end of case TELOPT_TTYPE */ 1159 1160 case TELOPT_NAWS: { 1161 register int xwinsize, ywinsize; 1162 1163 if (his_state_is_wont(TELOPT_NAWS)) /* Ignore if option disabled */ 1164 break; 1165 1166 if (SB_EOF()) 1167 return; 1168 xwinsize = SB_GET() << 8; 1169 if (SB_EOF()) 1170 return; 1171 xwinsize |= SB_GET(); 1172 if (SB_EOF()) 1173 return; 1174 ywinsize = SB_GET() << 8; 1175 if (SB_EOF()) 1176 return; 1177 ywinsize |= SB_GET(); 1178 clientstat(TELOPT_NAWS, xwinsize, ywinsize); 1179 1180 break; 1181 1182 } /* end of case TELOPT_NAWS */ 1183 1184#ifdef LINEMODE 1185 case TELOPT_LINEMODE: { 1186 register int request; 1187 1188 if (his_state_is_wont(TELOPT_LINEMODE)) /* Ignore if option disabled */ 1189 break; 1190 /* 1191 * Process linemode suboptions. 1192 */ 1193 if (SB_EOF()) 1194 break; /* garbage was sent */ 1195 request = SB_GET(); /* get will/wont */ 1196 1197 if (SB_EOF()) 1198 break; /* another garbage check */ 1199 1200 if (request == LM_SLC) { /* SLC is not preceeded by WILL or WONT */ 1201 /* 1202 * Process suboption buffer of slc's 1203 */ 1204 start_slc(1); 1205 do_opt_slc(subpointer, subend - subpointer); 1206 (void) end_slc(0); 1207 break; 1208 } else if (request == LM_MODE) { 1209 if (SB_EOF()) 1210 return; 1211 useeditmode = SB_GET(); /* get mode flag */ 1212 clientstat(LM_MODE, 0, 0); 1213 break; 1214 } 1215 1216 if (SB_EOF()) 1217 break; 1218 switch (SB_GET()) { /* what suboption? */ 1219 case LM_FORWARDMASK: 1220 /* 1221 * According to spec, only server can send request for 1222 * forwardmask, and client can only return a positive response. 1223 * So don't worry about it. 1224 */ 1225 1226 default: 1227 break; 1228 } 1229 break; 1230 } /* end of case TELOPT_LINEMODE */ 1231#endif 1232 case TELOPT_STATUS: { 1233 int mode; 1234 1235 if (SB_EOF()) 1236 break; 1237 mode = SB_GET(); 1238 switch (mode) { 1239 case TELQUAL_SEND: 1240 if (my_state_is_will(TELOPT_STATUS)) 1241 send_status(); 1242 break; 1243 1244 case TELQUAL_IS: 1245 break; 1246 1247 default: 1248 break; 1249 } 1250 break; 1251 } /* end of case TELOPT_STATUS */ 1252 1253 case TELOPT_XDISPLOC: { 1254 if (SB_EOF() || SB_GET() != TELQUAL_IS) 1255 return; 1256 settimer(xdisplocsubopt); 1257 subpointer[SB_LEN()] = '\0'; 1258 (void)setenv("DISPLAY", (char *)subpointer, 1); 1259 break; 1260 } /* end of case TELOPT_XDISPLOC */ 1261 1262#ifdef TELOPT_NEW_ENVIRON 1263 case TELOPT_NEW_ENVIRON: 1264#endif 1265 case TELOPT_OLD_ENVIRON: { 1266 register int c; 1267 register char *cp, *varp, *valp; 1268 1269 if (SB_EOF()) 1270 return; 1271 c = SB_GET(); 1272 if (c == TELQUAL_IS) { 1273 if (subchar == TELOPT_OLD_ENVIRON) 1274 settimer(oenvironsubopt); 1275 else 1276 settimer(environsubopt); 1277 } else if (c != TELQUAL_INFO) { 1278 return; 1279 } 1280 1281#ifdef TELOPT_NEW_ENVIRON 1282 if (subchar == TELOPT_NEW_ENVIRON) { 1283 while (!SB_EOF()) { 1284 c = SB_GET(); 1285 if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR)) 1286 break; 1287 } 1288 } else 1289#endif 1290 { 1291#ifdef ENV_HACK 1292 /* 1293 * We only want to do this if we haven't already decided 1294 * whether or not the other side has its VALUE and VAR 1295 * reversed. 1296 */ 1297 if (env_ovar < 0) { 1298 register int last = -1; /* invalid value */ 1299 int empty = 0; 1300 int got_var = 0, got_value = 0, got_uservar = 0; 1301 1302 /* 1303 * The other side might have its VALUE and VAR values 1304 * reversed. To be interoperable, we need to determine 1305 * which way it is. If the first recognized character 1306 * is a VAR or VALUE, then that will tell us what 1307 * type of client it is. If the fist recognized 1308 * character is a USERVAR, then we continue scanning 1309 * the suboption looking for two consecutive 1310 * VAR or VALUE fields. We should not get two 1311 * consecutive VALUE fields, so finding two 1312 * consecutive VALUE or VAR fields will tell us 1313 * what the client is. 1314 */ 1315 SB_SAVE(); 1316 while (!SB_EOF()) { 1317 c = SB_GET(); 1318 switch(c) { 1319 case OLD_ENV_VAR: 1320 if (last < 0 || last == OLD_ENV_VAR 1321 || (empty && (last == OLD_ENV_VALUE))) 1322 goto env_ovar_ok; 1323 got_var++; 1324 last = OLD_ENV_VAR; 1325 break; 1326 case OLD_ENV_VALUE: 1327 if (last < 0 || last == OLD_ENV_VALUE 1328 || (empty && (last == OLD_ENV_VAR))) 1329 goto env_ovar_wrong; 1330 got_value++; 1331 last = OLD_ENV_VALUE; 1332 break; 1333 case ENV_USERVAR: 1334 /* count strings of USERVAR as one */ 1335 if (last != ENV_USERVAR) 1336 got_uservar++; 1337 if (empty) { 1338 if (last == OLD_ENV_VALUE) 1339 goto env_ovar_ok; 1340 if (last == OLD_ENV_VAR) 1341 goto env_ovar_wrong; 1342 } 1343 last = ENV_USERVAR; 1344 break; 1345 case ENV_ESC: 1346 if (!SB_EOF()) 1347 c = SB_GET(); 1348 /* FALL THROUGH */ 1349 default: 1350 empty = 0; 1351 continue; 1352 } 1353 empty = 1; 1354 } 1355 if (empty) { 1356 if (last == OLD_ENV_VALUE) 1357 goto env_ovar_ok; 1358 if (last == OLD_ENV_VAR) 1359 goto env_ovar_wrong; 1360 } 1361 /* 1362 * Ok, the first thing was a USERVAR, and there 1363 * are not two consecutive VAR or VALUE commands, 1364 * and none of the VAR or VALUE commands are empty. 1365 * If the client has sent us a well-formed option, 1366 * then the number of VALUEs received should always 1367 * be less than or equal to the number of VARs and 1368 * USERVARs received. 1369 * 1370 * If we got exactly as many VALUEs as VARs and 1371 * USERVARs, the client has the same definitions. 1372 * 1373 * If we got exactly as many VARs as VALUEs and 1374 * USERVARS, the client has reversed definitions. 1375 */ 1376 if (got_uservar + got_var == got_value) { 1377 env_ovar_ok: 1378 env_ovar = OLD_ENV_VAR; 1379 env_ovalue = OLD_ENV_VALUE; 1380 } else if (got_uservar + got_value == got_var) { 1381 env_ovar_wrong: 1382 env_ovar = OLD_ENV_VALUE; 1383 env_ovalue = OLD_ENV_VAR; 1384 DIAG(TD_OPTIONS, 1385 output_data("ENVIRON VALUE and VAR are reversed!\r\n")); 1386 1387 } 1388 } 1389 SB_RESTORE(); 1390#endif 1391 1392 while (!SB_EOF()) { 1393 c = SB_GET(); 1394 if ((c == env_ovar) || (c == ENV_USERVAR)) 1395 break; 1396 } 1397 } 1398 1399 if (SB_EOF()) 1400 return; 1401 1402 cp = varp = (char *)subpointer; 1403 valp = 0; 1404 1405 while (!SB_EOF()) { 1406 c = SB_GET(); 1407 if (subchar == TELOPT_OLD_ENVIRON) { 1408 if (c == env_ovar) 1409 c = NEW_ENV_VAR; 1410 else if (c == env_ovalue) 1411 c = NEW_ENV_VALUE; 1412 } 1413 switch (c) { 1414 1415 case NEW_ENV_VALUE: 1416 *cp = '\0'; 1417 cp = valp = (char *)subpointer; 1418 break; 1419 1420 case NEW_ENV_VAR: 1421 case ENV_USERVAR: 1422 *cp = '\0'; 1423 if (valp) 1424 (void)setenv(varp, valp, 1); 1425 else 1426 unsetenv(varp); 1427 cp = varp = (char *)subpointer; 1428 valp = 0; 1429 break; 1430 1431 case ENV_ESC: 1432 if (SB_EOF()) 1433 break; 1434 c = SB_GET(); 1435 /* FALL THROUGH */ 1436 default: 1437 *cp++ = c; 1438 break; 1439 } 1440 } 1441 *cp = '\0'; 1442 if (valp) 1443 (void)setenv(varp, valp, 1); 1444 else 1445 unsetenv(varp); 1446 break; 1447 } /* end of case TELOPT_NEW_ENVIRON */ 1448#if defined(AUTHENTICATION) 1449 case TELOPT_AUTHENTICATION: 1450 if (SB_EOF()) 1451 break; 1452 switch(SB_GET()) { 1453 case TELQUAL_SEND: 1454 case TELQUAL_REPLY: 1455 /* 1456 * These are sent by us and cannot be sent by 1457 * the client. 1458 */ 1459 break; 1460 case TELQUAL_IS: 1461 auth_is(subpointer, SB_LEN()); 1462 break; 1463 case TELQUAL_NAME: 1464 auth_name(subpointer, SB_LEN()); 1465 break; 1466 } 1467 break; 1468#endif 1469#ifdef ENCRYPTION 1470 case TELOPT_ENCRYPT: 1471 if (SB_EOF()) 1472 break; 1473 switch(SB_GET()) { 1474 case ENCRYPT_SUPPORT: 1475 encrypt_support(subpointer, SB_LEN()); 1476 break; 1477 case ENCRYPT_IS: 1478 encrypt_is(subpointer, SB_LEN()); 1479 break; 1480 case ENCRYPT_REPLY: 1481 encrypt_reply(subpointer, SB_LEN()); 1482 break; 1483 case ENCRYPT_START: 1484 encrypt_start(subpointer, SB_LEN()); 1485 break; 1486 case ENCRYPT_END: 1487 encrypt_end(); 1488 break; 1489 case ENCRYPT_REQSTART: 1490 encrypt_request_start(subpointer, SB_LEN()); 1491 break; 1492 case ENCRYPT_REQEND: 1493 /* 1494 * We can always send an REQEND so that we cannot 1495 * get stuck encrypting. We should only get this 1496 * if we have been able to get in the correct mode 1497 * anyhow. 1498 */ 1499 encrypt_request_end(); 1500 break; 1501 case ENCRYPT_ENC_KEYID: 1502 encrypt_enc_keyid(subpointer, SB_LEN()); 1503 break; 1504 case ENCRYPT_DEC_KEYID: 1505 encrypt_dec_keyid(subpointer, SB_LEN()); 1506 break; 1507 default: 1508 break; 1509 } 1510 break; 1511#endif /* ENCRYPTION */ 1512 1513 default: 1514 break; 1515 } /* end of switch */ 1516 1517} /* end of suboption */ 1518 1519 void 1520doclientstat() 1521{ 1522 clientstat(TELOPT_LINEMODE, WILL, 0); 1523} 1524 1525#define ADD(c) *ncp++ = c 1526#define ADD_DATA(c) { *ncp++ = c; if (c == SE || c == IAC) *ncp++ = c; } 1527 void 1528send_status() 1529{ 1530 unsigned char statusbuf[256]; 1531 register unsigned char *ncp; 1532 register unsigned char i; 1533 1534 ncp = statusbuf; 1535 1536 netflush(); /* get rid of anything waiting to go out */ 1537 1538 ADD(IAC); 1539 ADD(SB); 1540 ADD(TELOPT_STATUS); 1541 ADD(TELQUAL_IS); 1542 1543 /* 1544 * We check the want_state rather than the current state, 1545 * because if we received a DO/WILL for an option that we 1546 * don't support, and the other side didn't send a DONT/WONT 1547 * in response to our WONT/DONT, then the "state" will be 1548 * WILL/DO, and the "want_state" will be WONT/DONT. We 1549 * need to go by the latter. 1550 */ 1551 for (i = 0; i < (unsigned char)NTELOPTS; i++) { 1552 if (my_want_state_is_will(i)) { 1553 ADD(WILL); 1554 ADD_DATA(i);
|
| 1555 if (i == IAC) 1556 ADD(IAC);
|
1554 } 1555 if (his_want_state_is_will(i)) { 1556 ADD(DO); 1557 ADD_DATA(i);
| 1557 } 1558 if (his_want_state_is_will(i)) { 1559 ADD(DO); 1560 ADD_DATA(i);
|
| 1561 if (i == IAC) 1562 ADD(IAC);
|
1558 } 1559 } 1560 1561 if (his_want_state_is_will(TELOPT_LFLOW)) { 1562 ADD(SB); 1563 ADD(TELOPT_LFLOW); 1564 if (flowmode) { 1565 ADD(LFLOW_ON); 1566 } else { 1567 ADD(LFLOW_OFF); 1568 } 1569 ADD(SE); 1570 1571 if (restartany >= 0) { 1572 ADD(SB); 1573 ADD(TELOPT_LFLOW); 1574 if (restartany) { 1575 ADD(LFLOW_RESTART_ANY); 1576 } else { 1577 ADD(LFLOW_RESTART_XON); 1578 } 1579 ADD(SE); 1580 } 1581 } 1582 1583#ifdef LINEMODE 1584 if (his_want_state_is_will(TELOPT_LINEMODE)) { 1585 unsigned char *cp, *cpe; 1586 int len; 1587 1588 ADD(SB); 1589 ADD(TELOPT_LINEMODE); 1590 ADD(LM_MODE); 1591 ADD_DATA(editmode); 1592 ADD(SE); 1593 1594 ADD(SB); 1595 ADD(TELOPT_LINEMODE); 1596 ADD(LM_SLC); 1597 start_slc(0); 1598 send_slc(); 1599 len = end_slc(&cp); 1600 for (cpe = cp + len; cp < cpe; cp++) 1601 ADD_DATA(*cp); 1602 ADD(SE); 1603 } 1604#endif /* LINEMODE */ 1605 1606 ADD(IAC); 1607 ADD(SE); 1608 1609 output_datalen(statusbuf, ncp - statusbuf); 1610 netflush(); /* Send it on its way */ 1611 1612 DIAG(TD_OPTIONS, 1613 {printsub('>', statusbuf, ncp - statusbuf); netflush();}); 1614} 1615 1616/* 1617 * This function appends data to nfrontp and advances nfrontp. 1618 * Returns the number of characters written altogether (the 1619 * buffer may have been flushed in the process). 1620 */ 1621 1622int 1623output_data(const char *format, ...) 1624{ 1625 va_list args; 1626 int len; 1627 char *buf; 1628 1629 va_start(args, format); 1630 if ((len = vasprintf(&buf, format, args)) == -1) 1631 return -1; 1632 output_datalen(buf, len); 1633 va_end(args); 1634 free(buf); 1635 return (len); 1636} 1637 1638void 1639output_datalen(const char *buf, int len) 1640{ 1641 int remaining, copied; 1642 1643 remaining = BUFSIZ - (nfrontp - netobuf); 1644 while (len > 0) { 1645 /* Free up enough space if the room is too low*/ 1646 if ((len > BUFSIZ ? BUFSIZ : len) > remaining) { 1647 netflush(); 1648 remaining = BUFSIZ - (nfrontp - netobuf); 1649 } 1650 1651 /* Copy out as much as will fit */ 1652 copied = remaining > len ? len : remaining; 1653 memmove(nfrontp, buf, copied); 1654 nfrontp += copied; 1655 len -= copied; 1656 remaining -= copied; 1657 buf += copied; 1658 } 1659 return; 1660}
| 1563 } 1564 } 1565 1566 if (his_want_state_is_will(TELOPT_LFLOW)) { 1567 ADD(SB); 1568 ADD(TELOPT_LFLOW); 1569 if (flowmode) { 1570 ADD(LFLOW_ON); 1571 } else { 1572 ADD(LFLOW_OFF); 1573 } 1574 ADD(SE); 1575 1576 if (restartany >= 0) { 1577 ADD(SB); 1578 ADD(TELOPT_LFLOW); 1579 if (restartany) { 1580 ADD(LFLOW_RESTART_ANY); 1581 } else { 1582 ADD(LFLOW_RESTART_XON); 1583 } 1584 ADD(SE); 1585 } 1586 } 1587 1588#ifdef LINEMODE 1589 if (his_want_state_is_will(TELOPT_LINEMODE)) { 1590 unsigned char *cp, *cpe; 1591 int len; 1592 1593 ADD(SB); 1594 ADD(TELOPT_LINEMODE); 1595 ADD(LM_MODE); 1596 ADD_DATA(editmode); 1597 ADD(SE); 1598 1599 ADD(SB); 1600 ADD(TELOPT_LINEMODE); 1601 ADD(LM_SLC); 1602 start_slc(0); 1603 send_slc(); 1604 len = end_slc(&cp); 1605 for (cpe = cp + len; cp < cpe; cp++) 1606 ADD_DATA(*cp); 1607 ADD(SE); 1608 } 1609#endif /* LINEMODE */ 1610 1611 ADD(IAC); 1612 ADD(SE); 1613 1614 output_datalen(statusbuf, ncp - statusbuf); 1615 netflush(); /* Send it on its way */ 1616 1617 DIAG(TD_OPTIONS, 1618 {printsub('>', statusbuf, ncp - statusbuf); netflush();}); 1619} 1620 1621/* 1622 * This function appends data to nfrontp and advances nfrontp. 1623 * Returns the number of characters written altogether (the 1624 * buffer may have been flushed in the process). 1625 */ 1626 1627int 1628output_data(const char *format, ...) 1629{ 1630 va_list args; 1631 int len; 1632 char *buf; 1633 1634 va_start(args, format); 1635 if ((len = vasprintf(&buf, format, args)) == -1) 1636 return -1; 1637 output_datalen(buf, len); 1638 va_end(args); 1639 free(buf); 1640 return (len); 1641} 1642 1643void 1644output_datalen(const char *buf, int len) 1645{ 1646 int remaining, copied; 1647 1648 remaining = BUFSIZ - (nfrontp - netobuf); 1649 while (len > 0) { 1650 /* Free up enough space if the room is too low*/ 1651 if ((len > BUFSIZ ? BUFSIZ : len) > remaining) { 1652 netflush(); 1653 remaining = BUFSIZ - (nfrontp - netobuf); 1654 } 1655 1656 /* Copy out as much as will fit */ 1657 copied = remaining > len ? len : remaining; 1658 memmove(nfrontp, buf, copied); 1659 nfrontp += copied; 1660 len -= copied; 1661 remaining -= copied; 1662 buf += copied; 1663 } 1664 return; 1665}
|