1 /* 2 * Copyright 1994-2002 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * usr/src/cmd/cmd-inet/usr.bin/telnet/utilities.c 8 */ 9 10 /* 11 * Copyright (c) 1988, 1993 12 * The Regents of the University of California. All rights reserved. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 */ 42 43 #ifndef lint 44 static char sccsid[] = "@(#)utilities.c 8.1 (Berkeley) 6/6/93"; 45 #endif /* not lint */ 46 47 #define TELOPTS 48 #ifdef lint 49 static char *telcmds[] = {0}; 50 static char *slc_names[] = {0}; 51 static char *encrypt_names[] = {0}; 52 static char *enctype_names[] = {0}; 53 #else /* lint */ 54 #define TELCMDS 55 #define SLC_NAMES 56 #endif /* lint */ 57 #include <arpa/telnet.h> 58 #include <sys/types.h> 59 #include <sys/time.h> 60 #include <sys/param.h> 61 #include <sys/socket.h> 62 #include <errno.h> 63 64 #include <ctype.h> 65 66 #include "general.h" 67 68 #include "ring.h" 69 70 #include "defines.h" 71 72 #include "externs.h" 73 74 FILE *NetTrace = 0; /* Not in bss, since needs to stay */ 75 int prettydump; 76 77 /* 78 * upcase() 79 * 80 * Upcase (in place) the argument. 81 */ 82 83 void 84 upcase(argument) 85 register char *argument; 86 { 87 register int c; 88 89 while ((c = *argument) != 0) { 90 if (islower(c)) { 91 *argument = toupper(c); 92 } 93 argument++; 94 } 95 } 96 97 /* 98 * SetSockOpt() 99 * 100 * Compensate for differences in 4.2 and 4.3 systems. 101 */ 102 103 int 104 SetSockOpt(fd, level, option, yesno) 105 int fd, level, option, yesno; 106 { 107 return (setsockopt(fd, level, option, &yesno, sizeof (yesno))); 108 } 109 110 /* 111 * The following are routines used to print out debugging information. 112 */ 113 114 unsigned char NetTraceFile[MAXPATHLEN] = "(standard output)"; 115 116 void 117 SetNetTrace(file) 118 register char *file; 119 { 120 if (NetTrace && NetTrace != stdout) 121 (void) fclose(NetTrace); 122 if (file && (strcmp(file, "-") != 0)) { 123 NetTrace = fopen(file, "w"); 124 if (NetTrace) { 125 (void) strcpy((char *)NetTraceFile, file); 126 return; 127 } 128 (void) fprintf(stderr, "Cannot open %s.\n", file); 129 } 130 NetTrace = stdout; 131 (void) strcpy((char *)NetTraceFile, "(standard output)"); 132 } 133 134 void 135 Dump(direction, buffer, length) 136 char direction; 137 unsigned char *buffer; 138 int length; 139 { 140 #define BYTES_PER_LINE 32 141 #define min(x, y) ((x < y) ? x:y) 142 unsigned char *pThis; 143 int offset; 144 145 offset = 0; 146 147 while (length) { 148 /* print one line */ 149 (void) fprintf(NetTrace, "%c 0x%x\t", direction, offset); 150 pThis = buffer; 151 if (prettydump) { 152 buffer = buffer + min(length, BYTES_PER_LINE/2); 153 while (pThis < buffer) { 154 (void) fprintf(NetTrace, "%c%.2x", 155 (((*pThis)&0xff) == 0xff) ? '*' : ' ', 156 (*pThis)&0xff); 157 pThis++; 158 } 159 length -= BYTES_PER_LINE/2; 160 offset += BYTES_PER_LINE/2; 161 } else { 162 buffer = buffer + min(length, BYTES_PER_LINE); 163 while (pThis < buffer) { 164 (void) fprintf(NetTrace, "%.2x", (*pThis)&0xff); 165 pThis++; 166 } 167 length -= BYTES_PER_LINE; 168 offset += BYTES_PER_LINE; 169 } 170 if (NetTrace == stdout) { 171 (void) fprintf(NetTrace, "\r\n"); 172 } else { 173 (void) fprintf(NetTrace, "\n"); 174 } 175 if (length < 0) { 176 (void) fflush(NetTrace); 177 return; 178 } 179 /* find next unique line */ 180 } 181 (void) fflush(NetTrace); 182 } 183 184 185 void 186 printoption(direction, cmd, option) 187 char *direction; 188 int cmd, option; 189 { 190 if (!showoptions) 191 return; 192 if (cmd == IAC) { 193 if (TELCMD_OK(option)) 194 (void) fprintf(NetTrace, "%s IAC %s", direction, 195 TELCMD(option)); 196 else 197 (void) fprintf(NetTrace, "%s IAC %d", direction, 198 option); 199 } else { 200 register char *fmt; 201 fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" : 202 (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0; 203 if (fmt) { 204 (void) fprintf(NetTrace, "%s %s ", direction, fmt); 205 if (TELOPT_OK(option)) 206 (void) fprintf(NetTrace, "%s", TELOPT(option)); 207 else if (option == TELOPT_EXOPL) 208 (void) fprintf(NetTrace, "EXOPL"); 209 else 210 (void) fprintf(NetTrace, "%d", option); 211 } else 212 (void) fprintf(NetTrace, "%s %d %d", direction, cmd, 213 option); 214 } 215 if (NetTrace == stdout) { 216 (void) fprintf(NetTrace, "\r\n"); 217 (void) fflush(NetTrace); 218 } else { 219 (void) fprintf(NetTrace, "\n"); 220 } 221 } 222 223 void 224 optionstatus() 225 { 226 register int i; 227 extern char will_wont_resp[], do_dont_resp[]; 228 229 for (i = 0; i < SUBBUFSIZE; i++) { 230 if (do_dont_resp[i]) { 231 if (TELOPT_OK(i)) 232 (void) printf("resp DO_DONT %s: %d\n", 233 TELOPT(i), do_dont_resp[i]); 234 else if (TELCMD_OK(i)) 235 (void) printf("resp DO_DONT %s: %d\n", 236 TELCMD(i), do_dont_resp[i]); 237 else 238 (void) printf("resp DO_DONT %d: %d\n", i, 239 do_dont_resp[i]); 240 if (my_want_state_is_do(i)) { 241 if (TELOPT_OK(i)) 242 (void) printf("want DO %s\n", 243 TELOPT(i)); 244 else if (TELCMD_OK(i)) 245 (void) printf("want DO %s\n", 246 TELCMD(i)); 247 else 248 (void) printf("want DO %d\n", i); 249 } else { 250 if (TELOPT_OK(i)) 251 (void) printf("want DONT %s\n", 252 TELOPT(i)); 253 else if (TELCMD_OK(i)) 254 (void) printf("want DONT %s\n", 255 TELCMD(i)); 256 else 257 (void) printf("want DONT %d\n", i); 258 } 259 } else { 260 if (my_state_is_do(i)) { 261 if (TELOPT_OK(i)) 262 (void) printf(" DO %s\n", 263 TELOPT(i)); 264 else if (TELCMD_OK(i)) 265 (void) printf(" DO %s\n", 266 TELCMD(i)); 267 else 268 (void) printf(" DO %d\n", i); 269 } 270 } 271 if (will_wont_resp[i]) { 272 if (TELOPT_OK(i)) 273 (void) printf("resp WILL_WONT %s: %d\n", 274 TELOPT(i), will_wont_resp[i]); 275 else if (TELCMD_OK(i)) 276 (void) printf("resp WILL_WONT %s: %d\n", 277 TELCMD(i), will_wont_resp[i]); 278 else 279 (void) printf("resp WILL_WONT %d: %d\n", 280 i, will_wont_resp[i]); 281 if (my_want_state_is_will(i)) { 282 if (TELOPT_OK(i)) 283 (void) printf("want WILL %s\n", 284 TELOPT(i)); 285 else if (TELCMD_OK(i)) 286 (void) printf("want WILL %s\n", 287 TELCMD(i)); 288 else 289 (void) printf("want WILL %d\n", i); 290 } else { 291 if (TELOPT_OK(i)) 292 (void) printf("want WONT %s\n", 293 TELOPT(i)); 294 else if (TELCMD_OK(i)) 295 (void) printf("want WONT %s\n", 296 TELCMD(i)); 297 else 298 (void) printf("want WONT %d\n", i); 299 } 300 } else { 301 if (my_state_is_will(i)) { 302 if (TELOPT_OK(i)) 303 (void) printf(" WILL %s\n", 304 TELOPT(i)); 305 else if (TELCMD_OK(i)) 306 (void) printf(" WILL %s\n", 307 TELCMD(i)); 308 else 309 (void) printf(" WILL %d\n", i); 310 } 311 } 312 } 313 314 } 315 316 void 317 printsub(direction, pointer, length) 318 char direction; /* '<' or '>' */ 319 unsigned char *pointer; /* where suboption data sits */ 320 int length; /* length of suboption data */ 321 { 322 register int i; 323 char buf[512]; 324 extern int want_status_response; 325 326 if (showoptions || direction == 0 || 327 (want_status_response && (pointer[0] == TELOPT_STATUS))) { 328 if (direction) { 329 (void) fprintf(NetTrace, "%s IAC SB ", 330 (direction == '<')? "RCVD":"SENT"); 331 if (length >= 3) { 332 register int j; 333 334 i = pointer[length-2]; 335 j = pointer[length-1]; 336 337 if (i != IAC || j != SE) { 338 (void) fprintf(NetTrace, 339 "(terminated by "); 340 if (TELOPT_OK(i)) 341 (void) fprintf(NetTrace, "%s ", 342 TELOPT(i)); 343 else if (TELCMD_OK(i)) 344 (void) fprintf(NetTrace, "%s ", 345 TELCMD(i)); 346 else 347 (void) fprintf(NetTrace, "%d ", 348 i); 349 if (TELOPT_OK(j)) 350 (void) fprintf(NetTrace, "%s", 351 TELOPT(j)); 352 else if (TELCMD_OK(j)) 353 (void) fprintf(NetTrace, "%s", 354 TELCMD(j)); 355 else 356 (void) fprintf(NetTrace, "%d", 357 j); 358 (void) fprintf(NetTrace, 359 ", not IAC SE!) "); 360 } 361 } 362 length -= 2; 363 } 364 if (length < 1) { 365 (void) fprintf(NetTrace, "(Empty suboption??\?)"); 366 if (NetTrace == stdout) 367 (void) fflush(NetTrace); 368 return; 369 } 370 switch (pointer[0]) { 371 case TELOPT_TTYPE: 372 (void) fprintf(NetTrace, "TERMINAL-TYPE "); 373 switch (pointer[1]) { 374 case TELQUAL_IS: 375 (void) fprintf(NetTrace, "IS \"%.*s\"", 376 length-2, 377 (char *)pointer+2); 378 break; 379 case TELQUAL_SEND: 380 (void) fprintf(NetTrace, "SEND"); 381 break; 382 default: 383 (void) fprintf(NetTrace, 384 "- unknown qualifier %d (0x%x).", 385 pointer[1], pointer[1]); 386 } 387 break; 388 case TELOPT_TSPEED: 389 (void) fprintf(NetTrace, "TERMINAL-SPEED"); 390 if (length < 2) { 391 (void) fprintf(NetTrace, 392 " (empty suboption??\?)"); 393 break; 394 } 395 switch (pointer[1]) { 396 case TELQUAL_IS: 397 (void) fprintf(NetTrace, " IS "); 398 (void) fprintf(NetTrace, "%.*s", length-2, 399 (char *)pointer+2); 400 break; 401 default: 402 if (pointer[1] == 1) 403 (void) fprintf(NetTrace, " SEND"); 404 else 405 (void) fprintf(NetTrace, 406 " %d (unknown)", pointer[1]); 407 for (i = 2; i < length; i++) 408 (void) fprintf(NetTrace, " ?%d?", 409 pointer[i]); 410 break; 411 } 412 break; 413 414 case TELOPT_LFLOW: 415 (void) fprintf(NetTrace, "TOGGLE-FLOW-CONTROL"); 416 if (length < 2) { 417 (void) fprintf(NetTrace, 418 " (empty suboption??\?)"); 419 break; 420 } 421 switch (pointer[1]) { 422 case LFLOW_OFF: 423 (void) fprintf(NetTrace, " OFF"); 424 break; 425 case LFLOW_ON: 426 (void) fprintf(NetTrace, " ON"); 427 break; 428 case LFLOW_RESTART_ANY: 429 (void) fprintf(NetTrace, " RESTART-ANY"); 430 break; 431 case LFLOW_RESTART_XON: 432 (void) fprintf(NetTrace, " RESTART-XON"); 433 break; 434 default: 435 (void) fprintf(NetTrace, " %d (unknown)", 436 pointer[1]); 437 } 438 for (i = 2; i < length; i++) 439 (void) fprintf(NetTrace, " ?%d?", 440 pointer[i]); 441 break; 442 443 case TELOPT_NAWS: 444 (void) fprintf(NetTrace, "NAWS"); 445 if (length < 2) { 446 (void) fprintf(NetTrace, 447 " (empty suboption??\?)"); 448 break; 449 } 450 if (length == 2) { 451 (void) fprintf(NetTrace, " ?%d?", pointer[1]); 452 break; 453 } 454 (void) fprintf(NetTrace, " %d %d (%d)", 455 pointer[1], pointer[2], 456 (int)((((unsigned int)pointer[1])<<8)| 457 ((unsigned int)pointer[2]))); 458 if (length == 4) { 459 (void) fprintf(NetTrace, " ?%d?", pointer[3]); 460 break; 461 } 462 (void) fprintf(NetTrace, " %d %d (%d)", 463 pointer[3], pointer[4], 464 (int)((((unsigned int)pointer[3])<<8)| 465 ((unsigned int)pointer[4]))); 466 for (i = 5; i < length; i++) 467 (void) fprintf(NetTrace, " ?%d?", pointer[i]); 468 break; 469 470 case TELOPT_AUTHENTICATION: 471 (void) fprintf(NetTrace, "AUTHENTICATION"); 472 if (length < 2) { 473 (void) fprintf(NetTrace, 474 " (empty suboption??\?)"); 475 break; 476 } 477 switch (pointer[1]) { 478 case TELQUAL_REPLY: 479 case TELQUAL_IS: 480 (void) fprintf(NetTrace, " %s ", 481 (pointer[1] == TELQUAL_IS) ? 482 "IS" : "REPLY"); 483 if (AUTHTYPE_NAME_OK(pointer[2])) 484 (void) fprintf(NetTrace, "%s ", 485 AUTHTYPE_NAME(pointer[2])); 486 else 487 (void) fprintf(NetTrace, "%d ", 488 pointer[2]); 489 if (length < 3) { 490 (void) fprintf(NetTrace, 491 "(partial suboption??\?)"); 492 break; 493 } 494 (void) fprintf(NetTrace, "%s|%s", 495 ((pointer[3] & AUTH_WHO_MASK) == 496 AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER", 497 ((pointer[3] & AUTH_HOW_MASK) == 498 AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY"); 499 500 auth_printsub(&pointer[1], length - 1, 501 (uchar_t *)buf, sizeof (buf)); 502 (void) fprintf(NetTrace, "%s", buf); 503 break; 504 505 case TELQUAL_SEND: 506 i = 2; 507 (void) fprintf(NetTrace, " SEND "); 508 while (i < length) { 509 if (AUTHTYPE_NAME_OK(pointer[i])) 510 (void) fprintf(NetTrace, "%s ", 511 AUTHTYPE_NAME(pointer[i])); 512 else 513 (void) fprintf(NetTrace, "%d ", 514 pointer[i]); 515 if (++i >= length) { 516 (void) fprintf(NetTrace, 517 "(partial " 518 "suboption??\?)"); 519 break; 520 } 521 (void) fprintf(NetTrace, "%s|%s ", 522 ((pointer[i] & AUTH_WHO_MASK) == 523 AUTH_WHO_CLIENT) ? 524 "CLIENT" : "SERVER", 525 ((pointer[i] & AUTH_HOW_MASK) == 526 AUTH_HOW_MUTUAL) ? 527 "MUTUAL" : "ONE-WAY"); 528 ++i; 529 } 530 break; 531 532 case TELQUAL_NAME: 533 i = 2; 534 (void) fprintf(NetTrace, " NAME \""); 535 while (i < length) 536 (void) putc(pointer[i++], NetTrace); 537 (void) putc('"', NetTrace); 538 break; 539 540 default: 541 for (i = 2; i < length; i++) 542 (void) fprintf(NetTrace, " ?%d?", pointer[i]); 543 break; 544 } 545 break; 546 547 case TELOPT_ENCRYPT: 548 (void) fprintf(NetTrace, "ENCRYPT"); 549 if (length < 2) { 550 (void) fprintf(NetTrace, 551 " (empty suboption??\?)"); 552 break; 553 } 554 switch (pointer[1]) { 555 case ENCRYPT_START: 556 (void) fprintf(NetTrace, " START"); 557 break; 558 559 case ENCRYPT_END: 560 (void) fprintf(NetTrace, " END"); 561 break; 562 563 case ENCRYPT_REQSTART: 564 (void) fprintf(NetTrace, " REQUEST-START"); 565 break; 566 567 case ENCRYPT_REQEND: 568 (void) fprintf(NetTrace, " REQUEST-END"); 569 break; 570 571 case ENCRYPT_IS: 572 case ENCRYPT_REPLY: 573 (void) fprintf(NetTrace, " %s ", 574 (pointer[1] == ENCRYPT_IS) ? 575 "IS" : "REPLY"); 576 if (length < 3) { 577 (void) fprintf(NetTrace, " (partial " 578 "suboption??\?)"); 579 break; 580 } 581 if (ENCTYPE_NAME_OK(pointer[2])) 582 (void) fprintf(NetTrace, "%s ", 583 ENCTYPE_NAME(pointer[2])); 584 else 585 (void) fprintf(NetTrace, 586 " %d (unknown)", pointer[2]); 587 588 encrypt_printsub(&pointer[1], length - 1, 589 (uchar_t *)buf, sizeof (buf)); 590 (void) fprintf(NetTrace, "%s", buf); 591 break; 592 593 case ENCRYPT_SUPPORT: 594 i = 2; 595 (void) fprintf(NetTrace, " SUPPORT "); 596 while (i < length) { 597 if (ENCTYPE_NAME_OK(pointer[i])) 598 (void) fprintf(NetTrace, "%s ", 599 ENCTYPE_NAME(pointer[i])); 600 else 601 (void) fprintf(NetTrace, "%d ", 602 pointer[i]); 603 i++; 604 } 605 break; 606 607 case ENCRYPT_ENC_KEYID: 608 (void) fprintf(NetTrace, " ENC_KEYID "); 609 goto encommon; 610 611 case ENCRYPT_DEC_KEYID: 612 (void) fprintf(NetTrace, " DEC_KEYID "); 613 goto encommon; 614 615 default: 616 (void) fprintf(NetTrace, " %d (unknown)", 617 pointer[1]); 618 encommon: 619 for (i = 2; i < length; i++) 620 (void) fprintf(NetTrace, " %d", 621 pointer[i]); 622 break; 623 } 624 break; 625 626 case TELOPT_LINEMODE: 627 (void) fprintf(NetTrace, "LINEMODE "); 628 if (length < 2) { 629 (void) fprintf(NetTrace, 630 " (empty suboption??\?)"); 631 break; 632 } 633 switch (pointer[1]) { 634 case WILL: 635 (void) fprintf(NetTrace, "WILL "); 636 goto common; 637 case WONT: 638 (void) fprintf(NetTrace, "WONT "); 639 goto common; 640 case DO: 641 (void) fprintf(NetTrace, "DO "); 642 goto common; 643 case DONT: 644 (void) fprintf(NetTrace, "DONT "); 645 common: 646 if (length < 3) { 647 (void) fprintf(NetTrace, 648 "(no option??\?)"); 649 break; 650 } 651 switch (pointer[2]) { 652 case LM_FORWARDMASK: 653 (void) fprintf(NetTrace, 654 "Forward Mask"); 655 for (i = 3; i < length; i++) 656 (void) fprintf(NetTrace, " %x", 657 pointer[i]); 658 break; 659 default: 660 (void) fprintf(NetTrace, "%d (unknown)", 661 pointer[2]); 662 for (i = 3; i < length; i++) 663 (void) fprintf(NetTrace, 664 " %d", pointer[i]); 665 break; 666 } 667 break; 668 669 case LM_SLC: 670 (void) fprintf(NetTrace, "SLC"); 671 for (i = 2; i < length - 2; i += 3) { 672 if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 673 (void) fprintf(NetTrace, " %s", 674 SLC_NAME(pointer[ 675 i+SLC_FUNC])); 676 else 677 (void) fprintf(NetTrace, " %d", 678 pointer[i+SLC_FUNC]); 679 switch (pointer[i+SLC_FLAGS] & 680 SLC_LEVELBITS) { 681 case SLC_NOSUPPORT: 682 (void) fprintf(NetTrace, 683 " NOSUPPORT"); 684 break; 685 case SLC_CANTCHANGE: 686 (void) fprintf(NetTrace, 687 " CANTCHANGE"); 688 break; 689 case SLC_VARIABLE: 690 (void) fprintf(NetTrace, 691 " VARIABLE"); 692 break; 693 case SLC_DEFAULT: 694 (void) fprintf(NetTrace, 695 " DEFAULT"); 696 break; 697 } 698 (void) fprintf(NetTrace, "%s%s%s", 699 pointer[i+SLC_FLAGS]&SLC_ACK ? 700 "|ACK" : "", 701 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? 702 "|FLUSHIN" : "", 703 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? 704 "|FLUSHOUT" : ""); 705 if (pointer[i+SLC_FLAGS] & 706 ~(SLC_ACK|SLC_FLUSHIN| 707 SLC_FLUSHOUT| SLC_LEVELBITS)) 708 (void) fprintf(NetTrace, "(0x%x)", 709 pointer[i+SLC_FLAGS]); 710 (void) fprintf(NetTrace, " %d;", 711 pointer[i+SLC_VALUE]); 712 if ((pointer[i+SLC_VALUE] == IAC) && 713 (pointer[i+SLC_VALUE+1] == IAC)) 714 i++; 715 } 716 for (; i < length; i++) 717 (void) fprintf(NetTrace, " ?%d?", 718 pointer[i]); 719 break; 720 721 case LM_MODE: 722 (void) fprintf(NetTrace, "MODE "); 723 if (length < 3) { 724 (void) fprintf(NetTrace, 725 "(no mode??\?)"); 726 break; 727 } 728 { 729 char tbuf[64]; 730 (void) sprintf(tbuf, "%s%s%s%s%s", 731 pointer[2]&MODE_EDIT ? "|EDIT" : "", 732 pointer[2]&MODE_TRAPSIG ? 733 "|TRAPSIG" : "", 734 pointer[2]&MODE_SOFT_TAB ? 735 "|SOFT_TAB" : "", 736 pointer[2]&MODE_LIT_ECHO ? 737 "|LIT_ECHO" : "", 738 pointer[2]&MODE_ACK ? "|ACK" : ""); 739 (void) fprintf(NetTrace, "%s", tbuf[1] ? 740 &tbuf[1] : "0"); 741 } 742 if (pointer[2]&~(MODE_MASK)) 743 (void) fprintf(NetTrace, " (0x%x)", 744 pointer[2]); 745 for (i = 3; i < length; i++) 746 (void) fprintf(NetTrace, " ?0x%x?", 747 pointer[i]); 748 break; 749 default: 750 (void) fprintf(NetTrace, "%d (unknown)", 751 pointer[1]); 752 for (i = 2; i < length; i++) 753 (void) fprintf(NetTrace, " %d", 754 pointer[i]); 755 } 756 break; 757 758 case TELOPT_STATUS: { 759 register char *cp; 760 register int j, k; 761 762 (void) fprintf(NetTrace, "STATUS"); 763 764 switch (pointer[1]) { 765 default: 766 if (pointer[1] == TELQUAL_SEND) 767 (void) fprintf(NetTrace, 768 " SEND"); 769 else 770 (void) fprintf(NetTrace, 771 " %d (unknown)", 772 pointer[1]); 773 for (i = 2; i < length; i++) 774 (void) fprintf(NetTrace, " ?%d?", 775 pointer[i]); 776 break; 777 case TELQUAL_IS: 778 if (--want_status_response < 0) 779 want_status_response = 0; 780 if (NetTrace == stdout) 781 (void) fprintf(NetTrace, 782 " IS\r\n"); 783 else 784 (void) fprintf(NetTrace, 785 " IS\n"); 786 787 for (i = 2; i < length; i++) { 788 switch (pointer[i]) { 789 case DO: 790 cp = "DO"; 791 goto common2; 792 case DONT: 793 cp = "DONT"; 794 goto common2; 795 case WILL: 796 cp = "WILL"; 797 goto common2; 798 case WONT: 799 cp = "WONT"; 800 goto common2; 801 common2: 802 i++; 803 if (TELOPT_OK( 804 (int)pointer[i])) 805 (void) fprintf( 806 NetTrace, 807 " %s %s", 808 cp, 809 TELOPT( 810 pointer[ 811 i])); 812 else 813 (void) fprintf( 814 NetTrace, 815 " %s %d", 816 cp, 817 pointer[i]); 818 819 if (NetTrace == stdout) 820 (void) fprintf( 821 NetTrace, 822 "\r\n"); 823 else 824 (void) fprintf( 825 NetTrace, 826 "\n"); 827 break; 828 829 case SB: 830 (void) fprintf(NetTrace, 831 " SB "); 832 i++; 833 j = k = i; 834 while (j < length) { 835 if (pointer[j] == SE) { 836 if (j+1 == length) 837 break; 838 if (pointer[j+1] == SE) 839 j++; 840 else 841 break; 842 } 843 pointer[k++] = pointer[j++]; 844 } 845 printsub(0, 846 &pointer[i], k - i); 847 if (i < length) { 848 (void) fprintf(NetTrace, " SE"); 849 i = j; 850 } else 851 i = j - 1; 852 853 if (NetTrace == stdout) 854 (void) fprintf(NetTrace, "\r\n"); 855 else 856 (void) fprintf(NetTrace, "\n"); 857 858 break; 859 860 default: 861 (void) fprintf(NetTrace, 862 " %d", pointer[i]); 863 break; 864 } 865 } 866 break; 867 } 868 break; 869 } 870 871 case TELOPT_XDISPLOC: 872 (void) fprintf(NetTrace, "X-DISPLAY-LOCATION "); 873 switch (pointer[1]) { 874 case TELQUAL_IS: 875 (void) fprintf(NetTrace, "IS \"%.*s\"", 876 length-2, (char *)pointer+2); 877 break; 878 case TELQUAL_SEND: 879 (void) fprintf(NetTrace, "SEND"); 880 break; 881 default: 882 (void) fprintf(NetTrace, 883 "- unknown qualifier %d (0x%x).", 884 pointer[1], pointer[1]); 885 } 886 break; 887 888 case TELOPT_NEW_ENVIRON: 889 (void) fprintf(NetTrace, "NEW-ENVIRON "); 890 #ifdef OLD_ENVIRON 891 goto env_common1; 892 case TELOPT_OLD_ENVIRON: 893 (void) fprintf(NetTrace, "OLD-ENVIRON "); 894 env_common1: 895 #endif 896 switch (pointer[1]) { 897 case TELQUAL_IS: 898 (void) fprintf(NetTrace, "IS "); 899 goto env_common; 900 case TELQUAL_SEND: 901 (void) fprintf(NetTrace, "SEND "); 902 goto env_common; 903 case TELQUAL_INFO: 904 (void) fprintf(NetTrace, "INFO "); 905 env_common: 906 { 907 register int noquote = 2; 908 #if defined(ENV_HACK) && defined(OLD_ENVIRON) 909 extern int old_env_var, old_env_value; 910 #endif 911 for (i = 2; i < length; i++) { 912 switch (pointer[i]) { 913 case NEW_ENV_VALUE: 914 #ifdef OLD_ENVIRON 915 /* case NEW_ENV_OVAR: */ 916 if (pointer[0] == TELOPT_OLD_ENVIRON) { 917 #ifdef ENV_HACK 918 if (old_env_var == OLD_ENV_VALUE) 919 (void) fprintf(NetTrace, 920 "\" (VALUE) " + noquote); 921 else 922 #endif 923 (void) fprintf(NetTrace, 924 "\" VAR " + noquote); 925 } else 926 #endif /* OLD_ENVIRON */ 927 (void) fprintf(NetTrace, "\" VALUE " + noquote); 928 noquote = 2; 929 break; 930 931 case NEW_ENV_VAR: 932 #ifdef OLD_ENVIRON 933 /* case OLD_ENV_VALUE: */ 934 if (pointer[0] == TELOPT_OLD_ENVIRON) { 935 #ifdef ENV_HACK 936 if (old_env_value == OLD_ENV_VAR) 937 (void) fprintf(NetTrace, 938 "\" (VAR) " + noquote); 939 else 940 #endif 941 (void) fprintf(NetTrace, 942 "\" VALUE " + noquote); 943 } else 944 #endif /* OLD_ENVIRON */ 945 (void) fprintf(NetTrace, "\" VAR " + noquote); 946 noquote = 2; 947 break; 948 949 case ENV_ESC: 950 (void) fprintf(NetTrace, "\" ESC " + noquote); 951 noquote = 2; 952 break; 953 954 case ENV_USERVAR: 955 (void) fprintf(NetTrace, "\" USERVAR " + noquote); 956 noquote = 2; 957 break; 958 959 default: 960 def_case: 961 if (isprint(pointer[i]) && pointer[i] != '"') { 962 if (noquote) { 963 (void) putc('"', NetTrace); 964 noquote = 0; 965 } 966 (void) putc(pointer[i], NetTrace); 967 } else { 968 (void) fprintf(NetTrace, "\" %03o " + noquote, 969 pointer[i]); 970 noquote = 2; 971 } 972 break; 973 } 974 } 975 if (!noquote) 976 (void) putc('"', NetTrace); 977 break; 978 } 979 } 980 break; 981 982 default: 983 if (TELOPT_OK(pointer[0])) 984 (void) fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0])); 985 else 986 (void) fprintf(NetTrace, "%d (unknown)", pointer[0]); 987 for (i = 1; i < length; i++) 988 (void) fprintf(NetTrace, " %d", pointer[i]); 989 break; 990 } 991 if (direction) { 992 if (NetTrace == stdout) 993 (void) fprintf(NetTrace, "\r\n"); 994 else 995 (void) fprintf(NetTrace, "\n"); 996 } 997 if (NetTrace == stdout) 998 (void) fflush(NetTrace); 999 } 1000 } 1001 1002 /* 1003 * EmptyTerminal - called to make sure that the terminal buffer is empty. 1004 * Note that we consider the buffer to run all the 1005 * way to the kernel (thus the select). 1006 */ 1007 1008 static void 1009 EmptyTerminal() 1010 { 1011 fd_set o; 1012 1013 FD_ZERO(&o); 1014 1015 if (TTYBYTES() == 0) { 1016 FD_SET(tout, &o); 1017 /* wait for TTLOWAT */ 1018 (void) select(tout+1, NULL, &o, NULL, NULL); 1019 } else { 1020 while (TTYBYTES()) { 1021 if (ttyflush(0) == -2) { 1022 /* This will not return. */ 1023 fatal_tty_error("write"); 1024 } 1025 FD_SET(tout, &o); 1026 /* wait for TTLOWAT */ 1027 (void) select(tout+1, NULL, &o, NULL, NULL); 1028 } 1029 } 1030 } 1031 1032 static void 1033 SetForExit() 1034 { 1035 setconnmode(0); 1036 do { 1037 (void) telrcv(); /* Process any incoming data */ 1038 EmptyTerminal(); 1039 } while (ring_full_count(&netiring)); /* While there is any */ 1040 setcommandmode(); 1041 (void) fflush(stdout); 1042 (void) fflush(stderr); 1043 setconnmode(0); 1044 EmptyTerminal(); /* Flush the path to the tty */ 1045 setcommandmode(); 1046 } 1047 1048 void 1049 Exit(returnCode) 1050 int returnCode; 1051 { 1052 SetForExit(); 1053 exit(returnCode); 1054 } 1055 1056 void 1057 ExitString(string, returnCode) 1058 char *string; 1059 int returnCode; 1060 { 1061 SetForExit(); 1062 (void) fwrite(string, 1, strlen(string), stderr); 1063 exit(returnCode); 1064 } 1065 1066 #define BUFFER_CHUNK_SIZE 64 1067 1068 /* Round up to a multiple of BUFFER_CHUNK_SIZE */ 1069 #define ROUND_CHUNK_SIZE(s) ((((s) + BUFFER_CHUNK_SIZE - 1) / \ 1070 BUFFER_CHUNK_SIZE) * BUFFER_CHUNK_SIZE) 1071 1072 /* 1073 * Optionally allocate a buffer, and optionally read a string from a stream 1074 * into the buffer, starting at the given offset. If the buffer isn't 1075 * large enough for the given offset, or if buffer space is exhausted 1076 * when reading the string, the size of the buffer is increased. 1077 * 1078 * A buffer can be supplied when the function is called, passing the 1079 * buffer address via the first argument. The buffer size can be 1080 * passed as well, in the second argument. If the second argument is 1081 * NULL, the function makes no assumptions about the buffer size. 1082 * The address of the buffer is returned via the first argument, and the 1083 * buffer size via the second argument if this is not NULL. 1084 * These returned values may differ from the supplied values if the buffer 1085 * was reallocated. 1086 * 1087 * If no buffer is to be supplied, specify a buffer address of NULL, via 1088 * the first argument. 1089 * 1090 * If the pointer to the buffer address is NULL, the function just returns 1091 * NULL, and performs no other processing. 1092 * 1093 * If a NULL stream is passed, the function will just make sure the 1094 * supplied buffer is large enough to hold the supplied offset, 1095 * reallocating it if is too small or too large. 1096 * 1097 * The returned buffer will be a multiple of BUFFER_CHUNK_SIZE in size. 1098 * 1099 * The function stops reading from the stream when a newline is read, 1100 * end of file is reached, or an error occurs. The newline is not 1101 * returned in the buffer. The returned string will be NULL terminated. 1102 * 1103 * The function returns the address of the buffer if any characters 1104 * are read and no error occurred, otherwise it returns NULL. 1105 * 1106 * If the function returns NULL, a buffer may have been allocated. The 1107 * buffer address will be returned via the first argument, together with 1108 * the buffer size if the second argument is not NULL. 1109 * 1110 */ 1111 static char * 1112 GetStringAtOffset(bufp, cbufsiz, off, st) 1113 char **bufp; 1114 unsigned int *cbufsiz; 1115 unsigned int off; 1116 FILE *st; 1117 { 1118 unsigned int bufsiz; 1119 char *buf; 1120 char *nbuf; 1121 unsigned int idx = off; 1122 1123 if (bufp == NULL) 1124 return (NULL); 1125 1126 buf = *bufp; 1127 1128 bufsiz = ROUND_CHUNK_SIZE(off + 1); 1129 1130 if (buf == NULL || cbufsiz == NULL || *cbufsiz != bufsiz) { 1131 if ((nbuf = realloc(buf, bufsiz)) == NULL) 1132 return (NULL); 1133 1134 buf = nbuf; 1135 *bufp = buf; 1136 if (cbufsiz != NULL) 1137 *cbufsiz = bufsiz; 1138 } 1139 1140 1141 if (st == NULL) 1142 return (buf); 1143 1144 clearerr(st); 1145 for (;;) { 1146 int c = getc(st); 1147 1148 /* Expand the buffer as needed. */ 1149 if (idx == bufsiz) { 1150 bufsiz += BUFFER_CHUNK_SIZE; 1151 if ((nbuf = realloc(buf, bufsiz)) == NULL) { 1152 /* Discard everything we read. */ 1153 buf[off] = 0; 1154 buf = NULL; 1155 break; 1156 } 1157 buf = nbuf; 1158 *bufp = buf; 1159 if (cbufsiz != NULL) 1160 *cbufsiz = bufsiz; 1161 } 1162 1163 if (c == EOF || c == '\n') { 1164 buf[idx] = 0; 1165 if (ferror(st) != 0) { 1166 /* Retry if interrupted by a signal. */ 1167 if (errno == EINTR) { 1168 clearerr(st); 1169 continue; 1170 } 1171 buf = NULL; 1172 } else if (feof(st) != 0) { 1173 /* No characters transferred? */ 1174 if (off == idx) 1175 buf = NULL; 1176 } 1177 break; 1178 } 1179 buf[idx++] = c; 1180 } 1181 return (buf); 1182 } 1183 1184 /* 1185 * Read a string from the supplied stream. Stop reading when a newline 1186 * is read, end of file reached, or an error occurs. 1187 * 1188 * A buffer can be supplied by specifying the buffer address via the 1189 * first argument. The buffer size can be passed via the second argument. 1190 * If the second argument is NULL, the function makes no assumptions 1191 * about the buffer size. The buffer will be reallocated if it is too 1192 * small or too large for the returned string. 1193 * 1194 * If no buffer is to be supplied, specify a buffer address of NULL, 1195 * via the first argument. 1196 * 1197 * If the first argument is NULL, the function just returns NULL, and 1198 * performs no other processing. 1199 * 1200 * The function returns the address of the buffer if any characters are 1201 * read and no error occurred. 1202 * 1203 * If the function returns NULL, a buffer may have been allocated. The 1204 * buffer address and buffer size will be returned via the first argument, 1205 * and the buffer size via the second argument, if this isn't NULL. 1206 */ 1207 char * 1208 GetString(bufp, bufsiz, st) 1209 char **bufp; 1210 unsigned int *bufsiz; 1211 FILE *st; 1212 { 1213 return (GetStringAtOffset(bufp, bufsiz, 0, st)); 1214 } 1215 1216 /* 1217 * Allocate a buffer to hold a string of given length. 1218 * 1219 * An existing buffer can be reallocated by passing its address and via 1220 * the first argument. The buffer size can be passed via the second 1221 * argument. If the second argument is NULL, the function makes no 1222 * assumptions about the buffer size. 1223 * 1224 * If no existing buffer is to be supplied, pass a NULL buffer address via 1225 * the first argument. 1226 * 1227 * If the first argument is NULL, the function just returns NULL, 1228 * and performs no other processing. 1229 */ 1230 char * 1231 AllocStringBuffer(bufp, bufsiz, size) 1232 char **bufp; 1233 unsigned int *bufsiz; 1234 unsigned int size; 1235 { 1236 return (GetStringAtOffset(bufp, bufsiz, size, (FILE *)NULL)); 1237 } 1238 1239 /* 1240 * This function is similar to GetString(), except that the string read 1241 * from the stream is appended to the supplied string. 1242 */ 1243 char * 1244 GetAndAppendString(bufp, bufsiz, str, st) 1245 char **bufp; 1246 unsigned int *bufsiz; 1247 char *str; 1248 FILE *st; 1249 { 1250 unsigned int off = strlen(str); 1251 1252 if (GetStringAtOffset(bufp, bufsiz, off, st) == NULL) 1253 return (NULL); 1254 1255 return (memcpy(*bufp, str, off)); 1256 } 1257