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