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