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