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