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 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(char * s)260 special(char *s)
261 {
262 char c;
263 char b;
264
265 switch (*s) {
266 case '^':
267 b = *++s;
268 if (b == '?') {
269 c = b | 0x40; /* DEL */
270 } else {
271 c = b & 0x1f;
272 }
273 break;
274 default:
275 c = *s;
276 break;
277 }
278 return (c);
279 }
280
281 /*
282 * Construct a control character sequence
283 * for a special character.
284 */
285 static char *
control(cc_t c)286 control(cc_t c)
287 {
288 static char buf[5];
289 /*
290 * The only way I could get the Sun 3.5 compiler
291 * to shut up about
292 * if ((unsigned int)c >= 0x80)
293 * was to assign "c" to an unsigned int variable...
294 * Arggg....
295 */
296 unsigned int uic = (unsigned int)c;
297
298 if (uic == 0x7f)
299 return ("^?");
300 if (c == (cc_t)_POSIX_VDISABLE) {
301 return ("off");
302 }
303 if (uic >= 0x80) {
304 buf[0] = '\\';
305 buf[1] = ((c>>6)&07) + '0';
306 buf[2] = ((c>>3)&07) + '0';
307 buf[3] = (c&07) + '0';
308 buf[4] = 0;
309 } else if (uic >= 0x20) {
310 buf[0] = c;
311 buf[1] = 0;
312 } else {
313 buf[0] = '^';
314 buf[1] = '@'+c;
315 buf[2] = 0;
316 }
317 return (buf);
318 }
319
320 /*
321 * Same as control() except that its only used for escape handling, which uses
322 * _POSIX_VDISABLE differently and is aided by the use of the state variable
323 * escape_valid.
324 */
325 static char *
esc_control(cc_t c)326 esc_control(cc_t c)
327 {
328 static char buf[5];
329 /*
330 * The only way I could get the Sun 3.5 compiler
331 * to shut up about
332 * if ((unsigned int)c >= 0x80)
333 * was to assign "c" to an unsigned int variable...
334 * Arggg....
335 */
336 unsigned int uic = (unsigned int)c;
337
338 if (escape_valid == B_FALSE)
339 return ("off");
340 if (uic == 0x7f)
341 return ("^?");
342 if (uic >= 0x80) {
343 buf[0] = '\\';
344 buf[1] = ((c>>6)&07) + '0';
345 buf[2] = ((c>>3)&07) + '0';
346 buf[3] = (c&07) + '0';
347 buf[4] = 0;
348 } else if (uic >= 0x20) {
349 buf[0] = c;
350 buf[1] = 0;
351 } else {
352 buf[0] = '^';
353 buf[1] = '@'+c;
354 buf[2] = 0;
355 }
356 return (buf);
357 }
358
359 /*
360 * The following are data structures and routines for
361 * the "send" command.
362 *
363 */
364
365 struct sendlist {
366 char *name; /* How user refers to it (case independent) */
367 char *help; /* Help information (0 ==> no help) */
368 int needconnect; /* Need to be connected */
369 int narg; /* Number of arguments */
370 int (*handler)(); /* Routine to perform (for special ops) */
371 int nbyte; /* Number of bytes to send this command */
372 int what; /* Character to be sent (<0 ==> special) */
373 };
374
375
376 static int send_esc(void);
377 static int send_help(void);
378 static int send_docmd(char *);
379 static int send_dontcmd(char *);
380 static int send_willcmd(char *);
381 static int send_wontcmd(char *);
382
383 static struct sendlist Sendlist[] = {
384 { "ao", "Send Telnet Abort output", 1, 0, 0, 2, AO },
385 { "ayt", "Send Telnet 'Are You There'", 1, 0, 0, 2, AYT },
386 { "b", 0, 1, 0, 0, 2, BREAK },
387 { "br", 0, 1, 0, 0, 2, BREAK },
388 { "break", 0, 1, 0, 0, 2, BREAK },
389 { "brk", "Send Telnet Break", 1, 0, 0, 2, BREAK },
390 { "ec", "Send Telnet Erase Character", 1, 0, 0, 2, EC },
391 { "el", "Send Telnet Erase Line", 1, 0, 0, 2, EL },
392 { "escape", "Send current escape character", 1, 0, send_esc, 1, 0 },
393 { "ga", "Send Telnet 'Go Ahead' sequence", 1, 0, 0, 2, GA },
394 { "ip", "Send Telnet Interrupt Process", 1, 0, 0, 2, IP },
395 { "intp", 0, 1, 0, 0, 2, IP },
396 { "interrupt", 0, 1, 0, 0, 2, IP },
397 { "intr", 0, 1, 0, 0, 2, IP },
398 { "nop", "Send Telnet 'No operation'", 1, 0, 0, 2, NOP },
399 { "eor", "Send Telnet 'End of Record'", 1, 0, 0, 2, EOR },
400 { "abort", "Send Telnet 'Abort Process'", 1, 0, 0, 2, ABORT },
401 { "susp", "Send Telnet 'Suspend Process'", 1, 0, 0, 2, SUSP },
402 { "eof", "Send Telnet End of File Character", 1, 0, 0, 2, xEOF },
403 { "synch", "Perform Telnet 'Synch operation'", 1, 0, dosynch, 2, 0 },
404 { "getstatus", "Send request for STATUS", 1, 0, get_status, 6, 0 },
405 { "?", "Display send options", 0, 0, send_help, 0, 0 },
406 { "help", 0, 0, 0, send_help, 0, 0 },
407 { "do", 0, 0, 1, send_docmd, 3, 0 },
408 { "dont", 0, 0, 1, send_dontcmd, 3, 0 },
409 { "will", 0, 0, 1, send_willcmd, 3, 0 },
410 { "wont", 0, 0, 1, send_wontcmd, 3, 0 },
411 { 0 }
412 };
413
414 #define GETSEND(name) ((struct sendlist *)genget(name, (char **)Sendlist, \
415 sizeof (struct sendlist)))
416
417 static int
sendcmd(argc,argv)418 sendcmd(argc, argv)
419 int argc;
420 char **argv;
421 {
422 int count; /* how many bytes we are going to need to send */
423 int i;
424 struct sendlist *s; /* pointer to current command */
425 int success = 0;
426 int needconnect = 0;
427
428 if (argc < 2) {
429 (void) printf(
430 "need at least one argument for 'send' command\n");
431 (void) printf("'send ?' for help\n");
432 return (0);
433 }
434 /*
435 * First, validate all the send arguments.
436 * In addition, we see how much space we are going to need, and
437 * whether or not we will be doing a "SYNCH" operation (which
438 * flushes the network queue).
439 */
440 count = 0;
441 for (i = 1; i < argc; i++) {
442 s = GETSEND(argv[i]);
443 if (s == 0) {
444 (void) printf("Unknown send argument '%s'\n'send ?' "
445 "for help.\n", argv[i]);
446 return (0);
447 } else if (Ambiguous(s)) {
448 (void) printf("Ambiguous send argument '%s'\n'send ?' "
449 "for help.\n", argv[i]);
450 return (0);
451 }
452 if (i + s->narg >= argc) {
453 (void) fprintf(stderr,
454 "Need %d argument%s to 'send %s' "
455 "command. 'send %s ?' for help.\n",
456 s->narg, s->narg == 1 ? "" : "s", s->name, s->name);
457 return (0);
458 }
459 count += s->nbyte;
460 if (s->handler == send_help) {
461 (void) send_help();
462 return (0);
463 }
464
465 i += s->narg;
466 needconnect += s->needconnect;
467 }
468 if (!connected && needconnect) {
469 (void) printf("?Need to be connected first.\n");
470 (void) printf("'send ?' for help\n");
471 return (0);
472 }
473 /* Now, do we have enough room? */
474 if (NETROOM() < count) {
475 (void) printf("There is not enough room in the buffer "
476 "TO the network\n");
477 (void) printf(
478 "to process your request. Nothing will be done.\n");
479 (void) printf("('send synch' will throw away most "
480 "data in the network\n");
481 (void) printf("buffer, if this might help.)\n");
482 return (0);
483 }
484 /* OK, they are all OK, now go through again and actually send */
485 count = 0;
486 for (i = 1; i < argc; i++) {
487 if ((s = GETSEND(argv[i])) == 0) {
488 (void) fprintf(stderr,
489 "Telnet 'send' error - argument disappeared!\n");
490 (void) quit();
491 /*NOTREACHED*/
492 }
493 if (s->handler) {
494 count++;
495 success += (*s->handler)((s->narg > 0) ? argv[i+1] : 0,
496 (s->narg > 1) ? argv[i+2] : 0);
497 i += s->narg;
498 } else {
499 NET2ADD(IAC, s->what);
500 printoption("SENT", IAC, s->what);
501 }
502 }
503 return (count == success);
504 }
505
506 static int
send_esc()507 send_esc()
508 {
509 NETADD(escape);
510 return (1);
511 }
512
513 static int
send_docmd(name)514 send_docmd(name)
515 char *name;
516 {
517 return (send_tncmd(send_do, "do", name));
518 }
519
520 static int
send_dontcmd(name)521 send_dontcmd(name)
522 char *name;
523 {
524 return (send_tncmd(send_dont, "dont", name));
525 }
526
527 static int
send_willcmd(name)528 send_willcmd(name)
529 char *name;
530 {
531 return (send_tncmd(send_will, "will", name));
532 }
533
534 static int
send_wontcmd(name)535 send_wontcmd(name)
536 char *name;
537 {
538 return (send_tncmd(send_wont, "wont", name));
539 }
540
541 int
send_tncmd(void (* func)(),char * cmd,char * name)542 send_tncmd(void (*func)(), char *cmd, char *name)
543 {
544 char **cpp;
545 extern char *telopts[];
546 int val = 0;
547
548 if (isprefix(name, "help") || isprefix(name, "?")) {
549 int col, len;
550
551 (void) printf("Usage: send %s <value|option>\n", cmd);
552 (void) printf("\"value\" must be from 0 to 255\n");
553 (void) printf("Valid options are:\n\t");
554
555 col = 8;
556 for (cpp = telopts; *cpp; cpp++) {
557 len = strlen(*cpp) + 3;
558 if (col + len > 65) {
559 (void) printf("\n\t");
560 col = 8;
561 }
562 (void) printf(" \"%s\"", *cpp);
563 col += len;
564 }
565 (void) printf("\n");
566 return (0);
567 }
568 cpp = (char **)genget(name, telopts, sizeof (char *));
569 if (Ambiguous(cpp)) {
570 (void) fprintf(stderr,
571 "'%s': ambiguous argument ('send %s ?' for help).\n",
572 name, cmd);
573 return (0);
574 }
575 if (cpp) {
576 val = cpp - telopts;
577 } else {
578 char *cp = name;
579
580 while (*cp >= '0' && *cp <= '9') {
581 val *= 10;
582 val += *cp - '0';
583 cp++;
584 }
585 if (*cp != 0) {
586 (void) fprintf(stderr,
587 "'%s': unknown argument ('send %s ?' for help).\n",
588 name, cmd);
589 return (0);
590 } else if (val < 0 || val > 255) {
591 (void) fprintf(stderr,
592 "'%s': bad value ('send %s ?' for help).\n",
593 name, cmd);
594 return (0);
595 }
596 }
597 if (!connected) {
598 (void) printf("?Need to be connected first.\n");
599 return (0);
600 }
601 (*func)(val, 1);
602 return (1);
603 }
604
605 static int
send_help()606 send_help()
607 {
608 struct sendlist *s; /* pointer to current command */
609 for (s = Sendlist; s->name; s++) {
610 if (s->help)
611 (void) printf("%-15s %s\n", s->name, s->help);
612 }
613 return (0);
614 }
615
616 /*
617 * The following are the routines and data structures referred
618 * to by the arguments to the "toggle" command.
619 */
620
621 static int
lclchars()622 lclchars()
623 {
624 donelclchars = 1;
625 return (1);
626 }
627
628 static int
togdebug()629 togdebug()
630 {
631 if (net > 0 &&
632 (SetSockOpt(net, SOL_SOCKET, SO_DEBUG, debug)) < 0) {
633 perror("setsockopt (SO_DEBUG)");
634 }
635 return (1);
636 }
637
638
639 static int
togcrlf()640 togcrlf()
641 {
642 if (crlf) {
643 (void) printf(
644 "Will send carriage returns as telnet <CR><LF>.\n");
645 } else {
646 (void) printf(
647 "Will send carriage returns as telnet <CR><NUL>.\n");
648 }
649 return (1);
650 }
651
652 static int binmode;
653
654 static int
togbinary(val)655 togbinary(val)
656 int val;
657 {
658 donebinarytoggle = 1;
659
660 if (val >= 0) {
661 binmode = val;
662 } else {
663 if (my_want_state_is_will(TELOPT_BINARY) &&
664 my_want_state_is_do(TELOPT_BINARY)) {
665 binmode = 1;
666 } else if (my_want_state_is_wont(TELOPT_BINARY) &&
667 my_want_state_is_dont(TELOPT_BINARY)) {
668 binmode = 0;
669 }
670 val = binmode ? 0 : 1;
671 }
672
673 if (val == 1) {
674 if (my_want_state_is_will(TELOPT_BINARY) &&
675 my_want_state_is_do(TELOPT_BINARY)) {
676 (void) printf("Already operating in binary mode "
677 "with remote host.\n");
678 } else {
679 (void) printf(
680 "Negotiating binary mode with remote host.\n");
681 tel_enter_binary(3);
682 }
683 } else {
684 if (my_want_state_is_wont(TELOPT_BINARY) &&
685 my_want_state_is_dont(TELOPT_BINARY)) {
686 (void) printf("Already in network ascii mode "
687 "with remote host.\n");
688 } else {
689 (void) printf("Negotiating network ascii mode "
690 "with remote host.\n");
691 tel_leave_binary(3);
692 }
693 }
694 return (1);
695 }
696
697 static int
togrbinary(val)698 togrbinary(val)
699 int val;
700 {
701 donebinarytoggle = 1;
702
703 if (val == -1)
704 val = my_want_state_is_do(TELOPT_BINARY) ? 0 : 1;
705
706 if (val == 1) {
707 if (my_want_state_is_do(TELOPT_BINARY)) {
708 (void) printf("Already receiving in binary mode.\n");
709 } else {
710 (void) printf("Negotiating binary mode on input.\n");
711 tel_enter_binary(1);
712 }
713 } else {
714 if (my_want_state_is_dont(TELOPT_BINARY)) {
715 (void) printf(
716 "Already receiving in network ascii mode.\n");
717 } else {
718 (void) printf(
719 "Negotiating network ascii mode on input.\n");
720 tel_leave_binary(1);
721 }
722 }
723 return (1);
724 }
725
726 static int
togxbinary(val)727 togxbinary(val)
728 int val;
729 {
730 donebinarytoggle = 1;
731
732 if (val == -1)
733 val = my_want_state_is_will(TELOPT_BINARY) ? 0 : 1;
734
735 if (val == 1) {
736 if (my_want_state_is_will(TELOPT_BINARY)) {
737 (void) printf("Already transmitting in binary mode.\n");
738 } else {
739 (void) printf("Negotiating binary mode on output.\n");
740 tel_enter_binary(2);
741 }
742 } else {
743 if (my_want_state_is_wont(TELOPT_BINARY)) {
744 (void) printf(
745 "Already transmitting in network ascii mode.\n");
746 } else {
747 (void) printf(
748 "Negotiating network ascii mode on output.\n");
749 tel_leave_binary(2);
750 }
751 }
752 return (1);
753 }
754
755
756 static int togglehelp(void);
757 extern int auth_togdebug(int);
758
759 struct togglelist {
760 char *name; /* name of toggle */
761 char *help; /* help message */
762 int (*handler)(); /* routine to do actual setting */
763 int *variable;
764 char *actionexplanation;
765 };
766
767 static struct togglelist Togglelist[] = {
768 { "autoflush",
769 "flushing of output when sending interrupt characters",
770 0,
771 &autoflush,
772 "flush output when sending interrupt characters" },
773 { "autosynch",
774 "automatic sending of interrupt characters in urgent mode",
775 0,
776 &autosynch,
777 "send interrupt characters in urgent mode" },
778 { "autologin",
779 "automatic sending of login and/or authentication info",
780 0,
781 &autologin,
782 "send login name and/or authentication information" },
783 { "authdebug",
784 "authentication debugging",
785 auth_togdebug,
786 0,
787 "print authentication debugging information" },
788 { "autoencrypt",
789 "automatic encryption of data stream",
790 EncryptAutoEnc,
791 0,
792 "automatically encrypt output" },
793 { "autodecrypt",
794 "automatic decryption of data stream",
795 EncryptAutoDec,
796 0,
797 "automatically decrypt input" },
798 { "verbose_encrypt",
799 "verbose encryption output",
800 EncryptVerbose,
801 0,
802 "print verbose encryption output" },
803 { "encdebug",
804 "encryption debugging",
805 EncryptDebug,
806 0,
807 "print encryption debugging information" },
808 { "skiprc",
809 "don't read ~/.telnetrc file",
810 0,
811 &skiprc,
812 "skip reading of ~/.telnetrc file" },
813 { "binary",
814 "sending and receiving of binary data",
815 togbinary,
816 0,
817 0 },
818 { "inbinary",
819 "receiving of binary data",
820 togrbinary,
821 0,
822 0 },
823 { "outbinary",
824 "sending of binary data",
825 togxbinary,
826 0,
827 0 },
828 { "crlf",
829 "sending carriage returns as telnet <CR><LF>",
830 togcrlf,
831 &crlf,
832 0 },
833 { "crmod",
834 "mapping of received carriage returns",
835 0,
836 &crmod,
837 "map carriage return on output" },
838 { "localchars",
839 "local recognition of certain control characters",
840 lclchars,
841 &localchars,
842 "recognize certain control characters" },
843 { " ", "", 0 }, /* empty line */
844 { "debug",
845 "debugging",
846 togdebug,
847 &debug,
848 "turn on socket level debugging" },
849 { "netdata",
850 "printing of hexadecimal network data (debugging)",
851 0,
852 &netdata,
853 "print hexadecimal representation of network traffic" },
854 { "prettydump",
855 "output of \"netdata\" to user readable format (debugging)",
856 0,
857 &prettydump,
858 "print user readable output for \"netdata\"" },
859 { "options",
860 "viewing of options processing (debugging)",
861 0,
862 &showoptions,
863 "show option processing" },
864 { "termdata",
865 "(debugging) toggle printing of hexadecimal terminal data",
866 0,
867 &termdata,
868 "print hexadecimal representation of terminal traffic" },
869 { "?",
870 0,
871 togglehelp },
872 { "help",
873 0,
874 togglehelp },
875 { 0 }
876 };
877
878 static int
togglehelp()879 togglehelp()
880 {
881 struct togglelist *c;
882
883 for (c = Togglelist; c->name; c++) {
884 if (c->help) {
885 if (*c->help)
886 (void) printf(
887 "%-15s toggle %s\n", c->name, c->help);
888 else
889 (void) printf("\n");
890 }
891 }
892 (void) printf("\n");
893 (void) printf("%-15s %s\n", "?", "display help information");
894 return (0);
895 }
896
897 static void
settogglehelp(set)898 settogglehelp(set)
899 int set;
900 {
901 struct togglelist *c;
902
903 for (c = Togglelist; c->name; c++) {
904 if (c->help) {
905 if (*c->help)
906 (void) printf("%-15s %s %s\n", c->name,
907 set ? "enable" : "disable", c->help);
908 else
909 (void) printf("\n");
910 }
911 }
912 }
913
914 #define GETTOGGLE(name) (struct togglelist *) \
915 genget(name, (char **)Togglelist, sizeof (struct togglelist))
916
917 static int
toggle(argc,argv)918 toggle(argc, argv)
919 int argc;
920 char *argv[];
921 {
922 int retval = 1;
923 char *name;
924 struct togglelist *c;
925
926 if (argc < 2) {
927 (void) fprintf(stderr,
928 "Need an argument to 'toggle' command. "
929 "'toggle ?' for help.\n");
930 return (0);
931 }
932 argc--;
933 argv++;
934 while (argc--) {
935 name = *argv++;
936 c = GETTOGGLE(name);
937 if (Ambiguous(c)) {
938 (void) fprintf(stderr, "'%s': ambiguous argument "
939 "('toggle ?' for help).\n", name);
940 return (0);
941 } else if (c == 0) {
942 (void) fprintf(stderr, "'%s': unknown argument "
943 "('toggle ?' for help).\n", name);
944 return (0);
945 } else {
946 if (c->variable) {
947 *c->variable = !*c->variable; /* invert it */
948 if (c->actionexplanation) {
949 (void) printf("%s %s.\n",
950 *c->variable ? "Will" : "Won't",
951 c->actionexplanation);
952 }
953 }
954 if (c->handler) {
955 retval &= (*c->handler)(-1);
956 }
957 }
958 }
959 return (retval);
960 }
961
962 /*
963 * The following perform the "set" command.
964 */
965
966 #ifdef USE_TERMIO
967 struct termio new_tc = { 0 };
968 #endif
969
970 struct setlist {
971 char *name; /* name */
972 char *help; /* help information */
973 void (*handler)();
974 cc_t *charp; /* where it is located at */
975 };
976
977 static struct setlist Setlist[] = {
978 #ifdef KLUDGELINEMODE
979 { "echo", "character to toggle local echoing on/off", 0, &echoc },
980 #endif
981 { "escape", "character to escape back to telnet command mode", 0,
982 &escape },
983 { "rlogin", "rlogin escape character", 0, &rlogin },
984 { "tracefile", "file to write trace information to", SetNetTrace,
985 (cc_t *)NetTraceFile},
986 { " ", "" },
987 { " ", "The following need 'localchars' to be toggled true", 0, 0 },
988 { "flushoutput", "character to cause an Abort Output", 0,
989 termFlushCharp },
990 { "interrupt", "character to cause an Interrupt Process", 0,
991 termIntCharp },
992 { "quit", "character to cause an Abort process", 0, termQuitCharp },
993 { "eof", "character to cause an EOF ", 0, termEofCharp },
994 { " ", "" },
995 { " ", "The following are for local editing in linemode", 0, 0 },
996 { "erase", "character to use to erase a character", 0, termEraseCharp },
997 { "kill", "character to use to erase a line", 0, termKillCharp },
998 { "lnext", "character to use for literal next", 0,
999 termLiteralNextCharp },
1000 { "susp", "character to cause a Suspend Process", 0, termSuspCharp },
1001 { "reprint", "character to use for line reprint", 0, termRprntCharp },
1002 { "worderase", "character to use to erase a word", 0, termWerasCharp },
1003 { "start", "character to use for XON", 0, termStartCharp },
1004 { "stop", "character to use for XOFF", 0, termStopCharp },
1005 { "forw1", "alternate end of line character", 0, termForw1Charp },
1006 { "forw2", "alternate end of line character", 0, termForw2Charp },
1007 { "ayt", "alternate AYT character", 0, termAytCharp },
1008 { 0 }
1009 };
1010
1011 static struct setlist *
getset(name)1012 getset(name)
1013 char *name;
1014 {
1015 return ((struct setlist *)
1016 genget(name, (char **)Setlist, sizeof (struct setlist)));
1017 }
1018
1019 void
set_escape_char(s)1020 set_escape_char(s)
1021 char *s;
1022 {
1023 if (rlogin != _POSIX_VDISABLE) {
1024 rlogin = (s && *s) ? special(s) : _POSIX_VDISABLE;
1025 (void) printf("Telnet rlogin escape character is '%s'.\n",
1026 control(rlogin));
1027 } else {
1028 escape = (s && *s) ? special(s) : _POSIX_VDISABLE;
1029 (void) printf("Telnet escape character is '%s'.\n",
1030 esc_control(escape));
1031 }
1032 }
1033
1034 static int
setcmd(argc,argv)1035 setcmd(argc, argv)
1036 int argc;
1037 char *argv[];
1038 {
1039 int value;
1040 struct setlist *ct;
1041 struct togglelist *c;
1042
1043 if (argc < 2 || argc > 3) {
1044 (void) printf(
1045 "Format is 'set Name Value'\n'set ?' for help.\n");
1046 return (0);
1047 }
1048 if ((argc == 2) &&
1049 (isprefix(argv[1], "?") || isprefix(argv[1], "help"))) {
1050 for (ct = Setlist; ct->name; ct++)
1051 (void) printf("%-15s %s\n", ct->name, ct->help);
1052 (void) printf("\n");
1053 settogglehelp(1);
1054 (void) printf("%-15s %s\n", "?", "display help information");
1055 return (0);
1056 }
1057
1058 ct = getset(argv[1]);
1059 if (ct == 0) {
1060 c = GETTOGGLE(argv[1]);
1061 if (c == 0) {
1062 (void) fprintf(stderr, "'%s': unknown argument "
1063 "('set ?' for help).\n", argv[1]);
1064 return (0);
1065 } else if (Ambiguous(c)) {
1066 (void) fprintf(stderr, "'%s': ambiguous argument "
1067 "('set ?' for help).\n", argv[1]);
1068 return (0);
1069 }
1070 if (c->variable) {
1071 if ((argc == 2) || (strcmp("on", argv[2]) == 0))
1072 *c->variable = 1;
1073 else if (strcmp("off", argv[2]) == 0)
1074 *c->variable = 0;
1075 else {
1076 (void) printf(
1077 "Format is 'set togglename [on|off]'\n"
1078 "'set ?' for help.\n");
1079 return (0);
1080 }
1081 if (c->actionexplanation) {
1082 (void) printf("%s %s.\n",
1083 *c->variable? "Will" : "Won't",
1084 c->actionexplanation);
1085 }
1086 }
1087 if (c->handler)
1088 (*c->handler)(1);
1089 } else if (argc != 3) {
1090 (void) printf(
1091 "Format is 'set Name Value'\n'set ?' for help.\n");
1092 return (0);
1093 } else if (Ambiguous(ct)) {
1094 (void) fprintf(stderr,
1095 "'%s': ambiguous argument ('set ?' for help).\n", argv[1]);
1096 return (0);
1097 } else if (ct->handler) {
1098 (*ct->handler)(argv[2]);
1099 (void) printf(
1100 "%s set to \"%s\".\n", ct->name, (char *)ct->charp);
1101 } else {
1102 if (strcmp("off", argv[2])) {
1103 value = special(argv[2]);
1104 } else {
1105 value = _POSIX_VDISABLE;
1106 }
1107 *(ct->charp) = (cc_t)value;
1108 (void) printf("%s character is '%s'.\n", ct->name,
1109 control(*(ct->charp)));
1110 }
1111 slc_check();
1112 return (1);
1113 }
1114
1115 static int
unsetcmd(int argc,char * argv[])1116 unsetcmd(int argc, char *argv[])
1117 {
1118 struct setlist *ct;
1119 struct togglelist *c;
1120 char *name;
1121
1122 if (argc < 2) {
1123 (void) fprintf(stderr, "Need an argument to 'unset' command. "
1124 "'unset ?' for help.\n");
1125 return (0);
1126 }
1127 if (isprefix(argv[1], "?") || isprefix(argv[1], "help")) {
1128 for (ct = Setlist; ct->name; ct++)
1129 (void) printf("%-15s %s\n", ct->name, ct->help);
1130 (void) printf("\n");
1131 settogglehelp(0);
1132 (void) printf("%-15s %s\n", "?", "display help information");
1133 return (0);
1134 }
1135
1136 argc--;
1137 argv++;
1138 while (argc--) {
1139 name = *argv++;
1140 ct = getset(name);
1141 if (ct == 0) {
1142 c = GETTOGGLE(name);
1143 if (c == 0) {
1144 (void) fprintf(stderr, "'%s': unknown argument "
1145 "('unset ?' for help).\n", name);
1146 return (0);
1147 } else if (Ambiguous(c)) {
1148 (void) fprintf(stderr,
1149 "'%s': ambiguous argument "
1150 "('unset ?' for help).\n", name);
1151 return (0);
1152 }
1153 if (c->variable) {
1154 *c->variable = 0;
1155 if (c->actionexplanation) {
1156 (void) printf("%s %s.\n",
1157 *c->variable? "Will" : "Won't",
1158 c->actionexplanation);
1159 }
1160 }
1161 if (c->handler)
1162 (*c->handler)(0);
1163 } else if (Ambiguous(ct)) {
1164 (void) fprintf(stderr, "'%s': ambiguous argument "
1165 "('unset ?' for help).\n", name);
1166 return (0);
1167 } else if (ct->handler) {
1168 (*ct->handler)(0);
1169 (void) printf("%s reset to \"%s\".\n", ct->name,
1170 (char *)ct->charp);
1171 } else {
1172 *(ct->charp) = _POSIX_VDISABLE;
1173 (void) printf("%s character is '%s'.\n", ct->name,
1174 control(*(ct->charp)));
1175 }
1176 }
1177 return (1);
1178 }
1179
1180 /*
1181 * The following are the data structures and routines for the
1182 * 'mode' command.
1183 */
1184 extern int reqd_linemode;
1185
1186 #ifdef KLUDGELINEMODE
1187 extern int kludgelinemode;
1188
1189 static int
dokludgemode()1190 dokludgemode()
1191 {
1192 kludgelinemode = 1;
1193 send_wont(TELOPT_LINEMODE, 1);
1194 send_dont(TELOPT_SGA, 1);
1195 send_dont(TELOPT_ECHO, 1);
1196 /*
1197 * If processing the .telnetrc file, keep track of linemode and/or
1198 * kludgelinemode requests which are processed before initial option
1199 * negotiations occur.
1200 */
1201 if (doing_rc)
1202 reqd_linemode = 1;
1203 return (1);
1204 }
1205 #endif
1206
1207 static int
dolinemode()1208 dolinemode()
1209 {
1210 #ifdef KLUDGELINEMODE
1211 if (kludgelinemode)
1212 send_dont(TELOPT_SGA, 1);
1213 #endif
1214 send_will(TELOPT_LINEMODE, 1);
1215 send_dont(TELOPT_ECHO, 1);
1216
1217 /*
1218 * If processing the .telnetrc file, keep track of linemode and/or
1219 * kludgelinemode requests which are processed before initial option
1220 * negotiations occur.
1221 */
1222 if (doing_rc)
1223 reqd_linemode = 1;
1224 return (1);
1225 }
1226
1227 static int
docharmode()1228 docharmode()
1229 {
1230 #ifdef KLUDGELINEMODE
1231 if (kludgelinemode)
1232 send_do(TELOPT_SGA, 1);
1233 else
1234 #endif
1235 send_wont(TELOPT_LINEMODE, 1);
1236 send_do(TELOPT_ECHO, 1);
1237 reqd_linemode = 0;
1238 return (1);
1239 }
1240
1241 static int
dolmmode(bit,on)1242 dolmmode(bit, on)
1243 int bit, on;
1244 {
1245 unsigned char c;
1246 extern int linemode;
1247
1248 if (my_want_state_is_wont(TELOPT_LINEMODE)) {
1249 (void) printf("?Need to have LINEMODE option enabled first.\n");
1250 (void) printf("'mode ?' for help.\n");
1251 return (0);
1252 }
1253
1254 if (on)
1255 c = (linemode | bit);
1256 else
1257 c = (linemode & ~bit);
1258 lm_mode(&c, 1, 1);
1259 return (1);
1260 }
1261
1262 static int
setmode(int bit)1263 setmode(int bit)
1264 {
1265 return (dolmmode(bit, 1));
1266 }
1267
1268 static int
clearmode(int bit)1269 clearmode(int bit)
1270 {
1271 return (dolmmode(bit, 0));
1272 }
1273
1274 struct modelist {
1275 char *name; /* command name */
1276 char *help; /* help string */
1277 int (*handler)(); /* routine which executes command */
1278 int needconnect; /* Do we need to be connected to execute? */
1279 int arg1;
1280 };
1281
1282 static int modehelp();
1283
1284 static struct modelist ModeList[] = {
1285 { "character", "Disable LINEMODE option", docharmode, 1 },
1286 #ifdef KLUDGELINEMODE
1287 { "", "(or disable obsolete line-by-line mode)", 0 },
1288 #endif
1289 { "line", "Enable LINEMODE option", dolinemode, 1 },
1290 #ifdef KLUDGELINEMODE
1291 { "", "(or enable obsolete line-by-line mode)", 0 },
1292 #endif
1293 { "", "", 0 },
1294 { "", "These require the LINEMODE option to be enabled", 0 },
1295 { "isig", "Enable signal trapping", setmode, 1, MODE_TRAPSIG },
1296 { "+isig", 0, setmode, 1, MODE_TRAPSIG },
1297 { "-isig", "Disable signal trapping", clearmode, 1, MODE_TRAPSIG },
1298 { "edit", "Enable character editing", setmode, 1, MODE_EDIT },
1299 { "+edit", 0, setmode, 1, MODE_EDIT },
1300 { "-edit", "Disable character editing", clearmode, 1, MODE_EDIT },
1301 { "softtabs", "Enable tab expansion", setmode, 1, MODE_SOFT_TAB },
1302 { "+softtabs", 0, setmode, 1, MODE_SOFT_TAB },
1303 { "-softtabs", "Disable tab expansion",
1304 clearmode, 1, MODE_SOFT_TAB },
1305 { "litecho", "Enable literal character echo",
1306 setmode, 1, MODE_LIT_ECHO },
1307 { "+litecho", 0, setmode, 1, MODE_LIT_ECHO },
1308 { "-litecho", "Disable literal character echo", clearmode, 1,
1309 MODE_LIT_ECHO },
1310 { "help", 0, modehelp, 0 },
1311 #ifdef KLUDGELINEMODE
1312 { "kludgeline", 0, dokludgemode, 1 },
1313 #endif
1314 { "", "", 0 },
1315 { "?", "Print help information", modehelp, 0 },
1316 { 0 },
1317 };
1318
1319
1320 static int
modehelp()1321 modehelp()
1322 {
1323 struct modelist *mt;
1324
1325 (void) printf("format is: 'mode Mode', where 'Mode' is one of:\n\n");
1326 for (mt = ModeList; mt->name; mt++) {
1327 if (mt->help) {
1328 if (*mt->help)
1329 (void) printf("%-15s %s\n", mt->name, mt->help);
1330 else
1331 (void) printf("\n");
1332 }
1333 }
1334 return (0);
1335 }
1336
1337 #define GETMODECMD(name) (struct modelist *) \
1338 genget(name, (char **)ModeList, sizeof (struct modelist))
1339
1340 static int
modecmd(argc,argv)1341 modecmd(argc, argv)
1342 int argc;
1343 char *argv[];
1344 {
1345 struct modelist *mt;
1346
1347 if (argc != 2) {
1348 (void) printf("'mode' command requires an argument\n");
1349 (void) printf("'mode ?' for help.\n");
1350 } else if ((mt = GETMODECMD(argv[1])) == 0) {
1351 (void) fprintf(stderr,
1352 "Unknown mode '%s' ('mode ?' for help).\n", argv[1]);
1353 } else if (Ambiguous(mt)) {
1354 (void) fprintf(stderr,
1355 "Ambiguous mode '%s' ('mode ?' for help).\n", argv[1]);
1356 } else if (mt->needconnect && !connected) {
1357 (void) printf("?Need to be connected first.\n");
1358 (void) printf("'mode ?' for help.\n");
1359 } else if (mt->handler) {
1360 return (*mt->handler)(mt->arg1);
1361 }
1362 return (0);
1363 }
1364
1365 /*
1366 * The following data structures and routines implement the
1367 * "display" command.
1368 */
1369
1370 static int
display(argc,argv)1371 display(argc, argv)
1372 int argc;
1373 char *argv[];
1374 {
1375 struct togglelist *tl;
1376 struct setlist *sl;
1377
1378 #define dotog(tl) if (tl->variable && tl->actionexplanation) { \
1379 if (*tl->variable) { \
1380 (void) printf("will"); \
1381 } else { \
1382 (void) printf("won't"); \
1383 } \
1384 (void) printf(" %s.\n", tl->actionexplanation); \
1385 }
1386
1387 #define doset(sl) if (sl->name && *sl->name != ' ') { \
1388 if (sl->handler == 0) \
1389 (void) printf("%-15s [%s]\n", sl->name, \
1390 control(*sl->charp)); \
1391 else \
1392 (void) printf("%-15s \"%s\"\n", sl->name, \
1393 (char *)sl->charp); \
1394 }
1395
1396 if (argc == 1) {
1397 for (tl = Togglelist; tl->name; tl++) {
1398 dotog(tl);
1399 }
1400 (void) printf("\n");
1401 for (sl = Setlist; sl->name; sl++) {
1402 doset(sl);
1403 }
1404 } else {
1405 int i;
1406
1407 for (i = 1; i < argc; i++) {
1408 sl = getset(argv[i]);
1409 tl = GETTOGGLE(argv[i]);
1410 if (Ambiguous(sl) || Ambiguous(tl)) {
1411 (void) printf(
1412 "?Ambiguous argument '%s'.\n", argv[i]);
1413 return (0);
1414 } else if (!sl && !tl) {
1415 (void) printf(
1416 "?Unknown argument '%s'.\n", argv[i]);
1417 return (0);
1418 } else {
1419 if (tl) {
1420 dotog(tl);
1421 }
1422 if (sl) {
1423 doset(sl);
1424 }
1425 }
1426 }
1427 }
1428 optionstatus();
1429 (void) EncryptStatus();
1430 return (1);
1431 #undef doset
1432 #undef dotog
1433 }
1434
1435 /*
1436 * The following are the data structures, and many of the routines,
1437 * relating to command processing.
1438 */
1439
1440 /*
1441 * Set the escape character.
1442 */
1443 static int
setescape(int argc,char * argv[])1444 setescape(int argc, char *argv[])
1445 {
1446 char *arg;
1447 char *buf = NULL;
1448
1449 if (argc > 2)
1450 arg = argv[1];
1451 else {
1452 (void) printf("new escape character: ");
1453 if (GetString(&buf, NULL, stdin) == NULL) {
1454 if (!feof(stdin)) {
1455 perror("can't set escape character");
1456 goto setescape_exit;
1457 }
1458 }
1459 arg = buf;
1460 }
1461 /* we place no limitations on what escape can be. */
1462 escape = arg[0];
1463 (void) printf("Escape character is '%s'.\n", esc_control(escape));
1464 (void) fflush(stdout);
1465 setescape_exit:
1466 Free(&buf);
1467 return (1);
1468 }
1469
1470 /*ARGSUSED*/
1471 static int
togcrmod(argc,argv)1472 togcrmod(argc, argv)
1473 int argc;
1474 char *argv[];
1475 {
1476 crmod = !crmod;
1477 (void) printf(
1478 "%s map carriage return on output.\n", crmod ? "Will" : "Won't");
1479 (void) fflush(stdout);
1480 return (1);
1481 }
1482
1483 /*ARGSUSED*/
1484 static int
suspend(argc,argv)1485 suspend(argc, argv)
1486 int argc;
1487 char *argv[];
1488 {
1489 setcommandmode();
1490 {
1491 unsigned short oldrows, oldcols, newrows, newcols;
1492 int err;
1493
1494 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1495 (void) kill(0, SIGTSTP);
1496 /*
1497 * If we didn't get the window size before the SUSPEND, but we
1498 * can get them now (?), then send the NAWS to make sure that
1499 * we are set up for the right window size.
1500 */
1501 if (TerminalWindowSize(&newrows, &newcols) && connected &&
1502 (err || ((oldrows != newrows) || (oldcols != newcols)))) {
1503 sendnaws();
1504 }
1505 }
1506 /* reget parameters in case they were changed */
1507 TerminalSaveState();
1508 setconnmode(0);
1509 return (1);
1510 }
1511
1512 /*ARGSUSED*/
1513 static int
shell(int argc,char * argv[])1514 shell(int argc, char *argv[])
1515 {
1516 unsigned short oldrows, oldcols, newrows, newcols;
1517 int err;
1518
1519 setcommandmode();
1520
1521 err = (TerminalWindowSize(&oldrows, &oldcols) == 0) ? 1 : 0;
1522 switch (vfork()) {
1523 case -1:
1524 perror("Fork failed\n");
1525 break;
1526
1527 case 0:
1528 {
1529 /*
1530 * Fire up the shell in the child.
1531 */
1532 char *shellp, *shellname;
1533
1534 shellp = getenv("SHELL");
1535 if (shellp == NULL)
1536 shellp = "/bin/sh";
1537 if ((shellname = strrchr(shellp, '/')) == 0)
1538 shellname = shellp;
1539 else
1540 shellname++;
1541 if (argc > 1)
1542 (void) execl(shellp, shellname, "-c", argv[1], 0);
1543 else
1544 (void) execl(shellp, shellname, 0);
1545 perror("Execl");
1546 _exit(EXIT_FAILURE);
1547 }
1548 default:
1549 (void) wait((int *)0); /* Wait for the shell to complete */
1550
1551 if (TerminalWindowSize(&newrows, &newcols) && connected &&
1552 (err || ((oldrows != newrows) || (oldcols != newcols)))) {
1553 sendnaws();
1554 }
1555 break;
1556 }
1557 return (1);
1558 }
1559
1560 static int
bye(argc,argv)1561 bye(argc, argv)
1562 int argc; /* Number of arguments */
1563 char *argv[]; /* arguments */
1564 {
1565 extern int resettermname;
1566
1567 if (connected) {
1568 (void) shutdown(net, 2);
1569 (void) printf("Connection to %.*s closed.\n", MAXHOSTNAMELEN,
1570 hostname);
1571 Close(&net);
1572 connected = 0;
1573 resettermname = 1;
1574 /* reset options */
1575 (void) tninit();
1576 }
1577 if ((argc != 2) || (strcmp(argv[1], "fromquit") != 0)) {
1578 longjmp(toplevel, 1);
1579 /* NOTREACHED */
1580 }
1581 return (1); /* Keep lint, etc., happy */
1582 }
1583
1584 /*VARARGS*/
1585 int
quit()1586 quit()
1587 {
1588 (void) call(3, bye, "bye", "fromquit");
1589 Exit(EXIT_SUCCESS);
1590 /*NOTREACHED*/
1591 return (1);
1592 }
1593
1594 /*ARGSUSED*/
1595 static int
logout(argc,argv)1596 logout(argc, argv)
1597 int argc;
1598 char *argv[];
1599 {
1600 send_do(TELOPT_LOGOUT, 1);
1601 (void) netflush();
1602 return (1);
1603 }
1604
1605
1606 /*
1607 * The SLC command.
1608 */
1609
1610 struct slclist {
1611 char *name;
1612 char *help;
1613 void (*handler)();
1614 int arg;
1615 };
1616
1617 static void slc_help();
1618
1619 static struct slclist SlcList[] = {
1620 { "export", "Use local special character definitions",
1621 slc_mode_export, 0 },
1622 { "import", "Use remote special character definitions",
1623 slc_mode_import, 1 },
1624 { "check", "Verify remote special character definitions",
1625 slc_mode_import, 0 },
1626 { "help", 0, slc_help, 0 },
1627 { "?", "Print help information", slc_help, 0 },
1628 { 0 },
1629 };
1630
1631 static void
slc_help()1632 slc_help()
1633 {
1634 struct slclist *c;
1635
1636 for (c = SlcList; c->name; c++) {
1637 if (c->help) {
1638 if (*c->help)
1639 (void) printf("%-15s %s\n", c->name, c->help);
1640 else
1641 (void) printf("\n");
1642 }
1643 }
1644 }
1645
1646 static struct slclist *
getslc(name)1647 getslc(name)
1648 char *name;
1649 {
1650 return ((struct slclist *)
1651 genget(name, (char **)SlcList, sizeof (struct slclist)));
1652 }
1653
1654 static int
slccmd(argc,argv)1655 slccmd(argc, argv)
1656 int argc;
1657 char *argv[];
1658 {
1659 struct slclist *c;
1660
1661 if (argc != 2) {
1662 (void) fprintf(stderr,
1663 "Need an argument to 'slc' command. 'slc ?' for help.\n");
1664 return (0);
1665 }
1666 c = getslc(argv[1]);
1667 if (c == 0) {
1668 (void) fprintf(stderr,
1669 "'%s': unknown argument ('slc ?' for help).\n",
1670 argv[1]);
1671 return (0);
1672 }
1673 if (Ambiguous(c)) {
1674 (void) fprintf(stderr,
1675 "'%s': ambiguous argument ('slc ?' for help).\n", argv[1]);
1676 return (0);
1677 }
1678 (*c->handler)(c->arg);
1679 slcstate();
1680 return (1);
1681 }
1682
1683 /*
1684 * The ENVIRON command.
1685 */
1686
1687 struct envlist {
1688 char *name;
1689 char *help;
1690 void (*handler)();
1691 int narg;
1692 };
1693
1694 static struct env_lst *env_define(unsigned char *, unsigned char *);
1695 static void env_undefine(unsigned char *);
1696 static void env_export(unsigned char *);
1697 static void env_unexport(unsigned char *);
1698 static void env_send(unsigned char *);
1699 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1700 static void env_varval(unsigned char *);
1701 #endif
1702 static void env_list(void);
1703
1704 static void env_help(void);
1705
1706 static struct envlist EnvList[] = {
1707 { "define", "Define an environment variable",
1708 (void (*)())env_define, 2 },
1709 { "undefine", "Undefine an environment variable",
1710 env_undefine, 1 },
1711 { "export", "Mark an environment variable for automatic export",
1712 env_export, 1 },
1713 { "unexport", "Don't mark an environment variable for automatic export",
1714 env_unexport, 1 },
1715 { "send", "Send an environment variable", env_send, 1 },
1716 { "list", "List the current environment variables",
1717 env_list, 0 },
1718 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
1719 { "varval", "Reverse VAR and VALUE (auto, right, wrong, status)",
1720 env_varval, 1 },
1721 #endif
1722 { "help", 0, env_help, 0 },
1723 { "?", "Print help information", env_help, 0 },
1724 { 0 },
1725 };
1726
1727 static void
env_help()1728 env_help()
1729 {
1730 struct envlist *c;
1731
1732 for (c = EnvList; c->name; c++) {
1733 if (c->help) {
1734 if (*c->help)
1735 (void) printf("%-15s %s\n", c->name, c->help);
1736 else
1737 (void) printf("\n");
1738 }
1739 }
1740 }
1741
1742 static struct envlist *
getenvcmd(name)1743 getenvcmd(name)
1744 char *name;
1745 {
1746 return ((struct envlist *)
1747 genget(name, (char **)EnvList, sizeof (struct envlist)));
1748 }
1749
1750 static int
env_cmd(argc,argv)1751 env_cmd(argc, argv)
1752 int argc;
1753 char *argv[];
1754 {
1755 struct envlist *c;
1756
1757 if (argc < 2) {
1758 (void) fprintf(stderr,
1759 "Need an argument to 'environ' command. "
1760 "'environ ?' for help.\n");
1761 return (0);
1762 }
1763 c = getenvcmd(argv[1]);
1764 if (c == 0) {
1765 (void) fprintf(stderr, "'%s': unknown argument "
1766 "('environ ?' for help).\n", argv[1]);
1767 return (0);
1768 }
1769 if (Ambiguous(c)) {
1770 (void) fprintf(stderr, "'%s': ambiguous argument "
1771 "('environ ?' for help).\n", argv[1]);
1772 return (0);
1773 }
1774 if (c->narg + 2 != argc) {
1775 (void) fprintf(stderr,
1776 "Need %s%d argument%s to 'environ %s' command. "
1777 "'environ ?' for help.\n",
1778 c->narg + 2 < argc ? "only " : "",
1779 c->narg, c->narg == 1 ? "" : "s", c->name);
1780 return (0);
1781 }
1782 (*c->handler)(argv[2], argv[3]);
1783 return (1);
1784 }
1785
1786 struct env_lst {
1787 struct env_lst *next; /* pointer to next structure */
1788 struct env_lst *prev; /* pointer to previous structure */
1789 unsigned char *var; /* pointer to variable name */
1790 unsigned char *value; /* pointer to variable value */
1791 int export; /* 1 -> export with default list of variables */
1792 int welldefined; /* A well defined variable */
1793 };
1794
1795 static struct env_lst envlisthead;
1796
1797 static struct env_lst *
env_find(unsigned char * var)1798 env_find(unsigned char *var)
1799 {
1800 struct env_lst *ep;
1801
1802 for (ep = envlisthead.next; ep; ep = ep->next) {
1803 if (strcmp((char *)ep->var, (char *)var) == 0)
1804 return (ep);
1805 }
1806 return (NULL);
1807 }
1808
1809 int
env_init(void)1810 env_init(void)
1811 {
1812 extern char **environ;
1813 char **epp, *cp;
1814 struct env_lst *ep;
1815
1816 for (epp = environ; *epp; epp++) {
1817 if (cp = strchr(*epp, '=')) {
1818 *cp = '\0';
1819
1820 ep = env_define((unsigned char *)*epp,
1821 (unsigned char *)cp+1);
1822 if (ep == NULL)
1823 return (0);
1824 ep->export = 0;
1825 *cp = '=';
1826 }
1827 }
1828 /*
1829 * Special case for DISPLAY variable. If it is ":0.0" or
1830 * "unix:0.0", we have to get rid of "unix" and insert our
1831 * hostname.
1832 */
1833 if (((ep = env_find((uchar_t *)"DISPLAY")) != NULL) &&
1834 ((*ep->value == ':') ||
1835 (strncmp((char *)ep->value, "unix:", 5) == 0))) {
1836 char hbuf[MAXHOSTNAMELEN];
1837 char *cp2 = strchr((char *)ep->value, ':');
1838
1839 if (gethostname(hbuf, MAXHOSTNAMELEN) == -1) {
1840 perror("telnet: cannot get hostname");
1841 return (0);
1842 }
1843 hbuf[MAXHOSTNAMELEN-1] = '\0';
1844 cp = malloc(strlen(hbuf) + strlen(cp2) + 1);
1845 if (cp == NULL) {
1846 perror("telnet: cannot define DISPLAY variable");
1847 return (0);
1848 }
1849 (void) sprintf((char *)cp, "%s%s", hbuf, cp2);
1850 free(ep->value);
1851 ep->value = (unsigned char *)cp;
1852 }
1853 /*
1854 * If LOGNAME is defined, but USER is not, then add
1855 * USER with the value from LOGNAME. We do this because the "accepted
1856 * practice" is to always pass USER on the wire, but SVR4 uses
1857 * LOGNAME by default.
1858 */
1859 if ((ep = env_find((uchar_t *)"LOGNAME")) != NULL &&
1860 env_find((uchar_t *)"USER") == NULL) {
1861 if (env_define((unsigned char *)"USER", ep->value) != NULL)
1862 env_unexport((unsigned char *)"USER");
1863 }
1864 env_export((unsigned char *)"DISPLAY");
1865 env_export((unsigned char *)"PRINTER");
1866
1867 return (1);
1868 }
1869
1870 static struct env_lst *
env_define(unsigned char * var,unsigned char * value)1871 env_define(unsigned char *var, unsigned char *value)
1872 {
1873 unsigned char *tmp_value;
1874 unsigned char *tmp_var;
1875 struct env_lst *ep;
1876
1877 /*
1878 * Allocate copies of arguments first, to make cleanup easier
1879 * in the case of allocation errors.
1880 */
1881 tmp_var = (unsigned char *)strdup((char *)var);
1882 if (tmp_var == NULL) {
1883 perror("telnet: can't copy environment variable name");
1884 return (NULL);
1885 }
1886
1887 tmp_value = (unsigned char *)strdup((char *)value);
1888 if (tmp_value == NULL) {
1889 free(tmp_var);
1890 perror("telnet: can't copy environment variable value");
1891 return (NULL);
1892 }
1893
1894 if (ep = env_find(var)) {
1895 if (ep->var)
1896 free(ep->var);
1897 if (ep->value)
1898 free(ep->value);
1899 } else {
1900 ep = malloc(sizeof (struct env_lst));
1901 if (ep == NULL) {
1902 perror("telnet: can't define environment variable");
1903 free(tmp_var);
1904 free(tmp_value);
1905 return (NULL);
1906 }
1907
1908 ep->next = envlisthead.next;
1909 envlisthead.next = ep;
1910 ep->prev = &envlisthead;
1911 if (ep->next)
1912 ep->next->prev = ep;
1913 }
1914 ep->welldefined = opt_welldefined((char *)var);
1915 ep->export = 1;
1916 ep->var = tmp_var;
1917 ep->value = tmp_value;
1918
1919 return (ep);
1920 }
1921
1922 static void
env_undefine(unsigned char * var)1923 env_undefine(unsigned char *var)
1924 {
1925 struct env_lst *ep;
1926
1927 if (ep = env_find(var)) {
1928 ep->prev->next = ep->next;
1929 if (ep->next)
1930 ep->next->prev = ep->prev;
1931 if (ep->var)
1932 free(ep->var);
1933 if (ep->value)
1934 free(ep->value);
1935 free(ep);
1936 }
1937 }
1938
1939 static void
env_export(unsigned char * var)1940 env_export(unsigned char *var)
1941 {
1942 struct env_lst *ep;
1943
1944 if (ep = env_find(var))
1945 ep->export = 1;
1946 }
1947
1948 static void
env_unexport(unsigned char * var)1949 env_unexport(unsigned char *var)
1950 {
1951 struct env_lst *ep;
1952
1953 if (ep = env_find(var))
1954 ep->export = 0;
1955 }
1956
1957 static void
env_send(unsigned char * var)1958 env_send(unsigned char *var)
1959 {
1960 struct env_lst *ep;
1961
1962 if (my_state_is_wont(TELOPT_NEW_ENVIRON)
1963 #ifdef OLD_ENVIRON
1964 /* old style */ && my_state_is_wont(TELOPT_OLD_ENVIRON)
1965 #endif
1966 /* no environ */) {
1967 (void) fprintf(stderr,
1968 "Cannot send '%s': Telnet ENVIRON option not enabled\n",
1969 var);
1970 return;
1971 }
1972 ep = env_find(var);
1973 if (ep == 0) {
1974 (void) fprintf(stderr,
1975 "Cannot send '%s': variable not defined\n", var);
1976 return;
1977 }
1978 env_opt_start_info();
1979 env_opt_add(ep->var);
1980 env_opt_end(0);
1981 }
1982
1983 static void
env_list(void)1984 env_list(void)
1985 {
1986 struct env_lst *ep;
1987
1988 for (ep = envlisthead.next; ep; ep = ep->next) {
1989 (void) printf("%c %-20s %s\n", ep->export ? '*' : ' ',
1990 ep->var, ep->value);
1991 }
1992 }
1993
1994 unsigned char *
env_default(int init,int welldefined)1995 env_default(int init, int welldefined)
1996 {
1997 static struct env_lst *nep = NULL;
1998
1999 if (init) {
2000 /* return value is not used */
2001 nep = &envlisthead;
2002 return (NULL);
2003 }
2004 if (nep) {
2005 while ((nep = nep->next) != NULL) {
2006 if (nep->export && (nep->welldefined == welldefined))
2007 return (nep->var);
2008 }
2009 }
2010 return (NULL);
2011 }
2012
2013 unsigned char *
env_getvalue(unsigned char * var)2014 env_getvalue(unsigned char *var)
2015 {
2016 struct env_lst *ep;
2017
2018 if (ep = env_find(var))
2019 return (ep->value);
2020 return (NULL);
2021 }
2022
2023 #if defined(OLD_ENVIRON) && defined(ENV_HACK)
2024 static void
env_varval(unsigned char * what)2025 env_varval(unsigned char *what)
2026 {
2027 extern int old_env_var, old_env_value, env_auto;
2028 int len = strlen((char *)what);
2029
2030 if (len == 0)
2031 goto unknown;
2032
2033 if (strncasecmp((char *)what, "status", len) == 0) {
2034 if (env_auto)
2035 (void) printf("%s%s", "VAR and VALUE are/will be ",
2036 "determined automatically\n");
2037 if (old_env_var == OLD_ENV_VAR)
2038 (void) printf(
2039 "VAR and VALUE set to correct definitions\n");
2040 else
2041 (void) printf(
2042 "VAR and VALUE definitions are reversed\n");
2043 } else if (strncasecmp((char *)what, "auto", len) == 0) {
2044 env_auto = 1;
2045 old_env_var = OLD_ENV_VALUE;
2046 old_env_value = OLD_ENV_VAR;
2047 } else if (strncasecmp((char *)what, "right", len) == 0) {
2048 env_auto = 0;
2049 old_env_var = OLD_ENV_VAR;
2050 old_env_value = OLD_ENV_VALUE;
2051 } else if (strncasecmp((char *)what, "wrong", len) == 0) {
2052 env_auto = 0;
2053 old_env_var = OLD_ENV_VALUE;
2054 old_env_value = OLD_ENV_VAR;
2055 } else {
2056 unknown:
2057 (void) printf(
2058 "Unknown \"varval\" command. (\"auto\", \"right\", "
2059 "\"wrong\", \"status\")\n");
2060 }
2061 }
2062 #endif /* OLD_ENVIRON && ENV_HACK */
2063
2064 /*
2065 * The AUTHENTICATE command.
2066 */
2067
2068 struct authlist {
2069 char *name;
2070 char *help;
2071 int (*handler)();
2072 int narg;
2073 };
2074
2075 extern int auth_enable(char *);
2076 extern int auth_disable(char *);
2077 extern int auth_status(void);
2078
2079 static int auth_help(void);
2080
2081 static struct authlist AuthList[] = {
2082 { "status",
2083 "Display current status of authentication information",
2084 auth_status, 0 },
2085 { "disable",
2086 "Disable an authentication type ('auth disable ?' for more)",
2087 auth_disable, 1 },
2088 { "enable",
2089 "Enable an authentication type ('auth enable ?' for more)",
2090 auth_enable, 1 },
2091 { "help", 0, auth_help, 0 },
2092 { "?", "Print help information", auth_help, 0 },
2093 { 0 },
2094 };
2095
2096 static int
auth_help(void)2097 auth_help(void)
2098 {
2099 struct authlist *c;
2100
2101 for (c = AuthList; c->name; c++) {
2102 if (c->help) {
2103 if (*c->help)
2104 (void) printf("%-15s %s\n", c->name, c->help);
2105 else
2106 (void) printf("\n");
2107 }
2108 }
2109 return (0);
2110 }
2111
2112
2113 static int
auth_cmd(int argc,char * argv[])2114 auth_cmd(int argc, char *argv[])
2115 {
2116 struct authlist *c;
2117
2118 if (argc < 2) {
2119 (void) fprintf(stderr, "Need an argument to 'auth' "
2120 "command. 'auth ?' for help.\n");
2121 return (0);
2122 }
2123
2124 c = (struct authlist *)
2125 genget(argv[1], (char **)AuthList, sizeof (struct authlist));
2126 if (c == 0) {
2127 (void) fprintf(stderr,
2128 "'%s': unknown argument ('auth ?' for help).\n",
2129 argv[1]);
2130 return (0);
2131 }
2132 if (Ambiguous(c)) {
2133 (void) fprintf(stderr,
2134 "'%s': ambiguous argument ('auth ?' for help).\n", argv[1]);
2135 return (0);
2136 }
2137 if (c->narg + 2 != argc) {
2138 (void) fprintf(stderr,
2139 "Need %s%d argument%s to 'auth %s' command."
2140 " 'auth ?' for help.\n",
2141 c->narg + 2 < argc ? "only " : "",
2142 c->narg, c->narg == 1 ? "" : "s", c->name);
2143 return (0);
2144 }
2145 return ((*c->handler)(argv[2], argv[3]));
2146 }
2147
2148 /*
2149 * The FORWARD command.
2150 */
2151
2152 extern int forward_flags;
2153
2154 struct forwlist {
2155 char *name;
2156 char *help;
2157 int (*handler)();
2158 int f_flags;
2159 };
2160
2161 static int forw_status(void);
2162 static int forw_set(int);
2163 static int forw_help(void);
2164
2165 static struct forwlist ForwList[] = {
2166 {"status",
2167 "Display current status of credential forwarding",
2168 forw_status, 0},
2169 {"disable",
2170 "Disable credential forwarding",
2171 forw_set, 0},
2172 {"enable",
2173 "Enable credential forwarding",
2174 forw_set, OPTS_FORWARD_CREDS},
2175 {"forwardable",
2176 "Enable credential forwarding of "
2177 "forwardable credentials",
2178 forw_set, OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS},
2179 {"help",
2180 0,
2181 forw_help, 0},
2182 {"?",
2183 "Print help information",
2184 forw_help, 0},
2185 {0},
2186 };
2187
2188 static int
forw_status(void)2189 forw_status(void)
2190 {
2191 if (forward_flags & OPTS_FORWARD_CREDS) {
2192 if (forward_flags & OPTS_FORWARDABLE_CREDS)
2193 (void) printf(gettext(
2194 "Credential forwarding of "
2195 "forwardable credentials enabled\n"));
2196 else
2197 (void) printf(gettext(
2198 "Credential forwarding enabled\n"));
2199 } else
2200 (void) printf(gettext("Credential forwarding disabled\n"));
2201 return (0);
2202 }
2203
2204 static int
forw_set(int f_flags)2205 forw_set(int f_flags)
2206 {
2207 forward_flags = f_flags;
2208 return (0);
2209 }
2210
2211 static int
forw_help(void)2212 forw_help(void)
2213 {
2214 struct forwlist *c;
2215
2216 for (c = ForwList; c->name; c++) {
2217 if (c->help) {
2218 if (*c->help)
2219 (void) printf("%-15s %s\r\n", c->name, c->help);
2220 else
2221 (void) printf("\n");
2222 }
2223 }
2224 return (0);
2225 }
2226
2227 static int
forw_cmd(int argc,char * argv[])2228 forw_cmd(int argc, char *argv[])
2229 {
2230 struct forwlist *c;
2231
2232 if (argc < 2) {
2233 (void) fprintf(stderr, gettext(
2234 "Need an argument to 'forward' "
2235 "command. 'forward ?' for help.\n"));
2236 return (0);
2237 }
2238 c = (struct forwlist *)genget(argv[1], (char **)ForwList,
2239 sizeof (struct forwlist));
2240 if (c == 0) {
2241 (void) fprintf(stderr, gettext(
2242 "'%s': unknown argument ('forward ?' for help).\n"),
2243 argv[1]);
2244 return (0);
2245 }
2246 if (Ambiguous(c)) {
2247 (void) fprintf(stderr, gettext(
2248 "'%s': ambiguous argument ('forward ?' for help).\n"),
2249 argv[1]);
2250 return (0);
2251 }
2252 if (argc != 2) {
2253 (void) fprintf(stderr, gettext(
2254 "No arguments needed to 'forward %s' command. "
2255 "'forward ?' for help.\n"), c->name);
2256 return (0);
2257 }
2258 return ((*c->handler) (c->f_flags));
2259 }
2260
2261 /*
2262 * The ENCRYPT command.
2263 */
2264
2265 struct encryptlist {
2266 char *name;
2267 char *help;
2268 int (*handler)();
2269 int needconnect;
2270 int minarg;
2271 int maxarg;
2272 };
2273
2274 static int EncryptHelp(void);
2275
2276 static struct encryptlist EncryptList[] = {
2277 { "enable", "Enable encryption. ('encrypt enable ?' for more)",
2278 EncryptEnable, 1, 1, 2 },
2279 { "disable", "Disable encryption. ('encrypt disable ?' for more)",
2280 EncryptDisable, 0, 1, 2 },
2281 { "type", "Set encryption type. ('encrypt type ?' for more)",
2282 EncryptType, 0, 1, 2 },
2283 { "start", "Start encryption. ('encrypt start ?' for more)",
2284 EncryptStart, 1, 0, 1 },
2285 { "stop", "Stop encryption. ('encrypt stop ?' for more)",
2286 EncryptStop, 1, 0, 1 },
2287 { "input", "Start encrypting the input stream",
2288 EncryptStartInput, 1, 0, 0 },
2289 { "-input", "Stop encrypting the input stream",
2290 EncryptStopInput, 1, 0, 0 },
2291 { "output", "Start encrypting the output stream",
2292 EncryptStartOutput, 1, 0, 0 },
2293 { "-output", "Stop encrypting the output stream",
2294 EncryptStopOutput, 1, 0, 0 },
2295
2296 { "status", "Display current status of encryption information",
2297 EncryptStatus, 0, 0, 0 },
2298 { "help", 0,
2299 EncryptHelp, 0, 0, 0 },
2300 { "?", "Print help information", EncryptHelp, 0, 0, 0 },
2301 { 0 },
2302 };
2303
2304 static int
EncryptHelp(void)2305 EncryptHelp(void)
2306 {
2307 struct encryptlist *c;
2308
2309 for (c = EncryptList; c->name; c++) {
2310 if (c->help) {
2311 if (*c->help)
2312 (void) printf("%-15s %s\n", c->name, c->help);
2313 else
2314 (void) printf("\n");
2315 }
2316 }
2317 return (0);
2318 }
2319
2320 static int
encrypt_cmd(int argc,char * argv[])2321 encrypt_cmd(int argc, char *argv[])
2322 {
2323 struct encryptlist *c;
2324
2325 if (argc < 2) {
2326 (void) fprintf(stderr, gettext(
2327 "Need an argument to 'encrypt' command. "
2328 "'encrypt ?' for help.\n"));
2329 return (0);
2330 }
2331
2332 c = (struct encryptlist *)
2333 genget(argv[1], (char **)EncryptList, sizeof (struct encryptlist));
2334 if (c == 0) {
2335 (void) fprintf(stderr, gettext(
2336 "'%s': unknown argument ('encrypt ?' for help).\n"),
2337 argv[1]);
2338 return (0);
2339 }
2340 if (Ambiguous(c)) {
2341 (void) fprintf(stderr, gettext(
2342 "'%s': ambiguous argument ('encrypt ?' for help).\n"),
2343 argv[1]);
2344 return (0);
2345 }
2346 argc -= 2;
2347 if (argc < c->minarg || argc > c->maxarg) {
2348 if (c->minarg == c->maxarg) {
2349 (void) fprintf(stderr, gettext("Need %s%d %s "),
2350 c->minarg < argc ?
2351 gettext("only ") : "", c->minarg,
2352 c->minarg == 1 ?
2353 gettext("argument") : gettext("arguments"));
2354 } else {
2355 (void) fprintf(stderr,
2356 gettext("Need %s%d-%d arguments "),
2357 c->maxarg < argc ?
2358 gettext("only ") : "", c->minarg, c->maxarg);
2359 }
2360 (void) fprintf(stderr, gettext(
2361 "to 'encrypt %s' command. 'encrypt ?' for help.\n"),
2362 c->name);
2363 return (0);
2364 }
2365 if (c->needconnect && !connected) {
2366 if (!(argc &&
2367 (isprefix(argv[2], "help") || isprefix(argv[2], "?")))) {
2368 (void) printf(
2369 gettext("?Need to be connected first.\n"));
2370 return (0);
2371 }
2372 }
2373 return ((*c->handler)(argc > 0 ? argv[2] : 0,
2374 argc > 1 ? argv[3] : 0, argc > 2 ? argv[4] : 0));
2375 }
2376
2377 /*
2378 * Print status about the connection.
2379 */
2380 static int
status(int argc,char * argv[])2381 status(int argc, char *argv[])
2382 {
2383 if (connected) {
2384 (void) printf("Connected to %s.\n", hostname);
2385 if ((argc < 2) || strcmp(argv[1], "notmuch")) {
2386 int mode = getconnmode();
2387
2388 if (my_want_state_is_will(TELOPT_LINEMODE)) {
2389 (void) printf(
2390 "Operating with LINEMODE option\n");
2391 (void) printf(
2392 "%s line editing\n", (mode&MODE_EDIT) ?
2393 "Local" : "No");
2394 (void) printf("%s catching of signals\n",
2395 (mode&MODE_TRAPSIG) ? "Local" : "No");
2396 slcstate();
2397 #ifdef KLUDGELINEMODE
2398 } else if (kludgelinemode &&
2399 my_want_state_is_dont(TELOPT_SGA)) {
2400 (void) printf(
2401 "Operating in obsolete linemode\n");
2402 #endif
2403 } else {
2404 (void) printf(
2405 "Operating in single character mode\n");
2406 if (localchars)
2407 (void) printf(
2408 "Catching signals locally\n");
2409 }
2410 (void) printf("%s character echo\n", (mode&MODE_ECHO) ?
2411 "Local" : "Remote");
2412 if (my_want_state_is_will(TELOPT_LFLOW))
2413 (void) printf("%s flow control\n",
2414 (mode&MODE_FLOW) ? "Local" : "No");
2415
2416 encrypt_display();
2417 }
2418 } else {
2419 (void) printf("No connection.\n");
2420 }
2421 if (rlogin != _POSIX_VDISABLE)
2422 (void) printf("Escape character is '%s'.\n", control(rlogin));
2423 else
2424 (void) printf(
2425 "Escape character is '%s'.\n", esc_control(escape));
2426 (void) fflush(stdout);
2427 return (1);
2428 }
2429
2430 /*
2431 * Parse the user input (cmd_line_input) which should:
2432 * - start with the target host, or with "@" or "!@" followed by at least one
2433 * gateway.
2434 * - each host (can be literal address or hostname) can be separated by ",",
2435 * "@", or ",@".
2436 * Note that the last host is the target, all the others (if any ) are the
2437 * gateways.
2438 *
2439 * Returns: -1 if a library call fails, too many gateways, or parse
2440 * error
2441 * num_gw otherwise
2442 * On successful return, hostname_list points to a list of hosts (last one being
2443 * the target, others gateways), src_rtng_type points to the type of source
2444 * routing (strict vs. loose)
2445 */
2446 static int
parse_input(char * cmd_line_input,char ** hostname_list,uchar_t * src_rtng_type)2447 parse_input(char *cmd_line_input, char **hostname_list, uchar_t *src_rtng_type)
2448 {
2449 char hname[MAXHOSTNAMELEN + 1];
2450 char *cp;
2451 int gw_count;
2452 int i;
2453
2454 gw_count = 0;
2455 cp = cmd_line_input;
2456
2457 /*
2458 * Defining ICMD generates the Itelnet binary, the special version of
2459 * telnet which is used with firewall proxy.
2460 * If ICMD is defined, parse_input will treat the whole cmd_line_input
2461 * as the target host and set the num_gw to 0. Therefore, none of the
2462 * source routing related code paths will be executed.
2463 */
2464 #ifndef ICMD
2465 if (*cp == '@') {
2466 *src_rtng_type = IPOPT_LSRR;
2467 cp++;
2468 } else if (*cp == '!') {
2469 *src_rtng_type = IPOPT_SSRR;
2470
2471 /* "!" must be followed by '@' */
2472 if (*(cp + 1) != '@')
2473 goto parse_error;
2474 cp += 2;
2475 } else {
2476 #endif /* ICMD */
2477 /* no gateways, just the target */
2478 hostname_list[0] = strdup(cp);
2479 if (hostname_list[0] == NULL) {
2480 perror("telnet: copying host name");
2481 return (-1);
2482 }
2483 return (0);
2484 #ifndef ICMD
2485 }
2486
2487 while (*cp != '\0') {
2488 /*
2489 * Identify each gateway separated by ",", "@" or ",@" and
2490 * store in hname[].
2491 */
2492 i = 0;
2493 while (*cp != '@' && *cp != ',' && *cp != '\0') {
2494 hname[i++] = *cp++;
2495 if (i > MAXHOSTNAMELEN)
2496 goto parse_error;
2497 }
2498 hname[i] = '\0';
2499
2500 /*
2501 * Two consecutive delimiters which result in a 0 length hname
2502 * is a parse error.
2503 */
2504 if (i == 0)
2505 goto parse_error;
2506
2507 hostname_list[gw_count] = strdup(hname);
2508 if (hostname_list[gw_count] == NULL) {
2509 perror("telnet: copying hostname from list");
2510 return (-1);
2511 }
2512
2513 if (++gw_count > MAXMAX_GATEWAY) {
2514 (void) fprintf(stderr, "telnet: too many gateways\n");
2515 return (-1);
2516 }
2517
2518 /* Jump over the next delimiter. */
2519 if (*cp != '\0') {
2520 /* ...gw1,@gw2... accepted */
2521 if (*cp == ',' && *(cp + 1) == '@')
2522 cp += 2;
2523 else
2524 cp++;
2525 }
2526 }
2527
2528 /* discount the target */
2529 gw_count--;
2530
2531 /* Any input starting with '!@' or '@' must have at least one gateway */
2532 if (gw_count <= 0)
2533 goto parse_error;
2534
2535 return (gw_count);
2536
2537 parse_error:
2538 (void) printf("Bad source route option: %s\n", cmd_line_input);
2539 return (-1);
2540 #endif /* ICMD */
2541 }
2542
2543 /*
2544 * Resolves the target and gateway addresses, determines what type of addresses
2545 * (ALL_ADDRS, ONLY_V6, ONLY_V4) telnet will be trying to connect.
2546 *
2547 * Returns: pointer to resolved target if name resolutions succeed
2548 * NULL if name resolutions fail or
2549 * a library function call fails
2550 *
2551 * The last host in the hostname_list is the target. After resolving the target,
2552 * determines for what type of addresses it should try to resolve gateways. It
2553 * resolves gateway addresses and picks one address for each desired address
2554 * type and stores in the array pointed by gw_addrsp. Also, this 'type of
2555 * addresses' is pointed by addr_type argument on successful return.
2556 */
2557 static struct addrinfo *
resolve_hosts(char ** hostname_list,int num_gw,struct gateway ** gw_addrsp,int * addr_type,const char * portp)2558 resolve_hosts(char **hostname_list, int num_gw, struct gateway **gw_addrsp,
2559 int *addr_type, const char *portp)
2560 {
2561 struct gateway *gw_addrs = NULL;
2562 struct gateway *gw;
2563 /* whether we already picked an IPv4 address for the current gateway */
2564 boolean_t got_v4_addr;
2565 boolean_t got_v6_addr;
2566 /* whether we need to get an IPv4 address for the current gateway */
2567 boolean_t need_v4_addr = B_FALSE;
2568 boolean_t need_v6_addr = B_FALSE;
2569 int res_failed_at4; /* save which gateway failed to resolve */
2570 int res_failed_at6;
2571 boolean_t is_v4mapped;
2572 struct in6_addr *v6addrp;
2573 struct in_addr *v4addrp;
2574 int error_num;
2575 int i;
2576 int rc;
2577 struct addrinfo *res, *host, *gateway, *addr;
2578 struct addrinfo hints;
2579
2580 *addr_type = ALL_ADDRS;
2581
2582 memset(&hints, 0, sizeof (hints));
2583 hints.ai_flags = AI_CANONNAME; /* used for config files, diags */
2584 hints.ai_socktype = SOCK_STREAM;
2585 rc = getaddrinfo(hostname_list[num_gw],
2586 (portp != NULL) ? portp : "telnet", &hints, &res);
2587 if (rc != 0) {
2588 if (hostname_list[num_gw] != NULL &&
2589 *hostname_list[num_gw] != '\0')
2590 (void) fprintf(stderr, "%s: ", hostname_list[num_gw]);
2591 (void) fprintf(stderr, "%s\n", gai_strerror(rc));
2592 return (NULL);
2593 }
2594
2595 /*
2596 * Let's see what type of addresses we got for the target. This
2597 * determines what type of addresses we'd like to resolve gateways
2598 * later.
2599 */
2600 for (host = res; host != NULL; host = host->ai_next) {
2601 struct sockaddr_in6 *s6;
2602
2603 s6 = (struct sockaddr_in6 *)host->ai_addr;
2604
2605 if (host->ai_addr->sa_family == AF_INET ||
2606 IN6_IS_ADDR_V4MAPPED(&s6->sin6_addr))
2607 need_v4_addr = B_TRUE;
2608 else
2609 need_v6_addr = B_TRUE;
2610
2611 /*
2612 * Let's stop after seeing we need both IPv6 and IPv4.
2613 */
2614 if (need_v4_addr && need_v6_addr)
2615 break;
2616 }
2617
2618 if (num_gw > 0) {
2619 /*
2620 * In the prepare_optbuf(), we'll store the IPv4 address of the
2621 * target in the last slot of gw_addrs array. Therefore we need
2622 * space for num_gw+1 hosts.
2623 */
2624 gw_addrs = calloc(num_gw + 1, sizeof (struct gateway));
2625 if (gw_addrs == NULL) {
2626 perror("telnet: calloc");
2627 freeaddrinfo(res);
2628 return (NULL);
2629 }
2630 }
2631
2632 /*
2633 * Now we'll go through all the gateways and try to resolve them to
2634 * the desired address types.
2635 */
2636 gw = gw_addrs;
2637
2638 /* -1 means 'no address resolution failure yet' */
2639 res_failed_at4 = -1;
2640 res_failed_at6 = -1;
2641 for (i = 0; i < num_gw; i++) {
2642 rc = getaddrinfo(hostname_list[i], NULL, NULL, &gateway);
2643 if (rc != 0) {
2644 if (hostname_list[i] != NULL &&
2645 *hostname_list[i] != '\0')
2646 (void) fprintf(stderr, "%s: ",
2647 hostname_list[i]);
2648 (void) fprintf(stderr, "bad address\n");
2649 return (NULL);
2650 }
2651
2652 /*
2653 * Initially we have no address of any type for this gateway.
2654 */
2655 got_v6_addr = B_FALSE;
2656 got_v4_addr = B_FALSE;
2657
2658 /*
2659 * Let's go through all the addresses of this gateway.
2660 * Use the first address which matches the needed family.
2661 */
2662 for (addr = gateway; addr != NULL; addr = addr->ai_next) {
2663 /*LINTED*/
2664 v6addrp = &((struct sockaddr_in6 *)addr->ai_addr)->
2665 sin6_addr;
2666 v4addrp = &((struct sockaddr_in *)addr->ai_addr)->
2667 sin_addr;
2668
2669 if (addr->ai_family == AF_INET6)
2670 is_v4mapped = IN6_IS_ADDR_V4MAPPED(v6addrp);
2671 else
2672 is_v4mapped = B_FALSE;
2673
2674 /*
2675 * If we need to determine an IPv4 address and haven't
2676 * found one yet and this is a IPv4-mapped IPv6 address,
2677 * then bingo!
2678 */
2679 if (need_v4_addr && !got_v4_addr) {
2680 if (is_v4mapped) {
2681 IN6_V4MAPPED_TO_INADDR(v6addrp,
2682 &gw->gw_addr);
2683 got_v4_addr = B_TRUE;
2684 } else if (addr->ai_family = AF_INET) {
2685 gw->gw_addr = *v4addrp;
2686 got_v4_addr = B_TRUE;
2687 }
2688 }
2689
2690 if (need_v6_addr && !got_v6_addr &&
2691 addr->ai_family == AF_INET6) {
2692 gw->gw_addr6 = *v6addrp;
2693 got_v6_addr = B_TRUE;
2694 }
2695
2696 /*
2697 * Let's stop if we got all what we looked for.
2698 */
2699 if ((!need_v4_addr || got_v4_addr) &&
2700 (!need_v6_addr || got_v6_addr))
2701 break;
2702 }
2703
2704 /*
2705 * We needed an IPv4 address for this gateway but couldn't
2706 * find one.
2707 */
2708 if (need_v4_addr && !got_v4_addr) {
2709 res_failed_at4 = i;
2710 /*
2711 * Since we couldn't resolve a gateway to IPv4 address
2712 * we can't use IPv4 at all. Therefore we no longer
2713 * need IPv4 addresses for any of the gateways.
2714 */
2715 need_v4_addr = B_FALSE;
2716 }
2717
2718 if (need_v6_addr && !got_v6_addr) {
2719 res_failed_at6 = i;
2720 need_v6_addr = B_FALSE;
2721 }
2722
2723 /*
2724 * If some gateways don't resolve to any of the desired
2725 * address types, we fail.
2726 */
2727 if (!need_v4_addr && !need_v6_addr) {
2728 if (res_failed_at6 != -1) {
2729 (void) fprintf(stderr,
2730 "%s: Host doesn't have any IPv6 address\n",
2731 hostname_list[res_failed_at6]);
2732 }
2733 if (res_failed_at4 != -1) {
2734 (void) fprintf(stderr,
2735 "%s: Host doesn't have any IPv4 address\n",
2736 hostname_list[res_failed_at4]);
2737 }
2738 free(gw_addrs);
2739 return (NULL);
2740 }
2741
2742 gw++;
2743 }
2744
2745 *gw_addrsp = gw_addrs;
2746
2747 /*
2748 * When we get here, need_v4_addr and need_v6_addr have their final
2749 * values based on the name resolution of the target and gateways.
2750 */
2751 if (need_v4_addr && need_v6_addr)
2752 *addr_type = ALL_ADDRS;
2753 else if (need_v4_addr && !need_v6_addr)
2754 *addr_type = ONLY_V4;
2755 else if (!need_v4_addr && need_v6_addr)
2756 *addr_type = ONLY_V6;
2757
2758 return (res);
2759 }
2760
2761
2762 /*
2763 * Initializes the buffer pointed by opt_bufpp for a IPv4 option of type
2764 * src_rtng_type using the gateway addresses stored in gw_addrs. If no buffer
2765 * is passed, it allocates one. If a buffer is passed, checks if it's big
2766 * enough.
2767 * On return opt_buf_len points to the buffer length which we need later for the
2768 * setsockopt() call, and opt_bufpp points to the newly allocated or already
2769 * passed buffer. Returns B_FALSE if a library function call fails or passed
2770 * buffer is not big enough, B_TRUE otherwise.
2771 */
2772 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)2773 prepare_optbuf(struct gateway *gw_addrs, int num_gw, char **opt_bufpp,
2774 size_t *opt_buf_len, struct in_addr *target, uchar_t src_rtng_type)
2775 {
2776 struct ip_sourceroute *sr_opt;
2777 size_t needed_buflen;
2778 int i;
2779
2780 /*
2781 * We have (num_gw + 1) IP addresses in the buffer because the number
2782 * of gateway addresses we put in the option buffer includes the target
2783 * address.
2784 * At the time of setsockopt() call, passed option length needs to be
2785 * multiple of 4 bytes. Therefore we need one IPOPT_NOP before (or
2786 * after) IPOPT_LSRR.
2787 * 1 = preceding 1 byte of IPOPT_NOP
2788 * 3 = 1 (code) + 1 (len) + 1 (ptr)
2789 */
2790 needed_buflen = 1 + 3 + (num_gw + 1) * sizeof (struct in_addr);
2791
2792 if (*opt_bufpp != NULL) {
2793 /* check if the passed buffer is big enough */
2794 if (*opt_buf_len < needed_buflen) {
2795 (void) fprintf(stderr,
2796 "telnet: buffer too small for IPv4 source routing "
2797 "option\n");
2798 return (B_FALSE);
2799 }
2800 } else {
2801 *opt_bufpp = malloc(needed_buflen);
2802 if (*opt_bufpp == NULL) {
2803 perror("telnet: malloc");
2804 return (B_FALSE);
2805 }
2806 }
2807
2808 *opt_buf_len = needed_buflen;
2809
2810 /* final hop is the target */
2811 gw_addrs[num_gw].gw_addr = *target;
2812
2813 *opt_bufpp[0] = IPOPT_NOP;
2814 /* IPOPT_LSRR starts right after IPOPT_NOP */
2815 sr_opt = (struct ip_sourceroute *)(*opt_bufpp + 1);
2816 sr_opt->ipsr_code = src_rtng_type;
2817 /* discount the 1 byte of IPOPT_NOP */
2818 sr_opt->ipsr_len = needed_buflen - 1;
2819 sr_opt->ipsr_ptr = IPOPT_MINOFF;
2820
2821 /* copy the gateways into the optlist */
2822 for (i = 0; i < num_gw + 1; i++) {
2823 (void) bcopy(&gw_addrs[i].gw_addr, &sr_opt->ipsr_addrs[i],
2824 sizeof (struct in_addr));
2825 }
2826
2827 return (B_TRUE);
2828 }
2829
2830 /*
2831 * Initializes the buffer pointed by opt_bufpp for a IPv6 routing header option
2832 * using the gateway addresses stored in gw_addrs. If no buffer is passed, it
2833 * allocates one. If a buffer is passed, checks if it's big enough.
2834 * On return opt_buf_len points to the buffer length which we need later for the
2835 * setsockopt() call, and opt_bufpp points to the newly allocated or already
2836 * passed buffer. Returns B_FALSE if a library function call fails or passed
2837 * buffer is not big enough, B_TRUE otherwise.
2838 */
2839 static boolean_t
prepare_optbuf6(struct gateway * gw_addrs,int num_gw,char ** opt_bufpp,size_t * opt_buf_len)2840 prepare_optbuf6(struct gateway *gw_addrs, int num_gw, char **opt_bufpp,
2841 size_t *opt_buf_len)
2842 {
2843 char *opt_bufp;
2844 size_t needed_buflen;
2845 int i;
2846
2847 needed_buflen = inet6_rth_space(IPV6_RTHDR_TYPE_0, num_gw);
2848
2849 if (*opt_bufpp != NULL) {
2850 /* check if the passed buffer is big enough */
2851 if (*opt_buf_len < needed_buflen) {
2852 (void) fprintf(stderr,
2853 "telnet: buffer too small for IPv6 routing "
2854 "header option\n");
2855 return (B_FALSE);
2856 }
2857 } else {
2858 *opt_bufpp = malloc(needed_buflen);
2859 if (*opt_bufpp == NULL) {
2860 perror("telnet: malloc");
2861 return (B_FALSE);
2862 }
2863 }
2864 *opt_buf_len = needed_buflen;
2865 opt_bufp = *opt_bufpp;
2866
2867 /*
2868 * Initialize the buffer to be used for IPv6 routing header type 0.
2869 */
2870 if (inet6_rth_init(opt_bufp, needed_buflen, IPV6_RTHDR_TYPE_0,
2871 num_gw) == NULL) {
2872 perror("telnet: inet6_rth_init");
2873 return (B_FALSE);
2874 }
2875
2876 /*
2877 * Add gateways one by one.
2878 */
2879 for (i = 0; i < num_gw; i++) {
2880 if (inet6_rth_add(opt_bufp, &gw_addrs[i].gw_addr6) == -1) {
2881 perror("telnet: inet6_rth_add");
2882 return (B_FALSE);
2883 }
2884 }
2885
2886 /* successful operation */
2887 return (B_TRUE);
2888 }
2889
2890 int
tn(int argc,char * argv[])2891 tn(int argc, char *argv[])
2892 {
2893 struct addrinfo *host = NULL;
2894 struct addrinfo *h;
2895 struct sockaddr_in6 sin6;
2896 struct sockaddr_in sin;
2897 struct in6_addr addr6;
2898 struct in_addr addr;
2899 void *addrp;
2900 struct gateway *gw_addrs;
2901 char *hostname_list[MAXMAX_GATEWAY + 1] = {NULL};
2902 char *opt_buf6 = NULL; /* used for IPv6 routing header */
2903 size_t opt_buf_len6 = 0;
2904 uchar_t src_rtng_type; /* type of IPv4 source routing */
2905 struct servent *sp = 0;
2906 char *opt_buf = NULL; /* used for IPv4 source routing */
2907 size_t opt_buf_len = 0;
2908 char *cmd;
2909 char *hostp = NULL;
2910 char *portp = NULL;
2911 char *user = NULL;
2912 #ifdef ICMD
2913 char *itelnet_host;
2914 char *real_host;
2915 unsigned short dest_port;
2916 #endif /* ICMD */
2917 /*
2918 * The two strings at the end of this function are 24 and 39
2919 * characters long (minus the %.*s in the format strings). Add
2920 * one for the null terminator making the longest print string 40.
2921 */
2922 char buf[MAXHOSTNAMELEN+40];
2923 /*
2924 * In the case of ICMD defined, dest_port will contain the real port
2925 * we are trying to telnet to, and target_port will contain
2926 * "telnet-passthru" port.
2927 */
2928 unsigned short target_port;
2929 char abuf[INET6_ADDRSTRLEN];
2930 int num_gw;
2931 int ret_val;
2932 boolean_t is_v4mapped;
2933 /*
2934 * Type of addresses we'll try to connect to (ALL_ADDRS, ONLY_V6,
2935 * ONLY_V4).
2936 */
2937 int addr_type;
2938
2939 /* clear the socket address prior to use */
2940 (void) memset(&sin6, '\0', sizeof (sin6));
2941 sin6.sin6_family = AF_INET6;
2942
2943 (void) memset(&sin, '\0', sizeof (sin));
2944 sin.sin_family = AF_INET;
2945
2946 if (connected) {
2947 (void) printf("?Already connected to %s\n", hostname);
2948 return (0);
2949 }
2950 #ifdef ICMD
2951 itelnet_host = getenv("INTERNET_HOST");
2952 if (itelnet_host == NULL || itelnet_host[0] == '\0') {
2953 (void) printf("INTERNET_HOST environment variable undefined\n");
2954 goto tn_exit;
2955 }
2956 #endif
2957 if (argc < 2) {
2958 (void) printf("(to) ");
2959 if (GetAndAppendString(&line, &linesize, "open ",
2960 stdin) == NULL) {
2961 if (!feof(stdin)) {
2962 perror("telnet");
2963 goto tn_exit;
2964 }
2965 }
2966 makeargv();
2967 argc = margc;
2968 argv = margv;
2969 }
2970 cmd = *argv;
2971 --argc; ++argv;
2972 while (argc) {
2973 if (isprefix(*argv, "help") == 4 || isprefix(*argv, "?") == 1)
2974 goto usage;
2975 if (strcmp(*argv, "-l") == 0) {
2976 --argc; ++argv;
2977 if (argc == 0)
2978 goto usage;
2979 user = *argv++;
2980 --argc;
2981 continue;
2982 }
2983 if (strcmp(*argv, "-a") == 0) {
2984 --argc; ++argv;
2985 autologin = autologin_set = 1;
2986 continue;
2987 }
2988 if (hostp == 0) {
2989 hostp = *argv++;
2990 --argc;
2991 continue;
2992 }
2993 if (portp == 0) {
2994 portp = *argv++;
2995 --argc;
2996 /*
2997 * Do we treat this like a telnet port or raw?
2998 */
2999 if (*portp == '-') {
3000 portp++;
3001 telnetport = 1;
3002 } else
3003 telnetport = 0;
3004 continue;
3005 }
3006 usage:
3007 (void) printf(
3008 "usage: %s [-l user] [-a] host-name [port]\n", cmd);
3009 goto tn_exit;
3010 }
3011 if (hostp == 0)
3012 goto usage;
3013
3014 #ifdef ICMD
3015 /*
3016 * For setup phase treat the relay host as the target host.
3017 */
3018 real_host = hostp;
3019 hostp = itelnet_host;
3020 #endif
3021 num_gw = parse_input(hostp, hostname_list, &src_rtng_type);
3022 if (num_gw < 0) {
3023 goto tn_exit;
3024 }
3025
3026 /* Last host in the hostname_list is the target */
3027 hostp = hostname_list[num_gw];
3028
3029 host = resolve_hosts(hostname_list, num_gw, &gw_addrs, &addr_type,
3030 portp);
3031 if (host == NULL) {
3032 goto tn_exit;
3033 }
3034
3035 /*
3036 * Check if number of gateways is less than max. available
3037 */
3038 if ((addr_type == ALL_ADDRS || addr_type == ONLY_V6) &&
3039 num_gw > MAX_GATEWAY6) {
3040 (void) fprintf(stderr, "telnet: too many IPv6 gateways\n");
3041 goto tn_exit;
3042 }
3043
3044 if ((addr_type == ALL_ADDRS || addr_type == ONLY_V4) &&
3045 num_gw > MAX_GATEWAY) {
3046 (void) fprintf(stderr, "telnet: too many IPv4 gateways\n");
3047 goto tn_exit;
3048 }
3049
3050 /*
3051 * If we pass a literal IPv4 address to getaddrinfo(), in the
3052 * returned addrinfo structure, hostname is the IPv4-mapped IPv6
3053 * address string. We prefer to preserve the literal IPv4 address
3054 * string as the hostname. Also, if the hostname entered by the
3055 * user is IPv4-mapped IPv6 address, we'll downgrade it to IPv4
3056 * address.
3057 */
3058 if (inet_addr(hostp) != (in_addr_t)-1) {
3059 /* this is a literal IPv4 address */
3060 (void) strlcpy(_hostname, hostp, sizeof (_hostname));
3061 } else if ((inet_pton(AF_INET6, hostp, &addr6) > 0) &&
3062 IN6_IS_ADDR_V4MAPPED(&addr6)) {
3063 /* this is a IPv4-mapped IPv6 address */
3064 IN6_V4MAPPED_TO_INADDR(&addr6, &addr);
3065 (void) inet_ntop(AF_INET, &addr, _hostname, sizeof (_hostname));
3066 } else {
3067 (void) strlcpy(_hostname, host->ai_canonname,
3068 sizeof (_hostname));
3069 }
3070 hostname = _hostname;
3071
3072 if (portp == NULL) {
3073 telnetport = 1;
3074 }
3075
3076 if (host->ai_family == AF_INET) {
3077 target_port = ((struct sockaddr_in *)(host->ai_addr))->sin_port;
3078 } else {
3079 target_port = ((struct sockaddr_in6 *)(host->ai_addr))
3080 ->sin6_port;
3081 }
3082
3083 #ifdef ICMD
3084 /*
3085 * Since we pass the port number as an ascii string to the proxy,
3086 * we need it in host format.
3087 */
3088 dest_port = ntohs(target_port);
3089 sp = getservbyname("telnet-passthru", "tcp");
3090 if (sp == 0) {
3091 (void) fprintf(stderr,
3092 "telnet: tcp/telnet-passthru: unknown service\n");
3093 goto tn_exit;
3094 }
3095 target_port = sp->s_port;
3096 #endif
3097 h = host;
3098
3099 /*
3100 * For IPv6 source routing, we need to initialize option buffer only
3101 * once.
3102 */
3103 if (num_gw > 0 && (addr_type == ALL_ADDRS || addr_type == ONLY_V6)) {
3104 if (!prepare_optbuf6(gw_addrs, num_gw, &opt_buf6,
3105 &opt_buf_len6)) {
3106 goto tn_exit;
3107 }
3108 }
3109
3110 /*
3111 * We procure the Kerberos config files options only
3112 * if the user has choosen Krb5 authentication.
3113 */
3114 if (krb5auth_flag > 0) {
3115 krb5_profile_get_options(hostname, telnet_krb5_realm,
3116 config_file_options);
3117 }
3118
3119 if (encrypt_flag) {
3120 extern boolean_t auth_enable_encrypt;
3121 if (krb5_privacy_allowed()) {
3122 encrypt_auto(1);
3123 decrypt_auto(1);
3124 wantencryption = B_TRUE;
3125 autologin = 1;
3126 auth_enable_encrypt = B_TRUE;
3127 } else {
3128 (void) fprintf(stderr, gettext(
3129 "%s:Encryption not supported.\n"), prompt);
3130 exit(1);
3131 }
3132 }
3133
3134 if (forward_flag && forwardable_flag) {
3135 (void) fprintf(stderr, gettext(
3136 "Error in krb5 configuration file. "
3137 "Both forward and forwardable are set.\n"));
3138 exit(1);
3139 }
3140 if (forwardable_flag) {
3141 forward_flags |= OPTS_FORWARD_CREDS | OPTS_FORWARDABLE_CREDS;
3142 } else if (forward_flag)
3143 forward_flags |= OPTS_FORWARD_CREDS;
3144
3145
3146 do {
3147 /*
3148 * Search for an address of desired type in the IP address list
3149 * of the target.
3150 */
3151 while (h != NULL) {
3152 struct sockaddr_in6 *addr;
3153
3154 addr = (struct sockaddr_in6 *)h->ai_addr;
3155
3156 if (h->ai_family == AF_INET6)
3157 is_v4mapped =
3158 IN6_IS_ADDR_V4MAPPED(&addr->sin6_addr);
3159 else
3160 is_v4mapped = B_FALSE;
3161
3162 if (addr_type == ALL_ADDRS ||
3163 (addr_type == ONLY_V6 &&
3164 h->ai_family == AF_INET6) ||
3165 (addr_type == ONLY_V4 &&
3166 (h->ai_family == AF_INET || is_v4mapped)))
3167 break;
3168
3169 /* skip undesired typed addresses */
3170 h = h->ai_next;
3171 }
3172
3173 if (h == NULL) {
3174 fprintf(stderr,
3175 "telnet: Unable to connect to remote host");
3176 goto tn_exit;
3177 }
3178
3179 /*
3180 * We need to open a socket with a family matching the type of
3181 * address we are trying to connect to. This is because we
3182 * deal with IPv4 options and IPv6 extension headers.
3183 */
3184 if (h->ai_family == AF_INET) {
3185 addrp = &((struct sockaddr_in *)(h->ai_addr))->sin_addr;
3186 ((struct sockaddr_in *)(h->ai_addr))->sin_port =
3187 target_port;
3188 } else {
3189 addrp = &((struct sockaddr_in6 *)(h->ai_addr))
3190 ->sin6_addr;
3191 ((struct sockaddr_in6 *)(h->ai_addr))->sin6_port =
3192 target_port;
3193 }
3194
3195 (void) printf("Trying %s...\n", inet_ntop(h->ai_family,
3196 addrp, abuf, sizeof (abuf)));
3197
3198 net = socket(h->ai_family, SOCK_STREAM, 0);
3199
3200 if (net < 0) {
3201 perror("telnet: socket");
3202 goto tn_exit;
3203 }
3204 #ifndef ICMD
3205 if (num_gw > 0) {
3206 if (h->ai_family == AF_INET || is_v4mapped) {
3207 if (!prepare_optbuf(gw_addrs, num_gw, &opt_buf,
3208 &opt_buf_len, addrp, src_rtng_type)) {
3209 goto tn_exit;
3210 }
3211
3212 if (setsockopt(net, IPPROTO_IP, IP_OPTIONS,
3213 opt_buf, opt_buf_len) < 0)
3214 perror("setsockopt (IP_OPTIONS)");
3215 } else {
3216 if (setsockopt(net, IPPROTO_IPV6, IPV6_RTHDR,
3217 opt_buf6, opt_buf_len6) < 0)
3218 perror("setsockopt (IPV6_RTHDR)");
3219 }
3220 }
3221 #endif
3222 #if defined(USE_TOS)
3223 if (is_v4mapped) {
3224 if (tos < 0)
3225 tos = 020; /* Low Delay bit */
3226 if (tos &&
3227 (setsockopt(net, IPPROTO_IP, IP_TOS,
3228 &tos, sizeof (int)) < 0) &&
3229 (errno != ENOPROTOOPT))
3230 perror("telnet: setsockopt (IP_TOS) (ignored)");
3231 }
3232 #endif /* defined(USE_TOS) */
3233
3234 if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
3235 perror("setsockopt (SO_DEBUG)");
3236 }
3237
3238 ret_val = connect(net, h->ai_addr, h->ai_addrlen);
3239
3240 /*
3241 * If failed, try the next address of the target.
3242 */
3243 if (ret_val < 0) {
3244 Close(&net);
3245 if (h->ai_next != NULL) {
3246
3247 int oerrno = errno;
3248
3249 (void) fprintf(stderr,
3250 "telnet: connect to address %s: ", abuf);
3251 errno = oerrno;
3252 perror((char *)0);
3253
3254 h = h->ai_next;
3255 continue;
3256 }
3257 perror("telnet: Unable to connect to remote host");
3258 goto tn_exit;
3259 }
3260 connected++;
3261 } while (connected == 0);
3262 freeaddrinfo(host);
3263 host = NULL;
3264 #ifdef ICMD
3265 /*
3266 * Do initial protocol to connect to farther end...
3267 */
3268 {
3269 char buf[1024];
3270 (void) sprintf(buf, "%s %d\n", real_host, (int)dest_port);
3271 write(net, buf, strlen(buf));
3272 }
3273 #endif
3274 if (cmdrc(hostp, hostname) != 0)
3275 goto tn_exit;
3276 FreeHostnameList(hostname_list);
3277 if (autologin && user == NULL) {
3278 struct passwd *pw;
3279
3280 user = getenv("LOGNAME");
3281 if (user == NULL ||
3282 ((pw = getpwnam(user)) != NULL) &&
3283 pw->pw_uid != getuid()) {
3284 if (pw = getpwuid(getuid()))
3285 user = pw->pw_name;
3286 else
3287 user = NULL;
3288 }
3289 }
3290
3291 if (user) {
3292 if (env_define((unsigned char *)"USER", (unsigned char *)user))
3293 env_export((unsigned char *)"USER");
3294 else {
3295 /* Clean up and exit. */
3296 Close(&net);
3297 (void) snprintf(buf, sizeof (buf),
3298 "Connection to %.*s closed.\n",
3299 MAXHOSTNAMELEN, hostname);
3300 ExitString(buf, EXIT_FAILURE);
3301
3302 /* NOTREACHED */
3303 }
3304 }
3305 (void) call(3, status, "status", "notmuch");
3306 if (setjmp(peerdied) == 0)
3307 telnet(user);
3308
3309 Close(&net);
3310
3311 (void) snprintf(buf, sizeof (buf),
3312 "Connection to %.*s closed by foreign host.\n",
3313 MAXHOSTNAMELEN, hostname);
3314 ExitString(buf, EXIT_FAILURE);
3315
3316 /*NOTREACHED*/
3317
3318 tn_exit:
3319 FreeHostnameList(hostname_list);
3320 Close(&net);
3321 connected = 0;
3322 if (host != NULL)
3323 freeaddrinfo(host);
3324 return (0);
3325 }
3326
3327 #define HELPINDENT (sizeof ("connect"))
3328
3329 static char openhelp[] = "connect to a site";
3330 static char closehelp[] = "close current connection";
3331 static char logouthelp[] =
3332 "forcibly logout remote user and close the connection";
3333 static char quithelp[] = "exit telnet";
3334 static char statushelp[] = "print status information";
3335 static char helphelp[] = "print help information";
3336 static char sendhelp[] =
3337 "transmit special characters ('send ?' for more)";
3338 static char sethelp[] = "set operating parameters ('set ?' for more)";
3339 static char unsethelp[] = "unset operating parameters ('unset ?' for more)";
3340 static char togglestring[] =
3341 "toggle operating parameters ('toggle ?' for more)";
3342 static char slchelp[] = "change state of special charaters ('slc ?' for more)";
3343 static char displayhelp[] = "display operating parameters";
3344 static char authhelp[] =
3345 "turn on (off) authentication ('auth ?' for more)";
3346 static char forwardhelp[] =
3347 "turn on (off) credential forwarding ('forward ?' for more)";
3348 static char encrypthelp[] =
3349 "turn on (off) encryption ('encrypt ?' for more)";
3350 static char zhelp[] = "suspend telnet";
3351 static char shellhelp[] = "invoke a subshell";
3352 static char envhelp[] = "change environment variables ('environ ?' for more)";
3353 static char modestring[] =
3354 "try to enter line or character mode ('mode ?' for more)";
3355
3356 static int help();
3357
3358 static Command cmdtab[] = {
3359 { "close", closehelp, bye, 1 },
3360 { "logout", logouthelp, logout, 1 },
3361 { "display", displayhelp, display, 0 },
3362 { "mode", modestring, modecmd, 0 },
3363 { "open", openhelp, tn, 0 },
3364 { "quit", quithelp, quit, 0 },
3365 { "send", sendhelp, sendcmd, 0 },
3366 { "set", sethelp, setcmd, 0 },
3367 { "unset", unsethelp, unsetcmd, 0 },
3368 { "status", statushelp, status, 0 },
3369 { "toggle", togglestring, toggle, 0 },
3370 { "slc", slchelp, slccmd, 0 },
3371 { "auth", authhelp, auth_cmd, 0 },
3372 { "encrypt", encrypthelp, encrypt_cmd, 0 },
3373 { "forward", forwardhelp, forw_cmd, 0 },
3374 { "z", zhelp, suspend, 0 },
3375 { "!", shellhelp, shell, 0 },
3376 { "environ", envhelp, env_cmd, 0 },
3377 { "?", helphelp, help, 0 },
3378 0
3379 };
3380
3381
3382 static Command cmdtab2[] = {
3383 { "help", 0, help, 0 },
3384 { "escape", 0, setescape, 0 },
3385 { "crmod", 0, togcrmod, 0 },
3386 0
3387 };
3388
3389
3390 /*
3391 * Call routine with argc, argv set from args.
3392 * Uses /usr/include/stdarg.h
3393 */
3394 #define MAXVARGS 100
3395 /*VARARGS1*/
3396 static void
call(int n_ptrs,...)3397 call(int n_ptrs, ...)
3398 {
3399 va_list ap;
3400 typedef int (*intrtn_t)();
3401 intrtn_t routine;
3402 char *args[MAXVARGS+1]; /* leave 1 for trailing NULL */
3403 int argno = 0;
3404
3405 if (n_ptrs > MAXVARGS)
3406 n_ptrs = MAXVARGS;
3407 va_start(ap, n_ptrs);
3408
3409 routine = (va_arg(ap, intrtn_t)); /* extract the routine's name */
3410 n_ptrs--;
3411
3412 while (argno < n_ptrs) /* extract the routine's args */
3413 args[argno++] = va_arg(ap, char *);
3414 args[argno] = NULL; /* NULL terminate for good luck */
3415 va_end(ap);
3416
3417 (*routine)(argno, args);
3418 }
3419
3420
3421 static Command *
getcmd(char * name)3422 getcmd(char *name)
3423 {
3424 Command *cm;
3425
3426 if (cm = (Command *) genget(name, (char **)cmdtab, sizeof (Command)))
3427 return (cm);
3428 return (Command *) genget(name, (char **)cmdtab2, sizeof (Command));
3429 }
3430
3431 void
command(int top,char * tbuf,int cnt)3432 command(int top, char *tbuf, int cnt)
3433 {
3434 Command *c;
3435
3436 setcommandmode();
3437 if (!top) {
3438 (void) putchar('\n');
3439 } else {
3440 (void) signal(SIGINT, SIG_DFL);
3441 (void) signal(SIGQUIT, SIG_DFL);
3442 }
3443 for (;;) {
3444 if (rlogin == _POSIX_VDISABLE)
3445 (void) printf("%s> ", prompt);
3446 if (tbuf) {
3447 char *cp;
3448 if (AllocStringBuffer(&line, &linesize, cnt) == NULL)
3449 goto command_exit;
3450 cp = line;
3451 while (cnt > 0 && (*cp++ = *tbuf++) != '\n')
3452 cnt--;
3453 tbuf = 0;
3454 if (cp == line || *--cp != '\n' || cp == line)
3455 goto getline;
3456 *cp = '\0';
3457 if (rlogin == _POSIX_VDISABLE)
3458 (void) printf("%s\n", line);
3459 } else {
3460 getline:
3461 if (rlogin != _POSIX_VDISABLE)
3462 (void) printf("%s> ", prompt);
3463 if (GetString(&line, &linesize, stdin) == NULL) {
3464 if (!feof(stdin))
3465 perror("telnet");
3466 (void) quit();
3467 /*NOTREACHED*/
3468 break;
3469 }
3470 }
3471 if (line[0] == 0)
3472 break;
3473 makeargv();
3474 if (margv[0] == 0) {
3475 break;
3476 }
3477 c = getcmd(margv[0]);
3478 if (Ambiguous(c)) {
3479 (void) printf("?Ambiguous command\n");
3480 continue;
3481 }
3482 if (c == 0) {
3483 (void) printf("?Invalid command\n");
3484 continue;
3485 }
3486 if (c->needconnect && !connected) {
3487 (void) printf("?Need to be connected first.\n");
3488 continue;
3489 }
3490 if ((*c->handler)(margc, margv)) {
3491 break;
3492 }
3493 }
3494 command_exit:
3495 if (!top) {
3496 if (!connected) {
3497 longjmp(toplevel, 1);
3498 /*NOTREACHED*/
3499 }
3500 setconnmode(0);
3501 }
3502 }
3503
3504 /*
3505 * Help command.
3506 */
3507 static int
help(int argc,char * argv[])3508 help(int argc, char *argv[])
3509 {
3510 Command *c;
3511
3512 if (argc == 1) {
3513 (void) printf(
3514 "Commands may be abbreviated. Commands are:\n\n");
3515 for (c = cmdtab; c->name; c++)
3516 if (c->help) {
3517 (void) printf("%-*s\t%s\n", HELPINDENT,
3518 c->name, c->help);
3519 }
3520 (void) printf("<return>\tleave command mode\n");
3521 return (0);
3522 }
3523 while (--argc > 0) {
3524 char *arg;
3525 arg = *++argv;
3526 c = getcmd(arg);
3527 if (Ambiguous(c))
3528 (void) printf("?Ambiguous help command %s\n", arg);
3529 else if (c == (Command *)0)
3530 (void) printf("?Invalid help command %s\n", arg);
3531 else if (c->help) {
3532 (void) printf("%s\n", c->help);
3533 } else {
3534 (void) printf("No additional help on %s\n", arg);
3535 }
3536 }
3537 return (0);
3538 }
3539
3540 static char *rcname = NULL;
3541 #define TELNETRC_NAME "telnetrc"
3542 #define TELNETRC_COMP "/." TELNETRC_NAME
3543
3544 static int
cmdrc(char * m1,char * m2)3545 cmdrc(char *m1, char *m2)
3546 {
3547 Command *c;
3548 FILE *rcfile = NULL;
3549 int gotmachine = 0;
3550 int l1 = strlen(m1);
3551 int l2 = strlen(m2);
3552 char m1save[MAXHOSTNAMELEN];
3553 int ret = 0;
3554 char def[] = "DEFAULT";
3555
3556 if (skiprc)
3557 goto cmdrc_exit;
3558
3559 doing_rc = 1;
3560
3561 (void) strlcpy(m1save, m1, sizeof (m1save));
3562 m1 = m1save;
3563
3564 if (rcname == NULL) {
3565 char *homedir;
3566 unsigned rcbuflen;
3567
3568 if ((homedir = getenv("HOME")) == NULL)
3569 homedir = "";
3570
3571 rcbuflen = strlen(homedir) + strlen(TELNETRC_COMP) + 1;
3572 if ((rcname = malloc(rcbuflen)) == NULL) {
3573 perror("telnet: can't process " TELNETRC_NAME);
3574 ret = 1;
3575 goto cmdrc_exit;
3576 }
3577 (void) strcpy(rcname, homedir);
3578 (void) strcat(rcname, TELNETRC_COMP);
3579 }
3580
3581 if ((rcfile = fopen(rcname, "r")) == NULL)
3582 goto cmdrc_exit;
3583
3584 for (;;) {
3585 if (GetString(&line, &linesize, rcfile) == NULL) {
3586 if (!feof(rcfile)) {
3587 perror("telnet: error reading " TELNETRC_NAME);
3588 ret = 1;
3589 goto cmdrc_exit;
3590 }
3591 break;
3592 }
3593 if (line[0] == 0)
3594 continue;
3595 if (line[0] == '#')
3596 continue;
3597 if (gotmachine) {
3598 if (!isspace(line[0]))
3599 gotmachine = 0;
3600 }
3601 if (gotmachine == 0) {
3602 if (isspace(line[0]))
3603 continue;
3604 if (strncasecmp(line, m1, l1) == 0)
3605 (void) strcpy(line, &line[l1]);
3606 else if (strncasecmp(line, m2, l2) == 0)
3607 (void) strcpy(line, &line[l2]);
3608 else if (strncasecmp(line, def, sizeof (def) - 1) == 0)
3609 (void) strcpy(line, &line[sizeof (def) - 1]);
3610 else
3611 continue;
3612 if (line[0] != ' ' && line[0] != '\t' &&
3613 line[0] != '\n')
3614 continue;
3615 gotmachine = 1;
3616 }
3617 makeargv();
3618 if (margv[0] == 0)
3619 continue;
3620 c = getcmd(margv[0]);
3621 if (Ambiguous(c)) {
3622 (void) printf("?Ambiguous command: %s\n", margv[0]);
3623 continue;
3624 }
3625 if (c == 0) {
3626 (void) printf("?Invalid command: %s\n", margv[0]);
3627 continue;
3628 }
3629 /*
3630 * This should never happen...
3631 */
3632 if (c->needconnect && !connected) {
3633 (void) printf("?Need to be connected first for %s.\n",
3634 margv[0]);
3635 continue;
3636 }
3637 (*c->handler)(margc, margv);
3638 }
3639 cmdrc_exit:
3640 if (rcfile != NULL)
3641 (void) fclose(rcfile);
3642 doing_rc = 0;
3643
3644 return (ret);
3645 }
3646