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