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