ttymodes.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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. * 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. * Encoding and decoding of terminal modes in a portable way.
  39. * Much of the format is defined in ttymodes.h; it is included multiple times
  40. * into this file with the appropriate macro definitions to generate the
  41. * suitable code.
  42. */
  43. #include "includes.h"
  44. #include <sys/types.h>
  45. #include <errno.h>
  46. #include <string.h>
  47. #include <termios.h>
  48. #include <stdarg.h>
  49. #include "packet.h"
  50. #include "log.h"
  51. #include "compat.h"
  52. #include "sshbuf.h"
  53. #include "ssherr.h"
  54. #define TTY_OP_END 0
  55. /*
  56. * uint32 (u_int) follows speed.
  57. */
  58. #define TTY_OP_ISPEED 128
  59. #define TTY_OP_OSPEED 129
  60. /*
  61. * Converts POSIX speed_t to a baud rate. The values of the
  62. * constants for speed_t are not themselves portable.
  63. */
  64. static int
  65. speed_to_baud(speed_t speed)
  66. {
  67. switch (speed) {
  68. case B0:
  69. return 0;
  70. case B50:
  71. return 50;
  72. case B75:
  73. return 75;
  74. case B110:
  75. return 110;
  76. case B134:
  77. return 134;
  78. case B150:
  79. return 150;
  80. case B200:
  81. return 200;
  82. case B300:
  83. return 300;
  84. case B600:
  85. return 600;
  86. case B1200:
  87. return 1200;
  88. case B1800:
  89. return 1800;
  90. case B2400:
  91. return 2400;
  92. case B4800:
  93. return 4800;
  94. case B9600:
  95. return 9600;
  96. #ifdef B19200
  97. case B19200:
  98. return 19200;
  99. #else /* B19200 */
  100. #ifdef EXTA
  101. case EXTA:
  102. return 19200;
  103. #endif /* EXTA */
  104. #endif /* B19200 */
  105. #ifdef B38400
  106. case B38400:
  107. return 38400;
  108. #else /* B38400 */
  109. #ifdef EXTB
  110. case EXTB:
  111. return 38400;
  112. #endif /* EXTB */
  113. #endif /* B38400 */
  114. #ifdef B7200
  115. case B7200:
  116. return 7200;
  117. #endif /* B7200 */
  118. #ifdef B14400
  119. case B14400:
  120. return 14400;
  121. #endif /* B14400 */
  122. #ifdef B28800
  123. case B28800:
  124. return 28800;
  125. #endif /* B28800 */
  126. #ifdef B57600
  127. case B57600:
  128. return 57600;
  129. #endif /* B57600 */
  130. #ifdef B76800
  131. case B76800:
  132. return 76800;
  133. #endif /* B76800 */
  134. #ifdef B115200
  135. case B115200:
  136. return 115200;
  137. #endif /* B115200 */
  138. #ifdef B230400
  139. case B230400:
  140. return 230400;
  141. #endif /* B230400 */
  142. default:
  143. return 9600;
  144. }
  145. }
  146. /*
  147. * Converts a numeric baud rate to a POSIX speed_t.
  148. */
  149. static speed_t
  150. baud_to_speed(int baud)
  151. {
  152. switch (baud) {
  153. case 0:
  154. return B0;
  155. case 50:
  156. return B50;
  157. case 75:
  158. return B75;
  159. case 110:
  160. return B110;
  161. case 134:
  162. return B134;
  163. case 150:
  164. return B150;
  165. case 200:
  166. return B200;
  167. case 300:
  168. return B300;
  169. case 600:
  170. return B600;
  171. case 1200:
  172. return B1200;
  173. case 1800:
  174. return B1800;
  175. case 2400:
  176. return B2400;
  177. case 4800:
  178. return B4800;
  179. case 9600:
  180. return B9600;
  181. #ifdef B19200
  182. case 19200:
  183. return B19200;
  184. #else /* B19200 */
  185. #ifdef EXTA
  186. case 19200:
  187. return EXTA;
  188. #endif /* EXTA */
  189. #endif /* B19200 */
  190. #ifdef B38400
  191. case 38400:
  192. return B38400;
  193. #else /* B38400 */
  194. #ifdef EXTB
  195. case 38400:
  196. return EXTB;
  197. #endif /* EXTB */
  198. #endif /* B38400 */
  199. #ifdef B7200
  200. case 7200:
  201. return B7200;
  202. #endif /* B7200 */
  203. #ifdef B14400
  204. case 14400:
  205. return B14400;
  206. #endif /* B14400 */
  207. #ifdef B28800
  208. case 28800:
  209. return B28800;
  210. #endif /* B28800 */
  211. #ifdef B57600
  212. case 57600:
  213. return B57600;
  214. #endif /* B57600 */
  215. #ifdef B76800
  216. case 76800:
  217. return B76800;
  218. #endif /* B76800 */
  219. #ifdef B115200
  220. case 115200:
  221. return B115200;
  222. #endif /* B115200 */
  223. #ifdef B230400
  224. case 230400:
  225. return B230400;
  226. #endif /* B230400 */
  227. default:
  228. return B9600;
  229. }
  230. }
  231. /*
  232. * Encode a special character into SSH line format.
  233. */
  234. static u_int
  235. special_char_encode(cc_t c)
  236. {
  237. #ifdef _POSIX_VDISABLE
  238. if (c == _POSIX_VDISABLE)
  239. return 255;
  240. #endif /* _POSIX_VDISABLE */
  241. return c;
  242. }
  243. /*
  244. * Decode a special character from SSH line format.
  245. */
  246. static cc_t
  247. special_char_decode(u_int c)
  248. {
  249. #ifdef _POSIX_VDISABLE
  250. if (c == 255)
  251. return _POSIX_VDISABLE;
  252. #endif /* _POSIX_VDISABLE */
  253. return c;
  254. }
  255. /*
  256. * Encodes terminal modes for the terminal referenced by fd
  257. * or tiop in a portable manner, and appends the modes to a packet
  258. * being constructed.
  259. */
  260. void
  261. ssh_tty_make_modes(struct ssh *ssh, int fd, struct termios *tiop)
  262. {
  263. struct termios tio;
  264. struct sshbuf *buf;
  265. int r, ibaud, obaud;
  266. if ((buf = sshbuf_new()) == NULL)
  267. fatal("%s: sshbuf_new failed", __func__);
  268. if (tiop == NULL) {
  269. if (fd == -1) {
  270. debug("%s: no fd or tio", __func__);
  271. goto end;
  272. }
  273. if (tcgetattr(fd, &tio) == -1) {
  274. logit("tcgetattr: %.100s", strerror(errno));
  275. goto end;
  276. }
  277. } else
  278. tio = *tiop;
  279. /* Store input and output baud rates. */
  280. obaud = speed_to_baud(cfgetospeed(&tio));
  281. ibaud = speed_to_baud(cfgetispeed(&tio));
  282. if ((r = sshbuf_put_u8(buf, TTY_OP_OSPEED)) != 0 ||
  283. (r = sshbuf_put_u32(buf, obaud)) != 0 ||
  284. (r = sshbuf_put_u8(buf, TTY_OP_ISPEED)) != 0 ||
  285. (r = sshbuf_put_u32(buf, ibaud)) != 0)
  286. fatal("%s: buffer error: %s", __func__, ssh_err(r));
  287. /* Store values of mode flags. */
  288. #define TTYCHAR(NAME, OP) \
  289. if ((r = sshbuf_put_u8(buf, OP)) != 0 || \
  290. (r = sshbuf_put_u32(buf, \
  291. special_char_encode(tio.c_cc[NAME]))) != 0) \
  292. fatal("%s: buffer error: %s", __func__, ssh_err(r)); \
  293. #define SSH_TTYMODE_IUTF8 42 /* for SSH_BUG_UTF8TTYMODE */
  294. #define TTYMODE(NAME, FIELD, OP) \
  295. if (OP == SSH_TTYMODE_IUTF8 && (ssh->compat & SSH_BUG_UTF8TTYMODE)) { \
  296. debug3("%s: SSH_BUG_UTF8TTYMODE", __func__); \
  297. } else if ((r = sshbuf_put_u8(buf, OP)) != 0 || \
  298. (r = sshbuf_put_u32(buf, ((tio.FIELD & NAME) != 0))) != 0) \
  299. fatal("%s: buffer error: %s", __func__, ssh_err(r)); \
  300. #include "ttymodes.h"
  301. #undef TTYCHAR
  302. #undef TTYMODE
  303. end:
  304. /* Mark end of mode data. */
  305. if ((r = sshbuf_put_u8(buf, TTY_OP_END)) != 0 ||
  306. (r = sshpkt_put_stringb(ssh, buf)) != 0)
  307. fatal("%s: packet error: %s", __func__, ssh_err(r));
  308. sshbuf_free(buf);
  309. }
  310. /*
  311. * Decodes terminal modes for the terminal referenced by fd in a portable
  312. * manner from a packet being read.
  313. */
  314. void
  315. ssh_tty_parse_modes(struct ssh *ssh, int fd)
  316. {
  317. struct termios tio;
  318. struct sshbuf *buf;
  319. const u_char *data;
  320. u_char opcode;
  321. u_int baud, u;
  322. int r, failure = 0;
  323. size_t len;
  324. if ((r = sshpkt_get_string_direct(ssh, &data, &len)) != 0)
  325. fatal("%s: packet error: %s", __func__, ssh_err(r));
  326. if (len == 0)
  327. return;
  328. if ((buf = sshbuf_from(data, len)) == NULL) {
  329. error("%s: sshbuf_from failed", __func__);
  330. return;
  331. }
  332. /*
  333. * Get old attributes for the terminal. We will modify these
  334. * flags. I am hoping that if there are any machine-specific
  335. * modes, they will initially have reasonable values.
  336. */
  337. if (tcgetattr(fd, &tio) == -1) {
  338. logit("tcgetattr: %.100s", strerror(errno));
  339. failure = -1;
  340. }
  341. while (sshbuf_len(buf) > 0) {
  342. if ((r = sshbuf_get_u8(buf, &opcode)) != 0)
  343. fatal("%s: packet error: %s", __func__, ssh_err(r));
  344. switch (opcode) {
  345. case TTY_OP_END:
  346. goto set;
  347. case TTY_OP_ISPEED:
  348. if ((r = sshbuf_get_u32(buf, &baud)) != 0)
  349. fatal("%s: packet error: %s",
  350. __func__, ssh_err(r));
  351. if (failure != -1 &&
  352. cfsetispeed(&tio, baud_to_speed(baud)) == -1)
  353. error("cfsetispeed failed for %d", baud);
  354. break;
  355. case TTY_OP_OSPEED:
  356. if ((r = sshbuf_get_u32(buf, &baud)) != 0)
  357. fatal("%s: packet error: %s",
  358. __func__, ssh_err(r));
  359. if (failure != -1 &&
  360. cfsetospeed(&tio, baud_to_speed(baud)) == -1)
  361. error("cfsetospeed failed for %d", baud);
  362. break;
  363. #define TTYCHAR(NAME, OP) \
  364. case OP: \
  365. if ((r = sshbuf_get_u32(buf, &u)) != 0) \
  366. fatal("%s: packet error: %s", __func__, \
  367. ssh_err(r)); \
  368. tio.c_cc[NAME] = special_char_decode(u); \
  369. break;
  370. #define TTYMODE(NAME, FIELD, OP) \
  371. case OP: \
  372. if ((r = sshbuf_get_u32(buf, &u)) != 0) \
  373. fatal("%s: packet error: %s", __func__, \
  374. ssh_err(r)); \
  375. if (u) \
  376. tio.FIELD |= NAME; \
  377. else \
  378. tio.FIELD &= ~NAME; \
  379. break;
  380. #include "ttymodes.h"
  381. #undef TTYCHAR
  382. #undef TTYMODE
  383. default:
  384. debug("Ignoring unsupported tty mode opcode %d (0x%x)",
  385. opcode, opcode);
  386. /*
  387. * SSH2:
  388. * Opcodes 1 to 159 are defined to have a uint32
  389. * argument.
  390. * Opcodes 160 to 255 are undefined and cause parsing
  391. * to stop.
  392. */
  393. if (opcode > 0 && opcode < 160) {
  394. if ((r = sshbuf_get_u32(buf, NULL)) != 0)
  395. fatal("%s: packet error: %s", __func__,
  396. ssh_err(r));
  397. break;
  398. } else {
  399. logit("%s: unknown opcode %d", __func__,
  400. opcode);
  401. goto set;
  402. }
  403. }
  404. }
  405. set:
  406. len = sshbuf_len(buf);
  407. sshbuf_free(buf);
  408. if (len > 0) {
  409. logit("%s: %zu bytes left", __func__, len);
  410. return; /* Don't process bytes passed */
  411. }
  412. if (failure == -1)
  413. return; /* Packet parsed ok but tcgetattr() failed */
  414. /* Set the new modes for the terminal. */
  415. if (tcsetattr(fd, TCSANOW, &tio) == -1)
  416. logit("Setting tty modes failed: %.100s", strerror(errno));
  417. }