1 /* $NetBSD: ttymodes.c,v 1.11 2019/01/27 02:08:33 pgoyette Exp $ */ 2 /* $OpenBSD: ttymodes.c,v 1.34 2018/07/09 21:20:26 markus Exp $ */ 3 4 /* 5 * Author: Tatu Ylonen <ylo@cs.hut.fi> 6 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 7 * All rights reserved 8 * 9 * As far as I am concerned, the code I have written for this software 10 * can be used freely for any purpose. Any derived versions of this 11 * software must be clearly marked as such, and if the derived work is 12 * incompatible with the protocol description in the RFC file, it must be 13 * called by a name other than "ssh" or "Secure Shell". 14 */ 15 16 /* 17 * SSH2 tty modes support by Kevin Steves. 18 * Copyright (c) 2001 Kevin Steves. All rights reserved. 19 * 20 * Redistribution and use in source and binary forms, with or without 21 * modification, are permitted provided that the following conditions 22 * are met: 23 * 1. Redistributions of source code must retain the above copyright 24 * notice, this list of conditions and the following disclaimer. 25 * 2. Redistributions in binary form must reproduce the above copyright 26 * notice, this list of conditions and the following disclaimer in the 27 * documentation and/or other materials provided with the distribution. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 30 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 31 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 32 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 33 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 34 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 38 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 */ 40 41 /* 42 * Encoding and decoding of terminal modes in a portable way. 43 * Much of the format is defined in ttymodes.h; it is included multiple times 44 * into this file with the appropriate macro definitions to generate the 45 * suitable code. 46 */ 47 48 #include "includes.h" 49 __RCSID("$NetBSD: ttymodes.c,v 1.11 2019/01/27 02:08:33 pgoyette Exp $"); 50 #include <sys/types.h> 51 52 #include <errno.h> 53 #include <string.h> 54 #include <termios.h> 55 #include <stdarg.h> 56 57 #include "packet.h" 58 #include "log.h" 59 #include "compat.h" 60 #include "sshbuf.h" 61 #include "ssherr.h" 62 63 #define TTY_OP_END 0 64 /* 65 * uint32 (u_int) follows speed. 66 */ 67 #define TTY_OP_ISPEED 128 68 #define TTY_OP_OSPEED 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 ssh_tty_make_modes(struct ssh *ssh, int fd, struct termios *tiop) 256 { 257 struct termios tio; 258 struct sshbuf *buf; 259 int r, ibaud, obaud; 260 261 if ((buf = sshbuf_new()) == NULL) 262 fatal("%s: sshbuf_new failed", __func__); 263 264 if (tiop == NULL) { 265 if (fd == -1) { 266 debug("%s: no fd or tio", __func__); 267 goto end; 268 } 269 if (tcgetattr(fd, &tio) == -1) { 270 logit("tcgetattr: %.100s", strerror(errno)); 271 goto end; 272 } 273 } else 274 tio = *tiop; 275 276 /* Store input and output baud rates. */ 277 obaud = speed_to_baud(cfgetospeed(&tio)); 278 ibaud = speed_to_baud(cfgetispeed(&tio)); 279 if ((r = sshbuf_put_u8(buf, TTY_OP_OSPEED)) != 0 || 280 (r = sshbuf_put_u32(buf, obaud)) != 0 || 281 (r = sshbuf_put_u8(buf, TTY_OP_ISPEED)) != 0 || 282 (r = sshbuf_put_u32(buf, ibaud)) != 0) 283 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 284 285 /* Store values of mode flags. */ 286 #define TTYCHAR(NAME, OP) \ 287 if ((r = sshbuf_put_u8(buf, OP)) != 0 || \ 288 (r = sshbuf_put_u32(buf, tio.c_cc[NAME])) != 0) \ 289 fatal("%s: buffer error: %s", __func__, ssh_err(r)); \ 290 291 #define SSH_TTYMODE_IUTF8 42 /* for SSH_BUG_UTF8TTYMODE */ 292 293 #define TTYMODE(NAME, FIELD, OP) \ 294 if (OP == SSH_TTYMODE_IUTF8 && (datafellows & SSH_BUG_UTF8TTYMODE)) { \ 295 debug3("%s: SSH_BUG_UTF8TTYMODE", __func__); \ 296 } else if ((r = sshbuf_put_u8(buf, OP)) != 0 || \ 297 (r = sshbuf_put_u32(buf, ((tio.FIELD & NAME) != 0))) != 0) \ 298 fatal("%s: buffer error: %s", __func__, ssh_err(r)); \ 299 300 #include "ttymodes.h" 301 302 #undef TTYCHAR 303 #undef TTYMODE 304 305 end: 306 /* Mark end of mode data. */ 307 if ((r = sshbuf_put_u8(buf, TTY_OP_END)) != 0 || 308 (r = sshpkt_put_stringb(ssh, buf)) != 0) 309 fatal("%s: packet error: %s", __func__, ssh_err(r)); 310 sshbuf_free(buf); 311 } 312 313 /* 314 * Decodes terminal modes for the terminal referenced by fd in a portable 315 * manner from a packet being read. 316 */ 317 void 318 ssh_tty_parse_modes(struct ssh *ssh, int fd) 319 { 320 struct termios tio; 321 struct sshbuf *buf; 322 const u_char *data; 323 u_char opcode; 324 u_int baud, u; 325 int r, failure = 0; 326 size_t len; 327 328 if ((r = sshpkt_get_string_direct(ssh, &data, &len)) != 0) 329 fatal("%s: packet error: %s", __func__, ssh_err(r)); 330 if (len == 0) 331 return; 332 if ((buf = sshbuf_from(data, len)) == NULL) { 333 error("%s: sshbuf_from failed", __func__); 334 return; 335 } 336 337 /* 338 * Get old attributes for the terminal. We will modify these 339 * flags. I am hoping that if there are any machine-specific 340 * modes, they will initially have reasonable values. 341 */ 342 if (tcgetattr(fd, &tio) == -1) { 343 logit("tcgetattr: %.100s", strerror(errno)); 344 failure = -1; 345 } 346 347 while (sshbuf_len(buf) > 0) { 348 if ((r = sshbuf_get_u8(buf, &opcode)) != 0) 349 fatal("%s: packet error: %s", __func__, ssh_err(r)); 350 switch (opcode) { 351 case TTY_OP_END: 352 goto set; 353 354 case TTY_OP_ISPEED: 355 if ((r = sshbuf_get_u32(buf, &baud)) != 0) 356 fatal("%s: packet error: %s", 357 __func__, ssh_err(r)); 358 if (failure != -1 && 359 cfsetispeed(&tio, baud_to_speed(baud)) == -1) 360 error("cfsetispeed failed for %d", baud); 361 break; 362 363 case TTY_OP_OSPEED: 364 if ((r = sshbuf_get_u32(buf, &baud)) != 0) 365 fatal("%s: packet error: %s", 366 __func__, ssh_err(r)); 367 if (failure != -1 && 368 cfsetospeed(&tio, baud_to_speed(baud)) == -1) 369 error("cfsetospeed failed for %d", baud); 370 break; 371 372 #define TTYCHAR(NAME, OP) \ 373 case OP: \ 374 if ((r = sshbuf_get_u32(buf, &u)) != 0) \ 375 fatal("%s: packet error: %s", __func__, \ 376 ssh_err(r)); \ 377 tio.c_cc[NAME] = u; \ 378 break; 379 #define TTYMODE(NAME, FIELD, OP) \ 380 case OP: \ 381 if ((r = sshbuf_get_u32(buf, &u)) != 0) \ 382 fatal("%s: packet error: %s", __func__, \ 383 ssh_err(r)); \ 384 if (u) \ 385 tio.FIELD |= NAME; \ 386 else \ 387 tio.FIELD &= ~NAME; \ 388 break; 389 390 #include "ttymodes.h" 391 392 #undef TTYCHAR 393 #undef TTYMODE 394 395 default: 396 debug("Ignoring unsupported tty mode opcode %d (0x%x)", 397 opcode, opcode); 398 /* 399 * SSH2: 400 * Opcodes 1 to 159 are defined to have a uint32 401 * argument. 402 * Opcodes 160 to 255 are undefined and cause parsing 403 * to stop. 404 */ 405 if (opcode > 0 && opcode < 160) { 406 if ((r = sshbuf_get_u32(buf, NULL)) != 0) 407 fatal("%s: packet error: %s", __func__, 408 ssh_err(r)); 409 break; 410 } else { 411 logit("%s: unknown opcode %d", __func__, 412 opcode); 413 goto set; 414 } 415 } 416 } 417 418 set: 419 len = sshbuf_len(buf); 420 sshbuf_free(buf); 421 if (len > 0) { 422 logit("%s: %zu bytes left", __func__, len); 423 return; /* Don't process bytes passed */ 424 } 425 if (failure == -1) 426 return; /* Packet parsed ok but tcgetattr() failed */ 427 428 /* Set the new modes for the terminal. */ 429 if (tcsetattr(fd, TCSANOW, &tio) == -1) 430 logit("Setting tty modes failed: %.100s", strerror(errno)); 431 } 432