xref: /titanic_44/usr/src/cmd/ssh/libssh/common/ttymodes.c (revision de81e71e031139a0a7f13b7bf64152c3faa76698)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
37c478bd9Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
47c478bd9Sstevel@tonic-gate  *                    All rights reserved
57c478bd9Sstevel@tonic-gate  *
67c478bd9Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
77c478bd9Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
87c478bd9Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
97c478bd9Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
107c478bd9Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
117c478bd9Sstevel@tonic-gate  */
127c478bd9Sstevel@tonic-gate 
137c478bd9Sstevel@tonic-gate /*
147c478bd9Sstevel@tonic-gate  * SSH2 tty modes support by Kevin Steves.
157c478bd9Sstevel@tonic-gate  * Copyright (c) 2001 Kevin Steves.  All rights reserved.
167c478bd9Sstevel@tonic-gate  *
177c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
187c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
197c478bd9Sstevel@tonic-gate  * are met:
207c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
217c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
227c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
237c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
247c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
277c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
287c478bd9Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
297c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
307c478bd9Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
317c478bd9Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
327c478bd9Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
337c478bd9Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
347c478bd9Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
357c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
367c478bd9Sstevel@tonic-gate  */
37*de81e71eSTim Marsland 
387c478bd9Sstevel@tonic-gate /*
39*de81e71eSTim Marsland  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
407c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate /*
447c478bd9Sstevel@tonic-gate  * Encoding and decoding of terminal modes in a portable way.
457c478bd9Sstevel@tonic-gate  * Much of the format is defined in ttymodes.h; it is included multiple times
467c478bd9Sstevel@tonic-gate  * into this file with the appropriate macro definitions to generate the
477c478bd9Sstevel@tonic-gate  * suitable code.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include "includes.h"
517c478bd9Sstevel@tonic-gate RCSID("$OpenBSD: ttymodes.c,v 1.18 2002/06/19 00:27:55 deraadt Exp $");
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #include "packet.h"
547c478bd9Sstevel@tonic-gate #include "log.h"
557c478bd9Sstevel@tonic-gate #include "ssh1.h"
567c478bd9Sstevel@tonic-gate #include "compat.h"
577c478bd9Sstevel@tonic-gate #include "buffer.h"
587c478bd9Sstevel@tonic-gate #include "bufaux.h"
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate #define TTY_OP_END		0
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * uint32 (u_int) follows speed in SSH1 and SSH2
637c478bd9Sstevel@tonic-gate  */
647c478bd9Sstevel@tonic-gate #define TTY_OP_ISPEED_PROTO1	192
657c478bd9Sstevel@tonic-gate #define TTY_OP_OSPEED_PROTO1	193
667c478bd9Sstevel@tonic-gate #define TTY_OP_ISPEED_PROTO2	128
677c478bd9Sstevel@tonic-gate #define TTY_OP_OSPEED_PROTO2	129
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /*
707c478bd9Sstevel@tonic-gate  * Converts POSIX speed_t to a baud rate.  The values of the
717c478bd9Sstevel@tonic-gate  * constants for speed_t are not themselves portable.
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate static int
speed_to_baud(speed_t speed)747c478bd9Sstevel@tonic-gate speed_to_baud(speed_t speed)
757c478bd9Sstevel@tonic-gate {
767c478bd9Sstevel@tonic-gate 	switch (speed) {
777c478bd9Sstevel@tonic-gate 	case B0:
787c478bd9Sstevel@tonic-gate 		return 0;
797c478bd9Sstevel@tonic-gate 	case B50:
807c478bd9Sstevel@tonic-gate 		return 50;
817c478bd9Sstevel@tonic-gate 	case B75:
827c478bd9Sstevel@tonic-gate 		return 75;
837c478bd9Sstevel@tonic-gate 	case B110:
847c478bd9Sstevel@tonic-gate 		return 110;
857c478bd9Sstevel@tonic-gate 	case B134:
867c478bd9Sstevel@tonic-gate 		return 134;
877c478bd9Sstevel@tonic-gate 	case B150:
887c478bd9Sstevel@tonic-gate 		return 150;
897c478bd9Sstevel@tonic-gate 	case B200:
907c478bd9Sstevel@tonic-gate 		return 200;
917c478bd9Sstevel@tonic-gate 	case B300:
927c478bd9Sstevel@tonic-gate 		return 300;
937c478bd9Sstevel@tonic-gate 	case B600:
947c478bd9Sstevel@tonic-gate 		return 600;
957c478bd9Sstevel@tonic-gate 	case B1200:
967c478bd9Sstevel@tonic-gate 		return 1200;
977c478bd9Sstevel@tonic-gate 	case B1800:
987c478bd9Sstevel@tonic-gate 		return 1800;
997c478bd9Sstevel@tonic-gate 	case B2400:
1007c478bd9Sstevel@tonic-gate 		return 2400;
1017c478bd9Sstevel@tonic-gate 	case B4800:
1027c478bd9Sstevel@tonic-gate 		return 4800;
1037c478bd9Sstevel@tonic-gate 	case B9600:
1047c478bd9Sstevel@tonic-gate 		return 9600;
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate #ifdef B19200
1077c478bd9Sstevel@tonic-gate 	case B19200:
1087c478bd9Sstevel@tonic-gate 		return 19200;
1097c478bd9Sstevel@tonic-gate #else /* B19200 */
1107c478bd9Sstevel@tonic-gate #ifdef EXTA
1117c478bd9Sstevel@tonic-gate 	case EXTA:
1127c478bd9Sstevel@tonic-gate 		return 19200;
1137c478bd9Sstevel@tonic-gate #endif /* EXTA */
1147c478bd9Sstevel@tonic-gate #endif /* B19200 */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate #ifdef B38400
1177c478bd9Sstevel@tonic-gate 	case B38400:
1187c478bd9Sstevel@tonic-gate 		return 38400;
1197c478bd9Sstevel@tonic-gate #else /* B38400 */
1207c478bd9Sstevel@tonic-gate #ifdef EXTB
1217c478bd9Sstevel@tonic-gate 	case EXTB:
1227c478bd9Sstevel@tonic-gate 		return 38400;
1237c478bd9Sstevel@tonic-gate #endif /* EXTB */
1247c478bd9Sstevel@tonic-gate #endif /* B38400 */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate #ifdef B7200
1277c478bd9Sstevel@tonic-gate 	case B7200:
1287c478bd9Sstevel@tonic-gate 		return 7200;
1297c478bd9Sstevel@tonic-gate #endif /* B7200 */
1307c478bd9Sstevel@tonic-gate #ifdef B14400
1317c478bd9Sstevel@tonic-gate 	case B14400:
1327c478bd9Sstevel@tonic-gate 		return 14400;
1337c478bd9Sstevel@tonic-gate #endif /* B14400 */
1347c478bd9Sstevel@tonic-gate #ifdef B28800
1357c478bd9Sstevel@tonic-gate 	case B28800:
1367c478bd9Sstevel@tonic-gate 		return 28800;
1377c478bd9Sstevel@tonic-gate #endif /* B28800 */
1387c478bd9Sstevel@tonic-gate #ifdef B57600
1397c478bd9Sstevel@tonic-gate 	case B57600:
1407c478bd9Sstevel@tonic-gate 		return 57600;
1417c478bd9Sstevel@tonic-gate #endif /* B57600 */
1427c478bd9Sstevel@tonic-gate #ifdef B76800
1437c478bd9Sstevel@tonic-gate 	case B76800:
1447c478bd9Sstevel@tonic-gate 		return 76800;
1457c478bd9Sstevel@tonic-gate #endif /* B76800 */
1467c478bd9Sstevel@tonic-gate #ifdef B115200
1477c478bd9Sstevel@tonic-gate 	case B115200:
1487c478bd9Sstevel@tonic-gate 		return 115200;
1497c478bd9Sstevel@tonic-gate #endif /* B115200 */
1507c478bd9Sstevel@tonic-gate #ifdef B230400
1517c478bd9Sstevel@tonic-gate 	case B230400:
1527c478bd9Sstevel@tonic-gate 		return 230400;
1537c478bd9Sstevel@tonic-gate #endif /* B230400 */
154*de81e71eSTim Marsland #ifdef B460800
155*de81e71eSTim Marsland 	case B460800:
156*de81e71eSTim Marsland 		return 460800;
157*de81e71eSTim Marsland #endif /* B460800 */
158*de81e71eSTim Marsland #ifdef B921600
159*de81e71eSTim Marsland 	case B921600:
160*de81e71eSTim Marsland 		return 921600;
161*de81e71eSTim Marsland #endif /* B921600 */
1627c478bd9Sstevel@tonic-gate 	default:
1637c478bd9Sstevel@tonic-gate 		return 9600;
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate }
1667c478bd9Sstevel@tonic-gate 
1677c478bd9Sstevel@tonic-gate /*
1687c478bd9Sstevel@tonic-gate  * Converts a numeric baud rate to a POSIX speed_t.
1697c478bd9Sstevel@tonic-gate  */
1707c478bd9Sstevel@tonic-gate static speed_t
baud_to_speed(int baud)1717c478bd9Sstevel@tonic-gate baud_to_speed(int baud)
1727c478bd9Sstevel@tonic-gate {
1737c478bd9Sstevel@tonic-gate 	switch (baud) {
1747c478bd9Sstevel@tonic-gate 	case 0:
1757c478bd9Sstevel@tonic-gate 		return B0;
1767c478bd9Sstevel@tonic-gate 	case 50:
1777c478bd9Sstevel@tonic-gate 		return B50;
1787c478bd9Sstevel@tonic-gate 	case 75:
1797c478bd9Sstevel@tonic-gate 		return B75;
1807c478bd9Sstevel@tonic-gate 	case 110:
1817c478bd9Sstevel@tonic-gate 		return B110;
1827c478bd9Sstevel@tonic-gate 	case 134:
1837c478bd9Sstevel@tonic-gate 		return B134;
1847c478bd9Sstevel@tonic-gate 	case 150:
1857c478bd9Sstevel@tonic-gate 		return B150;
1867c478bd9Sstevel@tonic-gate 	case 200:
1877c478bd9Sstevel@tonic-gate 		return B200;
1887c478bd9Sstevel@tonic-gate 	case 300:
1897c478bd9Sstevel@tonic-gate 		return B300;
1907c478bd9Sstevel@tonic-gate 	case 600:
1917c478bd9Sstevel@tonic-gate 		return B600;
1927c478bd9Sstevel@tonic-gate 	case 1200:
1937c478bd9Sstevel@tonic-gate 		return B1200;
1947c478bd9Sstevel@tonic-gate 	case 1800:
1957c478bd9Sstevel@tonic-gate 		return B1800;
1967c478bd9Sstevel@tonic-gate 	case 2400:
1977c478bd9Sstevel@tonic-gate 		return B2400;
1987c478bd9Sstevel@tonic-gate 	case 4800:
1997c478bd9Sstevel@tonic-gate 		return B4800;
2007c478bd9Sstevel@tonic-gate 	case 9600:
2017c478bd9Sstevel@tonic-gate 		return B9600;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate #ifdef B19200
2047c478bd9Sstevel@tonic-gate 	case 19200:
2057c478bd9Sstevel@tonic-gate 		return B19200;
2067c478bd9Sstevel@tonic-gate #else /* B19200 */
2077c478bd9Sstevel@tonic-gate #ifdef EXTA
2087c478bd9Sstevel@tonic-gate 	case 19200:
2097c478bd9Sstevel@tonic-gate 		return EXTA;
2107c478bd9Sstevel@tonic-gate #endif /* EXTA */
2117c478bd9Sstevel@tonic-gate #endif /* B19200 */
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate #ifdef B38400
2147c478bd9Sstevel@tonic-gate 	case 38400:
2157c478bd9Sstevel@tonic-gate 		return B38400;
2167c478bd9Sstevel@tonic-gate #else /* B38400 */
2177c478bd9Sstevel@tonic-gate #ifdef EXTB
2187c478bd9Sstevel@tonic-gate 	case 38400:
2197c478bd9Sstevel@tonic-gate 		return EXTB;
2207c478bd9Sstevel@tonic-gate #endif /* EXTB */
2217c478bd9Sstevel@tonic-gate #endif /* B38400 */
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate #ifdef B7200
2247c478bd9Sstevel@tonic-gate 	case 7200:
2257c478bd9Sstevel@tonic-gate 		return B7200;
2267c478bd9Sstevel@tonic-gate #endif /* B7200 */
2277c478bd9Sstevel@tonic-gate #ifdef B14400
2287c478bd9Sstevel@tonic-gate 	case 14400:
2297c478bd9Sstevel@tonic-gate 		return B14400;
2307c478bd9Sstevel@tonic-gate #endif /* B14400 */
2317c478bd9Sstevel@tonic-gate #ifdef B28800
2327c478bd9Sstevel@tonic-gate 	case 28800:
2337c478bd9Sstevel@tonic-gate 		return B28800;
2347c478bd9Sstevel@tonic-gate #endif /* B28800 */
2357c478bd9Sstevel@tonic-gate #ifdef B57600
2367c478bd9Sstevel@tonic-gate 	case 57600:
2377c478bd9Sstevel@tonic-gate 		return B57600;
2387c478bd9Sstevel@tonic-gate #endif /* B57600 */
2397c478bd9Sstevel@tonic-gate #ifdef B76800
2407c478bd9Sstevel@tonic-gate 	case 76800:
2417c478bd9Sstevel@tonic-gate 		return B76800;
2427c478bd9Sstevel@tonic-gate #endif /* B76800 */
2437c478bd9Sstevel@tonic-gate #ifdef B115200
2447c478bd9Sstevel@tonic-gate 	case 115200:
2457c478bd9Sstevel@tonic-gate 		return B115200;
2467c478bd9Sstevel@tonic-gate #endif /* B115200 */
2477c478bd9Sstevel@tonic-gate #ifdef B230400
2487c478bd9Sstevel@tonic-gate 	case 230400:
2497c478bd9Sstevel@tonic-gate 		return B230400;
2507c478bd9Sstevel@tonic-gate #endif /* B230400 */
251*de81e71eSTim Marsland #ifdef B460800
252*de81e71eSTim Marsland 	case 460800:
253*de81e71eSTim Marsland 		return B460800;
254*de81e71eSTim Marsland #endif /* B460800 */
255*de81e71eSTim Marsland #ifdef B921600
256*de81e71eSTim Marsland 	case 921600:
257*de81e71eSTim Marsland 		return B921600;
258*de81e71eSTim Marsland #endif /* B921600 */
2597c478bd9Sstevel@tonic-gate 	default:
2607c478bd9Sstevel@tonic-gate 		return B9600;
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate  * Encodes terminal modes for the terminal referenced by fd
2667c478bd9Sstevel@tonic-gate  * or tiop in a portable manner, and appends the modes to a packet
2677c478bd9Sstevel@tonic-gate  * being constructed.
2687c478bd9Sstevel@tonic-gate  */
2697c478bd9Sstevel@tonic-gate void
tty_make_modes(int fd,struct termios * tiop)2707c478bd9Sstevel@tonic-gate tty_make_modes(int fd, struct termios *tiop)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	struct termios tio;
2737c478bd9Sstevel@tonic-gate 	int baud;
2747c478bd9Sstevel@tonic-gate 	Buffer buf;
2757c478bd9Sstevel@tonic-gate 	int tty_op_ospeed, tty_op_ispeed;
2767c478bd9Sstevel@tonic-gate 	void (*put_arg)(Buffer *, u_int);
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	buffer_init(&buf);
2797c478bd9Sstevel@tonic-gate 	if (compat20) {
2807c478bd9Sstevel@tonic-gate 		tty_op_ospeed = TTY_OP_OSPEED_PROTO2;
2817c478bd9Sstevel@tonic-gate 		tty_op_ispeed = TTY_OP_ISPEED_PROTO2;
2827c478bd9Sstevel@tonic-gate 		put_arg = buffer_put_int;
2837c478bd9Sstevel@tonic-gate 	} else {
2847c478bd9Sstevel@tonic-gate 		tty_op_ospeed = TTY_OP_OSPEED_PROTO1;
2857c478bd9Sstevel@tonic-gate 		tty_op_ispeed = TTY_OP_ISPEED_PROTO1;
2867c478bd9Sstevel@tonic-gate 		put_arg = (void (*)(Buffer *, u_int)) buffer_put_char;
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	if (tiop == NULL) {
2907c478bd9Sstevel@tonic-gate 		if (tcgetattr(fd, &tio) == -1) {
2917c478bd9Sstevel@tonic-gate 			log("tcgetattr: %.100s", strerror(errno));
2927c478bd9Sstevel@tonic-gate 			goto end;
2937c478bd9Sstevel@tonic-gate 		}
2947c478bd9Sstevel@tonic-gate 	} else
2957c478bd9Sstevel@tonic-gate 		tio = *tiop;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	/* Store input and output baud rates. */
2987c478bd9Sstevel@tonic-gate 	baud = speed_to_baud(cfgetospeed(&tio));
2997c478bd9Sstevel@tonic-gate 	debug3("tty_make_modes: ospeed %d", baud);
3007c478bd9Sstevel@tonic-gate 	buffer_put_char(&buf, tty_op_ospeed);
3017c478bd9Sstevel@tonic-gate 	buffer_put_int(&buf, baud);
3027c478bd9Sstevel@tonic-gate 	baud = speed_to_baud(cfgetispeed(&tio));
3037c478bd9Sstevel@tonic-gate 	debug3("tty_make_modes: ispeed %d", baud);
3047c478bd9Sstevel@tonic-gate 	buffer_put_char(&buf, tty_op_ispeed);
3057c478bd9Sstevel@tonic-gate 	buffer_put_int(&buf, baud);
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	/* Store values of mode flags. */
3087c478bd9Sstevel@tonic-gate #define TTYCHAR(NAME, OP) \
3097c478bd9Sstevel@tonic-gate 	debug3("tty_make_modes: %d %d", OP, tio.c_cc[NAME]); \
3107c478bd9Sstevel@tonic-gate 	buffer_put_char(&buf, OP); \
3117c478bd9Sstevel@tonic-gate 	put_arg(&buf, tio.c_cc[NAME]);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate #define TTYMODE(NAME, FIELD, OP) \
3147c478bd9Sstevel@tonic-gate 	debug3("tty_make_modes: %d %d", OP, ((tio.FIELD & NAME) != 0)); \
3157c478bd9Sstevel@tonic-gate 	buffer_put_char(&buf, OP); \
3167c478bd9Sstevel@tonic-gate 	put_arg(&buf, ((tio.FIELD & NAME) != 0));
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate #include "ttymodes.h"
3197c478bd9Sstevel@tonic-gate 
3207c478bd9Sstevel@tonic-gate #undef TTYCHAR
3217c478bd9Sstevel@tonic-gate #undef TTYMODE
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate end:
3247c478bd9Sstevel@tonic-gate 	/* Mark end of mode data. */
3257c478bd9Sstevel@tonic-gate 	buffer_put_char(&buf, TTY_OP_END);
3267c478bd9Sstevel@tonic-gate 	if (compat20)
3277c478bd9Sstevel@tonic-gate 		packet_put_string(buffer_ptr(&buf), buffer_len(&buf));
3287c478bd9Sstevel@tonic-gate 	else
3297c478bd9Sstevel@tonic-gate 		packet_put_raw(buffer_ptr(&buf), buffer_len(&buf));
3307c478bd9Sstevel@tonic-gate 	buffer_free(&buf);
3317c478bd9Sstevel@tonic-gate }
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate /*
3347c478bd9Sstevel@tonic-gate  * Decodes terminal modes for the terminal referenced by fd in a portable
3357c478bd9Sstevel@tonic-gate  * manner from a packet being read.
3367c478bd9Sstevel@tonic-gate  */
3377c478bd9Sstevel@tonic-gate void
tty_parse_modes(int fd,int * n_bytes_ptr)3387c478bd9Sstevel@tonic-gate tty_parse_modes(int fd, int *n_bytes_ptr)
3397c478bd9Sstevel@tonic-gate {
3407c478bd9Sstevel@tonic-gate 	struct termios tio;
3417c478bd9Sstevel@tonic-gate 	int opcode, baud;
3427c478bd9Sstevel@tonic-gate 	int n_bytes = 0;
3437c478bd9Sstevel@tonic-gate 	int failure = 0;
3447c478bd9Sstevel@tonic-gate 	u_int (*get_arg)(void);
3457c478bd9Sstevel@tonic-gate 	int arg, arg_size;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	if (compat20) {
3487c478bd9Sstevel@tonic-gate 		*n_bytes_ptr = packet_get_int();
3497c478bd9Sstevel@tonic-gate 		debug3("tty_parse_modes: SSH2 n_bytes %d", *n_bytes_ptr);
3507c478bd9Sstevel@tonic-gate 		if (*n_bytes_ptr == 0)
3517c478bd9Sstevel@tonic-gate 			return;
3527c478bd9Sstevel@tonic-gate 		get_arg = packet_get_int;
3537c478bd9Sstevel@tonic-gate 		arg_size = 4;
3547c478bd9Sstevel@tonic-gate 	} else {
3557c478bd9Sstevel@tonic-gate 		get_arg = packet_get_char;
3567c478bd9Sstevel@tonic-gate 		arg_size = 1;
3577c478bd9Sstevel@tonic-gate 	}
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	/*
3607c478bd9Sstevel@tonic-gate 	 * Get old attributes for the terminal.  We will modify these
3617c478bd9Sstevel@tonic-gate 	 * flags. I am hoping that if there are any machine-specific
3627c478bd9Sstevel@tonic-gate 	 * modes, they will initially have reasonable values.
3637c478bd9Sstevel@tonic-gate 	 */
3647c478bd9Sstevel@tonic-gate 	if (tcgetattr(fd, &tio) == -1) {
3657c478bd9Sstevel@tonic-gate 		log("tcgetattr: %.100s", strerror(errno));
3667c478bd9Sstevel@tonic-gate 		failure = -1;
3677c478bd9Sstevel@tonic-gate 	}
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	for (;;) {
3707c478bd9Sstevel@tonic-gate 		n_bytes += 1;
3717c478bd9Sstevel@tonic-gate 		opcode = packet_get_char();
3727c478bd9Sstevel@tonic-gate 		switch (opcode) {
3737c478bd9Sstevel@tonic-gate 		case TTY_OP_END:
3747c478bd9Sstevel@tonic-gate 			goto set;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		/* XXX: future conflict possible */
3777c478bd9Sstevel@tonic-gate 		case TTY_OP_ISPEED_PROTO1:
3787c478bd9Sstevel@tonic-gate 		case TTY_OP_ISPEED_PROTO2:
3797c478bd9Sstevel@tonic-gate 			n_bytes += 4;
3807c478bd9Sstevel@tonic-gate 			baud = packet_get_int();
3817c478bd9Sstevel@tonic-gate 			debug3("tty_parse_modes: ispeed %d", baud);
3827c478bd9Sstevel@tonic-gate 			if (failure != -1 && cfsetispeed(&tio, baud_to_speed(baud)) == -1)
3837c478bd9Sstevel@tonic-gate 				error("cfsetispeed failed for %d", baud);
3847c478bd9Sstevel@tonic-gate 			break;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 		/* XXX: future conflict possible */
3877c478bd9Sstevel@tonic-gate 		case TTY_OP_OSPEED_PROTO1:
3887c478bd9Sstevel@tonic-gate 		case TTY_OP_OSPEED_PROTO2:
3897c478bd9Sstevel@tonic-gate 			n_bytes += 4;
3907c478bd9Sstevel@tonic-gate 			baud = packet_get_int();
3917c478bd9Sstevel@tonic-gate 			debug3("tty_parse_modes: ospeed %d", baud);
3927c478bd9Sstevel@tonic-gate 			if (failure != -1 && cfsetospeed(&tio, baud_to_speed(baud)) == -1)
3937c478bd9Sstevel@tonic-gate 				error("cfsetospeed failed for %d", baud);
3947c478bd9Sstevel@tonic-gate 			break;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate #define TTYCHAR(NAME, OP) \
3977c478bd9Sstevel@tonic-gate 	case OP: \
3987c478bd9Sstevel@tonic-gate 	  n_bytes += arg_size; \
3997c478bd9Sstevel@tonic-gate 	  tio.c_cc[NAME] = get_arg(); \
4007c478bd9Sstevel@tonic-gate 	  debug3("tty_parse_modes: %d %d", OP, tio.c_cc[NAME]); \
4017c478bd9Sstevel@tonic-gate 	  break;
4027c478bd9Sstevel@tonic-gate #define TTYMODE(NAME, FIELD, OP) \
4037c478bd9Sstevel@tonic-gate 	case OP: \
4047c478bd9Sstevel@tonic-gate 	  n_bytes += arg_size; \
4057c478bd9Sstevel@tonic-gate 	  if ((arg = get_arg())) \
4067c478bd9Sstevel@tonic-gate 	    tio.FIELD |= NAME; \
4077c478bd9Sstevel@tonic-gate 	  else \
4087c478bd9Sstevel@tonic-gate 	    tio.FIELD &= ~NAME;	\
4097c478bd9Sstevel@tonic-gate 	  debug3("tty_parse_modes: %d %d", OP, arg); \
4107c478bd9Sstevel@tonic-gate 	  break;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate #include "ttymodes.h"
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate #undef TTYCHAR
4157c478bd9Sstevel@tonic-gate #undef TTYMODE
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 		default:
4187c478bd9Sstevel@tonic-gate 			debug("Ignoring unsupported tty mode opcode %d (0x%x)",
4197c478bd9Sstevel@tonic-gate 			    opcode, opcode);
4207c478bd9Sstevel@tonic-gate 			if (!compat20) {
4217c478bd9Sstevel@tonic-gate 				/*
4227c478bd9Sstevel@tonic-gate 				 * SSH1:
4237c478bd9Sstevel@tonic-gate 				 * Opcodes 1 to 127 are defined to have
4247c478bd9Sstevel@tonic-gate 				 * a one-byte argument.
4257c478bd9Sstevel@tonic-gate 				 * Opcodes 128 to 159 are defined to have
4267c478bd9Sstevel@tonic-gate 				 * an integer argument.
4277c478bd9Sstevel@tonic-gate 				 */
4287c478bd9Sstevel@tonic-gate 				if (opcode > 0 && opcode < 128) {
4297c478bd9Sstevel@tonic-gate 					n_bytes += 1;
4307c478bd9Sstevel@tonic-gate 					(void) packet_get_char();
4317c478bd9Sstevel@tonic-gate 					break;
4327c478bd9Sstevel@tonic-gate 				} else if (opcode >= 128 && opcode < 160) {
4337c478bd9Sstevel@tonic-gate 					n_bytes += 4;
4347c478bd9Sstevel@tonic-gate 					(void) packet_get_int();
4357c478bd9Sstevel@tonic-gate 					break;
4367c478bd9Sstevel@tonic-gate 				} else {
4377c478bd9Sstevel@tonic-gate 					/*
4387c478bd9Sstevel@tonic-gate 					 * It is a truly undefined opcode (160 to 255).
4397c478bd9Sstevel@tonic-gate 					 * We have no idea about its arguments.  So we
4407c478bd9Sstevel@tonic-gate 					 * must stop parsing.  Note that some data may be
4417c478bd9Sstevel@tonic-gate 					 * left in the packet; hopefully there is nothing
4427c478bd9Sstevel@tonic-gate 					 * more coming after the mode data.
4437c478bd9Sstevel@tonic-gate 					 */
4447c478bd9Sstevel@tonic-gate 					log("parse_tty_modes: unknown opcode %d", opcode);
4457c478bd9Sstevel@tonic-gate 					goto set;
4467c478bd9Sstevel@tonic-gate 				}
4477c478bd9Sstevel@tonic-gate 			} else {
4487c478bd9Sstevel@tonic-gate 				/*
4497c478bd9Sstevel@tonic-gate 				 * SSH2:
4507c478bd9Sstevel@tonic-gate 				 * Opcodes 1 to 159 are defined to have
4517c478bd9Sstevel@tonic-gate 				 * a uint32 argument.
4527c478bd9Sstevel@tonic-gate 				 * Opcodes 160 to 255 are undefined and
4537c478bd9Sstevel@tonic-gate 				 * cause parsing to stop.
4547c478bd9Sstevel@tonic-gate 				 */
4557c478bd9Sstevel@tonic-gate 				if (opcode > 0 && opcode < 160) {
4567c478bd9Sstevel@tonic-gate 					n_bytes += 4;
4577c478bd9Sstevel@tonic-gate 					(void) packet_get_int();
4587c478bd9Sstevel@tonic-gate 					break;
4597c478bd9Sstevel@tonic-gate 				} else {
4607c478bd9Sstevel@tonic-gate 					log("parse_tty_modes: unknown opcode %d", opcode);
4617c478bd9Sstevel@tonic-gate 					goto set;
4627c478bd9Sstevel@tonic-gate 				}
4637c478bd9Sstevel@tonic-gate 			}
4647c478bd9Sstevel@tonic-gate 		}
4657c478bd9Sstevel@tonic-gate 	}
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate set:
4687c478bd9Sstevel@tonic-gate 	if (*n_bytes_ptr != n_bytes) {
4697c478bd9Sstevel@tonic-gate 		*n_bytes_ptr = n_bytes;
4707c478bd9Sstevel@tonic-gate 		log("parse_tty_modes: n_bytes_ptr != n_bytes: %d %d",
4717c478bd9Sstevel@tonic-gate 		    *n_bytes_ptr, n_bytes);
4727c478bd9Sstevel@tonic-gate 		return;		/* Don't process bytes passed */
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 	if (failure == -1)
4757c478bd9Sstevel@tonic-gate 		return;		/* Packet parsed ok but tcgetattr() failed */
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	/* Set the new modes for the terminal. */
4787c478bd9Sstevel@tonic-gate 	if (tcsetattr(fd, TCSANOW, &tio) == -1)
4797c478bd9Sstevel@tonic-gate 		log("Setting tty modes failed: %.100s", strerror(errno));
4807c478bd9Sstevel@tonic-gate }
481