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