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