1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * Copyright (c) 1988, 1990, 1993 10 * The Regents of the University of California. All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 41 #ifndef lint 42 static char sccsid[] = "@(#)telnet.c 8.1 (Berkeley) 6/6/93"; 43 #endif /* not lint */ 44 45 #include <netdb.h> 46 #include <sys/types.h> 47 48 #include <curses.h> 49 #include <signal.h> 50 /* 51 * By the way, we need to include curses.h before telnet.h since, 52 * among other things, telnet.h #defines 'DO', which is a variable 53 * declared in curses.h. 54 */ 55 56 #include <arpa/telnet.h> 57 58 #include <ctype.h> 59 60 #include "ring.h" 61 62 #include "defines.h" 63 #include "externs.h" 64 #include "types.h" 65 #include "general.h" 66 67 #include "auth.h" 68 #include "encrypt.h" 69 70 #define strip(x) ((x)&0x7f) 71 72 /* Buffer for sub-options */ 73 static unsigned char subbuffer[SUBBUFSIZE]; 74 static unsigned char *subpointer; 75 static unsigned char *subend; 76 77 #define SB_CLEAR() subpointer = subbuffer; 78 #define SB_TERM() { subend = subpointer; SB_CLEAR(); } 79 #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof (subbuffer))) { \ 80 *subpointer++ = (c); \ 81 } 82 83 #define SB_GET() ((*subpointer++)&0xff) 84 #define SB_PEEK() ((*subpointer)&0xff) 85 #define SB_EOF() (subpointer >= subend) 86 #define SB_LEN() (subend - subpointer) 87 88 char options[SUBBUFSIZE]; /* The combined options */ 89 char do_dont_resp[SUBBUFSIZE]; 90 char will_wont_resp[SUBBUFSIZE]; 91 92 int eight = 0; 93 int autologin = 0; /* Autologin anyone? */ 94 int skiprc = 0; 95 int connected; 96 int showoptions; 97 static int ISend; /* trying to send network data in */ 98 int debug = 0; 99 int crmod; 100 int netdata; /* Print out network data flow */ 101 int crlf; /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */ 102 int telnetport; 103 int SYNCHing; /* we are in TELNET SYNCH mode */ 104 int flushout; /* flush output */ 105 int autoflush = 0; /* flush output when interrupting? */ 106 int autosynch; /* send interrupt characters with SYNCH? */ 107 int localflow; /* we handle flow control locally */ 108 int restartany; /* if flow control enabled, restart on any character */ 109 int localchars; /* we recognize interrupt/quit */ 110 int donelclchars; /* the user has set "localchars" */ 111 int donebinarytoggle; /* the user has put us in binary */ 112 int dontlecho; /* do we suppress local echoing right now? */ 113 int eof_pending = 0; /* we received a genuine EOF on input, send IAC-EOF */ 114 int globalmode; 115 116 /* spin while waiting for authentication */ 117 boolean_t scheduler_lockout_tty = B_FALSE; 118 int encrypt_flag = 0; 119 int forwardable_flag = 0; 120 int forward_flag = 0; 121 boolean_t wantencryption = B_FALSE; 122 123 char *prompt = 0; 124 125 cc_t escape; 126 cc_t rlogin; 127 boolean_t escape_valid = B_TRUE; 128 #ifdef KLUDGELINEMODE 129 cc_t echoc; 130 #endif 131 132 /* 133 * Telnet receiver states for fsm 134 */ 135 #define TS_DATA 0 136 #define TS_IAC 1 137 #define TS_WILL 2 138 #define TS_WONT 3 139 #define TS_DO 4 140 #define TS_DONT 5 141 #define TS_CR 6 142 #define TS_SB 7 /* sub-option collection */ 143 #define TS_SE 8 /* looking for sub-option end */ 144 145 static int telrcv_state; 146 #ifdef OLD_ENVIRON 147 static unsigned char telopt_environ = TELOPT_NEW_ENVIRON; 148 #else 149 #define telopt_environ TELOPT_NEW_ENVIRON 150 #endif 151 152 jmp_buf toplevel = { 0 }; 153 jmp_buf peerdied; 154 155 static int flushline; 156 int linemode; 157 158 int reqd_linemode = 0; /* Set if either new or old line mode in */ 159 /* effect since before initial negotiations */ 160 161 #ifdef KLUDGELINEMODE 162 int kludgelinemode = 1; 163 #endif 164 165 /* 166 * The following are some clocks used to decide how to interpret 167 * the relationship between various variables. 168 */ 169 170 Clocks clocks; 171 172 #ifdef notdef 173 Modelist modelist[] = { 174 { "telnet command mode", COMMAND_LINE }, 175 { "character-at-a-time mode", 0 }, 176 { "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS }, 177 { "line-by-line mode (remote echo)", LINE | LOCAL_CHARS }, 178 { "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS }, 179 { "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS }, 180 { "3270 mode", 0 }, 181 }; 182 #endif 183 184 static void willoption(int); 185 static void wontoption(int); 186 static void lm_will(unsigned char *, int); 187 static void lm_wont(unsigned char *, int); 188 static void lm_do(unsigned char *, int); 189 static void lm_dont(unsigned char *, int); 190 static void slc_init(void); 191 static void slc_import(int); 192 static void slc_export(void); 193 static void slc_start_reply(size_t); 194 static void slc_add_reply(unsigned char, unsigned char, cc_t); 195 static void slc_end_reply(void); 196 static void slc(unsigned char *, int); 197 static int slc_update(void); 198 static void env_opt(unsigned char *, int); 199 static void env_opt_start(void); 200 static void sendeof(void); 201 static int is_unique(register char *, register char **, register char **); 202 203 /* 204 * Initialize telnet environment. 205 */ 206 207 int 208 init_telnet() 209 { 210 if (env_init() == 0) 211 return (0); 212 213 SB_CLEAR(); 214 ClearArray(options); 215 216 connected = ISend = localflow = donebinarytoggle = 0; 217 restartany = -1; 218 219 SYNCHing = 0; 220 221 /* Don't change NetTrace */ 222 223 escape = CONTROL(']'); 224 rlogin = _POSIX_VDISABLE; 225 #ifdef KLUDGELINEMODE 226 echoc = CONTROL('E'); 227 #endif 228 229 flushline = 1; 230 telrcv_state = TS_DATA; 231 232 return (1); 233 } 234 235 236 #ifdef notdef 237 #include <varargs.h> 238 239 /*VARARGS*/ 240 static void 241 printring(va_alist) 242 va_dcl 243 { 244 va_list ap; 245 char buffer[100]; /* where things go */ 246 char *ptr; 247 char *format; 248 char *string; 249 Ring *ring; 250 int i; 251 252 va_start(ap); 253 254 ring = va_arg(ap, Ring *); 255 format = va_arg(ap, char *); 256 ptr = buffer; 257 258 while ((i = *format++) != 0) { 259 if (i == '%') { 260 i = *format++; 261 switch (i) { 262 case 'c': 263 *ptr++ = va_arg(ap, int); 264 break; 265 case 's': 266 string = va_arg(ap, char *); 267 ring_supply_data(ring, buffer, ptr-buffer); 268 ring_supply_data(ring, string, strlen(string)); 269 ptr = buffer; 270 break; 271 case 0: 272 ExitString("printring: trailing %%.\n", 273 EXIT_FAILURE); 274 /*NOTREACHED*/ 275 default: 276 ExitString("printring: unknown format " 277 "character.\n", EXIT_FAILURE); 278 /*NOTREACHED*/ 279 } 280 } else { 281 *ptr++ = i; 282 } 283 } 284 ring_supply_data(ring, buffer, ptr-buffer); 285 } 286 #endif 287 288 /* 289 * These routines are in charge of sending option negotiations 290 * to the other side. 291 * 292 * The basic idea is that we send the negotiation if either side 293 * is in disagreement as to what the current state should be. 294 */ 295 296 void 297 send_do(c, init) 298 register int c, init; 299 { 300 if (init) { 301 if (((do_dont_resp[c] == 0) && my_state_is_do(c)) || 302 my_want_state_is_do(c)) 303 return; 304 set_my_want_state_do(c); 305 do_dont_resp[c]++; 306 } 307 NET2ADD(IAC, DO); 308 NETADD(c); 309 printoption("SENT", DO, c); 310 } 311 312 void 313 send_dont(c, init) 314 register int c, init; 315 { 316 if (init) { 317 if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) || 318 my_want_state_is_dont(c)) 319 return; 320 set_my_want_state_dont(c); 321 do_dont_resp[c]++; 322 } 323 NET2ADD(IAC, DONT); 324 NETADD(c); 325 printoption("SENT", DONT, c); 326 } 327 328 void 329 send_will(c, init) 330 register int c, init; 331 { 332 if (init) { 333 if (((will_wont_resp[c] == 0) && my_state_is_will(c)) || 334 my_want_state_is_will(c)) 335 return; 336 set_my_want_state_will(c); 337 will_wont_resp[c]++; 338 } 339 NET2ADD(IAC, WILL); 340 NETADD(c); 341 printoption("SENT", WILL, c); 342 } 343 344 void 345 send_wont(c, init) 346 register int c, init; 347 { 348 if (init) { 349 if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) || 350 my_want_state_is_wont(c)) 351 return; 352 set_my_want_state_wont(c); 353 will_wont_resp[c]++; 354 } 355 NET2ADD(IAC, WONT); 356 NETADD(c); 357 printoption("SENT", WONT, c); 358 } 359 360 361 static void 362 willoption(option) 363 int option; 364 { 365 int new_state_ok = 0; 366 367 if (do_dont_resp[option]) { 368 --do_dont_resp[option]; 369 if (do_dont_resp[option] && my_state_is_do(option)) 370 --do_dont_resp[option]; 371 } 372 373 if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) { 374 375 switch (option) { 376 377 case TELOPT_ECHO: 378 case TELOPT_SGA: 379 if (reqd_linemode && my_state_is_dont(option)) { 380 break; 381 } 382 /* FALLTHROUGH */ 383 case TELOPT_BINARY: 384 settimer(modenegotiated); 385 /* FALLTHROUGH */ 386 case TELOPT_STATUS: 387 case TELOPT_AUTHENTICATION: 388 /* FALLTHROUGH */ 389 case TELOPT_ENCRYPT: 390 new_state_ok = 1; 391 break; 392 393 case TELOPT_TM: 394 if (flushout) 395 flushout = 0; 396 /* 397 * Special case for TM. If we get back a WILL, 398 * pretend we got back a WONT. 399 */ 400 set_my_want_state_dont(option); 401 set_my_state_dont(option); 402 return; /* Never reply to TM will's/wont's */ 403 404 case TELOPT_LINEMODE: 405 default: 406 break; 407 } 408 409 if (new_state_ok) { 410 set_my_want_state_do(option); 411 send_do(option, 0); 412 setconnmode(0); /* possibly set new tty mode */ 413 } else { 414 do_dont_resp[option]++; 415 send_dont(option, 0); 416 } 417 } 418 set_my_state_do(option); 419 if (option == TELOPT_ENCRYPT) 420 encrypt_send_support(); 421 } 422 423 static void 424 wontoption(option) 425 int option; 426 { 427 if (do_dont_resp[option]) { 428 --do_dont_resp[option]; 429 if (do_dont_resp[option] && my_state_is_dont(option)) 430 --do_dont_resp[option]; 431 } 432 433 if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) { 434 435 switch (option) { 436 437 #ifdef KLUDGELINEMODE 438 case TELOPT_SGA: 439 if (!kludgelinemode) 440 break; 441 /* FALLTHROUGH */ 442 #endif 443 case TELOPT_ECHO: 444 settimer(modenegotiated); 445 break; 446 447 case TELOPT_TM: 448 if (flushout) 449 flushout = 0; 450 set_my_want_state_dont(option); 451 set_my_state_dont(option); 452 return; /* Never reply to TM will's/wont's */ 453 454 default: 455 break; 456 } 457 set_my_want_state_dont(option); 458 if (my_state_is_do(option)) 459 send_dont(option, 0); 460 setconnmode(0); /* Set new tty mode */ 461 } else if (option == TELOPT_TM) { 462 /* 463 * Special case for TM. 464 */ 465 if (flushout) 466 flushout = 0; 467 set_my_want_state_dont(option); 468 } 469 set_my_state_dont(option); 470 } 471 472 static void 473 dooption(option) 474 int option; 475 { 476 int new_state_ok = 0; 477 478 if (will_wont_resp[option]) { 479 --will_wont_resp[option]; 480 if (will_wont_resp[option] && my_state_is_will(option)) 481 --will_wont_resp[option]; 482 } 483 484 if (will_wont_resp[option] == 0) { 485 if (my_want_state_is_wont(option)) { 486 487 switch (option) { 488 489 case TELOPT_TM: 490 /* 491 * Special case for TM. We send a WILL, 492 * but pretend we sent WONT. 493 */ 494 send_will(option, 0); 495 set_my_want_state_wont(TELOPT_TM); 496 set_my_state_wont(TELOPT_TM); 497 return; 498 499 case TELOPT_BINARY: /* binary mode */ 500 case TELOPT_NAWS: /* window size */ 501 case TELOPT_TSPEED: /* terminal speed */ 502 case TELOPT_LFLOW: /* local flow control */ 503 case TELOPT_TTYPE: /* terminal type option */ 504 case TELOPT_SGA: /* no big deal */ 505 case TELOPT_ENCRYPT: /* encryption variable option */ 506 new_state_ok = 1; 507 break; 508 509 case TELOPT_NEW_ENVIRON: 510 /* New environment variable option */ 511 #ifdef OLD_ENVIRON 512 if (my_state_is_will(TELOPT_OLD_ENVIRON)) 513 /* turn off the old */ 514 send_wont(TELOPT_OLD_ENVIRON, 1); 515 goto env_common; 516 case TELOPT_OLD_ENVIRON: 517 /* Old environment variable option */ 518 if (my_state_is_will(TELOPT_NEW_ENVIRON)) 519 /* Don't enable if new one is in use! */ 520 break; 521 env_common: 522 telopt_environ = option; 523 #endif 524 new_state_ok = 1; 525 break; 526 527 case TELOPT_AUTHENTICATION: 528 if (autologin) 529 new_state_ok = 1; 530 break; 531 532 case TELOPT_XDISPLOC: /* X Display location */ 533 if (env_getvalue((unsigned char *)"DISPLAY")) 534 new_state_ok = 1; 535 break; 536 537 case TELOPT_LINEMODE: 538 #ifdef KLUDGELINEMODE 539 kludgelinemode = 0; 540 send_do(TELOPT_SGA, 1); 541 #endif 542 set_my_want_state_will(TELOPT_LINEMODE); 543 send_will(option, 0); 544 set_my_state_will(TELOPT_LINEMODE); 545 slc_init(); 546 return; 547 548 case TELOPT_ECHO: /* We're never going to echo... */ 549 default: 550 break; 551 } 552 553 if (new_state_ok) { 554 set_my_want_state_will(option); 555 send_will(option, 0); 556 setconnmode(0); /* Set new tty mode */ 557 } else { 558 will_wont_resp[option]++; 559 send_wont(option, 0); 560 } 561 } else { 562 /* 563 * Handle options that need more things done after the 564 * other side has acknowledged the option. 565 */ 566 switch (option) { 567 case TELOPT_LINEMODE: 568 #ifdef KLUDGELINEMODE 569 kludgelinemode = 0; 570 send_do(TELOPT_SGA, 1); 571 #endif 572 set_my_state_will(option); 573 slc_init(); 574 send_do(TELOPT_SGA, 0); 575 return; 576 } 577 } 578 } 579 set_my_state_will(option); 580 } 581 582 static void 583 dontoption(option) 584 int option; 585 { 586 587 if (will_wont_resp[option]) { 588 --will_wont_resp[option]; 589 if (will_wont_resp[option] && my_state_is_wont(option)) 590 --will_wont_resp[option]; 591 } 592 593 if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) { 594 switch (option) { 595 case TELOPT_LINEMODE: 596 linemode = 0; /* put us back to the default state */ 597 break; 598 #ifdef OLD_ENVIRON 599 case TELOPT_NEW_ENVIRON: 600 /* 601 * The new environ option wasn't recognized, try 602 * the old one. 603 */ 604 send_will(TELOPT_OLD_ENVIRON, 1); 605 telopt_environ = TELOPT_OLD_ENVIRON; 606 break; 607 #endif 608 } 609 /* we always accept a DONT */ 610 set_my_want_state_wont(option); 611 if (my_state_is_will(option)) 612 send_wont(option, 0); 613 setconnmode(0); /* Set new tty mode */ 614 } 615 set_my_state_wont(option); 616 } 617 618 /* 619 * Given a buffer returned by tgetent(), this routine will turn 620 * the pipe seperated list of names in the buffer into an array 621 * of pointers to null terminated names. We toss out any bad, 622 * duplicate, or verbose names (names with spaces). 623 */ 624 625 static char *name_unknown = "UNKNOWN"; 626 static char *unknown[] = { 0, 0 }; 627 628 static char ** 629 mklist(buf, name) 630 char *buf, *name; 631 { 632 register int n; 633 register char c, *cp, **argvp, *cp2, **argv, **avt; 634 635 if (name) { 636 if (strlen(name) > 40u) { 637 name = 0; 638 unknown[0] = name_unknown; 639 } else { 640 unknown[0] = name; 641 upcase(name); 642 } 643 } else 644 unknown[0] = name_unknown; 645 /* 646 * Count up the number of names. 647 */ 648 for (n = 1, cp = buf; *cp && *cp != ':'; cp++) { 649 if (*cp == '|') 650 n++; 651 } 652 /* 653 * Allocate an array to put the name pointers into 654 */ 655 argv = malloc((n+3)*sizeof (char *)); 656 if (argv == 0) 657 return (unknown); 658 659 /* 660 * Fill up the array of pointers to names. 661 */ 662 *argv = 0; 663 argvp = argv+1; 664 n = 0; 665 for (cp = cp2 = buf; (c = *cp) != NULL; cp++) { 666 if (c == '|' || c == ':') { 667 *cp++ = '\0'; 668 /* 669 * Skip entries that have spaces or are over 40 670 * characters long. If this is our environment 671 * name, then put it up front. Otherwise, as 672 * long as this is not a duplicate name (case 673 * insensitive) add it to the list. 674 */ 675 if (n || (cp - cp2 > 41)) 676 /* EMPTY */; 677 else if (name && (strncasecmp(name, cp2, cp-cp2) == 0)) 678 *argv = cp2; 679 else if (is_unique(cp2, argv+1, argvp)) 680 *argvp++ = cp2; 681 if (c == ':') 682 break; 683 /* 684 * Skip multiple delimiters. Reset cp2 to 685 * the beginning of the next name. Reset n, 686 * the flag for names with spaces. 687 */ 688 while ((c = *cp) == '|') 689 cp++; 690 cp2 = cp; 691 n = 0; 692 } 693 /* 694 * Skip entries with spaces or non-ascii values. 695 * Convert lower case letters to upper case. 696 */ 697 if ((c == ' ') || !isascii(c)) 698 n = 1; 699 else if (islower(c)) 700 *cp = toupper(c); 701 } 702 703 /* 704 * Check for an old V6 2 character name. If the second 705 * name points to the beginning of the buffer, and is 706 * only 2 characters long, move it to the end of the array. 707 */ 708 if ((argv[1] == buf) && (strlen(argv[1]) == 2)) { 709 --argvp; 710 for (avt = &argv[1]; avt < argvp; avt++) 711 *avt = *(avt+1); 712 *argvp++ = buf; 713 } 714 715 /* 716 * Duplicate last name, for TTYPE option, and null 717 * terminate the array. If we didn't find a match on 718 * our terminal name, put that name at the beginning. 719 */ 720 cp = *(argvp-1); 721 *argvp++ = cp; 722 *argvp = 0; 723 724 if (*argv == 0) { 725 if (name) 726 *argv = name; 727 else { 728 --argvp; 729 for (avt = argv; avt < argvp; avt++) 730 *avt = *(avt+1); 731 } 732 } 733 if (*argv) 734 return (argv); 735 else 736 return (unknown); 737 } 738 739 static int 740 is_unique(name, as, ae) 741 register char *name, **as, **ae; 742 { 743 register char **ap; 744 register int n; 745 746 n = strlen(name) + 1; 747 for (ap = as; ap < ae; ap++) 748 if (strncasecmp(*ap, name, n) == 0) 749 return (0); 750 return (1); 751 } 752 753 #define termbuf ttytype 754 extern char ttytype[]; 755 756 int resettermname = 1; 757 758 static char * 759 gettermname(void) 760 { 761 char *tname; 762 static char **tnamep = 0; 763 static char **next; 764 int err; 765 766 if (resettermname) { 767 resettermname = 0; 768 if (tnamep && tnamep != unknown) 769 free(tnamep); 770 tname = (char *)env_getvalue((unsigned char *)"TERM"); 771 if ((tname != NULL) && (setupterm(tname, 1, &err) == 0)) { 772 tnamep = mklist(termbuf, tname); 773 } else { 774 if (tname && (strlen(tname) <= 40u)) { 775 unknown[0] = tname; 776 upcase(tname); 777 } else 778 unknown[0] = name_unknown; 779 tnamep = unknown; 780 } 781 next = tnamep; 782 } 783 if (*next == 0) 784 next = tnamep; 785 return (*next++); 786 } 787 /* 788 * suboption() 789 * 790 * Look at the sub-option buffer, and try to be helpful to the other 791 * side. 792 * 793 * Currently we recognize: 794 * 795 * Terminal type, send request. 796 * Terminal speed (send request). 797 * Local flow control (is request). 798 * Linemode 799 */ 800 801 static void 802 suboption() 803 { 804 unsigned char subchar; 805 806 printsub('<', subbuffer, SB_LEN()+2); 807 switch (subchar = SB_GET()) { 808 case TELOPT_TTYPE: 809 if (my_want_state_is_wont(TELOPT_TTYPE)) 810 return; 811 if (SB_EOF() || SB_GET() != TELQUAL_SEND) { 812 return; 813 } else { 814 char *name; 815 unsigned char temp[50]; 816 int len, bytes; 817 818 name = gettermname(); 819 len = strlen(name) + 4 + 2; 820 bytes = snprintf((char *)temp, sizeof (temp), 821 "%c%c%c%c%s%c%c", IAC, SB, 822 TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE); 823 if ((len < NETROOM()) && (bytes < sizeof (temp))) { 824 ring_supply_data(&netoring, temp, len); 825 printsub('>', &temp[2], len-2); 826 } else { 827 ExitString("No room in buffer for " 828 "terminal type.\n", EXIT_FAILURE); 829 /*NOTREACHED*/ 830 } 831 } 832 break; 833 case TELOPT_TSPEED: 834 if (my_want_state_is_wont(TELOPT_TSPEED)) 835 return; 836 if (SB_EOF()) 837 return; 838 if (SB_GET() == TELQUAL_SEND) { 839 int ospeed, ispeed; 840 unsigned char temp[50]; 841 int len, bytes; 842 843 TerminalSpeeds(&ispeed, &ospeed); 844 845 bytes = snprintf((char *)temp, sizeof (temp), 846 "%c%c%c%c%d,%d%c%c", IAC, SB, 847 TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE); 848 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 849 850 if ((len < NETROOM()) && (bytes < sizeof (temp))) { 851 ring_supply_data(&netoring, temp, len); 852 printsub('>', temp+2, len - 2); 853 } 854 else 855 (void) printf( 856 "telnet: not enough room in buffer " 857 "for terminal speed option reply\n"); 858 } 859 break; 860 case TELOPT_LFLOW: 861 if (my_want_state_is_wont(TELOPT_LFLOW)) 862 return; 863 if (SB_EOF()) 864 return; 865 switch (SB_GET()) { 866 case LFLOW_RESTART_ANY: 867 restartany = 1; 868 break; 869 case LFLOW_RESTART_XON: 870 restartany = 0; 871 break; 872 case LFLOW_ON: 873 localflow = 1; 874 break; 875 case LFLOW_OFF: 876 localflow = 0; 877 break; 878 default: 879 return; 880 } 881 setcommandmode(); 882 setconnmode(0); 883 break; 884 885 case TELOPT_LINEMODE: 886 if (my_want_state_is_wont(TELOPT_LINEMODE)) 887 return; 888 if (SB_EOF()) 889 return; 890 switch (SB_GET()) { 891 case WILL: 892 lm_will(subpointer, SB_LEN()); 893 break; 894 case WONT: 895 lm_wont(subpointer, SB_LEN()); 896 break; 897 case DO: 898 lm_do(subpointer, SB_LEN()); 899 break; 900 case DONT: 901 lm_dont(subpointer, SB_LEN()); 902 break; 903 case LM_SLC: 904 slc(subpointer, SB_LEN()); 905 break; 906 case LM_MODE: 907 lm_mode(subpointer, SB_LEN(), 0); 908 break; 909 default: 910 break; 911 } 912 break; 913 914 #ifdef OLD_ENVIRON 915 case TELOPT_OLD_ENVIRON: 916 #endif 917 case TELOPT_NEW_ENVIRON: 918 if (SB_EOF()) 919 return; 920 switch (SB_PEEK()) { 921 case TELQUAL_IS: 922 case TELQUAL_INFO: 923 if (my_want_state_is_dont(subchar)) 924 return; 925 break; 926 case TELQUAL_SEND: 927 if (my_want_state_is_wont(subchar)) { 928 return; 929 } 930 break; 931 default: 932 return; 933 } 934 env_opt(subpointer, SB_LEN()); 935 break; 936 937 case TELOPT_XDISPLOC: 938 if (my_want_state_is_wont(TELOPT_XDISPLOC)) 939 return; 940 if (SB_EOF()) 941 return; 942 if (SB_GET() == TELQUAL_SEND) { 943 unsigned char temp[50], *dp; 944 int len, bytes; 945 946 if ((dp = env_getvalue((unsigned char *)"DISPLAY")) == 947 NULL) { 948 /* 949 * Something happened, we no longer have a 950 * DISPLAY variable. So, turn off the option. 951 */ 952 send_wont(TELOPT_XDISPLOC, 1); 953 break; 954 } 955 bytes = snprintf((char *)temp, sizeof (temp), 956 "%c%c%c%c%s%c%c", IAC, SB, 957 TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE); 958 len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */ 959 960 if ((len < NETROOM()) && (bytes < sizeof (temp))) { 961 ring_supply_data(&netoring, temp, len); 962 printsub('>', temp+2, len - 2); 963 } 964 else 965 (void) printf( 966 "telnet: not enough room in buffer" 967 " for display location option reply\n"); 968 } 969 break; 970 971 case TELOPT_AUTHENTICATION: { 972 if (!autologin) 973 break; 974 if (SB_EOF()) 975 return; 976 switch (SB_GET()) { 977 case TELQUAL_SEND: 978 if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 979 return; 980 auth_send(subpointer, SB_LEN()); 981 break; 982 case TELQUAL_REPLY: 983 if (my_want_state_is_wont(TELOPT_AUTHENTICATION)) 984 return; 985 auth_reply(subpointer, SB_LEN()); 986 break; 987 } 988 } 989 break; 990 991 case TELOPT_ENCRYPT: 992 if (SB_EOF()) 993 return; 994 switch (SB_GET()) { 995 case ENCRYPT_START: 996 if (my_want_state_is_dont(TELOPT_ENCRYPT)) 997 return; 998 encrypt_start(subpointer, SB_LEN()); 999 break; 1000 case ENCRYPT_END: 1001 if (my_want_state_is_dont(TELOPT_ENCRYPT)) 1002 return; 1003 encrypt_end(); 1004 break; 1005 case ENCRYPT_SUPPORT: 1006 if (my_want_state_is_wont(TELOPT_ENCRYPT)) 1007 return; 1008 encrypt_support(subpointer, SB_LEN()); 1009 break; 1010 case ENCRYPT_REQSTART: 1011 if (my_want_state_is_wont(TELOPT_ENCRYPT)) 1012 return; 1013 encrypt_request_start(subpointer, SB_LEN()); 1014 break; 1015 case ENCRYPT_REQEND: 1016 if (my_want_state_is_wont(TELOPT_ENCRYPT)) 1017 return; 1018 /* 1019 * We can always send an REQEND so that we cannot 1020 * get stuck encrypting. We should only get this 1021 * if we have been able to get in the correct mode 1022 * anyhow. 1023 */ 1024 encrypt_request_end(); 1025 break; 1026 case ENCRYPT_IS: 1027 if (my_want_state_is_dont(TELOPT_ENCRYPT)) 1028 return; 1029 encrypt_is(subpointer, SB_LEN()); 1030 break; 1031 case ENCRYPT_REPLY: 1032 if (my_want_state_is_wont(TELOPT_ENCRYPT)) 1033 return; 1034 encrypt_reply(subpointer, SB_LEN()); 1035 break; 1036 case ENCRYPT_ENC_KEYID: 1037 if (my_want_state_is_dont(TELOPT_ENCRYPT)) 1038 return; 1039 encrypt_enc_keyid(subpointer, SB_LEN()); 1040 break; 1041 case ENCRYPT_DEC_KEYID: 1042 if (my_want_state_is_wont(TELOPT_ENCRYPT)) 1043 return; 1044 encrypt_dec_keyid(subpointer, SB_LEN()); 1045 break; 1046 default: 1047 break; 1048 } 1049 break; 1050 default: 1051 break; 1052 } 1053 } 1054 1055 static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE }; 1056 1057 static void 1058 lm_will(cmd, len) 1059 unsigned char *cmd; 1060 int len; 1061 { 1062 if (len < 1) { 1063 /* Should not happen... */ 1064 (void) printf( 1065 "telnet: command missing from linemode WILL request\n"); 1066 return; 1067 } 1068 switch (cmd[0]) { 1069 case LM_FORWARDMASK: /* We shouldn't ever get this... */ 1070 default: 1071 str_lm[3] = DONT; 1072 str_lm[4] = cmd[0]; 1073 if (NETROOM() > sizeof (str_lm)) { 1074 ring_supply_data(&netoring, str_lm, sizeof (str_lm)); 1075 printsub('>', &str_lm[2], sizeof (str_lm)-2); 1076 } 1077 else 1078 (void) printf("telnet: not enough room in buffer for" 1079 "reply to linemode WILL request\n"); 1080 break; 1081 } 1082 } 1083 1084 static void 1085 lm_wont(cmd, len) 1086 unsigned char *cmd; 1087 int len; 1088 { 1089 if (len < 1) { 1090 /* Should not happen... */ 1091 (void) printf( 1092 "telnet: command missing from linemode WONT request\n"); 1093 return; 1094 } 1095 switch (cmd[0]) { 1096 case LM_FORWARDMASK: /* We shouldn't ever get this... */ 1097 default: 1098 /* We are always DONT, so don't respond */ 1099 return; 1100 } 1101 } 1102 1103 static void 1104 lm_do(cmd, len) 1105 unsigned char *cmd; 1106 int len; 1107 { 1108 if (len < 1) { 1109 /* Should not happen... */ 1110 (void) printf( 1111 "telnet: command missing from linemode DO request\n"); 1112 return; 1113 } 1114 switch (cmd[0]) { 1115 case LM_FORWARDMASK: 1116 default: 1117 str_lm[3] = WONT; 1118 str_lm[4] = cmd[0]; 1119 if (NETROOM() > sizeof (str_lm)) { 1120 ring_supply_data(&netoring, str_lm, sizeof (str_lm)); 1121 printsub('>', &str_lm[2], sizeof (str_lm)-2); 1122 } 1123 else 1124 (void) printf("telnet: not enough room in buffer for" 1125 "reply to linemode DO request\n"); 1126 break; 1127 } 1128 } 1129 1130 static void 1131 lm_dont(cmd, len) 1132 unsigned char *cmd; 1133 int len; 1134 { 1135 if (len < 1) { 1136 /* Should not happen... */ 1137 (void) printf( 1138 "telnet: command missing from linemode DONT request\n"); 1139 return; 1140 } 1141 switch (cmd[0]) { 1142 case LM_FORWARDMASK: 1143 default: 1144 /* we are always WONT, so don't respond */ 1145 break; 1146 } 1147 } 1148 1149 static unsigned char str_lm_mode[] = { 1150 IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE 1151 }; 1152 1153 void 1154 lm_mode(cmd, len, init) 1155 unsigned char *cmd; 1156 int len, init; 1157 { 1158 if (len != 1) 1159 return; 1160 if ((linemode&MODE_MASK&~MODE_ACK) == *cmd) 1161 return; 1162 linemode = *cmd&(MODE_MASK&~MODE_ACK); 1163 str_lm_mode[4] = linemode; 1164 if (!init) 1165 str_lm_mode[4] |= MODE_ACK; 1166 if (NETROOM() > sizeof (str_lm_mode)) { 1167 ring_supply_data(&netoring, str_lm_mode, sizeof (str_lm_mode)); 1168 printsub('>', &str_lm_mode[2], sizeof (str_lm_mode)-2); 1169 } 1170 else 1171 (void) printf("telnet: not enough room in buffer for" 1172 "reply to linemode request\n"); 1173 setconnmode(0); /* set changed mode */ 1174 } 1175 1176 1177 1178 /* 1179 * slc() 1180 * Handle special character suboption of LINEMODE. 1181 */ 1182 1183 static struct spc { 1184 cc_t val; 1185 cc_t *valp; 1186 char flags; /* Current flags & level */ 1187 char mylevel; /* Maximum level & flags */ 1188 } spc_data[NSLC+1]; 1189 1190 #define SLC_IMPORT 0 1191 #define SLC_EXPORT 1 1192 #define SLC_RVALUE 2 1193 static int slc_mode = SLC_EXPORT; 1194 1195 static void 1196 slc_init() 1197 { 1198 register struct spc *spcp; 1199 1200