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