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