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