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