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