utility.c revision 57416
1306196Sjkim/* 2238405Sjkim * Copyright (c) 1989, 1993 3238405Sjkim * The Regents of the University of California. All rights reserved. 4238405Sjkim * 5238405Sjkim * Redistribution and use in source and binary forms, with or without 6238405Sjkim * modification, are permitted provided that the following conditions 7238405Sjkim * are met: 8238405Sjkim * 1. Redistributions of source code must retain the above copyright 9238405Sjkim * notice, this list of conditions and the following disclaimer. 10238405Sjkim * 2. Redistributions in binary form must reproduce the above copyright 11238405Sjkim * notice, this list of conditions and the following disclaimer in the 12238405Sjkim * documentation and/or other materials provided with the distribution. 13238405Sjkim * 3. All advertising materials mentioning features or use of this software 14238405Sjkim * must display the following acknowledgement: 15238405Sjkim * This product includes software developed by the University of 16238405Sjkim * California, Berkeley and its contributors. 17238405Sjkim * 4. Neither the name of the University nor the names of its contributors 18238405Sjkim * may be used to endorse or promote products derived from this software 19238405Sjkim * without specific prior written permission. 20238405Sjkim * 21238405Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22238405Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23238405Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24238405Sjkim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25238405Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26238405Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27238405Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28238405Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29238405Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30238405Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31238405Sjkim * SUCH DAMAGE. 32238405Sjkim */ 33238405Sjkim 34238405Sjkim#define PRINTOPTIONS 35238405Sjkim#include "telnetd.h" 36238405Sjkim 37238405SjkimRCSID("$Id: utility.c,v 1.22 1999/09/16 20:41:38 assar Exp $"); 38238405Sjkim 39238405Sjkim/* 40238405Sjkim * utility functions performing io related tasks 41276864Sjkim */ 42276864Sjkim 43238405Sjkim/* 44238405Sjkim * ttloop 45238405Sjkim * 46238405Sjkim * A small subroutine to flush the network output buffer, get some 47238405Sjkim * data from the network, and pass it through the telnet state 48238405Sjkim * machine. We also flush the pty input buffer (by dropping its data) 49238405Sjkim * if it becomes too full. 50238405Sjkim * 51238405Sjkim * return 0 if OK or 1 if interrupted by a signal. 52238405Sjkim */ 53276864Sjkim 54276864Sjkimint 55276864Sjkimttloop(void) 56238405Sjkim{ 57276864Sjkim void netflush(void); 58276864Sjkim 59276864Sjkim DIAG(TD_REPORT, { 60276864Sjkim output_data("td: ttloop\r\n"); 61276864Sjkim }); 62276864Sjkim if (nfrontp-nbackp) 63238405Sjkim netflush(); 64276864Sjkim ncc = read(net, netibuf, sizeof netibuf); 65276864Sjkim if (ncc < 0) { 66276864Sjkim if (errno == EINTR) 67276864Sjkim return 1; 68276864Sjkim syslog(LOG_INFO, "ttloop: read: %m\n"); 69238405Sjkim exit(1); 70276864Sjkim } else if (ncc == 0) { 71238405Sjkim syslog(LOG_INFO, "ttloop: peer died: %m\n"); 72238405Sjkim exit(1); 73238405Sjkim } 74238405Sjkim DIAG(TD_REPORT, { 75238405Sjkim output_data("td: ttloop read %d chars\r\n", ncc); 76238405Sjkim }); 77238405Sjkim netip = netibuf; 78238405Sjkim telrcv(); /* state machine */ 79238405Sjkim if (ncc > 0) { 80238405Sjkim pfrontp = pbackp = ptyobuf; 81238405Sjkim telrcv(); 82238405Sjkim } 83238405Sjkim return 0; 84238405Sjkim} /* end of ttloop */ 85238405Sjkim 86238405Sjkim/* 87238405Sjkim * Check a descriptor to see if out of band data exists on it. 88238405Sjkim */ 89238405Sjkimint 90238405Sjkimstilloob(int s) 91238405Sjkim{ 92238405Sjkim static struct timeval timeout = { 0 }; 93238405Sjkim fd_set excepts; 94238405Sjkim int value; 95238405Sjkim 96238405Sjkim do { 97238405Sjkim FD_ZERO(&excepts); 98238405Sjkim FD_SET(s, &excepts); 99238405Sjkim value = select(s+1, 0, 0, &excepts, &timeout); 100238405Sjkim } while ((value == -1) && (errno == EINTR)); 101238405Sjkim 102238405Sjkim if (value < 0) { 103238405Sjkim fatalperror(ourpty, "select"); 104238405Sjkim } 105238405Sjkim if (FD_ISSET(s, &excepts)) { 106238405Sjkim return 1; 107238405Sjkim } else { 108238405Sjkim return 0; 109238405Sjkim } 110238405Sjkim} 111238405Sjkim 112238405Sjkimvoid 113238405Sjkimptyflush(void) 114238405Sjkim{ 115238405Sjkim int n; 116238405Sjkim 117238405Sjkim if ((n = pfrontp - pbackp) > 0) { 118238405Sjkim DIAG((TD_REPORT | TD_PTYDATA), { 119238405Sjkim output_data("td: ptyflush %d chars\r\n", n); 120238405Sjkim }); 121238405Sjkim DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); 122238405Sjkim n = write(ourpty, pbackp, n); 123238405Sjkim } 124238405Sjkim if (n < 0) { 125238405Sjkim if (errno == EWOULDBLOCK || errno == EINTR) 126238405Sjkim return; 127238405Sjkim cleanup(0); 128238405Sjkim } 129238405Sjkim pbackp += n; 130238405Sjkim if (pbackp == pfrontp) 131238405Sjkim pbackp = pfrontp = ptyobuf; 132238405Sjkim} 133238405Sjkim 134238405Sjkim/* 135238405Sjkim * nextitem() 136306196Sjkim * 137238405Sjkim * Return the address of the next "item" in the TELNET data 138238405Sjkim * stream. This will be the address of the next character if 139238405Sjkim * the current address is a user data character, or it will 140238405Sjkim * be the address of the character following the TELNET command 141238405Sjkim * if the current address is a TELNET IAC ("I Am a Command") 142238405Sjkim * character. 143238405Sjkim */ 144238405Sjkimchar * 145238405Sjkimnextitem(char *current) 146238405Sjkim{ 147238405Sjkim if ((*current&0xff) != IAC) { 148238405Sjkim return current+1; 149238405Sjkim } 150238405Sjkim switch (*(current+1)&0xff) { 151238405Sjkim case DO: 152238405Sjkim case DONT: 153238405Sjkim case WILL: 154238405Sjkim case WONT: 155238405Sjkim return current+3; 156238405Sjkim case SB:{ 157238405Sjkim /* loop forever looking for the SE */ 158238405Sjkim char *look = current+2; 159238405Sjkim 160238405Sjkim for (;;) { 161238405Sjkim if ((*look++&0xff) == IAC) { 162238405Sjkim if ((*look++&0xff) == SE) { 163238405Sjkim return look; 164238405Sjkim } 165238405Sjkim } 166238405Sjkim } 167238405Sjkim } 168238405Sjkim default: 169238405Sjkim return current+2; 170238405Sjkim } 171238405Sjkim} 172238405Sjkim 173238405Sjkim 174238405Sjkim/* 175238405Sjkim * netclear() 176238405Sjkim * 177238405Sjkim * We are about to do a TELNET SYNCH operation. Clear 178238405Sjkim * the path to the network. 179238405Sjkim * 180238405Sjkim * Things are a bit tricky since we may have sent the first 181238405Sjkim * byte or so of a previous TELNET command into the network. 182238405Sjkim * So, we have to scan the network buffer from the beginning 183238405Sjkim * until we are up to where we want to be. 184238405Sjkim * 185238405Sjkim * A side effect of what we do, just to keep things 186238405Sjkim * simple, is to clear the urgent data pointer. The principal 187238405Sjkim * caller should be setting the urgent data pointer AFTER calling 188238405Sjkim * us in any case. 189238405Sjkim */ 190238405Sjkimvoid 191238405Sjkimnetclear(void) 192238405Sjkim{ 193238405Sjkim char *thisitem, *next; 194238405Sjkim char *good; 195238405Sjkim#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 196238405Sjkim ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 197238405Sjkim 198238405Sjkim#ifdef ENCRYPTION 199276864Sjkim thisitem = nclearto > netobuf ? nclearto : netobuf; 200238405Sjkim#else 201238405Sjkim thisitem = netobuf; 202238405Sjkim#endif 203238405Sjkim 204238405Sjkim while ((next = nextitem(thisitem)) <= nbackp) { 205238405Sjkim thisitem = next; 206238405Sjkim } 207238405Sjkim 208238405Sjkim /* Now, thisitem is first before/at boundary. */ 209238405Sjkim 210238405Sjkim#ifdef ENCRYPTION 211238405Sjkim good = nclearto > netobuf ? nclearto : netobuf; 212238405Sjkim#else 213238405Sjkim good = netobuf; /* where the good bytes go */ 214238405Sjkim#endif 215238405Sjkim 216 while (nfrontp > thisitem) { 217 if (wewant(thisitem)) { 218 int length; 219 220 next = thisitem; 221 do { 222 next = nextitem(next); 223 } while (wewant(next) && (nfrontp > next)); 224 length = next-thisitem; 225 memmove(good, thisitem, length); 226 good += length; 227 thisitem = next; 228 } else { 229 thisitem = nextitem(thisitem); 230 } 231 } 232 233 nbackp = netobuf; 234 nfrontp = good; /* next byte to be sent */ 235 neturg = 0; 236} /* end of netclear */ 237 238/* 239 * netflush 240 * Send as much data as possible to the network, 241 * handling requests for urgent data. 242 */ 243void 244netflush(void) 245{ 246 int n; 247 extern int not42; 248 249 if ((n = nfrontp - nbackp) > 0) { 250 DIAG(TD_REPORT, 251 { n += output_data("td: netflush %d chars\r\n", n); 252 }); 253#ifdef ENCRYPTION 254 if (encrypt_output) { 255 char *s = nclearto ? nclearto : nbackp; 256 if (nfrontp - s > 0) { 257 (*encrypt_output)((unsigned char *)s, nfrontp-s); 258 nclearto = nfrontp; 259 } 260 } 261#endif 262 /* 263 * if no urgent data, or if the other side appears to be an 264 * old 4.2 client (and thus unable to survive TCP urgent data), 265 * write the entire buffer in non-OOB mode. 266 */ 267#if 1 /* remove this to make it work between solaris 2.6 and linux */ 268 if ((neturg == 0) || (not42 == 0)) { 269#endif 270 n = write(net, nbackp, n); /* normal write */ 271#if 1 /* remove this to make it work between solaris 2.6 and linux */ 272 } else { 273 n = neturg - nbackp; 274 /* 275 * In 4.2 (and 4.3) systems, there is some question about 276 * what byte in a sendOOB operation is the "OOB" data. 277 * To make ourselves compatible, we only send ONE byte 278 * out of band, the one WE THINK should be OOB (though 279 * we really have more the TCP philosophy of urgent data 280 * rather than the Unix philosophy of OOB data). 281 */ 282 if (n > 1) { 283 n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 284 } else { 285 n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 286 } 287 } 288#endif 289 } 290 if (n < 0) { 291 if (errno == EWOULDBLOCK || errno == EINTR) 292 return; 293 cleanup(0); 294 } 295 nbackp += n; 296#ifdef ENCRYPTION 297 if (nbackp > nclearto) 298 nclearto = 0; 299#endif 300 if (nbackp >= neturg) { 301 neturg = 0; 302 } 303 if (nbackp == nfrontp) { 304 nbackp = nfrontp = netobuf; 305#ifdef ENCRYPTION 306 nclearto = 0; 307#endif 308 } 309 return; 310} 311 312 313/* 314 * writenet 315 * 316 * Just a handy little function to write a bit of raw data to the net. 317 * It will force a transmit of the buffer if necessary 318 * 319 * arguments 320 * ptr - A pointer to a character string to write 321 * len - How many bytes to write 322 */ 323void 324writenet(unsigned char *ptr, int len) 325{ 326 /* flush buffer if no room for new data) */ 327 while ((&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 336 337/* 338 * miscellaneous functions doing a variety of little jobs follow ... 339 */ 340 341 342void fatal(int f, char *msg) 343{ 344 char buf[BUFSIZ]; 345 346 snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg); 347#ifdef ENCRYPTION 348 if (encrypt_output) { 349 /* 350 * Better turn off encryption first.... 351 * Hope it flushes... 352 */ 353 encrypt_send_end(); 354 netflush(); 355 } 356#endif 357 write(f, buf, (int)strlen(buf)); 358 sleep(1); /*XXX*/ 359 exit(1); 360} 361 362void 363fatalperror(int f, const char *msg) 364{ 365 char buf[BUFSIZ]; 366 367 snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(errno)); 368 fatal(f, buf); 369} 370 371char editedhost[32]; 372 373void edithost(char *pat, char *host) 374{ 375 char *res = editedhost; 376 377 if (!pat) 378 pat = ""; 379 while (*pat) { 380 switch (*pat) { 381 382 case '#': 383 if (*host) 384 host++; 385 break; 386 387 case '@': 388 if (*host) 389 *res++ = *host++; 390 break; 391 392 default: 393 *res++ = *pat; 394 break; 395 } 396 if (res == &editedhost[sizeof editedhost - 1]) { 397 *res = '\0'; 398 return; 399 } 400 pat++; 401 } 402 if (*host) 403 strlcpy (res, host, 404 sizeof editedhost - (res - editedhost)); 405 else 406 *res = '\0'; 407 editedhost[sizeof editedhost - 1] = '\0'; 408} 409 410static char *putlocation; 411 412void 413putstr(char *s) 414{ 415 416 while (*s) 417 putchr(*s++); 418} 419 420void 421putchr(int cc) 422{ 423 *putlocation++ = cc; 424} 425 426/* 427 * This is split on two lines so that SCCS will not see the M 428 * between two % signs and expand it... 429 */ 430static char fmtstr[] = { "%l:%M" "%P on %A, %d %B %Y" }; 431 432void putf(char *cp, char *where) 433{ 434#ifdef HAVE_UNAME 435 struct utsname name; 436#endif 437 char *slash; 438 time_t t; 439 char db[100]; 440 441 /* if we don't have uname, set these to sensible values */ 442 char *sysname = "Unix", 443 *machine = "", 444 *release = "", 445 *version = ""; 446 447#ifdef HAVE_UNAME 448 uname(&name); 449 sysname=name.sysname; 450 machine=name.machine; 451 release=name.release; 452 version=name.version; 453#endif 454 455 putlocation = where; 456 457 while (*cp) { 458 if (*cp != '%') { 459 putchr(*cp++); 460 continue; 461 } 462 switch (*++cp) { 463 464 case 't': 465#ifdef STREAMSPTY 466 /* names are like /dev/pts/2 -- we want pts/2 */ 467 slash = strchr(line+1, '/'); 468#else 469 slash = strrchr(line, '/'); 470#endif 471 if (slash == (char *) 0) 472 putstr(line); 473 else 474 putstr(&slash[1]); 475 break; 476 477 case 'h': 478 putstr(editedhost); 479 break; 480 481 case 's': 482 putstr(sysname); 483 break; 484 485 case 'm': 486 putstr(machine); 487 break; 488 489 case 'r': 490 putstr(release); 491 break; 492 493 case 'v': 494 putstr(version); 495 break; 496 497 case 'd': 498 time(&t); 499 strftime(db, sizeof(db), fmtstr, localtime(&t)); 500 putstr(db); 501 break; 502 503 case '%': 504 putchr('%'); 505 break; 506 } 507 cp++; 508 } 509} 510 511#ifdef DIAGNOSTICS 512/* 513 * Print telnet options and commands in plain text, if possible. 514 */ 515void 516printoption(char *fmt, int option) 517{ 518 if (TELOPT_OK(option)) 519 output_data("%s %s\r\n", 520 fmt, 521 TELOPT(option)); 522 else if (TELCMD_OK(option)) 523 output_data("%s %s\r\n", 524 fmt, 525 TELCMD(option)); 526 else 527 output_data("%s %d\r\n", 528 fmt, 529 option); 530 return; 531} 532 533void 534printsub(int direction, unsigned char *pointer, int length) 535 /* '<' or '>' */ 536 /* where suboption data sits */ 537 /* length of suboption data */ 538{ 539 int i = 0; 540 unsigned char buf[512]; 541 542 if (!(diagnostic & TD_OPTIONS)) 543 return; 544 545 if (direction) { 546 output_data("td: %s suboption ", 547 direction == '<' ? "recv" : "send"); 548 if (length >= 3) { 549 int j; 550 551 i = pointer[length-2]; 552 j = pointer[length-1]; 553 554 if (i != IAC || j != SE) { 555 output_data("(terminated by "); 556 if (TELOPT_OK(i)) 557 output_data("%s ", 558 TELOPT(i)); 559 else if (TELCMD_OK(i)) 560 output_data("%s ", 561 TELCMD(i)); 562 else 563 output_data("%d ", 564 i); 565 if (TELOPT_OK(j)) 566 output_data("%s", 567 TELOPT(j)); 568 else if (TELCMD_OK(j)) 569 output_data("%s", 570 TELCMD(j)); 571 else 572 output_data("%d", 573 j); 574 output_data(", not IAC SE!) "); 575 } 576 } 577 length -= 2; 578 } 579 if (length < 1) { 580 output_data("(Empty suboption??\?)"); 581 return; 582 } 583 switch (pointer[0]) { 584 case TELOPT_TTYPE: 585 output_data("TERMINAL-TYPE "); 586 switch (pointer[1]) { 587 case TELQUAL_IS: 588 output_data("IS \"%.*s\"", 589 length-2, 590 (char *)pointer+2); 591 break; 592 case TELQUAL_SEND: 593 output_data("SEND"); 594 break; 595 default: 596 output_data("- unknown qualifier %d (0x%x).", 597 pointer[1], pointer[1]); 598 } 599 break; 600 case TELOPT_TSPEED: 601 output_data("TERMINAL-SPEED"); 602 if (length < 2) { 603 output_data(" (empty suboption??\?)"); 604 break; 605 } 606 switch (pointer[1]) { 607 case TELQUAL_IS: 608 output_data(" IS %.*s", length-2, (char *)pointer+2); 609 break; 610 default: 611 if (pointer[1] == 1) 612 output_data(" SEND"); 613 else 614 output_data(" %d (unknown)", pointer[1]); 615 for (i = 2; i < length; i++) { 616 output_data(" ?%d?", pointer[i]); 617 } 618 break; 619 } 620 break; 621 622 case TELOPT_LFLOW: 623 output_data("TOGGLE-FLOW-CONTROL"); 624 if (length < 2) { 625 output_data(" (empty suboption??\?)"); 626 break; 627 } 628 switch (pointer[1]) { 629 case LFLOW_OFF: 630 output_data(" OFF"); 631 break; 632 case LFLOW_ON: 633 output_data(" ON"); 634 break; 635 case LFLOW_RESTART_ANY: 636 output_data(" RESTART-ANY"); 637 break; 638 case LFLOW_RESTART_XON: 639 output_data(" RESTART-XON"); 640 break; 641 default: 642 output_data(" %d (unknown)", 643 pointer[1]); 644 } 645 for (i = 2; i < length; i++) { 646 output_data(" ?%d?", 647 pointer[i]); 648 } 649 break; 650 651 case TELOPT_NAWS: 652 output_data("NAWS"); 653 if (length < 2) { 654 output_data(" (empty suboption??\?)"); 655 break; 656 } 657 if (length == 2) { 658 output_data(" ?%d?", 659 pointer[1]); 660 break; 661 } 662 output_data(" %u %u(%u)", 663 pointer[1], 664 pointer[2], 665 (((unsigned int)pointer[1])<<8) + pointer[2]); 666 if (length == 4) { 667 output_data(" ?%d?", 668 pointer[3]); 669 break; 670 } 671 output_data(" %u %u(%u)", 672 pointer[3], 673 pointer[4], 674 (((unsigned int)pointer[3])<<8) + pointer[4]); 675 for (i = 5; i < length; i++) { 676 output_data(" ?%d?", 677 pointer[i]); 678 } 679 break; 680 681 case TELOPT_LINEMODE: 682 output_data("LINEMODE "); 683 if (length < 2) { 684 output_data(" (empty suboption??\?)"); 685 break; 686 } 687 switch (pointer[1]) { 688 case WILL: 689 output_data("WILL "); 690 goto common; 691 case WONT: 692 output_data("WONT "); 693 goto common; 694 case DO: 695 output_data("DO "); 696 goto common; 697 case DONT: 698 output_data("DONT "); 699 common: 700 if (length < 3) { 701 output_data("(no option??\?)"); 702 break; 703 } 704 switch (pointer[2]) { 705 case LM_FORWARDMASK: 706 output_data("Forward Mask"); 707 for (i = 3; i < length; i++) { 708 output_data(" %x", pointer[i]); 709 } 710 break; 711 default: 712 output_data("%d (unknown)", 713 pointer[2]); 714 for (i = 3; i < length; i++) { 715 output_data(" %d", 716 pointer[i]); 717 } 718 break; 719 } 720 break; 721 722 case LM_SLC: 723 output_data("SLC"); 724 for (i = 2; i < length - 2; i += 3) { 725 if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 726 output_data(" %s", 727 SLC_NAME(pointer[i+SLC_FUNC])); 728 else 729 output_data(" %d", 730 pointer[i+SLC_FUNC]); 731 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 732 case SLC_NOSUPPORT: 733 output_data(" NOSUPPORT"); 734 break; 735 case SLC_CANTCHANGE: 736 output_data(" CANTCHANGE"); 737 break; 738 case SLC_VARIABLE: 739 output_data(" VARIABLE"); 740 break; 741 case SLC_DEFAULT: 742 output_data(" DEFAULT"); 743 break; 744 } 745 output_data("%s%s%s", 746 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 747 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 748 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 749 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 750 SLC_FLUSHOUT| SLC_LEVELBITS)) { 751 output_data("(0x%x)", 752 pointer[i+SLC_FLAGS]); 753 } 754 output_data(" %d;", 755 pointer[i+SLC_VALUE]); 756 if ((pointer[i+SLC_VALUE] == IAC) && 757 (pointer[i+SLC_VALUE+1] == IAC)) 758 i++; 759 } 760 for (; i < length; i++) { 761 output_data(" ?%d?", 762 pointer[i]); 763 } 764 break; 765 766 case LM_MODE: 767 output_data("MODE "); 768 if (length < 3) { 769 output_data("(no mode??\?)"); 770 break; 771 } 772 { 773 char tbuf[32]; 774 snprintf(tbuf, 775 sizeof(tbuf), 776 "%s%s%s%s%s", 777 pointer[2]&MODE_EDIT ? "|EDIT" : "", 778 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 779 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 780 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 781 pointer[2]&MODE_ACK ? "|ACK" : ""); 782 output_data("%s", 783 tbuf[1] ? &tbuf[1] : "0"); 784 } 785 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { 786 output_data(" (0x%x)", 787 pointer[2]); 788 } 789 for (i = 3; i < length; i++) { 790 output_data(" ?0x%x?", 791 pointer[i]); 792 } 793 break; 794 default: 795 output_data("%d (unknown)", 796 pointer[1]); 797 for (i = 2; i < length; i++) { 798 output_data(" %d", pointer[i]); 799 } 800 } 801 break; 802 803 case TELOPT_STATUS: { 804 char *cp; 805 int j, k; 806 807 output_data("STATUS"); 808 809 switch (pointer[1]) { 810 default: 811 if (pointer[1] == TELQUAL_SEND) 812 output_data(" SEND"); 813 else 814 output_data(" %d (unknown)", 815 pointer[1]); 816 for (i = 2; i < length; i++) { 817 output_data(" ?%d?", 818 pointer[i]); 819 } 820 break; 821 case TELQUAL_IS: 822 output_data(" IS\r\n"); 823 824 for (i = 2; i < length; i++) { 825 switch(pointer[i]) { 826 case DO: cp = "DO"; goto common2; 827 case DONT: cp = "DONT"; goto common2; 828 case WILL: cp = "WILL"; goto common2; 829 case WONT: cp = "WONT"; goto common2; 830 common2: 831 i++; 832 if (TELOPT_OK(pointer[i])) 833 output_data(" %s %s", 834 cp, 835 TELOPT(pointer[i])); 836 else 837 output_data(" %s %d", 838 cp, 839 pointer[i]); 840 841 output_data("\r\n"); 842 break; 843 844 case SB: 845 output_data(" SB "); 846 i++; 847 j = k = i; 848 while (j < length) { 849 if (pointer[j] == SE) { 850 if (j+1 == length) 851 break; 852 if (pointer[j+1] == SE) 853 j++; 854 else 855 break; 856 } 857 pointer[k++] = pointer[j++]; 858 } 859 printsub(0, &pointer[i], k - i); 860 if (i < length) { 861 output_data(" SE"); 862 i = j; 863 } else 864 i = j - 1; 865 866 output_data("\r\n"); 867 868 break; 869 870 default: 871 output_data(" %d", 872 pointer[i]); 873 break; 874 } 875 } 876 break; 877 } 878 break; 879 } 880 881 case TELOPT_XDISPLOC: 882 output_data("X-DISPLAY-LOCATION "); 883 switch (pointer[1]) { 884 case TELQUAL_IS: 885 output_data("IS \"%.*s\"", 886 length-2, 887 (char *)pointer+2); 888 break; 889 case TELQUAL_SEND: 890 output_data("SEND"); 891 break; 892 default: 893 output_data("- unknown qualifier %d (0x%x).", 894 pointer[1], pointer[1]); 895 } 896 break; 897 898 case TELOPT_NEW_ENVIRON: 899 output_data("NEW-ENVIRON "); 900 goto env_common1; 901 case TELOPT_OLD_ENVIRON: 902 output_data("OLD-ENVIRON"); 903 env_common1: 904 switch (pointer[1]) { 905 case TELQUAL_IS: 906 output_data("IS "); 907 goto env_common; 908 case TELQUAL_SEND: 909 output_data("SEND "); 910 goto env_common; 911 case TELQUAL_INFO: 912 output_data("INFO "); 913 env_common: 914 { 915 int noquote = 2; 916 for (i = 2; i < length; i++ ) { 917 switch (pointer[i]) { 918 case NEW_ENV_VAR: 919 output_data("\" VAR " + noquote); 920 noquote = 2; 921 break; 922 923 case NEW_ENV_VALUE: 924 output_data("\" VALUE " + noquote); 925 noquote = 2; 926 break; 927 928 case ENV_ESC: 929 output_data("\" ESC " + noquote); 930 noquote = 2; 931 break; 932 933 case ENV_USERVAR: 934 output_data("\" USERVAR " + noquote); 935 noquote = 2; 936 break; 937 938 default: 939 if (isprint(pointer[i]) && pointer[i] != '"') { 940 if (noquote) { 941 output_data ("\""); 942 noquote = 0; 943 } 944 output_data ("%c", pointer[i]); 945 } else { 946 output_data("\" %03o " + noquote, 947 pointer[i]); 948 noquote = 2; 949 } 950 break; 951 } 952 } 953 if (!noquote) 954 output_data ("\""); 955 break; 956 } 957 } 958 break; 959 960#ifdef AUTHENTICATION 961 case TELOPT_AUTHENTICATION: 962 output_data("AUTHENTICATION"); 963 964 if (length < 2) { 965 output_data(" (empty suboption??\?)"); 966 break; 967 } 968 switch (pointer[1]) { 969 case TELQUAL_REPLY: 970 case TELQUAL_IS: 971 output_data(" %s ", 972 (pointer[1] == TELQUAL_IS) ? 973 "IS" : "REPLY"); 974 if (AUTHTYPE_NAME_OK(pointer[2])) 975 output_data("%s ", 976 AUTHTYPE_NAME(pointer[2])); 977 else 978 output_data("%d ", 979 pointer[2]); 980 if (length < 3) { 981 output_data("(partial suboption??\?)"); 982 break; 983 } 984 output_data("%s|%s", 985 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 986 "CLIENT" : "SERVER", 987 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 988 "MUTUAL" : "ONE-WAY"); 989 990 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 991 output_data("%s", 992 buf); 993 break; 994 995 case TELQUAL_SEND: 996 i = 2; 997 output_data(" SEND "); 998 while (i < length) { 999 if (AUTHTYPE_NAME_OK(pointer[i])) 1000 output_data("%s ", 1001 AUTHTYPE_NAME(pointer[i])); 1002 else 1003 output_data("%d ", 1004 pointer[i]); 1005 if (++i >= length) { 1006 output_data("(partial suboption??\?)"); 1007 break; 1008 } 1009 output_data("%s|%s ", 1010 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 1011 "CLIENT" : "SERVER", 1012 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 1013 "MUTUAL" : "ONE-WAY"); 1014 ++i; 1015 } 1016 break; 1017 1018 case TELQUAL_NAME: 1019 i = 2; 1020 output_data(" NAME \"%.*s\"", 1021 length - 2, 1022 pointer); 1023 break; 1024 1025 default: 1026 for (i = 2; i < length; i++) { 1027 output_data(" ?%d?", 1028 pointer[i]); 1029 } 1030 break; 1031 } 1032 break; 1033#endif 1034 1035#ifdef ENCRYPTION 1036 case TELOPT_ENCRYPT: 1037 output_data("ENCRYPT"); 1038 if (length < 2) { 1039 output_data(" (empty suboption?)"); 1040 break; 1041 } 1042 switch (pointer[1]) { 1043 case ENCRYPT_START: 1044 output_data(" START"); 1045 break; 1046 1047 case ENCRYPT_END: 1048 output_data(" END"); 1049 break; 1050 1051 case ENCRYPT_REQSTART: 1052 output_data(" REQUEST-START"); 1053 break; 1054 1055 case ENCRYPT_REQEND: 1056 output_data(" REQUEST-END"); 1057 break; 1058 1059 case ENCRYPT_IS: 1060 case ENCRYPT_REPLY: 1061 output_data(" %s ", 1062 (pointer[1] == ENCRYPT_IS) ? 1063 "IS" : "REPLY"); 1064 if (length < 3) { 1065 output_data(" (partial suboption?)"); 1066 break; 1067 } 1068 if (ENCTYPE_NAME_OK(pointer[2])) 1069 output_data("%s ", 1070 ENCTYPE_NAME(pointer[2])); 1071 else 1072 output_data(" %d (unknown)", 1073 pointer[2]); 1074 1075 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 1076 output_data("%s", 1077 buf); 1078 break; 1079 1080 case ENCRYPT_SUPPORT: 1081 i = 2; 1082 output_data(" SUPPORT "); 1083 while (i < length) { 1084 if (ENCTYPE_NAME_OK(pointer[i])) 1085 output_data("%s ", 1086 ENCTYPE_NAME(pointer[i])); 1087 else 1088 output_data("%d ", 1089 pointer[i]); 1090 i++; 1091 } 1092 break; 1093 1094 case ENCRYPT_ENC_KEYID: 1095 output_data(" ENC_KEYID %d", pointer[1]); 1096 goto encommon; 1097 1098 case ENCRYPT_DEC_KEYID: 1099 output_data(" DEC_KEYID %d", pointer[1]); 1100 goto encommon; 1101 1102 default: 1103 output_data(" %d (unknown)", pointer[1]); 1104 encommon: 1105 for (i = 2; i < length; i++) { 1106 output_data(" %d", pointer[i]); 1107 } 1108 break; 1109 } 1110 break; 1111#endif 1112 1113 default: 1114 if (TELOPT_OK(pointer[0])) 1115 output_data("%s (unknown)", 1116 TELOPT(pointer[0])); 1117 else 1118 output_data("%d (unknown)", 1119 pointer[i]); 1120 for (i = 1; i < length; i++) { 1121 output_data(" %d", pointer[i]); 1122 } 1123 break; 1124 } 1125 output_data("\r\n"); 1126} 1127 1128/* 1129 * Dump a data buffer in hex and ascii to the output data stream. 1130 */ 1131void 1132printdata(char *tag, char *ptr, int cnt) 1133{ 1134 int i; 1135 char xbuf[30]; 1136 1137 while (cnt) { 1138 /* flush net output buffer if no room for new data) */ 1139 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 1140 netflush(); 1141 } 1142 1143 /* add a line of output */ 1144 output_data("%s: ", tag); 1145 for (i = 0; i < 20 && cnt; i++) { 1146 output_data("%02x", *ptr); 1147 if (isprint(*ptr)) { 1148 xbuf[i] = *ptr; 1149 } else { 1150 xbuf[i] = '.'; 1151 } 1152 if (i % 2) { 1153 output_data(" "); 1154 } 1155 cnt--; 1156 ptr++; 1157 } 1158 xbuf[i] = '\0'; 1159 output_data(" %s\r\n", xbuf); 1160 } 1161} 1162#endif /* DIAGNOSTICS */ 1163