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