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