dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / telnet / commands.c
blob7ba8b4af46c2dc576c006819e5b7a138d4873607
1 /*
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
7 * are met:
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
31 * SUCH DAMAGE.
33 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
34 * Use is subject to license terms.
37 #include <sys/param.h>
38 #include <sys/file.h>
39 #include <sys/socket.h>
40 #include <sys/sysmacros.h>
41 #include <netinet/in.h>
43 #include <signal.h>
44 #include <netdb.h>
45 #include <ctype.h>
46 #include <pwd.h>
47 #include <errno.h>
48 #include <strings.h>
50 #include <arpa/telnet.h>
51 #include <arpa/inet.h>
53 #include "general.h"
55 #include "ring.h"
57 #include "externs.h"
58 #include "defines.h"
59 #include "types.h"
61 extern char *telnet_krb5_realm;
62 extern void krb5_profile_get_options(char *, char *,
63 profile_options_boolean*);
65 #include <k5-int.h>
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 },
73 { NULL, NULL, 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.
82 #define MAX_GATEWAY 8
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 */
98 #if defined(USE_TOS)
99 int tos = -1;
100 #endif
102 char *hostname;
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 *);
109 typedef struct {
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? */
114 } Command;
117 * storage for IPv6 and/or IPv4 addresses of gateways
119 struct gateway {
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 {
132 uint8_t ipsr_code;
133 uint8_t ipsr_len;
134 uint8_t ipsr_ptr;
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;
141 static int margc;
142 static char **margv = NULL;
143 static unsigned margvlen = 0;
144 static int doing_rc = 0; /* .telnetrc file is being read and processed */
146 static void
147 Close(int *fd)
149 if (*fd != -1) {
150 (void) close(*fd);
151 *fd = -1;
155 static void
156 Free(char **p)
158 if (*p != NULL) {
159 free(*p);
160 *p = NULL;
164 static void
165 FreeHostnameList(char *list[])
167 unsigned i;
168 for (i = 0; i <= MAXMAX_GATEWAY && list[i] != NULL; i++)
169 Free(&list[i]);
172 #define MARGV_CHUNK_SIZE 8
174 static void
175 set_argv(str)
176 char *str;
178 if (margc == margvlen) {
179 char **newmargv;
181 margvlen += MARGV_CHUNK_SIZE;
183 if ((newmargv = realloc(margv, margvlen * sizeof (char *)))
184 == NULL)
185 ExitString("telnet: no space for arguments",
186 EXIT_FAILURE);
188 margv = newmargv;
191 margv[margc] = str;
192 if (str != NULL)
193 margc++;
196 static void
197 makeargv()
199 char *cp, *cp2, c;
200 boolean_t shellcmd = B_FALSE;
202 margc = 0;
203 cp = line;
204 if (*cp == '!') { /* Special case shell escape */
205 set_argv("!"); /* No room in string to get this */
206 cp++;
207 shellcmd = B_TRUE;
209 while ((c = *cp) != '\0') {
210 register int inquote = 0;
211 while (isspace(c))
212 c = *++cp;
213 if (c == '\0')
214 break;
215 set_argv(cp);
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.
222 if (shellcmd)
223 break;
224 for (cp2 = cp; c != '\0'; c = *++cp) {
225 if (inquote) {
226 if (c == inquote) {
227 inquote = 0;
228 continue;
230 } else {
231 if (c == '\\') {
232 if ((c = *++cp) == '\0')
233 break;
234 } else if (c == '"') {
235 inquote = '"';
236 continue;
237 } else if (c == '\'') {
238 inquote = '\'';
239 continue;
240 } else if (isspace(c))
241 break;
243 *cp2++ = c;
245 *cp2 = '\0';
246 if (c == '\0')
247 break;
248 cp++;
250 set_argv(NULL);
254 * Make a character string into a number.
256 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
259 static int
260 special(s)
261 register char *s;
263 register char c;
264 char b;
266 switch (*s) {
267 case '^':
268 b = *++s;
269 if (b == '?') {
270 c = b | 0x40; /* DEL */
271 } else {
272 c = b & 0x1f;
274 break;
275 default:
276 c = *s;
277 break;
279 return (c);
283 * Construct a control character sequence
284 * for a special character.
286 static char *
287 control(c)
288 register cc_t c;
290 static char buf[5];
292 * The only way I could get the Sun 3.5 compiler
293 * to shut up about
294 * if ((unsigned int)c >= 0x80)
295 * was to assign "c" to an unsigned int variable...
296 * Arggg....
298 register unsigned int uic = (unsigned int)c;
300 if (uic == 0x7f)
301 return ("^?");
302 if (c == (cc_t)_POSIX_VDISABLE) {
303 return ("off");
305 if (uic >= 0x80) {
306 buf[0] = '\\';
307 buf[1] = ((c>>6)&07) + '0';
308 buf[2] = ((c>>3)&07) + '0';
309 buf[3] = (c&07) + '0';
310 buf[4] = 0;
311 } else if (uic >= 0x20) {
312 buf[0] = c;
313 buf[1] = 0;
314 } else {
315 buf[0] = '^';
316 buf[1] = '@'+c;
317 buf[2] = 0;
319 return (buf);
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
325 * escape_valid.
327 static char *
328 esc_control(c)
329 register cc_t c;
331 static char buf[5];
333 * The only way I could get the Sun 3.5 compiler
334 * to shut up about
335 * if ((unsigned int)c >= 0x80)
336 * was to assign "c" to an unsigned int variable...
337 * Arggg....
339 register unsigned int uic = (unsigned int)c;
341 if (escape_valid == B_FALSE)
342 return ("off");
343 if (uic == 0x7f)
344 return ("^?");
345 if (uic >= 0x80) {
346 buf[0] = '\\';
347 buf[1] = ((c>>6)&07) + '0';
348 buf[2] = ((c>>3)&07) + '0';
349 buf[3] = (c&07) + '0';
350 buf[4] = 0;
351 } else if (uic >= 0x20) {
352 buf[0] = c;
353 buf[1] = 0;
354 } else {
355 buf[0] = '^';
356 buf[1] = '@'+c;
357 buf[2] = 0;
359 return (buf);
363 * The following are data structures and routines for
364 * the "send" command.
368 struct sendlist {
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 },
414 { 0 }
417 #define GETSEND(name) ((struct sendlist *)genget(name, (char **)Sendlist, \
418 sizeof (struct sendlist)))
420 static int
421 sendcmd(argc, argv)
422 int argc;
423 char **argv;
425 int count; /* how many bytes we are going to need to send */
426 int i;
427 struct sendlist *s; /* pointer to current command */
428 int success = 0;
429 int needconnect = 0;
431 if (argc < 2) {
432 (void) printf(
433 "need at least one argument for 'send' command\n");
434 (void) printf("'send ?' for help\n");
435 return (0);
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).
443 count = 0;
444 for (i = 1; i < argc; i++) {
445 s = GETSEND(argv[i]);
446 if (s == 0) {
447 (void) printf("Unknown send argument '%s'\n'send ?' "
448 "for help.\n", argv[i]);
449 return (0);
450 } else if (Ambiguous(s)) {
451 (void) printf("Ambiguous send argument '%s'\n'send ?' "
452 "for help.\n", argv[i]);
453 return (0);
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);
460 return (0);
462 count += s->nbyte;
463 if (s->handler == send_help) {
464 (void) send_help();
465 return (0);
468 i += s->narg;
469 needconnect += s->needconnect;
471 if (!connected && needconnect) {
472 (void) printf("?Need to be connected first.\n");
473 (void) printf("'send ?' for help\n");
474 return (0);
476 /* Now, do we have enough room? */
477 if (NETROOM() < count) {
478 (void) printf("There is not enough room in the buffer "
479 "TO the network\n");
480 (void) printf(
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");
485 return (0);
487 /* OK, they are all OK, now go through again and actually send */
488 count = 0;
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");
493 (void) quit();
494 /*NOTREACHED*/
496 if (s->handler) {
497 count++;
498 success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
499 (s->narg > 1) ? argv[i+2] : 0);
500 i += s->narg;
501 } else {
502 NET2ADD(IAC, s->what);
503 printoption("SENT", IAC, s->what);
506 return (count == success);
509 static int
510 send_esc()
512 NETADD(escape);
513 return (1);
516 static int
517 send_docmd(name)
518 char *name;
520 return (send_tncmd(send_do, "do", name));
523 static int
524 send_dontcmd(name)
525 char *name;
527 return (send_tncmd(send_dont, "dont", name));
530 static int
531 send_willcmd(name)
532 char *name;
534 return (send_tncmd(send_will, "will", name));
537 static int
538 send_wontcmd(name)
539 char *name;
541 return (send_tncmd(send_wont, "wont", name));
545 send_tncmd(func, cmd, name)
546 void (*func)();
547 char *cmd, *name;
549 char **cpp;
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");
560 col = 8;
561 for (cpp = telopts; *cpp; cpp++) {
562 len = strlen(*cpp) + 3;
563 if (col + len > 65) {
564 (void) printf("\n\t");
565 col = 8;
567 (void) printf(" \"%s\"", *cpp);
568 col += len;
570 (void) printf("\n");
571 return (0);
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",
577 name, cmd);
578 return (0);
580 if (cpp) {
581 val = cpp - telopts;
582 } else {
583 register char *cp = name;
585 while (*cp >= '0' && *cp <= '9') {
586 val *= 10;
587 val += *cp - '0';
588 cp++;
590 if (*cp != 0) {
591 (void) fprintf(stderr,
592 "'%s': unknown argument ('send %s ?' for help).\n",
593 name, cmd);
594 return (0);
595 } else if (val < 0 || val > 255) {
596 (void) fprintf(stderr,
597 "'%s': bad value ('send %s ?' for help).\n",
598 name, cmd);
599 return (0);
602 if (!connected) {
603 (void) printf("?Need to be connected first.\n");
604 return (0);
606 (*func)(val, 1);
607 return (1);
610 static int
611 send_help()
613 struct sendlist *s; /* pointer to current command */
614 for (s = Sendlist; s->name; s++) {
615 if (s->help)
616 (void) printf("%-15s %s\n", s->name, s->help);
618 return (0);
622 * The following are the routines and data structures referred
623 * to by the arguments to the "toggle" command.
626 static int
627 lclchars()
629 donelclchars = 1;
630 return (1);
633 static int
634 togdebug()
636 if (net > 0 &&
637 (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
638 perror("setsockopt (SO_DEBUG)");
640 return (1);
644 static int
645 togcrlf()
647 if (crlf) {
648 (void) printf(
649 "Will send carriage returns as telnet <CR><LF>.\n");
650 } else {
651 (void) printf(
652 "Will send carriage returns as telnet <CR><NUL>.\n");
654 return (1);
657 static int binmode;
659 static int
660 togbinary(val)
661 int val;
663 donebinarytoggle = 1;
665 if (val >= 0) {
666 binmode = val;
667 } else {
668 if (my_want_state_is_will(TELOPT_BINARY) &&
669 my_want_state_is_do(TELOPT_BINARY)) {
670 binmode = 1;
671 } else if (my_want_state_is_wont(TELOPT_BINARY) &&
672 my_want_state_is_dont(TELOPT_BINARY)) {
673 binmode = 0;
675 val = binmode ? 0 : 1;
678 if (val == 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");
683 } else {
684 (void) printf(
685 "Negotiating binary mode with remote host.\n");
686 tel_enter_binary(3);
688 } else {
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");
693 } else {
694 (void) printf("Negotiating network ascii mode "
695 "with remote host.\n");
696 tel_leave_binary(3);
699 return (1);
702 static int
703 togrbinary(val)
704 int val;
706 donebinarytoggle = 1;
708 if (val == -1)
709 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
711 if (val == 1) {
712 if (my_want_state_is_do(TELOPT_BINARY)) {
713 (void) printf("Already receiving in binary mode.\n");
714 } else {
715 (void) printf("Negotiating binary mode on input.\n");
716 tel_enter_binary(1);
718 } else {
719 if (my_want_state_is_dont(TELOPT_BINARY)) {
720 (void) printf(
721 "Already receiving in network ascii mode.\n");
722 } else {
723 (void) printf(
724 "Negotiating network ascii mode on input.\n");
725 tel_leave_binary(1);
728 return (1);
731 static int
732 togxbinary(val)
733 int val;
735 donebinarytoggle = 1;
737 if (val == -1)
738 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
740 if (val == 1) {
741 if (my_want_state_is_will(TELOPT_BINARY)) {
742 (void) printf("Already transmitting in binary mode.\n");
743 } else {
744 (void) printf("Negotiating binary mode on output.\n");
745 tel_enter_binary(2);
747 } else {
748 if (my_want_state_is_wont(TELOPT_BINARY)) {
749 (void) printf(
750 "Already transmitting in network ascii mode.\n");
751 } else {
752 (void) printf(
753 "Negotiating network ascii mode on output.\n");
754 tel_leave_binary(2);
757 return (1);
761 static int togglehelp(void);
762 extern int auth_togdebug(int);
764 struct togglelist {
765 char *name; /* name of toggle */
766 char *help; /* help message */
767 int (*handler)(); /* routine to do actual setting */
768 int *variable;
769 char *actionexplanation;
772 static struct togglelist Togglelist[] = {
773 { "autoflush",
774 "flushing of output when sending interrupt characters",
776 &autoflush,
777 "flush output when sending interrupt characters" },
778 { "autosynch",
779 "automatic sending of interrupt characters in urgent mode",
781 &autosynch,
782 "send interrupt characters in urgent mode" },
783 { "autologin",
784 "automatic sending of login and/or authentication info",
786 &autologin,
787 "send login name and/or authentication information" },
788 { "authdebug",
789 "authentication debugging",
790 auth_togdebug,
792 "print authentication debugging information" },
793 { "autoencrypt",
794 "automatic encryption of data stream",
795 EncryptAutoEnc,
797 "automatically encrypt output" },
798 { "autodecrypt",
799 "automatic decryption of data stream",
800 EncryptAutoDec,
802 "automatically decrypt input" },
803 { "verbose_encrypt",
804 "verbose encryption output",
805 EncryptVerbose,
807 "print verbose encryption output" },
808 { "encdebug",
809 "encryption debugging",
810 EncryptDebug,
812 "print encryption debugging information" },
813 { "skiprc",
814 "don't read ~/.telnetrc file",
816 &skiprc,
817 "skip reading of ~/.telnetrc file" },
818 { "binary",
819 "sending and receiving of binary data",
820 togbinary,
822 0 },
823 { "inbinary",
824 "receiving of binary data",
825 togrbinary,
827 0 },
828 { "outbinary",
829 "sending of binary data",
830 togxbinary,
832 0 },
833 { "crlf",
834 "sending carriage returns as telnet <CR><LF>",
835 togcrlf,
836 &crlf,
837 0 },
838 { "crmod",
839 "mapping of received carriage returns",
841 &crmod,
842 "map carriage return on output" },
843 { "localchars",
844 "local recognition of certain control characters",
845 lclchars,
846 &localchars,
847 "recognize certain control characters" },
848 { " ", "", 0 }, /* empty line */
849 { "debug",
850 "debugging",
851 togdebug,
852 &debug,
853 "turn on socket level debugging" },
854 { "netdata",
855 "printing of hexadecimal network data (debugging)",
857 &netdata,
858 "print hexadecimal representation of network traffic" },
859 { "prettydump",
860 "output of \"netdata\" to user readable format (debugging)",
862 &prettydump,
863 "print user readable output for \"netdata\"" },
864 { "options",
865 "viewing of options processing (debugging)",
867 &showoptions,
868 "show option processing" },
869 { "termdata",
870 "(debugging) toggle printing of hexadecimal terminal data",
872 &termdata,
873 "print hexadecimal representation of terminal traffic" },
874 { "?",
876 togglehelp },
877 { "help",
879 togglehelp },
880 { 0 }
883 static int
884 togglehelp()
886 struct togglelist *c;
888 for (c = Togglelist; c->name; c++) {
889 if (c->help) {
890 if (*c->help)
891 (void) printf(
892 "%-15s toggle %s\n", c->name, c->help);
893 else
894 (void) printf("\n");
897 (void) printf("\n");
898 (void) printf("%-15s %s\n", "?", "display help information");
899 return (0);
902 static void
903 settogglehelp(set)
904 int set;
906 struct togglelist *c;
908 for (c = Togglelist; c->name; c++) {
909 if (c->help) {
910 if (*c->help)
911 (void) printf("%-15s %s %s\n", c->name,
912 set ? "enable" : "disable", c->help);
913 else
914 (void) printf("\n");
919 #define GETTOGGLE(name) (struct togglelist *) \
920 genget(name, (char **)Togglelist, sizeof (struct togglelist))
922 static int
923 toggle(argc, argv)
924 int argc;
925 char *argv[];
927 int retval = 1;
928 char *name;
929 struct togglelist *c;
931 if (argc < 2) {
932 (void) fprintf(stderr,
933 "Need an argument to 'toggle' command. "
934 "'toggle ?' for help.\n");
935 return (0);
937 argc--;
938 argv++;
939 while (argc--) {
940 name = *argv++;
941 c = GETTOGGLE(name);
942 if (Ambiguous(c)) {
943 (void) fprintf(stderr, "'%s': ambiguous argument "
944 "('toggle ?' for help).\n", name);
945 return (0);
946 } else if (c == 0) {
947 (void) fprintf(stderr, "'%s': unknown argument "
948 "('toggle ?' for help).\n", name);
949 return (0);
950 } else {
951 if (c->variable) {
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);
959 if (c->handler) {
960 retval &= (*c->handler)(-1);
964 return (retval);
968 * The following perform the "set" command.
971 #ifdef USE_TERMIO
972 struct termio new_tc = { 0 };
973 #endif
975 struct setlist {
976 char *name; /* name */
977 char *help; /* help information */
978 void (*handler)();
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 },
985 #endif
986 { "escape", "character to escape back to telnet command mode", 0,
987 &escape },
988 { "rlogin", "rlogin escape character", 0, &rlogin },
989 { "tracefile", "file to write trace information to", SetNetTrace,
990 (cc_t *)NetTraceFile},
991 { " ", "" },
992 { " ", "The following need 'localchars' to be toggled true", 0, 0 },
993 { "flushoutput", "character to cause an Abort Output", 0,
994 termFlushCharp },
995 { "interrupt", "character to cause an Interrupt Process", 0,
996 termIntCharp },
997 { "quit", "character to cause an Abort process", 0, termQuitCharp },
998 { "eof", "character to cause an EOF ", 0, termEofCharp },
999 { " ", "" },
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 },
1013 { 0 }
1016 static struct setlist *
1017 getset(name)
1018 char *name;
1020 return ((struct setlist *)
1021 genget(name, (char **)Setlist, sizeof (struct setlist)));
1024 void
1025 set_escape_char(s)
1026 char *s;
1028 if (rlogin != _POSIX_VDISABLE) {
1029 rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
1030 (void) printf("Telnet rlogin escape character is '%s'.\n",
1031 control(rlogin));
1032 } else {
1033 escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
1034 (void) printf("Telnet escape character is '%s'.\n",
1035 esc_control(escape));
1039 static int
1040 setcmd(argc, argv)
1041 int argc;
1042 char *argv[];
1044 int value;
1045 struct setlist *ct;
1046 struct togglelist *c;
1048 if (argc < 2 || argc > 3) {
1049 (void) printf(
1050 "Format is 'set Name Value'\n'set ?' for help.\n");
1051 return (0);
1053 if ((argc == 2) &&
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");
1058 settogglehelp(1);
1059 (void) printf("%-15s %s\n", "?", "display help information");
1060 return (0);
1063 ct = getset(argv[1]);
1064 if (ct == 0) {
1065 c = GETTOGGLE(argv[1]);
1066 if (c == 0) {
1067 (void) fprintf(stderr, "'%s': unknown argument "
1068 "('set ?' for help).\n", argv[1]);
1069 return (0);
1070 } else if (Ambiguous(c)) {
1071 (void) fprintf(stderr, "'%s': ambiguous argument "
1072 "('set ?' for help).\n", argv[1]);
1073 return (0);
1075 if (c->variable) {
1076 if ((argc == 2) || (strcmp("on", argv[2]) == 0))
1077 *c->variable = 1;
1078 else if (strcmp("off", argv[2]) == 0)
1079 *c->variable = 0;
1080 else {
1081 (void) printf(
1082 "Format is 'set togglename [on|off]'\n"
1083 "'set ?' for help.\n");
1084 return (0);
1086 if (c->actionexplanation) {
1087 (void) printf("%s %s.\n",
1088 *c->variable? "Will" : "Won't",
1089 c->actionexplanation);
1092 if (c->handler)
1093 (*c->handler)(1);
1094 } else if (argc != 3) {
1095 (void) printf(
1096 "Format is 'set Name Value'\n'set ?' for help.\n");
1097 return (0);
1098 } else if (Ambiguous(ct)) {
1099 (void) fprintf(stderr,
1100 "'%s': ambiguous argument ('set ?' for help).\n", argv[1]);
1101 return (0);
1102 } else if (ct->handler) {
1103 (*ct->handler)(argv[2]);
1104 (void) printf(
1105 "%s set to \"%s\".\n", ct->name, (char *)ct->charp);
1106 } else {
1107 if (strcmp("off", argv[2])) {
1108 value = special(argv[2]);
1109 } else {
1110 value = _POSIX_VDISABLE;
1112 *(ct->charp) = (cc_t)value;
1113 (void) printf("%s character is '%s'.\n", ct->name,
1114 control(*(ct->charp)));
1116 slc_check();
1117 return (1);
1120 static int
1121 unsetcmd(argc, argv)
1122 int argc;
1123 char *argv[];
1125 struct setlist *ct;
1126 struct togglelist *c;
1127 register char *name;
1129 if (argc < 2) {
1130 (void) fprintf(stderr, "Need an argument to 'unset' command. "
1131 "'unset ?' for help.\n");
1132 return (0);
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");
1138 settogglehelp(0);
1139 (void) printf("%-15s %s\n", "?", "display help information");
1140 return (0);
1143 argc--;
1144 argv++;
1145 while (argc--) {
1146 name = *argv++;
1147 ct = getset(name);
1148 if (ct == 0) {
1149 c = GETTOGGLE(name);
1150 if (c == 0) {
1151 (void) fprintf(stderr, "'%s': unknown argument "
1152 "('unset ?' for help).\n", name);
1153 return (0);
1154 } else if (Ambiguous(c)) {
1155 (void) fprintf(stderr,
1156 "'%s': ambiguous argument "
1157 "('unset ?' for help).\n", name);
1158 return (0);
1160 if (c->variable) {
1161 *c->variable = 0;
1162 if (c->actionexplanation) {
1163 (void) printf("%s %s.\n",
1164 *c->variable? "Will" : "Won't",
1165 c->actionexplanation);
1168 if (c->handler)
1169 (*c->handler)(0);
1170 } else if (Ambiguous(ct)) {
1171 (void) fprintf(stderr, "'%s': ambiguous argument "
1172 "('unset ?' for help).\n", name);
1173 return (0);
1174 } else if (ct->handler) {
1175 (*ct->handler)(0);
1176 (void) printf("%s reset to \"%s\".\n", ct->name,
1177 (char *)ct->charp);
1178 } else {
1179 *(ct->charp) = _POSIX_VDISABLE;
1180 (void) printf("%s character is '%s'.\n", ct->name,
1181 control(*(ct->charp)));
1184 return (1);
1188 * The following are the data structures and routines for the
1189 * 'mode' command.
1191 extern int reqd_linemode;
1193 #ifdef KLUDGELINEMODE
1194 extern int kludgelinemode;
1196 static int
1197 dokludgemode()
1199 kludgelinemode = 1;
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.
1208 if (doing_rc)
1209 reqd_linemode = 1;
1210 return (1);
1212 #endif
1214 static int
1215 dolinemode()
1217 #ifdef KLUDGELINEMODE
1218 if (kludgelinemode)
1219 send_dont(TELOPT_SGA, 1);
1220 #endif
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.
1229 if (doing_rc)
1230 reqd_linemode = 1;
1231 return (1);
1234 static int
1235 docharmode()
1237 #ifdef KLUDGELINEMODE
1238 if (kludgelinemode)
1239 send_do(TELOPT_SGA, 1);
1240 else
1241 #endif
1242 send_wont(TELOPT_LINEMODE, 1);
1243 send_do(TELOPT_ECHO, 1);
1244 reqd_linemode = 0;
1245 return (1);
1248 static int
1249 dolmmode(bit, on)
1250 int bit, on;
1252 unsigned char c;
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");
1258 return (0);
1261 if (on)
1262 c = (linemode | bit);
1263 else
1264 c = (linemode & ~bit);
1265 lm_mode(&c, 1, 1);
1266 return (1);
1269 static int
1270 setmode(bit)
1272 return (dolmmode(bit, 1));
1275 static int
1276 clearmode(bit)
1278 return (dolmmode(bit, 0));
1281 struct modelist {
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? */
1286 int arg1;
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 },
1295 #endif
1296 { "line", "Enable LINEMODE option", dolinemode, 1 },
1297 #ifdef KLUDGELINEMODE
1298 { "", "(or enable obsolete line-by-line mode)", 0 },
1299 #endif
1300 { "", "", 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,
1316 MODE_LIT_ECHO },
1317 { "help", 0, modehelp, 0 },
1318 #ifdef KLUDGELINEMODE
1319 { "kludgeline", 0, dokludgemode, 1 },
1320 #endif
1321 { "", "", 0 },
1322 { "?", "Print help information", modehelp, 0 },
1323 { 0 },
1327 static int
1328 modehelp()
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++) {
1334 if (mt->help) {
1335 if (*mt->help)
1336 (void) printf("%-15s %s\n", mt->name, mt->help);
1337 else
1338 (void) printf("\n");
1341 return (0);
1344 #define GETMODECMD(name) (struct modelist *) \
1345 genget(name, (char **)ModeList, sizeof (struct modelist))
1347 static int
1348 modecmd(argc, argv)
1349 int argc;
1350 char *argv[];
1352 struct modelist *mt;
1354 if (argc != 2) {
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);
1369 return (0);
1373 * The following data structures and routines implement the
1374 * "display" command.
1377 static int
1378 display(argc, argv)
1379 int argc;
1380 char *argv[];
1382 struct togglelist *tl;
1383 struct setlist *sl;
1385 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1386 if (*tl->variable) { \
1387 (void) printf("will"); \
1388 } else { \
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)); \
1398 else \
1399 (void) printf("%-15s \"%s\"\n", sl->name, \
1400 (char *)sl->charp); \
1403 if (argc == 1) {
1404 for (tl = Togglelist; tl->name; tl++) {
1405 dotog(tl);
1407 (void) printf("\n");
1408 for (sl = Setlist; sl->name; sl++) {
1409 doset(sl);
1411 } else {
1412 int i;
1414 for (i = 1; i < argc; i++) {
1415 sl = getset(argv[i]);
1416 tl = GETTOGGLE(argv[i]);
1417 if (Ambiguous(sl) || Ambiguous(tl)) {
1418 (void) printf(
1419 "?Ambiguous argument '%s'.\n", argv[i]);
1420 return (0);
1421 } else if (!sl && !tl) {
1422 (void) printf(
1423 "?Unknown argument '%s'.\n", argv[i]);
1424 return (0);
1425 } else {
1426 if (tl) {
1427 dotog(tl);
1429 if (sl) {
1430 doset(sl);
1435 optionstatus();
1436 (void) EncryptStatus();
1437 return (1);
1438 #undef doset
1439 #undef dotog
1443 * The following are the data structures, and many of the routines,
1444 * relating to command processing.
1448 * Set the escape character.
1450 static int
1451 setescape(argc, argv)
1452 int argc;
1453 char *argv[];
1455 register char *arg;
1456 char *buf = NULL;
1458 if (argc > 2)
1459 arg = argv[1];
1460 else {
1461 (void) printf("new escape character: ");
1462 if (GetString(&buf, NULL, stdin) == NULL) {
1463 if (!feof(stdin)) {
1464 perror("can't set escape character");
1465 goto setescape_exit;
1468 arg = buf;
1470 /* we place no limitations on what escape can be. */
1471 escape = arg[0];
1472 (void) printf("Escape character is '%s'.\n", esc_control(escape));
1473 (void) fflush(stdout);
1474 setescape_exit:
1475 Free(&buf);
1476 return (1);
1479 /*ARGSUSED*/
1480 static int
1481 togcrmod(argc, argv)
1482 int argc;
1483 char *argv[];
1485 crmod = !crmod;
1486 (void) printf(
1487 "%s map carriage return on output.\n", crmod ? "Will" : "Won't");
1488 (void) fflush(stdout);
1489 return (1);
1492 /*ARGSUSED*/
1493 static int
1494 suspend(argc, argv)
1495 int argc;
1496 char *argv[];
1498 setcommandmode();
1500 unsigned short oldrows, oldcols, newrows, newcols;
1501 int err;
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)))) {
1512 sendnaws();
1515 /* reget parameters in case they were changed */
1516 TerminalSaveState();
1517 setconnmode(0);
1518 return (1);
1521 /*ARGSUSED*/
1522 static int
1523 shell(argc, argv)
1524 int argc;
1525 char *argv[];
1527 unsigned short oldrows, oldcols, newrows, newcols;
1528 int err;
1530 setcommandmode();
1532 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1533 switch (vfork()) {
1534 case -1:
1535 perror("Fork failed\n");
1536 break;
1538 case 0:
1541 * Fire up the shell in the child.
1543 register char *shellp, *shellname;
1545 shellp = getenv("SHELL");
1546 if (shellp == NULL)
1547 shellp = "/bin/sh";
1548 if ((shellname = strrchr(shellp, '/')) == 0)
1549 shellname = shellp;
1550 else
1551 shellname++;
1552 if (argc > 1)
1553 (void) execl(shellp, shellname, "-c", argv[1], 0);
1554 else
1555 (void) execl(shellp, shellname, 0);
1556 perror("Execl");
1557 _exit(EXIT_FAILURE);
1559 default:
1560 (void) wait((int *)0); /* Wait for the shell to complete */
1562 if (TerminalWindowSize(&newrows, &newcols) && connected &&
1563 (err || ((oldrows != newrows) || (oldcols != newcols)))) {
1564 sendnaws();
1566 break;
1568 return (1);
1571 static int
1572 bye(argc, argv)
1573 int argc; /* Number of arguments */
1574 char *argv[]; /* arguments */
1576 extern int resettermname;
1578 if (connected) {
1579 (void) shutdown(net, 2);
1580 (void) printf("Connection to %.*s closed.\n", MAXHOSTNAMELEN,
1581 hostname);
1582 Close(&net);
1583 connected = 0;
1584 resettermname = 1;
1585 /* reset options */
1586 (void) tninit();
1588 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
1589 longjmp(toplevel, 1);
1590 /* NOTREACHED */
1592 return (1); /* Keep lint, etc., happy */
1595 /*VARARGS*/
1597 quit()
1599 (void) call(3, bye, "bye", "fromquit");
1600 Exit(EXIT_SUCCESS);
1601 /*NOTREACHED*/
1602 return (1);
1605 /*ARGSUSED*/
1606 static int
1607 logout(argc, argv)
1608 int argc;
1609 char *argv[];
1611 send_do(TELOPT_LOGOUT, 1);
1612 (void) netflush();
1613 return (1);
1618 * The SLC command.
1621 struct slclist {
1622 char *name;
1623 char *help;
1624 void (*handler)();
1625 int arg;
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 },
1639 { 0 },
1642 static void
1643 slc_help()
1645 struct slclist *c;
1647 for (c = SlcList; c->name; c++) {
1648 if (c->help) {
1649 if (*c->help)
1650 (void) printf("%-15s %s\n", c->name, c->help);
1651 else
1652 (void) printf("\n");
1657 static struct slclist *
1658 getslc(name)
1659 char *name;
1661 return ((struct slclist *)
1662 genget(name, (char **)SlcList, sizeof (struct slclist)));
1665 static int
1666 slccmd(argc, argv)
1667 int argc;
1668 char *argv[];
1670 struct slclist *c;
1672 if (argc != 2) {
1673 (void) fprintf(stderr,
1674 "Need an argument to 'slc' command. 'slc ?' for help.\n");
1675 return (0);
1677 c = getslc(argv[1]);
1678 if (c == 0) {
1679 (void) fprintf(stderr,
1680 "'%s': unknown argument ('slc ?' for help).\n",
1681 argv[1]);
1682 return (0);
1684 if (Ambiguous(c)) {
1685 (void) fprintf(stderr,
1686 "'%s': ambiguous argument ('slc ?' for help).\n", argv[1]);
1687 return (0);
1689 (*c->handler)(c->arg);
1690 slcstate();
1691 return (1);
1695 * The ENVIRON command.
1698 struct envlist {
1699 char *name;
1700 char *help;
1701 void (*handler)();
1702 int narg;
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 *);
1712 #endif
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",
1721 env_undefine, 1 },
1722 { "export", "Mark an environment variable for automatic export",
1723 env_export, 1 },
1724 { "unexport", "Don't mark an environment variable for automatic export",
1725 env_unexport, 1 },
1726 { "send", "Send an environment variable", env_send, 1 },
1727 { "list", "List the current environment variables",
1728 env_list, 0 },
1729 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1730 { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
1731 env_varval, 1 },
1732 #endif
1733 { "help", 0, env_help, 0 },
1734 { "?", "Print help information", env_help, 0 },
1735 { 0 },
1738 static void
1739 env_help()
1741 struct envlist *c;
1743 for (c = EnvList; c->name; c++) {
1744 if (c->help) {
1745 if (*c->help)
1746 (void) printf("%-15s %s\n", c->name, c->help);
1747 else
1748 (void) printf("\n");
1753 static struct envlist *
1754 getenvcmd(name)
1755 char *name;
1757 return ((struct envlist *)
1758 genget(name, (char **)EnvList, sizeof (struct envlist)));
1761 static int
1762 env_cmd(argc, argv)
1763 int argc;
1764 char *argv[];
1766 struct envlist *c;
1768 if (argc < 2) {
1769 (void) fprintf(stderr,
1770 "Need an argument to 'environ' command. "
1771 "'environ ?' for help.\n");
1772 return (0);
1774 c = getenvcmd(argv[1]);
1775 if (c == 0) {
1776 (void) fprintf(stderr, "'%s': unknown argument "
1777 "('environ ?' for help).\n", argv[1]);
1778 return (0);
1780 if (Ambiguous(c)) {
1781 (void) fprintf(stderr, "'%s': ambiguous argument "
1782 "('environ ?' for help).\n", argv[1]);
1783 return (0);
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);
1791 return (0);
1793 (*c->handler)(argv[2], argv[3]);
1794 return (1);
1797 struct env_lst {
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 *
1809 env_find(var)
1810 unsigned char *var;
1812 register struct env_lst *ep;
1814 for (ep = envlisthead.next; ep; ep = ep->next) {
1815 if (strcmp((char *)ep->var, (char *)var) == 0)
1816 return (ep);
1818 return (NULL);
1822 env_init()
1824 extern char **environ;
1825 char **epp, *cp;
1826 struct env_lst *ep;
1828 for (epp = environ; *epp; epp++) {
1829 if (cp = strchr(*epp, '=')) {
1830 *cp = '\0';
1832 ep = env_define((unsigned char *)*epp,
1833 (unsigned char *)cp+1);
1834 if (ep == NULL)
1835 return (0);
1836 ep->export = 0;
1837 *cp = '=';
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
1843 * hostname.
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");
1853 return (0);
1855 hbuf[MAXHOSTNAMELEN-1] = '\0';
1856 cp = malloc(strlen(hbuf) + strlen(cp2) + 1);
1857 if (cp == NULL) {
1858 perror("telnet: cannot define DISPLAY variable");
1859 return (0);
1861 (void) sprintf((char *)cp, "%s%s", hbuf, cp2);
1862 free(ep->value);
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");
1879 return (1);
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;
1888 struct env_lst *ep;
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");
1897 return (NULL);
1900 tmp_value = (unsigned char *)strdup((char *)value);
1901 if (tmp_value == NULL) {
1902 free(tmp_var);
1903 perror("telnet: can't copy environment variable value");
1904 return (NULL);
1907 if (ep = env_find(var)) {
1908 free(ep->var);
1909 free(ep->value);
1910 } else {
1911 ep = malloc(sizeof (struct env_lst));
1912 if (ep == NULL) {
1913 perror("telnet: can't define environment variable");
1914 free(tmp_var);
1915 free(tmp_value);
1916 return (NULL);
1919 ep->next = envlisthead.next;
1920 envlisthead.next = ep;
1921 ep->prev = &envlisthead;
1922 if (ep->next)
1923 ep->next->prev = ep;
1925 ep->welldefined = opt_welldefined((char *)var);
1926 ep->export = 1;
1927 ep->var = tmp_var;
1928 ep->value = tmp_value;
1930 return (ep);
1933 static void
1934 env_undefine(var)
1935 unsigned char *var;
1937 register struct env_lst *ep;
1939 if (ep = env_find(var)) {
1940 ep->prev->next = ep->next;
1941 if (ep->next)
1942 ep->next->prev = ep->prev;
1943 free(ep->var);
1944 free(ep->value);
1945 free(ep);
1949 static void
1950 env_export(var)
1951 unsigned char *var;
1953 register struct env_lst *ep;
1955 if (ep = env_find(var))
1956 ep->export = 1;
1959 static void
1960 env_unexport(var)
1961 unsigned char *var;
1963 register struct env_lst *ep;
1965 if (ep = env_find(var))
1966 ep->export = 0;
1969 static void
1970 env_send(var)
1971 unsigned char *var;
1973 register struct env_lst *ep;
1975 if (my_state_is_wont(TELOPT_NEW_ENVIRON)
1976 #ifdef OLD_ENVIRON
1977 /* old style */ && my_state_is_wont(TELOPT_OLD_ENVIRON)
1978 #endif
1979 /* no environ */) {
1980 (void) fprintf(stderr,
1981 "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1982 var);
1983 return;
1985 ep = env_find(var);
1986 if (ep == 0) {
1987 (void) fprintf(stderr,
1988 "Cannot send '%s': variable not defined\n", var);
1989 return;
1991 env_opt_start_info();
1992 env_opt_add(ep->var);
1993 env_opt_end(0);
1996 static void
1997 env_list()
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);
2007 unsigned char *
2008 env_default(init, welldefined)
2009 int init;
2011 static struct env_lst *nep = NULL;
2013 if (init) {
2014 /* return value is not used */
2015 nep = &envlisthead;
2016 return (NULL);
2018 if (nep) {
2019 while ((nep = nep->next) != NULL) {
2020 if (nep->export && (nep->welldefined == welldefined))
2021 return (nep->var);
2024 return (NULL);
2027 unsigned char *
2028 env_getvalue(var)
2029 unsigned char *var;
2031 register struct env_lst *ep;
2033 if (ep = env_find(var))
2034 return (ep->value);
2035 return (NULL);
2038 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
2039 static void
2040 env_varval(what)
2041 unsigned char *what;
2043 extern int old_env_var, old_env_value, env_auto;
2044 int len = strlen((char *)what);
2046 if (len == 0)
2047 goto unknown;
2049 if (strncasecmp((char *)what, "status", len) == 0) {
2050 if (env_auto)
2051 (void) printf("%s%s", "VAR and VALUE are/will be ",
2052 "determined automatically\n");
2053 if (old_env_var == OLD_ENV_VAR)
2054 (void) printf(
2055 "VAR and VALUE set to correct definitions\n");
2056 else
2057 (void) printf(
2058 "VAR and VALUE definitions are reversed\n");
2059 } else if (strncasecmp((char *)what, "auto", len) == 0) {
2060 env_auto = 1;
2061 old_env_var = OLD_ENV_VALUE;
2062 old_env_value = OLD_ENV_VAR;
2063 } else if (strncasecmp((char *)what, "right", len) == 0) {
2064 env_auto = 0;
2065 old_env_var = OLD_ENV_VAR;
2066 old_env_value = OLD_ENV_VALUE;
2067 } else if (strncasecmp((char *)what, "wrong", len) == 0) {
2068 env_auto = 0;
2069 old_env_var = OLD_ENV_VALUE;
2070 old_env_value = OLD_ENV_VAR;
2071 } else {
2072 unknown:
2073 (void) printf(
2074 "Unknown \"varval\" command. (\"auto\", \"right\", "
2075 "\"wrong\", \"status\")\n");
2078 #endif /* OLD_ENVIRON && ENV_HACK */
2081 * The AUTHENTICATE command.
2084 struct authlist {
2085 char *name;
2086 char *help;
2087 int (*handler)();
2088 int narg;
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[] = {
2098 { "status",
2099 "Display current status of authentication information",
2100 auth_status, 0 },
2101 { "disable",
2102 "Disable an authentication type ('auth disable ?' for more)",
2103 auth_disable, 1 },
2104 { "enable",
2105 "Enable an authentication type ('auth enable ?' for more)",
2106 auth_enable, 1 },
2107 { "help", 0, auth_help, 0 },
2108 { "?", "Print help information", auth_help, 0 },
2109 { 0 },
2112 static int
2113 auth_help(void)
2115 struct authlist *c;
2117 for (c = AuthList; c->name; c++) {
2118 if (c->help) {
2119 if (*c->help)
2120 (void) printf("%-15s %s\n", c->name, c->help);
2121 else
2122 (void) printf("\n");
2125 return (0);
2129 static int
2130 auth_cmd(argc, argv)
2131 int argc;
2132 char *argv[];
2134 struct authlist *c;
2136 if (argc < 2) {
2137 (void) fprintf(stderr, "Need an argument to 'auth' "
2138 "command. 'auth ?' for help.\n");
2139 return (0);
2142 c = (struct authlist *)
2143 genget(argv[1], (char **)AuthList, sizeof (struct authlist));
2144 if (c == 0) {
2145 (void) fprintf(stderr,
2146 "'%s': unknown argument ('auth ?' for help).\n",
2147 argv[1]);
2148 return (0);
2150 if (Ambiguous(c)) {
2151 (void) fprintf(stderr,
2152 "'%s': ambiguous argument ('auth ?' for help).\n", argv[1]);
2153 return (0);
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);
2161 return (0);
2163 return ((*c->handler)(argv[2], argv[3]));
2167 * The FORWARD command.
2170 extern int forward_flags;
2172 struct forwlist {
2173 char *name;
2174 char *help;
2175 int (*handler)();
2176 int f_flags;
2179 static int forw_status(void);
2180 static int forw_set(int);
2181 static int forw_help(void);
2183 static struct forwlist ForwList[] = {
2184 {"status",
2185 "Display current status of credential forwarding",
2186 forw_status, 0},
2187 {"disable",
2188 "Disable credential forwarding",
2189 forw_set, 0},
2190 {"enable",
2191 "Enable credential forwarding",
2192 forw_set, OPTS_FORWARD_CREDS},
2193 {"forwardable",
2194 "Enable credential forwarding of "
2195 "forwardable credentials",
2196 forw_set, OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS},
2197 {"help",
2199 forw_help, 0},
2200 {"?",
2201 "Print help information",
2202 forw_help, 0},
2203 {0},
2206 static int
2207 forw_status(void)
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"));
2214 else
2215 (void) printf(gettext(
2216 "Credential forwarding enabled\n"));
2217 } else
2218 (void) printf(gettext("Credential forwarding disabled\n"));
2219 return (0);
2222 static int
2223 forw_set(int f_flags)
2225 forward_flags = f_flags;
2226 return (0);
2229 static int
2230 forw_help(void)
2232 struct forwlist *c;
2234 for (c = ForwList; c->name; c++) {
2235 if (c->help) {
2236 if (*c->help)
2237 (void) printf("%-15s %s\r\n", c->name, c->help);
2238 else
2239 (void) printf("\n");
2242 return (0);
2245 static int
2246 forw_cmd(int argc, char *argv[])
2248 struct forwlist *c;
2250 if (argc < 2) {
2251 (void) fprintf(stderr, gettext(
2252 "Need an argument to 'forward' "
2253 "command. 'forward ?' for help.\n"));
2254 return (0);
2256 c = (struct forwlist *)genget(argv[1], (char **)ForwList,
2257 sizeof (struct forwlist));
2258 if (c == 0) {
2259 (void) fprintf(stderr, gettext(
2260 "'%s': unknown argument ('forward ?' for help).\n"),
2261 argv[1]);
2262 return (0);
2264 if (Ambiguous(c)) {
2265 (void) fprintf(stderr, gettext(
2266 "'%s': ambiguous argument ('forward ?' for help).\n"),
2267 argv[1]);
2268 return (0);
2270 if (argc != 2) {
2271 (void) fprintf(stderr, gettext(
2272 "No arguments needed to 'forward %s' command. "
2273 "'forward ?' for help.\n"), c->name);
2274 return (0);
2276 return ((*c->handler) (c->f_flags));
2280 * The ENCRYPT command.
2283 struct encryptlist {
2284 char *name;
2285 char *help;
2286 int (*handler)();
2287 int needconnect;
2288 int minarg;
2289 int maxarg;
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 },
2316 { "help", 0,
2317 EncryptHelp, 0, 0, 0 },
2318 { "?", "Print help information", EncryptHelp, 0, 0, 0 },
2319 { 0 },
2322 static int
2323 EncryptHelp(void)
2325 struct encryptlist *c;
2327 for (c = EncryptList; c->name; c++) {
2328 if (c->help) {
2329 if (*c->help)
2330 (void) printf("%-15s %s\n", c->name, c->help);
2331 else
2332 (void) printf("\n");
2335 return (0);
2338 static int
2339 encrypt_cmd(int argc, char *argv[])
2341 struct encryptlist *c;
2343 if (argc < 2) {
2344 (void) fprintf(stderr, gettext(
2345 "Need an argument to 'encrypt' command. "
2346 "'encrypt ?' for help.\n"));
2347 return (0);
2350 c = (struct encryptlist *)
2351 genget(argv[1], (char **)EncryptList, sizeof (struct encryptlist));
2352 if (c == 0) {
2353 (void) fprintf(stderr, gettext(
2354 "'%s': unknown argument ('encrypt ?' for help).\n"),
2355 argv[1]);
2356 return (0);
2358 if (Ambiguous(c)) {
2359 (void) fprintf(stderr, gettext(
2360 "'%s': ambiguous argument ('encrypt ?' for help).\n"),
2361 argv[1]);
2362 return (0);
2364 argc -= 2;
2365 if (argc < c->minarg || argc > c->maxarg) {
2366 if (c->minarg == c->maxarg) {
2367 (void) fprintf(stderr, gettext("Need %s%d %s "),
2368 c->minarg < argc ?
2369 gettext("only ") : "", c->minarg,
2370 c->minarg == 1 ?
2371 gettext("argument") : gettext("arguments"));
2372 } else {
2373 (void) fprintf(stderr,
2374 gettext("Need %s%d-%d arguments "),
2375 c->maxarg < argc ?
2376 gettext("only ") : "", c->minarg, c->maxarg);
2378 (void) fprintf(stderr, gettext(
2379 "to 'encrypt %s' command. 'encrypt ?' for help.\n"),
2380 c->name);
2381 return (0);
2383 if (c->needconnect && !connected) {
2384 if (!(argc &&
2385 (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
2386 (void) printf(
2387 gettext("?Need to be connected first.\n"));
2388 return (0);
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.
2398 static int
2399 status(int argc, char *argv[])
2401 if (connected) {
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)) {
2407 (void) printf(
2408 "Operating with LINEMODE option\n");
2409 (void) printf(
2410 "%s line editing\n", (mode&MODE_EDIT) ?
2411 "Local" : "No");
2412 (void) printf("%s catching of signals\n",
2413 (mode&MODE_TRAPSIG) ? "Local" : "No");
2414 slcstate();
2415 #ifdef KLUDGELINEMODE
2416 } else if (kludgelinemode &&
2417 my_want_state_is_dont(TELOPT_SGA)) {
2418 (void) printf(
2419 "Operating in obsolete linemode\n");
2420 #endif
2421 } else {
2422 (void) printf(
2423 "Operating in single character mode\n");
2424 if (localchars)
2425 (void) printf(
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");
2434 encrypt_display();
2436 } else {
2437 (void) printf("No connection.\n");
2439 if (rlogin != _POSIX_VDISABLE)
2440 (void) printf("Escape character is '%s'.\n", control(rlogin));
2441 else
2442 (void) printf(
2443 "Escape character is '%s'.\n", esc_control(escape));
2444 (void) fflush(stdout);
2445 return (1);
2449 * Parse the user input (cmd_line_input) which should:
2450 * - start with the target host, or with "@" or "!@" followed by at least one
2451 * gateway.
2452 * - each host (can be literal address or hostname) can be separated by ",",
2453 * "@", or ",@".
2454 * Note that the last host is the target, all the others (if any ) are the
2455 * gateways.
2457 * Returns: -1 if a library call fails, too many gateways, or parse
2458 * error
2459 * num_gw otherwise
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)
2464 static int
2465 parse_input(char *cmd_line_input, char **hostname_list, uchar_t *src_rtng_type)
2467 char hname[MAXHOSTNAMELEN + 1];
2468 char *cp;
2469 int gw_count;
2470 int i;
2472 gw_count = 0;
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.
2482 #ifndef ICMD
2483 if (*cp == '@') {
2484 *src_rtng_type = IPOPT_LSRR;
2485 cp++;
2486 } else if (*cp == '!') {
2487 *src_rtng_type = IPOPT_SSRR;
2489 /* "!" must be followed by '@' */
2490 if (*(cp + 1) != '@')
2491 goto parse_error;
2492 cp += 2;
2493 } else {
2494 #endif /* ICMD */
2495 /* no gateways, just the target */
2496 hostname_list[0] = strdup(cp);
2497 if (hostname_list[0] == NULL) {
2498 perror("telnet: copying host name");
2499 return (-1);
2501 return (0);
2502 #ifndef ICMD
2505 while (*cp != '\0') {
2507 * Identify each gateway separated by ",", "@" or ",@" and
2508 * store in hname[].
2510 i = 0;
2511 while (*cp != '@' && *cp != ',' && *cp != '\0') {
2512 hname[i++] = *cp++;
2513 if (i > MAXHOSTNAMELEN)
2514 goto parse_error;
2516 hname[i] = '\0';
2519 * Two consecutive delimiters which result in a 0 length hname
2520 * is a parse error.
2522 if (i == 0)
2523 goto parse_error;
2525 hostname_list[gw_count] = strdup(hname);
2526 if (hostname_list[gw_count] == NULL) {
2527 perror("telnet: copying hostname from list");
2528 return (-1);
2531 if (++gw_count > MAXMAX_GATEWAY) {
2532 (void) fprintf(stderr, "telnet: too many gateways\n");
2533 return (-1);
2536 /* Jump over the next delimiter. */
2537 if (*cp != '\0') {
2538 /* ...gw1,@gw2... accepted */
2539 if (*cp == ',' && *(cp + 1) == '@')
2540 cp += 2;
2541 else
2542 cp++;
2546 /* discount the target */
2547 gw_count--;
2549 /* Any input starting with '!@' or '@' must have at least one gateway */
2550 if (gw_count <= 0)
2551 goto parse_error;
2553 return (gw_count);
2555 parse_error:
2556 (void) printf("Bad source route option: %s\n", cmd_line_input);
2557 return (-1);
2558 #endif /* ICMD */
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;
2580 struct gateway *gw;
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 */
2588 int res_failed_at6;
2589 boolean_t is_v4mapped;
2590 struct in6_addr *v6addrp;
2591 struct in_addr *v4addrp;
2592 int error_num;
2593 int i;
2594 int rc;
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);
2605 if (rc != 0) {
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));
2610 return (NULL);
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
2616 * later.
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;
2626 else
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)
2633 break;
2636 if (num_gw > 0) {
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");
2645 freeaddrinfo(res);
2646 return (NULL);
2651 * Now we'll go through all the gateways and try to resolve them to
2652 * the desired address types.
2654 gw = gw_addrs;
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);
2661 if (rc != 0) {
2662 if (hostname_list[i] != NULL &&
2663 *hostname_list[i] != '\0')
2664 (void) fprintf(stderr, "%s: ",
2665 hostname_list[i]);
2666 (void) fprintf(stderr, "bad address\n");
2667 return (NULL);
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) {
2681 /*LINTED*/
2682 v6addrp = &((struct sockaddr_in6 *)addr->ai_addr)->
2683 sin6_addr;
2684 v4addrp = &((struct sockaddr_in *)addr->ai_addr)->
2685 sin_addr;
2687 if (addr->ai_family == AF_INET6)
2688 is_v4mapped = IN6_IS_ADDR_V4MAPPED(v6addrp);
2689 else
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,
2695 * then bingo!
2697 if (need_v4_addr && !got_v4_addr) {
2698 if (is_v4mapped) {
2699 IN6_V4MAPPED_TO_INADDR(v6addrp,
2700 &gw->gw_addr);
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))
2719 break;
2723 * We needed an IPv4 address for this gateway but couldn't
2724 * find one.
2726 if (need_v4_addr && !got_v4_addr) {
2727 res_failed_at4 = i;
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) {
2737 res_failed_at6 = i;
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]);
2756 free(gw_addrs);
2757 return (NULL);
2760 gw++;
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;
2776 return (res);
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
2784 * enough.
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.
2790 static boolean_t
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;
2796 int i;
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
2801 * address.
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 "
2815 "option\n");
2816 return (B_FALSE);
2818 } else {
2819 *opt_bufpp = malloc(needed_buflen);
2820 if (*opt_bufpp == NULL) {
2821 perror("telnet: malloc");
2822 return (B_FALSE);
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));
2845 return (B_TRUE);
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.
2857 static boolean_t
2858 prepare_optbuf6(struct gateway *gw_addrs, int num_gw, char **opt_bufpp,
2859 size_t *opt_buf_len)
2861 char *opt_bufp;
2862 size_t needed_buflen;
2863 int i;
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 "
2872 "header option\n");
2873 return (B_FALSE);
2875 } else {
2876 *opt_bufpp = malloc(needed_buflen);
2877 if (*opt_bufpp == NULL) {
2878 perror("telnet: malloc");
2879 return (B_FALSE);
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,
2889 num_gw) == NULL) {
2890 perror("telnet: inet6_rth_init");
2891 return (B_FALSE);
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");
2900 return (B_FALSE);
2904 /* successful operation */
2905 return (B_TRUE);
2909 tn(argc, argv)
2910 int argc;
2911 char *argv[];
2913 struct addrinfo *host = NULL;
2914 struct addrinfo *h;
2915 struct sockaddr_in6 sin6;
2916 struct sockaddr_in sin;
2917 struct in6_addr addr6;
2918 struct in_addr addr;
2919 void *addrp;
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;
2928 char *cmd;
2929 char *hostp = NULL;
2930 char *portp = NULL;
2931 char *user = NULL;
2932 #ifdef ICMD
2933 char *itelnet_host;
2934 char *real_host;
2935 unsigned short dest_port;
2936 #endif /* ICMD */
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];
2950 int num_gw;
2951 int ret_val;
2952 boolean_t is_v4mapped;
2954 * Type of addresses we'll try to connect to (ALL_ADDRS, ONLY_V6,
2955 * ONLY_V4).
2957 int addr_type;
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;
2966 if (connected) {
2967 (void) printf("?Already connected to %s\n", hostname);
2968 return (0);
2970 #ifdef ICMD
2971 itelnet_host = getenv("INTERNET_HOST");
2972 if (itelnet_host == NULL || itelnet_host[0] == '\0') {
2973 (void) printf("INTERNET_HOST environment variable undefined\n");
2974 goto tn_exit;
2976 #endif
2977 if (argc < 2) {
2978 (void) printf("(to) ");
2979 if (GetAndAppendString(&line, &linesize, "open ",
2980 stdin) == NULL) {
2981 if (!feof(stdin)) {
2982 perror("telnet");
2983 goto tn_exit;
2986 makeargv();
2987 argc = margc;
2988 argv = margv;
2990 cmd = *argv;
2991 --argc; ++argv;
2992 while (argc) {
2993 if (isprefix(*argv, "help") == 4 || isprefix(*argv, "?") == 1)
2994 goto usage;
2995 if (strcmp(*argv, "-l") == 0) {
2996 --argc; ++argv;
2997 if (argc == 0)
2998 goto usage;
2999 user = *argv++;
3000 --argc;
3001 continue;
3003 if (strcmp(*argv, "-a") == 0) {
3004 --argc; ++argv;
3005 autologin = autologin_set = 1;
3006 continue;
3008 if (hostp == 0) {
3009 hostp = *argv++;
3010 --argc;
3011 continue;
3013 if (portp == 0) {
3014 portp = *argv++;
3015 --argc;
3017 * Do we treat this like a telnet port or raw?
3019 if (*portp == '-') {
3020 portp++;
3021 telnetport = 1;
3022 } else
3023 telnetport = 0;
3024 continue;
3026 usage:
3027 (void) printf(
3028 "usage: %s [-l user] [-a] host-name [port]\n", cmd);
3029 goto tn_exit;
3031 if (hostp == 0)
3032 goto usage;
3034 #ifdef ICMD
3036 * For setup phase treat the relay host as the target host.
3038 real_host = hostp;
3039 hostp = itelnet_host;
3040 #endif
3041 num_gw = parse_input(hostp, hostname_list, &src_rtng_type);
3042 if (num_gw < 0) {
3043 goto tn_exit;
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,
3050 portp);
3051 if (host == NULL) {
3052 goto tn_exit;
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");
3061 goto tn_exit;
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");
3067 goto tn_exit;
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
3076 * address.
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));
3086 } else {
3087 (void) strlcpy(_hostname, host->ai_canonname,
3088 sizeof (_hostname));
3090 hostname = _hostname;
3092 if (portp == NULL) {
3093 telnetport = 1;
3096 if (host->ai_family == AF_INET) {
3097 target_port = ((struct sockaddr_in *)(host->ai_addr))->sin_port;
3098 } else {
3099 target_port = ((struct sockaddr_in6 *)(host->ai_addr))
3100 ->sin6_port;
3103 #ifdef ICMD
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");
3110 if (sp == 0) {
3111 (void) fprintf(stderr,
3112 "telnet: tcp/telnet-passthru: unknown service\n");
3113 goto tn_exit;
3115 target_port = sp->s_port;
3116 #endif
3117 h = host;
3120 * For IPv6 source routing, we need to initialize option buffer only
3121 * once.
3123 if (num_gw > 0 && (addr_type == ALL_ADDRS || addr_type == ONLY_V6)) {
3124 if (!prepare_optbuf6(gw_addrs, num_gw, &opt_buf6,
3125 &opt_buf_len6)) {
3126 goto tn_exit;
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);
3139 if (encrypt_flag) {
3140 extern boolean_t auth_enable_encrypt;
3141 if (krb5_privacy_allowed()) {
3142 encrypt_auto(1);
3143 decrypt_auto(1);
3144 wantencryption = B_TRUE;
3145 autologin = 1;
3146 auth_enable_encrypt = B_TRUE;
3147 } else {
3148 (void) fprintf(stderr, gettext(
3149 "%s:Encryption not supported.\n"), prompt);
3150 exit(1);
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"));
3158 exit(1);
3160 if (forwardable_flag) {
3161 forward_flags |= OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS;
3162 } else if (forward_flag)
3163 forward_flags |= OPTS_FORWARD_CREDS;
3166 do {
3168 * Search for an address of desired type in the IP address list
3169 * of the target.
3171 while (h != NULL) {
3172 struct sockaddr_in6 *addr;
3174 addr = (struct sockaddr_in6 *)h->ai_addr;
3176 if (h->ai_family == AF_INET6)
3177 is_v4mapped =
3178 IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr);
3179 else
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)))
3187 break;
3189 /* skip undesired typed addresses */
3190 h = h->ai_next;
3193 if (h == NULL) {
3194 fprintf(stderr,
3195 "telnet: Unable to connect to remote host");
3196 goto tn_exit;
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 =
3207 target_port;
3208 } else {
3209 addrp = &((struct sockaddr_in6 *)(h->ai_addr))
3210 ->sin6_addr;
3211 ((struct sockaddr_in6 *)(h->ai_addr))->sin6_port =
3212 target_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);
3220 if (net < 0) {
3221 perror("telnet: socket");
3222 goto tn_exit;
3224 #ifndef ICMD
3225 if (num_gw > 0) {
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)) {
3229 goto tn_exit;
3232 if (setsockopt(net, IPPROTO_IP, IP_OPTIONS,
3233 opt_buf, opt_buf_len) < 0)
3234 perror("setsockopt (IP_OPTIONS)");
3235 } else {
3236 if (setsockopt(net, IPPROTO_IPV6, IPV6_RTHDR,
3237 opt_buf6, opt_buf_len6) < 0)
3238 perror("setsockopt (IPV6_RTHDR)");
3241 #endif
3242 #if defined(USE_TOS)
3243 if (is_v4mapped) {
3244 if (tos < 0)
3245 tos = 020; /* Low Delay bit */
3246 if (tos &&
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.
3263 if (ret_val < 0) {
3264 Close(&net);
3265 if (h->ai_next != NULL) {
3267 int oerrno = errno;
3269 (void) fprintf(stderr,
3270 "telnet: connect to address %s: ", abuf);
3271 errno = oerrno;
3272 perror((char *)0);
3274 h = h->ai_next;
3275 continue;
3277 perror("telnet: Unable to connect to remote host");
3278 goto tn_exit;
3280 connected++;
3281 } while (connected == 0);
3282 freeaddrinfo(host);
3283 host = NULL;
3284 #ifdef ICMD
3286 * Do initial protocol to connect to farther end...
3289 char buf[1024];
3290 (void) sprintf(buf, "%s %d\n", real_host, (int)dest_port);
3291 write(net, buf, strlen(buf));
3293 #endif
3294 if (cmdrc(hostp, hostname) != 0)
3295 goto tn_exit;
3296 FreeHostnameList(hostname_list);
3297 if (autologin && user == NULL) {
3298 struct passwd *pw;
3300 user = getenv("LOGNAME");
3301 if (user == NULL ||
3302 ((pw = getpwnam(user)) != NULL) &&
3303 pw->pw_uid != getuid()) {
3304 if (pw = getpwuid(getuid()))
3305 user = pw->pw_name;
3306 else
3307 user = NULL;
3311 if (user) {
3312 if (env_define((unsigned char *)"USER", (unsigned char *)user))
3313 env_export((unsigned char *)"USER");
3314 else {
3315 /* Clean up and exit. */
3316 Close(&net);
3317 (void) snprintf(buf, sizeof (buf),
3318 "Connection to %.*s closed.\n",
3319 MAXHOSTNAMELEN, hostname);
3320 ExitString(buf, EXIT_FAILURE);
3322 /* NOTREACHED */
3325 (void) call(3, status, "status", "notmuch");
3326 if (setjmp(peerdied) == 0)
3327 telnet(user);
3329 Close(&net);
3331 (void) snprintf(buf, sizeof (buf),
3332 "Connection to %.*s closed by foreign host.\n",
3333 MAXHOSTNAMELEN, hostname);
3334 ExitString(buf, EXIT_FAILURE);
3336 /*NOTREACHED*/
3338 tn_exit:
3339 FreeHostnameList(hostname_list);
3340 Close(&net);
3341 connected = 0;
3342 if (host != NULL)
3343 freeaddrinfo(host);
3344 return (0);
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)";
3376 static int help();
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
3415 /*VARARGS1*/
3416 static void
3417 call(int n_ptrs, ...)
3419 va_list ap;
3420 typedef int (*intrtn_t)();
3421 intrtn_t routine;
3422 char *args[MAXVARGS+1]; /* leave 1 for trailing NULL */
3423 int argno = 0;
3425 if (n_ptrs > MAXVARGS)
3426 n_ptrs = MAXVARGS;
3427 va_start(ap, n_ptrs);
3429 routine = (va_arg(ap, intrtn_t)); /* extract the routine's name */
3430 n_ptrs--;
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 */
3435 va_end(ap);
3437 (*routine)(argno, args);
3441 static Command *
3442 getcmd(name)
3443 char *name;
3445 Command *cm;
3447 if (cm = (Command *) genget(name, (char **)cmdtab, sizeof (Command)))
3448 return (cm);
3449 return (Command *) genget(name, (char **)cmdtab2, sizeof (Command));
3452 void
3453 command(top, tbuf, cnt)
3454 int top;
3455 char *tbuf;
3456 int cnt;
3458 Command *c;
3460 setcommandmode();
3461 if (!top) {
3462 (void) putchar('\n');
3463 } else {
3464 (void) signal(SIGINT, SIG_DFL);
3465 (void) signal(SIGQUIT, SIG_DFL);
3467 for (;;) {
3468 if (rlogin == _POSIX_VDISABLE)
3469 (void) printf("%s> ", prompt);
3470 if (tbuf) {
3471 char *cp;
3472 if (AllocStringBuffer(&line, &linesize, cnt) == NULL)
3473 goto command_exit;
3474 cp = line;
3475 while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
3476 cnt--;
3477 tbuf = 0;
3478 if (cp == line || *--cp != '\n' || cp == line)
3479 goto getline;
3480 *cp = '\0';
3481 if (rlogin == _POSIX_VDISABLE)
3482 (void) printf("%s\n", line);
3483 } else {
3484 getline:
3485 if (rlogin != _POSIX_VDISABLE)
3486 (void) printf("%s> ", prompt);
3487 if (GetString(&line, &linesize, stdin) == NULL) {
3488 if (!feof(stdin))
3489 perror("telnet");
3490 (void) quit();
3491 /*NOTREACHED*/
3492 break;
3495 if (line[0] == 0)
3496 break;
3497 makeargv();
3498 if (margv[0] == 0) {
3499 break;
3501 c = getcmd(margv[0]);
3502 if (Ambiguous(c)) {
3503 (void) printf("?Ambiguous command\n");
3504 continue;
3506 if (c == 0) {
3507 (void) printf("?Invalid command\n");
3508 continue;
3510 if (c->needconnect && !connected) {
3511 (void) printf("?Need to be connected first.\n");
3512 continue;
3514 if ((*c->handler)(margc, margv)) {
3515 break;
3518 command_exit:
3519 if (!top) {
3520 if (!connected) {
3521 longjmp(toplevel, 1);
3522 /*NOTREACHED*/
3524 setconnmode(0);
3529 * Help command.
3531 static int
3532 help(argc, argv)
3533 int argc;
3534 char *argv[];
3536 register Command *c;
3538 if (argc == 1) {
3539 (void) printf(
3540 "Commands may be abbreviated. Commands are:\n\n");
3541 for (c = cmdtab; c->name; c++)
3542 if (c->help) {
3543 (void) printf("%-*s\t%s\n", HELPINDENT,
3544 c->name, c->help);
3546 (void) printf("<return>\tleave command mode\n");
3547 return (0);
3549 while (--argc > 0) {
3550 register char *arg;
3551 arg = *++argv;
3552 c = getcmd(arg);
3553 if (Ambiguous(c))
3554 (void) printf("?Ambiguous help command %s\n", arg);
3555 else if (c == (Command *)0)
3556 (void) printf("?Invalid help command %s\n", arg);
3557 else if (c->help) {
3558 (void) printf("%s\n", c->help);
3559 } else {
3560 (void) printf("No additional help on %s\n", arg);
3563 return (0);
3566 static char *rcname = NULL;
3567 #define TELNETRC_NAME "telnetrc"
3568 #define TELNETRC_COMP "/." TELNETRC_NAME
3570 static int
3571 cmdrc(char *m1, char *m2)
3573 Command *c;
3574 FILE *rcfile = NULL;
3575 int gotmachine = 0;
3576 int l1 = strlen(m1);
3577 int l2 = strlen(m2);
3578 char m1save[MAXHOSTNAMELEN];
3579 int ret = 0;
3580 char def[] = "DEFAULT";
3582 if (skiprc)
3583 goto cmdrc_exit;
3585 doing_rc = 1;
3587 (void) strlcpy(m1save, m1, sizeof (m1save));
3588 m1 = m1save;
3590 if (rcname == NULL) {
3591 char *homedir;
3592 unsigned rcbuflen;
3594 if ((homedir = getenv("HOME")) == NULL)
3595 homedir = "";
3597 rcbuflen = strlen(homedir) + strlen(TELNETRC_COMP) + 1;
3598 if ((rcname = malloc(rcbuflen)) == NULL) {
3599 perror("telnet: can't process " TELNETRC_NAME);
3600 ret = 1;
3601 goto cmdrc_exit;
3603 (void) strcpy(rcname, homedir);
3604 (void) strcat(rcname, TELNETRC_COMP);
3607 if ((rcfile = fopen(rcname, "r")) == NULL)
3608 goto cmdrc_exit;
3610 for (;;) {
3611 if (GetString(&line, &linesize, rcfile) == NULL) {
3612 if (!feof(rcfile)) {
3613 perror("telnet: error reading " TELNETRC_NAME);
3614 ret = 1;
3615 goto cmdrc_exit;
3617 break;
3619 if (line[0] == 0)
3620 continue;
3621 if (line[0] == '#')
3622 continue;
3623 if (gotmachine) {
3624 if (!isspace(line[0]))
3625 gotmachine = 0;
3627 if (gotmachine == 0) {
3628 if (isspace(line[0]))
3629 continue;
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]);
3636 else
3637 continue;
3638 if (line[0] != ' ' && line[0] != '\t' &&
3639 line[0] != '\n')
3640 continue;
3641 gotmachine = 1;
3643 makeargv();
3644 if (margv[0] == 0)
3645 continue;
3646 c = getcmd(margv[0]);
3647 if (Ambiguous(c)) {
3648 (void) printf("?Ambiguous command: %s\n", margv[0]);
3649 continue;
3651 if (c == 0) {
3652 (void) printf("?Invalid command: %s\n", margv[0]);
3653 continue;
3656 * This should never happen...
3658 if (c->needconnect && !connected) {
3659 (void) printf("?Need to be connected first for %s.\n",
3660 margv[0]);
3661 continue;
3663 (*c->handler)(margc, margv);
3665 cmdrc_exit:
3666 if (rcfile != NULL)
3667 (void) fclose(rcfile);
3668 doing_rc = 0;
3670 return (ret);