1 /* 2 * Copyright (c) 1988, 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 34 * Use is subject to license terms. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/file.h> 39 #include <sys/socket.h> 40 #include <sys/sysmacros.h> 41 #include <netinet/in.h> 42 43 #include <signal.h> 44 #include <netdb.h> 45 #include <ctype.h> 46 #include <pwd.h> 47 #include <errno.h> 48 #include <strings.h> 49 50 #include <arpa/telnet.h> 51 #include <arpa/inet.h> 52 53 #include "general.h" 54 55 #include "ring.h" 56 57 #include "externs.h" 58 #include "defines.h" 59 #include "types.h" 60 61 extern char *telnet_krb5_realm; 62 extern void krb5_profile_get_options(char *, char *, 63 profile_options_boolean*); 64 65 #include <k5-int.h> 66 #include <profile/prof_int.h> 67 68 profile_options_boolean config_file_options[] = { 69 { "forwardable", &forwardable_flag, 0}, 70 { "forward", &forward_flag, 0}, 71 { "encrypt", &encrypt_flag, 0 }, 72 { "autologin", &autologin, 0 }, 73 { NULL, NULL, 0} 74 }; 75 76 #include <netinet/ip.h> 77 78 /* 79 * Number of maximum IPv4 gateways user can specify. This number is limited by 80 * the maximum size of the IPv4 options in the IPv4 header. 81 */ 82 #define MAX_GATEWAY 8 83 /* 84 * Number of maximum IPv6 gateways user can specify. This number is limited by 85 * the maximum header extension length of the IPv6 routing header. 86 */ 87 #define MAX_GATEWAY6 127 88 #define MAXMAX_GATEWAY MAX(MAX_GATEWAY, MAX_GATEWAY6) 89 90 /* 91 * Depending on the address resolutions of the target and gateways, 92 * we determine which addresses of the target we'll try connecting to. 93 */ 94 #define ALL_ADDRS 0 /* try all addrs of target */ 95 #define ONLY_V4 1 /* try only IPv4 addrs of target */ 96 #define ONLY_V6 2 /* try only IPv6 addrs of target */ 97 98 #if defined(USE_TOS) 99 int tos = -1; 100 #endif 101 102 char *hostname; 103 static char _hostname[MAXHOSTNAMELEN]; 104 105 static int send_tncmd(void (*func)(), char *, char *); 106 static void call(int n_ptrs, ...); 107 static int cmdrc(char *, char *); 108 109 typedef struct { 110 char *name; /* command name */ 111 char *help; /* help string (NULL for no help) */ 112 int (*handler)(); /* routine which executes command */ 113 int needconnect; /* Do we need to be connected to execute? */ 114 } Command; 115 116 /* 117 * storage for IPv6 and/or IPv4 addresses of gateways 118 */ 119 struct gateway { 120 struct in6_addr gw_addr6; 121 struct in_addr gw_addr; 122 }; 123 124 /* 125 * IPv4 source routing option. 126 * In order to avoid padding for the alignment of IPv4 addresses, ipsr_addrs 127 * is defined as a 2-D array of uint8_t, instead of 1-D array of struct in_addr. 128 * If it were defined as "struct in_addr ipsr_addrs[1]", "ipsr_ptr" would be 129 * followed by one byte of padding to avoid misaligned struct in_addr. 130 */ 131 struct ip_sourceroute { 132 uint8_t ipsr_code; 133 uint8_t ipsr_len; 134 uint8_t ipsr_ptr; 135 /* up to 9 IPv4 addresses */ 136 uint8_t ipsr_addrs[1][sizeof (struct in_addr)]; 137 }; 138 139 static char *line = NULL; 140 static unsigned linesize = 0; 141 static int margc; 142 static char **margv = NULL; 143 static unsigned margvlen = 0; 144 static int doing_rc = 0; /* .telnetrc file is being read and processed */ 145 146 static void 147 Close(int *fd) 148 { 149 if (*fd != -1) { 150 (void) close(*fd); 151 *fd = -1; 152 } 153 } 154 155 static void 156 Free(char **p) 157 { 158 if (*p != NULL) { 159 free(*p); 160 *p = NULL; 161 } 162 } 163 164 static void 165 FreeHostnameList(char *list[]) 166 { 167 unsigned i; 168 for (i = 0; i <= MAXMAX_GATEWAY && list[i] != NULL; i++) 169 Free(&list[i]); 170 } 171 172 #define MARGV_CHUNK_SIZE 8 173 174 static void 175 set_argv(str) 176 char *str; 177 { 178 if (margc == margvlen) { 179 char **newmargv; 180 181 margvlen += MARGV_CHUNK_SIZE; 182 183 if ((newmargv = realloc(margv, margvlen * sizeof (char *))) 184 == NULL) 185 ExitString("telnet: no space for arguments", 186 EXIT_FAILURE); 187 188 margv = newmargv; 189 } 190 191 margv[margc] = str; 192 if (str != NULL) 193 margc++; 194 } 195 196 static void 197 makeargv() 198 { 199 char *cp, *cp2, c; 200 boolean_t shellcmd = B_FALSE; 201 202 margc = 0; 203 cp = line; 204 if (*cp == '!') { /* Special case shell escape */ 205 set_argv("!"); /* No room in string to get this */ 206 cp++; 207 shellcmd = B_TRUE; 208 } 209 while ((c = *cp) != '\0') { 210 int inquote = 0; 211 while (isspace(c)) 212 c = *++cp; 213 if (c == '\0') 214 break; 215 set_argv(cp); 216 /* 217 * For the shell escape, put the rest of the line, less 218 * leading space, into a single argument, breaking out from 219 * the loop to prevent the rest of the line being split up 220 * into smaller arguments. 221 */ 222 if (shellcmd) 223 break; 224 for (cp2 = cp; c != '\0'; c = *++cp) { 225 if (inquote) { 226 if (c == inquote) { 227 inquote = 0; 228 continue; 229 } 230 } else { 231 if (c == '\\') { 232 if ((c = *++cp) == '\0') 233 break; 234 } else if (c == '"') { 235 inquote = '"'; 236 continue; 237 } else if (c == '\'') { 238 inquote = '\''; 239 continue; 240 } else if (isspace(c)) 241 break; 242 } 243 *cp2++ = c; 244 } 245 *cp2 = '\0'; 246 if (c == '\0') 247 break; 248 cp++; 249 } 250 set_argv((char *)NULL); 251 } 252 253 /* 254 * Make a character string into a number. 255 * 256 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1). 257 */ 258 259 static int 260 special(char *s) 261 { 262 char c; 263 char b; 264 265 switch (*s) { 266 case '^': 267 b = *++s; 268 if (b == '?') { 269 c = b | 0x40; /* DEL */ 270 } else { 271 c = b & 0x1f; 272 } 273 break; 274 default: 275 c = *s; 276 break; 277 } 278 return (c); 279 } 280 281 /* 282 * Construct a control character sequence 283 * for a special character. 284 */ 285 static char * 286 control(cc_t c) 287 { 288 static char buf[5]; 289 /* 290 * The only way I could get the Sun 3.5 compiler 291 * to shut up about 292 * if ((unsigned int)c >= 0x80) 293 * was to assign "c" to an unsigned int variable... 294 * Arggg.... 295 */ 296 unsigned int uic = (unsigned int)c; 297 298 if (uic == 0x7f) 299 return ("^?"); 300 if (c == (cc_t)_POSIX_VDISABLE) { 301 return ("off"); 302 } 303 if (uic >= 0x80) { 304 buf[0] = '\\'; 305 buf[1] = ((c>>6)&07) + '0'; 306 buf[2] = ((c>>3)&07) + '0'; 307 buf[3] = (c&07) + '0'; 308 buf[4] = 0; 309 } else if (uic >= 0x20) { 310 buf[0] = c; 311 buf[1] = 0; 312 } else { 313 buf[0] = '^'; 314 buf[1] = '@'+c; 315 buf[2] = 0; 316 } 317 return (buf); 318 } 319 320 /* 321 * Same as control() except that its only used for escape handling, which uses 322 * _POSIX_VDISABLE differently and is aided by the use of the state variable 323 * escape_valid. 324 */ 325 static char * 326 esc_control(cc_t c) 327 { 328 static char buf[5]; 329 /* 330 * The only way I could get the Sun 3.5 compiler 331 * to shut up about 332 * if ((unsigned int)c >= 0x80) 333 * was to assign "c" to an unsigned int variable... 334 * Arggg.... 335 */ 336 unsigned int uic = (unsigned int)c; 337 338 if (escape_valid == B_FALSE) 339 return ("off"); 340 if (uic == 0x7f) 341 return ("^?"); 342 if (uic >= 0x80) { 343 buf[0] = '\\'; 344 buf[1] = ((c>>6)&07) + '0'; 345 buf[2] = ((c>>3)&07) + '0'; 346 buf[3] = (c&07) + '0'; 347 buf[4] = 0; 348 } else if (uic >= 0x20) { 349 buf[0] = c; 350 buf[1] = 0; 351 } else { 352 buf[0] = '^'; 353 buf[1] = '@'+c; 354 buf[2] = 0; 355 } 356 return (buf); 357 } 358 359 /* 360 * The following are data structures and routines for 361 * the "send" command. 362 * 363 */ 364 365 struct sendlist { 366 char *name; /* How user refers to it (case independent) */ 367 char *help; /* Help information (0 ==> no help) */ 368 int needconnect; /* Need to be connected */ 369 int narg; /* Number of arguments */ 370 int (*handler)(); /* Routine to perform (for special ops) */ 371 int nbyte; /* Number of bytes to send this command */ 372 int what; /* Character to be sent (<0 ==> special) */ 373 }; 374 375 376 static int send_esc(void); 377 static int send_help(void); 378 static int send_docmd(char *); 379 static int send_dontcmd(char *); 380 static int send_willcmd(char *); 381 static int send_wontcmd(char *); 382 383 static struct sendlist Sendlist[] = { 384 { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO }, 385 { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT }, 386 { "b", 0, 1, 0, 0, 2, BREAK }, 387 { "br", 0, 1, 0, 0, 2, BREAK }, 388 { "break", 0, 1, 0, 0, 2, BREAK }, 389 { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK }, 390 { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC }, 391 { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL }, 392 { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 }, 393 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA }, 394 { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP }, 395 { "intp", 0, 1, 0, 0, 2, IP }, 396 { "interrupt", 0, 1, 0, 0, 2, IP }, 397 { "intr", 0, 1, 0, 0, 2, IP }, 398 { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP }, 399 { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR }, 400 { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT }, 401 { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP }, 402 { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF }, 403 { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 }, 404 { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 }, 405 { "?", "Display send options", 0, 0, send_help, 0, 0 }, 406 { "help", 0, 0, 0, send_help, 0, 0 }, 407 { "do", 0, 0, 1, send_docmd, 3, 0 }, 408 { "dont", 0, 0, 1, send_dontcmd, 3, 0 }, 409 { "will", 0, 0, 1, send_willcmd, 3, 0 }, 410 { "wont", 0, 0, 1, send_wontcmd, 3, 0 }, 411 { 0 } 412 }; 413 414 #define GETSEND(name) ((struct sendlist *)genget(name, (char **)Sendlist, \ 415 sizeof (struct sendlist))) 416 417 static int 418 sendcmd(argc, argv) 419 int argc; 420 char **argv; 421 { 422 int count; /* how many bytes we are going to need to send */ 423 int i; 424 struct sendlist *s; /* pointer to current command */ 425 int success = 0; 426 int needconnect = 0; 427 428 if (argc < 2) { 429 (void) printf( 430 "need at least one argument for 'send' command\n"); 431 (void) printf("'send ?' for help\n"); 432 return (0); 433 } 434 /* 435 * First, validate all the send arguments. 436 * In addition, we see how much space we are going to need, and 437 * whether or not we will be doing a "SYNCH" operation (which 438 * flushes the network queue). 439 */ 440 count = 0; 441 for (i = 1; i < argc; i++) { 442 s = GETSEND(argv[i]); 443 if (s == 0) { 444 (void) printf("Unknown send argument '%s'\n'send ?' " 445 "for help.\n", argv[i]); 446 return (0); 447 } else if (Ambiguous(s)) { 448 (void) printf("Ambiguous send argument '%s'\n'send ?' " 449 "for help.\n", argv[i]); 450 return (0); 451 } 452 if (i + s->narg >= argc) { 453 (void) fprintf(stderr, 454 "Need %d argument%s to 'send %s' " 455 "command. 'send %s ?' for help.\n", 456 s->narg, s->narg == 1 ? "" : "s", s->name, s->name); 457 return (0); 458 } 459 count += s->nbyte; 460 if (s->handler == send_help) { 461 (void) send_help(); 462 return (0); 463 } 464 465 i += s->narg; 466 needconnect += s->needconnect; 467 } 468 if (!connected && needconnect) { 469 (void) printf("?Need to be connected first.\n"); 470 (void) printf("'send ?' for help\n"); 471 return (0); 472 } 473 /* Now, do we have enough room? */ 474 if (NETROOM() < count) { 475 (void) printf("There is not enough room in the buffer " 476 "TO the network\n"); 477 (void) printf( 478 "to process your request. Nothing will be done.\n"); 479 (void) printf("('send synch' will throw away most " 480 "data in the network\n"); 481 (void) printf("buffer, if this might help.)\n"); 482 return (0); 483 } 484 /* OK, they are all OK, now go through again and actually send */ 485 count = 0; 486 for (i = 1; i < argc; i++) { 487 if ((s = GETSEND(argv[i])) == 0) { 488 (void) fprintf(stderr, 489 "Telnet 'send' error - argument disappeared!\n"); 490 (void) quit(); 491 /*NOTREACHED*/ 492 } 493 if (s->handler) { 494 count++; 495 success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0, 496 (s->narg > 1) ? argv[i+2] : 0); 497 i += s->narg; 498 } else { 499 NET2ADD(IAC, s->what); 500 printoption("SENT", IAC, s->what); 501 } 502 } 503 return (count == success); 504 } 505 506 static int 507 send_esc() 508 { 509 NETADD(escape); 510 return (1); 511 } 512 513 static int 514 send_docmd(name) 515 char *name; 516 { 517 return (send_tncmd(send_do, "do", name)); 518 } 519 520 static int 521 send_dontcmd(name) 522 char *name; 523 { 524 return (send_tncmd(send_dont, "dont", name)); 525 } 526 527 static int 528 send_willcmd(name) 529 char *name; 530 { 531 return (send_tncmd(send_will, "will", name)); 532 } 533 534 static int 535 send_wontcmd(name) 536 char *name; 537 { 538 return (send_tncmd(send_wont, "wont", name)); 539 } 540 541 int 542 send_tncmd(void (*func)(), char *cmd, char *name) 543 { 544 char **cpp; 545 extern char *telopts[]; 546 int val = 0; 547 548 if (isprefix(name, "help") || isprefix(name, "?")) { 549 int col, len; 550 551 (void) printf("Usage: send %s <value|option>\n", cmd); 552 (void) printf("\"value\" must be from 0 to 255\n"); 553 (void) printf("Valid options are:\n\t"); 554 555 col = 8; 556 for (cpp = telopts; *cpp; cpp++) { 557 len = strlen(*cpp) + 3; 558 if (col + len > 65) { 559 (void) printf("\n\t"); 560 col = 8; 561 } 562 (void) printf(" \"%s\"", *cpp); 563 col += len; 564 } 565 (void) printf("\n"); 566 return (0); 567 } 568 cpp = (char **)genget(name, telopts, sizeof (char *)); 569 if (Ambiguous(cpp)) { 570 (void) fprintf(stderr, 571 "'%s': ambiguous argument ('send %s ?' for help).\n", 572 name, cmd); 573 return (0); 574 } 575 if (cpp) { 576 val = cpp - telopts; 577 } else { 578 char *cp = name; 579 580 while (*cp >= '0' && *cp <= '9') { 581 val *= 10; 582 val += *cp - '0'; 583 cp++; 584 } 585 if (*cp != 0) { 586 (void) fprintf(stderr, 587 "'%s': unknown argument ('send %s ?' for help).\n", 588 name, cmd); 589 return (0); 590 } else if (val < 0 || val > 255) { 591 (void) fprintf(stderr, 592 "'%s': bad value ('send %s ?' for help).\n", 593 name, cmd); 594 return (0); 595 } 596 } 597 if (!connected) { 598 (void) printf("?Need to be connected first.\n"); 599 return (0); 600 } 601 (*func)(val, 1); 602 return (1); 603 } 604 605 static int 606 send_help() 607 { 608 struct sendlist *s; /* pointer to current command */ 609 for (s = Sendlist; s->name; s++) { 610 if (s->help) 611 (void) printf("%-15s %s\n", s->name, s->help); 612 } 613 return (0); 614 } 615 616 /* 617 * The following are the routines and data structures referred 618 * to by the arguments to the "toggle" command. 619 */ 620 621 static int 622 lclchars() 623 { 624 donelclchars = 1; 625 return (1); 626 } 627 628 static int 629 togdebug() 630 { 631 if (net > 0 && 632 (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) { 633 perror("setsockopt (SO_DEBUG)"); 634 } 635 return (1); 636 } 637 638 639 static int 640 togcrlf() 641 { 642 if (crlf) { 643 (void) printf( 644 "Will send carriage returns as telnet <CR><LF>.\n"); 645 } else { 646 (void) printf( 647 "Will send carriage returns as telnet <CR><NUL>.\n"); 648 } 649 return (1); 650 } 651 652 static int binmode; 653 654 static int 655 togbinary(val) 656 int val; 657 { 658 donebinarytoggle = 1; 659 660 if (val >= 0) { 661 binmode = val; 662 } else { 663 if (my_want_state_is_will(TELOPT_BINARY) && 664 my_want_state_is_do(TELOPT_BINARY)) { 665 binmode = 1; 666 } else if (my_want_state_is_wont(TELOPT_BINARY) && 667 my_want_state_is_dont(TELOPT_BINARY)) { 668 binmode = 0; 669 } 670 val = binmode ? 0 : 1; 671 } 672 673 if (val == 1) { 674 if (my_want_state_is_will(TELOPT_BINARY) && 675 my_want_state_is_do(TELOPT_BINARY)) { 676 (void) printf("Already operating in binary mode " 677 "with remote host.\n"); 678 } else { 679 (void) printf( 680 "Negotiating binary mode with remote host.\n"); 681 tel_enter_binary(3); 682 } 683 } else { 684 if (my_want_state_is_wont(TELOPT_BINARY) && 685 my_want_state_is_dont(TELOPT_BINARY)) { 686 (void) printf("Already in network ascii mode " 687 "with remote host.\n"); 688 } else { 689 (void) printf("Negotiating network ascii mode " 690 "with remote host.\n"); 691 tel_leave_binary(3); 692 } 693 } 694 return (1); 695 } 696 697 static int 698 togrbinary(val) 699 int val; 700 { 701 donebinarytoggle = 1; 702 703 if (val == -1) 704 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1; 705 706 if (val == 1) { 707 if (my_want_state_is_do(TELOPT_BINARY)) { 708 (void) printf("Already receiving in binary mode.\n"); 709 } else { 710 (void) printf("Negotiating binary mode on input.\n"); 711 tel_enter_binary(1); 712 } 713 } else { 714 if (my_want_state_is_dont(TELOPT_BINARY)) { 715 (void) printf( 716 "Already receiving in network ascii mode.\n"); 717 } else { 718 (void) printf( 719 "Negotiating network ascii mode on input.\n"); 720 tel_leave_binary(1); 721 } 722 } 723 return (1); 724 } 725 726 static int 727 togxbinary(val) 728 int val; 729 { 730 donebinarytoggle = 1; 731 732 if (val == -1) 733 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1; 734 735 if (val == 1) { 736 if (my_want_state_is_will(TELOPT_BINARY)) { 737 (void) printf("Already transmitting in binary mode.\n"); 738 } else { 739 (void) printf("Negotiating binary mode on output.\n"); 740 tel_enter_binary(2); 741 } 742 } else { 743 if (my_want_state_is_wont(TELOPT_BINARY)) { 744 (void) printf( 745 "Already transmitting in network ascii mode.\n"); 746 } else { 747 (void) printf( 748 "Negotiating network ascii mode on output.\n"); 749 tel_leave_binary(2); 750 } 751 } 752 return (1); 753 } 754 755 756 static int togglehelp(void); 757 extern int auth_togdebug(int); 758 759 struct togglelist { 760 char *name; /* name of toggle */ 761 char *help; /* help message */ 762 int (*handler)(); /* routine to do actual setting */ 763 int *variable; 764 char *actionexplanation; 765 }; 766 767 static struct togglelist Togglelist[] = { 768 { "autoflush", 769 "flushing of output when sending interrupt characters", 770 0, 771 &autoflush, 772 "flush output when sending interrupt characters" }, 773 { "autosynch", 774 "automatic sending of interrupt characters in urgent mode", 775 0, 776 &autosynch, 777 "send interrupt characters in urgent mode" }, 778 { "autologin", 779 "automatic sending of login and/or authentication info", 780 0, 781 &autologin, 782 "send login name and/or authentication information" }, 783 { "authdebug", 784 "authentication debugging", 785 auth_togdebug, 786 0, 787 "print authentication debugging information" }, 788 { "autoencrypt", 789 "automatic encryption of data stream", 790 EncryptAutoEnc, 791 0, 792 "automatically encrypt output" }, 793 { "autodecrypt", 794 "automatic decryption of data stream", 795 EncryptAutoDec, 796 0, 797 "automatically decrypt input" }, 798 { "verbose_encrypt", 799 "verbose encryption output", 800 EncryptVerbose, 801 0, 802 "print verbose encryption output" }, 803 { "encdebug", 804 "encryption debugging", 805 EncryptDebug, 806 0, 807 "print encryption debugging information" }, 808 { "skiprc", 809 "don't read ~/.telnetrc file", 810 0, 811 &skiprc, 812 "skip reading of ~/.telnetrc file" }, 813 { "binary", 814 "sending and receiving of binary data", 815 togbinary, 816 0, 817 0 }, 818 { "inbinary", 819 "receiving of binary data", 820 togrbinary, 821 0, 822 0 }, 823 { "outbinary", 824 "sending of binary data", 825 togxbinary, 826 0, 827 0 }, 828 { "crlf", 829 "sending carriage returns as telnet <CR><LF>", 830 togcrlf, 831 &crlf, 832 0 }, 833 { "crmod", 834 "mapping of received carriage returns", 835 0, 836 &crmod, 837 "map carriage return on output" }, 838 { "localchars", 839 "local recognition of certain control characters", 840 lclchars, 841 &localchars, 842 "recognize certain control characters" }, 843 { " ", "", 0 }, /* empty line */ 844 { "debug", 845 "debugging", 846 togdebug, 847 &debug, 848 "turn on socket level debugging" }, 849 { "netdata", 850 "printing of hexadecimal network data (debugging)", 851 0, 852 &netdata, 853 "print hexadecimal representation of network traffic" }, 854 { "prettydump", 855 "output of \"netdata\" to user readable format (debugging)", 856 0, 857 &prettydump, 858 "print user readable output for \"netdata\"" }, 859 { "options", 860 "viewing of options processing (debugging)", 861 0, 862 &showoptions, 863 "show option processing" }, 864 { "termdata", 865 "(debugging) toggle printing of hexadecimal terminal data", 866 0, 867 &termdata, 868 "print hexadecimal representation of terminal traffic" }, 869 { "?", 870 0, 871 togglehelp }, 872 { "help", 873 0, 874 togglehelp }, 875 { 0 } 876 }; 877 878 static int 879 togglehelp() 880 { 881 struct togglelist *c; 882 883 for (c = Togglelist; c->name; c++) { 884 if (c->help) { 885 if (*c->help) 886 (void) printf( 887 "%-15s toggle %s\n", c->name, c->help); 888 else 889 (void) printf("\n"); 890 } 891 } 892 (void) printf("\n"); 893 (void) printf("%-15s %s\n", "?", "display help information"); 894 return (0); 895 } 896 897 static void 898 settogglehelp(set) 899 int set; 900 { 901 struct togglelist *c; 902 903 for (c = Togglelist; c->name; c++) { 904 if (c->help) { 905 if (*c->help) 906 (void) printf("%-15s %s %s\n", c->name, 907 set ? "enable" : "disable", c->help); 908 else 909 (void) printf("\n"); 910 } 911 } 912 } 913 914 #define GETTOGGLE(name) (struct togglelist *) \ 915 genget(name, (char **)Togglelist, sizeof (struct togglelist)) 916 917 static int 918 toggle(argc, argv) 919 int argc; 920 char *argv[]; 921 { 922 int retval = 1; 923 char *name; 924 struct togglelist *c; 925 926 if (argc < 2) { 927 (void) fprintf(stderr, 928 "Need an argument to 'toggle' command. " 929 "'toggle ?' for help.\n"); 930 return (0); 931 } 932 argc--; 933 argv++; 934 while (argc--) { 935 name = *argv++; 936 c = GETTOGGLE(name); 937 if (Ambiguous(c)) { 938 (void) fprintf(stderr, "'%s': ambiguous argument " 939 "('toggle ?' for help).\n", name); 940 return (0); 941 } else if (c == 0) { 942 (void) fprintf(stderr, "'%s': unknown argument " 943 "('toggle ?' for help).\n", name); 944 return (0); 945 } else { 946 if (c->variable) { 947 *c->variable = !*c->variable; /* invert it */ 948 if (c->actionexplanation) { 949 (void) printf("%s %s.\n", 950 *c->variable ? "Will" : "Won't", 951 c->actionexplanation); 952 } 953 } 954 if (c->handler) { 955 retval &= (*c->handler)(-1); 956 } 957 } 958 } 959 return (retval); 960 } 961 962 /* 963 * The following perform the "set" command. 964 */ 965 966 #ifdef USE_TERMIO 967 struct termio new_tc = { 0 }; 968 #endif 969 970 struct setlist { 971 char *name; /* name */ 972 char *help; /* help information */ 973 void (*handler)(); 974 cc_t *charp; /* where it is located at */ 975 }; 976 977 static struct setlist Setlist[] = { 978 #ifdef KLUDGELINEMODE 979 { "echo", "character to toggle local echoing on/off", 0, &echoc }, 980 #endif 981 { "escape", "character to escape back to telnet command mode", 0, 982 &escape }, 983 { "rlogin", "rlogin escape character", 0, &rlogin }, 984 { "tracefile", "file to write trace information to", SetNetTrace, 985 (cc_t *)NetTraceFile}, 986 { " ", "" }, 987 { " ", "The following need 'localchars' to be toggled true", 0, 0 }, 988 { "flushoutput", "character to cause an Abort Output", 0, 989 termFlushCharp }, 990 { "interrupt", "character to cause an Interrupt Process", 0, 991 termIntCharp }, 992 { "quit", "character to cause an Abort process", 0, termQuitCharp }, 993 { "eof", "character to cause an EOF ", 0, termEofCharp }, 994 { " ", "" }, 995 { " ", "The following are for local editing in linemode", 0, 0 }, 996 { "erase", "character to use to erase a character", 0, termEraseCharp }, 997 { "kill", "character to use to erase a line", 0, termKillCharp }, 998 { "lnext", "character to use for literal next", 0, 999 termLiteralNextCharp }, 1000 { "susp", "character to cause a Suspend Process", 0, termSuspCharp }, 1001 { "reprint", "character to use for line reprint", 0, termRprntCharp }, 1002 { "worderase", "character to use to erase a word", 0, termWerasCharp }, 1003 { "start", "character to use for XON", 0, termStartCharp }, 1004 { "stop", "character to use for XOFF", 0, termStopCharp }, 1005 { "forw1", "alternate end of line character", 0, termForw1Charp }, 1006 { "forw2", "alternate end of line character", 0, termForw2Charp }, 1007 { "ayt", "alternate AYT character", 0, termAytCharp }, 1008 { 0 } 1009 }; 1010 1011 static struct setlist * 1012 getset(name) 1013 char *name; 1014 { 1015 return ((struct setlist *) 1016 genget(name, (char **)Setlist, sizeof (struct setlist))); 1017 } 1018 1019 void 1020 set_escape_char(s) 1021 char *s; 1022 { 1023 if (rlogin != _POSIX_VDISABLE) { 1024 rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE; 1025 (void) printf("Telnet rlogin escape character is '%s'.\n", 1026 control(rlogin)); 1027 } else { 1028 escape = (s && *s) ? special(s) : _POSIX_VDISABLE; 1029 (void) printf("Telnet escape character is '%s'.\n", 1030 esc_control(escape)); 1031 } 1032 } 1033 1034 static int 1035 setcmd(argc, argv) 1036 int argc; 1037 char *argv[]; 1038 { 1039 int value; 1040 struct setlist *ct; 1041 struct togglelist *c; 1042 1043 if (argc < 2 || argc > 3) { 1044 (void) printf( 1045 "Format is 'set Name Value'\n'set ?' for help.\n"); 1046 return (0); 1047 } 1048 if ((argc == 2) && 1049 (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) { 1050 for (ct = Setlist; ct->name; ct++) 1051 (void) printf("%-15s %s\n", ct->name, ct->help); 1052 (void) printf("\n"); 1053 settogglehelp(1); 1054 (void) printf("%-15s %s\n", "?", "display help information"); 1055 return (0); 1056 } 1057 1058 ct = getset(argv[1]); 1059 if (ct == 0) { 1060 c = GETTOGGLE(argv[1]); 1061 if (c == 0) { 1062 (void) fprintf(stderr, "'%s': unknown argument " 1063 "('set ?' for help).\n", argv[1]); 1064 return (0); 1065 } else if (Ambiguous(c)) { 1066 (void) fprintf(stderr, "'%s': ambiguous argument " 1067 "('set ?' for help).\n", argv[1]); 1068 return (0); 1069 } 1070 if (c->variable) { 1071 if ((argc == 2) || (strcmp("on", argv[2]) == 0)) 1072 *c->variable = 1; 1073 else if (strcmp("off", argv[2]) == 0) 1074 *c->variable = 0; 1075 else { 1076 (void) printf( 1077 "Format is 'set togglename [on|off]'\n" 1078 "'set ?' for help.\n"); 1079 return (0); 1080 } 1081 if (c->actionexplanation) { 1082 (void) printf("%s %s.\n", 1083 *c->variable? "Will" : "Won't", 1084 c->actionexplanation); 1085 } 1086 } 1087 if (c->handler) 1088 (*c->handler)(1); 1089 } else if (argc != 3) { 1090 (void) printf( 1091 "Format is 'set Name Value'\n'set ?' for help.\n"); 1092 return (0); 1093 } else if (Ambiguous(ct)) { 1094 (void) fprintf(stderr, 1095 "'%s': ambiguous argument ('set ?' for help).\n", argv[1]); 1096 return (0); 1097 } else if (ct->handler) { 1098 (*ct->handler)(argv[2]); 1099 (void) printf( 1100 "%s set to \"%s\".\n", ct->name, (char *)ct->charp); 1101 } else { 1102 if (strcmp("off", argv[2])) { 1103 value = special(argv[2]); 1104 } else { 1105 value = _POSIX_VDISABLE; 1106 } 1107 *(ct->charp) = (cc_t)value; 1108 (void) printf("%s character is '%s'.\n", ct->name, 1109 control(*(ct->charp))); 1110 } 1111 slc_check(); 1112 return (1); 1113 } 1114 1115 static int 1116 unsetcmd(int argc, char *argv[]) 1117 { 1118 struct setlist *ct; 1119 struct togglelist *c; 1120 char *name; 1121 1122 if (argc < 2) { 1123 (void) fprintf(stderr, "Need an argument to 'unset' command. " 1124 "'unset ?' for help.\n"); 1125 return (0); 1126 } 1127 if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) { 1128 for (ct = Setlist; ct->name; ct++) 1129 (void) printf("%-15s %s\n", ct->name, ct->help); 1130 (void) printf("\n"); 1131 settogglehelp(0); 1132 (void) printf("%-15s %s\n", "?", "display help information"); 1133 return (0); 1134 } 1135 1136 argc--; 1137 argv++; 1138 while (argc--) { 1139 name = *argv++; 1140 ct = getset(name); 1141 if (ct == 0) { 1142 c = GETTOGGLE(name); 1143 if (c == 0) { 1144 (void) fprintf(stderr, "'%s': unknown argument " 1145 "('unset ?' for help).\n", name); 1146 return (0); 1147 } else if (Ambiguous(c)) { 1148 (void) fprintf(stderr, 1149 "'%s': ambiguous argument " 1150 "('unset ?' for help).\n", name); 1151 return (0); 1152 } 1153 if (c->variable) { 1154 *c->variable = 0; 1155 if (c->actionexplanation) { 1156 (void) printf("%s %s.\n", 1157 *c->variable? "Will" : "Won't", 1158 c->actionexplanation); 1159 } 1160 } 1161 if (c->handler) 1162 (*c->handler)(0); 1163 } else if (Ambiguous(ct)) { 1164 (void) fprintf(stderr, "'%s': ambiguous argument " 1165 "('unset ?' for help).\n", name); 1166 return (0); 1167 } else if (ct->handler) { 1168 (*ct->handler)(0); 1169 (void) printf("%s reset to \"%s\".\n", ct->name, 1170 (char *)ct->charp); 1171 } else { 1172 *(ct->charp) = _POSIX_VDISABLE; 1173 (void) printf("%s character is '%s'.\n", ct->name, 1174 control(*(ct->charp))); 1175 } 1176 } 1177 return (1); 1178 } 1179 1180 /* 1181 * The following are the data structures and routines for the 1182 * 'mode' command. 1183 */ 1184 extern int reqd_linemode; 1185 1186 #ifdef KLUDGELINEMODE 1187 extern int kludgelinemode; 1188 1189 static int 1190 dokludgemode() 1191 { 1192 kludgelinemode = 1; 1193 send_wont(TELOPT_LINEMODE, 1); 1194 send_dont(TELOPT_SGA, 1); 1195 send_dont(TELOPT_ECHO, 1); 1196 /* 1197 * If processing the .telnetrc file, keep track of linemode and/or 1198 * kludgelinemode requests which are processed before initial option 1199 * negotiations occur. 1200 */ 1201 if (doing_rc) 1202 reqd_linemode = 1; 1203 return (1); 1204 } 1205 #endif 1206 1207 static int 1208 dolinemode() 1209 { 1210 #ifdef KLUDGELINEMODE 1211 if (kludgelinemode) 1212 send_dont(TELOPT_SGA, 1); 1213 #endif 1214 send_will(TELOPT_LINEMODE, 1); 1215 send_dont(TELOPT_ECHO, 1); 1216 1217 /* 1218 * If processing the .telnetrc file, keep track of linemode and/or 1219 * kludgelinemode requests which are processed before initial option 1220 * negotiations occur. 1221 */ 1222 if (doing_rc) 1223 reqd_linemode = 1; 1224 return (1); 1225 } 1226 1227 static int 1228 docharmode() 1229 { 1230 #ifdef KLUDGELINEMODE 1231 if (kludgelinemode) 1232 send_do(TELOPT_SGA, 1); 1233 else 1234 #endif 1235 send_wont(TELOPT_LINEMODE, 1); 1236 send_do(TELOPT_ECHO, 1); 1237 reqd_linemode = 0; 1238 return (1); 1239 } 1240 1241 static int 1242 dolmmode(bit, on) 1243 int bit, on; 1244 { 1245 unsigned char c; 1246 extern int linemode; 1247 1248 if (my_want_state_is_wont(TELOPT_LINEMODE)) { 1249 (void) printf("?Need to have LINEMODE option enabled first.\n"); 1250 (void) printf("'mode ?' for help.\n"); 1251 return (0); 1252 } 1253 1254 if (on) 1255 c = (linemode | bit); 1256 else 1257 c = (linemode & ~bit); 1258 lm_mode(&c, 1, 1); 1259 return (1); 1260 } 1261 1262 static int 1263 setmode(int bit) 1264 { 1265 return (dolmmode(bit, 1)); 1266 } 1267 1268 static int 1269 clearmode(int bit) 1270 { 1271 return (dolmmode(bit, 0)); 1272 } 1273 1274 struct modelist { 1275 char *name; /* command name */ 1276 char *help; /* help string */ 1277 int (*handler)(); /* routine which executes command */ 1278 int needconnect; /* Do we need to be connected to execute? */ 1279 int arg1; 1280 }; 1281 1282 static int modehelp(); 1283 1284 static struct modelist ModeList[] = { 1285 { "character", "Disable LINEMODE option", docharmode, 1 }, 1286 #ifdef KLUDGELINEMODE 1287 { "", "(or disable obsolete line-by-line mode)", 0 }, 1288 #endif 1289 { "line", "Enable LINEMODE option", dolinemode, 1 }, 1290 #ifdef KLUDGELINEMODE 1291 { "", "(or enable obsolete line-by-line mode)", 0 }, 1292 #endif 1293 { "", "", 0 }, 1294 { "", "These require the LINEMODE option to be enabled", 0 }, 1295 { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG }, 1296 { "+isig", 0, setmode, 1, MODE_TRAPSIG }, 1297 { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG }, 1298 { "edit", "Enable character editing", setmode, 1, MODE_EDIT }, 1299 { "+edit", 0, setmode, 1, MODE_EDIT }, 1300 { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT }, 1301 { "softtabs", "Enable tab expansion", setmode, 1, MODE_SOFT_TAB }, 1302 { "+softtabs", 0, setmode, 1, MODE_SOFT_TAB }, 1303 { "-softtabs", "Disable tab expansion", 1304 clearmode, 1, MODE_SOFT_TAB }, 1305 { "litecho", "Enable literal character echo", 1306 setmode, 1, MODE_LIT_ECHO }, 1307 { "+litecho", 0, setmode, 1, MODE_LIT_ECHO }, 1308 { "-litecho", "Disable literal character echo", clearmode, 1, 1309 MODE_LIT_ECHO }, 1310 { "help", 0, modehelp, 0 }, 1311 #ifdef KLUDGELINEMODE 1312 { "kludgeline", 0, dokludgemode, 1 }, 1313 #endif 1314 { "", "", 0 }, 1315 { "?", "Print help information", modehelp, 0 }, 1316 { 0 }, 1317 }; 1318 1319 1320 static int 1321 modehelp() 1322 { 1323 struct modelist *mt; 1324 1325 (void) printf("format is: 'mode Mode', where 'Mode' is one of:\n\n"); 1326 for (mt = ModeList; mt->name; mt++) { 1327 if (mt->help) { 1328 if (*mt->help) 1329 (void) printf("%-15s %s\n", mt->name, mt->help); 1330 else 1331 (void) printf("\n"); 1332 } 1333 } 1334 return (0); 1335 } 1336 1337 #define GETMODECMD(name) (struct modelist *) \ 1338 genget(name, (char **)ModeList, sizeof (struct modelist)) 1339 1340 static int 1341 modecmd(argc, argv) 1342 int argc; 1343 char *argv[]; 1344 { 1345 struct modelist *mt; 1346 1347 if (argc != 2) { 1348 (void) printf("'mode' command requires an argument\n"); 1349 (void) printf("'mode ?' for help.\n"); 1350 } else if ((mt = GETMODECMD(argv[1])) == 0) { 1351 (void) fprintf(stderr, 1352 "Unknown mode '%s' ('mode ?' for help).\n", argv[1]); 1353 } else if (Ambiguous(mt)) { 1354 (void) fprintf(stderr, 1355 "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]); 1356 } else if (mt->needconnect && !connected) { 1357 (void) printf("?Need to be connected first.\n"); 1358 (void) printf("'mode ?' for help.\n"); 1359 } else if (mt->handler) { 1360 return (*mt->handler)(mt->arg1); 1361 } 1362 return (0); 1363 } 1364 1365 /* 1366 * The following data structures and routines implement the 1367 * "display" command. 1368 */ 1369 1370 static int 1371 display(argc, argv) 1372 int argc; 1373 char *argv[]; 1374 { 1375 struct togglelist *tl; 1376 struct setlist *sl; 1377 1378 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \ 1379 if (*tl->variable) { \ 1380 (void) printf("will"); \ 1381 } else { \ 1382 (void) printf("won't"); \ 1383 } \ 1384 (void) printf(" %s.\n", tl->actionexplanation); \ 1385 } 1386 1387 #define doset(sl) if (sl->name && *sl->name != ' ') { \ 1388 if (sl->handler == 0) \ 1389 (void) printf("%-15s [%s]\n", sl->name, \ 1390 control(*sl->charp)); \ 1391 else \ 1392 (void) printf("%-15s \"%s\"\n", sl->name, \ 1393 (char *)sl->charp); \ 1394 } 1395 1396 if (argc == 1) { 1397 for (tl = Togglelist; tl->name; tl++) { 1398 dotog(tl); 1399 } 1400 (void) printf("\n"); 1401 for (sl = Setlist; sl->name; sl++) { 1402 doset(sl); 1403 } 1404 } else { 1405 int i; 1406 1407 for (i = 1; i < argc; i++) { 1408 sl = getset(argv[i]); 1409 tl = GETTOGGLE(argv[i]); 1410 if (Ambiguous(sl) || Ambiguous(tl)) { 1411 (void) printf( 1412 "?Ambiguous argument '%s'.\n", argv[i]); 1413 return (0); 1414 } else if (!sl && !tl) { 1415 (void) printf( 1416 "?Unknown argument '%s'.\n", argv[i]); 1417 return (0); 1418 } else { 1419 if (tl) { 1420 dotog(tl); 1421 } 1422 if (sl) { 1423 doset(sl); 1424 } 1425 } 1426 } 1427 } 1428 optionstatus(); 1429 (void) EncryptStatus(); 1430 return (1); 1431 #undef doset 1432 #undef dotog 1433 } 1434 1435 /* 1436 * The following are the data structures, and many of the routines, 1437 * relating to command processing. 1438 */ 1439 1440 /* 1441 * Set the escape character. 1442 */ 1443 static int 1444 setescape(int argc, char *argv[]) 1445 { 1446 char *arg; 1447 char *buf = NULL; 1448 1449 if (argc > 2) 1450 arg = argv[1]; 1451 else { 1452 (void) printf("new escape character: "); 1453 if (GetString(&buf, NULL, stdin) == NULL) { 1454 if (!feof(stdin)) { 1455 perror("can't set escape character"); 1456 goto setescape_exit; 1457 } 1458 } 1459 arg = buf; 1460 } 1461 /* we place no limitations on what escape can be. */ 1462 escape = arg[0]; 1463 (void) printf("Escape character is '%s'.\n", esc_control(escape)); 1464 (void) fflush(stdout); 1465 setescape_exit: 1466 Free(&buf); 1467 return (1); 1468 } 1469 1470 /*ARGSUSED*/ 1471 static int 1472 togcrmod(argc, argv) 1473 int argc; 1474 char *argv[]; 1475 { 1476 crmod = !crmod; 1477 (void) printf( 1478 "%s map carriage return on output.\n", crmod ? "Will" : "Won't"); 1479 (void) fflush(stdout); 1480 return (1); 1481 } 1482 1483 /*ARGSUSED*/ 1484 static int 1485 suspend(argc, argv) 1486 int argc; 1487 char *argv[]; 1488 { 1489 setcommandmode(); 1490 { 1491 unsigned short oldrows, oldcols, newrows, newcols; 1492 int err; 1493 1494 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1495 (void) kill(0, SIGTSTP); 1496 /* 1497 * If we didn't get the window size before the SUSPEND, but we 1498 * can get them now (?), then send the NAWS to make sure that 1499 * we are set up for the right window size. 1500 */ 1501 if (TerminalWindowSize(&newrows, &newcols) && connected && 1502 (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1503 sendnaws(); 1504 } 1505 } 1506 /* reget parameters in case they were changed */ 1507 TerminalSaveState(); 1508 setconnmode(0); 1509 return (1); 1510 } 1511 1512 /*ARGSUSED*/ 1513 static int 1514 shell(int argc, char *argv[]) 1515 { 1516 unsigned short oldrows, oldcols, newrows, newcols; 1517 int err; 1518 1519 setcommandmode(); 1520 1521 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0; 1522 switch (vfork()) { 1523 case -1: 1524 perror("Fork failed\n"); 1525 break; 1526 1527 case 0: 1528 { 1529 /* 1530 * Fire up the shell in the child. 1531 */ 1532 char *shellp, *shellname; 1533 1534 shellp = getenv("SHELL"); 1535 if (shellp == NULL) 1536 shellp = "/bin/sh"; 1537 if ((shellname = strrchr(shellp, '/')) == 0) 1538 shellname = shellp; 1539 else 1540 shellname++; 1541 if (argc > 1) 1542 (void) execl(shellp, shellname, "-c", argv[1], 0); 1543 else 1544 (void) execl(shellp, shellname, 0); 1545 perror("Execl"); 1546 _exit(EXIT_FAILURE); 1547 } 1548 default: 1549 (void) wait((int *)0); /* Wait for the shell to complete */ 1550 1551 if (TerminalWindowSize(&newrows, &newcols) && connected && 1552 (err || ((oldrows != newrows) || (oldcols != newcols)))) { 1553 sendnaws(); 1554 } 1555 break; 1556 } 1557 return (1); 1558 } 1559 1560 static int 1561 bye(argc, argv) 1562 int argc; /* Number of arguments */ 1563 char *argv[]; /* arguments */ 1564 { 1565 extern int resettermname; 1566 1567 if (connected) { 1568 (void) shutdown(net, 2); 1569 (void) printf("Connection to %.*s closed.\n", MAXHOSTNAMELEN, 1570 hostname); 1571 Close(&net); 1572 connected = 0; 1573 resettermname = 1; 1574 /* reset options */ 1575 (void) tninit(); 1576 } 1577 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) { 1578 longjmp(toplevel, 1); 1579 /* NOTREACHED */ 1580 } 1581 return (1); /* Keep lint, etc., happy */ 1582 } 1583 1584 /*VARARGS*/ 1585 int 1586 quit() 1587 { 1588 (void) call(3, bye, "bye", "fromquit"); 1589 Exit(EXIT_SUCCESS); 1590 /*NOTREACHED*/ 1591 return (1); 1592 } 1593 1594 /*ARGSUSED*/ 1595 static int 1596 logout(argc, argv) 1597 int argc; 1598 char *argv[]; 1599 { 1600 send_do(TELOPT_LOGOUT, 1); 1601 (void) netflush(); 1602 return (1); 1603 } 1604 1605 1606 /* 1607 * The SLC command. 1608 */ 1609 1610 struct slclist { 1611 char *name; 1612 char *help; 1613 void (*handler)(); 1614 int arg; 1615 }; 1616 1617 static void slc_help(); 1618 1619 static struct slclist SlcList[] = { 1620 { "export", "Use local special character definitions", 1621 slc_mode_export, 0 }, 1622 { "import", "Use remote special character definitions", 1623 slc_mode_import, 1 }, 1624 { "check", "Verify remote special character definitions", 1625 slc_mode_import, 0 }, 1626 { "help", 0, slc_help, 0 }, 1627 { "?", "Print help information", slc_help, 0 }, 1628 { 0 }, 1629 }; 1630 1631 static void 1632 slc_help() 1633 { 1634 struct slclist *c; 1635 1636 for (c = SlcList; c->name; c++) { 1637 if (c->help) { 1638 if (*c->help) 1639 (void) printf("%-15s %s\n", c->name, c->help); 1640 else 1641 (void) printf("\n"); 1642 } 1643 } 1644 } 1645 1646 static struct slclist * 1647 getslc(name) 1648 char *name; 1649 { 1650 return ((struct slclist *) 1651 genget(name, (char **)SlcList, sizeof (struct slclist))); 1652 } 1653 1654 static int 1655 slccmd(argc, argv) 1656 int argc; 1657 char *argv[]; 1658 { 1659 struct slclist *c; 1660 1661 if (argc != 2) { 1662 (void) fprintf(stderr, 1663 "Need an argument to 'slc' command. 'slc ?' for help.\n"); 1664 return (0); 1665 } 1666 c = getslc(argv[1]); 1667 if (c == 0) { 1668 (void) fprintf(stderr, 1669 "'%s': unknown argument ('slc ?' for help).\n", 1670 argv[1]); 1671 return (0); 1672 } 1673 if (Ambiguous(c)) { 1674 (void) fprintf(stderr, 1675 "'%s': ambiguous argument ('slc ?' for help).\n", argv[1]); 1676 return (0); 1677 } 1678 (*c->handler)(c->arg); 1679 slcstate(); 1680 return (1); 1681 } 1682 1683 /* 1684 * The ENVIRON command. 1685 */ 1686 1687 struct envlist { 1688 char *name; 1689 char *help; 1690 void (*handler)(); 1691 int narg; 1692 }; 1693 1694 static struct env_lst *env_define(unsigned char *, unsigned char *); 1695 static void env_undefine(unsigned char *); 1696 static void env_export(unsigned char *); 1697 static void env_unexport(unsigned char *); 1698 static void env_send(unsigned char *); 1699 #if defined(OLD_ENVIRON) && defined(ENV_HACK) 1700 static void env_varval(unsigned char *); 1701 #endif 1702 static void env_list(void); 1703 1704 static void env_help(void); 1705 1706 static struct envlist EnvList[] = { 1707 { "define", "Define an environment variable", 1708 (void (*)())env_define, 2 }, 1709 { "undefine", "Undefine an environment variable", 1710 env_undefine, 1 }, 1711 { "export", "Mark an environment variable for automatic export", 1712 env_export, 1 }, 1713 { "unexport", "Don't mark an environment variable for automatic export", 1714 env_unexport, 1 }, 1715 { "send", "Send an environment variable", env_send, 1 }, 1716 { "list", "List the current environment variables", 1717 env_list, 0 }, 1718 #if defined(OLD_ENVIRON) && defined(ENV_HACK) 1719 { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)", 1720 env_varval, 1 }, 1721 #endif 1722 { "help", 0, env_help, 0 }, 1723 { "?", "Print help information", env_help, 0 }, 1724 { 0 }, 1725 }; 1726 1727 static void 1728 env_help() 1729 { 1730 struct envlist *c; 1731 1732 for (c = EnvList; c->name; c++) { 1733 if (c->help) { 1734 if (*c->help) 1735 (void) printf("%-15s %s\n", c->name, c->help); 1736 else 1737 (void) printf("\n"); 1738 } 1739 } 1740 } 1741 1742 static struct envlist * 1743 getenvcmd(name) 1744 char *name; 1745 { 1746 return ((struct envlist *) 1747 genget(name, (char **)EnvList, sizeof (struct envlist))); 1748 } 1749 1750 static int 1751 env_cmd(argc, argv) 1752 int argc; 1753 char *argv[]; 1754 { 1755 struct envlist *c; 1756 1757 if (argc < 2) { 1758 (void) fprintf(stderr, 1759 "Need an argument to 'environ' command. " 1760 "'environ ?' for help.\n"); 1761 return (0); 1762 } 1763 c = getenvcmd(argv[1]); 1764 if (c == 0) { 1765 (void) fprintf(stderr, "'%s': unknown argument " 1766 "('environ ?' for help).\n", argv[1]); 1767 return (0); 1768 } 1769 if (Ambiguous(c)) { 1770 (void) fprintf(stderr, "'%s': ambiguous argument " 1771 "('environ ?' for help).\n", argv[1]); 1772 return (0); 1773 } 1774 if (c->narg + 2 != argc) { 1775 (void) fprintf(stderr, 1776 "Need %s%d argument%s to 'environ %s' command. " 1777 "'environ ?' for help.\n", 1778 c->narg + 2 < argc ? "only " : "", 1779 c->narg, c->narg == 1 ? "" : "s", c->name); 1780 return (0); 1781 } 1782 (*c->handler)(argv[2], argv[3]); 1783 return (1); 1784 } 1785 1786 struct env_lst { 1787 struct env_lst *next; /* pointer to next structure */ 1788 struct env_lst *prev; /* pointer to previous structure */ 1789 unsigned char *var; /* pointer to variable name */ 1790 unsigned char *value; /* pointer to variable value */ 1791 int export; /* 1 -> export with default list of variables */ 1792 int welldefined; /* A well defined variable */ 1793 }; 1794 1795 static struct env_lst envlisthead; 1796 1797 static struct env_lst * 1798 env_find(unsigned char *var) 1799 { 1800 struct env_lst *ep; 1801 1802 for (ep = envlisthead.next; ep; ep = ep->next) { 1803 if (strcmp((char *)ep->var, (char *)var) == 0) 1804 return (ep); 1805 } 1806 return (NULL); 1807 } 1808 1809 int 1810 env_init(void) 1811 { 1812 extern char **environ; 1813 char **epp, *cp; 1814 struct env_lst *ep; 1815 1816 for (epp = environ; *epp; epp++) { 1817 if (cp = strchr(*epp, '=')) { 1818 *cp = '\0'; 1819 1820 ep = env_define((unsigned char *)*epp, 1821 (unsigned char *)cp+1); 1822 if (ep == NULL) 1823 return (0); 1824 ep->export = 0; 1825 *cp = '='; 1826 } 1827 } 1828 /* 1829 * Special case for DISPLAY variable. If it is ":0.0" or 1830 * "unix:0.0", we have to get rid of "unix" and insert our 1831 * hostname. 1832 */ 1833 if (((ep = env_find((uchar_t *)"DISPLAY")) != NULL) && 1834 ((*ep->value == ':') || 1835 (strncmp((char *)ep->value, "unix:", 5) == 0))) { 1836 char hbuf[MAXHOSTNAMELEN]; 1837 char *cp2 = strchr((char *)ep->value, ':'); 1838 1839 if (gethostname(hbuf, MAXHOSTNAMELEN) == -1) { 1840 perror("telnet: cannot get hostname"); 1841 return (0); 1842 } 1843 hbuf[MAXHOSTNAMELEN-1] = '\0'; 1844 cp = malloc(strlen(hbuf) + strlen(cp2) + 1); 1845 if (cp == NULL) { 1846 perror("telnet: cannot define DISPLAY variable"); 1847 return (0); 1848 } 1849 (void) sprintf((char *)cp, "%s%s", hbuf, cp2); 1850 free(ep->value); 1851 ep->value = (unsigned char *)cp; 1852 } 1853 /* 1854 * If LOGNAME is defined, but USER is not, then add 1855 * USER with the value from LOGNAME. We do this because the "accepted 1856 * practice" is to always pass USER on the wire, but SVR4 uses 1857 * LOGNAME by default. 1858 */ 1859 if ((ep = env_find((uchar_t *)"LOGNAME")) != NULL && 1860 env_find((uchar_t *)"USER") == NULL) { 1861 if (env_define((unsigned char *)"USER", ep->value) != NULL) 1862 env_unexport((unsigned char *)"USER"); 1863 } 1864 env_export((unsigned char *)"DISPLAY"); 1865 env_export((unsigned char *)"PRINTER"); 1866 1867 return (1); 1868 } 1869 1870 static struct env_lst * 1871 env_define(unsigned char *var, unsigned char *value) 1872 { 1873 unsigned char *tmp_value; 1874 unsigned char *tmp_var; 1875 struct env_lst *ep; 1876 1877 /* 1878 * Allocate copies of arguments first, to make cleanup easier 1879 * in the case of allocation errors. 1880 */ 1881 tmp_var = (unsigned char *)strdup((char *)var); 1882 if (tmp_var == NULL) { 1883 perror("telnet: can't copy environment variable name"); 1884 return (NULL); 1885 } 1886 1887 tmp_value = (unsigned char *)strdup((char *)value); 1888 if (tmp_value == NULL) { 1889 free(tmp_var); 1890 perror("telnet: can't copy environment variable value"); 1891 return (NULL); 1892 } 1893 1894 if (ep = env_find(var)) { 1895 if (ep->var) 1896 free(ep->var); 1897 if (ep->value) 1898 free(ep->value); 1899 } else { 1900 ep = malloc(sizeof (struct env_lst)); 1901 if (ep == NULL) { 1902 perror("telnet: can't define environment variable"); 1903 free(tmp_var); 1904 free(tmp_value); 1905 return (NULL); 1906 } 1907 1908 ep->next = envlisthead.next; 1909 envlisthead.next = ep; 1910 ep->prev = &envlisthead; 1911 if (ep->next) 1912 ep->next->prev = ep; 1913 } 1914 ep->welldefined = opt_welldefined((char *)var); 1915 ep->export = 1; 1916 ep->var = tmp_var; 1917 ep->value = tmp_value; 1918 1919 return (ep); 1920 } 1921 1922 static void 1923 env_undefine(unsigned char *var) 1924 { 1925 struct env_lst *ep; 1926 1927 if (ep = env_find(var)) { 1928 ep->prev->next = ep->next; 1929 if (ep->next) 1930 ep->next->prev = ep->prev; 1931 if (ep->var) 1932 free(ep->var); 1933 if (ep->value) 1934 free(ep->value); 1935 free(ep); 1936 } 1937 } 1938 1939 static void 1940 env_export(unsigned char *var) 1941 { 1942 struct env_lst *ep; 1943 1944 if (ep = env_find(var)) 1945 ep->export = 1; 1946 } 1947 1948 static void 1949 env_unexport(unsigned char *var) 1950 { 1951 struct env_lst *ep; 1952 1953 if (ep = env_find(var)) 1954 ep->export = 0; 1955 } 1956 1957 static void 1958 env_send(unsigned char *var) 1959 { 1960 struct env_lst *ep; 1961 1962 if (my_state_is_wont(TELOPT_NEW_ENVIRON) 1963 #ifdef OLD_ENVIRON 1964 /* old style */ && my_state_is_wont(TELOPT_OLD_ENVIRON) 1965 #endif 1966 /* no environ */) { 1967 (void) fprintf(stderr, 1968 "Cannot send '%s': Telnet ENVIRON option not enabled\n", 1969 var); 1970 return; 1971 } 1972 ep = env_find(var); 1973 if (ep == 0) { 1974 (void) fprintf(stderr, 1975 "Cannot send '%s': variable not defined\n", var); 1976 return; 1977 } 1978 env_opt_start_info(); 1979 env_opt_add(ep->var); 1980 env_opt_end(0); 1981 } 1982 1983 static void 1984 env_list(void) 1985 { 1986 struct env_lst *ep; 1987 1988 for (ep = envlisthead.next; ep; ep = ep->next) { 1989 (void) printf("%c %-20s %s\n", ep->export ? '*' : ' ', 1990 ep->var, ep->value); 1991 } 1992 } 1993 1994 unsigned char * 1995 env_default(int init, int welldefined) 1996 { 1997 static struct env_lst *nep = NULL; 1998 1999 if (init) { 2000 /* return value is not used */ 2001 nep = &envlisthead; 2002 return (NULL); 2003 } 2004 if (nep) { 2005 while ((nep = nep->next) != NULL) { 2006 if (nep->export && (nep->welldefined == welldefined)) 2007 return (nep->var); 2008 } 2009 } 2010 return (NULL); 2011 } 2012 2013 unsigned char * 2014 env_getvalue(unsigned char *var) 2015 { 2016 struct env_lst *ep; 2017 2018 if (ep = env_find(var)) 2019 return (ep->value); 2020 return (NULL); 2021 } 2022 2023 #if defined(OLD_ENVIRON) && defined(ENV_HACK) 2024 static void 2025 env_varval(unsigned char *what) 2026 { 2027 extern int old_env_var, old_env_value, env_auto; 2028 int len = strlen((char *)what); 2029 2030 if (len == 0) 2031 goto unknown; 2032 2033 if (strncasecmp((char *)what, "status", len) == 0) { 2034 if (env_auto) 2035 (void) printf("%s%s", "VAR and VALUE are/will be ", 2036 "determined automatically\n"); 2037 if (old_env_var == OLD_ENV_VAR) 2038 (void) printf( 2039 "VAR and VALUE set to correct definitions\n"); 2040 else 2041 (void) printf( 2042 "VAR and VALUE definitions are reversed\n"); 2043 } else if (strncasecmp((char *)what, "auto", len) == 0) { 2044 env_auto = 1; 2045 old_env_var = OLD_ENV_VALUE; 2046 old_env_value = OLD_ENV_VAR; 2047 } else if (strncasecmp((char *)what, "right", len) == 0) { 2048 env_auto = 0; 2049 old_env_var = OLD_ENV_VAR; 2050 old_env_value = OLD_ENV_VALUE; 2051 } else if (strncasecmp((char *)what, "wrong", len) == 0) { 2052 env_auto = 0; 2053 old_env_var = OLD_ENV_VALUE; 2054 old_env_value = OLD_ENV_VAR; 2055 } else { 2056 unknown: 2057 (void) printf( 2058 "Unknown \"varval\" command. (\"auto\", \"right\", " 2059 "\"wrong\", \"status\")\n"); 2060 } 2061 } 2062 #endif /* OLD_ENVIRON && ENV_HACK */ 2063 2064 /* 2065 * The AUTHENTICATE command. 2066 */ 2067 2068 struct authlist { 2069 char *name; 2070 char *help; 2071 int (*handler)(); 2072 int narg; 2073 }; 2074 2075 extern int auth_enable(char *); 2076 extern int auth_disable(char *); 2077 extern int auth_status(void); 2078 2079 static int auth_help(void); 2080 2081 static struct authlist AuthList[] = { 2082 { "status", 2083 "Display current status of authentication information", 2084 auth_status, 0 }, 2085 { "disable", 2086 "Disable an authentication type ('auth disable ?' for more)", 2087 auth_disable, 1 }, 2088 { "enable", 2089 "Enable an authentication type ('auth enable ?' for more)", 2090 auth_enable, 1 }, 2091 { "help", 0, auth_help, 0 }, 2092 { "?", "Print help information", auth_help, 0 }, 2093 { 0 }, 2094 }; 2095 2096 static int 2097 auth_help(void) 2098 { 2099 struct authlist *c; 2100 2101 for (c = AuthList; c->name; c++) { 2102 if (c->help) { 2103 if (*c->help) 2104 (void) printf("%-15s %s\n", c->name, c->help); 2105 else 2106 (void) printf("\n"); 2107 } 2108 } 2109 return (0); 2110 } 2111 2112 2113 static int 2114 auth_cmd(int argc, char *argv[]) 2115 { 2116 struct authlist *c; 2117 2118 if (argc < 2) { 2119 (void) fprintf(stderr, "Need an argument to 'auth' " 2120 "command. 'auth ?' for help.\n"); 2121 return (0); 2122 } 2123 2124 c = (struct authlist *) 2125 genget(argv[1], (char **)AuthList, sizeof (struct authlist)); 2126 if (c == 0) { 2127 (void) fprintf(stderr, 2128 "'%s': unknown argument ('auth ?' for help).\n", 2129 argv[1]); 2130 return (0); 2131 } 2132 if (Ambiguous(c)) { 2133 (void) fprintf(stderr, 2134 "'%s': ambiguous argument ('auth ?' for help).\n", argv[1]); 2135 return (0); 2136 } 2137 if (c->narg + 2 != argc) { 2138 (void) fprintf(stderr, 2139 "Need %s%d argument%s to 'auth %s' command." 2140 " 'auth ?' for help.\n", 2141 c->narg + 2 < argc ? "only " : "", 2142 c->narg, c->narg == 1 ? "" : "s", c->name); 2143 return (0); 2144 } 2145 return ((*c->handler)(argv[2], argv[3])); 2146 } 2147 2148 /* 2149 * The FORWARD command. 2150 */ 2151 2152 extern int forward_flags; 2153 2154 struct forwlist { 2155 char *name; 2156 char *help; 2157 int (*handler)(); 2158 int f_flags; 2159 }; 2160 2161 static int forw_status(void); 2162 static int forw_set(int); 2163 static int forw_help(void); 2164 2165 static struct forwlist ForwList[] = { 2166 {"status", 2167 "Display current status of credential forwarding", 2168 forw_status, 0}, 2169 {"disable", 2170 "Disable credential forwarding", 2171 forw_set, 0}, 2172 {"enable", 2173 "Enable credential forwarding", 2174 forw_set, OPTS_FORWARD_CREDS}, 2175 {"forwardable", 2176 "Enable credential forwarding of " 2177 "forwardable credentials", 2178 forw_set, OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS}, 2179 {"help", 2180 0, 2181 forw_help, 0}, 2182 {"?", 2183 "Print help information", 2184 forw_help, 0}, 2185 {0}, 2186 }; 2187 2188 static int 2189 forw_status(void) 2190 { 2191 if (forward_flags & OPTS_FORWARD_CREDS) { 2192 if (forward_flags & OPTS_FORWARDABLE_CREDS) 2193 (void) printf(gettext( 2194 "Credential forwarding of " 2195 "forwardable credentials enabled\n")); 2196 else 2197 (void) printf(gettext( 2198 "Credential forwarding enabled\n")); 2199 } else 2200 (void) printf(gettext("Credential forwarding disabled\n")); 2201 return (0); 2202 } 2203 2204 static int 2205 forw_set(int f_flags) 2206 { 2207 forward_flags = f_flags; 2208 return (0); 2209 } 2210 2211 static int 2212 forw_help(void) 2213 { 2214 struct forwlist *c; 2215 2216 for (c = ForwList; c->name; c++) { 2217 if (c->help) { 2218 if (*c->help) 2219 (void) printf("%-15s %s\r\n", c->name, c->help); 2220 else 2221 (void) printf("\n"); 2222 } 2223 } 2224 return (0); 2225 } 2226 2227 static int 2228 forw_cmd(int argc, char *argv[]) 2229 { 2230 struct forwlist *c; 2231 2232 if (argc < 2) { 2233 (void) fprintf(stderr, gettext( 2234 "Need an argument to 'forward' " 2235 "command. 'forward ?' for help.\n")); 2236 return (0); 2237 } 2238 c = (struct forwlist *)genget(argv[1], (char **)ForwList, 2239 sizeof (struct forwlist)); 2240 if (c == 0) { 2241 (void) fprintf(stderr, gettext( 2242 "'%s': unknown argument ('forward ?' for help).\n"), 2243 argv[1]); 2244 return (0); 2245 } 2246 if (Ambiguous(c)) { 2247 (void) fprintf(stderr, gettext( 2248 "'%s': ambiguous argument ('forward ?' for help).\n"), 2249 argv[1]); 2250 return (0); 2251 } 2252 if (argc != 2) { 2253 (void) fprintf(stderr, gettext( 2254 "No arguments needed to 'forward %s' command. " 2255 "'forward ?' for help.\n"), c->name); 2256 return (0); 2257 } 2258 return ((*c->handler) (c->f_flags)); 2259 } 2260 2261 /* 2262 * The ENCRYPT command. 2263 */ 2264 2265 struct encryptlist { 2266 char *name; 2267 char *help; 2268 int (*handler)(); 2269 int needconnect; 2270 int minarg; 2271 int maxarg; 2272 }; 2273 2274 static int EncryptHelp(void); 2275 2276 static struct encryptlist EncryptList[] = { 2277 { "enable", "Enable encryption. ('encrypt enable ?' for more)", 2278 EncryptEnable, 1, 1, 2 }, 2279 { "disable", "Disable encryption. ('encrypt disable ?' for more)", 2280 EncryptDisable, 0, 1, 2 }, 2281 { "type", "Set encryption type. ('encrypt type ?' for more)", 2282 EncryptType, 0, 1, 2 }, 2283 { "start", "Start encryption. ('encrypt start ?' for more)", 2284 EncryptStart, 1, 0, 1 }, 2285 { "stop", "Stop encryption. ('encrypt stop ?' for more)", 2286 EncryptStop, 1, 0, 1 }, 2287 { "input", "Start encrypting the input stream", 2288 EncryptStartInput, 1, 0, 0 }, 2289 { "-input", "Stop encrypting the input stream", 2290 EncryptStopInput, 1, 0, 0 }, 2291 { "output", "Start encrypting the output stream", 2292 EncryptStartOutput, 1, 0, 0 }, 2293 { "-output", "Stop encrypting the output stream", 2294 EncryptStopOutput, 1, 0, 0 }, 2295 2296 { "status", "Display current status of encryption information", 2297 EncryptStatus, 0, 0, 0 }, 2298 { "help", 0, 2299 EncryptHelp, 0, 0, 0 }, 2300 { "?", "Print help information", EncryptHelp, 0, 0, 0 }, 2301 { 0 }, 2302 }; 2303 2304 static int 2305 EncryptHelp(void) 2306 { 2307 struct encryptlist *c; 2308 2309 for (c = EncryptList; c->name; c++) { 2310 if (c->help) { 2311 if (*c->help) 2312 (void) printf("%-15s %s\n", c->name, c->help); 2313 else 2314 (void) printf("\n"); 2315 } 2316 } 2317 return (0); 2318 } 2319 2320 static int 2321 encrypt_cmd(int argc, char *argv[]) 2322 { 2323 struct encryptlist *c; 2324 2325 if (argc < 2) { 2326 (void) fprintf(stderr, gettext( 2327 "Need an argument to 'encrypt' command. " 2328 "'encrypt ?' for help.\n")); 2329 return (0); 2330 } 2331 2332 c = (struct encryptlist *) 2333 genget(argv[1], (char **)EncryptList, sizeof (struct encryptlist)); 2334 if (c == 0) { 2335 (void) fprintf(stderr, gettext( 2336 "'%s': unknown argument ('encrypt ?' for help).\n"), 2337 argv[1]); 2338 return (0); 2339 } 2340 if (Ambiguous(c)) { 2341 (void) fprintf(stderr, gettext( 2342 "'%s': ambiguous argument ('encrypt ?' for help).\n"), 2343 argv[1]); 2344 return (0); 2345 } 2346 argc -= 2; 2347 if (argc < c->minarg || argc > c->maxarg) { 2348 if (c->minarg == c->maxarg) { 2349 (void) fprintf(stderr, gettext("Need %s%d %s "), 2350 c->minarg < argc ? 2351 gettext("only ") : "", c->minarg, 2352 c->minarg == 1 ? 2353 gettext("argument") : gettext("arguments")); 2354 } else { 2355 (void) fprintf(stderr, 2356 gettext("Need %s%d-%d arguments "), 2357 c->maxarg < argc ? 2358 gettext("only ") : "", c->minarg, c->maxarg); 2359 } 2360 (void) fprintf(stderr, gettext( 2361 "to 'encrypt %s' command. 'encrypt ?' for help.\n"), 2362 c->name); 2363 return (0); 2364 } 2365 if (c->needconnect && !connected) { 2366 if (!(argc && 2367 (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) { 2368 (void) printf( 2369 gettext("?Need to be connected first.\n")); 2370 return (0); 2371 } 2372 } 2373 return ((*c->handler)(argc > 0 ? argv[2] : 0, 2374 argc > 1 ? argv[3] : 0, argc > 2 ? argv[4] : 0)); 2375 } 2376 2377 /* 2378 * Print status about the connection. 2379 */ 2380 static int 2381 status(int argc, char *argv[]) 2382 { 2383 if (connected) { 2384 (void) printf("Connected to %s.\n", hostname); 2385 if ((argc < 2) || strcmp(argv[1], "notmuch")) { 2386 int mode = getconnmode(); 2387 2388 if (my_want_state_is_will(TELOPT_LINEMODE)) { 2389 (void) printf( 2390 "Operating with LINEMODE option\n"); 2391 (void) printf( 2392 "%s line editing\n", (mode&MODE_EDIT) ? 2393 "Local" : "No"); 2394 (void) printf("%s catching of signals\n", 2395 (mode&MODE_TRAPSIG) ? "Local" : "No"); 2396 slcstate(); 2397 #ifdef KLUDGELINEMODE 2398 } else if (kludgelinemode && 2399 my_want_state_is_dont(TELOPT_SGA)) { 2400 (void) printf( 2401 "Operating in obsolete linemode\n"); 2402 #endif 2403 } else { 2404 (void) printf( 2405 "Operating in single character mode\n"); 2406 if (localchars) 2407 (void) printf( 2408 "Catching signals locally\n"); 2409 } 2410 (void) printf("%s character echo\n", (mode&MODE_ECHO) ? 2411 "Local" : "Remote"); 2412 if (my_want_state_is_will(TELOPT_LFLOW)) 2413 (void) printf("%s flow control\n", 2414 (mode&MODE_FLOW) ? "Local" : "No"); 2415 2416 encrypt_display(); 2417 } 2418 } else { 2419 (void) printf("No connection.\n"); 2420 } 2421 if (rlogin != _POSIX_VDISABLE) 2422 (void) printf("Escape character is '%s'.\n", control(rlogin)); 2423 else 2424 (void) printf( 2425 "Escape character is '%s'.\n", esc_control(escape)); 2426 (void) fflush(stdout); 2427 return (1); 2428 } 2429 2430 /* 2431 * Parse the user input (cmd_line_input) which should: 2432 * - start with the target host, or with "@" or "!@" followed by at least one 2433 * gateway. 2434 * - each host (can be literal address or hostname) can be separated by ",", 2435 * "@", or ",@". 2436 * Note that the last host is the target, all the others (if any ) are the 2437 * gateways. 2438 * 2439 * Returns: -1 if a library call fails, too many gateways, or parse 2440 * error 2441 * num_gw otherwise 2442 * On successful return, hostname_list points to a list of hosts (last one being 2443 * the target, others gateways), src_rtng_type points to the type of source 2444 * routing (strict vs. loose) 2445 */ 2446 static int 2447 parse_input(char *cmd_line_input, char **hostname_list, uchar_t *src_rtng_type) 2448 { 2449 char hname[MAXHOSTNAMELEN + 1]; 2450 char *cp; 2451 int gw_count; 2452 int i; 2453 2454 gw_count = 0; 2455 cp = cmd_line_input; 2456 2457 /* 2458 * Defining ICMD generates the Itelnet binary, the special version of 2459 * telnet which is used with firewall proxy. 2460 * If ICMD is defined, parse_input will treat the whole cmd_line_input 2461 * as the target host and set the num_gw to 0. Therefore, none of the 2462 * source routing related code paths will be executed. 2463 */ 2464 #ifndef ICMD 2465 if (*cp == '@') { 2466 *src_rtng_type = IPOPT_LSRR; 2467 cp++; 2468 } else if (*cp == '!') { 2469 *src_rtng_type = IPOPT_SSRR; 2470 2471 /* "!" must be followed by '@' */ 2472 if (*(cp + 1) != '@') 2473 goto parse_error; 2474 cp += 2; 2475 } else { 2476 #endif /* ICMD */ 2477 /* no gateways, just the target */ 2478 hostname_list[0] = strdup(cp); 2479 if (hostname_list[0] == NULL) { 2480 perror("telnet: copying host name"); 2481 return (-1); 2482 } 2483 return (0); 2484 #ifndef ICMD 2485 } 2486 2487 while (*cp != '\0') { 2488 /* 2489 * Identify each gateway separated by ",", "@" or ",@" and 2490 * store in hname[]. 2491 */ 2492 i = 0; 2493 while (*cp != '@' && *cp != ',' && *cp != '\0') { 2494 hname[i++] = *cp++; 2495 if (i > MAXHOSTNAMELEN) 2496 goto parse_error; 2497 } 2498 hname[i] = '\0'; 2499 2500 /* 2501 * Two consecutive delimiters which result in a 0 length hname 2502 * is a parse error. 2503 */ 2504 if (i == 0) 2505 goto parse_error; 2506 2507 hostname_list[gw_count] = strdup(hname); 2508 if (hostname_list[gw_count] == NULL) { 2509 perror("telnet: copying hostname from list"); 2510 return (-1); 2511 } 2512 2513 if (++gw_count > MAXMAX_GATEWAY) { 2514 (void) fprintf(stderr, "telnet: too many gateways\n"); 2515 return (-1); 2516 } 2517 2518 /* Jump over the next delimiter. */ 2519 if (*cp != '\0') { 2520 /* ...gw1,@gw2... accepted */ 2521 if (*cp == ',' && *(cp + 1) == '@') 2522 cp += 2; 2523 else 2524 cp++; 2525 } 2526 } 2527 2528 /* discount the target */ 2529 gw_count--; 2530 2531 /* Any input starting with '!@' or '@' must have at least one gateway */ 2532 if (gw_count <= 0) 2533 goto parse_error; 2534 2535 return (gw_count); 2536 2537 parse_error: 2538 (void) printf("Bad source route option: %s\n", cmd_line_input); 2539 return (-1); 2540 #endif /* ICMD */ 2541 } 2542 2543 /* 2544 * Resolves the target and gateway addresses, determines what type of addresses 2545 * (ALL_ADDRS, ONLY_V6, ONLY_V4) telnet will be trying to connect. 2546 * 2547 * Returns: pointer to resolved target if name resolutions succeed 2548 * NULL if name resolutions fail or 2549 * a library function call fails 2550 * 2551 * The last host in the hostname_list is the target. After resolving the target, 2552 * determines for what type of addresses it should try to resolve gateways. It 2553 * resolves gateway addresses and picks one address for each desired address 2554 * type and stores in the array pointed by gw_addrsp. Also, this 'type of 2555 * addresses' is pointed by addr_type argument on successful return. 2556 */ 2557 static struct addrinfo * 2558 resolve_hosts(char **hostname_list, int num_gw, struct gateway **gw_addrsp, 2559 int *addr_type, const char *portp) 2560 { 2561 struct gateway *gw_addrs = NULL; 2562 struct gateway *gw; 2563 /* whether we already picked an IPv4 address for the current gateway */ 2564 boolean_t got_v4_addr; 2565 boolean_t got_v6_addr; 2566 /* whether we need to get an IPv4 address for the current gateway */ 2567 boolean_t need_v4_addr = B_FALSE; 2568 boolean_t need_v6_addr = B_FALSE; 2569 int res_failed_at4; /* save which gateway failed to resolve */ 2570 int res_failed_at6; 2571 boolean_t is_v4mapped; 2572 struct in6_addr *v6addrp; 2573 struct in_addr *v4addrp; 2574 int error_num; 2575 int i; 2576 int rc; 2577 struct addrinfo *res, *host, *gateway, *addr; 2578 struct addrinfo hints; 2579 2580 *addr_type = ALL_ADDRS; 2581 2582 memset(&hints, 0, sizeof (hints)); 2583 hints.ai_flags = AI_CANONNAME; /* used for config files, diags */ 2584 hints.ai_socktype = SOCK_STREAM; 2585 rc = getaddrinfo(hostname_list[num_gw], 2586 (portp != NULL) ? portp : "telnet", &hints, &res); 2587 if (rc != 0) { 2588 if (hostname_list[num_gw] != NULL && 2589 *hostname_list[num_gw] != '\0') 2590 (void) fprintf(stderr, "%s: ", hostname_list[num_gw]); 2591 (void) fprintf(stderr, "%s\n", gai_strerror(rc)); 2592 return (NULL); 2593 } 2594 2595 /* 2596 * Let's see what type of addresses we got for the target. This 2597 * determines what type of addresses we'd like to resolve gateways 2598 * later. 2599 */ 2600 for (host = res; host != NULL; host = host->ai_next) { 2601 struct sockaddr_in6 *s6; 2602 2603 s6 = (struct sockaddr_in6 *)host->ai_addr; 2604 2605 if (host->ai_addr->sa_family == AF_INET || 2606 IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr)) 2607 need_v4_addr = B_TRUE; 2608 else 2609 need_v6_addr = B_TRUE; 2610 2611 /* 2612 * Let's stop after seeing we need both IPv6 and IPv4. 2613 */ 2614 if (need_v4_addr && need_v6_addr) 2615 break; 2616 } 2617 2618 if (num_gw > 0) { 2619 /* 2620 * In the prepare_optbuf(), we'll store the IPv4 address of the 2621 * target in the last slot of gw_addrs array. Therefore we need 2622 * space for num_gw+1 hosts. 2623 */ 2624 gw_addrs = calloc(num_gw + 1, sizeof (struct gateway)); 2625 if (gw_addrs == NULL) { 2626 perror("telnet: calloc"); 2627 freeaddrinfo(res); 2628 return (NULL); 2629 } 2630 } 2631 2632 /* 2633 * Now we'll go through all the gateways and try to resolve them to 2634 * the desired address types. 2635 */ 2636 gw = gw_addrs; 2637 2638 /* -1 means 'no address resolution failure yet' */ 2639 res_failed_at4 = -1; 2640 res_failed_at6 = -1; 2641 for (i = 0; i < num_gw; i++) { 2642 rc = getaddrinfo(hostname_list[i], NULL, NULL, &gateway); 2643 if (rc != 0) { 2644 if (hostname_list[i] != NULL && 2645 *hostname_list[i] != '\0') 2646 (void) fprintf(stderr, "%s: ", 2647 hostname_list[i]); 2648 (void) fprintf(stderr, "bad address\n"); 2649 return (NULL); 2650 } 2651 2652 /* 2653 * Initially we have no address of any type for this gateway. 2654 */ 2655 got_v6_addr = B_FALSE; 2656 got_v4_addr = B_FALSE; 2657 2658 /* 2659 * Let's go through all the addresses of this gateway. 2660 * Use the first address which matches the needed family. 2661 */ 2662 for (addr = gateway; addr != NULL; addr = addr->ai_next) { 2663 /*LINTED*/ 2664 v6addrp = &((struct sockaddr_in6 *)addr->ai_addr)-> 2665 sin6_addr; 2666 v4addrp = &((struct sockaddr_in *)addr->ai_addr)-> 2667 sin_addr; 2668 2669 if (addr->ai_family == AF_INET6) 2670 is_v4mapped = IN6_IS_ADDR_V4MAPPED(v6addrp); 2671 else 2672 is_v4mapped = B_FALSE; 2673 2674 /* 2675 * If we need to determine an IPv4 address and haven't 2676 * found one yet and this is a IPv4-mapped IPv6 address, 2677 * then bingo! 2678 */ 2679 if (need_v4_addr && !got_v4_addr) { 2680 if (is_v4mapped) { 2681 IN6_V4MAPPED_TO_INADDR(v6addrp, 2682 &gw->gw_addr); 2683 got_v4_addr = B_TRUE; 2684 } else if (addr->ai_family = AF_INET) { 2685 gw->gw_addr = *v4addrp; 2686 got_v4_addr = B_TRUE; 2687 } 2688 } 2689 2690 if (need_v6_addr && !got_v6_addr && 2691 addr->ai_family == AF_INET6) { 2692 gw->gw_addr6 = *v6addrp; 2693 got_v6_addr = B_TRUE; 2694 } 2695 2696 /* 2697 * Let's stop if we got all what we looked for. 2698 */ 2699 if ((!need_v4_addr || got_v4_addr) && 2700 (!need_v6_addr || got_v6_addr)) 2701 break; 2702 } 2703 2704 /* 2705 * We needed an IPv4 address for this gateway but couldn't 2706 * find one. 2707 */ 2708 if (need_v4_addr && !got_v4_addr) { 2709 res_failed_at4 = i; 2710 /* 2711 * Since we couldn't resolve a gateway to IPv4 address 2712 * we can't use IPv4 at all. Therefore we no longer 2713 * need IPv4 addresses for any of the gateways. 2714 */ 2715 need_v4_addr = B_FALSE; 2716 } 2717 2718 if (need_v6_addr && !got_v6_addr) { 2719 res_failed_at6 = i; 2720 need_v6_addr = B_FALSE; 2721 } 2722 2723 /* 2724 * If some gateways don't resolve to any of the desired 2725 * address types, we fail. 2726 */ 2727 if (!need_v4_addr && !need_v6_addr) { 2728 if (res_failed_at6 != -1) { 2729 (void) fprintf(stderr, 2730 "%s: Host doesn't have any IPv6 address\n", 2731 hostname_list[res_failed_at6]); 2732 } 2733 if (res_failed_at4 != -1) { 2734 (void) fprintf(stderr, 2735 "%s: Host doesn't have any IPv4 address\n", 2736 hostname_list[res_failed_at4]); 2737 } 2738 free(gw_addrs); 2739 return (NULL); 2740 } 2741 2742 gw++; 2743 } 2744 2745 *gw_addrsp = gw_addrs; 2746 2747 /* 2748 * When we get here, need_v4_addr and need_v6_addr have their final 2749 * values based on the name resolution of the target and gateways. 2750 */ 2751 if (need_v4_addr && need_v6_addr) 2752 *addr_type = ALL_ADDRS; 2753 else if (need_v4_addr && !need_v6_addr) 2754 *addr_type = ONLY_V4; 2755 else if (!need_v4_addr && need_v6_addr) 2756 *addr_type = ONLY_V6; 2757 2758 return (res); 2759 } 2760 2761 2762 /* 2763 * Initializes the buffer pointed by opt_bufpp for a IPv4 option of type 2764 * src_rtng_type using the gateway addresses stored in gw_addrs. If no buffer 2765 * is passed, it allocates one. If a buffer is passed, checks if it's big 2766 * enough. 2767 * On return opt_buf_len points to the buffer length which we need later for the 2768 * setsockopt() call, and opt_bufpp points to the newly allocated or already 2769 * passed buffer. Returns B_FALSE if a library function call fails or passed 2770 * buffer is not big enough, B_TRUE otherwise. 2771 */ 2772 static boolean_t 2773 prepare_optbuf(struct gateway *gw_addrs, int num_gw, char **opt_bufpp, 2774 size_t *opt_buf_len, struct in_addr *target, uchar_t src_rtng_type) 2775 { 2776 struct ip_sourceroute *sr_opt; 2777 size_t needed_buflen; 2778 int i; 2779 2780 /* 2781 * We have (num_gw + 1) IP addresses in the buffer because the number 2782 * of gateway addresses we put in the option buffer includes the target 2783 * address. 2784 * At the time of setsockopt() call, passed option length needs to be 2785 * multiple of 4 bytes. Therefore we need one IPOPT_NOP before (or 2786 * after) IPOPT_LSRR. 2787 * 1 = preceding 1 byte of IPOPT_NOP 2788 * 3 = 1 (code) + 1 (len) + 1 (ptr) 2789 */ 2790 needed_buflen = 1 + 3 + (num_gw + 1) * sizeof (struct in_addr); 2791 2792 if (*opt_bufpp != NULL) { 2793 /* check if the passed buffer is big enough */ 2794 if (*opt_buf_len < needed_buflen) { 2795 (void) fprintf(stderr, 2796 "telnet: buffer too small for IPv4 source routing " 2797 "option\n"); 2798 return (B_FALSE); 2799 } 2800 } else { 2801 *opt_bufpp = malloc(needed_buflen); 2802 if (*opt_bufpp == NULL) { 2803 perror("telnet: malloc"); 2804 return (B_FALSE); 2805 } 2806 } 2807 2808 *opt_buf_len = needed_buflen; 2809 2810 /* final hop is the target */ 2811 gw_addrs[num_gw].gw_addr = *target; 2812 2813 *opt_bufpp[0] = IPOPT_NOP; 2814 /* IPOPT_LSRR starts right after IPOPT_NOP */ 2815 sr_opt = (struct ip_sourceroute *)(*opt_bufpp + 1); 2816 sr_opt->ipsr_code = src_rtng_type; 2817 /* discount the 1 byte of IPOPT_NOP */ 2818 sr_opt->ipsr_len = needed_buflen - 1; 2819 sr_opt->ipsr_ptr = IPOPT_MINOFF; 2820 2821 /* copy the gateways into the optlist */ 2822 for (i = 0; i < num_gw + 1; i++) { 2823 (void) bcopy(&gw_addrs[i].gw_addr, &sr_opt->ipsr_addrs[i], 2824 sizeof (struct in_addr)); 2825 } 2826 2827 return (B_TRUE); 2828 } 2829 2830 /* 2831 * Initializes the buffer pointed by opt_bufpp for a IPv6 routing header option 2832 * using the gateway addresses stored in gw_addrs. If no buffer is passed, it 2833 * allocates one. If a buffer is passed, checks if it's big enough. 2834 * On return opt_buf_len points to the buffer length which we need later for the 2835 * setsockopt() call, and opt_bufpp points to the newly allocated or already 2836 * passed buffer. Returns B_FALSE if a library function call fails or passed 2837 * buffer is not big enough, B_TRUE otherwise. 2838 */ 2839 static boolean_t 2840 prepare_optbuf6(struct gateway *gw_addrs, int num_gw, char **opt_bufpp, 2841 size_t *opt_buf_len) 2842 { 2843 char *opt_bufp; 2844 size_t needed_buflen; 2845 int i; 2846 2847 needed_buflen = inet6_rth_space(IPV6_RTHDR_TYPE_0, num_gw); 2848 2849 if (*opt_bufpp != NULL) { 2850 /* check if the passed buffer is big enough */ 2851 if (*opt_buf_len < needed_buflen) { 2852 (void) fprintf(stderr, 2853 "telnet: buffer too small for IPv6 routing " 2854 "header option\n"); 2855 return (B_FALSE); 2856 } 2857 } else { 2858 *opt_bufpp = malloc(needed_buflen); 2859 if (*opt_bufpp == NULL) { 2860 perror("telnet: malloc"); 2861 return (B_FALSE); 2862 } 2863 } 2864 *opt_buf_len = needed_buflen; 2865 opt_bufp = *opt_bufpp; 2866 2867 /* 2868 * Initialize the buffer to be used for IPv6 routing header type 0. 2869 */ 2870 if (inet6_rth_init(opt_bufp, needed_buflen, IPV6_RTHDR_TYPE_0, 2871 num_gw) == NULL) { 2872 perror("telnet: inet6_rth_init"); 2873 return (B_FALSE); 2874 } 2875 2876 /* 2877 * Add gateways one by one. 2878 */ 2879 for (i = 0; i < num_gw; i++) { 2880 if (inet6_rth_add(opt_bufp, &gw_addrs[i].gw_addr6) == -1) { 2881 perror("telnet: inet6_rth_add"); 2882 return (B_FALSE); 2883 } 2884 } 2885 2886 /* successful operation */ 2887 return (B_TRUE); 2888 } 2889 2890 int 2891 tn(int argc, char *argv[]) 2892 { 2893 struct addrinfo *host = NULL; 2894 struct addrinfo *h; 2895 struct sockaddr_in6 sin6; 2896 struct sockaddr_in sin; 2897 struct in6_addr addr6; 2898 struct in_addr addr; 2899 void *addrp; 2900 struct gateway *gw_addrs; 2901 char *hostname_list[MAXMAX_GATEWAY + 1] = {NULL}; 2902 char *opt_buf6 = NULL; /* used for IPv6 routing header */ 2903 size_t opt_buf_len6 = 0; 2904 uchar_t src_rtng_type; /* type of IPv4 source routing */ 2905 struct servent *sp = 0; 2906 char *opt_buf = NULL; /* used for IPv4 source routing */ 2907 size_t opt_buf_len = 0; 2908 char *cmd; 2909 char *hostp = NULL; 2910 char *portp = NULL; 2911 char *user = NULL; 2912 #ifdef ICMD 2913 char *itelnet_host; 2914 char *real_host; 2915 unsigned short dest_port; 2916 #endif /* ICMD */ 2917 /* 2918 * The two strings at the end of this function are 24 and 39 2919 * characters long (minus the %.*s in the format strings). Add 2920 * one for the null terminator making the longest print string 40. 2921 */ 2922 char buf[MAXHOSTNAMELEN+40]; 2923 /* 2924 * In the case of ICMD defined, dest_port will contain the real port 2925 * we are trying to telnet to, and target_port will contain 2926 * "telnet-passthru" port. 2927 */ 2928 unsigned short target_port; 2929 char abuf[INET6_ADDRSTRLEN]; 2930 int num_gw; 2931 int ret_val; 2932 boolean_t is_v4mapped; 2933 /* 2934 * Type of addresses we'll try to connect to (ALL_ADDRS, ONLY_V6, 2935 * ONLY_V4). 2936 */ 2937 int addr_type; 2938 2939 /* clear the socket address prior to use */ 2940 (void) memset(&sin6, '\0', sizeof (sin6)); 2941 sin6.sin6_family = AF_INET6; 2942 2943 (void) memset(&sin, '\0', sizeof (sin)); 2944 sin.sin_family = AF_INET; 2945 2946 if (connected) { 2947 (void) printf("?Already connected to %s\n", hostname); 2948 return (0); 2949 } 2950 #ifdef ICMD 2951 itelnet_host = getenv("INTERNET_HOST"); 2952 if (itelnet_host == NULL || itelnet_host[0] == '\0') { 2953 (void) printf("INTERNET_HOST environment variable undefined\n"); 2954 goto tn_exit; 2955 } 2956 #endif 2957 if (argc < 2) { 2958 (void) printf("(to) "); 2959 if (GetAndAppendString(&line, &linesize, "open ", 2960 stdin) == NULL) { 2961 if (!feof(stdin)) { 2962 perror("telnet"); 2963 goto tn_exit; 2964 } 2965 } 2966 makeargv(); 2967 argc = margc; 2968 argv = margv; 2969 } 2970 cmd = *argv; 2971 --argc; ++argv; 2972 while (argc) { 2973 if (isprefix(*argv, "help") == 4 || isprefix(*argv, "?") == 1) 2974 goto usage; 2975 if (strcmp(*argv, "-l") == 0) { 2976 --argc; ++argv; 2977 if (argc == 0) 2978 goto usage; 2979 user = *argv++; 2980 --argc; 2981 continue; 2982 } 2983 if (strcmp(*argv, "-a") == 0) { 2984 --argc; ++argv; 2985 autologin = autologin_set = 1; 2986 continue; 2987 } 2988 if (hostp == 0) { 2989 hostp = *argv++; 2990 --argc; 2991 continue; 2992 } 2993 if (portp == 0) { 2994 portp = *argv++; 2995 --argc; 2996 /* 2997 * Do we treat this like a telnet port or raw? 2998 */ 2999 if (*portp == '-') { 3000 portp++; 3001 telnetport = 1; 3002 } else 3003 telnetport = 0; 3004 continue; 3005 } 3006 usage: 3007 (void) printf( 3008 "usage: %s [-l user] [-a] host-name [port]\n", cmd); 3009 goto tn_exit; 3010 } 3011 if (hostp == 0) 3012 goto usage; 3013 3014 #ifdef ICMD 3015 /* 3016 * For setup phase treat the relay host as the target host. 3017 */ 3018 real_host = hostp; 3019 hostp = itelnet_host; 3020 #endif 3021 num_gw = parse_input(hostp, hostname_list, &src_rtng_type); 3022 if (num_gw < 0) { 3023 goto tn_exit; 3024 } 3025 3026 /* Last host in the hostname_list is the target */ 3027 hostp = hostname_list[num_gw]; 3028 3029 host = resolve_hosts(hostname_list, num_gw, &gw_addrs, &addr_type, 3030 portp); 3031 if (host == NULL) { 3032 goto tn_exit; 3033 } 3034 3035 /* 3036 * Check if number of gateways is less than max. available 3037 */ 3038 if ((addr_type == ALL_ADDRS || addr_type == ONLY_V6) && 3039 num_gw > MAX_GATEWAY6) { 3040 (void) fprintf(stderr, "telnet: too many IPv6 gateways\n"); 3041 goto tn_exit; 3042 } 3043 3044 if ((addr_type == ALL_ADDRS || addr_type == ONLY_V4) && 3045 num_gw > MAX_GATEWAY) { 3046 (void) fprintf(stderr, "telnet: too many IPv4 gateways\n"); 3047 goto tn_exit; 3048 } 3049 3050 /* 3051 * If we pass a literal IPv4 address to getaddrinfo(), in the 3052 * returned addrinfo structure, hostname is the IPv4-mapped IPv6 3053 * address string. We prefer to preserve the literal IPv4 address 3054 * string as the hostname. Also, if the hostname entered by the 3055 * user is IPv4-mapped IPv6 address, we'll downgrade it to IPv4 3056 * address. 3057 */ 3058 if (inet_addr(hostp) != (in_addr_t)-1) { 3059 /* this is a literal IPv4 address */ 3060 (void) strlcpy(_hostname, hostp, sizeof (_hostname)); 3061 } else if ((inet_pton(AF_INET6, hostp, &addr6) > 0) && 3062 IN6_IS_ADDR_V4MAPPED(&addr6)) { 3063 /* this is a IPv4-mapped IPv6 address */ 3064 IN6_V4MAPPED_TO_INADDR(&addr6, &addr); 3065 (void) inet_ntop(AF_INET, &addr, _hostname, sizeof (_hostname)); 3066 } else { 3067 (void) strlcpy(_hostname, host->ai_canonname, 3068 sizeof (_hostname)); 3069 } 3070 hostname = _hostname; 3071 3072 if (portp == NULL) { 3073 telnetport = 1; 3074 } 3075 3076 if (host->ai_family == AF_INET) { 3077 target_port = ((struct sockaddr_in *)(host->ai_addr))->sin_port; 3078 } else { 3079 target_port = ((struct sockaddr_in6 *)(host->ai_addr)) 3080 ->sin6_port; 3081 } 3082 3083 #ifdef ICMD 3084 /* 3085 * Since we pass the port number as an ascii string to the proxy, 3086 * we need it in host format. 3087 */ 3088 dest_port = ntohs(target_port); 3089 sp = getservbyname("telnet-passthru", "tcp"); 3090 if (sp == 0) { 3091 (void) fprintf(stderr, 3092 "telnet: tcp/telnet-passthru: unknown service\n"); 3093 goto tn_exit; 3094 } 3095 target_port = sp->s_port; 3096 #endif 3097 h = host; 3098 3099 /* 3100 * For IPv6 source routing, we need to initialize option buffer only 3101 * once. 3102 */ 3103 if (num_gw > 0 && (addr_type == ALL_ADDRS || addr_type == ONLY_V6)) { 3104 if (!prepare_optbuf6(gw_addrs, num_gw, &opt_buf6, 3105 &opt_buf_len6)) { 3106 goto tn_exit; 3107 } 3108 } 3109 3110 /* 3111 * We procure the Kerberos config files options only 3112 * if the user has choosen Krb5 authentication. 3113 */ 3114 if (krb5auth_flag > 0) { 3115 krb5_profile_get_options(hostname, telnet_krb5_realm, 3116 config_file_options); 3117 } 3118 3119 if (encrypt_flag) { 3120 extern boolean_t auth_enable_encrypt; 3121 if (krb5_privacy_allowed()) { 3122 encrypt_auto(1); 3123 decrypt_auto(1); 3124 wantencryption = B_TRUE; 3125 autologin = 1; 3126 auth_enable_encrypt = B_TRUE; 3127 } else { 3128 (void) fprintf(stderr, gettext( 3129 "%s:Encryption not supported.\n"), prompt); 3130 exit(1); 3131 } 3132 } 3133 3134 if (forward_flag && forwardable_flag) { 3135 (void) fprintf(stderr, gettext( 3136 "Error in krb5 configuration file. " 3137 "Both forward and forwardable are set.\n")); 3138 exit(1); 3139 } 3140 if (forwardable_flag) { 3141 forward_flags |= OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS; 3142 } else if (forward_flag) 3143 forward_flags |= OPTS_FORWARD_CREDS; 3144 3145 3146 do { 3147 /* 3148 * Search for an address of desired type in the IP address list 3149 * of the target. 3150 */ 3151 while (h != NULL) { 3152 struct sockaddr_in6 *addr; 3153 3154 addr = (struct sockaddr_in6 *)h->ai_addr; 3155 3156 if (h->ai_family == AF_INET6) 3157 is_v4mapped = 3158 IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr); 3159 else 3160 is_v4mapped = B_FALSE; 3161 3162 if (addr_type == ALL_ADDRS || 3163 (addr_type == ONLY_V6 && 3164 h->ai_family == AF_INET6) || 3165 (addr_type == ONLY_V4 && 3166 (h->ai_family == AF_INET || is_v4mapped))) 3167 break; 3168 3169 /* skip undesired typed addresses */ 3170 h = h->ai_next; 3171 } 3172 3173 if (h == NULL) { 3174 fprintf(stderr, 3175 "telnet: Unable to connect to remote host"); 3176 goto tn_exit; 3177 } 3178 3179 /* 3180 * We need to open a socket with a family matching the type of 3181 * address we are trying to connect to. This is because we 3182 * deal with IPv4 options and IPv6 extension headers. 3183 */ 3184 if (h->ai_family == AF_INET) { 3185 addrp = &((struct sockaddr_in *)(h->ai_addr))->sin_addr; 3186 ((struct sockaddr_in *)(h->ai_addr))->sin_port = 3187 target_port; 3188 } else { 3189 addrp = &((struct sockaddr_in6 *)(h->ai_addr)) 3190 ->sin6_addr; 3191 ((struct sockaddr_in6 *)(h->ai_addr))->sin6_port = 3192 target_port; 3193 } 3194 3195 (void) printf("Trying %s...\n", inet_ntop(h->ai_family, 3196 addrp, abuf, sizeof (abuf))); 3197 3198 net = socket(h->ai_family, SOCK_STREAM, 0); 3199 3200 if (net < 0) { 3201 perror("telnet: socket"); 3202 goto tn_exit; 3203 } 3204 #ifndef ICMD 3205 if (num_gw > 0) { 3206 if (h->ai_family == AF_INET || is_v4mapped) { 3207 if (!prepare_optbuf(gw_addrs, num_gw, &opt_buf, 3208 &opt_buf_len, addrp, src_rtng_type)) { 3209 goto tn_exit; 3210 } 3211 3212 if (setsockopt(net, IPPROTO_IP, IP_OPTIONS, 3213 opt_buf, opt_buf_len) < 0) 3214 perror("setsockopt (IP_OPTIONS)"); 3215 } else { 3216 if (setsockopt(net, IPPROTO_IPV6, IPV6_RTHDR, 3217 opt_buf6, opt_buf_len6) < 0) 3218 perror("setsockopt (IPV6_RTHDR)"); 3219 } 3220 } 3221 #endif 3222 #if defined(USE_TOS) 3223 if (is_v4mapped) { 3224 if (tos < 0) 3225 tos = 020; /* Low Delay bit */ 3226 if (tos && 3227 (setsockopt(net, IPPROTO_IP, IP_TOS, 3228 &tos, sizeof (int)) < 0) && 3229 (errno != ENOPROTOOPT)) 3230 perror("telnet: setsockopt (IP_TOS) (ignored)"); 3231 } 3232 #endif /* defined(USE_TOS) */ 3233 3234 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 3235 perror("setsockopt (SO_DEBUG)"); 3236 } 3237 3238 ret_val = connect(net, h->ai_addr, h->ai_addrlen); 3239 3240 /* 3241 * If failed, try the next address of the target. 3242 */ 3243 if (ret_val < 0) { 3244 Close(&net); 3245 if (h->ai_next != NULL) { 3246 3247 int oerrno = errno; 3248 3249 (void) fprintf(stderr, 3250 "telnet: connect to address %s: ", abuf); 3251 errno = oerrno; 3252 perror((char *)0); 3253 3254 h = h->ai_next; 3255 continue; 3256 } 3257 perror("telnet: Unable to connect to remote host"); 3258 goto tn_exit; 3259 } 3260 connected++; 3261 } while (connected == 0); 3262 freeaddrinfo(host); 3263 host = NULL; 3264 #ifdef ICMD 3265 /* 3266 * Do initial protocol to connect to farther end... 3267 */ 3268 { 3269 char buf[1024]; 3270 (void) sprintf(buf, "%s %d\n", real_host, (int)dest_port); 3271 write(net, buf, strlen(buf)); 3272 } 3273 #endif 3274 if (cmdrc(hostp, hostname) != 0) 3275 goto tn_exit; 3276 FreeHostnameList(hostname_list); 3277 if (autologin && user == NULL) { 3278 struct passwd *pw; 3279 3280 user = getenv("LOGNAME"); 3281 if (user == NULL || 3282 ((pw = getpwnam(user)) != NULL) && 3283 pw->pw_uid != getuid()) { 3284 if (pw = getpwuid(getuid())) 3285 user = pw->pw_name; 3286 else 3287 user = NULL; 3288 } 3289 } 3290 3291 if (user) { 3292 if (env_define((unsigned char *)"USER", (unsigned char *)user)) 3293 env_export((unsigned char *)"USER"); 3294 else { 3295 /* Clean up and exit. */ 3296 Close(&net); 3297 (void) snprintf(buf, sizeof (buf), 3298 "Connection to %.*s closed.\n", 3299 MAXHOSTNAMELEN, hostname); 3300 ExitString(buf, EXIT_FAILURE); 3301 3302 /* NOTREACHED */ 3303 } 3304 } 3305 (void) call(3, status, "status", "notmuch"); 3306 if (setjmp(peerdied) == 0) 3307 telnet(user); 3308 3309 Close(&net); 3310 3311 (void) snprintf(buf, sizeof (buf), 3312 "Connection to %.*s closed by foreign host.\n", 3313 MAXHOSTNAMELEN, hostname); 3314 ExitString(buf, EXIT_FAILURE); 3315 3316 /*NOTREACHED*/ 3317 3318 tn_exit: 3319 FreeHostnameList(hostname_list); 3320 Close(&net); 3321 connected = 0; 3322 if (host != NULL) 3323 freeaddrinfo(host); 3324 return (0); 3325 } 3326 3327 #define HELPINDENT (sizeof ("connect")) 3328 3329 static char openhelp[] = "connect to a site"; 3330 static char closehelp[] = "close current connection"; 3331 static char logouthelp[] = 3332 "forcibly logout remote user and close the connection"; 3333 static char quithelp[] = "exit telnet"; 3334 static char statushelp[] = "print status information"; 3335 static char helphelp[] = "print help information"; 3336 static char sendhelp[] = 3337 "transmit special characters ('send ?' for more)"; 3338 static char sethelp[] = "set operating parameters ('set ?' for more)"; 3339 static char unsethelp[] = "unset operating parameters ('unset ?' for more)"; 3340 static char togglestring[] = 3341 "toggle operating parameters ('toggle ?' for more)"; 3342 static char slchelp[] = "change state of special charaters ('slc ?' for more)"; 3343 static char displayhelp[] = "display operating parameters"; 3344 static char authhelp[] = 3345 "turn on (off) authentication ('auth ?' for more)"; 3346 static char forwardhelp[] = 3347 "turn on (off) credential forwarding ('forward ?' for more)"; 3348 static char encrypthelp[] = 3349 "turn on (off) encryption ('encrypt ?' for more)"; 3350 static char zhelp[] = "suspend telnet"; 3351 static char shellhelp[] = "invoke a subshell"; 3352 static char envhelp[] = "change environment variables ('environ ?' for more)"; 3353 static char modestring[] = 3354 "try to enter line or character mode ('mode ?' for more)"; 3355 3356 static int help(); 3357 3358 static Command cmdtab[] = { 3359 { "close", closehelp, bye, 1 }, 3360 { "logout", logouthelp, logout, 1 }, 3361 { "display", displayhelp, display, 0 }, 3362 { "mode", modestring, modecmd, 0 }, 3363 { "open", openhelp, tn, 0 }, 3364 { "quit", quithelp, quit, 0 }, 3365 { "send", sendhelp, sendcmd, 0 }, 3366 { "set", sethelp, setcmd, 0 }, 3367 { "unset", unsethelp, unsetcmd, 0 }, 3368 { "status", statushelp, status, 0 }, 3369 { "toggle", togglestring, toggle, 0 }, 3370 { "slc", slchelp, slccmd, 0 }, 3371 { "auth", authhelp, auth_cmd, 0 }, 3372 { "encrypt", encrypthelp, encrypt_cmd, 0 }, 3373 { "forward", forwardhelp, forw_cmd, 0 }, 3374 { "z", zhelp, suspend, 0 }, 3375 { "!", shellhelp, shell, 0 }, 3376 { "environ", envhelp, env_cmd, 0 }, 3377 { "?", helphelp, help, 0 }, 3378 0 3379 }; 3380 3381 3382 static Command cmdtab2[] = { 3383 { "help", 0, help, 0 }, 3384 { "escape", 0, setescape, 0 }, 3385 { "crmod", 0, togcrmod, 0 }, 3386 0 3387 }; 3388 3389 3390 /* 3391 * Call routine with argc, argv set from args. 3392 * Uses /usr/include/stdarg.h 3393 */ 3394 #define MAXVARGS 100 3395 /*VARARGS1*/ 3396 static void 3397 call(int n_ptrs, ...) 3398 { 3399 va_list ap; 3400 typedef int (*intrtn_t)(); 3401 intrtn_t routine; 3402 char *args[MAXVARGS+1]; /* leave 1 for trailing NULL */ 3403 int argno = 0; 3404 3405 if (n_ptrs > MAXVARGS) 3406 n_ptrs = MAXVARGS; 3407 va_start(ap, n_ptrs); 3408 3409 routine = (va_arg(ap, intrtn_t)); /* extract the routine's name */ 3410 n_ptrs--; 3411 3412 while (argno < n_ptrs) /* extract the routine's args */ 3413 args[argno++] = va_arg(ap, char *); 3414 args[argno] = NULL; /* NULL terminate for good luck */ 3415 va_end(ap); 3416 3417 (*routine)(argno, args); 3418 } 3419 3420 3421 static Command * 3422 getcmd(char *name) 3423 { 3424 Command *cm; 3425 3426 if (cm = (Command *) genget(name, (char **)cmdtab, sizeof (Command))) 3427 return (cm); 3428 return (Command *) genget(name, (char **)cmdtab2, sizeof (Command)); 3429 } 3430 3431 void 3432 command(int top, char *tbuf, int cnt) 3433 { 3434 Command *c; 3435 3436 setcommandmode(); 3437 if (!top) { 3438 (void) putchar('\n'); 3439 } else { 3440 (void) signal(SIGINT, SIG_DFL); 3441 (void) signal(SIGQUIT, SIG_DFL); 3442 } 3443 for (;;) { 3444 if (rlogin == _POSIX_VDISABLE) 3445 (void) printf("%s> ", prompt); 3446 if (tbuf) { 3447 char *cp; 3448 if (AllocStringBuffer(&line, &linesize, cnt) == NULL) 3449 goto command_exit; 3450 cp = line; 3451 while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 3452 cnt--; 3453 tbuf = 0; 3454 if (cp == line || *--cp != '\n' || cp == line) 3455 goto getline; 3456 *cp = '\0'; 3457 if (rlogin == _POSIX_VDISABLE) 3458 (void) printf("%s\n", line); 3459 } else { 3460 getline: 3461 if (rlogin != _POSIX_VDISABLE) 3462 (void) printf("%s> ", prompt); 3463 if (GetString(&line, &linesize, stdin) == NULL) { 3464 if (!feof(stdin)) 3465 perror("telnet"); 3466 (void) quit(); 3467 /*NOTREACHED*/ 3468 break; 3469 } 3470 } 3471 if (line[0] == 0) 3472 break; 3473 makeargv(); 3474 if (margv[0] == 0) { 3475 break; 3476 } 3477 c = getcmd(margv[0]); 3478 if (Ambiguous(c)) { 3479 (void) printf("?Ambiguous command\n"); 3480 continue; 3481 } 3482 if (c == 0) { 3483 (void) printf("?Invalid command\n"); 3484 continue; 3485 } 3486 if (c->needconnect && !connected) { 3487 (void) printf("?Need to be connected first.\n"); 3488 continue; 3489 } 3490 if ((*c->handler)(margc, margv)) { 3491 break; 3492 } 3493 } 3494 command_exit: 3495 if (!top) { 3496 if (!connected) { 3497 longjmp(toplevel, 1); 3498 /*NOTREACHED*/ 3499 } 3500 setconnmode(0); 3501 } 3502 } 3503 3504 /* 3505 * Help command. 3506 */ 3507 static int 3508 help(int argc, char *argv[]) 3509 { 3510 Command *c; 3511 3512 if (argc == 1) { 3513 (void) printf( 3514 "Commands may be abbreviated. Commands are:\n\n"); 3515 for (c = cmdtab; c->name; c++) 3516 if (c->help) { 3517 (void) printf("%-*s\t%s\n", HELPINDENT, 3518 c->name, c->help); 3519 } 3520 (void) printf("<return>\tleave command mode\n"); 3521 return (0); 3522 } 3523 while (--argc > 0) { 3524 char *arg; 3525 arg = *++argv; 3526 c = getcmd(arg); 3527 if (Ambiguous(c)) 3528 (void) printf("?Ambiguous help command %s\n", arg); 3529 else if (c == (Command *)0) 3530 (void) printf("?Invalid help command %s\n", arg); 3531 else if (c->help) { 3532 (void) printf("%s\n", c->help); 3533 } else { 3534 (void) printf("No additional help on %s\n", arg); 3535 } 3536 } 3537 return (0); 3538 } 3539 3540 static char *rcname = NULL; 3541 #define TELNETRC_NAME "telnetrc" 3542 #define TELNETRC_COMP "/." TELNETRC_NAME 3543 3544 static int 3545 cmdrc(char *m1, char *m2) 3546 { 3547 Command *c; 3548 FILE *rcfile = NULL; 3549 int gotmachine = 0; 3550 int l1 = strlen(m1); 3551 int l2 = strlen(m2); 3552 char m1save[MAXHOSTNAMELEN]; 3553 int ret = 0; 3554 char def[] = "DEFAULT"; 3555 3556 if (skiprc) 3557 goto cmdrc_exit; 3558 3559 doing_rc = 1; 3560 3561 (void) strlcpy(m1save, m1, sizeof (m1save)); 3562 m1 = m1save; 3563 3564 if (rcname == NULL) { 3565 char *homedir; 3566 unsigned rcbuflen; 3567 3568 if ((homedir = getenv("HOME")) == NULL) 3569 homedir = ""; 3570 3571 rcbuflen = strlen(homedir) + strlen(TELNETRC_COMP) + 1; 3572 if ((rcname = malloc(rcbuflen)) == NULL) { 3573 perror("telnet: can't process " TELNETRC_NAME); 3574 ret = 1; 3575 goto cmdrc_exit; 3576 } 3577 (void) strcpy(rcname, homedir); 3578 (void) strcat(rcname, TELNETRC_COMP); 3579 } 3580 3581 if ((rcfile = fopen(rcname, "r")) == NULL) 3582 goto cmdrc_exit; 3583 3584 for (;;) { 3585 if (GetString(&line, &linesize, rcfile) == NULL) { 3586 if (!feof(rcfile)) { 3587 perror("telnet: error reading " TELNETRC_NAME); 3588 ret = 1; 3589 goto cmdrc_exit; 3590 } 3591 break; 3592 } 3593 if (line[0] == 0) 3594 continue; 3595 if (line[0] == '#') 3596 continue; 3597 if (gotmachine) { 3598 if (!isspace(line[0])) 3599 gotmachine = 0; 3600 } 3601 if (gotmachine == 0) { 3602 if (isspace(line[0])) 3603 continue; 3604 if (strncasecmp(line, m1, l1) == 0) 3605 (void) strcpy(line, &line[l1]); 3606 else if (strncasecmp(line, m2, l2) == 0) 3607 (void) strcpy(line, &line[l2]); 3608 else if (strncasecmp(line, def, sizeof (def) - 1) == 0) 3609 (void) strcpy(line, &line[sizeof (def) - 1]); 3610 else 3611 continue; 3612 if (line[0] != ' ' && line[0] != '\t' && 3613 line[0] != '\n') 3614 continue; 3615 gotmachine = 1; 3616 } 3617 makeargv(); 3618 if (margv[0] == 0) 3619 continue; 3620 c = getcmd(margv[0]); 3621 if (Ambiguous(c)) { 3622 (void) printf("?Ambiguous command: %s\n", margv[0]); 3623 continue; 3624 } 3625 if (c == 0) { 3626 (void) printf("?Invalid command: %s\n", margv[0]); 3627 continue; 3628 } 3629 /* 3630 * This should never happen... 3631 */ 3632 if (c->needconnect && !connected) { 3633 (void) printf("?Need to be connected first for %s.\n", 3634 margv[0]); 3635 continue; 3636 } 3637 (*c->handler)(margc, margv); 3638 } 3639 cmdrc_exit: 3640 if (rcfile != NULL) 3641 (void) fclose(rcfile); 3642 doing_rc = 0; 3643 3644 return (ret); 3645 } 3646