xref: /freebsd/crypto/openssh/ttymodes.c (revision 190cef3d52236565eb22e18b33e9e865ec634aa3)
1*190cef3dSDag-Erling Smørgrav /* $OpenBSD: ttymodes.c,v 1.34 2018/07/09 21:20:26 markus Exp $ */
2511b41d2SMark Murray /*
3511b41d2SMark Murray  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4511b41d2SMark Murray  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5511b41d2SMark Murray  *                    All rights reserved
6b66f2d16SKris Kennaway  *
7b66f2d16SKris Kennaway  * As far as I am concerned, the code I have written for this software
8b66f2d16SKris Kennaway  * can be used freely for any purpose.  Any derived versions of this
9b66f2d16SKris Kennaway  * software must be clearly marked as such, and if the derived work is
10b66f2d16SKris Kennaway  * incompatible with the protocol description in the RFC file, it must be
11b66f2d16SKris Kennaway  * called by a name other than "ssh" or "Secure Shell".
12511b41d2SMark Murray  */
13511b41d2SMark Murray 
141e8db6e2SBrian Feldman /*
151e8db6e2SBrian Feldman  * SSH2 tty modes support by Kevin Steves.
161e8db6e2SBrian Feldman  * Copyright (c) 2001 Kevin Steves.  All rights reserved.
171e8db6e2SBrian Feldman  *
181e8db6e2SBrian Feldman  * Redistribution and use in source and binary forms, with or without
191e8db6e2SBrian Feldman  * modification, are permitted provided that the following conditions
201e8db6e2SBrian Feldman  * are met:
211e8db6e2SBrian Feldman  * 1. Redistributions of source code must retain the above copyright
221e8db6e2SBrian Feldman  *    notice, this list of conditions and the following disclaimer.
231e8db6e2SBrian Feldman  * 2. Redistributions in binary form must reproduce the above copyright
241e8db6e2SBrian Feldman  *    notice, this list of conditions and the following disclaimer in the
251e8db6e2SBrian Feldman  *    documentation and/or other materials provided with the distribution.
261e8db6e2SBrian Feldman  *
271e8db6e2SBrian Feldman  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
281e8db6e2SBrian Feldman  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
291e8db6e2SBrian Feldman  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
301e8db6e2SBrian Feldman  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
311e8db6e2SBrian Feldman  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
321e8db6e2SBrian Feldman  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
331e8db6e2SBrian Feldman  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
341e8db6e2SBrian Feldman  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
351e8db6e2SBrian Feldman  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
361e8db6e2SBrian Feldman  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
371e8db6e2SBrian Feldman  */
381e8db6e2SBrian Feldman 
391e8db6e2SBrian Feldman /*
401e8db6e2SBrian Feldman  * Encoding and decoding of terminal modes in a portable way.
411e8db6e2SBrian Feldman  * Much of the format is defined in ttymodes.h; it is included multiple times
421e8db6e2SBrian Feldman  * into this file with the appropriate macro definitions to generate the
431e8db6e2SBrian Feldman  * suitable code.
441e8db6e2SBrian Feldman  */
451e8db6e2SBrian Feldman 
46511b41d2SMark Murray #include "includes.h"
47761efaa7SDag-Erling Smørgrav 
48761efaa7SDag-Erling Smørgrav #include <sys/types.h>
49761efaa7SDag-Erling Smørgrav 
50761efaa7SDag-Erling Smørgrav #include <errno.h>
51761efaa7SDag-Erling Smørgrav #include <string.h>
52761efaa7SDag-Erling Smørgrav #include <termios.h>
53761efaa7SDag-Erling Smørgrav #include <stdarg.h>
54511b41d2SMark Murray 
55511b41d2SMark Murray #include "packet.h"
561e8db6e2SBrian Feldman #include "log.h"
571e8db6e2SBrian Feldman #include "compat.h"
58*190cef3dSDag-Erling Smørgrav #include "sshbuf.h"
59*190cef3dSDag-Erling Smørgrav #include "ssherr.h"
60511b41d2SMark Murray 
61511b41d2SMark Murray #define TTY_OP_END		0
621e8db6e2SBrian Feldman /*
634f52dfbbSDag-Erling Smørgrav  * uint32 (u_int) follows speed.
641e8db6e2SBrian Feldman  */
654f52dfbbSDag-Erling Smørgrav #define TTY_OP_ISPEED	128
664f52dfbbSDag-Erling Smørgrav #define TTY_OP_OSPEED	129
67511b41d2SMark Murray 
68511b41d2SMark Murray /*
69511b41d2SMark Murray  * Converts POSIX speed_t to a baud rate.  The values of the
70511b41d2SMark Murray  * constants for speed_t are not themselves portable.
71511b41d2SMark Murray  */
72511b41d2SMark Murray static int
73511b41d2SMark Murray speed_to_baud(speed_t speed)
74511b41d2SMark Murray {
75511b41d2SMark Murray 	switch (speed) {
76511b41d2SMark Murray 	case B0:
77511b41d2SMark Murray 		return 0;
78511b41d2SMark Murray 	case B50:
79511b41d2SMark Murray 		return 50;
80511b41d2SMark Murray 	case B75:
81511b41d2SMark Murray 		return 75;
82511b41d2SMark Murray 	case B110:
83511b41d2SMark Murray 		return 110;
84511b41d2SMark Murray 	case B134:
85511b41d2SMark Murray 		return 134;
86511b41d2SMark Murray 	case B150:
87511b41d2SMark Murray 		return 150;
88511b41d2SMark Murray 	case B200:
89511b41d2SMark Murray 		return 200;
90511b41d2SMark Murray 	case B300:
91511b41d2SMark Murray 		return 300;
92511b41d2SMark Murray 	case B600:
93511b41d2SMark Murray 		return 600;
94511b41d2SMark Murray 	case B1200:
95511b41d2SMark Murray 		return 1200;
96511b41d2SMark Murray 	case B1800:
97511b41d2SMark Murray 		return 1800;
98511b41d2SMark Murray 	case B2400:
99511b41d2SMark Murray 		return 2400;
100511b41d2SMark Murray 	case B4800:
101511b41d2SMark Murray 		return 4800;
102511b41d2SMark Murray 	case B9600:
103511b41d2SMark Murray 		return 9600;
104511b41d2SMark Murray 
105511b41d2SMark Murray #ifdef B19200
106511b41d2SMark Murray 	case B19200:
107511b41d2SMark Murray 		return 19200;
108511b41d2SMark Murray #else /* B19200 */
109511b41d2SMark Murray #ifdef EXTA
110511b41d2SMark Murray 	case EXTA:
111511b41d2SMark Murray 		return 19200;
112511b41d2SMark Murray #endif /* EXTA */
113511b41d2SMark Murray #endif /* B19200 */
114511b41d2SMark Murray 
115511b41d2SMark Murray #ifdef B38400
116511b41d2SMark Murray 	case B38400:
117511b41d2SMark Murray 		return 38400;
118511b41d2SMark Murray #else /* B38400 */
119511b41d2SMark Murray #ifdef EXTB
120511b41d2SMark Murray 	case EXTB:
121511b41d2SMark Murray 		return 38400;
122511b41d2SMark Murray #endif /* EXTB */
123511b41d2SMark Murray #endif /* B38400 */
124511b41d2SMark Murray 
125511b41d2SMark Murray #ifdef B7200
126511b41d2SMark Murray 	case B7200:
127511b41d2SMark Murray 		return 7200;
128511b41d2SMark Murray #endif /* B7200 */
129511b41d2SMark Murray #ifdef B14400
130511b41d2SMark Murray 	case B14400:
131511b41d2SMark Murray 		return 14400;
132511b41d2SMark Murray #endif /* B14400 */
133511b41d2SMark Murray #ifdef B28800
134511b41d2SMark Murray 	case B28800:
135511b41d2SMark Murray 		return 28800;
136511b41d2SMark Murray #endif /* B28800 */
137511b41d2SMark Murray #ifdef B57600
138511b41d2SMark Murray 	case B57600:
139511b41d2SMark Murray 		return 57600;
140511b41d2SMark Murray #endif /* B57600 */
141511b41d2SMark Murray #ifdef B76800
142511b41d2SMark Murray 	case B76800:
143511b41d2SMark Murray 		return 76800;
144511b41d2SMark Murray #endif /* B76800 */
145511b41d2SMark Murray #ifdef B115200
146511b41d2SMark Murray 	case B115200:
147511b41d2SMark Murray 		return 115200;
148511b41d2SMark Murray #endif /* B115200 */
149511b41d2SMark Murray #ifdef B230400
150511b41d2SMark Murray 	case B230400:
151511b41d2SMark Murray 		return 230400;
152511b41d2SMark Murray #endif /* B230400 */
153511b41d2SMark Murray 	default:
154511b41d2SMark Murray 		return 9600;
155511b41d2SMark Murray 	}
156511b41d2SMark Murray }
157511b41d2SMark Murray 
158511b41d2SMark Murray /*
159511b41d2SMark Murray  * Converts a numeric baud rate to a POSIX speed_t.
160511b41d2SMark Murray  */
161511b41d2SMark Murray static speed_t
162511b41d2SMark Murray baud_to_speed(int baud)
163511b41d2SMark Murray {
164511b41d2SMark Murray 	switch (baud) {
165511b41d2SMark Murray 	case 0:
166511b41d2SMark Murray 		return B0;
167511b41d2SMark Murray 	case 50:
168511b41d2SMark Murray 		return B50;
169511b41d2SMark Murray 	case 75:
170511b41d2SMark Murray 		return B75;
171511b41d2SMark Murray 	case 110:
172511b41d2SMark Murray 		return B110;
173511b41d2SMark Murray 	case 134:
174511b41d2SMark Murray 		return B134;
175511b41d2SMark Murray 	case 150:
176511b41d2SMark Murray 		return B150;
177511b41d2SMark Murray 	case 200:
178511b41d2SMark Murray 		return B200;
179511b41d2SMark Murray 	case 300:
180511b41d2SMark Murray 		return B300;
181511b41d2SMark Murray 	case 600:
182511b41d2SMark Murray 		return B600;
183511b41d2SMark Murray 	case 1200:
184511b41d2SMark Murray 		return B1200;
185511b41d2SMark Murray 	case 1800:
186511b41d2SMark Murray 		return B1800;
187511b41d2SMark Murray 	case 2400:
188511b41d2SMark Murray 		return B2400;
189511b41d2SMark Murray 	case 4800:
190511b41d2SMark Murray 		return B4800;
191511b41d2SMark Murray 	case 9600:
192511b41d2SMark Murray 		return B9600;
193511b41d2SMark Murray 
194511b41d2SMark Murray #ifdef B19200
195511b41d2SMark Murray 	case 19200:
196511b41d2SMark Murray 		return B19200;
197511b41d2SMark Murray #else /* B19200 */
198511b41d2SMark Murray #ifdef EXTA
199511b41d2SMark Murray 	case 19200:
200511b41d2SMark Murray 		return EXTA;
201511b41d2SMark Murray #endif /* EXTA */
202511b41d2SMark Murray #endif /* B19200 */
203511b41d2SMark Murray 
204511b41d2SMark Murray #ifdef B38400
205511b41d2SMark Murray 	case 38400:
206511b41d2SMark Murray 		return B38400;
207511b41d2SMark Murray #else /* B38400 */
208511b41d2SMark Murray #ifdef EXTB
209511b41d2SMark Murray 	case 38400:
210511b41d2SMark Murray 		return EXTB;
211511b41d2SMark Murray #endif /* EXTB */
212511b41d2SMark Murray #endif /* B38400 */
213511b41d2SMark Murray 
214511b41d2SMark Murray #ifdef B7200
215511b41d2SMark Murray 	case 7200:
216511b41d2SMark Murray 		return B7200;
217511b41d2SMark Murray #endif /* B7200 */
218511b41d2SMark Murray #ifdef B14400
219511b41d2SMark Murray 	case 14400:
220511b41d2SMark Murray 		return B14400;
221511b41d2SMark Murray #endif /* B14400 */
222511b41d2SMark Murray #ifdef B28800
223511b41d2SMark Murray 	case 28800:
224511b41d2SMark Murray 		return B28800;
225511b41d2SMark Murray #endif /* B28800 */
226511b41d2SMark Murray #ifdef B57600
227511b41d2SMark Murray 	case 57600:
228511b41d2SMark Murray 		return B57600;
229511b41d2SMark Murray #endif /* B57600 */
230511b41d2SMark Murray #ifdef B76800
231511b41d2SMark Murray 	case 76800:
232511b41d2SMark Murray 		return B76800;
233511b41d2SMark Murray #endif /* B76800 */
234511b41d2SMark Murray #ifdef B115200
235511b41d2SMark Murray 	case 115200:
236511b41d2SMark Murray 		return B115200;
237511b41d2SMark Murray #endif /* B115200 */
238511b41d2SMark Murray #ifdef B230400
239511b41d2SMark Murray 	case 230400:
240511b41d2SMark Murray 		return B230400;
241511b41d2SMark Murray #endif /* B230400 */
242511b41d2SMark Murray 	default:
243511b41d2SMark Murray 		return B9600;
244511b41d2SMark Murray 	}
245511b41d2SMark Murray }
246511b41d2SMark Murray 
247511b41d2SMark Murray /*
248043840dfSDag-Erling Smørgrav  * Encode a special character into SSH line format.
249043840dfSDag-Erling Smørgrav  */
250043840dfSDag-Erling Smørgrav static u_int
251043840dfSDag-Erling Smørgrav special_char_encode(cc_t c)
252043840dfSDag-Erling Smørgrav {
253043840dfSDag-Erling Smørgrav #ifdef _POSIX_VDISABLE
254043840dfSDag-Erling Smørgrav 	if (c == _POSIX_VDISABLE)
255043840dfSDag-Erling Smørgrav 		return 255;
256043840dfSDag-Erling Smørgrav #endif /* _POSIX_VDISABLE */
257043840dfSDag-Erling Smørgrav 	return c;
258043840dfSDag-Erling Smørgrav }
259043840dfSDag-Erling Smørgrav 
260043840dfSDag-Erling Smørgrav /*
261043840dfSDag-Erling Smørgrav  * Decode a special character from SSH line format.
262043840dfSDag-Erling Smørgrav  */
263043840dfSDag-Erling Smørgrav static cc_t
264043840dfSDag-Erling Smørgrav special_char_decode(u_int c)
265043840dfSDag-Erling Smørgrav {
266043840dfSDag-Erling Smørgrav #ifdef _POSIX_VDISABLE
267043840dfSDag-Erling Smørgrav 	if (c == 255)
268043840dfSDag-Erling Smørgrav 		return _POSIX_VDISABLE;
269043840dfSDag-Erling Smørgrav #endif /* _POSIX_VDISABLE */
270043840dfSDag-Erling Smørgrav 	return c;
271043840dfSDag-Erling Smørgrav }
272043840dfSDag-Erling Smørgrav 
273043840dfSDag-Erling Smørgrav /*
274511b41d2SMark Murray  * Encodes terminal modes for the terminal referenced by fd
2751e8db6e2SBrian Feldman  * or tiop in a portable manner, and appends the modes to a packet
276511b41d2SMark Murray  * being constructed.
277511b41d2SMark Murray  */
278511b41d2SMark Murray void
279*190cef3dSDag-Erling Smørgrav ssh_tty_make_modes(struct ssh *ssh, int fd, struct termios *tiop)
280511b41d2SMark Murray {
281511b41d2SMark Murray 	struct termios tio;
282*190cef3dSDag-Erling Smørgrav 	struct sshbuf *buf;
283*190cef3dSDag-Erling Smørgrav 	int r, ibaud, obaud;
284511b41d2SMark Murray 
285*190cef3dSDag-Erling Smørgrav 	if ((buf = sshbuf_new()) == NULL)
286*190cef3dSDag-Erling Smørgrav 		fatal("%s: sshbuf_new failed", __func__);
2871e8db6e2SBrian Feldman 
2881e8db6e2SBrian Feldman 	if (tiop == NULL) {
289d4af9e69SDag-Erling Smørgrav 		if (fd == -1) {
290*190cef3dSDag-Erling Smørgrav 			debug("%s: no fd or tio", __func__);
291d4af9e69SDag-Erling Smørgrav 			goto end;
292d4af9e69SDag-Erling Smørgrav 		}
2931e8db6e2SBrian Feldman 		if (tcgetattr(fd, &tio) == -1) {
294d95e11bfSDag-Erling Smørgrav 			logit("tcgetattr: %.100s", strerror(errno));
2951e8db6e2SBrian Feldman 			goto end;
2961e8db6e2SBrian Feldman 		}
2971e8db6e2SBrian Feldman 	} else
2981e8db6e2SBrian Feldman 		tio = *tiop;
2991e8db6e2SBrian Feldman 
300511b41d2SMark Murray 	/* Store input and output baud rates. */
301*190cef3dSDag-Erling Smørgrav 	obaud = speed_to_baud(cfgetospeed(&tio));
302*190cef3dSDag-Erling Smørgrav 	ibaud = speed_to_baud(cfgetispeed(&tio));
303*190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(buf, TTY_OP_OSPEED)) != 0 ||
304*190cef3dSDag-Erling Smørgrav 	    (r = sshbuf_put_u32(buf, obaud)) != 0 ||
305*190cef3dSDag-Erling Smørgrav 	    (r = sshbuf_put_u8(buf, TTY_OP_ISPEED)) != 0 ||
306*190cef3dSDag-Erling Smørgrav 	    (r = sshbuf_put_u32(buf, ibaud)) != 0)
307*190cef3dSDag-Erling Smørgrav 		fatal("%s: buffer error: %s", __func__, ssh_err(r));
308511b41d2SMark Murray 
309511b41d2SMark Murray 	/* Store values of mode flags. */
310511b41d2SMark Murray #define TTYCHAR(NAME, OP) \
311*190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(buf, OP)) != 0 || \
312*190cef3dSDag-Erling Smørgrav 	    (r = sshbuf_put_u32(buf, \
313*190cef3dSDag-Erling Smørgrav 	    special_char_encode(tio.c_cc[NAME]))) != 0) \
314*190cef3dSDag-Erling Smørgrav 		fatal("%s: buffer error: %s", __func__, ssh_err(r)); \
3151e8db6e2SBrian Feldman 
31647dd1d1bSDag-Erling Smørgrav #define SSH_TTYMODE_IUTF8 42  /* for SSH_BUG_UTF8TTYMODE */
31747dd1d1bSDag-Erling Smørgrav 
318511b41d2SMark Murray #define TTYMODE(NAME, FIELD, OP) \
31947dd1d1bSDag-Erling Smørgrav 	if (OP == SSH_TTYMODE_IUTF8 && (datafellows & SSH_BUG_UTF8TTYMODE)) { \
32047dd1d1bSDag-Erling Smørgrav 		debug3("%s: SSH_BUG_UTF8TTYMODE", __func__); \
321*190cef3dSDag-Erling Smørgrav 	} else if ((r = sshbuf_put_u8(buf, OP)) != 0 || \
322*190cef3dSDag-Erling Smørgrav 	    (r = sshbuf_put_u32(buf, ((tio.FIELD & NAME) != 0))) != 0) \
323*190cef3dSDag-Erling Smørgrav 		fatal("%s: buffer error: %s", __func__, ssh_err(r)); \
324511b41d2SMark Murray 
325511b41d2SMark Murray #include "ttymodes.h"
326511b41d2SMark Murray 
327511b41d2SMark Murray #undef TTYCHAR
328511b41d2SMark Murray #undef TTYMODE
329511b41d2SMark Murray 
3301e8db6e2SBrian Feldman end:
331511b41d2SMark Murray 	/* Mark end of mode data. */
332*190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(buf, TTY_OP_END)) != 0 ||
333*190cef3dSDag-Erling Smørgrav 	    (r = sshpkt_put_stringb(ssh, buf)) != 0)
334*190cef3dSDag-Erling Smørgrav 		fatal("%s: packet error: %s", __func__, ssh_err(r));
335*190cef3dSDag-Erling Smørgrav 	sshbuf_free(buf);
336511b41d2SMark Murray }
337511b41d2SMark Murray 
338511b41d2SMark Murray /*
339511b41d2SMark Murray  * Decodes terminal modes for the terminal referenced by fd in a portable
340511b41d2SMark Murray  * manner from a packet being read.
341511b41d2SMark Murray  */
342511b41d2SMark Murray void
343*190cef3dSDag-Erling Smørgrav ssh_tty_parse_modes(struct ssh *ssh, int fd)
344511b41d2SMark Murray {
345511b41d2SMark Murray 	struct termios tio;
346*190cef3dSDag-Erling Smørgrav 	struct sshbuf *buf;
347*190cef3dSDag-Erling Smørgrav 	const u_char *data;
348*190cef3dSDag-Erling Smørgrav 	u_char opcode;
349*190cef3dSDag-Erling Smørgrav 	u_int baud, u;
350*190cef3dSDag-Erling Smørgrav 	int r, failure = 0;
351*190cef3dSDag-Erling Smørgrav 	size_t len;
3521e8db6e2SBrian Feldman 
353*190cef3dSDag-Erling Smørgrav 	if ((r = sshpkt_get_string_direct(ssh, &data, &len)) != 0)
354*190cef3dSDag-Erling Smørgrav 		fatal("%s: packet error: %s", __func__, ssh_err(r));
355*190cef3dSDag-Erling Smørgrav 	if (len == 0)
3561e8db6e2SBrian Feldman 		return;
357*190cef3dSDag-Erling Smørgrav 	if ((buf = sshbuf_from(data, len)) == NULL) {
358*190cef3dSDag-Erling Smørgrav 		error("%s: sshbuf_from failed", __func__);
359*190cef3dSDag-Erling Smørgrav 		return;
360*190cef3dSDag-Erling Smørgrav 	}
361511b41d2SMark Murray 
362511b41d2SMark Murray 	/*
363511b41d2SMark Murray 	 * Get old attributes for the terminal.  We will modify these
364511b41d2SMark Murray 	 * flags. I am hoping that if there are any machine-specific
365511b41d2SMark Murray 	 * modes, they will initially have reasonable values.
366511b41d2SMark Murray 	 */
3671e8db6e2SBrian Feldman 	if (tcgetattr(fd, &tio) == -1) {
368d95e11bfSDag-Erling Smørgrav 		logit("tcgetattr: %.100s", strerror(errno));
369511b41d2SMark Murray 		failure = -1;
3701e8db6e2SBrian Feldman 	}
371511b41d2SMark Murray 
372*190cef3dSDag-Erling Smørgrav 	while (sshbuf_len(buf) > 0) {
373*190cef3dSDag-Erling Smørgrav 		if ((r = sshbuf_get_u8(buf, &opcode)) != 0)
374*190cef3dSDag-Erling Smørgrav 			fatal("%s: packet error: %s", __func__, ssh_err(r));
375511b41d2SMark Murray 		switch (opcode) {
376511b41d2SMark Murray 		case TTY_OP_END:
377511b41d2SMark Murray 			goto set;
378511b41d2SMark Murray 
3794f52dfbbSDag-Erling Smørgrav 		case TTY_OP_ISPEED:
380*190cef3dSDag-Erling Smørgrav 			if ((r = sshbuf_get_u32(buf, &baud)) != 0)
381*190cef3dSDag-Erling Smørgrav 				fatal("%s: packet error: %s",
382*190cef3dSDag-Erling Smørgrav 				    __func__, ssh_err(r));
383761efaa7SDag-Erling Smørgrav 			if (failure != -1 &&
384761efaa7SDag-Erling Smørgrav 			    cfsetispeed(&tio, baud_to_speed(baud)) == -1)
385511b41d2SMark Murray 				error("cfsetispeed failed for %d", baud);
386511b41d2SMark Murray 			break;
387511b41d2SMark Murray 
3884f52dfbbSDag-Erling Smørgrav 		case TTY_OP_OSPEED:
389*190cef3dSDag-Erling Smørgrav 			if ((r = sshbuf_get_u32(buf, &baud)) != 0)
390*190cef3dSDag-Erling Smørgrav 				fatal("%s: packet error: %s",
391*190cef3dSDag-Erling Smørgrav 				    __func__, ssh_err(r));
392761efaa7SDag-Erling Smørgrav 			if (failure != -1 &&
393761efaa7SDag-Erling Smørgrav 			    cfsetospeed(&tio, baud_to_speed(baud)) == -1)
394511b41d2SMark Murray 				error("cfsetospeed failed for %d", baud);
395511b41d2SMark Murray 			break;
396511b41d2SMark Murray 
397511b41d2SMark Murray #define TTYCHAR(NAME, OP) \
398511b41d2SMark Murray 		case OP: \
399*190cef3dSDag-Erling Smørgrav 			if ((r = sshbuf_get_u32(buf, &u)) != 0) \
400*190cef3dSDag-Erling Smørgrav 				fatal("%s: packet error: %s", __func__, \
401*190cef3dSDag-Erling Smørgrav 				    ssh_err(r)); \
402*190cef3dSDag-Erling Smørgrav 			tio.c_cc[NAME] = special_char_decode(u); \
403511b41d2SMark Murray 			break;
404511b41d2SMark Murray #define TTYMODE(NAME, FIELD, OP) \
405511b41d2SMark Murray 		case OP: \
406*190cef3dSDag-Erling Smørgrav 			if ((r = sshbuf_get_u32(buf, &u)) != 0) \
407*190cef3dSDag-Erling Smørgrav 				fatal("%s: packet error: %s", __func__, \
408*190cef3dSDag-Erling Smørgrav 				    ssh_err(r)); \
409*190cef3dSDag-Erling Smørgrav 			if (u) \
410511b41d2SMark Murray 				tio.FIELD |= NAME; \
411511b41d2SMark Murray 			else \
412511b41d2SMark Murray 				tio.FIELD &= ~NAME; \
413511b41d2SMark Murray 			break;
414511b41d2SMark Murray 
415511b41d2SMark Murray #include "ttymodes.h"
416511b41d2SMark Murray 
417511b41d2SMark Murray #undef TTYCHAR
418511b41d2SMark Murray #undef TTYMODE
419511b41d2SMark Murray 
420511b41d2SMark Murray 		default:
421511b41d2SMark Murray 			debug("Ignoring unsupported tty mode opcode %d (0x%x)",
422511b41d2SMark Murray 			    opcode, opcode);
4231e8db6e2SBrian Feldman 			/*
4241e8db6e2SBrian Feldman 			 * SSH2:
4254f52dfbbSDag-Erling Smørgrav 			 * Opcodes 1 to 159 are defined to have a uint32
4264f52dfbbSDag-Erling Smørgrav 			 * argument.
4274f52dfbbSDag-Erling Smørgrav 			 * Opcodes 160 to 255 are undefined and cause parsing
4284f52dfbbSDag-Erling Smørgrav 			 * to stop.
4291e8db6e2SBrian Feldman 			 */
4301e8db6e2SBrian Feldman 			if (opcode > 0 && opcode < 160) {
431*190cef3dSDag-Erling Smørgrav 				if ((r = sshbuf_get_u32(buf, NULL)) != 0)
432*190cef3dSDag-Erling Smørgrav 					fatal("%s: packet error: %s", __func__,
433*190cef3dSDag-Erling Smørgrav 					    ssh_err(r));
4341e8db6e2SBrian Feldman 				break;
4351e8db6e2SBrian Feldman 			} else {
436*190cef3dSDag-Erling Smørgrav 				logit("%s: unknown opcode %d", __func__,
437761efaa7SDag-Erling Smørgrav 				    opcode);
4381e8db6e2SBrian Feldman 				goto set;
4391e8db6e2SBrian Feldman 			}
4401e8db6e2SBrian Feldman 		}
4411e8db6e2SBrian Feldman 	}
442511b41d2SMark Murray 
443511b41d2SMark Murray set:
444*190cef3dSDag-Erling Smørgrav 	len = sshbuf_len(buf);
445*190cef3dSDag-Erling Smørgrav 	sshbuf_free(buf);
446*190cef3dSDag-Erling Smørgrav 	if (len > 0) {
447*190cef3dSDag-Erling Smørgrav 		logit("%s: %zu bytes left", __func__, len);
448511b41d2SMark Murray 		return;		/* Don't process bytes passed */
449511b41d2SMark Murray 	}
450511b41d2SMark Murray 	if (failure == -1)
4511e8db6e2SBrian Feldman 		return;		/* Packet parsed ok but tcgetattr() failed */
452511b41d2SMark Murray 
453511b41d2SMark Murray 	/* Set the new modes for the terminal. */
4541e8db6e2SBrian Feldman 	if (tcsetattr(fd, TCSANOW, &tio) == -1)
455d95e11bfSDag-Erling Smørgrav 		logit("Setting tty modes failed: %.100s", strerror(errno));
456511b41d2SMark Murray }
457