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