Home | History | Annotate | Download | only in telnet
      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
    153 Close(int *fd)
    154 {
    155 	if (*fd != -1) {
    156 		(void) close(*fd);
    157 		*fd = -1;
    158 	}
    159 }
    160 
    161 static void
    162 Free(char **p)
    163 {
    164 	if (*p != NULL) {
    165 		free(*p);
    166 		*p = NULL;
    167 	}
    168 }
    169 
    170 static void
    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
    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
    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
    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 *
    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 *
    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
    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
    516 send_esc()
    517 {
    518 	NETADD(escape);
    519 	return (1);
    520 }
    521 
    522 static int
    523 send_docmd(name)
    524 	char *name;
    525 {
    526 	return (send_tncmd(send_do, "do", name));
    527 }
    528 
    529 static int
    530 send_dontcmd(name)
    531 	char *name;
    532 {
    533 	return (send_tncmd(send_dont, "dont", name));
    534 }
    535 
    536 static int
    537 send_willcmd(name)
    538 	char *name;
    539 {
    540 	return (send_tncmd(send_will, "will", name));
    541 }
    542 
    543 static int
    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
    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
    633 lclchars()
    634 {
    635 	donelclchars = 1;
    636 	return (1);
    637 }
    638 
    639 static int
    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
    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
    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
    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
    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
    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
    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
    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 *
   1023 getset(name)
   1024     char *name;
   1025 {
   1026 	return ((struct setlist *)
   1027 	    genget(name, (char **)Setlist, sizeof (struct setlist)));
   1028 }
   1029 
   1030     void
   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
   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
   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
   1203