1 /* $OpenBSD: commands.c,v 1.89 2024/08/26 21:34:32 op Exp $ */ 2 /* $NetBSD: commands.c,v 1.14 1996/03/24 22:03:48 jtk Exp $ */ 3 4 /* 5 * Copyright (c) 1988, 1990, 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 #include "telnet_locl.h" 34 35 #include <sys/socket.h> 36 #include <netinet/in.h> 37 #include <netinet/ip.h> 38 #include <arpa/inet.h> 39 #include <arpa/telnet.h> 40 41 #include <ctype.h> 42 #include <err.h> 43 #include <errno.h> 44 #include <netdb.h> 45 #include <pwd.h> 46 #include <stdarg.h> 47 #include <stdlib.h> 48 #include <string.h> 49 #include <unistd.h> 50 #include <limits.h> 51 52 char *hostname; 53 54 typedef struct { 55 char *name; /* command name */ 56 char *help; /* help string (NULL for no help) */ 57 int (*handler)(int, char **);/* routine which executes command */ 58 int needconnect; /* Do we need to be connected to execute? */ 59 } Command; 60 61 #define MAXARGV 20 62 63 static char line[256]; 64 static int margc; 65 static char *margv[MAXARGV+1]; 66 67 static int 68 makeargv(void) 69 { 70 char *cp, *cp2, c; 71 char **argp = margv; 72 int ret = 0; 73 74 margc = 0; 75 cp = line; 76 while ((c = *cp)) { 77 if (margc >= MAXARGV) { 78 printf("too many arguments\n"); 79 ret = 1; 80 break; 81 } 82 int inquote = 0; 83 while (isspace((unsigned char)c)) 84 c = *++cp; 85 if (c == '\0') 86 break; 87 *argp++ = cp; 88 margc += 1; 89 for (cp2 = cp; c != '\0'; c = *++cp) { 90 if (inquote) { 91 if (c == inquote) { 92 inquote = 0; 93 continue; 94 } 95 } else { 96 if (c == '\\') { 97 if ((c = *++cp) == '\0') 98 break; 99 } else if (c == '"') { 100 inquote = '"'; 101 continue; 102 } else if (c == '\'') { 103 inquote = '\''; 104 continue; 105 } else if (isspace((unsigned char)c)) 106 break; 107 } 108 *cp2++ = c; 109 } 110 *cp2 = '\0'; 111 if (c == '\0') 112 break; 113 cp++; 114 } 115 *argp++ = 0; 116 return (ret); 117 } 118 119 /* 120 * Make a character string into a number. 121 * 122 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 123 */ 124 125 static char 126 special(char *s) 127 { 128 char c; 129 char b; 130 131 switch (*s) { 132 case '^': 133 b = *++s; 134 if (b == '?') { 135 c = b | 0x40; /* DEL */ 136 } else { 137 c = b & 0x1f; 138 } 139 break; 140 default: 141 c = *s; 142 break; 143 } 144 return c; 145 } 146 147 /* 148 * Construct a control character sequence 149 * for a special character. 150 */ 151 static char * 152 control(cc_t c) 153 { 154 static char buf[5]; 155 /* 156 * The only way I could get the Sun 3.5 compiler 157 * to shut up about 158 * if ((unsigned int)c >= 0x80) 159 * was to assign "c" to an unsigned int variable... 160 * Arggg.... 161 */ 162 unsigned int uic = (unsigned int)c; 163 164 if (uic == 0x7f) 165 return ("^?"); 166 if (c == (cc_t)_POSIX_VDISABLE) { 167 return "off"; 168 } 169 if (uic >= 0x80) { 170 buf[0] = '\\'; 171 buf[1] = ((c>>6)&07) + '0'; 172 buf[2] = ((c>>3)&07) + '0'; 173 buf[3] = (c&07) + '0'; 174 buf[4] = 0; 175 } else if (uic >= 0x20) { 176 buf[0] = c; 177 buf[1] = 0; 178 } else { 179 buf[0] = '^'; 180 buf[1] = '@'+c; 181 buf[2] = 0; 182 } 183 return (buf); 184 } 185 186 /* 187 * The following are data structures and routines for 188 * the "send" command. 189 * 190 */ 191 192 struct sendlist { 193 char *name; /* How user refers to it (case independent) */ 194 char *help; /* Help information (0 ==> no help) */ 195 int needconnect; /* Need to be connected */ 196 int narg; /* Number of arguments */ 197 int (*handler)(); /* Routine to perform (for special ops) */ 198 int nbyte; /* Number of bytes to send this command */ 199 int what; /* Character to be sent (<0 ==> special) */ 200 }; 201 202 203 static int 204 send_esc(void), 205 send_help(void), 206 send_docmd(char *), 207 send_dontcmd(char *), 208 send_willcmd(char *), 209 send_wontcmd(char *); 210 211 static struct sendlist Sendlist[] = { 212 { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, 213 { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, 214 { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, 215 { "break", 0, 1, 0, 0, 2, BREAK }, 216 { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, 217 { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, 218 { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, 219 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, 220 { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, 221 { "intp", 0, 1, 0, 0, 2, IP }, 222 { "interrupt", 0, 1, 0, 0, 2, IP }, 223 { "intr", 0, 1, 0, 0, 2, IP }, 224 { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, 225 { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, 226 { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, 227 { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, 228 { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, 229 { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 }, 230 { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, 231 { "?", "Display send options", 0, 0, send_help, 0, 0 }, 232 { "help", 0, 0, 0, send_help, 0, 0 }, 233 { "do", 0, 0, 1, send_docmd, 3, 0 }, 234 { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, 235 { "will", 0, 0, 1, send_willcmd, 3, 0 }, 236 { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, 237 { 0 } 238 }; 239 240 #define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \ 241 sizeof(struct sendlist))) 242 243 static int 244 sendcmd(int argc, char **argv) 245 { 246 int count; /* how many bytes we are going to need to send */ 247 int i; 248 struct sendlist *s; /* pointer to current command */ 249 int success = 0; 250 int needconnect = 0; 251 252 if (argc < 2) { 253 printf("need at least one argument for 'send' command\r\n"); 254 printf("'send ?' for help\r\n"); 255 return 0; 256 } 257 /* 258 * First, validate all the send arguments. 259 * In addition, we see how much space we are going to need, and 260 * whether or not we will be doing a "SYNCH" operation (which 261 * flushes the network queue). 262 */ 263 count = 0; 264 for (i = 1; i < argc; i++) { 265 s = GETSEND(argv[i]); 266 if (s == 0) { 267 printf("Unknown send argument '%s'\r\n'send ?' for help.\r\n", 268 argv[i]); 269 return 0; 270 } else if (Ambiguous(s)) { 271 printf("Ambiguous send argument '%s'\r\n'send ?' for help.\r\n", 272 argv[i]); 273 return 0; 274 } 275 if (i + s->narg >= argc) { 276 fprintf(stderr, 277 "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\r\n", 278 s->narg, s->narg == 1 ? "" : "s", s->name, s->name); 279 return 0; 280 } 281 count += s->nbyte; 282 if (s->handler == send_help) { 283 send_help(); 284 return 0; 285 } 286 287 i += s->narg; 288 needconnect += s->needconnect; 289 } 290 if (!connected && needconnect) { 291 printf("?Need to be connected first.\r\n"); 292 printf("'send ?' for help\r\n"); 293 return 0; 294 } 295 /* Now, do we have enough room? */ 296 if (NETROOM() < count) { 297 printf("There is not enough room in the buffer TO the network\r\n"); 298 printf("to process your request. Nothing will be done.\r\n"); 299 printf("('send synch' will throw away most data in the network\r\n"); 300 printf("buffer, if this might help.)\r\n"); 301 return 0; 302 } 303 /* OK, they are all OK, now go through again and actually send */ 304 count = 0; 305 for (i = 1; i < argc; i++) { 306 if ((s = GETSEND(argv[i])) == 0) { 307 fprintf(stderr, "Telnet 'send' error - argument disappeared!\r\n"); 308 quit(); 309 } 310 if (s->handler) { 311 count++; 312 success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, 313 (s->narg > 1) ? argv[i+2] : 0); 314 i += s->narg; 315 } else { 316 NET2ADD(IAC, s->what); 317 printoption("SENT", IAC, s->what); 318 } 319 } 320 return (count == success); 321 } 322 323 static int send_tncmd(void (*func)(int, int), char *cmd, char *name); 324 325 static int 326 send_esc(void) 327 { 328 NETADD(escape); 329 return 1; 330 } 331 332 static int 333 send_docmd(char *name) 334 { 335 return(send_tncmd(send_do, "do", name)); 336 } 337 338 static int 339 send_dontcmd(char *name) 340 { 341 return(send_tncmd(send_dont, "dont", name)); 342 } 343 344 static int 345 send_willcmd(char *name) 346 { 347 return(send_tncmd(send_will, "will", name)); 348 } 349 350 static int 351 send_wontcmd(char *name) 352 { 353 return(send_tncmd(send_wont, "wont", name)); 354 } 355 356 int 357 send_tncmd(void (*func)(int, int), char *cmd, char *name) 358 { 359 char **cpp; 360 extern char *telopts[]; 361 const char *errstr; 362 int val = 0; 363 364 if (isprefix(name, "help") || isprefix(name, "?")) { 365 int col, len; 366 367 printf("Usage: send %s <value|option>\r\n", cmd); 368 printf("\"value\" must be from 0 to 255\r\n"); 369 printf("Valid options are:\r\n\t"); 370 371 col = 8; 372 for (cpp = telopts; *cpp; cpp++) { 373 len = strlen(*cpp) + 3; 374 if (col + len > 65) { 375 printf("\r\n\t"); 376 col = 8; 377 } 378 printf(" \"%s\"", *cpp); 379 col += len; 380 } 381 printf("\r\n"); 382 return 0; 383 } 384 cpp = (char **)genget(name, telopts, sizeof(char *)); 385 if (Ambiguous(cpp)) { 386 fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\r\n", 387 name, cmd); 388 return 0; 389 } 390 if (cpp) { 391 val = cpp - telopts; 392 } else { 393 val = strtonum(name, 0, 255, &errstr); 394 if (errstr) { 395 fprintf(stderr, "'%s': %s ('send %s ?' for help).\r\n", 396 name, errstr, cmd); 397 return 0; 398 } 399 } 400 if (!connected) { 401 printf("?Need to be connected first.\r\n"); 402 return 0; 403 } 404 (*func)(val, 1); 405 return 1; 406 } 407 408 static int 409 send_help(void) 410 { 411 struct sendlist *s; /* pointer to current command */ 412 for (s = Sendlist; s->name; s++) { 413 if (s->help) 414 printf("%-15s %s\r\n", s->name, s->help); 415 } 416 return(0); 417 } 418 419 /* 420 * The following are the routines and data structures referred 421 * to by the arguments to the "toggle" command. 422 */ 423 424 static int 425 lclchars(int unused) 426 { 427 donelclchars = 1; 428 return 1; 429 } 430 431 static int 432 togcrlf(int unused) 433 { 434 if (crlf) { 435 printf("Will send carriage returns as telnet <CR><LF>.\r\n"); 436 } else { 437 printf("Will send carriage returns as telnet <CR><NUL>.\r\n"); 438 } 439 return 1; 440 } 441 442 int binmode; 443 444 static int 445 togbinary(int val) 446 { 447 donebinarytoggle = 1; 448 449 if (val >= 0) { 450 binmode = val; 451 } else { 452 if (my_want_state_is_will(TELOPT_BINARY) && 453 my_want_state_is_do(TELOPT_BINARY)) { 454 binmode = 1; 455 } else if (my_want_state_is_wont(TELOPT_BINARY) && 456 my_want_state_is_dont(TELOPT_BINARY)) { 457 binmode = 0; 458 } 459 val = binmode ? 0 : 1; 460 } 461 462 if (val == 1) { 463 if (my_want_state_is_will(TELOPT_BINARY) && 464 my_want_state_is_do(TELOPT_BINARY)) { 465 printf("Already operating in binary mode with remote host.\r\n"); 466 } else { 467 printf("Negotiating binary mode with remote host.\r\n"); 468 tel_enter_binary(3); 469 } 470 } else { 471 if (my_want_state_is_wont(TELOPT_BINARY) && 472 my_want_state_is_dont(TELOPT_BINARY)) { 473 printf("Already in network ascii mode with remote host.\r\n"); 474 } else { 475 printf("Negotiating network ascii mode with remote host.\r\n"); 476 tel_leave_binary(3); 477 } 478 } 479 return 1; 480 } 481 482 static int 483 togrbinary(int val) 484 { 485 donebinarytoggle = 1; 486 487 if (val == -1) 488 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; 489 490 if (val == 1) { 491 if (my_want_state_is_do(TELOPT_BINARY)) { 492 printf("Already receiving in binary mode.\r\n"); 493 } else { 494 printf("Negotiating binary mode on input.\r\n"); 495 tel_enter_binary(1); 496 } 497 } else { 498 if (my_want_state_is_dont(TELOPT_BINARY)) { 499 printf("Already receiving in network ascii mode.\r\n"); 500 } else { 501 printf("Negotiating network ascii mode on input.\r\n"); 502 tel_leave_binary(1); 503 } 504 } 505 return 1; 506 } 507 508 static int 509 togxbinary(int val) 510 { 511 donebinarytoggle = 1; 512 513 if (val == -1) 514 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; 515 516 if (val == 1) { 517 if (my_want_state_is_will(TELOPT_BINARY)) { 518 printf("Already transmitting in binary mode.\r\n"); 519 } else { 520 printf("Negotiating binary mode on output.\r\n"); 521 tel_enter_binary(2); 522 } 523 } else { 524 if (my_want_state_is_wont(TELOPT_BINARY)) { 525 printf("Already transmitting in network ascii mode.\r\n"); 526 } else { 527 printf("Negotiating network ascii mode on output.\r\n"); 528 tel_leave_binary(2); 529 } 530 } 531 return 1; 532 } 533 534 535 static int togglehelp(int); 536 537 struct togglelist { 538 char *name; /* name of toggle */ 539 char *help; /* help message */ 540 int (*handler)(int); /* routine to do actual setting */ 541 int *variable; 542 char *actionexplanation; 543 int needconnect; /* Need to be connected */ 544 }; 545 546 static struct togglelist Togglelist[] = { 547 { "autoflush", 548 "flushing of output when sending interrupt characters", 549 0, 550 &autoflush, 551 "flush output when sending interrupt characters" }, 552 { "autosynch", 553 "automatic sending of interrupt characters in urgent mode", 554 0, 555 &autosynch, 556 "send interrupt characters in urgent mode" }, 557 { "autologin", 558 "automatic sending of login name", 559 0, 560 &autologin, 561 "send login name" }, 562 { "skiprc", 563 "don't read ~/.telnetrc file", 564 0, 565 &skiprc, 566 "skip reading of ~/.telnetrc file" }, 567 { "binary", 568 "sending and receiving of binary data", 569 togbinary, 570 0, 571 0 }, 572 { "inbinary", 573 "receiving of binary data", 574 togrbinary, 575 0, 576 0 }, 577 { "outbinary", 578 "sending of binary data", 579 togxbinary, 580 0, 581 0 }, 582 { "crlf", 583 "sending carriage returns as telnet <CR><LF>", 584 togcrlf, 585 &crlf, 586 0 }, 587 { "crmod", 588 "mapping of received carriage returns", 589 0, 590 &crmod, 591 "map carriage return on output" }, 592 { "localchars", 593 "local recognition of certain control characters", 594 lclchars, 595 &localchars, 596 "recognize certain control characters" }, 597 { " ", "", 0, 0 }, /* empty line */ 598 { "netdata", 599 "printing of hexadecimal network data (debugging)", 600 0, 601 &netdata, 602 "print hexadecimal representation of network traffic" }, 603 { "prettydump", 604 "output of \"netdata\" to user readable format (debugging)", 605 0, 606 &prettydump, 607 "print user readable output for \"netdata\"" }, 608 { "options", 609 "viewing of options processing (debugging)", 610 0, 611 &showoptions, 612 "show option processing" }, 613 { "termdata", 614 "(debugging) toggle printing of hexadecimal terminal data", 615 0, 616 &termdata, 617 "print hexadecimal representation of terminal traffic" }, 618 { "?", 619 0, 620 togglehelp }, 621 { "help", 622 0, 623 togglehelp }, 624 { 0 } 625 }; 626 627 static int 628 togglehelp(int unused) 629 { 630 struct togglelist *c; 631 632 for (c = Togglelist; c->name; c++) { 633 if (c->help) { 634 if (*c->help) 635 printf("%-15s toggle %s\r\n", c->name, c->help); 636 else 637 printf("\r\n"); 638 } 639 } 640 printf("\r\n"); 641 printf("%-15s %s\r\n", "?", "display help information"); 642 return 0; 643 } 644 645 static void 646 settogglehelp(int set) 647 { 648 struct togglelist *c; 649 650 for (c = Togglelist; c->name; c++) { 651 if (c->help) { 652 if (*c->help) 653 printf("%-15s %s %s\r\n", c->name, set ? "enable" : "disable", 654 c->help); 655 else 656 printf("\r\n"); 657 } 658 } 659 } 660 661 #define GETTOGGLE(name) (struct togglelist *) \ 662 genget(name, (char **) Togglelist, sizeof(struct togglelist)) 663 664 static int 665 toggle(int argc, char *argv[]) 666 { 667 int retval = 1; 668 char *name; 669 struct togglelist *c; 670 671 if (argc < 2) { 672 fprintf(stderr, 673 "Need an argument to 'toggle' command. 'toggle ?' for help.\r\n"); 674 return 0; 675 } 676 argc--; 677 argv++; 678 while (argc--) { 679 name = *argv++; 680 c = GETTOGGLE(name); 681 if (Ambiguous(c)) { 682 fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\r\n", 683 name); 684 return 0; 685 } else if (c == 0) { 686 fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\r\n", 687 name); 688 return 0; 689 } else if (!connected && c->needconnect) { 690 printf("?Need to be connected first.\r\n"); 691 printf("'send ?' for help\r\n"); 692 return 0; 693 } else { 694 if (c->variable) { 695 *c->variable = !*c->variable; /* invert it */ 696 if (c->actionexplanation) { 697 printf("%s %s.\r\n", *c->variable? "Will" : "Won't", 698 c->actionexplanation); 699 } 700 } 701 if (c->handler) { 702 retval &= (*c->handler)(-1); 703 } 704 } 705 } 706 return retval; 707 } 708 709 /* 710 * The following perform the "set" command. 711 */ 712 713 struct termios new_tc = { 0 }; 714 715 struct setlist { 716 char *name; /* name */ 717 char *help; /* help information */ 718 void (*handler)(const char *); 719 cc_t *charp; /* where it is located at */ 720 }; 721 722 static struct setlist Setlist[] = { 723 #ifdef KLUDGELINEMODE 724 { "echo", "character to toggle local echoing on/off", 0, &echoc }, 725 #endif 726 { "escape", "character to escape back to telnet command mode", 0, &escape }, 727 { "rlogin", "rlogin escape character", 0, &rlogin }, 728 { " ", "" }, 729 { " ", "The following need 'localchars' to be toggled true", 0, 0 }, 730 { "flushoutput", "character to cause an Abort Output", 0, &termFlushChar }, 731 { "interrupt", "character to cause an Interrupt Process", 0, &termIntChar }, 732 { "quit", "character to cause an Abort process", 0, &termQuitChar }, 733 { "eof", "character to cause an EOF ", 0, &termEofChar }, 734 { " ", "" }, 735 { " ", "The following are for local editing in linemode", 0, 0 }, 736 { "erase", "character to use to erase a character", 0, &termEraseChar }, 737 { "kill", "character to use to erase a line", 0, &termKillChar }, 738 { "lnext", "character to use for literal next", 0, &termLiteralNextChar }, 739 { "susp", "character to cause a Suspend Process", 0, &termSuspChar }, 740 { "reprint", "character to use for line reprint", 0, &termRprntChar }, 741 { "worderase", "character to use to erase a word", 0, &termWerasChar }, 742 { "start", "character to use for XON", 0, &termStartChar }, 743 { "stop", "character to use for XOFF", 0, &termStopChar }, 744 { "forw1", "alternate end of line character", 0, &termForw1Char }, 745 { "forw2", "alternate end of line character", 0, &termForw2Char }, 746 { "ayt", "alternate AYT character", 0, &termAytChar }, 747 { 0 } 748 }; 749 750 static struct setlist * 751 getset(char *name) 752 { 753 return (struct setlist *) 754 genget(name, (char **) Setlist, sizeof(struct setlist)); 755 } 756 757 void 758 set_escape_char(char *s) 759 { 760 if (rlogin != _POSIX_VDISABLE) { 761 rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; 762 printf("Telnet rlogin escape character is '%s'.\r\n", 763 control(rlogin)); 764 } else { 765 escape = (s && *s) ? special(s) : _POSIX_VDISABLE; 766 printf("Telnet escape character is '%s'.\r\n", control(escape)); 767 } 768 } 769 770 static int 771 setcmd(int argc, char *argv[]) 772 { 773 int value; 774 struct setlist *ct; 775 struct togglelist *c; 776 777 if (argc < 2 || argc > 3) { 778 printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n"); 779 return 0; 780 } 781 if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) { 782 for (ct = Setlist; ct->name; ct++) 783 printf("%-15s %s\r\n", ct->name, ct->help); 784 printf("\r\n"); 785 settogglehelp(1); 786 printf("%-15s %s\r\n", "?", "display help information"); 787 return 0; 788 } 789 790 ct = getset(argv[1]); 791 if (ct == 0) { 792 c = GETTOGGLE(argv[1]); 793 if (c == 0) { 794 fprintf(stderr, "'%s': unknown argument ('set ?' for help).\r\n", 795 argv[1]); 796 return 0; 797 } else if (Ambiguous(c)) { 798 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n", 799 argv[1]); 800 return 0; 801 } else if (!connected && c->needconnect) { 802 printf("?Need to be connected first.\r\n"); 803 printf("'send ?' for help\r\n"); 804 return 0; 805 } 806 807 if (c->variable) { 808 if ((argc == 2) || (strcmp("on", argv[2]) == 0)) 809 *c->variable = 1; 810 else if (strcmp("off", argv[2]) == 0) 811 *c->variable = 0; 812 else { 813 printf("Format is 'set togglename [on|off]'\r\n'set ?' for help.\r\n"); 814 return 0; 815 } 816 if (c->actionexplanation) { 817 printf("%s %s.\r\n", *c->variable? "Will" : "Won't", 818 c->actionexplanation); 819 } 820 } 821 if (c->handler) 822 (*c->handler)(1); 823 } else if (argc != 3) { 824 printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n"); 825 return 0; 826 } else if (Ambiguous(ct)) { 827 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n", 828 argv[1]); 829 return 0; 830 } else if (ct->handler) { 831 (*ct->handler)(argv[2]); 832 printf("%s set to \"%s\".\r\n", ct->name, (char *)ct->charp); 833 } else { 834 if (strcmp("off", argv[2])) { 835 value = special(argv[2]); 836 } else { 837 value = _POSIX_VDISABLE; 838 } 839 *(ct->charp) = (cc_t)value; 840 printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp))); 841 } 842 slc_check(); 843 return 1; 844 } 845 846 static int 847 unsetcmd(int argc, char *argv[]) 848 { 849 struct setlist *ct; 850 struct togglelist *c; 851 char *name; 852 853 if (argc < 2) { 854 fprintf(stderr, 855 "Need an argument to 'unset' command. 'unset ?' for help.\r\n"); 856 return 0; 857 } 858 if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) { 859 for (ct = Setlist; ct->name; ct++) 860 printf("%-15s %s\r\n", ct->name, ct->help); 861 printf("\r\n"); 862 settogglehelp(0); 863 printf("%-15s %s\r\n", "?", "display help information"); 864 return 0; 865 } 866 867 argc--; 868 argv++; 869 while (argc--) { 870 name = *argv++; 871 ct = getset(name); 872 if (ct == 0) { 873 c = GETTOGGLE(name); 874 if (c == 0) { 875 fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\r\n", 876 name); 877 return 0; 878 } else if (Ambiguous(c)) { 879 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n", 880 name); 881 return 0; 882 } 883 if (c->variable) { 884 *c->variable = 0; 885 if (c->actionexplanation) { 886 printf("%s %s.\r\n", *c->variable? "Will" : "Won't", 887 c->actionexplanation); 888 } 889 } 890 if (c->handler) 891 (*c->handler)(0); 892 } else if (Ambiguous(ct)) { 893 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n", 894 name); 895 return 0; 896 } else if (ct->handler) { 897 (*ct->handler)(NULL); 898 printf("%s reset to \"%s\".\r\n", ct->name, (char *)ct->charp); 899 } else { 900 *(ct->charp) = _POSIX_VDISABLE; 901 printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp))); 902 } 903 } 904 return 1; 905 } 906 907 /* 908 * The following are the data structures and routines for the 909 * 'mode' command. 910 */ 911 #ifdef KLUDGELINEMODE 912 static int 913 dokludgemode(int unused) 914 { 915 kludgelinemode = 1; 916 send_wont(TELOPT_LINEMODE, 1); 917 send_dont(TELOPT_SGA, 1); 918 send_dont(TELOPT_ECHO, 1); 919 return 1; 920 } 921 #endif 922 923 static int 924 dolinemode(int unused) 925 { 926 #ifdef KLUDGELINEMODE 927 if (kludgelinemode) 928 send_dont(TELOPT_SGA, 1); 929 #endif 930 send_will(TELOPT_LINEMODE, 1); 931 send_dont(TELOPT_ECHO, 1); 932 return 1; 933 } 934 935 static int 936 docharmode(int unused) 937 { 938 #ifdef KLUDGELINEMODE 939 if (kludgelinemode) 940 send_do(TELOPT_SGA, 1); 941 else 942 #endif 943 send_wont(TELOPT_LINEMODE, 1); 944 send_do(TELOPT_ECHO, 1); 945 return 1; 946 } 947 948 static int 949 dolmmode(int bit, int on) 950 { 951 unsigned char c; 952 953 if (my_want_state_is_wont(TELOPT_LINEMODE)) { 954 printf("?Need to have LINEMODE option enabled first.\r\n"); 955 printf("'mode ?' for help.\r\n"); 956 return 0; 957 } 958 959 if (on) 960 c = (linemode | bit); 961 else 962 c = (linemode & ~bit); 963 lm_mode(&c, 1, 1); 964 return 1; 965 } 966 967 int 968 tn_setmode(int bit) 969 { 970 return dolmmode(bit, 1); 971 } 972 973 int 974 tn_clearmode(int bit) 975 { 976 return dolmmode(bit, 0); 977 } 978 979 struct modelist { 980 char *name; /* command name */ 981 char *help; /* help string */ 982 int (*handler)(int);/* routine which executes command */ 983 int needconnect; /* Do we need to be connected to execute? */ 984 int arg1; 985 }; 986 987 static int modehelp(int); 988 989 static struct modelist ModeList[] = { 990 { "character", "Disable LINEMODE option", docharmode, 1 }, 991 #ifdef KLUDGELINEMODE 992 { "", "(or disable obsolete line-by-line mode)", 0 }, 993 #endif 994 { "line", "Enable LINEMODE option", dolinemode, 1 }, 995 #ifdef KLUDGELINEMODE 996 { "", "(or enable obsolete line-by-line mode)", 0 }, 997 #endif 998 { "", "", 0 }, 999 { "", "These require the LINEMODE option to be enabled", 0 }, 1000 { "isig", "Enable signal trapping", tn_setmode, 1, MODE_TRAPSIG }, 1001 { "+isig", 0, tn_setmode, 1, MODE_TRAPSIG }, 1002 { "-isig", "Disable signal trapping", tn_clearmode, 1, MODE_TRAPSIG }, 1003 { "edit", "Enable character editing", tn_setmode, 1, MODE_EDIT }, 1004 { "+edit", 0, tn_setmode, 1, MODE_EDIT }, 1005 { "-edit", "Disable character editing", tn_clearmode, 1, MODE_EDIT }, 1006 { "softtabs", "Enable tab expansion", tn_setmode, 1, MODE_SOFT_TAB }, 1007 { "+softtabs", 0, tn_setmode, 1, MODE_SOFT_TAB }, 1008 { "-softtabs", "Disable character editing", tn_clearmode, 1, MODE_SOFT_TAB }, 1009 { "litecho", "Enable literal character echo", tn_setmode, 1, MODE_LIT_ECHO }, 1010 { "+litecho", 0, tn_setmode, 1, MODE_LIT_ECHO }, 1011 { "-litecho", "Disable literal character echo", tn_clearmode, 1, MODE_LIT_ECHO }, 1012 { "help", 0, modehelp, 0 }, 1013 #ifdef KLUDGELINEMODE 1014 { "kludgeline", 0, dokludgemode, 1 }, 1015 #endif 1016 { "", "", 0 }, 1017 { "?", "Print help information", modehelp, 0 }, 1018 { 0 }, 1019 }; 1020 1021 static int 1022 modehelp(int unused) 1023 { 1024 struct modelist *mt; 1025 1026 printf("format is: 'mode Mode', where 'Mode' is one of:\r\n\r\n"); 1027 for (mt = ModeList; mt->name; mt++) { 1028 if (mt->help) { 1029 if (*mt->help) 1030 printf("%-15s %s\r\n", mt->name, mt->help); 1031 else 1032 printf("\r\n"); 1033 } 1034 } 1035 return 0; 1036 } 1037 1038 #define GETMODECMD(name) (struct modelist *) \ 1039 genget(name, (char **) ModeList, sizeof(struct modelist)) 1040 1041 static int 1042 modecmd(int argc, char *argv[]) 1043 { 1044 struct modelist *mt; 1045 1046 if (argc != 2) { 1047 printf("'mode' command requires an argument\r\n"); 1048 printf("'mode ?' for help.\r\n"); 1049 } else if ((mt = GETMODECMD(argv[1])) == 0) { 1050 fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\r\n", argv[1]); 1051 } else if (Ambiguous(mt)) { 1052 fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\r\n", argv[1]); 1053 } else if (mt->needconnect && !connected) { 1054 printf("?Need to be connected first.\r\n"); 1055 printf("'mode ?' for help.\r\n"); 1056 } else if (mt->handler) { 1057 return (*mt->handler)(mt->arg1); 1058 } 1059 return 0; 1060 } 1061 1062 /* 1063 * The following data structures and routines implement the 1064 * "display" command. 1065 */ 1066 1067 static int 1068 display(int argc, char *argv[]) 1069 { 1070 struct togglelist *tl; 1071 struct setlist *sl; 1072 1073 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 1074 if (*tl->variable) { \ 1075 printf("will"); \ 1076 } else { \ 1077 printf("won't"); \ 1078 } \ 1079 printf(" %s.\r\n", tl->actionexplanation); \ 1080 } 1081 1082 #define doset(sl) if (sl->name && *sl->name != ' ') { \ 1083 if (sl->handler == 0) \ 1084 printf("%-15s [%s]\r\n", sl->name, control(*sl->charp)); \ 1085 else \ 1086 printf("%-15s \"%s\"\r\n", sl->name, (char *)sl->charp); \ 1087 } 1088 1089 if (argc == 1) { 1090 for (tl = Togglelist; tl->name; tl++) { 1091 dotog(tl); 1092 } 1093 printf("\r\n"); 1094 for (sl = Setlist; sl->name; sl++) { 1095 doset(sl); 1096 } 1097 } else { 1098 int i; 1099 1100 for (i = 1; i < argc; i++) { 1101 sl = getset(argv[i]); 1102 tl = GETTOGGLE(argv[i]); 1103 if (Ambiguous(sl) || Ambiguous(tl)) { 1104 printf("?Ambiguous argument '%s'.\r\n", argv[i]); 1105 return 0; 1106 } else if (!sl && !tl) { 1107 printf("?Unknown argument '%s'.\r\n", argv[i]); 1108 return 0; 1109 } else { 1110 if (tl) { 1111 dotog(tl); 1112 } 1113 if (sl) { 1114 doset(sl); 1115 } 1116 } 1117 } 1118 } 1119 /*@*/optionstatus(); 1120 return 1; 1121 #undef doset 1122 #undef dotog 1123 } 1124 1125 /* 1126 * The following are the data structures, and many of the routines, 1127 * relating to command processing. 1128 */ 1129 1130 /* 1131 * Set the escape character. 1132 */ 1133 static int 1134 setescape(int argc, char *argv[]) 1135 { 1136 char *arg; 1137 char buf[50]; 1138 1139 printf( 1140 "Deprecated usage - please use 'set escape%s%s' in the future.\r\n", 1141 (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 1142 if (argc > 2) 1143 arg = argv[1]; 1144 else { 1145 printf("new escape character: "); 1146 (void) fgets(buf, sizeof(buf), stdin); 1147 arg = buf; 1148 } 1149 if (arg[0] != '\0') 1150 escape = arg[0]; 1151 printf("Escape character is '%s'.\r\n", control(escape)); 1152 (void) fflush(stdout); 1153 return 1; 1154 } 1155 1156 static int 1157 togcrmod(int unused1, char *unused2[]) 1158 { 1159 crmod = !crmod; 1160 printf("Deprecated usage - please use 'toggle crmod' in the future.\r\n"); 1161 printf("%s map carriage return on output.\r\n", crmod ? "Will" : "Won't"); 1162 (void) fflush(stdout); 1163 return 1; 1164 } 1165 1166 int 1167 telnetsuspend(int unused1, char *unused2[]) 1168 { 1169 setcommandmode(); 1170 { 1171 long oldrows, oldcols, newrows, newcols, err; 1172 1173 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1174 (void) kill(0, SIGTSTP); 1175 /* 1176 * If we didn't get the window size before the SUSPEND, but we 1177 * can get them now (?), then send the NAWS to make sure that 1178 * we are set up for the right window size. 1179 */ 1180 if (TerminalWindowSize(&newrows, &newcols) && connected && 1181 (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1182 sendnaws(); 1183 } 1184 } 1185 /* reget parameters in case they were changed */ 1186 TerminalSaveState(); 1187 setconnmode(0); 1188 return 1; 1189 } 1190 1191 static void 1192 close_connection(void) 1193 { 1194 if (connected) { 1195 (void) shutdown(net, SHUT_RDWR); 1196 printf("Connection closed.\r\n"); 1197 (void)close(net); 1198 connected = 0; 1199 resettermname = 1; 1200 /* reset options */ 1201 tninit(); 1202 } 1203 } 1204 1205 static int 1206 bye(int argc, char *argv[]) 1207 { 1208 close_connection(); 1209 longjmp(toplevel, 1); 1210 } 1211 1212 void 1213 quit(void) 1214 { 1215 close_connection(); 1216 Exit(0); 1217 } 1218 1219 static int 1220 quitcmd(int unused1, char *unused2[]) 1221 { 1222 quit(); 1223 } 1224 1225 static int 1226 logout(int unused1, char *unused2[]) 1227 { 1228 send_do(TELOPT_LOGOUT, 1); 1229 (void) netflush(); 1230 return 1; 1231 } 1232 1233 1234 /* 1235 * The SLC command. 1236 */ 1237 1238 struct slclist { 1239 char *name; 1240 char *help; 1241 void (*handler)(int); 1242 int arg; 1243 }; 1244 1245 static void slc_help(int); 1246 1247 struct slclist SlcList[] = { 1248 { "export", "Use local special character definitions", 1249 slc_mode_export, 0 }, 1250 { "import", "Use remote special character definitions", 1251 slc_mode_import, 1 }, 1252 { "check", "Verify remote special character definitions", 1253 slc_mode_import, 0 }, 1254 { "help", 0, slc_help, 0 }, 1255 { "?", "Print help information", slc_help, 0 }, 1256 { 0 }, 1257 }; 1258 1259 static void 1260 slc_help(int unused) 1261 { 1262 struct slclist *c; 1263 1264 for (c = SlcList; c->name; c++) { 1265 if (c->help) { 1266 if (*c->help) 1267 printf("%-15s %s\r\n", c->name, c->help); 1268 else 1269 printf("\r\n"); 1270 } 1271 } 1272 } 1273 1274 static struct slclist * 1275 getslc(char *name) 1276 { 1277 return (struct slclist *) 1278 genget(name, (char **) SlcList, sizeof(struct slclist)); 1279 } 1280 1281 static int 1282 slccmd(int argc, char *argv[]) 1283 { 1284 struct slclist *c; 1285 1286 if (argc != 2) { 1287 fprintf(stderr, 1288 "Need an argument to 'slc' command. 'slc ?' for help.\r\n"); 1289 return 0; 1290 } 1291 c = getslc(argv[1]); 1292 if (c == 0) { 1293 fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\r\n", 1294 argv[1]); 1295 return 0; 1296 } 1297 if (Ambiguous(c)) { 1298 fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\r\n", 1299 argv[1]); 1300 return 0; 1301 } 1302 (*c->handler)(c->arg); 1303 slcstate(); 1304 return 1; 1305 } 1306 1307 /* 1308 * The ENVIRON command. 1309 */ 1310 1311 struct envlist { 1312 char *name; 1313 char *help; 1314 void (*handler)(); 1315 int narg; 1316 }; 1317 1318 static void env_help(void); 1319 static void env_undefine(const char *); 1320 static void env_export(const char *); 1321 static void env_unexport(const char *); 1322 static void env_send(const char *); 1323 static void env_list(void); 1324 static struct env_lst *env_find(const char *var); 1325 1326 struct envlist EnvList[] = { 1327 { "define", "Define an environment variable", 1328 (void (*)())env_define, 2 }, 1329 { "undefine", "Undefine an environment variable", 1330 env_undefine, 1 }, 1331 { "export", "Mark an environment variable for automatic export", 1332 env_export, 1 }, 1333 { "unexport", "Don't mark an environment variable for automatic export", 1334 env_unexport, 1 }, 1335 { "send", "Send an environment variable", env_send, 1 }, 1336 { "list", "List the current environment variables", 1337 env_list, 0 }, 1338 { "help", 0, env_help, 0 }, 1339 { "?", "Print help information", env_help, 0 }, 1340 { 0 }, 1341 }; 1342 1343 static void 1344 env_help(void) 1345 { 1346 struct envlist *c; 1347 1348 for (c = EnvList; c->name; c++) { 1349 if (c->help) { 1350 if (*c->help) 1351 printf("%-15s %s\r\n", c->name, c->help); 1352 else 1353 printf("\r\n"); 1354 } 1355 } 1356 } 1357 1358 static struct envlist * 1359 getenvcmd(char *name) 1360 { 1361 return (struct envlist *) 1362 genget(name, (char **) EnvList, sizeof(struct envlist)); 1363 } 1364 1365 static int 1366 env_cmd(int argc, char *argv[]) 1367 { 1368 struct envlist *c; 1369 1370 if (argc < 2) { 1371 fprintf(stderr, 1372 "Need an argument to 'environ' command. 'environ ?' for help.\r\n"); 1373 return 0; 1374 } 1375 c = getenvcmd(argv[1]); 1376 if (c == 0) { 1377 fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\r\n", 1378 argv[1]); 1379 return 0; 1380 } 1381 if (Ambiguous(c)) { 1382 fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\r\n", 1383 argv[1]); 1384 return 0; 1385 } 1386 if (c->narg + 2 != argc) { 1387 fprintf(stderr, 1388 "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\r\n", 1389 c->narg < argc + 2 ? "only " : "", 1390 c->narg, c->narg == 1 ? "" : "s", c->name); 1391 return 0; 1392 } 1393 (*c->handler)(argv[2], argv[3]); 1394 return 1; 1395 } 1396 1397 struct env_lst { 1398 struct env_lst *next; /* pointer to next structure */ 1399 struct env_lst *prev; /* pointer to previous structure */ 1400 char *var; /* pointer to variable name */ 1401 char *value; /* pointer to variable value */ 1402 int export; /* 1 -> export with default list of variables */ 1403 int welldefined; /* A well defined variable */ 1404 }; 1405 1406 struct env_lst envlisthead; 1407 1408 static struct env_lst * 1409 env_find(const char *var) 1410 { 1411 struct env_lst *ep; 1412 1413 for (ep = envlisthead.next; ep; ep = ep->next) { 1414 if (strcmp(ep->var, var) == 0) 1415 return(ep); 1416 } 1417 return(NULL); 1418 } 1419 1420 void 1421 env_init(void) 1422 { 1423 extern char **environ; 1424 char **epp, *cp; 1425 struct env_lst *ep; 1426 1427 for (epp = environ; *epp; epp++) { 1428 if ((cp = strchr(*epp, '='))) { 1429 *cp = '\0'; 1430 ep = env_define(*epp, cp+1); 1431 ep->export = 0; 1432 *cp = '='; 1433 } 1434 } 1435 /* 1436 * Special case for DISPLAY variable. If it is ":0.0" or 1437 * "unix:0.0", we have to get rid of "unix" and insert our 1438 * hostname. 1439 */ 1440 if ((ep = env_find("DISPLAY")) 1441 && ((*ep->value == ':') 1442 || (strncmp(ep->value, "unix:", 5) == 0))) { 1443 char hbuf[HOST_NAME_MAX+1]; 1444 char *cp2 = strchr(ep->value, ':'); 1445 1446 gethostname(hbuf, sizeof hbuf); 1447 1448 if (asprintf (&cp, "%s%s", hbuf, cp2) == -1) 1449 err(1, "asprintf"); 1450 1451 free(ep->value); 1452 ep->value = cp; 1453 } 1454 /* 1455 * If USER is not defined, but LOGNAME is, then add 1456 * USER with the value from LOGNAME. By default, we 1457 * don't export the USER variable. 1458 */ 1459 if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) { 1460 env_define("USER", ep->value); 1461 env_unexport("USER"); 1462 } 1463 env_export("DISPLAY"); 1464 env_export("PRINTER"); 1465 env_export("XAUTHORITY"); 1466 } 1467 1468 struct env_lst * 1469 env_define(const char *var, const char *value) 1470 { 1471 struct env_lst *ep; 1472 1473 if ((ep = env_find(var))) { 1474 free(ep->var); 1475 free(ep->value); 1476 } else { 1477 if ((ep = malloc(sizeof(struct env_lst))) == NULL) 1478 err(1, "malloc"); 1479 ep->next = envlisthead.next; 1480 envlisthead.next = ep; 1481 ep->prev = &envlisthead; 1482 if (ep->next) 1483 ep->next->prev = ep; 1484 } 1485 ep->welldefined = opt_welldefined(var); 1486 ep->export = 1; 1487 if ((ep->var = strdup(var)) == NULL) 1488 err(1, "strdup"); 1489 if ((ep->value = strdup(value)) == NULL) 1490 err(1, "strdup"); 1491 return(ep); 1492 } 1493 1494 static void 1495 env_undefine(const char *var) 1496 { 1497 struct env_lst *ep; 1498 1499 if ((ep = env_find(var))) { 1500 ep->prev->next = ep->next; 1501 if (ep->next) 1502 ep->next->prev = ep->prev; 1503 free(ep->var); 1504 free(ep->value); 1505 free(ep); 1506 } 1507 } 1508 1509 static void 1510 env_export(const char *var) 1511 { 1512 struct env_lst *ep; 1513 1514 if ((ep = env_find(var))) 1515 ep->export = 1; 1516 } 1517 1518 static void 1519 env_unexport(const char *var) 1520 { 1521 struct env_lst *ep; 1522 1523 if ((ep = env_find(var)) != NULL) 1524 ep->export = 0; 1525 } 1526 1527 static void 1528 env_send(const char *var) 1529 { 1530 struct env_lst *ep; 1531 1532 if (my_state_is_wont(TELOPT_NEW_ENVIRON) 1533 ) { 1534 fprintf(stderr, 1535 "Cannot send '%s': Telnet ENVIRON option not enabled\r\n", 1536 var); 1537 return; 1538 } 1539 ep = env_find(var); 1540 if (ep == 0) { 1541 fprintf(stderr, "Cannot send '%s': variable not defined\r\n", 1542 var); 1543 return; 1544 } 1545 env_opt_start_info(); 1546 env_opt_add(ep->var); 1547 env_opt_end(0); 1548 } 1549 1550 static void 1551 env_list(void) 1552 { 1553 struct env_lst *ep; 1554 1555 for (ep = envlisthead.next; ep; ep = ep->next) { 1556 printf("%c %-20s %s\r\n", ep->export ? '*' : ' ', 1557 ep->var, ep->value); 1558 } 1559 } 1560 1561 char * 1562 env_default(int init, int welldefined) 1563 { 1564 static struct env_lst *nep = NULL; 1565 1566 if (init) { 1567 nep = &envlisthead; 1568 return NULL; 1569 } 1570 if (nep) { 1571 while ((nep = nep->next)) { 1572 if (nep->export && (nep->welldefined == welldefined)) 1573 return(nep->var); 1574 } 1575 } 1576 return(NULL); 1577 } 1578 1579 char * 1580 env_getvalue(const char *var, int exported_only) 1581 { 1582 struct env_lst *ep; 1583 1584 if ((ep = env_find(var)) && (!exported_only || ep->export)) 1585 return(ep->value); 1586 return(NULL); 1587 } 1588 1589 static void 1590 connection_status(int local_only) 1591 { 1592 if (!connected) 1593 printf("No connection.\r\n"); 1594 else { 1595 printf("Connected to %s.\r\n", hostname); 1596 if (!local_only) { 1597 int mode = getconnmode(); 1598 1599 printf("Operating "); 1600 if (my_want_state_is_will(TELOPT_LINEMODE)) { 1601 printf("with LINEMODE option\r\n" 1602 "%s line editing\r\n" 1603 "%s catching of signals\r\n", 1604 (mode & MODE_EDIT) ? "Local" : "No", 1605 (mode & MODE_TRAPSIG) ? "Local" : "No"); 1606 slcstate(); 1607 #ifdef KLUDGELINEMODE 1608 } else if (kludgelinemode && 1609 my_want_state_is_dont(TELOPT_SGA)) { 1610 printf("in obsolete linemode\r\n"); 1611 #endif 1612 } else { 1613 printf("in single character mode\r\n"); 1614 if (localchars) 1615 printf("Catching signals locally\r\n"); 1616 } 1617 1618 printf("%s character echo\r\n", 1619 (mode & MODE_ECHO) ? "Local" : "Remote"); 1620 if (my_want_state_is_will(TELOPT_LFLOW)) 1621 printf("%s flow control\r\n", 1622 (mode & MODE_FLOW) ? "Local" : "No"); 1623 } 1624 } 1625 printf("Escape character is '%s'.\r\n", control(escape)); 1626 (void) fflush(stdout); 1627 } 1628 1629 /* 1630 * Print status about the connection. 1631 */ 1632 static int 1633 status(int argc, char *argv[]) 1634 { 1635 connection_status(0); 1636 return 1; 1637 } 1638 1639 /* 1640 * Function that gets called when SIGINFO is received. 1641 */ 1642 void 1643 ayt_status(int sig) 1644 { 1645 connection_status(1); 1646 } 1647 1648 static Command *getcmd(char *name); 1649 1650 static void 1651 cmdrc(char *m1, char *m2) 1652 { 1653 static char rcname[128]; 1654 Command *c; 1655 FILE *rcfile; 1656 int gotmachine = 0; 1657 int l1 = strlen(m1); 1658 int l2 = strlen(m2); 1659 char m1save[HOST_NAME_MAX+1]; 1660 1661 if (skiprc) 1662 return; 1663 1664 strlcpy(m1save, m1, sizeof(m1save)); 1665 m1 = m1save; 1666 1667 if (rcname[0] == 0) { 1668 char *home = getenv("HOME"); 1669 1670 if (home == NULL || *home == '\0') 1671 return; 1672 snprintf (rcname, sizeof(rcname), "%s/.telnetrc", 1673 home ? home : ""); 1674 } 1675 1676 if ((rcfile = fopen(rcname, "r")) == 0) { 1677 return; 1678 } 1679 1680 for (;;) { 1681 if (fgets(line, sizeof(line), rcfile) == NULL) 1682 break; 1683 if (line[0] == 0) 1684 break; 1685 if (line[0] == '#') 1686 continue; 1687 if (gotmachine) { 1688 if (!isspace((unsigned char)line[0])) 1689 gotmachine = 0; 1690 } 1691 if (gotmachine == 0) { 1692 if (isspace((unsigned char)line[0])) 1693 continue; 1694 if (strncasecmp(line, m1, l1) == 0) 1695 strncpy(line, &line[l1], sizeof(line) - l1); 1696 else if (strncasecmp(line, m2, l2) == 0) 1697 strncpy(line, &line[l2], sizeof(line) - l2); 1698 else if (strncasecmp(line, "DEFAULT", 7) == 0) 1699 strncpy(line, &line[7], sizeof(line) - 7); 1700 else 1701 continue; 1702 if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') 1703 continue; 1704 gotmachine = 1; 1705 } 1706 if (makeargv()) 1707 continue; 1708 if (margv[0] == 0) 1709 continue; 1710 c = getcmd(margv[0]); 1711 if (Ambiguous(c)) { 1712 printf("?Ambiguous command: %s\r\n", margv[0]); 1713 continue; 1714 } 1715 if (c == 0) { 1716 printf("?Invalid command: %s\r\n", margv[0]); 1717 continue; 1718 } 1719 /* 1720 * This should never happen... 1721 */ 1722 if (c->needconnect && !connected) { 1723 printf("?Need to be connected first for %s.\r\n", margv[0]); 1724 continue; 1725 } 1726 (*c->handler)(margc, margv); 1727 } 1728 fclose(rcfile); 1729 } 1730 1731 int 1732 tn(int argc, char *argv[]) 1733 { 1734 struct addrinfo hints, *res, *res0; 1735 char *cmd, *hostp = 0, *portp = 0, *user = 0, *aliasp = 0; 1736 int error, retry; 1737 const int niflags = NI_NUMERICHOST, tos = IPTOS_LOWDELAY; 1738 1739 if (connected) { 1740 printf("?Already connected to %s\r\n", hostname); 1741 return 0; 1742 } 1743 if (connections) { 1744 printf("Repeated connections not supported\r\n"); 1745 return 0; 1746 } 1747 if (argc < 2) { 1748 strlcpy(line, "open ", sizeof(line)); 1749 printf("(to) "); 1750 (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); 1751 if (makeargv()) 1752 return 0; 1753 argc = margc; 1754 argv = margv; 1755 } 1756 cmd = *argv; 1757 --argc; ++argv; 1758 while (argc) { 1759 if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?")) 1760 goto usage; 1761 if (strcmp(*argv, "-l") == 0) { 1762 --argc; ++argv; 1763 if (argc == 0) 1764 goto usage; 1765 if ((user = strdup(*argv++)) == NULL) 1766 err(1, "strdup"); 1767 --argc; 1768 continue; 1769 } 1770 if (strcmp(*argv, "-b") == 0) { 1771 --argc; ++argv; 1772 if (argc == 0) 1773 goto usage; 1774 aliasp = *argv++; 1775 --argc; 1776 continue; 1777 } 1778 if (strcmp(*argv, "-a") == 0) { 1779 --argc; ++argv; 1780 autologin = 1; 1781 continue; 1782 } 1783 if (hostp == 0) { 1784 hostp = *argv++; 1785 --argc; 1786 continue; 1787 } 1788 if (portp == 0) { 1789 portp = *argv++; 1790 --argc; 1791 continue; 1792 } 1793 usage: 1794 printf("usage: %s [-a] [-b hostalias] [-l user] host-name [port]\r\n", cmd); 1795 return 0; 1796 } 1797 if (hostp == 0) 1798 goto usage; 1799 1800 hostname = hostp; 1801 memset(&hints, 0, sizeof(hints)); 1802 hints.ai_family = family; 1803 hints.ai_socktype = SOCK_STREAM; 1804 hints.ai_flags = AI_CANONNAME; 1805 if (portp == NULL) { 1806 portp = "telnet"; 1807 telnetport = 1; 1808 } else if (*portp == '-') { 1809 portp++; 1810 telnetport = 1; 1811 } else 1812 telnetport = 0; 1813 error = getaddrinfo(hostp, portp, &hints, &res0); 1814 if (error) { 1815 if (error == EAI_SERVICE) 1816 warnx("%s: bad port", portp); 1817 else 1818 warnx("%s: %s", hostp, gai_strerror(error)); 1819 return 0; 1820 } 1821 1822 net = -1; 1823 retry = 0; 1824 for (res = res0; res; res = res->ai_next) { 1825 if (1 /* retry */) { 1826 char hbuf[NI_MAXHOST]; 1827 1828 if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), 1829 NULL, 0, niflags) != 0) { 1830 strlcpy(hbuf, "(invalid)", sizeof(hbuf)); 1831 } 1832 printf("Trying %s...\r\n", hbuf); 1833 } 1834 net = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 1835 if (net == -1) 1836 continue; 1837 1838 if (aliasp) { 1839 struct addrinfo ahints, *ares; 1840 1841 memset(&ahints, 0, sizeof(ahints)); 1842 ahints.ai_family = family; 1843 ahints.ai_socktype = SOCK_STREAM; 1844 ahints.ai_flags = AI_PASSIVE; 1845 error = getaddrinfo(aliasp, "0", &ahints, &ares); 1846 if (error) { 1847 warn("%s: %s", aliasp, gai_strerror(error)); 1848 close(net); 1849 net = -1; 1850 continue; 1851 } 1852 if (bind(net, ares->ai_addr, ares->ai_addrlen) == -1) { 1853 perror(aliasp); 1854 (void) close(net); /* dump descriptor */ 1855 net = -1; 1856 freeaddrinfo(ares); 1857 continue; 1858 } 1859 freeaddrinfo(ares); 1860 } 1861 1862 switch (res->ai_family) { 1863 case AF_INET: 1864 if (setsockopt(net, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1 1865 && errno != ENOPROTOOPT) 1866 perror("telnet: setsockopt (IP_TOS) (ignored)"); 1867 break; 1868 case AF_INET6: 1869 if (setsockopt(net, IPPROTO_IPV6, IPV6_TCLASS, &tos, 1870 sizeof(tos)) == -1 && errno != ENOPROTOOPT) 1871 perror("telnet: setsockopt (IPV6_TCLASS) (ignored)"); 1872 break; 1873 } 1874 1875 if (connect(net, res->ai_addr, res->ai_addrlen) == -1) { 1876 char hbuf[NI_MAXHOST]; 1877 1878 if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), 1879 NULL, 0, niflags) != 0) { 1880 strlcpy(hbuf, "(invalid)", sizeof(hbuf)); 1881 } 1882 fprintf(stderr, "telnet: connect to address %s: %s\n", hbuf, 1883 strerror(errno)); 1884 1885 close(net); 1886 net = -1; 1887 retry++; 1888 continue; 1889 } 1890 1891 connected++; 1892 break; 1893 } 1894 freeaddrinfo(res0); 1895 if (net < 0) { 1896 return 0; 1897 } 1898 cmdrc(hostp, hostname); 1899 if (autologin && user == NULL) { 1900 struct passwd *pw; 1901 1902 user = getlogin(); 1903 if (user == NULL || 1904 (pw = getpwnam(user)) == NULL || pw->pw_uid != getuid()) { 1905 if ((pw = getpwuid(getuid())) != NULL) 1906 user = pw->pw_name; 1907 else 1908 user = NULL; 1909 } 1910 } 1911 if (user) { 1912 env_define("USER", user); 1913 env_export("USER"); 1914 } 1915 connection_status(1); 1916 if (setjmp(peerdied) == 0) 1917 telnet(user); 1918 (void)close(net); 1919 ExitString("Connection closed by foreign host.\r\n",1); 1920 } 1921 1922 #define HELPINDENT (sizeof ("connect")) 1923 1924 static char 1925 openhelp[] = "connect to a site", 1926 closehelp[] = "close current connection", 1927 logouthelp[] = "forcibly logout remote user and close the connection", 1928 quithelp[] = "exit telnet", 1929 statushelp[] = "print status information", 1930 helphelp[] = "print help information", 1931 sendhelp[] = "transmit special characters ('send ?' for more)", 1932 sethelp[] = "set operating parameters ('set ?' for more)", 1933 unsethelp[] = "unset operating parameters ('unset ?' for more)", 1934 togglestring[] ="toggle operating parameters ('toggle ?' for more)", 1935 slchelp[] = "change state of special characters ('slc ?' for more)", 1936 displayhelp[] = "display operating parameters", 1937 zhelp[] = "suspend telnet", 1938 envhelp[] = "change environment variables ('environ ?' for more)", 1939 modestring[] = "try to enter line or character mode ('mode ?' for more)"; 1940 1941 static int help(int, char**); 1942 1943 static Command cmdtab[] = { 1944 { "close", closehelp, bye, 1 }, 1945 { "logout", logouthelp, logout, 1 }, 1946 { "display", displayhelp, display, 0 }, 1947 { "mode", modestring, modecmd, 0 }, 1948 { "open", openhelp, tn, 0 }, 1949 { "quit", quithelp, quitcmd, 0 }, 1950 { "send", sendhelp, sendcmd, 0 }, 1951 { "set", sethelp, setcmd, 0 }, 1952 { "unset", unsethelp, unsetcmd, 0 }, 1953 { "status", statushelp, status, 0 }, 1954 { "toggle", togglestring, toggle, 0 }, 1955 { "slc", slchelp, slccmd, 0 }, 1956 1957 { "z", zhelp, telnetsuspend, 0 }, 1958 { "environ", envhelp, env_cmd, 0 }, 1959 { "?", helphelp, help, 0 }, 1960 { 0, 0, 0, 0 } 1961 }; 1962 1963 static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 1964 static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 1965 1966 static Command cmdtab2[] = { 1967 { "help", 0, help, 0 }, 1968 { "escape", escapehelp, setescape, 0 }, 1969 { "crmod", crmodhelp, togcrmod, 0 }, 1970 { 0, 0, 0, 0 } 1971 }; 1972 1973 1974 static Command * 1975 getcmd(char *name) 1976 { 1977 Command *cm; 1978 1979 if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))) 1980 return cm; 1981 return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); 1982 } 1983 1984 void 1985 command(int top, char *tbuf, int cnt) 1986 { 1987 Command *c; 1988 1989 setcommandmode(); 1990 if (!top) { 1991 putchar('\n'); 1992 } else { 1993 (void) signal(SIGINT, SIG_DFL); 1994 (void) signal(SIGQUIT, SIG_DFL); 1995 } 1996 for (;;) { 1997 if (rlogin == _POSIX_VDISABLE) 1998 printf("%s> ", prompt); 1999 if (tbuf) { 2000 char *cp; 2001 cp = line; 2002 while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 2003 cnt--; 2004 tbuf = 0; 2005 if (cp == line || *--cp != '\n' || cp == line) 2006 goto getline; 2007 *cp = '\0'; 2008 if (rlogin == _POSIX_VDISABLE) 2009 printf("%s\r\n", line); 2010 } else { 2011 getline: 2012 if (rlogin != _POSIX_VDISABLE) 2013 printf("%s> ", prompt); 2014 if (fgets(line, sizeof(line), stdin) == NULL) { 2015 if (feof(stdin) || ferror(stdin)) 2016 quit(); 2017 break; 2018 } 2019 } 2020 if (line[0] == 0) 2021 break; 2022 if (makeargv()) 2023 break; 2024 if (margv[0] == 0) { 2025 break; 2026 } 2027 c = getcmd(margv[0]); 2028 if (Ambiguous(c)) { 2029 printf("?Ambiguous command\r\n"); 2030 continue; 2031 } 2032 if (c == 0) { 2033 printf("?Invalid command\r\n"); 2034 continue; 2035 } 2036 if (c->needconnect && !connected) { 2037 printf("?Need to be connected first.\r\n"); 2038 continue; 2039 } 2040 if ((*c->handler)(margc, margv)) { 2041 break; 2042 } 2043 } 2044 if (!top) { 2045 if (!connected) 2046 longjmp(toplevel, 1); 2047 setconnmode(0); 2048 } 2049 } 2050 2051 /* 2052 * Help command. 2053 */ 2054 static int 2055 help(int argc, char *argv[]) 2056 { 2057 Command *c; 2058 2059 if (argc == 1) { 2060 printf("Commands may be abbreviated. Commands are:\r\n\r\n"); 2061 for (c = cmdtab; c->name; c++) 2062 if (c->help) { 2063 printf("%-*s\t%s\r\n", (int)HELPINDENT, c->name, 2064 c->help); 2065 } 2066 return 0; 2067 } 2068 while (--argc > 0) { 2069 char *arg; 2070 arg = *++argv; 2071 c = getcmd(arg); 2072 if (Ambiguous(c)) 2073 printf("?Ambiguous help command %s\r\n", arg); 2074 else if (c == NULL) 2075 printf("?Invalid help command %s\r\n", arg); 2076 else 2077 printf("%s\r\n", c->help); 2078 } 2079 return 0; 2080 } 2081