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