X-Git-Url: http://andersk.mit.edu/gitweb/openssh.git/blobdiff_plain/42f11eb24fa39e437b4f1e6beb5cc83901aa5bdd..HEAD:/ttymodes.c diff --git a/ttymodes.c b/ttymodes.c index 2516e931..6f51b8a7 100644 --- a/ttymodes.c +++ b/ttymodes.c @@ -1,11 +1,8 @@ +/* $OpenBSD: ttymodes.c,v 1.29 2008/11/02 00:16:16 stevesk Exp $ */ /* * Author: Tatu Ylonen * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland * All rights reserved - * Encoding and decoding of terminal modes in a portable way. - * Much of the format is defined in ttymodes.h; it is included multiple times - * into this file with the appropriate macro definitions to generate the - * suitable code. * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose. Any derived versions of this @@ -14,16 +11,61 @@ * called by a name other than "ssh" or "Secure Shell". */ +/* + * SSH2 tty modes support by Kevin Steves. + * Copyright (c) 2001 Kevin Steves. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Encoding and decoding of terminal modes in a portable way. + * Much of the format is defined in ttymodes.h; it is included multiple times + * into this file with the appropriate macro definitions to generate the + * suitable code. + */ + #include "includes.h" -RCSID("$OpenBSD: ttymodes.c,v 1.10 2001/01/21 19:06:01 markus Exp $"); + +#include + +#include +#include +#include +#include #include "packet.h" #include "log.h" #include "ssh1.h" +#include "compat.h" +#include "buffer.h" -#define TTY_OP_END 0 -#define TTY_OP_ISPEED 192 /* int follows */ -#define TTY_OP_OSPEED 193 /* int follows */ +#define TTY_OP_END 0 +/* + * uint32 (u_int) follows speed in SSH1 and SSH2 + */ +#define TTY_OP_ISPEED_PROTO1 192 +#define TTY_OP_OSPEED_PROTO1 193 +#define TTY_OP_ISPEED_PROTO2 128 +#define TTY_OP_OSPEED_PROTO2 129 /* * Converts POSIX speed_t to a baud rate. The values of the @@ -122,7 +164,7 @@ static speed_t baud_to_speed(int baud) { switch (baud) { - case 0: + case 0: return B0; case 50: return B50; @@ -204,49 +246,99 @@ baud_to_speed(int baud) } } +/* + * Encode a special character into SSH line format. + */ +static u_int +special_char_encode(cc_t c) +{ +#ifdef _POSIX_VDISABLE + if (c == _POSIX_VDISABLE) + return 255; +#endif /* _POSIX_VDISABLE */ + return c; +} + +/* + * Decode a special character from SSH line format. + */ +static cc_t +special_char_decode(u_int c) +{ +#ifdef _POSIX_VDISABLE + if (c == 255) + return _POSIX_VDISABLE; +#endif /* _POSIX_VDISABLE */ + return c; +} + /* * Encodes terminal modes for the terminal referenced by fd - * in a portable manner, and appends the modes to a packet + * or tiop in a portable manner, and appends the modes to a packet * being constructed. */ void -tty_make_modes(int fd) +tty_make_modes(int fd, struct termios *tiop) { struct termios tio; int baud; + Buffer buf; + int tty_op_ospeed, tty_op_ispeed; + void (*put_arg)(Buffer *, u_int); - if (tcgetattr(fd, &tio) < 0) { - packet_put_char(TTY_OP_END); - log("tcgetattr: %.100s", strerror(errno)); - return; + buffer_init(&buf); + if (compat20) { + tty_op_ospeed = TTY_OP_OSPEED_PROTO2; + tty_op_ispeed = TTY_OP_ISPEED_PROTO2; + put_arg = buffer_put_int; + } else { + tty_op_ospeed = TTY_OP_OSPEED_PROTO1; + tty_op_ispeed = TTY_OP_ISPEED_PROTO1; + put_arg = (void (*)(Buffer *, u_int)) buffer_put_char; } + + if (tiop == NULL) { + if (fd == -1) { + debug("tty_make_modes: no fd or tio"); + goto end; + } + if (tcgetattr(fd, &tio) == -1) { + logit("tcgetattr: %.100s", strerror(errno)); + goto end; + } + } else + tio = *tiop; + /* Store input and output baud rates. */ baud = speed_to_baud(cfgetospeed(&tio)); - packet_put_char(TTY_OP_OSPEED); - packet_put_int(baud); + buffer_put_char(&buf, tty_op_ospeed); + buffer_put_int(&buf, baud); baud = speed_to_baud(cfgetispeed(&tio)); - packet_put_char(TTY_OP_ISPEED); - packet_put_int(baud); + buffer_put_char(&buf, tty_op_ispeed); + buffer_put_int(&buf, baud); /* Store values of mode flags. */ #define TTYCHAR(NAME, OP) \ - packet_put_char(OP); packet_put_char(tio.c_cc[NAME]); + buffer_put_char(&buf, OP); \ + put_arg(&buf, special_char_encode(tio.c_cc[NAME])); + #define TTYMODE(NAME, FIELD, OP) \ - packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0); -#define SGTTYCHAR(NAME, OP) -#define SGTTYMODE(NAME, FIELD, OP) -#define SGTTYMODEN(NAME, FIELD, OP) + buffer_put_char(&buf, OP); \ + put_arg(&buf, ((tio.FIELD & NAME) != 0)); #include "ttymodes.h" #undef TTYCHAR #undef TTYMODE -#undef SGTTYCHAR -#undef SGTTYMODE -#undef SGTTYMODEN +end: /* Mark end of mode data. */ - packet_put_char(TTY_OP_END); + buffer_put_char(&buf, TTY_OP_END); + if (compat20) + packet_put_string(buffer_ptr(&buf), buffer_len(&buf)); + else + packet_put_raw(buffer_ptr(&buf), buffer_len(&buf)); + buffer_free(&buf); } /* @@ -260,14 +352,29 @@ tty_parse_modes(int fd, int *n_bytes_ptr) int opcode, baud; int n_bytes = 0; int failure = 0; + u_int (*get_arg)(void); + int arg_size; + + if (compat20) { + *n_bytes_ptr = packet_get_int(); + if (*n_bytes_ptr == 0) + return; + get_arg = packet_get_int; + arg_size = 4; + } else { + get_arg = packet_get_char; + arg_size = 1; + } /* * Get old attributes for the terminal. We will modify these * flags. I am hoping that if there are any machine-specific * modes, they will initially have reasonable values. */ - if (tcgetattr(fd, &tio) < 0) + if (tcgetattr(fd, &tio) == -1) { + logit("tcgetattr: %.100s", strerror(errno)); failure = -1; + } for (;;) { n_bytes += 1; @@ -276,90 +383,108 @@ tty_parse_modes(int fd, int *n_bytes_ptr) case TTY_OP_END: goto set; - case TTY_OP_ISPEED: + /* XXX: future conflict possible */ + case TTY_OP_ISPEED_PROTO1: + case TTY_OP_ISPEED_PROTO2: n_bytes += 4; baud = packet_get_int(); - if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0) + if (failure != -1 && + cfsetispeed(&tio, baud_to_speed(baud)) == -1) error("cfsetispeed failed for %d", baud); break; - case TTY_OP_OSPEED: + /* XXX: future conflict possible */ + case TTY_OP_OSPEED_PROTO1: + case TTY_OP_OSPEED_PROTO2: n_bytes += 4; baud = packet_get_int(); - if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0) + if (failure != -1 && + cfsetospeed(&tio, baud_to_speed(baud)) == -1) error("cfsetospeed failed for %d", baud); break; -#define TTYCHAR(NAME, OP) \ - case OP: \ - n_bytes += 1; \ - tio.c_cc[NAME] = packet_get_char(); \ +#define TTYCHAR(NAME, OP) \ + case OP: \ + n_bytes += arg_size; \ + tio.c_cc[NAME] = special_char_decode(get_arg()); \ break; -#define TTYMODE(NAME, FIELD, OP) \ - case OP: \ - n_bytes += 1; \ - if (packet_get_char()) \ - tio.FIELD |= NAME; \ - else \ - tio.FIELD &= ~NAME; \ +#define TTYMODE(NAME, FIELD, OP) \ + case OP: \ + n_bytes += arg_size; \ + if (get_arg()) \ + tio.FIELD |= NAME; \ + else \ + tio.FIELD &= ~NAME; \ break; -#define SGTTYCHAR(NAME, OP) -#define SGTTYMODE(NAME, FIELD, OP) -#define SGTTYMODEN(NAME, FIELD, OP) #include "ttymodes.h" #undef TTYCHAR #undef TTYMODE -#undef SGTTYCHAR -#undef SGTTYMODE -#undef SGTTYMODEN default: debug("Ignoring unsupported tty mode opcode %d (0x%x)", - opcode, opcode); - /* - * Opcodes 0 to 127 are defined to have - * a one-byte argument. - */ - if (opcode >= 0 && opcode < 128) { - n_bytes += 1; - (void) packet_get_char(); - break; - } else { + opcode, opcode); + if (!compat20) { /* + * SSH1: + * Opcodes 1 to 127 are defined to have + * a one-byte argument. * Opcodes 128 to 159 are defined to have * an integer argument. */ - if (opcode >= 128 && opcode < 160) { + if (opcode > 0 && opcode < 128) { + n_bytes += 1; + (void) packet_get_char(); + break; + } else if (opcode >= 128 && opcode < 160) { + n_bytes += 4; + (void) packet_get_int(); + break; + } else { + /* + * It is a truly undefined opcode (160 to 255). + * We have no idea about its arguments. So we + * must stop parsing. Note that some data + * may be left in the packet; hopefully there + * is nothing more coming after the mode data. + */ + logit("parse_tty_modes: unknown opcode %d", + opcode); + goto set; + } + } else { + /* + * SSH2: + * Opcodes 1 to 159 are defined to have + * a uint32 argument. + * Opcodes 160 to 255 are undefined and + * cause parsing to stop. + */ + if (opcode > 0 && opcode < 160) { n_bytes += 4; (void) packet_get_int(); break; + } else { + logit("parse_tty_modes: unknown opcode %d", + opcode); + goto set; } } - /* - * It is a truly undefined opcode (160 to 255). - * We have no idea about its arguments. So we - * must stop parsing. Note that some data may be - * left in the packet; hopefully there is nothing - * more coming after the mode data. - */ - log("parse_tty_modes: unknown opcode %d", opcode); - packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY); - goto set; } } set: if (*n_bytes_ptr != n_bytes) { *n_bytes_ptr = n_bytes; + logit("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d", + *n_bytes_ptr, n_bytes); return; /* Don't process bytes passed */ } if (failure == -1) - return; /* Packet parsed ok but tty stuff failed */ + return; /* Packet parsed ok but tcgetattr() failed */ /* Set the new modes for the terminal. */ - if (tcsetattr(fd, TCSANOW, &tio) < 0) - log("Setting tty modes failed: %.100s", strerror(errno)); - return; + if (tcsetattr(fd, TCSANOW, &tio) == -1) + logit("Setting tty modes failed: %.100s", strerror(errno)); }