1 /*
2  * Copyright (c) 1989, 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 /* based on @(#)state.c	8.1 (Berkeley) 6/4/93 */
35 
36 #include <autoconf.h>
37 
38 #include "telnetd.h"
39 #if	defined(AUTHENTICATION)
40 #include <libtelnet/auth.h>
41 #endif
42 #if defined(ENCRYPTION)
43 #include <libtelnet/encrypt.h>
44 #endif
45 
46 unsigned char	doopt[] = { IAC, DO, '%', 'c', 0 };
47 unsigned char	dont[] = { IAC, DONT, '%', 'c', 0 };
48 unsigned char	will[] = { IAC, WILL, '%', 'c', 0 };
49 unsigned char	wont[] = { IAC, WONT, '%', 'c', 0 };
50 int	not42 = 1;
51 
52 static int envvarok (char *);
53 
54 /*
55  * Buffer for sub-options, and macros
56  * for suboptions buffer manipulations
57  */
58 unsigned char subbuffer[TELNET_BUFSIZE], *subpointer= subbuffer, *subend= subbuffer;
59 
60 #define	SB_CLEAR()	subpointer = subbuffer
61 #define	SB_TERM()	{ subend = subpointer; SB_CLEAR(); }
62 #define	SB_ACCUM(c)	if (subpointer < (subbuffer+sizeof subbuffer)) { \
63 				*subpointer++ = (c); \
64 			}
65 #define	SB_GET()	((*subpointer++)&0xff)
66 #define	SB_EOF()	(subpointer >= subend)
67 #define	SB_LEN()	(subend - subpointer)
68 
69 #ifdef	ENV_HACK
70 unsigned char *subsave;
71 #define SB_SAVE()	subsave = subpointer;
72 #define	SB_RESTORE()	subpointer = subsave;
73 #endif
74 
75 
76 /*
77  * State for recv fsm
78  */
79 #define	TS_DATA		0	/* base state */
80 #define	TS_IAC		1	/* look for double IAC's */
81 #define	TS_CR		2	/* CR-LF ->'s CR */
82 #define	TS_SB		3	/* throw away begin's... */
83 #define	TS_SE		4	/* ...end's (suboption negotiation) */
84 #define	TS_WILL		5	/* will option negotiation */
85 #define	TS_WONT		6	/* wont " */
86 #define	TS_DO		7	/* do " */
87 #define	TS_DONT		8	/* dont " */
88 
sb_auth_complete()89 static void sb_auth_complete()
90 {
91   if (!auth_negotiated) {
92     static char *error =
93       "An environment option was sent before authentication negotiation completed.\r\nThis may create a security hazard. Connection dropped.\r\n";
94     netputs(error);
95     netflush();
96     exit(1);
97   }
98 }
99 
100 	void
telrcv()101 telrcv()
102 {
103 	register int c;
104 	static int state = TS_DATA;
105 #if	defined(CRAY2) && defined(UNICOS5)
106 	char *opfrontp = pfrontp;
107 #endif
108 
109 	while (ncc > 0) {
110 		if ((&ptyobuf[BUFSIZ] - pfrontp) < 1)
111 			break;
112 		c = *netip++ & 0377, ncc--;
113 #ifdef	ENCRYPTION
114 		if (decrypt_input)
115 			c = (*decrypt_input)(c);
116 #endif	/* ENCRYPTION */
117 		switch (state) {
118 
119 		case TS_CR:
120 			state = TS_DATA;
121 			/* Strip off \n or \0 after a \r */
122 			if ((c == 0) || (c == '\n')) {
123 				break;
124 			}
125 			/* FALL THROUGH */
126 
127 		case TS_DATA:
128 			if (c == IAC) {
129 				state = TS_IAC;
130 				break;
131 			}
132 			/*
133 			 * We now map \r\n ==> \r for pragmatic reasons.
134 			 * Many client implementations send \r\n when
135 			 * the user hits the CarriageReturn key.
136 			 *
137 			 * We USED to map \r\n ==> \n, since \r\n says
138 			 * that we want to be in column 1 of the next
139 			 * printable line, and \n is the standard
140 			 * unix way of saying that (\r is only good
141 			 * if CRMOD is set, which it normally is).
142 			 */
143 			if ((c == '\r') && his_state_is_wont(TELOPT_BINARY)) {
144 				int nc = *netip;
145 #ifdef	ENCRYPTION
146 				if (decrypt_input)
147 					nc = (*decrypt_input)(nc & 0xff);
148 #endif	/* ENCRYPTION */
149 #ifdef	LINEMODE
150 				/*
151 				 * If we are operating in linemode,
152 				 * convert to local end-of-line.
153 				 */
154 				if (linemode && (ncc > 0) && (('\n' == nc) ||
155 					 ((0 == nc) && tty_iscrnl())) ) {
156 					netip++; ncc--;
157 					c = '\n';
158 				} else
159 #endif
160 				{
161 #ifdef	ENCRYPTION
162 					if (decrypt_input)
163 						(void)(*decrypt_input)(-1);
164 #endif	/* ENCRYPTION */
165 					state = TS_CR;
166 				}
167 			}
168 			*pfrontp++ = c;
169 			break;
170 
171 		case TS_IAC:
172 gotiac:			switch (c) {
173 
174 			/*
175 			 * Send the process on the pty side an
176 			 * interrupt.  Do this with a NULL or
177 			 * interrupt char; depending on the tty mode.
178 			 */
179 			case IP:
180 				DIAG(TD_OPTIONS,
181 					printoption("td: recv IAC", c));
182 				interrupt();
183 				break;
184 
185 			case BREAK:
186 				DIAG(TD_OPTIONS,
187 					printoption("td: recv IAC", c));
188 				sendbrk();
189 				break;
190 
191 			/*
192 			 * Are You There?
193 			 */
194 			case AYT:
195 				DIAG(TD_OPTIONS,
196 					printoption("td: recv IAC", c));
197 				recv_ayt();
198 				break;
199 
200 			/*
201 			 * Abort Output
202 			 */
203 			case AO:
204 			    {
205 				DIAG(TD_OPTIONS,
206 					printoption("td: recv IAC", c));
207 				ptyflush();	/* half-hearted */
208 				init_termbuf();
209 
210 				if (slctab[SLC_AO].sptr &&
211 				    *slctab[SLC_AO].sptr != (cc_t)(_POSIX_VDISABLE)) {
212 				    *pfrontp++ =
213 					(unsigned char)*slctab[SLC_AO].sptr;
214 				}
215 
216 				netclear();	/* clear buffer back */
217 				netprintf_urg("%c%c", IAC, DM);
218 				DIAG(TD_OPTIONS,
219 					printoption("td: send IAC", DM));
220 				break;
221 			    }
222 
223 			/*
224 			 * Erase Character and
225 			 * Erase Line
226 			 */
227 			case EC:
228 			case EL:
229 			    {
230 				cc_t ch;
231 
232 				DIAG(TD_OPTIONS,
233 					printoption("td: recv IAC", c));
234 				ptyflush();	/* half-hearted */
235 				init_termbuf();
236 				if (c == EC)
237 					ch = *slctab[SLC_EC].sptr;
238 				else
239 					ch = *slctab[SLC_EL].sptr;
240 				if (ch != (cc_t)(_POSIX_VDISABLE))
241 					*pfrontp++ = (unsigned char)ch;
242 				break;
243 			    }
244 
245 			/*
246 			 * Check for urgent data...
247 			 */
248 			case DM:
249 				DIAG(TD_OPTIONS,
250 					printoption("td: recv IAC", c));
251 				SYNCHing = stilloob(net);
252 				settimer(gotDM);
253 				break;
254 
255 
256 			/*
257 			 * Begin option subnegotiation...
258 			 */
259 			case SB:
260 				state = TS_SB;
261 				SB_CLEAR();
262 				continue;
263 
264 			case WILL:
265 				state = TS_WILL;
266 				continue;
267 
268 			case WONT:
269 				state = TS_WONT;
270 				continue;
271 
272 			case DO:
273 				state = TS_DO;
274 				continue;
275 
276 			case DONT:
277 				state = TS_DONT;
278 				continue;
279 			case EOR:
280 				if (his_state_is_will(TELOPT_EOR))
281 					doeof();
282 				break;
283 
284 			/*
285 			 * Handle RFC 10xx Telnet linemode option additions
286 			 * to command stream (EOF, SUSP, ABORT).
287 			 */
288 			case xEOF:
289 				doeof();
290 				break;
291 
292 			case SUSP:
293 				sendsusp();
294 				break;
295 
296 			case ABORT:
297 				sendbrk();
298 				break;
299 
300 			case IAC:
301 				*pfrontp++ = c;
302 				break;
303 			}
304 			state = TS_DATA;
305 			break;
306 
307 		case TS_SB:
308 			if (c == IAC) {
309 				state = TS_SE;
310 			} else {
311 				SB_ACCUM(c);
312 			}
313 			break;
314 
315 		case TS_SE:
316 			if (c != SE) {
317 				if (c != IAC) {
318 					/*
319 					 * bad form of suboption negotiation.
320 					 * handle it in such a way as to avoid
321 					 * damage to local state.  Parse
322 					 * suboption buffer found so far,
323 					 * then treat remaining stream as
324 					 * another command sequence.
325 					 */
326 
327 					/* for DIAGNOSTICS */
328 					SB_ACCUM(IAC);
329 					SB_ACCUM(c);
330 					subpointer -= 2;
331 
332 					SB_TERM();
333 					suboption();
334 					state = TS_IAC;
335 					goto gotiac;
336 				}
337 				SB_ACCUM(c);
338 				state = TS_SB;
339 			} else {
340 				/* for DIAGNOSTICS */
341 				SB_ACCUM(IAC);
342 				SB_ACCUM(SE);
343 				subpointer -= 2;
344 
345 				SB_TERM();
346 				suboption();	/* handle sub-option */
347 				state = TS_DATA;
348 			}
349 			break;
350 
351 		case TS_WILL:
352 			willoption(c);
353 			state = TS_DATA;
354 			continue;
355 
356 		case TS_WONT:
357 			wontoption(c);
358 			state = TS_DATA;
359 			continue;
360 
361 		case TS_DO:
362 			dooption(c);
363 			state = TS_DATA;
364 			continue;
365 
366 		case TS_DONT:
367 			dontoption(c);
368 			state = TS_DATA;
369 			continue;
370 
371 		default:
372 			syslog(LOG_ERR, "telnetd: panic state=%d", state);
373 			printf("telnetd: panic state=%d\n", state);
374 			exit(1);
375 		}
376 	}
377 #if	defined(CRAY2) && defined(UNICOS5)
378 	if (!linemode) {
379 		char	xptyobuf[BUFSIZ+NETSLOP];
380 		char	xbuf2[BUFSIZ];
381 		register char *cp;
382 		int n = pfrontp - opfrontp, oc;
383 		memcpy(xptyobuf, opfrontp, n);
384 		pfrontp = opfrontp;
385 		pfrontp += term_input(xptyobuf, pfrontp, n, BUFSIZ+NETSLOP,
386 					xbuf2, &oc, BUFSIZ);
387 		for (cp = xbuf2; oc > 0; --oc) {
388 			if (*cp == IAC)
389 				netprintf("%c%c", *cp++, IAC);
390 			else
391 				netprintf("%c", *cp++);
392 		}
393 	}
394 #endif	/* defined(CRAY2) && defined(UNICOS5) */
395 }  /* end of telrcv */
396 
397 /*
398  * The will/wont/do/dont state machines are based on Dave Borman's
399  * Telnet option processing state machine.
400  *
401  * These correspond to the following states:
402  *	my_state = the last negotiated state
403  *	want_state = what I want the state to go to
404  *	want_resp = how many requests I have sent
405  * All state defaults are negative, and resp defaults to 0.
406  *
407  * When initiating a request to change state to new_state:
408  *
409  * if ((want_resp == 0 && new_state == my_state) || want_state == new_state) {
410  *	do nothing;
411  * } else {
412  *	want_state = new_state;
413  *	send new_state;
414  *	want_resp++;
415  * }
416  *
417  * When receiving new_state:
418  *
419  * if (want_resp) {
420  *	want_resp--;
421  *	if (want_resp && (new_state == my_state))
422  *		want_resp--;
423  * }
424  * if ((want_resp == 0) && (new_state != want_state)) {
425  *	if (ok_to_switch_to new_state)
426  *		want_state = new_state;
427  *	else
428  *		want_resp++;
429  *	send want_state;
430  * }
431  * my_state = new_state;
432  *
433  * Note that new_state is implied in these functions by the function itself.
434  * will and do imply positive new_state, wont and dont imply negative.
435  *
436  * Finally, there is one catch.  If we send a negative response to a
437  * positive request, my_state will be the positive while want_state will
438  * remain negative.  my_state will revert to negative when the negative
439  * acknowlegment arrives from the peer.  Thus, my_state generally tells
440  * us not only the last negotiated state, but also tells us what the peer
441  * wants to be doing as well.  It is important to understand this difference
442  * as we may wish to be processing data streams based on our desired state
443  * (want_state) or based on what the peer thinks the state is (my_state).
444  *
445  * This all works fine because if the peer sends a positive request, the data
446  * that we receive prior to negative acknowlegment will probably be affected
447  * by the positive state, and we can process it as such (if we can; if we
448  * can't then it really doesn't matter).  If it is that important, then the
449  * peer probably should be buffering until this option state negotiation
450  * is complete.
451  *
452  */
453 	void
send_do(option,init)454 send_do(option, init)
455 	int option, init;
456 {
457 	if (init) {
458 		if ((do_dont_resp[option] == 0 && his_state_is_will(option)) ||
459 		    his_want_state_is_will(option))
460 			return;
461 		/*
462 		 * Special case for TELOPT_TM:  We send a DO, but pretend
463 		 * that we sent a DONT, so that we can send more DOs if
464 		 * we want to.
465 		 */
466 		if (option == TELOPT_TM)
467 			set_his_want_state_wont(option);
468 		else
469 			set_his_want_state_will(option);
470 		do_dont_resp[option]++;
471 	}
472 	netprintf((char *)doopt, option);
473 
474 	DIAG(TD_OPTIONS, printoption("td: send do", option));
475 }
476 
477 #ifdef	AUTHENTICATION
478 extern void auth_request();
479 #endif
480 #ifdef	LINEMODE
481 static void doclientstat(void);
482 #endif
483 #ifdef	ENCRYPTION
484 extern void encrypt_send_support();
485 #endif	/* ENCRYPTION */
486 
487 	void
willoption(option)488 willoption(option)
489 	int option;
490 {
491 	int changeok = 0;
492 	void (*func)() = 0;
493 
494 	/*
495 	 * process input from peer.
496 	 */
497 
498 	DIAG(TD_OPTIONS, printoption("td: recv will", option));
499 
500 	if (do_dont_resp[option]) {
501 		do_dont_resp[option]--;
502 		if (do_dont_resp[option] && his_state_is_will(option))
503 			do_dont_resp[option]--;
504 	}
505 	if (do_dont_resp[option] == 0) {
506 	    if (his_want_state_is_wont(option)) {
507 		switch (option) {
508 
509 		case TELOPT_BINARY:
510 			init_termbuf();
511 			tty_binaryin(1);
512 			set_termbuf();
513 			changeok++;
514 			break;
515 
516 		case TELOPT_ECHO:
517 			/*
518 			 * See comments below for more info.
519 			 */
520 			not42 = 0;	/* looks like a 4.2 system */
521 			break;
522 
523 		case TELOPT_TM:
524 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
525 			/*
526 			 * This telnetd implementation does not really
527 			 * support timing marks, it just uses them to
528 			 * support the kludge linemode stuff.  If we
529 			 * receive a will or wont TM in response to our
530 			 * do TM request that may have been sent to
531 			 * determine kludge linemode support, process
532 			 * it, otherwise TM should get a negative
533 			 * response back.
534 			 */
535 			/*
536 			 * Handle the linemode kludge stuff.
537 			 * If we are not currently supporting any
538 			 * linemode at all, then we assume that this
539 			 * is the client telling us to use kludge
540 			 * linemode in response to our query.  Set the
541 			 * linemode type that is to be supported, note
542 			 * that the client wishes to use linemode, and
543 			 * eat the will TM as though it never arrived.
544 			 */
545 			if (lmodetype < KLUDGE_LINEMODE) {
546 				lmodetype = KLUDGE_LINEMODE;
547 				clientstat(TELOPT_LINEMODE, WILL, 0);
548 				send_wont(TELOPT_SGA, 1);
549 			} else if (lmodetype == NO_AUTOKLUDGE) {
550 				lmodetype = KLUDGE_OK;
551 			}
552 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
553 			/*
554 			 * We never respond to a WILL TM, and
555 			 * we leave the state WONT.
556 			 */
557 			return;
558 
559 		case TELOPT_LFLOW:
560 			/*
561 			 * If we are going to support flow control
562 			 * option, then don't worry peer that we can't
563 			 * change the flow control characters.
564 			 */
565 			slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
566 			slctab[SLC_XON].defset.flag |= SLC_DEFAULT;
567 			slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
568 			slctab[SLC_XOFF].defset.flag |= SLC_DEFAULT;
569 		case TELOPT_TTYPE:
570 		case TELOPT_SGA:
571 		case TELOPT_NAWS:
572 		case TELOPT_TSPEED:
573 		case TELOPT_XDISPLOC:
574 		case TELOPT_NEW_ENVIRON:
575 		case TELOPT_OLD_ENVIRON:
576 			changeok++;
577 			break;
578 
579 #ifdef	LINEMODE
580 		case TELOPT_LINEMODE:
581 # ifdef	KLUDGELINEMODE
582 			/*
583 			 * Note client's desire to use linemode.
584 			 */
585 			lmodetype = REAL_LINEMODE;
586 # endif	/* KLUDGELINEMODE */
587 			func = doclientstat;
588 			changeok++;
589 			break;
590 #endif	/* LINEMODE */
591 
592 #ifdef	AUTHENTICATION
593 		case TELOPT_AUTHENTICATION:
594 			func = auth_request;
595 			changeok++;
596 			break;
597 #endif
598 
599 #ifdef	ENCRYPTION
600 		case TELOPT_ENCRYPT:
601 			func = encrypt_send_support;
602 			changeok++;
603 			break;
604 #endif	/* ENCRYPTION */
605 
606 		default:
607 			break;
608 		}
609 		if (changeok) {
610 			set_his_want_state_will(option);
611 			send_do(option, 0);
612 		} else {
613 			do_dont_resp[option]++;
614 			send_dont(option, 0);
615 		}
616 	    } else {
617 		/*
618 		 * Option processing that should happen when
619 		 * we receive conformation of a change in
620 		 * state that we had requested.
621 		 */
622 		switch (option) {
623 		case TELOPT_ECHO:
624 			not42 = 0;	/* looks like a 4.2 system */
625 			/*
626 			 * Egads, he responded "WILL ECHO".  Turn
627 			 * it off right now!
628 			 */
629 			send_dont(option, 1);
630 			/*
631 			 * "WILL ECHO".  Kludge upon kludge!
632 			 * A 4.2 client is now echoing user input at
633 			 * the tty.  This is probably undesireable and
634 			 * it should be stopped.  The client will
635 			 * respond WONT TM to the DO TM that we send to
636 			 * check for kludge linemode.  When the WONT TM
637 			 * arrives, linemode will be turned off and a
638 			 * change propogated to the pty.  This change
639 			 * will cause us to process the new pty state
640 			 * in localstat(), which will notice that
641 			 * linemode is off and send a WILL ECHO
642 			 * so that we are properly in character mode and
643 			 * all is well.
644 			 */
645 			break;
646 #ifdef	LINEMODE
647 		case TELOPT_LINEMODE:
648 # ifdef	KLUDGELINEMODE
649 			/*
650 			 * Note client's desire to use linemode.
651 			 */
652 			lmodetype = REAL_LINEMODE;
653 # endif	/* KLUDGELINEMODE */
654 			func = doclientstat;
655 			break;
656 #endif	/* LINEMODE */
657 
658 #ifdef	AUTHENTICATION
659 		case TELOPT_AUTHENTICATION:
660 			func = auth_request;
661 			break;
662 #endif
663 
664 #ifdef	ENCRYPTION
665 		case TELOPT_ENCRYPT:
666 			func = encrypt_send_support;
667 			break;
668 #endif	/* ENCRYPTION */
669 		case TELOPT_LFLOW:
670 			func = flowstat;
671 			break;
672 		}
673 	    }
674 	}
675 	set_his_state_will(option);
676 	if (func)
677 		(*func)();
678 }  /* end of willoption */
679 
680 	void
send_dont(option,init)681 send_dont(option, init)
682 	int option, init;
683 {
684 	if (init) {
685 		if ((do_dont_resp[option] == 0 && his_state_is_wont(option)) ||
686 		    his_want_state_is_wont(option))
687 			return;
688 		set_his_want_state_wont(option);
689 		do_dont_resp[option]++;
690 	}
691 	netprintf((char *)dont, option);
692 
693 	DIAG(TD_OPTIONS, printoption("td: send dont", option));
694 }
695 
696 	void
wontoption(option)697 wontoption(option)
698 	int option;
699 {
700 	/*
701 	 * Process client input.
702 	 */
703 
704 	DIAG(TD_OPTIONS, printoption("td: recv wont", option));
705 
706 	if (do_dont_resp[option]) {
707 		do_dont_resp[option]--;
708 		if (do_dont_resp[option] && his_state_is_wont(option))
709 			do_dont_resp[option]--;
710 	}
711 	if (do_dont_resp[option] == 0) {
712 	    if (his_want_state_is_will(option)) {
713 		/* it is always ok to change to negative state */
714 		switch (option) {
715 		case TELOPT_ECHO:
716 			not42 = 1; /* doesn't seem to be a 4.2 system */
717 			break;
718 
719 		case TELOPT_BINARY:
720 			init_termbuf();
721 			tty_binaryin(0);
722 			set_termbuf();
723 			break;
724 
725 #ifdef	LINEMODE
726 		case TELOPT_LINEMODE:
727 # ifdef	KLUDGELINEMODE
728 			/*
729 			 * If real linemode is supported, then client is
730 			 * asking to turn linemode off.
731 			 */
732 			if (lmodetype != REAL_LINEMODE)
733 				break;
734 			lmodetype = KLUDGE_LINEMODE;
735 # endif	/* KLUDGELINEMODE */
736 			clientstat(TELOPT_LINEMODE, WONT, 0);
737 			break;
738 #endif	/* LINEMODE */
739 
740 		case TELOPT_TM:
741 			/*
742 			 * If we get a WONT TM, and had sent a DO TM,
743 			 * don't respond with a DONT TM, just leave it
744 			 * as is.  Short circut the state machine to
745 			 * achive this.
746 			 */
747 			set_his_want_state_wont(TELOPT_TM);
748 			return;
749 
750 		case TELOPT_LFLOW:
751 			/*
752 			 * If we are not going to support flow control
753 			 * option, then let peer know that we can't
754 			 * change the flow control characters.
755 			 */
756 			slctab[SLC_XON].defset.flag &= ~SLC_LEVELBITS;
757 			slctab[SLC_XON].defset.flag |= SLC_CANTCHANGE;
758 			slctab[SLC_XOFF].defset.flag &= ~SLC_LEVELBITS;
759 			slctab[SLC_XOFF].defset.flag |= SLC_CANTCHANGE;
760 			break;
761 
762 #if	defined(AUTHENTICATION)
763 		case TELOPT_AUTHENTICATION:
764 			auth_finished(0, AUTH_REJECT);
765 			break;
766 #endif
767 
768 		/*
769 		 * For options that we might spin waiting for
770 		 * sub-negotiation, if the client turns off the
771 		 * option rather than responding to the request,
772 		 * we have to treat it here as if we got a response
773 		 * to the sub-negotiation, (by updating the timers)
774 		 * so that we'll break out of the loop.
775 		 */
776 		case TELOPT_TTYPE:
777 			settimer(ttypesubopt);
778 			break;
779 
780 		case TELOPT_TSPEED:
781 			settimer(tspeedsubopt);
782 			break;
783 
784 		case TELOPT_XDISPLOC:
785 			settimer(xdisplocsubopt);
786 			break;
787 
788 		case TELOPT_OLD_ENVIRON:
789 			settimer(oenvironsubopt);
790 			break;
791 
792 		case TELOPT_NEW_ENVIRON:
793 			settimer(environsubopt);
794 			break;
795 
796 		default:
797 			break;
798 		}
799 		set_his_want_state_wont(option);
800 		if (his_state_is_will(option))
801 			send_dont(option, 0);
802 	    } else {
803 		switch (option) {
804 		case TELOPT_TM:
805 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
806 			if (lmodetype < NO_AUTOKLUDGE) {
807 				lmodetype = NO_LINEMODE;
808 				clientstat(TELOPT_LINEMODE, WONT, 0);
809 				send_will(TELOPT_SGA, 1);
810 				send_will(TELOPT_ECHO, 1);
811 			}
812 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
813 			break;
814 
815 #if	defined(AUTHENTICATION)
816 		case TELOPT_AUTHENTICATION:
817 			auth_finished(0, AUTH_REJECT);
818 			break;
819 #endif
820 		default:
821 			break;
822 		}
823 	    }
824 	}
825 	set_his_state_wont(option);
826 
827 }  /* end of wontoption */
828 
829 	void
send_will(option,init)830 send_will(option, init)
831 	int option, init;
832 {
833 	if (init) {
834 		if ((will_wont_resp[option] == 0 && my_state_is_will(option))||
835 		    my_want_state_is_will(option))
836 			return;
837 		set_my_want_state_will(option);
838 		will_wont_resp[option]++;
839 	}
840 	netprintf((char *)will, option);
841 
842 	DIAG(TD_OPTIONS, printoption("td: send will", option));
843 }
844 
845 #if	!defined(LINEMODE) || !defined(KLUDGELINEMODE)
846 /*
847  * When we get a DONT SGA, we will try once to turn it
848  * back on.  If the other side responds DONT SGA, we
849  * leave it at that.  This is so that when we talk to
850  * clients that understand KLUDGELINEMODE but not LINEMODE,
851  * we'll keep them in char-at-a-time mode.
852  */
853 int turn_on_sga = 0;
854 #endif
855 
856 	void
dooption(option)857 dooption(option)
858 	int option;
859 {
860 	int changeok = 0;
861 
862 	/*
863 	 * Process client input.
864 	 */
865 
866 	DIAG(TD_OPTIONS, printoption("td: recv do", option));
867 
868 	if (will_wont_resp[option]) {
869 		will_wont_resp[option]--;
870 		if (will_wont_resp[option] && my_state_is_will(option))
871 			will_wont_resp[option]--;
872 	}
873 	if ((will_wont_resp[option] == 0) && (my_want_state_is_wont(option))) {
874 		switch (option) {
875 		case TELOPT_ECHO:
876 #ifdef	LINEMODE
877 # ifdef	KLUDGELINEMODE
878 			if (lmodetype == NO_LINEMODE)
879 # else
880 			if (his_state_is_wont(TELOPT_LINEMODE))
881 # endif
882 #endif
883 			{
884 				init_termbuf();
885 				tty_setecho(1);
886 				set_termbuf();
887 			}
888 			changeok++;
889 			break;
890 
891 		case TELOPT_BINARY:
892 			init_termbuf();
893 			tty_binaryout(1);
894 			set_termbuf();
895 			changeok++;
896 			break;
897 
898 		case TELOPT_SGA:
899 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
900 			/*
901 			 * If kludge linemode is in use, then we must
902 			 * process an incoming do SGA for linemode
903 			 * purposes.
904 			 */
905 			if (lmodetype == KLUDGE_LINEMODE) {
906 				/*
907 				 * Receipt of "do SGA" in kludge
908 				 * linemode is the peer asking us to
909 				 * turn off linemode.  Make note of
910 				 * the request.
911 				 */
912 				clientstat(TELOPT_LINEMODE, WONT, 0);
913 				/*
914 				 * If linemode did not get turned off
915 				 * then don't tell peer that we did.
916 				 * Breaking here forces a wont SGA to
917 				 * be returned.
918 				 */
919 				if (linemode)
920 					break;
921 			}
922 #else
923 			turn_on_sga = 0;
924 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
925 			changeok++;
926 			break;
927 
928 		case TELOPT_STATUS:
929 			changeok++;
930 			break;
931 
932 		case TELOPT_TM:
933 			/*
934 			 * Special case for TM.  We send a WILL, but
935 			 * pretend we sent a WONT.
936 			 */
937 			send_will(option, 0);
938 			set_my_want_state_wont(option);
939 			set_my_state_wont(option);
940 			return;
941 
942 		case TELOPT_LOGOUT:
943 			/*
944 			 * When we get a LOGOUT option, respond
945 			 * with a WILL LOGOUT, make sure that
946 			 * it gets written out to the network,
947 			 * and then just go away...
948 			 */
949 			set_my_want_state_will(TELOPT_LOGOUT);
950 			send_will(TELOPT_LOGOUT, 0);
951 			set_my_state_will(TELOPT_LOGOUT);
952 			(void)netflush();
953 			(void)signal(SIGCHLD, SIG_DFL);
954 			cleanup(0);
955 			/* NOT REACHED */
956 			break;
957 
958 #ifdef	ENCRYPTION
959 		case TELOPT_ENCRYPT:
960 			changeok++;
961 			break;
962 #endif	/* ENCRYPTION */
963 		case TELOPT_LINEMODE:
964 		case TELOPT_TTYPE:
965 		case TELOPT_NAWS:
966 		case TELOPT_TSPEED:
967 		case TELOPT_LFLOW:
968 		case TELOPT_XDISPLOC:
969 #ifdef	TELOPT_ENVIRON
970 		case TELOPT_NEW_ENVIRON:
971 #endif
972 		case TELOPT_OLD_ENVIRON:
973 		default:
974 			break;
975 		}
976 		if (changeok) {
977 			set_my_want_state_will(option);
978 			send_will(option, 0);
979 		} else {
980 			will_wont_resp[option]++;
981 			send_wont(option, 0);
982 		}
983 	}
984 	set_my_state_will(option);
985 
986 }  /* end of dooption */
987 
988 	void
send_wont(option,init)989 send_wont(option, init)
990 	int option, init;
991 {
992 	if (init) {
993 		if ((will_wont_resp[option] == 0 && my_state_is_wont(option)) ||
994 		    my_want_state_is_wont(option))
995 			return;
996 		set_my_want_state_wont(option);
997 		will_wont_resp[option]++;
998 	}
999 	netprintf((char *)wont, option);
1000 
1001 	DIAG(TD_OPTIONS, printoption("td: send wont", option));
1002 }
1003 
1004 	void
dontoption(option)1005 dontoption(option)
1006 	int option;
1007 {
1008 	/*
1009 	 * Process client input.
1010 	 */
1011 
1012 
1013 	DIAG(TD_OPTIONS, printoption("td: recv dont", option));
1014 
1015 	if (will_wont_resp[option]) {
1016 		will_wont_resp[option]--;
1017 		if (will_wont_resp[option] && my_state_is_wont(option))
1018 			will_wont_resp[option]--;
1019 	}
1020 	if ((will_wont_resp[option] == 0) && (my_want_state_is_will(option))) {
1021 		switch (option) {
1022 		case TELOPT_BINARY:
1023 			init_termbuf();
1024 			tty_binaryout(0);
1025 			set_termbuf();
1026 			break;
1027 
1028 		case TELOPT_ECHO:	/* we should stop echoing */
1029 #ifdef	LINEMODE
1030 # ifdef	KLUDGELINEMODE
1031 			if ((lmodetype != REAL_LINEMODE) &&
1032 			    (lmodetype != KLUDGE_LINEMODE))
1033 # else
1034 			if (his_state_is_wont(TELOPT_LINEMODE))
1035 # endif
1036 #endif
1037 			{
1038 				init_termbuf();
1039 				tty_setecho(0);
1040 				set_termbuf();
1041 			}
1042 			break;
1043 
1044 		case TELOPT_SGA:
1045 #if	defined(LINEMODE) && defined(KLUDGELINEMODE)
1046 			/*
1047 			 * If kludge linemode is in use, then we
1048 			 * must process an incoming do SGA for
1049 			 * linemode purposes.
1050 			 */
1051 			if ((lmodetype == KLUDGE_LINEMODE) ||
1052 			    (lmodetype == KLUDGE_OK)) {
1053 				/*
1054 				 * The client is asking us to turn
1055 				 * linemode on.
1056 				 */
1057 				lmodetype = KLUDGE_LINEMODE;
1058 				clientstat(TELOPT_LINEMODE, WILL, 0);
1059 				/*
1060 				 * If we did not turn line mode on,
1061 				 * then what do we say?  Will SGA?
1062 				 * This violates design of telnet.
1063 				 * Gross.  Very Gross.
1064 				 */
1065 			}
1066 			break;
1067 #else
1068 			set_my_want_state_wont(option);
1069 			if (my_state_is_will(option))
1070 				send_wont(option, 0);
1071 			set_my_state_wont(option);
1072 			if (turn_on_sga ^= 1)
1073 				send_will(option, 1);
1074 			return;
1075 #endif	/* defined(LINEMODE) && defined(KLUDGELINEMODE) */
1076 
1077 		default:
1078 			break;
1079 		}
1080 
1081 		set_my_want_state_wont(option);
1082 		if (my_state_is_will(option))
1083 			send_wont(option, 0);
1084 	}
1085 	set_my_state_wont(option);
1086 
1087 }  /* end of dontoption */
1088 
1089 #ifdef	ENV_HACK
1090 int env_ovar = -1;
1091 int env_ovalue = -1;
1092 #else	/* ENV_HACK */
1093 # define env_ovar OLD_ENV_VAR
1094 # define env_ovalue OLD_ENV_VALUE
1095 #endif	/* ENV_HACK */
1096 
1097 /*
1098  * suboption()
1099  *
1100  *	Look at the sub-option buffer, and try to be helpful to the other
1101  * side.
1102  *
1103  *	Currently we recognize:
1104  *
1105  *	Terminal type is
1106  *	Linemode
1107  *	Window size
1108  *	Terminal speed
1109  */
1110 	void
suboption()1111 suboption()
1112 {
1113     register int subchar;
1114 
1115     DIAG(TD_OPTIONS, {netflush(); printsub('<', subpointer, SB_LEN()+2);});
1116 
1117     subchar = SB_GET();
1118     switch (subchar) {
1119     case TELOPT_TSPEED: {
1120 	register int xspeed, rspeed;
1121 
1122 	if (his_state_is_wont(TELOPT_TSPEED))	/* Ignore if option disabled */
1123 		break;
1124 
1125 	sb_auth_complete();
1126 
1127 	settimer(tspeedsubopt);
1128 
1129 	if (SB_EOF() || SB_GET() != TELQUAL_IS)
1130 		return;
1131 
1132 	xspeed = atoi((char *)subpointer);
1133 
1134 	while (SB_GET() != ',' && !SB_EOF());
1135 	if (SB_EOF())
1136 		return;
1137 
1138 	rspeed = atoi((char *)subpointer);
1139 	clientstat(TELOPT_TSPEED, xspeed, rspeed);
1140 
1141 	break;
1142 
1143     }  /* end of case TELOPT_TSPEED */
1144 
1145     case TELOPT_TTYPE: {		/* Yaaaay! */
1146 	char *tt;
1147 
1148 	if (his_state_is_wont(TELOPT_TTYPE))	/* Ignore if option disabled */
1149 		break;
1150 	sb_auth_complete();
1151 	settimer(ttypesubopt);
1152 
1153 	if (SB_EOF() || SB_GET() != TELQUAL_IS) {
1154 	    return;		/* ??? XXX but, this is the most robust */
1155 	}
1156 
1157 	tt = terminaltype;
1158 
1159 	while ((tt < (terminaltype + sizeof(terminaltype) - 1)) && !SB_EOF()) {
1160 	    register int c;
1161 
1162 	    c = SB_GET();
1163 	    if (isupper(c)) {
1164 		c = tolower(c);
1165 	    }
1166 	    *tt++ = c;    /* accumulate name */
1167 	}
1168 	*tt = 0;
1169 	break;
1170     }  /* end of case TELOPT_TTYPE */
1171 
1172     case TELOPT_NAWS: {
1173 	register int xwinsize, ywinsize;
1174 
1175 	if (his_state_is_wont(TELOPT_NAWS))	/* Ignore if option disabled */
1176 		break;
1177 
1178 	if (SB_EOF())
1179 		return;
1180 	xwinsize = SB_GET() << 8;
1181 	if (SB_EOF())
1182 		return;
1183 	xwinsize |= SB_GET();
1184 	if (SB_EOF())
1185 		return;
1186 	ywinsize = SB_GET() << 8;
1187 	if (SB_EOF())
1188 		return;
1189 	ywinsize |= SB_GET();
1190 	clientstat(TELOPT_NAWS, xwinsize, ywinsize);
1191 
1192 	break;
1193 
1194     }  /* end of case TELOPT_NAWS */
1195 
1196 #ifdef	LINEMODE
1197     case TELOPT_LINEMODE: {
1198 	register int request;
1199 
1200 	if (his_state_is_wont(TELOPT_LINEMODE))	/* Ignore if option disabled */
1201 		break;
1202 	/*
1203 	 * Process linemode suboptions.
1204 	 */
1205 	if (SB_EOF())
1206 	    break;		/* garbage was sent */
1207 	request = SB_GET();	/* get will/wont */
1208 
1209 	if (SB_EOF())
1210 	    break;		/* another garbage check */
1211 
1212 	if (request == LM_SLC) {  /* SLC is not preceeded by WILL or WONT */
1213 		/*
1214 		 * Process suboption buffer of slc's
1215 		 */
1216 		start_slc(1);
1217 		do_opt_slc(subpointer, subend - subpointer);
1218 		(void) end_slc(0);
1219 		break;
1220 	} else if (request == LM_MODE) {
1221 		if (SB_EOF())
1222 		    return;
1223 		useeditmode = SB_GET();  /* get mode flag */
1224 		clientstat(LM_MODE, 0, 0);
1225 		break;
1226 	}
1227 
1228 	if (SB_EOF())
1229 	    break;
1230 	switch (SB_GET()) {  /* what suboption? */
1231 	case LM_FORWARDMASK:
1232 		/*
1233 		 * According to spec, only server can send request for
1234 		 * forwardmask, and client can only return a positive response.
1235 		 * So don't worry about it.
1236 		 */
1237 
1238 	default:
1239 		break;
1240 	}
1241 	break;
1242     }  /* end of case TELOPT_LINEMODE */
1243 #endif
1244     case TELOPT_STATUS: {
1245 	int mode;
1246 
1247 	if (SB_EOF())
1248 	    break;
1249 	mode = SB_GET();
1250 	switch (mode) {
1251 	case TELQUAL_SEND:
1252 	    if (my_state_is_will(TELOPT_STATUS))
1253 		send_status();
1254 	    break;
1255 
1256 	case TELQUAL_IS:
1257 	    break;
1258 
1259 	default:
1260 	    break;
1261 	}
1262 	break;
1263     }  /* end of case TELOPT_STATUS */
1264 
1265     case TELOPT_XDISPLOC: {
1266 	if (SB_EOF() || SB_GET() != TELQUAL_IS)
1267 		return;
1268 	sb_auth_complete();
1269 	settimer(xdisplocsubopt);
1270 	subpointer[SB_LEN()] = '\0';
1271 	(void)setenv("DISPLAY", (char *)subpointer, 1);
1272 	break;
1273     }  /* end of case TELOPT_XDISPLOC */
1274 
1275 #ifdef	TELOPT_NEW_ENVIRON
1276     case TELOPT_NEW_ENVIRON:
1277 #endif
1278     case TELOPT_OLD_ENVIRON: {
1279 	register int c;
1280 	register char *cp, *varp, *valp;
1281 
1282 	if (SB_EOF())
1283 		return;
1284 	sb_auth_complete();
1285 	c = SB_GET();
1286 	if (c == TELQUAL_IS) {
1287 		if (subchar == TELOPT_OLD_ENVIRON)
1288 			settimer(oenvironsubopt);
1289 		else
1290 			settimer(environsubopt);
1291 	} else if (c != TELQUAL_INFO) {
1292 		return;
1293 	}
1294 
1295 #ifdef	TELOPT_NEW_ENVIRON
1296 	if (subchar == TELOPT_NEW_ENVIRON) {
1297 	    while (!SB_EOF()) {
1298 		c = SB_GET();
1299 		if ((c == NEW_ENV_VAR) || (c == ENV_USERVAR))
1300 			break;
1301 	    }
1302 	} else
1303 #endif
1304 	{
1305 #ifdef	ENV_HACK
1306 	    /*
1307 	     * We only want to do this if we haven't already decided
1308 	     * whether or not the other side has its VALUE and VAR
1309 	     * reversed.
1310 	     */
1311 	    if (env_ovar < 0) {
1312 		register int last = -1;		/* invalid value */
1313 		int empty = 0;
1314 		int got_var = 0, got_value = 0, got_uservar = 0;
1315 
1316 		/*
1317 		 * The other side might have its VALUE and VAR values
1318 		 * reversed.  To be interoperable, we need to determine
1319 		 * which way it is.  If the first recognized character
1320 		 * is a VAR or VALUE, then that will tell us what
1321 		 * type of client it is.  If the fist recognized
1322 		 * character is a USERVAR, then we continue scanning
1323 		 * the suboption looking for two consecutive
1324 		 * VAR or VALUE fields.  We should not get two
1325 		 * consecutive VALUE fields, so finding two
1326 		 * consecutive VALUE or VAR fields will tell us
1327 		 * what the client is.
1328 		 */
1329 		SB_SAVE();
1330 		while (!SB_EOF()) {
1331 			c = SB_GET();
1332 			switch(c) {
1333 			case OLD_ENV_VAR:
1334 				if (last < 0 || last == OLD_ENV_VAR
1335 				    || (empty && (last == OLD_ENV_VALUE)))
1336 					goto env_ovar_ok;
1337 				got_var++;
1338 				last = OLD_ENV_VAR;
1339 				break;
1340 			case OLD_ENV_VALUE:
1341 				if (last < 0 || last == OLD_ENV_VALUE
1342 				    || (empty && (last == OLD_ENV_VAR)))
1343 					goto env_ovar_wrong;
1344 				got_value++;
1345 				last = OLD_ENV_VALUE;
1346 				break;
1347 			case ENV_USERVAR:
1348 				/* count strings of USERVAR as one */
1349 				if (last != ENV_USERVAR)
1350 					got_uservar++;
1351 				if (empty) {
1352 					if (last == OLD_ENV_VALUE)
1353 						goto env_ovar_ok;
1354 					if (last == OLD_ENV_VAR)
1355 						goto env_ovar_wrong;
1356 				}
1357 				last = ENV_USERVAR;
1358 				break;
1359 			case ENV_ESC:
1360 				if (!SB_EOF())
1361 					c = SB_GET();
1362 				/* FALL THROUGH */
1363 			default:
1364 				empty = 0;
1365 				continue;
1366 			}
1367 			empty = 1;
1368 		}
1369 		if (empty) {
1370 			if (last == OLD_ENV_VALUE)
1371 				goto env_ovar_ok;
1372 			if (last == OLD_ENV_VAR)
1373 				goto env_ovar_wrong;
1374 		}
1375 		/*
1376 		 * Ok, the first thing was a USERVAR, and there
1377 		 * are not two consecutive VAR or VALUE commands,
1378 		 * and none of the VAR or VALUE commands are empty.
1379 		 * If the client has sent us a well-formed option,
1380 		 * then the number of VALUEs received should always
1381 		 * be less than or equal to the number of VARs and
1382 		 * USERVARs received.
1383 		 *
1384 		 * If we got exactly as many VALUEs as VARs and
1385 		 * USERVARs, the client has the same definitions.
1386 		 *
1387 		 * If we got exactly as many VARs as VALUEs and
1388 		 * USERVARS, the client has reversed definitions.
1389 		 */
1390 		if (got_uservar + got_var == got_value) {
1391 	    env_ovar_ok:
1392 			env_ovar = OLD_ENV_VAR;
1393 			env_ovalue = OLD_ENV_VALUE;
1394 		} else if (got_uservar + got_value == got_var) {
1395 	    env_ovar_wrong:
1396 			env_ovar = OLD_ENV_VALUE;
1397 			env_ovalue = OLD_ENV_VAR;
1398 			DIAG(TD_OPTIONS,
1399 			     netputs("ENVIRON VALUE and VAR are reversed!\r\n"));
1400 		}
1401 	    }
1402 	    SB_RESTORE();
1403 #endif
1404 
1405 	    while (!SB_EOF()) {
1406 		c = SB_GET();
1407 		if ((c == env_ovar) || (c == ENV_USERVAR))
1408 			break;
1409 	    }
1410 	}
1411 
1412 	if (SB_EOF())
1413 		return;
1414 
1415 	cp = varp = (char *)subpointer;
1416 	valp = 0;
1417 
1418 	while (!SB_EOF()) {
1419 		c = SB_GET();
1420 		if (subchar == TELOPT_OLD_ENVIRON) {
1421 			if (c == env_ovar)
1422 				c = NEW_ENV_VAR;
1423 			else if (c == env_ovalue)
1424 				c = NEW_ENV_VALUE;
1425 		}
1426 		switch (c) {
1427 
1428 		case NEW_ENV_VALUE:
1429 			*cp = '\0';
1430 			cp = valp = (char *)subpointer;
1431 			break;
1432 
1433 		case NEW_ENV_VAR:
1434 		case ENV_USERVAR:
1435 			*cp = '\0';
1436 			if (envvarok(varp)) {
1437 				if (valp)
1438 					(void)setenv(varp, valp, 1);
1439 				else
1440 					unsetenv(varp);
1441 			}
1442 			cp = varp = (char *)subpointer;
1443 			valp = 0;
1444 			break;
1445 
1446 		case ENV_ESC:
1447 			if (SB_EOF())
1448 				break;
1449 			c = SB_GET();
1450 			/* FALL THROUGH */
1451 		default:
1452 			*cp++ = c;
1453 			break;
1454 		}
1455 	}
1456 	*cp = '\0';
1457 	if (envvarok(varp)) {
1458 		if (valp)
1459 			(void)setenv(varp, valp, 1);
1460 		else
1461 			unsetenv(varp);
1462 	}
1463 	break;
1464     }  /* end of case TELOPT_NEW_ENVIRON */
1465 #if	defined(AUTHENTICATION)
1466     case TELOPT_AUTHENTICATION:
1467 	if (SB_EOF())
1468 		break;
1469 	switch(SB_GET()) {
1470 	case TELQUAL_SEND:
1471 	case TELQUAL_REPLY:
1472 		/*
1473 		 * These are sent by us and cannot be sent by
1474 		 * the client.
1475 		 */
1476 		break;
1477 	case TELQUAL_IS:
1478 		if (!auth_negotiated)
1479 			auth_is(subpointer, SB_LEN());
1480 		break;
1481 	case TELQUAL_NAME:
1482 		if (!auth_negotiated)
1483 			auth_name(subpointer, SB_LEN());
1484 		break;
1485 	}
1486 	break;
1487 #endif
1488 #ifdef	ENCRYPTION
1489     case TELOPT_ENCRYPT:
1490 	if (SB_EOF())
1491 		break;
1492 	switch(SB_GET()) {
1493 	case ENCRYPT_SUPPORT:
1494 		encrypt_support(subpointer, SB_LEN());
1495 		break;
1496 	case ENCRYPT_IS:
1497 		encrypt_is(subpointer, SB_LEN());
1498 		break;
1499 	case ENCRYPT_REPLY:
1500 		encrypt_reply(subpointer, SB_LEN());
1501 		break;
1502 	case ENCRYPT_START:
1503 		encrypt_start(subpointer, SB_LEN());
1504 		break;
1505 	case ENCRYPT_END:
1506 		encrypt_end();
1507 		break;
1508 	case ENCRYPT_REQSTART:
1509 		encrypt_request_start(subpointer, SB_LEN());
1510 		break;
1511 	case ENCRYPT_REQEND:
1512 		/*
1513 		 * We can always send an REQEND so that we cannot
1514 		 * get stuck encrypting.  We should only get this
1515 		 * if we have been able to get in the correct mode
1516 		 * anyhow.
1517 		 */
1518 		encrypt_request_end();
1519 		break;
1520 	case ENCRYPT_ENC_KEYID:
1521 		encrypt_enc_keyid(subpointer, SB_LEN());
1522 		break;
1523 	case ENCRYPT_DEC_KEYID:
1524 		encrypt_dec_keyid(subpointer, SB_LEN());
1525 		break;
1526 	default:
1527 		break;
1528 	}
1529 	break;
1530 #endif	/* ENCRYPTION */
1531 
1532     default:
1533 	break;
1534     }  /* end of switch */
1535 
1536 }  /* end of suboption */
1537 
1538 #ifdef	LINEMODE
1539 static	void
doclientstat()1540 doclientstat()
1541 {
1542 	clientstat(TELOPT_LINEMODE, WILL, 0);
1543 }
1544 #endif
1545 
1546 #define	ADD(c)	 *ncp++ = c;
1547 #define	ADD_DATA(c) { *ncp++ = c; if (c == SE) *ncp++ = c; }
1548 	void
send_status()1549 send_status()
1550 {
1551 	unsigned char statusbuf[256];
1552 	register unsigned char *ncp;
1553 	register unsigned char i;
1554 
1555 	ncp = statusbuf;
1556 
1557 	netflush();	/* get rid of anything waiting to go out */
1558 
1559 	ADD(IAC);
1560 	ADD(SB);
1561 	ADD(TELOPT_STATUS);
1562 	ADD(TELQUAL_IS);
1563 
1564 	/*
1565 	 * We check the want_state rather than the current state,
1566 	 * because if we received a DO/WILL for an option that we
1567 	 * don't support, and the other side didn't send a DONT/WONT
1568 	 * in response to our WONT/DONT, then the "state" will be
1569 	 * WILL/DO, and the "want_state" will be WONT/DONT.  We
1570 	 * need to go by the latter.
1571 	 */
1572 	for (i = 0; i < (unsigned char)NTELOPTS; i++) {
1573 		if (my_want_state_is_will(i)) {
1574 			ADD(WILL);
1575 			ADD_DATA(i);
1576 			if (i == IAC)
1577 				ADD(IAC);
1578 		}
1579 		if (his_want_state_is_will(i)) {
1580 			ADD(DO);
1581 			ADD_DATA(i);
1582 			if (i == IAC)
1583 				ADD(IAC);
1584 		}
1585 	}
1586 
1587 	if (his_want_state_is_will(TELOPT_LFLOW)) {
1588 		ADD(SB);
1589 		ADD(TELOPT_LFLOW);
1590 		if (flowmode) {
1591 			ADD(LFLOW_ON);
1592 		} else {
1593 			ADD(LFLOW_OFF);
1594 		}
1595 		ADD(SE);
1596 
1597 		if (restartany >= 0) {
1598 			ADD(SB)
1599 			ADD(TELOPT_LFLOW);
1600 			if (restartany) {
1601 				ADD(LFLOW_RESTART_ANY);
1602 			} else {
1603 				ADD(LFLOW_RESTART_XON);
1604 			}
1605 			ADD(SE)
1606 			ADD(SB);
1607 		}
1608 	}
1609 
1610 #ifdef	LINEMODE
1611 	if (his_want_state_is_will(TELOPT_LINEMODE)) {
1612 		unsigned char *cp, *cpe;
1613 		int len;
1614 
1615 		ADD(SB);
1616 		ADD(TELOPT_LINEMODE);
1617 		ADD(LM_MODE);
1618 		ADD_DATA(editmode);
1619 		if (editmode == IAC)
1620 			ADD(IAC);
1621 		ADD(SE);
1622 
1623 		ADD(SB);
1624 		ADD(TELOPT_LINEMODE);
1625 		ADD(LM_SLC);
1626 		start_slc(0);
1627 		send_slc();
1628 		len = end_slc(&cp);
1629 		for (cpe = cp + len; cp < cpe; cp++)
1630 			ADD_DATA(*cp);
1631 		ADD(SE);
1632 	}
1633 #endif	/* LINEMODE */
1634 
1635 	ADD(IAC);
1636 	ADD(SE);
1637 
1638 	netwrite(statusbuf, (unsigned) (ncp - statusbuf));
1639 	netflush();	/* Send it on its way */
1640 
1641 	DIAG(TD_OPTIONS,
1642 		{printsub('>', statusbuf, ncp - statusbuf); netflush();});
1643 }
1644 
envvarok(varp)1645 static int envvarok(varp)
1646 	char *varp;
1647 {
1648 	if (!strchr(varp, '=') &&
1649 	    strcmp(varp, "TERMCAP") && /* to prevent a security hole  */
1650 	    strcmp(varp, "TERMINFO") &&	/* with tgetent */
1651 	    strcmp(varp, "TERMPATH") &&
1652 	    strcmp(varp, "HOME") && /* to prevent the tegetent bug  */
1653 	    strncmp(varp, "LD_", strlen("LD_")) && /* most systems */
1654 	    strncmp(varp, "_RLD_", strlen("_RLD_")) && /* irix */
1655 	    strncmp(varp, "KRB5", strlen("KRB5")) && /* v5 */
1656 	    /* The above is a catch-all for now.  Here are some of the
1657 	       specific ones we must avoid passing, at least until we
1658 	       can prove it can be done safely.  Keep this list around
1659 	       in case someone wants to remove the catch-all.  */
1660 	    strcmp(varp, "KRB5_CONFIG") && /* v5 */
1661 	    strcmp(varp, "KRB5CCNAME") &&  /* v5 */
1662 	    strcmp(varp, "KRB5_KTNAME") && /* v5 */
1663 	    strcmp(varp, "KRBTKFILE") &&   /* v4 */
1664 	    strcmp(varp, "KRB_CONF") &&	   /* cns v4 */
1665 	    strcmp(varp, "KRB_REALMS") &&  /* cns v4 */
1666 	    strcmp(varp, "LIBPATH") &&     /* AIX */
1667 	    strcmp(varp, "RESOLV_HOST_CONF") && /* linux */
1668 	    strcmp(varp, "NLSPATH") && /* locale stuff */
1669 	    strncmp(varp, "LC_", strlen("LC_")) && /* locale stuff */
1670 	    strcmp(varp, "IFS") &&
1671 	    (varp[0] != '-')) {
1672 		return 1;
1673 	} else {
1674 		syslog(LOG_INFO, "Rejected the attempt to modify the environment variable \"%s\"", varp);
1675 		return 0;
1676 	}
1677 
1678 }
1679