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