telnet.c revision 114630
1/*
2 * Copyright (c) 1988, 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by the University of
16 *	California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#if 0
35#ifndef lint
36static const char sccsid[] = "@(#)telnet.c	8.4 (Berkeley) 5/30/95";
37#endif
38#endif
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD: head/contrib/telnet/telnet/telnet.c 114630 2003-05-04 02:54:49Z obrien $");
41
42#include <sys/types.h>
43
44/* By the way, we need to include curses.h before telnet.h since,
45 * among other things, telnet.h #defines 'DO', which is a variable
46 * declared in curses.h.
47 */
48
49#include <ctype.h>
50#include <curses.h>
51#include <signal.h>
52#include <stdlib.h>
53#include <term.h>
54#include <unistd.h>
55#include <arpa/telnet.h>
56
57#include "ring.h"
58
59#include "defines.h"
60#include "externs.h"
61#include "types.h"
62#include "general.h"
63
64#ifdef	AUTHENTICATION
65#include <libtelnet/auth.h>
66#endif
67#ifdef	ENCRYPTION
68#include <libtelnet/encrypt.h>
69#endif
70#include <libtelnet/misc.h>
71
72#define	strip(x) ((my_want_state_is_wont(TELOPT_BINARY)) ? ((x)&0x7f) : (x))
73
74static unsigned char	subbuffer[SUBBUFSIZE],
75			*subpointer, *subend;	 /* buffer for sub-options */
76#define	SB_CLEAR()	subpointer = subbuffer;
77#define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
78#define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
79				*subpointer++ = (c); \
80			}
81
82#define	SB_GET()	((*subpointer++)&0xff)
83#define	SB_PEEK()	((*subpointer)&0xff)
84#define	SB_EOF()	(subpointer >= subend)
85#define	SB_LEN()	(subend - subpointer)
86
87char	options[256];		/* The combined options */
88char	do_dont_resp[256];
89char	will_wont_resp[256];
90
91int
92	eight = 0,
93	autologin = 0,	/* Autologin anyone? */
94	skiprc = 0,
95	connected,
96	showoptions,
97	ISend,		/* trying to send network data in */
98	debug = 0,
99	crmod,
100	netdata,	/* Print out network data flow */
101	crlf,		/* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
102	telnetport,
103	SYNCHing,	/* we are in TELNET SYNCH mode */
104	flushout,	/* flush output */
105	autoflush = 0,	/* flush output when interrupting? */
106	autosynch,	/* send interrupt characters with SYNCH? */
107	localflow,	/* we handle flow control locally */
108	restartany,	/* if flow control enabled, restart on any character */
109	localchars,	/* we recognize interrupt/quit */
110	donelclchars,	/* the user has set "localchars" */
111	donebinarytoggle,	/* the user has put us in binary */
112	dontlecho,	/* do we suppress local echoing right now? */
113	globalmode,
114	doaddrlookup = 1, /* do a reverse address lookup? */
115	clienteof = 0;
116
117char *prompt = 0;
118#ifdef ENCRYPTION
119char *line;		/* hack around breakage in sra.c :-( !! */
120#endif
121
122cc_t escape;
123cc_t rlogin;
124#ifdef	KLUDGELINEMODE
125cc_t echoc;
126#endif
127
128/*
129 * Telnet receiver states for fsm
130 */
131#define	TS_DATA		0
132#define	TS_IAC		1
133#define	TS_WILL		2
134#define	TS_WONT		3
135#define	TS_DO		4
136#define	TS_DONT		5
137#define	TS_CR		6
138#define	TS_SB		7		/* sub-option collection */
139#define	TS_SE		8		/* looking for sub-option end */
140
141static int	telrcv_state;
142#ifdef	OLD_ENVIRON
143unsigned char telopt_environ = TELOPT_NEW_ENVIRON;
144#else
145# define telopt_environ TELOPT_NEW_ENVIRON
146#endif
147
148jmp_buf	toplevel;
149jmp_buf	peerdied;
150
151int	flushline;
152int	linemode;
153
154#ifdef	KLUDGELINEMODE
155int	kludgelinemode = 1;
156#endif
157
158static int is_unique(char *, char **, char **);
159
160/*
161 * The following are some clocks used to decide how to interpret
162 * the relationship between various variables.
163 */
164
165Clocks clocks;
166
167/*
168 * Initialize telnet environment.
169 */
170
171void
172init_telnet(void)
173{
174    env_init();
175
176    SB_CLEAR();
177    ClearArray(options);
178
179    connected = ISend = localflow = donebinarytoggle = 0;
180#ifdef	AUTHENTICATION
181#ifdef	ENCRYPTION
182    auth_encrypt_connect(connected);
183#endif
184#endif
185    restartany = -1;
186
187    SYNCHing = 0;
188
189    /* Don't change NetTrace */
190
191    escape = CONTROL(']');
192    rlogin = _POSIX_VDISABLE;
193#ifdef	KLUDGELINEMODE
194    echoc = CONTROL('E');
195#endif
196
197    flushline = 1;
198    telrcv_state = TS_DATA;
199}
200
201
202/*
203 * These routines are in charge of sending option negotiations
204 * to the other side.
205 *
206 * The basic idea is that we send the negotiation if either side
207 * is in disagreement as to what the current state should be.
208 */
209
210void
211send_do(int c, int init)
212{
213    if (init) {
214	if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
215				my_want_state_is_do(c))
216	    return;
217	set_my_want_state_do(c);
218	do_dont_resp[c]++;
219    }
220    NET2ADD(IAC, DO);
221    NETADD(c);
222    printoption("SENT", DO, c);
223}
224
225void
226send_dont(int c, int init)
227{
228    if (init) {
229	if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
230				my_want_state_is_dont(c))
231	    return;
232	set_my_want_state_dont(c);
233	do_dont_resp[c]++;
234    }
235    NET2ADD(IAC, DONT);
236    NETADD(c);
237    printoption("SENT", DONT, c);
238}
239
240void
241send_will(int c, int init)
242{
243    if (init) {
244	if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
245				my_want_state_is_will(c))
246	    return;
247	set_my_want_state_will(c);
248	will_wont_resp[c]++;
249    }
250    NET2ADD(IAC, WILL);
251    NETADD(c);
252    printoption("SENT", WILL, c);
253}
254
255void
256send_wont(int c, int init)
257{
258    if (init) {
259	if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
260				my_want_state_is_wont(c))
261	    return;
262	set_my_want_state_wont(c);
263	will_wont_resp[c]++;
264    }
265    NET2ADD(IAC, WONT);
266    NETADD(c);
267    printoption("SENT", WONT, c);
268}
269
270void
271willoption(int option)
272{
273	int new_state_ok = 0;
274
275	if (do_dont_resp[option]) {
276	    --do_dont_resp[option];
277	    if (do_dont_resp[option] && my_state_is_do(option))
278		--do_dont_resp[option];
279	}
280
281	if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
282
283	    switch (option) {
284
285	    case TELOPT_ECHO:
286	    case TELOPT_BINARY:
287	    case TELOPT_SGA:
288		settimer(modenegotiated);
289		/* FALLTHROUGH */
290	    case TELOPT_STATUS:
291#ifdef	AUTHENTICATION
292	    case TELOPT_AUTHENTICATION:
293#endif
294#ifdef	ENCRYPTION
295	    case TELOPT_ENCRYPT:
296#endif /* ENCRYPTION */
297		new_state_ok = 1;
298		break;
299
300	    case TELOPT_TM:
301		if (flushout)
302		    flushout = 0;
303		/*
304		 * Special case for TM.  If we get back a WILL,
305		 * pretend we got back a WONT.
306		 */
307		set_my_want_state_dont(option);
308		set_my_state_dont(option);
309		return;			/* Never reply to TM will's/wont's */
310
311	    case TELOPT_LINEMODE:
312	    default:
313		break;
314	    }
315
316	    if (new_state_ok) {
317		set_my_want_state_do(option);
318		send_do(option, 0);
319		setconnmode(0);		/* possibly set new tty mode */
320	    } else {
321		do_dont_resp[option]++;
322		send_dont(option, 0);
323	    }
324	}
325	set_my_state_do(option);
326#ifdef	ENCRYPTION
327	if (option == TELOPT_ENCRYPT)
328		encrypt_send_support();
329#endif	/* ENCRYPTION */
330}
331
332void
333wontoption(int option)
334{
335	if (do_dont_resp[option]) {
336	    --do_dont_resp[option];
337	    if (do_dont_resp[option] && my_state_is_dont(option))
338		--do_dont_resp[option];
339	}
340
341	if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
342
343	    switch (option) {
344
345#ifdef	KLUDGELINEMODE
346	    case TELOPT_SGA:
347		if (!kludgelinemode)
348		    break;
349		/* FALLTHROUGH */
350#endif
351	    case TELOPT_ECHO:
352		settimer(modenegotiated);
353		break;
354
355	    case TELOPT_TM:
356		if (flushout)
357		    flushout = 0;
358		set_my_want_state_dont(option);
359		set_my_state_dont(option);
360		return;		/* Never reply to TM will's/wont's */
361
362	    default:
363		break;
364	    }
365	    set_my_want_state_dont(option);
366	    if (my_state_is_do(option))
367		send_dont(option, 0);
368	    setconnmode(0);			/* Set new tty mode */
369	} else if (option == TELOPT_TM) {
370	    /*
371	     * Special case for TM.
372	     */
373	    if (flushout)
374		flushout = 0;
375	    set_my_want_state_dont(option);
376	}
377	set_my_state_dont(option);
378}
379
380static void
381dooption(int option)
382{
383	int new_state_ok = 0;
384
385	if (will_wont_resp[option]) {
386	    --will_wont_resp[option];
387	    if (will_wont_resp[option] && my_state_is_will(option))
388		--will_wont_resp[option];
389	}
390
391	if (will_wont_resp[option] == 0) {
392	  if (my_want_state_is_wont(option)) {
393
394	    switch (option) {
395
396	    case TELOPT_TM:
397		/*
398		 * Special case for TM.  We send a WILL, but pretend
399		 * we sent WONT.
400		 */
401		send_will(option, 0);
402		set_my_want_state_wont(TELOPT_TM);
403		set_my_state_wont(TELOPT_TM);
404		return;
405
406	    case TELOPT_BINARY:		/* binary mode */
407	    case TELOPT_NAWS:		/* window size */
408	    case TELOPT_TSPEED:		/* terminal speed */
409	    case TELOPT_LFLOW:		/* local flow control */
410	    case TELOPT_TTYPE:		/* terminal type option */
411	    case TELOPT_SGA:		/* no big deal */
412#ifdef	ENCRYPTION
413	    case TELOPT_ENCRYPT:	/* encryption variable option */
414#endif	/* ENCRYPTION */
415		new_state_ok = 1;
416		break;
417
418	    case TELOPT_NEW_ENVIRON:	/* New environment variable option */
419#ifdef	OLD_ENVIRON
420		if (my_state_is_will(TELOPT_OLD_ENVIRON))
421			send_wont(TELOPT_OLD_ENVIRON, 1); /* turn off the old */
422		goto env_common;
423	    case TELOPT_OLD_ENVIRON:	/* Old environment variable option */
424		if (my_state_is_will(TELOPT_NEW_ENVIRON))
425			break;		/* Don't enable if new one is in use! */
426	    env_common:
427		telopt_environ = option;
428#endif
429		new_state_ok = 1;
430		break;
431
432#ifdef	AUTHENTICATION
433	    case TELOPT_AUTHENTICATION:
434		if (autologin)
435			new_state_ok = 1;
436		break;
437#endif
438
439	    case TELOPT_XDISPLOC:	/* X Display location */
440		if (env_getvalue("DISPLAY"))
441		    new_state_ok = 1;
442		break;
443
444	    case TELOPT_LINEMODE:
445#ifdef	KLUDGELINEMODE
446		kludgelinemode = 0;
447		send_do(TELOPT_SGA, 1);
448#endif
449		set_my_want_state_will(TELOPT_LINEMODE);
450		send_will(option, 0);
451		set_my_state_will(TELOPT_LINEMODE);
452		slc_init();
453		return;
454
455	    case TELOPT_ECHO:		/* We're never going to echo... */
456	    default:
457		break;
458	    }
459
460	    if (new_state_ok) {
461		set_my_want_state_will(option);
462		send_will(option, 0);
463		setconnmode(0);			/* Set new tty mode */
464	    } else {
465		will_wont_resp[option]++;
466		send_wont(option, 0);
467	    }
468	  } else {
469	    /*
470	     * Handle options that need more things done after the
471	     * other side has acknowledged the option.
472	     */
473	    switch (option) {
474	    case TELOPT_LINEMODE:
475#ifdef	KLUDGELINEMODE
476		kludgelinemode = 0;
477		send_do(TELOPT_SGA, 1);
478#endif
479		set_my_state_will(option);
480		slc_init();
481		send_do(TELOPT_SGA, 0);
482		return;
483	    }
484	  }
485	}
486	set_my_state_will(option);
487}
488
489static void
490dontoption(int option)
491{
492
493	if (will_wont_resp[option]) {
494	    --will_wont_resp[option];
495	    if (will_wont_resp[option] && my_state_is_wont(option))
496		--will_wont_resp[option];
497	}
498
499	if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
500	    switch (option) {
501	    case TELOPT_LINEMODE:
502		linemode = 0;	/* put us back to the default state */
503		break;
504#ifdef	OLD_ENVIRON
505	    case TELOPT_NEW_ENVIRON:
506		/*
507		 * The new environ option wasn't recognized, try
508		 * the old one.
509		 */
510		send_will(TELOPT_OLD_ENVIRON, 1);
511		telopt_environ = TELOPT_OLD_ENVIRON;
512		break;
513#endif
514	    }
515	    /* we always accept a DONT */
516	    set_my_want_state_wont(option);
517	    if (my_state_is_will(option))
518		send_wont(option, 0);
519	    setconnmode(0);			/* Set new tty mode */
520	}
521	set_my_state_wont(option);
522}
523
524/*
525 * Given a buffer returned by tgetent(), this routine will turn
526 * the pipe separated list of names in the buffer into an array
527 * of pointers to null terminated names.  We toss out any bad,
528 * duplicate, or verbose names (names with spaces).
529 */
530
531static const char *name_unknown = "UNKNOWN";
532static const char *unknown[] = { NULL, NULL };
533
534static const char **
535mklist(char *buf, char *name)
536{
537	int n;
538	char c, *cp, **argvp, *cp2, **argv, **avt;
539
540	if (name) {
541		if (strlen(name) > 40) {
542			name = 0;
543			unknown[0] = name_unknown;
544		} else {
545			unknown[0] = name;
546			upcase(name);
547		}
548	} else
549		unknown[0] = name_unknown;
550	/*
551	 * Count up the number of names.
552	 */
553	for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
554		if (*cp == '|')
555			n++;
556	}
557	/*
558	 * Allocate an array to put the name pointers into
559	 */
560	argv = (char **)malloc((n+3)*sizeof(char *));
561	if (argv == 0)
562		return(unknown);
563
564	/*
565	 * Fill up the array of pointers to names.
566	 */
567	*argv = 0;
568	argvp = argv+1;
569	n = 0;
570	for (cp = cp2 = buf; (c = *cp);  cp++) {
571		if (c == '|' || c == ':') {
572			*cp++ = '\0';
573			/*
574			 * Skip entries that have spaces or are over 40
575			 * characters long.  If this is our environment
576			 * name, then put it up front.  Otherwise, as
577			 * long as this is not a duplicate name (case
578			 * insensitive) add it to the list.
579			 */
580			if (n || (cp - cp2 > 41))
581				;
582			else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
583				*argv = cp2;
584			else if (is_unique(cp2, argv+1, argvp))
585				*argvp++ = cp2;
586			if (c == ':')
587				break;
588			/*
589			 * Skip multiple delimiters. Reset cp2 to
590			 * the beginning of the next name. Reset n,
591			 * the flag for names with spaces.
592			 */
593			while ((c = *cp) == '|')
594				cp++;
595			cp2 = cp;
596			n = 0;
597		}
598		/*
599		 * Skip entries with spaces or non-ascii values.
600		 * Convert lower case letters to upper case.
601		 */
602		if ((c == ' ') || !isascii(c))
603			n = 1;
604		else if (islower(c))
605			*cp = toupper(c);
606	}
607
608	/*
609	 * Check for an old V6 2 character name.  If the second
610	 * name points to the beginning of the buffer, and is
611	 * only 2 characters long, move it to the end of the array.
612	 */
613	if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
614		--argvp;
615		for (avt = &argv[1]; avt < argvp; avt++)
616			*avt = *(avt+1);
617		*argvp++ = buf;
618	}
619
620	/*
621	 * Duplicate last name, for TTYPE option, and null
622	 * terminate the array.  If we didn't find a match on
623	 * our terminal name, put that name at the beginning.
624	 */
625	cp = *(argvp-1);
626	*argvp++ = cp;
627	*argvp = 0;
628
629	if (*argv == 0) {
630		if (name)
631			*argv = name;
632		else {
633			--argvp;
634			for (avt = argv; avt < argvp; avt++)
635				*avt = *(avt+1);
636		}
637	}
638	if (*argv)
639		return((const char **)argv);
640	else
641		return(unknown);
642}
643
644static int
645is_unique(char *name, char **as, char **ae)
646{
647	char **ap;
648	int n;
649
650	n = strlen(name) + 1;
651	for (ap = as; ap < ae; ap++)
652		if (strncasecmp(*ap, name, n) == 0)
653			return(0);
654	return (1);
655}
656
657#ifdef	TERMCAP
658char termbuf[1024];
659
660/*ARGSUSED*/
661static int
662setupterm(char *tname, int fd, int *errp)
663{
664	if (tgetent(termbuf, tname) == 1) {
665		termbuf[1023] = '\0';
666		if (errp)
667			*errp = 1;
668		return(0);
669	}
670	if (errp)
671		*errp = 0;
672	return(-1);
673}
674#else
675#define	termbuf	ttytype
676extern char ttytype[];
677#endif
678
679int resettermname = 1;
680
681static const char *
682gettermname(void)
683{
684	char *tname;
685	static const char **tnamep = 0;
686	static const char **next;
687	int err;
688
689	if (resettermname) {
690		resettermname = 0;
691		if (tnamep && tnamep != unknown)
692			free(tnamep);
693		if ((tname = env_getvalue("TERM")) &&
694				(setupterm(tname, 1, &err) == 0)) {
695			tnamep = mklist(termbuf, tname);
696		} else {
697			if (tname && (strlen(tname) <= 40)) {
698				unknown[0] = tname;
699				upcase(tname);
700			} else
701				unknown[0] = name_unknown;
702			tnamep = unknown;
703		}
704		next = tnamep;
705	}
706	if (*next == 0)
707		next = tnamep;
708	return(*next++);
709}
710/*
711 * suboption()
712 *
713 *	Look at the sub-option buffer, and try to be helpful to the other
714 * side.
715 *
716 *	Currently we recognize:
717 *
718 *		Terminal type, send request.
719 *		Terminal speed (send request).
720 *		Local flow control (is request).
721 *		Linemode
722 */
723
724static void
725suboption(void)
726{
727    unsigned char subchar;
728
729    printsub('<', subbuffer, SB_LEN()+2);
730    switch (subchar = SB_GET()) {
731    case TELOPT_TTYPE:
732	if (my_want_state_is_wont(TELOPT_TTYPE))
733	    return;
734	if (SB_EOF() || SB_GET() != TELQUAL_SEND) {
735	    return;
736	} else {
737	    const char *name;
738	    unsigned char temp[50];
739	    int len;
740
741	    name = gettermname();
742	    len = strlen(name) + 4 + 2;
743	    if (len < NETROOM()) {
744		sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
745				TELQUAL_IS, name, IAC, SE);
746		ring_supply_data(&netoring, temp, len);
747		printsub('>', &temp[2], len-2);
748	    } else {
749		ExitString("No room in buffer for terminal type.\n", 1);
750		/*NOTREACHED*/
751	    }
752	}
753	break;
754    case TELOPT_TSPEED:
755	if (my_want_state_is_wont(TELOPT_TSPEED))
756	    return;
757	if (SB_EOF())
758	    return;
759	if (SB_GET() == TELQUAL_SEND) {
760	    long ospeed, ispeed;
761	    unsigned char temp[50];
762	    int len;
763
764	    TerminalSpeeds(&ispeed, &ospeed);
765
766	    sprintf((char *)temp, "%c%c%c%c%ld,%ld%c%c", IAC, SB, TELOPT_TSPEED,
767		    TELQUAL_IS, ospeed, ispeed, IAC, SE);
768	    len = strlen((char *)temp+4) + 4;	/* temp[3] is 0 ... */
769
770	    if (len < NETROOM()) {
771		ring_supply_data(&netoring, temp, len);
772		printsub('>', temp+2, len - 2);
773	    }
774/*@*/	    else printf("lm_will: not enough room in buffer\n");
775	}
776	break;
777    case TELOPT_LFLOW:
778	if (my_want_state_is_wont(TELOPT_LFLOW))
779	    return;
780	if (SB_EOF())
781	    return;
782	switch(SB_GET()) {
783	case LFLOW_RESTART_ANY:
784	    restartany = 1;
785	    break;
786	case LFLOW_RESTART_XON:
787	    restartany = 0;
788	    break;
789	case LFLOW_ON:
790	    localflow = 1;
791	    break;
792	case LFLOW_OFF:
793	    localflow = 0;
794	    break;
795	default:
796	    return;
797	}
798	setcommandmode();
799	setconnmode(0);
800	break;
801
802    case TELOPT_LINEMODE:
803	if (my_want_state_is_wont(TELOPT_LINEMODE))
804	    return;
805	if (SB_EOF())
806	    return;
807	switch (SB_GET()) {
808	case WILL:
809	    lm_will(subpointer, SB_LEN());
810	    break;
811	case WONT:
812	    lm_wont(subpointer, SB_LEN());
813	    break;
814	case DO:
815	    lm_do(subpointer, SB_LEN());
816	    break;
817	case DONT:
818	    lm_dont(subpointer, SB_LEN());
819	    break;
820	case LM_SLC:
821	    slc(subpointer, SB_LEN());
822	    break;
823	case LM_MODE:
824	    lm_mode(subpointer, SB_LEN(), 0);
825	    break;
826	default:
827	    break;
828	}
829	break;
830
831#ifdef	OLD_ENVIRON
832    case TELOPT_OLD_ENVIRON:
833#endif
834    case TELOPT_NEW_ENVIRON:
835	if (SB_EOF())
836	    return;
837	switch(SB_PEEK()) {
838	case TELQUAL_IS:
839	case TELQUAL_INFO:
840	    if (my_want_state_is_dont(subchar))
841		return;
842	    break;
843	case TELQUAL_SEND:
844	    if (my_want_state_is_wont(subchar)) {
845		return;
846	    }
847	    break;
848	default:
849	    return;
850	}
851	env_opt(subpointer, SB_LEN());
852	break;
853
854    case TELOPT_XDISPLOC:
855	if (my_want_state_is_wont(TELOPT_XDISPLOC))
856	    return;
857	if (SB_EOF())
858	    return;
859	if (SB_GET() == TELQUAL_SEND) {
860	    unsigned char temp[50], *dp;
861	    int len;
862
863	    if ((dp = env_getvalue("DISPLAY")) == NULL ||
864		strlen(dp) > sizeof(temp) - 7) {
865		/*
866		 * Something happened, we no longer have a DISPLAY
867		 * variable.  Or it is too long.  So, turn off the option.
868		 */
869		send_wont(TELOPT_XDISPLOC, 1);
870		break;
871	    }
872	    snprintf(temp, sizeof(temp), "%c%c%c%c%s%c%c", IAC, SB,
873		    TELOPT_XDISPLOC, TELQUAL_IS, dp, IAC, SE);
874	    len = strlen((char *)temp+4) + 4;	/* temp[3] is 0 ... */
875
876	    if (len < NETROOM()) {
877		ring_supply_data(&netoring, temp, len);
878		printsub('>', temp+2, len - 2);
879	    }
880/*@*/	    else printf("lm_will: not enough room in buffer\n");
881	}
882	break;
883
884#ifdef	AUTHENTICATION
885	case TELOPT_AUTHENTICATION: {
886		if (!autologin)
887			break;
888		if (SB_EOF())
889			return;
890		switch(SB_GET()) {
891		case TELQUAL_IS:
892			if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
893				return;
894			auth_is(subpointer, SB_LEN());
895			break;
896		case TELQUAL_SEND:
897			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
898				return;
899			auth_send(subpointer, SB_LEN());
900			break;
901		case TELQUAL_REPLY:
902			if (my_want_state_is_wont(TELOPT_AUTHENTICATION))
903				return;
904			auth_reply(subpointer, SB_LEN());
905			break;
906		case TELQUAL_NAME:
907			if (my_want_state_is_dont(TELOPT_AUTHENTICATION))
908				return;
909			auth_name(subpointer, SB_LEN());
910			break;
911		}
912	}
913	break;
914#endif
915#ifdef	ENCRYPTION
916	case TELOPT_ENCRYPT:
917		if (SB_EOF())
918			return;
919		switch(SB_GET()) {
920		case ENCRYPT_START:
921			if (my_want_state_is_dont(TELOPT_ENCRYPT))
922				return;
923			encrypt_start(subpointer, SB_LEN());
924			break;
925		case ENCRYPT_END:
926			if (my_want_state_is_dont(TELOPT_ENCRYPT))
927				return;
928			encrypt_end();
929			break;
930		case ENCRYPT_SUPPORT:
931			if (my_want_state_is_wont(TELOPT_ENCRYPT))
932				return;
933			encrypt_support(subpointer, SB_LEN());
934			break;
935		case ENCRYPT_REQSTART:
936			if (my_want_state_is_wont(TELOPT_ENCRYPT))
937				return;
938			encrypt_request_start(subpointer, SB_LEN());
939			break;
940		case ENCRYPT_REQEND:
941			if (my_want_state_is_wont(TELOPT_ENCRYPT))
942				return;
943			/*
944			 * We can always send an REQEND so that we cannot
945			 * get stuck encrypting.  We should only get this
946			 * if we have been able to get in the correct mode
947			 * anyhow.
948			 */
949			encrypt_request_end();
950			break;
951		case ENCRYPT_IS:
952			if (my_want_state_is_dont(TELOPT_ENCRYPT))
953				return;
954			encrypt_is(subpointer, SB_LEN());
955			break;
956		case ENCRYPT_REPLY:
957			if (my_want_state_is_wont(TELOPT_ENCRYPT))
958				return;
959			encrypt_reply(subpointer, SB_LEN());
960			break;
961		case ENCRYPT_ENC_KEYID:
962			if (my_want_state_is_dont(TELOPT_ENCRYPT))
963				return;
964			encrypt_enc_keyid(subpointer, SB_LEN());
965			break;
966		case ENCRYPT_DEC_KEYID:
967			if (my_want_state_is_wont(TELOPT_ENCRYPT))
968				return;
969			encrypt_dec_keyid(subpointer, SB_LEN());
970			break;
971		default:
972			break;
973		}
974		break;
975#endif	/* ENCRYPTION */
976    default:
977	break;
978    }
979}
980
981static unsigned char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
982
983void
984lm_will(unsigned char *cmd, int len)
985{
986    if (len < 1) {
987/*@*/	printf("lm_will: no command!!!\n");	/* Should not happen... */
988	return;
989    }
990    switch(cmd[0]) {
991    case LM_FORWARDMASK:	/* We shouldn't ever get this... */
992    default:
993	str_lm[3] = DONT;
994	str_lm[4] = cmd[0];
995	if (NETROOM() > (int)sizeof(str_lm)) {
996	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
997	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
998	}
999/*@*/	else printf("lm_will: not enough room in buffer\n");
1000	break;
1001    }
1002}
1003
1004void
1005lm_wont(unsigned char *cmd, int len)
1006{
1007    if (len < 1) {
1008/*@*/	printf("lm_wont: no command!!!\n");	/* Should not happen... */
1009	return;
1010    }
1011    switch(cmd[0]) {
1012    case LM_FORWARDMASK:	/* We shouldn't ever get this... */
1013    default:
1014	/* We are always DONT, so don't respond */
1015	return;
1016    }
1017}
1018
1019void
1020lm_do(unsigned char *cmd, int len)
1021{
1022    if (len < 1) {
1023/*@*/	printf("lm_do: no command!!!\n");	/* Should not happen... */
1024	return;
1025    }
1026    switch(cmd[0]) {
1027    case LM_FORWARDMASK:
1028    default:
1029	str_lm[3] = WONT;
1030	str_lm[4] = cmd[0];
1031	if (NETROOM() > (int)sizeof(str_lm)) {
1032	    ring_supply_data(&netoring, str_lm, sizeof(str_lm));
1033	    printsub('>', &str_lm[2], sizeof(str_lm)-2);
1034	}
1035/*@*/	else printf("lm_do: not enough room in buffer\n");
1036	break;
1037    }
1038}
1039
1040void
1041lm_dont(unsigned char *cmd, int len)
1042{
1043    if (len < 1) {
1044/*@*/	printf("lm_dont: no command!!!\n");	/* Should not happen... */
1045	return;
1046    }
1047    switch(cmd[0]) {
1048    case LM_FORWARDMASK:
1049    default:
1050	/* we are always WONT, so don't respond */
1051	break;
1052    }
1053}
1054
1055static unsigned char str_lm_mode[] = {
1056	IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE
1057};
1058
1059void
1060lm_mode(unsigned char *cmd, int len, int init)
1061{
1062	if (len != 1)
1063		return;
1064	if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
1065		return;
1066	if (*cmd&MODE_ACK)
1067		return;
1068	linemode = *cmd&(MODE_MASK&~MODE_ACK);
1069	str_lm_mode[4] = linemode;
1070	if (!init)
1071	    str_lm_mode[4] |= MODE_ACK;
1072	if (NETROOM() > (int)sizeof(str_lm_mode)) {
1073	    ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
1074	    printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
1075	}
1076/*@*/	else printf("lm_mode: not enough room in buffer\n");
1077	setconnmode(0);	/* set changed mode */
1078}
1079
1080
1081
1082/*
1083 * slc()
1084 * Handle special character suboption of LINEMODE.
1085 */
1086
1087struct spc {
1088	cc_t val;
1089	cc_t *valp;
1090	char flags;	/* Current flags & level */
1091	char mylevel;	/* Maximum level & flags */
1092} spc_data[NSLC+1];
1093
1094#define SLC_IMPORT	0
1095#define	SLC_EXPORT	1
1096#define SLC_RVALUE	2
1097static int slc_mode = SLC_EXPORT;
1098
1099void
1100slc_init(void)
1101{
1102	struct spc *spcp;
1103
1104	localchars = 1;
1105	for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
1106		spcp->val = 0;
1107		spcp->valp = 0;
1108		spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
1109	}
1110
1111#define	initfunc(func, flags) { \
1112					spcp = &spc_data[func]; \
1113					if ((spcp->valp = tcval(func))) { \
1114					    spcp->val = *spcp->valp; \
1115					    spcp->mylevel = SLC_VARIABLE|flags; \
1116					} else { \
1117					    spcp->val = 0; \
1118					    spcp->mylevel = SLC_DEFAULT; \
1119					} \
1120				    }
1121
1122	initfunc(SLC_SYNCH, 0);
1123	/* No BRK */
1124	initfunc(SLC_AO, 0);
1125	initfunc(SLC_AYT, 0);
1126	/* No EOR */
1127	initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
1128	initfunc(SLC_EOF, 0);
1129#ifndef	SYSV_TERMIO
1130	initfunc(SLC_SUSP, SLC_FLUSHIN);
1131#endif
1132	initfunc(SLC_EC, 0);
1133	initfunc(SLC_EL, 0);
1134#ifndef	SYSV_TERMIO
1135	initfunc(SLC_EW, 0);
1136	initfunc(SLC_RP, 0);
1137	initfunc(SLC_LNEXT, 0);
1138#endif
1139	initfunc(SLC_XON, 0);
1140	initfunc(SLC_XOFF, 0);
1141#ifdef	SYSV_TERMIO
1142	spc_data[SLC_XON].mylevel = SLC_CANTCHANGE;
1143	spc_data[SLC_XOFF].mylevel = SLC_CANTCHANGE;
1144#endif
1145	initfunc(SLC_FORW1, 0);
1146#ifdef	USE_TERMIO
1147	initfunc(SLC_FORW2, 0);
1148	/* No FORW2 */
1149#endif
1150
1151	initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
1152#undef	initfunc
1153
1154	if (slc_mode == SLC_EXPORT)
1155		slc_export();
1156	else
1157		slc_import(1);
1158
1159}
1160
1161void
1162slcstate(void)
1163{
1164    printf("Special characters are %s values\n",
1165		slc_mode == SLC_IMPORT ? "remote default" :
1166		slc_mode == SLC_EXPORT ? "local" :
1167					 "remote");
1168}
1169
1170void
1171slc_mode_export(void)
1172{
1173    slc_mode = SLC_EXPORT;
1174    if (my_state_is_will(TELOPT_LINEMODE))
1175	slc_export();
1176}
1177
1178void
1179slc_mode_import(int def)
1180{
1181    slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
1182    if (my_state_is_will(TELOPT_LINEMODE))
1183	slc_import(def);
1184}
1185
1186unsigned char slc_import_val[] = {
1187	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
1188};
1189unsigned char slc_import_def[] = {
1190	IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
1191};
1192
1193void
1194slc_import(int def)
1195{
1196    if (NETROOM() > (int)sizeof(slc_import_val)) {
1197	if (def) {
1198	    ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
1199	    printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
1200	} else {
1201	    ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
1202	    printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
1203	}
1204    }
1205/*@*/ else printf("slc_import: not enough room\n");
1206}
1207
1208void
1209slc_export(void)
1210{
1211    struct spc *spcp;
1212
1213    TerminalDefaultChars();
1214
1215    slc_start_reply();
1216    for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1217	if (spcp->mylevel != SLC_NOSUPPORT) {
1218	    if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1219		spcp->flags = SLC_NOSUPPORT;
1220	    else
1221		spcp->flags = spcp->mylevel;
1222	    if (spcp->valp)
1223		spcp->val = *spcp->valp;
1224	    slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1225	}
1226    }
1227    slc_end_reply();
1228    (void)slc_update();
1229    setconnmode(1);	/* Make sure the character values are set */
1230}
1231
1232void
1233slc(unsigned char *cp, int len)
1234{
1235	struct spc *spcp;
1236	int func,level;
1237
1238	slc_start_reply();
1239
1240	for (; len >= 3; len -=3, cp +=3) {
1241
1242		func = cp[SLC_FUNC];
1243
1244		if (func == 0) {
1245			/*
1246			 * Client side: always ignore 0 function.
1247			 */
1248			continue;
1249		}
1250		if (func > NSLC) {
1251			if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
1252				slc_add_reply(func, SLC_NOSUPPORT, 0);
1253			continue;
1254		}
1255
1256		spcp = &spc_data[func];
1257
1258		level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
1259
1260		if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
1261		    ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
1262			continue;
1263		}
1264
1265		if (level == (SLC_DEFAULT|SLC_ACK)) {
1266			/*
1267			 * This is an error condition, the SLC_ACK
1268			 * bit should never be set for the SLC_DEFAULT
1269			 * level.  Our best guess to recover is to
1270			 * ignore the SLC_ACK bit.
1271			 */
1272			cp[SLC_FLAGS] &= ~SLC_ACK;
1273		}
1274
1275		if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
1276			spcp->val = (cc_t)cp[SLC_VALUE];
1277			spcp->flags = cp[SLC_FLAGS];	/* include SLC_ACK */
1278			continue;
1279		}
1280
1281		level &= ~SLC_ACK;
1282
1283		if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
1284			spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
1285			spcp->val = (cc_t)cp[SLC_VALUE];
1286		}
1287		if (level == SLC_DEFAULT) {
1288			if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
1289				spcp->flags = spcp->mylevel;
1290			else
1291				spcp->flags = SLC_NOSUPPORT;
1292		}
1293		slc_add_reply(func, spcp->flags, spcp->val);
1294	}
1295	slc_end_reply();
1296	if (slc_update())
1297		setconnmode(1);	/* set the  new character values */
1298}
1299
1300void
1301slc_check(void)
1302{
1303    struct spc *spcp;
1304
1305    slc_start_reply();
1306    for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1307	if (spcp->valp && spcp->val != *spcp->valp) {
1308	    spcp->val = *spcp->valp;
1309	    if (spcp->val == (cc_t)(_POSIX_VDISABLE))
1310		spcp->flags = SLC_NOSUPPORT;
1311	    else
1312		spcp->flags = spcp->mylevel;
1313	    slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
1314	}
1315    }
1316    slc_end_reply();
1317    setconnmode(1);
1318}
1319
1320unsigned char slc_reply[128];
1321unsigned char *slc_replyp;
1322
1323void
1324slc_start_reply(void)
1325{
1326	slc_replyp = slc_reply;
1327	*slc_replyp++ = IAC;
1328	*slc_replyp++ = SB;
1329	*slc_replyp++ = TELOPT_LINEMODE;
1330	*slc_replyp++ = LM_SLC;
1331}
1332
1333void
1334slc_add_reply(unsigned char func, unsigned char flags, cc_t value)
1335{
1336	if ((*slc_replyp++ = func) == IAC)
1337		*slc_replyp++ = IAC;
1338	if ((*slc_replyp++ = flags) == IAC)
1339		*slc_replyp++ = IAC;
1340	if ((*slc_replyp++ = (unsigned char)value) == IAC)
1341		*slc_replyp++ = IAC;
1342}
1343
1344void
1345slc_end_reply(void)
1346{
1347    int len;
1348
1349    *slc_replyp++ = IAC;
1350    *slc_replyp++ = SE;
1351    len = slc_replyp - slc_reply;
1352    if (len <= 6)
1353	return;
1354    if (NETROOM() > len) {
1355	ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
1356	printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
1357    }
1358/*@*/else printf("slc_end_reply: not enough room\n");
1359}
1360
1361int
1362slc_update(void)
1363{
1364	struct spc *spcp;
1365	int need_update = 0;
1366
1367	for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
1368		if (!(spcp->flags&SLC_ACK))
1369			continue;
1370		spcp->flags &= ~SLC_ACK;
1371		if (spcp->valp && (*spcp->valp != spcp->val)) {
1372			*spcp->valp = spcp->val;
1373			need_update = 1;
1374		}
1375	}
1376	return(need_update);
1377}
1378
1379#ifdef	OLD_ENVIRON
1380# ifdef	ENV_HACK
1381/*
1382 * Earlier version of telnet/telnetd from the BSD code had
1383 * the definitions of VALUE and VAR reversed.  To ensure
1384 * maximum interoperability, we assume that the server is
1385 * an older BSD server, until proven otherwise.  The newer
1386 * BSD servers should be able to handle either definition,
1387 * so it is better to use the wrong values if we don't
1388 * know what type of server it is.
1389 */
1390int env_auto = 1;
1391int old_env_var = OLD_ENV_VAR;
1392int old_env_value = OLD_ENV_VALUE;
1393# else
1394#  define old_env_var OLD_ENV_VAR
1395#  define old_env_value OLD_ENV_VALUE
1396# endif
1397#endif
1398
1399void
1400env_opt(unsigned char *buf, int len)
1401{
1402	unsigned char *ep = 0, *epc = 0;
1403	int i;
1404
1405	switch(buf[0]&0xff) {
1406	case TELQUAL_SEND:
1407		env_opt_start();
1408		if (len == 1) {
1409			env_opt_add(NULL);
1410		} else for (i = 1; i < len; i++) {
1411			switch (buf[i]&0xff) {
1412#ifdef	OLD_ENVIRON
1413			case OLD_ENV_VAR:
1414# ifdef	ENV_HACK
1415				if (telopt_environ == TELOPT_OLD_ENVIRON
1416				    && env_auto) {
1417					/* Server has the same definitions */
1418					old_env_var = OLD_ENV_VAR;
1419					old_env_value = OLD_ENV_VALUE;
1420				}
1421				/* FALLTHROUGH */
1422# endif
1423			case OLD_ENV_VALUE:
1424				/*
1425				 * Although OLD_ENV_VALUE is not legal, we will
1426				 * still recognize it, just in case it is an
1427				 * old server that has VAR & VALUE mixed up...
1428				 */
1429				/* FALLTHROUGH */
1430#else
1431			case NEW_ENV_VAR:
1432#endif
1433			case ENV_USERVAR:
1434				if (ep) {
1435					*epc = 0;
1436					env_opt_add(ep);
1437				}
1438				ep = epc = &buf[i+1];
1439				break;
1440			case ENV_ESC:
1441				i++;
1442				/*FALLTHROUGH*/
1443			default:
1444				if (epc)
1445					*epc++ = buf[i];
1446				break;
1447			}
1448		}
1449		if (ep) {
1450			*epc = 0;
1451			env_opt_add(ep);
1452		}
1453		env_opt_end(1);
1454		break;
1455
1456	case TELQUAL_IS:
1457	case TELQUAL_INFO:
1458		/* Ignore for now.  We shouldn't get it anyway. */
1459		break;
1460
1461	default:
1462		break;
1463	}
1464}
1465
1466#define	OPT_REPLY_SIZE	256
1467unsigned char *opt_reply;
1468unsigned char *opt_replyp;
1469unsigned char *opt_replyend;
1470
1471void
1472env_opt_start(void)
1473{
1474	if (opt_reply)
1475		opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
1476	else
1477		opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
1478	if (opt_reply == NULL) {
1479/*@*/		printf("env_opt_start: malloc()/realloc() failed!!!\n");
1480		opt_reply = opt_replyp = opt_replyend = NULL;
1481		return;
1482	}
1483	opt_replyp = opt_reply;
1484	opt_replyend = opt_reply + OPT_REPLY_SIZE;
1485	*opt_replyp++ = IAC;
1486	*opt_replyp++ = SB;
1487	*opt_replyp++ = telopt_environ;
1488	*opt_replyp++ = TELQUAL_IS;
1489}
1490
1491void
1492env_opt_start_info(void)
1493{
1494	env_opt_start();
1495	if (opt_replyp)
1496	    opt_replyp[-1] = TELQUAL_INFO;
1497}
1498
1499void
1500env_opt_add(unsigned char *ep)
1501{
1502	unsigned char *vp, c;
1503
1504	if (opt_reply == NULL)		/*XXX*/
1505		return;			/*XXX*/
1506
1507	if (ep == NULL || *ep == '\0') {
1508		/* Send user defined variables first. */
1509		env_default(1, 0);
1510		while ((ep = env_default(0, 0)))
1511			env_opt_add(ep);
1512
1513		/* Now add the list of well know variables.  */
1514		env_default(1, 1);
1515		while ((ep = env_default(0, 1)))
1516			env_opt_add(ep);
1517		return;
1518	}
1519	vp = env_getvalue(ep);
1520	if (opt_replyp + (vp ? strlen((char *)vp) : 0) +
1521				strlen((char *)ep) + 6 > opt_replyend)
1522	{
1523		int len;
1524		opt_replyend += OPT_REPLY_SIZE;
1525		len = opt_replyend - opt_reply;
1526		opt_reply = (unsigned char *)realloc(opt_reply, len);
1527		if (opt_reply == NULL) {
1528/*@*/			printf("env_opt_add: realloc() failed!!!\n");
1529			opt_reply = opt_replyp = opt_replyend = NULL;
1530			return;
1531		}
1532		opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
1533		opt_replyend = opt_reply + len;
1534	}
1535	if (opt_welldefined(ep))
1536#ifdef	OLD_ENVIRON
1537		if (telopt_environ == TELOPT_OLD_ENVIRON)
1538			*opt_replyp++ = old_env_var;
1539		else
1540#endif
1541			*opt_replyp++ = NEW_ENV_VAR;
1542	else
1543		*opt_replyp++ = ENV_USERVAR;
1544	for (;;) {
1545		while ((c = *ep++)) {
1546			switch(c&0xff) {
1547			case IAC:
1548				*opt_replyp++ = IAC;
1549				break;
1550			case NEW_ENV_VAR:
1551			case NEW_ENV_VALUE:
1552			case ENV_ESC:
1553			case ENV_USERVAR:
1554				*opt_replyp++ = ENV_ESC;
1555				break;
1556			}
1557			*opt_replyp++ = c;
1558		}
1559		if ((ep = vp)) {
1560#ifdef	OLD_ENVIRON
1561			if (telopt_environ == TELOPT_OLD_ENVIRON)
1562				*opt_replyp++ = old_env_value;
1563			else
1564#endif
1565				*opt_replyp++ = NEW_ENV_VALUE;
1566			vp = NULL;
1567		} else
1568			break;
1569	}
1570}
1571
1572int
1573opt_welldefined(const char *ep)
1574{
1575	if ((strcmp(ep, "USER") == 0) ||
1576	    (strcmp(ep, "DISPLAY") == 0) ||
1577	    (strcmp(ep, "PRINTER") == 0) ||
1578	    (strcmp(ep, "SYSTEMTYPE") == 0) ||
1579	    (strcmp(ep, "JOB") == 0) ||
1580	    (strcmp(ep, "ACCT") == 0))
1581		return(1);
1582	return(0);
1583}
1584
1585void
1586env_opt_end(int emptyok)
1587{
1588	int len;
1589
1590	len = opt_replyp - opt_reply + 2;
1591	if (emptyok || len > 6) {
1592		*opt_replyp++ = IAC;
1593		*opt_replyp++ = SE;
1594		if (NETROOM() > len) {
1595			ring_supply_data(&netoring, opt_reply, len);
1596			printsub('>', &opt_reply[2], len - 2);
1597		}
1598/*@*/		else printf("slc_end_reply: not enough room\n");
1599	}
1600	if (opt_reply) {
1601		free(opt_reply);
1602		opt_reply = opt_replyp = opt_replyend = NULL;
1603	}
1604}
1605
1606
1607
1608int
1609telrcv(void)
1610{
1611    int c;
1612    int scc;
1613    unsigned char *sbp;
1614    int count;
1615    int returnValue = 0;
1616
1617    scc = 0;
1618    count = 0;
1619    while (TTYROOM() > 2) {
1620	if (scc == 0) {
1621	    if (count) {
1622		ring_consumed(&netiring, count);
1623		returnValue = 1;
1624		count = 0;
1625	    }
1626	    sbp = netiring.consume;
1627	    scc = ring_full_consecutive(&netiring);
1628	    if (scc == 0) {
1629		/* No more data coming in */
1630		break;
1631	    }
1632	}
1633
1634	c = *sbp++ & 0xff, scc--; count++;
1635#ifdef	ENCRYPTION
1636	if (decrypt_input)
1637		c = (*decrypt_input)(c);
1638#endif	/* ENCRYPTION */
1639
1640	switch (telrcv_state) {
1641
1642	case TS_CR:
1643	    telrcv_state = TS_DATA;
1644	    if (c == '\0') {
1645		break;	/* Ignore \0 after CR */
1646	    }
1647	    else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
1648		TTYADD(c);
1649		break;
1650	    }
1651	    /* FALLTHROUGH */
1652
1653	case TS_DATA:
1654	    if (c == IAC) {
1655		telrcv_state = TS_IAC;
1656		break;
1657	    }
1658		    /*
1659		     * The 'crmod' hack (see following) is needed
1660		     * since we can't * set CRMOD on output only.
1661		     * Machines like MULTICS like to send \r without
1662		     * \n; since we must turn off CRMOD to get proper
1663		     * input, the mapping is done here (sigh).
1664		     */
1665	    if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
1666		if (scc > 0) {
1667		    c = *sbp&0xff;
1668#ifdef	ENCRYPTION
1669		    if (decrypt_input)
1670			c = (*decrypt_input)(c);
1671#endif	/* ENCRYPTION */
1672		    if (c == 0) {
1673			sbp++, scc--; count++;
1674			/* a "true" CR */
1675			TTYADD('\r');
1676		    } else if (my_want_state_is_dont(TELOPT_ECHO) &&
1677					(c == '\n')) {
1678			sbp++, scc--; count++;
1679			TTYADD('\n');
1680		    } else {
1681#ifdef	ENCRYPTION
1682			if (decrypt_input)
1683			    (*decrypt_input)(-1);
1684#endif	/* ENCRYPTION */
1685
1686			TTYADD('\r');
1687			if (crmod) {
1688				TTYADD('\n');
1689			}
1690		    }
1691		} else {
1692		    telrcv_state = TS_CR;
1693		    TTYADD('\r');
1694		    if (crmod) {
1695			    TTYADD('\n');
1696		    }
1697		}
1698	    } else {
1699		TTYADD(c);
1700	    }
1701	    continue;
1702
1703	case TS_IAC:
1704process_iac:
1705	    switch (c) {
1706
1707	    case WILL:
1708		telrcv_state = TS_WILL;
1709		continue;
1710
1711	    case WONT:
1712		telrcv_state = TS_WONT;
1713		continue;
1714
1715	    case DO:
1716		telrcv_state = TS_DO;
1717		continue;
1718
1719	    case DONT:
1720		telrcv_state = TS_DONT;
1721		continue;
1722
1723	    case DM:
1724		    /*
1725		     * We may have missed an urgent notification,
1726		     * so make sure we flush whatever is in the
1727		     * buffer currently.
1728		     */
1729		printoption("RCVD", IAC, DM);
1730		SYNCHing = 1;
1731		(void) ttyflush(1);
1732		SYNCHing = stilloob();
1733		settimer(gotDM);
1734		break;
1735
1736	    case SB:
1737		SB_CLEAR();
1738		telrcv_state = TS_SB;
1739		continue;
1740
1741	    case IAC:
1742		TTYADD(IAC);
1743		break;
1744
1745	    case NOP:
1746	    case GA:
1747	    default:
1748		printoption("RCVD", IAC, c);
1749		break;
1750	    }
1751	    telrcv_state = TS_DATA;
1752	    continue;
1753
1754	case TS_WILL:
1755	    printoption("RCVD", WILL, c);
1756	    willoption(c);
1757	    telrcv_state = TS_DATA;
1758	    continue;
1759
1760	case TS_WONT:
1761	    printoption("RCVD", WONT, c);
1762	    wontoption(c);
1763	    telrcv_state = TS_DATA;
1764	    continue;
1765
1766	case TS_DO:
1767	    printoption("RCVD", DO, c);
1768	    dooption(c);
1769	    if (c == TELOPT_NAWS) {
1770		sendnaws();
1771	    } else if (c == TELOPT_LFLOW) {
1772		localflow = 1;
1773		setcommandmode();
1774		setconnmode(0);
1775	    }
1776	    telrcv_state = TS_DATA;
1777	    continue;
1778
1779	case TS_DONT:
1780	    printoption("RCVD", DONT, c);
1781	    dontoption(c);
1782	    flushline = 1;
1783	    setconnmode(0);	/* set new tty mode (maybe) */
1784	    telrcv_state = TS_DATA;
1785	    continue;
1786
1787	case TS_SB:
1788	    if (c == IAC) {
1789		telrcv_state = TS_SE;
1790	    } else {
1791		SB_ACCUM(c);
1792	    }
1793	    continue;
1794
1795	case TS_SE:
1796	    if (c != SE) {
1797		if (c != IAC) {
1798		    /*
1799		     * This is an error.  We only expect to get
1800		     * "IAC IAC" or "IAC SE".  Several things may
1801		     * have happend.  An IAC was not doubled, the
1802		     * IAC SE was left off, or another option got
1803		     * inserted into the suboption are all possibilities.
1804		     * If we assume that the IAC was not doubled,
1805		     * and really the IAC SE was left off, we could
1806		     * get into an infinate loop here.  So, instead,
1807		     * we terminate the suboption, and process the
1808		     * partial suboption if we can.
1809		     */
1810		    SB_ACCUM(IAC);
1811		    SB_ACCUM(c);
1812		    subpointer -= 2;
1813		    SB_TERM();
1814
1815		    printoption("In SUBOPTION processing, RCVD", IAC, c);
1816		    suboption();	/* handle sub-option */
1817		    telrcv_state = TS_IAC;
1818		    goto process_iac;
1819		}
1820		SB_ACCUM(c);
1821		telrcv_state = TS_SB;
1822	    } else {
1823		SB_ACCUM(IAC);
1824		SB_ACCUM(SE);
1825		subpointer -= 2;
1826		SB_TERM();
1827		suboption();	/* handle sub-option */
1828		telrcv_state = TS_DATA;
1829	    }
1830	}
1831    }
1832    if (count)
1833	ring_consumed(&netiring, count);
1834    return returnValue||count;
1835}
1836
1837static int bol = 1, local = 0;
1838
1839int
1840rlogin_susp(void)
1841{
1842    if (local) {
1843	local = 0;
1844	bol = 1;
1845	command(0, "z\n", 2);
1846	return(1);
1847    }
1848    return(0);
1849}
1850
1851static int
1852telsnd(void)
1853{
1854    int tcc;
1855    int count;
1856    int returnValue = 0;
1857    unsigned char *tbp;
1858
1859    tcc = 0;
1860    count = 0;
1861    while (NETROOM() > 2) {
1862	int sc;
1863	int c;
1864
1865	if (tcc == 0) {
1866	    if (count) {
1867		ring_consumed(&ttyiring, count);
1868		returnValue = 1;
1869		count = 0;
1870	    }
1871	    tbp = ttyiring.consume;
1872	    tcc = ring_full_consecutive(&ttyiring);
1873	    if (tcc == 0) {
1874		break;
1875	    }
1876	}
1877	c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
1878	if (rlogin != _POSIX_VDISABLE) {
1879		if (bol) {
1880			bol = 0;
1881			if (sc == rlogin) {
1882				local = 1;
1883				continue;
1884			}
1885		} else if (local) {
1886			local = 0;
1887			if (sc == '.' || c == termEofChar) {
1888				bol = 1;
1889				command(0, "close\n", 6);
1890				continue;
1891			}
1892			if (sc == termSuspChar) {
1893				bol = 1;
1894				command(0, "z\n", 2);
1895				continue;
1896			}
1897			if (sc == escape) {
1898				command(0, tbp, tcc);
1899				bol = 1;
1900				count += tcc;
1901				tcc = 0;
1902				flushline = 1;
1903				break;
1904			}
1905			if (sc != rlogin) {
1906				++tcc;
1907				--tbp;
1908				--count;
1909				c = sc = rlogin;
1910			}
1911		}
1912		if ((sc == '\n') || (sc == '\r'))
1913			bol = 1;
1914	} else if (escape != _POSIX_VDISABLE && sc == escape) {
1915	    /*
1916	     * Double escape is a pass through of a single escape character.
1917	     */
1918	    if (tcc && strip(*tbp) == escape) {
1919		tbp++;
1920		tcc--;
1921		count++;
1922		bol = 0;
1923	    } else {
1924		command(0, (char *)tbp, tcc);
1925		bol = 1;
1926		count += tcc;
1927		tcc = 0;
1928		flushline = 1;
1929		break;
1930	    }
1931	} else
1932	    bol = 0;
1933#ifdef	KLUDGELINEMODE
1934	if (kludgelinemode && (globalmode&MODE_EDIT) && (sc == echoc)) {
1935	    if (tcc > 0 && strip(*tbp) == echoc) {
1936		tcc--; tbp++; count++;
1937	    } else {
1938		dontlecho = !dontlecho;
1939		settimer(echotoggle);
1940		setconnmode(0);
1941		flushline = 1;
1942		break;
1943	    }
1944	}
1945#endif
1946	if (MODE_LOCAL_CHARS(globalmode)) {
1947	    if (TerminalSpecialChars(sc) == 0) {
1948		bol = 1;
1949		break;
1950	    }
1951	}
1952	if (my_want_state_is_wont(TELOPT_BINARY)) {
1953	    switch (c) {
1954	    case '\n':
1955		    /*
1956		     * If we are in CRMOD mode (\r ==> \n)
1957		     * on our local machine, then probably
1958		     * a newline (unix) is CRLF (TELNET).
1959		     */
1960		if (MODE_LOCAL_CHARS(globalmode)) {
1961		    NETADD('\r');
1962		}
1963		NETADD('\n');
1964		bol = flushline = 1;
1965		break;
1966	    case '\r':
1967		if (!crlf) {
1968		    NET2ADD('\r', '\0');
1969		} else {
1970		    NET2ADD('\r', '\n');
1971		}
1972		bol = flushline = 1;
1973		break;
1974	    case IAC:
1975		NET2ADD(IAC, IAC);
1976		break;
1977	    default:
1978		NETADD(c);
1979		break;
1980	    }
1981	} else if (c == IAC) {
1982	    NET2ADD(IAC, IAC);
1983	} else {
1984	    NETADD(c);
1985	}
1986    }
1987    if (count)
1988	ring_consumed(&ttyiring, count);
1989    return returnValue||count;		/* Non-zero if we did anything */
1990}
1991
1992/*
1993 * Scheduler()
1994 *
1995 * Try to do something.
1996 *
1997 * If we do something useful, return 1; else return 0.
1998 *
1999 */
2000
2001static int
2002Scheduler(int block)
2003{
2004		/* One wants to be a bit careful about setting returnValue
2005		 * to one, since a one implies we did some useful work,
2006		 * and therefore probably won't be called to block next
2007		 */
2008    int returnValue;
2009    int netin, netout, netex, ttyin, ttyout;
2010
2011    /* Decide which rings should be processed */
2012
2013    netout = ring_full_count(&netoring) &&
2014	    (flushline ||
2015		(my_want_state_is_wont(TELOPT_LINEMODE)
2016#ifdef	KLUDGELINEMODE
2017			&& (!kludgelinemode || my_want_state_is_do(TELOPT_SGA))
2018#endif
2019		) ||
2020			my_want_state_is_will(TELOPT_BINARY));
2021    ttyout = ring_full_count(&ttyoring);
2022
2023    ttyin = ring_empty_count(&ttyiring) && (clienteof == 0);
2024
2025    netin = !ISend && ring_empty_count(&netiring);
2026
2027    netex = !SYNCHing;
2028
2029    /* Call to system code to process rings */
2030
2031    returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
2032
2033    /* Now, look at the input rings, looking for work to do. */
2034
2035    if (ring_full_count(&ttyiring)) {
2036	    returnValue |= telsnd();
2037    }
2038
2039    if (ring_full_count(&netiring)) {
2040	returnValue |= telrcv();
2041    }
2042    return returnValue;
2043}
2044
2045#ifdef	AUTHENTICATION
2046#define __unusedhere
2047#else
2048#define __unusedhere __unused
2049#endif
2050/*
2051 * Select from tty and network...
2052 */
2053void
2054telnet(char *user __unusedhere)
2055{
2056    sys_telnet_init();
2057
2058#ifdef	AUTHENTICATION
2059#ifdef	ENCRYPTION
2060    {
2061	static char local_host[256] = { 0 };
2062
2063	if (!local_host[0]) {
2064		gethostname(local_host, sizeof(local_host));
2065		local_host[sizeof(local_host)-1] = 0;
2066	}
2067	auth_encrypt_init(local_host, hostname, "TELNET", 0);
2068	auth_encrypt_user(user);
2069    }
2070#endif
2071#endif
2072    if (telnetport) {
2073#ifdef	AUTHENTICATION
2074	if (autologin)
2075		send_will(TELOPT_AUTHENTICATION, 1);
2076#endif
2077#ifdef	ENCRYPTION
2078	send_do(TELOPT_ENCRYPT, 1);
2079	send_will(TELOPT_ENCRYPT, 1);
2080#endif	/* ENCRYPTION */
2081	send_do(TELOPT_SGA, 1);
2082	send_will(TELOPT_TTYPE, 1);
2083	send_will(TELOPT_NAWS, 1);
2084	send_will(TELOPT_TSPEED, 1);
2085	send_will(TELOPT_LFLOW, 1);
2086	send_will(TELOPT_LINEMODE, 1);
2087	send_will(TELOPT_NEW_ENVIRON, 1);
2088	send_do(TELOPT_STATUS, 1);
2089	if (env_getvalue("DISPLAY"))
2090	    send_will(TELOPT_XDISPLOC, 1);
2091	if (eight)
2092	    tel_enter_binary(eight);
2093    }
2094
2095    for (;;) {
2096	int schedValue;
2097
2098	while ((schedValue = Scheduler(0)) != 0) {
2099	    if (schedValue == -1) {
2100		setcommandmode();
2101		return;
2102	    }
2103	}
2104
2105	if (Scheduler(1) == -1) {
2106	    setcommandmode();
2107	    return;
2108	}
2109    }
2110}
2111
2112#if	0	/* XXX - this not being in is a bug */
2113/*
2114 * nextitem()
2115 *
2116 *	Return the address of the next "item" in the TELNET data
2117 * stream.  This will be the address of the next character if
2118 * the current address is a user data character, or it will
2119 * be the address of the character following the TELNET command
2120 * if the current address is a TELNET IAC ("I Am a Command")
2121 * character.
2122 */
2123
2124static char *
2125nextitem(char *current)
2126{
2127    if ((*current&0xff) != IAC) {
2128	return current+1;
2129    }
2130    switch (*(current+1)&0xff) {
2131    case DO:
2132    case DONT:
2133    case WILL:
2134    case WONT:
2135	return current+3;
2136    case SB:		/* loop forever looking for the SE */
2137	{
2138	    char *look = current+2;
2139
2140	    for (;;) {
2141		if ((*look++&0xff) == IAC) {
2142		    if ((*look++&0xff) == SE) {
2143			return look;
2144		    }
2145		}
2146	    }
2147	}
2148    default:
2149	return current+2;
2150    }
2151}
2152#endif	/* 0 */
2153
2154/*
2155 * netclear()
2156 *
2157 *	We are about to do a TELNET SYNCH operation.  Clear
2158 * the path to the network.
2159 *
2160 *	Things are a bit tricky since we may have sent the first
2161 * byte or so of a previous TELNET command into the network.
2162 * So, we have to scan the network buffer from the beginning
2163 * until we are up to where we want to be.
2164 *
2165 *	A side effect of what we do, just to keep things
2166 * simple, is to clear the urgent data pointer.  The principal
2167 * caller should be setting the urgent data pointer AFTER calling
2168 * us in any case.
2169 */
2170
2171static void
2172netclear(void)
2173{
2174	/* Deleted */
2175}
2176
2177/*
2178 * These routines add various telnet commands to the data stream.
2179 */
2180
2181static void
2182doflush(void)
2183{
2184    NET2ADD(IAC, DO);
2185    NETADD(TELOPT_TM);
2186    flushline = 1;
2187    flushout = 1;
2188    (void) ttyflush(1);			/* Flush/drop output */
2189    /* do printoption AFTER flush, otherwise the output gets tossed... */
2190    printoption("SENT", DO, TELOPT_TM);
2191}
2192
2193void
2194xmitAO(void)
2195{
2196    NET2ADD(IAC, AO);
2197    printoption("SENT", IAC, AO);
2198    if (autoflush) {
2199	doflush();
2200    }
2201}
2202
2203void
2204xmitEL(void)
2205{
2206    NET2ADD(IAC, EL);
2207    printoption("SENT", IAC, EL);
2208}
2209
2210void
2211xmitEC(void)
2212{
2213    NET2ADD(IAC, EC);
2214    printoption("SENT", IAC, EC);
2215}
2216
2217int
2218dosynch(char *ch __unused)
2219{
2220    netclear();			/* clear the path to the network */
2221    NETADD(IAC);
2222    setneturg();
2223    NETADD(DM);
2224    printoption("SENT", IAC, DM);
2225    return 1;
2226}
2227
2228int want_status_response = 0;
2229
2230int
2231get_status(char *ch __unused)
2232{
2233    unsigned char tmp[16];
2234    unsigned char *cp;
2235
2236    if (my_want_state_is_dont(TELOPT_STATUS)) {
2237	printf("Remote side does not support STATUS option\n");
2238	return 0;
2239    }
2240    cp = tmp;
2241
2242    *cp++ = IAC;
2243    *cp++ = SB;
2244    *cp++ = TELOPT_STATUS;
2245    *cp++ = TELQUAL_SEND;
2246    *cp++ = IAC;
2247    *cp++ = SE;
2248    if (NETROOM() >= cp - tmp) {
2249	ring_supply_data(&netoring, tmp, cp-tmp);
2250	printsub('>', tmp+2, cp - tmp - 2);
2251    }
2252    ++want_status_response;
2253    return 1;
2254}
2255
2256void
2257intp(void)
2258{
2259    NET2ADD(IAC, IP);
2260    printoption("SENT", IAC, IP);
2261    flushline = 1;
2262    if (autoflush) {
2263	doflush();
2264    }
2265    if (autosynch) {
2266	dosynch(NULL);
2267    }
2268}
2269
2270void
2271sendbrk(void)
2272{
2273    NET2ADD(IAC, BREAK);
2274    printoption("SENT", IAC, BREAK);
2275    flushline = 1;
2276    if (autoflush) {
2277	doflush();
2278    }
2279    if (autosynch) {
2280	dosynch(NULL);
2281    }
2282}
2283
2284void
2285sendabort(void)
2286{
2287    NET2ADD(IAC, ABORT);
2288    printoption("SENT", IAC, ABORT);
2289    flushline = 1;
2290    if (autoflush) {
2291	doflush();
2292    }
2293    if (autosynch) {
2294	dosynch(NULL);
2295    }
2296}
2297
2298void
2299sendsusp(void)
2300{
2301    NET2ADD(IAC, SUSP);
2302    printoption("SENT", IAC, SUSP);
2303    flushline = 1;
2304    if (autoflush) {
2305	doflush();
2306    }
2307    if (autosynch) {
2308	dosynch(NULL);
2309    }
2310}
2311
2312void
2313sendeof(void)
2314{
2315    NET2ADD(IAC, xEOF);
2316    printoption("SENT", IAC, xEOF);
2317}
2318
2319void
2320sendayt(void)
2321{
2322    NET2ADD(IAC, AYT);
2323    printoption("SENT", IAC, AYT);
2324}
2325
2326/*
2327 * Send a window size update to the remote system.
2328 */
2329
2330void
2331sendnaws(void)
2332{
2333    long rows, cols;
2334    unsigned char tmp[16];
2335    unsigned char *cp;
2336
2337    if (my_state_is_wont(TELOPT_NAWS))
2338	return;
2339
2340#define	PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
2341			    if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
2342
2343    if (TerminalWindowSize(&rows, &cols) == 0) {	/* Failed */
2344	return;
2345    }
2346
2347    cp = tmp;
2348
2349    *cp++ = IAC;
2350    *cp++ = SB;
2351    *cp++ = TELOPT_NAWS;
2352    PUTSHORT(cp, cols);
2353    PUTSHORT(cp, rows);
2354    *cp++ = IAC;
2355    *cp++ = SE;
2356    if (NETROOM() >= cp - tmp) {
2357	ring_supply_data(&netoring, tmp, cp-tmp);
2358	printsub('>', tmp+2, cp - tmp - 2);
2359    }
2360}
2361
2362void
2363tel_enter_binary(int rw)
2364{
2365    if (rw&1)
2366	send_do(TELOPT_BINARY, 1);
2367    if (rw&2)
2368	send_will(TELOPT_BINARY, 1);
2369}
2370
2371void
2372tel_leave_binary(int rw)
2373{
2374    if (rw&1)
2375	send_dont(TELOPT_BINARY, 1);
2376    if (rw&2)
2377	send_wont(TELOPT_BINARY, 1);
2378}
2379