1 /* $OpenBSD: ttymodes.c,v 1.32 2017/04/30 23:26:54 djm Exp $ */ 2 /* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * 7 * As far as I am concerned, the code I have written for this software 8 * can be used freely for any purpose. Any derived versions of this 9 * software must be clearly marked as such, and if the derived work is 10 * incompatible with the protocol description in the RFC file, it must be 11 * called by a name other than "ssh" or "Secure Shell". 12 */ 13 14 /* 15 * SSH2 tty modes support by Kevin Steves. 16 * Copyright (c) 2001 Kevin Steves. All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 32 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 /* 40 * Encoding and decoding of terminal modes in a portable way. 41 * Much of the format is defined in ttymodes.h; it is included multiple times 42 * into this file with the appropriate macro definitions to generate the 43 * suitable code. 44 */ 45 46 #include <sys/types.h> 47 48 #include <errno.h> 49 #include <string.h> 50 #include <termios.h> 51 #include <stdarg.h> 52 53 #include "packet.h" 54 #include "log.h" 55 #include "compat.h" 56 #include "buffer.h" 57 58 #define TTY_OP_END 0 59 /* 60 * uint32 (u_int) follows speed. 61 */ 62 #define TTY_OP_ISPEED 128 63 #define TTY_OP_OSPEED 129 64 65 /* 66 * Converts POSIX speed_t to a baud rate. The values of the 67 * constants for speed_t are not themselves portable. 68 */ 69 static int 70 speed_to_baud(speed_t speed) 71 { 72 switch (speed) { 73 case B0: 74 return 0; 75 case B50: 76 return 50; 77 case B75: 78 return 75; 79 case B110: 80 return 110; 81 case B134: 82 return 134; 83 case B150: 84 return 150; 85 case B200: 86 return 200; 87 case B300: 88 return 300; 89 case B600: 90 return 600; 91 case B1200: 92 return 1200; 93 case B1800: 94 return 1800; 95 case B2400: 96 return 2400; 97 case B4800: 98 return 4800; 99 case B9600: 100 return 9600; 101 102 #ifdef B19200 103 case B19200: 104 return 19200; 105 #else /* B19200 */ 106 #ifdef EXTA 107 case EXTA: 108 return 19200; 109 #endif /* EXTA */ 110 #endif /* B19200 */ 111 112 #ifdef B38400 113 case B38400: 114 return 38400; 115 #else /* B38400 */ 116 #ifdef EXTB 117 case EXTB: 118 return 38400; 119 #endif /* EXTB */ 120 #endif /* B38400 */ 121 122 #ifdef B7200 123 case B7200: 124 return 7200; 125 #endif /* B7200 */ 126 #ifdef B14400 127 case B14400: 128 return 14400; 129 #endif /* B14400 */ 130 #ifdef B28800 131 case B28800: 132 return 28800; 133 #endif /* B28800 */ 134 #ifdef B57600 135 case B57600: 136 return 57600; 137 #endif /* B57600 */ 138 #ifdef B76800 139 case B76800: 140 return 76800; 141 #endif /* B76800 */ 142 #ifdef B115200 143 case B115200: 144 return 115200; 145 #endif /* B115200 */ 146 #ifdef B230400 147 case B230400: 148 return 230400; 149 #endif /* B230400 */ 150 default: 151 return 9600; 152 } 153 } 154 155 /* 156 * Converts a numeric baud rate to a POSIX speed_t. 157 */ 158 static speed_t 159 baud_to_speed(int baud) 160 { 161 switch (baud) { 162 case 0: 163 return B0; 164 case 50: 165 return B50; 166 case 75: 167 return B75; 168 case 110: 169 return B110; 170 case 134: 171 return B134; 172 case 150: 173 return B150; 174 case 200: 175 return B200; 176 case 300: 177 return B300; 178 case 600: 179 return B600; 180 case 1200: 181 return B1200; 182 case 1800: 183 return B1800; 184 case 2400: 185 return B2400; 186 case 4800: 187 return B4800; 188 case 9600: 189 return B9600; 190 191 #ifdef B19200 192 case 19200: 193 return B19200; 194 #else /* B19200 */ 195 #ifdef EXTA 196 case 19200: 197 return EXTA; 198 #endif /* EXTA */ 199 #endif /* B19200 */ 200 201 #ifdef B38400 202 case 38400: 203 return B38400; 204 #else /* B38400 */ 205 #ifdef EXTB 206 case 38400: 207 return EXTB; 208 #endif /* EXTB */ 209 #endif /* B38400 */ 210 211 #ifdef B7200 212 case 7200: 213 return B7200; 214 #endif /* B7200 */ 215 #ifdef B14400 216 case 14400: 217 return B14400; 218 #endif /* B14400 */ 219 #ifdef B28800 220 case 28800: 221 return B28800; 222 #endif /* B28800 */ 223 #ifdef B57600 224 case 57600: 225 return B57600; 226 #endif /* B57600 */ 227 #ifdef B76800 228 case 76800: 229 return B76800; 230 #endif /* B76800 */ 231 #ifdef B115200 232 case 115200: 233 return B115200; 234 #endif /* B115200 */ 235 #ifdef B230400 236 case 230400: 237 return B230400; 238 #endif /* B230400 */ 239 default: 240 return B9600; 241 } 242 } 243 244 /* 245 * Encodes terminal modes for the terminal referenced by fd 246 * or tiop in a portable manner, and appends the modes to a packet 247 * being constructed. 248 */ 249 void 250 tty_make_modes(int fd, struct termios *tiop) 251 { 252 struct termios tio; 253 int baud; 254 Buffer buf; 255 256 buffer_init(&buf); 257 258 if (tiop == NULL) { 259 if (fd == -1) { 260 debug("tty_make_modes: no fd or tio"); 261 goto end; 262 } 263 if (tcgetattr(fd, &tio) == -1) { 264 logit("tcgetattr: %.100s", strerror(errno)); 265 goto end; 266 } 267 } else 268 tio = *tiop; 269 270 /* Store input and output baud rates. */ 271 baud = speed_to_baud(cfgetospeed(&tio)); 272 buffer_put_char(&buf, TTY_OP_OSPEED); 273 buffer_put_int(&buf, baud); 274 baud = speed_to_baud(cfgetispeed(&tio)); 275 buffer_put_char(&buf, TTY_OP_ISPEED); 276 buffer_put_int(&buf, baud); 277 278 /* Store values of mode flags. */ 279 #define TTYCHAR(NAME, OP) \ 280 buffer_put_char(&buf, OP); \ 281 buffer_put_int(&buf, tio.c_cc[NAME]); 282 283 #define TTYMODE(NAME, FIELD, OP) \ 284 buffer_put_char(&buf, OP); \ 285 buffer_put_int(&buf, ((tio.FIELD & NAME) != 0)); 286 287 #include "ttymodes.h" 288 289 #undef TTYCHAR 290 #undef TTYMODE 291 292 end: 293 /* Mark end of mode data. */ 294 buffer_put_char(&buf, TTY_OP_END); 295 packet_put_string(buffer_ptr(&buf), buffer_len(&buf)); 296 buffer_free(&buf); 297 } 298 299 /* 300 * Decodes terminal modes for the terminal referenced by fd in a portable 301 * manner from a packet being read. 302 */ 303 void 304 tty_parse_modes(int fd, int *n_bytes_ptr) 305 { 306 struct termios tio; 307 int opcode, baud; 308 int n_bytes = 0; 309 int failure = 0; 310 311 *n_bytes_ptr = packet_get_int(); 312 if (*n_bytes_ptr == 0) 313 return; 314 315 /* 316 * Get old attributes for the terminal. We will modify these 317 * flags. I am hoping that if there are any machine-specific 318 * modes, they will initially have reasonable values. 319 */ 320 if (tcgetattr(fd, &tio) == -1) { 321 logit("tcgetattr: %.100s", strerror(errno)); 322 failure = -1; 323 } 324 325 for (;;) { 326 n_bytes += 1; 327 opcode = packet_get_char(); 328 switch (opcode) { 329 case TTY_OP_END: 330 goto set; 331 332 case TTY_OP_ISPEED: 333 n_bytes += 4; 334 baud = packet_get_int(); 335 if (failure != -1 && 336 cfsetispeed(&tio, baud_to_speed(baud)) == -1) 337 error("cfsetispeed failed for %d", baud); 338 break; 339 340 case TTY_OP_OSPEED: 341 n_bytes += 4; 342 baud = packet_get_int(); 343 if (failure != -1 && 344 cfsetospeed(&tio, baud_to_speed(baud)) == -1) 345 error("cfsetospeed failed for %d", baud); 346 break; 347 348 #define TTYCHAR(NAME, OP) \ 349 case OP: \ 350 n_bytes += 4; \ 351 tio.c_cc[NAME] = packet_get_int(); \ 352 break; 353 #define TTYMODE(NAME, FIELD, OP) \ 354 case OP: \ 355 n_bytes += 4; \ 356 if (packet_get_int()) \ 357 tio.FIELD |= NAME; \ 358 else \ 359 tio.FIELD &= ~NAME; \ 360 break; 361 362 #include "ttymodes.h" 363 364 #undef TTYCHAR 365 #undef TTYMODE 366 367 default: 368 debug("Ignoring unsupported tty mode opcode %d (0x%x)", 369 opcode, opcode); 370 /* 371 * SSH2: 372 * Opcodes 1 to 159 are defined to have a uint32 373 * argument. 374 * Opcodes 160 to 255 are undefined and cause parsing 375 * to stop. 376 */ 377 if (opcode > 0 && opcode < 160) { 378 n_bytes += 4; 379 (void) packet_get_int(); 380 break; 381 } else { 382 logit("parse_tty_modes: unknown opcode %d", 383 opcode); 384 goto set; 385 } 386 } 387 } 388 389 set: 390 if (*n_bytes_ptr != n_bytes) { 391 *n_bytes_ptr = n_bytes; 392 logit("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d", 393 *n_bytes_ptr, n_bytes); 394 return; /* Don't process bytes passed */ 395 } 396 if (failure == -1) 397 return; /* Packet parsed ok but tcgetattr() failed */ 398 399 /* Set the new modes for the terminal. */ 400 if (tcsetattr(fd, TCSANOW, &tio) == -1) 401 logit("Setting tty modes failed: %.100s", strerror(errno)); 402 } 403