1511b41d2SMark Murray /* 2511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi> 3511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4511b41d2SMark Murray * All rights reserved 5511b41d2SMark Murray * Created: Tue Mar 21 15:59:15 1995 ylo 6511b41d2SMark Murray * Encoding and decoding of terminal modes in a portable way. 7511b41d2SMark Murray * Much of the format is defined in ttymodes.h; it is included multiple times 8511b41d2SMark Murray * into this file with the appropriate macro definitions to generate the 9511b41d2SMark Murray * suitable code. 10511b41d2SMark Murray */ 11511b41d2SMark Murray 12511b41d2SMark Murray #include "includes.h" 13511b41d2SMark Murray RCSID("$Id: ttymodes.c,v 1.5 1999/11/24 19:53:54 markus Exp $"); 14511b41d2SMark Murray 15511b41d2SMark Murray #include "packet.h" 16511b41d2SMark Murray #include "ssh.h" 17511b41d2SMark Murray 18511b41d2SMark Murray #define TTY_OP_END 0 19511b41d2SMark Murray #define TTY_OP_ISPEED 192 /* int follows */ 20511b41d2SMark Murray #define TTY_OP_OSPEED 193 /* int follows */ 21511b41d2SMark Murray 22511b41d2SMark Murray /* 23511b41d2SMark Murray * Converts POSIX speed_t to a baud rate. The values of the 24511b41d2SMark Murray * constants for speed_t are not themselves portable. 25511b41d2SMark Murray */ 26511b41d2SMark Murray static int 27511b41d2SMark Murray speed_to_baud(speed_t speed) 28511b41d2SMark Murray { 29511b41d2SMark Murray switch (speed) { 30511b41d2SMark Murray case B0: 31511b41d2SMark Murray return 0; 32511b41d2SMark Murray case B50: 33511b41d2SMark Murray return 50; 34511b41d2SMark Murray case B75: 35511b41d2SMark Murray return 75; 36511b41d2SMark Murray case B110: 37511b41d2SMark Murray return 110; 38511b41d2SMark Murray case B134: 39511b41d2SMark Murray return 134; 40511b41d2SMark Murray case B150: 41511b41d2SMark Murray return 150; 42511b41d2SMark Murray case B200: 43511b41d2SMark Murray return 200; 44511b41d2SMark Murray case B300: 45511b41d2SMark Murray return 300; 46511b41d2SMark Murray case B600: 47511b41d2SMark Murray return 600; 48511b41d2SMark Murray case B1200: 49511b41d2SMark Murray return 1200; 50511b41d2SMark Murray case B1800: 51511b41d2SMark Murray return 1800; 52511b41d2SMark Murray case B2400: 53511b41d2SMark Murray return 2400; 54511b41d2SMark Murray case B4800: 55511b41d2SMark Murray return 4800; 56511b41d2SMark Murray case B9600: 57511b41d2SMark Murray return 9600; 58511b41d2SMark Murray 59511b41d2SMark Murray #ifdef B19200 60511b41d2SMark Murray case B19200: 61511b41d2SMark Murray return 19200; 62511b41d2SMark Murray #else /* B19200 */ 63511b41d2SMark Murray #ifdef EXTA 64511b41d2SMark Murray case EXTA: 65511b41d2SMark Murray return 19200; 66511b41d2SMark Murray #endif /* EXTA */ 67511b41d2SMark Murray #endif /* B19200 */ 68511b41d2SMark Murray 69511b41d2SMark Murray #ifdef B38400 70511b41d2SMark Murray case B38400: 71511b41d2SMark Murray return 38400; 72511b41d2SMark Murray #else /* B38400 */ 73511b41d2SMark Murray #ifdef EXTB 74511b41d2SMark Murray case EXTB: 75511b41d2SMark Murray return 38400; 76511b41d2SMark Murray #endif /* EXTB */ 77511b41d2SMark Murray #endif /* B38400 */ 78511b41d2SMark Murray 79511b41d2SMark Murray #ifdef B7200 80511b41d2SMark Murray case B7200: 81511b41d2SMark Murray return 7200; 82511b41d2SMark Murray #endif /* B7200 */ 83511b41d2SMark Murray #ifdef B14400 84511b41d2SMark Murray case B14400: 85511b41d2SMark Murray return 14400; 86511b41d2SMark Murray #endif /* B14400 */ 87511b41d2SMark Murray #ifdef B28800 88511b41d2SMark Murray case B28800: 89511b41d2SMark Murray return 28800; 90511b41d2SMark Murray #endif /* B28800 */ 91511b41d2SMark Murray #ifdef B57600 92511b41d2SMark Murray case B57600: 93511b41d2SMark Murray return 57600; 94511b41d2SMark Murray #endif /* B57600 */ 95511b41d2SMark Murray #ifdef B76800 96511b41d2SMark Murray case B76800: 97511b41d2SMark Murray return 76800; 98511b41d2SMark Murray #endif /* B76800 */ 99511b41d2SMark Murray #ifdef B115200 100511b41d2SMark Murray case B115200: 101511b41d2SMark Murray return 115200; 102511b41d2SMark Murray #endif /* B115200 */ 103511b41d2SMark Murray #ifdef B230400 104511b41d2SMark Murray case B230400: 105511b41d2SMark Murray return 230400; 106511b41d2SMark Murray #endif /* B230400 */ 107511b41d2SMark Murray default: 108511b41d2SMark Murray return 9600; 109511b41d2SMark Murray } 110511b41d2SMark Murray } 111511b41d2SMark Murray 112511b41d2SMark Murray /* 113511b41d2SMark Murray * Converts a numeric baud rate to a POSIX speed_t. 114511b41d2SMark Murray */ 115511b41d2SMark Murray static speed_t 116511b41d2SMark Murray baud_to_speed(int baud) 117511b41d2SMark Murray { 118511b41d2SMark Murray switch (baud) { 119511b41d2SMark Murray case 0: 120511b41d2SMark Murray return B0; 121511b41d2SMark Murray case 50: 122511b41d2SMark Murray return B50; 123511b41d2SMark Murray case 75: 124511b41d2SMark Murray return B75; 125511b41d2SMark Murray case 110: 126511b41d2SMark Murray return B110; 127511b41d2SMark Murray case 134: 128511b41d2SMark Murray return B134; 129511b41d2SMark Murray case 150: 130511b41d2SMark Murray return B150; 131511b41d2SMark Murray case 200: 132511b41d2SMark Murray return B200; 133511b41d2SMark Murray case 300: 134511b41d2SMark Murray return B300; 135511b41d2SMark Murray case 600: 136511b41d2SMark Murray return B600; 137511b41d2SMark Murray case 1200: 138511b41d2SMark Murray return B1200; 139511b41d2SMark Murray case 1800: 140511b41d2SMark Murray return B1800; 141511b41d2SMark Murray case 2400: 142511b41d2SMark Murray return B2400; 143511b41d2SMark Murray case 4800: 144511b41d2SMark Murray return B4800; 145511b41d2SMark Murray case 9600: 146511b41d2SMark Murray return B9600; 147511b41d2SMark Murray 148511b41d2SMark Murray #ifdef B19200 149511b41d2SMark Murray case 19200: 150511b41d2SMark Murray return B19200; 151511b41d2SMark Murray #else /* B19200 */ 152511b41d2SMark Murray #ifdef EXTA 153511b41d2SMark Murray case 19200: 154511b41d2SMark Murray return EXTA; 155511b41d2SMark Murray #endif /* EXTA */ 156511b41d2SMark Murray #endif /* B19200 */ 157511b41d2SMark Murray 158511b41d2SMark Murray #ifdef B38400 159511b41d2SMark Murray case 38400: 160511b41d2SMark Murray return B38400; 161511b41d2SMark Murray #else /* B38400 */ 162511b41d2SMark Murray #ifdef EXTB 163511b41d2SMark Murray case 38400: 164511b41d2SMark Murray return EXTB; 165511b41d2SMark Murray #endif /* EXTB */ 166511b41d2SMark Murray #endif /* B38400 */ 167511b41d2SMark Murray 168511b41d2SMark Murray #ifdef B7200 169511b41d2SMark Murray case 7200: 170511b41d2SMark Murray return B7200; 171511b41d2SMark Murray #endif /* B7200 */ 172511b41d2SMark Murray #ifdef B14400 173511b41d2SMark Murray case 14400: 174511b41d2SMark Murray return B14400; 175511b41d2SMark Murray #endif /* B14400 */ 176511b41d2SMark Murray #ifdef B28800 177511b41d2SMark Murray case 28800: 178511b41d2SMark Murray return B28800; 179511b41d2SMark Murray #endif /* B28800 */ 180511b41d2SMark Murray #ifdef B57600 181511b41d2SMark Murray case 57600: 182511b41d2SMark Murray return B57600; 183511b41d2SMark Murray #endif /* B57600 */ 184511b41d2SMark Murray #ifdef B76800 185511b41d2SMark Murray case 76800: 186511b41d2SMark Murray return B76800; 187511b41d2SMark Murray #endif /* B76800 */ 188511b41d2SMark Murray #ifdef B115200 189511b41d2SMark Murray case 115200: 190511b41d2SMark Murray return B115200; 191511b41d2SMark Murray #endif /* B115200 */ 192511b41d2SMark Murray #ifdef B230400 193511b41d2SMark Murray case 230400: 194511b41d2SMark Murray return B230400; 195511b41d2SMark Murray #endif /* B230400 */ 196511b41d2SMark Murray default: 197511b41d2SMark Murray return B9600; 198511b41d2SMark Murray } 199511b41d2SMark Murray } 200511b41d2SMark Murray 201511b41d2SMark Murray /* 202511b41d2SMark Murray * Encodes terminal modes for the terminal referenced by fd 203511b41d2SMark Murray * in a portable manner, and appends the modes to a packet 204511b41d2SMark Murray * being constructed. 205511b41d2SMark Murray */ 206511b41d2SMark Murray void 207511b41d2SMark Murray tty_make_modes(int fd) 208511b41d2SMark Murray { 209511b41d2SMark Murray struct termios tio; 210511b41d2SMark Murray int baud; 211511b41d2SMark Murray 212511b41d2SMark Murray if (tcgetattr(fd, &tio) < 0) { 213511b41d2SMark Murray packet_put_char(TTY_OP_END); 214511b41d2SMark Murray log("tcgetattr: %.100s", strerror(errno)); 215511b41d2SMark Murray return; 216511b41d2SMark Murray } 217511b41d2SMark Murray /* Store input and output baud rates. */ 218511b41d2SMark Murray baud = speed_to_baud(cfgetospeed(&tio)); 219511b41d2SMark Murray packet_put_char(TTY_OP_OSPEED); 220511b41d2SMark Murray packet_put_int(baud); 221511b41d2SMark Murray baud = speed_to_baud(cfgetispeed(&tio)); 222511b41d2SMark Murray packet_put_char(TTY_OP_ISPEED); 223511b41d2SMark Murray packet_put_int(baud); 224511b41d2SMark Murray 225511b41d2SMark Murray /* Store values of mode flags. */ 226511b41d2SMark Murray #define TTYCHAR(NAME, OP) \ 227511b41d2SMark Murray packet_put_char(OP); packet_put_char(tio.c_cc[NAME]); 228511b41d2SMark Murray #define TTYMODE(NAME, FIELD, OP) \ 229511b41d2SMark Murray packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0); 230511b41d2SMark Murray #define SGTTYCHAR(NAME, OP) 231511b41d2SMark Murray #define SGTTYMODE(NAME, FIELD, OP) 232511b41d2SMark Murray #define SGTTYMODEN(NAME, FIELD, OP) 233511b41d2SMark Murray 234511b41d2SMark Murray #include "ttymodes.h" 235511b41d2SMark Murray 236511b41d2SMark Murray #undef TTYCHAR 237511b41d2SMark Murray #undef TTYMODE 238511b41d2SMark Murray #undef SGTTYCHAR 239511b41d2SMark Murray #undef SGTTYMODE 240511b41d2SMark Murray #undef SGTTYMODEN 241511b41d2SMark Murray 242511b41d2SMark Murray /* Mark end of mode data. */ 243511b41d2SMark Murray packet_put_char(TTY_OP_END); 244511b41d2SMark Murray } 245511b41d2SMark Murray 246511b41d2SMark Murray /* 247511b41d2SMark Murray * Decodes terminal modes for the terminal referenced by fd in a portable 248511b41d2SMark Murray * manner from a packet being read. 249511b41d2SMark Murray */ 250511b41d2SMark Murray void 251511b41d2SMark Murray tty_parse_modes(int fd, int *n_bytes_ptr) 252511b41d2SMark Murray { 253511b41d2SMark Murray struct termios tio; 254511b41d2SMark Murray int opcode, baud; 255511b41d2SMark Murray int n_bytes = 0; 256511b41d2SMark Murray int failure = 0; 257511b41d2SMark Murray 258511b41d2SMark Murray /* 259511b41d2SMark Murray * Get old attributes for the terminal. We will modify these 260511b41d2SMark Murray * flags. I am hoping that if there are any machine-specific 261511b41d2SMark Murray * modes, they will initially have reasonable values. 262511b41d2SMark Murray */ 263511b41d2SMark Murray if (tcgetattr(fd, &tio) < 0) 264511b41d2SMark Murray failure = -1; 265511b41d2SMark Murray 266511b41d2SMark Murray for (;;) { 267511b41d2SMark Murray n_bytes += 1; 268511b41d2SMark Murray opcode = packet_get_char(); 269511b41d2SMark Murray switch (opcode) { 270511b41d2SMark Murray case TTY_OP_END: 271511b41d2SMark Murray goto set; 272511b41d2SMark Murray 273511b41d2SMark Murray case TTY_OP_ISPEED: 274511b41d2SMark Murray n_bytes += 4; 275511b41d2SMark Murray baud = packet_get_int(); 276511b41d2SMark Murray if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0) 277511b41d2SMark Murray error("cfsetispeed failed for %d", baud); 278511b41d2SMark Murray break; 279511b41d2SMark Murray 280511b41d2SMark Murray case TTY_OP_OSPEED: 281511b41d2SMark Murray n_bytes += 4; 282511b41d2SMark Murray baud = packet_get_int(); 283511b41d2SMark Murray if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0) 284511b41d2SMark Murray error("cfsetospeed failed for %d", baud); 285511b41d2SMark Murray break; 286511b41d2SMark Murray 287511b41d2SMark Murray #define TTYCHAR(NAME, OP) \ 288511b41d2SMark Murray case OP: \ 289511b41d2SMark Murray n_bytes += 1; \ 290511b41d2SMark Murray tio.c_cc[NAME] = packet_get_char(); \ 291511b41d2SMark Murray break; 292511b41d2SMark Murray #define TTYMODE(NAME, FIELD, OP) \ 293511b41d2SMark Murray case OP: \ 294511b41d2SMark Murray n_bytes += 1; \ 295511b41d2SMark Murray if (packet_get_char()) \ 296511b41d2SMark Murray tio.FIELD |= NAME; \ 297511b41d2SMark Murray else \ 298511b41d2SMark Murray tio.FIELD &= ~NAME; \ 299511b41d2SMark Murray break; 300511b41d2SMark Murray #define SGTTYCHAR(NAME, OP) 301511b41d2SMark Murray #define SGTTYMODE(NAME, FIELD, OP) 302511b41d2SMark Murray #define SGTTYMODEN(NAME, FIELD, OP) 303511b41d2SMark Murray 304511b41d2SMark Murray #include "ttymodes.h" 305511b41d2SMark Murray 306511b41d2SMark Murray #undef TTYCHAR 307511b41d2SMark Murray #undef TTYMODE 308511b41d2SMark Murray #undef SGTTYCHAR 309511b41d2SMark Murray #undef SGTTYMODE 310511b41d2SMark Murray #undef SGTTYMODEN 311511b41d2SMark Murray 312511b41d2SMark Murray default: 313511b41d2SMark Murray debug("Ignoring unsupported tty mode opcode %d (0x%x)", 314511b41d2SMark Murray opcode, opcode); 315511b41d2SMark Murray /* 316511b41d2SMark Murray * Opcodes 0 to 127 are defined to have 317511b41d2SMark Murray * a one-byte argument. 318511b41d2SMark Murray */ 319511b41d2SMark Murray if (opcode >= 0 && opcode < 128) { 320511b41d2SMark Murray n_bytes += 1; 321511b41d2SMark Murray (void) packet_get_char(); 322511b41d2SMark Murray break; 323511b41d2SMark Murray } else { 324511b41d2SMark Murray /* 325511b41d2SMark Murray * Opcodes 128 to 159 are defined to have 326511b41d2SMark Murray * an integer argument. 327511b41d2SMark Murray */ 328511b41d2SMark Murray if (opcode >= 128 && opcode < 160) { 329511b41d2SMark Murray n_bytes += 4; 330511b41d2SMark Murray (void) packet_get_int(); 331511b41d2SMark Murray break; 332511b41d2SMark Murray } 333511b41d2SMark Murray } 334511b41d2SMark Murray /* 335511b41d2SMark Murray * It is a truly undefined opcode (160 to 255). 336511b41d2SMark Murray * We have no idea about its arguments. So we 337511b41d2SMark Murray * must stop parsing. Note that some data may be 338511b41d2SMark Murray * left in the packet; hopefully there is nothing 339511b41d2SMark Murray * more coming after the mode data. 340511b41d2SMark Murray */ 341511b41d2SMark Murray log("parse_tty_modes: unknown opcode %d", opcode); 342511b41d2SMark Murray packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY); 343511b41d2SMark Murray goto set; 344511b41d2SMark Murray } 345511b41d2SMark Murray } 346511b41d2SMark Murray 347511b41d2SMark Murray set: 348511b41d2SMark Murray if (*n_bytes_ptr != n_bytes) { 349511b41d2SMark Murray *n_bytes_ptr = n_bytes; 350511b41d2SMark Murray return; /* Don't process bytes passed */ 351511b41d2SMark Murray } 352511b41d2SMark Murray if (failure == -1) 353511b41d2SMark Murray return; /* Packet parsed ok but tty stuff failed */ 354511b41d2SMark Murray 355511b41d2SMark Murray /* Set the new modes for the terminal. */ 356511b41d2SMark Murray if (tcsetattr(fd, TCSANOW, &tio) < 0) 357511b41d2SMark Murray log("Setting tty modes failed: %.100s", strerror(errno)); 358511b41d2SMark Murray return; 359511b41d2SMark Murray } 360