1 /* $OpenBSD: utilities.c,v 1.22 2017/08/22 15:04:18 bluhm Exp $ */ 2 /* $NetBSD: utilities.c,v 1.5 1996/02/28 21:04:21 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 1988, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* these three defines affect the behavior of <arpa/telnet.h> */ 34 #define TELOPTS 35 #define TELCMDS 36 #define SLC_NAMES 37 38 #include "telnet_locl.h" 39 40 #include <arpa/telnet.h> 41 #include <ctype.h> 42 #include <limits.h> 43 #include <poll.h> 44 #include <stdlib.h> 45 #include <string.h> 46 47 static FILE *NetTrace = NULL; 48 int prettydump; 49 50 /* 51 * upcase() 52 * 53 * Upcase (in place) the argument. 54 */ 55 56 void 57 upcase(char *argument) 58 { 59 int c; 60 61 while ((c = *argument) != '\0') 62 *argument++ = toupper((unsigned char)c); 63 } 64 65 /* 66 * The following are routines used to print out debugging information. 67 */ 68 69 char NetTraceFile[PATH_MAX] = "(standard output)"; 70 71 void 72 SetNetTrace(const char *file) 73 { 74 if (NetTrace && NetTrace != stdout) 75 fclose(NetTrace); 76 if (file && (strcmp(file, "-") != 0)) { 77 NetTrace = fopen(file, "we"); 78 if (NetTrace) { 79 strlcpy(NetTraceFile, file, sizeof(NetTraceFile)); 80 return; 81 } 82 fprintf(stderr, "Cannot open %s.\n", file); 83 } 84 NetTrace = stdout; 85 strlcpy(NetTraceFile, "(standard output)", sizeof(NetTraceFile)); 86 } 87 88 void 89 Dump(char direction, unsigned char *buffer, int length) 90 { 91 # define BYTES_PER_LINE 32 92 # define min(x,y) ((x<y)? x:y) 93 unsigned char *pThis; 94 int offset; 95 96 offset = 0; 97 98 while (length) { 99 /* print one line */ 100 fprintf(NetTrace, "%c 0x%x\t", direction, offset); 101 pThis = buffer; 102 if (prettydump) { 103 buffer = buffer + min(length, BYTES_PER_LINE/2); 104 while (pThis < buffer) { 105 fprintf(NetTrace, "%c%.2x", 106 (((*pThis)&0xff) == 0xff) ? '*' : ' ', 107 (*pThis)&0xff); 108 pThis++; 109 } 110 length -= BYTES_PER_LINE/2; 111 offset += BYTES_PER_LINE/2; 112 } else { 113 buffer = buffer + min(length, BYTES_PER_LINE); 114 while (pThis < buffer) { 115 fprintf(NetTrace, "%.2x", (*pThis)&0xff); 116 pThis++; 117 } 118 length -= BYTES_PER_LINE; 119 offset += BYTES_PER_LINE; 120 } 121 if (NetTrace == stdout) { 122 fprintf(NetTrace, "\r\n"); 123 } else { 124 fprintf(NetTrace, "\n"); 125 } 126 if (length < 0) { 127 fflush(NetTrace); 128 return; 129 } 130 /* find next unique line */ 131 } 132 fflush(NetTrace); 133 } 134 135 void 136 printoption(char *direction, int cmd, int option) 137 { 138 if (!showoptions) 139 return; 140 if (cmd == IAC) { 141 if (TELCMD_OK(option)) 142 fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option)); 143 else 144 fprintf(NetTrace, "%s IAC %d", direction, option); 145 } else { 146 char *fmt; 147 fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" : 148 (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0; 149 if (fmt) { 150 fprintf(NetTrace, "%s %s ", direction, fmt); 151 if (TELOPT_OK(option)) 152 fprintf(NetTrace, "%s", TELOPT(option)); 153 else if (option == TELOPT_EXOPL) 154 fprintf(NetTrace, "EXOPL"); 155 else 156 fprintf(NetTrace, "%d", option); 157 } else 158 fprintf(NetTrace, "%s %d %d", direction, cmd, option); 159 } 160 if (NetTrace == stdout) { 161 fprintf(NetTrace, "\r\n"); 162 fflush(NetTrace); 163 } else { 164 fprintf(NetTrace, "\n"); 165 } 166 return; 167 } 168 169 void 170 optionstatus(void) 171 { 172 int i; 173 174 for (i = 0; i < 256; i++) { 175 if (do_dont_resp[i]) { 176 if (TELOPT_OK(i)) 177 printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]); 178 else if (TELCMD_OK(i)) 179 printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]); 180 else 181 printf("resp DO_DONT %d: %d\n", i, 182 do_dont_resp[i]); 183 if (my_want_state_is_do(i)) { 184 if (TELOPT_OK(i)) 185 printf("want DO %s\n", TELOPT(i)); 186 else if (TELCMD_OK(i)) 187 printf("want DO %s\n", TELCMD(i)); 188 else 189 printf("want DO %d\n", i); 190 } else { 191 if (TELOPT_OK(i)) 192 printf("want DONT %s\n", TELOPT(i)); 193 else if (TELCMD_OK(i)) 194 printf("want DONT %s\n", TELCMD(i)); 195 else 196 printf("want DONT %d\n", i); 197 } 198 } else { 199 if (my_state_is_do(i)) { 200 if (TELOPT_OK(i)) 201 printf(" DO %s\n", TELOPT(i)); 202 else if (TELCMD_OK(i)) 203 printf(" DO %s\n", TELCMD(i)); 204 else 205 printf(" DO %d\n", i); 206 } 207 } 208 if (will_wont_resp[i]) { 209 if (TELOPT_OK(i)) 210 printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]); 211 else if (TELCMD_OK(i)) 212 printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]); 213 else 214 printf("resp WILL_WONT %d: %d\n", 215 i, will_wont_resp[i]); 216 if (my_want_state_is_will(i)) { 217 if (TELOPT_OK(i)) 218 printf("want WILL %s\n", TELOPT(i)); 219 else if (TELCMD_OK(i)) 220 printf("want WILL %s\n", TELCMD(i)); 221 else 222 printf("want WILL %d\n", i); 223 } else { 224 if (TELOPT_OK(i)) 225 printf("want WONT %s\n", TELOPT(i)); 226 else if (TELCMD_OK(i)) 227 printf("want WONT %s\n", TELCMD(i)); 228 else 229 printf("want WONT %d\n", i); 230 } 231 } else { 232 if (my_state_is_will(i)) { 233 if (TELOPT_OK(i)) 234 printf(" WILL %s\n", TELOPT(i)); 235 else if (TELCMD_OK(i)) 236 printf(" WILL %s\n", TELCMD(i)); 237 else 238 printf(" WILL %d\n", i); 239 } 240 } 241 } 242 243 } 244 245 void 246 printsub(char direction, /* '<' or '>' */ 247 unsigned char *pointer, /* where suboption data sits */ 248 int length) /* length of suboption data */ 249 { 250 int i; 251 252 if (showoptions || direction == 0 || 253 (want_status_response && (pointer[0] == TELOPT_STATUS))) { 254 if (direction) { 255 fprintf(NetTrace, "%s IAC SB ", 256 (direction == '<')? "RCVD":"SENT"); 257 if (length >= 3) { 258 int j; 259 260 i = pointer[length-2]; 261 j = pointer[length-1]; 262 263 if (i != IAC || j != SE) { 264 fprintf(NetTrace, "(terminated by "); 265 if (TELOPT_OK(i)) 266 fprintf(NetTrace, "%s ", TELOPT(i)); 267 else if (TELCMD_OK(i)) 268 fprintf(NetTrace, "%s ", TELCMD(i)); 269 else 270 fprintf(NetTrace, "%d ", i); 271 if (TELOPT_OK(j)) 272 fprintf(NetTrace, "%s", TELOPT(j)); 273 else if (TELCMD_OK(j)) 274 fprintf(NetTrace, "%s", TELCMD(j)); 275 else 276 fprintf(NetTrace, "%d", j); 277 fprintf(NetTrace, ", not IAC SE!) "); 278 } 279 } 280 length -= 2; 281 } 282 if (length < 1) { 283 fprintf(NetTrace, "(Empty suboption??\?)"); 284 if (NetTrace == stdout) 285 fflush(NetTrace); 286 return; 287 } 288 switch (pointer[0]) { 289 case TELOPT_TTYPE: 290 fprintf(NetTrace, "TERMINAL-TYPE "); 291 switch (pointer[1]) { 292 case TELQUAL_IS: 293 fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); 294 break; 295 case TELQUAL_SEND: 296 fprintf(NetTrace, "SEND"); 297 break; 298 default: 299 fprintf(NetTrace, 300 "- unknown qualifier %d (0x%x).", 301 pointer[1], pointer[1]); 302 } 303 break; 304 case TELOPT_TSPEED: 305 fprintf(NetTrace, "TERMINAL-SPEED"); 306 if (length < 2) { 307 fprintf(NetTrace, " (empty suboption??\?)"); 308 break; 309 } 310 switch (pointer[1]) { 311 case TELQUAL_IS: 312 fprintf(NetTrace, " IS "); 313 fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2); 314 break; 315 default: 316 if (pointer[1] == 1) 317 fprintf(NetTrace, " SEND"); 318 else 319 fprintf(NetTrace, " %d (unknown)", pointer[1]); 320 for (i = 2; i < length; i++) 321 fprintf(NetTrace, " ?%d?", pointer[i]); 322 break; 323 } 324 break; 325 326 case TELOPT_LFLOW: 327 fprintf(NetTrace, "TOGGLE-FLOW-CONTROL"); 328 if (length < 2) { 329 fprintf(NetTrace, " (empty suboption??\?)"); 330 break; 331 } 332 switch (pointer[1]) { 333 case LFLOW_OFF: 334 fprintf(NetTrace, " OFF"); break; 335 case LFLOW_ON: 336 fprintf(NetTrace, " ON"); break; 337 case LFLOW_RESTART_ANY: 338 fprintf(NetTrace, " RESTART-ANY"); break; 339 case LFLOW_RESTART_XON: 340 fprintf(NetTrace, " RESTART-XON"); break; 341 default: 342 fprintf(NetTrace, " %d (unknown)", pointer[1]); 343 } 344 for (i = 2; i < length; i++) 345 fprintf(NetTrace, " ?%d?", pointer[i]); 346 break; 347 348 case TELOPT_NAWS: 349 fprintf(NetTrace, "NAWS"); 350 if (length < 2) { 351 fprintf(NetTrace, " (empty suboption??\?)"); 352 break; 353 } 354 if (length == 2) { 355 fprintf(NetTrace, " ?%d?", pointer[1]); 356 break; 357 } 358 fprintf(NetTrace, " %d %d (%d)", 359 pointer[1], pointer[2], (pointer[1]<<8) | pointer[2]); 360 if (length == 4) { 361 fprintf(NetTrace, " ?%d?", pointer[3]); 362 break; 363 } 364 fprintf(NetTrace, " %d %d (%d)", 365 pointer[3], pointer[4], (pointer[3]<<8) | pointer[4]); 366 for (i = 5; i < length; i++) 367 fprintf(NetTrace, " ?%d?", pointer[i]); 368 break; 369 370 case TELOPT_LINEMODE: 371 fprintf(NetTrace, "LINEMODE "); 372 if (length < 2) { 373 fprintf(NetTrace, " (empty suboption??\?)"); 374 break; 375 } 376 switch (pointer[1]) { 377 case WILL: 378 fprintf(NetTrace, "WILL "); 379 goto common; 380 case WONT: 381 fprintf(NetTrace, "WONT "); 382 goto common; 383 case DO: 384 fprintf(NetTrace, "DO "); 385 goto common; 386 case DONT: 387 fprintf(NetTrace, "DONT "); 388 common: 389 if (length < 3) { 390 fprintf(NetTrace, "(no option??\?)"); 391 break; 392 } 393 switch (pointer[2]) { 394 case LM_FORWARDMASK: 395 fprintf(NetTrace, "Forward Mask"); 396 for (i = 3; i < length; i++) 397 fprintf(NetTrace, " %x", pointer[i]); 398 break; 399 default: 400 fprintf(NetTrace, "%d (unknown)", pointer[2]); 401 for (i = 3; i < length; i++) 402 fprintf(NetTrace, " %d", pointer[i]); 403 break; 404 } 405 break; 406 407 case LM_SLC: 408 fprintf(NetTrace, "SLC"); 409 for (i = 2; i < length - 2; i += 3) { 410 if (SLC_NAME_OK(pointer[i+SLC_FUNC])) 411 fprintf(NetTrace, " %s", SLC_NAME(pointer[i+SLC_FUNC])); 412 else 413 fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]); 414 switch (pointer[i+SLC_FLAGS]&SLC_LEVELBITS) { 415 case SLC_NOSUPPORT: 416 fprintf(NetTrace, " NOSUPPORT"); break; 417 case SLC_CANTCHANGE: 418 fprintf(NetTrace, " CANTCHANGE"); break; 419 case SLC_VARIABLE: 420 fprintf(NetTrace, " VARIABLE"); break; 421 case SLC_DEFAULT: 422 fprintf(NetTrace, " DEFAULT"); break; 423 } 424 fprintf(NetTrace, "%s%s%s", 425 pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", 426 pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", 427 pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); 428 if (pointer[i+SLC_FLAGS]& ~(SLC_ACK|SLC_FLUSHIN| 429 SLC_FLUSHOUT| SLC_LEVELBITS)) 430 fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]); 431 fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]); 432 if ((pointer[i+SLC_VALUE] == IAC) && 433 (pointer[i+SLC_VALUE+1] == IAC)) 434 i++; 435 } 436 for (; i < length; i++) 437 fprintf(NetTrace, " ?%d?", pointer[i]); 438 break; 439 440 case LM_MODE: 441 fprintf(NetTrace, "MODE "); 442 if (length < 3) { 443 fprintf(NetTrace, "(no mode??\?)"); 444 break; 445 } 446 { 447 char tbuf[64]; 448 snprintf(tbuf, sizeof(tbuf), 449 "%s%s%s%s%s", 450 pointer[2]&MODE_EDIT ? "|EDIT" : "", 451 pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", 452 pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", 453 pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", 454 pointer[2]&MODE_ACK ? "|ACK" : ""); 455 fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0"); 456 } 457 if (pointer[2]&~(MODE_MASK)) 458 fprintf(NetTrace, " (0x%x)", pointer[2]); 459 for (i = 3; i < length; i++) 460 fprintf(NetTrace, " ?0x%x?", pointer[i]); 461 break; 462 default: 463 fprintf(NetTrace, "%d (unknown)", pointer[1]); 464 for (i = 2; i < length; i++) 465 fprintf(NetTrace, " %d", pointer[i]); 466 } 467 break; 468 469 case TELOPT_STATUS: { 470 char *cp; 471 int j, k; 472 473 fprintf(NetTrace, "STATUS"); 474 475 switch (pointer[1]) { 476 default: 477 if (pointer[1] == TELQUAL_SEND) 478 fprintf(NetTrace, " SEND"); 479 else 480 fprintf(NetTrace, " %d (unknown)", pointer[1]); 481 for (i = 2; i < length; i++) 482 fprintf(NetTrace, " ?%d?", pointer[i]); 483 break; 484 case TELQUAL_IS: 485 if (--want_status_response < 0) 486 want_status_response = 0; 487 if (NetTrace == stdout) 488 fprintf(NetTrace, " IS\r\n"); 489 else 490 fprintf(NetTrace, " IS\n"); 491 492 for (i = 2; i < length; i++) { 493 switch(pointer[i]) { 494 case DO: cp = "DO"; goto common2; 495 case DONT: cp = "DONT"; goto common2; 496 case WILL: cp = "WILL"; goto common2; 497 case WONT: cp = "WONT"; goto common2; 498 common2: 499 i++; 500 if (TELOPT_OK(pointer[i])) 501 fprintf(NetTrace, " %s %s", cp, TELOPT(pointer[i])); 502 else 503 fprintf(NetTrace, " %s %d", cp, pointer[i]); 504 505 if (NetTrace == stdout) 506 fprintf(NetTrace, "\r\n"); 507 else 508 fprintf(NetTrace, "\n"); 509 break; 510 511 case SB: 512 fprintf(NetTrace, " SB "); 513 i++; 514 j = k = i; 515 while (j < length) { 516 if (pointer[j] == SE) { 517 if (j+1 == length) 518 break; 519 if (pointer[j+1] == SE) 520 j++; 521 else 522 break; 523 } 524 pointer[k++] = pointer[j++]; 525 } 526 printsub(0, &pointer[i], k - i); 527 if (i < length) { 528 fprintf(NetTrace, " SE"); 529 i = j; 530 } else 531 i = j - 1; 532 533 if (NetTrace == stdout) 534 fprintf(NetTrace, "\r\n"); 535 else 536 fprintf(NetTrace, "\n"); 537 538 break; 539 540 default: 541 fprintf(NetTrace, " %d", pointer[i]); 542 break; 543 } 544 } 545 break; 546 } 547 break; 548 } 549 550 case TELOPT_XDISPLOC: 551 fprintf(NetTrace, "X-DISPLAY-LOCATION "); 552 switch (pointer[1]) { 553 case TELQUAL_IS: 554 fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); 555 break; 556 case TELQUAL_SEND: 557 fprintf(NetTrace, "SEND"); 558 break; 559 default: 560 fprintf(NetTrace, "- unknown qualifier %d (0x%x).", 561 pointer[1], pointer[1]); 562 } 563 break; 564 565 case TELOPT_NEW_ENVIRON: 566 fprintf(NetTrace, "NEW-ENVIRON "); 567 switch (pointer[1]) { 568 case TELQUAL_IS: 569 fprintf(NetTrace, "IS "); 570 goto env_common; 571 case TELQUAL_SEND: 572 fprintf(NetTrace, "SEND "); 573 goto env_common; 574 case TELQUAL_INFO: 575 fprintf(NetTrace, "INFO "); 576 env_common: 577 { 578 int quote = 0; 579 for (i = 2; i < length; i++ ) { 580 switch (pointer[i]) { 581 case NEW_ENV_VALUE: 582 fprintf(NetTrace, "%sVALUE ", quote ? "\" " : ""); 583 quote = 0; 584 break; 585 586 case NEW_ENV_VAR: 587 fprintf(NetTrace, "%sVAR ", quote ? "\" " : ""); 588 quote = 0; 589 break; 590 591 case ENV_ESC: 592 fprintf(NetTrace, "%sESC ", quote ? "\" " : ""); 593 quote = 0; 594 break; 595 596 case ENV_USERVAR: 597 fprintf(NetTrace, "%sUSERVAR ", quote ? "\" " : ""); 598 quote = 0; 599 break; 600 601 default: 602 if (isprint((unsigned char)pointer[i]) && 603 pointer[i] != '"') { 604 fprintf(NetTrace, "%s%c", 605 quote ? "" : "\"", pointer[i]); 606 quote = 1; 607 } else { 608 fprintf(NetTrace, "%s%03o ", 609 quote ? "\" " : "", pointer[i]); 610 quote = 0; 611 } 612 break; 613 } 614 } 615 if (quote) 616 putc('"', NetTrace); 617 break; 618 } 619 } 620 break; 621 622 default: 623 if (TELOPT_OK(pointer[0])) 624 fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0])); 625 else 626 fprintf(NetTrace, "%d (unknown)", pointer[0]); 627 for (i = 1; i < length; i++) 628 fprintf(NetTrace, " %d", pointer[i]); 629 break; 630 } 631 if (direction) { 632 if (NetTrace == stdout) 633 fprintf(NetTrace, "\r\n"); 634 else 635 fprintf(NetTrace, "\n"); 636 } 637 if (NetTrace == stdout) 638 fflush(NetTrace); 639 } 640 } 641 642 /* EmptyTerminal - called to make sure that the terminal buffer is empty. 643 * Note that we consider the buffer to run all the 644 * way to the kernel (thus the poll). 645 */ 646 647 void 648 EmptyTerminal(void) 649 { 650 struct pollfd pfd[1]; 651 652 pfd[0].fd = tout; 653 pfd[0].events = POLLOUT; 654 655 if (TTYBYTES() == 0) { 656 (void) poll(pfd, 1, INFTIM); /* wait for TTLOWAT */ 657 } else { 658 while (TTYBYTES()) { 659 (void) ttyflush(0); 660 (void) poll(pfd, 1, INFTIM); /* wait for TTLOWAT */ 661 } 662 } 663 } 664 665 void 666 SetForExit(void) 667 { 668 setconnmode(0); 669 do { 670 (void)telrcv(); /* Process any incoming data */ 671 EmptyTerminal(); 672 } while (ring_full_count(&netiring)); /* While there is any */ 673 setcommandmode(); 674 fflush(stdout); 675 fflush(stderr); 676 setconnmode(0); 677 EmptyTerminal(); /* Flush the path to the tty */ 678 setcommandmode(); 679 } 680 681 void 682 Exit(int returnCode) 683 { 684 SetForExit(); 685 exit(returnCode); 686 } 687 688 void 689 ExitString(char *string, int returnCode) 690 { 691 SetForExit(); 692 fwrite(string, 1, strlen(string), stderr); 693 exit(returnCode); 694 } 695