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