diff options
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 195 |
1 files changed, 116 insertions, 79 deletions
diff --git a/clientloop.c b/clientloop.c index 5653cc489..3b6cacb08 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.275 2015/07/10 06:21:53 markus Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.284 2016/02/08 10:57:07 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -111,7 +111,6 @@ | |||
111 | #include "sshpty.h" | 111 | #include "sshpty.h" |
112 | #include "match.h" | 112 | #include "match.h" |
113 | #include "msg.h" | 113 | #include "msg.h" |
114 | #include "roaming.h" | ||
115 | #include "ssherr.h" | 114 | #include "ssherr.h" |
116 | #include "hostfile.h" | 115 | #include "hostfile.h" |
117 | 116 | ||
@@ -173,8 +172,6 @@ static u_int x11_refuse_time; /* If >0, refuse x11 opens after this time. */ | |||
173 | static void client_init_dispatch(void); | 172 | static void client_init_dispatch(void); |
174 | int session_ident = -1; | 173 | int session_ident = -1; |
175 | 174 | ||
176 | int session_resumed = 0; | ||
177 | |||
178 | /* Track escape per proto2 channel */ | 175 | /* Track escape per proto2 channel */ |
179 | struct escape_filter_ctx { | 176 | struct escape_filter_ctx { |
180 | int escape_pending; | 177 | int escape_pending; |
@@ -292,6 +289,9 @@ client_x11_display_valid(const char *display) | |||
292 | { | 289 | { |
293 | size_t i, dlen; | 290 | size_t i, dlen; |
294 | 291 | ||
292 | if (display == NULL) | ||
293 | return 0; | ||
294 | |||
295 | dlen = strlen(display); | 295 | dlen = strlen(display); |
296 | for (i = 0; i < dlen; i++) { | 296 | for (i = 0; i < dlen; i++) { |
297 | if (!isalnum((u_char)display[i]) && | 297 | if (!isalnum((u_char)display[i]) && |
@@ -305,35 +305,34 @@ client_x11_display_valid(const char *display) | |||
305 | 305 | ||
306 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" | 306 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" |
307 | #define X11_TIMEOUT_SLACK 60 | 307 | #define X11_TIMEOUT_SLACK 60 |
308 | void | 308 | int |
309 | client_x11_get_proto(const char *display, const char *xauth_path, | 309 | client_x11_get_proto(const char *display, const char *xauth_path, |
310 | u_int trusted, u_int timeout, char **_proto, char **_data) | 310 | u_int trusted, u_int timeout, char **_proto, char **_data) |
311 | { | 311 | { |
312 | char cmd[1024]; | 312 | char cmd[1024], line[512], xdisplay[512]; |
313 | char line[512]; | 313 | char xauthfile[PATH_MAX], xauthdir[PATH_MAX]; |
314 | char xdisplay[512]; | ||
315 | static char proto[512], data[512]; | 314 | static char proto[512], data[512]; |
316 | FILE *f; | 315 | FILE *f; |
317 | int got_data = 0, generated = 0, do_unlink = 0, i; | 316 | int got_data = 0, generated = 0, do_unlink = 0, i, r; |
318 | char *xauthdir, *xauthfile; | ||
319 | struct stat st; | 317 | struct stat st; |
320 | u_int now, x11_timeout_real; | 318 | u_int now, x11_timeout_real; |
321 | 319 | ||
322 | xauthdir = xauthfile = NULL; | ||
323 | *_proto = proto; | 320 | *_proto = proto; |
324 | *_data = data; | 321 | *_data = data; |
325 | proto[0] = data[0] = '\0'; | 322 | proto[0] = data[0] = xauthfile[0] = xauthdir[0] = '\0'; |
326 | 323 | ||
327 | if (xauth_path == NULL ||(stat(xauth_path, &st) == -1)) { | 324 | if (!client_x11_display_valid(display)) { |
325 | if (display != NULL) | ||
326 | logit("DISPLAY \"%s\" invalid; disabling X11 forwarding", | ||
327 | display); | ||
328 | return -1; | ||
329 | } | ||
330 | if (xauth_path != NULL && stat(xauth_path, &st) == -1) { | ||
328 | debug("No xauth program."); | 331 | debug("No xauth program."); |
329 | } else if (!client_x11_display_valid(display)) { | 332 | xauth_path = NULL; |
330 | logit("DISPLAY '%s' invalid, falling back to fake xauth data", | 333 | } |
331 | display); | 334 | |
332 | } else { | 335 | if (xauth_path != NULL) { |
333 | if (display == NULL) { | ||
334 | debug("x11_get_proto: DISPLAY not set"); | ||
335 | return; | ||
336 | } | ||
337 | /* | 336 | /* |
338 | * Handle FamilyLocal case where $DISPLAY does | 337 | * Handle FamilyLocal case where $DISPLAY does |
339 | * not match an authorization entry. For this we | 338 | * not match an authorization entry. For this we |
@@ -342,45 +341,60 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
342 | * is not perfect. | 341 | * is not perfect. |
343 | */ | 342 | */ |
344 | if (strncmp(display, "localhost:", 10) == 0) { | 343 | if (strncmp(display, "localhost:", 10) == 0) { |
345 | snprintf(xdisplay, sizeof(xdisplay), "unix:%s", | 344 | if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s", |
346 | display + 10); | 345 | display + 10)) < 0 || |
346 | (size_t)r >= sizeof(xdisplay)) { | ||
347 | error("%s: display name too long", __func__); | ||
348 | return -1; | ||
349 | } | ||
347 | display = xdisplay; | 350 | display = xdisplay; |
348 | } | 351 | } |
349 | if (trusted == 0) { | 352 | if (trusted == 0) { |
350 | xauthdir = xmalloc(PATH_MAX); | ||
351 | xauthfile = xmalloc(PATH_MAX); | ||
352 | mktemp_proto(xauthdir, PATH_MAX); | ||
353 | /* | 353 | /* |
354 | * Generate an untrusted X11 auth cookie. | ||
355 | * | ||
354 | * The authentication cookie should briefly outlive | 356 | * The authentication cookie should briefly outlive |
355 | * ssh's willingness to forward X11 connections to | 357 | * ssh's willingness to forward X11 connections to |
356 | * avoid nasty fail-open behaviour in the X server. | 358 | * avoid nasty fail-open behaviour in the X server. |
357 | */ | 359 | */ |
360 | mktemp_proto(xauthdir, sizeof(xauthdir)); | ||
361 | if (mkdtemp(xauthdir) == NULL) { | ||
362 | error("%s: mkdtemp: %s", | ||
363 | __func__, strerror(errno)); | ||
364 | return -1; | ||
365 | } | ||
366 | do_unlink = 1; | ||
367 | if ((r = snprintf(xauthfile, sizeof(xauthfile), | ||
368 | "%s/xauthfile", xauthdir)) < 0 || | ||
369 | (size_t)r >= sizeof(xauthfile)) { | ||
370 | error("%s: xauthfile path too long", __func__); | ||
371 | unlink(xauthfile); | ||
372 | rmdir(xauthdir); | ||
373 | return -1; | ||
374 | } | ||
375 | |||
358 | if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK) | 376 | if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK) |
359 | x11_timeout_real = UINT_MAX; | 377 | x11_timeout_real = UINT_MAX; |
360 | else | 378 | else |
361 | x11_timeout_real = timeout + X11_TIMEOUT_SLACK; | 379 | x11_timeout_real = timeout + X11_TIMEOUT_SLACK; |
362 | if (mkdtemp(xauthdir) != NULL) { | 380 | if ((r = snprintf(cmd, sizeof(cmd), |
363 | do_unlink = 1; | 381 | "%s -f %s generate %s " SSH_X11_PROTO |
364 | snprintf(xauthfile, PATH_MAX, "%s/xauthfile", | 382 | " untrusted timeout %u 2>" _PATH_DEVNULL, |
365 | xauthdir); | 383 | xauth_path, xauthfile, display, |
366 | snprintf(cmd, sizeof(cmd), | 384 | x11_timeout_real)) < 0 || |
367 | "%s -f %s generate %s " SSH_X11_PROTO | 385 | (size_t)r >= sizeof(cmd)) |
368 | " untrusted timeout %u 2>" _PATH_DEVNULL, | 386 | fatal("%s: cmd too long", __func__); |
369 | xauth_path, xauthfile, display, | 387 | debug2("%s: %s", __func__, cmd); |
370 | x11_timeout_real); | 388 | if (x11_refuse_time == 0) { |
371 | debug2("x11_get_proto: %s", cmd); | 389 | now = monotime() + 1; |
372 | if (x11_refuse_time == 0) { | 390 | if (UINT_MAX - timeout < now) |
373 | now = monotime() + 1; | 391 | x11_refuse_time = UINT_MAX; |
374 | if (UINT_MAX - timeout < now) | 392 | else |
375 | x11_refuse_time = UINT_MAX; | 393 | x11_refuse_time = now + timeout; |
376 | else | 394 | channel_set_x11_refuse_time(x11_refuse_time); |
377 | x11_refuse_time = now + timeout; | ||
378 | channel_set_x11_refuse_time( | ||
379 | x11_refuse_time); | ||
380 | } | ||
381 | if (system(cmd) == 0) | ||
382 | generated = 1; | ||
383 | } | 395 | } |
396 | if (system(cmd) == 0) | ||
397 | generated = 1; | ||
384 | } | 398 | } |
385 | 399 | ||
386 | /* | 400 | /* |
@@ -402,17 +416,20 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
402 | got_data = 1; | 416 | got_data = 1; |
403 | if (f) | 417 | if (f) |
404 | pclose(f); | 418 | pclose(f); |
405 | } else | 419 | } |
406 | error("Warning: untrusted X11 forwarding setup failed: " | ||
407 | "xauth key data not generated"); | ||
408 | } | 420 | } |
409 | 421 | ||
410 | if (do_unlink) { | 422 | if (do_unlink) { |
411 | unlink(xauthfile); | 423 | unlink(xauthfile); |
412 | rmdir(xauthdir); | 424 | rmdir(xauthdir); |
413 | } | 425 | } |
414 | free(xauthdir); | 426 | |
415 | free(xauthfile); | 427 | /* Don't fall back to fake X11 data for untrusted forwarding */ |
428 | if (!trusted && !got_data) { | ||
429 | error("Warning: untrusted X11 forwarding setup failed: " | ||
430 | "xauth key data not generated"); | ||
431 | return -1; | ||
432 | } | ||
416 | 433 | ||
417 | /* | 434 | /* |
418 | * If we didn't get authentication data, just make up some | 435 | * If we didn't get authentication data, just make up some |
@@ -436,6 +453,8 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
436 | rnd >>= 8; | 453 | rnd >>= 8; |
437 | } | 454 | } |
438 | } | 455 | } |
456 | |||
457 | return 0; | ||
439 | } | 458 | } |
440 | 459 | ||
441 | /* | 460 | /* |
@@ -739,7 +758,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) | |||
739 | static void | 758 | static void |
740 | client_process_net_input(fd_set *readset) | 759 | client_process_net_input(fd_set *readset) |
741 | { | 760 | { |
742 | int len, cont = 0; | 761 | int len; |
743 | char buf[SSH_IOBUFSZ]; | 762 | char buf[SSH_IOBUFSZ]; |
744 | 763 | ||
745 | /* | 764 | /* |
@@ -748,8 +767,8 @@ client_process_net_input(fd_set *readset) | |||
748 | */ | 767 | */ |
749 | if (FD_ISSET(connection_in, readset)) { | 768 | if (FD_ISSET(connection_in, readset)) { |
750 | /* Read as much as possible. */ | 769 | /* Read as much as possible. */ |
751 | len = roaming_read(connection_in, buf, sizeof(buf), &cont); | 770 | len = read(connection_in, buf, sizeof(buf)); |
752 | if (len == 0 && cont == 0) { | 771 | if (len == 0) { |
753 | /* | 772 | /* |
754 | * Received EOF. The remote host has closed the | 773 | * Received EOF. The remote host has closed the |
755 | * connection. | 774 | * connection. |
@@ -1487,13 +1506,43 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1487 | { | 1506 | { |
1488 | fd_set *readset = NULL, *writeset = NULL; | 1507 | fd_set *readset = NULL, *writeset = NULL; |
1489 | double start_time, total_time; | 1508 | double start_time, total_time; |
1490 | int r, max_fd = 0, max_fd2 = 0, len, rekeying = 0; | 1509 | int r, max_fd = 0, max_fd2 = 0, len; |
1491 | u_int64_t ibytes, obytes; | 1510 | u_int64_t ibytes, obytes; |
1492 | u_int nalloc = 0; | 1511 | u_int nalloc = 0; |
1493 | char buf[100]; | 1512 | char buf[100]; |
1494 | 1513 | ||
1495 | debug("Entering interactive session."); | 1514 | debug("Entering interactive session."); |
1496 | 1515 | ||
1516 | if (options.control_master && | ||
1517 | ! option_clear_or_none(options.control_path)) { | ||
1518 | debug("pledge: id"); | ||
1519 | if (pledge("stdio rpath wpath cpath unix inet dns proc exec id tty", | ||
1520 | NULL) == -1) | ||
1521 | fatal("%s pledge(): %s", __func__, strerror(errno)); | ||
1522 | |||
1523 | } else if (options.forward_x11 || options.permit_local_command) { | ||
1524 | debug("pledge: exec"); | ||
1525 | if (pledge("stdio rpath wpath cpath unix inet dns proc exec tty", | ||
1526 | NULL) == -1) | ||
1527 | fatal("%s pledge(): %s", __func__, strerror(errno)); | ||
1528 | |||
1529 | } else if (options.update_hostkeys) { | ||
1530 | debug("pledge: filesystem full"); | ||
1531 | if (pledge("stdio rpath wpath cpath unix inet dns proc tty", | ||
1532 | NULL) == -1) | ||
1533 | fatal("%s pledge(): %s", __func__, strerror(errno)); | ||
1534 | |||
1535 | } else if (! option_clear_or_none(options.proxy_command)) { | ||
1536 | debug("pledge: proc"); | ||
1537 | if (pledge("stdio cpath unix inet dns proc tty", NULL) == -1) | ||
1538 | fatal("%s pledge(): %s", __func__, strerror(errno)); | ||
1539 | |||
1540 | } else { | ||
1541 | debug("pledge: network"); | ||
1542 | if (pledge("stdio unix inet dns tty", NULL) == -1) | ||
1543 | fatal("%s pledge(): %s", __func__, strerror(errno)); | ||
1544 | } | ||
1545 | |||
1497 | start_time = get_current_time(); | 1546 | start_time = get_current_time(); |
1498 | 1547 | ||
1499 | /* Initialize variables. */ | 1548 | /* Initialize variables. */ |
@@ -1572,10 +1621,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1572 | if (compat20 && session_closed && !channel_still_open()) | 1621 | if (compat20 && session_closed && !channel_still_open()) |
1573 | break; | 1622 | break; |
1574 | 1623 | ||
1575 | rekeying = (active_state->kex != NULL && !active_state->kex->done); | 1624 | if (ssh_packet_is_rekeying(active_state)) { |
1576 | |||
1577 | if (rekeying) { | ||
1578 | debug("rekeying in progress"); | 1625 | debug("rekeying in progress"); |
1626 | } else if (need_rekeying) { | ||
1627 | /* manual rekey request */ | ||
1628 | debug("need rekeying"); | ||
1629 | if ((r = kex_start_rekex(active_state)) != 0) | ||
1630 | fatal("%s: kex_start_rekex: %s", __func__, | ||
1631 | ssh_err(r)); | ||
1632 | need_rekeying = 0; | ||
1579 | } else { | 1633 | } else { |
1580 | /* | 1634 | /* |
1581 | * Make packets of buffered stdin data, and buffer | 1635 | * Make packets of buffered stdin data, and buffer |
@@ -1606,13 +1660,13 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1606 | */ | 1660 | */ |
1607 | max_fd2 = max_fd; | 1661 | max_fd2 = max_fd; |
1608 | client_wait_until_can_do_something(&readset, &writeset, | 1662 | client_wait_until_can_do_something(&readset, &writeset, |
1609 | &max_fd2, &nalloc, rekeying); | 1663 | &max_fd2, &nalloc, ssh_packet_is_rekeying(active_state)); |
1610 | 1664 | ||
1611 | if (quit_pending) | 1665 | if (quit_pending) |
1612 | break; | 1666 | break; |
1613 | 1667 | ||
1614 | /* Do channel operations unless rekeying in progress. */ | 1668 | /* Do channel operations unless rekeying in progress. */ |
1615 | if (!rekeying) { | 1669 | if (!ssh_packet_is_rekeying(active_state)) { |
1616 | channel_after_select(readset, writeset); | 1670 | channel_after_select(readset, writeset); |
1617 | 1671 | ||
1618 | #ifdef GSSAPI | 1672 | #ifdef GSSAPI |
@@ -1622,15 +1676,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1622 | need_rekeying = 1; | 1676 | need_rekeying = 1; |
1623 | } | 1677 | } |
1624 | #endif | 1678 | #endif |
1625 | |||
1626 | if (need_rekeying || packet_need_rekeying()) { | ||
1627 | debug("need rekeying"); | ||
1628 | active_state->kex->done = 0; | ||
1629 | if ((r = kex_send_kexinit(active_state)) != 0) | ||
1630 | fatal("%s: kex_send_kexinit: %s", | ||
1631 | __func__, ssh_err(r)); | ||
1632 | need_rekeying = 0; | ||
1633 | } | ||
1634 | } | 1679 | } |
1635 | 1680 | ||
1636 | /* Buffer input from the connection. */ | 1681 | /* Buffer input from the connection. */ |
@@ -1649,14 +1694,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1649 | client_process_output(writeset); | 1694 | client_process_output(writeset); |
1650 | } | 1695 | } |
1651 | 1696 | ||
1652 | if (session_resumed) { | ||
1653 | connection_in = packet_get_connection_in(); | ||
1654 | connection_out = packet_get_connection_out(); | ||
1655 | max_fd = MAX(max_fd, connection_out); | ||
1656 | max_fd = MAX(max_fd, connection_in); | ||
1657 | session_resumed = 0; | ||
1658 | } | ||
1659 | |||
1660 | /* | 1697 | /* |
1661 | * Send as much buffered packet data as possible to the | 1698 | * Send as much buffered packet data as possible to the |
1662 | * sender. | 1699 | * sender. |
@@ -1752,7 +1789,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1752 | } | 1789 | } |
1753 | 1790 | ||
1754 | /* Clear and free any buffers. */ | 1791 | /* Clear and free any buffers. */ |
1755 | memset(buf, 0, sizeof(buf)); | 1792 | explicit_bzero(buf, sizeof(buf)); |
1756 | buffer_free(&stdin_buffer); | 1793 | buffer_free(&stdin_buffer); |
1757 | buffer_free(&stdout_buffer); | 1794 | buffer_free(&stdout_buffer); |
1758 | buffer_free(&stderr_buffer); | 1795 | buffer_free(&stderr_buffer); |