1 /*
2 * Copyright (c) 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
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.
20 *
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.
32 *
33 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
34 * Use is subject to license terms.
35 */
36
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>
42
43 #include <signal.h>
44 #include <netdb.h>
45 #include <ctype.h>
46 #include <pwd.h>
47 #include <errno.h>
48 #include <strings.h>
49
50 #include <arpa/telnet.h>
51 #include <arpa/inet.h>
52
53 #include "general.h"
54
55 #include "ring.h"
56
57 #include "externs.h"
58 #include "defines.h"
59 #include "types.h"
60
61 extern char *telnet_krb5_realm;
62 extern void krb5_profile_get_options(char *, char *,
63 profile_options_boolean*);
64
65 #include <k5-int.h>
66 #include <profile/prof_int.h>
67
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}
74 };
75
76 #include <netinet/ip.h>
77
78 /*
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.
81 */
82 #define MAX_GATEWAY 8
83 /*
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.
86 */
87 #define MAX_GATEWAY6 127
88 #define MAXMAX_GATEWAY MAX(MAX_GATEWAY, MAX_GATEWAY6)
89
90 /*
91 * Depending on the address resolutions of the target and gateways,
92 * we determine which addresses of the target we'll try connecting to.
93 */
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 */
97
98 #if defined(USE_TOS)
99 int tos = -1;
100 #endif
101
102 char *hostname;
103 static char _hostname[MAXHOSTNAMELEN];
104
105 static int send_tncmd(void (*func)(), char *, char *);
106 static void call(int n_ptrs, ...);
107 static int cmdrc(char *, char *);
108
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;
115
116 /*
117 * storage for IPv6 and/or IPv4 addresses of gateways
118 */
119 struct gateway {
120 struct in6_addr gw_addr6;
121 struct in_addr gw_addr;
122 };
123
124 /*
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.
130 */
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)];
137 };
138
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 */
145
146 static void
Close(int * fd)147 Close(int *fd)
148 {
149 if (*fd != -1) {
150 (void) close(*fd);
151 *fd = -1;
152 }
153 }
154
155 static void
Free(char ** p)156 Free(char **p)
157 {
158 if (*p != NULL) {
159 free(*p);
160 *p = NULL;
161 }
162 }
163
164 static void
FreeHostnameList(char * list[])165 FreeHostnameList(char *list[])
166 {
167 unsigned i;
168 for (i = 0; i <= MAXMAX_GATEWAY && list[i] != NULL; i++)
169 Free(&list[i]);
170 }
171
172 #define MARGV_CHUNK_SIZE 8
173
174 static void
set_argv(str)175 set_argv(str)
176 char *str;
177 {
178 if (margc == margvlen) {
179 char **newmargv;
180
181 margvlen += MARGV_CHUNK_SIZE;
182
183 if ((newmargv = realloc(margv, margvlen * sizeof (char *)))
184 == NULL)
185 ExitString("telnet: no space for arguments",
186 EXIT_FAILURE);
187
188 margv = newmargv;
189 }
190
191 margv[margc] = str;
192 if (str != NULL)
193 margc++;
194 }
195
196 static void
makeargv()197 makeargv()
198 {
199 char *cp, *cp2, c;
200 boolean_t shellcmd = B_FALSE;
201
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;
208 }
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);
216 /*
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.
221 */
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;
229 }
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;
242 }
243 *cp2++ = c;
244 }
245 *cp2 = '\0';
246 if (c == '\0')
247 break;
248 cp++;
249 }
250 set_argv((char *)NULL);
251 }
252
253 /*
254 * Make a character string into a number.
255 *
256 * Todo: 1. Could take random integers (12, 0x12, 012, 0b1).
257 */
258
259 static int
special(s)260 special(s)
261 register char *s;
262 {
263 register char c;
264 char b;
265
266 switch (*s) {
267 case '^':
268 b = *++s;
269 if (b == '?') {
270 c = b | 0x40; /* DEL */
271 } else {
272 c = b & 0x1f;
273 }
274 break;
275 default:
276 c = *s;
277 break;
278 }
279 return (c);
280 }
281
282 /*
283 * Construct a control character sequence
284 * for a special character.
285 */
286 static char *
control(c)287 control(c)
288 register cc_t c;
289 {
290 static char buf[5];
291 /*
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....
297 */
298 register unsigned int uic = (unsigned int)c;
299
300 if (uic == 0x7f)
301 return ("^?");
302 if (c == (cc_t)_POSIX_VDISABLE) {
303 return ("off");
304 }
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;
318 }
319 return (buf);
320 }
321
322 /*
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.
326 */
327 static char *
esc_control(c)328 esc_control(c)
329 register cc_t c;
330 {
331 static char buf[5];
332 /*
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....
338 */
339 register unsigned int uic = (unsigned int)c;
340
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;
358 }
359 return (buf);
360 }
361
362 /*
363 * The following are data structures and routines for
364 * the "send" command.
365 *
366 */
367
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) */
376 };
377
378
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 *);
385
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 }
415 };
416
417 #define GETSEND(name) ((struct sendlist *)genget(name, (char **)Sendlist, \
418 sizeof (struct sendlist)))
419
420 static int
sendcmd(argc,argv)421 sendcmd(argc, argv)
422 int argc;
423 char **argv;
424 {
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;
430
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);
436 }
437 /*
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).
442 */
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);
454 }
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);
461 }
462 count += s->nbyte;
463 if (s->handler == send_help) {
464 (void) send_help();
465 return (0);
466 }
467
468 i += s->narg;
469 needconnect += s->needconnect;
470 }
471 if (!connected && needconnect) {
472 (void) printf("?Need to be connected first.\n");
473 (void) printf("'send ?' for help\n");
474 return (0);
475 }
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);
486 }
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*/
495 }
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);
504 }
505 }
506 return (count == success);
507 }
508
509 static int
send_esc()510 send_esc()
511 {
512 NETADD(escape);
513 return (1);
514 }
515
516 static int
send_docmd(name)517 send_docmd(name)
518 char *name;
519 {
520 return (send_tncmd(send_do, "do", name));
521 }
522
523 static int
send_dontcmd(name)524 send_dontcmd(name)
525 char *name;
526 {
527 return (send_tncmd(send_dont, "dont", name));
528 }
529
530 static int
send_willcmd(name)531 send_willcmd(name)
532 char *name;
533 {
534 return (send_tncmd(send_will, "will", name));
535 }
536
537 static int
send_wontcmd(name)538 send_wontcmd(name)
539 char *name;
540 {
541 return (send_tncmd(send_wont, "wont", name));
542 }
543
544 int
545 send_tncmd(func, cmd, name)
546 void (*func)();
547 char *cmd, *name;
548 {
549 char **cpp;
550 extern char *telopts[];
551 register int val = 0;
552
553 if (isprefix(name, "help") || isprefix(name, "?")) {
554 register int col, len;
555
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");
559
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;
566 }
567 (void) printf(" \"%s\"", *cpp);
568 col += len;
569 }
570 (void) printf("\n");
571 return (0);
572 }
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);
579 }
580 if (cpp) {
581 val = cpp - telopts;
582 } else {
583 register char *cp = name;
584
585 while (*cp >= '0' && *cp <= '9') {
586 val *= 10;
587 val += *cp - '0';
588 cp++;
589 }
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);
600 }
601 }
602 if (!connected) {
603 (void) printf("?Need to be connected first.\n");
604 return (0);
605 }
606 (*func)(val, 1);
607 return (1);
608 }
609
610 static int
send_help()611 send_help()
612 {
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);
617 }
618 return (0);
619 }
620
621 /*
622 * The following are the routines and data structures referred
623 * to by the arguments to the "toggle" command.
624 */
625
626 static int
lclchars()627 lclchars()
628 {
629 donelclchars = 1;
630 return (1);
631 }
632
633 static int
togdebug()634 togdebug()
635 {
636 if (net > 0 &&
637 (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
638 perror("setsockopt (SO_DEBUG)");
639 }
640 return (1);
641 }
642
643
644 static int
togcrlf()645 togcrlf()
646 {
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");
653 }
654 return (1);
655 }
656
657 static int binmode;
658
659 static int
togbinary(val)660 togbinary(val)
661 int val;
662 {
663 donebinarytoggle = 1;
664
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;
674 }
675 val = binmode ? 0 : 1;
676 }
677
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);
687 }
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);
697 }
698 }
699 return (1);
700 }
701
702 static int
togrbinary(val)703 togrbinary(val)
704 int val;
705 {
706 donebinarytoggle = 1;
707
708 if (val == -1)
709 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
710
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);
717 }
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);
726 }
727 }
728 return (1);
729 }
730
731 static int
togxbinary(val)732 togxbinary(val)
733 int val;
734 {
735 donebinarytoggle = 1;
736
737 if (val == -1)
738 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
739
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);
746 }
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);
755 }
756 }
757 return (1);
758 }
759
760
761 static int togglehelp(void);
762 extern int auth_togdebug(int);
763
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;
770 };
771
772 static struct togglelist Togglelist[] = {
773 { "autoflush",
774 "flushing of output when sending interrupt characters",
775 0,
776 &autoflush,
777 "flush output when sending interrupt characters" },
778 { "autosynch",
779 "automatic sending of interrupt characters in urgent mode",
780 0,
781 &autosynch,
782 "send interrupt characters in urgent mode" },
783 { "autologin",
784 "automatic sending of login and/or authentication info",
785 0,
786 &autologin,
787 "send login name and/or authentication information" },
788 { "authdebug",
789 "authentication debugging",
790 auth_togdebug,
791 0,
792 "print authentication debugging information" },
793 { "autoencrypt",
794 "automatic encryption of data stream",
795 EncryptAutoEnc,
796 0,
797 "automatically encrypt output" },
798 { "autodecrypt",
799 "automatic decryption of data stream",
800 EncryptAutoDec,
801 0,
802 "automatically decrypt input" },
803 { "verbose_encrypt",
804 "verbose encryption output",
805 EncryptVerbose,
806 0,
807 "print verbose encryption output" },
808 { "encdebug",
809 "encryption debugging",
810 EncryptDebug,
811 0,
812 "print encryption debugging information" },
813 { "skiprc",
814 "don't read ~/.telnetrc file",
815 0,
816 &skiprc,
817 "skip reading of ~/.telnetrc file" },
818 { "binary",
819 "sending and receiving of binary data",
820 togbinary,
821 0,
822 0 },
823 { "inbinary",
824 "receiving of binary data",
825 togrbinary,
826 0,
827 0 },
828 { "outbinary",
829 "sending of binary data",
830 togxbinary,
831 0,
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",
840 0,
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)",
856 0,
857 &netdata,
858 "print hexadecimal representation of network traffic" },
859 { "prettydump",
860 "output of \"netdata\" to user readable format (debugging)",
861 0,
862 &prettydump,
863 "print user readable output for \"netdata\"" },
864 { "options",
865 "viewing of options processing (debugging)",
866 0,
867 &showoptions,
868 "show option processing" },
869 { "termdata",
870 "(debugging) toggle printing of hexadecimal terminal data",
871 0,
872 &termdata,
873 "print hexadecimal representation of terminal traffic" },
874 { "?",
875 0,
876 togglehelp },
877 { "help",
878 0,
879 togglehelp },
880 { 0 }
881 };
882
883 static int
togglehelp()884 togglehelp()
885 {
886 struct togglelist *c;
887
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");
895 }
896 }
897 (void) printf("\n");
898 (void) printf("%-15s %s\n", "?", "display help information");
899 return (0);
900 }
901
902 static void
settogglehelp(set)903 settogglehelp(set)
904 int set;
905 {
906 struct togglelist *c;
907
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");
915 }
916 }
917 }
918
919 #define GETTOGGLE(name) (struct togglelist *) \
920 genget(name, (char **)Togglelist, sizeof (struct togglelist))
921
922 static int
toggle(argc,argv)923 toggle(argc, argv)
924 int argc;
925 char *argv[];
926 {
927 int retval = 1;
928 char *name;
929 struct togglelist *c;
930
931 if (argc < 2) {
932 (void) fprintf(stderr,
933 "Need an argument to 'toggle' command. "
934 "'toggle ?' for help.\n");
935 return (0);
936 }
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);
957 }
958 }
959 if (c->handler) {
960 retval &= (*c->handler)(-1);
961 }
962 }
963 }
964 return (retval);
965 }
966
967 /*
968 * The following perform the "set" command.
969 */
970
971 #ifdef USE_TERMIO
972 struct termio new_tc = { 0 };
973 #endif
974
975 struct setlist {
976 char *name; /* name */
977 char *help; /* help information */
978 void (*handler)();
979 cc_t *charp; /* where it is located at */
980 };
981
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 }
1014 };
1015
1016 static struct setlist *
getset(name)1017 getset(name)
1018 char *name;
1019 {
1020 return ((struct setlist *)
1021 genget(name, (char **)Setlist, sizeof (struct setlist)));
1022 }
1023
1024 void
set_escape_char(s)1025 set_escape_char(s)
1026 char *s;
1027 {
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));
1036 }
1037 }
1038
1039 static int
setcmd(argc,argv)1040 setcmd(argc, argv)
1041 int argc;
1042 char *argv[];
1043 {
1044 int value;
1045 struct setlist *ct;
1046 struct togglelist *c;
1047
1048 if (argc < 2 || argc > 3) {
1049 (void) printf(
1050 "Format is 'set Name Value'\n'set ?' for help.\n");
1051 return (0);
1052 }
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);
1061 }
1062
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);
1074 }
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);
1085 }
1086 if (c->actionexplanation) {
1087 (void) printf("%s %s.\n",
1088 *c->variable? "Will" : "Won't",
1089 c->actionexplanation);
1090 }
1091 }
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;
1111 }
1112 *(ct->charp) = (cc_t)value;
1113 (void) printf("%s character is '%s'.\n", ct->name,
1114 control(*(ct->charp)));
1115 }
1116 slc_check();
1117 return (1);
1118 }
1119
1120 static int
unsetcmd(argc,argv)1121 unsetcmd(argc, argv)
1122 int argc;
1123 char *argv[];
1124 {
1125 struct setlist *ct;
1126 struct togglelist *c;
1127 register char *name;
1128
1129 if (argc < 2) {
1130 (void) fprintf(stderr, "Need an argument to 'unset' command. "
1131 "'unset ?' for help.\n");
1132 return (0);
1133 }
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);
1141 }
1142
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);
1159 }
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);
1166 }
1167 }
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)));
1182 }
1183 }
1184 return (1);
1185 }
1186
1187 /*
1188 * The following are the data structures and routines for the
1189 * 'mode' command.
1190 */
1191 extern int reqd_linemode;
1192
1193 #ifdef KLUDGELINEMODE
1194 extern int kludgelinemode;
1195
1196 static int
dokludgemode()1197 dokludgemode()
1198 {
1199 kludgelinemode = 1;
1200 send_wont(TELOPT_LINEMODE, 1);
1201 send_dont(TELOPT_SGA, 1);
1202 send_dont(TELOPT_ECHO, 1);
1203 /*
1204 * If processing the .telnetrc file, keep track of linemode and/or
1205 * kludgelinemode requests which are processed before initial option
1206 * negotiations occur.
1207 */
1208 if (doing_rc)
1209 reqd_linemode = 1;
1210 return (1);
1211 }
1212 #endif
1213
1214 static int
dolinemode()1215 dolinemode()
1216 {
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);
1223
1224 /*
1225 * If processing the .telnetrc file, keep track of linemode and/or
1226 * kludgelinemode requests which are processed before initial option
1227 * negotiations occur.
1228 */
1229 if (doing_rc)
1230 reqd_linemode = 1;
1231 return (1);
1232 }
1233
1234 static int
docharmode()1235 docharmode()
1236 {
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);
1246 }
1247
1248 static int
dolmmode(bit,on)1249 dolmmode(bit, on)
1250 int bit, on;
1251 {
1252 unsigned char c;
1253 extern int linemode;
1254
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);
1259 }
1260
1261 if (on)
1262 c = (linemode | bit);
1263 else
1264 c = (linemode & ~bit);
1265 lm_mode(&c, 1, 1);
1266 return (1);
1267 }
1268
1269 static int
setmode(bit)1270 setmode(bit)
1271 {
1272 return (dolmmode(bit, 1));
1273 }
1274
1275 static int
clearmode(bit)1276 clearmode(bit)
1277 {
1278 return (dolmmode(bit, 0));
1279 }
1280
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;
1287 };
1288
1289 static int modehelp();
1290
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 },
1324 };
1325
1326
1327 static int
modehelp()1328 modehelp()
1329 {
1330 struct modelist *mt;
1331
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");
1339 }
1340 }
1341 return (0);
1342 }
1343
1344 #define GETMODECMD(name) (struct modelist *) \
1345 genget(name, (char **)ModeList, sizeof (struct modelist))
1346
1347 static int
modecmd(argc,argv)1348 modecmd(argc, argv)
1349 int argc;
1350 char *argv[];
1351 {
1352 struct modelist *mt;
1353
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);
1368 }
1369 return (0);
1370 }
1371
1372 /*
1373 * The following data structures and routines implement the
1374 * "display" command.
1375 */
1376
1377 static int
display(argc,argv)1378 display(argc, argv)
1379 int argc;
1380 char *argv[];
1381 {
1382 struct togglelist *tl;
1383 struct setlist *sl;
1384
1385 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1386 if (*tl->variable) { \
1387 (void) printf("will"); \
1388 } else { \
1389 (void) printf("won't"); \
1390 } \
1391 (void) printf(" %s.\n", tl->actionexplanation); \
1392 }
1393
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); \
1401 }
1402
1403 if (argc == 1) {
1404 for (tl = Togglelist; tl->name; tl++) {
1405 dotog(tl);
1406 }
1407 (void) printf("\n");
1408 for (sl = Setlist; sl->name; sl++) {
1409 doset(sl);
1410 }
1411 } else {
1412 int i;
1413
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);
1428 }
1429 if (sl) {
1430 doset(sl);
1431 }
1432 }
1433 }
1434 }
1435 optionstatus();
1436 (void) EncryptStatus();
1437 return (1);
1438 #undef doset
1439 #undef dotog
1440 }
1441
1442 /*
1443 * The following are the data structures, and many of the routines,
1444 * relating to command processing.
1445 */
1446
1447 /*
1448 * Set the escape character.
1449 */
1450 static int
setescape(argc,argv)1451 setescape(argc, argv)
1452 int argc;
1453 char *argv[];
1454 {
1455 register char *arg;
1456 char *buf = NULL;
1457
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;
1466 }
1467 }
1468 arg = buf;
1469 }
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);
1477 }
1478
1479 /*ARGSUSED*/
1480 static int
togcrmod(argc,argv)1481 togcrmod(argc, argv)
1482 int argc;
1483 char *argv[];
1484 {
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);
1490 }
1491
1492 /*ARGSUSED*/
1493 static int
suspend(argc,argv)1494 suspend(argc, argv)
1495 int argc;
1496 char *argv[];
1497 {
1498 setcommandmode();
1499 {
1500 unsigned short oldrows, oldcols, newrows, newcols;
1501 int err;
1502
1503 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1504 (void) kill(0, SIGTSTP);
1505 /*
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.
1509 */
1510 if (TerminalWindowSize(&newrows, &newcols) && connected &&
1511 (err || ((oldrows != newrows) || (oldcols != newcols)))) {
1512 sendnaws();
1513 }
1514 }
1515 /* reget parameters in case they were changed */
1516 TerminalSaveState();
1517 setconnmode(0);
1518 return (1);
1519 }
1520
1521 /*ARGSUSED*/
1522 static int
shell(argc,argv)1523 shell(argc, argv)
1524 int argc;
1525 char *argv[];
1526 {
1527 unsigned short oldrows, oldcols, newrows, newcols;
1528 int err;
1529
1530 setcommandmode();
1531
1532 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1533 switch (vfork()) {
1534 case -1:
1535 perror("Fork failed\n");
1536 break;
1537
1538 case 0:
1539 {
1540 /*
1541 * Fire up the shell in the child.
1542 */
1543 register char *shellp, *shellname;
1544
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);
1558 }
1559 default:
1560 (void) wait((int *)0); /* Wait for the shell to complete */
1561
1562 if (TerminalWindowSize(&newrows, &newcols) && connected &&
1563 (err || ((oldrows != newrows) || (oldcols != newcols)))) {
1564 sendnaws();
1565 }
1566 break;
1567 }
1568 return (1);
1569 }
1570
1571 static int
bye(argc,argv)1572 bye(argc, argv)
1573 int argc; /* Number of arguments */
1574 char *argv[]; /* arguments */
1575 {
1576 extern int resettermname;
1577
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();
1587 }
1588 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
1589 longjmp(toplevel, 1);
1590 /* NOTREACHED */
1591 }
1592 return (1); /* Keep lint, etc., happy */
1593 }
1594
1595 /*VARARGS*/
1596 int
quit()1597 quit()
1598 {
1599 (void) call(3, bye, "bye", "fromquit");
1600 Exit(EXIT_SUCCESS);
1601 /*NOTREACHED*/
1602 return (1);
1603 }
1604
1605 /*ARGSUSED*/
1606 static int
logout(argc,argv)1607 logout(argc, argv)
1608 int argc;
1609 char *argv[];
1610 {
1611 send_do(TELOPT_LOGOUT, 1);
1612 (void) netflush();
1613 return (1);
1614 }
1615
1616
1617 /*
1618 * The SLC command.
1619 */
1620
1621 struct slclist {
1622 char *name;
1623 char *help;
1624 void (*handler)();
1625 int arg;
1626 };
1627
1628 static void slc_help();
1629
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 },
1640 };
1641
1642 static void
slc_help()1643 slc_help()
1644 {
1645 struct slclist *c;
1646
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");
1653 }
1654 }
1655 }
1656
1657 static struct slclist *
getslc(name)1658 getslc(name)
1659 char *name;
1660 {
1661 return ((struct slclist *)
1662 genget(name, (char **)SlcList, sizeof (struct slclist)));
1663 }
1664
1665 static int
slccmd(argc,argv)1666 slccmd(argc, argv)
1667 int argc;
1668 char *argv[];
1669 {
1670 struct slclist *c;
1671
1672 if (argc != 2) {
1673 (void) fprintf(stderr,
1674 "Need an argument to 'slc' command. 'slc ?' for help.\n");
1675 return (0);
1676 }
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);
1683 }
1684 if (Ambiguous(c)) {
1685 (void) fprintf(stderr,
1686 "'%s': ambiguous argument ('slc ?' for help).\n", argv[1]);
1687 return (0);
1688 }
1689 (*c->handler)(c->arg);
1690 slcstate();
1691 return (1);
1692 }
1693
1694 /*
1695 * The ENVIRON command.
1696 */
1697
1698 struct envlist {
1699 char *name;
1700 char *help;
1701 void (*handler)();
1702 int narg;
1703 };
1704
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);
1714
1715 static void env_help(void);
1716
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 },
1736 };
1737
1738 static void
env_help()1739 env_help()
1740 {
1741 struct envlist *c;
1742
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");
1749 }
1750 }
1751 }
1752
1753 static struct envlist *
getenvcmd(name)1754 getenvcmd(name)
1755 char *name;
1756 {
1757 return ((struct envlist *)
1758 genget(name, (char **)EnvList, sizeof (struct envlist)));
1759 }
1760
1761 static int
env_cmd(argc,argv)1762 env_cmd(argc, argv)
1763 int argc;
1764 char *argv[];
1765 {
1766 struct envlist *c;
1767
1768 if (argc < 2) {
1769 (void) fprintf(stderr,
1770 "Need an argument to 'environ' command. "
1771 "'environ ?' for help.\n");
1772 return (0);
1773 }
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);
1779 }
1780 if (Ambiguous(c)) {
1781 (void) fprintf(stderr, "'%s': ambiguous argument "
1782 "('environ ?' for help).\n", argv[1]);
1783 return (0);
1784 }
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);
1792 }
1793 (*c->handler)(argv[2], argv[3]);
1794 return (1);
1795 }
1796
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 */
1804 };
1805
1806 static struct env_lst envlisthead;
1807
1808 static struct env_lst *
env_find(var)1809 env_find(var)
1810 unsigned char *var;
1811 {
1812 register struct env_lst *ep;
1813
1814 for (ep = envlisthead.next; ep; ep = ep->next) {
1815 if (strcmp((char *)ep->var, (char *)var) == 0)
1816 return (ep);
1817 }
1818 return (NULL);
1819 }
1820
1821 int
env_init()1822 env_init()
1823 {
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;
1831
1832 for (epp = environ; *epp; epp++) {
1833 if (cp = strchr(*epp, '=')) {
1834 *cp = '\0';
1835
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 = '=';
1842 }
1843 }
1844 /*
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.
1848 */
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, ':');
1854
1855 if (gethostname(hbuf, MAXHOSTNAMELEN) == -1) {
1856 perror("telnet: cannot get hostname");
1857 return (0);
1858 }
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);
1864 }
1865 (void) sprintf((char *)cp, "%s%s", hbuf, cp2);
1866 free(ep->value);
1867 ep->value = (unsigned char *)cp;
1868 }
1869 /*
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.
1874 */
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");
1879 }
1880 env_export((unsigned char *)"DISPLAY");
1881 env_export((unsigned char *)"PRINTER");
1882
1883 return (1);
1884 }
1885
1886 static struct env_lst *
env_define(var,value)1887 env_define(var, value)
1888 unsigned char *var, *value;
1889 {
1890 unsigned char *tmp_value;
1891 unsigned char *tmp_var;
1892 struct env_lst *ep;
1893
1894 /*
1895 * Allocate copies of arguments first, to make cleanup easier
1896 * in the case of allocation errors.
1897 */
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);
1902 }
1903
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);
1909 }
1910
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);
1923 }
1924
1925 ep->next = envlisthead.next;
1926 envlisthead.next = ep;
1927 ep->prev = &envlisthead;
1928 if (ep->next)
1929 ep->next->prev = ep;
1930 }
1931 ep->welldefined = opt_welldefined((char *)var);
1932 ep->export = 1;
1933 ep->var = tmp_var;
1934 ep->value = tmp_value;
1935
1936 return (ep);
1937 }
1938
1939 static void
env_undefine(var)1940 env_undefine(var)
1941 unsigned char *var;
1942 {
1943 register struct env_lst *ep;
1944
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);
1954 }
1955 }
1956
1957 static void
env_export(var)1958 env_export(var)
1959 unsigned char *var;
1960 {
1961 register struct env_lst *ep;
1962
1963 if (ep = env_find(var))
1964 ep->export = 1;
1965 }
1966
1967 static void
env_unexport(var)1968 env_unexport(var)
1969 unsigned char *var;
1970 {
1971 register struct env_lst *ep;
1972
1973 if (ep = env_find(var))
1974 ep->export = 0;
1975 }
1976
1977 static void
env_send(var)1978 env_send(var)
1979 unsigned char *var;
1980 {
1981 register struct env_lst *ep;
1982
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;
1992 }
1993 ep = env_find(var);
1994 if (ep == 0) {
1995 (void) fprintf(stderr,
1996 "Cannot send '%s': variable not defined\n", var);
1997 return;
1998 }
1999 env_opt_start_info();
2000 env_opt_add(ep->var);
2001 env_opt_end(0);
2002 }
2003
2004 static void
env_list()2005 env_list()
2006 {
2007 register struct env_lst *ep;
2008
2009 for (ep = envlisthead.next; ep; ep = ep->next) {
2010 (void) printf("%c %-20s %s\n", ep->export ? '*' : ' ',
2011 ep->var, ep->value);
2012 }
2013 }
2014
2015 unsigned char *
env_default(init,welldefined)2016 env_default(init, welldefined)
2017 int init;
2018 {
2019 static struct env_lst *nep = NULL;
2020
2021 if (init) {
2022 /* return value is not used */
2023 nep = &envlisthead;
2024 return (NULL);
2025 }
2026 if (nep) {
2027 while ((nep = nep->next) != NULL) {
2028 if (nep->export && (nep->welldefined == welldefined))
2029 return (nep->var);
2030 }
2031 }
2032 return (NULL);
2033 }
2034
2035 unsigned char *
env_getvalue(var)2036 env_getvalue(var)
2037 unsigned char *var;
2038 {
2039 register struct env_lst *ep;
2040
2041 if (ep = env_find(var))
2042 return (ep->value);
2043 return (NULL);
2044 }
2045
2046 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
2047 static void
env_varval(what)2048 env_varval(what)
2049 unsigned char *what;
2050 {
2051 extern int old_env_var, old_env_value, env_auto;
2052 int len = strlen((char *)what);
2053
2054 if (len == 0)
2055 goto unknown;
2056
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");
2084 }
2085 }
2086 #endif /* OLD_ENVIRON && ENV_HACK */
2087
2088 /*
2089 * The AUTHENTICATE command.
2090 */
2091
2092 struct authlist {
2093 char *name;
2094 char *help;
2095 int (*handler)();
2096 int narg;
2097 };
2098
2099 extern int auth_enable(char *);
2100 extern int auth_disable(char *);
2101 extern int auth_status(void);
2102
2103 static int auth_help(void);
2104
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 },
2118 };
2119
2120 static int
auth_help(void)2121 auth_help(void)
2122 {
2123 struct authlist *c;
2124
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");
2131 }
2132 }
2133 return (0);
2134 }
2135
2136
2137 static int
auth_cmd(argc,argv)2138 auth_cmd(argc, argv)
2139 int argc;
2140 char *argv[];
2141 {
2142 struct authlist *c;
2143
2144 if (argc < 2) {
2145 (void) fprintf(stderr, "Need an argument to 'auth' "
2146 "command. 'auth ?' for help.\n");
2147 return (0);
2148 }
2149
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);
2157 }
2158 if (Ambiguous(c)) {
2159 (void) fprintf(stderr,
2160 "'%s': ambiguous argument ('auth ?' for help).\n", argv[1]);
2161 return (0);
2162 }
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);
2170 }
2171 return ((*c->handler)(argv[2], argv[3]));
2172 }
2173
2174 /*
2175 * The FORWARD command.
2176 */
2177
2178 extern int forward_flags;
2179
2180 struct forwlist {
2181 char *name;
2182 char *help;
2183 int (*handler)();
2184 int f_flags;
2185 };
2186
2187 static int forw_status(void);
2188 static int forw_set(int);
2189 static int forw_help(void);
2190
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",
2206 0,
2207 forw_help, 0},
2208 {"?",
2209 "Print help information",
2210 forw_help, 0},
2211 {0},
2212 };
2213
2214 static int
forw_status(void)2215 forw_status(void)
2216 {
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);
2228 }
2229
2230 static int
forw_set(int f_flags)2231 forw_set(int f_flags)
2232 {
2233 forward_flags = f_flags;
2234 return (0);
2235 }
2236
2237 static int
forw_help(void)2238 forw_help(void)
2239 {
2240 struct forwlist *c;
2241
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");
2248 }
2249 }
2250 return (0);
2251 }
2252
2253 static int
forw_cmd(int argc,char * argv[])2254 forw_cmd(int argc, char *argv[])
2255 {
2256 struct forwlist *c;
2257
2258 if (argc < 2) {
2259 (void) fprintf(stderr, gettext(
2260 "Need an argument to 'forward' "
2261 "command. 'forward ?' for help.\n"));
2262 return (0);
2263 }
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);
2271 }
2272 if (Ambiguous(c)) {
2273 (void) fprintf(stderr, gettext(
2274 "'%s': ambiguous argument ('forward ?' for help).\n"),
2275 argv[1]);
2276 return (0);
2277 }
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);
2283 }
2284 return ((*c->handler) (c->f_flags));
2285 }
2286
2287 /*
2288 * The ENCRYPT command.
2289 */
2290
2291 struct encryptlist {
2292 char *name;
2293 char *help;
2294 int (*handler)();
2295 int needconnect;
2296 int minarg;
2297 int maxarg;
2298 };
2299
2300 static int EncryptHelp(void);
2301
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 },
2321
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 },
2328 };
2329
2330 static int
EncryptHelp(void)2331 EncryptHelp(void)
2332 {
2333 struct encryptlist *c;
2334
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");
2341 }
2342 }
2343 return (0);
2344 }
2345
2346 static int
encrypt_cmd(int argc,char * argv[])2347 encrypt_cmd(int argc, char *argv[])
2348 {
2349 struct encryptlist *c;
2350
2351 if (argc < 2) {
2352 (void) fprintf(stderr, gettext(
2353 "Need an argument to 'encrypt' command. "
2354 "'encrypt ?' for help.\n"));
2355 return (0);
2356 }
2357
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);
2365 }
2366 if (Ambiguous(c)) {
2367 (void) fprintf(stderr, gettext(
2368 "'%s': ambiguous argument ('encrypt ?' for help).\n"),
2369 argv[1]);
2370 return (0);
2371 }
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);
2385 }
2386 (void) fprintf(stderr, gettext(
2387 "to 'encrypt %s' command. 'encrypt ?' for help.\n"),
2388 c->name);
2389 return (0);
2390 }
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);
2397 }
2398 }
2399 return ((*c->handler)(argc > 0 ? argv[2] : 0,
2400 argc > 1 ? argv[3] : 0, argc > 2 ? argv[4] : 0));
2401 }
2402
2403 /*
2404 * Print status about the connection.
2405 */
2406 static int
status(int argc,char * argv[])2407 status(int argc, char *argv[])
2408 {
2409 if (connected) {
2410 (void) printf("Connected to %s.\n", hostname);
2411 if ((argc < 2) || strcmp(argv[1], "notmuch")) {
2412 int mode = getconnmode();
2413
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");
2435 }
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");
2441
2442 encrypt_display();
2443 }
2444 } else {
2445 (void) printf("No connection.\n");
2446 }
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);
2454 }
2455
2456 /*
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.
2464 *
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)
2471 */
2472 static int
parse_input(char * cmd_line_input,char ** hostname_list,uchar_t * src_rtng_type)2473 parse_input(char *cmd_line_input, char **hostname_list, uchar_t *src_rtng_type)
2474 {
2475 char hname[MAXHOSTNAMELEN + 1];
2476 char *cp;
2477 int gw_count;
2478 int i;
2479
2480 gw_count = 0;
2481 cp = cmd_line_input;
2482
2483 /*
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.
2489 */
2490 #ifndef ICMD
2491 if (*cp == '@') {
2492 *src_rtng_type = IPOPT_LSRR;
2493 cp++;
2494 } else if (*cp == '!') {
2495 *src_rtng_type = IPOPT_SSRR;
2496
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);
2508 }
2509 return (0);
2510 #ifndef ICMD
2511 }
2512
2513 while (*cp != '\0') {
2514 /*
2515 * Identify each gateway separated by ",", "@" or ",@" and
2516 * store in hname[].
2517 */
2518 i = 0;
2519 while (*cp != '@' && *cp != ',' && *cp != '\0') {
2520 hname[i++] = *cp++;
2521 if (i > MAXHOSTNAMELEN)
2522 goto parse_error;
2523 }
2524 hname[i] = '\0';
2525
2526 /*
2527 * Two consecutive delimiters which result in a 0 length hname
2528 * is a parse error.
2529 */
2530 if (i == 0)
2531 goto parse_error;
2532
2533 hostname_list[gw_count] = strdup(hname);
2534 if (hostname_list[gw_count] == NULL) {
2535 perror("telnet: copying hostname from list");
2536 return (-1);
2537 }
2538
2539 if (++gw_count > MAXMAX_GATEWAY) {
2540 (void) fprintf(stderr, "telnet: too many gateways\n");
2541 return (-1);
2542 }
2543
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++;
2551 }
2552 }
2553
2554 /* discount the target */
2555 gw_count--;
2556
2557 /* Any input starting with '!@' or '@' must have at least one gateway */
2558 if (gw_count <= 0)
2559 goto parse_error;
2560
2561 return (gw_count);
2562
2563 parse_error:
2564 (void) printf("Bad source route option: %s\n", cmd_line_input);
2565 return (-1);
2566 #endif /* ICMD */
2567 }
2568
2569 /*
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.
2572 *
2573 * Returns: pointer to resolved target if name resolutions succeed
2574 * NULL if name resolutions fail or
2575 * a library function call fails
2576 *
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.
2582 */
2583 static struct addrinfo *
resolve_hosts(char ** hostname_list,int num_gw,struct gateway ** gw_addrsp,int * addr_type,const char * portp)2584 resolve_hosts(char **hostname_list, int num_gw, struct gateway **gw_addrsp,
2585 int *addr_type, const char *portp)
2586 {
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;
2605
2606 *addr_type = ALL_ADDRS;
2607
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);
2619 }
2620
2621 /*
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.
2625 */
2626 for (host = res; host != NULL; host = host->ai_next) {
2627 struct sockaddr_in6 *s6;
2628
2629 s6 = (struct sockaddr_in6 *)host->ai_addr;
2630
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;
2636
2637 /*
2638 * Let's stop after seeing we need both IPv6 and IPv4.
2639 */
2640 if (need_v4_addr && need_v6_addr)
2641 break;
2642 }
2643
2644 if (num_gw > 0) {
2645 /*
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.
2649 */
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);
2655 }
2656 }
2657
2658 /*
2659 * Now we'll go through all the gateways and try to resolve them to
2660 * the desired address types.
2661 */
2662 gw = gw_addrs;
2663
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);
2676 }
2677
2678 /*
2679 * Initially we have no address of any type for this gateway.
2680 */
2681 got_v6_addr = B_FALSE;
2682 got_v4_addr = B_FALSE;
2683
2684 /*
2685 * Let's go through all the addresses of this gateway.
2686 * Use the first address which matches the needed family.
2687 */
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;
2694
2695 if (addr->ai_family == AF_INET6)
2696 is_v4mapped = IN6_IS_ADDR_V4MAPPED(v6addrp);
2697 else
2698 is_v4mapped = B_FALSE;
2699
2700 /*
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!
2704 */
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;
2713 }
2714 }
2715
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;
2720 }
2721
2722 /*
2723 * Let's stop if we got all what we looked for.
2724 */
2725 if ((!need_v4_addr || got_v4_addr) &&
2726 (!need_v6_addr || got_v6_addr))
2727 break;
2728 }
2729
2730 /*
2731 * We needed an IPv4 address for this gateway but couldn't
2732 * find one.
2733 */
2734 if (need_v4_addr && !got_v4_addr) {
2735 res_failed_at4 = i;
2736 /*
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.
2740 */
2741 need_v4_addr = B_FALSE;
2742 }
2743
2744 if (need_v6_addr && !got_v6_addr) {
2745 res_failed_at6 = i;
2746 need_v6_addr = B_FALSE;
2747 }
2748
2749 /*
2750 * If some gateways don't resolve to any of the desired
2751 * address types, we fail.
2752 */
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]);
2758 }
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]);
2763 }
2764 free(gw_addrs);
2765 return (NULL);
2766 }
2767
2768 gw++;
2769 }
2770
2771 *gw_addrsp = gw_addrs;
2772
2773 /*
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.
2776 */
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;
2783
2784 return (res);
2785 }
2786
2787
2788 /*
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.
2797 */
2798 static boolean_t
prepare_optbuf(struct gateway * gw_addrs,int num_gw,char ** opt_bufpp,size_t * opt_buf_len,struct in_addr * target,uchar_t src_rtng_type)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)
2801 {
2802 struct ip_sourceroute *sr_opt;
2803 size_t needed_buflen;
2804 int i;
2805
2806 /*
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)
2815 */
2816 needed_buflen = 1 + 3 + (num_gw + 1) * sizeof (struct in_addr);
2817
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);
2825 }
2826 } else {
2827 *opt_bufpp = malloc(needed_buflen);
2828 if (*opt_bufpp == NULL) {
2829 perror("telnet: malloc");
2830 return (B_FALSE);
2831 }
2832 }
2833
2834 *opt_buf_len = needed_buflen;
2835
2836 /* final hop is the target */
2837 gw_addrs[num_gw].gw_addr = *target;
2838
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;
2846
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));
2851 }
2852
2853 return (B_TRUE);
2854 }
2855
2856 /*
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.
2864 */
2865 static boolean_t
prepare_optbuf6(struct gateway * gw_addrs,int num_gw,char ** opt_bufpp,size_t * opt_buf_len)2866 prepare_optbuf6(struct gateway *gw_addrs, int num_gw, char **opt_bufpp,
2867 size_t *opt_buf_len)
2868 {
2869 char *opt_bufp;
2870 size_t needed_buflen;
2871 int i;
2872
2873 needed_buflen = inet6_rth_space(IPV6_RTHDR_TYPE_0, num_gw);
2874
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);
2882 }
2883 } else {
2884 *opt_bufpp = malloc(needed_buflen);
2885 if (*opt_bufpp == NULL) {
2886 perror("telnet: malloc");
2887 return (B_FALSE);
2888 }
2889 }
2890 *opt_buf_len = needed_buflen;
2891 opt_bufp = *opt_bufpp;
2892
2893 /*
2894 * Initialize the buffer to be used for IPv6 routing header type 0.
2895 */
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);
2900 }
2901
2902 /*
2903 * Add gateways one by one.
2904 */
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);
2909 }
2910 }
2911
2912 /* successful operation */
2913 return (B_TRUE);
2914 }
2915
2916 int
tn(argc,argv)2917 tn(argc, argv)
2918 int argc;
2919 char *argv[];
2920 {
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 */
2945 /*
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.
2949 */
2950 char buf[MAXHOSTNAMELEN+40];
2951 /*
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.
2955 */
2956 unsigned short target_port;
2957 char abuf[INET6_ADDRSTRLEN];
2958 int num_gw;
2959 int ret_val;
2960 boolean_t is_v4mapped;
2961 /*
2962 * Type of addresses we'll try to connect to (ALL_ADDRS, ONLY_V6,
2963 * ONLY_V4).
2964 */
2965 int addr_type;
2966
2967 /* clear the socket address prior to use */
2968 (void) memset(&sin6, '\0', sizeof (sin6));
2969 sin6.sin6_family = AF_INET6;
2970
2971 (void) memset(&sin, '\0', sizeof (sin));
2972 sin.sin_family = AF_INET;
2973
2974 if (connected) {
2975 (void) printf("?Already connected to %s\n", hostname);
2976 return (0);
2977 }
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;
2983 }
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;
2992 }
2993 }
2994 makeargv();
2995 argc = margc;
2996 argv = margv;
2997 }
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;
3010 }
3011 if (strcmp(*argv, "-a") == 0) {
3012 --argc; ++argv;
3013 autologin = autologin_set = 1;
3014 continue;
3015 }
3016 if (hostp == 0) {
3017 hostp = *argv++;
3018 --argc;
3019 continue;
3020 }
3021 if (portp == 0) {
3022 portp = *argv++;
3023 --argc;
3024 /*
3025 * Do we treat this like a telnet port or raw?
3026 */
3027 if (*portp == '-') {
3028 portp++;
3029 telnetport = 1;
3030 } else
3031 telnetport = 0;
3032 continue;
3033 }
3034 usage:
3035 (void) printf(
3036 "usage: %s [-l user] [-a] host-name [port]\n", cmd);
3037 goto tn_exit;
3038 }
3039 if (hostp == 0)
3040 goto usage;
3041
3042 #ifdef ICMD
3043 /*
3044 * For setup phase treat the relay host as the target host.
3045 */
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;
3052 }
3053
3054 /* Last host in the hostname_list is the target */
3055 hostp = hostname_list[num_gw];
3056
3057 host = resolve_hosts(hostname_list, num_gw, &gw_addrs, &addr_type,
3058 portp);
3059 if (host == NULL) {
3060 goto tn_exit;
3061 }
3062
3063 /*
3064 * Check if number of gateways is less than max. available
3065 */
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;
3070 }
3071
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;
3076 }
3077
3078 /*
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.
3085 */
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));
3097 }
3098 hostname = _hostname;
3099
3100 if (portp == NULL) {
3101 telnetport = 1;
3102 }
3103
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;
3109 }
3110
3111 #ifdef ICMD
3112 /*
3113 * Since we pass the port number as an ascii string to the proxy,
3114 * we need it in host format.
3115 */
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;
3122 }
3123 target_port = sp->s_port;
3124 #endif
3125 h = host;
3126
3127 /*
3128 * For IPv6 source routing, we need to initialize option buffer only
3129 * once.
3130 */
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;
3135 }
3136 }
3137
3138 /*
3139 * We procure the Kerberos config files options only
3140 * if the user has choosen Krb5 authentication.
3141 */
3142 if (krb5auth_flag > 0) {
3143 krb5_profile_get_options(hostname, telnet_krb5_realm,
3144 config_file_options);
3145 }
3146
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);
3159 }
3160 }
3161
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);
3167 }
3168 if (forwardable_flag) {
3169 forward_flags |= OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS;
3170 } else if (forward_flag)
3171 forward_flags |= OPTS_FORWARD_CREDS;
3172
3173
3174 do {
3175 /*
3176 * Search for an address of desired type in the IP address list
3177 * of the target.
3178 */
3179 while (h != NULL) {
3180 struct sockaddr_in6 *addr;
3181
3182 addr = (struct sockaddr_in6 *)h->ai_addr;
3183
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;
3189
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;
3196
3197 /* skip undesired typed addresses */
3198 h = h->ai_next;
3199 }
3200
3201 if (h == NULL) {
3202 fprintf(stderr,
3203 "telnet: Unable to connect to remote host");
3204 goto tn_exit;
3205 }
3206
3207 /*
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.
3211 */
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;
3221 }
3222
3223 (void) printf("Trying %s...\n", inet_ntop(h->ai_family,
3224 addrp, abuf, sizeof (abuf)));
3225
3226 net = socket(h->ai_family, SOCK_STREAM, 0);
3227
3228 if (net < 0) {
3229 perror("telnet: socket");
3230 goto tn_exit;
3231 }
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;
3238 }
3239
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)");
3247 }
3248 }
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)");
3259 }
3260 #endif /* defined(USE_TOS) */
3261
3262 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
3263 perror("setsockopt (SO_DEBUG)");
3264 }
3265
3266 ret_val = connect(net, h->ai_addr, h->ai_addrlen);
3267
3268 /*
3269 * If failed, try the next address of the target.
3270 */
3271 if (ret_val < 0) {
3272 Close(&net);
3273 if (h->ai_next != NULL) {
3274
3275 int oerrno = errno;
3276
3277 (void) fprintf(stderr,
3278 "telnet: connect to address %s: ", abuf);
3279 errno = oerrno;
3280 perror((char *)0);
3281
3282 h = h->ai_next;
3283 continue;
3284 }
3285 perror("telnet: Unable to connect to remote host");
3286 goto tn_exit;
3287 }
3288 connected++;
3289 } while (connected == 0);
3290 freeaddrinfo(host);
3291 host = NULL;
3292 #ifdef ICMD
3293 /*
3294 * Do initial protocol to connect to farther end...
3295 */
3296 {
3297 char buf[1024];
3298 (void) sprintf(buf, "%s %d\n", real_host, (int)dest_port);
3299 write(net, buf, strlen(buf));
3300 }
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;
3307
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;
3316 }
3317 }
3318
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);
3329
3330 /* NOTREACHED */
3331 }
3332 }
3333 (void) call(3, status, "status", "notmuch");
3334 if (setjmp(peerdied) == 0)
3335 telnet(user);
3336
3337 Close(&net);
3338
3339 (void) snprintf(buf, sizeof (buf),
3340 "Connection to %.*s closed by foreign host.\n",
3341 MAXHOSTNAMELEN, hostname);
3342 ExitString(buf, EXIT_FAILURE);
3343
3344 /*NOTREACHED*/
3345
3346 tn_exit:
3347 FreeHostnameList(hostname_list);
3348 Close(&net);
3349 connected = 0;
3350 if (host != NULL)
3351 freeaddrinfo(host);
3352 return (0);
3353 }
3354
3355 #define HELPINDENT (sizeof ("connect"))
3356
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)";
3383
3384 static int help();
3385
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 },
3406 0
3407 };
3408
3409
3410 static Command cmdtab2[] = {
3411 { "help", 0, help, 0 },
3412 { "escape", 0, setescape, 0 },
3413 { "crmod", 0, togcrmod, 0 },
3414 0
3415 };
3416
3417
3418 /*
3419 * Call routine with argc, argv set from args.
3420 * Uses /usr/include/stdarg.h
3421 */
3422 #define MAXVARGS 100
3423 /*VARARGS1*/
3424 static void
call(int n_ptrs,...)3425 call(int n_ptrs, ...)
3426 {
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;
3432
3433 if (n_ptrs > MAXVARGS)
3434 n_ptrs = MAXVARGS;
3435 va_start(ap, n_ptrs);
3436
3437 routine = (va_arg(ap, intrtn_t)); /* extract the routine's name */
3438 n_ptrs--;
3439
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);
3444
3445 (*routine)(argno, args);
3446 }
3447
3448
3449 static Command *
getcmd(name)3450 getcmd(name)
3451 char *name;
3452 {
3453 Command *cm;
3454
3455 if (cm = (Command *) genget(name, (char **)cmdtab, sizeof (Command)))
3456 return (cm);
3457 return (Command *) genget(name, (char **)cmdtab2, sizeof (Command));
3458 }
3459
3460 void
command(top,tbuf,cnt)3461 command(top, tbuf, cnt)
3462 int top;
3463 char *tbuf;
3464 int cnt;
3465 {
3466 Command *c;
3467
3468 setcommandmode();
3469 if (!top) {
3470 (void) putchar('\n');
3471 } else {
3472 (void) signal(SIGINT, SIG_DFL);
3473 (void) signal(SIGQUIT, SIG_DFL);
3474 }
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;
3501 }
3502 }
3503 if (line[0] == 0)
3504 break;
3505 makeargv();
3506 if (margv[0] == 0) {
3507 break;
3508 }
3509 c = getcmd(margv[0]);
3510 if (Ambiguous(c)) {
3511 (void) printf("?Ambiguous command\n");
3512 continue;
3513 }
3514 if (c == 0) {
3515 (void) printf("?Invalid command\n");
3516 continue;
3517 }
3518 if (c->needconnect && !connected) {
3519 (void) printf("?Need to be connected first.\n");
3520 continue;
3521 }
3522 if ((*c->handler)(margc, margv)) {
3523 break;
3524 }
3525 }
3526 command_exit:
3527 if (!top) {
3528 if (!connected) {
3529 longjmp(toplevel, 1);
3530 /*NOTREACHED*/
3531 }
3532 setconnmode(0);
3533 }
3534 }
3535
3536 /*
3537 * Help command.
3538 */
3539 static int
help(argc,argv)3540 help(argc, argv)
3541 int argc;
3542 char *argv[];
3543 {
3544 register Command *c;
3545
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);
3553 }
3554 (void) printf("<return>\tleave command mode\n");
3555 return (0);
3556 }
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);
3569 }
3570 }
3571 return (0);
3572 }
3573
3574 static char *rcname = NULL;
3575 #define TELNETRC_NAME "telnetrc"
3576 #define TELNETRC_COMP "/." TELNETRC_NAME
3577
3578 static int
cmdrc(char * m1,char * m2)3579 cmdrc(char *m1, char *m2)
3580 {
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";
3589
3590 if (skiprc)
3591 goto cmdrc_exit;
3592
3593 doing_rc = 1;
3594
3595 (void) strlcpy(m1save, m1, sizeof (m1save));
3596 m1 = m1save;
3597
3598 if (rcname == NULL) {
3599 char *homedir;
3600 unsigned rcbuflen;
3601
3602 if ((homedir = getenv("HOME")) == NULL)
3603 homedir = "";
3604
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;
3610 }
3611 (void) strcpy(rcname, homedir);
3612 (void) strcat(rcname, TELNETRC_COMP);
3613 }
3614
3615 if ((rcfile = fopen(rcname, "r")) == NULL)
3616 goto cmdrc_exit;
3617
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;
3624 }
3625 break;
3626 }
3627 if (line[0] == 0)
3628 continue;
3629 if (line[0] == '#')
3630 continue;
3631 if (gotmachine) {
3632 if (!isspace(line[0]))
3633 gotmachine = 0;
3634 }
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;
3650 }
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;
3658 }
3659 if (c == 0) {
3660 (void) printf("?Invalid command: %s\n", margv[0]);
3661 continue;
3662 }
3663 /*
3664 * This should never happen...
3665 */
3666 if (c->needconnect && !connected) {
3667 (void) printf("?Need to be connected first for %s.\n",
3668 margv[0]);
3669 continue;
3670 }
3671 (*c->handler)(margc, margv);
3672 }
3673 cmdrc_exit:
3674 if (rcfile != NULL)
3675 (void) fclose(rcfile);
3676 doing_rc = 0;
3677
3678 return (ret);
3679 }
3680