Annotation of src/usr.bin/ssh/ttymodes.c, Revision 1.1
1.1 ! deraadt 1: /*
! 2:
! 3: ttymodes.c
! 4:
! 5: Author: Tatu Ylonen <ylo@cs.hut.fi>
! 6:
! 7: Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
! 8: All rights reserved
! 9:
! 10: Created: Tue Mar 21 15:59:15 1995 ylo
! 11:
! 12: Encoding and decoding of terminal modes in a portable way.
! 13: Much of the format is defined in ttymodes.h; it is included multiple times
! 14: into this file with the appropriate macro definitions to generate the
! 15: suitable code.
! 16:
! 17: */
! 18:
! 19: #include "includes.h"
! 20: RCSID("$Id: ttymodes.c,v 1.3 1999/05/04 11:59:25 bg Exp $");
! 21:
! 22: #include "packet.h"
! 23: #include "ssh.h"
! 24:
! 25: #define TTY_OP_END 0
! 26: #define TTY_OP_ISPEED 192 /* int follows */
! 27: #define TTY_OP_OSPEED 193 /* int follows */
! 28:
! 29: /* Speed extraction & setting macros for sgtty. */
! 30:
! 31: #ifdef USING_SGTTY
! 32: #define cfgetospeed(tio) ((tio)->sg_ospeed)
! 33: #define cfgetispeed(tio) ((tio)->sg_ispeed)
! 34: #define cfsetospeed(tio, spd) ((tio)->sg_ospeed = (spd), 0)
! 35: #define cfsetispeed(tio, spd) ((tio)->sg_ispeed = (spd), 0)
! 36: #ifndef SPEED_T_IN_STDTYPES_H
! 37: typedef char speed_t;
! 38: #endif
! 39: #endif
! 40:
! 41: /* Converts POSIX speed_t to a baud rate. The values of the constants
! 42: for speed_t are not themselves portable. */
! 43:
! 44: static int speed_to_baud(speed_t speed)
! 45: {
! 46: switch (speed)
! 47: {
! 48: case B0:
! 49: return 0;
! 50: case B50:
! 51: return 50;
! 52: case B75:
! 53: return 75;
! 54: case B110:
! 55: return 110;
! 56: case B134:
! 57: return 134;
! 58: case B150:
! 59: return 150;
! 60: case B200:
! 61: return 200;
! 62: case B300:
! 63: return 300;
! 64: case B600:
! 65: return 600;
! 66: case B1200:
! 67: return 1200;
! 68: case B1800:
! 69: return 1800;
! 70: case B2400:
! 71: return 2400;
! 72: case B4800:
! 73: return 4800;
! 74: case B9600:
! 75: return 9600;
! 76:
! 77: #ifdef B19200
! 78: case B19200:
! 79: return 19200;
! 80: #else /* B19200 */
! 81: #ifdef EXTA
! 82: case EXTA:
! 83: return 19200;
! 84: #endif /* EXTA */
! 85: #endif /* B19200 */
! 86:
! 87: #ifdef B38400
! 88: case B38400:
! 89: return 38400;
! 90: #else /* B38400 */
! 91: #ifdef EXTB
! 92: case EXTB:
! 93: return 38400;
! 94: #endif /* EXTB */
! 95: #endif /* B38400 */
! 96:
! 97: #ifdef B7200
! 98: case B7200:
! 99: return 7200;
! 100: #endif /* B7200 */
! 101: #ifdef B14400
! 102: case B14400:
! 103: return 14400;
! 104: #endif /* B14400 */
! 105: #ifdef B28800
! 106: case B28800:
! 107: return 28800;
! 108: #endif /* B28800 */
! 109: #ifdef B57600
! 110: case B57600:
! 111: return 57600;
! 112: #endif /* B57600 */
! 113: #ifdef B76800
! 114: case B76800:
! 115: return 76800;
! 116: #endif /* B76800 */
! 117: #ifdef B115200
! 118: case B115200:
! 119: return 115200;
! 120: #endif /* B115200 */
! 121: #ifdef B230400
! 122: case B230400:
! 123: return 230400;
! 124: #endif /* B230400 */
! 125: default:
! 126: return 9600;
! 127: }
! 128: }
! 129:
! 130: /* Converts a numeric baud rate to a POSIX speed_t. */
! 131:
! 132: static speed_t baud_to_speed(int baud)
! 133: {
! 134: switch (baud)
! 135: {
! 136: case 0:
! 137: return B0;
! 138: case 50:
! 139: return B50;
! 140: case 75:
! 141: return B75;
! 142: case 110:
! 143: return B110;
! 144: case 134:
! 145: return B134;
! 146: case 150:
! 147: return B150;
! 148: case 200:
! 149: return B200;
! 150: case 300:
! 151: return B300;
! 152: case 600:
! 153: return B600;
! 154: case 1200:
! 155: return B1200;
! 156: case 1800:
! 157: return B1800;
! 158: case 2400:
! 159: return B2400;
! 160: case 4800:
! 161: return B4800;
! 162: case 9600:
! 163: return B9600;
! 164:
! 165: #ifdef B19200
! 166: case 19200:
! 167: return B19200;
! 168: #else /* B19200 */
! 169: #ifdef EXTA
! 170: case 19200:
! 171: return EXTA;
! 172: #endif /* EXTA */
! 173: #endif /* B19200 */
! 174:
! 175: #ifdef B38400
! 176: case 38400:
! 177: return B38400;
! 178: #else /* B38400 */
! 179: #ifdef EXTB
! 180: case 38400:
! 181: return EXTB;
! 182: #endif /* EXTB */
! 183: #endif /* B38400 */
! 184:
! 185: #ifdef B7200
! 186: case 7200:
! 187: return B7200;
! 188: #endif /* B7200 */
! 189: #ifdef B14400
! 190: case 14400:
! 191: return B14400;
! 192: #endif /* B14400 */
! 193: #ifdef B28800
! 194: case 28800:
! 195: return B28800;
! 196: #endif /* B28800 */
! 197: #ifdef B57600
! 198: case 57600:
! 199: return B57600;
! 200: #endif /* B57600 */
! 201: #ifdef B76800
! 202: case 76800:
! 203: return B76800;
! 204: #endif /* B76800 */
! 205: #ifdef B115200
! 206: case 115200:
! 207: return B115200;
! 208: #endif /* B115200 */
! 209: #ifdef B230400
! 210: case 230400:
! 211: return B230400;
! 212: #endif /* B230400 */
! 213: default:
! 214: return B9600;
! 215: }
! 216: }
! 217:
! 218: /* Encodes terminal modes for the terminal referenced by fd in a portable
! 219: manner, and appends the modes to a packet being constructed. */
! 220:
! 221: void tty_make_modes(int fd)
! 222: {
! 223: #ifdef USING_TERMIOS
! 224: struct termios tio;
! 225: #endif
! 226: #ifdef USING_SGTTY
! 227: struct sgttyb tio;
! 228: struct tchars tiotc;
! 229: struct ltchars tioltc;
! 230: int tiolm;
! 231: #ifdef TIOCGSTAT
! 232: struct tstatus tiots;
! 233: #endif /* TIOCGSTAT */
! 234: #endif /* USING_SGTTY */
! 235: int baud;
! 236:
! 237: /* Get the modes. */
! 238: #ifdef USING_TERMIOS
! 239: if (tcgetattr(fd, &tio) < 0)
! 240: {
! 241: packet_put_char(TTY_OP_END);
! 242: log("tcgetattr: %.100s", strerror(errno));
! 243: return;
! 244: }
! 245: #endif /* USING_TERMIOS */
! 246: #ifdef USING_SGTTY
! 247: if (ioctl(fd, TIOCGETP, &tio) < 0)
! 248: {
! 249: packet_put_char(TTY_OP_END);
! 250: log("ioctl(fd, TIOCGETP, ...): %.100s", strerror(errno));
! 251: return;
! 252: }
! 253: if (ioctl(fd, TIOCGETC, &tiotc) < 0)
! 254: {
! 255: packet_put_char(TTY_OP_END);
! 256: log("ioctl(fd, TIOCGETC, ...): %.100s", strerror(errno));
! 257: return;
! 258: }
! 259: if (ioctl(fd, TIOCLGET, &tiolm) < 0)
! 260: {
! 261: packet_put_char(TTY_OP_END);
! 262: log("ioctl(fd, TIOCLGET, ...): %.100s", strerror(errno));
! 263: return;
! 264: }
! 265: if (ioctl(fd, TIOCGLTC, &tioltc) < 0)
! 266: {
! 267: packet_put_char(TTY_OP_END);
! 268: log("ioctl(fd, TIOCGLTC, ...): %.100s", strerror(errno));
! 269: return;
! 270: }
! 271: #ifdef TIOCGSTAT
! 272: if (ioctl(fd, TIOCGSTAT, &tiots) < 0)
! 273: {
! 274: packet_put_char(TTY_OP_END);
! 275: log("ioctl(fd, TIOCGSTAT, ...): %.100s", strerror(errno));
! 276: return;
! 277: }
! 278: #endif /* TIOCGSTAT */
! 279: #endif /* USING_SGTTY */
! 280:
! 281: /* Store input and output baud rates. */
! 282: baud = speed_to_baud(cfgetospeed(&tio));
! 283: packet_put_char(TTY_OP_OSPEED);
! 284: packet_put_int(baud);
! 285: baud = speed_to_baud(cfgetispeed(&tio));
! 286: packet_put_char(TTY_OP_ISPEED);
! 287: packet_put_int(baud);
! 288:
! 289: /* Store values of mode flags. */
! 290: #ifdef USING_TERMIOS
! 291: #define TTYCHAR(NAME, OP) \
! 292: packet_put_char(OP); packet_put_char(tio.c_cc[NAME]);
! 293: #define TTYMODE(NAME, FIELD, OP) \
! 294: packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0);
! 295: #define SGTTYCHAR(NAME, OP)
! 296: #define SGTTYMODE(NAME, FIELD, OP)
! 297: #define SGTTYMODEN(NAME, FIELD, OP)
! 298: #endif /* USING_TERMIOS */
! 299:
! 300: #ifdef USING_SGTTY
! 301: #define TTYCHAR(NAME, OP)
! 302: #define TTYMODE(NAME, FIELD, OP)
! 303: #define SGTTYCHAR(NAME, OP) \
! 304: packet_put_char(OP); packet_put_char(NAME);
! 305: #define SGTTYMODE(NAME, FIELD, OP) \
! 306: packet_put_char(OP); packet_put_char((FIELD & NAME) != 0);
! 307: #define SGTTYMODEN(NAME, FIELD, OP) \
! 308: packet_put_char(OP); packet_put_char((FIELD & NAME) == 0);
! 309: #endif /* USING_SGTTY */
! 310:
! 311: #include "ttymodes.h"
! 312:
! 313: #undef TTYCHAR
! 314: #undef TTYMODE
! 315: #undef SGTTYCHAR
! 316: #undef SGTTYMODE
! 317: #undef SGTTYMODEN
! 318:
! 319: /* Mark end of mode data. */
! 320: packet_put_char(TTY_OP_END);
! 321: }
! 322:
! 323: /* Decodes terminal modes for the terminal referenced by fd in a portable
! 324: manner from a packet being read. */
! 325:
! 326: void tty_parse_modes(int fd, int *n_bytes_ptr)
! 327: {
! 328: #ifdef USING_TERMIOS
! 329: struct termios tio;
! 330: #endif /* USING_TERMIOS */
! 331: #ifdef USING_SGTTY
! 332: struct sgttyb tio;
! 333: struct tchars tiotc;
! 334: struct ltchars tioltc;
! 335: int tiolm;
! 336: #ifdef TIOCGSTAT
! 337: struct tstatus tiots;
! 338: #endif /* TIOCGSTAT */
! 339: #endif
! 340: int opcode, baud;
! 341: int n_bytes = 0;
! 342: int failure = 0;
! 343:
! 344: /* Get old attributes for the terminal. We will modify these flags.
! 345: I am hoping that if there are any machine-specific modes, they will
! 346: initially have reasonable values. */
! 347: #ifdef USING_TERMIOS
! 348: if (tcgetattr(fd, &tio) < 0)
! 349: failure = -1;
! 350: #endif /* USING_TERMIOS */
! 351: #ifdef USING_SGTTY
! 352: if (ioctl(fd, TIOCGETP, &tio) < 0)
! 353: failure = -1;
! 354: if (ioctl(fd, TIOCGETC, &tiotc) < 0)
! 355: failure = -1;
! 356: if (ioctl(fd, TIOCLGET, &tiolm) < 0)
! 357: failure = -1;
! 358: if (ioctl(fd, TIOCGLTC, &tioltc) < 0)
! 359: failure = -1;
! 360: #ifdef TIOCGSTAT
! 361: if (ioctl(fd, TIOCGSTAT, &tiots) < 0)
! 362: failure = -1;
! 363: #endif /* TIOCGSTAT */
! 364: #endif /* USING_SGTTY */
! 365:
! 366: for (;;)
! 367: {
! 368: n_bytes += 1;
! 369: opcode = packet_get_char();
! 370: switch (opcode)
! 371: {
! 372: case TTY_OP_END:
! 373: goto set;
! 374:
! 375: case TTY_OP_ISPEED:
! 376: n_bytes += 4;
! 377: baud = packet_get_int();
! 378: if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0)
! 379: error("cfsetispeed failed for %d", baud);
! 380: break;
! 381:
! 382: case TTY_OP_OSPEED:
! 383: n_bytes += 4;
! 384: baud = packet_get_int();
! 385: if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0)
! 386: error("cfsetospeed failed for %d", baud);
! 387: break;
! 388:
! 389: #ifdef USING_TERMIOS
! 390: #define TTYCHAR(NAME, OP) \
! 391: case OP: \
! 392: n_bytes += 1; \
! 393: tio.c_cc[NAME] = packet_get_char(); \
! 394: break;
! 395: #define TTYMODE(NAME, FIELD, OP) \
! 396: case OP: \
! 397: n_bytes += 1; \
! 398: if (packet_get_char()) \
! 399: tio.FIELD |= NAME; \
! 400: else \
! 401: tio.FIELD &= ~NAME; \
! 402: break;
! 403: #define SGTTYCHAR(NAME, OP)
! 404: #define SGTTYMODE(NAME, FIELD, OP)
! 405: #define SGTTYMODEN(NAME, FIELD, OP)
! 406: #endif /* USING_TERMIOS */
! 407:
! 408: #ifdef USING_SGTTY
! 409: #define TTYCHAR(NAME, OP)
! 410: #define TTYMODE(NAME, FIELD, OP)
! 411: #define SGTTYCHAR(NAME, OP) \
! 412: case OP: \
! 413: n_bytes += 1; \
! 414: NAME = packet_get_char(); \
! 415: break;
! 416: #define SGTTYMODE(NAME, FIELD, OP) \
! 417: case OP: \
! 418: n_bytes += 1; \
! 419: if (packet_get_char()) \
! 420: FIELD |= NAME; \
! 421: else \
! 422: FIELD &= ~NAME; \
! 423: break;
! 424: #define SGTTYMODEN(NAME, FIELD, OP) \
! 425: case OP: \
! 426: n_bytes += 1; \
! 427: if (packet_get_char()) \
! 428: FIELD &= ~NAME; \
! 429: else \
! 430: FIELD |= NAME; \
! 431: break;
! 432: #endif /* USING_SGTTY */
! 433:
! 434: #include "ttymodes.h"
! 435:
! 436: #undef TTYCHAR
! 437: #undef TTYMODE
! 438: #undef SGTTYCHAR
! 439: #undef SGTTYMODE
! 440: #undef SGTTYMODEN
! 441:
! 442: default:
! 443: debug("Ignoring unsupported tty mode opcode %d (0x%x)",
! 444: opcode, opcode);
! 445: /* Opcodes 0 to 127 are defined to have a one-byte argument. */
! 446: if (opcode >= 0 && opcode < 128)
! 447: {
! 448: n_bytes += 1;
! 449: (void)packet_get_char();
! 450: break;
! 451: }
! 452: else
! 453: {
! 454: /* Opcodes 128 to 159 are defined to have an integer argument. */
! 455: if (opcode >= 128 && opcode < 160)
! 456: {
! 457: n_bytes += 4;
! 458: (void)packet_get_int();
! 459: break;
! 460: }
! 461: }
! 462: /* It is a truly undefined opcode (160 to 255). We have no idea
! 463: about its arguments. So we must stop parsing. Note that some
! 464: data may be left in the packet; hopefully there is nothing more
! 465: coming after the mode data. */
! 466: log("parse_tty_modes: unknown opcode %d", opcode);
! 467: packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
! 468: goto set;
! 469: }
! 470: }
! 471:
! 472: set:
! 473: if (*n_bytes_ptr != n_bytes)
! 474: {
! 475: *n_bytes_ptr = n_bytes;
! 476: return; /* Don't process bytes passed */
! 477: }
! 478:
! 479: if (failure == -1)
! 480: return; /* Packet parsed ok but tty stuff failed */
! 481:
! 482: /* Set the new modes for the terminal. */
! 483: #ifdef USING_TERMIOS
! 484: if (tcsetattr(fd, TCSANOW, &tio) < 0)
! 485: log("Setting tty modes failed: %.100s", strerror(errno));
! 486: #endif /* USING_TERMIOS */
! 487: #ifdef USING_SGTTY
! 488: if (ioctl(fd, TIOCSETP, &tio) < 0
! 489: || ioctl(fd, TIOCSETC, &tiotc) < 0
! 490: || ioctl(fd, TIOCLSET, &tiolm) < 0
! 491: || ioctl(fd, TIOCSLTC, &tioltc) < 0
! 492: #ifdef TIOCSSTAT
! 493: || ioctl(fd, TIOCSSTAT, &tiots) < 0
! 494: #endif /* TIOCSSTAT */
! 495: )
! 496: log("Setting tty modes failed: %.100s", strerror(errno));
! 497: #endif /* USING_SGTTY */
! 498: return;
! 499: }