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