2 * Copyright (c) 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
34 * Use is subject to license terms.
37 #include <sys/param.h>
39 #include <sys/socket.h>
40 #include <sys/sysmacros.h>
41 #include <netinet/in.h>
50 #include <arpa/telnet.h>
51 #include <arpa/inet.h>
61 extern char *telnet_krb5_realm
;
62 extern void krb5_profile_get_options(char *, char *,
63 profile_options_boolean
*);
66 #include <profile/prof_int.h>
68 profile_options_boolean config_file_options
[] = {
69 { "forwardable", &forwardable_flag
, 0},
70 { "forward", &forward_flag
, 0},
71 { "encrypt", &encrypt_flag
, 0 },
72 { "autologin", &autologin
, 0 },
76 #include <netinet/ip.h>
79 * Number of maximum IPv4 gateways user can specify. This number is limited by
80 * the maximum size of the IPv4 options in the IPv4 header.
84 * Number of maximum IPv6 gateways user can specify. This number is limited by
85 * the maximum header extension length of the IPv6 routing header.
87 #define MAX_GATEWAY6 127
88 #define MAXMAX_GATEWAY MAX(MAX_GATEWAY, MAX_GATEWAY6)
91 * Depending on the address resolutions of the target and gateways,
92 * we determine which addresses of the target we'll try connecting to.
94 #define ALL_ADDRS 0 /* try all addrs of target */
95 #define ONLY_V4 1 /* try only IPv4 addrs of target */
96 #define ONLY_V6 2 /* try only IPv6 addrs of target */
103 static char _hostname
[MAXHOSTNAMELEN
];
105 static int send_tncmd(void (*func
)(), char *, char *);
106 static void call(int n_ptrs
, ...);
107 static int cmdrc(char *, char *);
110 char *name
; /* command name */
111 char *help
; /* help string (NULL for no help) */
112 int (*handler
)(); /* routine which executes command */
113 int needconnect
; /* Do we need to be connected to execute? */
117 * storage for IPv6 and/or IPv4 addresses of gateways
120 struct in6_addr gw_addr6
;
121 struct in_addr gw_addr
;
125 * IPv4 source routing option.
126 * In order to avoid padding for the alignment of IPv4 addresses, ipsr_addrs
127 * is defined as a 2-D array of uint8_t, instead of 1-D array of struct in_addr.
128 * If it were defined as "struct in_addr ipsr_addrs[1]", "ipsr_ptr" would be
129 * followed by one byte of padding to avoid misaligned struct in_addr.
131 struct ip_sourceroute
{
135 /* up to 9 IPv4 addresses */
136 uint8_t ipsr_addrs
[1][sizeof (struct in_addr
)];
139 static char *line
= NULL
;
140 static unsigned linesize
= 0;
142 static char **margv
= NULL
;
143 static unsigned margvlen
= 0;
144 static int doing_rc
= 0; /* .telnetrc file is being read and processed */
165 FreeHostnameList(char *list
[])
168 for (i
= 0; i
<= MAXMAX_GATEWAY
&& list
[i
] != NULL
; i
++)
172 #define MARGV_CHUNK_SIZE 8
178 if (margc
== margvlen
) {
181 margvlen
+= MARGV_CHUNK_SIZE
;
183 if ((newmargv
= realloc(margv
, margvlen
* sizeof (char *)))
185 ExitString("telnet: no space for arguments",
200 boolean_t shellcmd
= B_FALSE
;
204 if (*cp
== '!') { /* Special case shell escape */
205 set_argv("!"); /* No room in string to get this */
209 while ((c
= *cp
) != '\0') {
210 register int inquote
= 0;
217 * For the shell escape, put the rest of the line, less
218 * leading space, into a single argument, breaking out from
219 * the loop to prevent the rest of the line being split up
220 * into smaller arguments.
224 for (cp2
= cp
; c
!= '\0'; c
= *++cp
) {
232 if ((c
= *++cp
) == '\0')
234 } else if (c
== '"') {
237 } else if (c
== '\'') {
240 } else if (isspace(c
))
254 * Make a character string into a number.
256 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
270 c
= b
| 0x40; /* DEL */
283 * Construct a control character sequence
284 * for a special character.
292 * The only way I could get the Sun 3.5 compiler
294 * if ((unsigned int)c >= 0x80)
295 * was to assign "c" to an unsigned int variable...
298 register unsigned int uic
= (unsigned int)c
;
302 if (c
== (cc_t
)_POSIX_VDISABLE
) {
307 buf
[1] = ((c
>>6)&07) + '0';
308 buf
[2] = ((c
>>3)&07) + '0';
309 buf
[3] = (c
&07) + '0';
311 } else if (uic
>= 0x20) {
323 * Same as control() except that its only used for escape handling, which uses
324 * _POSIX_VDISABLE differently and is aided by the use of the state variable
333 * The only way I could get the Sun 3.5 compiler
335 * if ((unsigned int)c >= 0x80)
336 * was to assign "c" to an unsigned int variable...
339 register unsigned int uic
= (unsigned int)c
;
341 if (escape_valid
== B_FALSE
)
347 buf
[1] = ((c
>>6)&07) + '0';
348 buf
[2] = ((c
>>3)&07) + '0';
349 buf
[3] = (c
&07) + '0';
351 } else if (uic
>= 0x20) {
363 * The following are data structures and routines for
364 * the "send" command.
369 char *name
; /* How user refers to it (case independent) */
370 char *help
; /* Help information (0 ==> no help) */
371 int needconnect
; /* Need to be connected */
372 int narg
; /* Number of arguments */
373 int (*handler
)(); /* Routine to perform (for special ops) */
374 int nbyte
; /* Number of bytes to send this command */
375 int what
; /* Character to be sent (<0 ==> special) */
379 static int send_esc(void);
380 static int send_help(void);
381 static int send_docmd(char *);
382 static int send_dontcmd(char *);
383 static int send_willcmd(char *);
384 static int send_wontcmd(char *);
386 static struct sendlist Sendlist
[] = {
387 { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO
},
388 { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT
},
389 { "b", 0, 1, 0, 0, 2, BREAK
},
390 { "br", 0, 1, 0, 0, 2, BREAK
},
391 { "break", 0, 1, 0, 0, 2, BREAK
},
392 { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK
},
393 { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC
},
394 { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL
},
395 { "escape", "Send current escape character", 1, 0, send_esc
, 1, 0 },
396 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA
},
397 { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP
},
398 { "intp", 0, 1, 0, 0, 2, IP
},
399 { "interrupt", 0, 1, 0, 0, 2, IP
},
400 { "intr", 0, 1, 0, 0, 2, IP
},
401 { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP
},
402 { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR
},
403 { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT
},
404 { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP
},
405 { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF
},
406 { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch
, 2, 0 },
407 { "getstatus", "Send request for STATUS", 1, 0, get_status
, 6, 0 },
408 { "?", "Display send options", 0, 0, send_help
, 0, 0 },
409 { "help", 0, 0, 0, send_help
, 0, 0 },
410 { "do", 0, 0, 1, send_docmd
, 3, 0 },
411 { "dont", 0, 0, 1, send_dontcmd
, 3, 0 },
412 { "will", 0, 0, 1, send_willcmd
, 3, 0 },
413 { "wont", 0, 0, 1, send_wontcmd
, 3, 0 },
417 #define GETSEND(name) ((struct sendlist *)genget(name, (char **)Sendlist, \
418 sizeof (struct sendlist)))
425 int count
; /* how many bytes we are going to need to send */
427 struct sendlist
*s
; /* pointer to current command */
433 "need at least one argument for 'send' command\n");
434 (void) printf("'send ?' for help\n");
438 * First, validate all the send arguments.
439 * In addition, we see how much space we are going to need, and
440 * whether or not we will be doing a "SYNCH" operation (which
441 * flushes the network queue).
444 for (i
= 1; i
< argc
; i
++) {
445 s
= GETSEND(argv
[i
]);
447 (void) printf("Unknown send argument '%s'\n'send ?' "
448 "for help.\n", argv
[i
]);
450 } else if (Ambiguous(s
)) {
451 (void) printf("Ambiguous send argument '%s'\n'send ?' "
452 "for help.\n", argv
[i
]);
455 if (i
+ s
->narg
>= argc
) {
456 (void) fprintf(stderr
,
457 "Need %d argument%s to 'send %s' "
458 "command. 'send %s ?' for help.\n",
459 s
->narg
, s
->narg
== 1 ? "" : "s", s
->name
, s
->name
);
463 if (s
->handler
== send_help
) {
469 needconnect
+= s
->needconnect
;
471 if (!connected
&& needconnect
) {
472 (void) printf("?Need to be connected first.\n");
473 (void) printf("'send ?' for help\n");
476 /* Now, do we have enough room? */
477 if (NETROOM() < count
) {
478 (void) printf("There is not enough room in the buffer "
481 "to process your request. Nothing will be done.\n");
482 (void) printf("('send synch' will throw away most "
483 "data in the network\n");
484 (void) printf("buffer, if this might help.)\n");
487 /* OK, they are all OK, now go through again and actually send */
489 for (i
= 1; i
< argc
; i
++) {
490 if ((s
= GETSEND(argv
[i
])) == 0) {
491 (void) fprintf(stderr
,
492 "Telnet 'send' error - argument disappeared!\n");
498 success
+= (*s
->handler
)((s
->narg
> 0) ? argv
[i
+1] : 0,
499 (s
->narg
> 1) ? argv
[i
+2] : 0);
502 NET2ADD(IAC
, s
->what
);
503 printoption("SENT", IAC
, s
->what
);
506 return (count
== success
);
520 return (send_tncmd(send_do
, "do", name
));
527 return (send_tncmd(send_dont
, "dont", name
));
534 return (send_tncmd(send_will
, "will", name
));
541 return (send_tncmd(send_wont
, "wont", name
));
545 send_tncmd(func
, cmd
, name
)
550 extern char *telopts
[];
551 register int val
= 0;
553 if (isprefix(name
, "help") || isprefix(name
, "?")) {
554 register int col
, len
;
556 (void) printf("Usage: send %s <value|option>\n", cmd
);
557 (void) printf("\"value\" must be from 0 to 255\n");
558 (void) printf("Valid options are:\n\t");
561 for (cpp
= telopts
; *cpp
; cpp
++) {
562 len
= strlen(*cpp
) + 3;
563 if (col
+ len
> 65) {
564 (void) printf("\n\t");
567 (void) printf(" \"%s\"", *cpp
);
573 cpp
= (char **)genget(name
, telopts
, sizeof (char *));
574 if (Ambiguous(cpp
)) {
575 (void) fprintf(stderr
,
576 "'%s': ambiguous argument ('send %s ?' for help).\n",
583 register char *cp
= name
;
585 while (*cp
>= '0' && *cp
<= '9') {
591 (void) fprintf(stderr
,
592 "'%s': unknown argument ('send %s ?' for help).\n",
595 } else if (val
< 0 || val
> 255) {
596 (void) fprintf(stderr
,
597 "'%s': bad value ('send %s ?' for help).\n",
603 (void) printf("?Need to be connected first.\n");
613 struct sendlist
*s
; /* pointer to current command */
614 for (s
= Sendlist
; s
->name
; s
++) {
616 (void) printf("%-15s %s\n", s
->name
, s
->help
);
622 * The following are the routines and data structures referred
623 * to by the arguments to the "toggle" command.
637 (SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, debug
)) < 0) {
638 perror("setsockopt (SO_DEBUG)");
649 "Will send carriage returns as telnet <CR><LF>.\n");
652 "Will send carriage returns as telnet <CR><NUL>.\n");
663 donebinarytoggle
= 1;
668 if (my_want_state_is_will(TELOPT_BINARY
) &&
669 my_want_state_is_do(TELOPT_BINARY
)) {
671 } else if (my_want_state_is_wont(TELOPT_BINARY
) &&
672 my_want_state_is_dont(TELOPT_BINARY
)) {
675 val
= binmode
? 0 : 1;
679 if (my_want_state_is_will(TELOPT_BINARY
) &&
680 my_want_state_is_do(TELOPT_BINARY
)) {
681 (void) printf("Already operating in binary mode "
682 "with remote host.\n");
685 "Negotiating binary mode with remote host.\n");
689 if (my_want_state_is_wont(TELOPT_BINARY
) &&
690 my_want_state_is_dont(TELOPT_BINARY
)) {
691 (void) printf("Already in network ascii mode "
692 "with remote host.\n");
694 (void) printf("Negotiating network ascii mode "
695 "with remote host.\n");
706 donebinarytoggle
= 1;
709 val
= my_want_state_is_do(TELOPT_BINARY
) ? 0 : 1;
712 if (my_want_state_is_do(TELOPT_BINARY
)) {
713 (void) printf("Already receiving in binary mode.\n");
715 (void) printf("Negotiating binary mode on input.\n");
719 if (my_want_state_is_dont(TELOPT_BINARY
)) {
721 "Already receiving in network ascii mode.\n");
724 "Negotiating network ascii mode on input.\n");
735 donebinarytoggle
= 1;
738 val
= my_want_state_is_will(TELOPT_BINARY
) ? 0 : 1;
741 if (my_want_state_is_will(TELOPT_BINARY
)) {
742 (void) printf("Already transmitting in binary mode.\n");
744 (void) printf("Negotiating binary mode on output.\n");
748 if (my_want_state_is_wont(TELOPT_BINARY
)) {
750 "Already transmitting in network ascii mode.\n");
753 "Negotiating network ascii mode on output.\n");
761 static int togglehelp(void);
762 extern int auth_togdebug(int);
765 char *name
; /* name of toggle */
766 char *help
; /* help message */
767 int (*handler
)(); /* routine to do actual setting */
769 char *actionexplanation
;
772 static struct togglelist Togglelist
[] = {
774 "flushing of output when sending interrupt characters",
777 "flush output when sending interrupt characters" },
779 "automatic sending of interrupt characters in urgent mode",
782 "send interrupt characters in urgent mode" },
784 "automatic sending of login and/or authentication info",
787 "send login name and/or authentication information" },
789 "authentication debugging",
792 "print authentication debugging information" },
794 "automatic encryption of data stream",
797 "automatically encrypt output" },
799 "automatic decryption of data stream",
802 "automatically decrypt input" },
804 "verbose encryption output",
807 "print verbose encryption output" },
809 "encryption debugging",
812 "print encryption debugging information" },
814 "don't read ~/.telnetrc file",
817 "skip reading of ~/.telnetrc file" },
819 "sending and receiving of binary data",
824 "receiving of binary data",
829 "sending of binary data",
834 "sending carriage returns as telnet <CR><LF>",
839 "mapping of received carriage returns",
842 "map carriage return on output" },
844 "local recognition of certain control characters",
847 "recognize certain control characters" },
848 { " ", "", 0 }, /* empty line */
853 "turn on socket level debugging" },
855 "printing of hexadecimal network data (debugging)",
858 "print hexadecimal representation of network traffic" },
860 "output of \"netdata\" to user readable format (debugging)",
863 "print user readable output for \"netdata\"" },
865 "viewing of options processing (debugging)",
868 "show option processing" },
870 "(debugging) toggle printing of hexadecimal terminal data",
873 "print hexadecimal representation of terminal traffic" },
886 struct togglelist
*c
;
888 for (c
= Togglelist
; c
->name
; c
++) {
892 "%-15s toggle %s\n", c
->name
, c
->help
);
898 (void) printf("%-15s %s\n", "?", "display help information");
906 struct togglelist
*c
;
908 for (c
= Togglelist
; c
->name
; c
++) {
911 (void) printf("%-15s %s %s\n", c
->name
,
912 set
? "enable" : "disable", c
->help
);
919 #define GETTOGGLE(name) (struct togglelist *) \
920 genget(name, (char **)Togglelist, sizeof (struct togglelist))
929 struct togglelist
*c
;
932 (void) fprintf(stderr
,
933 "Need an argument to 'toggle' command. "
934 "'toggle ?' for help.\n");
943 (void) fprintf(stderr
, "'%s': ambiguous argument "
944 "('toggle ?' for help).\n", name
);
947 (void) fprintf(stderr
, "'%s': unknown argument "
948 "('toggle ?' for help).\n", name
);
952 *c
->variable
= !*c
->variable
; /* invert it */
953 if (c
->actionexplanation
) {
954 (void) printf("%s %s.\n",
955 *c
->variable
? "Will" : "Won't",
956 c
->actionexplanation
);
960 retval
&= (*c
->handler
)(-1);
968 * The following perform the "set" command.
972 struct termio new_tc
= { 0 };
976 char *name
; /* name */
977 char *help
; /* help information */
979 cc_t
*charp
; /* where it is located at */
982 static struct setlist Setlist
[] = {
983 #ifdef KLUDGELINEMODE
984 { "echo", "character to toggle local echoing on/off", 0, &echoc
},
986 { "escape", "character to escape back to telnet command mode", 0,
988 { "rlogin", "rlogin escape character", 0, &rlogin
},
989 { "tracefile", "file to write trace information to", SetNetTrace
,
990 (cc_t
*)NetTraceFile
},
992 { " ", "The following need 'localchars' to be toggled true", 0, 0 },
993 { "flushoutput", "character to cause an Abort Output", 0,
995 { "interrupt", "character to cause an Interrupt Process", 0,
997 { "quit", "character to cause an Abort process", 0, termQuitCharp
},
998 { "eof", "character to cause an EOF ", 0, termEofCharp
},
1000 { " ", "The following are for local editing in linemode", 0, 0 },
1001 { "erase", "character to use to erase a character", 0, termEraseCharp
},
1002 { "kill", "character to use to erase a line", 0, termKillCharp
},
1003 { "lnext", "character to use for literal next", 0,
1004 termLiteralNextCharp
},
1005 { "susp", "character to cause a Suspend Process", 0, termSuspCharp
},
1006 { "reprint", "character to use for line reprint", 0, termRprntCharp
},
1007 { "worderase", "character to use to erase a word", 0, termWerasCharp
},
1008 { "start", "character to use for XON", 0, termStartCharp
},
1009 { "stop", "character to use for XOFF", 0, termStopCharp
},
1010 { "forw1", "alternate end of line character", 0, termForw1Charp
},
1011 { "forw2", "alternate end of line character", 0, termForw2Charp
},
1012 { "ayt", "alternate AYT character", 0, termAytCharp
},
1016 static struct setlist
*
1020 return ((struct setlist
*)
1021 genget(name
, (char **)Setlist
, sizeof (struct setlist
)));
1028 if (rlogin
!= _POSIX_VDISABLE
) {
1029 rlogin
= (s
&& *s
) ? special(s
) : _POSIX_VDISABLE
;
1030 (void) printf("Telnet rlogin escape character is '%s'.\n",
1033 escape
= (s
&& *s
) ? special(s
) : _POSIX_VDISABLE
;
1034 (void) printf("Telnet escape character is '%s'.\n",
1035 esc_control(escape
));
1046 struct togglelist
*c
;
1048 if (argc
< 2 || argc
> 3) {
1050 "Format is 'set Name Value'\n'set ?' for help.\n");
1054 (isprefix(argv
[1], "?") || isprefix(argv
[1], "help"))) {
1055 for (ct
= Setlist
; ct
->name
; ct
++)
1056 (void) printf("%-15s %s\n", ct
->name
, ct
->help
);
1057 (void) printf("\n");
1059 (void) printf("%-15s %s\n", "?", "display help information");
1063 ct
= getset(argv
[1]);
1065 c
= GETTOGGLE(argv
[1]);
1067 (void) fprintf(stderr
, "'%s': unknown argument "
1068 "('set ?' for help).\n", argv
[1]);
1070 } else if (Ambiguous(c
)) {
1071 (void) fprintf(stderr
, "'%s': ambiguous argument "
1072 "('set ?' for help).\n", argv
[1]);
1076 if ((argc
== 2) || (strcmp("on", argv
[2]) == 0))
1078 else if (strcmp("off", argv
[2]) == 0)
1082 "Format is 'set togglename [on|off]'\n"
1083 "'set ?' for help.\n");
1086 if (c
->actionexplanation
) {
1087 (void) printf("%s %s.\n",
1088 *c
->variable
? "Will" : "Won't",
1089 c
->actionexplanation
);
1094 } else if (argc
!= 3) {
1096 "Format is 'set Name Value'\n'set ?' for help.\n");
1098 } else if (Ambiguous(ct
)) {
1099 (void) fprintf(stderr
,
1100 "'%s': ambiguous argument ('set ?' for help).\n", argv
[1]);
1102 } else if (ct
->handler
) {
1103 (*ct
->handler
)(argv
[2]);
1105 "%s set to \"%s\".\n", ct
->name
, (char *)ct
->charp
);
1107 if (strcmp("off", argv
[2])) {
1108 value
= special(argv
[2]);
1110 value
= _POSIX_VDISABLE
;
1112 *(ct
->charp
) = (cc_t
)value
;
1113 (void) printf("%s character is '%s'.\n", ct
->name
,
1114 control(*(ct
->charp
)));
1121 unsetcmd(argc
, argv
)
1126 struct togglelist
*c
;
1127 register char *name
;
1130 (void) fprintf(stderr
, "Need an argument to 'unset' command. "
1131 "'unset ?' for help.\n");
1134 if (isprefix(argv
[1], "?") || isprefix(argv
[1], "help")) {
1135 for (ct
= Setlist
; ct
->name
; ct
++)
1136 (void) printf("%-15s %s\n", ct
->name
, ct
->help
);
1137 (void) printf("\n");
1139 (void) printf("%-15s %s\n", "?", "display help information");
1149 c
= GETTOGGLE(name
);
1151 (void) fprintf(stderr
, "'%s': unknown argument "
1152 "('unset ?' for help).\n", name
);
1154 } else if (Ambiguous(c
)) {
1155 (void) fprintf(stderr
,
1156 "'%s': ambiguous argument "
1157 "('unset ?' for help).\n", name
);
1162 if (c
->actionexplanation
) {
1163 (void) printf("%s %s.\n",
1164 *c
->variable
? "Will" : "Won't",
1165 c
->actionexplanation
);
1170 } else if (Ambiguous(ct
)) {
1171 (void) fprintf(stderr
, "'%s': ambiguous argument "
1172 "('unset ?' for help).\n", name
);
1174 } else if (ct
->handler
) {
1176 (void) printf("%s reset to \"%s\".\n", ct
->name
,
1179 *(ct
->charp
) = _POSIX_VDISABLE
;
1180 (void) printf("%s character is '%s'.\n", ct
->name
,
1181 control(*(ct
->charp
)));
1188 * The following are the data structures and routines for the
1191 extern int reqd_linemode
;
1193 #ifdef KLUDGELINEMODE
1194 extern int kludgelinemode
;
1200 send_wont(TELOPT_LINEMODE
, 1);
1201 send_dont(TELOPT_SGA
, 1);
1202 send_dont(TELOPT_ECHO
, 1);
1204 * If processing the .telnetrc file, keep track of linemode and/or
1205 * kludgelinemode requests which are processed before initial option
1206 * negotiations occur.
1217 #ifdef KLUDGELINEMODE
1219 send_dont(TELOPT_SGA
, 1);
1221 send_will(TELOPT_LINEMODE
, 1);
1222 send_dont(TELOPT_ECHO
, 1);
1225 * If processing the .telnetrc file, keep track of linemode and/or
1226 * kludgelinemode requests which are processed before initial option
1227 * negotiations occur.
1237 #ifdef KLUDGELINEMODE
1239 send_do(TELOPT_SGA
, 1);
1242 send_wont(TELOPT_LINEMODE
, 1);
1243 send_do(TELOPT_ECHO
, 1);
1253 extern int linemode
;
1255 if (my_want_state_is_wont(TELOPT_LINEMODE
)) {
1256 (void) printf("?Need to have LINEMODE option enabled first.\n");
1257 (void) printf("'mode ?' for help.\n");
1262 c
= (linemode
| bit
);
1264 c
= (linemode
& ~bit
);
1272 return (dolmmode(bit
, 1));
1278 return (dolmmode(bit
, 0));
1282 char *name
; /* command name */
1283 char *help
; /* help string */
1284 int (*handler
)(); /* routine which executes command */
1285 int needconnect
; /* Do we need to be connected to execute? */
1289 static int modehelp();
1291 static struct modelist ModeList
[] = {
1292 { "character", "Disable LINEMODE option", docharmode
, 1 },
1293 #ifdef KLUDGELINEMODE
1294 { "", "(or disable obsolete line-by-line mode)", 0 },
1296 { "line", "Enable LINEMODE option", dolinemode
, 1 },
1297 #ifdef KLUDGELINEMODE
1298 { "", "(or enable obsolete line-by-line mode)", 0 },
1301 { "", "These require the LINEMODE option to be enabled", 0 },
1302 { "isig", "Enable signal trapping", setmode
, 1, MODE_TRAPSIG
},
1303 { "+isig", 0, setmode
, 1, MODE_TRAPSIG
},
1304 { "-isig", "Disable signal trapping", clearmode
, 1, MODE_TRAPSIG
},
1305 { "edit", "Enable character editing", setmode
, 1, MODE_EDIT
},
1306 { "+edit", 0, setmode
, 1, MODE_EDIT
},
1307 { "-edit", "Disable character editing", clearmode
, 1, MODE_EDIT
},
1308 { "softtabs", "Enable tab expansion", setmode
, 1, MODE_SOFT_TAB
},
1309 { "+softtabs", 0, setmode
, 1, MODE_SOFT_TAB
},
1310 { "-softtabs", "Disable tab expansion",
1311 clearmode
, 1, MODE_SOFT_TAB
},
1312 { "litecho", "Enable literal character echo",
1313 setmode
, 1, MODE_LIT_ECHO
},
1314 { "+litecho", 0, setmode
, 1, MODE_LIT_ECHO
},
1315 { "-litecho", "Disable literal character echo", clearmode
, 1,
1317 { "help", 0, modehelp
, 0 },
1318 #ifdef KLUDGELINEMODE
1319 { "kludgeline", 0, dokludgemode
, 1 },
1322 { "?", "Print help information", modehelp
, 0 },
1330 struct modelist
*mt
;
1332 (void) printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
1333 for (mt
= ModeList
; mt
->name
; mt
++) {
1336 (void) printf("%-15s %s\n", mt
->name
, mt
->help
);
1338 (void) printf("\n");
1344 #define GETMODECMD(name) (struct modelist *) \
1345 genget(name, (char **)ModeList, sizeof (struct modelist))
1352 struct modelist
*mt
;
1355 (void) printf("'mode' command requires an argument\n");
1356 (void) printf("'mode ?' for help.\n");
1357 } else if ((mt
= GETMODECMD(argv
[1])) == 0) {
1358 (void) fprintf(stderr
,
1359 "Unknown mode '%s' ('mode ?' for help).\n", argv
[1]);
1360 } else if (Ambiguous(mt
)) {
1361 (void) fprintf(stderr
,
1362 "Ambiguous mode '%s' ('mode ?' for help).\n", argv
[1]);
1363 } else if (mt
->needconnect
&& !connected
) {
1364 (void) printf("?Need to be connected first.\n");
1365 (void) printf("'mode ?' for help.\n");
1366 } else if (mt
->handler
) {
1367 return (*mt
->handler
)(mt
->arg1
);
1373 * The following data structures and routines implement the
1374 * "display" command.
1382 struct togglelist
*tl
;
1385 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1386 if (*tl->variable) { \
1387 (void) printf("will"); \
1389 (void) printf("won't"); \
1391 (void) printf(" %s.\n", tl->actionexplanation); \
1394 #define doset(sl) if (sl->name && *sl->name != ' ') { \
1395 if (sl->handler == 0) \
1396 (void) printf("%-15s [%s]\n", sl->name, \
1397 control(*sl->charp)); \
1399 (void) printf("%-15s \"%s\"\n", sl->name, \
1400 (char *)sl->charp); \
1404 for (tl
= Togglelist
; tl
->name
; tl
++) {
1407 (void) printf("\n");
1408 for (sl
= Setlist
; sl
->name
; sl
++) {
1414 for (i
= 1; i
< argc
; i
++) {
1415 sl
= getset(argv
[i
]);
1416 tl
= GETTOGGLE(argv
[i
]);
1417 if (Ambiguous(sl
) || Ambiguous(tl
)) {
1419 "?Ambiguous argument '%s'.\n", argv
[i
]);
1421 } else if (!sl
&& !tl
) {
1423 "?Unknown argument '%s'.\n", argv
[i
]);
1436 (void) EncryptStatus();
1443 * The following are the data structures, and many of the routines,
1444 * relating to command processing.
1448 * Set the escape character.
1451 setescape(argc
, argv
)
1461 (void) printf("new escape character: ");
1462 if (GetString(&buf
, NULL
, stdin
) == NULL
) {
1464 perror("can't set escape character");
1465 goto setescape_exit
;
1470 /* we place no limitations on what escape can be. */
1472 (void) printf("Escape character is '%s'.\n", esc_control(escape
));
1473 (void) fflush(stdout
);
1481 togcrmod(argc
, argv
)
1487 "%s map carriage return on output.\n", crmod
? "Will" : "Won't");
1488 (void) fflush(stdout
);
1500 unsigned short oldrows
, oldcols
, newrows
, newcols
;
1503 err
= (TerminalWindowSize(&oldrows
, &oldcols
) == 0) ? 1 : 0;
1504 (void) kill(0, SIGTSTP
);
1506 * If we didn't get the window size before the SUSPEND, but we
1507 * can get them now (?), then send the NAWS to make sure that
1508 * we are set up for the right window size.
1510 if (TerminalWindowSize(&newrows
, &newcols
) && connected
&&
1511 (err
|| ((oldrows
!= newrows
) || (oldcols
!= newcols
)))) {
1515 /* reget parameters in case they were changed */
1516 TerminalSaveState();
1527 unsigned short oldrows
, oldcols
, newrows
, newcols
;
1532 err
= (TerminalWindowSize(&oldrows
, &oldcols
) == 0) ? 1 : 0;
1535 perror("Fork failed\n");
1541 * Fire up the shell in the child.
1543 register char *shellp
, *shellname
;
1545 shellp
= getenv("SHELL");
1548 if ((shellname
= strrchr(shellp
, '/')) == 0)
1553 (void) execl(shellp
, shellname
, "-c", argv
[1], 0);
1555 (void) execl(shellp
, shellname
, 0);
1557 _exit(EXIT_FAILURE
);
1560 (void) wait((int *)0); /* Wait for the shell to complete */
1562 if (TerminalWindowSize(&newrows
, &newcols
) && connected
&&
1563 (err
|| ((oldrows
!= newrows
) || (oldcols
!= newcols
)))) {
1573 int argc
; /* Number of arguments */
1574 char *argv
[]; /* arguments */
1576 extern int resettermname
;
1579 (void) shutdown(net
, 2);
1580 (void) printf("Connection to %.*s closed.\n", MAXHOSTNAMELEN
,
1588 if ((argc
!= 2) || (strcmp(argv
[1], "fromquit") != 0)) {
1589 longjmp(toplevel
, 1);
1592 return (1); /* Keep lint, etc., happy */
1599 (void) call(3, bye
, "bye", "fromquit");
1611 send_do(TELOPT_LOGOUT
, 1);
1628 static void slc_help();
1630 static struct slclist SlcList
[] = {
1631 { "export", "Use local special character definitions",
1632 slc_mode_export
, 0 },
1633 { "import", "Use remote special character definitions",
1634 slc_mode_import
, 1 },
1635 { "check", "Verify remote special character definitions",
1636 slc_mode_import
, 0 },
1637 { "help", 0, slc_help
, 0 },
1638 { "?", "Print help information", slc_help
, 0 },
1647 for (c
= SlcList
; c
->name
; c
++) {
1650 (void) printf("%-15s %s\n", c
->name
, c
->help
);
1652 (void) printf("\n");
1657 static struct slclist
*
1661 return ((struct slclist
*)
1662 genget(name
, (char **)SlcList
, sizeof (struct slclist
)));
1673 (void) fprintf(stderr
,
1674 "Need an argument to 'slc' command. 'slc ?' for help.\n");
1677 c
= getslc(argv
[1]);
1679 (void) fprintf(stderr
,
1680 "'%s': unknown argument ('slc ?' for help).\n",
1685 (void) fprintf(stderr
,
1686 "'%s': ambiguous argument ('slc ?' for help).\n", argv
[1]);
1689 (*c
->handler
)(c
->arg
);
1695 * The ENVIRON command.
1705 static struct env_lst
*env_define(unsigned char *, unsigned char *);
1706 static void env_undefine(unsigned char *);
1707 static void env_export(unsigned char *);
1708 static void env_unexport(unsigned char *);
1709 static void env_send(unsigned char *);
1710 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1711 static void env_varval(unsigned char *);
1713 static void env_list(void);
1715 static void env_help(void);
1717 static struct envlist EnvList
[] = {
1718 { "define", "Define an environment variable",
1719 (void (*)())env_define
, 2 },
1720 { "undefine", "Undefine an environment variable",
1722 { "export", "Mark an environment variable for automatic export",
1724 { "unexport", "Don't mark an environment variable for automatic export",
1726 { "send", "Send an environment variable", env_send
, 1 },
1727 { "list", "List the current environment variables",
1729 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1730 { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
1733 { "help", 0, env_help
, 0 },
1734 { "?", "Print help information", env_help
, 0 },
1743 for (c
= EnvList
; c
->name
; c
++) {
1746 (void) printf("%-15s %s\n", c
->name
, c
->help
);
1748 (void) printf("\n");
1753 static struct envlist
*
1757 return ((struct envlist
*)
1758 genget(name
, (char **)EnvList
, sizeof (struct envlist
)));
1769 (void) fprintf(stderr
,
1770 "Need an argument to 'environ' command. "
1771 "'environ ?' for help.\n");
1774 c
= getenvcmd(argv
[1]);
1776 (void) fprintf(stderr
, "'%s': unknown argument "
1777 "('environ ?' for help).\n", argv
[1]);
1781 (void) fprintf(stderr
, "'%s': ambiguous argument "
1782 "('environ ?' for help).\n", argv
[1]);
1785 if (c
->narg
+ 2 != argc
) {
1786 (void) fprintf(stderr
,
1787 "Need %s%d argument%s to 'environ %s' command. "
1788 "'environ ?' for help.\n",
1789 c
->narg
+ 2 < argc
? "only " : "",
1790 c
->narg
, c
->narg
== 1 ? "" : "s", c
->name
);
1793 (*c
->handler
)(argv
[2], argv
[3]);
1798 struct env_lst
*next
; /* pointer to next structure */
1799 struct env_lst
*prev
; /* pointer to previous structure */
1800 unsigned char *var
; /* pointer to variable name */
1801 unsigned char *value
; /* pointer to variable value */
1802 int export
; /* 1 -> export with default list of variables */
1803 int welldefined
; /* A well defined variable */
1806 static struct env_lst envlisthead
;
1808 static struct env_lst
*
1812 register struct env_lst
*ep
;
1814 for (ep
= envlisthead
.next
; ep
; ep
= ep
->next
) {
1815 if (strcmp((char *)ep
->var
, (char *)var
) == 0)
1824 extern char **environ
;
1828 for (epp
= environ
; *epp
; epp
++) {
1829 if (cp
= strchr(*epp
, '=')) {
1832 ep
= env_define((unsigned char *)*epp
,
1833 (unsigned char *)cp
+1);
1841 * Special case for DISPLAY variable. If it is ":0.0" or
1842 * "unix:0.0", we have to get rid of "unix" and insert our
1845 if (((ep
= env_find((uchar_t
*)"DISPLAY")) != NULL
) &&
1846 ((*ep
->value
== ':') ||
1847 (strncmp((char *)ep
->value
, "unix:", 5) == 0))) {
1848 char hbuf
[MAXHOSTNAMELEN
];
1849 char *cp2
= strchr((char *)ep
->value
, ':');
1851 if (gethostname(hbuf
, MAXHOSTNAMELEN
) == -1) {
1852 perror("telnet: cannot get hostname");
1855 hbuf
[MAXHOSTNAMELEN
-1] = '\0';
1856 cp
= malloc(strlen(hbuf
) + strlen(cp2
) + 1);
1858 perror("telnet: cannot define DISPLAY variable");
1861 (void) sprintf((char *)cp
, "%s%s", hbuf
, cp2
);
1863 ep
->value
= (unsigned char *)cp
;
1866 * If LOGNAME is defined, but USER is not, then add
1867 * USER with the value from LOGNAME. We do this because the "accepted
1868 * practice" is to always pass USER on the wire, but SVR4 uses
1869 * LOGNAME by default.
1871 if ((ep
= env_find((uchar_t
*)"LOGNAME")) != NULL
&&
1872 env_find((uchar_t
*)"USER") == NULL
) {
1873 if (env_define((unsigned char *)"USER", ep
->value
) != NULL
)
1874 env_unexport((unsigned char *)"USER");
1876 env_export((unsigned char *)"DISPLAY");
1877 env_export((unsigned char *)"PRINTER");
1882 static struct env_lst
*
1883 env_define(var
, value
)
1884 unsigned char *var
, *value
;
1886 unsigned char *tmp_value
;
1887 unsigned char *tmp_var
;
1891 * Allocate copies of arguments first, to make cleanup easier
1892 * in the case of allocation errors.
1894 tmp_var
= (unsigned char *)strdup((char *)var
);
1895 if (tmp_var
== NULL
) {
1896 perror("telnet: can't copy environment variable name");
1900 tmp_value
= (unsigned char *)strdup((char *)value
);
1901 if (tmp_value
== NULL
) {
1903 perror("telnet: can't copy environment variable value");
1907 if (ep
= env_find(var
)) {
1911 ep
= malloc(sizeof (struct env_lst
));
1913 perror("telnet: can't define environment variable");
1919 ep
->next
= envlisthead
.next
;
1920 envlisthead
.next
= ep
;
1921 ep
->prev
= &envlisthead
;
1923 ep
->next
->prev
= ep
;
1925 ep
->welldefined
= opt_welldefined((char *)var
);
1928 ep
->value
= tmp_value
;
1937 register struct env_lst
*ep
;
1939 if (ep
= env_find(var
)) {
1940 ep
->prev
->next
= ep
->next
;
1942 ep
->next
->prev
= ep
->prev
;
1953 register struct env_lst
*ep
;
1955 if (ep
= env_find(var
))
1963 register struct env_lst
*ep
;
1965 if (ep
= env_find(var
))
1973 register struct env_lst
*ep
;
1975 if (my_state_is_wont(TELOPT_NEW_ENVIRON
)
1977 /* old style */ && my_state_is_wont(TELOPT_OLD_ENVIRON
)
1980 (void) fprintf(stderr
,
1981 "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1987 (void) fprintf(stderr
,
1988 "Cannot send '%s': variable not defined\n", var
);
1991 env_opt_start_info();
1992 env_opt_add(ep
->var
);
1999 register struct env_lst
*ep
;
2001 for (ep
= envlisthead
.next
; ep
; ep
= ep
->next
) {
2002 (void) printf("%c %-20s %s\n", ep
->export
? '*' : ' ',
2003 ep
->var
, ep
->value
);
2008 env_default(init
, welldefined
)
2011 static struct env_lst
*nep
= NULL
;
2014 /* return value is not used */
2019 while ((nep
= nep
->next
) != NULL
) {
2020 if (nep
->export
&& (nep
->welldefined
== welldefined
))
2031 register struct env_lst
*ep
;
2033 if (ep
= env_find(var
))
2038 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
2041 unsigned char *what
;
2043 extern int old_env_var
, old_env_value
, env_auto
;
2044 int len
= strlen((char *)what
);
2049 if (strncasecmp((char *)what
, "status", len
) == 0) {
2051 (void) printf("%s%s", "VAR and VALUE are/will be ",
2052 "determined automatically\n");
2053 if (old_env_var
== OLD_ENV_VAR
)
2055 "VAR and VALUE set to correct definitions\n");
2058 "VAR and VALUE definitions are reversed\n");
2059 } else if (strncasecmp((char *)what
, "auto", len
) == 0) {
2061 old_env_var
= OLD_ENV_VALUE
;
2062 old_env_value
= OLD_ENV_VAR
;
2063 } else if (strncasecmp((char *)what
, "right", len
) == 0) {
2065 old_env_var
= OLD_ENV_VAR
;
2066 old_env_value
= OLD_ENV_VALUE
;
2067 } else if (strncasecmp((char *)what
, "wrong", len
) == 0) {
2069 old_env_var
= OLD_ENV_VALUE
;
2070 old_env_value
= OLD_ENV_VAR
;
2074 "Unknown \"varval\" command. (\"auto\", \"right\", "
2075 "\"wrong\", \"status\")\n");
2078 #endif /* OLD_ENVIRON && ENV_HACK */
2081 * The AUTHENTICATE command.
2091 extern int auth_enable(char *);
2092 extern int auth_disable(char *);
2093 extern int auth_status(void);
2095 static int auth_help(void);
2097 static struct authlist AuthList
[] = {
2099 "Display current status of authentication information",
2102 "Disable an authentication type ('auth disable ?' for more)",
2105 "Enable an authentication type ('auth enable ?' for more)",
2107 { "help", 0, auth_help
, 0 },
2108 { "?", "Print help information", auth_help
, 0 },
2117 for (c
= AuthList
; c
->name
; c
++) {
2120 (void) printf("%-15s %s\n", c
->name
, c
->help
);
2122 (void) printf("\n");
2130 auth_cmd(argc
, argv
)
2137 (void) fprintf(stderr
, "Need an argument to 'auth' "
2138 "command. 'auth ?' for help.\n");
2142 c
= (struct authlist
*)
2143 genget(argv
[1], (char **)AuthList
, sizeof (struct authlist
));
2145 (void) fprintf(stderr
,
2146 "'%s': unknown argument ('auth ?' for help).\n",
2151 (void) fprintf(stderr
,
2152 "'%s': ambiguous argument ('auth ?' for help).\n", argv
[1]);
2155 if (c
->narg
+ 2 != argc
) {
2156 (void) fprintf(stderr
,
2157 "Need %s%d argument%s to 'auth %s' command."
2158 " 'auth ?' for help.\n",
2159 c
->narg
+ 2 < argc
? "only " : "",
2160 c
->narg
, c
->narg
== 1 ? "" : "s", c
->name
);
2163 return ((*c
->handler
)(argv
[2], argv
[3]));
2167 * The FORWARD command.
2170 extern int forward_flags
;
2179 static int forw_status(void);
2180 static int forw_set(int);
2181 static int forw_help(void);
2183 static struct forwlist ForwList
[] = {
2185 "Display current status of credential forwarding",
2188 "Disable credential forwarding",
2191 "Enable credential forwarding",
2192 forw_set
, OPTS_FORWARD_CREDS
},
2194 "Enable credential forwarding of "
2195 "forwardable credentials",
2196 forw_set
, OPTS_FORWARD_CREDS
| OPTS_FORWARDABLE_CREDS
},
2201 "Print help information",
2209 if (forward_flags
& OPTS_FORWARD_CREDS
) {
2210 if (forward_flags
& OPTS_FORWARDABLE_CREDS
)
2211 (void) printf(gettext(
2212 "Credential forwarding of "
2213 "forwardable credentials enabled\n"));
2215 (void) printf(gettext(
2216 "Credential forwarding enabled\n"));
2218 (void) printf(gettext("Credential forwarding disabled\n"));
2223 forw_set(int f_flags
)
2225 forward_flags
= f_flags
;
2234 for (c
= ForwList
; c
->name
; c
++) {
2237 (void) printf("%-15s %s\r\n", c
->name
, c
->help
);
2239 (void) printf("\n");
2246 forw_cmd(int argc
, char *argv
[])
2251 (void) fprintf(stderr
, gettext(
2252 "Need an argument to 'forward' "
2253 "command. 'forward ?' for help.\n"));
2256 c
= (struct forwlist
*)genget(argv
[1], (char **)ForwList
,
2257 sizeof (struct forwlist
));
2259 (void) fprintf(stderr
, gettext(
2260 "'%s': unknown argument ('forward ?' for help).\n"),
2265 (void) fprintf(stderr
, gettext(
2266 "'%s': ambiguous argument ('forward ?' for help).\n"),
2271 (void) fprintf(stderr
, gettext(
2272 "No arguments needed to 'forward %s' command. "
2273 "'forward ?' for help.\n"), c
->name
);
2276 return ((*c
->handler
) (c
->f_flags
));
2280 * The ENCRYPT command.
2283 struct encryptlist
{
2292 static int EncryptHelp(void);
2294 static struct encryptlist EncryptList
[] = {
2295 { "enable", "Enable encryption. ('encrypt enable ?' for more)",
2296 EncryptEnable
, 1, 1, 2 },
2297 { "disable", "Disable encryption. ('encrypt disable ?' for more)",
2298 EncryptDisable
, 0, 1, 2 },
2299 { "type", "Set encryption type. ('encrypt type ?' for more)",
2300 EncryptType
, 0, 1, 2 },
2301 { "start", "Start encryption. ('encrypt start ?' for more)",
2302 EncryptStart
, 1, 0, 1 },
2303 { "stop", "Stop encryption. ('encrypt stop ?' for more)",
2304 EncryptStop
, 1, 0, 1 },
2305 { "input", "Start encrypting the input stream",
2306 EncryptStartInput
, 1, 0, 0 },
2307 { "-input", "Stop encrypting the input stream",
2308 EncryptStopInput
, 1, 0, 0 },
2309 { "output", "Start encrypting the output stream",
2310 EncryptStartOutput
, 1, 0, 0 },
2311 { "-output", "Stop encrypting the output stream",
2312 EncryptStopOutput
, 1, 0, 0 },
2314 { "status", "Display current status of encryption information",
2315 EncryptStatus
, 0, 0, 0 },
2317 EncryptHelp
, 0, 0, 0 },
2318 { "?", "Print help information", EncryptHelp
, 0, 0, 0 },
2325 struct encryptlist
*c
;
2327 for (c
= EncryptList
; c
->name
; c
++) {
2330 (void) printf("%-15s %s\n", c
->name
, c
->help
);
2332 (void) printf("\n");
2339 encrypt_cmd(int argc
, char *argv
[])
2341 struct encryptlist
*c
;
2344 (void) fprintf(stderr
, gettext(
2345 "Need an argument to 'encrypt' command. "
2346 "'encrypt ?' for help.\n"));
2350 c
= (struct encryptlist
*)
2351 genget(argv
[1], (char **)EncryptList
, sizeof (struct encryptlist
));
2353 (void) fprintf(stderr
, gettext(
2354 "'%s': unknown argument ('encrypt ?' for help).\n"),
2359 (void) fprintf(stderr
, gettext(
2360 "'%s': ambiguous argument ('encrypt ?' for help).\n"),
2365 if (argc
< c
->minarg
|| argc
> c
->maxarg
) {
2366 if (c
->minarg
== c
->maxarg
) {
2367 (void) fprintf(stderr
, gettext("Need %s%d %s "),
2369 gettext("only ") : "", c
->minarg
,
2371 gettext("argument") : gettext("arguments"));
2373 (void) fprintf(stderr
,
2374 gettext("Need %s%d-%d arguments "),
2376 gettext("only ") : "", c
->minarg
, c
->maxarg
);
2378 (void) fprintf(stderr
, gettext(
2379 "to 'encrypt %s' command. 'encrypt ?' for help.\n"),
2383 if (c
->needconnect
&& !connected
) {
2385 (isprefix(argv
[2], "help") || isprefix(argv
[2], "?")))) {
2387 gettext("?Need to be connected first.\n"));
2391 return ((*c
->handler
)(argc
> 0 ? argv
[2] : 0,
2392 argc
> 1 ? argv
[3] : 0, argc
> 2 ? argv
[4] : 0));
2396 * Print status about the connection.
2399 status(int argc
, char *argv
[])
2402 (void) printf("Connected to %s.\n", hostname
);
2403 if ((argc
< 2) || strcmp(argv
[1], "notmuch")) {
2404 int mode
= getconnmode();
2406 if (my_want_state_is_will(TELOPT_LINEMODE
)) {
2408 "Operating with LINEMODE option\n");
2410 "%s line editing\n", (mode
&MODE_EDIT
) ?
2412 (void) printf("%s catching of signals\n",
2413 (mode
&MODE_TRAPSIG
) ? "Local" : "No");
2415 #ifdef KLUDGELINEMODE
2416 } else if (kludgelinemode
&&
2417 my_want_state_is_dont(TELOPT_SGA
)) {
2419 "Operating in obsolete linemode\n");
2423 "Operating in single character mode\n");
2426 "Catching signals locally\n");
2428 (void) printf("%s character echo\n", (mode
&MODE_ECHO
) ?
2429 "Local" : "Remote");
2430 if (my_want_state_is_will(TELOPT_LFLOW
))
2431 (void) printf("%s flow control\n",
2432 (mode
&MODE_FLOW
) ? "Local" : "No");
2437 (void) printf("No connection.\n");
2439 if (rlogin
!= _POSIX_VDISABLE
)
2440 (void) printf("Escape character is '%s'.\n", control(rlogin
));
2443 "Escape character is '%s'.\n", esc_control(escape
));
2444 (void) fflush(stdout
);
2449 * Parse the user input (cmd_line_input) which should:
2450 * - start with the target host, or with "@" or "!@" followed by at least one
2452 * - each host (can be literal address or hostname) can be separated by ",",
2454 * Note that the last host is the target, all the others (if any ) are the
2457 * Returns: -1 if a library call fails, too many gateways, or parse
2460 * On successful return, hostname_list points to a list of hosts (last one being
2461 * the target, others gateways), src_rtng_type points to the type of source
2462 * routing (strict vs. loose)
2465 parse_input(char *cmd_line_input
, char **hostname_list
, uchar_t
*src_rtng_type
)
2467 char hname
[MAXHOSTNAMELEN
+ 1];
2473 cp
= cmd_line_input
;
2476 * Defining ICMD generates the Itelnet binary, the special version of
2477 * telnet which is used with firewall proxy.
2478 * If ICMD is defined, parse_input will treat the whole cmd_line_input
2479 * as the target host and set the num_gw to 0. Therefore, none of the
2480 * source routing related code paths will be executed.
2484 *src_rtng_type
= IPOPT_LSRR
;
2486 } else if (*cp
== '!') {
2487 *src_rtng_type
= IPOPT_SSRR
;
2489 /* "!" must be followed by '@' */
2490 if (*(cp
+ 1) != '@')
2495 /* no gateways, just the target */
2496 hostname_list
[0] = strdup(cp
);
2497 if (hostname_list
[0] == NULL
) {
2498 perror("telnet: copying host name");
2505 while (*cp
!= '\0') {
2507 * Identify each gateway separated by ",", "@" or ",@" and
2511 while (*cp
!= '@' && *cp
!= ',' && *cp
!= '\0') {
2513 if (i
> MAXHOSTNAMELEN
)
2519 * Two consecutive delimiters which result in a 0 length hname
2525 hostname_list
[gw_count
] = strdup(hname
);
2526 if (hostname_list
[gw_count
] == NULL
) {
2527 perror("telnet: copying hostname from list");
2531 if (++gw_count
> MAXMAX_GATEWAY
) {
2532 (void) fprintf(stderr
, "telnet: too many gateways\n");
2536 /* Jump over the next delimiter. */
2538 /* ...gw1,@gw2... accepted */
2539 if (*cp
== ',' && *(cp
+ 1) == '@')
2546 /* discount the target */
2549 /* Any input starting with '!@' or '@' must have at least one gateway */
2556 (void) printf("Bad source route option: %s\n", cmd_line_input
);
2562 * Resolves the target and gateway addresses, determines what type of addresses
2563 * (ALL_ADDRS, ONLY_V6, ONLY_V4) telnet will be trying to connect.
2565 * Returns: pointer to resolved target if name resolutions succeed
2566 * NULL if name resolutions fail or
2567 * a library function call fails
2569 * The last host in the hostname_list is the target. After resolving the target,
2570 * determines for what type of addresses it should try to resolve gateways. It
2571 * resolves gateway addresses and picks one address for each desired address
2572 * type and stores in the array pointed by gw_addrsp. Also, this 'type of
2573 * addresses' is pointed by addr_type argument on successful return.
2575 static struct addrinfo
*
2576 resolve_hosts(char **hostname_list
, int num_gw
, struct gateway
**gw_addrsp
,
2577 int *addr_type
, const char *portp
)
2579 struct gateway
*gw_addrs
= NULL
;
2581 /* whether we already picked an IPv4 address for the current gateway */
2582 boolean_t got_v4_addr
;
2583 boolean_t got_v6_addr
;
2584 /* whether we need to get an IPv4 address for the current gateway */
2585 boolean_t need_v4_addr
= B_FALSE
;
2586 boolean_t need_v6_addr
= B_FALSE
;
2587 int res_failed_at4
; /* save which gateway failed to resolve */
2589 boolean_t is_v4mapped
;
2590 struct in6_addr
*v6addrp
;
2591 struct in_addr
*v4addrp
;
2595 struct addrinfo
*res
, *host
, *gateway
, *addr
;
2596 struct addrinfo hints
;
2598 *addr_type
= ALL_ADDRS
;
2600 memset(&hints
, 0, sizeof (hints
));
2601 hints
.ai_flags
= AI_CANONNAME
; /* used for config files, diags */
2602 hints
.ai_socktype
= SOCK_STREAM
;
2603 rc
= getaddrinfo(hostname_list
[num_gw
],
2604 (portp
!= NULL
) ? portp
: "telnet", &hints
, &res
);
2606 if (hostname_list
[num_gw
] != NULL
&&
2607 *hostname_list
[num_gw
] != '\0')
2608 (void) fprintf(stderr
, "%s: ", hostname_list
[num_gw
]);
2609 (void) fprintf(stderr
, "%s\n", gai_strerror(rc
));
2614 * Let's see what type of addresses we got for the target. This
2615 * determines what type of addresses we'd like to resolve gateways
2618 for (host
= res
; host
!= NULL
; host
= host
->ai_next
) {
2619 struct sockaddr_in6
*s6
;
2621 s6
= (struct sockaddr_in6
*)host
->ai_addr
;
2623 if (host
->ai_addr
->sa_family
== AF_INET
||
2624 IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
))
2625 need_v4_addr
= B_TRUE
;
2627 need_v6_addr
= B_TRUE
;
2630 * Let's stop after seeing we need both IPv6 and IPv4.
2632 if (need_v4_addr
&& need_v6_addr
)
2638 * In the prepare_optbuf(), we'll store the IPv4 address of the
2639 * target in the last slot of gw_addrs array. Therefore we need
2640 * space for num_gw+1 hosts.
2642 gw_addrs
= calloc(num_gw
+ 1, sizeof (struct gateway
));
2643 if (gw_addrs
== NULL
) {
2644 perror("telnet: calloc");
2651 * Now we'll go through all the gateways and try to resolve them to
2652 * the desired address types.
2656 /* -1 means 'no address resolution failure yet' */
2657 res_failed_at4
= -1;
2658 res_failed_at6
= -1;
2659 for (i
= 0; i
< num_gw
; i
++) {
2660 rc
= getaddrinfo(hostname_list
[i
], NULL
, NULL
, &gateway
);
2662 if (hostname_list
[i
] != NULL
&&
2663 *hostname_list
[i
] != '\0')
2664 (void) fprintf(stderr
, "%s: ",
2666 (void) fprintf(stderr
, "bad address\n");
2671 * Initially we have no address of any type for this gateway.
2673 got_v6_addr
= B_FALSE
;
2674 got_v4_addr
= B_FALSE
;
2677 * Let's go through all the addresses of this gateway.
2678 * Use the first address which matches the needed family.
2680 for (addr
= gateway
; addr
!= NULL
; addr
= addr
->ai_next
) {
2682 v6addrp
= &((struct sockaddr_in6
*)addr
->ai_addr
)->
2684 v4addrp
= &((struct sockaddr_in
*)addr
->ai_addr
)->
2687 if (addr
->ai_family
== AF_INET6
)
2688 is_v4mapped
= IN6_IS_ADDR_V4MAPPED(v6addrp
);
2690 is_v4mapped
= B_FALSE
;
2693 * If we need to determine an IPv4 address and haven't
2694 * found one yet and this is a IPv4-mapped IPv6 address,
2697 if (need_v4_addr
&& !got_v4_addr
) {
2699 IN6_V4MAPPED_TO_INADDR(v6addrp
,
2701 got_v4_addr
= B_TRUE
;
2702 } else if (addr
->ai_family
= AF_INET
) {
2703 gw
->gw_addr
= *v4addrp
;
2704 got_v4_addr
= B_TRUE
;
2708 if (need_v6_addr
&& !got_v6_addr
&&
2709 addr
->ai_family
== AF_INET6
) {
2710 gw
->gw_addr6
= *v6addrp
;
2711 got_v6_addr
= B_TRUE
;
2715 * Let's stop if we got all what we looked for.
2717 if ((!need_v4_addr
|| got_v4_addr
) &&
2718 (!need_v6_addr
|| got_v6_addr
))
2723 * We needed an IPv4 address for this gateway but couldn't
2726 if (need_v4_addr
&& !got_v4_addr
) {
2729 * Since we couldn't resolve a gateway to IPv4 address
2730 * we can't use IPv4 at all. Therefore we no longer
2731 * need IPv4 addresses for any of the gateways.
2733 need_v4_addr
= B_FALSE
;
2736 if (need_v6_addr
&& !got_v6_addr
) {
2738 need_v6_addr
= B_FALSE
;
2742 * If some gateways don't resolve to any of the desired
2743 * address types, we fail.
2745 if (!need_v4_addr
&& !need_v6_addr
) {
2746 if (res_failed_at6
!= -1) {
2747 (void) fprintf(stderr
,
2748 "%s: Host doesn't have any IPv6 address\n",
2749 hostname_list
[res_failed_at6
]);
2751 if (res_failed_at4
!= -1) {
2752 (void) fprintf(stderr
,
2753 "%s: Host doesn't have any IPv4 address\n",
2754 hostname_list
[res_failed_at4
]);
2763 *gw_addrsp
= gw_addrs
;
2766 * When we get here, need_v4_addr and need_v6_addr have their final
2767 * values based on the name resolution of the target and gateways.
2769 if (need_v4_addr
&& need_v6_addr
)
2770 *addr_type
= ALL_ADDRS
;
2771 else if (need_v4_addr
&& !need_v6_addr
)
2772 *addr_type
= ONLY_V4
;
2773 else if (!need_v4_addr
&& need_v6_addr
)
2774 *addr_type
= ONLY_V6
;
2781 * Initializes the buffer pointed by opt_bufpp for a IPv4 option of type
2782 * src_rtng_type using the gateway addresses stored in gw_addrs. If no buffer
2783 * is passed, it allocates one. If a buffer is passed, checks if it's big
2785 * On return opt_buf_len points to the buffer length which we need later for the
2786 * setsockopt() call, and opt_bufpp points to the newly allocated or already
2787 * passed buffer. Returns B_FALSE if a library function call fails or passed
2788 * buffer is not big enough, B_TRUE otherwise.
2791 prepare_optbuf(struct gateway
*gw_addrs
, int num_gw
, char **opt_bufpp
,
2792 size_t *opt_buf_len
, struct in_addr
*target
, uchar_t src_rtng_type
)
2794 struct ip_sourceroute
*sr_opt
;
2795 size_t needed_buflen
;
2799 * We have (num_gw + 1) IP addresses in the buffer because the number
2800 * of gateway addresses we put in the option buffer includes the target
2802 * At the time of setsockopt() call, passed option length needs to be
2803 * multiple of 4 bytes. Therefore we need one IPOPT_NOP before (or
2804 * after) IPOPT_LSRR.
2805 * 1 = preceding 1 byte of IPOPT_NOP
2806 * 3 = 1 (code) + 1 (len) + 1 (ptr)
2808 needed_buflen
= 1 + 3 + (num_gw
+ 1) * sizeof (struct in_addr
);
2810 if (*opt_bufpp
!= NULL
) {
2811 /* check if the passed buffer is big enough */
2812 if (*opt_buf_len
< needed_buflen
) {
2813 (void) fprintf(stderr
,
2814 "telnet: buffer too small for IPv4 source routing "
2819 *opt_bufpp
= malloc(needed_buflen
);
2820 if (*opt_bufpp
== NULL
) {
2821 perror("telnet: malloc");
2826 *opt_buf_len
= needed_buflen
;
2828 /* final hop is the target */
2829 gw_addrs
[num_gw
].gw_addr
= *target
;
2831 *opt_bufpp
[0] = IPOPT_NOP
;
2832 /* IPOPT_LSRR starts right after IPOPT_NOP */
2833 sr_opt
= (struct ip_sourceroute
*)(*opt_bufpp
+ 1);
2834 sr_opt
->ipsr_code
= src_rtng_type
;
2835 /* discount the 1 byte of IPOPT_NOP */
2836 sr_opt
->ipsr_len
= needed_buflen
- 1;
2837 sr_opt
->ipsr_ptr
= IPOPT_MINOFF
;
2839 /* copy the gateways into the optlist */
2840 for (i
= 0; i
< num_gw
+ 1; i
++) {
2841 (void) bcopy(&gw_addrs
[i
].gw_addr
, &sr_opt
->ipsr_addrs
[i
],
2842 sizeof (struct in_addr
));
2849 * Initializes the buffer pointed by opt_bufpp for a IPv6 routing header option
2850 * using the gateway addresses stored in gw_addrs. If no buffer is passed, it
2851 * allocates one. If a buffer is passed, checks if it's big enough.
2852 * On return opt_buf_len points to the buffer length which we need later for the
2853 * setsockopt() call, and opt_bufpp points to the newly allocated or already
2854 * passed buffer. Returns B_FALSE if a library function call fails or passed
2855 * buffer is not big enough, B_TRUE otherwise.
2858 prepare_optbuf6(struct gateway
*gw_addrs
, int num_gw
, char **opt_bufpp
,
2859 size_t *opt_buf_len
)
2862 size_t needed_buflen
;
2865 needed_buflen
= inet6_rth_space(IPV6_RTHDR_TYPE_0
, num_gw
);
2867 if (*opt_bufpp
!= NULL
) {
2868 /* check if the passed buffer is big enough */
2869 if (*opt_buf_len
< needed_buflen
) {
2870 (void) fprintf(stderr
,
2871 "telnet: buffer too small for IPv6 routing "
2876 *opt_bufpp
= malloc(needed_buflen
);
2877 if (*opt_bufpp
== NULL
) {
2878 perror("telnet: malloc");
2882 *opt_buf_len
= needed_buflen
;
2883 opt_bufp
= *opt_bufpp
;
2886 * Initialize the buffer to be used for IPv6 routing header type 0.
2888 if (inet6_rth_init(opt_bufp
, needed_buflen
, IPV6_RTHDR_TYPE_0
,
2890 perror("telnet: inet6_rth_init");
2895 * Add gateways one by one.
2897 for (i
= 0; i
< num_gw
; i
++) {
2898 if (inet6_rth_add(opt_bufp
, &gw_addrs
[i
].gw_addr6
) == -1) {
2899 perror("telnet: inet6_rth_add");
2904 /* successful operation */
2913 struct addrinfo
*host
= NULL
;
2915 struct sockaddr_in6 sin6
;
2916 struct sockaddr_in sin
;
2917 struct in6_addr addr6
;
2918 struct in_addr addr
;
2920 struct gateway
*gw_addrs
;
2921 char *hostname_list
[MAXMAX_GATEWAY
+ 1] = {NULL
};
2922 char *opt_buf6
= NULL
; /* used for IPv6 routing header */
2923 size_t opt_buf_len6
= 0;
2924 uchar_t src_rtng_type
; /* type of IPv4 source routing */
2925 struct servent
*sp
= 0;
2926 char *opt_buf
= NULL
; /* used for IPv4 source routing */
2927 size_t opt_buf_len
= 0;
2935 unsigned short dest_port
;
2938 * The two strings at the end of this function are 24 and 39
2939 * characters long (minus the %.*s in the format strings). Add
2940 * one for the null terminator making the longest print string 40.
2942 char buf
[MAXHOSTNAMELEN
+40];
2944 * In the case of ICMD defined, dest_port will contain the real port
2945 * we are trying to telnet to, and target_port will contain
2946 * "telnet-passthru" port.
2948 unsigned short target_port
;
2949 char abuf
[INET6_ADDRSTRLEN
];
2952 boolean_t is_v4mapped
;
2954 * Type of addresses we'll try to connect to (ALL_ADDRS, ONLY_V6,
2959 /* clear the socket address prior to use */
2960 (void) memset(&sin6
, '\0', sizeof (sin6
));
2961 sin6
.sin6_family
= AF_INET6
;
2963 (void) memset(&sin
, '\0', sizeof (sin
));
2964 sin
.sin_family
= AF_INET
;
2967 (void) printf("?Already connected to %s\n", hostname
);
2971 itelnet_host
= getenv("INTERNET_HOST");
2972 if (itelnet_host
== NULL
|| itelnet_host
[0] == '\0') {
2973 (void) printf("INTERNET_HOST environment variable undefined\n");
2978 (void) printf("(to) ");
2979 if (GetAndAppendString(&line
, &linesize
, "open ",
2993 if (isprefix(*argv
, "help") == 4 || isprefix(*argv
, "?") == 1)
2995 if (strcmp(*argv
, "-l") == 0) {
3003 if (strcmp(*argv
, "-a") == 0) {
3005 autologin
= autologin_set
= 1;
3017 * Do we treat this like a telnet port or raw?
3019 if (*portp
== '-') {
3028 "usage: %s [-l user] [-a] host-name [port]\n", cmd
);
3036 * For setup phase treat the relay host as the target host.
3039 hostp
= itelnet_host
;
3041 num_gw
= parse_input(hostp
, hostname_list
, &src_rtng_type
);
3046 /* Last host in the hostname_list is the target */
3047 hostp
= hostname_list
[num_gw
];
3049 host
= resolve_hosts(hostname_list
, num_gw
, &gw_addrs
, &addr_type
,
3056 * Check if number of gateways is less than max. available
3058 if ((addr_type
== ALL_ADDRS
|| addr_type
== ONLY_V6
) &&
3059 num_gw
> MAX_GATEWAY6
) {
3060 (void) fprintf(stderr
, "telnet: too many IPv6 gateways\n");
3064 if ((addr_type
== ALL_ADDRS
|| addr_type
== ONLY_V4
) &&
3065 num_gw
> MAX_GATEWAY
) {
3066 (void) fprintf(stderr
, "telnet: too many IPv4 gateways\n");
3071 * If we pass a literal IPv4 address to getaddrinfo(), in the
3072 * returned addrinfo structure, hostname is the IPv4-mapped IPv6
3073 * address string. We prefer to preserve the literal IPv4 address
3074 * string as the hostname. Also, if the hostname entered by the
3075 * user is IPv4-mapped IPv6 address, we'll downgrade it to IPv4
3078 if (inet_addr(hostp
) != (in_addr_t
)-1) {
3079 /* this is a literal IPv4 address */
3080 (void) strlcpy(_hostname
, hostp
, sizeof (_hostname
));
3081 } else if ((inet_pton(AF_INET6
, hostp
, &addr6
) > 0) &&
3082 IN6_IS_ADDR_V4MAPPED(&addr6
)) {
3083 /* this is a IPv4-mapped IPv6 address */
3084 IN6_V4MAPPED_TO_INADDR(&addr6
, &addr
);
3085 (void) inet_ntop(AF_INET
, &addr
, _hostname
, sizeof (_hostname
));
3087 (void) strlcpy(_hostname
, host
->ai_canonname
,
3088 sizeof (_hostname
));
3090 hostname
= _hostname
;
3092 if (portp
== NULL
) {
3096 if (host
->ai_family
== AF_INET
) {
3097 target_port
= ((struct sockaddr_in
*)(host
->ai_addr
))->sin_port
;
3099 target_port
= ((struct sockaddr_in6
*)(host
->ai_addr
))
3105 * Since we pass the port number as an ascii string to the proxy,
3106 * we need it in host format.
3108 dest_port
= ntohs(target_port
);
3109 sp
= getservbyname("telnet-passthru", "tcp");
3111 (void) fprintf(stderr
,
3112 "telnet: tcp/telnet-passthru: unknown service\n");
3115 target_port
= sp
->s_port
;
3120 * For IPv6 source routing, we need to initialize option buffer only
3123 if (num_gw
> 0 && (addr_type
== ALL_ADDRS
|| addr_type
== ONLY_V6
)) {
3124 if (!prepare_optbuf6(gw_addrs
, num_gw
, &opt_buf6
,
3131 * We procure the Kerberos config files options only
3132 * if the user has choosen Krb5 authentication.
3134 if (krb5auth_flag
> 0) {
3135 krb5_profile_get_options(hostname
, telnet_krb5_realm
,
3136 config_file_options
);
3140 extern boolean_t auth_enable_encrypt
;
3141 if (krb5_privacy_allowed()) {
3144 wantencryption
= B_TRUE
;
3146 auth_enable_encrypt
= B_TRUE
;
3148 (void) fprintf(stderr
, gettext(
3149 "%s:Encryption not supported.\n"), prompt
);
3154 if (forward_flag
&& forwardable_flag
) {
3155 (void) fprintf(stderr
, gettext(
3156 "Error in krb5 configuration file. "
3157 "Both forward and forwardable are set.\n"));
3160 if (forwardable_flag
) {
3161 forward_flags
|= OPTS_FORWARD_CREDS
| OPTS_FORWARDABLE_CREDS
;
3162 } else if (forward_flag
)
3163 forward_flags
|= OPTS_FORWARD_CREDS
;
3168 * Search for an address of desired type in the IP address list
3172 struct sockaddr_in6
*addr
;
3174 addr
= (struct sockaddr_in6
*)h
->ai_addr
;
3176 if (h
->ai_family
== AF_INET6
)
3178 IN6_IS_ADDR_V4MAPPED(&addr
->sin6_addr
);
3180 is_v4mapped
= B_FALSE
;
3182 if (addr_type
== ALL_ADDRS
||
3183 (addr_type
== ONLY_V6
&&
3184 h
->ai_family
== AF_INET6
) ||
3185 (addr_type
== ONLY_V4
&&
3186 (h
->ai_family
== AF_INET
|| is_v4mapped
)))
3189 /* skip undesired typed addresses */
3195 "telnet: Unable to connect to remote host");
3200 * We need to open a socket with a family matching the type of
3201 * address we are trying to connect to. This is because we
3202 * deal with IPv4 options and IPv6 extension headers.
3204 if (h
->ai_family
== AF_INET
) {
3205 addrp
= &((struct sockaddr_in
*)(h
->ai_addr
))->sin_addr
;
3206 ((struct sockaddr_in
*)(h
->ai_addr
))->sin_port
=
3209 addrp
= &((struct sockaddr_in6
*)(h
->ai_addr
))
3211 ((struct sockaddr_in6
*)(h
->ai_addr
))->sin6_port
=
3215 (void) printf("Trying %s...\n", inet_ntop(h
->ai_family
,
3216 addrp
, abuf
, sizeof (abuf
)));
3218 net
= socket(h
->ai_family
, SOCK_STREAM
, 0);
3221 perror("telnet: socket");
3226 if (h
->ai_family
== AF_INET
|| is_v4mapped
) {
3227 if (!prepare_optbuf(gw_addrs
, num_gw
, &opt_buf
,
3228 &opt_buf_len
, addrp
, src_rtng_type
)) {
3232 if (setsockopt(net
, IPPROTO_IP
, IP_OPTIONS
,
3233 opt_buf
, opt_buf_len
) < 0)
3234 perror("setsockopt (IP_OPTIONS)");
3236 if (setsockopt(net
, IPPROTO_IPV6
, IPV6_RTHDR
,
3237 opt_buf6
, opt_buf_len6
) < 0)
3238 perror("setsockopt (IPV6_RTHDR)");
3242 #if defined(USE_TOS)
3245 tos
= 020; /* Low Delay bit */
3247 (setsockopt(net
, IPPROTO_IP
, IP_TOS
,
3248 &tos
, sizeof (int)) < 0) &&
3249 (errno
!= ENOPROTOOPT
))
3250 perror("telnet: setsockopt (IP_TOS) (ignored)");
3252 #endif /* defined(USE_TOS) */
3254 if (debug
&& SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, 1) < 0) {
3255 perror("setsockopt (SO_DEBUG)");
3258 ret_val
= connect(net
, h
->ai_addr
, h
->ai_addrlen
);
3261 * If failed, try the next address of the target.
3265 if (h
->ai_next
!= NULL
) {
3269 (void) fprintf(stderr
,
3270 "telnet: connect to address %s: ", abuf
);
3277 perror("telnet: Unable to connect to remote host");
3281 } while (connected
== 0);
3286 * Do initial protocol to connect to farther end...
3290 (void) sprintf(buf
, "%s %d\n", real_host
, (int)dest_port
);
3291 write(net
, buf
, strlen(buf
));
3294 if (cmdrc(hostp
, hostname
) != 0)
3296 FreeHostnameList(hostname_list
);
3297 if (autologin
&& user
== NULL
) {
3300 user
= getenv("LOGNAME");
3302 ((pw
= getpwnam(user
)) != NULL
) &&
3303 pw
->pw_uid
!= getuid()) {
3304 if (pw
= getpwuid(getuid()))
3312 if (env_define((unsigned char *)"USER", (unsigned char *)user
))
3313 env_export((unsigned char *)"USER");
3315 /* Clean up and exit. */
3317 (void) snprintf(buf
, sizeof (buf
),
3318 "Connection to %.*s closed.\n",
3319 MAXHOSTNAMELEN
, hostname
);
3320 ExitString(buf
, EXIT_FAILURE
);
3325 (void) call(3, status
, "status", "notmuch");
3326 if (setjmp(peerdied
) == 0)
3331 (void) snprintf(buf
, sizeof (buf
),
3332 "Connection to %.*s closed by foreign host.\n",
3333 MAXHOSTNAMELEN
, hostname
);
3334 ExitString(buf
, EXIT_FAILURE
);
3339 FreeHostnameList(hostname_list
);
3347 #define HELPINDENT (sizeof ("connect"))
3349 static char openhelp
[] = "connect to a site";
3350 static char closehelp
[] = "close current connection";
3351 static char logouthelp
[] =
3352 "forcibly logout remote user and close the connection";
3353 static char quithelp
[] = "exit telnet";
3354 static char statushelp
[] = "print status information";
3355 static char helphelp
[] = "print help information";
3356 static char sendhelp
[] =
3357 "transmit special characters ('send ?' for more)";
3358 static char sethelp
[] = "set operating parameters ('set ?' for more)";
3359 static char unsethelp
[] = "unset operating parameters ('unset ?' for more)";
3360 static char togglestring
[] =
3361 "toggle operating parameters ('toggle ?' for more)";
3362 static char slchelp
[] = "change state of special charaters ('slc ?' for more)";
3363 static char displayhelp
[] = "display operating parameters";
3364 static char authhelp
[] =
3365 "turn on (off) authentication ('auth ?' for more)";
3366 static char forwardhelp
[] =
3367 "turn on (off) credential forwarding ('forward ?' for more)";
3368 static char encrypthelp
[] =
3369 "turn on (off) encryption ('encrypt ?' for more)";
3370 static char zhelp
[] = "suspend telnet";
3371 static char shellhelp
[] = "invoke a subshell";
3372 static char envhelp
[] = "change environment variables ('environ ?' for more)";
3373 static char modestring
[] =
3374 "try to enter line or character mode ('mode ?' for more)";
3378 static Command cmdtab
[] = {
3379 { "close", closehelp
, bye
, 1 },
3380 { "logout", logouthelp
, logout
, 1 },
3381 { "display", displayhelp
, display
, 0 },
3382 { "mode", modestring
, modecmd
, 0 },
3383 { "open", openhelp
, tn
, 0 },
3384 { "quit", quithelp
, quit
, 0 },
3385 { "send", sendhelp
, sendcmd
, 0 },
3386 { "set", sethelp
, setcmd
, 0 },
3387 { "unset", unsethelp
, unsetcmd
, 0 },
3388 { "status", statushelp
, status
, 0 },
3389 { "toggle", togglestring
, toggle
, 0 },
3390 { "slc", slchelp
, slccmd
, 0 },
3391 { "auth", authhelp
, auth_cmd
, 0 },
3392 { "encrypt", encrypthelp
, encrypt_cmd
, 0 },
3393 { "forward", forwardhelp
, forw_cmd
, 0 },
3394 { "z", zhelp
, suspend
, 0 },
3395 { "!", shellhelp
, shell
, 0 },
3396 { "environ", envhelp
, env_cmd
, 0 },
3397 { "?", helphelp
, help
, 0 },
3402 static Command cmdtab2
[] = {
3403 { "help", 0, help
, 0 },
3404 { "escape", 0, setescape
, 0 },
3405 { "crmod", 0, togcrmod
, 0 },
3411 * Call routine with argc, argv set from args.
3412 * Uses /usr/include/stdarg.h
3414 #define MAXVARGS 100
3417 call(int n_ptrs
, ...)
3420 typedef int (*intrtn_t
)();
3422 char *args
[MAXVARGS
+1]; /* leave 1 for trailing NULL */
3425 if (n_ptrs
> MAXVARGS
)
3427 va_start(ap
, n_ptrs
);
3429 routine
= (va_arg(ap
, intrtn_t
)); /* extract the routine's name */
3432 while (argno
< n_ptrs
) /* extract the routine's args */
3433 args
[argno
++] = va_arg(ap
, char *);
3434 args
[argno
] = NULL
; /* NULL terminate for good luck */
3437 (*routine
)(argno
, args
);
3447 if (cm
= (Command
*) genget(name
, (char **)cmdtab
, sizeof (Command
)))
3449 return (Command
*) genget(name
, (char **)cmdtab2
, sizeof (Command
));
3453 command(top
, tbuf
, cnt
)
3462 (void) putchar('\n');
3464 (void) signal(SIGINT
, SIG_DFL
);
3465 (void) signal(SIGQUIT
, SIG_DFL
);
3468 if (rlogin
== _POSIX_VDISABLE
)
3469 (void) printf("%s> ", prompt
);
3472 if (AllocStringBuffer(&line
, &linesize
, cnt
) == NULL
)
3475 while (cnt
> 0 && (*cp
++ = *tbuf
++) != '\n')
3478 if (cp
== line
|| *--cp
!= '\n' || cp
== line
)
3481 if (rlogin
== _POSIX_VDISABLE
)
3482 (void) printf("%s\n", line
);
3485 if (rlogin
!= _POSIX_VDISABLE
)
3486 (void) printf("%s> ", prompt
);
3487 if (GetString(&line
, &linesize
, stdin
) == NULL
) {
3498 if (margv
[0] == 0) {
3501 c
= getcmd(margv
[0]);
3503 (void) printf("?Ambiguous command\n");
3507 (void) printf("?Invalid command\n");
3510 if (c
->needconnect
&& !connected
) {
3511 (void) printf("?Need to be connected first.\n");
3514 if ((*c
->handler
)(margc
, margv
)) {
3521 longjmp(toplevel
, 1);
3536 register Command
*c
;
3540 "Commands may be abbreviated. Commands are:\n\n");
3541 for (c
= cmdtab
; c
->name
; c
++)
3543 (void) printf("%-*s\t%s\n", HELPINDENT
,
3546 (void) printf("<return>\tleave command mode\n");
3549 while (--argc
> 0) {
3554 (void) printf("?Ambiguous help command %s\n", arg
);
3555 else if (c
== (Command
*)0)
3556 (void) printf("?Invalid help command %s\n", arg
);
3558 (void) printf("%s\n", c
->help
);
3560 (void) printf("No additional help on %s\n", arg
);
3566 static char *rcname
= NULL
;
3567 #define TELNETRC_NAME "telnetrc"
3568 #define TELNETRC_COMP "/." TELNETRC_NAME
3571 cmdrc(char *m1
, char *m2
)
3574 FILE *rcfile
= NULL
;
3576 int l1
= strlen(m1
);
3577 int l2
= strlen(m2
);
3578 char m1save
[MAXHOSTNAMELEN
];
3580 char def
[] = "DEFAULT";
3587 (void) strlcpy(m1save
, m1
, sizeof (m1save
));
3590 if (rcname
== NULL
) {
3594 if ((homedir
= getenv("HOME")) == NULL
)
3597 rcbuflen
= strlen(homedir
) + strlen(TELNETRC_COMP
) + 1;
3598 if ((rcname
= malloc(rcbuflen
)) == NULL
) {
3599 perror("telnet: can't process " TELNETRC_NAME
);
3603 (void) strcpy(rcname
, homedir
);
3604 (void) strcat(rcname
, TELNETRC_COMP
);
3607 if ((rcfile
= fopen(rcname
, "r")) == NULL
)
3611 if (GetString(&line
, &linesize
, rcfile
) == NULL
) {
3612 if (!feof(rcfile
)) {
3613 perror("telnet: error reading " TELNETRC_NAME
);
3624 if (!isspace(line
[0]))
3627 if (gotmachine
== 0) {
3628 if (isspace(line
[0]))
3630 if (strncasecmp(line
, m1
, l1
) == 0)
3631 (void) strcpy(line
, &line
[l1
]);
3632 else if (strncasecmp(line
, m2
, l2
) == 0)
3633 (void) strcpy(line
, &line
[l2
]);
3634 else if (strncasecmp(line
, def
, sizeof (def
) - 1) == 0)
3635 (void) strcpy(line
, &line
[sizeof (def
) - 1]);
3638 if (line
[0] != ' ' && line
[0] != '\t' &&
3646 c
= getcmd(margv
[0]);
3648 (void) printf("?Ambiguous command: %s\n", margv
[0]);
3652 (void) printf("?Invalid command: %s\n", margv
[0]);
3656 * This should never happen...
3658 if (c
->needconnect
&& !connected
) {
3659 (void) printf("?Need to be connected first for %s.\n",
3663 (*c
->handler
)(margc
, margv
);
3667 (void) fclose(rcfile
);