xref: /freebsd/crypto/openssh/ttymodes.c (revision 1d66272a85cde1c8a69c58f4b5dd649babd6eca6)
1 /*
2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  * Encoding and decoding of terminal modes in a portable way.
6  * Much of the format is defined in ttymodes.h; it is included multiple times
7  * into this file with the appropriate macro definitions to generate the
8  * suitable code.
9  *
10  * As far as I am concerned, the code I have written for this software
11  * can be used freely for any purpose.  Any derived versions of this
12  * software must be clearly marked as such, and if the derived work is
13  * incompatible with the protocol description in the RFC file, it must be
14  * called by a name other than "ssh" or "Secure Shell".
15  */
16 
17 #include "includes.h"
18 RCSID("$OpenBSD: ttymodes.c,v 1.8 2000/09/07 20:27:55 deraadt Exp $");
19 
20 #include "packet.h"
21 #include "ssh.h"
22 
23 #define TTY_OP_END	0
24 #define TTY_OP_ISPEED	192	/* int follows */
25 #define TTY_OP_OSPEED	193	/* int follows */
26 
27 /*
28  * Converts POSIX speed_t to a baud rate.  The values of the
29  * constants for speed_t are not themselves portable.
30  */
31 static int
32 speed_to_baud(speed_t speed)
33 {
34 	switch (speed) {
35 	case B0:
36 		return 0;
37 	case B50:
38 		return 50;
39 	case B75:
40 		return 75;
41 	case B110:
42 		return 110;
43 	case B134:
44 		return 134;
45 	case B150:
46 		return 150;
47 	case B200:
48 		return 200;
49 	case B300:
50 		return 300;
51 	case B600:
52 		return 600;
53 	case B1200:
54 		return 1200;
55 	case B1800:
56 		return 1800;
57 	case B2400:
58 		return 2400;
59 	case B4800:
60 		return 4800;
61 	case B9600:
62 		return 9600;
63 
64 #ifdef B19200
65 	case B19200:
66 		return 19200;
67 #else /* B19200 */
68 #ifdef EXTA
69 	case EXTA:
70 		return 19200;
71 #endif /* EXTA */
72 #endif /* B19200 */
73 
74 #ifdef B38400
75 	case B38400:
76 		return 38400;
77 #else /* B38400 */
78 #ifdef EXTB
79 	case EXTB:
80 		return 38400;
81 #endif /* EXTB */
82 #endif /* B38400 */
83 
84 #ifdef B7200
85 	case B7200:
86 		return 7200;
87 #endif /* B7200 */
88 #ifdef B14400
89 	case B14400:
90 		return 14400;
91 #endif /* B14400 */
92 #ifdef B28800
93 	case B28800:
94 		return 28800;
95 #endif /* B28800 */
96 #ifdef B57600
97 	case B57600:
98 		return 57600;
99 #endif /* B57600 */
100 #ifdef B76800
101 	case B76800:
102 		return 76800;
103 #endif /* B76800 */
104 #ifdef B115200
105 	case B115200:
106 		return 115200;
107 #endif /* B115200 */
108 #ifdef B230400
109 	case B230400:
110 		return 230400;
111 #endif /* B230400 */
112 	default:
113 		return 9600;
114 	}
115 }
116 
117 /*
118  * Converts a numeric baud rate to a POSIX speed_t.
119  */
120 static speed_t
121 baud_to_speed(int baud)
122 {
123 	switch (baud) {
124 		case 0:
125 		return B0;
126 	case 50:
127 		return B50;
128 	case 75:
129 		return B75;
130 	case 110:
131 		return B110;
132 	case 134:
133 		return B134;
134 	case 150:
135 		return B150;
136 	case 200:
137 		return B200;
138 	case 300:
139 		return B300;
140 	case 600:
141 		return B600;
142 	case 1200:
143 		return B1200;
144 	case 1800:
145 		return B1800;
146 	case 2400:
147 		return B2400;
148 	case 4800:
149 		return B4800;
150 	case 9600:
151 		return B9600;
152 
153 #ifdef B19200
154 	case 19200:
155 		return B19200;
156 #else /* B19200 */
157 #ifdef EXTA
158 	case 19200:
159 		return EXTA;
160 #endif /* EXTA */
161 #endif /* B19200 */
162 
163 #ifdef B38400
164 	case 38400:
165 		return B38400;
166 #else /* B38400 */
167 #ifdef EXTB
168 	case 38400:
169 		return EXTB;
170 #endif /* EXTB */
171 #endif /* B38400 */
172 
173 #ifdef B7200
174 	case 7200:
175 		return B7200;
176 #endif /* B7200 */
177 #ifdef B14400
178 	case 14400:
179 		return B14400;
180 #endif /* B14400 */
181 #ifdef B28800
182 	case 28800:
183 		return B28800;
184 #endif /* B28800 */
185 #ifdef B57600
186 	case 57600:
187 		return B57600;
188 #endif /* B57600 */
189 #ifdef B76800
190 	case 76800:
191 		return B76800;
192 #endif /* B76800 */
193 #ifdef B115200
194 	case 115200:
195 		return B115200;
196 #endif /* B115200 */
197 #ifdef B230400
198 	case 230400:
199 		return B230400;
200 #endif /* B230400 */
201 	default:
202 		return B9600;
203 	}
204 }
205 
206 /*
207  * Encodes terminal modes for the terminal referenced by fd
208  * in a portable manner, and appends the modes to a packet
209  * being constructed.
210  */
211 void
212 tty_make_modes(int fd)
213 {
214 	struct termios tio;
215 	int baud;
216 
217 	if (tcgetattr(fd, &tio) < 0) {
218 		packet_put_char(TTY_OP_END);
219 		log("tcgetattr: %.100s", strerror(errno));
220 		return;
221 	}
222 	/* Store input and output baud rates. */
223 	baud = speed_to_baud(cfgetospeed(&tio));
224 	packet_put_char(TTY_OP_OSPEED);
225 	packet_put_int(baud);
226 	baud = speed_to_baud(cfgetispeed(&tio));
227 	packet_put_char(TTY_OP_ISPEED);
228 	packet_put_int(baud);
229 
230 	/* Store values of mode flags. */
231 #define TTYCHAR(NAME, OP) \
232   packet_put_char(OP); packet_put_char(tio.c_cc[NAME]);
233 #define TTYMODE(NAME, FIELD, OP) \
234   packet_put_char(OP); packet_put_char((tio.FIELD & NAME) != 0);
235 #define SGTTYCHAR(NAME, OP)
236 #define SGTTYMODE(NAME, FIELD, OP)
237 #define SGTTYMODEN(NAME, FIELD, OP)
238 
239 #include "ttymodes.h"
240 
241 #undef TTYCHAR
242 #undef TTYMODE
243 #undef SGTTYCHAR
244 #undef SGTTYMODE
245 #undef SGTTYMODEN
246 
247 	/* Mark end of mode data. */
248 	packet_put_char(TTY_OP_END);
249 }
250 
251 /*
252  * Decodes terminal modes for the terminal referenced by fd in a portable
253  * manner from a packet being read.
254  */
255 void
256 tty_parse_modes(int fd, int *n_bytes_ptr)
257 {
258 	struct termios tio;
259 	int opcode, baud;
260 	int n_bytes = 0;
261 	int failure = 0;
262 
263 	/*
264 	 * Get old attributes for the terminal.  We will modify these
265 	 * flags. I am hoping that if there are any machine-specific
266 	 * modes, they will initially have reasonable values.
267 	 */
268 	if (tcgetattr(fd, &tio) < 0)
269 		failure = -1;
270 
271 	for (;;) {
272 		n_bytes += 1;
273 		opcode = packet_get_char();
274 		switch (opcode) {
275 		case TTY_OP_END:
276 			goto set;
277 
278 		case TTY_OP_ISPEED:
279 			n_bytes += 4;
280 			baud = packet_get_int();
281 			if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) < 0)
282 				error("cfsetispeed failed for %d", baud);
283 			break;
284 
285 		case TTY_OP_OSPEED:
286 			n_bytes += 4;
287 			baud = packet_get_int();
288 			if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) < 0)
289 				error("cfsetospeed failed for %d", baud);
290 			break;
291 
292 #define TTYCHAR(NAME, OP) 				\
293 	case OP:					\
294 	  n_bytes += 1;					\
295 	  tio.c_cc[NAME] = packet_get_char();		\
296 	  break;
297 #define TTYMODE(NAME, FIELD, OP)		       	\
298 	case OP:					\
299 	  n_bytes += 1;					\
300 	  if (packet_get_char())			\
301 	    tio.FIELD |= NAME;				\
302 	  else						\
303 	    tio.FIELD &= ~NAME;				\
304 	  break;
305 #define SGTTYCHAR(NAME, OP)
306 #define SGTTYMODE(NAME, FIELD, OP)
307 #define SGTTYMODEN(NAME, FIELD, OP)
308 
309 #include "ttymodes.h"
310 
311 #undef TTYCHAR
312 #undef TTYMODE
313 #undef SGTTYCHAR
314 #undef SGTTYMODE
315 #undef SGTTYMODEN
316 
317 		default:
318 			debug("Ignoring unsupported tty mode opcode %d (0x%x)",
319 			      opcode, opcode);
320 			/*
321 			 * Opcodes 0 to 127 are defined to have
322 			 * a one-byte argument.
323 			 */
324 			if (opcode >= 0 && opcode < 128) {
325 				n_bytes += 1;
326 				(void) packet_get_char();
327 				break;
328 			} else {
329 				/*
330 				 * Opcodes 128 to 159 are defined to have
331 				 * an integer argument.
332 				 */
333 				if (opcode >= 128 && opcode < 160) {
334 					n_bytes += 4;
335 					(void) packet_get_int();
336 					break;
337 				}
338 			}
339 			/*
340 			 * It is a truly undefined opcode (160 to 255).
341 			 * We have no idea about its arguments.  So we
342 			 * must stop parsing.  Note that some data may be
343 			 * left in the packet; hopefully there is nothing
344 			 * more coming after the mode data.
345 			 */
346 			log("parse_tty_modes: unknown opcode %d", opcode);
347 			packet_integrity_check(0, 1, SSH_CMSG_REQUEST_PTY);
348 			goto set;
349 		}
350 	}
351 
352 set:
353 	if (*n_bytes_ptr != n_bytes) {
354 		*n_bytes_ptr = n_bytes;
355 		return;		/* Don't process bytes passed */
356 	}
357 	if (failure == -1)
358 		return;		/* Packet parsed ok but tty stuff failed */
359 
360 	/* Set the new modes for the terminal. */
361 	if (tcsetattr(fd, TCSANOW, &tio) < 0)
362 		log("Setting tty modes failed: %.100s", strerror(errno));
363 	return;
364 }
365