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