utility.c revision 78527
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.25 2001/05/17 00:34:42 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_errno(int f, const char *msg, int error) 367{ 368 char buf[BUFSIZ]; 369 370 snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(error)); 371 fatal(f, buf); 372} 373 374void 375fatalperror(int f, const char *msg) 376{ 377 fatalperror_errno(f, msg, errno); 378} 379 380char editedhost[32]; 381 382void edithost(char *pat, char *host) 383{ 384 char *res = editedhost; 385 386 if (!pat) 387 pat = ""; 388 while (*pat) { 389 switch (*pat) { 390 391 case '#': 392 if (*host) 393 host++; 394 break; 395 396 case '@': 397 if (*host) 398 *res++ = *host++; 399 break; 400 401 default: 402 *res++ = *pat; 403 break; 404 } 405 if (res == &editedhost[sizeof editedhost - 1]) { 406 *res = '\0'; 407 return; 408 } 409 pat++; 410 } 411 if (*host) 412 strlcpy (res, host, 413 sizeof editedhost - (res - editedhost)); 414 else 415 *res = '\0'; 416 editedhost[sizeof editedhost - 1] = '\0'; 417} 418 419static char *putlocation; 420 421void 422putstr(char *s) 423{ 424 425 while (*s) 426 putchr(*s++); 427} 428 429void 430putchr(int cc) 431{ 432 *putlocation++ = cc; 433} 434 435/* 436 * This is split on two lines so that SCCS will not see the M 437 * between two % signs and expand it... 438 */ 439static char fmtstr[] = { "%l:%M" "%P on %A, %d %B %Y" }; 440 441void putf(char *cp, char *where) 442{ 443#ifdef HAVE_UNAME 444 struct utsname name; 445#endif 446 char *slash; 447 time_t t; 448 char db[100]; 449 450 /* if we don't have uname, set these to sensible values */ 451 char *sysname = "Unix", 452 *machine = "", 453 *release = "", 454 *version = ""; 455 456#ifdef HAVE_UNAME 457 uname(&name); 458 sysname=name.sysname; 459 machine=name.machine; 460 release=name.release; 461 version=name.version; 462#endif 463 464 putlocation = where; 465 466 while (*cp) { 467 if (*cp != '%') { 468 putchr(*cp++); 469 continue; 470 } 471 switch (*++cp) { 472 473 case 't': 474#ifdef STREAMSPTY 475 /* names are like /dev/pts/2 -- we want pts/2 */ 476 slash = strchr(line+1, '/'); 477#else 478 slash = strrchr(line, '/'); 479#endif 480 if (slash == (char *) 0) 481 putstr(line); 482 else 483 putstr(&slash[1]); 484 break; 485 486 case 'h': 487 putstr(editedhost); 488 break; 489 490 case 's': 491 putstr(sysname); 492 break; 493 494 case 'm': 495 putstr(machine); 496 break; 497 498 case 'r': 499 putstr(release); 500 break; 501 502 case 'v': 503 putstr(version); 504 break; 505 506 case 'd': 507 time(&t); 508 strftime(db, sizeof(db), fmtstr, localtime(&t)); 509 putstr(db); 510 break; 511 512 case '%': 513 putchr('%'); 514 break; 515 } 516 cp++; 517 } 518} 519 520#ifdef DIAGNOSTICS 521/* 522 * Print telnet options and commands in plain text, if possible. 523 */ 524void 525printoption(char *fmt, int option) 526{ 527 if (TELOPT_OK(option)) 528 output_data("%s %s\r\n", 529 fmt, 530 TELOPT(option)); 531 else if (TELCMD_OK(option)) 532 output_data("%s %s\r\n", 533 fmt, 534 TELCMD(option)); 535 else 536 output_data("%s %d\r\n", 537 fmt, 538 option); 539 return; 540} 541 542void 543printsub(int direction, unsigned char *pointer, int length) 544 /* '<' or '>' */ 545 /* where suboption data sits */ 546 /* length of suboption data */ 547{ 548 int i = 0; 549 unsigned char buf[512]; 550 551 if (!(diagnostic & TD_OPTIONS)) 552 return; 553 554 if (direction) { 555 output_data("td: %s suboption ", 556 direction == '<' ? "recv" : "send"); 557 if (length >= 3) { 558 int j; 559 560 i = pointer[length-2]; 561 j = pointer[length-1]; 562 563 if (i != IAC || j != SE) { 564 output_data("(terminated by "); 565 if (TELOPT_OK(i)) 566 output_data("%s ", 567 TELOPT(i)); 568 else if (TELCMD_OK(i)) 569 output_data("%s ", 570 TELCMD(i)); 571 else 572 output_data("%d ", 573 i); 574 if (TELOPT_OK(j)) 575 output_data("%s", 576 TELOPT(j)); 577 else if (TELCMD_OK(j)) 578 output_data("%s", 579 TELCMD(j)); 580 else 581 output_data("%d", 582 j); 583 output_data(", not IAC SE!) "); 584 } 585 } 586 length -= 2; 587 } 588 if (length < 1) { 589 output_data("(Empty suboption??\?)"); 590 return; 591 } 592 switch (pointer[0]) { 593 case TELOPT_TTYPE: 594 output_data("TERMINAL-TYPE "); 595 switch (pointer[1]) { 596 case TELQUAL_IS: 597 output_data("IS \"%.*s\"", 598 length-2, 599 (char *)pointer+2); 600 break; 601 case TELQUAL_SEND: 602 output_data("SEND"); 603 break; 604 default: 605 output_data("- unknown qualifier %d (0x%x).", 606 pointer[1], pointer[1]); 607 } 608 break; 609 case TELOPT_TSPEED: 610 output_data("TERMINAL-SPEED"); 611 if (length < 2) { 612 output_data(" (empty suboption??\?)"); 613 break; 614 } 615 switch (pointer[1]) { 616 case TELQUAL_IS: 617 output_data(" IS %.*s", length-2, (char *)pointer+2); 618 break; 619 default: 620 if (pointer[1] == 1) 621 output_data(" SEND"); 622 else 623 output_data(" %d (unknown)", pointer[1]); 624 for (i = 2; i < length; i++) { 625 output_data(" ?%d?", pointer[i]); 626 } 627 break; 628 } 629 break; 630 631 case TELOPT_LFLOW: 632 output_data("TOGGLE-FLOW-CONTROL"); 633 if (length < 2) { 634 output_data(" (empty suboption??\?)"); 635 break; 636 } 637 switch (pointer[1]) { 638 case LFLOW_OFF: 639 output_data(" OFF"); 640 break; 641 case LFLOW_ON: 642 output_data(" ON"); 643 break; 644 case LFLOW_RESTART_ANY: 645 output_data(" RESTART-ANY"); 646 break; 647 case LFLOW_RESTART_XON: 648 output_data(" RESTART-XON"); 649 break; 650 default: 651 output_data(" %d (unknown)", 652 pointer[1]); 653 } 654 for (i = 2; i < length; i++) { 655 output_data(" ?%d?", 656 pointer[i]); 657 } 658 break; 659 660 case TELOPT_NAWS: 661 output_data("NAWS"); 662 if (length < 2) { 663 output_data(" (empty suboption??\?)"); 664 break; 665 } 666 if (length == 2) { 667 output_data(" ?%d?", 668 pointer[1]); 669 break; 670 } 671 output_data(" %u %u(%u)", 672 pointer[1], 673 pointer[2], 674 (((unsigned int)pointer[1])<<8) + pointer[2]); 675 if (length == 4) { 676 output_data(" ?%d?", 677 pointer[3]); 678 break; 679 } 680 output_data(" %u %u(%u)", 681 pointer[3], 682 pointer[4], 683 (((unsigned int)pointer[3])<<8) + pointer[4]); 684 for (i = 5; i < length; i++) { 685 output_data(" ?%d?", 686 pointer[i]); 687 } 688 break; 689 690 case TELOPT_LINEMODE: 691 output_data("LINEMODE "); 692 if (length < 2) { 693 output_data(" (empty suboption??\?)"); 694 break; 695 } 696 switch (pointer[1]) { 697 case WILL: 698 output_data("WILL "); 699 goto common; 700 case WONT: 701 output_data("WONT "); 702 goto common; 703 case DO: 704 output_data("DO "); 705 goto common; 706 case DONT: 707 output_data("DONT "); 708 common: 709 if (length < 3) { 710 output_data("(no option??\?)"); 711 break; 712 } 713 switch (pointer[2]) { 714 case LM_FORWARDMASK: 715 output_data("Forward Mask"); 716 for (i = 3; i < length; i++) { 717 output_data(" %x", pointer[i]); 718 } 719 break; 720 default: 721 output_data("%d (unknown)", 722 pointer[2]); 723 for (i = 3; i < length; i++) { 724 output_data(" %d", 725 pointer[i]); 726 } 727 break; 728 } 729 break; 730 731 case LM_SLC: 732 output_data("SLC"); 733 for (i = 2; i < length - 2; i += 3) { 734 if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 735 output_data(" %s", 736 SLC_NAME(pointer[i+SLC_FUNC])); 737 else 738 output_data(" %d", 739 pointer[i+SLC_FUNC]); 740 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 741 case SLC_NOSUPPORT: 742 output_data(" NOSUPPORT"); 743 break; 744 case SLC_CANTCHANGE: 745 output_data(" CANTCHANGE"); 746 break; 747 case SLC_VARIABLE: 748 output_data(" VARIABLE"); 749 break; 750 case SLC_DEFAULT: 751 output_data(" DEFAULT"); 752 break; 753 } 754 output_data("%s%s%s", 755 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 756 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 757 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 758 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 759 SLC_FLUSHOUT| SLC_LEVELBITS)) { 760 output_data("(0x%x)", 761 pointer[i+SLC_FLAGS]); 762 } 763 output_data(" %d;", 764 pointer[i+SLC_VALUE]); 765 if ((pointer[i+SLC_VALUE] == IAC) && 766 (pointer[i+SLC_VALUE+1] == IAC)) 767 i++; 768 } 769 for (; i < length; i++) { 770 output_data(" ?%d?", 771 pointer[i]); 772 } 773 break; 774 775 case LM_MODE: 776 output_data("MODE "); 777 if (length < 3) { 778 output_data("(no mode??\?)"); 779 break; 780 } 781 { 782 char tbuf[32]; 783 snprintf(tbuf, 784 sizeof(tbuf), 785 "%s%s%s%s%s", 786 pointer[2]&MODE_EDIT ? "|EDIT" : "", 787 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 788 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 789 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 790 pointer[2]&MODE_ACK ? "|ACK" : ""); 791 output_data("%s", 792 tbuf[1] ? &tbuf[1] : "0"); 793 } 794 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { 795 output_data(" (0x%x)", 796 pointer[2]); 797 } 798 for (i = 3; i < length; i++) { 799 output_data(" ?0x%x?", 800 pointer[i]); 801 } 802 break; 803 default: 804 output_data("%d (unknown)", 805 pointer[1]); 806 for (i = 2; i < length; i++) { 807 output_data(" %d", pointer[i]); 808 } 809 } 810 break; 811 812 case TELOPT_STATUS: { 813 char *cp; 814 int j, k; 815 816 output_data("STATUS"); 817 818 switch (pointer[1]) { 819 default: 820 if (pointer[1] == TELQUAL_SEND) 821 output_data(" SEND"); 822 else 823 output_data(" %d (unknown)", 824 pointer[1]); 825 for (i = 2; i < length; i++) { 826 output_data(" ?%d?", 827 pointer[i]); 828 } 829 break; 830 case TELQUAL_IS: 831 output_data(" IS\r\n"); 832 833 for (i = 2; i < length; i++) { 834 switch(pointer[i]) { 835 case DO: cp = "DO"; goto common2; 836 case DONT: cp = "DONT"; goto common2; 837 case WILL: cp = "WILL"; goto common2; 838 case WONT: cp = "WONT"; goto common2; 839 common2: 840 i++; 841 if (TELOPT_OK(pointer[i])) 842 output_data(" %s %s", 843 cp, 844 TELOPT(pointer[i])); 845 else 846 output_data(" %s %d", 847 cp, 848 pointer[i]); 849 850 output_data("\r\n"); 851 break; 852 853 case SB: 854 output_data(" SB "); 855 i++; 856 j = k = i; 857 while (j < length) { 858 if (pointer[j] == SE) { 859 if (j+1 == length) 860 break; 861 if (pointer[j+1] == SE) 862 j++; 863 else 864 break; 865 } 866 pointer[k++] = pointer[j++]; 867 } 868 printsub(0, &pointer[i], k - i); 869 if (i < length) { 870 output_data(" SE"); 871 i = j; 872 } else 873 i = j - 1; 874 875 output_data("\r\n"); 876 877 break; 878 879 default: 880 output_data(" %d", 881 pointer[i]); 882 break; 883 } 884 } 885 break; 886 } 887 break; 888 } 889 890 case TELOPT_XDISPLOC: 891 output_data("X-DISPLAY-LOCATION "); 892 switch (pointer[1]) { 893 case TELQUAL_IS: 894 output_data("IS \"%.*s\"", 895 length-2, 896 (char *)pointer+2); 897 break; 898 case TELQUAL_SEND: 899 output_data("SEND"); 900 break; 901 default: 902 output_data("- unknown qualifier %d (0x%x).", 903 pointer[1], pointer[1]); 904 } 905 break; 906 907 case TELOPT_NEW_ENVIRON: 908 output_data("NEW-ENVIRON "); 909 goto env_common1; 910 case TELOPT_OLD_ENVIRON: 911 output_data("OLD-ENVIRON"); 912 env_common1: 913 switch (pointer[1]) { 914 case TELQUAL_IS: 915 output_data("IS "); 916 goto env_common; 917 case TELQUAL_SEND: 918 output_data("SEND "); 919 goto env_common; 920 case TELQUAL_INFO: 921 output_data("INFO "); 922 env_common: 923 { 924 int noquote = 2; 925 for (i = 2; i < length; i++ ) { 926 switch (pointer[i]) { 927 case NEW_ENV_VAR: 928 output_data("\" VAR " + noquote); 929 noquote = 2; 930 break; 931 932 case NEW_ENV_VALUE: 933 output_data("\" VALUE " + noquote); 934 noquote = 2; 935 break; 936 937 case ENV_ESC: 938 output_data("\" ESC " + noquote); 939 noquote = 2; 940 break; 941 942 case ENV_USERVAR: 943 output_data("\" USERVAR " + noquote); 944 noquote = 2; 945 break; 946 947 default: 948 if (isprint(pointer[i]) && pointer[i] != '"') { 949 if (noquote) { 950 output_data ("\""); 951 noquote = 0; 952 } 953 output_data ("%c", pointer[i]); 954 } else { 955 output_data("\" %03o " + noquote, 956 pointer[i]); 957 noquote = 2; 958 } 959 break; 960 } 961 } 962 if (!noquote) 963 output_data ("\""); 964 break; 965 } 966 } 967 break; 968 969#ifdef AUTHENTICATION 970 case TELOPT_AUTHENTICATION: 971 output_data("AUTHENTICATION"); 972 973 if (length < 2) { 974 output_data(" (empty suboption??\?)"); 975 break; 976 } 977 switch (pointer[1]) { 978 case TELQUAL_REPLY: 979 case TELQUAL_IS: 980 output_data(" %s ", 981 (pointer[1] == TELQUAL_IS) ? 982 "IS" : "REPLY"); 983 if (AUTHTYPE_NAME_OK(pointer[2])) 984 output_data("%s ", 985 AUTHTYPE_NAME(pointer[2])); 986 else 987 output_data("%d ", 988 pointer[2]); 989 if (length < 3) { 990 output_data("(partial suboption??\?)"); 991 break; 992 } 993 output_data("%s|%s", 994 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 995 "CLIENT" : "SERVER", 996 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 997 "MUTUAL" : "ONE-WAY"); 998 999 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 1000 output_data("%s", 1001 buf); 1002 break; 1003 1004 case TELQUAL_SEND: 1005 i = 2; 1006 output_data(" SEND "); 1007 while (i < length) { 1008 if (AUTHTYPE_NAME_OK(pointer[i])) 1009 output_data("%s ", 1010 AUTHTYPE_NAME(pointer[i])); 1011 else 1012 output_data("%d ", 1013 pointer[i]); 1014 if (++i >= length) { 1015 output_data("(partial suboption??\?)"); 1016 break; 1017 } 1018 output_data("%s|%s ", 1019 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 1020 "CLIENT" : "SERVER", 1021 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 1022 "MUTUAL" : "ONE-WAY"); 1023 ++i; 1024 } 1025 break; 1026 1027 case TELQUAL_NAME: 1028 i = 2; 1029 output_data(" NAME \"%.*s\"", 1030 length - 2, 1031 pointer); 1032 break; 1033 1034 default: 1035 for (i = 2; i < length; i++) { 1036 output_data(" ?%d?", 1037 pointer[i]); 1038 } 1039 break; 1040 } 1041 break; 1042#endif 1043 1044#ifdef ENCRYPTION 1045 case TELOPT_ENCRYPT: 1046 output_data("ENCRYPT"); 1047 if (length < 2) { 1048 output_data(" (empty suboption?)"); 1049 break; 1050 } 1051 switch (pointer[1]) { 1052 case ENCRYPT_START: 1053 output_data(" START"); 1054 break; 1055 1056 case ENCRYPT_END: 1057 output_data(" END"); 1058 break; 1059 1060 case ENCRYPT_REQSTART: 1061 output_data(" REQUEST-START"); 1062 break; 1063 1064 case ENCRYPT_REQEND: 1065 output_data(" REQUEST-END"); 1066 break; 1067 1068 case ENCRYPT_IS: 1069 case ENCRYPT_REPLY: 1070 output_data(" %s ", 1071 (pointer[1] == ENCRYPT_IS) ? 1072 "IS" : "REPLY"); 1073 if (length < 3) { 1074 output_data(" (partial suboption?)"); 1075 break; 1076 } 1077 if (ENCTYPE_NAME_OK(pointer[2])) 1078 output_data("%s ", 1079 ENCTYPE_NAME(pointer[2])); 1080 else 1081 output_data(" %d (unknown)", 1082 pointer[2]); 1083 1084 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 1085 output_data("%s", 1086 buf); 1087 break; 1088 1089 case ENCRYPT_SUPPORT: 1090 i = 2; 1091 output_data(" SUPPORT "); 1092 while (i < length) { 1093 if (ENCTYPE_NAME_OK(pointer[i])) 1094 output_data("%s ", 1095 ENCTYPE_NAME(pointer[i])); 1096 else 1097 output_data("%d ", 1098 pointer[i]); 1099 i++; 1100 } 1101 break; 1102 1103 case ENCRYPT_ENC_KEYID: 1104 output_data(" ENC_KEYID %d", pointer[1]); 1105 goto encommon; 1106 1107 case ENCRYPT_DEC_KEYID: 1108 output_data(" DEC_KEYID %d", pointer[1]); 1109 goto encommon; 1110 1111 default: 1112 output_data(" %d (unknown)", pointer[1]); 1113 encommon: 1114 for (i = 2; i < length; i++) { 1115 output_data(" %d", pointer[i]); 1116 } 1117 break; 1118 } 1119 break; 1120#endif 1121 1122 default: 1123 if (TELOPT_OK(pointer[0])) 1124 output_data("%s (unknown)", 1125 TELOPT(pointer[0])); 1126 else 1127 output_data("%d (unknown)", 1128 pointer[i]); 1129 for (i = 1; i < length; i++) { 1130 output_data(" %d", pointer[i]); 1131 } 1132 break; 1133 } 1134 output_data("\r\n"); 1135} 1136 1137/* 1138 * Dump a data buffer in hex and ascii to the output data stream. 1139 */ 1140void 1141printdata(char *tag, char *ptr, int cnt) 1142{ 1143 int i; 1144 char xbuf[30]; 1145 1146 while (cnt) { 1147 /* flush net output buffer if no room for new data) */ 1148 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 1149 netflush(); 1150 } 1151 1152 /* add a line of output */ 1153 output_data("%s: ", tag); 1154 for (i = 0; i < 20 && cnt; i++) { 1155 output_data("%02x", *ptr); 1156 if (isprint(*ptr)) { 1157 xbuf[i] = *ptr; 1158 } else { 1159 xbuf[i] = '.'; 1160 } 1161 if (i % 2) { 1162 output_data(" "); 1163 } 1164 cnt--; 1165 ptr++; 1166 } 1167 xbuf[i] = '\0'; 1168 output_data(" %s\r\n", xbuf); 1169 } 1170} 1171#endif /* DIAGNOSTICS */ 1172