1 /* $NetBSD: commands.c,v 1.67 2006/12/18 14:18:40 christos 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.67 2006/12/18 14:18:40 christos 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; 1363 long volatile err; /* Avoid vfork clobbering */ 1364 1365 setcommandmode(); 1366 1367 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1368 switch(vfork()) { 1369 case -1: 1370 perror("Fork failed"); 1371 break; 1372 1373 case 0: 1374 { 1375 /* 1376 * Fire up the shell in the child. 1377 */ 1378 char *shellp, *shellname; 1379 1380 shellp = getenv("SHELL"); 1381 if (shellp == NULL) 1382 shellp = "/bin/sh"; 1383 if ((shellname = strrchr(shellp, '/')) == 0) 1384 shellname = shellp; 1385 else 1386 shellname++; 1387 if (argc > 1) 1388 execl(shellp, shellname, "-c", &saveline[1], NULL); 1389 else 1390 execl(shellp, shellname, NULL); 1391 perror("execl"); 1392 _exit(1); 1393 } 1394 default: 1395 (void)wait((int *)0); /* Wait for the shell to complete */ 1396 1397 if (TerminalWindowSize(&newrows, &newcols) && connected && 1398 (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1399 sendnaws(); 1400 } 1401 break; 1402 } 1403 return 1; 1404 } 1405 #endif /* !defined(TN3270) */ 1406 1407 /*VARARGS*/ 1408 static int 1409 bye(int argc, char *argv[]) 1410 { 1411 extern int resettermname; 1412 1413 if (connected) { 1414 (void) shutdown(net, 2); 1415 printf("Connection closed.\n"); 1416 (void) NetClose(net); 1417 connected = 0; 1418 resettermname = 1; 1419 #if defined(AUTHENTICATION) || defined(ENCRYPTION) 1420 auth_encrypt_connect(connected); 1421 #endif /* defined(AUTHENTICATION) */ 1422 /* reset options */ 1423 tninit(); 1424 #ifdef TN3270 1425 SetIn3270(); /* Get out of 3270 mode */ 1426 #endif /* defined(TN3270) */ 1427 } 1428 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 1429 longjmp(toplevel, 1); 1430 /* NOTREACHED */ 1431 } 1432 return 1; /* Keep lint, etc., happy */ 1433 } 1434 1435 /*VARARGS*/ 1436 int 1437 quit(int argc, char *argv[]) 1438 { 1439 (void) call(bye, "bye", "fromquit", 0); 1440 Exit(0); 1441 /*NOTREACHED*/ 1442 } 1443 1444 /*VARARGS*/ 1445 int 1446 logout(int argc, char *argv[]) 1447 { 1448 send_do(TELOPT_LOGOUT, 1); 1449 (void) netflush(); 1450 return 1; 1451 } 1452 1453 1454 /* 1455 * The SLC command. 1456 */ 1457 1458 struct slclist { 1459 char *name; 1460 char *help; 1461 void (*handler)(int); 1462 int arg; 1463 }; 1464 1465 struct slclist SlcList[] = { 1466 { "export", "Use local special character definitions", 1467 slc_mode_export, 0 }, 1468 { "import", "Use remote special character definitions", 1469 slc_mode_import, 1 }, 1470 { "check", "Verify remote special character definitions", 1471 slc_mode_import, 0 }, 1472 { "help", 0, slc_help, 0 }, 1473 { "?", "Print help information", slc_help, 0 }, 1474 { 0 }, 1475 }; 1476 1477 static void 1478 slc_help(int n) 1479 { 1480 struct slclist *c; 1481 1482 for (c = SlcList; c->name; c++) { 1483 if (c->help) { 1484 if (*c->help) 1485 printf("%-15s %s\n", c->name, c->help); 1486 else 1487 printf("\n"); 1488 } 1489 } 1490 } 1491 1492 static struct slclist * 1493 getslc(char *name) 1494 { 1495 return (struct slclist *) 1496 genget(name, (char **) SlcList, sizeof(struct slclist)); 1497 } 1498 1499 static int 1500 slccmd(int argc, char *argv[]) 1501 { 1502 struct slclist *c; 1503 1504 if (argc != 2) { 1505 fprintf(stderr, 1506 "Need an argument to 'slc' command. 'slc ?' for help.\n"); 1507 return 0; 1508 } 1509 c = getslc(argv[1]); 1510 if (c == 0) { 1511 fprintf(stderr, "'%s': unknown argument ('slc ?' for help).\n", 1512 argv[1]); 1513 return 0; 1514 } 1515 if (Ambiguous(c)) { 1516 fprintf(stderr, "'%s': ambiguous argument ('slc ?' for help).\n", 1517 argv[1]); 1518 return 0; 1519 } 1520 (*c->handler)(c->arg); 1521 slcstate(); 1522 return 1; 1523 } 1524 1525 /* 1526 * The ENVIRON command. 1527 */ 1528 1529 struct envlist { 1530 char *name; 1531 char *help; 1532 struct env_lst *(*handler)(unsigned char *, unsigned char *); 1533 int narg; 1534 }; 1535 1536 struct envlist EnvList[] = { 1537 { "define", "Define an environment variable", 1538 env_define, 2 }, 1539 { "undefine", "Undefine an environment variable", 1540 env_undefine, 1 }, 1541 { "export", "Mark an environment variable for automatic export", 1542 env_export, 1 }, 1543 { "unexport", "Don't mark an environment variable for automatic export", 1544 env_unexport, 1 }, 1545 { "send", "Send an environment variable", env_send, 1 }, 1546 { "list", "List the current environment variables", 1547 env_list, 0 }, 1548 #if defined(OLD_ENVIRON) && defined(ENV_HACK) 1549 { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)", 1550 env_varval, 1 }, 1551 #endif 1552 { "help", 0, env_help, 0 }, 1553 { "?", "Print help information", env_help, 0 }, 1554 { 0 }, 1555 }; 1556 1557 static struct env_lst * 1558 env_help( unsigned char *us1, unsigned char *us2) 1559 { 1560 struct envlist *c; 1561 1562 for (c = EnvList; c->name; c++) { 1563 if (c->help) { 1564 if (*c->help) 1565 printf("%-15s %s\n", c->name, c->help); 1566 else 1567 printf("\n"); 1568 } 1569 } 1570 return NULL; 1571 } 1572 1573 static struct envlist * 1574 getenvcmd(char *name) 1575 { 1576 return (struct envlist *) 1577 genget(name, (char **) EnvList, sizeof(struct envlist)); 1578 } 1579 1580 int 1581 env_cmd(int argc, char *argv[]) 1582 { 1583 struct envlist *c; 1584 1585 if (argc < 2) { 1586 fprintf(stderr, 1587 "Need an argument to 'environ' command. 'environ ?' for help.\n"); 1588 return 0; 1589 } 1590 c = getenvcmd(argv[1]); 1591 if (c == 0) { 1592 fprintf(stderr, "'%s': unknown argument ('environ ?' for help).\n", 1593 argv[1]); 1594 return 0; 1595 } 1596 if (Ambiguous(c)) { 1597 fprintf(stderr, "'%s': ambiguous argument ('environ ?' for help).\n", 1598 argv[1]); 1599 return 0; 1600 } 1601 if (c->narg + 2 != argc) { 1602 fprintf(stderr, 1603 "Need %s%d argument%s to 'environ %s' command. 'environ ?' for help.\n", 1604 c->narg < argc + 2 ? "only " : "", 1605 c->narg, c->narg == 1 ? "" : "s", c->name); 1606 return 0; 1607 } 1608 (*c->handler)(argv[2], argv[3]); 1609 return 1; 1610 } 1611 1612 struct env_lst { 1613 struct env_lst *next; /* pointer to next structure */ 1614 struct env_lst *prev; /* pointer to previous structure */ 1615 unsigned char *var; /* pointer to variable name */ 1616 unsigned char *value; /* pointer to variable value */ 1617 int export; /* 1 -> export with default list of variables */ 1618 int welldefined; /* A well defined variable */ 1619 }; 1620 1621 struct env_lst envlisthead; 1622 1623 struct env_lst * 1624 env_find(unsigned char *var) 1625 { 1626 struct env_lst *ep; 1627 1628 for (ep = envlisthead.next; ep; ep = ep->next) { 1629 if (strcmp((char *)ep->var, (char *)var) == 0) 1630 return(ep); 1631 } 1632 return(NULL); 1633 } 1634 1635 void 1636 env_init(void) 1637 { 1638 extern char **environ; 1639 char **epp, *cp; 1640 struct env_lst *ep; 1641 1642 for (epp = environ; *epp; epp++) { 1643 if ((cp = strchr(*epp, '=')) != NULL) { 1644 *cp = '\0'; 1645 ep = env_define((unsigned char *)*epp, 1646 (unsigned char *)cp+1); 1647 ep->export = 0; 1648 *cp = '='; 1649 } 1650 } 1651 /* 1652 * Special case for DISPLAY variable. If it is ":0.0" or 1653 * "unix:0.0", we have to get rid of "unix" and insert our 1654 * hostname. 1655 */ 1656 if ((ep = env_find("DISPLAY")) 1657 && ((*ep->value == ':') 1658 || (strncmp((char *)ep->value, "unix:", 5) == 0))) { 1659 char hbuf[MAXHOSTNAMELEN + 1]; 1660 char *cp2 = strchr((char *)ep->value, ':'); 1661 1662 gethostname(hbuf, sizeof hbuf); 1663 hbuf[sizeof(hbuf) - 1] = '\0'; 1664 cp = (char *)malloc(strlen(hbuf) + strlen(cp2) + 1); 1665 sprintf((char *)cp, "%s%s", hbuf, cp2); 1666 free(ep->value); 1667 ep->value = (unsigned char *)cp; 1668 } 1669 /* 1670 * If USER is not defined, but LOGNAME is, then add 1671 * USER with the value from LOGNAME. By default, we 1672 * don't export the USER variable. 1673 */ 1674 if ((env_find("USER") == NULL) && (ep = env_find("LOGNAME"))) { 1675 env_define((unsigned char *)"USER", ep->value); 1676 env_unexport((unsigned char *)"USER", NULL); 1677 } 1678 env_export((unsigned char *)"DISPLAY", NULL); 1679 env_export((unsigned char *)"PRINTER", NULL); 1680 } 1681 1682 struct env_lst * 1683 env_define(unsigned char *var, unsigned char *value) 1684 { 1685 struct env_lst *ep; 1686 1687 if ((ep = env_find(var)) != NULL) { 1688 if (ep->var) 1689 free(ep->var); 1690 if (ep->value) 1691 free(ep->value); 1692 } else { 1693 ep = (struct env_lst *)malloc(sizeof(struct env_lst)); 1694 ep->next = envlisthead.next; 1695 envlisthead.next = ep; 1696 ep->prev = &envlisthead; 1697 if (ep->next) 1698 ep->next->prev = ep; 1699 } 1700 ep->welldefined = opt_welldefined(var); 1701 ep->export = 1; 1702 ep->var = (unsigned char *)strdup((char *)var); 1703 ep->value = (unsigned char *)strdup((char *)value); 1704 return(ep); 1705 } 1706 1707 struct env_lst * 1708 env_undefine(unsigned char *var, unsigned char *d) 1709 { 1710 struct env_lst *ep; 1711 1712 if ((ep = env_find(var)) != NULL) { 1713 ep->prev->next = ep->next; 1714 if (ep->next) 1715 ep->next->prev = ep->prev; 1716 if (ep->var) 1717 free(ep->var); 1718 if (ep->value) 1719 free(ep->value); 1720 free(ep); 1721 } 1722 return NULL; 1723 } 1724 1725 struct env_lst * 1726 env_export(unsigned char *var, unsigned char *d) 1727 { 1728 struct env_lst *ep; 1729 1730 if ((ep = env_find(var)) != NULL) 1731 ep->export = 1; 1732 return NULL; 1733 } 1734 1735 struct env_lst * 1736 env_unexport(unsigned char *var, unsigned char *d) 1737 { 1738 struct env_lst *ep; 1739 1740 if ((ep = env_find(var)) != NULL) 1741 ep->export = 0; 1742 return NULL; 1743 } 1744 1745 struct env_lst * 1746 env_send(unsigned char *var, unsigned char *d) 1747 { 1748 struct env_lst *ep; 1749 1750 if (my_state_is_wont(TELOPT_NEW_ENVIRON) 1751 #ifdef OLD_ENVIRON 1752 && my_state_is_wont(TELOPT_OLD_ENVIRON) 1753 #endif 1754 ) { 1755 fprintf(stderr, 1756 "Cannot send '%s': Telnet ENVIRON option not enabled\n", 1757 var); 1758 return NULL; 1759 } 1760 ep = env_find(var); 1761 if (ep == 0) { 1762 fprintf(stderr, "Cannot send '%s': variable not defined\n", 1763 var); 1764 return NULL; 1765 } 1766 env_opt_start_info(); 1767 env_opt_add(ep->var); 1768 env_opt_end(0); 1769 return NULL; 1770 } 1771 1772 struct env_lst * 1773 env_list(unsigned char *d1, unsigned char *d2) 1774 { 1775 struct env_lst *ep; 1776 1777 for (ep = envlisthead.next; ep; ep = ep->next) { 1778 printf("%c %-20s %s\n", ep->export ? '*' : ' ', 1779 ep->var, ep->value); 1780 } 1781 return NULL; 1782 } 1783 1784 unsigned char * 1785 env_default(int init, int welldefined) 1786 { 1787 static struct env_lst *nep = NULL; 1788 1789 if (init) { 1790 nep = &envlisthead; 1791 return NULL; 1792 } 1793 if (nep) { 1794 while ((nep = nep->next) != NULL) { 1795 if (nep->export && (nep->welldefined == welldefined)) 1796 return(nep->var); 1797 } 1798 } 1799 return(NULL); 1800 } 1801 1802 unsigned char * 1803 env_getvalue(unsigned char *var) 1804 { 1805 struct env_lst *ep; 1806 1807 if ((ep = env_find(var)) != NULL) 1808 return(ep->value); 1809 return(NULL); 1810 } 1811 1812 #if defined(OLD_ENVIRON) && defined(ENV_HACK) 1813 void 1814 env_varval(unsigned char *what) 1815 { 1816 extern int old_env_var, old_env_value, env_auto; 1817 int len = strlen((char *)what); 1818 1819 if (len == 0) 1820 goto unknown; 1821 1822 if (strncasecmp((char *)what, "status", len) == 0) { 1823 if (env_auto) 1824 printf("%s%s", "VAR and VALUE are/will be ", 1825 "determined automatically\n"); 1826 if (old_env_var == OLD_ENV_VAR) 1827 printf("VAR and VALUE set to correct definitions\n"); 1828 else 1829 printf("VAR and VALUE definitions are reversed\n"); 1830 } else if (strncasecmp((char *)what, "auto", len) == 0) { 1831 env_auto = 1; 1832 old_env_var = OLD_ENV_VALUE; 1833 old_env_value = OLD_ENV_VAR; 1834 } else if (strncasecmp((char *)what, "right", len) == 0) { 1835 env_auto = 0; 1836 old_env_var = OLD_ENV_VAR; 1837 old_env_value = OLD_ENV_VALUE; 1838 } else if (strncasecmp((char *)what, "wrong", len) == 0) { 1839 env_auto = 0; 1840 old_env_var = OLD_ENV_VALUE; 1841 old_env_value = OLD_ENV_VAR; 1842 } else { 1843 unknown: 1844 printf("Unknown \"varval\" command. (\"auto\", \"right\", \"wrong\", \"status\")\n"); 1845 } 1846 } 1847 #endif 1848 1849 #ifdef AUTHENTICATION 1850 /* 1851 * The AUTHENTICATE command. 1852 */ 1853 1854 struct authlist { 1855 char *name; 1856 char *help; 1857 int (*handler)(char *); 1858 int narg; 1859 }; 1860 1861 struct authlist AuthList[] = { 1862 { "status", "Display current status of authentication information", 1863 auth_status, 0 }, 1864 { "disable", "Disable an authentication type ('auth disable ?' for more)", 1865 auth_disable, 1 }, 1866 { "enable", "Enable an authentication type ('auth enable ?' for more)", 1867 auth_enable, 1 }, 1868 { "help", 0, auth_help, 0 }, 1869 { "?", "Print help information", auth_help, 0 }, 1870 { 0 }, 1871 }; 1872 1873 static int 1874 auth_help(char *s) 1875 { 1876 struct authlist *c; 1877 1878 for (c = AuthList; c->name; c++) { 1879 if (c->help) { 1880 if (*c->help) 1881 printf("%-15s %s\n", c->name, c->help); 1882 else 1883 printf("\n"); 1884 } 1885 } 1886 return 0; 1887 } 1888 1889 int 1890 auth_cmd(int argc, char *argv[]) 1891 { 1892 struct authlist *c; 1893 1894 if (argc < 2) { 1895 fprintf(stderr, 1896 "Need an argument to 'auth' command. 'auth ?' for help.\n"); 1897 return 0; 1898 } 1899 1900 c = (struct authlist *) 1901 genget(argv[1], (char **) AuthList, sizeof(struct authlist)); 1902 if (c == 0) { 1903 fprintf(stderr, "'%s': unknown argument ('auth ?' for help).\n", 1904 argv[1]); 1905 return 0; 1906 } 1907 if (Ambiguous(c)) { 1908 fprintf(stderr, "'%s': ambiguous argument ('auth ?' for help).\n", 1909 argv[1]); 1910 return 0; 1911 } 1912 if (c->narg + 2 != argc) { 1913 fprintf(stderr, 1914 "Need %s%d argument%s to 'auth %s' command. 'auth ?' for help.\n", 1915 c->narg < argc + 2 ? "only " : "", 1916 c->narg, c->narg == 1 ? "" : "s", c->name); 1917 return 0; 1918 } 1919 return((*c->handler)(argv[2])); 1920 } 1921 #endif 1922 1923 #ifdef ENCRYPTION 1924 /* 1925 * The ENCRYPT command. 1926 */ 1927 1928 struct encryptlist { 1929 char *name; 1930 char *help; 1931 int (*handler)(char *, char *); 1932 int needconnect; 1933 int minarg; 1934 int maxarg; 1935 }; 1936 1937 static int 1938 EncryptHelp(char *, char *); 1939 typedef int (*encrypthandler)(char *, char *); 1940 1941 struct encryptlist EncryptList[] = { 1942 { "enable", "Enable encryption. ('encrypt enable ?' for more)", 1943 EncryptEnable, 1, 1, 2 }, 1944 { "disable", "Disable encryption. ('encrypt enable ?' for more)", 1945 EncryptDisable, 0, 1, 2 }, 1946 { "type", "Set encryption type. ('encrypt type ?' for more)", 1947 EncryptType, 0, 1, 1 }, 1948 { "start", "Start encryption. ('encrypt start ?' for more)", 1949 (encrypthandler) EncryptStart, 1, 0, 1 }, 1950 { "stop", "Stop encryption. ('encrypt stop ?' for more)", 1951 (encrypthandler) EncryptStop, 1, 0, 1 }, 1952 { "input", "Start encrypting the input stream", 1953 (encrypthandler) EncryptStartInput, 1, 0, 0 }, 1954 { "-input", "Stop encrypting the input stream", 1955 (encrypthandler) EncryptStopInput, 1, 0, 0 }, 1956 { "output", "Start encrypting the output stream", 1957 (encrypthandler) EncryptStartOutput, 1, 0, 0 }, 1958 { "-output", "Stop encrypting the output stream", 1959 (encrypthandler) EncryptStopOutput, 1, 0, 0 }, 1960 1961 { "status", "Display current status of authentication information", 1962 (encrypthandler) EncryptStatus, 0, 0, 0 }, 1963 { "help", 0, EncryptHelp, 0, 0, 0 }, 1964 { "?", "Print help information", EncryptHelp, 0, 0, 0 }, 1965 { 0 }, 1966 }; 1967 1968 static int 1969 EncryptHelp(char *s1, char *s2) 1970 { 1971 struct encryptlist *c; 1972 1973 for (c = EncryptList; c->name; c++) { 1974 if (c->help) { 1975 if (*c->help) 1976 printf("%-15s %s\n", c->name, c->help); 1977 else 1978 printf("\n"); 1979 } 1980 } 1981 return (0); 1982 } 1983 1984 int 1985 encrypt_cmd(int argc, char *argv[]) 1986 { 1987 struct encryptlist *c; 1988 1989 if (argc < 2) { 1990 fprintf(stderr, 1991 "Need an argument to 'encrypt' command. " 1992 "'encrypt ?' for help.\n"); 1993 return (0); 1994 } 1995 1996 c = (struct encryptlist *) 1997 genget(argv[1], (char **) EncryptList, sizeof(struct encryptlist)); 1998 if (c == NULL) { 1999 fprintf(stderr, 2000 "'%s': unknown argument ('encrypt ?' for help).\n", 2001 argv[1]); 2002 return (0); 2003 } 2004 if (Ambiguous(c)) { 2005 fprintf(stderr, 2006 "'%s': ambiguous argument ('encrypt ?' for help).\n", 2007 argv[1]); 2008 return (0); 2009 } 2010 argc -= 2; 2011 if (argc < c->minarg || argc > c->maxarg) { 2012 if (c->minarg == c->maxarg) { 2013 fprintf(stderr, "Need %s%d argument%s ", 2014 c->minarg < argc ? "only " : "", c->minarg, 2015 c->minarg == 1 ? "" : "s"); 2016 } else { 2017 fprintf(stderr, "Need %s%d-%d arguments ", 2018 c->maxarg < argc ? "only " : "", c->minarg, 2019 c->maxarg); 2020 } 2021 fprintf(stderr, 2022 "to 'encrypt %s' command. 'encrypt ?' for help.\n", 2023 c->name); 2024 return (0); 2025 } 2026 if (c->needconnect && !connected) { 2027 if (!(argc && (isprefix(argv[2], "help") || 2028 isprefix(argv[2], "?")))) { 2029 printf("?Need to be connected first.\n"); 2030 return (0); 2031 } 2032 } 2033 return ((*c->handler)(argv[2], argv[3])); 2034 } 2035 #endif /* ENCRYPTION */ 2036 2037 #ifdef TN3270 2038 static void 2039 filestuff(int fd) 2040 { 2041 int res; 2042 2043 setconnmode(0); 2044 res = fcntl(fd, F_GETOWN, 0); 2045 setcommandmode(); 2046 2047 if (res == -1) { 2048 perror("fcntl"); 2049 return; 2050 } 2051 printf("\tOwner is %d.\n", res); 2052 2053 setconnmode(0); 2054 res = fcntl(fd, F_GETFL, 0); 2055 setcommandmode(); 2056 2057 if (res == -1) { 2058 perror("fcntl"); 2059 return; 2060 } 2061 #ifdef notdef 2062 printf("\tFlags are 0x%x: %s\n", res, decodeflags(res)); 2063 #endif 2064 } 2065 #endif /* defined(TN3270) */ 2066 2067 /* 2068 * Print status about the connection. 2069 */ 2070 /*ARGSUSED*/ 2071 static int 2072 status(int argc, char *argv[]) 2073 { 2074 if (connected) { 2075 printf("Connected to %s.\n", hostname); 2076 if ((argc < 2) || strcmp(argv[1], "notmuch")) { 2077 int mode = getconnmode(); 2078 2079 if (my_want_state_is_will(TELOPT_LINEMODE)) { 2080 printf("Operating with LINEMODE option\n"); 2081 printf("%s line editing\n", (mode&MODE_EDIT) ? "Local" : "No"); 2082 printf("%s catching of signals\n", 2083 (mode&MODE_TRAPSIG) ? "Local" : "No"); 2084 slcstate(); 2085 #ifdef KLUDGELINEMODE 2086 } else if (kludgelinemode && my_want_state_is_dont(TELOPT_SGA)) { 2087 printf("Operating in obsolete linemode\n"); 2088 #endif 2089 } else { 2090 printf("Operating in single character mode\n"); 2091 if (localchars) 2092 printf("Catching signals locally\n"); 2093 } 2094 printf("%s character echo\n", (mode&MODE_ECHO) ? "Local" : "Remote"); 2095 if (my_want_state_is_will(TELOPT_LFLOW)) 2096 printf("%s flow control\n", (mode&MODE_FLOW) ? "Local" : "No"); 2097 #ifdef ENCRYPTION 2098 encrypt_display(); 2099 #endif /* ENCRYPTION */ 2100 } 2101 } else { 2102 printf("No connection.\n"); 2103 } 2104 # ifndef TN3270 2105 printf("Escape character is '%s'.\n", control(escape)); 2106 (void) fflush(stdout); 2107 # else /* !defined(TN3270) */ 2108 if ((!In3270) && ((argc < 2) || strcmp(argv[1], "notmuch"))) { 2109 printf("Escape character is '%s'.\n", control(escape)); 2110 } 2111 if ((argc >= 2) && !strcmp(argv[1], "everything")) { 2112 printf("SIGIO received %d time%s.\n", 2113 sigiocount, (sigiocount == 1)? "":"s"); 2114 if (In3270) { 2115 printf("Process ID %d, process group %d.\n", 2116 getpid(), getpgrp()); 2117 printf("Terminal input:\n"); 2118 filestuff(tin); 2119 printf("Terminal output:\n"); 2120 filestuff(tout); 2121 printf("Network socket:\n"); 2122 filestuff(net); 2123 } 2124 } 2125 if (In3270 && transcom) { 2126 printf("Transparent mode command is '%s'.\n", transcom); 2127 } 2128 (void) fflush(stdout); 2129 if (In3270) { 2130 return 0; 2131 } 2132 # endif /* defined(TN3270) */ 2133 return 1; 2134 } 2135 2136 /* 2137 * Function that gets called when SIGINFO is received. 2138 */ 2139 int 2140 ayt_status(void) 2141 { 2142 return call(status, "status", "notmuch", 0); 2143 } 2144 2145 static const char * 2146 sockaddr_ntop(struct sockaddr *sa) 2147 { 2148 static char addrbuf[NI_MAXHOST]; 2149 const int niflags = NI_NUMERICHOST; 2150 2151 if (getnameinfo(sa, sa->sa_len, addrbuf, sizeof(addrbuf), 2152 NULL, 0, niflags) == 0) 2153 return addrbuf; 2154 else 2155 return NULL; 2156 } 2157 2158 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 2159 static int setpolicy (int, struct addrinfo *, char *); 2160 2161 static int 2162 setpolicy(int net, struct addrinfo *res, char *policy) 2163 { 2164 char *buf; 2165 int level; 2166 int optname; 2167 2168 if (policy == NULL) 2169 return 0; 2170 2171 buf = ipsec_set_policy(policy, strlen(policy)); 2172 if (buf == NULL) { 2173 printf("%s\n", ipsec_strerror()); 2174 return -1; 2175 } 2176 level = res->ai_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6; 2177 optname = res->ai_family == AF_INET ? IP_IPSEC_POLICY : IPV6_IPSEC_POLICY; 2178 if (setsockopt(net, level, optname, buf, ipsec_get_policylen(buf)) < 0){ 2179 perror("setsockopt"); 2180 return -1; 2181 } 2182 2183 free(buf); 2184 return 0; 2185 } 2186 #endif 2187 2188 int 2189 tn(int argc, char *argv[]) 2190 { 2191 struct addrinfo hints, *res, *res0; 2192 char *cause = "telnet: unknown"; 2193 int error; 2194 #if defined(IP_OPTIONS) && defined(IPPROTO_IP) 2195 char *srp = 0; 2196 unsigned long srlen; 2197 int proto, opt; 2198 #endif 2199 char *cmd, *hostp = 0, *portp = 0; 2200 const char *user = 0; 2201 2202 if (connected) { 2203 printf("?Already connected to %s\n", hostname); 2204 return 0; 2205 } 2206 if (argc < 2) { 2207 (void) strlcpy(line, "open ", sizeof(line)); 2208 printf("(to) "); 2209 (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin); 2210 makeargv(); 2211 argc = margc; 2212 argv = margv; 2213 } 2214 cmd = *argv; 2215 --argc; ++argv; 2216 while (argc) { 2217 if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?")) 2218 goto usage; 2219 if (strcmp(*argv, "-l") == 0) { 2220 --argc; ++argv; 2221 if (argc == 0) 2222 goto usage; 2223 user = *argv++; 2224 --argc; 2225 continue; 2226 } 2227 if (strcmp(*argv, "-a") == 0) { 2228 --argc; ++argv; 2229 autologin = 1; 2230 continue; 2231 } 2232 if (hostp == 0) { 2233 hostp = *argv++; 2234 --argc; 2235 continue; 2236 } 2237 if (portp == 0) { 2238 portp = *argv++; 2239 --argc; 2240 continue; 2241 } 2242 usage: 2243 printf("usage: %s [-l user] [-a] host-name [port]\n", cmd); 2244 return 0; 2245 } 2246 if (hostp == 0) 2247 goto usage; 2248 2249 (void) strlcpy(_hostname, hostp, sizeof(_hostname)); 2250 if (hostp[0] == '@' || hostp[0] == '!') { 2251 char *p; 2252 hostname = NULL; 2253 for (p = hostp + 1; *p; p++) { 2254 if (*p == ',' || *p == '@') 2255 hostname = p; 2256 } 2257 if (hostname == NULL) { 2258 fprintf(stderr, "%s: bad source route specification\n", hostp); 2259 return 0; 2260 } 2261 *hostname++ = '\0'; 2262 } else 2263 hostname = hostp; 2264 2265 if (!portp) { 2266 telnetport = 1; 2267 portp = "telnet"; 2268 } else if (portp[0] == '-') { 2269 /* use telnet negotiation if port number/name preceded by minus sign */ 2270 telnetport = 1; 2271 portp++; 2272 } else 2273 telnetport = 0; 2274 2275 memset(&hints, 0, sizeof(hints)); 2276 hints.ai_family = family; 2277 hints.ai_socktype = SOCK_STREAM; 2278 hints.ai_protocol = 0; 2279 hints.ai_flags = AI_NUMERICHOST; /* avoid forward lookup */ 2280 error = getaddrinfo(hostname, portp, &hints, &res0); 2281 if (!error) { 2282 /* numeric */ 2283 if (doaddrlookup && 2284 getnameinfo(res0->ai_addr, res0->ai_addrlen, 2285 _hostname, sizeof(_hostname), NULL, 0, NI_NAMEREQD) == 0) 2286 ; /* okay */ 2287 else 2288 strlcpy(_hostname, hostname, sizeof(_hostname)); 2289 } else { 2290 /* FQDN - try again with forward DNS lookup */ 2291 memset(&hints, 0, sizeof(hints)); 2292 hints.ai_family = family; 2293 hints.ai_socktype = SOCK_STREAM; 2294 hints.ai_protocol = 0; 2295 hints.ai_flags = AI_CANONNAME; 2296 error = getaddrinfo(hostname, portp, &hints, &res0); 2297 if (error == EAI_SERVICE) { 2298 fprintf(stderr, "tcp/%s: unknown service\n", portp); 2299 return 0; 2300 } else if (error) { 2301 fprintf(stderr, "%s: %s\n", hostname, gai_strerror(error)); 2302 return 0; 2303 } 2304 if (res0->ai_canonname) 2305 (void)strlcpy(_hostname, res0->ai_canonname, sizeof(_hostname)); 2306 else 2307 (void)strlcpy(_hostname, hostname, sizeof(_hostname)); 2308 } 2309 hostname = _hostname; 2310 2311 net = -1; 2312 for (res = res0; res; res = res->ai_next) { 2313 printf("Trying %s...\n", sockaddr_ntop(res->ai_addr)); 2314 net = socket(res->ai_family, res->ai_socktype, res->ai_protocol); 2315 if (net < 0) { 2316 cause = "telnet: socket"; 2317 continue; 2318 } 2319 2320 if (telnet_debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 2321 perror("setsockopt (SO_DEBUG)"); 2322 } 2323 if (hostp[0] == '@' || hostp[0] == '!') { 2324 if ((srlen = sourceroute(res, hostp, &srp, &proto, &opt)) < 0) { 2325 (void) NetClose(net); 2326 net = -1; 2327 continue; 2328 } 2329 if (srp && setsockopt(net, proto, opt, srp, srlen) < 0) 2330 perror("setsockopt (source route)"); 2331 } 2332 2333 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 2334 if (setpolicy(net, res, ipsec_policy_in) < 0) { 2335 (void) NetClose(net); 2336 net = -1; 2337 continue; 2338 } 2339 if (setpolicy(net, res, ipsec_policy_out) < 0) { 2340 (void) NetClose(net); 2341 net = -1; 2342 continue; 2343 } 2344 #endif 2345 2346 if (connect(net, res->ai_addr, res->ai_addrlen) < 0) { 2347 if (res->ai_next) { 2348 int oerrno = errno; 2349 2350 fprintf(stderr, "telnet: connect to address %s: ", 2351 sockaddr_ntop(res->ai_addr)); 2352 errno = oerrno; 2353 perror((char *)0); 2354 } 2355 cause = "telnet: Unable to connect to remote host"; 2356 (void) NetClose(net); 2357 net = -1; 2358 continue; 2359 } 2360 2361 connected++; 2362 #if defined(AUTHENTICATION) || defined(ENCRYPTION) 2363 auth_encrypt_connect(connected); 2364 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */ 2365 break; 2366 } 2367 freeaddrinfo(res0); 2368 if (net < 0 || connected == 0) { 2369 perror(cause); 2370 return 0; 2371 } 2372 2373 cmdrc(hostp, hostname); 2374 if (autologin && user == NULL) { 2375 struct passwd *pw; 2376 2377 user = getenv("USER"); 2378 if (user == NULL || 2379 ((pw = getpwnam(user)) && pw->pw_uid != getuid())) { 2380 if ((pw = getpwuid(getuid())) != NULL) 2381 user = pw->pw_name; 2382 else 2383 user = NULL; 2384 } 2385 } 2386 if (user) { 2387 env_define((unsigned char *)"USER", (unsigned char *)user); 2388 env_export((unsigned char *)"USER", NULL); 2389 } 2390 (void) call(status, "status", "notmuch", 0); 2391 telnet(user); 2392 (void) NetClose(net); 2393 ExitString("Connection closed by foreign host.\n",1); 2394 /*NOTREACHED*/ 2395 } 2396 2397 #define HELPINDENT ((int)sizeof ("connect")) 2398 2399 static char 2400 openhelp[] = "connect to a site", 2401 closehelp[] = "close current connection", 2402 logouthelp[] = "forcibly logout remote user and close the connection", 2403 quithelp[] = "exit telnet", 2404 statushelp[] = "print status information", 2405 helphelp[] = "print help information", 2406 sendhelp[] = "transmit special characters ('send ?' for more)", 2407 sethelp[] = "set operating parameters ('set ?' for more)", 2408 unsethelp[] = "unset operating parameters ('unset ?' for more)", 2409 togglestring[] ="toggle operating parameters ('toggle ?' for more)", 2410 slchelp[] = "change state of special characters ('slc ?' for more)", 2411 displayhelp[] = "display operating parameters", 2412 #ifdef TN3270 2413 transcomhelp[] = "specify Unix command for transparent mode pipe", 2414 #endif /* defined(TN3270) */ 2415 #ifdef AUTHENTICATION 2416 authhelp[] = "turn on (off) authentication ('auth ?' for more)", 2417 #endif 2418 #ifdef ENCRYPTION 2419 encrypthelp[] = "turn on (off) encryption ('encrypt ?' for more)", 2420 #endif /* ENCRYPTION */ 2421 zhelp[] = "suspend telnet", 2422 shellhelp[] = "invoke a subshell", 2423 envhelp[] = "change environment variables ('environ ?' for more)", 2424 modestring[] = "try to enter line or character mode ('mode ?' for more)"; 2425 2426 static Command cmdtab[] = { 2427 { "close", closehelp, bye, 1 }, 2428 { "logout", logouthelp, logout, 1 }, 2429 { "display", displayhelp, display, 0 }, 2430 { "mode", modestring, modecmd, 0 }, 2431 { "open", openhelp, tn, 0 }, 2432 { "quit", quithelp, quit, 0 }, 2433 { "send", sendhelp, sendcmd, 0 }, 2434 { "set", sethelp, setcmd, 0 }, 2435 { "unset", unsethelp, unsetcmd, 0 }, 2436 { "status", statushelp, status, 0 }, 2437 { "toggle", togglestring, toggle, 0 }, 2438 { "slc", slchelp, slccmd, 0 }, 2439 #ifdef TN3270 2440 { "transcom", transcomhelp, settranscom, 0 }, 2441 #endif /* defined(TN3270) */ 2442 #ifdef AUTHENTICATION 2443 { "auth", authhelp, auth_cmd, 0 }, 2444 #endif 2445 #ifdef ENCRYPTION 2446 { "encrypt", encrypthelp, encrypt_cmd, 0 }, 2447 #endif 2448 { "z", zhelp, suspend, 0 }, 2449 #ifdef TN3270 2450 { "!", shellhelp, shell, 1 }, 2451 #else 2452 { "!", shellhelp, shell, 0 }, 2453 #endif 2454 { "environ", envhelp, env_cmd, 0 }, 2455 { "?", helphelp, help, 0 }, 2456 { NULL, NULL, NULL, 0 } 2457 }; 2458 2459 static char crmodhelp[] = "deprecated command -- use 'toggle crmod' instead"; 2460 static char escapehelp[] = "deprecated command -- use 'set escape' instead"; 2461 2462 static Command cmdtab2[] = { 2463 { "help", 0, help, 0 }, 2464 { "escape", escapehelp, setescape, 0 }, 2465 { "crmod", crmodhelp, togcrmod, 0 }, 2466 { NULL, NULL, NULL, 0 } 2467 }; 2468 2469 2470 /* 2471 * Call routine with argc, argv set from args (terminated by 0). 2472 */ 2473 2474 /*VARARGS1*/ 2475 static int 2476 call(intrtn_t routine, ...) 2477 { 2478 va_list ap; 2479 char *args[100]; 2480 int argno = 0; 2481 2482 va_start(ap, routine); 2483 while ((args[argno++] = va_arg(ap, char *)) != 0) { 2484 ; 2485 } 2486 va_end(ap); 2487 return (*routine)(argno-1, args); 2488 } 2489 2490 2491 static Command * 2492 getcmd(char *name) 2493 { 2494 Command *cm; 2495 2496 if ((cm = (Command *) genget(name, (char **) cmdtab, sizeof(Command))) != NULL) 2497 return cm; 2498 return (Command *) genget(name, (char **) cmdtab2, sizeof(Command)); 2499 } 2500 2501 void 2502 command(int top, char *tbuf, int cnt) 2503 { 2504 Command *c; 2505 2506 setcommandmode(); 2507 if (!top) { 2508 putchar('\n'); 2509 } else { 2510 (void) signal(SIGINT, SIG_DFL); 2511 (void) signal(SIGQUIT, SIG_DFL); 2512 } 2513 for (;;) { 2514 if (rlogin == _POSIX_VDISABLE) 2515 printf("%s> ", prompt); 2516 if (tbuf) { 2517 char *cp; 2518 cp = line; 2519 while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 2520 cnt--; 2521 tbuf = 0; 2522 if (cp == line || *--cp != '\n' || cp == line) 2523 goto getline; 2524 *cp = '\0'; 2525 if (rlogin == _POSIX_VDISABLE) 2526 printf("%s\n", line); 2527 } else { 2528 getline: 2529 if (rlogin != _POSIX_VDISABLE) 2530 printf("%s> ", prompt); 2531 #ifdef TN3270 2532 fflush(stdout); 2533 #endif 2534 if (fgets(line, sizeof(line), stdin) == NULL) { 2535 if (feof(stdin) || ferror(stdin)) { 2536 (void) quit(0, NULL); 2537 /*NOTREACHED*/ 2538 } 2539 break; 2540 } 2541 } 2542 if (line[0] == 0) 2543 break; 2544 makeargv(); 2545 if (margv[0] == 0) { 2546 break; 2547 } 2548 c = getcmd(margv[0]); 2549 if (Ambiguous(c)) { 2550 printf("?Ambiguous command\n"); 2551 continue; 2552 } 2553 if (c == 0) { 2554 printf("?Invalid command\n"); 2555 continue; 2556 } 2557 if (c->needconnect && !connected) { 2558 printf("?Need to be connected first.\n"); 2559 continue; 2560 } 2561 if ((*c->handler)(margc, margv)) { 2562 break; 2563 } 2564 } 2565 if (!top) { 2566 if (!connected) { 2567 longjmp(toplevel, 1); 2568 /*NOTREACHED*/ 2569 } 2570 #ifdef TN3270 2571 if (shell_active == 0) { 2572 setconnmode(0); 2573 } 2574 #else /* defined(TN3270) */ 2575 setconnmode(0); 2576 #endif /* defined(TN3270) */ 2577 } 2578 } 2579 2580 /* 2581 * Help command. 2582 */ 2583 static int 2584 help(int argc, char *argv[]) 2585 { 2586 Command *c; 2587 2588 if (argc == 1) { 2589 printf("Commands may be abbreviated. Commands are:\n\n"); 2590 for (c = cmdtab; c->name; c++) 2591 if (c->help) { 2592 printf("%-*s\t%s\n", HELPINDENT, c->name, 2593 c->help); 2594 } 2595 return 0; 2596 } 2597 while (--argc > 0) { 2598 char *arg; 2599 arg = *++argv; 2600 c = getcmd(arg); 2601 if (Ambiguous(c)) 2602 printf("?Ambiguous help command %s\n", arg); 2603 else if (c == (Command *)0) 2604 printf("?Invalid help command %s\n", arg); 2605 else 2606 printf("%s\n", c->help); 2607 } 2608 return 0; 2609 } 2610 2611 static char *rcname = 0; 2612 static char rcbuf[128]; 2613 2614 void 2615 cmdrc(const char *m1, const char *m2) 2616 { 2617 Command *c; 2618 FILE *rcfile; 2619 int gotmachine = 0; 2620 int l1 = strlen(m1); 2621 int l2 = strlen(m2); 2622 char m1save[MAXHOSTNAMELEN + 1]; 2623 2624 if (skiprc) 2625 return; 2626 2627 strlcpy(m1save, m1, sizeof(m1save)); 2628 m1 = m1save; 2629 2630 if (rcname == 0) { 2631 rcname = getenv("HOME"); 2632 if (rcname) 2633 strlcpy(rcbuf, rcname, sizeof(rcbuf)); 2634 else 2635 rcbuf[0] = '\0'; 2636 strlcat(rcbuf, "/.telnetrc", sizeof(rcbuf)); 2637 rcname = rcbuf; 2638 } 2639 2640 if ((rcfile = fopen(rcname, "r")) == 0) { 2641 return; 2642 } 2643 2644 for (;;) { 2645 if (fgets(line, sizeof(line), rcfile) == NULL) 2646 break; 2647 if (line[0] == 0) 2648 break; 2649 if (line[0] == '#') 2650 continue; 2651 if (gotmachine) { 2652 if (!isspace((unsigned char)line[0])) 2653 gotmachine = 0; 2654 } 2655 if (gotmachine == 0) { 2656 if (isspace((unsigned char)line[0])) 2657 continue; 2658 if (strncasecmp(line, m1, l1) == 0) 2659 strncpy(line, &line[l1], sizeof(line) - l1); 2660 else if (strncasecmp(line, m2, l2) == 0) 2661 strncpy(line, &line[l2], sizeof(line) - l2); 2662 else if (strncasecmp(line, "DEFAULT", 7) == 0) 2663 strncpy(line, &line[7], sizeof(line) - 7); 2664 else 2665 continue; 2666 if (line[0] != ' ' && line[0] != '\t' && line[0] != '\n') 2667 continue; 2668 gotmachine = 1; 2669 } 2670 makeargv(); 2671 if (margv[0] == 0) 2672 continue; 2673 c = getcmd(margv[0]); 2674 if (Ambiguous(c)) { 2675 printf("?Ambiguous command: %s\n", margv[0]); 2676 continue; 2677 } 2678 if (c == 0) { 2679 printf("?Invalid command: %s\n", margv[0]); 2680 continue; 2681 } 2682 /* 2683 * This should never happen... 2684 */ 2685 if (c->needconnect && !connected) { 2686 printf("?Need to be connected first for %s.\n", margv[0]); 2687 continue; 2688 } 2689 (*c->handler)(margc, margv); 2690 } 2691 fclose(rcfile); 2692 } 2693 2694 /* 2695 * Source route is handed in as 2696 * [!]@hop1@hop2...@dst 2697 * 2698 * If the leading ! is present, it is a strict source route, otherwise it is 2699 * assmed to be a loose source route. Note that leading ! is effective 2700 * only for IPv4 case. 2701 * 2702 * We fill in the source route option as 2703 * hop1,hop2,hop3...dest 2704 * and return a pointer to hop1, which will 2705 * be the address to connect() to. 2706 * 2707 * Arguments: 2708 * ai: The address (by struct addrinfo) for the final destination. 2709 * 2710 * arg: Pointer to route list to decipher 2711 * 2712 * cpp: Pointer to a pointer, so that sourceroute() can return 2713 * the address of result buffer (statically alloc'ed). 2714 * 2715 * protop/optp: 2716 * Pointer to an integer. The pointed variable 2717 * lenp: pointer to an integer that contains the 2718 * length of *cpp if *cpp != NULL. 2719 * 2720 * Return values: 2721 * 2722 * Returns the length of the option pointed to by *cpp. If the 2723 * return value is -1, there was a syntax error in the 2724 * option, either arg contained unknown characters or too many hosts, 2725 * or hostname cannot be resolved. 2726 * 2727 * The caller needs to pass return value (len), *cpp, *protop and *optp 2728 * to setsockopt(2). 2729 * 2730 * *cpp: Points to the result buffer. The region is statically 2731 * allocated by the function. 2732 * 2733 * *protop: 2734 * protocol # to be passed to setsockopt(2). 2735 * 2736 * *optp: option # to be passed to setsockopt(2). 2737 * 2738 */ 2739 int 2740 sourceroute(struct addrinfo *ai, char *arg, char **cpp, int *protop, int *optp) 2741 { 2742 char *cp, *cp2, *lsrp, *lsrep; 2743 struct addrinfo hints, *res; 2744 int len, error; 2745 struct sockaddr_in *sin; 2746 char c; 2747 static char lsr[44]; 2748 #ifdef INET6 2749 struct cmsghdr *cmsg; 2750 struct sockaddr_in6 *sin6; 2751 static char rhbuf[1024]; 2752 #endif 2753 2754 /* 2755 * Verify the arguments. 2756 */ 2757 if (cpp == NULL) 2758 return -1; 2759 2760 cp = arg; 2761 2762 *cpp = NULL; 2763 2764 /* init these just in case.... */ 2765 lsrp = NULL; 2766 lsrep = NULL; 2767 #ifdef INET6 2768 cmsg = NULL; 2769 #endif 2770 2771 switch (ai->ai_family) { 2772 case AF_INET: 2773 lsrp = lsr; 2774 lsrep = lsrp + sizeof(lsr); 2775 2776 /* 2777 * Next, decide whether we have a loose source 2778 * route or a strict source route, and fill in 2779 * the begining of the option. 2780 */ 2781 if (*cp == '!') { 2782 cp++; 2783 *lsrp++ = IPOPT_SSRR; 2784 } else 2785 *lsrp++ = IPOPT_LSRR; 2786 if (*cp != '@') 2787 return -1; 2788 lsrp++; /* skip over length, we'll fill it in later */ 2789 *lsrp++ = 4; 2790 cp++; 2791 *protop = IPPROTO_IP; 2792 *optp = IP_OPTIONS; 2793 break; 2794 #ifdef INET6 2795 case AF_INET6: 2796 #ifdef IPV6_PKTOPTIONS 2797 /* RFC2292 */ 2798 cmsg = inet6_rthdr_init(rhbuf, IPV6_RTHDR_TYPE_0); 2799 if (*cp != '@') 2800 return -1; 2801 cp++; 2802 *protop = IPPROTO_IPV6; 2803 *optp = IPV6_PKTOPTIONS; 2804 break; 2805 #else 2806 /* no RFC2292 */ 2807 return -1; 2808 #endif 2809 #endif 2810 default: 2811 return -1; 2812 } 2813 2814 memset(&hints, 0, sizeof(hints)); 2815 hints.ai_family = ai->ai_family; 2816 hints.ai_socktype = SOCK_STREAM; 2817 2818 for (c = 0;;) { 2819 if (c == ':') 2820 cp2 = 0; 2821 else for (cp2 = cp; (c = *cp2) != '\0'; cp2++) { 2822 if (c == ',') { 2823 *cp2++ = '\0'; 2824 if (*cp2 == '@') 2825 cp2++; 2826 } else if (c == '@') { 2827 *cp2++ = '\0'; 2828 } 2829 #if 0 /*colon conflicts with IPv6 address*/ 2830 else if (c == ':') { 2831 *cp2++ = '\0'; 2832 } 2833 #endif 2834 else 2835 continue; 2836 break; 2837 } 2838 if (!c) 2839 cp2 = 0; 2840 2841 error = getaddrinfo(cp, NULL, &hints, &res); 2842 if (error) { 2843 fprintf(stderr, "%s: %s\n", cp, gai_strerror(error)); 2844 return -1; 2845 } 2846 if (ai->ai_family != res->ai_family) { 2847 freeaddrinfo(res); 2848 return -1; 2849 } 2850 if (ai->ai_family == AF_INET) { 2851 /* 2852 * Check to make sure there is space for address 2853 */ 2854 if (lsrp + 4 > lsrep) { 2855 freeaddrinfo(res); 2856 return -1; 2857 } 2858 sin = (struct sockaddr_in *)res->ai_addr; 2859 memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr)); 2860 lsrp += sizeof(struct in_addr); 2861 } 2862 #ifdef INET6 2863 else if (ai->ai_family == AF_INET6) { 2864 sin6 = (struct sockaddr_in6 *)res->ai_addr; 2865 inet6_rthdr_add(cmsg, &sin6->sin6_addr, 2866 IPV6_RTHDR_LOOSE); 2867 } 2868 #endif 2869 else { 2870 freeaddrinfo(res); 2871 return -1; 2872 } 2873 freeaddrinfo(res); 2874 if (cp2) 2875 cp = cp2; 2876 else 2877 break; 2878 } 2879 switch (ai->ai_family) { 2880 case AF_INET: 2881 /* record the last hop */ 2882 if (lsrp + 4 > lsrep) 2883 return -1; 2884 sin = (struct sockaddr_in *)ai->ai_addr; 2885 memcpy(lsrp, &sin->sin_addr, sizeof(struct in_addr)); 2886 lsrp += sizeof(struct in_addr); 2887 lsr[IPOPT_OLEN] = lsrp - lsr; 2888 if (lsr[IPOPT_OLEN] <= 7 || lsr[IPOPT_OLEN] > 40) 2889 return -1; 2890 *lsrp++ = IPOPT_NOP; /*32bit word align*/ 2891 len = lsrp - lsr; 2892 *cpp = lsr; 2893 break; 2894 #ifdef INET6 2895 case AF_INET6: 2896 inet6_rthdr_lasthop(cmsg, IPV6_RTHDR_LOOSE); 2897 len = cmsg->cmsg_len; 2898 *cpp = rhbuf; 2899 break; 2900 #endif 2901 default: 2902 return -1; 2903 } 2904 return len; 2905 } 2906