Annotation of src/usr.bin/telnet/sys_bsd.c, Revision 1.8
1.8 ! millert 1: /* $OpenBSD: sys_bsd.c,v 1.7 1999/05/07 18:29:07 deraadt Exp $ */
1.3 niklas 2: /* $NetBSD: sys_bsd.c,v 1.11 1996/02/28 21:04:10 thorpej Exp $ */
3:
1.1 deraadt 4: /*
5: * Copyright (c) 1988, 1990, 1993
6: * The Regents of the University of California. All rights reserved.
7: *
8: * Redistribution and use in source and binary forms, with or without
9: * modification, are permitted provided that the following conditions
10: * are met:
11: * 1. Redistributions of source code must retain the above copyright
12: * notice, this list of conditions and the following disclaimer.
13: * 2. Redistributions in binary form must reproduce the above copyright
14: * notice, this list of conditions and the following disclaimer in the
15: * documentation and/or other materials provided with the distribution.
16: * 3. All advertising materials mentioning features or use of this software
17: * must display the following acknowledgement:
18: * This product includes software developed by the University of
19: * California, Berkeley and its contributors.
20: * 4. Neither the name of the University nor the names of its contributors
21: * may be used to endorse or promote products derived from this software
22: * without specific prior written permission.
23: *
24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34: * SUCH DAMAGE.
35: */
36:
1.5 art 37: #include "telnet_locl.h"
1.8 ! millert 38: #include <err.h>
1.1 deraadt 39:
40: /*
41: * The following routines try to encapsulate what is system dependent
42: * (at least between 4.x and dos) which is used in telnet.c.
43: */
44:
45: int
46: tout, /* Output file descriptor */
47: tin, /* Input file descriptor */
48: net;
49:
50: #ifndef USE_TERMIO
51: struct tchars otc = { 0 }, ntc = { 0 };
52: struct ltchars oltc = { 0 }, nltc = { 0 };
53: struct sgttyb ottyb = { 0 }, nttyb = { 0 };
54: int olmode = 0;
55: # define cfgetispeed(ptr) (ptr)->sg_ispeed
56: # define cfgetospeed(ptr) (ptr)->sg_ospeed
57: # define old_tc ottyb
58:
59: #else /* USE_TERMIO */
1.5 art 60: struct termios old_tc = { 0 };
61: extern struct termios new_tc;
1.1 deraadt 62:
63: # ifndef TCSANOW
64: # ifdef TCSETS
65: # define TCSANOW TCSETS
66: # define TCSADRAIN TCSETSW
67: # define tcgetattr(f, t) ioctl(f, TCGETS, (char *)t)
68: # else
69: # ifdef TCSETA
70: # define TCSANOW TCSETA
71: # define TCSADRAIN TCSETAW
72: # define tcgetattr(f, t) ioctl(f, TCGETA, (char *)t)
73: # else
74: # define TCSANOW TIOCSETA
75: # define TCSADRAIN TIOCSETAW
76: # define tcgetattr(f, t) ioctl(f, TIOCGETA, (char *)t)
77: # endif
78: # endif
79: # define tcsetattr(f, a, t) ioctl(f, a, (char *)t)
80: # define cfgetospeed(ptr) ((ptr)->c_cflag&CBAUD)
81: # ifdef CIBAUD
82: # define cfgetispeed(ptr) (((ptr)->c_cflag&CIBAUD) >> IBSHIFT)
83: # else
84: # define cfgetispeed(ptr) cfgetospeed(ptr)
85: # endif
86: # endif /* TCSANOW */
87: # ifdef sysV88
88: # define TIOCFLUSH TC_PX_DRAIN
89: # endif
90: #endif /* USE_TERMIO */
91:
1.6 deraadt 92: fd_set *ibitsp, *obitsp, *xbitsp;
93: int fdsn;
1.1 deraadt 94:
95: void
96: init_sys()
97: {
98: tout = fileno(stdout);
99: tin = fileno(stdin);
100:
101: errno = 0;
102: }
103:
104:
105: int
106: TerminalWrite(buf, n)
107: char *buf;
108: int n;
109: {
110: return write(tout, buf, n);
111: }
112:
113: int
114: TerminalRead(buf, n)
1.3 niklas 115: unsigned char *buf;
1.1 deraadt 116: int n;
117: {
118: return read(tin, buf, n);
119: }
120:
121: /*
122: *
123: */
124:
125: int
126: TerminalAutoFlush()
127: {
128: #if defined(LNOFLSH)
129: int flush;
130:
131: ioctl(0, TIOCLGET, (char *)&flush);
132: return !(flush&LNOFLSH); /* if LNOFLSH, no autoflush */
133: #else /* LNOFLSH */
134: return 1;
135: #endif /* LNOFLSH */
136: }
137:
138: #ifdef KLUDGELINEMODE
139: extern int kludgelinemode;
140: #endif
141: /*
142: * TerminalSpecialChars()
143: *
144: * Look at an input character to see if it is a special character
145: * and decide what to do.
146: *
147: * Output:
148: *
149: * 0 Don't add this character.
150: * 1 Do add this character
151: */
152:
153: extern void xmitAO(), xmitEL(), xmitEC(), intp(), sendbrk();
154:
155: int
156: TerminalSpecialChars(c)
157: int c;
158: {
159: if (c == termIntChar) {
160: intp();
161: return 0;
162: } else if (c == termQuitChar) {
163: #ifdef KLUDGELINEMODE
164: if (kludgelinemode)
165: sendbrk();
166: else
167: #endif
168: sendabort();
169: return 0;
170: } else if (c == termEofChar) {
171: if (my_want_state_is_will(TELOPT_LINEMODE)) {
172: sendeof();
173: return 0;
174: }
175: return 1;
176: } else if (c == termSuspChar) {
177: sendsusp();
178: return(0);
179: } else if (c == termFlushChar) {
180: xmitAO(); /* Transmit Abort Output */
181: return 0;
182: } else if (!MODE_LOCAL_CHARS(globalmode)) {
183: if (c == termKillChar) {
184: xmitEL();
185: return 0;
186: } else if (c == termEraseChar) {
187: xmitEC(); /* Transmit Erase Character */
188: return 0;
189: }
190: }
191: return 1;
192: }
193:
194:
195: /*
196: * Flush output to the terminal
197: */
1.3 niklas 198:
1.1 deraadt 199: void
200: TerminalFlushOutput()
201: {
202: #ifdef TIOCFLUSH
1.7 deraadt 203: int com = FWRITE;
204: (void) ioctl(fileno(stdout), TIOCFLUSH, (int *) &com);
1.1 deraadt 205: #else
1.7 deraadt 206: (void) ioctl(fileno(stdout), TCFLSH, (int *) 0);
1.1 deraadt 207: #endif
208: }
209:
210: void
211: TerminalSaveState()
212: {
213: #ifndef USE_TERMIO
214: ioctl(0, TIOCGETP, (char *)&ottyb);
215: ioctl(0, TIOCGETC, (char *)&otc);
216: ioctl(0, TIOCGLTC, (char *)&oltc);
217: ioctl(0, TIOCLGET, (char *)&olmode);
218:
219: ntc = otc;
220: nltc = oltc;
221: nttyb = ottyb;
222:
223: #else /* USE_TERMIO */
224: tcgetattr(0, &old_tc);
225:
226: new_tc = old_tc;
227:
228: #ifndef VDISCARD
229: termFlushChar = CONTROL('O');
230: #endif
231: #ifndef VWERASE
232: termWerasChar = CONTROL('W');
233: #endif
234: #ifndef VREPRINT
235: termRprntChar = CONTROL('R');
236: #endif
237: #ifndef VLNEXT
238: termLiteralNextChar = CONTROL('V');
239: #endif
240: #ifndef VSTART
241: termStartChar = CONTROL('Q');
242: #endif
243: #ifndef VSTOP
244: termStopChar = CONTROL('S');
245: #endif
246: #ifndef VSTATUS
247: termAytChar = CONTROL('T');
248: #endif
249: #endif /* USE_TERMIO */
250: }
251:
252: cc_t *
253: tcval(func)
254: register int func;
255: {
256: switch(func) {
257: case SLC_IP: return(&termIntChar);
258: case SLC_ABORT: return(&termQuitChar);
259: case SLC_EOF: return(&termEofChar);
260: case SLC_EC: return(&termEraseChar);
261: case SLC_EL: return(&termKillChar);
262: case SLC_XON: return(&termStartChar);
263: case SLC_XOFF: return(&termStopChar);
264: case SLC_FORW1: return(&termForw1Char);
265: #ifdef USE_TERMIO
266: case SLC_FORW2: return(&termForw2Char);
267: # ifdef VDISCARD
268: case SLC_AO: return(&termFlushChar);
269: # endif
270: # ifdef VSUSP
271: case SLC_SUSP: return(&termSuspChar);
272: # endif
273: # ifdef VWERASE
274: case SLC_EW: return(&termWerasChar);
275: # endif
276: # ifdef VREPRINT
277: case SLC_RP: return(&termRprntChar);
278: # endif
279: # ifdef VLNEXT
280: case SLC_LNEXT: return(&termLiteralNextChar);
281: # endif
282: # ifdef VSTATUS
283: case SLC_AYT: return(&termAytChar);
284: # endif
285: #endif
286:
287: case SLC_SYNCH:
288: case SLC_BRK:
289: case SLC_EOR:
290: default:
291: return((cc_t *)0);
292: }
293: }
294:
295: void
296: TerminalDefaultChars()
297: {
298: #ifndef USE_TERMIO
299: ntc = otc;
300: nltc = oltc;
301: nttyb.sg_kill = ottyb.sg_kill;
302: nttyb.sg_erase = ottyb.sg_erase;
303: #else /* USE_TERMIO */
1.3 niklas 304: memmove(new_tc.c_cc, old_tc.c_cc, sizeof(old_tc.c_cc));
1.1 deraadt 305: # ifndef VDISCARD
306: termFlushChar = CONTROL('O');
307: # endif
308: # ifndef VWERASE
309: termWerasChar = CONTROL('W');
310: # endif
311: # ifndef VREPRINT
312: termRprntChar = CONTROL('R');
313: # endif
314: # ifndef VLNEXT
315: termLiteralNextChar = CONTROL('V');
316: # endif
317: # ifndef VSTART
318: termStartChar = CONTROL('Q');
319: # endif
320: # ifndef VSTOP
321: termStopChar = CONTROL('S');
322: # endif
323: # ifndef VSTATUS
324: termAytChar = CONTROL('T');
325: # endif
326: #endif /* USE_TERMIO */
327: }
328:
329: #ifdef notdef
330: void
331: TerminalRestoreState()
332: {
333: }
334: #endif
335:
336: /*
337: * TerminalNewMode - set up terminal to a specific mode.
338: * MODE_ECHO: do local terminal echo
339: * MODE_FLOW: do local flow control
340: * MODE_TRAPSIG: do local mapping to TELNET IAC sequences
341: * MODE_EDIT: do local line editing
342: *
343: * Command mode:
344: * MODE_ECHO|MODE_EDIT|MODE_FLOW|MODE_TRAPSIG
345: * local echo
346: * local editing
347: * local xon/xoff
348: * local signal mapping
349: *
350: * Linemode:
351: * local/no editing
352: * Both Linemode and Single Character mode:
353: * local/remote echo
354: * local/no xon/xoff
355: * local/no signal mapping
356: */
357:
1.5 art 358: #ifdef SIGTSTP
359: static void susp();
360: #endif /* SIGTSTP */
361: #ifdef SIGINFO
362: static void ayt();
363: #endif
1.1 deraadt 364:
365: void
366: TerminalNewMode(f)
367: register 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 */
1.5 art 376: struct termios tmp_tc;
1.1 deraadt 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: # ifdef notdef
443: if (crlf)
444: tmp_tc.c_iflag &= ~ICRNL;
445: # endif
446: #endif
447: }
448:
449: if ((f&MODE_FLOW) == 0) {
450: #ifndef USE_TERMIO
451: tc.t_startc = _POSIX_VDISABLE;
452: tc.t_stopc = _POSIX_VDISABLE;
453: #else
454: tmp_tc.c_iflag &= ~(IXOFF|IXON); /* Leave the IXANY bit alone */
455: } else {
456: if (restartany < 0) {
457: tmp_tc.c_iflag |= IXOFF|IXON; /* Leave the IXANY bit alone */
458: } else if (restartany > 0) {
459: tmp_tc.c_iflag |= IXOFF|IXON|IXANY;
460: } else {
461: tmp_tc.c_iflag |= IXOFF|IXON;
462: tmp_tc.c_iflag &= ~IXANY;
463: }
464: #endif
465: }
466:
467: if ((f&MODE_TRAPSIG) == 0) {
468: #ifndef USE_TERMIO
469: tc.t_intrc = _POSIX_VDISABLE;
470: tc.t_quitc = _POSIX_VDISABLE;
471: tc.t_eofc = _POSIX_VDISABLE;
472: ltc.t_suspc = _POSIX_VDISABLE;
473: ltc.t_dsuspc = _POSIX_VDISABLE;
474: #else
475: tmp_tc.c_lflag &= ~ISIG;
476: #endif
477: localchars = 0;
478: } else {
479: #ifdef USE_TERMIO
480: tmp_tc.c_lflag |= ISIG;
481: #endif
482: localchars = 1;
483: }
484:
485: if (f&MODE_EDIT) {
486: #ifndef USE_TERMIO
487: sb.sg_flags &= ~CBREAK;
488: sb.sg_flags |= CRMOD;
489: #else
490: tmp_tc.c_lflag |= ICANON;
491: #endif
492: } else {
493: #ifndef USE_TERMIO
494: sb.sg_flags |= CBREAK;
495: if (f&MODE_ECHO)
496: sb.sg_flags |= CRMOD;
497: else
498: sb.sg_flags &= ~CRMOD;
499: #else
500: tmp_tc.c_lflag &= ~ICANON;
501: tmp_tc.c_iflag &= ~ICRNL;
502: tmp_tc.c_cc[VMIN] = 1;
503: tmp_tc.c_cc[VTIME] = 0;
504: #endif
505: }
506:
507: if ((f&(MODE_EDIT|MODE_TRAPSIG)) == 0) {
508: #ifndef USE_TERMIO
509: ltc.t_lnextc = _POSIX_VDISABLE;
510: #else
1.2 niklas 511: tmp_tc.c_lflag &= ~IEXTEN;
1.1 deraadt 512: #endif
513: }
514:
515: if (f&MODE_SOFT_TAB) {
516: #ifndef USE_TERMIO
517: sb.sg_flags |= XTABS;
518: #else
519: # ifdef OXTABS
520: tmp_tc.c_oflag |= OXTABS;
521: # endif
522: # ifdef TABDLY
523: tmp_tc.c_oflag &= ~TABDLY;
524: tmp_tc.c_oflag |= TAB3;
525: # endif
526: #endif
527: } else {
528: #ifndef USE_TERMIO
529: sb.sg_flags &= ~XTABS;
530: #else
531: # ifdef OXTABS
532: tmp_tc.c_oflag &= ~OXTABS;
533: # endif
534: # ifdef TABDLY
535: tmp_tc.c_oflag &= ~TABDLY;
536: # endif
537: #endif
538: }
539:
540: if (f&MODE_LIT_ECHO) {
541: #ifndef USE_TERMIO
542: lmode &= ~LCTLECH;
543: #else
544: # ifdef ECHOCTL
545: tmp_tc.c_lflag &= ~ECHOCTL;
546: # endif
547: #endif
548: } else {
549: #ifndef USE_TERMIO
550: lmode |= LCTLECH;
551: #else
552: # ifdef ECHOCTL
553: tmp_tc.c_lflag |= ECHOCTL;
554: # endif
555: #endif
556: }
557:
558: if (f == -1) {
559: onoff = 0;
560: } else {
561: #ifndef USE_TERMIO
562: if (f & MODE_OUTBIN)
563: lmode |= LLITOUT;
564: else
565: lmode &= ~LLITOUT;
566:
567: if (f & MODE_INBIN)
568: lmode |= LPASS8;
569: else
570: lmode &= ~LPASS8;
571: #else
572: if (f & MODE_INBIN)
573: tmp_tc.c_iflag &= ~ISTRIP;
574: else
575: tmp_tc.c_iflag |= ISTRIP;
1.5 art 576: if ((f & MODE_OUTBIN) || (f & MODE_OUT8)) {
1.1 deraadt 577: tmp_tc.c_cflag &= ~(CSIZE|PARENB);
578: tmp_tc.c_cflag |= CS8;
1.5 art 579: if(f & MODE_OUTBIN)
580: tmp_tc.c_oflag &= ~OPOST;
581: else
582: tmp_tc.c_oflag |= OPOST;
583:
1.1 deraadt 584: } else {
585: tmp_tc.c_cflag &= ~(CSIZE|PARENB);
586: tmp_tc.c_cflag |= old_tc.c_cflag & (CSIZE|PARENB);
587: tmp_tc.c_oflag |= OPOST;
588: }
589: #endif
590: onoff = 1;
591: }
592:
593: if (f != -1) {
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
1.5 art 640: void ayt_status();
1.1 deraadt 641:
1.5 art 642: (void) signal(SIGINFO, (void (*)(int))ayt_status);
1.1 deraadt 643: #endif
644: #ifdef SIGTSTP
645: (void) signal(SIGTSTP, SIG_DFL);
1.3 niklas 646: # ifndef SOLARIS
1.1 deraadt 647: (void) sigsetmask(sigblock(0) & ~(1<<(SIGTSTP-1)));
1.3 niklas 648: # else SOLARIS
649: (void) sigrelse(SIGTSTP);
650: # endif SOLARIS
1.1 deraadt 651: #endif /* SIGTSTP */
652: #ifndef USE_TERMIO
653: ltc = oltc;
654: tc = otc;
655: sb = ottyb;
656: lmode = olmode;
657: #else
658: tmp_tc = old_tc;
659: #endif
660: }
661: #ifndef USE_TERMIO
662: ioctl(tin, TIOCLSET, (char *)&lmode);
663: ioctl(tin, TIOCSLTC, (char *)<c);
664: ioctl(tin, TIOCSETC, (char *)&tc);
665: ioctl(tin, TIOCSETN, (char *)&sb);
666: #else
667: if (tcsetattr(tin, TCSADRAIN, &tmp_tc) < 0)
668: tcsetattr(tin, TCSANOW, &tmp_tc);
669: #endif
670:
671: #if (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR))
672: # if !defined(sysV88)
673: ioctl(tin, FIONBIO, (char *)&onoff);
674: ioctl(tout, FIONBIO, (char *)&onoff);
675: # endif
676: #endif /* (!defined(TN3270)) || ((!defined(NOT43)) || defined(PUTCHAR)) */
677: #if defined(TN3270)
678: if (noasynchtty == 0) {
679: ioctl(tin, FIOASYNC, (char *)&onoff);
680: }
681: #endif /* defined(TN3270) */
682:
683: }
684:
1.3 niklas 685: /*
686: * Try to guess whether speeds are "encoded" (4.2BSD) or just numeric (4.4BSD).
687: */
688: #if B4800 != 4800
689: #define DECODE_BAUD
690: #endif
691:
692: #ifdef DECODE_BAUD
693: #ifndef B7200
694: #define B7200 B4800
695: #endif
696:
697: #ifndef B14400
698: #define B14400 B9600
699: #endif
700:
1.1 deraadt 701: #ifndef B19200
1.3 niklas 702: # define B19200 B14400
703: #endif
704:
705: #ifndef B28800
706: #define B28800 B19200
1.1 deraadt 707: #endif
708:
709: #ifndef B38400
1.3 niklas 710: # define B38400 B28800
711: #endif
712:
713: #ifndef B57600
714: #define B57600 B38400
1.1 deraadt 715: #endif
716:
1.3 niklas 717: #ifndef B76800
718: #define B76800 B57600
719: #endif
720:
721: #ifndef B115200
722: #define B115200 B76800
723: #endif
724:
725: #ifndef B230400
726: #define B230400 B115200
727: #endif
728:
729:
1.1 deraadt 730: /*
731: * This code assumes that the values B0, B50, B75...
732: * are in ascending order. They do not have to be
733: * contiguous.
734: */
735: struct termspeeds {
736: long speed;
737: long value;
738: } termspeeds[] = {
1.3 niklas 739: { 0, B0 }, { 50, B50 }, { 75, B75 },
740: { 110, B110 }, { 134, B134 }, { 150, B150 },
741: { 200, B200 }, { 300, B300 }, { 600, B600 },
742: { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 },
743: { 4800, B4800 }, { 7200, B7200 }, { 9600, B9600 },
744: { 14400, B14400 }, { 19200, B19200 }, { 28800, B28800 },
745: { 38400, B38400 }, { 57600, B57600 }, { 115200, B115200 },
746: { 230400, B230400 }, { -1, B230400 }
1.1 deraadt 747: };
1.3 niklas 748: #endif /* DECODE_BAUD */
1.1 deraadt 749:
750: void
751: TerminalSpeeds(ispeed, ospeed)
752: long *ispeed;
753: long *ospeed;
754: {
1.3 niklas 755: #ifdef DECODE_BAUD
1.1 deraadt 756: register struct termspeeds *tp;
1.3 niklas 757: #endif /* DECODE_BAUD */
1.1 deraadt 758: register long in, out;
759:
760: out = cfgetospeed(&old_tc);
761: in = cfgetispeed(&old_tc);
762: if (in == 0)
763: in = out;
764:
1.3 niklas 765: #ifdef DECODE_BAUD
1.1 deraadt 766: tp = termspeeds;
767: while ((tp->speed != -1) && (tp->value < in))
768: tp++;
769: *ispeed = tp->speed;
770:
771: tp = termspeeds;
772: while ((tp->speed != -1) && (tp->value < out))
773: tp++;
774: *ospeed = tp->speed;
1.3 niklas 775: #else /* DECODE_BAUD */
776: *ispeed = in;
777: *ospeed = out;
778: #endif /* DECODE_BAUD */
1.1 deraadt 779: }
780:
781: int
782: TerminalWindowSize(rows, cols)
783: long *rows, *cols;
784: {
785: #ifdef TIOCGWINSZ
786: struct winsize ws;
787:
788: if (ioctl(fileno(stdin), TIOCGWINSZ, (char *)&ws) >= 0) {
789: *rows = ws.ws_row;
790: *cols = ws.ws_col;
791: return 1;
792: }
793: #endif /* TIOCGWINSZ */
794: return 0;
795: }
796:
797: int
798: NetClose(fd)
799: int fd;
800: {
801: return close(fd);
802: }
803:
804:
805: void
806: NetNonblockingIO(fd, onoff)
807: int fd;
808: int onoff;
809: {
810: ioctl(fd, FIONBIO, (char *)&onoff);
811: }
812:
813: #if defined(TN3270)
814: void
815: NetSigIO(fd, onoff)
816: int fd;
817: int onoff;
818: {
819: ioctl(fd, FIOASYNC, (char *)&onoff); /* hear about input */
820: }
821:
822: void
823: NetSetPgrp(fd)
824: int fd;
825: {
826: int myPid;
827:
828: myPid = getpid();
829: fcntl(fd, F_SETOWN, myPid);
830: }
831: #endif /*defined(TN3270)*/
832:
833: /*
834: * Various signal handling routines.
835: */
836:
837: /* ARGSUSED */
1.5 art 838: void
1.1 deraadt 839: deadpeer(sig)
840: int sig;
841: {
842: setcommandmode();
843: longjmp(peerdied, -1);
844: }
845:
846: /* ARGSUSED */
1.5 art 847: void
1.1 deraadt 848: intr(sig)
849: int sig;
850: {
851: if (localchars) {
852: intp();
853: return;
854: }
855: setcommandmode();
856: longjmp(toplevel, -1);
857: }
858:
859: /* ARGSUSED */
1.5 art 860: void
1.1 deraadt 861: intr2(sig)
862: int sig;
863: {
864: if (localchars) {
865: #ifdef KLUDGELINEMODE
866: if (kludgelinemode)
867: sendbrk();
868: else
869: #endif
870: sendabort();
871: return;
872: }
873: }
874:
875: #ifdef SIGTSTP
876: /* ARGSUSED */
1.5 art 877: void
1.1 deraadt 878: susp(sig)
879: int sig;
880: {
881: if ((rlogin != _POSIX_VDISABLE) && rlogin_susp())
882: return;
883: if (localchars)
884: sendsusp();
885: }
886: #endif
887:
888: #ifdef SIGWINCH
889: /* ARGSUSED */
1.5 art 890: void
1.1 deraadt 891: sendwin(sig)
892: int sig;
893: {
894: if (connected) {
895: sendnaws();
896: }
897: }
898: #endif
899:
900: #ifdef SIGINFO
901: /* ARGSUSED */
1.5 art 902: void
1.1 deraadt 903: ayt(sig)
904: int sig;
905: {
906: if (connected)
907: sendayt();
908: else
909: ayt_status();
910: }
911: #endif
912:
913:
914: void
915: sys_telnet_init()
916: {
917: (void) signal(SIGINT, intr);
918: (void) signal(SIGQUIT, intr2);
919: (void) signal(SIGPIPE, deadpeer);
920: #ifdef SIGWINCH
921: (void) signal(SIGWINCH, sendwin);
922: #endif
923: #ifdef SIGTSTP
924: (void) signal(SIGTSTP, susp);
925: #endif
926: #ifdef SIGINFO
927: (void) signal(SIGINFO, ayt);
928: #endif
929:
930: setconnmode(0);
931:
932: NetNonblockingIO(net, 1);
933:
934: #if defined(TN3270)
935: if (noasynchnet == 0) { /* DBX can't handle! */
936: NetSigIO(net, 1);
937: NetSetPgrp(net);
938: }
939: #endif /* defined(TN3270) */
940:
941: #if defined(SO_OOBINLINE)
942: if (SetSockOpt(net, SOL_SOCKET, SO_OOBINLINE, 1) == -1) {
943: perror("SetSockOpt");
944: }
945: #endif /* defined(SO_OOBINLINE) */
946: }
947:
948: /*
949: * Process rings -
950: *
951: * This routine tries to fill up/empty our various rings.
952: *
953: * The parameter specifies whether this is a poll operation,
954: * or a block-until-something-happens operation.
955: *
956: * The return value is 1 if something happened, 0 if not.
957: */
958:
959: int
960: process_rings(netin, netout, netex, ttyin, ttyout, poll)
961: int poll; /* If 0, then block until something to do */
962: {
963: register int c;
964: /* One wants to be a bit careful about setting returnValue
965: * to one, since a one implies we did some useful work,
966: * and therefore probably won't be called to block next
967: * time (TN3270 mode only).
968: */
969: int returnValue = 0;
970: static struct timeval TimeValue = { 0 };
1.6 deraadt 971: int maxfd = -1;
972: int tmp;
973:
974: if ((netout || netin || netex) && net > maxfd)
975: maxfd = net;
976: if (ttyout && tout > maxfd)
977: maxfd = tout;
978: if (ttyin && tin > maxfd)
979: maxfd = tin;
980: tmp = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);
981: if (tmp > fdsn) {
982: if (ibitsp)
983: free(ibitsp);
984: if (obitsp)
985: free(obitsp);
986: if (xbitsp)
987: free(xbitsp);
988: fdsn = tmp;
989: if ((ibitsp = (fd_set *)malloc(fdsn)) == NULL)
990: err(1, "malloc");
991: if ((obitsp = (fd_set *)malloc(fdsn)) == NULL)
992: err(1, "malloc");
993: if ((xbitsp = (fd_set *)malloc(fdsn)) == NULL)
994: err(1, "malloc");
995: memset(ibitsp, 0, fdsn);
996: memset(obitsp, 0, fdsn);
997: memset(xbitsp, 0, fdsn);
998: }
999:
1000: if (netout)
1001: FD_SET(net, obitsp);
1002: if (ttyout)
1003: FD_SET(tout, obitsp);
1004: if (ttyin)
1005: FD_SET(tin, ibitsp);
1006: if (netin)
1007: FD_SET(net, ibitsp);
1008: if (netex)
1009: FD_SET(net, xbitsp);
1.1 deraadt 1010:
1.6 deraadt 1011: if ((c = select(maxfd+1, ibitsp, obitsp, xbitsp,
1012: (poll == 0)? (struct timeval *)0 : &TimeValue)) < 0) {
1.1 deraadt 1013: if (c == -1) {
1014: /*
1015: * we can get EINTR if we are in line mode,
1016: * and the user does an escape (TSTP), or
1017: * some other signal generator.
1018: */
1019: if (errno == EINTR) {
1020: return 0;
1021: }
1022: # if defined(TN3270)
1023: /*
1024: * we can get EBADF if we were in transparent
1025: * mode, and the transcom process died.
1026: */
1027: if (errno == EBADF) {
1028: /*
1029: * zero the bits (even though kernel does it)
1030: * to make sure we are selecting on the right
1031: * ones.
1032: */
1.6 deraadt 1033: memset(ibitsp, 0, fdsn);
1034: memset(obitsp, 0, fdsn);
1035: memset(xbitsp, 0, fdsn);
1.1 deraadt 1036: return 0;
1037: }
1038: # endif /* defined(TN3270) */
1039: /* I don't like this, does it ever happen? */
1040: printf("sleep(5) from telnet, after select\r\n");
1041: sleep(5);
1042: }
1043: return 0;
1044: }
1045:
1046: /*
1047: * Any urgent data?
1048: */
1.6 deraadt 1049: if (FD_ISSET(net, xbitsp)) {
1050: FD_CLR(net, xbitsp);
1.1 deraadt 1051: SYNCHing = 1;
1052: (void) ttyflush(1); /* flush already enqueued data */
1053: }
1054:
1055: /*
1056: * Something to read from the network...
1057: */
1.6 deraadt 1058: if (FD_ISSET(net, ibitsp)) {
1.1 deraadt 1059: int canread;
1060:
1.6 deraadt 1061: FD_CLR(net, ibitsp);
1.1 deraadt 1062: canread = ring_empty_consecutive(&netiring);
1063: #if !defined(SO_OOBINLINE)
1064: /*
1065: * In 4.2 (and some early 4.3) systems, the
1066: * OOB indication and data handling in the kernel
1067: * is such that if two separate TCP Urgent requests
1068: * come in, one byte of TCP data will be overlaid.
1069: * This is fatal for Telnet, but we try to live
1070: * with it.
1071: *
1072: * In addition, in 4.2 (and...), a special protocol
1073: * is needed to pick up the TCP Urgent data in
1074: * the correct sequence.
1075: *
1076: * What we do is: if we think we are in urgent
1077: * mode, we look to see if we are "at the mark".
1078: * If we are, we do an OOB receive. If we run
1079: * this twice, we will do the OOB receive twice,
1080: * but the second will fail, since the second
1081: * time we were "at the mark", but there wasn't
1082: * any data there (the kernel doesn't reset
1083: * "at the mark" until we do a normal read).
1084: * Once we've read the OOB data, we go ahead
1085: * and do normal reads.
1086: *
1087: * There is also another problem, which is that
1088: * since the OOB byte we read doesn't put us
1089: * out of OOB state, and since that byte is most
1090: * likely the TELNET DM (data mark), we would
1091: * stay in the TELNET SYNCH (SYNCHing) state.
1092: * So, clocks to the rescue. If we've "just"
1093: * received a DM, then we test for the
1094: * presence of OOB data when the receive OOB
1095: * fails (and AFTER we did the normal mode read
1096: * to clear "at the mark").
1097: */
1098: if (SYNCHing) {
1099: int atmark;
1100: static int bogus_oob = 0, first = 1;
1101:
1102: ioctl(net, SIOCATMARK, (char *)&atmark);
1103: if (atmark) {
1104: c = recv(net, netiring.supply, canread, MSG_OOB);
1105: if ((c == -1) && (errno == EINVAL)) {
1106: c = recv(net, netiring.supply, canread, 0);
1107: if (clocks.didnetreceive < clocks.gotDM) {
1108: SYNCHing = stilloob(net);
1109: }
1110: } else if (first && c > 0) {
1111: /*
1112: * Bogosity check. Systems based on 4.2BSD
1113: * do not return an error if you do a second
1114: * recv(MSG_OOB). So, we do one. If it
1115: * succeeds and returns exactly the same
1116: * data, then assume that we are running
1117: * on a broken system and set the bogus_oob
1118: * flag. (If the data was different, then
1119: * we probably got some valid new data, so
1120: * increment the count...)
1121: */
1122: int i;
1123: i = recv(net, netiring.supply + c, canread - c, MSG_OOB);
1124: if (i == c &&
1.3 niklas 1125: memcmp(netiring.supply, netiring.supply + c, i) == 0) {
1.1 deraadt 1126: bogus_oob = 1;
1127: first = 0;
1128: } else if (i < 0) {
1129: bogus_oob = 0;
1130: first = 0;
1131: } else
1132: c += i;
1133: }
1134: if (bogus_oob && c > 0) {
1135: int i;
1136: /*
1137: * Bogosity. We have to do the read
1138: * to clear the atmark to get out of
1139: * an infinate loop.
1140: */
1141: i = read(net, netiring.supply + c, canread - c);
1142: if (i > 0)
1143: c += i;
1144: }
1145: } else {
1146: c = recv(net, netiring.supply, canread, 0);
1147: }
1148: } else {
1149: c = recv(net, netiring.supply, canread, 0);
1150: }
1151: settimer(didnetreceive);
1152: #else /* !defined(SO_OOBINLINE) */
1153: c = recv(net, (char *)netiring.supply, canread, 0);
1154: #endif /* !defined(SO_OOBINLINE) */
1155: if (c < 0 && errno == EWOULDBLOCK) {
1156: c = 0;
1157: } else if (c <= 0) {
1158: return -1;
1159: }
1160: if (netdata) {
1161: Dump('<', netiring.supply, c);
1162: }
1163: if (c)
1164: ring_supplied(&netiring, c);
1165: returnValue = 1;
1166: }
1167:
1168: /*
1169: * Something to read from the tty...
1170: */
1.6 deraadt 1171: if (FD_ISSET(tin, ibitsp)) {
1172: FD_CLR(tin, ibitsp);
1.1 deraadt 1173: c = TerminalRead(ttyiring.supply, ring_empty_consecutive(&ttyiring));
1.3 niklas 1174: if (c < 0 && errno == EIO)
1175: c = 0;
1.1 deraadt 1176: if (c < 0 && errno == EWOULDBLOCK) {
1177: c = 0;
1178: } else {
1.5 art 1179: /* EOF detection for line mode!!!! */
1180: if ((c == 0) && MODE_LOCAL_CHARS(globalmode) && isatty(tin)) {
1181: /* must be an EOF... */
1182: *ttyiring.supply = termEofChar;
1183: c = 1;
1184: }
1185: if (c <= 0) {
1.1 deraadt 1186: return -1;
1187: }
1188: if (termdata) {
1189: Dump('<', ttyiring.supply, c);
1190: }
1191: ring_supplied(&ttyiring, c);
1192: }
1193: returnValue = 1; /* did something useful */
1194: }
1195:
1.6 deraadt 1196: if (FD_ISSET(net, obitsp)) {
1197: FD_CLR(net, obitsp);
1.1 deraadt 1198: returnValue |= netflush();
1199: }
1.6 deraadt 1200: if (FD_ISSET(tout, obitsp)) {
1201: FD_CLR(tout, obitsp);
1.1 deraadt 1202: returnValue |= (ttyflush(SYNCHing|flushout) > 0);
1203: }
1204:
1205: return returnValue;
1206: }