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