utility.c revision 233294
1219019Sgabor/* 2219019Sgabor * Copyright (c) 1989, 1993 3219019Sgabor * The Regents of the University of California. All rights reserved. 4219019Sgabor * 5219019Sgabor * Redistribution and use in source and binary forms, with or without 6219019Sgabor * modification, are permitted provided that the following conditions 7219019Sgabor * are met: 8219019Sgabor * 1. Redistributions of source code must retain the above copyright 9219019Sgabor * notice, this list of conditions and the following disclaimer. 10219019Sgabor * 2. Redistributions in binary form must reproduce the above copyright 11219019Sgabor * notice, this list of conditions and the following disclaimer in the 12219019Sgabor * documentation and/or other materials provided with the distribution. 13219019Sgabor * 3. All advertising materials mentioning features or use of this software 14219019Sgabor * must display the following acknowledgement: 15219019Sgabor * This product includes software developed by the University of 16219019Sgabor * California, Berkeley and its contributors. 17219019Sgabor * 4. Neither the name of the University nor the names of its contributors 18219019Sgabor * may be used to endorse or promote products derived from this software 19219019Sgabor * without specific prior written permission. 20219019Sgabor * 21219019Sgabor * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22219019Sgabor * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23219019Sgabor * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24219019Sgabor * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25219019Sgabor * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26219019Sgabor * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27219019Sgabor * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28219019Sgabor * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29219019Sgabor * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30219019Sgabor * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31219019Sgabor * SUCH DAMAGE. 32219019Sgabor */ 33219019Sgabor 34219019Sgabor#define PRINTOPTIONS 35219019Sgabor#include "telnetd.h" 36219019Sgabor 37219019SgaborRCSID("$Id$"); 38219019Sgabor 39219019Sgabor/* 40219019Sgabor * utility functions performing io related tasks 41219019Sgabor */ 42219019Sgabor 43219019Sgabor/* 44219019Sgabor * ttloop 45219019Sgabor * 46219019Sgabor * A small subroutine to flush the network output buffer, get some 47219019Sgabor * data from the network, and pass it through the telnet state 48219019Sgabor * machine. We also flush the pty input buffer (by dropping its data) 49219019Sgabor * if it becomes too full. 50219019Sgabor * 51219019Sgabor * return 0 if OK or 1 if interrupted by a signal. 52219019Sgabor */ 53219019Sgabor 54219019Sgaborint 55219019Sgaborttloop(void) 56219019Sgabor{ 57219019Sgabor DIAG(TD_REPORT, { 58219019Sgabor output_data("td: ttloop\r\n"); 59219019Sgabor }); 60219019Sgabor if (nfrontp-nbackp) 61219019Sgabor netflush(); 62219019Sgabor ncc = read(net, netibuf, sizeof netibuf); 63219019Sgabor if (ncc < 0) { 64219019Sgabor if (errno == EINTR) 65219019Sgabor return 1; 66219019Sgabor syslog(LOG_INFO, "ttloop: read: %m\n"); 67219019Sgabor exit(1); 68219019Sgabor } else if (ncc == 0) { 69219019Sgabor syslog(LOG_INFO, "ttloop: peer died\n"); 70219019Sgabor exit(1); 71219019Sgabor } 72219019Sgabor DIAG(TD_REPORT, { 73219019Sgabor output_data("td: ttloop read %d chars\r\n", ncc); 74219019Sgabor }); 75219019Sgabor netip = netibuf; 76219019Sgabor telrcv(); /* state machine */ 77219019Sgabor if (ncc > 0) { 78219019Sgabor pfrontp = pbackp = ptyobuf; 79219019Sgabor telrcv(); 80219019Sgabor } 81219019Sgabor return 0; 82219019Sgabor} /* end of ttloop */ 83219019Sgabor 84219019Sgabor/* 85219019Sgabor * Check a descriptor to see if out of band data exists on it. 86219019Sgabor */ 87219019Sgaborint 88219019Sgaborstilloob(int s) 89219019Sgabor{ 90219019Sgabor static struct timeval timeout = { 0 }; 91219019Sgabor fd_set excepts; 92219019Sgabor int value; 93219019Sgabor 94219019Sgabor if (s >= FD_SETSIZE) 95219019Sgabor fatal(ourpty, "fd too large"); 96219019Sgabor 97219019Sgabor do { 98219019Sgabor FD_ZERO(&excepts); 99219019Sgabor FD_SET(s, &excepts); 100219019Sgabor value = select(s+1, 0, 0, &excepts, &timeout); 101219019Sgabor } while ((value == -1) && (errno == EINTR)); 102219019Sgabor 103219019Sgabor if (value < 0) { 104219019Sgabor fatalperror(ourpty, "select"); 105219019Sgabor } 106219019Sgabor if (FD_ISSET(s, &excepts)) { 107219019Sgabor return 1; 108219019Sgabor } else { 109219019Sgabor return 0; 110219019Sgabor } 111219019Sgabor} 112219019Sgabor 113219019Sgaborvoid 114219019Sgaborptyflush(void) 115219019Sgabor{ 116219019Sgabor int n; 117219019Sgabor 118219019Sgabor if ((n = pfrontp - pbackp) > 0) { 119219019Sgabor DIAG((TD_REPORT | TD_PTYDATA), { 120219019Sgabor output_data("td: ptyflush %d chars\r\n", n); 121219019Sgabor }); 122219019Sgabor DIAG(TD_PTYDATA, printdata("pd", pbackp, n)); 123219019Sgabor n = write(ourpty, pbackp, n); 124219019Sgabor } 125219019Sgabor if (n < 0) { 126219019Sgabor if (errno == EWOULDBLOCK || errno == EINTR) 127219019Sgabor return; 128219019Sgabor cleanup(0); 129219019Sgabor } 130219019Sgabor pbackp += n; 131219019Sgabor if (pbackp == pfrontp) 132219019Sgabor pbackp = pfrontp = ptyobuf; 133219019Sgabor} 134219019Sgabor 135219019Sgabor/* 136219019Sgabor * nextitem() 137219019Sgabor * 138219019Sgabor * Return the address of the next "item" in the TELNET data 139219019Sgabor * stream. This will be the address of the next character if 140219019Sgabor * the current address is a user data character, or it will 141219019Sgabor * be the address of the character following the TELNET command 142219019Sgabor * if the current address is a TELNET IAC ("I Am a Command") 143219019Sgabor * character. 144219019Sgabor */ 145219019Sgaborchar * 146219019Sgabornextitem(char *current) 147219019Sgabor{ 148219019Sgabor if ((*current&0xff) != IAC) { 149219019Sgabor return current+1; 150219019Sgabor } 151219019Sgabor switch (*(current+1)&0xff) { 152219019Sgabor case DO: 153219019Sgabor case DONT: 154219019Sgabor case WILL: 155219019Sgabor case WONT: 156219019Sgabor return current+3; 157219019Sgabor case SB:{ 158219019Sgabor /* loop forever looking for the SE */ 159260264Sdim char *look = current+2; 160219019Sgabor 161219019Sgabor for (;;) { 162219019Sgabor if ((*look++&0xff) == IAC) { 163219019Sgabor if ((*look++&0xff) == SE) { 164219019Sgabor return look; 165219019Sgabor } 166219019Sgabor } 167219019Sgabor } 168219019Sgabor } 169219019Sgabor default: 170219019Sgabor return current+2; 171219019Sgabor } 172219019Sgabor} 173219019Sgabor 174219019Sgabor 175219019Sgabor/* 176219019Sgabor * netclear() 177260264Sdim * 178219019Sgabor * We are about to do a TELNET SYNCH operation. Clear 179219019Sgabor * the path to the network. 180282275Stijl * 181219019Sgabor * Things are a bit tricky since we may have sent the first 182219019Sgabor * byte or so of a previous TELNET command into the network. 183282275Stijl * So, we have to scan the network buffer from the beginning 184219019Sgabor * until we are up to where we want to be. 185219019Sgabor * 186219019Sgabor * A side effect of what we do, just to keep things 187219019Sgabor * simple, is to clear the urgent data pointer. The principal 188219019Sgabor * caller should be setting the urgent data pointer AFTER calling 189219019Sgabor * us in any case. 190219019Sgabor */ 191219019Sgaborvoid 192219019Sgabornetclear(void) 193219019Sgabor{ 194219019Sgabor char *thisitem, *next; 195219019Sgabor char *good; 196219019Sgabor#define wewant(p) ((nfrontp > p) && ((*p&0xff) == IAC) && \ 197219019Sgabor ((*(p+1)&0xff) != EC) && ((*(p+1)&0xff) != EL)) 198219019Sgabor 199219019Sgabor#ifdef ENCRYPTION 200219019Sgabor thisitem = nclearto > netobuf ? nclearto : netobuf; 201219019Sgabor#else 202219019Sgabor thisitem = netobuf; 203219019Sgabor#endif 204219019Sgabor 205219019Sgabor while ((next = nextitem(thisitem)) <= nbackp) { 206219019Sgabor thisitem = next; 207219019Sgabor } 208219019Sgabor 209219019Sgabor /* Now, thisitem is first before/at boundary. */ 210219019Sgabor 211219019Sgabor#ifdef ENCRYPTION 212219019Sgabor good = nclearto > netobuf ? nclearto : netobuf; 213219019Sgabor#else 214219019Sgabor good = netobuf; /* where the good bytes go */ 215219019Sgabor#endif 216219019Sgabor 217219019Sgabor while (nfrontp > thisitem) { 218219019Sgabor if (wewant(thisitem)) { 219219019Sgabor int length; 220219019Sgabor 221219019Sgabor next = thisitem; 222219019Sgabor do { 223219019Sgabor next = nextitem(next); 224219019Sgabor } while (wewant(next) && (nfrontp > next)); 225219019Sgabor length = next-thisitem; 226219019Sgabor memmove(good, thisitem, length); 227219019Sgabor good += length; 228219019Sgabor thisitem = next; 229219019Sgabor } else { 230219019Sgabor thisitem = nextitem(thisitem); 231219019Sgabor } 232219019Sgabor } 233219019Sgabor 234219019Sgabor nbackp = netobuf; 235219019Sgabor nfrontp = good; /* next byte to be sent */ 236219019Sgabor neturg = 0; 237219019Sgabor} /* end of netclear */ 238219019Sgabor 239219019Sgaborextern int not42; 240219019Sgabor 241219019Sgabor/* 242219019Sgabor * netflush 243219019Sgabor * Send as much data as possible to the network, 244219019Sgabor * handling requests for urgent data. 245219019Sgabor */ 246219019Sgaborvoid 247219019Sgabornetflush(void) 248219019Sgabor{ 249219019Sgabor int n; 250219019Sgabor 251219019Sgabor if ((n = nfrontp - nbackp) > 0) { 252219019Sgabor DIAG(TD_REPORT, 253219019Sgabor { n += output_data("td: netflush %d chars\r\n", n); 254219019Sgabor }); 255219019Sgabor#ifdef ENCRYPTION 256219019Sgabor if (encrypt_output) { 257219019Sgabor char *s = nclearto ? nclearto : nbackp; 258219019Sgabor if (nfrontp - s > 0) { 259219019Sgabor (*encrypt_output)((unsigned char *)s, nfrontp-s); 260219019Sgabor nclearto = nfrontp; 261219019Sgabor } 262219019Sgabor } 263219019Sgabor#endif 264219019Sgabor /* 265219019Sgabor * if no urgent data, or if the other side appears to be an 266219019Sgabor * old 4.2 client (and thus unable to survive TCP urgent data), 267219019Sgabor * write the entire buffer in non-OOB mode. 268219019Sgabor */ 269219019Sgabor#if 1 /* remove this to make it work between solaris 2.6 and linux */ 270219019Sgabor if ((neturg == 0) || (not42 == 0)) { 271219019Sgabor#endif 272219019Sgabor n = write(net, nbackp, n); /* normal write */ 273219019Sgabor#if 1 /* remove this to make it work between solaris 2.6 and linux */ 274219019Sgabor } else { 275219019Sgabor n = neturg - nbackp; 276219019Sgabor /* 277219019Sgabor * In 4.2 (and 4.3) systems, there is some question about 278219019Sgabor * what byte in a sendOOB operation is the "OOB" data. 279219019Sgabor * To make ourselves compatible, we only send ONE byte 280219019Sgabor * out of band, the one WE THINK should be OOB (though 281219019Sgabor * we really have more the TCP philosophy of urgent data 282219019Sgabor * rather than the Unix philosophy of OOB data). 283219019Sgabor */ 284219019Sgabor if (n > 1) { 285219019Sgabor n = send(net, nbackp, n-1, 0); /* send URGENT all by itself */ 286219019Sgabor } else { 287219019Sgabor n = send(net, nbackp, n, MSG_OOB); /* URGENT data */ 288219019Sgabor } 289219019Sgabor } 290219019Sgabor#endif 291219019Sgabor } 292219019Sgabor if (n < 0) { 293219019Sgabor if (errno == EWOULDBLOCK || errno == EINTR) 294219019Sgabor return; 295219019Sgabor cleanup(0); 296219019Sgabor } 297219019Sgabor nbackp += n; 298219019Sgabor#ifdef ENCRYPTION 299219019Sgabor if (nbackp > nclearto) 300219019Sgabor nclearto = 0; 301219019Sgabor#endif 302219019Sgabor if (nbackp >= neturg) { 303219019Sgabor neturg = 0; 304219019Sgabor } 305219019Sgabor if (nbackp == nfrontp) { 306219019Sgabor nbackp = nfrontp = netobuf; 307219019Sgabor#ifdef ENCRYPTION 308219019Sgabor nclearto = 0; 309219019Sgabor#endif 310219019Sgabor } 311219019Sgabor return; 312219019Sgabor} 313219019Sgabor 314219019Sgabor 315219019Sgabor/* 316219019Sgabor * writenet 317219019Sgabor * 318219019Sgabor * Just a handy little function to write a bit of raw data to the net. 319219019Sgabor * It will force a transmit of the buffer if necessary 320219019Sgabor * 321219019Sgabor * arguments 322219019Sgabor * ptr - A pointer to a character string to write 323219019Sgabor * len - How many bytes to write 324219019Sgabor */ 325219019Sgaborvoid 326219019Sgaborwritenet(const void *ptr, size_t len) 327219019Sgabor{ 328219019Sgabor /* flush buffer if no room for new data) */ 329219019Sgabor while ((&netobuf[BUFSIZ] - nfrontp) < len) { 330219019Sgabor /* if this fails, don't worry, buffer is a little big */ 331219019Sgabor netflush(); 332219019Sgabor } 333219019Sgabor if ((&netobuf[BUFSIZ] - nfrontp) < len) 334219019Sgabor abort(); 335219019Sgabor 336219019Sgabor memmove(nfrontp, ptr, len); 337219019Sgabor nfrontp += len; 338219019Sgabor} 339219019Sgabor 340219019Sgabor 341219019Sgabor/* 342219019Sgabor * miscellaneous functions doing a variety of little jobs follow ... 343219019Sgabor */ 344219019Sgabor 345219019Sgabor 346219019Sgaborvoid fatal(int f, char *msg) 347219019Sgabor{ 348219019Sgabor char buf[BUFSIZ]; 349219019Sgabor 350219019Sgabor snprintf(buf, sizeof(buf), "telnetd: %s.\r\n", msg); 351219019Sgabor#ifdef ENCRYPTION 352 if (encrypt_output) { 353 /* 354 * Better turn off encryption first.... 355 * Hope it flushes... 356 */ 357 encrypt_send_end(); 358 netflush(); 359 } 360#endif 361 write(f, buf, (int)strlen(buf)); 362 sleep(1); /*XXX*/ 363 exit(1); 364} 365 366void 367fatalperror_errno(int f, const char *msg, int error) 368{ 369 char buf[BUFSIZ]; 370 371 snprintf(buf, sizeof(buf), "%s: %s", msg, strerror(error)); 372 fatal(f, buf); 373} 374 375void 376fatalperror(int f, const char *msg) 377{ 378 fatalperror_errno(f, msg, errno); 379} 380 381char editedhost[32]; 382 383void edithost(char *pat, 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 strlcpy (res, host, 414 sizeof editedhost - (res - editedhost)); 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 436static char fmtstr[] = { "%l:%M%P on %A, %d %B %Y" }; 437 438void putf(char *cp, char *where) 439{ 440#ifdef HAVE_UNAME 441 struct utsname name; 442#endif 443 char *slash; 444 time_t t; 445 char db[100]; 446 447 /* if we don't have uname, set these to sensible values */ 448 char *sysname = "Unix", 449 *machine = "", 450 *release = "", 451 *version = ""; 452 453#ifdef HAVE_UNAME 454 uname(&name); 455 sysname=name.sysname; 456 machine=name.machine; 457 release=name.release; 458 version=name.version; 459#endif 460 461 putlocation = where; 462 463 while (*cp) { 464 if (*cp != '%') { 465 putchr(*cp++); 466 continue; 467 } 468 switch (*++cp) { 469 470 case 't': 471 slash = strchr(line+1, '/'); 472 if (slash == (char *) 0) 473 putstr(line); 474 else 475 putstr(&slash[1]); 476 break; 477 478 case 'h': 479 putstr(editedhost); 480 break; 481 482 case 's': 483 putstr(sysname); 484 break; 485 486 case 'm': 487 putstr(machine); 488 break; 489 490 case 'r': 491 putstr(release); 492 break; 493 494 case 'v': 495 putstr(version); 496 break; 497 498 case 'd': 499 time(&t); 500 strftime(db, sizeof(db), fmtstr, localtime(&t)); 501 putstr(db); 502 break; 503 504 case '%': 505 putchr('%'); 506 break; 507 } 508 cp++; 509 } 510} 511 512#ifdef DIAGNOSTICS 513/* 514 * Print telnet options and commands in plain text, if possible. 515 */ 516void 517printoption(char *fmt, int option) 518{ 519 if (TELOPT_OK(option)) 520 output_data("%s %s\r\n", 521 fmt, 522 TELOPT(option)); 523 else if (TELCMD_OK(option)) 524 output_data("%s %s\r\n", 525 fmt, 526 TELCMD(option)); 527 else 528 output_data("%s %d\r\n", 529 fmt, 530 option); 531 return; 532} 533 534void 535printsub(int direction, unsigned char *pointer, size_t length) 536 /* '<' or '>' */ 537 /* where suboption data sits */ 538 /* length of suboption data */ 539{ 540 int i = 0; 541 unsigned char buf[512]; 542 543 if (!(diagnostic & TD_OPTIONS)) 544 return; 545 546 if (direction) { 547 output_data("td: %s suboption ", 548 direction == '<' ? "recv" : "send"); 549 if (length >= 3) { 550 int j; 551 552 i = pointer[length-2]; 553 j = pointer[length-1]; 554 555 if (i != IAC || j != SE) { 556 output_data("(terminated by "); 557 if (TELOPT_OK(i)) 558 output_data("%s ", 559 TELOPT(i)); 560 else if (TELCMD_OK(i)) 561 output_data("%s ", 562 TELCMD(i)); 563 else 564 output_data("%d ", 565 i); 566 if (TELOPT_OK(j)) 567 output_data("%s", 568 TELOPT(j)); 569 else if (TELCMD_OK(j)) 570 output_data("%s", 571 TELCMD(j)); 572 else 573 output_data("%d", 574 j); 575 output_data(", not IAC SE!) "); 576 } 577 } 578 length -= 2; 579 } 580 if (length < 1) { 581 output_data("(Empty suboption??\?)"); 582 return; 583 } 584 switch (pointer[0]) { 585 case TELOPT_TTYPE: 586 output_data("TERMINAL-TYPE "); 587 switch (pointer[1]) { 588 case TELQUAL_IS: 589 output_data("IS \"%.*s\"", 590 (int)(length-2), 591 (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", (int)(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"); 632 break; 633 case LFLOW_ON: 634 output_data(" ON"); 635 break; 636 case LFLOW_RESTART_ANY: 637 output_data(" RESTART-ANY"); 638 break; 639 case LFLOW_RESTART_XON: 640 output_data(" RESTART-XON"); 641 break; 642 default: 643 output_data(" %d (unknown)", 644 pointer[1]); 645 } 646 for (i = 2; i < length; i++) { 647 output_data(" ?%d?", 648 pointer[i]); 649 } 650 break; 651 652 case TELOPT_NAWS: 653 output_data("NAWS"); 654 if (length < 2) { 655 output_data(" (empty suboption??\?)"); 656 break; 657 } 658 if (length == 2) { 659 output_data(" ?%d?", 660 pointer[1]); 661 break; 662 } 663 output_data(" %u %u(%u)", 664 pointer[1], 665 pointer[2], 666 (((unsigned int)pointer[1])<<8) + pointer[2]); 667 if (length == 4) { 668 output_data(" ?%d?", 669 pointer[3]); 670 break; 671 } 672 output_data(" %u %u(%u)", 673 pointer[3], 674 pointer[4], 675 (((unsigned int)pointer[3])<<8) + pointer[4]); 676 for (i = 5; i < length; i++) { 677 output_data(" ?%d?", 678 pointer[i]); 679 } 680 break; 681 682 case TELOPT_LINEMODE: 683 output_data("LINEMODE "); 684 if (length < 2) { 685 output_data(" (empty suboption??\?)"); 686 break; 687 } 688 switch (pointer[1]) { 689 case WILL: 690 output_data("WILL "); 691 goto common; 692 case WONT: 693 output_data("WONT "); 694 goto common; 695 case DO: 696 output_data("DO "); 697 goto common; 698 case DONT: 699 output_data("DONT "); 700 common: 701 if (length < 3) { 702 output_data("(no option??\?)"); 703 break; 704 } 705 switch (pointer[2]) { 706 case LM_FORWARDMASK: 707 output_data("Forward Mask"); 708 for (i = 3; i < length; i++) { 709 output_data(" %x", pointer[i]); 710 } 711 break; 712 default: 713 output_data("%d (unknown)", 714 pointer[2]); 715 for (i = 3; i < length; i++) { 716 output_data(" %d", 717 pointer[i]); 718 } 719 break; 720 } 721 break; 722 723 case LM_SLC: 724 output_data("SLC"); 725 for (i = 2; i < length - 2; i += 3) { 726 if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 727 output_data(" %s", 728 SLC_NAME(pointer[i+SLC_FUNC])); 729 else 730 output_data(" %d", 731 pointer[i+SLC_FUNC]); 732 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 733 case SLC_NOSUPPORT: 734 output_data(" NOSUPPORT"); 735 break; 736 case SLC_CANTCHANGE: 737 output_data(" CANTCHANGE"); 738 break; 739 case SLC_VARIABLE: 740 output_data(" VARIABLE"); 741 break; 742 case SLC_DEFAULT: 743 output_data(" DEFAULT"); 744 break; 745 } 746 output_data("%s%s%s", 747 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 748 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 749 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 750 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 751 SLC_FLUSHOUT| SLC_LEVELBITS)) { 752 output_data("(0x%x)", 753 pointer[i+SLC_FLAGS]); 754 } 755 output_data(" %d;", 756 pointer[i+SLC_VALUE]); 757 if ((pointer[i+SLC_VALUE] == IAC) && 758 (pointer[i+SLC_VALUE+1] == IAC)) 759 i++; 760 } 761 for (; i < length; i++) { 762 output_data(" ?%d?", 763 pointer[i]); 764 } 765 break; 766 767 case LM_MODE: 768 output_data("MODE "); 769 if (length < 3) { 770 output_data("(no mode??\?)"); 771 break; 772 } 773 { 774 char tbuf[32]; 775 snprintf(tbuf, 776 sizeof(tbuf), 777 "%s%s%s%s%s", 778 pointer[2]&MODE_EDIT ? "|EDIT" : "", 779 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 780 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 781 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 782 pointer[2]&MODE_ACK ? "|ACK" : ""); 783 output_data("%s", 784 tbuf[1] ? &tbuf[1] : "0"); 785 } 786 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { 787 output_data(" (0x%x)", 788 pointer[2]); 789 } 790 for (i = 3; i < length; i++) { 791 output_data(" ?0x%x?", 792 pointer[i]); 793 } 794 break; 795 default: 796 output_data("%d (unknown)", 797 pointer[1]); 798 for (i = 2; i < length; i++) { 799 output_data(" %d", pointer[i]); 800 } 801 } 802 break; 803 804 case TELOPT_STATUS: { 805 char *cp; 806 int j, k; 807 808 output_data("STATUS"); 809 810 switch (pointer[1]) { 811 default: 812 if (pointer[1] == TELQUAL_SEND) 813 output_data(" SEND"); 814 else 815 output_data(" %d (unknown)", 816 pointer[1]); 817 for (i = 2; i < length; i++) { 818 output_data(" ?%d?", 819 pointer[i]); 820 } 821 break; 822 case TELQUAL_IS: 823 output_data(" IS\r\n"); 824 825 for (i = 2; i < length; i++) { 826 switch(pointer[i]) { 827 case DO: cp = "DO"; goto common2; 828 case DONT: cp = "DONT"; goto common2; 829 case WILL: cp = "WILL"; goto common2; 830 case WONT: cp = "WONT"; goto common2; 831 common2: 832 i++; 833 if (TELOPT_OK(pointer[i])) 834 output_data(" %s %s", 835 cp, 836 TELOPT(pointer[i])); 837 else 838 output_data(" %s %d", 839 cp, 840 pointer[i]); 841 842 output_data("\r\n"); 843 break; 844 845 case SB: 846 output_data(" SB "); 847 i++; 848 j = k = i; 849 while (j < length) { 850 if (pointer[j] == SE) { 851 if (j+1 == length) 852 break; 853 if (pointer[j+1] == SE) 854 j++; 855 else 856 break; 857 } 858 pointer[k++] = pointer[j++]; 859 } 860 printsub(0, &pointer[i], k - i); 861 if (i < length) { 862 output_data(" SE"); 863 i = j; 864 } else 865 i = j - 1; 866 867 output_data("\r\n"); 868 869 break; 870 871 default: 872 output_data(" %d", 873 pointer[i]); 874 break; 875 } 876 } 877 break; 878 } 879 break; 880 } 881 882 case TELOPT_XDISPLOC: 883 output_data("X-DISPLAY-LOCATION "); 884 switch (pointer[1]) { 885 case TELQUAL_IS: 886 output_data("IS \"%.*s\"", 887 (int)(length-2), 888 (char *)pointer+2); 889 break; 890 case TELQUAL_SEND: 891 output_data("SEND"); 892 break; 893 default: 894 output_data("- unknown qualifier %d (0x%x).", 895 pointer[1], pointer[1]); 896 } 897 break; 898 899 case TELOPT_NEW_ENVIRON: 900 output_data("NEW-ENVIRON "); 901 goto env_common1; 902 case TELOPT_OLD_ENVIRON: 903 output_data("OLD-ENVIRON"); 904 env_common1: 905 switch (pointer[1]) { 906 case TELQUAL_IS: 907 output_data("IS "); 908 goto env_common; 909 case TELQUAL_SEND: 910 output_data("SEND "); 911 goto env_common; 912 case TELQUAL_INFO: 913 output_data("INFO "); 914 env_common: 915 { 916 int quote = 0; 917 for (i = 2; i < length; i++ ) { 918 switch (pointer[i]) { 919 case NEW_ENV_VAR: 920 if (quote) 921 output_data("\" "); 922 output_data("VAR "); 923 quote = 0; 924 break; 925 926 case NEW_ENV_VALUE: 927 if (quote) 928 output_data("\" "); 929 output_data("VALUE "); 930 quote = 0; 931 break; 932 933 case ENV_ESC: 934 if (quote) 935 output_data("\" "); 936 output_data("ESC "); 937 quote = 0; 938 break; 939 940 case ENV_USERVAR: 941 if (quote) 942 output_data("\" "); 943 output_data("USERVAR "); 944 quote = 0; 945 break; 946 947 default: 948 if (isprint(pointer[i]) && pointer[i] != '"') { 949 if (!quote) { 950 output_data("\""); 951 quote = 1; 952 } 953 output_data("%c", pointer[i]); 954 } else { 955 output_data("%03o ", pointer[i]); 956 quote = 0; 957 } 958 break; 959 } 960 } 961 if (quote) 962 output_data("\""); 963 break; 964 } 965 } 966 break; 967 968#ifdef AUTHENTICATION 969 case TELOPT_AUTHENTICATION: 970 output_data("AUTHENTICATION"); 971 972 if (length < 2) { 973 output_data(" (empty suboption??\?)"); 974 break; 975 } 976 switch (pointer[1]) { 977 case TELQUAL_REPLY: 978 case TELQUAL_IS: 979 output_data(" %s ", 980 (pointer[1] == TELQUAL_IS) ? 981 "IS" : "REPLY"); 982 if (AUTHTYPE_NAME_OK(pointer[2])) 983 output_data("%s ", 984 AUTHTYPE_NAME(pointer[2])); 985 else 986 output_data("%d ", 987 pointer[2]); 988 if (length < 3) { 989 output_data("(partial suboption??\?)"); 990 break; 991 } 992 output_data("%s|%s", 993 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 994 "CLIENT" : "SERVER", 995 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 996 "MUTUAL" : "ONE-WAY"); 997 998 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 999 output_data("%s", 1000 buf); 1001 break; 1002 1003 case TELQUAL_SEND: 1004 i = 2; 1005 output_data(" SEND "); 1006 while (i < length) { 1007 if (AUTHTYPE_NAME_OK(pointer[i])) 1008 output_data("%s ", 1009 AUTHTYPE_NAME(pointer[i])); 1010 else 1011 output_data("%d ", 1012 pointer[i]); 1013 if (++i >= length) { 1014 output_data("(partial suboption??\?)"); 1015 break; 1016 } 1017 output_data("%s|%s ", 1018 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 1019 "CLIENT" : "SERVER", 1020 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 1021 "MUTUAL" : "ONE-WAY"); 1022 ++i; 1023 } 1024 break; 1025 1026 case TELQUAL_NAME: 1027 i = 2; 1028 output_data(" NAME \"%.*s\"", 1029 (int)(length - 2), 1030 pointer); 1031 break; 1032 1033 default: 1034 for (i = 2; i < length; i++) { 1035 output_data(" ?%d?", 1036 pointer[i]); 1037 } 1038 break; 1039 } 1040 break; 1041#endif 1042 1043#ifdef ENCRYPTION 1044 case TELOPT_ENCRYPT: 1045 output_data("ENCRYPT"); 1046 if (length < 2) { 1047 output_data(" (empty suboption?)"); 1048 break; 1049 } 1050 switch (pointer[1]) { 1051 case ENCRYPT_START: 1052 output_data(" START"); 1053 break; 1054 1055 case ENCRYPT_END: 1056 output_data(" END"); 1057 break; 1058 1059 case ENCRYPT_REQSTART: 1060 output_data(" REQUEST-START"); 1061 break; 1062 1063 case ENCRYPT_REQEND: 1064 output_data(" REQUEST-END"); 1065 break; 1066 1067 case ENCRYPT_IS: 1068 case ENCRYPT_REPLY: 1069 output_data(" %s ", 1070 (pointer[1] == ENCRYPT_IS) ? 1071 "IS" : "REPLY"); 1072 if (length < 3) { 1073 output_data(" (partial suboption?)"); 1074 break; 1075 } 1076 if (ENCTYPE_NAME_OK(pointer[2])) 1077 output_data("%s ", 1078 ENCTYPE_NAME(pointer[2])); 1079 else 1080 output_data(" %d (unknown)", 1081 pointer[2]); 1082 1083 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 1084 output_data("%s", 1085 buf); 1086 break; 1087 1088 case ENCRYPT_SUPPORT: 1089 i = 2; 1090 output_data(" SUPPORT "); 1091 while (i < length) { 1092 if (ENCTYPE_NAME_OK(pointer[i])) 1093 output_data("%s ", 1094 ENCTYPE_NAME(pointer[i])); 1095 else 1096 output_data("%d ", 1097 pointer[i]); 1098 i++; 1099 } 1100 break; 1101 1102 case ENCRYPT_ENC_KEYID: 1103 output_data(" ENC_KEYID %d", pointer[1]); 1104 goto encommon; 1105 1106 case ENCRYPT_DEC_KEYID: 1107 output_data(" DEC_KEYID %d", pointer[1]); 1108 goto encommon; 1109 1110 default: 1111 output_data(" %d (unknown)", pointer[1]); 1112 encommon: 1113 for (i = 2; i < length; i++) { 1114 output_data(" %d", pointer[i]); 1115 } 1116 break; 1117 } 1118 break; 1119#endif 1120 1121 default: 1122 if (TELOPT_OK(pointer[0])) 1123 output_data("%s (unknown)", 1124 TELOPT(pointer[0])); 1125 else 1126 output_data("%d (unknown)", 1127 pointer[i]); 1128 for (i = 1; i < length; i++) { 1129 output_data(" %d", pointer[i]); 1130 } 1131 break; 1132 } 1133 output_data("\r\n"); 1134} 1135 1136/* 1137 * Dump a data buffer in hex and ascii to the output data stream. 1138 */ 1139void 1140printdata(char *tag, char *ptr, size_t cnt) 1141{ 1142 size_t i; 1143 char xbuf[30]; 1144 1145 while (cnt) { 1146 /* flush net output buffer if no room for new data) */ 1147 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 1148 netflush(); 1149 } 1150 1151 /* add a line of output */ 1152 output_data("%s: ", tag); 1153 for (i = 0; i < 20 && cnt; i++) { 1154 output_data("%02x", *ptr); 1155 if (isprint((unsigned char)*ptr)) { 1156 xbuf[i] = *ptr; 1157 } else { 1158 xbuf[i] = '.'; 1159 } 1160 if (i % 2) { 1161 output_data(" "); 1162 } 1163 cnt--; 1164 ptr++; 1165 } 1166 xbuf[i] = '\0'; 1167 output_data(" %s\r\n", xbuf); 1168 } 1169} 1170#endif /* DIAGNOSTICS */ 1171