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