1 /* $NetBSD: utility.c,v 1.32 2012/01/09 16:36:48 christos 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.32 2012/01/09 16:36:48 christos 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(const char *pat, const 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 const char fmtstr[] = { "%l:%M\ 431 %p on %A, %d %B %Y" }; 432 433 char * 434 putf(const 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 const 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 static const char NQ[] = "\" "; 845 const char *noquote = NQ; 846 for (i = 2; i < length; i++ ) { 847 switch (pointer[i]) { 848 case NEW_ENV_VAR: 849 output_data("%sVAR ", noquote); 850 noquote = NQ; 851 break; 852 853 case NEW_ENV_VALUE: 854 output_data("%sVALUE ", noquote); 855 noquote = NQ; 856 break; 857 858 case ENV_ESC: 859 output_data("%sESC ", noquote); 860 noquote = NQ; 861 break; 862 863 case ENV_USERVAR: 864 output_data("%sUSERVAR ", noquote); 865 noquote = NQ; 866 break; 867 868 default: 869 if (isprint(pointer[i]) && pointer[i] != '"') { 870 if (*noquote) { 871 output_data("\""); 872 noquote = ""; 873 } 874 output_data("%c", pointer[i]); 875 } else { 876 output_data("%s%03o ", noquote, pointer[i]); 877 noquote = NQ; 878 } 879 break; 880 } 881 } 882 if (!noquote) 883 output_data("\""); 884 break; 885 } 886 } 887 break; 888 889 #ifdef AUTHENTICATION 890 case TELOPT_AUTHENTICATION: 891 output_data("AUTHENTICATION"); 892 893 if (length < 2) { 894 output_data(" (empty suboption??\?)"); 895 break; 896 } 897 switch (pointer[1]) { 898 case TELQUAL_REPLY: 899 case TELQUAL_IS: 900 output_data(" %s ", (pointer[1] == TELQUAL_IS) ? 901 "IS" : "REPLY"); 902 if (AUTHTYPE_NAME_OK(pointer[2])) 903 output_data("%s ", AUTHTYPE_NAME(pointer[2])); 904 else 905 output_data("%d ", pointer[2]); 906 if (length < 3) { 907 output_data("(partial suboption??\?)"); 908 break; 909 } 910 output_data("%s|%s", 911 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 912 "CLIENT" : "SERVER", 913 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 914 "MUTUAL" : "ONE-WAY"); 915 916 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 917 output_data("%s", buf); 918 break; 919 920 case TELQUAL_SEND: 921 i = 2; 922 output_data(" SEND "); 923 while (i < length) { 924 if (AUTHTYPE_NAME_OK(pointer[i])) 925 output_data("%s ", AUTHTYPE_NAME(pointer[i])); 926 else 927 output_data("%d ", pointer[i]); 928 if (++i >= length) { 929 output_data("(partial suboption??\?)"); 930 break; 931 } 932 output_data("%s|%s ", 933 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 934 "CLIENT" : "SERVER", 935 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 936 "MUTUAL" : "ONE-WAY"); 937 ++i; 938 } 939 break; 940 941 case TELQUAL_NAME: 942 i = 2; 943 output_data(" NAME \""); 944 while (i < length) { 945 if (isprint(pointer[i])) 946 output_data("%c", pointer[i++]); 947 else 948 output_data("\"%03o\"",pointer[i++]); 949 } 950 output_data("\""); 951 break; 952 953 default: 954 for (i = 2; i < length; i++) 955 output_data(" ?%d?", pointer[i]); 956 break; 957 } 958 break; 959 #endif 960 961 #ifdef ENCRYPTION 962 case TELOPT_ENCRYPT: 963 output_data("ENCRYPT"); 964 if (length < 2) { 965 output_data(" (empty suboption??\?)"); 966 break; 967 } 968 switch (pointer[1]) { 969 case ENCRYPT_START: 970 output_data(" START"); 971 break; 972 973 case ENCRYPT_END: 974 output_data(" END"); 975 break; 976 977 case ENCRYPT_REQSTART: 978 output_data(" REQUEST-START"); 979 break; 980 981 case ENCRYPT_REQEND: 982 output_data(" REQUEST-END"); 983 break; 984 985 case ENCRYPT_IS: 986 case ENCRYPT_REPLY: 987 output_data(" %s ", (pointer[1] == ENCRYPT_IS) ? 988 "IS" : "REPLY"); 989 if (length < 3) { 990 output_data(" (partial suboption??\?)"); 991 break; 992 } 993 if (ENCTYPE_NAME_OK(pointer[2])) 994 output_data("%s ", ENCTYPE_NAME(pointer[2])); 995 else 996 output_data(" %d (unknown)", pointer[2]); 997 998 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 999 output_data("%s", buf); 1000 break; 1001 1002 case ENCRYPT_SUPPORT: 1003 i = 2; 1004 output_data(" SUPPORT "); 1005 while (i < length) { 1006 if (ENCTYPE_NAME_OK(pointer[i])) 1007 output_data("%s ", ENCTYPE_NAME(pointer[i])); 1008 else 1009 output_data("%d ", pointer[i]); 1010 i++; 1011 } 1012 break; 1013 1014 case ENCRYPT_ENC_KEYID: 1015 output_data(" ENC_KEYID"); 1016 goto encommon; 1017 1018 case ENCRYPT_DEC_KEYID: 1019 output_data(" DEC_KEYID"); 1020 goto encommon; 1021 1022 default: 1023 output_data(" %d (unknown)", pointer[1]); 1024 encommon: 1025 for (i = 2; i < length; i++) 1026 output_data(" %d", pointer[i]); 1027 break; 1028 } 1029 break; 1030 #endif /* ENCRYPTION */ 1031 1032 default: 1033 if (TELOPT_OK(pointer[0])) 1034 output_data("%s (unknown)", TELOPT(pointer[0])); 1035 else 1036 output_data("%d (unknown)", pointer[i]); 1037 for (i = 1; i < length; i++) 1038 output_data(" %d", pointer[i]); 1039 break; 1040 } 1041 output_data("\r\n"); 1042 } 1043 1044 /* 1045 * Dump a data buffer in hex and ascii to the output data stream. 1046 */ 1047 void 1048 printdata(const char *tag, char *ptr, int cnt) 1049 { 1050 int i; 1051 char xbuf[30]; 1052 1053 while (cnt) { 1054 /* flush net output buffer if no room for new data) */ 1055 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 1056 netflush(); 1057 } 1058 1059 /* add a line of output */ 1060 output_data("%s: ", tag); 1061 for (i = 0; i < 20 && cnt; i++) { 1062 output_data("%02x", *ptr); 1063 if (isprint((unsigned char)*ptr)) { 1064 xbuf[i] = *ptr; 1065 } else { 1066 xbuf[i] = '.'; 1067 } 1068 if (i % 2) 1069 output_data(" "); 1070 cnt--; 1071 ptr++; 1072 } 1073 xbuf[i] = '\0'; 1074 output_data(" %s\r\n", xbuf); 1075 } 1076 } 1077 #endif /* DIAGNOSTICS */ 1078