version 1.8.2.6, 2002/03/08 17:04:43 |
version 1.9, 2001/01/19 15:55:12 |
|
|
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
* All rights reserved |
* 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 |
* 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 |
* can be used freely for any purpose. Any derived versions of this |
|
|
* called by a name other than "ssh" or "Secure Shell". |
* 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" |
#include "includes.h" |
RCSID("$OpenBSD$"); |
RCSID("$OpenBSD$"); |
|
|
#include "packet.h" |
#include "packet.h" |
#include "log.h" |
#include "ssh.h" |
#include "ssh1.h" |
#include "ssh1.h" |
#include "compat.h" |
|
#include "buffer.h" |
|
#include "bufaux.h" |
|
|
|
#define TTY_OP_END 0 |
#define TTY_OP_END 0 |
/* |
#define TTY_OP_ISPEED 192 /* int follows */ |
* uint32 (u_int) follows speed in SSH1 and SSH2 |
#define TTY_OP_OSPEED 193 /* int follows */ |
*/ |
|
#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 |
* Converts POSIX speed_t to a baud rate. The values of the |
|
|
baud_to_speed(int baud) |
baud_to_speed(int baud) |
{ |
{ |
switch (baud) { |
switch (baud) { |
case 0: |
case 0: |
return B0; |
return B0; |
case 50: |
case 50: |
return B50; |
return B50; |
|
|
|
|
/* |
/* |
* Encodes terminal modes for the terminal referenced by fd |
* Encodes terminal modes for the terminal referenced by fd |
* or tiop in a portable manner, and appends the modes to a packet |
* in a portable manner, and appends the modes to a packet |
* being constructed. |
* being constructed. |
*/ |
*/ |
void |
void |
tty_make_modes(int fd, struct termios *tiop) |
tty_make_modes(int fd) |
{ |
{ |
struct termios tio; |
struct termios tio; |
int baud; |
int baud; |
Buffer buf; |
|
int tty_op_ospeed, tty_op_ispeed; |
|
void (*put_arg)(Buffer *, u_int); |
|
|
|
buffer_init(&buf); |
if (tcgetattr(fd, &tio) < 0) { |
if (compat20) { |
packet_put_char(TTY_OP_END); |
tty_op_ospeed = TTY_OP_OSPEED_PROTO2; |
log("tcgetattr: %.100s", strerror(errno)); |
tty_op_ispeed = TTY_OP_ISPEED_PROTO2; |
return; |
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 (tcgetattr(fd, &tio) == -1) { |
|
log("tcgetattr: %.100s", strerror(errno)); |
|
goto end; |
|
} |
|
} else |
|
tio = *tiop; |
|
|
|
/* Store input and output baud rates. */ |
/* Store input and output baud rates. */ |
baud = speed_to_baud(cfgetospeed(&tio)); |
baud = speed_to_baud(cfgetospeed(&tio)); |
debug3("tty_make_modes: ospeed %d", baud); |
packet_put_char(TTY_OP_OSPEED); |
buffer_put_char(&buf, tty_op_ospeed); |
packet_put_int(baud); |
buffer_put_int(&buf, baud); |
|
baud = speed_to_baud(cfgetispeed(&tio)); |
baud = speed_to_baud(cfgetispeed(&tio)); |
debug3("tty_make_modes: ispeed %d", baud); |
packet_put_char(TTY_OP_ISPEED); |
buffer_put_char(&buf, tty_op_ispeed); |
packet_put_int(baud); |
buffer_put_int(&buf, baud); |
|
|
|
/* Store values of mode flags. */ |
/* Store values of mode flags. */ |
#define TTYCHAR(NAME, OP) \ |
#define TTYCHAR(NAME, OP) \ |
debug3("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \ |
packet_put_char(OP); packet_put_char(tio.c_cc[NAME]); |
buffer_put_char(&buf, OP); \ |
|
put_arg(&buf, tio.c_cc[NAME]); |
|
|
|
#define TTYMODE(NAME, FIELD, OP) \ |
#define TTYMODE(NAME, FIELD, OP) \ |
debug3("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \ |
packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0); |
buffer_put_char(&buf, OP); \ |
#define SGTTYCHAR(NAME, OP) |
put_arg(&buf, ((tio.FIELD & NAME) != 0)); |
#define SGTTYMODE(NAME, FIELD, OP) |
|
#define SGTTYMODEN(NAME, FIELD, OP) |
|
|
#include "ttymodes.h" |
#include "ttymodes.h" |
|
|
#undef TTYCHAR |
#undef TTYCHAR |
#undef TTYMODE |
#undef TTYMODE |
|
#undef SGTTYCHAR |
|
#undef SGTTYMODE |
|
#undef SGTTYMODEN |
|
|
end: |
|
/* Mark end of mode data. */ |
/* Mark end of mode data. */ |
buffer_put_char(&buf, TTY_OP_END); |
packet_put_char(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); |
|
return; |
|
} |
} |
|
|
/* |
/* |
|
|
int opcode, baud; |
int opcode, baud; |
int n_bytes = 0; |
int n_bytes = 0; |
int failure = 0; |
int failure = 0; |
u_int (*get_arg)(void); |
|
int arg, arg_size; |
|
|
|
if (compat20) { |
|
*n_bytes_ptr = packet_get_int(); |
|
debug3("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr); |
|
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 |
* Get old attributes for the terminal. We will modify these |
* flags. I am hoping that if there are any machine-specific |
* flags. I am hoping that if there are any machine-specific |
* modes, they will initially have reasonable values. |
* modes, they will initially have reasonable values. |
*/ |
*/ |
if (tcgetattr(fd, &tio) == -1) { |
if (tcgetattr(fd, &tio) < 0) |
log("tcgetattr: %.100s", strerror(errno)); |
|
failure = -1; |
failure = -1; |
} |
|
|
|
for (;;) { |
for (;;) { |
n_bytes += 1; |
n_bytes += 1; |
|
|
case TTY_OP_END: |
case TTY_OP_END: |
goto set; |
goto set; |
|
|
/* XXX: future conflict possible */ |
case TTY_OP_ISPEED: |
case TTY_OP_ISPEED_PROTO1: |
|
case TTY_OP_ISPEED_PROTO2: |
|
n_bytes += 4; |
n_bytes += 4; |
baud = packet_get_int(); |
baud = packet_get_int(); |
debug3("tty_parse_modes: ispeed %d", baud); |
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); |
error("cfsetispeed failed for %d", baud); |
break; |
break; |
|
|
/* XXX: future conflict possible */ |
case TTY_OP_OSPEED: |
case TTY_OP_OSPEED_PROTO1: |
|
case TTY_OP_OSPEED_PROTO2: |
|
n_bytes += 4; |
n_bytes += 4; |
baud = packet_get_int(); |
baud = packet_get_int(); |
debug3("tty_parse_modes: ospeed %d", baud); |
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); |
error("cfsetospeed failed for %d", baud); |
break; |
break; |
|
|
#define TTYCHAR(NAME, OP) \ |
#define TTYCHAR(NAME, OP) \ |
case OP: \ |
case OP: \ |
n_bytes += arg_size; \ |
n_bytes += 1; \ |
tio.c_cc[NAME] = get_arg(); \ |
tio.c_cc[NAME] = packet_get_char(); \ |
debug3("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \ |
|
break; |
break; |
#define TTYMODE(NAME, FIELD, OP) \ |
#define TTYMODE(NAME, FIELD, OP) \ |
case OP: \ |
case OP: \ |
n_bytes += arg_size; \ |
n_bytes += 1; \ |
if ((arg = get_arg())) \ |
if (packet_get_char()) \ |
tio.FIELD |= NAME; \ |
tio.FIELD |= NAME; \ |
else \ |
else \ |
tio.FIELD &= ~NAME; \ |
tio.FIELD &= ~NAME; \ |
debug3("tty_parse_modes: %d %d", OP, arg); \ |
|
break; |
break; |
|
#define SGTTYCHAR(NAME, OP) |
|
#define SGTTYMODE(NAME, FIELD, OP) |
|
#define SGTTYMODEN(NAME, FIELD, OP) |
|
|
#include "ttymodes.h" |
#include "ttymodes.h" |
|
|
#undef TTYCHAR |
#undef TTYCHAR |
#undef TTYMODE |
#undef TTYMODE |
|
#undef SGTTYCHAR |
|
#undef SGTTYMODE |
|
#undef SGTTYMODEN |
|
|
default: |
default: |
debug("Ignoring unsupported tty mode opcode %d (0x%x)", |
debug("Ignoring unsupported tty mode opcode %d (0x%x)", |
opcode, opcode); |
opcode, opcode); |
if (!compat20) { |
/* |
/* |
* Opcodes 0 to 127 are defined to have |
* SSH1: |
* a one-byte argument. |
* Opcodes 1 to 127 are defined to have |
*/ |
* a one-byte argument. |
if (opcode >= 0 && opcode < 128) { |
* Opcodes 128 to 159 are defined to have |
n_bytes += 1; |
* an integer argument. |
(void) packet_get_char(); |
*/ |
break; |
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. |
|
*/ |
|
log("parse_tty_modes: unknown opcode %d", opcode); |
|
goto set; |
|
} |
|
} else { |
} else { |
/* |
/* |
* SSH2: |
* Opcodes 128 to 159 are defined to have |
* Opcodes 1 to 159 are defined to have |
* an integer argument. |
* a uint32 argument. |
|
* Opcodes 160 to 255 are undefined and |
|
* cause parsing to stop. |
|
*/ |
*/ |
if (opcode > 0 && opcode < 160) { |
if (opcode >= 128 && opcode < 160) { |
n_bytes += 4; |
n_bytes += 4; |
(void) packet_get_int(); |
(void) packet_get_int(); |
break; |
break; |
} else { |
|
log("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: |
set: |
if (*n_bytes_ptr != n_bytes) { |
if (*n_bytes_ptr != n_bytes) { |
*n_bytes_ptr = n_bytes; |
*n_bytes_ptr = n_bytes; |
log("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d", |
|
*n_bytes_ptr, n_bytes); |
|
return; /* Don't process bytes passed */ |
return; /* Don't process bytes passed */ |
} |
} |
if (failure == -1) |
if (failure == -1) |
return; /* Packet parsed ok but tcgetattr() failed */ |
return; /* Packet parsed ok but tty stuff failed */ |
|
|
/* Set the new modes for the terminal. */ |
/* Set the new modes for the terminal. */ |
if (tcsetattr(fd, TCSANOW, &tio) == -1) |
if (tcsetattr(fd, TCSANOW, &tio) < 0) |
log("Setting tty modes failed: %.100s", strerror(errno)); |
log("Setting tty modes failed: %.100s", strerror(errno)); |
return; |
return; |
} |
} |