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