Merge branch 'vendor/ZLIB'
[dragonfly.git] / crypto / openssh / ttymodes.c
1 /* $OpenBSD: ttymodes.c,v 1.34 2018/07/09 21:20:26 markus Exp $ */
2 /*
3  * Author: Tatu Ylonen <ylo@cs.hut.fi>
4  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5  *                    All rights reserved
6  *
7  * As far as I am concerned, the code I have written for this software
8  * can be used freely for any purpose.  Any derived versions of this
9  * software must be clearly marked as such, and if the derived work is
10  * incompatible with the protocol description in the RFC file, it must be
11  * called by a name other than "ssh" or "Secure Shell".
12  */
13
14 /*
15  * SSH2 tty modes support by Kevin Steves.
16  * Copyright (c) 2001 Kevin Steves.  All rights reserved.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */
38
39 /*
40  * Encoding and decoding of terminal modes in a portable way.
41  * Much of the format is defined in ttymodes.h; it is included multiple times
42  * into this file with the appropriate macro definitions to generate the
43  * suitable code.
44  */
45
46 #include "includes.h"
47
48 #include <sys/types.h>
49
50 #include <errno.h>
51 #include <string.h>
52 #include <termios.h>
53 #include <stdarg.h>
54
55 #include "packet.h"
56 #include "log.h"
57 #include "compat.h"
58 #include "sshbuf.h"
59 #include "ssherr.h"
60
61 #define TTY_OP_END              0
62 /*
63  * uint32 (u_int) follows speed.
64  */
65 #define TTY_OP_ISPEED   128
66 #define TTY_OP_OSPEED   129
67
68 /*
69  * Converts POSIX speed_t to a baud rate.  The values of the
70  * constants for speed_t are not themselves portable.
71  */
72 static int
73 speed_to_baud(speed_t speed)
74 {
75         switch (speed) {
76         case B0:
77                 return 0;
78         case B50:
79                 return 50;
80         case B75:
81                 return 75;
82         case B110:
83                 return 110;
84         case B134:
85                 return 134;
86         case B150:
87                 return 150;
88         case B200:
89                 return 200;
90         case B300:
91                 return 300;
92         case B600:
93                 return 600;
94         case B1200:
95                 return 1200;
96         case B1800:
97                 return 1800;
98         case B2400:
99                 return 2400;
100         case B4800:
101                 return 4800;
102         case B9600:
103                 return 9600;
104
105 #ifdef B19200
106         case B19200:
107                 return 19200;
108 #else /* B19200 */
109 #ifdef EXTA
110         case EXTA:
111                 return 19200;
112 #endif /* EXTA */
113 #endif /* B19200 */
114
115 #ifdef B38400
116         case B38400:
117                 return 38400;
118 #else /* B38400 */
119 #ifdef EXTB
120         case EXTB:
121                 return 38400;
122 #endif /* EXTB */
123 #endif /* B38400 */
124
125 #ifdef B7200
126         case B7200:
127                 return 7200;
128 #endif /* B7200 */
129 #ifdef B14400
130         case B14400:
131                 return 14400;
132 #endif /* B14400 */
133 #ifdef B28800
134         case B28800:
135                 return 28800;
136 #endif /* B28800 */
137 #ifdef B57600
138         case B57600:
139                 return 57600;
140 #endif /* B57600 */
141 #ifdef B76800
142         case B76800:
143                 return 76800;
144 #endif /* B76800 */
145 #ifdef B115200
146         case B115200:
147                 return 115200;
148 #endif /* B115200 */
149 #ifdef B230400
150         case B230400:
151                 return 230400;
152 #endif /* B230400 */
153         default:
154                 return 9600;
155         }
156 }
157
158 /*
159  * Converts a numeric baud rate to a POSIX speed_t.
160  */
161 static speed_t
162 baud_to_speed(int baud)
163 {
164         switch (baud) {
165         case 0:
166                 return B0;
167         case 50:
168                 return B50;
169         case 75:
170                 return B75;
171         case 110:
172                 return B110;
173         case 134:
174                 return B134;
175         case 150:
176                 return B150;
177         case 200:
178                 return B200;
179         case 300:
180                 return B300;
181         case 600:
182                 return B600;
183         case 1200:
184                 return B1200;
185         case 1800:
186                 return B1800;
187         case 2400:
188                 return B2400;
189         case 4800:
190                 return B4800;
191         case 9600:
192                 return B9600;
193
194 #ifdef B19200
195         case 19200:
196                 return B19200;
197 #else /* B19200 */
198 #ifdef EXTA
199         case 19200:
200                 return EXTA;
201 #endif /* EXTA */
202 #endif /* B19200 */
203
204 #ifdef B38400
205         case 38400:
206                 return B38400;
207 #else /* B38400 */
208 #ifdef EXTB
209         case 38400:
210                 return EXTB;
211 #endif /* EXTB */
212 #endif /* B38400 */
213
214 #ifdef B7200
215         case 7200:
216                 return B7200;
217 #endif /* B7200 */
218 #ifdef B14400
219         case 14400:
220                 return B14400;
221 #endif /* B14400 */
222 #ifdef B28800
223         case 28800:
224                 return B28800;
225 #endif /* B28800 */
226 #ifdef B57600
227         case 57600:
228                 return B57600;
229 #endif /* B57600 */
230 #ifdef B76800
231         case 76800:
232                 return B76800;
233 #endif /* B76800 */
234 #ifdef B115200
235         case 115200:
236                 return B115200;
237 #endif /* B115200 */
238 #ifdef B230400
239         case 230400:
240                 return B230400;
241 #endif /* B230400 */
242         default:
243                 return B9600;
244         }
245 }
246
247 /*
248  * Encode a special character into SSH line format.
249  */
250 static u_int
251 special_char_encode(cc_t c)
252 {
253 #ifdef _POSIX_VDISABLE
254         if (c == _POSIX_VDISABLE)
255                 return 255;
256 #endif /* _POSIX_VDISABLE */
257         return c;
258 }
259
260 /*
261  * Decode a special character from SSH line format.
262  */
263 static cc_t
264 special_char_decode(u_int c)
265 {
266 #ifdef _POSIX_VDISABLE
267         if (c == 255)
268                 return _POSIX_VDISABLE;
269 #endif /* _POSIX_VDISABLE */
270         return c;
271 }
272
273 /*
274  * Encodes terminal modes for the terminal referenced by fd
275  * or tiop in a portable manner, and appends the modes to a packet
276  * being constructed.
277  */
278 void
279 ssh_tty_make_modes(struct ssh *ssh, int fd, struct termios *tiop)
280 {
281         struct termios tio;
282         struct sshbuf *buf;
283         int r, ibaud, obaud;
284
285         if ((buf = sshbuf_new()) == NULL)
286                 fatal("%s: sshbuf_new failed", __func__);
287
288         if (tiop == NULL) {
289                 if (fd == -1) {
290                         debug("%s: no fd or tio", __func__);
291                         goto end;
292                 }
293                 if (tcgetattr(fd, &tio) == -1) {
294                         logit("tcgetattr: %.100s", strerror(errno));
295                         goto end;
296                 }
297         } else
298                 tio = *tiop;
299
300         /* Store input and output baud rates. */
301         obaud = speed_to_baud(cfgetospeed(&tio));
302         ibaud = speed_to_baud(cfgetispeed(&tio));
303         if ((r = sshbuf_put_u8(buf, TTY_OP_OSPEED)) != 0 ||
304             (r = sshbuf_put_u32(buf, obaud)) != 0 ||
305             (r = sshbuf_put_u8(buf, TTY_OP_ISPEED)) != 0 ||
306             (r = sshbuf_put_u32(buf, ibaud)) != 0)
307                 fatal("%s: buffer error: %s", __func__, ssh_err(r));
308
309         /* Store values of mode flags. */
310 #define TTYCHAR(NAME, OP) \
311         if ((r = sshbuf_put_u8(buf, OP)) != 0 || \
312             (r = sshbuf_put_u32(buf, \
313             special_char_encode(tio.c_cc[NAME]))) != 0) \
314                 fatal("%s: buffer error: %s", __func__, ssh_err(r)); \
315
316 #define SSH_TTYMODE_IUTF8 42  /* for SSH_BUG_UTF8TTYMODE */
317
318 #define TTYMODE(NAME, FIELD, OP) \
319         if (OP == SSH_TTYMODE_IUTF8 && (datafellows & SSH_BUG_UTF8TTYMODE)) { \
320                 debug3("%s: SSH_BUG_UTF8TTYMODE", __func__); \
321         } else if ((r = sshbuf_put_u8(buf, OP)) != 0 || \
322             (r = sshbuf_put_u32(buf, ((tio.FIELD & NAME) != 0))) != 0) \
323                 fatal("%s: buffer error: %s", __func__, ssh_err(r)); \
324
325 #include "ttymodes.h"
326
327 #undef TTYCHAR
328 #undef TTYMODE
329
330 end:
331         /* Mark end of mode data. */
332         if ((r = sshbuf_put_u8(buf, TTY_OP_END)) != 0 ||
333             (r = sshpkt_put_stringb(ssh, buf)) != 0)
334                 fatal("%s: packet error: %s", __func__, ssh_err(r));
335         sshbuf_free(buf);
336 }
337
338 /*
339  * Decodes terminal modes for the terminal referenced by fd in a portable
340  * manner from a packet being read.
341  */
342 void
343 ssh_tty_parse_modes(struct ssh *ssh, int fd)
344 {
345         struct termios tio;
346         struct sshbuf *buf;
347         const u_char *data;
348         u_char opcode;
349         u_int baud, u;
350         int r, failure = 0;
351         size_t len;
352
353         if ((r = sshpkt_get_string_direct(ssh, &data, &len)) != 0)
354                 fatal("%s: packet error: %s", __func__, ssh_err(r));
355         if (len == 0)
356                 return;
357         if ((buf = sshbuf_from(data, len)) == NULL) {
358                 error("%s: sshbuf_from failed", __func__);
359                 return;
360         }
361
362         /*
363          * Get old attributes for the terminal.  We will modify these
364          * flags. I am hoping that if there are any machine-specific
365          * modes, they will initially have reasonable values.
366          */
367         if (tcgetattr(fd, &tio) == -1) {
368                 logit("tcgetattr: %.100s", strerror(errno));
369                 failure = -1;
370         }
371
372         while (sshbuf_len(buf) > 0) {
373                 if ((r = sshbuf_get_u8(buf, &opcode)) != 0)
374                         fatal("%s: packet error: %s", __func__, ssh_err(r));
375                 switch (opcode) {
376                 case TTY_OP_END:
377                         goto set;
378
379                 case TTY_OP_ISPEED:
380                         if ((r = sshbuf_get_u32(buf, &baud)) != 0)
381                                 fatal("%s: packet error: %s",
382                                     __func__, ssh_err(r));
383                         if (failure != -1 &&
384                             cfsetispeed(&tio, baud_to_speed(baud)) == -1)
385                                 error("cfsetispeed failed for %d", baud);
386                         break;
387
388                 case TTY_OP_OSPEED:
389                         if ((r = sshbuf_get_u32(buf, &baud)) != 0)
390                                 fatal("%s: packet error: %s",
391                                     __func__, ssh_err(r));
392                         if (failure != -1 &&
393                             cfsetospeed(&tio, baud_to_speed(baud)) == -1)
394                                 error("cfsetospeed failed for %d", baud);
395                         break;
396
397 #define TTYCHAR(NAME, OP) \
398                 case OP: \
399                         if ((r = sshbuf_get_u32(buf, &u)) != 0) \
400                                 fatal("%s: packet error: %s", __func__, \
401                                     ssh_err(r)); \
402                         tio.c_cc[NAME] = special_char_decode(u); \
403                         break;
404 #define TTYMODE(NAME, FIELD, OP) \
405                 case OP: \
406                         if ((r = sshbuf_get_u32(buf, &u)) != 0) \
407                                 fatal("%s: packet error: %s", __func__, \
408                                     ssh_err(r)); \
409                         if (u) \
410                                 tio.FIELD |= NAME; \
411                         else \
412                                 tio.FIELD &= ~NAME; \
413                         break;
414
415 #include "ttymodes.h"
416
417 #undef TTYCHAR
418 #undef TTYMODE
419
420                 default:
421                         debug("Ignoring unsupported tty mode opcode %d (0x%x)",
422                             opcode, opcode);
423                         /*
424                          * SSH2:
425                          * Opcodes 1 to 159 are defined to have a uint32
426                          * argument.
427                          * Opcodes 160 to 255 are undefined and cause parsing
428                          * to stop.
429                          */
430                         if (opcode > 0 && opcode < 160) {
431                                 if ((r = sshbuf_get_u32(buf, NULL)) != 0)
432                                         fatal("%s: packet error: %s", __func__,
433                                             ssh_err(r));
434                                 break;
435                         } else {
436                                 logit("%s: unknown opcode %d", __func__,
437                                     opcode);
438                                 goto set;
439                         }
440                 }
441         }
442
443 set:
444         len = sshbuf_len(buf);
445         sshbuf_free(buf);
446         if (len > 0) {
447                 logit("%s: %zu bytes left", __func__, len);
448                 return;         /* Don't process bytes passed */
449         }
450         if (failure == -1)
451                 return;         /* Packet parsed ok but tcgetattr() failed */
452
453         /* Set the new modes for the terminal. */
454         if (tcsetattr(fd, TCSANOW, &tio) == -1)
455                 logit("Setting tty modes failed: %.100s", strerror(errno));
456 }