Annotation of src/usr.bin/ssh/ttymodes.c, Revision 1.14.2.2
1.1 deraadt 1: /*
1.4 deraadt 2: * Author: Tatu Ylonen <ylo@cs.hut.fi>
3: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4: * All rights reserved
1.8 deraadt 5: *
6: * As far as I am concerned, the code I have written for this software
7: * can be used freely for any purpose. Any derived versions of this
8: * software must be clearly marked as such, and if the derived work is
9: * incompatible with the protocol description in the RFC file, it must be
10: * called by a name other than "ssh" or "Secure Shell".
1.4 deraadt 11: */
1.1 deraadt 12:
1.12 stevesk 13: /*
14: * SSH2 tty modes support by Kevin Steves.
15: * Copyright (c) 2001 Kevin Steves. All rights reserved.
16: *
17: * Redistribution and use in source and binary forms, with or without
18: * modification, are permitted provided that the following conditions
19: * are met:
20: * 1. Redistributions of source code must retain the above copyright
21: * notice, this list of conditions and the following disclaimer.
22: * 2. Redistributions in binary form must reproduce the above copyright
23: * notice, this list of conditions and the following disclaimer in the
24: * documentation and/or other materials provided with the distribution.
25: *
26: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
27: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
28: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
30: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36: */
37:
38: /*
39: * Encoding and decoding of terminal modes in a portable way.
40: * Much of the format is defined in ttymodes.h; it is included multiple times
41: * into this file with the appropriate macro definitions to generate the
42: * suitable code.
43: */
44:
1.1 deraadt 45: #include "includes.h"
1.14.2.2! miod 46: RCSID("$OpenBSD: ttymodes.c,v 1.17 2002/03/19 10:49:35 markus Exp $");
1.1 deraadt 47:
48: #include "packet.h"
1.10 markus 49: #include "log.h"
1.9 markus 50: #include "ssh1.h"
1.12 stevesk 51: #include "compat.h"
52: #include "buffer.h"
53: #include "bufaux.h"
1.1 deraadt 54:
1.12 stevesk 55: #define TTY_OP_END 0
56: /*
57: * uint32 (u_int) follows speed in SSH1 and SSH2
58: */
59: #define TTY_OP_ISPEED_PROTO1 192
60: #define TTY_OP_OSPEED_PROTO1 193
61: #define TTY_OP_ISPEED_PROTO2 128
62: #define TTY_OP_OSPEED_PROTO2 129
1.1 deraadt 63:
1.4 deraadt 64: /*
65: * Converts POSIX speed_t to a baud rate. The values of the
66: * constants for speed_t are not themselves portable.
67: */
1.6 markus 68: static int
1.3 markus 69: speed_to_baud(speed_t speed)
1.1 deraadt 70: {
1.3 markus 71: switch (speed) {
72: case B0:
73: return 0;
74: case B50:
75: return 50;
76: case B75:
77: return 75;
78: case B110:
79: return 110;
80: case B134:
81: return 134;
82: case B150:
83: return 150;
84: case B200:
85: return 200;
86: case B300:
87: return 300;
88: case B600:
89: return 600;
90: case B1200:
91: return 1200;
92: case B1800:
93: return 1800;
94: case B2400:
95: return 2400;
96: case B4800:
97: return 4800;
98: case B9600:
99: return 9600;
1.1 deraadt 100:
101: #ifdef B19200
1.3 markus 102: case B19200:
103: return 19200;
1.1 deraadt 104: #else /* B19200 */
105: #ifdef EXTA
1.3 markus 106: case EXTA:
107: return 19200;
1.1 deraadt 108: #endif /* EXTA */
109: #endif /* B19200 */
110:
111: #ifdef B38400
1.3 markus 112: case B38400:
113: return 38400;
1.1 deraadt 114: #else /* B38400 */
115: #ifdef EXTB
1.3 markus 116: case EXTB:
117: return 38400;
1.1 deraadt 118: #endif /* EXTB */
119: #endif /* B38400 */
120:
121: #ifdef B7200
1.3 markus 122: case B7200:
123: return 7200;
1.1 deraadt 124: #endif /* B7200 */
125: #ifdef B14400
1.3 markus 126: case B14400:
127: return 14400;
1.1 deraadt 128: #endif /* B14400 */
129: #ifdef B28800
1.3 markus 130: case B28800:
131: return 28800;
1.1 deraadt 132: #endif /* B28800 */
133: #ifdef B57600
1.3 markus 134: case B57600:
135: return 57600;
1.1 deraadt 136: #endif /* B57600 */
137: #ifdef B76800
1.3 markus 138: case B76800:
139: return 76800;
1.1 deraadt 140: #endif /* B76800 */
141: #ifdef B115200
1.3 markus 142: case B115200:
143: return 115200;
1.1 deraadt 144: #endif /* B115200 */
145: #ifdef B230400
1.3 markus 146: case B230400:
147: return 230400;
1.1 deraadt 148: #endif /* B230400 */
1.3 markus 149: default:
150: return 9600;
151: }
1.1 deraadt 152: }
153:
1.4 deraadt 154: /*
155: * Converts a numeric baud rate to a POSIX speed_t.
156: */
1.6 markus 157: static speed_t
1.3 markus 158: baud_to_speed(int baud)
1.1 deraadt 159: {
1.3 markus 160: switch (baud) {
1.12 stevesk 161: case 0:
1.3 markus 162: return B0;
163: case 50:
164: return B50;
165: case 75:
166: return B75;
167: case 110:
168: return B110;
169: case 134:
170: return B134;
171: case 150:
172: return B150;
173: case 200:
174: return B200;
175: case 300:
176: return B300;
177: case 600:
178: return B600;
179: case 1200:
180: return B1200;
181: case 1800:
182: return B1800;
183: case 2400:
184: return B2400;
185: case 4800:
186: return B4800;
187: case 9600:
188: return B9600;
1.1 deraadt 189:
190: #ifdef B19200
1.3 markus 191: case 19200:
192: return B19200;
1.1 deraadt 193: #else /* B19200 */
194: #ifdef EXTA
1.3 markus 195: case 19200:
196: return EXTA;
1.1 deraadt 197: #endif /* EXTA */
198: #endif /* B19200 */
199:
200: #ifdef B38400
1.3 markus 201: case 38400:
202: return B38400;
1.1 deraadt 203: #else /* B38400 */
204: #ifdef EXTB
1.3 markus 205: case 38400:
206: return EXTB;
1.1 deraadt 207: #endif /* EXTB */
208: #endif /* B38400 */
209:
210: #ifdef B7200
1.3 markus 211: case 7200:
212: return B7200;
1.1 deraadt 213: #endif /* B7200 */
214: #ifdef B14400
1.3 markus 215: case 14400:
216: return B14400;
1.1 deraadt 217: #endif /* B14400 */
218: #ifdef B28800
1.3 markus 219: case 28800:
220: return B28800;
1.1 deraadt 221: #endif /* B28800 */
222: #ifdef B57600
1.3 markus 223: case 57600:
224: return B57600;
1.1 deraadt 225: #endif /* B57600 */
226: #ifdef B76800
1.3 markus 227: case 76800:
228: return B76800;
1.1 deraadt 229: #endif /* B76800 */
230: #ifdef B115200
1.3 markus 231: case 115200:
232: return B115200;
1.1 deraadt 233: #endif /* B115200 */
234: #ifdef B230400
1.3 markus 235: case 230400:
236: return B230400;
1.1 deraadt 237: #endif /* B230400 */
1.3 markus 238: default:
239: return B9600;
240: }
1.1 deraadt 241: }
242:
1.4 deraadt 243: /*
244: * Encodes terminal modes for the terminal referenced by fd
1.12 stevesk 245: * or tiop in a portable manner, and appends the modes to a packet
1.4 deraadt 246: * being constructed.
247: */
1.6 markus 248: void
1.12 stevesk 249: tty_make_modes(int fd, struct termios *tiop)
1.1 deraadt 250: {
1.3 markus 251: struct termios tio;
252: int baud;
1.12 stevesk 253: Buffer buf;
254: int tty_op_ospeed, tty_op_ispeed;
255: void (*put_arg)(Buffer *, u_int);
256:
257: buffer_init(&buf);
258: if (compat20) {
259: tty_op_ospeed = TTY_OP_OSPEED_PROTO2;
260: tty_op_ispeed = TTY_OP_ISPEED_PROTO2;
261: put_arg = buffer_put_int;
262: } else {
263: tty_op_ospeed = TTY_OP_OSPEED_PROTO1;
264: tty_op_ispeed = TTY_OP_ISPEED_PROTO1;
265: put_arg = (void (*)(Buffer *, u_int)) buffer_put_char;
266: }
267:
268: if (tiop == NULL) {
269: if (tcgetattr(fd, &tio) == -1) {
270: log("tcgetattr: %.100s", strerror(errno));
271: goto end;
272: }
273: } else
274: tio = *tiop;
1.1 deraadt 275:
1.3 markus 276: /* Store input and output baud rates. */
277: baud = speed_to_baud(cfgetospeed(&tio));
1.14 markus 278: debug3("tty_make_modes: ospeed %d", baud);
1.12 stevesk 279: buffer_put_char(&buf, tty_op_ospeed);
280: buffer_put_int(&buf, baud);
1.3 markus 281: baud = speed_to_baud(cfgetispeed(&tio));
1.14 markus 282: debug3("tty_make_modes: ispeed %d", baud);
1.12 stevesk 283: buffer_put_char(&buf, tty_op_ispeed);
284: buffer_put_int(&buf, baud);
1.1 deraadt 285:
1.3 markus 286: /* Store values of mode flags. */
1.1 deraadt 287: #define TTYCHAR(NAME, OP) \
1.14 markus 288: debug3("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \
1.12 stevesk 289: buffer_put_char(&buf, OP); \
290: put_arg(&buf, tio.c_cc[NAME]);
291:
1.1 deraadt 292: #define TTYMODE(NAME, FIELD, OP) \
1.14 markus 293: debug3("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \
1.12 stevesk 294: buffer_put_char(&buf, OP); \
295: put_arg(&buf, ((tio.FIELD & NAME) != 0));
1.1 deraadt 296:
297: #include "ttymodes.h"
298:
299: #undef TTYCHAR
300: #undef TTYMODE
301:
1.12 stevesk 302: end:
1.3 markus 303: /* Mark end of mode data. */
1.12 stevesk 304: buffer_put_char(&buf, TTY_OP_END);
305: if (compat20)
306: packet_put_string(buffer_ptr(&buf), buffer_len(&buf));
307: else
308: packet_put_raw(buffer_ptr(&buf), buffer_len(&buf));
309: buffer_free(&buf);
310: return;
1.1 deraadt 311: }
312:
1.4 deraadt 313: /*
314: * Decodes terminal modes for the terminal referenced by fd in a portable
315: * manner from a packet being read.
316: */
1.6 markus 317: void
1.3 markus 318: tty_parse_modes(int fd, int *n_bytes_ptr)
1.1 deraadt 319: {
1.3 markus 320: struct termios tio;
321: int opcode, baud;
322: int n_bytes = 0;
323: int failure = 0;
1.12 stevesk 324: u_int (*get_arg)(void);
325: int arg, arg_size;
326:
327: if (compat20) {
328: *n_bytes_ptr = packet_get_int();
1.14 markus 329: debug3("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr);
1.12 stevesk 330: if (*n_bytes_ptr == 0)
331: return;
332: get_arg = packet_get_int;
333: arg_size = 4;
334: } else {
335: get_arg = packet_get_char;
336: arg_size = 1;
337: }
1.3 markus 338:
1.4 deraadt 339: /*
340: * Get old attributes for the terminal. We will modify these
341: * flags. I am hoping that if there are any machine-specific
342: * modes, they will initially have reasonable values.
343: */
1.12 stevesk 344: if (tcgetattr(fd, &tio) == -1) {
345: log("tcgetattr: %.100s", strerror(errno));
1.3 markus 346: failure = -1;
1.12 stevesk 347: }
1.3 markus 348:
349: for (;;) {
350: n_bytes += 1;
351: opcode = packet_get_char();
352: switch (opcode) {
353: case TTY_OP_END:
354: goto set;
355:
1.12 stevesk 356: /* XXX: future conflict possible */
357: case TTY_OP_ISPEED_PROTO1:
358: case TTY_OP_ISPEED_PROTO2:
1.3 markus 359: n_bytes += 4;
360: baud = packet_get_int();
1.14 markus 361: debug3("tty_parse_modes: ispeed %d", baud);
1.12 stevesk 362: if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) == -1)
1.3 markus 363: error("cfsetispeed failed for %d", baud);
364: break;
365:
1.12 stevesk 366: /* XXX: future conflict possible */
367: case TTY_OP_OSPEED_PROTO1:
368: case TTY_OP_OSPEED_PROTO2:
1.3 markus 369: n_bytes += 4;
370: baud = packet_get_int();
1.14 markus 371: debug3("tty_parse_modes: ospeed %d", baud);
1.12 stevesk 372: if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) == -1)
1.3 markus 373: error("cfsetospeed failed for %d", baud);
374: break;
1.1 deraadt 375:
1.12 stevesk 376: #define TTYCHAR(NAME, OP) \
377: case OP: \
378: n_bytes += arg_size; \
379: tio.c_cc[NAME] = get_arg(); \
1.14 markus 380: debug3("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \
1.1 deraadt 381: break;
1.12 stevesk 382: #define TTYMODE(NAME, FIELD, OP) \
383: case OP: \
384: n_bytes += arg_size; \
385: if ((arg = get_arg())) \
386: tio.FIELD |= NAME; \
387: else \
388: tio.FIELD &= ~NAME; \
1.14 markus 389: debug3("tty_parse_modes: %d %d", OP, arg); \
1.1 deraadt 390: break;
391:
392: #include "ttymodes.h"
393:
394: #undef TTYCHAR
395: #undef TTYMODE
396:
1.3 markus 397: default:
398: debug("Ignoring unsupported tty mode opcode %d (0x%x)",
1.14.2.1 jason 399: opcode, opcode);
1.12 stevesk 400: if (!compat20) {
401: /*
402: * SSH1:
403: * Opcodes 1 to 127 are defined to have
404: * a one-byte argument.
1.14.2.2! miod 405: * Opcodes 128 to 159 are defined to have
! 406: * an integer argument.
! 407: */
1.12 stevesk 408: if (opcode > 0 && opcode < 128) {
409: n_bytes += 1;
410: (void) packet_get_char();
411: break;
412: } else if (opcode >= 128 && opcode < 160) {
1.14.2.2! miod 413: n_bytes += 4;
! 414: (void) packet_get_int();
! 415: break;
1.12 stevesk 416: } else {
417: /*
418: * It is a truly undefined opcode (160 to 255).
419: * We have no idea about its arguments. So we
420: * must stop parsing. Note that some data may be
421: * left in the packet; hopefully there is nothing
422: * more coming after the mode data.
423: */
424: log("parse_tty_modes: unknown opcode %d", opcode);
425: goto set;
1.14.2.2! miod 426: }
1.3 markus 427: } else {
1.4 deraadt 428: /*
1.12 stevesk 429: * SSH2:
1.13 stevesk 430: * Opcodes 1 to 159 are defined to have
1.12 stevesk 431: * a uint32 argument.
432: * Opcodes 160 to 255 are undefined and
433: * cause parsing to stop.
1.4 deraadt 434: */
1.12 stevesk 435: if (opcode > 0 && opcode < 160) {
1.3 markus 436: n_bytes += 4;
437: (void) packet_get_int();
438: break;
1.12 stevesk 439: } else {
440: log("parse_tty_modes: unknown opcode %d", opcode);
441: goto set;
1.3 markus 442: }
1.14.2.2! miod 443: }
1.1 deraadt 444: }
445: }
446:
1.3 markus 447: set:
448: if (*n_bytes_ptr != n_bytes) {
449: *n_bytes_ptr = n_bytes;
1.12 stevesk 450: log("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d",
451: *n_bytes_ptr, n_bytes);
1.3 markus 452: return; /* Don't process bytes passed */
453: }
454: if (failure == -1)
1.13 stevesk 455: return; /* Packet parsed ok but tcgetattr() failed */
1.3 markus 456:
457: /* Set the new modes for the terminal. */
1.12 stevesk 458: if (tcsetattr(fd, TCSANOW, &tio) == -1)
1.3 markus 459: log("Setting tty modes failed: %.100s", strerror(errno));
460: return;
1.1 deraadt 461: }