source: trunk/third/openssh/ttymodes.c @ 18759

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