commands.c revision 57416
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.59 2000/01/08 08:04:16 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 991extern int kludgelinemode; 992 993static int 994dokludgemode(void) 995{ 996 kludgelinemode = 1; 997 send_wont(TELOPT_LINEMODE, 1); 998 send_dont(TELOPT_SGA, 1); 999 send_dont(TELOPT_ECHO, 1); 1000 return 1; 1001} 1002#endif 1003 1004static int 1005dolinemode() 1006{ 1007#ifdef KLUDGELINEMODE 1008 if (kludgelinemode) 1009 send_dont(TELOPT_SGA, 1); 1010#endif 1011 send_will(TELOPT_LINEMODE, 1); 1012 send_dont(TELOPT_ECHO, 1); 1013 return 1; 1014} 1015 1016static int 1017docharmode() 1018{ 1019#ifdef KLUDGELINEMODE 1020 if (kludgelinemode) 1021 send_do(TELOPT_SGA, 1); 1022 else 1023#endif 1024 send_wont(TELOPT_LINEMODE, 1); 1025 send_do(TELOPT_ECHO, 1); 1026 return 1; 1027} 1028 1029static int 1030dolmmode(int bit, int on) 1031{ 1032 unsigned char c; 1033 extern int linemode; 1034 1035 if (my_want_state_is_wont(TELOPT_LINEMODE)) { 1036 printf("?Need to have LINEMODE option enabled first.\r\n"); 1037 printf("'mode ?' for help.\r\n"); 1038 return 0; 1039 } 1040 1041 if (on) 1042 c = (linemode | bit); 1043 else 1044 c = (linemode & ~bit); 1045 lm_mode(&c, 1, 1); 1046 return 1; 1047} 1048 1049static int 1050tn_setmode(int bit) 1051{ 1052 return dolmmode(bit, 1); 1053} 1054 1055static int 1056tn_clearmode(int bit) 1057{ 1058 return dolmmode(bit, 0); 1059} 1060 1061struct modelist { 1062 char *name; /* command name */ 1063 char *help; /* help string */ 1064 int (*handler)(); /* routine which executes command */ 1065 int needconnect; /* Do we need to be connected to execute? */ 1066 int arg1; 1067}; 1068 1069static int modehelp(void); 1070 1071static struct modelist ModeList[] = { 1072 { "character", "Disable LINEMODE option", docharmode, 1 }, 1073#ifdef KLUDGELINEMODE 1074 { "", "(or disable obsolete line-by-line mode)", 0 }, 1075#endif 1076 { "line", "Enable LINEMODE option", dolinemode, 1 }, 1077#ifdef KLUDGELINEMODE 1078 { "", "(or enable obsolete line-by-line mode)", 0 }, 1079#endif 1080 { "", "", 0 }, 1081 { "", "These require the LINEMODE option to be enabled", 0 }, 1082 { "isig", "Enable signal trapping", tn_setmode, 1, MODE_TRAPSIG }, 1083 { "+isig", 0, tn_setmode, 1, MODE_TRAPSIG }, 1084 { "-isig", "Disable signal trapping", tn_clearmode, 1, MODE_TRAPSIG }, 1085 { "edit", "Enable character editing", tn_setmode, 1, MODE_EDIT }, 1086 { "+edit", 0, tn_setmode, 1, MODE_EDIT }, 1087 { "-edit", "Disable character editing", tn_clearmode, 1, MODE_EDIT }, 1088 { "softtabs", "Enable tab expansion", tn_setmode, 1, MODE_SOFT_TAB }, 1089 { "+softtabs", 0, tn_setmode, 1, MODE_SOFT_TAB }, 1090 { "-softtabs", "Disable character editing", tn_clearmode, 1, MODE_SOFT_TAB }, 1091 { "litecho", "Enable literal character echo", tn_setmode, 1, MODE_LIT_ECHO }, 1092 { "+litecho", 0, tn_setmode, 1, MODE_LIT_ECHO }, 1093 { "-litecho", "Disable literal character echo", tn_clearmode, 1, MODE_LIT_ECHO }, 1094 { "help", 0, modehelp, 0 }, 1095#ifdef KLUDGELINEMODE 1096 { "kludgeline", 0, dokludgemode, 1 }, 1097#endif 1098 { "", "", 0 }, 1099 { "?", "Print help information", modehelp, 0 }, 1100 { 0 }, 1101}; 1102 1103 1104static int 1105modehelp(void) 1106{ 1107 struct modelist *mt; 1108 1109 printf("format is: 'mode Mode', where 'Mode' is one of:\r\n\r\n"); 1110 for (mt = ModeList; mt->name; mt++) { 1111 if (mt->help) { 1112 if (*mt->help) 1113 printf("%-15s %s\r\n", mt->name, mt->help); 1114 else 1115 printf("\r\n"); 1116 } 1117 } 1118 return 0; 1119} 1120 1121#define GETMODECMD(name) (struct modelist *) \ 1122 genget(name, (char **) ModeList, sizeof(struct modelist)) 1123 1124static int 1125modecmd(int argc, char **argv) 1126{ 1127 struct modelist *mt; 1128 1129 if (argc != 2) { 1130 printf("'mode' command requires an argument\r\n"); 1131 printf("'mode ?' for help.\r\n"); 1132 } else if ((mt = GETMODECMD(argv[1])) == 0) { 1133 fprintf(stderr, "Unknown mode '%s' ('mode ?' for help).\r\n", argv[1]); 1134 } else if (Ambiguous(mt)) { 1135 fprintf(stderr, "Ambiguous mode '%s' ('mode ?' for help).\r\n", argv[1]); 1136 } else if (mt->needconnect && !connected) { 1137 printf("?Need to be connected first.\r\n"); 1138 printf("'mode ?' for help.\r\n"); 1139 } else if (mt->handler) { 1140 return (*mt->handler)(mt->arg1); 1141 } 1142 return 0; 1143} 1144 1145/* 1146 * The following data structures and routines implement the 1147 * "display" command. 1148 */ 1149 1150static int 1151display(int argc, char *argv[]) 1152{ 1153 struct togglelist *tl; 1154 struct setlist *sl; 1155 1156#define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 1157 if (*tl->variable) { \ 1158 printf("will"); \ 1159 } else { \ 1160 printf("won't"); \ 1161 } \ 1162 printf(" %s.\r\n", tl->actionexplanation); \ 1163 } 1164 1165#define doset(sl) if (sl->name && *sl->name != ' ') { \ 1166 if (sl->handler == 0) \ 1167 printf("%-15s [%s]\r\n", sl->name, control(*sl->charp)); \ 1168 else \ 1169 printf("%-15s \"%s\"\r\n", sl->name, (char *)sl->charp); \ 1170 } 1171 1172 if (argc == 1) { 1173 for (tl = Togglelist; tl->name; tl++) { 1174 dotog(tl); 1175 } 1176 printf("\r\n"); 1177 for (sl = Setlist; sl->name; sl++) { 1178 doset(sl); 1179 } 1180 } else { 1181 int i; 1182 1183 for (i = 1; i < argc; i++) { 1184 sl = getset(argv[i]); 1185 tl = GETTOGGLE(argv[i]); 1186 if (Ambiguous(sl) || Ambiguous(tl)) { 1187 printf("?Ambiguous argument '%s'.\r\n", argv[i]); 1188 return 0; 1189 } else if (!sl && !tl) { 1190 printf("?Unknown argument '%s'.\r\n", argv[i]); 1191 return 0; 1192 } else { 1193 if (tl) { 1194 dotog(tl); 1195 } 1196 if (sl) { 1197 doset(sl); 1198 } 1199 } 1200 } 1201 } 1202/*@*/optionstatus(); 1203#if defined(ENCRYPTION) 1204 EncryptStatus(); 1205#endif 1206 return 1; 1207#undef doset 1208#undef dotog 1209} 1210 1211/* 1212 * The following are the data structures, and many of the routines, 1213 * relating to command processing. 1214 */ 1215 1216/* 1217 * Set the escape character. 1218 */ 1219static int 1220setescape(int argc, char *argv[]) 1221{ 1222 char *arg; 1223 char buf[50]; 1224 1225 printf( 1226 "Deprecated usage - please use 'set escape%s%s' in the future.\r\n", 1227 (argc > 2)? " ":"", (argc > 2)? argv[1]: ""); 1228 if (argc > 2) 1229 arg = argv[1]; 1230 else { 1231 printf("new escape character: "); 1232 fgets(buf, sizeof(buf), stdin); 1233 arg = buf; 1234 } 1235 if (arg[0] != '\0') 1236 escape = arg[0]; 1237 printf("Escape character is '%s'.\r\n", control(escape)); 1238 1239 fflush(stdout); 1240 return 1; 1241} 1242 1243static int 1244togcrmod() 1245{ 1246 crmod = !crmod; 1247 printf("Deprecated usage - please use 'toggle crmod' in the future.\r\n"); 1248 printf("%s map carriage return on output.\r\n", crmod ? "Will" : "Won't"); 1249 fflush(stdout); 1250 return 1; 1251} 1252 1253static int 1254telnetsuspend() 1255{ 1256#ifdef SIGTSTP 1257 setcommandmode(); 1258 { 1259 long oldrows, oldcols, newrows, newcols, err; 1260 1261 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1262 kill(0, SIGTSTP); 1263 /* 1264 * If we didn't get the window size before the SUSPEND, but we 1265 * can get them now (?), then send the NAWS to make sure that 1266 * we are set up for the right window size. 1267 */ 1268 if (TerminalWindowSize(&newrows, &newcols) && connected && 1269 (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1270 sendnaws(); 1271 } 1272 } 1273 /* reget parameters in case they were changed */ 1274 TerminalSaveState(); 1275 setconnmode(0); 1276#else 1277 printf("Suspend is not supported. Try the '!' command instead\r\n"); 1278#endif 1279 return 1; 1280} 1281 1282static int 1283shell(int argc, char **argv) 1284{ 1285 long oldrows, oldcols, newrows, newcols, err; 1286 1287 setcommandmode(); 1288 1289 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1290 switch(fork()) { 1291 case -1: 1292 perror("Fork failed\r\n"); 1293 break; 1294 1295 case 0: 1296 { 1297 /* 1298 * Fire up the shell in the child. 1299 */ 1300 char *shellp, *shellname; 1301 1302 shellp = getenv("SHELL"); 1303 if (shellp == NULL) 1304 shellp = "/bin/sh"; 1305 if ((shellname = strrchr(shellp, '/')) == 0) 1306 shellname = shellp; 1307 else 1308 shellname++; 1309 if (argc > 1) 1310 execl(shellp, shellname, "-c", &saveline[1], 0); 1311 else 1312 execl(shellp, shellname, 0); 1313 perror("Execl"); 1314 _exit(1); 1315 } 1316 default: 1317 wait((int *)0); /* Wait for the shell to complete */ 1318 1319 if (TerminalWindowSize(&newrows, &newcols) && connected && 1320 (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1321 sendnaws(); 1322 } 1323 break; 1324 } 1325 return 1; 1326} 1327 1328static int 1329bye(int argc, char **argv) 1330{ 1331 extern int resettermname; 1332 1333 if (connected) { 1334 shutdown(net, 2); 1335 printf("Connection closed.\r\n"); 1336 NetClose(net); 1337 connected = 0; 1338 resettermname = 1; 1339#if defined(AUTHENTICATION) || defined(ENCRYPTION) 1340 auth_encrypt_connect(connected); 1341#endif 1342 /* reset options */ 1343 tninit(); 1344 } 1345 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) 1346 longjmp(toplevel, 1); 1347 return 0; /* NOTREACHED */ 1348} 1349 1350int 1351quit(void) 1352{ 1353 call(bye, "bye", "fromquit", 0); 1354 Exit(0); 1355 return 0; /*NOTREACHED*/ 1356} 1357 1358static int 1359logout() 1360{ 1361 send_do(TELOPT_LOGOUT, 1); 1362 netflush(); 1363 return 1; 1364} 1365 1366 1367/* 1368 * The SLC command. 1369 */ 1370 1371struct slclist { 1372 char *name; 1373 char *help; 1374 void (*handler)(); 1375 int arg; 1376}; 1377 1378static void slc_help(void); 1379 1380struct slclist SlcList[] = { 1381 { "export", "Use local special character definitions", 1382 slc_mode_export, 0 }, 1383 { "import", "Use remote special character definitions", 1384 slc_mode_import, 1 }, 1385 { "check", "Verify remote special character definitions", 1386 slc_mode_import, 0 }, 1387 { "help", 0, slc_help, 0 }, 1388 { "?", "Print help information", slc_help, 0 }, 1389 { 0 }, 1390}; 1391 1392static void 1393slc_help(void) 1394{ 1395 struct slclist *c; 1396 1397 for (c = SlcList; c->name; c++) { 1398 if (c->help) { 1399 if (*c->help) 1400 printf("%-15s %s\r\n", c->name, c->help); 1401 else 1402 printf("\r\n"); 1403 } 1404 } 1405} 1406 1407static struct slclist * 1408getslc(char *name) 1409{ 1410 return (struct slclist *) 1411 genget(name, (char **) SlcList, sizeof(struct slclist)); 1412} 1413 1414static int 1415slccmd(int argc, char **argv) 1416{ 1417 struct slclist *c; 1418 1419 if (argc != 2) { 1420 fprintf(stderr, 1421 "Need an argument to 'slc' command. 'slc ?' for help.\r\n"); 1422 return 0; 1423 } 1424 c = getslc(argv[1]); 1425 if (c == 0) { 1426 fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\r\n", 1427 argv[1]); 1428 return 0; 1429 } 1430 if (Ambiguous(c)) { 1431 fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\r\n", 1432 argv[1]); 1433 return 0; 1434 } 1435 (*c->handler)(c->arg); 1436 slcstate(); 1437 return 1; 1438} 1439 1440/* 1441 * The ENVIRON command. 1442 */ 1443 1444struct envlist { 1445 char *name; 1446 char *help; 1447 void (*handler)(); 1448 int narg; 1449}; 1450 1451static void env_help (void); 1452 1453struct envlist EnvList[] = { 1454 { "define", "Define an environment variable", 1455 (void (*)())env_define, 2 }, 1456 { "undefine", "Undefine an environment variable", 1457 env_undefine, 1 }, 1458 { "export", "Mark an environment variable for automatic export", 1459 env_export, 1 }, 1460 { "unexport", "Don't mark an environment variable for automatic export", 1461 env_unexport, 1 }, 1462 { "send", "Send an environment variable", env_send, 1 }, 1463 { "list", "List the current environment variables", 1464 env_list, 0 }, 1465 { "help", 0, env_help, 0 }, 1466 { "?", "Print help information", env_help, 0 }, 1467 { 0 }, 1468}; 1469 1470static void 1471env_help() 1472{ 1473 struct envlist *c; 1474 1475 for (c = EnvList; c->name; c++) { 1476 if (c->help) { 1477 if (*c->help) 1478 printf("%-15s %s\r\n", c->name, c->help); 1479 else 1480 printf("\r\n"); 1481 } 1482 } 1483} 1484 1485static struct envlist * 1486getenvcmd(char *name) 1487{ 1488 return (struct envlist *) 1489 genget(name, (char **) EnvList, sizeof(struct envlist)); 1490} 1491 1492static int 1493env_cmd(int argc, char **argv) 1494{ 1495 struct envlist *c; 1496 1497 if (argc < 2) { 1498 fprintf(stderr, 1499 "Need an argument to 'environ' command. 'environ ?' for help.\r\n"); 1500 return 0; 1501 } 1502 c = getenvcmd(argv[1]); 1503 if (c == 0) { 1504 fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\r\n", 1505 argv[1]); 1506 return 0; 1507 } 1508 if (Ambiguous(c)) { 1509 fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\r\n", 1510 argv[1]); 1511 return 0; 1512 } 1513 if (c->narg + 2 != argc) { 1514 fprintf(stderr, 1515 "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\r\n", 1516 c->narg < argc + 2 ? "only " : "", 1517 c->narg, c->narg == 1 ? "" : "s", c->name); 1518 return 0; 1519 } 1520 (*c->handler)(argv[2], argv[3]); 1521 return 1; 1522} 1523 1524struct env_lst { 1525 struct env_lst *next; /* pointer to next structure */ 1526 struct env_lst *prev; /* pointer to previous structure */ 1527 unsigned char *var; /* pointer to variable name */ 1528 unsigned char *value; /* pointer to variable value */ 1529 int export; /* 1 -> export with default list of variables */ 1530 int welldefined; /* A well defined variable */ 1531}; 1532 1533struct env_lst envlisthead; 1534 1535struct env_lst * 1536env_find(unsigned char *var) 1537{ 1538 struct env_lst *ep; 1539 1540 for (ep = envlisthead.next; ep; ep = ep->next) { 1541 if (strcmp((char *)ep->var, (char *)var) == 0) 1542 return(ep); 1543 } 1544 return(NULL); 1545} 1546 1547#if IRIX == 4 1548#define environ _environ 1549#endif 1550 1551void 1552env_init(void) 1553{ 1554 extern char **environ; 1555 char **epp, *cp; 1556 struct env_lst *ep; 1557 1558 for (epp = environ; *epp; epp++) { 1559 if ((cp = strchr(*epp, '='))) { 1560 *cp = '\0'; 1561 ep = env_define((unsigned char *)*epp, 1562 (unsigned char *)cp+1); 1563 ep->export = 0; 1564 *cp = '='; 1565 } 1566 } 1567 /* 1568 * Special case for DISPLAY variable. If it is ":0.0" or 1569 * "unix:0.0", we have to get rid of "unix" and insert our 1570 * hostname. 1571 */ 1572 if ((ep = env_find("DISPLAY")) 1573 && (*ep->value == ':' 1574 || strncmp((char *)ep->value, "unix:", 5) == 0)) { 1575 char hbuf[256+1]; 1576 char *cp2 = strchr((char *)ep->value, ':'); 1577 1578 /* XXX - should be k_gethostname? */ 1579 gethostname(hbuf, 256); 1580 hbuf[256] = '\0'; 1581 1582 /* If this is not the full name, try to get it via DNS */ 1583 if (strchr(hbuf, '.') == 0) { 1584 struct addrinfo hints, *ai, *a; 1585 int error; 1586 1587 memset (&hints, 0, sizeof(hints)); 1588 hints.ai_flags = AI_CANONNAME; 1589 1590 error = getaddrinfo (hbuf, NULL, &hints, &ai); 1591 if (error == 0) { 1592 for (a = ai; a != NULL; a = a->ai_next) 1593 if (a->ai_canonname != NULL) { 1594 strlcpy (hbuf, 1595 ai->ai_canonname, 1596 256); 1597 break; 1598 } 1599 freeaddrinfo (ai); 1600 } 1601 } 1602 1603 asprintf (&cp, "%s%s", hbuf, cp2); 1604 free (ep->value); 1605 ep->value = (unsigned char *)cp; 1606 } 1607 /* 1608 * If USER is not defined, but LOGNAME is, then add 1609 * USER with the value from LOGNAME. By default, we 1610 * don't export the USER variable. 1611 */ 1612 if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) { 1613 env_define((unsigned char *)"USER", ep->value); 1614 env_unexport((unsigned char *)"USER"); 1615 } 1616 env_export((unsigned char *)"DISPLAY"); 1617 env_export((unsigned char *)"PRINTER"); 1618 env_export((unsigned char *)"XAUTHORITY"); 1619} 1620 1621struct env_lst * 1622env_define(unsigned char *var, unsigned char *value) 1623{ 1624 struct env_lst *ep; 1625 1626 if ((ep = env_find(var))) { 1627 if (ep->var) 1628 free(ep->var); 1629 if (ep->value) 1630 free(ep->value); 1631 } else { 1632 ep = (struct env_lst *)malloc(sizeof(struct env_lst)); 1633 ep->next = envlisthead.next; 1634 envlisthead.next = ep; 1635 ep->prev = &envlisthead; 1636 if (ep->next) 1637 ep->next->prev = ep; 1638 } 1639 ep->welldefined = opt_welldefined((char *)var); 1640 ep->export = 1; 1641 ep->var = (unsigned char *)strdup((char *)var); 1642 ep->value = (unsigned char *)strdup((char *)value); 1643 return(ep); 1644} 1645 1646void 1647env_undefine(unsigned char *var) 1648{ 1649 struct env_lst *ep; 1650 1651 if ((ep = env_find(var))) { 1652 ep->prev->next = ep->next; 1653 if (ep->next) 1654 ep->next->prev = ep->prev; 1655 if (ep->var) 1656 free(ep->var); 1657 if (ep->value) 1658 free(ep->value); 1659 free(ep); 1660 } 1661} 1662 1663void 1664env_export(unsigned char *var) 1665{ 1666 struct env_lst *ep; 1667 1668 if ((ep = env_find(var))) 1669 ep->export = 1; 1670} 1671 1672void 1673env_unexport(unsigned char *var) 1674{ 1675 struct env_lst *ep; 1676 1677 if ((ep = env_find(var))) 1678 ep->export = 0; 1679} 1680 1681void 1682env_send(unsigned char *var) 1683{ 1684 struct env_lst *ep; 1685 1686 if (my_state_is_wont(TELOPT_NEW_ENVIRON) 1687#ifdef OLD_ENVIRON 1688 && my_state_is_wont(TELOPT_OLD_ENVIRON) 1689#endif 1690 ) { 1691 fprintf(stderr, 1692 "Cannot send '%s': Telnet ENVIRON option not enabled\r\n", 1693 var); 1694 return; 1695 } 1696 ep = env_find(var); 1697 if (ep == 0) { 1698 fprintf(stderr, "Cannot send '%s': variable not defined\r\n", 1699 var); 1700 return; 1701 } 1702 env_opt_start_info(); 1703 env_opt_add(ep->var); 1704 env_opt_end(0); 1705} 1706 1707void 1708env_list(void) 1709{ 1710 struct env_lst *ep; 1711 1712 for (ep = envlisthead.next; ep; ep = ep->next) { 1713 printf("%c %-20s %s\r\n", ep->export ? '*' : ' ', 1714 ep->var, ep->value); 1715 } 1716} 1717 1718unsigned char * 1719env_default(int init, int welldefined) 1720{ 1721 static struct env_lst *nep = NULL; 1722 1723 if (init) { 1724 nep = &envlisthead; 1725 return NULL; 1726 } 1727 if (nep) { 1728 while ((nep = nep->next)) { 1729 if (nep->export && (nep->welldefined == welldefined)) 1730 return(nep->var); 1731 } 1732 } 1733 return(NULL); 1734} 1735 1736unsigned char * 1737env_getvalue(unsigned char *var) 1738{ 1739 struct env_lst *ep; 1740 1741 if ((ep = env_find(var))) 1742 return(ep->value); 1743 return(NULL); 1744} 1745 1746 1747#if defined(AUTHENTICATION) 1748/* 1749 * The AUTHENTICATE command. 1750 */ 1751 1752struct authlist { 1753 char *name; 1754 char *help; 1755 int (*handler)(); 1756 int narg; 1757}; 1758 1759static int 1760 auth_help (void); 1761 1762struct authlist AuthList[] = { 1763 { "status", "Display current status of authentication information", 1764 auth_status, 0 }, 1765 { "disable", "Disable an authentication type ('auth disable ?' for more)", 1766 auth_disable, 1 }, 1767 { "enable", "Enable an authentication type ('auth enable ?' for more)", 1768 auth_enable, 1 }, 1769 { "help", 0, auth_help, 0 }, 1770 { "?", "Print help information", auth_help, 0 }, 1771 { 0 }, 1772}; 1773 1774static int 1775auth_help() 1776{ 1777 struct authlist *c; 1778 1779 for (c = AuthList; c->name; c++) { 1780 if (c->help) { 1781 if (*c->help) 1782 printf("%-15s %s\r\n", c->name, c->help); 1783 else 1784 printf("\r\n"); 1785 } 1786 } 1787 return 0; 1788} 1789 1790static int 1791auth_cmd(int argc, char **argv) 1792{ 1793 struct authlist *c; 1794 1795 if (argc < 2) { 1796 fprintf(stderr, 1797 "Need an argument to 'auth' command. 'auth ?' for help.\r\n"); 1798 return 0; 1799 } 1800 1801 c = (struct authlist *) 1802 genget(argv[1], (char **) AuthList, sizeof(struct authlist)); 1803 if (c == 0) { 1804 fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\r\n", 1805 argv[1]); 1806 return 0; 1807 } 1808 if (Ambiguous(c)) { 1809 fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\r\n", 1810 argv[1]); 1811 return 0; 1812 } 1813 if (c->narg + 2 != argc) { 1814 fprintf(stderr, 1815 "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\r\n", 1816 c->narg < argc + 2 ? "only " : "", 1817 c->narg, c->narg == 1 ? "" : "s", c->name); 1818 return 0; 1819 } 1820 return((*c->handler)(argv[2], argv[3])); 1821} 1822#endif 1823 1824 1825#if defined(ENCRYPTION) 1826/* 1827 * The ENCRYPT command. 1828 */ 1829 1830struct encryptlist { 1831 char *name; 1832 char *help; 1833 int (*handler)(); 1834 int needconnect; 1835 int minarg; 1836 int maxarg; 1837}; 1838 1839static int 1840 EncryptHelp (void); 1841 1842struct encryptlist EncryptList[] = { 1843 { "enable", "Enable encryption. ('encrypt enable ?' for more)", 1844 EncryptEnable, 1, 1, 2 }, 1845 { "disable", "Disable encryption. ('encrypt enable ?' for more)", 1846 EncryptDisable, 0, 1, 2 }, 1847 { "type", "Set encryptiong type. ('encrypt type ?' for more)", 1848 EncryptType, 0, 1, 1 }, 1849 { "start", "Start encryption. ('encrypt start ?' for more)", 1850 EncryptStart, 1, 0, 1 }, 1851 { "stop", "Stop encryption. ('encrypt stop ?' for more)", 1852 EncryptStop, 1, 0, 1 }, 1853 { "input", "Start encrypting the input stream", 1854 EncryptStartInput, 1, 0, 0 }, 1855 { "-input", "Stop encrypting the input stream", 1856 EncryptStopInput, 1, 0, 0 }, 1857 { "output", "Start encrypting the output stream", 1858 EncryptStartOutput, 1, 0, 0 }, 1859 { "-output", "Stop encrypting the output stream", 1860 EncryptStopOutput, 1, 0, 0 }, 1861 1862 { "status", "Display current status of authentication information", 1863 EncryptStatus, 0, 0, 0 }, 1864 { "help", 0, EncryptHelp, 0, 0, 0 }, 1865 { "?", "Print help information", EncryptHelp, 0, 0, 0 }, 1866 { 0 }, 1867}; 1868 1869static int 1870EncryptHelp() 1871{ 1872 struct encryptlist *c; 1873 1874 for (c = EncryptList; c->name; c++) { 1875 if (c->help) { 1876 if (*c->help) 1877 printf("%-15s %s\r\n", c->name, c->help); 1878 else 1879 printf("\r\n"); 1880 } 1881 } 1882 return 0; 1883} 1884 1885static int 1886encrypt_cmd(int argc, char **argv) 1887{ 1888 struct encryptlist *c; 1889 1890 c = (struct encryptlist *) 1891 genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist)); 1892 if (c == 0) { 1893 fprintf(stderr, "'%s': unknown argument ('encrypt ?' for help).\r\n", 1894 argv[1]); 1895 return 0; 1896 } 1897 if (Ambiguous(c)) { 1898 fprintf(stderr, "'%s': ambiguous argument ('encrypt ?' for help).\r\n", 1899 argv[1]); 1900 return 0; 1901 } 1902 argc -= 2; 1903 if (argc < c->minarg || argc > c->maxarg) { 1904 if (c->minarg == c->maxarg) { 1905 fprintf(stderr, "Need %s%d argument%s ", 1906 c->minarg < argc ? "only " : "", c->minarg, 1907 c->minarg == 1 ? "" : "s"); 1908 } else { 1909 fprintf(stderr, "Need %s%d-%d arguments ", 1910 c->maxarg < argc ? "only " : "", c->minarg, c->maxarg); 1911 } 1912 fprintf(stderr, "to 'encrypt %s' command. 'encrypt ?' for help.\r\n", 1913 c->name); 1914 return 0; 1915 } 1916 if (c->needconnect && !connected) { 1917 if (!(argc && (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) { 1918 printf("?Need to be connected first.\r\n"); 1919 return 0; 1920 } 1921 } 1922 return ((*c->handler)(argc > 0 ? argv[2] : 0, 1923 argc > 1 ? argv[3] : 0, 1924 argc > 2 ? argv[4] : 0)); 1925} 1926#endif 1927 1928 1929/* 1930 * Print status about the connection. 1931 */ 1932 1933static int 1934status(int argc, char **argv) 1935{ 1936 if (connected) { 1937 printf("Connected to %s.\r\n", hostname); 1938 if ((argc < 2) || strcmp(argv[1], "notmuch")) { 1939 int mode = getconnmode(); 1940 1941 if (my_want_state_is_will(TELOPT_LINEMODE)) { 1942 printf("Operating with LINEMODE option\r\n"); 1943 printf("%s line editing\r\n", (mode&MODE_EDIT) ? "Local" : "No"); 1944 printf("%s catching of signals\r\n", 1945 (mode&MODE_TRAPSIG) ? "Local" : "No"); 1946 slcstate(); 1947#ifdef KLUDGELINEMODE 1948 } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { 1949 printf("Operating in obsolete linemode\r\n"); 1950#endif 1951 } else { 1952 printf("Operating in single character mode\r\n"); 1953 if (localchars) 1954 printf("Catching signals locally\r\n"); 1955 } 1956 printf("%s character echo\r\n", (mode&MODE_ECHO) ? "Local" : "Remote"); 1957 if (my_want_state_is_will(TELOPT_LFLOW)) 1958 printf("%s flow control\r\n", (mode&MODE_FLOW) ? "Local" : "No"); 1959#if defined(ENCRYPTION) 1960 encrypt_display(); 1961#endif 1962 } 1963 } else { 1964 printf("No connection.\r\n"); 1965 } 1966 printf("Escape character is '%s'.\r\n", control(escape)); 1967 fflush(stdout); 1968 return 1; 1969} 1970 1971#ifdef SIGINFO 1972/* 1973 * Function that gets called when SIGINFO is received. 1974 */ 1975void 1976ayt_status(int ignore) 1977{ 1978 call(status, "status", "notmuch", 0); 1979} 1980#endif 1981 1982static Command *getcmd(char *name); 1983 1984static void 1985cmdrc(char *m1, char *m2) 1986{ 1987 static char rcname[128]; 1988 Command *c; 1989 FILE *rcfile; 1990 int gotmachine = 0; 1991 int l1 = strlen(m1); 1992 int l2 = strlen(m2); 1993 char m1save[64]; 1994 1995 if (skiprc) 1996 return; 1997 1998 strlcpy(m1save, m1, sizeof(m1save)); 1999 m1 = m1save; 2000 2001 if (rcname[0] == 0) { 2002 char *home = getenv("HOME"); 2003 2004 snprintf (rcname, sizeof(rcname), "%s/.telnetrc", 2005 home ? home : ""); 2006 } 2007 2008 if ((rcfile = fopen(rcname, "r")) == 0) { 2009 return; 2010 } 2011 2012 for (;;) { 2013 if (fgets(line, sizeof(line), rcfile) == NULL) 2014 break; 2015 if (line[0] == 0) 2016 break; 2017 if (line[0] == '#') 2018 continue; 2019 if (gotmachine) { 2020 if (!isspace(line[0])) 2021 gotmachine = 0; 2022 } 2023 if (gotmachine == 0) { 2024 if (isspace(line[0])) 2025 continue; 2026 if (strncasecmp(line, m1, l1) == 0) 2027 strncpy(line, &line[l1], sizeof(line) - l1); 2028 else if (strncasecmp(line, m2, l2) == 0) 2029 strncpy(line, &line[l2], sizeof(line) - l2); 2030 else if (strncasecmp(line, "DEFAULT", 7) == 0) 2031 strncpy(line, &line[7], sizeof(line) - 7); 2032 else 2033 continue; 2034 if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') 2035 continue; 2036 gotmachine = 1; 2037 } 2038 makeargv(); 2039 if (margv[0] == 0) 2040 continue; 2041 c = getcmd(margv[0]); 2042 if (Ambiguous(c)) { 2043 printf("?Ambiguous command: %s\r\n", margv[0]); 2044 continue; 2045 } 2046 if (c == 0) { 2047 printf("?Invalid command: %s\r\n", margv[0]); 2048 continue; 2049 } 2050 /* 2051 * This should never happen... 2052 */ 2053 if (c->needconnect && !connected) { 2054 printf("?Need to be connected first for %s.\r\n", margv[0]); 2055 continue; 2056 } 2057 (*c->handler)(margc, margv); 2058 } 2059 fclose(rcfile); 2060} 2061 2062int 2063tn(int argc, char **argv) 2064{ 2065 struct servent *sp = 0; 2066 extern char *inet_ntoa(); 2067#if defined(IP_OPTIONS) && defined(IPPROTO_IP) 2068 char *srp = 0; 2069 int srlen; 2070#endif 2071 char *cmd, *hostp = 0, *portp = 0; 2072 char *user = 0; 2073 int port = 0; 2074 2075 /* clear the socket address prior to use */ 2076 2077 if (connected) { 2078 printf("?Already connected to %s\r\n", hostname); 2079 setuid(getuid()); 2080 return 0; 2081 } 2082 if (argc < 2) { 2083 strlcpy(line, "open ", sizeof(line)); 2084 printf("(to) "); 2085 fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); 2086 makeargv(); 2087 argc = margc; 2088 argv = margv; 2089 } 2090 cmd = *argv; 2091 --argc; ++argv; 2092 while (argc) { 2093 if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?")) 2094 goto usage; 2095 if (strcmp(*argv, "-l") == 0) { 2096 --argc; ++argv; 2097 if (argc == 0) 2098 goto usage; 2099 user = strdup(*argv++); 2100 --argc; 2101 continue; 2102 } 2103 if (strcmp(*argv, "-a") == 0) { 2104 --argc; ++argv; 2105 autologin = 1; 2106 continue; 2107 } 2108 if (hostp == 0) { 2109 hostp = *argv++; 2110 --argc; 2111 continue; 2112 } 2113 if (portp == 0) { 2114 portp = *argv++; 2115 --argc; 2116 continue; 2117 } 2118 usage: 2119 printf("usage: %s [-l user] [-a] host-name [port]\r\n", cmd); 2120 setuid(getuid()); 2121 return 0; 2122 } 2123 if (hostp == 0) 2124 goto usage; 2125 2126 if (portp) { 2127 if (*portp == '-') { 2128 portp++; 2129 telnetport = 1; 2130 } else 2131 telnetport = 0; 2132 port = atoi(portp); 2133 if (port == 0) { 2134 sp = roken_getservbyname(portp, "tcp"); 2135 if (sp) 2136 port = sp->s_port; 2137 else { 2138 printf("%s: bad port number\r\n", portp); 2139 setuid(getuid()); 2140 return 0; 2141 } 2142 } else { 2143 port = htons(port); 2144 } 2145 } else { 2146 if (sp == 0) { 2147 sp = roken_getservbyname("telnet", "tcp"); 2148 if (sp == 0) { 2149 fprintf(stderr, "telnet: tcp/telnet: unknown service\r\n"); 2150 setuid(getuid()); 2151 return 0; 2152 } 2153 port = sp->s_port; 2154 } 2155 telnetport = 1; 2156 } 2157 2158 { 2159 struct addrinfo *ai, *a, hints; 2160 int error; 2161 char portstr[NI_MAXSERV]; 2162 2163 memset (&hints, 0, sizeof(hints)); 2164 hints.ai_socktype = SOCK_STREAM; 2165 hints.ai_protocol = IPPROTO_TCP; 2166 hints.ai_flags = AI_CANONNAME; 2167 2168 snprintf (portstr, sizeof(portstr), "%u", ntohs(port)); 2169 2170 error = getaddrinfo (hostp, portstr, &hints, &ai); 2171 if (error) { 2172 fprintf (stderr, "%s: %s\r\n", hostp, gai_strerror (error)); 2173 setuid (getuid ()); 2174 return 0; 2175 } 2176 strlcpy (_hostname, hostp, sizeof(_hostname)); 2177 hostname = _hostname; 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 setuid (getuid ()); 2194 if (net < 0) { 2195 warn ("telnet: socket"); 2196 continue; 2197 } 2198#if defined(IP_OPTIONS) && defined(IPPROTO_IP) && defined(HAVE_SETSOCKOPT) 2199 if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, 2200 (void *)srp, srlen) < 0) 2201 perror("setsockopt (IP_OPTIONS)"); 2202#endif 2203#if defined(IPPROTO_IP) && defined(IP_TOS) 2204 { 2205# if defined(HAVE_GETTOSBYNAME) 2206 struct tosent *tp; 2207 if (tos < 0 && (tp = gettosbyname("telnet", "tcp"))) 2208 tos = tp->t_tos; 2209# endif 2210 if (tos < 0) 2211 tos = 020; /* Low Delay bit */ 2212 if (tos 2213 && (setsockopt(net, IPPROTO_IP, IP_TOS, 2214 (void *)&tos, sizeof(int)) < 0) 2215 && (errno != ENOPROTOOPT)) 2216 perror("telnet: setsockopt (IP_TOS) (ignored)"); 2217 } 2218#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */ 2219 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 2220 perror("setsockopt (SO_DEBUG)"); 2221 } 2222 2223 if (connect (net, a->ai_addr, a->ai_addrlen) < 0) { 2224 fprintf (stderr, "telnet: connect to address %s: %s\n", 2225 addrstr, strerror(errno)); 2226 NetClose(net); 2227 if (a->ai_next != NULL) { 2228 continue; 2229 } else { 2230 freeaddrinfo (ai); 2231 return 0; 2232 } 2233 } 2234 ++connected; 2235#if defined(AUTHENTICATION) || defined(ENCRYPTION) 2236 auth_encrypt_connect(connected); 2237#endif 2238 } 2239 } 2240 cmdrc(hostp, hostname); 2241 if (autologin && user == NULL) 2242 user = (char *)get_default_username (); 2243 if (user) { 2244 env_define((unsigned char *)"USER", (unsigned char *)user); 2245 env_export((unsigned char *)"USER"); 2246 } 2247 call(status, "status", "notmuch", 0); 2248 if (setjmp(peerdied) == 0) 2249 my_telnet((char *)user); 2250 NetClose(net); 2251 ExitString("Connection closed by foreign host.\r\n",1); 2252 /*NOTREACHED*/ 2253 return 0; 2254} 2255 2256#define HELPINDENT ((int)sizeof ("connect")) 2257 2258static char 2259 openhelp[] = "connect to a site", 2260 closehelp[] = "close current connection", 2261 logouthelp[] = "forcibly logout remote user and close the connection", 2262 quithelp[] = "exit telnet", 2263 statushelp[] = "print status information", 2264 helphelp[] = "print help information", 2265 sendhelp[] = "transmit special characters ('send ?' for more)", 2266 sethelp[] = "set operating parameters ('set ?' for more)", 2267 unsethelp[] = "unset operating parameters ('unset ?' for more)", 2268 togglestring[] ="toggle operating parameters ('toggle ?' for more)", 2269 slchelp[] = "change state of special charaters ('slc ?' for more)", 2270 displayhelp[] = "display operating parameters", 2271#if defined(AUTHENTICATION) 2272 authhelp[] = "turn on (off) authentication ('auth ?' for more)", 2273#endif 2274#if defined(ENCRYPTION) 2275 encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)", 2276#endif 2277 zhelp[] = "suspend telnet", 2278 shellhelp[] = "invoke a subshell", 2279 envhelp[] = "change environment variables ('environ ?' for more)", 2280 modestring[] = "try to enter line or character mode ('mode ?' for more)"; 2281 2282static int help(int argc, char **argv); 2283 2284static Command cmdtab[] = { 2285 { "close", closehelp, bye, 1 }, 2286 { "logout", logouthelp, logout, 1 }, 2287 { "display", displayhelp, display, 0 }, 2288 { "mode", modestring, modecmd, 0 }, 2289 { "open", openhelp, tn, 0 }, 2290 { "quit", quithelp, quit, 0 }, 2291 { "send", sendhelp, sendcmd, 0 }, 2292 { "set", sethelp, setcmd, 0 }, 2293 { "unset", unsethelp, unsetcmd, 0 }, 2294 { "status", statushelp, status, 0 }, 2295 { "toggle", togglestring, toggle, 0 }, 2296 { "slc", slchelp, slccmd, 0 }, 2297#if defined(AUTHENTICATION) 2298 { "auth", authhelp, auth_cmd, 0 }, 2299#endif 2300#if defined(ENCRYPTION) 2301 { "encrypt", encrypthelp, encrypt_cmd, 0 }, 2302#endif 2303 { "z", zhelp, telnetsuspend, 0 }, 2304 { "!", shellhelp, shell, 0 }, 2305 { "environ", envhelp, env_cmd, 0 }, 2306 { "?", helphelp, help, 0 }, 2307 { 0, 0, 0, 0 } 2308}; 2309 2310static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 2311static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 2312 2313static Command cmdtab2[] = { 2314 { "help", 0, help, 0 }, 2315 { "escape", escapehelp, setescape, 0 }, 2316 { "crmod", crmodhelp, togcrmod, 0 }, 2317 { 0, 0, 0, 0 } 2318}; 2319 2320 2321/* 2322 * Call routine with argc, argv set from args (terminated by 0). 2323 */ 2324 2325static int 2326call(intrtn_t routine, ...) 2327{ 2328 va_list ap; 2329 char *args[100]; 2330 int argno = 0; 2331 2332 va_start(ap, routine); 2333 while ((args[argno++] = va_arg(ap, char *)) != 0); 2334 va_end(ap); 2335 return (*routine)(argno-1, args); 2336} 2337 2338 2339static Command 2340*getcmd(char *name) 2341{ 2342 Command *cm; 2343 2344 if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command)))) 2345 return cm; 2346 return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); 2347} 2348 2349void 2350command(int top, char *tbuf, int cnt) 2351{ 2352 Command *c; 2353 2354 setcommandmode(); 2355 if (!top) { 2356 putchar('\n'); 2357 } else { 2358 signal(SIGINT, SIG_DFL); 2359 signal(SIGQUIT, SIG_DFL); 2360 } 2361 for (;;) { 2362 if (rlogin == _POSIX_VDISABLE) 2363 printf("%s> ", prompt); 2364 if (tbuf) { 2365 char *cp; 2366 cp = line; 2367 while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 2368 cnt--; 2369 tbuf = 0; 2370 if (cp == line || *--cp != '\n' || cp == line) 2371 goto getline; 2372 *cp = '\0'; 2373 if (rlogin == _POSIX_VDISABLE) 2374 printf("%s\r\n", line); 2375 } else { 2376 getline: 2377 if (rlogin != _POSIX_VDISABLE) 2378 printf("%s> ", prompt); 2379 if (fgets(line, sizeof(line), stdin) == NULL) { 2380 if (feof(stdin) || ferror(stdin)) { 2381 quit(); 2382 /*NOTREACHED*/ 2383 } 2384 break; 2385 } 2386 } 2387 if (line[0] == 0) 2388 break; 2389 makeargv(); 2390 if (margv[0] == 0) { 2391 break; 2392 } 2393 c = getcmd(margv[0]); 2394 if (Ambiguous(c)) { 2395 printf("?Ambiguous command\r\n"); 2396 continue; 2397 } 2398 if (c == 0) { 2399 printf("?Invalid command\r\n"); 2400 continue; 2401 } 2402 if (c->needconnect && !connected) { 2403 printf("?Need to be connected first.\r\n"); 2404 continue; 2405 } 2406 if ((*c->handler)(margc, margv)) { 2407 break; 2408 } 2409 } 2410 if (!top) { 2411 if (!connected) { 2412 longjmp(toplevel, 1); 2413 /*NOTREACHED*/ 2414 } 2415 setconnmode(0); 2416 } 2417} 2418 2419/* 2420 * Help command. 2421 */ 2422static int 2423help(int argc, char **argv) 2424{ 2425 Command *c; 2426 2427 if (argc == 1) { 2428 printf("Commands may be abbreviated. Commands are:\r\n\r\n"); 2429 for (c = cmdtab; c->name; c++) 2430 if (c->help) { 2431 printf("%-*s\t%s\r\n", HELPINDENT, c->name, 2432 c->help); 2433 } 2434 return 0; 2435 } 2436 while (--argc > 0) { 2437 char *arg; 2438 arg = *++argv; 2439 c = getcmd(arg); 2440 if (Ambiguous(c)) 2441 printf("?Ambiguous help command %s\r\n", arg); 2442 else if (c == (Command *)0) 2443 printf("?Invalid help command %s\r\n", arg); 2444 else 2445 printf("%s\r\n", c->help); 2446 } 2447 return 0; 2448} 2449 2450 2451#if 0 /* XXX - broken */ 2452 2453#if defined(IP_OPTIONS) && defined(IPPROTO_IP) 2454 2455/* 2456 * Source route is handed in as 2457 * [!]@hop1@hop2...[@|:]dst 2458 * If the leading ! is present, it is a 2459 * strict source route, otherwise it is 2460 * assmed to be a loose source route. 2461 * 2462 * We fill in the source route option as 2463 * hop1,hop2,hop3...dest 2464 * and return a pointer to hop1, which will 2465 * be the address to connect() to. 2466 * 2467 * Arguments: 2468 * arg: pointer to route list to decipher 2469 * 2470 * cpp: If *cpp is not equal to NULL, this is a 2471 * pointer to a pointer to a character array 2472 * that should be filled in with the option. 2473 * 2474 * lenp: pointer to an integer that contains the 2475 * length of *cpp if *cpp != NULL. 2476 * 2477 * Return values: 2478 * 2479 * Returns the address of the host to connect to. If the 2480 * return value is -1, there was a syntax error in the 2481 * option, either unknown characters, or too many hosts. 2482 * If the return value is 0, one of the hostnames in the 2483 * path is unknown, and *cpp is set to point to the bad 2484 * hostname. 2485 * 2486 * *cpp: If *cpp was equal to NULL, it will be filled 2487 * in with a pointer to our static area that has 2488 * the option filled in. This will be 32bit aligned. 2489 * 2490 * *lenp: This will be filled in with how long the option 2491 * pointed to by *cpp is. 2492 * 2493 */ 2494unsigned long 2495sourceroute(char *arg, char **cpp, int *lenp) 2496{ 2497 static char lsr[44]; 2498 char *cp, *cp2, *lsrp, *lsrep; 2499 int tmp; 2500 struct in_addr sin_addr; 2501 struct hostent *host = 0; 2502 char c; 2503 2504 /* 2505 * Verify the arguments, and make sure we have 2506 * at least 7 bytes for the option. 2507 */ 2508 if (cpp == NULL || lenp == NULL) 2509 return((unsigned long)-1); 2510 if (*cpp != NULL && *lenp < 7) 2511 return((unsigned long)-1); 2512 /* 2513 * Decide whether we have a buffer passed to us, 2514 * or if we need to use our own static buffer. 2515 */ 2516 if (*cpp) { 2517 lsrp = *cpp; 2518 lsrep = lsrp + *lenp; 2519 } else { 2520 *cpp = lsrp = lsr; 2521 lsrep = lsrp + 44; 2522 } 2523 2524 cp = arg; 2525 2526 /* 2527 * Next, decide whether we have a loose source 2528 * route or a strict source route, and fill in 2529 * the begining of the option. 2530 */ 2531 if (*cp == '!') { 2532 cp++; 2533 *lsrp++ = IPOPT_SSRR; 2534 } else 2535 *lsrp++ = IPOPT_LSRR; 2536 2537 if (*cp != '@') 2538 return((unsigned long)-1); 2539 2540 lsrp++; /* skip over length, we'll fill it in later */ 2541 *lsrp++ = 4; 2542 2543 cp++; 2544 2545 sin_addr.s_addr = 0; 2546 2547 for (c = 0;;) { 2548 if (c == ':') 2549 cp2 = 0; 2550 else for (cp2 = cp; (c = *cp2); cp2++) { 2551 if (c == ',') { 2552 *cp2++ = '\0'; 2553 if (*cp2 == '@') 2554 cp2++; 2555 } else if (c == '@') { 2556 *cp2++ = '\0'; 2557 } else if (c == ':') { 2558 *cp2++ = '\0'; 2559 } else 2560 continue; 2561 break; 2562 } 2563 if (!c) 2564 cp2 = 0; 2565 2566 if ((tmp = inet_addr(cp)) != -1) { 2567 sin_addr.s_addr = tmp; 2568 } else if ((host = roken_gethostbyname(cp))) { 2569 memmove(&sin_addr, 2570 host->h_addr_list[0], 2571 sizeof(sin_addr)); 2572 } else { 2573 *cpp = cp; 2574 return(0); 2575 } 2576 memmove(lsrp, &sin_addr, 4); 2577 lsrp += 4; 2578 if (cp2) 2579 cp = cp2; 2580 else 2581 break; 2582 /* 2583 * Check to make sure there is space for next address 2584 */ 2585 if (lsrp + 4 > lsrep) 2586 return((unsigned long)-1); 2587 } 2588 if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) { 2589 *cpp = 0; 2590 *lenp = 0; 2591 return((unsigned long)-1); 2592 } 2593 *lsrp++ = IPOPT_NOP; /* 32 bit word align it */ 2594 *lenp = lsrp - *cpp; 2595 return(sin_addr.s_addr); 2596} 2597#endif 2598#endif 2599