8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / cmd-inet / usr.bin / telnet / commands.c
blobfe7a2f4b09374f809322dd8c196990b5912f2b4a
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((char *)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 #ifdef lint
1825 char **environ = NULL;
1826 #else /* lint */
1827 extern char **environ;
1828 #endif /* lint */
1829 char **epp, *cp;
1830 struct env_lst *ep;
1832 for (epp = environ; *epp; epp++) {
1833 if (cp = strchr(*epp, '=')) {
1834 *cp = '\0';
1836 ep = env_define((unsigned char *)*epp,
1837 (unsigned char *)cp+1);
1838 if (ep == NULL)
1839 return (0);
1840 ep->export = 0;
1841 *cp = '=';
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
1847 * hostname.
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");
1857 return (0);
1859 hbuf[MAXHOSTNAMELEN-1] = '\0';
1860 cp = malloc(strlen(hbuf) + strlen(cp2) + 1);
1861 if (cp == NULL) {
1862 perror("telnet: cannot define DISPLAY variable");
1863 return (0);
1865 (void) sprintf((char *)cp, "%s%s", hbuf, cp2);
1866 free(ep->value);
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");
1883 return (1);
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;
1892 struct env_lst *ep;
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");
1901 return (NULL);
1904 tmp_value = (unsigned char *)strdup((char *)value);
1905 if (tmp_value == NULL) {
1906 free(tmp_var);
1907 perror("telnet: can't copy environment variable value");
1908 return (NULL);
1911 if (ep = env_find(var)) {
1912 if (ep->var)
1913 free(ep->var);
1914 if (ep->value)
1915 free(ep->value);
1916 } else {
1917 ep = malloc(sizeof (struct env_lst));
1918 if (ep == NULL) {
1919 perror("telnet: can't define environment variable");
1920 free(tmp_var);
1921 free(tmp_value);
1922 return (NULL);
1925 ep->next = envlisthead.next;
1926 envlisthead.next = ep;
1927 ep->prev = &envlisthead;
1928 if (ep->next)
1929 ep->next->prev = ep;
1931 ep->welldefined = opt_welldefined((char *)var);
1932 ep->export = 1;
1933 ep->var = tmp_var;
1934 ep->value = tmp_value;
1936 return (ep);
1939 static void
1940 env_undefine(var)
1941 unsigned char *var;
1943 register struct env_lst *ep;
1945 if (ep = env_find(var)) {
1946 ep->prev->next = ep->next;
1947 if (ep->next)
1948 ep->next->prev = ep->prev;
1949 if (ep->var)
1950 free(ep->var);
1951 if (ep->value)
1952 free(ep->value);
1953 free(ep);
1957 static void
1958 env_export(var)
1959 unsigned char *var;
1961 register struct env_lst *ep;
1963 if (ep = env_find(var))
1964 ep->export = 1;
1967 static void
1968 env_unexport(var)
1969 unsigned char *var;
1971 register struct env_lst *ep;
1973 if (ep = env_find(var))
1974 ep->export = 0;
1977 static void
1978 env_send(var)
1979 unsigned char *var;
1981 register struct env_lst *ep;
1983 if (my_state_is_wont(TELOPT_NEW_ENVIRON)
1984 #ifdef OLD_ENVIRON
1985 /* old style */ && my_state_is_wont(TELOPT_OLD_ENVIRON)
1986 #endif
1987 /* no environ */) {
1988 (void) fprintf(stderr,
1989 "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1990 var);
1991 return;
1993 ep = env_find(var);
1994 if (ep == 0) {
1995 (void) fprintf(stderr,
1996 "Cannot send '%s': variable not defined\n", var);
1997 return;
1999 env_opt_start_info();
2000 env_opt_add(ep->var);
2001 env_opt_end(0);
2004 static void
2005 env_list()
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);
2015 unsigned char *
2016 env_default(init, welldefined)
2017 int init;
2019 static struct env_lst *nep = NULL;
2021 if (init) {
2022 /* return value is not used */
2023 nep = &envlisthead;
2024 return (NULL);
2026 if (nep) {
2027 while ((nep = nep->next) != NULL) {
2028 if (nep->export && (nep->welldefined == welldefined))
2029 return (nep->var);
2032 return (NULL);
2035 unsigned char *
2036 env_getvalue(var)
2037 unsigned char *var;
2039 register struct env_lst *ep;
2041 if (ep = env_find(var))
2042 return (ep->value);
2043 return (NULL);
2046 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
2047 static void
2048 env_varval(what)
2049 unsigned char *what;
2051 extern int old_env_var, old_env_value, env_auto;
2052 int len = strlen((char *)what);
2054 if (len == 0)
2055 goto unknown;
2057 if (strncasecmp((char *)what, "status", len) == 0) {
2058 if (env_auto)
2059 (void) printf("%s%s", "VAR and VALUE are/will be ",
2060 "determined automatically\n");
2061 if (old_env_var == OLD_ENV_VAR)
2062 (void) printf(
2063 "VAR and VALUE set to correct definitions\n");
2064 else
2065 (void) printf(
2066 "VAR and VALUE definitions are reversed\n");
2067 } else if (strncasecmp((char *)what, "auto", len) == 0) {
2068 env_auto = 1;
2069 old_env_var = OLD_ENV_VALUE;
2070 old_env_value = OLD_ENV_VAR;
2071 } else if (strncasecmp((char *)what, "right", len) == 0) {
2072 env_auto = 0;
2073 old_env_var = OLD_ENV_VAR;
2074 old_env_value = OLD_ENV_VALUE;
2075 } else if (strncasecmp((char *)what, "wrong", len) == 0) {
2076 env_auto = 0;
2077 old_env_var = OLD_ENV_VALUE;
2078 old_env_value = OLD_ENV_VAR;
2079 } else {
2080 unknown:
2081 (void) printf(
2082 "Unknown \"varval\" command. (\"auto\", \"right\", "
2083 "\"wrong\", \"status\")\n");
2086 #endif /* OLD_ENVIRON && ENV_HACK */
2089 * The AUTHENTICATE command.
2092 struct authlist {
2093 char *name;
2094 char *help;
2095 int (*handler)();
2096 int narg;
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[] = {
2106 { "status",
2107 "Display current status of authentication information",
2108 auth_status, 0 },
2109 { "disable",
2110 "Disable an authentication type ('auth disable ?' for more)",
2111 auth_disable, 1 },
2112 { "enable",
2113 "Enable an authentication type ('auth enable ?' for more)",
2114 auth_enable, 1 },
2115 { "help", 0, auth_help, 0 },
2116 { "?", "Print help information", auth_help, 0 },
2117 { 0 },
2120 static int
2121 auth_help(void)
2123 struct authlist *c;
2125 for (c = AuthList; c->name; c++) {
2126 if (c->help) {
2127 if (*c->help)
2128 (void) printf("%-15s %s\n", c->name, c->help);
2129 else
2130 (void) printf("\n");
2133 return (0);
2137 static int
2138 auth_cmd(argc, argv)
2139 int argc;
2140 char *argv[];
2142 struct authlist *c;
2144 if (argc < 2) {
2145 (void) fprintf(stderr, "Need an argument to 'auth' "
2146 "command. 'auth ?' for help.\n");
2147 return (0);
2150 c = (struct authlist *)
2151 genget(argv[1], (char **)AuthList, sizeof (struct authlist));
2152 if (c == 0) {
2153 (void) fprintf(stderr,
2154 "'%s': unknown argument ('auth ?' for help).\n",
2155 argv[1]);
2156 return (0);
2158 if (Ambiguous(c)) {
2159 (void) fprintf(stderr,
2160 "'%s': ambiguous argument ('auth ?' for help).\n", argv[1]);
2161 return (0);
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);
2169 return (0);
2171 return ((*c->handler)(argv[2], argv[3]));
2175 * The FORWARD command.
2178 extern int forward_flags;
2180 struct forwlist {
2181 char *name;
2182 char *help;
2183 int (*handler)();
2184 int f_flags;
2187 static int forw_status(void);
2188 static int forw_set(int);
2189 static int forw_help(void);
2191 static struct forwlist ForwList[] = {
2192 {"status",
2193 "Display current status of credential forwarding",
2194 forw_status, 0},
2195 {"disable",
2196 "Disable credential forwarding",
2197 forw_set, 0},
2198 {"enable",
2199 "Enable credential forwarding",
2200 forw_set, OPTS_FORWARD_CREDS},
2201 {"forwardable",
2202 "Enable credential forwarding of "
2203 "forwardable credentials",
2204 forw_set, OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS},
2205 {"help",
2207 forw_help, 0},
2208 {"?",
2209 "Print help information",
2210 forw_help, 0},
2211 {0},
2214 static int
2215 forw_status(void)
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"));
2222 else
2223 (void) printf(gettext(
2224 "Credential forwarding enabled\n"));
2225 } else
2226 (void) printf(gettext("Credential forwarding disabled\n"));
2227 return (0);
2230 static int
2231 forw_set(int f_flags)
2233 forward_flags = f_flags;
2234 return (0);
2237 static int
2238 forw_help(void)
2240 struct forwlist *c;
2242 for (c = ForwList; c->name; c++) {
2243 if (c->help) {
2244 if (*c->help)
2245 (void) printf("%-15s %s\r\n", c->name, c->help);
2246 else
2247 (void) printf("\n");
2250 return (0);
2253 static int
2254 forw_cmd(int argc, char *argv[])
2256 struct forwlist *c;
2258 if (argc < 2) {
2259 (void) fprintf(stderr, gettext(
2260 "Need an argument to 'forward' "
2261 "command. 'forward ?' for help.\n"));
2262 return (0);
2264 c = (struct forwlist *)genget(argv[1], (char **)ForwList,
2265 sizeof (struct forwlist));
2266 if (c == 0) {
2267 (void) fprintf(stderr, gettext(
2268 "'%s': unknown argument ('forward ?' for help).\n"),
2269 argv[1]);
2270 return (0);
2272 if (Ambiguous(c)) {
2273 (void) fprintf(stderr, gettext(
2274 "'%s': ambiguous argument ('forward ?' for help).\n"),
2275 argv[1]);
2276 return (0);
2278 if (argc != 2) {
2279 (void) fprintf(stderr, gettext(
2280 "No arguments needed to 'forward %s' command. "
2281 "'forward ?' for help.\n"), c->name);
2282 return (0);
2284 return ((*c->handler) (c->f_flags));
2288 * The ENCRYPT command.
2291 struct encryptlist {
2292 char *name;
2293 char *help;
2294 int (*handler)();
2295 int needconnect;
2296 int minarg;
2297 int maxarg;
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 },
2324 { "help", 0,
2325 EncryptHelp, 0, 0, 0 },
2326 { "?", "Print help information", EncryptHelp, 0, 0, 0 },
2327 { 0 },
2330 static int
2331 EncryptHelp(void)
2333 struct encryptlist *c;
2335 for (c = EncryptList; c->name; c++) {
2336 if (c->help) {
2337 if (*c->help)
2338 (void) printf("%-15s %s\n", c->name, c->help);
2339 else
2340 (void) printf("\n");
2343 return (0);
2346 static int
2347 encrypt_cmd(int argc, char *argv[])
2349 struct encryptlist *c;
2351 if (argc < 2) {
2352 (void) fprintf(stderr, gettext(
2353 "Need an argument to 'encrypt' command. "
2354 "'encrypt ?' for help.\n"));
2355 return (0);
2358 c = (struct encryptlist *)
2359 genget(argv[1], (char **)EncryptList, sizeof (struct encryptlist));
2360 if (c == 0) {
2361 (void) fprintf(stderr, gettext(
2362 "'%s': unknown argument ('encrypt ?' for help).\n"),
2363 argv[1]);
2364 return (0);
2366 if (Ambiguous(c)) {
2367 (void) fprintf(stderr, gettext(
2368 "'%s': ambiguous argument ('encrypt ?' for help).\n"),
2369 argv[1]);
2370 return (0);
2372 argc -= 2;
2373 if (argc < c->minarg || argc > c->maxarg) {
2374 if (c->minarg == c->maxarg) {
2375 (void) fprintf(stderr, gettext("Need %s%d %s "),
2376 c->minarg < argc ?
2377 gettext("only ") : "", c->minarg,
2378 c->minarg == 1 ?
2379 gettext("argument") : gettext("arguments"));
2380 } else {
2381 (void) fprintf(stderr,
2382 gettext("Need %s%d-%d arguments "),
2383 c->maxarg < argc ?
2384 gettext("only ") : "", c->minarg, c->maxarg);
2386 (void) fprintf(stderr, gettext(
2387 "to 'encrypt %s' command. 'encrypt ?' for help.\n"),
2388 c->name);
2389 return (0);
2391 if (c->needconnect && !connected) {
2392 if (!(argc &&
2393 (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
2394 (void) printf(
2395 gettext("?Need to be connected first.\n"));
2396 return (0);
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.
2406 static int
2407 status(int argc, char *argv[])
2409 if (connected) {
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)) {
2415 (void) printf(
2416 "Operating with LINEMODE option\n");
2417 (void) printf(
2418 "%s line editing\n", (mode&MODE_EDIT) ?
2419 "Local" : "No");
2420 (void) printf("%s catching of signals\n",
2421 (mode&MODE_TRAPSIG) ? "Local" : "No");
2422 slcstate();
2423 #ifdef KLUDGELINEMODE
2424 } else if (kludgelinemode &&
2425 my_want_state_is_dont(TELOPT_SGA)) {
2426 (void) printf(
2427 "Operating in obsolete linemode\n");
2428 #endif
2429 } else {
2430 (void) printf(
2431 "Operating in single character mode\n");
2432 if (localchars)
2433 (void) printf(
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");
2442 encrypt_display();
2444 } else {
2445 (void) printf("No connection.\n");
2447 if (rlogin != _POSIX_VDISABLE)
2448 (void) printf("Escape character is '%s'.\n", control(rlogin));
2449 else
2450 (void) printf(
2451 "Escape character is '%s'.\n", esc_control(escape));
2452 (void) fflush(stdout);
2453 return (1);
2457 * Parse the user input (cmd_line_input) which should:
2458 * - start with the target host, or with "@" or "!@" followed by at least one
2459 * gateway.
2460 * - each host (can be literal address or hostname) can be separated by ",",
2461 * "@", or ",@".
2462 * Note that the last host is the target, all the others (if any ) are the
2463 * gateways.
2465 * Returns: -1 if a library call fails, too many gateways, or parse
2466 * error
2467 * num_gw otherwise
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)
2472 static int
2473 parse_input(char *cmd_line_input, char **hostname_list, uchar_t *src_rtng_type)
2475 char hname[MAXHOSTNAMELEN + 1];
2476 char *cp;
2477 int gw_count;
2478 int i;
2480 gw_count = 0;
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.
2490 #ifndef ICMD
2491 if (*cp == '@') {
2492 *src_rtng_type = IPOPT_LSRR;
2493 cp++;
2494 } else if (*cp == '!') {
2495 *src_rtng_type = IPOPT_SSRR;
2497 /* "!" must be followed by '@' */
2498 if (*(cp + 1) != '@')
2499 goto parse_error;
2500 cp += 2;
2501 } else {
2502 #endif /* ICMD */
2503 /* no gateways, just the target */
2504 hostname_list[0] = strdup(cp);
2505 if (hostname_list[0] == NULL) {
2506 perror("telnet: copying host name");
2507 return (-1);
2509 return (0);
2510 #ifndef ICMD
2513 while (*cp != '\0') {
2515 * Identify each gateway separated by ",", "@" or ",@" and
2516 * store in hname[].
2518 i = 0;
2519 while (*cp != '@' && *cp != ',' && *cp != '\0') {
2520 hname[i++] = *cp++;
2521 if (i > MAXHOSTNAMELEN)
2522 goto parse_error;
2524 hname[i] = '\0';
2527 * Two consecutive delimiters which result in a 0 length hname
2528 * is a parse error.
2530 if (i == 0)
2531 goto parse_error;
2533 hostname_list[gw_count] = strdup(hname);
2534 if (hostname_list[gw_count] == NULL) {
2535 perror("telnet: copying hostname from list");
2536 return (-1);
2539 if (++gw_count > MAXMAX_GATEWAY) {
2540 (void) fprintf(stderr, "telnet: too many gateways\n");
2541 return (-1);
2544 /* Jump over the next delimiter. */
2545 if (*cp != '\0') {
2546 /* ...gw1,@gw2... accepted */
2547 if (*cp == ',' && *(cp + 1) == '@')
2548 cp += 2;
2549 else
2550 cp++;
2554 /* discount the target */
2555 gw_count--;
2557 /* Any input starting with '!@' or '@' must have at least one gateway */
2558 if (gw_count <= 0)
2559 goto parse_error;
2561 return (gw_count);
2563 parse_error:
2564 (void) printf("Bad source route option: %s\n", cmd_line_input);
2565 return (-1);
2566 #endif /* ICMD */
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;
2588 struct gateway *gw;
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 */
2596 int res_failed_at6;
2597 boolean_t is_v4mapped;
2598 struct in6_addr *v6addrp;
2599 struct in_addr *v4addrp;
2600 int error_num;
2601 int i;
2602 int rc;
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);
2613 if (rc != 0) {
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));
2618 return (NULL);
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
2624 * later.
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;
2634 else
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)
2641 break;
2644 if (num_gw > 0) {
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");
2653 freeaddrinfo(res);
2654 return (NULL);
2659 * Now we'll go through all the gateways and try to resolve them to
2660 * the desired address types.
2662 gw = gw_addrs;
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);
2669 if (rc != 0) {
2670 if (hostname_list[i] != NULL &&
2671 *hostname_list[i] != '\0')
2672 (void) fprintf(stderr, "%s: ",
2673 hostname_list[i]);
2674 (void) fprintf(stderr, "bad address\n");
2675 return (NULL);
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) {
2689 /*LINTED*/
2690 v6addrp = &((struct sockaddr_in6 *)addr->ai_addr)->
2691 sin6_addr;
2692 v4addrp = &((struct sockaddr_in *)addr->ai_addr)->
2693 sin_addr;
2695 if (addr->ai_family == AF_INET6)
2696 is_v4mapped = IN6_IS_ADDR_V4MAPPED(v6addrp);
2697 else
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,
2703 * then bingo!
2705 if (need_v4_addr && !got_v4_addr) {
2706 if (is_v4mapped) {
2707 IN6_V4MAPPED_TO_INADDR(v6addrp,
2708 &gw->gw_addr);
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))
2727 break;
2731 * We needed an IPv4 address for this gateway but couldn't
2732 * find one.
2734 if (need_v4_addr && !got_v4_addr) {
2735 res_failed_at4 = i;
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) {
2745 res_failed_at6 = i;
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]);
2764 free(gw_addrs);
2765 return (NULL);
2768 gw++;
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;
2784 return (res);
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
2792 * enough.
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.
2798 static boolean_t
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;
2804 int i;
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
2809 * address.
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 "
2823 "option\n");
2824 return (B_FALSE);
2826 } else {
2827 *opt_bufpp = malloc(needed_buflen);
2828 if (*opt_bufpp == NULL) {
2829 perror("telnet: malloc");
2830 return (B_FALSE);
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));
2853 return (B_TRUE);
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.
2865 static boolean_t
2866 prepare_optbuf6(struct gateway *gw_addrs, int num_gw, char **opt_bufpp,
2867 size_t *opt_buf_len)
2869 char *opt_bufp;
2870 size_t needed_buflen;
2871 int i;
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 "
2880 "header option\n");
2881 return (B_FALSE);
2883 } else {
2884 *opt_bufpp = malloc(needed_buflen);
2885 if (*opt_bufpp == NULL) {
2886 perror("telnet: malloc");
2887 return (B_FALSE);
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,
2897 num_gw) == NULL) {
2898 perror("telnet: inet6_rth_init");
2899 return (B_FALSE);
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");
2908 return (B_FALSE);
2912 /* successful operation */
2913 return (B_TRUE);
2917 tn(argc, argv)
2918 int argc;
2919 char *argv[];
2921 struct addrinfo *host = NULL;
2922 struct addrinfo *h;
2923 struct sockaddr_in6 sin6;
2924 struct sockaddr_in sin;
2925 struct in6_addr addr6;
2926 struct in_addr addr;
2927 void *addrp;
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;
2936 char *cmd;
2937 char *hostp = NULL;
2938 char *portp = NULL;
2939 char *user = NULL;
2940 #ifdef ICMD
2941 char *itelnet_host;
2942 char *real_host;
2943 unsigned short dest_port;
2944 #endif /* ICMD */
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];
2958 int num_gw;
2959 int ret_val;
2960 boolean_t is_v4mapped;
2962 * Type of addresses we'll try to connect to (ALL_ADDRS, ONLY_V6,
2963 * ONLY_V4).
2965 int addr_type;
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;
2974 if (connected) {
2975 (void) printf("?Already connected to %s\n", hostname);
2976 return (0);
2978 #ifdef ICMD
2979 itelnet_host = getenv("INTERNET_HOST");
2980 if (itelnet_host == NULL || itelnet_host[0] == '\0') {
2981 (void) printf("INTERNET_HOST environment variable undefined\n");
2982 goto tn_exit;
2984 #endif
2985 if (argc < 2) {
2986 (void) printf("(to) ");
2987 if (GetAndAppendString(&line, &linesize, "open ",
2988 stdin) == NULL) {
2989 if (!feof(stdin)) {
2990 perror("telnet");
2991 goto tn_exit;
2994 makeargv();
2995 argc = margc;
2996 argv = margv;
2998 cmd = *argv;
2999 --argc; ++argv;
3000 while (argc) {
3001 if (isprefix(*argv, "help") == 4 || isprefix(*argv, "?") == 1)
3002 goto usage;
3003 if (strcmp(*argv, "-l") == 0) {
3004 --argc; ++argv;
3005 if (argc == 0)
3006 goto usage;
3007 user = *argv++;
3008 --argc;
3009 continue;
3011 if (strcmp(*argv, "-a") == 0) {
3012 --argc; ++argv;
3013 autologin = autologin_set = 1;
3014 continue;
3016 if (hostp == 0) {
3017 hostp = *argv++;
3018 --argc;
3019 continue;
3021 if (portp == 0) {
3022 portp = *argv++;
3023 --argc;
3025 * Do we treat this like a telnet port or raw?
3027 if (*portp == '-') {
3028 portp++;
3029 telnetport = 1;
3030 } else
3031 telnetport = 0;
3032 continue;
3034 usage:
3035 (void) printf(
3036 "usage: %s [-l user] [-a] host-name [port]\n", cmd);
3037 goto tn_exit;
3039 if (hostp == 0)
3040 goto usage;
3042 #ifdef ICMD
3044 * For setup phase treat the relay host as the target host.
3046 real_host = hostp;
3047 hostp = itelnet_host;
3048 #endif
3049 num_gw = parse_input(hostp, hostname_list, &src_rtng_type);
3050 if (num_gw < 0) {
3051 goto tn_exit;
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,
3058 portp);
3059 if (host == NULL) {
3060 goto tn_exit;
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");
3069 goto tn_exit;
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");
3075 goto tn_exit;
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
3084 * address.
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));
3094 } else {
3095 (void) strlcpy(_hostname, host->ai_canonname,
3096 sizeof (_hostname));
3098 hostname = _hostname;
3100 if (portp == NULL) {
3101 telnetport = 1;
3104 if (host->ai_family == AF_INET) {
3105 target_port = ((struct sockaddr_in *)(host->ai_addr))->sin_port;
3106 } else {
3107 target_port = ((struct sockaddr_in6 *)(host->ai_addr))
3108 ->sin6_port;
3111 #ifdef ICMD
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");
3118 if (sp == 0) {
3119 (void) fprintf(stderr,
3120 "telnet: tcp/telnet-passthru: unknown service\n");
3121 goto tn_exit;
3123 target_port = sp->s_port;
3124 #endif
3125 h = host;
3128 * For IPv6 source routing, we need to initialize option buffer only
3129 * once.
3131 if (num_gw > 0 && (addr_type == ALL_ADDRS || addr_type == ONLY_V6)) {
3132 if (!prepare_optbuf6(gw_addrs, num_gw, &opt_buf6,
3133 &opt_buf_len6)) {
3134 goto tn_exit;
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);
3147 if (encrypt_flag) {
3148 extern boolean_t auth_enable_encrypt;
3149 if (krb5_privacy_allowed()) {
3150 encrypt_auto(1);
3151 decrypt_auto(1);
3152 wantencryption = B_TRUE;
3153 autologin = 1;
3154 auth_enable_encrypt = B_TRUE;
3155 } else {
3156 (void) fprintf(stderr, gettext(
3157 "%s:Encryption not supported.\n"), prompt);
3158 exit(1);
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"));
3166 exit(1);
3168 if (forwardable_flag) {
3169 forward_flags |= OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS;
3170 } else if (forward_flag)
3171 forward_flags |= OPTS_FORWARD_CREDS;
3174 do {
3176 * Search for an address of desired type in the IP address list
3177 * of the target.
3179 while (h != NULL) {
3180 struct sockaddr_in6 *addr;
3182 addr = (struct sockaddr_in6 *)h->ai_addr;
3184 if (h->ai_family == AF_INET6)
3185 is_v4mapped =
3186 IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr);
3187 else
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)))
3195 break;
3197 /* skip undesired typed addresses */
3198 h = h->ai_next;
3201 if (h == NULL) {
3202 fprintf(stderr,
3203 "telnet: Unable to connect to remote host");
3204 goto tn_exit;
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 =
3215 target_port;
3216 } else {
3217 addrp = &((struct sockaddr_in6 *)(h->ai_addr))
3218 ->sin6_addr;
3219 ((struct sockaddr_in6 *)(h->ai_addr))->sin6_port =
3220 target_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);
3228 if (net < 0) {
3229 perror("telnet: socket");
3230 goto tn_exit;
3232 #ifndef ICMD
3233 if (num_gw > 0) {
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)) {
3237 goto tn_exit;
3240 if (setsockopt(net, IPPROTO_IP, IP_OPTIONS,
3241 opt_buf, opt_buf_len) < 0)
3242 perror("setsockopt (IP_OPTIONS)");
3243 } else {
3244 if (setsockopt(net, IPPROTO_IPV6, IPV6_RTHDR,
3245 opt_buf6, opt_buf_len6) < 0)
3246 perror("setsockopt (IPV6_RTHDR)");
3249 #endif
3250 #if defined(USE_TOS)
3251 if (is_v4mapped) {
3252 if (tos < 0)
3253 tos = 020; /* Low Delay bit */
3254 if (tos &&
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.
3271 if (ret_val < 0) {
3272 Close(&net);
3273 if (h->ai_next != NULL) {
3275 int oerrno = errno;
3277 (void) fprintf(stderr,
3278 "telnet: connect to address %s: ", abuf);
3279 errno = oerrno;
3280 perror((char *)0);
3282 h = h->ai_next;
3283 continue;
3285 perror("telnet: Unable to connect to remote host");
3286 goto tn_exit;
3288 connected++;
3289 } while (connected == 0);
3290 freeaddrinfo(host);
3291 host = NULL;
3292 #ifdef ICMD
3294 * Do initial protocol to connect to farther end...
3297 char buf[1024];
3298 (void) sprintf(buf, "%s %d\n", real_host, (int)dest_port);
3299 write(net, buf, strlen(buf));
3301 #endif
3302 if (cmdrc(hostp, hostname) != 0)
3303 goto tn_exit;
3304 FreeHostnameList(hostname_list);
3305 if (autologin && user == NULL) {
3306 struct passwd *pw;
3308 user = getenv("LOGNAME");
3309 if (user == NULL ||
3310 ((pw = getpwnam(user)) != NULL) &&
3311 pw->pw_uid != getuid()) {
3312 if (pw = getpwuid(getuid()))
3313 user = pw->pw_name;
3314 else
3315 user = NULL;
3319 if (user) {
3320 if (env_define((unsigned char *)"USER", (unsigned char *)user))
3321 env_export((unsigned char *)"USER");
3322 else {
3323 /* Clean up and exit. */
3324 Close(&net);
3325 (void) snprintf(buf, sizeof (buf),
3326 "Connection to %.*s closed.\n",
3327 MAXHOSTNAMELEN, hostname);
3328 ExitString(buf, EXIT_FAILURE);
3330 /* NOTREACHED */
3333 (void) call(3, status, "status", "notmuch");
3334 if (setjmp(peerdied) == 0)
3335 telnet(user);
3337 Close(&net);
3339 (void) snprintf(buf, sizeof (buf),
3340 "Connection to %.*s closed by foreign host.\n",
3341 MAXHOSTNAMELEN, hostname);
3342 ExitString(buf, EXIT_FAILURE);
3344 /*NOTREACHED*/
3346 tn_exit:
3347 FreeHostnameList(hostname_list);
3348 Close(&net);
3349 connected = 0;
3350 if (host != NULL)
3351 freeaddrinfo(host);
3352 return (0);
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)";
3384 static int help();
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
3423 /*VARARGS1*/
3424 static void
3425 call(int n_ptrs, ...)
3427 va_list ap;
3428 typedef int (*intrtn_t)();
3429 intrtn_t routine;
3430 char *args[MAXVARGS+1]; /* leave 1 for trailing NULL */
3431 int argno = 0;
3433 if (n_ptrs > MAXVARGS)
3434 n_ptrs = MAXVARGS;
3435 va_start(ap, n_ptrs);
3437 routine = (va_arg(ap, intrtn_t)); /* extract the routine's name */
3438 n_ptrs--;
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 */
3443 va_end(ap);
3445 (*routine)(argno, args);
3449 static Command *
3450 getcmd(name)
3451 char *name;
3453 Command *cm;
3455 if (cm = (Command *) genget(name, (char **)cmdtab, sizeof (Command)))
3456 return (cm);
3457 return (Command *) genget(name, (char **)cmdtab2, sizeof (Command));
3460 void
3461 command(top, tbuf, cnt)
3462 int top;
3463 char *tbuf;
3464 int cnt;
3466 Command *c;
3468 setcommandmode();
3469 if (!top) {
3470 (void) putchar('\n');
3471 } else {
3472 (void) signal(SIGINT, SIG_DFL);
3473 (void) signal(SIGQUIT, SIG_DFL);
3475 for (;;) {
3476 if (rlogin == _POSIX_VDISABLE)
3477 (void) printf("%s> ", prompt);
3478 if (tbuf) {
3479 char *cp;
3480 if (AllocStringBuffer(&line, &linesize, cnt) == NULL)
3481 goto command_exit;
3482 cp = line;
3483 while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
3484 cnt--;
3485 tbuf = 0;
3486 if (cp == line || *--cp != '\n' || cp == line)
3487 goto getline;
3488 *cp = '\0';
3489 if (rlogin == _POSIX_VDISABLE)
3490 (void) printf("%s\n", line);
3491 } else {
3492 getline:
3493 if (rlogin != _POSIX_VDISABLE)
3494 (void) printf("%s> ", prompt);
3495 if (GetString(&line, &linesize, stdin) == NULL) {
3496 if (!feof(stdin))
3497 perror("telnet");
3498 (void) quit();
3499 /*NOTREACHED*/
3500 break;
3503 if (line[0] == 0)
3504 break;
3505 makeargv();
3506 if (margv[0] == 0) {
3507 break;
3509 c = getcmd(margv[0]);
3510 if (Ambiguous(c)) {
3511 (void) printf("?Ambiguous command\n");
3512 continue;
3514 if (c == 0) {
3515 (void) printf("?Invalid command\n");
3516 continue;
3518 if (c->needconnect && !connected) {
3519 (void) printf("?Need to be connected first.\n");
3520 continue;
3522 if ((*c->handler)(margc, margv)) {
3523 break;
3526 command_exit:
3527 if (!top) {
3528 if (!connected) {
3529 longjmp(toplevel, 1);
3530 /*NOTREACHED*/
3532 setconnmode(0);
3537 * Help command.
3539 static int
3540 help(argc, argv)
3541 int argc;
3542 char *argv[];
3544 register Command *c;
3546 if (argc == 1) {
3547 (void) printf(
3548 "Commands may be abbreviated. Commands are:\n\n");
3549 for (c = cmdtab; c->name; c++)
3550 if (c->help) {
3551 (void) printf("%-*s\t%s\n", HELPINDENT,
3552 c->name, c->help);
3554 (void) printf("<return>\tleave command mode\n");
3555 return (0);
3557 while (--argc > 0) {
3558 register char *arg;
3559 arg = *++argv;
3560 c = getcmd(arg);
3561 if (Ambiguous(c))
3562 (void) printf("?Ambiguous help command %s\n", arg);
3563 else if (c == (Command *)0)
3564 (void) printf("?Invalid help command %s\n", arg);
3565 else if (c->help) {
3566 (void) printf("%s\n", c->help);
3567 } else {
3568 (void) printf("No additional help on %s\n", arg);
3571 return (0);
3574 static char *rcname = NULL;
3575 #define TELNETRC_NAME "telnetrc"
3576 #define TELNETRC_COMP "/." TELNETRC_NAME
3578 static int
3579 cmdrc(char *m1, char *m2)
3581 Command *c;
3582 FILE *rcfile = NULL;
3583 int gotmachine = 0;
3584 int l1 = strlen(m1);
3585 int l2 = strlen(m2);
3586 char m1save[MAXHOSTNAMELEN];
3587 int ret = 0;
3588 char def[] = "DEFAULT";
3590 if (skiprc)
3591 goto cmdrc_exit;
3593 doing_rc = 1;
3595 (void) strlcpy(m1save, m1, sizeof (m1save));
3596 m1 = m1save;
3598 if (rcname == NULL) {
3599 char *homedir;
3600 unsigned rcbuflen;
3602 if ((homedir = getenv("HOME")) == NULL)
3603 homedir = "";
3605 rcbuflen = strlen(homedir) + strlen(TELNETRC_COMP) + 1;
3606 if ((rcname = malloc(rcbuflen)) == NULL) {
3607 perror("telnet: can't process " TELNETRC_NAME);
3608 ret = 1;
3609 goto cmdrc_exit;
3611 (void) strcpy(rcname, homedir);
3612 (void) strcat(rcname, TELNETRC_COMP);
3615 if ((rcfile = fopen(rcname, "r")) == NULL)
3616 goto cmdrc_exit;
3618 for (;;) {
3619 if (GetString(&line, &linesize, rcfile) == NULL) {
3620 if (!feof(rcfile)) {
3621 perror("telnet: error reading " TELNETRC_NAME);
3622 ret = 1;
3623 goto cmdrc_exit;
3625 break;
3627 if (line[0] == 0)
3628 continue;
3629 if (line[0] == '#')
3630 continue;
3631 if (gotmachine) {
3632 if (!isspace(line[0]))
3633 gotmachine = 0;
3635 if (gotmachine == 0) {
3636 if (isspace(line[0]))
3637 continue;
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]);
3644 else
3645 continue;
3646 if (line[0] != ' ' && line[0] != '\t' &&
3647 line[0] != '\n')
3648 continue;
3649 gotmachine = 1;
3651 makeargv();
3652 if (margv[0] == 0)
3653 continue;
3654 c = getcmd(margv[0]);
3655 if (Ambiguous(c)) {
3656 (void) printf("?Ambiguous command: %s\n", margv[0]);
3657 continue;
3659 if (c == 0) {
3660 (void) printf("?Invalid command: %s\n", margv[0]);
3661 continue;
3664 * This should never happen...
3666 if (c->needconnect && !connected) {
3667 (void) printf("?Need to be connected first for %s.\n",
3668 margv[0]);
3669 continue;
3671 (*c->handler)(margc, margv);
3673 cmdrc_exit:
3674 if (rcfile != NULL)
3675 (void) fclose(rcfile);
3676 doing_rc = 0;
3678 return (ret);