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