1 /* $NetBSD: utility.c,v 1.27 2005/02/06 17:30:33 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 #ifndef lint 34 #if 0 35 static char sccsid[] = "@(#)utility.c 8.4 (Berkeley) 5/30/95"; 36 #else 37 __RCSID("$NetBSD: utility.c,v 1.27 2005/02/06 17:30:33 agc Exp $"); 38 #endif 39 #endif /* not lint */ 40 41 #include <sys/utsname.h> 42 #define PRINTOPTIONS 43 #include "telnetd.h" 44 45 char *nextitem(char *); 46 void putstr(char *); 47 48 extern int not42; 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) { 69 netflush(); 70 } 71 ncc = read(net, netibuf, sizeof netibuf); 72 if (ncc < 0) { 73 syslog(LOG_ERR, "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 /* socket number */) 93 { 94 struct pollfd set[1]; 95 int value; 96 97 set[0].fd = s; 98 set[0].events = POLLPRI; 99 do { 100 value = poll(set, 1, 0); 101 } while ((value == -1) && (errno == EINTR)); 102 103 if (value < 0) { 104 fatalperror(pty, "poll"); 105 } 106 if (set[0].revents & POLLPRI) { 107 return 1; 108 } else { 109 return 0; 110 } 111 } 112 113 void 114 ptyflush(void) 115 { 116 int n; 117 118 if ((n = pfrontp - pbackp) > 0) { 119 DIAG((TD_REPORT | TD_PTYDATA), 120 { output_data("td: ptyflush %d chars\r\n", n); }); 121 DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); 122 n = write(pty, pbackp, n); 123 } 124 if (n < 0) { 125 if (errno == EWOULDBLOCK || errno == EINTR) 126 return; 127 cleanup(0); 128 } 129 pbackp += n; 130 if (pbackp == pfrontp) 131 pbackp = pfrontp = ptyobuf; 132 } 133 134 /* 135 * nextitem() 136 * 137 * Return the address of the next "item" in the TELNET data 138 * stream. This will be the address of the next character if 139 * the current address is a user data character, or it will 140 * be the address of the character following the TELNET command 141 * if the current address is a TELNET IAC ("I Am a Command") 142 * character. 143 */ 144 char * 145 nextitem(char *current) 146 { 147 if ((*current&0xff) != IAC) { 148 return current+1; 149 } 150 switch (*(current+1)&0xff) { 151 case DO: 152 case DONT: 153 case WILL: 154 case WONT: 155 return current+3; 156 case SB: /* loop forever looking for the SE */ 157 { 158 char *look = current+2; 159 160 for (;;) { 161 if ((*look++&0xff) == IAC) { 162 if ((*look++&0xff) == SE) { 163 return look; 164 } 165 } 166 } 167 } 168 default: 169 return current+2; 170 } 171 } /* end of nextitem */ 172 173 174 /* 175 * netclear() 176 * 177 * We are about to do a TELNET SYNCH operation. Clear 178 * the path to the network. 179 * 180 * Things are a bit tricky since we may have sent the first 181 * byte or so of a previous TELNET command into the network. 182 * So, we have to scan the network buffer from the beginning 183 * until we are up to where we want to be. 184 * 185 * A side effect of what we do, just to keep things 186 * simple, is to clear the urgent data pointer. The principal 187 * caller should be setting the urgent data pointer AFTER calling 188 * us in any case. 189 */ 190 void 191 netclear(void) 192 { 193 char *thisitem, *next; 194 char *good; 195 #define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 196 ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 197 198 #ifdef ENCRYPTION 199 thisitem = nclearto > netobuf ? nclearto : netobuf; 200 #else /* ENCRYPTION */ 201 thisitem = netobuf; 202 #endif /* ENCRYPTION */ 203 204 while ((next = nextitem(thisitem)) <= nbackp) { 205 thisitem = next; 206 } 207 208 /* Now, thisitem is first before/at boundary. */ 209 210 #ifdef ENCRYPTION 211 good = nclearto > netobuf ? nclearto : netobuf; 212 #else /* ENCRYPTION */ 213 good = netobuf; /* where the good bytes go */ 214 #endif /* ENCRYPTION */ 215 216 while (nfrontp > thisitem) { 217 if (wewant(thisitem)) { 218 int length; 219 220 next = thisitem; 221 do { 222 next = nextitem(next); 223 } while (wewant(next) && (nfrontp > next)); 224 length = next-thisitem; 225 memmove(good, thisitem, length); 226 good += length; 227 thisitem = next; 228 } else { 229 thisitem = nextitem(thisitem); 230 } 231 } 232 233 nbackp = netobuf; 234 nfrontp = good; /* next byte to be sent */ 235 neturg = 0; 236 } /* end of netclear */ 237 238 /* 239 * netflush 240 * Send as much data as possible to the network, 241 * handling requests for urgent data. 242 */ 243 void 244 netflush(void) 245 { 246 int n; 247 248 if ((n = nfrontp - nbackp) > 0) { 249 DIAG(TD_REPORT, 250 { output_data("td: netflush %d chars\r\n", n); 251 n = nfrontp - nbackp; /* re-compute count */ 252 }); 253 #ifdef ENCRYPTION 254 if (encrypt_output) { 255 char *s = nclearto ? nclearto : nbackp; 256 if (nfrontp - s > 0) { 257 (*encrypt_output)((unsigned char *)s, nfrontp - s); 258 nclearto = nfrontp; 259 } 260 } 261 #endif /* ENCRYPTION */ 262 /* 263 * if no urgent data, or if the other side appears to be an 264 * old 4.2 client (and thus unable to survive TCP urgent data), 265 * write the entire buffer in non-OOB mode. 266 */ 267 if ((neturg == 0) || (not42 == 0)) { 268 n = write(net, nbackp, n); /* normal write */ 269 } else { 270 n = neturg - nbackp; 271 /* 272 * In 4.2 (and 4.3) systems, there is some question about 273 * what byte in a sendOOB operation is the "OOB" data. 274 * To make ourselves compatible, we only send ONE byte 275 * out of band, the one WE THINK should be OOB (though 276 * we really have more the TCP philosophy of urgent data 277 * rather than the Unix philosophy of OOB data). 278 */ 279 if (n > 1) { 280 n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 281 } else { 282 n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 283 } 284 } 285 } 286 if (n < 0) { 287 if (errno == EWOULDBLOCK || errno == EINTR) 288 return; 289 cleanup(0); 290 } 291 nbackp += n; 292 #ifdef ENCRYPTION 293 if (nbackp > nclearto) 294 nclearto = 0; 295 #endif /* ENCRYPTION */ 296 if (nbackp >= neturg) { 297 neturg = 0; 298 } 299 if (nbackp == nfrontp) { 300 nbackp = nfrontp = netobuf; 301 #ifdef ENCRYPTION 302 nclearto = 0; 303 #endif /* ENCRYPTION */ 304 } 305 return; 306 } /* end of netflush */ 307 308 309 /* 310 * writenet 311 * 312 * Just a handy little function to write a bit of raw data to the net. 313 * It will force a transmit of the buffer if necessary 314 * 315 * arguments 316 * ptr - A pointer to a character string to write 317 * len - How many bytes to write 318 */ 319 void 320 writenet(unsigned char *ptr, int len) 321 { 322 /* flush buffer if no room for new data) */ 323 if ((&netobuf[BUFSIZ] - nfrontp) < len) { 324 /* if this fails, don't worry, buffer is a little big */ 325 netflush(); 326 } 327 328 memmove(nfrontp, ptr, len); 329 nfrontp += len; 330 331 } /* end of writenet */ 332 333 334 /* 335 * miscellaneous functions doing a variety of little jobs follow ... 336 */ 337 void 338 fatal(int f, const char *msg) 339 { 340 char buf[BUFSIZ]; 341 342 (void)snprintf(buf, sizeof buf, "telnetd: %s.\r\n", msg); 343 #ifdef ENCRYPTION 344 if (encrypt_output) { 345 /* 346 * Better turn off encryption first.... 347 * Hope it flushes... 348 */ 349 encrypt_send_end(); 350 netflush(); 351 } 352 #endif /* ENCRYPTION */ 353 (void)write(f, buf, (int)strlen(buf)); 354 sleep(1); /*XXX*/ 355 exit(1); 356 } 357 358 void 359 fatalperror(f, msg) 360 int f; 361 const char *msg; 362 { 363 char buf[BUFSIZ]; 364 365 (void)snprintf(buf, sizeof buf, "%s: %s", msg, strerror(errno)); 366 fatal(f, buf); 367 } 368 369 char editedhost[MAXHOSTNAMELEN]; 370 371 void 372 edithost(char *pat, char *host) 373 { 374 char *res = editedhost; 375 376 if (!pat) 377 pat = ""; 378 while (*pat) { 379 switch (*pat) { 380 381 case '#': 382 if (*host) 383 host++; 384 break; 385 386 case '@': 387 if (*host) 388 *res++ = *host++; 389 break; 390 391 default: 392 *res++ = *pat; 393 break; 394 } 395 if (res == &editedhost[sizeof editedhost - 1]) { 396 *res = '\0'; 397 return; 398 } 399 pat++; 400 } 401 if (*host) 402 (void) strncpy(res, host, 403 sizeof editedhost - (res - editedhost) -1); 404 else 405 *res = '\0'; 406 editedhost[sizeof editedhost - 1] = '\0'; 407 } 408 409 static char *putlocation; 410 411 void 412 putstr(char *s) 413 { 414 415 while (*s) 416 putchr(*s++); 417 } 418 419 void 420 putchr(int cc) 421 { 422 *putlocation++ = cc; 423 } 424 425 /* 426 * This is split on two lines so that SCCS will not see the M 427 * between two % signs and expand it... 428 */ 429 static char fmtstr[] = { "%l:%M\ 430 %p on %A, %d %B %Y" }; 431 432 char * 433 putf(char *cp, char *where) 434 { 435 char *slash; 436 time_t t; 437 char db[100]; 438 struct utsname utsinfo; 439 440 uname(&utsinfo); 441 442 putlocation = where; 443 444 while (*cp) { 445 if (*cp != '%') { 446 putchr(*cp++); 447 continue; 448 } 449 switch (*++cp) { 450 451 case 't': 452 slash = strrchr(line, '/'); 453 if (slash == (char *) 0) 454 putstr(line); 455 else 456 putstr(&slash[1]); 457 break; 458 459 case 'h': 460 putstr(editedhost); 461 break; 462 463 case 'd': 464 (void)time(&t); 465 (void)strftime(db, sizeof(db), fmtstr, localtime(&t)); 466 putstr(db); 467 break; 468 469 case '%': 470 putchr('%'); 471 break; 472 473 case 's': 474 putstr(utsinfo.sysname); 475 break; 476 477 case 'm': 478 putstr(utsinfo.machine); 479 break; 480 481 case 'r': 482 putstr(utsinfo.release); 483 break; 484 485 case 'v': 486 putstr(utsinfo.version); 487 break; 488 } 489 cp++; 490 } 491 492 return (putlocation); 493 } 494 495 #ifdef DIAGNOSTICS 496 /* 497 * Print telnet options and commands in plain text, if possible. 498 */ 499 void 500 printoption(const char *fmt, int option) 501 { 502 if (TELOPT_OK(option)) 503 output_data("%s %s\r\n", fmt, TELOPT(option)); 504 else if (TELCMD_OK(option)) 505 output_data("%s %s\r\n", fmt, TELCMD(option)); 506 else 507 output_data("%s %d\r\n", fmt, option); 508 return; 509 } 510 511 void 512 printsub( 513 int direction, /* '<' or '>' */ 514 unsigned char *pointer, /* where suboption data sits */ 515 int length) /* length of suboption data */ 516 { 517 int i = 0; 518 #if defined(AUTHENTICATION) || defined(ENCRYPTION) 519 char buf[512]; 520 #endif 521 522 if (!(diagnostic & TD_OPTIONS)) 523 return; 524 525 if (direction) { 526 output_data("td: %s suboption ", 527 direction == '<' ? "recv" : "send"); 528 if (length >= 3) { 529 int j; 530 531 i = pointer[length - 2]; 532 j = pointer[length - 1]; 533 534 if (i != IAC || j != SE) { 535 output_data("(terminated by "); 536 if (TELOPT_OK(i)) 537 output_data("%s ", TELOPT(i)); 538 else if (TELCMD_OK(i)) 539 output_data("%s ", TELCMD(i)); 540 else 541 output_data("%d ", i); 542 if (TELOPT_OK(j)) 543 output_data("%s", TELOPT(j)); 544 else if (TELCMD_OK(j)) 545 output_data("%s", TELCMD(j)); 546 else 547 output_data("%d", j); 548 output_data(", not IAC SE!) "); 549 } 550 } 551 length -= 2; 552 } 553 if (length < 1) { 554 output_data("(Empty suboption??\?)"); 555 return; 556 } 557 switch (pointer[0]) { 558 case TELOPT_TTYPE: 559 output_data("TERMINAL-TYPE "); 560 switch (pointer[1]) { 561 case TELQUAL_IS: 562 output_data("IS \"%.*s\"", length-2, (char *)pointer+2); 563 break; 564 case TELQUAL_SEND: 565 output_data("SEND"); 566 break; 567 default: 568 output_data("- unknown qualifier %d (0x%x).", 569 pointer[1], pointer[1]); 570 } 571 break; 572 case TELOPT_TSPEED: 573 output_data("TERMINAL-SPEED"); 574 if (length < 2) { 575 output_data(" (empty suboption??\?)"); 576 break; 577 } 578 switch (pointer[1]) { 579 case TELQUAL_IS: 580 output_data(" IS %.*s", length-2, (char *)pointer+2); 581 break; 582 default: 583 if (pointer[1] == 1) 584 output_data(" SEND"); 585 else 586 output_data(" %d (unknown)", pointer[1]); 587 for (i = 2; i < length; i++) { 588 output_data(" ?%d?", pointer[i]); 589 } 590 break; 591 } 592 break; 593 594 case TELOPT_LFLOW: 595 output_data("TOGGLE-FLOW-CONTROL"); 596 if (length < 2) { 597 output_data(" (empty suboption??\?)"); 598 break; 599 } 600 switch (pointer[1]) { 601 case LFLOW_OFF: 602 output_data(" OFF"); break; 603 case LFLOW_ON: 604 output_data(" ON"); break; 605 case LFLOW_RESTART_ANY: 606 output_data(" RESTART-ANY"); break; 607 case LFLOW_RESTART_XON: 608 output_data(" RESTART-XON"); break; 609 default: 610 output_data(" %d (unknown)", pointer[1]); 611 } 612 for (i = 2; i < length; i++) 613 output_data(" ?%d?", pointer[i]); 614 break; 615 616 case TELOPT_NAWS: 617 output_data("NAWS"); 618 if (length < 2) { 619 output_data(" (empty suboption??\?)"); 620 break; 621 } 622 if (length == 2) { 623 output_data(" ?%d?", pointer[1]); 624 break; 625 } 626 output_data(" %d %d (%d)", 627 pointer[1], pointer[2], 628 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); 629 if (length == 4) { 630 output_data(" ?%d?", pointer[3]); 631 break; 632 } 633 output_data(" %d %d (%d)", pointer[3], pointer[4], 634 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); 635 for (i = 5; i < length; i++) { 636 output_data(" ?%d?", pointer[i]); 637 } 638 break; 639 640 case TELOPT_LINEMODE: 641 output_data("LINEMODE "); 642 if (length < 2) { 643 output_data(" (empty suboption??\?)"); 644 break; 645 } 646 switch (pointer[1]) { 647 case WILL: 648 output_data("WILL "); 649 goto common; 650 case WONT: 651 output_data("WONT "); 652 goto common; 653 case DO: 654 output_data("DO "); 655 goto common; 656 case DONT: 657 output_data("DONT "); 658 common: 659 if (length < 3) { 660 output_data("(no option??\?)"); 661 break; 662 } 663 switch (pointer[2]) { 664 case LM_FORWARDMASK: 665 output_data("Forward Mask"); 666 for (i = 3; i < length; i++) 667 output_data(" %x", pointer[i]); 668 break; 669 default: 670 output_data("%d (unknown)", pointer[2]); 671 for (i = 3; i < length; i++) 672 output_data(" %d", pointer[i]); 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 break; 710 711 case LM_MODE: 712 output_data("MODE "); 713 if (length < 3) { 714 output_data("(no mode??\?)"); 715 break; 716 } 717 { 718 char tbuf[32]; 719 720 (void)snprintf(tbuf, sizeof 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 for (i = 3; i < length; i++) 731 output_data(" ?0x%x?", pointer[i]); 732 break; 733 default: 734 output_data("%d (unknown)", pointer[1]); 735 for (i = 2; i < length; i++) 736 output_data(" %d", pointer[i]); 737 } 738 break; 739 740 case TELOPT_STATUS: { 741 char *cp; 742 int j, k; 743 744 output_data("STATUS"); 745 746 switch (pointer[1]) { 747 default: 748 if (pointer[1] == TELQUAL_SEND) 749 output_data(" SEND"); 750 else 751 output_data(" %d (unknown)", pointer[1]); 752 for (i = 2; i < length; i++) 753 output_data(" ?%d?", pointer[i]); 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("%s", "\" VAR " + noquote); 847 noquote = 2; 848 break; 849 850 case NEW_ENV_VALUE: 851 output_data("%s", "\" VALUE " + noquote); 852 noquote = 2; 853 break; 854 855 case ENV_ESC: 856 output_data("%s", "\" ESC " + noquote); 857 noquote = 2; 858 break; 859 860 case ENV_USERVAR: 861 output_data("%s", "\" 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, 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 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 914 output_data("%s", buf); 915 break; 916 917 case TELQUAL_SEND: 918 i = 2; 919 output_data(" SEND "); 920 while (i < length) { 921 if (AUTHTYPE_NAME_OK(pointer[i])) 922 output_data("%s ", AUTHTYPE_NAME(pointer[i])); 923 else 924 output_data("%d ", pointer[i]); 925 if (++i >= length) { 926 output_data("(partial suboption??\?)"); 927 break; 928 } 929 output_data("%s|%s ", 930 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 931 "CLIENT" : "SERVER", 932 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 933 "MUTUAL" : "ONE-WAY"); 934 ++i; 935 } 936 break; 937 938 case TELQUAL_NAME: 939 i = 2; 940 output_data(" NAME \""); 941 while (i < length) { 942 if (isprint(pointer[i])) 943 output_data("%c", pointer[i++]); 944 else 945 output_data("\"%03o\"",pointer[i++]); 946 } 947 output_data("\""); 948 break; 949 950 default: 951 for (i = 2; i < length; i++) 952 output_data(" ?%d?", pointer[i]); 953 break; 954 } 955 break; 956 #endif 957 958 #ifdef ENCRYPTION 959 case TELOPT_ENCRYPT: 960 output_data("ENCRYPT"); 961 if (length < 2) { 962 output_data(" (empty suboption??\?)"); 963 break; 964 } 965 switch (pointer[1]) { 966 case ENCRYPT_START: 967 output_data(" START"); 968 break; 969 970 case ENCRYPT_END: 971 output_data(" END"); 972 break; 973 974 case ENCRYPT_REQSTART: 975 output_data(" REQUEST-START"); 976 break; 977 978 case ENCRYPT_REQEND: 979 output_data(" REQUEST-END"); 980 break; 981 982 case ENCRYPT_IS: 983 case ENCRYPT_REPLY: 984 output_data(" %s ", (pointer[1] == ENCRYPT_IS) ? 985 "IS" : "REPLY"); 986 if (length < 3) { 987 output_data(" (partial suboption??\?)"); 988 break; 989 } 990 if (ENCTYPE_NAME_OK(pointer[2])) 991 output_data("%s ", ENCTYPE_NAME(pointer[2])); 992 else 993 output_data(" %d (unknown)", pointer[2]); 994 995 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 996 output_data("%s", buf); 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 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 break; 1037 } 1038 output_data("\r\n"); 1039 } 1040 1041 /* 1042 * Dump a data buffer in hex and ascii to the output data stream. 1043 */ 1044 void 1045 printdata(char *tag, char *ptr, int cnt) 1046 { 1047 int i; 1048 char xbuf[30]; 1049 1050 while (cnt) { 1051 /* flush net output buffer if no room for new data) */ 1052 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 1053 netflush(); 1054 } 1055 1056 /* add a line of output */ 1057 output_data("%s: ", tag); 1058 for (i = 0; i < 20 && cnt; i++) { 1059 output_data("%02x", *ptr); 1060 if (isprint((unsigned char)*ptr)) { 1061 xbuf[i] = *ptr; 1062 } else { 1063 xbuf[i] = '.'; 1064 } 1065 if (i % 2) 1066 output_data(" "); 1067 cnt--; 1068 ptr++; 1069 } 1070 xbuf[i] = '\0'; 1071 output_data(" %s\r\n", xbuf); 1072 } 1073 } 1074 #endif /* DIAGNOSTICS */ 1075