Home | History | Annotate | Download | only in telnet
      1 /*
      2  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
      7 
      8 /*
      9  * Copyright (c) 1988, 1990, 1993
     10  *	The Regents of the University of California.  All rights reserved.
     11  *
     12  * Redistribution and use in source and binary forms, with or without
     13  * modification, are permitted provided that the following conditions
     14  * are met:
     15  * 1. Redistributions of source code must retain the above copyright
     16  *    notice, this list of conditions and the following disclaimer.
     17  * 2. Redistributions in binary form must reproduce the above copyright
     18  *    notice, this list of conditions and the following disclaimer in the
     19  *    documentation and/or other materials provided with the distribution.
     20  * 3. All advertising materials mentioning features or use of this software
     21  *    must display the following acknowledgement:
     22  *	This product includes software developed by the University of
     23  *	California, Berkeley and its contributors.
     24  * 4. Neither the name of the University nor the names of its contributors
     25  *    may be used to endorse or promote products derived from this software
     26  *    without specific prior written permission.
     27  *
     28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     38  * SUCH DAMAGE.
     39  */
     40 
     41 #ifndef lint
     42 static char sccsid[] = "@(#)telnet.c	8.1 (Berkeley) 6/6/93";
     43 #endif /* not lint */
     44 
     45 #include <netdb.h>
     46 #include <sys/types.h>
     47 
     48 #include <curses.h>
     49 #include <signal.h>
     50 /*
     51  * By the way, we need to include curses.h before telnet.h since,
     52  * among other things, telnet.h #defines 'DO', which is a variable
     53  * declared in curses.h.
     54  */
     55 
     56 #include <arpa/telnet.h>
     57 
     58 #include <ctype.h>
     59 
     60 #include "ring.h"
     61 
     62 #include "defines.h"
     63 #include "externs.h"
     64 #include "types.h"
     65 #include "general.h"
     66 
     67 #include "auth.h"
     68 #include "encrypt.h"
     69 
     70 #define	strip(x)	((x)&0x7f)
     71 
     72 /* Buffer for sub-options */
     73 static unsigned char	subbuffer[SUBBUFSIZE];
     74 static unsigned char	*subpointer;
     75 static unsigned char	*subend;
     76 
     77 #define	SB_CLEAR()	subpointer = subbuffer;
     78 #define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
     79 #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof (subbuffer))) { \
     80 				*subpointer++ = (c); \
     81 			}
     82 
     83 #define	SB_GET()	((*subpointer++)&0xff)
     84 #define	SB_PEEK()	((*subpointer)&0xff)
     85 #define	SB_EOF()	(subpointer >= subend)
     86 #define	SB_LEN()	(subend - subpointer)
     87 
     88 char	options[SUBBUFSIZE];		/* The combined options */
     89 char	do_dont_resp[SUBBUFSIZE];
     90 char	will_wont_resp[SUBBUFSIZE];
     91 
     92 int eight = 0;
     93 int autologin = 0;	/* Autologin anyone? */
     94 int skiprc = 0;
     95 int connected;
     96 int showoptions;
     97 static int ISend;	/* trying to send network data in */
     98 int debug = 0;
     99 int crmod;
    100 int netdata;		/* Print out network data flow */
    101 int crlf;		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
    102 int telnetport;
    103 int SYNCHing;		/* we are in TELNET SYNCH mode */
    104 int flushout;		/* flush output */
    105 int autoflush = 0;	/* flush output when interrupting? */
    106 int autosynch;		/* send interrupt characters with SYNCH? */
    107 int localflow;		/* we handle flow control locally */
    108 int restartany;		/* if flow control enabled, restart on any character */
    109 int localchars;		/* we recognize interrupt/quit */
    110 int donelclchars;	/* the user has set "localchars" */
    111 int donebinarytoggle;	/* the user has put us in binary */
    112 int dontlecho;		/* do we suppress local echoing right now? */
    113 int eof_pending = 0;	/* we received a genuine EOF on input, send IAC-EOF */
    114 int globalmode;
    115 
    116 /* spin while waiting for authentication */
    117 boolean_t scheduler_lockout_tty = B_FALSE;
    118 int encrypt_flag = 0;
    119 int forwardable_flag = 0;
    120 int forward_flag = 0;
    121 boolean_t wantencryption = B_FALSE;
    122 
    123 char *prompt = 0;
    124 
    125 cc_t escape;
    126 cc_t rlogin;
    127 boolean_t escape_valid = B_TRUE;
    128 #ifdef	KLUDGELINEMODE
    129 cc_t echoc;
    130 #endif
    131 
    132 /*
    133  * Telnet receiver states for fsm
    134  */
    135 #define	TS_DATA		0
    136 #define	TS_IAC		1
    137 #define	TS_WILL		2
    138 #define	TS_WONT		3
    139 #define	TS_DO		4
    140 #define	TS_DONT		5
    141 #define	TS_CR		6
    142 #define	TS_SB		7		/* sub-option collection */
    143 #define	TS_SE		8		/* looking for sub-option end */
    144 
    145 static int	telrcv_state;
    146 #ifdef	OLD_ENVIRON
    147 static	unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
    148 #else
    149 #define	telopt_environ	TELOPT_NEW_ENVIRON
    150 #endif
    151 
    152 jmp_buf	toplevel = { 0 };
    153 jmp_buf	peerdied;
    154 
    155 static int flushline;
    156 int	linemode;
    157 
    158 int	reqd_linemode = 0; /* Set if either new or old line mode in */
    159 			/* effect since before initial negotiations */
    160 
    161 #ifdef	KLUDGELINEMODE
    162 int	kludgelinemode = 1;
    163 #endif
    164 
    165 /*
    166  * The following are some clocks used to decide how to interpret
    167  * the relationship between various variables.
    168  */
    169 
    170 Clocks clocks;
    171 
    172 #ifdef	notdef
    173 Modelist modelist[] = {
    174 	{ "telnet command mode", COMMAND_LINE },
    175 	{ "character-at-a-time mode", 0 },
    176 	{ "character-at-a-time mode (local echo)", LOCAL_ECHO|LOCAL_CHARS },
    177 	{ "line-by-line mode (remote echo)", LINE | LOCAL_CHARS },
    178 	{ "line-by-line mode", LINE | LOCAL_ECHO | LOCAL_CHARS },
    179 	{ "line-by-line mode (local echoing suppressed)", LINE | LOCAL_CHARS },
    180 	{ "3270 mode", 0 },
    181 };
    182 #endif
    183 
    184 static void willoption(int);
    185 static void wontoption(int);
    186 static void lm_will(unsigned char *, int);
    187 static void lm_wont(unsigned char *, int);
    188 static void lm_do(unsigned char *, int);
    189 static void lm_dont(unsigned char *, int);
    190 static void slc_init(void);
    191 static void slc_import(int);
    192 static void slc_export(void);
    193 static void slc_start_reply(size_t);
    194 static void slc_add_reply(unsigned char, unsigned char, cc_t);
    195 static void slc_end_reply(void);
    196 static void slc(unsigned char *, int);
    197 static int slc_update(void);
    198 static void env_opt(unsigned char *, int);
    199 static void env_opt_start(void);
    200 static void sendeof(void);
    201 static int is_unique(register char *, register char **, register char **);
    202 
    203 /*
    204  * Initialize telnet environment.
    205  */
    206 
    207 int
    208 init_telnet()
    209 {
    210 	if (env_init() == 0)
    211 		return (0);
    212 
    213 	SB_CLEAR();
    214 	ClearArray(options);
    215 
    216 	connected = ISend = localflow = donebinarytoggle = 0;
    217 	restartany = -1;
    218 
    219 	SYNCHing = 0;
    220 
    221 	/* Don't change NetTrace */
    222 
    223 	escape = CONTROL(']');
    224 	rlogin = _POSIX_VDISABLE;
    225 #ifdef	KLUDGELINEMODE
    226 	echoc = CONTROL('E');
    227 #endif
    228 
    229 	flushline = 1;
    230 	telrcv_state = TS_DATA;
    231 
    232 	return (1);
    233 }
    234 
    235 
    236 #ifdef	notdef
    237 #include <varargs.h>
    238 
    239 /*VARARGS*/
    240 static void
    241 printring(va_alist)
    242 	va_dcl
    243 {
    244 	va_list ap;
    245 	char buffer[100];		/* where things go */
    246 	char *ptr;
    247 	char *format;
    248 	char *string;
    249 	Ring *ring;
    250 	int i;
    251 
    252 	va_start(ap);
    253 
    254 	ring = va_arg(ap, Ring *);
    255 	format = va_arg(ap, char *);
    256 	ptr = buffer;
    257 
    258 	while ((i = *format++) != 0) {
    259 		if (i == '%') {
    260 			i = *format++;
    261 			switch (i) {
    262 			case 'c':
    263 				*ptr++ = va_arg(ap, int);
    264 				break;
    265 			case 's':
    266 				string = va_arg(ap, char *);
    267 				ring_supply_data(ring, buffer, ptr-buffer);
    268 				ring_supply_data(ring, string, strlen(string));
    269 				ptr = buffer;
    270 				break;
    271 			case 0:
    272 				ExitString("printring: trailing %%.\n",
    273 				    EXIT_FAILURE);
    274 				/*NOTREACHED*/
    275 			default:
    276 				ExitString("printring: unknown format "
    277 				    "character.\n", EXIT_FAILURE);
    278 				/*NOTREACHED*/
    279 			}
    280 		} else {
    281 			*ptr++ = i;
    282 		}
    283 	}
    284 	ring_supply_data(ring, buffer, ptr-buffer);
    285 }
    286 #endif
    287 
    288 /*
    289  * These routines are in charge of sending option negotiations
    290  * to the other side.
    291  *
    292  * The basic idea is that we send the negotiation if either side
    293  * is in disagreement as to what the current state should be.
    294  */
    295 
    296 void
    297 send_do(c, init)
    298 	register int c, init;
    299 {
    300 	if (init) {
    301 		if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
    302 		    my_want_state_is_do(c))
    303 			return;
    304 		set_my_want_state_do(c);
    305 		do_dont_resp[c]++;
    306 	}
    307 	NET2ADD(IAC, DO);
    308 	NETADD(c);
    309 	printoption("SENT", DO, c);
    310 }
    311 
    312 void
    313 send_dont(c, init)
    314 	register int c, init;
    315 {
    316 	if (init) {
    317 		if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
    318 		    my_want_state_is_dont(c))
    319 			return;
    320 		set_my_want_state_dont(c);
    321 		do_dont_resp[c]++;
    322 	}
    323 	NET2ADD(IAC, DONT);
    324 	NETADD(c);
    325 	printoption("SENT", DONT, c);
    326 }
    327 
    328 void
    329 send_will(c, init)
    330 	register int c, init;
    331 {
    332 	if (init) {
    333 		if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
    334 		    my_want_state_is_will(c))
    335 			return;
    336 		set_my_want_state_will(c);
    337 		will_wont_resp[c]++;
    338 	}
    339 	NET2ADD(IAC, WILL);
    340 	NETADD(c);
    341 	printoption("SENT", WILL, c);
    342 }
    343 
    344 void
    345 send_wont(c, init)
    346 	register int c, init;
    347 {
    348 	if (init) {
    349 		if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
    350 		    my_want_state_is_wont(c))
    351 			return;
    352 		set_my_want_state_wont(c);
    353 		will_wont_resp[c]++;
    354 	}
    355 	NET2ADD(IAC, WONT);
    356 	NETADD(c);
    357 	printoption("SENT", WONT, c);
    358 }
    359 
    360 
    361 static void
    362 willoption(option)
    363 	int option;
    364 {
    365 	int new_state_ok = 0;
    366 
    367 	if (do_dont_resp[option]) {
    368 	    --do_dont_resp[option];
    369 	    if (do_dont_resp[option] && my_state_is_do(option))
    370 		--do_dont_resp[option];
    371 	}
    372 
    373 	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
    374 
    375 	    switch (option) {
    376 
    377 	    case TELOPT_ECHO:
    378 	    case TELOPT_SGA:
    379 		if (reqd_linemode && my_state_is_dont(option)) {
    380 		    break;
    381 		}
    382 		/* FALLTHROUGH */
    383 	    case TELOPT_BINARY:
    384 		settimer(modenegotiated);
    385 		/* FALLTHROUGH */
    386 	    case TELOPT_STATUS:
    387 	    case TELOPT_AUTHENTICATION:
    388 		/* FALLTHROUGH */
    389 	    case TELOPT_ENCRYPT:
    390 		new_state_ok = 1;
    391 		break;
    392 
    393 	    case TELOPT_TM:
    394 		if (flushout)
    395 		    flushout = 0;
    396 		/*
    397 		 * Special case for TM.  If we get back a WILL,
    398 		 * pretend we got back a WONT.
    399 		 */
    400 		set_my_want_state_dont(option);
    401 		set_my_state_dont(option);
    402 		return;			/* Never reply to TM will's/wont's */
    403 
    404 	    case TELOPT_LINEMODE:
    405 	    default:
    406 		break;
    407 	    }
    408 
    409 	    if (new_state_ok) {
    410 		set_my_want_state_do(option);
    411 		send_do(option, 0);
    412 		setconnmode(0);		/* possibly set new tty mode */
    413 	    } else {
    414 		do_dont_resp[option]++;
    415 		send_dont(option, 0);
    416 	    }
    417 	}
    418 	set_my_state_do(option);
    419 	if (option == TELOPT_ENCRYPT)
    420 		encrypt_send_support();
    421 }
    422 
    423 static void
    424 wontoption(option)
    425 	int option;
    426 {
    427 	if (do_dont_resp[option]) {
    428 		--do_dont_resp[option];
    429 		if (do_dont_resp[option] && my_state_is_dont(option))
    430 			--do_dont_resp[option];
    431 	}
    432 
    433 	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
    434 
    435 		switch (option) {
    436 
    437 #ifdef	KLUDGELINEMODE
    438 		case TELOPT_SGA:
    439 			if (!kludgelinemode)
    440 				break;
    441 			/* FALLTHROUGH */
    442 #endif
    443 		case TELOPT_ECHO:
    444 			settimer(modenegotiated);
    445 			break;
    446 
    447 		case TELOPT_TM:
    448 			if (flushout)
    449 				flushout = 0;
    450 			set_my_want_state_dont(option);
    451 			set_my_state_dont(option);
    452 			return;		/* Never reply to TM will's/wont's */
    453 
    454 		default:
    455 			break;
    456 		}
    457 		set_my_want_state_dont(option);
    458 		if (my_state_is_do(option))
    459 			send_dont(option, 0);
    460 		setconnmode(0);			/* Set new tty mode */
    461 	} else if (option == TELOPT_TM) {
    462 		/*
    463 		 * Special case for TM.
    464 		 */
    465 		if (flushout)
    466 			flushout = 0;
    467 		set_my_want_state_dont(option);
    468 	}
    469 	set_my_state_dont(option);
    470 }
    471 
    472 static void
    473 dooption(option)
    474 	int option;
    475 {
    476 	int new_state_ok = 0;
    477 
    478 	if (will_wont_resp[option]) {
    479 		--will_wont_resp[option];
    480 		if (will_wont_resp[option] && my_state_is_will(option))
    481 			--will_wont_resp[option];
    482 	}
    483 
    484 	if (will_wont_resp[option] == 0) {
    485 		if (my_want_state_is_wont(option)) {
    486 
    487 			switch (option) {
    488 
    489 			case TELOPT_TM:
    490 				/*
    491 				 * Special case for TM.  We send a WILL,
    492 				 * but pretend we sent WONT.
    493 				 */
    494 				send_will(option, 0);
    495 				set_my_want_state_wont(TELOPT_TM);
    496 				set_my_state_wont(TELOPT_TM);
    497 				return;
    498 
    499 			case TELOPT_BINARY:	/* binary mode */
    500 			case TELOPT_NAWS:	/* window size */
    501 			case TELOPT_TSPEED:	/* terminal speed */
    502 			case TELOPT_LFLOW:	/* local flow control */
    503 			case TELOPT_TTYPE:	/* terminal type option */
    504 			case TELOPT_SGA:	/* no big deal */
    505 			case TELOPT_ENCRYPT:	/* encryption variable option */
    506 				new_state_ok = 1;
    507 				break;
    508 
    509 			case TELOPT_NEW_ENVIRON:
    510 				/* New environment variable option */
    511 #ifdef	OLD_ENVIRON
    512 				if (my_state_is_will(TELOPT_OLD_ENVIRON))
    513 					/* turn off the old */
    514 					send_wont(TELOPT_OLD_ENVIRON, 1);
    515 goto env_common;
    516 			case TELOPT_OLD_ENVIRON:
    517 				/* Old environment variable option */
    518 				if (my_state_is_will(TELOPT_NEW_ENVIRON))
    519 					/* Don't enable if new one is in use! */
    520 					break;
    521 env_common:
    522 				telopt_environ = option;
    523 #endif
    524 				new_state_ok = 1;
    525 				break;
    526 
    527 			case TELOPT_AUTHENTICATION:
    528 				if (autologin)
    529 					new_state_ok = 1;
    530 				break;
    531 
    532 			case TELOPT_XDISPLOC:	/* X Display location */
    533 				if (env_getvalue((unsigned char *)"DISPLAY"))
    534 					new_state_ok = 1;
    535 				break;
    536 
    537 			case TELOPT_LINEMODE:
    538 #ifdef	KLUDGELINEMODE
    539 				kludgelinemode = 0;
    540 				send_do(TELOPT_SGA, 1);
    541 #endif
    542 				set_my_want_state_will(TELOPT_LINEMODE);
    543 				send_will(option, 0);
    544 				set_my_state_will(TELOPT_LINEMODE);
    545 				slc_init();
    546 				return;
    547 
    548 			case TELOPT_ECHO: /* We're never going to echo... */
    549 			default:
    550 				break;
    551 			}
    552 
    553 			if (new_state_ok) {
    554 				set_my_want_state_will(option);
    555 				send_will(option, 0);
    556 				setconnmode(0);		/* Set new tty mode */
    557 			} else {
    558 				will_wont_resp[option]++;
    559 				send_wont(option, 0);
    560 			}
    561 		} else {
    562 			/*
    563 			 * Handle options that need more things done after the
    564 			 * other side has acknowledged the option.
    565 			 */
    566 			switch (option) {
    567 			case TELOPT_LINEMODE:
    568 #ifdef	KLUDGELINEMODE
    569 				kludgelinemode = 0;
    570 				send_do(TELOPT_SGA, 1);
    571 #endif
    572 				set_my_state_will(option);
    573 				slc_init();
    574 				send_do(TELOPT_SGA, 0);
    575 				return;
    576 			}
    577 		}
    578 	}
    579 	set_my_state_will(option);
    580 }
    581 
    582 	static void
    583 dontoption(option)
    584 	int option;
    585 {
    586 
    587 	if (will_wont_resp[option]) {
    588 	    --will_wont_resp[option];
    589 	    if (will_wont_resp[option] && my_state_is_wont(option))
    590 		--will_wont_resp[option];
    591 	}
    592 
    593 	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
    594 	    switch (option) {
    595 	    case TELOPT_LINEMODE:
    596 		linemode = 0;	/* put us back to the default state */
    597 		break;
    598 #ifdef	OLD_ENVIRON
    599 	    case TELOPT_NEW_ENVIRON:
    600 		/*
    601 		 * The new environ option wasn't recognized, try
    602 		 * the old one.
    603 		 */
    604 		send_will(TELOPT_OLD_ENVIRON, 1);
    605 		telopt_environ = TELOPT_OLD_ENVIRON;
    606 		break;
    607 #endif
    608 	    }
    609 	    /* we always accept a DONT */
    610 	    set_my_want_state_wont(option);
    611 	    if (my_state_is_will(option))
    612 		send_wont(option, 0);
    613 	    setconnmode(0);			/* Set new tty mode */
    614 	}
    615 	set_my_state_wont(option);
    616 }
    617 
    618 /*
    619  * Given a buffer returned by tgetent(), this routine will turn
    620  * the pipe seperated list of names in the buffer into an array
    621  * of pointers to null terminated names.  We toss out any bad,
    622  * duplicate, or verbose names (names with spaces).
    623  */
    624 
    625 static char *name_unknown = "UNKNOWN";
    626 static char *unknown[] = { 0, 0 };
    627 
    628 static char **
    629 mklist(buf, name)
    630 	char *buf, *name;
    631 {
    632 	register int n;
    633 	register char c, *cp, **argvp, *cp2, **argv, **avt;
    634 
    635 	if (name) {
    636 		if (strlen(name) > 40u) {
    637 			name = 0;
    638 			unknown[0] = name_unknown;
    639 		} else {
    640 			unknown[0] = name;
    641 			upcase(name);
    642 		}
    643 	} else
    644 		unknown[0] = name_unknown;
    645 	/*
    646 	 * Count up the number of names.
    647 	 */
    648 	for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
    649 		if (*cp == '|')
    650 			n++;
    651 	}
    652 	/*
    653 	 * Allocate an array to put the name pointers into
    654 	 */
    655 	argv = malloc((n+3)*sizeof (char *));
    656 	if (argv == 0)
    657 		return (unknown);
    658 
    659 	/*
    660 	 * Fill up the array of pointers to names.
    661 	 */
    662 	*argv = 0;
    663 	argvp = argv+1;
    664 	n = 0;
    665 	for (cp = cp2 = buf; (c = *cp) != NULL;  cp++) {
    666 		if (c == '|' || c == ':') {
    667 			*cp++ = '\0';
    668 			/*
    669 			 * Skip entries that have spaces or are over 40
    670 			 * characters long.  If this is our environment
    671 			 * name, then put it up front.  Otherwise, as
    672 			 * long as this is not a duplicate name (case
    673 			 * insensitive) add it to the list.
    674 			 */
    675 			if (n || (cp - cp2 > 41))
    676 				/* EMPTY */;
    677 			else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
    678 				*argv = cp2;
    679 			else if (is_unique(cp2, argv+1, argvp))
    680 				*argvp++ = cp2;
    681 			if (c == ':')
    682 				break;
    683 			/*
    684 			 * Skip multiple delimiters. Reset cp2 to
    685 			 * the beginning of the next name. Reset n,
    686 			 * the flag for names with spaces.
    687 			 */
    688 			while ((c = *cp) == '|')
    689 				cp++;
    690 			cp2 = cp;
    691 			n = 0;
    692 		}
    693 		/*
    694 		 * Skip entries with spaces or non-ascii values.
    695 		 * Convert lower case letters to upper case.
    696 		 */
    697 		if ((c == ' ') || !isascii(c))
    698 			n = 1;
    699 		else if (islower(c))
    700 			*cp = toupper(c);
    701 	}
    702 
    703 	/*
    704 	 * Check for an old V6 2 character name.  If the second
    705 	 * name points to the beginning of the buffer, and is
    706 	 * only 2 characters long, move it to the end of the array.
    707 	 */
    708 	if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
    709 		--argvp;
    710 		for (avt = &argv[1]; avt < argvp; avt++)
    711 			*avt = *(avt+1);
    712 		*argvp++ = buf;
    713 	}
    714 
    715 	/*
    716 	 * Duplicate last name, for TTYPE option, and null
    717 	 * terminate the array.  If we didn't find a match on
    718 	 * our terminal name, put that name at the beginning.
    719 	 */
    720 	cp = *(argvp-1);
    721 	*argvp++ = cp;
    722 	*argvp = 0;
    723 
    724 	if (*argv == 0) {
    725 		if (name)
    726 			*argv = name;
    727 		else {
    728 			--argvp;
    729 			for (avt = argv; avt < argvp; avt++)
    730 				*avt = *(avt+1);
    731 		}
    732 	}
    733 	if (*argv)
    734 		return (argv);
    735 	else
    736 		return (unknown);
    737 }
    738 
    739 static int
    740 is_unique(name, as, ae)
    741 	register char *name, **as, **ae;
    742 {
    743 	register char **ap;
    744 	register int n;
    745 
    746 	n = strlen(name) + 1;
    747 	for (ap = as; ap < ae; ap++)
    748 		if (strncasecmp(*ap, name, n) == 0)
    749 			return (0);
    750 	return (1);
    751 }
    752 
    753 #define	termbuf	ttytype
    754 extern char ttytype[];
    755 
    756 int resettermname = 1;
    757 
    758 static char *
    759 gettermname(void)
    760 {
    761 	char *tname;
    762 	static char **tnamep = 0;
    763 	static char **next;
    764 	int err;
    765 
    766 	if (resettermname) {
    767 		resettermname = 0;
    768 		if (tnamep && tnamep != unknown)
    769 			free(tnamep);
    770 		tname = (char *)env_getvalue((unsigned char *)"TERM");
    771 		if ((tname != NULL) && (setupterm(tname, 1, &err) == 0)) {
    772 			tnamep = mklist(termbuf, tname);
    773 		} else {
    774 			if (tname && (strlen(tname) <= 40u)) {
    775 				unknown[0] = tname;
    776 				upcase(tname);
    777 			} else
    778 				unknown[0] = name_unknown;
    779 			tnamep = unknown;
    780 		}
    781 		next = tnamep;
    782 	}
    783 	if (*next == 0)
    784 		next = tnamep;
    785 	return (*next++);
    786 }
    787 /*
    788  * suboption()
    789  *
    790  *	Look at the sub-option buffer, and try to be helpful to the other
    791  * side.
    792  *
    793  *	Currently we recognize:
    794  *
    795  *		Terminal type, send request.
    796  *		Terminal speed (send request).
    797  *		Local flow control (is request).
    798  *		Linemode
    799  */
    800 
    801     static void
    802 suboption()
    803 {
    804 	unsigned char subchar;
    805 
    806 	printsub('<', subbuffer, SB_LEN()+2);
    807 	switch (subchar = SB_GET()) {
    808 	case TELOPT_TTYPE:
    809 		if (my_want_state_is_wont(TELOPT_TTYPE))
    810 			return;
    811 		if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
    812 			return;
    813 		} else {
    814 			char *name;
    815 			unsigned char temp[50];
    816 			int len, bytes;
    817 
    818 			name = gettermname();
    819 			len = strlen(name) + 4 + 2;
    820 			bytes = snprintf((char *)temp, sizeof (temp),
    821 				"%c%c%c%c%s%c%c", IAC, SB,
    822 				TELOPT_TTYPE, TELQUAL_IS, name, IAC, SE);
    823 			if ((len < NETROOM()) && (bytes < sizeof (temp))) {
    824 					ring_supply_data(&netoring, temp, len);
    825 					printsub('>', &temp[2], len-2);
    826 			} else {
    827 				ExitString("No room in buffer for "
    828 				    "terminal type.\n", EXIT_FAILURE);
    829 				/*NOTREACHED*/
    830 			}
    831 		}
    832 		break;
    833 	case TELOPT_TSPEED:
    834 		if (my_want_state_is_wont(TELOPT_TSPEED))
    835 			return;
    836 		if (SB_EOF())
    837 			return;
    838 		if (SB_GET() == TELQUAL_SEND) {
    839 			int ospeed, ispeed;
    840 			unsigned char temp[50];
    841 			int len, bytes;
    842 
    843 			TerminalSpeeds(&ispeed, &ospeed);
    844 
    845 			bytes = snprintf((char *)temp, sizeof (temp),
    846 			    "%c%c%c%c%d,%d%c%c", IAC, SB,
    847 			    TELOPT_TSPEED, TELQUAL_IS, ospeed, ispeed, IAC, SE);
    848 			len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
    849 
    850 			if ((len < NETROOM()) && (bytes < sizeof (temp))) {
    851 				ring_supply_data(&netoring, temp, len);
    852 				printsub('>', temp+2, len - 2);
    853 			}
    854 			else
    855 				(void) printf(
    856 				    "telnet: not enough room in buffer "
    857 				    "for terminal speed option reply\n");
    858 		}
    859 		break;
    860 	case TELOPT_LFLOW:
    861 		if (my_want_state_is_wont(TELOPT_LFLOW))
    862 			return;
    863 		if (SB_EOF())
    864 			return;
    865 		switch (SB_GET()) {
    866 		case LFLOW_RESTART_ANY:
    867 			restartany = 1;
    868 			break;
    869 		case LFLOW_RESTART_XON:
    870 			restartany = 0;
    871 			break;
    872 		case LFLOW_ON:
    873 			localflow = 1;
    874 			break;
    875 		case LFLOW_OFF:
    876 			localflow = 0;
    877 			break;
    878 		default:
    879 			return;
    880 		}
    881 		setcommandmode();
    882 		setconnmode(0);
    883 		break;
    884 
    885 	case TELOPT_LINEMODE:
    886 		if (my_want_state_is_wont(TELOPT_LINEMODE))
    887 			return;
    888 		if (SB_EOF())
    889 			return;
    890 		switch (SB_GET()) {
    891 		case WILL:
    892 			lm_will(subpointer, SB_LEN());
    893 			break;
    894 		case WONT:
    895 			lm_wont(subpointer, SB_LEN());
    896 			break;
    897 		case DO:
    898 			lm_do(subpointer, SB_LEN());
    899 			break;
    900 		case DONT:
    901 			lm_dont(subpointer, SB_LEN());
    902 			break;
    903 		case LM_SLC:
    904 			slc(subpointer, SB_LEN());
    905 			break;
    906 		case LM_MODE:
    907 			lm_mode(subpointer, SB_LEN(), 0);
    908 			break;
    909 		default:
    910 			break;
    911 		}
    912 		break;
    913 
    914 #ifdef	OLD_ENVIRON
    915 	case TELOPT_OLD_ENVIRON:
    916 #endif
    917 	case TELOPT_NEW_ENVIRON:
    918 		if (SB_EOF())
    919 			return;
    920 		switch (SB_PEEK()) {
    921 		case TELQUAL_IS:
    922 		case TELQUAL_INFO:
    923 			if (my_want_state_is_dont(subchar))
    924 				return;
    925 			break;
    926 		case TELQUAL_SEND:
    927 			if (my_want_state_is_wont(subchar)) {
    928 				return;
    929 			}
    930 			break;
    931 		default:
    932 			return;
    933 		}
    934 		env_opt(subpointer, SB_LEN());
    935 		break;
    936 
    937 	case TELOPT_XDISPLOC:
    938 		if (my_want_state_is_wont(TELOPT_XDISPLOC))
    939 			return;
    940 		if (SB_EOF())
    941 			return;
    942 		if (SB_GET() == TELQUAL_SEND) {
    943 			unsigned char temp[50], *dp;
    944 			int len, bytes;
    945 
    946 			if ((dp = env_getvalue((unsigned char *)"DISPLAY")) ==
    947 			    NULL) {
    948 				/*
    949 				 * Something happened, we no longer have a
    950 				 * DISPLAY variable.  So, turn off the option.
    951 				 */
    952 				send_wont(TELOPT_XDISPLOC, 1);
    953 				break;
    954 			}
    955 			bytes = snprintf((char *)temp, sizeof (temp),
    956 			    "%c%c%c%c%s%c%c", IAC, SB,
    957 			    TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE);
    958 			len = strlen((char *)temp+4) + 4; /* temp[3] is 0 ... */
    959 
    960 			if ((len < NETROOM()) && (bytes < sizeof (temp))) {
    961 				ring_supply_data(&netoring, temp, len);
    962 				printsub('>', temp+2, len - 2);
    963 			}
    964 			else
    965 				(void) printf(
    966 				    "telnet: not enough room in buffer"
    967 				    " for display location option reply\n");
    968 		}
    969 		break;
    970 
    971 	case TELOPT_AUTHENTICATION: {
    972 		if (!autologin)
    973 			break;
    974 		if (SB_EOF())
    975 			return;
    976 		switch (SB_GET()) {
    977 		case TELQUAL_SEND:
    978 			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
    979 				return;
    980 			auth_send(subpointer, SB_LEN());
    981 			break;
    982 		case TELQUAL_REPLY:
    983 			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
    984 				return;
    985 			auth_reply(subpointer, SB_LEN());
    986 			break;
    987 		}
    988 	}
    989 	break;
    990 
    991 	case TELOPT_ENCRYPT:
    992 		if (SB_EOF())
    993 			return;
    994 		switch (SB_GET()) {
    995 		case ENCRYPT_START:
    996 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
    997 				return;
    998 			encrypt_start(subpointer, SB_LEN());
    999 			break;
   1000 		case ENCRYPT_END:
   1001 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
   1002 				return;
   1003 			encrypt_end();
   1004 			break;
   1005 		case ENCRYPT_SUPPORT:
   1006 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
   1007 				return;
   1008 			encrypt_support(subpointer, SB_LEN());
   1009 			break;
   1010 		case ENCRYPT_REQSTART:
   1011 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
   1012 				return;
   1013 			encrypt_request_start(subpointer, SB_LEN());
   1014 			break;
   1015 		case ENCRYPT_REQEND:
   1016 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
   1017 				return;
   1018 			/*
   1019 			 * We can always send an REQEND so that we cannot
   1020 			 * get stuck encrypting.  We should only get this
   1021 			 * if we have been able to get in the correct mode
   1022 			 * anyhow.
   1023 			 */
   1024 			encrypt_request_end();
   1025 			break;
   1026 		case ENCRYPT_IS:
   1027 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
   1028 				return;
   1029 			encrypt_is(subpointer, SB_LEN());
   1030 			break;
   1031 		case ENCRYPT_REPLY:
   1032 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
   1033 				return;
   1034 			encrypt_reply(subpointer, SB_LEN());
   1035 			break;
   1036 		case ENCRYPT_ENC_KEYID:
   1037 			if (my_want_state_is_dont(TELOPT_ENCRYPT))
   1038 				return;
   1039 			encrypt_enc_keyid(subpointer, SB_LEN());
   1040 			break;
   1041 		case ENCRYPT_DEC_KEYID:
   1042 			if (my_want_state_is_wont(TELOPT_ENCRYPT))
   1043 				return;
   1044 			encrypt_dec_keyid(subpointer, SB_LEN());
   1045 			break;
   1046 		default:
   1047 			break;
   1048 		}
   1049 		break;
   1050 	default:
   1051 		break;
   1052 	}
   1053 }
   1054 
   1055 static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
   1056 
   1057 static void
   1058 lm_will(cmd, len)
   1059 	unsigned char *cmd;
   1060 	int len;
   1061 {
   1062 	if (len < 1) {
   1063 		/* Should not happen... */
   1064 		(void) printf(
   1065 		    "telnet: command missing from linemode WILL request\n");
   1066 		return;
   1067 	}
   1068 	switch (cmd[0]) {
   1069 	case LM_FORWARDMASK:	/* We shouldn't ever get this... */
   1070 	default:
   1071 		str_lm[3] = DONT;
   1072 		str_lm[4] = cmd[0];
   1073 		if (NETROOM() > sizeof (str_lm)) {
   1074 			ring_supply_data(&netoring, str_lm, sizeof (str_lm));
   1075 			printsub('>', &str_lm[2], sizeof (str_lm)-2);
   1076 		}
   1077 		else
   1078 			(void) printf("telnet: not enough room in buffer for"
   1079 			    "reply to linemode WILL request\n");
   1080 		break;
   1081 	}
   1082 }
   1083 
   1084 static void
   1085 lm_wont(cmd, len)
   1086 	unsigned char *cmd;
   1087 	int len;
   1088 {
   1089 	if (len < 1) {
   1090 		/* Should not happen... */
   1091 		(void) printf(
   1092 		    "telnet: command missing from linemode WONT request\n");
   1093 		return;
   1094 	}
   1095 	switch (cmd[0]) {
   1096 	case LM_FORWARDMASK:	/* We shouldn't ever get this... */
   1097 	default:
   1098 		/* We are always DONT, so don't respond */
   1099 		return;
   1100 	}
   1101 }
   1102 
   1103 static void
   1104 lm_do(cmd, len)
   1105 	unsigned char *cmd;
   1106 	int len;
   1107 {
   1108 	if (len < 1) {
   1109 		/* Should not happen... */
   1110 		(void) printf(
   1111 		    "telnet: command missing from linemode DO request\n");
   1112 		return;
   1113 	}
   1114 	switch (cmd[0]) {
   1115 	case LM_FORWARDMASK:
   1116 	default:
   1117 		str_lm[3] = WONT;
   1118 		str_lm[4] = cmd[0];
   1119 		if (NETROOM() > sizeof (str_lm)) {
   1120 			ring_supply_data(&netoring, str_lm, sizeof (str_lm));
   1121 			printsub('>', &str_lm[2], sizeof (str_lm)-2);
   1122 		}
   1123 		else
   1124 			(void) printf("telnet: not enough room in buffer for"
   1125 			    "reply to linemode DO request\n");
   1126 		break;
   1127 	}
   1128 }
   1129 
   1130 static void
   1131 lm_dont(cmd, len)
   1132 	unsigned char *cmd;
   1133 	int len;
   1134 {
   1135 	if (len < 1) {
   1136 		/* Should not happen... */
   1137 		(void) printf(
   1138 		    "telnet: command missing from linemode DONT request\n");
   1139 		return;
   1140 	}
   1141 	switch (cmd[0]) {
   1142 	case LM_FORWARDMASK:
   1143 	default:
   1144 		/* we are always WONT, so don't respond */
   1145 		break;
   1146 	}
   1147 }
   1148 
   1149 static unsigned char str_lm_mode[] = {
   1150 	IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
   1151 };
   1152 
   1153 	void
   1154 lm_mode(cmd, len, init)
   1155 	unsigned char *cmd;
   1156 	int len, init;
   1157 {
   1158 	if (len != 1)
   1159 		return;
   1160 	if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
   1161 		return;
   1162 	linemode = *cmd&(MODE_MASK&~MODE_ACK);
   1163 	str_lm_mode[4] = linemode;
   1164 	if (!init)
   1165 		str_lm_mode[4] |= MODE_ACK;
   1166 	if (NETROOM() > sizeof (str_lm_mode)) {
   1167 		ring_supply_data(&netoring, str_lm_mode, sizeof (str_lm_mode));
   1168 		printsub('>', &str_lm_mode[2], sizeof (str_lm_mode)-2);
   1169 	}
   1170 	else
   1171 		(void) printf("telnet: not enough room in buffer for"
   1172 		    "reply to linemode request\n");
   1173 	setconnmode(0);	/* set changed mode */
   1174 }
   1175 
   1176 
   1177 
   1178 /*
   1179  * slc()
   1180  * Handle special character suboption of LINEMODE.
   1181  */
   1182 
   1183 static struct spc {
   1184 	cc_t val;
   1185 	cc_t *valp;
   1186 	char flags;	/* Current flags & level */
   1187 	char mylevel;	/* Maximum level & flags */
   1188 } spc_data[NSLC+1];
   1189 
   1190 #define	SLC_IMPORT	0
   1191 #define	SLC_EXPORT	1
   1192 #define	SLC_RVALUE	2
   1193 static int slc_mode = SLC_EXPORT;
   1194 
   1195 static void
   1196 slc_init()
   1197 {
   1198 	register struct spc *spcp;
   1199 
   1200