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 87ceb3dab..9820455c4 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 | ||
@@ -169,8 +168,6 @@ static u_int x11_refuse_time; /* If >0, refuse x11 opens after this time. */ | |||
169 | static void client_init_dispatch(void); | 168 | static void client_init_dispatch(void); |
170 | int session_ident = -1; | 169 | int session_ident = -1; |
171 | 170 | ||
172 | int session_resumed = 0; | ||
173 | |||
174 | /* Track escape per proto2 channel */ | 171 | /* Track escape per proto2 channel */ |
175 | struct escape_filter_ctx { | 172 | struct escape_filter_ctx { |
176 | int escape_pending; | 173 | int escape_pending; |
@@ -288,6 +285,9 @@ client_x11_display_valid(const char *display) | |||
288 | { | 285 | { |
289 | size_t i, dlen; | 286 | size_t i, dlen; |
290 | 287 | ||
288 | if (display == NULL) | ||
289 | return 0; | ||
290 | |||
291 | dlen = strlen(display); | 291 | dlen = strlen(display); |
292 | for (i = 0; i < dlen; i++) { | 292 | for (i = 0; i < dlen; i++) { |
293 | if (!isalnum((u_char)display[i]) && | 293 | if (!isalnum((u_char)display[i]) && |
@@ -301,35 +301,34 @@ client_x11_display_valid(const char *display) | |||
301 | 301 | ||
302 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" | 302 | #define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1" |
303 | #define X11_TIMEOUT_SLACK 60 | 303 | #define X11_TIMEOUT_SLACK 60 |
304 | void | 304 | int |
305 | client_x11_get_proto(const char *display, const char *xauth_path, | 305 | client_x11_get_proto(const char *display, const char *xauth_path, |
306 | u_int trusted, u_int timeout, char **_proto, char **_data) | 306 | u_int trusted, u_int timeout, char **_proto, char **_data) |
307 | { | 307 | { |
308 | char cmd[1024]; | 308 | char cmd[1024], line[512], xdisplay[512]; |
309 | char line[512]; | 309 | char xauthfile[PATH_MAX], xauthdir[PATH_MAX]; |
310 | char xdisplay[512]; | ||
311 | static char proto[512], data[512]; | 310 | static char proto[512], data[512]; |
312 | FILE *f; | 311 | FILE *f; |
313 | int got_data = 0, generated = 0, do_unlink = 0, i; | 312 | int got_data = 0, generated = 0, do_unlink = 0, i, r; |
314 | char *xauthdir, *xauthfile; | ||
315 | struct stat st; | 313 | struct stat st; |
316 | u_int now, x11_timeout_real; | 314 | u_int now, x11_timeout_real; |
317 | 315 | ||
318 | xauthdir = xauthfile = NULL; | ||
319 | *_proto = proto; | 316 | *_proto = proto; |
320 | *_data = data; | 317 | *_data = data; |
321 | proto[0] = data[0] = '\0'; | 318 | proto[0] = data[0] = xauthfile[0] = xauthdir[0] = '\0'; |
322 | 319 | ||
323 | if (xauth_path == NULL ||(stat(xauth_path, &st) == -1)) { | 320 | if (!client_x11_display_valid(display)) { |
321 | if (display != NULL) | ||
322 | logit("DISPLAY \"%s\" invalid; disabling X11 forwarding", | ||
323 | display); | ||
324 | return -1; | ||
325 | } | ||
326 | if (xauth_path != NULL && stat(xauth_path, &st) == -1) { | ||
324 | debug("No xauth program."); | 327 | debug("No xauth program."); |
325 | } else if (!client_x11_display_valid(display)) { | 328 | xauth_path = NULL; |
326 | logit("DISPLAY '%s' invalid, falling back to fake xauth data", | 329 | } |
327 | display); | 330 | |
328 | } else { | 331 | if (xauth_path != NULL) { |
329 | if (display == NULL) { | ||
330 | debug("x11_get_proto: DISPLAY not set"); | ||
331 | return; | ||
332 | } | ||
333 | /* | 332 | /* |
334 | * Handle FamilyLocal case where $DISPLAY does | 333 | * Handle FamilyLocal case where $DISPLAY does |
335 | * not match an authorization entry. For this we | 334 | * not match an authorization entry. For this we |
@@ -338,45 +337,60 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
338 | * is not perfect. | 337 | * is not perfect. |
339 | */ | 338 | */ |
340 | if (strncmp(display, "localhost:", 10) == 0) { | 339 | if (strncmp(display, "localhost:", 10) == 0) { |
341 | snprintf(xdisplay, sizeof(xdisplay), "unix:%s", | 340 | if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s", |
342 | display + 10); | 341 | display + 10)) < 0 || |
342 | (size_t)r >= sizeof(xdisplay)) { | ||
343 | error("%s: display name too long", __func__); | ||
344 | return -1; | ||
345 | } | ||
343 | display = xdisplay; | 346 | display = xdisplay; |
344 | } | 347 | } |
345 | if (trusted == 0) { | 348 | if (trusted == 0) { |
346 | xauthdir = xmalloc(PATH_MAX); | ||
347 | xauthfile = xmalloc(PATH_MAX); | ||
348 | mktemp_proto(xauthdir, PATH_MAX); | ||
349 | /* | 349 | /* |
350 | * Generate an untrusted X11 auth cookie. | ||
351 | * | ||
350 | * The authentication cookie should briefly outlive | 352 | * The authentication cookie should briefly outlive |
351 | * ssh's willingness to forward X11 connections to | 353 | * ssh's willingness to forward X11 connections to |
352 | * avoid nasty fail-open behaviour in the X server. | 354 | * avoid nasty fail-open behaviour in the X server. |
353 | */ | 355 | */ |
356 | mktemp_proto(xauthdir, sizeof(xauthdir)); | ||
357 | if (mkdtemp(xauthdir) == NULL) { | ||
358 | error("%s: mkdtemp: %s", | ||
359 | __func__, strerror(errno)); | ||
360 | return -1; | ||
361 | } | ||
362 | do_unlink = 1; | ||
363 | if ((r = snprintf(xauthfile, sizeof(xauthfile), | ||
364 | "%s/xauthfile", xauthdir)) < 0 || | ||
365 | (size_t)r >= sizeof(xauthfile)) { | ||
366 | error("%s: xauthfile path too long", __func__); | ||
367 | unlink(xauthfile); | ||
368 | rmdir(xauthdir); | ||
369 | return -1; | ||
370 | } | ||
371 | |||
354 | if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK) | 372 | if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK) |
355 | x11_timeout_real = UINT_MAX; | 373 | x11_timeout_real = UINT_MAX; |
356 | else | 374 | else |
357 | x11_timeout_real = timeout + X11_TIMEOUT_SLACK; | 375 | x11_timeout_real = timeout + X11_TIMEOUT_SLACK; |
358 | if (mkdtemp(xauthdir) != NULL) { | 376 | if ((r = snprintf(cmd, sizeof(cmd), |
359 | do_unlink = 1; | 377 | "%s -f %s generate %s " SSH_X11_PROTO |
360 | snprintf(xauthfile, PATH_MAX, "%s/xauthfile", | 378 | " untrusted timeout %u 2>" _PATH_DEVNULL, |
361 | xauthdir); | 379 | xauth_path, xauthfile, display, |
362 | snprintf(cmd, sizeof(cmd), | 380 | x11_timeout_real)) < 0 || |
363 | "%s -f %s generate %s " SSH_X11_PROTO | 381 | (size_t)r >= sizeof(cmd)) |
364 | " untrusted timeout %u 2>" _PATH_DEVNULL, | 382 | fatal("%s: cmd too long", __func__); |
365 | xauth_path, xauthfile, display, | 383 | debug2("%s: %s", __func__, cmd); |
366 | x11_timeout_real); | 384 | if (x11_refuse_time == 0) { |
367 | debug2("x11_get_proto: %s", cmd); | 385 | now = monotime() + 1; |
368 | if (x11_refuse_time == 0) { | 386 | if (UINT_MAX - timeout < now) |
369 | now = monotime() + 1; | 387 | x11_refuse_time = UINT_MAX; |
370 | if (UINT_MAX - timeout < now) | 388 | else |
371 | x11_refuse_time = UINT_MAX; | 389 | x11_refuse_time = now + timeout; |
372 | else | 390 | channel_set_x11_refuse_time(x11_refuse_time); |
373 | x11_refuse_time = now + timeout; | ||
374 | channel_set_x11_refuse_time( | ||
375 | x11_refuse_time); | ||
376 | } | ||
377 | if (system(cmd) == 0) | ||
378 | generated = 1; | ||
379 | } | 391 | } |
392 | if (system(cmd) == 0) | ||
393 | generated = 1; | ||
380 | } | 394 | } |
381 | 395 | ||
382 | /* | 396 | /* |
@@ -398,17 +412,20 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
398 | got_data = 1; | 412 | got_data = 1; |
399 | if (f) | 413 | if (f) |
400 | pclose(f); | 414 | pclose(f); |
401 | } else | 415 | } |
402 | error("Warning: untrusted X11 forwarding setup failed: " | ||
403 | "xauth key data not generated"); | ||
404 | } | 416 | } |
405 | 417 | ||
406 | if (do_unlink) { | 418 | if (do_unlink) { |
407 | unlink(xauthfile); | 419 | unlink(xauthfile); |
408 | rmdir(xauthdir); | 420 | rmdir(xauthdir); |
409 | } | 421 | } |
410 | free(xauthdir); | 422 | |
411 | free(xauthfile); | 423 | /* Don't fall back to fake X11 data for untrusted forwarding */ |
424 | if (!trusted && !got_data) { | ||
425 | error("Warning: untrusted X11 forwarding setup failed: " | ||
426 | "xauth key data not generated"); | ||
427 | return -1; | ||
428 | } | ||
412 | 429 | ||
413 | /* | 430 | /* |
414 | * If we didn't get authentication data, just make up some | 431 | * If we didn't get authentication data, just make up some |
@@ -432,6 +449,8 @@ client_x11_get_proto(const char *display, const char *xauth_path, | |||
432 | rnd >>= 8; | 449 | rnd >>= 8; |
433 | } | 450 | } |
434 | } | 451 | } |
452 | |||
453 | return 0; | ||
435 | } | 454 | } |
436 | 455 | ||
437 | /* | 456 | /* |
@@ -735,7 +754,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) | |||
735 | static void | 754 | static void |
736 | client_process_net_input(fd_set *readset) | 755 | client_process_net_input(fd_set *readset) |
737 | { | 756 | { |
738 | int len, cont = 0; | 757 | int len; |
739 | char buf[SSH_IOBUFSZ]; | 758 | char buf[SSH_IOBUFSZ]; |
740 | 759 | ||
741 | /* | 760 | /* |
@@ -744,8 +763,8 @@ client_process_net_input(fd_set *readset) | |||
744 | */ | 763 | */ |
745 | if (FD_ISSET(connection_in, readset)) { | 764 | if (FD_ISSET(connection_in, readset)) { |
746 | /* Read as much as possible. */ | 765 | /* Read as much as possible. */ |
747 | len = roaming_read(connection_in, buf, sizeof(buf), &cont); | 766 | len = read(connection_in, buf, sizeof(buf)); |
748 | if (len == 0 && cont == 0) { | 767 | if (len == 0) { |
749 | /* | 768 | /* |
750 | * Received EOF. The remote host has closed the | 769 | * Received EOF. The remote host has closed the |
751 | * connection. | 770 | * connection. |
@@ -1483,13 +1502,43 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1483 | { | 1502 | { |
1484 | fd_set *readset = NULL, *writeset = NULL; | 1503 | fd_set *readset = NULL, *writeset = NULL; |
1485 | double start_time, total_time; | 1504 | double start_time, total_time; |
1486 | int r, max_fd = 0, max_fd2 = 0, len, rekeying = 0; | 1505 | int r, max_fd = 0, max_fd2 = 0, len; |
1487 | u_int64_t ibytes, obytes; | 1506 | u_int64_t ibytes, obytes; |
1488 | u_int nalloc = 0; | 1507 | u_int nalloc = 0; |
1489 | char buf[100]; | 1508 | char buf[100]; |
1490 | 1509 | ||
1491 | debug("Entering interactive session."); | 1510 | debug("Entering interactive session."); |
1492 | 1511 | ||
1512 | if (options.control_master && | ||
1513 | ! option_clear_or_none(options.control_path)) { | ||
1514 | debug("pledge: id"); | ||
1515 | if (pledge("stdio rpath wpath cpath unix inet dns proc exec id tty", | ||
1516 | NULL) == -1) | ||
1517 | fatal("%s pledge(): %s", __func__, strerror(errno)); | ||
1518 | |||
1519 | } else if (options.forward_x11 || options.permit_local_command) { | ||
1520 | debug("pledge: exec"); | ||
1521 | if (pledge("stdio rpath wpath cpath unix inet dns proc exec tty", | ||
1522 | NULL) == -1) | ||
1523 | fatal("%s pledge(): %s", __func__, strerror(errno)); | ||
1524 | |||
1525 | } else if (options.update_hostkeys) { | ||
1526 | debug("pledge: filesystem full"); | ||
1527 | if (pledge("stdio rpath wpath cpath unix inet dns proc tty", | ||
1528 | NULL) == -1) | ||
1529 | fatal("%s pledge(): %s", __func__, strerror(errno)); | ||
1530 | |||
1531 | } else if (! option_clear_or_none(options.proxy_command)) { | ||
1532 | debug("pledge: proc"); | ||
1533 | if (pledge("stdio cpath unix inet dns proc tty", NULL) == -1) | ||
1534 | fatal("%s pledge(): %s", __func__, strerror(errno)); | ||
1535 | |||
1536 | } else { | ||
1537 | debug("pledge: network"); | ||
1538 | if (pledge("stdio unix inet dns tty", NULL) == -1) | ||
1539 | fatal("%s pledge(): %s", __func__, strerror(errno)); | ||
1540 | } | ||
1541 | |||
1493 | start_time = get_current_time(); | 1542 | start_time = get_current_time(); |
1494 | 1543 | ||
1495 | /* Initialize variables. */ | 1544 | /* Initialize variables. */ |
@@ -1568,10 +1617,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1568 | if (compat20 && session_closed && !channel_still_open()) | 1617 | if (compat20 && session_closed && !channel_still_open()) |
1569 | break; | 1618 | break; |
1570 | 1619 | ||
1571 | rekeying = (active_state->kex != NULL && !active_state->kex->done); | 1620 | if (ssh_packet_is_rekeying(active_state)) { |
1572 | |||
1573 | if (rekeying) { | ||
1574 | debug("rekeying in progress"); | 1621 | debug("rekeying in progress"); |
1622 | } else if (need_rekeying) { | ||
1623 | /* manual rekey request */ | ||
1624 | debug("need rekeying"); | ||
1625 | if ((r = kex_start_rekex(active_state)) != 0) | ||
1626 | fatal("%s: kex_start_rekex: %s", __func__, | ||
1627 | ssh_err(r)); | ||
1628 | need_rekeying = 0; | ||
1575 | } else { | 1629 | } else { |
1576 | /* | 1630 | /* |
1577 | * Make packets of buffered stdin data, and buffer | 1631 | * Make packets of buffered stdin data, and buffer |
@@ -1602,23 +1656,14 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1602 | */ | 1656 | */ |
1603 | max_fd2 = max_fd; | 1657 | max_fd2 = max_fd; |
1604 | client_wait_until_can_do_something(&readset, &writeset, | 1658 | client_wait_until_can_do_something(&readset, &writeset, |
1605 | &max_fd2, &nalloc, rekeying); | 1659 | &max_fd2, &nalloc, ssh_packet_is_rekeying(active_state)); |
1606 | 1660 | ||
1607 | if (quit_pending) | 1661 | if (quit_pending) |
1608 | break; | 1662 | break; |
1609 | 1663 | ||
1610 | /* Do channel operations unless rekeying in progress. */ | 1664 | /* Do channel operations unless rekeying in progress. */ |
1611 | if (!rekeying) { | 1665 | if (!ssh_packet_is_rekeying(active_state)) |
1612 | channel_after_select(readset, writeset); | 1666 | channel_after_select(readset, writeset); |
1613 | if (need_rekeying || packet_need_rekeying()) { | ||
1614 | debug("need rekeying"); | ||
1615 | active_state->kex->done = 0; | ||
1616 | if ((r = kex_send_kexinit(active_state)) != 0) | ||
1617 | fatal("%s: kex_send_kexinit: %s", | ||
1618 | __func__, ssh_err(r)); | ||
1619 | need_rekeying = 0; | ||
1620 | } | ||
1621 | } | ||
1622 | 1667 | ||
1623 | /* Buffer input from the connection. */ | 1668 | /* Buffer input from the connection. */ |
1624 | client_process_net_input(readset); | 1669 | client_process_net_input(readset); |
@@ -1636,14 +1681,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1636 | client_process_output(writeset); | 1681 | client_process_output(writeset); |
1637 | } | 1682 | } |
1638 | 1683 | ||
1639 | if (session_resumed) { | ||
1640 | connection_in = packet_get_connection_in(); | ||
1641 | connection_out = packet_get_connection_out(); | ||
1642 | max_fd = MAX(max_fd, connection_out); | ||
1643 | max_fd = MAX(max_fd, connection_in); | ||
1644 | session_resumed = 0; | ||
1645 | } | ||
1646 | |||
1647 | /* | 1684 | /* |
1648 | * Send as much buffered packet data as possible to the | 1685 | * Send as much buffered packet data as possible to the |
1649 | * sender. | 1686 | * sender. |
@@ -1737,7 +1774,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1737 | } | 1774 | } |
1738 | 1775 | ||
1739 | /* Clear and free any buffers. */ | 1776 | /* Clear and free any buffers. */ |
1740 | memset(buf, 0, sizeof(buf)); | 1777 | explicit_bzero(buf, sizeof(buf)); |
1741 | buffer_free(&stdin_buffer); | 1778 | buffer_free(&stdin_buffer); |
1742 | buffer_free(&stdout_buffer); | 1779 | buffer_free(&stdout_buffer); |
1743 | buffer_free(&stderr_buffer); | 1780 | buffer_free(&stderr_buffer); |