aboutsummaryrefslogtreecommitdiffstats
path: root/clientloop.c
diff options
context:
space:
mode:
Diffstat (limited to 'clientloop.c')
-rw-r--r--clientloop.c295
1 files changed, 192 insertions, 103 deletions
diff --git a/clientloop.c b/clientloop.c
index 87ceb3da..06481623 100644
--- a/clientloop.c
+++ b/clientloop.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: clientloop.c,v 1.275 2015/07/10 06:21:53 markus Exp $ */
+/* $OpenBSD: clientloop.c,v 1.291 2017/03/10 05:01:13 djm Exp $ */
/*
* Author: Tatu Ylonen <ylo@cs.hut.fi>
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -61,7 +61,6 @@
#include "includes.h"
-#include <sys/param.h> /* MIN MAX */
#include <sys/types.h>
#include <sys/ioctl.h>
#ifdef HAVE_SYS_STAT_H
@@ -111,7 +110,6 @@
#include "sshpty.h"
#include "match.h"
#include "msg.h"
-#include "roaming.h"
#include "ssherr.h"
#include "hostfile.h"
@@ -124,6 +122,9 @@ extern int stdin_null_flag;
/* Flag indicating that no shell has been requested */
extern int no_shell_flag;
+/* Flag indicating that ssh should daemonise after authentication is complete */
+extern int fork_after_authentication_flag;
+
/* Control socket */
extern int muxserver_sock; /* XXX use mux_client_cleanup() instead */
@@ -169,8 +170,6 @@ static u_int x11_refuse_time; /* If >0, refuse x11 opens after this time. */
static void client_init_dispatch(void);
int session_ident = -1;
-int session_resumed = 0;
-
/* Track escape per proto2 channel */
struct escape_filter_ctx {
int escape_pending;
@@ -288,6 +287,9 @@ client_x11_display_valid(const char *display)
{
size_t i, dlen;
+ if (display == NULL)
+ return 0;
+
dlen = strlen(display);
for (i = 0; i < dlen; i++) {
if (!isalnum((u_char)display[i]) &&
@@ -301,35 +303,34 @@ client_x11_display_valid(const char *display)
#define SSH_X11_PROTO "MIT-MAGIC-COOKIE-1"
#define X11_TIMEOUT_SLACK 60
-void
+int
client_x11_get_proto(const char *display, const char *xauth_path,
u_int trusted, u_int timeout, char **_proto, char **_data)
{
- char cmd[1024];
- char line[512];
- char xdisplay[512];
+ char cmd[1024], line[512], xdisplay[512];
+ char xauthfile[PATH_MAX], xauthdir[PATH_MAX];
static char proto[512], data[512];
FILE *f;
- int got_data = 0, generated = 0, do_unlink = 0, i;
- char *xauthdir, *xauthfile;
+ int got_data = 0, generated = 0, do_unlink = 0, r;
struct stat st;
u_int now, x11_timeout_real;
- xauthdir = xauthfile = NULL;
*_proto = proto;
*_data = data;
- proto[0] = data[0] = '\0';
+ proto[0] = data[0] = xauthfile[0] = xauthdir[0] = '\0';
- if (xauth_path == NULL ||(stat(xauth_path, &st) == -1)) {
+ if (!client_x11_display_valid(display)) {
+ if (display != NULL)
+ logit("DISPLAY \"%s\" invalid; disabling X11 forwarding",
+ display);
+ return -1;
+ }
+ if (xauth_path != NULL && stat(xauth_path, &st) == -1) {
debug("No xauth program.");
- } else if (!client_x11_display_valid(display)) {
- logit("DISPLAY '%s' invalid, falling back to fake xauth data",
- display);
- } else {
- if (display == NULL) {
- debug("x11_get_proto: DISPLAY not set");
- return;
- }
+ xauth_path = NULL;
+ }
+
+ if (xauth_path != NULL) {
/*
* Handle FamilyLocal case where $DISPLAY does
* not match an authorization entry. For this we
@@ -338,45 +339,60 @@ client_x11_get_proto(const char *display, const char *xauth_path,
* is not perfect.
*/
if (strncmp(display, "localhost:", 10) == 0) {
- snprintf(xdisplay, sizeof(xdisplay), "unix:%s",
- display + 10);
+ if ((r = snprintf(xdisplay, sizeof(xdisplay), "unix:%s",
+ display + 10)) < 0 ||
+ (size_t)r >= sizeof(xdisplay)) {
+ error("%s: display name too long", __func__);
+ return -1;
+ }
display = xdisplay;
}
if (trusted == 0) {
- xauthdir = xmalloc(PATH_MAX);
- xauthfile = xmalloc(PATH_MAX);
- mktemp_proto(xauthdir, PATH_MAX);
/*
+ * Generate an untrusted X11 auth cookie.
+ *
* The authentication cookie should briefly outlive
* ssh's willingness to forward X11 connections to
* avoid nasty fail-open behaviour in the X server.
*/
+ mktemp_proto(xauthdir, sizeof(xauthdir));
+ if (mkdtemp(xauthdir) == NULL) {
+ error("%s: mkdtemp: %s",
+ __func__, strerror(errno));
+ return -1;
+ }
+ do_unlink = 1;
+ if ((r = snprintf(xauthfile, sizeof(xauthfile),
+ "%s/xauthfile", xauthdir)) < 0 ||
+ (size_t)r >= sizeof(xauthfile)) {
+ error("%s: xauthfile path too long", __func__);
+ unlink(xauthfile);
+ rmdir(xauthdir);
+ return -1;
+ }
+
if (timeout >= UINT_MAX - X11_TIMEOUT_SLACK)
x11_timeout_real = UINT_MAX;
else
x11_timeout_real = timeout + X11_TIMEOUT_SLACK;
- if (mkdtemp(xauthdir) != NULL) {
- do_unlink = 1;
- snprintf(xauthfile, PATH_MAX, "%s/xauthfile",
- xauthdir);
- snprintf(cmd, sizeof(cmd),
- "%s -f %s generate %s " SSH_X11_PROTO
- " untrusted timeout %u 2>" _PATH_DEVNULL,
- xauth_path, xauthfile, display,
- x11_timeout_real);
- debug2("x11_get_proto: %s", cmd);
- if (x11_refuse_time == 0) {
- now = monotime() + 1;
- if (UINT_MAX - timeout < now)
- x11_refuse_time = UINT_MAX;
- else
- x11_refuse_time = now + timeout;
- channel_set_x11_refuse_time(
- x11_refuse_time);
- }
- if (system(cmd) == 0)
- generated = 1;
+ if ((r = snprintf(cmd, sizeof(cmd),
+ "%s -f %s generate %s " SSH_X11_PROTO
+ " untrusted timeout %u 2>" _PATH_DEVNULL,
+ xauth_path, xauthfile, display,
+ x11_timeout_real)) < 0 ||
+ (size_t)r >= sizeof(cmd))
+ fatal("%s: cmd too long", __func__);
+ debug2("%s: %s", __func__, cmd);
+ if (x11_refuse_time == 0) {
+ now = monotime() + 1;
+ if (UINT_MAX - timeout < now)
+ x11_refuse_time = UINT_MAX;
+ else
+ x11_refuse_time = now + timeout;
+ channel_set_x11_refuse_time(x11_refuse_time);
}
+ if (system(cmd) == 0)
+ generated = 1;
}
/*
@@ -398,17 +414,20 @@ client_x11_get_proto(const char *display, const char *xauth_path,
got_data = 1;
if (f)
pclose(f);
- } else
- error("Warning: untrusted X11 forwarding setup failed: "
- "xauth key data not generated");
+ }
}
if (do_unlink) {
unlink(xauthfile);
rmdir(xauthdir);
}
- free(xauthdir);
- free(xauthfile);
+
+ /* Don't fall back to fake X11 data for untrusted forwarding */
+ if (!trusted && !got_data) {
+ error("Warning: untrusted X11 forwarding setup failed: "
+ "xauth key data not generated");
+ return -1;
+ }
/*
* If we didn't get authentication data, just make up some
@@ -419,19 +438,20 @@ client_x11_get_proto(const char *display, const char *xauth_path,
* for the local connection.
*/
if (!got_data) {
- u_int32_t rnd = 0;
+ u_int8_t rnd[16];
+ u_int i;
logit("Warning: No xauth data; "
"using fake authentication data for X11 forwarding.");
strlcpy(proto, SSH_X11_PROTO, sizeof proto);
- for (i = 0; i < 16; i++) {
- if (i % 4 == 0)
- rnd = arc4random();
+ arc4random_buf(rnd, sizeof(rnd));
+ for (i = 0; i < sizeof(rnd); i++) {
snprintf(data + 2 * i, sizeof data - 2 * i, "%02x",
- rnd & 0xff);
- rnd >>= 8;
+ rnd[i]);
}
}
+
+ return 0;
}
/*
@@ -650,16 +670,16 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp,
server_alive_time = now + options.server_alive_interval;
}
if (options.rekey_interval > 0 && compat20 && !rekeying)
- timeout_secs = MIN(timeout_secs, packet_get_rekey_timeout());
+ timeout_secs = MINIMUM(timeout_secs, packet_get_rekey_timeout());
set_control_persist_exit_time();
if (control_persist_exit_time > 0) {
- timeout_secs = MIN(timeout_secs,
+ timeout_secs = MINIMUM(timeout_secs,
control_persist_exit_time - now);
if (timeout_secs < 0)
timeout_secs = 0;
}
if (minwait_secs != 0)
- timeout_secs = MIN(timeout_secs, (int)minwait_secs);
+ timeout_secs = MINIMUM(timeout_secs, (int)minwait_secs);
if (timeout_secs == INT_MAX)
tvp = NULL;
else {
@@ -735,7 +755,7 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr)
static void
client_process_net_input(fd_set *readset)
{
- int len, cont = 0;
+ int len;
char buf[SSH_IOBUFSZ];
/*
@@ -744,8 +764,8 @@ client_process_net_input(fd_set *readset)
*/
if (FD_ISSET(connection_in, readset)) {
/* Read as much as possible. */
- len = roaming_read(connection_in, buf, sizeof(buf), &cont);
- if (len == 0 && cont == 0) {
+ len = read(connection_in, buf, sizeof(buf));
+ if (len == 0) {
/*
* Received EOF. The remote host has closed the
* connection.
@@ -971,7 +991,7 @@ process_cmdline(void)
CHANNEL_CANCEL_PORT_STATIC,
&options.fwd_opts) > 0;
if (!ok) {
- logit("Unkown port forwarding.");
+ logit("Unknown port forwarding.");
goto out;
}
logit("Canceled forwarding.");
@@ -1483,13 +1503,44 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
{
fd_set *readset = NULL, *writeset = NULL;
double start_time, total_time;
- int r, max_fd = 0, max_fd2 = 0, len, rekeying = 0;
+ int r, max_fd = 0, max_fd2 = 0, len;
u_int64_t ibytes, obytes;
u_int nalloc = 0;
char buf[100];
debug("Entering interactive session.");
+ if (options.control_master &&
+ !option_clear_or_none(options.control_path)) {
+ debug("pledge: id");
+ if (pledge("stdio rpath wpath cpath unix inet dns recvfd proc exec id tty",
+ NULL) == -1)
+ fatal("%s pledge(): %s", __func__, strerror(errno));
+
+ } else if (options.forward_x11 || options.permit_local_command) {
+ debug("pledge: exec");
+ if (pledge("stdio rpath wpath cpath unix inet dns proc exec tty",
+ NULL) == -1)
+ fatal("%s pledge(): %s", __func__, strerror(errno));
+
+ } else if (options.update_hostkeys) {
+ debug("pledge: filesystem full");
+ if (pledge("stdio rpath wpath cpath unix inet dns proc tty",
+ NULL) == -1)
+ fatal("%s pledge(): %s", __func__, strerror(errno));
+
+ } else if (!option_clear_or_none(options.proxy_command) ||
+ fork_after_authentication_flag) {
+ debug("pledge: proc");
+ if (pledge("stdio cpath unix inet dns proc tty", NULL) == -1)
+ fatal("%s pledge(): %s", __func__, strerror(errno));
+
+ } else {
+ debug("pledge: network");
+ if (pledge("stdio unix inet dns tty", NULL) == -1)
+ fatal("%s pledge(): %s", __func__, strerror(errno));
+ }
+
start_time = get_current_time();
/* Initialize variables. */
@@ -1500,7 +1551,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
buffer_high = 64 * 1024;
connection_in = packet_get_connection_in();
connection_out = packet_get_connection_out();
- max_fd = MAX(connection_in, connection_out);
+ max_fd = MAXIMUM(connection_in, connection_out);
if (!compat20) {
/* enable nonblocking unless tty */
@@ -1510,9 +1561,9 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
set_nonblock(fileno(stdout));
if (!isatty(fileno(stderr)))
set_nonblock(fileno(stderr));
- max_fd = MAX(max_fd, fileno(stdin));
- max_fd = MAX(max_fd, fileno(stdout));
- max_fd = MAX(max_fd, fileno(stderr));
+ max_fd = MAXIMUM(max_fd, fileno(stdin));
+ max_fd = MAXIMUM(max_fd, fileno(stdout));
+ max_fd = MAXIMUM(max_fd, fileno(stderr));
}
quit_pending = 0;
escape_char1 = escape_char_arg;
@@ -1568,10 +1619,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
if (compat20 && session_closed && !channel_still_open())
break;
- rekeying = (active_state->kex != NULL && !active_state->kex->done);
-
- if (rekeying) {
+ if (ssh_packet_is_rekeying(active_state)) {
debug("rekeying in progress");
+ } else if (need_rekeying) {
+ /* manual rekey request */
+ debug("need rekeying");
+ if ((r = kex_start_rekex(active_state)) != 0)
+ fatal("%s: kex_start_rekex: %s", __func__,
+ ssh_err(r));
+ need_rekeying = 0;
} else {
/*
* Make packets of buffered stdin data, and buffer
@@ -1602,23 +1658,14 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
*/
max_fd2 = max_fd;
client_wait_until_can_do_something(&readset, &writeset,
- &max_fd2, &nalloc, rekeying);
+ &max_fd2, &nalloc, ssh_packet_is_rekeying(active_state));
if (quit_pending)
break;
/* Do channel operations unless rekeying in progress. */
- if (!rekeying) {
+ if (!ssh_packet_is_rekeying(active_state))
channel_after_select(readset, writeset);
- if (need_rekeying || packet_need_rekeying()) {
- debug("need rekeying");
- active_state->kex->done = 0;
- if ((r = kex_send_kexinit(active_state)) != 0)
- fatal("%s: kex_send_kexinit: %s",
- __func__, ssh_err(r));
- need_rekeying = 0;
- }
- }
/* Buffer input from the connection. */
client_process_net_input(readset);
@@ -1636,14 +1683,6 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
client_process_output(writeset);
}
- if (session_resumed) {
- connection_in = packet_get_connection_in();
- connection_out = packet_get_connection_out();
- max_fd = MAX(max_fd, connection_out);
- max_fd = MAX(max_fd, connection_in);
- session_resumed = 0;
- }
-
/*
* Send as much buffered packet data as possible to the
* sender.
@@ -1737,7 +1776,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id)
}
/* Clear and free any buffers. */
- memset(buf, 0, sizeof(buf));
+ explicit_bzero(buf, sizeof(buf));
buffer_free(&stdin_buffer);
buffer_free(&stdout_buffer);
buffer_free(&stderr_buffer);
@@ -1844,11 +1883,14 @@ client_input_agent_open(int type, u_int32_t seq, void *ctxt)
}
static Channel *
-client_request_forwarded_tcpip(const char *request_type, int rchan)
+client_request_forwarded_tcpip(const char *request_type, int rchan,
+ u_int rwindow, u_int rmaxpack)
{
Channel *c = NULL;
+ struct sshbuf *b = NULL;
char *listen_address, *originator_address;
u_short listen_port, originator_port;
+ int r;
/* Get rest of the packet */
listen_address = packet_get_string(NULL);
@@ -1863,6 +1905,31 @@ client_request_forwarded_tcpip(const char *request_type, int rchan)
c = channel_connect_by_listen_address(listen_address, listen_port,
"forwarded-tcpip", originator_address);
+ if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) {
+ if ((b = sshbuf_new()) == NULL) {
+ error("%s: alloc reply", __func__);
+ goto out;
+ }
+ /* reconstruct and send to muxclient */
+ if ((r = sshbuf_put_u8(b, 0)) != 0 || /* padlen */
+ (r = sshbuf_put_u8(b, SSH2_MSG_CHANNEL_OPEN)) != 0 ||
+ (r = sshbuf_put_cstring(b, request_type)) != 0 ||
+ (r = sshbuf_put_u32(b, rchan)) != 0 ||
+ (r = sshbuf_put_u32(b, rwindow)) != 0 ||
+ (r = sshbuf_put_u32(b, rmaxpack)) != 0 ||
+ (r = sshbuf_put_cstring(b, listen_address)) != 0 ||
+ (r = sshbuf_put_u32(b, listen_port)) != 0 ||
+ (r = sshbuf_put_cstring(b, originator_address)) != 0 ||
+ (r = sshbuf_put_u32(b, originator_port)) != 0 ||
+ (r = sshbuf_put_stringb(&c->output, b)) != 0) {
+ error("%s: compose for muxclient %s", __func__,
+ ssh_err(r));
+ goto out;
+ }
+ }
+
+ out:
+ sshbuf_free(b);
free(originator_address);
free(listen_address);
return c;
@@ -2018,7 +2085,8 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
ctype, rchan, rwindow, rmaxpack);
if (strcmp(ctype, "forwarded-tcpip") == 0) {
- c = client_request_forwarded_tcpip(ctype, rchan);
+ c = client_request_forwarded_tcpip(ctype, rchan, rwindow,
+ rmaxpack);
} else if (strcmp(ctype, "forwarded-streamlocal@openssh.com") == 0) {
c = client_request_forwarded_streamlocal(ctype, rchan);
} else if (strcmp(ctype, "x11") == 0) {
@@ -2026,8 +2094,9 @@ client_input_channel_open(int type, u_int32_t seq, void *ctxt)
} else if (strcmp(ctype, "auth-agent@openssh.com") == 0) {
c = client_request_agent(ctype, rchan);
}
-/* XXX duplicate : */
- if (c != NULL) {
+ if (c != NULL && c->type == SSH_CHANNEL_MUX_CLIENT) {
+ debug3("proxied to downstream: %s", ctype);
+ } else if (c != NULL) {
debug("confirm %s", ctype);
c->remote_id = rchan;
c->remote_window = rwindow;
@@ -2063,6 +2132,9 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
char *rtype;
id = packet_get_int();
+ c = channel_lookup(id);
+ if (channel_proxy_upstream(c, type, seq, ctxt))
+ return 0;
rtype = packet_get_string(NULL);
reply = packet_get_char();
@@ -2071,7 +2143,7 @@ client_input_channel_req(int type, u_int32_t seq, void *ctxt)
if (id == -1) {
error("client_input_channel_req: request for channel -1");
- } else if ((c = channel_lookup(id)) == NULL) {
+ } else if (c == NULL) {
error("client_input_channel_req: channel %d: "
"unknown channel", id);
} else if (strcmp(rtype, "eow@openssh.com") == 0) {
@@ -2319,6 +2391,26 @@ client_global_hostkeys_private_confirm(int type, u_int32_t seq, void *_ctx)
}
/*
+ * Returns non-zero if the key is accepted by HostkeyAlgorithms.
+ * Made slightly less trivial by the multiple RSA signature algorithm names.
+ */
+static int
+key_accepted_by_hostkeyalgs(const struct sshkey *key)
+{
+ const char *ktype = sshkey_ssh_name(key);
+ const char *hostkeyalgs = options.hostkeyalgorithms != NULL ?
+ options.hostkeyalgorithms : KEX_DEFAULT_PK_ALG;
+
+ if (key == NULL || key->type == KEY_UNSPEC)
+ return 0;
+ if (key->type == KEY_RSA &&
+ (match_pattern_list("rsa-sha2-256", hostkeyalgs, 0) == 1 ||
+ match_pattern_list("rsa-sha2-512", hostkeyalgs, 0) == 1))
+ return 1;
+ return match_pattern_list(ktype, hostkeyalgs, 0) == 1;
+}
+
+/*
* Handle hostkeys-00@openssh.com global request to inform the client of all
* the server's hostkeys. The keys are checked against the user's
* HostkeyAlgorithms preference before they are accepted.
@@ -2364,10 +2456,7 @@ client_input_hostkeys(void)
sshkey_type(key), fp);
free(fp);
- /* Check that the key is accepted in HostkeyAlgorithms */
- if (match_pattern_list(sshkey_ssh_name(key),
- options.hostkeyalgorithms ? options.hostkeyalgorithms :
- KEX_DEFAULT_PK_ALG, 0) != 1) {
+ if (!key_accepted_by_hostkeyalgs(key)) {
debug3("%s: %s key not permitted by HostkeyAlgorithms",
__func__, sshkey_ssh_name(key));
continue;