1/* 2 * Copyright (c) 1988, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include "telnet_locl.h" 35 36RCSID("$Id: commands.c 16224 2005-10-22 17:17:44Z lha $"); 37 38#if defined(IPPROTO_IP) && defined(IP_TOS) 39int tos = -1; 40#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ 41 42char *hostname; 43static char _hostname[MaxHostNameLen]; 44 45typedef int (*intrtn_t)(int, char**); 46static int call(intrtn_t, ...); 47 48typedef struct { 49 char *name; /* command name */ 50 char *help; /* help string (NULL for no help) */ 51 int (*handler)(); /* routine which executes command */ 52 int needconnect; /* Do we need to be connected to execute? */ 53} Command; 54 55static char line[256]; 56static char saveline[256]; 57static int margc; 58static char *margv[20]; 59 60static void 61makeargv() 62{ 63 char *cp, *cp2, c; 64 char **argp = margv; 65 66 margc = 0; 67 cp = line; 68 if (*cp == '!') { /* Special case shell escape */ 69 /* save for shell command */ 70 strlcpy(saveline, line, sizeof(saveline)); 71 *argp++ = "!"; /* No room in string to get this */ 72 margc++; 73 cp++; 74 } 75 while ((c = *cp)) { 76 int inquote = 0; 77 while (isspace((unsigned char)c)) 78 c = *++cp; 79 if (c == '\0') 80 break; 81 *argp++ = cp; 82 margc += 1; 83 for (cp2 = cp; c != '\0'; c = *++cp) { 84 if (inquote) { 85 if (c == inquote) { 86 inquote = 0; 87 continue; 88 } 89 } else { 90 if (c == '\\') { 91 if ((c = *++cp) == '\0') 92 break; 93 } else if (c == '"') { 94 inquote = '"'; 95 continue; 96 } else if (c == '\'') { 97 inquote = '\''; 98 continue; 99 } else if (isspace((unsigned char)c)) 100 break; 101 } 102 *cp2++ = c; 103 } 104 *cp2 = '\0'; 105 if (c == '\0') 106 break; 107 cp++; 108 } 109 *argp++ = 0; 110} 111 112/* 113 * Make a character string into a number. 114 * 115 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 116 */ 117 118static char 119special(char *s) 120{ 121 char c; 122 char b; 123 124 switch (*s) { 125 case '^': 126 b = *++s; 127 if (b == '?') { 128 c = b | 0x40; /* DEL */ 129 } else { 130 c = b & 0x1f; 131 } 132 break; 133 default: 134 c = *s; 135 break; 136 } 137 return c; 138} 139 140/* 141 * Construct a control character sequence 142 * for a special character. 143 */ 144static char * 145control(cc_t c) 146{ 147 static char buf[5]; 148 /* 149 * The only way I could get the Sun 3.5 compiler 150 * to shut up about 151 * if ((unsigned int)c >= 0x80) 152 * was to assign "c" to an unsigned int variable... 153 * Arggg.... 154 */ 155 unsigned int uic = (unsigned int)c; 156 157 if (uic == 0x7f) 158 return ("^?"); 159 if (c == (cc_t)_POSIX_VDISABLE) { 160 return "off"; 161 } 162 if (uic >= 0x80) { 163 buf[0] = '\\'; 164 buf[1] = ((c>>6)&07) + '0'; 165 buf[2] = ((c>>3)&07) + '0'; 166 buf[3] = (c&07) + '0'; 167 buf[4] = 0; 168 } else if (uic >= 0x20) { 169 buf[0] = c; 170 buf[1] = 0; 171 } else { 172 buf[0] = '^'; 173 buf[1] = '@'+c; 174 buf[2] = 0; 175 } 176 return (buf); 177} 178 179 180 181/* 182 * The following are data structures and routines for 183 * the "send" command. 184 * 185 */ 186 187struct sendlist { 188 char *name; /* How user refers to it (case independent) */ 189 char *help; /* Help information (0 ==> no help) */ 190 int needconnect; /* Need to be connected */ 191 int narg; /* Number of arguments */ 192 int (*handler)(); /* Routine to perform (for special ops) */ 193 int nbyte; /* Number of bytes to send this command */ 194 int what; /* Character to be sent (<0 ==> special) */ 195}; 196 197 198static int 199 send_esc (void), 200 send_help (void), 201 send_docmd (char *), 202 send_dontcmd (char *), 203 send_willcmd (char *), 204 send_wontcmd (char *); 205 206static struct sendlist Sendlist[] = { 207 { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, 208 { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, 209 { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, 210 { "break", 0, 1, 0, 0, 2, BREAK }, 211 { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, 212 { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, 213 { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, 214 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, 215 { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, 216 { "intp", 0, 1, 0, 0, 2, IP }, 217 { "interrupt", 0, 1, 0, 0, 2, IP }, 218 { "intr", 0, 1, 0, 0, 2, IP }, 219 { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, 220 { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, 221 { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, 222 { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, 223 { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, 224 { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 }, 225 { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, 226 { "?", "Display send options", 0, 0, send_help, 0, 0 }, 227 { "help", 0, 0, 0, send_help, 0, 0 }, 228 { "do", 0, 0, 1, send_docmd, 3, 0 }, 229 { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, 230 { "will", 0, 0, 1, send_willcmd, 3, 0 }, 231 { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, 232 { 0 } 233}; 234 235#define GETSEND(name) ((struct sendlist *) genget(name, (char **) Sendlist, \ 236 sizeof(struct sendlist))) 237 238static int 239sendcmd(int argc, char **argv) 240{ 241 int count; /* how many bytes we are going to need to send */ 242 int i; 243 struct sendlist *s; /* pointer to current command */ 244 int success = 0; 245 int needconnect = 0; 246 247 if (argc < 2) { 248 printf("need at least one argument for 'send' command\r\n"); 249 printf("'send ?' for help\r\n"); 250 return 0; 251 } 252 /* 253 * First, validate all the send arguments. 254 * In addition, we see how much space we are going to need, and 255 * whether or not we will be doing a "SYNCH" operation (which 256 * flushes the network queue). 257 */ 258 count = 0; 259 for (i = 1; i < argc; i++) { 260 s = GETSEND(argv[i]); 261 if (s == 0) { 262 printf("Unknown send argument '%s'\r\n'send ?' for help.\r\n", 263 argv[i]); 264 return 0; 265 } else if (Ambiguous(s)) { 266 printf("Ambiguous send argument '%s'\r\n'send ?' for help.\r\n", 267 argv[i]); 268 return 0; 269 } 270 if (i + s->narg >= argc) { 271 fprintf(stderr, 272 "Need %d argument%s to 'send %s' command. 'send %s ?' for help.\r\n", 273 s->narg, s->narg == 1 ? "" : "s", s->name, s->name); 274 return 0; 275 } 276 count += s->nbyte; 277 if (s->handler == send_help) { 278 send_help(); 279 return 0; 280 } 281 282 i += s->narg; 283 needconnect += s->needconnect; 284 } 285 if (!connected && needconnect) { 286 printf("?Need to be connected first.\r\n"); 287 printf("'send ?' for help\r\n"); 288 return 0; 289 } 290 /* Now, do we have enough room? */ 291 if (NETROOM() < count) { 292 printf("There is not enough room in the buffer TO the network\r\n"); 293 printf("to process your request. Nothing will be done.\r\n"); 294 printf("('send synch' will throw away most data in the network\r\n"); 295 printf("buffer, if this might help.)\r\n"); 296 return 0; 297 } 298 /* OK, they are all OK, now go through again and actually send */ 299 count = 0; 300 for (i = 1; i < argc; i++) { 301 if ((s = GETSEND(argv[i])) == 0) { 302 fprintf(stderr, "Telnet 'send' error - argument disappeared!\r\n"); 303 quit(); 304 /*NOTREACHED*/ 305 } 306 if (s->handler) { 307 count++; 308 success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, 309 (s->narg > 1) ? argv[i+2] : 0); 310 i += s->narg; 311 } else { 312 NET2ADD(IAC, s->what); 313 printoption("SENT", IAC, s->what); 314 } 315 } 316 return (count == success); 317} 318 319static int 320send_tncmd(void (*func)(), char *cmd, char *name); 321 322static int 323send_esc() 324{ 325 NETADD(escape); 326 return 1; 327} 328 329static int 330send_docmd(char *name) 331{ 332 return(send_tncmd(send_do, "do", name)); 333} 334 335static int 336send_dontcmd(char *name) 337{ 338 return(send_tncmd(send_dont, "dont", name)); 339} 340 341static int 342send_willcmd(char *name) 343{ 344 return(send_tncmd(send_will, "will", name)); 345} 346 347static int 348send_wontcmd(char *name) 349{ 350 return(send_tncmd(send_wont, "wont", name)); 351} 352 353extern char *telopts[]; /* XXX */ 354 355static int 356send_tncmd(void (*func)(), char *cmd, char *name) 357{ 358 char **cpp; 359 int val = 0; 360 361 if (isprefix(name, "help") || isprefix(name, "?")) { 362 int col, len; 363 364 printf("Usage: send %s <value|option>\r\n", cmd); 365 printf("\"value\" must be from 0 to 255\r\n"); 366 printf("Valid options are:\r\n\t"); 367 368 col = 8; 369 for (cpp = telopts; *cpp; cpp++) { 370 len = strlen(*cpp) + 3; 371 if (col + len > 65) { 372 printf("\r\n\t"); 373 col = 8; 374 } 375 printf(" \"%s\"", *cpp); 376 col += len; 377 } 378 printf("\r\n"); 379 return 0; 380 } 381 cpp = genget(name, telopts, sizeof(char *)); 382 if (Ambiguous(cpp)) { 383 fprintf(stderr,"'%s': ambiguous argument ('send %s ?' for help).\r\n", 384 name, cmd); 385 return 0; 386 } 387 if (cpp) { 388 val = cpp - telopts; 389 } else { 390 char *cp = name; 391 392 while (*cp >= '0' && *cp <= '9') { 393 val *= 10; 394 val += *cp - '0'; 395 cp++; 396 } 397 if (*cp != 0) { 398 fprintf(stderr, "'%s': unknown argument ('send %s ?' for help).\r\n", 399 name, cmd); 400 return 0; 401 } else if (val < 0 || val > 255) { 402 fprintf(stderr, "'%s': bad value ('send %s ?' for help).\r\n", 403 name, cmd); 404 return 0; 405 } 406 } 407 if (!connected) { 408 printf("?Need to be connected first.\r\n"); 409 return 0; 410 } 411 (*func)(val, 1); 412 return 1; 413} 414 415static int 416send_help() 417{ 418 struct sendlist *s; /* pointer to current command */ 419 for (s = Sendlist; s->name; s++) { 420 if (s->help) 421 printf("%-15s %s\r\n", s->name, s->help); 422 } 423 return(0); 424} 425 426/* 427 * The following are the routines and data structures referred 428 * to by the arguments to the "toggle" command. 429 */ 430 431static int 432lclchars() 433{ 434 donelclchars = 1; 435 return 1; 436} 437 438static int 439togdebug() 440{ 441#ifndef NOT43 442 if (net > 0 && 443 (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 444 perror("setsockopt (SO_DEBUG)"); 445 } 446#else /* NOT43 */ 447 if (debug) { 448 if (net > 0 && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) 449 perror("setsockopt (SO_DEBUG)"); 450 } else 451 printf("Cannot turn off socket debugging\r\n"); 452#endif /* NOT43 */ 453 return 1; 454} 455 456#if defined(KRB4) && defined(HAVE_KRB_DISABLE_DEBUG) 457#include <krb.h> 458 459static int 460togkrbdebug(void) 461{ 462 if(krb_debug) 463 krb_enable_debug(); 464 else 465 krb_disable_debug(); 466 return 1; 467} 468#endif 469 470static int 471togcrlf() 472{ 473 if (crlf) { 474 printf("Will send carriage returns as telnet <CR><LF>.\r\n"); 475 } else { 476 printf("Will send carriage returns as telnet <CR><NUL>.\r\n"); 477 } 478 return 1; 479} 480 481int binmode; 482 483static int 484togbinary(int val) 485{ 486 donebinarytoggle = 1; 487 488 if (val >= 0) { 489 binmode = val; 490 } else { 491 if (my_want_state_is_will(TELOPT_BINARY) && 492 my_want_state_is_do(TELOPT_BINARY)) { 493 binmode = 1; 494 } else if (my_want_state_is_wont(TELOPT_BINARY) && 495 my_want_state_is_dont(TELOPT_BINARY)) { 496 binmode = 0; 497 } 498 val = binmode ? 0 : 1; 499 } 500 501 if (val == 1) { 502 if (my_want_state_is_will(TELOPT_BINARY) && 503 my_want_state_is_do(TELOPT_BINARY)) { 504 printf("Already operating in binary mode with remote host.\r\n"); 505 } else { 506 printf("Negotiating binary mode with remote host.\r\n"); 507 tel_enter_binary(3); 508 } 509 } else { 510 if (my_want_state_is_wont(TELOPT_BINARY) && 511 my_want_state_is_dont(TELOPT_BINARY)) { 512 printf("Already in network ascii mode with remote host.\r\n"); 513 } else { 514 printf("Negotiating network ascii mode with remote host.\r\n"); 515 tel_leave_binary(3); 516 } 517 } 518 return 1; 519} 520 521static int 522togrbinary(int val) 523{ 524 donebinarytoggle = 1; 525 526 if (val == -1) 527 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; 528 529 if (val == 1) { 530 if (my_want_state_is_do(TELOPT_BINARY)) { 531 printf("Already receiving in binary mode.\r\n"); 532 } else { 533 printf("Negotiating binary mode on input.\r\n"); 534 tel_enter_binary(1); 535 } 536 } else { 537 if (my_want_state_is_dont(TELOPT_BINARY)) { 538 printf("Already receiving in network ascii mode.\r\n"); 539 } else { 540 printf("Negotiating network ascii mode on input.\r\n"); 541 tel_leave_binary(1); 542 } 543 } 544 return 1; 545} 546 547static int 548togxbinary(int val) 549{ 550 donebinarytoggle = 1; 551 552 if (val == -1) 553 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; 554 555 if (val == 1) { 556 if (my_want_state_is_will(TELOPT_BINARY)) { 557 printf("Already transmitting in binary mode.\r\n"); 558 } else { 559 printf("Negotiating binary mode on output.\r\n"); 560 tel_enter_binary(2); 561 } 562 } else { 563 if (my_want_state_is_wont(TELOPT_BINARY)) { 564 printf("Already transmitting in network ascii mode.\r\n"); 565 } else { 566 printf("Negotiating network ascii mode on output.\r\n"); 567 tel_leave_binary(2); 568 } 569 } 570 return 1; 571} 572 573 574static int togglehelp (void); 575#if defined(AUTHENTICATION) 576extern int auth_togdebug (int); 577#endif 578#if defined(ENCRYPTION) 579extern int EncryptAutoEnc (int); 580extern int EncryptAutoDec (int); 581extern int EncryptDebug (int); 582extern int EncryptVerbose (int); 583#endif 584 585struct togglelist { 586 char *name; /* name of toggle */ 587 char *help; /* help message */ 588 int (*handler)(); /* routine to do actual setting */ 589 int *variable; 590 char *actionexplanation; 591}; 592 593static struct togglelist Togglelist[] = { 594 { "autoflush", 595 "flushing of output when sending interrupt characters", 596 0, 597 &autoflush, 598 "flush output when sending interrupt characters" }, 599 { "autosynch", 600 "automatic sending of interrupt characters in urgent mode", 601 0, 602 &autosynch, 603 "send interrupt characters in urgent mode" }, 604#if defined(AUTHENTICATION) 605 { "autologin", 606 "automatic sending of login and/or authentication info", 607 0, 608 &autologin, 609 "send login name and/or authentication information" }, 610 { "authdebug", 611 "authentication debugging", 612 auth_togdebug, 613 0, 614 "print authentication debugging information" }, 615#endif 616#if defined(ENCRYPTION) 617 { "autoencrypt", 618 "automatic encryption of data stream", 619 EncryptAutoEnc, 620 0, 621 "automatically encrypt output" }, 622 { "autodecrypt", 623 "automatic decryption of data stream", 624 EncryptAutoDec, 625 0, 626 "automatically decrypt input" }, 627 { "verbose_encrypt", 628 "verbose encryption output", 629 EncryptVerbose, 630 0, 631 "print verbose encryption output" }, 632 { "encdebug", 633 "encryption debugging", 634 EncryptDebug, 635 0, 636 "print encryption debugging information" }, 637#endif 638#if defined(KRB5) 639 { "forward", 640 "credentials forwarding", 641 kerberos5_set_forward, 642 0, 643 "forward credentials" }, 644 { "forwardable", 645 "forwardable flag of forwarded credentials", 646 kerberos5_set_forwardable, 647 0, 648 "forward forwardable credentials" }, 649#endif 650 { "skiprc", 651 "don't read ~/.telnetrc file", 652 0, 653 &skiprc, 654 "skip reading of ~/.telnetrc file" }, 655 { "binary", 656 "sending and receiving of binary data", 657 togbinary, 658 0, 659 0 }, 660 { "inbinary", 661 "receiving of binary data", 662 togrbinary, 663 0, 664 0 }, 665 { "outbinary", 666 "sending of binary data", 667 togxbinary, 668 0, 669 0 }, 670 { "crlf", 671 "sending carriage returns as telnet <CR><LF>", 672 togcrlf, 673 &crlf, 674 0 }, 675 { "crmod", 676 "mapping of received carriage returns", 677 0, 678 &crmod, 679 "map carriage return on output" }, 680 { "localchars", 681 "local recognition of certain control characters", 682 lclchars, 683 &localchars, 684 "recognize certain control characters" }, 685 { " ", "", 0 }, /* empty line */ 686 { "debug", 687 "debugging", 688 togdebug, 689 &debug, 690 "turn on socket level debugging" }, 691#if defined(KRB4) && defined(HAVE_KRB_DISABLE_DEBUG) 692 { "krb_debug", 693 "kerberos 4 debugging", 694 togkrbdebug, 695 &krb_debug, 696 "turn on kerberos 4 debugging" }, 697#endif 698 { "netdata", 699 "printing of hexadecimal network data (debugging)", 700 0, 701 &netdata, 702 "print hexadecimal representation of network traffic" }, 703 { "prettydump", 704 "output of \"netdata\" to user readable format (debugging)", 705 0, 706 &prettydump, 707 "print user readable output for \"netdata\"" }, 708 { "options", 709 "viewing of options processing (debugging)", 710 0, 711 &showoptions, 712 "show option processing" }, 713 { "termdata", 714 "printing of hexadecimal terminal data (debugging)", 715 0, 716 &termdata, 717 "print hexadecimal representation of terminal traffic" }, 718 { "?", 719 0, 720 togglehelp }, 721 { "help", 722 0, 723 togglehelp }, 724 { 0 } 725}; 726 727static int 728togglehelp() 729{ 730 struct togglelist *c; 731 732 for (c = Togglelist; c->name; c++) { 733 if (c->help) { 734 if (*c->help) 735 printf("%-15s toggle %s\r\n", c->name, c->help); 736 else 737 printf("\r\n"); 738 } 739 } 740 printf("\r\n"); 741 printf("%-15s %s\r\n", "?", "display help information"); 742 return 0; 743} 744 745static void 746settogglehelp(int set) 747{ 748 struct togglelist *c; 749 750 for (c = Togglelist; c->name; c++) { 751 if (c->help) { 752 if (*c->help) 753 printf("%-15s %s %s\r\n", c->name, set ? "enable" : "disable", 754 c->help); 755 else 756 printf("\r\n"); 757 } 758 } 759} 760 761#define GETTOGGLE(name) (struct togglelist *) \ 762 genget(name, (char **) Togglelist, sizeof(struct togglelist)) 763 764static int 765toggle(int argc, char *argv[]) 766{ 767 int retval = 1; 768 char *name; 769 struct togglelist *c; 770 771 if (argc < 2) { 772 fprintf(stderr, 773 "Need an argument to 'toggle' command. 'toggle ?' for help.\r\n"); 774 return 0; 775 } 776 argc--; 777 argv++; 778 while (argc--) { 779 name = *argv++; 780 c = GETTOGGLE(name); 781 if (Ambiguous(c)) { 782 fprintf(stderr, "'%s': ambiguous argument ('toggle ?' for help).\r\n", 783 name); 784 return 0; 785 } else if (c == 0) { 786 fprintf(stderr, "'%s': unknown argument ('toggle ?' for help).\r\n", 787 name); 788 return 0; 789 } else { 790 if (c->variable) { 791 *c->variable = !*c->variable; /* invert it */ 792 if (c->actionexplanation) { 793 printf("%s %s.\r\n", *c->variable? "Will" : "Won't", 794 c->actionexplanation); 795 } 796 } 797 if (c->handler) { 798 retval &= (*c->handler)(-1); 799 } 800 } 801 } 802 return retval; 803} 804 805/* 806 * The following perform the "set" command. 807 */ 808 809struct termios new_tc = { 0 }; 810 811struct setlist { 812 char *name; /* name */ 813 char *help; /* help information */ 814 void (*handler)(); 815 cc_t *charp; /* where it is located at */ 816}; 817 818static struct setlist Setlist[] = { 819#ifdef KLUDGELINEMODE 820 { "echo", "character to toggle local echoing on/off", 0, &echoc }, 821#endif 822 { "escape", "character to escape back to telnet command mode", 0, &escape }, 823 { "rlogin", "rlogin escape character", 0, &rlogin }, 824 { "tracefile", "file to write trace information to", SetNetTrace, (cc_t *)NetTraceFile}, 825 { " ", "" }, 826 { " ", "The following need 'localchars' to be toggled true", 0, 0 }, 827 { "flushoutput", "character to cause an Abort Output", 0, &termFlushChar }, 828 { "interrupt", "character to cause an Interrupt Process", 0, &termIntChar }, 829 { "quit", "character to cause an Abort process", 0, &termQuitChar }, 830 { "eof", "character to cause an EOF ", 0, &termEofChar }, 831 { " ", "" }, 832 { " ", "The following are for local editing in linemode", 0, 0 }, 833 { "erase", "character to use to erase a character", 0, &termEraseChar }, 834 { "kill", "character to use to erase a line", 0, &termKillChar }, 835 { "lnext", "character to use for literal next", 0, &termLiteralNextChar }, 836 { "susp", "character to cause a Suspend Process", 0, &termSuspChar }, 837 { "reprint", "character to use for line reprint", 0, &termRprntChar }, 838 { "worderase", "character to use to erase a word", 0, &termWerasChar }, 839 { "start", "character to use for XON", 0, &termStartChar }, 840 { "stop", "character to use for XOFF", 0, &termStopChar }, 841 { "forw1", "alternate end of line character", 0, &termForw1Char }, 842 { "forw2", "alternate end of line character", 0, &termForw2Char }, 843 { "ayt", "alternate AYT character", 0, &termAytChar }, 844 { 0 } 845}; 846 847static struct setlist * 848getset(char *name) 849{ 850 return (struct setlist *) 851 genget(name, (char **) Setlist, sizeof(struct setlist)); 852} 853 854void 855set_escape_char(char *s) 856{ 857 if (rlogin != _POSIX_VDISABLE) { 858 rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; 859 printf("Telnet rlogin escape character is '%s'.\r\n", 860 control(rlogin)); 861 } else { 862 escape = (s && *s) ? special(s) : _POSIX_VDISABLE; 863 printf("Telnet escape character is '%s'.\r\n", control(escape)); 864 } 865} 866 867static int 868setcmd(int argc, char *argv[]) 869{ 870 int value; 871 struct setlist *ct; 872 struct togglelist *c; 873 874 if (argc < 2 || argc > 3) { 875 printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n"); 876 return 0; 877 } 878 if ((argc == 2) && (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) { 879 for (ct = Setlist; ct->name; ct++) 880 printf("%-15s %s\r\n", ct->name, ct->help); 881 printf("\r\n"); 882 settogglehelp(1); 883 printf("%-15s %s\r\n", "?", "display help information"); 884 return 0; 885 } 886 887 ct = getset(argv[1]); 888 if (ct == 0) { 889 c = GETTOGGLE(argv[1]); 890 if (c == 0) { 891 fprintf(stderr, "'%s': unknown argument ('set ?' for help).\r\n", 892 argv[1]); 893 return 0; 894 } else if (Ambiguous(c)) { 895 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n", 896 argv[1]); 897 return 0; 898 } 899 if (c->variable) { 900 if ((argc == 2) || (strcmp("on", argv[2]) == 0)) 901 *c->variable = 1; 902 else if (strcmp("off", argv[2]) == 0) 903 *c->variable = 0; 904 else { 905 printf("Format is 'set togglename [on|off]'\r\n'set ?' for help.\r\n"); 906 return 0; 907 } 908 if (c->actionexplanation) { 909 printf("%s %s.\r\n", *c->variable? "Will" : "Won't", 910 c->actionexplanation); 911 } 912 } 913 if (c->handler) 914 (*c->handler)(1); 915 } else if (argc != 3) { 916 printf("Format is 'set Name Value'\r\n'set ?' for help.\r\n"); 917 return 0; 918 } else if (Ambiguous(ct)) { 919 fprintf(stderr, "'%s': ambiguous argument ('set ?' for help).\r\n", 920 argv[1]); 921 return 0; 922 } else if (ct->handler) { 923 (*ct->handler)(argv[2]); 924 printf("%s set to \"%s\".\r\n", ct->name, (char *)ct->charp); 925 } else { 926 if (strcmp("off", argv[2])) { 927 value = special(argv[2]); 928 } else { 929 value = _POSIX_VDISABLE; 930 } 931 *(ct->charp) = (cc_t)value; 932 printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp))); 933 } 934 slc_check(); 935 return 1; 936} 937 938static int 939unsetcmd(int argc, char *argv[]) 940{ 941 struct setlist *ct; 942 struct togglelist *c; 943 char *name; 944 945 if (argc < 2) { 946 fprintf(stderr, 947 "Need an argument to 'unset' command. 'unset ?' for help.\r\n"); 948 return 0; 949 } 950 if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) { 951 for (ct = Setlist; ct->name; ct++) 952 printf("%-15s %s\r\n", ct->name, ct->help); 953 printf("\r\n"); 954 settogglehelp(0); 955 printf("%-15s %s\r\n", "?", "display help information"); 956 return 0; 957 } 958 959 argc--; 960 argv++; 961 while (argc--) { 962 name = *argv++; 963 ct = getset(name); 964 if (ct == 0) { 965 c = GETTOGGLE(name); 966 if (c == 0) { 967 fprintf(stderr, "'%s': unknown argument ('unset ?' for help).\r\n", 968 name); 969 return 0; 970 } else if (Ambiguous(c)) { 971 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n", 972 name); 973 return 0; 974 } 975 if (c->variable) { 976 *c->variable = 0; 977 if (c->actionexplanation) { 978 printf("%s %s.\r\n", *c->variable? "Will" : "Won't", 979 c->actionexplanation); 980 } 981 } 982 if (c->handler) 983 (*c->handler)(0); 984 } else if (Ambiguous(ct)) { 985 fprintf(stderr, "'%s': ambiguous argument ('unset ?' for help).\r\n", 986 name); 987 return 0; 988 } else if (ct->handler) { 989 (*ct->handler)(0); 990 printf("%s reset to \"%s\".\r\n", ct->name, (char *)ct->charp); 991 } else { 992 *(ct->charp) = _POSIX_VDISABLE; 993 printf("%s character is '%s'.\r\n", ct->name, control(*(ct->charp))); 994 } 995 } 996 return 1; 997} 998 999/* 1000 * The following are the data structures and routines for the 1001 * 'mode' command. 1002 */ 1003#ifdef KLUDGELINEMODE 1004 1005static int 1006dokludgemode(void) 1007{ 1008 kludgelinemode = 1; 1009 send_wont(TELOPT_LINEMODE, 1); 1010 send_dont(TELOPT_SGA, 1); 1011 send_dont(TELOPT_ECHO, 1); 1012 return 1; 1013} 1014#endif 1015 1016static int 1017dolinemode() 1018{ 1019#ifdef KLUDGELINEMODE 1020 if (kludgelinemode) 1021 send_dont(TELOPT_SGA, 1); 1022#endif 1023 send_will(TELOPT_LINEMODE, 1); 1024 send_dont(TELOPT_ECHO, 1); 1025 return 1; 1026} 1027 1028static int 1029docharmode() 1030{ 1031#ifdef KLUDGELINEMODE 1032 if (kludgelinemode) 1033 send_do(TELOPT_SGA, 1); 1034 else 1035#endif 1036 send_wont(TELOPT_LINEMODE, 1); 1037 send_do(TELOPT_ECHO, 1); 1038 return 1; 1039} 1040 1041static int 1042dolmmode(int bit, int on) 1043{ 1044 unsigned char c; 1045 1046 if (my_want_state_is_wont(TELOPT_LINEMODE)) { 1047 printf("?Need to have LINEMODE option enabled first.\r\n"); 1048 printf("'mode ?' for help.\r\n"); 1049 return 0; 1050 } 1051 1052 if (on) 1053 c = (linemode | bit); 1054 else 1055 c = (linemode & ~bit); 1056 lm_mode(&c, 1, 1); 1057 return 1; 1058} 1059 1060static int 1061tn_setmode(int bit) 1062{ 1063 return dolmmode(bit, 1); 1064} 1065 1066static int 1067tn_clearmode(int bit) 1068{ 1069 return dolmmode(bit, 0); 1070} 1071 1072struct modelist { 1073 char *name; /* command name */ 1074 char *help; /* help string */ 1075 int (*handler)(); /* routine which executes command */ 1076 int needconnect; /* Do we need to be connected to execute? */ 1077 int arg1; 1078}; 1079 1080static int modehelp(void); 1081 1082static struct modelist ModeList[] = { 1083 { "character", "Disable LINEMODE option", docharmode, 1 }, 1084#ifdef KLUDGELINEMODE 1085 { "", "(or disable obsolete line-by-line mode)", 0 }, 1086#endif 1087 { "line", "Enable LINEMODE option", dolinemode, 1 }, 1088#ifdef KLUDGELINEMODE 1089 { "", "(or enable obsolete line-by-line mode)", 0 }, 1090#endif 1091 { "", "", 0 }, 1092 { "", "These require the LINEMODE option to be enabled", 0 }, 1093 { "isig", "Enable signal trapping", tn_setmode, 1, MODE_TRAPSIG }, 1094 { "+isig", 0, tn_setmode, 1, MODE_TRAPSIG }, 1095 { "-isig", "Disable signal trapping", tn_clearmode, 1, MODE_TRAPSIG }, 1096 { "edit", "Enable character editing", tn_setmode, 1, MODE_EDIT }, 1097 { "+edit", 0, tn_setmode, 1, MODE_EDIT }, 1098 { "-edit", "Disable character editing", tn_clearmode, 1, MODE_EDIT }, 1099 { "softtabs", "Enable tab expansion", tn_setmode, 1, MODE_SOFT_TAB }, 1100 { "+softtabs", 0, tn_setmode, 1, MODE_SOFT_TAB }, 1101 { "-softtabs", "Disable tab expansion", tn_clearmode, 1, MODE_SOFT_TAB }, 1102 { "litecho", "Enable literal character echo", tn_setmode, 1, MODE_LIT_ECHO }, 1103 { "+litecho", 0, tn_setmode, 1, MODE_LIT_ECHO }, 1104 { "-litecho", "Disable literal character echo", tn_clearmode, 1, MODE_LIT_ECHO }, 1105 { "help", 0, modehelp, 0 }, 1106#ifdef KLUDGELINEMODE 1107 { "kludgeline", 0, dokludgemode, 1 }, 1108#endif 1109 { "", "", 0 }, 1110 { "?", "Print help information", modehelp, 0 }, 1111 { 0 }, 1112}; 1113 1114 1115static int 1116modehelp(void) 1117{ 1118 struct modelist *mt; 1119 1120 printf("format is: 'mode Mode', where 'Mode' is one of:\r\n\r\n"); 1121 for (mt = ModeList; mt->name; mt++) { 1122 if (mt->help) { 1123 if (*mt->help) 1124 printf("%-15s %s\r\n", mt->name, mt->help); 1125 else 1126 printf("\r\n"); 1127 } 1128 } 1129 return 0; 1130} 1131 1132#define GETMODECMD(name) (struct modelist *) \ 1133 genget(name, (char **) ModeList, sizeof(struct modelist)) 1134 1135static int 1136modecmd(int argc, char **argv) 1137{ 1138 struct modelist *mt; 1139 1140 if (argc != 2) { 1141 printf("'mode' command requires an argument\r\n"); 1142 printf("'mode ?' for help.\r\n"); 1143 } else if ((mt = GETMODECMD(argv[1])) == 0) { 1144 fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\r\n", argv[1]); 1145 } else if (Ambiguous(mt)) { 1146 fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\r\n", argv[1]); 1147 } else if (mt->needconnect && !connected) { 1148 printf("?Need to be connected first.\r\n"); 1149 printf("'mode ?' for help.\r\n"); 1150 } else if (mt->handler) { 1151 return (*mt->handler)(mt->arg1); 1152 } 1153 return 0; 1154} 1155 1156/* 1157 * The following data structures and routines implement the 1158 * "display" command. 1159 */ 1160 1161static int 1162display(int argc, char *argv[]) 1163{ 1164 struct togglelist *tl; 1165 struct setlist *sl; 1166 1167#define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 1168 if (*tl->variable) { \ 1169 printf("will"); \ 1170 } else { \ 1171 printf("won't"); \ 1172 } \ 1173 printf(" %s.\r\n", tl->actionexplanation); \ 1174 } 1175 1176#define doset(sl) if (sl->name && *sl->name != ' ') { \ 1177 if (sl->handler == 0) \ 1178 printf("%-15s [%s]\r\n", sl->name, control(*sl->charp)); \ 1179 else \ 1180 printf("%-15s \"%s\"\r\n", sl->name, (char *)sl->charp); \ 1181 } 1182 1183 if (argc == 1) { 1184 for (tl = Togglelist; tl->name; tl++) { 1185 dotog(tl); 1186 } 1187 printf("\r\n"); 1188 for (sl = Setlist; sl->name; sl++) { 1189 doset(sl); 1190 } 1191 } else { 1192 int i; 1193 1194 for (i = 1; i < argc; i++) { 1195 sl = getset(argv[i]); 1196 tl = GETTOGGLE(argv[i]); 1197 if (Ambiguous(sl) || Ambiguous(tl)) { 1198 printf("?Ambiguous argument '%s'.\r\n", argv[i]); 1199 return 0; 1200 } else if (!sl && !tl) { 1201 printf("?Unknown argument '%s'.\r\n", argv[i]); 1202 return 0; 1203 } else { 1204 if (tl) { 1205 dotog(tl); 1206 } 1207 if (sl) { 1208 doset(sl); 1209 } 1210 } 1211 } 1212 } 1213/*@*/optionstatus(); 1214#if defined(ENCRYPTION) 1215 EncryptStatus(); 1216#endif 1217 return 1; 1218#undef doset 1219#undef dotog 1220} 1221 1222/* 1223 * The following are the data structures, and many of the routines, 1224 * relating to command processing. 1225 */ 1226 1227/* 1228 * Set the escape character. 1229 */ 1230static int 1231setescape(int argc, char *argv[]) 1232{ 1233 char *arg; 1234 char buf[50]; 1235 1236 printf( 1237 "Deprecated usage - please use 'set escape%s%s' in the future.\r\n", 1238 (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 1239 if (argc > 2) 1240 arg = argv[1]; 1241 else { 1242 printf("new escape character: "); 1243 fgets(buf, sizeof(buf), stdin); 1244 arg = buf; 1245 } 1246 if (arg[0] != '\0') 1247 escape = arg[0]; 1248 printf("Escape character is '%s'.\r\n", control(escape)); 1249 1250 fflush(stdout); 1251 return 1; 1252} 1253 1254static int 1255togcrmod() 1256{ 1257 crmod = !crmod; 1258 printf("Deprecated usage - please use 'toggle crmod' in the future.\r\n"); 1259 printf("%s map carriage return on output.\r\n", crmod ? "Will" : "Won't"); 1260 fflush(stdout); 1261 return 1; 1262} 1263 1264static int 1265telnetsuspend() 1266{ 1267#ifdef SIGTSTP 1268 setcommandmode(); 1269 { 1270 long oldrows, oldcols, newrows, newcols, err; 1271 1272 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1273 kill(0, SIGTSTP); 1274 /* 1275 * If we didn't get the window size before the SUSPEND, but we 1276 * can get them now (?), then send the NAWS to make sure that 1277 * we are set up for the right window size. 1278 */ 1279 if (TerminalWindowSize(&newrows, &newcols) && connected && 1280 (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1281 sendnaws(); 1282 } 1283 } 1284 /* reget parameters in case they were changed */ 1285 TerminalSaveState(); 1286 setconnmode(0); 1287#else 1288 printf("Suspend is not supported. Try the '!' command instead\r\n"); 1289#endif 1290 return 1; 1291} 1292 1293static int 1294shell(int argc, char **argv) 1295{ 1296 long oldrows, oldcols, newrows, newcols, err; 1297 1298 setcommandmode(); 1299 1300 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1301 switch(fork()) { 1302 case -1: 1303 perror("Fork failed\r\n"); 1304 break; 1305 1306 case 0: 1307 { 1308 /* 1309 * Fire up the shell in the child. 1310 */ 1311 char *shellp, *shellname; 1312 1313 shellp = getenv("SHELL"); 1314 if (shellp == NULL) 1315 shellp = "/bin/sh"; 1316 if ((shellname = strrchr(shellp, '/')) == 0) 1317 shellname = shellp; 1318 else 1319 shellname++; 1320 if (argc > 1) 1321 execl(shellp, shellname, "-c", &saveline[1], NULL); 1322 else 1323 execl(shellp, shellname, NULL); 1324 perror("Execl"); 1325 _exit(1); 1326 } 1327 default: 1328 wait((int *)0); /* Wait for the shell to complete */ 1329 1330 if (TerminalWindowSize(&newrows, &newcols) && connected && 1331 (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1332 sendnaws(); 1333 } 1334 break; 1335 } 1336 return 1; 1337} 1338 1339static int 1340bye(int argc, char **argv) 1341{ 1342 if (connected) { 1343 shutdown(net, 2); 1344 printf("Connection closed.\r\n"); 1345 NetClose(net); 1346 connected = 0; 1347 resettermname = 1; 1348#if defined(AUTHENTICATION) || defined(ENCRYPTION) 1349 auth_encrypt_connect(connected); 1350#endif 1351 /* reset options */ 1352 tninit(); 1353 } 1354 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) 1355 longjmp(toplevel, 1); 1356 return 0; /* NOTREACHED */ 1357} 1358 1359int 1360quit(void) 1361{ 1362 call(bye, "bye", "fromquit", 0); 1363 Exit(0); 1364 return 0; /*NOTREACHED*/ 1365} 1366 1367static int 1368logout() 1369{ 1370 send_do(TELOPT_LOGOUT, 1); 1371 netflush(); 1372 return 1; 1373} 1374 1375 1376/* 1377 * The SLC command. 1378 */ 1379 1380struct slclist { 1381 char *name; 1382 char *help; 1383 void (*handler)(); 1384 int arg; 1385}; 1386 1387static void slc_help(void); 1388 1389struct slclist SlcList[] = { 1390 { "export", "Use local special character definitions", 1391 slc_mode_export, 0 }, 1392 { "import", "Use remote special character definitions", 1393 slc_mode_import, 1 }, 1394 { "check", "Verify remote special character definitions", 1395 slc_mode_import, 0 }, 1396 { "help", 0, slc_help, 0 }, 1397 { "?", "Print help information", slc_help, 0 }, 1398 { 0 }, 1399}; 1400 1401static void 1402slc_help(void) 1403{ 1404 struct slclist *c; 1405 1406 for (c = SlcList; c->name; c++) { 1407 if (c->help) { 1408 if (*c->help) 1409 printf("%-15s %s\r\n", c->name, c->help); 1410 else 1411 printf("\r\n"); 1412 } 1413 } 1414} 1415 1416static struct slclist * 1417getslc(char *name) 1418{ 1419 return (struct slclist *) 1420 genget(name, (char **) SlcList, sizeof(struct slclist)); 1421} 1422 1423static int 1424slccmd(int argc, char **argv) 1425{ 1426 struct slclist *c; 1427 1428 if (argc != 2) { 1429 fprintf(stderr, 1430 "Need an argument to 'slc' command. 'slc ?' for help.\r\n"); 1431 return 0; 1432 } 1433 c = getslc(argv[1]); 1434 if (c == 0) { 1435 fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\r\n", 1436 argv[1]); 1437 return 0; 1438 } 1439 if (Ambiguous(c)) { 1440 fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\r\n", 1441 argv[1]); 1442 return 0; 1443 } 1444 (*c->handler)(c->arg); 1445 slcstate(); 1446 return 1; 1447} 1448 1449/* 1450 * The ENVIRON command. 1451 */ 1452 1453struct envlist { 1454 char *name; 1455 char *help; 1456 void (*handler)(); 1457 int narg; 1458}; 1459 1460static void env_help (void); 1461 1462struct envlist EnvList[] = { 1463 { "define", "Define an environment variable", 1464 (void (*)())env_define, 2 }, 1465 { "undefine", "Undefine an environment variable", 1466 env_undefine, 1 }, 1467 { "export", "Mark an environment variable for automatic export", 1468 env_export, 1 }, 1469 { "unexport", "Don't mark an environment variable for automatic export", 1470 env_unexport, 1 }, 1471 { "send", "Send an environment variable", env_send, 1 }, 1472 { "list", "List the current environment variables", 1473 env_list, 0 }, 1474 { "help", 0, env_help, 0 }, 1475 { "?", "Print help information", env_help, 0 }, 1476 { 0 }, 1477}; 1478 1479static void 1480env_help() 1481{ 1482 struct envlist *c; 1483 1484 for (c = EnvList; c->name; c++) { 1485 if (c->help) { 1486 if (*c->help) 1487 printf("%-15s %s\r\n", c->name, c->help); 1488 else 1489 printf("\r\n"); 1490 } 1491 } 1492} 1493 1494static struct envlist * 1495getenvcmd(char *name) 1496{ 1497 return (struct envlist *) 1498 genget(name, (char **) EnvList, sizeof(struct envlist)); 1499} 1500 1501static int 1502env_cmd(int argc, char **argv) 1503{ 1504 struct envlist *c; 1505 1506 if (argc < 2) { 1507 fprintf(stderr, 1508 "Need an argument to 'environ' command. 'environ ?' for help.\r\n"); 1509 return 0; 1510 } 1511 c = getenvcmd(argv[1]); 1512 if (c == 0) { 1513 fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\r\n", 1514 argv[1]); 1515 return 0; 1516 } 1517 if (Ambiguous(c)) { 1518 fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\r\n", 1519 argv[1]); 1520 return 0; 1521 } 1522 if (c->narg + 2 != argc) { 1523 fprintf(stderr, 1524 "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\r\n", 1525 c->narg < argc + 2 ? "only " : "", 1526 c->narg, c->narg == 1 ? "" : "s", c->name); 1527 return 0; 1528 } 1529 (*c->handler)(argv[2], argv[3]); 1530 return 1; 1531} 1532 1533struct env_lst { 1534 struct env_lst *next; /* pointer to next structure */ 1535 struct env_lst *prev; /* pointer to previous structure */ 1536 unsigned char *var; /* pointer to variable name */ 1537 unsigned char *value; /* pointer to variable value */ 1538 int export; /* 1 -> export with default list of variables */ 1539 int welldefined; /* A well defined variable */ 1540}; 1541 1542struct env_lst envlisthead; 1543 1544struct env_lst * 1545env_find(unsigned char *var) 1546{ 1547 struct env_lst *ep; 1548 1549 for (ep = envlisthead.next; ep; ep = ep->next) { 1550 if (strcmp((char *)ep->var, (char *)var) == 0) 1551 return(ep); 1552 } 1553 return(NULL); 1554} 1555 1556#ifdef IRIX4 1557#define environ _environ 1558#endif 1559 1560void 1561env_init(void) 1562{ 1563 char **epp, *cp; 1564 struct env_lst *ep; 1565 1566 for (epp = environ; *epp; epp++) { 1567 if ((cp = strchr(*epp, '='))) { 1568 *cp = '\0'; 1569 ep = env_define((unsigned char *)*epp, 1570 (unsigned char *)cp+1); 1571 ep->export = 0; 1572 *cp = '='; 1573 } 1574 } 1575 /* 1576 * Special case for DISPLAY variable. If it is ":0.0" or 1577 * "unix:0.0", we have to get rid of "unix" and insert our 1578 * hostname. 1579 */ 1580 if ((ep = env_find((unsigned char*)"DISPLAY")) 1581 && (*ep->value == ':' 1582 || strncmp((char *)ep->value, "unix:", 5) == 0)) { 1583 char hbuf[256+1]; 1584 char *cp2 = strchr((char *)ep->value, ':'); 1585 int error; 1586 1587 /* XXX - should be k_gethostname? */ 1588 gethostname(hbuf, 256); 1589 hbuf[256] = '\0'; 1590 1591 /* If this is not the full name, try to get it via DNS */ 1592 if (strchr(hbuf, '.') == 0) { 1593 struct addrinfo hints, *ai, *a; 1594 1595 memset (&hints, 0, sizeof(hints)); 1596 hints.ai_flags = AI_CANONNAME; 1597 1598 error = getaddrinfo (hbuf, NULL, &hints, &ai); 1599 if (error == 0) { 1600 for (a = ai; a != NULL; a = a->ai_next) 1601 if (a->ai_canonname != NULL) { 1602 strlcpy (hbuf, 1603 ai->ai_canonname, 1604 256); 1605 break; 1606 } 1607 freeaddrinfo (ai); 1608 } 1609 } 1610 1611 error = asprintf (&cp, "%s%s", hbuf, cp2); 1612 if (error != -1) { 1613 free (ep->value); 1614 ep->value = (unsigned char *)cp; 1615 } 1616 } 1617 /* 1618 * If USER is not defined, but LOGNAME is, then add 1619 * USER with the value from LOGNAME. By default, we 1620 * don't export the USER variable. 1621 */ 1622 if ((env_find((unsigned char*)"USER") == NULL) && 1623 (ep = env_find((unsigned char*)"LOGNAME"))) { 1624 env_define((unsigned char *)"USER", ep->value); 1625 env_unexport((unsigned char *)"USER"); 1626 } 1627 env_export((unsigned char *)"DISPLAY"); 1628 env_export((unsigned char *)"PRINTER"); 1629 env_export((unsigned char *)"XAUTHORITY"); 1630} 1631 1632struct env_lst * 1633env_define(unsigned char *var, unsigned char *value) 1634{ 1635 struct env_lst *ep; 1636 1637 if ((ep = env_find(var))) { 1638 if (ep->var) 1639 free(ep->var); 1640 if (ep->value) 1641 free(ep->value); 1642 } else { 1643 ep = (struct env_lst *)malloc(sizeof(struct env_lst)); 1644 ep->next = envlisthead.next; 1645 envlisthead.next = ep; 1646 ep->prev = &envlisthead; 1647 if (ep->next) 1648 ep->next->prev = ep; 1649 } 1650 ep->welldefined = opt_welldefined((char *)var); 1651 ep->export = 1; 1652 ep->var = (unsigned char *)strdup((char *)var); 1653 ep->value = (unsigned char *)strdup((char *)value); 1654 return(ep); 1655} 1656 1657void 1658env_undefine(unsigned char *var) 1659{ 1660 struct env_lst *ep; 1661 1662 if ((ep = env_find(var))) { 1663 ep->prev->next = ep->next; 1664 if (ep->next) 1665 ep->next->prev = ep->prev; 1666 if (ep->var) 1667 free(ep->var); 1668 if (ep->value) 1669 free(ep->value); 1670 free(ep); 1671 } 1672} 1673 1674void 1675env_export(unsigned char *var) 1676{ 1677 struct env_lst *ep; 1678 1679 if ((ep = env_find(var))) 1680 ep->export = 1; 1681} 1682 1683void 1684env_unexport(unsigned char *var) 1685{ 1686 struct env_lst *ep; 1687 1688 if ((ep = env_find(var))) 1689 ep->export = 0; 1690} 1691 1692void 1693env_send(unsigned char *var) 1694{ 1695 struct env_lst *ep; 1696 1697 if (my_state_is_wont(TELOPT_NEW_ENVIRON) 1698#ifdef OLD_ENVIRON 1699 && my_state_is_wont(TELOPT_OLD_ENVIRON) 1700#endif 1701 ) { 1702 fprintf(stderr, 1703 "Cannot send '%s': Telnet ENVIRON option not enabled\r\n", 1704 var); 1705 return; 1706 } 1707 ep = env_find(var); 1708 if (ep == 0) { 1709 fprintf(stderr, "Cannot send '%s': variable not defined\r\n", 1710 var); 1711 return; 1712 } 1713 env_opt_start_info(); 1714 env_opt_add(ep->var); 1715 env_opt_end(0); 1716} 1717 1718void 1719env_list(void) 1720{ 1721 struct env_lst *ep; 1722 1723 for (ep = envlisthead.next; ep; ep = ep->next) { 1724 printf("%c %-20s %s\r\n", ep->export ? '*' : ' ', 1725 ep->var, ep->value); 1726 } 1727} 1728 1729unsigned char * 1730env_default(int init, int welldefined) 1731{ 1732 static struct env_lst *nep = NULL; 1733 1734 if (init) { 1735 nep = &envlisthead; 1736 return NULL; 1737 } 1738 if (nep) { 1739 while ((nep = nep->next)) { 1740 if (nep->export && (nep->welldefined == welldefined)) 1741 return(nep->var); 1742 } 1743 } 1744 return(NULL); 1745} 1746 1747unsigned char * 1748env_getvalue(unsigned char *var) 1749{ 1750 struct env_lst *ep; 1751 1752 if ((ep = env_find(var))) 1753 return(ep->value); 1754 return(NULL); 1755} 1756 1757 1758#if defined(AUTHENTICATION) 1759/* 1760 * The AUTHENTICATE command. 1761 */ 1762 1763struct authlist { 1764 char *name; 1765 char *help; 1766 int (*handler)(); 1767 int narg; 1768}; 1769 1770static int 1771 auth_help (void); 1772 1773struct authlist AuthList[] = { 1774 { "status", "Display current status of authentication information", 1775 auth_status, 0 }, 1776 { "disable", "Disable an authentication type ('auth disable ?' for more)", 1777 auth_disable, 1 }, 1778 { "enable", "Enable an authentication type ('auth enable ?' for more)", 1779 auth_enable, 1 }, 1780 { "help", 0, auth_help, 0 }, 1781 { "?", "Print help information", auth_help, 0 }, 1782 { 0 }, 1783}; 1784 1785static int 1786auth_help() 1787{ 1788 struct authlist *c; 1789 1790 for (c = AuthList; c->name; c++) { 1791 if (c->help) { 1792 if (*c->help) 1793 printf("%-15s %s\r\n", c->name, c->help); 1794 else 1795 printf("\r\n"); 1796 } 1797 } 1798 return 0; 1799} 1800 1801static int 1802auth_cmd(int argc, char **argv) 1803{ 1804 struct authlist *c; 1805 1806 if (argc < 2) { 1807 fprintf(stderr, 1808 "Need an argument to 'auth' command. 'auth ?' for help.\r\n"); 1809 return 0; 1810 } 1811 1812 c = (struct authlist *) 1813 genget(argv[1], (char **) AuthList, sizeof(struct authlist)); 1814 if (c == 0) { 1815 fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\r\n", 1816 argv[1]); 1817 return 0; 1818 } 1819 if (Ambiguous(c)) { 1820 fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\r\n", 1821 argv[1]); 1822 return 0; 1823 } 1824 if (c->narg + 2 != argc) { 1825 fprintf(stderr, 1826 "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\r\n", 1827 c->narg < argc + 2 ? "only " : "", 1828 c->narg, c->narg == 1 ? "" : "s", c->name); 1829 return 0; 1830 } 1831 return((*c->handler)(argv[2], argv[3])); 1832} 1833#endif 1834 1835 1836#if defined(ENCRYPTION) 1837/* 1838 * The ENCRYPT command. 1839 */ 1840 1841struct encryptlist { 1842 char *name; 1843 char *help; 1844 int (*handler)(); 1845 int needconnect; 1846 int minarg; 1847 int maxarg; 1848}; 1849 1850static int 1851 EncryptHelp (void); 1852 1853struct encryptlist EncryptList[] = { 1854 { "enable", "Enable encryption. ('encrypt enable ?' for more)", 1855 EncryptEnable, 1, 1, 2 }, 1856 { "disable", "Disable encryption. ('encrypt enable ?' for more)", 1857 EncryptDisable, 0, 1, 2 }, 1858 { "type", "Set encryptiong type. ('encrypt type ?' for more)", 1859 EncryptType, 0, 1, 1 }, 1860 { "start", "Start encryption. ('encrypt start ?' for more)", 1861 EncryptStart, 1, 0, 1 }, 1862 { "stop", "Stop encryption. ('encrypt stop ?' for more)", 1863 EncryptStop, 1, 0, 1 }, 1864 { "input", "Start encrypting the input stream", 1865 EncryptStartInput, 1, 0, 0 }, 1866 { "-input", "Stop encrypting the input stream", 1867 EncryptStopInput, 1, 0, 0 }, 1868 { "output", "Start encrypting the output stream", 1869 EncryptStartOutput, 1, 0, 0 }, 1870 { "-output", "Stop encrypting the output stream", 1871 EncryptStopOutput, 1, 0, 0 }, 1872 1873 { "status", "Display current status of authentication information", 1874 EncryptStatus, 0, 0, 0 }, 1875 { "help", 0, EncryptHelp, 0, 0, 0 }, 1876 { "?", "Print help information", EncryptHelp, 0, 0, 0 }, 1877 { 0 }, 1878}; 1879 1880static int 1881EncryptHelp() 1882{ 1883 struct encryptlist *c; 1884 1885 for (c = EncryptList; c->name; c++) { 1886 if (c->help) { 1887 if (*c->help) 1888 printf("%-15s %s\r\n", c->name, c->help); 1889 else 1890 printf("\r\n"); 1891 } 1892 } 1893 return 0; 1894} 1895 1896static int 1897encrypt_cmd(int argc, char **argv) 1898{ 1899 struct encryptlist *c; 1900 1901 c = (struct encryptlist *) 1902 genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist)); 1903 if (c == 0) { 1904 fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\r\n", 1905 argv[1]); 1906 return 0; 1907 } 1908 if (Ambiguous(c)) { 1909 fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\r\n", 1910 argv[1]); 1911 return 0; 1912 } 1913 argc -= 2; 1914 if (argc < c->minarg || argc > c->maxarg) { 1915 if (c->minarg == c->maxarg) { 1916 fprintf(stderr, "Need %s%d argument%s ", 1917 c->minarg < argc ? "only " : "", c->minarg, 1918 c->minarg == 1 ? "" : "s"); 1919 } else { 1920 fprintf(stderr, "Need %s%d-%d arguments ", 1921 c->maxarg < argc ? "only " : "", c->minarg, c->maxarg); 1922 } 1923 fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\r\n", 1924 c->name); 1925 return 0; 1926 } 1927 if (c->needconnect && !connected) { 1928 if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) { 1929 printf("?Need to be connected first.\r\n"); 1930 return 0; 1931 } 1932 } 1933 return ((*c->handler)(argc > 0 ? argv[2] : 0, 1934 argc > 1 ? argv[3] : 0, 1935 argc > 2 ? argv[4] : 0)); 1936} 1937#endif 1938 1939 1940/* 1941 * Print status about the connection. 1942 */ 1943 1944static int 1945status(int argc, char **argv) 1946{ 1947 if (connected) { 1948 printf("Connected to %s.\r\n", hostname); 1949 if ((argc < 2) || strcmp(argv[1], "notmuch")) { 1950 int mode = getconnmode(); 1951 1952 if (my_want_state_is_will(TELOPT_LINEMODE)) { 1953 printf("Operating with LINEMODE option\r\n"); 1954 printf("%s line editing\r\n", (mode&MODE_EDIT) ? "Local" : "No"); 1955 printf("%s catching of signals\r\n", 1956 (mode&MODE_TRAPSIG) ? "Local" : "No"); 1957 slcstate(); 1958#ifdef KLUDGELINEMODE 1959 } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { 1960 printf("Operating in obsolete linemode\r\n"); 1961#endif 1962 } else { 1963 printf("Operating in single character mode\r\n"); 1964 if (localchars) 1965 printf("Catching signals locally\r\n"); 1966 } 1967 printf("%s character echo\r\n", (mode&MODE_ECHO) ? "Local" : "Remote"); 1968 if (my_want_state_is_will(TELOPT_LFLOW)) 1969 printf("%s flow control\r\n", (mode&MODE_FLOW) ? "Local" : "No"); 1970#if defined(ENCRYPTION) 1971 encrypt_display(); 1972#endif 1973 } 1974 } else { 1975 printf("No connection.\r\n"); 1976 } 1977 printf("Escape character is '%s'.\r\n", control(escape)); 1978 fflush(stdout); 1979 return 1; 1980} 1981 1982#ifdef SIGINFO 1983/* 1984 * Function that gets called when SIGINFO is received. 1985 */ 1986RETSIGTYPE 1987ayt_status(int ignore) 1988{ 1989 call(status, "status", "notmuch", 0); 1990} 1991#endif 1992 1993static Command *getcmd(char *name); 1994 1995static void 1996cmdrc(char *m1, char *m2) 1997{ 1998 static char rcname[128]; 1999 Command *c; 2000 FILE *rcfile; 2001 int gotmachine = 0; 2002 int l1 = strlen(m1); 2003 int l2 = strlen(m2); 2004 char m1save[64]; 2005 2006 if (skiprc) 2007 return; 2008 2009 strlcpy(m1save, m1, sizeof(m1save)); 2010 m1 = m1save; 2011 2012 if (rcname[0] == 0) { 2013 char *home = getenv("HOME"); 2014 2015 snprintf (rcname, sizeof(rcname), "%s/.telnetrc", 2016 home ? home : ""); 2017 } 2018 2019 if ((rcfile = fopen(rcname, "r")) == 0) { 2020 return; 2021 } 2022 2023 for (;;) { 2024 if (fgets(line, sizeof(line), rcfile) == NULL) 2025 break; 2026 if (line[0] == 0) 2027 break; 2028 if (line[0] == '#') 2029 continue; 2030 if (gotmachine) { 2031 if (!isspace((unsigned char)line[0])) 2032 gotmachine = 0; 2033 } 2034 if (gotmachine == 0) { 2035 if (isspace((unsigned char)line[0])) 2036 continue; 2037 if (strncasecmp(line, m1, l1) == 0) 2038 strncpy(line, &line[l1], sizeof(line) - l1); 2039 else if (strncasecmp(line, m2, l2) == 0) 2040 strncpy(line, &line[l2], sizeof(line) - l2); 2041 else if (strncasecmp(line, "DEFAULT", 7) == 0) 2042 strncpy(line, &line[7], sizeof(line) - 7); 2043 else 2044 continue; 2045 if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') 2046 continue; 2047 gotmachine = 1; 2048 } 2049 makeargv(); 2050 if (margv[0] == 0) 2051 continue; 2052 c = getcmd(margv[0]); 2053 if (Ambiguous(c)) { 2054 printf("?Ambiguous command: %s\r\n", margv[0]); 2055 continue; 2056 } 2057 if (c == 0) { 2058 printf("?Invalid command: %s\r\n", margv[0]); 2059 continue; 2060 } 2061 /* 2062 * This should never happen... 2063 */ 2064 if (c->needconnect && !connected) { 2065 printf("?Need to be connected first for %s.\r\n", margv[0]); 2066 continue; 2067 } 2068 (*c->handler)(margc, margv); 2069 } 2070 fclose(rcfile); 2071} 2072 2073int 2074tn(int argc, char **argv) 2075{ 2076 struct servent *sp = 0; 2077 char *cmd, *hostp = 0, *portp = 0; 2078 char *user = 0; 2079 int port = 0; 2080 2081 /* clear the socket address prior to use */ 2082 2083 if (connected) { 2084 printf("?Already connected to %s\r\n", hostname); 2085 return 0; 2086 } 2087 if (argc < 2) { 2088 strlcpy(line, "open ", sizeof(line)); 2089 printf("(to) "); 2090 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); 2091 makeargv(); 2092 argc = margc; 2093 argv = margv; 2094 } 2095 cmd = *argv; 2096 --argc; ++argv; 2097 while (argc) { 2098 if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?")) 2099 goto usage; 2100 if (strcmp(*argv, "-l") == 0) { 2101 --argc; ++argv; 2102 if (argc == 0) 2103 goto usage; 2104 user = strdup(*argv++); 2105 --argc; 2106 continue; 2107 } 2108 if (strcmp(*argv, "-a") == 0) { 2109 --argc; ++argv; 2110 autologin = 1; 2111 continue; 2112 } 2113 if (hostp == 0) { 2114 hostp = *argv++; 2115 --argc; 2116 continue; 2117 } 2118 if (portp == 0) { 2119 portp = *argv++; 2120 --argc; 2121 continue; 2122 } 2123 usage: 2124 printf("usage: %s [-l user] [-a] host-name [port]\r\n", cmd); 2125 return 0; 2126 } 2127 if (hostp == 0) 2128 goto usage; 2129 2130 strlcpy (_hostname, hostp, sizeof(_hostname)); 2131 hostp = _hostname; 2132 if (hostp[0] == '@' || hostp[0] == '!') { 2133 char *p; 2134 hostname = NULL; 2135 for (p = hostp + 1; *p; p++) { 2136 if (*p == ',' || *p == '@') 2137 hostname = p; 2138 } 2139 if (hostname == NULL) { 2140 fprintf(stderr, "%s: bad source route specification\n", hostp); 2141 return 0; 2142 } 2143 *hostname++ = '\0'; 2144 } else 2145 hostname = hostp; 2146 2147 if (portp) { 2148 if (*portp == '-') { 2149 portp++; 2150 telnetport = 1; 2151 } else 2152 telnetport = 0; 2153 port = atoi(portp); 2154 if (port == 0) { 2155 sp = roken_getservbyname(portp, "tcp"); 2156 if (sp) 2157 port = sp->s_port; 2158 else { 2159 printf("%s: bad port number\r\n", portp); 2160 return 0; 2161 } 2162 } else { 2163 port = htons(port); 2164 } 2165 } else { 2166 if (sp == 0) { 2167 sp = roken_getservbyname("telnet", "tcp"); 2168 if (sp == 0) { 2169 fprintf(stderr, "telnet: tcp/telnet: unknown service\r\n"); 2170 return 0; 2171 } 2172 port = sp->s_port; 2173 } 2174 telnetport = 1; 2175 } 2176 2177 { 2178 struct addrinfo *ai, *a, hints; 2179 int error; 2180 char portstr[NI_MAXSERV]; 2181 2182 memset (&hints, 0, sizeof(hints)); 2183 hints.ai_socktype = SOCK_STREAM; 2184 hints.ai_protocol = IPPROTO_TCP; 2185 hints.ai_flags = AI_CANONNAME; 2186 2187 snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); 2188 2189 error = getaddrinfo (hostname, portstr, &hints, &ai); 2190 if (error) { 2191 fprintf (stderr, "%s: %s\r\n", hostname, gai_strerror (error)); 2192 return 0; 2193 } 2194 2195 for (a = ai; a != NULL && connected == 0; a = a->ai_next) { 2196 char addrstr[256]; 2197 2198 if (a->ai_canonname != NULL) 2199 strlcpy (_hostname, a->ai_canonname, sizeof(_hostname)); 2200 2201 if (getnameinfo (a->ai_addr, a->ai_addrlen, 2202 addrstr, sizeof(addrstr), 2203 NULL, 0, NI_NUMERICHOST) != 0) 2204 strlcpy (addrstr, "unknown address", sizeof(addrstr)); 2205 2206 printf("Trying %s...\r\n", addrstr); 2207 2208 net = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 2209 if (net < 0) { 2210 warn ("socket"); 2211 continue; 2212 } 2213 2214#if defined(IP_OPTIONS) && defined(IPPROTO_IP) && defined(HAVE_SETSOCKOPT) 2215 if (hostp[0] == '@' || hostp[0] == '!') { 2216 char *srp = 0; 2217 int srlen; 2218 int proto, opt; 2219 2220 if ((srlen = sourceroute(a, hostp, &srp, &proto, &opt)) < 0) { 2221 (void) NetClose(net); 2222 net = -1; 2223 continue; 2224 } 2225 if (srp && setsockopt(net, proto, opt, srp, srlen) < 0) 2226 perror("setsockopt (source route)"); 2227 } 2228#endif 2229 2230#if defined(IPPROTO_IP) && defined(IP_TOS) 2231 if (a->ai_family == AF_INET) { 2232# if defined(HAVE_GETTOSBYNAME) 2233 struct tosent *tp; 2234 if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) 2235 tos = tp->t_tos; 2236# endif 2237 if (tos < 0) 2238 tos = 020; /* Low Delay bit */ 2239 if (tos 2240 && (setsockopt(net, IPPROTO_IP, IP_TOS, 2241 (void *)&tos, sizeof(int)) < 0) 2242 && (errno != ENOPROTOOPT)) 2243 perror("telnet: setsockopt (IP_TOS) (ignored)"); 2244 } 2245#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ 2246 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 2247 perror("setsockopt (SO_DEBUG)"); 2248 } 2249 2250 if (connect (net, a->ai_addr, a->ai_addrlen) < 0) { 2251 fprintf (stderr, "telnet: connect to address %s: %s\n", 2252 addrstr, strerror(errno)); 2253 NetClose(net); 2254 if (a->ai_next != NULL) { 2255 continue; 2256 } else { 2257 freeaddrinfo (ai); 2258 return 0; 2259 } 2260 } 2261 ++connected; 2262#if defined(AUTHENTICATION) || defined(ENCRYPTION) 2263 auth_encrypt_connect(connected); 2264#endif 2265 } 2266 freeaddrinfo (ai); 2267 if (connected == 0) 2268 return 0; 2269 } 2270 cmdrc(hostp, hostname); 2271 set_forward_options(); 2272 if (autologin && user == NULL) 2273 user = (char *)get_default_username (); 2274 if (user) { 2275 env_define((unsigned char *)"USER", (unsigned char *)user); 2276 env_export((unsigned char *)"USER"); 2277 } 2278 call(status, "status", "notmuch", 0); 2279 if (setjmp(peerdied) == 0) 2280 my_telnet((char *)user); 2281 NetClose(net); 2282 ExitString("Connection closed by foreign host.\r\n",1); 2283 /*NOTREACHED*/ 2284 return 0; 2285} 2286 2287#define HELPINDENT ((int)sizeof ("connect")) 2288 2289static char 2290 openhelp[] = "connect to a site", 2291 closehelp[] = "close current connection", 2292 logouthelp[] = "forcibly logout remote user and close the connection", 2293 quithelp[] = "exit telnet", 2294 statushelp[] = "print status information", 2295 helphelp[] = "print help information", 2296 sendhelp[] = "transmit special characters ('send ?' for more)", 2297 sethelp[] = "set operating parameters ('set ?' for more)", 2298 unsethelp[] = "unset operating parameters ('unset ?' for more)", 2299 togglestring[] ="toggle operating parameters ('toggle ?' for more)", 2300 slchelp[] = "change state of special charaters ('slc ?' for more)", 2301 displayhelp[] = "display operating parameters", 2302#if defined(AUTHENTICATION) 2303 authhelp[] = "turn on (off) authentication ('auth ?' for more)", 2304#endif 2305#if defined(ENCRYPTION) 2306 encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)", 2307#endif 2308 zhelp[] = "suspend telnet", 2309 shellhelp[] = "invoke a subshell", 2310 envhelp[] = "change environment variables ('environ ?' for more)", 2311 modestring[] = "try to enter line or character mode ('mode ?' for more)"; 2312 2313static int help(int argc, char **argv); 2314 2315static Command cmdtab[] = { 2316 { "close", closehelp, bye, 1 }, 2317 { "logout", logouthelp, logout, 1 }, 2318 { "display", displayhelp, display, 0 }, 2319 { "mode", modestring, modecmd, 0 }, 2320 { "open", openhelp, tn, 0 }, 2321 { "quit", quithelp, quit, 0 }, 2322 { "send", sendhelp, sendcmd, 0 }, 2323 { "set", sethelp, setcmd, 0 }, 2324 { "unset", unsethelp, unsetcmd, 0 }, 2325 { "status", statushelp, status, 0 }, 2326 { "toggle", togglestring, toggle, 0 }, 2327 { "slc", slchelp, slccmd, 0 }, 2328#if defined(AUTHENTICATION) 2329 { "auth", authhelp, auth_cmd, 0 }, 2330#endif 2331#if defined(ENCRYPTION) 2332 { "encrypt", encrypthelp, encrypt_cmd, 0 }, 2333#endif 2334 { "z", zhelp, telnetsuspend, 0 }, 2335 { "!", shellhelp, shell, 0 }, 2336 { "environ", envhelp, env_cmd, 0 }, 2337 { "?", helphelp, help, 0 }, 2338 { 0, 0, 0, 0 } 2339}; 2340 2341static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 2342static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 2343 2344static Command cmdtab2[] = { 2345 { "help", 0, help, 0 }, 2346 { "escape", escapehelp, setescape, 0 }, 2347 { "crmod", crmodhelp, togcrmod, 0 }, 2348 { 0, 0, 0, 0 } 2349}; 2350 2351 2352/* 2353 * Call routine with argc, argv set from args (terminated by 0). 2354 */ 2355 2356static int 2357call(intrtn_t routine, ...) 2358{ 2359 va_list ap; 2360 char *args[100]; 2361 int argno = 0; 2362 2363 va_start(ap, routine); 2364 while ((args[argno++] = va_arg(ap, char *)) != 0); 2365 va_end(ap); 2366 return (*routine)(argno-1, args); 2367} 2368 2369 2370static Command 2371*getcmd(char *name) 2372{ 2373 Command *cm; 2374 2375 if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))) 2376 return cm; 2377 return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); 2378} 2379 2380void 2381command(int top, char *tbuf, int cnt) 2382{ 2383 Command *c; 2384 2385 setcommandmode(); 2386 if (!top) { 2387 putchar('\n'); 2388 } else { 2389 signal(SIGINT, SIG_DFL); 2390 signal(SIGQUIT, SIG_DFL); 2391 } 2392 for (;;) { 2393 if (rlogin == _POSIX_VDISABLE) 2394 printf("%s> ", prompt); 2395 if (tbuf) { 2396 char *cp; 2397 cp = line; 2398 while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 2399 cnt--; 2400 tbuf = 0; 2401 if (cp == line || *--cp != '\n' || cp == line) 2402 goto getline; 2403 *cp = '\0'; 2404 if (rlogin == _POSIX_VDISABLE) 2405 printf("%s\r\n", line); 2406 } else { 2407 getline: 2408 if (rlogin != _POSIX_VDISABLE) 2409 printf("%s> ", prompt); 2410 if (fgets(line, sizeof(line), stdin) == NULL) { 2411 if (feof(stdin) || ferror(stdin)) { 2412 quit(); 2413 /*NOTREACHED*/ 2414 } 2415 break; 2416 } 2417 } 2418 if (line[0] == 0) 2419 break; 2420 makeargv(); 2421 if (margv[0] == 0) { 2422 break; 2423 } 2424 c = getcmd(margv[0]); 2425 if (Ambiguous(c)) { 2426 printf("?Ambiguous command\r\n"); 2427 continue; 2428 } 2429 if (c == 0) { 2430 printf("?Invalid command\r\n"); 2431 continue; 2432 } 2433 if (c->needconnect && !connected) { 2434 printf("?Need to be connected first.\r\n"); 2435 continue; 2436 } 2437 if ((*c->handler)(margc, margv)) { 2438 break; 2439 } 2440 } 2441 if (!top) { 2442 if (!connected) { 2443 longjmp(toplevel, 1); 2444 /*NOTREACHED*/ 2445 } 2446 setconnmode(0); 2447 } 2448} 2449 2450/* 2451 * Help command. 2452 */ 2453static int 2454help(int argc, char **argv) 2455{ 2456 Command *c; 2457 2458 if (argc == 1) { 2459 printf("Commands may be abbreviated. Commands are:\r\n\r\n"); 2460 for (c = cmdtab; c->name; c++) 2461 if (c->help) { 2462 printf("%-*s\t%s\r\n", HELPINDENT, c->name, 2463 c->help); 2464 } 2465 return 0; 2466 } 2467 while (--argc > 0) { 2468 char *arg; 2469 arg = *++argv; 2470 c = getcmd(arg); 2471 if (Ambiguous(c)) 2472 printf("?Ambiguous help command %s\r\n", arg); 2473 else if (c == (Command *)0) 2474 printf("?Invalid help command %s\r\n", arg); 2475 else 2476 printf("%s\r\n", c->help); 2477 } 2478 return 0; 2479} 2480 2481 2482#if defined(IP_OPTIONS) && defined(IPPROTO_IP) 2483 2484/* 2485 * Source route is handed in as 2486 * [!]@hop1@hop2...@dst 2487 * 2488 * If the leading ! is present, it is a strict source route, otherwise it is 2489 * assmed to be a loose source route. Note that leading ! is effective 2490 * only for IPv4 case. 2491 * 2492 * We fill in the source route option as 2493 * hop1,hop2,hop3...dest 2494 * and return a pointer to hop1, which will 2495 * be the address to connect() to. 2496 * 2497 * Arguments: 2498 * ai: The address (by struct addrinfo) for the final destination. 2499 * 2500 * arg: Pointer to route list to decipher 2501 * 2502 * cpp: Pointer to a pointer, so that sourceroute() can return 2503 * the address of result buffer (statically alloc'ed). 2504 * 2505 * protop/optp: 2506 * Pointer to an integer. The pointed variable 2507 * lenp: pointer to an integer that contains the 2508 * length of *cpp if *cpp != NULL. 2509 * 2510 * Return values: 2511 * 2512 * Returns the length of the option pointed to by *cpp. If the 2513 * return value is -1, there was a syntax error in the 2514 * option, either arg contained unknown characters or too many hosts, 2515 * or hostname cannot be resolved. 2516 * 2517 * The caller needs to pass return value (len), *cpp, *protop and *optp 2518 * to setsockopt(2). 2519 * 2520 * *cpp: Points to the result buffer. The region is statically 2521 * allocated by the function. 2522 * 2523 * *protop: 2524 * protocol # to be passed to setsockopt(2). 2525 * 2526 * *optp: option # to be passed to setsockopt(2). 2527 * 2528 */ 2529int 2530sourceroute(struct addrinfo *ai, 2531 char *arg, 2532 char **cpp, 2533 int *protop, 2534 int *optp) 2535{ 2536 char *cp, *cp2, *lsrp = NULL, *lsrep = NULL; 2537 struct addrinfo hints, *res; 2538 int len, error; 2539 struct sockaddr_in *sin; 2540 register char c; 2541 static char lsr[44]; 2542#ifdef INET6 2543 struct cmsghdr *cmsg = NULL; 2544 struct sockaddr_in6 *sin6; 2545 static char rhbuf[1024]; 2546#endif 2547 2548 /* 2549 * Verify the arguments. 2550 */ 2551 if (cpp == NULL) 2552 return -1; 2553 2554 cp = arg; 2555 2556 *cpp = NULL; 2557 switch (ai->ai_family) { 2558 case AF_INET: 2559 lsrp = lsr; 2560 lsrep = lsrp + sizeof(lsr); 2561 2562 /* 2563 * Next, decide whether we have a loose source 2564 * route or a strict source route, and fill in 2565 * the begining of the option. 2566 */ 2567 if (*cp == '!') { 2568 cp++; 2569 *lsrp++ = IPOPT_SSRR; 2570 } else 2571 *lsrp++ = IPOPT_LSRR; 2572 if (*cp != '@') 2573 return -1; 2574 lsrp++; /* skip over length, we'll fill it in later */ 2575 *lsrp++ = 4; 2576 cp++; 2577 *protop = IPPROTO_IP; 2578 *optp = IP_OPTIONS; 2579 break; 2580#ifdef INET6 2581 case AF_INET6: 2582/* this needs to be updated for rfc2292bis */ 2583#ifdef IPV6_PKTOPTIONS 2584 cmsg = inet6_rthdr_init(rhbuf, IPV6_RTHDR_TYPE_0); 2585 if (*cp != '@') 2586 return -1; 2587 cp++; 2588 *protop = IPPROTO_IPV6; 2589 *optp = IPV6_PKTOPTIONS; 2590 break; 2591#else 2592 return -1; 2593#endif 2594#endif 2595 default: 2596 return -1; 2597 } 2598 2599 memset(&hints, 0, sizeof(hints)); 2600 hints.ai_family = ai->ai_family; 2601 hints.ai_socktype = SOCK_STREAM; 2602 2603 for (c = 0;;) { 2604 if (c == ':') 2605 cp2 = 0; 2606 else for (cp2 = cp; (c = *cp2) != '\0'; cp2++) { 2607 if (c == ',') { 2608 *cp2++ = '\0'; 2609 if (*cp2 == '@') 2610 cp2++; 2611 } else if (c == '@') { 2612 *cp2++ = '\0'; 2613 } 2614#if 0 /*colon conflicts with IPv6 address*/ 2615 else if (c == ':') { 2616 *cp2++ = '\0'; 2617 } 2618#endif 2619 else 2620 continue; 2621 break; 2622 } 2623 if (!c) 2624 cp2 = 0; 2625 2626 error = getaddrinfo(cp, NULL, &hints, &res); 2627 if (error) { 2628 fprintf(stderr, "%s: %s\n", cp, gai_strerror(error)); 2629 return -1; 2630 } 2631 if (ai->ai_family != res->ai_family) { 2632 freeaddrinfo(res); 2633 return -1; 2634 } 2635 if (ai->ai_family == AF_INET) { 2636 /* 2637 * Check to make sure there is space for address 2638 */ 2639 if (lsrp + 4 > lsrep) { 2640 freeaddrinfo(res); 2641 return -1; 2642 } 2643 sin = (struct sockaddr_in *)res->ai_addr; 2644 memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr)); 2645 lsrp += sizeof(struct in_addr); 2646 } 2647#ifdef INET6 2648 else if (ai->ai_family == AF_INET6) { 2649 sin6 = (struct sockaddr_in6 *)res->ai_addr; 2650 inet6_rthdr_add(cmsg, &sin6->sin6_addr, 2651 IPV6_RTHDR_LOOSE); 2652 } 2653#endif 2654 else { 2655 freeaddrinfo(res); 2656 return -1; 2657 } 2658 freeaddrinfo(res); 2659 if (cp2) 2660 cp = cp2; 2661 else 2662 break; 2663 } 2664 if (ai->ai_family == AF_INET) { 2665 /* record the last hop */ 2666 if (lsrp + 4 > lsrep) 2667 return -1; 2668 sin = (struct sockaddr_in *)ai->ai_addr; 2669 memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr)); 2670 lsrp += sizeof(struct in_addr); 2671#ifndef sysV88 2672 lsr[IPOPT_OLEN] = lsrp - lsr; 2673 if (lsr[IPOPT_OLEN] <= 7 || lsr[IPOPT_OLEN] > 40) 2674 return -1; 2675 *lsrp++ = IPOPT_NOP; /*32bit word align*/ 2676 len = lsrp - lsr; 2677 *cpp = lsr; 2678#else 2679 ipopt.io_len = lsrp - lsr; 2680 if (ipopt.io_len <= 5) /*is 3 better?*/ 2681 return -1; 2682 *cpp = (char 8)&ipopt; 2683#endif 2684 } 2685#ifdef INET6 2686 else if (ai->ai_family == AF_INET6) { 2687 inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); 2688 len = cmsg->cmsg_len; 2689 *cpp = rhbuf; 2690 } 2691#endif 2692 else 2693 return -1; 2694 return len; 2695} 2696#endif 2697