1 /* $NetBSD: utility.c,v 1.28 2005/03/17 01:34:41 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.28 2005/03/17 01:34:41 christos 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 if ((slash = strstr(line, "/pts/")) == NULL) 453 slash = strrchr(line, '/'); 454 if (slash == (char *) 0) 455 putstr(line); 456 else 457 putstr(&slash[1]); 458 break; 459 460 case 'h': 461 putstr(editedhost); 462 break; 463 464 case 'd': 465 (void)time(&t); 466 (void)strftime(db, sizeof(db), fmtstr, localtime(&t)); 467 putstr(db); 468 break; 469 470 case '%': 471 putchr('%'); 472 break; 473 474 case 's': 475 putstr(utsinfo.sysname); 476 break; 477 478 case 'm': 479 putstr(utsinfo.machine); 480 break; 481 482 case 'r': 483 putstr(utsinfo.release); 484 break; 485 486 case 'v': 487 putstr(utsinfo.version); 488 break; 489 } 490 cp++; 491 } 492 493 return (putlocation); 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( 514 int direction, /* '<' or '>' */ 515 unsigned char *pointer, /* where suboption data sits */ 516 int length) /* length of suboption data */ 517 { 518 int i = 0; 519 #if defined(AUTHENTICATION) || defined(ENCRYPTION) 520 char buf[512]; 521 #endif 522 523 if (!(diagnostic & TD_OPTIONS)) 524 return; 525 526 if (direction) { 527 output_data("td: %s suboption ", 528 direction == '<' ? "recv" : "send"); 529 if (length >= 3) { 530 int j; 531 532 i = pointer[length - 2]; 533 j = pointer[length - 1]; 534 535 if (i != IAC || j != SE) { 536 output_data("(terminated by "); 537 if (TELOPT_OK(i)) 538 output_data("%s ", TELOPT(i)); 539 else if (TELCMD_OK(i)) 540 output_data("%s ", TELCMD(i)); 541 else 542 output_data("%d ", i); 543 if (TELOPT_OK(j)) 544 output_data("%s", TELOPT(j)); 545 else if (TELCMD_OK(j)) 546 output_data("%s", TELCMD(j)); 547 else 548 output_data("%d", j); 549 output_data(", not IAC SE!) "); 550 } 551 } 552 length -= 2; 553 } 554 if (length < 1) { 555 output_data("(Empty suboption??\?)"); 556 return; 557 } 558 switch (pointer[0]) { 559 case TELOPT_TTYPE: 560 output_data("TERMINAL-TYPE "); 561 switch (pointer[1]) { 562 case TELQUAL_IS: 563 output_data("IS \"%.*s\"", length-2, (char *)pointer+2); 564 break; 565 case TELQUAL_SEND: 566 output_data("SEND"); 567 break; 568 default: 569 output_data("- unknown qualifier %d (0x%x).", 570 pointer[1], pointer[1]); 571 } 572 break; 573 case TELOPT_TSPEED: 574 output_data("TERMINAL-SPEED"); 575 if (length < 2) { 576 output_data(" (empty suboption??\?)"); 577 break; 578 } 579 switch (pointer[1]) { 580 case TELQUAL_IS: 581 output_data(" IS %.*s", length-2, (char *)pointer+2); 582 break; 583 default: 584 if (pointer[1] == 1) 585 output_data(" SEND"); 586 else 587 output_data(" %d (unknown)", pointer[1]); 588 for (i = 2; i < length; i++) { 589 output_data(" ?%d?", pointer[i]); 590 } 591 break; 592 } 593 break; 594 595 case TELOPT_LFLOW: 596 output_data("TOGGLE-FLOW-CONTROL"); 597 if (length < 2) { 598 output_data(" (empty suboption??\?)"); 599 break; 600 } 601 switch (pointer[1]) { 602 case LFLOW_OFF: 603 output_data(" OFF"); break; 604 case LFLOW_ON: 605 output_data(" ON"); break; 606 case LFLOW_RESTART_ANY: 607 output_data(" RESTART-ANY"); break; 608 case LFLOW_RESTART_XON: 609 output_data(" RESTART-XON"); break; 610 default: 611 output_data(" %d (unknown)", pointer[1]); 612 } 613 for (i = 2; i < length; i++) 614 output_data(" ?%d?", pointer[i]); 615 break; 616 617 case TELOPT_NAWS: 618 output_data("NAWS"); 619 if (length < 2) { 620 output_data(" (empty suboption??\?)"); 621 break; 622 } 623 if (length == 2) { 624 output_data(" ?%d?", pointer[1]); 625 break; 626 } 627 output_data(" %d %d (%d)", 628 pointer[1], pointer[2], 629 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); 630 if (length == 4) { 631 output_data(" ?%d?", pointer[3]); 632 break; 633 } 634 output_data(" %d %d (%d)", pointer[3], pointer[4], 635 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); 636 for (i = 5; i < length; i++) { 637 output_data(" ?%d?", pointer[i]); 638 } 639 break; 640 641 case TELOPT_LINEMODE: 642 output_data("LINEMODE "); 643 if (length < 2) { 644 output_data(" (empty suboption??\?)"); 645 break; 646 } 647 switch (pointer[1]) { 648 case WILL: 649 output_data("WILL "); 650 goto common; 651 case WONT: 652 output_data("WONT "); 653 goto common; 654 case DO: 655 output_data("DO "); 656 goto common; 657 case DONT: 658 output_data("DONT "); 659 common: 660 if (length < 3) { 661 output_data("(no option??\?)"); 662 break; 663 } 664 switch (pointer[2]) { 665 case LM_FORWARDMASK: 666 output_data("Forward Mask"); 667 for (i = 3; i < length; i++) 668 output_data(" %x", pointer[i]); 669 break; 670 default: 671 output_data("%d (unknown)", pointer[2]); 672 for (i = 3; i < length; i++) 673 output_data(" %d", pointer[i]); 674 break; 675 } 676 break; 677 678 case LM_SLC: 679 output_data("SLC"); 680 for (i = 2; i < length - 2; i += 3) { 681 if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 682 output_data(" %s", SLC_NAME(pointer[i+SLC_FUNC])); 683 else 684 output_data(" %d", pointer[i+SLC_FUNC]); 685 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 686 case SLC_NOSUPPORT: 687 output_data(" NOSUPPORT"); break; 688 case SLC_CANTCHANGE: 689 output_data(" CANTCHANGE"); break; 690 case SLC_VARIABLE: 691 output_data(" VARIABLE"); break; 692 case SLC_DEFAULT: 693 output_data(" DEFAULT"); break; 694 } 695 output_data("%s%s%s", 696 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 697 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 698 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 699 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 700 SLC_FLUSHOUT| SLC_LEVELBITS)) { 701 output_data("(0x%x)", pointer[i+SLC_FLAGS]); 702 } 703 output_data(" %d;", pointer[i+SLC_VALUE]); 704 if ((pointer[i+SLC_VALUE] == IAC) && 705 (pointer[i+SLC_VALUE+1] == IAC)) 706 i++; 707 } 708 for (; i < length; i++) 709 output_data(" ?%d?", pointer[i]); 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 721 (void)snprintf(tbuf, sizeof tbuf, "%s%s%s%s%s", 722 pointer[2]&MODE_EDIT ? "|EDIT" : "", 723 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 724 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 725 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 726 pointer[2]&MODE_ACK ? "|ACK" : ""); 727 output_data("%s", tbuf[1] ? &tbuf[1] : "0"); 728 } 729 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) 730 output_data(" (0x%x)", pointer[2]); 731 for (i = 3; i < length; i++) 732 output_data(" ?0x%x?", pointer[i]); 733 break; 734 default: 735 output_data("%d (unknown)", pointer[1]); 736 for (i = 2; i < length; i++) 737 output_data(" %d", pointer[i]); 738 } 739 break; 740 741 case TELOPT_STATUS: { 742 char *cp; 743 int j, k; 744 745 output_data("STATUS"); 746 747 switch (pointer[1]) { 748 default: 749 if (pointer[1] == TELQUAL_SEND) 750 output_data(" SEND"); 751 else 752 output_data(" %d (unknown)", pointer[1]); 753 for (i = 2; i < length; i++) 754 output_data(" ?%d?", pointer[i]); 755 break; 756 case TELQUAL_IS: 757 output_data(" IS\r\n"); 758 759 for (i = 2; i < length; i++) { 760 switch(pointer[i]) { 761 case DO: cp = "DO"; goto common2; 762 case DONT: cp = "DONT"; goto common2; 763 case WILL: cp = "WILL"; goto common2; 764 case WONT: cp = "WONT"; goto common2; 765 common2: 766 i++; 767 if (TELOPT_OK(pointer[i])) 768 output_data(" %s %s", cp, TELOPT(pointer[i])); 769 else 770 output_data(" %s %d", cp, pointer[i]); 771 772 output_data("\r\n"); 773 break; 774 775 case SB: 776 output_data(" SB "); 777 i++; 778 j = k = i; 779 while (j < length) { 780 if (pointer[j] == SE) { 781 if (j+1 == length) 782 break; 783 if (pointer[j+1] == SE) 784 j++; 785 else 786 break; 787 } 788 pointer[k++] = pointer[j++]; 789 } 790 printsub(0, &pointer[i], k - i); 791 if (i < length) { 792 output_data(" SE"); 793 i = j; 794 } else 795 i = j - 1; 796 797 output_data("\r\n"); 798 799 break; 800 801 default: 802 output_data(" %d", pointer[i]); 803 break; 804 } 805 } 806 break; 807 } 808 break; 809 } 810 811 case TELOPT_XDISPLOC: 812 output_data("X-DISPLAY-LOCATION "); 813 switch (pointer[1]) { 814 case TELQUAL_IS: 815 output_data("IS \"%.*s\"", length - 2, (char *)pointer + 2); 816 break; 817 case TELQUAL_SEND: 818 output_data("SEND"); 819 break; 820 default: 821 output_data("- unknown qualifier %d (0x%x).", 822 pointer[1], pointer[1]); 823 } 824 break; 825 826 case TELOPT_NEW_ENVIRON: 827 output_data("NEW-ENVIRON "); 828 goto env_common1; 829 case TELOPT_OLD_ENVIRON: 830 output_data("OLD-ENVIRON"); 831 env_common1: 832 switch (pointer[1]) { 833 case TELQUAL_IS: 834 output_data("IS "); 835 goto env_common; 836 case TELQUAL_SEND: 837 output_data("SEND "); 838 goto env_common; 839 case TELQUAL_INFO: 840 output_data("INFO "); 841 env_common: 842 { 843 int noquote = 2; 844 for (i = 2; i < length; i++ ) { 845 switch (pointer[i]) { 846 case NEW_ENV_VAR: 847 output_data("%s", "\" VAR " + noquote); 848 noquote = 2; 849 break; 850 851 case NEW_ENV_VALUE: 852 output_data("%s", "\" VALUE " + noquote); 853 noquote = 2; 854 break; 855 856 case ENV_ESC: 857 output_data("%s", "\" ESC " + noquote); 858 noquote = 2; 859 break; 860 861 case ENV_USERVAR: 862 output_data("%s", "\" USERVAR " + noquote); 863 noquote = 2; 864 break; 865 866 default: 867 if (isprint(pointer[i]) && pointer[i] != '"') { 868 if (noquote) { 869 output_data("\""); 870 noquote = 0; 871 } 872 output_data("%c", pointer[i]); 873 } else { 874 output_data("\" %03o " + noquote, pointer[i]); 875 noquote = 2; 876 } 877 break; 878 } 879 } 880 if (!noquote) 881 output_data("\""); 882 break; 883 } 884 } 885 break; 886 887 #ifdef AUTHENTICATION 888 case TELOPT_AUTHENTICATION: 889 output_data("AUTHENTICATION"); 890 891 if (length < 2) { 892 output_data(" (empty suboption??\?)"); 893 break; 894 } 895 switch (pointer[1]) { 896 case TELQUAL_REPLY: 897 case TELQUAL_IS: 898 output_data(" %s ", (pointer[1] == TELQUAL_IS) ? 899 "IS" : "REPLY"); 900 if (AUTHTYPE_NAME_OK(pointer[2])) 901 output_data("%s ", AUTHTYPE_NAME(pointer[2])); 902 else 903 output_data("%d ", pointer[2]); 904 if (length < 3) { 905 output_data("(partial suboption??\?)"); 906 break; 907 } 908 output_data("%s|%s", 909 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 910 "CLIENT" : "SERVER", 911 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 912 "MUTUAL" : "ONE-WAY"); 913 914 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 915 output_data("%s", buf); 916 break; 917 918 case TELQUAL_SEND: 919 i = 2; 920 output_data(" SEND "); 921 while (i < length) { 922 if (AUTHTYPE_NAME_OK(pointer[i])) 923 output_data("%s ", AUTHTYPE_NAME(pointer[i])); 924 else 925 output_data("%d ", pointer[i]); 926 if (++i >= length) { 927 output_data("(partial suboption??\?)"); 928 break; 929 } 930 output_data("%s|%s ", 931 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 932 "CLIENT" : "SERVER", 933 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 934 "MUTUAL" : "ONE-WAY"); 935 ++i; 936 } 937 break; 938 939 case TELQUAL_NAME: 940 i = 2; 941 output_data(" NAME \""); 942 while (i < length) { 943 if (isprint(pointer[i])) 944 output_data("%c", pointer[i++]); 945 else 946 output_data("\"%03o\"",pointer[i++]); 947 } 948 output_data("\""); 949 break; 950 951 default: 952 for (i = 2; i < length; i++) 953 output_data(" ?%d?", pointer[i]); 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 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 997 output_data("%s", buf); 998 break; 999 1000 case ENCRYPT_SUPPORT: 1001 i = 2; 1002 output_data(" SUPPORT "); 1003 while (i < length) { 1004 if (ENCTYPE_NAME_OK(pointer[i])) 1005 output_data("%s ", ENCTYPE_NAME(pointer[i])); 1006 else 1007 output_data("%d ", pointer[i]); 1008 i++; 1009 } 1010 break; 1011 1012 case ENCRYPT_ENC_KEYID: 1013 output_data(" ENC_KEYID"); 1014 goto encommon; 1015 1016 case ENCRYPT_DEC_KEYID: 1017 output_data(" DEC_KEYID"); 1018 goto encommon; 1019 1020 default: 1021 output_data(" %d (unknown)", pointer[1]); 1022 encommon: 1023 for (i = 2; i < length; i++) 1024 output_data(" %d", pointer[i]); 1025 break; 1026 } 1027 break; 1028 #endif /* ENCRYPTION */ 1029 1030 default: 1031 if (TELOPT_OK(pointer[0])) 1032 output_data("%s (unknown)", TELOPT(pointer[0])); 1033 else 1034 output_data("%d (unknown)", pointer[i]); 1035 for (i = 1; i < length; i++) 1036 output_data(" %d", pointer[i]); 1037 break; 1038 } 1039 output_data("\r\n"); 1040 } 1041 1042 /* 1043 * Dump a data buffer in hex and ascii to the output data stream. 1044 */ 1045 void 1046 printdata(char *tag, char *ptr, int cnt) 1047 { 1048 int i; 1049 char xbuf[30]; 1050 1051 while (cnt) { 1052 /* flush net output buffer if no room for new data) */ 1053 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 1054 netflush(); 1055 } 1056 1057 /* add a line of output */ 1058 output_data("%s: ", tag); 1059 for (i = 0; i < 20 && cnt; i++) { 1060 output_data("%02x", *ptr); 1061 if (isprint((unsigned char)*ptr)) { 1062 xbuf[i] = *ptr; 1063 } else { 1064 xbuf[i] = '.'; 1065 } 1066 if (i % 2) 1067 output_data(" "); 1068 cnt--; 1069 ptr++; 1070 } 1071 xbuf[i] = '\0'; 1072 output_data(" %s\r\n", xbuf); 1073 } 1074 } 1075 #endif /* DIAGNOSTICS */ 1076