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