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