1 /* 2 * Author: Tatu Ylonen <ylo@cs.hut.fi> 3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4 * All rights reserved 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". 11 */ 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 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 39 * Use is subject to license terms. 40 */ 41 42 /* 43 * Encoding and decoding of terminal modes in a portable way. 44 * Much of the format is defined in ttymodes.h; it is included multiple times 45 * into this file with the appropriate macro definitions to generate the 46 * suitable code. 47 */ 48 49 #include "includes.h" 50 RCSID("$OpenBSD: ttymodes.c,v 1.18 2002/06/19 00:27:55 deraadt Exp $"); 51 52 #pragma ident "%Z%%M% %I% %E% SMI" 53 54 #include "packet.h" 55 #include "log.h" 56 #include "ssh1.h" 57 #include "compat.h" 58 #include "buffer.h" 59 #include "bufaux.h" 60 61 #define TTY_OP_END 0 62 /* 63 * uint32 (u_int) follows speed in SSH1 and SSH2 64 */ 65 #define TTY_OP_ISPEED_PROTO1 192 66 #define TTY_OP_OSPEED_PROTO1 193 67 #define TTY_OP_ISPEED_PROTO2 128 68 #define TTY_OP_OSPEED_PROTO2 129 69 70 /* 71 * Converts POSIX speed_t to a baud rate. The values of the 72 * constants for speed_t are not themselves portable. 73 */ 74 static int 75 speed_to_baud(speed_t speed) 76 { 77 switch (speed) { 78 case B0: 79 return 0; 80 case B50: 81 return 50; 82 case B75: 83 return 75; 84 case B110: 85 return 110; 86 case B134: 87 return 134; 88 case B150: 89 return 150; 90 case B200: 91 return 200; 92 case B300: 93 return 300; 94 case B600: 95 return 600; 96 case B1200: 97 return 1200; 98 case B1800: 99 return 1800; 100 case B2400: 101 return 2400; 102 case B4800: 103 return 4800; 104 case B9600: 105 return 9600; 106 107 #ifdef B19200 108 case B19200: 109 return 19200; 110 #else /* B19200 */ 111 #ifdef EXTA 112 case EXTA: 113 return 19200; 114 #endif /* EXTA */ 115 #endif /* B19200 */ 116 117 #ifdef B38400 118 case B38400: 119 return 38400; 120 #else /* B38400 */ 121 #ifdef EXTB 122 case EXTB: 123 return 38400; 124 #endif /* EXTB */ 125 #endif /* B38400 */ 126 127 #ifdef B7200 128 case B7200: 129 return 7200; 130 #endif /* B7200 */ 131 #ifdef B14400 132 case B14400: 133 return 14400; 134 #endif /* B14400 */ 135 #ifdef B28800 136 case B28800: 137 return 28800; 138 #endif /* B28800 */ 139 #ifdef B57600 140 case B57600: 141 return 57600; 142 #endif /* B57600 */ 143 #ifdef B76800 144 case B76800: 145 return 76800; 146 #endif /* B76800 */ 147 #ifdef B115200 148 case B115200: 149 return 115200; 150 #endif /* B115200 */ 151 #ifdef B230400 152 case B230400: 153 return 230400; 154 #endif /* B230400 */ 155 default: 156 return 9600; 157 } 158 } 159 160 /* 161 * Converts a numeric baud rate to a POSIX speed_t. 162 */ 163 static speed_t 164 baud_to_speed(int baud) 165 { 166 switch (baud) { 167 case 0: 168 return B0; 169 case 50: 170 return B50; 171 case 75: 172 return B75; 173 case 110: 174 return B110; 175 case 134: 176 return B134; 177 case 150: 178 return B150; 179 case 200: 180 return B200; 181 case 300: 182 return B300; 183 case 600: 184 return B600; 185 case 1200: 186 return B1200; 187 case 1800: 188 return B1800; 189 case 2400: 190 return B2400; 191 case 4800: 192 return B4800; 193 case 9600: 194 return B9600; 195 196 #ifdef B19200 197 case 19200: 198 return B19200; 199 #else /* B19200 */ 200 #ifdef EXTA 201 case 19200: 202 return EXTA; 203 #endif /* EXTA */ 204 #endif /* B19200 */ 205 206 #ifdef B38400 207 case 38400: 208 return B38400; 209 #else /* B38400 */ 210 #ifdef EXTB 211 case 38400: 212 return EXTB; 213 #endif /* EXTB */ 214 #endif /* B38400 */ 215 216 #ifdef B7200 217 case 7200: 218 return B7200; 219 #endif /* B7200 */ 220 #ifdef B14400 221 case 14400: 222 return B14400; 223 #endif /* B14400 */ 224 #ifdef B28800 225 case 28800: 226 return B28800; 227 #endif /* B28800 */ 228 #ifdef B57600 229 case 57600: 230 return B57600; 231 #endif /* B57600 */ 232 #ifdef B76800 233 case 76800: 234 return B76800; 235 #endif /* B76800 */ 236 #ifdef B115200 237 case 115200: 238 return B115200; 239 #endif /* B115200 */ 240 #ifdef B230400 241 case 230400: 242 return B230400; 243 #endif /* B230400 */ 244 default: 245 return B9600; 246 } 247 } 248 249 /* 250 * Encodes terminal modes for the terminal referenced by fd 251 * or tiop in a portable manner, and appends the modes to a packet 252 * being constructed. 253 */ 254 void 255 tty_make_modes(int fd, struct termios *tiop) 256 { 257 struct termios tio; 258 int baud; 259 Buffer buf; 260 int tty_op_ospeed, tty_op_ispeed; 261 void (*put_arg)(Buffer *, u_int); 262 263 buffer_init(&buf); 264 if (compat20) { 265 tty_op_ospeed = TTY_OP_OSPEED_PROTO2; 266 tty_op_ispeed = TTY_OP_ISPEED_PROTO2; 267 put_arg = buffer_put_int; 268 } else { 269 tty_op_ospeed = TTY_OP_OSPEED_PROTO1; 270 tty_op_ispeed = TTY_OP_ISPEED_PROTO1; 271 put_arg = (void (*)(Buffer *, u_int)) buffer_put_char; 272 } 273 274 if (tiop == NULL) { 275 if (tcgetattr(fd, &tio) == -1) { 276 log("tcgetattr: %.100s", strerror(errno)); 277 goto end; 278 } 279 } else 280 tio = *tiop; 281 282 /* Store input and output baud rates. */ 283 baud = speed_to_baud(cfgetospeed(&tio)); 284 debug3("tty_make_modes: ospeed %d", baud); 285 buffer_put_char(&buf, tty_op_ospeed); 286 buffer_put_int(&buf, baud); 287 baud = speed_to_baud(cfgetispeed(&tio)); 288 debug3("tty_make_modes: ispeed %d", baud); 289 buffer_put_char(&buf, tty_op_ispeed); 290 buffer_put_int(&buf, baud); 291 292 /* Store values of mode flags. */ 293 #define TTYCHAR(NAME, OP) \ 294 debug3("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \ 295 buffer_put_char(&buf, OP); \ 296 put_arg(&buf, tio.c_cc[NAME]); 297 298 #define TTYMODE(NAME, FIELD, OP) \ 299 debug3("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \ 300 buffer_put_char(&buf, OP); \ 301 put_arg(&buf, ((tio.FIELD & NAME) != 0)); 302 303 #include "ttymodes.h" 304 305 #undef TTYCHAR 306 #undef TTYMODE 307 308 end: 309 /* Mark end of mode data. */ 310 buffer_put_char(&buf, TTY_OP_END); 311 if (compat20) 312 packet_put_string(buffer_ptr(&buf), buffer_len(&buf)); 313 else 314 packet_put_raw(buffer_ptr(&buf), buffer_len(&buf)); 315 buffer_free(&buf); 316 } 317 318 /* 319 * Decodes terminal modes for the terminal referenced by fd in a portable 320 * manner from a packet being read. 321 */ 322 void 323 tty_parse_modes(int fd, int *n_bytes_ptr) 324 { 325 struct termios tio; 326 int opcode, baud; 327 int n_bytes = 0; 328 int failure = 0; 329 u_int (*get_arg)(void); 330 int arg, arg_size; 331 332 if (compat20) { 333 *n_bytes_ptr = packet_get_int(); 334 debug3("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr); 335 if (*n_bytes_ptr == 0) 336 return; 337 get_arg = packet_get_int; 338 arg_size = 4; 339 } else { 340 get_arg = packet_get_char; 341 arg_size = 1; 342 } 343 344 /* 345 * Get old attributes for the terminal. We will modify these 346 * flags. I am hoping that if there are any machine-specific 347 * modes, they will initially have reasonable values. 348 */ 349 if (tcgetattr(fd, &tio) == -1) { 350 log("tcgetattr: %.100s", strerror(errno)); 351 failure = -1; 352 } 353 354 for (;;) { 355 n_bytes += 1; 356 opcode = packet_get_char(); 357 switch (opcode) { 358 case TTY_OP_END: 359 goto set; 360 361 /* XXX: future conflict possible */ 362 case TTY_OP_ISPEED_PROTO1: 363 case TTY_OP_ISPEED_PROTO2: 364 n_bytes += 4; 365 baud = packet_get_int(); 366 debug3("tty_parse_modes: ispeed %d", baud); 367 if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) == -1) 368 error("cfsetispeed failed for %d", baud); 369 break; 370 371 /* XXX: future conflict possible */ 372 case TTY_OP_OSPEED_PROTO1: 373 case TTY_OP_OSPEED_PROTO2: 374 n_bytes += 4; 375 baud = packet_get_int(); 376 debug3("tty_parse_modes: ospeed %d", baud); 377 if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) == -1) 378 error("cfsetospeed failed for %d", baud); 379 break; 380 381 #define TTYCHAR(NAME, OP) \ 382 case OP: \ 383 n_bytes += arg_size; \ 384 tio.c_cc[NAME] = get_arg(); \ 385 debug3("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \ 386 break; 387 #define TTYMODE(NAME, FIELD, OP) \ 388 case OP: \ 389 n_bytes += arg_size; \ 390 if ((arg = get_arg())) \ 391 tio.FIELD |= NAME; \ 392 else \ 393 tio.FIELD &= ~NAME; \ 394 debug3("tty_parse_modes: %d %d", OP, arg); \ 395 break; 396 397 #include "ttymodes.h" 398 399 #undef TTYCHAR 400 #undef TTYMODE 401 402 default: 403 debug("Ignoring unsupported tty mode opcode %d (0x%x)", 404 opcode, opcode); 405 if (!compat20) { 406 /* 407 * SSH1: 408 * Opcodes 1 to 127 are defined to have 409 * a one-byte argument. 410 * Opcodes 128 to 159 are defined to have 411 * an integer argument. 412 */ 413 if (opcode > 0 && opcode < 128) { 414 n_bytes += 1; 415 (void) packet_get_char(); 416 break; 417 } else if (opcode >= 128 && opcode < 160) { 418 n_bytes += 4; 419 (void) packet_get_int(); 420 break; 421 } else { 422 /* 423 * It is a truly undefined opcode (160 to 255). 424 * We have no idea about its arguments. So we 425 * must stop parsing. Note that some data may be 426 * left in the packet; hopefully there is nothing 427 * more coming after the mode data. 428 */ 429 log("parse_tty_modes: unknown opcode %d", opcode); 430 goto set; 431 } 432 } else { 433 /* 434 * SSH2: 435 * Opcodes 1 to 159 are defined to have 436 * a uint32 argument. 437 * Opcodes 160 to 255 are undefined and 438 * cause parsing to stop. 439 */ 440 if (opcode > 0 && opcode < 160) { 441 n_bytes += 4; 442 (void) packet_get_int(); 443 break; 444 } else { 445 log("parse_tty_modes: unknown opcode %d", opcode); 446 goto set; 447 } 448 } 449 } 450 } 451 452 set: 453 if (*n_bytes_ptr != n_bytes) { 454 *n_bytes_ptr = n_bytes; 455 log("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d", 456 *n_bytes_ptr, n_bytes); 457 return; /* Don't process bytes passed */ 458 } 459 if (failure == -1) 460 return; /* Packet parsed ok but tcgetattr() failed */ 461 462 /* Set the new modes for the terminal. */ 463 if (tcsetattr(fd, TCSANOW, &tio) == -1) 464 log("Setting tty modes failed: %.100s", strerror(errno)); 465 } 466