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