1 /* $NetBSD: telnet.c,v 1.44 2021/10/30 13:43:40 hannken Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)telnet.c 8.4 (Berkeley) 5/30/95"; 36 #else 37 __RCSID("$NetBSD: telnet.c,v 1.44 2021/10/30 13:43:40 hannken Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/param.h> 42 43 #include <signal.h> 44 #include <term.h> 45 #include <unistd.h> 46 /* By the way, we need to include curses.h before telnet.h since, 47 * among other things, telnet.h #defines 'DO', which is a variable 48 * declared in curses.h. 49 */ 50 51 #include <arpa/telnet.h> 52 53 #include <ctype.h> 54 55 #include "ring.h" 56 #include "defines.h" 57 #include "externs.h" 58 #include "types.h" 59 #include "general.h" 60 61 #include <libtelnet/misc.h> 62 #ifdef AUTHENTICATION 63 #include <libtelnet/auth.h> 64 #endif 65 #ifdef ENCRYPTION 66 #include <libtelnet/encrypt.h> 67 #endif 68 69 #define strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x)) 70 71 static unsigned char subbuffer[SUBBUFSIZE], 72 *subpointer, *subend; /* buffer for sub-options */ 73 #define SB_CLEAR() subpointer = subbuffer; 74 #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 75 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ 76 *subpointer++ = (c); \ 77 } 78 79 #define SB_GET() ((*subpointer++)&0xff) 80 #define SB_PEEK() ((*subpointer)&0xff) 81 #define SB_EOF() (subpointer >= subend) 82 #define SB_LEN() (subend - subpointer) 83 84 char options[256]; /* The combined options */ 85 char do_dont_resp[256]; 86 char will_wont_resp[256]; 87 88 int 89 eight = 0, 90 autologin = 0, /* Autologin anyone? */ 91 skiprc = 0, 92 connected, 93 showoptions, 94 ISend, /* trying to send network data in */ 95 telnet_debug = 0, 96 crmod, 97 netdata, /* Print out network data flow */ 98 crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 99 telnetport, 100 SYNCHing, /* we are in TELNET SYNCH mode */ 101 flushout, /* flush output */ 102 autoflush = 0, /* flush output when interrupting? */ 103 autosynch, /* send interrupt characters with SYNCH? */ 104 localflow, /* we handle flow control locally */ 105 restartany, /* if flow control enabled, restart on any character */ 106 localchars, /* we recognize interrupt/quit */ 107 donelclchars, /* the user has set "localchars" */ 108 donebinarytoggle, /* the user has put us in binary */ 109 dontlecho, /* do we suppress local echoing right now? */ 110 globalmode, 111 doaddrlookup = 1, /* do a reverse address lookup? */ 112 clienteof = 0; 113 114 char *prompt = 0; 115 116 cc_t escape; 117 cc_t rlogin; 118 #ifdef KLUDGELINEMODE 119 cc_t echoc; 120 #endif 121 122 /* 123 * Telnet receiver states for fsm 124 */ 125 #define TS_DATA 0 126 #define TS_IAC 1 127 #define TS_WILL 2 128 #define TS_WONT 3 129 #define TS_DO 4 130 #define TS_DONT 5 131 #define TS_CR 6 132 #define TS_SB 7 /* sub-option collection */ 133 #define TS_SE 8 /* looking for sub-option end */ 134 135 static int telrcv_state; 136 # define telopt_environ TELOPT_NEW_ENVIRON 137 138 jmp_buf toplevel = { 0 }; 139 140 int flushline; 141 int linemode; 142 143 #ifdef KLUDGELINEMODE 144 int kludgelinemode = 1; 145 #endif 146 147 static void dooption(int); 148 static void dontoption(int); 149 static void suboption(void); 150 static int telsnd(void); 151 static void netclear(void); 152 static void doflush(void); 153 154 /* 155 * The following are some clocks used to decide how to interpret 156 * the relationship between various variables. 157 */ 158 159 Clocks clocks; 160 161 162 /* 164 * Initialize telnet environment. 165 */ 166 167 void 168 init_telnet(void) 169 { 170 env_init(); 171 172 SB_CLEAR(); 173 ClearArray(options); 174 175 connected = ISend = localflow = donebinarytoggle = 0; 176 #if defined(AUTHENTICATION) || defined(ENCRYPTION) 177 auth_encrypt_connect(connected); 178 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ 179 restartany = -1; 180 181 SYNCHing = 0; 182 183 /* Don't change NetTrace */ 184 185 escape = CONTROL(']'); 186 rlogin = _POSIX_VDISABLE; 187 #ifdef KLUDGELINEMODE 188 echoc = CONTROL('E'); 189 #endif 190 191 flushline = 1; 192 telrcv_state = TS_DATA; 193 } 194 195 197 #ifdef notdef 198 #include <stdarg.h> 199 200 /*VARARGS*/ 201 static void 202 printring(Ring *ring, char *format, ...) 203 va_dcl 204 { 205 va_list ap; 206 char buffer[100]; /* where things go */ 207 char *ptr; 208 char *string; 209 int i; 210 211 va_start(ap, format); 212 213 ptr = buffer; 214 215 while ((i = *format++) != 0) { 216 if (i == '%') { 217 i = *format++; 218 switch (i) { 219 case 'c': 220 *ptr++ = va_arg(ap, int); 221 break; 222 case 's': 223 string = va_arg(ap, char *); 224 ring_supply_data(ring, buffer, ptr-buffer); 225 ring_supply_data(ring, string, strlen(string)); 226 ptr = buffer; 227 break; 228 case 0: 229 ExitString("printring: trailing %%.\n", 1); 230 /*NOTREACHED*/ 231 default: 232 ExitString("printring: unknown format character.\n", 1); 233 /*NOTREACHED*/ 234 } 235 } else { 236 *ptr++ = i; 237 } 238 } 239 va_end(ap); 240 ring_supply_data(ring, buffer, ptr-buffer); 241 } 242 #endif 243 244 /* 245 * These routines are in charge of sending option negotiations 246 * to the other side. 247 * 248 * The basic idea is that we send the negotiation if either side 249 * is in disagreement as to what the current state should be. 250 */ 251 252 void 253 send_do(int c, int init) 254 { 255 if (init) { 256 if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 257 my_want_state_is_do(c)) 258 return; 259 set_my_want_state_do(c); 260 do_dont_resp[c]++; 261 } 262 NET2ADD(IAC, DO); 263 NETADD(c); 264 printoption("SENT", DO, c); 265 } 266 267 void 268 send_dont(int c, int init) 269 { 270 if (init) { 271 if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 272 my_want_state_is_dont(c)) 273 return; 274 set_my_want_state_dont(c); 275 do_dont_resp[c]++; 276 } 277 NET2ADD(IAC, DONT); 278 NETADD(c); 279 printoption("SENT", DONT, c); 280 } 281 282 void 283 send_will(int c, int init) 284 { 285 if (init) { 286 if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 287 my_want_state_is_will(c)) 288 return; 289 set_my_want_state_will(c); 290 will_wont_resp[c]++; 291 } 292 NET2ADD(IAC, WILL); 293 NETADD(c); 294 printoption("SENT", WILL, c); 295 } 296 297 void 298 send_wont(int c, int init) 299 { 300 if (init) { 301 if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 302 my_want_state_is_wont(c)) 303 return; 304 set_my_want_state_wont(c); 305 will_wont_resp[c]++; 306 } 307 NET2ADD(IAC, WONT); 308 NETADD(c); 309 printoption("SENT", WONT, c); 310 } 311 312 313 void 314 willoption(int option) 315 { 316 int new_state_ok = 0; 317 318 if (do_dont_resp[option]) { 319 --do_dont_resp[option]; 320 if (do_dont_resp[option] && my_state_is_do(option)) 321 --do_dont_resp[option]; 322 } 323 324 if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 325 326 switch (option) { 327 328 case TELOPT_ECHO: 329 case TELOPT_BINARY: 330 case TELOPT_SGA: 331 settimer(modenegotiated); 332 /* FALL THROUGH */ 333 case TELOPT_STATUS: 334 #ifdef AUTHENTICATION 335 case TELOPT_AUTHENTICATION: 336 #ifdef ENCRYPTION 337 case TELOPT_ENCRYPT: 338 #endif /* ENCRYPTION */ 339 #endif 340 new_state_ok = 1; 341 break; 342 343 case TELOPT_TM: 344 if (flushout) 345 flushout = 0; 346 /* 347 * Special case for TM. If we get back a WILL, 348 * pretend we got back a WONT. 349 */ 350 set_my_want_state_dont(option); 351 set_my_state_dont(option); 352 return; /* Never reply to TM will's/wont's */ 353 354 case TELOPT_LINEMODE: 355 default: 356 break; 357 } 358 359 if (new_state_ok) { 360 set_my_want_state_do(option); 361 send_do(option, 0); 362 setconnmode(0); /* possibly set new tty mode */ 363 } else { 364 do_dont_resp[option]++; 365 send_dont(option, 0); 366 } 367 } 368 set_my_state_do(option); 369 #ifdef ENCRYPTION 370 if (option == TELOPT_ENCRYPT) 371 encrypt_send_support(); 372 #endif /* ENCRYPTION */ 373 } 374 375 void 376 wontoption(int option) 377 { 378 if (do_dont_resp[option]) { 379 --do_dont_resp[option]; 380 if (do_dont_resp[option] && my_state_is_dont(option)) 381 --do_dont_resp[option]; 382 } 383 384 if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 385 386 switch (option) { 387 388 #ifdef KLUDGELINEMODE 389 case TELOPT_SGA: 390 if (!kludgelinemode) 391 break; 392 /* FALL THROUGH */ 393 #endif 394 case TELOPT_ECHO: 395 settimer(modenegotiated); 396 break; 397 398 case TELOPT_TM: 399 if (flushout) 400 flushout = 0; 401 set_my_want_state_dont(option); 402 set_my_state_dont(option); 403 return; /* Never reply to TM will's/wont's */ 404 405 default: 406 break; 407 } 408 set_my_want_state_dont(option); 409 if (my_state_is_do(option)) 410 send_dont(option, 0); 411 setconnmode(0); /* Set new tty mode */ 412 } else if (option == TELOPT_TM) { 413 /* 414 * Special case for TM. 415 */ 416 if (flushout) 417 flushout = 0; 418 set_my_want_state_dont(option); 419 } 420 set_my_state_dont(option); 421 } 422 423 static void 424 dooption(int option) 425 { 426 int new_state_ok = 0; 427 428 if (will_wont_resp[option]) { 429 --will_wont_resp[option]; 430 if (will_wont_resp[option] && my_state_is_will(option)) 431 --will_wont_resp[option]; 432 } 433 434 if (will_wont_resp[option] == 0) { 435 if (my_want_state_is_wont(option)) { 436 437 switch (option) { 438 439 case TELOPT_TM: 440 /* 441 * Special case for TM. We send a WILL, but pretend 442 * we sent WONT. 443 */ 444 send_will(option, 0); 445 set_my_want_state_wont(TELOPT_TM); 446 set_my_state_wont(TELOPT_TM); 447 return; 448 449 case TELOPT_BINARY: /* binary mode */ 450 case TELOPT_NAWS: /* window size */ 451 case TELOPT_TSPEED: /* terminal speed */ 452 case TELOPT_LFLOW: /* local flow control */ 453 case TELOPT_TTYPE: /* terminal type option */ 454 case TELOPT_SGA: /* no big deal */ 455 #ifdef ENCRYPTION 456 case TELOPT_ENCRYPT: /* encryption variable option */ 457 #endif /* ENCRYPTION */ 458 new_state_ok = 1; 459 break; 460 461 case TELOPT_NEW_ENVIRON: /* New environment variable option */ 462 new_state_ok = 1; 463 break; 464 465 #ifdef AUTHENTICATION 466 case TELOPT_AUTHENTICATION: 467 if (autologin) 468 new_state_ok = 1; 469 break; 470 #endif 471 472 case TELOPT_XDISPLOC: /* X Display location */ 473 if (env_getvalue((const unsigned char *)"DISPLAY")) 474 new_state_ok = 1; 475 break; 476 477 case TELOPT_LINEMODE: 478 #ifdef KLUDGELINEMODE 479 kludgelinemode = 0; 480 send_do(TELOPT_SGA, 1); 481 #endif 482 set_my_want_state_will(TELOPT_LINEMODE); 483 send_will(option, 0); 484 set_my_state_will(TELOPT_LINEMODE); 485 slc_init(); 486 return; 487 488 case TELOPT_ECHO: /* We're never going to echo... */ 489 default: 490 break; 491 } 492 493 if (new_state_ok) { 494 set_my_want_state_will(option); 495 send_will(option, 0); 496 setconnmode(0); /* Set new tty mode */ 497 } else { 498 will_wont_resp[option]++; 499 send_wont(option, 0); 500 } 501 } else { 502 /* 503 * Handle options that need more things done after the 504 * other side has acknowledged the option. 505 */ 506 switch (option) { 507 case TELOPT_LINEMODE: 508 #ifdef KLUDGELINEMODE 509 kludgelinemode = 0; 510 send_do(TELOPT_SGA, 1); 511 #endif 512 set_my_state_will(option); 513 slc_init(); 514 send_do(TELOPT_SGA, 0); 515 return; 516 } 517 } 518 } 519 set_my_state_will(option); 520 } 521 522 static void 523 dontoption(int option) 524 { 525 526 if (will_wont_resp[option]) { 527 --will_wont_resp[option]; 528 if (will_wont_resp[option] && my_state_is_wont(option)) 529 --will_wont_resp[option]; 530 } 531 532 if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 533 switch (option) { 534 case TELOPT_LINEMODE: 535 linemode = 0; /* put us back to the default state */ 536 break; 537 } 538 /* we always accept a DONT */ 539 set_my_want_state_wont(option); 540 if (my_state_is_will(option)) 541 send_wont(option, 0); 542 setconnmode(0); /* Set new tty mode */ 543 } 544 set_my_state_wont(option); 545 } 546 547 /* 548 * Given a buffer returned by tgetent(), this routine will turn 549 * the pipe separated list of names in the buffer into an array 550 * of pointers to null terminated names. We toss out any bad, 551 * duplicate, or verbose names (names with spaces). 552 */ 553 554 static char name_unknown[] = "UNKNOWN"; 555 static char *unknown[] = { 0, 0 }; 556 557 char ** 558 mklist(char *buf, char *name) 559 { 560 int n; 561 char c, *cp, **argvp, *cp2, **argv, **avt; 562 563 if (name) { 564 if ((int)strlen(name) > 40) { 565 name = 0; 566 unknown[0] = name_unknown; 567 } else { 568 unknown[0] = name; 569 upcase(name); 570 } 571 } else 572 unknown[0] = name_unknown; 573 /* 574 * Count up the number of names. 575 */ 576 for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 577 if (*cp == '|') 578 n++; 579 } 580 /* 581 * Allocate an array to put the name pointers into 582 */ 583 argv = NULL; 584 if (reallocarr(&argv, n + 3, sizeof(char *)) != 0) 585 return(unknown); 586 587 /* 588 * Fill up the array of pointers to names. 589 */ 590 *argv = 0; 591 argvp = argv+1; 592 n = 0; 593 for (cp = cp2 = buf; (c = *cp); cp++) { 594 if (c == '|' || c == ':') { 595 *cp++ = '\0'; 596 /* 597 * Skip entries that have spaces or are over 40 598 * characters long. If this is our environment 599 * name, then put it up front. Otherwise, as 600 * long as this is not a duplicate name (case 601 * insensitive) add it to the list. 602 */ 603 if (n || (cp - cp2 > 41)) 604 ; 605 else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 606 *argv = cp2; 607 else if (is_unique(cp2, argv+1, argvp)) 608 *argvp++ = cp2; 609 if (c == ':') 610 break; 611 /* 612 * Skip multiple delimiters. Reset cp2 to 613 * the beginning of the next name. Reset n, 614 * the flag for names with spaces. 615 */ 616 while ((c = *cp) == '|') 617 cp++; 618 cp2 = cp; 619 n = 0; 620 } 621 /* 622 * Skip entries with spaces or non-ascii values. 623 * Convert lower case letters to upper case. 624 */ 625 if ((c == ' ') || !isascii(c)) 626 n = 1; 627 else if (islower((unsigned char)c)) 628 *cp = toupper((unsigned char)c); 629 } 630 631 /* 632 * Check for an old V6 2 character name. If the second 633 * name points to the beginning of the buffer, and is 634 * only 2 characters long, move it to the end of the array. 635 */ 636 if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 637 --argvp; 638 for (avt = &argv[1]; avt < argvp; avt++) 639 *avt = *(avt+1); 640 *argvp++ = buf; 641 } 642 643 /* 644 * Duplicate last name, for TTYPE option, and null 645 * terminate the array. If we didn't find a match on 646 * our terminal name, put that name at the beginning. 647 */ 648 cp = *(argvp-1); 649 *argvp++ = cp; 650 *argvp = 0; 651 652 if (*argv == 0) { 653 if (name) 654 *argv = name; 655 else { 656 --argvp; 657 for (avt = argv; avt < argvp; avt++) 658 *avt = *(avt+1); 659 } 660 } 661 if (*argv) 662 return(argv); 663 else 664 return(unknown); 665 } 666 667 int 668 is_unique(char *name, char **as, char **ae) 669 { 670 char **ap; 671 int n; 672 673 n = strlen(name) + 1; 674 for (ap = as; ap < ae; ap++) 675 if (strncasecmp(*ap, name, n) == 0) 676 return(0); 677 return (1); 678 } 679 680 #ifdef TERMCAP 681 char *termbuf; 682 683 /*ARGSUSED*/ 684 int 685 setupterm(char *tname, int fd, int *errp) 686 { 687 char zz[1024], *zz_ptr; 688 char *ext_tc, *newptr; 689 size_t len; 690 691 if ((termbuf = malloc(1024)) == NULL) 692 goto error; 693 694 if (tgetent(termbuf, tname) == 1) { 695 /* check for ZZ capability, indicating termcap truncated */ 696 zz_ptr = zz; 697 if (tgetstr("ZZ", &zz_ptr) != NULL) { 698 /* it was, fish back the full termcap */ 699 sscanf(zz, "%p", &ext_tc); 700 len = strlen(ext_tc) + 1; 701 if ((newptr = realloc(termbuf, len)) == NULL) 702 goto error; 703 704 memcpy(newptr, ext_tc, len); 705 termbuf = newptr; 706 } 707 708 if (errp) 709 *errp = 1; 710 return(0); 711 } 712 error: 713 if (errp) 714 *errp = 0; 715 return(-1); 716 } 717 #else 718 #define termbuf ttytype 719 extern char ttytype[]; 720 #endif 721 722 int resettermname = 1; 723 724 char * 725 gettermname(void) 726 { 727 char *tname; 728 static char **tnamep = 0; 729 static char **next; 730 int err; 731 732 if (resettermname) { 733 resettermname = 0; 734 if (tnamep && tnamep != unknown) 735 free(tnamep); 736 if ((tname = (char *)env_getvalue((const unsigned char *)"TERM")) && 737 (setupterm(tname, 1, &err) == 0)) { 738 tnamep = mklist(termbuf, tname); 739 } else { 740 if (tname && ((int)strlen(tname) <= 40)) { 741 unknown[0] = tname; 742 upcase(tname); 743 } else 744 unknown[0] = name_unknown; 745 tnamep = unknown; 746 } 747 next = tnamep; 748 } 749 if (*next == 0) 750 next = tnamep; 751 return(*next++); 752 } 753 /* 754 * suboption() 755 * 756 * Look at the sub-option buffer, and try to be helpful to the other 757 * side. 758 * 759 * Currently we recognize: 760 * 761 * Terminal type, send request. 762 * Terminal speed (send request). 763 * Local flow control (is request). 764 * Linemode 765 */ 766 767 static void 768 suboption(void) 769 { 770 unsigned char subchar; 771 772 printsub('<', subbuffer, SB_LEN()+2); 773 switch (subchar = SB_GET()) { 774 case TELOPT_TTYPE: 775 if (my_want_state_is_wont(TELOPT_TTYPE)) 776 return; 777 if (SB_EOF() || SB_GET() != TELQUAL_SEND) { 778 return; 779 } else { 780 char *name; 781 unsigned char temp[50]; 782 int len; 783 784 name = gettermname(); 785 len = strlen(name) + 4 + 2; 786 if (len < NETROOM()) { 787 snprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, 788 TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE); 789 ring_supply_data(&netoring, temp, len); 790 printsub('>', &temp[2], len-2); 791 } else { 792 ExitString("No room in buffer for terminal type.\n", 1); 793 /*NOTREACHED*/ 794 } 795 } 796 break; 797 case TELOPT_TSPEED: 798 if (my_want_state_is_wont(TELOPT_TSPEED)) 799 return; 800 if (SB_EOF()) 801 return; 802 if (SB_GET() == TELQUAL_SEND) { 803 long osp, isp; 804 unsigned char temp[50]; 805 int len; 806 807 TerminalSpeeds(&isp, &osp); 808 809 snprintf((char *)temp, sizeof(temp), "%c%c%c%c%ld,%ld%c%c", IAC, SB, 810 TELOPT_TSPEED, TELQUAL_IS, osp, isp, IAC, SE); 811 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 812 813 if (len < NETROOM()) { 814 ring_supply_data(&netoring, temp, len); 815 printsub('>', temp+2, len - 2); 816 } 817 /*@*/ else printf("lm_will: not enough room in buffer\n"); 818 } 819 break; 820 case TELOPT_LFLOW: 821 if (my_want_state_is_wont(TELOPT_LFLOW)) 822 return; 823 if (SB_EOF()) 824 return; 825 switch(SB_GET()) { 826 case LFLOW_RESTART_ANY: 827 restartany = 1; 828 break; 829 case LFLOW_RESTART_XON: 830 restartany = 0; 831 break; 832 case LFLOW_ON: 833 localflow = 1; 834 break; 835 case LFLOW_OFF: 836 localflow = 0; 837 break; 838 default: 839 return; 840 } 841 setcommandmode(); 842 setconnmode(0); 843 break; 844 845 case TELOPT_LINEMODE: 846 if (my_want_state_is_wont(TELOPT_LINEMODE)) 847 return; 848 if (SB_EOF()) 849 return; 850 switch (SB_GET()) { 851 case WILL: 852 lm_will(subpointer, SB_LEN()); 853 break; 854 case WONT: 855 lm_wont(subpointer, SB_LEN()); 856 break; 857 case DO: 858 lm_do(subpointer, SB_LEN()); 859 break; 860 case DONT: 861 lm_dont(subpointer, SB_LEN()); 862 break; 863 case LM_SLC: 864 slc(subpointer, SB_LEN()); 865 break; 866 case LM_MODE: 867 lm_mode(subpointer, SB_LEN(), 0); 868 break; 869 default: 870 break; 871 } 872 break; 873 874 case TELOPT_NEW_ENVIRON: 875 if (SB_EOF()) 876 return; 877 switch(SB_PEEK()) { 878 case TELQUAL_IS: 879 case TELQUAL_INFO: 880 if (my_want_state_is_dont(subchar)) 881 return; 882 break; 883 case TELQUAL_SEND: 884 if (my_want_state_is_wont(subchar)) { 885 return; 886 } 887 break; 888 default: 889 return; 890 } 891 env_opt(subpointer, SB_LEN()); 892 break; 893 894 case TELOPT_XDISPLOC: 895 if (my_want_state_is_wont(TELOPT_XDISPLOC)) 896 return; 897 if (SB_EOF()) 898 return; 899 if (SB_GET() == TELQUAL_SEND) { 900 unsigned char temp[50], *dp; 901 int len; 902 903 if ((dp = env_getvalue((const unsigned char *)"DISPLAY")) == NULL) { 904 /* 905 * Something happened, we no longer have a DISPLAY 906 * variable. So, turn off the option. 907 */ 908 send_wont(TELOPT_XDISPLOC, 1); 909 break; 910 } 911 snprintf((char *)temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB, 912 TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); 913 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 914 915 if (len < NETROOM()) { 916 ring_supply_data(&netoring, temp, len); 917 printsub('>', temp+2, len - 2); 918 } 919 /*@*/ else printf("lm_will: not enough room in buffer\n"); 920 } 921 break; 922 923 #ifdef AUTHENTICATION 924 case TELOPT_AUTHENTICATION: { 925 if (!autologin) 926 break; 927 if (SB_EOF()) 928 return; 929 switch(SB_GET()) { 930 case TELQUAL_IS: 931 if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 932 return; 933 auth_is(subpointer, SB_LEN()); 934 break; 935 case TELQUAL_SEND: 936 if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 937 return; 938 auth_send(subpointer, SB_LEN()); 939 break; 940 case TELQUAL_REPLY: 941 if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 942 return; 943 auth_reply(subpointer, SB_LEN()); 944 break; 945 case TELQUAL_NAME: 946 if (my_want_state_is_dont(TELOPT_AUTHENTICATION)) 947 return; 948 auth_name(subpointer, SB_LEN()); 949 break; 950 } 951 } 952 break; 953 #endif 954 #ifdef ENCRYPTION 955 case TELOPT_ENCRYPT: 956 if (SB_EOF()) 957 return; 958 switch(SB_GET()) { 959 case ENCRYPT_START: 960 if (my_want_state_is_dont(TELOPT_ENCRYPT)) 961 return; 962 encrypt_start(subpointer, SB_LEN()); 963 break; 964 case ENCRYPT_END: 965 if (my_want_state_is_dont(TELOPT_ENCRYPT)) 966 return; 967 encrypt_end(); 968 break; 969 case ENCRYPT_SUPPORT: 970 if (my_want_state_is_wont(TELOPT_ENCRYPT)) 971 return; 972 encrypt_support(subpointer, SB_LEN()); 973 break; 974 case ENCRYPT_REQSTART: 975 if (my_want_state_is_wont(TELOPT_ENCRYPT)) 976 return; 977 encrypt_request_start(subpointer, SB_LEN()); 978 break; 979 case ENCRYPT_REQEND: 980 if (my_want_state_is_wont(TELOPT_ENCRYPT)) 981 return; 982 /* 983 * We can always send an REQEND so that we cannot 984 * get stuck encrypting. We should only get this 985 * if we have been able to get in the correct mode 986 * anyhow. 987 */ 988 encrypt_request_end(); 989 break; 990 case ENCRYPT_IS: 991 if (my_want_state_is_dont(TELOPT_ENCRYPT)) 992 return; 993 encrypt_is(subpointer, SB_LEN()); 994 break; 995 case ENCRYPT_REPLY: 996 if (my_want_state_is_wont(TELOPT_ENCRYPT)) 997 return; 998 encrypt_reply(subpointer, SB_LEN()); 999 break; 1000 case ENCRYPT_ENC_KEYID: 1001 if (my_want_state_is_dont(TELOPT_ENCRYPT)) 1002 return; 1003 encrypt_enc_keyid(subpointer, SB_LEN()); 1004 break; 1005 case ENCRYPT_DEC_KEYID: 1006 if (my_want_state_is_wont(TELOPT_ENCRYPT)) 1007 return; 1008 encrypt_dec_keyid(subpointer, SB_LEN()); 1009 break; 1010 default: 1011 break; 1012 } 1013 break; 1014 #endif /* ENCRYPTION */ 1015 default: 1016 break; 1017 } 1018 } 1019 1020 static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 1021 1022 void 1023 lm_will(unsigned char *cmd, int len) 1024 { 1025 if (len < 1) { 1026 /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */ 1027 return; 1028 } 1029 switch(cmd[0]) { 1030 case LM_FORWARDMASK: /* We shouldn't ever get this... */ 1031 default: 1032 str_lm[3] = DONT; 1033 str_lm[4] = cmd[0]; 1034 if ((size_t)NETROOM() > sizeof(str_lm)) { 1035 ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 1036 printsub('>', &str_lm[2], sizeof(str_lm)-2); 1037 } 1038 /*@*/ else printf("lm_will: not enough room in buffer\n"); 1039 break; 1040 } 1041 } 1042 1043 void 1044 lm_wont(unsigned char *cmd, int len) 1045 { 1046 if (len < 1) { 1047 /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */ 1048 return; 1049 } 1050 switch(cmd[0]) { 1051 case LM_FORWARDMASK: /* We shouldn't ever get this... */ 1052 default: 1053 /* We are always DONT, so don't respond */ 1054 return; 1055 } 1056 } 1057 1058 void 1059 lm_do(unsigned char *cmd, int len) 1060 { 1061 if (len < 1) { 1062 /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */ 1063 return; 1064 } 1065 switch(cmd[0]) { 1066 case LM_FORWARDMASK: 1067 default: 1068 str_lm[3] = WONT; 1069 str_lm[4] = cmd[0]; 1070 if ((size_t)NETROOM() > sizeof(str_lm)) { 1071 ring_supply_data(&netoring, str_lm, sizeof(str_lm)); 1072 printsub('>', &str_lm[2], sizeof(str_lm)-2); 1073 } 1074 /*@*/ else printf("lm_do: not enough room in buffer\n"); 1075 break; 1076 } 1077 } 1078 1079 void 1080 lm_dont(unsigned char *cmd, int len) 1081 { 1082 if (len < 1) { 1083 /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */ 1084 return; 1085 } 1086 switch(cmd[0]) { 1087 case LM_FORWARDMASK: 1088 default: 1089 /* we are always WONT, so don't respond */ 1090 break; 1091 } 1092 } 1093 1094 static unsigned char str_lm_mode[] = { 1095 IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE 1096 }; 1097 1098 void 1099 lm_mode(unsigned char *cmd, int len, int init) 1100 { 1101 if (len != 1) 1102 return; 1103 if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 1104 return; 1105 if (*cmd&MODE_ACK) 1106 return; 1107 linemode = *cmd&(MODE_MASK&~MODE_ACK); 1108 str_lm_mode[4] = linemode; 1109 if (!init) 1110 str_lm_mode[4] |= MODE_ACK; 1111 if ((size_t)NETROOM() > sizeof(str_lm_mode)) { 1112 ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode)); 1113 printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2); 1114 } 1115 /*@*/ else printf("lm_mode: not enough room in buffer\n"); 1116 setconnmode(0); /* set changed mode */ 1117 } 1118 1119 1120 1122 /* 1123 * slc() 1124 * Handle special character suboption of LINEMODE. 1125 */ 1126 1127 struct spc { 1128 cc_t val; 1129 cc_t *valp; 1130 char flags; /* Current flags & level */ 1131 char mylevel; /* Maximum level & flags */ 1132 } spc_data[NSLC+1]; 1133 1134 #define SLC_IMPORT 0 1135 #define SLC_EXPORT 1 1136 #define SLC_RVALUE 2 1137 static int slc_mode = SLC_EXPORT; 1138 1139 void 1140 slc_init(void) 1141 { 1142 struct spc *spcp; 1143 1144 localchars = 1; 1145 for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) { 1146 spcp->val = 0; 1147 spcp->valp = 0; 1148 spcp->flags = spcp->mylevel = SLC_NOSUPPORT; 1149 } 1150 1151 #define initfunc(func, flags) { \ 1152 spcp = &spc_data[func]; \ 1153 if ((spcp->valp = tcval(func)) != NULL){ \ 1154 spcp->val = *spcp->valp; \ 1155 spcp->mylevel = SLC_VARIABLE|flags; \ 1156 } else { \ 1157 spcp->val = 0; \ 1158 spcp->mylevel = SLC_DEFAULT; \ 1159 } \ 1160 } 1161 1162 initfunc(SLC_SYNCH, 0); 1163 /* No BRK */ 1164 initfunc(SLC_AO, 0); 1165 initfunc(SLC_AYT, 0); 1166 /* No EOR */ 1167 initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT); 1168 initfunc(SLC_EOF, 0); 1169 initfunc(SLC_SUSP, SLC_FLUSHIN); 1170 initfunc(SLC_EC, 0); 1171 initfunc(SLC_EL, 0); 1172 initfunc(SLC_EW, 0); 1173 initfunc(SLC_RP, 0); 1174 initfunc(SLC_LNEXT, 0); 1175 initfunc(SLC_XON, 0); 1176 initfunc(SLC_XOFF, 0); 1177 initfunc(SLC_FORW1, 0); 1178 initfunc(SLC_FORW2, 0); 1179 /* No FORW2 */ 1180 1181 initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT); 1182 #undef initfunc 1183 1184 if (slc_mode == SLC_EXPORT) 1185 slc_export(); 1186 else 1187 slc_import(1); 1188 1189 } 1190 1191 void 1192 slcstate(void) 1193 { 1194 printf("Special characters are %s values\n", 1195 slc_mode == SLC_IMPORT ? "remote default" : 1196 slc_mode == SLC_EXPORT ? "local" : 1197 "remote"); 1198 } 1199 1200 void 1201 slc_mode_export(int n) 1202 { 1203 slc_mode = SLC_EXPORT; 1204 if (my_state_is_will(TELOPT_LINEMODE)) 1205 slc_export(); 1206 } 1207 1208 void 1209 slc_mode_import(int def) 1210 { 1211 slc_mode = def ? SLC_IMPORT : SLC_RVALUE; 1212 if (my_state_is_will(TELOPT_LINEMODE)) 1213 slc_import(def); 1214 } 1215 1216 unsigned char slc_import_val[] = { 1217 IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE 1218 }; 1219 unsigned char slc_import_def[] = { 1220 IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE 1221 }; 1222 1223 void 1224 slc_import(int def) 1225 { 1226 if ((size_t)NETROOM() > sizeof(slc_import_val)) { 1227 if (def) { 1228 ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def)); 1229 printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2); 1230 } else { 1231 ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val)); 1232 printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2); 1233 } 1234 } 1235 /*@*/ else printf("slc_import: not enough room\n"); 1236 } 1237 1238 void 1239 slc_export(void) 1240 { 1241 struct spc *spcp; 1242 1243 TerminalDefaultChars(); 1244 1245 slc_start_reply(); 1246 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 1247 if (spcp->mylevel != SLC_NOSUPPORT) { 1248 if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 1249 spcp->flags = SLC_NOSUPPORT; 1250 else 1251 spcp->flags = spcp->mylevel; 1252 if (spcp->valp) 1253 spcp->val = *spcp->valp; 1254 slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 1255 } 1256 } 1257 slc_end_reply(); 1258 (void)slc_update(); 1259 setconnmode(1); /* Make sure the character values are set */ 1260 } 1261 1262 void 1263 slc(unsigned char *cp, int len) 1264 { 1265 struct spc *spcp; 1266 int func,level; 1267 1268 slc_start_reply(); 1269 1270 for (; len >= 3; len -=3, cp +=3) { 1271 1272 func = cp[SLC_FUNC]; 1273 1274 if (func == 0) { 1275 /* 1276 * Client side: always ignore 0 function. 1277 */ 1278 continue; 1279 } 1280 if (func > NSLC) { 1281 if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT) 1282 slc_add_reply(func, SLC_NOSUPPORT, 0); 1283 continue; 1284 } 1285 1286 spcp = &spc_data[func]; 1287 1288 level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK); 1289 1290 if ((cp[SLC_VALUE] == (unsigned char)spcp->val) && 1291 ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) { 1292 continue; 1293 } 1294 1295 if (level == (SLC_DEFAULT|SLC_ACK)) { 1296 /* 1297 * This is an error condition, the SLC_ACK 1298 * bit should never be set for the SLC_DEFAULT 1299 * level. Our best guess to recover is to 1300 * ignore the SLC_ACK bit. 1301 */ 1302 cp[SLC_FLAGS] &= ~SLC_ACK; 1303 } 1304 1305 if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) { 1306 spcp->val = (cc_t)cp[SLC_VALUE]; 1307 spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */ 1308 continue; 1309 } 1310 1311 level &= ~SLC_ACK; 1312 1313 if (level <= (spcp->mylevel&SLC_LEVELBITS)) { 1314 spcp->flags = cp[SLC_FLAGS]|SLC_ACK; 1315 spcp->val = (cc_t)cp[SLC_VALUE]; 1316 } 1317 if (level == SLC_DEFAULT) { 1318 if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT) 1319 spcp->flags = spcp->mylevel; 1320 else 1321 spcp->flags = SLC_NOSUPPORT; 1322 } 1323 slc_add_reply(func, spcp->flags, spcp->val); 1324 } 1325 slc_end_reply(); 1326 if (slc_update()) 1327 setconnmode(1); /* set the new character values */ 1328 } 1329 1330 void 1331 slc_check(void) 1332 { 1333 struct spc *spcp; 1334 1335 slc_start_reply(); 1336 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 1337 if (spcp->valp && spcp->val != *spcp->valp) { 1338 spcp->val = *spcp->valp; 1339 if (spcp->val == (cc_t)(_POSIX_VDISABLE)) 1340 spcp->flags = SLC_NOSUPPORT; 1341 else 1342 spcp->flags = spcp->mylevel; 1343 slc_add_reply(spcp - spc_data, spcp->flags, spcp->val); 1344 } 1345 } 1346 slc_end_reply(); 1347 setconnmode(1); 1348 } 1349 1350 1351 unsigned char slc_reply[128]; 1352 unsigned char *slc_replyp; 1353 1354 void 1355 slc_start_reply(void) 1356 { 1357 slc_replyp = slc_reply; 1358 *slc_replyp++ = IAC; 1359 *slc_replyp++ = SB; 1360 *slc_replyp++ = TELOPT_LINEMODE; 1361 *slc_replyp++ = LM_SLC; 1362 } 1363 1364 void 1365 slc_add_reply(unsigned int func, unsigned int flags, cc_t value) 1366 { 1367 if ((size_t)(slc_replyp - slc_reply) + 6 > sizeof(slc_reply)) 1368 return; 1369 if ((*slc_replyp++ = func) == IAC) 1370 *slc_replyp++ = IAC; 1371 if ((*slc_replyp++ = flags) == IAC) 1372 *slc_replyp++ = IAC; 1373 if ((*slc_replyp++ = (unsigned char)value) == IAC) 1374 *slc_replyp++ = IAC; 1375 } 1376 1377 void 1378 slc_end_reply(void) 1379 { 1380 int len; 1381 1382 len = slc_replyp - slc_reply; 1383 if (len <= 4 || ((size_t)len + 2 > sizeof(slc_reply))) 1384 return; 1385 *slc_replyp++ = IAC; 1386 *slc_replyp++ = SE; 1387 len += 2; 1388 if (NETROOM() > len) { 1389 ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply); 1390 printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2); 1391 } 1392 /*@*/else printf("slc_end_reply: not enough room\n"); 1393 } 1394 1395 int 1396 slc_update(void) 1397 { 1398 struct spc *spcp; 1399 int need_update = 0; 1400 1401 for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) { 1402 if (!(spcp->flags&SLC_ACK)) 1403 continue; 1404 spcp->flags &= ~SLC_ACK; 1405 if (spcp->valp && (*spcp->valp != spcp->val)) { 1406 *spcp->valp = spcp->val; 1407 need_update = 1; 1408 } 1409 } 1410 return(need_update); 1411 } 1412 1413 void 1414 env_opt(unsigned char *buf, int len) 1415 { 1416 unsigned char *ep = 0, *epc = 0; 1417 int i; 1418 1419 switch(buf[0]&0xff) { 1420 case TELQUAL_SEND: 1421 env_opt_start(); 1422 if (len == 1) { 1423 env_opt_add(NULL); 1424 } else for (i = 1; i < len; i++) { 1425 switch (buf[i]&0xff) { 1426 case NEW_ENV_VAR: 1427 case ENV_USERVAR: 1428 if (ep) { 1429 *epc = 0; 1430 env_opt_add(ep); 1431 } 1432 ep = epc = &buf[i+1]; 1433 break; 1434 case ENV_ESC: 1435 i++; 1436 /*FALL THROUGH*/ 1437 default: 1438 if (epc) 1439 *epc++ = buf[i]; 1440 break; 1441 } 1442 } 1443 if (ep) { 1444 *epc = 0; 1445 env_opt_add(ep); 1446 } 1447 env_opt_end(1); 1448 break; 1449 1450 case TELQUAL_IS: 1451 case TELQUAL_INFO: 1452 /* Ignore for now. We shouldn't get it anyway. */ 1453 break; 1454 1455 default: 1456 break; 1457 } 1458 } 1459 1460 #define OPT_REPLY_SIZE 256 1461 unsigned char *opt_reply; 1462 unsigned char *opt_replyp; 1463 unsigned char *opt_replyend; 1464 1465 void 1466 env_opt_start(void) 1467 { 1468 unsigned char *p; 1469 1470 if (opt_reply) { 1471 p = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE); 1472 if (p == NULL) 1473 free(opt_reply); 1474 } else 1475 p = (unsigned char *)malloc(OPT_REPLY_SIZE); 1476 opt_reply = p; 1477 if (opt_reply == NULL) { 1478 /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n"); 1479 opt_reply = opt_replyp = opt_replyend = NULL; 1480 return; 1481 } 1482 opt_replyp = opt_reply; 1483 opt_replyend = opt_reply + OPT_REPLY_SIZE; 1484 *opt_replyp++ = IAC; 1485 *opt_replyp++ = SB; 1486 *opt_replyp++ = telopt_environ; 1487 *opt_replyp++ = TELQUAL_IS; 1488 } 1489 1490 void 1491 env_opt_start_info(void) 1492 { 1493 env_opt_start(); 1494 if (opt_replyp) 1495 opt_replyp[-1] = TELQUAL_INFO; 1496 } 1497 1498 void 1499 env_opt_add(unsigned char *ep) 1500 { 1501 unsigned char *vp, c; 1502 unsigned int len, olen, elen; 1503 1504 if (opt_reply == NULL) /*XXX*/ 1505 return; /*XXX*/ 1506 1507 if (ep == NULL || *ep == '\0') { 1508 /* Send user defined variables first. */ 1509 env_default(1, 0); 1510 while ((ep = env_default(0, 0)) != NULL) 1511 env_opt_add(ep); 1512 1513 /* Now add the list of well know variables. */ 1514 env_default(1, 1); 1515 while ((ep = env_default(0, 1)) != NULL) 1516 env_opt_add(ep); 1517 return; 1518 } 1519 vp = env_getvalue(ep); 1520 elen = 2 * (vp ? strlen((char *)vp) : 0) + 1521 2 * strlen((char *)ep) + 6; 1522 if ((unsigned int)(opt_replyend - opt_replyp) < elen) 1523 { 1524 unsigned char *p; 1525 len = opt_replyend - opt_reply + elen; 1526 olen = opt_replyp - opt_reply; 1527 p = (unsigned char *)realloc(opt_reply, len); 1528 if (p == NULL) 1529 free(opt_reply); 1530 opt_reply = p; 1531 if (opt_reply == NULL) { 1532 /*@*/ printf("env_opt_add: realloc() failed!!!\n"); 1533 opt_reply = opt_replyp = opt_replyend = NULL; 1534 return; 1535 } 1536 opt_replyp = opt_reply + olen; 1537 opt_replyend = opt_reply + len; 1538 } 1539 if (opt_welldefined(ep)) 1540 *opt_replyp++ = NEW_ENV_VAR; 1541 else 1542 *opt_replyp++ = ENV_USERVAR; 1543 for (;;) { 1544 while ((c = *ep++) != '\0') { 1545 switch(c&0xff) { 1546 case IAC: 1547 *opt_replyp++ = IAC; 1548 break; 1549 case NEW_ENV_VAR: 1550 case NEW_ENV_VALUE: 1551 case ENV_ESC: 1552 case ENV_USERVAR: 1553 *opt_replyp++ = ENV_ESC; 1554 break; 1555 } 1556 *opt_replyp++ = c; 1557 } 1558 if ((ep = vp) != NULL) { 1559 *opt_replyp++ = NEW_ENV_VALUE; 1560 vp = NULL; 1561 } else 1562 break; 1563 } 1564 } 1565 1566 int 1567 opt_welldefined(const char *ep) 1568 { 1569 if ((strcmp(ep, "USER") == 0) || 1570 (strcmp(ep, "DISPLAY") == 0) || 1571 (strcmp(ep, "PRINTER") == 0) || 1572 (strcmp(ep, "SYSTEMTYPE") == 0) || 1573 (strcmp(ep, "JOB") == 0) || 1574 (strcmp(ep, "ACCT") == 0)) 1575 return(1); 1576 return(0); 1577 } 1578 void 1579 env_opt_end(int emptyok) 1580 { 1581 int len; 1582 1583 len = opt_replyp - opt_reply + 2; 1584 if (emptyok || len > 6) { 1585 *opt_replyp++ = IAC; 1586 *opt_replyp++ = SE; 1587 if (NETROOM() > len) { 1588 ring_supply_data(&netoring, opt_reply, len); 1589 printsub('>', &opt_reply[2], len - 2); 1590 } 1591 /*@*/ else printf("slc_end_reply: not enough room\n"); 1592 } 1593 if (opt_reply) { 1594 free(opt_reply); 1595 opt_reply = opt_replyp = opt_replyend = NULL; 1596 } 1597 } 1598 1599 1600 1602 int 1603 telrcv(void) 1604 { 1605 int c; 1606 int scc; 1607 unsigned char *sbp = NULL; 1608 int count; 1609 int returnValue = 0; 1610 1611 scc = 0; 1612 count = 0; 1613 while (TTYROOM() > 2) { 1614 if (scc == 0) { 1615 if (count) { 1616 ring_consumed(&netiring, count); 1617 returnValue = 1; 1618 count = 0; 1619 } 1620 sbp = netiring.consume; 1621 scc = ring_full_consecutive(&netiring); 1622 if (scc == 0) { 1623 /* No more data coming in */ 1624 break; 1625 } 1626 } 1627 1628 c = *sbp++ & 0xff, scc--; count++; 1629 #ifdef ENCRYPTION 1630 if (decrypt_input) 1631 c = (*decrypt_input)(c); 1632 #endif /* ENCRYPTION */ 1633 1634 switch (telrcv_state) { 1635 1636 case TS_CR: 1637 telrcv_state = TS_DATA; 1638 if (c == '\0') { 1639 break; /* Ignore \0 after CR */ 1640 } 1641 else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) { 1642 TTYADD(c); 1643 break; 1644 } 1645 /* Else, fall through */ 1646 1647 case TS_DATA: 1648 if (c == IAC) { 1649 telrcv_state = TS_IAC; 1650 break; 1651 } 1652 /* 1653 * The 'crmod' hack (see following) is needed 1654 * since we can't * set CRMOD on output only. 1655 * Machines like MULTICS like to send \r without 1656 * \n; since we must turn off CRMOD to get proper 1657 * input, the mapping is done here (sigh). 1658 */ 1659 if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) { 1660 if (scc > 0) { 1661 c = *sbp&0xff; 1662 #ifdef ENCRYPTION 1663 if (decrypt_input) 1664 c = (*decrypt_input)(c); 1665 #endif /* ENCRYPTION */ 1666 if (c == 0) { 1667 sbp++, scc--; count++; 1668 /* a "true" CR */ 1669 TTYADD('\r'); 1670 } else if (my_want_state_is_dont(TELOPT_ECHO) && 1671 (c == '\n')) { 1672 sbp++, scc--; count++; 1673 TTYADD('\n'); 1674 } else { 1675 #ifdef ENCRYPTION 1676 if (decrypt_input) 1677 (*decrypt_input)(-1); 1678 #endif /* ENCRYPTION */ 1679 1680 TTYADD('\r'); 1681 if (crmod) { 1682 TTYADD('\n'); 1683 } 1684 } 1685 } else { 1686 telrcv_state = TS_CR; 1687 TTYADD('\r'); 1688 if (crmod) { 1689 TTYADD('\n'); 1690 } 1691 } 1692 } else { 1693 TTYADD(c); 1694 } 1695 continue; 1696 1697 case TS_IAC: 1698 process_iac: 1699 switch (c) { 1700 1701 case WILL: 1702 telrcv_state = TS_WILL; 1703 continue; 1704 1705 case WONT: 1706 telrcv_state = TS_WONT; 1707 continue; 1708 1709 case DO: 1710 telrcv_state = TS_DO; 1711 continue; 1712 1713 case DONT: 1714 telrcv_state = TS_DONT; 1715 continue; 1716 1717 case DM: 1718 /* 1719 * We may have missed an urgent notification, 1720 * so make sure we flush whatever is in the 1721 * buffer currently. 1722 */ 1723 printoption("RCVD", IAC, DM); 1724 SYNCHing = 1; 1725 (void) ttyflush(1); 1726 SYNCHing = stilloob(); 1727 settimer(gotDM); 1728 break; 1729 1730 case SB: 1731 SB_CLEAR(); 1732 telrcv_state = TS_SB; 1733 continue; 1734 1735 1736 case IAC: 1737 TTYADD(IAC); 1738 break; 1739 1740 case NOP: 1741 case GA: 1742 default: 1743 printoption("RCVD", IAC, c); 1744 break; 1745 } 1746 telrcv_state = TS_DATA; 1747 continue; 1748 1749 case TS_WILL: 1750 printoption("RCVD", WILL, c); 1751 willoption(c); 1752 telrcv_state = TS_DATA; 1753 continue; 1754 1755 case TS_WONT: 1756 printoption("RCVD", WONT, c); 1757 wontoption(c); 1758 telrcv_state = TS_DATA; 1759 continue; 1760 1761 case TS_DO: 1762 printoption("RCVD", DO, c); 1763 dooption(c); 1764 if (c == TELOPT_NAWS) { 1765 sendnaws(); 1766 } else if (c == TELOPT_LFLOW) { 1767 localflow = 1; 1768 setcommandmode(); 1769 setconnmode(0); 1770 } 1771 telrcv_state = TS_DATA; 1772 continue; 1773 1774 case TS_DONT: 1775 printoption("RCVD", DONT, c); 1776 dontoption(c); 1777 flushline = 1; 1778 setconnmode(0); /* set new tty mode (maybe) */ 1779 telrcv_state = TS_DATA; 1780 continue; 1781 1782 case TS_SB: 1783 if (c == IAC) { 1784 telrcv_state = TS_SE; 1785 } else { 1786 SB_ACCUM(c); 1787 } 1788 continue; 1789 1790 case TS_SE: 1791 if (c != SE) { 1792 if (c != IAC) { 1793 /* 1794 * This is an error. We only expect to get 1795 * "IAC IAC" or "IAC SE". Several things may 1796 * have happened. An IAC was not doubled, the 1797 * IAC SE was left off, or another option got 1798 * inserted into the suboption are all possibilities. 1799 * If we assume that the IAC was not doubled, 1800 * and really the IAC SE was left off, we could 1801 * get into an infinite loop here. So, instead, 1802 * we terminate the suboption, and process the 1803 * partial suboption if we can. 1804 */ 1805 SB_ACCUM(IAC); 1806 SB_ACCUM(c); 1807 subpointer -= 2; 1808 SB_TERM(); 1809 1810 printoption("In SUBOPTION processing, RCVD", IAC, c); 1811 suboption(); /* handle sub-option */ 1812 telrcv_state = TS_IAC; 1813 goto process_iac; 1814 } 1815 SB_ACCUM(c); 1816 telrcv_state = TS_SB; 1817 } else { 1818 SB_ACCUM(IAC); 1819 SB_ACCUM(SE); 1820 subpointer -= 2; 1821 SB_TERM(); 1822 suboption(); /* handle sub-option */ 1823 telrcv_state = TS_DATA; 1824 } 1825 } 1826 } 1827 if (count) 1828 ring_consumed(&netiring, count); 1829 return returnValue||count; 1830 } 1831 1832 static int bol = 1, local = 0; 1833 1834 int 1835 rlogin_susp(void) 1836 { 1837 if (local) { 1838 local = 0; 1839 bol = 1; 1840 command(0, "z\n", 2); 1841 return(1); 1842 } 1843 return(0); 1844 } 1845 1846 static int 1847 telsnd(void) 1848 { 1849 int tcc; 1850 int count; 1851 int returnValue = 0; 1852 unsigned char *tbp = NULL; 1853 1854 tcc = 0; 1855 count = 0; 1856 while (NETROOM() > 2) { 1857 int sc; 1858 int c; 1859 1860 if (tcc == 0) { 1861 if (count) { 1862 ring_consumed(&ttyiring, count); 1863 returnValue = 1; 1864 count = 0; 1865 } 1866 tbp = ttyiring.consume; 1867 tcc = ring_full_consecutive(&ttyiring); 1868 if (tcc == 0) { 1869 break; 1870 } 1871 } 1872 c = *tbp++ & 0xff, sc = strip(c), tcc--; count++; 1873 if (rlogin != _POSIX_VDISABLE) { 1874 if (bol) { 1875 bol = 0; 1876 if (sc == rlogin) { 1877 local = 1; 1878 continue; 1879 } 1880 } else if (local) { 1881 local = 0; 1882 if (sc == '.' || c == termEofChar) { 1883 bol = 1; 1884 command(0, "close\n", 6); 1885 continue; 1886 } 1887 if (sc == termSuspChar) { 1888 bol = 1; 1889 command(0, "z\n", 2); 1890 continue; 1891 } 1892 if (sc == escape) { 1893 command(0, (char *)tbp, tcc); 1894 bol = 1; 1895 count += tcc; 1896 tcc = 0; 1897 flushline = 1; 1898 break; 1899 } 1900 if (sc != rlogin) { 1901 ++tcc; 1902 --tbp; 1903 --count; 1904 c = sc = rlogin; 1905 } 1906 } 1907 if ((sc == '\n') || (sc == '\r')) 1908 bol = 1; 1909 } else if (sc == escape && escape != _POSIX_VDISABLE) { 1910 /* 1911 * Double escape is a pass through of a single escape character. 1912 */ 1913 if (tcc && strip(*tbp) == escape) { 1914 tbp++; 1915 tcc--; 1916 count++; 1917 bol = 0; 1918 } else { 1919 command(0, (char *)tbp, tcc); 1920 bol = 1; 1921 count += tcc; 1922 tcc = 0; 1923 flushline = 1; 1924 break; 1925 } 1926 } else 1927 bol = 0; 1928 #ifdef KLUDGELINEMODE 1929 if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) { 1930 if (tcc > 0 && strip(*tbp) == echoc) { 1931 tcc--; tbp++; count++; 1932 } else { 1933 dontlecho = !dontlecho; 1934 settimer(echotoggle); 1935 setconnmode(0); 1936 flushline = 1; 1937 break; 1938 } 1939 } 1940 #endif 1941 if (sc != _POSIX_VDISABLE && MODE_LOCAL_CHARS(globalmode)) { 1942 if (TerminalSpecialChars(sc) == 0) { 1943 bol = 1; 1944 break; 1945 } 1946 } 1947 if (my_want_state_is_wont(TELOPT_BINARY)) { 1948 switch (c) { 1949 case '\n': 1950 /* 1951 * If we are in CRMOD mode (\r ==> \n) 1952 * on our local machine, then probably 1953 * a newline (unix) is CRLF (TELNET). 1954 */ 1955 if (MODE_LOCAL_CHARS(globalmode)) { 1956 NETADD('\r'); 1957 } 1958 NETADD('\n'); 1959 bol = flushline = 1; 1960 break; 1961 case '\r': 1962 if (!crlf) { 1963 NET2ADD('\r', '\0'); 1964 } else { 1965 NET2ADD('\r', '\n'); 1966 } 1967 bol = flushline = 1; 1968 break; 1969 case IAC: 1970 NET2ADD(IAC, IAC); 1971 break; 1972 default: 1973 NETADD(c); 1974 break; 1975 } 1976 } else if (c == IAC) { 1977 NET2ADD(IAC, IAC); 1978 } else { 1979 NETADD(c); 1980 } 1981 } 1982 if (count) 1983 ring_consumed(&ttyiring, count); 1984 return returnValue||count; /* Non-zero if we did anything */ 1985 } 1986 1987 /* 1989 * Scheduler() 1990 * 1991 * Try to do something. 1992 * 1993 * If we do something useful, return 1; else return 0. 1994 * 1995 */ 1996 1997 1998 int 1999 Scheduler(int block) /* should we block in the select ? */ 2000 { 2001 /* One wants to be a bit careful about setting returnValue 2002 * to one, since a one implies we did some useful work, 2003 * and therefore probably won't be called to block next 2004 * time (TN3270 mode only). 2005 */ 2006 int returnValue; 2007 int netin, netout, netex, ttyin, ttyout; 2008 2009 /* Decide which rings should be processed */ 2010 2011 netout = ring_full_count(&netoring) && 2012 (flushline || 2013 (my_want_state_is_wont(TELOPT_LINEMODE) 2014 #ifdef KLUDGELINEMODE 2015 && (!kludgelinemode || my_want_state_is_do(TELOPT_SGA)) 2016 #endif 2017 ) || 2018 my_want_state_is_will(TELOPT_BINARY)); 2019 ttyout = ring_full_count(&ttyoring); 2020 2021 ttyin = ring_empty_count(&ttyiring) && (clienteof == 0); 2022 2023 netin = !ISend && ring_empty_count(&netiring); 2024 2025 netex = !SYNCHing; 2026 2027 /* If we have seen a signal recently, reset things */ 2028 2029 /* Call to system code to process rings */ 2030 2031 returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block); 2032 2033 /* Now, look at the input rings, looking for work to do. */ 2034 2035 if (ring_full_count(&ttyiring)) { 2036 returnValue |= telsnd(); 2037 } 2038 2039 if (ring_full_count(&netiring)) { 2040 returnValue |= telrcv(); 2041 } 2042 return returnValue; 2043 } 2044 2045 /* 2047 * Select from tty and network... 2048 */ 2049 void 2050 telnet(const char *user) 2051 { 2052 sys_telnet_init(); 2053 2054 #if defined(AUTHENTICATION) || defined(ENCRYPTION) 2055 { 2056 static char local_host[MAXHOSTNAMELEN + 1] = { 0 }; 2057 2058 if (!local_host[0]) { 2059 gethostname(local_host, sizeof(local_host)); 2060 local_host[sizeof(local_host)-1] = 0; 2061 } 2062 auth_encrypt_init(local_host, hostname, "TELNET", 0); 2063 auth_encrypt_user(user); 2064 } 2065 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ 2066 if (telnetport) { 2067 #ifdef AUTHENTICATION 2068 if (autologin) 2069 send_will(TELOPT_AUTHENTICATION, 1); 2070 #endif 2071 #ifdef ENCRYPTION 2072 send_do(TELOPT_ENCRYPT, 1); 2073 send_will(TELOPT_ENCRYPT, 1); 2074 #endif /* ENCRYPTION */ 2075 send_do(TELOPT_SGA, 1); 2076 send_will(TELOPT_TTYPE, 1); 2077 send_will(TELOPT_NAWS, 1); 2078 send_will(TELOPT_TSPEED, 1); 2079 send_will(TELOPT_LFLOW, 1); 2080 send_will(TELOPT_LINEMODE, 1); 2081 send_will(TELOPT_NEW_ENVIRON, 1); 2082 send_do(TELOPT_STATUS, 1); 2083 if (env_getvalue((const unsigned char *)"DISPLAY")) 2084 send_will(TELOPT_XDISPLOC, 1); 2085 if (eight) 2086 tel_enter_binary(eight); 2087 } 2088 2089 for (;;) { 2090 int schedValue; 2091 2092 while ((schedValue = Scheduler(0)) != 0) { 2093 if (schedValue == -1) { 2094 setcommandmode(); 2095 return; 2096 } 2097 } 2098 2099 if (Scheduler(1) == -1) { 2100 setcommandmode(); 2101 return; 2102 } 2103 } 2104 } 2105 2106 #if 0 /* XXX - this not being in is a bug */ 2108 /* 2109 * nextitem() 2110 * 2111 * Return the address of the next "item" in the TELNET data 2112 * stream. This will be the address of the next character if 2113 * the current address is a user data character, or it will 2114 * be the address of the character following the TELNET command 2115 * if the current address is a TELNET IAC ("I Am a Command") 2116 * character. 2117 */ 2118 2119 static char * 2120 nextitem(char *current) 2121 { 2122 if ((*current&0xff) != IAC) { 2123 return current+1; 2124 } 2125 switch (*(current+1)&0xff) { 2126 case DO: 2127 case DONT: 2128 case WILL: 2129 case WONT: 2130 return current+3; 2131 case SB: /* loop forever looking for the SE */ 2132 { 2133 char *look = current+2; 2134 2135 for (;;) { 2136 if ((*look++&0xff) == IAC) { 2137 if ((*look++&0xff) == SE) { 2138 return look; 2139 } 2140 } 2141 } 2142 } 2143 default: 2144 return current+2; 2145 } 2146 } 2147 #endif /* 0 */ 2148 2149 /* 2150 * netclear() 2151 * 2152 * We are about to do a TELNET SYNCH operation. Clear 2153 * the path to the network. 2154 * 2155 * Things are a bit tricky since we may have sent the first 2156 * byte or so of a previous TELNET command into the network. 2157 * So, we have to scan the network buffer from the beginning 2158 * until we are up to where we want to be. 2159 * 2160 * A side effect of what we do, just to keep things 2161 * simple, is to clear the urgent data pointer. The principal 2162 * caller should be setting the urgent data pointer AFTER calling 2163 * us in any case. 2164 */ 2165 2166 static void 2167 netclear(void) 2168 { 2169 #if 0 /* XXX */ 2170 char *thisitem, *next; 2171 char *good; 2172 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 2173 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 2174 2175 thisitem = netobuf; 2176 2177 while ((next = nextitem(thisitem)) <= netobuf.send) { 2178 thisitem = next; 2179 } 2180 2181 /* Now, thisitem is first before/at boundary. */ 2182 2183 good = netobuf; /* where the good bytes go */ 2184 2185 while (netoring.add > thisitem) { 2186 if (wewant(thisitem)) { 2187 int length; 2188 2189 next = thisitem; 2190 do { 2191 next = nextitem(next); 2192 } while (wewant(next) && (nfrontp > next)); 2193 length = next-thisitem; 2194 memmove(good, thisitem, length); 2195 good += length; 2196 thisitem = next; 2197 } else { 2198 thisitem = nextitem(thisitem); 2199 } 2200 } 2201 2202 #endif /* 0 */ 2203 } 2204 2205 /* 2207 * These routines add various telnet commands to the data stream. 2208 */ 2209 2210 static void 2211 doflush(void) 2212 { 2213 NET2ADD(IAC, DO); 2214 NETADD(TELOPT_TM); 2215 flushline = 1; 2216 flushout = 1; 2217 (void) ttyflush(1); /* Flush/drop output */ 2218 /* do printoption AFTER flush, otherwise the output gets tossed... */ 2219 printoption("SENT", DO, TELOPT_TM); 2220 } 2221 2222 void 2223 xmitAO(void) 2224 { 2225 NET2ADD(IAC, AO); 2226 printoption("SENT", IAC, AO); 2227 if (autoflush) { 2228 doflush(); 2229 } 2230 } 2231 2232 2233 void 2234 xmitEL(void) 2235 { 2236 NET2ADD(IAC, EL); 2237 printoption("SENT", IAC, EL); 2238 } 2239 2240 void 2241 xmitEC(void) 2242 { 2243 NET2ADD(IAC, EC); 2244 printoption("SENT", IAC, EC); 2245 } 2246 2247 2248 int 2249 dosynch(const char *s) 2250 { 2251 netclear(); /* clear the path to the network */ 2252 NETADD(IAC); 2253 setneturg(); 2254 NETADD(DM); 2255 printoption("SENT", IAC, DM); 2256 return 1; 2257 } 2258 2259 int want_status_response = 0; 2260 2261 int 2262 get_status(const char *s) 2263 { 2264 unsigned char tmp[16]; 2265 unsigned char *cp; 2266 2267 if (my_want_state_is_dont(TELOPT_STATUS)) { 2268 printf("Remote side does not support STATUS option\n"); 2269 return 0; 2270 } 2271 cp = tmp; 2272 2273 *cp++ = IAC; 2274 *cp++ = SB; 2275 *cp++ = TELOPT_STATUS; 2276 *cp++ = TELQUAL_SEND; 2277 *cp++ = IAC; 2278 *cp++ = SE; 2279 if (NETROOM() >= cp - tmp) { 2280 ring_supply_data(&netoring, tmp, cp-tmp); 2281 printsub('>', tmp+2, cp - tmp - 2); 2282 } 2283 ++want_status_response; 2284 return 1; 2285 } 2286 2287 void 2288 intp(void) 2289 { 2290 NET2ADD(IAC, IP); 2291 printoption("SENT", IAC, IP); 2292 flushline = 1; 2293 if (autoflush) { 2294 doflush(); 2295 } 2296 if (autosynch) { 2297 dosynch(NULL); 2298 } 2299 } 2300 2301 void 2302 sendbrk(void) 2303 { 2304 NET2ADD(IAC, BREAK); 2305 printoption("SENT", IAC, BREAK); 2306 flushline = 1; 2307 if (autoflush) { 2308 doflush(); 2309 } 2310 if (autosynch) { 2311 dosynch(NULL); 2312 } 2313 } 2314 2315 void 2316 sendabort(void) 2317 { 2318 NET2ADD(IAC, ABORT); 2319 printoption("SENT", IAC, ABORT); 2320 flushline = 1; 2321 if (autoflush) { 2322 doflush(); 2323 } 2324 if (autosynch) { 2325 dosynch(NULL); 2326 } 2327 } 2328 2329 void 2330 sendsusp(void) 2331 { 2332 NET2ADD(IAC, SUSP); 2333 printoption("SENT", IAC, SUSP); 2334 flushline = 1; 2335 if (autoflush) { 2336 doflush(); 2337 } 2338 if (autosynch) { 2339 dosynch(NULL); 2340 } 2341 } 2342 2343 void 2344 sendeof(void) 2345 { 2346 NET2ADD(IAC, xEOF); 2347 printoption("SENT", IAC, xEOF); 2348 } 2349 2350 void 2351 sendayt(void) 2352 { 2353 NET2ADD(IAC, AYT); 2354 printoption("SENT", IAC, AYT); 2355 } 2356 2357 /* 2358 * Send a window size update to the remote system. 2359 */ 2360 2361 void 2362 sendnaws(void) 2363 { 2364 long rows, cols; 2365 unsigned char tmp[16]; 2366 unsigned char *cp; 2367 2368 if (my_state_is_wont(TELOPT_NAWS)) 2369 return; 2370 2371 #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \ 2372 if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; } 2373 2374 if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */ 2375 return; 2376 } 2377 2378 cp = tmp; 2379 2380 *cp++ = IAC; 2381 *cp++ = SB; 2382 *cp++ = TELOPT_NAWS; 2383 PUTSHORT(cp, cols); 2384 PUTSHORT(cp, rows); 2385 *cp++ = IAC; 2386 *cp++ = SE; 2387 if (NETROOM() >= cp - tmp) { 2388 ring_supply_data(&netoring, tmp, cp-tmp); 2389 printsub('>', tmp+2, cp - tmp - 2); 2390 } 2391 } 2392 2393 void 2394 tel_enter_binary(int rw) 2395 { 2396 if (rw&1) 2397 send_do(TELOPT_BINARY, 1); 2398 if (rw&2) 2399 send_will(TELOPT_BINARY, 1); 2400 } 2401 2402 void 2403 tel_leave_binary(int rw) 2404 { 2405 if (rw&1) 2406 send_dont(TELOPT_BINARY, 1); 2407 if (rw&2) 2408 send_wont(TELOPT_BINARY, 1); 2409 } 2410