xref: /dflybsd-src/crypto/openssh/ttymodes.c (revision 50a69bb51183a7916e776f2c9f5fa64c999f1a2f)
1*50a69bb5SSascha Wildner /* $OpenBSD: ttymodes.c,v 1.36 2021/01/27 09:26:54 djm Exp $ */
218de8d7fSPeter Avalos /*
318de8d7fSPeter Avalos  * Author: Tatu Ylonen <ylo@cs.hut.fi>
418de8d7fSPeter Avalos  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
518de8d7fSPeter Avalos  *                    All rights reserved
618de8d7fSPeter Avalos  *
718de8d7fSPeter Avalos  * As far as I am concerned, the code I have written for this software
818de8d7fSPeter Avalos  * can be used freely for any purpose.  Any derived versions of this
918de8d7fSPeter Avalos  * software must be clearly marked as such, and if the derived work is
1018de8d7fSPeter Avalos  * incompatible with the protocol description in the RFC file, it must be
1118de8d7fSPeter Avalos  * called by a name other than "ssh" or "Secure Shell".
1218de8d7fSPeter Avalos  */
1318de8d7fSPeter Avalos 
1418de8d7fSPeter Avalos /*
1518de8d7fSPeter Avalos  * SSH2 tty modes support by Kevin Steves.
1618de8d7fSPeter Avalos  * Copyright (c) 2001 Kevin Steves.  All rights reserved.
1718de8d7fSPeter Avalos  *
1818de8d7fSPeter Avalos  * Redistribution and use in source and binary forms, with or without
1918de8d7fSPeter Avalos  * modification, are permitted provided that the following conditions
2018de8d7fSPeter Avalos  * are met:
2118de8d7fSPeter Avalos  * 1. Redistributions of source code must retain the above copyright
2218de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer.
2318de8d7fSPeter Avalos  * 2. Redistributions in binary form must reproduce the above copyright
2418de8d7fSPeter Avalos  *    notice, this list of conditions and the following disclaimer in the
2518de8d7fSPeter Avalos  *    documentation and/or other materials provided with the distribution.
2618de8d7fSPeter Avalos  *
2718de8d7fSPeter Avalos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2818de8d7fSPeter Avalos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2918de8d7fSPeter Avalos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
3018de8d7fSPeter Avalos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
3118de8d7fSPeter Avalos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
3218de8d7fSPeter Avalos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3318de8d7fSPeter Avalos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3418de8d7fSPeter Avalos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3518de8d7fSPeter Avalos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3618de8d7fSPeter Avalos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3718de8d7fSPeter Avalos  */
3818de8d7fSPeter Avalos 
3918de8d7fSPeter Avalos /*
4018de8d7fSPeter Avalos  * Encoding and decoding of terminal modes in a portable way.
4118de8d7fSPeter Avalos  * Much of the format is defined in ttymodes.h; it is included multiple times
4218de8d7fSPeter Avalos  * into this file with the appropriate macro definitions to generate the
4318de8d7fSPeter Avalos  * suitable code.
4418de8d7fSPeter Avalos  */
4518de8d7fSPeter Avalos 
4618de8d7fSPeter Avalos #include "includes.h"
4718de8d7fSPeter Avalos 
4818de8d7fSPeter Avalos #include <sys/types.h>
4918de8d7fSPeter Avalos 
5018de8d7fSPeter Avalos #include <errno.h>
5118de8d7fSPeter Avalos #include <string.h>
5218de8d7fSPeter Avalos #include <termios.h>
5318de8d7fSPeter Avalos #include <stdarg.h>
5418de8d7fSPeter Avalos 
5518de8d7fSPeter Avalos #include "packet.h"
5618de8d7fSPeter Avalos #include "log.h"
5718de8d7fSPeter Avalos #include "compat.h"
58664f4763Szrj #include "sshbuf.h"
59664f4763Szrj #include "ssherr.h"
6018de8d7fSPeter Avalos 
6118de8d7fSPeter Avalos #define TTY_OP_END		0
6218de8d7fSPeter Avalos /*
63ce74bacaSMatthew Dillon  * uint32 (u_int) follows speed.
6418de8d7fSPeter Avalos  */
65ce74bacaSMatthew Dillon #define TTY_OP_ISPEED	128
66ce74bacaSMatthew Dillon #define TTY_OP_OSPEED	129
6718de8d7fSPeter Avalos 
6818de8d7fSPeter Avalos /*
6918de8d7fSPeter Avalos  * Converts POSIX speed_t to a baud rate.  The values of the
7018de8d7fSPeter Avalos  * constants for speed_t are not themselves portable.
7118de8d7fSPeter Avalos  */
7218de8d7fSPeter Avalos static int
speed_to_baud(speed_t speed)7318de8d7fSPeter Avalos speed_to_baud(speed_t speed)
7418de8d7fSPeter Avalos {
7518de8d7fSPeter Avalos 	switch (speed) {
7618de8d7fSPeter Avalos 	case B0:
7718de8d7fSPeter Avalos 		return 0;
7818de8d7fSPeter Avalos 	case B50:
7918de8d7fSPeter Avalos 		return 50;
8018de8d7fSPeter Avalos 	case B75:
8118de8d7fSPeter Avalos 		return 75;
8218de8d7fSPeter Avalos 	case B110:
8318de8d7fSPeter Avalos 		return 110;
8418de8d7fSPeter Avalos 	case B134:
8518de8d7fSPeter Avalos 		return 134;
8618de8d7fSPeter Avalos 	case B150:
8718de8d7fSPeter Avalos 		return 150;
8818de8d7fSPeter Avalos 	case B200:
8918de8d7fSPeter Avalos 		return 200;
9018de8d7fSPeter Avalos 	case B300:
9118de8d7fSPeter Avalos 		return 300;
9218de8d7fSPeter Avalos 	case B600:
9318de8d7fSPeter Avalos 		return 600;
9418de8d7fSPeter Avalos 	case B1200:
9518de8d7fSPeter Avalos 		return 1200;
9618de8d7fSPeter Avalos 	case B1800:
9718de8d7fSPeter Avalos 		return 1800;
9818de8d7fSPeter Avalos 	case B2400:
9918de8d7fSPeter Avalos 		return 2400;
10018de8d7fSPeter Avalos 	case B4800:
10118de8d7fSPeter Avalos 		return 4800;
10218de8d7fSPeter Avalos 	case B9600:
10318de8d7fSPeter Avalos 		return 9600;
10418de8d7fSPeter Avalos 
10518de8d7fSPeter Avalos #ifdef B19200
10618de8d7fSPeter Avalos 	case B19200:
10718de8d7fSPeter Avalos 		return 19200;
10818de8d7fSPeter Avalos #else /* B19200 */
10918de8d7fSPeter Avalos #ifdef EXTA
11018de8d7fSPeter Avalos 	case EXTA:
11118de8d7fSPeter Avalos 		return 19200;
11218de8d7fSPeter Avalos #endif /* EXTA */
11318de8d7fSPeter Avalos #endif /* B19200 */
11418de8d7fSPeter Avalos 
11518de8d7fSPeter Avalos #ifdef B38400
11618de8d7fSPeter Avalos 	case B38400:
11718de8d7fSPeter Avalos 		return 38400;
11818de8d7fSPeter Avalos #else /* B38400 */
11918de8d7fSPeter Avalos #ifdef EXTB
12018de8d7fSPeter Avalos 	case EXTB:
12118de8d7fSPeter Avalos 		return 38400;
12218de8d7fSPeter Avalos #endif /* EXTB */
12318de8d7fSPeter Avalos #endif /* B38400 */
12418de8d7fSPeter Avalos 
12518de8d7fSPeter Avalos #ifdef B7200
12618de8d7fSPeter Avalos 	case B7200:
12718de8d7fSPeter Avalos 		return 7200;
12818de8d7fSPeter Avalos #endif /* B7200 */
12918de8d7fSPeter Avalos #ifdef B14400
13018de8d7fSPeter Avalos 	case B14400:
13118de8d7fSPeter Avalos 		return 14400;
13218de8d7fSPeter Avalos #endif /* B14400 */
13318de8d7fSPeter Avalos #ifdef B28800
13418de8d7fSPeter Avalos 	case B28800:
13518de8d7fSPeter Avalos 		return 28800;
13618de8d7fSPeter Avalos #endif /* B28800 */
13718de8d7fSPeter Avalos #ifdef B57600
13818de8d7fSPeter Avalos 	case B57600:
13918de8d7fSPeter Avalos 		return 57600;
14018de8d7fSPeter Avalos #endif /* B57600 */
14118de8d7fSPeter Avalos #ifdef B76800
14218de8d7fSPeter Avalos 	case B76800:
14318de8d7fSPeter Avalos 		return 76800;
14418de8d7fSPeter Avalos #endif /* B76800 */
14518de8d7fSPeter Avalos #ifdef B115200
14618de8d7fSPeter Avalos 	case B115200:
14718de8d7fSPeter Avalos 		return 115200;
14818de8d7fSPeter Avalos #endif /* B115200 */
14918de8d7fSPeter Avalos #ifdef B230400
15018de8d7fSPeter Avalos 	case B230400:
15118de8d7fSPeter Avalos 		return 230400;
15218de8d7fSPeter Avalos #endif /* B230400 */
15318de8d7fSPeter Avalos 	default:
15418de8d7fSPeter Avalos 		return 9600;
15518de8d7fSPeter Avalos 	}
15618de8d7fSPeter Avalos }
15718de8d7fSPeter Avalos 
15818de8d7fSPeter Avalos /*
15918de8d7fSPeter Avalos  * Converts a numeric baud rate to a POSIX speed_t.
16018de8d7fSPeter Avalos  */
16118de8d7fSPeter Avalos static speed_t
baud_to_speed(int baud)16218de8d7fSPeter Avalos baud_to_speed(int baud)
16318de8d7fSPeter Avalos {
16418de8d7fSPeter Avalos 	switch (baud) {
16518de8d7fSPeter Avalos 	case 0:
16618de8d7fSPeter Avalos 		return B0;
16718de8d7fSPeter Avalos 	case 50:
16818de8d7fSPeter Avalos 		return B50;
16918de8d7fSPeter Avalos 	case 75:
17018de8d7fSPeter Avalos 		return B75;
17118de8d7fSPeter Avalos 	case 110:
17218de8d7fSPeter Avalos 		return B110;
17318de8d7fSPeter Avalos 	case 134:
17418de8d7fSPeter Avalos 		return B134;
17518de8d7fSPeter Avalos 	case 150:
17618de8d7fSPeter Avalos 		return B150;
17718de8d7fSPeter Avalos 	case 200:
17818de8d7fSPeter Avalos 		return B200;
17918de8d7fSPeter Avalos 	case 300:
18018de8d7fSPeter Avalos 		return B300;
18118de8d7fSPeter Avalos 	case 600:
18218de8d7fSPeter Avalos 		return B600;
18318de8d7fSPeter Avalos 	case 1200:
18418de8d7fSPeter Avalos 		return B1200;
18518de8d7fSPeter Avalos 	case 1800:
18618de8d7fSPeter Avalos 		return B1800;
18718de8d7fSPeter Avalos 	case 2400:
18818de8d7fSPeter Avalos 		return B2400;
18918de8d7fSPeter Avalos 	case 4800:
19018de8d7fSPeter Avalos 		return B4800;
19118de8d7fSPeter Avalos 	case 9600:
19218de8d7fSPeter Avalos 		return B9600;
19318de8d7fSPeter Avalos 
19418de8d7fSPeter Avalos #ifdef B19200
19518de8d7fSPeter Avalos 	case 19200:
19618de8d7fSPeter Avalos 		return B19200;
19718de8d7fSPeter Avalos #else /* B19200 */
19818de8d7fSPeter Avalos #ifdef EXTA
19918de8d7fSPeter Avalos 	case 19200:
20018de8d7fSPeter Avalos 		return EXTA;
20118de8d7fSPeter Avalos #endif /* EXTA */
20218de8d7fSPeter Avalos #endif /* B19200 */
20318de8d7fSPeter Avalos 
20418de8d7fSPeter Avalos #ifdef B38400
20518de8d7fSPeter Avalos 	case 38400:
20618de8d7fSPeter Avalos 		return B38400;
20718de8d7fSPeter Avalos #else /* B38400 */
20818de8d7fSPeter Avalos #ifdef EXTB
20918de8d7fSPeter Avalos 	case 38400:
21018de8d7fSPeter Avalos 		return EXTB;
21118de8d7fSPeter Avalos #endif /* EXTB */
21218de8d7fSPeter Avalos #endif /* B38400 */
21318de8d7fSPeter Avalos 
21418de8d7fSPeter Avalos #ifdef B7200
21518de8d7fSPeter Avalos 	case 7200:
21618de8d7fSPeter Avalos 		return B7200;
21718de8d7fSPeter Avalos #endif /* B7200 */
21818de8d7fSPeter Avalos #ifdef B14400
21918de8d7fSPeter Avalos 	case 14400:
22018de8d7fSPeter Avalos 		return B14400;
22118de8d7fSPeter Avalos #endif /* B14400 */
22218de8d7fSPeter Avalos #ifdef B28800
22318de8d7fSPeter Avalos 	case 28800:
22418de8d7fSPeter Avalos 		return B28800;
22518de8d7fSPeter Avalos #endif /* B28800 */
22618de8d7fSPeter Avalos #ifdef B57600
22718de8d7fSPeter Avalos 	case 57600:
22818de8d7fSPeter Avalos 		return B57600;
22918de8d7fSPeter Avalos #endif /* B57600 */
23018de8d7fSPeter Avalos #ifdef B76800
23118de8d7fSPeter Avalos 	case 76800:
23218de8d7fSPeter Avalos 		return B76800;
23318de8d7fSPeter Avalos #endif /* B76800 */
23418de8d7fSPeter Avalos #ifdef B115200
23518de8d7fSPeter Avalos 	case 115200:
23618de8d7fSPeter Avalos 		return B115200;
23718de8d7fSPeter Avalos #endif /* B115200 */
23818de8d7fSPeter Avalos #ifdef B230400
23918de8d7fSPeter Avalos 	case 230400:
24018de8d7fSPeter Avalos 		return B230400;
24118de8d7fSPeter Avalos #endif /* B230400 */
24218de8d7fSPeter Avalos 	default:
24318de8d7fSPeter Avalos 		return B9600;
24418de8d7fSPeter Avalos 	}
24518de8d7fSPeter Avalos }
24618de8d7fSPeter Avalos 
24718de8d7fSPeter Avalos /*
24818de8d7fSPeter Avalos  * Encode a special character into SSH line format.
24918de8d7fSPeter Avalos  */
25018de8d7fSPeter Avalos static u_int
special_char_encode(cc_t c)25118de8d7fSPeter Avalos special_char_encode(cc_t c)
25218de8d7fSPeter Avalos {
25318de8d7fSPeter Avalos #ifdef _POSIX_VDISABLE
25418de8d7fSPeter Avalos 	if (c == _POSIX_VDISABLE)
25518de8d7fSPeter Avalos 		return 255;
25618de8d7fSPeter Avalos #endif /* _POSIX_VDISABLE */
25718de8d7fSPeter Avalos 	return c;
25818de8d7fSPeter Avalos }
25918de8d7fSPeter Avalos 
26018de8d7fSPeter Avalos /*
26118de8d7fSPeter Avalos  * Decode a special character from SSH line format.
26218de8d7fSPeter Avalos  */
26318de8d7fSPeter Avalos static cc_t
special_char_decode(u_int c)26418de8d7fSPeter Avalos special_char_decode(u_int c)
26518de8d7fSPeter Avalos {
26618de8d7fSPeter Avalos #ifdef _POSIX_VDISABLE
26718de8d7fSPeter Avalos 	if (c == 255)
26818de8d7fSPeter Avalos 		return _POSIX_VDISABLE;
26918de8d7fSPeter Avalos #endif /* _POSIX_VDISABLE */
27018de8d7fSPeter Avalos 	return c;
27118de8d7fSPeter Avalos }
27218de8d7fSPeter Avalos 
27318de8d7fSPeter Avalos /*
27418de8d7fSPeter Avalos  * Encodes terminal modes for the terminal referenced by fd
27518de8d7fSPeter Avalos  * or tiop in a portable manner, and appends the modes to a packet
27618de8d7fSPeter Avalos  * being constructed.
27718de8d7fSPeter Avalos  */
27818de8d7fSPeter Avalos void
ssh_tty_make_modes(struct ssh * ssh,int fd,struct termios * tiop)279664f4763Szrj ssh_tty_make_modes(struct ssh *ssh, int fd, struct termios *tiop)
28018de8d7fSPeter Avalos {
28118de8d7fSPeter Avalos 	struct termios tio;
282664f4763Szrj 	struct sshbuf *buf;
283664f4763Szrj 	int r, ibaud, obaud;
28418de8d7fSPeter Avalos 
285664f4763Szrj 	if ((buf = sshbuf_new()) == NULL)
286*50a69bb5SSascha Wildner 		fatal_f("sshbuf_new failed");
28718de8d7fSPeter Avalos 
28818de8d7fSPeter Avalos 	if (tiop == NULL) {
28918de8d7fSPeter Avalos 		if (fd == -1) {
290*50a69bb5SSascha Wildner 			debug_f("no fd or tio");
29118de8d7fSPeter Avalos 			goto end;
29218de8d7fSPeter Avalos 		}
29318de8d7fSPeter Avalos 		if (tcgetattr(fd, &tio) == -1) {
29418de8d7fSPeter Avalos 			logit("tcgetattr: %.100s", strerror(errno));
29518de8d7fSPeter Avalos 			goto end;
29618de8d7fSPeter Avalos 		}
29718de8d7fSPeter Avalos 	} else
29818de8d7fSPeter Avalos 		tio = *tiop;
29918de8d7fSPeter Avalos 
30018de8d7fSPeter Avalos 	/* Store input and output baud rates. */
301664f4763Szrj 	obaud = speed_to_baud(cfgetospeed(&tio));
302664f4763Szrj 	ibaud = speed_to_baud(cfgetispeed(&tio));
303664f4763Szrj 	if ((r = sshbuf_put_u8(buf, TTY_OP_OSPEED)) != 0 ||
304664f4763Szrj 	    (r = sshbuf_put_u32(buf, obaud)) != 0 ||
305664f4763Szrj 	    (r = sshbuf_put_u8(buf, TTY_OP_ISPEED)) != 0 ||
306664f4763Szrj 	    (r = sshbuf_put_u32(buf, ibaud)) != 0)
307*50a69bb5SSascha Wildner 		fatal_fr(r, "compose");
30818de8d7fSPeter Avalos 
30918de8d7fSPeter Avalos 	/* Store values of mode flags. */
31018de8d7fSPeter Avalos #define TTYCHAR(NAME, OP) \
311664f4763Szrj 	if ((r = sshbuf_put_u8(buf, OP)) != 0 || \
312664f4763Szrj 	    (r = sshbuf_put_u32(buf, \
313664f4763Szrj 	    special_char_encode(tio.c_cc[NAME]))) != 0) \
314*50a69bb5SSascha Wildner 		fatal_fr(r, "compose %s", #NAME);
315664f4763Szrj 
316664f4763Szrj #define SSH_TTYMODE_IUTF8 42  /* for SSH_BUG_UTF8TTYMODE */
31718de8d7fSPeter Avalos 
31818de8d7fSPeter Avalos #define TTYMODE(NAME, FIELD, OP) \
319*50a69bb5SSascha Wildner 	if (OP == SSH_TTYMODE_IUTF8 && (ssh->compat & SSH_BUG_UTF8TTYMODE)) { \
320*50a69bb5SSascha Wildner 		debug3_f("SSH_BUG_UTF8TTYMODE"); \
321664f4763Szrj 	} else if ((r = sshbuf_put_u8(buf, OP)) != 0 || \
322664f4763Szrj 	    (r = sshbuf_put_u32(buf, ((tio.FIELD & NAME) != 0))) != 0) \
323*50a69bb5SSascha Wildner 		fatal_fr(r, "compose %s", #NAME);
32418de8d7fSPeter Avalos 
32518de8d7fSPeter Avalos #include "ttymodes.h"
32618de8d7fSPeter Avalos 
32718de8d7fSPeter Avalos #undef TTYCHAR
32818de8d7fSPeter Avalos #undef TTYMODE
32918de8d7fSPeter Avalos 
33018de8d7fSPeter Avalos end:
33118de8d7fSPeter Avalos 	/* Mark end of mode data. */
332664f4763Szrj 	if ((r = sshbuf_put_u8(buf, TTY_OP_END)) != 0 ||
333664f4763Szrj 	    (r = sshpkt_put_stringb(ssh, buf)) != 0)
334*50a69bb5SSascha Wildner 		fatal_fr(r, "compose end");
335664f4763Szrj 	sshbuf_free(buf);
33618de8d7fSPeter Avalos }
33718de8d7fSPeter Avalos 
33818de8d7fSPeter Avalos /*
33918de8d7fSPeter Avalos  * Decodes terminal modes for the terminal referenced by fd in a portable
34018de8d7fSPeter Avalos  * manner from a packet being read.
34118de8d7fSPeter Avalos  */
34218de8d7fSPeter Avalos void
ssh_tty_parse_modes(struct ssh * ssh,int fd)343664f4763Szrj ssh_tty_parse_modes(struct ssh *ssh, int fd)
34418de8d7fSPeter Avalos {
34518de8d7fSPeter Avalos 	struct termios tio;
346664f4763Szrj 	struct sshbuf *buf;
347664f4763Szrj 	const u_char *data;
348664f4763Szrj 	u_char opcode;
349664f4763Szrj 	u_int baud, u;
350664f4763Szrj 	int r, failure = 0;
351664f4763Szrj 	size_t len;
35218de8d7fSPeter Avalos 
353664f4763Szrj 	if ((r = sshpkt_get_string_direct(ssh, &data, &len)) != 0)
354*50a69bb5SSascha Wildner 		fatal_fr(r, "parse");
355664f4763Szrj 	if (len == 0)
35618de8d7fSPeter Avalos 		return;
357664f4763Szrj 	if ((buf = sshbuf_from(data, len)) == NULL) {
358*50a69bb5SSascha Wildner 		error_f("sshbuf_from failed");
359664f4763Szrj 		return;
360664f4763Szrj 	}
36118de8d7fSPeter Avalos 
36218de8d7fSPeter Avalos 	/*
36318de8d7fSPeter Avalos 	 * Get old attributes for the terminal.  We will modify these
36418de8d7fSPeter Avalos 	 * flags. I am hoping that if there are any machine-specific
36518de8d7fSPeter Avalos 	 * modes, they will initially have reasonable values.
36618de8d7fSPeter Avalos 	 */
36718de8d7fSPeter Avalos 	if (tcgetattr(fd, &tio) == -1) {
36818de8d7fSPeter Avalos 		logit("tcgetattr: %.100s", strerror(errno));
36918de8d7fSPeter Avalos 		failure = -1;
37018de8d7fSPeter Avalos 	}
37118de8d7fSPeter Avalos 
372664f4763Szrj 	while (sshbuf_len(buf) > 0) {
373664f4763Szrj 		if ((r = sshbuf_get_u8(buf, &opcode)) != 0)
374*50a69bb5SSascha Wildner 			fatal_fr(r, "parse opcode");
37518de8d7fSPeter Avalos 		switch (opcode) {
37618de8d7fSPeter Avalos 		case TTY_OP_END:
37718de8d7fSPeter Avalos 			goto set;
37818de8d7fSPeter Avalos 
379ce74bacaSMatthew Dillon 		case TTY_OP_ISPEED:
380664f4763Szrj 			if ((r = sshbuf_get_u32(buf, &baud)) != 0)
381*50a69bb5SSascha Wildner 				fatal_fr(r, "parse ispeed");
38218de8d7fSPeter Avalos 			if (failure != -1 &&
38318de8d7fSPeter Avalos 			    cfsetispeed(&tio, baud_to_speed(baud)) == -1)
38418de8d7fSPeter Avalos 				error("cfsetispeed failed for %d", baud);
38518de8d7fSPeter Avalos 			break;
38618de8d7fSPeter Avalos 
387ce74bacaSMatthew Dillon 		case TTY_OP_OSPEED:
388664f4763Szrj 			if ((r = sshbuf_get_u32(buf, &baud)) != 0)
389*50a69bb5SSascha Wildner 				fatal_fr(r, "parse ospeed");
39018de8d7fSPeter Avalos 			if (failure != -1 &&
39118de8d7fSPeter Avalos 			    cfsetospeed(&tio, baud_to_speed(baud)) == -1)
39218de8d7fSPeter Avalos 				error("cfsetospeed failed for %d", baud);
39318de8d7fSPeter Avalos 			break;
39418de8d7fSPeter Avalos 
39518de8d7fSPeter Avalos #define TTYCHAR(NAME, OP) \
39618de8d7fSPeter Avalos 		case OP: \
397664f4763Szrj 			if ((r = sshbuf_get_u32(buf, &u)) != 0) \
398*50a69bb5SSascha Wildner 				fatal_fr(r, "parse %s", #NAME); \
399664f4763Szrj 			tio.c_cc[NAME] = special_char_decode(u); \
40018de8d7fSPeter Avalos 			break;
40118de8d7fSPeter Avalos #define TTYMODE(NAME, FIELD, OP) \
40218de8d7fSPeter Avalos 		case OP: \
403664f4763Szrj 			if ((r = sshbuf_get_u32(buf, &u)) != 0) \
404*50a69bb5SSascha Wildner 				fatal_fr(r, "parse %s", #NAME); \
405664f4763Szrj 			if (u) \
40618de8d7fSPeter Avalos 				tio.FIELD |= NAME; \
40718de8d7fSPeter Avalos 			else \
40818de8d7fSPeter Avalos 				tio.FIELD &= ~NAME; \
40918de8d7fSPeter Avalos 			break;
41018de8d7fSPeter Avalos 
41118de8d7fSPeter Avalos #include "ttymodes.h"
41218de8d7fSPeter Avalos 
41318de8d7fSPeter Avalos #undef TTYCHAR
41418de8d7fSPeter Avalos #undef TTYMODE
41518de8d7fSPeter Avalos 
41618de8d7fSPeter Avalos 		default:
41718de8d7fSPeter Avalos 			debug("Ignoring unsupported tty mode opcode %d (0x%x)",
41818de8d7fSPeter Avalos 			    opcode, opcode);
41918de8d7fSPeter Avalos 			/*
42018de8d7fSPeter Avalos 			 * SSH2:
421ce74bacaSMatthew Dillon 			 * Opcodes 1 to 159 are defined to have a uint32
422ce74bacaSMatthew Dillon 			 * argument.
423ce74bacaSMatthew Dillon 			 * Opcodes 160 to 255 are undefined and cause parsing
424ce74bacaSMatthew Dillon 			 * to stop.
42518de8d7fSPeter Avalos 			 */
42618de8d7fSPeter Avalos 			if (opcode > 0 && opcode < 160) {
427664f4763Szrj 				if ((r = sshbuf_get_u32(buf, NULL)) != 0)
428*50a69bb5SSascha Wildner 					fatal_fr(r, "parse arg");
42918de8d7fSPeter Avalos 				break;
43018de8d7fSPeter Avalos 			} else {
431*50a69bb5SSascha Wildner 				logit_f("unknown opcode %d", opcode);
43218de8d7fSPeter Avalos 				goto set;
43318de8d7fSPeter Avalos 			}
43418de8d7fSPeter Avalos 		}
43518de8d7fSPeter Avalos 	}
43618de8d7fSPeter Avalos 
43718de8d7fSPeter Avalos set:
438664f4763Szrj 	len = sshbuf_len(buf);
439664f4763Szrj 	sshbuf_free(buf);
440664f4763Szrj 	if (len > 0) {
441*50a69bb5SSascha Wildner 		logit_f("%zu bytes left", len);
44218de8d7fSPeter Avalos 		return;		/* Don't process bytes passed */
44318de8d7fSPeter Avalos 	}
44418de8d7fSPeter Avalos 	if (failure == -1)
44518de8d7fSPeter Avalos 		return;		/* Packet parsed ok but tcgetattr() failed */
44618de8d7fSPeter Avalos 
44718de8d7fSPeter Avalos 	/* Set the new modes for the terminal. */
44818de8d7fSPeter Avalos 	if (tcsetattr(fd, TCSANOW, &tio) == -1)
44918de8d7fSPeter Avalos 		logit("Setting tty modes failed: %.100s", strerror(errno));
45018de8d7fSPeter Avalos }
451