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