diff options
Diffstat (limited to 'ttymodes.c')
-rw-r--r-- | ttymodes.c | 231 |
1 files changed, 170 insertions, 61 deletions
diff --git a/ttymodes.c b/ttymodes.c index 65caf2ff8..9ce3fbcc4 100644 --- a/ttymodes.c +++ b/ttymodes.c | |||
@@ -2,10 +2,6 @@ | |||
2 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 2 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
4 | * All rights reserved | 4 | * All rights reserved |
5 | * Encoding and decoding of terminal modes in a portable way. | ||
6 | * Much of the format is defined in ttymodes.h; it is included multiple times | ||
7 | * into this file with the appropriate macro definitions to generate the | ||
8 | * suitable code. | ||
9 | * | 5 | * |
10 | * As far as I am concerned, the code I have written for this software | 6 | * As far as I am concerned, the code I have written for this software |
11 | * can be used freely for any purpose. Any derived versions of this | 7 | * can be used freely for any purpose. Any derived versions of this |
@@ -14,16 +10,56 @@ | |||
14 | * called by a name other than "ssh" or "Secure Shell". | 10 | * called by a name other than "ssh" or "Secure Shell". |
15 | */ | 11 | */ |
16 | 12 | ||
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 | |||
17 | #include "includes.h" | 45 | #include "includes.h" |
18 | RCSID("$OpenBSD: ttymodes.c,v 1.11 2001/03/10 15:02:05 stevesk Exp $"); | 46 | RCSID("$OpenBSD: ttymodes.c,v 1.12 2001/04/14 16:33:20 stevesk Exp $"); |
19 | 47 | ||
20 | #include "packet.h" | 48 | #include "packet.h" |
21 | #include "log.h" | 49 | #include "log.h" |
22 | #include "ssh1.h" | 50 | #include "ssh1.h" |
51 | #include "compat.h" | ||
52 | #include "buffer.h" | ||
53 | #include "bufaux.h" | ||
23 | 54 | ||
24 | #define TTY_OP_END 0 | 55 | #define TTY_OP_END 0 |
25 | #define TTY_OP_ISPEED 192 /* int follows */ | 56 | /* |
26 | #define TTY_OP_OSPEED 193 /* int follows */ | 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 | ||
27 | 63 | ||
28 | /* | 64 | /* |
29 | * Converts POSIX speed_t to a baud rate. The values of the | 65 | * Converts POSIX speed_t to a baud rate. The values of the |
@@ -122,7 +158,7 @@ static speed_t | |||
122 | baud_to_speed(int baud) | 158 | baud_to_speed(int baud) |
123 | { | 159 | { |
124 | switch (baud) { | 160 | switch (baud) { |
125 | case 0: | 161 | case 0: |
126 | return B0; | 162 | return B0; |
127 | case 50: | 163 | case 50: |
128 | return B50; | 164 | return B50; |
@@ -206,41 +242,72 @@ baud_to_speed(int baud) | |||
206 | 242 | ||
207 | /* | 243 | /* |
208 | * Encodes terminal modes for the terminal referenced by fd | 244 | * Encodes terminal modes for the terminal referenced by fd |
209 | * in a portable manner, and appends the modes to a packet | 245 | * or tiop in a portable manner, and appends the modes to a packet |
210 | * being constructed. | 246 | * being constructed. |
211 | */ | 247 | */ |
212 | void | 248 | void |
213 | tty_make_modes(int fd) | 249 | tty_make_modes(int fd, struct termios *tiop) |
214 | { | 250 | { |
215 | struct termios tio; | 251 | struct termios tio; |
216 | int baud; | 252 | int baud; |
253 | Buffer buf; | ||
254 | int tty_op_ospeed, tty_op_ispeed; | ||
255 | void (*put_arg)(Buffer *, u_int); | ||
217 | 256 | ||
218 | if (tcgetattr(fd, &tio) < 0) { | 257 | buffer_init(&buf); |
219 | packet_put_char(TTY_OP_END); | 258 | if (compat20) { |
220 | log("tcgetattr: %.100s", strerror(errno)); | 259 | tty_op_ospeed = TTY_OP_OSPEED_PROTO2; |
221 | return; | 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; | ||
222 | } | 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; | ||
275 | |||
223 | /* Store input and output baud rates. */ | 276 | /* Store input and output baud rates. */ |
224 | baud = speed_to_baud(cfgetospeed(&tio)); | 277 | baud = speed_to_baud(cfgetospeed(&tio)); |
225 | packet_put_char(TTY_OP_OSPEED); | 278 | debug2("tty_make_modes: ospeed %d", baud); |
226 | packet_put_int(baud); | 279 | buffer_put_char(&buf, tty_op_ospeed); |
280 | buffer_put_int(&buf, baud); | ||
227 | baud = speed_to_baud(cfgetispeed(&tio)); | 281 | baud = speed_to_baud(cfgetispeed(&tio)); |
228 | packet_put_char(TTY_OP_ISPEED); | 282 | debug2("tty_make_modes: ispeed %d", baud); |
229 | packet_put_int(baud); | 283 | buffer_put_char(&buf, tty_op_ispeed); |
284 | buffer_put_int(&buf, baud); | ||
230 | 285 | ||
231 | /* Store values of mode flags. */ | 286 | /* Store values of mode flags. */ |
232 | #define TTYCHAR(NAME, OP) \ | 287 | #define TTYCHAR(NAME, OP) \ |
233 | packet_put_char(OP); packet_put_char(tio.c_cc[NAME]); | 288 | debug2("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \ |
289 | buffer_put_char(&buf, OP); \ | ||
290 | put_arg(&buf, tio.c_cc[NAME]); | ||
291 | |||
234 | #define TTYMODE(NAME, FIELD, OP) \ | 292 | #define TTYMODE(NAME, FIELD, OP) \ |
235 | packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0); | 293 | debug2("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \ |
294 | buffer_put_char(&buf, OP); \ | ||
295 | put_arg(&buf, ((tio.FIELD & NAME) != 0)); | ||
236 | 296 | ||
237 | #include "ttymodes.h" | 297 | #include "ttymodes.h" |
238 | 298 | ||
239 | #undef TTYCHAR | 299 | #undef TTYCHAR |
240 | #undef TTYMODE | 300 | #undef TTYMODE |
241 | 301 | ||
302 | end: | ||
242 | /* Mark end of mode data. */ | 303 | /* Mark end of mode data. */ |
243 | packet_put_char(TTY_OP_END); | 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; | ||
244 | } | 311 | } |
245 | 312 | ||
246 | /* | 313 | /* |
@@ -254,14 +321,30 @@ tty_parse_modes(int fd, int *n_bytes_ptr) | |||
254 | int opcode, baud; | 321 | int opcode, baud; |
255 | int n_bytes = 0; | 322 | int n_bytes = 0; |
256 | int failure = 0; | 323 | int failure = 0; |
324 | u_int (*get_arg)(void); | ||
325 | int arg, arg_size; | ||
326 | |||
327 | if (compat20) { | ||
328 | *n_bytes_ptr = packet_get_int(); | ||
329 | debug2("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr); | ||
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 | } | ||
257 | 338 | ||
258 | /* | 339 | /* |
259 | * Get old attributes for the terminal. We will modify these | 340 | * Get old attributes for the terminal. We will modify these |
260 | * flags. I am hoping that if there are any machine-specific | 341 | * flags. I am hoping that if there are any machine-specific |
261 | * modes, they will initially have reasonable values. | 342 | * modes, they will initially have reasonable values. |
262 | */ | 343 | */ |
263 | if (tcgetattr(fd, &tio) < 0) | 344 | if (tcgetattr(fd, &tio) == -1) { |
345 | log("tcgetattr: %.100s", strerror(errno)); | ||
264 | failure = -1; | 346 | failure = -1; |
347 | } | ||
265 | 348 | ||
266 | for (;;) { | 349 | for (;;) { |
267 | n_bytes += 1; | 350 | n_bytes += 1; |
@@ -270,32 +353,40 @@ tty_parse_modes(int fd, int *n_bytes_ptr) | |||
270 | case TTY_OP_END: | 353 | case TTY_OP_END: |
271 | goto set; | 354 | goto set; |
272 | 355 | ||
273 | case TTY_OP_ISPEED: | 356 | /* XXX: future conflict possible */ |
357 | case TTY_OP_ISPEED_PROTO1: | ||
358 | case TTY_OP_ISPEED_PROTO2: | ||
274 | n_bytes += 4; | 359 | n_bytes += 4; |
275 | baud = packet_get_int(); | 360 | baud = packet_get_int(); |
276 | if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0) | 361 | debug2("tty_parse_modes: ispeed %d", baud); |
362 | if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) == -1) | ||
277 | error("cfsetispeed failed for %d", baud); | 363 | error("cfsetispeed failed for %d", baud); |
278 | break; | 364 | break; |
279 | 365 | ||
280 | case TTY_OP_OSPEED: | 366 | /* XXX: future conflict possible */ |
367 | case TTY_OP_OSPEED_PROTO1: | ||
368 | case TTY_OP_OSPEED_PROTO2: | ||
281 | n_bytes += 4; | 369 | n_bytes += 4; |
282 | baud = packet_get_int(); | 370 | baud = packet_get_int(); |
283 | if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0) | 371 | debug2("tty_parse_modes: ospeed %d", baud); |
372 | if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) == -1) | ||
284 | error("cfsetospeed failed for %d", baud); | 373 | error("cfsetospeed failed for %d", baud); |
285 | break; | 374 | break; |
286 | 375 | ||
287 | #define TTYCHAR(NAME, OP) \ | 376 | #define TTYCHAR(NAME, OP) \ |
288 | case OP: \ | 377 | case OP: \ |
289 | n_bytes += 1; \ | 378 | n_bytes += arg_size; \ |
290 | tio.c_cc[NAME] = packet_get_char(); \ | 379 | tio.c_cc[NAME] = get_arg(); \ |
380 | debug2("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \ | ||
291 | break; | 381 | break; |
292 | #define TTYMODE(NAME, FIELD, OP) \ | 382 | #define TTYMODE(NAME, FIELD, OP) \ |
293 | case OP: \ | 383 | case OP: \ |
294 | n_bytes += 1; \ | 384 | n_bytes += arg_size; \ |
295 | if (packet_get_char()) \ | 385 | if ((arg = get_arg())) \ |
296 | tio.FIELD |= NAME; \ | 386 | tio.FIELD |= NAME; \ |
297 | else \ | 387 | else \ |
298 | tio.FIELD &= ~NAME; \ | 388 | tio.FIELD &= ~NAME; \ |
389 | debug2("tty_parse_modes: %d %d", OP, arg); \ | ||
299 | break; | 390 | break; |
300 | 391 | ||
301 | #include "ttymodes.h" | 392 | #include "ttymodes.h" |
@@ -306,48 +397,66 @@ tty_parse_modes(int fd, int *n_bytes_ptr) | |||
306 | default: | 397 | default: |
307 | debug("Ignoring unsupported tty mode opcode %d (0x%x)", | 398 | debug("Ignoring unsupported tty mode opcode %d (0x%x)", |
308 | opcode, opcode); | 399 | opcode, opcode); |
309 | /* | 400 | if (!compat20) { |
310 | * Opcodes 0 to 127 are defined to have | 401 | /* |
311 | * a one-byte argument. | 402 | * SSH1: |
312 | */ | 403 | * Opcodes 1 to 127 are defined to have |
313 | if (opcode >= 0 && opcode < 128) { | 404 | * a one-byte argument. |
314 | n_bytes += 1; | 405 | * Opcodes 128 to 159 are defined to have |
315 | (void) packet_get_char(); | 406 | * an integer argument. |
316 | break; | 407 | */ |
408 | if (opcode > 0 && opcode < 128) { | ||
409 | n_bytes += 1; | ||
410 | (void) packet_get_char(); | ||
411 | break; | ||
412 | } else if (opcode >= 128 && opcode < 160) { | ||
413 | n_bytes += 4; | ||
414 | (void) packet_get_int(); | ||
415 | break; | ||
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 | packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY); | ||
426 | goto set; | ||
427 | } | ||
317 | } else { | 428 | } else { |
318 | /* | 429 | /* |
319 | * Opcodes 128 to 159 are defined to have | 430 | * SSH2: |
320 | * an integer argument. | 431 | * Opcodes 0 to 159 are defined to have |
432 | * a uint32 argument. | ||
433 | * Opcodes 160 to 255 are undefined and | ||
434 | * cause parsing to stop. | ||
321 | */ | 435 | */ |
322 | if (opcode >= 128 && opcode < 160) { | 436 | if (opcode > 0 && opcode < 160) { |
323 | n_bytes += 4; | 437 | n_bytes += 4; |
324 | (void) packet_get_int(); | 438 | (void) packet_get_int(); |
325 | break; | 439 | break; |
440 | } else { | ||
441 | log("parse_tty_modes: unknown opcode %d", opcode); | ||
442 | goto set; | ||
326 | } | 443 | } |
327 | } | 444 | } |
328 | /* | ||
329 | * It is a truly undefined opcode (160 to 255). | ||
330 | * We have no idea about its arguments. So we | ||
331 | * must stop parsing. Note that some data may be | ||
332 | * left in the packet; hopefully there is nothing | ||
333 | * more coming after the mode data. | ||
334 | */ | ||
335 | log("parse_tty_modes: unknown opcode %d", opcode); | ||
336 | packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY); | ||
337 | goto set; | ||
338 | } | 445 | } |
339 | } | 446 | } |
340 | 447 | ||
341 | set: | 448 | set: |
342 | if (*n_bytes_ptr != n_bytes) { | 449 | if (*n_bytes_ptr != n_bytes) { |
343 | *n_bytes_ptr = n_bytes; | 450 | *n_bytes_ptr = n_bytes; |
451 | log("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d", | ||
452 | *n_bytes_ptr, n_bytes); | ||
344 | return; /* Don't process bytes passed */ | 453 | return; /* Don't process bytes passed */ |
345 | } | 454 | } |
346 | if (failure == -1) | 455 | if (failure == -1) |
347 | return; /* Packet parsed ok but tty stuff failed */ | 456 | return; /* Packet parsed ok but tty stuff failed */ |
348 | 457 | ||
349 | /* Set the new modes for the terminal. */ | 458 | /* Set the new modes for the terminal. */ |
350 | if (tcsetattr(fd, TCSANOW, &tio) < 0) | 459 | if (tcsetattr(fd, TCSANOW, &tio) == -1) |
351 | log("Setting tty modes failed: %.100s", strerror(errno)); | 460 | log("Setting tty modes failed: %.100s", strerror(errno)); |
352 | return; | 461 | return; |
353 | } | 462 | } |