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