utility.c revision 72445
1/* 2 * Copyright (c) 1989, 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#define PRINTOPTIONS 35#include "telnetd.h" 36 37RCSID("$Id: utility.c,v 1.23 2000/10/08 13:34:27 assar Exp $"); 38 39/* 40 * utility functions performing io related tasks 41 */ 42 43/* 44 * ttloop 45 * 46 * A small subroutine to flush the network output buffer, get some 47 * data from the network, and pass it through the telnet state 48 * machine. We also flush the pty input buffer (by dropping its data) 49 * if it becomes too full. 50 * 51 * return 0 if OK or 1 if interrupted by a signal. 52 */ 53 54int 55ttloop(void) 56{ 57 void netflush(void); 58 59 DIAG(TD_REPORT, { 60 output_data("td: ttloop\r\n"); 61 }); 62 if (nfrontp-nbackp) 63 netflush(); 64 ncc = read(net, netibuf, sizeof netibuf); 65 if (ncc < 0) { 66 if (errno == EINTR) 67 return 1; 68 syslog(LOG_INFO, "ttloop: read: %m\n"); 69 exit(1); 70 } else if (ncc == 0) { 71 syslog(LOG_INFO, "ttloop: peer died\n"); 72 exit(1); 73 } 74 DIAG(TD_REPORT, { 75 output_data("td: ttloop read %d chars\r\n", ncc); 76 }); 77 netip = netibuf; 78 telrcv(); /* state machine */ 79 if (ncc > 0) { 80 pfrontp = pbackp = ptyobuf; 81 telrcv(); 82 } 83 return 0; 84} /* end of ttloop */ 85 86/* 87 * Check a descriptor to see if out of band data exists on it. 88 */ 89int 90stilloob(int s) 91{ 92 static struct timeval timeout = { 0 }; 93 fd_set excepts; 94 int value; 95 96 if (s >= FD_SETSIZE) 97 fatal(ourpty, "fd too large"); 98 99 do { 100 FD_ZERO(&excepts); 101 FD_SET(s, &excepts); 102 value = select(s+1, 0, 0, &excepts, &timeout); 103 } while ((value == -1) && (errno == EINTR)); 104 105 if (value < 0) { 106 fatalperror(ourpty, "select"); 107 } 108 if (FD_ISSET(s, &excepts)) { 109 return 1; 110 } else { 111 return 0; 112 } 113} 114 115void 116ptyflush(void) 117{ 118 int n; 119 120 if ((n = pfrontp - pbackp) > 0) { 121 DIAG((TD_REPORT | TD_PTYDATA), { 122 output_data("td: ptyflush %d chars\r\n", n); 123 }); 124 DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); 125 n = write(ourpty, pbackp, n); 126 } 127 if (n < 0) { 128 if (errno == EWOULDBLOCK || errno == EINTR) 129 return; 130 cleanup(0); 131 } 132 pbackp += n; 133 if (pbackp == pfrontp) 134 pbackp = pfrontp = ptyobuf; 135} 136 137/* 138 * nextitem() 139 * 140 * Return the address of the next "item" in the TELNET data 141 * stream. This will be the address of the next character if 142 * the current address is a user data character, or it will 143 * be the address of the character following the TELNET command 144 * if the current address is a TELNET IAC ("I Am a Command") 145 * character. 146 */ 147char * 148nextitem(char *current) 149{ 150 if ((*current&0xff) != IAC) { 151 return current+1; 152 } 153 switch (*(current+1)&0xff) { 154 case DO: 155 case DONT: 156 case WILL: 157 case WONT: 158 return current+3; 159 case SB:{ 160 /* loop forever looking for the SE */ 161 char *look = current+2; 162 163 for (;;) { 164 if ((*look++&0xff) == IAC) { 165 if ((*look++&0xff) == SE) { 166 return look; 167 } 168 } 169 } 170 } 171 default: 172 return current+2; 173 } 174} 175 176 177/* 178 * netclear() 179 * 180 * We are about to do a TELNET SYNCH operation. Clear 181 * the path to the network. 182 * 183 * Things are a bit tricky since we may have sent the first 184 * byte or so of a previous TELNET command into the network. 185 * So, we have to scan the network buffer from the beginning 186 * until we are up to where we want to be. 187 * 188 * A side effect of what we do, just to keep things 189 * simple, is to clear the urgent data pointer. The principal 190 * caller should be setting the urgent data pointer AFTER calling 191 * us in any case. 192 */ 193void 194netclear(void) 195{ 196 char *thisitem, *next; 197 char *good; 198#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 199 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 200 201#ifdef ENCRYPTION 202 thisitem = nclearto > netobuf ? nclearto : netobuf; 203#else 204 thisitem = netobuf; 205#endif 206 207 while ((next = nextitem(thisitem)) <= nbackp) { 208 thisitem = next; 209 } 210 211 /* Now, thisitem is first before/at boundary. */ 212 213#ifdef ENCRYPTION 214 good = nclearto > netobuf ? nclearto : netobuf; 215#else 216 good = netobuf; /* where the good bytes go */ 217#endif 218 219 while (nfrontp > thisitem) { 220 if (wewant(thisitem)) { 221 int length; 222 223 next = thisitem; 224 do { 225 next = nextitem(next); 226 } while (wewant(next) && (nfrontp > next)); 227 length = next-thisitem; 228 memmove(good, thisitem, length); 229 good += length; 230 thisitem = next; 231 } else { 232 thisitem = nextitem(thisitem); 233 } 234 } 235 236 nbackp = netobuf; 237 nfrontp = good; /* next byte to be sent */ 238 neturg = 0; 239} /* end of netclear */ 240 241/* 242 * netflush 243 * Send as much data as possible to the network, 244 * handling requests for urgent data. 245 */ 246void 247netflush(void) 248{ 249 int n; 250 extern int not42; 251 252 if ((n = nfrontp - nbackp) > 0) { 253 DIAG(TD_REPORT, 254 { n += output_data("td: netflush %d chars\r\n", n); 255 }); 256#ifdef ENCRYPTION 257 if (encrypt_output) { 258 char *s = nclearto ? nclearto : nbackp; 259 if (nfrontp - s > 0) { 260 (*encrypt_output)((unsigned char *)s, nfrontp-s); 261 nclearto = nfrontp; 262 } 263 } 264#endif 265 /* 266 * if no urgent data, or if the other side appears to be an 267 * old 4.2 client (and thus unable to survive TCP urgent data), 268 * write the entire buffer in non-OOB mode. 269 */ 270#if 1 /* remove this to make it work between solaris 2.6 and linux */ 271 if ((neturg == 0) || (not42 == 0)) { 272#endif 273 n = write(net, nbackp, n); /* normal write */ 274#if 1 /* remove this to make it work between solaris 2.6 and linux */ 275 } else { 276 n = neturg - nbackp; 277 /* 278 * In 4.2 (and 4.3) systems, there is some question about 279 * what byte in a sendOOB operation is the "OOB" data. 280 * To make ourselves compatible, we only send ONE byte 281 * out of band, the one WE THINK should be OOB (though 282 * we really have more the TCP philosophy of urgent data 283 * rather than the Unix philosophy of OOB data). 284 */ 285 if (n > 1) { 286 n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 287 } else { 288 n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 289 } 290 } 291#endif 292 } 293 if (n < 0) { 294 if (errno == EWOULDBLOCK || errno == EINTR) 295 return; 296 cleanup(0); 297 } 298 nbackp += n; 299#ifdef ENCRYPTION 300 if (nbackp > nclearto) 301 nclearto = 0; 302#endif 303 if (nbackp >= neturg) { 304 neturg = 0; 305 } 306 if (nbackp == nfrontp) { 307 nbackp = nfrontp = netobuf; 308#ifdef ENCRYPTION 309 nclearto = 0; 310#endif 311 } 312 return; 313} 314 315 316/* 317 * writenet 318 * 319 * Just a handy little function to write a bit of raw data to the net. 320 * It will force a transmit of the buffer if necessary 321 * 322 * arguments 323 * ptr - A pointer to a character string to write 324 * len - How many bytes to write 325 */ 326void 327writenet(unsigned char *ptr, int len) 328{ 329 /* flush buffer if no room for new data) */ 330 while ((&netobuf[BUFSIZ] - nfrontp) < len) { 331 /* if this fails, don't worry, buffer is a little big */ 332 netflush(); 333 } 334 335 memmove(nfrontp, ptr, len); 336 nfrontp += len; 337} 338 339 340/* 341 * miscellaneous functions doing a variety of little jobs follow ... 342 */ 343 344 345void fatal(int f, char *msg) 346{ 347 char buf[BUFSIZ]; 348 349 snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg); 350#ifdef ENCRYPTION 351 if (encrypt_output) { 352 /* 353 * Better turn off encryption first.... 354 * Hope it flushes... 355 */ 356 encrypt_send_end(); 357 netflush(); 358 } 359#endif 360 write(f, buf, (int)strlen(buf)); 361 sleep(1); /*XXX*/ 362 exit(1); 363} 364 365void 366fatalperror(int f, const char *msg) 367{ 368 char buf[BUFSIZ]; 369 370 snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno)); 371 fatal(f, buf); 372} 373 374char editedhost[32]; 375 376void edithost(char *pat, char *host) 377{ 378 char *res = editedhost; 379 380 if (!pat) 381 pat = ""; 382 while (*pat) { 383 switch (*pat) { 384 385 case '#': 386 if (*host) 387 host++; 388 break; 389 390 case '@': 391 if (*host) 392 *res++ = *host++; 393 break; 394 395 default: 396 *res++ = *pat; 397 break; 398 } 399 if (res == &editedhost[sizeof editedhost - 1]) { 400 *res = '\0'; 401 return; 402 } 403 pat++; 404 } 405 if (*host) 406 strlcpy (res, host, 407 sizeof editedhost - (res - editedhost)); 408 else 409 *res = '\0'; 410 editedhost[sizeof editedhost - 1] = '\0'; 411} 412 413static char *putlocation; 414 415void 416putstr(char *s) 417{ 418 419 while (*s) 420 putchr(*s++); 421} 422 423void 424putchr(int cc) 425{ 426 *putlocation++ = cc; 427} 428 429/* 430 * This is split on two lines so that SCCS will not see the M 431 * between two % signs and expand it... 432 */ 433static char fmtstr[] = { "%l:%M" "%P on %A, %d %B %Y" }; 434 435void putf(char *cp, char *where) 436{ 437#ifdef HAVE_UNAME 438 struct utsname name; 439#endif 440 char *slash; 441 time_t t; 442 char db[100]; 443 444 /* if we don't have uname, set these to sensible values */ 445 char *sysname = "Unix", 446 *machine = "", 447 *release = "", 448 *version = ""; 449 450#ifdef HAVE_UNAME 451 uname(&name); 452 sysname=name.sysname; 453 machine=name.machine; 454 release=name.release; 455 version=name.version; 456#endif 457 458 putlocation = where; 459 460 while (*cp) { 461 if (*cp != '%') { 462 putchr(*cp++); 463 continue; 464 } 465 switch (*++cp) { 466 467 case 't': 468#ifdef STREAMSPTY 469 /* names are like /dev/pts/2 -- we want pts/2 */ 470 slash = strchr(line+1, '/'); 471#else 472 slash = strrchr(line, '/'); 473#endif 474 if (slash == (char *) 0) 475 putstr(line); 476 else 477 putstr(&slash[1]); 478 break; 479 480 case 'h': 481 putstr(editedhost); 482 break; 483 484 case 's': 485 putstr(sysname); 486 break; 487 488 case 'm': 489 putstr(machine); 490 break; 491 492 case 'r': 493 putstr(release); 494 break; 495 496 case 'v': 497 putstr(version); 498 break; 499 500 case 'd': 501 time(&t); 502 strftime(db, sizeof(db), fmtstr, localtime(&t)); 503 putstr(db); 504 break; 505 506 case '%': 507 putchr('%'); 508 break; 509 } 510 cp++; 511 } 512} 513 514#ifdef DIAGNOSTICS 515/* 516 * Print telnet options and commands in plain text, if possible. 517 */ 518void 519printoption(char *fmt, int option) 520{ 521 if (TELOPT_OK(option)) 522 output_data("%s %s\r\n", 523 fmt, 524 TELOPT(option)); 525 else if (TELCMD_OK(option)) 526 output_data("%s %s\r\n", 527 fmt, 528 TELCMD(option)); 529 else 530 output_data("%s %d\r\n", 531 fmt, 532 option); 533 return; 534} 535 536void 537printsub(int direction, unsigned char *pointer, int length) 538 /* '<' or '>' */ 539 /* where suboption data sits */ 540 /* length of suboption data */ 541{ 542 int i = 0; 543 unsigned char buf[512]; 544 545 if (!(diagnostic & TD_OPTIONS)) 546 return; 547 548 if (direction) { 549 output_data("td: %s suboption ", 550 direction == '<' ? "recv" : "send"); 551 if (length >= 3) { 552 int j; 553 554 i = pointer[length-2]; 555 j = pointer[length-1]; 556 557 if (i != IAC || j != SE) { 558 output_data("(terminated by "); 559 if (TELOPT_OK(i)) 560 output_data("%s ", 561 TELOPT(i)); 562 else if (TELCMD_OK(i)) 563 output_data("%s ", 564 TELCMD(i)); 565 else 566 output_data("%d ", 567 i); 568 if (TELOPT_OK(j)) 569 output_data("%s", 570 TELOPT(j)); 571 else if (TELCMD_OK(j)) 572 output_data("%s", 573 TELCMD(j)); 574 else 575 output_data("%d", 576 j); 577 output_data(", not IAC SE!) "); 578 } 579 } 580 length -= 2; 581 } 582 if (length < 1) { 583 output_data("(Empty suboption??\?)"); 584 return; 585 } 586 switch (pointer[0]) { 587 case TELOPT_TTYPE: 588 output_data("TERMINAL-TYPE "); 589 switch (pointer[1]) { 590 case TELQUAL_IS: 591 output_data("IS \"%.*s\"", 592 length-2, 593 (char *)pointer+2); 594 break; 595 case TELQUAL_SEND: 596 output_data("SEND"); 597 break; 598 default: 599 output_data("- unknown qualifier %d (0x%x).", 600 pointer[1], pointer[1]); 601 } 602 break; 603 case TELOPT_TSPEED: 604 output_data("TERMINAL-SPEED"); 605 if (length < 2) { 606 output_data(" (empty suboption??\?)"); 607 break; 608 } 609 switch (pointer[1]) { 610 case TELQUAL_IS: 611 output_data(" IS %.*s", length-2, (char *)pointer+2); 612 break; 613 default: 614 if (pointer[1] == 1) 615 output_data(" SEND"); 616 else 617 output_data(" %d (unknown)", pointer[1]); 618 for (i = 2; i < length; i++) { 619 output_data(" ?%d?", pointer[i]); 620 } 621 break; 622 } 623 break; 624 625 case TELOPT_LFLOW: 626 output_data("TOGGLE-FLOW-CONTROL"); 627 if (length < 2) { 628 output_data(" (empty suboption??\?)"); 629 break; 630 } 631 switch (pointer[1]) { 632 case LFLOW_OFF: 633 output_data(" OFF"); 634 break; 635 case LFLOW_ON: 636 output_data(" ON"); 637 break; 638 case LFLOW_RESTART_ANY: 639 output_data(" RESTART-ANY"); 640 break; 641 case LFLOW_RESTART_XON: 642 output_data(" RESTART-XON"); 643 break; 644 default: 645 output_data(" %d (unknown)", 646 pointer[1]); 647 } 648 for (i = 2; i < length; i++) { 649 output_data(" ?%d?", 650 pointer[i]); 651 } 652 break; 653 654 case TELOPT_NAWS: 655 output_data("NAWS"); 656 if (length < 2) { 657 output_data(" (empty suboption??\?)"); 658 break; 659 } 660 if (length == 2) { 661 output_data(" ?%d?", 662 pointer[1]); 663 break; 664 } 665 output_data(" %u %u(%u)", 666 pointer[1], 667 pointer[2], 668 (((unsigned int)pointer[1])<<8) + pointer[2]); 669 if (length == 4) { 670 output_data(" ?%d?", 671 pointer[3]); 672 break; 673 } 674 output_data(" %u %u(%u)", 675 pointer[3], 676 pointer[4], 677 (((unsigned int)pointer[3])<<8) + pointer[4]); 678 for (i = 5; i < length; i++) { 679 output_data(" ?%d?", 680 pointer[i]); 681 } 682 break; 683 684 case TELOPT_LINEMODE: 685 output_data("LINEMODE "); 686 if (length < 2) { 687 output_data(" (empty suboption??\?)"); 688 break; 689 } 690 switch (pointer[1]) { 691 case WILL: 692 output_data("WILL "); 693 goto common; 694 case WONT: 695 output_data("WONT "); 696 goto common; 697 case DO: 698 output_data("DO "); 699 goto common; 700 case DONT: 701 output_data("DONT "); 702 common: 703 if (length < 3) { 704 output_data("(no option??\?)"); 705 break; 706 } 707 switch (pointer[2]) { 708 case LM_FORWARDMASK: 709 output_data("Forward Mask"); 710 for (i = 3; i < length; i++) { 711 output_data(" %x", pointer[i]); 712 } 713 break; 714 default: 715 output_data("%d (unknown)", 716 pointer[2]); 717 for (i = 3; i < length; i++) { 718 output_data(" %d", 719 pointer[i]); 720 } 721 break; 722 } 723 break; 724 725 case LM_SLC: 726 output_data("SLC"); 727 for (i = 2; i < length - 2; i += 3) { 728 if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 729 output_data(" %s", 730 SLC_NAME(pointer[i+SLC_FUNC])); 731 else 732 output_data(" %d", 733 pointer[i+SLC_FUNC]); 734 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 735 case SLC_NOSUPPORT: 736 output_data(" NOSUPPORT"); 737 break; 738 case SLC_CANTCHANGE: 739 output_data(" CANTCHANGE"); 740 break; 741 case SLC_VARIABLE: 742 output_data(" VARIABLE"); 743 break; 744 case SLC_DEFAULT: 745 output_data(" DEFAULT"); 746 break; 747 } 748 output_data("%s%s%s", 749 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 750 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 751 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 752 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 753 SLC_FLUSHOUT| SLC_LEVELBITS)) { 754 output_data("(0x%x)", 755 pointer[i+SLC_FLAGS]); 756 } 757 output_data(" %d;", 758 pointer[i+SLC_VALUE]); 759 if ((pointer[i+SLC_VALUE] == IAC) && 760 (pointer[i+SLC_VALUE+1] == IAC)) 761 i++; 762 } 763 for (; i < length; i++) { 764 output_data(" ?%d?", 765 pointer[i]); 766 } 767 break; 768 769 case LM_MODE: 770 output_data("MODE "); 771 if (length < 3) { 772 output_data("(no mode??\?)"); 773 break; 774 } 775 { 776 char tbuf[32]; 777 snprintf(tbuf, 778 sizeof(tbuf), 779 "%s%s%s%s%s", 780 pointer[2]&MODE_EDIT ? "|EDIT" : "", 781 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 782 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 783 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 784 pointer[2]&MODE_ACK ? "|ACK" : ""); 785 output_data("%s", 786 tbuf[1] ? &tbuf[1] : "0"); 787 } 788 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { 789 output_data(" (0x%x)", 790 pointer[2]); 791 } 792 for (i = 3; i < length; i++) { 793 output_data(" ?0x%x?", 794 pointer[i]); 795 } 796 break; 797 default: 798 output_data("%d (unknown)", 799 pointer[1]); 800 for (i = 2; i < length; i++) { 801 output_data(" %d", pointer[i]); 802 } 803 } 804 break; 805 806 case TELOPT_STATUS: { 807 char *cp; 808 int j, k; 809 810 output_data("STATUS"); 811 812 switch (pointer[1]) { 813 default: 814 if (pointer[1] == TELQUAL_SEND) 815 output_data(" SEND"); 816 else 817 output_data(" %d (unknown)", 818 pointer[1]); 819 for (i = 2; i < length; i++) { 820 output_data(" ?%d?", 821 pointer[i]); 822 } 823 break; 824 case TELQUAL_IS: 825 output_data(" IS\r\n"); 826 827 for (i = 2; i < length; i++) { 828 switch(pointer[i]) { 829 case DO: cp = "DO"; goto common2; 830 case DONT: cp = "DONT"; goto common2; 831 case WILL: cp = "WILL"; goto common2; 832 case WONT: cp = "WONT"; goto common2; 833 common2: 834 i++; 835 if (TELOPT_OK(pointer[i])) 836 output_data(" %s %s", 837 cp, 838 TELOPT(pointer[i])); 839 else 840 output_data(" %s %d", 841 cp, 842 pointer[i]); 843 844 output_data("\r\n"); 845 break; 846 847 case SB: 848 output_data(" SB "); 849 i++; 850 j = k = i; 851 while (j < length) { 852 if (pointer[j] == SE) { 853 if (j+1 == length) 854 break; 855 if (pointer[j+1] == SE) 856 j++; 857 else 858 break; 859 } 860 pointer[k++] = pointer[j++]; 861 } 862 printsub(0, &pointer[i], k - i); 863 if (i < length) { 864 output_data(" SE"); 865 i = j; 866 } else 867 i = j - 1; 868 869 output_data("\r\n"); 870 871 break; 872 873 default: 874 output_data(" %d", 875 pointer[i]); 876 break; 877 } 878 } 879 break; 880 } 881 break; 882 } 883 884 case TELOPT_XDISPLOC: 885 output_data("X-DISPLAY-LOCATION "); 886 switch (pointer[1]) { 887 case TELQUAL_IS: 888 output_data("IS \"%.*s\"", 889 length-2, 890 (char *)pointer+2); 891 break; 892 case TELQUAL_SEND: 893 output_data("SEND"); 894 break; 895 default: 896 output_data("- unknown qualifier %d (0x%x).", 897 pointer[1], pointer[1]); 898 } 899 break; 900 901 case TELOPT_NEW_ENVIRON: 902 output_data("NEW-ENVIRON "); 903 goto env_common1; 904 case TELOPT_OLD_ENVIRON: 905 output_data("OLD-ENVIRON"); 906 env_common1: 907 switch (pointer[1]) { 908 case TELQUAL_IS: 909 output_data("IS "); 910 goto env_common; 911 case TELQUAL_SEND: 912 output_data("SEND "); 913 goto env_common; 914 case TELQUAL_INFO: 915 output_data("INFO "); 916 env_common: 917 { 918 int noquote = 2; 919 for (i = 2; i < length; i++ ) { 920 switch (pointer[i]) { 921 case NEW_ENV_VAR: 922 output_data("\" VAR " + noquote); 923 noquote = 2; 924 break; 925 926 case NEW_ENV_VALUE: 927 output_data("\" VALUE " + noquote); 928 noquote = 2; 929 break; 930 931 case ENV_ESC: 932 output_data("\" ESC " + noquote); 933 noquote = 2; 934 break; 935 936 case ENV_USERVAR: 937 output_data("\" USERVAR " + noquote); 938 noquote = 2; 939 break; 940 941 default: 942 if (isprint(pointer[i]) && pointer[i] != '"') { 943 if (noquote) { 944 output_data ("\""); 945 noquote = 0; 946 } 947 output_data ("%c", pointer[i]); 948 } else { 949 output_data("\" %03o " + noquote, 950 pointer[i]); 951 noquote = 2; 952 } 953 break; 954 } 955 } 956 if (!noquote) 957 output_data ("\""); 958 break; 959 } 960 } 961 break; 962 963#ifdef AUTHENTICATION 964 case TELOPT_AUTHENTICATION: 965 output_data("AUTHENTICATION"); 966 967 if (length < 2) { 968 output_data(" (empty suboption??\?)"); 969 break; 970 } 971 switch (pointer[1]) { 972 case TELQUAL_REPLY: 973 case TELQUAL_IS: 974 output_data(" %s ", 975 (pointer[1] == TELQUAL_IS) ? 976 "IS" : "REPLY"); 977 if (AUTHTYPE_NAME_OK(pointer[2])) 978 output_data("%s ", 979 AUTHTYPE_NAME(pointer[2])); 980 else 981 output_data("%d ", 982 pointer[2]); 983 if (length < 3) { 984 output_data("(partial suboption??\?)"); 985 break; 986 } 987 output_data("%s|%s", 988 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 989 "CLIENT" : "SERVER", 990 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 991 "MUTUAL" : "ONE-WAY"); 992 993 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 994 output_data("%s", 995 buf); 996 break; 997 998 case TELQUAL_SEND: 999 i = 2; 1000 output_data(" SEND "); 1001 while (i < length) { 1002 if (AUTHTYPE_NAME_OK(pointer[i])) 1003 output_data("%s ", 1004 AUTHTYPE_NAME(pointer[i])); 1005 else 1006 output_data("%d ", 1007 pointer[i]); 1008 if (++i >= length) { 1009 output_data("(partial suboption??\?)"); 1010 break; 1011 } 1012 output_data("%s|%s ", 1013 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 1014 "CLIENT" : "SERVER", 1015 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 1016 "MUTUAL" : "ONE-WAY"); 1017 ++i; 1018 } 1019 break; 1020 1021 case TELQUAL_NAME: 1022 i = 2; 1023 output_data(" NAME \"%.*s\"", 1024 length - 2, 1025 pointer); 1026 break; 1027 1028 default: 1029 for (i = 2; i < length; i++) { 1030 output_data(" ?%d?", 1031 pointer[i]); 1032 } 1033 break; 1034 } 1035 break; 1036#endif 1037 1038#ifdef ENCRYPTION 1039 case TELOPT_ENCRYPT: 1040 output_data("ENCRYPT"); 1041 if (length < 2) { 1042 output_data(" (empty suboption?)"); 1043 break; 1044 } 1045 switch (pointer[1]) { 1046 case ENCRYPT_START: 1047 output_data(" START"); 1048 break; 1049 1050 case ENCRYPT_END: 1051 output_data(" END"); 1052 break; 1053 1054 case ENCRYPT_REQSTART: 1055 output_data(" REQUEST-START"); 1056 break; 1057 1058 case ENCRYPT_REQEND: 1059 output_data(" REQUEST-END"); 1060 break; 1061 1062 case ENCRYPT_IS: 1063 case ENCRYPT_REPLY: 1064 output_data(" %s ", 1065 (pointer[1] == ENCRYPT_IS) ? 1066 "IS" : "REPLY"); 1067 if (length < 3) { 1068 output_data(" (partial suboption?)"); 1069 break; 1070 } 1071 if (ENCTYPE_NAME_OK(pointer[2])) 1072 output_data("%s ", 1073 ENCTYPE_NAME(pointer[2])); 1074 else 1075 output_data(" %d (unknown)", 1076 pointer[2]); 1077 1078 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 1079 output_data("%s", 1080 buf); 1081 break; 1082 1083 case ENCRYPT_SUPPORT: 1084 i = 2; 1085 output_data(" SUPPORT "); 1086 while (i < length) { 1087 if (ENCTYPE_NAME_OK(pointer[i])) 1088 output_data("%s ", 1089 ENCTYPE_NAME(pointer[i])); 1090 else 1091 output_data("%d ", 1092 pointer[i]); 1093 i++; 1094 } 1095 break; 1096 1097 case ENCRYPT_ENC_KEYID: 1098 output_data(" ENC_KEYID %d", pointer[1]); 1099 goto encommon; 1100 1101 case ENCRYPT_DEC_KEYID: 1102 output_data(" DEC_KEYID %d", pointer[1]); 1103 goto encommon; 1104 1105 default: 1106 output_data(" %d (unknown)", pointer[1]); 1107 encommon: 1108 for (i = 2; i < length; i++) { 1109 output_data(" %d", pointer[i]); 1110 } 1111 break; 1112 } 1113 break; 1114#endif 1115 1116 default: 1117 if (TELOPT_OK(pointer[0])) 1118 output_data("%s (unknown)", 1119 TELOPT(pointer[0])); 1120 else 1121 output_data("%d (unknown)", 1122 pointer[i]); 1123 for (i = 1; i < length; i++) { 1124 output_data(" %d", pointer[i]); 1125 } 1126 break; 1127 } 1128 output_data("\r\n"); 1129} 1130 1131/* 1132 * Dump a data buffer in hex and ascii to the output data stream. 1133 */ 1134void 1135printdata(char *tag, char *ptr, int cnt) 1136{ 1137 int i; 1138 char xbuf[30]; 1139 1140 while (cnt) { 1141 /* flush net output buffer if no room for new data) */ 1142 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 1143 netflush(); 1144 } 1145 1146 /* add a line of output */ 1147 output_data("%s: ", tag); 1148 for (i = 0; i < 20 && cnt; i++) { 1149 output_data("%02x", *ptr); 1150 if (isprint(*ptr)) { 1151 xbuf[i] = *ptr; 1152 } else { 1153 xbuf[i] = '.'; 1154 } 1155 if (i % 2) { 1156 output_data(" "); 1157 } 1158 cnt--; 1159 ptr++; 1160 } 1161 xbuf[i] = '\0'; 1162 output_data(" %s\r\n", xbuf); 1163 } 1164} 1165#endif /* DIAGNOSTICS */ 1166