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