xref: /freebsd/crypto/openssh/ttymodes.c (revision 19261079b74319502c6ffa1249920079f0f69a72)
1*19261079SEd Maste /* $OpenBSD: ttymodes.c,v 1.36 2021/01/27 09:26:54 djm 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"
58190cef3dSDag-Erling Smørgrav #include "sshbuf.h"
59190cef3dSDag-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
speed_to_baud(speed_t speed)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
baud_to_speed(int baud)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
special_char_encode(cc_t c)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
special_char_decode(u_int c)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
ssh_tty_make_modes(struct ssh * ssh,int fd,struct termios * tiop)279190cef3dSDag-Erling Smørgrav ssh_tty_make_modes(struct ssh *ssh, int fd, struct termios *tiop)
280511b41d2SMark Murray {
281511b41d2SMark Murray 	struct termios tio;
282190cef3dSDag-Erling Smørgrav 	struct sshbuf *buf;
283190cef3dSDag-Erling Smørgrav 	int r, ibaud, obaud;
284511b41d2SMark Murray 
285190cef3dSDag-Erling Smørgrav 	if ((buf = sshbuf_new()) == NULL)
286*19261079SEd Maste 		fatal_f("sshbuf_new failed");
2871e8db6e2SBrian Feldman 
2881e8db6e2SBrian Feldman 	if (tiop == NULL) {
289d4af9e69SDag-Erling Smørgrav 		if (fd == -1) {
290*19261079SEd Maste 			debug_f("no fd or tio");
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. */
301190cef3dSDag-Erling Smørgrav 	obaud = speed_to_baud(cfgetospeed(&tio));
302190cef3dSDag-Erling Smørgrav 	ibaud = speed_to_baud(cfgetispeed(&tio));
303190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(buf, TTY_OP_OSPEED)) != 0 ||
304190cef3dSDag-Erling Smørgrav 	    (r = sshbuf_put_u32(buf, obaud)) != 0 ||
305190cef3dSDag-Erling Smørgrav 	    (r = sshbuf_put_u8(buf, TTY_OP_ISPEED)) != 0 ||
306190cef3dSDag-Erling Smørgrav 	    (r = sshbuf_put_u32(buf, ibaud)) != 0)
307*19261079SEd Maste 		fatal_fr(r, "compose");
308511b41d2SMark Murray 
309511b41d2SMark Murray 	/* Store values of mode flags. */
310511b41d2SMark Murray #define TTYCHAR(NAME, OP) \
311190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(buf, OP)) != 0 || \
312190cef3dSDag-Erling Smørgrav 	    (r = sshbuf_put_u32(buf, \
313190cef3dSDag-Erling Smørgrav 	    special_char_encode(tio.c_cc[NAME]))) != 0) \
314*19261079SEd Maste 		fatal_fr(r, "compose %s", #NAME);
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) \
319*19261079SEd Maste 	if (OP == SSH_TTYMODE_IUTF8 && (ssh->compat & SSH_BUG_UTF8TTYMODE)) { \
320*19261079SEd Maste 		debug3_f("SSH_BUG_UTF8TTYMODE"); \
321190cef3dSDag-Erling Smørgrav 	} else if ((r = sshbuf_put_u8(buf, OP)) != 0 || \
322190cef3dSDag-Erling Smørgrav 	    (r = sshbuf_put_u32(buf, ((tio.FIELD & NAME) != 0))) != 0) \
323*19261079SEd Maste 		fatal_fr(r, "compose %s", #NAME);
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. */
332190cef3dSDag-Erling Smørgrav 	if ((r = sshbuf_put_u8(buf, TTY_OP_END)) != 0 ||
333190cef3dSDag-Erling Smørgrav 	    (r = sshpkt_put_stringb(ssh, buf)) != 0)
334*19261079SEd Maste 		fatal_fr(r, "compose end");
335190cef3dSDag-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
ssh_tty_parse_modes(struct ssh * ssh,int fd)343190cef3dSDag-Erling Smørgrav ssh_tty_parse_modes(struct ssh *ssh, int fd)
344511b41d2SMark Murray {
345511b41d2SMark Murray 	struct termios tio;
346190cef3dSDag-Erling Smørgrav 	struct sshbuf *buf;
347190cef3dSDag-Erling Smørgrav 	const u_char *data;
348190cef3dSDag-Erling Smørgrav 	u_char opcode;
349190cef3dSDag-Erling Smørgrav 	u_int baud, u;
350190cef3dSDag-Erling Smørgrav 	int r, failure = 0;
351190cef3dSDag-Erling Smørgrav 	size_t len;
3521e8db6e2SBrian Feldman 
353190cef3dSDag-Erling Smørgrav 	if ((r = sshpkt_get_string_direct(ssh, &data, &len)) != 0)
354*19261079SEd Maste 		fatal_fr(r, "parse");
355190cef3dSDag-Erling Smørgrav 	if (len == 0)
3561e8db6e2SBrian Feldman 		return;
357190cef3dSDag-Erling Smørgrav 	if ((buf = sshbuf_from(data, len)) == NULL) {
358*19261079SEd Maste 		error_f("sshbuf_from failed");
359190cef3dSDag-Erling Smørgrav 		return;
360190cef3dSDag-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 
372190cef3dSDag-Erling Smørgrav 	while (sshbuf_len(buf) > 0) {
373190cef3dSDag-Erling Smørgrav 		if ((r = sshbuf_get_u8(buf, &opcode)) != 0)
374*19261079SEd Maste 			fatal_fr(r, "parse opcode");
375511b41d2SMark Murray 		switch (opcode) {
376511b41d2SMark Murray 		case TTY_OP_END:
377511b41d2SMark Murray 			goto set;
378511b41d2SMark Murray 
3794f52dfbbSDag-Erling Smørgrav 		case TTY_OP_ISPEED:
380190cef3dSDag-Erling Smørgrav 			if ((r = sshbuf_get_u32(buf, &baud)) != 0)
381*19261079SEd Maste 				fatal_fr(r, "parse ispeed");
382761efaa7SDag-Erling Smørgrav 			if (failure != -1 &&
383761efaa7SDag-Erling Smørgrav 			    cfsetispeed(&tio, baud_to_speed(baud)) == -1)
384511b41d2SMark Murray 				error("cfsetispeed failed for %d", baud);
385511b41d2SMark Murray 			break;
386511b41d2SMark Murray 
3874f52dfbbSDag-Erling Smørgrav 		case TTY_OP_OSPEED:
388190cef3dSDag-Erling Smørgrav 			if ((r = sshbuf_get_u32(buf, &baud)) != 0)
389*19261079SEd Maste 				fatal_fr(r, "parse ospeed");
390761efaa7SDag-Erling Smørgrav 			if (failure != -1 &&
391761efaa7SDag-Erling Smørgrav 			    cfsetospeed(&tio, baud_to_speed(baud)) == -1)
392511b41d2SMark Murray 				error("cfsetospeed failed for %d", baud);
393511b41d2SMark Murray 			break;
394511b41d2SMark Murray 
395511b41d2SMark Murray #define TTYCHAR(NAME, OP) \
396511b41d2SMark Murray 		case OP: \
397190cef3dSDag-Erling Smørgrav 			if ((r = sshbuf_get_u32(buf, &u)) != 0) \
398*19261079SEd Maste 				fatal_fr(r, "parse %s", #NAME); \
399190cef3dSDag-Erling Smørgrav 			tio.c_cc[NAME] = special_char_decode(u); \
400511b41d2SMark Murray 			break;
401511b41d2SMark Murray #define TTYMODE(NAME, FIELD, OP) \
402511b41d2SMark Murray 		case OP: \
403190cef3dSDag-Erling Smørgrav 			if ((r = sshbuf_get_u32(buf, &u)) != 0) \
404*19261079SEd Maste 				fatal_fr(r, "parse %s", #NAME); \
405190cef3dSDag-Erling Smørgrav 			if (u) \
406511b41d2SMark Murray 				tio.FIELD |= NAME; \
407511b41d2SMark Murray 			else \
408511b41d2SMark Murray 				tio.FIELD &= ~NAME; \
409511b41d2SMark Murray 			break;
410511b41d2SMark Murray 
411511b41d2SMark Murray #include "ttymodes.h"
412511b41d2SMark Murray 
413511b41d2SMark Murray #undef TTYCHAR
414511b41d2SMark Murray #undef TTYMODE
415511b41d2SMark Murray 
416511b41d2SMark Murray 		default:
417511b41d2SMark Murray 			debug("Ignoring unsupported tty mode opcode %d (0x%x)",
418511b41d2SMark Murray 			    opcode, opcode);
4191e8db6e2SBrian Feldman 			/*
4201e8db6e2SBrian Feldman 			 * SSH2:
4214f52dfbbSDag-Erling Smørgrav 			 * Opcodes 1 to 159 are defined to have a uint32
4224f52dfbbSDag-Erling Smørgrav 			 * argument.
4234f52dfbbSDag-Erling Smørgrav 			 * Opcodes 160 to 255 are undefined and cause parsing
4244f52dfbbSDag-Erling Smørgrav 			 * to stop.
4251e8db6e2SBrian Feldman 			 */
4261e8db6e2SBrian Feldman 			if (opcode > 0 && opcode < 160) {
427190cef3dSDag-Erling Smørgrav 				if ((r = sshbuf_get_u32(buf, NULL)) != 0)
428*19261079SEd Maste 					fatal_fr(r, "parse arg");
4291e8db6e2SBrian Feldman 				break;
4301e8db6e2SBrian Feldman 			} else {
431*19261079SEd Maste 				logit_f("unknown opcode %d", opcode);
4321e8db6e2SBrian Feldman 				goto set;
4331e8db6e2SBrian Feldman 			}
4341e8db6e2SBrian Feldman 		}
4351e8db6e2SBrian Feldman 	}
436511b41d2SMark Murray 
437511b41d2SMark Murray set:
438190cef3dSDag-Erling Smørgrav 	len = sshbuf_len(buf);
439190cef3dSDag-Erling Smørgrav 	sshbuf_free(buf);
440190cef3dSDag-Erling Smørgrav 	if (len > 0) {
441*19261079SEd Maste 		logit_f("%zu bytes left", len);
442511b41d2SMark Murray 		return;		/* Don't process bytes passed */
443511b41d2SMark Murray 	}
444511b41d2SMark Murray 	if (failure == -1)
4451e8db6e2SBrian Feldman 		return;		/* Packet parsed ok but tcgetattr() failed */
446511b41d2SMark Murray 
447511b41d2SMark Murray 	/* Set the new modes for the terminal. */
4481e8db6e2SBrian Feldman 	if (tcsetattr(fd, TCSANOW, &tio) == -1)
449d95e11bfSDag-Erling Smørgrav 		logit("Setting tty modes failed: %.100s", strerror(errno));
450511b41d2SMark Murray }
451