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