xref: /freebsd/contrib/telnet/telnet/sys_bsd.c (revision a3c85800)
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. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #if 0
31 #ifndef lint
32 static const char sccsid[] = "@(#)sys_bsd.c	8.4 (Berkeley) 5/30/95";
33 #endif
34 #endif
35 
36 /*
37  * The following routines try to encapsulate what is system dependent
38  * (at least between 4.x and dos) which is used in telnet.c.
39  */
40 
41 #include <sys/param.h>
42 #include <sys/socket.h>
43 #include <sys/time.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <signal.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <arpa/telnet.h>
51 
52 #include "ring.h"
53 #include "fdset.h"
54 #include "defines.h"
55 #include "externs.h"
56 #include "types.h"
57 #include "baud.h"
58 
59 int
60 	tout,			/* Output file descriptor */
61 	tin,			/* Input file descriptor */
62 	net;
63 
64 #ifndef	USE_TERMIO
65 struct	tchars otc = { 0 }, ntc = { 0 };
66 struct	ltchars oltc = { 0 }, nltc = { 0 };
67 struct	sgttyb ottyb = { 0 }, nttyb = { 0 };
68 int	olmode = 0;
69 # define cfgetispeed(ptr)	(ptr)->sg_ispeed
70 # define cfgetospeed(ptr)	(ptr)->sg_ospeed
71 # define old_tc ottyb
72 
73 #else	/* USE_TERMIO */
74 struct	termio old_tc = { 0, 0, 0, 0, {}, 0, 0 };
75 
76 # ifndef	TCSANOW
77 #  ifdef TCSETS
78 #   define	TCSANOW		TCSETS
79 #   define	TCSADRAIN	TCSETSW
80 #   define	tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
81 #  else
82 #   ifdef TCSETA
83 #    define	TCSANOW		TCSETA
84 #    define	TCSADRAIN	TCSETAW
85 #    define	tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
86 #   else
87 #    define	TCSANOW		TIOCSETA
88 #    define	TCSADRAIN	TIOCSETAW
89 #    define	tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
90 #   endif
91 #  endif
92 #  define	tcsetattr(f, a, t) ioctl(f, a, (char *)t)
93 #  define	cfgetospeed(ptr)	((ptr)->c_cflag&CBAUD)
94 #  ifdef CIBAUD
95 #   define	cfgetispeed(ptr)	(((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
96 #  else
97 #   define	cfgetispeed(ptr)	cfgetospeed(ptr)
98 #  endif
99 # endif /* TCSANOW */
100 # ifdef	sysV88
101 # define TIOCFLUSH TC_PX_DRAIN
102 # endif
103 #endif	/* USE_TERMIO */
104 
105 static fd_set *ibitsp, *obitsp, *xbitsp;
106 int fdsn;
107 
108 #ifdef	SIGINT
109 static SIG_FUNC_RET intr(int);
110 #endif	/* SIGINT */
111 #ifdef	SIGQUIT
112 static SIG_FUNC_RET intr2(int);
113 #endif	/* SIGQUIT */
114 #ifdef	SIGTSTP
115 static SIG_FUNC_RET susp(int);
116 #endif	/* SIGTSTP */
117 #ifdef	SIGINFO
118 static SIG_FUNC_RET ayt(int);
119 #endif
120 
121 void
init_sys(void)122 init_sys(void)
123 {
124     tout = fileno(stdout);
125     tin = fileno(stdin);
126     errno = 0;
127 }
128 
129 int
TerminalWrite(char * buf,int n)130 TerminalWrite(char *buf, int n)
131 {
132     return write(tout, buf, n);
133 }
134 
135 int
TerminalRead(char * buf,int n)136 TerminalRead(char *buf, int n)
137 {
138     return read(tin, buf, n);
139 }
140 
141 /*
142  *
143  */
144 
145 int
TerminalAutoFlush(void)146 TerminalAutoFlush(void)
147 {
148 #if	defined(LNOFLSH)
149     int flush;
150 
151     ioctl(0, TIOCLGET, (char *)&flush);
152     return !(flush&LNOFLSH);	/* if LNOFLSH, no autoflush */
153 #else	/* LNOFLSH */
154     return 1;
155 #endif	/* LNOFLSH */
156 }
157 
158 #ifdef	KLUDGELINEMODE
159 extern int kludgelinemode;
160 #endif
161 /*
162  * TerminalSpecialChars()
163  *
164  * Look at an input character to see if it is a special character
165  * and decide what to do.
166  *
167  * Output:
168  *
169  *	0	Don't add this character.
170  *	1	Do add this character
171  */
172 
173 int
TerminalSpecialChars(int c)174 TerminalSpecialChars(int c)
175 {
176     if (c == termIntChar) {
177 	intp();
178 	return 0;
179     } else if (c == termQuitChar) {
180 #ifdef	KLUDGELINEMODE
181 	if (kludgelinemode)
182 	    sendbrk();
183 	else
184 #endif
185 	    sendabort();
186 	return 0;
187     } else if (c == termEofChar) {
188 	if (my_want_state_is_will(TELOPT_LINEMODE)) {
189 	    sendeof();
190 	    return 0;
191 	}
192 	return 1;
193     } else if (c == termSuspChar) {
194 	sendsusp();
195 	return(0);
196     } else if (c == termFlushChar) {
197 	xmitAO();		/* Transmit Abort Output */
198 	return 0;
199     } else if (!MODE_LOCAL_CHARS(globalmode)) {
200 	if (c == termKillChar) {
201 	    xmitEL();
202 	    return 0;
203 	} else if (c == termEraseChar) {
204 	    xmitEC();		/* Transmit Erase Character */
205 	    return 0;
206 	}
207     }
208     return 1;
209 }
210 
211 
212 /*
213  * Flush output to the terminal
214  */
215 
216 void
TerminalFlushOutput(void)217 TerminalFlushOutput(void)
218 {
219 #ifdef	TIOCFLUSH
220     (void) ioctl(fileno(stdout), TIOCFLUSH, (char *) 0);
221 #else
222     (void) ioctl(fileno(stdout), TCFLSH, (char *) 0);
223 #endif
224 }
225 
226 void
TerminalSaveState(void)227 TerminalSaveState(void)
228 {
229 #ifndef	USE_TERMIO
230     ioctl(0, TIOCGETP, (char *)&ottyb);
231     ioctl(0, TIOCGETC, (char *)&otc);
232     ioctl(0, TIOCGLTC, (char *)&oltc);
233     ioctl(0, TIOCLGET, (char *)&olmode);
234 
235     ntc = otc;
236     nltc = oltc;
237     nttyb = ottyb;
238 
239 #else	/* USE_TERMIO */
240     tcgetattr(0, &old_tc);
241 
242     new_tc = old_tc;
243 
244 #ifndef	VDISCARD
245     termFlushChar = CONTROL('O');
246 #endif
247 #ifndef	VWERASE
248     termWerasChar = CONTROL('W');
249 #endif
250 #ifndef	VREPRINT
251     termRprntChar = CONTROL('R');
252 #endif
253 #ifndef	VLNEXT
254     termLiteralNextChar = CONTROL('V');
255 #endif
256 #ifndef	VSTART
257     termStartChar = CONTROL('Q');
258 #endif
259 #ifndef	VSTOP
260     termStopChar = CONTROL('S');
261 #endif
262 #ifndef	VSTATUS
263     termAytChar = CONTROL('T');
264 #endif
265 #endif	/* USE_TERMIO */
266 }
267 
268 cc_t *
tcval(int func)269 tcval(int func)
270 {
271     switch(func) {
272     case SLC_IP:	return(&termIntChar);
273     case SLC_ABORT:	return(&termQuitChar);
274     case SLC_EOF:	return(&termEofChar);
275     case SLC_EC:	return(&termEraseChar);
276     case SLC_EL:	return(&termKillChar);
277     case SLC_XON:	return(&termStartChar);
278     case SLC_XOFF:	return(&termStopChar);
279     case SLC_FORW1:	return(&termForw1Char);
280 #ifdef	USE_TERMIO
281     case SLC_FORW2:	return(&termForw2Char);
282 # ifdef	VDISCARD
283     case SLC_AO:	return(&termFlushChar);
284 # endif
285 # ifdef	VSUSP
286     case SLC_SUSP:	return(&termSuspChar);
287 # endif
288 # ifdef	VWERASE
289     case SLC_EW:	return(&termWerasChar);
290 # endif
291 # ifdef	VREPRINT
292     case SLC_RP:	return(&termRprntChar);
293 # endif
294 # ifdef	VLNEXT
295     case SLC_LNEXT:	return(&termLiteralNextChar);
296 # endif
297 # ifdef	VSTATUS
298     case SLC_AYT:	return(&termAytChar);
299 # endif
300 #endif
301 
302     case SLC_SYNCH:
303     case SLC_BRK:
304     case SLC_EOR:
305     default:
306 	return((cc_t *)0);
307     }
308 }
309 
310 void
TerminalDefaultChars(void)311 TerminalDefaultChars(void)
312 {
313 #ifndef	USE_TERMIO
314     ntc = otc;
315     nltc = oltc;
316     nttyb.sg_kill = ottyb.sg_kill;
317     nttyb.sg_erase = ottyb.sg_erase;
318 #else	/* USE_TERMIO */
319     memcpy(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
320 # ifndef	VDISCARD
321     termFlushChar = CONTROL('O');
322 # endif
323 # ifndef	VWERASE
324     termWerasChar = CONTROL('W');
325 # endif
326 # ifndef	VREPRINT
327     termRprntChar = CONTROL('R');
328 # endif
329 # ifndef	VLNEXT
330     termLiteralNextChar = CONTROL('V');
331 # endif
332 # ifndef	VSTART
333     termStartChar = CONTROL('Q');
334 # endif
335 # ifndef	VSTOP
336     termStopChar = CONTROL('S');
337 # endif
338 # ifndef	VSTATUS
339     termAytChar = CONTROL('T');
340 # endif
341 #endif	/* USE_TERMIO */
342 }
343 
344 /*
345  * TerminalNewMode - set up terminal to a specific mode.
346  *	MODE_ECHO: do local terminal echo
347  *	MODE_FLOW: do local flow control
348  *	MODE_TRAPSIG: do local mapping to TELNET IAC sequences
349  *	MODE_EDIT: do local line editing
350  *
351  *	Command mode:
352  *		MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
353  *		local echo
354  *		local editing
355  *		local xon/xoff
356  *		local signal mapping
357  *
358  *	Linemode:
359  *		local/no editing
360  *	Both Linemode and Single Character mode:
361  *		local/remote echo
362  *		local/no xon/xoff
363  *		local/no signal mapping
364  */
365 
366 void
TerminalNewMode(int f)367 TerminalNewMode(int f)
368 {
369     static int prevmode = 0;
370 #ifndef	USE_TERMIO
371     struct tchars tc;
372     struct ltchars ltc;
373     struct sgttyb sb;
374     int lmode;
375 #else	/* USE_TERMIO */
376     struct termio tmp_tc;
377 #endif	/* USE_TERMIO */
378     int onoff;
379     int old;
380     cc_t esc;
381 
382     globalmode = f&~MODE_FORCE;
383     if (prevmode == f)
384 	return;
385 
386     /*
387      * Write any outstanding data before switching modes
388      * ttyflush() returns 0 only when there is no more data
389      * left to write out, it returns -1 if it couldn't do
390      * anything at all, otherwise it returns 1 + the number
391      * of characters left to write.
392 #ifndef	USE_TERMIO
393      * We would really like ask the kernel to wait for the output
394      * to drain, like we can do with the TCSADRAIN, but we don't have
395      * that option.  The only ioctl that waits for the output to
396      * drain, TIOCSETP, also flushes the input queue, which is NOT
397      * what we want (TIOCSETP is like TCSADFLUSH).
398 #endif
399      */
400     old = ttyflush(SYNCHing|flushout);
401     if (old < 0 || old > 1) {
402 #ifdef	USE_TERMIO
403 	tcgetattr(tin, &tmp_tc);
404 #endif	/* USE_TERMIO */
405 	do {
406 	    /*
407 	     * Wait for data to drain, then flush again.
408 	     */
409 #ifdef	USE_TERMIO
410 	    tcsetattr(tin, TCSADRAIN, &tmp_tc);
411 #endif	/* USE_TERMIO */
412 	    old = ttyflush(SYNCHing|flushout);
413 	} while (old < 0 || old > 1);
414     }
415 
416     old = prevmode;
417     prevmode = f&~MODE_FORCE;
418 #ifndef	USE_TERMIO
419     sb = nttyb;
420     tc = ntc;
421     ltc = nltc;
422     lmode = olmode;
423 #else
424     tmp_tc = new_tc;
425 #endif
426 
427     if (f&MODE_ECHO) {
428 #ifndef	USE_TERMIO
429 	sb.sg_flags |= ECHO;
430 #else
431 	tmp_tc.c_lflag |= ECHO;
432 	tmp_tc.c_oflag |= ONLCR;
433 	if (crlf)
434 		tmp_tc.c_iflag |= ICRNL;
435 #endif
436     } else {
437 #ifndef	USE_TERMIO
438 	sb.sg_flags &= ~ECHO;
439 #else
440 	tmp_tc.c_lflag &= ~ECHO;
441 	tmp_tc.c_oflag &= ~ONLCR;
442 #endif
443     }
444 
445     if ((f&MODE_FLOW) == 0) {
446 #ifndef	USE_TERMIO
447 	tc.t_startc = _POSIX_VDISABLE;
448 	tc.t_stopc = _POSIX_VDISABLE;
449 #else
450 	tmp_tc.c_iflag &= ~(IXOFF|IXON);	/* Leave the IXANY bit alone */
451     } else {
452 	if (restartany < 0) {
453 		tmp_tc.c_iflag |= IXOFF|IXON;	/* Leave the IXANY bit alone */
454 	} else if (restartany > 0) {
455 		tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
456 	} else {
457 		tmp_tc.c_iflag |= IXOFF|IXON;
458 		tmp_tc.c_iflag &= ~IXANY;
459 	}
460 #endif
461     }
462 
463     if ((f&MODE_TRAPSIG) == 0) {
464 #ifndef	USE_TERMIO
465 	tc.t_intrc = _POSIX_VDISABLE;
466 	tc.t_quitc = _POSIX_VDISABLE;
467 	tc.t_eofc = _POSIX_VDISABLE;
468 	ltc.t_suspc = _POSIX_VDISABLE;
469 	ltc.t_dsuspc = _POSIX_VDISABLE;
470 #else
471 	tmp_tc.c_lflag &= ~ISIG;
472 #endif
473 	localchars = 0;
474     } else {
475 #ifdef	USE_TERMIO
476 	tmp_tc.c_lflag |= ISIG;
477 #endif
478 	localchars = 1;
479     }
480 
481     if (f&MODE_EDIT) {
482 #ifndef	USE_TERMIO
483 	sb.sg_flags &= ~CBREAK;
484 	sb.sg_flags |= CRMOD;
485 #else
486 	tmp_tc.c_lflag |= ICANON;
487 #endif
488     } else {
489 #ifndef	USE_TERMIO
490 	sb.sg_flags |= CBREAK;
491 	if (f&MODE_ECHO)
492 	    sb.sg_flags |= CRMOD;
493 	else
494 	    sb.sg_flags &= ~CRMOD;
495 #else
496 	tmp_tc.c_lflag &= ~ICANON;
497 	tmp_tc.c_iflag &= ~ICRNL;
498 	tmp_tc.c_cc[VMIN] = 1;
499 	tmp_tc.c_cc[VTIME] = 0;
500 #endif
501     }
502 
503     if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
504 #ifndef	USE_TERMIO
505 	ltc.t_lnextc = _POSIX_VDISABLE;
506 #else
507 # ifdef VLNEXT
508 	tmp_tc.c_cc[VLNEXT] = (cc_t)(_POSIX_VDISABLE);
509 # endif
510 #endif
511     }
512 
513     if (f&MODE_SOFT_TAB) {
514 #ifndef USE_TERMIO
515 	sb.sg_flags |= XTABS;
516 #else
517 # ifdef	OXTABS
518 	tmp_tc.c_oflag |= OXTABS;
519 # endif
520 # ifdef	TABDLY
521 	tmp_tc.c_oflag &= ~TABDLY;
522 	tmp_tc.c_oflag |= TAB3;
523 # endif
524 #endif
525     } else {
526 #ifndef USE_TERMIO
527 	sb.sg_flags &= ~XTABS;
528 #else
529 # ifdef	OXTABS
530 	tmp_tc.c_oflag &= ~OXTABS;
531 # endif
532 # ifdef	TABDLY
533 	tmp_tc.c_oflag &= ~TABDLY;
534 # endif
535 #endif
536     }
537 
538     if (f&MODE_LIT_ECHO) {
539 #ifndef USE_TERMIO
540 	lmode &= ~LCTLECH;
541 #else
542 # ifdef	ECHOCTL
543 	tmp_tc.c_lflag &= ~ECHOCTL;
544 # endif
545 #endif
546     } else {
547 #ifndef USE_TERMIO
548 	lmode |= LCTLECH;
549 #else
550 # ifdef	ECHOCTL
551 	tmp_tc.c_lflag |= ECHOCTL;
552 # endif
553 #endif
554     }
555 
556     if (f == -1) {
557 	onoff = 0;
558     } else {
559 #ifndef	USE_TERMIO
560 	if (f & MODE_OUTBIN)
561 		lmode |= LLITOUT;
562 	else
563 		lmode &= ~LLITOUT;
564 
565 	if (f & MODE_INBIN)
566 		lmode |= LPASS8;
567 	else
568 		lmode &= ~LPASS8;
569 #else
570 	if (f & MODE_INBIN)
571 		tmp_tc.c_iflag &= ~ISTRIP;
572 	else
573 		tmp_tc.c_iflag |= ISTRIP;
574 	if (f & MODE_OUTBIN) {
575 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
576 		tmp_tc.c_cflag |= CS8;
577 		tmp_tc.c_oflag &= ~OPOST;
578 	} else {
579 		tmp_tc.c_cflag &= ~(CSIZE|PARENB);
580 		tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
581 		tmp_tc.c_oflag |= OPOST;
582 	}
583 #endif
584 	onoff = 1;
585     }
586 
587     if (f != -1) {
588 #ifdef  SIGINT
589 	(void) signal(SIGINT, intr);
590 #endif
591 #ifdef  SIGQUIT
592 	(void) signal(SIGQUIT, intr2);
593 #endif
594 #ifdef	SIGTSTP
595 	(void) signal(SIGTSTP, susp);
596 #endif	/* SIGTSTP */
597 #ifdef	SIGINFO
598 	(void) signal(SIGINFO, ayt);
599 #endif
600 #if	defined(USE_TERMIO) && defined(NOKERNINFO)
601 	tmp_tc.c_lflag |= NOKERNINFO;
602 #endif
603 	/*
604 	 * We don't want to process ^Y here.  It's just another
605 	 * character that we'll pass on to the back end.  It has
606 	 * to process it because it will be processed when the
607 	 * user attempts to read it, not when we send it.
608 	 */
609 #ifndef	USE_TERMIO
610 	ltc.t_dsuspc = _POSIX_VDISABLE;
611 #else
612 # ifdef	VDSUSP
613 	tmp_tc.c_cc[VDSUSP] = (cc_t)(_POSIX_VDISABLE);
614 # endif
615 #endif
616 #ifdef	USE_TERMIO
617 	/*
618 	 * If the VEOL character is already set, then use VEOL2,
619 	 * otherwise use VEOL.
620 	 */
621 	esc = (rlogin != _POSIX_VDISABLE) ? rlogin : escape;
622 	if ((tmp_tc.c_cc[VEOL] != esc)
623 # ifdef	VEOL2
624 	    && (tmp_tc.c_cc[VEOL2] != esc)
625 # endif
626 	    ) {
627 		if (tmp_tc.c_cc[VEOL] == (cc_t)(_POSIX_VDISABLE))
628 		    tmp_tc.c_cc[VEOL] = esc;
629 # ifdef	VEOL2
630 		else if (tmp_tc.c_cc[VEOL2] == (cc_t)(_POSIX_VDISABLE))
631 		    tmp_tc.c_cc[VEOL2] = esc;
632 # endif
633 	}
634 #else
635 	if (tc.t_brkc == (cc_t)(_POSIX_VDISABLE))
636 		tc.t_brkc = esc;
637 #endif
638     } else {
639 #ifdef	SIGINFO
640 	(void) signal(SIGINFO, (void (*)(int))ayt_status);
641 #endif
642 #ifdef  SIGINT
643 	(void) signal(SIGINT, SIG_DFL);
644 #endif
645 #ifdef  SIGQUIT
646 	(void) signal(SIGQUIT, SIG_DFL);
647 #endif
648 #ifdef	SIGTSTP
649 	(void) signal(SIGTSTP, SIG_DFL);
650 # ifndef SOLARIS
651 	(void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
652 # else	/* SOLARIS */
653 	(void) sigrelse(SIGTSTP);
654 # endif	/* SOLARIS */
655 #endif	/* SIGTSTP */
656 #ifndef USE_TERMIO
657 	ltc = oltc;
658 	tc = otc;
659 	sb = ottyb;
660 	lmode = olmode;
661 #else
662 	tmp_tc = old_tc;
663 #endif
664     }
665 #ifndef USE_TERMIO
666     ioctl(tin, TIOCLSET, (char *)&lmode);
667     ioctl(tin, TIOCSLTC, (char *)&ltc);
668     ioctl(tin, TIOCSETC, (char *)&tc);
669     ioctl(tin, TIOCSETN, (char *)&sb);
670 #else
671     if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
672 	tcsetattr(tin, TCSANOW, &tmp_tc);
673 #endif
674 
675     ioctl(tin, FIONBIO, (char *)&onoff);
676     ioctl(tout, FIONBIO, (char *)&onoff);
677 
678 }
679 
680 void
TerminalSpeeds(long * ispeed,long * ospeed)681 TerminalSpeeds(long *ispeed, long *ospeed)
682 {
683 #ifdef	DECODE_BAUD
684     struct termspeeds *tp;
685 #endif	/* DECODE_BAUD */
686     long in, out;
687 
688     out = cfgetospeed(&old_tc);
689     in = cfgetispeed(&old_tc);
690     if (in == 0)
691 	in = out;
692 
693 #ifdef	DECODE_BAUD
694     tp = termspeeds;
695     while ((tp->speed != -1) && (tp->value < in))
696 	tp++;
697     *ispeed = tp->speed;
698 
699     tp = termspeeds;
700     while ((tp->speed != -1) && (tp->value < out))
701 	tp++;
702     *ospeed = tp->speed;
703 #else	/* DECODE_BAUD */
704 	*ispeed = in;
705 	*ospeed = out;
706 #endif	/* DECODE_BAUD */
707 }
708 
709 int
TerminalWindowSize(long * rows,long * cols)710 TerminalWindowSize(long *rows, long *cols)
711 {
712 #ifdef	TIOCGWINSZ
713     struct winsize ws;
714 
715     if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
716 	*rows = ws.ws_row;
717 	*cols = ws.ws_col;
718 	return 1;
719     }
720 #endif	/* TIOCGWINSZ */
721     return 0;
722 }
723 
724 int
NetClose(int fd)725 NetClose(int fd)
726 {
727     return close(fd);
728 }
729 
730 static void
NetNonblockingIO(int fd,int onoff)731 NetNonblockingIO(int fd, int onoff)
732 {
733     ioctl(fd, FIONBIO, (char *)&onoff);
734 }
735 
736 
737 /*
738  * Various signal handling routines.
739  */
740 
741 /* ARGSUSED */
742 SIG_FUNC_RET
intr(int sig __unused)743 intr(int sig __unused)
744 {
745     if (localchars) {
746 	intp();
747 	return;
748     }
749     setcommandmode();
750     longjmp(toplevel, -1);
751 }
752 
753 /* ARGSUSED */
754 SIG_FUNC_RET
intr2(int sig __unused)755 intr2(int sig __unused)
756 {
757     if (localchars) {
758 #ifdef	KLUDGELINEMODE
759 	if (kludgelinemode)
760 	    sendbrk();
761 	else
762 #endif
763 	    sendabort();
764 	return;
765     }
766 }
767 
768 #ifdef	SIGTSTP
769 /* ARGSUSED */
770 SIG_FUNC_RET
susp(int sig __unused)771 susp(int sig __unused)
772 {
773     if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
774 	return;
775     if (localchars)
776 	sendsusp();
777 }
778 #endif
779 
780 #ifdef	SIGWINCH
781 /* ARGSUSED */
782 static SIG_FUNC_RET
sendwin(int sig __unused)783 sendwin(int sig __unused)
784 {
785     if (connected) {
786 	sendnaws();
787     }
788 }
789 #endif
790 
791 #ifdef	SIGINFO
792 /* ARGSUSED */
793 SIG_FUNC_RET
ayt(int sig __unused)794 ayt(int sig __unused)
795 {
796     if (connected)
797 	sendayt();
798     else
799 	ayt_status();
800 }
801 #endif
802 
803 
804 void
sys_telnet_init(void)805 sys_telnet_init(void)
806 {
807     (void) signal(SIGINT, intr);
808     (void) signal(SIGQUIT, intr2);
809     (void) signal(SIGPIPE, SIG_IGN);
810 #ifdef	SIGWINCH
811     (void) signal(SIGWINCH, sendwin);
812 #endif
813 #ifdef	SIGTSTP
814     (void) signal(SIGTSTP, susp);
815 #endif
816 #ifdef	SIGINFO
817     (void) signal(SIGINFO, ayt);
818 #endif
819 
820     setconnmode(0);
821 
822     NetNonblockingIO(net, 1);
823 
824 #if	defined(SO_OOBINLINE)
825     if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
826 	perror("SetSockOpt");
827     }
828 #endif	/* defined(SO_OOBINLINE) */
829 }
830 
831 /*
832  * Process rings -
833  *
834  *	This routine tries to fill up/empty our various rings.
835  *
836  *	The parameter specifies whether this is a poll operation,
837  *	or a block-until-something-happens operation.
838  *
839  *	The return value is 1 if something happened, 0 if not.
840  */
841 
842 int
process_rings(int netin,int netout,int netex,int ttyin,int ttyout,int poll)843 process_rings(int netin, int netout, int netex, int ttyin, int ttyout, int poll)
844 {
845     int c;
846     int returnValue = 0;
847     static struct timeval TimeValue = { 0, 0 };
848     int maxfd = -1;
849     int tmp;
850 
851     if ((netout || netin || netex) && net > maxfd)
852 	maxfd = net;
853 
854     if (ttyout && tout > maxfd)
855 	maxfd = tout;
856     if (ttyin && tin > maxfd)
857 	maxfd = tin;
858     tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
859     if (tmp > fdsn) {
860 	if (ibitsp)
861 	    free(ibitsp);
862 	if (obitsp)
863 	    free(obitsp);
864 	if (xbitsp)
865 	    free(xbitsp);
866 
867 	fdsn = tmp;
868 	if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL)
869 	    err(1, "malloc");
870 	if ((obitsp = (fd_set *)malloc(fdsn)) == NULL)
871 	    err(1, "malloc");
872 	if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL)
873 	    err(1, "malloc");
874 	memset(ibitsp, 0, fdsn);
875 	memset(obitsp, 0, fdsn);
876 	memset(xbitsp, 0, fdsn);
877     }
878 
879     if (netout)
880 	FD_SET(net, obitsp);
881     if (ttyout)
882 	FD_SET(tout, obitsp);
883     if (ttyin)
884 	FD_SET(tin, ibitsp);
885     if (netin)
886 	FD_SET(net, ibitsp);
887     if (netex)
888 	FD_SET(net, xbitsp);
889     if ((c = select(maxfd + 1, ibitsp, obitsp, xbitsp,
890 	     (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
891 	if (c == -1) {
892 		    /*
893 		     * we can get EINTR if we are in line mode,
894 		     * and the user does an escape (TSTP), or
895 		     * some other signal generator.
896 		     */
897 	    if (errno == EINTR) {
898 		return 0;
899 	    }
900 		    /* I don't like this, does it ever happen? */
901 	    printf("sleep(5) from telnet, after select: %s\r\n", strerror(errno));
902 	    sleep(5);
903 	}
904 	return 0;
905     }
906 
907     /*
908      * Any urgent data?
909      */
910     if (FD_ISSET(net, xbitsp)) {
911 	FD_CLR(net, xbitsp);
912 	SYNCHing = 1;
913 	(void) ttyflush(1);	/* flush already enqueued data */
914     }
915 
916     /*
917      * Something to read from the network...
918      */
919     if (FD_ISSET(net, ibitsp)) {
920 	int canread;
921 
922 	FD_CLR(net, ibitsp);
923 	canread = ring_empty_consecutive(&netiring);
924 #if	!defined(SO_OOBINLINE)
925 	    /*
926 	     * In 4.2 (and some early 4.3) systems, the
927 	     * OOB indication and data handling in the kernel
928 	     * is such that if two separate TCP Urgent requests
929 	     * come in, one byte of TCP data will be overlaid.
930 	     * This is fatal for Telnet, but we try to live
931 	     * with it.
932 	     *
933 	     * In addition, in 4.2 (and...), a special protocol
934 	     * is needed to pick up the TCP Urgent data in
935 	     * the correct sequence.
936 	     *
937 	     * What we do is:  if we think we are in urgent
938 	     * mode, we look to see if we are "at the mark".
939 	     * If we are, we do an OOB receive.  If we run
940 	     * this twice, we will do the OOB receive twice,
941 	     * but the second will fail, since the second
942 	     * time we were "at the mark", but there wasn't
943 	     * any data there (the kernel doesn't reset
944 	     * "at the mark" until we do a normal read).
945 	     * Once we've read the OOB data, we go ahead
946 	     * and do normal reads.
947 	     *
948 	     * There is also another problem, which is that
949 	     * since the OOB byte we read doesn't put us
950 	     * out of OOB state, and since that byte is most
951 	     * likely the TELNET DM (data mark), we would
952 	     * stay in the TELNET SYNCH (SYNCHing) state.
953 	     * So, clocks to the rescue.  If we've "just"
954 	     * received a DM, then we test for the
955 	     * presence of OOB data when the receive OOB
956 	     * fails (and AFTER we did the normal mode read
957 	     * to clear "at the mark").
958 	     */
959 	if (SYNCHing) {
960 	    int atmark;
961 	    static int bogus_oob = 0, first = 1;
962 
963 	    ioctl(net, SIOCATMARK, (char *)&atmark);
964 	    if (atmark) {
965 		c = recv(net, netiring.supply, canread, MSG_OOB);
966 		if ((c == -1) && (errno == EINVAL)) {
967 		    c = recv(net, netiring.supply, canread, 0);
968 		    if (clocks.didnetreceive < clocks.gotDM) {
969 			SYNCHing = stilloob(net);
970 		    }
971 		} else if (first && c > 0) {
972 		    /*
973 		     * Bogosity check.  Systems based on 4.2BSD
974 		     * do not return an error if you do a second
975 		     * recv(MSG_OOB).  So, we do one.  If it
976 		     * succeeds and returns exactly the same
977 		     * data, then assume that we are running
978 		     * on a broken system and set the bogus_oob
979 		     * flag.  (If the data was different, then
980 		     * we probably got some valid new data, so
981 		     * increment the count...)
982 		     */
983 		    int i;
984 		    i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
985 		    if (i == c &&
986 			memcmp(netiring.supply, netiring.supply + c, i) == 0) {
987 			bogus_oob = 1;
988 			first = 0;
989 		    } else if (i < 0) {
990 			bogus_oob = 0;
991 			first = 0;
992 		    } else
993 			c += i;
994 		}
995 		if (bogus_oob && c > 0) {
996 		    int i;
997 		    /*
998 		     * Bogosity.  We have to do the read
999 		     * to clear the atmark to get out of
1000 		     * an infinate loop.
1001 		     */
1002 		    i = read(net, netiring.supply + c, canread - c);
1003 		    if (i > 0)
1004 			c += i;
1005 		}
1006 	    } else {
1007 		c = recv(net, netiring.supply, canread, 0);
1008 	    }
1009 	} else {
1010 	    c = recv(net, netiring.supply, canread, 0);
1011 	}
1012 	settimer(didnetreceive);
1013 #else	/* !defined(SO_OOBINLINE) */
1014 	c = recv(net, (char *)netiring.supply, canread, 0);
1015 #endif	/* !defined(SO_OOBINLINE) */
1016 	if (c < 0 && errno == EWOULDBLOCK) {
1017 	    c = 0;
1018 	} else if (c <= 0) {
1019 	    return -1;
1020 	}
1021 	if (netdata) {
1022 	    Dump('<', netiring.supply, c);
1023 	}
1024 	if (c)
1025 	    ring_supplied(&netiring, c);
1026 	returnValue = 1;
1027     }
1028 
1029     /*
1030      * Something to read from the tty...
1031      */
1032     if (FD_ISSET(tin, ibitsp)) {
1033 	FD_CLR(tin, ibitsp);
1034 	c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
1035 	if (c < 0 && errno == EIO)
1036 	    c = 0;
1037 	if (c < 0 && errno == EWOULDBLOCK) {
1038 	    c = 0;
1039 	} else {
1040 	    /* EOF detection for line mode!!!! */
1041 	    if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
1042 			/* must be an EOF... */
1043 		*ttyiring.supply = termEofChar;
1044 		c = 1;
1045 	    }
1046 	    if (c <= 0) {
1047 		return -1;
1048 	    }
1049 	    if (termdata) {
1050 		Dump('<', ttyiring.supply, c);
1051 	    }
1052 	    ring_supplied(&ttyiring, c);
1053 	}
1054 	returnValue = 1;		/* did something useful */
1055     }
1056 
1057     if (FD_ISSET(net, obitsp)) {
1058 	FD_CLR(net, obitsp);
1059 	returnValue |= netflush();
1060     }
1061     if (FD_ISSET(tout, obitsp)) {
1062 	FD_CLR(tout, obitsp);
1063 	returnValue |= (ttyflush(SYNCHing|flushout) > 0);
1064     }
1065 
1066     return returnValue;
1067 }
1068