1 /* 2 * Copyright (c) 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)utility.c 5.8 (Berkeley) 03/22/91"; 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 #if defined(ENCRYPT) 171 thisitem = nclearto > netobuf ? nclearto : netobuf; 172 #else 173 thisitem = netobuf; 174 #endif 175 176 while ((next = nextitem(thisitem)) <= nbackp) { 177 thisitem = next; 178 } 179 180 /* Now, thisitem is first before/at boundary. */ 181 182 #if defined(ENCRYPT) 183 good = nclearto > netobuf ? nclearto : netobuf; 184 #else 185 good = netobuf; /* where the good bytes go */ 186 #endif 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 #if defined(ENCRYPT) 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 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 #if defined(ENCRYPT) 267 if (nbackp > nclearto) 268 nclearto = 0; 269 #endif 270 if (nbackp >= neturg) { 271 neturg = 0; 272 } 273 if (nbackp == nfrontp) { 274 nbackp = nfrontp = netobuf; 275 #if defined(ENCRYPT) 276 nclearto = 0; 277 #endif 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 #if defined(ENCRYPT) 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 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 slash = rindex(line, '/'); 438 if (slash == (char *) 0) 439 putstr(line); 440 else 441 putstr(&slash[1]); 442 break; 443 444 case 'h': 445 putstr(editedhost); 446 break; 447 448 case 'd': 449 (void)time(&t); 450 (void)strftime(db, sizeof(db), fmtstr, localtime(&t)); 451 putstr(db); 452 break; 453 454 case '%': 455 putchr('%'); 456 break; 457 } 458 cp++; 459 } 460 } 461 462 #ifdef DIAGNOSTICS 463 /* 464 * Print telnet options and commands in plain text, if possible. 465 */ 466 void 467 printoption(fmt, option) 468 register char *fmt; 469 register int option; 470 { 471 if (TELOPT_OK(option)) 472 sprintf(nfrontp, "%s %s\r\n", fmt, TELOPT(option)); 473 else if (TELCMD_OK(option)) 474 sprintf(nfrontp, "%s %s\r\n", fmt, TELCMD(option)); 475 else 476 sprintf(nfrontp, "%s %d\r\n", fmt, option); 477 nfrontp += strlen(nfrontp); 478 return; 479 } 480 481 void 482 printsub(direction, pointer, length) 483 char direction; /* '<' or '>' */ 484 unsigned char *pointer; /* where suboption data sits */ 485 int length; /* length of suboption data */ 486 { 487 register int i; 488 char buf[512]; 489 490 if (!(diagnostic & TD_OPTIONS)) 491 return; 492 493 if (direction) { 494 sprintf(nfrontp, "td: %s suboption ", 495 direction == '<' ? "recv" : "send"); 496 nfrontp += strlen(nfrontp); 497 if (length >= 3) { 498 register int j; 499 500 i = pointer[length-2]; 501 j = pointer[length-1]; 502 503 if (i != IAC || j != SE) { 504 sprintf(nfrontp, "(terminated by "); 505 nfrontp += strlen(nfrontp); 506 if (TELOPT_OK(i)) 507 sprintf(nfrontp, "%s ", TELOPT(i)); 508 else if (TELCMD_OK(i)) 509 sprintf(nfrontp, "%s ", TELCMD(i)); 510 else 511 sprintf(nfrontp, "%d ", i); 512 nfrontp += strlen(nfrontp); 513 if (TELOPT_OK(j)) 514 sprintf(nfrontp, "%s", TELOPT(j)); 515 else if (TELCMD_OK(j)) 516 sprintf(nfrontp, "%s", TELCMD(j)); 517 else 518 sprintf(nfrontp, "%d", j); 519 nfrontp += strlen(nfrontp); 520 sprintf(nfrontp, ", not IAC SE!) "); 521 nfrontp += strlen(nfrontp); 522 } 523 } 524 length -= 2; 525 } 526 if (length < 1) { 527 sprintf(nfrontp, "(Empty suboption???)"); 528 nfrontp += strlen(nfrontp); 529 return; 530 } 531 switch (pointer[0]) { 532 case TELOPT_TTYPE: 533 sprintf(nfrontp, "TERMINAL-TYPE "); 534 nfrontp += strlen(nfrontp); 535 switch (pointer[1]) { 536 case TELQUAL_IS: 537 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); 538 break; 539 case TELQUAL_SEND: 540 sprintf(nfrontp, "SEND"); 541 break; 542 default: 543 sprintf(nfrontp, 544 "- unknown qualifier %d (0x%x).", 545 pointer[1], pointer[1]); 546 } 547 nfrontp += strlen(nfrontp); 548 break; 549 case TELOPT_TSPEED: 550 sprintf(nfrontp, "TERMINAL-SPEED"); 551 nfrontp += strlen(nfrontp); 552 if (length < 2) { 553 sprintf(nfrontp, " (empty suboption???)"); 554 nfrontp += strlen(nfrontp); 555 break; 556 } 557 switch (pointer[1]) { 558 case TELQUAL_IS: 559 sprintf(nfrontp, " IS %.*s", length-2, (char *)pointer+2); 560 nfrontp += strlen(nfrontp); 561 break; 562 default: 563 if (pointer[1] == 1) 564 sprintf(nfrontp, " SEND"); 565 else 566 sprintf(nfrontp, " %d (unknown)", pointer[1]); 567 nfrontp += strlen(nfrontp); 568 for (i = 2; i < length; i++) { 569 sprintf(nfrontp, " ?%d?", pointer[i]); 570 nfrontp += strlen(nfrontp); 571 } 572 break; 573 } 574 break; 575 576 case TELOPT_LFLOW: 577 sprintf(nfrontp, "TOGGLE-FLOW-CONTROL"); 578 nfrontp += strlen(nfrontp); 579 if (length < 2) { 580 sprintf(nfrontp, " (empty suboption???)"); 581 nfrontp += strlen(nfrontp); 582 break; 583 } 584 switch (pointer[1]) { 585 case 0: 586 sprintf(nfrontp, " OFF"); break; 587 case 1: 588 sprintf(nfrontp, " ON"); break; 589 default: 590 sprintf(nfrontp, " %d (unknown)", pointer[1]); 591 } 592 nfrontp += strlen(nfrontp); 593 for (i = 2; i < length; i++) { 594 sprintf(nfrontp, " ?%d?", pointer[i]); 595 nfrontp += strlen(nfrontp); 596 } 597 break; 598 599 case TELOPT_NAWS: 600 sprintf(nfrontp, "NAWS"); 601 nfrontp += strlen(nfrontp); 602 if (length < 2) { 603 sprintf(nfrontp, " (empty suboption???)"); 604 nfrontp += strlen(nfrontp); 605 break; 606 } 607 if (length == 2) { 608 sprintf(nfrontp, " ?%d?", pointer[1]); 609 nfrontp += strlen(nfrontp); 610 break; 611 } 612 sprintf(nfrontp, " %d %d (%d)", 613 pointer[1], pointer[2], 614 (int)((((unsigned int)pointer[1])<<8)|((unsigned int)pointer[2]))); 615 nfrontp += strlen(nfrontp); 616 if (length == 4) { 617 sprintf(nfrontp, " ?%d?", pointer[3]); 618 nfrontp += strlen(nfrontp); 619 break; 620 } 621 sprintf(nfrontp, " %d %d (%d)", 622 pointer[3], pointer[4], 623 (int)((((unsigned int)pointer[3])<<8)|((unsigned int)pointer[4]))); 624 nfrontp += strlen(nfrontp); 625 for (i = 5; i < length; i++) { 626 sprintf(nfrontp, " ?%d?", pointer[i]); 627 nfrontp += strlen(nfrontp); 628 } 629 break; 630 631 case TELOPT_LINEMODE: 632 sprintf(nfrontp, "LINEMODE "); 633 nfrontp += strlen(nfrontp); 634 if (length < 2) { 635 sprintf(nfrontp, " (empty suboption???)"); 636 nfrontp += strlen(nfrontp); 637 break; 638 } 639 switch (pointer[1]) { 640 case WILL: 641 sprintf(nfrontp, "WILL "); 642 goto common; 643 case WONT: 644 sprintf(nfrontp, "WONT "); 645 goto common; 646 case DO: 647 sprintf(nfrontp, "DO "); 648 goto common; 649 case DONT: 650 sprintf(nfrontp, "DONT "); 651 common: 652 nfrontp += strlen(nfrontp); 653 if (length < 3) { 654 sprintf(nfrontp, "(no option???)"); 655 nfrontp += strlen(nfrontp); 656 break; 657 } 658 switch (pointer[2]) { 659 case LM_FORWARDMASK: 660 sprintf(nfrontp, "Forward Mask"); 661 nfrontp += strlen(nfrontp); 662 for (i = 3; i < length; i++) { 663 sprintf(nfrontp, " %x", pointer[i]); 664 nfrontp += strlen(nfrontp); 665 } 666 break; 667 default: 668 sprintf(nfrontp, "%d (unknown)", pointer[2]); 669 nfrontp += strlen(nfrontp); 670 for (i = 3; i < length; i++) { 671 sprintf(nfrontp, " %d", pointer[i]); 672 nfrontp += strlen(nfrontp); 673 } 674 break; 675 } 676 break; 677 678 case LM_SLC: 679 sprintf(nfrontp, "SLC"); 680 nfrontp += strlen(nfrontp); 681 for (i = 2; i < length - 2; i += 3) { 682 if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 683 sprintf(nfrontp, " %s", SLC_NAME(pointer[i+SLC_FUNC])); 684 else 685 sprintf(nfrontp, " %d", pointer[i+SLC_FUNC]); 686 nfrontp += strlen(nfrontp); 687 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 688 case SLC_NOSUPPORT: 689 sprintf(nfrontp, " NOSUPPORT"); break; 690 case SLC_CANTCHANGE: 691 sprintf(nfrontp, " CANTCHANGE"); break; 692 case SLC_VARIABLE: 693 sprintf(nfrontp, " VARIABLE"); break; 694 case SLC_DEFAULT: 695 sprintf(nfrontp, " DEFAULT"); break; 696 } 697 nfrontp += strlen(nfrontp); 698 sprintf(nfrontp, "%s%s%s", 699 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 700 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 701 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 702 nfrontp += strlen(nfrontp); 703 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 704 SLC_FLUSHOUT| SLC_LEVELBITS)) { 705 sprintf(nfrontp, "(0x%x)", pointer[i+SLC_FLAGS]); 706 nfrontp += strlen(nfrontp); 707 } 708 sprintf(nfrontp, " %d;", pointer[i+SLC_VALUE]); 709 nfrontp += strlen(nfrontp); 710 if ((pointer[i+SLC_VALUE] == IAC) && 711 (pointer[i+SLC_VALUE+1] == IAC)) 712 i++; 713 } 714 for (; i < length; i++) { 715 sprintf(nfrontp, " ?%d?", pointer[i]); 716 nfrontp += strlen(nfrontp); 717 } 718 break; 719 720 case LM_MODE: 721 sprintf(nfrontp, "MODE "); 722 nfrontp += strlen(nfrontp); 723 if (length < 3) { 724 sprintf(nfrontp, "(no mode???)"); 725 nfrontp += strlen(nfrontp); 726 break; 727 } 728 { 729 char tbuf[32]; 730 sprintf(tbuf, "%s%s%s%s%s", 731 pointer[2]&MODE_EDIT ? "|EDIT" : "", 732 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 733 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 734 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 735 pointer[2]&MODE_ACK ? "|ACK" : ""); 736 sprintf(nfrontp, "%s", tbuf[1] ? &tbuf[1] : "0"); 737 nfrontp += strlen(nfrontp); 738 } 739 if (pointer[2]&~(MODE_EDIT|MODE_TRAPSIG|MODE_ACK)) { 740 sprintf(nfrontp, " (0x%x)", pointer[2]); 741 nfrontp += strlen(nfrontp); 742 } 743 for (i = 3; i < length; i++) { 744 sprintf(nfrontp, " ?0x%x?", pointer[i]); 745 nfrontp += strlen(nfrontp); 746 } 747 break; 748 default: 749 sprintf(nfrontp, "%d (unknown)", pointer[1]); 750 nfrontp += strlen(nfrontp); 751 for (i = 2; i < length; i++) { 752 sprintf(nfrontp, " %d", pointer[i]); 753 nfrontp += strlen(nfrontp); 754 } 755 } 756 break; 757 758 case TELOPT_STATUS: { 759 register char *cp; 760 register int j, k; 761 762 sprintf(nfrontp, "STATUS"); 763 nfrontp += strlen(nfrontp); 764 765 switch (pointer[1]) { 766 default: 767 if (pointer[1] == TELQUAL_SEND) 768 sprintf(nfrontp, " SEND"); 769 else 770 sprintf(nfrontp, " %d (unknown)", pointer[1]); 771 nfrontp += strlen(nfrontp); 772 for (i = 2; i < length; i++) { 773 sprintf(nfrontp, " ?%d?", pointer[i]); 774 nfrontp += strlen(nfrontp); 775 } 776 break; 777 case TELQUAL_IS: 778 sprintf(nfrontp, " IS\r\n"); 779 nfrontp += strlen(nfrontp); 780 781 for (i = 2; i < length; i++) { 782 switch(pointer[i]) { 783 case DO: cp = "DO"; goto common2; 784 case DONT: cp = "DONT"; goto common2; 785 case WILL: cp = "WILL"; goto common2; 786 case WONT: cp = "WONT"; goto common2; 787 common2: 788 i++; 789 if (TELOPT_OK((int)pointer[i])) 790 sprintf(nfrontp, " %s %s", cp, TELOPT(pointer[i])); 791 else 792 sprintf(nfrontp, " %s %d", cp, pointer[i]); 793 nfrontp += strlen(nfrontp); 794 795 sprintf(nfrontp, "\r\n"); 796 nfrontp += strlen(nfrontp); 797 break; 798 799 case SB: 800 sprintf(nfrontp, " SB "); 801 nfrontp += strlen(nfrontp); 802 i++; 803 j = k = i; 804 while (j < length) { 805 if (pointer[j] == SE) { 806 if (j+1 == length) 807 break; 808 if (pointer[j+1] == SE) 809 j++; 810 else 811 break; 812 } 813 pointer[k++] = pointer[j++]; 814 } 815 printsub(0, &pointer[i], k - i); 816 if (i < length) { 817 sprintf(nfrontp, " SE"); 818 nfrontp += strlen(nfrontp); 819 i = j; 820 } else 821 i = j - 1; 822 823 sprintf(nfrontp, "\r\n"); 824 nfrontp += strlen(nfrontp); 825 826 break; 827 828 default: 829 sprintf(nfrontp, " %d", pointer[i]); 830 nfrontp += strlen(nfrontp); 831 break; 832 } 833 } 834 break; 835 } 836 break; 837 } 838 839 case TELOPT_XDISPLOC: 840 sprintf(nfrontp, "X-DISPLAY-LOCATION "); 841 nfrontp += strlen(nfrontp); 842 switch (pointer[1]) { 843 case TELQUAL_IS: 844 sprintf(nfrontp, "IS \"%.*s\"", length-2, (char *)pointer+2); 845 break; 846 case TELQUAL_SEND: 847 sprintf(nfrontp, "SEND"); 848 break; 849 default: 850 sprintf(nfrontp, "- unknown qualifier %d (0x%x).", 851 pointer[1], pointer[1]); 852 } 853 nfrontp += strlen(nfrontp); 854 break; 855 856 case TELOPT_ENVIRON: 857 sprintf(nfrontp, "ENVIRON "); 858 nfrontp += strlen(nfrontp); 859 switch (pointer[1]) { 860 case TELQUAL_IS: 861 sprintf(nfrontp, "IS "); 862 goto env_common; 863 case TELQUAL_SEND: 864 sprintf(nfrontp, "SEND "); 865 goto env_common; 866 case TELQUAL_INFO: 867 sprintf(nfrontp, "INFO "); 868 env_common: 869 nfrontp += strlen(nfrontp); 870 { 871 register int noquote = 2; 872 for (i = 2; i < length; i++ ) { 873 switch (pointer[i]) { 874 case ENV_VAR: 875 if (pointer[1] == TELQUAL_SEND) 876 goto def_case; 877 sprintf(nfrontp, "\" VAR " + noquote); 878 nfrontp += strlen(nfrontp); 879 noquote = 2; 880 break; 881 882 case ENV_VALUE: 883 sprintf(nfrontp, "\" VALUE " + noquote); 884 nfrontp += strlen(nfrontp); 885 noquote = 2; 886 break; 887 888 case ENV_ESC: 889 sprintf(nfrontp, "\" ESC " + noquote); 890 nfrontp += strlen(nfrontp); 891 noquote = 2; 892 break; 893 894 default: 895 def_case: 896 if (isprint(pointer[i]) && pointer[i] != '"') { 897 if (noquote) { 898 *nfrontp++ = '"'; 899 noquote = 0; 900 } 901 *nfrontp++ = pointer[i]; 902 } else { 903 sprintf(nfrontp, "\" %03o " + noquote, 904 pointer[i]); 905 nfrontp += strlen(nfrontp); 906 noquote = 2; 907 } 908 break; 909 } 910 } 911 if (!noquote) 912 *nfrontp++ = '"'; 913 break; 914 } 915 } 916 break; 917 918 #if defined(AUTHENTICATE) 919 case TELOPT_AUTHENTICATION: 920 sprintf(nfrontp, "AUTHENTICATION"); 921 nfrontp += strlen(nfrontp); 922 923 if (length < 2) { 924 sprintf(nfrontp, " (empty suboption???)"); 925 nfrontp += strlen(nfrontp); 926 break; 927 } 928 switch (pointer[1]) { 929 case TELQUAL_REPLY: 930 case TELQUAL_IS: 931 sprintf(nfrontp, " %s ", (pointer[1] == TELQUAL_IS) ? 932 "IS" : "REPLY"); 933 nfrontp += strlen(nfrontp); 934 if (AUTHTYPE_NAME_OK(pointer[2])) 935 sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[2])); 936 else 937 sprintf(nfrontp, "%d ", pointer[2]); 938 nfrontp += strlen(nfrontp); 939 if (length < 3) { 940 sprintf(nfrontp, "(partial suboption???)"); 941 nfrontp += strlen(nfrontp); 942 break; 943 } 944 sprintf(nfrontp, "%s|%s", 945 ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 946 "CLIENT" : "SERVER", 947 ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 948 "MUTUAL" : "ONE-WAY"); 949 nfrontp += strlen(nfrontp); 950 951 auth_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 952 sprintf(nfrontp, "%s", buf); 953 nfrontp += strlen(nfrontp); 954 break; 955 956 case TELQUAL_SEND: 957 i = 2; 958 sprintf(nfrontp, " SEND "); 959 nfrontp += strlen(nfrontp); 960 while (i < length) { 961 if (AUTHTYPE_NAME_OK(pointer[i])) 962 sprintf(nfrontp, "%s ", AUTHTYPE_NAME(pointer[i])); 963 else 964 sprintf(nfrontp, "%d ", pointer[i]); 965 nfrontp += strlen(nfrontp); 966 if (++i >= length) { 967 sprintf(nfrontp, "(partial suboption???)"); 968 nfrontp += strlen(nfrontp); 969 break; 970 } 971 sprintf(nfrontp, "%s|%s ", 972 ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? 973 "CLIENT" : "SERVER", 974 ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? 975 "MUTUAL" : "ONE-WAY"); 976 nfrontp += strlen(nfrontp); 977 ++i; 978 } 979 break; 980 981 case TELQUAL_NAME: 982 i = 2; 983 sprintf(nfrontp, " NAME \""); 984 nfrontp += strlen(nfrontp); 985 while (i < length) 986 *nfrontp += pointer[i++]; 987 *nfrontp += '"'; 988 break; 989 990 default: 991 for (i = 2; i < length; i++) { 992 sprintf(nfrontp, " ?%d?", pointer[i]); 993 nfrontp += strlen(nfrontp); 994 } 995 break; 996 } 997 break; 998 #endif 999 1000 #if defined(ENCRYPT) 1001 case TELOPT_ENCRYPT: 1002 sprintf(nfrontp, "ENCRYPT"); 1003 nfrontp += strlen(nfrontp); 1004 if (length < 2) { 1005 sprintf(nfrontp, " (empty suboption???)"); 1006 nfrontp += strlen(nfrontp); 1007 break; 1008 } 1009 switch (pointer[1]) { 1010 case ENCRYPT_START: 1011 sprintf(nfrontp, " START"); 1012 nfrontp += strlen(nfrontp); 1013 break; 1014 1015 case ENCRYPT_END: 1016 sprintf(nfrontp, " END"); 1017 nfrontp += strlen(nfrontp); 1018 break; 1019 1020 case ENCRYPT_REQSTART: 1021 sprintf(nfrontp, " REQUEST-START"); 1022 nfrontp += strlen(nfrontp); 1023 break; 1024 1025 case ENCRYPT_REQEND: 1026 sprintf(nfrontp, " REQUEST-END"); 1027 nfrontp += strlen(nfrontp); 1028 break; 1029 1030 case ENCRYPT_IS: 1031 case ENCRYPT_REPLY: 1032 sprintf(nfrontp, " %s ", (pointer[1] == ENCRYPT_IS) ? 1033 "IS" : "REPLY"); 1034 nfrontp += strlen(nfrontp); 1035 if (length < 3) { 1036 sprintf(nfrontp, " (partial suboption???)"); 1037 nfrontp += strlen(nfrontp); 1038 break; 1039 } 1040 if (ENCTYPE_NAME_OK(pointer[2])) 1041 sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[2])); 1042 else 1043 sprintf(nfrontp, " %d (unknown)", pointer[2]); 1044 nfrontp += strlen(nfrontp); 1045 1046 encrypt_printsub(&pointer[1], length - 1, buf, sizeof(buf)); 1047 sprintf(nfrontp, "%s", buf); 1048 nfrontp += strlen(nfrontp); 1049 break; 1050 1051 case ENCRYPT_SUPPORT: 1052 i = 2; 1053 sprintf(nfrontp, " SUPPORT "); 1054 nfrontp += strlen(nfrontp); 1055 while (i < length) { 1056 if (ENCTYPE_NAME_OK(pointer[i])) 1057 sprintf(nfrontp, "%s ", ENCTYPE_NAME(pointer[i])); 1058 else 1059 sprintf(nfrontp, "%d ", pointer[i]); 1060 nfrontp += strlen(nfrontp); 1061 i++; 1062 } 1063 break; 1064 1065 case ENCRYPT_ENC_KEYID: 1066 sprintf(nfrontp, " ENC_KEYID", pointer[1]); 1067 nfrontp += strlen(nfrontp); 1068 goto encommon; 1069 1070 case ENCRYPT_DEC_KEYID: 1071 sprintf(nfrontp, " DEC_KEYID", pointer[1]); 1072 nfrontp += strlen(nfrontp); 1073 goto encommon; 1074 1075 default: 1076 sprintf(nfrontp, " %d (unknown)", pointer[1]); 1077 nfrontp += strlen(nfrontp); 1078 encommon: 1079 for (i = 2; i < length; i++) { 1080 sprintf(nfrontp, " %d", pointer[i]); 1081 nfrontp += strlen(nfrontp); 1082 } 1083 break; 1084 } 1085 break; 1086 #endif 1087 1088 default: 1089 if (TELOPT_OK(pointer[0])) 1090 sprintf(nfrontp, "%s (unknown)", TELOPT(pointer[0])); 1091 else 1092 sprintf(nfrontp, "%d (unknown)", pointer[i]); 1093 nfrontp += strlen(nfrontp); 1094 for (i = 1; i < length; i++) { 1095 sprintf(nfrontp, " %d", pointer[i]); 1096 nfrontp += strlen(nfrontp); 1097 } 1098 break; 1099 } 1100 sprintf(nfrontp, "\r\n"); 1101 nfrontp += strlen(nfrontp); 1102 } 1103 1104 /* 1105 * Dump a data buffer in hex and ascii to the output data stream. 1106 */ 1107 void 1108 printdata(tag, ptr, cnt) 1109 register char *tag; 1110 register char *ptr; 1111 register int cnt; 1112 { 1113 register int i; 1114 char xbuf[30]; 1115 1116 while (cnt) { 1117 /* flush net output buffer if no room for new data) */ 1118 if ((&netobuf[BUFSIZ] - nfrontp) < 80) { 1119 netflush(); 1120 } 1121 1122 /* add a line of output */ 1123 sprintf(nfrontp, "%s: ", tag); 1124 nfrontp += strlen(nfrontp); 1125 for (i = 0; i < 20 && cnt; i++) { 1126 sprintf(nfrontp, "%02x", *ptr); 1127 nfrontp += strlen(nfrontp); 1128 if (isprint(*ptr)) { 1129 xbuf[i] = *ptr; 1130 } else { 1131 xbuf[i] = '.'; 1132 } 1133 if (i % 2) { 1134 *nfrontp = ' '; 1135 nfrontp++; 1136 } 1137 cnt--; 1138 ptr++; 1139 } 1140 xbuf[i] = '\0'; 1141 sprintf(nfrontp, " %s\r\n", xbuf ); 1142 nfrontp += strlen(nfrontp); 1143 } 1144 } 1145 #endif /* DIAGNOSTICS */ 1146