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