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
))
250 set_argv((char *)NULL
);
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)
1825 char **environ
= NULL
;
1827 extern char **environ
;
1832 for (epp
= environ
; *epp
; epp
++) {
1833 if (cp
= strchr(*epp
, '=')) {
1836 ep
= env_define((unsigned char *)*epp
,
1837 (unsigned char *)cp
+1);
1845 * Special case for DISPLAY variable. If it is ":0.0" or
1846 * "unix:0.0", we have to get rid of "unix" and insert our
1849 if (((ep
= env_find((uchar_t
*)"DISPLAY")) != NULL
) &&
1850 ((*ep
->value
== ':') ||
1851 (strncmp((char *)ep
->value
, "unix:", 5) == 0))) {
1852 char hbuf
[MAXHOSTNAMELEN
];
1853 char *cp2
= strchr((char *)ep
->value
, ':');
1855 if (gethostname(hbuf
, MAXHOSTNAMELEN
) == -1) {
1856 perror("telnet: cannot get hostname");
1859 hbuf
[MAXHOSTNAMELEN
-1] = '\0';
1860 cp
= malloc(strlen(hbuf
) + strlen(cp2
) + 1);
1862 perror("telnet: cannot define DISPLAY variable");
1865 (void) sprintf((char *)cp
, "%s%s", hbuf
, cp2
);
1867 ep
->value
= (unsigned char *)cp
;
1870 * If LOGNAME is defined, but USER is not, then add
1871 * USER with the value from LOGNAME. We do this because the "accepted
1872 * practice" is to always pass USER on the wire, but SVR4 uses
1873 * LOGNAME by default.
1875 if ((ep
= env_find((uchar_t
*)"LOGNAME")) != NULL
&&
1876 env_find((uchar_t
*)"USER") == NULL
) {
1877 if (env_define((unsigned char *)"USER", ep
->value
) != NULL
)
1878 env_unexport((unsigned char *)"USER");
1880 env_export((unsigned char *)"DISPLAY");
1881 env_export((unsigned char *)"PRINTER");
1886 static struct env_lst
*
1887 env_define(var
, value
)
1888 unsigned char *var
, *value
;
1890 unsigned char *tmp_value
;
1891 unsigned char *tmp_var
;
1895 * Allocate copies of arguments first, to make cleanup easier
1896 * in the case of allocation errors.
1898 tmp_var
= (unsigned char *)strdup((char *)var
);
1899 if (tmp_var
== NULL
) {
1900 perror("telnet: can't copy environment variable name");
1904 tmp_value
= (unsigned char *)strdup((char *)value
);
1905 if (tmp_value
== NULL
) {
1907 perror("telnet: can't copy environment variable value");
1911 if (ep
= env_find(var
)) {
1917 ep
= malloc(sizeof (struct env_lst
));
1919 perror("telnet: can't define environment variable");
1925 ep
->next
= envlisthead
.next
;
1926 envlisthead
.next
= ep
;
1927 ep
->prev
= &envlisthead
;
1929 ep
->next
->prev
= ep
;
1931 ep
->welldefined
= opt_welldefined((char *)var
);
1934 ep
->value
= tmp_value
;
1943 register struct env_lst
*ep
;
1945 if (ep
= env_find(var
)) {
1946 ep
->prev
->next
= ep
->next
;
1948 ep
->next
->prev
= ep
->prev
;
1961 register struct env_lst
*ep
;
1963 if (ep
= env_find(var
))
1971 register struct env_lst
*ep
;
1973 if (ep
= env_find(var
))
1981 register struct env_lst
*ep
;
1983 if (my_state_is_wont(TELOPT_NEW_ENVIRON
)
1985 /* old style */ && my_state_is_wont(TELOPT_OLD_ENVIRON
)
1988 (void) fprintf(stderr
,
1989 "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1995 (void) fprintf(stderr
,
1996 "Cannot send '%s': variable not defined\n", var
);
1999 env_opt_start_info();
2000 env_opt_add(ep
->var
);
2007 register struct env_lst
*ep
;
2009 for (ep
= envlisthead
.next
; ep
; ep
= ep
->next
) {
2010 (void) printf("%c %-20s %s\n", ep
->export
? '*' : ' ',
2011 ep
->var
, ep
->value
);
2016 env_default(init
, welldefined
)
2019 static struct env_lst
*nep
= NULL
;
2022 /* return value is not used */
2027 while ((nep
= nep
->next
) != NULL
) {
2028 if (nep
->export
&& (nep
->welldefined
== welldefined
))
2039 register struct env_lst
*ep
;
2041 if (ep
= env_find(var
))
2046 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
2049 unsigned char *what
;
2051 extern int old_env_var
, old_env_value
, env_auto
;
2052 int len
= strlen((char *)what
);
2057 if (strncasecmp((char *)what
, "status", len
) == 0) {
2059 (void) printf("%s%s", "VAR and VALUE are/will be ",
2060 "determined automatically\n");
2061 if (old_env_var
== OLD_ENV_VAR
)
2063 "VAR and VALUE set to correct definitions\n");
2066 "VAR and VALUE definitions are reversed\n");
2067 } else if (strncasecmp((char *)what
, "auto", len
) == 0) {
2069 old_env_var
= OLD_ENV_VALUE
;
2070 old_env_value
= OLD_ENV_VAR
;
2071 } else if (strncasecmp((char *)what
, "right", len
) == 0) {
2073 old_env_var
= OLD_ENV_VAR
;
2074 old_env_value
= OLD_ENV_VALUE
;
2075 } else if (strncasecmp((char *)what
, "wrong", len
) == 0) {
2077 old_env_var
= OLD_ENV_VALUE
;
2078 old_env_value
= OLD_ENV_VAR
;
2082 "Unknown \"varval\" command. (\"auto\", \"right\", "
2083 "\"wrong\", \"status\")\n");
2086 #endif /* OLD_ENVIRON && ENV_HACK */
2089 * The AUTHENTICATE command.
2099 extern int auth_enable(char *);
2100 extern int auth_disable(char *);
2101 extern int auth_status(void);
2103 static int auth_help(void);
2105 static struct authlist AuthList
[] = {
2107 "Display current status of authentication information",
2110 "Disable an authentication type ('auth disable ?' for more)",
2113 "Enable an authentication type ('auth enable ?' for more)",
2115 { "help", 0, auth_help
, 0 },
2116 { "?", "Print help information", auth_help
, 0 },
2125 for (c
= AuthList
; c
->name
; c
++) {
2128 (void) printf("%-15s %s\n", c
->name
, c
->help
);
2130 (void) printf("\n");
2138 auth_cmd(argc
, argv
)
2145 (void) fprintf(stderr
, "Need an argument to 'auth' "
2146 "command. 'auth ?' for help.\n");
2150 c
= (struct authlist
*)
2151 genget(argv
[1], (char **)AuthList
, sizeof (struct authlist
));
2153 (void) fprintf(stderr
,
2154 "'%s': unknown argument ('auth ?' for help).\n",
2159 (void) fprintf(stderr
,
2160 "'%s': ambiguous argument ('auth ?' for help).\n", argv
[1]);
2163 if (c
->narg
+ 2 != argc
) {
2164 (void) fprintf(stderr
,
2165 "Need %s%d argument%s to 'auth %s' command."
2166 " 'auth ?' for help.\n",
2167 c
->narg
+ 2 < argc
? "only " : "",
2168 c
->narg
, c
->narg
== 1 ? "" : "s", c
->name
);
2171 return ((*c
->handler
)(argv
[2], argv
[3]));
2175 * The FORWARD command.
2178 extern int forward_flags
;
2187 static int forw_status(void);
2188 static int forw_set(int);
2189 static int forw_help(void);
2191 static struct forwlist ForwList
[] = {
2193 "Display current status of credential forwarding",
2196 "Disable credential forwarding",
2199 "Enable credential forwarding",
2200 forw_set
, OPTS_FORWARD_CREDS
},
2202 "Enable credential forwarding of "
2203 "forwardable credentials",
2204 forw_set
, OPTS_FORWARD_CREDS
| OPTS_FORWARDABLE_CREDS
},
2209 "Print help information",
2217 if (forward_flags
& OPTS_FORWARD_CREDS
) {
2218 if (forward_flags
& OPTS_FORWARDABLE_CREDS
)
2219 (void) printf(gettext(
2220 "Credential forwarding of "
2221 "forwardable credentials enabled\n"));
2223 (void) printf(gettext(
2224 "Credential forwarding enabled\n"));
2226 (void) printf(gettext("Credential forwarding disabled\n"));
2231 forw_set(int f_flags
)
2233 forward_flags
= f_flags
;
2242 for (c
= ForwList
; c
->name
; c
++) {
2245 (void) printf("%-15s %s\r\n", c
->name
, c
->help
);
2247 (void) printf("\n");
2254 forw_cmd(int argc
, char *argv
[])
2259 (void) fprintf(stderr
, gettext(
2260 "Need an argument to 'forward' "
2261 "command. 'forward ?' for help.\n"));
2264 c
= (struct forwlist
*)genget(argv
[1], (char **)ForwList
,
2265 sizeof (struct forwlist
));
2267 (void) fprintf(stderr
, gettext(
2268 "'%s': unknown argument ('forward ?' for help).\n"),
2273 (void) fprintf(stderr
, gettext(
2274 "'%s': ambiguous argument ('forward ?' for help).\n"),
2279 (void) fprintf(stderr
, gettext(
2280 "No arguments needed to 'forward %s' command. "
2281 "'forward ?' for help.\n"), c
->name
);
2284 return ((*c
->handler
) (c
->f_flags
));
2288 * The ENCRYPT command.
2291 struct encryptlist
{
2300 static int EncryptHelp(void);
2302 static struct encryptlist EncryptList
[] = {
2303 { "enable", "Enable encryption. ('encrypt enable ?' for more)",
2304 EncryptEnable
, 1, 1, 2 },
2305 { "disable", "Disable encryption. ('encrypt disable ?' for more)",
2306 EncryptDisable
, 0, 1, 2 },
2307 { "type", "Set encryption type. ('encrypt type ?' for more)",
2308 EncryptType
, 0, 1, 2 },
2309 { "start", "Start encryption. ('encrypt start ?' for more)",
2310 EncryptStart
, 1, 0, 1 },
2311 { "stop", "Stop encryption. ('encrypt stop ?' for more)",
2312 EncryptStop
, 1, 0, 1 },
2313 { "input", "Start encrypting the input stream",
2314 EncryptStartInput
, 1, 0, 0 },
2315 { "-input", "Stop encrypting the input stream",
2316 EncryptStopInput
, 1, 0, 0 },
2317 { "output", "Start encrypting the output stream",
2318 EncryptStartOutput
, 1, 0, 0 },
2319 { "-output", "Stop encrypting the output stream",
2320 EncryptStopOutput
, 1, 0, 0 },
2322 { "status", "Display current status of encryption information",
2323 EncryptStatus
, 0, 0, 0 },
2325 EncryptHelp
, 0, 0, 0 },
2326 { "?", "Print help information", EncryptHelp
, 0, 0, 0 },
2333 struct encryptlist
*c
;
2335 for (c
= EncryptList
; c
->name
; c
++) {
2338 (void) printf("%-15s %s\n", c
->name
, c
->help
);
2340 (void) printf("\n");
2347 encrypt_cmd(int argc
, char *argv
[])
2349 struct encryptlist
*c
;
2352 (void) fprintf(stderr
, gettext(
2353 "Need an argument to 'encrypt' command. "
2354 "'encrypt ?' for help.\n"));
2358 c
= (struct encryptlist
*)
2359 genget(argv
[1], (char **)EncryptList
, sizeof (struct encryptlist
));
2361 (void) fprintf(stderr
, gettext(
2362 "'%s': unknown argument ('encrypt ?' for help).\n"),
2367 (void) fprintf(stderr
, gettext(
2368 "'%s': ambiguous argument ('encrypt ?' for help).\n"),
2373 if (argc
< c
->minarg
|| argc
> c
->maxarg
) {
2374 if (c
->minarg
== c
->maxarg
) {
2375 (void) fprintf(stderr
, gettext("Need %s%d %s "),
2377 gettext("only ") : "", c
->minarg
,
2379 gettext("argument") : gettext("arguments"));
2381 (void) fprintf(stderr
,
2382 gettext("Need %s%d-%d arguments "),
2384 gettext("only ") : "", c
->minarg
, c
->maxarg
);
2386 (void) fprintf(stderr
, gettext(
2387 "to 'encrypt %s' command. 'encrypt ?' for help.\n"),
2391 if (c
->needconnect
&& !connected
) {
2393 (isprefix(argv
[2], "help") || isprefix(argv
[2], "?")))) {
2395 gettext("?Need to be connected first.\n"));
2399 return ((*c
->handler
)(argc
> 0 ? argv
[2] : 0,
2400 argc
> 1 ? argv
[3] : 0, argc
> 2 ? argv
[4] : 0));
2404 * Print status about the connection.
2407 status(int argc
, char *argv
[])
2410 (void) printf("Connected to %s.\n", hostname
);
2411 if ((argc
< 2) || strcmp(argv
[1], "notmuch")) {
2412 int mode
= getconnmode();
2414 if (my_want_state_is_will(TELOPT_LINEMODE
)) {
2416 "Operating with LINEMODE option\n");
2418 "%s line editing\n", (mode
&MODE_EDIT
) ?
2420 (void) printf("%s catching of signals\n",
2421 (mode
&MODE_TRAPSIG
) ? "Local" : "No");
2423 #ifdef KLUDGELINEMODE
2424 } else if (kludgelinemode
&&
2425 my_want_state_is_dont(TELOPT_SGA
)) {
2427 "Operating in obsolete linemode\n");
2431 "Operating in single character mode\n");
2434 "Catching signals locally\n");
2436 (void) printf("%s character echo\n", (mode
&MODE_ECHO
) ?
2437 "Local" : "Remote");
2438 if (my_want_state_is_will(TELOPT_LFLOW
))
2439 (void) printf("%s flow control\n",
2440 (mode
&MODE_FLOW
) ? "Local" : "No");
2445 (void) printf("No connection.\n");
2447 if (rlogin
!= _POSIX_VDISABLE
)
2448 (void) printf("Escape character is '%s'.\n", control(rlogin
));
2451 "Escape character is '%s'.\n", esc_control(escape
));
2452 (void) fflush(stdout
);
2457 * Parse the user input (cmd_line_input) which should:
2458 * - start with the target host, or with "@" or "!@" followed by at least one
2460 * - each host (can be literal address or hostname) can be separated by ",",
2462 * Note that the last host is the target, all the others (if any ) are the
2465 * Returns: -1 if a library call fails, too many gateways, or parse
2468 * On successful return, hostname_list points to a list of hosts (last one being
2469 * the target, others gateways), src_rtng_type points to the type of source
2470 * routing (strict vs. loose)
2473 parse_input(char *cmd_line_input
, char **hostname_list
, uchar_t
*src_rtng_type
)
2475 char hname
[MAXHOSTNAMELEN
+ 1];
2481 cp
= cmd_line_input
;
2484 * Defining ICMD generates the Itelnet binary, the special version of
2485 * telnet which is used with firewall proxy.
2486 * If ICMD is defined, parse_input will treat the whole cmd_line_input
2487 * as the target host and set the num_gw to 0. Therefore, none of the
2488 * source routing related code paths will be executed.
2492 *src_rtng_type
= IPOPT_LSRR
;
2494 } else if (*cp
== '!') {
2495 *src_rtng_type
= IPOPT_SSRR
;
2497 /* "!" must be followed by '@' */
2498 if (*(cp
+ 1) != '@')
2503 /* no gateways, just the target */
2504 hostname_list
[0] = strdup(cp
);
2505 if (hostname_list
[0] == NULL
) {
2506 perror("telnet: copying host name");
2513 while (*cp
!= '\0') {
2515 * Identify each gateway separated by ",", "@" or ",@" and
2519 while (*cp
!= '@' && *cp
!= ',' && *cp
!= '\0') {
2521 if (i
> MAXHOSTNAMELEN
)
2527 * Two consecutive delimiters which result in a 0 length hname
2533 hostname_list
[gw_count
] = strdup(hname
);
2534 if (hostname_list
[gw_count
] == NULL
) {
2535 perror("telnet: copying hostname from list");
2539 if (++gw_count
> MAXMAX_GATEWAY
) {
2540 (void) fprintf(stderr
, "telnet: too many gateways\n");
2544 /* Jump over the next delimiter. */
2546 /* ...gw1,@gw2... accepted */
2547 if (*cp
== ',' && *(cp
+ 1) == '@')
2554 /* discount the target */
2557 /* Any input starting with '!@' or '@' must have at least one gateway */
2564 (void) printf("Bad source route option: %s\n", cmd_line_input
);
2570 * Resolves the target and gateway addresses, determines what type of addresses
2571 * (ALL_ADDRS, ONLY_V6, ONLY_V4) telnet will be trying to connect.
2573 * Returns: pointer to resolved target if name resolutions succeed
2574 * NULL if name resolutions fail or
2575 * a library function call fails
2577 * The last host in the hostname_list is the target. After resolving the target,
2578 * determines for what type of addresses it should try to resolve gateways. It
2579 * resolves gateway addresses and picks one address for each desired address
2580 * type and stores in the array pointed by gw_addrsp. Also, this 'type of
2581 * addresses' is pointed by addr_type argument on successful return.
2583 static struct addrinfo
*
2584 resolve_hosts(char **hostname_list
, int num_gw
, struct gateway
**gw_addrsp
,
2585 int *addr_type
, const char *portp
)
2587 struct gateway
*gw_addrs
= NULL
;
2589 /* whether we already picked an IPv4 address for the current gateway */
2590 boolean_t got_v4_addr
;
2591 boolean_t got_v6_addr
;
2592 /* whether we need to get an IPv4 address for the current gateway */
2593 boolean_t need_v4_addr
= B_FALSE
;
2594 boolean_t need_v6_addr
= B_FALSE
;
2595 int res_failed_at4
; /* save which gateway failed to resolve */
2597 boolean_t is_v4mapped
;
2598 struct in6_addr
*v6addrp
;
2599 struct in_addr
*v4addrp
;
2603 struct addrinfo
*res
, *host
, *gateway
, *addr
;
2604 struct addrinfo hints
;
2606 *addr_type
= ALL_ADDRS
;
2608 memset(&hints
, 0, sizeof (hints
));
2609 hints
.ai_flags
= AI_CANONNAME
; /* used for config files, diags */
2610 hints
.ai_socktype
= SOCK_STREAM
;
2611 rc
= getaddrinfo(hostname_list
[num_gw
],
2612 (portp
!= NULL
) ? portp
: "telnet", &hints
, &res
);
2614 if (hostname_list
[num_gw
] != NULL
&&
2615 *hostname_list
[num_gw
] != '\0')
2616 (void) fprintf(stderr
, "%s: ", hostname_list
[num_gw
]);
2617 (void) fprintf(stderr
, "%s\n", gai_strerror(rc
));
2622 * Let's see what type of addresses we got for the target. This
2623 * determines what type of addresses we'd like to resolve gateways
2626 for (host
= res
; host
!= NULL
; host
= host
->ai_next
) {
2627 struct sockaddr_in6
*s6
;
2629 s6
= (struct sockaddr_in6
*)host
->ai_addr
;
2631 if (host
->ai_addr
->sa_family
== AF_INET
||
2632 IN6_IS_ADDR_V4MAPPED(&s6
->sin6_addr
))
2633 need_v4_addr
= B_TRUE
;
2635 need_v6_addr
= B_TRUE
;
2638 * Let's stop after seeing we need both IPv6 and IPv4.
2640 if (need_v4_addr
&& need_v6_addr
)
2646 * In the prepare_optbuf(), we'll store the IPv4 address of the
2647 * target in the last slot of gw_addrs array. Therefore we need
2648 * space for num_gw+1 hosts.
2650 gw_addrs
= calloc(num_gw
+ 1, sizeof (struct gateway
));
2651 if (gw_addrs
== NULL
) {
2652 perror("telnet: calloc");
2659 * Now we'll go through all the gateways and try to resolve them to
2660 * the desired address types.
2664 /* -1 means 'no address resolution failure yet' */
2665 res_failed_at4
= -1;
2666 res_failed_at6
= -1;
2667 for (i
= 0; i
< num_gw
; i
++) {
2668 rc
= getaddrinfo(hostname_list
[i
], NULL
, NULL
, &gateway
);
2670 if (hostname_list
[i
] != NULL
&&
2671 *hostname_list
[i
] != '\0')
2672 (void) fprintf(stderr
, "%s: ",
2674 (void) fprintf(stderr
, "bad address\n");
2679 * Initially we have no address of any type for this gateway.
2681 got_v6_addr
= B_FALSE
;
2682 got_v4_addr
= B_FALSE
;
2685 * Let's go through all the addresses of this gateway.
2686 * Use the first address which matches the needed family.
2688 for (addr
= gateway
; addr
!= NULL
; addr
= addr
->ai_next
) {
2690 v6addrp
= &((struct sockaddr_in6
*)addr
->ai_addr
)->
2692 v4addrp
= &((struct sockaddr_in
*)addr
->ai_addr
)->
2695 if (addr
->ai_family
== AF_INET6
)
2696 is_v4mapped
= IN6_IS_ADDR_V4MAPPED(v6addrp
);
2698 is_v4mapped
= B_FALSE
;
2701 * If we need to determine an IPv4 address and haven't
2702 * found one yet and this is a IPv4-mapped IPv6 address,
2705 if (need_v4_addr
&& !got_v4_addr
) {
2707 IN6_V4MAPPED_TO_INADDR(v6addrp
,
2709 got_v4_addr
= B_TRUE
;
2710 } else if (addr
->ai_family
= AF_INET
) {
2711 gw
->gw_addr
= *v4addrp
;
2712 got_v4_addr
= B_TRUE
;
2716 if (need_v6_addr
&& !got_v6_addr
&&
2717 addr
->ai_family
== AF_INET6
) {
2718 gw
->gw_addr6
= *v6addrp
;
2719 got_v6_addr
= B_TRUE
;
2723 * Let's stop if we got all what we looked for.
2725 if ((!need_v4_addr
|| got_v4_addr
) &&
2726 (!need_v6_addr
|| got_v6_addr
))
2731 * We needed an IPv4 address for this gateway but couldn't
2734 if (need_v4_addr
&& !got_v4_addr
) {
2737 * Since we couldn't resolve a gateway to IPv4 address
2738 * we can't use IPv4 at all. Therefore we no longer
2739 * need IPv4 addresses for any of the gateways.
2741 need_v4_addr
= B_FALSE
;
2744 if (need_v6_addr
&& !got_v6_addr
) {
2746 need_v6_addr
= B_FALSE
;
2750 * If some gateways don't resolve to any of the desired
2751 * address types, we fail.
2753 if (!need_v4_addr
&& !need_v6_addr
) {
2754 if (res_failed_at6
!= -1) {
2755 (void) fprintf(stderr
,
2756 "%s: Host doesn't have any IPv6 address\n",
2757 hostname_list
[res_failed_at6
]);
2759 if (res_failed_at4
!= -1) {
2760 (void) fprintf(stderr
,
2761 "%s: Host doesn't have any IPv4 address\n",
2762 hostname_list
[res_failed_at4
]);
2771 *gw_addrsp
= gw_addrs
;
2774 * When we get here, need_v4_addr and need_v6_addr have their final
2775 * values based on the name resolution of the target and gateways.
2777 if (need_v4_addr
&& need_v6_addr
)
2778 *addr_type
= ALL_ADDRS
;
2779 else if (need_v4_addr
&& !need_v6_addr
)
2780 *addr_type
= ONLY_V4
;
2781 else if (!need_v4_addr
&& need_v6_addr
)
2782 *addr_type
= ONLY_V6
;
2789 * Initializes the buffer pointed by opt_bufpp for a IPv4 option of type
2790 * src_rtng_type using the gateway addresses stored in gw_addrs. If no buffer
2791 * is passed, it allocates one. If a buffer is passed, checks if it's big
2793 * On return opt_buf_len points to the buffer length which we need later for the
2794 * setsockopt() call, and opt_bufpp points to the newly allocated or already
2795 * passed buffer. Returns B_FALSE if a library function call fails or passed
2796 * buffer is not big enough, B_TRUE otherwise.
2799 prepare_optbuf(struct gateway
*gw_addrs
, int num_gw
, char **opt_bufpp
,
2800 size_t *opt_buf_len
, struct in_addr
*target
, uchar_t src_rtng_type
)
2802 struct ip_sourceroute
*sr_opt
;
2803 size_t needed_buflen
;
2807 * We have (num_gw + 1) IP addresses in the buffer because the number
2808 * of gateway addresses we put in the option buffer includes the target
2810 * At the time of setsockopt() call, passed option length needs to be
2811 * multiple of 4 bytes. Therefore we need one IPOPT_NOP before (or
2812 * after) IPOPT_LSRR.
2813 * 1 = preceding 1 byte of IPOPT_NOP
2814 * 3 = 1 (code) + 1 (len) + 1 (ptr)
2816 needed_buflen
= 1 + 3 + (num_gw
+ 1) * sizeof (struct in_addr
);
2818 if (*opt_bufpp
!= NULL
) {
2819 /* check if the passed buffer is big enough */
2820 if (*opt_buf_len
< needed_buflen
) {
2821 (void) fprintf(stderr
,
2822 "telnet: buffer too small for IPv4 source routing "
2827 *opt_bufpp
= malloc(needed_buflen
);
2828 if (*opt_bufpp
== NULL
) {
2829 perror("telnet: malloc");
2834 *opt_buf_len
= needed_buflen
;
2836 /* final hop is the target */
2837 gw_addrs
[num_gw
].gw_addr
= *target
;
2839 *opt_bufpp
[0] = IPOPT_NOP
;
2840 /* IPOPT_LSRR starts right after IPOPT_NOP */
2841 sr_opt
= (struct ip_sourceroute
*)(*opt_bufpp
+ 1);
2842 sr_opt
->ipsr_code
= src_rtng_type
;
2843 /* discount the 1 byte of IPOPT_NOP */
2844 sr_opt
->ipsr_len
= needed_buflen
- 1;
2845 sr_opt
->ipsr_ptr
= IPOPT_MINOFF
;
2847 /* copy the gateways into the optlist */
2848 for (i
= 0; i
< num_gw
+ 1; i
++) {
2849 (void) bcopy(&gw_addrs
[i
].gw_addr
, &sr_opt
->ipsr_addrs
[i
],
2850 sizeof (struct in_addr
));
2857 * Initializes the buffer pointed by opt_bufpp for a IPv6 routing header option
2858 * using the gateway addresses stored in gw_addrs. If no buffer is passed, it
2859 * allocates one. If a buffer is passed, checks if it's big enough.
2860 * On return opt_buf_len points to the buffer length which we need later for the
2861 * setsockopt() call, and opt_bufpp points to the newly allocated or already
2862 * passed buffer. Returns B_FALSE if a library function call fails or passed
2863 * buffer is not big enough, B_TRUE otherwise.
2866 prepare_optbuf6(struct gateway
*gw_addrs
, int num_gw
, char **opt_bufpp
,
2867 size_t *opt_buf_len
)
2870 size_t needed_buflen
;
2873 needed_buflen
= inet6_rth_space(IPV6_RTHDR_TYPE_0
, num_gw
);
2875 if (*opt_bufpp
!= NULL
) {
2876 /* check if the passed buffer is big enough */
2877 if (*opt_buf_len
< needed_buflen
) {
2878 (void) fprintf(stderr
,
2879 "telnet: buffer too small for IPv6 routing "
2884 *opt_bufpp
= malloc(needed_buflen
);
2885 if (*opt_bufpp
== NULL
) {
2886 perror("telnet: malloc");
2890 *opt_buf_len
= needed_buflen
;
2891 opt_bufp
= *opt_bufpp
;
2894 * Initialize the buffer to be used for IPv6 routing header type 0.
2896 if (inet6_rth_init(opt_bufp
, needed_buflen
, IPV6_RTHDR_TYPE_0
,
2898 perror("telnet: inet6_rth_init");
2903 * Add gateways one by one.
2905 for (i
= 0; i
< num_gw
; i
++) {
2906 if (inet6_rth_add(opt_bufp
, &gw_addrs
[i
].gw_addr6
) == -1) {
2907 perror("telnet: inet6_rth_add");
2912 /* successful operation */
2921 struct addrinfo
*host
= NULL
;
2923 struct sockaddr_in6 sin6
;
2924 struct sockaddr_in sin
;
2925 struct in6_addr addr6
;
2926 struct in_addr addr
;
2928 struct gateway
*gw_addrs
;
2929 char *hostname_list
[MAXMAX_GATEWAY
+ 1] = {NULL
};
2930 char *opt_buf6
= NULL
; /* used for IPv6 routing header */
2931 size_t opt_buf_len6
= 0;
2932 uchar_t src_rtng_type
; /* type of IPv4 source routing */
2933 struct servent
*sp
= 0;
2934 char *opt_buf
= NULL
; /* used for IPv4 source routing */
2935 size_t opt_buf_len
= 0;
2943 unsigned short dest_port
;
2946 * The two strings at the end of this function are 24 and 39
2947 * characters long (minus the %.*s in the format strings). Add
2948 * one for the null terminator making the longest print string 40.
2950 char buf
[MAXHOSTNAMELEN
+40];
2952 * In the case of ICMD defined, dest_port will contain the real port
2953 * we are trying to telnet to, and target_port will contain
2954 * "telnet-passthru" port.
2956 unsigned short target_port
;
2957 char abuf
[INET6_ADDRSTRLEN
];
2960 boolean_t is_v4mapped
;
2962 * Type of addresses we'll try to connect to (ALL_ADDRS, ONLY_V6,
2967 /* clear the socket address prior to use */
2968 (void) memset(&sin6
, '\0', sizeof (sin6
));
2969 sin6
.sin6_family
= AF_INET6
;
2971 (void) memset(&sin
, '\0', sizeof (sin
));
2972 sin
.sin_family
= AF_INET
;
2975 (void) printf("?Already connected to %s\n", hostname
);
2979 itelnet_host
= getenv("INTERNET_HOST");
2980 if (itelnet_host
== NULL
|| itelnet_host
[0] == '\0') {
2981 (void) printf("INTERNET_HOST environment variable undefined\n");
2986 (void) printf("(to) ");
2987 if (GetAndAppendString(&line
, &linesize
, "open ",
3001 if (isprefix(*argv
, "help") == 4 || isprefix(*argv
, "?") == 1)
3003 if (strcmp(*argv
, "-l") == 0) {
3011 if (strcmp(*argv
, "-a") == 0) {
3013 autologin
= autologin_set
= 1;
3025 * Do we treat this like a telnet port or raw?
3027 if (*portp
== '-') {
3036 "usage: %s [-l user] [-a] host-name [port]\n", cmd
);
3044 * For setup phase treat the relay host as the target host.
3047 hostp
= itelnet_host
;
3049 num_gw
= parse_input(hostp
, hostname_list
, &src_rtng_type
);
3054 /* Last host in the hostname_list is the target */
3055 hostp
= hostname_list
[num_gw
];
3057 host
= resolve_hosts(hostname_list
, num_gw
, &gw_addrs
, &addr_type
,
3064 * Check if number of gateways is less than max. available
3066 if ((addr_type
== ALL_ADDRS
|| addr_type
== ONLY_V6
) &&
3067 num_gw
> MAX_GATEWAY6
) {
3068 (void) fprintf(stderr
, "telnet: too many IPv6 gateways\n");
3072 if ((addr_type
== ALL_ADDRS
|| addr_type
== ONLY_V4
) &&
3073 num_gw
> MAX_GATEWAY
) {
3074 (void) fprintf(stderr
, "telnet: too many IPv4 gateways\n");
3079 * If we pass a literal IPv4 address to getaddrinfo(), in the
3080 * returned addrinfo structure, hostname is the IPv4-mapped IPv6
3081 * address string. We prefer to preserve the literal IPv4 address
3082 * string as the hostname. Also, if the hostname entered by the
3083 * user is IPv4-mapped IPv6 address, we'll downgrade it to IPv4
3086 if (inet_addr(hostp
) != (in_addr_t
)-1) {
3087 /* this is a literal IPv4 address */
3088 (void) strlcpy(_hostname
, hostp
, sizeof (_hostname
));
3089 } else if ((inet_pton(AF_INET6
, hostp
, &addr6
) > 0) &&
3090 IN6_IS_ADDR_V4MAPPED(&addr6
)) {
3091 /* this is a IPv4-mapped IPv6 address */
3092 IN6_V4MAPPED_TO_INADDR(&addr6
, &addr
);
3093 (void) inet_ntop(AF_INET
, &addr
, _hostname
, sizeof (_hostname
));
3095 (void) strlcpy(_hostname
, host
->ai_canonname
,
3096 sizeof (_hostname
));
3098 hostname
= _hostname
;
3100 if (portp
== NULL
) {
3104 if (host
->ai_family
== AF_INET
) {
3105 target_port
= ((struct sockaddr_in
*)(host
->ai_addr
))->sin_port
;
3107 target_port
= ((struct sockaddr_in6
*)(host
->ai_addr
))
3113 * Since we pass the port number as an ascii string to the proxy,
3114 * we need it in host format.
3116 dest_port
= ntohs(target_port
);
3117 sp
= getservbyname("telnet-passthru", "tcp");
3119 (void) fprintf(stderr
,
3120 "telnet: tcp/telnet-passthru: unknown service\n");
3123 target_port
= sp
->s_port
;
3128 * For IPv6 source routing, we need to initialize option buffer only
3131 if (num_gw
> 0 && (addr_type
== ALL_ADDRS
|| addr_type
== ONLY_V6
)) {
3132 if (!prepare_optbuf6(gw_addrs
, num_gw
, &opt_buf6
,
3139 * We procure the Kerberos config files options only
3140 * if the user has choosen Krb5 authentication.
3142 if (krb5auth_flag
> 0) {
3143 krb5_profile_get_options(hostname
, telnet_krb5_realm
,
3144 config_file_options
);
3148 extern boolean_t auth_enable_encrypt
;
3149 if (krb5_privacy_allowed()) {
3152 wantencryption
= B_TRUE
;
3154 auth_enable_encrypt
= B_TRUE
;
3156 (void) fprintf(stderr
, gettext(
3157 "%s:Encryption not supported.\n"), prompt
);
3162 if (forward_flag
&& forwardable_flag
) {
3163 (void) fprintf(stderr
, gettext(
3164 "Error in krb5 configuration file. "
3165 "Both forward and forwardable are set.\n"));
3168 if (forwardable_flag
) {
3169 forward_flags
|= OPTS_FORWARD_CREDS
| OPTS_FORWARDABLE_CREDS
;
3170 } else if (forward_flag
)
3171 forward_flags
|= OPTS_FORWARD_CREDS
;
3176 * Search for an address of desired type in the IP address list
3180 struct sockaddr_in6
*addr
;
3182 addr
= (struct sockaddr_in6
*)h
->ai_addr
;
3184 if (h
->ai_family
== AF_INET6
)
3186 IN6_IS_ADDR_V4MAPPED(&addr
->sin6_addr
);
3188 is_v4mapped
= B_FALSE
;
3190 if (addr_type
== ALL_ADDRS
||
3191 (addr_type
== ONLY_V6
&&
3192 h
->ai_family
== AF_INET6
) ||
3193 (addr_type
== ONLY_V4
&&
3194 (h
->ai_family
== AF_INET
|| is_v4mapped
)))
3197 /* skip undesired typed addresses */
3203 "telnet: Unable to connect to remote host");
3208 * We need to open a socket with a family matching the type of
3209 * address we are trying to connect to. This is because we
3210 * deal with IPv4 options and IPv6 extension headers.
3212 if (h
->ai_family
== AF_INET
) {
3213 addrp
= &((struct sockaddr_in
*)(h
->ai_addr
))->sin_addr
;
3214 ((struct sockaddr_in
*)(h
->ai_addr
))->sin_port
=
3217 addrp
= &((struct sockaddr_in6
*)(h
->ai_addr
))
3219 ((struct sockaddr_in6
*)(h
->ai_addr
))->sin6_port
=
3223 (void) printf("Trying %s...\n", inet_ntop(h
->ai_family
,
3224 addrp
, abuf
, sizeof (abuf
)));
3226 net
= socket(h
->ai_family
, SOCK_STREAM
, 0);
3229 perror("telnet: socket");
3234 if (h
->ai_family
== AF_INET
|| is_v4mapped
) {
3235 if (!prepare_optbuf(gw_addrs
, num_gw
, &opt_buf
,
3236 &opt_buf_len
, addrp
, src_rtng_type
)) {
3240 if (setsockopt(net
, IPPROTO_IP
, IP_OPTIONS
,
3241 opt_buf
, opt_buf_len
) < 0)
3242 perror("setsockopt (IP_OPTIONS)");
3244 if (setsockopt(net
, IPPROTO_IPV6
, IPV6_RTHDR
,
3245 opt_buf6
, opt_buf_len6
) < 0)
3246 perror("setsockopt (IPV6_RTHDR)");
3250 #if defined(USE_TOS)
3253 tos
= 020; /* Low Delay bit */
3255 (setsockopt(net
, IPPROTO_IP
, IP_TOS
,
3256 &tos
, sizeof (int)) < 0) &&
3257 (errno
!= ENOPROTOOPT
))
3258 perror("telnet: setsockopt (IP_TOS) (ignored)");
3260 #endif /* defined(USE_TOS) */
3262 if (debug
&& SetSockOpt(net
, SOL_SOCKET
, SO_DEBUG
, 1) < 0) {
3263 perror("setsockopt (SO_DEBUG)");
3266 ret_val
= connect(net
, h
->ai_addr
, h
->ai_addrlen
);
3269 * If failed, try the next address of the target.
3273 if (h
->ai_next
!= NULL
) {
3277 (void) fprintf(stderr
,
3278 "telnet: connect to address %s: ", abuf
);
3285 perror("telnet: Unable to connect to remote host");
3289 } while (connected
== 0);
3294 * Do initial protocol to connect to farther end...
3298 (void) sprintf(buf
, "%s %d\n", real_host
, (int)dest_port
);
3299 write(net
, buf
, strlen(buf
));
3302 if (cmdrc(hostp
, hostname
) != 0)
3304 FreeHostnameList(hostname_list
);
3305 if (autologin
&& user
== NULL
) {
3308 user
= getenv("LOGNAME");
3310 ((pw
= getpwnam(user
)) != NULL
) &&
3311 pw
->pw_uid
!= getuid()) {
3312 if (pw
= getpwuid(getuid()))
3320 if (env_define((unsigned char *)"USER", (unsigned char *)user
))
3321 env_export((unsigned char *)"USER");
3323 /* Clean up and exit. */
3325 (void) snprintf(buf
, sizeof (buf
),
3326 "Connection to %.*s closed.\n",
3327 MAXHOSTNAMELEN
, hostname
);
3328 ExitString(buf
, EXIT_FAILURE
);
3333 (void) call(3, status
, "status", "notmuch");
3334 if (setjmp(peerdied
) == 0)
3339 (void) snprintf(buf
, sizeof (buf
),
3340 "Connection to %.*s closed by foreign host.\n",
3341 MAXHOSTNAMELEN
, hostname
);
3342 ExitString(buf
, EXIT_FAILURE
);
3347 FreeHostnameList(hostname_list
);
3355 #define HELPINDENT (sizeof ("connect"))
3357 static char openhelp
[] = "connect to a site";
3358 static char closehelp
[] = "close current connection";
3359 static char logouthelp
[] =
3360 "forcibly logout remote user and close the connection";
3361 static char quithelp
[] = "exit telnet";
3362 static char statushelp
[] = "print status information";
3363 static char helphelp
[] = "print help information";
3364 static char sendhelp
[] =
3365 "transmit special characters ('send ?' for more)";
3366 static char sethelp
[] = "set operating parameters ('set ?' for more)";
3367 static char unsethelp
[] = "unset operating parameters ('unset ?' for more)";
3368 static char togglestring
[] =
3369 "toggle operating parameters ('toggle ?' for more)";
3370 static char slchelp
[] = "change state of special charaters ('slc ?' for more)";
3371 static char displayhelp
[] = "display operating parameters";
3372 static char authhelp
[] =
3373 "turn on (off) authentication ('auth ?' for more)";
3374 static char forwardhelp
[] =
3375 "turn on (off) credential forwarding ('forward ?' for more)";
3376 static char encrypthelp
[] =
3377 "turn on (off) encryption ('encrypt ?' for more)";
3378 static char zhelp
[] = "suspend telnet";
3379 static char shellhelp
[] = "invoke a subshell";
3380 static char envhelp
[] = "change environment variables ('environ ?' for more)";
3381 static char modestring
[] =
3382 "try to enter line or character mode ('mode ?' for more)";
3386 static Command cmdtab
[] = {
3387 { "close", closehelp
, bye
, 1 },
3388 { "logout", logouthelp
, logout
, 1 },
3389 { "display", displayhelp
, display
, 0 },
3390 { "mode", modestring
, modecmd
, 0 },
3391 { "open", openhelp
, tn
, 0 },
3392 { "quit", quithelp
, quit
, 0 },
3393 { "send", sendhelp
, sendcmd
, 0 },
3394 { "set", sethelp
, setcmd
, 0 },
3395 { "unset", unsethelp
, unsetcmd
, 0 },
3396 { "status", statushelp
, status
, 0 },
3397 { "toggle", togglestring
, toggle
, 0 },
3398 { "slc", slchelp
, slccmd
, 0 },
3399 { "auth", authhelp
, auth_cmd
, 0 },
3400 { "encrypt", encrypthelp
, encrypt_cmd
, 0 },
3401 { "forward", forwardhelp
, forw_cmd
, 0 },
3402 { "z", zhelp
, suspend
, 0 },
3403 { "!", shellhelp
, shell
, 0 },
3404 { "environ", envhelp
, env_cmd
, 0 },
3405 { "?", helphelp
, help
, 0 },
3410 static Command cmdtab2
[] = {
3411 { "help", 0, help
, 0 },
3412 { "escape", 0, setescape
, 0 },
3413 { "crmod", 0, togcrmod
, 0 },
3419 * Call routine with argc, argv set from args.
3420 * Uses /usr/include/stdarg.h
3422 #define MAXVARGS 100
3425 call(int n_ptrs
, ...)
3428 typedef int (*intrtn_t
)();
3430 char *args
[MAXVARGS
+1]; /* leave 1 for trailing NULL */
3433 if (n_ptrs
> MAXVARGS
)
3435 va_start(ap
, n_ptrs
);
3437 routine
= (va_arg(ap
, intrtn_t
)); /* extract the routine's name */
3440 while (argno
< n_ptrs
) /* extract the routine's args */
3441 args
[argno
++] = va_arg(ap
, char *);
3442 args
[argno
] = NULL
; /* NULL terminate for good luck */
3445 (*routine
)(argno
, args
);
3455 if (cm
= (Command
*) genget(name
, (char **)cmdtab
, sizeof (Command
)))
3457 return (Command
*) genget(name
, (char **)cmdtab2
, sizeof (Command
));
3461 command(top
, tbuf
, cnt
)
3470 (void) putchar('\n');
3472 (void) signal(SIGINT
, SIG_DFL
);
3473 (void) signal(SIGQUIT
, SIG_DFL
);
3476 if (rlogin
== _POSIX_VDISABLE
)
3477 (void) printf("%s> ", prompt
);
3480 if (AllocStringBuffer(&line
, &linesize
, cnt
) == NULL
)
3483 while (cnt
> 0 && (*cp
++ = *tbuf
++) != '\n')
3486 if (cp
== line
|| *--cp
!= '\n' || cp
== line
)
3489 if (rlogin
== _POSIX_VDISABLE
)
3490 (void) printf("%s\n", line
);
3493 if (rlogin
!= _POSIX_VDISABLE
)
3494 (void) printf("%s> ", prompt
);
3495 if (GetString(&line
, &linesize
, stdin
) == NULL
) {
3506 if (margv
[0] == 0) {
3509 c
= getcmd(margv
[0]);
3511 (void) printf("?Ambiguous command\n");
3515 (void) printf("?Invalid command\n");
3518 if (c
->needconnect
&& !connected
) {
3519 (void) printf("?Need to be connected first.\n");
3522 if ((*c
->handler
)(margc
, margv
)) {
3529 longjmp(toplevel
, 1);
3544 register Command
*c
;
3548 "Commands may be abbreviated. Commands are:\n\n");
3549 for (c
= cmdtab
; c
->name
; c
++)
3551 (void) printf("%-*s\t%s\n", HELPINDENT
,
3554 (void) printf("<return>\tleave command mode\n");
3557 while (--argc
> 0) {
3562 (void) printf("?Ambiguous help command %s\n", arg
);
3563 else if (c
== (Command
*)0)
3564 (void) printf("?Invalid help command %s\n", arg
);
3566 (void) printf("%s\n", c
->help
);
3568 (void) printf("No additional help on %s\n", arg
);
3574 static char *rcname
= NULL
;
3575 #define TELNETRC_NAME "telnetrc"
3576 #define TELNETRC_COMP "/." TELNETRC_NAME
3579 cmdrc(char *m1
, char *m2
)
3582 FILE *rcfile
= NULL
;
3584 int l1
= strlen(m1
);
3585 int l2
= strlen(m2
);
3586 char m1save
[MAXHOSTNAMELEN
];
3588 char def
[] = "DEFAULT";
3595 (void) strlcpy(m1save
, m1
, sizeof (m1save
));
3598 if (rcname
== NULL
) {
3602 if ((homedir
= getenv("HOME")) == NULL
)
3605 rcbuflen
= strlen(homedir
) + strlen(TELNETRC_COMP
) + 1;
3606 if ((rcname
= malloc(rcbuflen
)) == NULL
) {
3607 perror("telnet: can't process " TELNETRC_NAME
);
3611 (void) strcpy(rcname
, homedir
);
3612 (void) strcat(rcname
, TELNETRC_COMP
);
3615 if ((rcfile
= fopen(rcname
, "r")) == NULL
)
3619 if (GetString(&line
, &linesize
, rcfile
) == NULL
) {
3620 if (!feof(rcfile
)) {
3621 perror("telnet: error reading " TELNETRC_NAME
);
3632 if (!isspace(line
[0]))
3635 if (gotmachine
== 0) {
3636 if (isspace(line
[0]))
3638 if (strncasecmp(line
, m1
, l1
) == 0)
3639 (void) strcpy(line
, &line
[l1
]);
3640 else if (strncasecmp(line
, m2
, l2
) == 0)
3641 (void) strcpy(line
, &line
[l2
]);
3642 else if (strncasecmp(line
, def
, sizeof (def
) - 1) == 0)
3643 (void) strcpy(line
, &line
[sizeof (def
) - 1]);
3646 if (line
[0] != ' ' && line
[0] != '\t' &&
3654 c
= getcmd(margv
[0]);
3656 (void) printf("?Ambiguous command: %s\n", margv
[0]);
3660 (void) printf("?Invalid command: %s\n", margv
[0]);
3664 * This should never happen...
3666 if (c
->needconnect
&& !connected
) {
3667 (void) printf("?Need to be connected first for %s.\n",
3671 (*c
->handler
)(margc
, margv
);
3675 (void) fclose(rcfile
);