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 2005 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 int 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 int 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 static int 2237 forw_set(int f_flags) 2238 { 2239 forward_flags = f_flags; 2240 return (0); 2241 } 2242 2243 static int 2244 forw_help(void) 2245 { 2246 struct forwlist *c; 2247 2248 for (c = ForwList; c->name; c++) { 2249 if (c->help) { 2250 if (*c->help) 2251 (void) printf("%-15s %s\r\n", c->name, c->help); 2252 else 2253 (void) printf("\n"); 2254 } 2255 } 2256 return (0); 2257 } 2258 2259 static int 2260 forw_cmd(int argc, char *argv[]) 2261 { 2262 struct forwlist *c; 2263 2264 if (argc < 2) { 2265 (void) fprintf(stderr, gettext( 2266 "Need an argument to 'forward' " 2267 "command. 'forward ?' for help.\n")); 2268 return (0); 2269 } 2270 c = (struct forwlist *)genget(argv[1], (char **)ForwList, 2271 sizeof (struct forwlist)); 2272 if (c == 0) { 2273 (void) fprintf(stderr, gettext( 2274 "'%s': unknown argument ('forward ?' for help).\n"), 2275 argv[1]); 2276 return (0); 2277 } 2278 if (Ambiguous(c)) { 2279 (void) fprintf(stderr, gettext( 2280 "'%s': ambiguous argument ('forward ?' for help).\n"), 2281 argv[1]); 2282 return (0); 2283 } 2284 if (argc != 2) { 2285 (void) fprintf(stderr, gettext( 2286 "No arguments needed to 'forward %s' command. " 2287 "'forward ?' for help.\n"), c->name); 2288 return (0); 2289 } 2290 return ((*c->handler) (c->f_flags)); 2291 } 2292 2293 /* 2294 * The ENCRYPT command. 2295 */ 2296 2297 struct encryptlist { 2298 char *name; 2299 char *help; 2300 int (*handler)(); 2301 int needconnect; 2302 int minarg; 2303 int maxarg; 2304 }; 2305 2306 static int EncryptHelp(void); 2307 2308 static struct encryptlist EncryptList[] = { 2309 { "enable", "Enable encryption. ('encrypt enable ?' for more)", 2310 EncryptEnable, 1, 1, 2 }, 2311 { "disable", "Disable encryption. ('encrypt disable ?' for more)", 2312 EncryptDisable, 0, 1, 2 }, 2313 { "type", "Set encryption type. ('encrypt type ?' for more)", 2314 EncryptType, 0, 1, 2 }, 2315 { "start", "Start encryption. ('encrypt start ?' for more)", 2316 EncryptStart, 1, 0, 1 }, 2317 { "stop", "Stop encryption. ('encrypt stop ?' for more)", 2318 EncryptStop, 1, 0, 1 }, 2319 { "input", "Start encrypting the input stream", 2320 EncryptStartInput, 1, 0, 0 }, 2321 { "-input", "Stop encrypting the input stream", 2322 EncryptStopInput, 1, 0, 0 }, 2323 { "output", "Start encrypting the output stream", 2324 EncryptStartOutput, 1, 0, 0 }, 2325 { "-output", "Stop encrypting the output stream", 2326 EncryptStopOutput, 1, 0, 0 }, 2327 2328 { "status", "Display current status of encryption information", 2329 EncryptStatus, 0, 0, 0 }, 2330 { "help", 0, 2331 EncryptHelp, 0, 0, 0 }, 2332 { "?", "Print help information", EncryptHelp, 0, 0, 0 }, 2333 { 0 }, 2334 }; 2335 2336 static int 2337 EncryptHelp(void) 2338 { 2339 struct encryptlist *c; 2340 2341 for (c = EncryptList; c->name; c++) { 2342 if (c->help) { 2343 if (*c->help) 2344 (void) printf("%-15s %s\n", c->name, c->help); 2345 else 2346 (void) printf("\n"); 2347 } 2348 } 2349 return (0); 2350 } 2351 2352 static int 2353 encrypt_cmd(int argc, char *argv[]) 2354 { 2355 struct encryptlist *c; 2356 2357 if (argc < 2) { 2358 (void) fprintf(stderr, gettext( 2359 "Need an argument to 'encrypt' command. " 2360 "'encrypt ?' for help.\n")); 2361 return (0); 2362 } 2363 2364 c = (struct encryptlist *) 2365 genget(argv[1], (char **)EncryptList, sizeof (struct encryptlist)); 2366 if (c == 0) { 2367 (void) fprintf(stderr, gettext( 2368 "'%s': unknown argument ('encrypt ?' for help).\n"), 2369 argv[1]); 2370 return (0); 2371 } 2372 if (Ambiguous(c)) { 2373 (void) fprintf(stderr, gettext( 2374 "'%s': ambiguous argument ('encrypt ?' for help).\n"), 2375 argv[1]); 2376 return (0); 2377 } 2378 argc -= 2; 2379 if (argc < c->minarg || argc > c->maxarg) { 2380 if (c->minarg == c->maxarg) { 2381 (void) fprintf(stderr, gettext("Need %s%d %s "), 2382 c->minarg < argc ? 2383 gettext("only ") : "", c->minarg, 2384 c->minarg == 1 ? 2385 gettext("argument") : gettext("arguments")); 2386 } else { 2387 (void) fprintf(stderr, 2388 gettext("Need %s%d-%d arguments "), 2389 c->maxarg < argc ? 2390 gettext("only ") : "", c->minarg, c->maxarg); 2391 } 2392 (void) fprintf(stderr, gettext( 2393 "to 'encrypt %s' command. 'encrypt ?' for help.\n"), 2394 c->name); 2395 return (0); 2396 } 2397 if (c->needconnect && !connected) { 2398 if (!(argc && 2399 (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) { 2400 (void) printf( 2401 gettext("?Need to be connected first.\n")); 2402 return (0); 2403 } 2404 } 2405 return ((*c->handler)(argc > 0 ? argv[2] : 0, 2406 argc > 1 ? argv[3] : 0, argc > 2 ? argv[4] : 0)); 2407 } 2408 2409 /* 2410 * Print status about the connection. 2411 */ 2412 static int 2413 status(int argc, char *argv[]) 2414 { 2415 if (connected) { 2416 (void) printf("Connected to %s.\n", hostname); 2417 if ((argc < 2) || strcmp(argv[1], "notmuch")) { 2418 int mode = getconnmode(); 2419 2420 if (my_want_state_is_will(TELOPT_LINEMODE)) { 2421 (void) printf( 2422 "Operating with LINEMODE option\n"); 2423 (void) printf( 2424 "%s line editing\n", (mode&MODE_EDIT) ? 2425 "Local" : "No"); 2426 (void) printf("%s catching of signals\n", 2427 (mode&MODE_TRAPSIG) ? "Local" : "No"); 2428 slcstate(); 2429 #ifdef KLUDGELINEMODE 2430 } else if (kludgelinemode && 2431 my_want_state_is_dont(TELOPT_SGA)) { 2432 (void) printf( 2433 "Operating in obsolete linemode\n"); 2434 #endif 2435 } else { 2436 (void) printf( 2437 "Operating in single character mode\n"); 2438 if (localchars) 2439 (void) printf( 2440 "Catching signals locally\n"); 2441 } 2442 (void) printf("%s character echo\n", (mode&MODE_ECHO) ? 2443 "Local" : "Remote"); 2444 if (my_want_state_is_will(TELOPT_LFLOW)) 2445 (void) printf("%s flow control\n", 2446 (mode&MODE_FLOW) ? "Local" : "No"); 2447 2448 encrypt_display(); 2449 } 2450 } else { 2451 (void) printf("No connection.\n"); 2452 } 2453 if (rlogin != _POSIX_VDISABLE) 2454 (void) printf("Escape character is '%s'.\n", control(rlogin)); 2455 else 2456 (void) printf( 2457 "Escape character is '%s'.\n", esc_control(escape)); 2458 (void) fflush(stdout); 2459 return (1); 2460 } 2461 2462 /* 2463 * Parse the user input (cmd_line_input) which should: 2464 * - start with the target host, or with "@" or "!@" followed by at least one 2465 * gateway. 2466 * - each host (can be literal address or hostname) can be separated by ",", 2467 * "@", or ",@". 2468 * Note that the last host is the target, all the others (if any ) are the 2469 * gateways. 2470 * 2471 * Returns: -1 if a library call fails, too many gateways, or parse 2472 * error 2473 * num_gw otherwise 2474 * On successful return, hostname_list points to a list of hosts (last one being 2475 * the target, others gateways), src_rtng_type points to the type of source 2476 * routing (strict vs. loose) 2477 */ 2478 static int 2479 parse_input(char *cmd_line_input, char **hostname_list, uchar_t *src_rtng_type) 2480 { 2481 char hname[MAXHOSTNAMELEN + 1]; 2482 char *cp; 2483 int gw_count; 2484 int i; 2485 2486 gw_count = 0; 2487 cp = cmd_line_input; 2488 2489 /* 2490 * Defining ICMD generates the Itelnet binary, the special version of 2491 * telnet which is used with firewall proxy. 2492 * If ICMD is defined, parse_input will treat the whole cmd_line_input 2493 * as the target host and set the num_gw to 0. Therefore, none of the 2494 * source routing related code paths will be executed. 2495 */ 2496 #ifndef ICMD 2497 if (*cp == '@') { 2498 *src_rtng_type = IPOPT_LSRR; 2499 cp++; 2500 } else if (*cp == '!') { 2501 *src_rtng_type = IPOPT_SSRR; 2502 2503 /* "!" must be followed by '@' */ 2504 if (*(cp + 1) != '@') 2505 goto parse_error; 2506 cp += 2; 2507 } else { 2508 #endif /* ICMD */ 2509 /* no gateways, just the target */ 2510 hostname_list[0] = strdup(cp); 2511 if (hostname_list[0] == NULL) { 2512 perror("telnet: copying host name"); 2513 return (-1); 2514 } 2515 return (0); 2516 #ifndef ICMD 2517 } 2518 2519 while (*cp != '\0') { 2520 /* 2521 * Identify each gateway separated by ",", "@" or ",@" and 2522 * store in hname[]. 2523 */ 2524 i = 0; 2525 while (*cp != '@' && *cp != ',' && *cp != '\0') { 2526 hname[i++] = *cp++; 2527 if (i > MAXHOSTNAMELEN) 2528 goto parse_error; 2529 } 2530 hname[i] = '\0'; 2531 2532 /* 2533 * Two consecutive delimiters which result in a 0 length hname 2534 * is a parse error. 2535 */ 2536 if (i == 0) 2537 goto parse_error; 2538 2539 hostname_list[gw_count] = strdup(hname); 2540 if (hostname_list[gw_count] == NULL) { 2541 perror("telnet: copying hostname from list"); 2542 return (-1); 2543 } 2544 2545 if (++gw_count > MAXMAX_GATEWAY) { 2546 (void) fprintf(stderr, "telnet: too many gateways\n"); 2547 return (-1); 2548 } 2549 2550 /* Jump over the next delimiter. */ 2551 if (*cp != '\0') { 2552 /* ...gw1,@gw2... accepted */ 2553 if (*cp == ',' && *(cp + 1) == '@') 2554 cp += 2; 2555 else 2556 cp++; 2557 } 2558 } 2559 2560 /* discount the target */ 2561 gw_count--; 2562 2563 /* Any input starting with '!@' or '@' must have at least one gateway */ 2564 if (gw_count <= 0) 2565 goto parse_error; 2566 2567 return (gw_count); 2568 2569 parse_error: 2570 (void) printf("Bad source route option: %s\n", cmd_line_input); 2571 return (-1); 2572 #endif /* ICMD */ 2573 } 2574 2575 /* 2576 * Resolves the target and gateway addresses, determines what type of addresses 2577 * (ALL_ADDRS, ONLY_V6, ONLY_V4) telnet will be trying to connect. 2578 * 2579 * Returns: pointer to resolved target if name resolutions succeed 2580 * NULL if name resolutions fail or 2581 * a library function call fails 2582 * 2583 * The last host in the hostname_list is the target. After resolving the target, 2584 * determines for what type of addresses it should try to resolve gateways. It 2585 * resolves gateway addresses and picks one address for each desired address 2586 * type and stores in the array pointed by gw_addrsp. Also, this 'type of 2587 * addresses' is pointed by addr_type argument on successful return. 2588 */ 2589 static struct addrinfo * 2590 resolve_hosts(char **hostname_list, int num_gw, struct gateway **gw_addrsp, 2591 int *addr_type, const char *portp) 2592 { 2593 struct gateway *gw_addrs = NULL; 2594 struct gateway *gw; 2595 /* whether we already picked an IPv4 address for the current gateway */ 2596 boolean_t got_v4_addr; 2597 boolean_t got_v6_addr; 2598 /* whether we need to get an IPv4 address for the current gateway */ 2599 boolean_t need_v4_addr = B_FALSE; 2600 boolean_t need_v6_addr = B_FALSE; 2601 int res_failed_at4; /* save which gateway failed to resolve */ 2602 int res_failed_at6; 2603 boolean_t is_v4mapped; 2604 struct in6_addr *v6addrp; 2605 struct in_addr *v4addrp; 2606 int error_num; 2607 int i; 2608 int rc; 2609 struct addrinfo *res, *host, *gateway, *addr; 2610 struct addrinfo hints; 2611 2612 *addr_type = ALL_ADDRS; 2613 2614 memset(&hints, 0, sizeof (hints)); 2615 hints.ai_flags = AI_CANONNAME; /* used for config files, diags */ 2616 hints.ai_socktype = SOCK_STREAM; 2617 rc = getaddrinfo(hostname_list[num_gw], 2618 (portp != NULL) ? portp : "telnet", &hints, &res); 2619 if (rc != 0) { 2620 if (hostname_list[num_gw] != NULL && 2621 *hostname_list[num_gw] != '\0') 2622 (void) fprintf(stderr, "%s: ", hostname_list[num_gw]); 2623 (void) fprintf(stderr, "%s\n", gai_strerror(rc)); 2624 return (NULL); 2625 } 2626 2627 /* 2628 * Let's see what type of addresses we got for the target. This 2629 * determines what type of addresses we'd like to resolve gateways 2630 * later. 2631 */ 2632 for (host = res; host != NULL; host = host->ai_next) { 2633 struct sockaddr_in6 *s6; 2634 2635 s6 = (struct sockaddr_in6 *)host->ai_addr; 2636 2637 if (host->ai_addr->sa_family == AF_INET || 2638 IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr)) 2639 need_v4_addr = B_TRUE; 2640 else 2641 need_v6_addr = B_TRUE; 2642 2643 /* 2644 * Let's stop after seeing we need both IPv6 and IPv4. 2645 */ 2646 if (need_v4_addr && need_v6_addr) 2647 break; 2648 } 2649 2650 if (num_gw > 0) { 2651 /* 2652 * In the prepare_optbuf(), we'll store the IPv4 address of the 2653 * target in the last slot of gw_addrs array. Therefore we need 2654 * space for num_gw+1 hosts. 2655 */ 2656 gw_addrs = calloc(num_gw + 1, sizeof (struct gateway)); 2657 if (gw_addrs == NULL) { 2658 perror("telnet: calloc"); 2659 freeaddrinfo(res); 2660 return (NULL); 2661 } 2662 } 2663 2664 /* 2665 * Now we'll go through all the gateways and try to resolve them to 2666 * the desired address types. 2667 */ 2668 gw = gw_addrs; 2669 2670 /* -1 means 'no address resolution failure yet' */ 2671 res_failed_at4 = -1; 2672 res_failed_at6 = -1; 2673 for (i = 0; i < num_gw; i++) { 2674 rc = getaddrinfo(hostname_list[i], NULL, NULL, &gateway); 2675 if (rc != 0) { 2676 if (hostname_list[i] != NULL && 2677 *hostname_list[i] != '\0') 2678 (void) fprintf(stderr, "%s: ", 2679 hostname_list[i]); 2680 (void) fprintf(stderr, "bad address\n"); 2681 return (NULL); 2682 } 2683 2684 /* 2685 * Initially we have no address of any type for this gateway. 2686 */ 2687 got_v6_addr = B_FALSE; 2688 got_v4_addr = B_FALSE; 2689 2690 /* 2691 * Let's go through all the addresses of this gateway. 2692 * Use the first address which matches the needed family. 2693 */ 2694 for (addr = gateway; addr != NULL; addr = addr->ai_next) { 2695 /*LINTED*/ 2696 v6addrp = &((struct sockaddr_in6 *)addr->ai_addr)-> 2697 sin6_addr; 2698 v4addrp = &((struct sockaddr_in *)addr->ai_addr)-> 2699 sin_addr; 2700 2701 if (addr->ai_family == AF_INET6) 2702 is_v4mapped = IN6_IS_ADDR_V4MAPPED(v6addrp); 2703 else 2704 is_v4mapped = B_FALSE; 2705 2706 /* 2707 * If we need to determine an IPv4 address and haven't 2708 * found one yet and this is a IPv4-mapped IPv6 address, 2709 * then bingo! 2710 */ 2711 if (need_v4_addr && !got_v4_addr) { 2712 if (is_v4mapped) { 2713 IN6_V4MAPPED_TO_INADDR(v6addrp, 2714 &gw->gw_addr); 2715 got_v4_addr = B_TRUE; 2716 } else if (addr->ai_family = AF_INET) { 2717 gw->gw_addr = *v4addrp; 2718 got_v4_addr = B_TRUE; 2719 } 2720 } 2721 2722 if (need_v6_addr && !got_v6_addr && 2723 addr->ai_family == AF_INET6) { 2724 gw->gw_addr6 = *v6addrp; 2725 got_v6_addr = B_TRUE; 2726 } 2727 2728 /* 2729 * Let's stop if we got all what we looked for. 2730 */ 2731 if ((!need_v4_addr || got_v4_addr) && 2732 (!need_v6_addr || got_v6_addr)) 2733 break; 2734 } 2735 2736 /* 2737 * We needed an IPv4 address for this gateway but couldn't 2738 * find one. 2739 */ 2740 if (need_v4_addr && !got_v4_addr) { 2741 res_failed_at4 = i; 2742 /* 2743 * Since we couldn't resolve a gateway to IPv4 address 2744 * we can't use IPv4 at all. Therefore we no longer 2745 * need IPv4 addresses for any of the gateways. 2746 */ 2747 need_v4_addr = B_FALSE; 2748 } 2749 2750 if (need_v6_addr && !got_v6_addr) { 2751 res_failed_at6 = i; 2752 need_v6_addr = B_FALSE; 2753 } 2754 2755 /* 2756 * If some gateways don't resolve to any of the desired 2757 * address types, we fail. 2758 */ 2759 if (!need_v4_addr && !need_v6_addr) { 2760 if (res_failed_at6 != -1) { 2761 (void) fprintf(stderr, 2762 "%s: Host doesn't have any IPv6 address\n", 2763 hostname_list[res_failed_at6]); 2764 } 2765 if (res_failed_at4 != -1) { 2766 (void) fprintf(stderr, 2767 "%s: Host doesn't have any IPv4 address\n", 2768 hostname_list[res_failed_at4]); 2769 } 2770 free(gw_addrs); 2771 return (NULL); 2772 } 2773 2774 gw++; 2775 } 2776 2777 *gw_addrsp = gw_addrs; 2778 2779 /* 2780 * When we get here, need_v4_addr and need_v6_addr have their final 2781 * values based on the name resolution of the target and gateways. 2782 */ 2783 if (need_v4_addr && need_v6_addr) 2784 *addr_type = ALL_ADDRS; 2785 else if (need_v4_addr && !need_v6_addr) 2786 *addr_type = ONLY_V4; 2787 else if (!need_v4_addr && need_v6_addr) 2788 *addr_type = ONLY_V6; 2789 2790 return (res); 2791 } 2792 2793 2794 /* 2795 * Initializes the buffer pointed by opt_bufpp for a IPv4 option of type 2796 * src_rtng_type using the gateway addresses stored in gw_addrs. If no buffer 2797 * is passed, it allocates one. If a buffer is passed, checks if it's big 2798 * enough. 2799 * On return opt_buf_len points to the buffer length which we need later for the 2800 * setsockopt() call, and opt_bufpp points to the newly allocated or already 2801 * passed buffer. Returns B_FALSE if a library function call fails or passed 2802 * buffer is not big enough, B_TRUE otherwise. 2803 */ 2804 static boolean_t 2805 prepare_optbuf(struct gateway *gw_addrs, int num_gw, char **opt_bufpp, 2806 size_t *opt_buf_len, struct in_addr *target, uchar_t src_rtng_type) 2807 { 2808 struct ip_sourceroute *sr_opt; 2809 size_t needed_buflen; 2810 int i; 2811 2812 /* 2813 * We have (num_gw + 1) IP addresses in the buffer because the number 2814 * of gateway addresses we put in the option buffer includes the target 2815 * address. 2816 * At the time of setsockopt() call, passed option length needs to be 2817 * multiple of 4 bytes. Therefore we need one IPOPT_NOP before (or 2818 * after) IPOPT_LSRR. 2819 * 1 = preceding 1 byte of IPOPT_NOP 2820 * 3 = 1 (code) + 1 (len) + 1 (ptr) 2821 */ 2822 needed_buflen = 1 + 3 + (num_gw + 1) * sizeof (struct in_addr); 2823 2824 if (*opt_bufpp != NULL) { 2825 /* check if the passed buffer is big enough */ 2826 if (*opt_buf_len < needed_buflen) { 2827 (void) fprintf(stderr, 2828 "telnet: buffer too small for IPv4 source routing " 2829 "option\n"); 2830 return (B_FALSE); 2831 } 2832 } else { 2833 *opt_bufpp = malloc(needed_buflen); 2834 if (*opt_bufpp == NULL) { 2835 perror("telnet: malloc"); 2836 return (B_FALSE); 2837 } 2838 } 2839 2840 *opt_buf_len = needed_buflen; 2841 2842 /* final hop is the target */ 2843 gw_addrs[num_gw].gw_addr = *target; 2844 2845 *opt_bufpp[0] = IPOPT_NOP; 2846 /* IPOPT_LSRR starts right after IPOPT_NOP */ 2847 sr_opt = (struct ip_sourceroute *)(*opt_bufpp + 1); 2848 sr_opt->ipsr_code = src_rtng_type; 2849 /* discount the 1 byte of IPOPT_NOP */ 2850 sr_opt->ipsr_len = needed_buflen - 1; 2851 sr_opt->ipsr_ptr = IPOPT_MINOFF; 2852 2853 /* copy the gateways into the optlist */ 2854 for (i = 0; i < num_gw + 1; i++) { 2855 (void) bcopy(&gw_addrs[i].gw_addr, &sr_opt->ipsr_addrs[i], 2856 sizeof (struct in_addr)); 2857 } 2858 2859 return (B_TRUE); 2860 } 2861 2862 /* 2863 * Initializes the buffer pointed by opt_bufpp for a IPv6 routing header option 2864 * using the gateway addresses stored in gw_addrs. If no buffer is passed, it 2865 * allocates one. If a buffer is passed, checks if it's big enough. 2866 * On return opt_buf_len points to the buffer length which we need later for the 2867 * setsockopt() call, and opt_bufpp points to the newly allocated or already 2868 * passed buffer. Returns B_FALSE if a library function call fails or passed 2869 * buffer is not big enough, B_TRUE otherwise. 2870 */ 2871 static boolean_t 2872 prepare_optbuf6(struct gateway *gw_addrs, int num_gw, char **opt_bufpp, 2873 size_t *opt_buf_len) 2874 { 2875 char *opt_bufp; 2876 size_t needed_buflen; 2877 int i; 2878 2879 needed_buflen = inet6_rth_space(IPV6_RTHDR_TYPE_0, num_gw); 2880 2881 if (*opt_bufpp != NULL) { 2882 /* check if the passed buffer is big enough */ 2883 if (*opt_buf_len < needed_buflen) { 2884 (void) fprintf(stderr, 2885 "telnet: buffer too small for IPv6 routing " 2886 "header option\n"); 2887 return (B_FALSE); 2888 } 2889 } else { 2890 *opt_bufpp = malloc(needed_buflen); 2891 if (*opt_bufpp == NULL) { 2892 perror("telnet: malloc"); 2893 return (B_FALSE); 2894 } 2895 } 2896 *opt_buf_len = needed_buflen; 2897 opt_bufp = *opt_bufpp; 2898 2899 /* 2900 * Initialize the buffer to be used for IPv6 routing header type 0. 2901 */ 2902 if (inet6_rth_init(opt_bufp, needed_buflen, IPV6_RTHDR_TYPE_0, 2903 num_gw) == NULL) { 2904 perror("telnet: inet6_rth_init"); 2905 return (B_FALSE); 2906 } 2907 2908 /* 2909 * Add gateways one by one. 2910 */ 2911 for (i = 0; i < num_gw; i++) { 2912 if (inet6_rth_add(opt_bufp, &gw_addrs[i].gw_addr6) == -1) { 2913 perror("telnet: inet6_rth_add"); 2914 return (B_FALSE); 2915 } 2916 } 2917 2918 /* successful operation */ 2919 return (B_TRUE); 2920 } 2921 2922 int 2923 tn(argc, argv) 2924 int argc; 2925 char *argv[]; 2926 { 2927 struct addrinfo *host = NULL; 2928 struct addrinfo *h; 2929 struct sockaddr_in6 sin6; 2930 struct sockaddr_in sin; 2931 struct in6_addr addr6; 2932 struct in_addr addr; 2933 void *addrp; 2934 struct gateway *gw_addrs; 2935 char *hostname_list[MAXMAX_GATEWAY + 1] = {NULL}; 2936 char *opt_buf6 = NULL; /* used for IPv6 routing header */ 2937 size_t opt_buf_len6 = 0; 2938 uchar_t src_rtng_type; /* type of IPv4 source routing */ 2939 struct servent *sp = 0; 2940 char *opt_buf = NULL; /* used for IPv4 source routing */ 2941 size_t opt_buf_len = 0; 2942 char *cmd; 2943 char *hostp = NULL; 2944 char *portp = NULL; 2945 char *user = NULL; 2946 #ifdef ICMD 2947 char *itelnet_host; 2948 char *real_host; 2949 unsigned short dest_port; 2950 #endif /* ICMD */ 2951 /* 2952 * The two strings at the end of this function are 24 and 39 2953 * characters long (minus the %.*s in the format strings). Add 2954 * one for the null terminator making the longest print string 40. 2955 */ 2956 char buf[MAXHOSTNAMELEN+40]; 2957 /* 2958 * In the case of ICMD defined, dest_port will contain the real port 2959 * we are trying to telnet to, and target_port will contain 2960 * "telnet-passthru" port. 2961 */ 2962 unsigned short target_port; 2963 char abuf[INET6_ADDRSTRLEN]; 2964 int num_gw; 2965 int ret_val; 2966 boolean_t is_v4mapped; 2967 /* 2968 * Type of addresses we'll try to connect to (ALL_ADDRS, ONLY_V6, 2969 * ONLY_V4). 2970 */ 2971 int addr_type; 2972 2973 /* clear the socket address prior to use */ 2974 (void) memset(&sin6, '\0', sizeof (sin6)); 2975 sin6.sin6_family = AF_INET6; 2976 2977 (void) memset(&sin, '\0', sizeof (sin)); 2978 sin.sin_family = AF_INET; 2979 2980 if (connected) { 2981 (void) printf("?Already connected to %s\n", hostname); 2982 return (0); 2983 } 2984 #ifdef ICMD 2985 itelnet_host = getenv("INTERNET_HOST"); 2986 if (itelnet_host == NULL || itelnet_host[0] == '\0') { 2987 (void) printf("INTERNET_HOST environment variable undefined\n"); 2988 goto tn_exit; 2989 } 2990 #endif 2991 if (argc < 2) { 2992 (void) printf("(to) "); 2993 if (GetAndAppendString(&line, &linesize, "open ", 2994 stdin) == NULL) { 2995 if (!feof(stdin)) { 2996 perror("telnet"); 2997 goto tn_exit; 2998 } 2999 } 3000 makeargv(); 3001 argc = margc; 3002 argv = margv; 3003 } 3004 cmd = *argv; 3005 --argc; ++argv; 3006 while (argc) { 3007 if (isprefix(*argv, "help") == 4 || isprefix(*argv, "?") == 1) 3008 goto usage; 3009 if (strcmp(*argv, "-l") == 0) { 3010 --argc; ++argv; 3011 if (argc == 0) 3012 goto usage; 3013 user = *argv++; 3014 --argc; 3015 continue; 3016 } 3017 if (strcmp(*argv, "-a") == 0) { 3018 --argc; ++argv; 3019 autologin = autologin_set = 1; 3020 continue; 3021 } 3022 if (hostp == 0) { 3023 hostp = *argv++; 3024 --argc; 3025 continue; 3026 } 3027 if (portp == 0) { 3028 portp = *argv++; 3029 --argc; 3030 /* 3031 * Do we treat this like a telnet port or raw? 3032 */ 3033 if (*portp == '-') { 3034 portp++; 3035 telnetport = 1; 3036 } else 3037 telnetport = 0; 3038 continue; 3039 } 3040 usage: 3041 (void) printf( 3042 "usage: %s [-l user] [-a] host-name [port]\n", cmd); 3043 goto tn_exit; 3044 } 3045 if (hostp == 0) 3046 goto usage; 3047 3048 #ifdef ICMD 3049 /* 3050 * For setup phase treat the relay host as the target host. 3051 */ 3052 real_host = hostp; 3053 hostp = itelnet_host; 3054 #endif 3055 num_gw = parse_input(hostp, hostname_list, &src_rtng_type); 3056 if (num_gw < 0) { 3057 goto tn_exit; 3058 } 3059 3060 /* Last host in the hostname_list is the target */ 3061 hostp = hostname_list[num_gw]; 3062 3063 host = resolve_hosts(hostname_list, num_gw, &gw_addrs, &addr_type, 3064 portp); 3065 if (host == NULL) { 3066 goto tn_exit; 3067 } 3068 3069 /* 3070 * Check if number of gateways is less than max. available 3071 */ 3072 if ((addr_type == ALL_ADDRS || addr_type == ONLY_V6) && 3073 num_gw > MAX_GATEWAY6) { 3074 (void) fprintf(stderr, "telnet: too many IPv6 gateways\n"); 3075 goto tn_exit; 3076 } 3077 3078 if ((addr_type == ALL_ADDRS || addr_type == ONLY_V4) && 3079 num_gw > MAX_GATEWAY) { 3080 (void) fprintf(stderr, "telnet: too many IPv4 gateways\n"); 3081 goto tn_exit; 3082 } 3083 3084 /* 3085 * If we pass a literal IPv4 address to getaddrinfo(), in the 3086 * returned addrinfo structure, hostname is the IPv4-mapped IPv6 3087 * address string. We prefer to preserve the literal IPv4 address 3088 * string as the hostname. Also, if the hostname entered by the 3089 * user is IPv4-mapped IPv6 address, we'll downgrade it to IPv4 3090 * address. 3091 */ 3092 if (inet_addr(hostp) != (in_addr_t)-1) { 3093 /* this is a literal IPv4 address */ 3094 (void) strlcpy(_hostname, hostp, sizeof (_hostname)); 3095 } else if ((inet_pton(AF_INET6, hostp, &addr6) > 0) && 3096 IN6_IS_ADDR_V4MAPPED(&addr6)) { 3097 /* this is a IPv4-mapped IPv6 address */ 3098 IN6_V4MAPPED_TO_INADDR(&addr6, &addr); 3099 (void) inet_ntop(AF_INET, &addr, _hostname, sizeof (_hostname)); 3100 } else { 3101 (void) strlcpy(_hostname, host->ai_canonname, 3102 sizeof (_hostname)); 3103 } 3104 hostname = _hostname; 3105 3106 if (portp == NULL) { 3107 telnetport = 1; 3108 } 3109 3110 if (host->ai_family == AF_INET) { 3111 target_port = ((struct sockaddr_in *)(host->ai_addr))->sin_port; 3112 } else { 3113 target_port = ((struct sockaddr_in6 *)(host->ai_addr)) 3114 ->sin6_port; 3115 } 3116 3117 #ifdef ICMD 3118 /* 3119 * Since we pass the port number as an ascii string to the proxy, 3120 * we need it in host format. 3121 */ 3122 dest_port = ntohs(target_port); 3123 sp = getservbyname("telnet-passthru", "tcp"); 3124 if (sp == 0) { 3125 (void) fprintf(stderr, 3126 "telnet: tcp/telnet-passthru: unknown service\n"); 3127 goto tn_exit; 3128 } 3129 target_port = sp->s_port; 3130 #endif 3131 h = host; 3132 3133 /* 3134 * For IPv6 source routing, we need to initialize option buffer only 3135 * once. 3136 */ 3137 if (num_gw > 0 && (addr_type == ALL_ADDRS || addr_type == ONLY_V6)) { 3138 if (!prepare_optbuf6(gw_addrs, num_gw, &opt_buf6, 3139 &opt_buf_len6)) { 3140 goto tn_exit; 3141 } 3142 } 3143 3144 /* 3145 * We procure the Kerberos config files options only 3146 * if the user has choosen Krb5 authentication. 3147 */ 3148 if (krb5auth_flag > 0) { 3149 krb5_profile_get_options(hostname, telnet_krb5_realm, 3150 config_file_options); 3151 } 3152 3153 if (encrypt_flag) { 3154 extern boolean_t auth_enable_encrypt; 3155 if (krb5_privacy_allowed()) { 3156 encrypt_auto(1); 3157 decrypt_auto(1); 3158 wantencryption = B_TRUE; 3159 autologin = 1; 3160 auth_enable_encrypt = B_TRUE; 3161 } else { 3162 (void) fprintf(stderr, gettext( 3163 "%s:Encryption not supported.\n"), prompt); 3164 exit(1); 3165 } 3166 } 3167 3168 if (forward_flag && forwardable_flag) { 3169 (void) fprintf(stderr, gettext( 3170 "Error in krb5 configuration file. " 3171 "Both forward and forwardable are set.\n")); 3172 exit(1); 3173 } 3174 if (forwardable_flag) { 3175 forward_flags |= OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS; 3176 } else if (forward_flag) 3177 forward_flags |= OPTS_FORWARD_CREDS; 3178 3179 3180 do { 3181 /* 3182 * Search for an address of desired type in the IP address list 3183 * of the target. 3184 */ 3185 while (h != NULL) { 3186 struct sockaddr_in6 *addr; 3187 3188 addr = (struct sockaddr_in6 *)h->ai_addr; 3189 3190 if (h->ai_family == AF_INET6) 3191 is_v4mapped = 3192 IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr); 3193 else 3194 is_v4mapped = B_FALSE; 3195 3196 if (addr_type == ALL_ADDRS || 3197 (addr_type == ONLY_V6 && 3198 h->ai_family == AF_INET6) || 3199 (addr_type == ONLY_V4 && 3200 (h->ai_family == AF_INET || is_v4mapped))) 3201 break; 3202 3203 /* skip undesired typed addresses */ 3204 h = h->ai_next; 3205 } 3206 3207 if (h == NULL) { 3208 fprintf(stderr, 3209 "telnet: Unable to connect to remote host"); 3210 goto tn_exit; 3211 } 3212 3213 /* 3214 * We need to open a socket with a family matching the type of 3215 * address we are trying to connect to. This is because we 3216 * deal with IPv4 options and IPv6 extension headers. 3217 */ 3218 if (h->ai_family == AF_INET) { 3219 addrp = &((struct sockaddr_in *)(h->ai_addr))->sin_addr; 3220 ((struct sockaddr_in *)(h->ai_addr))->sin_port = 3221 target_port; 3222 } else { 3223 addrp = &((struct sockaddr_in6 *)(h->ai_addr)) 3224 ->sin6_addr; 3225 ((struct sockaddr_in6 *)(h->ai_addr))->sin6_port = 3226 target_port; 3227 } 3228 3229 (void) printf("Trying %s...\n", inet_ntop(h->ai_family, 3230 addrp, abuf, sizeof (abuf))); 3231 3232 net = socket(h->ai_family, SOCK_STREAM, 0); 3233 3234 if (net < 0) { 3235 perror("telnet: socket"); 3236 goto tn_exit; 3237 } 3238 #ifndef ICMD 3239 if (num_gw > 0) { 3240 if (h->ai_family == AF_INET || is_v4mapped) { 3241 if (!prepare_optbuf(gw_addrs, num_gw, &opt_buf, 3242 &opt_buf_len, addrp, src_rtng_type)) { 3243 goto tn_exit; 3244 } 3245 3246 if (setsockopt(net, IPPROTO_IP, IP_OPTIONS, 3247 opt_buf, opt_buf_len) < 0) 3248 perror("setsockopt (IP_OPTIONS)"); 3249 } else { 3250 if (setsockopt(net, IPPROTO_IPV6, IPV6_RTHDR, 3251 opt_buf6, opt_buf_len6) < 0) 3252 perror("setsockopt (IPV6_RTHDR)"); 3253 } 3254 } 3255 #endif 3256 #if defined(USE_TOS) 3257 if (is_v4mapped) { 3258 if (tos < 0) 3259 tos = 020; /* Low Delay bit */ 3260 if (tos && 3261 (setsockopt(net, IPPROTO_IP, IP_TOS, 3262 &tos, sizeof (int)) < 0) && 3263 (errno != ENOPROTOOPT)) 3264 perror("telnet: setsockopt (IP_TOS) (ignored)"); 3265 } 3266 #endif /* defined(USE_TOS) */ 3267 3268 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) { 3269 perror("setsockopt (SO_DEBUG)"); 3270 } 3271 3272 ret_val = connect(net, h->ai_addr, h->ai_addrlen); 3273 3274 /* 3275 * If failed, try the next address of the target. 3276 */ 3277 if (ret_val < 0) { 3278 Close(&net); 3279 if (h->ai_next != NULL) { 3280 3281 int oerrno = errno; 3282 3283 (void) fprintf(stderr, 3284 "telnet: connect to address %s: ", abuf); 3285 errno = oerrno; 3286 perror((char *)0); 3287 3288 h = h->ai_next; 3289 continue; 3290 } 3291 perror("telnet: Unable to connect to remote host"); 3292 goto tn_exit; 3293 } 3294 connected++; 3295 } while (connected == 0); 3296 freeaddrinfo(host); 3297 host = NULL; 3298 #ifdef ICMD 3299 /* 3300 * Do initial protocol to connect to farther end... 3301 */ 3302 { 3303 char buf[1024]; 3304 (void) sprintf(buf, "%s %d\n", real_host, (int)dest_port); 3305 write(net, buf, strlen(buf)); 3306 } 3307 #endif 3308 if (cmdrc(hostp, hostname) != 0) 3309 goto tn_exit; 3310 FreeHostnameList(hostname_list); 3311 if (autologin && user == NULL) { 3312 struct passwd *pw; 3313 3314 user = getenv("LOGNAME"); 3315 if (user == NULL || 3316 ((pw = getpwnam(user)) != NULL) && 3317 pw->pw_uid != getuid()) { 3318 if (pw = getpwuid(getuid())) 3319 user = pw->pw_name; 3320 else 3321 user = NULL; 3322 } 3323 } 3324 3325 if (user) { 3326 if (env_define((unsigned char *)"USER", (unsigned char *)user)) 3327 env_export((unsigned char *)"USER"); 3328 else { 3329 /* Clean up and exit. */ 3330 Close(&net); 3331 (void) snprintf(buf, sizeof (buf), 3332 "Connection to %.*s closed.\n", 3333 MAXHOSTNAMELEN, hostname); 3334 ExitString(buf, EXIT_FAILURE); 3335 3336 /* NOTREACHED */ 3337 } 3338 } 3339 (void) call(3, status, "status", "notmuch"); 3340 if (setjmp(peerdied) == 0) 3341 telnet(user); 3342 3343 Close(&net); 3344 3345 (void) snprintf(buf, sizeof (buf), 3346 "Connection to %.*s closed by foreign host.\n", 3347 MAXHOSTNAMELEN, hostname); 3348 ExitString(buf, EXIT_FAILURE); 3349 3350 /*NOTREACHED*/ 3351 3352 tn_exit: 3353 FreeHostnameList(hostname_list); 3354 Close(&net); 3355 connected = 0; 3356 if (host != NULL) 3357 freeaddrinfo(host); 3358 return (0); 3359 } 3360 3361 #define HELPINDENT (sizeof ("connect")) 3362 3363 static char openhelp[] = "connect to a site"; 3364 static char closehelp[] = "close current connection"; 3365 static char logouthelp[] = 3366 "forcibly logout remote user and close the connection"; 3367 static char quithelp[] = "exit telnet"; 3368 static char statushelp[] = "print status information"; 3369 static char helphelp[] = "print help information"; 3370 static char sendhelp[] = 3371 "transmit special characters ('send ?' for more)"; 3372 static char sethelp[] = "set operating parameters ('set ?' for more)"; 3373 static char unsethelp[] = "unset operating parameters ('unset ?' for more)"; 3374 static char togglestring[] = 3375 "toggle operating parameters ('toggle ?' for more)"; 3376 static char slchelp[] = "change state of special charaters ('slc ?' for more)"; 3377 static char displayhelp[] = "display operating parameters"; 3378 static char authhelp[] = 3379 "turn on (off) authentication ('auth ?' for more)"; 3380 static char forwardhelp[] = 3381 "turn on (off) credential forwarding ('forward ?' for more)"; 3382 static char encrypthelp[] = 3383 "turn on (off) encryption ('encrypt ?' for more)"; 3384 static char zhelp[] = "suspend telnet"; 3385 static char shellhelp[] = "invoke a subshell"; 3386 static char envhelp[] = "change environment variables ('environ ?' for more)"; 3387 static char modestring[] = 3388 "try to enter line or character mode ('mode ?' for more)"; 3389 3390 static int help(); 3391 3392 static Command cmdtab[] = { 3393 { "close", closehelp, bye, 1 }, 3394 { "logout", logouthelp, logout, 1 }, 3395 { "display", displayhelp, display, 0 }, 3396 { "mode", modestring, modecmd, 0 }, 3397 { "open", openhelp, tn, 0 }, 3398 { "quit", quithelp, quit, 0 }, 3399 { "send", sendhelp, sendcmd, 0 }, 3400 { "set", sethelp, setcmd, 0 }, 3401 { "unset", unsethelp, unsetcmd, 0 }, 3402 { "status", statushelp, status, 0 }, 3403 { "toggle", togglestring, toggle, 0 }, 3404 { "slc", slchelp, slccmd, 0 }, 3405 { "auth", authhelp, auth_cmd, 0 }, 3406 { "encrypt", encrypthelp, encrypt_cmd, 0 }, 3407 { "forward", forwardhelp, forw_cmd, 0 }, 3408 { "z", zhelp, suspend, 0 }, 3409 { "!", shellhelp, shell, 0 }, 3410 { "environ", envhelp, env_cmd, 0 }, 3411 { "?", helphelp, help, 0 }, 3412 0 3413 }; 3414 3415 3416 static Command cmdtab2[] = { 3417 { "help", 0, help, 0 }, 3418 { "escape", 0, setescape, 0 }, 3419 { "crmod", 0, togcrmod, 0 }, 3420 0 3421 }; 3422 3423 3424 /* 3425 * Call routine with argc, argv set from args. 3426 * Uses /usr/include/stdarg.h 3427 */ 3428 #define MAXVARGS 100 3429 /*VARARGS1*/ 3430 static void 3431 call(int n_ptrs, ...) 3432 { 3433 va_list ap; 3434 typedef int (*intrtn_t)(); 3435 intrtn_t routine; 3436 char *args[MAXVARGS+1]; /* leave 1 for trailing NULL */ 3437 int argno = 0; 3438 3439 if (n_ptrs > MAXVARGS) 3440 n_ptrs = MAXVARGS; 3441 va_start(ap, n_ptrs); 3442 3443 routine = (va_arg(ap, intrtn_t)); /* extract the routine's name */ 3444 n_ptrs--; 3445 3446 while (argno < n_ptrs) /* extract the routine's args */ 3447 args[argno++] = va_arg(ap, char *); 3448 args[argno] = NULL; /* NULL terminate for good luck */ 3449 va_end(ap); 3450 3451 (*routine)(argno, args); 3452 } 3453 3454 3455 static Command * 3456 getcmd(name) 3457 char *name; 3458 { 3459 Command *cm; 3460 3461 if (cm = (Command *) genget(name, (char **)cmdtab, sizeof (Command))) 3462 return (cm); 3463 return (Command *) genget(name, (char **)cmdtab2, sizeof (Command)); 3464 } 3465 3466 void 3467 command(top, tbuf, cnt) 3468 int top; 3469 char *tbuf; 3470 int cnt; 3471 { 3472 Command *c; 3473 3474 setcommandmode(); 3475 if (!top) { 3476 (void) putchar('\n'); 3477 } else { 3478 (void) signal(SIGINT, SIG_DFL); 3479 (void) signal(SIGQUIT, SIG_DFL); 3480 } 3481 for (;;) { 3482 if (rlogin == _POSIX_VDISABLE) 3483 (void) printf("%s> ", prompt); 3484 if (tbuf) { 3485 char *cp; 3486 if (AllocStringBuffer(&line, &linesize, cnt) == NULL) 3487 goto command_exit; 3488 cp = line; 3489 while (cnt > 0 && (*cp++ = *tbuf++) != '\n') 3490 cnt--; 3491 tbuf = 0; 3492 if (cp == line || *--cp != '\n' || cp == line) 3493 goto getline; 3494 *cp = '\0'; 3495 if (rlogin == _POSIX_VDISABLE) 3496 (void) printf("%s\n", line); 3497 } else { 3498 getline: 3499 if (rlogin != _POSIX_VDISABLE) 3500 (void) printf("%s> ", prompt); 3501 if (GetString(&line, &linesize, stdin) == NULL) { 3502 if (!feof(stdin)) 3503 perror("telnet"); 3504 (void) quit(); 3505 /*NOTREACHED*/ 3506 break; 3507 } 3508 } 3509 if (line[0] == 0) 3510 break; 3511 makeargv(); 3512 if (margv[0] == 0) { 3513 break; 3514 } 3515 c = getcmd(margv[0]); 3516 if (Ambiguous(c)) { 3517 (void) printf("?Ambiguous command\n"); 3518 continue; 3519 } 3520 if (c == 0) { 3521 (void) printf("?Invalid command\n"); 3522 continue; 3523 } 3524 if (c->needconnect && !connected) { 3525 (void) printf("?Need to be connected first.\n"); 3526 continue; 3527 } 3528 if ((*c->handler)(margc, margv)) { 3529 break; 3530 } 3531 } 3532 command_exit: 3533 if (!top) { 3534 if (!connected) { 3535 longjmp(toplevel, 1); 3536 /*NOTREACHED*/ 3537 } 3538 setconnmode(0); 3539 } 3540 } 3541 3542 /* 3543 * Help command. 3544 */ 3545 static int 3546 help(argc, argv) 3547 int argc; 3548 char *argv[]; 3549 { 3550 register Command *c; 3551 3552 if (argc == 1) { 3553 (void) printf( 3554 "Commands may be abbreviated. Commands are:\n\n"); 3555 for (c = cmdtab; c->name; c++) 3556 if (c->help) { 3557 (void) printf("%-*s\t%s\n", HELPINDENT, 3558 c->name, c->help); 3559 } 3560 (void) printf("<return>\tleave command mode\n"); 3561 return (0); 3562 } 3563 while (--argc > 0) { 3564 register char *arg; 3565 arg = *++argv; 3566 c = getcmd(arg); 3567 if (Ambiguous(c)) 3568 (void) printf("?Ambiguous help command %s\n", arg); 3569 else if (c == (Command *)0) 3570 (void) printf("?Invalid help command %s\n", arg); 3571 else if (c->help) { 3572 (void) printf("%s\n", c->help); 3573 } else { 3574 (void) printf("No additional help on %s\n", arg); 3575 } 3576 } 3577 return (0); 3578 } 3579 3580 static char *rcname = NULL; 3581 #define TELNETRC_NAME "telnetrc" 3582 #define TELNETRC_COMP "/." TELNETRC_NAME 3583 3584 static int 3585 cmdrc(char *m1, char *m2) 3586 { 3587 Command *c; 3588 FILE *rcfile = NULL; 3589 int gotmachine = 0; 3590 int l1 = strlen(m1); 3591 int l2 = strlen(m2); 3592 char m1save[MAXHOSTNAMELEN]; 3593 int ret = 0; 3594 char def[] = "DEFAULT"; 3595 3596 if (skiprc) 3597 goto cmdrc_exit; 3598 3599 doing_rc = 1; 3600 3601 (void) strlcpy(m1save, m1, sizeof (m1save)); 3602 m1 = m1save; 3603 3604 if (rcname == NULL) { 3605 char *homedir; 3606 unsigned rcbuflen; 3607 3608 if ((homedir = getenv("HOME")) == NULL) 3609 homedir = ""; 3610 3611 rcbuflen = strlen(homedir) + strlen(TELNETRC_COMP) + 1; 3612 if ((rcname = malloc(rcbuflen)) == NULL) { 3613 perror("telnet: can't process " TELNETRC_NAME); 3614 ret = 1; 3615 goto cmdrc_exit; 3616 } 3617 (void) strcpy(rcname, homedir); 3618 (void) strcat(rcname, TELNETRC_COMP); 3619 } 3620 3621 if ((rcfile = fopen(rcname, "r")) == NULL) 3622 goto cmdrc_exit; 3623 3624 for (;;) { 3625 if (GetString(&line, &linesize, rcfile) == NULL) { 3626 if (!feof(rcfile)) { 3627 perror("telnet: error reading " TELNETRC_NAME); 3628 ret = 1; 3629 goto cmdrc_exit; 3630 } 3631 break; 3632 } 3633 if (line[0] == 0) 3634 continue; 3635 if (line[0] == '#') 3636 continue; 3637 if (gotmachine) { 3638 if (!isspace(line[0])) 3639 gotmachine = 0; 3640 } 3641 if (gotmachine == 0) { 3642 if (isspace(line[0])) 3643 continue; 3644 if (strncasecmp(line, m1, l1) == 0) 3645 (void) strcpy(line, &line[l1]); 3646 else if (strncasecmp(line, m2, l2) == 0) 3647 (void) strcpy(line, &line[l2]); 3648 else if (strncasecmp(line, def, sizeof (def) - 1) == 0) 3649 (void) strcpy(line, &line[sizeof (def) - 1]); 3650 else 3651 continue; 3652 if (line[0] != ' ' && line[0] != '\t' && 3653 line[0] != '\n') 3654 continue; 3655 gotmachine = 1; 3656 } 3657 makeargv(); 3658 if (margv[0] == 0) 3659 continue; 3660 c = getcmd(margv[0]); 3661 if (Ambiguous(c)) { 3662 (void) printf("?Ambiguous command: %s\n", margv[0]); 3663 continue; 3664 } 3665 if (c == 0) { 3666 (void) printf("?Invalid command: %s\n", margv[0]); 3667 continue; 3668 } 3669 /* 3670 * This should never happen... 3671 */ 3672 if (c->needconnect && !connected) { 3673 (void) printf("?Need to be connected first for %s.\n", 3674 margv[0]); 3675 continue; 3676 } 3677 (*c->handler)(margc, margv); 3678 } 3679 cmdrc_exit: 3680 if (rcfile != NULL) 3681 (void) fclose(rcfile); 3682 doing_rc = 0; 3683 3684 return (ret); 3685 } 3686